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