123443Smckusick /* 237616Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 333288Sbostic * All rights reserved. 423443Smckusick * 533288Sbostic * Redistribution and use in source and binary forms are permitted 634859Sbostic * provided that the above copyright notice and this paragraph are 734859Sbostic * duplicated in all such forms and that any documentation, 834859Sbostic * advertising materials, and other materials related to such 934859Sbostic * distribution and use acknowledge that the software was developed 1034859Sbostic * by the University of California, Berkeley. The name of the 1134859Sbostic * University may not be used to endorse or promote products derived 1234859Sbostic * from this software without specific prior written permission. 1334859Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434859Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1537616Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1633288Sbostic * 17*41381Smckusick * @(#)uipc_usrreq.c 7.17 (Berkeley) 05/04/90 1823443Smckusick */ 198925Sroot 2017105Sbloom #include "param.h" 2117105Sbloom #include "user.h" 2217105Sbloom #include "domain.h" 2317105Sbloom #include "protosw.h" 2417105Sbloom #include "socket.h" 2517105Sbloom #include "socketvar.h" 2617105Sbloom #include "unpcb.h" 2717105Sbloom #include "un.h" 2837616Smckusick #include "vnode.h" 2917105Sbloom #include "file.h" 3017105Sbloom #include "stat.h" 31*41381Smckusick #include "mbuf.h" 328925Sroot 338925Sroot /* 348925Sroot * Unix communications domain. 3512760Ssam * 3612760Ssam * TODO: 3712760Ssam * SEQPACKET, RDM 3813119Ssam * rethink name space problems 3912760Ssam * need a proper out-of-band 408925Sroot */ 4137617Smckusick struct sockaddr sun_noname = { sizeof(sun_noname), AF_UNIX }; 4240800Ssklower ino_t unp_ino; /* prototype for fake inode numbers */ 438925Sroot 448925Sroot /*ARGSUSED*/ 4540800Ssklower uipc_usrreq(so, req, m, nam, control) 468925Sroot struct socket *so; 478925Sroot int req; 4840800Ssklower struct mbuf *m, *nam, *control; 498925Sroot { 508925Sroot struct unpcb *unp = sotounpcb(so); 518925Sroot register struct socket *so2; 5240937Skarels register int error = 0; 538925Sroot 5425555Skarels if (req == PRU_CONTROL) 5525555Skarels return (EOPNOTSUPP); 5640800Ssklower if (req != PRU_SEND && control && control->m_len) { 5712760Ssam error = EOPNOTSUPP; 5812760Ssam goto release; 5912760Ssam } 6012760Ssam if (unp == 0 && req != PRU_ATTACH) { 6112760Ssam error = EINVAL; 6212760Ssam goto release; 6312760Ssam } 648925Sroot switch (req) { 658925Sroot 668925Sroot case PRU_ATTACH: 678925Sroot if (unp) { 689169Ssam error = EISCONN; 698925Sroot break; 708925Sroot } 719028Sroot error = unp_attach(so); 728925Sroot break; 738925Sroot 748925Sroot case PRU_DETACH: 758925Sroot unp_detach(unp); 768925Sroot break; 778925Sroot 789169Ssam case PRU_BIND: 799169Ssam error = unp_bind(unp, nam); 809169Ssam break; 819169Ssam 829169Ssam case PRU_LISTEN: 8337616Smckusick if (unp->unp_vnode == 0) 849169Ssam error = EINVAL; 859169Ssam break; 869169Ssam 878925Sroot case PRU_CONNECT: 889028Sroot error = unp_connect(so, nam); 898925Sroot break; 908925Sroot 9112760Ssam case PRU_CONNECT2: 9226281Skarels error = unp_connect2(so, (struct socket *)nam); 9312760Ssam break; 9412760Ssam 958925Sroot case PRU_DISCONNECT: 968925Sroot unp_disconnect(unp); 978925Sroot break; 988925Sroot 999169Ssam case PRU_ACCEPT: 10025899Skarels /* 10125899Skarels * Pass back name of connected socket, 10225899Skarels * if it was bound and we are still connected 10325899Skarels * (our peer may have closed already!). 10425899Skarels */ 10525899Skarels if (unp->unp_conn && unp->unp_conn->unp_addr) { 10625632Skarels nam->m_len = unp->unp_conn->unp_addr->m_len; 10725632Skarels bcopy(mtod(unp->unp_conn->unp_addr, caddr_t), 10825632Skarels mtod(nam, caddr_t), (unsigned)nam->m_len); 10925632Skarels } else { 11025632Skarels nam->m_len = sizeof(sun_noname); 11125632Skarels *(mtod(nam, struct sockaddr *)) = sun_noname; 11225632Skarels } 1138925Sroot break; 1148925Sroot 1158925Sroot case PRU_SHUTDOWN: 1168925Sroot socantsendmore(so); 1178925Sroot unp_usrclosed(unp); 1188925Sroot break; 1198925Sroot 1208925Sroot case PRU_RCVD: 1218925Sroot switch (so->so_type) { 1228925Sroot 1238925Sroot case SOCK_DGRAM: 1248925Sroot panic("uipc 1"); 12510139Ssam /*NOTREACHED*/ 1268925Sroot 12710139Ssam case SOCK_STREAM: 1288925Sroot #define rcv (&so->so_rcv) 1298925Sroot #define snd (&so2->so_snd) 1308925Sroot if (unp->unp_conn == 0) 1318925Sroot break; 1328925Sroot so2 = unp->unp_conn->unp_socket; 1338925Sroot /* 13425632Skarels * Adjust backpressure on sender 1358925Sroot * and wakeup any waiting to write. 1368925Sroot */ 13725632Skarels snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt; 13825632Skarels unp->unp_mbcnt = rcv->sb_mbcnt; 13925632Skarels snd->sb_hiwat += unp->unp_cc - rcv->sb_cc; 14025632Skarels unp->unp_cc = rcv->sb_cc; 14117543Skarels sowwakeup(so2); 1428925Sroot #undef snd 1438925Sroot #undef rcv 1448925Sroot break; 1458925Sroot 1468925Sroot default: 1478925Sroot panic("uipc 2"); 1488925Sroot } 1498925Sroot break; 1508925Sroot 1518925Sroot case PRU_SEND: 15240937Skarels if (control && (error = unp_internalize(control))) 15340937Skarels break; 1548925Sroot switch (so->so_type) { 1558925Sroot 15625632Skarels case SOCK_DGRAM: { 15725632Skarels struct sockaddr *from; 15825632Skarels 1599028Sroot if (nam) { 1608925Sroot if (unp->unp_conn) { 1618925Sroot error = EISCONN; 1628925Sroot break; 1638925Sroot } 1649028Sroot error = unp_connect(so, nam); 1658925Sroot if (error) 1668925Sroot break; 1678925Sroot } else { 1688925Sroot if (unp->unp_conn == 0) { 1698925Sroot error = ENOTCONN; 1708925Sroot break; 1718925Sroot } 1728925Sroot } 1738925Sroot so2 = unp->unp_conn->unp_socket; 17425632Skarels if (unp->unp_addr) 17525632Skarels from = mtod(unp->unp_addr, struct sockaddr *); 17625632Skarels else 17725632Skarels from = &sun_noname; 17840937Skarels if (sbappendaddr(&so2->so_rcv, from, m, control)) { 17925632Skarels sorwakeup(so2); 18025632Skarels m = 0; 18140937Skarels control = 0; 18225632Skarels } else 18325632Skarels error = ENOBUFS; 1849028Sroot if (nam) 1859169Ssam unp_disconnect(unp); 1868925Sroot break; 18725632Skarels } 1888925Sroot 1898925Sroot case SOCK_STREAM: 1908925Sroot #define rcv (&so2->so_rcv) 1918925Sroot #define snd (&so->so_snd) 19223524Skarels if (so->so_state & SS_CANTSENDMORE) { 19323524Skarels error = EPIPE; 19423524Skarels break; 19523524Skarels } 1968925Sroot if (unp->unp_conn == 0) 1978925Sroot panic("uipc 3"); 1988925Sroot so2 = unp->unp_conn->unp_socket; 1998925Sroot /* 20025632Skarels * Send to paired receive port, and then reduce 20125632Skarels * send buffer hiwater marks to maintain backpressure. 2028925Sroot * Wake up readers. 2038925Sroot */ 20440937Skarels if (control) { 20540937Skarels (void)sbappendcontrol(rcv, m, control); 20640937Skarels control = 0; 20740937Skarels } else 20825632Skarels sbappend(rcv, m); 20925632Skarels snd->sb_mbmax -= 21025632Skarels rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt; 21125632Skarels unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt; 21225632Skarels snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc; 21325632Skarels unp->unp_conn->unp_cc = rcv->sb_cc; 21417543Skarels sorwakeup(so2); 21517543Skarels m = 0; 2168925Sroot #undef snd 2178925Sroot #undef rcv 2188925Sroot break; 2198925Sroot 2208925Sroot default: 2218925Sroot panic("uipc 4"); 2228925Sroot } 2238925Sroot break; 2248925Sroot 2258925Sroot case PRU_ABORT: 2268925Sroot unp_drop(unp, ECONNABORTED); 2278925Sroot break; 2288925Sroot 2298925Sroot case PRU_SENSE: 23016973Skarels ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat; 23116973Skarels if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) { 23216973Skarels so2 = unp->unp_conn->unp_socket; 23316973Skarels ((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc; 23416973Skarels } 23521110Skarels ((struct stat *) m)->st_dev = NODEV; 23640800Ssklower if (unp->unp_ino == 0) 23740800Ssklower unp->unp_ino = unp_ino++; 23840800Ssklower ((struct stat *) m)->st_ino = unp->unp_ino; 23916973Skarels return (0); 2408925Sroot 2418925Sroot case PRU_RCVOOB: 24216774Sbloom return (EOPNOTSUPP); 2438925Sroot 2448925Sroot case PRU_SENDOOB: 24517543Skarels error = EOPNOTSUPP; 2468925Sroot break; 2478925Sroot 2488925Sroot case PRU_SOCKADDR: 24937617Smckusick if (unp->unp_addr) { 25037617Smckusick nam->m_len = unp->unp_addr->m_len; 25137617Smckusick bcopy(mtod(unp->unp_addr, caddr_t), 25237617Smckusick mtod(nam, caddr_t), (unsigned)nam->m_len); 25337617Smckusick } else 25437617Smckusick nam->m_len = 0; 2558925Sroot break; 2568925Sroot 25714121Ssam case PRU_PEERADDR: 25828292Skarels if (unp->unp_conn && unp->unp_conn->unp_addr) { 25928292Skarels nam->m_len = unp->unp_conn->unp_addr->m_len; 26028292Skarels bcopy(mtod(unp->unp_conn->unp_addr, caddr_t), 26133287Sbostic mtod(nam, caddr_t), (unsigned)nam->m_len); 26237617Smckusick } else 26337617Smckusick nam->m_len = 0; 26414121Ssam break; 26514121Ssam 2668925Sroot case PRU_SLOWTIMO: 2678925Sroot break; 2688925Sroot 2698925Sroot default: 2708925Sroot panic("piusrreq"); 2718925Sroot } 27212760Ssam release: 27340937Skarels if (control) 27440937Skarels m_freem(control); 27512760Ssam if (m) 27612760Ssam m_freem(m); 27711709Ssam return (error); 2788925Sroot } 2798925Sroot 28016973Skarels /* 28125632Skarels * Both send and receive buffers are allocated PIPSIZ bytes of buffering 28225632Skarels * for stream sockets, although the total for sender and receiver is 28325632Skarels * actually only PIPSIZ. 28416973Skarels * Datagram sockets really use the sendspace as the maximum datagram size, 28516973Skarels * and don't really want to reserve the sendspace. Their recvspace should 28616973Skarels * be large enough for at least one max-size datagram plus address. 28716973Skarels */ 28816973Skarels #define PIPSIZ 4096 28937617Smckusick u_long unpst_sendspace = PIPSIZ; 29037617Smckusick u_long unpst_recvspace = PIPSIZ; 29137617Smckusick u_long unpdg_sendspace = 2*1024; /* really max datagram size */ 29237617Smckusick u_long unpdg_recvspace = 4*1024; 2938925Sroot 29425632Skarels int unp_rights; /* file descriptors in flight */ 29525632Skarels 2969169Ssam unp_attach(so) 2978925Sroot struct socket *so; 2988925Sroot { 2999169Ssam register struct mbuf *m; 3008925Sroot register struct unpcb *unp; 3018925Sroot int error; 3028925Sroot 30337617Smckusick if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 30437617Smckusick switch (so->so_type) { 30516973Skarels 30637617Smckusick case SOCK_STREAM: 30737617Smckusick error = soreserve(so, unpst_sendspace, unpst_recvspace); 30837617Smckusick break; 30916973Skarels 31037617Smckusick case SOCK_DGRAM: 31137617Smckusick error = soreserve(so, unpdg_sendspace, unpdg_recvspace); 31237617Smckusick break; 31337617Smckusick } 31437617Smckusick if (error) 31537617Smckusick return (error); 31616973Skarels } 3179637Ssam m = m_getclr(M_DONTWAIT, MT_PCB); 31810139Ssam if (m == NULL) 31910139Ssam return (ENOBUFS); 3208925Sroot unp = mtod(m, struct unpcb *); 3218925Sroot so->so_pcb = (caddr_t)unp; 3228925Sroot unp->unp_socket = so; 3238925Sroot return (0); 3248925Sroot } 3258925Sroot 3268925Sroot unp_detach(unp) 3279169Ssam register struct unpcb *unp; 3288925Sroot { 3298925Sroot 33037616Smckusick if (unp->unp_vnode) { 33137616Smckusick unp->unp_vnode->v_socket = 0; 33237616Smckusick vrele(unp->unp_vnode); 33337616Smckusick unp->unp_vnode = 0; 3348925Sroot } 3358925Sroot if (unp->unp_conn) 3368925Sroot unp_disconnect(unp); 3378925Sroot while (unp->unp_refs) 3388925Sroot unp_drop(unp->unp_refs, ECONNRESET); 3398925Sroot soisdisconnected(unp->unp_socket); 3408925Sroot unp->unp_socket->so_pcb = 0; 34125632Skarels m_freem(unp->unp_addr); 3429169Ssam (void) m_free(dtom(unp)); 34325632Skarels if (unp_rights) 34425632Skarels unp_gc(); 3458925Sroot } 3468925Sroot 3479169Ssam unp_bind(unp, nam) 3488925Sroot struct unpcb *unp; 3499169Ssam struct mbuf *nam; 3508925Sroot { 3519169Ssam struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 35237616Smckusick register struct vnode *vp; 35316695Smckusick register struct nameidata *ndp = &u.u_nd; 35437616Smckusick struct vattr vattr; 3558925Sroot int error; 3568925Sroot 35716695Smckusick ndp->ni_dirp = soun->sun_path; 35837617Smckusick if (unp->unp_vnode != NULL) 35912760Ssam return (EINVAL); 36037617Smckusick if (nam->m_len == MLEN) { 36137617Smckusick if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0) 36237617Smckusick return (EINVAL); 36337617Smckusick } else 36437617Smckusick *(mtod(nam, caddr_t) + nam->m_len) = 0; 36512760Ssam /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ 36637616Smckusick ndp->ni_nameiop = CREATE | FOLLOW | LOCKPARENT; 36716695Smckusick ndp->ni_segflg = UIO_SYSSPACE; 36837616Smckusick if (error = namei(ndp)) 36937616Smckusick return (error); 37037616Smckusick vp = ndp->ni_vp; 37137616Smckusick if (vp != NULL) { 37237728Smckusick VOP_ABORTOP(ndp); 37310139Ssam return (EADDRINUSE); 3748925Sroot } 37541362Smckusick VATTR_NULL(&vattr); 37637616Smckusick vattr.va_type = VSOCK; 37737616Smckusick vattr.va_mode = 0777; 37837728Smckusick if (error = VOP_CREATE(ndp, &vattr)) 37911828Ssam return (error); 38037616Smckusick vp = ndp->ni_vp; 38137616Smckusick vp->v_socket = unp->unp_socket; 38237616Smckusick unp->unp_vnode = vp; 38325632Skarels unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL); 38437728Smckusick VOP_UNLOCK(vp); 3858925Sroot return (0); 3868925Sroot } 3878925Sroot 3889169Ssam unp_connect(so, nam) 3898925Sroot struct socket *so; 3909169Ssam struct mbuf *nam; 3918925Sroot { 3929169Ssam register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 39337616Smckusick register struct vnode *vp; 39437617Smckusick register struct socket *so2, *so3; 39537617Smckusick register struct nameidata *ndp = &u.u_nd; 39637617Smckusick struct unpcb *unp2, *unp3; 39737616Smckusick int error; 3988925Sroot 39916695Smckusick ndp->ni_dirp = soun->sun_path; 40037617Smckusick if (nam->m_data + nam->m_len == &nam->m_dat[MLEN]) { /* XXX */ 40137617Smckusick if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0) 40237617Smckusick return (EMSGSIZE); 40337617Smckusick } else 40437617Smckusick *(mtod(nam, caddr_t) + nam->m_len) = 0; 40537728Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 40616695Smckusick ndp->ni_segflg = UIO_SYSSPACE; 40737616Smckusick if (error = namei(ndp)) 40837616Smckusick return (error); 40937616Smckusick vp = ndp->ni_vp; 41037616Smckusick if (vp->v_type != VSOCK) { 4118925Sroot error = ENOTSOCK; 4128925Sroot goto bad; 4138925Sroot } 41438396Smckusick if (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)) 41538396Smckusick goto bad; 41637616Smckusick so2 = vp->v_socket; 4178925Sroot if (so2 == 0) { 4188925Sroot error = ECONNREFUSED; 4198925Sroot goto bad; 4208925Sroot } 42113115Ssam if (so->so_type != so2->so_type) { 42213115Ssam error = EPROTOTYPE; 42313115Ssam goto bad; 42413115Ssam } 42537617Smckusick if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 42637617Smckusick if ((so2->so_options & SO_ACCEPTCONN) == 0 || 42740800Ssklower (so3 = sonewconn(so2, 0)) == 0) { 42837617Smckusick error = ECONNREFUSED; 42937617Smckusick goto bad; 43037617Smckusick } 43137617Smckusick unp2 = sotounpcb(so2); 43237617Smckusick unp3 = sotounpcb(so3); 43337617Smckusick if (unp2->unp_addr) 43437617Smckusick unp3->unp_addr = 43537617Smckusick m_copy(unp2->unp_addr, 0, (int)M_COPYALL); 43637617Smckusick so2 = so3; 43713115Ssam } 43826281Skarels error = unp_connect2(so, so2); 43912760Ssam bad: 44037728Smckusick vput(vp); 44112760Ssam return (error); 44212760Ssam } 44312760Ssam 44426281Skarels unp_connect2(so, so2) 44512760Ssam register struct socket *so; 44612760Ssam register struct socket *so2; 44712760Ssam { 44812760Ssam register struct unpcb *unp = sotounpcb(so); 44912760Ssam register struct unpcb *unp2; 45012760Ssam 45112760Ssam if (so2->so_type != so->so_type) 45212760Ssam return (EPROTOTYPE); 45314049Ssam unp2 = sotounpcb(so2); 45414049Ssam unp->unp_conn = unp2; 4558925Sroot switch (so->so_type) { 4568925Sroot 4578925Sroot case SOCK_DGRAM: 4588925Sroot unp->unp_nextref = unp2->unp_refs; 4598925Sroot unp2->unp_refs = unp; 46017543Skarels soisconnected(so); 4618925Sroot break; 4628925Sroot 4638925Sroot case SOCK_STREAM: 4649169Ssam unp2->unp_conn = unp; 46540800Ssklower soisconnected(so); 46614049Ssam soisconnected(so2); 4678925Sroot break; 4688925Sroot 4698925Sroot default: 47012760Ssam panic("unp_connect2"); 4718925Sroot } 4728925Sroot return (0); 4738925Sroot } 4749169Ssam 4759169Ssam unp_disconnect(unp) 4769169Ssam struct unpcb *unp; 4779169Ssam { 4789169Ssam register struct unpcb *unp2 = unp->unp_conn; 4799169Ssam 4809169Ssam if (unp2 == 0) 4819169Ssam return; 4829169Ssam unp->unp_conn = 0; 4839169Ssam switch (unp->unp_socket->so_type) { 4849169Ssam 4859169Ssam case SOCK_DGRAM: 4869169Ssam if (unp2->unp_refs == unp) 4879169Ssam unp2->unp_refs = unp->unp_nextref; 4889169Ssam else { 4899169Ssam unp2 = unp2->unp_refs; 4909169Ssam for (;;) { 4919169Ssam if (unp2 == 0) 4929169Ssam panic("unp_disconnect"); 4939169Ssam if (unp2->unp_nextref == unp) 4949169Ssam break; 4959169Ssam unp2 = unp2->unp_nextref; 4969169Ssam } 4979169Ssam unp2->unp_nextref = unp->unp_nextref; 4989169Ssam } 4999169Ssam unp->unp_nextref = 0; 50021768Skarels unp->unp_socket->so_state &= ~SS_ISCONNECTED; 5019169Ssam break; 5029169Ssam 5039169Ssam case SOCK_STREAM: 50414049Ssam soisdisconnected(unp->unp_socket); 5059169Ssam unp2->unp_conn = 0; 5069169Ssam soisdisconnected(unp2->unp_socket); 5079169Ssam break; 5089169Ssam } 5099169Ssam } 5109169Ssam 51112760Ssam #ifdef notdef 5129169Ssam unp_abort(unp) 5139169Ssam struct unpcb *unp; 5149169Ssam { 5159169Ssam 5169169Ssam unp_detach(unp); 5179169Ssam } 51812760Ssam #endif 5199169Ssam 5209169Ssam /*ARGSUSED*/ 5219169Ssam unp_usrclosed(unp) 5229169Ssam struct unpcb *unp; 5239169Ssam { 5249169Ssam 5259169Ssam } 5269169Ssam 5279169Ssam unp_drop(unp, errno) 5289169Ssam struct unpcb *unp; 5299169Ssam int errno; 5309169Ssam { 53116054Skarels struct socket *so = unp->unp_socket; 5329169Ssam 53316054Skarels so->so_error = errno; 5349169Ssam unp_disconnect(unp); 53516054Skarels if (so->so_head) { 53616054Skarels so->so_pcb = (caddr_t) 0; 53725632Skarels m_freem(unp->unp_addr); 53816054Skarels (void) m_free(dtom(unp)); 53916054Skarels sofree(so); 54016054Skarels } 5419169Ssam } 5429169Ssam 54312760Ssam #ifdef notdef 5449169Ssam unp_drain() 5459169Ssam { 5469169Ssam 5479169Ssam } 54812760Ssam #endif 54912760Ssam 55012760Ssam unp_externalize(rights) 55112760Ssam struct mbuf *rights; 55212760Ssam { 55312760Ssam register int i; 55440800Ssklower register struct cmsghdr *cm = mtod(rights, struct cmsghdr *); 55540800Ssklower register struct file **rp = (struct file **)(cm + 1); 55612760Ssam register struct file *fp; 55740800Ssklower int newfds = (cm->cmsg_len - sizeof(*cm)) / sizeof (int); 55812760Ssam int f; 55912760Ssam 56012760Ssam if (newfds > ufavail()) { 56112760Ssam for (i = 0; i < newfds; i++) { 56212760Ssam fp = *rp; 56312760Ssam unp_discard(fp); 56412760Ssam *rp++ = 0; 56512760Ssam } 56612760Ssam return (EMSGSIZE); 56712760Ssam } 56812760Ssam for (i = 0; i < newfds; i++) { 56937616Smckusick if (ufalloc(0, &f)) 57012760Ssam panic("unp_externalize"); 57112760Ssam fp = *rp; 57212760Ssam u.u_ofile[f] = fp; 57312760Ssam fp->f_msgcount--; 57425632Skarels unp_rights--; 57514927Smckusick *(int *)rp++ = f; 57612760Ssam } 57712760Ssam return (0); 57812760Ssam } 57912760Ssam 58040937Skarels unp_internalize(control) 58140937Skarels struct mbuf *control; 58212760Ssam { 58340937Skarels register struct cmsghdr *cm = mtod(control, struct cmsghdr *); 58412760Ssam register struct file **rp; 58540937Skarels register struct file *fp; 58637728Smckusick register int i, fd; 58740937Skarels int oldfds; 58812760Ssam 58940937Skarels if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET || 59040937Skarels cm->cmsg_len != control->m_len) 59140800Ssklower return (EINVAL); 59240800Ssklower oldfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int); 59340800Ssklower rp = (struct file **)(cm + 1); 59437728Smckusick for (i = 0; i < oldfds; i++) { 59537728Smckusick fd = *(int *)rp++; 59637728Smckusick if ((unsigned)fd >= NOFILE || u.u_ofile[fd] == NULL) 59712760Ssam return (EBADF); 59837728Smckusick } 59940800Ssklower rp = (struct file **)(cm + 1); 60013084Ssam for (i = 0; i < oldfds; i++) { 60137728Smckusick fp = u.u_ofile[*(int *)rp]; 60212760Ssam *rp++ = fp; 60312760Ssam fp->f_count++; 60412760Ssam fp->f_msgcount++; 60525632Skarels unp_rights++; 60612760Ssam } 60712760Ssam return (0); 60812760Ssam } 60912760Ssam 61012760Ssam int unp_defer, unp_gcing; 61112760Ssam int unp_mark(); 61216995Skarels extern struct domain unixdomain; 61312760Ssam 61412760Ssam unp_gc() 61512760Ssam { 61612760Ssam register struct file *fp; 61712760Ssam register struct socket *so; 61812760Ssam 61912760Ssam if (unp_gcing) 62012760Ssam return; 62112760Ssam unp_gcing = 1; 62212760Ssam restart: 62312760Ssam unp_defer = 0; 62412760Ssam for (fp = file; fp < fileNFILE; fp++) 62512760Ssam fp->f_flag &= ~(FMARK|FDEFER); 62612760Ssam do { 62712760Ssam for (fp = file; fp < fileNFILE; fp++) { 62812760Ssam if (fp->f_count == 0) 62912760Ssam continue; 63012760Ssam if (fp->f_flag & FDEFER) { 63112760Ssam fp->f_flag &= ~FDEFER; 63212760Ssam unp_defer--; 63312760Ssam } else { 63412760Ssam if (fp->f_flag & FMARK) 63512760Ssam continue; 63612760Ssam if (fp->f_count == fp->f_msgcount) 63712760Ssam continue; 63812760Ssam fp->f_flag |= FMARK; 63912760Ssam } 64037617Smckusick if (fp->f_type != DTYPE_SOCKET || 64137617Smckusick (so = (struct socket *)fp->f_data) == 0) 64212760Ssam continue; 64316995Skarels if (so->so_proto->pr_domain != &unixdomain || 64421768Skarels (so->so_proto->pr_flags&PR_RIGHTS) == 0) 64512760Ssam continue; 64612760Ssam if (so->so_rcv.sb_flags & SB_LOCK) { 64712760Ssam sbwait(&so->so_rcv); 64812760Ssam goto restart; 64912760Ssam } 65012760Ssam unp_scan(so->so_rcv.sb_mb, unp_mark); 65112760Ssam } 65212760Ssam } while (unp_defer); 65312760Ssam for (fp = file; fp < fileNFILE; fp++) { 65412760Ssam if (fp->f_count == 0) 65512760Ssam continue; 65625632Skarels if (fp->f_count == fp->f_msgcount && (fp->f_flag & FMARK) == 0) 65725632Skarels while (fp->f_msgcount) 65825632Skarels unp_discard(fp); 65912760Ssam } 66012760Ssam unp_gcing = 0; 66112760Ssam } 66212760Ssam 66316995Skarels unp_dispose(m) 66416995Skarels struct mbuf *m; 66516995Skarels { 66616995Skarels int unp_discard(); 66716995Skarels 66817020Skarels if (m) 66917020Skarels unp_scan(m, unp_discard); 67016995Skarels } 67116995Skarels 67216995Skarels unp_scan(m0, op) 67316995Skarels register struct mbuf *m0; 67412760Ssam int (*op)(); 67512760Ssam { 67616995Skarels register struct mbuf *m; 67712760Ssam register struct file **rp; 67840937Skarels register struct cmsghdr *cm; 67912760Ssam register int i; 68017020Skarels int qfds; 68112760Ssam 68216995Skarels while (m0) { 68316995Skarels for (m = m0; m; m = m->m_next) 68440937Skarels if (m->m_type == MT_CONTROL && 68540937Skarels m->m_len >= sizeof(*cm)) { 68640800Ssklower cm = mtod(m, struct cmsghdr *); 68740937Skarels if (cm->cmsg_level != SOL_SOCKET || 68840937Skarels cm->cmsg_type != SCM_RIGHTS) 68940937Skarels continue; 69040800Ssklower qfds = (cm->cmsg_len - sizeof *cm) 69140800Ssklower / sizeof (struct file *); 69240800Ssklower rp = (struct file **)(cm + 1); 69316995Skarels for (i = 0; i < qfds; i++) 69416995Skarels (*op)(*rp++); 69516995Skarels break; /* XXX, but saves time */ 69616995Skarels } 69717020Skarels m0 = m0->m_act; 69812760Ssam } 69912760Ssam } 70012760Ssam 70112760Ssam unp_mark(fp) 70212760Ssam struct file *fp; 70312760Ssam { 70412760Ssam 70512760Ssam if (fp->f_flag & FMARK) 70612760Ssam return; 70712760Ssam unp_defer++; 70812760Ssam fp->f_flag |= (FMARK|FDEFER); 70912760Ssam } 71012760Ssam 71112760Ssam unp_discard(fp) 71212760Ssam struct file *fp; 71312760Ssam { 71412760Ssam 71512760Ssam fp->f_msgcount--; 71625632Skarels unp_rights--; 71739353Smckusick (void) closef(fp); 71812760Ssam } 719