move net addresses from interface to protocol layer;
[unix-history] / usr / src / sys / netinet / in_pcb.c
CommitLineData
f2d10020 1/* in_pcb.c 6.5 84/11/27 */
af092e86 2
20666ad3
JB
3#include "param.h"
4#include "systm.h"
5#include "dir.h"
6#include "user.h"
7#include "mbuf.h"
8#include "socket.h"
9#include "socketvar.h"
10#include "in.h"
11#include "in_systm.h"
4ad99bae 12#include "../net/if.h"
c124e997 13#include "../net/route.h"
20666ad3
JB
14#include "in_pcb.h"
15#include "protosw.h"
af092e86 16
1a3dbf93 17struct in_addr zeroin_addr;
405c9168 18
8f0d18de
BJ
19in_pcballoc(so, head)
20 struct socket *so;
21 struct inpcb *head;
22{
23 struct mbuf *m;
24 register struct inpcb *inp;
25
cce93e4b 26 m = m_getclr(M_DONTWAIT, MT_PCB);
5cdc4d65 27 if (m == NULL)
8f0d18de
BJ
28 return (ENOBUFS);
29 inp = mtod(m, struct inpcb *);
30 inp->inp_head = head;
31 inp->inp_socket = so;
32 insque(inp, head);
33 so->so_pcb = (caddr_t)inp;
34 return (0);
35}
36
8075bb0e 37in_pcbbind(inp, nam)
8f0d18de 38 register struct inpcb *inp;
8075bb0e 39 struct mbuf *nam;
8f0d18de
BJ
40{
41 register struct socket *so = inp->inp_socket;
42 register struct inpcb *head = inp->inp_head;
8075bb0e 43 register struct sockaddr_in *sin;
8f0d18de
BJ
44 u_short lport = 0;
45
46 if (ifnet == 0)
47 return (EADDRNOTAVAIL);
5cdc4d65 48 if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
8075bb0e
BJ
49 return (EINVAL);
50 if (nam == 0)
51 goto noname;
52 sin = mtod(nam, struct sockaddr_in *);
53 if (nam->m_len != sizeof (*sin))
54 return (EINVAL);
5cdc4d65 55 if (sin->sin_addr.s_addr != INADDR_ANY) {
8075bb0e 56 int tport = sin->sin_port;
8f0d18de 57
8075bb0e
BJ
58 sin->sin_port = 0; /* yech... */
59 if (if_ifwithaddr((struct sockaddr *)sin) == 0)
60 return (EADDRNOTAVAIL);
61 sin->sin_port = tport;
8f0d18de 62 }
8075bb0e
BJ
63 lport = sin->sin_port;
64 if (lport) {
f2d10020 65 u_short aport = ntohs(lport);
8075bb0e 66 int wild = 0;
c124e997 67
8075bb0e
BJ
68 /* GROSS */
69 if (aport < IPPORT_RESERVED && u.u_uid != 0)
70 return (EACCES);
b4a3d4a7
SL
71 /* even GROSSER, but this is the Internet */
72 if ((so->so_options & SO_REUSEADDR) == 0 &&
73 ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
74 (so->so_options & SO_ACCEPTCONN) == 0))
8075bb0e
BJ
75 wild = INPLOOKUP_WILDCARD;
76 if (in_pcblookup(head,
77 zeroin_addr, 0, sin->sin_addr, lport, wild))
78 return (EADDRINUSE);
4ad99bae 79 }
8075bb0e
BJ
80 inp->inp_laddr = sin->sin_addr;
81noname:
b454c3ea
BJ
82 if (lport == 0)
83 do {
1aa87517
BJ
84 if (head->inp_lport++ < IPPORT_RESERVED)
85 head->inp_lport = IPPORT_RESERVED;
b454c3ea 86 lport = htons(head->inp_lport);
1aa87517
BJ
87 } while (in_pcblookup(head,
88 zeroin_addr, 0, inp->inp_laddr, lport, 0));
4ad99bae 89 inp->inp_lport = lport;
4ad99bae 90 return (0);
af092e86
BJ
91}
92
1acff8ec
BJ
93/*
94 * Connect from a socket to a specified address.
95 * Both address and port must be specified in argument sin.
96 * If don't have a local address for this socket yet,
97 * then pick one.
98 */
8075bb0e 99in_pcbconnect(inp, nam)
4ad99bae 100 struct inpcb *inp;
8075bb0e 101 struct mbuf *nam;
2b4b57cd 102{
1aa87517 103 struct ifnet *ifp;
ee787340 104 struct sockaddr_in *ifaddr;
8075bb0e 105 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
2b4b57cd 106
8075bb0e
BJ
107 if (nam->m_len != sizeof (*sin))
108 return (EINVAL);
4ad99bae
BJ
109 if (sin->sin_family != AF_INET)
110 return (EAFNOSUPPORT);
5cdc4d65 111 if (sin->sin_addr.s_addr == INADDR_ANY || sin->sin_port == 0)
4ad99bae 112 return (EADDRNOTAVAIL);
5cdc4d65 113 if (inp->inp_laddr.s_addr == INADDR_ANY) {
6187f8f4 114 ifp = if_ifonnetof(in_netof(sin->sin_addr));
ee787340 115 if (ifp == 0) {
99578149
MK
116 register struct route *ro;
117
118 /*
119 * If route is known or can be allocated now,
120 * our src addr is taken from the i/f, else punt.
72e4f44e 121 */
99578149
MK
122 ro = &inp->inp_route;
123#define satosin(sa) ((struct sockaddr_in *)(sa))
124 if (ro->ro_rt &&
125 satosin(&ro->ro_dst)->sin_addr.s_addr !=
126 sin->sin_addr.s_addr) {
127 RTFREE(ro->ro_rt);
128 ro->ro_rt = (struct rtentry *)0;
129 }
130 if ((ro->ro_rt == (struct rtentry *)0) ||
131 (ifp = ro->ro_rt->rt_ifp) == (struct ifnet *)0) {
132 /* No route yet, so try to acquire one */
133 ro->ro_dst.sa_family = AF_INET;
134 ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
135 sin->sin_addr;
136 rtalloc(ro);
137 if (ro->ro_rt == 0)
138 ifp = (struct ifnet *) 0;
139 else
140 ifp = ro->ro_rt->rt_ifp;
141 }
142 if (ifp == 0)
143 ifp = if_ifwithaf(AF_INET);
ee787340 144 if (ifp == 0)
72e4f44e 145 return (EADDRNOTAVAIL);
ee787340
SL
146 }
147 ifaddr = (struct sockaddr_in *)&ifp->if_addr;
1aa87517
BJ
148 }
149 if (in_pcblookup(inp->inp_head,
1acff8ec
BJ
150 sin->sin_addr,
151 sin->sin_port,
ee787340 152 inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
1acff8ec
BJ
153 inp->inp_lport,
154 0))
b454c3ea 155 return (EADDRINUSE);
3cd2053b
SL
156 if (inp->inp_laddr.s_addr == INADDR_ANY) {
157 if (inp->inp_lport == 0)
158 in_pcbbind(inp, (struct mbuf *)0);
ee787340 159 inp->inp_laddr = ifaddr->sin_addr;
3cd2053b 160 }
4ad99bae
BJ
161 inp->inp_faddr = sin->sin_addr;
162 inp->inp_fport = sin->sin_port;
2b4b57cd
BJ
163 return (0);
164}
165
405c9168
BJ
166in_pcbdisconnect(inp)
167 struct inpcb *inp;
168{
169
5cdc4d65 170 inp->inp_faddr.s_addr = INADDR_ANY;
ebcadd38 171 inp->inp_fport = 0;
8f0d18de 172 if (inp->inp_socket->so_state & SS_NOFDREF)
405c9168
BJ
173 in_pcbdetach(inp);
174}
175
176in_pcbdetach(inp)
af092e86
BJ
177 struct inpcb *inp;
178{
179 struct socket *so = inp->inp_socket;
180
ba55c9af
BJ
181 so->so_pcb = 0;
182 sofree(so);
c124e997 183 if (inp->inp_route.ro_rt)
f6311fb6 184 rtfree(inp->inp_route.ro_rt);
7545cf09 185 remque(inp);
cdad2eb1 186 (void) m_free(dtom(inp));
af092e86
BJ
187}
188
8075bb0e 189in_setsockaddr(inp, nam)
126472ab 190 register struct inpcb *inp;
8075bb0e 191 struct mbuf *nam;
126472ab 192{
8075bb0e
BJ
193 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
194
195 nam->m_len = sizeof (*sin);
196 sin = mtod(nam, struct sockaddr_in *);
126472ab
SL
197 bzero((caddr_t)sin, sizeof (*sin));
198 sin->sin_family = AF_INET;
199 sin->sin_port = inp->inp_lport;
200 sin->sin_addr = inp->inp_laddr;
201}
202
a7343092
SL
203in_setpeeraddr(inp, nam)
204 register struct inpcb *inp;
205 struct mbuf *nam;
206{
207 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
208
209 nam->m_len = sizeof (*sin);
210 sin = mtod(nam, struct sockaddr_in *);
211 bzero((caddr_t)sin, sizeof (*sin));
212 sin->sin_family = AF_INET;
213 sin->sin_port = inp->inp_fport;
214 sin->sin_addr = inp->inp_faddr;
215}
216
72e4f44e 217/*
842b6bb5
MK
218 * Pass some notification to all connections of a protocol
219 * associated with address dst. Call the
220 * protocol specific routine to handle each connection.
72e4f44e 221 */
842b6bb5 222in_pcbnotify(head, dst, errno, notify)
72e4f44e
SL
223 struct inpcb *head;
224 register struct in_addr *dst;
842b6bb5 225 int errno, (*notify)();
72e4f44e
SL
226{
227 register struct inpcb *inp, *oinp;
228 int s = splimp();
229
72e4f44e
SL
230 for (inp = head->inp_next; inp != head;) {
231 if (inp->inp_faddr.s_addr != dst->s_addr) {
232 next:
233 inp = inp->inp_next;
234 continue;
235 }
236 if (inp->inp_socket == 0)
237 goto next;
842b6bb5
MK
238 if (errno)
239 inp->inp_socket->so_error = errno;
72e4f44e
SL
240 oinp = inp;
241 inp = inp->inp_next;
842b6bb5 242 (*notify)(oinp);
72e4f44e
SL
243 }
244 splx(s);
245}
246
842b6bb5
MK
247/*
248 * After a routing change, flush old routing
249 * and allocate a (hopefully) better one.
250 */
251in_rtchange(inp)
252 struct inpcb *inp;
253{
254 if (inp->inp_route.ro_rt) {
255 rtfree(inp->inp_route.ro_rt);
256 inp->inp_route.ro_rt = 0;
257 /*
258 * A new route can be allocated the next time
259 * output is attempted.
260 */
261 }
262 /* SHOULD NOTIFY HIGHER-LEVEL PROTOCOLS */
263}
264
cdad2eb1 265struct inpcb *
ebcadd38 266in_pcblookup(head, faddr, fport, laddr, lport, flags)
af092e86 267 struct inpcb *head;
4ad99bae 268 struct in_addr faddr, laddr;
af092e86 269 u_short fport, lport;
ebcadd38 270 int flags;
af092e86 271{
1aa87517
BJ
272 register struct inpcb *inp, *match = 0;
273 int matchwild = 3, wildcard;
af092e86 274
405c9168 275 for (inp = head->inp_next; inp != head; inp = inp->inp_next) {
1aa87517 276 if (inp->inp_lport != lport)
405c9168 277 continue;
1aa87517 278 wildcard = 0;
5cdc4d65
SL
279 if (inp->inp_laddr.s_addr != INADDR_ANY) {
280 if (laddr.s_addr == INADDR_ANY)
1acff8ec
BJ
281 wildcard++;
282 else if (inp->inp_laddr.s_addr != laddr.s_addr)
1aa87517
BJ
283 continue;
284 } else {
5cdc4d65 285 if (laddr.s_addr != INADDR_ANY)
1aa87517
BJ
286 wildcard++;
287 }
5cdc4d65
SL
288 if (inp->inp_faddr.s_addr != INADDR_ANY) {
289 if (faddr.s_addr == INADDR_ANY)
1acff8ec
BJ
290 wildcard++;
291 else if (inp->inp_faddr.s_addr != faddr.s_addr ||
ebcadd38 292 inp->inp_fport != fport)
1aa87517
BJ
293 continue;
294 } else {
5cdc4d65 295 if (faddr.s_addr != INADDR_ANY)
1aa87517
BJ
296 wildcard++;
297 }
ebcadd38 298 if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0)
405c9168 299 continue;
1aa87517
BJ
300 if (wildcard < matchwild) {
301 match = inp;
302 matchwild = wildcard;
303 if (matchwild == 0)
304 break;
405c9168 305 }
1aa87517 306 }
405c9168 307 return (match);
af092e86 308}