1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1982, 1986, 1989, 1991, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 6df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 7df8bae1dSRodney W. Grimes * are met: 8df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 9df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 10df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 12df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 13df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 14df8bae1dSRodney W. Grimes * must display the following acknowledgement: 15df8bae1dSRodney W. Grimes * This product includes software developed by the University of 16df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 17df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 18df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 19df8bae1dSRodney W. Grimes * without specific prior written permission. 20df8bae1dSRodney W. Grimes * 21df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31df8bae1dSRodney W. Grimes * SUCH DAMAGE. 32df8bae1dSRodney W. Grimes * 33748e0b0aSGarrett Wollman * From: @(#)uipc_usrreq.c 8.3 (Berkeley) 1/4/94 34f708ef1bSPoul-Henning Kamp * $Id: uipc_usrreq.c,v 1.12 1995/08/31 01:39:31 dyson Exp $ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 37df8bae1dSRodney W. Grimes #include <sys/param.h> 38df8bae1dSRodney W. Grimes #include <sys/systm.h> 39df8bae1dSRodney W. Grimes #include <sys/proc.h> 40df8bae1dSRodney W. Grimes #include <sys/filedesc.h> 41df8bae1dSRodney W. Grimes #include <sys/domain.h> 42df8bae1dSRodney W. Grimes #include <sys/protosw.h> 43797f2d22SPoul-Henning Kamp #include <sys/stat.h> 44df8bae1dSRodney W. Grimes #include <sys/socket.h> 45df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 46df8bae1dSRodney W. Grimes #include <sys/unpcb.h> 47df8bae1dSRodney W. Grimes #include <sys/un.h> 48df8bae1dSRodney W. Grimes #include <sys/namei.h> 49df8bae1dSRodney W. Grimes #include <sys/vnode.h> 50df8bae1dSRodney W. Grimes #include <sys/file.h> 51df8bae1dSRodney W. Grimes #include <sys/stat.h> 52df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 53df8bae1dSRodney W. Grimes 54df8bae1dSRodney W. Grimes /* 55df8bae1dSRodney W. Grimes * Unix communications domain. 56df8bae1dSRodney W. Grimes * 57df8bae1dSRodney W. Grimes * TODO: 58df8bae1dSRodney W. Grimes * SEQPACKET, RDM 59df8bae1dSRodney W. Grimes * rethink name space problems 60df8bae1dSRodney W. Grimes * need a proper out-of-band 61df8bae1dSRodney W. Grimes */ 62f708ef1bSPoul-Henning Kamp static struct sockaddr sun_noname = { sizeof(sun_noname), AF_LOCAL }; 63f708ef1bSPoul-Henning Kamp static ino_t unp_ino; /* prototype for fake inode numbers */ 64f708ef1bSPoul-Henning Kamp 65f708ef1bSPoul-Henning Kamp static int unp_attach __P((struct socket *)); 66f708ef1bSPoul-Henning Kamp static void unp_detach __P((struct unpcb *)); 67f708ef1bSPoul-Henning Kamp static int unp_bind __P((struct unpcb *,struct mbuf *, struct proc *)); 68f708ef1bSPoul-Henning Kamp static int unp_connect __P((struct socket *,struct mbuf *, struct proc *)); 69f708ef1bSPoul-Henning Kamp static void unp_disconnect __P((struct unpcb *)); 70f708ef1bSPoul-Henning Kamp static void unp_shutdown __P((struct unpcb *)); 71f708ef1bSPoul-Henning Kamp static void unp_drop __P((struct unpcb *, int)); 72f708ef1bSPoul-Henning Kamp static void unp_gc __P((void)); 73f708ef1bSPoul-Henning Kamp static void unp_scan __P((struct mbuf *, void (*)(struct file *))); 74f708ef1bSPoul-Henning Kamp static void unp_mark __P((struct file *)); 75f708ef1bSPoul-Henning Kamp static void unp_discard __P((struct file *)); 76f708ef1bSPoul-Henning Kamp static int unp_internalize __P((struct mbuf *, struct proc *)); 77f708ef1bSPoul-Henning Kamp 78df8bae1dSRodney W. Grimes 79df8bae1dSRodney W. Grimes /*ARGSUSED*/ 8026f9a767SRodney W. Grimes int 81df8bae1dSRodney W. Grimes uipc_usrreq(so, req, m, nam, control) 82df8bae1dSRodney W. Grimes struct socket *so; 83df8bae1dSRodney W. Grimes int req; 84df8bae1dSRodney W. Grimes struct mbuf *m, *nam, *control; 85df8bae1dSRodney W. Grimes { 86df8bae1dSRodney W. Grimes struct unpcb *unp = sotounpcb(so); 87df8bae1dSRodney W. Grimes register struct socket *so2; 88df8bae1dSRodney W. Grimes register int error = 0; 89df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 90df8bae1dSRodney W. Grimes 91df8bae1dSRodney W. Grimes if (req == PRU_CONTROL) 92df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 93df8bae1dSRodney W. Grimes if (req != PRU_SEND && control && control->m_len) { 94df8bae1dSRodney W. Grimes error = EOPNOTSUPP; 95df8bae1dSRodney W. Grimes goto release; 96df8bae1dSRodney W. Grimes } 97df8bae1dSRodney W. Grimes if (unp == 0 && req != PRU_ATTACH) { 98df8bae1dSRodney W. Grimes error = EINVAL; 99df8bae1dSRodney W. Grimes goto release; 100df8bae1dSRodney W. Grimes } 101df8bae1dSRodney W. Grimes switch (req) { 102df8bae1dSRodney W. Grimes 103df8bae1dSRodney W. Grimes case PRU_ATTACH: 104df8bae1dSRodney W. Grimes if (unp) { 105df8bae1dSRodney W. Grimes error = EISCONN; 106df8bae1dSRodney W. Grimes break; 107df8bae1dSRodney W. Grimes } 108df8bae1dSRodney W. Grimes error = unp_attach(so); 109df8bae1dSRodney W. Grimes break; 110df8bae1dSRodney W. Grimes 111df8bae1dSRodney W. Grimes case PRU_DETACH: 112df8bae1dSRodney W. Grimes unp_detach(unp); 113df8bae1dSRodney W. Grimes break; 114df8bae1dSRodney W. Grimes 115df8bae1dSRodney W. Grimes case PRU_BIND: 116df8bae1dSRodney W. Grimes error = unp_bind(unp, nam, p); 117df8bae1dSRodney W. Grimes break; 118df8bae1dSRodney W. Grimes 119df8bae1dSRodney W. Grimes case PRU_LISTEN: 120df8bae1dSRodney W. Grimes if (unp->unp_vnode == 0) 121df8bae1dSRodney W. Grimes error = EINVAL; 122df8bae1dSRodney W. Grimes break; 123df8bae1dSRodney W. Grimes 124df8bae1dSRodney W. Grimes case PRU_CONNECT: 125df8bae1dSRodney W. Grimes error = unp_connect(so, nam, p); 126df8bae1dSRodney W. Grimes break; 127df8bae1dSRodney W. Grimes 128df8bae1dSRodney W. Grimes case PRU_CONNECT2: 129df8bae1dSRodney W. Grimes error = unp_connect2(so, (struct socket *)nam); 130df8bae1dSRodney W. Grimes break; 131df8bae1dSRodney W. Grimes 132df8bae1dSRodney W. Grimes case PRU_DISCONNECT: 133df8bae1dSRodney W. Grimes unp_disconnect(unp); 134df8bae1dSRodney W. Grimes break; 135df8bae1dSRodney W. Grimes 136df8bae1dSRodney W. Grimes case PRU_ACCEPT: 137df8bae1dSRodney W. Grimes /* 138df8bae1dSRodney W. Grimes * Pass back name of connected socket, 139df8bae1dSRodney W. Grimes * if it was bound and we are still connected 140df8bae1dSRodney W. Grimes * (our peer may have closed already!). 141df8bae1dSRodney W. Grimes */ 142df8bae1dSRodney W. Grimes if (unp->unp_conn && unp->unp_conn->unp_addr) { 143df8bae1dSRodney W. Grimes nam->m_len = unp->unp_conn->unp_addr->m_len; 144df8bae1dSRodney W. Grimes bcopy(mtod(unp->unp_conn->unp_addr, caddr_t), 145df8bae1dSRodney W. Grimes mtod(nam, caddr_t), (unsigned)nam->m_len); 146df8bae1dSRodney W. Grimes } else { 147df8bae1dSRodney W. Grimes nam->m_len = sizeof(sun_noname); 148df8bae1dSRodney W. Grimes *(mtod(nam, struct sockaddr *)) = sun_noname; 149df8bae1dSRodney W. Grimes } 150df8bae1dSRodney W. Grimes break; 151df8bae1dSRodney W. Grimes 152df8bae1dSRodney W. Grimes case PRU_SHUTDOWN: 153df8bae1dSRodney W. Grimes socantsendmore(so); 154df8bae1dSRodney W. Grimes unp_shutdown(unp); 155df8bae1dSRodney W. Grimes break; 156df8bae1dSRodney W. Grimes 157df8bae1dSRodney W. Grimes case PRU_RCVD: 158df8bae1dSRodney W. Grimes switch (so->so_type) { 159df8bae1dSRodney W. Grimes 160df8bae1dSRodney W. Grimes case SOCK_DGRAM: 161df8bae1dSRodney W. Grimes panic("uipc 1"); 162df8bae1dSRodney W. Grimes /*NOTREACHED*/ 163df8bae1dSRodney W. Grimes 164df8bae1dSRodney W. Grimes case SOCK_STREAM: 165df8bae1dSRodney W. Grimes #define rcv (&so->so_rcv) 166df8bae1dSRodney W. Grimes #define snd (&so2->so_snd) 167df8bae1dSRodney W. Grimes if (unp->unp_conn == 0) 168df8bae1dSRodney W. Grimes break; 169df8bae1dSRodney W. Grimes so2 = unp->unp_conn->unp_socket; 170df8bae1dSRodney W. Grimes /* 171df8bae1dSRodney W. Grimes * Adjust backpressure on sender 172df8bae1dSRodney W. Grimes * and wakeup any waiting to write. 173df8bae1dSRodney W. Grimes */ 174df8bae1dSRodney W. Grimes snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt; 175df8bae1dSRodney W. Grimes unp->unp_mbcnt = rcv->sb_mbcnt; 176df8bae1dSRodney W. Grimes snd->sb_hiwat += unp->unp_cc - rcv->sb_cc; 177df8bae1dSRodney W. Grimes unp->unp_cc = rcv->sb_cc; 178df8bae1dSRodney W. Grimes sowwakeup(so2); 179df8bae1dSRodney W. Grimes #undef snd 180df8bae1dSRodney W. Grimes #undef rcv 181df8bae1dSRodney W. Grimes break; 182df8bae1dSRodney W. Grimes 183df8bae1dSRodney W. Grimes default: 184df8bae1dSRodney W. Grimes panic("uipc 2"); 185df8bae1dSRodney W. Grimes } 186df8bae1dSRodney W. Grimes break; 187df8bae1dSRodney W. Grimes 188df8bae1dSRodney W. Grimes case PRU_SEND: 1896b8fda4dSGarrett Wollman case PRU_SEND_EOF: 190df8bae1dSRodney W. Grimes if (control && (error = unp_internalize(control, p))) 191df8bae1dSRodney W. Grimes break; 192df8bae1dSRodney W. Grimes switch (so->so_type) { 193df8bae1dSRodney W. Grimes 194df8bae1dSRodney W. Grimes case SOCK_DGRAM: { 195df8bae1dSRodney W. Grimes struct sockaddr *from; 196df8bae1dSRodney W. Grimes 197df8bae1dSRodney W. Grimes if (nam) { 198df8bae1dSRodney W. Grimes if (unp->unp_conn) { 199df8bae1dSRodney W. Grimes error = EISCONN; 200df8bae1dSRodney W. Grimes break; 201df8bae1dSRodney W. Grimes } 202df8bae1dSRodney W. Grimes error = unp_connect(so, nam, p); 203df8bae1dSRodney W. Grimes if (error) 204df8bae1dSRodney W. Grimes break; 205df8bae1dSRodney W. Grimes } else { 206df8bae1dSRodney W. Grimes if (unp->unp_conn == 0) { 207df8bae1dSRodney W. Grimes error = ENOTCONN; 208df8bae1dSRodney W. Grimes break; 209df8bae1dSRodney W. Grimes } 210df8bae1dSRodney W. Grimes } 211df8bae1dSRodney W. Grimes so2 = unp->unp_conn->unp_socket; 212df8bae1dSRodney W. Grimes if (unp->unp_addr) 213df8bae1dSRodney W. Grimes from = mtod(unp->unp_addr, struct sockaddr *); 214df8bae1dSRodney W. Grimes else 215df8bae1dSRodney W. Grimes from = &sun_noname; 216df8bae1dSRodney W. Grimes if (sbappendaddr(&so2->so_rcv, from, m, control)) { 217df8bae1dSRodney W. Grimes sorwakeup(so2); 218df8bae1dSRodney W. Grimes m = 0; 219df8bae1dSRodney W. Grimes control = 0; 220df8bae1dSRodney W. Grimes } else 221df8bae1dSRodney W. Grimes error = ENOBUFS; 222df8bae1dSRodney W. Grimes if (nam) 223df8bae1dSRodney W. Grimes unp_disconnect(unp); 224df8bae1dSRodney W. Grimes break; 225df8bae1dSRodney W. Grimes } 226df8bae1dSRodney W. Grimes 227df8bae1dSRodney W. Grimes case SOCK_STREAM: 228df8bae1dSRodney W. Grimes #define rcv (&so2->so_rcv) 229df8bae1dSRodney W. Grimes #define snd (&so->so_snd) 2306b8fda4dSGarrett Wollman /* Connect if not connected yet. */ 2316b8fda4dSGarrett Wollman /* 2326b8fda4dSGarrett Wollman * Note: A better implementation would complain 233402cc72dSDavid Greenman * if not equal to the peer's address. 2346b8fda4dSGarrett Wollman */ 235402cc72dSDavid Greenman if ((so->so_state & SS_ISCONNECTED) == 0) { 236402cc72dSDavid Greenman if (nam) { 237402cc72dSDavid Greenman error = unp_connect(so, nam, p); 238402cc72dSDavid Greenman if (error) 2396b8fda4dSGarrett Wollman break; /* XXX */ 240402cc72dSDavid Greenman } else { 241402cc72dSDavid Greenman error = ENOTCONN; 242402cc72dSDavid Greenman break; 243402cc72dSDavid Greenman } 244402cc72dSDavid Greenman } 245402cc72dSDavid Greenman 246df8bae1dSRodney W. Grimes if (so->so_state & SS_CANTSENDMORE) { 247df8bae1dSRodney W. Grimes error = EPIPE; 248df8bae1dSRodney W. Grimes break; 249df8bae1dSRodney W. Grimes } 250df8bae1dSRodney W. Grimes if (unp->unp_conn == 0) 251df8bae1dSRodney W. Grimes panic("uipc 3"); 252df8bae1dSRodney W. Grimes so2 = unp->unp_conn->unp_socket; 253df8bae1dSRodney W. Grimes /* 254df8bae1dSRodney W. Grimes * Send to paired receive port, and then reduce 255df8bae1dSRodney W. Grimes * send buffer hiwater marks to maintain backpressure. 256df8bae1dSRodney W. Grimes * Wake up readers. 257df8bae1dSRodney W. Grimes */ 258df8bae1dSRodney W. Grimes if (control) { 259df8bae1dSRodney W. Grimes if (sbappendcontrol(rcv, m, control)) 260df8bae1dSRodney W. Grimes control = 0; 261df8bae1dSRodney W. Grimes } else 262df8bae1dSRodney W. Grimes sbappend(rcv, m); 263df8bae1dSRodney W. Grimes snd->sb_mbmax -= 264df8bae1dSRodney W. Grimes rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt; 265df8bae1dSRodney W. Grimes unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt; 266df8bae1dSRodney W. Grimes snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc; 267df8bae1dSRodney W. Grimes unp->unp_conn->unp_cc = rcv->sb_cc; 268df8bae1dSRodney W. Grimes sorwakeup(so2); 269df8bae1dSRodney W. Grimes m = 0; 270df8bae1dSRodney W. Grimes #undef snd 271df8bae1dSRodney W. Grimes #undef rcv 272df8bae1dSRodney W. Grimes break; 273df8bae1dSRodney W. Grimes 274df8bae1dSRodney W. Grimes default: 275df8bae1dSRodney W. Grimes panic("uipc 4"); 276df8bae1dSRodney W. Grimes } 2776b8fda4dSGarrett Wollman /* 2786b8fda4dSGarrett Wollman * SEND_EOF is equivalent to a SEND followed by 2796b8fda4dSGarrett Wollman * a SHUTDOWN. 2806b8fda4dSGarrett Wollman */ 2816b8fda4dSGarrett Wollman if (req == PRU_SEND_EOF) { 2826b8fda4dSGarrett Wollman socantsendmore(so); 2836b8fda4dSGarrett Wollman unp_shutdown(unp); 2846b8fda4dSGarrett Wollman } 285df8bae1dSRodney W. Grimes break; 286df8bae1dSRodney W. Grimes 287df8bae1dSRodney W. Grimes case PRU_ABORT: 288df8bae1dSRodney W. Grimes unp_drop(unp, ECONNABORTED); 289df8bae1dSRodney W. Grimes break; 290df8bae1dSRodney W. Grimes 291df8bae1dSRodney W. Grimes case PRU_SENSE: 292df8bae1dSRodney W. Grimes ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat; 293df8bae1dSRodney W. Grimes if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) { 294df8bae1dSRodney W. Grimes so2 = unp->unp_conn->unp_socket; 295df8bae1dSRodney W. Grimes ((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc; 296df8bae1dSRodney W. Grimes } 297df8bae1dSRodney W. Grimes ((struct stat *) m)->st_dev = NODEV; 298df8bae1dSRodney W. Grimes if (unp->unp_ino == 0) 299df8bae1dSRodney W. Grimes unp->unp_ino = unp_ino++; 300df8bae1dSRodney W. Grimes ((struct stat *) m)->st_ino = unp->unp_ino; 301df8bae1dSRodney W. Grimes return (0); 302df8bae1dSRodney W. Grimes 303df8bae1dSRodney W. Grimes case PRU_RCVOOB: 304df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 305df8bae1dSRodney W. Grimes 306df8bae1dSRodney W. Grimes case PRU_SENDOOB: 307df8bae1dSRodney W. Grimes error = EOPNOTSUPP; 308df8bae1dSRodney W. Grimes break; 309df8bae1dSRodney W. Grimes 310df8bae1dSRodney W. Grimes case PRU_SOCKADDR: 311df8bae1dSRodney W. Grimes if (unp->unp_addr) { 312df8bae1dSRodney W. Grimes nam->m_len = unp->unp_addr->m_len; 313df8bae1dSRodney W. Grimes bcopy(mtod(unp->unp_addr, caddr_t), 314df8bae1dSRodney W. Grimes mtod(nam, caddr_t), (unsigned)nam->m_len); 315df8bae1dSRodney W. Grimes } else 316df8bae1dSRodney W. Grimes nam->m_len = 0; 317df8bae1dSRodney W. Grimes break; 318df8bae1dSRodney W. Grimes 319df8bae1dSRodney W. Grimes case PRU_PEERADDR: 320df8bae1dSRodney W. Grimes if (unp->unp_conn && unp->unp_conn->unp_addr) { 321df8bae1dSRodney W. Grimes nam->m_len = unp->unp_conn->unp_addr->m_len; 322df8bae1dSRodney W. Grimes bcopy(mtod(unp->unp_conn->unp_addr, caddr_t), 323df8bae1dSRodney W. Grimes mtod(nam, caddr_t), (unsigned)nam->m_len); 324df8bae1dSRodney W. Grimes } else 325df8bae1dSRodney W. Grimes nam->m_len = 0; 326df8bae1dSRodney W. Grimes break; 327df8bae1dSRodney W. Grimes 328df8bae1dSRodney W. Grimes case PRU_SLOWTIMO: 329df8bae1dSRodney W. Grimes break; 330df8bae1dSRodney W. Grimes 331df8bae1dSRodney W. Grimes default: 332df8bae1dSRodney W. Grimes panic("piusrreq"); 333df8bae1dSRodney W. Grimes } 334df8bae1dSRodney W. Grimes release: 335df8bae1dSRodney W. Grimes if (control) 336df8bae1dSRodney W. Grimes m_freem(control); 337df8bae1dSRodney W. Grimes if (m) 338df8bae1dSRodney W. Grimes m_freem(m); 339df8bae1dSRodney W. Grimes return (error); 340df8bae1dSRodney W. Grimes } 341df8bae1dSRodney W. Grimes 342df8bae1dSRodney W. Grimes /* 343df8bae1dSRodney W. Grimes * Both send and receive buffers are allocated PIPSIZ bytes of buffering 344df8bae1dSRodney W. Grimes * for stream sockets, although the total for sender and receiver is 345df8bae1dSRodney W. Grimes * actually only PIPSIZ. 346df8bae1dSRodney W. Grimes * Datagram sockets really use the sendspace as the maximum datagram size, 347df8bae1dSRodney W. Grimes * and don't really want to reserve the sendspace. Their recvspace should 348df8bae1dSRodney W. Grimes * be large enough for at least one max-size datagram plus address. 349df8bae1dSRodney W. Grimes */ 3505dce41c5SJohn Dyson #ifndef PIPSIZ 3515dce41c5SJohn Dyson #define PIPSIZ 8192 3525dce41c5SJohn Dyson #endif 353f708ef1bSPoul-Henning Kamp static u_long unpst_sendspace = PIPSIZ; 354f708ef1bSPoul-Henning Kamp static u_long unpst_recvspace = PIPSIZ; 355f708ef1bSPoul-Henning Kamp static u_long unpdg_sendspace = 2*1024; /* really max datagram size */ 356f708ef1bSPoul-Henning Kamp static u_long unpdg_recvspace = 4*1024; 357df8bae1dSRodney W. Grimes 358f708ef1bSPoul-Henning Kamp static int unp_rights; /* file descriptors in flight */ 359df8bae1dSRodney W. Grimes 360f708ef1bSPoul-Henning Kamp static int 361df8bae1dSRodney W. Grimes unp_attach(so) 362df8bae1dSRodney W. Grimes struct socket *so; 363df8bae1dSRodney W. Grimes { 364df8bae1dSRodney W. Grimes register struct mbuf *m; 365df8bae1dSRodney W. Grimes register struct unpcb *unp; 366df8bae1dSRodney W. Grimes int error; 367df8bae1dSRodney W. Grimes 368df8bae1dSRodney W. Grimes if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 369df8bae1dSRodney W. Grimes switch (so->so_type) { 370df8bae1dSRodney W. Grimes 371df8bae1dSRodney W. Grimes case SOCK_STREAM: 372df8bae1dSRodney W. Grimes error = soreserve(so, unpst_sendspace, unpst_recvspace); 373df8bae1dSRodney W. Grimes break; 374df8bae1dSRodney W. Grimes 375df8bae1dSRodney W. Grimes case SOCK_DGRAM: 376df8bae1dSRodney W. Grimes error = soreserve(so, unpdg_sendspace, unpdg_recvspace); 377df8bae1dSRodney W. Grimes break; 378df8bae1dSRodney W. Grimes 379df8bae1dSRodney W. Grimes default: 380df8bae1dSRodney W. Grimes panic("unp_attach"); 381df8bae1dSRodney W. Grimes } 382df8bae1dSRodney W. Grimes if (error) 383df8bae1dSRodney W. Grimes return (error); 384df8bae1dSRodney W. Grimes } 385df8bae1dSRodney W. Grimes m = m_getclr(M_DONTWAIT, MT_PCB); 386df8bae1dSRodney W. Grimes if (m == NULL) 387df8bae1dSRodney W. Grimes return (ENOBUFS); 388df8bae1dSRodney W. Grimes unp = mtod(m, struct unpcb *); 389df8bae1dSRodney W. Grimes so->so_pcb = (caddr_t)unp; 390df8bae1dSRodney W. Grimes unp->unp_socket = so; 391df8bae1dSRodney W. Grimes return (0); 392df8bae1dSRodney W. Grimes } 393df8bae1dSRodney W. Grimes 394f708ef1bSPoul-Henning Kamp static void 395df8bae1dSRodney W. Grimes unp_detach(unp) 396df8bae1dSRodney W. Grimes register struct unpcb *unp; 397df8bae1dSRodney W. Grimes { 398df8bae1dSRodney W. Grimes 399df8bae1dSRodney W. Grimes if (unp->unp_vnode) { 400df8bae1dSRodney W. Grimes unp->unp_vnode->v_socket = 0; 401df8bae1dSRodney W. Grimes vrele(unp->unp_vnode); 402df8bae1dSRodney W. Grimes unp->unp_vnode = 0; 403df8bae1dSRodney W. Grimes } 404df8bae1dSRodney W. Grimes if (unp->unp_conn) 405df8bae1dSRodney W. Grimes unp_disconnect(unp); 406df8bae1dSRodney W. Grimes while (unp->unp_refs) 407df8bae1dSRodney W. Grimes unp_drop(unp->unp_refs, ECONNRESET); 408df8bae1dSRodney W. Grimes soisdisconnected(unp->unp_socket); 409df8bae1dSRodney W. Grimes unp->unp_socket->so_pcb = 0; 410df8bae1dSRodney W. Grimes if (unp_rights) { 411df8bae1dSRodney W. Grimes /* 412df8bae1dSRodney W. Grimes * Normally the receive buffer is flushed later, 413df8bae1dSRodney W. Grimes * in sofree, but if our receive buffer holds references 414df8bae1dSRodney W. Grimes * to descriptors that are now garbage, we will dispose 415df8bae1dSRodney W. Grimes * of those descriptor references after the garbage collector 416df8bae1dSRodney W. Grimes * gets them (resulting in a "panic: closef: count < 0"). 417df8bae1dSRodney W. Grimes */ 418df8bae1dSRodney W. Grimes sorflush(unp->unp_socket); 419df8bae1dSRodney W. Grimes unp_gc(); 420df8bae1dSRodney W. Grimes } 421b4c19655SDavid Greenman m_freem(unp->unp_addr); 422b4c19655SDavid Greenman (void) m_free(dtom(unp)); 423df8bae1dSRodney W. Grimes } 424df8bae1dSRodney W. Grimes 425f708ef1bSPoul-Henning Kamp static int 426df8bae1dSRodney W. Grimes unp_bind(unp, nam, p) 427df8bae1dSRodney W. Grimes struct unpcb *unp; 428df8bae1dSRodney W. Grimes struct mbuf *nam; 429df8bae1dSRodney W. Grimes struct proc *p; 430df8bae1dSRodney W. Grimes { 431df8bae1dSRodney W. Grimes struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 432df8bae1dSRodney W. Grimes register struct vnode *vp; 433df8bae1dSRodney W. Grimes struct vattr vattr; 434df8bae1dSRodney W. Grimes int error; 435df8bae1dSRodney W. Grimes struct nameidata nd; 436df8bae1dSRodney W. Grimes 437df8bae1dSRodney W. Grimes NDINIT(&nd, CREATE, FOLLOW | LOCKPARENT, UIO_SYSSPACE, 438df8bae1dSRodney W. Grimes soun->sun_path, p); 439df8bae1dSRodney W. Grimes if (unp->unp_vnode != NULL) 440df8bae1dSRodney W. Grimes return (EINVAL); 441df8bae1dSRodney W. Grimes if (nam->m_len == MLEN) { 442df8bae1dSRodney W. Grimes if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0) 443df8bae1dSRodney W. Grimes return (EINVAL); 444df8bae1dSRodney W. Grimes } else 445df8bae1dSRodney W. Grimes *(mtod(nam, caddr_t) + nam->m_len) = 0; 446df8bae1dSRodney W. Grimes /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ 447797f2d22SPoul-Henning Kamp error = namei(&nd); 448797f2d22SPoul-Henning Kamp if (error) 449df8bae1dSRodney W. Grimes return (error); 450df8bae1dSRodney W. Grimes vp = nd.ni_vp; 451df8bae1dSRodney W. Grimes if (vp != NULL) { 452df8bae1dSRodney W. Grimes VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 453df8bae1dSRodney W. Grimes if (nd.ni_dvp == vp) 454df8bae1dSRodney W. Grimes vrele(nd.ni_dvp); 455df8bae1dSRodney W. Grimes else 456df8bae1dSRodney W. Grimes vput(nd.ni_dvp); 457df8bae1dSRodney W. Grimes vrele(vp); 458df8bae1dSRodney W. Grimes return (EADDRINUSE); 459df8bae1dSRodney W. Grimes } 460df8bae1dSRodney W. Grimes VATTR_NULL(&vattr); 461df8bae1dSRodney W. Grimes vattr.va_type = VSOCK; 462df8bae1dSRodney W. Grimes vattr.va_mode = ACCESSPERMS; 463df8bae1dSRodney W. Grimes LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 464797f2d22SPoul-Henning Kamp error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 465797f2d22SPoul-Henning Kamp if (error) 466df8bae1dSRodney W. Grimes return (error); 467df8bae1dSRodney W. Grimes vp = nd.ni_vp; 468df8bae1dSRodney W. Grimes vp->v_socket = unp->unp_socket; 469df8bae1dSRodney W. Grimes unp->unp_vnode = vp; 470df8bae1dSRodney W. Grimes unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL); 471df8bae1dSRodney W. Grimes VOP_UNLOCK(vp); 472df8bae1dSRodney W. Grimes return (0); 473df8bae1dSRodney W. Grimes } 474df8bae1dSRodney W. Grimes 475f708ef1bSPoul-Henning Kamp static int 476df8bae1dSRodney W. Grimes unp_connect(so, nam, p) 477df8bae1dSRodney W. Grimes struct socket *so; 478df8bae1dSRodney W. Grimes struct mbuf *nam; 479df8bae1dSRodney W. Grimes struct proc *p; 480df8bae1dSRodney W. Grimes { 481df8bae1dSRodney W. Grimes register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 482df8bae1dSRodney W. Grimes register struct vnode *vp; 483df8bae1dSRodney W. Grimes register struct socket *so2, *so3; 484df8bae1dSRodney W. Grimes struct unpcb *unp2, *unp3; 485df8bae1dSRodney W. Grimes int error; 486df8bae1dSRodney W. Grimes struct nameidata nd; 487df8bae1dSRodney W. Grimes 488df8bae1dSRodney W. Grimes NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, soun->sun_path, p); 489df8bae1dSRodney W. Grimes if (nam->m_data + nam->m_len == &nam->m_dat[MLEN]) { /* XXX */ 490df8bae1dSRodney W. Grimes if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0) 491df8bae1dSRodney W. Grimes return (EMSGSIZE); 492df8bae1dSRodney W. Grimes } else 493df8bae1dSRodney W. Grimes *(mtod(nam, caddr_t) + nam->m_len) = 0; 494797f2d22SPoul-Henning Kamp error = namei(&nd); 495797f2d22SPoul-Henning Kamp if (error) 496df8bae1dSRodney W. Grimes return (error); 497df8bae1dSRodney W. Grimes vp = nd.ni_vp; 498df8bae1dSRodney W. Grimes if (vp->v_type != VSOCK) { 499df8bae1dSRodney W. Grimes error = ENOTSOCK; 500df8bae1dSRodney W. Grimes goto bad; 501df8bae1dSRodney W. Grimes } 502797f2d22SPoul-Henning Kamp error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p); 503797f2d22SPoul-Henning Kamp if (error) 504df8bae1dSRodney W. Grimes goto bad; 505df8bae1dSRodney W. Grimes so2 = vp->v_socket; 506df8bae1dSRodney W. Grimes if (so2 == 0) { 507df8bae1dSRodney W. Grimes error = ECONNREFUSED; 508df8bae1dSRodney W. Grimes goto bad; 509df8bae1dSRodney W. Grimes } 510df8bae1dSRodney W. Grimes if (so->so_type != so2->so_type) { 511df8bae1dSRodney W. Grimes error = EPROTOTYPE; 512df8bae1dSRodney W. Grimes goto bad; 513df8bae1dSRodney W. Grimes } 514df8bae1dSRodney W. Grimes if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 515df8bae1dSRodney W. Grimes if ((so2->so_options & SO_ACCEPTCONN) == 0 || 516df8bae1dSRodney W. Grimes (so3 = sonewconn(so2, 0)) == 0) { 517df8bae1dSRodney W. Grimes error = ECONNREFUSED; 518df8bae1dSRodney W. Grimes goto bad; 519df8bae1dSRodney W. Grimes } 520df8bae1dSRodney W. Grimes unp2 = sotounpcb(so2); 521df8bae1dSRodney W. Grimes unp3 = sotounpcb(so3); 522df8bae1dSRodney W. Grimes if (unp2->unp_addr) 523df8bae1dSRodney W. Grimes unp3->unp_addr = 524df8bae1dSRodney W. Grimes m_copy(unp2->unp_addr, 0, (int)M_COPYALL); 525df8bae1dSRodney W. Grimes so2 = so3; 526df8bae1dSRodney W. Grimes } 527df8bae1dSRodney W. Grimes error = unp_connect2(so, so2); 528df8bae1dSRodney W. Grimes bad: 529df8bae1dSRodney W. Grimes vput(vp); 530df8bae1dSRodney W. Grimes return (error); 531df8bae1dSRodney W. Grimes } 532df8bae1dSRodney W. Grimes 53326f9a767SRodney W. Grimes int 534df8bae1dSRodney W. Grimes unp_connect2(so, so2) 535df8bae1dSRodney W. Grimes register struct socket *so; 536df8bae1dSRodney W. Grimes register struct socket *so2; 537df8bae1dSRodney W. Grimes { 538df8bae1dSRodney W. Grimes register struct unpcb *unp = sotounpcb(so); 539df8bae1dSRodney W. Grimes register struct unpcb *unp2; 540df8bae1dSRodney W. Grimes 541df8bae1dSRodney W. Grimes if (so2->so_type != so->so_type) 542df8bae1dSRodney W. Grimes return (EPROTOTYPE); 543df8bae1dSRodney W. Grimes unp2 = sotounpcb(so2); 544df8bae1dSRodney W. Grimes unp->unp_conn = unp2; 545df8bae1dSRodney W. Grimes switch (so->so_type) { 546df8bae1dSRodney W. Grimes 547df8bae1dSRodney W. Grimes case SOCK_DGRAM: 548df8bae1dSRodney W. Grimes unp->unp_nextref = unp2->unp_refs; 549df8bae1dSRodney W. Grimes unp2->unp_refs = unp; 550df8bae1dSRodney W. Grimes soisconnected(so); 551df8bae1dSRodney W. Grimes break; 552df8bae1dSRodney W. Grimes 553df8bae1dSRodney W. Grimes case SOCK_STREAM: 554df8bae1dSRodney W. Grimes unp2->unp_conn = unp; 555df8bae1dSRodney W. Grimes soisconnected(so); 556df8bae1dSRodney W. Grimes soisconnected(so2); 557df8bae1dSRodney W. Grimes break; 558df8bae1dSRodney W. Grimes 559df8bae1dSRodney W. Grimes default: 560df8bae1dSRodney W. Grimes panic("unp_connect2"); 561df8bae1dSRodney W. Grimes } 562df8bae1dSRodney W. Grimes return (0); 563df8bae1dSRodney W. Grimes } 564df8bae1dSRodney W. Grimes 565f708ef1bSPoul-Henning Kamp static void 566df8bae1dSRodney W. Grimes unp_disconnect(unp) 567df8bae1dSRodney W. Grimes struct unpcb *unp; 568df8bae1dSRodney W. Grimes { 569df8bae1dSRodney W. Grimes register struct unpcb *unp2 = unp->unp_conn; 570df8bae1dSRodney W. Grimes 571df8bae1dSRodney W. Grimes if (unp2 == 0) 572df8bae1dSRodney W. Grimes return; 573df8bae1dSRodney W. Grimes unp->unp_conn = 0; 574df8bae1dSRodney W. Grimes switch (unp->unp_socket->so_type) { 575df8bae1dSRodney W. Grimes 576df8bae1dSRodney W. Grimes case SOCK_DGRAM: 577df8bae1dSRodney W. Grimes if (unp2->unp_refs == unp) 578df8bae1dSRodney W. Grimes unp2->unp_refs = unp->unp_nextref; 579df8bae1dSRodney W. Grimes else { 580df8bae1dSRodney W. Grimes unp2 = unp2->unp_refs; 581df8bae1dSRodney W. Grimes for (;;) { 582df8bae1dSRodney W. Grimes if (unp2 == 0) 583df8bae1dSRodney W. Grimes panic("unp_disconnect"); 584df8bae1dSRodney W. Grimes if (unp2->unp_nextref == unp) 585df8bae1dSRodney W. Grimes break; 586df8bae1dSRodney W. Grimes unp2 = unp2->unp_nextref; 587df8bae1dSRodney W. Grimes } 588df8bae1dSRodney W. Grimes unp2->unp_nextref = unp->unp_nextref; 589df8bae1dSRodney W. Grimes } 590df8bae1dSRodney W. Grimes unp->unp_nextref = 0; 591df8bae1dSRodney W. Grimes unp->unp_socket->so_state &= ~SS_ISCONNECTED; 592df8bae1dSRodney W. Grimes break; 593df8bae1dSRodney W. Grimes 594df8bae1dSRodney W. Grimes case SOCK_STREAM: 595df8bae1dSRodney W. Grimes soisdisconnected(unp->unp_socket); 596df8bae1dSRodney W. Grimes unp2->unp_conn = 0; 597df8bae1dSRodney W. Grimes soisdisconnected(unp2->unp_socket); 598df8bae1dSRodney W. Grimes break; 599df8bae1dSRodney W. Grimes } 600df8bae1dSRodney W. Grimes } 601df8bae1dSRodney W. Grimes 602df8bae1dSRodney W. Grimes #ifdef notdef 60326f9a767SRodney W. Grimes void 604df8bae1dSRodney W. Grimes unp_abort(unp) 605df8bae1dSRodney W. Grimes struct unpcb *unp; 606df8bae1dSRodney W. Grimes { 607df8bae1dSRodney W. Grimes 608df8bae1dSRodney W. Grimes unp_detach(unp); 609df8bae1dSRodney W. Grimes } 610df8bae1dSRodney W. Grimes #endif 611df8bae1dSRodney W. Grimes 612f708ef1bSPoul-Henning Kamp static void 613df8bae1dSRodney W. Grimes unp_shutdown(unp) 614df8bae1dSRodney W. Grimes struct unpcb *unp; 615df8bae1dSRodney W. Grimes { 616df8bae1dSRodney W. Grimes struct socket *so; 617df8bae1dSRodney W. Grimes 618df8bae1dSRodney W. Grimes if (unp->unp_socket->so_type == SOCK_STREAM && unp->unp_conn && 619df8bae1dSRodney W. Grimes (so = unp->unp_conn->unp_socket)) 620df8bae1dSRodney W. Grimes socantrcvmore(so); 621df8bae1dSRodney W. Grimes } 622df8bae1dSRodney W. Grimes 623f708ef1bSPoul-Henning Kamp static void 624df8bae1dSRodney W. Grimes unp_drop(unp, errno) 625df8bae1dSRodney W. Grimes struct unpcb *unp; 626df8bae1dSRodney W. Grimes int errno; 627df8bae1dSRodney W. Grimes { 628df8bae1dSRodney W. Grimes struct socket *so = unp->unp_socket; 629df8bae1dSRodney W. Grimes 630df8bae1dSRodney W. Grimes so->so_error = errno; 631df8bae1dSRodney W. Grimes unp_disconnect(unp); 632df8bae1dSRodney W. Grimes if (so->so_head) { 633df8bae1dSRodney W. Grimes so->so_pcb = (caddr_t) 0; 634df8bae1dSRodney W. Grimes m_freem(unp->unp_addr); 635df8bae1dSRodney W. Grimes (void) m_free(dtom(unp)); 636df8bae1dSRodney W. Grimes sofree(so); 637df8bae1dSRodney W. Grimes } 638df8bae1dSRodney W. Grimes } 639df8bae1dSRodney W. Grimes 640df8bae1dSRodney W. Grimes #ifdef notdef 64126f9a767SRodney W. Grimes void 642df8bae1dSRodney W. Grimes unp_drain() 643df8bae1dSRodney W. Grimes { 644df8bae1dSRodney W. Grimes 645df8bae1dSRodney W. Grimes } 646df8bae1dSRodney W. Grimes #endif 647df8bae1dSRodney W. Grimes 64826f9a767SRodney W. Grimes int 649df8bae1dSRodney W. Grimes unp_externalize(rights) 650df8bae1dSRodney W. Grimes struct mbuf *rights; 651df8bae1dSRodney W. Grimes { 652df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 653df8bae1dSRodney W. Grimes register int i; 654df8bae1dSRodney W. Grimes register struct cmsghdr *cm = mtod(rights, struct cmsghdr *); 655df8bae1dSRodney W. Grimes register struct file **rp = (struct file **)(cm + 1); 656df8bae1dSRodney W. Grimes register struct file *fp; 657df8bae1dSRodney W. Grimes int newfds = (cm->cmsg_len - sizeof(*cm)) / sizeof (int); 658df8bae1dSRodney W. Grimes int f; 659df8bae1dSRodney W. Grimes 660df8bae1dSRodney W. Grimes if (!fdavail(p, newfds)) { 661df8bae1dSRodney W. Grimes for (i = 0; i < newfds; i++) { 662df8bae1dSRodney W. Grimes fp = *rp; 663df8bae1dSRodney W. Grimes unp_discard(fp); 664df8bae1dSRodney W. Grimes *rp++ = 0; 665df8bae1dSRodney W. Grimes } 666df8bae1dSRodney W. Grimes return (EMSGSIZE); 667df8bae1dSRodney W. Grimes } 668df8bae1dSRodney W. Grimes for (i = 0; i < newfds; i++) { 669df8bae1dSRodney W. Grimes if (fdalloc(p, 0, &f)) 670df8bae1dSRodney W. Grimes panic("unp_externalize"); 671df8bae1dSRodney W. Grimes fp = *rp; 672df8bae1dSRodney W. Grimes p->p_fd->fd_ofiles[f] = fp; 673df8bae1dSRodney W. Grimes fp->f_msgcount--; 674df8bae1dSRodney W. Grimes unp_rights--; 675df8bae1dSRodney W. Grimes *(int *)rp++ = f; 676df8bae1dSRodney W. Grimes } 677df8bae1dSRodney W. Grimes return (0); 678df8bae1dSRodney W. Grimes } 679df8bae1dSRodney W. Grimes 680f708ef1bSPoul-Henning Kamp static int 681df8bae1dSRodney W. Grimes unp_internalize(control, p) 682df8bae1dSRodney W. Grimes struct mbuf *control; 683df8bae1dSRodney W. Grimes struct proc *p; 684df8bae1dSRodney W. Grimes { 685df8bae1dSRodney W. Grimes struct filedesc *fdp = p->p_fd; 686df8bae1dSRodney W. Grimes register struct cmsghdr *cm = mtod(control, struct cmsghdr *); 687df8bae1dSRodney W. Grimes register struct file **rp; 688df8bae1dSRodney W. Grimes register struct file *fp; 689df8bae1dSRodney W. Grimes register int i, fd; 690df8bae1dSRodney W. Grimes int oldfds; 691df8bae1dSRodney W. Grimes 692df8bae1dSRodney W. Grimes if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET || 693df8bae1dSRodney W. Grimes cm->cmsg_len != control->m_len) 694df8bae1dSRodney W. Grimes return (EINVAL); 695df8bae1dSRodney W. Grimes oldfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int); 696df8bae1dSRodney W. Grimes rp = (struct file **)(cm + 1); 697df8bae1dSRodney W. Grimes for (i = 0; i < oldfds; i++) { 698df8bae1dSRodney W. Grimes fd = *(int *)rp++; 699df8bae1dSRodney W. Grimes if ((unsigned)fd >= fdp->fd_nfiles || 700df8bae1dSRodney W. Grimes fdp->fd_ofiles[fd] == NULL) 701df8bae1dSRodney W. Grimes return (EBADF); 702df8bae1dSRodney W. Grimes } 703df8bae1dSRodney W. Grimes rp = (struct file **)(cm + 1); 704df8bae1dSRodney W. Grimes for (i = 0; i < oldfds; i++) { 705df8bae1dSRodney W. Grimes fp = fdp->fd_ofiles[*(int *)rp]; 706df8bae1dSRodney W. Grimes *rp++ = fp; 707df8bae1dSRodney W. Grimes fp->f_count++; 708df8bae1dSRodney W. Grimes fp->f_msgcount++; 709df8bae1dSRodney W. Grimes unp_rights++; 710df8bae1dSRodney W. Grimes } 711df8bae1dSRodney W. Grimes return (0); 712df8bae1dSRodney W. Grimes } 713df8bae1dSRodney W. Grimes 714f708ef1bSPoul-Henning Kamp static int unp_defer, unp_gcing; 715df8bae1dSRodney W. Grimes 716f708ef1bSPoul-Henning Kamp static void 717df8bae1dSRodney W. Grimes unp_gc() 718df8bae1dSRodney W. Grimes { 719df8bae1dSRodney W. Grimes register struct file *fp, *nextfp; 720df8bae1dSRodney W. Grimes register struct socket *so; 721df8bae1dSRodney W. Grimes struct file **extra_ref, **fpp; 722df8bae1dSRodney W. Grimes int nunref, i; 723df8bae1dSRodney W. Grimes 724df8bae1dSRodney W. Grimes if (unp_gcing) 725df8bae1dSRodney W. Grimes return; 726df8bae1dSRodney W. Grimes unp_gcing = 1; 727df8bae1dSRodney W. Grimes unp_defer = 0; 728df8bae1dSRodney W. Grimes for (fp = filehead; fp; fp = fp->f_filef) 729df8bae1dSRodney W. Grimes fp->f_flag &= ~(FMARK|FDEFER); 730df8bae1dSRodney W. Grimes do { 731df8bae1dSRodney W. Grimes for (fp = filehead; fp; fp = fp->f_filef) { 732df8bae1dSRodney W. Grimes if (fp->f_count == 0) 733df8bae1dSRodney W. Grimes continue; 734df8bae1dSRodney W. Grimes if (fp->f_flag & FDEFER) { 735df8bae1dSRodney W. Grimes fp->f_flag &= ~FDEFER; 736df8bae1dSRodney W. Grimes unp_defer--; 737df8bae1dSRodney W. Grimes } else { 738df8bae1dSRodney W. Grimes if (fp->f_flag & FMARK) 739df8bae1dSRodney W. Grimes continue; 740df8bae1dSRodney W. Grimes if (fp->f_count == fp->f_msgcount) 741df8bae1dSRodney W. Grimes continue; 742df8bae1dSRodney W. Grimes fp->f_flag |= FMARK; 743df8bae1dSRodney W. Grimes } 744df8bae1dSRodney W. Grimes if (fp->f_type != DTYPE_SOCKET || 745df8bae1dSRodney W. Grimes (so = (struct socket *)fp->f_data) == 0) 746df8bae1dSRodney W. Grimes continue; 747748e0b0aSGarrett Wollman if (so->so_proto->pr_domain != &localdomain || 748df8bae1dSRodney W. Grimes (so->so_proto->pr_flags&PR_RIGHTS) == 0) 749df8bae1dSRodney W. Grimes continue; 750df8bae1dSRodney W. Grimes #ifdef notdef 751df8bae1dSRodney W. Grimes if (so->so_rcv.sb_flags & SB_LOCK) { 752df8bae1dSRodney W. Grimes /* 753df8bae1dSRodney W. Grimes * This is problematical; it's not clear 754df8bae1dSRodney W. Grimes * we need to wait for the sockbuf to be 755df8bae1dSRodney W. Grimes * unlocked (on a uniprocessor, at least), 756df8bae1dSRodney W. Grimes * and it's also not clear what to do 757df8bae1dSRodney W. Grimes * if sbwait returns an error due to receipt 758df8bae1dSRodney W. Grimes * of a signal. If sbwait does return 759df8bae1dSRodney W. Grimes * an error, we'll go into an infinite 760df8bae1dSRodney W. Grimes * loop. Delete all of this for now. 761df8bae1dSRodney W. Grimes */ 762df8bae1dSRodney W. Grimes (void) sbwait(&so->so_rcv); 763df8bae1dSRodney W. Grimes goto restart; 764df8bae1dSRodney W. Grimes } 765df8bae1dSRodney W. Grimes #endif 766df8bae1dSRodney W. Grimes unp_scan(so->so_rcv.sb_mb, unp_mark); 767df8bae1dSRodney W. Grimes } 768df8bae1dSRodney W. Grimes } while (unp_defer); 769df8bae1dSRodney W. Grimes /* 770df8bae1dSRodney W. Grimes * We grab an extra reference to each of the file table entries 771df8bae1dSRodney W. Grimes * that are not otherwise accessible and then free the rights 772df8bae1dSRodney W. Grimes * that are stored in messages on them. 773df8bae1dSRodney W. Grimes * 774df8bae1dSRodney W. Grimes * The bug in the orginal code is a little tricky, so I'll describe 775df8bae1dSRodney W. Grimes * what's wrong with it here. 776df8bae1dSRodney W. Grimes * 777df8bae1dSRodney W. Grimes * It is incorrect to simply unp_discard each entry for f_msgcount 778df8bae1dSRodney W. Grimes * times -- consider the case of sockets A and B that contain 779df8bae1dSRodney W. Grimes * references to each other. On a last close of some other socket, 780df8bae1dSRodney W. Grimes * we trigger a gc since the number of outstanding rights (unp_rights) 781df8bae1dSRodney W. Grimes * is non-zero. If during the sweep phase the gc code un_discards, 782df8bae1dSRodney W. Grimes * we end up doing a (full) closef on the descriptor. A closef on A 783df8bae1dSRodney W. Grimes * results in the following chain. Closef calls soo_close, which 784df8bae1dSRodney W. Grimes * calls soclose. Soclose calls first (through the switch 785df8bae1dSRodney W. Grimes * uipc_usrreq) unp_detach, which re-invokes unp_gc. Unp_gc simply 786df8bae1dSRodney W. Grimes * returns because the previous instance had set unp_gcing, and 787df8bae1dSRodney W. Grimes * we return all the way back to soclose, which marks the socket 788df8bae1dSRodney W. Grimes * with SS_NOFDREF, and then calls sofree. Sofree calls sorflush 789df8bae1dSRodney W. Grimes * to free up the rights that are queued in messages on the socket A, 790df8bae1dSRodney W. Grimes * i.e., the reference on B. The sorflush calls via the dom_dispose 791df8bae1dSRodney W. Grimes * switch unp_dispose, which unp_scans with unp_discard. This second 792df8bae1dSRodney W. Grimes * instance of unp_discard just calls closef on B. 793df8bae1dSRodney W. Grimes * 794df8bae1dSRodney W. Grimes * Well, a similar chain occurs on B, resulting in a sorflush on B, 795df8bae1dSRodney W. Grimes * which results in another closef on A. Unfortunately, A is already 796df8bae1dSRodney W. Grimes * being closed, and the descriptor has already been marked with 797df8bae1dSRodney W. Grimes * SS_NOFDREF, and soclose panics at this point. 798df8bae1dSRodney W. Grimes * 799df8bae1dSRodney W. Grimes * Here, we first take an extra reference to each inaccessible 800df8bae1dSRodney W. Grimes * descriptor. Then, we call sorflush ourself, since we know 801df8bae1dSRodney W. Grimes * it is a Unix domain socket anyhow. After we destroy all the 802df8bae1dSRodney W. Grimes * rights carried in messages, we do a last closef to get rid 803df8bae1dSRodney W. Grimes * of our extra reference. This is the last close, and the 804df8bae1dSRodney W. Grimes * unp_detach etc will shut down the socket. 805df8bae1dSRodney W. Grimes * 806df8bae1dSRodney W. Grimes * 91/09/19, bsy@cs.cmu.edu 807df8bae1dSRodney W. Grimes */ 808df8bae1dSRodney W. Grimes extra_ref = malloc(nfiles * sizeof(struct file *), M_FILE, M_WAITOK); 809df8bae1dSRodney W. Grimes for (nunref = 0, fp = filehead, fpp = extra_ref; fp; fp = nextfp) { 810df8bae1dSRodney W. Grimes nextfp = fp->f_filef; 811df8bae1dSRodney W. Grimes if (fp->f_count == 0) 812df8bae1dSRodney W. Grimes continue; 813df8bae1dSRodney W. Grimes if (fp->f_count == fp->f_msgcount && !(fp->f_flag & FMARK)) { 814df8bae1dSRodney W. Grimes *fpp++ = fp; 815df8bae1dSRodney W. Grimes nunref++; 816df8bae1dSRodney W. Grimes fp->f_count++; 817df8bae1dSRodney W. Grimes } 818df8bae1dSRodney W. Grimes } 819df8bae1dSRodney W. Grimes for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp) 820df8bae1dSRodney W. Grimes sorflush((struct socket *)(*fpp)->f_data); 821df8bae1dSRodney W. Grimes for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp) 82292cbac68SPoul-Henning Kamp closef(*fpp,(struct proc*) NULL); 823df8bae1dSRodney W. Grimes free((caddr_t)extra_ref, M_FILE); 824df8bae1dSRodney W. Grimes unp_gcing = 0; 825df8bae1dSRodney W. Grimes } 826df8bae1dSRodney W. Grimes 82726f9a767SRodney W. Grimes void 828df8bae1dSRodney W. Grimes unp_dispose(m) 829df8bae1dSRodney W. Grimes struct mbuf *m; 830df8bae1dSRodney W. Grimes { 831df8bae1dSRodney W. Grimes if (m) 832df8bae1dSRodney W. Grimes unp_scan(m, unp_discard); 833df8bae1dSRodney W. Grimes } 834df8bae1dSRodney W. Grimes 835f708ef1bSPoul-Henning Kamp static void 836df8bae1dSRodney W. Grimes unp_scan(m0, op) 837df8bae1dSRodney W. Grimes register struct mbuf *m0; 83826f9a767SRodney W. Grimes void (*op)(struct file *); 839df8bae1dSRodney W. Grimes { 840df8bae1dSRodney W. Grimes register struct mbuf *m; 841df8bae1dSRodney W. Grimes register struct file **rp; 842df8bae1dSRodney W. Grimes register struct cmsghdr *cm; 843df8bae1dSRodney W. Grimes register int i; 844df8bae1dSRodney W. Grimes int qfds; 845df8bae1dSRodney W. Grimes 846df8bae1dSRodney W. Grimes while (m0) { 847df8bae1dSRodney W. Grimes for (m = m0; m; m = m->m_next) 848df8bae1dSRodney W. Grimes if (m->m_type == MT_CONTROL && 849df8bae1dSRodney W. Grimes m->m_len >= sizeof(*cm)) { 850df8bae1dSRodney W. Grimes cm = mtod(m, struct cmsghdr *); 851df8bae1dSRodney W. Grimes if (cm->cmsg_level != SOL_SOCKET || 852df8bae1dSRodney W. Grimes cm->cmsg_type != SCM_RIGHTS) 853df8bae1dSRodney W. Grimes continue; 854df8bae1dSRodney W. Grimes qfds = (cm->cmsg_len - sizeof *cm) 855df8bae1dSRodney W. Grimes / sizeof (struct file *); 856df8bae1dSRodney W. Grimes rp = (struct file **)(cm + 1); 857df8bae1dSRodney W. Grimes for (i = 0; i < qfds; i++) 858df8bae1dSRodney W. Grimes (*op)(*rp++); 859df8bae1dSRodney W. Grimes break; /* XXX, but saves time */ 860df8bae1dSRodney W. Grimes } 861df8bae1dSRodney W. Grimes m0 = m0->m_act; 862df8bae1dSRodney W. Grimes } 863df8bae1dSRodney W. Grimes } 864df8bae1dSRodney W. Grimes 865f708ef1bSPoul-Henning Kamp static void 866df8bae1dSRodney W. Grimes unp_mark(fp) 867df8bae1dSRodney W. Grimes struct file *fp; 868df8bae1dSRodney W. Grimes { 869df8bae1dSRodney W. Grimes 870df8bae1dSRodney W. Grimes if (fp->f_flag & FMARK) 871df8bae1dSRodney W. Grimes return; 872df8bae1dSRodney W. Grimes unp_defer++; 873df8bae1dSRodney W. Grimes fp->f_flag |= (FMARK|FDEFER); 874df8bae1dSRodney W. Grimes } 875df8bae1dSRodney W. Grimes 876f708ef1bSPoul-Henning Kamp static void 877df8bae1dSRodney W. Grimes unp_discard(fp) 878df8bae1dSRodney W. Grimes struct file *fp; 879df8bae1dSRodney W. Grimes { 880df8bae1dSRodney W. Grimes 881df8bae1dSRodney W. Grimes fp->f_msgcount--; 882df8bae1dSRodney W. Grimes unp_rights--; 883df8bae1dSRodney W. Grimes (void) closef(fp, (struct proc *)NULL); 884df8bae1dSRodney W. Grimes } 885