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