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