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