]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet/in_pcb.c
xnu-792.6.56.tar.gz
[apple/xnu.git] / bsd / netinet / in_pcb.c
CommitLineData
1c79356b 1/*
91447636 2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
1c79356b
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
ff6e181a
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
1c79356b 12 *
ff6e181a
A
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
ff6e181a
A
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
1c79356b
A
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*
24 * Copyright (c) 1982, 1986, 1991, 1993, 1995
25 * The Regents of the University of California. All rights reserved.
26 *
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
29 * are met:
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. All advertising materials mentioning features or use of this software
36 * must display the following acknowledgement:
37 * This product includes software developed by the University of
38 * California, Berkeley and its contributors.
39 * 4. Neither the name of the University nor the names of its contributors
40 * may be used to endorse or promote products derived from this software
41 * without specific prior written permission.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 * SUCH DAMAGE.
54 *
55 * @(#)in_pcb.c 8.4 (Berkeley) 5/24/95
9bccf70c 56 * $FreeBSD: src/sys/netinet/in_pcb.c,v 1.59.2.17 2001/08/13 16:26:17 ume Exp $
1c79356b
A
57 */
58
59#include <sys/param.h>
60#include <sys/systm.h>
61#include <sys/malloc.h>
62#include <sys/mbuf.h>
1c79356b 63#include <sys/domain.h>
1c79356b
A
64#include <sys/protosw.h>
65#include <sys/socket.h>
66#include <sys/socketvar.h>
67#include <sys/proc.h>
9bccf70c
A
68#ifndef __APPLE__
69#include <sys/jail.h>
70#endif
1c79356b
A
71#include <sys/kernel.h>
72#include <sys/sysctl.h>
91447636 73#include <libkern/OSAtomic.h>
1c79356b
A
74
75#include <machine/limits.h>
76
9bccf70c 77#ifdef __APPLE__
1c79356b
A
78#include <kern/zalloc.h>
79#endif
80
81#include <net/if.h>
1c79356b 82#include <net/if_types.h>
9bccf70c 83#include <net/route.h>
1c79356b
A
84
85#include <netinet/in.h>
86#include <netinet/in_pcb.h>
87#include <netinet/in_var.h>
88#include <netinet/ip_var.h>
89#if INET6
90#include <netinet/ip6.h>
91#include <netinet6/ip6_var.h>
92#endif /* INET6 */
93
94#include "faith.h"
95
96#if IPSEC
97#include <netinet6/ipsec.h>
98#include <netkey/key.h>
1c79356b
A
99#endif /* IPSEC */
100
101#include <sys/kdebug.h>
102
9bccf70c
A
103#if IPSEC
104extern int ipsec_bypass;
91447636 105extern lck_mtx_t *sadb_mutex;
9bccf70c 106#endif
1c79356b 107
55e303ae
A
108extern u_long route_generation;
109
1c79356b
A
110#define DBG_FNC_PCB_LOOKUP NETDBG_CODE(DBG_NETTCP, (6 << 8))
111#define DBG_FNC_PCB_HLOOKUP NETDBG_CODE(DBG_NETTCP, ((6 << 8) | 1))
112
113struct in_addr zeroin_addr;
114
1c79356b
A
115/*
116 * These configure the range of local port addresses assigned to
117 * "unspecified" outgoing connections/packets/whatever.
118 */
9bccf70c
A
119int ipport_lowfirstauto = IPPORT_RESERVED - 1; /* 1023 */
120int ipport_lowlastauto = IPPORT_RESERVEDSTART; /* 600 */
121#ifndef __APPLE__
122int ipport_firstauto = IPPORT_RESERVED; /* 1024 */
123int ipport_lastauto = IPPORT_USERRESERVED; /* 5000 */
124#else
125int ipport_firstauto = IPPORT_HIFIRSTAUTO; /* 49152 */
126int ipport_lastauto = IPPORT_HILASTAUTO; /* 65535 */
127#endif
128int ipport_hifirstauto = IPPORT_HIFIRSTAUTO; /* 49152 */
129int ipport_hilastauto = IPPORT_HILASTAUTO; /* 65535 */
1c79356b
A
130
131#define RANGECHK(var, min, max) \
132 if ((var) < (min)) { (var) = (min); } \
133 else if ((var) > (max)) { (var) = (max); }
134
1c79356b
A
135static int
136sysctl_net_ipport_check SYSCTL_HANDLER_ARGS
137{
138 int error = sysctl_handle_int(oidp,
139 oidp->oid_arg1, oidp->oid_arg2, req);
140 if (!error) {
141 RANGECHK(ipport_lowfirstauto, 1, IPPORT_RESERVED - 1);
142 RANGECHK(ipport_lowlastauto, 1, IPPORT_RESERVED - 1);
143 RANGECHK(ipport_firstauto, IPPORT_RESERVED, USHRT_MAX);
144 RANGECHK(ipport_lastauto, IPPORT_RESERVED, USHRT_MAX);
145 RANGECHK(ipport_hifirstauto, IPPORT_RESERVED, USHRT_MAX);
146 RANGECHK(ipport_hilastauto, IPPORT_RESERVED, USHRT_MAX);
147 }
148 return error;
149}
150
151#undef RANGECHK
152
153SYSCTL_NODE(_net_inet_ip, IPPROTO_IP, portrange, CTLFLAG_RW, 0, "IP Ports");
154
155SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowfirst, CTLTYPE_INT|CTLFLAG_RW,
156 &ipport_lowfirstauto, 0, &sysctl_net_ipport_check, "I", "");
157SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, lowlast, CTLTYPE_INT|CTLFLAG_RW,
158 &ipport_lowlastauto, 0, &sysctl_net_ipport_check, "I", "");
159SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, first, CTLTYPE_INT|CTLFLAG_RW,
160 &ipport_firstauto, 0, &sysctl_net_ipport_check, "I", "");
161SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, last, CTLTYPE_INT|CTLFLAG_RW,
162 &ipport_lastauto, 0, &sysctl_net_ipport_check, "I", "");
163SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hifirst, CTLTYPE_INT|CTLFLAG_RW,
164 &ipport_hifirstauto, 0, &sysctl_net_ipport_check, "I", "");
165SYSCTL_PROC(_net_inet_ip_portrange, OID_AUTO, hilast, CTLTYPE_INT|CTLFLAG_RW,
166 &ipport_hilastauto, 0, &sysctl_net_ipport_check, "I", "");
167
168/*
169 * in_pcb.c: manage the Protocol Control Blocks.
170 *
171 * NOTE: It is assumed that most of these functions will be called at
172 * splnet(). XXX - There are, unfortunately, a few exceptions to this
173 * rule that should be fixed.
174 */
175
176/*
177 * Allocate a PCB and associate it with the socket.
178 */
179int
180in_pcballoc(so, pcbinfo, p)
181 struct socket *so;
182 struct inpcbinfo *pcbinfo;
183 struct proc *p;
184{
185 register struct inpcb *inp;
186 caddr_t temp;
9bccf70c 187#if IPSEC
91447636 188#ifndef __APPLE__
9bccf70c 189 int error;
91447636 190#endif
9bccf70c 191#endif
1c79356b
A
192
193 if (so->cached_in_sock_layer == 0) {
194#if TEMPDEBUG
195 printf("PCBALLOC calling zalloc for socket %x\n", so);
196#endif
197 inp = (struct inpcb *) zalloc(pcbinfo->ipi_zone);
198 if (inp == NULL)
199 return (ENOBUFS);
200 bzero((caddr_t)inp, sizeof(*inp));
201 }
202 else {
203#if TEMPDEBUG
204 printf("PCBALLOC reusing PCB for socket %x\n", so);
205#endif
206 inp = (struct inpcb *) so->so_saved_pcb;
207 temp = inp->inp_saved_ppcb;
208 bzero((caddr_t) inp, sizeof(*inp));
209 inp->inp_saved_ppcb = temp;
210 }
211
212 inp->inp_gencnt = ++pcbinfo->ipi_gencnt;
213 inp->inp_pcbinfo = pcbinfo;
214 inp->inp_socket = so;
91447636
A
215 so->so_pcb = (caddr_t)inp;
216
217 if (so->so_proto->pr_flags & PR_PCBLOCK) {
218 inp->inpcb_mtx = lck_mtx_alloc_init(pcbinfo->mtx_grp, pcbinfo->mtx_attr);
219 if (inp->inpcb_mtx == NULL) {
220 printf("in_pcballoc: can't alloc mutex! so=%x\n", so);
221 return(ENOMEM);
222 }
223 }
224
9bccf70c
A
225#if IPSEC
226#ifndef __APPLE__
227 if (ipsec_bypass == 0) {
91447636 228 lck_mtx_lock(sadb_mutex);
9bccf70c 229 error = ipsec_init_policy(so, &inp->inp_sp);
91447636 230 lck_mtx_unlock(sadb_mutex);
9bccf70c 231 if (error != 0) {
91447636 232 zfree(pcbinfo->ipi_zone, inp);
9bccf70c
A
233 return error;
234 }
235 }
236#endif
237#endif /*IPSEC*/
238#if defined(INET6)
239 if (INP_SOCKAF(so) == AF_INET6 && !ip6_mapped_addr_on)
240 inp->inp_flags |= IN6P_IPV6_V6ONLY;
241#endif
91447636 242
9bccf70c
A
243#if INET6
244 if (ip6_auto_flowlabel)
245 inp->inp_flags |= IN6P_AUTOFLOWLABEL;
246#endif
91447636
A
247 lck_rw_lock_exclusive(pcbinfo->mtx);
248 inp->inp_gencnt = ++pcbinfo->ipi_gencnt;
249 LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list);
250 pcbinfo->ipi_count++;
251 lck_rw_done(pcbinfo->mtx);
1c79356b
A
252 return (0);
253}
254
255int
256in_pcbbind(inp, nam, p)
257 register struct inpcb *inp;
258 struct sockaddr *nam;
259 struct proc *p;
260{
261 register struct socket *so = inp->inp_socket;
9bccf70c 262 unsigned short *lastport;
1c79356b
A
263 struct sockaddr_in *sin;
264 struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
265 u_short lport = 0;
266 int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
267 int error;
268
269 if (TAILQ_EMPTY(&in_ifaddrhead)) /* XXX broken! */
270 return (EADDRNOTAVAIL);
271 if (inp->inp_lport || inp->inp_laddr.s_addr != INADDR_ANY)
272 return (EINVAL);
273 if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0)
274 wild = 1;
91447636
A
275 socket_unlock(so, 0); /* keep reference on socket */
276 lck_rw_lock_exclusive(pcbinfo->mtx);
1c79356b
A
277 if (nam) {
278 sin = (struct sockaddr_in *)nam;
91447636
A
279 if (nam->sa_len != sizeof (*sin)) {
280 lck_rw_done(pcbinfo->mtx);
281 socket_lock(so, 0);
1c79356b 282 return (EINVAL);
91447636 283 }
1c79356b
A
284#ifdef notdef
285 /*
286 * We should check the family, but old programs
287 * incorrectly fail to initialize it.
288 */
91447636
A
289 if (sin->sin_family != AF_INET) {
290 lck_rw_done(pcbinfo->mtx);
291 socket_lock(so, 0);
1c79356b 292 return (EAFNOSUPPORT);
91447636 293 }
1c79356b
A
294#endif
295 lport = sin->sin_port;
296 if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
297 /*
298 * Treat SO_REUSEADDR as SO_REUSEPORT for multicast;
299 * allow complete duplication of binding if
300 * SO_REUSEPORT is set, or if SO_REUSEADDR is set
301 * and a multicast address is bound on both
302 * new and duplicated sockets.
303 */
304 if (so->so_options & SO_REUSEADDR)
305 reuseport = SO_REUSEADDR|SO_REUSEPORT;
306 } else if (sin->sin_addr.s_addr != INADDR_ANY) {
91447636 307 struct ifaddr *ifa;
1c79356b 308 sin->sin_port = 0; /* yech... */
91447636
A
309 if ((ifa = ifa_ifwithaddr((struct sockaddr *)sin)) == 0) {
310 lck_rw_done(pcbinfo->mtx);
311 socket_lock(so, 0);
1c79356b 312 return (EADDRNOTAVAIL);
91447636
A
313 }
314 else {
315 ifafree(ifa);
316 }
1c79356b
A
317 }
318 if (lport) {
319 struct inpcb *t;
320
321 /* GROSS */
322 if (ntohs(lport) < IPPORT_RESERVED && p &&
91447636
A
323 proc_suser(p)) {
324 lck_rw_done(pcbinfo->mtx);
325 socket_lock(so, 0);
1c79356b 326 return (EACCES);
91447636 327 }
1c79356b
A
328 if (so->so_uid &&
329 !IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) {
330 t = in_pcblookup_local(inp->inp_pcbinfo,
331 sin->sin_addr, lport, INPLOOKUP_WILDCARD);
332 if (t &&
333 (ntohl(sin->sin_addr.s_addr) != INADDR_ANY ||
334 ntohl(t->inp_laddr.s_addr) != INADDR_ANY ||
335 (t->inp_socket->so_options &
336 SO_REUSEPORT) == 0) &&
337 (so->so_uid != t->inp_socket->so_uid)) {
338#if INET6
9bccf70c 339 if (ntohl(sin->sin_addr.s_addr) !=
1c79356b
A
340 INADDR_ANY ||
341 ntohl(t->inp_laddr.s_addr) !=
342 INADDR_ANY ||
343 INP_SOCKAF(so) ==
91447636 344 INP_SOCKAF(t->inp_socket)) {
9bccf70c 345#endif /* defined(INET6) */
91447636
A
346 lck_rw_done(pcbinfo->mtx);
347 socket_lock(so, 0);
348 return (EADDRINUSE);
349 }
1c79356b
A
350 }
351 }
352 t = in_pcblookup_local(pcbinfo, sin->sin_addr,
353 lport, wild);
354 if (t &&
355 (reuseport & t->inp_socket->so_options) == 0) {
356#if INET6
357 if (ip6_mapped_addr_on == 0 ||
358 ntohl(sin->sin_addr.s_addr) !=
359 INADDR_ANY ||
360 ntohl(t->inp_laddr.s_addr) !=
361 INADDR_ANY ||
362 INP_SOCKAF(so) ==
91447636 363 INP_SOCKAF(t->inp_socket)) {
9bccf70c 364#endif /* defined(INET6) */
91447636
A
365 lck_rw_done(pcbinfo->mtx);
366 socket_lock(so, 0);
367 return (EADDRINUSE);
368 }
1c79356b
A
369 }
370 }
371 inp->inp_laddr = sin->sin_addr;
372 }
373 if (lport == 0) {
374 u_short first, last;
375 int count;
376
377 inp->inp_flags |= INP_ANONPORT;
378
379 if (inp->inp_flags & INP_HIGHPORT) {
380 first = ipport_hifirstauto; /* sysctl */
381 last = ipport_hilastauto;
382 lastport = &pcbinfo->lasthi;
383 } else if (inp->inp_flags & INP_LOWPORT) {
91447636
A
384 if (p && (error = proc_suser(p))) {
385 lck_rw_done(pcbinfo->mtx);
386 socket_lock(so, 0);
1c79356b 387 return error;
91447636 388 }
1c79356b
A
389 first = ipport_lowfirstauto; /* 1023 */
390 last = ipport_lowlastauto; /* 600 */
391 lastport = &pcbinfo->lastlow;
392 } else {
393 first = ipport_firstauto; /* sysctl */
394 last = ipport_lastauto;
395 lastport = &pcbinfo->lastport;
396 }
397 /*
398 * Simple check to ensure all ports are not used up causing
399 * a deadlock here.
400 *
401 * We split the two cases (up and down) so that the direction
402 * is not being tested on each round of the loop.
403 */
404 if (first > last) {
405 /*
406 * counting down
407 */
408 count = first - last;
409
410 do {
411 if (count-- < 0) { /* completely used? */
91447636
A
412 lck_rw_done(pcbinfo->mtx);
413 socket_lock(so, 0);
1c79356b 414 inp->inp_laddr.s_addr = INADDR_ANY;
9bccf70c 415 return (EADDRNOTAVAIL);
1c79356b
A
416 }
417 --*lastport;
418 if (*lastport > first || *lastport < last)
419 *lastport = first;
420 lport = htons(*lastport);
421 } while (in_pcblookup_local(pcbinfo,
422 inp->inp_laddr, lport, wild));
423 } else {
424 /*
425 * counting up
426 */
427 count = last - first;
428
429 do {
430 if (count-- < 0) { /* completely used? */
91447636
A
431 lck_rw_done(pcbinfo->mtx);
432 socket_lock(so, 0);
1c79356b 433 inp->inp_laddr.s_addr = INADDR_ANY;
9bccf70c 434 return (EADDRNOTAVAIL);
1c79356b
A
435 }
436 ++*lastport;
437 if (*lastport < first || *lastport > last)
438 *lastport = first;
439 lport = htons(*lastport);
440 } while (in_pcblookup_local(pcbinfo,
441 inp->inp_laddr, lport, wild));
442 }
443 }
91447636 444 socket_lock(so, 0);
1c79356b 445 inp->inp_lport = lport;
91447636 446 if (in_pcbinshash(inp, 1) != 0) {
1c79356b
A
447 inp->inp_laddr.s_addr = INADDR_ANY;
448 inp->inp_lport = 0;
91447636 449 lck_rw_done(pcbinfo->mtx);
1c79356b
A
450 return (EAGAIN);
451 }
91447636 452 lck_rw_done(pcbinfo->mtx);
1c79356b
A
453 return (0);
454}
455
456/*
457 * Transform old in_pcbconnect() into an inner subroutine for new
458 * in_pcbconnect(): Do some validity-checking on the remote
459 * address (in mbuf 'nam') and then determine local host address
460 * (i.e., which interface) to use to access that remote host.
461 *
462 * This preserves definition of in_pcbconnect(), while supporting a
463 * slightly different version for T/TCP. (This is more than
464 * a bit of a kludge, but cleaning up the internal interfaces would
465 * have forced minor changes in every protocol).
466 */
467
468int
469in_pcbladdr(inp, nam, plocal_sin)
470 register struct inpcb *inp;
471 struct sockaddr *nam;
472 struct sockaddr_in **plocal_sin;
473{
474 struct in_ifaddr *ia;
475 register struct sockaddr_in *sin = (struct sockaddr_in *)nam;
476
477 if (nam->sa_len != sizeof (*sin))
478 return (EINVAL);
479 if (sin->sin_family != AF_INET)
480 return (EAFNOSUPPORT);
481 if (sin->sin_port == 0)
482 return (EADDRNOTAVAIL);
91447636 483 lck_mtx_lock(rt_mtx);
1c79356b
A
484 if (!TAILQ_EMPTY(&in_ifaddrhead)) {
485 /*
486 * If the destination address is INADDR_ANY,
487 * use the primary local address.
488 * If the supplied address is INADDR_BROADCAST,
489 * and the primary interface supports broadcast,
490 * choose the broadcast address for that interface.
491 */
492#define satosin(sa) ((struct sockaddr_in *)(sa))
493#define sintosa(sin) ((struct sockaddr *)(sin))
494#define ifatoia(ifa) ((struct in_ifaddr *)(ifa))
495 if (sin->sin_addr.s_addr == INADDR_ANY)
9bccf70c 496 sin->sin_addr = IA_SIN(TAILQ_FIRST(&in_ifaddrhead))->sin_addr;
1c79356b 497 else if (sin->sin_addr.s_addr == (u_long)INADDR_BROADCAST &&
9bccf70c
A
498 (TAILQ_FIRST(&in_ifaddrhead)->ia_ifp->if_flags & IFF_BROADCAST))
499 sin->sin_addr = satosin(&TAILQ_FIRST(&in_ifaddrhead)->ia_broadaddr)->sin_addr;
1c79356b
A
500 }
501 if (inp->inp_laddr.s_addr == INADDR_ANY) {
502 register struct route *ro;
503
504 ia = (struct in_ifaddr *)0;
505 /*
506 * If route is known or can be allocated now,
507 * our src addr is taken from the i/f, else punt.
55e303ae
A
508 * Note that we should check the address family of the cached
509 * destination, in case of sharing the cache with IPv6.
1c79356b
A
510 */
511 ro = &inp->inp_route;
512 if (ro->ro_rt &&
55e303ae
A
513 (ro->ro_dst.sa_family != AF_INET ||
514 satosin(&ro->ro_dst)->sin_addr.s_addr !=
1c79356b 515 sin->sin_addr.s_addr ||
55e303ae
A
516 inp->inp_socket->so_options & SO_DONTROUTE ||
517 ro->ro_rt->generation_id != route_generation)) {
91447636 518 rtfree_locked(ro->ro_rt);
1c79356b
A
519 ro->ro_rt = (struct rtentry *)0;
520 }
521 if ((inp->inp_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
522 (ro->ro_rt == (struct rtentry *)0 ||
91447636 523 ro->ro_rt->rt_ifp == 0)) {
1c79356b 524 /* No route yet, so try to acquire one */
55e303ae 525 bzero(&ro->ro_dst, sizeof(struct sockaddr_in));
1c79356b
A
526 ro->ro_dst.sa_family = AF_INET;
527 ro->ro_dst.sa_len = sizeof(struct sockaddr_in);
528 ((struct sockaddr_in *) &ro->ro_dst)->sin_addr =
529 sin->sin_addr;
91447636 530 rtalloc_ign_locked(ro, 0UL);
1c79356b
A
531 }
532 /*
533 * If we found a route, use the address
534 * corresponding to the outgoing interface
535 * unless it is the loopback (in case a route
536 * to our address on another net goes to loopback).
537 */
91447636 538 if (ro->ro_rt && !(ro->ro_rt->rt_ifp->if_flags & IFF_LOOPBACK)) {
1c79356b 539 ia = ifatoia(ro->ro_rt->rt_ifa);
91447636
A
540 if (ia)
541 ifaref(&ia->ia_ifa);
542 }
1c79356b
A
543 if (ia == 0) {
544 u_short fport = sin->sin_port;
545
546 sin->sin_port = 0;
547 ia = ifatoia(ifa_ifwithdstaddr(sintosa(sin)));
91447636 548 if (ia == 0) {
1c79356b 549 ia = ifatoia(ifa_ifwithnet(sintosa(sin)));
91447636 550 }
1c79356b 551 sin->sin_port = fport;
91447636 552 if (ia == 0) {
9bccf70c 553 ia = TAILQ_FIRST(&in_ifaddrhead);
91447636
A
554 if (ia)
555 ifaref(&ia->ia_ifa);
556 }
557 if (ia == 0) {
558 lck_mtx_unlock(rt_mtx);
1c79356b 559 return (EADDRNOTAVAIL);
91447636 560 }
1c79356b
A
561 }
562 /*
563 * If the destination address is multicast and an outgoing
564 * interface has been set as a multicast option, use the
565 * address of that interface as our source address.
566 */
567 if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) &&
568 inp->inp_moptions != NULL) {
569 struct ip_moptions *imo;
570 struct ifnet *ifp;
571
572 imo = inp->inp_moptions;
91447636
A
573 if (imo->imo_multicast_ifp != NULL && (ia == NULL ||
574 ia->ia_ifp != imo->imo_multicast_ifp)) {
1c79356b 575 ifp = imo->imo_multicast_ifp;
91447636
A
576 if (ia)
577 ifafree(&ia->ia_ifa);
9bccf70c 578 TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link)
1c79356b
A
579 if (ia->ia_ifp == ifp)
580 break;
91447636
A
581 if (ia == 0) {
582 lck_mtx_unlock(rt_mtx);
1c79356b 583 return (EADDRNOTAVAIL);
91447636
A
584 }
585 ifaref(ia);
1c79356b
A
586 }
587 }
91447636
A
588 /*
589 * Don't do pcblookup call here; return interface in plocal_sin
590 * and exit to caller, that will do the lookup.
591 */
1c79356b 592 *plocal_sin = &ia->ia_addr;
91447636 593 ifafree(&ia->ia_ifa);
1c79356b 594 }
91447636 595 lck_mtx_unlock(rt_mtx);
1c79356b
A
596 return(0);
597}
598
599/*
600 * Outer subroutine:
601 * Connect from a socket to a specified address.
602 * Both address and port must be specified in argument sin.
603 * If don't have a local address for this socket yet,
604 * then pick one.
605 */
606int
607in_pcbconnect(inp, nam, p)
608 register struct inpcb *inp;
609 struct sockaddr *nam;
610 struct proc *p;
611{
612 struct sockaddr_in *ifaddr;
9bccf70c 613 struct sockaddr_in *sin = (struct sockaddr_in *)nam;
91447636 614 struct inpcb *pcb;
1c79356b
A
615 int error;
616
617 /*
618 * Call inner routine, to assign local interface address.
619 */
620 if ((error = in_pcbladdr(inp, nam, &ifaddr)) != 0)
621 return(error);
622
91447636
A
623 socket_unlock(inp->inp_socket, 0);
624 pcb = in_pcblookup_hash(inp->inp_pcbinfo, sin->sin_addr, sin->sin_port,
1c79356b 625 inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr,
91447636
A
626 inp->inp_lport, 0, NULL);
627 socket_lock(inp->inp_socket, 0);
628 if (pcb != NULL) {
629 in_pcb_checkstate(pcb, WNT_RELEASE, 0);
1c79356b
A
630 return (EADDRINUSE);
631 }
632 if (inp->inp_laddr.s_addr == INADDR_ANY) {
9bccf70c
A
633 if (inp->inp_lport == 0) {
634 error = in_pcbbind(inp, (struct sockaddr *)0, p);
635 if (error)
636 return (error);
637 }
91447636
A
638 if (!lck_rw_try_lock_exclusive(inp->inp_pcbinfo->mtx)) {
639 /*lock inversion issue, mostly with udp multicast packets */
640 socket_unlock(inp->inp_socket, 0);
641 lck_rw_lock_exclusive(inp->inp_pcbinfo->mtx);
642 socket_lock(inp->inp_socket, 0);
643 }
1c79356b 644 inp->inp_laddr = ifaddr->sin_addr;
55e303ae 645 inp->inp_flags |= INP_INADDR_ANY;
91447636
A
646 }
647 else {
648 if (!lck_rw_try_lock_exclusive(inp->inp_pcbinfo->mtx)) {
649 /*lock inversion issue, mostly with udp multicast packets */
650 socket_unlock(inp->inp_socket, 0);
651 lck_rw_lock_exclusive(inp->inp_pcbinfo->mtx);
652 socket_lock(inp->inp_socket, 0);
653 }
1c79356b
A
654 }
655 inp->inp_faddr = sin->sin_addr;
656 inp->inp_fport = sin->sin_port;
657 in_pcbrehash(inp);
91447636 658 lck_rw_done(inp->inp_pcbinfo->mtx);
1c79356b
A
659 return (0);
660}
661
662void
663in_pcbdisconnect(inp)
664 struct inpcb *inp;
665{
666
667 inp->inp_faddr.s_addr = INADDR_ANY;
668 inp->inp_fport = 0;
91447636
A
669
670 if (!lck_rw_try_lock_exclusive(inp->inp_pcbinfo->mtx)) {
671 /*lock inversion issue, mostly with udp multicast packets */
672 socket_unlock(inp->inp_socket, 0);
673 lck_rw_lock_exclusive(inp->inp_pcbinfo->mtx);
674 socket_lock(inp->inp_socket, 0);
675 }
676
1c79356b 677 in_pcbrehash(inp);
91447636
A
678 lck_rw_done(inp->inp_pcbinfo->mtx);
679
680 if (inp->inp_socket->so_state & SS_NOFDREF)
1c79356b
A
681 in_pcbdetach(inp);
682}
683
684void
685in_pcbdetach(inp)
686 struct inpcb *inp;
687{
688 struct socket *so = inp->inp_socket;
9bccf70c 689 struct rtentry *rt = inp->inp_route.ro_rt;
1c79356b 690
91447636
A
691 if (so->so_pcb == 0) { /* we've been called twice */
692 panic("in_pcbdetach: inp=%x so=%x proto=%x so_pcb is null!\n",
693 inp, so, so->so_proto->pr_protocol);
694 }
ab86ba33 695
1c79356b 696#if IPSEC
91447636
A
697 if (ipsec_bypass == 0) {
698 lck_mtx_lock(sadb_mutex);
699 ipsec4_delete_pcbpolicy(inp);
700 lck_mtx_unlock(sadb_mutex);
701 }
1c79356b 702#endif /*IPSEC*/
91447636
A
703
704 /* mark socket state as dead */
705 if (in_pcb_checkstate(inp, WNT_STOPUSING, 1) != WNT_STOPUSING)
706 panic("in_pcbdetach so=%x prot=%x couldn't set to STOPUSING\n", so, so->so_proto->pr_protocol);
1c79356b
A
707
708#if TEMPDEBUG
709 if (so->cached_in_sock_layer)
91447636 710 printf("in_pcbdetach for cached socket %x flags=%x\n", so, so->so_flags);
1c79356b 711 else
91447636 712 printf("in_pcbdetach for allocated socket %x flags=%x\n", so, so->so_flags);
1c79356b 713#endif
91447636
A
714 if ((so->so_flags & SOF_PCBCLEARING) == 0) {
715 inp->inp_vflag = 0;
716 if (inp->inp_options)
717 (void)m_free(inp->inp_options);
718 if (rt) {
719 /*
720 * route deletion requires reference count to be <= zero
721 */
722 lck_mtx_lock(rt_mtx);
723 if ((rt->rt_flags & RTF_DELCLONE) &&
724 (rt->rt_flags & RTF_WASCLONED) &&
725 (rt->rt_refcnt <= 1)) {
726 rtunref(rt);
727 rt->rt_flags &= ~RTF_UP;
728 rtrequest_locked(RTM_DELETE, rt_key(rt),
729 rt->rt_gateway, rt_mask(rt),
730 rt->rt_flags, (struct rtentry **)0);
731 }
732 else {
733 rtfree_locked(rt);
734 inp->inp_route.ro_rt = 0;
735 }
736 lck_mtx_unlock(rt_mtx);
737 }
738 ip_freemoptions(inp->inp_moptions);
739 inp->inp_moptions = NULL;
740 sofreelastref(so, 0);
741 inp->inp_state = INPCB_STATE_DEAD;
742 so->so_flags |= SOF_PCBCLEARING; /* makes sure we're not called twice from so_close */
743 }
744}
1c79356b 745
1c79356b 746
91447636
A
747void
748in_pcbdispose(inp)
749 struct inpcb *inp;
750{
751 struct socket *so = inp->inp_socket;
752 struct inpcbinfo *ipi = inp->inp_pcbinfo;
753
754#if TEMPDEBUG
755 if (inp->inp_state != INPCB_STATE_DEAD) {
756 printf("in_pcbdispose: not dead yet? so=%x\n", so);
757 }
758#endif
759
760 if (so && so->so_usecount != 0)
761 panic("in_pcbdispose: use count=%x so=%x\n", so->so_usecount, so);
762
763
764 inp->inp_gencnt = ++ipi->ipi_gencnt;
765 /*### access ipi in in_pcbremlists */
766 in_pcbremlists(inp);
767
768 if (so) {
769 if (so->so_proto->pr_flags & PR_PCBLOCK) {
770 sofreelastref(so, 0);
771 if (so->so_rcv.sb_cc || so->so_snd.sb_cc) {
772#if TEMPDEBUG
773 printf("in_pcbdispose sb not cleaned up so=%x rc_cci=%x snd_cc=%x\n",
774 so, so->so_rcv.sb_cc, so->so_snd.sb_cc);
775#endif
776 sbrelease(&so->so_rcv);
777 sbrelease(&so->so_snd);
778 }
779 if (so->so_head != NULL)
780 panic("in_pcbdispose, so=%x head still exist\n", so);
781 lck_mtx_unlock(inp->inpcb_mtx);
782 lck_mtx_free(inp->inpcb_mtx, ipi->mtx_grp);
9bccf70c 783 }
91447636
A
784 so->so_flags |= SOF_PCBCLEARING; /* makes sure we're not called twice from so_close */
785 so->so_saved_pcb = (caddr_t) inp;
786 so->so_pcb = 0;
787 inp->inp_socket = 0;
788 inp->reserved[0] = so;
789 if (so->cached_in_sock_layer == 0) {
790 zfree(ipi->ipi_zone, inp);
55e303ae 791 }
91447636 792 sodealloc(so);
9bccf70c 793 }
91447636 794#if TEMPDEBUG
1c79356b 795 else
91447636
A
796 printf("in_pcbdispose: no socket for inp=%x\n", inp);
797#endif
1c79356b
A
798}
799
800/*
801 * The calling convention of in_setsockaddr() and in_setpeeraddr() was
802 * modified to match the pru_sockaddr() and pru_peeraddr() entry points
803 * in struct pr_usrreqs, so that protocols can just reference then directly
804 * without the need for a wrapper function. The socket must have a valid
805 * (i.e., non-nil) PCB, but it should be impossible to get an invalid one
806 * except through a kernel programming error, so it is acceptable to panic
807 * (or in this case trap) if the PCB is invalid. (Actually, we don't trap
808 * because there actually /is/ a programming error somewhere... XXX)
809 */
810int
811in_setsockaddr(so, nam)
812 struct socket *so;
813 struct sockaddr **nam;
814{
1c79356b
A
815 register struct inpcb *inp;
816 register struct sockaddr_in *sin;
817
818 /*
819 * Do the malloc first in case it blocks.
820 */
821 MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME, M_WAITOK);
0b4e3aa0
A
822 if (sin == NULL)
823 return ENOBUFS;
1c79356b
A
824 bzero(sin, sizeof *sin);
825 sin->sin_family = AF_INET;
826 sin->sin_len = sizeof(*sin);
827
1c79356b
A
828 inp = sotoinpcb(so);
829 if (!inp) {
1c79356b 830 FREE(sin, M_SONAME);
9bccf70c 831 return ECONNRESET;
1c79356b
A
832 }
833 sin->sin_port = inp->inp_lport;
834 sin->sin_addr = inp->inp_laddr;
1c79356b
A
835
836 *nam = (struct sockaddr *)sin;
837 return 0;
838}
839
840int
841in_setpeeraddr(so, nam)
842 struct socket *so;
843 struct sockaddr **nam;
844{
1c79356b
A
845 struct inpcb *inp;
846 register struct sockaddr_in *sin;
847
848 /*
849 * Do the malloc first in case it blocks.
850 */
851 MALLOC(sin, struct sockaddr_in *, sizeof *sin, M_SONAME, M_WAITOK);
0b4e3aa0
A
852 if (sin == NULL)
853 return ENOBUFS;
1c79356b
A
854 bzero((caddr_t)sin, sizeof (*sin));
855 sin->sin_family = AF_INET;
856 sin->sin_len = sizeof(*sin);
857
1c79356b
A
858 inp = sotoinpcb(so);
859 if (!inp) {
1c79356b 860 FREE(sin, M_SONAME);
9bccf70c 861 return ECONNRESET;
1c79356b
A
862 }
863 sin->sin_port = inp->inp_fport;
864 sin->sin_addr = inp->inp_faddr;
1c79356b
A
865
866 *nam = (struct sockaddr *)sin;
867 return 0;
868}
869
1c79356b 870void
91447636
A
871in_pcbnotifyall(pcbinfo, faddr, errno, notify)
872 struct inpcbinfo *pcbinfo;
9bccf70c 873 struct in_addr faddr;
91447636 874 void (*notify) (struct inpcb *, int);
1c79356b 875{
91447636
A
876 struct inpcb *inp;
877
878 lck_rw_lock_shared(pcbinfo->mtx);
1c79356b 879
91447636 880 LIST_FOREACH(inp, pcbinfo->listhead, inp_list) {
9bccf70c
A
881#if INET6
882 if ((inp->inp_vflag & INP_IPV4) == 0)
1c79356b 883 continue;
9bccf70c 884#endif
1c79356b 885 if (inp->inp_faddr.s_addr != faddr.s_addr ||
9bccf70c
A
886 inp->inp_socket == NULL)
887 continue;
91447636
A
888 if (in_pcb_checkstate(inp, WNT_ACQUIRE, 0) == WNT_STOPUSING)
889 continue;
890 socket_lock(inp->inp_socket, 1);
9bccf70c 891 (*notify)(inp, errno);
91447636
A
892 (void)in_pcb_checkstate(inp, WNT_RELEASE, 1);
893 socket_unlock(inp->inp_socket, 1);
1c79356b 894 }
91447636 895 lck_rw_done(pcbinfo->mtx);
1c79356b
A
896}
897
9bccf70c 898void
91447636
A
899in_pcbpurgeif0(
900 struct inpcb *head,
901 struct ifnet *ifp)
9bccf70c
A
902{
903 struct inpcb *inp;
904 struct ip_moptions *imo;
905 int i, gap;
906
907 for (inp = head; inp != NULL; inp = LIST_NEXT(inp, inp_list)) {
908 imo = inp->inp_moptions;
909 if ((inp->inp_vflag & INP_IPV4) &&
910 imo != NULL) {
911 /*
912 * Unselect the outgoing interface if it is being
913 * detached.
914 */
915 if (imo->imo_multicast_ifp == ifp)
916 imo->imo_multicast_ifp = NULL;
917
918 /*
919 * Drop multicast group membership if we joined
920 * through the interface being detached.
921 */
922 for (i = 0, gap = 0; i < imo->imo_num_memberships;
923 i++) {
924 if (imo->imo_membership[i]->inm_ifp == ifp) {
91447636 925 in_delmulti(&imo->imo_membership[i]);
9bccf70c
A
926 gap++;
927 } else if (gap != 0)
928 imo->imo_membership[i - gap] =
929 imo->imo_membership[i];
930 }
931 imo->imo_num_memberships -= gap;
932 }
933 }
934}
935
1c79356b
A
936/*
937 * Check for alternatives when higher level complains
938 * about service problems. For now, invalidate cached
939 * routing information. If the route was created dynamically
940 * (by a redirect), time to try a default gateway again.
941 */
942void
943in_losing(inp)
944 struct inpcb *inp;
945{
946 register struct rtentry *rt;
947 struct rt_addrinfo info;
948
949 if ((rt = inp->inp_route.ro_rt)) {
91447636 950 lck_mtx_lock(rt_mtx);
1c79356b
A
951 bzero((caddr_t)&info, sizeof(info));
952 info.rti_info[RTAX_DST] =
953 (struct sockaddr *)&inp->inp_route.ro_dst;
954 info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
955 info.rti_info[RTAX_NETMASK] = rt_mask(rt);
956 rt_missmsg(RTM_LOSING, &info, rt->rt_flags, 0);
957 if (rt->rt_flags & RTF_DYNAMIC)
91447636 958 (void) rtrequest_locked(RTM_DELETE, rt_key(rt),
1c79356b
A
959 rt->rt_gateway, rt_mask(rt), rt->rt_flags,
960 (struct rtentry **)0);
9bccf70c 961 inp->inp_route.ro_rt = 0;
91447636
A
962 rtfree_locked(rt);
963 lck_mtx_unlock(rt_mtx);
1c79356b
A
964 /*
965 * A new route can be allocated
966 * the next time output is attempted.
967 */
1c79356b
A
968 }
969}
970
971/*
972 * After a routing change, flush old routing
973 * and allocate a (hopefully) better one.
974 */
9bccf70c 975void
1c79356b
A
976in_rtchange(inp, errno)
977 register struct inpcb *inp;
978 int errno;
979{
980 if (inp->inp_route.ro_rt) {
91447636 981 if ((ifa_foraddr(inp->inp_laddr.s_addr)) == 0)
ab86ba33 982 return; /* we can't remove the route now. not sure if still ok to use src */
1c79356b
A
983 rtfree(inp->inp_route.ro_rt);
984 inp->inp_route.ro_rt = 0;
985 /*
986 * A new route can be allocated the next time
987 * output is attempted.
988 */
989 }
990}
991
992/*
993 * Lookup a PCB based on the local address and port.
994 */
995struct inpcb *
996in_pcblookup_local(pcbinfo, laddr, lport_arg, wild_okay)
997 struct inpcbinfo *pcbinfo;
998 struct in_addr laddr;
999 u_int lport_arg;
1000 int wild_okay;
1001{
1002 register struct inpcb *inp;
1003 int matchwild = 3, wildcard;
1004 u_short lport = lport_arg;
1005
1006 KERNEL_DEBUG(DBG_FNC_PCB_LOOKUP | DBG_FUNC_START, 0,0,0,0,0);
1007
1008 if (!wild_okay) {
1009 struct inpcbhead *head;
1010 /*
1011 * Look for an unconnected (wildcard foreign addr) PCB that
1012 * matches the local address and port we're looking for.
1013 */
1014 head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
9bccf70c
A
1015 LIST_FOREACH(inp, head, inp_hash) {
1016#if INET6
1017 if ((inp->inp_vflag & INP_IPV4) == 0)
1c79356b 1018 continue;
9bccf70c 1019#endif
1c79356b
A
1020 if (inp->inp_faddr.s_addr == INADDR_ANY &&
1021 inp->inp_laddr.s_addr == laddr.s_addr &&
1022 inp->inp_lport == lport) {
1023 /*
1024 * Found.
1025 */
1026 return (inp);
1027 }
1028 }
1029 /*
1030 * Not found.
1031 */
1032 KERNEL_DEBUG(DBG_FNC_PCB_LOOKUP | DBG_FUNC_END, 0,0,0,0,0);
1033 return (NULL);
1034 } else {
1035 struct inpcbporthead *porthash;
1036 struct inpcbport *phd;
1037 struct inpcb *match = NULL;
1038 /*
1039 * Best fit PCB lookup.
1040 *
1041 * First see if this local port is in use by looking on the
1042 * port hash list.
1043 */
1044 porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport,
1045 pcbinfo->porthashmask)];
9bccf70c 1046 LIST_FOREACH(phd, porthash, phd_hash) {
1c79356b
A
1047 if (phd->phd_port == lport)
1048 break;
1049 }
1050 if (phd != NULL) {
1051 /*
1052 * Port is in use by one or more PCBs. Look for best
1053 * fit.
1054 */
9bccf70c 1055 LIST_FOREACH(inp, &phd->phd_pcblist, inp_portlist) {
1c79356b 1056 wildcard = 0;
9bccf70c
A
1057#if INET6
1058 if ((inp->inp_vflag & INP_IPV4) == 0)
1c79356b 1059 continue;
9bccf70c 1060#endif
1c79356b
A
1061 if (inp->inp_faddr.s_addr != INADDR_ANY)
1062 wildcard++;
1063 if (inp->inp_laddr.s_addr != INADDR_ANY) {
1064 if (laddr.s_addr == INADDR_ANY)
1065 wildcard++;
1066 else if (inp->inp_laddr.s_addr != laddr.s_addr)
1067 continue;
1068 } else {
1069 if (laddr.s_addr != INADDR_ANY)
1070 wildcard++;
1071 }
1072 if (wildcard < matchwild) {
1073 match = inp;
1074 matchwild = wildcard;
1075 if (matchwild == 0) {
1076 break;
1077 }
1078 }
1079 }
1080 }
1081 KERNEL_DEBUG(DBG_FNC_PCB_LOOKUP | DBG_FUNC_END, match,0,0,0,0);
1082 return (match);
1083 }
1084}
1085
1086/*
1087 * Lookup PCB in hash list.
1088 */
1089struct inpcb *
91447636
A
1090in_pcblookup_hash(
1091 struct inpcbinfo *pcbinfo,
1092 struct in_addr faddr,
1093 u_int fport_arg,
1094 struct in_addr laddr,
1095 u_int lport_arg,
1096 int wildcard,
1097 struct ifnet *ifp)
1c79356b
A
1098{
1099 struct inpcbhead *head;
1100 register struct inpcb *inp;
1101 u_short fport = fport_arg, lport = lport_arg;
1102
1103 /*
1104 * We may have found the pcb in the last lookup - check this first.
1105 */
1106
91447636 1107 lck_rw_lock_shared(pcbinfo->mtx);
1c79356b
A
1108
1109 /*
1110 * First look for an exact match.
1111 */
1112 head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)];
9bccf70c
A
1113 LIST_FOREACH(inp, head, inp_hash) {
1114#if INET6
1115 if ((inp->inp_vflag & INP_IPV4) == 0)
1c79356b 1116 continue;
9bccf70c 1117#endif
1c79356b
A
1118 if (inp->inp_faddr.s_addr == faddr.s_addr &&
1119 inp->inp_laddr.s_addr == laddr.s_addr &&
1120 inp->inp_fport == fport &&
1121 inp->inp_lport == lport) {
1122 /*
1123 * Found.
1124 */
91447636
A
1125 if (in_pcb_checkstate(inp, WNT_ACQUIRE, 0) != WNT_STOPUSING) {
1126 lck_rw_done(pcbinfo->mtx);
1127 return (inp);
1128 }
1129 else { /* it's there but dead, say it isn't found */
1130 lck_rw_done(pcbinfo->mtx);
1131 return(NULL);
1132 }
1c79356b
A
1133 }
1134 }
1135 if (wildcard) {
1136 struct inpcb *local_wild = NULL;
1137#if INET6
1138 struct inpcb *local_wild_mapped = NULL;
1139#endif
1140
1141 head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)];
9bccf70c
A
1142 LIST_FOREACH(inp, head, inp_hash) {
1143#if INET6
1144 if ((inp->inp_vflag & INP_IPV4) == 0)
1c79356b 1145 continue;
9bccf70c 1146#endif
1c79356b
A
1147 if (inp->inp_faddr.s_addr == INADDR_ANY &&
1148 inp->inp_lport == lport) {
1149#if defined(NFAITH) && NFAITH > 0
1150 if (ifp && ifp->if_type == IFT_FAITH &&
1151 (inp->inp_flags & INP_FAITH) == 0)
1152 continue;
1153#endif
91447636
A
1154 if (inp->inp_laddr.s_addr == laddr.s_addr) {
1155 if (in_pcb_checkstate(inp, WNT_ACQUIRE, 0) != WNT_STOPUSING) {
1156 lck_rw_done(pcbinfo->mtx);
1157 return (inp);
1158 }
1159 else { /* it's there but dead, say it isn't found */
1160 lck_rw_done(pcbinfo->mtx);
1161 return(NULL);
1162 }
1163 }
1c79356b 1164 else if (inp->inp_laddr.s_addr == INADDR_ANY) {
9bccf70c 1165#if defined(INET6)
1c79356b
A
1166 if (INP_CHECK_SOCKAF(inp->inp_socket,
1167 AF_INET6))
1168 local_wild_mapped = inp;
1169 else
9bccf70c 1170#endif /* defined(INET6) */
1c79356b
A
1171 local_wild = inp;
1172 }
1173 }
1174 }
9bccf70c 1175#if defined(INET6)
91447636
A
1176 if (local_wild == NULL) {
1177 if (local_wild_mapped != NULL) {
1178 if (in_pcb_checkstate(local_wild_mapped, WNT_ACQUIRE, 0) != WNT_STOPUSING) {
1179 lck_rw_done(pcbinfo->mtx);
1180 return (local_wild_mapped);
1181 }
1182 else { /* it's there but dead, say it isn't found */
1183 lck_rw_done(pcbinfo->mtx);
1184 return(NULL);
1185 }
1186 }
1187 lck_rw_done(pcbinfo->mtx);
1188 return (NULL);
1189 }
9bccf70c 1190#endif /* defined(INET6) */
91447636
A
1191 if (in_pcb_checkstate(local_wild, WNT_ACQUIRE, 0) != WNT_STOPUSING) {
1192 lck_rw_done(pcbinfo->mtx);
1193 return (local_wild);
1194 }
1195 else { /* it's there but dead, say it isn't found */
1196 lck_rw_done(pcbinfo->mtx);
1197 return(NULL);
1198 }
1c79356b
A
1199 }
1200
1201 /*
1202 * Not found.
1203 */
91447636 1204 lck_rw_done(pcbinfo->mtx);
1c79356b
A
1205 return (NULL);
1206}
1207
1208/*
1209 * Insert PCB onto various hash lists.
1210 */
1211int
91447636 1212in_pcbinshash(inp, locked)
1c79356b 1213 struct inpcb *inp;
91447636 1214 int locked; /* list already locked exclusive */
1c79356b
A
1215{
1216 struct inpcbhead *pcbhash;
1217 struct inpcbporthead *pcbporthash;
1218 struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
1219 struct inpcbport *phd;
1220 u_int32_t hashkey_faddr;
1221
1222#if INET6
1223 if (inp->inp_vflag & INP_IPV6)
1224 hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */;
1225 else
1226#endif /* INET6 */
1227 hashkey_faddr = inp->inp_faddr.s_addr;
1228
91447636
A
1229 inp->hash_element = INP_PCBHASH(hashkey_faddr, inp->inp_lport, inp->inp_fport, pcbinfo->hashmask);
1230
1231 if (!locked) {
1232 if (!lck_rw_try_lock_exclusive(pcbinfo->mtx)) {
1233 /*lock inversion issue, mostly with udp multicast packets */
1234 socket_unlock(inp->inp_socket, 0);
1235 lck_rw_lock_exclusive(pcbinfo->mtx);
1236 socket_lock(inp->inp_socket, 0);
1237 }
1238 }
1239
1240 pcbhash = &pcbinfo->hashbase[inp->hash_element];
1c79356b
A
1241
1242 pcbporthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(inp->inp_lport,
1243 pcbinfo->porthashmask)];
1244
1245 /*
1246 * Go through port list and look for a head for this lport.
1247 */
9bccf70c 1248 LIST_FOREACH(phd, pcbporthash, phd_hash) {
1c79356b
A
1249 if (phd->phd_port == inp->inp_lport)
1250 break;
1251 }
1252 /*
1253 * If none exists, malloc one and tack it on.
1254 */
1255 if (phd == NULL) {
0b4e3aa0 1256 MALLOC(phd, struct inpcbport *, sizeof(struct inpcbport), M_PCB, M_WAITOK);
1c79356b 1257 if (phd == NULL) {
91447636
A
1258 if (!locked)
1259 lck_rw_done(pcbinfo->mtx);
1c79356b
A
1260 return (ENOBUFS); /* XXX */
1261 }
1262 phd->phd_port = inp->inp_lport;
1263 LIST_INIT(&phd->phd_pcblist);
1264 LIST_INSERT_HEAD(pcbporthash, phd, phd_hash);
1265 }
1266 inp->inp_phd = phd;
1267 LIST_INSERT_HEAD(&phd->phd_pcblist, inp, inp_portlist);
1268 LIST_INSERT_HEAD(pcbhash, inp, inp_hash);
91447636
A
1269 if (!locked)
1270 lck_rw_done(pcbinfo->mtx);
1c79356b
A
1271 return (0);
1272}
1273
1274/*
1275 * Move PCB to the proper hash bucket when { faddr, fport } have been
1276 * changed. NOTE: This does not handle the case of the lport changing (the
1277 * hashed port list would have to be updated as well), so the lport must
1278 * not change after in_pcbinshash() has been called.
1279 */
1280void
1281in_pcbrehash(inp)
1282 struct inpcb *inp;
1283{
1284 struct inpcbhead *head;
1285 u_int32_t hashkey_faddr;
1286
1287#if INET6
1288 if (inp->inp_vflag & INP_IPV6)
1289 hashkey_faddr = inp->in6p_faddr.s6_addr32[3] /* XXX */;
1290 else
1291#endif /* INET6 */
1292 hashkey_faddr = inp->inp_faddr.s_addr;
91447636
A
1293 inp->hash_element = INP_PCBHASH(hashkey_faddr, inp->inp_lport,
1294 inp->inp_fport, inp->inp_pcbinfo->hashmask);
1295 head = &inp->inp_pcbinfo->hashbase[inp->hash_element];
1c79356b
A
1296
1297 LIST_REMOVE(inp, inp_hash);
1298 LIST_INSERT_HEAD(head, inp, inp_hash);
1c79356b
A
1299}
1300
1301/*
1302 * Remove PCB from various lists.
1303 */
91447636 1304//###LOCK must be called with list lock held
1c79356b
A
1305void
1306in_pcbremlists(inp)
1307 struct inpcb *inp;
1308{
1309 inp->inp_gencnt = ++inp->inp_pcbinfo->ipi_gencnt;
1c79356b
A
1310
1311 if (inp->inp_lport) {
1312 struct inpcbport *phd = inp->inp_phd;
1313
1314 LIST_REMOVE(inp, inp_hash);
1315 LIST_REMOVE(inp, inp_portlist);
55e303ae 1316 if (phd != NULL && (LIST_FIRST(&phd->phd_pcblist) == NULL)) {
1c79356b
A
1317 LIST_REMOVE(phd, phd_hash);
1318 FREE(phd, M_PCB);
1319 }
1320 }
1c79356b
A
1321 LIST_REMOVE(inp, inp_list);
1322 inp->inp_pcbinfo->ipi_count--;
1323}
1324
91447636 1325static void in_pcb_detach_port( struct inpcb *inp);
1c79356b 1326int
91447636 1327in_pcb_grab_port (struct inpcbinfo *pcbinfo,
1c79356b
A
1328 u_short options,
1329 struct in_addr laddr,
1330 u_short *lport,
1331 struct in_addr faddr,
1332 u_short fport,
1333 u_int cookie,
91447636 1334 u_char owner_id)
1c79356b 1335{
91447636 1336 struct inpcb *inp, *pcb;
1c79356b
A
1337 struct sockaddr_in sin;
1338 struct proc *p = current_proc();
1339 int stat;
1340
1341
1342 pcbinfo->nat_dummy_socket.so_pcb = 0;
1343 pcbinfo->nat_dummy_socket.so_options = 0;
1344 if (*lport) {
1345 /* The grabber wants a particular port */
1346
1347 if (faddr.s_addr || fport) {
1348 /*
1349 * This is either the second half of an active connect, or
1350 * it's from the acceptance of an incoming connection.
1351 */
1352 if (laddr.s_addr == 0) {
91447636 1353 pcbinfo->nat_dummy_socket.so_pcb = (caddr_t)pcbinfo->nat_dummy_pcb;
1c79356b
A
1354 return EINVAL;
1355 }
1356
91447636
A
1357 inp = in_pcblookup_hash(pcbinfo, faddr, fport, laddr, *lport, 0, NULL);
1358 if (inp) {
1359 /* pcb was found, its count was upped. need to decrease it here */
1360 in_pcb_checkstate(inp, WNT_RELEASE, 0);
1361 if (!(IN_MULTICAST(ntohl(laddr.s_addr)))) {
1362 pcbinfo->nat_dummy_socket.so_pcb = (caddr_t)pcbinfo->nat_dummy_pcb;
1363 return (EADDRINUSE);
1364 }
1c79356b
A
1365 }
1366
1367 stat = in_pcballoc(&pcbinfo->nat_dummy_socket, pcbinfo, p);
91447636
A
1368 if (stat) {
1369 pcbinfo->nat_dummy_socket.so_pcb = (caddr_t)pcbinfo->nat_dummy_pcb;
1c79356b 1370 return stat;
91447636 1371 }
1c79356b
A
1372 pcb = sotoinpcb(&pcbinfo->nat_dummy_socket);
1373 pcb->inp_vflag |= INP_IPV4;
1374
1375 pcb->inp_lport = *lport;
1376 pcb->inp_laddr.s_addr = laddr.s_addr;
1377
1378 pcb->inp_faddr = faddr;
1379 pcb->inp_fport = fport;
91447636
A
1380
1381 lck_rw_lock_exclusive(pcbinfo->mtx);
1382 in_pcbinshash(pcb, 1);
1383 lck_rw_done(pcbinfo->mtx);
1c79356b
A
1384 }
1385 else {
1386 /*
1387 * This is either a bind for a passive socket, or it's the
1388 * first part of bind-connect sequence (not likely since an
1389 * ephemeral port is usually used in this case). Or, it's
1390 * the result of a connection acceptance when the foreign
1391 * address/port cannot be provided (which requires the SO_REUSEADDR
1392 * flag if laddr is not multicast).
1393 */
1394
1395 stat = in_pcballoc(&pcbinfo->nat_dummy_socket, pcbinfo, p);
91447636
A
1396 if (stat) {
1397 pcbinfo->nat_dummy_socket.so_pcb = (caddr_t)pcbinfo->nat_dummy_pcb;
1c79356b 1398 return stat;
91447636 1399 }
1c79356b
A
1400 pcb = sotoinpcb(&pcbinfo->nat_dummy_socket);
1401 pcb->inp_vflag |= INP_IPV4;
1402
1403 pcbinfo->nat_dummy_socket.so_options = options;
1404 bzero(&sin, sizeof(struct sockaddr_in));
1405 sin.sin_len = sizeof(struct sockaddr_in);
1406 sin.sin_family = AF_INET;
1407 sin.sin_addr.s_addr = laddr.s_addr;
1408 sin.sin_port = *lport;
91447636
A
1409
1410 socket_lock(&pcbinfo->nat_dummy_socket, 1);
1c79356b
A
1411 stat = in_pcbbind((struct inpcb *) pcbinfo->nat_dummy_socket.so_pcb,
1412 (struct sockaddr *) &sin, p);
1413 if (stat) {
91447636
A
1414 socket_unlock(&pcbinfo->nat_dummy_socket, 1); /*detach first */
1415 in_pcb_detach_port(pcb); /* will restore dummy pcb */
1416 return stat;
1c79356b 1417 }
91447636 1418 socket_unlock(&pcbinfo->nat_dummy_socket, 1);
1c79356b
A
1419 }
1420 }
1421 else {
1422 /* The grabber wants an ephemeral port */
1423
1424 stat = in_pcballoc(&pcbinfo->nat_dummy_socket, pcbinfo, p);
91447636
A
1425 if (stat) {
1426 pcbinfo->nat_dummy_socket.so_pcb = (caddr_t)pcbinfo->nat_dummy_pcb;
1c79356b 1427 return stat;
91447636 1428 }
1c79356b
A
1429 pcb = sotoinpcb(&pcbinfo->nat_dummy_socket);
1430 pcb->inp_vflag |= INP_IPV4;
1431
1432 bzero(&sin, sizeof(struct sockaddr_in));
1433 sin.sin_len = sizeof(struct sockaddr_in);
1434 sin.sin_family = AF_INET;
1435 sin.sin_addr.s_addr = laddr.s_addr;
1436 sin.sin_port = 0;
1437
1438 if (faddr.s_addr || fport) {
1439 /*
1440 * Not sure if this case will be used - could occur when connect
1441 * is called, skipping the bind.
1442 */
1443
1444 if (laddr.s_addr == 0) {
91447636 1445 in_pcb_detach_port(pcb); /* restores dummy pcb */
1c79356b
A
1446 return EINVAL;
1447 }
1448
91447636 1449 socket_lock(&pcbinfo->nat_dummy_socket, 1);
1c79356b
A
1450 stat = in_pcbbind((struct inpcb *) pcbinfo->nat_dummy_socket.so_pcb,
1451 (struct sockaddr *) &sin, p);
1452 if (stat) {
91447636
A
1453 socket_unlock(&pcbinfo->nat_dummy_socket, 1);
1454 in_pcb_detach_port(pcb); /* restores dummy pcb */
1c79356b
A
1455 return stat;
1456 }
1457
91447636
A
1458 socket_unlock(&pcbinfo->nat_dummy_socket, 1);
1459 inp = in_pcblookup_hash(pcbinfo, faddr, fport,
1460 pcb->inp_laddr, pcb->inp_lport, 0, NULL);
1461 if (inp) {
1462 /* pcb was found, its count was upped. need to decrease it here */
1463 in_pcb_checkstate(inp, WNT_RELEASE, 0);
1464 in_pcb_detach_port(pcb);
1465 return (EADDRINUSE);
1c79356b
A
1466 }
1467
91447636 1468 lck_rw_lock_exclusive(pcbinfo->mtx);
1c79356b
A
1469 pcb->inp_faddr = faddr;
1470 pcb->inp_fport = fport;
1471 in_pcbrehash(pcb);
91447636 1472 lck_rw_done(pcbinfo->mtx);
1c79356b
A
1473 }
1474 else {
1475 /*
1476 * This is a simple bind of an ephemeral port. The local addr
1477 * may or may not be defined.
1478 */
1479
91447636 1480 socket_lock(&pcbinfo->nat_dummy_socket, 1);
1c79356b
A
1481 stat = in_pcbbind((struct inpcb *) pcbinfo->nat_dummy_socket.so_pcb,
1482 (struct sockaddr *) &sin, p);
1483 if (stat) {
91447636
A
1484 socket_unlock(&pcbinfo->nat_dummy_socket, 1);
1485 in_pcb_detach_port(pcb);
1c79356b
A
1486 return stat;
1487 }
91447636 1488 socket_unlock(&pcbinfo->nat_dummy_socket, 1);
1c79356b
A
1489 }
1490 *lport = pcb->inp_lport;
1491 }
1492
1493
1494 pcb->nat_owner = owner_id;
1495 pcb->nat_cookie = cookie;
1496 pcb->inp_ppcb = (caddr_t) pcbinfo->dummy_cb;
91447636 1497 pcbinfo->nat_dummy_socket.so_pcb = (caddr_t)pcbinfo->nat_dummy_pcb; /* restores dummypcb */
1c79356b
A
1498 return 0;
1499}
1500
91447636
A
1501/* 3962035 - in_pcb_letgo_port needs a special case function for detaching */
1502static void
1503in_pcb_detach_port(
1504 struct inpcb *inp)
1505{
1506 struct socket *so = inp->inp_socket;
1507 struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
1508
1509 if (so != &pcbinfo->nat_dummy_socket)
1510 panic("in_pcb_detach_port: not a dummy_sock: so=%x, inp=%x\n", so, inp);
1511 inp->inp_gencnt = ++pcbinfo->ipi_gencnt;
1512 /*### access ipi in in_pcbremlists */
1513 in_pcbremlists(inp);
1514
1515 inp->inp_socket = 0;
1516 inp->reserved[0] = so;
1517 zfree(pcbinfo->ipi_zone, inp);
1518 pcbinfo->nat_dummy_socket.so_pcb = (caddr_t)pcbinfo->nat_dummy_pcb; /* restores dummypcb */
1519}
1520
1c79356b 1521int
91447636
A
1522in_pcb_letgo_port(struct inpcbinfo *pcbinfo, struct in_addr laddr, u_short lport,
1523 struct in_addr faddr, u_short fport, u_char owner_id)
1c79356b
A
1524{
1525 struct inpcbhead *head;
1526 register struct inpcb *inp;
1527
1528
1529 /*
1530 * First look for an exact match.
1531 */
91447636
A
1532
1533 lck_rw_lock_exclusive(pcbinfo->mtx);
1c79356b
A
1534 head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)];
1535 for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
1536 if (inp->inp_faddr.s_addr == faddr.s_addr &&
1537 inp->inp_laddr.s_addr == laddr.s_addr &&
1538 inp->inp_fport == fport &&
1539 inp->inp_lport == lport &&
1540 inp->nat_owner == owner_id) {
1541 /*
1542 * Found.
1543 */
91447636
A
1544 in_pcb_detach_port(inp);
1545 lck_rw_done(pcbinfo->mtx);
1c79356b
A
1546 return 0;
1547 }
1548 }
1549
91447636 1550 lck_rw_done(pcbinfo->mtx);
1c79356b
A
1551 return ENOENT;
1552}
1553
1554u_char
1555in_pcb_get_owner(struct inpcbinfo *pcbinfo,
1556 struct in_addr laddr, u_short lport,
1557 struct in_addr faddr, u_short fport,
1558 u_int *cookie)
1559
1560{
1561 struct inpcb *inp;
1562 u_char owner_id = INPCB_NO_OWNER;
1563 struct inpcbport *phd;
1564 struct inpcbporthead *porthash;
1565
1566
1567 if (IN_MULTICAST(laddr.s_addr)) {
1568 /*
1569 * Walk through PCB's looking for registered
1570 * owners.
1571 */
1572
91447636 1573 lck_rw_lock_shared(pcbinfo->mtx);
1c79356b
A
1574 porthash = &pcbinfo->porthashbase[INP_PCBPORTHASH(lport,
1575 pcbinfo->porthashmask)];
1576 for (phd = porthash->lh_first; phd != NULL; phd = phd->phd_hash.le_next) {
1577 if (phd->phd_port == lport)
1578 break;
1579 }
1580
1581 if (phd == 0) {
91447636 1582 lck_rw_done(pcbinfo->mtx);
1c79356b
A
1583 return INPCB_NO_OWNER;
1584 }
1585
1586 owner_id = INPCB_NO_OWNER;
1587 for (inp = phd->phd_pcblist.lh_first; inp != NULL;
1588 inp = inp->inp_portlist.le_next) {
1589
1590 if (inp->inp_laddr.s_addr == laddr.s_addr) {
1591 if (inp->nat_owner == 0)
1592 owner_id |= INPCB_OWNED_BY_X;
1593 else
1594 owner_id |= inp->nat_owner;
1595 }
1596 }
1597
91447636 1598 lck_rw_done(pcbinfo->mtx);
1c79356b
A
1599 return owner_id;
1600 }
1601 else {
1602 inp = in_pcblookup_hash(pcbinfo, faddr, fport,
1603 laddr, lport, 1, NULL);
1604 if (inp) {
91447636
A
1605 /* pcb was found, its count was upped. need to decrease it here */
1606 /* if we found it, that pcb is already locked by the caller */
1607 if (in_pcb_checkstate(inp, WNT_RELEASE, 1) == WNT_STOPUSING)
1608 return(INPCB_NO_OWNER);
1609
1c79356b
A
1610 if (inp->nat_owner) {
1611 owner_id = inp->nat_owner;
1612 *cookie = inp->nat_cookie;
1613 }
1614 else {
1c79356b
A
1615 owner_id = INPCB_OWNED_BY_X;
1616 }
1617 }
1618 else
1619 owner_id = INPCB_NO_OWNER;
1620
1621 return owner_id;
1622 }
1623}
1624
1625int
1626in_pcb_new_share_client(struct inpcbinfo *pcbinfo, u_char *owner_id)
1627{
1628
1629 int i;
1630
1631
1632 for (i=0; i < INPCB_MAX_IDS; i++) {
1633 if ((pcbinfo->all_owners & (1 << i)) == 0) {
1634 pcbinfo->all_owners |= (1 << i);
1635 *owner_id = (1 << i);
1636 return 0;
1637 }
1638 }
1639
1640 return ENOSPC;
1641}
1642
1643int
1644in_pcb_rem_share_client(struct inpcbinfo *pcbinfo, u_char owner_id)
1645{
1646 struct inpcb *inp;
1647
1648
91447636 1649 lck_rw_lock_exclusive(pcbinfo->mtx);
1c79356b
A
1650 if (pcbinfo->all_owners & owner_id) {
1651 pcbinfo->all_owners &= ~owner_id;
1652 for (inp = pcbinfo->listhead->lh_first; inp != NULL; inp = inp->inp_list.le_next) {
1653 if (inp->nat_owner & owner_id) {
1654 if (inp->nat_owner == owner_id)
1655 /*
1656 * Deallocate the pcb
1657 */
91447636 1658 in_pcb_detach_port(inp);
1c79356b
A
1659 else
1660 inp->nat_owner &= ~owner_id;
1661 }
1662 }
1663 }
1664 else {
91447636 1665 lck_rw_done(pcbinfo->mtx);
1c79356b
A
1666 return ENOENT;
1667 }
1668
91447636 1669 lck_rw_done(pcbinfo->mtx);
1c79356b
A
1670 return 0;
1671}
1672
9bccf70c
A
1673
1674
1c79356b
A
1675void in_pcb_nat_init(struct inpcbinfo *pcbinfo, int afamily,
1676 int pfamily, int protocol)
1677{
91447636
A
1678 int stat;
1679 struct proc *p = current_proc();
1680
1c79356b 1681 bzero(&pcbinfo->nat_dummy_socket, sizeof(struct socket));
91447636 1682 pcbinfo->nat_dummy_socket.so_proto = pffindproto_locked(afamily, pfamily, protocol);
1c79356b 1683 pcbinfo->all_owners = 0;
91447636
A
1684 stat = in_pcballoc(&pcbinfo->nat_dummy_socket, pcbinfo, p);
1685 if (stat)
1686 panic("in_pcb_nat_init: can't alloc fakepcb err=%\n", stat);
1687 pcbinfo->nat_dummy_pcb = pcbinfo->nat_dummy_socket.so_pcb;
1c79356b 1688}
9bccf70c 1689
91447636
A
1690/* Mechanism used to defer the memory release of PCBs
1691 * The pcb list will contain the pcb until the ripper can clean it up if
1692 * the following conditions are met: 1) state "DEAD", 2) wantcnt is STOPUSING
1693 * 3) usecount is null
1694 * This function will be called to either mark the pcb as
1695*/
1696int
1697in_pcb_checkstate(struct inpcb *pcb, int mode, int locked)
1698
1699{
1700
1701 volatile UInt32 *wantcnt = (volatile UInt32 *)&pcb->inp_wantcnt;
1702 UInt32 origwant;
1703 UInt32 newwant;
1704
1705 switch (mode) {
1706
1707 case WNT_STOPUSING: /* try to mark the pcb as ready for recycling */
1708
1709 /* compareswap with STOPUSING, if success we're good, if it's in use, will be marked later */
1710
1711 if (locked == 0)
1712 socket_lock(pcb->inp_socket, 1);
1713 pcb->inp_state = INPCB_STATE_DEAD;
1714stopusing:
1715 if (pcb->inp_socket->so_usecount < 0)
1716 panic("in_pcb_checkstate STOP pcb=%x so=%x usecount is negative\n", pcb, pcb->inp_socket);
1717 if (locked == 0)
1718 socket_unlock(pcb->inp_socket, 1);
1719
1720 origwant = *wantcnt;
1721 if ((UInt16) origwant == 0xffff ) /* should stop using */
1722 return (WNT_STOPUSING);
1723 newwant = 0xffff;
1724 if ((UInt16) origwant == 0) {/* try to mark it as unsuable now */
1725 OSCompareAndSwap(origwant, newwant, (UInt32 *) wantcnt) ;
1726 }
1727 return (WNT_STOPUSING);
1728 break;
1729
1730 case WNT_ACQUIRE: /* try to increase reference to pcb */
1731 /* if WNT_STOPUSING should bail out */
1732 /*
1733 * if socket state DEAD, try to set count to STOPUSING, return failed
1734 * otherwise increase cnt
1735 */
1736 do {
1737 origwant = *wantcnt;
1738 if ((UInt16) origwant == 0xffff ) {/* should stop using */
1739// printf("in_pcb_checkstate: ACQ PCB was STOPUSING while release. odd pcb=%x\n", pcb);
1740 return (WNT_STOPUSING);
1741 }
1742 newwant = origwant + 1;
1743 } while (!OSCompareAndSwap(origwant, newwant, (UInt32 *) wantcnt));
1744 return (WNT_ACQUIRE);
1745 break;
1746
1747 case WNT_RELEASE: /* release reference. if result is null and pcb state is DEAD,
1748 set wanted bit to STOPUSING
1749 */
1750
1751 if (locked == 0)
1752 socket_lock(pcb->inp_socket, 1);
1753
1754 do {
1755 origwant = *wantcnt;
1756 if ((UInt16) origwant == 0x0 )
1757 panic("in_pcb_checkstate pcb=%x release with zero count", pcb);
1758 if ((UInt16) origwant == 0xffff ) {/* should stop using */
1759#if TEMPDEBUG
1760 printf("in_pcb_checkstate: REL PCB was STOPUSING while release. odd pcb=%x\n", pcb);
1761#endif
1762 if (locked == 0)
1763 socket_unlock(pcb->inp_socket, 1);
1764 return (WNT_STOPUSING);
1765 }
1766 newwant = origwant - 1;
1767 } while (!OSCompareAndSwap(origwant, newwant, (UInt32 *) wantcnt));
1768
1769 if (pcb->inp_state == INPCB_STATE_DEAD)
1770 goto stopusing;
1771 if (pcb->inp_socket->so_usecount < 0)
1772 panic("in_pcb_checkstate RELEASE pcb=%x so=%x usecount is negative\n", pcb, pcb->inp_socket);
1773
1774 if (locked == 0)
1775 socket_unlock(pcb->inp_socket, 1);
1776 return (WNT_RELEASE);
1777 break;
1778
1779 default:
1780
1781 panic("in_pcb_checkstate: so=%x not a valid state =%x\n", pcb->inp_socket, mode);
1782 }
1783
1784 /* NOTREACHED */
1785 return (mode);
1786}
1787
1788/*
1789 * inpcb_to_compat copies specific bits of an inpcb to a inpcb_compat.
1790 * The inpcb_compat data structure is passed to user space and must
1791 * not change. We intentionally avoid copying pointers. The socket is
1792 * the one exception, though we probably shouldn't copy that either.
1793 */
1794void
1795inpcb_to_compat(
1796 struct inpcb *inp,
1797 struct inpcb_compat *inp_compat)
1798{
1799 bzero(inp_compat, sizeof(*inp_compat));
1800 inp_compat->inp_fport = inp->inp_fport;
1801 inp_compat->inp_lport = inp->inp_lport;
1802 inp_compat->inp_socket = inp->inp_socket;
1803 inp_compat->nat_owner = inp->nat_owner;
1804 inp_compat->nat_cookie = inp->nat_cookie;
1805 inp_compat->inp_gencnt = inp->inp_gencnt;
1806 inp_compat->inp_flags = inp->inp_flags;
1807 inp_compat->inp_flow = inp->inp_flow;
1808 inp_compat->inp_vflag = inp->inp_vflag;
1809 inp_compat->inp_ip_ttl = inp->inp_ip_ttl;
1810 inp_compat->inp_ip_p = inp->inp_ip_p;
1811 inp_compat->inp_dependfaddr.inp6_foreign = inp->inp_dependfaddr.inp6_foreign;
1812 inp_compat->inp_dependladdr.inp6_local = inp->inp_dependladdr.inp6_local;
1813 inp_compat->inp_depend4.inp4_ip_tos = inp->inp_depend4.inp4_ip_tos;
1814 inp_compat->inp_depend6.inp6_hlim = inp->inp_depend6.inp6_hlim;
1815 inp_compat->inp_depend6.inp6_cksum = inp->inp_depend6.inp6_cksum;
1816 inp_compat->inp6_ifindex = inp->inp6_ifindex;
1817 inp_compat->inp_depend6.inp6_hops = inp->inp_depend6.inp6_hops;
1818}
9bccf70c
A
1819
1820#ifndef __APPLE__
1821prison_xinpcb(struct proc *p, struct inpcb *inp)
1822{
1823 if (!p->p_prison)
1824 return (0);
1825 if (ntohl(inp->inp_laddr.s_addr) == p->p_prison->pr_ip)
1826 return (0);
1827 return (1);
1828}
1829#endif