]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet/in_pcb.c
d12ef72b2bccf53a5b494b950597114677676c1e
[apple/xnu.git] / bsd / netinet / in_pcb.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * Copyright (c) 1982, 1986, 1991, 1993, 1995
24 * The Regents of the University of California. All rights reserved.
25 *
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
28 * are met:
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
34 * 3. All advertising materials mentioning features or use of this software
35 * must display the following acknowledgement:
36 * This product includes software developed by the University of
37 * California, Berkeley and its contributors.
38 * 4. Neither the name of the University nor the names of its contributors
39 * may be used to endorse or promote products derived from this software
40 * without specific prior written permission.
41 *
42 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52 * SUCH DAMAGE.
53 *
54 * @(#)in_pcb.c 8.4 (Berkeley) 5/24/95
55 */
56
57 #include <sys/param.h>
58 #include <sys/systm.h>
59 #include <sys/malloc.h>
60 #include <sys/mbuf.h>
61 #if INET6
62 #include <sys/domain.h>
63 #endif
64 #include <sys/protosw.h>
65 #include <sys/socket.h>
66 #include <sys/socketvar.h>
67 #include <sys/proc.h>
68 #include <sys/kernel.h>
69 #include <sys/sysctl.h>
70
71 #include <machine/limits.h>
72
73 #if ISFB31
74 #include <vm/vm_zone.h>
75 #else
76 #include <kern/zalloc.h>
77 #endif
78
79 #include <net/if.h>
80 #include <net/route.h>
81 #include <net/if_types.h>
82
83 #include <netinet/in.h>
84 #include <netinet/in_pcb.h>
85 #include <netinet/in_var.h>
86 #include <netinet/ip_var.h>
87 #if INET6
88 #include <netinet/ip6.h>
89 #include <netinet6/ip6_var.h>
90 #endif /* INET6 */
91
92 #include "faith.h"
93
94 #if IPSEC
95 #include <netinet6/ipsec.h>
96 #include <netkey/key.h>
97 #include <netkey/key_debug.h>
98 #endif /* IPSEC */
99
100 #include <sys/kdebug.h>
101
102
103 #define DBG_FNC_PCB_LOOKUP NETDBG_CODE(DBG_NETTCP, (6 << 8))
104 #define DBG_FNC_PCB_HLOOKUP NETDBG_CODE(DBG_NETTCP, ((6 << 8) | 1))
105
106 struct in_addr zeroin_addr;
107
108 void in_pcbremlists __P((struct inpcb *));
109 static void in_rtchange __P((struct inpcb *, int));
110
111
112 /*
113 * These configure the range of local port addresses assigned to
114 * "unspecified" outgoing connections/packets/whatever.
115 */
116 int ipport_lowfirstauto = IPPORT_RESERVED - 1; /* 1023 */
117 int ipport_lowlastauto = IPPORT_RESERVEDSTART; /* 600 */
118 int ipport_firstauto = IPPORT_HIFIRSTAUTO; /* 49152 */
119 int ipport_lastauto = IPPORT_HILASTAUTO; /* 65535 */
120 int ipport_hifirstauto = IPPORT_HIFIRSTAUTO; /* 49152 */
121 int ipport_hilastauto = IPPORT_HILASTAUTO; /* 65535 */
122
123 #define RANGECHK(var, min, max) \
124 if ((var) < (min)) { (var) = (min); } \
125 else if ((var) > (max)) { (var) = (max); }
126
127
128 static int
129 sysctl_net_ipport_check SYSCTL_HANDLER_ARGS
130 {
131 int error = sysctl_handle_int(oidp,
132 oidp->oid_arg1, oidp->oid_arg2, req);
133 if (!error) {
134 RANGECHK(ipport_lowfirstauto, 1, IPPORT_RESERVED - 1);
135 RANGECHK(ipport_lowlastauto, 1, IPPORT_RESERVED - 1);
136 RANGECHK(ipport_firstauto, IPPORT_RESERVED, USHRT_MAX);
137 RANGECHK(ipport_lastauto, IPPORT_RESERVED, USHRT_MAX);
138 RANGECHK(ipport_hifirstauto, IPPORT_RESERVED, USHRT_MAX);
139 RANGECHK(ipport_hilastauto, IPPORT_RESERVED, USHRT_MAX);
140 }
141 return error;
142 }
143
144 #undef RANGECHK
145
146 SYSCTL_NODE(_net_inet_ip, IPPROTO_IP, portrange, CTLFLAG_RW, 0, "IP Ports");
147
148 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowfirst, CTLTYPE_INT|CTLFLAG_RW,
149 &ipport_lowfirstauto, 0, &sysctl_net_ipport_check, "I", "");
150 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowlast, CTLTYPE_INT|CTLFLAG_RW,
151 &ipport_lowlastauto, 0, &sysctl_net_ipport_check, "I", "");
152 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, first, CTLTYPE_INT|CTLFLAG_RW,
153 &ipport_firstauto, 0, &sysctl_net_ipport_check, "I", "");
154 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, last, CTLTYPE_INT|CTLFLAG_RW,
155 &ipport_lastauto, 0, &sysctl_net_ipport_check, "I", "");
156 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hifirst, CTLTYPE_INT|CTLFLAG_RW,
157 &ipport_hifirstauto, 0, &sysctl_net_ipport_check, "I", "");
158 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hilast, CTLTYPE_INT|CTLFLAG_RW,
159 &ipport_hilastauto, 0, &sysctl_net_ipport_check, "I", "");
160
161 /*
162 * in_pcb.c: manage the Protocol Control Blocks.
163 *
164 * NOTE: It is assumed that most of these functions will be called at
165 * splnet(). XXX - There are, unfortunately, a few exceptions to this
166 * rule that should be fixed.
167 */
168
169 /*
170 * Allocate a PCB and associate it with the socket.
171 */
172 int
173 in_pcballoc(so, pcbinfo, p)
174 struct socket *so;
175 struct inpcbinfo *pcbinfo;
176 struct proc *p;
177 {
178 register struct inpcb *inp;
179 caddr_t temp;
180
181 if (so->cached_in_sock_layer == 0) {
182 #if TEMPDEBUG
183 printf("PCBALLOC calling zalloc for socket %x\n", so);
184 #endif
185 inp = (struct inpcb *) zalloc(pcbinfo->ipi_zone);
186 if (inp == NULL)
187 return (ENOBUFS);
188 bzero((caddr_t)inp, sizeof(*inp));
189 }
190 else {
191 #if TEMPDEBUG
192 printf("PCBALLOC reusing PCB for socket %x\n", so);
193 #endif
194 inp = (struct inpcb *) so->so_saved_pcb;
195 temp = inp->inp_saved_ppcb;
196 bzero((caddr_t) inp, sizeof(*inp));
197 inp->inp_saved_ppcb = temp;
198 }
199
200 inp->inp_gencnt = ++pcbinfo->ipi_gencnt;
201 inp->inp_pcbinfo = pcbinfo;
202 inp->inp_socket = so;
203 LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list);
204 pcbinfo->ipi_count++;
205 so->so_pcb = (caddr_t)inp;
206 return (0);
207 }
208
209 int
210 in_pcbbind(inp, nam, p)
211 register struct inpcb *inp;
212 struct sockaddr *nam;
213 struct proc *p;
214 {
215 register struct socket *so = inp->inp_socket;
216 u_short *lastport;
217 struct sockaddr_in *sin;
218 struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
219 u_short lport = 0;
220 int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
221 int error;
222
223 if (TAILQ_EMPTY(&in_ifaddrhead)) /* XXX broken! */
224 return (EADDRNOTAVAIL);
225 if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
226 return (EINVAL);
227 if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
228 wild = 1;
229 if (nam) {
230 sin = (struct sockaddr_in *)nam;
231 if (nam->sa_len != sizeof (*sin))
232 return (EINVAL);
233 #ifdef notdef
234 /*
235 * We should check the family, but old programs
236 * incorrectly fail to initialize it.
237 */
238 if (sin->sin_family != AF_INET)
239 return (EAFNOSUPPORT);
240 #endif
241 lport = sin->sin_port;
242 if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
243 /*
244 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
245 * allow complete duplication of binding if
246 * SO_REUSEPORT is set, or if SO_REUSEADDR is set
247 * and a multicast address is bound on both
248 * new and duplicated sockets.
249 */
250 if (so->so_options & SO_REUSEADDR)
251 reuseport = SO_REUSEADDR|SO_REUSEPORT;
252 } else if (sin->sin_addr.s_addr != INADDR_ANY) {
253 sin->sin_port = 0; /* yech... */
254 if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
255 return (EADDRNOTAVAIL);
256 }
257 if (lport) {
258 struct inpcb *t;
259
260 /* GROSS */
261 if (ntohs(lport) < IPPORT_RESERVED && p &&
262 suser(p->p_ucred, &p->p_acflag))
263 return (EACCES);
264 if (so->so_uid &&
265 !IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
266 t = in_pcblookup_local(inp->inp_pcbinfo,
267 sin->sin_addr, lport, INPLOOKUP_WILDCARD);
268 if (t &&
269 (ntohl(sin->sin_addr.s_addr) != INADDR_ANY ||
270 ntohl(t->inp_laddr.s_addr) != INADDR_ANY ||
271 (t->inp_socket->so_options &
272 SO_REUSEPORT) == 0) &&
273 (so->so_uid != t->inp_socket->so_uid)) {
274 #if INET6
275 if (ip6_mapped_addr_on == 0 ||
276 ntohl(sin->sin_addr.s_addr) !=
277 INADDR_ANY ||
278 ntohl(t->inp_laddr.s_addr) !=
279 INADDR_ANY ||
280 INP_SOCKAF(so) ==
281 INP_SOCKAF(t->inp_socket))
282 #endif
283 return (EADDRINUSE);
284 }
285 }
286 t = in_pcblookup_local(pcbinfo, sin->sin_addr,
287 lport, wild);
288 if (t &&
289 (reuseport & t->inp_socket->so_options) == 0) {
290 #if INET6
291 if (ip6_mapped_addr_on == 0 ||
292 ntohl(sin->sin_addr.s_addr) !=
293 INADDR_ANY ||
294 ntohl(t->inp_laddr.s_addr) !=
295 INADDR_ANY ||
296 INP_SOCKAF(so) ==
297 INP_SOCKAF(t->inp_socket))
298 #endif
299 return (EADDRINUSE);
300 }
301 }
302 inp->inp_laddr = sin->sin_addr;
303 }
304 if (lport == 0) {
305 u_short first, last;
306 int count;
307
308 inp->inp_flags |= INP_ANONPORT;
309
310 if (inp->inp_flags & INP_HIGHPORT) {
311 first = ipport_hifirstauto; /* sysctl */
312 last = ipport_hilastauto;
313 lastport = &pcbinfo->lasthi;
314 } else if (inp->inp_flags & INP_LOWPORT) {
315 if (p && (error = suser(p->p_ucred, &p->p_acflag)))
316 return error;
317 first = ipport_lowfirstauto; /* 1023 */
318 last = ipport_lowlastauto; /* 600 */
319 lastport = &pcbinfo->lastlow;
320 } else {
321 first = ipport_firstauto; /* sysctl */
322 last = ipport_lastauto;
323 lastport = &pcbinfo->lastport;
324 }
325 /*
326 * Simple check to ensure all ports are not used up causing
327 * a deadlock here.
328 *
329 * We split the two cases (up and down) so that the direction
330 * is not being tested on each round of the loop.
331 */
332 if (first > last) {
333 /*
334 * counting down
335 */
336 count = first - last;
337
338 do {
339 if (count-- < 0) { /* completely used? */
340 /*
341 * Undo any address bind that may have
342 * occurred above.
343 */
344 inp->inp_laddr.s_addr = INADDR_ANY;
345 return (EAGAIN);
346 }
347 --*lastport;
348 if (*lastport > first || *lastport < last)
349 *lastport = first;
350 lport = htons(*lastport);
351 } while (in_pcblookup_local(pcbinfo,
352 inp->inp_laddr, lport, wild));
353 } else {
354 /*
355 * counting up
356 */
357 count = last - first;
358
359 do {
360 if (count-- < 0) { /* completely used? */
361 /*
362 * Undo any address bind that may have
363 * occurred above.
364 */
365 inp->inp_laddr.s_addr = INADDR_ANY;
366 return (EAGAIN);
367 }
368 ++*lastport;
369 if (*lastport < first || *lastport > last)
370 *lastport = first;
371 lport = htons(*lastport);
372 } while (in_pcblookup_local(pcbinfo,
373 inp->inp_laddr, lport, wild));
374 }
375 }
376 inp->inp_lport = lport;
377 if (in_pcbinshash(inp) != 0) {
378 inp->inp_laddr.s_addr = INADDR_ANY;
379 inp->inp_lport = 0;
380 return (EAGAIN);
381 }
382 return (0);
383 }
384
385 /*
386 * Transform old in_pcbconnect() into an inner subroutine for new
387 * in_pcbconnect(): Do some validity-checking on the remote
388 * address (in mbuf 'nam') and then determine local host address
389 * (i.e., which interface) to use to access that remote host.
390 *
391 * This preserves definition of in_pcbconnect(), while supporting a
392 * slightly different version for T/TCP. (This is more than
393 * a bit of a kludge, but cleaning up the internal interfaces would
394 * have forced minor changes in every protocol).
395 */
396
397 int
398 in_pcbladdr(inp, nam, plocal_sin)
399 register struct inpcb *inp;
400 struct sockaddr *nam;
401 struct sockaddr_in **plocal_sin;
402 {
403 struct in_ifaddr *ia;
404 register struct sockaddr_in *sin = (struct sockaddr_in *)nam;
405
406 if (nam->sa_len != sizeof (*sin))
407 return (EINVAL);
408 if (sin->sin_family != AF_INET)
409 return (EAFNOSUPPORT);
410 if (sin->sin_port == 0)
411 return (EADDRNOTAVAIL);
412 if (!TAILQ_EMPTY(&in_ifaddrhead)) {
413 /*
414 * If the destination address is INADDR_ANY,
415 * use the primary local address.
416 * If the supplied address is INADDR_BROADCAST,
417 * and the primary interface supports broadcast,
418 * choose the broadcast address for that interface.
419 */
420 #define satosin(sa) ((struct sockaddr_in *)(sa))
421 #define sintosa(sin) ((struct sockaddr *)(sin))
422 #define ifatoia(ifa) ((struct in_ifaddr *)(ifa))
423 if (sin->sin_addr.s_addr == INADDR_ANY)
424 sin->sin_addr = IA_SIN(in_ifaddrhead.tqh_first)->sin_addr;
425 else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
426 (in_ifaddrhead.tqh_first->ia_ifp->if_flags & IFF_BROADCAST))
427 sin->sin_addr = satosin(&in_ifaddrhead.tqh_first->ia_broadaddr)->sin_addr;
428 }
429 if (inp->inp_laddr.s_addr == INADDR_ANY) {
430 register struct route *ro;
431
432 ia = (struct in_ifaddr *)0;
433 /*
434 * If route is known or can be allocated now,
435 * our src addr is taken from the i/f, else punt.
436 */
437 ro = &inp->inp_route;
438 if (ro->ro_rt &&
439 (satosin(&ro->ro_dst)->sin_addr.s_addr !=
440 sin->sin_addr.s_addr ||
441 inp->inp_socket->so_options & SO_DONTROUTE)) {
442 RTFREE(ro->ro_rt);
443 ro->ro_rt = (struct rtentry *)0;
444 }
445 if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
446 (ro->ro_rt == (struct rtentry *)0 ||
447 ro->ro_rt->rt_ifp == (struct ifnet *)0)) {
448 /* No route yet, so try to acquire one */
449 ro->ro_dst.sa_family = AF_INET;
450 ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
451 ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
452 sin->sin_addr;
453 rtalloc(ro);
454 }
455 /*
456 * If we found a route, use the address
457 * corresponding to the outgoing interface
458 * unless it is the loopback (in case a route
459 * to our address on another net goes to loopback).
460 */
461 if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK))
462 ia = ifatoia(ro->ro_rt->rt_ifa);
463 if (ia == 0) {
464 u_short fport = sin->sin_port;
465
466 sin->sin_port = 0;
467 ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin)));
468 if (ia == 0)
469 ia = ifatoia(ifa_ifwithnet(sintosa(sin)));
470 sin->sin_port = fport;
471 if (ia == 0)
472 ia = in_ifaddrhead.tqh_first;
473 if (ia == 0)
474 return (EADDRNOTAVAIL);
475 }
476 /*
477 * If the destination address is multicast and an outgoing
478 * interface has been set as a multicast option, use the
479 * address of that interface as our source address.
480 */
481 if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) &&
482 inp->inp_moptions != NULL) {
483 struct ip_moptions *imo;
484 struct ifnet *ifp;
485
486 imo = inp->inp_moptions;
487 if (imo->imo_multicast_ifp != NULL) {
488 ifp = imo->imo_multicast_ifp;
489 for (ia = in_ifaddrhead.tqh_first; ia;
490 ia = ia->ia_link.tqe_next)
491 if (ia->ia_ifp == ifp)
492 break;
493 if (ia == 0)
494 return (EADDRNOTAVAIL);
495 }
496 }
497 /*
498 * Don't do pcblookup call here; return interface in plocal_sin
499 * and exit to caller, that will do the lookup.
500 */
501 *plocal_sin = &ia->ia_addr;
502
503 }
504 return(0);
505 }
506
507 /*
508 * Outer subroutine:
509 * Connect from a socket to a specified address.
510 * Both address and port must be specified in argument sin.
511 * If don't have a local address for this socket yet,
512 * then pick one.
513 */
514 int
515 in_pcbconnect(inp, nam, p)
516 register struct inpcb *inp;
517 struct sockaddr *nam;
518 struct proc *p;
519 {
520 struct sockaddr_in *ifaddr;
521 register struct sockaddr_in *sin = (struct sockaddr_in *)nam;
522 int error;
523
524 /*
525 * Call inner routine, to assign local interface address.
526 */
527 if ((error = in_pcbladdr(inp, nam, &ifaddr)) != 0)
528 return(error);
529
530 if (in_pcblookup_hash(inp->inp_pcbinfo, sin->sin_addr, sin->sin_port,
531 inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
532 inp->inp_lport, 0, NULL) != NULL) {
533 return (EADDRINUSE);
534 }
535 if (inp->inp_laddr.s_addr == INADDR_ANY) {
536 if (inp->inp_lport == 0)
537 (void)in_pcbbind(inp, (struct sockaddr *)0, p);
538 inp->inp_laddr = ifaddr->sin_addr;
539 }
540 inp->inp_faddr = sin->sin_addr;
541 inp->inp_fport = sin->sin_port;
542 in_pcbrehash(inp);
543 return (0);
544 }
545
546 void
547 in_pcbdisconnect(inp)
548 struct inpcb *inp;
549 {
550
551 inp->inp_faddr.s_addr = INADDR_ANY;
552 inp->inp_fport = 0;
553 in_pcbrehash(inp);
554 if (inp->inp_socket->so_state & SS_NOFDREF)
555 in_pcbdetach(inp);
556 }
557
558 void
559 in_pcbdetach(inp)
560 struct inpcb *inp;
561 {
562 struct socket *so = inp->inp_socket;
563 struct inpcbinfo *ipi = inp->inp_pcbinfo;
564
565 #if IPSEC
566 ipsec4_delete_pcbpolicy(inp);
567 #endif /*IPSEC*/
568 inp->inp_gencnt = ++ipi->ipi_gencnt;
569 in_pcbremlists(inp);
570
571 #if TEMPDEBUG
572 if (so->cached_in_sock_layer)
573 printf("PCB_DETACH for cached socket %x\n", so);
574 else
575 printf("PCB_DETACH for allocated socket %x\n", so);
576 #endif
577
578 so->so_pcb = 0;
579
580 if (inp->inp_options)
581 (void)m_free(inp->inp_options);
582 if (inp->inp_route.ro_rt)
583 rtfree(inp->inp_route.ro_rt);
584 ip_freemoptions(inp->inp_moptions);
585 if (so->cached_in_sock_layer)
586 so->so_saved_pcb = (caddr_t) inp;
587 else
588 zfree(ipi->ipi_zone, (vm_offset_t) inp);
589
590 sofree(so);
591 }
592
593 /*
594 * The calling convention of in_setsockaddr() and in_setpeeraddr() was
595 * modified to match the pru_sockaddr() and pru_peeraddr() entry points
596 * in struct pr_usrreqs, so that protocols can just reference then directly
597 * without the need for a wrapper function. The socket must have a valid
598 * (i.e., non-nil) PCB, but it should be impossible to get an invalid one
599 * except through a kernel programming error, so it is acceptable to panic
600 * (or in this case trap) if the PCB is invalid. (Actually, we don't trap
601 * because there actually /is/ a programming error somewhere... XXX)
602 */
603 int
604 in_setsockaddr(so, nam)
605 struct socket *so;
606 struct sockaddr **nam;
607 {
608 int s;
609 register struct inpcb *inp;
610 register struct sockaddr_in *sin;
611
612 /*
613 * Do the malloc first in case it blocks.
614 */
615 MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME, M_WAITOK);
616 if (sin == NULL)
617 return ENOBUFS;
618 bzero(sin, sizeof *sin);
619 sin->sin_family = AF_INET;
620 sin->sin_len = sizeof(*sin);
621
622 s = splnet();
623 inp = sotoinpcb(so);
624 if (!inp) {
625 splx(s);
626 FREE(sin, M_SONAME);
627 return EINVAL;
628 }
629 sin->sin_port = inp->inp_lport;
630 sin->sin_addr = inp->inp_laddr;
631 splx(s);
632
633 *nam = (struct sockaddr *)sin;
634 return 0;
635 }
636
637 int
638 in_setpeeraddr(so, nam)
639 struct socket *so;
640 struct sockaddr **nam;
641 {
642 int s;
643 struct inpcb *inp;
644 register struct sockaddr_in *sin;
645
646 /*
647 * Do the malloc first in case it blocks.
648 */
649 MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME, M_WAITOK);
650 if (sin == NULL)
651 return ENOBUFS;
652 bzero((caddr_t)sin, sizeof (*sin));
653 sin->sin_family = AF_INET;
654 sin->sin_len = sizeof(*sin);
655
656 s = splnet();
657 inp = sotoinpcb(so);
658 if (!inp) {
659 splx(s);
660 FREE(sin, M_SONAME);
661 return EINVAL;
662 }
663 sin->sin_port = inp->inp_fport;
664 sin->sin_addr = inp->inp_faddr;
665 splx(s);
666
667 *nam = (struct sockaddr *)sin;
668 return 0;
669 }
670
671 /*
672 * Pass some notification to all connections of a protocol
673 * associated with address dst. The local address and/or port numbers
674 * may be specified to limit the search. The "usual action" will be
675 * taken, depending on the ctlinput cmd. The caller must filter any
676 * cmds that are uninteresting (e.g., no error in the map).
677 * Call the protocol specific routine (if any) to report
678 * any errors for each matching socket.
679 */
680 void
681 in_pcbnotify(head, dst, fport_arg, laddr, lport_arg, cmd, notify)
682 struct inpcbhead *head;
683 struct sockaddr *dst;
684 u_int fport_arg, lport_arg;
685 struct in_addr laddr;
686 int cmd;
687 void (*notify) __P((struct inpcb *, int));
688 {
689 register struct inpcb *inp, *oinp;
690 struct in_addr faddr;
691 u_short fport = fport_arg, lport = lport_arg;
692 int errno, s;
693
694 if ((unsigned)cmd > PRC_NCMDS || dst->sa_family != AF_INET)
695 return;
696 faddr = ((struct sockaddr_in *)dst)->sin_addr;
697 if (faddr.s_addr == INADDR_ANY)
698 return;
699
700 /*
701 * Redirects go to all references to the destination,
702 * and use in_rtchange to invalidate the route cache.
703 * Dead host indications: notify all references to the destination.
704 * Otherwise, if we have knowledge of the local port and address,
705 * deliver only to that socket.
706 */
707 if (PRC_IS_REDIRECT(cmd) || cmd == PRC_HOSTDEAD) {
708 fport = 0;
709 lport = 0;
710 laddr.s_addr = 0;
711 if (cmd != PRC_HOSTDEAD)
712 notify = in_rtchange;
713 }
714 errno = inetctlerrmap[cmd];
715 s = splnet();
716 for (inp = head->lh_first; inp != NULL;) {
717 if ((inp->inp_vflag & INP_IPV4) == NULL) {
718 inp = LIST_NEXT(inp, inp_list);
719 continue;
720 }
721 if (inp->inp_faddr.s_addr != faddr.s_addr ||
722 inp->inp_socket == 0 ||
723 (lport && inp->inp_lport != lport) ||
724 (laddr.s_addr && inp->inp_laddr.s_addr != laddr.s_addr) ||
725 (fport && inp->inp_fport != fport)) {
726 inp = LIST_NEXT(inp, inp_list);
727 continue;
728 }
729 oinp = inp;
730 inp = LIST_NEXT(inp, inp_list);
731 if (notify)
732 (*notify)(oinp, errno);
733 }
734 splx(s);
735 }
736
737 /*
738 * Check for alternatives when higher level complains
739 * about service problems. For now, invalidate cached
740 * routing information. If the route was created dynamically
741 * (by a redirect), time to try a default gateway again.
742 */
743 void
744 in_losing(inp)
745 struct inpcb *inp;
746 {
747 register struct rtentry *rt;
748 struct rt_addrinfo info;
749
750 if ((rt = inp->inp_route.ro_rt)) {
751 inp->inp_route.ro_rt = 0;
752 bzero((caddr_t)&info, sizeof(info));
753 info.rti_info[RTAX_DST] =
754 (struct sockaddr *)&inp->inp_route.ro_dst;
755 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
756 info.rti_info[RTAX_NETMASK] = rt_mask(rt);
757 rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
758 if (rt->rt_flags & RTF_DYNAMIC)
759 (void) rtrequest(RTM_DELETE, rt_key(rt),
760 rt->rt_gateway, rt_mask(rt), rt->rt_flags,
761 (struct rtentry **)0);
762 else
763 /*
764 * A new route can be allocated
765 * the next time output is attempted.
766 */
767 rtfree(rt);
768 }
769 }
770
771 /*
772 * After a routing change, flush old routing
773 * and allocate a (hopefully) better one.
774 */
775 static void
776 in_rtchange(inp, errno)
777 register struct inpcb *inp;
778 int errno;
779 {
780 if (inp->inp_route.ro_rt) {
781 rtfree(inp->inp_route.ro_rt);
782 inp->inp_route.ro_rt = 0;
783 /*
784 * A new route can be allocated the next time
785 * output is attempted.
786 */
787 }
788 }
789
790 /*
791 * Lookup a PCB based on the local address and port.
792 */
793 struct inpcb *
794 in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay)
795 struct inpcbinfo *pcbinfo;
796 struct in_addr laddr;
797 u_int lport_arg;
798 int wild_okay;
799 {
800 register struct inpcb *inp;
801 int matchwild = 3, wildcard;
802 u_short lport = lport_arg;
803
804 KERNEL_DEBUG(DBG_FNC_PCB_LOOKUP | DBG_FUNC_START, 0,0,0,0,0);
805
806 if (!wild_okay) {
807 struct inpcbhead *head;
808 /*
809 * Look for an unconnected (wildcard foreign addr) PCB that
810 * matches the local address and port we're looking for.
811 */
812 head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
813 for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
814 if ((inp->inp_vflag & INP_IPV4) == NULL)
815 continue;
816 if (inp->inp_faddr.s_addr == INADDR_ANY &&
817 inp->inp_laddr.s_addr == laddr.s_addr &&
818 inp->inp_lport == lport) {
819 /*
820 * Found.
821 */
822 return (inp);
823 }
824 }
825 /*
826 * Not found.
827 */
828 KERNEL_DEBUG(DBG_FNC_PCB_LOOKUP | DBG_FUNC_END, 0,0,0,0,0);
829 return (NULL);
830 } else {
831 struct inpcbporthead *porthash;
832 struct inpcbport *phd;
833 struct inpcb *match = NULL;
834 /*
835 * Best fit PCB lookup.
836 *
837 * First see if this local port is in use by looking on the
838 * port hash list.
839 */
840 porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport,
841 pcbinfo->porthashmask)];
842 for (phd = porthash->lh_first; phd != NULL; phd = phd->phd_hash.le_next) {
843 if (phd->phd_port == lport)
844 break;
845 }
846 if (phd != NULL) {
847 /*
848 * Port is in use by one or more PCBs. Look for best
849 * fit.
850 */
851 for (inp = phd->phd_pcblist.lh_first; inp != NULL;
852 inp = inp->inp_portlist.le_next) {
853 wildcard = 0;
854 if ((inp->inp_vflag & INP_IPV4) == NULL)
855 continue;
856 if (inp->inp_faddr.s_addr != INADDR_ANY)
857 wildcard++;
858 if (inp->inp_laddr.s_addr != INADDR_ANY) {
859 if (laddr.s_addr == INADDR_ANY)
860 wildcard++;
861 else if (inp->inp_laddr.s_addr != laddr.s_addr)
862 continue;
863 } else {
864 if (laddr.s_addr != INADDR_ANY)
865 wildcard++;
866 }
867 if (wildcard < matchwild) {
868 match = inp;
869 matchwild = wildcard;
870 if (matchwild == 0) {
871 break;
872 }
873 }
874 }
875 }
876 KERNEL_DEBUG(DBG_FNC_PCB_LOOKUP | DBG_FUNC_END, match,0,0,0,0);
877 return (match);
878 }
879 }
880
881 /*
882 * Lookup PCB in hash list.
883 */
884 struct inpcb *
885 in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard, ifp)
886 struct inpcbinfo *pcbinfo;
887 struct in_addr faddr, laddr;
888 u_int fport_arg, lport_arg;
889 int wildcard;
890 struct ifnet *ifp;
891 {
892 struct inpcbhead *head;
893 register struct inpcb *inp;
894 u_short fport = fport_arg, lport = lport_arg;
895
896 /*
897 * We may have found the pcb in the last lookup - check this first.
898 */
899
900 if ((!IN_MULTICAST(laddr.s_addr)) && (pcbinfo->last_pcb)) {
901 if (faddr.s_addr == pcbinfo->last_pcb->inp_faddr.s_addr &&
902 laddr.s_addr == pcbinfo->last_pcb->inp_laddr.s_addr &&
903 fport_arg == pcbinfo->last_pcb->inp_fport &&
904 lport_arg == pcbinfo->last_pcb->inp_lport) {
905 /*
906 * Found.
907 */
908 return (pcbinfo->last_pcb);
909 }
910
911 pcbinfo->last_pcb = 0;
912 }
913
914 /*
915 * First look for an exact match.
916 */
917 head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)];
918 for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
919 if ((inp->inp_vflag & INP_IPV4) == NULL)
920 continue;
921 if (inp->inp_faddr.s_addr == faddr.s_addr &&
922 inp->inp_laddr.s_addr == laddr.s_addr &&
923 inp->inp_fport == fport &&
924 inp->inp_lport == lport) {
925 /*
926 * Found.
927 */
928 return (inp);
929 }
930 }
931 if (wildcard) {
932 struct inpcb *local_wild = NULL;
933 #if INET6
934 struct inpcb *local_wild_mapped = NULL;
935 #endif
936
937 head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
938 for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
939 if ((inp->inp_vflag & INP_IPV4) == NULL)
940 continue;
941 if (inp->inp_faddr.s_addr == INADDR_ANY &&
942 inp->inp_lport == lport) {
943 #if defined(NFAITH) && NFAITH > 0
944 if (ifp && ifp->if_type == IFT_FAITH &&
945 (inp->inp_flags & INP_FAITH) == 0)
946 continue;
947 #endif
948 if (inp->inp_laddr.s_addr == laddr.s_addr)
949 return (inp);
950 else if (inp->inp_laddr.s_addr == INADDR_ANY) {
951 #if INET6
952 if (INP_CHECK_SOCKAF(inp->inp_socket,
953 AF_INET6))
954 local_wild_mapped = inp;
955 else
956 #endif
957 local_wild = inp;
958 }
959 }
960 }
961 #if INET6
962 if (local_wild == NULL)
963 return (local_wild_mapped);
964 #endif
965 return (local_wild);
966 }
967
968 /*
969 * Not found.
970 */
971 return (NULL);
972 }
973
974 /*
975 * Insert PCB onto various hash lists.
976 */
977 int
978 in_pcbinshash(inp)
979 struct inpcb *inp;
980 {
981 struct inpcbhead *pcbhash;
982 struct inpcbporthead *pcbporthash;
983 struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
984 struct inpcbport *phd;
985 u_int32_t hashkey_faddr;
986
987 #if INET6
988 if (inp->inp_vflag & INP_IPV6)
989 hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */;
990 else
991 #endif /* INET6 */
992 hashkey_faddr = inp->inp_faddr.s_addr;
993
994 pcbhash = &pcbinfo->hashbase[INP_PCBHASH(hashkey_faddr,
995 inp->inp_lport, inp->inp_fport, pcbinfo->hashmask)];
996
997 pcbporthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(inp->inp_lport,
998 pcbinfo->porthashmask)];
999
1000 /*
1001 * Go through port list and look for a head for this lport.
1002 */
1003 for (phd = pcbporthash->lh_first; phd != NULL; phd = phd->phd_hash.le_next) {
1004 if (phd->phd_port == inp->inp_lport)
1005 break;
1006 }
1007 /*
1008 * If none exists, malloc one and tack it on.
1009 */
1010 if (phd == NULL) {
1011 MALLOC(phd, struct inpcbport *, sizeof(struct inpcbport), M_PCB, M_WAITOK);
1012 if (phd == NULL) {
1013 return (ENOBUFS); /* XXX */
1014 }
1015 phd->phd_port = inp->inp_lport;
1016 LIST_INIT(&phd->phd_pcblist);
1017 LIST_INSERT_HEAD(pcbporthash, phd, phd_hash);
1018 }
1019 inp->inp_phd = phd;
1020 LIST_INSERT_HEAD(&phd->phd_pcblist, inp, inp_portlist);
1021 LIST_INSERT_HEAD(pcbhash, inp, inp_hash);
1022 inp->hash_element = INP_PCBHASH(inp->inp_faddr.s_addr, inp->inp_lport,
1023 inp->inp_fport, pcbinfo->hashmask);
1024 return (0);
1025 }
1026
1027 /*
1028 * Move PCB to the proper hash bucket when { faddr, fport } have been
1029 * changed. NOTE: This does not handle the case of the lport changing (the
1030 * hashed port list would have to be updated as well), so the lport must
1031 * not change after in_pcbinshash() has been called.
1032 */
1033 void
1034 in_pcbrehash(inp)
1035 struct inpcb *inp;
1036 {
1037 struct inpcbhead *head;
1038 u_int32_t hashkey_faddr;
1039
1040 #if INET6
1041 if (inp->inp_vflag & INP_IPV6)
1042 hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */;
1043 else
1044 #endif /* INET6 */
1045 hashkey_faddr = inp->inp_faddr.s_addr;
1046
1047 head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(hashkey_faddr,
1048 inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)];
1049
1050 LIST_REMOVE(inp, inp_hash);
1051 LIST_INSERT_HEAD(head, inp, inp_hash);
1052 inp->hash_element = INP_PCBHASH(inp->inp_faddr.s_addr, inp->inp_lport,
1053 inp->inp_fport, inp->inp_pcbinfo->hashmask);
1054 }
1055
1056 /*
1057 * Remove PCB from various lists.
1058 */
1059 void
1060 in_pcbremlists(inp)
1061 struct inpcb *inp;
1062 {
1063 inp->inp_gencnt = ++inp->inp_pcbinfo->ipi_gencnt;
1064 if (inp == inp->inp_pcbinfo->last_pcb)
1065 inp->inp_pcbinfo->last_pcb = 0;
1066
1067 if (inp->inp_lport) {
1068 struct inpcbport *phd = inp->inp_phd;
1069
1070 LIST_REMOVE(inp, inp_hash);
1071 LIST_REMOVE(inp, inp_portlist);
1072 if (phd->phd_pcblist.lh_first == NULL) {
1073 LIST_REMOVE(phd, phd_hash);
1074 FREE(phd, M_PCB);
1075 }
1076 }
1077
1078 LIST_REMOVE(inp, inp_list);
1079 inp->inp_pcbinfo->ipi_count--;
1080 }
1081
1082 int
1083 in_pcb_grab_port __P((struct inpcbinfo *pcbinfo,
1084 u_short options,
1085 struct in_addr laddr,
1086 u_short *lport,
1087 struct in_addr faddr,
1088 u_short fport,
1089 u_int cookie,
1090 u_char owner_id))
1091 {
1092 struct inpcb *pcb;
1093 struct sockaddr_in sin;
1094 struct proc *p = current_proc();
1095 int stat;
1096
1097
1098 pcbinfo->nat_dummy_socket.so_pcb = 0;
1099 pcbinfo->nat_dummy_socket.so_options = 0;
1100 if (*lport) {
1101 /* The grabber wants a particular port */
1102
1103 if (faddr.s_addr || fport) {
1104 /*
1105 * This is either the second half of an active connect, or
1106 * it's from the acceptance of an incoming connection.
1107 */
1108 if (laddr.s_addr == 0) {
1109 return EINVAL;
1110 }
1111
1112 if (in_pcblookup_hash(pcbinfo, faddr, fport,
1113 laddr, *lport, 0, NULL) != NULL) {
1114 if (!(IN_MULTICAST(ntohl(laddr.s_addr)))) {
1115 return (EADDRINUSE);
1116 }
1117 }
1118
1119 stat = in_pcballoc(&pcbinfo->nat_dummy_socket, pcbinfo, p);
1120 if (stat)
1121 return stat;
1122 pcb = sotoinpcb(&pcbinfo->nat_dummy_socket);
1123 pcb->inp_vflag |= INP_IPV4;
1124
1125 pcb->inp_lport = *lport;
1126 pcb->inp_laddr.s_addr = laddr.s_addr;
1127
1128 pcb->inp_faddr = faddr;
1129 pcb->inp_fport = fport;
1130 in_pcbinshash(pcb);
1131 }
1132 else {
1133 /*
1134 * This is either a bind for a passive socket, or it's the
1135 * first part of bind-connect sequence (not likely since an
1136 * ephemeral port is usually used in this case). Or, it's
1137 * the result of a connection acceptance when the foreign
1138 * address/port cannot be provided (which requires the SO_REUSEADDR
1139 * flag if laddr is not multicast).
1140 */
1141
1142 stat = in_pcballoc(&pcbinfo->nat_dummy_socket, pcbinfo, p);
1143 if (stat)
1144 return stat;
1145 pcb = sotoinpcb(&pcbinfo->nat_dummy_socket);
1146 pcb->inp_vflag |= INP_IPV4;
1147
1148 pcbinfo->nat_dummy_socket.so_options = options;
1149 bzero(&sin, sizeof(struct sockaddr_in));
1150 sin.sin_len = sizeof(struct sockaddr_in);
1151 sin.sin_family = AF_INET;
1152 sin.sin_addr.s_addr = laddr.s_addr;
1153 sin.sin_port = *lport;
1154
1155 stat = in_pcbbind((struct inpcb *) pcbinfo->nat_dummy_socket.so_pcb,
1156 (struct sockaddr *) &sin, p);
1157 if (stat) {
1158 in_pcbdetach(pcb);
1159 return stat;
1160 }
1161 }
1162 }
1163 else {
1164 /* The grabber wants an ephemeral port */
1165
1166 stat = in_pcballoc(&pcbinfo->nat_dummy_socket, pcbinfo, p);
1167 if (stat)
1168 return stat;
1169 pcb = sotoinpcb(&pcbinfo->nat_dummy_socket);
1170 pcb->inp_vflag |= INP_IPV4;
1171
1172 bzero(&sin, sizeof(struct sockaddr_in));
1173 sin.sin_len = sizeof(struct sockaddr_in);
1174 sin.sin_family = AF_INET;
1175 sin.sin_addr.s_addr = laddr.s_addr;
1176 sin.sin_port = 0;
1177
1178 if (faddr.s_addr || fport) {
1179 /*
1180 * Not sure if this case will be used - could occur when connect
1181 * is called, skipping the bind.
1182 */
1183
1184 if (laddr.s_addr == 0) {
1185 in_pcbdetach(pcb);
1186 return EINVAL;
1187 }
1188
1189 stat = in_pcbbind((struct inpcb *) pcbinfo->nat_dummy_socket.so_pcb,
1190 (struct sockaddr *) &sin, p);
1191 if (stat) {
1192 in_pcbdetach(pcb);
1193 return stat;
1194 }
1195
1196 if (in_pcblookup_hash(pcbinfo, faddr, fport,
1197 pcb->inp_laddr, pcb->inp_lport, 0, NULL) != NULL) {
1198 in_pcbdetach(pcb);
1199 return (EADDRINUSE);
1200 }
1201
1202 pcb->inp_faddr = faddr;
1203 pcb->inp_fport = fport;
1204 in_pcbrehash(pcb);
1205 }
1206 else {
1207 /*
1208 * This is a simple bind of an ephemeral port. The local addr
1209 * may or may not be defined.
1210 */
1211
1212 stat = in_pcbbind((struct inpcb *) pcbinfo->nat_dummy_socket.so_pcb,
1213 (struct sockaddr *) &sin, p);
1214 if (stat) {
1215 in_pcbdetach(pcb);
1216 return stat;
1217 }
1218 }
1219 *lport = pcb->inp_lport;
1220 }
1221
1222
1223 pcb->nat_owner = owner_id;
1224 pcb->nat_cookie = cookie;
1225 pcb->inp_ppcb = (caddr_t) pcbinfo->dummy_cb;
1226 return 0;
1227 }
1228
1229 int
1230 in_pcb_letgo_port __P((struct inpcbinfo *pcbinfo, struct in_addr laddr, u_short lport,
1231 struct in_addr faddr, u_short fport, u_char owner_id))
1232 {
1233 struct inpcbhead *head;
1234 register struct inpcb *inp;
1235
1236
1237 /*
1238 * First look for an exact match.
1239 */
1240 head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)];
1241 for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
1242 if (inp->inp_faddr.s_addr == faddr.s_addr &&
1243 inp->inp_laddr.s_addr == laddr.s_addr &&
1244 inp->inp_fport == fport &&
1245 inp->inp_lport == lport &&
1246 inp->nat_owner == owner_id) {
1247 /*
1248 * Found.
1249 */
1250 in_pcbdetach(inp);
1251 return 0;
1252 }
1253 }
1254
1255 return ENOENT;
1256 }
1257
1258 u_char
1259 in_pcb_get_owner(struct inpcbinfo *pcbinfo,
1260 struct in_addr laddr, u_short lport,
1261 struct in_addr faddr, u_short fport,
1262 u_int *cookie)
1263
1264 {
1265 struct inpcb *inp;
1266 u_char owner_id = INPCB_NO_OWNER;
1267 struct inpcbport *phd;
1268 struct inpcbporthead *porthash;
1269
1270
1271 if (IN_MULTICAST(laddr.s_addr)) {
1272 /*
1273 * Walk through PCB's looking for registered
1274 * owners.
1275 */
1276
1277 porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport,
1278 pcbinfo->porthashmask)];
1279 for (phd = porthash->lh_first; phd != NULL; phd = phd->phd_hash.le_next) {
1280 if (phd->phd_port == lport)
1281 break;
1282 }
1283
1284 if (phd == 0) {
1285 return INPCB_NO_OWNER;
1286 }
1287
1288 owner_id = INPCB_NO_OWNER;
1289 for (inp = phd->phd_pcblist.lh_first; inp != NULL;
1290 inp = inp->inp_portlist.le_next) {
1291
1292 if (inp->inp_laddr.s_addr == laddr.s_addr) {
1293 if (inp->nat_owner == 0)
1294 owner_id |= INPCB_OWNED_BY_X;
1295 else
1296 owner_id |= inp->nat_owner;
1297 }
1298 }
1299
1300 return owner_id;
1301 }
1302 else {
1303 inp = in_pcblookup_hash(pcbinfo, faddr, fport,
1304 laddr, lport, 1, NULL);
1305 if (inp) {
1306 if (inp->nat_owner) {
1307 owner_id = inp->nat_owner;
1308 *cookie = inp->nat_cookie;
1309 }
1310 else {
1311 pcbinfo->last_pcb = inp;
1312 owner_id = INPCB_OWNED_BY_X;
1313 }
1314 }
1315 else
1316 owner_id = INPCB_NO_OWNER;
1317
1318 return owner_id;
1319 }
1320 }
1321
1322 int
1323 in_pcb_new_share_client(struct inpcbinfo *pcbinfo, u_char *owner_id)
1324 {
1325
1326 int i;
1327
1328
1329 for (i=0; i < INPCB_MAX_IDS; i++) {
1330 if ((pcbinfo->all_owners & (1 << i)) == 0) {
1331 pcbinfo->all_owners |= (1 << i);
1332 *owner_id = (1 << i);
1333 return 0;
1334 }
1335 }
1336
1337 return ENOSPC;
1338 }
1339
1340 int
1341 in_pcb_rem_share_client(struct inpcbinfo *pcbinfo, u_char owner_id)
1342 {
1343 struct inpcb *inp;
1344
1345
1346 if (pcbinfo->all_owners & owner_id) {
1347 pcbinfo->all_owners &= ~owner_id;
1348 for (inp = pcbinfo->listhead->lh_first; inp != NULL; inp = inp->inp_list.le_next) {
1349 if (inp->nat_owner & owner_id) {
1350 if (inp->nat_owner == owner_id)
1351 /*
1352 * Deallocate the pcb
1353 */
1354 in_pcbdetach(inp);
1355 else
1356 inp->nat_owner &= ~owner_id;
1357 }
1358 }
1359 }
1360 else {
1361 return ENOENT;
1362 }
1363
1364 return 0;
1365 }
1366
1367 void in_pcb_nat_init(struct inpcbinfo *pcbinfo, int afamily,
1368 int pfamily, int protocol)
1369 {
1370 bzero(&pcbinfo->nat_dummy_socket, sizeof(struct socket));
1371 pcbinfo->nat_dummy_socket.so_proto = pffindproto(afamily, pfamily, protocol);
1372 pcbinfo->all_owners = 0;
1373 }