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 8fd532987SGleb Smirnoff * Copyright (c) 2022 Gleb Smirnoff <glebius@FreeBSD.org> 9df8bae1dSRodney W. Grimes * 10df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 11df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 12df8bae1dSRodney W. Grimes * are met: 13df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 14df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 15df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 16df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 17df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 1869a28758SEd Maste * 3. Neither the name of the University nor the names of its contributors 19df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 20df8bae1dSRodney W. Grimes * without specific prior written permission. 21df8bae1dSRodney W. Grimes * 22df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32df8bae1dSRodney W. Grimes * SUCH DAMAGE. 33df8bae1dSRodney W. Grimes * 34748e0b0aSGarrett Wollman * From: @(#)uipc_usrreq.c 8.3 (Berkeley) 1/4/94 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 37f23929fbSRobert Watson /* 38f23929fbSRobert Watson * UNIX Domain (Local) Sockets 39f23929fbSRobert Watson * 40f23929fbSRobert Watson * This is an implementation of UNIX (local) domain sockets. Each socket has 41f23929fbSRobert Watson * an associated struct unpcb (UNIX protocol control block). Stream sockets 42f23929fbSRobert Watson * may be connected to 0 or 1 other socket. Datagram sockets may be 43f23929fbSRobert Watson * connected to 0, 1, or many other sockets. Sockets may be created and 44f23929fbSRobert Watson * connected in pairs (socketpair(2)), or bound/connected to using the file 45f23929fbSRobert Watson * system name space. For most purposes, only the receive socket buffer is 46f23929fbSRobert Watson * used, as sending on one socket delivers directly to the receive socket 475b950deaSRobert Watson * buffer of a second socket. 485b950deaSRobert Watson * 495b950deaSRobert Watson * The implementation is substantially complicated by the fact that 505b950deaSRobert Watson * "ancillary data", such as file descriptors or credentials, may be passed 515b950deaSRobert Watson * across UNIX domain sockets. The potential for passing UNIX domain sockets 525b950deaSRobert Watson * over other UNIX domain sockets requires the implementation of a simple 535b950deaSRobert Watson * garbage collector to find and tear down cycles of disconnected sockets. 54aea52f1bSRobert Watson * 55aea52f1bSRobert Watson * TODO: 5684d61770SRobert Watson * RDM 57aea52f1bSRobert Watson * rethink name space problems 58aea52f1bSRobert Watson * need a proper out-of-band 59f23929fbSRobert Watson */ 60f23929fbSRobert Watson 61677b542eSDavid E. O'Brien #include <sys/cdefs.h> 62677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 63677b542eSDavid E. O'Brien 6403c96c31SRobert Watson #include "opt_ddb.h" 65335654d7SRobert Watson 66df8bae1dSRodney W. Grimes #include <sys/param.h> 674a144410SRobert Watson #include <sys/capsicum.h> 68fb919e4dSMark Murray #include <sys/domain.h> 694f590175SPaul Saab #include <sys/eventhandler.h> 70d5cbccecSMark Johnston #include <sys/fcntl.h> 71639acc13SGarrett Wollman #include <sys/file.h> 72960ed29cSSeigo Tanimura #include <sys/filedesc.h> 73960ed29cSSeigo Tanimura #include <sys/kernel.h> 74960ed29cSSeigo Tanimura #include <sys/lock.h> 75d5cbccecSMark Johnston #include <sys/malloc.h> 76639acc13SGarrett Wollman #include <sys/mbuf.h> 77033eb86eSJeff Roberson #include <sys/mount.h> 78960ed29cSSeigo Tanimura #include <sys/mutex.h> 79639acc13SGarrett Wollman #include <sys/namei.h> 80639acc13SGarrett Wollman #include <sys/proc.h> 81df8bae1dSRodney W. Grimes #include <sys/protosw.h> 820cb64678SKonstantin Belousov #include <sys/queue.h> 83960ed29cSSeigo Tanimura #include <sys/resourcevar.h> 84e7c33e29SRobert Watson #include <sys/rwlock.h> 85df8bae1dSRodney W. Grimes #include <sys/socket.h> 86df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 87960ed29cSSeigo Tanimura #include <sys/signalvar.h> 88df8bae1dSRodney W. Grimes #include <sys/stat.h> 89960ed29cSSeigo Tanimura #include <sys/sx.h> 90639acc13SGarrett Wollman #include <sys/sysctl.h> 91960ed29cSSeigo Tanimura #include <sys/systm.h> 92a0ec558aSRobert Watson #include <sys/taskqueue.h> 93639acc13SGarrett Wollman #include <sys/un.h> 9498271db4SGarrett Wollman #include <sys/unpcb.h> 95639acc13SGarrett Wollman #include <sys/vnode.h> 96530c0060SRobert Watson 97530c0060SRobert Watson #include <net/vnet.h> 98df8bae1dSRodney W. Grimes 9903c96c31SRobert Watson #ifdef DDB 10003c96c31SRobert Watson #include <ddb/ddb.h> 10103c96c31SRobert Watson #endif 10203c96c31SRobert Watson 103aed55708SRobert Watson #include <security/mac/mac_framework.h> 104aed55708SRobert Watson 1059e9d298aSJeff Roberson #include <vm/uma.h> 10698271db4SGarrett Wollman 1078cb539f1SPawel Jakub Dawidek MALLOC_DECLARE(M_FILECAPS); 1088cb539f1SPawel Jakub Dawidek 109e7d02be1SGleb Smirnoff static struct domain localdomain; 1103dab55bcSRobert Watson 1119e9d298aSJeff Roberson static uma_zone_t unp_zone; 1123dab55bcSRobert Watson static unp_gen_t unp_gencnt; /* (l) */ 1133dab55bcSRobert Watson static u_int unp_count; /* (l) Count of local sockets. */ 114aea52f1bSRobert Watson static ino_t unp_ino; /* Prototype for fake inode numbers. */ 1153dab55bcSRobert Watson static int unp_rights; /* (g) File descriptors in flight. */ 1163dab55bcSRobert Watson static struct unp_head unp_shead; /* (l) List of stream sockets. */ 1173dab55bcSRobert Watson static struct unp_head unp_dhead; /* (l) List of datagram sockets. */ 11884d61770SRobert Watson static struct unp_head unp_sphead; /* (l) List of seqpacket sockets. */ 11998271db4SGarrett Wollman 1200cb64678SKonstantin Belousov struct unp_defer { 1210cb64678SKonstantin Belousov SLIST_ENTRY(unp_defer) ud_link; 1220cb64678SKonstantin Belousov struct file *ud_fp; 1230cb64678SKonstantin Belousov }; 1240cb64678SKonstantin Belousov static SLIST_HEAD(, unp_defer) unp_defers; 1250cb64678SKonstantin Belousov static int unp_defers_count; 1260cb64678SKonstantin Belousov 127aea52f1bSRobert Watson static const struct sockaddr sun_noname = { sizeof(sun_noname), AF_LOCAL }; 12898271db4SGarrett Wollman 129df8bae1dSRodney W. Grimes /* 130aea52f1bSRobert Watson * Garbage collection of cyclic file descriptor/socket references occurs 131aea52f1bSRobert Watson * asynchronously in a taskqueue context in order to avoid recursion and 132aea52f1bSRobert Watson * reentrance in the UNIX domain socket, file descriptor, and socket layer 133aea52f1bSRobert Watson * code. See unp_gc() for a full description. 134df8bae1dSRodney W. Grimes */ 135daee0f0bSKonstantin Belousov static struct timeout_task unp_gc_task; 136f708ef1bSPoul-Henning Kamp 137ce5f32deSRobert Watson /* 1380cb64678SKonstantin Belousov * The close of unix domain sockets attached as SCM_RIGHTS is 1390cb64678SKonstantin Belousov * postponed to the taskqueue, to avoid arbitrary recursion depth. 1400cb64678SKonstantin Belousov * The attached sockets might have another sockets attached. 1410cb64678SKonstantin Belousov */ 1420cb64678SKonstantin Belousov static struct task unp_defer_task; 1430cb64678SKonstantin Belousov 1440cb64678SKonstantin Belousov /* 1457e711c3aSRobert Watson * Both send and receive buffers are allocated PIPSIZ bytes of buffering for 1467e711c3aSRobert Watson * stream sockets, although the total for sender and receiver is actually 1477e711c3aSRobert Watson * only PIPSIZ. 1487e711c3aSRobert Watson * 1497e711c3aSRobert Watson * Datagram sockets really use the sendspace as the maximum datagram size, 1507e711c3aSRobert Watson * and don't really want to reserve the sendspace. Their recvspace should be 1517e711c3aSRobert Watson * large enough for at least one max-size datagram plus address. 1527e711c3aSRobert Watson */ 1537e711c3aSRobert Watson #ifndef PIPSIZ 1547e711c3aSRobert Watson #define PIPSIZ 8192 1557e711c3aSRobert Watson #endif 1567e711c3aSRobert Watson static u_long unpst_sendspace = PIPSIZ; 1577e711c3aSRobert Watson static u_long unpst_recvspace = PIPSIZ; 1582573e6ceSGleb Smirnoff static u_long unpdg_maxdgram = 2*1024; 159d157f262SMark Johnston static u_long unpdg_recvspace = 16*1024; /* support 8KB syslog msgs */ 16084d61770SRobert Watson static u_long unpsp_sendspace = PIPSIZ; /* really max datagram size */ 16184d61770SRobert Watson static u_long unpsp_recvspace = PIPSIZ; 1627e711c3aSRobert Watson 1637029da5cSPawel Biernacki static SYSCTL_NODE(_net, PF_LOCAL, local, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 1647029da5cSPawel Biernacki "Local domain"); 1657029da5cSPawel Biernacki static SYSCTL_NODE(_net_local, SOCK_STREAM, stream, 1667029da5cSPawel Biernacki CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 1676472ac3dSEd Schouten "SOCK_STREAM"); 1687029da5cSPawel Biernacki static SYSCTL_NODE(_net_local, SOCK_DGRAM, dgram, 1697029da5cSPawel Biernacki CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 1707029da5cSPawel Biernacki "SOCK_DGRAM"); 1717029da5cSPawel Biernacki static SYSCTL_NODE(_net_local, SOCK_SEQPACKET, seqpacket, 1727029da5cSPawel Biernacki CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 17384d61770SRobert Watson "SOCK_SEQPACKET"); 174e4445a03SRobert Watson 1757e711c3aSRobert Watson SYSCTL_ULONG(_net_local_stream, OID_AUTO, sendspace, CTLFLAG_RW, 176be6b1304STom Rhodes &unpst_sendspace, 0, "Default stream send space."); 1777e711c3aSRobert Watson SYSCTL_ULONG(_net_local_stream, OID_AUTO, recvspace, CTLFLAG_RW, 178be6b1304STom Rhodes &unpst_recvspace, 0, "Default stream receive space."); 1797e711c3aSRobert Watson SYSCTL_ULONG(_net_local_dgram, OID_AUTO, maxdgram, CTLFLAG_RW, 1802573e6ceSGleb Smirnoff &unpdg_maxdgram, 0, "Maximum datagram size."); 1817e711c3aSRobert Watson SYSCTL_ULONG(_net_local_dgram, OID_AUTO, recvspace, CTLFLAG_RW, 182be6b1304STom Rhodes &unpdg_recvspace, 0, "Default datagram receive space."); 18384d61770SRobert Watson SYSCTL_ULONG(_net_local_seqpacket, OID_AUTO, maxseqpacket, CTLFLAG_RW, 18484d61770SRobert Watson &unpsp_sendspace, 0, "Default seqpacket send space."); 18584d61770SRobert Watson SYSCTL_ULONG(_net_local_seqpacket, OID_AUTO, recvspace, CTLFLAG_RW, 18684d61770SRobert Watson &unpsp_recvspace, 0, "Default seqpacket receive space."); 187be6b1304STom Rhodes SYSCTL_INT(_net_local, OID_AUTO, inflight, CTLFLAG_RD, &unp_rights, 0, 188be6b1304STom Rhodes "File descriptors in flight."); 1890cb64678SKonstantin Belousov SYSCTL_INT(_net_local, OID_AUTO, deferred, CTLFLAG_RD, 1900cb64678SKonstantin Belousov &unp_defers_count, 0, 1910cb64678SKonstantin Belousov "File descriptors deferred to taskqueue for close."); 1927e711c3aSRobert Watson 193175389cfSEdward Tomasz Napierala /* 194e7c33e29SRobert Watson * Locking and synchronization: 195ce5f32deSRobert Watson * 196d5cbccecSMark Johnston * Several types of locks exist in the local domain socket implementation: 197d5cbccecSMark Johnston * - a global linkage lock 198d5cbccecSMark Johnston * - a global connection list lock 199d5cbccecSMark Johnston * - the mtxpool lock 200d5cbccecSMark Johnston * - per-unpcb mutexes 201d5cbccecSMark Johnston * 202d5cbccecSMark Johnston * The linkage lock protects the global socket lists, the generation number 203d5cbccecSMark Johnston * counter and garbage collector state. 204d5cbccecSMark Johnston * 205d5cbccecSMark Johnston * The connection list lock protects the list of referring sockets in a datagram 206d5cbccecSMark Johnston * socket PCB. This lock is also overloaded to protect a global list of 207d5cbccecSMark Johnston * sockets whose buffers contain socket references in the form of SCM_RIGHTS 208d5cbccecSMark Johnston * messages. To avoid recursion, such references are released by a dedicated 209d5cbccecSMark Johnston * thread. 21075a67bf3SMatt Macy * 21175a67bf3SMatt Macy * The mtxpool lock protects the vnode from being modified while referenced. 212d5cbccecSMark Johnston * Lock ordering rules require that it be acquired before any PCB locks. 21375a67bf3SMatt Macy * 214d5cbccecSMark Johnston * The unpcb lock (unp_mtx) protects the most commonly referenced fields in the 215d5cbccecSMark Johnston * unpcb. This includes the unp_conn field, which either links two connected 216d5cbccecSMark Johnston * PCBs together (for connected socket types) or points at the destination 217d5cbccecSMark Johnston * socket (for connectionless socket types). The operations of creating or 218d5cbccecSMark Johnston * destroying a connection therefore involve locking multiple PCBs. To avoid 219d5cbccecSMark Johnston * lock order reversals, in some cases this involves dropping a PCB lock and 220d5cbccecSMark Johnston * using a reference counter to maintain liveness. 221ce5f32deSRobert Watson * 222e7c33e29SRobert Watson * UNIX domain sockets each have an unpcb hung off of their so_pcb pointer, 223e7d02be1SGleb Smirnoff * allocated in pr_attach() and freed in pr_detach(). The validity of that 224e7c33e29SRobert Watson * pointer is an invariant, so no lock is required to dereference the so_pcb 225e7c33e29SRobert Watson * pointer if a valid socket reference is held by the caller. In practice, 226e7c33e29SRobert Watson * this is always true during operations performed on a socket. Each unpcb 227e7c33e29SRobert Watson * has a back-pointer to its socket, unp_socket, which will be stable under 228e7c33e29SRobert Watson * the same circumstances. 229e7c33e29SRobert Watson * 230e7c33e29SRobert Watson * This pointer may only be safely dereferenced as long as a valid reference 231e7c33e29SRobert Watson * to the unpcb is held. Typically, this reference will be from the socket, 232e7c33e29SRobert Watson * or from another unpcb when the referring unpcb's lock is held (in order 233e7c33e29SRobert Watson * that the reference not be invalidated during use). For example, to follow 23475a67bf3SMatt Macy * unp->unp_conn->unp_socket, you need to hold a lock on unp_conn to guarantee 23575a67bf3SMatt Macy * that detach is not run clearing unp_socket. 236e7c33e29SRobert Watson * 237e7c33e29SRobert Watson * Blocking with UNIX domain sockets is a tricky issue: unlike most network 238e7c33e29SRobert Watson * protocols, bind() is a non-atomic operation, and connect() requires 239e7c33e29SRobert Watson * potential sleeping in the protocol, due to potentially waiting on local or 240e7c33e29SRobert Watson * distributed file systems. We try to separate "lookup" operations, which 241e7c33e29SRobert Watson * may sleep, and the IPC operations themselves, which typically can occur 242e7c33e29SRobert Watson * with relative atomicity as locks can be held over the entire operation. 243e7c33e29SRobert Watson * 244e7c33e29SRobert Watson * Another tricky issue is simultaneous multi-threaded or multi-process 245e7c33e29SRobert Watson * access to a single UNIX domain socket. These are handled by the flags 246e7c33e29SRobert Watson * UNP_CONNECTING and UNP_BINDING, which prevent concurrent connecting or 247e7c33e29SRobert Watson * binding, both of which involve dropping UNIX domain socket locks in order 248e7c33e29SRobert Watson * to perform namei() and other file system operations. 249ce5f32deSRobert Watson */ 2503dab55bcSRobert Watson static struct rwlock unp_link_rwlock; 2510cb64678SKonstantin Belousov static struct mtx unp_defers_lock; 252e7c33e29SRobert Watson 2533dab55bcSRobert Watson #define UNP_LINK_LOCK_INIT() rw_init(&unp_link_rwlock, \ 2543dab55bcSRobert Watson "unp_link_rwlock") 255e7c33e29SRobert Watson 2563dab55bcSRobert Watson #define UNP_LINK_LOCK_ASSERT() rw_assert(&unp_link_rwlock, \ 257e7c33e29SRobert Watson RA_LOCKED) 2583dab55bcSRobert Watson #define UNP_LINK_UNLOCK_ASSERT() rw_assert(&unp_link_rwlock, \ 259e7c33e29SRobert Watson RA_UNLOCKED) 260e7c33e29SRobert Watson 2613dab55bcSRobert Watson #define UNP_LINK_RLOCK() rw_rlock(&unp_link_rwlock) 2623dab55bcSRobert Watson #define UNP_LINK_RUNLOCK() rw_runlock(&unp_link_rwlock) 2633dab55bcSRobert Watson #define UNP_LINK_WLOCK() rw_wlock(&unp_link_rwlock) 2643dab55bcSRobert Watson #define UNP_LINK_WUNLOCK() rw_wunlock(&unp_link_rwlock) 2653dab55bcSRobert Watson #define UNP_LINK_WLOCK_ASSERT() rw_assert(&unp_link_rwlock, \ 266e7c33e29SRobert Watson RA_WLOCKED) 267779f106aSGleb Smirnoff #define UNP_LINK_WOWNED() rw_wowned(&unp_link_rwlock) 268e7c33e29SRobert Watson 2690cb64678SKonstantin Belousov #define UNP_DEFERRED_LOCK_INIT() mtx_init(&unp_defers_lock, \ 2700cb64678SKonstantin Belousov "unp_defer", NULL, MTX_DEF) 2710cb64678SKonstantin Belousov #define UNP_DEFERRED_LOCK() mtx_lock(&unp_defers_lock) 2720cb64678SKonstantin Belousov #define UNP_DEFERRED_UNLOCK() mtx_unlock(&unp_defers_lock) 2730cb64678SKonstantin Belousov 27475a67bf3SMatt Macy #define UNP_REF_LIST_LOCK() UNP_DEFERRED_LOCK(); 27575a67bf3SMatt Macy #define UNP_REF_LIST_UNLOCK() UNP_DEFERRED_UNLOCK(); 27675a67bf3SMatt Macy 277e7c33e29SRobert Watson #define UNP_PCB_LOCK_INIT(unp) mtx_init(&(unp)->unp_mtx, \ 278d9525340SMatt Macy "unp", "unp", \ 27975a67bf3SMatt Macy MTX_DUPOK|MTX_DEF) 280e7c33e29SRobert Watson #define UNP_PCB_LOCK_DESTROY(unp) mtx_destroy(&(unp)->unp_mtx) 281ccdadf1aSMark Johnston #define UNP_PCB_LOCKPTR(unp) (&(unp)->unp_mtx) 282e7c33e29SRobert Watson #define UNP_PCB_LOCK(unp) mtx_lock(&(unp)->unp_mtx) 28375a67bf3SMatt Macy #define UNP_PCB_TRYLOCK(unp) mtx_trylock(&(unp)->unp_mtx) 284e7c33e29SRobert Watson #define UNP_PCB_UNLOCK(unp) mtx_unlock(&(unp)->unp_mtx) 28575a67bf3SMatt Macy #define UNP_PCB_OWNED(unp) mtx_owned(&(unp)->unp_mtx) 286e7c33e29SRobert Watson #define UNP_PCB_LOCK_ASSERT(unp) mtx_assert(&(unp)->unp_mtx, MA_OWNED) 28775a67bf3SMatt Macy #define UNP_PCB_UNLOCK_ASSERT(unp) mtx_assert(&(unp)->unp_mtx, MA_NOTOWNED) 2880d9ce3a1SRobert Watson 2892c899584SRobert Watson static int uipc_connect2(struct socket *, struct socket *); 2900b36cd25SRobert Watson static int uipc_ctloutput(struct socket *, struct sockopt *); 291aea52f1bSRobert Watson static int unp_connect(struct socket *, struct sockaddr *, 292aea52f1bSRobert Watson struct thread *); 2937493f24eSPawel Jakub Dawidek static int unp_connectat(int, struct socket *, struct sockaddr *, 294315167c0SGleb Smirnoff struct thread *, bool); 295f6dc5aa3SGleb Smirnoff typedef enum { PRU_CONNECT, PRU_CONNECT2 } conn2_how; 296f6dc5aa3SGleb Smirnoff static void unp_connect2(struct socket *so, struct socket *so2, conn2_how); 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 421ac45e92fSRobert Watson static void 422a29f300eSGarrett Wollman uipc_abort(struct socket *so) 423df8bae1dSRodney W. Grimes { 424e7c33e29SRobert Watson struct unpcb *unp, *unp2; 425df8bae1dSRodney W. Grimes 42640f2ac28SRobert Watson unp = sotounpcb(so); 4274d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_abort: unp == NULL")); 42875a67bf3SMatt Macy UNP_PCB_UNLOCK_ASSERT(unp); 429e7c33e29SRobert Watson 430e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 431e7c33e29SRobert Watson unp2 = unp->unp_conn; 432e7c33e29SRobert Watson if (unp2 != NULL) { 43375a67bf3SMatt Macy unp_pcb_hold(unp2); 434e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 43575a67bf3SMatt Macy unp_drop(unp2); 43675a67bf3SMatt Macy } else 43775a67bf3SMatt Macy UNP_PCB_UNLOCK(unp); 438df8bae1dSRodney W. Grimes } 439df8bae1dSRodney W. Grimes 440a29f300eSGarrett Wollman static int 44157bf258eSGarrett Wollman uipc_accept(struct socket *so, struct sockaddr **nam) 442a29f300eSGarrett Wollman { 443e7c33e29SRobert Watson struct unpcb *unp, *unp2; 4440d9ce3a1SRobert Watson const struct sockaddr *sa; 445df8bae1dSRodney W. Grimes 446df8bae1dSRodney W. Grimes /* 4471c381b19SRobert Watson * Pass back name of connected socket, if it was bound and we are 4481c381b19SRobert Watson * still connected (our peer may have closed already!). 449df8bae1dSRodney W. Grimes */ 4504d4b555eSRobert Watson unp = sotounpcb(so); 4514d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_accept: unp == NULL")); 452e7c33e29SRobert Watson 4530d9ce3a1SRobert Watson *nam = malloc(sizeof(struct sockaddr_un), M_SONAME, M_WAITOK); 45444800027SMark Johnston UNP_PCB_LOCK(unp); 45544800027SMark Johnston unp2 = unp_pcb_lock_peer(unp); 45644800027SMark Johnston if (unp2 != NULL && unp2->unp_addr != NULL) 457e7c33e29SRobert Watson sa = (struct sockaddr *)unp2->unp_addr; 45844800027SMark Johnston else 4590d9ce3a1SRobert Watson sa = &sun_noname; 4600d9ce3a1SRobert Watson bcopy(sa, *nam, sa->sa_len); 461b4e07e3dSMark Johnston if (unp2 != NULL) 46244800027SMark Johnston unp_pcb_unlock_pair(unp, unp2); 463b4e07e3dSMark Johnston else 464b4e07e3dSMark Johnston UNP_PCB_UNLOCK(unp); 465e5aeaa0cSDag-Erling Smørgrav return (0); 466a29f300eSGarrett Wollman } 467df8bae1dSRodney W. Grimes 468a29f300eSGarrett Wollman static int 469b40ce416SJulian Elischer uipc_attach(struct socket *so, int proto, struct thread *td) 470a29f300eSGarrett Wollman { 471e7c33e29SRobert Watson u_long sendspace, recvspace; 4726d32873cSRobert Watson struct unpcb *unp; 4733dab55bcSRobert Watson int error; 474779f106aSGleb Smirnoff bool locked; 475df8bae1dSRodney W. Grimes 4766d32873cSRobert Watson KASSERT(so->so_pcb == NULL, ("uipc_attach: so_pcb != NULL")); 4776d32873cSRobert Watson if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 4786d32873cSRobert Watson switch (so->so_type) { 4796d32873cSRobert Watson case SOCK_STREAM: 480e7c33e29SRobert Watson sendspace = unpst_sendspace; 481e7c33e29SRobert Watson recvspace = unpst_recvspace; 4826d32873cSRobert Watson break; 4836d32873cSRobert Watson 4846d32873cSRobert Watson case SOCK_DGRAM: 485a7444f80SGleb Smirnoff STAILQ_INIT(&so->so_rcv.uxdg_mb); 486458f475dSGleb Smirnoff STAILQ_INIT(&so->so_snd.uxdg_mb); 487458f475dSGleb Smirnoff TAILQ_INIT(&so->so_rcv.uxdg_conns); 488458f475dSGleb Smirnoff /* 489458f475dSGleb Smirnoff * Since send buffer is either bypassed or is a part 490458f475dSGleb Smirnoff * of one-to-many receive buffer, we assign both space 491458f475dSGleb Smirnoff * limits to unpdg_recvspace. 492458f475dSGleb Smirnoff */ 493458f475dSGleb Smirnoff sendspace = recvspace = unpdg_recvspace; 4946d32873cSRobert Watson break; 4956d32873cSRobert Watson 49684d61770SRobert Watson case SOCK_SEQPACKET: 49784d61770SRobert Watson sendspace = unpsp_sendspace; 49884d61770SRobert Watson recvspace = unpsp_recvspace; 49984d61770SRobert Watson break; 50084d61770SRobert Watson 5016d32873cSRobert Watson default: 502e7c33e29SRobert Watson panic("uipc_attach"); 5036d32873cSRobert Watson } 504e7c33e29SRobert Watson error = soreserve(so, sendspace, recvspace); 5056d32873cSRobert Watson if (error) 5066d32873cSRobert Watson return (error); 5076d32873cSRobert Watson } 50846a1d9bfSRobert Watson unp = uma_zalloc(unp_zone, M_NOWAIT | M_ZERO); 5096d32873cSRobert Watson if (unp == NULL) 5106d32873cSRobert Watson return (ENOBUFS); 5116d32873cSRobert Watson LIST_INIT(&unp->unp_refs); 512e7c33e29SRobert Watson UNP_PCB_LOCK_INIT(unp); 5136d32873cSRobert Watson unp->unp_socket = so; 5146d32873cSRobert Watson so->so_pcb = unp; 5155362170dSMark Johnston refcount_init(&unp->unp_refcount, 1); 516e7c33e29SRobert Watson 517779f106aSGleb Smirnoff if ((locked = UNP_LINK_WOWNED()) == false) 518779f106aSGleb Smirnoff UNP_LINK_WLOCK(); 519779f106aSGleb Smirnoff 5206d32873cSRobert Watson unp->unp_gencnt = ++unp_gencnt; 521f218ac50SMateusz Guzik unp->unp_ino = ++unp_ino; 5226d32873cSRobert Watson unp_count++; 52384d61770SRobert Watson switch (so->so_type) { 52484d61770SRobert Watson case SOCK_STREAM: 52584d61770SRobert Watson LIST_INSERT_HEAD(&unp_shead, unp, unp_link); 52684d61770SRobert Watson break; 52784d61770SRobert Watson 52884d61770SRobert Watson case SOCK_DGRAM: 52984d61770SRobert Watson LIST_INSERT_HEAD(&unp_dhead, unp, unp_link); 53084d61770SRobert Watson break; 53184d61770SRobert Watson 53284d61770SRobert Watson case SOCK_SEQPACKET: 53384d61770SRobert Watson LIST_INSERT_HEAD(&unp_sphead, unp, unp_link); 53484d61770SRobert Watson break; 53584d61770SRobert Watson 53684d61770SRobert Watson default: 53784d61770SRobert Watson panic("uipc_attach"); 53884d61770SRobert Watson } 539779f106aSGleb Smirnoff 540779f106aSGleb Smirnoff if (locked == false) 541779f106aSGleb Smirnoff UNP_LINK_WUNLOCK(); 5426d32873cSRobert Watson 5436d32873cSRobert Watson return (0); 544a29f300eSGarrett Wollman } 545a29f300eSGarrett Wollman 546a29f300eSGarrett Wollman static int 5477493f24eSPawel Jakub Dawidek uipc_bindat(int fd, struct socket *so, struct sockaddr *nam, struct thread *td) 548a29f300eSGarrett Wollman { 549dd47f5caSRobert Watson struct sockaddr_un *soun = (struct sockaddr_un *)nam; 550dd47f5caSRobert Watson struct vattr vattr; 5515050aa86SKonstantin Belousov int error, namelen; 552dd47f5caSRobert Watson struct nameidata nd; 55340f2ac28SRobert Watson struct unpcb *unp; 554dd47f5caSRobert Watson struct vnode *vp; 555dd47f5caSRobert Watson struct mount *mp; 5567008be5bSPawel Jakub Dawidek cap_rights_t rights; 557dd47f5caSRobert Watson char *buf; 558a29f300eSGarrett Wollman 559cb7df69bSKevin Lo if (nam->sa_family != AF_UNIX) 560cb7df69bSKevin Lo return (EAFNOSUPPORT); 561cb7df69bSKevin Lo 56240f2ac28SRobert Watson unp = sotounpcb(so); 5634d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_bind: unp == NULL")); 5644f1f0ef5SRobert Watson 565a06534c3SBjoern A. Zeeb if (soun->sun_len > sizeof(struct sockaddr_un)) 566a06534c3SBjoern A. Zeeb return (EINVAL); 5674f1f0ef5SRobert Watson namelen = soun->sun_len - offsetof(struct sockaddr_un, sun_path); 5684f1f0ef5SRobert Watson if (namelen <= 0) 5694f1f0ef5SRobert Watson return (EINVAL); 570dd47f5caSRobert Watson 571dd47f5caSRobert Watson /* 5724f1f0ef5SRobert Watson * We don't allow simultaneous bind() calls on a single UNIX domain 5734f1f0ef5SRobert Watson * socket, so flag in-progress operations, and return an error if an 5744f1f0ef5SRobert Watson * operation is already in progress. 5754f1f0ef5SRobert Watson * 5764f1f0ef5SRobert Watson * Historically, we have not allowed a socket to be rebound, so this 577d7924b70SRobert Watson * also returns an error. Not allowing re-binding simplifies the 578d7924b70SRobert Watson * implementation and avoids a great many possible failure modes. 579dd47f5caSRobert Watson */ 580e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 581dd47f5caSRobert Watson if (unp->unp_vnode != NULL) { 582e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 583dd47f5caSRobert Watson return (EINVAL); 584dd47f5caSRobert Watson } 5854f1f0ef5SRobert Watson if (unp->unp_flags & UNP_BINDING) { 586e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 5874f1f0ef5SRobert Watson return (EALREADY); 588dd47f5caSRobert Watson } 5894f1f0ef5SRobert Watson unp->unp_flags |= UNP_BINDING; 590e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 591dd47f5caSRobert Watson 592dd47f5caSRobert Watson buf = malloc(namelen + 1, M_TEMP, M_WAITOK); 5937928893dSEd Maste bcopy(soun->sun_path, buf, namelen); 5947928893dSEd Maste buf[namelen] = 0; 595dd47f5caSRobert Watson 596dd47f5caSRobert Watson restart: 5975b5b7e2cSMateusz Guzik NDINIT_ATRIGHTS(&nd, CREATE, NOFOLLOW | LOCKPARENT | NOCACHE, 5987e1d3eefSMateusz Guzik UIO_SYSSPACE, buf, fd, cap_rights_init_one(&rights, CAP_BINDAT)); 599dd47f5caSRobert Watson /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ 600dd47f5caSRobert Watson error = namei(&nd); 601dd47f5caSRobert Watson if (error) 6024f1f0ef5SRobert Watson goto error; 603dd47f5caSRobert Watson vp = nd.ni_vp; 604dd47f5caSRobert Watson if (vp != NULL || vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) { 605bb92cd7bSMateusz Guzik NDFREE_PNBUF(&nd); 606dd47f5caSRobert Watson if (nd.ni_dvp == vp) 607dd47f5caSRobert Watson vrele(nd.ni_dvp); 608dd47f5caSRobert Watson else 609dd47f5caSRobert Watson vput(nd.ni_dvp); 610dd47f5caSRobert Watson if (vp != NULL) { 611dd47f5caSRobert Watson vrele(vp); 612dd47f5caSRobert Watson error = EADDRINUSE; 6134f1f0ef5SRobert Watson goto error; 614dd47f5caSRobert Watson } 615a75d1dddSMateusz Guzik error = vn_start_write(NULL, &mp, V_XSLEEP | V_PCATCH); 616dd47f5caSRobert Watson if (error) 6174f1f0ef5SRobert Watson goto error; 618dd47f5caSRobert Watson goto restart; 619dd47f5caSRobert Watson } 620dd47f5caSRobert Watson VATTR_NULL(&vattr); 621dd47f5caSRobert Watson vattr.va_type = VSOCK; 62285078b85SConrad Meyer vattr.va_mode = (ACCESSPERMS & ~td->td_proc->p_pd->pd_cmask); 623dd47f5caSRobert Watson #ifdef MAC 62430d239bcSRobert Watson error = mac_vnode_check_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd, 625dd47f5caSRobert Watson &vattr); 626dd47f5caSRobert Watson #endif 627885868cdSRobert Watson if (error == 0) 628dd47f5caSRobert Watson error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 629bb92cd7bSMateusz Guzik NDFREE_PNBUF(&nd); 630dd47f5caSRobert Watson if (error) { 6313b2aa360SKonstantin Belousov VOP_VPUT_PAIR(nd.ni_dvp, NULL, true); 632dd47f5caSRobert Watson vn_finished_write(mp); 633441eb16aSKonstantin Belousov if (error == ERELOOKUP) 634441eb16aSKonstantin Belousov goto restart; 6354f1f0ef5SRobert Watson goto error; 636dd47f5caSRobert Watson } 637dd47f5caSRobert Watson vp = nd.ni_vp; 63857fd3d55SPawel Jakub Dawidek ASSERT_VOP_ELOCKED(vp, "uipc_bind"); 639dd47f5caSRobert Watson soun = (struct sockaddr_un *)sodupsockaddr(nam, M_WAITOK); 640e7c33e29SRobert Watson 641e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 6420c3c207fSGleb Smirnoff VOP_UNP_BIND(vp, unp); 643dd47f5caSRobert Watson unp->unp_vnode = vp; 644dd47f5caSRobert Watson unp->unp_addr = soun; 6454f1f0ef5SRobert Watson unp->unp_flags &= ~UNP_BINDING; 646e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 6473b2aa360SKonstantin Belousov vref(vp); 6483b2aa360SKonstantin Belousov VOP_VPUT_PAIR(nd.ni_dvp, &vp, true); 649dd47f5caSRobert Watson vn_finished_write(mp); 6504f1f0ef5SRobert Watson free(buf, M_TEMP); 6514f1f0ef5SRobert Watson return (0); 652e7c33e29SRobert Watson 6534f1f0ef5SRobert Watson error: 654e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 6554f1f0ef5SRobert Watson unp->unp_flags &= ~UNP_BINDING; 656e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 657dd47f5caSRobert Watson free(buf, M_TEMP); 65840f2ac28SRobert Watson return (error); 659a29f300eSGarrett Wollman } 660a29f300eSGarrett Wollman 661a29f300eSGarrett Wollman static int 6627493f24eSPawel Jakub Dawidek uipc_bind(struct socket *so, struct sockaddr *nam, struct thread *td) 6637493f24eSPawel Jakub Dawidek { 6647493f24eSPawel Jakub Dawidek 6657493f24eSPawel Jakub Dawidek return (uipc_bindat(AT_FDCWD, so, nam, td)); 6667493f24eSPawel Jakub Dawidek } 6677493f24eSPawel Jakub Dawidek 6687493f24eSPawel Jakub Dawidek static int 669b40ce416SJulian Elischer uipc_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 670a29f300eSGarrett Wollman { 6710d9ce3a1SRobert Watson int error; 672a29f300eSGarrett Wollman 673fd179ee9SRobert Watson KASSERT(td == curthread, ("uipc_connect: td != curthread")); 674fd179ee9SRobert Watson error = unp_connect(so, nam, td); 6750d9ce3a1SRobert Watson return (error); 676a29f300eSGarrett Wollman } 677a29f300eSGarrett Wollman 6787493f24eSPawel Jakub Dawidek static int 6797493f24eSPawel Jakub Dawidek uipc_connectat(int fd, struct socket *so, struct sockaddr *nam, 6807493f24eSPawel Jakub Dawidek struct thread *td) 6817493f24eSPawel Jakub Dawidek { 6827493f24eSPawel Jakub Dawidek int error; 6837493f24eSPawel Jakub Dawidek 6847493f24eSPawel Jakub Dawidek KASSERT(td == curthread, ("uipc_connectat: td != curthread")); 685315167c0SGleb Smirnoff error = unp_connectat(fd, so, nam, td, false); 6867493f24eSPawel Jakub Dawidek return (error); 6877493f24eSPawel Jakub Dawidek } 6887493f24eSPawel Jakub Dawidek 689a152f8a3SRobert Watson static void 690a152f8a3SRobert Watson uipc_close(struct socket *so) 691a152f8a3SRobert Watson { 692e7c33e29SRobert Watson struct unpcb *unp, *unp2; 693779f106aSGleb Smirnoff struct vnode *vp = NULL; 69475a67bf3SMatt Macy struct mtx *vplock; 695ccdadf1aSMark Johnston 696a152f8a3SRobert Watson unp = sotounpcb(so); 697a152f8a3SRobert Watson KASSERT(unp != NULL, ("uipc_close: unp == NULL")); 698e7c33e29SRobert Watson 69975a67bf3SMatt Macy vplock = NULL; 70075a67bf3SMatt Macy if ((vp = unp->unp_vnode) != NULL) { 70175a67bf3SMatt Macy vplock = mtx_pool_find(mtxpool_sleep, vp); 70275a67bf3SMatt Macy mtx_lock(vplock); 703e7c33e29SRobert Watson } 70475a67bf3SMatt Macy UNP_PCB_LOCK(unp); 70575a67bf3SMatt Macy if (vp && unp->unp_vnode == NULL) { 70675a67bf3SMatt Macy mtx_unlock(vplock); 70775a67bf3SMatt Macy vp = NULL; 70875a67bf3SMatt Macy } 70975a67bf3SMatt Macy if (vp != NULL) { 710779f106aSGleb Smirnoff VOP_UNP_DETACH(vp); 711779f106aSGleb Smirnoff unp->unp_vnode = NULL; 712779f106aSGleb Smirnoff } 713ccdadf1aSMark Johnston if ((unp2 = unp_pcb_lock_peer(unp)) != NULL) 714acf9fd05SMatt Macy unp_disconnect(unp, unp2); 715ccdadf1aSMark Johnston else 716e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 71775a67bf3SMatt Macy if (vp) { 71875a67bf3SMatt Macy mtx_unlock(vplock); 719779f106aSGleb Smirnoff vrele(vp); 720a152f8a3SRobert Watson } 72175a67bf3SMatt Macy } 722a152f8a3SRobert Watson 7232c899584SRobert Watson static int 724a29f300eSGarrett Wollman uipc_connect2(struct socket *so1, struct socket *so2) 725a29f300eSGarrett Wollman { 726e7c33e29SRobert Watson struct unpcb *unp, *unp2; 72708f17d14SGleb Smirnoff 72808f17d14SGleb Smirnoff if (so1->so_type != so2->so_type) 72908f17d14SGleb Smirnoff return (EPROTOTYPE); 730a29f300eSGarrett Wollman 731e7c33e29SRobert Watson unp = so1->so_pcb; 7324d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_connect2: unp == NULL")); 733e7c33e29SRobert Watson unp2 = so2->so_pcb; 734e7c33e29SRobert Watson KASSERT(unp2 != NULL, ("uipc_connect2: unp2 == NULL")); 7354820bf6aSMark Johnston unp_pcb_lock_pair(unp, unp2); 73608f17d14SGleb Smirnoff unp_connect2(so1, so2, PRU_CONNECT2); 7374820bf6aSMark Johnston unp_pcb_unlock_pair(unp, unp2); 73808f17d14SGleb Smirnoff 73908f17d14SGleb Smirnoff return (0); 740a29f300eSGarrett Wollman } 741a29f300eSGarrett Wollman 742bc725eafSRobert Watson static void 743a29f300eSGarrett Wollman uipc_detach(struct socket *so) 744a29f300eSGarrett Wollman { 745e7c33e29SRobert Watson struct unpcb *unp, *unp2; 74675a67bf3SMatt Macy struct mtx *vplock; 7476d32873cSRobert Watson struct vnode *vp; 748ccdadf1aSMark Johnston int local_unp_rights; 749a29f300eSGarrett Wollman 75040f2ac28SRobert Watson unp = sotounpcb(so); 7514d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_detach: unp == NULL")); 752e7c33e29SRobert Watson 753434ac8b6SMark Johnston vp = NULL; 754c0874c34SMatt Macy vplock = NULL; 755434ac8b6SMark Johnston 756779f106aSGleb Smirnoff UNP_LINK_WLOCK(); 7576d32873cSRobert Watson LIST_REMOVE(unp, unp_link); 758a9aa06f7SJason A. Harmening if (unp->unp_gcflag & UNPGC_DEAD) 759a9aa06f7SJason A. Harmening LIST_REMOVE(unp, unp_dead); 7606d32873cSRobert Watson unp->unp_gencnt = ++unp_gencnt; 7616d32873cSRobert Watson --unp_count; 76275a67bf3SMatt Macy UNP_LINK_WUNLOCK(); 763434ac8b6SMark Johnston 76475a67bf3SMatt Macy UNP_PCB_UNLOCK_ASSERT(unp); 76575a67bf3SMatt Macy restart: 76675a67bf3SMatt Macy if ((vp = unp->unp_vnode) != NULL) { 76775a67bf3SMatt Macy vplock = mtx_pool_find(mtxpool_sleep, vp); 76875a67bf3SMatt Macy mtx_lock(vplock); 76975a67bf3SMatt Macy } 77075a67bf3SMatt Macy UNP_PCB_LOCK(unp); 771db38b699SMark Johnston if (unp->unp_vnode != vp && unp->unp_vnode != NULL) { 772c0874c34SMatt Macy if (vplock) 77375a67bf3SMatt Macy mtx_unlock(vplock); 77475a67bf3SMatt Macy UNP_PCB_UNLOCK(unp); 77575a67bf3SMatt Macy goto restart; 77675a67bf3SMatt Macy } 7776d32873cSRobert Watson if ((vp = unp->unp_vnode) != NULL) { 778c7e41c8bSMikolaj Golub VOP_UNP_DETACH(vp); 7796d32873cSRobert Watson unp->unp_vnode = NULL; 7806d32873cSRobert Watson } 781ccdadf1aSMark Johnston if ((unp2 = unp_pcb_lock_peer(unp)) != NULL) 782e7c33e29SRobert Watson unp_disconnect(unp, unp2); 783f0317f86SMark Johnston else 78475a67bf3SMatt Macy UNP_PCB_UNLOCK(unp); 785ccdadf1aSMark Johnston 78675a67bf3SMatt Macy UNP_REF_LIST_LOCK(); 7876d32873cSRobert Watson while (!LIST_EMPTY(&unp->unp_refs)) { 7886d32873cSRobert Watson struct unpcb *ref = LIST_FIRST(&unp->unp_refs); 789e7c33e29SRobert Watson 79075a67bf3SMatt Macy unp_pcb_hold(ref); 79175a67bf3SMatt Macy UNP_REF_LIST_UNLOCK(); 79275a67bf3SMatt Macy 79375a67bf3SMatt Macy MPASS(ref != unp); 79475a67bf3SMatt Macy UNP_PCB_UNLOCK_ASSERT(ref); 795afc055d9SEd Schouten unp_drop(ref); 79675a67bf3SMatt Macy UNP_REF_LIST_LOCK(); 7976d32873cSRobert Watson } 79875a67bf3SMatt Macy UNP_REF_LIST_UNLOCK(); 799ccdadf1aSMark Johnston 80075a67bf3SMatt Macy UNP_PCB_LOCK(unp); 801397c19d1SJeff Roberson local_unp_rights = unp_rights; 8026d32873cSRobert Watson unp->unp_socket->so_pcb = NULL; 80375a67bf3SMatt Macy unp->unp_socket = NULL; 804db38b699SMark Johnston free(unp->unp_addr, M_SONAME); 805db38b699SMark Johnston unp->unp_addr = NULL; 806db38b699SMark Johnston if (!unp_pcb_rele(unp)) 8076e2faa24SRobert Watson UNP_PCB_UNLOCK(unp); 80875a67bf3SMatt Macy if (vp) { 80975a67bf3SMatt Macy mtx_unlock(vplock); 8106d32873cSRobert Watson vrele(vp); 81175a67bf3SMatt Macy } 8126d32873cSRobert Watson if (local_unp_rights) 813daee0f0bSKonstantin Belousov taskqueue_enqueue_timeout(taskqueue_thread, &unp_gc_task, -1); 814a7444f80SGleb Smirnoff 815a7444f80SGleb Smirnoff switch (so->so_type) { 816a7444f80SGleb Smirnoff case SOCK_DGRAM: 817a7444f80SGleb Smirnoff /* 818458f475dSGleb Smirnoff * Everything should have been unlinked/freed by unp_dispose() 819458f475dSGleb Smirnoff * and/or unp_disconnect(). 820a7444f80SGleb Smirnoff */ 821458f475dSGleb Smirnoff MPASS(so->so_rcv.uxdg_peeked == NULL); 822a7444f80SGleb Smirnoff MPASS(STAILQ_EMPTY(&so->so_rcv.uxdg_mb)); 823458f475dSGleb Smirnoff MPASS(TAILQ_EMPTY(&so->so_rcv.uxdg_conns)); 824458f475dSGleb Smirnoff MPASS(STAILQ_EMPTY(&so->so_snd.uxdg_mb)); 825a7444f80SGleb Smirnoff } 826a29f300eSGarrett Wollman } 827a29f300eSGarrett Wollman 828a29f300eSGarrett Wollman static int 829a29f300eSGarrett Wollman uipc_disconnect(struct socket *so) 830a29f300eSGarrett Wollman { 831e7c33e29SRobert Watson struct unpcb *unp, *unp2; 832a29f300eSGarrett Wollman 83340f2ac28SRobert Watson unp = sotounpcb(so); 8344d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_disconnect: unp == NULL")); 835e7c33e29SRobert Watson 836e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 837ccdadf1aSMark Johnston if ((unp2 = unp_pcb_lock_peer(unp)) != NULL) 83875a67bf3SMatt Macy unp_disconnect(unp, unp2); 839ccdadf1aSMark Johnston else 840ccdadf1aSMark Johnston UNP_PCB_UNLOCK(unp); 841e5aeaa0cSDag-Erling Smørgrav return (0); 842a29f300eSGarrett Wollman } 843a29f300eSGarrett Wollman 844a29f300eSGarrett Wollman static int 845d374e81eSRobert Watson uipc_listen(struct socket *so, int backlog, struct thread *td) 846a29f300eSGarrett Wollman { 84740f2ac28SRobert Watson struct unpcb *unp; 8480d9ce3a1SRobert Watson int error; 849a29f300eSGarrett Wollman 85001235012SGleb Smirnoff MPASS(so->so_type != SOCK_DGRAM); 851beb4b312SGleb Smirnoff 852bd4a39ccSMark Johnston /* 853bd4a39ccSMark Johnston * Synchronize with concurrent connection attempts. 854bd4a39ccSMark Johnston */ 855bd4a39ccSMark Johnston error = 0; 85640f2ac28SRobert Watson unp = sotounpcb(so); 857e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 858bd4a39ccSMark Johnston if (unp->unp_conn != NULL || (unp->unp_flags & UNP_CONNECTING) != 0) 859bd4a39ccSMark Johnston error = EINVAL; 860bd4a39ccSMark Johnston else if (unp->unp_vnode == NULL) 861bd4a39ccSMark Johnston error = EDESTADDRREQ; 862bd4a39ccSMark Johnston if (error != 0) { 863e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 86447a84387SEd Schouten return (error); 86540f2ac28SRobert Watson } 866e7c33e29SRobert Watson 867e7c33e29SRobert Watson SOCK_LOCK(so); 868e7c33e29SRobert Watson error = solisten_proto_check(so); 869e7c33e29SRobert Watson if (error == 0) { 870c5afec6eSDmitry Chagin cru2xt(td, &unp->unp_peercred); 871e7c33e29SRobert Watson solisten_proto(so, backlog); 872e7c33e29SRobert Watson } 873e7c33e29SRobert Watson SOCK_UNLOCK(so); 874e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 8750d9ce3a1SRobert Watson return (error); 876a29f300eSGarrett Wollman } 877a29f300eSGarrett Wollman 878a29f300eSGarrett Wollman static int 87957bf258eSGarrett Wollman uipc_peeraddr(struct socket *so, struct sockaddr **nam) 880a29f300eSGarrett Wollman { 881e7c33e29SRobert Watson struct unpcb *unp, *unp2; 8820d9ce3a1SRobert Watson const struct sockaddr *sa; 883a29f300eSGarrett Wollman 8844d4b555eSRobert Watson unp = sotounpcb(so); 8854d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_peeraddr: unp == NULL")); 886e7c33e29SRobert Watson 8870d9ce3a1SRobert Watson *nam = malloc(sizeof(struct sockaddr_un), M_SONAME, M_WAITOK); 888e8f6e5b2SMark Johnston 889e8f6e5b2SMark Johnston UNP_PCB_LOCK(unp); 890e8f6e5b2SMark Johnston unp2 = unp_pcb_lock_peer(unp); 891e7c33e29SRobert Watson if (unp2 != NULL) { 892e7c33e29SRobert Watson if (unp2->unp_addr != NULL) 893afd9f91cSJohn Baldwin sa = (struct sockaddr *)unp2->unp_addr; 894e7c33e29SRobert Watson else 8950d9ce3a1SRobert Watson sa = &sun_noname; 8960d9ce3a1SRobert Watson bcopy(sa, *nam, sa->sa_len); 897*712079d3SMark Johnston unp_pcb_unlock_pair(unp, unp2); 898e7c33e29SRobert Watson } else { 899e7c33e29SRobert Watson sa = &sun_noname; 900e7c33e29SRobert Watson bcopy(sa, *nam, sa->sa_len); 901e8f6e5b2SMark Johnston UNP_PCB_UNLOCK(unp); 902*712079d3SMark Johnston } 903e5aeaa0cSDag-Erling Smørgrav return (0); 904a29f300eSGarrett Wollman } 905a29f300eSGarrett Wollman 906a29f300eSGarrett Wollman static int 907a29f300eSGarrett Wollman uipc_rcvd(struct socket *so, int flags) 908a29f300eSGarrett Wollman { 909e7c33e29SRobert Watson struct unpcb *unp, *unp2; 910a29f300eSGarrett Wollman struct socket *so2; 911337cc6b6SRobert Watson u_int mbcnt, sbcc; 912a29f300eSGarrett Wollman 91340f2ac28SRobert Watson unp = sotounpcb(so); 9142b21d0e8SGleb Smirnoff KASSERT(unp != NULL, ("%s: unp == NULL", __func__)); 9152b21d0e8SGleb Smirnoff KASSERT(so->so_type == SOCK_STREAM || so->so_type == SOCK_SEQPACKET, 9162b21d0e8SGleb Smirnoff ("%s: socktype %d", __func__, so->so_type)); 917e7c33e29SRobert Watson 918df8bae1dSRodney W. Grimes /* 919e7c33e29SRobert Watson * Adjust backpressure on sender and wakeup any waiting to write. 920e7c33e29SRobert Watson * 921d7924b70SRobert Watson * The unp lock is acquired to maintain the validity of the unp_conn 922d7924b70SRobert Watson * pointer; no lock on unp2 is required as unp2->unp_socket will be 923d7924b70SRobert Watson * static as long as we don't permit unp2 to disconnect from unp, 924d7924b70SRobert Watson * which is prevented by the lock on unp. We cache values from 925d7924b70SRobert Watson * so_rcv to avoid holding the so_rcv lock over the entire 926d7924b70SRobert Watson * transaction on the remote so_snd. 927df8bae1dSRodney W. Grimes */ 928337cc6b6SRobert Watson SOCKBUF_LOCK(&so->so_rcv); 929337cc6b6SRobert Watson mbcnt = so->so_rcv.sb_mbcnt; 9302b21d0e8SGleb Smirnoff sbcc = sbavail(&so->so_rcv); 931337cc6b6SRobert Watson SOCKBUF_UNLOCK(&so->so_rcv); 932c2090e73SAlan Somers /* 933c2090e73SAlan Somers * There is a benign race condition at this point. If we're planning to 934c2090e73SAlan Somers * clear SB_STOP, but uipc_send is called on the connected socket at 935c2090e73SAlan Somers * this instant, it might add data to the sockbuf and set SB_STOP. Then 936c2090e73SAlan Somers * we would erroneously clear SB_STOP below, even though the sockbuf is 937c2090e73SAlan Somers * full. The race is benign because the only ill effect is to allow the 938c2090e73SAlan Somers * sockbuf to exceed its size limit, and the size limits are not 939c2090e73SAlan Somers * strictly guaranteed anyway. 940c2090e73SAlan Somers */ 941e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 942e7c33e29SRobert Watson unp2 = unp->unp_conn; 943e7c33e29SRobert Watson if (unp2 == NULL) { 944e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 945e7c33e29SRobert Watson return (0); 946337cc6b6SRobert Watson } 947e7c33e29SRobert Watson so2 = unp2->unp_socket; 948337cc6b6SRobert Watson SOCKBUF_LOCK(&so2->so_snd); 949c2090e73SAlan Somers if (sbcc < so2->so_snd.sb_hiwat && mbcnt < so2->so_snd.sb_mbmax) 950c2090e73SAlan Somers so2->so_snd.sb_flags &= ~SB_STOP; 9511e4d7da7SRobert Watson sowwakeup_locked(so2); 952e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 953e5aeaa0cSDag-Erling Smørgrav return (0); 954a29f300eSGarrett Wollman } 955df8bae1dSRodney W. Grimes 956a29f300eSGarrett Wollman static int 95757bf258eSGarrett Wollman uipc_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, 958b40ce416SJulian Elischer struct mbuf *control, struct thread *td) 959a29f300eSGarrett Wollman { 960f3f49bbbSRobert Watson struct unpcb *unp, *unp2; 961a29f300eSGarrett Wollman struct socket *so2; 962c2090e73SAlan Somers u_int mbcnt, sbcc; 96342188bb5SMark Johnston int error; 964a29f300eSGarrett Wollman 96540f2ac28SRobert Watson unp = sotounpcb(so); 9662b21d0e8SGleb Smirnoff KASSERT(unp != NULL, ("%s: unp == NULL", __func__)); 96734649582SGleb Smirnoff KASSERT(so->so_type == SOCK_STREAM || so->so_type == SOCK_SEQPACKET, 9682b21d0e8SGleb Smirnoff ("%s: socktype %d", __func__, so->so_type)); 969e7c33e29SRobert Watson 97042188bb5SMark Johnston error = 0; 971a29f300eSGarrett Wollman if (flags & PRUS_OOB) { 972a29f300eSGarrett Wollman error = EOPNOTSUPP; 973a29f300eSGarrett Wollman goto release; 974a29f300eSGarrett Wollman } 9751093f164SGleb Smirnoff if (control != NULL && 9761093f164SGleb Smirnoff (error = unp_internalize(&control, td, NULL, NULL, NULL))) 977a29f300eSGarrett Wollman goto release; 97875a67bf3SMatt Macy 97975a67bf3SMatt Macy unp2 = NULL; 980402cc72dSDavid Greenman if ((so->so_state & SS_ISCONNECTED) == 0) { 981fc3fcacfSRobert Watson if (nam != NULL) { 982f384a97cSGleb Smirnoff if ((error = unp_connect(so, nam, td)) != 0) 983f384a97cSGleb Smirnoff goto out; 984402cc72dSDavid Greenman } else { 985402cc72dSDavid Greenman error = ENOTCONN; 986f384a97cSGleb Smirnoff goto out; 987402cc72dSDavid Greenman } 988b36871afSMark Johnston } 989b36871afSMark Johnston 990ccdadf1aSMark Johnston UNP_PCB_LOCK(unp); 991ccdadf1aSMark Johnston if ((unp2 = unp_pcb_lock_peer(unp)) == NULL) { 99275a67bf3SMatt Macy UNP_PCB_UNLOCK(unp); 993b5ff0914SRobert Watson error = ENOTCONN; 994f384a97cSGleb Smirnoff goto out; 995b36871afSMark Johnston } else if (so->so_snd.sb_state & SBS_CANTSENDMORE) { 996ccdadf1aSMark Johnston unp_pcb_unlock_pair(unp, unp2); 997b36871afSMark Johnston error = EPIPE; 998f384a97cSGleb Smirnoff goto out; 99975a67bf3SMatt Macy } 100075a67bf3SMatt Macy UNP_PCB_UNLOCK(unp); 100175a67bf3SMatt Macy if ((so2 = unp2->unp_socket) == NULL) { 100275a67bf3SMatt Macy UNP_PCB_UNLOCK(unp2); 100375a67bf3SMatt Macy error = ENOTCONN; 1004f384a97cSGleb Smirnoff goto out; 100575a67bf3SMatt Macy } 1006a34b7046SRobert Watson SOCKBUF_LOCK(&so2->so_rcv); 10072de07e40SConrad Meyer if (unp2->unp_flags & UNP_WANTCRED_MASK) { 10086a2989fdSMatthew N. Dodd /* 10092de07e40SConrad Meyer * Credentials are passed only once on SOCK_STREAM and 10102de07e40SConrad Meyer * SOCK_SEQPACKET (LOCAL_CREDS => WANTCRED_ONESHOT), or 10112de07e40SConrad Meyer * forever (LOCAL_CREDS_PERSISTENT => WANTCRED_ALWAYS). 10126a2989fdSMatthew N. Dodd */ 10131093f164SGleb Smirnoff control = unp_addsockcred(td, control, unp2->unp_flags, NULL, 10141093f164SGleb Smirnoff NULL, NULL); 10152de07e40SConrad Meyer unp2->unp_flags &= ~UNP_WANTCRED_ONESHOT; 10166a2989fdSMatthew N. Dodd } 10175b0480f2SMark Johnston 1018df8bae1dSRodney W. Grimes /* 10195b0480f2SMark Johnston * Send to paired receive port and wake up readers. Don't 10205b0480f2SMark Johnston * check for space available in the receive buffer if we're 10215b0480f2SMark Johnston * attaching ancillary data; Unix domain sockets only check 10225b0480f2SMark Johnston * for space in the sending sockbuf, and that check is 10235b0480f2SMark Johnston * performed one level up the stack. At that level we cannot 10245b0480f2SMark Johnston * precisely account for the amount of buffer space used 10255b0480f2SMark Johnston * (e.g., because control messages are not yet internalized). 1026df8bae1dSRodney W. Grimes */ 102784d61770SRobert Watson switch (so->so_type) { 102884d61770SRobert Watson case SOCK_STREAM: 1029fc3fcacfSRobert Watson if (control != NULL) { 10305b0480f2SMark Johnston sbappendcontrol_locked(&so2->so_rcv, m, 103125f4ddfbSMark Johnston control, flags); 1032fc3fcacfSRobert Watson control = NULL; 1033e7c33e29SRobert Watson } else 1034829fae90SGleb Smirnoff sbappend_locked(&so2->so_rcv, m, flags); 103584d61770SRobert Watson break; 103684d61770SRobert Watson 1037b36871afSMark Johnston case SOCK_SEQPACKET: 10388de34a88SAlan Somers if (sbappendaddr_nospacecheck_locked(&so2->so_rcv, 1039b36871afSMark Johnston &sun_noname, m, control)) 104084d61770SRobert Watson control = NULL; 104184d61770SRobert Watson break; 104284d61770SRobert Watson } 104384d61770SRobert Watson 1044c2090e73SAlan Somers mbcnt = so2->so_rcv.sb_mbcnt; 10452b21d0e8SGleb Smirnoff sbcc = sbavail(&so2->so_rcv); 10462b21d0e8SGleb Smirnoff if (sbcc) 1047337cc6b6SRobert Watson sorwakeup_locked(so2); 10482b21d0e8SGleb Smirnoff else 10492b21d0e8SGleb Smirnoff SOCKBUF_UNLOCK(&so2->so_rcv); 1050337cc6b6SRobert Watson 1051c2090e73SAlan Somers /* 1052c2090e73SAlan Somers * The PCB lock on unp2 protects the SB_STOP flag. Without it, 1053c2090e73SAlan Somers * it would be possible for uipc_rcvd to be called at this 1054c2090e73SAlan Somers * point, drain the receiving sockbuf, clear SB_STOP, and then 1055c2090e73SAlan Somers * we would set SB_STOP below. That could lead to an empty 1056c2090e73SAlan Somers * sockbuf having SB_STOP set 1057c2090e73SAlan Somers */ 1058337cc6b6SRobert Watson SOCKBUF_LOCK(&so->so_snd); 1059c2090e73SAlan Somers if (sbcc >= so->so_snd.sb_hiwat || mbcnt >= so->so_snd.sb_mbmax) 1060c2090e73SAlan Somers so->so_snd.sb_flags |= SB_STOP; 10617abe2ac2SAlan Cox SOCKBUF_UNLOCK(&so->so_snd); 1062e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp2); 1063fc3fcacfSRobert Watson m = NULL; 1064f384a97cSGleb Smirnoff out: 10656b8fda4dSGarrett Wollman /* 1066e7d02be1SGleb Smirnoff * PRUS_EOF is equivalent to pr_send followed by pr_shutdown. 10676b8fda4dSGarrett Wollman */ 1068a29f300eSGarrett Wollman if (flags & PRUS_EOF) { 1069ede6e136SRobert Watson UNP_PCB_LOCK(unp); 10706b8fda4dSGarrett Wollman socantsendmore(so); 10716b8fda4dSGarrett Wollman unp_shutdown(unp); 1072e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 1073ede6e136SRobert Watson } 1074fc3fcacfSRobert Watson if (control != NULL && error != 0) 1075eac7f079SGleb Smirnoff unp_scan(control, unp_freerights); 1076bd508d39SDon Lewis 1077a29f300eSGarrett Wollman release: 1078fc3fcacfSRobert Watson if (control != NULL) 1079a29f300eSGarrett Wollman m_freem(control); 1080100db364SGleb Smirnoff /* 1081100db364SGleb Smirnoff * In case of PRUS_NOTREADY, uipc_ready() is responsible 1082100db364SGleb Smirnoff * for freeing memory. 1083100db364SGleb Smirnoff */ 1084100db364SGleb Smirnoff if (m != NULL && (flags & PRUS_NOTREADY) == 0) 1085a29f300eSGarrett Wollman m_freem(m); 1086e5aeaa0cSDag-Erling Smørgrav return (error); 1087a29f300eSGarrett Wollman } 1088df8bae1dSRodney W. Grimes 1089458f475dSGleb Smirnoff /* PF_UNIX/SOCK_DGRAM version of sbspace() */ 1090458f475dSGleb Smirnoff static inline bool 1091458f475dSGleb Smirnoff uipc_dgram_sbspace(struct sockbuf *sb, u_int cc, u_int mbcnt) 1092458f475dSGleb Smirnoff { 1093458f475dSGleb Smirnoff u_int bleft, mleft; 1094458f475dSGleb Smirnoff 1095820bafd0SGleb Smirnoff /* 1096820bafd0SGleb Smirnoff * Negative space may happen if send(2) is followed by 1097820bafd0SGleb Smirnoff * setsockopt(SO_SNDBUF/SO_RCVBUF) that shrinks maximum. 1098820bafd0SGleb Smirnoff */ 1099820bafd0SGleb Smirnoff if (__predict_false(sb->sb_hiwat < sb->uxdg_cc || 1100820bafd0SGleb Smirnoff sb->sb_mbmax < sb->uxdg_mbcnt)) 1101820bafd0SGleb Smirnoff return (false); 1102458f475dSGleb Smirnoff 1103458f475dSGleb Smirnoff if (__predict_false(sb->sb_state & SBS_CANTRCVMORE)) 1104458f475dSGleb Smirnoff return (false); 1105458f475dSGleb Smirnoff 1106458f475dSGleb Smirnoff bleft = sb->sb_hiwat - sb->uxdg_cc; 1107458f475dSGleb Smirnoff mleft = sb->sb_mbmax - sb->uxdg_mbcnt; 1108458f475dSGleb Smirnoff 1109458f475dSGleb Smirnoff return (bleft >= cc && mleft >= mbcnt); 1110458f475dSGleb Smirnoff } 1111458f475dSGleb Smirnoff 111234649582SGleb Smirnoff /* 111334649582SGleb Smirnoff * PF_UNIX/SOCK_DGRAM send 11145dc8dd5fSGleb Smirnoff * 11155dc8dd5fSGleb Smirnoff * Allocate a record consisting of 3 mbufs in the sequence of 11165dc8dd5fSGleb Smirnoff * from -> control -> data and append it to the socket buffer. 11171093f164SGleb Smirnoff * 11181093f164SGleb Smirnoff * The first mbuf carries sender's name and is a pkthdr that stores 11191093f164SGleb Smirnoff * overall length of datagram, its memory consumption and control length. 112034649582SGleb Smirnoff */ 11211093f164SGleb Smirnoff #define ctllen PH_loc.thirtytwo[1] 11221093f164SGleb Smirnoff _Static_assert(offsetof(struct pkthdr, memlen) + sizeof(u_int) <= 11231093f164SGleb Smirnoff offsetof(struct pkthdr, ctllen), "unix/dgram can not store ctllen"); 112434649582SGleb Smirnoff static int 112534649582SGleb Smirnoff uipc_sosend_dgram(struct socket *so, struct sockaddr *addr, struct uio *uio, 112634649582SGleb Smirnoff struct mbuf *m, struct mbuf *c, int flags, struct thread *td) 112734649582SGleb Smirnoff { 112834649582SGleb Smirnoff struct unpcb *unp, *unp2; 112934649582SGleb Smirnoff const struct sockaddr *from; 113034649582SGleb Smirnoff struct socket *so2; 11315dc8dd5fSGleb Smirnoff struct sockbuf *sb; 11321093f164SGleb Smirnoff struct mbuf *f, *clast; 11331093f164SGleb Smirnoff u_int cc, ctl, mbcnt; 11341093f164SGleb Smirnoff u_int dcc __diagused, dctl __diagused, dmbcnt __diagused; 1135a7444f80SGleb Smirnoff int error; 113634649582SGleb Smirnoff 113734649582SGleb Smirnoff MPASS((uio != NULL && m == NULL) || (m != NULL && uio == NULL)); 113834649582SGleb Smirnoff 113934649582SGleb Smirnoff error = 0; 11405dc8dd5fSGleb Smirnoff f = NULL; 11411093f164SGleb Smirnoff ctl = 0; 114234649582SGleb Smirnoff 114334649582SGleb Smirnoff if (__predict_false(flags & MSG_OOB)) { 114434649582SGleb Smirnoff error = EOPNOTSUPP; 114534649582SGleb Smirnoff goto out; 114634649582SGleb Smirnoff } 114734649582SGleb Smirnoff if (m == NULL) { 114834649582SGleb Smirnoff if (__predict_false(uio->uio_resid > unpdg_maxdgram)) { 114934649582SGleb Smirnoff error = EMSGSIZE; 115034649582SGleb Smirnoff goto out; 115134649582SGleb Smirnoff } 115234649582SGleb Smirnoff m = m_uiotombuf(uio, M_WAITOK, 0, max_hdr, M_PKTHDR); 115334649582SGleb Smirnoff if (__predict_false(m == NULL)) { 115434649582SGleb Smirnoff error = EFAULT; 115534649582SGleb Smirnoff goto out; 115634649582SGleb Smirnoff } 11571093f164SGleb Smirnoff f = m_gethdr(M_WAITOK, MT_SONAME); 11581093f164SGleb Smirnoff cc = m->m_pkthdr.len; 11591093f164SGleb Smirnoff mbcnt = MSIZE + m->m_pkthdr.memlen; 11601093f164SGleb Smirnoff if (c != NULL && 11611093f164SGleb Smirnoff (error = unp_internalize(&c, td, &clast, &ctl, &mbcnt))) 116234649582SGleb Smirnoff goto out; 116334649582SGleb Smirnoff } else { 1164e7d02be1SGleb Smirnoff /* pr_sosend() with mbuf usually is a kernel thread. */ 116534649582SGleb Smirnoff 116634649582SGleb Smirnoff M_ASSERTPKTHDR(m); 116734649582SGleb Smirnoff if (__predict_false(c != NULL)) 116834649582SGleb Smirnoff panic("%s: control from a kernel thread", __func__); 116934649582SGleb Smirnoff 117034649582SGleb Smirnoff if (__predict_false(m->m_pkthdr.len > unpdg_maxdgram)) { 117134649582SGleb Smirnoff error = EMSGSIZE; 117234649582SGleb Smirnoff goto out; 117334649582SGleb Smirnoff } 11741093f164SGleb Smirnoff if ((f = m_gethdr(M_NOWAIT, MT_SONAME)) == NULL) { 11755dc8dd5fSGleb Smirnoff error = ENOBUFS; 11765dc8dd5fSGleb Smirnoff goto out; 11775dc8dd5fSGleb Smirnoff } 117834649582SGleb Smirnoff /* Condition the foreign mbuf to our standards. */ 117934649582SGleb Smirnoff m_clrprotoflags(m); 118034649582SGleb Smirnoff m_tag_delete_chain(m, NULL); 118134649582SGleb Smirnoff m->m_pkthdr.rcvif = NULL; 118234649582SGleb Smirnoff m->m_pkthdr.flowid = 0; 118334649582SGleb Smirnoff m->m_pkthdr.csum_flags = 0; 118434649582SGleb Smirnoff m->m_pkthdr.fibnum = 0; 118534649582SGleb Smirnoff m->m_pkthdr.rsstype = 0; 11861093f164SGleb Smirnoff 11871093f164SGleb Smirnoff cc = m->m_pkthdr.len; 11881093f164SGleb Smirnoff mbcnt = MSIZE; 11891093f164SGleb Smirnoff for (struct mbuf *mb = m; mb != NULL; mb = mb->m_next) { 11901093f164SGleb Smirnoff mbcnt += MSIZE; 11911093f164SGleb Smirnoff if (mb->m_flags & M_EXT) 11921093f164SGleb Smirnoff mbcnt += mb->m_ext.ext_size; 11931093f164SGleb Smirnoff } 119434649582SGleb Smirnoff } 119534649582SGleb Smirnoff 119634649582SGleb Smirnoff unp = sotounpcb(so); 119734649582SGleb Smirnoff MPASS(unp); 119834649582SGleb Smirnoff 119934649582SGleb Smirnoff /* 120034649582SGleb Smirnoff * XXXGL: would be cool to fully remove so_snd out of the equation 120134649582SGleb Smirnoff * and avoid this lock, which is not only extraneous, but also being 120234649582SGleb Smirnoff * released, thus still leaving possibility for a race. We can easily 120334649582SGleb Smirnoff * handle SBS_CANTSENDMORE/SS_ISCONNECTED complement in unpcb, but it 120434649582SGleb Smirnoff * is more difficult to invent something to handle so_error. 120534649582SGleb Smirnoff */ 120634649582SGleb Smirnoff error = SOCK_IO_SEND_LOCK(so, SBLOCKWAIT(flags)); 120734649582SGleb Smirnoff if (error) 120834649582SGleb Smirnoff goto out2; 1209a7444f80SGleb Smirnoff SOCK_SENDBUF_LOCK(so); 121034649582SGleb Smirnoff if (so->so_snd.sb_state & SBS_CANTSENDMORE) { 121134649582SGleb Smirnoff SOCK_SENDBUF_UNLOCK(so); 121234649582SGleb Smirnoff error = EPIPE; 121334649582SGleb Smirnoff goto out3; 121434649582SGleb Smirnoff } 121534649582SGleb Smirnoff if (so->so_error != 0) { 121634649582SGleb Smirnoff error = so->so_error; 121734649582SGleb Smirnoff so->so_error = 0; 1218a7444f80SGleb Smirnoff SOCK_SENDBUF_UNLOCK(so); 121934649582SGleb Smirnoff goto out3; 122034649582SGleb Smirnoff } 122134649582SGleb Smirnoff if (((so->so_state & SS_ISCONNECTED) == 0) && addr == NULL) { 1222a7444f80SGleb Smirnoff SOCK_SENDBUF_UNLOCK(so); 122334649582SGleb Smirnoff error = EDESTADDRREQ; 122434649582SGleb Smirnoff goto out3; 122534649582SGleb Smirnoff } 1226a7444f80SGleb Smirnoff SOCK_SENDBUF_UNLOCK(so); 122734649582SGleb Smirnoff 1228315167c0SGleb Smirnoff if (addr != NULL) { 1229315167c0SGleb Smirnoff if ((error = unp_connectat(AT_FDCWD, so, addr, td, true))) 123034649582SGleb Smirnoff goto out3; 1231315167c0SGleb Smirnoff UNP_PCB_LOCK_ASSERT(unp); 1232315167c0SGleb Smirnoff unp2 = unp->unp_conn; 1233315167c0SGleb Smirnoff UNP_PCB_LOCK_ASSERT(unp2); 1234315167c0SGleb Smirnoff } else { 123534649582SGleb Smirnoff UNP_PCB_LOCK(unp); 123634649582SGleb Smirnoff unp2 = unp_pcb_lock_peer(unp); 123734649582SGleb Smirnoff if (unp2 == NULL) { 123834649582SGleb Smirnoff UNP_PCB_UNLOCK(unp); 123934649582SGleb Smirnoff error = ENOTCONN; 124034649582SGleb Smirnoff goto out3; 124134649582SGleb Smirnoff } 1242315167c0SGleb Smirnoff } 124334649582SGleb Smirnoff 124434649582SGleb Smirnoff if (unp2->unp_flags & UNP_WANTCRED_MASK) 12451093f164SGleb Smirnoff c = unp_addsockcred(td, c, unp2->unp_flags, &clast, &ctl, 12461093f164SGleb Smirnoff &mbcnt); 124734649582SGleb Smirnoff if (unp->unp_addr != NULL) 124834649582SGleb Smirnoff from = (struct sockaddr *)unp->unp_addr; 124934649582SGleb Smirnoff else 125034649582SGleb Smirnoff from = &sun_noname; 12515dc8dd5fSGleb Smirnoff f->m_len = from->sa_len; 12525dc8dd5fSGleb Smirnoff MPASS(from->sa_len <= MLEN); 12535dc8dd5fSGleb Smirnoff bcopy(from, mtod(f, void *), from->sa_len); 12541093f164SGleb Smirnoff ctl += f->m_len; 1255a7444f80SGleb Smirnoff 12561093f164SGleb Smirnoff /* 12571093f164SGleb Smirnoff * Concatenate mbufs: from -> control -> data. 12581093f164SGleb Smirnoff * Save overall cc and mbcnt in "from" mbuf. 12591093f164SGleb Smirnoff */ 12605dc8dd5fSGleb Smirnoff if (c != NULL) { 12611093f164SGleb Smirnoff #ifdef INVARIANTS 12621093f164SGleb Smirnoff struct mbuf *mc; 1263a7444f80SGleb Smirnoff 12641093f164SGleb Smirnoff for (mc = c; mc->m_next != NULL; mc = mc->m_next); 12651093f164SGleb Smirnoff MPASS(mc == clast); 12661093f164SGleb Smirnoff #endif 12675dc8dd5fSGleb Smirnoff f->m_next = c; 12685dc8dd5fSGleb Smirnoff clast->m_next = m; 1269a7444f80SGleb Smirnoff c = NULL; 12705dc8dd5fSGleb Smirnoff } else 12715dc8dd5fSGleb Smirnoff f->m_next = m; 1272a7444f80SGleb Smirnoff m = NULL; 12731093f164SGleb Smirnoff #ifdef INVARIANTS 12741093f164SGleb Smirnoff dcc = dctl = dmbcnt = 0; 12751093f164SGleb Smirnoff for (struct mbuf *mb = f; mb != NULL; mb = mb->m_next) { 12761093f164SGleb Smirnoff if (mb->m_type == MT_DATA) 12771093f164SGleb Smirnoff dcc += mb->m_len; 12781093f164SGleb Smirnoff else 12791093f164SGleb Smirnoff dctl += mb->m_len; 12801093f164SGleb Smirnoff dmbcnt += MSIZE; 12811093f164SGleb Smirnoff if (mb->m_flags & M_EXT) 12821093f164SGleb Smirnoff dmbcnt += mb->m_ext.ext_size; 12831093f164SGleb Smirnoff } 12841093f164SGleb Smirnoff MPASS(dcc == cc); 12851093f164SGleb Smirnoff MPASS(dctl == ctl); 12861093f164SGleb Smirnoff MPASS(dmbcnt == mbcnt); 12871093f164SGleb Smirnoff #endif 12881093f164SGleb Smirnoff f->m_pkthdr.len = cc + ctl; 12891093f164SGleb Smirnoff f->m_pkthdr.memlen = mbcnt; 12901093f164SGleb Smirnoff f->m_pkthdr.ctllen = ctl; 1291a7444f80SGleb Smirnoff 1292458f475dSGleb Smirnoff /* 1293458f475dSGleb Smirnoff * Destination socket buffer selection. 1294458f475dSGleb Smirnoff * 1295458f475dSGleb Smirnoff * Unconnected sends, when !(so->so_state & SS_ISCONNECTED) and the 1296458f475dSGleb Smirnoff * destination address is supplied, create a temporary connection for 1297458f475dSGleb Smirnoff * the run time of the function (see call to unp_connectat() above and 1298458f475dSGleb Smirnoff * to unp_disconnect() below). We distinguish them by condition of 1299458f475dSGleb Smirnoff * (addr != NULL). We intentionally avoid adding 'bool connected' for 1300458f475dSGleb Smirnoff * that condition, since, again, through the run time of this code we 1301458f475dSGleb Smirnoff * are always connected. For such "unconnected" sends, the destination 1302458f475dSGleb Smirnoff * buffer would be the receive buffer of destination socket so2. 1303458f475dSGleb Smirnoff * 1304458f475dSGleb Smirnoff * For connected sends, data lands on the send buffer of the sender's 1305458f475dSGleb Smirnoff * socket "so". Then, if we just added the very first datagram 1306458f475dSGleb Smirnoff * on this send buffer, we need to add the send buffer on to the 1307458f475dSGleb Smirnoff * receiving socket's buffer list. We put ourselves on top of the 1308458f475dSGleb Smirnoff * list. Such logic gives infrequent senders priority over frequent 1309458f475dSGleb Smirnoff * senders. 1310458f475dSGleb Smirnoff * 1311458f475dSGleb Smirnoff * Note on byte count management. As long as event methods kevent(2), 1312458f475dSGleb Smirnoff * select(2) are not protocol specific (yet), we need to maintain 1313458f475dSGleb Smirnoff * meaningful values on the receive buffer. So, the receive buffer 1314458f475dSGleb Smirnoff * would accumulate counters from all connected buffers potentially 1315458f475dSGleb Smirnoff * having sb_ccc > sb_hiwat or sb_mbcnt > sb_mbmax. 1316458f475dSGleb Smirnoff */ 1317a7444f80SGleb Smirnoff so2 = unp2->unp_socket; 1318458f475dSGleb Smirnoff sb = (addr == NULL) ? &so->so_snd : &so2->so_rcv; 1319a7444f80SGleb Smirnoff SOCK_RECVBUF_LOCK(so2); 1320458f475dSGleb Smirnoff if (uipc_dgram_sbspace(sb, cc + ctl, mbcnt)) { 1321458f475dSGleb Smirnoff if (addr == NULL && STAILQ_EMPTY(&sb->uxdg_mb)) 1322458f475dSGleb Smirnoff TAILQ_INSERT_HEAD(&so2->so_rcv.uxdg_conns, &so->so_snd, 1323458f475dSGleb Smirnoff uxdg_clist); 1324a7444f80SGleb Smirnoff STAILQ_INSERT_TAIL(&sb->uxdg_mb, f, m_stailqpkt); 1325458f475dSGleb Smirnoff sb->uxdg_cc += cc + ctl; 1326458f475dSGleb Smirnoff sb->uxdg_ctl += ctl; 1327458f475dSGleb Smirnoff sb->uxdg_mbcnt += mbcnt; 1328458f475dSGleb Smirnoff so2->so_rcv.sb_acc += cc + ctl; 1329458f475dSGleb Smirnoff so2->so_rcv.sb_ccc += cc + ctl; 1330458f475dSGleb Smirnoff so2->so_rcv.sb_ctl += ctl; 1331458f475dSGleb Smirnoff so2->so_rcv.sb_mbcnt += mbcnt; 133234649582SGleb Smirnoff sorwakeup_locked(so2); 13331093f164SGleb Smirnoff f = NULL; 133434649582SGleb Smirnoff } else { 133534649582SGleb Smirnoff soroverflow_locked(so2); 133671e70c25SGleb Smirnoff error = ENOBUFS; 1337636420bdSGleb Smirnoff if (f->m_next->m_type == MT_CONTROL) 1338636420bdSGleb Smirnoff unp_scan(f->m_next, unp_freerights); 133934649582SGleb Smirnoff } 134034649582SGleb Smirnoff 134134649582SGleb Smirnoff if (addr != NULL) 134234649582SGleb Smirnoff unp_disconnect(unp, unp2); 134334649582SGleb Smirnoff else 134434649582SGleb Smirnoff unp_pcb_unlock_pair(unp, unp2); 134534649582SGleb Smirnoff 134634649582SGleb Smirnoff td->td_ru.ru_msgsnd++; 134734649582SGleb Smirnoff 134834649582SGleb Smirnoff out3: 134934649582SGleb Smirnoff SOCK_IO_SEND_UNLOCK(so); 135034649582SGleb Smirnoff out2: 135134649582SGleb Smirnoff if (c) 135234649582SGleb Smirnoff unp_scan(c, unp_freerights); 135334649582SGleb Smirnoff out: 13545dc8dd5fSGleb Smirnoff if (f) 1355a7444f80SGleb Smirnoff m_freem(f); 135634649582SGleb Smirnoff if (c) 135734649582SGleb Smirnoff m_freem(c); 135834649582SGleb Smirnoff if (m) 135934649582SGleb Smirnoff m_freem(m); 136034649582SGleb Smirnoff 136134649582SGleb Smirnoff return (error); 136234649582SGleb Smirnoff } 136334649582SGleb Smirnoff 1364e3fbbf96SGleb Smirnoff /* 1365458f475dSGleb Smirnoff * PF_UNIX/SOCK_DGRAM receive with MSG_PEEK. 1366458f475dSGleb Smirnoff * The mbuf has already been unlinked from the uxdg_mb of socket buffer 1367458f475dSGleb Smirnoff * and needs to be linked onto uxdg_peeked of receive socket buffer. 1368e3fbbf96SGleb Smirnoff */ 1369e3fbbf96SGleb Smirnoff static int 1370458f475dSGleb Smirnoff uipc_peek_dgram(struct socket *so, struct mbuf *m, struct sockaddr **psa, 1371458f475dSGleb Smirnoff struct uio *uio, struct mbuf **controlp, int *flagsp) 1372e3fbbf96SGleb Smirnoff { 1373be1f485dSAlexander V. Chernikov ssize_t len = 0; 1374e3fbbf96SGleb Smirnoff int error; 1375e3fbbf96SGleb Smirnoff 1376458f475dSGleb Smirnoff so->so_rcv.uxdg_peeked = m; 1377458f475dSGleb Smirnoff so->so_rcv.uxdg_cc += m->m_pkthdr.len; 1378458f475dSGleb Smirnoff so->so_rcv.uxdg_ctl += m->m_pkthdr.ctllen; 1379458f475dSGleb Smirnoff so->so_rcv.uxdg_mbcnt += m->m_pkthdr.memlen; 1380a7444f80SGleb Smirnoff SOCK_RECVBUF_UNLOCK(so); 1381e3fbbf96SGleb Smirnoff 1382e3fbbf96SGleb Smirnoff KASSERT(m->m_type == MT_SONAME, ("m->m_type == %d", m->m_type)); 1383e3fbbf96SGleb Smirnoff if (psa != NULL) 1384e3fbbf96SGleb Smirnoff *psa = sodupsockaddr(mtod(m, struct sockaddr *), M_WAITOK); 1385e3fbbf96SGleb Smirnoff 1386a7444f80SGleb Smirnoff m = m->m_next; 1387a7444f80SGleb Smirnoff KASSERT(m, ("%s: no data or control after soname", __func__)); 1388e3fbbf96SGleb Smirnoff 1389e3fbbf96SGleb Smirnoff /* 1390e3fbbf96SGleb Smirnoff * With MSG_PEEK the control isn't executed, just copied. 1391e3fbbf96SGleb Smirnoff */ 1392e3fbbf96SGleb Smirnoff while (m != NULL && m->m_type == MT_CONTROL) { 1393e3fbbf96SGleb Smirnoff if (controlp != NULL) { 1394e3fbbf96SGleb Smirnoff *controlp = m_copym(m, 0, m->m_len, M_WAITOK); 1395e3fbbf96SGleb Smirnoff controlp = &(*controlp)->m_next; 1396e3fbbf96SGleb Smirnoff } 1397e3fbbf96SGleb Smirnoff m = m->m_next; 1398e3fbbf96SGleb Smirnoff } 1399e3fbbf96SGleb Smirnoff KASSERT(m == NULL || m->m_type == MT_DATA, 1400e3fbbf96SGleb Smirnoff ("%s: not MT_DATA mbuf %p", __func__, m)); 1401e3fbbf96SGleb Smirnoff while (m != NULL && uio->uio_resid > 0) { 1402e3fbbf96SGleb Smirnoff len = uio->uio_resid; 1403e3fbbf96SGleb Smirnoff if (len > m->m_len) 1404e3fbbf96SGleb Smirnoff len = m->m_len; 1405e3fbbf96SGleb Smirnoff error = uiomove(mtod(m, char *), (int)len, uio); 1406e3fbbf96SGleb Smirnoff if (error) { 1407e3fbbf96SGleb Smirnoff SOCK_IO_RECV_UNLOCK(so); 1408e3fbbf96SGleb Smirnoff return (error); 1409e3fbbf96SGleb Smirnoff } 1410e3fbbf96SGleb Smirnoff if (len == m->m_len) 1411e3fbbf96SGleb Smirnoff m = m->m_next; 1412e3fbbf96SGleb Smirnoff } 1413e3fbbf96SGleb Smirnoff SOCK_IO_RECV_UNLOCK(so); 1414e3fbbf96SGleb Smirnoff 1415be1f485dSAlexander V. Chernikov if (flagsp != NULL) { 1416be1f485dSAlexander V. Chernikov if (m != NULL) { 1417be1f485dSAlexander V. Chernikov if (*flagsp & MSG_TRUNC) { 1418be1f485dSAlexander V. Chernikov /* Report real length of the packet */ 1419be1f485dSAlexander V. Chernikov uio->uio_resid -= m_length(m, NULL) - len; 1420be1f485dSAlexander V. Chernikov } 1421e3fbbf96SGleb Smirnoff *flagsp |= MSG_TRUNC; 1422be1f485dSAlexander V. Chernikov } else 1423be1f485dSAlexander V. Chernikov *flagsp &= ~MSG_TRUNC; 1424be1f485dSAlexander V. Chernikov } 1425e3fbbf96SGleb Smirnoff 1426e3fbbf96SGleb Smirnoff return (0); 1427e3fbbf96SGleb Smirnoff } 1428e3fbbf96SGleb Smirnoff 1429e3fbbf96SGleb Smirnoff /* 1430e3fbbf96SGleb Smirnoff * PF_UNIX/SOCK_DGRAM receive 1431e3fbbf96SGleb Smirnoff */ 1432e3fbbf96SGleb Smirnoff static int 1433e3fbbf96SGleb Smirnoff uipc_soreceive_dgram(struct socket *so, struct sockaddr **psa, struct uio *uio, 1434e3fbbf96SGleb Smirnoff struct mbuf **mp0, struct mbuf **controlp, int *flagsp) 1435e3fbbf96SGleb Smirnoff { 1436458f475dSGleb Smirnoff struct sockbuf *sb = NULL; 14371093f164SGleb Smirnoff struct mbuf *m; 1438e3fbbf96SGleb Smirnoff int flags, error; 1439be1f485dSAlexander V. Chernikov ssize_t len = 0; 1440e3fbbf96SGleb Smirnoff bool nonblock; 1441e3fbbf96SGleb Smirnoff 1442e3fbbf96SGleb Smirnoff MPASS(mp0 == NULL); 1443e3fbbf96SGleb Smirnoff 1444e3fbbf96SGleb Smirnoff if (psa != NULL) 1445e3fbbf96SGleb Smirnoff *psa = NULL; 1446e3fbbf96SGleb Smirnoff if (controlp != NULL) 1447e3fbbf96SGleb Smirnoff *controlp = NULL; 1448e3fbbf96SGleb Smirnoff 1449e3fbbf96SGleb Smirnoff flags = flagsp != NULL ? *flagsp : 0; 1450e3fbbf96SGleb Smirnoff nonblock = (so->so_state & SS_NBIO) || 1451e3fbbf96SGleb Smirnoff (flags & (MSG_DONTWAIT | MSG_NBIO)); 1452e3fbbf96SGleb Smirnoff 1453e3fbbf96SGleb Smirnoff error = SOCK_IO_RECV_LOCK(so, SBLOCKWAIT(flags)); 1454e3fbbf96SGleb Smirnoff if (__predict_false(error)) 1455e3fbbf96SGleb Smirnoff return (error); 1456e3fbbf96SGleb Smirnoff 1457e3fbbf96SGleb Smirnoff /* 1458458f475dSGleb Smirnoff * Loop blocking while waiting for a datagram. Prioritize connected 1459458f475dSGleb Smirnoff * peers over unconnected sends. Set sb to selected socket buffer 1460458f475dSGleb Smirnoff * containing an mbuf on exit from the wait loop. A datagram that 1461458f475dSGleb Smirnoff * had already been peeked at has top priority. 1462e3fbbf96SGleb Smirnoff */ 1463e3fbbf96SGleb Smirnoff SOCK_RECVBUF_LOCK(so); 1464458f475dSGleb Smirnoff while ((m = so->so_rcv.uxdg_peeked) == NULL && 1465458f475dSGleb Smirnoff (sb = TAILQ_FIRST(&so->so_rcv.uxdg_conns)) == NULL && 1466458f475dSGleb Smirnoff (m = STAILQ_FIRST(&so->so_rcv.uxdg_mb)) == NULL) { 1467e3fbbf96SGleb Smirnoff if (so->so_error) { 1468e3fbbf96SGleb Smirnoff error = so->so_error; 1469e3fbbf96SGleb Smirnoff so->so_error = 0; 1470a7444f80SGleb Smirnoff SOCK_RECVBUF_UNLOCK(so); 1471e3fbbf96SGleb Smirnoff SOCK_IO_RECV_UNLOCK(so); 1472e3fbbf96SGleb Smirnoff return (error); 1473e3fbbf96SGleb Smirnoff } 1474e3fbbf96SGleb Smirnoff if (so->so_rcv.sb_state & SBS_CANTRCVMORE || 1475e3fbbf96SGleb Smirnoff uio->uio_resid == 0) { 1476a7444f80SGleb Smirnoff SOCK_RECVBUF_UNLOCK(so); 1477e3fbbf96SGleb Smirnoff SOCK_IO_RECV_UNLOCK(so); 1478e3fbbf96SGleb Smirnoff return (0); 1479e3fbbf96SGleb Smirnoff } 1480e3fbbf96SGleb Smirnoff if (nonblock) { 1481a7444f80SGleb Smirnoff SOCK_RECVBUF_UNLOCK(so); 1482e3fbbf96SGleb Smirnoff SOCK_IO_RECV_UNLOCK(so); 1483e3fbbf96SGleb Smirnoff return (EWOULDBLOCK); 1484e3fbbf96SGleb Smirnoff } 1485e3fbbf96SGleb Smirnoff error = sbwait(so, SO_RCV); 1486e3fbbf96SGleb Smirnoff if (error) { 1487a7444f80SGleb Smirnoff SOCK_RECVBUF_UNLOCK(so); 1488e3fbbf96SGleb Smirnoff SOCK_IO_RECV_UNLOCK(so); 1489e3fbbf96SGleb Smirnoff return (error); 1490e3fbbf96SGleb Smirnoff } 1491e3fbbf96SGleb Smirnoff } 14921093f164SGleb Smirnoff 1493458f475dSGleb Smirnoff if (sb == NULL) 1494458f475dSGleb Smirnoff sb = &so->so_rcv; 1495458f475dSGleb Smirnoff else if (m == NULL) 1496458f475dSGleb Smirnoff m = STAILQ_FIRST(&sb->uxdg_mb); 1497458f475dSGleb Smirnoff else 1498458f475dSGleb Smirnoff MPASS(m == so->so_rcv.uxdg_peeked); 1499458f475dSGleb Smirnoff 1500458f475dSGleb Smirnoff MPASS(sb->uxdg_cc > 0); 15011093f164SGleb Smirnoff M_ASSERTPKTHDR(m); 15021093f164SGleb Smirnoff KASSERT(m->m_type == MT_SONAME, ("m->m_type == %d", m->m_type)); 1503e3fbbf96SGleb Smirnoff 1504e3fbbf96SGleb Smirnoff if (uio->uio_td) 1505e3fbbf96SGleb Smirnoff uio->uio_td->td_ru.ru_msgrcv++; 1506e3fbbf96SGleb Smirnoff 1507458f475dSGleb Smirnoff if (__predict_true(m != so->so_rcv.uxdg_peeked)) { 1508458f475dSGleb Smirnoff STAILQ_REMOVE_HEAD(&sb->uxdg_mb, m_stailqpkt); 1509458f475dSGleb Smirnoff if (STAILQ_EMPTY(&sb->uxdg_mb) && sb != &so->so_rcv) 1510458f475dSGleb Smirnoff TAILQ_REMOVE(&so->so_rcv.uxdg_conns, sb, uxdg_clist); 1511458f475dSGleb Smirnoff } else 1512458f475dSGleb Smirnoff so->so_rcv.uxdg_peeked = NULL; 1513e3fbbf96SGleb Smirnoff 1514458f475dSGleb Smirnoff sb->uxdg_cc -= m->m_pkthdr.len; 1515458f475dSGleb Smirnoff sb->uxdg_ctl -= m->m_pkthdr.ctllen; 1516458f475dSGleb Smirnoff sb->uxdg_mbcnt -= m->m_pkthdr.memlen; 1517458f475dSGleb Smirnoff 1518458f475dSGleb Smirnoff if (__predict_false(flags & MSG_PEEK)) 1519458f475dSGleb Smirnoff return (uipc_peek_dgram(so, m, psa, uio, controlp, flagsp)); 1520458f475dSGleb Smirnoff 15211093f164SGleb Smirnoff so->so_rcv.sb_acc -= m->m_pkthdr.len; 15221093f164SGleb Smirnoff so->so_rcv.sb_ccc -= m->m_pkthdr.len; 15231093f164SGleb Smirnoff so->so_rcv.sb_ctl -= m->m_pkthdr.ctllen; 15241093f164SGleb Smirnoff so->so_rcv.sb_mbcnt -= m->m_pkthdr.memlen; 1525a7444f80SGleb Smirnoff SOCK_RECVBUF_UNLOCK(so); 1526e3fbbf96SGleb Smirnoff 1527e3fbbf96SGleb Smirnoff if (psa != NULL) 1528e3fbbf96SGleb Smirnoff *psa = sodupsockaddr(mtod(m, struct sockaddr *), M_WAITOK); 1529e3fbbf96SGleb Smirnoff m = m_free(m); 1530a7444f80SGleb Smirnoff KASSERT(m, ("%s: no data or control after soname", __func__)); 1531e3fbbf96SGleb Smirnoff 1532e3fbbf96SGleb Smirnoff /* 1533e3fbbf96SGleb Smirnoff * Packet to copyout() is now in 'm' and it is disconnected from the 1534e3fbbf96SGleb Smirnoff * queue. 1535e3fbbf96SGleb Smirnoff * 1536e3fbbf96SGleb Smirnoff * Process one or more MT_CONTROL mbufs present before any data mbufs 1537e3fbbf96SGleb Smirnoff * in the first mbuf chain on the socket buffer. We call into the 1538e3fbbf96SGleb Smirnoff * unp_externalize() to perform externalization (or freeing if 1539e3fbbf96SGleb Smirnoff * controlp == NULL). In some cases there can be only MT_CONTROL mbufs 1540e3fbbf96SGleb Smirnoff * without MT_DATA mbufs. 1541e3fbbf96SGleb Smirnoff */ 1542e3fbbf96SGleb Smirnoff while (m != NULL && m->m_type == MT_CONTROL) { 1543e3fbbf96SGleb Smirnoff struct mbuf *cm; 1544e3fbbf96SGleb Smirnoff 1545e3fbbf96SGleb Smirnoff /* XXXGL: unp_externalize() is also dom_externalize() KBI and 1546e3fbbf96SGleb Smirnoff * it frees whole chain, so we must disconnect the mbuf. 1547e3fbbf96SGleb Smirnoff */ 1548e3fbbf96SGleb Smirnoff cm = m; m = m->m_next; cm->m_next = NULL; 1549e3fbbf96SGleb Smirnoff error = unp_externalize(cm, controlp, flags); 1550e3fbbf96SGleb Smirnoff if (error != 0) { 1551e3fbbf96SGleb Smirnoff SOCK_IO_RECV_UNLOCK(so); 1552e3fbbf96SGleb Smirnoff unp_scan(m, unp_freerights); 1553e3fbbf96SGleb Smirnoff m_freem(m); 1554e3fbbf96SGleb Smirnoff return (error); 1555e3fbbf96SGleb Smirnoff } 1556e3fbbf96SGleb Smirnoff if (controlp != NULL) { 1557e3fbbf96SGleb Smirnoff while (*controlp != NULL) 1558e3fbbf96SGleb Smirnoff controlp = &(*controlp)->m_next; 1559e3fbbf96SGleb Smirnoff } 1560e3fbbf96SGleb Smirnoff } 1561e3fbbf96SGleb Smirnoff KASSERT(m == NULL || m->m_type == MT_DATA, 1562e3fbbf96SGleb Smirnoff ("%s: not MT_DATA mbuf %p", __func__, m)); 1563e3fbbf96SGleb Smirnoff while (m != NULL && uio->uio_resid > 0) { 1564e3fbbf96SGleb Smirnoff len = uio->uio_resid; 1565e3fbbf96SGleb Smirnoff if (len > m->m_len) 1566e3fbbf96SGleb Smirnoff len = m->m_len; 1567e3fbbf96SGleb Smirnoff error = uiomove(mtod(m, char *), (int)len, uio); 1568e3fbbf96SGleb Smirnoff if (error) { 1569e3fbbf96SGleb Smirnoff SOCK_IO_RECV_UNLOCK(so); 1570e3fbbf96SGleb Smirnoff m_freem(m); 1571e3fbbf96SGleb Smirnoff return (error); 1572e3fbbf96SGleb Smirnoff } 1573e3fbbf96SGleb Smirnoff if (len == m->m_len) 1574e3fbbf96SGleb Smirnoff m = m_free(m); 1575e3fbbf96SGleb Smirnoff else { 1576e3fbbf96SGleb Smirnoff m->m_data += len; 1577e3fbbf96SGleb Smirnoff m->m_len -= len; 1578e3fbbf96SGleb Smirnoff } 1579e3fbbf96SGleb Smirnoff } 1580e3fbbf96SGleb Smirnoff SOCK_IO_RECV_UNLOCK(so); 1581e3fbbf96SGleb Smirnoff 1582e3fbbf96SGleb Smirnoff if (m != NULL) { 1583be1f485dSAlexander V. Chernikov if (flagsp != NULL) { 1584be1f485dSAlexander V. Chernikov if (flags & MSG_TRUNC) { 1585be1f485dSAlexander V. Chernikov /* Report real length of the packet */ 1586be1f485dSAlexander V. Chernikov uio->uio_resid -= m_length(m, NULL); 1587e3fbbf96SGleb Smirnoff } 1588be1f485dSAlexander V. Chernikov *flagsp |= MSG_TRUNC; 1589be1f485dSAlexander V. Chernikov } 1590be1f485dSAlexander V. Chernikov m_freem(m); 1591be1f485dSAlexander V. Chernikov } else if (flagsp != NULL) 1592be1f485dSAlexander V. Chernikov *flagsp &= ~MSG_TRUNC; 1593e3fbbf96SGleb Smirnoff 1594e3fbbf96SGleb Smirnoff return (0); 1595e3fbbf96SGleb Smirnoff } 1596e3fbbf96SGleb Smirnoff 1597a50b1900SMark Johnston static bool 1598a50b1900SMark Johnston uipc_ready_scan(struct socket *so, struct mbuf *m, int count, int *errorp) 1599a50b1900SMark Johnston { 1600a50b1900SMark Johnston struct mbuf *mb, *n; 1601a50b1900SMark Johnston struct sockbuf *sb; 1602a50b1900SMark Johnston 1603a50b1900SMark Johnston SOCK_LOCK(so); 1604a50b1900SMark Johnston if (SOLISTENING(so)) { 1605a50b1900SMark Johnston SOCK_UNLOCK(so); 1606a50b1900SMark Johnston return (false); 1607a50b1900SMark Johnston } 1608a50b1900SMark Johnston mb = NULL; 1609a50b1900SMark Johnston sb = &so->so_rcv; 1610a50b1900SMark Johnston SOCKBUF_LOCK(sb); 1611a50b1900SMark Johnston if (sb->sb_fnrdy != NULL) { 1612a50b1900SMark Johnston for (mb = sb->sb_mb, n = mb->m_nextpkt; mb != NULL;) { 1613a50b1900SMark Johnston if (mb == m) { 1614a50b1900SMark Johnston *errorp = sbready(sb, m, count); 1615a50b1900SMark Johnston break; 1616a50b1900SMark Johnston } 1617a50b1900SMark Johnston mb = mb->m_next; 1618a50b1900SMark Johnston if (mb == NULL) { 1619a50b1900SMark Johnston mb = n; 16201b778ba2SMark Johnston if (mb != NULL) 1621a50b1900SMark Johnston n = mb->m_nextpkt; 1622a50b1900SMark Johnston } 1623a50b1900SMark Johnston } 1624a50b1900SMark Johnston } 1625a50b1900SMark Johnston SOCKBUF_UNLOCK(sb); 1626a50b1900SMark Johnston SOCK_UNLOCK(so); 1627a50b1900SMark Johnston return (mb != NULL); 1628a50b1900SMark Johnston } 1629a50b1900SMark Johnston 1630a29f300eSGarrett Wollman static int 1631c80ea19bSGleb Smirnoff uipc_ready(struct socket *so, struct mbuf *m, int count) 1632c80ea19bSGleb Smirnoff { 1633c80ea19bSGleb Smirnoff struct unpcb *unp, *unp2; 1634c80ea19bSGleb Smirnoff struct socket *so2; 1635a50b1900SMark Johnston int error, i; 1636c80ea19bSGleb Smirnoff 1637c80ea19bSGleb Smirnoff unp = sotounpcb(so); 1638c80ea19bSGleb Smirnoff 1639a50b1900SMark Johnston KASSERT(so->so_type == SOCK_STREAM, 1640a50b1900SMark Johnston ("%s: unexpected socket type for %p", __func__, so)); 1641a50b1900SMark Johnston 1642a62b4665SMatt Macy UNP_PCB_LOCK(unp); 1643ccdadf1aSMark Johnston if ((unp2 = unp_pcb_lock_peer(unp)) != NULL) { 1644a62b4665SMatt Macy UNP_PCB_UNLOCK(unp); 1645c80ea19bSGleb Smirnoff so2 = unp2->unp_socket; 1646c80ea19bSGleb Smirnoff SOCKBUF_LOCK(&so2->so_rcv); 1647c80ea19bSGleb Smirnoff if ((error = sbready(&so2->so_rcv, m, count)) == 0) 1648c80ea19bSGleb Smirnoff sorwakeup_locked(so2); 1649c80ea19bSGleb Smirnoff else 1650c80ea19bSGleb Smirnoff SOCKBUF_UNLOCK(&so2->so_rcv); 1651c80ea19bSGleb Smirnoff UNP_PCB_UNLOCK(unp2); 1652c80ea19bSGleb Smirnoff return (error); 1653ccdadf1aSMark Johnston } 1654ccdadf1aSMark Johnston UNP_PCB_UNLOCK(unp); 1655a50b1900SMark Johnston 1656a50b1900SMark Johnston /* 1657a50b1900SMark Johnston * The receiving socket has been disconnected, but may still be valid. 1658a50b1900SMark Johnston * In this case, the now-ready mbufs are still present in its socket 1659a50b1900SMark Johnston * buffer, so perform an exhaustive search before giving up and freeing 1660a50b1900SMark Johnston * the mbufs. 1661a50b1900SMark Johnston */ 1662a50b1900SMark Johnston UNP_LINK_RLOCK(); 1663a50b1900SMark Johnston LIST_FOREACH(unp, &unp_shead, unp_link) { 1664a50b1900SMark Johnston if (uipc_ready_scan(unp->unp_socket, m, count, &error)) 1665a50b1900SMark Johnston break; 1666a50b1900SMark Johnston } 1667a50b1900SMark Johnston UNP_LINK_RUNLOCK(); 1668a50b1900SMark Johnston 1669a50b1900SMark Johnston if (unp == NULL) { 1670a50b1900SMark Johnston for (i = 0; i < count; i++) 1671a62b4665SMatt Macy m = m_free(m); 1672a50b1900SMark Johnston error = ECONNRESET; 1673a50b1900SMark Johnston } 1674a50b1900SMark Johnston return (error); 1675c80ea19bSGleb Smirnoff } 1676c80ea19bSGleb Smirnoff 1677c80ea19bSGleb Smirnoff static int 1678a29f300eSGarrett Wollman uipc_sense(struct socket *so, struct stat *sb) 1679a29f300eSGarrett Wollman { 1680c2090e73SAlan Somers struct unpcb *unp; 1681a29f300eSGarrett Wollman 168240f2ac28SRobert Watson unp = sotounpcb(so); 16834d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_sense: unp == NULL")); 1684e7c33e29SRobert Watson 1685a29f300eSGarrett Wollman sb->st_blksize = so->so_snd.sb_hiwat; 1686f3732fd1SPoul-Henning Kamp sb->st_dev = NODEV; 1687a29f300eSGarrett Wollman sb->st_ino = unp->unp_ino; 1688df8bae1dSRodney W. Grimes return (0); 1689a29f300eSGarrett Wollman } 1690df8bae1dSRodney W. Grimes 1691a29f300eSGarrett Wollman static int 1692a29f300eSGarrett Wollman uipc_shutdown(struct socket *so) 1693a29f300eSGarrett Wollman { 169440f2ac28SRobert Watson struct unpcb *unp; 1695df8bae1dSRodney W. Grimes 169640f2ac28SRobert Watson unp = sotounpcb(so); 16974d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_shutdown: unp == NULL")); 1698e7c33e29SRobert Watson 1699e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 1700a29f300eSGarrett Wollman socantsendmore(so); 1701a29f300eSGarrett Wollman unp_shutdown(unp); 1702e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 1703e5aeaa0cSDag-Erling Smørgrav return (0); 1704a29f300eSGarrett Wollman } 1705df8bae1dSRodney W. Grimes 1706a29f300eSGarrett Wollman static int 170757bf258eSGarrett Wollman uipc_sockaddr(struct socket *so, struct sockaddr **nam) 1708a29f300eSGarrett Wollman { 170940f2ac28SRobert Watson struct unpcb *unp; 17100d9ce3a1SRobert Watson const struct sockaddr *sa; 1711a29f300eSGarrett Wollman 17124d4b555eSRobert Watson unp = sotounpcb(so); 17134d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_sockaddr: unp == NULL")); 1714e7c33e29SRobert Watson 17150d9ce3a1SRobert Watson *nam = malloc(sizeof(struct sockaddr_un), M_SONAME, M_WAITOK); 1716e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 1717fc3fcacfSRobert Watson if (unp->unp_addr != NULL) 17180d9ce3a1SRobert Watson sa = (struct sockaddr *) unp->unp_addr; 171983f3198bSThomas Moestl else 17200d9ce3a1SRobert Watson sa = &sun_noname; 17210d9ce3a1SRobert Watson bcopy(sa, *nam, sa->sa_len); 1722e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 1723e5aeaa0cSDag-Erling Smørgrav return (0); 1724df8bae1dSRodney W. Grimes } 1725a29f300eSGarrett Wollman 17260b36cd25SRobert Watson static int 1727892af6b9SRobert Watson uipc_ctloutput(struct socket *so, struct sockopt *sopt) 17280c1bb4fbSDima Dorfman { 172940f2ac28SRobert Watson struct unpcb *unp; 17300d9ce3a1SRobert Watson struct xucred xu; 17316a2989fdSMatthew N. Dodd int error, optval; 17326a2989fdSMatthew N. Dodd 17336e0c8e1aSKonstantin Belousov if (sopt->sopt_level != SOL_LOCAL) 173496a041b5SMatthew N. Dodd return (EINVAL); 173596a041b5SMatthew N. Dodd 17366a2989fdSMatthew N. Dodd unp = sotounpcb(so); 17374d4b555eSRobert Watson KASSERT(unp != NULL, ("uipc_ctloutput: unp == NULL")); 17386a2989fdSMatthew N. Dodd error = 0; 17390c1bb4fbSDima Dorfman switch (sopt->sopt_dir) { 17400c1bb4fbSDima Dorfman case SOPT_GET: 17410c1bb4fbSDima Dorfman switch (sopt->sopt_name) { 17420c1bb4fbSDima Dorfman case LOCAL_PEERCRED: 1743e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 17440c1bb4fbSDima Dorfman if (unp->unp_flags & UNP_HAVEPC) 17450d9ce3a1SRobert Watson xu = unp->unp_peercred; 17460c1bb4fbSDima Dorfman else { 17470c1bb4fbSDima Dorfman if (so->so_type == SOCK_STREAM) 17480c1bb4fbSDima Dorfman error = ENOTCONN; 17490c1bb4fbSDima Dorfman else 17500c1bb4fbSDima Dorfman error = EINVAL; 17510c1bb4fbSDima Dorfman } 1752e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 17530d9ce3a1SRobert Watson if (error == 0) 17540d9ce3a1SRobert Watson error = sooptcopyout(sopt, &xu, sizeof(xu)); 17550c1bb4fbSDima Dorfman break; 1756e7c33e29SRobert Watson 17576a2989fdSMatthew N. Dodd case LOCAL_CREDS: 1758a6357845SRobert Watson /* Unlocked read. */ 17592de07e40SConrad Meyer optval = unp->unp_flags & UNP_WANTCRED_ONESHOT ? 1 : 0; 17602de07e40SConrad Meyer error = sooptcopyout(sopt, &optval, sizeof(optval)); 17612de07e40SConrad Meyer break; 17622de07e40SConrad Meyer 17632de07e40SConrad Meyer case LOCAL_CREDS_PERSISTENT: 17642de07e40SConrad Meyer /* Unlocked read. */ 17652de07e40SConrad Meyer optval = unp->unp_flags & UNP_WANTCRED_ALWAYS ? 1 : 0; 17666a2989fdSMatthew N. Dodd error = sooptcopyout(sopt, &optval, sizeof(optval)); 17676a2989fdSMatthew N. Dodd break; 1768e7c33e29SRobert Watson 17696a2989fdSMatthew N. Dodd case LOCAL_CONNWAIT: 1770a6357845SRobert Watson /* Unlocked read. */ 17716a2989fdSMatthew N. Dodd optval = unp->unp_flags & UNP_CONNWAIT ? 1 : 0; 17726a2989fdSMatthew N. Dodd error = sooptcopyout(sopt, &optval, sizeof(optval)); 17736a2989fdSMatthew N. Dodd break; 1774e7c33e29SRobert Watson 17750c1bb4fbSDima Dorfman default: 17760c1bb4fbSDima Dorfman error = EOPNOTSUPP; 17770c1bb4fbSDima Dorfman break; 17780c1bb4fbSDima Dorfman } 17790c1bb4fbSDima Dorfman break; 1780e7c33e29SRobert Watson 17810c1bb4fbSDima Dorfman case SOPT_SET: 17826a2989fdSMatthew N. Dodd switch (sopt->sopt_name) { 17836a2989fdSMatthew N. Dodd case LOCAL_CREDS: 17842de07e40SConrad Meyer case LOCAL_CREDS_PERSISTENT: 17856a2989fdSMatthew N. Dodd case LOCAL_CONNWAIT: 17866a2989fdSMatthew N. Dodd error = sooptcopyin(sopt, &optval, sizeof(optval), 17876a2989fdSMatthew N. Dodd sizeof(optval)); 17886a2989fdSMatthew N. Dodd if (error) 17896a2989fdSMatthew N. Dodd break; 17906a2989fdSMatthew N. Dodd 17912de07e40SConrad Meyer #define OPTSET(bit, exclusive) do { \ 1792e7c33e29SRobert Watson UNP_PCB_LOCK(unp); \ 17932de07e40SConrad Meyer if (optval) { \ 17942de07e40SConrad Meyer if ((unp->unp_flags & (exclusive)) != 0) { \ 17952de07e40SConrad Meyer UNP_PCB_UNLOCK(unp); \ 17962de07e40SConrad Meyer error = EINVAL; \ 17972de07e40SConrad Meyer break; \ 17982de07e40SConrad Meyer } \ 17992de07e40SConrad Meyer unp->unp_flags |= (bit); \ 18002de07e40SConrad Meyer } else \ 18012de07e40SConrad Meyer unp->unp_flags &= ~(bit); \ 1802e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); \ 1803e7c33e29SRobert Watson } while (0) 18046a2989fdSMatthew N. Dodd 18056a2989fdSMatthew N. Dodd switch (sopt->sopt_name) { 18066a2989fdSMatthew N. Dodd case LOCAL_CREDS: 18072de07e40SConrad Meyer OPTSET(UNP_WANTCRED_ONESHOT, UNP_WANTCRED_ALWAYS); 18082de07e40SConrad Meyer break; 18092de07e40SConrad Meyer 18102de07e40SConrad Meyer case LOCAL_CREDS_PERSISTENT: 18112de07e40SConrad Meyer OPTSET(UNP_WANTCRED_ALWAYS, UNP_WANTCRED_ONESHOT); 18126a2989fdSMatthew N. Dodd break; 1813e7c33e29SRobert Watson 18146a2989fdSMatthew N. Dodd case LOCAL_CONNWAIT: 18152de07e40SConrad Meyer OPTSET(UNP_CONNWAIT, 0); 18166a2989fdSMatthew N. Dodd break; 1817e7c33e29SRobert Watson 18186a2989fdSMatthew N. Dodd default: 18196a2989fdSMatthew N. Dodd break; 18206a2989fdSMatthew N. Dodd } 18216a2989fdSMatthew N. Dodd break; 18226a2989fdSMatthew N. Dodd #undef OPTSET 18236a2989fdSMatthew N. Dodd default: 18246a2989fdSMatthew N. Dodd error = ENOPROTOOPT; 18256a2989fdSMatthew N. Dodd break; 18266a2989fdSMatthew N. Dodd } 1827abb886faSMatthew N. Dodd break; 1828e7c33e29SRobert Watson 18290c1bb4fbSDima Dorfman default: 18300c1bb4fbSDima Dorfman error = EOPNOTSUPP; 18310c1bb4fbSDima Dorfman break; 18320c1bb4fbSDima Dorfman } 18330c1bb4fbSDima Dorfman return (error); 18340c1bb4fbSDima Dorfman } 18350c1bb4fbSDima Dorfman 1836f708ef1bSPoul-Henning Kamp static int 1837892af6b9SRobert Watson unp_connect(struct socket *so, struct sockaddr *nam, struct thread *td) 1838df8bae1dSRodney W. Grimes { 18397493f24eSPawel Jakub Dawidek 1840315167c0SGleb Smirnoff return (unp_connectat(AT_FDCWD, so, nam, td, false)); 18417493f24eSPawel Jakub Dawidek } 18427493f24eSPawel Jakub Dawidek 18437493f24eSPawel Jakub Dawidek static int 18447493f24eSPawel Jakub Dawidek unp_connectat(int fd, struct socket *so, struct sockaddr *nam, 1845315167c0SGleb Smirnoff struct thread *td, bool return_locked) 18467493f24eSPawel Jakub Dawidek { 1847ed92e1c7SMark Johnston struct mtx *vplock; 1848ed92e1c7SMark Johnston struct sockaddr_un *soun; 1849892af6b9SRobert Watson struct vnode *vp; 1850779f106aSGleb Smirnoff struct socket *so2; 1851b295bdcdSRobert Watson struct unpcb *unp, *unp2, *unp3; 1852df8bae1dSRodney W. Grimes struct nameidata nd; 185357bf258eSGarrett Wollman char buf[SOCK_MAXADDRLEN]; 18540d9ce3a1SRobert Watson struct sockaddr *sa; 18557008be5bSPawel Jakub Dawidek cap_rights_t rights; 1856ccdadf1aSMark Johnston int error, len; 1857ed92e1c7SMark Johnston bool connreq; 18580d9ce3a1SRobert Watson 1859cb7df69bSKevin Lo if (nam->sa_family != AF_UNIX) 1860cb7df69bSKevin Lo return (EAFNOSUPPORT); 1861a06534c3SBjoern A. Zeeb if (nam->sa_len > sizeof(struct sockaddr_un)) 1862a06534c3SBjoern A. Zeeb return (EINVAL); 186357bf258eSGarrett Wollman len = nam->sa_len - offsetof(struct sockaddr_un, sun_path); 186457bf258eSGarrett Wollman if (len <= 0) 1865e5aeaa0cSDag-Erling Smørgrav return (EINVAL); 1866ed92e1c7SMark Johnston soun = (struct sockaddr_un *)nam; 18677928893dSEd Maste bcopy(soun->sun_path, buf, len); 18687928893dSEd Maste buf[len] = 0; 1869e7c33e29SRobert Watson 1870bd4a39ccSMark Johnston error = 0; 187175a67bf3SMatt Macy unp = sotounpcb(so); 1872e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 1873ccdadf1aSMark Johnston for (;;) { 1874ccdadf1aSMark Johnston /* 1875ccdadf1aSMark Johnston * Wait for connection state to stabilize. If a connection 1876ccdadf1aSMark Johnston * already exists, give up. For datagram sockets, which permit 1877ccdadf1aSMark Johnston * multiple consecutive connect(2) calls, upper layers are 1878ccdadf1aSMark Johnston * responsible for disconnecting in advance of a subsequent 1879ccdadf1aSMark Johnston * connect(2), but this is not synchronized with PCB connection 1880ccdadf1aSMark Johnston * state. 1881ccdadf1aSMark Johnston * 1882ccdadf1aSMark Johnston * Also make sure that no threads are currently attempting to 1883ccdadf1aSMark Johnston * lock the peer socket, to ensure that unp_conn cannot 1884ccdadf1aSMark Johnston * transition between two valid sockets while locks are dropped. 1885ccdadf1aSMark Johnston */ 1886bd4a39ccSMark Johnston if (SOLISTENING(so)) 1887bd4a39ccSMark Johnston error = EOPNOTSUPP; 1888bd4a39ccSMark Johnston else if (unp->unp_conn != NULL) 1889bd4a39ccSMark Johnston error = EISCONN; 1890bd4a39ccSMark Johnston else if ((unp->unp_flags & UNP_CONNECTING) != 0) { 1891bd4a39ccSMark Johnston error = EALREADY; 1892ccdadf1aSMark Johnston } 1893bd4a39ccSMark Johnston if (error != 0) { 1894e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 1895bd4a39ccSMark Johnston return (error); 18964f1f0ef5SRobert Watson } 1897ccdadf1aSMark Johnston if (unp->unp_pairbusy > 0) { 1898ccdadf1aSMark Johnston unp->unp_flags |= UNP_WAITING; 1899ccdadf1aSMark Johnston mtx_sleep(unp, UNP_PCB_LOCKPTR(unp), 0, "unpeer", 0); 1900ccdadf1aSMark Johnston continue; 1901ccdadf1aSMark Johnston } 1902ccdadf1aSMark Johnston break; 1903ccdadf1aSMark Johnston } 190405102f04SRobert Watson unp->unp_flags |= UNP_CONNECTING; 1905e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 1906e7c33e29SRobert Watson 1907ed92e1c7SMark Johnston connreq = (so->so_proto->pr_flags & PR_CONNREQUIRED) != 0; 1908ed92e1c7SMark Johnston if (connreq) 19090d9ce3a1SRobert Watson sa = malloc(sizeof(struct sockaddr_un), M_SONAME, M_WAITOK); 1910ed92e1c7SMark Johnston else 1911ed92e1c7SMark Johnston sa = NULL; 19127493f24eSPawel Jakub Dawidek NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF, 19137e1d3eefSMateusz Guzik UIO_SYSSPACE, buf, fd, cap_rights_init_one(&rights, CAP_CONNECTAT)); 1914797f2d22SPoul-Henning Kamp error = namei(&nd); 1915797f2d22SPoul-Henning Kamp if (error) 19160d9ce3a1SRobert Watson vp = NULL; 19170d9ce3a1SRobert Watson else 1918df8bae1dSRodney W. Grimes vp = nd.ni_vp; 19190d9ce3a1SRobert Watson ASSERT_VOP_LOCKED(vp, "unp_connect"); 19200d9ce3a1SRobert Watson if (error) 19210d9ce3a1SRobert Watson goto bad; 19225b5b7e2cSMateusz Guzik NDFREE_PNBUF(&nd); 19230d9ce3a1SRobert Watson 1924df8bae1dSRodney W. Grimes if (vp->v_type != VSOCK) { 1925df8bae1dSRodney W. Grimes error = ENOTSOCK; 1926df8bae1dSRodney W. Grimes goto bad; 1927df8bae1dSRodney W. Grimes } 19286fac927cSRobert Watson #ifdef MAC 192930d239bcSRobert Watson error = mac_vnode_check_open(td->td_ucred, vp, VWRITE | VREAD); 19306fac927cSRobert Watson if (error) 19316fac927cSRobert Watson goto bad; 19326fac927cSRobert Watson #endif 1933a854ed98SJohn Baldwin error = VOP_ACCESS(vp, VWRITE, td->td_ucred, td); 1934797f2d22SPoul-Henning Kamp if (error) 1935df8bae1dSRodney W. Grimes goto bad; 1936e7c33e29SRobert Watson 1937b295bdcdSRobert Watson unp = sotounpcb(so); 19384d4b555eSRobert Watson KASSERT(unp != NULL, ("unp_connect: unp == NULL")); 1939e7c33e29SRobert Watson 194075a67bf3SMatt Macy vplock = mtx_pool_find(mtxpool_sleep, vp); 194175a67bf3SMatt Macy mtx_lock(vplock); 19420c3c207fSGleb Smirnoff VOP_UNP_CONNECT(vp, &unp2); 19430c3c207fSGleb Smirnoff if (unp2 == NULL) { 1944df8bae1dSRodney W. Grimes error = ECONNREFUSED; 19452260c03dSRobert Watson goto bad2; 1946df8bae1dSRodney W. Grimes } 19470c3c207fSGleb Smirnoff so2 = unp2->unp_socket; 1948df8bae1dSRodney W. Grimes if (so->so_type != so2->so_type) { 1949df8bae1dSRodney W. Grimes error = EPROTOTYPE; 19502260c03dSRobert Watson goto bad2; 1951df8bae1dSRodney W. Grimes } 1952ed92e1c7SMark Johnston if (connreq) { 1953f4bb1869SMark Johnston if (SOLISTENING(so2)) { 19541fb51a12SBjoern A. Zeeb CURVNET_SET(so2->so_vnet); 1955779f106aSGleb Smirnoff so2 = sonewconn(so2, 0); 19561fb51a12SBjoern A. Zeeb CURVNET_RESTORE(); 1957e7c33e29SRobert Watson } else 1958779f106aSGleb Smirnoff so2 = NULL; 1959779f106aSGleb Smirnoff if (so2 == NULL) { 1960df8bae1dSRodney W. Grimes error = ECONNREFUSED; 1961cb8f450bSMatt Macy goto bad2; 1962df8bae1dSRodney W. Grimes } 1963779f106aSGleb Smirnoff unp3 = sotounpcb(so2); 19644820bf6aSMark Johnston unp_pcb_lock_pair(unp2, unp3); 19650d9ce3a1SRobert Watson if (unp2->unp_addr != NULL) { 19660d9ce3a1SRobert Watson bcopy(unp2->unp_addr, sa, unp2->unp_addr->sun_len); 19670d9ce3a1SRobert Watson unp3->unp_addr = (struct sockaddr_un *) sa; 19680d9ce3a1SRobert Watson sa = NULL; 19690d9ce3a1SRobert Watson } 1970b523ec24SRobert Watson 1971da446550SAlan Somers unp_copy_peercred(td, unp3, unp, unp2); 1972b523ec24SRobert Watson 1973e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp2); 1974779f106aSGleb Smirnoff unp2 = unp3; 1975ccdadf1aSMark Johnston 1976ccdadf1aSMark Johnston /* 1977ccdadf1aSMark Johnston * It is safe to block on the PCB lock here since unp2 is 1978ccdadf1aSMark Johnston * nascent and cannot be connected to any other sockets. 1979ccdadf1aSMark Johnston */ 1980ccdadf1aSMark Johnston UNP_PCB_LOCK(unp); 1981335654d7SRobert Watson #ifdef MAC 1982779f106aSGleb Smirnoff mac_socketpeer_set_from_socket(so, so2); 1983779f106aSGleb Smirnoff mac_socketpeer_set_from_socket(so2, so); 1984335654d7SRobert Watson #endif 1985a3a73490SMatt Macy } else { 19864820bf6aSMark Johnston unp_pcb_lock_pair(unp, unp2); 1987a3a73490SMatt Macy } 1988779f106aSGleb Smirnoff KASSERT(unp2 != NULL && so2 != NULL && unp2->unp_socket == so2 && 1989779f106aSGleb Smirnoff sotounpcb(so2) == unp2, 1990779f106aSGleb Smirnoff ("%s: unp2 %p so2 %p", __func__, unp2, so2)); 199108f17d14SGleb Smirnoff unp_connect2(so, so2, PRU_CONNECT); 1992bb35a4e1SGleb Smirnoff KASSERT((unp->unp_flags & UNP_CONNECTING) != 0, 1993bb35a4e1SGleb Smirnoff ("%s: unp %p has UNP_CONNECTING clear", __func__, unp)); 1994bb35a4e1SGleb Smirnoff unp->unp_flags &= ~UNP_CONNECTING; 1995315167c0SGleb Smirnoff if (!return_locked) 19964820bf6aSMark Johnston unp_pcb_unlock_pair(unp, unp2); 19970d9ce3a1SRobert Watson bad2: 199875a67bf3SMatt Macy mtx_unlock(vplock); 1999df8bae1dSRodney W. Grimes bad: 200075a67bf3SMatt Macy if (vp != NULL) { 2001315167c0SGleb Smirnoff /* 2002315167c0SGleb Smirnoff * If we are returning locked (called via uipc_sosend_dgram()), 2003315167c0SGleb Smirnoff * we need to be sure that vput() won't sleep. This is 2004315167c0SGleb Smirnoff * guaranteed by VOP_UNP_CONNECT() call above and unp2 lock. 2005315167c0SGleb Smirnoff * SOCK_STREAM/SEQPACKET can't request return_locked (yet). 2006315167c0SGleb Smirnoff */ 2007315167c0SGleb Smirnoff MPASS(!(return_locked && connreq)); 2008df8bae1dSRodney W. Grimes vput(vp); 200975a67bf3SMatt Macy } 20100d9ce3a1SRobert Watson free(sa, M_SONAME); 2011bb35a4e1SGleb Smirnoff if (__predict_false(error)) { 2012e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 2013ccdadf1aSMark Johnston KASSERT((unp->unp_flags & UNP_CONNECTING) != 0, 2014ccdadf1aSMark Johnston ("%s: unp %p has UNP_CONNECTING clear", __func__, unp)); 20154f1f0ef5SRobert Watson unp->unp_flags &= ~UNP_CONNECTING; 2016e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 2017bb35a4e1SGleb Smirnoff } 2018df8bae1dSRodney W. Grimes return (error); 2019df8bae1dSRodney W. Grimes } 2020df8bae1dSRodney W. Grimes 2021da446550SAlan Somers /* 2022da446550SAlan Somers * Set socket peer credentials at connection time. 2023da446550SAlan Somers * 2024da446550SAlan Somers * The client's PCB credentials are copied from its process structure. The 2025da446550SAlan Somers * server's PCB credentials are copied from the socket on which it called 2026da446550SAlan Somers * listen(2). uipc_listen cached that process's credentials at the time. 2027da446550SAlan Somers */ 2028da446550SAlan Somers void 2029da446550SAlan Somers unp_copy_peercred(struct thread *td, struct unpcb *client_unp, 2030da446550SAlan Somers struct unpcb *server_unp, struct unpcb *listen_unp) 2031da446550SAlan Somers { 2032c5afec6eSDmitry Chagin cru2xt(td, &client_unp->unp_peercred); 2033da446550SAlan Somers client_unp->unp_flags |= UNP_HAVEPC; 2034da446550SAlan Somers 2035da446550SAlan Somers memcpy(&server_unp->unp_peercred, &listen_unp->unp_peercred, 2036da446550SAlan Somers sizeof(server_unp->unp_peercred)); 2037da446550SAlan Somers server_unp->unp_flags |= UNP_HAVEPC; 20382de07e40SConrad Meyer client_unp->unp_flags |= (listen_unp->unp_flags & UNP_WANTCRED_MASK); 2039da446550SAlan Somers } 2040da446550SAlan Somers 204108f17d14SGleb Smirnoff static void 2042f6dc5aa3SGleb Smirnoff unp_connect2(struct socket *so, struct socket *so2, conn2_how req) 2043df8bae1dSRodney W. Grimes { 2044e7c33e29SRobert Watson struct unpcb *unp; 2045892af6b9SRobert Watson struct unpcb *unp2; 2046df8bae1dSRodney W. Grimes 204708f17d14SGleb Smirnoff MPASS(so2->so_type == so->so_type); 2048e7c33e29SRobert Watson unp = sotounpcb(so); 2049e7c33e29SRobert Watson KASSERT(unp != NULL, ("unp_connect2: unp == NULL")); 2050e7c33e29SRobert Watson unp2 = sotounpcb(so2); 2051e7c33e29SRobert Watson KASSERT(unp2 != NULL, ("unp_connect2: unp2 == NULL")); 2052e7c33e29SRobert Watson 2053e7c33e29SRobert Watson UNP_PCB_LOCK_ASSERT(unp); 2054e7c33e29SRobert Watson UNP_PCB_LOCK_ASSERT(unp2); 2055ccdadf1aSMark Johnston KASSERT(unp->unp_conn == NULL, 2056ccdadf1aSMark Johnston ("%s: socket %p is already connected", __func__, unp)); 20570d9ce3a1SRobert Watson 2058df8bae1dSRodney W. Grimes unp->unp_conn = unp2; 205975a67bf3SMatt Macy unp_pcb_hold(unp2); 206075a67bf3SMatt Macy unp_pcb_hold(unp); 2061df8bae1dSRodney W. Grimes switch (so->so_type) { 2062df8bae1dSRodney W. Grimes case SOCK_DGRAM: 206375a67bf3SMatt Macy UNP_REF_LIST_LOCK(); 206498271db4SGarrett Wollman LIST_INSERT_HEAD(&unp2->unp_refs, unp, unp_reflink); 206575a67bf3SMatt Macy UNP_REF_LIST_UNLOCK(); 2066df8bae1dSRodney W. Grimes soisconnected(so); 2067df8bae1dSRodney W. Grimes break; 2068df8bae1dSRodney W. Grimes 2069df8bae1dSRodney W. Grimes case SOCK_STREAM: 207084d61770SRobert Watson case SOCK_SEQPACKET: 2071ccdadf1aSMark Johnston KASSERT(unp2->unp_conn == NULL, 2072ccdadf1aSMark Johnston ("%s: socket %p is already connected", __func__, unp2)); 2073df8bae1dSRodney W. Grimes unp2->unp_conn = unp; 20746a2989fdSMatthew N. Dodd if (req == PRU_CONNECT && 20756a2989fdSMatthew N. Dodd ((unp->unp_flags | unp2->unp_flags) & UNP_CONNWAIT)) 20766a2989fdSMatthew N. Dodd soisconnecting(so); 20776a2989fdSMatthew N. Dodd else 2078df8bae1dSRodney W. Grimes soisconnected(so); 2079df8bae1dSRodney W. Grimes soisconnected(so2); 2080df8bae1dSRodney W. Grimes break; 2081df8bae1dSRodney W. Grimes 2082df8bae1dSRodney W. Grimes default: 2083df8bae1dSRodney W. Grimes panic("unp_connect2"); 2084df8bae1dSRodney W. Grimes } 2085df8bae1dSRodney W. Grimes } 2086df8bae1dSRodney W. Grimes 2087f708ef1bSPoul-Henning Kamp static void 2088e7c33e29SRobert Watson unp_disconnect(struct unpcb *unp, struct unpcb *unp2) 2089df8bae1dSRodney W. Grimes { 209075a67bf3SMatt Macy struct socket *so, *so2; 2091458f475dSGleb Smirnoff struct mbuf *m = NULL; 2092f0317f86SMark Johnston #ifdef INVARIANTS 2093f0317f86SMark Johnston struct unpcb *unptmp; 2094f0317f86SMark Johnston #endif 20950d9ce3a1SRobert Watson 2096e7c33e29SRobert Watson UNP_PCB_LOCK_ASSERT(unp); 2097e7c33e29SRobert Watson UNP_PCB_LOCK_ASSERT(unp2); 2098f0317f86SMark Johnston KASSERT(unp->unp_conn == unp2, 2099f0317f86SMark Johnston ("%s: unpcb %p is not connected to %p", __func__, unp, unp2)); 2100e7c33e29SRobert Watson 2101fc3fcacfSRobert Watson unp->unp_conn = NULL; 210275a67bf3SMatt Macy so = unp->unp_socket; 210375a67bf3SMatt Macy so2 = unp2->unp_socket; 2104df8bae1dSRodney W. Grimes switch (unp->unp_socket->so_type) { 2105df8bae1dSRodney W. Grimes case SOCK_DGRAM: 2106458f475dSGleb Smirnoff /* 2107458f475dSGleb Smirnoff * Remove our send socket buffer from the peer's receive buffer. 2108458f475dSGleb Smirnoff * Move the data to the receive buffer only if it is empty. 2109458f475dSGleb Smirnoff * This is a protection against a scenario where a peer 2110458f475dSGleb Smirnoff * connects, floods and disconnects, effectively blocking 2111458f475dSGleb Smirnoff * sendto() from unconnected sockets. 2112458f475dSGleb Smirnoff */ 2113458f475dSGleb Smirnoff SOCK_RECVBUF_LOCK(so2); 2114458f475dSGleb Smirnoff if (!STAILQ_EMPTY(&so->so_snd.uxdg_mb)) { 2115458f475dSGleb Smirnoff TAILQ_REMOVE(&so2->so_rcv.uxdg_conns, &so->so_snd, 2116458f475dSGleb Smirnoff uxdg_clist); 2117458f475dSGleb Smirnoff if (__predict_true((so2->so_rcv.sb_state & 2118458f475dSGleb Smirnoff SBS_CANTRCVMORE) == 0) && 2119458f475dSGleb Smirnoff STAILQ_EMPTY(&so2->so_rcv.uxdg_mb)) { 2120458f475dSGleb Smirnoff STAILQ_CONCAT(&so2->so_rcv.uxdg_mb, 2121458f475dSGleb Smirnoff &so->so_snd.uxdg_mb); 2122458f475dSGleb Smirnoff so2->so_rcv.uxdg_cc += so->so_snd.uxdg_cc; 2123458f475dSGleb Smirnoff so2->so_rcv.uxdg_ctl += so->so_snd.uxdg_ctl; 2124458f475dSGleb Smirnoff so2->so_rcv.uxdg_mbcnt += so->so_snd.uxdg_mbcnt; 2125458f475dSGleb Smirnoff } else { 2126458f475dSGleb Smirnoff m = STAILQ_FIRST(&so->so_snd.uxdg_mb); 2127458f475dSGleb Smirnoff STAILQ_INIT(&so->so_snd.uxdg_mb); 2128458f475dSGleb Smirnoff so2->so_rcv.sb_acc -= so->so_snd.uxdg_cc; 2129458f475dSGleb Smirnoff so2->so_rcv.sb_ccc -= so->so_snd.uxdg_cc; 2130458f475dSGleb Smirnoff so2->so_rcv.sb_ctl -= so->so_snd.uxdg_ctl; 2131458f475dSGleb Smirnoff so2->so_rcv.sb_mbcnt -= so->so_snd.uxdg_mbcnt; 2132458f475dSGleb Smirnoff } 2133458f475dSGleb Smirnoff /* Note: so may reconnect. */ 2134458f475dSGleb Smirnoff so->so_snd.uxdg_cc = 0; 2135458f475dSGleb Smirnoff so->so_snd.uxdg_ctl = 0; 2136458f475dSGleb Smirnoff so->so_snd.uxdg_mbcnt = 0; 2137458f475dSGleb Smirnoff } 2138458f475dSGleb Smirnoff SOCK_RECVBUF_UNLOCK(so2); 213975a67bf3SMatt Macy UNP_REF_LIST_LOCK(); 2140f0317f86SMark Johnston #ifdef INVARIANTS 2141f0317f86SMark Johnston LIST_FOREACH(unptmp, &unp2->unp_refs, unp_reflink) { 2142f0317f86SMark Johnston if (unptmp == unp) 2143f0317f86SMark Johnston break; 2144f0317f86SMark Johnston } 2145f0317f86SMark Johnston KASSERT(unptmp != NULL, 2146f0317f86SMark Johnston ("%s: %p not found in reflist of %p", __func__, unp, unp2)); 2147f0317f86SMark Johnston #endif 214898271db4SGarrett Wollman LIST_REMOVE(unp, unp_reflink); 214975a67bf3SMatt Macy UNP_REF_LIST_UNLOCK(); 215075a67bf3SMatt Macy if (so) { 21511b2e3b4bSRobert Watson SOCK_LOCK(so); 21521b2e3b4bSRobert Watson so->so_state &= ~SS_ISCONNECTED; 21531b2e3b4bSRobert Watson SOCK_UNLOCK(so); 215475a67bf3SMatt Macy } 2155df8bae1dSRodney W. Grimes break; 2156df8bae1dSRodney W. Grimes 2157df8bae1dSRodney W. Grimes case SOCK_STREAM: 215884d61770SRobert Watson case SOCK_SEQPACKET: 215975a67bf3SMatt Macy if (so) 216075a67bf3SMatt Macy soisdisconnected(so); 216175a67bf3SMatt Macy MPASS(unp2->unp_conn == unp); 2162fc3fcacfSRobert Watson unp2->unp_conn = NULL; 216375a67bf3SMatt Macy if (so2) 216475a67bf3SMatt Macy soisdisconnected(so2); 2165df8bae1dSRodney W. Grimes break; 2166df8bae1dSRodney W. Grimes } 2167f0317f86SMark Johnston 2168f0317f86SMark Johnston if (unp == unp2) { 2169f0317f86SMark Johnston unp_pcb_rele_notlast(unp); 2170f0317f86SMark Johnston if (!unp_pcb_rele(unp)) 2171f0317f86SMark Johnston UNP_PCB_UNLOCK(unp); 2172f0317f86SMark Johnston } else { 2173f0317f86SMark Johnston if (!unp_pcb_rele(unp)) 2174f0317f86SMark Johnston UNP_PCB_UNLOCK(unp); 2175f0317f86SMark Johnston if (!unp_pcb_rele(unp2)) 2176f0317f86SMark Johnston UNP_PCB_UNLOCK(unp2); 2177f0317f86SMark Johnston } 2178458f475dSGleb Smirnoff 2179458f475dSGleb Smirnoff if (m != NULL) { 2180458f475dSGleb Smirnoff unp_scan(m, unp_freerights); 2181458f475dSGleb Smirnoff m_freem(m); 2182458f475dSGleb Smirnoff } 2183df8bae1dSRodney W. Grimes } 2184df8bae1dSRodney W. Grimes 21850d9ce3a1SRobert Watson /* 2186d7924b70SRobert Watson * unp_pcblist() walks the global list of struct unpcb's to generate a 2187d7924b70SRobert Watson * pointer list, bumping the refcount on each unpcb. It then copies them out 2188d7924b70SRobert Watson * sequentially, validating the generation number on each to see if it has 2189d7924b70SRobert Watson * been detached. All of this is necessary because copyout() may sleep on 2190d7924b70SRobert Watson * disk I/O. 21910d9ce3a1SRobert Watson */ 219298271db4SGarrett Wollman static int 219382d9ae4eSPoul-Henning Kamp unp_pcblist(SYSCTL_HANDLER_ARGS) 219498271db4SGarrett Wollman { 219598271db4SGarrett Wollman struct unpcb *unp, **unp_list; 219698271db4SGarrett Wollman unp_gen_t gencnt; 21978f364875SJulian Elischer struct xunpgen *xug; 219898271db4SGarrett Wollman struct unp_head *head; 21998f364875SJulian Elischer struct xunpcb *xu; 2200d821d364SPedro F. Giffuni u_int i; 22015362170dSMark Johnston int error, n; 220298271db4SGarrett Wollman 220384d61770SRobert Watson switch ((intptr_t)arg1) { 220484d61770SRobert Watson case SOCK_STREAM: 220584d61770SRobert Watson head = &unp_shead; 220684d61770SRobert Watson break; 220784d61770SRobert Watson 220884d61770SRobert Watson case SOCK_DGRAM: 220984d61770SRobert Watson head = &unp_dhead; 221084d61770SRobert Watson break; 221184d61770SRobert Watson 221284d61770SRobert Watson case SOCK_SEQPACKET: 221384d61770SRobert Watson head = &unp_sphead; 221484d61770SRobert Watson break; 221584d61770SRobert Watson 221684d61770SRobert Watson default: 2217604f19c9SRobert Watson panic("unp_pcblist: arg1 %d", (int)(intptr_t)arg1); 221884d61770SRobert Watson } 221998271db4SGarrett Wollman 222098271db4SGarrett Wollman /* 222198271db4SGarrett Wollman * The process of preparing the PCB list is too time-consuming and 222298271db4SGarrett Wollman * resource-intensive to repeat twice on every request. 222398271db4SGarrett Wollman */ 2224fc3fcacfSRobert Watson if (req->oldptr == NULL) { 222598271db4SGarrett Wollman n = unp_count; 22268f364875SJulian Elischer req->oldidx = 2 * (sizeof *xug) 222798271db4SGarrett Wollman + (n + n/8) * sizeof(struct xunpcb); 2228e5aeaa0cSDag-Erling Smørgrav return (0); 222998271db4SGarrett Wollman } 223098271db4SGarrett Wollman 2231fc3fcacfSRobert Watson if (req->newptr != NULL) 2232e5aeaa0cSDag-Erling Smørgrav return (EPERM); 223398271db4SGarrett Wollman 223498271db4SGarrett Wollman /* 223598271db4SGarrett Wollman * OK, now we're committed to doing something. 223698271db4SGarrett Wollman */ 223779db6fe7SMark Johnston xug = malloc(sizeof(*xug), M_TEMP, M_WAITOK | M_ZERO); 2238779f106aSGleb Smirnoff UNP_LINK_RLOCK(); 223998271db4SGarrett Wollman gencnt = unp_gencnt; 224098271db4SGarrett Wollman n = unp_count; 2241779f106aSGleb Smirnoff UNP_LINK_RUNLOCK(); 224298271db4SGarrett Wollman 22438f364875SJulian Elischer xug->xug_len = sizeof *xug; 22448f364875SJulian Elischer xug->xug_count = n; 22458f364875SJulian Elischer xug->xug_gen = gencnt; 22468f364875SJulian Elischer xug->xug_sogen = so_gencnt; 22478f364875SJulian Elischer error = SYSCTL_OUT(req, xug, sizeof *xug); 22488f364875SJulian Elischer if (error) { 22498f364875SJulian Elischer free(xug, M_TEMP); 2250e5aeaa0cSDag-Erling Smørgrav return (error); 22518f364875SJulian Elischer } 225298271db4SGarrett Wollman 2253a163d034SWarner Losh unp_list = malloc(n * sizeof *unp_list, M_TEMP, M_WAITOK); 225498271db4SGarrett Wollman 2255779f106aSGleb Smirnoff UNP_LINK_RLOCK(); 22562e3c8fcbSPoul-Henning Kamp for (unp = LIST_FIRST(head), i = 0; unp && i < n; 22572e3c8fcbSPoul-Henning Kamp unp = LIST_NEXT(unp, unp_link)) { 2258e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 22598a7d8cc6SRobert Watson if (unp->unp_gencnt <= gencnt) { 2260a854ed98SJohn Baldwin if (cr_cansee(req->td->td_ucred, 2261e7c33e29SRobert Watson unp->unp_socket->so_cred)) { 2262e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 22634787fd37SPaul Saab continue; 2264e7c33e29SRobert Watson } 226598271db4SGarrett Wollman unp_list[i++] = unp; 226675a67bf3SMatt Macy unp_pcb_hold(unp); 226798271db4SGarrett Wollman } 2268e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 22694787fd37SPaul Saab } 2270779f106aSGleb Smirnoff UNP_LINK_RUNLOCK(); 22711c381b19SRobert Watson n = i; /* In case we lost some during malloc. */ 227298271db4SGarrett Wollman 227398271db4SGarrett Wollman error = 0; 2274fe2eee82SColin Percival xu = malloc(sizeof(*xu), M_TEMP, M_WAITOK | M_ZERO); 227598271db4SGarrett Wollman for (i = 0; i < n; i++) { 227698271db4SGarrett Wollman unp = unp_list[i]; 2277e7c33e29SRobert Watson UNP_PCB_LOCK(unp); 22785362170dSMark Johnston if (unp_pcb_rele(unp)) 22795362170dSMark Johnston continue; 228075a67bf3SMatt Macy 22815362170dSMark Johnston if (unp->unp_gencnt <= gencnt) { 22828f364875SJulian Elischer xu->xu_len = sizeof *xu; 22833a20f06aSBrooks Davis xu->xu_unpp = (uintptr_t)unp; 228498271db4SGarrett Wollman /* 228598271db4SGarrett Wollman * XXX - need more locking here to protect against 228698271db4SGarrett Wollman * connect/disconnect races for SMP. 228798271db4SGarrett Wollman */ 2288fc3fcacfSRobert Watson if (unp->unp_addr != NULL) 22898f364875SJulian Elischer bcopy(unp->unp_addr, &xu->xu_addr, 229098271db4SGarrett Wollman unp->unp_addr->sun_len); 22910e229f34SGleb Smirnoff else 22920e229f34SGleb Smirnoff bzero(&xu->xu_addr, sizeof(xu->xu_addr)); 2293fc3fcacfSRobert Watson if (unp->unp_conn != NULL && 2294fc3fcacfSRobert Watson unp->unp_conn->unp_addr != NULL) 229598271db4SGarrett Wollman bcopy(unp->unp_conn->unp_addr, 22968f364875SJulian Elischer &xu->xu_caddr, 229798271db4SGarrett Wollman unp->unp_conn->unp_addr->sun_len); 22980e229f34SGleb Smirnoff else 22990e229f34SGleb Smirnoff bzero(&xu->xu_caddr, sizeof(xu->xu_caddr)); 23003a20f06aSBrooks Davis xu->unp_vnode = (uintptr_t)unp->unp_vnode; 23013a20f06aSBrooks Davis xu->unp_conn = (uintptr_t)unp->unp_conn; 23023a20f06aSBrooks Davis xu->xu_firstref = (uintptr_t)LIST_FIRST(&unp->unp_refs); 23033a20f06aSBrooks Davis xu->xu_nextref = (uintptr_t)LIST_NEXT(unp, unp_reflink); 23040e229f34SGleb Smirnoff xu->unp_gencnt = unp->unp_gencnt; 23058f364875SJulian Elischer sotoxsocket(unp->unp_socket, &xu->xu_socket); 2306e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 23078f364875SJulian Elischer error = SYSCTL_OUT(req, xu, sizeof *xu); 23085362170dSMark Johnston } else { 2309e7c33e29SRobert Watson UNP_PCB_UNLOCK(unp); 2310e7c33e29SRobert Watson } 23115362170dSMark Johnston } 23128f364875SJulian Elischer free(xu, M_TEMP); 231398271db4SGarrett Wollman if (!error) { 231498271db4SGarrett Wollman /* 23151c381b19SRobert Watson * Give the user an updated idea of our state. If the 23161c381b19SRobert Watson * generation differs from what we told her before, she knows 23171c381b19SRobert Watson * that something happened while we were processing this 23181c381b19SRobert Watson * request, and it might be necessary to retry. 231998271db4SGarrett Wollman */ 23208f364875SJulian Elischer xug->xug_gen = unp_gencnt; 23218f364875SJulian Elischer xug->xug_sogen = so_gencnt; 23228f364875SJulian Elischer xug->xug_count = unp_count; 23238f364875SJulian Elischer error = SYSCTL_OUT(req, xug, sizeof *xug); 232498271db4SGarrett Wollman } 232598271db4SGarrett Wollman free(unp_list, M_TEMP); 23268f364875SJulian Elischer free(xug, M_TEMP); 2327e5aeaa0cSDag-Erling Smørgrav return (error); 232898271db4SGarrett Wollman } 232998271db4SGarrett Wollman 23307029da5cSPawel Biernacki SYSCTL_PROC(_net_local_dgram, OID_AUTO, pcblist, 23317029da5cSPawel Biernacki CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, 23322fee06f0SMatthew D Fleming (void *)(intptr_t)SOCK_DGRAM, 0, unp_pcblist, "S,xunpcb", 233398271db4SGarrett Wollman "List of active local datagram sockets"); 23347029da5cSPawel Biernacki SYSCTL_PROC(_net_local_stream, OID_AUTO, pcblist, 23357029da5cSPawel Biernacki CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, 23362fee06f0SMatthew D Fleming (void *)(intptr_t)SOCK_STREAM, 0, unp_pcblist, "S,xunpcb", 233798271db4SGarrett Wollman "List of active local stream sockets"); 23382fee06f0SMatthew D Fleming SYSCTL_PROC(_net_local_seqpacket, OID_AUTO, pcblist, 23397029da5cSPawel Biernacki CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, 23402fee06f0SMatthew D Fleming (void *)(intptr_t)SOCK_SEQPACKET, 0, unp_pcblist, "S,xunpcb", 234184d61770SRobert Watson "List of active local seqpacket sockets"); 234298271db4SGarrett Wollman 2343f708ef1bSPoul-Henning Kamp static void 2344892af6b9SRobert Watson unp_shutdown(struct unpcb *unp) 2345df8bae1dSRodney W. Grimes { 2346e7c33e29SRobert Watson struct unpcb *unp2; 2347df8bae1dSRodney W. Grimes struct socket *so; 2348df8bae1dSRodney W. Grimes 2349e7c33e29SRobert Watson UNP_PCB_LOCK_ASSERT(unp); 23500d9ce3a1SRobert Watson 2351e7c33e29SRobert Watson unp2 = unp->unp_conn; 235284d61770SRobert Watson if ((unp->unp_socket->so_type == SOCK_STREAM || 235384d61770SRobert Watson (unp->unp_socket->so_type == SOCK_SEQPACKET)) && unp2 != NULL) { 2354e7c33e29SRobert Watson so = unp2->unp_socket; 2355e7c33e29SRobert Watson if (so != NULL) 2356df8bae1dSRodney W. Grimes socantrcvmore(so); 2357df8bae1dSRodney W. Grimes } 2358e7c33e29SRobert Watson } 2359df8bae1dSRodney W. Grimes 2360f708ef1bSPoul-Henning Kamp static void 2361afc055d9SEd Schouten unp_drop(struct unpcb *unp) 2362df8bae1dSRodney W. Grimes { 236350b07c1fSMark Johnston struct socket *so; 2364e7c33e29SRobert Watson struct unpcb *unp2; 23650d9ce3a1SRobert Watson 2366afc055d9SEd Schouten /* 2367afc055d9SEd Schouten * Regardless of whether the socket's peer dropped the connection 2368afc055d9SEd Schouten * with this socket by aborting or disconnecting, POSIX requires 2369afc055d9SEd Schouten * that ECONNRESET is returned. 2370afc055d9SEd Schouten */ 237175a67bf3SMatt Macy 237275a67bf3SMatt Macy UNP_PCB_LOCK(unp); 237350b07c1fSMark Johnston so = unp->unp_socket; 237475a67bf3SMatt Macy if (so) 2375afc055d9SEd Schouten so->so_error = ECONNRESET; 2376ccdadf1aSMark Johnston if ((unp2 = unp_pcb_lock_peer(unp)) != NULL) { 2377f0317f86SMark Johnston /* Last reference dropped in unp_disconnect(). */ 2378f0317f86SMark Johnston unp_pcb_rele_notlast(unp); 2379e7c33e29SRobert Watson unp_disconnect(unp, unp2); 2380f0317f86SMark Johnston } else if (!unp_pcb_rele(unp)) { 238175a67bf3SMatt Macy UNP_PCB_UNLOCK(unp); 238275a67bf3SMatt Macy } 2383f0317f86SMark Johnston } 2384df8bae1dSRodney W. Grimes 23852bc21ed9SDavid Malone static void 23868cb539f1SPawel Jakub Dawidek unp_freerights(struct filedescent **fdep, int fdcount) 2387df8bae1dSRodney W. Grimes { 23882bc21ed9SDavid Malone struct file *fp; 23892609222aSPawel Jakub Dawidek int i; 2390df8bae1dSRodney W. Grimes 239182e825c4SGleb Smirnoff KASSERT(fdcount > 0, ("%s: fdcount %d", __func__, fdcount)); 239282e825c4SGleb Smirnoff 23938cb539f1SPawel Jakub Dawidek for (i = 0; i < fdcount; i++) { 23948cb539f1SPawel Jakub Dawidek fp = fdep[i]->fde_file; 23958cb539f1SPawel Jakub Dawidek filecaps_free(&fdep[i]->fde_caps); 23968692c025SYoshinobu Inoue unp_discard(fp); 2397df8bae1dSRodney W. Grimes } 23988cb539f1SPawel Jakub Dawidek free(fdep[0], M_FILECAPS); 23992bc21ed9SDavid Malone } 24002bc21ed9SDavid Malone 24010b36cd25SRobert Watson static int 2402c2e3c52eSJilles Tjoelker unp_externalize(struct mbuf *control, struct mbuf **controlp, int flags) 24032bc21ed9SDavid Malone { 24042bc21ed9SDavid Malone struct thread *td = curthread; /* XXX */ 24052bc21ed9SDavid Malone struct cmsghdr *cm = mtod(control, struct cmsghdr *); 24062bc21ed9SDavid Malone int i; 24072bc21ed9SDavid Malone int *fdp; 24082609222aSPawel Jakub Dawidek struct filedesc *fdesc = td->td_proc->p_fd; 2409ea31808cSMateusz Guzik struct filedescent **fdep; 24102bc21ed9SDavid Malone void *data; 24112bc21ed9SDavid Malone socklen_t clen = control->m_len, datalen; 24122bc21ed9SDavid Malone int error, newfds; 24132bc21ed9SDavid Malone u_int newlen; 24142bc21ed9SDavid Malone 24153dab55bcSRobert Watson UNP_LINK_UNLOCK_ASSERT(); 24164c5bc1caSRobert Watson 24172bc21ed9SDavid Malone error = 0; 24182bc21ed9SDavid Malone if (controlp != NULL) /* controlp == NULL => free control messages */ 24192bc21ed9SDavid Malone *controlp = NULL; 24202bc21ed9SDavid Malone while (cm != NULL) { 242175e7e3ceSGleb Smirnoff MPASS(clen >= sizeof(*cm) && clen >= cm->cmsg_len); 24224682ac69SGleb Smirnoff 24232bc21ed9SDavid Malone data = CMSG_DATA(cm); 24242bc21ed9SDavid Malone datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data; 24252bc21ed9SDavid Malone if (cm->cmsg_level == SOL_SOCKET 24262bc21ed9SDavid Malone && cm->cmsg_type == SCM_RIGHTS) { 24272609222aSPawel Jakub Dawidek newfds = datalen / sizeof(*fdep); 242882e825c4SGleb Smirnoff if (newfds == 0) 242982e825c4SGleb Smirnoff goto next; 24302609222aSPawel Jakub Dawidek fdep = data; 24312bc21ed9SDavid Malone 2432e2f9a08bSOlivier Houchard /* If we're not outputting the descriptors free them. */ 24332bc21ed9SDavid Malone if (error || controlp == NULL) { 24342609222aSPawel Jakub Dawidek unp_freerights(fdep, newfds); 24352bc21ed9SDavid Malone goto next; 24362bc21ed9SDavid Malone } 24372609222aSPawel Jakub Dawidek FILEDESC_XLOCK(fdesc); 243860a5ef26SRobert Watson 2439ed5b7817SJulian Elischer /* 24401c381b19SRobert Watson * Now change each pointer to an fd in the global 24411c381b19SRobert Watson * table to an integer that is the index to the local 24421c381b19SRobert Watson * fd table entry that we set up to point to the 24431c381b19SRobert Watson * global one we are transferring. 2444ed5b7817SJulian Elischer */ 24452bc21ed9SDavid Malone newlen = newfds * sizeof(int); 24462bc21ed9SDavid Malone *controlp = sbcreatecontrol(NULL, newlen, 2447d64f2f42SGleb Smirnoff SCM_RIGHTS, SOL_SOCKET, M_WAITOK); 24482bc21ed9SDavid Malone 24492bc21ed9SDavid Malone fdp = (int *) 24502bc21ed9SDavid Malone CMSG_DATA(mtod(*controlp, struct cmsghdr *)); 245148a55bbfSGleb Smirnoff if ((error = fdallocn(td, 0, fdp, newfds))) { 24523331a33aSMateusz Guzik FILEDESC_XUNLOCK(fdesc); 2453db8f33fdSMateusz Guzik unp_freerights(fdep, newfds); 2454db8f33fdSMateusz Guzik m_freem(*controlp); 2455db8f33fdSMateusz Guzik *controlp = NULL; 2456db8f33fdSMateusz Guzik goto next; 2457db8f33fdSMateusz Guzik } 24588cb539f1SPawel Jakub Dawidek for (i = 0; i < newfds; i++, fdp++) { 2459ea31808cSMateusz Guzik _finstall(fdesc, fdep[i]->fde_file, *fdp, 24606ceacebdSAlex Richardson (flags & MSG_CMSG_CLOEXEC) != 0 ? O_CLOEXEC : 0, 2461ea31808cSMateusz Guzik &fdep[i]->fde_caps); 2462ea31808cSMateusz Guzik unp_externalize_fp(fdep[i]->fde_file); 2463df8bae1dSRodney W. Grimes } 2464c7902fbeSMark Johnston 2465c7902fbeSMark Johnston /* 2466c7902fbeSMark Johnston * The new type indicates that the mbuf data refers to 2467c7902fbeSMark Johnston * kernel resources that may need to be released before 2468c7902fbeSMark Johnston * the mbuf is freed. 2469c7902fbeSMark Johnston */ 2470c7902fbeSMark Johnston m_chtype(*controlp, MT_EXTCONTROL); 24712609222aSPawel Jakub Dawidek FILEDESC_XUNLOCK(fdesc); 24728cb539f1SPawel Jakub Dawidek free(fdep[0], M_FILECAPS); 24731c381b19SRobert Watson } else { 24741c381b19SRobert Watson /* We can just copy anything else across. */ 24752bc21ed9SDavid Malone if (error || controlp == NULL) 24762bc21ed9SDavid Malone goto next; 24772bc21ed9SDavid Malone *controlp = sbcreatecontrol(NULL, datalen, 2478d64f2f42SGleb Smirnoff cm->cmsg_type, cm->cmsg_level, M_WAITOK); 24792bc21ed9SDavid Malone bcopy(data, 24802bc21ed9SDavid Malone CMSG_DATA(mtod(*controlp, struct cmsghdr *)), 24812bc21ed9SDavid Malone datalen); 24822bc21ed9SDavid Malone } 24832bc21ed9SDavid Malone controlp = &(*controlp)->m_next; 24842bc21ed9SDavid Malone 24852bc21ed9SDavid Malone next: 24862bc21ed9SDavid Malone if (CMSG_SPACE(datalen) < clen) { 24872bc21ed9SDavid Malone clen -= CMSG_SPACE(datalen); 24882bc21ed9SDavid Malone cm = (struct cmsghdr *) 24892bc21ed9SDavid Malone ((caddr_t)cm + CMSG_SPACE(datalen)); 24908692c025SYoshinobu Inoue } else { 24912bc21ed9SDavid Malone clen = 0; 24922bc21ed9SDavid Malone cm = NULL; 24938692c025SYoshinobu Inoue } 24948692c025SYoshinobu Inoue } 24958692c025SYoshinobu Inoue 24962bc21ed9SDavid Malone m_freem(control); 24972bc21ed9SDavid Malone return (error); 2498df8bae1dSRodney W. Grimes } 2499df8bae1dSRodney W. Grimes 25004f590175SPaul Saab static void 25014f590175SPaul Saab unp_zone_change(void *tag) 25024f590175SPaul Saab { 25034f590175SPaul Saab 25044f590175SPaul Saab uma_zone_set_max(unp_zone, maxsockets); 25054f590175SPaul Saab } 25064f590175SPaul Saab 25075362170dSMark Johnston #ifdef INVARIANTS 25085362170dSMark Johnston static void 25095362170dSMark Johnston unp_zdtor(void *mem, int size __unused, void *arg __unused) 25105362170dSMark Johnston { 25115362170dSMark Johnston struct unpcb *unp; 25125362170dSMark Johnston 25135362170dSMark Johnston unp = mem; 25145362170dSMark Johnston 25155362170dSMark Johnston KASSERT(LIST_EMPTY(&unp->unp_refs), 25165362170dSMark Johnston ("%s: unpcb %p has lingering refs", __func__, unp)); 25175362170dSMark Johnston KASSERT(unp->unp_socket == NULL, 25185362170dSMark Johnston ("%s: unpcb %p has socket backpointer", __func__, unp)); 25195362170dSMark Johnston KASSERT(unp->unp_vnode == NULL, 25205362170dSMark Johnston ("%s: unpcb %p has vnode references", __func__, unp)); 25215362170dSMark Johnston KASSERT(unp->unp_conn == NULL, 25225362170dSMark Johnston ("%s: unpcb %p is still connected", __func__, unp)); 25235362170dSMark Johnston KASSERT(unp->unp_addr == NULL, 25245362170dSMark Johnston ("%s: unpcb %p has leaked addr", __func__, unp)); 25255362170dSMark Johnston } 25265362170dSMark Johnston #endif 25275362170dSMark Johnston 25280b36cd25SRobert Watson static void 252924e1c6aeSGleb Smirnoff unp_init(void *arg __unused) 253098271db4SGarrett Wollman { 25315362170dSMark Johnston uma_dtor dtor; 25321c381b19SRobert Watson 25335362170dSMark Johnston #ifdef INVARIANTS 25345362170dSMark Johnston dtor = unp_zdtor; 25355362170dSMark Johnston #else 25365362170dSMark Johnston dtor = NULL; 25375362170dSMark Johnston #endif 25385362170dSMark Johnston unp_zone = uma_zcreate("unpcb", sizeof(struct unpcb), NULL, dtor, 253975a67bf3SMatt Macy NULL, NULL, UMA_ALIGN_CACHE, 0); 25404f590175SPaul Saab uma_zone_set_max(unp_zone, maxsockets); 25416e0b6746SPawel Jakub Dawidek uma_zone_set_warning(unp_zone, "kern.ipc.maxsockets limit reached"); 25424f590175SPaul Saab EVENTHANDLER_REGISTER(maxsockets_change, unp_zone_change, 25434f590175SPaul Saab NULL, EVENTHANDLER_PRI_ANY); 254498271db4SGarrett Wollman LIST_INIT(&unp_dhead); 254598271db4SGarrett Wollman LIST_INIT(&unp_shead); 254684d61770SRobert Watson LIST_INIT(&unp_sphead); 25470cb64678SKonstantin Belousov SLIST_INIT(&unp_defers); 2548daee0f0bSKonstantin Belousov TIMEOUT_TASK_INIT(taskqueue_thread, &unp_gc_task, 0, unp_gc, NULL); 25490cb64678SKonstantin Belousov TASK_INIT(&unp_defer_task, 0, unp_process_defers, NULL); 25503dab55bcSRobert Watson UNP_LINK_LOCK_INIT(); 25510cb64678SKonstantin Belousov UNP_DEFERRED_LOCK_INIT(); 255298271db4SGarrett Wollman } 255324e1c6aeSGleb Smirnoff SYSINIT(unp_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_SECOND, unp_init, NULL); 255498271db4SGarrett Wollman 255547c3450eSKonstantin Belousov static void 255647c3450eSKonstantin Belousov unp_internalize_cleanup_rights(struct mbuf *control) 255747c3450eSKonstantin Belousov { 255847c3450eSKonstantin Belousov struct cmsghdr *cp; 255947c3450eSKonstantin Belousov struct mbuf *m; 256047c3450eSKonstantin Belousov void *data; 256147c3450eSKonstantin Belousov socklen_t datalen; 256247c3450eSKonstantin Belousov 256347c3450eSKonstantin Belousov for (m = control; m != NULL; m = m->m_next) { 256447c3450eSKonstantin Belousov cp = mtod(m, struct cmsghdr *); 256547c3450eSKonstantin Belousov if (cp->cmsg_level != SOL_SOCKET || 256647c3450eSKonstantin Belousov cp->cmsg_type != SCM_RIGHTS) 256747c3450eSKonstantin Belousov continue; 256847c3450eSKonstantin Belousov data = CMSG_DATA(cp); 256947c3450eSKonstantin Belousov datalen = (caddr_t)cp + cp->cmsg_len - (caddr_t)data; 257047c3450eSKonstantin Belousov unp_freerights(data, datalen / sizeof(struct filedesc *)); 257147c3450eSKonstantin Belousov } 257247c3450eSKonstantin Belousov } 257347c3450eSKonstantin Belousov 2574f708ef1bSPoul-Henning Kamp static int 25751093f164SGleb Smirnoff unp_internalize(struct mbuf **controlp, struct thread *td, 25761093f164SGleb Smirnoff struct mbuf **clast, u_int *space, u_int *mbcnt) 2577df8bae1dSRodney W. Grimes { 257847c3450eSKonstantin Belousov struct mbuf *control, **initial_controlp; 257947c3450eSKonstantin Belousov struct proc *p; 258047c3450eSKonstantin Belousov struct filedesc *fdesc; 2581ab15d803SSergey Kandaurov struct bintime *bt; 258247c3450eSKonstantin Belousov struct cmsghdr *cm; 25832bc21ed9SDavid Malone struct cmsgcred *cmcred; 25848cb539f1SPawel Jakub Dawidek struct filedescent *fde, **fdep, *fdev; 25852bc21ed9SDavid Malone struct file *fp; 25862bc21ed9SDavid Malone struct timeval *tv; 2587339efd75SMaxim Sobolev struct timespec *ts; 25882bc21ed9SDavid Malone void *data; 258947c3450eSKonstantin Belousov socklen_t clen, datalen; 2590f1cf2b9dSKonstantin Belousov int i, j, error, *fdp, oldfds; 25918692c025SYoshinobu Inoue u_int newlen; 2592df8bae1dSRodney W. Grimes 25931093f164SGleb Smirnoff MPASS((*controlp)->m_next == NULL); /* COMPAT_OLDSOCK may violate */ 25943dab55bcSRobert Watson UNP_LINK_UNLOCK_ASSERT(); 25954c5bc1caSRobert Watson 259647c3450eSKonstantin Belousov p = td->td_proc; 259747c3450eSKonstantin Belousov fdesc = p->p_fd; 25982bc21ed9SDavid Malone error = 0; 259947c3450eSKonstantin Belousov control = *controlp; 26002bc21ed9SDavid Malone *controlp = NULL; 260147c3450eSKonstantin Belousov initial_controlp = controlp; 2602d97922c6SGleb Smirnoff for (clen = control->m_len, cm = mtod(control, struct cmsghdr *), 26032bc21ed9SDavid Malone data = CMSG_DATA(cm); 26042bc21ed9SDavid Malone 2605d97922c6SGleb Smirnoff clen >= sizeof(*cm) && cm->cmsg_level == SOL_SOCKET && 2606d97922c6SGleb Smirnoff clen >= cm->cmsg_len && cm->cmsg_len >= sizeof(*cm) && 2607d97922c6SGleb Smirnoff (char *)cm + cm->cmsg_len >= (char *)data; 2608d97922c6SGleb Smirnoff 2609d97922c6SGleb Smirnoff clen -= min(CMSG_SPACE(datalen), clen), 2610d97922c6SGleb Smirnoff cm = (struct cmsghdr *) ((char *)cm + CMSG_SPACE(datalen)), 2611d97922c6SGleb Smirnoff data = CMSG_DATA(cm)) { 2612d97922c6SGleb Smirnoff datalen = (char *)cm + cm->cmsg_len - (char *)data; 26132bc21ed9SDavid Malone switch (cm->cmsg_type) { 26142bc21ed9SDavid Malone case SCM_CREDS: 2615b46667c6SGleb Smirnoff *controlp = sbcreatecontrol(NULL, sizeof(*cmcred), 261624df85d2SGleb Smirnoff SCM_CREDS, SOL_SOCKET, M_WAITOK); 26172bc21ed9SDavid Malone cmcred = (struct cmsgcred *) 26182bc21ed9SDavid Malone CMSG_DATA(mtod(*controlp, struct cmsghdr *)); 26190b788fa1SBill Paul cmcred->cmcred_pid = p->p_pid; 2620a854ed98SJohn Baldwin cmcred->cmcred_uid = td->td_ucred->cr_ruid; 2621a854ed98SJohn Baldwin cmcred->cmcred_gid = td->td_ucred->cr_rgid; 2622a854ed98SJohn Baldwin cmcred->cmcred_euid = td->td_ucred->cr_uid; 2623a854ed98SJohn Baldwin cmcred->cmcred_ngroups = MIN(td->td_ucred->cr_ngroups, 26240b788fa1SBill Paul CMGROUP_MAX); 26250b788fa1SBill Paul for (i = 0; i < cmcred->cmcred_ngroups; i++) 26262bc21ed9SDavid Malone cmcred->cmcred_groups[i] = 2627a854ed98SJohn Baldwin td->td_ucred->cr_groups[i]; 26282bc21ed9SDavid Malone break; 26290b788fa1SBill Paul 26302bc21ed9SDavid Malone case SCM_RIGHTS: 26312bc21ed9SDavid Malone oldfds = datalen / sizeof (int); 263282e825c4SGleb Smirnoff if (oldfds == 0) 2633d97922c6SGleb Smirnoff continue; 2634579b45e2SGleb Smirnoff /* On some machines sizeof pointer is bigger than 2635579b45e2SGleb Smirnoff * sizeof int, so we need to check if data fits into 2636579b45e2SGleb Smirnoff * single mbuf. We could allocate several mbufs, and 2637579b45e2SGleb Smirnoff * unp_externalize() should even properly handle that. 2638579b45e2SGleb Smirnoff * But it is not worth to complicate the code for an 2639579b45e2SGleb Smirnoff * insane scenario of passing over 200 file descriptors 2640579b45e2SGleb Smirnoff * at once. 2641579b45e2SGleb Smirnoff */ 2642579b45e2SGleb Smirnoff newlen = oldfds * sizeof(fdep[0]); 2643579b45e2SGleb Smirnoff if (CMSG_SPACE(newlen) > MCLBYTES) { 2644579b45e2SGleb Smirnoff error = EMSGSIZE; 2645579b45e2SGleb Smirnoff goto out; 2646579b45e2SGleb Smirnoff } 2647ed5b7817SJulian Elischer /* 26481c381b19SRobert Watson * Check that all the FDs passed in refer to legal 26491c381b19SRobert Watson * files. If not, reject the entire operation. 2650ed5b7817SJulian Elischer */ 26512bc21ed9SDavid Malone fdp = data; 26522609222aSPawel Jakub Dawidek FILEDESC_SLOCK(fdesc); 26536a1cf96bSMateusz Guzik for (i = 0; i < oldfds; i++, fdp++) { 2654f17ef286SMateusz Guzik fp = fget_noref(fdesc, *fdp); 26556a1cf96bSMateusz Guzik if (fp == NULL) { 26562609222aSPawel Jakub Dawidek FILEDESC_SUNLOCK(fdesc); 26572bc21ed9SDavid Malone error = EBADF; 26582bc21ed9SDavid Malone goto out; 26592bc21ed9SDavid Malone } 2660e7d6662fSAlfred Perlstein if (!(fp->f_ops->fo_flags & DFLAG_PASSABLE)) { 26612609222aSPawel Jakub Dawidek FILEDESC_SUNLOCK(fdesc); 2662e7d6662fSAlfred Perlstein error = EOPNOTSUPP; 2663e7d6662fSAlfred Perlstein goto out; 2664e7d6662fSAlfred Perlstein } 2665df8bae1dSRodney W. Grimes } 26665e3f7694SRobert Watson 2667ed5b7817SJulian Elischer /* 26680b36cd25SRobert Watson * Now replace the integer FDs with pointers to the 26692609222aSPawel Jakub Dawidek * file structure and capability rights. 2670ed5b7817SJulian Elischer */ 2671b46667c6SGleb Smirnoff *controlp = sbcreatecontrol(NULL, newlen, 267224df85d2SGleb Smirnoff SCM_RIGHTS, SOL_SOCKET, M_WAITOK); 26732bc21ed9SDavid Malone fdp = data; 2674f1cf2b9dSKonstantin Belousov for (i = 0; i < oldfds; i++, fdp++) { 2675f1cf2b9dSKonstantin Belousov if (!fhold(fdesc->fd_ofiles[*fdp].fde_file)) { 2676f1cf2b9dSKonstantin Belousov fdp = data; 2677f1cf2b9dSKonstantin Belousov for (j = 0; j < i; j++, fdp++) { 2678f1cf2b9dSKonstantin Belousov fdrop(fdesc->fd_ofiles[*fdp]. 2679f1cf2b9dSKonstantin Belousov fde_file, td); 2680f1cf2b9dSKonstantin Belousov } 2681f1cf2b9dSKonstantin Belousov FILEDESC_SUNLOCK(fdesc); 2682f1cf2b9dSKonstantin Belousov error = EBADF; 2683f1cf2b9dSKonstantin Belousov goto out; 2684f1cf2b9dSKonstantin Belousov } 2685f1cf2b9dSKonstantin Belousov } 2686f1cf2b9dSKonstantin Belousov fdp = data; 26878cb539f1SPawel Jakub Dawidek fdep = (struct filedescent **) 26882bc21ed9SDavid Malone CMSG_DATA(mtod(*controlp, struct cmsghdr *)); 26898cb539f1SPawel Jakub Dawidek fdev = malloc(sizeof(*fdev) * oldfds, M_FILECAPS, 26908cb539f1SPawel Jakub Dawidek M_WAITOK); 26918cb539f1SPawel Jakub Dawidek for (i = 0; i < oldfds; i++, fdev++, fdp++) { 26922609222aSPawel Jakub Dawidek fde = &fdesc->fd_ofiles[*fdp]; 26938cb539f1SPawel Jakub Dawidek fdep[i] = fdev; 26948cb539f1SPawel Jakub Dawidek fdep[i]->fde_file = fde->fde_file; 26958cb539f1SPawel Jakub Dawidek filecaps_copy(&fde->fde_caps, 2696d7832811SMateusz Guzik &fdep[i]->fde_caps, true); 26978cb539f1SPawel Jakub Dawidek unp_internalize_fp(fdep[i]->fde_file); 2698df8bae1dSRodney W. Grimes } 26992609222aSPawel Jakub Dawidek FILEDESC_SUNLOCK(fdesc); 27002bc21ed9SDavid Malone break; 27012bc21ed9SDavid Malone 27022bc21ed9SDavid Malone case SCM_TIMESTAMP: 2703b46667c6SGleb Smirnoff *controlp = sbcreatecontrol(NULL, sizeof(*tv), 270424df85d2SGleb Smirnoff SCM_TIMESTAMP, SOL_SOCKET, M_WAITOK); 27052bc21ed9SDavid Malone tv = (struct timeval *) 27062bc21ed9SDavid Malone CMSG_DATA(mtod(*controlp, struct cmsghdr *)); 27072bc21ed9SDavid Malone microtime(tv); 27082bc21ed9SDavid Malone break; 27092bc21ed9SDavid Malone 2710ab15d803SSergey Kandaurov case SCM_BINTIME: 2711b46667c6SGleb Smirnoff *controlp = sbcreatecontrol(NULL, sizeof(*bt), 271224df85d2SGleb Smirnoff SCM_BINTIME, SOL_SOCKET, M_WAITOK); 2713ab15d803SSergey Kandaurov bt = (struct bintime *) 2714ab15d803SSergey Kandaurov CMSG_DATA(mtod(*controlp, struct cmsghdr *)); 2715ab15d803SSergey Kandaurov bintime(bt); 2716ab15d803SSergey Kandaurov break; 2717ab15d803SSergey Kandaurov 2718339efd75SMaxim Sobolev case SCM_REALTIME: 2719b46667c6SGleb Smirnoff *controlp = sbcreatecontrol(NULL, sizeof(*ts), 272024df85d2SGleb Smirnoff SCM_REALTIME, SOL_SOCKET, M_WAITOK); 2721339efd75SMaxim Sobolev ts = (struct timespec *) 2722339efd75SMaxim Sobolev CMSG_DATA(mtod(*controlp, struct cmsghdr *)); 2723339efd75SMaxim Sobolev nanotime(ts); 2724339efd75SMaxim Sobolev break; 2725339efd75SMaxim Sobolev 2726339efd75SMaxim Sobolev case SCM_MONOTONIC: 2727b46667c6SGleb Smirnoff *controlp = sbcreatecontrol(NULL, sizeof(*ts), 272824df85d2SGleb Smirnoff SCM_MONOTONIC, SOL_SOCKET, M_WAITOK); 2729339efd75SMaxim Sobolev ts = (struct timespec *) 2730339efd75SMaxim Sobolev CMSG_DATA(mtod(*controlp, struct cmsghdr *)); 2731339efd75SMaxim Sobolev nanouptime(ts); 2732339efd75SMaxim Sobolev break; 2733339efd75SMaxim Sobolev 27342bc21ed9SDavid Malone default: 27352bc21ed9SDavid Malone error = EINVAL; 27362bc21ed9SDavid Malone goto out; 27372bc21ed9SDavid Malone } 27382bc21ed9SDavid Malone 27391093f164SGleb Smirnoff if (space != NULL) { 27401093f164SGleb Smirnoff *space += (*controlp)->m_len; 27411093f164SGleb Smirnoff *mbcnt += MSIZE; 27421093f164SGleb Smirnoff if ((*controlp)->m_flags & M_EXT) 27431093f164SGleb Smirnoff *mbcnt += (*controlp)->m_ext.ext_size; 27441093f164SGleb Smirnoff *clast = *controlp; 27451093f164SGleb Smirnoff } 27462bc21ed9SDavid Malone controlp = &(*controlp)->m_next; 27472bc21ed9SDavid Malone } 2748d97922c6SGleb Smirnoff if (clen > 0) 2749d97922c6SGleb Smirnoff error = EINVAL; 27502bc21ed9SDavid Malone 27512bc21ed9SDavid Malone out: 275247c3450eSKonstantin Belousov if (error != 0 && initial_controlp != NULL) 275347c3450eSKonstantin Belousov unp_internalize_cleanup_rights(*initial_controlp); 27542bc21ed9SDavid Malone m_freem(control); 27552bc21ed9SDavid Malone return (error); 2756df8bae1dSRodney W. Grimes } 2757df8bae1dSRodney W. Grimes 27585b950deaSRobert Watson static struct mbuf * 27591093f164SGleb Smirnoff unp_addsockcred(struct thread *td, struct mbuf *control, int mode, 27601093f164SGleb Smirnoff struct mbuf **clast, u_int *space, u_int *mbcnt) 27616a2989fdSMatthew N. Dodd { 276270df31f4SMaxim Konovalov struct mbuf *m, *n, *n_prev; 276370df31f4SMaxim Konovalov const struct cmsghdr *cm; 2764ede4af47SConrad Meyer int ngroups, i, cmsgtype; 2765ede4af47SConrad Meyer size_t ctrlsz; 27666a2989fdSMatthew N. Dodd 27676a2989fdSMatthew N. Dodd ngroups = MIN(td->td_ucred->cr_ngroups, CMGROUP_MAX); 2768ede4af47SConrad Meyer if (mode & UNP_WANTCRED_ALWAYS) { 2769ede4af47SConrad Meyer ctrlsz = SOCKCRED2SIZE(ngroups); 2770ede4af47SConrad Meyer cmsgtype = SCM_CREDS2; 2771ede4af47SConrad Meyer } else { 2772ede4af47SConrad Meyer ctrlsz = SOCKCREDSIZE(ngroups); 2773ede4af47SConrad Meyer cmsgtype = SCM_CREDS; 2774ede4af47SConrad Meyer } 2775ede4af47SConrad Meyer 2776b46667c6SGleb Smirnoff m = sbcreatecontrol(NULL, ctrlsz, cmsgtype, SOL_SOCKET, M_NOWAIT); 27776a2989fdSMatthew N. Dodd if (m == NULL) 27786a2989fdSMatthew N. Dodd return (control); 27791093f164SGleb Smirnoff MPASS((m->m_flags & M_EXT) == 0 && m->m_next == NULL); 27806a2989fdSMatthew N. Dodd 2781ede4af47SConrad Meyer if (mode & UNP_WANTCRED_ALWAYS) { 2782ede4af47SConrad Meyer struct sockcred2 *sc; 2783ede4af47SConrad Meyer 2784ede4af47SConrad Meyer sc = (void *)CMSG_DATA(mtod(m, struct cmsghdr *)); 2785ede4af47SConrad Meyer sc->sc_version = 0; 2786ede4af47SConrad Meyer sc->sc_pid = td->td_proc->p_pid; 27876a2989fdSMatthew N. Dodd sc->sc_uid = td->td_ucred->cr_ruid; 27886a2989fdSMatthew N. Dodd sc->sc_euid = td->td_ucred->cr_uid; 27896a2989fdSMatthew N. Dodd sc->sc_gid = td->td_ucred->cr_rgid; 27906a2989fdSMatthew N. Dodd sc->sc_egid = td->td_ucred->cr_gid; 27916a2989fdSMatthew N. Dodd sc->sc_ngroups = ngroups; 27926a2989fdSMatthew N. Dodd for (i = 0; i < sc->sc_ngroups; i++) 27936a2989fdSMatthew N. Dodd sc->sc_groups[i] = td->td_ucred->cr_groups[i]; 2794ede4af47SConrad Meyer } else { 2795ede4af47SConrad Meyer struct sockcred *sc; 2796ede4af47SConrad Meyer 2797ede4af47SConrad Meyer sc = (void *)CMSG_DATA(mtod(m, struct cmsghdr *)); 2798ede4af47SConrad Meyer sc->sc_uid = td->td_ucred->cr_ruid; 2799ede4af47SConrad Meyer sc->sc_euid = td->td_ucred->cr_uid; 2800ede4af47SConrad Meyer sc->sc_gid = td->td_ucred->cr_rgid; 2801ede4af47SConrad Meyer sc->sc_egid = td->td_ucred->cr_gid; 2802ede4af47SConrad Meyer sc->sc_ngroups = ngroups; 2803ede4af47SConrad Meyer for (i = 0; i < sc->sc_ngroups; i++) 2804ede4af47SConrad Meyer sc->sc_groups[i] = td->td_ucred->cr_groups[i]; 2805ede4af47SConrad Meyer } 28066a2989fdSMatthew N. Dodd 28076a2989fdSMatthew N. Dodd /* 28081c381b19SRobert Watson * Unlink SCM_CREDS control messages (struct cmsgcred), since just 28091c381b19SRobert Watson * created SCM_CREDS control message (struct sockcred) has another 28101c381b19SRobert Watson * format. 28116a2989fdSMatthew N. Dodd */ 2812ede4af47SConrad Meyer if (control != NULL && cmsgtype == SCM_CREDS) 281370df31f4SMaxim Konovalov for (n = control, n_prev = NULL; n != NULL;) { 281470df31f4SMaxim Konovalov cm = mtod(n, struct cmsghdr *); 281570df31f4SMaxim Konovalov if (cm->cmsg_level == SOL_SOCKET && 281670df31f4SMaxim Konovalov cm->cmsg_type == SCM_CREDS) { 281770df31f4SMaxim Konovalov if (n_prev == NULL) 281870df31f4SMaxim Konovalov control = n->m_next; 281970df31f4SMaxim Konovalov else 282070df31f4SMaxim Konovalov n_prev->m_next = n->m_next; 28211093f164SGleb Smirnoff if (space != NULL) { 28221093f164SGleb Smirnoff MPASS(*space >= n->m_len); 28231093f164SGleb Smirnoff *space -= n->m_len; 28241093f164SGleb Smirnoff MPASS(*mbcnt >= MSIZE); 28251093f164SGleb Smirnoff *mbcnt -= MSIZE; 28261093f164SGleb Smirnoff if (n->m_flags & M_EXT) { 28271093f164SGleb Smirnoff MPASS(*mbcnt >= 28281093f164SGleb Smirnoff n->m_ext.ext_size); 28291093f164SGleb Smirnoff *mbcnt -= n->m_ext.ext_size; 28301093f164SGleb Smirnoff } 28311093f164SGleb Smirnoff MPASS(clast); 28321093f164SGleb Smirnoff if (*clast == n) { 28331093f164SGleb Smirnoff MPASS(n->m_next == NULL); 28341093f164SGleb Smirnoff if (n_prev == NULL) 28351093f164SGleb Smirnoff *clast = m; 28361093f164SGleb Smirnoff else 28371093f164SGleb Smirnoff *clast = n_prev; 28381093f164SGleb Smirnoff } 28391093f164SGleb Smirnoff } 284070df31f4SMaxim Konovalov n = m_free(n); 284170df31f4SMaxim Konovalov } else { 284270df31f4SMaxim Konovalov n_prev = n; 284370df31f4SMaxim Konovalov n = n->m_next; 284470df31f4SMaxim Konovalov } 284570df31f4SMaxim Konovalov } 28466a2989fdSMatthew N. Dodd 284770df31f4SMaxim Konovalov /* Prepend it to the head. */ 284870df31f4SMaxim Konovalov m->m_next = control; 28491093f164SGleb Smirnoff if (space != NULL) { 28501093f164SGleb Smirnoff *space += m->m_len; 28511093f164SGleb Smirnoff *mbcnt += MSIZE; 28521093f164SGleb Smirnoff if (control == NULL) 28531093f164SGleb Smirnoff *clast = m; 28541093f164SGleb Smirnoff } 285570df31f4SMaxim Konovalov return (m); 28566a2989fdSMatthew N. Dodd } 28576a2989fdSMatthew N. Dodd 2858397c19d1SJeff Roberson static struct unpcb * 2859397c19d1SJeff Roberson fptounp(struct file *fp) 2860397c19d1SJeff Roberson { 2861397c19d1SJeff Roberson struct socket *so; 2862397c19d1SJeff Roberson 2863397c19d1SJeff Roberson if (fp->f_type != DTYPE_SOCKET) 2864397c19d1SJeff Roberson return (NULL); 2865397c19d1SJeff Roberson if ((so = fp->f_data) == NULL) 2866397c19d1SJeff Roberson return (NULL); 2867397c19d1SJeff Roberson if (so->so_proto->pr_domain != &localdomain) 2868397c19d1SJeff Roberson return (NULL); 2869397c19d1SJeff Roberson return sotounpcb(so); 2870397c19d1SJeff Roberson } 2871397c19d1SJeff Roberson 2872397c19d1SJeff Roberson static void 2873397c19d1SJeff Roberson unp_discard(struct file *fp) 2874397c19d1SJeff Roberson { 28750cb64678SKonstantin Belousov struct unp_defer *dr; 2876397c19d1SJeff Roberson 28770cb64678SKonstantin Belousov if (unp_externalize_fp(fp)) { 28780cb64678SKonstantin Belousov dr = malloc(sizeof(*dr), M_TEMP, M_WAITOK); 28790cb64678SKonstantin Belousov dr->ud_fp = fp; 28800cb64678SKonstantin Belousov UNP_DEFERRED_LOCK(); 28810cb64678SKonstantin Belousov SLIST_INSERT_HEAD(&unp_defers, dr, ud_link); 28820cb64678SKonstantin Belousov UNP_DEFERRED_UNLOCK(); 28830cb64678SKonstantin Belousov atomic_add_int(&unp_defers_count, 1); 28840cb64678SKonstantin Belousov taskqueue_enqueue(taskqueue_thread, &unp_defer_task); 28850cb64678SKonstantin Belousov } else 28864faa375cSMateusz Guzik closef_nothread(fp); 2887397c19d1SJeff Roberson } 2888397c19d1SJeff Roberson 2889397c19d1SJeff Roberson static void 28900cb64678SKonstantin Belousov unp_process_defers(void *arg __unused, int pending) 28910cb64678SKonstantin Belousov { 28920cb64678SKonstantin Belousov struct unp_defer *dr; 28930cb64678SKonstantin Belousov SLIST_HEAD(, unp_defer) drl; 28940cb64678SKonstantin Belousov int count; 28950cb64678SKonstantin Belousov 28960cb64678SKonstantin Belousov SLIST_INIT(&drl); 28970cb64678SKonstantin Belousov for (;;) { 28980cb64678SKonstantin Belousov UNP_DEFERRED_LOCK(); 28990cb64678SKonstantin Belousov if (SLIST_FIRST(&unp_defers) == NULL) { 29000cb64678SKonstantin Belousov UNP_DEFERRED_UNLOCK(); 29010cb64678SKonstantin Belousov break; 29020cb64678SKonstantin Belousov } 29030cb64678SKonstantin Belousov SLIST_SWAP(&unp_defers, &drl, unp_defer); 29040cb64678SKonstantin Belousov UNP_DEFERRED_UNLOCK(); 29050cb64678SKonstantin Belousov count = 0; 29060cb64678SKonstantin Belousov while ((dr = SLIST_FIRST(&drl)) != NULL) { 29070cb64678SKonstantin Belousov SLIST_REMOVE_HEAD(&drl, ud_link); 29084faa375cSMateusz Guzik closef_nothread(dr->ud_fp); 29090cb64678SKonstantin Belousov free(dr, M_TEMP); 29100cb64678SKonstantin Belousov count++; 29110cb64678SKonstantin Belousov } 29120cb64678SKonstantin Belousov atomic_add_int(&unp_defers_count, -count); 29130cb64678SKonstantin Belousov } 29140cb64678SKonstantin Belousov } 29150cb64678SKonstantin Belousov 29160cb64678SKonstantin Belousov static void 2917397c19d1SJeff Roberson unp_internalize_fp(struct file *fp) 2918397c19d1SJeff Roberson { 2919397c19d1SJeff Roberson struct unpcb *unp; 2920397c19d1SJeff Roberson 29213dab55bcSRobert Watson UNP_LINK_WLOCK(); 2922397c19d1SJeff Roberson if ((unp = fptounp(fp)) != NULL) { 2923397c19d1SJeff Roberson unp->unp_file = fp; 2924397c19d1SJeff Roberson unp->unp_msgcount++; 2925397c19d1SJeff Roberson } 2926397c19d1SJeff Roberson unp_rights++; 29273dab55bcSRobert Watson UNP_LINK_WUNLOCK(); 2928397c19d1SJeff Roberson } 2929397c19d1SJeff Roberson 29300cb64678SKonstantin Belousov static int 2931397c19d1SJeff Roberson unp_externalize_fp(struct file *fp) 2932397c19d1SJeff Roberson { 2933397c19d1SJeff Roberson struct unpcb *unp; 29340cb64678SKonstantin Belousov int ret; 2935397c19d1SJeff Roberson 29363dab55bcSRobert Watson UNP_LINK_WLOCK(); 29370cb64678SKonstantin Belousov if ((unp = fptounp(fp)) != NULL) { 2938397c19d1SJeff Roberson unp->unp_msgcount--; 29390cb64678SKonstantin Belousov ret = 1; 29400cb64678SKonstantin Belousov } else 29410cb64678SKonstantin Belousov ret = 0; 2942397c19d1SJeff Roberson unp_rights--; 29433dab55bcSRobert Watson UNP_LINK_WUNLOCK(); 29440cb64678SKonstantin Belousov return (ret); 2945397c19d1SJeff Roberson } 2946397c19d1SJeff Roberson 2947161a0c7cSRobert Watson /* 2948a0ec558aSRobert Watson * unp_defer indicates whether additional work has been defered for a future 2949a0ec558aSRobert Watson * pass through unp_gc(). It is thread local and does not require explicit 2950a0ec558aSRobert Watson * synchronization. 2951161a0c7cSRobert Watson */ 2952397c19d1SJeff Roberson static int unp_marked; 2953a0ec558aSRobert Watson 2954397c19d1SJeff Roberson static void 2955a9aa06f7SJason A. Harmening unp_remove_dead_ref(struct filedescent **fdep, int fdcount) 2956397c19d1SJeff Roberson { 2957397c19d1SJeff Roberson struct unpcb *unp; 2958be26ba7cSPawel Jakub Dawidek struct file *fp; 2959be26ba7cSPawel Jakub Dawidek int i; 2960397c19d1SJeff Roberson 2961a9aa06f7SJason A. Harmening /* 2962a9aa06f7SJason A. Harmening * This function can only be called from the gc task. 2963a9aa06f7SJason A. Harmening */ 2964a9aa06f7SJason A. Harmening KASSERT(taskqueue_member(taskqueue_thread, curthread) != 0, 2965a9aa06f7SJason A. Harmening ("%s: not on gc callout", __func__)); 2966a9aa06f7SJason A. Harmening UNP_LINK_LOCK_ASSERT(); 2967a9aa06f7SJason A. Harmening 2968be26ba7cSPawel Jakub Dawidek for (i = 0; i < fdcount; i++) { 2969be26ba7cSPawel Jakub Dawidek fp = fdep[i]->fde_file; 29706f552cb0SJeff Roberson if ((unp = fptounp(fp)) == NULL) 2971be26ba7cSPawel Jakub Dawidek continue; 2972a9aa06f7SJason A. Harmening if ((unp->unp_gcflag & UNPGC_DEAD) == 0) 2973be26ba7cSPawel Jakub Dawidek continue; 2974a9aa06f7SJason A. Harmening unp->unp_gcrefs--; 2975a9aa06f7SJason A. Harmening } 2976a9aa06f7SJason A. Harmening } 2977a9aa06f7SJason A. Harmening 2978a9aa06f7SJason A. Harmening static void 2979a9aa06f7SJason A. Harmening unp_restore_undead_ref(struct filedescent **fdep, int fdcount) 2980a9aa06f7SJason A. Harmening { 2981a9aa06f7SJason A. Harmening struct unpcb *unp; 2982a9aa06f7SJason A. Harmening struct file *fp; 2983a9aa06f7SJason A. Harmening int i; 2984a9aa06f7SJason A. Harmening 2985a9aa06f7SJason A. Harmening /* 2986a9aa06f7SJason A. Harmening * This function can only be called from the gc task. 2987a9aa06f7SJason A. Harmening */ 2988a9aa06f7SJason A. Harmening KASSERT(taskqueue_member(taskqueue_thread, curthread) != 0, 2989a9aa06f7SJason A. Harmening ("%s: not on gc callout", __func__)); 2990a9aa06f7SJason A. Harmening UNP_LINK_LOCK_ASSERT(); 2991a9aa06f7SJason A. Harmening 2992a9aa06f7SJason A. Harmening for (i = 0; i < fdcount; i++) { 2993a9aa06f7SJason A. Harmening fp = fdep[i]->fde_file; 2994a9aa06f7SJason A. Harmening if ((unp = fptounp(fp)) == NULL) 2995a9aa06f7SJason A. Harmening continue; 2996a9aa06f7SJason A. Harmening if ((unp->unp_gcflag & UNPGC_DEAD) == 0) 2997a9aa06f7SJason A. Harmening continue; 2998a9aa06f7SJason A. Harmening unp->unp_gcrefs++; 2999397c19d1SJeff Roberson unp_marked++; 3000397c19d1SJeff Roberson } 3001be26ba7cSPawel Jakub Dawidek } 3002397c19d1SJeff Roberson 3003397c19d1SJeff Roberson static void 3004a7444f80SGleb Smirnoff unp_scan_socket(struct socket *so, void (*op)(struct filedescent **, int)) 3005a7444f80SGleb Smirnoff { 3006458f475dSGleb Smirnoff struct sockbuf *sb; 3007a7444f80SGleb Smirnoff 3008a7444f80SGleb Smirnoff SOCK_LOCK_ASSERT(so); 3009a7444f80SGleb Smirnoff 3010a7444f80SGleb Smirnoff if (sotounpcb(so)->unp_gcflag & UNPGC_IGNORE_RIGHTS) 3011a7444f80SGleb Smirnoff return; 3012a7444f80SGleb Smirnoff 3013a7444f80SGleb Smirnoff SOCK_RECVBUF_LOCK(so); 3014a7444f80SGleb Smirnoff switch (so->so_type) { 3015a7444f80SGleb Smirnoff case SOCK_DGRAM: 3016a7444f80SGleb Smirnoff unp_scan(STAILQ_FIRST(&so->so_rcv.uxdg_mb), op); 3017458f475dSGleb Smirnoff unp_scan(so->so_rcv.uxdg_peeked, op); 3018458f475dSGleb Smirnoff TAILQ_FOREACH(sb, &so->so_rcv.uxdg_conns, uxdg_clist) 3019458f475dSGleb Smirnoff unp_scan(STAILQ_FIRST(&sb->uxdg_mb), op); 3020a7444f80SGleb Smirnoff break; 3021a7444f80SGleb Smirnoff case SOCK_STREAM: 3022a7444f80SGleb Smirnoff case SOCK_SEQPACKET: 3023a7444f80SGleb Smirnoff unp_scan(so->so_rcv.sb_mb, op); 3024a7444f80SGleb Smirnoff break; 3025a7444f80SGleb Smirnoff } 3026a7444f80SGleb Smirnoff SOCK_RECVBUF_UNLOCK(so); 3027a7444f80SGleb Smirnoff } 3028a7444f80SGleb Smirnoff 3029a7444f80SGleb Smirnoff static void 3030a9aa06f7SJason A. Harmening unp_gc_scan(struct unpcb *unp, void (*op)(struct filedescent **, int)) 3031397c19d1SJeff Roberson { 3032779f106aSGleb Smirnoff struct socket *so, *soa; 303360a5ef26SRobert Watson 3034397c19d1SJeff Roberson so = unp->unp_socket; 3035779f106aSGleb Smirnoff SOCK_LOCK(so); 3036779f106aSGleb Smirnoff if (SOLISTENING(so)) { 3037397c19d1SJeff Roberson /* 3038397c19d1SJeff Roberson * Mark all sockets in our accept queue. 3039397c19d1SJeff Roberson */ 3040a7444f80SGleb Smirnoff TAILQ_FOREACH(soa, &so->sol_comp, so_list) 3041a7444f80SGleb Smirnoff unp_scan_socket(soa, op); 3042779f106aSGleb Smirnoff } else { 3043779f106aSGleb Smirnoff /* 3044779f106aSGleb Smirnoff * Mark all sockets we reference with RIGHTS. 3045779f106aSGleb Smirnoff */ 3046a7444f80SGleb Smirnoff unp_scan_socket(so, op); 3047779f106aSGleb Smirnoff } 3048779f106aSGleb Smirnoff SOCK_UNLOCK(so); 3049397c19d1SJeff Roberson } 3050a0ec558aSRobert Watson 3051a0ec558aSRobert Watson static int unp_recycled; 3052be6b1304STom Rhodes SYSCTL_INT(_net_local, OID_AUTO, recycled, CTLFLAG_RD, &unp_recycled, 0, 3053be6b1304STom Rhodes "Number of unreachable sockets claimed by the garbage collector."); 3054df8bae1dSRodney W. Grimes 3055397c19d1SJeff Roberson static int unp_taskcount; 3056be6b1304STom Rhodes SYSCTL_INT(_net_local, OID_AUTO, taskcount, CTLFLAG_RD, &unp_taskcount, 0, 3057be6b1304STom Rhodes "Number of times the garbage collector has run."); 3058397c19d1SJeff Roberson 3059a9aa06f7SJason A. Harmening SYSCTL_UINT(_net_local, OID_AUTO, sockcount, CTLFLAG_RD, &unp_count, 0, 3060a9aa06f7SJason A. Harmening "Number of active local sockets."); 3061a9aa06f7SJason A. Harmening 3062f708ef1bSPoul-Henning Kamp static void 3063a0ec558aSRobert Watson unp_gc(__unused void *arg, int pending) 3064df8bae1dSRodney W. Grimes { 306584d61770SRobert Watson struct unp_head *heads[] = { &unp_dhead, &unp_shead, &unp_sphead, 306684d61770SRobert Watson NULL }; 3067397c19d1SJeff Roberson struct unp_head **head; 3068a9aa06f7SJason A. Harmening struct unp_head unp_deadhead; /* List of potentially-dead sockets. */ 3069f7780c61SKonstantin Belousov struct file *f, **unref; 3070a9aa06f7SJason A. Harmening struct unpcb *unp, *unptmp; 3071a9aa06f7SJason A. Harmening int i, total, unp_unreachable; 3072df8bae1dSRodney W. Grimes 3073a9aa06f7SJason A. Harmening LIST_INIT(&unp_deadhead); 3074a0ec558aSRobert Watson unp_taskcount++; 3075779f106aSGleb Smirnoff UNP_LINK_RLOCK(); 3076ed5b7817SJulian Elischer /* 3077a9aa06f7SJason A. Harmening * First determine which sockets may be in cycles. 3078ed5b7817SJulian Elischer */ 3079a9aa06f7SJason A. Harmening unp_unreachable = 0; 3080a9aa06f7SJason A. Harmening 3081397c19d1SJeff Roberson for (head = heads; *head != NULL; head++) 3082a9aa06f7SJason A. Harmening LIST_FOREACH(unp, *head, unp_link) { 3083a9aa06f7SJason A. Harmening KASSERT((unp->unp_gcflag & ~UNPGC_IGNORE_RIGHTS) == 0, 3084a9aa06f7SJason A. Harmening ("%s: unp %p has unexpected gc flags 0x%x", 3085a9aa06f7SJason A. Harmening __func__, unp, (unsigned int)unp->unp_gcflag)); 3086a9aa06f7SJason A. Harmening 3087a9aa06f7SJason A. Harmening f = unp->unp_file; 308860a5ef26SRobert Watson 3089397c19d1SJeff Roberson /* 3090a9aa06f7SJason A. Harmening * Check for an unreachable socket potentially in a 3091a9aa06f7SJason A. Harmening * cycle. It must be in a queue as indicated by 3092a9aa06f7SJason A. Harmening * msgcount, and this must equal the file reference 3093a9aa06f7SJason A. Harmening * count. Note that when msgcount is 0 the file is 3094a9aa06f7SJason A. Harmening * NULL. 3095a9aa06f7SJason A. Harmening */ 3096a9aa06f7SJason A. Harmening if (f != NULL && unp->unp_msgcount != 0 && 30973c50616fSMateusz Guzik refcount_load(&f->f_count) == unp->unp_msgcount) { 3098a9aa06f7SJason A. Harmening LIST_INSERT_HEAD(&unp_deadhead, unp, unp_dead); 3099a9aa06f7SJason A. Harmening unp->unp_gcflag |= UNPGC_DEAD; 3100a9aa06f7SJason A. Harmening unp->unp_gcrefs = unp->unp_msgcount; 3101a9aa06f7SJason A. Harmening unp_unreachable++; 3102a9aa06f7SJason A. Harmening } 3103a9aa06f7SJason A. Harmening } 3104a9aa06f7SJason A. Harmening 3105a9aa06f7SJason A. Harmening /* 3106a9aa06f7SJason A. Harmening * Scan all sockets previously marked as potentially being in a cycle 3107a9aa06f7SJason A. Harmening * and remove the references each socket holds on any UNPGC_DEAD 3108a9aa06f7SJason A. Harmening * sockets in its queue. After this step, all remaining references on 3109a9aa06f7SJason A. Harmening * sockets marked UNPGC_DEAD should not be part of any cycle. 3110a9aa06f7SJason A. Harmening */ 3111a9aa06f7SJason A. Harmening LIST_FOREACH(unp, &unp_deadhead, unp_dead) 3112a9aa06f7SJason A. Harmening unp_gc_scan(unp, unp_remove_dead_ref); 3113a9aa06f7SJason A. Harmening 3114a9aa06f7SJason A. Harmening /* 3115a9aa06f7SJason A. Harmening * If a socket still has a non-negative refcount, it cannot be in a 3116a9aa06f7SJason A. Harmening * cycle. In this case increment refcount of all children iteratively. 3117397c19d1SJeff Roberson * Stop the scan once we do a complete loop without discovering 3118397c19d1SJeff Roberson * a new reachable socket. 3119397c19d1SJeff Roberson */ 3120df8bae1dSRodney W. Grimes do { 3121397c19d1SJeff Roberson unp_marked = 0; 3122a9aa06f7SJason A. Harmening LIST_FOREACH_SAFE(unp, &unp_deadhead, unp_dead, unptmp) 3123a9aa06f7SJason A. Harmening if (unp->unp_gcrefs > 0) { 3124a9aa06f7SJason A. Harmening unp->unp_gcflag &= ~UNPGC_DEAD; 3125a9aa06f7SJason A. Harmening LIST_REMOVE(unp, unp_dead); 3126a9aa06f7SJason A. Harmening KASSERT(unp_unreachable > 0, 3127a9aa06f7SJason A. Harmening ("%s: unp_unreachable underflow.", 3128a9aa06f7SJason A. Harmening __func__)); 3129a9aa06f7SJason A. Harmening unp_unreachable--; 3130a9aa06f7SJason A. Harmening unp_gc_scan(unp, unp_restore_undead_ref); 3131a9aa06f7SJason A. Harmening } 3132397c19d1SJeff Roberson } while (unp_marked); 3133a9aa06f7SJason A. Harmening 3134779f106aSGleb Smirnoff UNP_LINK_RUNLOCK(); 3135a9aa06f7SJason A. Harmening 3136397c19d1SJeff Roberson if (unp_unreachable == 0) 3137397c19d1SJeff Roberson return; 313860a5ef26SRobert Watson 3139ed5b7817SJulian Elischer /* 3140a9aa06f7SJason A. Harmening * Allocate space for a local array of dead unpcbs. 3141a9aa06f7SJason A. Harmening * TODO: can this path be simplified by instead using the local 3142a9aa06f7SJason A. Harmening * dead list at unp_deadhead, after taking out references 3143a9aa06f7SJason A. Harmening * on the file object and/or unpcb and dropping the link lock? 3144ed5b7817SJulian Elischer */ 3145397c19d1SJeff Roberson unref = malloc(unp_unreachable * sizeof(struct file *), 3146397c19d1SJeff Roberson M_TEMP, M_WAITOK); 314760a5ef26SRobert Watson 3148ed5b7817SJulian Elischer /* 3149397c19d1SJeff Roberson * Iterate looking for sockets which have been specifically marked 3150a9aa06f7SJason A. Harmening * as unreachable and store them locally. 3151ed5b7817SJulian Elischer */ 3152f7780c61SKonstantin Belousov UNP_LINK_RLOCK(); 3153a9aa06f7SJason A. Harmening total = 0; 3154a9aa06f7SJason A. Harmening LIST_FOREACH(unp, &unp_deadhead, unp_dead) { 3155a9aa06f7SJason A. Harmening KASSERT((unp->unp_gcflag & UNPGC_DEAD) != 0, 3156a9aa06f7SJason A. Harmening ("%s: unp %p not marked UNPGC_DEAD", __func__, unp)); 3157a9aa06f7SJason A. Harmening unp->unp_gcflag &= ~UNPGC_DEAD; 3158f7780c61SKonstantin Belousov f = unp->unp_file; 3159f7780c61SKonstantin Belousov if (unp->unp_msgcount == 0 || f == NULL || 31603c50616fSMateusz Guzik refcount_load(&f->f_count) != unp->unp_msgcount || 3161f1cf2b9dSKonstantin Belousov !fhold(f)) 3162f7780c61SKonstantin Belousov continue; 3163f7780c61SKonstantin Belousov unref[total++] = f; 3164f7780c61SKonstantin Belousov KASSERT(total <= unp_unreachable, 3165a9aa06f7SJason A. Harmening ("%s: incorrect unreachable count.", __func__)); 3166397c19d1SJeff Roberson } 3167f7780c61SKonstantin Belousov UNP_LINK_RUNLOCK(); 316860a5ef26SRobert Watson 3169ed5b7817SJulian Elischer /* 3170397c19d1SJeff Roberson * Now flush all sockets, free'ing rights. This will free the 3171397c19d1SJeff Roberson * struct files associated with these sockets but leave each socket 3172397c19d1SJeff Roberson * with one remaining ref. 3173ed5b7817SJulian Elischer */ 31741fb51a12SBjoern A. Zeeb for (i = 0; i < total; i++) { 31751fb51a12SBjoern A. Zeeb struct socket *so; 31761fb51a12SBjoern A. Zeeb 31771fb51a12SBjoern A. Zeeb so = unref[i]->f_data; 31781fb51a12SBjoern A. Zeeb CURVNET_SET(so->so_vnet); 31791fb51a12SBjoern A. Zeeb sorflush(so); 31801fb51a12SBjoern A. Zeeb CURVNET_RESTORE(); 31811fb51a12SBjoern A. Zeeb } 318260a5ef26SRobert Watson 3183ed5b7817SJulian Elischer /* 3184397c19d1SJeff Roberson * And finally release the sockets so they can be reclaimed. 3185ed5b7817SJulian Elischer */ 3186f7780c61SKonstantin Belousov for (i = 0; i < total; i++) 3187397c19d1SJeff Roberson fdrop(unref[i], NULL); 3188f7780c61SKonstantin Belousov unp_recycled += total; 3189397c19d1SJeff Roberson free(unref, M_TEMP); 3190df8bae1dSRodney W. Grimes } 3191df8bae1dSRodney W. Grimes 31920c40f353SConrad Meyer /* 31930c40f353SConrad Meyer * Synchronize against unp_gc, which can trip over data as we are freeing it. 31940c40f353SConrad Meyer */ 31950c40f353SConrad Meyer static void 319699ab95dbSMark Johnston unp_dispose(struct socket *so) 31970c40f353SConrad Meyer { 3198458f475dSGleb Smirnoff struct sockbuf *sb; 31990c40f353SConrad Meyer struct unpcb *unp; 3200a982ce04SGleb Smirnoff struct mbuf *m; 32010c40f353SConrad Meyer 320242f2fa99SGleb Smirnoff MPASS(!SOLISTENING(so)); 320342f2fa99SGleb Smirnoff 32040c40f353SConrad Meyer unp = sotounpcb(so); 3205779f106aSGleb Smirnoff UNP_LINK_WLOCK(); 32060c40f353SConrad Meyer unp->unp_gcflag |= UNPGC_IGNORE_RIGHTS; 3207779f106aSGleb Smirnoff UNP_LINK_WUNLOCK(); 3208a982ce04SGleb Smirnoff 3209a982ce04SGleb Smirnoff /* 3210a982ce04SGleb Smirnoff * Grab our special mbufs before calling sbrelease(). 3211a982ce04SGleb Smirnoff */ 3212a982ce04SGleb Smirnoff SOCK_RECVBUF_LOCK(so); 3213a7444f80SGleb Smirnoff switch (so->so_type) { 3214a7444f80SGleb Smirnoff case SOCK_DGRAM: 3215458f475dSGleb Smirnoff while ((sb = TAILQ_FIRST(&so->so_rcv.uxdg_conns)) != NULL) { 3216458f475dSGleb Smirnoff STAILQ_CONCAT(&so->so_rcv.uxdg_mb, &sb->uxdg_mb); 3217458f475dSGleb Smirnoff TAILQ_REMOVE(&so->so_rcv.uxdg_conns, sb, uxdg_clist); 3218458f475dSGleb Smirnoff /* Note: socket of sb may reconnect. */ 3219458f475dSGleb Smirnoff sb->uxdg_cc = sb->uxdg_ctl = sb->uxdg_mbcnt = 0; 3220458f475dSGleb Smirnoff } 3221458f475dSGleb Smirnoff sb = &so->so_rcv; 3222458f475dSGleb Smirnoff if (sb->uxdg_peeked != NULL) { 3223458f475dSGleb Smirnoff STAILQ_INSERT_HEAD(&sb->uxdg_mb, sb->uxdg_peeked, 3224458f475dSGleb Smirnoff m_stailqpkt); 3225458f475dSGleb Smirnoff sb->uxdg_peeked = NULL; 3226458f475dSGleb Smirnoff } 3227a7444f80SGleb Smirnoff m = STAILQ_FIRST(&sb->uxdg_mb); 3228a7444f80SGleb Smirnoff STAILQ_INIT(&sb->uxdg_mb); 3229a7444f80SGleb Smirnoff /* XXX: our shortened sbrelease() */ 3230a7444f80SGleb Smirnoff (void)chgsbsize(so->so_cred->cr_uidinfo, &sb->sb_hiwat, 0, 3231a7444f80SGleb Smirnoff RLIM_INFINITY); 3232458f475dSGleb Smirnoff /* 3233458f475dSGleb Smirnoff * XXXGL Mark sb with SBS_CANTRCVMORE. This is needed to 3234458f475dSGleb Smirnoff * prevent uipc_sosend_dgram() or unp_disconnect() adding more 3235458f475dSGleb Smirnoff * data to the socket. 3236458f475dSGleb Smirnoff * We are now in dom_dispose and it could be a call from 3237458f475dSGleb Smirnoff * soshutdown() or from the final sofree(). The sofree() case 3238458f475dSGleb Smirnoff * is simple as it guarantees that no more sends will happen, 3239458f475dSGleb Smirnoff * however we can race with unp_disconnect() from our peer. 3240458f475dSGleb Smirnoff * The shutdown(2) case is more exotic. It would call into 3241458f475dSGleb Smirnoff * dom_dispose() only if socket is SS_ISCONNECTED. This is 3242458f475dSGleb Smirnoff * possible if we did connect(2) on this socket and we also 3243458f475dSGleb Smirnoff * had it bound with bind(2) and receive connections from other 3244458f475dSGleb Smirnoff * sockets. Because soshutdown() violates POSIX (see comment 3245458f475dSGleb Smirnoff * there) we will end up here shutting down our receive side. 3246458f475dSGleb Smirnoff * Of course this will have affect not only on the peer we 3247458f475dSGleb Smirnoff * connect(2)ed to, but also on all of the peers who had 3248458f475dSGleb Smirnoff * connect(2)ed to us. Their sends would end up with ENOBUFS. 3249458f475dSGleb Smirnoff */ 3250458f475dSGleb Smirnoff sb->sb_state |= SBS_CANTRCVMORE; 3251a7444f80SGleb Smirnoff break; 3252a7444f80SGleb Smirnoff case SOCK_STREAM: 3253a7444f80SGleb Smirnoff case SOCK_SEQPACKET: 3254458f475dSGleb Smirnoff sb = &so->so_rcv; 3255a982ce04SGleb Smirnoff m = sbcut_locked(sb, sb->sb_ccc); 3256a982ce04SGleb Smirnoff KASSERT(sb->sb_ccc == 0 && sb->sb_mb == 0 && sb->sb_mbcnt == 0, 3257a982ce04SGleb Smirnoff ("%s: ccc %u mb %p mbcnt %u", __func__, 3258a982ce04SGleb Smirnoff sb->sb_ccc, (void *)sb->sb_mb, sb->sb_mbcnt)); 325943283184SGleb Smirnoff sbrelease_locked(so, SO_RCV); 3260a7444f80SGleb Smirnoff break; 3261a7444f80SGleb Smirnoff } 3262a982ce04SGleb Smirnoff SOCK_RECVBUF_UNLOCK(so); 3263a982ce04SGleb Smirnoff if (SOCK_IO_RECV_OWNED(so)) 3264a982ce04SGleb Smirnoff SOCK_IO_RECV_UNLOCK(so); 3265a982ce04SGleb Smirnoff 32662e5bf7c4SGleb Smirnoff if (m != NULL) { 3267eac7f079SGleb Smirnoff unp_scan(m, unp_freerights); 32682e5bf7c4SGleb Smirnoff m_freem(m); 32692e5bf7c4SGleb Smirnoff } 32700c40f353SConrad Meyer } 32710c40f353SConrad Meyer 3272f708ef1bSPoul-Henning Kamp static void 3273be26ba7cSPawel Jakub Dawidek unp_scan(struct mbuf *m0, void (*op)(struct filedescent **, int)) 3274df8bae1dSRodney W. Grimes { 32752bc21ed9SDavid Malone struct mbuf *m; 32762bc21ed9SDavid Malone struct cmsghdr *cm; 32772bc21ed9SDavid Malone void *data; 32782bc21ed9SDavid Malone socklen_t clen, datalen; 3279df8bae1dSRodney W. Grimes 3280fc3fcacfSRobert Watson while (m0 != NULL) { 32812bc21ed9SDavid Malone for (m = m0; m; m = m->m_next) { 328212396bdcSDavid Malone if (m->m_type != MT_CONTROL) 3283df8bae1dSRodney W. Grimes continue; 32842bc21ed9SDavid Malone 32852bc21ed9SDavid Malone cm = mtod(m, struct cmsghdr *); 32862bc21ed9SDavid Malone clen = m->m_len; 32872bc21ed9SDavid Malone 32882bc21ed9SDavid Malone while (cm != NULL) { 32892bc21ed9SDavid Malone if (sizeof(*cm) > clen || cm->cmsg_len > clen) 32902bc21ed9SDavid Malone break; 32912bc21ed9SDavid Malone 32922bc21ed9SDavid Malone data = CMSG_DATA(cm); 32932bc21ed9SDavid Malone datalen = (caddr_t)cm + cm->cmsg_len 32942bc21ed9SDavid Malone - (caddr_t)data; 32952bc21ed9SDavid Malone 32962bc21ed9SDavid Malone if (cm->cmsg_level == SOL_SOCKET && 32972bc21ed9SDavid Malone cm->cmsg_type == SCM_RIGHTS) { 3298be26ba7cSPawel Jakub Dawidek (*op)(data, datalen / 3299be26ba7cSPawel Jakub Dawidek sizeof(struct filedescent *)); 33002bc21ed9SDavid Malone } 33012bc21ed9SDavid Malone 33022bc21ed9SDavid Malone if (CMSG_SPACE(datalen) < clen) { 33032bc21ed9SDavid Malone clen -= CMSG_SPACE(datalen); 33042bc21ed9SDavid Malone cm = (struct cmsghdr *) 33052bc21ed9SDavid Malone ((caddr_t)cm + CMSG_SPACE(datalen)); 33062bc21ed9SDavid Malone } else { 33072bc21ed9SDavid Malone clen = 0; 33082bc21ed9SDavid Malone cm = NULL; 33092bc21ed9SDavid Malone } 33102bc21ed9SDavid Malone } 3311df8bae1dSRodney W. Grimes } 3312c29a3321SKevin Lo m0 = m0->m_nextpkt; 3313df8bae1dSRodney W. Grimes } 3314df8bae1dSRodney W. Grimes } 3315df8bae1dSRodney W. Grimes 3316662c901cSMikolaj Golub /* 3317e7d02be1SGleb Smirnoff * Definitions of protocols supported in the LOCAL domain. 3318e7d02be1SGleb Smirnoff */ 3319e7d02be1SGleb Smirnoff static struct protosw streamproto = { 3320e7d02be1SGleb Smirnoff .pr_type = SOCK_STREAM, 3321e7d02be1SGleb Smirnoff .pr_flags = PR_CONNREQUIRED|PR_WANTRCVD|PR_RIGHTS| 3322e7d02be1SGleb Smirnoff PR_CAPATTACH, 3323e7d02be1SGleb Smirnoff .pr_ctloutput = &uipc_ctloutput, 3324e7d02be1SGleb Smirnoff .pr_abort = uipc_abort, 3325e7d02be1SGleb Smirnoff .pr_accept = uipc_accept, 3326e7d02be1SGleb Smirnoff .pr_attach = uipc_attach, 3327e7d02be1SGleb Smirnoff .pr_bind = uipc_bind, 3328e7d02be1SGleb Smirnoff .pr_bindat = uipc_bindat, 3329e7d02be1SGleb Smirnoff .pr_connect = uipc_connect, 3330e7d02be1SGleb Smirnoff .pr_connectat = uipc_connectat, 3331e7d02be1SGleb Smirnoff .pr_connect2 = uipc_connect2, 3332e7d02be1SGleb Smirnoff .pr_detach = uipc_detach, 3333e7d02be1SGleb Smirnoff .pr_disconnect = uipc_disconnect, 3334e7d02be1SGleb Smirnoff .pr_listen = uipc_listen, 3335e7d02be1SGleb Smirnoff .pr_peeraddr = uipc_peeraddr, 3336e7d02be1SGleb Smirnoff .pr_rcvd = uipc_rcvd, 3337e7d02be1SGleb Smirnoff .pr_send = uipc_send, 3338e7d02be1SGleb Smirnoff .pr_ready = uipc_ready, 3339e7d02be1SGleb Smirnoff .pr_sense = uipc_sense, 3340e7d02be1SGleb Smirnoff .pr_shutdown = uipc_shutdown, 3341e7d02be1SGleb Smirnoff .pr_sockaddr = uipc_sockaddr, 3342e7d02be1SGleb Smirnoff .pr_soreceive = soreceive_generic, 3343e7d02be1SGleb Smirnoff .pr_close = uipc_close, 3344e7d02be1SGleb Smirnoff }; 3345e7d02be1SGleb Smirnoff 3346e7d02be1SGleb Smirnoff static struct protosw dgramproto = { 3347e7d02be1SGleb Smirnoff .pr_type = SOCK_DGRAM, 3348e7d02be1SGleb Smirnoff .pr_flags = PR_ATOMIC | PR_ADDR |PR_RIGHTS | PR_CAPATTACH | 3349e7d02be1SGleb Smirnoff PR_SOCKBUF, 3350e7d02be1SGleb Smirnoff .pr_ctloutput = &uipc_ctloutput, 3351e7d02be1SGleb Smirnoff .pr_abort = uipc_abort, 3352e7d02be1SGleb Smirnoff .pr_accept = uipc_accept, 3353e7d02be1SGleb Smirnoff .pr_attach = uipc_attach, 3354e7d02be1SGleb Smirnoff .pr_bind = uipc_bind, 3355e7d02be1SGleb Smirnoff .pr_bindat = uipc_bindat, 3356e7d02be1SGleb Smirnoff .pr_connect = uipc_connect, 3357e7d02be1SGleb Smirnoff .pr_connectat = uipc_connectat, 3358e7d02be1SGleb Smirnoff .pr_connect2 = uipc_connect2, 3359e7d02be1SGleb Smirnoff .pr_detach = uipc_detach, 3360e7d02be1SGleb Smirnoff .pr_disconnect = uipc_disconnect, 3361e7d02be1SGleb Smirnoff .pr_peeraddr = uipc_peeraddr, 3362e7d02be1SGleb Smirnoff .pr_sosend = uipc_sosend_dgram, 3363e7d02be1SGleb Smirnoff .pr_sense = uipc_sense, 3364e7d02be1SGleb Smirnoff .pr_shutdown = uipc_shutdown, 3365e7d02be1SGleb Smirnoff .pr_sockaddr = uipc_sockaddr, 3366e7d02be1SGleb Smirnoff .pr_soreceive = uipc_soreceive_dgram, 3367e7d02be1SGleb Smirnoff .pr_close = uipc_close, 3368e7d02be1SGleb Smirnoff }; 3369e7d02be1SGleb Smirnoff 3370e7d02be1SGleb Smirnoff static struct protosw seqpacketproto = { 3371e7d02be1SGleb Smirnoff .pr_type = SOCK_SEQPACKET, 3372e7d02be1SGleb Smirnoff /* 3373e7d02be1SGleb Smirnoff * XXXRW: For now, PR_ADDR because soreceive will bump into them 3374e7d02be1SGleb Smirnoff * due to our use of sbappendaddr. A new sbappend variants is needed 3375e7d02be1SGleb Smirnoff * that supports both atomic record writes and control data. 3376e7d02be1SGleb Smirnoff */ 3377e7d02be1SGleb Smirnoff .pr_flags = PR_ADDR|PR_ATOMIC|PR_CONNREQUIRED| 3378e7d02be1SGleb Smirnoff PR_WANTRCVD|PR_RIGHTS|PR_CAPATTACH, 3379e7d02be1SGleb Smirnoff .pr_ctloutput = &uipc_ctloutput, 3380e7d02be1SGleb Smirnoff .pr_abort = uipc_abort, 3381e7d02be1SGleb Smirnoff .pr_accept = uipc_accept, 3382e7d02be1SGleb Smirnoff .pr_attach = uipc_attach, 3383e7d02be1SGleb Smirnoff .pr_bind = uipc_bind, 3384e7d02be1SGleb Smirnoff .pr_bindat = uipc_bindat, 3385e7d02be1SGleb Smirnoff .pr_connect = uipc_connect, 3386e7d02be1SGleb Smirnoff .pr_connectat = uipc_connectat, 3387e7d02be1SGleb Smirnoff .pr_connect2 = uipc_connect2, 3388e7d02be1SGleb Smirnoff .pr_detach = uipc_detach, 3389e7d02be1SGleb Smirnoff .pr_disconnect = uipc_disconnect, 3390e7d02be1SGleb Smirnoff .pr_listen = uipc_listen, 3391e7d02be1SGleb Smirnoff .pr_peeraddr = uipc_peeraddr, 3392e7d02be1SGleb Smirnoff .pr_rcvd = uipc_rcvd, 3393e7d02be1SGleb Smirnoff .pr_send = uipc_send, 3394e7d02be1SGleb Smirnoff .pr_sense = uipc_sense, 3395e7d02be1SGleb Smirnoff .pr_shutdown = uipc_shutdown, 3396e7d02be1SGleb Smirnoff .pr_sockaddr = uipc_sockaddr, 3397e7d02be1SGleb Smirnoff .pr_soreceive = soreceive_generic, /* XXX: or...? */ 3398e7d02be1SGleb Smirnoff .pr_close = uipc_close, 3399e7d02be1SGleb Smirnoff }; 3400e7d02be1SGleb Smirnoff 3401e7d02be1SGleb Smirnoff static struct domain localdomain = { 3402e7d02be1SGleb Smirnoff .dom_family = AF_LOCAL, 3403e7d02be1SGleb Smirnoff .dom_name = "local", 3404e7d02be1SGleb Smirnoff .dom_externalize = unp_externalize, 3405e7d02be1SGleb Smirnoff .dom_dispose = unp_dispose, 3406e7d02be1SGleb Smirnoff .dom_nprotosw = 3, 3407e7d02be1SGleb Smirnoff .dom_protosw = { 3408e7d02be1SGleb Smirnoff &streamproto, 3409e7d02be1SGleb Smirnoff &dgramproto, 3410e7d02be1SGleb Smirnoff &seqpacketproto, 3411e7d02be1SGleb Smirnoff } 3412e7d02be1SGleb Smirnoff }; 3413e7d02be1SGleb Smirnoff DOMAIN_SET(local); 3414e7d02be1SGleb Smirnoff 3415e7d02be1SGleb Smirnoff /* 3416662c901cSMikolaj Golub * A helper function called by VFS before socket-type vnode reclamation. 3417662c901cSMikolaj Golub * For an active vnode it clears unp_vnode pointer and decrements unp_vnode 3418662c901cSMikolaj Golub * use count. 3419662c901cSMikolaj Golub */ 3420662c901cSMikolaj Golub void 3421662c901cSMikolaj Golub vfs_unp_reclaim(struct vnode *vp) 3422662c901cSMikolaj Golub { 3423662c901cSMikolaj Golub struct unpcb *unp; 3424662c901cSMikolaj Golub int active; 342575a67bf3SMatt Macy struct mtx *vplock; 3426662c901cSMikolaj Golub 3427662c901cSMikolaj Golub ASSERT_VOP_ELOCKED(vp, "vfs_unp_reclaim"); 3428662c901cSMikolaj Golub KASSERT(vp->v_type == VSOCK, 3429662c901cSMikolaj Golub ("vfs_unp_reclaim: vp->v_type != VSOCK")); 3430662c901cSMikolaj Golub 3431662c901cSMikolaj Golub active = 0; 343275a67bf3SMatt Macy vplock = mtx_pool_find(mtxpool_sleep, vp); 343375a67bf3SMatt Macy mtx_lock(vplock); 34340c3c207fSGleb Smirnoff VOP_UNP_CONNECT(vp, &unp); 3435662c901cSMikolaj Golub if (unp == NULL) 3436662c901cSMikolaj Golub goto done; 3437662c901cSMikolaj Golub UNP_PCB_LOCK(unp); 3438c7e41c8bSMikolaj Golub if (unp->unp_vnode == vp) { 3439c7e41c8bSMikolaj Golub VOP_UNP_DETACH(vp); 3440662c901cSMikolaj Golub unp->unp_vnode = NULL; 3441662c901cSMikolaj Golub active = 1; 3442662c901cSMikolaj Golub } 3443662c901cSMikolaj Golub UNP_PCB_UNLOCK(unp); 3444662c901cSMikolaj Golub done: 344575a67bf3SMatt Macy mtx_unlock(vplock); 3446662c901cSMikolaj Golub if (active) 3447662c901cSMikolaj Golub vunref(vp); 3448662c901cSMikolaj Golub } 3449662c901cSMikolaj Golub 345003c96c31SRobert Watson #ifdef DDB 345103c96c31SRobert Watson static void 345203c96c31SRobert Watson db_print_indent(int indent) 345303c96c31SRobert Watson { 345403c96c31SRobert Watson int i; 345503c96c31SRobert Watson 345603c96c31SRobert Watson for (i = 0; i < indent; i++) 345703c96c31SRobert Watson db_printf(" "); 345803c96c31SRobert Watson } 345903c96c31SRobert Watson 346003c96c31SRobert Watson static void 346103c96c31SRobert Watson db_print_unpflags(int unp_flags) 346203c96c31SRobert Watson { 346303c96c31SRobert Watson int comma; 346403c96c31SRobert Watson 346503c96c31SRobert Watson comma = 0; 346603c96c31SRobert Watson if (unp_flags & UNP_HAVEPC) { 346703c96c31SRobert Watson db_printf("%sUNP_HAVEPC", comma ? ", " : ""); 346803c96c31SRobert Watson comma = 1; 346903c96c31SRobert Watson } 34702de07e40SConrad Meyer if (unp_flags & UNP_WANTCRED_ALWAYS) { 34712de07e40SConrad Meyer db_printf("%sUNP_WANTCRED_ALWAYS", comma ? ", " : ""); 34722de07e40SConrad Meyer comma = 1; 34732de07e40SConrad Meyer } 34742de07e40SConrad Meyer if (unp_flags & UNP_WANTCRED_ONESHOT) { 34752de07e40SConrad Meyer db_printf("%sUNP_WANTCRED_ONESHOT", comma ? ", " : ""); 347603c96c31SRobert Watson comma = 1; 347703c96c31SRobert Watson } 347803c96c31SRobert Watson if (unp_flags & UNP_CONNWAIT) { 347903c96c31SRobert Watson db_printf("%sUNP_CONNWAIT", comma ? ", " : ""); 348003c96c31SRobert Watson comma = 1; 348103c96c31SRobert Watson } 348203c96c31SRobert Watson if (unp_flags & UNP_CONNECTING) { 348303c96c31SRobert Watson db_printf("%sUNP_CONNECTING", comma ? ", " : ""); 348403c96c31SRobert Watson comma = 1; 348503c96c31SRobert Watson } 348603c96c31SRobert Watson if (unp_flags & UNP_BINDING) { 348703c96c31SRobert Watson db_printf("%sUNP_BINDING", comma ? ", " : ""); 348803c96c31SRobert Watson comma = 1; 348903c96c31SRobert Watson } 349003c96c31SRobert Watson } 349103c96c31SRobert Watson 349203c96c31SRobert Watson static void 349303c96c31SRobert Watson db_print_xucred(int indent, struct xucred *xu) 349403c96c31SRobert Watson { 349503c96c31SRobert Watson int comma, i; 349603c96c31SRobert Watson 349703c96c31SRobert Watson db_print_indent(indent); 3498c5afec6eSDmitry Chagin db_printf("cr_version: %u cr_uid: %u cr_pid: %d cr_ngroups: %d\n", 3499c5afec6eSDmitry Chagin xu->cr_version, xu->cr_uid, xu->cr_pid, xu->cr_ngroups); 350003c96c31SRobert Watson db_print_indent(indent); 350103c96c31SRobert Watson db_printf("cr_groups: "); 350203c96c31SRobert Watson comma = 0; 350303c96c31SRobert Watson for (i = 0; i < xu->cr_ngroups; i++) { 350403c96c31SRobert Watson db_printf("%s%u", comma ? ", " : "", xu->cr_groups[i]); 350503c96c31SRobert Watson comma = 1; 350603c96c31SRobert Watson } 350703c96c31SRobert Watson db_printf("\n"); 350803c96c31SRobert Watson } 350903c96c31SRobert Watson 351003c96c31SRobert Watson static void 351103c96c31SRobert Watson db_print_unprefs(int indent, struct unp_head *uh) 351203c96c31SRobert Watson { 351303c96c31SRobert Watson struct unpcb *unp; 351403c96c31SRobert Watson int counter; 351503c96c31SRobert Watson 351603c96c31SRobert Watson counter = 0; 351703c96c31SRobert Watson LIST_FOREACH(unp, uh, unp_reflink) { 351803c96c31SRobert Watson if (counter % 4 == 0) 351903c96c31SRobert Watson db_print_indent(indent); 352003c96c31SRobert Watson db_printf("%p ", unp); 352103c96c31SRobert Watson if (counter % 4 == 3) 352203c96c31SRobert Watson db_printf("\n"); 352303c96c31SRobert Watson counter++; 352403c96c31SRobert Watson } 352503c96c31SRobert Watson if (counter != 0 && counter % 4 != 0) 352603c96c31SRobert Watson db_printf("\n"); 352703c96c31SRobert Watson } 352803c96c31SRobert Watson 352903c96c31SRobert Watson DB_SHOW_COMMAND(unpcb, db_show_unpcb) 353003c96c31SRobert Watson { 353103c96c31SRobert Watson struct unpcb *unp; 353203c96c31SRobert Watson 353303c96c31SRobert Watson if (!have_addr) { 353403c96c31SRobert Watson db_printf("usage: show unpcb <addr>\n"); 353503c96c31SRobert Watson return; 353603c96c31SRobert Watson } 353703c96c31SRobert Watson unp = (struct unpcb *)addr; 353803c96c31SRobert Watson 353903c96c31SRobert Watson db_printf("unp_socket: %p unp_vnode: %p\n", unp->unp_socket, 354003c96c31SRobert Watson unp->unp_vnode); 354103c96c31SRobert Watson 3542fc8fdae0SMatthew D Fleming db_printf("unp_ino: %ju unp_conn: %p\n", (uintmax_t)unp->unp_ino, 354303c96c31SRobert Watson unp->unp_conn); 354403c96c31SRobert Watson 354503c96c31SRobert Watson db_printf("unp_refs:\n"); 354603c96c31SRobert Watson db_print_unprefs(2, &unp->unp_refs); 354703c96c31SRobert Watson 354803c96c31SRobert Watson /* XXXRW: Would be nice to print the full address, if any. */ 354903c96c31SRobert Watson db_printf("unp_addr: %p\n", unp->unp_addr); 355003c96c31SRobert Watson 3551c2090e73SAlan Somers db_printf("unp_gencnt: %llu\n", 355203c96c31SRobert Watson (unsigned long long)unp->unp_gencnt); 355303c96c31SRobert Watson 355403c96c31SRobert Watson db_printf("unp_flags: %x (", unp->unp_flags); 355503c96c31SRobert Watson db_print_unpflags(unp->unp_flags); 355603c96c31SRobert Watson db_printf(")\n"); 355703c96c31SRobert Watson 355803c96c31SRobert Watson db_printf("unp_peercred:\n"); 355903c96c31SRobert Watson db_print_xucred(2, &unp->unp_peercred); 356003c96c31SRobert Watson 356103c96c31SRobert Watson db_printf("unp_refcount: %u\n", unp->unp_refcount); 356203c96c31SRobert Watson } 356303c96c31SRobert Watson #endif 3564