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 34a29f300eSGarrett Wollman * $Id: uipc_usrreq.c,v 1.22 1997/03/23 03:36:33 bde Exp $ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 37df8bae1dSRodney W. Grimes #include <sys/param.h> 382ee45d7dSDavid Greenman #include <sys/queue.h> 39df8bae1dSRodney W. Grimes #include <sys/systm.h> 40639acc13SGarrett Wollman #include <sys/kernel.h> 41df8bae1dSRodney W. Grimes #include <sys/domain.h> 423ac4d1efSBruce Evans #include <sys/fcntl.h> 43639acc13SGarrett Wollman #include <sys/file.h> 44639acc13SGarrett Wollman #include <sys/filedesc.h> 45639acc13SGarrett Wollman #include <sys/mbuf.h> 46639acc13SGarrett Wollman #include <sys/namei.h> 47639acc13SGarrett Wollman #include <sys/proc.h> 48df8bae1dSRodney W. Grimes #include <sys/protosw.h> 49df8bae1dSRodney W. Grimes #include <sys/socket.h> 50df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 51df8bae1dSRodney W. Grimes #include <sys/stat.h> 52639acc13SGarrett Wollman #include <sys/sysctl.h> 53639acc13SGarrett Wollman #include <sys/un.h> 54639acc13SGarrett Wollman #include <sys/unpcb.h> 55639acc13SGarrett Wollman #include <sys/vnode.h> 56df8bae1dSRodney W. Grimes 57df8bae1dSRodney W. Grimes /* 58df8bae1dSRodney W. Grimes * Unix communications domain. 59df8bae1dSRodney W. Grimes * 60df8bae1dSRodney W. Grimes * TODO: 61df8bae1dSRodney W. Grimes * SEQPACKET, RDM 62df8bae1dSRodney W. Grimes * rethink name space problems 63df8bae1dSRodney W. Grimes * need a proper out-of-band 64df8bae1dSRodney W. Grimes */ 65f708ef1bSPoul-Henning Kamp static struct sockaddr sun_noname = { sizeof(sun_noname), AF_LOCAL }; 66f708ef1bSPoul-Henning Kamp static ino_t unp_ino; /* prototype for fake inode numbers */ 67f708ef1bSPoul-Henning Kamp 68f708ef1bSPoul-Henning Kamp static int unp_attach __P((struct socket *)); 69f708ef1bSPoul-Henning Kamp static void unp_detach __P((struct unpcb *)); 70f708ef1bSPoul-Henning Kamp static int unp_bind __P((struct unpcb *,struct mbuf *, struct proc *)); 71f708ef1bSPoul-Henning Kamp static int unp_connect __P((struct socket *,struct mbuf *, struct proc *)); 72f708ef1bSPoul-Henning Kamp static void unp_disconnect __P((struct unpcb *)); 73f708ef1bSPoul-Henning Kamp static void unp_shutdown __P((struct unpcb *)); 74f708ef1bSPoul-Henning Kamp static void unp_drop __P((struct unpcb *, int)); 75f708ef1bSPoul-Henning Kamp static void unp_gc __P((void)); 76f708ef1bSPoul-Henning Kamp static void unp_scan __P((struct mbuf *, void (*)(struct file *))); 77f708ef1bSPoul-Henning Kamp static void unp_mark __P((struct file *)); 78f708ef1bSPoul-Henning Kamp static void unp_discard __P((struct file *)); 79f708ef1bSPoul-Henning Kamp static int unp_internalize __P((struct mbuf *, struct proc *)); 80f708ef1bSPoul-Henning Kamp 81a29f300eSGarrett Wollman static int 82a29f300eSGarrett Wollman uipc_abort(struct socket *so) 83df8bae1dSRodney W. Grimes { 84df8bae1dSRodney W. Grimes struct unpcb *unp = sotounpcb(so); 85df8bae1dSRodney W. Grimes 86a29f300eSGarrett Wollman if (unp == 0) 87a29f300eSGarrett Wollman return EINVAL; 88a29f300eSGarrett Wollman unp_drop(unp, ECONNABORTED); 89a29f300eSGarrett Wollman return 0; 90df8bae1dSRodney W. Grimes } 91df8bae1dSRodney W. Grimes 92a29f300eSGarrett Wollman static int 93a29f300eSGarrett Wollman uipc_accept(struct socket *so, struct mbuf *nam) 94a29f300eSGarrett Wollman { 95a29f300eSGarrett Wollman struct unpcb *unp = sotounpcb(so); 96df8bae1dSRodney W. Grimes 97a29f300eSGarrett Wollman if (unp == 0) 98a29f300eSGarrett Wollman return EINVAL; 99df8bae1dSRodney W. Grimes 100df8bae1dSRodney W. Grimes /* 101df8bae1dSRodney W. Grimes * Pass back name of connected socket, 102df8bae1dSRodney W. Grimes * if it was bound and we are still connected 103df8bae1dSRodney W. Grimes * (our peer may have closed already!). 104df8bae1dSRodney W. Grimes */ 105df8bae1dSRodney W. Grimes if (unp->unp_conn && unp->unp_conn->unp_addr) { 106df8bae1dSRodney W. Grimes nam->m_len = unp->unp_conn->unp_addr->m_len; 107df8bae1dSRodney W. Grimes bcopy(mtod(unp->unp_conn->unp_addr, caddr_t), 108df8bae1dSRodney W. Grimes mtod(nam, caddr_t), (unsigned)nam->m_len); 109df8bae1dSRodney W. Grimes } else { 110df8bae1dSRodney W. Grimes nam->m_len = sizeof(sun_noname); 111df8bae1dSRodney W. Grimes *(mtod(nam, struct sockaddr *)) = sun_noname; 112df8bae1dSRodney W. Grimes } 113a29f300eSGarrett Wollman return 0; 114a29f300eSGarrett Wollman } 115df8bae1dSRodney W. Grimes 116a29f300eSGarrett Wollman static int 117a29f300eSGarrett Wollman uipc_attach(struct socket *so, int proto, struct proc *p) 118a29f300eSGarrett Wollman { 119a29f300eSGarrett Wollman struct unpcb *unp = sotounpcb(so); 120df8bae1dSRodney W. Grimes 121a29f300eSGarrett Wollman if (unp != 0) 122a29f300eSGarrett Wollman return EISCONN; 123a29f300eSGarrett Wollman return unp_attach(so); 124a29f300eSGarrett Wollman } 125a29f300eSGarrett Wollman 126a29f300eSGarrett Wollman static int 127a29f300eSGarrett Wollman uipc_bind(struct socket *so, struct mbuf *nam, struct proc *p) 128a29f300eSGarrett Wollman { 129a29f300eSGarrett Wollman struct unpcb *unp = sotounpcb(so); 130a29f300eSGarrett Wollman 131a29f300eSGarrett Wollman if (unp == 0) 132a29f300eSGarrett Wollman return EINVAL; 133a29f300eSGarrett Wollman 134a29f300eSGarrett Wollman return unp_bind(unp, nam, p); 135a29f300eSGarrett Wollman } 136a29f300eSGarrett Wollman 137a29f300eSGarrett Wollman static int 138a29f300eSGarrett Wollman uipc_connect(struct socket *so, struct mbuf *nam, struct proc *p) 139a29f300eSGarrett Wollman { 140a29f300eSGarrett Wollman struct unpcb *unp = sotounpcb(so); 141a29f300eSGarrett Wollman 142a29f300eSGarrett Wollman if (unp == 0) 143a29f300eSGarrett Wollman return EINVAL; 144a29f300eSGarrett Wollman return unp_connect(so, nam, curproc); 145a29f300eSGarrett Wollman } 146a29f300eSGarrett Wollman 147a29f300eSGarrett Wollman static int 148a29f300eSGarrett Wollman uipc_connect2(struct socket *so1, struct socket *so2) 149a29f300eSGarrett Wollman { 150a29f300eSGarrett Wollman struct unpcb *unp = sotounpcb(so1); 151a29f300eSGarrett Wollman 152a29f300eSGarrett Wollman if (unp == 0) 153a29f300eSGarrett Wollman return EINVAL; 154a29f300eSGarrett Wollman 155a29f300eSGarrett Wollman return unp_connect2(so1, so2); 156a29f300eSGarrett Wollman } 157a29f300eSGarrett Wollman 158a29f300eSGarrett Wollman /* control is EOPNOTSUPP */ 159a29f300eSGarrett Wollman 160a29f300eSGarrett Wollman static int 161a29f300eSGarrett Wollman uipc_detach(struct socket *so) 162a29f300eSGarrett Wollman { 163a29f300eSGarrett Wollman struct unpcb *unp = sotounpcb(so); 164a29f300eSGarrett Wollman 165a29f300eSGarrett Wollman if (unp == 0) 166a29f300eSGarrett Wollman return EINVAL; 167a29f300eSGarrett Wollman 168a29f300eSGarrett Wollman unp_detach(unp); 169a29f300eSGarrett Wollman return 0; 170a29f300eSGarrett Wollman } 171a29f300eSGarrett Wollman 172a29f300eSGarrett Wollman static int 173a29f300eSGarrett Wollman uipc_disconnect(struct socket *so) 174a29f300eSGarrett Wollman { 175a29f300eSGarrett Wollman struct unpcb *unp = sotounpcb(so); 176a29f300eSGarrett Wollman 177a29f300eSGarrett Wollman if (unp == 0) 178a29f300eSGarrett Wollman return EINVAL; 179a29f300eSGarrett Wollman unp_disconnect(unp); 180a29f300eSGarrett Wollman return 0; 181a29f300eSGarrett Wollman } 182a29f300eSGarrett Wollman 183a29f300eSGarrett Wollman static int 184a29f300eSGarrett Wollman uipc_listen(struct socket *so, struct proc *p) 185a29f300eSGarrett Wollman { 186a29f300eSGarrett Wollman struct unpcb *unp = sotounpcb(so); 187a29f300eSGarrett Wollman 188a29f300eSGarrett Wollman if (unp == 0 || unp->unp_vnode == 0) 189a29f300eSGarrett Wollman return EINVAL; 190a29f300eSGarrett Wollman return 0; 191a29f300eSGarrett Wollman } 192a29f300eSGarrett Wollman 193a29f300eSGarrett Wollman static int 194a29f300eSGarrett Wollman uipc_peeraddr(struct socket *so, struct mbuf *nam) 195a29f300eSGarrett Wollman { 196a29f300eSGarrett Wollman struct unpcb *unp = sotounpcb(so); 197a29f300eSGarrett Wollman 198a29f300eSGarrett Wollman if (unp == 0) 199a29f300eSGarrett Wollman return EINVAL; 200a29f300eSGarrett Wollman if (unp->unp_conn && unp->unp_conn->unp_addr) { 201a29f300eSGarrett Wollman nam->m_len = unp->unp_conn->unp_addr->m_len; 202a29f300eSGarrett Wollman bcopy(mtod(unp->unp_conn->unp_addr, caddr_t), 203a29f300eSGarrett Wollman mtod(nam, caddr_t), (unsigned)nam->m_len); 204a29f300eSGarrett Wollman } else 205a29f300eSGarrett Wollman nam->m_len = 0; 206a29f300eSGarrett Wollman return 0; 207a29f300eSGarrett Wollman } 208a29f300eSGarrett Wollman 209a29f300eSGarrett Wollman static int 210a29f300eSGarrett Wollman uipc_rcvd(struct socket *so, int flags) 211a29f300eSGarrett Wollman { 212a29f300eSGarrett Wollman struct unpcb *unp = sotounpcb(so); 213a29f300eSGarrett Wollman struct socket *so2; 214a29f300eSGarrett Wollman 215a29f300eSGarrett Wollman if (unp == 0) 216a29f300eSGarrett Wollman return EINVAL; 217df8bae1dSRodney W. Grimes switch (so->so_type) { 218df8bae1dSRodney W. Grimes case SOCK_DGRAM: 219a29f300eSGarrett Wollman panic("uipc_rcvd DGRAM?"); 220df8bae1dSRodney W. Grimes /*NOTREACHED*/ 221df8bae1dSRodney W. Grimes 222df8bae1dSRodney W. Grimes case SOCK_STREAM: 223df8bae1dSRodney W. Grimes #define rcv (&so->so_rcv) 224df8bae1dSRodney W. Grimes #define snd (&so2->so_snd) 225df8bae1dSRodney W. Grimes if (unp->unp_conn == 0) 226df8bae1dSRodney W. Grimes break; 227df8bae1dSRodney W. Grimes so2 = unp->unp_conn->unp_socket; 228df8bae1dSRodney W. Grimes /* 229df8bae1dSRodney W. Grimes * Adjust backpressure on sender 230df8bae1dSRodney W. Grimes * and wakeup any waiting to write. 231df8bae1dSRodney W. Grimes */ 232df8bae1dSRodney W. Grimes snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt; 233df8bae1dSRodney W. Grimes unp->unp_mbcnt = rcv->sb_mbcnt; 234df8bae1dSRodney W. Grimes snd->sb_hiwat += unp->unp_cc - rcv->sb_cc; 235df8bae1dSRodney W. Grimes unp->unp_cc = rcv->sb_cc; 236df8bae1dSRodney W. Grimes sowwakeup(so2); 237df8bae1dSRodney W. Grimes #undef snd 238df8bae1dSRodney W. Grimes #undef rcv 239df8bae1dSRodney W. Grimes break; 240df8bae1dSRodney W. Grimes 241df8bae1dSRodney W. Grimes default: 242a29f300eSGarrett Wollman panic("uipc_rcvd unknown socktype"); 243df8bae1dSRodney W. Grimes } 244a29f300eSGarrett Wollman return 0; 245a29f300eSGarrett Wollman } 246df8bae1dSRodney W. Grimes 247a29f300eSGarrett Wollman /* pru_rcvoob is EOPNOTSUPP */ 248a29f300eSGarrett Wollman 249a29f300eSGarrett Wollman static int 250a29f300eSGarrett Wollman uipc_send(struct socket *so, int flags, struct mbuf *m, struct mbuf *nam, 251a29f300eSGarrett Wollman struct mbuf *control, struct proc *p) 252a29f300eSGarrett Wollman { 253a29f300eSGarrett Wollman int error = 0; 254a29f300eSGarrett Wollman struct unpcb *unp = sotounpcb(so); 255a29f300eSGarrett Wollman struct socket *so2; 256a29f300eSGarrett Wollman 257a29f300eSGarrett Wollman if (unp == 0) { 258a29f300eSGarrett Wollman error = EINVAL; 259a29f300eSGarrett Wollman goto release; 260a29f300eSGarrett Wollman } 261a29f300eSGarrett Wollman if (flags & PRUS_OOB) { 262a29f300eSGarrett Wollman error = EOPNOTSUPP; 263a29f300eSGarrett Wollman goto release; 264a29f300eSGarrett Wollman } 265a29f300eSGarrett Wollman 266df8bae1dSRodney W. Grimes if (control && (error = unp_internalize(control, p))) 267a29f300eSGarrett Wollman goto release; 268df8bae1dSRodney W. Grimes 269a29f300eSGarrett Wollman switch (so->so_type) { 270a29f300eSGarrett Wollman case SOCK_DGRAM: 271a29f300eSGarrett Wollman { 272df8bae1dSRodney W. Grimes struct sockaddr *from; 273df8bae1dSRodney W. Grimes 274df8bae1dSRodney W. Grimes if (nam) { 275df8bae1dSRodney W. Grimes if (unp->unp_conn) { 276df8bae1dSRodney W. Grimes error = EISCONN; 277df8bae1dSRodney W. Grimes break; 278df8bae1dSRodney W. Grimes } 279df8bae1dSRodney W. Grimes error = unp_connect(so, nam, p); 280df8bae1dSRodney W. Grimes if (error) 281df8bae1dSRodney W. Grimes break; 282df8bae1dSRodney W. Grimes } else { 283df8bae1dSRodney W. Grimes if (unp->unp_conn == 0) { 284df8bae1dSRodney W. Grimes error = ENOTCONN; 285df8bae1dSRodney W. Grimes break; 286df8bae1dSRodney W. Grimes } 287df8bae1dSRodney W. Grimes } 288df8bae1dSRodney W. Grimes so2 = unp->unp_conn->unp_socket; 289df8bae1dSRodney W. Grimes if (unp->unp_addr) 290df8bae1dSRodney W. Grimes from = mtod(unp->unp_addr, struct sockaddr *); 291df8bae1dSRodney W. Grimes else 292df8bae1dSRodney W. Grimes from = &sun_noname; 293df8bae1dSRodney W. Grimes if (sbappendaddr(&so2->so_rcv, from, m, control)) { 294df8bae1dSRodney W. Grimes sorwakeup(so2); 295df8bae1dSRodney W. Grimes m = 0; 296df8bae1dSRodney W. Grimes control = 0; 297df8bae1dSRodney W. Grimes } else 298df8bae1dSRodney W. Grimes error = ENOBUFS; 299df8bae1dSRodney W. Grimes if (nam) 300df8bae1dSRodney W. Grimes unp_disconnect(unp); 301df8bae1dSRodney W. Grimes break; 302df8bae1dSRodney W. Grimes } 303df8bae1dSRodney W. Grimes 304df8bae1dSRodney W. Grimes case SOCK_STREAM: 305df8bae1dSRodney W. Grimes #define rcv (&so2->so_rcv) 306df8bae1dSRodney W. Grimes #define snd (&so->so_snd) 3076b8fda4dSGarrett Wollman /* Connect if not connected yet. */ 3086b8fda4dSGarrett Wollman /* 3096b8fda4dSGarrett Wollman * Note: A better implementation would complain 310402cc72dSDavid Greenman * if not equal to the peer's address. 3116b8fda4dSGarrett Wollman */ 312402cc72dSDavid Greenman if ((so->so_state & SS_ISCONNECTED) == 0) { 313402cc72dSDavid Greenman if (nam) { 314402cc72dSDavid Greenman error = unp_connect(so, nam, p); 315402cc72dSDavid Greenman if (error) 3166b8fda4dSGarrett Wollman break; /* XXX */ 317402cc72dSDavid Greenman } else { 318402cc72dSDavid Greenman error = ENOTCONN; 319402cc72dSDavid Greenman break; 320402cc72dSDavid Greenman } 321402cc72dSDavid Greenman } 322402cc72dSDavid Greenman 323df8bae1dSRodney W. Grimes if (so->so_state & SS_CANTSENDMORE) { 324df8bae1dSRodney W. Grimes error = EPIPE; 325df8bae1dSRodney W. Grimes break; 326df8bae1dSRodney W. Grimes } 327df8bae1dSRodney W. Grimes if (unp->unp_conn == 0) 328a29f300eSGarrett Wollman panic("uipc_send connected but no connection?"); 329df8bae1dSRodney W. Grimes so2 = unp->unp_conn->unp_socket; 330df8bae1dSRodney W. Grimes /* 331df8bae1dSRodney W. Grimes * Send to paired receive port, and then reduce 332df8bae1dSRodney W. Grimes * send buffer hiwater marks to maintain backpressure. 333df8bae1dSRodney W. Grimes * Wake up readers. 334df8bae1dSRodney W. Grimes */ 335df8bae1dSRodney W. Grimes if (control) { 336df8bae1dSRodney W. Grimes if (sbappendcontrol(rcv, m, control)) 337df8bae1dSRodney W. Grimes control = 0; 338df8bae1dSRodney W. Grimes } else 339df8bae1dSRodney W. Grimes sbappend(rcv, m); 340df8bae1dSRodney W. Grimes snd->sb_mbmax -= 341df8bae1dSRodney W. Grimes rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt; 342df8bae1dSRodney W. Grimes unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt; 343df8bae1dSRodney W. Grimes snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc; 344df8bae1dSRodney W. Grimes unp->unp_conn->unp_cc = rcv->sb_cc; 345df8bae1dSRodney W. Grimes sorwakeup(so2); 346df8bae1dSRodney W. Grimes m = 0; 347df8bae1dSRodney W. Grimes #undef snd 348df8bae1dSRodney W. Grimes #undef rcv 349df8bae1dSRodney W. Grimes break; 350df8bae1dSRodney W. Grimes 351df8bae1dSRodney W. Grimes default: 352a29f300eSGarrett Wollman panic("uipc_send unknown socktype"); 353df8bae1dSRodney W. Grimes } 354a29f300eSGarrett Wollman 3556b8fda4dSGarrett Wollman /* 3566b8fda4dSGarrett Wollman * SEND_EOF is equivalent to a SEND followed by 3576b8fda4dSGarrett Wollman * a SHUTDOWN. 3586b8fda4dSGarrett Wollman */ 359a29f300eSGarrett Wollman if (flags & PRUS_EOF) { 3606b8fda4dSGarrett Wollman socantsendmore(so); 3616b8fda4dSGarrett Wollman unp_shutdown(unp); 3626b8fda4dSGarrett Wollman } 363df8bae1dSRodney W. Grimes 364a29f300eSGarrett Wollman release: 365a29f300eSGarrett Wollman if (control) 366a29f300eSGarrett Wollman m_freem(control); 367a29f300eSGarrett Wollman if (m) 368a29f300eSGarrett Wollman m_freem(m); 369a29f300eSGarrett Wollman return error; 370a29f300eSGarrett Wollman } 371df8bae1dSRodney W. Grimes 372a29f300eSGarrett Wollman static int 373a29f300eSGarrett Wollman uipc_sense(struct socket *so, struct stat *sb) 374a29f300eSGarrett Wollman { 375a29f300eSGarrett Wollman struct unpcb *unp = sotounpcb(so); 376a29f300eSGarrett Wollman struct socket *so2; 377a29f300eSGarrett Wollman 378a29f300eSGarrett Wollman if (unp == 0) 379a29f300eSGarrett Wollman return EINVAL; 380a29f300eSGarrett Wollman sb->st_blksize = so->so_snd.sb_hiwat; 381df8bae1dSRodney W. Grimes if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) { 382df8bae1dSRodney W. Grimes so2 = unp->unp_conn->unp_socket; 383a29f300eSGarrett Wollman sb->st_blksize += so2->so_rcv.sb_cc; 384df8bae1dSRodney W. Grimes } 385a29f300eSGarrett Wollman sb->st_dev = NODEV; 386df8bae1dSRodney W. Grimes if (unp->unp_ino == 0) 387df8bae1dSRodney W. Grimes unp->unp_ino = unp_ino++; 388a29f300eSGarrett Wollman sb->st_ino = unp->unp_ino; 389df8bae1dSRodney W. Grimes return (0); 390a29f300eSGarrett Wollman } 391df8bae1dSRodney W. Grimes 392a29f300eSGarrett Wollman static int 393a29f300eSGarrett Wollman uipc_shutdown(struct socket *so) 394a29f300eSGarrett Wollman { 395a29f300eSGarrett Wollman struct unpcb *unp = sotounpcb(so); 396df8bae1dSRodney W. Grimes 397a29f300eSGarrett Wollman if (unp == 0) 398a29f300eSGarrett Wollman return EINVAL; 399a29f300eSGarrett Wollman socantsendmore(so); 400a29f300eSGarrett Wollman unp_shutdown(unp); 401a29f300eSGarrett Wollman return 0; 402a29f300eSGarrett Wollman } 403df8bae1dSRodney W. Grimes 404a29f300eSGarrett Wollman static int 405a29f300eSGarrett Wollman uipc_sockaddr(struct socket *so, struct mbuf *nam) 406a29f300eSGarrett Wollman { 407a29f300eSGarrett Wollman struct unpcb *unp = sotounpcb(so); 408a29f300eSGarrett Wollman 409a29f300eSGarrett Wollman if (unp == 0) 410a29f300eSGarrett Wollman return EINVAL; 411df8bae1dSRodney W. Grimes if (unp->unp_addr) { 412df8bae1dSRodney W. Grimes nam->m_len = unp->unp_addr->m_len; 413df8bae1dSRodney W. Grimes bcopy(mtod(unp->unp_addr, caddr_t), 414df8bae1dSRodney W. Grimes mtod(nam, caddr_t), (unsigned)nam->m_len); 415df8bae1dSRodney W. Grimes } else 416df8bae1dSRodney W. Grimes nam->m_len = 0; 417a29f300eSGarrett Wollman return 0; 418df8bae1dSRodney W. Grimes } 419a29f300eSGarrett Wollman 420a29f300eSGarrett Wollman struct pr_usrreqs uipc_usrreqs = { 421a29f300eSGarrett Wollman uipc_abort, uipc_accept, uipc_attach, uipc_bind, uipc_connect, 422a29f300eSGarrett Wollman uipc_connect2, pru_control_notsupp, uipc_detach, uipc_disconnect, 423a29f300eSGarrett Wollman uipc_listen, uipc_peeraddr, uipc_rcvd, pru_rcvoob_notsupp, 424a29f300eSGarrett Wollman uipc_send, uipc_sense, uipc_shutdown, uipc_sockaddr, 425a29f300eSGarrett Wollman sosend, soreceive, soselect 426a29f300eSGarrett Wollman }; 427df8bae1dSRodney W. Grimes 428df8bae1dSRodney W. Grimes /* 429df8bae1dSRodney W. Grimes * Both send and receive buffers are allocated PIPSIZ bytes of buffering 430df8bae1dSRodney W. Grimes * for stream sockets, although the total for sender and receiver is 431df8bae1dSRodney W. Grimes * actually only PIPSIZ. 432df8bae1dSRodney W. Grimes * Datagram sockets really use the sendspace as the maximum datagram size, 433df8bae1dSRodney W. Grimes * and don't really want to reserve the sendspace. Their recvspace should 434df8bae1dSRodney W. Grimes * be large enough for at least one max-size datagram plus address. 435df8bae1dSRodney W. Grimes */ 4365dce41c5SJohn Dyson #ifndef PIPSIZ 4375dce41c5SJohn Dyson #define PIPSIZ 8192 4385dce41c5SJohn Dyson #endif 439f708ef1bSPoul-Henning Kamp static u_long unpst_sendspace = PIPSIZ; 440f708ef1bSPoul-Henning Kamp static u_long unpst_recvspace = PIPSIZ; 441f708ef1bSPoul-Henning Kamp static u_long unpdg_sendspace = 2*1024; /* really max datagram size */ 442f708ef1bSPoul-Henning Kamp static u_long unpdg_recvspace = 4*1024; 443df8bae1dSRodney W. Grimes 444f708ef1bSPoul-Henning Kamp static int unp_rights; /* file descriptors in flight */ 445df8bae1dSRodney W. Grimes 446639acc13SGarrett Wollman SYSCTL_INT(_net_local_stream, OID_AUTO, sendspace, CTLFLAG_RW, 447639acc13SGarrett Wollman &unpst_sendspace, 0, ""); 448639acc13SGarrett Wollman SYSCTL_INT(_net_local_stream, OID_AUTO, recvspace, CTLFLAG_RW, 449639acc13SGarrett Wollman &unpst_recvspace, 0, ""); 450639acc13SGarrett Wollman SYSCTL_INT(_net_local_dgram, OID_AUTO, maxdgram, CTLFLAG_RW, 451639acc13SGarrett Wollman &unpdg_sendspace, 0, ""); 452639acc13SGarrett Wollman SYSCTL_INT(_net_local_dgram, OID_AUTO, recvspace, CTLFLAG_RW, 453639acc13SGarrett Wollman &unpdg_recvspace, 0, ""); 454639acc13SGarrett Wollman SYSCTL_INT(_net_local, OID_AUTO, inflight, CTLFLAG_RD, &unp_rights, 0, ""); 455639acc13SGarrett Wollman 456f708ef1bSPoul-Henning Kamp static int 457df8bae1dSRodney W. Grimes unp_attach(so) 458df8bae1dSRodney W. Grimes struct socket *so; 459df8bae1dSRodney W. Grimes { 460df8bae1dSRodney W. Grimes register struct mbuf *m; 461df8bae1dSRodney W. Grimes register struct unpcb *unp; 462df8bae1dSRodney W. Grimes int error; 463df8bae1dSRodney W. Grimes 464df8bae1dSRodney W. Grimes if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 465df8bae1dSRodney W. Grimes switch (so->so_type) { 466df8bae1dSRodney W. Grimes 467df8bae1dSRodney W. Grimes case SOCK_STREAM: 468df8bae1dSRodney W. Grimes error = soreserve(so, unpst_sendspace, unpst_recvspace); 469df8bae1dSRodney W. Grimes break; 470df8bae1dSRodney W. Grimes 471df8bae1dSRodney W. Grimes case SOCK_DGRAM: 472df8bae1dSRodney W. Grimes error = soreserve(so, unpdg_sendspace, unpdg_recvspace); 473df8bae1dSRodney W. Grimes break; 474df8bae1dSRodney W. Grimes 475df8bae1dSRodney W. Grimes default: 476df8bae1dSRodney W. Grimes panic("unp_attach"); 477df8bae1dSRodney W. Grimes } 478df8bae1dSRodney W. Grimes if (error) 479df8bae1dSRodney W. Grimes return (error); 480df8bae1dSRodney W. Grimes } 481df8bae1dSRodney W. Grimes m = m_getclr(M_DONTWAIT, MT_PCB); 482df8bae1dSRodney W. Grimes if (m == NULL) 483df8bae1dSRodney W. Grimes return (ENOBUFS); 484df8bae1dSRodney W. Grimes unp = mtod(m, struct unpcb *); 485df8bae1dSRodney W. Grimes so->so_pcb = (caddr_t)unp; 486df8bae1dSRodney W. Grimes unp->unp_socket = so; 487df8bae1dSRodney W. Grimes return (0); 488df8bae1dSRodney W. Grimes } 489df8bae1dSRodney W. Grimes 490f708ef1bSPoul-Henning Kamp static void 491df8bae1dSRodney W. Grimes unp_detach(unp) 492df8bae1dSRodney W. Grimes register struct unpcb *unp; 493df8bae1dSRodney W. Grimes { 494df8bae1dSRodney W. Grimes 495df8bae1dSRodney W. Grimes if (unp->unp_vnode) { 496df8bae1dSRodney W. Grimes unp->unp_vnode->v_socket = 0; 497df8bae1dSRodney W. Grimes vrele(unp->unp_vnode); 498df8bae1dSRodney W. Grimes unp->unp_vnode = 0; 499df8bae1dSRodney W. Grimes } 500df8bae1dSRodney W. Grimes if (unp->unp_conn) 501df8bae1dSRodney W. Grimes unp_disconnect(unp); 502df8bae1dSRodney W. Grimes while (unp->unp_refs) 503df8bae1dSRodney W. Grimes unp_drop(unp->unp_refs, ECONNRESET); 504df8bae1dSRodney W. Grimes soisdisconnected(unp->unp_socket); 505df8bae1dSRodney W. Grimes unp->unp_socket->so_pcb = 0; 506df8bae1dSRodney W. Grimes if (unp_rights) { 507df8bae1dSRodney W. Grimes /* 508df8bae1dSRodney W. Grimes * Normally the receive buffer is flushed later, 509df8bae1dSRodney W. Grimes * in sofree, but if our receive buffer holds references 510df8bae1dSRodney W. Grimes * to descriptors that are now garbage, we will dispose 511df8bae1dSRodney W. Grimes * of those descriptor references after the garbage collector 512df8bae1dSRodney W. Grimes * gets them (resulting in a "panic: closef: count < 0"). 513df8bae1dSRodney W. Grimes */ 514df8bae1dSRodney W. Grimes sorflush(unp->unp_socket); 515df8bae1dSRodney W. Grimes unp_gc(); 516df8bae1dSRodney W. Grimes } 517b4c19655SDavid Greenman m_freem(unp->unp_addr); 518b4c19655SDavid Greenman (void) m_free(dtom(unp)); 519df8bae1dSRodney W. Grimes } 520df8bae1dSRodney W. Grimes 521f708ef1bSPoul-Henning Kamp static int 522df8bae1dSRodney W. Grimes unp_bind(unp, nam, p) 523df8bae1dSRodney W. Grimes struct unpcb *unp; 524df8bae1dSRodney W. Grimes struct mbuf *nam; 525df8bae1dSRodney W. Grimes struct proc *p; 526df8bae1dSRodney W. Grimes { 527df8bae1dSRodney W. Grimes struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 528df8bae1dSRodney W. Grimes register struct vnode *vp; 529df8bae1dSRodney W. Grimes struct vattr vattr; 530df8bae1dSRodney W. Grimes int error; 531df8bae1dSRodney W. Grimes struct nameidata nd; 532df8bae1dSRodney W. Grimes 533df8bae1dSRodney W. Grimes NDINIT(&nd, CREATE, FOLLOW | LOCKPARENT, UIO_SYSSPACE, 534df8bae1dSRodney W. Grimes soun->sun_path, p); 535df8bae1dSRodney W. Grimes if (unp->unp_vnode != NULL) 536df8bae1dSRodney W. Grimes return (EINVAL); 537df8bae1dSRodney W. Grimes if (nam->m_len == MLEN) { 538df8bae1dSRodney W. Grimes if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0) 539df8bae1dSRodney W. Grimes return (EINVAL); 540df8bae1dSRodney W. Grimes } else 541df8bae1dSRodney W. Grimes *(mtod(nam, caddr_t) + nam->m_len) = 0; 542df8bae1dSRodney W. Grimes /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ 543797f2d22SPoul-Henning Kamp error = namei(&nd); 544797f2d22SPoul-Henning Kamp if (error) 545df8bae1dSRodney W. Grimes return (error); 546df8bae1dSRodney W. Grimes vp = nd.ni_vp; 547df8bae1dSRodney W. Grimes if (vp != NULL) { 548df8bae1dSRodney W. Grimes VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 549df8bae1dSRodney W. Grimes if (nd.ni_dvp == vp) 550df8bae1dSRodney W. Grimes vrele(nd.ni_dvp); 551df8bae1dSRodney W. Grimes else 552df8bae1dSRodney W. Grimes vput(nd.ni_dvp); 553df8bae1dSRodney W. Grimes vrele(vp); 554df8bae1dSRodney W. Grimes return (EADDRINUSE); 555df8bae1dSRodney W. Grimes } 556df8bae1dSRodney W. Grimes VATTR_NULL(&vattr); 557df8bae1dSRodney W. Grimes vattr.va_type = VSOCK; 558a29f300eSGarrett Wollman vattr.va_mode = (ACCESSPERMS & ~p->p_fd->fd_cmask); 559996c772fSJohn Dyson VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 560996c772fSJohn Dyson if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)) 561df8bae1dSRodney W. Grimes return (error); 562df8bae1dSRodney W. Grimes vp = nd.ni_vp; 563df8bae1dSRodney W. Grimes vp->v_socket = unp->unp_socket; 564df8bae1dSRodney W. Grimes unp->unp_vnode = vp; 565df8bae1dSRodney W. Grimes unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL); 566996c772fSJohn Dyson VOP_UNLOCK(vp, 0, p); 567df8bae1dSRodney W. Grimes return (0); 568df8bae1dSRodney W. Grimes } 569df8bae1dSRodney W. Grimes 570f708ef1bSPoul-Henning Kamp static int 571df8bae1dSRodney W. Grimes unp_connect(so, nam, p) 572df8bae1dSRodney W. Grimes struct socket *so; 573df8bae1dSRodney W. Grimes struct mbuf *nam; 574df8bae1dSRodney W. Grimes struct proc *p; 575df8bae1dSRodney W. Grimes { 576df8bae1dSRodney W. Grimes register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 577df8bae1dSRodney W. Grimes register struct vnode *vp; 578df8bae1dSRodney W. Grimes register struct socket *so2, *so3; 579df8bae1dSRodney W. Grimes struct unpcb *unp2, *unp3; 580df8bae1dSRodney W. Grimes int error; 581df8bae1dSRodney W. Grimes struct nameidata nd; 582df8bae1dSRodney W. Grimes 583df8bae1dSRodney W. Grimes NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, soun->sun_path, p); 584df8bae1dSRodney W. Grimes if (nam->m_data + nam->m_len == &nam->m_dat[MLEN]) { /* XXX */ 585df8bae1dSRodney W. Grimes if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0) 586df8bae1dSRodney W. Grimes return (EMSGSIZE); 587df8bae1dSRodney W. Grimes } else 588df8bae1dSRodney W. Grimes *(mtod(nam, caddr_t) + nam->m_len) = 0; 589797f2d22SPoul-Henning Kamp error = namei(&nd); 590797f2d22SPoul-Henning Kamp if (error) 591df8bae1dSRodney W. Grimes return (error); 592df8bae1dSRodney W. Grimes vp = nd.ni_vp; 593df8bae1dSRodney W. Grimes if (vp->v_type != VSOCK) { 594df8bae1dSRodney W. Grimes error = ENOTSOCK; 595df8bae1dSRodney W. Grimes goto bad; 596df8bae1dSRodney W. Grimes } 597797f2d22SPoul-Henning Kamp error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p); 598797f2d22SPoul-Henning Kamp if (error) 599df8bae1dSRodney W. Grimes goto bad; 600df8bae1dSRodney W. Grimes so2 = vp->v_socket; 601df8bae1dSRodney W. Grimes if (so2 == 0) { 602df8bae1dSRodney W. Grimes error = ECONNREFUSED; 603df8bae1dSRodney W. Grimes goto bad; 604df8bae1dSRodney W. Grimes } 605df8bae1dSRodney W. Grimes if (so->so_type != so2->so_type) { 606df8bae1dSRodney W. Grimes error = EPROTOTYPE; 607df8bae1dSRodney W. Grimes goto bad; 608df8bae1dSRodney W. Grimes } 609df8bae1dSRodney W. Grimes if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 610df8bae1dSRodney W. Grimes if ((so2->so_options & SO_ACCEPTCONN) == 0 || 611df8bae1dSRodney W. Grimes (so3 = sonewconn(so2, 0)) == 0) { 612df8bae1dSRodney W. Grimes error = ECONNREFUSED; 613df8bae1dSRodney W. Grimes goto bad; 614df8bae1dSRodney W. Grimes } 615df8bae1dSRodney W. Grimes unp2 = sotounpcb(so2); 616df8bae1dSRodney W. Grimes unp3 = sotounpcb(so3); 617df8bae1dSRodney W. Grimes if (unp2->unp_addr) 618df8bae1dSRodney W. Grimes unp3->unp_addr = 619df8bae1dSRodney W. Grimes m_copy(unp2->unp_addr, 0, (int)M_COPYALL); 620df8bae1dSRodney W. Grimes so2 = so3; 621df8bae1dSRodney W. Grimes } 622df8bae1dSRodney W. Grimes error = unp_connect2(so, so2); 623df8bae1dSRodney W. Grimes bad: 624df8bae1dSRodney W. Grimes vput(vp); 625df8bae1dSRodney W. Grimes return (error); 626df8bae1dSRodney W. Grimes } 627df8bae1dSRodney W. Grimes 62826f9a767SRodney W. Grimes int 629df8bae1dSRodney W. Grimes unp_connect2(so, so2) 630df8bae1dSRodney W. Grimes register struct socket *so; 631df8bae1dSRodney W. Grimes register struct socket *so2; 632df8bae1dSRodney W. Grimes { 633df8bae1dSRodney W. Grimes register struct unpcb *unp = sotounpcb(so); 634df8bae1dSRodney W. Grimes register struct unpcb *unp2; 635df8bae1dSRodney W. Grimes 636df8bae1dSRodney W. Grimes if (so2->so_type != so->so_type) 637df8bae1dSRodney W. Grimes return (EPROTOTYPE); 638df8bae1dSRodney W. Grimes unp2 = sotounpcb(so2); 639df8bae1dSRodney W. Grimes unp->unp_conn = unp2; 640df8bae1dSRodney W. Grimes switch (so->so_type) { 641df8bae1dSRodney W. Grimes 642df8bae1dSRodney W. Grimes case SOCK_DGRAM: 643df8bae1dSRodney W. Grimes unp->unp_nextref = unp2->unp_refs; 644df8bae1dSRodney W. Grimes unp2->unp_refs = unp; 645df8bae1dSRodney W. Grimes soisconnected(so); 646df8bae1dSRodney W. Grimes break; 647df8bae1dSRodney W. Grimes 648df8bae1dSRodney W. Grimes case SOCK_STREAM: 649df8bae1dSRodney W. Grimes unp2->unp_conn = unp; 650df8bae1dSRodney W. Grimes soisconnected(so); 651df8bae1dSRodney W. Grimes soisconnected(so2); 652df8bae1dSRodney W. Grimes break; 653df8bae1dSRodney W. Grimes 654df8bae1dSRodney W. Grimes default: 655df8bae1dSRodney W. Grimes panic("unp_connect2"); 656df8bae1dSRodney W. Grimes } 657df8bae1dSRodney W. Grimes return (0); 658df8bae1dSRodney W. Grimes } 659df8bae1dSRodney W. Grimes 660f708ef1bSPoul-Henning Kamp static void 661df8bae1dSRodney W. Grimes unp_disconnect(unp) 662df8bae1dSRodney W. Grimes struct unpcb *unp; 663df8bae1dSRodney W. Grimes { 664df8bae1dSRodney W. Grimes register struct unpcb *unp2 = unp->unp_conn; 665df8bae1dSRodney W. Grimes 666df8bae1dSRodney W. Grimes if (unp2 == 0) 667df8bae1dSRodney W. Grimes return; 668df8bae1dSRodney W. Grimes unp->unp_conn = 0; 669df8bae1dSRodney W. Grimes switch (unp->unp_socket->so_type) { 670df8bae1dSRodney W. Grimes 671df8bae1dSRodney W. Grimes case SOCK_DGRAM: 672df8bae1dSRodney W. Grimes if (unp2->unp_refs == unp) 673df8bae1dSRodney W. Grimes unp2->unp_refs = unp->unp_nextref; 674df8bae1dSRodney W. Grimes else { 675df8bae1dSRodney W. Grimes unp2 = unp2->unp_refs; 676df8bae1dSRodney W. Grimes for (;;) { 677df8bae1dSRodney W. Grimes if (unp2 == 0) 678df8bae1dSRodney W. Grimes panic("unp_disconnect"); 679df8bae1dSRodney W. Grimes if (unp2->unp_nextref == unp) 680df8bae1dSRodney W. Grimes break; 681df8bae1dSRodney W. Grimes unp2 = unp2->unp_nextref; 682df8bae1dSRodney W. Grimes } 683df8bae1dSRodney W. Grimes unp2->unp_nextref = unp->unp_nextref; 684df8bae1dSRodney W. Grimes } 685df8bae1dSRodney W. Grimes unp->unp_nextref = 0; 686df8bae1dSRodney W. Grimes unp->unp_socket->so_state &= ~SS_ISCONNECTED; 687df8bae1dSRodney W. Grimes break; 688df8bae1dSRodney W. Grimes 689df8bae1dSRodney W. Grimes case SOCK_STREAM: 690df8bae1dSRodney W. Grimes soisdisconnected(unp->unp_socket); 691df8bae1dSRodney W. Grimes unp2->unp_conn = 0; 692df8bae1dSRodney W. Grimes soisdisconnected(unp2->unp_socket); 693df8bae1dSRodney W. Grimes break; 694df8bae1dSRodney W. Grimes } 695df8bae1dSRodney W. Grimes } 696df8bae1dSRodney W. Grimes 697df8bae1dSRodney W. Grimes #ifdef notdef 69826f9a767SRodney W. Grimes void 699df8bae1dSRodney W. Grimes unp_abort(unp) 700df8bae1dSRodney W. Grimes struct unpcb *unp; 701df8bae1dSRodney W. Grimes { 702df8bae1dSRodney W. Grimes 703df8bae1dSRodney W. Grimes unp_detach(unp); 704df8bae1dSRodney W. Grimes } 705df8bae1dSRodney W. Grimes #endif 706df8bae1dSRodney W. Grimes 707f708ef1bSPoul-Henning Kamp static void 708df8bae1dSRodney W. Grimes unp_shutdown(unp) 709df8bae1dSRodney W. Grimes struct unpcb *unp; 710df8bae1dSRodney W. Grimes { 711df8bae1dSRodney W. Grimes struct socket *so; 712df8bae1dSRodney W. Grimes 713df8bae1dSRodney W. Grimes if (unp->unp_socket->so_type == SOCK_STREAM && unp->unp_conn && 714df8bae1dSRodney W. Grimes (so = unp->unp_conn->unp_socket)) 715df8bae1dSRodney W. Grimes socantrcvmore(so); 716df8bae1dSRodney W. Grimes } 717df8bae1dSRodney W. Grimes 718f708ef1bSPoul-Henning Kamp static void 719df8bae1dSRodney W. Grimes unp_drop(unp, errno) 720df8bae1dSRodney W. Grimes struct unpcb *unp; 721df8bae1dSRodney W. Grimes int errno; 722df8bae1dSRodney W. Grimes { 723df8bae1dSRodney W. Grimes struct socket *so = unp->unp_socket; 724df8bae1dSRodney W. Grimes 725df8bae1dSRodney W. Grimes so->so_error = errno; 726df8bae1dSRodney W. Grimes unp_disconnect(unp); 727df8bae1dSRodney W. Grimes if (so->so_head) { 728df8bae1dSRodney W. Grimes so->so_pcb = (caddr_t) 0; 729df8bae1dSRodney W. Grimes m_freem(unp->unp_addr); 730df8bae1dSRodney W. Grimes (void) m_free(dtom(unp)); 731df8bae1dSRodney W. Grimes sofree(so); 732df8bae1dSRodney W. Grimes } 733df8bae1dSRodney W. Grimes } 734df8bae1dSRodney W. Grimes 735df8bae1dSRodney W. Grimes #ifdef notdef 73626f9a767SRodney W. Grimes void 737df8bae1dSRodney W. Grimes unp_drain() 738df8bae1dSRodney W. Grimes { 739df8bae1dSRodney W. Grimes 740df8bae1dSRodney W. Grimes } 741df8bae1dSRodney W. Grimes #endif 742df8bae1dSRodney W. Grimes 74326f9a767SRodney W. Grimes int 744df8bae1dSRodney W. Grimes unp_externalize(rights) 745df8bae1dSRodney W. Grimes struct mbuf *rights; 746df8bae1dSRodney W. Grimes { 747df8bae1dSRodney W. Grimes struct proc *p = curproc; /* XXX */ 748df8bae1dSRodney W. Grimes register int i; 749df8bae1dSRodney W. Grimes register struct cmsghdr *cm = mtod(rights, struct cmsghdr *); 750df8bae1dSRodney W. Grimes register struct file **rp = (struct file **)(cm + 1); 751df8bae1dSRodney W. Grimes register struct file *fp; 752df8bae1dSRodney W. Grimes int newfds = (cm->cmsg_len - sizeof(*cm)) / sizeof (int); 753df8bae1dSRodney W. Grimes int f; 754df8bae1dSRodney W. Grimes 755ed5b7817SJulian Elischer /* 756ed5b7817SJulian Elischer * if the new FD's will not fit, then we free them all 757ed5b7817SJulian Elischer */ 758df8bae1dSRodney W. Grimes if (!fdavail(p, newfds)) { 759df8bae1dSRodney W. Grimes for (i = 0; i < newfds; i++) { 760df8bae1dSRodney W. Grimes fp = *rp; 761df8bae1dSRodney W. Grimes unp_discard(fp); 762df8bae1dSRodney W. Grimes *rp++ = 0; 763df8bae1dSRodney W. Grimes } 764df8bae1dSRodney W. Grimes return (EMSGSIZE); 765df8bae1dSRodney W. Grimes } 766ed5b7817SJulian Elischer /* 767ed5b7817SJulian Elischer * now change each pointer to an fd in the global table to 768ed5b7817SJulian Elischer * an integer that is the index to the local fd table entry 769ed5b7817SJulian Elischer * that we set up to point to the global one we are transferring. 770ed5b7817SJulian Elischer * XXX this assumes a pointer and int are the same size...! 771ed5b7817SJulian Elischer */ 772df8bae1dSRodney W. Grimes for (i = 0; i < newfds; i++) { 773df8bae1dSRodney W. Grimes if (fdalloc(p, 0, &f)) 774df8bae1dSRodney W. Grimes panic("unp_externalize"); 775df8bae1dSRodney W. Grimes fp = *rp; 776df8bae1dSRodney W. Grimes p->p_fd->fd_ofiles[f] = fp; 777df8bae1dSRodney W. Grimes fp->f_msgcount--; 778df8bae1dSRodney W. Grimes unp_rights--; 779df8bae1dSRodney W. Grimes *(int *)rp++ = f; 780df8bae1dSRodney W. Grimes } 781df8bae1dSRodney W. Grimes return (0); 782df8bae1dSRodney W. Grimes } 783df8bae1dSRodney W. Grimes 7840b788fa1SBill Paul #ifndef MIN 7850b788fa1SBill Paul #define MIN(a,b) (((a)<(b))?(a):(b)) 7860b788fa1SBill Paul #endif 7870b788fa1SBill Paul 788f708ef1bSPoul-Henning Kamp static int 789df8bae1dSRodney W. Grimes unp_internalize(control, p) 790df8bae1dSRodney W. Grimes struct mbuf *control; 791df8bae1dSRodney W. Grimes struct proc *p; 792df8bae1dSRodney W. Grimes { 793df8bae1dSRodney W. Grimes struct filedesc *fdp = p->p_fd; 794df8bae1dSRodney W. Grimes register struct cmsghdr *cm = mtod(control, struct cmsghdr *); 795df8bae1dSRodney W. Grimes register struct file **rp; 796df8bae1dSRodney W. Grimes register struct file *fp; 797df8bae1dSRodney W. Grimes register int i, fd; 7980b788fa1SBill Paul register struct cmsgcred *cmcred; 799df8bae1dSRodney W. Grimes int oldfds; 800df8bae1dSRodney W. Grimes 8010b788fa1SBill Paul if ((cm->cmsg_type != SCM_RIGHTS && cm->cmsg_type != SCM_CREDS) || 8020b788fa1SBill Paul cm->cmsg_level != SOL_SOCKET || cm->cmsg_len != control->m_len) 803df8bae1dSRodney W. Grimes return (EINVAL); 8040b788fa1SBill Paul 8050b788fa1SBill Paul /* 8060b788fa1SBill Paul * Fill in credential information. 8070b788fa1SBill Paul */ 8080b788fa1SBill Paul if (cm->cmsg_type == SCM_CREDS) { 8090b788fa1SBill Paul cmcred = (struct cmsgcred *)(cm + 1); 8100b788fa1SBill Paul cmcred->cmcred_pid = p->p_pid; 8110b788fa1SBill Paul cmcred->cmcred_uid = p->p_cred->p_ruid; 8120b788fa1SBill Paul cmcred->cmcred_gid = p->p_cred->p_rgid; 8130b788fa1SBill Paul cmcred->cmcred_euid = p->p_ucred->cr_uid; 8140b788fa1SBill Paul cmcred->cmcred_ngroups = MIN(p->p_ucred->cr_ngroups, 8150b788fa1SBill Paul CMGROUP_MAX); 8160b788fa1SBill Paul for (i = 0; i < cmcred->cmcred_ngroups; i++) 8170b788fa1SBill Paul cmcred->cmcred_groups[i] = p->p_ucred->cr_groups[i]; 8180b788fa1SBill Paul return(0); 8190b788fa1SBill Paul } 8200b788fa1SBill Paul 821df8bae1dSRodney W. Grimes oldfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int); 822ed5b7817SJulian Elischer /* 823ed5b7817SJulian Elischer * check that all the FDs passed in refer to legal OPEN files 824ed5b7817SJulian Elischer * If not, reject the entire operation. 825ed5b7817SJulian Elischer */ 826df8bae1dSRodney W. Grimes rp = (struct file **)(cm + 1); 827df8bae1dSRodney W. Grimes for (i = 0; i < oldfds; i++) { 828df8bae1dSRodney W. Grimes fd = *(int *)rp++; 829df8bae1dSRodney W. Grimes if ((unsigned)fd >= fdp->fd_nfiles || 830df8bae1dSRodney W. Grimes fdp->fd_ofiles[fd] == NULL) 831df8bae1dSRodney W. Grimes return (EBADF); 832df8bae1dSRodney W. Grimes } 833ed5b7817SJulian Elischer /* 834ed5b7817SJulian Elischer * Now replace the integer FDs with pointers to 835ed5b7817SJulian Elischer * the associated global file table entry.. 836ed5b7817SJulian Elischer * XXX this assumes a pointer and an int are the same size! 837ed5b7817SJulian Elischer */ 838df8bae1dSRodney W. Grimes rp = (struct file **)(cm + 1); 839df8bae1dSRodney W. Grimes for (i = 0; i < oldfds; i++) { 840df8bae1dSRodney W. Grimes fp = fdp->fd_ofiles[*(int *)rp]; 841df8bae1dSRodney W. Grimes *rp++ = fp; 842df8bae1dSRodney W. Grimes fp->f_count++; 843df8bae1dSRodney W. Grimes fp->f_msgcount++; 844df8bae1dSRodney W. Grimes unp_rights++; 845df8bae1dSRodney W. Grimes } 846df8bae1dSRodney W. Grimes return (0); 847df8bae1dSRodney W. Grimes } 848df8bae1dSRodney W. Grimes 849f708ef1bSPoul-Henning Kamp static int unp_defer, unp_gcing; 850df8bae1dSRodney W. Grimes 851f708ef1bSPoul-Henning Kamp static void 852df8bae1dSRodney W. Grimes unp_gc() 853df8bae1dSRodney W. Grimes { 854df8bae1dSRodney W. Grimes register struct file *fp, *nextfp; 855df8bae1dSRodney W. Grimes register struct socket *so; 856df8bae1dSRodney W. Grimes struct file **extra_ref, **fpp; 857df8bae1dSRodney W. Grimes int nunref, i; 858df8bae1dSRodney W. Grimes 859df8bae1dSRodney W. Grimes if (unp_gcing) 860df8bae1dSRodney W. Grimes return; 861df8bae1dSRodney W. Grimes unp_gcing = 1; 862df8bae1dSRodney W. Grimes unp_defer = 0; 863ed5b7817SJulian Elischer /* 864ed5b7817SJulian Elischer * before going through all this, set all FDs to 865ed5b7817SJulian Elischer * be NOT defered and NOT externally accessible 866ed5b7817SJulian Elischer */ 867bc6f0e79SJeffrey Hsu for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) 868df8bae1dSRodney W. Grimes fp->f_flag &= ~(FMARK|FDEFER); 869df8bae1dSRodney W. Grimes do { 870bc6f0e79SJeffrey Hsu for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) { 871ed5b7817SJulian Elischer /* 872ed5b7817SJulian Elischer * If the file is not open, skip it 873ed5b7817SJulian Elischer */ 874df8bae1dSRodney W. Grimes if (fp->f_count == 0) 875df8bae1dSRodney W. Grimes continue; 876ed5b7817SJulian Elischer /* 877ed5b7817SJulian Elischer * If we already marked it as 'defer' in a 878ed5b7817SJulian Elischer * previous pass, then try process it this time 879ed5b7817SJulian Elischer * and un-mark it 880ed5b7817SJulian Elischer */ 881df8bae1dSRodney W. Grimes if (fp->f_flag & FDEFER) { 882df8bae1dSRodney W. Grimes fp->f_flag &= ~FDEFER; 883df8bae1dSRodney W. Grimes unp_defer--; 884df8bae1dSRodney W. Grimes } else { 885ed5b7817SJulian Elischer /* 886ed5b7817SJulian Elischer * if it's not defered, then check if it's 887ed5b7817SJulian Elischer * already marked.. if so skip it 888ed5b7817SJulian Elischer */ 889df8bae1dSRodney W. Grimes if (fp->f_flag & FMARK) 890df8bae1dSRodney W. Grimes continue; 891ed5b7817SJulian Elischer /* 892ed5b7817SJulian Elischer * If all references are from messages 893ed5b7817SJulian Elischer * in transit, then skip it. it's not 894ed5b7817SJulian Elischer * externally accessible. 895ed5b7817SJulian Elischer */ 896df8bae1dSRodney W. Grimes if (fp->f_count == fp->f_msgcount) 897df8bae1dSRodney W. Grimes continue; 898ed5b7817SJulian Elischer /* 899ed5b7817SJulian Elischer * If it got this far then it must be 900ed5b7817SJulian Elischer * externally accessible. 901ed5b7817SJulian Elischer */ 902df8bae1dSRodney W. Grimes fp->f_flag |= FMARK; 903df8bae1dSRodney W. Grimes } 904ed5b7817SJulian Elischer /* 905ed5b7817SJulian Elischer * either it was defered, or it is externally 906ed5b7817SJulian Elischer * accessible and not already marked so. 907ed5b7817SJulian Elischer * Now check if it is possibly one of OUR sockets. 908ed5b7817SJulian Elischer */ 909df8bae1dSRodney W. Grimes if (fp->f_type != DTYPE_SOCKET || 910df8bae1dSRodney W. Grimes (so = (struct socket *)fp->f_data) == 0) 911df8bae1dSRodney W. Grimes continue; 912748e0b0aSGarrett Wollman if (so->so_proto->pr_domain != &localdomain || 913df8bae1dSRodney W. Grimes (so->so_proto->pr_flags&PR_RIGHTS) == 0) 914df8bae1dSRodney W. Grimes continue; 915df8bae1dSRodney W. Grimes #ifdef notdef 916df8bae1dSRodney W. Grimes if (so->so_rcv.sb_flags & SB_LOCK) { 917df8bae1dSRodney W. Grimes /* 918df8bae1dSRodney W. Grimes * This is problematical; it's not clear 919df8bae1dSRodney W. Grimes * we need to wait for the sockbuf to be 920df8bae1dSRodney W. Grimes * unlocked (on a uniprocessor, at least), 921df8bae1dSRodney W. Grimes * and it's also not clear what to do 922df8bae1dSRodney W. Grimes * if sbwait returns an error due to receipt 923df8bae1dSRodney W. Grimes * of a signal. If sbwait does return 924df8bae1dSRodney W. Grimes * an error, we'll go into an infinite 925df8bae1dSRodney W. Grimes * loop. Delete all of this for now. 926df8bae1dSRodney W. Grimes */ 927df8bae1dSRodney W. Grimes (void) sbwait(&so->so_rcv); 928df8bae1dSRodney W. Grimes goto restart; 929df8bae1dSRodney W. Grimes } 930df8bae1dSRodney W. Grimes #endif 931ed5b7817SJulian Elischer /* 932ed5b7817SJulian Elischer * So, Ok, it's one of our sockets and it IS externally 933ed5b7817SJulian Elischer * accessible (or was defered). Now we look 934ed5b7817SJulian Elischer * to see if we hold any file descriptors in it's 935ed5b7817SJulian Elischer * message buffers. Follow those links and mark them 936ed5b7817SJulian Elischer * as accessible too. 937ed5b7817SJulian Elischer */ 938df8bae1dSRodney W. Grimes unp_scan(so->so_rcv.sb_mb, unp_mark); 939df8bae1dSRodney W. Grimes } 940df8bae1dSRodney W. Grimes } while (unp_defer); 941df8bae1dSRodney W. Grimes /* 942df8bae1dSRodney W. Grimes * We grab an extra reference to each of the file table entries 943df8bae1dSRodney W. Grimes * that are not otherwise accessible and then free the rights 944df8bae1dSRodney W. Grimes * that are stored in messages on them. 945df8bae1dSRodney W. Grimes * 946df8bae1dSRodney W. Grimes * The bug in the orginal code is a little tricky, so I'll describe 947df8bae1dSRodney W. Grimes * what's wrong with it here. 948df8bae1dSRodney W. Grimes * 949df8bae1dSRodney W. Grimes * It is incorrect to simply unp_discard each entry for f_msgcount 950df8bae1dSRodney W. Grimes * times -- consider the case of sockets A and B that contain 951df8bae1dSRodney W. Grimes * references to each other. On a last close of some other socket, 952df8bae1dSRodney W. Grimes * we trigger a gc since the number of outstanding rights (unp_rights) 953df8bae1dSRodney W. Grimes * is non-zero. If during the sweep phase the gc code un_discards, 954df8bae1dSRodney W. Grimes * we end up doing a (full) closef on the descriptor. A closef on A 955df8bae1dSRodney W. Grimes * results in the following chain. Closef calls soo_close, which 956df8bae1dSRodney W. Grimes * calls soclose. Soclose calls first (through the switch 957df8bae1dSRodney W. Grimes * uipc_usrreq) unp_detach, which re-invokes unp_gc. Unp_gc simply 958df8bae1dSRodney W. Grimes * returns because the previous instance had set unp_gcing, and 959df8bae1dSRodney W. Grimes * we return all the way back to soclose, which marks the socket 960df8bae1dSRodney W. Grimes * with SS_NOFDREF, and then calls sofree. Sofree calls sorflush 961df8bae1dSRodney W. Grimes * to free up the rights that are queued in messages on the socket A, 962df8bae1dSRodney W. Grimes * i.e., the reference on B. The sorflush calls via the dom_dispose 963df8bae1dSRodney W. Grimes * switch unp_dispose, which unp_scans with unp_discard. This second 964df8bae1dSRodney W. Grimes * instance of unp_discard just calls closef on B. 965df8bae1dSRodney W. Grimes * 966df8bae1dSRodney W. Grimes * Well, a similar chain occurs on B, resulting in a sorflush on B, 967df8bae1dSRodney W. Grimes * which results in another closef on A. Unfortunately, A is already 968df8bae1dSRodney W. Grimes * being closed, and the descriptor has already been marked with 969df8bae1dSRodney W. Grimes * SS_NOFDREF, and soclose panics at this point. 970df8bae1dSRodney W. Grimes * 971df8bae1dSRodney W. Grimes * Here, we first take an extra reference to each inaccessible 972df8bae1dSRodney W. Grimes * descriptor. Then, we call sorflush ourself, since we know 973df8bae1dSRodney W. Grimes * it is a Unix domain socket anyhow. After we destroy all the 974df8bae1dSRodney W. Grimes * rights carried in messages, we do a last closef to get rid 975df8bae1dSRodney W. Grimes * of our extra reference. This is the last close, and the 976df8bae1dSRodney W. Grimes * unp_detach etc will shut down the socket. 977df8bae1dSRodney W. Grimes * 978df8bae1dSRodney W. Grimes * 91/09/19, bsy@cs.cmu.edu 979df8bae1dSRodney W. Grimes */ 980df8bae1dSRodney W. Grimes extra_ref = malloc(nfiles * sizeof(struct file *), M_FILE, M_WAITOK); 981bc6f0e79SJeffrey Hsu for (nunref = 0, fp = filehead.lh_first, fpp = extra_ref; fp != 0; 982bc6f0e79SJeffrey Hsu fp = nextfp) { 983bc6f0e79SJeffrey Hsu nextfp = fp->f_list.le_next; 984ed5b7817SJulian Elischer /* 985ed5b7817SJulian Elischer * If it's not open, skip it 986ed5b7817SJulian Elischer */ 987df8bae1dSRodney W. Grimes if (fp->f_count == 0) 988df8bae1dSRodney W. Grimes continue; 989ed5b7817SJulian Elischer /* 990ed5b7817SJulian Elischer * If all refs are from msgs, and it's not marked accessible 991ed5b7817SJulian Elischer * then it must be referenced from some unreachable cycle 992ed5b7817SJulian Elischer * of (shut-down) FDs, so include it in our 993ed5b7817SJulian Elischer * list of FDs to remove 994ed5b7817SJulian Elischer */ 995df8bae1dSRodney W. Grimes if (fp->f_count == fp->f_msgcount && !(fp->f_flag & FMARK)) { 996df8bae1dSRodney W. Grimes *fpp++ = fp; 997df8bae1dSRodney W. Grimes nunref++; 998df8bae1dSRodney W. Grimes fp->f_count++; 999df8bae1dSRodney W. Grimes } 1000df8bae1dSRodney W. Grimes } 1001ed5b7817SJulian Elischer /* 1002ed5b7817SJulian Elischer * for each FD on our hit list, do the following two things 1003ed5b7817SJulian Elischer */ 1004df8bae1dSRodney W. Grimes for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp) 1005df8bae1dSRodney W. Grimes sorflush((struct socket *)(*fpp)->f_data); 1006df8bae1dSRodney W. Grimes for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp) 100792cbac68SPoul-Henning Kamp closef(*fpp, (struct proc *) NULL); 1008df8bae1dSRodney W. Grimes free((caddr_t)extra_ref, M_FILE); 1009df8bae1dSRodney W. Grimes unp_gcing = 0; 1010df8bae1dSRodney W. Grimes } 1011df8bae1dSRodney W. Grimes 101226f9a767SRodney W. Grimes void 1013df8bae1dSRodney W. Grimes unp_dispose(m) 1014df8bae1dSRodney W. Grimes struct mbuf *m; 1015df8bae1dSRodney W. Grimes { 1016996c772fSJohn Dyson 1017df8bae1dSRodney W. Grimes if (m) 1018df8bae1dSRodney W. Grimes unp_scan(m, unp_discard); 1019df8bae1dSRodney W. Grimes } 1020df8bae1dSRodney W. Grimes 1021f708ef1bSPoul-Henning Kamp static void 1022df8bae1dSRodney W. Grimes unp_scan(m0, op) 1023df8bae1dSRodney W. Grimes register struct mbuf *m0; 1024996c772fSJohn Dyson void (*op) __P((struct file *)); 1025df8bae1dSRodney W. Grimes { 1026df8bae1dSRodney W. Grimes register struct mbuf *m; 1027df8bae1dSRodney W. Grimes register struct file **rp; 1028df8bae1dSRodney W. Grimes register struct cmsghdr *cm; 1029df8bae1dSRodney W. Grimes register int i; 1030df8bae1dSRodney W. Grimes int qfds; 1031df8bae1dSRodney W. Grimes 1032df8bae1dSRodney W. Grimes while (m0) { 1033df8bae1dSRodney W. Grimes for (m = m0; m; m = m->m_next) 1034df8bae1dSRodney W. Grimes if (m->m_type == MT_CONTROL && 1035df8bae1dSRodney W. Grimes m->m_len >= sizeof(*cm)) { 1036df8bae1dSRodney W. Grimes cm = mtod(m, struct cmsghdr *); 1037df8bae1dSRodney W. Grimes if (cm->cmsg_level != SOL_SOCKET || 1038df8bae1dSRodney W. Grimes cm->cmsg_type != SCM_RIGHTS) 1039df8bae1dSRodney W. Grimes continue; 1040df8bae1dSRodney W. Grimes qfds = (cm->cmsg_len - sizeof *cm) 1041df8bae1dSRodney W. Grimes / sizeof (struct file *); 1042df8bae1dSRodney W. Grimes rp = (struct file **)(cm + 1); 1043df8bae1dSRodney W. Grimes for (i = 0; i < qfds; i++) 1044df8bae1dSRodney W. Grimes (*op)(*rp++); 1045df8bae1dSRodney W. Grimes break; /* XXX, but saves time */ 1046df8bae1dSRodney W. Grimes } 1047df8bae1dSRodney W. Grimes m0 = m0->m_act; 1048df8bae1dSRodney W. Grimes } 1049df8bae1dSRodney W. Grimes } 1050df8bae1dSRodney W. Grimes 1051f708ef1bSPoul-Henning Kamp static void 1052df8bae1dSRodney W. Grimes unp_mark(fp) 1053df8bae1dSRodney W. Grimes struct file *fp; 1054df8bae1dSRodney W. Grimes { 1055df8bae1dSRodney W. Grimes 1056df8bae1dSRodney W. Grimes if (fp->f_flag & FMARK) 1057df8bae1dSRodney W. Grimes return; 1058df8bae1dSRodney W. Grimes unp_defer++; 1059df8bae1dSRodney W. Grimes fp->f_flag |= (FMARK|FDEFER); 1060df8bae1dSRodney W. Grimes } 1061df8bae1dSRodney W. Grimes 1062f708ef1bSPoul-Henning Kamp static void 1063df8bae1dSRodney W. Grimes unp_discard(fp) 1064df8bae1dSRodney W. Grimes struct file *fp; 1065df8bae1dSRodney W. Grimes { 1066df8bae1dSRodney W. Grimes 1067df8bae1dSRodney W. Grimes fp->f_msgcount--; 1068df8bae1dSRodney W. Grimes unp_rights--; 1069df8bae1dSRodney W. Grimes (void) closef(fp, (struct proc *)NULL); 1070df8bae1dSRodney W. Grimes } 1071