19454b2d8SWarner Losh /*- 251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 351369649SPedro F. Giffuni * 4df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1989, 1991, 1993 5f344fb0bSWarner Losh * The Regents of the University of California. All Rights Reserved. 6f344fb0bSWarner Losh * Copyright (c) 2004-2009 Robert N. M. Watson All Rights Reserved. 7c0874c34SMatt Macy * Copyright (c) 2018 Matthew Macy 8df8bae1dSRodney W. Grimes * 9df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 10df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 11df8bae1dSRodney W. Grimes * are met: 12df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 13df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 14df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 15df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 16df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 1769a28758SEd Maste * 3. Neither the name of the University nor the names of its contributors 18df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 19df8bae1dSRodney W. Grimes * without specific prior written permission. 20df8bae1dSRodney W. Grimes * 21df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31df8bae1dSRodney W. Grimes * SUCH DAMAGE. 32df8bae1dSRodney W. Grimes * 33748e0b0aSGarrett Wollman * From: @(#)uipc_usrreq.c 8.3 (Berkeley) 1/4/94 34df8bae1dSRodney W. Grimes */ 35df8bae1dSRodney W. Grimes 36f23929fbSRobert Watson /* 37f23929fbSRobert Watson * UNIX Domain (Local) Sockets 38f23929fbSRobert Watson * 39f23929fbSRobert Watson * This is an implementation of UNIX (local) domain sockets. Each socket has 40f23929fbSRobert Watson * an associated struct unpcb (UNIX protocol control block). Stream sockets 41f23929fbSRobert Watson * may be connected to 0 or 1 other socket. Datagram sockets may be 42f23929fbSRobert Watson * connected to 0, 1, or many other sockets. Sockets may be created and 43f23929fbSRobert Watson * connected in pairs (socketpair(2)), or bound/connected to using the file 44f23929fbSRobert Watson * system name space. For most purposes, only the receive socket buffer is 45f23929fbSRobert Watson * used, as sending on one socket delivers directly to the receive socket 465b950deaSRobert Watson * buffer of a second socket. 475b950deaSRobert Watson * 485b950deaSRobert Watson * The implementation is substantially complicated by the fact that 495b950deaSRobert Watson * "ancillary data", such as file descriptors or credentials, may be passed 505b950deaSRobert Watson * across UNIX domain sockets. The potential for passing UNIX domain sockets 515b950deaSRobert Watson * over other UNIX domain sockets requires the implementation of a simple 525b950deaSRobert Watson * garbage collector to find and tear down cycles of disconnected sockets. 53aea52f1bSRobert Watson * 54aea52f1bSRobert Watson * TODO: 5584d61770SRobert Watson * RDM 56aea52f1bSRobert Watson * rethink name space problems 57aea52f1bSRobert Watson * need a proper out-of-band 58f23929fbSRobert Watson */ 59f23929fbSRobert Watson 60677b542eSDavid E. O'Brien #include <sys/cdefs.h> 61677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 62677b542eSDavid E. O'Brien 6303c96c31SRobert Watson #include "opt_ddb.h" 64335654d7SRobert Watson 65df8bae1dSRodney W. Grimes #include <sys/param.h> 664a144410SRobert Watson #include <sys/capsicum.h> 67fb919e4dSMark Murray #include <sys/domain.h> 684f590175SPaul Saab #include <sys/eventhandler.h> 69d5cbccecSMark Johnston #include <sys/fcntl.h> 70639acc13SGarrett Wollman #include <sys/file.h> 71960ed29cSSeigo Tanimura #include <sys/filedesc.h> 72960ed29cSSeigo Tanimura #include <sys/kernel.h> 73960ed29cSSeigo Tanimura #include <sys/lock.h> 74d5cbccecSMark Johnston #include <sys/malloc.h> 75639acc13SGarrett Wollman #include <sys/mbuf.h> 76033eb86eSJeff Roberson #include <sys/mount.h> 77960ed29cSSeigo Tanimura #include <sys/mutex.h> 78639acc13SGarrett Wollman #include <sys/namei.h> 79639acc13SGarrett Wollman #include <sys/proc.h> 80df8bae1dSRodney W. Grimes #include <sys/protosw.h> 810cb64678SKonstantin Belousov #include <sys/queue.h> 82960ed29cSSeigo Tanimura #include <sys/resourcevar.h> 83e7c33e29SRobert Watson #include <sys/rwlock.h> 84df8bae1dSRodney W. Grimes #include <sys/socket.h> 85df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 86960ed29cSSeigo Tanimura #include <sys/signalvar.h> 87df8bae1dSRodney W. Grimes #include <sys/stat.h> 88960ed29cSSeigo Tanimura #include <sys/sx.h> 89639acc13SGarrett Wollman #include <sys/sysctl.h> 90960ed29cSSeigo Tanimura #include <sys/systm.h> 91a0ec558aSRobert Watson #include <sys/taskqueue.h> 92639acc13SGarrett Wollman #include <sys/un.h> 9398271db4SGarrett Wollman #include <sys/unpcb.h> 94639acc13SGarrett Wollman #include <sys/vnode.h> 95530c0060SRobert Watson 96530c0060SRobert Watson #include <net/vnet.h> 97df8bae1dSRodney W. Grimes 9803c96c31SRobert Watson #ifdef DDB 9903c96c31SRobert Watson #include <ddb/ddb.h> 10003c96c31SRobert Watson #endif 10103c96c31SRobert Watson 102aed55708SRobert Watson #include <security/mac/mac_framework.h> 103aed55708SRobert Watson 1049e9d298aSJeff Roberson #include <vm/uma.h> 10598271db4SGarrett Wollman 1068cb539f1SPawel Jakub Dawidek MALLOC_DECLARE(M_FILECAPS); 1078cb539f1SPawel Jakub Dawidek 1083dab55bcSRobert Watson /* 109d5cbccecSMark Johnston * See unpcb.h for the locking key. 1103dab55bcSRobert Watson */ 1113dab55bcSRobert Watson 1129e9d298aSJeff Roberson static uma_zone_t unp_zone; 1133dab55bcSRobert Watson static unp_gen_t unp_gencnt; /* (l) */ 1143dab55bcSRobert Watson static u_int unp_count; /* (l) Count of local sockets. */ 115aea52f1bSRobert Watson static ino_t unp_ino; /* Prototype for fake inode numbers. */ 1163dab55bcSRobert Watson static int unp_rights; /* (g) File descriptors in flight. */ 1173dab55bcSRobert Watson static struct unp_head unp_shead; /* (l) List of stream sockets. */ 1183dab55bcSRobert Watson static struct unp_head unp_dhead; /* (l) List of datagram sockets. */ 11984d61770SRobert Watson static struct unp_head unp_sphead; /* (l) List of seqpacket sockets. */ 12098271db4SGarrett Wollman 1210cb64678SKonstantin Belousov struct unp_defer { 1220cb64678SKonstantin Belousov SLIST_ENTRY(unp_defer) ud_link; 1230cb64678SKonstantin Belousov struct file *ud_fp; 1240cb64678SKonstantin Belousov }; 1250cb64678SKonstantin Belousov static SLIST_HEAD(, unp_defer) unp_defers; 1260cb64678SKonstantin Belousov static int unp_defers_count; 1270cb64678SKonstantin Belousov 128aea52f1bSRobert Watson static const struct sockaddr sun_noname = { sizeof(sun_noname), AF_LOCAL }; 12998271db4SGarrett Wollman 130df8bae1dSRodney W. Grimes /* 131aea52f1bSRobert Watson * Garbage collection of cyclic file descriptor/socket references occurs 132aea52f1bSRobert Watson * asynchronously in a taskqueue context in order to avoid recursion and 133aea52f1bSRobert Watson * reentrance in the UNIX domain socket, file descriptor, and socket layer 134aea52f1bSRobert Watson * code. See unp_gc() for a full description. 135df8bae1dSRodney W. Grimes */ 136daee0f0bSKonstantin Belousov static struct timeout_task unp_gc_task; 137f708ef1bSPoul-Henning Kamp 138ce5f32deSRobert Watson /* 1390cb64678SKonstantin Belousov * The close of unix domain sockets attached as SCM_RIGHTS is 1400cb64678SKonstantin Belousov * postponed to the taskqueue, to avoid arbitrary recursion depth. 1410cb64678SKonstantin Belousov * The attached sockets might have another sockets attached. 1420cb64678SKonstantin Belousov */ 1430cb64678SKonstantin Belousov static struct task unp_defer_task; 1440cb64678SKonstantin Belousov 1450cb64678SKonstantin Belousov /* 1467e711c3aSRobert Watson * Both send and receive buffers are allocated PIPSIZ bytes of buffering for 1477e711c3aSRobert Watson * stream sockets, although the total for sender and receiver is actually 1487e711c3aSRobert Watson * only PIPSIZ. 1497e711c3aSRobert Watson * 1507e711c3aSRobert Watson * Datagram sockets really use the sendspace as the maximum datagram size, 1517e711c3aSRobert Watson * and don't really want to reserve the sendspace. Their recvspace should be 1527e711c3aSRobert Watson * large enough for at least one max-size datagram plus address. 1537e711c3aSRobert Watson */ 1547e711c3aSRobert Watson #ifndef PIPSIZ 1557e711c3aSRobert Watson #define PIPSIZ 8192 1567e711c3aSRobert Watson #endif 1577e711c3aSRobert Watson static u_long unpst_sendspace = PIPSIZ; 1587e711c3aSRobert Watson static u_long unpst_recvspace = PIPSIZ; 1592573e6ceSGleb Smirnoff static u_long unpdg_maxdgram = 2*1024; 160d157f262SMark Johnston static u_long unpdg_recvspace = 16*1024; /* support 8KB syslog msgs */ 16184d61770SRobert Watson static u_long unpsp_sendspace = PIPSIZ; /* really max datagram size */ 16284d61770SRobert Watson static u_long unpsp_recvspace = PIPSIZ; 1637e711c3aSRobert Watson 1647029da5cSPawel Biernacki static SYSCTL_NODE(_net, PF_LOCAL, local, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 1657029da5cSPawel Biernacki "Local domain"); 1667029da5cSPawel Biernacki static SYSCTL_NODE(_net_local, SOCK_STREAM, stream, 1677029da5cSPawel Biernacki CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 1686472ac3dSEd Schouten "SOCK_STREAM"); 1697029da5cSPawel Biernacki static SYSCTL_NODE(_net_local, SOCK_DGRAM, dgram, 1707029da5cSPawel Biernacki CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 1717029da5cSPawel Biernacki "SOCK_DGRAM"); 1727029da5cSPawel Biernacki static SYSCTL_NODE(_net_local, SOCK_SEQPACKET, seqpacket, 1737029da5cSPawel Biernacki CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 17484d61770SRobert Watson "SOCK_SEQPACKET"); 175e4445a03SRobert Watson 1767e711c3aSRobert Watson SYSCTL_ULONG(_net_local_stream, OID_AUTO, sendspace, CTLFLAG_RW, 177be6b1304STom Rhodes &unpst_sendspace, 0, "Default stream send space."); 1787e711c3aSRobert Watson SYSCTL_ULONG(_net_local_stream, OID_AUTO, recvspace, CTLFLAG_RW, 179be6b1304STom Rhodes &unpst_recvspace, 0, "Default stream receive space."); 1807e711c3aSRobert Watson SYSCTL_ULONG(_net_local_dgram, OID_AUTO, maxdgram, CTLFLAG_RW, 1812573e6ceSGleb Smirnoff &unpdg_maxdgram, 0, "Maximum datagram size."); 1827e711c3aSRobert Watson SYSCTL_ULONG(_net_local_dgram, OID_AUTO, recvspace, CTLFLAG_RW, 183be6b1304STom Rhodes &unpdg_recvspace, 0, "Default datagram receive space."); 18484d61770SRobert Watson SYSCTL_ULONG(_net_local_seqpacket, OID_AUTO, maxseqpacket, CTLFLAG_RW, 18584d61770SRobert Watson &unpsp_sendspace, 0, "Default seqpacket send space."); 18684d61770SRobert Watson SYSCTL_ULONG(_net_local_seqpacket, OID_AUTO, recvspace, CTLFLAG_RW, 18784d61770SRobert Watson &unpsp_recvspace, 0, "Default seqpacket receive space."); 188be6b1304STom Rhodes SYSCTL_INT(_net_local, OID_AUTO, inflight, CTLFLAG_RD, &unp_rights, 0, 189be6b1304STom Rhodes "File descriptors in flight."); 1900cb64678SKonstantin Belousov SYSCTL_INT(_net_local, OID_AUTO, deferred, CTLFLAG_RD, 1910cb64678SKonstantin Belousov &unp_defers_count, 0, 1920cb64678SKonstantin Belousov "File descriptors deferred to taskqueue for close."); 1937e711c3aSRobert Watson 194175389cfSEdward Tomasz Napierala /* 195e7c33e29SRobert Watson * Locking and synchronization: 196ce5f32deSRobert Watson * 197d5cbccecSMark Johnston * Several types of locks exist in the local domain socket implementation: 198d5cbccecSMark Johnston * - a global linkage lock 199d5cbccecSMark Johnston * - a global connection list lock 200d5cbccecSMark Johnston * - the mtxpool lock 201d5cbccecSMark Johnston * - per-unpcb mutexes 202d5cbccecSMark Johnston * 203d5cbccecSMark Johnston * The linkage lock protects the global socket lists, the generation number 204d5cbccecSMark Johnston * counter and garbage collector state. 205d5cbccecSMark Johnston * 206d5cbccecSMark Johnston * The connection list lock protects the list of referring sockets in a datagram 207d5cbccecSMark Johnston * socket PCB. This lock is also overloaded to protect a global list of 208d5cbccecSMark Johnston * sockets whose buffers contain socket references in the form of SCM_RIGHTS 209d5cbccecSMark Johnston * messages. To avoid recursion, such references are released by a dedicated 210d5cbccecSMark Johnston * thread. 21175a67bf3SMatt Macy * 21275a67bf3SMatt Macy * The mtxpool lock protects the vnode from being modified while referenced. 213d5cbccecSMark Johnston * Lock ordering rules require that it be acquired before any PCB locks. 21475a67bf3SMatt Macy * 215d5cbccecSMark Johnston * The unpcb lock (unp_mtx) protects the most commonly referenced fields in the 216d5cbccecSMark Johnston * unpcb. This includes the unp_conn field, which either links two connected 217d5cbccecSMark Johnston * PCBs together (for connected socket types) or points at the destination 218d5cbccecSMark Johnston * socket (for connectionless socket types). The operations of creating or 219d5cbccecSMark Johnston * destroying a connection therefore involve locking multiple PCBs. To avoid 220d5cbccecSMark Johnston * lock order reversals, in some cases this involves dropping a PCB lock and 221d5cbccecSMark Johnston * using a reference counter to maintain liveness. 222ce5f32deSRobert Watson * 223e7c33e29SRobert Watson * UNIX domain sockets each have an unpcb hung off of their so_pcb pointer, 224e7c33e29SRobert Watson * allocated in pru_attach() and freed in pru_detach(). The validity of that 225e7c33e29SRobert Watson * pointer is an invariant, so no lock is required to dereference the so_pcb 226e7c33e29SRobert Watson * pointer if a valid socket reference is held by the caller. In practice, 227e7c33e29SRobert Watson * this is always true during operations performed on a socket. Each unpcb 228e7c33e29SRobert Watson * has a back-pointer to its socket, unp_socket, which will be stable under 229e7c33e29SRobert Watson * the same circumstances. 230e7c33e29SRobert Watson * 231e7c33e29SRobert Watson * This pointer may only be safely dereferenced as long as a valid reference 232e7c33e29SRobert Watson * to the unpcb is held. Typically, this reference will be from the socket, 233e7c33e29SRobert Watson * or from another unpcb when the referring unpcb's lock is held (in order 234e7c33e29SRobert Watson * that the reference not be invalidated during use). For example, to follow 23575a67bf3SMatt Macy * unp->unp_conn->unp_socket, you need to hold a lock on unp_conn to guarantee 23675a67bf3SMatt Macy * that detach is not run clearing unp_socket. 237e7c33e29SRobert Watson * 238e7c33e29SRobert Watson * Blocking with UNIX domain sockets is a tricky issue: unlike most network 239e7c33e29SRobert Watson * protocols, bind() is a non-atomic operation, and connect() requires 240e7c33e29SRobert Watson * potential sleeping in the protocol, due to potentially waiting on local or 241e7c33e29SRobert Watson * distributed file systems. We try to separate "lookup" operations, which 242e7c33e29SRobert Watson * may sleep, and the IPC operations themselves, which typically can occur 243e7c33e29SRobert Watson * with relative atomicity as locks can be held over the entire operation. 244e7c33e29SRobert Watson * 245e7c33e29SRobert Watson * Another tricky issue is simultaneous multi-threaded or multi-process 246e7c33e29SRobert Watson * access to a single UNIX domain socket. These are handled by the flags 247e7c33e29SRobert Watson * UNP_CONNECTING and UNP_BINDING, which prevent concurrent connecting or 248e7c33e29SRobert Watson * binding, both of which involve dropping UNIX domain socket locks in order 249e7c33e29SRobert Watson * to perform namei() and other file system operations. 250ce5f32deSRobert Watson */ 2513dab55bcSRobert Watson static struct rwlock unp_link_rwlock; 2520cb64678SKonstantin Belousov static struct mtx unp_defers_lock; 253e7c33e29SRobert Watson 2543dab55bcSRobert Watson #define UNP_LINK_LOCK_INIT() rw_init(&unp_link_rwlock, \ 2553dab55bcSRobert Watson "unp_link_rwlock") 256e7c33e29SRobert Watson 2573dab55bcSRobert Watson #define UNP_LINK_LOCK_ASSERT() rw_assert(&unp_link_rwlock, \ 258e7c33e29SRobert Watson RA_LOCKED) 2593dab55bcSRobert Watson #define UNP_LINK_UNLOCK_ASSERT() rw_assert(&unp_link_rwlock, \ 260e7c33e29SRobert Watson RA_UNLOCKED) 261e7c33e29SRobert Watson 2623dab55bcSRobert Watson #define UNP_LINK_RLOCK() rw_rlock(&unp_link_rwlock) 2633dab55bcSRobert Watson #define UNP_LINK_RUNLOCK() rw_runlock(&unp_link_rwlock) 2643dab55bcSRobert Watson #define UNP_LINK_WLOCK() rw_wlock(&unp_link_rwlock) 2653dab55bcSRobert Watson #define UNP_LINK_WUNLOCK() rw_wunlock(&unp_link_rwlock) 2663dab55bcSRobert Watson #define UNP_LINK_WLOCK_ASSERT() rw_assert(&unp_link_rwlock, \ 267e7c33e29SRobert Watson RA_WLOCKED) 268779f106aSGleb Smirnoff #define UNP_LINK_WOWNED() rw_wowned(&unp_link_rwlock) 269e7c33e29SRobert Watson 2700cb64678SKonstantin Belousov #define UNP_DEFERRED_LOCK_INIT() mtx_init(&unp_defers_lock, \ 2710cb64678SKonstantin Belousov "unp_defer", NULL, MTX_DEF) 2720cb64678SKonstantin Belousov #define UNP_DEFERRED_LOCK() mtx_lock(&unp_defers_lock) 2730cb64678SKonstantin Belousov #define UNP_DEFERRED_UNLOCK() mtx_unlock(&unp_defers_lock) 2740cb64678SKonstantin Belousov 27575a67bf3SMatt Macy #define UNP_REF_LIST_LOCK() UNP_DEFERRED_LOCK(); 27675a67bf3SMatt Macy #define UNP_REF_LIST_UNLOCK() UNP_DEFERRED_UNLOCK(); 27775a67bf3SMatt Macy 278e7c33e29SRobert Watson #define UNP_PCB_LOCK_INIT(unp) mtx_init(&(unp)->unp_mtx, \ 279d9525340SMatt Macy "unp", "unp", \ 28075a67bf3SMatt Macy MTX_DUPOK|MTX_DEF) 281e7c33e29SRobert Watson #define UNP_PCB_LOCK_DESTROY(unp) mtx_destroy(&(unp)->unp_mtx) 282ccdadf1aSMark Johnston #define UNP_PCB_LOCKPTR(unp) (&(unp)->unp_mtx) 283e7c33e29SRobert Watson #define UNP_PCB_LOCK(unp) mtx_lock(&(unp)->unp_mtx) 28475a67bf3SMatt Macy #define UNP_PCB_TRYLOCK(unp) mtx_trylock(&(unp)->unp_mtx) 285e7c33e29SRobert Watson #define UNP_PCB_UNLOCK(unp) mtx_unlock(&(unp)->unp_mtx) 28675a67bf3SMatt Macy #define UNP_PCB_OWNED(unp) mtx_owned(&(unp)->unp_mtx) 287e7c33e29SRobert Watson #define UNP_PCB_LOCK_ASSERT(unp) mtx_assert(&(unp)->unp_mtx, MA_OWNED) 28875a67bf3SMatt Macy #define UNP_PCB_UNLOCK_ASSERT(unp) mtx_assert(&(unp)->unp_mtx, MA_NOTOWNED) 2890d9ce3a1SRobert Watson 2902c899584SRobert Watson static int uipc_connect2(struct socket *, struct socket *); 2910b36cd25SRobert Watson static int uipc_ctloutput(struct socket *, struct sockopt *); 292aea52f1bSRobert Watson static int unp_connect(struct socket *, struct sockaddr *, 293aea52f1bSRobert Watson struct thread *); 2947493f24eSPawel Jakub Dawidek static int unp_connectat(int, struct socket *, struct sockaddr *, 295315167c0SGleb Smirnoff struct thread *, bool); 29608f17d14SGleb Smirnoff static void unp_connect2(struct socket *so, struct socket *so2, int); 297e7c33e29SRobert Watson static void unp_disconnect(struct unpcb *unp, struct unpcb *unp2); 29899ab95dbSMark Johnston static void unp_dispose(struct socket *so); 2994d77a549SAlfred Perlstein static void unp_shutdown(struct unpcb *); 300afc055d9SEd Schouten static void unp_drop(struct unpcb *); 301a0ec558aSRobert Watson static void unp_gc(__unused void *, int); 302be26ba7cSPawel Jakub Dawidek static void unp_scan(struct mbuf *, void (*)(struct filedescent **, int)); 3034d77a549SAlfred Perlstein static void unp_discard(struct file *); 3048cb539f1SPawel Jakub Dawidek static void unp_freerights(struct filedescent **, int); 3051093f164SGleb Smirnoff static int unp_internalize(struct mbuf **, struct thread *, 3061093f164SGleb Smirnoff struct mbuf **, u_int *, u_int *); 307397c19d1SJeff Roberson static void unp_internalize_fp(struct file *); 308c2e3c52eSJilles Tjoelker static int unp_externalize(struct mbuf *, struct mbuf **, int); 3090cb64678SKonstantin Belousov static int unp_externalize_fp(struct file *); 3101093f164SGleb Smirnoff static struct mbuf *unp_addsockcred(struct thread *, struct mbuf *, 3111093f164SGleb Smirnoff int, struct mbuf **, u_int *, u_int *); 3120cb64678SKonstantin Belousov static void unp_process_defers(void * __unused, int); 313f708ef1bSPoul-Henning Kamp 31475a67bf3SMatt Macy static void 31575a67bf3SMatt Macy unp_pcb_hold(struct unpcb *unp) 31675a67bf3SMatt Macy { 3175362170dSMark Johnston u_int old __unused; 3185362170dSMark Johnston 3195362170dSMark Johnston old = refcount_acquire(&unp->unp_refcount); 3205362170dSMark Johnston KASSERT(old > 0, ("%s: unpcb %p has no references", __func__, unp)); 32175a67bf3SMatt Macy } 32275a67bf3SMatt Macy 3235362170dSMark Johnston static __result_use_check bool 32475a67bf3SMatt Macy unp_pcb_rele(struct unpcb *unp) 32575a67bf3SMatt Macy { 3265362170dSMark Johnston bool ret; 32775a67bf3SMatt Macy 32875a67bf3SMatt Macy UNP_PCB_LOCK_ASSERT(unp); 3295362170dSMark Johnston 3305362170dSMark Johnston if ((ret = refcount_release(&unp->unp_refcount))) { 33175a67bf3SMatt Macy UNP_PCB_UNLOCK(unp); 33275a67bf3SMatt Macy UNP_PCB_LOCK_DESTROY(unp); 33375a67bf3SMatt Macy uma_zfree(unp_zone, unp); 33475a67bf3SMatt Macy } 3355362170dSMark Johnston return (ret); 33675a67bf3SMatt Macy } 33775a67bf3SMatt Macy 33875a67bf3SMatt Macy static void 339f0317f86SMark Johnston unp_pcb_rele_notlast(struct unpcb *unp) 340f0317f86SMark Johnston { 341f0317f86SMark Johnston bool ret __unused; 342f0317f86SMark Johnston 343f0317f86SMark Johnston ret = refcount_release(&unp->unp_refcount); 344f0317f86SMark Johnston KASSERT(!ret, ("%s: unpcb %p has no references", __func__, unp)); 345f0317f86SMark Johnston } 346f0317f86SMark Johnston 347f0317f86SMark Johnston static void 3484820bf6aSMark Johnston unp_pcb_lock_pair(struct unpcb *unp, struct unpcb *unp2) 34975a67bf3SMatt Macy { 35075a67bf3SMatt Macy UNP_PCB_UNLOCK_ASSERT(unp); 35175a67bf3SMatt Macy UNP_PCB_UNLOCK_ASSERT(unp2); 3524820bf6aSMark Johnston 3534820bf6aSMark Johnston if (unp == unp2) { 3544820bf6aSMark Johnston UNP_PCB_LOCK(unp); 3554820bf6aSMark Johnston } else if ((uintptr_t)unp2 > (uintptr_t)unp) { 35675a67bf3SMatt Macy UNP_PCB_LOCK(unp); 35775a67bf3SMatt Macy UNP_PCB_LOCK(unp2); 35875a67bf3SMatt Macy } else { 35975a67bf3SMatt Macy UNP_PCB_LOCK(unp2); 36075a67bf3SMatt Macy UNP_PCB_LOCK(unp); 36175a67bf3SMatt Macy } 36275a67bf3SMatt Macy } 36375a67bf3SMatt Macy 3644820bf6aSMark Johnston static void 3654820bf6aSMark Johnston unp_pcb_unlock_pair(struct unpcb *unp, struct unpcb *unp2) 3664820bf6aSMark Johnston { 3674820bf6aSMark Johnston UNP_PCB_UNLOCK(unp); 3684820bf6aSMark Johnston if (unp != unp2) 3694820bf6aSMark Johnston UNP_PCB_UNLOCK(unp2); 3704820bf6aSMark Johnston } 3714820bf6aSMark Johnston 372ccdadf1aSMark Johnston /* 373ccdadf1aSMark Johnston * Try to lock the connected peer of an already locked socket. In some cases 374ccdadf1aSMark Johnston * this requires that we unlock the current socket. The pairbusy counter is 375ccdadf1aSMark Johnston * used to block concurrent connection attempts while the lock is dropped. The 376ccdadf1aSMark Johnston * caller must be careful to revalidate PCB state. 377ccdadf1aSMark Johnston */ 378ccdadf1aSMark Johnston static struct unpcb * 379ccdadf1aSMark Johnston unp_pcb_lock_peer(struct unpcb *unp) 38075a67bf3SMatt Macy { 38175a67bf3SMatt Macy struct unpcb *unp2; 38275a67bf3SMatt Macy 383ccdadf1aSMark Johnston UNP_PCB_LOCK_ASSERT(unp); 384ccdadf1aSMark Johnston unp2 = unp->unp_conn; 3856404d7ffSMateusz Guzik if (unp2 == NULL) 386ccdadf1aSMark Johnston return (NULL); 387ccdadf1aSMark Johnston if (__predict_false(unp == unp2)) 388ccdadf1aSMark Johnston return (unp); 389ccdadf1aSMark Johnston 390ccdadf1aSMark Johnston UNP_PCB_UNLOCK_ASSERT(unp2); 391ccdadf1aSMark Johnston 392ccdadf1aSMark Johnston if (__predict_true(UNP_PCB_TRYLOCK(unp2))) 393ccdadf1aSMark Johnston return (unp2); 394ccdadf1aSMark Johnston if ((uintptr_t)unp2 > (uintptr_t)unp) { 395ccdadf1aSMark Johnston UNP_PCB_LOCK(unp2); 396ccdadf1aSMark Johnston return (unp2); 397ccdadf1aSMark Johnston } 398ccdadf1aSMark Johnston unp->unp_pairbusy++; 399e62ca80bSMark Johnston unp_pcb_hold(unp2); 400e62ca80bSMark Johnston UNP_PCB_UNLOCK(unp); 401ccdadf1aSMark Johnston 402e62ca80bSMark Johnston UNP_PCB_LOCK(unp2); 403e62ca80bSMark Johnston UNP_PCB_LOCK(unp); 404ccdadf1aSMark Johnston KASSERT(unp->unp_conn == unp2 || unp->unp_conn == NULL, 405ccdadf1aSMark Johnston ("%s: socket %p was reconnected", __func__, unp)); 406ccdadf1aSMark Johnston if (--unp->unp_pairbusy == 0 && (unp->unp_flags & UNP_WAITING) != 0) { 407ccdadf1aSMark Johnston unp->unp_flags &= ~UNP_WAITING; 408ccdadf1aSMark Johnston wakeup(unp); 40975a67bf3SMatt Macy } 410ccdadf1aSMark Johnston if (unp_pcb_rele(unp2)) { 411ccdadf1aSMark Johnston /* unp2 is unlocked. */ 412ccdadf1aSMark Johnston return (NULL); 413ccdadf1aSMark Johnston } 414ccdadf1aSMark Johnston if (unp->unp_conn == NULL) { 415ccdadf1aSMark Johnston UNP_PCB_UNLOCK(unp2); 416ccdadf1aSMark Johnston return (NULL); 417ccdadf1aSMark Johnston } 418ccdadf1aSMark Johnston return (unp2); 419ccdadf1aSMark Johnston } 42075a67bf3SMatt Macy 421e4445a03SRobert Watson /* 422e4445a03SRobert Watson * Definitions of protocols supported in the LOCAL domain. 423e4445a03SRobert Watson */ 424e4445a03SRobert Watson static struct domain localdomain; 425fa9402f2SRobert Watson static struct pr_usrreqs uipc_usrreqs_dgram, uipc_usrreqs_stream; 42684d61770SRobert Watson static struct pr_usrreqs uipc_usrreqs_seqpacket; 427e4445a03SRobert Watson static struct protosw localsw[] = { 428e4445a03SRobert Watson { 429e4445a03SRobert Watson .pr_type = SOCK_STREAM, 430e4445a03SRobert Watson .pr_domain = &localdomain, 43127457983SMark Johnston .pr_flags = PR_CONNREQUIRED|PR_WANTRCVD|PR_RIGHTS| 43227457983SMark Johnston PR_CAPATTACH, 433e4445a03SRobert Watson .pr_ctloutput = &uipc_ctloutput, 434fa9402f2SRobert Watson .pr_usrreqs = &uipc_usrreqs_stream 435e4445a03SRobert Watson }, 436e4445a03SRobert Watson { 437e4445a03SRobert Watson .pr_type = SOCK_DGRAM, 438e4445a03SRobert Watson .pr_domain = &localdomain, 439a7444f80SGleb Smirnoff .pr_flags = PR_ATOMIC | PR_ADDR |PR_RIGHTS | PR_CAPATTACH | 440a7444f80SGleb Smirnoff PR_SOCKBUF, 441aaf63435SGleb Smirnoff .pr_ctloutput = &uipc_ctloutput, 442fa9402f2SRobert Watson .pr_usrreqs = &uipc_usrreqs_dgram 443e4445a03SRobert Watson }, 44484d61770SRobert Watson { 44584d61770SRobert Watson .pr_type = SOCK_SEQPACKET, 44684d61770SRobert Watson .pr_domain = &localdomain, 44784d61770SRobert Watson 44884d61770SRobert Watson /* 44984d61770SRobert Watson * XXXRW: For now, PR_ADDR because soreceive will bump into them 45084d61770SRobert Watson * due to our use of sbappendaddr. A new sbappend variants is needed 45184d61770SRobert Watson * that supports both atomic record writes and control data. 45284d61770SRobert Watson */ 45327457983SMark Johnston .pr_flags = PR_ADDR|PR_ATOMIC|PR_CONNREQUIRED| 45427457983SMark Johnston PR_WANTRCVD|PR_RIGHTS|PR_CAPATTACH, 455e0643280SGleb Smirnoff .pr_ctloutput = &uipc_ctloutput, 45684d61770SRobert Watson .pr_usrreqs = &uipc_usrreqs_seqpacket, 45784d61770SRobert Watson }, 458e4445a03SRobert Watson }; 459e4445a03SRobert Watson 460e4445a03SRobert Watson static struct domain localdomain = { 461e4445a03SRobert Watson .dom_family = AF_LOCAL, 462e4445a03SRobert Watson .dom_name = "local", 463e4445a03SRobert Watson .dom_externalize = unp_externalize, 46499ab95dbSMark Johnston .dom_dispose = unp_dispose, 465e4445a03SRobert Watson .dom_protosw = localsw, 46602abd400SPedro F. Giffuni .dom_protoswNPROTOSW = &localsw[nitems(localsw)] 467e4445a03SRobert Watson }; 468e4445a03SRobert Watson DOMAIN_SET(local); 469e4445a03SRobert Watson 470ac45e92fSRobert Watson static void 471a29f300eSGarrett Wollman uipc_abort(struct socket *so) 472df8bae1dSRodney W. Grimes { 473e7c33e29SRobert Watson struct unpcb *unp, *unp2; 474df8bae1dSRodney W. Grimes 47540f2ac28SRobert Watson unp = sotounpcb(so); 4764d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_abort: unp == NULL")); 47775a67bf3SMatt Macy UNP_PCB_UNLOCK_ASSERT(unp); 478e7c33e29SRobert Watson 479e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 480e7c33e29SRobert Watson unp2 = unp->unp_conn; 481e7c33e29SRobert Watson if (unp2 != NULL) { 48275a67bf3SMatt Macy unp_pcb_hold(unp2); 483e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 48475a67bf3SMatt Macy unp_drop(unp2); 48575a67bf3SMatt Macy } else 48675a67bf3SMatt Macy UNP_PCB_UNLOCK(unp); 487df8bae1dSRodney W. Grimes } 488df8bae1dSRodney W. Grimes 489a29f300eSGarrett Wollman static int 49057bf258eSGarrett Wollman uipc_accept(struct socket *so, struct sockaddr **nam) 491a29f300eSGarrett Wollman { 492e7c33e29SRobert Watson struct unpcb *unp, *unp2; 4930d9ce3a1SRobert Watson const struct sockaddr *sa; 494df8bae1dSRodney W. Grimes 495df8bae1dSRodney W. Grimes /* 4961c381b19SRobert Watson * Pass back name of connected socket, if it was bound and we are 4971c381b19SRobert Watson * still connected (our peer may have closed already!). 498df8bae1dSRodney W. Grimes */ 4994d4b555eSRobert Watson unp = sotounpcb(so); 5004d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_accept: unp == NULL")); 501e7c33e29SRobert Watson 5020d9ce3a1SRobert Watson *nam = malloc(sizeof(struct sockaddr_un), M_SONAME, M_WAITOK); 50344800027SMark Johnston UNP_PCB_LOCK(unp); 50444800027SMark Johnston unp2 = unp_pcb_lock_peer(unp); 50544800027SMark Johnston if (unp2 != NULL && unp2->unp_addr != NULL) 506e7c33e29SRobert Watson sa = (struct sockaddr *)unp2->unp_addr; 50744800027SMark Johnston else 5080d9ce3a1SRobert Watson sa = &sun_noname; 5090d9ce3a1SRobert Watson bcopy(sa, *nam, sa->sa_len); 510b4e07e3dSMark Johnston if (unp2 != NULL) 51144800027SMark Johnston unp_pcb_unlock_pair(unp, unp2); 512b4e07e3dSMark Johnston else 513b4e07e3dSMark Johnston UNP_PCB_UNLOCK(unp); 514e5aeaa0cSDag-Erling Smørgrav return (0); 515a29f300eSGarrett Wollman } 516df8bae1dSRodney W. Grimes 517a29f300eSGarrett Wollman static int 518b40ce416SJulian Elischer uipc_attach(struct socket *so, int proto, struct thread *td) 519a29f300eSGarrett Wollman { 520e7c33e29SRobert Watson u_long sendspace, recvspace; 5216d32873cSRobert Watson struct unpcb *unp; 5223dab55bcSRobert Watson int error; 523779f106aSGleb Smirnoff bool locked; 524df8bae1dSRodney W. Grimes 5256d32873cSRobert Watson KASSERT(so->so_pcb == NULL, ("uipc_attach: so_pcb != NULL")); 5266d32873cSRobert Watson if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 5276d32873cSRobert Watson switch (so->so_type) { 5286d32873cSRobert Watson case SOCK_STREAM: 529e7c33e29SRobert Watson sendspace = unpst_sendspace; 530e7c33e29SRobert Watson recvspace = unpst_recvspace; 5316d32873cSRobert Watson break; 5326d32873cSRobert Watson 5336d32873cSRobert Watson case SOCK_DGRAM: 534a7444f80SGleb Smirnoff STAILQ_INIT(&so->so_rcv.uxdg_mb); 535458f475dSGleb Smirnoff STAILQ_INIT(&so->so_snd.uxdg_mb); 536458f475dSGleb Smirnoff TAILQ_INIT(&so->so_rcv.uxdg_conns); 537458f475dSGleb Smirnoff /* 538458f475dSGleb Smirnoff * Since send buffer is either bypassed or is a part 539458f475dSGleb Smirnoff * of one-to-many receive buffer, we assign both space 540458f475dSGleb Smirnoff * limits to unpdg_recvspace. 541458f475dSGleb Smirnoff */ 542458f475dSGleb Smirnoff sendspace = recvspace = unpdg_recvspace; 5436d32873cSRobert Watson break; 5446d32873cSRobert Watson 54584d61770SRobert Watson case SOCK_SEQPACKET: 54684d61770SRobert Watson sendspace = unpsp_sendspace; 54784d61770SRobert Watson recvspace = unpsp_recvspace; 54884d61770SRobert Watson break; 54984d61770SRobert Watson 5506d32873cSRobert Watson default: 551e7c33e29SRobert Watson panic("uipc_attach"); 5526d32873cSRobert Watson } 553e7c33e29SRobert Watson error = soreserve(so, sendspace, recvspace); 5546d32873cSRobert Watson if (error) 5556d32873cSRobert Watson return (error); 5566d32873cSRobert Watson } 55746a1d9bfSRobert Watson unp = uma_zalloc(unp_zone, M_NOWAIT | M_ZERO); 5586d32873cSRobert Watson if (unp == NULL) 5596d32873cSRobert Watson return (ENOBUFS); 5606d32873cSRobert Watson LIST_INIT(&unp->unp_refs); 561e7c33e29SRobert Watson UNP_PCB_LOCK_INIT(unp); 5626d32873cSRobert Watson unp->unp_socket = so; 5636d32873cSRobert Watson so->so_pcb = unp; 5645362170dSMark Johnston refcount_init(&unp->unp_refcount, 1); 565e7c33e29SRobert Watson 566779f106aSGleb Smirnoff if ((locked = UNP_LINK_WOWNED()) == false) 567779f106aSGleb Smirnoff UNP_LINK_WLOCK(); 568779f106aSGleb Smirnoff 5696d32873cSRobert Watson unp->unp_gencnt = ++unp_gencnt; 570f218ac50SMateusz Guzik unp->unp_ino = ++unp_ino; 5716d32873cSRobert Watson unp_count++; 57284d61770SRobert Watson switch (so->so_type) { 57384d61770SRobert Watson case SOCK_STREAM: 57484d61770SRobert Watson LIST_INSERT_HEAD(&unp_shead, unp, unp_link); 57584d61770SRobert Watson break; 57684d61770SRobert Watson 57784d61770SRobert Watson case SOCK_DGRAM: 57884d61770SRobert Watson LIST_INSERT_HEAD(&unp_dhead, unp, unp_link); 57984d61770SRobert Watson break; 58084d61770SRobert Watson 58184d61770SRobert Watson case SOCK_SEQPACKET: 58284d61770SRobert Watson LIST_INSERT_HEAD(&unp_sphead, unp, unp_link); 58384d61770SRobert Watson break; 58484d61770SRobert Watson 58584d61770SRobert Watson default: 58684d61770SRobert Watson panic("uipc_attach"); 58784d61770SRobert Watson } 588779f106aSGleb Smirnoff 589779f106aSGleb Smirnoff if (locked == false) 590779f106aSGleb Smirnoff UNP_LINK_WUNLOCK(); 5916d32873cSRobert Watson 5926d32873cSRobert Watson return (0); 593a29f300eSGarrett Wollman } 594a29f300eSGarrett Wollman 595a29f300eSGarrett Wollman static int 5967493f24eSPawel Jakub Dawidek uipc_bindat(int fd, struct socket *so, struct sockaddr *nam, struct thread *td) 597a29f300eSGarrett Wollman { 598dd47f5caSRobert Watson struct sockaddr_un *soun = (struct sockaddr_un *)nam; 599dd47f5caSRobert Watson struct vattr vattr; 6005050aa86SKonstantin Belousov int error, namelen; 601dd47f5caSRobert Watson struct nameidata nd; 60240f2ac28SRobert Watson struct unpcb *unp; 603dd47f5caSRobert Watson struct vnode *vp; 604dd47f5caSRobert Watson struct mount *mp; 6057008be5bSPawel Jakub Dawidek cap_rights_t rights; 606dd47f5caSRobert Watson char *buf; 607a29f300eSGarrett Wollman 608cb7df69bSKevin Lo if (nam->sa_family != AF_UNIX) 609cb7df69bSKevin Lo return (EAFNOSUPPORT); 610cb7df69bSKevin Lo 61140f2ac28SRobert Watson unp = sotounpcb(so); 6124d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_bind: unp == NULL")); 6134f1f0ef5SRobert Watson 614a06534c3SBjoern A. Zeeb if (soun->sun_len > sizeof(struct sockaddr_un)) 615a06534c3SBjoern A. Zeeb return (EINVAL); 6164f1f0ef5SRobert Watson namelen = soun->sun_len - offsetof(struct sockaddr_un, sun_path); 6174f1f0ef5SRobert Watson if (namelen <= 0) 6184f1f0ef5SRobert Watson return (EINVAL); 619dd47f5caSRobert Watson 620dd47f5caSRobert Watson /* 6214f1f0ef5SRobert Watson * We don't allow simultaneous bind() calls on a single UNIX domain 6224f1f0ef5SRobert Watson * socket, so flag in-progress operations, and return an error if an 6234f1f0ef5SRobert Watson * operation is already in progress. 6244f1f0ef5SRobert Watson * 6254f1f0ef5SRobert Watson * Historically, we have not allowed a socket to be rebound, so this 626d7924b70SRobert Watson * also returns an error. Not allowing re-binding simplifies the 627d7924b70SRobert Watson * implementation and avoids a great many possible failure modes. 628dd47f5caSRobert Watson */ 629e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 630dd47f5caSRobert Watson if (unp->unp_vnode != NULL) { 631e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 632dd47f5caSRobert Watson return (EINVAL); 633dd47f5caSRobert Watson } 6344f1f0ef5SRobert Watson if (unp->unp_flags & UNP_BINDING) { 635e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 6364f1f0ef5SRobert Watson return (EALREADY); 637dd47f5caSRobert Watson } 6384f1f0ef5SRobert Watson unp->unp_flags |= UNP_BINDING; 639e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 640dd47f5caSRobert Watson 641dd47f5caSRobert Watson buf = malloc(namelen + 1, M_TEMP, M_WAITOK); 6427928893dSEd Maste bcopy(soun->sun_path, buf, namelen); 6437928893dSEd Maste buf[namelen] = 0; 644dd47f5caSRobert Watson 645dd47f5caSRobert Watson restart: 6466c21f6edSKonstantin Belousov NDINIT_ATRIGHTS(&nd, CREATE, NOFOLLOW | LOCKPARENT | SAVENAME | NOCACHE, 6477e1d3eefSMateusz Guzik UIO_SYSSPACE, buf, fd, cap_rights_init_one(&rights, CAP_BINDAT)); 648dd47f5caSRobert Watson /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ 649dd47f5caSRobert Watson error = namei(&nd); 650dd47f5caSRobert Watson if (error) 6514f1f0ef5SRobert Watson goto error; 652dd47f5caSRobert Watson vp = nd.ni_vp; 653dd47f5caSRobert Watson if (vp != NULL || vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { 654bb92cd7bSMateusz Guzik NDFREE_PNBUF(&nd); 655dd47f5caSRobert Watson if (nd.ni_dvp == vp) 656dd47f5caSRobert Watson vrele(nd.ni_dvp); 657dd47f5caSRobert Watson else 658dd47f5caSRobert Watson vput(nd.ni_dvp); 659dd47f5caSRobert Watson if (vp != NULL) { 660dd47f5caSRobert Watson vrele(vp); 661dd47f5caSRobert Watson error = EADDRINUSE; 6624f1f0ef5SRobert Watson goto error; 663dd47f5caSRobert Watson } 664dd47f5caSRobert Watson error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH); 665dd47f5caSRobert Watson if (error) 6664f1f0ef5SRobert Watson goto error; 667dd47f5caSRobert Watson goto restart; 668dd47f5caSRobert Watson } 669dd47f5caSRobert Watson VATTR_NULL(&vattr); 670dd47f5caSRobert Watson vattr.va_type = VSOCK; 67185078b85SConrad Meyer vattr.va_mode = (ACCESSPERMS & ~td->td_proc->p_pd->pd_cmask); 672dd47f5caSRobert Watson #ifdef MAC 67330d239bcSRobert Watson error = mac_vnode_check_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd, 674dd47f5caSRobert Watson &vattr); 675dd47f5caSRobert Watson #endif 676885868cdSRobert Watson if (error == 0) 677dd47f5caSRobert Watson error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 678bb92cd7bSMateusz Guzik NDFREE_PNBUF(&nd); 679dd47f5caSRobert Watson if (error) { 6803b2aa360SKonstantin Belousov VOP_VPUT_PAIR(nd.ni_dvp, NULL, true); 681dd47f5caSRobert Watson vn_finished_write(mp); 682441eb16aSKonstantin Belousov if (error == ERELOOKUP) 683441eb16aSKonstantin Belousov goto restart; 6844f1f0ef5SRobert Watson goto error; 685dd47f5caSRobert Watson } 686dd47f5caSRobert Watson vp = nd.ni_vp; 68757fd3d55SPawel Jakub Dawidek ASSERT_VOP_ELOCKED(vp, "uipc_bind"); 688dd47f5caSRobert Watson soun = (struct sockaddr_un *)sodupsockaddr(nam, M_WAITOK); 689e7c33e29SRobert Watson 690e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 6910c3c207fSGleb Smirnoff VOP_UNP_BIND(vp, unp); 692dd47f5caSRobert Watson unp->unp_vnode = vp; 693dd47f5caSRobert Watson unp->unp_addr = soun; 6944f1f0ef5SRobert Watson unp->unp_flags &= ~UNP_BINDING; 695e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 6963b2aa360SKonstantin Belousov vref(vp); 6973b2aa360SKonstantin Belousov VOP_VPUT_PAIR(nd.ni_dvp, &vp, true); 698dd47f5caSRobert Watson vn_finished_write(mp); 6994f1f0ef5SRobert Watson free(buf, M_TEMP); 7004f1f0ef5SRobert Watson return (0); 701e7c33e29SRobert Watson 7024f1f0ef5SRobert Watson error: 703e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 7044f1f0ef5SRobert Watson unp->unp_flags &= ~UNP_BINDING; 705e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 706dd47f5caSRobert Watson free(buf, M_TEMP); 70740f2ac28SRobert Watson return (error); 708a29f300eSGarrett Wollman } 709a29f300eSGarrett Wollman 710a29f300eSGarrett Wollman static int 7117493f24eSPawel Jakub Dawidek uipc_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 7127493f24eSPawel Jakub Dawidek { 7137493f24eSPawel Jakub Dawidek 7147493f24eSPawel Jakub Dawidek return (uipc_bindat(AT_FDCWD, so, nam, td)); 7157493f24eSPawel Jakub Dawidek } 7167493f24eSPawel Jakub Dawidek 7177493f24eSPawel Jakub Dawidek static int 718b40ce416SJulian Elischer uipc_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 719a29f300eSGarrett Wollman { 7200d9ce3a1SRobert Watson int error; 721a29f300eSGarrett Wollman 722fd179ee9SRobert Watson KASSERT(td == curthread, ("uipc_connect: td != curthread")); 723fd179ee9SRobert Watson error = unp_connect(so, nam, td); 7240d9ce3a1SRobert Watson return (error); 725a29f300eSGarrett Wollman } 726a29f300eSGarrett Wollman 7277493f24eSPawel Jakub Dawidek static int 7287493f24eSPawel Jakub Dawidek uipc_connectat(int fd, struct socket *so, struct sockaddr *nam, 7297493f24eSPawel Jakub Dawidek struct thread *td) 7307493f24eSPawel Jakub Dawidek { 7317493f24eSPawel Jakub Dawidek int error; 7327493f24eSPawel Jakub Dawidek 7337493f24eSPawel Jakub Dawidek KASSERT(td == curthread, ("uipc_connectat: td != curthread")); 734315167c0SGleb Smirnoff error = unp_connectat(fd, so, nam, td, false); 7357493f24eSPawel Jakub Dawidek return (error); 7367493f24eSPawel Jakub Dawidek } 7377493f24eSPawel Jakub Dawidek 738a152f8a3SRobert Watson static void 739a152f8a3SRobert Watson uipc_close(struct socket *so) 740a152f8a3SRobert Watson { 741e7c33e29SRobert Watson struct unpcb *unp, *unp2; 742779f106aSGleb Smirnoff struct vnode *vp = NULL; 74375a67bf3SMatt Macy struct mtx *vplock; 744ccdadf1aSMark Johnston 745a152f8a3SRobert Watson unp = sotounpcb(so); 746a152f8a3SRobert Watson KASSERT(unp != NULL, ("uipc_close: unp == NULL")); 747e7c33e29SRobert Watson 74875a67bf3SMatt Macy vplock = NULL; 74975a67bf3SMatt Macy if ((vp = unp->unp_vnode) != NULL) { 75075a67bf3SMatt Macy vplock = mtx_pool_find(mtxpool_sleep, vp); 75175a67bf3SMatt Macy mtx_lock(vplock); 752e7c33e29SRobert Watson } 75375a67bf3SMatt Macy UNP_PCB_LOCK(unp); 75475a67bf3SMatt Macy if (vp && unp->unp_vnode == NULL) { 75575a67bf3SMatt Macy mtx_unlock(vplock); 75675a67bf3SMatt Macy vp = NULL; 75775a67bf3SMatt Macy } 75875a67bf3SMatt Macy if (vp != NULL) { 759779f106aSGleb Smirnoff VOP_UNP_DETACH(vp); 760779f106aSGleb Smirnoff unp->unp_vnode = NULL; 761779f106aSGleb Smirnoff } 762ccdadf1aSMark Johnston if ((unp2 = unp_pcb_lock_peer(unp)) != NULL) 763acf9fd05SMatt Macy unp_disconnect(unp, unp2); 764ccdadf1aSMark Johnston else 765e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 76675a67bf3SMatt Macy if (vp) { 76775a67bf3SMatt Macy mtx_unlock(vplock); 768779f106aSGleb Smirnoff vrele(vp); 769a152f8a3SRobert Watson } 77075a67bf3SMatt Macy } 771a152f8a3SRobert Watson 7722c899584SRobert Watson static int 773a29f300eSGarrett Wollman uipc_connect2(struct socket *so1, struct socket *so2) 774a29f300eSGarrett Wollman { 775e7c33e29SRobert Watson struct unpcb *unp, *unp2; 77608f17d14SGleb Smirnoff 77708f17d14SGleb Smirnoff if (so1->so_type != so2->so_type) 77808f17d14SGleb Smirnoff return (EPROTOTYPE); 779a29f300eSGarrett Wollman 780e7c33e29SRobert Watson unp = so1->so_pcb; 7814d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_connect2: unp == NULL")); 782e7c33e29SRobert Watson unp2 = so2->so_pcb; 783e7c33e29SRobert Watson KASSERT(unp2 != NULL, ("uipc_connect2: unp2 == NULL")); 7844820bf6aSMark Johnston unp_pcb_lock_pair(unp, unp2); 78508f17d14SGleb Smirnoff unp_connect2(so1, so2, PRU_CONNECT2); 7864820bf6aSMark Johnston unp_pcb_unlock_pair(unp, unp2); 78708f17d14SGleb Smirnoff 78808f17d14SGleb Smirnoff return (0); 789a29f300eSGarrett Wollman } 790a29f300eSGarrett Wollman 791bc725eafSRobert Watson static void 792a29f300eSGarrett Wollman uipc_detach(struct socket *so) 793a29f300eSGarrett Wollman { 794e7c33e29SRobert Watson struct unpcb *unp, *unp2; 79575a67bf3SMatt Macy struct mtx *vplock; 7966d32873cSRobert Watson struct vnode *vp; 797ccdadf1aSMark Johnston int local_unp_rights; 798a29f300eSGarrett Wollman 79940f2ac28SRobert Watson unp = sotounpcb(so); 8004d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_detach: unp == NULL")); 801e7c33e29SRobert Watson 802434ac8b6SMark Johnston vp = NULL; 803c0874c34SMatt Macy vplock = NULL; 804434ac8b6SMark Johnston 805779f106aSGleb Smirnoff UNP_LINK_WLOCK(); 8066d32873cSRobert Watson LIST_REMOVE(unp, unp_link); 807a9aa06f7SJason A. Harmening if (unp->unp_gcflag & UNPGC_DEAD) 808a9aa06f7SJason A. Harmening LIST_REMOVE(unp, unp_dead); 8096d32873cSRobert Watson unp->unp_gencnt = ++unp_gencnt; 8106d32873cSRobert Watson --unp_count; 81175a67bf3SMatt Macy UNP_LINK_WUNLOCK(); 812434ac8b6SMark Johnston 81375a67bf3SMatt Macy UNP_PCB_UNLOCK_ASSERT(unp); 81475a67bf3SMatt Macy restart: 81575a67bf3SMatt Macy if ((vp = unp->unp_vnode) != NULL) { 81675a67bf3SMatt Macy vplock = mtx_pool_find(mtxpool_sleep, vp); 81775a67bf3SMatt Macy mtx_lock(vplock); 81875a67bf3SMatt Macy } 81975a67bf3SMatt Macy UNP_PCB_LOCK(unp); 820db38b699SMark Johnston if (unp->unp_vnode != vp && unp->unp_vnode != NULL) { 821c0874c34SMatt Macy if (vplock) 82275a67bf3SMatt Macy mtx_unlock(vplock); 82375a67bf3SMatt Macy UNP_PCB_UNLOCK(unp); 82475a67bf3SMatt Macy goto restart; 82575a67bf3SMatt Macy } 8266d32873cSRobert Watson if ((vp = unp->unp_vnode) != NULL) { 827c7e41c8bSMikolaj Golub VOP_UNP_DETACH(vp); 8286d32873cSRobert Watson unp->unp_vnode = NULL; 8296d32873cSRobert Watson } 830ccdadf1aSMark Johnston if ((unp2 = unp_pcb_lock_peer(unp)) != NULL) 831e7c33e29SRobert Watson unp_disconnect(unp, unp2); 832f0317f86SMark Johnston else 83375a67bf3SMatt Macy UNP_PCB_UNLOCK(unp); 834ccdadf1aSMark Johnston 83575a67bf3SMatt Macy UNP_REF_LIST_LOCK(); 8366d32873cSRobert Watson while (!LIST_EMPTY(&unp->unp_refs)) { 8376d32873cSRobert Watson struct unpcb *ref = LIST_FIRST(&unp->unp_refs); 838e7c33e29SRobert Watson 83975a67bf3SMatt Macy unp_pcb_hold(ref); 84075a67bf3SMatt Macy UNP_REF_LIST_UNLOCK(); 84175a67bf3SMatt Macy 84275a67bf3SMatt Macy MPASS(ref != unp); 84375a67bf3SMatt Macy UNP_PCB_UNLOCK_ASSERT(ref); 844afc055d9SEd Schouten unp_drop(ref); 84575a67bf3SMatt Macy UNP_REF_LIST_LOCK(); 8466d32873cSRobert Watson } 84775a67bf3SMatt Macy UNP_REF_LIST_UNLOCK(); 848ccdadf1aSMark Johnston 84975a67bf3SMatt Macy UNP_PCB_LOCK(unp); 850397c19d1SJeff Roberson local_unp_rights = unp_rights; 8516d32873cSRobert Watson unp->unp_socket->so_pcb = NULL; 85275a67bf3SMatt Macy unp->unp_socket = NULL; 853db38b699SMark Johnston free(unp->unp_addr, M_SONAME); 854db38b699SMark Johnston unp->unp_addr = NULL; 855db38b699SMark Johnston if (!unp_pcb_rele(unp)) 8566e2faa24SRobert Watson UNP_PCB_UNLOCK(unp); 85775a67bf3SMatt Macy if (vp) { 85875a67bf3SMatt Macy mtx_unlock(vplock); 8596d32873cSRobert Watson vrele(vp); 86075a67bf3SMatt Macy } 8616d32873cSRobert Watson if (local_unp_rights) 862daee0f0bSKonstantin Belousov taskqueue_enqueue_timeout(taskqueue_thread, &unp_gc_task, -1); 863a7444f80SGleb Smirnoff 864a7444f80SGleb Smirnoff switch (so->so_type) { 865a7444f80SGleb Smirnoff case SOCK_DGRAM: 866a7444f80SGleb Smirnoff /* 867458f475dSGleb Smirnoff * Everything should have been unlinked/freed by unp_dispose() 868458f475dSGleb Smirnoff * and/or unp_disconnect(). 869a7444f80SGleb Smirnoff */ 870458f475dSGleb Smirnoff MPASS(so->so_rcv.uxdg_peeked == NULL); 871a7444f80SGleb Smirnoff MPASS(STAILQ_EMPTY(&so->so_rcv.uxdg_mb)); 872458f475dSGleb Smirnoff MPASS(TAILQ_EMPTY(&so->so_rcv.uxdg_conns)); 873458f475dSGleb Smirnoff MPASS(STAILQ_EMPTY(&so->so_snd.uxdg_mb)); 874a7444f80SGleb Smirnoff } 875a29f300eSGarrett Wollman } 876a29f300eSGarrett Wollman 877a29f300eSGarrett Wollman static int 878a29f300eSGarrett Wollman uipc_disconnect(struct socket *so) 879a29f300eSGarrett Wollman { 880e7c33e29SRobert Watson struct unpcb *unp, *unp2; 881a29f300eSGarrett Wollman 88240f2ac28SRobert Watson unp = sotounpcb(so); 8834d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_disconnect: unp == NULL")); 884e7c33e29SRobert Watson 885e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 886ccdadf1aSMark Johnston if ((unp2 = unp_pcb_lock_peer(unp)) != NULL) 88775a67bf3SMatt Macy unp_disconnect(unp, unp2); 888ccdadf1aSMark Johnston else 889ccdadf1aSMark Johnston UNP_PCB_UNLOCK(unp); 890e5aeaa0cSDag-Erling Smørgrav return (0); 891a29f300eSGarrett Wollman } 892a29f300eSGarrett Wollman 893a29f300eSGarrett Wollman static int 894d374e81eSRobert Watson uipc_listen(struct socket *so, int backlog, struct thread *td) 895a29f300eSGarrett Wollman { 89640f2ac28SRobert Watson struct unpcb *unp; 8970d9ce3a1SRobert Watson int error; 898a29f300eSGarrett Wollman 89901235012SGleb Smirnoff MPASS(so->so_type != SOCK_DGRAM); 900beb4b312SGleb Smirnoff 901bd4a39ccSMark Johnston /* 902bd4a39ccSMark Johnston * Synchronize with concurrent connection attempts. 903bd4a39ccSMark Johnston */ 904bd4a39ccSMark Johnston error = 0; 90540f2ac28SRobert Watson unp = sotounpcb(so); 906e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 907bd4a39ccSMark Johnston if (unp->unp_conn != NULL || (unp->unp_flags & UNP_CONNECTING) != 0) 908bd4a39ccSMark Johnston error = EINVAL; 909bd4a39ccSMark Johnston else if (unp->unp_vnode == NULL) 910bd4a39ccSMark Johnston error = EDESTADDRREQ; 911bd4a39ccSMark Johnston if (error != 0) { 912e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 91347a84387SEd Schouten return (error); 91440f2ac28SRobert Watson } 915e7c33e29SRobert Watson 916e7c33e29SRobert Watson SOCK_LOCK(so); 917e7c33e29SRobert Watson error = solisten_proto_check(so); 918e7c33e29SRobert Watson if (error == 0) { 919c5afec6eSDmitry Chagin cru2xt(td, &unp->unp_peercred); 920e7c33e29SRobert Watson solisten_proto(so, backlog); 921e7c33e29SRobert Watson } 922e7c33e29SRobert Watson SOCK_UNLOCK(so); 923e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 9240d9ce3a1SRobert Watson return (error); 925a29f300eSGarrett Wollman } 926a29f300eSGarrett Wollman 927a29f300eSGarrett Wollman static int 92857bf258eSGarrett Wollman uipc_peeraddr(struct socket *so, struct sockaddr **nam) 929a29f300eSGarrett Wollman { 930e7c33e29SRobert Watson struct unpcb *unp, *unp2; 9310d9ce3a1SRobert Watson const struct sockaddr *sa; 932a29f300eSGarrett Wollman 9334d4b555eSRobert Watson unp = sotounpcb(so); 9344d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_peeraddr: unp == NULL")); 935e7c33e29SRobert Watson 9360d9ce3a1SRobert Watson *nam = malloc(sizeof(struct sockaddr_un), M_SONAME, M_WAITOK); 937afd9f91cSJohn Baldwin UNP_LINK_RLOCK(); 938bdc5f6a3SHajimu UMEMOTO /* 939e7c33e29SRobert Watson * XXX: It seems that this test always fails even when connection is 940e7c33e29SRobert Watson * established. So, this else clause is added as workaround to 941e7c33e29SRobert Watson * return PF_LOCAL sockaddr. 942bdc5f6a3SHajimu UMEMOTO */ 943e7c33e29SRobert Watson unp2 = unp->unp_conn; 944e7c33e29SRobert Watson if (unp2 != NULL) { 945e7c33e29SRobert Watson UNP_PCB_LOCK(unp2); 946e7c33e29SRobert Watson if (unp2->unp_addr != NULL) 947afd9f91cSJohn Baldwin sa = (struct sockaddr *) unp2->unp_addr; 948e7c33e29SRobert Watson else 9490d9ce3a1SRobert Watson sa = &sun_noname; 9500d9ce3a1SRobert Watson bcopy(sa, *nam, sa->sa_len); 951e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp2); 952e7c33e29SRobert Watson } else { 953e7c33e29SRobert Watson sa = &sun_noname; 954e7c33e29SRobert Watson bcopy(sa, *nam, sa->sa_len); 955e7c33e29SRobert Watson } 956afd9f91cSJohn Baldwin UNP_LINK_RUNLOCK(); 957e5aeaa0cSDag-Erling Smørgrav return (0); 958a29f300eSGarrett Wollman } 959a29f300eSGarrett Wollman 960a29f300eSGarrett Wollman static int 961a29f300eSGarrett Wollman uipc_rcvd(struct socket *so, int flags) 962a29f300eSGarrett Wollman { 963e7c33e29SRobert Watson struct unpcb *unp, *unp2; 964a29f300eSGarrett Wollman struct socket *so2; 965337cc6b6SRobert Watson u_int mbcnt, sbcc; 966a29f300eSGarrett Wollman 96740f2ac28SRobert Watson unp = sotounpcb(so); 9682b21d0e8SGleb Smirnoff KASSERT(unp != NULL, ("%s: unp == NULL", __func__)); 9692b21d0e8SGleb Smirnoff KASSERT(so->so_type == SOCK_STREAM || so->so_type == SOCK_SEQPACKET, 9702b21d0e8SGleb Smirnoff ("%s: socktype %d", __func__, so->so_type)); 971e7c33e29SRobert Watson 972df8bae1dSRodney W. Grimes /* 973e7c33e29SRobert Watson * Adjust backpressure on sender and wakeup any waiting to write. 974e7c33e29SRobert Watson * 975d7924b70SRobert Watson * The unp lock is acquired to maintain the validity of the unp_conn 976d7924b70SRobert Watson * pointer; no lock on unp2 is required as unp2->unp_socket will be 977d7924b70SRobert Watson * static as long as we don't permit unp2 to disconnect from unp, 978d7924b70SRobert Watson * which is prevented by the lock on unp. We cache values from 979d7924b70SRobert Watson * so_rcv to avoid holding the so_rcv lock over the entire 980d7924b70SRobert Watson * transaction on the remote so_snd. 981df8bae1dSRodney W. Grimes */ 982337cc6b6SRobert Watson SOCKBUF_LOCK(&so->so_rcv); 983337cc6b6SRobert Watson mbcnt = so->so_rcv.sb_mbcnt; 9842b21d0e8SGleb Smirnoff sbcc = sbavail(&so->so_rcv); 985337cc6b6SRobert Watson SOCKBUF_UNLOCK(&so->so_rcv); 986c2090e73SAlan Somers /* 987c2090e73SAlan Somers * There is a benign race condition at this point. If we're planning to 988c2090e73SAlan Somers * clear SB_STOP, but uipc_send is called on the connected socket at 989c2090e73SAlan Somers * this instant, it might add data to the sockbuf and set SB_STOP. Then 990c2090e73SAlan Somers * we would erroneously clear SB_STOP below, even though the sockbuf is 991c2090e73SAlan Somers * full. The race is benign because the only ill effect is to allow the 992c2090e73SAlan Somers * sockbuf to exceed its size limit, and the size limits are not 993c2090e73SAlan Somers * strictly guaranteed anyway. 994c2090e73SAlan Somers */ 995e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 996e7c33e29SRobert Watson unp2 = unp->unp_conn; 997e7c33e29SRobert Watson if (unp2 == NULL) { 998e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 999e7c33e29SRobert Watson return (0); 1000337cc6b6SRobert Watson } 1001e7c33e29SRobert Watson so2 = unp2->unp_socket; 1002337cc6b6SRobert Watson SOCKBUF_LOCK(&so2->so_snd); 1003c2090e73SAlan Somers if (sbcc < so2->so_snd.sb_hiwat && mbcnt < so2->so_snd.sb_mbmax) 1004c2090e73SAlan Somers so2->so_snd.sb_flags &= ~SB_STOP; 10051e4d7da7SRobert Watson sowwakeup_locked(so2); 1006e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 1007e5aeaa0cSDag-Erling Smørgrav return (0); 1008a29f300eSGarrett Wollman } 1009df8bae1dSRodney W. Grimes 1010a29f300eSGarrett Wollman static int 101157bf258eSGarrett Wollman uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, 1012b40ce416SJulian Elischer struct mbuf *control, struct thread *td) 1013a29f300eSGarrett Wollman { 1014f3f49bbbSRobert Watson struct unpcb *unp, *unp2; 1015a29f300eSGarrett Wollman struct socket *so2; 1016c2090e73SAlan Somers u_int mbcnt, sbcc; 101742188bb5SMark Johnston int error; 1018a29f300eSGarrett Wollman 101940f2ac28SRobert Watson unp = sotounpcb(so); 10202b21d0e8SGleb Smirnoff KASSERT(unp != NULL, ("%s: unp == NULL", __func__)); 102134649582SGleb Smirnoff KASSERT(so->so_type == SOCK_STREAM || so->so_type == SOCK_SEQPACKET, 10222b21d0e8SGleb Smirnoff ("%s: socktype %d", __func__, so->so_type)); 1023e7c33e29SRobert Watson 102442188bb5SMark Johnston error = 0; 1025a29f300eSGarrett Wollman if (flags & PRUS_OOB) { 1026a29f300eSGarrett Wollman error = EOPNOTSUPP; 1027a29f300eSGarrett Wollman goto release; 1028a29f300eSGarrett Wollman } 10291093f164SGleb Smirnoff if (control != NULL && 10301093f164SGleb Smirnoff (error = unp_internalize(&control, td, NULL, NULL, NULL))) 1031a29f300eSGarrett Wollman goto release; 103275a67bf3SMatt Macy 103375a67bf3SMatt Macy unp2 = NULL; 1034402cc72dSDavid Greenman if ((so->so_state & SS_ISCONNECTED) == 0) { 1035fc3fcacfSRobert Watson if (nam != NULL) { 1036f384a97cSGleb Smirnoff if ((error = unp_connect(so, nam, td)) != 0) 1037f384a97cSGleb Smirnoff goto out; 1038402cc72dSDavid Greenman } else { 1039402cc72dSDavid Greenman error = ENOTCONN; 1040f384a97cSGleb Smirnoff goto out; 1041402cc72dSDavid Greenman } 1042b36871afSMark Johnston } 1043b36871afSMark Johnston 1044ccdadf1aSMark Johnston UNP_PCB_LOCK(unp); 1045ccdadf1aSMark Johnston if ((unp2 = unp_pcb_lock_peer(unp)) == NULL) { 104675a67bf3SMatt Macy UNP_PCB_UNLOCK(unp); 1047b5ff0914SRobert Watson error = ENOTCONN; 1048f384a97cSGleb Smirnoff goto out; 1049b36871afSMark Johnston } else if (so->so_snd.sb_state & SBS_CANTSENDMORE) { 1050ccdadf1aSMark Johnston unp_pcb_unlock_pair(unp, unp2); 1051b36871afSMark Johnston error = EPIPE; 1052f384a97cSGleb Smirnoff goto out; 105375a67bf3SMatt Macy } 105475a67bf3SMatt Macy UNP_PCB_UNLOCK(unp); 105575a67bf3SMatt Macy if ((so2 = unp2->unp_socket) == NULL) { 105675a67bf3SMatt Macy UNP_PCB_UNLOCK(unp2); 105775a67bf3SMatt Macy error = ENOTCONN; 1058f384a97cSGleb Smirnoff goto out; 105975a67bf3SMatt Macy } 1060a34b7046SRobert Watson SOCKBUF_LOCK(&so2->so_rcv); 10612de07e40SConrad Meyer if (unp2->unp_flags & UNP_WANTCRED_MASK) { 10626a2989fdSMatthew N. Dodd /* 10632de07e40SConrad Meyer * Credentials are passed only once on SOCK_STREAM and 10642de07e40SConrad Meyer * SOCK_SEQPACKET (LOCAL_CREDS => WANTCRED_ONESHOT), or 10652de07e40SConrad Meyer * forever (LOCAL_CREDS_PERSISTENT => WANTCRED_ALWAYS). 10666a2989fdSMatthew N. Dodd */ 10671093f164SGleb Smirnoff control = unp_addsockcred(td, control, unp2->unp_flags, NULL, 10681093f164SGleb Smirnoff NULL, NULL); 10692de07e40SConrad Meyer unp2->unp_flags &= ~UNP_WANTCRED_ONESHOT; 10706a2989fdSMatthew N. Dodd } 10715b0480f2SMark Johnston 1072df8bae1dSRodney W. Grimes /* 10735b0480f2SMark Johnston * Send to paired receive port and wake up readers. Don't 10745b0480f2SMark Johnston * check for space available in the receive buffer if we're 10755b0480f2SMark Johnston * attaching ancillary data; Unix domain sockets only check 10765b0480f2SMark Johnston * for space in the sending sockbuf, and that check is 10775b0480f2SMark Johnston * performed one level up the stack. At that level we cannot 10785b0480f2SMark Johnston * precisely account for the amount of buffer space used 10795b0480f2SMark Johnston * (e.g., because control messages are not yet internalized). 1080df8bae1dSRodney W. Grimes */ 108184d61770SRobert Watson switch (so->so_type) { 108284d61770SRobert Watson case SOCK_STREAM: 1083fc3fcacfSRobert Watson if (control != NULL) { 10845b0480f2SMark Johnston sbappendcontrol_locked(&so2->so_rcv, m, 108525f4ddfbSMark Johnston control, flags); 1086fc3fcacfSRobert Watson control = NULL; 1087e7c33e29SRobert Watson } else 1088829fae90SGleb Smirnoff sbappend_locked(&so2->so_rcv, m, flags); 108984d61770SRobert Watson break; 109084d61770SRobert Watson 1091b36871afSMark Johnston case SOCK_SEQPACKET: 10928de34a88SAlan Somers if (sbappendaddr_nospacecheck_locked(&so2->so_rcv, 1093b36871afSMark Johnston &sun_noname, m, control)) 109484d61770SRobert Watson control = NULL; 109584d61770SRobert Watson break; 109684d61770SRobert Watson } 109784d61770SRobert Watson 1098c2090e73SAlan Somers mbcnt = so2->so_rcv.sb_mbcnt; 10992b21d0e8SGleb Smirnoff sbcc = sbavail(&so2->so_rcv); 11002b21d0e8SGleb Smirnoff if (sbcc) 1101337cc6b6SRobert Watson sorwakeup_locked(so2); 11022b21d0e8SGleb Smirnoff else 11032b21d0e8SGleb Smirnoff SOCKBUF_UNLOCK(&so2->so_rcv); 1104337cc6b6SRobert Watson 1105c2090e73SAlan Somers /* 1106c2090e73SAlan Somers * The PCB lock on unp2 protects the SB_STOP flag. Without it, 1107c2090e73SAlan Somers * it would be possible for uipc_rcvd to be called at this 1108c2090e73SAlan Somers * point, drain the receiving sockbuf, clear SB_STOP, and then 1109c2090e73SAlan Somers * we would set SB_STOP below. That could lead to an empty 1110c2090e73SAlan Somers * sockbuf having SB_STOP set 1111c2090e73SAlan Somers */ 1112337cc6b6SRobert Watson SOCKBUF_LOCK(&so->so_snd); 1113c2090e73SAlan Somers if (sbcc >= so->so_snd.sb_hiwat || mbcnt >= so->so_snd.sb_mbmax) 1114c2090e73SAlan Somers so->so_snd.sb_flags |= SB_STOP; 11157abe2ac2SAlan Cox SOCKBUF_UNLOCK(&so->so_snd); 1116e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp2); 1117fc3fcacfSRobert Watson m = NULL; 1118f384a97cSGleb Smirnoff out: 11196b8fda4dSGarrett Wollman /* 112060a5ef26SRobert Watson * PRUS_EOF is equivalent to pru_send followed by pru_shutdown. 11216b8fda4dSGarrett Wollman */ 1122a29f300eSGarrett Wollman if (flags & PRUS_EOF) { 1123ede6e136SRobert Watson UNP_PCB_LOCK(unp); 11246b8fda4dSGarrett Wollman socantsendmore(so); 11256b8fda4dSGarrett Wollman unp_shutdown(unp); 1126e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 1127ede6e136SRobert Watson } 1128fc3fcacfSRobert Watson if (control != NULL && error != 0) 1129eac7f079SGleb Smirnoff unp_scan(control, unp_freerights); 1130bd508d39SDon Lewis 1131a29f300eSGarrett Wollman release: 1132fc3fcacfSRobert Watson if (control != NULL) 1133a29f300eSGarrett Wollman m_freem(control); 1134100db364SGleb Smirnoff /* 1135100db364SGleb Smirnoff * In case of PRUS_NOTREADY, uipc_ready() is responsible 1136100db364SGleb Smirnoff * for freeing memory. 1137100db364SGleb Smirnoff */ 1138100db364SGleb Smirnoff if (m != NULL && (flags & PRUS_NOTREADY) == 0) 1139a29f300eSGarrett Wollman m_freem(m); 1140e5aeaa0cSDag-Erling Smørgrav return (error); 1141a29f300eSGarrett Wollman } 1142df8bae1dSRodney W. Grimes 1143458f475dSGleb Smirnoff /* PF_UNIX/SOCK_DGRAM version of sbspace() */ 1144458f475dSGleb Smirnoff static inline bool 1145458f475dSGleb Smirnoff uipc_dgram_sbspace(struct sockbuf *sb, u_int cc, u_int mbcnt) 1146458f475dSGleb Smirnoff { 1147458f475dSGleb Smirnoff u_int bleft, mleft; 1148458f475dSGleb Smirnoff 1149458f475dSGleb Smirnoff MPASS(sb->sb_hiwat >= sb->uxdg_cc); 1150458f475dSGleb Smirnoff MPASS(sb->sb_mbmax >= sb->uxdg_mbcnt); 1151458f475dSGleb Smirnoff 1152458f475dSGleb Smirnoff if (__predict_false(sb->sb_state & SBS_CANTRCVMORE)) 1153458f475dSGleb Smirnoff return (false); 1154458f475dSGleb Smirnoff 1155458f475dSGleb Smirnoff bleft = sb->sb_hiwat - sb->uxdg_cc; 1156458f475dSGleb Smirnoff mleft = sb->sb_mbmax - sb->uxdg_mbcnt; 1157458f475dSGleb Smirnoff 1158458f475dSGleb Smirnoff return (bleft >= cc && mleft >= mbcnt); 1159458f475dSGleb Smirnoff } 1160458f475dSGleb Smirnoff 116134649582SGleb Smirnoff /* 116234649582SGleb Smirnoff * PF_UNIX/SOCK_DGRAM send 11635dc8dd5fSGleb Smirnoff * 11645dc8dd5fSGleb Smirnoff * Allocate a record consisting of 3 mbufs in the sequence of 11655dc8dd5fSGleb Smirnoff * from -> control -> data and append it to the socket buffer. 11661093f164SGleb Smirnoff * 11671093f164SGleb Smirnoff * The first mbuf carries sender's name and is a pkthdr that stores 11681093f164SGleb Smirnoff * overall length of datagram, its memory consumption and control length. 116934649582SGleb Smirnoff */ 11701093f164SGleb Smirnoff #define ctllen PH_loc.thirtytwo[1] 11711093f164SGleb Smirnoff _Static_assert(offsetof(struct pkthdr, memlen) + sizeof(u_int) <= 11721093f164SGleb Smirnoff offsetof(struct pkthdr, ctllen), "unix/dgram can not store ctllen"); 117334649582SGleb Smirnoff static int 117434649582SGleb Smirnoff uipc_sosend_dgram(struct socket *so, struct sockaddr *addr, struct uio *uio, 117534649582SGleb Smirnoff struct mbuf *m, struct mbuf *c, int flags, struct thread *td) 117634649582SGleb Smirnoff { 117734649582SGleb Smirnoff struct unpcb *unp, *unp2; 117834649582SGleb Smirnoff const struct sockaddr *from; 117934649582SGleb Smirnoff struct socket *so2; 11805dc8dd5fSGleb Smirnoff struct sockbuf *sb; 11811093f164SGleb Smirnoff struct mbuf *f, *clast; 11821093f164SGleb Smirnoff u_int cc, ctl, mbcnt; 11831093f164SGleb Smirnoff u_int dcc __diagused, dctl __diagused, dmbcnt __diagused; 1184a7444f80SGleb Smirnoff int error; 118534649582SGleb Smirnoff 118634649582SGleb Smirnoff MPASS((uio != NULL && m == NULL) || (m != NULL && uio == NULL)); 118734649582SGleb Smirnoff 118834649582SGleb Smirnoff error = 0; 11895dc8dd5fSGleb Smirnoff f = NULL; 11901093f164SGleb Smirnoff ctl = 0; 119134649582SGleb Smirnoff 119234649582SGleb Smirnoff if (__predict_false(flags & MSG_OOB)) { 119334649582SGleb Smirnoff error = EOPNOTSUPP; 119434649582SGleb Smirnoff goto out; 119534649582SGleb Smirnoff } 119634649582SGleb Smirnoff if (m == NULL) { 119734649582SGleb Smirnoff if (__predict_false(uio->uio_resid > unpdg_maxdgram)) { 119834649582SGleb Smirnoff error = EMSGSIZE; 119934649582SGleb Smirnoff goto out; 120034649582SGleb Smirnoff } 120134649582SGleb Smirnoff m = m_uiotombuf(uio, M_WAITOK, 0, max_hdr, M_PKTHDR); 120234649582SGleb Smirnoff if (__predict_false(m == NULL)) { 120334649582SGleb Smirnoff error = EFAULT; 120434649582SGleb Smirnoff goto out; 120534649582SGleb Smirnoff } 12061093f164SGleb Smirnoff f = m_gethdr(M_WAITOK, MT_SONAME); 12071093f164SGleb Smirnoff cc = m->m_pkthdr.len; 12081093f164SGleb Smirnoff mbcnt = MSIZE + m->m_pkthdr.memlen; 12091093f164SGleb Smirnoff if (c != NULL && 12101093f164SGleb Smirnoff (error = unp_internalize(&c, td, &clast, &ctl, &mbcnt))) 121134649582SGleb Smirnoff goto out; 121234649582SGleb Smirnoff } else { 121334649582SGleb Smirnoff /* pru_sosend() with mbuf usually is a kernel thread. */ 121434649582SGleb Smirnoff 121534649582SGleb Smirnoff M_ASSERTPKTHDR(m); 121634649582SGleb Smirnoff if (__predict_false(c != NULL)) 121734649582SGleb Smirnoff panic("%s: control from a kernel thread", __func__); 121834649582SGleb Smirnoff 121934649582SGleb Smirnoff if (__predict_false(m->m_pkthdr.len > unpdg_maxdgram)) { 122034649582SGleb Smirnoff error = EMSGSIZE; 122134649582SGleb Smirnoff goto out; 122234649582SGleb Smirnoff } 12231093f164SGleb Smirnoff if ((f = m_gethdr(M_NOWAIT, MT_SONAME)) == NULL) { 12245dc8dd5fSGleb Smirnoff error = ENOBUFS; 12255dc8dd5fSGleb Smirnoff goto out; 12265dc8dd5fSGleb Smirnoff } 122734649582SGleb Smirnoff /* Condition the foreign mbuf to our standards. */ 122834649582SGleb Smirnoff m_clrprotoflags(m); 122934649582SGleb Smirnoff m_tag_delete_chain(m, NULL); 123034649582SGleb Smirnoff m->m_pkthdr.rcvif = NULL; 123134649582SGleb Smirnoff m->m_pkthdr.flowid = 0; 123234649582SGleb Smirnoff m->m_pkthdr.csum_flags = 0; 123334649582SGleb Smirnoff m->m_pkthdr.fibnum = 0; 123434649582SGleb Smirnoff m->m_pkthdr.rsstype = 0; 12351093f164SGleb Smirnoff 12361093f164SGleb Smirnoff cc = m->m_pkthdr.len; 12371093f164SGleb Smirnoff mbcnt = MSIZE; 12381093f164SGleb Smirnoff for (struct mbuf *mb = m; mb != NULL; mb = mb->m_next) { 12391093f164SGleb Smirnoff mbcnt += MSIZE; 12401093f164SGleb Smirnoff if (mb->m_flags & M_EXT) 12411093f164SGleb Smirnoff mbcnt += mb->m_ext.ext_size; 12421093f164SGleb Smirnoff } 124334649582SGleb Smirnoff } 124434649582SGleb Smirnoff 124534649582SGleb Smirnoff unp = sotounpcb(so); 124634649582SGleb Smirnoff MPASS(unp); 124734649582SGleb Smirnoff 124834649582SGleb Smirnoff /* 124934649582SGleb Smirnoff * XXXGL: would be cool to fully remove so_snd out of the equation 125034649582SGleb Smirnoff * and avoid this lock, which is not only extraneous, but also being 125134649582SGleb Smirnoff * released, thus still leaving possibility for a race. We can easily 125234649582SGleb Smirnoff * handle SBS_CANTSENDMORE/SS_ISCONNECTED complement in unpcb, but it 125334649582SGleb Smirnoff * is more difficult to invent something to handle so_error. 125434649582SGleb Smirnoff */ 125534649582SGleb Smirnoff error = SOCK_IO_SEND_LOCK(so, SBLOCKWAIT(flags)); 125634649582SGleb Smirnoff if (error) 125734649582SGleb Smirnoff goto out2; 1258a7444f80SGleb Smirnoff SOCK_SENDBUF_LOCK(so); 125934649582SGleb Smirnoff if (so->so_snd.sb_state & SBS_CANTSENDMORE) { 126034649582SGleb Smirnoff SOCK_SENDBUF_UNLOCK(so); 126134649582SGleb Smirnoff error = EPIPE; 126234649582SGleb Smirnoff goto out3; 126334649582SGleb Smirnoff } 126434649582SGleb Smirnoff if (so->so_error != 0) { 126534649582SGleb Smirnoff error = so->so_error; 126634649582SGleb Smirnoff so->so_error = 0; 1267a7444f80SGleb Smirnoff SOCK_SENDBUF_UNLOCK(so); 126834649582SGleb Smirnoff goto out3; 126934649582SGleb Smirnoff } 127034649582SGleb Smirnoff if (((so->so_state & SS_ISCONNECTED) == 0) && addr == NULL) { 1271a7444f80SGleb Smirnoff SOCK_SENDBUF_UNLOCK(so); 127234649582SGleb Smirnoff error = EDESTADDRREQ; 127334649582SGleb Smirnoff goto out3; 127434649582SGleb Smirnoff } 1275a7444f80SGleb Smirnoff SOCK_SENDBUF_UNLOCK(so); 127634649582SGleb Smirnoff 1277315167c0SGleb Smirnoff if (addr != NULL) { 1278315167c0SGleb Smirnoff if ((error = unp_connectat(AT_FDCWD, so, addr, td, true))) 127934649582SGleb Smirnoff goto out3; 1280315167c0SGleb Smirnoff UNP_PCB_LOCK_ASSERT(unp); 1281315167c0SGleb Smirnoff unp2 = unp->unp_conn; 1282315167c0SGleb Smirnoff UNP_PCB_LOCK_ASSERT(unp2); 1283315167c0SGleb Smirnoff } else { 128434649582SGleb Smirnoff UNP_PCB_LOCK(unp); 128534649582SGleb Smirnoff unp2 = unp_pcb_lock_peer(unp); 128634649582SGleb Smirnoff if (unp2 == NULL) { 128734649582SGleb Smirnoff UNP_PCB_UNLOCK(unp); 128834649582SGleb Smirnoff error = ENOTCONN; 128934649582SGleb Smirnoff goto out3; 129034649582SGleb Smirnoff } 1291315167c0SGleb Smirnoff } 129234649582SGleb Smirnoff 129334649582SGleb Smirnoff if (unp2->unp_flags & UNP_WANTCRED_MASK) 12941093f164SGleb Smirnoff c = unp_addsockcred(td, c, unp2->unp_flags, &clast, &ctl, 12951093f164SGleb Smirnoff &mbcnt); 129634649582SGleb Smirnoff if (unp->unp_addr != NULL) 129734649582SGleb Smirnoff from = (struct sockaddr *)unp->unp_addr; 129834649582SGleb Smirnoff else 129934649582SGleb Smirnoff from = &sun_noname; 13005dc8dd5fSGleb Smirnoff f->m_len = from->sa_len; 13015dc8dd5fSGleb Smirnoff MPASS(from->sa_len <= MLEN); 13025dc8dd5fSGleb Smirnoff bcopy(from, mtod(f, void *), from->sa_len); 13031093f164SGleb Smirnoff ctl += f->m_len; 1304a7444f80SGleb Smirnoff 13051093f164SGleb Smirnoff /* 13061093f164SGleb Smirnoff * Concatenate mbufs: from -> control -> data. 13071093f164SGleb Smirnoff * Save overall cc and mbcnt in "from" mbuf. 13081093f164SGleb Smirnoff */ 13095dc8dd5fSGleb Smirnoff if (c != NULL) { 13101093f164SGleb Smirnoff #ifdef INVARIANTS 13111093f164SGleb Smirnoff struct mbuf *mc; 1312a7444f80SGleb Smirnoff 13131093f164SGleb Smirnoff for (mc = c; mc->m_next != NULL; mc = mc->m_next); 13141093f164SGleb Smirnoff MPASS(mc == clast); 13151093f164SGleb Smirnoff #endif 13165dc8dd5fSGleb Smirnoff f->m_next = c; 13175dc8dd5fSGleb Smirnoff clast->m_next = m; 1318a7444f80SGleb Smirnoff c = NULL; 13195dc8dd5fSGleb Smirnoff } else 13205dc8dd5fSGleb Smirnoff f->m_next = m; 1321a7444f80SGleb Smirnoff m = NULL; 13221093f164SGleb Smirnoff #ifdef INVARIANTS 13231093f164SGleb Smirnoff dcc = dctl = dmbcnt = 0; 13241093f164SGleb Smirnoff for (struct mbuf *mb = f; mb != NULL; mb = mb->m_next) { 13251093f164SGleb Smirnoff if (mb->m_type == MT_DATA) 13261093f164SGleb Smirnoff dcc += mb->m_len; 13271093f164SGleb Smirnoff else 13281093f164SGleb Smirnoff dctl += mb->m_len; 13291093f164SGleb Smirnoff dmbcnt += MSIZE; 13301093f164SGleb Smirnoff if (mb->m_flags & M_EXT) 13311093f164SGleb Smirnoff dmbcnt += mb->m_ext.ext_size; 13321093f164SGleb Smirnoff } 13331093f164SGleb Smirnoff MPASS(dcc == cc); 13341093f164SGleb Smirnoff MPASS(dctl == ctl); 13351093f164SGleb Smirnoff MPASS(dmbcnt == mbcnt); 13361093f164SGleb Smirnoff #endif 13371093f164SGleb Smirnoff f->m_pkthdr.len = cc + ctl; 13381093f164SGleb Smirnoff f->m_pkthdr.memlen = mbcnt; 13391093f164SGleb Smirnoff f->m_pkthdr.ctllen = ctl; 1340a7444f80SGleb Smirnoff 1341458f475dSGleb Smirnoff /* 1342458f475dSGleb Smirnoff * Destination socket buffer selection. 1343458f475dSGleb Smirnoff * 1344458f475dSGleb Smirnoff * Unconnected sends, when !(so->so_state & SS_ISCONNECTED) and the 1345458f475dSGleb Smirnoff * destination address is supplied, create a temporary connection for 1346458f475dSGleb Smirnoff * the run time of the function (see call to unp_connectat() above and 1347458f475dSGleb Smirnoff * to unp_disconnect() below). We distinguish them by condition of 1348458f475dSGleb Smirnoff * (addr != NULL). We intentionally avoid adding 'bool connected' for 1349458f475dSGleb Smirnoff * that condition, since, again, through the run time of this code we 1350458f475dSGleb Smirnoff * are always connected. For such "unconnected" sends, the destination 1351458f475dSGleb Smirnoff * buffer would be the receive buffer of destination socket so2. 1352458f475dSGleb Smirnoff * 1353458f475dSGleb Smirnoff * For connected sends, data lands on the send buffer of the sender's 1354458f475dSGleb Smirnoff * socket "so". Then, if we just added the very first datagram 1355458f475dSGleb Smirnoff * on this send buffer, we need to add the send buffer on to the 1356458f475dSGleb Smirnoff * receiving socket's buffer list. We put ourselves on top of the 1357458f475dSGleb Smirnoff * list. Such logic gives infrequent senders priority over frequent 1358458f475dSGleb Smirnoff * senders. 1359458f475dSGleb Smirnoff * 1360458f475dSGleb Smirnoff * Note on byte count management. As long as event methods kevent(2), 1361458f475dSGleb Smirnoff * select(2) are not protocol specific (yet), we need to maintain 1362458f475dSGleb Smirnoff * meaningful values on the receive buffer. So, the receive buffer 1363458f475dSGleb Smirnoff * would accumulate counters from all connected buffers potentially 1364458f475dSGleb Smirnoff * having sb_ccc > sb_hiwat or sb_mbcnt > sb_mbmax. 1365458f475dSGleb Smirnoff */ 1366a7444f80SGleb Smirnoff so2 = unp2->unp_socket; 1367458f475dSGleb Smirnoff sb = (addr == NULL) ? &so->so_snd : &so2->so_rcv; 1368a7444f80SGleb Smirnoff SOCK_RECVBUF_LOCK(so2); 1369458f475dSGleb Smirnoff if (uipc_dgram_sbspace(sb, cc + ctl, mbcnt)) { 1370458f475dSGleb Smirnoff if (addr == NULL && STAILQ_EMPTY(&sb->uxdg_mb)) 1371458f475dSGleb Smirnoff TAILQ_INSERT_HEAD(&so2->so_rcv.uxdg_conns, &so->so_snd, 1372458f475dSGleb Smirnoff uxdg_clist); 1373a7444f80SGleb Smirnoff STAILQ_INSERT_TAIL(&sb->uxdg_mb, f, m_stailqpkt); 1374458f475dSGleb Smirnoff sb->uxdg_cc += cc + ctl; 1375458f475dSGleb Smirnoff sb->uxdg_ctl += ctl; 1376458f475dSGleb Smirnoff sb->uxdg_mbcnt += mbcnt; 1377458f475dSGleb Smirnoff so2->so_rcv.sb_acc += cc + ctl; 1378458f475dSGleb Smirnoff so2->so_rcv.sb_ccc += cc + ctl; 1379458f475dSGleb Smirnoff so2->so_rcv.sb_ctl += ctl; 1380458f475dSGleb Smirnoff so2->so_rcv.sb_mbcnt += mbcnt; 138134649582SGleb Smirnoff sorwakeup_locked(so2); 13821093f164SGleb Smirnoff f = NULL; 138334649582SGleb Smirnoff } else { 138434649582SGleb Smirnoff soroverflow_locked(so2); 138534649582SGleb Smirnoff error = (so->so_state & SS_NBIO) ? EAGAIN : ENOBUFS; 138634649582SGleb Smirnoff } 138734649582SGleb Smirnoff 138834649582SGleb Smirnoff if (addr != NULL) 138934649582SGleb Smirnoff unp_disconnect(unp, unp2); 139034649582SGleb Smirnoff else 139134649582SGleb Smirnoff unp_pcb_unlock_pair(unp, unp2); 139234649582SGleb Smirnoff 139334649582SGleb Smirnoff td->td_ru.ru_msgsnd++; 139434649582SGleb Smirnoff 139534649582SGleb Smirnoff out3: 139634649582SGleb Smirnoff SOCK_IO_SEND_UNLOCK(so); 139734649582SGleb Smirnoff out2: 139834649582SGleb Smirnoff if (c) 139934649582SGleb Smirnoff unp_scan(c, unp_freerights); 140034649582SGleb Smirnoff out: 14015dc8dd5fSGleb Smirnoff if (f) 1402a7444f80SGleb Smirnoff m_freem(f); 140334649582SGleb Smirnoff if (c) 140434649582SGleb Smirnoff m_freem(c); 140534649582SGleb Smirnoff if (m) 140634649582SGleb Smirnoff m_freem(m); 140734649582SGleb Smirnoff 140834649582SGleb Smirnoff return (error); 140934649582SGleb Smirnoff } 141034649582SGleb Smirnoff 1411e3fbbf96SGleb Smirnoff /* 1412458f475dSGleb Smirnoff * PF_UNIX/SOCK_DGRAM receive with MSG_PEEK. 1413458f475dSGleb Smirnoff * The mbuf has already been unlinked from the uxdg_mb of socket buffer 1414458f475dSGleb Smirnoff * and needs to be linked onto uxdg_peeked of receive socket buffer. 1415e3fbbf96SGleb Smirnoff */ 1416e3fbbf96SGleb Smirnoff static int 1417458f475dSGleb Smirnoff uipc_peek_dgram(struct socket *so, struct mbuf *m, struct sockaddr **psa, 1418458f475dSGleb Smirnoff struct uio *uio, struct mbuf **controlp, int *flagsp) 1419e3fbbf96SGleb Smirnoff { 1420*be1f485dSAlexander V. Chernikov ssize_t len = 0; 1421e3fbbf96SGleb Smirnoff int error; 1422e3fbbf96SGleb Smirnoff 1423458f475dSGleb Smirnoff so->so_rcv.uxdg_peeked = m; 1424458f475dSGleb Smirnoff so->so_rcv.uxdg_cc += m->m_pkthdr.len; 1425458f475dSGleb Smirnoff so->so_rcv.uxdg_ctl += m->m_pkthdr.ctllen; 1426458f475dSGleb Smirnoff so->so_rcv.uxdg_mbcnt += m->m_pkthdr.memlen; 1427a7444f80SGleb Smirnoff SOCK_RECVBUF_UNLOCK(so); 1428e3fbbf96SGleb Smirnoff 1429e3fbbf96SGleb Smirnoff KASSERT(m->m_type == MT_SONAME, ("m->m_type == %d", m->m_type)); 1430e3fbbf96SGleb Smirnoff if (psa != NULL) 1431e3fbbf96SGleb Smirnoff *psa = sodupsockaddr(mtod(m, struct sockaddr *), M_WAITOK); 1432e3fbbf96SGleb Smirnoff 1433a7444f80SGleb Smirnoff m = m->m_next; 1434a7444f80SGleb Smirnoff KASSERT(m, ("%s: no data or control after soname", __func__)); 1435e3fbbf96SGleb Smirnoff 1436e3fbbf96SGleb Smirnoff /* 1437e3fbbf96SGleb Smirnoff * With MSG_PEEK the control isn't executed, just copied. 1438e3fbbf96SGleb Smirnoff */ 1439e3fbbf96SGleb Smirnoff while (m != NULL && m->m_type == MT_CONTROL) { 1440e3fbbf96SGleb Smirnoff if (controlp != NULL) { 1441e3fbbf96SGleb Smirnoff *controlp = m_copym(m, 0, m->m_len, M_WAITOK); 1442e3fbbf96SGleb Smirnoff controlp = &(*controlp)->m_next; 1443e3fbbf96SGleb Smirnoff } 1444e3fbbf96SGleb Smirnoff m = m->m_next; 1445e3fbbf96SGleb Smirnoff } 1446e3fbbf96SGleb Smirnoff KASSERT(m == NULL || m->m_type == MT_DATA, 1447e3fbbf96SGleb Smirnoff ("%s: not MT_DATA mbuf %p", __func__, m)); 1448e3fbbf96SGleb Smirnoff while (m != NULL && uio->uio_resid > 0) { 1449e3fbbf96SGleb Smirnoff len = uio->uio_resid; 1450e3fbbf96SGleb Smirnoff if (len > m->m_len) 1451e3fbbf96SGleb Smirnoff len = m->m_len; 1452e3fbbf96SGleb Smirnoff error = uiomove(mtod(m, char *), (int)len, uio); 1453e3fbbf96SGleb Smirnoff if (error) { 1454e3fbbf96SGleb Smirnoff SOCK_IO_RECV_UNLOCK(so); 1455e3fbbf96SGleb Smirnoff return (error); 1456e3fbbf96SGleb Smirnoff } 1457e3fbbf96SGleb Smirnoff if (len == m->m_len) 1458e3fbbf96SGleb Smirnoff m = m->m_next; 1459e3fbbf96SGleb Smirnoff } 1460e3fbbf96SGleb Smirnoff SOCK_IO_RECV_UNLOCK(so); 1461e3fbbf96SGleb Smirnoff 1462*be1f485dSAlexander V. Chernikov if (flagsp != NULL) { 1463*be1f485dSAlexander V. Chernikov if (m != NULL) { 1464*be1f485dSAlexander V. Chernikov if (*flagsp & MSG_TRUNC) { 1465*be1f485dSAlexander V. Chernikov /* Report real length of the packet */ 1466*be1f485dSAlexander V. Chernikov uio->uio_resid -= m_length(m, NULL) - len; 1467*be1f485dSAlexander V. Chernikov } 1468e3fbbf96SGleb Smirnoff *flagsp |= MSG_TRUNC; 1469*be1f485dSAlexander V. Chernikov } else 1470*be1f485dSAlexander V. Chernikov *flagsp &= ~MSG_TRUNC; 1471*be1f485dSAlexander V. Chernikov } 1472e3fbbf96SGleb Smirnoff 1473e3fbbf96SGleb Smirnoff return (0); 1474e3fbbf96SGleb Smirnoff } 1475e3fbbf96SGleb Smirnoff 1476e3fbbf96SGleb Smirnoff /* 1477e3fbbf96SGleb Smirnoff * PF_UNIX/SOCK_DGRAM receive 1478e3fbbf96SGleb Smirnoff */ 1479e3fbbf96SGleb Smirnoff static int 1480e3fbbf96SGleb Smirnoff uipc_soreceive_dgram(struct socket *so, struct sockaddr **psa, struct uio *uio, 1481e3fbbf96SGleb Smirnoff struct mbuf **mp0, struct mbuf **controlp, int *flagsp) 1482e3fbbf96SGleb Smirnoff { 1483458f475dSGleb Smirnoff struct sockbuf *sb = NULL; 14841093f164SGleb Smirnoff struct mbuf *m; 1485e3fbbf96SGleb Smirnoff int flags, error; 1486*be1f485dSAlexander V. Chernikov ssize_t len = 0; 1487e3fbbf96SGleb Smirnoff bool nonblock; 1488e3fbbf96SGleb Smirnoff 1489e3fbbf96SGleb Smirnoff MPASS(mp0 == NULL); 1490e3fbbf96SGleb Smirnoff 1491e3fbbf96SGleb Smirnoff if (psa != NULL) 1492e3fbbf96SGleb Smirnoff *psa = NULL; 1493e3fbbf96SGleb Smirnoff if (controlp != NULL) 1494e3fbbf96SGleb Smirnoff *controlp = NULL; 1495e3fbbf96SGleb Smirnoff 1496e3fbbf96SGleb Smirnoff flags = flagsp != NULL ? *flagsp : 0; 1497e3fbbf96SGleb Smirnoff nonblock = (so->so_state & SS_NBIO) || 1498e3fbbf96SGleb Smirnoff (flags & (MSG_DONTWAIT | MSG_NBIO)); 1499e3fbbf96SGleb Smirnoff 1500e3fbbf96SGleb Smirnoff error = SOCK_IO_RECV_LOCK(so, SBLOCKWAIT(flags)); 1501e3fbbf96SGleb Smirnoff if (__predict_false(error)) 1502e3fbbf96SGleb Smirnoff return (error); 1503e3fbbf96SGleb Smirnoff 1504e3fbbf96SGleb Smirnoff /* 1505458f475dSGleb Smirnoff * Loop blocking while waiting for a datagram. Prioritize connected 1506458f475dSGleb Smirnoff * peers over unconnected sends. Set sb to selected socket buffer 1507458f475dSGleb Smirnoff * containing an mbuf on exit from the wait loop. A datagram that 1508458f475dSGleb Smirnoff * had already been peeked at has top priority. 1509e3fbbf96SGleb Smirnoff */ 1510e3fbbf96SGleb Smirnoff SOCK_RECVBUF_LOCK(so); 1511458f475dSGleb Smirnoff while ((m = so->so_rcv.uxdg_peeked) == NULL && 1512458f475dSGleb Smirnoff (sb = TAILQ_FIRST(&so->so_rcv.uxdg_conns)) == NULL && 1513458f475dSGleb Smirnoff (m = STAILQ_FIRST(&so->so_rcv.uxdg_mb)) == NULL) { 1514e3fbbf96SGleb Smirnoff if (so->so_error) { 1515e3fbbf96SGleb Smirnoff error = so->so_error; 1516e3fbbf96SGleb Smirnoff so->so_error = 0; 1517a7444f80SGleb Smirnoff SOCK_RECVBUF_UNLOCK(so); 1518e3fbbf96SGleb Smirnoff SOCK_IO_RECV_UNLOCK(so); 1519e3fbbf96SGleb Smirnoff return (error); 1520e3fbbf96SGleb Smirnoff } 1521e3fbbf96SGleb Smirnoff if (so->so_rcv.sb_state & SBS_CANTRCVMORE || 1522e3fbbf96SGleb Smirnoff uio->uio_resid == 0) { 1523a7444f80SGleb Smirnoff SOCK_RECVBUF_UNLOCK(so); 1524e3fbbf96SGleb Smirnoff SOCK_IO_RECV_UNLOCK(so); 1525e3fbbf96SGleb Smirnoff return (0); 1526e3fbbf96SGleb Smirnoff } 1527e3fbbf96SGleb Smirnoff if (nonblock) { 1528a7444f80SGleb Smirnoff SOCK_RECVBUF_UNLOCK(so); 1529e3fbbf96SGleb Smirnoff SOCK_IO_RECV_UNLOCK(so); 1530e3fbbf96SGleb Smirnoff return (EWOULDBLOCK); 1531e3fbbf96SGleb Smirnoff } 1532e3fbbf96SGleb Smirnoff error = sbwait(so, SO_RCV); 1533e3fbbf96SGleb Smirnoff if (error) { 1534a7444f80SGleb Smirnoff SOCK_RECVBUF_UNLOCK(so); 1535e3fbbf96SGleb Smirnoff SOCK_IO_RECV_UNLOCK(so); 1536e3fbbf96SGleb Smirnoff return (error); 1537e3fbbf96SGleb Smirnoff } 1538e3fbbf96SGleb Smirnoff } 15391093f164SGleb Smirnoff 1540458f475dSGleb Smirnoff if (sb == NULL) 1541458f475dSGleb Smirnoff sb = &so->so_rcv; 1542458f475dSGleb Smirnoff else if (m == NULL) 1543458f475dSGleb Smirnoff m = STAILQ_FIRST(&sb->uxdg_mb); 1544458f475dSGleb Smirnoff else 1545458f475dSGleb Smirnoff MPASS(m == so->so_rcv.uxdg_peeked); 1546458f475dSGleb Smirnoff 1547458f475dSGleb Smirnoff MPASS(sb->uxdg_cc > 0); 15481093f164SGleb Smirnoff M_ASSERTPKTHDR(m); 15491093f164SGleb Smirnoff KASSERT(m->m_type == MT_SONAME, ("m->m_type == %d", m->m_type)); 1550e3fbbf96SGleb Smirnoff 1551e3fbbf96SGleb Smirnoff if (uio->uio_td) 1552e3fbbf96SGleb Smirnoff uio->uio_td->td_ru.ru_msgrcv++; 1553e3fbbf96SGleb Smirnoff 1554458f475dSGleb Smirnoff if (__predict_true(m != so->so_rcv.uxdg_peeked)) { 1555458f475dSGleb Smirnoff STAILQ_REMOVE_HEAD(&sb->uxdg_mb, m_stailqpkt); 1556458f475dSGleb Smirnoff if (STAILQ_EMPTY(&sb->uxdg_mb) && sb != &so->so_rcv) 1557458f475dSGleb Smirnoff TAILQ_REMOVE(&so->so_rcv.uxdg_conns, sb, uxdg_clist); 1558458f475dSGleb Smirnoff } else 1559458f475dSGleb Smirnoff so->so_rcv.uxdg_peeked = NULL; 1560e3fbbf96SGleb Smirnoff 1561458f475dSGleb Smirnoff sb->uxdg_cc -= m->m_pkthdr.len; 1562458f475dSGleb Smirnoff sb->uxdg_ctl -= m->m_pkthdr.ctllen; 1563458f475dSGleb Smirnoff sb->uxdg_mbcnt -= m->m_pkthdr.memlen; 1564458f475dSGleb Smirnoff 1565458f475dSGleb Smirnoff if (__predict_false(flags & MSG_PEEK)) 1566458f475dSGleb Smirnoff return (uipc_peek_dgram(so, m, psa, uio, controlp, flagsp)); 1567458f475dSGleb Smirnoff 15681093f164SGleb Smirnoff so->so_rcv.sb_acc -= m->m_pkthdr.len; 15691093f164SGleb Smirnoff so->so_rcv.sb_ccc -= m->m_pkthdr.len; 15701093f164SGleb Smirnoff so->so_rcv.sb_ctl -= m->m_pkthdr.ctllen; 15711093f164SGleb Smirnoff so->so_rcv.sb_mbcnt -= m->m_pkthdr.memlen; 1572a7444f80SGleb Smirnoff SOCK_RECVBUF_UNLOCK(so); 1573e3fbbf96SGleb Smirnoff 1574e3fbbf96SGleb Smirnoff if (psa != NULL) 1575e3fbbf96SGleb Smirnoff *psa = sodupsockaddr(mtod(m, struct sockaddr *), M_WAITOK); 1576e3fbbf96SGleb Smirnoff m = m_free(m); 1577a7444f80SGleb Smirnoff KASSERT(m, ("%s: no data or control after soname", __func__)); 1578e3fbbf96SGleb Smirnoff 1579e3fbbf96SGleb Smirnoff /* 1580e3fbbf96SGleb Smirnoff * Packet to copyout() is now in 'm' and it is disconnected from the 1581e3fbbf96SGleb Smirnoff * queue. 1582e3fbbf96SGleb Smirnoff * 1583e3fbbf96SGleb Smirnoff * Process one or more MT_CONTROL mbufs present before any data mbufs 1584e3fbbf96SGleb Smirnoff * in the first mbuf chain on the socket buffer. We call into the 1585e3fbbf96SGleb Smirnoff * unp_externalize() to perform externalization (or freeing if 1586e3fbbf96SGleb Smirnoff * controlp == NULL). In some cases there can be only MT_CONTROL mbufs 1587e3fbbf96SGleb Smirnoff * without MT_DATA mbufs. 1588e3fbbf96SGleb Smirnoff */ 1589e3fbbf96SGleb Smirnoff while (m != NULL && m->m_type == MT_CONTROL) { 1590e3fbbf96SGleb Smirnoff struct mbuf *cm; 1591e3fbbf96SGleb Smirnoff 1592e3fbbf96SGleb Smirnoff /* XXXGL: unp_externalize() is also dom_externalize() KBI and 1593e3fbbf96SGleb Smirnoff * it frees whole chain, so we must disconnect the mbuf. 1594e3fbbf96SGleb Smirnoff */ 1595e3fbbf96SGleb Smirnoff cm = m; m = m->m_next; cm->m_next = NULL; 1596e3fbbf96SGleb Smirnoff error = unp_externalize(cm, controlp, flags); 1597e3fbbf96SGleb Smirnoff if (error != 0) { 1598e3fbbf96SGleb Smirnoff SOCK_IO_RECV_UNLOCK(so); 1599e3fbbf96SGleb Smirnoff unp_scan(m, unp_freerights); 1600e3fbbf96SGleb Smirnoff m_freem(m); 1601e3fbbf96SGleb Smirnoff return (error); 1602e3fbbf96SGleb Smirnoff } 1603e3fbbf96SGleb Smirnoff if (controlp != NULL) { 1604e3fbbf96SGleb Smirnoff while (*controlp != NULL) 1605e3fbbf96SGleb Smirnoff controlp = &(*controlp)->m_next; 1606e3fbbf96SGleb Smirnoff } 1607e3fbbf96SGleb Smirnoff } 1608e3fbbf96SGleb Smirnoff KASSERT(m == NULL || m->m_type == MT_DATA, 1609e3fbbf96SGleb Smirnoff ("%s: not MT_DATA mbuf %p", __func__, m)); 1610e3fbbf96SGleb Smirnoff while (m != NULL && uio->uio_resid > 0) { 1611e3fbbf96SGleb Smirnoff len = uio->uio_resid; 1612e3fbbf96SGleb Smirnoff if (len > m->m_len) 1613e3fbbf96SGleb Smirnoff len = m->m_len; 1614e3fbbf96SGleb Smirnoff error = uiomove(mtod(m, char *), (int)len, uio); 1615e3fbbf96SGleb Smirnoff if (error) { 1616e3fbbf96SGleb Smirnoff SOCK_IO_RECV_UNLOCK(so); 1617e3fbbf96SGleb Smirnoff m_freem(m); 1618e3fbbf96SGleb Smirnoff return (error); 1619e3fbbf96SGleb Smirnoff } 1620e3fbbf96SGleb Smirnoff if (len == m->m_len) 1621e3fbbf96SGleb Smirnoff m = m_free(m); 1622e3fbbf96SGleb Smirnoff else { 1623e3fbbf96SGleb Smirnoff m->m_data += len; 1624e3fbbf96SGleb Smirnoff m->m_len -= len; 1625e3fbbf96SGleb Smirnoff } 1626e3fbbf96SGleb Smirnoff } 1627e3fbbf96SGleb Smirnoff SOCK_IO_RECV_UNLOCK(so); 1628e3fbbf96SGleb Smirnoff 1629e3fbbf96SGleb Smirnoff if (m != NULL) { 1630*be1f485dSAlexander V. Chernikov if (flagsp != NULL) { 1631*be1f485dSAlexander V. Chernikov if (flags & MSG_TRUNC) { 1632*be1f485dSAlexander V. Chernikov /* Report real length of the packet */ 1633*be1f485dSAlexander V. Chernikov uio->uio_resid -= m_length(m, NULL); 1634e3fbbf96SGleb Smirnoff } 1635*be1f485dSAlexander V. Chernikov *flagsp |= MSG_TRUNC; 1636*be1f485dSAlexander V. Chernikov } 1637*be1f485dSAlexander V. Chernikov m_freem(m); 1638*be1f485dSAlexander V. Chernikov } else if (flagsp != NULL) 1639*be1f485dSAlexander V. Chernikov *flagsp &= ~MSG_TRUNC; 1640e3fbbf96SGleb Smirnoff 1641e3fbbf96SGleb Smirnoff return (0); 1642e3fbbf96SGleb Smirnoff } 1643e3fbbf96SGleb Smirnoff 1644a50b1900SMark Johnston static bool 1645a50b1900SMark Johnston uipc_ready_scan(struct socket *so, struct mbuf *m, int count, int *errorp) 1646a50b1900SMark Johnston { 1647a50b1900SMark Johnston struct mbuf *mb, *n; 1648a50b1900SMark Johnston struct sockbuf *sb; 1649a50b1900SMark Johnston 1650a50b1900SMark Johnston SOCK_LOCK(so); 1651a50b1900SMark Johnston if (SOLISTENING(so)) { 1652a50b1900SMark Johnston SOCK_UNLOCK(so); 1653a50b1900SMark Johnston return (false); 1654a50b1900SMark Johnston } 1655a50b1900SMark Johnston mb = NULL; 1656a50b1900SMark Johnston sb = &so->so_rcv; 1657a50b1900SMark Johnston SOCKBUF_LOCK(sb); 1658a50b1900SMark Johnston if (sb->sb_fnrdy != NULL) { 1659a50b1900SMark Johnston for (mb = sb->sb_mb, n = mb->m_nextpkt; mb != NULL;) { 1660a50b1900SMark Johnston if (mb == m) { 1661a50b1900SMark Johnston *errorp = sbready(sb, m, count); 1662a50b1900SMark Johnston break; 1663a50b1900SMark Johnston } 1664a50b1900SMark Johnston mb = mb->m_next; 1665a50b1900SMark Johnston if (mb == NULL) { 1666a50b1900SMark Johnston mb = n; 16671b778ba2SMark Johnston if (mb != NULL) 1668a50b1900SMark Johnston n = mb->m_nextpkt; 1669a50b1900SMark Johnston } 1670a50b1900SMark Johnston } 1671a50b1900SMark Johnston } 1672a50b1900SMark Johnston SOCKBUF_UNLOCK(sb); 1673a50b1900SMark Johnston SOCK_UNLOCK(so); 1674a50b1900SMark Johnston return (mb != NULL); 1675a50b1900SMark Johnston } 1676a50b1900SMark Johnston 1677a29f300eSGarrett Wollman static int 1678c80ea19bSGleb Smirnoff uipc_ready(struct socket *so, struct mbuf *m, int count) 1679c80ea19bSGleb Smirnoff { 1680c80ea19bSGleb Smirnoff struct unpcb *unp, *unp2; 1681c80ea19bSGleb Smirnoff struct socket *so2; 1682a50b1900SMark Johnston int error, i; 1683c80ea19bSGleb Smirnoff 1684c80ea19bSGleb Smirnoff unp = sotounpcb(so); 1685c80ea19bSGleb Smirnoff 1686a50b1900SMark Johnston KASSERT(so->so_type == SOCK_STREAM, 1687a50b1900SMark Johnston ("%s: unexpected socket type for %p", __func__, so)); 1688a50b1900SMark Johnston 1689a62b4665SMatt Macy UNP_PCB_LOCK(unp); 1690ccdadf1aSMark Johnston if ((unp2 = unp_pcb_lock_peer(unp)) != NULL) { 1691a62b4665SMatt Macy UNP_PCB_UNLOCK(unp); 1692c80ea19bSGleb Smirnoff so2 = unp2->unp_socket; 1693c80ea19bSGleb Smirnoff SOCKBUF_LOCK(&so2->so_rcv); 1694c80ea19bSGleb Smirnoff if ((error = sbready(&so2->so_rcv, m, count)) == 0) 1695c80ea19bSGleb Smirnoff sorwakeup_locked(so2); 1696c80ea19bSGleb Smirnoff else 1697c80ea19bSGleb Smirnoff SOCKBUF_UNLOCK(&so2->so_rcv); 1698c80ea19bSGleb Smirnoff UNP_PCB_UNLOCK(unp2); 1699c80ea19bSGleb Smirnoff return (error); 1700ccdadf1aSMark Johnston } 1701ccdadf1aSMark Johnston UNP_PCB_UNLOCK(unp); 1702a50b1900SMark Johnston 1703a50b1900SMark Johnston /* 1704a50b1900SMark Johnston * The receiving socket has been disconnected, but may still be valid. 1705a50b1900SMark Johnston * In this case, the now-ready mbufs are still present in its socket 1706a50b1900SMark Johnston * buffer, so perform an exhaustive search before giving up and freeing 1707a50b1900SMark Johnston * the mbufs. 1708a50b1900SMark Johnston */ 1709a50b1900SMark Johnston UNP_LINK_RLOCK(); 1710a50b1900SMark Johnston LIST_FOREACH(unp, &unp_shead, unp_link) { 1711a50b1900SMark Johnston if (uipc_ready_scan(unp->unp_socket, m, count, &error)) 1712a50b1900SMark Johnston break; 1713a50b1900SMark Johnston } 1714a50b1900SMark Johnston UNP_LINK_RUNLOCK(); 1715a50b1900SMark Johnston 1716a50b1900SMark Johnston if (unp == NULL) { 1717a50b1900SMark Johnston for (i = 0; i < count; i++) 1718a62b4665SMatt Macy m = m_free(m); 1719a50b1900SMark Johnston error = ECONNRESET; 1720a50b1900SMark Johnston } 1721a50b1900SMark Johnston return (error); 1722c80ea19bSGleb Smirnoff } 1723c80ea19bSGleb Smirnoff 1724c80ea19bSGleb Smirnoff static int 1725a29f300eSGarrett Wollman uipc_sense(struct socket *so, struct stat *sb) 1726a29f300eSGarrett Wollman { 1727c2090e73SAlan Somers struct unpcb *unp; 1728a29f300eSGarrett Wollman 172940f2ac28SRobert Watson unp = sotounpcb(so); 17304d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_sense: unp == NULL")); 1731e7c33e29SRobert Watson 1732a29f300eSGarrett Wollman sb->st_blksize = so->so_snd.sb_hiwat; 1733f3732fd1SPoul-Henning Kamp sb->st_dev = NODEV; 1734a29f300eSGarrett Wollman sb->st_ino = unp->unp_ino; 1735df8bae1dSRodney W. Grimes return (0); 1736a29f300eSGarrett Wollman } 1737df8bae1dSRodney W. Grimes 1738a29f300eSGarrett Wollman static int 1739a29f300eSGarrett Wollman uipc_shutdown(struct socket *so) 1740a29f300eSGarrett Wollman { 174140f2ac28SRobert Watson struct unpcb *unp; 1742df8bae1dSRodney W. Grimes 174340f2ac28SRobert Watson unp = sotounpcb(so); 17444d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_shutdown: unp == NULL")); 1745e7c33e29SRobert Watson 1746e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 1747a29f300eSGarrett Wollman socantsendmore(so); 1748a29f300eSGarrett Wollman unp_shutdown(unp); 1749e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 1750e5aeaa0cSDag-Erling Smørgrav return (0); 1751a29f300eSGarrett Wollman } 1752df8bae1dSRodney W. Grimes 1753a29f300eSGarrett Wollman static int 175457bf258eSGarrett Wollman uipc_sockaddr(struct socket *so, struct sockaddr **nam) 1755a29f300eSGarrett Wollman { 175640f2ac28SRobert Watson struct unpcb *unp; 17570d9ce3a1SRobert Watson const struct sockaddr *sa; 1758a29f300eSGarrett Wollman 17594d4b555eSRobert Watson unp = sotounpcb(so); 17604d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_sockaddr: unp == NULL")); 1761e7c33e29SRobert Watson 17620d9ce3a1SRobert Watson *nam = malloc(sizeof(struct sockaddr_un), M_SONAME, M_WAITOK); 1763e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 1764fc3fcacfSRobert Watson if (unp->unp_addr != NULL) 17650d9ce3a1SRobert Watson sa = (struct sockaddr *) unp->unp_addr; 176683f3198bSThomas Moestl else 17670d9ce3a1SRobert Watson sa = &sun_noname; 17680d9ce3a1SRobert Watson bcopy(sa, *nam, sa->sa_len); 1769e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 1770e5aeaa0cSDag-Erling Smørgrav return (0); 1771df8bae1dSRodney W. Grimes } 1772a29f300eSGarrett Wollman 1773fa9402f2SRobert Watson static struct pr_usrreqs uipc_usrreqs_dgram = { 1774756d52a1SPoul-Henning Kamp .pru_abort = uipc_abort, 1775756d52a1SPoul-Henning Kamp .pru_accept = uipc_accept, 1776756d52a1SPoul-Henning Kamp .pru_attach = uipc_attach, 1777756d52a1SPoul-Henning Kamp .pru_bind = uipc_bind, 17787493f24eSPawel Jakub Dawidek .pru_bindat = uipc_bindat, 1779756d52a1SPoul-Henning Kamp .pru_connect = uipc_connect, 17807493f24eSPawel Jakub Dawidek .pru_connectat = uipc_connectat, 1781756d52a1SPoul-Henning Kamp .pru_connect2 = uipc_connect2, 1782756d52a1SPoul-Henning Kamp .pru_detach = uipc_detach, 1783756d52a1SPoul-Henning Kamp .pru_disconnect = uipc_disconnect, 1784756d52a1SPoul-Henning Kamp .pru_peeraddr = uipc_peeraddr, 178534649582SGleb Smirnoff .pru_sosend = uipc_sosend_dgram, 1786756d52a1SPoul-Henning Kamp .pru_sense = uipc_sense, 1787756d52a1SPoul-Henning Kamp .pru_shutdown = uipc_shutdown, 1788756d52a1SPoul-Henning Kamp .pru_sockaddr = uipc_sockaddr, 1789e3fbbf96SGleb Smirnoff .pru_soreceive = uipc_soreceive_dgram, 1790fa9402f2SRobert Watson .pru_close = uipc_close, 1791fa9402f2SRobert Watson }; 1792fa9402f2SRobert Watson 179384d61770SRobert Watson static struct pr_usrreqs uipc_usrreqs_seqpacket = { 179484d61770SRobert Watson .pru_abort = uipc_abort, 179584d61770SRobert Watson .pru_accept = uipc_accept, 179684d61770SRobert Watson .pru_attach = uipc_attach, 179784d61770SRobert Watson .pru_bind = uipc_bind, 17987493f24eSPawel Jakub Dawidek .pru_bindat = uipc_bindat, 179984d61770SRobert Watson .pru_connect = uipc_connect, 18007493f24eSPawel Jakub Dawidek .pru_connectat = uipc_connectat, 180184d61770SRobert Watson .pru_connect2 = uipc_connect2, 180284d61770SRobert Watson .pru_detach = uipc_detach, 180384d61770SRobert Watson .pru_disconnect = uipc_disconnect, 180484d61770SRobert Watson .pru_listen = uipc_listen, 180584d61770SRobert Watson .pru_peeraddr = uipc_peeraddr, 180684d61770SRobert Watson .pru_rcvd = uipc_rcvd, 180784d61770SRobert Watson .pru_send = uipc_send, 180884d61770SRobert Watson .pru_sense = uipc_sense, 180984d61770SRobert Watson .pru_shutdown = uipc_shutdown, 181084d61770SRobert Watson .pru_sockaddr = uipc_sockaddr, 181184d61770SRobert Watson .pru_soreceive = soreceive_generic, /* XXX: or...? */ 181284d61770SRobert Watson .pru_close = uipc_close, 181384d61770SRobert Watson }; 181484d61770SRobert Watson 1815fa9402f2SRobert Watson static struct pr_usrreqs uipc_usrreqs_stream = { 1816fa9402f2SRobert Watson .pru_abort = uipc_abort, 1817fa9402f2SRobert Watson .pru_accept = uipc_accept, 1818fa9402f2SRobert Watson .pru_attach = uipc_attach, 1819fa9402f2SRobert Watson .pru_bind = uipc_bind, 18207493f24eSPawel Jakub Dawidek .pru_bindat = uipc_bindat, 1821fa9402f2SRobert Watson .pru_connect = uipc_connect, 18227493f24eSPawel Jakub Dawidek .pru_connectat = uipc_connectat, 1823fa9402f2SRobert Watson .pru_connect2 = uipc_connect2, 1824fa9402f2SRobert Watson .pru_detach = uipc_detach, 1825fa9402f2SRobert Watson .pru_disconnect = uipc_disconnect, 1826fa9402f2SRobert Watson .pru_listen = uipc_listen, 1827fa9402f2SRobert Watson .pru_peeraddr = uipc_peeraddr, 1828fa9402f2SRobert Watson .pru_rcvd = uipc_rcvd, 1829fa9402f2SRobert Watson .pru_send = uipc_send, 1830c80ea19bSGleb Smirnoff .pru_ready = uipc_ready, 1831fa9402f2SRobert Watson .pru_sense = uipc_sense, 1832fa9402f2SRobert Watson .pru_shutdown = uipc_shutdown, 1833fa9402f2SRobert Watson .pru_sockaddr = uipc_sockaddr, 1834fa9402f2SRobert Watson .pru_soreceive = soreceive_generic, 1835a152f8a3SRobert Watson .pru_close = uipc_close, 1836a29f300eSGarrett Wollman }; 1837df8bae1dSRodney W. Grimes 18380b36cd25SRobert Watson static int 1839892af6b9SRobert Watson uipc_ctloutput(struct socket *so, struct sockopt *sopt) 18400c1bb4fbSDima Dorfman { 184140f2ac28SRobert Watson struct unpcb *unp; 18420d9ce3a1SRobert Watson struct xucred xu; 18436a2989fdSMatthew N. Dodd int error, optval; 18446a2989fdSMatthew N. Dodd 18456e0c8e1aSKonstantin Belousov if (sopt->sopt_level != SOL_LOCAL) 184696a041b5SMatthew N. Dodd return (EINVAL); 184796a041b5SMatthew N. Dodd 18486a2989fdSMatthew N. Dodd unp = sotounpcb(so); 18494d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_ctloutput: unp == NULL")); 18506a2989fdSMatthew N. Dodd error = 0; 18510c1bb4fbSDima Dorfman switch (sopt->sopt_dir) { 18520c1bb4fbSDima Dorfman case SOPT_GET: 18530c1bb4fbSDima Dorfman switch (sopt->sopt_name) { 18540c1bb4fbSDima Dorfman case LOCAL_PEERCRED: 1855e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 18560c1bb4fbSDima Dorfman if (unp->unp_flags & UNP_HAVEPC) 18570d9ce3a1SRobert Watson xu = unp->unp_peercred; 18580c1bb4fbSDima Dorfman else { 18590c1bb4fbSDima Dorfman if (so->so_type == SOCK_STREAM) 18600c1bb4fbSDima Dorfman error = ENOTCONN; 18610c1bb4fbSDima Dorfman else 18620c1bb4fbSDima Dorfman error = EINVAL; 18630c1bb4fbSDima Dorfman } 1864e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 18650d9ce3a1SRobert Watson if (error == 0) 18660d9ce3a1SRobert Watson error = sooptcopyout(sopt, &xu, sizeof(xu)); 18670c1bb4fbSDima Dorfman break; 1868e7c33e29SRobert Watson 18696a2989fdSMatthew N. Dodd case LOCAL_CREDS: 1870a6357845SRobert Watson /* Unlocked read. */ 18712de07e40SConrad Meyer optval = unp->unp_flags & UNP_WANTCRED_ONESHOT ? 1 : 0; 18722de07e40SConrad Meyer error = sooptcopyout(sopt, &optval, sizeof(optval)); 18732de07e40SConrad Meyer break; 18742de07e40SConrad Meyer 18752de07e40SConrad Meyer case LOCAL_CREDS_PERSISTENT: 18762de07e40SConrad Meyer /* Unlocked read. */ 18772de07e40SConrad Meyer optval = unp->unp_flags & UNP_WANTCRED_ALWAYS ? 1 : 0; 18786a2989fdSMatthew N. Dodd error = sooptcopyout(sopt, &optval, sizeof(optval)); 18796a2989fdSMatthew N. Dodd break; 1880e7c33e29SRobert Watson 18816a2989fdSMatthew N. Dodd case LOCAL_CONNWAIT: 1882a6357845SRobert Watson /* Unlocked read. */ 18836a2989fdSMatthew N. Dodd optval = unp->unp_flags & UNP_CONNWAIT ? 1 : 0; 18846a2989fdSMatthew N. Dodd error = sooptcopyout(sopt, &optval, sizeof(optval)); 18856a2989fdSMatthew N. Dodd break; 1886e7c33e29SRobert Watson 18870c1bb4fbSDima Dorfman default: 18880c1bb4fbSDima Dorfman error = EOPNOTSUPP; 18890c1bb4fbSDima Dorfman break; 18900c1bb4fbSDima Dorfman } 18910c1bb4fbSDima Dorfman break; 1892e7c33e29SRobert Watson 18930c1bb4fbSDima Dorfman case SOPT_SET: 18946a2989fdSMatthew N. Dodd switch (sopt->sopt_name) { 18956a2989fdSMatthew N. Dodd case LOCAL_CREDS: 18962de07e40SConrad Meyer case LOCAL_CREDS_PERSISTENT: 18976a2989fdSMatthew N. Dodd case LOCAL_CONNWAIT: 18986a2989fdSMatthew N. Dodd error = sooptcopyin(sopt, &optval, sizeof(optval), 18996a2989fdSMatthew N. Dodd sizeof(optval)); 19006a2989fdSMatthew N. Dodd if (error) 19016a2989fdSMatthew N. Dodd break; 19026a2989fdSMatthew N. Dodd 19032de07e40SConrad Meyer #define OPTSET(bit, exclusive) do { \ 1904e7c33e29SRobert Watson UNP_PCB_LOCK(unp); \ 19052de07e40SConrad Meyer if (optval) { \ 19062de07e40SConrad Meyer if ((unp->unp_flags & (exclusive)) != 0) { \ 19072de07e40SConrad Meyer UNP_PCB_UNLOCK(unp); \ 19082de07e40SConrad Meyer error = EINVAL; \ 19092de07e40SConrad Meyer break; \ 19102de07e40SConrad Meyer } \ 19112de07e40SConrad Meyer unp->unp_flags |= (bit); \ 19122de07e40SConrad Meyer } else \ 19132de07e40SConrad Meyer unp->unp_flags &= ~(bit); \ 1914e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); \ 1915e7c33e29SRobert Watson } while (0) 19166a2989fdSMatthew N. Dodd 19176a2989fdSMatthew N. Dodd switch (sopt->sopt_name) { 19186a2989fdSMatthew N. Dodd case LOCAL_CREDS: 19192de07e40SConrad Meyer OPTSET(UNP_WANTCRED_ONESHOT, UNP_WANTCRED_ALWAYS); 19202de07e40SConrad Meyer break; 19212de07e40SConrad Meyer 19222de07e40SConrad Meyer case LOCAL_CREDS_PERSISTENT: 19232de07e40SConrad Meyer OPTSET(UNP_WANTCRED_ALWAYS, UNP_WANTCRED_ONESHOT); 19246a2989fdSMatthew N. Dodd break; 1925e7c33e29SRobert Watson 19266a2989fdSMatthew N. Dodd case LOCAL_CONNWAIT: 19272de07e40SConrad Meyer OPTSET(UNP_CONNWAIT, 0); 19286a2989fdSMatthew N. Dodd break; 1929e7c33e29SRobert Watson 19306a2989fdSMatthew N. Dodd default: 19316a2989fdSMatthew N. Dodd break; 19326a2989fdSMatthew N. Dodd } 19336a2989fdSMatthew N. Dodd break; 19346a2989fdSMatthew N. Dodd #undef OPTSET 19356a2989fdSMatthew N. Dodd default: 19366a2989fdSMatthew N. Dodd error = ENOPROTOOPT; 19376a2989fdSMatthew N. Dodd break; 19386a2989fdSMatthew N. Dodd } 1939abb886faSMatthew N. Dodd break; 1940e7c33e29SRobert Watson 19410c1bb4fbSDima Dorfman default: 19420c1bb4fbSDima Dorfman error = EOPNOTSUPP; 19430c1bb4fbSDima Dorfman break; 19440c1bb4fbSDima Dorfman } 19450c1bb4fbSDima Dorfman return (error); 19460c1bb4fbSDima Dorfman } 19470c1bb4fbSDima Dorfman 1948f708ef1bSPoul-Henning Kamp static int 1949892af6b9SRobert Watson unp_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 1950df8bae1dSRodney W. Grimes { 19517493f24eSPawel Jakub Dawidek 1952315167c0SGleb Smirnoff return (unp_connectat(AT_FDCWD, so, nam, td, false)); 19537493f24eSPawel Jakub Dawidek } 19547493f24eSPawel Jakub Dawidek 19557493f24eSPawel Jakub Dawidek static int 19567493f24eSPawel Jakub Dawidek unp_connectat(int fd, struct socket *so, struct sockaddr *nam, 1957315167c0SGleb Smirnoff struct thread *td, bool return_locked) 19587493f24eSPawel Jakub Dawidek { 1959ed92e1c7SMark Johnston struct mtx *vplock; 1960ed92e1c7SMark Johnston struct sockaddr_un *soun; 1961892af6b9SRobert Watson struct vnode *vp; 1962779f106aSGleb Smirnoff struct socket *so2; 1963b295bdcdSRobert Watson struct unpcb *unp, *unp2, *unp3; 1964df8bae1dSRodney W. Grimes struct nameidata nd; 196557bf258eSGarrett Wollman char buf[SOCK_MAXADDRLEN]; 19660d9ce3a1SRobert Watson struct sockaddr *sa; 19677008be5bSPawel Jakub Dawidek cap_rights_t rights; 1968ccdadf1aSMark Johnston int error, len; 1969ed92e1c7SMark Johnston bool connreq; 19700d9ce3a1SRobert Watson 1971cb7df69bSKevin Lo if (nam->sa_family != AF_UNIX) 1972cb7df69bSKevin Lo return (EAFNOSUPPORT); 1973a06534c3SBjoern A. Zeeb if (nam->sa_len > sizeof(struct sockaddr_un)) 1974a06534c3SBjoern A. Zeeb return (EINVAL); 197557bf258eSGarrett Wollman len = nam->sa_len - offsetof(struct sockaddr_un, sun_path); 197657bf258eSGarrett Wollman if (len <= 0) 1977e5aeaa0cSDag-Erling Smørgrav return (EINVAL); 1978ed92e1c7SMark Johnston soun = (struct sockaddr_un *)nam; 19797928893dSEd Maste bcopy(soun->sun_path, buf, len); 19807928893dSEd Maste buf[len] = 0; 1981e7c33e29SRobert Watson 1982bd4a39ccSMark Johnston error = 0; 198375a67bf3SMatt Macy unp = sotounpcb(so); 1984e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 1985ccdadf1aSMark Johnston for (;;) { 1986ccdadf1aSMark Johnston /* 1987ccdadf1aSMark Johnston * Wait for connection state to stabilize. If a connection 1988ccdadf1aSMark Johnston * already exists, give up. For datagram sockets, which permit 1989ccdadf1aSMark Johnston * multiple consecutive connect(2) calls, upper layers are 1990ccdadf1aSMark Johnston * responsible for disconnecting in advance of a subsequent 1991ccdadf1aSMark Johnston * connect(2), but this is not synchronized with PCB connection 1992ccdadf1aSMark Johnston * state. 1993ccdadf1aSMark Johnston * 1994ccdadf1aSMark Johnston * Also make sure that no threads are currently attempting to 1995ccdadf1aSMark Johnston * lock the peer socket, to ensure that unp_conn cannot 1996ccdadf1aSMark Johnston * transition between two valid sockets while locks are dropped. 1997ccdadf1aSMark Johnston */ 1998bd4a39ccSMark Johnston if (SOLISTENING(so)) 1999bd4a39ccSMark Johnston error = EOPNOTSUPP; 2000bd4a39ccSMark Johnston else if (unp->unp_conn != NULL) 2001bd4a39ccSMark Johnston error = EISCONN; 2002bd4a39ccSMark Johnston else if ((unp->unp_flags & UNP_CONNECTING) != 0) { 2003bd4a39ccSMark Johnston error = EALREADY; 2004ccdadf1aSMark Johnston } 2005bd4a39ccSMark Johnston if (error != 0) { 2006e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 2007bd4a39ccSMark Johnston return (error); 20084f1f0ef5SRobert Watson } 2009ccdadf1aSMark Johnston if (unp->unp_pairbusy > 0) { 2010ccdadf1aSMark Johnston unp->unp_flags |= UNP_WAITING; 2011ccdadf1aSMark Johnston mtx_sleep(unp, UNP_PCB_LOCKPTR(unp), 0, "unpeer", 0); 2012ccdadf1aSMark Johnston continue; 2013ccdadf1aSMark Johnston } 2014ccdadf1aSMark Johnston break; 2015ccdadf1aSMark Johnston } 201605102f04SRobert Watson unp->unp_flags |= UNP_CONNECTING; 2017e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 2018e7c33e29SRobert Watson 2019ed92e1c7SMark Johnston connreq = (so->so_proto->pr_flags & PR_CONNREQUIRED) != 0; 2020ed92e1c7SMark Johnston if (connreq) 20210d9ce3a1SRobert Watson sa = malloc(sizeof(struct sockaddr_un), M_SONAME, M_WAITOK); 2022ed92e1c7SMark Johnston else 2023ed92e1c7SMark Johnston sa = NULL; 20247493f24eSPawel Jakub Dawidek NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF, 20257e1d3eefSMateusz Guzik UIO_SYSSPACE, buf, fd, cap_rights_init_one(&rights, CAP_CONNECTAT)); 2026797f2d22SPoul-Henning Kamp error = namei(&nd); 2027797f2d22SPoul-Henning Kamp if (error) 20280d9ce3a1SRobert Watson vp = NULL; 20290d9ce3a1SRobert Watson else 2030df8bae1dSRodney W. Grimes vp = nd.ni_vp; 20310d9ce3a1SRobert Watson ASSERT_VOP_LOCKED(vp, "unp_connect"); 2032cdb62ab7SMateusz Guzik NDFREE_NOTHING(&nd); 20330d9ce3a1SRobert Watson if (error) 20340d9ce3a1SRobert Watson goto bad; 20350d9ce3a1SRobert Watson 2036df8bae1dSRodney W. Grimes if (vp->v_type != VSOCK) { 2037df8bae1dSRodney W. Grimes error = ENOTSOCK; 2038df8bae1dSRodney W. Grimes goto bad; 2039df8bae1dSRodney W. Grimes } 20406fac927cSRobert Watson #ifdef MAC 204130d239bcSRobert Watson error = mac_vnode_check_open(td->td_ucred, vp, VWRITE | VREAD); 20426fac927cSRobert Watson if (error) 20436fac927cSRobert Watson goto bad; 20446fac927cSRobert Watson #endif 2045a854ed98SJohn Baldwin error = VOP_ACCESS(vp, VWRITE, td->td_ucred, td); 2046797f2d22SPoul-Henning Kamp if (error) 2047df8bae1dSRodney W. Grimes goto bad; 2048e7c33e29SRobert Watson 2049b295bdcdSRobert Watson unp = sotounpcb(so); 20504d4b555eSRobert Watson KASSERT(unp != NULL, ("unp_connect: unp == NULL")); 2051e7c33e29SRobert Watson 205275a67bf3SMatt Macy vplock = mtx_pool_find(mtxpool_sleep, vp); 205375a67bf3SMatt Macy mtx_lock(vplock); 20540c3c207fSGleb Smirnoff VOP_UNP_CONNECT(vp, &unp2); 20550c3c207fSGleb Smirnoff if (unp2 == NULL) { 2056df8bae1dSRodney W. Grimes error = ECONNREFUSED; 20572260c03dSRobert Watson goto bad2; 2058df8bae1dSRodney W. Grimes } 20590c3c207fSGleb Smirnoff so2 = unp2->unp_socket; 2060df8bae1dSRodney W. Grimes if (so->so_type != so2->so_type) { 2061df8bae1dSRodney W. Grimes error = EPROTOTYPE; 20622260c03dSRobert Watson goto bad2; 2063df8bae1dSRodney W. Grimes } 2064ed92e1c7SMark Johnston if (connreq) { 2065f4bb1869SMark Johnston if (SOLISTENING(so2)) { 20661fb51a12SBjoern A. Zeeb CURVNET_SET(so2->so_vnet); 2067779f106aSGleb Smirnoff so2 = sonewconn(so2, 0); 20681fb51a12SBjoern A. Zeeb CURVNET_RESTORE(); 2069e7c33e29SRobert Watson } else 2070779f106aSGleb Smirnoff so2 = NULL; 2071779f106aSGleb Smirnoff if (so2 == NULL) { 2072df8bae1dSRodney W. Grimes error = ECONNREFUSED; 2073cb8f450bSMatt Macy goto bad2; 2074df8bae1dSRodney W. Grimes } 2075779f106aSGleb Smirnoff unp3 = sotounpcb(so2); 20764820bf6aSMark Johnston unp_pcb_lock_pair(unp2, unp3); 20770d9ce3a1SRobert Watson if (unp2->unp_addr != NULL) { 20780d9ce3a1SRobert Watson bcopy(unp2->unp_addr, sa, unp2->unp_addr->sun_len); 20790d9ce3a1SRobert Watson unp3->unp_addr = (struct sockaddr_un *) sa; 20800d9ce3a1SRobert Watson sa = NULL; 20810d9ce3a1SRobert Watson } 2082b523ec24SRobert Watson 2083da446550SAlan Somers unp_copy_peercred(td, unp3, unp, unp2); 2084b523ec24SRobert Watson 2085e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp2); 2086779f106aSGleb Smirnoff unp2 = unp3; 2087ccdadf1aSMark Johnston 2088ccdadf1aSMark Johnston /* 2089ccdadf1aSMark Johnston * It is safe to block on the PCB lock here since unp2 is 2090ccdadf1aSMark Johnston * nascent and cannot be connected to any other sockets. 2091ccdadf1aSMark Johnston */ 2092ccdadf1aSMark Johnston UNP_PCB_LOCK(unp); 2093335654d7SRobert Watson #ifdef MAC 2094779f106aSGleb Smirnoff mac_socketpeer_set_from_socket(so, so2); 2095779f106aSGleb Smirnoff mac_socketpeer_set_from_socket(so2, so); 2096335654d7SRobert Watson #endif 2097a3a73490SMatt Macy } else { 20984820bf6aSMark Johnston unp_pcb_lock_pair(unp, unp2); 2099a3a73490SMatt Macy } 2100779f106aSGleb Smirnoff KASSERT(unp2 != NULL && so2 != NULL && unp2->unp_socket == so2 && 2101779f106aSGleb Smirnoff sotounpcb(so2) == unp2, 2102779f106aSGleb Smirnoff ("%s: unp2 %p so2 %p", __func__, unp2, so2)); 210308f17d14SGleb Smirnoff unp_connect2(so, so2, PRU_CONNECT); 2104bb35a4e1SGleb Smirnoff KASSERT((unp->unp_flags & UNP_CONNECTING) != 0, 2105bb35a4e1SGleb Smirnoff ("%s: unp %p has UNP_CONNECTING clear", __func__, unp)); 2106bb35a4e1SGleb Smirnoff unp->unp_flags &= ~UNP_CONNECTING; 2107315167c0SGleb Smirnoff if (!return_locked) 21084820bf6aSMark Johnston unp_pcb_unlock_pair(unp, unp2); 21090d9ce3a1SRobert Watson bad2: 211075a67bf3SMatt Macy mtx_unlock(vplock); 2111df8bae1dSRodney W. Grimes bad: 211275a67bf3SMatt Macy if (vp != NULL) { 2113315167c0SGleb Smirnoff /* 2114315167c0SGleb Smirnoff * If we are returning locked (called via uipc_sosend_dgram()), 2115315167c0SGleb Smirnoff * we need to be sure that vput() won't sleep. This is 2116315167c0SGleb Smirnoff * guaranteed by VOP_UNP_CONNECT() call above and unp2 lock. 2117315167c0SGleb Smirnoff * SOCK_STREAM/SEQPACKET can't request return_locked (yet). 2118315167c0SGleb Smirnoff */ 2119315167c0SGleb Smirnoff MPASS(!(return_locked && connreq)); 2120df8bae1dSRodney W. Grimes vput(vp); 212175a67bf3SMatt Macy } 21220d9ce3a1SRobert Watson free(sa, M_SONAME); 2123bb35a4e1SGleb Smirnoff if (__predict_false(error)) { 2124e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 2125ccdadf1aSMark Johnston KASSERT((unp->unp_flags & UNP_CONNECTING) != 0, 2126ccdadf1aSMark Johnston ("%s: unp %p has UNP_CONNECTING clear", __func__, unp)); 21274f1f0ef5SRobert Watson unp->unp_flags &= ~UNP_CONNECTING; 2128e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 2129bb35a4e1SGleb Smirnoff } 2130df8bae1dSRodney W. Grimes return (error); 2131df8bae1dSRodney W. Grimes } 2132df8bae1dSRodney W. Grimes 2133da446550SAlan Somers /* 2134da446550SAlan Somers * Set socket peer credentials at connection time. 2135da446550SAlan Somers * 2136da446550SAlan Somers * The client's PCB credentials are copied from its process structure. The 2137da446550SAlan Somers * server's PCB credentials are copied from the socket on which it called 2138da446550SAlan Somers * listen(2). uipc_listen cached that process's credentials at the time. 2139da446550SAlan Somers */ 2140da446550SAlan Somers void 2141da446550SAlan Somers unp_copy_peercred(struct thread *td, struct unpcb *client_unp, 2142da446550SAlan Somers struct unpcb *server_unp, struct unpcb *listen_unp) 2143da446550SAlan Somers { 2144c5afec6eSDmitry Chagin cru2xt(td, &client_unp->unp_peercred); 2145da446550SAlan Somers client_unp->unp_flags |= UNP_HAVEPC; 2146da446550SAlan Somers 2147da446550SAlan Somers memcpy(&server_unp->unp_peercred, &listen_unp->unp_peercred, 2148da446550SAlan Somers sizeof(server_unp->unp_peercred)); 2149da446550SAlan Somers server_unp->unp_flags |= UNP_HAVEPC; 21502de07e40SConrad Meyer client_unp->unp_flags |= (listen_unp->unp_flags & UNP_WANTCRED_MASK); 2151da446550SAlan Somers } 2152da446550SAlan Somers 215308f17d14SGleb Smirnoff static void 21546a2989fdSMatthew N. Dodd unp_connect2(struct socket *so, struct socket *so2, int req) 2155df8bae1dSRodney W. Grimes { 2156e7c33e29SRobert Watson struct unpcb *unp; 2157892af6b9SRobert Watson struct unpcb *unp2; 2158df8bae1dSRodney W. Grimes 215908f17d14SGleb Smirnoff MPASS(so2->so_type == so->so_type); 2160e7c33e29SRobert Watson unp = sotounpcb(so); 2161e7c33e29SRobert Watson KASSERT(unp != NULL, ("unp_connect2: unp == NULL")); 2162e7c33e29SRobert Watson unp2 = sotounpcb(so2); 2163e7c33e29SRobert Watson KASSERT(unp2 != NULL, ("unp_connect2: unp2 == NULL")); 2164e7c33e29SRobert Watson 2165e7c33e29SRobert Watson UNP_PCB_LOCK_ASSERT(unp); 2166e7c33e29SRobert Watson UNP_PCB_LOCK_ASSERT(unp2); 2167ccdadf1aSMark Johnston KASSERT(unp->unp_conn == NULL, 2168ccdadf1aSMark Johnston ("%s: socket %p is already connected", __func__, unp)); 21690d9ce3a1SRobert Watson 2170df8bae1dSRodney W. Grimes unp->unp_conn = unp2; 217175a67bf3SMatt Macy unp_pcb_hold(unp2); 217275a67bf3SMatt Macy unp_pcb_hold(unp); 2173df8bae1dSRodney W. Grimes switch (so->so_type) { 2174df8bae1dSRodney W. Grimes case SOCK_DGRAM: 217575a67bf3SMatt Macy UNP_REF_LIST_LOCK(); 217698271db4SGarrett Wollman LIST_INSERT_HEAD(&unp2->unp_refs, unp, unp_reflink); 217775a67bf3SMatt Macy UNP_REF_LIST_UNLOCK(); 2178df8bae1dSRodney W. Grimes soisconnected(so); 2179df8bae1dSRodney W. Grimes break; 2180df8bae1dSRodney W. Grimes 2181df8bae1dSRodney W. Grimes case SOCK_STREAM: 218284d61770SRobert Watson case SOCK_SEQPACKET: 2183ccdadf1aSMark Johnston KASSERT(unp2->unp_conn == NULL, 2184ccdadf1aSMark Johnston ("%s: socket %p is already connected", __func__, unp2)); 2185df8bae1dSRodney W. Grimes unp2->unp_conn = unp; 21866a2989fdSMatthew N. Dodd if (req == PRU_CONNECT && 21876a2989fdSMatthew N. Dodd ((unp->unp_flags | unp2->unp_flags) & UNP_CONNWAIT)) 21886a2989fdSMatthew N. Dodd soisconnecting(so); 21896a2989fdSMatthew N. Dodd else 2190df8bae1dSRodney W. Grimes soisconnected(so); 2191df8bae1dSRodney W. Grimes soisconnected(so2); 2192df8bae1dSRodney W. Grimes break; 2193df8bae1dSRodney W. Grimes 2194df8bae1dSRodney W. Grimes default: 2195df8bae1dSRodney W. Grimes panic("unp_connect2"); 2196df8bae1dSRodney W. Grimes } 2197df8bae1dSRodney W. Grimes } 2198df8bae1dSRodney W. Grimes 2199f708ef1bSPoul-Henning Kamp static void 2200e7c33e29SRobert Watson unp_disconnect(struct unpcb *unp, struct unpcb *unp2) 2201df8bae1dSRodney W. Grimes { 220275a67bf3SMatt Macy struct socket *so, *so2; 2203458f475dSGleb Smirnoff struct mbuf *m = NULL; 2204f0317f86SMark Johnston #ifdef INVARIANTS 2205f0317f86SMark Johnston struct unpcb *unptmp; 2206f0317f86SMark Johnston #endif 22070d9ce3a1SRobert Watson 2208e7c33e29SRobert Watson UNP_PCB_LOCK_ASSERT(unp); 2209e7c33e29SRobert Watson UNP_PCB_LOCK_ASSERT(unp2); 2210f0317f86SMark Johnston KASSERT(unp->unp_conn == unp2, 2211f0317f86SMark Johnston ("%s: unpcb %p is not connected to %p", __func__, unp, unp2)); 2212e7c33e29SRobert Watson 2213fc3fcacfSRobert Watson unp->unp_conn = NULL; 221475a67bf3SMatt Macy so = unp->unp_socket; 221575a67bf3SMatt Macy so2 = unp2->unp_socket; 2216df8bae1dSRodney W. Grimes switch (unp->unp_socket->so_type) { 2217df8bae1dSRodney W. Grimes case SOCK_DGRAM: 2218458f475dSGleb Smirnoff /* 2219458f475dSGleb Smirnoff * Remove our send socket buffer from the peer's receive buffer. 2220458f475dSGleb Smirnoff * Move the data to the receive buffer only if it is empty. 2221458f475dSGleb Smirnoff * This is a protection against a scenario where a peer 2222458f475dSGleb Smirnoff * connects, floods and disconnects, effectively blocking 2223458f475dSGleb Smirnoff * sendto() from unconnected sockets. 2224458f475dSGleb Smirnoff */ 2225458f475dSGleb Smirnoff SOCK_RECVBUF_LOCK(so2); 2226458f475dSGleb Smirnoff if (!STAILQ_EMPTY(&so->so_snd.uxdg_mb)) { 2227458f475dSGleb Smirnoff TAILQ_REMOVE(&so2->so_rcv.uxdg_conns, &so->so_snd, 2228458f475dSGleb Smirnoff uxdg_clist); 2229458f475dSGleb Smirnoff if (__predict_true((so2->so_rcv.sb_state & 2230458f475dSGleb Smirnoff SBS_CANTRCVMORE) == 0) && 2231458f475dSGleb Smirnoff STAILQ_EMPTY(&so2->so_rcv.uxdg_mb)) { 2232458f475dSGleb Smirnoff STAILQ_CONCAT(&so2->so_rcv.uxdg_mb, 2233458f475dSGleb Smirnoff &so->so_snd.uxdg_mb); 2234458f475dSGleb Smirnoff so2->so_rcv.uxdg_cc += so->so_snd.uxdg_cc; 2235458f475dSGleb Smirnoff so2->so_rcv.uxdg_ctl += so->so_snd.uxdg_ctl; 2236458f475dSGleb Smirnoff so2->so_rcv.uxdg_mbcnt += so->so_snd.uxdg_mbcnt; 2237458f475dSGleb Smirnoff } else { 2238458f475dSGleb Smirnoff m = STAILQ_FIRST(&so->so_snd.uxdg_mb); 2239458f475dSGleb Smirnoff STAILQ_INIT(&so->so_snd.uxdg_mb); 2240458f475dSGleb Smirnoff so2->so_rcv.sb_acc -= so->so_snd.uxdg_cc; 2241458f475dSGleb Smirnoff so2->so_rcv.sb_ccc -= so->so_snd.uxdg_cc; 2242458f475dSGleb Smirnoff so2->so_rcv.sb_ctl -= so->so_snd.uxdg_ctl; 2243458f475dSGleb Smirnoff so2->so_rcv.sb_mbcnt -= so->so_snd.uxdg_mbcnt; 2244458f475dSGleb Smirnoff } 2245458f475dSGleb Smirnoff /* Note: so may reconnect. */ 2246458f475dSGleb Smirnoff so->so_snd.uxdg_cc = 0; 2247458f475dSGleb Smirnoff so->so_snd.uxdg_ctl = 0; 2248458f475dSGleb Smirnoff so->so_snd.uxdg_mbcnt = 0; 2249458f475dSGleb Smirnoff } 2250458f475dSGleb Smirnoff SOCK_RECVBUF_UNLOCK(so2); 225175a67bf3SMatt Macy UNP_REF_LIST_LOCK(); 2252f0317f86SMark Johnston #ifdef INVARIANTS 2253f0317f86SMark Johnston LIST_FOREACH(unptmp, &unp2->unp_refs, unp_reflink) { 2254f0317f86SMark Johnston if (unptmp == unp) 2255f0317f86SMark Johnston break; 2256f0317f86SMark Johnston } 2257f0317f86SMark Johnston KASSERT(unptmp != NULL, 2258f0317f86SMark Johnston ("%s: %p not found in reflist of %p", __func__, unp, unp2)); 2259f0317f86SMark Johnston #endif 226098271db4SGarrett Wollman LIST_REMOVE(unp, unp_reflink); 226175a67bf3SMatt Macy UNP_REF_LIST_UNLOCK(); 226275a67bf3SMatt Macy if (so) { 22631b2e3b4bSRobert Watson SOCK_LOCK(so); 22641b2e3b4bSRobert Watson so->so_state &= ~SS_ISCONNECTED; 22651b2e3b4bSRobert Watson SOCK_UNLOCK(so); 226675a67bf3SMatt Macy } 2267df8bae1dSRodney W. Grimes break; 2268df8bae1dSRodney W. Grimes 2269df8bae1dSRodney W. Grimes case SOCK_STREAM: 227084d61770SRobert Watson case SOCK_SEQPACKET: 227175a67bf3SMatt Macy if (so) 227275a67bf3SMatt Macy soisdisconnected(so); 227375a67bf3SMatt Macy MPASS(unp2->unp_conn == unp); 2274fc3fcacfSRobert Watson unp2->unp_conn = NULL; 227575a67bf3SMatt Macy if (so2) 227675a67bf3SMatt Macy soisdisconnected(so2); 2277df8bae1dSRodney W. Grimes break; 2278df8bae1dSRodney W. Grimes } 2279f0317f86SMark Johnston 2280f0317f86SMark Johnston if (unp == unp2) { 2281f0317f86SMark Johnston unp_pcb_rele_notlast(unp); 2282f0317f86SMark Johnston if (!unp_pcb_rele(unp)) 2283f0317f86SMark Johnston UNP_PCB_UNLOCK(unp); 2284f0317f86SMark Johnston } else { 2285f0317f86SMark Johnston if (!unp_pcb_rele(unp)) 2286f0317f86SMark Johnston UNP_PCB_UNLOCK(unp); 2287f0317f86SMark Johnston if (!unp_pcb_rele(unp2)) 2288f0317f86SMark Johnston UNP_PCB_UNLOCK(unp2); 2289f0317f86SMark Johnston } 2290458f475dSGleb Smirnoff 2291458f475dSGleb Smirnoff if (m != NULL) { 2292458f475dSGleb Smirnoff unp_scan(m, unp_freerights); 2293458f475dSGleb Smirnoff m_freem(m); 2294458f475dSGleb Smirnoff } 2295df8bae1dSRodney W. Grimes } 2296df8bae1dSRodney W. Grimes 22970d9ce3a1SRobert Watson /* 2298d7924b70SRobert Watson * unp_pcblist() walks the global list of struct unpcb's to generate a 2299d7924b70SRobert Watson * pointer list, bumping the refcount on each unpcb. It then copies them out 2300d7924b70SRobert Watson * sequentially, validating the generation number on each to see if it has 2301d7924b70SRobert Watson * been detached. All of this is necessary because copyout() may sleep on 2302d7924b70SRobert Watson * disk I/O. 23030d9ce3a1SRobert Watson */ 230498271db4SGarrett Wollman static int 230582d9ae4eSPoul-Henning Kamp unp_pcblist(SYSCTL_HANDLER_ARGS) 230698271db4SGarrett Wollman { 230798271db4SGarrett Wollman struct unpcb *unp, **unp_list; 230898271db4SGarrett Wollman unp_gen_t gencnt; 23098f364875SJulian Elischer struct xunpgen *xug; 231098271db4SGarrett Wollman struct unp_head *head; 23118f364875SJulian Elischer struct xunpcb *xu; 2312d821d364SPedro F. Giffuni u_int i; 23135362170dSMark Johnston int error, n; 231498271db4SGarrett Wollman 231584d61770SRobert Watson switch ((intptr_t)arg1) { 231684d61770SRobert Watson case SOCK_STREAM: 231784d61770SRobert Watson head = &unp_shead; 231884d61770SRobert Watson break; 231984d61770SRobert Watson 232084d61770SRobert Watson case SOCK_DGRAM: 232184d61770SRobert Watson head = &unp_dhead; 232284d61770SRobert Watson break; 232384d61770SRobert Watson 232484d61770SRobert Watson case SOCK_SEQPACKET: 232584d61770SRobert Watson head = &unp_sphead; 232684d61770SRobert Watson break; 232784d61770SRobert Watson 232884d61770SRobert Watson default: 2329604f19c9SRobert Watson panic("unp_pcblist: arg1 %d", (int)(intptr_t)arg1); 233084d61770SRobert Watson } 233198271db4SGarrett Wollman 233298271db4SGarrett Wollman /* 233398271db4SGarrett Wollman * The process of preparing the PCB list is too time-consuming and 233498271db4SGarrett Wollman * resource-intensive to repeat twice on every request. 233598271db4SGarrett Wollman */ 2336fc3fcacfSRobert Watson if (req->oldptr == NULL) { 233798271db4SGarrett Wollman n = unp_count; 23388f364875SJulian Elischer req->oldidx = 2 * (sizeof *xug) 233998271db4SGarrett Wollman + (n + n/8) * sizeof(struct xunpcb); 2340e5aeaa0cSDag-Erling Smørgrav return (0); 234198271db4SGarrett Wollman } 234298271db4SGarrett Wollman 2343fc3fcacfSRobert Watson if (req->newptr != NULL) 2344e5aeaa0cSDag-Erling Smørgrav return (EPERM); 234598271db4SGarrett Wollman 234698271db4SGarrett Wollman /* 234798271db4SGarrett Wollman * OK, now we're committed to doing something. 234898271db4SGarrett Wollman */ 234979db6fe7SMark Johnston xug = malloc(sizeof(*xug), M_TEMP, M_WAITOK | M_ZERO); 2350779f106aSGleb Smirnoff UNP_LINK_RLOCK(); 235198271db4SGarrett Wollman gencnt = unp_gencnt; 235298271db4SGarrett Wollman n = unp_count; 2353779f106aSGleb Smirnoff UNP_LINK_RUNLOCK(); 235498271db4SGarrett Wollman 23558f364875SJulian Elischer xug->xug_len = sizeof *xug; 23568f364875SJulian Elischer xug->xug_count = n; 23578f364875SJulian Elischer xug->xug_gen = gencnt; 23588f364875SJulian Elischer xug->xug_sogen = so_gencnt; 23598f364875SJulian Elischer error = SYSCTL_OUT(req, xug, sizeof *xug); 23608f364875SJulian Elischer if (error) { 23618f364875SJulian Elischer free(xug, M_TEMP); 2362e5aeaa0cSDag-Erling Smørgrav return (error); 23638f364875SJulian Elischer } 236498271db4SGarrett Wollman 2365a163d034SWarner Losh unp_list = malloc(n * sizeof *unp_list, M_TEMP, M_WAITOK); 236698271db4SGarrett Wollman 2367779f106aSGleb Smirnoff UNP_LINK_RLOCK(); 23682e3c8fcbSPoul-Henning Kamp for (unp = LIST_FIRST(head), i = 0; unp && i < n; 23692e3c8fcbSPoul-Henning Kamp unp = LIST_NEXT(unp, unp_link)) { 2370e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 23718a7d8cc6SRobert Watson if (unp->unp_gencnt <= gencnt) { 2372a854ed98SJohn Baldwin if (cr_cansee(req->td->td_ucred, 2373e7c33e29SRobert Watson unp->unp_socket->so_cred)) { 2374e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 23754787fd37SPaul Saab continue; 2376e7c33e29SRobert Watson } 237798271db4SGarrett Wollman unp_list[i++] = unp; 237875a67bf3SMatt Macy unp_pcb_hold(unp); 237998271db4SGarrett Wollman } 2380e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 23814787fd37SPaul Saab } 2382779f106aSGleb Smirnoff UNP_LINK_RUNLOCK(); 23831c381b19SRobert Watson n = i; /* In case we lost some during malloc. */ 238498271db4SGarrett Wollman 238598271db4SGarrett Wollman error = 0; 2386fe2eee82SColin Percival xu = malloc(sizeof(*xu), M_TEMP, M_WAITOK | M_ZERO); 238798271db4SGarrett Wollman for (i = 0; i < n; i++) { 238898271db4SGarrett Wollman unp = unp_list[i]; 2389e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 23905362170dSMark Johnston if (unp_pcb_rele(unp)) 23915362170dSMark Johnston continue; 239275a67bf3SMatt Macy 23935362170dSMark Johnston if (unp->unp_gencnt <= gencnt) { 23948f364875SJulian Elischer xu->xu_len = sizeof *xu; 23953a20f06aSBrooks Davis xu->xu_unpp = (uintptr_t)unp; 239698271db4SGarrett Wollman /* 239798271db4SGarrett Wollman * XXX - need more locking here to protect against 239898271db4SGarrett Wollman * connect/disconnect races for SMP. 239998271db4SGarrett Wollman */ 2400fc3fcacfSRobert Watson if (unp->unp_addr != NULL) 24018f364875SJulian Elischer bcopy(unp->unp_addr, &xu->xu_addr, 240298271db4SGarrett Wollman unp->unp_addr->sun_len); 24030e229f34SGleb Smirnoff else 24040e229f34SGleb Smirnoff bzero(&xu->xu_addr, sizeof(xu->xu_addr)); 2405fc3fcacfSRobert Watson if (unp->unp_conn != NULL && 2406fc3fcacfSRobert Watson unp->unp_conn->unp_addr != NULL) 240798271db4SGarrett Wollman bcopy(unp->unp_conn->unp_addr, 24088f364875SJulian Elischer &xu->xu_caddr, 240998271db4SGarrett Wollman unp->unp_conn->unp_addr->sun_len); 24100e229f34SGleb Smirnoff else 24110e229f34SGleb Smirnoff bzero(&xu->xu_caddr, sizeof(xu->xu_caddr)); 24123a20f06aSBrooks Davis xu->unp_vnode = (uintptr_t)unp->unp_vnode; 24133a20f06aSBrooks Davis xu->unp_conn = (uintptr_t)unp->unp_conn; 24143a20f06aSBrooks Davis xu->xu_firstref = (uintptr_t)LIST_FIRST(&unp->unp_refs); 24153a20f06aSBrooks Davis xu->xu_nextref = (uintptr_t)LIST_NEXT(unp, unp_reflink); 24160e229f34SGleb Smirnoff xu->unp_gencnt = unp->unp_gencnt; 24178f364875SJulian Elischer sotoxsocket(unp->unp_socket, &xu->xu_socket); 2418e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 24198f364875SJulian Elischer error = SYSCTL_OUT(req, xu, sizeof *xu); 24205362170dSMark Johnston } else { 2421e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 2422e7c33e29SRobert Watson } 24235362170dSMark Johnston } 24248f364875SJulian Elischer free(xu, M_TEMP); 242598271db4SGarrett Wollman if (!error) { 242698271db4SGarrett Wollman /* 24271c381b19SRobert Watson * Give the user an updated idea of our state. If the 24281c381b19SRobert Watson * generation differs from what we told her before, she knows 24291c381b19SRobert Watson * that something happened while we were processing this 24301c381b19SRobert Watson * request, and it might be necessary to retry. 243198271db4SGarrett Wollman */ 24328f364875SJulian Elischer xug->xug_gen = unp_gencnt; 24338f364875SJulian Elischer xug->xug_sogen = so_gencnt; 24348f364875SJulian Elischer xug->xug_count = unp_count; 24358f364875SJulian Elischer error = SYSCTL_OUT(req, xug, sizeof *xug); 243698271db4SGarrett Wollman } 243798271db4SGarrett Wollman free(unp_list, M_TEMP); 24388f364875SJulian Elischer free(xug, M_TEMP); 2439e5aeaa0cSDag-Erling Smørgrav return (error); 244098271db4SGarrett Wollman } 244198271db4SGarrett Wollman 24427029da5cSPawel Biernacki SYSCTL_PROC(_net_local_dgram, OID_AUTO, pcblist, 24437029da5cSPawel Biernacki CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, 24442fee06f0SMatthew D Fleming (void *)(intptr_t)SOCK_DGRAM, 0, unp_pcblist, "S,xunpcb", 244598271db4SGarrett Wollman "List of active local datagram sockets"); 24467029da5cSPawel Biernacki SYSCTL_PROC(_net_local_stream, OID_AUTO, pcblist, 24477029da5cSPawel Biernacki CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, 24482fee06f0SMatthew D Fleming (void *)(intptr_t)SOCK_STREAM, 0, unp_pcblist, "S,xunpcb", 244998271db4SGarrett Wollman "List of active local stream sockets"); 24502fee06f0SMatthew D Fleming SYSCTL_PROC(_net_local_seqpacket, OID_AUTO, pcblist, 24517029da5cSPawel Biernacki CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, 24522fee06f0SMatthew D Fleming (void *)(intptr_t)SOCK_SEQPACKET, 0, unp_pcblist, "S,xunpcb", 245384d61770SRobert Watson "List of active local seqpacket sockets"); 245498271db4SGarrett Wollman 2455f708ef1bSPoul-Henning Kamp static void 2456892af6b9SRobert Watson unp_shutdown(struct unpcb *unp) 2457df8bae1dSRodney W. Grimes { 2458e7c33e29SRobert Watson struct unpcb *unp2; 2459df8bae1dSRodney W. Grimes struct socket *so; 2460df8bae1dSRodney W. Grimes 2461e7c33e29SRobert Watson UNP_PCB_LOCK_ASSERT(unp); 24620d9ce3a1SRobert Watson 2463e7c33e29SRobert Watson unp2 = unp->unp_conn; 246484d61770SRobert Watson if ((unp->unp_socket->so_type == SOCK_STREAM || 246584d61770SRobert Watson (unp->unp_socket->so_type == SOCK_SEQPACKET)) && unp2 != NULL) { 2466e7c33e29SRobert Watson so = unp2->unp_socket; 2467e7c33e29SRobert Watson if (so != NULL) 2468df8bae1dSRodney W. Grimes socantrcvmore(so); 2469df8bae1dSRodney W. Grimes } 2470e7c33e29SRobert Watson } 2471df8bae1dSRodney W. Grimes 2472f708ef1bSPoul-Henning Kamp static void 2473afc055d9SEd Schouten unp_drop(struct unpcb *unp) 2474df8bae1dSRodney W. Grimes { 247550b07c1fSMark Johnston struct socket *so; 2476e7c33e29SRobert Watson struct unpcb *unp2; 24770d9ce3a1SRobert Watson 2478afc055d9SEd Schouten /* 2479afc055d9SEd Schouten * Regardless of whether the socket's peer dropped the connection 2480afc055d9SEd Schouten * with this socket by aborting or disconnecting, POSIX requires 2481afc055d9SEd Schouten * that ECONNRESET is returned. 2482afc055d9SEd Schouten */ 248375a67bf3SMatt Macy 248475a67bf3SMatt Macy UNP_PCB_LOCK(unp); 248550b07c1fSMark Johnston so = unp->unp_socket; 248675a67bf3SMatt Macy if (so) 2487afc055d9SEd Schouten so->so_error = ECONNRESET; 2488ccdadf1aSMark Johnston if ((unp2 = unp_pcb_lock_peer(unp)) != NULL) { 2489f0317f86SMark Johnston /* Last reference dropped in unp_disconnect(). */ 2490f0317f86SMark Johnston unp_pcb_rele_notlast(unp); 2491e7c33e29SRobert Watson unp_disconnect(unp, unp2); 2492f0317f86SMark Johnston } else if (!unp_pcb_rele(unp)) { 249375a67bf3SMatt Macy UNP_PCB_UNLOCK(unp); 249475a67bf3SMatt Macy } 2495f0317f86SMark Johnston } 2496df8bae1dSRodney W. Grimes 24972bc21ed9SDavid Malone static void 24988cb539f1SPawel Jakub Dawidek unp_freerights(struct filedescent **fdep, int fdcount) 2499df8bae1dSRodney W. Grimes { 25002bc21ed9SDavid Malone struct file *fp; 25012609222aSPawel Jakub Dawidek int i; 2502df8bae1dSRodney W. Grimes 250382e825c4SGleb Smirnoff KASSERT(fdcount > 0, ("%s: fdcount %d", __func__, fdcount)); 250482e825c4SGleb Smirnoff 25058cb539f1SPawel Jakub Dawidek for (i = 0; i < fdcount; i++) { 25068cb539f1SPawel Jakub Dawidek fp = fdep[i]->fde_file; 25078cb539f1SPawel Jakub Dawidek filecaps_free(&fdep[i]->fde_caps); 25088692c025SYoshinobu Inoue unp_discard(fp); 2509df8bae1dSRodney W. Grimes } 25108cb539f1SPawel Jakub Dawidek free(fdep[0], M_FILECAPS); 25112bc21ed9SDavid Malone } 25122bc21ed9SDavid Malone 25130b36cd25SRobert Watson static int 2514c2e3c52eSJilles Tjoelker unp_externalize(struct mbuf *control, struct mbuf **controlp, int flags) 25152bc21ed9SDavid Malone { 25162bc21ed9SDavid Malone struct thread *td = curthread; /* XXX */ 25172bc21ed9SDavid Malone struct cmsghdr *cm = mtod(control, struct cmsghdr *); 25182bc21ed9SDavid Malone int i; 25192bc21ed9SDavid Malone int *fdp; 25202609222aSPawel Jakub Dawidek struct filedesc *fdesc = td->td_proc->p_fd; 2521ea31808cSMateusz Guzik struct filedescent **fdep; 25222bc21ed9SDavid Malone void *data; 25232bc21ed9SDavid Malone socklen_t clen = control->m_len, datalen; 25242bc21ed9SDavid Malone int error, newfds; 25252bc21ed9SDavid Malone u_int newlen; 25262bc21ed9SDavid Malone 25273dab55bcSRobert Watson UNP_LINK_UNLOCK_ASSERT(); 25284c5bc1caSRobert Watson 25292bc21ed9SDavid Malone error = 0; 25302bc21ed9SDavid Malone if (controlp != NULL) /* controlp == NULL => free control messages */ 25312bc21ed9SDavid Malone *controlp = NULL; 25322bc21ed9SDavid Malone while (cm != NULL) { 253375e7e3ceSGleb Smirnoff MPASS(clen >= sizeof(*cm) && clen >= cm->cmsg_len); 25344682ac69SGleb Smirnoff 25352bc21ed9SDavid Malone data = CMSG_DATA(cm); 25362bc21ed9SDavid Malone datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data; 25372bc21ed9SDavid Malone if (cm->cmsg_level == SOL_SOCKET 25382bc21ed9SDavid Malone && cm->cmsg_type == SCM_RIGHTS) { 25392609222aSPawel Jakub Dawidek newfds = datalen / sizeof(*fdep); 254082e825c4SGleb Smirnoff if (newfds == 0) 254182e825c4SGleb Smirnoff goto next; 25422609222aSPawel Jakub Dawidek fdep = data; 25432bc21ed9SDavid Malone 2544e2f9a08bSOlivier Houchard /* If we're not outputting the descriptors free them. */ 25452bc21ed9SDavid Malone if (error || controlp == NULL) { 25462609222aSPawel Jakub Dawidek unp_freerights(fdep, newfds); 25472bc21ed9SDavid Malone goto next; 25482bc21ed9SDavid Malone } 25492609222aSPawel Jakub Dawidek FILEDESC_XLOCK(fdesc); 255060a5ef26SRobert Watson 2551ed5b7817SJulian Elischer /* 25521c381b19SRobert Watson * Now change each pointer to an fd in the global 25531c381b19SRobert Watson * table to an integer that is the index to the local 25541c381b19SRobert Watson * fd table entry that we set up to point to the 25551c381b19SRobert Watson * global one we are transferring. 2556ed5b7817SJulian Elischer */ 25572bc21ed9SDavid Malone newlen = newfds * sizeof(int); 25582bc21ed9SDavid Malone *controlp = sbcreatecontrol(NULL, newlen, 2559d64f2f42SGleb Smirnoff SCM_RIGHTS, SOL_SOCKET, M_WAITOK); 25602bc21ed9SDavid Malone 25612bc21ed9SDavid Malone fdp = (int *) 25622bc21ed9SDavid Malone CMSG_DATA(mtod(*controlp, struct cmsghdr *)); 256348a55bbfSGleb Smirnoff if ((error = fdallocn(td, 0, fdp, newfds))) { 25643331a33aSMateusz Guzik FILEDESC_XUNLOCK(fdesc); 2565db8f33fdSMateusz Guzik unp_freerights(fdep, newfds); 2566db8f33fdSMateusz Guzik m_freem(*controlp); 2567db8f33fdSMateusz Guzik *controlp = NULL; 2568db8f33fdSMateusz Guzik goto next; 2569db8f33fdSMateusz Guzik } 25708cb539f1SPawel Jakub Dawidek for (i = 0; i < newfds; i++, fdp++) { 2571ea31808cSMateusz Guzik _finstall(fdesc, fdep[i]->fde_file, *fdp, 25726ceacebdSAlex Richardson (flags & MSG_CMSG_CLOEXEC) != 0 ? O_CLOEXEC : 0, 2573ea31808cSMateusz Guzik &fdep[i]->fde_caps); 2574ea31808cSMateusz Guzik unp_externalize_fp(fdep[i]->fde_file); 2575df8bae1dSRodney W. Grimes } 2576c7902fbeSMark Johnston 2577c7902fbeSMark Johnston /* 2578c7902fbeSMark Johnston * The new type indicates that the mbuf data refers to 2579c7902fbeSMark Johnston * kernel resources that may need to be released before 2580c7902fbeSMark Johnston * the mbuf is freed. 2581c7902fbeSMark Johnston */ 2582c7902fbeSMark Johnston m_chtype(*controlp, MT_EXTCONTROL); 25832609222aSPawel Jakub Dawidek FILEDESC_XUNLOCK(fdesc); 25848cb539f1SPawel Jakub Dawidek free(fdep[0], M_FILECAPS); 25851c381b19SRobert Watson } else { 25861c381b19SRobert Watson /* We can just copy anything else across. */ 25872bc21ed9SDavid Malone if (error || controlp == NULL) 25882bc21ed9SDavid Malone goto next; 25892bc21ed9SDavid Malone *controlp = sbcreatecontrol(NULL, datalen, 2590d64f2f42SGleb Smirnoff cm->cmsg_type, cm->cmsg_level, M_WAITOK); 25912bc21ed9SDavid Malone bcopy(data, 25922bc21ed9SDavid Malone CMSG_DATA(mtod(*controlp, struct cmsghdr *)), 25932bc21ed9SDavid Malone datalen); 25942bc21ed9SDavid Malone } 25952bc21ed9SDavid Malone controlp = &(*controlp)->m_next; 25962bc21ed9SDavid Malone 25972bc21ed9SDavid Malone next: 25982bc21ed9SDavid Malone if (CMSG_SPACE(datalen) < clen) { 25992bc21ed9SDavid Malone clen -= CMSG_SPACE(datalen); 26002bc21ed9SDavid Malone cm = (struct cmsghdr *) 26012bc21ed9SDavid Malone ((caddr_t)cm + CMSG_SPACE(datalen)); 26028692c025SYoshinobu Inoue } else { 26032bc21ed9SDavid Malone clen = 0; 26042bc21ed9SDavid Malone cm = NULL; 26058692c025SYoshinobu Inoue } 26068692c025SYoshinobu Inoue } 26078692c025SYoshinobu Inoue 26082bc21ed9SDavid Malone m_freem(control); 26092bc21ed9SDavid Malone return (error); 2610df8bae1dSRodney W. Grimes } 2611df8bae1dSRodney W. Grimes 26124f590175SPaul Saab static void 26134f590175SPaul Saab unp_zone_change(void *tag) 26144f590175SPaul Saab { 26154f590175SPaul Saab 26164f590175SPaul Saab uma_zone_set_max(unp_zone, maxsockets); 26174f590175SPaul Saab } 26184f590175SPaul Saab 26195362170dSMark Johnston #ifdef INVARIANTS 26205362170dSMark Johnston static void 26215362170dSMark Johnston unp_zdtor(void *mem, int size __unused, void *arg __unused) 26225362170dSMark Johnston { 26235362170dSMark Johnston struct unpcb *unp; 26245362170dSMark Johnston 26255362170dSMark Johnston unp = mem; 26265362170dSMark Johnston 26275362170dSMark Johnston KASSERT(LIST_EMPTY(&unp->unp_refs), 26285362170dSMark Johnston ("%s: unpcb %p has lingering refs", __func__, unp)); 26295362170dSMark Johnston KASSERT(unp->unp_socket == NULL, 26305362170dSMark Johnston ("%s: unpcb %p has socket backpointer", __func__, unp)); 26315362170dSMark Johnston KASSERT(unp->unp_vnode == NULL, 26325362170dSMark Johnston ("%s: unpcb %p has vnode references", __func__, unp)); 26335362170dSMark Johnston KASSERT(unp->unp_conn == NULL, 26345362170dSMark Johnston ("%s: unpcb %p is still connected", __func__, unp)); 26355362170dSMark Johnston KASSERT(unp->unp_addr == NULL, 26365362170dSMark Johnston ("%s: unpcb %p has leaked addr", __func__, unp)); 26375362170dSMark Johnston } 26385362170dSMark Johnston #endif 26395362170dSMark Johnston 26400b36cd25SRobert Watson static void 264124e1c6aeSGleb Smirnoff unp_init(void *arg __unused) 264298271db4SGarrett Wollman { 26435362170dSMark Johnston uma_dtor dtor; 26441c381b19SRobert Watson 26455362170dSMark Johnston #ifdef INVARIANTS 26465362170dSMark Johnston dtor = unp_zdtor; 26475362170dSMark Johnston #else 26485362170dSMark Johnston dtor = NULL; 26495362170dSMark Johnston #endif 26505362170dSMark Johnston unp_zone = uma_zcreate("unpcb", sizeof(struct unpcb), NULL, dtor, 265175a67bf3SMatt Macy NULL, NULL, UMA_ALIGN_CACHE, 0); 26524f590175SPaul Saab uma_zone_set_max(unp_zone, maxsockets); 26536e0b6746SPawel Jakub Dawidek uma_zone_set_warning(unp_zone, "kern.ipc.maxsockets limit reached"); 26544f590175SPaul Saab EVENTHANDLER_REGISTER(maxsockets_change, unp_zone_change, 26554f590175SPaul Saab NULL, EVENTHANDLER_PRI_ANY); 265698271db4SGarrett Wollman LIST_INIT(&unp_dhead); 265798271db4SGarrett Wollman LIST_INIT(&unp_shead); 265884d61770SRobert Watson LIST_INIT(&unp_sphead); 26590cb64678SKonstantin Belousov SLIST_INIT(&unp_defers); 2660daee0f0bSKonstantin Belousov TIMEOUT_TASK_INIT(taskqueue_thread, &unp_gc_task, 0, unp_gc, NULL); 26610cb64678SKonstantin Belousov TASK_INIT(&unp_defer_task, 0, unp_process_defers, NULL); 26623dab55bcSRobert Watson UNP_LINK_LOCK_INIT(); 26630cb64678SKonstantin Belousov UNP_DEFERRED_LOCK_INIT(); 266498271db4SGarrett Wollman } 266524e1c6aeSGleb Smirnoff SYSINIT(unp_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_SECOND, unp_init, NULL); 266698271db4SGarrett Wollman 266747c3450eSKonstantin Belousov static void 266847c3450eSKonstantin Belousov unp_internalize_cleanup_rights(struct mbuf *control) 266947c3450eSKonstantin Belousov { 267047c3450eSKonstantin Belousov struct cmsghdr *cp; 267147c3450eSKonstantin Belousov struct mbuf *m; 267247c3450eSKonstantin Belousov void *data; 267347c3450eSKonstantin Belousov socklen_t datalen; 267447c3450eSKonstantin Belousov 267547c3450eSKonstantin Belousov for (m = control; m != NULL; m = m->m_next) { 267647c3450eSKonstantin Belousov cp = mtod(m, struct cmsghdr *); 267747c3450eSKonstantin Belousov if (cp->cmsg_level != SOL_SOCKET || 267847c3450eSKonstantin Belousov cp->cmsg_type != SCM_RIGHTS) 267947c3450eSKonstantin Belousov continue; 268047c3450eSKonstantin Belousov data = CMSG_DATA(cp); 268147c3450eSKonstantin Belousov datalen = (caddr_t)cp + cp->cmsg_len - (caddr_t)data; 268247c3450eSKonstantin Belousov unp_freerights(data, datalen / sizeof(struct filedesc *)); 268347c3450eSKonstantin Belousov } 268447c3450eSKonstantin Belousov } 268547c3450eSKonstantin Belousov 2686f708ef1bSPoul-Henning Kamp static int 26871093f164SGleb Smirnoff unp_internalize(struct mbuf **controlp, struct thread *td, 26881093f164SGleb Smirnoff struct mbuf **clast, u_int *space, u_int *mbcnt) 2689df8bae1dSRodney W. Grimes { 269047c3450eSKonstantin Belousov struct mbuf *control, **initial_controlp; 269147c3450eSKonstantin Belousov struct proc *p; 269247c3450eSKonstantin Belousov struct filedesc *fdesc; 2693ab15d803SSergey Kandaurov struct bintime *bt; 269447c3450eSKonstantin Belousov struct cmsghdr *cm; 26952bc21ed9SDavid Malone struct cmsgcred *cmcred; 26968cb539f1SPawel Jakub Dawidek struct filedescent *fde, **fdep, *fdev; 26972bc21ed9SDavid Malone struct file *fp; 26982bc21ed9SDavid Malone struct timeval *tv; 2699339efd75SMaxim Sobolev struct timespec *ts; 27002bc21ed9SDavid Malone void *data; 270147c3450eSKonstantin Belousov socklen_t clen, datalen; 2702f1cf2b9dSKonstantin Belousov int i, j, error, *fdp, oldfds; 27038692c025SYoshinobu Inoue u_int newlen; 2704df8bae1dSRodney W. Grimes 27051093f164SGleb Smirnoff MPASS((*controlp)->m_next == NULL); /* COMPAT_OLDSOCK may violate */ 27063dab55bcSRobert Watson UNP_LINK_UNLOCK_ASSERT(); 27074c5bc1caSRobert Watson 270847c3450eSKonstantin Belousov p = td->td_proc; 270947c3450eSKonstantin Belousov fdesc = p->p_fd; 27102bc21ed9SDavid Malone error = 0; 271147c3450eSKonstantin Belousov control = *controlp; 27122bc21ed9SDavid Malone *controlp = NULL; 271347c3450eSKonstantin Belousov initial_controlp = controlp; 2714d97922c6SGleb Smirnoff for (clen = control->m_len, cm = mtod(control, struct cmsghdr *), 27152bc21ed9SDavid Malone data = CMSG_DATA(cm); 27162bc21ed9SDavid Malone 2717d97922c6SGleb Smirnoff clen >= sizeof(*cm) && cm->cmsg_level == SOL_SOCKET && 2718d97922c6SGleb Smirnoff clen >= cm->cmsg_len && cm->cmsg_len >= sizeof(*cm) && 2719d97922c6SGleb Smirnoff (char *)cm + cm->cmsg_len >= (char *)data; 2720d97922c6SGleb Smirnoff 2721d97922c6SGleb Smirnoff clen -= min(CMSG_SPACE(datalen), clen), 2722d97922c6SGleb Smirnoff cm = (struct cmsghdr *) ((char *)cm + CMSG_SPACE(datalen)), 2723d97922c6SGleb Smirnoff data = CMSG_DATA(cm)) { 2724d97922c6SGleb Smirnoff datalen = (char *)cm + cm->cmsg_len - (char *)data; 27252bc21ed9SDavid Malone switch (cm->cmsg_type) { 27262bc21ed9SDavid Malone case SCM_CREDS: 2727b46667c6SGleb Smirnoff *controlp = sbcreatecontrol(NULL, sizeof(*cmcred), 272824df85d2SGleb Smirnoff SCM_CREDS, SOL_SOCKET, M_WAITOK); 27292bc21ed9SDavid Malone cmcred = (struct cmsgcred *) 27302bc21ed9SDavid Malone CMSG_DATA(mtod(*controlp, struct cmsghdr *)); 27310b788fa1SBill Paul cmcred->cmcred_pid = p->p_pid; 2732a854ed98SJohn Baldwin cmcred->cmcred_uid = td->td_ucred->cr_ruid; 2733a854ed98SJohn Baldwin cmcred->cmcred_gid = td->td_ucred->cr_rgid; 2734a854ed98SJohn Baldwin cmcred->cmcred_euid = td->td_ucred->cr_uid; 2735a854ed98SJohn Baldwin cmcred->cmcred_ngroups = MIN(td->td_ucred->cr_ngroups, 27360b788fa1SBill Paul CMGROUP_MAX); 27370b788fa1SBill Paul for (i = 0; i < cmcred->cmcred_ngroups; i++) 27382bc21ed9SDavid Malone cmcred->cmcred_groups[i] = 2739a854ed98SJohn Baldwin td->td_ucred->cr_groups[i]; 27402bc21ed9SDavid Malone break; 27410b788fa1SBill Paul 27422bc21ed9SDavid Malone case SCM_RIGHTS: 27432bc21ed9SDavid Malone oldfds = datalen / sizeof (int); 274482e825c4SGleb Smirnoff if (oldfds == 0) 2745d97922c6SGleb Smirnoff continue; 2746579b45e2SGleb Smirnoff /* On some machines sizeof pointer is bigger than 2747579b45e2SGleb Smirnoff * sizeof int, so we need to check if data fits into 2748579b45e2SGleb Smirnoff * single mbuf. We could allocate several mbufs, and 2749579b45e2SGleb Smirnoff * unp_externalize() should even properly handle that. 2750579b45e2SGleb Smirnoff * But it is not worth to complicate the code for an 2751579b45e2SGleb Smirnoff * insane scenario of passing over 200 file descriptors 2752579b45e2SGleb Smirnoff * at once. 2753579b45e2SGleb Smirnoff */ 2754579b45e2SGleb Smirnoff newlen = oldfds * sizeof(fdep[0]); 2755579b45e2SGleb Smirnoff if (CMSG_SPACE(newlen) > MCLBYTES) { 2756579b45e2SGleb Smirnoff error = EMSGSIZE; 2757579b45e2SGleb Smirnoff goto out; 2758579b45e2SGleb Smirnoff } 2759ed5b7817SJulian Elischer /* 27601c381b19SRobert Watson * Check that all the FDs passed in refer to legal 27611c381b19SRobert Watson * files. If not, reject the entire operation. 2762ed5b7817SJulian Elischer */ 27632bc21ed9SDavid Malone fdp = data; 27642609222aSPawel Jakub Dawidek FILEDESC_SLOCK(fdesc); 27656a1cf96bSMateusz Guzik for (i = 0; i < oldfds; i++, fdp++) { 2766f17ef286SMateusz Guzik fp = fget_noref(fdesc, *fdp); 27676a1cf96bSMateusz Guzik if (fp == NULL) { 27682609222aSPawel Jakub Dawidek FILEDESC_SUNLOCK(fdesc); 27692bc21ed9SDavid Malone error = EBADF; 27702bc21ed9SDavid Malone goto out; 27712bc21ed9SDavid Malone } 2772e7d6662fSAlfred Perlstein if (!(fp->f_ops->fo_flags & DFLAG_PASSABLE)) { 27732609222aSPawel Jakub Dawidek FILEDESC_SUNLOCK(fdesc); 2774e7d6662fSAlfred Perlstein error = EOPNOTSUPP; 2775e7d6662fSAlfred Perlstein goto out; 2776e7d6662fSAlfred Perlstein } 2777df8bae1dSRodney W. Grimes } 27785e3f7694SRobert Watson 2779ed5b7817SJulian Elischer /* 27800b36cd25SRobert Watson * Now replace the integer FDs with pointers to the 27812609222aSPawel Jakub Dawidek * file structure and capability rights. 2782ed5b7817SJulian Elischer */ 2783b46667c6SGleb Smirnoff *controlp = sbcreatecontrol(NULL, newlen, 278424df85d2SGleb Smirnoff SCM_RIGHTS, SOL_SOCKET, M_WAITOK); 27852bc21ed9SDavid Malone fdp = data; 2786f1cf2b9dSKonstantin Belousov for (i = 0; i < oldfds; i++, fdp++) { 2787f1cf2b9dSKonstantin Belousov if (!fhold(fdesc->fd_ofiles[*fdp].fde_file)) { 2788f1cf2b9dSKonstantin Belousov fdp = data; 2789f1cf2b9dSKonstantin Belousov for (j = 0; j < i; j++, fdp++) { 2790f1cf2b9dSKonstantin Belousov fdrop(fdesc->fd_ofiles[*fdp]. 2791f1cf2b9dSKonstantin Belousov fde_file, td); 2792f1cf2b9dSKonstantin Belousov } 2793f1cf2b9dSKonstantin Belousov FILEDESC_SUNLOCK(fdesc); 2794f1cf2b9dSKonstantin Belousov error = EBADF; 2795f1cf2b9dSKonstantin Belousov goto out; 2796f1cf2b9dSKonstantin Belousov } 2797f1cf2b9dSKonstantin Belousov } 2798f1cf2b9dSKonstantin Belousov fdp = data; 27998cb539f1SPawel Jakub Dawidek fdep = (struct filedescent **) 28002bc21ed9SDavid Malone CMSG_DATA(mtod(*controlp, struct cmsghdr *)); 28018cb539f1SPawel Jakub Dawidek fdev = malloc(sizeof(*fdev) * oldfds, M_FILECAPS, 28028cb539f1SPawel Jakub Dawidek M_WAITOK); 28038cb539f1SPawel Jakub Dawidek for (i = 0; i < oldfds; i++, fdev++, fdp++) { 28042609222aSPawel Jakub Dawidek fde = &fdesc->fd_ofiles[*fdp]; 28058cb539f1SPawel Jakub Dawidek fdep[i] = fdev; 28068cb539f1SPawel Jakub Dawidek fdep[i]->fde_file = fde->fde_file; 28078cb539f1SPawel Jakub Dawidek filecaps_copy(&fde->fde_caps, 2808d7832811SMateusz Guzik &fdep[i]->fde_caps, true); 28098cb539f1SPawel Jakub Dawidek unp_internalize_fp(fdep[i]->fde_file); 2810df8bae1dSRodney W. Grimes } 28112609222aSPawel Jakub Dawidek FILEDESC_SUNLOCK(fdesc); 28122bc21ed9SDavid Malone break; 28132bc21ed9SDavid Malone 28142bc21ed9SDavid Malone case SCM_TIMESTAMP: 2815b46667c6SGleb Smirnoff *controlp = sbcreatecontrol(NULL, sizeof(*tv), 281624df85d2SGleb Smirnoff SCM_TIMESTAMP, SOL_SOCKET, M_WAITOK); 28172bc21ed9SDavid Malone tv = (struct timeval *) 28182bc21ed9SDavid Malone CMSG_DATA(mtod(*controlp, struct cmsghdr *)); 28192bc21ed9SDavid Malone microtime(tv); 28202bc21ed9SDavid Malone break; 28212bc21ed9SDavid Malone 2822ab15d803SSergey Kandaurov case SCM_BINTIME: 2823b46667c6SGleb Smirnoff *controlp = sbcreatecontrol(NULL, sizeof(*bt), 282424df85d2SGleb Smirnoff SCM_BINTIME, SOL_SOCKET, M_WAITOK); 2825ab15d803SSergey Kandaurov bt = (struct bintime *) 2826ab15d803SSergey Kandaurov CMSG_DATA(mtod(*controlp, struct cmsghdr *)); 2827ab15d803SSergey Kandaurov bintime(bt); 2828ab15d803SSergey Kandaurov break; 2829ab15d803SSergey Kandaurov 2830339efd75SMaxim Sobolev case SCM_REALTIME: 2831b46667c6SGleb Smirnoff *controlp = sbcreatecontrol(NULL, sizeof(*ts), 283224df85d2SGleb Smirnoff SCM_REALTIME, SOL_SOCKET, M_WAITOK); 2833339efd75SMaxim Sobolev ts = (struct timespec *) 2834339efd75SMaxim Sobolev CMSG_DATA(mtod(*controlp, struct cmsghdr *)); 2835339efd75SMaxim Sobolev nanotime(ts); 2836339efd75SMaxim Sobolev break; 2837339efd75SMaxim Sobolev 2838339efd75SMaxim Sobolev case SCM_MONOTONIC: 2839b46667c6SGleb Smirnoff *controlp = sbcreatecontrol(NULL, sizeof(*ts), 284024df85d2SGleb Smirnoff SCM_MONOTONIC, SOL_SOCKET, M_WAITOK); 2841339efd75SMaxim Sobolev ts = (struct timespec *) 2842339efd75SMaxim Sobolev CMSG_DATA(mtod(*controlp, struct cmsghdr *)); 2843339efd75SMaxim Sobolev nanouptime(ts); 2844339efd75SMaxim Sobolev break; 2845339efd75SMaxim Sobolev 28462bc21ed9SDavid Malone default: 28472bc21ed9SDavid Malone error = EINVAL; 28482bc21ed9SDavid Malone goto out; 28492bc21ed9SDavid Malone } 28502bc21ed9SDavid Malone 28511093f164SGleb Smirnoff if (space != NULL) { 28521093f164SGleb Smirnoff *space += (*controlp)->m_len; 28531093f164SGleb Smirnoff *mbcnt += MSIZE; 28541093f164SGleb Smirnoff if ((*controlp)->m_flags & M_EXT) 28551093f164SGleb Smirnoff *mbcnt += (*controlp)->m_ext.ext_size; 28561093f164SGleb Smirnoff *clast = *controlp; 28571093f164SGleb Smirnoff } 28582bc21ed9SDavid Malone controlp = &(*controlp)->m_next; 28592bc21ed9SDavid Malone } 2860d97922c6SGleb Smirnoff if (clen > 0) 2861d97922c6SGleb Smirnoff error = EINVAL; 28622bc21ed9SDavid Malone 28632bc21ed9SDavid Malone out: 286447c3450eSKonstantin Belousov if (error != 0 && initial_controlp != NULL) 286547c3450eSKonstantin Belousov unp_internalize_cleanup_rights(*initial_controlp); 28662bc21ed9SDavid Malone m_freem(control); 28672bc21ed9SDavid Malone return (error); 2868df8bae1dSRodney W. Grimes } 2869df8bae1dSRodney W. Grimes 28705b950deaSRobert Watson static struct mbuf * 28711093f164SGleb Smirnoff unp_addsockcred(struct thread *td, struct mbuf *control, int mode, 28721093f164SGleb Smirnoff struct mbuf **clast, u_int *space, u_int *mbcnt) 28736a2989fdSMatthew N. Dodd { 287470df31f4SMaxim Konovalov struct mbuf *m, *n, *n_prev; 287570df31f4SMaxim Konovalov const struct cmsghdr *cm; 2876ede4af47SConrad Meyer int ngroups, i, cmsgtype; 2877ede4af47SConrad Meyer size_t ctrlsz; 28786a2989fdSMatthew N. Dodd 28796a2989fdSMatthew N. Dodd ngroups = MIN(td->td_ucred->cr_ngroups, CMGROUP_MAX); 2880ede4af47SConrad Meyer if (mode & UNP_WANTCRED_ALWAYS) { 2881ede4af47SConrad Meyer ctrlsz = SOCKCRED2SIZE(ngroups); 2882ede4af47SConrad Meyer cmsgtype = SCM_CREDS2; 2883ede4af47SConrad Meyer } else { 2884ede4af47SConrad Meyer ctrlsz = SOCKCREDSIZE(ngroups); 2885ede4af47SConrad Meyer cmsgtype = SCM_CREDS; 2886ede4af47SConrad Meyer } 2887ede4af47SConrad Meyer 2888b46667c6SGleb Smirnoff m = sbcreatecontrol(NULL, ctrlsz, cmsgtype, SOL_SOCKET, M_NOWAIT); 28896a2989fdSMatthew N. Dodd if (m == NULL) 28906a2989fdSMatthew N. Dodd return (control); 28911093f164SGleb Smirnoff MPASS((m->m_flags & M_EXT) == 0 && m->m_next == NULL); 28926a2989fdSMatthew N. Dodd 2893ede4af47SConrad Meyer if (mode & UNP_WANTCRED_ALWAYS) { 2894ede4af47SConrad Meyer struct sockcred2 *sc; 2895ede4af47SConrad Meyer 2896ede4af47SConrad Meyer sc = (void *)CMSG_DATA(mtod(m, struct cmsghdr *)); 2897ede4af47SConrad Meyer sc->sc_version = 0; 2898ede4af47SConrad Meyer sc->sc_pid = td->td_proc->p_pid; 28996a2989fdSMatthew N. Dodd sc->sc_uid = td->td_ucred->cr_ruid; 29006a2989fdSMatthew N. Dodd sc->sc_euid = td->td_ucred->cr_uid; 29016a2989fdSMatthew N. Dodd sc->sc_gid = td->td_ucred->cr_rgid; 29026a2989fdSMatthew N. Dodd sc->sc_egid = td->td_ucred->cr_gid; 29036a2989fdSMatthew N. Dodd sc->sc_ngroups = ngroups; 29046a2989fdSMatthew N. Dodd for (i = 0; i < sc->sc_ngroups; i++) 29056a2989fdSMatthew N. Dodd sc->sc_groups[i] = td->td_ucred->cr_groups[i]; 2906ede4af47SConrad Meyer } else { 2907ede4af47SConrad Meyer struct sockcred *sc; 2908ede4af47SConrad Meyer 2909ede4af47SConrad Meyer sc = (void *)CMSG_DATA(mtod(m, struct cmsghdr *)); 2910ede4af47SConrad Meyer sc->sc_uid = td->td_ucred->cr_ruid; 2911ede4af47SConrad Meyer sc->sc_euid = td->td_ucred->cr_uid; 2912ede4af47SConrad Meyer sc->sc_gid = td->td_ucred->cr_rgid; 2913ede4af47SConrad Meyer sc->sc_egid = td->td_ucred->cr_gid; 2914ede4af47SConrad Meyer sc->sc_ngroups = ngroups; 2915ede4af47SConrad Meyer for (i = 0; i < sc->sc_ngroups; i++) 2916ede4af47SConrad Meyer sc->sc_groups[i] = td->td_ucred->cr_groups[i]; 2917ede4af47SConrad Meyer } 29186a2989fdSMatthew N. Dodd 29196a2989fdSMatthew N. Dodd /* 29201c381b19SRobert Watson * Unlink SCM_CREDS control messages (struct cmsgcred), since just 29211c381b19SRobert Watson * created SCM_CREDS control message (struct sockcred) has another 29221c381b19SRobert Watson * format. 29236a2989fdSMatthew N. Dodd */ 2924ede4af47SConrad Meyer if (control != NULL && cmsgtype == SCM_CREDS) 292570df31f4SMaxim Konovalov for (n = control, n_prev = NULL; n != NULL;) { 292670df31f4SMaxim Konovalov cm = mtod(n, struct cmsghdr *); 292770df31f4SMaxim Konovalov if (cm->cmsg_level == SOL_SOCKET && 292870df31f4SMaxim Konovalov cm->cmsg_type == SCM_CREDS) { 292970df31f4SMaxim Konovalov if (n_prev == NULL) 293070df31f4SMaxim Konovalov control = n->m_next; 293170df31f4SMaxim Konovalov else 293270df31f4SMaxim Konovalov n_prev->m_next = n->m_next; 29331093f164SGleb Smirnoff if (space != NULL) { 29341093f164SGleb Smirnoff MPASS(*space >= n->m_len); 29351093f164SGleb Smirnoff *space -= n->m_len; 29361093f164SGleb Smirnoff MPASS(*mbcnt >= MSIZE); 29371093f164SGleb Smirnoff *mbcnt -= MSIZE; 29381093f164SGleb Smirnoff if (n->m_flags & M_EXT) { 29391093f164SGleb Smirnoff MPASS(*mbcnt >= 29401093f164SGleb Smirnoff n->m_ext.ext_size); 29411093f164SGleb Smirnoff *mbcnt -= n->m_ext.ext_size; 29421093f164SGleb Smirnoff } 29431093f164SGleb Smirnoff MPASS(clast); 29441093f164SGleb Smirnoff if (*clast == n) { 29451093f164SGleb Smirnoff MPASS(n->m_next == NULL); 29461093f164SGleb Smirnoff if (n_prev == NULL) 29471093f164SGleb Smirnoff *clast = m; 29481093f164SGleb Smirnoff else 29491093f164SGleb Smirnoff *clast = n_prev; 29501093f164SGleb Smirnoff } 29511093f164SGleb Smirnoff } 295270df31f4SMaxim Konovalov n = m_free(n); 295370df31f4SMaxim Konovalov } else { 295470df31f4SMaxim Konovalov n_prev = n; 295570df31f4SMaxim Konovalov n = n->m_next; 295670df31f4SMaxim Konovalov } 295770df31f4SMaxim Konovalov } 29586a2989fdSMatthew N. Dodd 295970df31f4SMaxim Konovalov /* Prepend it to the head. */ 296070df31f4SMaxim Konovalov m->m_next = control; 29611093f164SGleb Smirnoff if (space != NULL) { 29621093f164SGleb Smirnoff *space += m->m_len; 29631093f164SGleb Smirnoff *mbcnt += MSIZE; 29641093f164SGleb Smirnoff if (control == NULL) 29651093f164SGleb Smirnoff *clast = m; 29661093f164SGleb Smirnoff } 296770df31f4SMaxim Konovalov return (m); 29686a2989fdSMatthew N. Dodd } 29696a2989fdSMatthew N. Dodd 2970397c19d1SJeff Roberson static struct unpcb * 2971397c19d1SJeff Roberson fptounp(struct file *fp) 2972397c19d1SJeff Roberson { 2973397c19d1SJeff Roberson struct socket *so; 2974397c19d1SJeff Roberson 2975397c19d1SJeff Roberson if (fp->f_type != DTYPE_SOCKET) 2976397c19d1SJeff Roberson return (NULL); 2977397c19d1SJeff Roberson if ((so = fp->f_data) == NULL) 2978397c19d1SJeff Roberson return (NULL); 2979397c19d1SJeff Roberson if (so->so_proto->pr_domain != &localdomain) 2980397c19d1SJeff Roberson return (NULL); 2981397c19d1SJeff Roberson return sotounpcb(so); 2982397c19d1SJeff Roberson } 2983397c19d1SJeff Roberson 2984397c19d1SJeff Roberson static void 2985397c19d1SJeff Roberson unp_discard(struct file *fp) 2986397c19d1SJeff Roberson { 29870cb64678SKonstantin Belousov struct unp_defer *dr; 2988397c19d1SJeff Roberson 29890cb64678SKonstantin Belousov if (unp_externalize_fp(fp)) { 29900cb64678SKonstantin Belousov dr = malloc(sizeof(*dr), M_TEMP, M_WAITOK); 29910cb64678SKonstantin Belousov dr->ud_fp = fp; 29920cb64678SKonstantin Belousov UNP_DEFERRED_LOCK(); 29930cb64678SKonstantin Belousov SLIST_INSERT_HEAD(&unp_defers, dr, ud_link); 29940cb64678SKonstantin Belousov UNP_DEFERRED_UNLOCK(); 29950cb64678SKonstantin Belousov atomic_add_int(&unp_defers_count, 1); 29960cb64678SKonstantin Belousov taskqueue_enqueue(taskqueue_thread, &unp_defer_task); 29970cb64678SKonstantin Belousov } else 29984faa375cSMateusz Guzik closef_nothread(fp); 2999397c19d1SJeff Roberson } 3000397c19d1SJeff Roberson 3001397c19d1SJeff Roberson static void 30020cb64678SKonstantin Belousov unp_process_defers(void *arg __unused, int pending) 30030cb64678SKonstantin Belousov { 30040cb64678SKonstantin Belousov struct unp_defer *dr; 30050cb64678SKonstantin Belousov SLIST_HEAD(, unp_defer) drl; 30060cb64678SKonstantin Belousov int count; 30070cb64678SKonstantin Belousov 30080cb64678SKonstantin Belousov SLIST_INIT(&drl); 30090cb64678SKonstantin Belousov for (;;) { 30100cb64678SKonstantin Belousov UNP_DEFERRED_LOCK(); 30110cb64678SKonstantin Belousov if (SLIST_FIRST(&unp_defers) == NULL) { 30120cb64678SKonstantin Belousov UNP_DEFERRED_UNLOCK(); 30130cb64678SKonstantin Belousov break; 30140cb64678SKonstantin Belousov } 30150cb64678SKonstantin Belousov SLIST_SWAP(&unp_defers, &drl, unp_defer); 30160cb64678SKonstantin Belousov UNP_DEFERRED_UNLOCK(); 30170cb64678SKonstantin Belousov count = 0; 30180cb64678SKonstantin Belousov while ((dr = SLIST_FIRST(&drl)) != NULL) { 30190cb64678SKonstantin Belousov SLIST_REMOVE_HEAD(&drl, ud_link); 30204faa375cSMateusz Guzik closef_nothread(dr->ud_fp); 30210cb64678SKonstantin Belousov free(dr, M_TEMP); 30220cb64678SKonstantin Belousov count++; 30230cb64678SKonstantin Belousov } 30240cb64678SKonstantin Belousov atomic_add_int(&unp_defers_count, -count); 30250cb64678SKonstantin Belousov } 30260cb64678SKonstantin Belousov } 30270cb64678SKonstantin Belousov 30280cb64678SKonstantin Belousov static void 3029397c19d1SJeff Roberson unp_internalize_fp(struct file *fp) 3030397c19d1SJeff Roberson { 3031397c19d1SJeff Roberson struct unpcb *unp; 3032397c19d1SJeff Roberson 30333dab55bcSRobert Watson UNP_LINK_WLOCK(); 3034397c19d1SJeff Roberson if ((unp = fptounp(fp)) != NULL) { 3035397c19d1SJeff Roberson unp->unp_file = fp; 3036397c19d1SJeff Roberson unp->unp_msgcount++; 3037397c19d1SJeff Roberson } 3038397c19d1SJeff Roberson unp_rights++; 30393dab55bcSRobert Watson UNP_LINK_WUNLOCK(); 3040397c19d1SJeff Roberson } 3041397c19d1SJeff Roberson 30420cb64678SKonstantin Belousov static int 3043397c19d1SJeff Roberson unp_externalize_fp(struct file *fp) 3044397c19d1SJeff Roberson { 3045397c19d1SJeff Roberson struct unpcb *unp; 30460cb64678SKonstantin Belousov int ret; 3047397c19d1SJeff Roberson 30483dab55bcSRobert Watson UNP_LINK_WLOCK(); 30490cb64678SKonstantin Belousov if ((unp = fptounp(fp)) != NULL) { 3050397c19d1SJeff Roberson unp->unp_msgcount--; 30510cb64678SKonstantin Belousov ret = 1; 30520cb64678SKonstantin Belousov } else 30530cb64678SKonstantin Belousov ret = 0; 3054397c19d1SJeff Roberson unp_rights--; 30553dab55bcSRobert Watson UNP_LINK_WUNLOCK(); 30560cb64678SKonstantin Belousov return (ret); 3057397c19d1SJeff Roberson } 3058397c19d1SJeff Roberson 3059161a0c7cSRobert Watson /* 3060a0ec558aSRobert Watson * unp_defer indicates whether additional work has been defered for a future 3061a0ec558aSRobert Watson * pass through unp_gc(). It is thread local and does not require explicit 3062a0ec558aSRobert Watson * synchronization. 3063161a0c7cSRobert Watson */ 3064397c19d1SJeff Roberson static int unp_marked; 3065a0ec558aSRobert Watson 3066397c19d1SJeff Roberson static void 3067a9aa06f7SJason A. Harmening unp_remove_dead_ref(struct filedescent **fdep, int fdcount) 3068397c19d1SJeff Roberson { 3069397c19d1SJeff Roberson struct unpcb *unp; 3070be26ba7cSPawel Jakub Dawidek struct file *fp; 3071be26ba7cSPawel Jakub Dawidek int i; 3072397c19d1SJeff Roberson 3073a9aa06f7SJason A. Harmening /* 3074a9aa06f7SJason A. Harmening * This function can only be called from the gc task. 3075a9aa06f7SJason A. Harmening */ 3076a9aa06f7SJason A. Harmening KASSERT(taskqueue_member(taskqueue_thread, curthread) != 0, 3077a9aa06f7SJason A. Harmening ("%s: not on gc callout", __func__)); 3078a9aa06f7SJason A. Harmening UNP_LINK_LOCK_ASSERT(); 3079a9aa06f7SJason A. Harmening 3080be26ba7cSPawel Jakub Dawidek for (i = 0; i < fdcount; i++) { 3081be26ba7cSPawel Jakub Dawidek fp = fdep[i]->fde_file; 30826f552cb0SJeff Roberson if ((unp = fptounp(fp)) == NULL) 3083be26ba7cSPawel Jakub Dawidek continue; 3084a9aa06f7SJason A. Harmening if ((unp->unp_gcflag & UNPGC_DEAD) == 0) 3085be26ba7cSPawel Jakub Dawidek continue; 3086a9aa06f7SJason A. Harmening unp->unp_gcrefs--; 3087a9aa06f7SJason A. Harmening } 3088a9aa06f7SJason A. Harmening } 3089a9aa06f7SJason A. Harmening 3090a9aa06f7SJason A. Harmening static void 3091a9aa06f7SJason A. Harmening unp_restore_undead_ref(struct filedescent **fdep, int fdcount) 3092a9aa06f7SJason A. Harmening { 3093a9aa06f7SJason A. Harmening struct unpcb *unp; 3094a9aa06f7SJason A. Harmening struct file *fp; 3095a9aa06f7SJason A. Harmening int i; 3096a9aa06f7SJason A. Harmening 3097a9aa06f7SJason A. Harmening /* 3098a9aa06f7SJason A. Harmening * This function can only be called from the gc task. 3099a9aa06f7SJason A. Harmening */ 3100a9aa06f7SJason A. Harmening KASSERT(taskqueue_member(taskqueue_thread, curthread) != 0, 3101a9aa06f7SJason A. Harmening ("%s: not on gc callout", __func__)); 3102a9aa06f7SJason A. Harmening UNP_LINK_LOCK_ASSERT(); 3103a9aa06f7SJason A. Harmening 3104a9aa06f7SJason A. Harmening for (i = 0; i < fdcount; i++) { 3105a9aa06f7SJason A. Harmening fp = fdep[i]->fde_file; 3106a9aa06f7SJason A. Harmening if ((unp = fptounp(fp)) == NULL) 3107a9aa06f7SJason A. Harmening continue; 3108a9aa06f7SJason A. Harmening if ((unp->unp_gcflag & UNPGC_DEAD) == 0) 3109a9aa06f7SJason A. Harmening continue; 3110a9aa06f7SJason A. Harmening unp->unp_gcrefs++; 3111397c19d1SJeff Roberson unp_marked++; 3112397c19d1SJeff Roberson } 3113be26ba7cSPawel Jakub Dawidek } 3114397c19d1SJeff Roberson 3115397c19d1SJeff Roberson static void 3116a7444f80SGleb Smirnoff unp_scan_socket(struct socket *so, void (*op)(struct filedescent **, int)) 3117a7444f80SGleb Smirnoff { 3118458f475dSGleb Smirnoff struct sockbuf *sb; 3119a7444f80SGleb Smirnoff 3120a7444f80SGleb Smirnoff SOCK_LOCK_ASSERT(so); 3121a7444f80SGleb Smirnoff 3122a7444f80SGleb Smirnoff if (sotounpcb(so)->unp_gcflag & UNPGC_IGNORE_RIGHTS) 3123a7444f80SGleb Smirnoff return; 3124a7444f80SGleb Smirnoff 3125a7444f80SGleb Smirnoff SOCK_RECVBUF_LOCK(so); 3126a7444f80SGleb Smirnoff switch (so->so_type) { 3127a7444f80SGleb Smirnoff case SOCK_DGRAM: 3128a7444f80SGleb Smirnoff unp_scan(STAILQ_FIRST(&so->so_rcv.uxdg_mb), op); 3129458f475dSGleb Smirnoff unp_scan(so->so_rcv.uxdg_peeked, op); 3130458f475dSGleb Smirnoff TAILQ_FOREACH(sb, &so->so_rcv.uxdg_conns, uxdg_clist) 3131458f475dSGleb Smirnoff unp_scan(STAILQ_FIRST(&sb->uxdg_mb), op); 3132a7444f80SGleb Smirnoff break; 3133a7444f80SGleb Smirnoff case SOCK_STREAM: 3134a7444f80SGleb Smirnoff case SOCK_SEQPACKET: 3135a7444f80SGleb Smirnoff unp_scan(so->so_rcv.sb_mb, op); 3136a7444f80SGleb Smirnoff break; 3137a7444f80SGleb Smirnoff } 3138a7444f80SGleb Smirnoff SOCK_RECVBUF_UNLOCK(so); 3139a7444f80SGleb Smirnoff } 3140a7444f80SGleb Smirnoff 3141a7444f80SGleb Smirnoff static void 3142a9aa06f7SJason A. Harmening unp_gc_scan(struct unpcb *unp, void (*op)(struct filedescent **, int)) 3143397c19d1SJeff Roberson { 3144779f106aSGleb Smirnoff struct socket *so, *soa; 314560a5ef26SRobert Watson 3146397c19d1SJeff Roberson so = unp->unp_socket; 3147779f106aSGleb Smirnoff SOCK_LOCK(so); 3148779f106aSGleb Smirnoff if (SOLISTENING(so)) { 3149397c19d1SJeff Roberson /* 3150397c19d1SJeff Roberson * Mark all sockets in our accept queue. 3151397c19d1SJeff Roberson */ 3152a7444f80SGleb Smirnoff TAILQ_FOREACH(soa, &so->sol_comp, so_list) 3153a7444f80SGleb Smirnoff unp_scan_socket(soa, op); 3154779f106aSGleb Smirnoff } else { 3155779f106aSGleb Smirnoff /* 3156779f106aSGleb Smirnoff * Mark all sockets we reference with RIGHTS. 3157779f106aSGleb Smirnoff */ 3158a7444f80SGleb Smirnoff unp_scan_socket(so, op); 3159779f106aSGleb Smirnoff } 3160779f106aSGleb Smirnoff SOCK_UNLOCK(so); 3161397c19d1SJeff Roberson } 3162a0ec558aSRobert Watson 3163a0ec558aSRobert Watson static int unp_recycled; 3164be6b1304STom Rhodes SYSCTL_INT(_net_local, OID_AUTO, recycled, CTLFLAG_RD, &unp_recycled, 0, 3165be6b1304STom Rhodes "Number of unreachable sockets claimed by the garbage collector."); 3166df8bae1dSRodney W. Grimes 3167397c19d1SJeff Roberson static int unp_taskcount; 3168be6b1304STom Rhodes SYSCTL_INT(_net_local, OID_AUTO, taskcount, CTLFLAG_RD, &unp_taskcount, 0, 3169be6b1304STom Rhodes "Number of times the garbage collector has run."); 3170397c19d1SJeff Roberson 3171a9aa06f7SJason A. Harmening SYSCTL_UINT(_net_local, OID_AUTO, sockcount, CTLFLAG_RD, &unp_count, 0, 3172a9aa06f7SJason A. Harmening "Number of active local sockets."); 3173a9aa06f7SJason A. Harmening 3174f708ef1bSPoul-Henning Kamp static void 3175a0ec558aSRobert Watson unp_gc(__unused void *arg, int pending) 3176df8bae1dSRodney W. Grimes { 317784d61770SRobert Watson struct unp_head *heads[] = { &unp_dhead, &unp_shead, &unp_sphead, 317884d61770SRobert Watson NULL }; 3179397c19d1SJeff Roberson struct unp_head **head; 3180a9aa06f7SJason A. Harmening struct unp_head unp_deadhead; /* List of potentially-dead sockets. */ 3181f7780c61SKonstantin Belousov struct file *f, **unref; 3182a9aa06f7SJason A. Harmening struct unpcb *unp, *unptmp; 3183a9aa06f7SJason A. Harmening int i, total, unp_unreachable; 3184df8bae1dSRodney W. Grimes 3185a9aa06f7SJason A. Harmening LIST_INIT(&unp_deadhead); 3186a0ec558aSRobert Watson unp_taskcount++; 3187779f106aSGleb Smirnoff UNP_LINK_RLOCK(); 3188ed5b7817SJulian Elischer /* 3189a9aa06f7SJason A. Harmening * First determine which sockets may be in cycles. 3190ed5b7817SJulian Elischer */ 3191a9aa06f7SJason A. Harmening unp_unreachable = 0; 3192a9aa06f7SJason A. Harmening 3193397c19d1SJeff Roberson for (head = heads; *head != NULL; head++) 3194a9aa06f7SJason A. Harmening LIST_FOREACH(unp, *head, unp_link) { 3195a9aa06f7SJason A. Harmening KASSERT((unp->unp_gcflag & ~UNPGC_IGNORE_RIGHTS) == 0, 3196a9aa06f7SJason A. Harmening ("%s: unp %p has unexpected gc flags 0x%x", 3197a9aa06f7SJason A. Harmening __func__, unp, (unsigned int)unp->unp_gcflag)); 3198a9aa06f7SJason A. Harmening 3199a9aa06f7SJason A. Harmening f = unp->unp_file; 320060a5ef26SRobert Watson 3201397c19d1SJeff Roberson /* 3202a9aa06f7SJason A. Harmening * Check for an unreachable socket potentially in a 3203a9aa06f7SJason A. Harmening * cycle. It must be in a queue as indicated by 3204a9aa06f7SJason A. Harmening * msgcount, and this must equal the file reference 3205a9aa06f7SJason A. Harmening * count. Note that when msgcount is 0 the file is 3206a9aa06f7SJason A. Harmening * NULL. 3207a9aa06f7SJason A. Harmening */ 3208a9aa06f7SJason A. Harmening if (f != NULL && unp->unp_msgcount != 0 && 32093c50616fSMateusz Guzik refcount_load(&f->f_count) == unp->unp_msgcount) { 3210a9aa06f7SJason A. Harmening LIST_INSERT_HEAD(&unp_deadhead, unp, unp_dead); 3211a9aa06f7SJason A. Harmening unp->unp_gcflag |= UNPGC_DEAD; 3212a9aa06f7SJason A. Harmening unp->unp_gcrefs = unp->unp_msgcount; 3213a9aa06f7SJason A. Harmening unp_unreachable++; 3214a9aa06f7SJason A. Harmening } 3215a9aa06f7SJason A. Harmening } 3216a9aa06f7SJason A. Harmening 3217a9aa06f7SJason A. Harmening /* 3218a9aa06f7SJason A. Harmening * Scan all sockets previously marked as potentially being in a cycle 3219a9aa06f7SJason A. Harmening * and remove the references each socket holds on any UNPGC_DEAD 3220a9aa06f7SJason A. Harmening * sockets in its queue. After this step, all remaining references on 3221a9aa06f7SJason A. Harmening * sockets marked UNPGC_DEAD should not be part of any cycle. 3222a9aa06f7SJason A. Harmening */ 3223a9aa06f7SJason A. Harmening LIST_FOREACH(unp, &unp_deadhead, unp_dead) 3224a9aa06f7SJason A. Harmening unp_gc_scan(unp, unp_remove_dead_ref); 3225a9aa06f7SJason A. Harmening 3226a9aa06f7SJason A. Harmening /* 3227a9aa06f7SJason A. Harmening * If a socket still has a non-negative refcount, it cannot be in a 3228a9aa06f7SJason A. Harmening * cycle. In this case increment refcount of all children iteratively. 3229397c19d1SJeff Roberson * Stop the scan once we do a complete loop without discovering 3230397c19d1SJeff Roberson * a new reachable socket. 3231397c19d1SJeff Roberson */ 3232df8bae1dSRodney W. Grimes do { 3233397c19d1SJeff Roberson unp_marked = 0; 3234a9aa06f7SJason A. Harmening LIST_FOREACH_SAFE(unp, &unp_deadhead, unp_dead, unptmp) 3235a9aa06f7SJason A. Harmening if (unp->unp_gcrefs > 0) { 3236a9aa06f7SJason A. Harmening unp->unp_gcflag &= ~UNPGC_DEAD; 3237a9aa06f7SJason A. Harmening LIST_REMOVE(unp, unp_dead); 3238a9aa06f7SJason A. Harmening KASSERT(unp_unreachable > 0, 3239a9aa06f7SJason A. Harmening ("%s: unp_unreachable underflow.", 3240a9aa06f7SJason A. Harmening __func__)); 3241a9aa06f7SJason A. Harmening unp_unreachable--; 3242a9aa06f7SJason A. Harmening unp_gc_scan(unp, unp_restore_undead_ref); 3243a9aa06f7SJason A. Harmening } 3244397c19d1SJeff Roberson } while (unp_marked); 3245a9aa06f7SJason A. Harmening 3246779f106aSGleb Smirnoff UNP_LINK_RUNLOCK(); 3247a9aa06f7SJason A. Harmening 3248397c19d1SJeff Roberson if (unp_unreachable == 0) 3249397c19d1SJeff Roberson return; 325060a5ef26SRobert Watson 3251ed5b7817SJulian Elischer /* 3252a9aa06f7SJason A. Harmening * Allocate space for a local array of dead unpcbs. 3253a9aa06f7SJason A. Harmening * TODO: can this path be simplified by instead using the local 3254a9aa06f7SJason A. Harmening * dead list at unp_deadhead, after taking out references 3255a9aa06f7SJason A. Harmening * on the file object and/or unpcb and dropping the link lock? 3256ed5b7817SJulian Elischer */ 3257397c19d1SJeff Roberson unref = malloc(unp_unreachable * sizeof(struct file *), 3258397c19d1SJeff Roberson M_TEMP, M_WAITOK); 325960a5ef26SRobert Watson 3260ed5b7817SJulian Elischer /* 3261397c19d1SJeff Roberson * Iterate looking for sockets which have been specifically marked 3262a9aa06f7SJason A. Harmening * as unreachable and store them locally. 3263ed5b7817SJulian Elischer */ 3264f7780c61SKonstantin Belousov UNP_LINK_RLOCK(); 3265a9aa06f7SJason A. Harmening total = 0; 3266a9aa06f7SJason A. Harmening LIST_FOREACH(unp, &unp_deadhead, unp_dead) { 3267a9aa06f7SJason A. Harmening KASSERT((unp->unp_gcflag & UNPGC_DEAD) != 0, 3268a9aa06f7SJason A. Harmening ("%s: unp %p not marked UNPGC_DEAD", __func__, unp)); 3269a9aa06f7SJason A. Harmening unp->unp_gcflag &= ~UNPGC_DEAD; 3270f7780c61SKonstantin Belousov f = unp->unp_file; 3271f7780c61SKonstantin Belousov if (unp->unp_msgcount == 0 || f == NULL || 32723c50616fSMateusz Guzik refcount_load(&f->f_count) != unp->unp_msgcount || 3273f1cf2b9dSKonstantin Belousov !fhold(f)) 3274f7780c61SKonstantin Belousov continue; 3275f7780c61SKonstantin Belousov unref[total++] = f; 3276f7780c61SKonstantin Belousov KASSERT(total <= unp_unreachable, 3277a9aa06f7SJason A. Harmening ("%s: incorrect unreachable count.", __func__)); 3278397c19d1SJeff Roberson } 3279f7780c61SKonstantin Belousov UNP_LINK_RUNLOCK(); 328060a5ef26SRobert Watson 3281ed5b7817SJulian Elischer /* 3282397c19d1SJeff Roberson * Now flush all sockets, free'ing rights. This will free the 3283397c19d1SJeff Roberson * struct files associated with these sockets but leave each socket 3284397c19d1SJeff Roberson * with one remaining ref. 3285ed5b7817SJulian Elischer */ 32861fb51a12SBjoern A. Zeeb for (i = 0; i < total; i++) { 32871fb51a12SBjoern A. Zeeb struct socket *so; 32881fb51a12SBjoern A. Zeeb 32891fb51a12SBjoern A. Zeeb so = unref[i]->f_data; 32901fb51a12SBjoern A. Zeeb CURVNET_SET(so->so_vnet); 32911fb51a12SBjoern A. Zeeb sorflush(so); 32921fb51a12SBjoern A. Zeeb CURVNET_RESTORE(); 32931fb51a12SBjoern A. Zeeb } 329460a5ef26SRobert Watson 3295ed5b7817SJulian Elischer /* 3296397c19d1SJeff Roberson * And finally release the sockets so they can be reclaimed. 3297ed5b7817SJulian Elischer */ 3298f7780c61SKonstantin Belousov for (i = 0; i < total; i++) 3299397c19d1SJeff Roberson fdrop(unref[i], NULL); 3300f7780c61SKonstantin Belousov unp_recycled += total; 3301397c19d1SJeff Roberson free(unref, M_TEMP); 3302df8bae1dSRodney W. Grimes } 3303df8bae1dSRodney W. Grimes 33040c40f353SConrad Meyer /* 33050c40f353SConrad Meyer * Synchronize against unp_gc, which can trip over data as we are freeing it. 33060c40f353SConrad Meyer */ 33070c40f353SConrad Meyer static void 330899ab95dbSMark Johnston unp_dispose(struct socket *so) 33090c40f353SConrad Meyer { 3310458f475dSGleb Smirnoff struct sockbuf *sb; 33110c40f353SConrad Meyer struct unpcb *unp; 3312a982ce04SGleb Smirnoff struct mbuf *m; 33130c40f353SConrad Meyer 331442f2fa99SGleb Smirnoff MPASS(!SOLISTENING(so)); 331542f2fa99SGleb Smirnoff 33160c40f353SConrad Meyer unp = sotounpcb(so); 3317779f106aSGleb Smirnoff UNP_LINK_WLOCK(); 33180c40f353SConrad Meyer unp->unp_gcflag |= UNPGC_IGNORE_RIGHTS; 3319779f106aSGleb Smirnoff UNP_LINK_WUNLOCK(); 3320a982ce04SGleb Smirnoff 3321a982ce04SGleb Smirnoff /* 3322a982ce04SGleb Smirnoff * Grab our special mbufs before calling sbrelease(). 3323a982ce04SGleb Smirnoff */ 3324a982ce04SGleb Smirnoff SOCK_RECVBUF_LOCK(so); 3325a7444f80SGleb Smirnoff switch (so->so_type) { 3326a7444f80SGleb Smirnoff case SOCK_DGRAM: 3327458f475dSGleb Smirnoff while ((sb = TAILQ_FIRST(&so->so_rcv.uxdg_conns)) != NULL) { 3328458f475dSGleb Smirnoff STAILQ_CONCAT(&so->so_rcv.uxdg_mb, &sb->uxdg_mb); 3329458f475dSGleb Smirnoff TAILQ_REMOVE(&so->so_rcv.uxdg_conns, sb, uxdg_clist); 3330458f475dSGleb Smirnoff /* Note: socket of sb may reconnect. */ 3331458f475dSGleb Smirnoff sb->uxdg_cc = sb->uxdg_ctl = sb->uxdg_mbcnt = 0; 3332458f475dSGleb Smirnoff } 3333458f475dSGleb Smirnoff sb = &so->so_rcv; 3334458f475dSGleb Smirnoff if (sb->uxdg_peeked != NULL) { 3335458f475dSGleb Smirnoff STAILQ_INSERT_HEAD(&sb->uxdg_mb, sb->uxdg_peeked, 3336458f475dSGleb Smirnoff m_stailqpkt); 3337458f475dSGleb Smirnoff sb->uxdg_peeked = NULL; 3338458f475dSGleb Smirnoff } 3339a7444f80SGleb Smirnoff m = STAILQ_FIRST(&sb->uxdg_mb); 3340a7444f80SGleb Smirnoff STAILQ_INIT(&sb->uxdg_mb); 3341a7444f80SGleb Smirnoff /* XXX: our shortened sbrelease() */ 3342a7444f80SGleb Smirnoff (void)chgsbsize(so->so_cred->cr_uidinfo, &sb->sb_hiwat, 0, 3343a7444f80SGleb Smirnoff RLIM_INFINITY); 3344458f475dSGleb Smirnoff /* 3345458f475dSGleb Smirnoff * XXXGL Mark sb with SBS_CANTRCVMORE. This is needed to 3346458f475dSGleb Smirnoff * prevent uipc_sosend_dgram() or unp_disconnect() adding more 3347458f475dSGleb Smirnoff * data to the socket. 3348458f475dSGleb Smirnoff * We are now in dom_dispose and it could be a call from 3349458f475dSGleb Smirnoff * soshutdown() or from the final sofree(). The sofree() case 3350458f475dSGleb Smirnoff * is simple as it guarantees that no more sends will happen, 3351458f475dSGleb Smirnoff * however we can race with unp_disconnect() from our peer. 3352458f475dSGleb Smirnoff * The shutdown(2) case is more exotic. It would call into 3353458f475dSGleb Smirnoff * dom_dispose() only if socket is SS_ISCONNECTED. This is 3354458f475dSGleb Smirnoff * possible if we did connect(2) on this socket and we also 3355458f475dSGleb Smirnoff * had it bound with bind(2) and receive connections from other 3356458f475dSGleb Smirnoff * sockets. Because soshutdown() violates POSIX (see comment 3357458f475dSGleb Smirnoff * there) we will end up here shutting down our receive side. 3358458f475dSGleb Smirnoff * Of course this will have affect not only on the peer we 3359458f475dSGleb Smirnoff * connect(2)ed to, but also on all of the peers who had 3360458f475dSGleb Smirnoff * connect(2)ed to us. Their sends would end up with ENOBUFS. 3361458f475dSGleb Smirnoff */ 3362458f475dSGleb Smirnoff sb->sb_state |= SBS_CANTRCVMORE; 3363a7444f80SGleb Smirnoff break; 3364a7444f80SGleb Smirnoff case SOCK_STREAM: 3365a7444f80SGleb Smirnoff case SOCK_SEQPACKET: 3366458f475dSGleb Smirnoff sb = &so->so_rcv; 3367a982ce04SGleb Smirnoff m = sbcut_locked(sb, sb->sb_ccc); 3368a982ce04SGleb Smirnoff KASSERT(sb->sb_ccc == 0 && sb->sb_mb == 0 && sb->sb_mbcnt == 0, 3369a982ce04SGleb Smirnoff ("%s: ccc %u mb %p mbcnt %u", __func__, 3370a982ce04SGleb Smirnoff sb->sb_ccc, (void *)sb->sb_mb, sb->sb_mbcnt)); 337143283184SGleb Smirnoff sbrelease_locked(so, SO_RCV); 3372a7444f80SGleb Smirnoff break; 3373a7444f80SGleb Smirnoff } 3374a982ce04SGleb Smirnoff SOCK_RECVBUF_UNLOCK(so); 3375a982ce04SGleb Smirnoff if (SOCK_IO_RECV_OWNED(so)) 3376a982ce04SGleb Smirnoff SOCK_IO_RECV_UNLOCK(so); 3377a982ce04SGleb Smirnoff 33782e5bf7c4SGleb Smirnoff if (m != NULL) { 3379eac7f079SGleb Smirnoff unp_scan(m, unp_freerights); 33802e5bf7c4SGleb Smirnoff m_freem(m); 33812e5bf7c4SGleb Smirnoff } 33820c40f353SConrad Meyer } 33830c40f353SConrad Meyer 3384f708ef1bSPoul-Henning Kamp static void 3385be26ba7cSPawel Jakub Dawidek unp_scan(struct mbuf *m0, void (*op)(struct filedescent **, int)) 3386df8bae1dSRodney W. Grimes { 33872bc21ed9SDavid Malone struct mbuf *m; 33882bc21ed9SDavid Malone struct cmsghdr *cm; 33892bc21ed9SDavid Malone void *data; 33902bc21ed9SDavid Malone socklen_t clen, datalen; 3391df8bae1dSRodney W. Grimes 3392fc3fcacfSRobert Watson while (m0 != NULL) { 33932bc21ed9SDavid Malone for (m = m0; m; m = m->m_next) { 339412396bdcSDavid Malone if (m->m_type != MT_CONTROL) 3395df8bae1dSRodney W. Grimes continue; 33962bc21ed9SDavid Malone 33972bc21ed9SDavid Malone cm = mtod(m, struct cmsghdr *); 33982bc21ed9SDavid Malone clen = m->m_len; 33992bc21ed9SDavid Malone 34002bc21ed9SDavid Malone while (cm != NULL) { 34012bc21ed9SDavid Malone if (sizeof(*cm) > clen || cm->cmsg_len > clen) 34022bc21ed9SDavid Malone break; 34032bc21ed9SDavid Malone 34042bc21ed9SDavid Malone data = CMSG_DATA(cm); 34052bc21ed9SDavid Malone datalen = (caddr_t)cm + cm->cmsg_len 34062bc21ed9SDavid Malone - (caddr_t)data; 34072bc21ed9SDavid Malone 34082bc21ed9SDavid Malone if (cm->cmsg_level == SOL_SOCKET && 34092bc21ed9SDavid Malone cm->cmsg_type == SCM_RIGHTS) { 3410be26ba7cSPawel Jakub Dawidek (*op)(data, datalen / 3411be26ba7cSPawel Jakub Dawidek sizeof(struct filedescent *)); 34122bc21ed9SDavid Malone } 34132bc21ed9SDavid Malone 34142bc21ed9SDavid Malone if (CMSG_SPACE(datalen) < clen) { 34152bc21ed9SDavid Malone clen -= CMSG_SPACE(datalen); 34162bc21ed9SDavid Malone cm = (struct cmsghdr *) 34172bc21ed9SDavid Malone ((caddr_t)cm + CMSG_SPACE(datalen)); 34182bc21ed9SDavid Malone } else { 34192bc21ed9SDavid Malone clen = 0; 34202bc21ed9SDavid Malone cm = NULL; 34212bc21ed9SDavid Malone } 34222bc21ed9SDavid Malone } 3423df8bae1dSRodney W. Grimes } 3424c29a3321SKevin Lo m0 = m0->m_nextpkt; 3425df8bae1dSRodney W. Grimes } 3426df8bae1dSRodney W. Grimes } 3427df8bae1dSRodney W. Grimes 3428662c901cSMikolaj Golub /* 3429662c901cSMikolaj Golub * A helper function called by VFS before socket-type vnode reclamation. 3430662c901cSMikolaj Golub * For an active vnode it clears unp_vnode pointer and decrements unp_vnode 3431662c901cSMikolaj Golub * use count. 3432662c901cSMikolaj Golub */ 3433662c901cSMikolaj Golub void 3434662c901cSMikolaj Golub vfs_unp_reclaim(struct vnode *vp) 3435662c901cSMikolaj Golub { 3436662c901cSMikolaj Golub struct unpcb *unp; 3437662c901cSMikolaj Golub int active; 343875a67bf3SMatt Macy struct mtx *vplock; 3439662c901cSMikolaj Golub 3440662c901cSMikolaj Golub ASSERT_VOP_ELOCKED(vp, "vfs_unp_reclaim"); 3441662c901cSMikolaj Golub KASSERT(vp->v_type == VSOCK, 3442662c901cSMikolaj Golub ("vfs_unp_reclaim: vp->v_type != VSOCK")); 3443662c901cSMikolaj Golub 3444662c901cSMikolaj Golub active = 0; 344575a67bf3SMatt Macy vplock = mtx_pool_find(mtxpool_sleep, vp); 344675a67bf3SMatt Macy mtx_lock(vplock); 34470c3c207fSGleb Smirnoff VOP_UNP_CONNECT(vp, &unp); 3448662c901cSMikolaj Golub if (unp == NULL) 3449662c901cSMikolaj Golub goto done; 3450662c901cSMikolaj Golub UNP_PCB_LOCK(unp); 3451c7e41c8bSMikolaj Golub if (unp->unp_vnode == vp) { 3452c7e41c8bSMikolaj Golub VOP_UNP_DETACH(vp); 3453662c901cSMikolaj Golub unp->unp_vnode = NULL; 3454662c901cSMikolaj Golub active = 1; 3455662c901cSMikolaj Golub } 3456662c901cSMikolaj Golub UNP_PCB_UNLOCK(unp); 3457662c901cSMikolaj Golub done: 345875a67bf3SMatt Macy mtx_unlock(vplock); 3459662c901cSMikolaj Golub if (active) 3460662c901cSMikolaj Golub vunref(vp); 3461662c901cSMikolaj Golub } 3462662c901cSMikolaj Golub 346303c96c31SRobert Watson #ifdef DDB 346403c96c31SRobert Watson static void 346503c96c31SRobert Watson db_print_indent(int indent) 346603c96c31SRobert Watson { 346703c96c31SRobert Watson int i; 346803c96c31SRobert Watson 346903c96c31SRobert Watson for (i = 0; i < indent; i++) 347003c96c31SRobert Watson db_printf(" "); 347103c96c31SRobert Watson } 347203c96c31SRobert Watson 347303c96c31SRobert Watson static void 347403c96c31SRobert Watson db_print_unpflags(int unp_flags) 347503c96c31SRobert Watson { 347603c96c31SRobert Watson int comma; 347703c96c31SRobert Watson 347803c96c31SRobert Watson comma = 0; 347903c96c31SRobert Watson if (unp_flags & UNP_HAVEPC) { 348003c96c31SRobert Watson db_printf("%sUNP_HAVEPC", comma ? ", " : ""); 348103c96c31SRobert Watson comma = 1; 348203c96c31SRobert Watson } 34832de07e40SConrad Meyer if (unp_flags & UNP_WANTCRED_ALWAYS) { 34842de07e40SConrad Meyer db_printf("%sUNP_WANTCRED_ALWAYS", comma ? ", " : ""); 34852de07e40SConrad Meyer comma = 1; 34862de07e40SConrad Meyer } 34872de07e40SConrad Meyer if (unp_flags & UNP_WANTCRED_ONESHOT) { 34882de07e40SConrad Meyer db_printf("%sUNP_WANTCRED_ONESHOT", comma ? ", " : ""); 348903c96c31SRobert Watson comma = 1; 349003c96c31SRobert Watson } 349103c96c31SRobert Watson if (unp_flags & UNP_CONNWAIT) { 349203c96c31SRobert Watson db_printf("%sUNP_CONNWAIT", comma ? ", " : ""); 349303c96c31SRobert Watson comma = 1; 349403c96c31SRobert Watson } 349503c96c31SRobert Watson if (unp_flags & UNP_CONNECTING) { 349603c96c31SRobert Watson db_printf("%sUNP_CONNECTING", comma ? ", " : ""); 349703c96c31SRobert Watson comma = 1; 349803c96c31SRobert Watson } 349903c96c31SRobert Watson if (unp_flags & UNP_BINDING) { 350003c96c31SRobert Watson db_printf("%sUNP_BINDING", comma ? ", " : ""); 350103c96c31SRobert Watson comma = 1; 350203c96c31SRobert Watson } 350303c96c31SRobert Watson } 350403c96c31SRobert Watson 350503c96c31SRobert Watson static void 350603c96c31SRobert Watson db_print_xucred(int indent, struct xucred *xu) 350703c96c31SRobert Watson { 350803c96c31SRobert Watson int comma, i; 350903c96c31SRobert Watson 351003c96c31SRobert Watson db_print_indent(indent); 3511c5afec6eSDmitry Chagin db_printf("cr_version: %u cr_uid: %u cr_pid: %d cr_ngroups: %d\n", 3512c5afec6eSDmitry Chagin xu->cr_version, xu->cr_uid, xu->cr_pid, xu->cr_ngroups); 351303c96c31SRobert Watson db_print_indent(indent); 351403c96c31SRobert Watson db_printf("cr_groups: "); 351503c96c31SRobert Watson comma = 0; 351603c96c31SRobert Watson for (i = 0; i < xu->cr_ngroups; i++) { 351703c96c31SRobert Watson db_printf("%s%u", comma ? ", " : "", xu->cr_groups[i]); 351803c96c31SRobert Watson comma = 1; 351903c96c31SRobert Watson } 352003c96c31SRobert Watson db_printf("\n"); 352103c96c31SRobert Watson } 352203c96c31SRobert Watson 352303c96c31SRobert Watson static void 352403c96c31SRobert Watson db_print_unprefs(int indent, struct unp_head *uh) 352503c96c31SRobert Watson { 352603c96c31SRobert Watson struct unpcb *unp; 352703c96c31SRobert Watson int counter; 352803c96c31SRobert Watson 352903c96c31SRobert Watson counter = 0; 353003c96c31SRobert Watson LIST_FOREACH(unp, uh, unp_reflink) { 353103c96c31SRobert Watson if (counter % 4 == 0) 353203c96c31SRobert Watson db_print_indent(indent); 353303c96c31SRobert Watson db_printf("%p ", unp); 353403c96c31SRobert Watson if (counter % 4 == 3) 353503c96c31SRobert Watson db_printf("\n"); 353603c96c31SRobert Watson counter++; 353703c96c31SRobert Watson } 353803c96c31SRobert Watson if (counter != 0 && counter % 4 != 0) 353903c96c31SRobert Watson db_printf("\n"); 354003c96c31SRobert Watson } 354103c96c31SRobert Watson 354203c96c31SRobert Watson DB_SHOW_COMMAND(unpcb, db_show_unpcb) 354303c96c31SRobert Watson { 354403c96c31SRobert Watson struct unpcb *unp; 354503c96c31SRobert Watson 354603c96c31SRobert Watson if (!have_addr) { 354703c96c31SRobert Watson db_printf("usage: show unpcb <addr>\n"); 354803c96c31SRobert Watson return; 354903c96c31SRobert Watson } 355003c96c31SRobert Watson unp = (struct unpcb *)addr; 355103c96c31SRobert Watson 355203c96c31SRobert Watson db_printf("unp_socket: %p unp_vnode: %p\n", unp->unp_socket, 355303c96c31SRobert Watson unp->unp_vnode); 355403c96c31SRobert Watson 3555fc8fdae0SMatthew D Fleming db_printf("unp_ino: %ju unp_conn: %p\n", (uintmax_t)unp->unp_ino, 355603c96c31SRobert Watson unp->unp_conn); 355703c96c31SRobert Watson 355803c96c31SRobert Watson db_printf("unp_refs:\n"); 355903c96c31SRobert Watson db_print_unprefs(2, &unp->unp_refs); 356003c96c31SRobert Watson 356103c96c31SRobert Watson /* XXXRW: Would be nice to print the full address, if any. */ 356203c96c31SRobert Watson db_printf("unp_addr: %p\n", unp->unp_addr); 356303c96c31SRobert Watson 3564c2090e73SAlan Somers db_printf("unp_gencnt: %llu\n", 356503c96c31SRobert Watson (unsigned long long)unp->unp_gencnt); 356603c96c31SRobert Watson 356703c96c31SRobert Watson db_printf("unp_flags: %x (", unp->unp_flags); 356803c96c31SRobert Watson db_print_unpflags(unp->unp_flags); 356903c96c31SRobert Watson db_printf(")\n"); 357003c96c31SRobert Watson 357103c96c31SRobert Watson db_printf("unp_peercred:\n"); 357203c96c31SRobert Watson db_print_xucred(2, &unp->unp_peercred); 357303c96c31SRobert Watson 357403c96c31SRobert Watson db_printf("unp_refcount: %u\n", unp->unp_refcount); 357503c96c31SRobert Watson } 357603c96c31SRobert Watson #endif 3577