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