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