]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet/in_pcb.c
3cb31d09f477e4ec8423c71114046ff389c346d1
[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 * 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
105 extern int ipsec_bypass;
106 #endif
107
108 extern 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
113 struct in_addr zeroin_addr;
114
115 /*
116 * These configure the range of local port addresses assigned to
117 * "unspecified" outgoing connections/packets/whatever.
118 */
119 int ipport_lowfirstauto = IPPORT_RESERVED - 1; /* 1023 */
120 int ipport_lowlastauto = IPPORT_RESERVEDSTART; /* 600 */
121 #ifndef __APPLE__
122 int ipport_firstauto = IPPORT_RESERVED; /* 1024 */
123 int ipport_lastauto = IPPORT_USERRESERVED; /* 5000 */
124 #else
125 int ipport_firstauto = IPPORT_HIFIRSTAUTO; /* 49152 */
126 int ipport_lastauto = IPPORT_HILASTAUTO; /* 65535 */
127 #endif
128 int ipport_hifirstauto = IPPORT_HIFIRSTAUTO; /* 49152 */
129 int 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
135 static int
136 sysctl_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
153 SYSCTL_NODE(_net_inet_ip, IPPROTO_IP, portrange, CTLFLAG_RW, 0, "IP Ports");
154
155 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowfirst, CTLTYPE_INT|CTLFLAG_RW,
156 &ipport_lowfirstauto, 0, &sysctl_net_ipport_check, "I", "");
157 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowlast, CTLTYPE_INT|CTLFLAG_RW,
158 &ipport_lowlastauto, 0, &sysctl_net_ipport_check, "I", "");
159 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, first, CTLTYPE_INT|CTLFLAG_RW,
160 &ipport_firstauto, 0, &sysctl_net_ipport_check, "I", "");
161 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, last, CTLTYPE_INT|CTLFLAG_RW,
162 &ipport_lastauto, 0, &sysctl_net_ipport_check, "I", "");
163 SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hifirst, CTLTYPE_INT|CTLFLAG_RW,
164 &ipport_hifirstauto, 0, &sysctl_net_ipport_check, "I", "");
165 SYSCTL_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 */
179 int
180 in_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
238 int
239 in_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
417 int
418 in_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 */
538 int
539 in_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
575 void
576 in_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
587 void
588 in_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
596 if (so->so_pcb == 0) /* we've been called twice, ignore */
597 return;
598
599 #if IPSEC
600 ipsec4_delete_pcbpolicy(inp);
601 #endif /*IPSEC*/
602 inp->inp_gencnt = ++ipi->ipi_gencnt;
603 in_pcbremlists(inp);
604
605 #if TEMPDEBUG
606 if (so->cached_in_sock_layer)
607 printf("PCB_DETACH for cached socket %x\n", so);
608 else
609 printf("PCB_DETACH for allocated socket %x\n", so);
610 #endif
611
612 so->so_pcb = 0;
613
614 if (inp->inp_options)
615 (void)m_free(inp->inp_options);
616 if (rt) {
617 /*
618 * route deletion requires reference count to be <= zero
619 */
620 if ((rt->rt_flags & RTF_DELCLONE) &&
621 (rt->rt_flags & RTF_WASCLONED) &&
622 (rt->rt_refcnt <= 1)) {
623 rtunref(rt);
624 rt->rt_flags &= ~RTF_UP;
625 rtrequest(RTM_DELETE, rt_key(rt),
626 rt->rt_gateway, rt_mask(rt),
627 rt->rt_flags, (struct rtentry **)0);
628 }
629 else {
630 rtfree(rt);
631 inp->inp_route.ro_rt = 0;
632 }
633 }
634 ip_freemoptions(inp->inp_moptions);
635 inp->inp_vflag = 0;
636 if (so->cached_in_sock_layer)
637 so->so_saved_pcb = (caddr_t) inp;
638 else
639 zfree(ipi->ipi_zone, (vm_offset_t) inp);
640
641 sofree(so);
642 }
643
644 /*
645 * The calling convention of in_setsockaddr() and in_setpeeraddr() was
646 * modified to match the pru_sockaddr() and pru_peeraddr() entry points
647 * in struct pr_usrreqs, so that protocols can just reference then directly
648 * without the need for a wrapper function. The socket must have a valid
649 * (i.e., non-nil) PCB, but it should be impossible to get an invalid one
650 * except through a kernel programming error, so it is acceptable to panic
651 * (or in this case trap) if the PCB is invalid. (Actually, we don't trap
652 * because there actually /is/ a programming error somewhere... XXX)
653 */
654 int
655 in_setsockaddr(so, nam)
656 struct socket *so;
657 struct sockaddr **nam;
658 {
659 int s;
660 register struct inpcb *inp;
661 register struct sockaddr_in *sin;
662
663 /*
664 * Do the malloc first in case it blocks.
665 */
666 MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME, M_WAITOK);
667 if (sin == NULL)
668 return ENOBUFS;
669 bzero(sin, sizeof *sin);
670 sin->sin_family = AF_INET;
671 sin->sin_len = sizeof(*sin);
672
673 s = splnet();
674 inp = sotoinpcb(so);
675 if (!inp) {
676 splx(s);
677 FREE(sin, M_SONAME);
678 return ECONNRESET;
679 }
680 sin->sin_port = inp->inp_lport;
681 sin->sin_addr = inp->inp_laddr;
682 splx(s);
683
684 *nam = (struct sockaddr *)sin;
685 return 0;
686 }
687
688 int
689 in_setpeeraddr(so, nam)
690 struct socket *so;
691 struct sockaddr **nam;
692 {
693 int s;
694 struct inpcb *inp;
695 register struct sockaddr_in *sin;
696
697 /*
698 * Do the malloc first in case it blocks.
699 */
700 MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME, M_WAITOK);
701 if (sin == NULL)
702 return ENOBUFS;
703 bzero((caddr_t)sin, sizeof (*sin));
704 sin->sin_family = AF_INET;
705 sin->sin_len = sizeof(*sin);
706
707 s = splnet();
708 inp = sotoinpcb(so);
709 if (!inp) {
710 splx(s);
711 FREE(sin, M_SONAME);
712 return ECONNRESET;
713 }
714 sin->sin_port = inp->inp_fport;
715 sin->sin_addr = inp->inp_faddr;
716 splx(s);
717
718 *nam = (struct sockaddr *)sin;
719 return 0;
720 }
721
722 void
723 in_pcbnotifyall(head, faddr, errno, notify)
724 struct inpcbhead *head;
725 struct in_addr faddr;
726 void (*notify) __P((struct inpcb *, int));
727 {
728 struct inpcb *inp, *ninp;
729 int s;
730
731 s = splnet();
732 for (inp = LIST_FIRST(head); inp != NULL; inp = ninp) {
733 ninp = LIST_NEXT(inp, inp_list);
734 #if INET6
735 if ((inp->inp_vflag & INP_IPV4) == 0)
736 continue;
737 #endif
738 if (inp->inp_faddr.s_addr != faddr.s_addr ||
739 inp->inp_socket == NULL)
740 continue;
741 (*notify)(inp, errno);
742 }
743 splx(s);
744 }
745
746 void
747 in_pcbpurgeif0(head, ifp)
748 struct inpcb *head;
749 struct ifnet *ifp;
750 {
751 struct inpcb *inp;
752 struct ip_moptions *imo;
753 int i, gap;
754
755 for (inp = head; inp != NULL; inp = LIST_NEXT(inp, inp_list)) {
756 imo = inp->inp_moptions;
757 if ((inp->inp_vflag & INP_IPV4) &&
758 imo != NULL) {
759 /*
760 * Unselect the outgoing interface if it is being
761 * detached.
762 */
763 if (imo->imo_multicast_ifp == ifp)
764 imo->imo_multicast_ifp = NULL;
765
766 /*
767 * Drop multicast group membership if we joined
768 * through the interface being detached.
769 */
770 for (i = 0, gap = 0; i < imo->imo_num_memberships;
771 i++) {
772 if (imo->imo_membership[i]->inm_ifp == ifp) {
773 in_delmulti(imo->imo_membership[i]);
774 gap++;
775 } else if (gap != 0)
776 imo->imo_membership[i - gap] =
777 imo->imo_membership[i];
778 }
779 imo->imo_num_memberships -= gap;
780 }
781 }
782 }
783
784 /*
785 * Check for alternatives when higher level complains
786 * about service problems. For now, invalidate cached
787 * routing information. If the route was created dynamically
788 * (by a redirect), time to try a default gateway again.
789 */
790 void
791 in_losing(inp)
792 struct inpcb *inp;
793 {
794 register struct rtentry *rt;
795 struct rt_addrinfo info;
796
797 if ((rt = inp->inp_route.ro_rt)) {
798 bzero((caddr_t)&info, sizeof(info));
799 info.rti_info[RTAX_DST] =
800 (struct sockaddr *)&inp->inp_route.ro_dst;
801 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
802 info.rti_info[RTAX_NETMASK] = rt_mask(rt);
803 rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
804 if (rt->rt_flags & RTF_DYNAMIC)
805 (void) rtrequest(RTM_DELETE, rt_key(rt),
806 rt->rt_gateway, rt_mask(rt), rt->rt_flags,
807 (struct rtentry **)0);
808 inp->inp_route.ro_rt = 0;
809 rtfree(rt);
810 /*
811 * A new route can be allocated
812 * the next time output is attempted.
813 */
814 }
815 }
816
817 /*
818 * After a routing change, flush old routing
819 * and allocate a (hopefully) better one.
820 */
821 void
822 in_rtchange(inp, errno)
823 register struct inpcb *inp;
824 int errno;
825 {
826 if (inp->inp_route.ro_rt) {
827 if (ifa_foraddr(inp->inp_laddr.s_addr) == NULL)
828 return; /* we can't remove the route now. not sure if still ok to use src */
829 rtfree(inp->inp_route.ro_rt);
830 inp->inp_route.ro_rt = 0;
831 /*
832 * A new route can be allocated the next time
833 * output is attempted.
834 */
835 }
836 }
837
838 /*
839 * Lookup a PCB based on the local address and port.
840 */
841 struct inpcb *
842 in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay)
843 struct inpcbinfo *pcbinfo;
844 struct in_addr laddr;
845 u_int lport_arg;
846 int wild_okay;
847 {
848 register struct inpcb *inp;
849 int matchwild = 3, wildcard;
850 u_short lport = lport_arg;
851
852 KERNEL_DEBUG(DBG_FNC_PCB_LOOKUP | DBG_FUNC_START, 0,0,0,0,0);
853
854 if (!wild_okay) {
855 struct inpcbhead *head;
856 /*
857 * Look for an unconnected (wildcard foreign addr) PCB that
858 * matches the local address and port we're looking for.
859 */
860 head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
861 LIST_FOREACH(inp, head, inp_hash) {
862 #if INET6
863 if ((inp->inp_vflag & INP_IPV4) == 0)
864 continue;
865 #endif
866 if (inp->inp_faddr.s_addr == INADDR_ANY &&
867 inp->inp_laddr.s_addr == laddr.s_addr &&
868 inp->inp_lport == lport) {
869 /*
870 * Found.
871 */
872 return (inp);
873 }
874 }
875 /*
876 * Not found.
877 */
878 KERNEL_DEBUG(DBG_FNC_PCB_LOOKUP | DBG_FUNC_END, 0,0,0,0,0);
879 return (NULL);
880 } else {
881 struct inpcbporthead *porthash;
882 struct inpcbport *phd;
883 struct inpcb *match = NULL;
884 /*
885 * Best fit PCB lookup.
886 *
887 * First see if this local port is in use by looking on the
888 * port hash list.
889 */
890 porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport,
891 pcbinfo->porthashmask)];
892 LIST_FOREACH(phd, porthash, phd_hash) {
893 if (phd->phd_port == lport)
894 break;
895 }
896 if (phd != NULL) {
897 /*
898 * Port is in use by one or more PCBs. Look for best
899 * fit.
900 */
901 LIST_FOREACH(inp, &phd->phd_pcblist, inp_portlist) {
902 wildcard = 0;
903 #if INET6
904 if ((inp->inp_vflag & INP_IPV4) == 0)
905 continue;
906 #endif
907 if (inp->inp_faddr.s_addr != INADDR_ANY)
908 wildcard++;
909 if (inp->inp_laddr.s_addr != INADDR_ANY) {
910 if (laddr.s_addr == INADDR_ANY)
911 wildcard++;
912 else if (inp->inp_laddr.s_addr != laddr.s_addr)
913 continue;
914 } else {
915 if (laddr.s_addr != INADDR_ANY)
916 wildcard++;
917 }
918 if (wildcard < matchwild) {
919 match = inp;
920 matchwild = wildcard;
921 if (matchwild == 0) {
922 break;
923 }
924 }
925 }
926 }
927 KERNEL_DEBUG(DBG_FNC_PCB_LOOKUP | DBG_FUNC_END, match,0,0,0,0);
928 return (match);
929 }
930 }
931
932 /*
933 * Lookup PCB in hash list.
934 */
935 struct inpcb *
936 in_pcblookup_hash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard,
937 ifp)
938 struct inpcbinfo *pcbinfo;
939 struct in_addr faddr, laddr;
940 u_int fport_arg, lport_arg;
941 int wildcard;
942 struct ifnet *ifp;
943 {
944 struct inpcbhead *head;
945 register struct inpcb *inp;
946 u_short fport = fport_arg, lport = lport_arg;
947
948 /*
949 * We may have found the pcb in the last lookup - check this first.
950 */
951
952 if ((!IN_MULTICAST(laddr.s_addr)) && (pcbinfo->last_pcb)) {
953 if (faddr.s_addr == pcbinfo->last_pcb->inp_faddr.s_addr &&
954 laddr.s_addr == pcbinfo->last_pcb->inp_laddr.s_addr &&
955 fport_arg == pcbinfo->last_pcb->inp_fport &&
956 lport_arg == pcbinfo->last_pcb->inp_lport) {
957 /*
958 * Found.
959 */
960 return (pcbinfo->last_pcb);
961 }
962
963 pcbinfo->last_pcb = 0;
964 }
965
966 /*
967 * First look for an exact match.
968 */
969 head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)];
970 LIST_FOREACH(inp, head, inp_hash) {
971 #if INET6
972 if ((inp->inp_vflag & INP_IPV4) == 0)
973 continue;
974 #endif
975 if (inp->inp_faddr.s_addr == faddr.s_addr &&
976 inp->inp_laddr.s_addr == laddr.s_addr &&
977 inp->inp_fport == fport &&
978 inp->inp_lport == lport) {
979 /*
980 * Found.
981 */
982 return (inp);
983 }
984 }
985 if (wildcard) {
986 struct inpcb *local_wild = NULL;
987 #if INET6
988 struct inpcb *local_wild_mapped = NULL;
989 #endif
990
991 head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
992 LIST_FOREACH(inp, head, inp_hash) {
993 #if INET6
994 if ((inp->inp_vflag & INP_IPV4) == 0)
995 continue;
996 #endif
997 if (inp->inp_faddr.s_addr == INADDR_ANY &&
998 inp->inp_lport == lport) {
999 #if defined(NFAITH) && NFAITH > 0
1000 if (ifp && ifp->if_type == IFT_FAITH &&
1001 (inp->inp_flags & INP_FAITH) == 0)
1002 continue;
1003 #endif
1004 if (inp->inp_laddr.s_addr == laddr.s_addr)
1005 return (inp);
1006 else if (inp->inp_laddr.s_addr == INADDR_ANY) {
1007 #if defined(INET6)
1008 if (INP_CHECK_SOCKAF(inp->inp_socket,
1009 AF_INET6))
1010 local_wild_mapped = inp;
1011 else
1012 #endif /* defined(INET6) */
1013 local_wild = inp;
1014 }
1015 }
1016 }
1017 #if defined(INET6)
1018 if (local_wild == NULL)
1019 return (local_wild_mapped);
1020 #endif /* defined(INET6) */
1021 return (local_wild);
1022 }
1023
1024 /*
1025 * Not found.
1026 */
1027 return (NULL);
1028 }
1029
1030 /*
1031 * Insert PCB onto various hash lists.
1032 */
1033 int
1034 in_pcbinshash(inp)
1035 struct inpcb *inp;
1036 {
1037 struct inpcbhead *pcbhash;
1038 struct inpcbporthead *pcbporthash;
1039 struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
1040 struct inpcbport *phd;
1041 u_int32_t hashkey_faddr;
1042
1043 #if INET6
1044 if (inp->inp_vflag & INP_IPV6)
1045 hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */;
1046 else
1047 #endif /* INET6 */
1048 hashkey_faddr = inp->inp_faddr.s_addr;
1049
1050 pcbhash = &pcbinfo->hashbase[INP_PCBHASH(hashkey_faddr,
1051 inp->inp_lport, inp->inp_fport, pcbinfo->hashmask)];
1052
1053 pcbporthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(inp->inp_lport,
1054 pcbinfo->porthashmask)];
1055
1056 /*
1057 * Go through port list and look for a head for this lport.
1058 */
1059 LIST_FOREACH(phd, pcbporthash, phd_hash) {
1060 if (phd->phd_port == inp->inp_lport)
1061 break;
1062 }
1063 /*
1064 * If none exists, malloc one and tack it on.
1065 */
1066 if (phd == NULL) {
1067 MALLOC(phd, struct inpcbport *, sizeof(struct inpcbport), M_PCB, M_WAITOK);
1068 if (phd == NULL) {
1069 return (ENOBUFS); /* XXX */
1070 }
1071 phd->phd_port = inp->inp_lport;
1072 LIST_INIT(&phd->phd_pcblist);
1073 LIST_INSERT_HEAD(pcbporthash, phd, phd_hash);
1074 }
1075 inp->inp_phd = phd;
1076 LIST_INSERT_HEAD(&phd->phd_pcblist, inp, inp_portlist);
1077 LIST_INSERT_HEAD(pcbhash, inp, inp_hash);
1078 #ifdef __APPLE__
1079 inp->hash_element = INP_PCBHASH(inp->inp_faddr.s_addr, inp->inp_lport,
1080 inp->inp_fport, pcbinfo->hashmask);
1081 #endif
1082 return (0);
1083 }
1084
1085 /*
1086 * Move PCB to the proper hash bucket when { faddr, fport } have been
1087 * changed. NOTE: This does not handle the case of the lport changing (the
1088 * hashed port list would have to be updated as well), so the lport must
1089 * not change after in_pcbinshash() has been called.
1090 */
1091 void
1092 in_pcbrehash(inp)
1093 struct inpcb *inp;
1094 {
1095 struct inpcbhead *head;
1096 u_int32_t hashkey_faddr;
1097
1098 #if INET6
1099 if (inp->inp_vflag & INP_IPV6)
1100 hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */;
1101 else
1102 #endif /* INET6 */
1103 hashkey_faddr = inp->inp_faddr.s_addr;
1104
1105 head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(hashkey_faddr,
1106 inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)];
1107
1108 LIST_REMOVE(inp, inp_hash);
1109 LIST_INSERT_HEAD(head, inp, inp_hash);
1110 #ifdef __APPLE__
1111 inp->hash_element = INP_PCBHASH(inp->inp_faddr.s_addr, inp->inp_lport,
1112 inp->inp_fport, inp->inp_pcbinfo->hashmask);
1113 #endif
1114 }
1115
1116 /*
1117 * Remove PCB from various lists.
1118 */
1119 void
1120 in_pcbremlists(inp)
1121 struct inpcb *inp;
1122 {
1123 inp->inp_gencnt = ++inp->inp_pcbinfo->ipi_gencnt;
1124 #ifdef __APPLE__
1125 if (inp == inp->inp_pcbinfo->last_pcb)
1126 inp->inp_pcbinfo->last_pcb = 0;
1127 #endif
1128
1129 if (inp->inp_lport) {
1130 struct inpcbport *phd = inp->inp_phd;
1131
1132 LIST_REMOVE(inp, inp_hash);
1133 LIST_REMOVE(inp, inp_portlist);
1134 if (phd != NULL && (LIST_FIRST(&phd->phd_pcblist) == NULL)) {
1135 LIST_REMOVE(phd, phd_hash);
1136 FREE(phd, M_PCB);
1137 }
1138 }
1139 LIST_REMOVE(inp, inp_list);
1140 inp->inp_pcbinfo->ipi_count--;
1141 }
1142
1143 int
1144 in_pcb_grab_port __P((struct inpcbinfo *pcbinfo,
1145 u_short options,
1146 struct in_addr laddr,
1147 u_short *lport,
1148 struct in_addr faddr,
1149 u_short fport,
1150 u_int cookie,
1151 u_char owner_id))
1152 {
1153 struct inpcb *pcb;
1154 struct sockaddr_in sin;
1155 struct proc *p = current_proc();
1156 int stat;
1157
1158
1159 pcbinfo->nat_dummy_socket.so_pcb = 0;
1160 pcbinfo->nat_dummy_socket.so_options = 0;
1161 if (*lport) {
1162 /* The grabber wants a particular port */
1163
1164 if (faddr.s_addr || fport) {
1165 /*
1166 * This is either the second half of an active connect, or
1167 * it's from the acceptance of an incoming connection.
1168 */
1169 if (laddr.s_addr == 0) {
1170 return EINVAL;
1171 }
1172
1173 if (in_pcblookup_hash(pcbinfo, faddr, fport,
1174 laddr, *lport, 0, NULL) != NULL) {
1175 if (!(IN_MULTICAST(ntohl(laddr.s_addr)))) {
1176 return (EADDRINUSE);
1177 }
1178 }
1179
1180 stat = in_pcballoc(&pcbinfo->nat_dummy_socket, pcbinfo, p);
1181 if (stat)
1182 return stat;
1183 pcb = sotoinpcb(&pcbinfo->nat_dummy_socket);
1184 pcb->inp_vflag |= INP_IPV4;
1185
1186 pcb->inp_lport = *lport;
1187 pcb->inp_laddr.s_addr = laddr.s_addr;
1188
1189 pcb->inp_faddr = faddr;
1190 pcb->inp_fport = fport;
1191 in_pcbinshash(pcb);
1192 }
1193 else {
1194 /*
1195 * This is either a bind for a passive socket, or it's the
1196 * first part of bind-connect sequence (not likely since an
1197 * ephemeral port is usually used in this case). Or, it's
1198 * the result of a connection acceptance when the foreign
1199 * address/port cannot be provided (which requires the SO_REUSEADDR
1200 * flag if laddr is not multicast).
1201 */
1202
1203 stat = in_pcballoc(&pcbinfo->nat_dummy_socket, pcbinfo, p);
1204 if (stat)
1205 return stat;
1206 pcb = sotoinpcb(&pcbinfo->nat_dummy_socket);
1207 pcb->inp_vflag |= INP_IPV4;
1208
1209 pcbinfo->nat_dummy_socket.so_options = options;
1210 bzero(&sin, sizeof(struct sockaddr_in));
1211 sin.sin_len = sizeof(struct sockaddr_in);
1212 sin.sin_family = AF_INET;
1213 sin.sin_addr.s_addr = laddr.s_addr;
1214 sin.sin_port = *lport;
1215
1216 stat = in_pcbbind((struct inpcb *) pcbinfo->nat_dummy_socket.so_pcb,
1217 (struct sockaddr *) &sin, p);
1218 if (stat) {
1219 in_pcbdetach(pcb);
1220 return stat;
1221 }
1222 }
1223 }
1224 else {
1225 /* The grabber wants an ephemeral port */
1226
1227 stat = in_pcballoc(&pcbinfo->nat_dummy_socket, pcbinfo, p);
1228 if (stat)
1229 return stat;
1230 pcb = sotoinpcb(&pcbinfo->nat_dummy_socket);
1231 pcb->inp_vflag |= INP_IPV4;
1232
1233 bzero(&sin, sizeof(struct sockaddr_in));
1234 sin.sin_len = sizeof(struct sockaddr_in);
1235 sin.sin_family = AF_INET;
1236 sin.sin_addr.s_addr = laddr.s_addr;
1237 sin.sin_port = 0;
1238
1239 if (faddr.s_addr || fport) {
1240 /*
1241 * Not sure if this case will be used - could occur when connect
1242 * is called, skipping the bind.
1243 */
1244
1245 if (laddr.s_addr == 0) {
1246 in_pcbdetach(pcb);
1247 return EINVAL;
1248 }
1249
1250 stat = in_pcbbind((struct inpcb *) pcbinfo->nat_dummy_socket.so_pcb,
1251 (struct sockaddr *) &sin, p);
1252 if (stat) {
1253 in_pcbdetach(pcb);
1254 return stat;
1255 }
1256
1257 if (in_pcblookup_hash(pcbinfo, faddr, fport,
1258 pcb->inp_laddr, pcb->inp_lport, 0, NULL) != NULL) {
1259 in_pcbdetach(pcb);
1260 return (EADDRINUSE);
1261 }
1262
1263 pcb->inp_faddr = faddr;
1264 pcb->inp_fport = fport;
1265 in_pcbrehash(pcb);
1266 }
1267 else {
1268 /*
1269 * This is a simple bind of an ephemeral port. The local addr
1270 * may or may not be defined.
1271 */
1272
1273 stat = in_pcbbind((struct inpcb *) pcbinfo->nat_dummy_socket.so_pcb,
1274 (struct sockaddr *) &sin, p);
1275 if (stat) {
1276 in_pcbdetach(pcb);
1277 return stat;
1278 }
1279 }
1280 *lport = pcb->inp_lport;
1281 }
1282
1283
1284 pcb->nat_owner = owner_id;
1285 pcb->nat_cookie = cookie;
1286 pcb->inp_ppcb = (caddr_t) pcbinfo->dummy_cb;
1287 return 0;
1288 }
1289
1290 int
1291 in_pcb_letgo_port __P((struct inpcbinfo *pcbinfo, struct in_addr laddr, u_short lport,
1292 struct in_addr faddr, u_short fport, u_char owner_id))
1293 {
1294 struct inpcbhead *head;
1295 register struct inpcb *inp;
1296
1297
1298 /*
1299 * First look for an exact match.
1300 */
1301 head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)];
1302 for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
1303 if (inp->inp_faddr.s_addr == faddr.s_addr &&
1304 inp->inp_laddr.s_addr == laddr.s_addr &&
1305 inp->inp_fport == fport &&
1306 inp->inp_lport == lport &&
1307 inp->nat_owner == owner_id) {
1308 /*
1309 * Found.
1310 */
1311 in_pcbdetach(inp);
1312 return 0;
1313 }
1314 }
1315
1316 return ENOENT;
1317 }
1318
1319 u_char
1320 in_pcb_get_owner(struct inpcbinfo *pcbinfo,
1321 struct in_addr laddr, u_short lport,
1322 struct in_addr faddr, u_short fport,
1323 u_int *cookie)
1324
1325 {
1326 struct inpcb *inp;
1327 u_char owner_id = INPCB_NO_OWNER;
1328 struct inpcbport *phd;
1329 struct inpcbporthead *porthash;
1330
1331
1332 if (IN_MULTICAST(laddr.s_addr)) {
1333 /*
1334 * Walk through PCB's looking for registered
1335 * owners.
1336 */
1337
1338 porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport,
1339 pcbinfo->porthashmask)];
1340 for (phd = porthash->lh_first; phd != NULL; phd = phd->phd_hash.le_next) {
1341 if (phd->phd_port == lport)
1342 break;
1343 }
1344
1345 if (phd == 0) {
1346 return INPCB_NO_OWNER;
1347 }
1348
1349 owner_id = INPCB_NO_OWNER;
1350 for (inp = phd->phd_pcblist.lh_first; inp != NULL;
1351 inp = inp->inp_portlist.le_next) {
1352
1353 if (inp->inp_laddr.s_addr == laddr.s_addr) {
1354 if (inp->nat_owner == 0)
1355 owner_id |= INPCB_OWNED_BY_X;
1356 else
1357 owner_id |= inp->nat_owner;
1358 }
1359 }
1360
1361 return owner_id;
1362 }
1363 else {
1364 inp = in_pcblookup_hash(pcbinfo, faddr, fport,
1365 laddr, lport, 1, NULL);
1366 if (inp) {
1367 if (inp->nat_owner) {
1368 owner_id = inp->nat_owner;
1369 *cookie = inp->nat_cookie;
1370 }
1371 else {
1372 pcbinfo->last_pcb = inp;
1373 owner_id = INPCB_OWNED_BY_X;
1374 }
1375 }
1376 else
1377 owner_id = INPCB_NO_OWNER;
1378
1379 return owner_id;
1380 }
1381 }
1382
1383 int
1384 in_pcb_new_share_client(struct inpcbinfo *pcbinfo, u_char *owner_id)
1385 {
1386
1387 int i;
1388
1389
1390 for (i=0; i < INPCB_MAX_IDS; i++) {
1391 if ((pcbinfo->all_owners & (1 << i)) == 0) {
1392 pcbinfo->all_owners |= (1 << i);
1393 *owner_id = (1 << i);
1394 return 0;
1395 }
1396 }
1397
1398 return ENOSPC;
1399 }
1400
1401 int
1402 in_pcb_rem_share_client(struct inpcbinfo *pcbinfo, u_char owner_id)
1403 {
1404 struct inpcb *inp;
1405
1406
1407 if (pcbinfo->all_owners & owner_id) {
1408 pcbinfo->all_owners &= ~owner_id;
1409 for (inp = pcbinfo->listhead->lh_first; inp != NULL; inp = inp->inp_list.le_next) {
1410 if (inp->nat_owner & owner_id) {
1411 if (inp->nat_owner == owner_id)
1412 /*
1413 * Deallocate the pcb
1414 */
1415 in_pcbdetach(inp);
1416 else
1417 inp->nat_owner &= ~owner_id;
1418 }
1419 }
1420 }
1421 else {
1422 return ENOENT;
1423 }
1424
1425 return 0;
1426 }
1427
1428
1429
1430 void in_pcb_nat_init(struct inpcbinfo *pcbinfo, int afamily,
1431 int pfamily, int protocol)
1432 {
1433 bzero(&pcbinfo->nat_dummy_socket, sizeof(struct socket));
1434 pcbinfo->nat_dummy_socket.so_proto = pffindproto(afamily, pfamily, protocol);
1435 pcbinfo->all_owners = 0;
1436 }
1437
1438
1439 #ifndef __APPLE__
1440 prison_xinpcb(struct proc *p, struct inpcb *inp)
1441 {
1442 if (!p->p_prison)
1443 return (0);
1444 if (ntohl(inp->inp_laddr.s_addr) == p->p_prison->pr_ip)
1445 return (0);
1446 return (1);
1447 }
1448 #endif