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 * 33df8bae1dSRodney W. Grimes * @(#)uipc_usrreq.c 8.3 (Berkeley) 1/4/94 34797f2d22SPoul-Henning Kamp * $Id: uipc_usrreq.c,v 1.4 1994/09/28 19:55:10 phk 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 */ 62df8bae1dSRodney W. Grimes struct sockaddr sun_noname = { sizeof(sun_noname), AF_UNIX }; 63df8bae1dSRodney W. Grimes ino_t unp_ino; /* prototype for fake inode numbers */ 64df8bae1dSRodney W. Grimes 65df8bae1dSRodney W. Grimes /*ARGSUSED*/ 6626f9a767SRodney W. Grimes int 67df8bae1dSRodney W. Grimes uipc_usrreq(so, req, m, nam, control) 68df8bae1dSRodney W. Grimes struct socket *so; 69df8bae1dSRodney W. Grimes int req; 70df8bae1dSRodney W. Grimes struct mbuf *m, *nam, *control; 71df8bae1dSRodney W. Grimes { 72df8bae1dSRodney W. Grimes struct unpcb *unp = sotounpcb(so); 73df8bae1dSRodney W. Grimes register struct socket *so2; 74df8bae1dSRodney W. Grimes register int error = 0; 75df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 76df8bae1dSRodney W. Grimes 77df8bae1dSRodney W. Grimes if (req == PRU_CONTROL) 78df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 79df8bae1dSRodney W. Grimes if (req != PRU_SEND && control && control->m_len) { 80df8bae1dSRodney W. Grimes error = EOPNOTSUPP; 81df8bae1dSRodney W. Grimes goto release; 82df8bae1dSRodney W. Grimes } 83df8bae1dSRodney W. Grimes if (unp == 0 && req != PRU_ATTACH) { 84df8bae1dSRodney W. Grimes error = EINVAL; 85df8bae1dSRodney W. Grimes goto release; 86df8bae1dSRodney W. Grimes } 87df8bae1dSRodney W. Grimes switch (req) { 88df8bae1dSRodney W. Grimes 89df8bae1dSRodney W. Grimes case PRU_ATTACH: 90df8bae1dSRodney W. Grimes if (unp) { 91df8bae1dSRodney W. Grimes error = EISCONN; 92df8bae1dSRodney W. Grimes break; 93df8bae1dSRodney W. Grimes } 94df8bae1dSRodney W. Grimes error = unp_attach(so); 95df8bae1dSRodney W. Grimes break; 96df8bae1dSRodney W. Grimes 97df8bae1dSRodney W. Grimes case PRU_DETACH: 98df8bae1dSRodney W. Grimes unp_detach(unp); 99df8bae1dSRodney W. Grimes break; 100df8bae1dSRodney W. Grimes 101df8bae1dSRodney W. Grimes case PRU_BIND: 102df8bae1dSRodney W. Grimes error = unp_bind(unp, nam, p); 103df8bae1dSRodney W. Grimes break; 104df8bae1dSRodney W. Grimes 105df8bae1dSRodney W. Grimes case PRU_LISTEN: 106df8bae1dSRodney W. Grimes if (unp->unp_vnode == 0) 107df8bae1dSRodney W. Grimes error = EINVAL; 108df8bae1dSRodney W. Grimes break; 109df8bae1dSRodney W. Grimes 110df8bae1dSRodney W. Grimes case PRU_CONNECT: 111df8bae1dSRodney W. Grimes error = unp_connect(so, nam, p); 112df8bae1dSRodney W. Grimes break; 113df8bae1dSRodney W. Grimes 114df8bae1dSRodney W. Grimes case PRU_CONNECT2: 115df8bae1dSRodney W. Grimes error = unp_connect2(so, (struct socket *)nam); 116df8bae1dSRodney W. Grimes break; 117df8bae1dSRodney W. Grimes 118df8bae1dSRodney W. Grimes case PRU_DISCONNECT: 119df8bae1dSRodney W. Grimes unp_disconnect(unp); 120df8bae1dSRodney W. Grimes break; 121df8bae1dSRodney W. Grimes 122df8bae1dSRodney W. Grimes case PRU_ACCEPT: 123df8bae1dSRodney W. Grimes /* 124df8bae1dSRodney W. Grimes * Pass back name of connected socket, 125df8bae1dSRodney W. Grimes * if it was bound and we are still connected 126df8bae1dSRodney W. Grimes * (our peer may have closed already!). 127df8bae1dSRodney W. Grimes */ 128df8bae1dSRodney W. Grimes if (unp->unp_conn && unp->unp_conn->unp_addr) { 129df8bae1dSRodney W. Grimes nam->m_len = unp->unp_conn->unp_addr->m_len; 130df8bae1dSRodney W. Grimes bcopy(mtod(unp->unp_conn->unp_addr, caddr_t), 131df8bae1dSRodney W. Grimes mtod(nam, caddr_t), (unsigned)nam->m_len); 132df8bae1dSRodney W. Grimes } else { 133df8bae1dSRodney W. Grimes nam->m_len = sizeof(sun_noname); 134df8bae1dSRodney W. Grimes *(mtod(nam, struct sockaddr *)) = sun_noname; 135df8bae1dSRodney W. Grimes } 136df8bae1dSRodney W. Grimes break; 137df8bae1dSRodney W. Grimes 138df8bae1dSRodney W. Grimes case PRU_SHUTDOWN: 139df8bae1dSRodney W. Grimes socantsendmore(so); 140df8bae1dSRodney W. Grimes unp_shutdown(unp); 141df8bae1dSRodney W. Grimes break; 142df8bae1dSRodney W. Grimes 143df8bae1dSRodney W. Grimes case PRU_RCVD: 144df8bae1dSRodney W. Grimes switch (so->so_type) { 145df8bae1dSRodney W. Grimes 146df8bae1dSRodney W. Grimes case SOCK_DGRAM: 147df8bae1dSRodney W. Grimes panic("uipc 1"); 148df8bae1dSRodney W. Grimes /*NOTREACHED*/ 149df8bae1dSRodney W. Grimes 150df8bae1dSRodney W. Grimes case SOCK_STREAM: 151df8bae1dSRodney W. Grimes #define rcv (&so->so_rcv) 152df8bae1dSRodney W. Grimes #define snd (&so2->so_snd) 153df8bae1dSRodney W. Grimes if (unp->unp_conn == 0) 154df8bae1dSRodney W. Grimes break; 155df8bae1dSRodney W. Grimes so2 = unp->unp_conn->unp_socket; 156df8bae1dSRodney W. Grimes /* 157df8bae1dSRodney W. Grimes * Adjust backpressure on sender 158df8bae1dSRodney W. Grimes * and wakeup any waiting to write. 159df8bae1dSRodney W. Grimes */ 160df8bae1dSRodney W. Grimes snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt; 161df8bae1dSRodney W. Grimes unp->unp_mbcnt = rcv->sb_mbcnt; 162df8bae1dSRodney W. Grimes snd->sb_hiwat += unp->unp_cc - rcv->sb_cc; 163df8bae1dSRodney W. Grimes unp->unp_cc = rcv->sb_cc; 164df8bae1dSRodney W. Grimes sowwakeup(so2); 165df8bae1dSRodney W. Grimes #undef snd 166df8bae1dSRodney W. Grimes #undef rcv 167df8bae1dSRodney W. Grimes break; 168df8bae1dSRodney W. Grimes 169df8bae1dSRodney W. Grimes default: 170df8bae1dSRodney W. Grimes panic("uipc 2"); 171df8bae1dSRodney W. Grimes } 172df8bae1dSRodney W. Grimes break; 173df8bae1dSRodney W. Grimes 174df8bae1dSRodney W. Grimes case PRU_SEND: 175df8bae1dSRodney W. Grimes if (control && (error = unp_internalize(control, p))) 176df8bae1dSRodney W. Grimes break; 177df8bae1dSRodney W. Grimes switch (so->so_type) { 178df8bae1dSRodney W. Grimes 179df8bae1dSRodney W. Grimes case SOCK_DGRAM: { 180df8bae1dSRodney W. Grimes struct sockaddr *from; 181df8bae1dSRodney W. Grimes 182df8bae1dSRodney W. Grimes if (nam) { 183df8bae1dSRodney W. Grimes if (unp->unp_conn) { 184df8bae1dSRodney W. Grimes error = EISCONN; 185df8bae1dSRodney W. Grimes break; 186df8bae1dSRodney W. Grimes } 187df8bae1dSRodney W. Grimes error = unp_connect(so, nam, p); 188df8bae1dSRodney W. Grimes if (error) 189df8bae1dSRodney W. Grimes break; 190df8bae1dSRodney W. Grimes } else { 191df8bae1dSRodney W. Grimes if (unp->unp_conn == 0) { 192df8bae1dSRodney W. Grimes error = ENOTCONN; 193df8bae1dSRodney W. Grimes break; 194df8bae1dSRodney W. Grimes } 195df8bae1dSRodney W. Grimes } 196df8bae1dSRodney W. Grimes so2 = unp->unp_conn->unp_socket; 197df8bae1dSRodney W. Grimes if (unp->unp_addr) 198df8bae1dSRodney W. Grimes from = mtod(unp->unp_addr, struct sockaddr *); 199df8bae1dSRodney W. Grimes else 200df8bae1dSRodney W. Grimes from = &sun_noname; 201df8bae1dSRodney W. Grimes if (sbappendaddr(&so2->so_rcv, from, m, control)) { 202df8bae1dSRodney W. Grimes sorwakeup(so2); 203df8bae1dSRodney W. Grimes m = 0; 204df8bae1dSRodney W. Grimes control = 0; 205df8bae1dSRodney W. Grimes } else 206df8bae1dSRodney W. Grimes error = ENOBUFS; 207df8bae1dSRodney W. Grimes if (nam) 208df8bae1dSRodney W. Grimes unp_disconnect(unp); 209df8bae1dSRodney W. Grimes break; 210df8bae1dSRodney W. Grimes } 211df8bae1dSRodney W. Grimes 212df8bae1dSRodney W. Grimes case SOCK_STREAM: 213df8bae1dSRodney W. Grimes #define rcv (&so2->so_rcv) 214df8bae1dSRodney W. Grimes #define snd (&so->so_snd) 215df8bae1dSRodney W. Grimes if (so->so_state & SS_CANTSENDMORE) { 216df8bae1dSRodney W. Grimes error = EPIPE; 217df8bae1dSRodney W. Grimes break; 218df8bae1dSRodney W. Grimes } 219df8bae1dSRodney W. Grimes if (unp->unp_conn == 0) 220df8bae1dSRodney W. Grimes panic("uipc 3"); 221df8bae1dSRodney W. Grimes so2 = unp->unp_conn->unp_socket; 222df8bae1dSRodney W. Grimes /* 223df8bae1dSRodney W. Grimes * Send to paired receive port, and then reduce 224df8bae1dSRodney W. Grimes * send buffer hiwater marks to maintain backpressure. 225df8bae1dSRodney W. Grimes * Wake up readers. 226df8bae1dSRodney W. Grimes */ 227df8bae1dSRodney W. Grimes if (control) { 228df8bae1dSRodney W. Grimes if (sbappendcontrol(rcv, m, control)) 229df8bae1dSRodney W. Grimes control = 0; 230df8bae1dSRodney W. Grimes } else 231df8bae1dSRodney W. Grimes sbappend(rcv, m); 232df8bae1dSRodney W. Grimes snd->sb_mbmax -= 233df8bae1dSRodney W. Grimes rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt; 234df8bae1dSRodney W. Grimes unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt; 235df8bae1dSRodney W. Grimes snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc; 236df8bae1dSRodney W. Grimes unp->unp_conn->unp_cc = rcv->sb_cc; 237df8bae1dSRodney W. Grimes sorwakeup(so2); 238df8bae1dSRodney W. Grimes m = 0; 239df8bae1dSRodney W. Grimes #undef snd 240df8bae1dSRodney W. Grimes #undef rcv 241df8bae1dSRodney W. Grimes break; 242df8bae1dSRodney W. Grimes 243df8bae1dSRodney W. Grimes default: 244df8bae1dSRodney W. Grimes panic("uipc 4"); 245df8bae1dSRodney W. Grimes } 246df8bae1dSRodney W. Grimes break; 247df8bae1dSRodney W. Grimes 248df8bae1dSRodney W. Grimes case PRU_ABORT: 249df8bae1dSRodney W. Grimes unp_drop(unp, ECONNABORTED); 250df8bae1dSRodney W. Grimes break; 251df8bae1dSRodney W. Grimes 252df8bae1dSRodney W. Grimes case PRU_SENSE: 253df8bae1dSRodney W. Grimes ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat; 254df8bae1dSRodney W. Grimes if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) { 255df8bae1dSRodney W. Grimes so2 = unp->unp_conn->unp_socket; 256df8bae1dSRodney W. Grimes ((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc; 257df8bae1dSRodney W. Grimes } 258df8bae1dSRodney W. Grimes ((struct stat *) m)->st_dev = NODEV; 259df8bae1dSRodney W. Grimes if (unp->unp_ino == 0) 260df8bae1dSRodney W. Grimes unp->unp_ino = unp_ino++; 261df8bae1dSRodney W. Grimes ((struct stat *) m)->st_ino = unp->unp_ino; 262df8bae1dSRodney W. Grimes return (0); 263df8bae1dSRodney W. Grimes 264df8bae1dSRodney W. Grimes case PRU_RCVOOB: 265df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 266df8bae1dSRodney W. Grimes 267df8bae1dSRodney W. Grimes case PRU_SENDOOB: 268df8bae1dSRodney W. Grimes error = EOPNOTSUPP; 269df8bae1dSRodney W. Grimes break; 270df8bae1dSRodney W. Grimes 271df8bae1dSRodney W. Grimes case PRU_SOCKADDR: 272df8bae1dSRodney W. Grimes if (unp->unp_addr) { 273df8bae1dSRodney W. Grimes nam->m_len = unp->unp_addr->m_len; 274df8bae1dSRodney W. Grimes bcopy(mtod(unp->unp_addr, caddr_t), 275df8bae1dSRodney W. Grimes mtod(nam, caddr_t), (unsigned)nam->m_len); 276df8bae1dSRodney W. Grimes } else 277df8bae1dSRodney W. Grimes nam->m_len = 0; 278df8bae1dSRodney W. Grimes break; 279df8bae1dSRodney W. Grimes 280df8bae1dSRodney W. Grimes case PRU_PEERADDR: 281df8bae1dSRodney W. Grimes if (unp->unp_conn && unp->unp_conn->unp_addr) { 282df8bae1dSRodney W. Grimes nam->m_len = unp->unp_conn->unp_addr->m_len; 283df8bae1dSRodney W. Grimes bcopy(mtod(unp->unp_conn->unp_addr, caddr_t), 284df8bae1dSRodney W. Grimes mtod(nam, caddr_t), (unsigned)nam->m_len); 285df8bae1dSRodney W. Grimes } else 286df8bae1dSRodney W. Grimes nam->m_len = 0; 287df8bae1dSRodney W. Grimes break; 288df8bae1dSRodney W. Grimes 289df8bae1dSRodney W. Grimes case PRU_SLOWTIMO: 290df8bae1dSRodney W. Grimes break; 291df8bae1dSRodney W. Grimes 292df8bae1dSRodney W. Grimes default: 293df8bae1dSRodney W. Grimes panic("piusrreq"); 294df8bae1dSRodney W. Grimes } 295df8bae1dSRodney W. Grimes release: 296df8bae1dSRodney W. Grimes if (control) 297df8bae1dSRodney W. Grimes m_freem(control); 298df8bae1dSRodney W. Grimes if (m) 299df8bae1dSRodney W. Grimes m_freem(m); 300df8bae1dSRodney W. Grimes return (error); 301df8bae1dSRodney W. Grimes } 302df8bae1dSRodney W. Grimes 303df8bae1dSRodney W. Grimes /* 304df8bae1dSRodney W. Grimes * Both send and receive buffers are allocated PIPSIZ bytes of buffering 305df8bae1dSRodney W. Grimes * for stream sockets, although the total for sender and receiver is 306df8bae1dSRodney W. Grimes * actually only PIPSIZ. 307df8bae1dSRodney W. Grimes * Datagram sockets really use the sendspace as the maximum datagram size, 308df8bae1dSRodney W. Grimes * and don't really want to reserve the sendspace. Their recvspace should 309df8bae1dSRodney W. Grimes * be large enough for at least one max-size datagram plus address. 310df8bae1dSRodney W. Grimes */ 311df8bae1dSRodney W. Grimes #define PIPSIZ 4096 312df8bae1dSRodney W. Grimes u_long unpst_sendspace = PIPSIZ; 313df8bae1dSRodney W. Grimes u_long unpst_recvspace = PIPSIZ; 314df8bae1dSRodney W. Grimes u_long unpdg_sendspace = 2*1024; /* really max datagram size */ 315df8bae1dSRodney W. Grimes u_long unpdg_recvspace = 4*1024; 316df8bae1dSRodney W. Grimes 317df8bae1dSRodney W. Grimes int unp_rights; /* file descriptors in flight */ 318df8bae1dSRodney W. Grimes 31926f9a767SRodney W. Grimes int 320df8bae1dSRodney W. Grimes unp_attach(so) 321df8bae1dSRodney W. Grimes struct socket *so; 322df8bae1dSRodney W. Grimes { 323df8bae1dSRodney W. Grimes register struct mbuf *m; 324df8bae1dSRodney W. Grimes register struct unpcb *unp; 325df8bae1dSRodney W. Grimes int error; 326df8bae1dSRodney W. Grimes 327df8bae1dSRodney W. Grimes if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 328df8bae1dSRodney W. Grimes switch (so->so_type) { 329df8bae1dSRodney W. Grimes 330df8bae1dSRodney W. Grimes case SOCK_STREAM: 331df8bae1dSRodney W. Grimes error = soreserve(so, unpst_sendspace, unpst_recvspace); 332df8bae1dSRodney W. Grimes break; 333df8bae1dSRodney W. Grimes 334df8bae1dSRodney W. Grimes case SOCK_DGRAM: 335df8bae1dSRodney W. Grimes error = soreserve(so, unpdg_sendspace, unpdg_recvspace); 336df8bae1dSRodney W. Grimes break; 337df8bae1dSRodney W. Grimes 338df8bae1dSRodney W. Grimes default: 339df8bae1dSRodney W. Grimes panic("unp_attach"); 340df8bae1dSRodney W. Grimes } 341df8bae1dSRodney W. Grimes if (error) 342df8bae1dSRodney W. Grimes return (error); 343df8bae1dSRodney W. Grimes } 344df8bae1dSRodney W. Grimes m = m_getclr(M_DONTWAIT, MT_PCB); 345df8bae1dSRodney W. Grimes if (m == NULL) 346df8bae1dSRodney W. Grimes return (ENOBUFS); 347df8bae1dSRodney W. Grimes unp = mtod(m, struct unpcb *); 348df8bae1dSRodney W. Grimes so->so_pcb = (caddr_t)unp; 349df8bae1dSRodney W. Grimes unp->unp_socket = so; 350df8bae1dSRodney W. Grimes return (0); 351df8bae1dSRodney W. Grimes } 352df8bae1dSRodney W. Grimes 35326f9a767SRodney W. Grimes void 354df8bae1dSRodney W. Grimes unp_detach(unp) 355df8bae1dSRodney W. Grimes register struct unpcb *unp; 356df8bae1dSRodney W. Grimes { 357df8bae1dSRodney W. Grimes 358df8bae1dSRodney W. Grimes if (unp->unp_vnode) { 359df8bae1dSRodney W. Grimes unp->unp_vnode->v_socket = 0; 360df8bae1dSRodney W. Grimes vrele(unp->unp_vnode); 361df8bae1dSRodney W. Grimes unp->unp_vnode = 0; 362df8bae1dSRodney W. Grimes } 363df8bae1dSRodney W. Grimes if (unp->unp_conn) 364df8bae1dSRodney W. Grimes unp_disconnect(unp); 365df8bae1dSRodney W. Grimes while (unp->unp_refs) 366df8bae1dSRodney W. Grimes unp_drop(unp->unp_refs, ECONNRESET); 367df8bae1dSRodney W. Grimes soisdisconnected(unp->unp_socket); 368df8bae1dSRodney W. Grimes unp->unp_socket->so_pcb = 0; 369df8bae1dSRodney W. Grimes m_freem(unp->unp_addr); 370df8bae1dSRodney W. Grimes (void) m_free(dtom(unp)); 371df8bae1dSRodney W. Grimes if (unp_rights) { 372df8bae1dSRodney W. Grimes /* 373df8bae1dSRodney W. Grimes * Normally the receive buffer is flushed later, 374df8bae1dSRodney W. Grimes * in sofree, but if our receive buffer holds references 375df8bae1dSRodney W. Grimes * to descriptors that are now garbage, we will dispose 376df8bae1dSRodney W. Grimes * of those descriptor references after the garbage collector 377df8bae1dSRodney W. Grimes * gets them (resulting in a "panic: closef: count < 0"). 378df8bae1dSRodney W. Grimes */ 379df8bae1dSRodney W. Grimes sorflush(unp->unp_socket); 380df8bae1dSRodney W. Grimes unp_gc(); 381df8bae1dSRodney W. Grimes } 382df8bae1dSRodney W. Grimes } 383df8bae1dSRodney W. Grimes 38426f9a767SRodney W. Grimes int 385df8bae1dSRodney W. Grimes unp_bind(unp, nam, p) 386df8bae1dSRodney W. Grimes struct unpcb *unp; 387df8bae1dSRodney W. Grimes struct mbuf *nam; 388df8bae1dSRodney W. Grimes struct proc *p; 389df8bae1dSRodney W. Grimes { 390df8bae1dSRodney W. Grimes struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 391df8bae1dSRodney W. Grimes register struct vnode *vp; 392df8bae1dSRodney W. Grimes struct vattr vattr; 393df8bae1dSRodney W. Grimes int error; 394df8bae1dSRodney W. Grimes struct nameidata nd; 395df8bae1dSRodney W. Grimes 396df8bae1dSRodney W. Grimes NDINIT(&nd, CREATE, FOLLOW | LOCKPARENT, UIO_SYSSPACE, 397df8bae1dSRodney W. Grimes soun->sun_path, p); 398df8bae1dSRodney W. Grimes if (unp->unp_vnode != NULL) 399df8bae1dSRodney W. Grimes return (EINVAL); 400df8bae1dSRodney W. Grimes if (nam->m_len == MLEN) { 401df8bae1dSRodney W. Grimes if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0) 402df8bae1dSRodney W. Grimes return (EINVAL); 403df8bae1dSRodney W. Grimes } else 404df8bae1dSRodney W. Grimes *(mtod(nam, caddr_t) + nam->m_len) = 0; 405df8bae1dSRodney W. Grimes /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ 406797f2d22SPoul-Henning Kamp error = namei(&nd); 407797f2d22SPoul-Henning Kamp if (error) 408df8bae1dSRodney W. Grimes return (error); 409df8bae1dSRodney W. Grimes vp = nd.ni_vp; 410df8bae1dSRodney W. Grimes if (vp != NULL) { 411df8bae1dSRodney W. Grimes VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 412df8bae1dSRodney W. Grimes if (nd.ni_dvp == vp) 413df8bae1dSRodney W. Grimes vrele(nd.ni_dvp); 414df8bae1dSRodney W. Grimes else 415df8bae1dSRodney W. Grimes vput(nd.ni_dvp); 416df8bae1dSRodney W. Grimes vrele(vp); 417df8bae1dSRodney W. Grimes return (EADDRINUSE); 418df8bae1dSRodney W. Grimes } 419df8bae1dSRodney W. Grimes VATTR_NULL(&vattr); 420df8bae1dSRodney W. Grimes vattr.va_type = VSOCK; 421df8bae1dSRodney W. Grimes vattr.va_mode = ACCESSPERMS; 422df8bae1dSRodney W. Grimes LEASE_CHECK(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 423797f2d22SPoul-Henning Kamp error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); 424797f2d22SPoul-Henning Kamp if (error) 425df8bae1dSRodney W. Grimes return (error); 426df8bae1dSRodney W. Grimes vp = nd.ni_vp; 427df8bae1dSRodney W. Grimes vp->v_socket = unp->unp_socket; 428df8bae1dSRodney W. Grimes unp->unp_vnode = vp; 429df8bae1dSRodney W. Grimes unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL); 430df8bae1dSRodney W. Grimes VOP_UNLOCK(vp); 431df8bae1dSRodney W. Grimes return (0); 432df8bae1dSRodney W. Grimes } 433df8bae1dSRodney W. Grimes 43426f9a767SRodney W. Grimes int 435df8bae1dSRodney W. Grimes unp_connect(so, nam, p) 436df8bae1dSRodney W. Grimes struct socket *so; 437df8bae1dSRodney W. Grimes struct mbuf *nam; 438df8bae1dSRodney W. Grimes struct proc *p; 439df8bae1dSRodney W. Grimes { 440df8bae1dSRodney W. Grimes register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 441df8bae1dSRodney W. Grimes register struct vnode *vp; 442df8bae1dSRodney W. Grimes register struct socket *so2, *so3; 443df8bae1dSRodney W. Grimes struct unpcb *unp2, *unp3; 444df8bae1dSRodney W. Grimes int error; 445df8bae1dSRodney W. Grimes struct nameidata nd; 446df8bae1dSRodney W. Grimes 447df8bae1dSRodney W. Grimes NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, soun->sun_path, p); 448df8bae1dSRodney W. Grimes if (nam->m_data + nam->m_len == &nam->m_dat[MLEN]) { /* XXX */ 449df8bae1dSRodney W. Grimes if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0) 450df8bae1dSRodney W. Grimes return (EMSGSIZE); 451df8bae1dSRodney W. Grimes } else 452df8bae1dSRodney W. Grimes *(mtod(nam, caddr_t) + nam->m_len) = 0; 453797f2d22SPoul-Henning Kamp error = namei(&nd); 454797f2d22SPoul-Henning Kamp if (error) 455df8bae1dSRodney W. Grimes return (error); 456df8bae1dSRodney W. Grimes vp = nd.ni_vp; 457df8bae1dSRodney W. Grimes if (vp->v_type != VSOCK) { 458df8bae1dSRodney W. Grimes error = ENOTSOCK; 459df8bae1dSRodney W. Grimes goto bad; 460df8bae1dSRodney W. Grimes } 461797f2d22SPoul-Henning Kamp error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p); 462797f2d22SPoul-Henning Kamp if (error) 463df8bae1dSRodney W. Grimes goto bad; 464df8bae1dSRodney W. Grimes so2 = vp->v_socket; 465df8bae1dSRodney W. Grimes if (so2 == 0) { 466df8bae1dSRodney W. Grimes error = ECONNREFUSED; 467df8bae1dSRodney W. Grimes goto bad; 468df8bae1dSRodney W. Grimes } 469df8bae1dSRodney W. Grimes if (so->so_type != so2->so_type) { 470df8bae1dSRodney W. Grimes error = EPROTOTYPE; 471df8bae1dSRodney W. Grimes goto bad; 472df8bae1dSRodney W. Grimes } 473df8bae1dSRodney W. Grimes if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 474df8bae1dSRodney W. Grimes if ((so2->so_options & SO_ACCEPTCONN) == 0 || 475df8bae1dSRodney W. Grimes (so3 = sonewconn(so2, 0)) == 0) { 476df8bae1dSRodney W. Grimes error = ECONNREFUSED; 477df8bae1dSRodney W. Grimes goto bad; 478df8bae1dSRodney W. Grimes } 479df8bae1dSRodney W. Grimes unp2 = sotounpcb(so2); 480df8bae1dSRodney W. Grimes unp3 = sotounpcb(so3); 481df8bae1dSRodney W. Grimes if (unp2->unp_addr) 482df8bae1dSRodney W. Grimes unp3->unp_addr = 483df8bae1dSRodney W. Grimes m_copy(unp2->unp_addr, 0, (int)M_COPYALL); 484df8bae1dSRodney W. Grimes so2 = so3; 485df8bae1dSRodney W. Grimes } 486df8bae1dSRodney W. Grimes error = unp_connect2(so, so2); 487df8bae1dSRodney W. Grimes bad: 488df8bae1dSRodney W. Grimes vput(vp); 489df8bae1dSRodney W. Grimes return (error); 490df8bae1dSRodney W. Grimes } 491df8bae1dSRodney W. Grimes 49226f9a767SRodney W. Grimes int 493df8bae1dSRodney W. Grimes unp_connect2(so, so2) 494df8bae1dSRodney W. Grimes register struct socket *so; 495df8bae1dSRodney W. Grimes register struct socket *so2; 496df8bae1dSRodney W. Grimes { 497df8bae1dSRodney W. Grimes register struct unpcb *unp = sotounpcb(so); 498df8bae1dSRodney W. Grimes register struct unpcb *unp2; 499df8bae1dSRodney W. Grimes 500df8bae1dSRodney W. Grimes if (so2->so_type != so->so_type) 501df8bae1dSRodney W. Grimes return (EPROTOTYPE); 502df8bae1dSRodney W. Grimes unp2 = sotounpcb(so2); 503df8bae1dSRodney W. Grimes unp->unp_conn = unp2; 504df8bae1dSRodney W. Grimes switch (so->so_type) { 505df8bae1dSRodney W. Grimes 506df8bae1dSRodney W. Grimes case SOCK_DGRAM: 507df8bae1dSRodney W. Grimes unp->unp_nextref = unp2->unp_refs; 508df8bae1dSRodney W. Grimes unp2->unp_refs = unp; 509df8bae1dSRodney W. Grimes soisconnected(so); 510df8bae1dSRodney W. Grimes break; 511df8bae1dSRodney W. Grimes 512df8bae1dSRodney W. Grimes case SOCK_STREAM: 513df8bae1dSRodney W. Grimes unp2->unp_conn = unp; 514df8bae1dSRodney W. Grimes soisconnected(so); 515df8bae1dSRodney W. Grimes soisconnected(so2); 516df8bae1dSRodney W. Grimes break; 517df8bae1dSRodney W. Grimes 518df8bae1dSRodney W. Grimes default: 519df8bae1dSRodney W. Grimes panic("unp_connect2"); 520df8bae1dSRodney W. Grimes } 521df8bae1dSRodney W. Grimes return (0); 522df8bae1dSRodney W. Grimes } 523df8bae1dSRodney W. Grimes 52426f9a767SRodney W. Grimes void 525df8bae1dSRodney W. Grimes unp_disconnect(unp) 526df8bae1dSRodney W. Grimes struct unpcb *unp; 527df8bae1dSRodney W. Grimes { 528df8bae1dSRodney W. Grimes register struct unpcb *unp2 = unp->unp_conn; 529df8bae1dSRodney W. Grimes 530df8bae1dSRodney W. Grimes if (unp2 == 0) 531df8bae1dSRodney W. Grimes return; 532df8bae1dSRodney W. Grimes unp->unp_conn = 0; 533df8bae1dSRodney W. Grimes switch (unp->unp_socket->so_type) { 534df8bae1dSRodney W. Grimes 535df8bae1dSRodney W. Grimes case SOCK_DGRAM: 536df8bae1dSRodney W. Grimes if (unp2->unp_refs == unp) 537df8bae1dSRodney W. Grimes unp2->unp_refs = unp->unp_nextref; 538df8bae1dSRodney W. Grimes else { 539df8bae1dSRodney W. Grimes unp2 = unp2->unp_refs; 540df8bae1dSRodney W. Grimes for (;;) { 541df8bae1dSRodney W. Grimes if (unp2 == 0) 542df8bae1dSRodney W. Grimes panic("unp_disconnect"); 543df8bae1dSRodney W. Grimes if (unp2->unp_nextref == unp) 544df8bae1dSRodney W. Grimes break; 545df8bae1dSRodney W. Grimes unp2 = unp2->unp_nextref; 546df8bae1dSRodney W. Grimes } 547df8bae1dSRodney W. Grimes unp2->unp_nextref = unp->unp_nextref; 548df8bae1dSRodney W. Grimes } 549df8bae1dSRodney W. Grimes unp->unp_nextref = 0; 550df8bae1dSRodney W. Grimes unp->unp_socket->so_state &= ~SS_ISCONNECTED; 551df8bae1dSRodney W. Grimes break; 552df8bae1dSRodney W. Grimes 553df8bae1dSRodney W. Grimes case SOCK_STREAM: 554df8bae1dSRodney W. Grimes soisdisconnected(unp->unp_socket); 555df8bae1dSRodney W. Grimes unp2->unp_conn = 0; 556df8bae1dSRodney W. Grimes soisdisconnected(unp2->unp_socket); 557df8bae1dSRodney W. Grimes break; 558df8bae1dSRodney W. Grimes } 559df8bae1dSRodney W. Grimes } 560df8bae1dSRodney W. Grimes 561df8bae1dSRodney W. Grimes #ifdef notdef 56226f9a767SRodney W. Grimes void 563df8bae1dSRodney W. Grimes unp_abort(unp) 564df8bae1dSRodney W. Grimes struct unpcb *unp; 565df8bae1dSRodney W. Grimes { 566df8bae1dSRodney W. Grimes 567df8bae1dSRodney W. Grimes unp_detach(unp); 568df8bae1dSRodney W. Grimes } 569df8bae1dSRodney W. Grimes #endif 570df8bae1dSRodney W. Grimes 57126f9a767SRodney W. Grimes void 572df8bae1dSRodney W. Grimes unp_shutdown(unp) 573df8bae1dSRodney W. Grimes struct unpcb *unp; 574df8bae1dSRodney W. Grimes { 575df8bae1dSRodney W. Grimes struct socket *so; 576df8bae1dSRodney W. Grimes 577df8bae1dSRodney W. Grimes if (unp->unp_socket->so_type == SOCK_STREAM && unp->unp_conn && 578df8bae1dSRodney W. Grimes (so = unp->unp_conn->unp_socket)) 579df8bae1dSRodney W. Grimes socantrcvmore(so); 580df8bae1dSRodney W. Grimes } 581df8bae1dSRodney W. Grimes 58226f9a767SRodney W. Grimes void 583df8bae1dSRodney W. Grimes unp_drop(unp, errno) 584df8bae1dSRodney W. Grimes struct unpcb *unp; 585df8bae1dSRodney W. Grimes int errno; 586df8bae1dSRodney W. Grimes { 587df8bae1dSRodney W. Grimes struct socket *so = unp->unp_socket; 588df8bae1dSRodney W. Grimes 589df8bae1dSRodney W. Grimes so->so_error = errno; 590df8bae1dSRodney W. Grimes unp_disconnect(unp); 591df8bae1dSRodney W. Grimes if (so->so_head) { 592df8bae1dSRodney W. Grimes so->so_pcb = (caddr_t) 0; 593df8bae1dSRodney W. Grimes m_freem(unp->unp_addr); 594df8bae1dSRodney W. Grimes (void) m_free(dtom(unp)); 595df8bae1dSRodney W. Grimes sofree(so); 596df8bae1dSRodney W. Grimes } 597df8bae1dSRodney W. Grimes } 598df8bae1dSRodney W. Grimes 599df8bae1dSRodney W. Grimes #ifdef notdef 60026f9a767SRodney W. Grimes void 601df8bae1dSRodney W. Grimes unp_drain() 602df8bae1dSRodney W. Grimes { 603df8bae1dSRodney W. Grimes 604df8bae1dSRodney W. Grimes } 605df8bae1dSRodney W. Grimes #endif 606df8bae1dSRodney W. Grimes 60726f9a767SRodney W. Grimes int 608df8bae1dSRodney W. Grimes unp_externalize(rights) 609df8bae1dSRodney W. Grimes struct mbuf *rights; 610df8bae1dSRodney W. Grimes { 611df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 612df8bae1dSRodney W. Grimes register int i; 613df8bae1dSRodney W. Grimes register struct cmsghdr *cm = mtod(rights, struct cmsghdr *); 614df8bae1dSRodney W. Grimes register struct file **rp = (struct file **)(cm + 1); 615df8bae1dSRodney W. Grimes register struct file *fp; 616df8bae1dSRodney W. Grimes int newfds = (cm->cmsg_len - sizeof(*cm)) / sizeof (int); 617df8bae1dSRodney W. Grimes int f; 618df8bae1dSRodney W. Grimes 619df8bae1dSRodney W. Grimes if (!fdavail(p, newfds)) { 620df8bae1dSRodney W. Grimes for (i = 0; i < newfds; i++) { 621df8bae1dSRodney W. Grimes fp = *rp; 622df8bae1dSRodney W. Grimes unp_discard(fp); 623df8bae1dSRodney W. Grimes *rp++ = 0; 624df8bae1dSRodney W. Grimes } 625df8bae1dSRodney W. Grimes return (EMSGSIZE); 626df8bae1dSRodney W. Grimes } 627df8bae1dSRodney W. Grimes for (i = 0; i < newfds; i++) { 628df8bae1dSRodney W. Grimes if (fdalloc(p, 0, &f)) 629df8bae1dSRodney W. Grimes panic("unp_externalize"); 630df8bae1dSRodney W. Grimes fp = *rp; 631df8bae1dSRodney W. Grimes p->p_fd->fd_ofiles[f] = fp; 632df8bae1dSRodney W. Grimes fp->f_msgcount--; 633df8bae1dSRodney W. Grimes unp_rights--; 634df8bae1dSRodney W. Grimes *(int *)rp++ = f; 635df8bae1dSRodney W. Grimes } 636df8bae1dSRodney W. Grimes return (0); 637df8bae1dSRodney W. Grimes } 638df8bae1dSRodney W. Grimes 63926f9a767SRodney W. Grimes int 640df8bae1dSRodney W. Grimes unp_internalize(control, p) 641df8bae1dSRodney W. Grimes struct mbuf *control; 642df8bae1dSRodney W. Grimes struct proc *p; 643df8bae1dSRodney W. Grimes { 644df8bae1dSRodney W. Grimes struct filedesc *fdp = p->p_fd; 645df8bae1dSRodney W. Grimes register struct cmsghdr *cm = mtod(control, struct cmsghdr *); 646df8bae1dSRodney W. Grimes register struct file **rp; 647df8bae1dSRodney W. Grimes register struct file *fp; 648df8bae1dSRodney W. Grimes register int i, fd; 649df8bae1dSRodney W. Grimes int oldfds; 650df8bae1dSRodney W. Grimes 651df8bae1dSRodney W. Grimes if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET || 652df8bae1dSRodney W. Grimes cm->cmsg_len != control->m_len) 653df8bae1dSRodney W. Grimes return (EINVAL); 654df8bae1dSRodney W. Grimes oldfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int); 655df8bae1dSRodney W. Grimes rp = (struct file **)(cm + 1); 656df8bae1dSRodney W. Grimes for (i = 0; i < oldfds; i++) { 657df8bae1dSRodney W. Grimes fd = *(int *)rp++; 658df8bae1dSRodney W. Grimes if ((unsigned)fd >= fdp->fd_nfiles || 659df8bae1dSRodney W. Grimes fdp->fd_ofiles[fd] == NULL) 660df8bae1dSRodney W. Grimes return (EBADF); 661df8bae1dSRodney W. Grimes } 662df8bae1dSRodney W. Grimes rp = (struct file **)(cm + 1); 663df8bae1dSRodney W. Grimes for (i = 0; i < oldfds; i++) { 664df8bae1dSRodney W. Grimes fp = fdp->fd_ofiles[*(int *)rp]; 665df8bae1dSRodney W. Grimes *rp++ = fp; 666df8bae1dSRodney W. Grimes fp->f_count++; 667df8bae1dSRodney W. Grimes fp->f_msgcount++; 668df8bae1dSRodney W. Grimes unp_rights++; 669df8bae1dSRodney W. Grimes } 670df8bae1dSRodney W. Grimes return (0); 671df8bae1dSRodney W. Grimes } 672df8bae1dSRodney W. Grimes 673df8bae1dSRodney W. Grimes int unp_defer, unp_gcing; 674df8bae1dSRodney W. Grimes extern struct domain unixdomain; 675df8bae1dSRodney W. Grimes 67626f9a767SRodney W. Grimes void 677df8bae1dSRodney W. Grimes unp_gc() 678df8bae1dSRodney W. Grimes { 679df8bae1dSRodney W. Grimes register struct file *fp, *nextfp; 680df8bae1dSRodney W. Grimes register struct socket *so; 681df8bae1dSRodney W. Grimes struct file **extra_ref, **fpp; 682df8bae1dSRodney W. Grimes int nunref, i; 683df8bae1dSRodney W. Grimes 684df8bae1dSRodney W. Grimes if (unp_gcing) 685df8bae1dSRodney W. Grimes return; 686df8bae1dSRodney W. Grimes unp_gcing = 1; 687df8bae1dSRodney W. Grimes unp_defer = 0; 688df8bae1dSRodney W. Grimes for (fp = filehead; fp; fp = fp->f_filef) 689df8bae1dSRodney W. Grimes fp->f_flag &= ~(FMARK|FDEFER); 690df8bae1dSRodney W. Grimes do { 691df8bae1dSRodney W. Grimes for (fp = filehead; fp; fp = fp->f_filef) { 692df8bae1dSRodney W. Grimes if (fp->f_count == 0) 693df8bae1dSRodney W. Grimes continue; 694df8bae1dSRodney W. Grimes if (fp->f_flag & FDEFER) { 695df8bae1dSRodney W. Grimes fp->f_flag &= ~FDEFER; 696df8bae1dSRodney W. Grimes unp_defer--; 697df8bae1dSRodney W. Grimes } else { 698df8bae1dSRodney W. Grimes if (fp->f_flag & FMARK) 699df8bae1dSRodney W. Grimes continue; 700df8bae1dSRodney W. Grimes if (fp->f_count == fp->f_msgcount) 701df8bae1dSRodney W. Grimes continue; 702df8bae1dSRodney W. Grimes fp->f_flag |= FMARK; 703df8bae1dSRodney W. Grimes } 704df8bae1dSRodney W. Grimes if (fp->f_type != DTYPE_SOCKET || 705df8bae1dSRodney W. Grimes (so = (struct socket *)fp->f_data) == 0) 706df8bae1dSRodney W. Grimes continue; 707df8bae1dSRodney W. Grimes if (so->so_proto->pr_domain != &unixdomain || 708df8bae1dSRodney W. Grimes (so->so_proto->pr_flags&PR_RIGHTS) == 0) 709df8bae1dSRodney W. Grimes continue; 710df8bae1dSRodney W. Grimes #ifdef notdef 711df8bae1dSRodney W. Grimes if (so->so_rcv.sb_flags & SB_LOCK) { 712df8bae1dSRodney W. Grimes /* 713df8bae1dSRodney W. Grimes * This is problematical; it's not clear 714df8bae1dSRodney W. Grimes * we need to wait for the sockbuf to be 715df8bae1dSRodney W. Grimes * unlocked (on a uniprocessor, at least), 716df8bae1dSRodney W. Grimes * and it's also not clear what to do 717df8bae1dSRodney W. Grimes * if sbwait returns an error due to receipt 718df8bae1dSRodney W. Grimes * of a signal. If sbwait does return 719df8bae1dSRodney W. Grimes * an error, we'll go into an infinite 720df8bae1dSRodney W. Grimes * loop. Delete all of this for now. 721df8bae1dSRodney W. Grimes */ 722df8bae1dSRodney W. Grimes (void) sbwait(&so->so_rcv); 723df8bae1dSRodney W. Grimes goto restart; 724df8bae1dSRodney W. Grimes } 725df8bae1dSRodney W. Grimes #endif 726df8bae1dSRodney W. Grimes unp_scan(so->so_rcv.sb_mb, unp_mark); 727df8bae1dSRodney W. Grimes } 728df8bae1dSRodney W. Grimes } while (unp_defer); 729df8bae1dSRodney W. Grimes /* 730df8bae1dSRodney W. Grimes * We grab an extra reference to each of the file table entries 731df8bae1dSRodney W. Grimes * that are not otherwise accessible and then free the rights 732df8bae1dSRodney W. Grimes * that are stored in messages on them. 733df8bae1dSRodney W. Grimes * 734df8bae1dSRodney W. Grimes * The bug in the orginal code is a little tricky, so I'll describe 735df8bae1dSRodney W. Grimes * what's wrong with it here. 736df8bae1dSRodney W. Grimes * 737df8bae1dSRodney W. Grimes * It is incorrect to simply unp_discard each entry for f_msgcount 738df8bae1dSRodney W. Grimes * times -- consider the case of sockets A and B that contain 739df8bae1dSRodney W. Grimes * references to each other. On a last close of some other socket, 740df8bae1dSRodney W. Grimes * we trigger a gc since the number of outstanding rights (unp_rights) 741df8bae1dSRodney W. Grimes * is non-zero. If during the sweep phase the gc code un_discards, 742df8bae1dSRodney W. Grimes * we end up doing a (full) closef on the descriptor. A closef on A 743df8bae1dSRodney W. Grimes * results in the following chain. Closef calls soo_close, which 744df8bae1dSRodney W. Grimes * calls soclose. Soclose calls first (through the switch 745df8bae1dSRodney W. Grimes * uipc_usrreq) unp_detach, which re-invokes unp_gc. Unp_gc simply 746df8bae1dSRodney W. Grimes * returns because the previous instance had set unp_gcing, and 747df8bae1dSRodney W. Grimes * we return all the way back to soclose, which marks the socket 748df8bae1dSRodney W. Grimes * with SS_NOFDREF, and then calls sofree. Sofree calls sorflush 749df8bae1dSRodney W. Grimes * to free up the rights that are queued in messages on the socket A, 750df8bae1dSRodney W. Grimes * i.e., the reference on B. The sorflush calls via the dom_dispose 751df8bae1dSRodney W. Grimes * switch unp_dispose, which unp_scans with unp_discard. This second 752df8bae1dSRodney W. Grimes * instance of unp_discard just calls closef on B. 753df8bae1dSRodney W. Grimes * 754df8bae1dSRodney W. Grimes * Well, a similar chain occurs on B, resulting in a sorflush on B, 755df8bae1dSRodney W. Grimes * which results in another closef on A. Unfortunately, A is already 756df8bae1dSRodney W. Grimes * being closed, and the descriptor has already been marked with 757df8bae1dSRodney W. Grimes * SS_NOFDREF, and soclose panics at this point. 758df8bae1dSRodney W. Grimes * 759df8bae1dSRodney W. Grimes * Here, we first take an extra reference to each inaccessible 760df8bae1dSRodney W. Grimes * descriptor. Then, we call sorflush ourself, since we know 761df8bae1dSRodney W. Grimes * it is a Unix domain socket anyhow. After we destroy all the 762df8bae1dSRodney W. Grimes * rights carried in messages, we do a last closef to get rid 763df8bae1dSRodney W. Grimes * of our extra reference. This is the last close, and the 764df8bae1dSRodney W. Grimes * unp_detach etc will shut down the socket. 765df8bae1dSRodney W. Grimes * 766df8bae1dSRodney W. Grimes * 91/09/19, bsy@cs.cmu.edu 767df8bae1dSRodney W. Grimes */ 768df8bae1dSRodney W. Grimes extra_ref = malloc(nfiles * sizeof(struct file *), M_FILE, M_WAITOK); 769df8bae1dSRodney W. Grimes for (nunref = 0, fp = filehead, fpp = extra_ref; fp; fp = nextfp) { 770df8bae1dSRodney W. Grimes nextfp = fp->f_filef; 771df8bae1dSRodney W. Grimes if (fp->f_count == 0) 772df8bae1dSRodney W. Grimes continue; 773df8bae1dSRodney W. Grimes if (fp->f_count == fp->f_msgcount && !(fp->f_flag & FMARK)) { 774df8bae1dSRodney W. Grimes *fpp++ = fp; 775df8bae1dSRodney W. Grimes nunref++; 776df8bae1dSRodney W. Grimes fp->f_count++; 777df8bae1dSRodney W. Grimes } 778df8bae1dSRodney W. Grimes } 779df8bae1dSRodney W. Grimes for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp) 780df8bae1dSRodney W. Grimes sorflush((struct socket *)(*fpp)->f_data); 781df8bae1dSRodney W. Grimes for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp) 78292cbac68SPoul-Henning Kamp closef(*fpp,(struct proc*) NULL); 783df8bae1dSRodney W. Grimes free((caddr_t)extra_ref, M_FILE); 784df8bae1dSRodney W. Grimes unp_gcing = 0; 785df8bae1dSRodney W. Grimes } 786df8bae1dSRodney W. Grimes 78726f9a767SRodney W. Grimes void 788df8bae1dSRodney W. Grimes unp_dispose(m) 789df8bae1dSRodney W. Grimes struct mbuf *m; 790df8bae1dSRodney W. Grimes { 791df8bae1dSRodney W. Grimes if (m) 792df8bae1dSRodney W. Grimes unp_scan(m, unp_discard); 793df8bae1dSRodney W. Grimes } 794df8bae1dSRodney W. Grimes 79526f9a767SRodney W. Grimes void 796df8bae1dSRodney W. Grimes unp_scan(m0, op) 797df8bae1dSRodney W. Grimes register struct mbuf *m0; 79826f9a767SRodney W. Grimes void (*op)(struct file *); 799df8bae1dSRodney W. Grimes { 800df8bae1dSRodney W. Grimes register struct mbuf *m; 801df8bae1dSRodney W. Grimes register struct file **rp; 802df8bae1dSRodney W. Grimes register struct cmsghdr *cm; 803df8bae1dSRodney W. Grimes register int i; 804df8bae1dSRodney W. Grimes int qfds; 805df8bae1dSRodney W. Grimes 806df8bae1dSRodney W. Grimes while (m0) { 807df8bae1dSRodney W. Grimes for (m = m0; m; m = m->m_next) 808df8bae1dSRodney W. Grimes if (m->m_type == MT_CONTROL && 809df8bae1dSRodney W. Grimes m->m_len >= sizeof(*cm)) { 810df8bae1dSRodney W. Grimes cm = mtod(m, struct cmsghdr *); 811df8bae1dSRodney W. Grimes if (cm->cmsg_level != SOL_SOCKET || 812df8bae1dSRodney W. Grimes cm->cmsg_type != SCM_RIGHTS) 813df8bae1dSRodney W. Grimes continue; 814df8bae1dSRodney W. Grimes qfds = (cm->cmsg_len - sizeof *cm) 815df8bae1dSRodney W. Grimes / sizeof (struct file *); 816df8bae1dSRodney W. Grimes rp = (struct file **)(cm + 1); 817df8bae1dSRodney W. Grimes for (i = 0; i < qfds; i++) 818df8bae1dSRodney W. Grimes (*op)(*rp++); 819df8bae1dSRodney W. Grimes break; /* XXX, but saves time */ 820df8bae1dSRodney W. Grimes } 821df8bae1dSRodney W. Grimes m0 = m0->m_act; 822df8bae1dSRodney W. Grimes } 823df8bae1dSRodney W. Grimes } 824df8bae1dSRodney W. Grimes 82526f9a767SRodney W. Grimes void 826df8bae1dSRodney W. Grimes unp_mark(fp) 827df8bae1dSRodney W. Grimes struct file *fp; 828df8bae1dSRodney W. Grimes { 829df8bae1dSRodney W. Grimes 830df8bae1dSRodney W. Grimes if (fp->f_flag & FMARK) 831df8bae1dSRodney W. Grimes return; 832df8bae1dSRodney W. Grimes unp_defer++; 833df8bae1dSRodney W. Grimes fp->f_flag |= (FMARK|FDEFER); 834df8bae1dSRodney W. Grimes } 835df8bae1dSRodney W. Grimes 83626f9a767SRodney W. Grimes void 837df8bae1dSRodney W. Grimes unp_discard(fp) 838df8bae1dSRodney W. Grimes struct file *fp; 839df8bae1dSRodney W. Grimes { 840df8bae1dSRodney W. Grimes 841df8bae1dSRodney W. Grimes fp->f_msgcount--; 842df8bae1dSRodney W. Grimes unp_rights--; 843df8bae1dSRodney W. Grimes (void) closef(fp, (struct proc *)NULL); 844df8bae1dSRodney W. Grimes } 845