prototype everything
[unix-history] / usr / src / sys / netinet / in_pcb.c
CommitLineData
8ae0e4b4 1/*
6d5b2d5f 2 * Copyright (c) 1982, 1986, 1991, 1993 Regents of the University of California.
2b6b6284 3 * All rights reserved.
8ae0e4b4 4 *
dbf0c423 5 * %sccs.include.redist.c%
2b6b6284 6 *
6d5b2d5f 7 * @(#)in_pcb.c 7.27 (Berkeley) %G%
8ae0e4b4 8 */
af092e86 9
5548a02f
KB
10#include <sys/param.h>
11#include <sys/systm.h>
12#include <sys/malloc.h>
13#include <sys/mbuf.h>
14#include <sys/protosw.h>
15#include <sys/socket.h>
16#include <sys/socketvar.h>
17#include <sys/ioctl.h>
18#include <sys/errno.h>
6d5b2d5f
MK
19#include <sys/time.h>
20#include <sys/proc.h>
6aa944c6 21
5548a02f
KB
22#include <net/if.h>
23#include <net/route.h>
6aa944c6 24
5548a02f
KB
25#include <netinet/in.h>
26#include <netinet/in_systm.h>
27#include <netinet/ip.h>
28#include <netinet/in_pcb.h>
29#include <netinet/in_var.h>
af092e86 30
5548a02f 31#include <netinet/ip_var.h>
d6fa15c2 32
1a3dbf93 33struct in_addr zeroin_addr;
405c9168 34
8f0d18de
BJ
35in_pcballoc(so, head)
36 struct socket *so;
37 struct inpcb *head;
38{
39 struct mbuf *m;
40 register struct inpcb *inp;
41
d6fa15c2
KS
42 MALLOC(inp, struct inpcb *, sizeof(*inp), M_PCB, M_WAITOK);
43 if (inp == NULL)
8f0d18de 44 return (ENOBUFS);
d6fa15c2 45 bzero((caddr_t)inp, sizeof(*inp));
8f0d18de
BJ
46 inp->inp_head = head;
47 inp->inp_socket = so;
48 insque(inp, head);
49 so->so_pcb = (caddr_t)inp;
50 return (0);
51}
52
8075bb0e 53in_pcbbind(inp, nam)
8f0d18de 54 register struct inpcb *inp;
8075bb0e 55 struct mbuf *nam;
8f0d18de
BJ
56{
57 register struct socket *so = inp->inp_socket;
58 register struct inpcb *head = inp->inp_head;
8075bb0e 59 register struct sockaddr_in *sin;
6d5b2d5f 60 struct proc *p = curproc; /* XXX */
8f0d18de 61 u_short lport = 0;
6d5b2d5f
MK
62 int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
63 int error;
8f0d18de 64
5d305bdd 65 if (in_ifaddr == 0)
8f0d18de 66 return (EADDRNOTAVAIL);
5cdc4d65 67 if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
8075bb0e 68 return (EINVAL);
6d5b2d5f 69 if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 &&
12472eef
KM
70 ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 ||
71 (so->so_options & SO_ACCEPTCONN) == 0))
72 wild = INPLOOKUP_WILDCARD;
6d5b2d5f
MK
73 if (nam) {
74 sin = mtod(nam, struct sockaddr_in *);
75 if (nam->m_len != sizeof (*sin))
76 return (EINVAL);
77#ifdef notdef
78 /*
79 * We should check the family, but old programs
80 * incorrectly fail to initialize it.
81 */
82 if (sin->sin_family != AF_INET)
83 return (EAFNOSUPPORT);
84#endif
85 lport = sin->sin_port;
86 if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
87 /*
88 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
89 * allow complete duplication of binding if
90 * SO_REUSEPORT is set, or if SO_REUSEADDR is set
91 * and a multicast address is bound on both
92 * new and duplicated sockets.
93 */
94 if (so->so_options & SO_REUSEADDR)
95 reuseport = SO_REUSEADDR|SO_REUSEPORT;
96 } else if (sin->sin_addr.s_addr != INADDR_ANY) {
97 sin->sin_port = 0; /* yech... */
98 if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
99 return (EADDRNOTAVAIL);
100 }
101 if (lport) {
102 struct inpcb *t;
c124e997 103
6d5b2d5f
MK
104 /* GROSS */
105 if (ntohs(lport) < IPPORT_RESERVED &&
106 (error = suser(p->p_ucred, &p->p_acflag)))
107 return (error);
108 t = in_pcblookup(head, zeroin_addr, 0,
109 sin->sin_addr, lport, wild);
110 if (t && (reuseport & t->inp_socket->so_options) == 0)
111 return (EADDRINUSE);
112 }
113 inp->inp_laddr = sin->sin_addr;
4ad99bae 114 }
b454c3ea
BJ
115 if (lport == 0)
116 do {
f44e5691
MK
117 if (head->inp_lport++ < IPPORT_RESERVED ||
118 head->inp_lport > IPPORT_USERRESERVED)
1aa87517 119 head->inp_lport = IPPORT_RESERVED;
b454c3ea 120 lport = htons(head->inp_lport);
1aa87517 121 } while (in_pcblookup(head,
12472eef 122 zeroin_addr, 0, inp->inp_laddr, lport, wild));
4ad99bae 123 inp->inp_lport = lport;
4ad99bae 124 return (0);
af092e86
BJ
125}
126
1acff8ec
BJ
127/*
128 * Connect from a socket to a specified address.
129 * Both address and port must be specified in argument sin.
130 * If don't have a local address for this socket yet,
131 * then pick one.
132 */
8075bb0e 133in_pcbconnect(inp, nam)
552daad2 134 register struct inpcb *inp;
8075bb0e 135 struct mbuf *nam;
2b4b57cd 136{
5d305bdd 137 struct in_ifaddr *ia;
ee787340 138 struct sockaddr_in *ifaddr;
8075bb0e 139 register struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
2b4b57cd 140
8075bb0e
BJ
141 if (nam->m_len != sizeof (*sin))
142 return (EINVAL);
4ad99bae
BJ
143 if (sin->sin_family != AF_INET)
144 return (EAFNOSUPPORT);
5d305bdd 145 if (sin->sin_port == 0)
4ad99bae 146 return (EADDRNOTAVAIL);
5d305bdd 147 if (in_ifaddr) {
3f319daa
MK
148 /*
149 * If the destination address is INADDR_ANY,
150 * use the primary local address.
151 * If the supplied address is INADDR_BROADCAST,
152 * and the primary interface supports broadcast,
153 * choose the broadcast address for that interface.
154 */
5d305bdd 155#define satosin(sa) ((struct sockaddr_in *)(sa))
09ed489e
KS
156#define sintosa(sin) ((struct sockaddr *)(sin))
157#define ifatoia(ifa) ((struct in_ifaddr *)(ifa))
5d305bdd 158 if (sin->sin_addr.s_addr == INADDR_ANY)
3f319daa 159 sin->sin_addr = IA_SIN(in_ifaddr)->sin_addr;
c9aca561 160 else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
3f319daa
MK
161 (in_ifaddr->ia_ifp->if_flags & IFF_BROADCAST))
162 sin->sin_addr = satosin(&in_ifaddr->ia_broadaddr)->sin_addr;
5d305bdd 163 }
5cdc4d65 164 if (inp->inp_laddr.s_addr == INADDR_ANY) {
c198b4ed 165 register struct route *ro;
99578149 166
c198b4ed
MK
167 ia = (struct in_ifaddr *)0;
168 /*
169 * If route is known or can be allocated now,
170 * our src addr is taken from the i/f, else punt.
171 */
172 ro = &inp->inp_route;
173 if (ro->ro_rt &&
1bf75d4e
MK
174 (satosin(&ro->ro_dst)->sin_addr.s_addr !=
175 sin->sin_addr.s_addr ||
176 inp->inp_socket->so_options & SO_DONTROUTE)) {
c198b4ed
MK
177 RTFREE(ro->ro_rt);
178 ro->ro_rt = (struct rtentry *)0;
179 }
9f21d23f
MK
180 if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
181 (ro->ro_rt == (struct rtentry *)0 ||
d4538fe2 182 ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
c198b4ed
MK
183 /* No route yet, so try to acquire one */
184 ro->ro_dst.sa_family = AF_INET;
b4dc7708 185 ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
c198b4ed
MK
186 ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
187 sin->sin_addr;
188 rtalloc(ro);
ee787340 189 }
d4538fe2
MK
190 /*
191 * If we found a route, use the address
192 * corresponding to the outgoing interface
193 * unless it is the loopback (in case a route
194 * to our address on another net goes to loopback).
195 */
09ed489e
KS
196 if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK))
197 ia = ifatoia(ro->ro_rt->rt_ifa);
9f21d23f 198 if (ia == 0) {
1bf75d4e
MK
199 int fport = sin->sin_port;
200
201 sin->sin_port = 0;
09ed489e 202 ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin)));
9f21d23f 203 if (ia == 0)
09ed489e
KS
204 ia = ifatoia(ifa_ifwithnet(sintosa(sin)));
205 sin->sin_port = fport;
9f21d23f
MK
206 if (ia == 0)
207 ia = in_ifaddr;
208 if (ia == 0)
209 return (EADDRNOTAVAIL);
c198b4ed 210 }
d6fa15c2
KS
211 /*
212 * If the destination address is multicast and an outgoing
213 * interface has been set as a multicast option, use the
214 * address of that interface as our source address.
215 */
216 if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) &&
217 inp->inp_moptions != NULL) {
218 struct ip_moptions *imo;
09ed489e 219 struct ifnet *ifp;
d6fa15c2
KS
220
221 imo = inp->inp_moptions;
222 if (imo->imo_multicast_ifp != NULL) {
223 ifp = imo->imo_multicast_ifp;
224 for (ia = in_ifaddr; ia; ia = ia->ia_next)
225 if (ia->ia_ifp == ifp)
226 break;
227 if (ia == 0)
228 return (EADDRNOTAVAIL);
229 }
230 }
5d305bdd 231 ifaddr = (struct sockaddr_in *)&ia->ia_addr;
1aa87517
BJ
232 }
233 if (in_pcblookup(inp->inp_head,
1acff8ec
BJ
234 sin->sin_addr,
235 sin->sin_port,
ee787340 236 inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
1acff8ec
BJ
237 inp->inp_lport,
238 0))
b454c3ea 239 return (EADDRINUSE);
3cd2053b
SL
240 if (inp->inp_laddr.s_addr == INADDR_ANY) {
241 if (inp->inp_lport == 0)
8011f5df 242 (void)in_pcbbind(inp, (struct mbuf *)0);
ee787340 243 inp->inp_laddr = ifaddr->sin_addr;
3cd2053b 244 }
4ad99bae
BJ
245 inp->inp_faddr = sin->sin_addr;
246 inp->inp_fport = sin->sin_port;
2b4b57cd
BJ
247 return (0);
248}
249
405c9168
BJ
250in_pcbdisconnect(inp)
251 struct inpcb *inp;
252{
253
5cdc4d65 254 inp->inp_faddr.s_addr = INADDR_ANY;
ebcadd38 255 inp->inp_fport = 0;
8f0d18de 256 if (inp->inp_socket->so_state & SS_NOFDREF)
405c9168
BJ
257 in_pcbdetach(inp);
258}
259
260in_pcbdetach(inp)
af092e86
BJ
261 struct inpcb *inp;
262{
263 struct socket *so = inp->inp_socket;
264
ba55c9af
BJ
265 so->so_pcb = 0;
266 sofree(so);
c9aca561 267 if (inp->inp_options)
8011f5df 268 (void)m_free(inp->inp_options);
c124e997 269 if (inp->inp_route.ro_rt)
f6311fb6 270 rtfree(inp->inp_route.ro_rt);
d6fa15c2 271 ip_freemoptions(inp->inp_moptions);
7545cf09 272 remque(inp);
d6fa15c2 273 FREE(inp, M_PCB);
af092e86
BJ
274}
275
8075bb0e 276in_setsockaddr(inp, nam)
126472ab 277 register struct inpcb *inp;
8075bb0e 278 struct mbuf *nam;
126472ab 279{
2aa0644d 280 register struct sockaddr_in *sin;
8075bb0e
BJ
281
282 nam->m_len = sizeof (*sin);
283 sin = mtod(nam, struct sockaddr_in *);
126472ab
SL
284 bzero((caddr_t)sin, sizeof (*sin));
285 sin->sin_family = AF_INET;
b4dc7708 286 sin->sin_len = sizeof(*sin);
126472ab
SL
287 sin->sin_port = inp->inp_lport;
288 sin->sin_addr = inp->inp_laddr;
289}
290
a7343092 291in_setpeeraddr(inp, nam)
552daad2 292 struct inpcb *inp;
a7343092
SL
293 struct mbuf *nam;
294{
2aa0644d 295 register struct sockaddr_in *sin;
a7343092
SL
296
297 nam->m_len = sizeof (*sin);
298 sin = mtod(nam, struct sockaddr_in *);
299 bzero((caddr_t)sin, sizeof (*sin));
300 sin->sin_family = AF_INET;
b4dc7708 301 sin->sin_len = sizeof(*sin);
a7343092
SL
302 sin->sin_port = inp->inp_fport;
303 sin->sin_addr = inp->inp_faddr;
304}
305
72e4f44e 306/*
842b6bb5 307 * Pass some notification to all connections of a protocol
b1dd4cca
MK
308 * associated with address dst. The local address and/or port numbers
309 * may be specified to limit the search. The "usual action" will be
310 * taken, depending on the ctlinput cmd. The caller must filter any
311 * cmds that are uninteresting (e.g., no error in the map).
312 * Call the protocol specific routine (if any) to report
313 * any errors for each matching socket.
314 *
315 * Must be called at splnet.
72e4f44e 316 */
b1dd4cca 317in_pcbnotify(head, dst, fport, laddr, lport, cmd, notify)
72e4f44e 318 struct inpcb *head;
b1dd4cca
MK
319 struct sockaddr *dst;
320 u_short fport, lport;
321 struct in_addr laddr;
322 int cmd, (*notify)();
72e4f44e
SL
323{
324 register struct inpcb *inp, *oinp;
b1dd4cca
MK
325 struct in_addr faddr;
326 int errno;
327 int in_rtchange();
328 extern u_char inetctlerrmap[];
329
330 if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET)
331 return;
332 faddr = ((struct sockaddr_in *)dst)->sin_addr;
333 if (faddr.s_addr == INADDR_ANY)
334 return;
72e4f44e 335
b1dd4cca
MK
336 /*
337 * Redirects go to all references to the destination,
338 * and use in_rtchange to invalidate the route cache.
339 * Dead host indications: notify all references to the destination.
340 * Otherwise, if we have knowledge of the local port and address,
341 * deliver only to that socket.
342 */
343 if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
344 fport = 0;
345 lport = 0;
346 laddr.s_addr = 0;
347 if (cmd != PRC_HOSTDEAD)
348 notify = in_rtchange;
349 }
350 errno = inetctlerrmap[cmd];
72e4f44e 351 for (inp = head->inp_next; inp != head;) {
b1dd4cca
MK
352 if (inp->inp_faddr.s_addr != faddr.s_addr ||
353 inp->inp_socket == 0 ||
354 (lport && inp->inp_lport != lport) ||
355 (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) ||
356 (fport && inp->inp_fport != fport)) {
72e4f44e
SL
357 inp = inp->inp_next;
358 continue;
359 }
72e4f44e
SL
360 oinp = inp;
361 inp = inp->inp_next;
c9aca561 362 if (notify)
b6cdc71a 363 (*notify)(oinp, errno);
72e4f44e 364 }
72e4f44e
SL
365}
366
2ba2de86
MK
367/*
368 * Check for alternatives when higher level complains
369 * about service problems. For now, invalidate cached
370 * routing information. If the route was created dynamically
371 * (by a redirect), time to try a default gateway again.
372 */
373in_losing(inp)
374 struct inpcb *inp;
375{
376 register struct rtentry *rt;
400be97f 377 struct rt_addrinfo info;
2ba2de86
MK
378
379 if ((rt = inp->inp_route.ro_rt)) {
60da172c 380 inp->inp_route.ro_rt = 0;
400be97f
KS
381 bzero((caddr_t)&info, sizeof(info));
382 info.rti_info[RTAX_DST] =
383 (struct sockaddr *)&inp->inp_route.ro_dst;
384 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
385 info.rti_info[RTAX_NETMASK] = rt_mask(rt);
386 rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
2ba2de86 387 if (rt->rt_flags & RTF_DYNAMIC)
b4dc7708
KS
388 (void) rtrequest(RTM_DELETE, rt_key(rt),
389 rt->rt_gateway, rt_mask(rt), rt->rt_flags,
390 (struct rtentry **)0);
60da172c 391 else
2ba2de86
MK
392 /*
393 * A new route can be allocated
394 * the next time output is attempted.
395 */
60da172c 396 rtfree(rt);
2ba2de86
MK
397 }
398}
399
842b6bb5
MK
400/*
401 * After a routing change, flush old routing
402 * and allocate a (hopefully) better one.
403 */
404in_rtchange(inp)
2ba2de86 405 register struct inpcb *inp;
842b6bb5
MK
406{
407 if (inp->inp_route.ro_rt) {
408 rtfree(inp->inp_route.ro_rt);
409 inp->inp_route.ro_rt = 0;
410 /*
411 * A new route can be allocated the next time
412 * output is attempted.
413 */
414 }
842b6bb5
MK
415}
416
cdad2eb1 417struct inpcb *
ebcadd38 418in_pcblookup(head, faddr, fport, laddr, lport, flags)
af092e86 419 struct inpcb *head;
4ad99bae 420 struct in_addr faddr, laddr;
af092e86 421 u_short fport, lport;
ebcadd38 422 int flags;
af092e86 423{
1aa87517
BJ
424 register struct inpcb *inp, *match = 0;
425 int matchwild = 3, wildcard;
af092e86 426
405c9168 427 for (inp = head->inp_next; inp != head; inp = inp->inp_next) {
1aa87517 428 if (inp->inp_lport != lport)
405c9168 429 continue;
1aa87517 430 wildcard = 0;
5cdc4d65
SL
431 if (inp->inp_laddr.s_addr != INADDR_ANY) {
432 if (laddr.s_addr == INADDR_ANY)
1acff8ec
BJ
433 wildcard++;
434 else if (inp->inp_laddr.s_addr != laddr.s_addr)
1aa87517
BJ
435 continue;
436 } else {
5cdc4d65 437 if (laddr.s_addr != INADDR_ANY)
1aa87517
BJ
438 wildcard++;
439 }
5cdc4d65
SL
440 if (inp->inp_faddr.s_addr != INADDR_ANY) {
441 if (faddr.s_addr == INADDR_ANY)
1acff8ec
BJ
442 wildcard++;
443 else if (inp->inp_faddr.s_addr != faddr.s_addr ||
ebcadd38 444 inp->inp_fport != fport)
1aa87517
BJ
445 continue;
446 } else {
5cdc4d65 447 if (faddr.s_addr != INADDR_ANY)
1aa87517
BJ
448 wildcard++;
449 }
ebcadd38 450 if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0)
405c9168 451 continue;
1aa87517
BJ
452 if (wildcard < matchwild) {
453 match = inp;
454 matchwild = wildcard;
455 if (matchwild == 0)
456 break;
405c9168 457 }
1aa87517 458 }
405c9168 459 return (match);
af092e86 460}