]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/uipc_usrreq.c
xnu-2050.48.11.tar.gz
[apple/xnu.git] / bsd / kern / uipc_usrreq.c
CommitLineData
1c79356b 1/*
316670eb 2 * Copyright (c) 2000-2012 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
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. 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.
8f6c56a5 14 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 * Copyright (c) 1982, 1986, 1989, 1991, 1993
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 * From: @(#)uipc_usrreq.c 8.3 (Berkeley) 1/4/94
61 */
2d21ac55
A
62/*
63 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
64 * support for mandatory and extensible security protections. This notice
65 * is included in support of clause 2.2 (b) of the Apple Public License,
66 * Version 2.0.
67 */
1c79356b
A
68
69#include <sys/param.h>
70#include <sys/systm.h>
71#include <sys/kernel.h>
72#include <sys/domain.h>
73#include <sys/fcntl.h>
74#include <sys/malloc.h> /* XXX must be before <sys/file.h> */
91447636 75#include <sys/file_internal.h>
1c79356b
A
76#include <sys/filedesc.h>
77#include <sys/lock.h>
78#include <sys/mbuf.h>
79#include <sys/namei.h>
91447636
A
80#include <sys/proc_internal.h>
81#include <sys/kauth.h>
1c79356b
A
82#include <sys/protosw.h>
83#include <sys/socket.h>
84#include <sys/socketvar.h>
85#include <sys/stat.h>
86#include <sys/sysctl.h>
87#include <sys/un.h>
88#include <sys/unpcb.h>
91447636
A
89#include <sys/vnode_internal.h>
90#include <sys/kdebug.h>
1c79356b
A
91
92#include <kern/zalloc.h>
91447636 93#include <kern/locks.h>
1c79356b 94
b0d623f7 95#if CONFIG_MACF
2d21ac55 96#include <security/mac_framework.h>
b0d623f7 97#endif /* CONFIG_MACF */
2d21ac55 98
316670eb
A
99#include <mach/vm_param.h>
100
2d21ac55
A
101#define f_msgcount f_fglob->fg_msgcount
102#define f_cred f_fglob->fg_cred
103#define f_ops f_fglob->fg_ops
104#define f_offset f_fglob->fg_offset
105#define f_data f_fglob->fg_data
1c79356b
A
106struct zone *unp_zone;
107static unp_gen_t unp_gencnt;
108static u_int unp_count;
37839358 109
2d21ac55
A
110static lck_attr_t *unp_mtx_attr;
111static lck_grp_t *unp_mtx_grp;
112static lck_grp_attr_t *unp_mtx_grp_attr;
113static lck_rw_t *unp_list_mtx;
1c79356b 114
b0d623f7
A
115static lck_mtx_t *unp_disconnect_lock;
116static lck_mtx_t *unp_connect_lock;
117static u_int disconnect_in_progress;
118
2d21ac55 119extern lck_mtx_t *uipc_lock;
1c79356b
A
120static struct unp_head unp_shead, unp_dhead;
121
6d2010ae
A
122/*
123 * mDNSResponder tracing. When enabled, endpoints connected to
124 * /var/run/mDNSResponder will be traced; during each send on
125 * the traced socket, we log the PID and process name of the
126 * sending process. We also print out a bit of info related
127 * to the data itself; this assumes ipc_msg_hdr in dnssd_ipc.h
128 * of mDNSResponder stays the same.
129 */
130#define MDNSRESPONDER_PATH "/var/run/mDNSResponder"
131
132static int unpst_tracemdns; /* enable tracing */
133
134#define MDNS_IPC_MSG_HDR_VERSION_1 1
135
136struct mdns_ipc_msg_hdr {
137 uint32_t version;
138 uint32_t datalen;
139 uint32_t ipc_flags;
140 uint32_t op;
141 union {
142 void *context;
143 uint32_t u32[2];
144 } __attribute__((packed));
145 uint32_t reg_index;
146} __attribute__((packed));
147
1c79356b
A
148/*
149 * Unix communications domain.
150 *
151 * TODO:
152 * SEQPACKET, RDM
153 * rethink name space problems
154 * need a proper out-of-band
155 * lock pushdown
156 */
2d21ac55 157static struct sockaddr sun_noname = { sizeof (sun_noname), AF_LOCAL, { 0 } };
1c79356b
A
158static ino_t unp_ino; /* prototype for fake inode numbers */
159
2d21ac55
A
160static int unp_attach(struct socket *);
161static void unp_detach(struct unpcb *);
162static int unp_bind(struct unpcb *, struct sockaddr *, proc_t);
163static int unp_connect(struct socket *, struct sockaddr *, proc_t);
164static void unp_disconnect(struct unpcb *);
165static void unp_shutdown(struct unpcb *);
166static void unp_drop(struct unpcb *, int);
e2fac8b1 167__private_extern__ void unp_gc(void);
2d21ac55
A
168static void unp_scan(struct mbuf *, void (*)(struct fileglob *));
169static void unp_mark(struct fileglob *);
170static void unp_discard(struct fileglob *);
171static void unp_discard_fdlocked(struct fileglob *, proc_t);
172static int unp_internalize(struct mbuf *, proc_t);
173static int unp_listen(struct unpcb *, proc_t);
b0d623f7
A
174static void unpcb_to_compat(struct unpcb *, struct unpcb_compat *);
175static void unp_get_locks_in_order(struct socket *so, struct socket *conn_so);
176
177static void
178unp_get_locks_in_order(struct socket *so, struct socket *conn_so)
179{
180 if (so < conn_so) {
181 socket_lock(conn_so, 1);
182 } else {
183 struct unpcb *unp = sotounpcb(so);
184 unp->unp_flags |= UNP_DONTDISCONNECT;
185 unp->rw_thrcount++;
186 socket_unlock(so, 0);
2d21ac55 187
b0d623f7
A
188 /* Get the locks in the correct order */
189 socket_lock(conn_so, 1);
190 socket_lock(so, 0);
191 unp->rw_thrcount--;
192 if (unp->rw_thrcount == 0) {
193 unp->unp_flags &= ~UNP_DONTDISCONNECT;
194 wakeup(unp);
195 }
196 }
197}
1c79356b
A
198
199static int
200uipc_abort(struct socket *so)
201{
202 struct unpcb *unp = sotounpcb(so);
203
204 if (unp == 0)
2d21ac55 205 return (EINVAL);
1c79356b 206 unp_drop(unp, ECONNABORTED);
91447636
A
207 unp_detach(unp);
208 sofree(so);
2d21ac55 209 return (0);
1c79356b
A
210}
211
212static int
213uipc_accept(struct socket *so, struct sockaddr **nam)
214{
215 struct unpcb *unp = sotounpcb(so);
216
217 if (unp == 0)
2d21ac55 218 return (EINVAL);
1c79356b
A
219
220 /*
221 * Pass back name of connected socket,
222 * if it was bound and we are still connected
223 * (our peer may have closed already!).
224 */
225 if (unp->unp_conn && unp->unp_conn->unp_addr) {
2d21ac55
A
226 *nam = dup_sockaddr((struct sockaddr *)
227 unp->unp_conn->unp_addr, 1);
1c79356b
A
228 } else {
229 *nam = dup_sockaddr((struct sockaddr *)&sun_noname, 1);
230 }
2d21ac55 231 return (0);
1c79356b
A
232}
233
2d21ac55
A
234/*
235 * Returns: 0 Success
236 * EISCONN
237 * unp_attach:
238 */
1c79356b 239static int
2d21ac55 240uipc_attach(struct socket *so, __unused int proto, __unused proc_t p)
1c79356b
A
241{
242 struct unpcb *unp = sotounpcb(so);
243
244 if (unp != 0)
2d21ac55
A
245 return (EISCONN);
246 return (unp_attach(so));
1c79356b
A
247}
248
249static int
2d21ac55 250uipc_bind(struct socket *so, struct sockaddr *nam, proc_t p)
1c79356b
A
251{
252 struct unpcb *unp = sotounpcb(so);
253
254 if (unp == 0)
2d21ac55 255 return (EINVAL);
1c79356b 256
2d21ac55 257 return (unp_bind(unp, nam, p));
1c79356b
A
258}
259
2d21ac55
A
260/*
261 * Returns: 0 Success
262 * EINVAL
263 * unp_connect:??? [See elsewhere in this file]
264 */
1c79356b 265static int
2d21ac55 266uipc_connect(struct socket *so, struct sockaddr *nam, proc_t p)
1c79356b
A
267{
268 struct unpcb *unp = sotounpcb(so);
269
270 if (unp == 0)
2d21ac55
A
271 return (EINVAL);
272 return (unp_connect(so, nam, p));
1c79356b
A
273}
274
2d21ac55
A
275/*
276 * Returns: 0 Success
277 * EINVAL
278 * unp_connect2:EPROTOTYPE Protocol wrong type for socket
279 * unp_connect2:EINVAL Invalid argument
280 */
1c79356b
A
281static int
282uipc_connect2(struct socket *so1, struct socket *so2)
283{
284 struct unpcb *unp = sotounpcb(so1);
285
286 if (unp == 0)
2d21ac55 287 return (EINVAL);
1c79356b 288
2d21ac55 289 return (unp_connect2(so1, so2));
1c79356b
A
290}
291
292/* control is EOPNOTSUPP */
293
294static int
295uipc_detach(struct socket *so)
296{
297 struct unpcb *unp = sotounpcb(so);
298
299 if (unp == 0)
2d21ac55 300 return (EINVAL);
1c79356b 301
6d2010ae 302 lck_mtx_assert(&unp->unp_mtx, LCK_MTX_ASSERT_OWNED);
1c79356b 303 unp_detach(unp);
2d21ac55 304 return (0);
1c79356b
A
305}
306
307static int
308uipc_disconnect(struct socket *so)
309{
310 struct unpcb *unp = sotounpcb(so);
311
312 if (unp == 0)
2d21ac55 313 return (EINVAL);
1c79356b 314 unp_disconnect(unp);
2d21ac55 315 return (0);
1c79356b
A
316}
317
2d21ac55
A
318/*
319 * Returns: 0 Success
320 * EINVAL
321 */
1c79356b 322static int
2d21ac55 323uipc_listen(struct socket *so, __unused proc_t p)
1c79356b
A
324{
325 struct unpcb *unp = sotounpcb(so);
326
327 if (unp == 0 || unp->unp_vnode == 0)
2d21ac55
A
328 return (EINVAL);
329 return (unp_listen(unp, p));
1c79356b
A
330}
331
332static int
333uipc_peeraddr(struct socket *so, struct sockaddr **nam)
334{
335 struct unpcb *unp = sotounpcb(so);
336
2d21ac55
A
337 if (unp == NULL)
338 return (EINVAL);
339 if (unp->unp_conn != NULL && unp->unp_conn->unp_addr != NULL) {
340 *nam = dup_sockaddr((struct sockaddr *)
341 unp->unp_conn->unp_addr, 1);
342 } else {
343 *nam = dup_sockaddr((struct sockaddr *)&sun_noname, 1);
344 }
345 return (0);
1c79356b
A
346}
347
348static int
91447636 349uipc_rcvd(struct socket *so, __unused int flags)
1c79356b
A
350{
351 struct unpcb *unp = sotounpcb(so);
352 struct socket *so2;
353
354 if (unp == 0)
2d21ac55 355 return (EINVAL);
1c79356b
A
356 switch (so->so_type) {
357 case SOCK_DGRAM:
358 panic("uipc_rcvd DGRAM?");
359 /*NOTREACHED*/
360
361 case SOCK_STREAM:
362#define rcv (&so->so_rcv)
2d21ac55 363#define snd (&so2->so_snd)
1c79356b
A
364 if (unp->unp_conn == 0)
365 break;
b0d623f7 366
1c79356b 367 so2 = unp->unp_conn->unp_socket;
b0d623f7 368 unp_get_locks_in_order(so, so2);
1c79356b
A
369 /*
370 * Adjust backpressure on sender
371 * and wakeup any waiting to write.
372 */
373 snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt;
374 unp->unp_mbcnt = rcv->sb_mbcnt;
375 snd->sb_hiwat += unp->unp_cc - rcv->sb_cc;
376 unp->unp_cc = rcv->sb_cc;
377 sowwakeup(so2);
b0d623f7
A
378
379 socket_unlock(so2, 1);
380
1c79356b
A
381#undef snd
382#undef rcv
383 break;
384
385 default:
386 panic("uipc_rcvd unknown socktype");
387 }
2d21ac55 388 return (0);
1c79356b
A
389}
390
391/* pru_rcvoob is EOPNOTSUPP */
392
2d21ac55
A
393/*
394 * Returns: 0 Success
395 * EINVAL
396 * EOPNOTSUPP
397 * EPIPE
398 * ENOTCONN
399 * EISCONN
400 * unp_internalize:EINVAL
401 * unp_internalize:EBADF
402 * unp_connect:EAFNOSUPPORT Address family not supported
403 * unp_connect:EINVAL Invalid argument
404 * unp_connect:ENOTSOCK Not a socket
405 * unp_connect:ECONNREFUSED Connection refused
406 * unp_connect:EISCONN Socket is connected
407 * unp_connect:EPROTOTYPE Protocol wrong type for socket
408 * unp_connect:???
409 * sbappendaddr:ENOBUFS [5th argument, contents modified]
410 * sbappendaddr:??? [whatever a filter author chooses]
411 */
1c79356b
A
412static int
413uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam,
2d21ac55 414 struct mbuf *control, proc_t p)
1c79356b
A
415{
416 int error = 0;
417 struct unpcb *unp = sotounpcb(so);
418 struct socket *so2;
419
420 if (unp == 0) {
421 error = EINVAL;
422 goto release;
423 }
424 if (flags & PRUS_OOB) {
425 error = EOPNOTSUPP;
426 goto release;
427 }
428
13fec989 429 if (control) {
b0d623f7 430 /* release lock to avoid deadlock (4436174) */
2d21ac55 431 socket_unlock(so, 0);
13fec989
A
432 error = unp_internalize(control, p);
433 socket_lock(so, 0);
434 if (error)
435 goto release;
436 }
1c79356b
A
437
438 switch (so->so_type) {
2d21ac55 439 case SOCK_DGRAM:
1c79356b
A
440 {
441 struct sockaddr *from;
442
443 if (nam) {
444 if (unp->unp_conn) {
445 error = EISCONN;
446 break;
447 }
448 error = unp_connect(so, nam, p);
449 if (error)
450 break;
451 } else {
452 if (unp->unp_conn == 0) {
453 error = ENOTCONN;
454 break;
455 }
456 }
b0d623f7 457
1c79356b 458 so2 = unp->unp_conn->unp_socket;
6d2010ae
A
459 if (so != so2)
460 unp_get_locks_in_order(so, so2);
b0d623f7 461
1c79356b
A
462 if (unp->unp_addr)
463 from = (struct sockaddr *)unp->unp_addr;
464 else
465 from = &sun_noname;
2d21ac55
A
466 /*
467 * sbappendaddr() will fail when the receiver runs out of
468 * space; in contrast to SOCK_STREAM, we will lose messages
469 * for the SOCK_DGRAM case when the receiver's queue overflows.
470 * SB_UNIX on the socket buffer implies that the callee will
471 * not free the control message, if any, because we would need
472 * to call unp_dispose() on it.
473 */
91447636 474 if (sbappendaddr(&so2->so_rcv, from, m, control, &error)) {
2d21ac55 475 control = NULL;
1c79356b 476 sorwakeup(so2);
2d21ac55
A
477 } else if (control != NULL && error == 0) {
478 /* A socket filter took control; don't touch it */
479 control = NULL;
91447636 480 }
b0d623f7 481
6d2010ae
A
482 if (so != so2)
483 socket_unlock(so2, 1);
b0d623f7 484
2d21ac55 485 m = NULL;
1c79356b
A
486 if (nam)
487 unp_disconnect(unp);
488 break;
489 }
490
91447636
A
491 case SOCK_STREAM: {
492 int didreceive = 0;
1c79356b
A
493#define rcv (&so2->so_rcv)
494#define snd (&so->so_snd)
495 /* Connect if not connected yet. */
496 /*
497 * Note: A better implementation would complain
498 * if not equal to the peer's address.
499 */
500 if ((so->so_state & SS_ISCONNECTED) == 0) {
501 if (nam) {
502 error = unp_connect(so, nam, p);
503 if (error)
504 break; /* XXX */
505 } else {
506 error = ENOTCONN;
507 break;
508 }
509 }
510
511 if (so->so_state & SS_CANTSENDMORE) {
512 error = EPIPE;
513 break;
514 }
515 if (unp->unp_conn == 0)
516 panic("uipc_send connected but no connection?");
b0d623f7 517
1c79356b 518 so2 = unp->unp_conn->unp_socket;
b0d623f7
A
519 unp_get_locks_in_order(so, so2);
520
521 /* Check socket state again as we might have unlocked the socket
522 * while trying to get the locks in order
523 */
524
525 if ((so->so_state & SS_CANTSENDMORE)) {
526 error = EPIPE;
527 socket_unlock(so2, 1);
528 break;
529 }
530
6d2010ae
A
531 if (unp->unp_flags & UNP_TRACE_MDNS) {
532 struct mdns_ipc_msg_hdr hdr;
533
534 if (mbuf_copydata(m, 0, sizeof (hdr), &hdr) == 0 &&
535 hdr.version == ntohl(MDNS_IPC_MSG_HDR_VERSION_1)) {
536 printf("%s[mDNSResponder] pid=%d (%s): op=0x%x\n",
537 __func__, p->p_pid, p->p_comm, ntohl(hdr.op));
538 }
539 }
540
1c79356b 541 /*
2d21ac55
A
542 * Send to paired receive port, and then reduce send buffer
543 * hiwater marks to maintain backpressure. Wake up readers.
544 * SB_UNIX flag will allow new record to be appended to the
545 * receiver's queue even when it is already full. It is
546 * possible, however, that append might fail. In that case,
547 * we will need to call unp_dispose() on the control message;
548 * the callee will not free it since SB_UNIX is set.
1c79356b 549 */
2d21ac55
A
550 didreceive = control ?
551 sbappendcontrol(rcv, m, control, &error) : sbappend(rcv, m);
552
553 snd->sb_mbmax -= rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt;
1c79356b
A
554 unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt;
555 snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc;
556 unp->unp_conn->unp_cc = rcv->sb_cc;
2d21ac55
A
557 if (didreceive) {
558 control = NULL;
91447636 559 sorwakeup(so2);
2d21ac55
A
560 } else if (control != NULL && error == 0) {
561 /* A socket filter took control; don't touch it */
562 control = NULL;
563 }
b0d623f7
A
564
565 socket_unlock(so2, 1);
2d21ac55 566 m = NULL;
1c79356b
A
567#undef snd
568#undef rcv
91447636 569 }
1c79356b
A
570 break;
571
572 default:
573 panic("uipc_send unknown socktype");
574 }
575
576 /*
577 * SEND_EOF is equivalent to a SEND followed by
578 * a SHUTDOWN.
579 */
580 if (flags & PRUS_EOF) {
581 socantsendmore(so);
582 unp_shutdown(unp);
583 }
584
2d21ac55
A
585 if (control && error != 0) {
586 socket_unlock(so, 0);
91447636 587 unp_dispose(control);
2d21ac55
A
588 socket_lock(so, 0);
589 }
91447636 590
1c79356b
A
591release:
592 if (control)
593 m_freem(control);
594 if (m)
595 m_freem(m);
2d21ac55 596 return (error);
1c79356b
A
597}
598
599static int
2d21ac55 600uipc_sense(struct socket *so, void *ub, int isstat64)
1c79356b
A
601{
602 struct unpcb *unp = sotounpcb(so);
603 struct socket *so2;
2d21ac55 604 blksize_t blksize;
1c79356b
A
605
606 if (unp == 0)
2d21ac55
A
607 return (EINVAL);
608
609 blksize = so->so_snd.sb_hiwat;
1c79356b
A
610 if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) {
611 so2 = unp->unp_conn->unp_socket;
2d21ac55 612 blksize += so2->so_rcv.sb_cc;
1c79356b 613 }
1c79356b
A
614 if (unp->unp_ino == 0)
615 unp->unp_ino = unp_ino++;
2d21ac55
A
616
617 if (isstat64 != 0) {
618 struct stat64 *sb64;
619
620 sb64 = (struct stat64 *)ub;
621 sb64->st_blksize = blksize;
622 sb64->st_dev = NODEV;
623 sb64->st_ino = (ino64_t)unp->unp_ino;
624 } else {
625 struct stat *sb;
626
627 sb = (struct stat *)ub;
628 sb->st_blksize = blksize;
629 sb->st_dev = NODEV;
b0d623f7 630 sb->st_ino = (ino_t)(uintptr_t)unp->unp_ino;
2d21ac55
A
631 }
632
1c79356b
A
633 return (0);
634}
635
2d21ac55
A
636/*
637 * Returns: 0 Success
638 * EINVAL
639 *
640 * Notes: This is not strictly correct, as unp_shutdown() also calls
641 * socantrcvmore(). These should maybe both be conditionalized
642 * on the 'how' argument in soshutdown() as called from the
643 * shutdown() system call.
644 */
1c79356b
A
645static int
646uipc_shutdown(struct socket *so)
647{
648 struct unpcb *unp = sotounpcb(so);
649
650 if (unp == 0)
2d21ac55 651 return (EINVAL);
1c79356b
A
652 socantsendmore(so);
653 unp_shutdown(unp);
2d21ac55 654 return (0);
1c79356b
A
655}
656
2d21ac55
A
657/*
658 * Returns: 0 Success
659 * EINVAL Invalid argument
660 */
1c79356b
A
661static int
662uipc_sockaddr(struct socket *so, struct sockaddr **nam)
663{
664 struct unpcb *unp = sotounpcb(so);
665
2d21ac55
A
666 if (unp == NULL)
667 return (EINVAL);
668 if (unp->unp_addr != NULL) {
1c79356b 669 *nam = dup_sockaddr((struct sockaddr *)unp->unp_addr, 1);
2d21ac55
A
670 } else {
671 *nam = dup_sockaddr((struct sockaddr *)&sun_noname, 1);
672 }
673 return (0);
1c79356b
A
674}
675
676struct pr_usrreqs uipc_usrreqs = {
677 uipc_abort, uipc_accept, uipc_attach, uipc_bind, uipc_connect,
678 uipc_connect2, pru_control_notsupp, uipc_detach, uipc_disconnect,
679 uipc_listen, uipc_peeraddr, uipc_rcvd, pru_rcvoob_notsupp,
680 uipc_send, uipc_sense, uipc_shutdown, uipc_sockaddr,
91447636 681 sosend, soreceive, pru_sopoll_notsupp
1c79356b 682};
91447636
A
683
684int
2d21ac55 685uipc_ctloutput(struct socket *so, struct sockopt *sopt)
91447636
A
686{
687 struct unpcb *unp = sotounpcb(so);
688 int error;
689
690 switch (sopt->sopt_dir) {
691 case SOPT_GET:
692 switch (sopt->sopt_name) {
693 case LOCAL_PEERCRED:
2d21ac55 694 if (unp->unp_flags & UNP_HAVEPC) {
91447636 695 error = sooptcopyout(sopt, &unp->unp_peercred,
2d21ac55
A
696 sizeof (unp->unp_peercred));
697 } else {
91447636
A
698 if (so->so_type == SOCK_STREAM)
699 error = ENOTCONN;
700 else
701 error = EINVAL;
702 }
703 break;
316670eb
A
704 case LOCAL_PEERPID:
705 if (unp->unp_conn != NULL) {
706 if (unp->unp_conn->unp_socket != NULL) {
707 pid_t peerpid = unp->unp_conn->unp_socket->last_pid;
708 error = sooptcopyout(sopt, &peerpid, sizeof (peerpid));
709 } else {
710 panic("peer is connected but has no socket?");
711 }
712 } else {
713 error = ENOTCONN;
714 }
715 break;
91447636
A
716 default:
717 error = EOPNOTSUPP;
718 break;
719 }
720 break;
721 case SOPT_SET:
722 default:
723 error = EOPNOTSUPP;
724 break;
725 }
726 return (error);
727}
2d21ac55 728
1c79356b
A
729/*
730 * Both send and receive buffers are allocated PIPSIZ bytes of buffering
731 * for stream sockets, although the total for sender and receiver is
732 * actually only PIPSIZ.
733 * Datagram sockets really use the sendspace as the maximum datagram size,
734 * and don't really want to reserve the sendspace. Their recvspace should
735 * be large enough for at least one max-size datagram plus address.
736 */
737#ifndef PIPSIZ
738#define PIPSIZ 8192
739#endif
b0d623f7
A
740static u_int32_t unpst_sendspace = PIPSIZ;
741static u_int32_t unpst_recvspace = PIPSIZ;
742static u_int32_t unpdg_sendspace = 2*1024; /* really max datagram size */
743static u_int32_t unpdg_recvspace = 4*1024;
1c79356b
A
744
745static int unp_rights; /* file descriptors in flight */
2d21ac55 746static int unp_disposed; /* discarded file descriptors */
1c79356b
A
747
748SYSCTL_DECL(_net_local_stream);
6d2010ae 749SYSCTL_INT(_net_local_stream, OID_AUTO, sendspace, CTLFLAG_RW | CTLFLAG_LOCKED,
2d21ac55 750 &unpst_sendspace, 0, "");
6d2010ae 751SYSCTL_INT(_net_local_stream, OID_AUTO, recvspace, CTLFLAG_RW | CTLFLAG_LOCKED,
2d21ac55 752 &unpst_recvspace, 0, "");
6d2010ae
A
753SYSCTL_INT(_net_local_stream, OID_AUTO, tracemdns, CTLFLAG_RW | CTLFLAG_LOCKED,
754 &unpst_tracemdns, 0, "");
1c79356b 755SYSCTL_DECL(_net_local_dgram);
6d2010ae 756SYSCTL_INT(_net_local_dgram, OID_AUTO, maxdgram, CTLFLAG_RW | CTLFLAG_LOCKED,
2d21ac55 757 &unpdg_sendspace, 0, "");
6d2010ae 758SYSCTL_INT(_net_local_dgram, OID_AUTO, recvspace, CTLFLAG_RW | CTLFLAG_LOCKED,
2d21ac55 759 &unpdg_recvspace, 0, "");
1c79356b 760SYSCTL_DECL(_net_local);
6d2010ae 761SYSCTL_INT(_net_local, OID_AUTO, inflight, CTLFLAG_RD | CTLFLAG_LOCKED, &unp_rights, 0, "");
1c79356b 762
2d21ac55
A
763/*
764 * Returns: 0 Success
765 * ENOBUFS
766 * soreserve:ENOBUFS
767 */
1c79356b 768static int
91447636 769unp_attach(struct socket *so)
1c79356b 770{
91447636
A
771 struct unpcb *unp;
772 int error = 0;
1c79356b
A
773
774 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
775 switch (so->so_type) {
776
777 case SOCK_STREAM:
778 error = soreserve(so, unpst_sendspace, unpst_recvspace);
779 break;
780
781 case SOCK_DGRAM:
782 error = soreserve(so, unpdg_sendspace, unpdg_recvspace);
783 break;
784
785 default:
786 panic("unp_attach");
787 }
788 if (error)
789 return (error);
790 }
2d21ac55 791 unp = (struct unpcb *)zalloc(unp_zone);
1c79356b
A
792 if (unp == NULL)
793 return (ENOBUFS);
2d21ac55 794 bzero(unp, sizeof (*unp));
b0d623f7 795
6d2010ae
A
796 lck_mtx_init(&unp->unp_mtx,
797 unp_mtx_grp, unp_mtx_attr);
b0d623f7 798
37839358 799 lck_rw_lock_exclusive(unp_list_mtx);
1c79356b
A
800 LIST_INIT(&unp->unp_refs);
801 unp->unp_socket = so;
91447636
A
802 unp->unp_gencnt = ++unp_gencnt;
803 unp_count++;
2d21ac55
A
804 LIST_INSERT_HEAD(so->so_type == SOCK_DGRAM ?
805 &unp_dhead : &unp_shead, unp, unp_link);
b0d623f7 806 lck_rw_done(unp_list_mtx);
1c79356b 807 so->so_pcb = (caddr_t)unp;
2d21ac55
A
808 /*
809 * Mark AF_UNIX socket buffers accordingly so that:
810 *
811 * a. In the SOCK_STREAM case, socket buffer append won't fail due to
812 * the lack of space; this essentially loosens the sbspace() check,
813 * since there is disconnect between sosend() and uipc_send() with
814 * respect to flow control that might result in our dropping the
815 * data in uipc_send(). By setting this, we allow for slightly
816 * more records to be appended to the receiving socket to avoid
817 * losing data (which we can't afford in the SOCK_STREAM case).
818 * Flow control still takes place since we adjust the sender's
819 * hiwat during each send. This doesn't affect the SOCK_DGRAM
820 * case and append would still fail when the queue overflows.
821 *
822 * b. In the presence of control messages containing internalized
823 * file descriptors, the append routines will not free them since
824 * we'd need to undo the work first via unp_dispose().
825 */
826 so->so_rcv.sb_flags |= SB_UNIX;
827 so->so_snd.sb_flags |= SB_UNIX;
1c79356b
A
828 return (0);
829}
830
831static void
91447636 832unp_detach(struct unpcb *unp)
1c79356b 833{
b7266188
A
834 int so_locked = 1;
835
37839358 836 lck_rw_lock_exclusive(unp_list_mtx);
1c79356b 837 LIST_REMOVE(unp, unp_link);
316670eb
A
838 --unp_count;
839 ++unp_gencnt;
37839358 840 lck_rw_done(unp_list_mtx);
1c79356b 841 if (unp->unp_vnode) {
b0d623f7
A
842 struct vnode *tvp = NULL;
843 socket_unlock(unp->unp_socket, 0);
844
845 /* Holding unp_connect_lock will avoid a race between
846 * a thread closing the listening socket and a thread
847 * connecting to it.
848 */
849 lck_mtx_lock(unp_connect_lock);
850 socket_lock(unp->unp_socket, 0);
851 if (unp->unp_vnode) {
852 tvp = unp->unp_vnode;
853 unp->unp_vnode->v_socket = NULL;
854 unp->unp_vnode = NULL;
855 }
856 lck_mtx_unlock(unp_connect_lock);
857 if (tvp != NULL)
858 vnode_rele(tvp); /* drop the usecount */
1c79356b
A
859 }
860 if (unp->unp_conn)
861 unp_disconnect(unp);
b0d623f7 862 while (unp->unp_refs.lh_first) {
b7266188
A
863 struct unpcb *unp2 = NULL;
864
865 /* This datagram socket is connected to one or more
866 * sockets. In order to avoid a race condition between removing
867 * this reference and closing the connected socket, we need
868 * to check disconnect_in_progress
869 */
870 if (so_locked == 1) {
871 socket_unlock(unp->unp_socket, 0);
872 so_locked = 0;
873 }
874 lck_mtx_lock(unp_disconnect_lock);
875 while (disconnect_in_progress != 0) {
876 (void)msleep((caddr_t)&disconnect_in_progress, unp_disconnect_lock,
877 PSOCK, "disconnect", NULL);
878 }
879 disconnect_in_progress = 1;
880 lck_mtx_unlock(unp_disconnect_lock);
881
882 /* Now we are sure that any unpcb socket disconnect is not happening */
883 if (unp->unp_refs.lh_first != NULL) {
884 unp2 = unp->unp_refs.lh_first;
885 socket_lock(unp2->unp_socket, 1);
886 }
887
888 lck_mtx_lock(unp_disconnect_lock);
889 disconnect_in_progress = 0;
890 wakeup(&disconnect_in_progress);
891 lck_mtx_unlock(unp_disconnect_lock);
892
893 if (unp2 != NULL) {
894 /* We already locked this socket and have a reference on it */
895 unp_drop(unp2, ECONNRESET);
896 socket_unlock(unp2->unp_socket, 1);
897 }
898 }
899
900 if (so_locked == 0) {
b0d623f7 901 socket_lock(unp->unp_socket, 0);
b7266188 902 so_locked = 1;
b0d623f7 903 }
1c79356b 904 soisdisconnected(unp->unp_socket);
2d21ac55
A
905 /* makes sure we're getting dealloced */
906 unp->unp_socket->so_flags |= SOF_PCBCLEARING;
1c79356b
A
907}
908
2d21ac55
A
909/*
910 * Returns: 0 Success
911 * EAFNOSUPPORT
912 * EINVAL
913 * EADDRINUSE
914 * namei:??? [anything namei can return]
915 * vnode_authorize:??? [anything vnode_authorize can return]
916 *
917 * Notes: p at this point is the current process, as this function is
918 * only called by sobind().
919 */
1c79356b 920static int
91447636
A
921unp_bind(
922 struct unpcb *unp,
923 struct sockaddr *nam,
2d21ac55 924 proc_t p)
1c79356b
A
925{
926 struct sockaddr_un *soun = (struct sockaddr_un *)nam;
91447636
A
927 struct vnode *vp, *dvp;
928 struct vnode_attr va;
2d21ac55 929 vfs_context_t ctx = vfs_context_current();
1c79356b
A
930 int error, namelen;
931 struct nameidata nd;
b0d623f7 932 struct socket *so = unp->unp_socket;
1c79356b
A
933 char buf[SOCK_MAXADDRLEN];
934
2d21ac55
A
935 if (nam->sa_family != 0 && nam->sa_family != AF_UNIX) {
936 return (EAFNOSUPPORT);
937 }
91447636 938
2d21ac55 939 if (unp->unp_vnode != NULL)
1c79356b 940 return (EINVAL);
1c79356b 941 namelen = soun->sun_len - offsetof(struct sockaddr_un, sun_path);
2d21ac55
A
942 if (namelen <= 0)
943 return (EINVAL);
944
b0d623f7
A
945 socket_unlock(so, 0);
946
2d21ac55 947 strlcpy(buf, soun->sun_path, namelen+1);
6d2010ae 948 NDINIT(&nd, CREATE, OP_MKFIFO, FOLLOW | LOCKPARENT, UIO_SYSSPACE,
2d21ac55
A
949 CAST_USER_ADDR_T(buf), ctx);
950 /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
1c79356b
A
951 error = namei(&nd);
952 if (error) {
b0d623f7 953 socket_lock(so, 0);
1c79356b
A
954 return (error);
955 }
91447636 956 dvp = nd.ni_dvp;
1c79356b 957 vp = nd.ni_vp;
91447636 958
1c79356b 959 if (vp != NULL) {
2d21ac55 960 /*
91447636
A
961 * need to do this before the vnode_put of dvp
962 * since we may have to release an fs_nodelock
963 */
964 nameidone(&nd);
965
966 vnode_put(dvp);
967 vnode_put(vp);
968
b0d623f7 969 socket_lock(so, 0);
1c79356b
A
970 return (EADDRINUSE);
971 }
91447636 972
2d21ac55
A
973 VATTR_INIT(&va);
974 VATTR_SET(&va, va_type, VSOCK);
975 VATTR_SET(&va, va_mode, (ACCESSPERMS & ~p->p_fd->fd_cmask));
976
b0d623f7 977#if CONFIG_MACF
2d21ac55
A
978 error = mac_vnode_check_create(ctx,
979 nd.ni_dvp, &nd.ni_cnd, &va);
980
981 if (error == 0)
b0d623f7
A
982#endif /* CONFIG_MACF */
983#if CONFIG_MACF_SOCKET_SUBSET
984 error = mac_vnode_check_uipc_bind(ctx,
985 nd.ni_dvp, &nd.ni_cnd, &va);
986
987 if (error == 0)
988#endif /* MAC_SOCKET_SUBSET */
91447636 989 /* authorize before creating */
2d21ac55 990 error = vnode_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, ctx);
91447636
A
991
992 if (!error) {
91447636 993 /* create the socket */
6d2010ae 994 error = vn_create(dvp, &vp, &nd, &va, 0, 0, NULL, ctx);
91447636 995 }
2d21ac55 996
91447636
A
997 nameidone(&nd);
998 vnode_put(dvp);
999
1c79356b 1000 if (error) {
b0d623f7 1001 socket_lock(so, 0);
1c79356b
A
1002 return (error);
1003 }
91447636 1004 vnode_ref(vp); /* gain a longterm reference */
b0d623f7 1005 socket_lock(so, 0);
1c79356b
A
1006 vp->v_socket = unp->unp_socket;
1007 unp->unp_vnode = vp;
1008 unp->unp_addr = (struct sockaddr_un *)dup_sockaddr(nam, 1);
91447636
A
1009 vnode_put(vp); /* drop the iocount */
1010
1c79356b
A
1011 return (0);
1012}
1013
2d21ac55
A
1014
1015/*
1016 * Returns: 0 Success
1017 * EAFNOSUPPORT Address family not supported
1018 * EINVAL Invalid argument
1019 * ENOTSOCK Not a socket
1020 * ECONNREFUSED Connection refused
1021 * EPROTOTYPE Protocol wrong type for socket
1022 * EISCONN Socket is connected
1023 * unp_connect2:EPROTOTYPE Protocol wrong type for socket
1024 * unp_connect2:EINVAL Invalid argument
1025 * namei:??? [anything namei can return]
1026 * vnode_authorize:???? [anything vnode_authorize can return]
1027 *
1028 * Notes: p at this point is the current process, as this function is
1029 * only called by sosend(), sendfile(), and soconnectlock().
1030 */
1c79356b 1031static int
2d21ac55 1032unp_connect(struct socket *so, struct sockaddr *nam, __unused proc_t p)
1c79356b 1033{
91447636
A
1034 struct sockaddr_un *soun = (struct sockaddr_un *)nam;
1035 struct vnode *vp;
b0d623f7 1036 struct socket *so2, *so3, *list_so=NULL;
91447636 1037 struct unpcb *unp, *unp2, *unp3;
2d21ac55 1038 vfs_context_t ctx = vfs_context_current();
1c79356b
A
1039 int error, len;
1040 struct nameidata nd;
1041 char buf[SOCK_MAXADDRLEN];
1042
2d21ac55
A
1043 if (nam->sa_family != 0 && nam->sa_family != AF_UNIX) {
1044 return (EAFNOSUPPORT);
1045 }
1046
b0d623f7 1047 unp = sotounpcb(so);
cc9f6e38 1048 so2 = so3 = NULL;
91447636 1049
1c79356b 1050 len = nam->sa_len - offsetof(struct sockaddr_un, sun_path);
2d21ac55
A
1051 if (len <= 0)
1052 return (EINVAL);
1053
1054 strlcpy(buf, soun->sun_path, len+1);
b0d623f7 1055 socket_unlock(so, 0);
1c79356b 1056
6d2010ae 1057 NDINIT(&nd, LOOKUP, OP_LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE,
2d21ac55 1058 CAST_USER_ADDR_T(buf), ctx);
1c79356b
A
1059 error = namei(&nd);
1060 if (error) {
b0d623f7 1061 socket_lock(so, 0);
1c79356b
A
1062 return (error);
1063 }
91447636 1064 nameidone(&nd);
1c79356b
A
1065 vp = nd.ni_vp;
1066 if (vp->v_type != VSOCK) {
1067 error = ENOTSOCK;
b0d623f7
A
1068 socket_lock(so, 0);
1069 goto out;
1c79356b 1070 }
91447636 1071
b0d623f7
A
1072#if CONFIG_MACF_SOCKET_SUBSET
1073 error = mac_vnode_check_uipc_connect(ctx, vp);
1074 if (error) {
1075 socket_lock(so, 0);
1076 goto out;
1077 }
1078#endif /* MAC_SOCKET_SUBSET */
1079
2d21ac55 1080 error = vnode_authorize(vp, NULL, KAUTH_VNODE_WRITE_DATA, ctx);
b0d623f7
A
1081 if (error) {
1082 socket_lock(so, 0);
1083 goto out;
1084 }
1085
1086 lck_mtx_lock(unp_connect_lock);
1087
1088 if (vp->v_socket == 0) {
1089 lck_mtx_unlock(unp_connect_lock);
1c79356b 1090 error = ECONNREFUSED;
b0d623f7
A
1091 socket_lock(so, 0);
1092 goto out;
1c79356b 1093 }
91447636 1094
b0d623f7
A
1095 socket_lock(vp->v_socket, 1); /* Get a reference on the listening socket */
1096 so2 = vp->v_socket;
1097 lck_mtx_unlock(unp_connect_lock);
91447636 1098
b0d623f7
A
1099
1100 if (so2->so_pcb == NULL) {
1101 error = ECONNREFUSED;
6d2010ae
A
1102 if (so != so2) {
1103 socket_unlock(so2, 1);
1104 socket_lock(so, 0);
1105 } else {
1106 /* Release the reference held for the listen socket */
1107 so2->so_usecount--;
1108 }
b0d623f7 1109 goto out;
1c79356b 1110 }
2d21ac55 1111
b0d623f7
A
1112 if (so < so2) {
1113 socket_unlock(so2, 0);
1114 socket_lock(so, 0);
1115 socket_lock(so2, 0);
6d2010ae 1116 } else if (so > so2) {
b0d623f7
A
1117 socket_lock(so, 0);
1118 }
55e303ae
A
1119 /*
1120 * Check if socket was connected while we were trying to
b0d623f7 1121 * get the socket locks in order.
55e303ae
A
1122 * XXX - probably shouldn't return an error for SOCK_DGRAM
1123 */
1124 if ((so->so_state & SS_ISCONNECTED) != 0) {
1125 error = EISCONN;
6d2010ae 1126 goto decref_out;
b0d623f7
A
1127 }
1128
1129 if (so->so_type != so2->so_type) {
b0d623f7 1130 error = EPROTOTYPE;
6d2010ae 1131 goto decref_out;
55e303ae 1132 }
2d21ac55 1133
1c79356b 1134 if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
b0d623f7
A
1135 /* Release the incoming socket but keep a reference */
1136 socket_unlock(so, 0);
1137
1c79356b 1138 if ((so2->so_options & SO_ACCEPTCONN) == 0 ||
91447636 1139 (so3 = sonewconn(so2, 0, nam)) == 0) {
1c79356b 1140 error = ECONNREFUSED;
316670eb
A
1141 if (so != so2) {
1142 socket_unlock(so2, 1);
1143 socket_lock(so, 0);
1144 } else {
1145 socket_lock(so, 0);
1146 /* Release the reference held for
1147 * listen socket.
1148 */
1149 so2->so_usecount--;
1150 }
b0d623f7 1151 goto out;
1c79356b
A
1152 }
1153 unp2 = sotounpcb(so2);
1154 unp3 = sotounpcb(so3);
1155 if (unp2->unp_addr)
1156 unp3->unp_addr = (struct sockaddr_un *)
2d21ac55 1157 dup_sockaddr((struct sockaddr *)unp2->unp_addr, 1);
91447636
A
1158
1159 /*
1160 * unp_peercred management:
1161 *
1162 * The connecter's (client's) credentials are copied
1163 * from its process structure at the time of connect()
1164 * (which is now).
1165 */
2d21ac55 1166 cru2x(vfs_context_ucred(ctx), &unp3->unp_peercred);
91447636
A
1167 unp3->unp_flags |= UNP_HAVEPC;
1168 /*
1169 * The receiver's (server's) credentials are copied
1170 * from the unp_peercred member of socket on which the
1171 * former called listen(); unp_listen() cached that
1172 * process's credentials at that time so we can use
1173 * them now.
1174 */
1175 KASSERT(unp2->unp_flags & UNP_HAVEPCCACHED,
1176 ("unp_connect: listener without cached peercred"));
b0d623f7
A
1177
1178 /* Here we need to have both so and so2 locks and so2
1179 * is already locked. Lock ordering is required.
1180 */
1181 if (so < so2) {
1182 socket_unlock(so2, 0);
1183 socket_lock(so, 0);
1184 socket_lock(so2, 0);
1185 } else {
1186 socket_lock(so, 0);
1187 }
1188
1189 /* Check again if the socket state changed when its lock was released */
1190 if ((so->so_state & SS_ISCONNECTED) != 0) {
1191 error = EISCONN;
1192 socket_unlock(so2, 1);
1193 socket_lock(so3, 0);
1194 sofreelastref(so3, 1);
1195 goto out;
1196 }
91447636 1197 memcpy(&unp->unp_peercred, &unp2->unp_peercred,
2d21ac55 1198 sizeof (unp->unp_peercred));
91447636
A
1199 unp->unp_flags |= UNP_HAVEPC;
1200
2d21ac55
A
1201#if CONFIG_MACF_SOCKET
1202 /* XXXMAC: recursive lock: SOCK_LOCK(so); */
1203 mac_socketpeer_label_associate_socket(so, so3);
1204 mac_socketpeer_label_associate_socket(so3, so);
1205 /* XXXMAC: SOCK_UNLOCK(so); */
1206#endif /* MAC_SOCKET */
b0d623f7
A
1207
1208 /* Hold the reference on listening socket until the end */
1209 socket_unlock(so2, 0);
1210 list_so = so2;
1211
1212 /* Lock ordering doesn't matter because so3 was just created */
1213 socket_lock(so3, 1);
1c79356b 1214 so2 = so3;
b0d623f7 1215
6d2010ae
A
1216 /*
1217 * Enable tracing for mDNSResponder endpoints. (The use
1218 * of sizeof instead of strlen below takes the null
1219 * terminating character into account.)
1220 */
1221 if (unpst_tracemdns &&
1222 !strncmp(soun->sun_path, MDNSRESPONDER_PATH,
1223 sizeof (MDNSRESPONDER_PATH))) {
1224 unp->unp_flags |= UNP_TRACE_MDNS;
1225 unp2->unp_flags |= UNP_TRACE_MDNS;
1226 }
1c79356b 1227 }
b0d623f7 1228
1c79356b 1229 error = unp_connect2(so, so2);
6d2010ae
A
1230
1231decref_out:
b0d623f7 1232 if (so2 != NULL) {
6d2010ae
A
1233 if (so != so2) {
1234 socket_unlock(so2, 1);
1235 } else {
1236 /* Release the extra reference held for the listen socket.
1237 * This is possible only for SOCK_DGRAM sockets. We refuse
1238 * connecting to the same socket for SOCK_STREAM sockets.
1239 */
1240 so2->so_usecount--;
1241 }
b0d623f7
A
1242 }
1243
1244 if (list_so != NULL) {
1245 socket_lock(list_so, 0);
1246 socket_unlock(list_so, 1);
1247 }
6d2010ae 1248
b0d623f7 1249out:
6d2010ae 1250 lck_mtx_assert(&unp->unp_mtx, LCK_MTX_ASSERT_OWNED);
91447636 1251 vnode_put(vp);
1c79356b
A
1252 return (error);
1253}
1254
2d21ac55
A
1255/*
1256 * Returns: 0 Success
1257 * EPROTOTYPE Protocol wrong type for socket
1258 * EINVAL Invalid argument
1259 */
1c79356b 1260int
2d21ac55 1261unp_connect2(struct socket *so, struct socket *so2)
1c79356b 1262{
91447636
A
1263 struct unpcb *unp = sotounpcb(so);
1264 struct unpcb *unp2;
1c79356b
A
1265
1266 if (so2->so_type != so->so_type)
1267 return (EPROTOTYPE);
b0d623f7 1268
1c79356b 1269 unp2 = sotounpcb(so2);
0b4e3aa0 1270
6d2010ae
A
1271 lck_mtx_assert(&unp->unp_mtx, LCK_MTX_ASSERT_OWNED);
1272 lck_mtx_assert(&unp2->unp_mtx, LCK_MTX_ASSERT_OWNED);
b0d623f7 1273
0b4e3aa0
A
1274 /* Verify both sockets are still opened */
1275 if (unp == 0 || unp2 == 0)
1276 return (EINVAL);
1277
1c79356b 1278 unp->unp_conn = unp2;
b0d623f7
A
1279 so2->so_usecount++;
1280
1c79356b
A
1281 switch (so->so_type) {
1282
1283 case SOCK_DGRAM:
1284 LIST_INSERT_HEAD(&unp2->unp_refs, unp, unp_reflink);
b0d623f7 1285
6d2010ae
A
1286 if (so != so2) {
1287 /* Avoid lock order reversals due to drop/acquire in soisconnected. */
1288 /* Keep an extra reference on so2 that will be dropped
1289 * soon after getting the locks in order
1290 */
1291 socket_unlock(so2, 0);
1292 soisconnected(so);
1293 unp_get_locks_in_order(so, so2);
1294 so2->so_usecount--;
1295 } else {
1296 soisconnected(so);
1297 }
b0d623f7 1298
1c79356b
A
1299 break;
1300
1301 case SOCK_STREAM:
2d21ac55
A
1302 /* This takes care of socketpair */
1303 if (!(unp->unp_flags & UNP_HAVEPC) &&
1304 !(unp2->unp_flags & UNP_HAVEPC)) {
1305 cru2x(kauth_cred_get(), &unp->unp_peercred);
1306 unp->unp_flags |= UNP_HAVEPC;
1307
1308 cru2x(kauth_cred_get(), &unp2->unp_peercred);
1309 unp2->unp_flags |= UNP_HAVEPC;
1310 }
1c79356b 1311 unp2->unp_conn = unp;
b0d623f7
A
1312 so->so_usecount++;
1313
1314 /* Avoid lock order reversals due to drop/acquire in soisconnected. */
1315 socket_unlock(so, 0);
1c79356b 1316 soisconnected(so2);
b0d623f7
A
1317
1318 /* Keep an extra reference on so2, that will be dropped soon after
1319 * getting the locks in order again.
1320 */
1321 socket_unlock(so2, 0);
1322
1323 socket_lock(so, 0);
1324 soisconnected(so);
1325
1326 unp_get_locks_in_order(so, so2);
1327 /* Decrement the extra reference left before */
1328 so2->so_usecount--;
1c79356b
A
1329 break;
1330
1331 default:
b0d623f7 1332 panic("unknown socket type %d in unp_connect2", so->so_type);
1c79356b 1333 }
6d2010ae
A
1334 lck_mtx_assert(&unp->unp_mtx, LCK_MTX_ASSERT_OWNED);
1335 lck_mtx_assert(&unp2->unp_mtx, LCK_MTX_ASSERT_OWNED);
1c79356b
A
1336 return (0);
1337}
1338
1339static void
91447636 1340unp_disconnect(struct unpcb *unp)
1c79356b 1341{
b0d623f7
A
1342 struct unpcb *unp2 = NULL;
1343 struct socket *so2 = NULL, *so;
1344 struct socket *waitso;
1345 int so_locked = 1, strdisconn = 0;
1c79356b 1346
b0d623f7
A
1347 so = unp->unp_socket;
1348 if (unp->unp_conn == NULL) {
1c79356b 1349 return;
b0d623f7
A
1350 }
1351 lck_mtx_lock(unp_disconnect_lock);
1352 while (disconnect_in_progress != 0) {
1353 if (so_locked == 1) {
1354 socket_unlock(so, 0);
1355 so_locked = 0;
1356 }
1357 (void)msleep((caddr_t)&disconnect_in_progress, unp_disconnect_lock,
1358 PSOCK, "disconnect", NULL);
1359 }
1360 disconnect_in_progress = 1;
1361 lck_mtx_unlock(unp_disconnect_lock);
1362
1363 if (so_locked == 0) {
1364 socket_lock(so, 0);
1365 so_locked = 1;
1366 }
1367
1368 unp2 = unp->unp_conn;
1369
1370 if (unp2 == 0 || unp2->unp_socket == NULL) {
1371 goto out;
1372 }
1373 so2 = unp2->unp_socket;
1374
1375try_again:
6d2010ae
A
1376 if (so == so2) {
1377 if (so_locked == 0) {
1378 socket_lock(so, 0);
1379 }
1380 waitso = so;
1381 } else if (so < so2) {
b0d623f7
A
1382 if (so_locked == 0) {
1383 socket_lock(so, 0);
1384 }
1385 socket_lock(so2, 1);
1386 waitso = so2;
1387 } else {
1388 if (so_locked == 1) {
1389 socket_unlock(so, 0);
1390 }
1391 socket_lock(so2, 1);
1392 socket_lock(so, 0);
1393 waitso = so;
1394 }
6d2010ae 1395 so_locked = 1;
b0d623f7 1396
6d2010ae
A
1397 lck_mtx_assert(&unp->unp_mtx, LCK_MTX_ASSERT_OWNED);
1398 lck_mtx_assert(&unp2->unp_mtx, LCK_MTX_ASSERT_OWNED);
b0d623f7
A
1399
1400 /* Check for the UNP_DONTDISCONNECT flag, if it
1401 * is set, release both sockets and go to sleep
1402 */
1403
1404 if ((((struct unpcb *)waitso->so_pcb)->unp_flags & UNP_DONTDISCONNECT) != 0) {
6d2010ae
A
1405 if (so != so2) {
1406 socket_unlock(so2, 1);
1407 }
b0d623f7
A
1408 so_locked = 0;
1409
6d2010ae 1410 (void)msleep(waitso->so_pcb, &unp->unp_mtx,
b0d623f7
A
1411 PSOCK | PDROP, "unpdisconnect", NULL);
1412 goto try_again;
1413 }
1414
1415 if (unp->unp_conn == NULL) {
1416 panic("unp_conn became NULL after sleep");
1417 }
1418
2d21ac55 1419 unp->unp_conn = NULL;
b0d623f7
A
1420 so2->so_usecount--;
1421
6d2010ae
A
1422 if (unp->unp_flags & UNP_TRACE_MDNS)
1423 unp->unp_flags &= ~UNP_TRACE_MDNS;
1424
1c79356b
A
1425 switch (unp->unp_socket->so_type) {
1426
1427 case SOCK_DGRAM:
1428 LIST_REMOVE(unp, unp_reflink);
1429 unp->unp_socket->so_state &= ~SS_ISCONNECTED;
6d2010ae
A
1430 if (so != so2)
1431 socket_unlock(so2, 1);
1c79356b
A
1432 break;
1433
1434 case SOCK_STREAM:
2d21ac55 1435 unp2->unp_conn = NULL;
b0d623f7
A
1436 so->so_usecount--;
1437
1438 /* Set the socket state correctly but do a wakeup later when
1439 * we release all locks except the socket lock, this will avoid
1440 * a deadlock.
1441 */
1442 unp->unp_socket->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
1443 unp->unp_socket->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE|SS_ISDISCONNECTED);
1444
1445 unp2->unp_socket->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
1446 unp->unp_socket->so_state |= (SS_CANTRCVMORE|SS_CANTSENDMORE|SS_ISDISCONNECTED);
6d2010ae
A
1447
1448 if (unp2->unp_flags & UNP_TRACE_MDNS)
1449 unp2->unp_flags &= ~UNP_TRACE_MDNS;
1450
b0d623f7 1451 strdisconn = 1;
1c79356b 1452 break;
b0d623f7
A
1453 default:
1454 panic("unknown socket type %d", so->so_type);
1c79356b 1455 }
b0d623f7
A
1456out:
1457 lck_mtx_lock(unp_disconnect_lock);
1458 disconnect_in_progress = 0;
1459 wakeup(&disconnect_in_progress);
1460 lck_mtx_unlock(unp_disconnect_lock);
1c79356b 1461
b0d623f7
A
1462 if (strdisconn) {
1463 socket_unlock(so, 0);
1464 soisdisconnected(so2);
1465 socket_unlock(so2, 1);
1c79356b 1466
b0d623f7
A
1467 socket_lock(so,0);
1468 soisdisconnected(so);
1469 }
6d2010ae 1470 lck_mtx_assert(&unp->unp_mtx, LCK_MTX_ASSERT_OWNED);
b0d623f7 1471 return;
1c79356b 1472}
b0d623f7
A
1473
1474/*
1475 * unpcb_to_compat copies specific bits of a unpcb to a unpcb_compat format.
1476 * The unpcb_compat data structure is passed to user space and must not change.
1477 */
1478static void
1479unpcb_to_compat(struct unpcb *up, struct unpcb_compat *cp)
1480{
1481#if defined(__LP64__)
316670eb
A
1482 cp->unp_link.le_next = (u_int32_t)
1483 VM_KERNEL_ADDRPERM(up->unp_link.le_next);
1484 cp->unp_link.le_prev = (u_int32_t)
1485 VM_KERNEL_ADDRPERM(up->unp_link.le_prev);
b0d623f7 1486#else
316670eb
A
1487 cp->unp_link.le_next = (struct unpcb_compat *)
1488 VM_KERNEL_ADDRPERM(up->unp_link.le_next);
1489 cp->unp_link.le_prev = (struct unpcb_compat **)
1490 VM_KERNEL_ADDRPERM(up->unp_link.le_prev);
b0d623f7 1491#endif
316670eb
A
1492 cp->unp_socket = (_UNPCB_PTR(struct socket *))
1493 VM_KERNEL_ADDRPERM(up->unp_socket);
1494 cp->unp_vnode = (_UNPCB_PTR(struct vnode *))
1495 VM_KERNEL_ADDRPERM(up->unp_vnode);
b0d623f7
A
1496 cp->unp_ino = up->unp_ino;
1497 cp->unp_conn = (_UNPCB_PTR(struct unpcb_compat *))
316670eb
A
1498 VM_KERNEL_ADDRPERM(up->unp_conn);
1499 cp->unp_refs = (u_int32_t)VM_KERNEL_ADDRPERM(up->unp_refs.lh_first);
b0d623f7
A
1500#if defined(__LP64__)
1501 cp->unp_reflink.le_next =
316670eb 1502 (u_int32_t)VM_KERNEL_ADDRPERM(up->unp_reflink.le_next);
b0d623f7 1503 cp->unp_reflink.le_prev =
316670eb 1504 (u_int32_t)VM_KERNEL_ADDRPERM(up->unp_reflink.le_prev);
b0d623f7
A
1505#else
1506 cp->unp_reflink.le_next =
316670eb 1507 (struct unpcb_compat *)VM_KERNEL_ADDRPERM(up->unp_reflink.le_next);
b0d623f7 1508 cp->unp_reflink.le_prev =
316670eb 1509 (struct unpcb_compat **)VM_KERNEL_ADDRPERM(up->unp_reflink.le_prev);
1c79356b 1510#endif
b0d623f7 1511 cp->unp_addr = (_UNPCB_PTR(struct sockaddr_un *))
316670eb 1512 VM_KERNEL_ADDRPERM(up->unp_addr);
b0d623f7
A
1513 cp->unp_cc = up->unp_cc;
1514 cp->unp_mbcnt = up->unp_mbcnt;
1515 cp->unp_gencnt = up->unp_gencnt;
1516}
1c79356b
A
1517
1518static int
1519unp_pcblist SYSCTL_HANDLER_ARGS
1520{
2d21ac55 1521#pragma unused(oidp,arg2)
1c79356b
A
1522 int error, i, n;
1523 struct unpcb *unp, **unp_list;
1524 unp_gen_t gencnt;
1525 struct xunpgen xug;
1526 struct unp_head *head;
1527
37839358 1528 lck_rw_lock_shared(unp_list_mtx);
1c79356b
A
1529 head = ((intptr_t)arg1 == SOCK_DGRAM ? &unp_dhead : &unp_shead);
1530
1531 /*
1532 * The process of preparing the PCB list is too time-consuming and
1533 * resource-intensive to repeat twice on every request.
1534 */
91447636 1535 if (req->oldptr == USER_ADDR_NULL) {
1c79356b 1536 n = unp_count;
2d21ac55
A
1537 req->oldidx = 2 * sizeof (xug) + (n + n / 8) *
1538 sizeof (struct xunpcb);
37839358 1539 lck_rw_done(unp_list_mtx);
2d21ac55 1540 return (0);
1c79356b
A
1541 }
1542
91447636 1543 if (req->newptr != USER_ADDR_NULL) {
37839358 1544 lck_rw_done(unp_list_mtx);
2d21ac55 1545 return (EPERM);
91447636 1546 }
1c79356b
A
1547
1548 /*
1549 * OK, now we're committed to doing something.
1550 */
1551 gencnt = unp_gencnt;
1552 n = unp_count;
1553
2d21ac55
A
1554 bzero(&xug, sizeof (xug));
1555 xug.xug_len = sizeof (xug);
1c79356b
A
1556 xug.xug_count = n;
1557 xug.xug_gen = gencnt;
1558 xug.xug_sogen = so_gencnt;
2d21ac55 1559 error = SYSCTL_OUT(req, &xug, sizeof (xug));
91447636 1560 if (error) {
37839358 1561 lck_rw_done(unp_list_mtx);
2d21ac55 1562 return (error);
91447636 1563 }
1c79356b 1564
0b4e3aa0
A
1565 /*
1566 * We are done if there is no pcb
1567 */
91447636 1568 if (n == 0) {
2d21ac55
A
1569 lck_rw_done(unp_list_mtx);
1570 return (0);
91447636 1571 }
0b4e3aa0 1572
2d21ac55
A
1573 MALLOC(unp_list, struct unpcb **, n * sizeof (*unp_list),
1574 M_TEMP, M_WAITOK);
91447636 1575 if (unp_list == 0) {
37839358 1576 lck_rw_done(unp_list_mtx);
2d21ac55 1577 return (ENOMEM);
91447636 1578 }
2d21ac55 1579
1c79356b 1580 for (unp = head->lh_first, i = 0; unp && i < n;
2d21ac55 1581 unp = unp->unp_link.le_next) {
1c79356b
A
1582 if (unp->unp_gencnt <= gencnt)
1583 unp_list[i++] = unp;
1584 }
1585 n = i; /* in case we lost some during malloc */
1586
1587 error = 0;
1588 for (i = 0; i < n; i++) {
1589 unp = unp_list[i];
1590 if (unp->unp_gencnt <= gencnt) {
1591 struct xunpcb xu;
3a60a9f5 1592
2d21ac55
A
1593 bzero(&xu, sizeof (xu));
1594 xu.xu_len = sizeof (xu);
b0d623f7 1595 xu.xu_unpp = (_UNPCB_PTR(struct unpcb_compat *))
316670eb 1596 VM_KERNEL_ADDRPERM(unp);
1c79356b
A
1597 /*
1598 * XXX - need more locking here to protect against
1599 * connect/disconnect races for SMP.
1600 */
1601 if (unp->unp_addr)
2d21ac55
A
1602 bcopy(unp->unp_addr, &xu.xu_addr,
1603 unp->unp_addr->sun_len);
1c79356b
A
1604 if (unp->unp_conn && unp->unp_conn->unp_addr)
1605 bcopy(unp->unp_conn->unp_addr,
2d21ac55
A
1606 &xu.xu_caddr,
1607 unp->unp_conn->unp_addr->sun_len);
b0d623f7 1608 unpcb_to_compat(unp, &xu.xu_unp);
1c79356b 1609 sotoxsocket(unp->unp_socket, &xu.xu_socket);
2d21ac55 1610 error = SYSCTL_OUT(req, &xu, sizeof (xu));
1c79356b
A
1611 }
1612 }
1613 if (!error) {
1614 /*
1615 * Give the user an updated idea of our state.
1616 * If the generation differs from what we told
1617 * her before, she knows that something happened
1618 * while we were processing this request, and it
1619 * might be necessary to retry.
1620 */
2d21ac55
A
1621 bzero(&xug, sizeof (xug));
1622 xug.xug_len = sizeof (xug);
1c79356b
A
1623 xug.xug_gen = unp_gencnt;
1624 xug.xug_sogen = so_gencnt;
1625 xug.xug_count = unp_count;
2d21ac55 1626 error = SYSCTL_OUT(req, &xug, sizeof (xug));
1c79356b
A
1627 }
1628 FREE(unp_list, M_TEMP);
37839358 1629 lck_rw_done(unp_list_mtx);
2d21ac55 1630 return (error);
1c79356b
A
1631}
1632
6d2010ae 1633SYSCTL_PROC(_net_local_dgram, OID_AUTO, pcblist, CTLFLAG_RD | CTLFLAG_LOCKED,
b0d623f7
A
1634 (caddr_t)(long)SOCK_DGRAM, 0, unp_pcblist, "S,xunpcb",
1635 "List of active local datagram sockets");
6d2010ae 1636SYSCTL_PROC(_net_local_stream, OID_AUTO, pcblist, CTLFLAG_RD | CTLFLAG_LOCKED,
b0d623f7
A
1637 (caddr_t)(long)SOCK_STREAM, 0, unp_pcblist, "S,xunpcb",
1638 "List of active local stream sockets");
1639
1640#if !CONFIG_EMBEDDED
1641
1642static int
1643unp_pcblist64 SYSCTL_HANDLER_ARGS
1644{
1645#pragma unused(oidp,arg2)
1646 int error, i, n;
1647 struct unpcb *unp, **unp_list;
1648 unp_gen_t gencnt;
1649 struct xunpgen xug;
1650 struct unp_head *head;
1651
1652 lck_rw_lock_shared(unp_list_mtx);
1653 head = ((intptr_t)arg1 == SOCK_DGRAM ? &unp_dhead : &unp_shead);
1654
1655 /*
1656 * The process of preparing the PCB list is too time-consuming and
1657 * resource-intensive to repeat twice on every request.
1658 */
1659 if (req->oldptr == USER_ADDR_NULL) {
1660 n = unp_count;
1661 req->oldidx = 2 * sizeof (xug) + (n + n / 8) *
1662 (sizeof (struct xunpcb64));
1663 lck_rw_done(unp_list_mtx);
1664 return (0);
1665 }
1666
1667 if (req->newptr != USER_ADDR_NULL) {
1668 lck_rw_done(unp_list_mtx);
1669 return (EPERM);
1670 }
1671
1672 /*
1673 * OK, now we're committed to doing something.
1674 */
1675 gencnt = unp_gencnt;
1676 n = unp_count;
1677
1678 bzero(&xug, sizeof (xug));
1679 xug.xug_len = sizeof (xug);
1680 xug.xug_count = n;
1681 xug.xug_gen = gencnt;
1682 xug.xug_sogen = so_gencnt;
1683 error = SYSCTL_OUT(req, &xug, sizeof (xug));
1684 if (error) {
1685 lck_rw_done(unp_list_mtx);
1686 return (error);
1687 }
1688
1689 /*
1690 * We are done if there is no pcb
1691 */
1692 if (n == 0) {
1693 lck_rw_done(unp_list_mtx);
1694 return (0);
1695 }
1696
1697 MALLOC(unp_list, struct unpcb **, n * sizeof (*unp_list),
1698 M_TEMP, M_WAITOK);
1699 if (unp_list == 0) {
1700 lck_rw_done(unp_list_mtx);
1701 return (ENOMEM);
1702 }
1703
1704 for (unp = head->lh_first, i = 0; unp && i < n;
1705 unp = unp->unp_link.le_next) {
1706 if (unp->unp_gencnt <= gencnt)
1707 unp_list[i++] = unp;
1708 }
1709 n = i; /* in case we lost some during malloc */
1710
1711 error = 0;
1712 for (i = 0; i < n; i++) {
1713 unp = unp_list[i];
1714 if (unp->unp_gencnt <= gencnt) {
1715 struct xunpcb64 xu;
1716 size_t xu_len = sizeof(struct xunpcb64);
1717
1718 bzero(&xu, xu_len);
1719 xu.xu_len = xu_len;
316670eb
A
1720 xu.xu_unpp = (u_int64_t)VM_KERNEL_ADDRPERM(unp);
1721 xu.xunp_link.le_next = (u_int64_t)
1722 VM_KERNEL_ADDRPERM(unp->unp_link.le_next);
1723 xu.xunp_link.le_prev = (u_int64_t)
1724 VM_KERNEL_ADDRPERM(unp->unp_link.le_prev);
1725 xu.xunp_socket = (u_int64_t)
1726 VM_KERNEL_ADDRPERM(unp->unp_socket);
1727 xu.xunp_vnode = (u_int64_t)
1728 VM_KERNEL_ADDRPERM(unp->unp_vnode);
b0d623f7 1729 xu.xunp_ino = unp->unp_ino;
316670eb
A
1730 xu.xunp_conn = (u_int64_t)
1731 VM_KERNEL_ADDRPERM(unp->unp_conn);
1732 xu.xunp_refs = (u_int64_t)
1733 VM_KERNEL_ADDRPERM(unp->unp_refs.lh_first);
1734 xu.xunp_reflink.le_next = (u_int64_t)
1735 VM_KERNEL_ADDRPERM(unp->unp_reflink.le_next);
1736 xu.xunp_reflink.le_prev = (u_int64_t)
1737 VM_KERNEL_ADDRPERM(unp->unp_reflink.le_prev);
b0d623f7
A
1738 xu.xunp_cc = unp->unp_cc;
1739 xu.xunp_mbcnt = unp->unp_mbcnt;
1740 xu.xunp_gencnt = unp->unp_gencnt;
1741
1742 if (unp->unp_socket)
1743 sotoxsocket64(unp->unp_socket, &xu.xu_socket);
1744
1745 /*
1746 * XXX - need more locking here to protect against
1747 * connect/disconnect races for SMP.
1748 */
1749 if (unp->unp_addr)
1750 bcopy(unp->unp_addr, &xu.xunp_addr,
1751 unp->unp_addr->sun_len);
1752 if (unp->unp_conn && unp->unp_conn->unp_addr)
1753 bcopy(unp->unp_conn->unp_addr,
1754 &xu.xunp_caddr,
1755 unp->unp_conn->unp_addr->sun_len);
1756
1757 error = SYSCTL_OUT(req, &xu, xu_len);
1758 }
1759 }
1760 if (!error) {
1761 /*
1762 * Give the user an updated idea of our state.
1763 * If the generation differs from what we told
1764 * her before, she knows that something happened
1765 * while we were processing this request, and it
1766 * might be necessary to retry.
1767 */
1768 bzero(&xug, sizeof (xug));
1769 xug.xug_len = sizeof (xug);
1770 xug.xug_gen = unp_gencnt;
1771 xug.xug_sogen = so_gencnt;
1772 xug.xug_count = unp_count;
1773 error = SYSCTL_OUT(req, &xug, sizeof (xug));
1774 }
1775 FREE(unp_list, M_TEMP);
1776 lck_rw_done(unp_list_mtx);
1777 return (error);
1778}
1779
6d2010ae 1780SYSCTL_PROC(_net_local_dgram, OID_AUTO, pcblist64, CTLFLAG_RD | CTLFLAG_LOCKED,
b0d623f7
A
1781 (caddr_t)(long)SOCK_DGRAM, 0, unp_pcblist64, "S,xunpcb64",
1782 "List of active local datagram sockets 64 bit");
6d2010ae 1783SYSCTL_PROC(_net_local_stream, OID_AUTO, pcblist64, CTLFLAG_RD | CTLFLAG_LOCKED,
b0d623f7
A
1784 (caddr_t)(long)SOCK_STREAM, 0, unp_pcblist64, "S,xunpcb64",
1785 "List of active local stream sockets 64 bit");
1786
1787#endif /* !CONFIG_EMBEDDED */
1c79356b
A
1788
1789static void
91447636 1790unp_shutdown(struct unpcb *unp)
1c79356b 1791{
b0d623f7
A
1792 struct socket *so = unp->unp_socket;
1793 struct socket *so2;
1794 if (unp->unp_socket->so_type == SOCK_STREAM && unp->unp_conn) {
1795 so2 = unp->unp_conn->unp_socket;
1796 unp_get_locks_in_order(so, so2);
1797 socantrcvmore(so2);
1798 socket_unlock(so2, 1);
1799 }
1c79356b
A
1800}
1801
1802static void
2d21ac55 1803unp_drop(struct unpcb *unp, int errno)
1c79356b
A
1804{
1805 struct socket *so = unp->unp_socket;
1806
1807 so->so_error = errno;
1808 unp_disconnect(unp);
1c79356b
A
1809}
1810
2d21ac55
A
1811/*
1812 * Returns: 0 Success
1813 * EMSGSIZE The new fd's will not fit
1814 * ENOBUFS Cannot alloc struct fileproc
1815 */
1c79356b 1816int
91447636 1817unp_externalize(struct mbuf *rights)
1c79356b 1818{
2d21ac55 1819 proc_t p = current_proc(); /* XXX */
91447636
A
1820 int i;
1821 struct cmsghdr *cm = mtod(rights, struct cmsghdr *);
1822 struct fileglob **rp = (struct fileglob **)(cm + 1);
b0d623f7 1823 int *fds = (int *)(cm + 1);
91447636
A
1824 struct fileproc *fp;
1825 struct fileglob *fg;
2d21ac55 1826 int newfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int);
1c79356b
A
1827 int f;
1828
91447636 1829 proc_fdlock(p);
1c79356b
A
1830
1831 /*
1832 * if the new FD's will not fit, then we free them all
1833 */
1834 if (!fdavail(p, newfds)) {
1835 for (i = 0; i < newfds; i++) {
91447636
A
1836 fg = *rp;
1837 unp_discard_fdlocked(fg, p);
2d21ac55 1838 *rp++ = NULL;
1c79356b 1839 }
91447636 1840 proc_fdunlock(p);
1c79356b 1841
1c79356b
A
1842 return (EMSGSIZE);
1843 }
1844 /*
2d21ac55 1845 * now change each pointer to an fd in the global table to
1c79356b
A
1846 * an integer that is the index to the local fd table entry
1847 * that we set up to point to the global one we are transferring.
b0d623f7
A
1848 * XXX (1) this assumes a pointer and int are the same size,
1849 * XXX or the mbuf can hold the expansion
2d21ac55 1850 * XXX (2) allocation failures should be non-fatal
1c79356b
A
1851 */
1852 for (i = 0; i < newfds; i++) {
2d21ac55
A
1853#if CONFIG_MACF_SOCKET
1854 /*
1855 * If receive access is denied, don't pass along
1856 * and error message, just discard the descriptor.
1857 */
1858 if (mac_file_check_receive(kauth_cred_get(), *rp)) {
1859 fg = *rp;
1860 *rp++ = 0;
1861 unp_discard_fdlocked(fg, p);
1862 continue;
1863 }
1864#endif
1c79356b 1865 if (fdalloc(p, 0, &f))
2d21ac55 1866 panic("unp_externalize:fdalloc");
b0d623f7 1867 fg = rp[i];
2d21ac55
A
1868 MALLOC_ZONE(fp, struct fileproc *, sizeof (struct fileproc),
1869 M_FILEPROC, M_WAITOK);
1870 if (fp == NULL)
1871 panic("unp_externalize: MALLOC_ZONE");
1872 bzero(fp, sizeof (struct fileproc));
91447636
A
1873 fp->f_iocount = 0;
1874 fp->f_fglob = fg;
91447636 1875 fg_removeuipc(fg);
6601e61a 1876 procfdtbl_releasefd(p, f, fp);
b0d623f7
A
1877 (void) OSAddAtomic(-1, &unp_rights);
1878 fds[i] = f;
1c79356b 1879 }
91447636 1880 proc_fdunlock(p);
1c79356b 1881
1c79356b
A
1882 return (0);
1883}
1884
1885void
1886unp_init(void)
1887{
2d21ac55
A
1888 unp_zone = zinit(sizeof (struct unpcb),
1889 (nmbclusters * sizeof (struct unpcb)), 4096, "unpzone");
1890
1c79356b
A
1891 if (unp_zone == 0)
1892 panic("unp_init");
1893 LIST_INIT(&unp_dhead);
1894 LIST_INIT(&unp_shead);
2d21ac55 1895
37839358
A
1896 /*
1897 * allocate lock group attribute and group for udp pcb mutexes
1898 */
1899 unp_mtx_grp_attr = lck_grp_attr_alloc_init();
1900
1901 unp_mtx_grp = lck_grp_alloc_init("unp_list", unp_mtx_grp_attr);
2d21ac55 1902
37839358
A
1903 unp_mtx_attr = lck_attr_alloc_init();
1904
2d21ac55
A
1905 if ((unp_list_mtx = lck_rw_alloc_init(unp_mtx_grp,
1906 unp_mtx_attr)) == NULL)
37839358
A
1907 return; /* pretty much dead if this fails... */
1908
b0d623f7
A
1909 if ((unp_disconnect_lock = lck_mtx_alloc_init(unp_mtx_grp,
1910 unp_mtx_attr)) == NULL)
1911 return;
1912
1913 if ((unp_connect_lock = lck_mtx_alloc_init(unp_mtx_grp,
1914 unp_mtx_attr)) == NULL)
1915 return;
1c79356b
A
1916}
1917
1918#ifndef MIN
2d21ac55 1919#define MIN(a, b) (((a) < (b)) ? (a) : (b))
1c79356b
A
1920#endif
1921
2d21ac55
A
1922/*
1923 * Returns: 0 Success
1924 * EINVAL
1925 * fdgetf_noref:EBADF
1926 */
1c79356b 1927static int
2d21ac55 1928unp_internalize(struct mbuf *control, proc_t p)
1c79356b 1929{
91447636 1930 struct cmsghdr *cm = mtod(control, struct cmsghdr *);
b0d623f7 1931 int *fds;
91447636
A
1932 struct fileglob **rp;
1933 struct fileproc *fp;
2d21ac55 1934 int i, error;
1c79356b
A
1935 int oldfds;
1936
2d21ac55 1937 /* 64bit: cmsg_len is 'uint32_t', m_len is 'long' */
1c79356b 1938 if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||
b0d623f7 1939 (socklen_t)cm->cmsg_len != (socklen_t)control->m_len) {
2d21ac55 1940 return (EINVAL);
1c79356b 1941 }
1c79356b 1942 oldfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int);
1c79356b 1943
91447636 1944 proc_fdlock(p);
b0d623f7 1945 fds = (int *)(cm + 1);
91447636
A
1946
1947 for (i = 0; i < oldfds; i++) {
b0d623f7
A
1948 struct fileproc *tmpfp;
1949 if (((error = fdgetf_noref(p, fds[i], &tmpfp)) != 0)) {
2d21ac55
A
1950 proc_fdunlock(p);
1951 return (error);
b0d623f7
A
1952 } else if (!filetype_issendable(tmpfp->f_fglob->fg_type)) {
1953 proc_fdunlock(p);
1954 return (EINVAL);
2d21ac55 1955 }
91447636
A
1956 }
1957 rp = (struct fileglob **)(cm + 1);
1c79356b 1958
b0d623f7
A
1959 /* On K64 we need to walk backwards because a fileglob * is twice the size of an fd
1960 * and doing them in-order would result in stomping over unprocessed fd's
1961 */
1962 for (i = (oldfds - 1); i >= 0; i--) {
1963 (void) fdgetf_noref(p, fds[i], &fp);
91447636 1964 fg_insertuipc(fp->f_fglob);
b0d623f7
A
1965 rp[i] = fp->f_fglob;
1966 (void) OSAddAtomic(1, &unp_rights);
1c79356b 1967 }
91447636 1968 proc_fdunlock(p);
1c79356b 1969
1c79356b
A
1970 return (0);
1971}
1972
6601e61a 1973static int unp_defer, unp_gcing, unp_gcwait;
e2fac8b1 1974static thread_t unp_gcthread = NULL;
2d21ac55 1975
6601e61a
A
1976/* always called under uipc_lock */
1977void
1978unp_gc_wait(void)
1979{
e2fac8b1
A
1980 if (unp_gcthread == current_thread())
1981 return;
1982
6601e61a
A
1983 while (unp_gcing != 0) {
1984 unp_gcwait = 1;
1985 msleep(&unp_gcing, uipc_lock, 0 , "unp_gc_wait", NULL);
1986 }
1987}
1c79356b 1988
2d21ac55 1989
e2fac8b1 1990__private_extern__ void
2d21ac55 1991unp_gc(void)
1c79356b 1992{
2d21ac55
A
1993 struct fileglob *fg, *nextfg;
1994 struct socket *so;
e2fac8b1 1995 static struct fileglob **extra_ref;
b0d623f7 1996 struct fileglob **fpp;
1c79356b 1997 int nunref, i;
6601e61a 1998 int need_gcwakeup = 0;
2d21ac55 1999
91447636
A
2000 lck_mtx_lock(uipc_lock);
2001 if (unp_gcing) {
2002 lck_mtx_unlock(uipc_lock);
1c79356b 2003 return;
91447636 2004 }
1c79356b
A
2005 unp_gcing = 1;
2006 unp_defer = 0;
e2fac8b1 2007 unp_gcthread = current_thread();
91447636 2008 lck_mtx_unlock(uipc_lock);
2d21ac55
A
2009 /*
2010 * before going through all this, set all FDs to
1c79356b
A
2011 * be NOT defered and NOT externally accessible
2012 */
91447636
A
2013 for (fg = fmsghead.lh_first; fg != 0; fg = fg->f_msglist.le_next) {
2014 lck_mtx_lock(&fg->fg_lock);
2015 fg->fg_flag &= ~(FMARK|FDEFER);
2016 lck_mtx_unlock(&fg->fg_lock);
2017 }
1c79356b 2018 do {
2d21ac55
A
2019 for (fg = fmsghead.lh_first; fg != 0;
2020 fg = fg->f_msglist.le_next) {
91447636 2021 lck_mtx_lock(&fg->fg_lock);
1c79356b
A
2022 /*
2023 * If the file is not open, skip it
2024 */
91447636
A
2025 if (fg->fg_count == 0) {
2026 lck_mtx_unlock(&fg->fg_lock);
1c79356b 2027 continue;
91447636 2028 }
1c79356b
A
2029 /*
2030 * If we already marked it as 'defer' in a
2031 * previous pass, then try process it this time
2032 * and un-mark it
2033 */
91447636
A
2034 if (fg->fg_flag & FDEFER) {
2035 fg->fg_flag &= ~FDEFER;
1c79356b
A
2036 unp_defer--;
2037 } else {
2038 /*
2039 * if it's not defered, then check if it's
2040 * already marked.. if so skip it
2041 */
2d21ac55 2042 if (fg->fg_flag & FMARK) {
91447636 2043 lck_mtx_unlock(&fg->fg_lock);
1c79356b 2044 continue;
91447636 2045 }
2d21ac55 2046 /*
1c79356b 2047 * If all references are from messages
2d21ac55 2048 * in transit, then skip it. it's not
1c79356b 2049 * externally accessible.
2d21ac55 2050 */
91447636
A
2051 if (fg->fg_count == fg->fg_msgcount) {
2052 lck_mtx_unlock(&fg->fg_lock);
1c79356b 2053 continue;
91447636 2054 }
2d21ac55 2055 /*
1c79356b
A
2056 * If it got this far then it must be
2057 * externally accessible.
2058 */
91447636 2059 fg->fg_flag |= FMARK;
1c79356b
A
2060 }
2061 /*
2d21ac55 2062 * either it was defered, or it is externally
1c79356b
A
2063 * accessible and not already marked so.
2064 * Now check if it is possibly one of OUR sockets.
2d21ac55 2065 */
91447636
A
2066 if (fg->fg_type != DTYPE_SOCKET ||
2067 (so = (struct socket *)fg->fg_data) == 0) {
2068 lck_mtx_unlock(&fg->fg_lock);
1c79356b 2069 continue;
91447636 2070 }
1c79356b 2071 if (so->so_proto->pr_domain != &localdomain ||
91447636
A
2072 (so->so_proto->pr_flags&PR_RIGHTS) == 0) {
2073 lck_mtx_unlock(&fg->fg_lock);
1c79356b 2074 continue;
91447636 2075 }
1c79356b 2076#ifdef notdef
2d21ac55
A
2077 /*
2078 * if this code is enabled need to run
2079 * under network funnel
2080 */
1c79356b
A
2081 if (so->so_rcv.sb_flags & SB_LOCK) {
2082 /*
2083 * This is problematical; it's not clear
2084 * we need to wait for the sockbuf to be
2085 * unlocked (on a uniprocessor, at least),
2086 * and it's also not clear what to do
2087 * if sbwait returns an error due to receipt
2088 * of a signal. If sbwait does return
2089 * an error, we'll go into an infinite
2090 * loop. Delete all of this for now.
2091 */
2092 (void) sbwait(&so->so_rcv);
2093 goto restart;
2094 }
2095#endif
2096 /*
2097 * So, Ok, it's one of our sockets and it IS externally
2098 * accessible (or was defered). Now we look
2099 * to see if we hold any file descriptors in its
2d21ac55 2100 * message buffers. Follow those links and mark them
1c79356b 2101 * as accessible too.
e2fac8b1 2102 *
b0d623f7 2103 * In case a file is passed onto itself we need to
e2fac8b1 2104 * release the file lock.
1c79356b 2105 */
91447636 2106 lck_mtx_unlock(&fg->fg_lock);
e2fac8b1
A
2107
2108 unp_scan(so->so_rcv.sb_mb, unp_mark);
1c79356b
A
2109 }
2110 } while (unp_defer);
2111 /*
2112 * We grab an extra reference to each of the file table entries
2113 * that are not otherwise accessible and then free the rights
2114 * that are stored in messages on them.
2115 *
2116 * The bug in the orginal code is a little tricky, so I'll describe
2117 * what's wrong with it here.
2118 *
2119 * It is incorrect to simply unp_discard each entry for f_msgcount
2120 * times -- consider the case of sockets A and B that contain
2121 * references to each other. On a last close of some other socket,
2122 * we trigger a gc since the number of outstanding rights (unp_rights)
2123 * is non-zero. If during the sweep phase the gc code un_discards,
2124 * we end up doing a (full) closef on the descriptor. A closef on A
2125 * results in the following chain. Closef calls soo_close, which
2126 * calls soclose. Soclose calls first (through the switch
2127 * uipc_usrreq) unp_detach, which re-invokes unp_gc. Unp_gc simply
2128 * returns because the previous instance had set unp_gcing, and
2129 * we return all the way back to soclose, which marks the socket
2130 * with SS_NOFDREF, and then calls sofree. Sofree calls sorflush
2131 * to free up the rights that are queued in messages on the socket A,
2132 * i.e., the reference on B. The sorflush calls via the dom_dispose
2133 * switch unp_dispose, which unp_scans with unp_discard. This second
2134 * instance of unp_discard just calls closef on B.
2135 *
2136 * Well, a similar chain occurs on B, resulting in a sorflush on B,
2137 * which results in another closef on A. Unfortunately, A is already
2138 * being closed, and the descriptor has already been marked with
2139 * SS_NOFDREF, and soclose panics at this point.
2140 *
2141 * Here, we first take an extra reference to each inaccessible
2142 * descriptor. Then, we call sorflush ourself, since we know
2143 * it is a Unix domain socket anyhow. After we destroy all the
2144 * rights carried in messages, we do a last closef to get rid
2145 * of our extra reference. This is the last close, and the
2146 * unp_detach etc will shut down the socket.
2147 *
2148 * 91/09/19, bsy@cs.cmu.edu
2149 */
2d21ac55
A
2150 extra_ref = _MALLOC(nfiles * sizeof (struct fileglob *),
2151 M_FILEGLOB, M_WAITOK);
b0d623f7
A
2152 if (extra_ref == NULL)
2153 goto bail;
91447636
A
2154 for (nunref = 0, fg = fmsghead.lh_first, fpp = extra_ref; fg != 0;
2155 fg = nextfg) {
2156 lck_mtx_lock(&fg->fg_lock);
2157
2158 nextfg = fg->f_msglist.le_next;
2d21ac55 2159 /*
1c79356b
A
2160 * If it's not open, skip it
2161 */
91447636
A
2162 if (fg->fg_count == 0) {
2163 lck_mtx_unlock(&fg->fg_lock);
1c79356b 2164 continue;
91447636 2165 }
2d21ac55 2166 /*
1c79356b
A
2167 * If all refs are from msgs, and it's not marked accessible
2168 * then it must be referenced from some unreachable cycle
2169 * of (shut-down) FDs, so include it in our
2170 * list of FDs to remove
2171 */
91447636
A
2172 if (fg->fg_count == fg->fg_msgcount && !(fg->fg_flag & FMARK)) {
2173 fg->fg_count++;
2174 *fpp++ = fg;
1c79356b 2175 nunref++;
1c79356b 2176 }
91447636 2177 lck_mtx_unlock(&fg->fg_lock);
1c79356b 2178 }
2d21ac55 2179 /*
1c79356b
A
2180 * for each FD on our hit list, do the following two things
2181 */
2182 for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp) {
91447636 2183 struct fileglob *tfg;
1c79356b 2184
91447636 2185 tfg = *fpp;
1c79356b 2186
91447636 2187 if (tfg->fg_type == DTYPE_SOCKET && tfg->fg_data != NULL) {
2d21ac55
A
2188 so = (struct socket *)(tfg->fg_data);
2189
e2fac8b1 2190 socket_lock(so, 0);
b0d623f7 2191
2d21ac55
A
2192 sorflush(so);
2193
e2fac8b1 2194 socket_unlock(so, 0);
91447636
A
2195 }
2196 }
1c79356b 2197 for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp)
2d21ac55
A
2198 closef_locked((struct fileproc *)0, *fpp, (proc_t)NULL);
2199
b0d623f7
A
2200 FREE((caddr_t)extra_ref, M_FILEGLOB);
2201bail:
2d21ac55 2202 lck_mtx_lock(uipc_lock);
1c79356b 2203 unp_gcing = 0;
e2fac8b1 2204 unp_gcthread = NULL;
6601e61a
A
2205
2206 if (unp_gcwait != 0) {
2207 unp_gcwait = 0;
2208 need_gcwakeup = 1;
2209 }
2210 lck_mtx_unlock(uipc_lock);
2211
2212 if (need_gcwakeup != 0)
2213 wakeup(&unp_gcing);
1c79356b
A
2214}
2215
2216void
91447636 2217unp_dispose(struct mbuf *m)
1c79356b 2218{
1c79356b 2219 if (m) {
1c79356b 2220 unp_scan(m, unp_discard);
1c79356b
A
2221 }
2222}
2223
2d21ac55
A
2224/*
2225 * Returns: 0 Success
2226 */
91447636 2227static int
2d21ac55 2228unp_listen(struct unpcb *unp, proc_t p)
91447636 2229{
0c530ab8
A
2230 kauth_cred_t safecred = kauth_cred_proc_ref(p);
2231 cru2x(safecred, &unp->unp_peercred);
2232 kauth_cred_unref(&safecred);
91447636
A
2233 unp->unp_flags |= UNP_HAVEPCCACHED;
2234 return (0);
2235}
2236
2d21ac55 2237/* should run under kernel funnel */
1c79356b 2238static void
2d21ac55 2239unp_scan(struct mbuf *m0, void (*op)(struct fileglob *))
1c79356b 2240{
91447636
A
2241 struct mbuf *m;
2242 struct fileglob **rp;
2243 struct cmsghdr *cm;
2244 int i;
1c79356b
A
2245 int qfds;
2246
2247 while (m0) {
2248 for (m = m0; m; m = m->m_next)
2249 if (m->m_type == MT_CONTROL &&
2d21ac55 2250 (size_t)m->m_len >= sizeof (*cm)) {
1c79356b
A
2251 cm = mtod(m, struct cmsghdr *);
2252 if (cm->cmsg_level != SOL_SOCKET ||
2253 cm->cmsg_type != SCM_RIGHTS)
2254 continue;
2d21ac55 2255 qfds = (cm->cmsg_len - sizeof (*cm)) /
b0d623f7 2256 sizeof (int);
91447636 2257 rp = (struct fileglob **)(cm + 1);
1c79356b
A
2258 for (i = 0; i < qfds; i++)
2259 (*op)(*rp++);
2260 break; /* XXX, but saves time */
2261 }
2262 m0 = m0->m_act;
2263 }
2264}
2265
2266/* should run under kernel funnel */
2267static void
91447636 2268unp_mark(struct fileglob *fg)
1c79356b 2269{
2d21ac55 2270 lck_mtx_lock(&fg->fg_lock);
1c79356b 2271
91447636 2272 if (fg->fg_flag & FMARK) {
2d21ac55 2273 lck_mtx_unlock(&fg->fg_lock);
1c79356b 2274 return;
91447636
A
2275 }
2276 fg->fg_flag |= (FMARK|FDEFER);
2277
2d21ac55 2278 lck_mtx_unlock(&fg->fg_lock);
91447636 2279
1c79356b 2280 unp_defer++;
1c79356b
A
2281}
2282
2283/* should run under kernel funnel */
2284static void
2d21ac55 2285unp_discard(struct fileglob *fg)
1c79356b 2286{
2d21ac55
A
2287 proc_t p = current_proc(); /* XXX */
2288
b0d623f7 2289 (void) OSAddAtomic(1, &unp_disposed);
91447636
A
2290
2291 proc_fdlock(p);
2292 unp_discard_fdlocked(fg, p);
2293 proc_fdunlock(p);
2294}
2295static void
2d21ac55 2296unp_discard_fdlocked(struct fileglob *fg, proc_t p)
91447636 2297{
91447636 2298 fg_removeuipc(fg);
1c79356b 2299
b0d623f7 2300 (void) OSAddAtomic(-1, &unp_rights);
91447636 2301 (void) closef_locked((struct fileproc *)0, fg, p);
1c79356b 2302}
b0d623f7
A
2303
2304int
2305unp_lock(struct socket *so, int refcount, void * lr)
2306 {
2307 void * lr_saved;
2308 if (lr == 0)
2309 lr_saved = (void *) __builtin_return_address(0);
2310 else lr_saved = lr;
2311
2312 if (so->so_pcb) {
6d2010ae 2313 lck_mtx_lock(&((struct unpcb *)so->so_pcb)->unp_mtx);
b0d623f7
A
2314 } else {
2315 panic("unp_lock: so=%p NO PCB! lr=%p ref=0x%x\n",
2316 so, lr_saved, so->so_usecount);
2317 }
2318
2319 if (so->so_usecount < 0)
2320 panic("unp_lock: so=%p so_pcb=%p lr=%p ref=0x%x\n",
2321 so, so->so_pcb, lr_saved, so->so_usecount);
2322
2323 if (refcount)
2324 so->so_usecount++;
2325
2326 so->lock_lr[so->next_lock_lr] = lr_saved;
2327 so->next_lock_lr = (so->next_lock_lr+1) % SO_LCKDBG_MAX;
2328 return (0);
2329}
2330
2331int
2332unp_unlock(struct socket *so, int refcount, void * lr)
2333{
2334 void * lr_saved;
2335 lck_mtx_t * mutex_held = NULL;
2336 struct unpcb *unp = sotounpcb(so);
2337
2338 if (lr == 0)
2339 lr_saved = (void *) __builtin_return_address(0);
2340 else lr_saved = lr;
2341
2342 if (refcount)
2343 so->so_usecount--;
2344
2345 if (so->so_usecount < 0)
2346 panic("unp_unlock: so=%p usecount=%x\n", so, so->so_usecount);
2347 if (so->so_pcb == NULL) {
2348 panic("unp_unlock: so=%p NO PCB usecount=%x\n", so, so->so_usecount);
2349 } else {
6d2010ae 2350 mutex_held = &((struct unpcb *)so->so_pcb)->unp_mtx;
b0d623f7
A
2351 }
2352 lck_mtx_assert(mutex_held, LCK_MTX_ASSERT_OWNED);
2353 so->unlock_lr[so->next_unlock_lr] = lr_saved;
2354 so->next_unlock_lr = (so->next_unlock_lr+1) % SO_LCKDBG_MAX;
2355
2356 if (so->so_usecount == 0 && (so->so_flags & SOF_PCBCLEARING)) {
2357 sofreelastref(so, 1);
2358
2359 if (unp->unp_addr)
2360 FREE(unp->unp_addr, M_SONAME);
2361
2362 lck_mtx_unlock(mutex_held);
b0d623f7 2363
316670eb 2364 lck_mtx_destroy(&unp->unp_mtx, unp_mtx_grp);
b0d623f7 2365 zfree(unp_zone, unp);
b0d623f7
A
2366
2367 unp_gc();
2368 } else {
2369 lck_mtx_unlock(mutex_held);
2370 }
2371
2372 return (0);
2373}
2374
2375lck_mtx_t *
2376unp_getlock(struct socket *so, __unused int locktype)
2377{
2378 struct unpcb *unp = (struct unpcb *)so->so_pcb;
2379
2380
2381 if (so->so_pcb) {
2382 if (so->so_usecount < 0)
2383 panic("unp_getlock: so=%p usecount=%x\n", so, so->so_usecount);
6d2010ae 2384 return(&unp->unp_mtx);
b0d623f7
A
2385 } else {
2386 panic("unp_getlock: so=%p NULL so_pcb\n", so);
2387 return (so->so_proto->pr_domain->dom_mtx);
2388 }
2389}
2390