19454b2d8SWarner Losh /*- 2df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1989, 1991, 1993 3e1ac28e2SRobert Watson * The Regents of the University of California. 43dab55bcSRobert Watson * Copyright (c) 2004-2009 Robert N. M. Watson 5e1ac28e2SRobert Watson * All rights reserved. 6df8bae1dSRodney W. Grimes * 7df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 8df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 9df8bae1dSRodney W. Grimes * are met: 10df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 12df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 13df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 14df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 15df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 16df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 17df8bae1dSRodney W. Grimes * without specific prior written permission. 18df8bae1dSRodney W. Grimes * 19df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29df8bae1dSRodney W. Grimes * SUCH DAMAGE. 30df8bae1dSRodney W. Grimes * 31748e0b0aSGarrett Wollman * From: @(#)uipc_usrreq.c 8.3 (Berkeley) 1/4/94 32df8bae1dSRodney W. Grimes */ 33df8bae1dSRodney W. Grimes 34f23929fbSRobert Watson /* 35f23929fbSRobert Watson * UNIX Domain (Local) Sockets 36f23929fbSRobert Watson * 37f23929fbSRobert Watson * This is an implementation of UNIX (local) domain sockets. Each socket has 38f23929fbSRobert Watson * an associated struct unpcb (UNIX protocol control block). Stream sockets 39f23929fbSRobert Watson * may be connected to 0 or 1 other socket. Datagram sockets may be 40f23929fbSRobert Watson * connected to 0, 1, or many other sockets. Sockets may be created and 41f23929fbSRobert Watson * connected in pairs (socketpair(2)), or bound/connected to using the file 42f23929fbSRobert Watson * system name space. For most purposes, only the receive socket buffer is 43f23929fbSRobert Watson * used, as sending on one socket delivers directly to the receive socket 445b950deaSRobert Watson * buffer of a second socket. 455b950deaSRobert Watson * 465b950deaSRobert Watson * The implementation is substantially complicated by the fact that 475b950deaSRobert Watson * "ancillary data", such as file descriptors or credentials, may be passed 485b950deaSRobert Watson * across UNIX domain sockets. The potential for passing UNIX domain sockets 495b950deaSRobert Watson * over other UNIX domain sockets requires the implementation of a simple 505b950deaSRobert Watson * garbage collector to find and tear down cycles of disconnected sockets. 51aea52f1bSRobert Watson * 52aea52f1bSRobert Watson * TODO: 53aea52f1bSRobert Watson * SEQPACKET, RDM 54aea52f1bSRobert Watson * rethink name space problems 55aea52f1bSRobert Watson * need a proper out-of-band 56f23929fbSRobert Watson */ 57f23929fbSRobert Watson 58677b542eSDavid E. O'Brien #include <sys/cdefs.h> 59677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 60677b542eSDavid E. O'Brien 6103c96c31SRobert Watson #include "opt_ddb.h" 62335654d7SRobert Watson #include "opt_mac.h" 63335654d7SRobert Watson 64df8bae1dSRodney W. Grimes #include <sys/param.h> 65fb919e4dSMark Murray #include <sys/domain.h> 66960ed29cSSeigo Tanimura #include <sys/fcntl.h> 67d826c479SBruce Evans #include <sys/malloc.h> /* XXX must be before <sys/file.h> */ 684f590175SPaul Saab #include <sys/eventhandler.h> 69639acc13SGarrett Wollman #include <sys/file.h> 70960ed29cSSeigo Tanimura #include <sys/filedesc.h> 71960ed29cSSeigo Tanimura #include <sys/jail.h> 72960ed29cSSeigo Tanimura #include <sys/kernel.h> 73960ed29cSSeigo Tanimura #include <sys/lock.h> 74639acc13SGarrett Wollman #include <sys/mbuf.h> 75033eb86eSJeff Roberson #include <sys/mount.h> 76960ed29cSSeigo Tanimura #include <sys/mutex.h> 77639acc13SGarrett Wollman #include <sys/namei.h> 78639acc13SGarrett Wollman #include <sys/proc.h> 79df8bae1dSRodney W. Grimes #include <sys/protosw.h> 80960ed29cSSeigo Tanimura #include <sys/resourcevar.h> 81e7c33e29SRobert Watson #include <sys/rwlock.h> 82df8bae1dSRodney W. Grimes #include <sys/socket.h> 83df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 84960ed29cSSeigo Tanimura #include <sys/signalvar.h> 85df8bae1dSRodney W. Grimes #include <sys/stat.h> 86960ed29cSSeigo Tanimura #include <sys/sx.h> 87639acc13SGarrett Wollman #include <sys/sysctl.h> 88960ed29cSSeigo Tanimura #include <sys/systm.h> 89a0ec558aSRobert Watson #include <sys/taskqueue.h> 90639acc13SGarrett Wollman #include <sys/un.h> 9198271db4SGarrett Wollman #include <sys/unpcb.h> 92639acc13SGarrett Wollman #include <sys/vnode.h> 93df8bae1dSRodney W. Grimes 9403c96c31SRobert Watson #ifdef DDB 9503c96c31SRobert Watson #include <ddb/ddb.h> 9603c96c31SRobert Watson #endif 9703c96c31SRobert Watson 98aed55708SRobert Watson #include <security/mac/mac_framework.h> 99aed55708SRobert Watson 1009e9d298aSJeff Roberson #include <vm/uma.h> 10198271db4SGarrett Wollman 1023dab55bcSRobert Watson /* 1033dab55bcSRobert Watson * Locking key: 1043dab55bcSRobert Watson * (l) Locked using list lock 1053dab55bcSRobert Watson * (g) Locked using linkage lock 1063dab55bcSRobert Watson */ 1073dab55bcSRobert Watson 1089e9d298aSJeff Roberson static uma_zone_t unp_zone; 1093dab55bcSRobert Watson static unp_gen_t unp_gencnt; /* (l) */ 1103dab55bcSRobert Watson static u_int unp_count; /* (l) Count of local sockets. */ 111aea52f1bSRobert Watson static ino_t unp_ino; /* Prototype for fake inode numbers. */ 1123dab55bcSRobert Watson static int unp_rights; /* (g) File descriptors in flight. */ 1133dab55bcSRobert Watson static struct unp_head unp_shead; /* (l) List of stream sockets. */ 1143dab55bcSRobert Watson static struct unp_head unp_dhead; /* (l) List of datagram sockets. */ 11598271db4SGarrett Wollman 116aea52f1bSRobert Watson static const struct sockaddr sun_noname = { sizeof(sun_noname), AF_LOCAL }; 11798271db4SGarrett Wollman 118df8bae1dSRodney W. Grimes /* 119aea52f1bSRobert Watson * Garbage collection of cyclic file descriptor/socket references occurs 120aea52f1bSRobert Watson * asynchronously in a taskqueue context in order to avoid recursion and 121aea52f1bSRobert Watson * reentrance in the UNIX domain socket, file descriptor, and socket layer 122aea52f1bSRobert Watson * code. See unp_gc() for a full description. 123df8bae1dSRodney W. Grimes */ 124aea52f1bSRobert Watson static struct task unp_gc_task; 125f708ef1bSPoul-Henning Kamp 126ce5f32deSRobert Watson /* 1277e711c3aSRobert Watson * Both send and receive buffers are allocated PIPSIZ bytes of buffering for 1287e711c3aSRobert Watson * stream sockets, although the total for sender and receiver is actually 1297e711c3aSRobert Watson * only PIPSIZ. 1307e711c3aSRobert Watson * 1317e711c3aSRobert Watson * Datagram sockets really use the sendspace as the maximum datagram size, 1327e711c3aSRobert Watson * and don't really want to reserve the sendspace. Their recvspace should be 1337e711c3aSRobert Watson * large enough for at least one max-size datagram plus address. 1347e711c3aSRobert Watson */ 1357e711c3aSRobert Watson #ifndef PIPSIZ 1367e711c3aSRobert Watson #define PIPSIZ 8192 1377e711c3aSRobert Watson #endif 1387e711c3aSRobert Watson static u_long unpst_sendspace = PIPSIZ; 1397e711c3aSRobert Watson static u_long unpst_recvspace = PIPSIZ; 1407e711c3aSRobert Watson static u_long unpdg_sendspace = 2*1024; /* really max datagram size */ 1417e711c3aSRobert Watson static u_long unpdg_recvspace = 4*1024; 1427e711c3aSRobert Watson 143e4445a03SRobert Watson SYSCTL_NODE(_net, PF_LOCAL, local, CTLFLAG_RW, 0, "Local domain"); 144e4445a03SRobert Watson SYSCTL_NODE(_net_local, SOCK_STREAM, stream, CTLFLAG_RW, 0, "SOCK_STREAM"); 145e4445a03SRobert Watson SYSCTL_NODE(_net_local, SOCK_DGRAM, dgram, CTLFLAG_RW, 0, "SOCK_DGRAM"); 146e4445a03SRobert Watson 1477e711c3aSRobert Watson SYSCTL_ULONG(_net_local_stream, OID_AUTO, sendspace, CTLFLAG_RW, 148be6b1304STom Rhodes &unpst_sendspace, 0, "Default stream send space."); 1497e711c3aSRobert Watson SYSCTL_ULONG(_net_local_stream, OID_AUTO, recvspace, CTLFLAG_RW, 150be6b1304STom Rhodes &unpst_recvspace, 0, "Default stream receive space."); 1517e711c3aSRobert Watson SYSCTL_ULONG(_net_local_dgram, OID_AUTO, maxdgram, CTLFLAG_RW, 152be6b1304STom Rhodes &unpdg_sendspace, 0, "Default datagram send space."); 1537e711c3aSRobert Watson SYSCTL_ULONG(_net_local_dgram, OID_AUTO, recvspace, CTLFLAG_RW, 154be6b1304STom Rhodes &unpdg_recvspace, 0, "Default datagram receive space."); 155be6b1304STom Rhodes SYSCTL_INT(_net_local, OID_AUTO, inflight, CTLFLAG_RD, &unp_rights, 0, 156be6b1304STom Rhodes "File descriptors in flight."); 1577e711c3aSRobert Watson 158e7c33e29SRobert Watson /*- 159e7c33e29SRobert Watson * Locking and synchronization: 160ce5f32deSRobert Watson * 1613dab55bcSRobert Watson * Three types of locks exit in the local domain socket implementation: a 1623dab55bcSRobert Watson * global list mutex, a global linkage rwlock, and per-unpcb mutexes. Of the 1633dab55bcSRobert Watson * global locks, the list lock protects the socket count, global generation 1643dab55bcSRobert Watson * number, and stream/datagram global lists. The linkage lock protects the 1653dab55bcSRobert Watson * interconnection of unpcbs, the v_socket and unp_vnode pointers, and can be 1663dab55bcSRobert Watson * held exclusively over the acquisition of multiple unpcb locks to prevent 1673dab55bcSRobert Watson * deadlock. 168ce5f32deSRobert Watson * 169e7c33e29SRobert Watson * UNIX domain sockets each have an unpcb hung off of their so_pcb pointer, 170e7c33e29SRobert Watson * allocated in pru_attach() and freed in pru_detach(). The validity of that 171e7c33e29SRobert Watson * pointer is an invariant, so no lock is required to dereference the so_pcb 172e7c33e29SRobert Watson * pointer if a valid socket reference is held by the caller. In practice, 173e7c33e29SRobert Watson * this is always true during operations performed on a socket. Each unpcb 174e7c33e29SRobert Watson * has a back-pointer to its socket, unp_socket, which will be stable under 175e7c33e29SRobert Watson * the same circumstances. 176e7c33e29SRobert Watson * 177e7c33e29SRobert Watson * This pointer may only be safely dereferenced as long as a valid reference 178e7c33e29SRobert Watson * to the unpcb is held. Typically, this reference will be from the socket, 179e7c33e29SRobert Watson * or from another unpcb when the referring unpcb's lock is held (in order 180e7c33e29SRobert Watson * that the reference not be invalidated during use). For example, to follow 181e7c33e29SRobert Watson * unp->unp_conn->unp_socket, you need unlock the lock on unp, not unp_conn, 182e7c33e29SRobert Watson * as unp_socket remains valid as long as the reference to unp_conn is valid. 183e7c33e29SRobert Watson * 184e7c33e29SRobert Watson * Fields of unpcbss are locked using a per-unpcb lock, unp_mtx. Individual 185e7c33e29SRobert Watson * atomic reads without the lock may be performed "lockless", but more 186e7c33e29SRobert Watson * complex reads and read-modify-writes require the mutex to be held. No 187e7c33e29SRobert Watson * lock order is defined between unpcb locks -- multiple unpcb locks may be 1883dab55bcSRobert Watson * acquired at the same time only when holding the linkage rwlock 1893dab55bcSRobert Watson * exclusively, which prevents deadlocks. 190e7c33e29SRobert Watson * 191e7c33e29SRobert Watson * Blocking with UNIX domain sockets is a tricky issue: unlike most network 192e7c33e29SRobert Watson * protocols, bind() is a non-atomic operation, and connect() requires 193e7c33e29SRobert Watson * potential sleeping in the protocol, due to potentially waiting on local or 194e7c33e29SRobert Watson * distributed file systems. We try to separate "lookup" operations, which 195e7c33e29SRobert Watson * may sleep, and the IPC operations themselves, which typically can occur 196e7c33e29SRobert Watson * with relative atomicity as locks can be held over the entire operation. 197e7c33e29SRobert Watson * 198e7c33e29SRobert Watson * Another tricky issue is simultaneous multi-threaded or multi-process 199e7c33e29SRobert Watson * access to a single UNIX domain socket. These are handled by the flags 200e7c33e29SRobert Watson * UNP_CONNECTING and UNP_BINDING, which prevent concurrent connecting or 201e7c33e29SRobert Watson * binding, both of which involve dropping UNIX domain socket locks in order 202e7c33e29SRobert Watson * to perform namei() and other file system operations. 203ce5f32deSRobert Watson */ 2043dab55bcSRobert Watson static struct rwlock unp_link_rwlock; 2053dab55bcSRobert Watson static struct mtx unp_list_lock; 206e7c33e29SRobert Watson 2073dab55bcSRobert Watson #define UNP_LINK_LOCK_INIT() rw_init(&unp_link_rwlock, \ 2083dab55bcSRobert Watson "unp_link_rwlock") 209e7c33e29SRobert Watson 2103dab55bcSRobert Watson #define UNP_LINK_LOCK_ASSERT() rw_assert(&unp_link_rwlock, \ 211e7c33e29SRobert Watson RA_LOCKED) 2123dab55bcSRobert Watson #define UNP_LINK_UNLOCK_ASSERT() rw_assert(&unp_link_rwlock, \ 213e7c33e29SRobert Watson RA_UNLOCKED) 214e7c33e29SRobert Watson 2153dab55bcSRobert Watson #define UNP_LINK_RLOCK() rw_rlock(&unp_link_rwlock) 2163dab55bcSRobert Watson #define UNP_LINK_RUNLOCK() rw_runlock(&unp_link_rwlock) 2173dab55bcSRobert Watson #define UNP_LINK_WLOCK() rw_wlock(&unp_link_rwlock) 2183dab55bcSRobert Watson #define UNP_LINK_WUNLOCK() rw_wunlock(&unp_link_rwlock) 2193dab55bcSRobert Watson #define UNP_LINK_WLOCK_ASSERT() rw_assert(&unp_link_rwlock, \ 220e7c33e29SRobert Watson RA_WLOCKED) 221e7c33e29SRobert Watson 2223dab55bcSRobert Watson #define UNP_LIST_LOCK_INIT() mtx_init(&unp_list_lock, \ 2233dab55bcSRobert Watson "unp_list_lock", NULL, MTX_DEF) 2243dab55bcSRobert Watson #define UNP_LIST_LOCK() mtx_lock(&unp_list_lock) 2253dab55bcSRobert Watson #define UNP_LIST_UNLOCK() mtx_unlock(&unp_list_lock) 226e7c33e29SRobert Watson 227e7c33e29SRobert Watson #define UNP_PCB_LOCK_INIT(unp) mtx_init(&(unp)->unp_mtx, \ 228e7c33e29SRobert Watson "unp_mtx", "unp_mtx", \ 229e7c33e29SRobert Watson MTX_DUPOK|MTX_DEF|MTX_RECURSE) 230e7c33e29SRobert Watson #define UNP_PCB_LOCK_DESTROY(unp) mtx_destroy(&(unp)->unp_mtx) 231e7c33e29SRobert Watson #define UNP_PCB_LOCK(unp) mtx_lock(&(unp)->unp_mtx) 232e7c33e29SRobert Watson #define UNP_PCB_UNLOCK(unp) mtx_unlock(&(unp)->unp_mtx) 233e7c33e29SRobert Watson #define UNP_PCB_LOCK_ASSERT(unp) mtx_assert(&(unp)->unp_mtx, MA_OWNED) 2340d9ce3a1SRobert Watson 2352c899584SRobert Watson static int uipc_connect2(struct socket *, struct socket *); 2360b36cd25SRobert Watson static int uipc_ctloutput(struct socket *, struct sockopt *); 237aea52f1bSRobert Watson static int unp_connect(struct socket *, struct sockaddr *, 238aea52f1bSRobert Watson struct thread *); 2396a2989fdSMatthew N. Dodd static int unp_connect2(struct socket *so, struct socket *so2, int); 240e7c33e29SRobert Watson static void unp_disconnect(struct unpcb *unp, struct unpcb *unp2); 2410b36cd25SRobert Watson static void unp_dispose(struct mbuf *); 2424d77a549SAlfred Perlstein static void unp_shutdown(struct unpcb *); 2434d77a549SAlfred Perlstein static void unp_drop(struct unpcb *, int); 244a0ec558aSRobert Watson static void unp_gc(__unused void *, int); 2454d77a549SAlfred Perlstein static void unp_scan(struct mbuf *, void (*)(struct file *)); 2464d77a549SAlfred Perlstein static void unp_discard(struct file *); 2474d77a549SAlfred Perlstein static void unp_freerights(struct file **, int); 2480b36cd25SRobert Watson static void unp_init(void); 2494d77a549SAlfred Perlstein static int unp_internalize(struct mbuf **, struct thread *); 250397c19d1SJeff Roberson static void unp_internalize_fp(struct file *); 2510b36cd25SRobert Watson static int unp_externalize(struct mbuf *, struct mbuf **); 252397c19d1SJeff Roberson static void unp_externalize_fp(struct file *); 2535b950deaSRobert Watson static struct mbuf *unp_addsockcred(struct thread *, struct mbuf *); 254f708ef1bSPoul-Henning Kamp 255e4445a03SRobert Watson /* 256e4445a03SRobert Watson * Definitions of protocols supported in the LOCAL domain. 257e4445a03SRobert Watson */ 258e4445a03SRobert Watson static struct domain localdomain; 259fa9402f2SRobert Watson static struct pr_usrreqs uipc_usrreqs_dgram, uipc_usrreqs_stream; 260e4445a03SRobert Watson static struct protosw localsw[] = { 261e4445a03SRobert Watson { 262e4445a03SRobert Watson .pr_type = SOCK_STREAM, 263e4445a03SRobert Watson .pr_domain = &localdomain, 264e4445a03SRobert Watson .pr_flags = PR_CONNREQUIRED|PR_WANTRCVD|PR_RIGHTS, 265e4445a03SRobert Watson .pr_ctloutput = &uipc_ctloutput, 266fa9402f2SRobert Watson .pr_usrreqs = &uipc_usrreqs_stream 267e4445a03SRobert Watson }, 268e4445a03SRobert Watson { 269e4445a03SRobert Watson .pr_type = SOCK_DGRAM, 270e4445a03SRobert Watson .pr_domain = &localdomain, 271e4445a03SRobert Watson .pr_flags = PR_ATOMIC|PR_ADDR|PR_RIGHTS, 272fa9402f2SRobert Watson .pr_usrreqs = &uipc_usrreqs_dgram 273e4445a03SRobert Watson }, 274e4445a03SRobert Watson }; 275e4445a03SRobert Watson 276e4445a03SRobert Watson static struct domain localdomain = { 277e4445a03SRobert Watson .dom_family = AF_LOCAL, 278e4445a03SRobert Watson .dom_name = "local", 279e4445a03SRobert Watson .dom_init = unp_init, 280e4445a03SRobert Watson .dom_externalize = unp_externalize, 281e4445a03SRobert Watson .dom_dispose = unp_dispose, 282e4445a03SRobert Watson .dom_protosw = localsw, 283e4445a03SRobert Watson .dom_protoswNPROTOSW = &localsw[sizeof(localsw)/sizeof(localsw[0])] 284e4445a03SRobert Watson }; 285e4445a03SRobert Watson DOMAIN_SET(local); 286e4445a03SRobert Watson 287ac45e92fSRobert Watson static void 288a29f300eSGarrett Wollman uipc_abort(struct socket *so) 289df8bae1dSRodney W. Grimes { 290e7c33e29SRobert Watson struct unpcb *unp, *unp2; 291df8bae1dSRodney W. Grimes 29240f2ac28SRobert Watson unp = sotounpcb(so); 2934d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_abort: unp == NULL")); 294e7c33e29SRobert Watson 2953dab55bcSRobert Watson UNP_LINK_WLOCK(); 296e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 297e7c33e29SRobert Watson unp2 = unp->unp_conn; 298e7c33e29SRobert Watson if (unp2 != NULL) { 299e7c33e29SRobert Watson UNP_PCB_LOCK(unp2); 300e7c33e29SRobert Watson unp_drop(unp2, ECONNABORTED); 301e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp2); 302e7c33e29SRobert Watson } 303e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 3043dab55bcSRobert Watson UNP_LINK_WUNLOCK(); 305df8bae1dSRodney W. Grimes } 306df8bae1dSRodney W. Grimes 307a29f300eSGarrett Wollman static int 30857bf258eSGarrett Wollman uipc_accept(struct socket *so, struct sockaddr **nam) 309a29f300eSGarrett Wollman { 310e7c33e29SRobert Watson struct unpcb *unp, *unp2; 3110d9ce3a1SRobert Watson const struct sockaddr *sa; 312df8bae1dSRodney W. Grimes 313df8bae1dSRodney W. Grimes /* 3141c381b19SRobert Watson * Pass back name of connected socket, if it was bound and we are 3151c381b19SRobert Watson * still connected (our peer may have closed already!). 316df8bae1dSRodney W. Grimes */ 3174d4b555eSRobert Watson unp = sotounpcb(so); 3184d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_accept: unp == NULL")); 319e7c33e29SRobert Watson 3200d9ce3a1SRobert Watson *nam = malloc(sizeof(struct sockaddr_un), M_SONAME, M_WAITOK); 3213dab55bcSRobert Watson UNP_LINK_RLOCK(); 322e7c33e29SRobert Watson unp2 = unp->unp_conn; 323e7c33e29SRobert Watson if (unp2 != NULL && unp2->unp_addr != NULL) { 324e7c33e29SRobert Watson UNP_PCB_LOCK(unp2); 325e7c33e29SRobert Watson sa = (struct sockaddr *) unp2->unp_addr; 326e7c33e29SRobert Watson bcopy(sa, *nam, sa->sa_len); 327e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp2); 328e7c33e29SRobert Watson } else { 3290d9ce3a1SRobert Watson sa = &sun_noname; 3300d9ce3a1SRobert Watson bcopy(sa, *nam, sa->sa_len); 331e7c33e29SRobert Watson } 3323dab55bcSRobert Watson UNP_LINK_RUNLOCK(); 333e5aeaa0cSDag-Erling Smørgrav return (0); 334a29f300eSGarrett Wollman } 335df8bae1dSRodney W. Grimes 336a29f300eSGarrett Wollman static int 337b40ce416SJulian Elischer uipc_attach(struct socket *so, int proto, struct thread *td) 338a29f300eSGarrett Wollman { 339e7c33e29SRobert Watson u_long sendspace, recvspace; 3406d32873cSRobert Watson struct unpcb *unp; 3413dab55bcSRobert Watson int error; 342df8bae1dSRodney W. Grimes 3436d32873cSRobert Watson KASSERT(so->so_pcb == NULL, ("uipc_attach: so_pcb != NULL")); 3446d32873cSRobert Watson if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 3456d32873cSRobert Watson switch (so->so_type) { 3466d32873cSRobert Watson case SOCK_STREAM: 347e7c33e29SRobert Watson sendspace = unpst_sendspace; 348e7c33e29SRobert Watson recvspace = unpst_recvspace; 3496d32873cSRobert Watson break; 3506d32873cSRobert Watson 3516d32873cSRobert Watson case SOCK_DGRAM: 352e7c33e29SRobert Watson sendspace = unpdg_sendspace; 353e7c33e29SRobert Watson recvspace = unpdg_recvspace; 3546d32873cSRobert Watson break; 3556d32873cSRobert Watson 3566d32873cSRobert Watson default: 357e7c33e29SRobert Watson panic("uipc_attach"); 3586d32873cSRobert Watson } 359e7c33e29SRobert Watson error = soreserve(so, sendspace, recvspace); 3606d32873cSRobert Watson if (error) 3616d32873cSRobert Watson return (error); 3626d32873cSRobert Watson } 36346a1d9bfSRobert Watson unp = uma_zalloc(unp_zone, M_NOWAIT | M_ZERO); 3646d32873cSRobert Watson if (unp == NULL) 3656d32873cSRobert Watson return (ENOBUFS); 3666d32873cSRobert Watson LIST_INIT(&unp->unp_refs); 367e7c33e29SRobert Watson UNP_PCB_LOCK_INIT(unp); 3686d32873cSRobert Watson unp->unp_socket = so; 3696d32873cSRobert Watson so->so_pcb = unp; 3709ae328fcSJohn Baldwin unp->unp_refcount = 1; 371e7c33e29SRobert Watson 3723dab55bcSRobert Watson UNP_LIST_LOCK(); 3736d32873cSRobert Watson unp->unp_gencnt = ++unp_gencnt; 3746d32873cSRobert Watson unp_count++; 375b7e2f3ecSRobert Watson LIST_INSERT_HEAD(so->so_type == SOCK_DGRAM ? &unp_dhead : &unp_shead, 376b7e2f3ecSRobert Watson unp, unp_link); 3773dab55bcSRobert Watson UNP_LIST_UNLOCK(); 3786d32873cSRobert Watson 3796d32873cSRobert Watson return (0); 380a29f300eSGarrett Wollman } 381a29f300eSGarrett Wollman 382a29f300eSGarrett Wollman static int 383b40ce416SJulian Elischer uipc_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 384a29f300eSGarrett Wollman { 385dd47f5caSRobert Watson struct sockaddr_un *soun = (struct sockaddr_un *)nam; 386dd47f5caSRobert Watson struct vattr vattr; 3879e289446SWojciech A. Koszek int error, namelen, vfslocked; 388dd47f5caSRobert Watson struct nameidata nd; 38940f2ac28SRobert Watson struct unpcb *unp; 390dd47f5caSRobert Watson struct vnode *vp; 391dd47f5caSRobert Watson struct mount *mp; 392dd47f5caSRobert Watson char *buf; 393a29f300eSGarrett Wollman 39440f2ac28SRobert Watson unp = sotounpcb(so); 3954d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_bind: unp == NULL")); 3964f1f0ef5SRobert Watson 3974f1f0ef5SRobert Watson namelen = soun->sun_len - offsetof(struct sockaddr_un, sun_path); 3984f1f0ef5SRobert Watson if (namelen <= 0) 3994f1f0ef5SRobert Watson return (EINVAL); 400dd47f5caSRobert Watson 401dd47f5caSRobert Watson /* 4024f1f0ef5SRobert Watson * We don't allow simultaneous bind() calls on a single UNIX domain 4034f1f0ef5SRobert Watson * socket, so flag in-progress operations, and return an error if an 4044f1f0ef5SRobert Watson * operation is already in progress. 4054f1f0ef5SRobert Watson * 4064f1f0ef5SRobert Watson * Historically, we have not allowed a socket to be rebound, so this 407d7924b70SRobert Watson * also returns an error. Not allowing re-binding simplifies the 408d7924b70SRobert Watson * implementation and avoids a great many possible failure modes. 409dd47f5caSRobert Watson */ 410e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 411dd47f5caSRobert Watson if (unp->unp_vnode != NULL) { 412e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 413dd47f5caSRobert Watson return (EINVAL); 414dd47f5caSRobert Watson } 4154f1f0ef5SRobert Watson if (unp->unp_flags & UNP_BINDING) { 416e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 4174f1f0ef5SRobert Watson return (EALREADY); 418dd47f5caSRobert Watson } 4194f1f0ef5SRobert Watson unp->unp_flags |= UNP_BINDING; 420e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 421dd47f5caSRobert Watson 422dd47f5caSRobert Watson buf = malloc(namelen + 1, M_TEMP, M_WAITOK); 4237928893dSEd Maste bcopy(soun->sun_path, buf, namelen); 4247928893dSEd Maste buf[namelen] = 0; 425dd47f5caSRobert Watson 426dd47f5caSRobert Watson restart: 4279e289446SWojciech A. Koszek vfslocked = 0; 4289e289446SWojciech A. Koszek NDINIT(&nd, CREATE, MPSAFE | NOFOLLOW | LOCKPARENT | SAVENAME, 4299e289446SWojciech A. Koszek UIO_SYSSPACE, buf, td); 430dd47f5caSRobert Watson /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ 431dd47f5caSRobert Watson error = namei(&nd); 432dd47f5caSRobert Watson if (error) 4334f1f0ef5SRobert Watson goto error; 434dd47f5caSRobert Watson vp = nd.ni_vp; 4359e289446SWojciech A. Koszek vfslocked = NDHASGIANT(&nd); 436dd47f5caSRobert Watson if (vp != NULL || vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { 437dd47f5caSRobert Watson NDFREE(&nd, NDF_ONLY_PNBUF); 438dd47f5caSRobert Watson if (nd.ni_dvp == vp) 439dd47f5caSRobert Watson vrele(nd.ni_dvp); 440dd47f5caSRobert Watson else 441dd47f5caSRobert Watson vput(nd.ni_dvp); 442dd47f5caSRobert Watson if (vp != NULL) { 443dd47f5caSRobert Watson vrele(vp); 444dd47f5caSRobert Watson error = EADDRINUSE; 4454f1f0ef5SRobert Watson goto error; 446dd47f5caSRobert Watson } 447dd47f5caSRobert Watson error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH); 448dd47f5caSRobert Watson if (error) 4494f1f0ef5SRobert Watson goto error; 4509e289446SWojciech A. Koszek VFS_UNLOCK_GIANT(vfslocked); 451dd47f5caSRobert Watson goto restart; 452dd47f5caSRobert Watson } 453dd47f5caSRobert Watson VATTR_NULL(&vattr); 454dd47f5caSRobert Watson vattr.va_type = VSOCK; 455dd47f5caSRobert Watson vattr.va_mode = (ACCESSPERMS & ~td->td_proc->p_fd->fd_cmask); 456dd47f5caSRobert Watson #ifdef MAC 45730d239bcSRobert Watson error = mac_vnode_check_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd, 458dd47f5caSRobert Watson &vattr); 459dd47f5caSRobert Watson #endif 460dd47f5caSRobert Watson if (error == 0) { 461dd47f5caSRobert Watson VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE); 462dd47f5caSRobert Watson error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 463dd47f5caSRobert Watson } 464dd47f5caSRobert Watson NDFREE(&nd, NDF_ONLY_PNBUF); 465dd47f5caSRobert Watson vput(nd.ni_dvp); 466dd47f5caSRobert Watson if (error) { 467dd47f5caSRobert Watson vn_finished_write(mp); 4684f1f0ef5SRobert Watson goto error; 469dd47f5caSRobert Watson } 470dd47f5caSRobert Watson vp = nd.ni_vp; 47157fd3d55SPawel Jakub Dawidek ASSERT_VOP_ELOCKED(vp, "uipc_bind"); 472dd47f5caSRobert Watson soun = (struct sockaddr_un *)sodupsockaddr(nam, M_WAITOK); 473e7c33e29SRobert Watson 4743dab55bcSRobert Watson UNP_LINK_WLOCK(); 475e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 476dd47f5caSRobert Watson vp->v_socket = unp->unp_socket; 477dd47f5caSRobert Watson unp->unp_vnode = vp; 478dd47f5caSRobert Watson unp->unp_addr = soun; 4794f1f0ef5SRobert Watson unp->unp_flags &= ~UNP_BINDING; 480e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 4813dab55bcSRobert Watson UNP_LINK_WUNLOCK(); 48222db15c0SAttilio Rao VOP_UNLOCK(vp, 0); 483dd47f5caSRobert Watson vn_finished_write(mp); 4849e289446SWojciech A. Koszek VFS_UNLOCK_GIANT(vfslocked); 4854f1f0ef5SRobert Watson free(buf, M_TEMP); 4864f1f0ef5SRobert Watson return (0); 487e7c33e29SRobert Watson 4884f1f0ef5SRobert Watson error: 4899e289446SWojciech A. Koszek VFS_UNLOCK_GIANT(vfslocked); 490e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 4914f1f0ef5SRobert Watson unp->unp_flags &= ~UNP_BINDING; 492e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 493dd47f5caSRobert Watson free(buf, M_TEMP); 49440f2ac28SRobert Watson return (error); 495a29f300eSGarrett Wollman } 496a29f300eSGarrett Wollman 497a29f300eSGarrett Wollman static int 498b40ce416SJulian Elischer uipc_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 499a29f300eSGarrett Wollman { 5000d9ce3a1SRobert Watson int error; 501a29f300eSGarrett Wollman 502fd179ee9SRobert Watson KASSERT(td == curthread, ("uipc_connect: td != curthread")); 5033dab55bcSRobert Watson UNP_LINK_WLOCK(); 504fd179ee9SRobert Watson error = unp_connect(so, nam, td); 5053dab55bcSRobert Watson UNP_LINK_WUNLOCK(); 5060d9ce3a1SRobert Watson return (error); 507a29f300eSGarrett Wollman } 508a29f300eSGarrett Wollman 509a152f8a3SRobert Watson static void 510a152f8a3SRobert Watson uipc_close(struct socket *so) 511a152f8a3SRobert Watson { 512e7c33e29SRobert Watson struct unpcb *unp, *unp2; 513a152f8a3SRobert Watson 514a152f8a3SRobert Watson unp = sotounpcb(so); 515a152f8a3SRobert Watson KASSERT(unp != NULL, ("uipc_close: unp == NULL")); 516e7c33e29SRobert Watson 5173dab55bcSRobert Watson UNP_LINK_WLOCK(); 518e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 519e7c33e29SRobert Watson unp2 = unp->unp_conn; 520e7c33e29SRobert Watson if (unp2 != NULL) { 521e7c33e29SRobert Watson UNP_PCB_LOCK(unp2); 522e7c33e29SRobert Watson unp_disconnect(unp, unp2); 523e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp2); 524e7c33e29SRobert Watson } 525e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 5263dab55bcSRobert Watson UNP_LINK_WUNLOCK(); 527a152f8a3SRobert Watson } 528a152f8a3SRobert Watson 5292c899584SRobert Watson static int 530a29f300eSGarrett Wollman uipc_connect2(struct socket *so1, struct socket *so2) 531a29f300eSGarrett Wollman { 532e7c33e29SRobert Watson struct unpcb *unp, *unp2; 5330d9ce3a1SRobert Watson int error; 534a29f300eSGarrett Wollman 5353dab55bcSRobert Watson UNP_LINK_WLOCK(); 536e7c33e29SRobert Watson unp = so1->so_pcb; 5374d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_connect2: unp == NULL")); 538e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 539e7c33e29SRobert Watson unp2 = so2->so_pcb; 540e7c33e29SRobert Watson KASSERT(unp2 != NULL, ("uipc_connect2: unp2 == NULL")); 541e7c33e29SRobert Watson UNP_PCB_LOCK(unp2); 5426a2989fdSMatthew N. Dodd error = unp_connect2(so1, so2, PRU_CONNECT2); 543e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp2); 544e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 5453dab55bcSRobert Watson UNP_LINK_WUNLOCK(); 5460d9ce3a1SRobert Watson return (error); 547a29f300eSGarrett Wollman } 548a29f300eSGarrett Wollman 549bc725eafSRobert Watson static void 550a29f300eSGarrett Wollman uipc_detach(struct socket *so) 551a29f300eSGarrett Wollman { 552e7c33e29SRobert Watson struct unpcb *unp, *unp2; 5539ae328fcSJohn Baldwin struct sockaddr_un *saved_unp_addr; 5546d32873cSRobert Watson struct vnode *vp; 5559ae328fcSJohn Baldwin int freeunp, local_unp_rights; 556a29f300eSGarrett Wollman 55740f2ac28SRobert Watson unp = sotounpcb(so); 5584d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_detach: unp == NULL")); 559e7c33e29SRobert Watson 5603dab55bcSRobert Watson UNP_LINK_WLOCK(); 5613dab55bcSRobert Watson UNP_LIST_LOCK(); 562e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 5636d32873cSRobert Watson LIST_REMOVE(unp, unp_link); 5646d32873cSRobert Watson unp->unp_gencnt = ++unp_gencnt; 5656d32873cSRobert Watson --unp_count; 5663dab55bcSRobert Watson UNP_LIST_UNLOCK(); 567e7c33e29SRobert Watson 568e7c33e29SRobert Watson /* 569e7c33e29SRobert Watson * XXXRW: Should assert vp->v_socket == so. 570e7c33e29SRobert Watson */ 5716d32873cSRobert Watson if ((vp = unp->unp_vnode) != NULL) { 5726d32873cSRobert Watson unp->unp_vnode->v_socket = NULL; 5736d32873cSRobert Watson unp->unp_vnode = NULL; 5746d32873cSRobert Watson } 575e7c33e29SRobert Watson unp2 = unp->unp_conn; 576e7c33e29SRobert Watson if (unp2 != NULL) { 577e7c33e29SRobert Watson UNP_PCB_LOCK(unp2); 578e7c33e29SRobert Watson unp_disconnect(unp, unp2); 579e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp2); 580e7c33e29SRobert Watson } 581e7c33e29SRobert Watson 582e7c33e29SRobert Watson /* 5833dab55bcSRobert Watson * We hold the linkage lock exclusively, so it's OK to acquire 58460a5ef26SRobert Watson * multiple pcb locks at a time. 585e7c33e29SRobert Watson */ 5866d32873cSRobert Watson while (!LIST_EMPTY(&unp->unp_refs)) { 5876d32873cSRobert Watson struct unpcb *ref = LIST_FIRST(&unp->unp_refs); 588e7c33e29SRobert Watson 589e7c33e29SRobert Watson UNP_PCB_LOCK(ref); 5906d32873cSRobert Watson unp_drop(ref, ECONNRESET); 591e7c33e29SRobert Watson UNP_PCB_UNLOCK(ref); 5926d32873cSRobert Watson } 593397c19d1SJeff Roberson local_unp_rights = unp_rights; 5943dab55bcSRobert Watson UNP_LINK_WUNLOCK(); 5956d32873cSRobert Watson unp->unp_socket->so_pcb = NULL; 5969ae328fcSJohn Baldwin saved_unp_addr = unp->unp_addr; 5979ae328fcSJohn Baldwin unp->unp_addr = NULL; 5989ae328fcSJohn Baldwin unp->unp_refcount--; 5999ae328fcSJohn Baldwin freeunp = (unp->unp_refcount == 0); 6009ae328fcSJohn Baldwin if (saved_unp_addr != NULL) 6011ede983cSDag-Erling Smørgrav free(saved_unp_addr, M_SONAME); 602e7c33e29SRobert Watson if (freeunp) { 603e7c33e29SRobert Watson UNP_PCB_LOCK_DESTROY(unp); 6046d32873cSRobert Watson uma_zfree(unp_zone, unp); 6056e2faa24SRobert Watson } else 6066e2faa24SRobert Watson UNP_PCB_UNLOCK(unp); 6076d32873cSRobert Watson if (vp) { 6086d32873cSRobert Watson int vfslocked; 6096d32873cSRobert Watson 6106d32873cSRobert Watson vfslocked = VFS_LOCK_GIANT(vp->v_mount); 6116d32873cSRobert Watson vrele(vp); 6126d32873cSRobert Watson VFS_UNLOCK_GIANT(vfslocked); 6136d32873cSRobert Watson } 6146d32873cSRobert Watson if (local_unp_rights) 6156d32873cSRobert Watson taskqueue_enqueue(taskqueue_thread, &unp_gc_task); 616a29f300eSGarrett Wollman } 617a29f300eSGarrett Wollman 618a29f300eSGarrett Wollman static int 619a29f300eSGarrett Wollman uipc_disconnect(struct socket *so) 620a29f300eSGarrett Wollman { 621e7c33e29SRobert Watson struct unpcb *unp, *unp2; 622a29f300eSGarrett Wollman 62340f2ac28SRobert Watson unp = sotounpcb(so); 6244d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_disconnect: unp == NULL")); 625e7c33e29SRobert Watson 6263dab55bcSRobert Watson UNP_LINK_WLOCK(); 627e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 628e7c33e29SRobert Watson unp2 = unp->unp_conn; 629e7c33e29SRobert Watson if (unp2 != NULL) { 630e7c33e29SRobert Watson UNP_PCB_LOCK(unp2); 631e7c33e29SRobert Watson unp_disconnect(unp, unp2); 632e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp2); 633e7c33e29SRobert Watson } 634e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 6353dab55bcSRobert Watson UNP_LINK_WUNLOCK(); 636e5aeaa0cSDag-Erling Smørgrav return (0); 637a29f300eSGarrett Wollman } 638a29f300eSGarrett Wollman 639a29f300eSGarrett Wollman static int 640d374e81eSRobert Watson uipc_listen(struct socket *so, int backlog, struct thread *td) 641a29f300eSGarrett Wollman { 64240f2ac28SRobert Watson struct unpcb *unp; 6430d9ce3a1SRobert Watson int error; 644a29f300eSGarrett Wollman 64540f2ac28SRobert Watson unp = sotounpcb(so); 6464d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_listen: unp == NULL")); 647e7c33e29SRobert Watson 648e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 6494d4b555eSRobert Watson if (unp->unp_vnode == NULL) { 650e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 65140f2ac28SRobert Watson return (EINVAL); 65240f2ac28SRobert Watson } 653e7c33e29SRobert Watson 654e7c33e29SRobert Watson SOCK_LOCK(so); 655e7c33e29SRobert Watson error = solisten_proto_check(so); 656e7c33e29SRobert Watson if (error == 0) { 657e7c33e29SRobert Watson cru2x(td->td_ucred, &unp->unp_peercred); 658e7c33e29SRobert Watson unp->unp_flags |= UNP_HAVEPCCACHED; 659e7c33e29SRobert Watson solisten_proto(so, backlog); 660e7c33e29SRobert Watson } 661e7c33e29SRobert Watson SOCK_UNLOCK(so); 662e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 6630d9ce3a1SRobert Watson return (error); 664a29f300eSGarrett Wollman } 665a29f300eSGarrett Wollman 666a29f300eSGarrett Wollman static int 66757bf258eSGarrett Wollman uipc_peeraddr(struct socket *so, struct sockaddr **nam) 668a29f300eSGarrett Wollman { 669e7c33e29SRobert Watson struct unpcb *unp, *unp2; 6700d9ce3a1SRobert Watson const struct sockaddr *sa; 671a29f300eSGarrett Wollman 6724d4b555eSRobert Watson unp = sotounpcb(so); 6734d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_peeraddr: unp == NULL")); 674e7c33e29SRobert Watson 6750d9ce3a1SRobert Watson *nam = malloc(sizeof(struct sockaddr_un), M_SONAME, M_WAITOK); 676e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 677bdc5f6a3SHajimu UMEMOTO /* 678e7c33e29SRobert Watson * XXX: It seems that this test always fails even when connection is 679e7c33e29SRobert Watson * established. So, this else clause is added as workaround to 680e7c33e29SRobert Watson * return PF_LOCAL sockaddr. 681bdc5f6a3SHajimu UMEMOTO */ 682e7c33e29SRobert Watson unp2 = unp->unp_conn; 683e7c33e29SRobert Watson if (unp2 != NULL) { 684e7c33e29SRobert Watson UNP_PCB_LOCK(unp2); 685e7c33e29SRobert Watson if (unp2->unp_addr != NULL) 686e7c33e29SRobert Watson sa = (struct sockaddr *) unp->unp_conn->unp_addr; 687e7c33e29SRobert Watson else 6880d9ce3a1SRobert Watson sa = &sun_noname; 6890d9ce3a1SRobert Watson bcopy(sa, *nam, sa->sa_len); 690e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp2); 691e7c33e29SRobert Watson } else { 692e7c33e29SRobert Watson sa = &sun_noname; 693e7c33e29SRobert Watson bcopy(sa, *nam, sa->sa_len); 694e7c33e29SRobert Watson } 695e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 696e5aeaa0cSDag-Erling Smørgrav return (0); 697a29f300eSGarrett Wollman } 698a29f300eSGarrett Wollman 699a29f300eSGarrett Wollman static int 700a29f300eSGarrett Wollman uipc_rcvd(struct socket *so, int flags) 701a29f300eSGarrett Wollman { 702e7c33e29SRobert Watson struct unpcb *unp, *unp2; 703a29f300eSGarrett Wollman struct socket *so2; 704337cc6b6SRobert Watson u_int mbcnt, sbcc; 7056aef685fSBrian Feldman u_long newhiwat; 706a29f300eSGarrett Wollman 70740f2ac28SRobert Watson unp = sotounpcb(so); 7084d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_rcvd: unp == NULL")); 709df8bae1dSRodney W. Grimes 710e7c33e29SRobert Watson if (so->so_type == SOCK_DGRAM) 711e7c33e29SRobert Watson panic("uipc_rcvd DGRAM?"); 712e7c33e29SRobert Watson 713e7c33e29SRobert Watson if (so->so_type != SOCK_STREAM) 714e7c33e29SRobert Watson panic("uipc_rcvd unknown socktype"); 715e7c33e29SRobert Watson 716df8bae1dSRodney W. Grimes /* 717e7c33e29SRobert Watson * Adjust backpressure on sender and wakeup any waiting to write. 718e7c33e29SRobert Watson * 719d7924b70SRobert Watson * The unp lock is acquired to maintain the validity of the unp_conn 720d7924b70SRobert Watson * pointer; no lock on unp2 is required as unp2->unp_socket will be 721d7924b70SRobert Watson * static as long as we don't permit unp2 to disconnect from unp, 722d7924b70SRobert Watson * which is prevented by the lock on unp. We cache values from 723d7924b70SRobert Watson * so_rcv to avoid holding the so_rcv lock over the entire 724d7924b70SRobert Watson * transaction on the remote so_snd. 725df8bae1dSRodney W. Grimes */ 726337cc6b6SRobert Watson SOCKBUF_LOCK(&so->so_rcv); 727337cc6b6SRobert Watson mbcnt = so->so_rcv.sb_mbcnt; 728337cc6b6SRobert Watson sbcc = so->so_rcv.sb_cc; 729337cc6b6SRobert Watson SOCKBUF_UNLOCK(&so->so_rcv); 730e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 731e7c33e29SRobert Watson unp2 = unp->unp_conn; 732e7c33e29SRobert Watson if (unp2 == NULL) { 733e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 734e7c33e29SRobert Watson return (0); 735337cc6b6SRobert Watson } 736e7c33e29SRobert Watson so2 = unp2->unp_socket; 737337cc6b6SRobert Watson SOCKBUF_LOCK(&so2->so_snd); 738337cc6b6SRobert Watson so2->so_snd.sb_mbmax += unp->unp_mbcnt - mbcnt; 739337cc6b6SRobert Watson newhiwat = so2->so_snd.sb_hiwat + unp->unp_cc - sbcc; 740f535380cSDon Lewis (void)chgsbsize(so2->so_cred->cr_uidinfo, &so2->so_snd.sb_hiwat, 7416aef685fSBrian Feldman newhiwat, RLIM_INFINITY); 7421e4d7da7SRobert Watson sowwakeup_locked(so2); 743337cc6b6SRobert Watson unp->unp_mbcnt = mbcnt; 744337cc6b6SRobert Watson unp->unp_cc = sbcc; 745e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 746e5aeaa0cSDag-Erling Smørgrav return (0); 747a29f300eSGarrett Wollman } 748df8bae1dSRodney W. Grimes 749a29f300eSGarrett Wollman static int 75057bf258eSGarrett Wollman uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, 751b40ce416SJulian Elischer struct mbuf *control, struct thread *td) 752a29f300eSGarrett Wollman { 753f3f49bbbSRobert Watson struct unpcb *unp, *unp2; 754a29f300eSGarrett Wollman struct socket *so2; 755a9f3c7d2SRobert Watson u_int mbcnt_delta, sbcc; 7566aef685fSBrian Feldman u_long newhiwat; 757f3f49bbbSRobert Watson int error = 0; 758a29f300eSGarrett Wollman 75940f2ac28SRobert Watson unp = sotounpcb(so); 7604d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_send: unp == NULL")); 761e7c33e29SRobert Watson 762a29f300eSGarrett Wollman if (flags & PRUS_OOB) { 763a29f300eSGarrett Wollman error = EOPNOTSUPP; 764a29f300eSGarrett Wollman goto release; 765a29f300eSGarrett Wollman } 766fc3fcacfSRobert Watson if (control != NULL && (error = unp_internalize(&control, td))) 767a29f300eSGarrett Wollman goto release; 768e7c33e29SRobert Watson if ((nam != NULL) || (flags & PRUS_EOF)) 7693dab55bcSRobert Watson UNP_LINK_WLOCK(); 770e7c33e29SRobert Watson else 7713dab55bcSRobert Watson UNP_LINK_RLOCK(); 772a29f300eSGarrett Wollman switch (so->so_type) { 773a29f300eSGarrett Wollman case SOCK_DGRAM: 774a29f300eSGarrett Wollman { 775e7dd9a10SRobert Watson const struct sockaddr *from; 776df8bae1dSRodney W. Grimes 777e7c33e29SRobert Watson unp2 = unp->unp_conn; 778fc3fcacfSRobert Watson if (nam != NULL) { 7793dab55bcSRobert Watson UNP_LINK_WLOCK_ASSERT(); 780e7c33e29SRobert Watson if (unp2 != NULL) { 781df8bae1dSRodney W. Grimes error = EISCONN; 782df8bae1dSRodney W. Grimes break; 783df8bae1dSRodney W. Grimes } 784b40ce416SJulian Elischer error = unp_connect(so, nam, td); 785df8bae1dSRodney W. Grimes if (error) 786df8bae1dSRodney W. Grimes break; 787e7c33e29SRobert Watson unp2 = unp->unp_conn; 788df8bae1dSRodney W. Grimes } 78960a5ef26SRobert Watson 790b5ff0914SRobert Watson /* 791b5ff0914SRobert Watson * Because connect() and send() are non-atomic in a sendto() 792b5ff0914SRobert Watson * with a target address, it's possible that the socket will 793b5ff0914SRobert Watson * have disconnected before the send() can run. In that case 794b5ff0914SRobert Watson * return the slightly counter-intuitive but otherwise 795b5ff0914SRobert Watson * correct error that the socket is not connected. 796b5ff0914SRobert Watson */ 797b5ff0914SRobert Watson if (unp2 == NULL) { 798b5ff0914SRobert Watson error = ENOTCONN; 799b5ff0914SRobert Watson break; 800b5ff0914SRobert Watson } 801ede6e136SRobert Watson /* Lockless read. */ 802ede6e136SRobert Watson if (unp2->unp_flags & UNP_WANTCRED) 803ede6e136SRobert Watson control = unp_addsockcred(td, control); 804ede6e136SRobert Watson UNP_PCB_LOCK(unp); 805fc3fcacfSRobert Watson if (unp->unp_addr != NULL) 80657bf258eSGarrett Wollman from = (struct sockaddr *)unp->unp_addr; 807df8bae1dSRodney W. Grimes else 808df8bae1dSRodney W. Grimes from = &sun_noname; 809ede6e136SRobert Watson so2 = unp2->unp_socket; 810a34b7046SRobert Watson SOCKBUF_LOCK(&so2->so_rcv); 811a34b7046SRobert Watson if (sbappendaddr_locked(&so2->so_rcv, from, m, control)) { 8121e4d7da7SRobert Watson sorwakeup_locked(so2); 813fc3fcacfSRobert Watson m = NULL; 814fc3fcacfSRobert Watson control = NULL; 815e5aeaa0cSDag-Erling Smørgrav } else { 816a34b7046SRobert Watson SOCKBUF_UNLOCK(&so2->so_rcv); 817df8bae1dSRodney W. Grimes error = ENOBUFS; 818e5aeaa0cSDag-Erling Smørgrav } 819ede6e136SRobert Watson if (nam != NULL) { 8203dab55bcSRobert Watson UNP_LINK_WLOCK_ASSERT(); 821ede6e136SRobert Watson UNP_PCB_LOCK(unp2); 822e7c33e29SRobert Watson unp_disconnect(unp, unp2); 823e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp2); 824ede6e136SRobert Watson } 825ede6e136SRobert Watson UNP_PCB_UNLOCK(unp); 826df8bae1dSRodney W. Grimes break; 827df8bae1dSRodney W. Grimes } 828df8bae1dSRodney W. Grimes 829df8bae1dSRodney W. Grimes case SOCK_STREAM: 830402cc72dSDavid Greenman if ((so->so_state & SS_ISCONNECTED) == 0) { 831fc3fcacfSRobert Watson if (nam != NULL) { 8323dab55bcSRobert Watson UNP_LINK_WLOCK_ASSERT(); 833b40ce416SJulian Elischer error = unp_connect(so, nam, td); 834402cc72dSDavid Greenman if (error) 8356b8fda4dSGarrett Wollman break; /* XXX */ 836402cc72dSDavid Greenman } else { 837402cc72dSDavid Greenman error = ENOTCONN; 838402cc72dSDavid Greenman break; 839402cc72dSDavid Greenman } 840ede6e136SRobert Watson } 841402cc72dSDavid Greenman 842337cc6b6SRobert Watson /* Lockless read. */ 843c0b99ffaSRobert Watson if (so->so_snd.sb_state & SBS_CANTSENDMORE) { 844df8bae1dSRodney W. Grimes error = EPIPE; 845df8bae1dSRodney W. Grimes break; 846df8bae1dSRodney W. Grimes } 84760a5ef26SRobert Watson 848b5ff0914SRobert Watson /* 849b5ff0914SRobert Watson * Because connect() and send() are non-atomic in a sendto() 850b5ff0914SRobert Watson * with a target address, it's possible that the socket will 851b5ff0914SRobert Watson * have disconnected before the send() can run. In that case 852b5ff0914SRobert Watson * return the slightly counter-intuitive but otherwise 853b5ff0914SRobert Watson * correct error that the socket is not connected. 854e7c33e29SRobert Watson * 8553dab55bcSRobert Watson * Locking here must be done carefully: the inkage lock 856d7924b70SRobert Watson * prevents interconnections between unpcbs from changing, so 857d7924b70SRobert Watson * we can traverse from unp to unp2 without acquiring unp's 858d7924b70SRobert Watson * lock. Socket buffer locks follow unpcb locks, so we can 859d7924b70SRobert Watson * acquire both remote and lock socket buffer locks. 860b5ff0914SRobert Watson */ 861f3f49bbbSRobert Watson unp2 = unp->unp_conn; 862b5ff0914SRobert Watson if (unp2 == NULL) { 863b5ff0914SRobert Watson error = ENOTCONN; 864b5ff0914SRobert Watson break; 865b5ff0914SRobert Watson } 866f3f49bbbSRobert Watson so2 = unp2->unp_socket; 867ede6e136SRobert Watson UNP_PCB_LOCK(unp2); 868a34b7046SRobert Watson SOCKBUF_LOCK(&so2->so_rcv); 869f3f49bbbSRobert Watson if (unp2->unp_flags & UNP_WANTCRED) { 8706a2989fdSMatthew N. Dodd /* 871ede6e136SRobert Watson * Credentials are passed only once on SOCK_STREAM. 8726a2989fdSMatthew N. Dodd */ 873f3f49bbbSRobert Watson unp2->unp_flags &= ~UNP_WANTCRED; 8746a2989fdSMatthew N. Dodd control = unp_addsockcred(td, control); 8756a2989fdSMatthew N. Dodd } 876df8bae1dSRodney W. Grimes /* 8771c381b19SRobert Watson * Send to paired receive port, and then reduce send buffer 8781c381b19SRobert Watson * hiwater marks to maintain backpressure. Wake up readers. 879df8bae1dSRodney W. Grimes */ 880fc3fcacfSRobert Watson if (control != NULL) { 881a34b7046SRobert Watson if (sbappendcontrol_locked(&so2->so_rcv, m, control)) 882fc3fcacfSRobert Watson control = NULL; 883e7c33e29SRobert Watson } else 884a34b7046SRobert Watson sbappend_locked(&so2->so_rcv, m); 885a9f3c7d2SRobert Watson mbcnt_delta = so2->so_rcv.sb_mbcnt - unp2->unp_mbcnt; 886f3f49bbbSRobert Watson unp2->unp_mbcnt = so2->so_rcv.sb_mbcnt; 887337cc6b6SRobert Watson sbcc = so2->so_rcv.sb_cc; 888337cc6b6SRobert Watson sorwakeup_locked(so2); 889337cc6b6SRobert Watson 890337cc6b6SRobert Watson SOCKBUF_LOCK(&so->so_snd); 891f3f49bbbSRobert Watson newhiwat = so->so_snd.sb_hiwat - (sbcc - unp2->unp_cc); 892f535380cSDon Lewis (void)chgsbsize(so->so_cred->cr_uidinfo, &so->so_snd.sb_hiwat, 8936aef685fSBrian Feldman newhiwat, RLIM_INFINITY); 894a9f3c7d2SRobert Watson so->so_snd.sb_mbmax -= mbcnt_delta; 8957abe2ac2SAlan Cox SOCKBUF_UNLOCK(&so->so_snd); 896f3f49bbbSRobert Watson unp2->unp_cc = sbcc; 897e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp2); 898fc3fcacfSRobert Watson m = NULL; 899df8bae1dSRodney W. Grimes break; 900df8bae1dSRodney W. Grimes 901df8bae1dSRodney W. Grimes default: 902a29f300eSGarrett Wollman panic("uipc_send unknown socktype"); 903df8bae1dSRodney W. Grimes } 904a29f300eSGarrett Wollman 9056b8fda4dSGarrett Wollman /* 90660a5ef26SRobert Watson * PRUS_EOF is equivalent to pru_send followed by pru_shutdown. 9076b8fda4dSGarrett Wollman */ 908a29f300eSGarrett Wollman if (flags & PRUS_EOF) { 909ede6e136SRobert Watson UNP_PCB_LOCK(unp); 9106b8fda4dSGarrett Wollman socantsendmore(so); 9116b8fda4dSGarrett Wollman unp_shutdown(unp); 912e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 913ede6e136SRobert Watson } 914e7c33e29SRobert Watson 915e7c33e29SRobert Watson if ((nam != NULL) || (flags & PRUS_EOF)) 9163dab55bcSRobert Watson UNP_LINK_WUNLOCK(); 917e7c33e29SRobert Watson else 9183dab55bcSRobert Watson UNP_LINK_RUNLOCK(); 919df8bae1dSRodney W. Grimes 920fc3fcacfSRobert Watson if (control != NULL && error != 0) 921bd508d39SDon Lewis unp_dispose(control); 922bd508d39SDon Lewis 923a29f300eSGarrett Wollman release: 924fc3fcacfSRobert Watson if (control != NULL) 925a29f300eSGarrett Wollman m_freem(control); 926fc3fcacfSRobert Watson if (m != NULL) 927a29f300eSGarrett Wollman m_freem(m); 928e5aeaa0cSDag-Erling Smørgrav return (error); 929a29f300eSGarrett Wollman } 930df8bae1dSRodney W. Grimes 931a29f300eSGarrett Wollman static int 932a29f300eSGarrett Wollman uipc_sense(struct socket *so, struct stat *sb) 933a29f300eSGarrett Wollman { 934e7c33e29SRobert Watson struct unpcb *unp, *unp2; 935a29f300eSGarrett Wollman struct socket *so2; 936a29f300eSGarrett Wollman 93740f2ac28SRobert Watson unp = sotounpcb(so); 9384d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_sense: unp == NULL")); 939e7c33e29SRobert Watson 940a29f300eSGarrett Wollman sb->st_blksize = so->so_snd.sb_hiwat; 9413dab55bcSRobert Watson UNP_LINK_RLOCK(); 942e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 943e7c33e29SRobert Watson unp2 = unp->unp_conn; 944e7c33e29SRobert Watson if (so->so_type == SOCK_STREAM && unp2 != NULL) { 945e7c33e29SRobert Watson so2 = unp2->unp_socket; 946a29f300eSGarrett Wollman sb->st_blksize += so2->so_rcv.sb_cc; 947df8bae1dSRodney W. Grimes } 948f3732fd1SPoul-Henning Kamp sb->st_dev = NODEV; 949df8bae1dSRodney W. Grimes if (unp->unp_ino == 0) 9506f782c46SJeffrey Hsu unp->unp_ino = (++unp_ino == 0) ? ++unp_ino : unp_ino; 951a29f300eSGarrett Wollman sb->st_ino = unp->unp_ino; 952e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 9533dab55bcSRobert Watson UNP_LINK_RUNLOCK(); 954df8bae1dSRodney W. Grimes return (0); 955a29f300eSGarrett Wollman } 956df8bae1dSRodney W. Grimes 957a29f300eSGarrett Wollman static int 958a29f300eSGarrett Wollman uipc_shutdown(struct socket *so) 959a29f300eSGarrett Wollman { 96040f2ac28SRobert Watson struct unpcb *unp; 961df8bae1dSRodney W. Grimes 96240f2ac28SRobert Watson unp = sotounpcb(so); 9634d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_shutdown: unp == NULL")); 964e7c33e29SRobert Watson 9653dab55bcSRobert Watson UNP_LINK_WLOCK(); 966e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 967a29f300eSGarrett Wollman socantsendmore(so); 968a29f300eSGarrett Wollman unp_shutdown(unp); 969e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 9703dab55bcSRobert Watson UNP_LINK_WUNLOCK(); 971e5aeaa0cSDag-Erling Smørgrav return (0); 972a29f300eSGarrett Wollman } 973df8bae1dSRodney W. Grimes 974a29f300eSGarrett Wollman static int 97557bf258eSGarrett Wollman uipc_sockaddr(struct socket *so, struct sockaddr **nam) 976a29f300eSGarrett Wollman { 97740f2ac28SRobert Watson struct unpcb *unp; 9780d9ce3a1SRobert Watson const struct sockaddr *sa; 979a29f300eSGarrett Wollman 9804d4b555eSRobert Watson unp = sotounpcb(so); 9814d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_sockaddr: unp == NULL")); 982e7c33e29SRobert Watson 9830d9ce3a1SRobert Watson *nam = malloc(sizeof(struct sockaddr_un), M_SONAME, M_WAITOK); 984e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 985fc3fcacfSRobert Watson if (unp->unp_addr != NULL) 9860d9ce3a1SRobert Watson sa = (struct sockaddr *) unp->unp_addr; 98783f3198bSThomas Moestl else 9880d9ce3a1SRobert Watson sa = &sun_noname; 9890d9ce3a1SRobert Watson bcopy(sa, *nam, sa->sa_len); 990e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 991e5aeaa0cSDag-Erling Smørgrav return (0); 992df8bae1dSRodney W. Grimes } 993a29f300eSGarrett Wollman 994fa9402f2SRobert Watson static struct pr_usrreqs uipc_usrreqs_dgram = { 995756d52a1SPoul-Henning Kamp .pru_abort = uipc_abort, 996756d52a1SPoul-Henning Kamp .pru_accept = uipc_accept, 997756d52a1SPoul-Henning Kamp .pru_attach = uipc_attach, 998756d52a1SPoul-Henning Kamp .pru_bind = uipc_bind, 999756d52a1SPoul-Henning Kamp .pru_connect = uipc_connect, 1000756d52a1SPoul-Henning Kamp .pru_connect2 = uipc_connect2, 1001756d52a1SPoul-Henning Kamp .pru_detach = uipc_detach, 1002756d52a1SPoul-Henning Kamp .pru_disconnect = uipc_disconnect, 1003756d52a1SPoul-Henning Kamp .pru_listen = uipc_listen, 1004756d52a1SPoul-Henning Kamp .pru_peeraddr = uipc_peeraddr, 1005756d52a1SPoul-Henning Kamp .pru_rcvd = uipc_rcvd, 1006756d52a1SPoul-Henning Kamp .pru_send = uipc_send, 1007756d52a1SPoul-Henning Kamp .pru_sense = uipc_sense, 1008756d52a1SPoul-Henning Kamp .pru_shutdown = uipc_shutdown, 1009756d52a1SPoul-Henning Kamp .pru_sockaddr = uipc_sockaddr, 1010fa9402f2SRobert Watson .pru_soreceive = soreceive_dgram, 1011fa9402f2SRobert Watson .pru_close = uipc_close, 1012fa9402f2SRobert Watson }; 1013fa9402f2SRobert Watson 1014fa9402f2SRobert Watson static struct pr_usrreqs uipc_usrreqs_stream = { 1015fa9402f2SRobert Watson .pru_abort = uipc_abort, 1016fa9402f2SRobert Watson .pru_accept = uipc_accept, 1017fa9402f2SRobert Watson .pru_attach = uipc_attach, 1018fa9402f2SRobert Watson .pru_bind = uipc_bind, 1019fa9402f2SRobert Watson .pru_connect = uipc_connect, 1020fa9402f2SRobert Watson .pru_connect2 = uipc_connect2, 1021fa9402f2SRobert Watson .pru_detach = uipc_detach, 1022fa9402f2SRobert Watson .pru_disconnect = uipc_disconnect, 1023fa9402f2SRobert Watson .pru_listen = uipc_listen, 1024fa9402f2SRobert Watson .pru_peeraddr = uipc_peeraddr, 1025fa9402f2SRobert Watson .pru_rcvd = uipc_rcvd, 1026fa9402f2SRobert Watson .pru_send = uipc_send, 1027fa9402f2SRobert Watson .pru_sense = uipc_sense, 1028fa9402f2SRobert Watson .pru_shutdown = uipc_shutdown, 1029fa9402f2SRobert Watson .pru_sockaddr = uipc_sockaddr, 1030fa9402f2SRobert Watson .pru_soreceive = soreceive_generic, 1031a152f8a3SRobert Watson .pru_close = uipc_close, 1032a29f300eSGarrett Wollman }; 1033df8bae1dSRodney W. Grimes 10340b36cd25SRobert Watson static int 1035892af6b9SRobert Watson uipc_ctloutput(struct socket *so, struct sockopt *sopt) 10360c1bb4fbSDima Dorfman { 103740f2ac28SRobert Watson struct unpcb *unp; 10380d9ce3a1SRobert Watson struct xucred xu; 10396a2989fdSMatthew N. Dodd int error, optval; 10406a2989fdSMatthew N. Dodd 104196a041b5SMatthew N. Dodd if (sopt->sopt_level != 0) 104296a041b5SMatthew N. Dodd return (EINVAL); 104396a041b5SMatthew N. Dodd 10446a2989fdSMatthew N. Dodd unp = sotounpcb(so); 10454d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_ctloutput: unp == NULL")); 10466a2989fdSMatthew N. Dodd error = 0; 10470c1bb4fbSDima Dorfman switch (sopt->sopt_dir) { 10480c1bb4fbSDima Dorfman case SOPT_GET: 10490c1bb4fbSDima Dorfman switch (sopt->sopt_name) { 10500c1bb4fbSDima Dorfman case LOCAL_PEERCRED: 1051e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 10520c1bb4fbSDima Dorfman if (unp->unp_flags & UNP_HAVEPC) 10530d9ce3a1SRobert Watson xu = unp->unp_peercred; 10540c1bb4fbSDima Dorfman else { 10550c1bb4fbSDima Dorfman if (so->so_type == SOCK_STREAM) 10560c1bb4fbSDima Dorfman error = ENOTCONN; 10570c1bb4fbSDima Dorfman else 10580c1bb4fbSDima Dorfman error = EINVAL; 10590c1bb4fbSDima Dorfman } 1060e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 10610d9ce3a1SRobert Watson if (error == 0) 10620d9ce3a1SRobert Watson error = sooptcopyout(sopt, &xu, sizeof(xu)); 10630c1bb4fbSDima Dorfman break; 1064e7c33e29SRobert Watson 10656a2989fdSMatthew N. Dodd case LOCAL_CREDS: 1066a6357845SRobert Watson /* Unlocked read. */ 10676a2989fdSMatthew N. Dodd optval = unp->unp_flags & UNP_WANTCRED ? 1 : 0; 10686a2989fdSMatthew N. Dodd error = sooptcopyout(sopt, &optval, sizeof(optval)); 10696a2989fdSMatthew N. Dodd break; 1070e7c33e29SRobert Watson 10716a2989fdSMatthew N. Dodd case LOCAL_CONNWAIT: 1072a6357845SRobert Watson /* Unlocked read. */ 10736a2989fdSMatthew N. Dodd optval = unp->unp_flags & UNP_CONNWAIT ? 1 : 0; 10746a2989fdSMatthew N. Dodd error = sooptcopyout(sopt, &optval, sizeof(optval)); 10756a2989fdSMatthew N. Dodd break; 1076e7c33e29SRobert Watson 10770c1bb4fbSDima Dorfman default: 10780c1bb4fbSDima Dorfman error = EOPNOTSUPP; 10790c1bb4fbSDima Dorfman break; 10800c1bb4fbSDima Dorfman } 10810c1bb4fbSDima Dorfman break; 1082e7c33e29SRobert Watson 10830c1bb4fbSDima Dorfman case SOPT_SET: 10846a2989fdSMatthew N. Dodd switch (sopt->sopt_name) { 10856a2989fdSMatthew N. Dodd case LOCAL_CREDS: 10866a2989fdSMatthew N. Dodd case LOCAL_CONNWAIT: 10876a2989fdSMatthew N. Dodd error = sooptcopyin(sopt, &optval, sizeof(optval), 10886a2989fdSMatthew N. Dodd sizeof(optval)); 10896a2989fdSMatthew N. Dodd if (error) 10906a2989fdSMatthew N. Dodd break; 10916a2989fdSMatthew N. Dodd 1092e7c33e29SRobert Watson #define OPTSET(bit) do { \ 1093e7c33e29SRobert Watson UNP_PCB_LOCK(unp); \ 10946a2989fdSMatthew N. Dodd if (optval) \ 10956a2989fdSMatthew N. Dodd unp->unp_flags |= bit; \ 10966a2989fdSMatthew N. Dodd else \ 1097e7c33e29SRobert Watson unp->unp_flags &= ~bit; \ 1098e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); \ 1099e7c33e29SRobert Watson } while (0) 11006a2989fdSMatthew N. Dodd 11016a2989fdSMatthew N. Dodd switch (sopt->sopt_name) { 11026a2989fdSMatthew N. Dodd case LOCAL_CREDS: 11036a2989fdSMatthew N. Dodd OPTSET(UNP_WANTCRED); 11046a2989fdSMatthew N. Dodd break; 1105e7c33e29SRobert Watson 11066a2989fdSMatthew N. Dodd case LOCAL_CONNWAIT: 11076a2989fdSMatthew N. Dodd OPTSET(UNP_CONNWAIT); 11086a2989fdSMatthew N. Dodd break; 1109e7c33e29SRobert Watson 11106a2989fdSMatthew N. Dodd default: 11116a2989fdSMatthew N. Dodd break; 11126a2989fdSMatthew N. Dodd } 11136a2989fdSMatthew N. Dodd break; 11146a2989fdSMatthew N. Dodd #undef OPTSET 11156a2989fdSMatthew N. Dodd default: 11166a2989fdSMatthew N. Dodd error = ENOPROTOOPT; 11176a2989fdSMatthew N. Dodd break; 11186a2989fdSMatthew N. Dodd } 1119abb886faSMatthew N. Dodd break; 1120e7c33e29SRobert Watson 11210c1bb4fbSDima Dorfman default: 11220c1bb4fbSDima Dorfman error = EOPNOTSUPP; 11230c1bb4fbSDima Dorfman break; 11240c1bb4fbSDima Dorfman } 11250c1bb4fbSDima Dorfman return (error); 11260c1bb4fbSDima Dorfman } 11270c1bb4fbSDima Dorfman 1128f708ef1bSPoul-Henning Kamp static int 1129892af6b9SRobert Watson unp_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 1130df8bae1dSRodney W. Grimes { 1131892af6b9SRobert Watson struct sockaddr_un *soun = (struct sockaddr_un *)nam; 1132892af6b9SRobert Watson struct vnode *vp; 1133892af6b9SRobert Watson struct socket *so2, *so3; 1134b295bdcdSRobert Watson struct unpcb *unp, *unp2, *unp3; 11359e289446SWojciech A. Koszek int error, len, vfslocked; 1136df8bae1dSRodney W. Grimes struct nameidata nd; 113757bf258eSGarrett Wollman char buf[SOCK_MAXADDRLEN]; 11380d9ce3a1SRobert Watson struct sockaddr *sa; 11390d9ce3a1SRobert Watson 11403dab55bcSRobert Watson UNP_LINK_WLOCK_ASSERT(); 1141df8bae1dSRodney W. Grimes 11424d4b555eSRobert Watson unp = sotounpcb(so); 11434d4b555eSRobert Watson KASSERT(unp != NULL, ("unp_connect: unp == NULL")); 1144e7c33e29SRobert Watson 114557bf258eSGarrett Wollman len = nam->sa_len - offsetof(struct sockaddr_un, sun_path); 114657bf258eSGarrett Wollman if (len <= 0) 1147e5aeaa0cSDag-Erling Smørgrav return (EINVAL); 11487928893dSEd Maste bcopy(soun->sun_path, buf, len); 11497928893dSEd Maste buf[len] = 0; 1150e7c33e29SRobert Watson 1151e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 11524f1f0ef5SRobert Watson if (unp->unp_flags & UNP_CONNECTING) { 1153e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 11544f1f0ef5SRobert Watson return (EALREADY); 11554f1f0ef5SRobert Watson } 11563dab55bcSRobert Watson UNP_LINK_WUNLOCK(); 115705102f04SRobert Watson unp->unp_flags |= UNP_CONNECTING; 1158e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 1159e7c33e29SRobert Watson 11600d9ce3a1SRobert Watson sa = malloc(sizeof(struct sockaddr_un), M_SONAME, M_WAITOK); 11619e289446SWojciech A. Koszek NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | LOCKLEAF, UIO_SYSSPACE, buf, 11629e289446SWojciech A. Koszek td); 1163797f2d22SPoul-Henning Kamp error = namei(&nd); 1164797f2d22SPoul-Henning Kamp if (error) 11650d9ce3a1SRobert Watson vp = NULL; 11660d9ce3a1SRobert Watson else 1167df8bae1dSRodney W. Grimes vp = nd.ni_vp; 11680d9ce3a1SRobert Watson ASSERT_VOP_LOCKED(vp, "unp_connect"); 11699e289446SWojciech A. Koszek vfslocked = NDHASGIANT(&nd); 1170762e6b85SEivind Eklund NDFREE(&nd, NDF_ONLY_PNBUF); 11710d9ce3a1SRobert Watson if (error) 11720d9ce3a1SRobert Watson goto bad; 11730d9ce3a1SRobert Watson 1174df8bae1dSRodney W. Grimes if (vp->v_type != VSOCK) { 1175df8bae1dSRodney W. Grimes error = ENOTSOCK; 1176df8bae1dSRodney W. Grimes goto bad; 1177df8bae1dSRodney W. Grimes } 11786fac927cSRobert Watson #ifdef MAC 117930d239bcSRobert Watson error = mac_vnode_check_open(td->td_ucred, vp, VWRITE | VREAD); 11806fac927cSRobert Watson if (error) 11816fac927cSRobert Watson goto bad; 11826fac927cSRobert Watson #endif 1183a854ed98SJohn Baldwin error = VOP_ACCESS(vp, VWRITE, td->td_ucred, td); 1184797f2d22SPoul-Henning Kamp if (error) 1185df8bae1dSRodney W. Grimes goto bad; 11869e289446SWojciech A. Koszek VFS_UNLOCK_GIANT(vfslocked); 1187e7c33e29SRobert Watson 1188b295bdcdSRobert Watson unp = sotounpcb(so); 11894d4b555eSRobert Watson KASSERT(unp != NULL, ("unp_connect: unp == NULL")); 1190e7c33e29SRobert Watson 1191e7c33e29SRobert Watson /* 11923dab55bcSRobert Watson * Lock linkage lock for two reasons: make sure v_socket is stable, 1193e7c33e29SRobert Watson * and to protect simultaneous locking of multiple pcbs. 1194e7c33e29SRobert Watson */ 11953dab55bcSRobert Watson UNP_LINK_WLOCK(); 1196df8bae1dSRodney W. Grimes so2 = vp->v_socket; 1197fc3fcacfSRobert Watson if (so2 == NULL) { 1198df8bae1dSRodney W. Grimes error = ECONNREFUSED; 11992260c03dSRobert Watson goto bad2; 1200df8bae1dSRodney W. Grimes } 1201df8bae1dSRodney W. Grimes if (so->so_type != so2->so_type) { 1202df8bae1dSRodney W. Grimes error = EPROTOTYPE; 12032260c03dSRobert Watson goto bad2; 1204df8bae1dSRodney W. Grimes } 1205df8bae1dSRodney W. Grimes if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 1206e7c33e29SRobert Watson if (so2->so_options & SO_ACCEPTCONN) { 12070d9ce3a1SRobert Watson so3 = sonewconn(so2, 0); 1208e7c33e29SRobert Watson } else 12090d9ce3a1SRobert Watson so3 = NULL; 12100d9ce3a1SRobert Watson if (so3 == NULL) { 1211df8bae1dSRodney W. Grimes error = ECONNREFUSED; 12120d9ce3a1SRobert Watson goto bad2; 1213df8bae1dSRodney W. Grimes } 12140c1bb4fbSDima Dorfman unp = sotounpcb(so); 1215df8bae1dSRodney W. Grimes unp2 = sotounpcb(so2); 1216df8bae1dSRodney W. Grimes unp3 = sotounpcb(so3); 1217e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 1218e7c33e29SRobert Watson UNP_PCB_LOCK(unp2); 1219e7c33e29SRobert Watson UNP_PCB_LOCK(unp3); 12200d9ce3a1SRobert Watson if (unp2->unp_addr != NULL) { 12210d9ce3a1SRobert Watson bcopy(unp2->unp_addr, sa, unp2->unp_addr->sun_len); 12220d9ce3a1SRobert Watson unp3->unp_addr = (struct sockaddr_un *) sa; 12230d9ce3a1SRobert Watson sa = NULL; 12240d9ce3a1SRobert Watson } 1225b523ec24SRobert Watson 12260c1bb4fbSDima Dorfman /* 12271c381b19SRobert Watson * The connecter's (client's) credentials are copied from its 12281c381b19SRobert Watson * process structure at the time of connect() (which is now). 12290c1bb4fbSDima Dorfman */ 1230a854ed98SJohn Baldwin cru2x(td->td_ucred, &unp3->unp_peercred); 12310c1bb4fbSDima Dorfman unp3->unp_flags |= UNP_HAVEPC; 1232b523ec24SRobert Watson 12330c1bb4fbSDima Dorfman /* 12341c381b19SRobert Watson * The receiver's (server's) credentials are copied from the 12351c381b19SRobert Watson * unp_peercred member of socket on which the former called 1236e7c33e29SRobert Watson * listen(); uipc_listen() cached that process's credentials 12371c381b19SRobert Watson * at that time so we can use them now. 12380c1bb4fbSDima Dorfman */ 12390c1bb4fbSDima Dorfman KASSERT(unp2->unp_flags & UNP_HAVEPCCACHED, 12400c1bb4fbSDima Dorfman ("unp_connect: listener without cached peercred")); 12410c1bb4fbSDima Dorfman memcpy(&unp->unp_peercred, &unp2->unp_peercred, 12420c1bb4fbSDima Dorfman sizeof(unp->unp_peercred)); 12430c1bb4fbSDima Dorfman unp->unp_flags |= UNP_HAVEPC; 1244481f8fe8SMaxim Konovalov if (unp2->unp_flags & UNP_WANTCRED) 1245481f8fe8SMaxim Konovalov unp3->unp_flags |= UNP_WANTCRED; 1246e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp3); 1247e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp2); 1248e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 1249335654d7SRobert Watson #ifdef MAC 1250310e7cebSRobert Watson SOCK_LOCK(so); 125130d239bcSRobert Watson mac_socketpeer_set_from_socket(so, so3); 125230d239bcSRobert Watson mac_socketpeer_set_from_socket(so3, so); 1253310e7cebSRobert Watson SOCK_UNLOCK(so); 1254335654d7SRobert Watson #endif 12550c1bb4fbSDima Dorfman 1256df8bae1dSRodney W. Grimes so2 = so3; 1257df8bae1dSRodney W. Grimes } 1258e7c33e29SRobert Watson unp = sotounpcb(so); 1259e7c33e29SRobert Watson KASSERT(unp != NULL, ("unp_connect: unp == NULL")); 1260e7c33e29SRobert Watson unp2 = sotounpcb(so2); 1261e7c33e29SRobert Watson KASSERT(unp2 != NULL, ("unp_connect: unp2 == NULL")); 1262e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 1263e7c33e29SRobert Watson UNP_PCB_LOCK(unp2); 12646a2989fdSMatthew N. Dodd error = unp_connect2(so, so2, PRU_CONNECT); 1265e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp2); 1266e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 12670d9ce3a1SRobert Watson bad2: 12683dab55bcSRobert Watson UNP_LINK_WUNLOCK(); 12699e289446SWojciech A. Koszek if (vfslocked) 12709e289446SWojciech A. Koszek /* 12719e289446SWojciech A. Koszek * Giant has been previously acquired. This means filesystem 12729e289446SWojciech A. Koszek * isn't MPSAFE. Do it once again. 12739e289446SWojciech A. Koszek */ 12740d9ce3a1SRobert Watson mtx_lock(&Giant); 1275df8bae1dSRodney W. Grimes bad: 12760d9ce3a1SRobert Watson if (vp != NULL) 1277df8bae1dSRodney W. Grimes vput(vp); 12789e289446SWojciech A. Koszek VFS_UNLOCK_GIANT(vfslocked); 12790d9ce3a1SRobert Watson free(sa, M_SONAME); 12803dab55bcSRobert Watson UNP_LINK_WLOCK(); 1281e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 12824f1f0ef5SRobert Watson unp->unp_flags &= ~UNP_CONNECTING; 1283e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 1284df8bae1dSRodney W. Grimes return (error); 1285df8bae1dSRodney W. Grimes } 1286df8bae1dSRodney W. Grimes 1287db48c0d2SRobert Watson static int 12886a2989fdSMatthew N. Dodd unp_connect2(struct socket *so, struct socket *so2, int req) 1289df8bae1dSRodney W. Grimes { 1290e7c33e29SRobert Watson struct unpcb *unp; 1291892af6b9SRobert Watson struct unpcb *unp2; 1292df8bae1dSRodney W. Grimes 1293e7c33e29SRobert Watson unp = sotounpcb(so); 1294e7c33e29SRobert Watson KASSERT(unp != NULL, ("unp_connect2: unp == NULL")); 1295e7c33e29SRobert Watson unp2 = sotounpcb(so2); 1296e7c33e29SRobert Watson KASSERT(unp2 != NULL, ("unp_connect2: unp2 == NULL")); 1297e7c33e29SRobert Watson 12983dab55bcSRobert Watson UNP_LINK_WLOCK_ASSERT(); 1299e7c33e29SRobert Watson UNP_PCB_LOCK_ASSERT(unp); 1300e7c33e29SRobert Watson UNP_PCB_LOCK_ASSERT(unp2); 13010d9ce3a1SRobert Watson 1302df8bae1dSRodney W. Grimes if (so2->so_type != so->so_type) 1303df8bae1dSRodney W. Grimes return (EPROTOTYPE); 1304df8bae1dSRodney W. Grimes unp->unp_conn = unp2; 1305e7c33e29SRobert Watson 1306df8bae1dSRodney W. Grimes switch (so->so_type) { 1307df8bae1dSRodney W. Grimes case SOCK_DGRAM: 130898271db4SGarrett Wollman LIST_INSERT_HEAD(&unp2->unp_refs, unp, unp_reflink); 1309df8bae1dSRodney W. Grimes soisconnected(so); 1310df8bae1dSRodney W. Grimes break; 1311df8bae1dSRodney W. Grimes 1312df8bae1dSRodney W. Grimes case SOCK_STREAM: 1313df8bae1dSRodney W. Grimes unp2->unp_conn = unp; 13146a2989fdSMatthew N. Dodd if (req == PRU_CONNECT && 13156a2989fdSMatthew N. Dodd ((unp->unp_flags | unp2->unp_flags) & UNP_CONNWAIT)) 13166a2989fdSMatthew N. Dodd soisconnecting(so); 13176a2989fdSMatthew N. Dodd else 1318df8bae1dSRodney W. Grimes soisconnected(so); 1319df8bae1dSRodney W. Grimes soisconnected(so2); 1320df8bae1dSRodney W. Grimes break; 1321df8bae1dSRodney W. Grimes 1322df8bae1dSRodney W. Grimes default: 1323df8bae1dSRodney W. Grimes panic("unp_connect2"); 1324df8bae1dSRodney W. Grimes } 1325df8bae1dSRodney W. Grimes return (0); 1326df8bae1dSRodney W. Grimes } 1327df8bae1dSRodney W. Grimes 1328f708ef1bSPoul-Henning Kamp static void 1329e7c33e29SRobert Watson unp_disconnect(struct unpcb *unp, struct unpcb *unp2) 1330df8bae1dSRodney W. Grimes { 13311b2e3b4bSRobert Watson struct socket *so; 1332df8bae1dSRodney W. Grimes 1333e7c33e29SRobert Watson KASSERT(unp2 != NULL, ("unp_disconnect: unp2 == NULL")); 13340d9ce3a1SRobert Watson 13353dab55bcSRobert Watson UNP_LINK_WLOCK_ASSERT(); 1336e7c33e29SRobert Watson UNP_PCB_LOCK_ASSERT(unp); 1337e7c33e29SRobert Watson UNP_PCB_LOCK_ASSERT(unp2); 1338e7c33e29SRobert Watson 1339fc3fcacfSRobert Watson unp->unp_conn = NULL; 1340df8bae1dSRodney W. Grimes switch (unp->unp_socket->so_type) { 1341df8bae1dSRodney W. Grimes case SOCK_DGRAM: 134298271db4SGarrett Wollman LIST_REMOVE(unp, unp_reflink); 13431b2e3b4bSRobert Watson so = unp->unp_socket; 13441b2e3b4bSRobert Watson SOCK_LOCK(so); 13451b2e3b4bSRobert Watson so->so_state &= ~SS_ISCONNECTED; 13461b2e3b4bSRobert Watson SOCK_UNLOCK(so); 1347df8bae1dSRodney W. Grimes break; 1348df8bae1dSRodney W. Grimes 1349df8bae1dSRodney W. Grimes case SOCK_STREAM: 1350df8bae1dSRodney W. Grimes soisdisconnected(unp->unp_socket); 1351fc3fcacfSRobert Watson unp2->unp_conn = NULL; 1352df8bae1dSRodney W. Grimes soisdisconnected(unp2->unp_socket); 1353df8bae1dSRodney W. Grimes break; 1354df8bae1dSRodney W. Grimes } 1355df8bae1dSRodney W. Grimes } 1356df8bae1dSRodney W. Grimes 13570d9ce3a1SRobert Watson /* 1358d7924b70SRobert Watson * unp_pcblist() walks the global list of struct unpcb's to generate a 1359d7924b70SRobert Watson * pointer list, bumping the refcount on each unpcb. It then copies them out 1360d7924b70SRobert Watson * sequentially, validating the generation number on each to see if it has 1361d7924b70SRobert Watson * been detached. All of this is necessary because copyout() may sleep on 1362d7924b70SRobert Watson * disk I/O. 13630d9ce3a1SRobert Watson */ 136498271db4SGarrett Wollman static int 136582d9ae4eSPoul-Henning Kamp unp_pcblist(SYSCTL_HANDLER_ARGS) 136698271db4SGarrett Wollman { 1367f5ef029eSPoul-Henning Kamp int error, i, n; 13689ae328fcSJohn Baldwin int freeunp; 136998271db4SGarrett Wollman struct unpcb *unp, **unp_list; 137098271db4SGarrett Wollman unp_gen_t gencnt; 13718f364875SJulian Elischer struct xunpgen *xug; 137298271db4SGarrett Wollman struct unp_head *head; 13738f364875SJulian Elischer struct xunpcb *xu; 137498271db4SGarrett Wollman 1375a23d65bfSBruce Evans head = ((intptr_t)arg1 == SOCK_DGRAM ? &unp_dhead : &unp_shead); 137698271db4SGarrett Wollman 137798271db4SGarrett Wollman /* 137898271db4SGarrett Wollman * The process of preparing the PCB list is too time-consuming and 137998271db4SGarrett Wollman * resource-intensive to repeat twice on every request. 138098271db4SGarrett Wollman */ 1381fc3fcacfSRobert Watson if (req->oldptr == NULL) { 138298271db4SGarrett Wollman n = unp_count; 13838f364875SJulian Elischer req->oldidx = 2 * (sizeof *xug) 138498271db4SGarrett Wollman + (n + n/8) * sizeof(struct xunpcb); 1385e5aeaa0cSDag-Erling Smørgrav return (0); 138698271db4SGarrett Wollman } 138798271db4SGarrett Wollman 1388fc3fcacfSRobert Watson if (req->newptr != NULL) 1389e5aeaa0cSDag-Erling Smørgrav return (EPERM); 139098271db4SGarrett Wollman 139198271db4SGarrett Wollman /* 139298271db4SGarrett Wollman * OK, now we're committed to doing something. 139398271db4SGarrett Wollman */ 1394a163d034SWarner Losh xug = malloc(sizeof(*xug), M_TEMP, M_WAITOK); 13953dab55bcSRobert Watson UNP_LIST_LOCK(); 139698271db4SGarrett Wollman gencnt = unp_gencnt; 139798271db4SGarrett Wollman n = unp_count; 13983dab55bcSRobert Watson UNP_LIST_UNLOCK(); 139998271db4SGarrett Wollman 14008f364875SJulian Elischer xug->xug_len = sizeof *xug; 14018f364875SJulian Elischer xug->xug_count = n; 14028f364875SJulian Elischer xug->xug_gen = gencnt; 14038f364875SJulian Elischer xug->xug_sogen = so_gencnt; 14048f364875SJulian Elischer error = SYSCTL_OUT(req, xug, sizeof *xug); 14058f364875SJulian Elischer if (error) { 14068f364875SJulian Elischer free(xug, M_TEMP); 1407e5aeaa0cSDag-Erling Smørgrav return (error); 14088f364875SJulian Elischer } 140998271db4SGarrett Wollman 1410a163d034SWarner Losh unp_list = malloc(n * sizeof *unp_list, M_TEMP, M_WAITOK); 141198271db4SGarrett Wollman 14123dab55bcSRobert Watson UNP_LIST_LOCK(); 14132e3c8fcbSPoul-Henning Kamp for (unp = LIST_FIRST(head), i = 0; unp && i < n; 14142e3c8fcbSPoul-Henning Kamp unp = LIST_NEXT(unp, unp_link)) { 1415e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 14168a7d8cc6SRobert Watson if (unp->unp_gencnt <= gencnt) { 1417a854ed98SJohn Baldwin if (cr_cansee(req->td->td_ucred, 1418e7c33e29SRobert Watson unp->unp_socket->so_cred)) { 1419e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 14204787fd37SPaul Saab continue; 1421e7c33e29SRobert Watson } 142298271db4SGarrett Wollman unp_list[i++] = unp; 14239ae328fcSJohn Baldwin unp->unp_refcount++; 142498271db4SGarrett Wollman } 1425e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 14264787fd37SPaul Saab } 14273dab55bcSRobert Watson UNP_LIST_UNLOCK(); 14281c381b19SRobert Watson n = i; /* In case we lost some during malloc. */ 142998271db4SGarrett Wollman 143098271db4SGarrett Wollman error = 0; 1431fe2eee82SColin Percival xu = malloc(sizeof(*xu), M_TEMP, M_WAITOK | M_ZERO); 143298271db4SGarrett Wollman for (i = 0; i < n; i++) { 143398271db4SGarrett Wollman unp = unp_list[i]; 1434e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 14359ae328fcSJohn Baldwin unp->unp_refcount--; 14369ae328fcSJohn Baldwin if (unp->unp_refcount != 0 && unp->unp_gencnt <= gencnt) { 14378f364875SJulian Elischer xu->xu_len = sizeof *xu; 14388f364875SJulian Elischer xu->xu_unpp = unp; 143998271db4SGarrett Wollman /* 144098271db4SGarrett Wollman * XXX - need more locking here to protect against 144198271db4SGarrett Wollman * connect/disconnect races for SMP. 144298271db4SGarrett Wollman */ 1443fc3fcacfSRobert Watson if (unp->unp_addr != NULL) 14448f364875SJulian Elischer bcopy(unp->unp_addr, &xu->xu_addr, 144598271db4SGarrett Wollman unp->unp_addr->sun_len); 1446fc3fcacfSRobert Watson if (unp->unp_conn != NULL && 1447fc3fcacfSRobert Watson unp->unp_conn->unp_addr != NULL) 144898271db4SGarrett Wollman bcopy(unp->unp_conn->unp_addr, 14498f364875SJulian Elischer &xu->xu_caddr, 145098271db4SGarrett Wollman unp->unp_conn->unp_addr->sun_len); 14518f364875SJulian Elischer bcopy(unp, &xu->xu_unp, sizeof *unp); 14528f364875SJulian Elischer sotoxsocket(unp->unp_socket, &xu->xu_socket); 1453e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 14548f364875SJulian Elischer error = SYSCTL_OUT(req, xu, sizeof *xu); 14559ae328fcSJohn Baldwin } else { 14569ae328fcSJohn Baldwin freeunp = (unp->unp_refcount == 0); 1457e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 1458e7c33e29SRobert Watson if (freeunp) { 1459e7c33e29SRobert Watson UNP_PCB_LOCK_DESTROY(unp); 14609ae328fcSJohn Baldwin uma_zfree(unp_zone, unp); 146198271db4SGarrett Wollman } 146298271db4SGarrett Wollman } 1463e7c33e29SRobert Watson } 14648f364875SJulian Elischer free(xu, M_TEMP); 146598271db4SGarrett Wollman if (!error) { 146698271db4SGarrett Wollman /* 14671c381b19SRobert Watson * Give the user an updated idea of our state. If the 14681c381b19SRobert Watson * generation differs from what we told her before, she knows 14691c381b19SRobert Watson * that something happened while we were processing this 14701c381b19SRobert Watson * request, and it might be necessary to retry. 147198271db4SGarrett Wollman */ 14728f364875SJulian Elischer xug->xug_gen = unp_gencnt; 14738f364875SJulian Elischer xug->xug_sogen = so_gencnt; 14748f364875SJulian Elischer xug->xug_count = unp_count; 14758f364875SJulian Elischer error = SYSCTL_OUT(req, xug, sizeof *xug); 147698271db4SGarrett Wollman } 147798271db4SGarrett Wollman free(unp_list, M_TEMP); 14788f364875SJulian Elischer free(xug, M_TEMP); 1479e5aeaa0cSDag-Erling Smørgrav return (error); 148098271db4SGarrett Wollman } 148198271db4SGarrett Wollman 148298271db4SGarrett Wollman SYSCTL_PROC(_net_local_dgram, OID_AUTO, pcblist, CTLFLAG_RD, 148398271db4SGarrett Wollman (caddr_t)(long)SOCK_DGRAM, 0, unp_pcblist, "S,xunpcb", 148498271db4SGarrett Wollman "List of active local datagram sockets"); 148598271db4SGarrett Wollman SYSCTL_PROC(_net_local_stream, OID_AUTO, pcblist, CTLFLAG_RD, 148698271db4SGarrett Wollman (caddr_t)(long)SOCK_STREAM, 0, unp_pcblist, "S,xunpcb", 148798271db4SGarrett Wollman "List of active local stream sockets"); 148898271db4SGarrett Wollman 1489f708ef1bSPoul-Henning Kamp static void 1490892af6b9SRobert Watson unp_shutdown(struct unpcb *unp) 1491df8bae1dSRodney W. Grimes { 1492e7c33e29SRobert Watson struct unpcb *unp2; 1493df8bae1dSRodney W. Grimes struct socket *so; 1494df8bae1dSRodney W. Grimes 14953dab55bcSRobert Watson UNP_LINK_WLOCK_ASSERT(); 1496e7c33e29SRobert Watson UNP_PCB_LOCK_ASSERT(unp); 14970d9ce3a1SRobert Watson 1498e7c33e29SRobert Watson unp2 = unp->unp_conn; 1499e7c33e29SRobert Watson if (unp->unp_socket->so_type == SOCK_STREAM && unp2 != NULL) { 1500e7c33e29SRobert Watson so = unp2->unp_socket; 1501e7c33e29SRobert Watson if (so != NULL) 1502df8bae1dSRodney W. Grimes socantrcvmore(so); 1503df8bae1dSRodney W. Grimes } 1504e7c33e29SRobert Watson } 1505df8bae1dSRodney W. Grimes 1506f708ef1bSPoul-Henning Kamp static void 1507892af6b9SRobert Watson unp_drop(struct unpcb *unp, int errno) 1508df8bae1dSRodney W. Grimes { 1509df8bae1dSRodney W. Grimes struct socket *so = unp->unp_socket; 1510e7c33e29SRobert Watson struct unpcb *unp2; 1511df8bae1dSRodney W. Grimes 15123dab55bcSRobert Watson UNP_LINK_WLOCK_ASSERT(); 1513e7c33e29SRobert Watson UNP_PCB_LOCK_ASSERT(unp); 15140d9ce3a1SRobert Watson 1515df8bae1dSRodney W. Grimes so->so_error = errno; 1516e7c33e29SRobert Watson unp2 = unp->unp_conn; 1517e7c33e29SRobert Watson if (unp2 == NULL) 1518e7c33e29SRobert Watson return; 1519e7c33e29SRobert Watson UNP_PCB_LOCK(unp2); 1520e7c33e29SRobert Watson unp_disconnect(unp, unp2); 1521e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp2); 1522df8bae1dSRodney W. Grimes } 1523df8bae1dSRodney W. Grimes 15242bc21ed9SDavid Malone static void 1525892af6b9SRobert Watson unp_freerights(struct file **rp, int fdcount) 1526df8bae1dSRodney W. Grimes { 15272bc21ed9SDavid Malone int i; 15282bc21ed9SDavid Malone struct file *fp; 1529df8bae1dSRodney W. Grimes 15302bc21ed9SDavid Malone for (i = 0; i < fdcount; i++) { 1531e7c33e29SRobert Watson fp = *rp; 1532e7c33e29SRobert Watson *rp++ = NULL; 15338692c025SYoshinobu Inoue unp_discard(fp); 1534df8bae1dSRodney W. Grimes } 15352bc21ed9SDavid Malone } 15362bc21ed9SDavid Malone 15370b36cd25SRobert Watson static int 1538892af6b9SRobert Watson unp_externalize(struct mbuf *control, struct mbuf **controlp) 15392bc21ed9SDavid Malone { 15402bc21ed9SDavid Malone struct thread *td = curthread; /* XXX */ 15412bc21ed9SDavid Malone struct cmsghdr *cm = mtod(control, struct cmsghdr *); 15422bc21ed9SDavid Malone int i; 15432bc21ed9SDavid Malone int *fdp; 15442bc21ed9SDavid Malone struct file **rp; 15452bc21ed9SDavid Malone struct file *fp; 15462bc21ed9SDavid Malone void *data; 15472bc21ed9SDavid Malone socklen_t clen = control->m_len, datalen; 15482bc21ed9SDavid Malone int error, newfds; 15492bc21ed9SDavid Malone int f; 15502bc21ed9SDavid Malone u_int newlen; 15512bc21ed9SDavid Malone 15523dab55bcSRobert Watson UNP_LINK_UNLOCK_ASSERT(); 15534c5bc1caSRobert Watson 15542bc21ed9SDavid Malone error = 0; 15552bc21ed9SDavid Malone if (controlp != NULL) /* controlp == NULL => free control messages */ 15562bc21ed9SDavid Malone *controlp = NULL; 15572bc21ed9SDavid Malone while (cm != NULL) { 15582bc21ed9SDavid Malone if (sizeof(*cm) > clen || cm->cmsg_len > clen) { 15592bc21ed9SDavid Malone error = EINVAL; 15602bc21ed9SDavid Malone break; 15612bc21ed9SDavid Malone } 15622bc21ed9SDavid Malone data = CMSG_DATA(cm); 15632bc21ed9SDavid Malone datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data; 15642bc21ed9SDavid Malone if (cm->cmsg_level == SOL_SOCKET 15652bc21ed9SDavid Malone && cm->cmsg_type == SCM_RIGHTS) { 15662bc21ed9SDavid Malone newfds = datalen / sizeof(struct file *); 15672bc21ed9SDavid Malone rp = data; 15682bc21ed9SDavid Malone 1569e2f9a08bSOlivier Houchard /* If we're not outputting the descriptors free them. */ 15702bc21ed9SDavid Malone if (error || controlp == NULL) { 15712bc21ed9SDavid Malone unp_freerights(rp, newfds); 15722bc21ed9SDavid Malone goto next; 15732bc21ed9SDavid Malone } 15745e3f7694SRobert Watson FILEDESC_XLOCK(td->td_proc->p_fd); 15752bc21ed9SDavid Malone /* if the new FD's will not fit free them. */ 15762bc21ed9SDavid Malone if (!fdavail(td, newfds)) { 15775e3f7694SRobert Watson FILEDESC_XUNLOCK(td->td_proc->p_fd); 15782bc21ed9SDavid Malone error = EMSGSIZE; 15792bc21ed9SDavid Malone unp_freerights(rp, newfds); 15802bc21ed9SDavid Malone goto next; 1581df8bae1dSRodney W. Grimes } 158260a5ef26SRobert Watson 1583ed5b7817SJulian Elischer /* 15841c381b19SRobert Watson * Now change each pointer to an fd in the global 15851c381b19SRobert Watson * table to an integer that is the index to the local 15861c381b19SRobert Watson * fd table entry that we set up to point to the 15871c381b19SRobert Watson * global one we are transferring. 1588ed5b7817SJulian Elischer */ 15892bc21ed9SDavid Malone newlen = newfds * sizeof(int); 15902bc21ed9SDavid Malone *controlp = sbcreatecontrol(NULL, newlen, 15912bc21ed9SDavid Malone SCM_RIGHTS, SOL_SOCKET); 15922bc21ed9SDavid Malone if (*controlp == NULL) { 15935e3f7694SRobert Watson FILEDESC_XUNLOCK(td->td_proc->p_fd); 15942bc21ed9SDavid Malone error = E2BIG; 15952bc21ed9SDavid Malone unp_freerights(rp, newfds); 15962bc21ed9SDavid Malone goto next; 15972bc21ed9SDavid Malone } 15982bc21ed9SDavid Malone 15992bc21ed9SDavid Malone fdp = (int *) 16002bc21ed9SDavid Malone CMSG_DATA(mtod(*controlp, struct cmsghdr *)); 1601df8bae1dSRodney W. Grimes for (i = 0; i < newfds; i++) { 1602a6d4491cSDag-Erling Smørgrav if (fdalloc(td, 0, &f)) 16032bc21ed9SDavid Malone panic("unp_externalize fdalloc failed"); 16048692c025SYoshinobu Inoue fp = *rp++; 1605b40ce416SJulian Elischer td->td_proc->p_fd->fd_ofiles[f] = fp; 1606397c19d1SJeff Roberson unp_externalize_fp(fp); 16078692c025SYoshinobu Inoue *fdp++ = f; 1608df8bae1dSRodney W. Grimes } 16095e3f7694SRobert Watson FILEDESC_XUNLOCK(td->td_proc->p_fd); 16101c381b19SRobert Watson } else { 16111c381b19SRobert Watson /* We can just copy anything else across. */ 16122bc21ed9SDavid Malone if (error || controlp == NULL) 16132bc21ed9SDavid Malone goto next; 16142bc21ed9SDavid Malone *controlp = sbcreatecontrol(NULL, datalen, 16152bc21ed9SDavid Malone cm->cmsg_type, cm->cmsg_level); 16162bc21ed9SDavid Malone if (*controlp == NULL) { 16172bc21ed9SDavid Malone error = ENOBUFS; 16182bc21ed9SDavid Malone goto next; 16192bc21ed9SDavid Malone } 16202bc21ed9SDavid Malone bcopy(data, 16212bc21ed9SDavid Malone CMSG_DATA(mtod(*controlp, struct cmsghdr *)), 16222bc21ed9SDavid Malone datalen); 16232bc21ed9SDavid Malone } 16242bc21ed9SDavid Malone controlp = &(*controlp)->m_next; 16252bc21ed9SDavid Malone 16262bc21ed9SDavid Malone next: 16272bc21ed9SDavid Malone if (CMSG_SPACE(datalen) < clen) { 16282bc21ed9SDavid Malone clen -= CMSG_SPACE(datalen); 16292bc21ed9SDavid Malone cm = (struct cmsghdr *) 16302bc21ed9SDavid Malone ((caddr_t)cm + CMSG_SPACE(datalen)); 16318692c025SYoshinobu Inoue } else { 16322bc21ed9SDavid Malone clen = 0; 16332bc21ed9SDavid Malone cm = NULL; 16348692c025SYoshinobu Inoue } 16358692c025SYoshinobu Inoue } 16368692c025SYoshinobu Inoue 16372bc21ed9SDavid Malone m_freem(control); 16382bc21ed9SDavid Malone return (error); 1639df8bae1dSRodney W. Grimes } 1640df8bae1dSRodney W. Grimes 16414f590175SPaul Saab static void 16424f590175SPaul Saab unp_zone_change(void *tag) 16434f590175SPaul Saab { 16444f590175SPaul Saab 16454f590175SPaul Saab uma_zone_set_max(unp_zone, maxsockets); 16464f590175SPaul Saab } 16474f590175SPaul Saab 16480b36cd25SRobert Watson static void 164998271db4SGarrett Wollman unp_init(void) 165098271db4SGarrett Wollman { 16511c381b19SRobert Watson 16529e9d298aSJeff Roberson unp_zone = uma_zcreate("unpcb", sizeof(struct unpcb), NULL, NULL, 16539ae328fcSJohn Baldwin NULL, NULL, UMA_ALIGN_PTR, 0); 1654fc3fcacfSRobert Watson if (unp_zone == NULL) 165598271db4SGarrett Wollman panic("unp_init"); 16564f590175SPaul Saab uma_zone_set_max(unp_zone, maxsockets); 16574f590175SPaul Saab EVENTHANDLER_REGISTER(maxsockets_change, unp_zone_change, 16584f590175SPaul Saab NULL, EVENTHANDLER_PRI_ANY); 165998271db4SGarrett Wollman LIST_INIT(&unp_dhead); 166098271db4SGarrett Wollman LIST_INIT(&unp_shead); 1661a0ec558aSRobert Watson TASK_INIT(&unp_gc_task, 0, unp_gc, NULL); 16623dab55bcSRobert Watson UNP_LINK_LOCK_INIT(); 16633dab55bcSRobert Watson UNP_LIST_LOCK_INIT(); 166498271db4SGarrett Wollman } 166598271db4SGarrett Wollman 1666f708ef1bSPoul-Henning Kamp static int 1667892af6b9SRobert Watson unp_internalize(struct mbuf **controlp, struct thread *td) 1668df8bae1dSRodney W. Grimes { 16692bc21ed9SDavid Malone struct mbuf *control = *controlp; 1670b40ce416SJulian Elischer struct proc *p = td->td_proc; 16718692c025SYoshinobu Inoue struct filedesc *fdescp = p->p_fd; 16722bc21ed9SDavid Malone struct cmsghdr *cm = mtod(control, struct cmsghdr *); 16732bc21ed9SDavid Malone struct cmsgcred *cmcred; 16742bc21ed9SDavid Malone struct file **rp; 16752bc21ed9SDavid Malone struct file *fp; 16762bc21ed9SDavid Malone struct timeval *tv; 16772bc21ed9SDavid Malone int i, fd, *fdp; 16782bc21ed9SDavid Malone void *data; 16792bc21ed9SDavid Malone socklen_t clen = control->m_len, datalen; 16802bc21ed9SDavid Malone int error, oldfds; 16818692c025SYoshinobu Inoue u_int newlen; 1682df8bae1dSRodney W. Grimes 16833dab55bcSRobert Watson UNP_LINK_UNLOCK_ASSERT(); 16844c5bc1caSRobert Watson 16852bc21ed9SDavid Malone error = 0; 16862bc21ed9SDavid Malone *controlp = NULL; 16872bc21ed9SDavid Malone while (cm != NULL) { 16882bc21ed9SDavid Malone if (sizeof(*cm) > clen || cm->cmsg_level != SOL_SOCKET 16892bc21ed9SDavid Malone || cm->cmsg_len > clen) { 16902bc21ed9SDavid Malone error = EINVAL; 16912bc21ed9SDavid Malone goto out; 16922bc21ed9SDavid Malone } 16932bc21ed9SDavid Malone data = CMSG_DATA(cm); 16942bc21ed9SDavid Malone datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data; 16952bc21ed9SDavid Malone 16962bc21ed9SDavid Malone switch (cm->cmsg_type) { 16970b788fa1SBill Paul /* 16980b788fa1SBill Paul * Fill in credential information. 16990b788fa1SBill Paul */ 17002bc21ed9SDavid Malone case SCM_CREDS: 17012bc21ed9SDavid Malone *controlp = sbcreatecontrol(NULL, sizeof(*cmcred), 17022bc21ed9SDavid Malone SCM_CREDS, SOL_SOCKET); 17032bc21ed9SDavid Malone if (*controlp == NULL) { 17042bc21ed9SDavid Malone error = ENOBUFS; 17052bc21ed9SDavid Malone goto out; 17062bc21ed9SDavid Malone } 17072bc21ed9SDavid Malone cmcred = (struct cmsgcred *) 17082bc21ed9SDavid Malone CMSG_DATA(mtod(*controlp, struct cmsghdr *)); 17090b788fa1SBill Paul cmcred->cmcred_pid = p->p_pid; 1710a854ed98SJohn Baldwin cmcred->cmcred_uid = td->td_ucred->cr_ruid; 1711a854ed98SJohn Baldwin cmcred->cmcred_gid = td->td_ucred->cr_rgid; 1712a854ed98SJohn Baldwin cmcred->cmcred_euid = td->td_ucred->cr_uid; 1713a854ed98SJohn Baldwin cmcred->cmcred_ngroups = MIN(td->td_ucred->cr_ngroups, 17140b788fa1SBill Paul CMGROUP_MAX); 17150b788fa1SBill Paul for (i = 0; i < cmcred->cmcred_ngroups; i++) 17162bc21ed9SDavid Malone cmcred->cmcred_groups[i] = 1717a854ed98SJohn Baldwin td->td_ucred->cr_groups[i]; 17182bc21ed9SDavid Malone break; 17190b788fa1SBill Paul 17202bc21ed9SDavid Malone case SCM_RIGHTS: 17212bc21ed9SDavid Malone oldfds = datalen / sizeof (int); 1722ed5b7817SJulian Elischer /* 17231c381b19SRobert Watson * Check that all the FDs passed in refer to legal 17241c381b19SRobert Watson * files. If not, reject the entire operation. 1725ed5b7817SJulian Elischer */ 17262bc21ed9SDavid Malone fdp = data; 17275e3f7694SRobert Watson FILEDESC_SLOCK(fdescp); 1728df8bae1dSRodney W. Grimes for (i = 0; i < oldfds; i++) { 17298692c025SYoshinobu Inoue fd = *fdp++; 17308692c025SYoshinobu Inoue if ((unsigned)fd >= fdescp->fd_nfiles || 17312bc21ed9SDavid Malone fdescp->fd_ofiles[fd] == NULL) { 17325e3f7694SRobert Watson FILEDESC_SUNLOCK(fdescp); 17332bc21ed9SDavid Malone error = EBADF; 17342bc21ed9SDavid Malone goto out; 17352bc21ed9SDavid Malone } 1736e7d6662fSAlfred Perlstein fp = fdescp->fd_ofiles[fd]; 1737e7d6662fSAlfred Perlstein if (!(fp->f_ops->fo_flags & DFLAG_PASSABLE)) { 17385e3f7694SRobert Watson FILEDESC_SUNLOCK(fdescp); 1739e7d6662fSAlfred Perlstein error = EOPNOTSUPP; 1740e7d6662fSAlfred Perlstein goto out; 1741e7d6662fSAlfred Perlstein } 1742e7d6662fSAlfred Perlstein 1743df8bae1dSRodney W. Grimes } 17445e3f7694SRobert Watson 1745ed5b7817SJulian Elischer /* 17460b36cd25SRobert Watson * Now replace the integer FDs with pointers to the 17470b36cd25SRobert Watson * associated global file table entry.. 1748ed5b7817SJulian Elischer */ 17492bc21ed9SDavid Malone newlen = oldfds * sizeof(struct file *); 17502bc21ed9SDavid Malone *controlp = sbcreatecontrol(NULL, newlen, 17512bc21ed9SDavid Malone SCM_RIGHTS, SOL_SOCKET); 17522bc21ed9SDavid Malone if (*controlp == NULL) { 17535e3f7694SRobert Watson FILEDESC_SUNLOCK(fdescp); 17542bc21ed9SDavid Malone error = E2BIG; 17552bc21ed9SDavid Malone goto out; 17568692c025SYoshinobu Inoue } 17572bc21ed9SDavid Malone fdp = data; 17582bc21ed9SDavid Malone rp = (struct file **) 17592bc21ed9SDavid Malone CMSG_DATA(mtod(*controlp, struct cmsghdr *)); 17608692c025SYoshinobu Inoue for (i = 0; i < oldfds; i++) { 17618692c025SYoshinobu Inoue fp = fdescp->fd_ofiles[*fdp++]; 1762df8bae1dSRodney W. Grimes *rp++ = fp; 1763397c19d1SJeff Roberson unp_internalize_fp(fp); 1764df8bae1dSRodney W. Grimes } 17655e3f7694SRobert Watson FILEDESC_SUNLOCK(fdescp); 17662bc21ed9SDavid Malone break; 17672bc21ed9SDavid Malone 17682bc21ed9SDavid Malone case SCM_TIMESTAMP: 17692bc21ed9SDavid Malone *controlp = sbcreatecontrol(NULL, sizeof(*tv), 17702bc21ed9SDavid Malone SCM_TIMESTAMP, SOL_SOCKET); 17712bc21ed9SDavid Malone if (*controlp == NULL) { 17722bc21ed9SDavid Malone error = ENOBUFS; 17732bc21ed9SDavid Malone goto out; 17748692c025SYoshinobu Inoue } 17752bc21ed9SDavid Malone tv = (struct timeval *) 17762bc21ed9SDavid Malone CMSG_DATA(mtod(*controlp, struct cmsghdr *)); 17772bc21ed9SDavid Malone microtime(tv); 17782bc21ed9SDavid Malone break; 17792bc21ed9SDavid Malone 17802bc21ed9SDavid Malone default: 17812bc21ed9SDavid Malone error = EINVAL; 17822bc21ed9SDavid Malone goto out; 17832bc21ed9SDavid Malone } 17842bc21ed9SDavid Malone 17852bc21ed9SDavid Malone controlp = &(*controlp)->m_next; 17862bc21ed9SDavid Malone if (CMSG_SPACE(datalen) < clen) { 17872bc21ed9SDavid Malone clen -= CMSG_SPACE(datalen); 17882bc21ed9SDavid Malone cm = (struct cmsghdr *) 17892bc21ed9SDavid Malone ((caddr_t)cm + CMSG_SPACE(datalen)); 17902bc21ed9SDavid Malone } else { 17912bc21ed9SDavid Malone clen = 0; 17922bc21ed9SDavid Malone cm = NULL; 17932bc21ed9SDavid Malone } 17942bc21ed9SDavid Malone } 17952bc21ed9SDavid Malone 17962bc21ed9SDavid Malone out: 17972bc21ed9SDavid Malone m_freem(control); 17982bc21ed9SDavid Malone return (error); 1799df8bae1dSRodney W. Grimes } 1800df8bae1dSRodney W. Grimes 18015b950deaSRobert Watson static struct mbuf * 18026a2989fdSMatthew N. Dodd unp_addsockcred(struct thread *td, struct mbuf *control) 18036a2989fdSMatthew N. Dodd { 180470df31f4SMaxim Konovalov struct mbuf *m, *n, *n_prev; 18056a2989fdSMatthew N. Dodd struct sockcred *sc; 180670df31f4SMaxim Konovalov const struct cmsghdr *cm; 18076a2989fdSMatthew N. Dodd int ngroups; 18086a2989fdSMatthew N. Dodd int i; 18096a2989fdSMatthew N. Dodd 18106a2989fdSMatthew N. Dodd ngroups = MIN(td->td_ucred->cr_ngroups, CMGROUP_MAX); 18116a2989fdSMatthew N. Dodd m = sbcreatecontrol(NULL, SOCKCREDSIZE(ngroups), SCM_CREDS, SOL_SOCKET); 18126a2989fdSMatthew N. Dodd if (m == NULL) 18136a2989fdSMatthew N. Dodd return (control); 18146a2989fdSMatthew N. Dodd 18156a2989fdSMatthew N. Dodd sc = (struct sockcred *) CMSG_DATA(mtod(m, struct cmsghdr *)); 18166a2989fdSMatthew N. Dodd sc->sc_uid = td->td_ucred->cr_ruid; 18176a2989fdSMatthew N. Dodd sc->sc_euid = td->td_ucred->cr_uid; 18186a2989fdSMatthew N. Dodd sc->sc_gid = td->td_ucred->cr_rgid; 18196a2989fdSMatthew N. Dodd sc->sc_egid = td->td_ucred->cr_gid; 18206a2989fdSMatthew N. Dodd sc->sc_ngroups = ngroups; 18216a2989fdSMatthew N. Dodd for (i = 0; i < sc->sc_ngroups; i++) 18226a2989fdSMatthew N. Dodd sc->sc_groups[i] = td->td_ucred->cr_groups[i]; 18236a2989fdSMatthew N. Dodd 18246a2989fdSMatthew N. Dodd /* 18251c381b19SRobert Watson * Unlink SCM_CREDS control messages (struct cmsgcred), since just 18261c381b19SRobert Watson * created SCM_CREDS control message (struct sockcred) has another 18271c381b19SRobert Watson * format. 18286a2989fdSMatthew N. Dodd */ 182970df31f4SMaxim Konovalov if (control != NULL) 183070df31f4SMaxim Konovalov for (n = control, n_prev = NULL; n != NULL;) { 183170df31f4SMaxim Konovalov cm = mtod(n, struct cmsghdr *); 183270df31f4SMaxim Konovalov if (cm->cmsg_level == SOL_SOCKET && 183370df31f4SMaxim Konovalov cm->cmsg_type == SCM_CREDS) { 183470df31f4SMaxim Konovalov if (n_prev == NULL) 183570df31f4SMaxim Konovalov control = n->m_next; 183670df31f4SMaxim Konovalov else 183770df31f4SMaxim Konovalov n_prev->m_next = n->m_next; 183870df31f4SMaxim Konovalov n = m_free(n); 183970df31f4SMaxim Konovalov } else { 184070df31f4SMaxim Konovalov n_prev = n; 184170df31f4SMaxim Konovalov n = n->m_next; 184270df31f4SMaxim Konovalov } 184370df31f4SMaxim Konovalov } 18446a2989fdSMatthew N. Dodd 184570df31f4SMaxim Konovalov /* Prepend it to the head. */ 184670df31f4SMaxim Konovalov m->m_next = control; 184770df31f4SMaxim Konovalov return (m); 18486a2989fdSMatthew N. Dodd } 18496a2989fdSMatthew N. Dodd 1850397c19d1SJeff Roberson static struct unpcb * 1851397c19d1SJeff Roberson fptounp(struct file *fp) 1852397c19d1SJeff Roberson { 1853397c19d1SJeff Roberson struct socket *so; 1854397c19d1SJeff Roberson 1855397c19d1SJeff Roberson if (fp->f_type != DTYPE_SOCKET) 1856397c19d1SJeff Roberson return (NULL); 1857397c19d1SJeff Roberson if ((so = fp->f_data) == NULL) 1858397c19d1SJeff Roberson return (NULL); 1859397c19d1SJeff Roberson if (so->so_proto->pr_domain != &localdomain) 1860397c19d1SJeff Roberson return (NULL); 1861397c19d1SJeff Roberson return sotounpcb(so); 1862397c19d1SJeff Roberson } 1863397c19d1SJeff Roberson 1864397c19d1SJeff Roberson static void 1865397c19d1SJeff Roberson unp_discard(struct file *fp) 1866397c19d1SJeff Roberson { 1867397c19d1SJeff Roberson 1868397c19d1SJeff Roberson unp_externalize_fp(fp); 1869397c19d1SJeff Roberson (void) closef(fp, (struct thread *)NULL); 1870397c19d1SJeff Roberson } 1871397c19d1SJeff Roberson 1872397c19d1SJeff Roberson static void 1873397c19d1SJeff Roberson unp_internalize_fp(struct file *fp) 1874397c19d1SJeff Roberson { 1875397c19d1SJeff Roberson struct unpcb *unp; 1876397c19d1SJeff Roberson 18773dab55bcSRobert Watson UNP_LINK_WLOCK(); 1878397c19d1SJeff Roberson if ((unp = fptounp(fp)) != NULL) { 1879397c19d1SJeff Roberson unp->unp_file = fp; 1880397c19d1SJeff Roberson unp->unp_msgcount++; 1881397c19d1SJeff Roberson } 188241e0f66dSJeff Roberson fhold(fp); 1883397c19d1SJeff Roberson unp_rights++; 18843dab55bcSRobert Watson UNP_LINK_WUNLOCK(); 1885397c19d1SJeff Roberson } 1886397c19d1SJeff Roberson 1887397c19d1SJeff Roberson static void 1888397c19d1SJeff Roberson unp_externalize_fp(struct file *fp) 1889397c19d1SJeff Roberson { 1890397c19d1SJeff Roberson struct unpcb *unp; 1891397c19d1SJeff Roberson 18923dab55bcSRobert Watson UNP_LINK_WLOCK(); 1893397c19d1SJeff Roberson if ((unp = fptounp(fp)) != NULL) 1894397c19d1SJeff Roberson unp->unp_msgcount--; 1895397c19d1SJeff Roberson unp_rights--; 18963dab55bcSRobert Watson UNP_LINK_WUNLOCK(); 1897397c19d1SJeff Roberson } 1898397c19d1SJeff Roberson 1899161a0c7cSRobert Watson /* 1900a0ec558aSRobert Watson * unp_defer indicates whether additional work has been defered for a future 1901a0ec558aSRobert Watson * pass through unp_gc(). It is thread local and does not require explicit 1902a0ec558aSRobert Watson * synchronization. 1903161a0c7cSRobert Watson */ 1904397c19d1SJeff Roberson static int unp_marked; 1905397c19d1SJeff Roberson static int unp_unreachable; 1906a0ec558aSRobert Watson 1907397c19d1SJeff Roberson static void 1908397c19d1SJeff Roberson unp_accessable(struct file *fp) 1909397c19d1SJeff Roberson { 1910397c19d1SJeff Roberson struct unpcb *unp; 1911397c19d1SJeff Roberson 19126f552cb0SJeff Roberson if ((unp = fptounp(fp)) == NULL) 1913397c19d1SJeff Roberson return; 1914397c19d1SJeff Roberson if (unp->unp_gcflag & UNPGC_REF) 1915397c19d1SJeff Roberson return; 1916397c19d1SJeff Roberson unp->unp_gcflag &= ~UNPGC_DEAD; 1917397c19d1SJeff Roberson unp->unp_gcflag |= UNPGC_REF; 1918397c19d1SJeff Roberson unp_marked++; 1919397c19d1SJeff Roberson } 1920397c19d1SJeff Roberson 1921397c19d1SJeff Roberson static void 1922397c19d1SJeff Roberson unp_gc_process(struct unpcb *unp) 1923397c19d1SJeff Roberson { 1924397c19d1SJeff Roberson struct socket *soa; 1925397c19d1SJeff Roberson struct socket *so; 1926397c19d1SJeff Roberson struct file *fp; 1927397c19d1SJeff Roberson 1928397c19d1SJeff Roberson /* Already processed. */ 1929397c19d1SJeff Roberson if (unp->unp_gcflag & UNPGC_SCANNED) 1930397c19d1SJeff Roberson return; 1931397c19d1SJeff Roberson fp = unp->unp_file; 193260a5ef26SRobert Watson 1933397c19d1SJeff Roberson /* 1934397c19d1SJeff Roberson * Check for a socket potentially in a cycle. It must be in a 1935397c19d1SJeff Roberson * queue as indicated by msgcount, and this must equal the file 1936397c19d1SJeff Roberson * reference count. Note that when msgcount is 0 the file is NULL. 1937397c19d1SJeff Roberson */ 193841e0f66dSJeff Roberson if ((unp->unp_gcflag & UNPGC_REF) == 0 && fp && 193941e0f66dSJeff Roberson unp->unp_msgcount != 0 && fp->f_count == unp->unp_msgcount) { 1940397c19d1SJeff Roberson unp->unp_gcflag |= UNPGC_DEAD; 1941397c19d1SJeff Roberson unp_unreachable++; 1942397c19d1SJeff Roberson return; 1943397c19d1SJeff Roberson } 194460a5ef26SRobert Watson 1945397c19d1SJeff Roberson /* 1946397c19d1SJeff Roberson * Mark all sockets we reference with RIGHTS. 1947397c19d1SJeff Roberson */ 1948397c19d1SJeff Roberson so = unp->unp_socket; 1949397c19d1SJeff Roberson SOCKBUF_LOCK(&so->so_rcv); 1950397c19d1SJeff Roberson unp_scan(so->so_rcv.sb_mb, unp_accessable); 1951397c19d1SJeff Roberson SOCKBUF_UNLOCK(&so->so_rcv); 195260a5ef26SRobert Watson 1953397c19d1SJeff Roberson /* 1954397c19d1SJeff Roberson * Mark all sockets in our accept queue. 1955397c19d1SJeff Roberson */ 1956397c19d1SJeff Roberson ACCEPT_LOCK(); 1957397c19d1SJeff Roberson TAILQ_FOREACH(soa, &so->so_comp, so_list) { 1958397c19d1SJeff Roberson SOCKBUF_LOCK(&soa->so_rcv); 1959397c19d1SJeff Roberson unp_scan(soa->so_rcv.sb_mb, unp_accessable); 1960397c19d1SJeff Roberson SOCKBUF_UNLOCK(&soa->so_rcv); 1961397c19d1SJeff Roberson } 1962397c19d1SJeff Roberson ACCEPT_UNLOCK(); 1963397c19d1SJeff Roberson unp->unp_gcflag |= UNPGC_SCANNED; 1964397c19d1SJeff Roberson } 1965a0ec558aSRobert Watson 1966a0ec558aSRobert Watson static int unp_recycled; 1967be6b1304STom Rhodes SYSCTL_INT(_net_local, OID_AUTO, recycled, CTLFLAG_RD, &unp_recycled, 0, 1968be6b1304STom Rhodes "Number of unreachable sockets claimed by the garbage collector."); 1969df8bae1dSRodney W. Grimes 1970397c19d1SJeff Roberson static int unp_taskcount; 1971be6b1304STom Rhodes SYSCTL_INT(_net_local, OID_AUTO, taskcount, CTLFLAG_RD, &unp_taskcount, 0, 1972be6b1304STom Rhodes "Number of times the garbage collector has run."); 1973397c19d1SJeff Roberson 1974f708ef1bSPoul-Henning Kamp static void 1975a0ec558aSRobert Watson unp_gc(__unused void *arg, int pending) 1976df8bae1dSRodney W. Grimes { 1977397c19d1SJeff Roberson struct unp_head *heads[] = { &unp_dhead, &unp_shead, NULL }; 1978397c19d1SJeff Roberson struct unp_head **head; 1979397c19d1SJeff Roberson struct file **unref; 1980397c19d1SJeff Roberson struct unpcb *unp; 1981397c19d1SJeff Roberson int i; 1982df8bae1dSRodney W. Grimes 1983a0ec558aSRobert Watson unp_taskcount++; 19843dab55bcSRobert Watson UNP_LIST_LOCK(); 1985ed5b7817SJulian Elischer /* 1986397c19d1SJeff Roberson * First clear all gc flags from previous runs. 1987ed5b7817SJulian Elischer */ 1988397c19d1SJeff Roberson for (head = heads; *head != NULL; head++) 1989397c19d1SJeff Roberson LIST_FOREACH(unp, *head, unp_link) 199041e0f66dSJeff Roberson unp->unp_gcflag = 0; 199160a5ef26SRobert Watson 1992397c19d1SJeff Roberson /* 1993397c19d1SJeff Roberson * Scan marking all reachable sockets with UNPGC_REF. Once a socket 1994397c19d1SJeff Roberson * is reachable all of the sockets it references are reachable. 1995397c19d1SJeff Roberson * Stop the scan once we do a complete loop without discovering 1996397c19d1SJeff Roberson * a new reachable socket. 1997397c19d1SJeff Roberson */ 1998df8bae1dSRodney W. Grimes do { 1999397c19d1SJeff Roberson unp_unreachable = 0; 2000397c19d1SJeff Roberson unp_marked = 0; 2001397c19d1SJeff Roberson for (head = heads; *head != NULL; head++) 2002397c19d1SJeff Roberson LIST_FOREACH(unp, *head, unp_link) 2003397c19d1SJeff Roberson unp_gc_process(unp); 2004397c19d1SJeff Roberson } while (unp_marked); 20053dab55bcSRobert Watson UNP_LIST_UNLOCK(); 2006397c19d1SJeff Roberson if (unp_unreachable == 0) 2007397c19d1SJeff Roberson return; 200860a5ef26SRobert Watson 2009ed5b7817SJulian Elischer /* 2010397c19d1SJeff Roberson * Allocate space for a local list of dead unpcbs. 2011ed5b7817SJulian Elischer */ 2012397c19d1SJeff Roberson unref = malloc(unp_unreachable * sizeof(struct file *), 2013397c19d1SJeff Roberson M_TEMP, M_WAITOK); 201460a5ef26SRobert Watson 2015ed5b7817SJulian Elischer /* 2016397c19d1SJeff Roberson * Iterate looking for sockets which have been specifically marked 2017397c19d1SJeff Roberson * as as unreachable and store them locally. 2018ed5b7817SJulian Elischer */ 20193dab55bcSRobert Watson UNP_LIST_LOCK(); 2020397c19d1SJeff Roberson for (i = 0, head = heads; *head != NULL; head++) 2021397c19d1SJeff Roberson LIST_FOREACH(unp, *head, unp_link) 2022397c19d1SJeff Roberson if (unp->unp_gcflag & UNPGC_DEAD) { 2023397c19d1SJeff Roberson unref[i++] = unp->unp_file; 202441e0f66dSJeff Roberson fhold(unp->unp_file); 2025397c19d1SJeff Roberson KASSERT(unp->unp_file != NULL, 2026397c19d1SJeff Roberson ("unp_gc: Invalid unpcb.")); 2027397c19d1SJeff Roberson KASSERT(i <= unp_unreachable, 2028397c19d1SJeff Roberson ("unp_gc: incorrect unreachable count.")); 2029397c19d1SJeff Roberson } 20303dab55bcSRobert Watson UNP_LIST_UNLOCK(); 203160a5ef26SRobert Watson 2032ed5b7817SJulian Elischer /* 2033397c19d1SJeff Roberson * Now flush all sockets, free'ing rights. This will free the 2034397c19d1SJeff Roberson * struct files associated with these sockets but leave each socket 2035397c19d1SJeff Roberson * with one remaining ref. 2036ed5b7817SJulian Elischer */ 2037397c19d1SJeff Roberson for (i = 0; i < unp_unreachable; i++) 2038397c19d1SJeff Roberson sorflush(unref[i]->f_data); 203960a5ef26SRobert Watson 2040ed5b7817SJulian Elischer /* 2041397c19d1SJeff Roberson * And finally release the sockets so they can be reclaimed. 2042ed5b7817SJulian Elischer */ 2043397c19d1SJeff Roberson for (i = 0; i < unp_unreachable; i++) 2044397c19d1SJeff Roberson fdrop(unref[i], NULL); 2045397c19d1SJeff Roberson unp_recycled += unp_unreachable; 2046397c19d1SJeff Roberson free(unref, M_TEMP); 2047df8bae1dSRodney W. Grimes } 2048df8bae1dSRodney W. Grimes 20490b36cd25SRobert Watson static void 2050892af6b9SRobert Watson unp_dispose(struct mbuf *m) 2051df8bae1dSRodney W. Grimes { 2052996c772fSJohn Dyson 2053df8bae1dSRodney W. Grimes if (m) 2054df8bae1dSRodney W. Grimes unp_scan(m, unp_discard); 2055df8bae1dSRodney W. Grimes } 2056df8bae1dSRodney W. Grimes 2057f708ef1bSPoul-Henning Kamp static void 2058892af6b9SRobert Watson unp_scan(struct mbuf *m0, void (*op)(struct file *)) 2059df8bae1dSRodney W. Grimes { 20602bc21ed9SDavid Malone struct mbuf *m; 20612bc21ed9SDavid Malone struct file **rp; 20622bc21ed9SDavid Malone struct cmsghdr *cm; 20632bc21ed9SDavid Malone void *data; 20642bc21ed9SDavid Malone int i; 20652bc21ed9SDavid Malone socklen_t clen, datalen; 2066df8bae1dSRodney W. Grimes int qfds; 2067df8bae1dSRodney W. Grimes 2068fc3fcacfSRobert Watson while (m0 != NULL) { 20692bc21ed9SDavid Malone for (m = m0; m; m = m->m_next) { 207012396bdcSDavid Malone if (m->m_type != MT_CONTROL) 2071df8bae1dSRodney W. Grimes continue; 20722bc21ed9SDavid Malone 20732bc21ed9SDavid Malone cm = mtod(m, struct cmsghdr *); 20742bc21ed9SDavid Malone clen = m->m_len; 20752bc21ed9SDavid Malone 20762bc21ed9SDavid Malone while (cm != NULL) { 20772bc21ed9SDavid Malone if (sizeof(*cm) > clen || cm->cmsg_len > clen) 20782bc21ed9SDavid Malone break; 20792bc21ed9SDavid Malone 20802bc21ed9SDavid Malone data = CMSG_DATA(cm); 20812bc21ed9SDavid Malone datalen = (caddr_t)cm + cm->cmsg_len 20822bc21ed9SDavid Malone - (caddr_t)data; 20832bc21ed9SDavid Malone 20842bc21ed9SDavid Malone if (cm->cmsg_level == SOL_SOCKET && 20852bc21ed9SDavid Malone cm->cmsg_type == SCM_RIGHTS) { 20862bc21ed9SDavid Malone qfds = datalen / sizeof (struct file *); 20872bc21ed9SDavid Malone rp = data; 2088df8bae1dSRodney W. Grimes for (i = 0; i < qfds; i++) 2089df8bae1dSRodney W. Grimes (*op)(*rp++); 20902bc21ed9SDavid Malone } 20912bc21ed9SDavid Malone 20922bc21ed9SDavid Malone if (CMSG_SPACE(datalen) < clen) { 20932bc21ed9SDavid Malone clen -= CMSG_SPACE(datalen); 20942bc21ed9SDavid Malone cm = (struct cmsghdr *) 20952bc21ed9SDavid Malone ((caddr_t)cm + CMSG_SPACE(datalen)); 20962bc21ed9SDavid Malone } else { 20972bc21ed9SDavid Malone clen = 0; 20982bc21ed9SDavid Malone cm = NULL; 20992bc21ed9SDavid Malone } 21002bc21ed9SDavid Malone } 2101df8bae1dSRodney W. Grimes } 2102df8bae1dSRodney W. Grimes m0 = m0->m_act; 2103df8bae1dSRodney W. Grimes } 2104df8bae1dSRodney W. Grimes } 2105df8bae1dSRodney W. Grimes 210603c96c31SRobert Watson #ifdef DDB 210703c96c31SRobert Watson static void 210803c96c31SRobert Watson db_print_indent(int indent) 210903c96c31SRobert Watson { 211003c96c31SRobert Watson int i; 211103c96c31SRobert Watson 211203c96c31SRobert Watson for (i = 0; i < indent; i++) 211303c96c31SRobert Watson db_printf(" "); 211403c96c31SRobert Watson } 211503c96c31SRobert Watson 211603c96c31SRobert Watson static void 211703c96c31SRobert Watson db_print_unpflags(int unp_flags) 211803c96c31SRobert Watson { 211903c96c31SRobert Watson int comma; 212003c96c31SRobert Watson 212103c96c31SRobert Watson comma = 0; 212203c96c31SRobert Watson if (unp_flags & UNP_HAVEPC) { 212303c96c31SRobert Watson db_printf("%sUNP_HAVEPC", comma ? ", " : ""); 212403c96c31SRobert Watson comma = 1; 212503c96c31SRobert Watson } 212603c96c31SRobert Watson if (unp_flags & UNP_HAVEPCCACHED) { 212703c96c31SRobert Watson db_printf("%sUNP_HAVEPCCACHED", comma ? ", " : ""); 212803c96c31SRobert Watson comma = 1; 212903c96c31SRobert Watson } 213003c96c31SRobert Watson if (unp_flags & UNP_WANTCRED) { 213103c96c31SRobert Watson db_printf("%sUNP_WANTCRED", comma ? ", " : ""); 213203c96c31SRobert Watson comma = 1; 213303c96c31SRobert Watson } 213403c96c31SRobert Watson if (unp_flags & UNP_CONNWAIT) { 213503c96c31SRobert Watson db_printf("%sUNP_CONNWAIT", comma ? ", " : ""); 213603c96c31SRobert Watson comma = 1; 213703c96c31SRobert Watson } 213803c96c31SRobert Watson if (unp_flags & UNP_CONNECTING) { 213903c96c31SRobert Watson db_printf("%sUNP_CONNECTING", comma ? ", " : ""); 214003c96c31SRobert Watson comma = 1; 214103c96c31SRobert Watson } 214203c96c31SRobert Watson if (unp_flags & UNP_BINDING) { 214303c96c31SRobert Watson db_printf("%sUNP_BINDING", comma ? ", " : ""); 214403c96c31SRobert Watson comma = 1; 214503c96c31SRobert Watson } 214603c96c31SRobert Watson } 214703c96c31SRobert Watson 214803c96c31SRobert Watson static void 214903c96c31SRobert Watson db_print_xucred(int indent, struct xucred *xu) 215003c96c31SRobert Watson { 215103c96c31SRobert Watson int comma, i; 215203c96c31SRobert Watson 215303c96c31SRobert Watson db_print_indent(indent); 215403c96c31SRobert Watson db_printf("cr_version: %u cr_uid: %u cr_ngroups: %d\n", 215503c96c31SRobert Watson xu->cr_version, xu->cr_uid, xu->cr_ngroups); 215603c96c31SRobert Watson db_print_indent(indent); 215703c96c31SRobert Watson db_printf("cr_groups: "); 215803c96c31SRobert Watson comma = 0; 215903c96c31SRobert Watson for (i = 0; i < xu->cr_ngroups; i++) { 216003c96c31SRobert Watson db_printf("%s%u", comma ? ", " : "", xu->cr_groups[i]); 216103c96c31SRobert Watson comma = 1; 216203c96c31SRobert Watson } 216303c96c31SRobert Watson db_printf("\n"); 216403c96c31SRobert Watson } 216503c96c31SRobert Watson 216603c96c31SRobert Watson static void 216703c96c31SRobert Watson db_print_unprefs(int indent, struct unp_head *uh) 216803c96c31SRobert Watson { 216903c96c31SRobert Watson struct unpcb *unp; 217003c96c31SRobert Watson int counter; 217103c96c31SRobert Watson 217203c96c31SRobert Watson counter = 0; 217303c96c31SRobert Watson LIST_FOREACH(unp, uh, unp_reflink) { 217403c96c31SRobert Watson if (counter % 4 == 0) 217503c96c31SRobert Watson db_print_indent(indent); 217603c96c31SRobert Watson db_printf("%p ", unp); 217703c96c31SRobert Watson if (counter % 4 == 3) 217803c96c31SRobert Watson db_printf("\n"); 217903c96c31SRobert Watson counter++; 218003c96c31SRobert Watson } 218103c96c31SRobert Watson if (counter != 0 && counter % 4 != 0) 218203c96c31SRobert Watson db_printf("\n"); 218303c96c31SRobert Watson } 218403c96c31SRobert Watson 218503c96c31SRobert Watson DB_SHOW_COMMAND(unpcb, db_show_unpcb) 218603c96c31SRobert Watson { 218703c96c31SRobert Watson struct unpcb *unp; 218803c96c31SRobert Watson 218903c96c31SRobert Watson if (!have_addr) { 219003c96c31SRobert Watson db_printf("usage: show unpcb <addr>\n"); 219103c96c31SRobert Watson return; 219203c96c31SRobert Watson } 219303c96c31SRobert Watson unp = (struct unpcb *)addr; 219403c96c31SRobert Watson 219503c96c31SRobert Watson db_printf("unp_socket: %p unp_vnode: %p\n", unp->unp_socket, 219603c96c31SRobert Watson unp->unp_vnode); 219703c96c31SRobert Watson 219803c96c31SRobert Watson db_printf("unp_ino: %d unp_conn: %p\n", unp->unp_ino, 219903c96c31SRobert Watson unp->unp_conn); 220003c96c31SRobert Watson 220103c96c31SRobert Watson db_printf("unp_refs:\n"); 220203c96c31SRobert Watson db_print_unprefs(2, &unp->unp_refs); 220303c96c31SRobert Watson 220403c96c31SRobert Watson /* XXXRW: Would be nice to print the full address, if any. */ 220503c96c31SRobert Watson db_printf("unp_addr: %p\n", unp->unp_addr); 220603c96c31SRobert Watson 220703c96c31SRobert Watson db_printf("unp_cc: %d unp_mbcnt: %d unp_gencnt: %llu\n", 220803c96c31SRobert Watson unp->unp_cc, unp->unp_mbcnt, 220903c96c31SRobert Watson (unsigned long long)unp->unp_gencnt); 221003c96c31SRobert Watson 221103c96c31SRobert Watson db_printf("unp_flags: %x (", unp->unp_flags); 221203c96c31SRobert Watson db_print_unpflags(unp->unp_flags); 221303c96c31SRobert Watson db_printf(")\n"); 221403c96c31SRobert Watson 221503c96c31SRobert Watson db_printf("unp_peercred:\n"); 221603c96c31SRobert Watson db_print_xucred(2, &unp->unp_peercred); 221703c96c31SRobert Watson 221803c96c31SRobert Watson db_printf("unp_refcount: %u\n", unp->unp_refcount); 221903c96c31SRobert Watson } 222003c96c31SRobert Watson #endif 2221