FreeBSD/Linux Kernel Cross Reference
sys/netinet/in_pcb.c
1 /*
2 * Copyright (c) 1982, 1986, 1991, 1993, 1995
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)in_pcb.c 8.4 (Berkeley) 5/24/95
34 * $FreeBSD$
35 */
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/malloc.h>
40 #include <sys/mbuf.h>
41 #include <sys/protosw.h>
42 #include <sys/socket.h>
43 #include <sys/socketvar.h>
44 #include <sys/proc.h>
45 #include <sys/kernel.h>
46 #include <sys/sysctl.h>
47
48 #include <machine/limits.h>
49
50 #include <vm/vm_zone.h>
51
52 #include <net/if.h>
53 #include <net/route.h>
54
55 #include <netinet/in.h>
56 #include <netinet/in_pcb.h>
57 #include <netinet/in_var.h>
58 #include <netinet/ip_var.h>
59
60 struct in_addr zeroin_addr;
61
62 static void in_pcbremlists __P((struct inpcb *));
63
64 /*
65 * These configure the range of local port addresses assigned to
66 * "unspecified" outgoing connections/packets/whatever.
67 */
68 static int ipport_lowfirstauto = IPPORT_RESERVED - 1; /* 1023 */
69 static int ipport_lowlastauto = IPPORT_RESERVEDSTART; /* 600 */
70 static int ipport_firstauto = IPPORT_RESERVED; /* 1024 */
71 static int ipport_lastauto = IPPORT_USERRESERVED; /* 5000 */
72 static int ipport_hifirstauto = IPPORT_HIFIRSTAUTO; /* 49152 */
73 static int ipport_hilastauto = IPPORT_HILASTAUTO; /* 65535 */
74
75 #define RANGECHK(var, min, max) \
76 if ((var) < (min)) { (var) = (min); } \
77 else if ((var) > (max)) { (var) = (max); }
78
79 static int
80 sysctl_net_ipport_check SYSCTL_HANDLER_ARGS
81 {
82 int error = sysctl_handle_int(oidp,
83 oidp->oid_arg1, oidp->oid_arg2, req);
84 if (!error) {
85 RANGECHK(ipport_lowfirstauto, 1, IPPORT_RESERVED - 1);
86 RANGECHK(ipport_lowlastauto, 1, IPPORT_RESERVED - 1);
87 RANGECHK(ipport_firstauto, IPPORT_RESERVED, USHRT_MAX);
88 RANGECHK(ipport_lastauto, IPPORT_RESERVED, USHRT_MAX);
89 RANGECHK(ipport_hifirstauto, IPPORT_RESERVED, USHRT_MAX);
90 RANGECHK(ipport_hilastauto, IPPORT_RESERVED, USHRT_MAX);
91 }
92 return error;
93 }
94
95 #undef RANGECHK
96
97 SYSCTL_NODE(_net_inet_ip, IPPROTO_IP, portrange, CTLFLAG_RW, 0, "IP Ports");
98
99 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowfirst, CTLTYPE_INT|CTLFLAG_RW,
100 &ipport_lowfirstauto, 0, &sysctl_net_ipport_check, "I", "");
101 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowlast, CTLTYPE_INT|CTLFLAG_RW,
102 &ipport_lowlastauto, 0, &sysctl_net_ipport_check, "I", "");
103 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, first, CTLTYPE_INT|CTLFLAG_RW,
104 &ipport_firstauto, 0, &sysctl_net_ipport_check, "I", "");
105 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, last, CTLTYPE_INT|CTLFLAG_RW,
106 &ipport_lastauto, 0, &sysctl_net_ipport_check, "I", "");
107 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hifirst, CTLTYPE_INT|CTLFLAG_RW,
108 &ipport_hifirstauto, 0, &sysctl_net_ipport_check, "I", "");
109 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hilast, CTLTYPE_INT|CTLFLAG_RW,
110 &ipport_hilastauto, 0, &sysctl_net_ipport_check, "I", "");
111
112 /*
113 * in_pcb.c: manage the Protocol Control Blocks.
114 *
115 * NOTE: It is assumed that most of these functions will be called at
116 * splnet(). XXX - There are, unfortunately, a few exceptions to this
117 * rule that should be fixed.
118 */
119
120 /*
121 * Allocate a PCB and associate it with the socket.
122 */
123 int
124 in_pcballoc(so, pcbinfo, p)
125 struct socket *so;
126 struct inpcbinfo *pcbinfo;
127 struct proc *p;
128 {
129 register struct inpcb *inp;
130
131 inp = zalloci(pcbinfo->ipi_zone);
132 if (inp == NULL)
133 return (ENOBUFS);
134 bzero((caddr_t)inp, sizeof(*inp));
135 inp->inp_gencnt = ++pcbinfo->ipi_gencnt;
136 inp->inp_pcbinfo = pcbinfo;
137 inp->inp_socket = so;
138 LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list);
139 pcbinfo->ipi_count++;
140 so->so_pcb = (caddr_t)inp;
141 return (0);
142 }
143
144 int
145 in_pcbbind(inp, nam, p)
146 register struct inpcb *inp;
147 struct sockaddr *nam;
148 struct proc *p;
149 {
150 register struct socket *so = inp->inp_socket;
151 unsigned short *lastport;
152 struct sockaddr_in *sin;
153 struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
154 u_short lport = 0;
155 int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
156 int error;
157
158 if (TAILQ_EMPTY(&in_ifaddrhead)) /* XXX broken! */
159 return (EADDRNOTAVAIL);
160 if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
161 return (EINVAL);
162 if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
163 wild = 1;
164 if (nam) {
165 sin = (struct sockaddr_in *)nam;
166 if (nam->sa_len != sizeof (*sin))
167 return (EINVAL);
168 #ifdef notdef
169 /*
170 * We should check the family, but old programs
171 * incorrectly fail to initialize it.
172 */
173 if (sin->sin_family != AF_INET)
174 return (EAFNOSUPPORT);
175 #endif
176 lport = sin->sin_port;
177 if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
178 /*
179 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
180 * allow complete duplication of binding if
181 * SO_REUSEPORT is set, or if SO_REUSEADDR is set
182 * and a multicast address is bound on both
183 * new and duplicated sockets.
184 */
185 if (so->so_options & SO_REUSEADDR)
186 reuseport = SO_REUSEADDR|SO_REUSEPORT;
187 } else if (sin->sin_addr.s_addr != INADDR_ANY) {
188 sin->sin_port = 0; /* yech... */
189 if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
190 return (EADDRNOTAVAIL);
191 }
192 if (lport) {
193 struct inpcb *t;
194
195 /* GROSS */
196 if (ntohs(lport) < IPPORT_RESERVED && p &&
197 suser(p->p_ucred, &p->p_acflag))
198 return (EACCES);
199 if (so->so_cred && so->so_cred->p_ruid != 0 &&
200 !IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
201 t = in_pcblookup_local(inp->inp_pcbinfo,
202 sin->sin_addr, lport, INPLOOKUP_WILDCARD);
203 if (t &&
204 (ntohl(sin->sin_addr.s_addr) != INADDR_ANY ||
205 ntohl(t->inp_laddr.s_addr) != INADDR_ANY ||
206 (t->inp_socket->so_options &
207 SO_REUSEPORT) == 0) &&
208 (t->inp_socket->so_cred) &&
209 (so->so_cred->p_ruid !=
210 t->inp_socket->so_cred->p_ruid))
211 return (EADDRINUSE);
212 }
213 t = in_pcblookup_local(pcbinfo, sin->sin_addr,
214 lport, wild);
215 if (t && (reuseport & t->inp_socket->so_options) == 0)
216 return (EADDRINUSE);
217 }
218 inp->inp_laddr = sin->sin_addr;
219 }
220 if (lport == 0) {
221 ushort first, last;
222 int count;
223
224 inp->inp_flags |= INP_ANONPORT;
225
226 if (inp->inp_flags & INP_HIGHPORT) {
227 first = ipport_hifirstauto; /* sysctl */
228 last = ipport_hilastauto;
229 lastport = &pcbinfo->lasthi;
230 } else if (inp->inp_flags & INP_LOWPORT) {
231 if (p && (error = suser(p->p_ucred, &p->p_acflag)))
232 return error;
233 first = ipport_lowfirstauto; /* 1023 */
234 last = ipport_lowlastauto; /* 600 */
235 lastport = &pcbinfo->lastlow;
236 } else {
237 first = ipport_firstauto; /* sysctl */
238 last = ipport_lastauto;
239 lastport = &pcbinfo->lastport;
240 }
241 /*
242 * Simple check to ensure all ports are not used up causing
243 * a deadlock here.
244 *
245 * We split the two cases (up and down) so that the direction
246 * is not being tested on each round of the loop.
247 */
248 if (first > last) {
249 /*
250 * counting down
251 */
252 count = first - last;
253
254 do {
255 if (count-- < 0) { /* completely used? */
256 /*
257 * Undo any address bind that may have
258 * occurred above.
259 */
260 inp->inp_laddr.s_addr = INADDR_ANY;
261 return (EAGAIN);
262 }
263 --*lastport;
264 if (*lastport > first || *lastport < last)
265 *lastport = first;
266 lport = htons(*lastport);
267 } while (in_pcblookup_local(pcbinfo,
268 inp->inp_laddr, lport, wild));
269 } else {
270 /*
271 * counting up
272 */
273 count = last - first;
274
275 do {
276 if (count-- < 0) { /* completely used? */
277 /*
278 * Undo any address bind that may have
279 * occurred above.
280 */
281 inp->inp_laddr.s_addr = INADDR_ANY;
282 return (EAGAIN);
283 }
284 ++*lastport;
285 if (*lastport < first || *lastport > last)
286 *lastport = first;
287 lport = htons(*lastport);
288 } while (in_pcblookup_local(pcbinfo,
289 inp->inp_laddr, lport, wild));
290 }
291 }
292 inp->inp_lport = lport;
293 if (in_pcbinshash(inp) != 0) {
294 inp->inp_laddr.s_addr = INADDR_ANY;
295 inp->inp_lport = 0;
296 return (EAGAIN);
297 }
298 return (0);
299 }
300
301 /*
302 * Transform old in_pcbconnect() into an inner subroutine for new
303 * in_pcbconnect(): Do some validity-checking on the remote
304 * address (in mbuf 'nam') and then determine local host address
305 * (i.e., which interface) to use to access that remote host.
306 *
307 * This preserves definition of in_pcbconnect(), while supporting a
308 * slightly different version for T/TCP. (This is more than
309 * a bit of a kludge, but cleaning up the internal interfaces would
310 * have forced minor changes in every protocol).
311 */
312
313 int
314 in_pcbladdr(inp, nam, plocal_sin)
315 register struct inpcb *inp;
316 struct sockaddr *nam;
317 struct sockaddr_in **plocal_sin;
318 {
319 struct in_ifaddr *ia;
320 register struct sockaddr_in *sin = (struct sockaddr_in *)nam;
321
322 if (nam->sa_len != sizeof (*sin))
323 return (EINVAL);
324 if (sin->sin_family != AF_INET)
325 return (EAFNOSUPPORT);
326 if (sin->sin_port == 0)
327 return (EADDRNOTAVAIL);
328 if (!TAILQ_EMPTY(&in_ifaddrhead)) {
329 /*
330 * If the destination address is INADDR_ANY,
331 * use the primary local address.
332 * If the supplied address is INADDR_BROADCAST,
333 * and the primary interface supports broadcast,
334 * choose the broadcast address for that interface.
335 */
336 #define satosin(sa) ((struct sockaddr_in *)(sa))
337 #define sintosa(sin) ((struct sockaddr *)(sin))
338 #define ifatoia(ifa) ((struct in_ifaddr *)(ifa))
339 if (sin->sin_addr.s_addr == INADDR_ANY)
340 sin->sin_addr = IA_SIN(in_ifaddrhead.tqh_first)->sin_addr;
341 else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
342 (in_ifaddrhead.tqh_first->ia_ifp->if_flags & IFF_BROADCAST))
343 sin->sin_addr = satosin(&in_ifaddrhead.tqh_first->ia_broadaddr)->sin_addr;
344 }
345 if (inp->inp_laddr.s_addr == INADDR_ANY) {
346 register struct route *ro;
347
348 ia = (struct in_ifaddr *)0;
349 /*
350 * If route is known or can be allocated now,
351 * our src addr is taken from the i/f, else punt.
352 */
353 ro = &inp->inp_route;
354 if (ro->ro_rt &&
355 (satosin(&ro->ro_dst)->sin_addr.s_addr !=
356 sin->sin_addr.s_addr ||
357 inp->inp_socket->so_options & SO_DONTROUTE)) {
358 RTFREE(ro->ro_rt);
359 ro->ro_rt = (struct rtentry *)0;
360 }
361 if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
362 (ro->ro_rt == (struct rtentry *)0 ||
363 ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
364 /* No route yet, so try to acquire one */
365 ro->ro_dst.sa_family = AF_INET;
366 ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
367 ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
368 sin->sin_addr;
369 rtalloc(ro);
370 }
371 /*
372 * If we found a route, use the address
373 * corresponding to the outgoing interface
374 * unless it is the loopback (in case a route
375 * to our address on another net goes to loopback).
376 */
377 if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK))
378 ia = ifatoia(ro->ro_rt->rt_ifa);
379 if (ia == 0) {
380 u_short fport = sin->sin_port;
381
382 sin->sin_port = 0;
383 ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin)));
384 if (ia == 0)
385 ia = ifatoia(ifa_ifwithnet(sintosa(sin)));
386 sin->sin_port = fport;
387 if (ia == 0)
388 ia = in_ifaddrhead.tqh_first;
389 if (ia == 0)
390 return (EADDRNOTAVAIL);
391 }
392 /*
393 * If the destination address is multicast and an outgoing
394 * interface has been set as a multicast option, use the
395 * address of that interface as our source address.
396 */
397 if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) &&
398 inp->inp_moptions != NULL) {
399 struct ip_moptions *imo;
400 struct ifnet *ifp;
401
402 imo = inp->inp_moptions;
403 if (imo->imo_multicast_ifp != NULL) {
404 ifp = imo->imo_multicast_ifp;
405 for (ia = in_ifaddrhead.tqh_first; ia;
406 ia = ia->ia_link.tqe_next)
407 if (ia->ia_ifp == ifp)
408 break;
409 if (ia == 0)
410 return (EADDRNOTAVAIL);
411 }
412 }
413 /*
414 * Don't do pcblookup call here; return interface in plocal_sin
415 * and exit to caller, that will do the lookup.
416 */
417 *plocal_sin = &ia->ia_addr;
418
419 }
420 return(0);
421 }
422
423 /*
424 * Outer subroutine:
425 * Connect from a socket to a specified address.
426 * Both address and port must be specified in argument sin.
427 * If don't have a local address for this socket yet,
428 * then pick one.
429 */
430 int
431 in_pcbconnect(inp, nam, p)
432 register struct inpcb *inp;
433 struct sockaddr *nam;
434 struct proc *p;
435 {
436 struct sockaddr_in *ifaddr;
437 register struct sockaddr_in *sin = (struct sockaddr_in *)nam;
438 int error;
439
440 /*
441 * Call inner routine, to assign local interface address.
442 */
443 if (error = in_pcbladdr(inp, nam, &ifaddr))
444 return(error);
445
446 if (in_pcblookup_hash(inp->inp_pcbinfo, sin->sin_addr, sin->sin_port,
447 inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
448 inp->inp_lport, 0) != NULL) {
449 return (EADDRINUSE);
450 }
451 if (inp->inp_laddr.s_addr == INADDR_ANY) {
452 if (inp->inp_lport == 0) {
453 error = in_pcbbind(inp, (struct sockaddr *)0, p);
454 if (error)
455 return (error);
456 }
457 inp->inp_laddr = ifaddr->sin_addr;
458 }
459 inp->inp_faddr = sin->sin_addr;
460 inp->inp_fport = sin->sin_port;
461 in_pcbrehash(inp);
462 return (0);
463 }
464
465 void
466 in_pcbdisconnect(inp)
467 struct inpcb *inp;
468 {
469
470 inp->inp_faddr.s_addr = INADDR_ANY;
471 inp->inp_fport = 0;
472 in_pcbrehash(inp);
473 if (inp->inp_socket->so_state & SS_NOFDREF)
474 in_pcbdetach(inp);
475 }
476
477 void
478 in_pcbdetach(inp)
479 struct inpcb *inp;
480 {
481 struct socket *so = inp->inp_socket;
482 struct inpcbinfo *ipi = inp->inp_pcbinfo;
483
484 inp->inp_gencnt = ++ipi->ipi_gencnt;
485 in_pcbremlists(inp);
486 so->so_pcb = 0;
487 sofree(so);
488 if (inp->inp_options)
489 (void)m_free(inp->inp_options);
490 if (inp->inp_route.ro_rt)
491 rtfree(inp->inp_route.ro_rt);
492 ip_freemoptions(inp->inp_moptions);
493 zfreei(ipi->ipi_zone, inp);
494 }
495
496 /*
497 * The calling convention of in_setsockaddr() and in_setpeeraddr() was
498 * modified to match the pru_sockaddr() and pru_peeraddr() entry points
499 * in struct pr_usrreqs, so that protocols can just reference then directly
500 * without the need for a wrapper function. The socket must have a valid
501 * (i.e., non-nil) PCB, but it should be impossible to get an invalid one
502 * except through a kernel programming error, so it is acceptable to panic
503 * (or in this case trap) if the PCB is invalid. (Actually, we don't trap
504 * because there actually /is/ a programming error somewhere... XXX)
505 */
506 int
507 in_setsockaddr(so, nam)
508 struct socket *so;
509 struct sockaddr **nam;
510 {
511 int s;
512 register struct inpcb *inp;
513 register struct sockaddr_in *sin;
514
515 /*
516 * Do the malloc first in case it blocks.
517 */
518 MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME, M_WAITOK);
519 bzero(sin, sizeof *sin);
520 sin->sin_family = AF_INET;
521 sin->sin_len = sizeof(*sin);
522
523 s = splnet();
524 inp = sotoinpcb(so);
525 if (!inp) {
526 splx(s);
527 free(sin, M_SONAME);
528 return EINVAL;
529 }
530 sin->sin_port = inp->inp_lport;
531 sin->sin_addr = inp->inp_laddr;
532 splx(s);
533
534 *nam = (struct sockaddr *)sin;
535 return 0;
536 }
537
538 int
539 in_setpeeraddr(so, nam)
540 struct socket *so;
541 struct sockaddr **nam;
542 {
543 int s;
544 struct inpcb *inp;
545 register struct sockaddr_in *sin;
546
547 /*
548 * Do the malloc first in case it blocks.
549 */
550 MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME, M_WAITOK);
551 bzero((caddr_t)sin, sizeof (*sin));
552 sin->sin_family = AF_INET;
553 sin->sin_len = sizeof(*sin);
554
555 s = splnet();
556 inp = sotoinpcb(so);
557 if (!inp) {
558 splx(s);
559 free(sin, M_SONAME);
560 return EINVAL;
561 }
562 sin->sin_port = inp->inp_fport;
563 sin->sin_addr = inp->inp_faddr;
564 splx(s);
565
566 *nam = (struct sockaddr *)sin;
567 return 0;
568 }
569
570 /*
571 * Pass some notification to all connections of a protocol
572 * associated with address dst. The local address and/or port numbers
573 * may be specified to limit the search. The "usual action" will be
574 * taken, depending on the ctlinput cmd. The caller must filter any
575 * cmds that are uninteresting (e.g., no error in the map).
576 * Call the protocol specific routine (if any) to report
577 * any errors for each matching socket.
578 */
579 void
580 in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify)
581 struct inpcbhead *head;
582 struct sockaddr *dst;
583 u_int fport_arg, lport_arg;
584 struct in_addr laddr;
585 int cmd;
586 void (*notify) __P((struct inpcb *, int));
587 {
588 register struct inpcb *inp, *oinp;
589 struct in_addr faddr;
590 u_short fport = fport_arg, lport = lport_arg;
591 int errno, s;
592
593 if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET)
594 return;
595 faddr = ((struct sockaddr_in *)dst)->sin_addr;
596 if (faddr.s_addr == INADDR_ANY)
597 return;
598
599 errno = inetctlerrmap[cmd];
600 s = splnet();
601 for (inp = head->lh_first; inp != NULL;) {
602 if (inp->inp_faddr.s_addr != faddr.s_addr ||
603 inp->inp_socket == 0 || inp->inp_lport != lport ||
604 inp->inp_laddr.s_addr != laddr.s_addr ||
605 inp->inp_fport != fport) {
606 inp = inp->inp_list.le_next;
607 continue;
608 }
609 oinp = inp;
610 inp = inp->inp_list.le_next;
611 if (notify)
612 (*notify)(oinp, errno);
613 }
614 splx(s);
615 }
616
617 void
618 in_pcbnotifyall(head, dst, cmd, notify)
619 struct inpcbhead *head;
620 struct sockaddr *dst;
621 int cmd;
622 void (*notify) __P((struct inpcb *, int));
623 {
624 register struct inpcb *inp, *oinp;
625 struct in_addr faddr;
626 int errno, s;
627
628 if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET)
629 return;
630 faddr = ((struct sockaddr_in *)dst)->sin_addr;
631 if (faddr.s_addr == INADDR_ANY)
632 return;
633
634 errno = inetctlerrmap[cmd];
635 s = splnet();
636 for (inp = LIST_FIRST(head); inp != NULL;) {
637 #ifdef INET6
638 if ((inp->inp_vflag & INP_IPV4) == 0) {
639 inp = LIST_NEXT(inp, inp_list);
640 continue;
641 }
642 #endif
643 if (inp->inp_faddr.s_addr != faddr.s_addr || inp->inp_socket == 0) {
644 inp = LIST_NEXT(inp, inp_list);
645 continue;
646 }
647 oinp = inp;
648 inp = LIST_NEXT(inp, inp_list);
649 if (notify)
650 (*notify)(oinp, errno);
651 }
652 splx(s);
653 }
654
655 /*
656 * Check for alternatives when higher level complains
657 * about service problems. For now, invalidate cached
658 * routing information. If the route was created dynamically
659 * (by a redirect), time to try a default gateway again.
660 */
661 void
662 in_losing(inp)
663 struct inpcb *inp;
664 {
665 register struct rtentry *rt;
666 struct rt_addrinfo info;
667
668 if ((rt = inp->inp_route.ro_rt)) {
669 inp->inp_route.ro_rt = 0;
670 bzero((caddr_t)&info, sizeof(info));
671 info.rti_info[RTAX_DST] =
672 (struct sockaddr *)&inp->inp_route.ro_dst;
673 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
674 info.rti_info[RTAX_NETMASK] = rt_mask(rt);
675 rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
676 if (rt->rt_flags & RTF_DYNAMIC)
677 (void) rtrequest(RTM_DELETE, rt_key(rt),
678 rt->rt_gateway, rt_mask(rt), rt->rt_flags,
679 (struct rtentry **)0);
680 else
681 /*
682 * A new route can be allocated
683 * the next time output is attempted.
684 */
685 rtfree(rt);
686 }
687 }
688
689 /*
690 * After a routing change, flush old routing
691 * and allocate a (hopefully) better one.
692 */
693 void
694 in_rtchange(inp, errno)
695 register struct inpcb *inp;
696 int errno;
697 {
698 if (inp->inp_route.ro_rt) {
699 rtfree(inp->inp_route.ro_rt);
700 inp->inp_route.ro_rt = 0;
701 /*
702 * A new route can be allocated the next time
703 * output is attempted.
704 */
705 }
706 }
707
708 /*
709 * Lookup a PCB based on the local address and port.
710 */
711 struct inpcb *
712 in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay)
713 struct inpcbinfo *pcbinfo;
714 struct in_addr laddr;
715 u_int lport_arg;
716 int wild_okay;
717 {
718 register struct inpcb *inp;
719 int matchwild = 3, wildcard;
720 u_short lport = lport_arg;
721
722 if (!wild_okay) {
723 struct inpcbhead *head;
724 /*
725 * Look for an unconnected (wildcard foreign addr) PCB that
726 * matches the local address and port we're looking for.
727 */
728 head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
729 for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
730 if (inp->inp_faddr.s_addr == INADDR_ANY &&
731 inp->inp_laddr.s_addr == laddr.s_addr &&
732 inp->inp_lport == lport) {
733 /*
734 * Found.
735 */
736 return (inp);
737 }
738 }
739 /*
740 * Not found.
741 */
742 return (NULL);
743 } else {
744 struct inpcbporthead *porthash;
745 struct inpcbport *phd;
746 struct inpcb *match = NULL;
747 /*
748 * Best fit PCB lookup.
749 *
750 * First see if this local port is in use by looking on the
751 * port hash list.
752 */
753 porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport,
754 pcbinfo->porthashmask)];
755 for (phd = porthash->lh_first; phd != NULL; phd = phd->phd_hash.le_next) {
756 if (phd->phd_port == lport)
757 break;
758 }
759 if (phd != NULL) {
760 /*
761 * Port is in use by one or more PCBs. Look for best
762 * fit.
763 */
764 for (inp = phd->phd_pcblist.lh_first; inp != NULL;
765 inp = inp->inp_portlist.le_next) {
766 wildcard = 0;
767 if (inp->inp_faddr.s_addr != INADDR_ANY)
768 wildcard++;
769 if (inp->inp_laddr.s_addr != INADDR_ANY) {
770 if (laddr.s_addr == INADDR_ANY)
771 wildcard++;
772 else if (inp->inp_laddr.s_addr != laddr.s_addr)
773 continue;
774 } else {
775 if (laddr.s_addr != INADDR_ANY)
776 wildcard++;
777 }
778 if (wildcard < matchwild) {
779 match = inp;
780 matchwild = wildcard;
781 if (matchwild == 0) {
782 break;
783 }
784 }
785 }
786 }
787 return (match);
788 }
789 }
790
791 /*
792 * Lookup PCB in hash list.
793 */
794 struct inpcb *
795 in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard)
796 struct inpcbinfo *pcbinfo;
797 struct in_addr faddr, laddr;
798 u_int fport_arg, lport_arg;
799 int wildcard;
800 {
801 struct inpcbhead *head;
802 register struct inpcb *inp;
803 u_short fport = fport_arg, lport = lport_arg;
804
805 /*
806 * First look for an exact match.
807 */
808 head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)];
809 for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
810 if (inp->inp_faddr.s_addr == faddr.s_addr &&
811 inp->inp_laddr.s_addr == laddr.s_addr &&
812 inp->inp_fport == fport &&
813 inp->inp_lport == lport) {
814 /*
815 * Found.
816 */
817 return (inp);
818 }
819 }
820 if (wildcard) {
821 struct inpcb *local_wild = NULL;
822
823 head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
824 for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
825 if (inp->inp_faddr.s_addr == INADDR_ANY &&
826 inp->inp_lport == lport) {
827 if (inp->inp_laddr.s_addr == laddr.s_addr)
828 return (inp);
829 else if (inp->inp_laddr.s_addr == INADDR_ANY)
830 local_wild = inp;
831 }
832 }
833 return (local_wild);
834 }
835
836 /*
837 * Not found.
838 */
839 return (NULL);
840 }
841
842 /*
843 * Insert PCB onto various hash lists.
844 */
845 int
846 in_pcbinshash(inp)
847 struct inpcb *inp;
848 {
849 struct inpcbhead *pcbhash;
850 struct inpcbporthead *pcbporthash;
851 struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
852 struct inpcbport *phd;
853
854 pcbhash = &pcbinfo->hashbase[INP_PCBHASH(inp->inp_faddr.s_addr,
855 inp->inp_lport, inp->inp_fport, pcbinfo->hashmask)];
856
857 pcbporthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(inp->inp_lport,
858 pcbinfo->porthashmask)];
859
860 /*
861 * Go through port list and look for a head for this lport.
862 */
863 for (phd = pcbporthash->lh_first; phd != NULL; phd = phd->phd_hash.le_next) {
864 if (phd->phd_port == inp->inp_lport)
865 break;
866 }
867 /*
868 * If none exists, malloc one and tack it on.
869 */
870 if (phd == NULL) {
871 MALLOC(phd, struct inpcbport *, sizeof(struct inpcbport), M_PCB, M_NOWAIT);
872 if (phd == NULL) {
873 return (ENOBUFS); /* XXX */
874 }
875 phd->phd_port = inp->inp_lport;
876 LIST_INIT(&phd->phd_pcblist);
877 LIST_INSERT_HEAD(pcbporthash, phd, phd_hash);
878 }
879 inp->inp_phd = phd;
880 LIST_INSERT_HEAD(&phd->phd_pcblist, inp, inp_portlist);
881 LIST_INSERT_HEAD(pcbhash, inp, inp_hash);
882 return (0);
883 }
884
885 /*
886 * Move PCB to the proper hash bucket when { faddr, fport } have been
887 * changed. NOTE: This does not handle the case of the lport changing (the
888 * hashed port list would have to be updated as well), so the lport must
889 * not change after in_pcbinshash() has been called.
890 */
891 void
892 in_pcbrehash(inp)
893 struct inpcb *inp;
894 {
895 struct inpcbhead *head;
896
897 head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(inp->inp_faddr.s_addr,
898 inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)];
899
900 LIST_REMOVE(inp, inp_hash);
901 LIST_INSERT_HEAD(head, inp, inp_hash);
902 }
903
904 /*
905 * Remove PCB from various lists.
906 */
907 static void
908 in_pcbremlists(inp)
909 struct inpcb *inp;
910 {
911 inp->inp_gencnt = ++inp->inp_pcbinfo->ipi_gencnt;
912 if (inp->inp_lport) {
913 struct inpcbport *phd = inp->inp_phd;
914
915 LIST_REMOVE(inp, inp_hash);
916 LIST_REMOVE(inp, inp_portlist);
917 if (phd->phd_pcblist.lh_first == NULL) {
918 LIST_REMOVE(phd, phd_hash);
919 free(phd, M_PCB);
920 }
921 }
922 LIST_REMOVE(inp, inp_list);
923 inp->inp_pcbinfo->ipi_count--;
924 }
Cache object: f7d1d462e2a2dd757e385a7af5b89259
|