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*43342Smckusick * @(#)uipc_usrreq.c 7.19 (Berkeley) 06/21/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" 3141381Smckusick #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); 373*43342Smckusick if (ndp->ni_dvp == vp) 374*43342Smckusick vrele(ndp->ni_dvp); 375*43342Smckusick else 376*43342Smckusick vput(ndp->ni_dvp); 37742465Smckusick vrele(vp); 37810139Ssam return (EADDRINUSE); 3798925Sroot } 38041362Smckusick VATTR_NULL(&vattr); 38137616Smckusick vattr.va_type = VSOCK; 38237616Smckusick vattr.va_mode = 0777; 38337728Smckusick if (error = VOP_CREATE(ndp, &vattr)) 38411828Ssam return (error); 38537616Smckusick vp = ndp->ni_vp; 38637616Smckusick vp->v_socket = unp->unp_socket; 38737616Smckusick unp->unp_vnode = vp; 38825632Skarels unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL); 38937728Smckusick VOP_UNLOCK(vp); 3908925Sroot return (0); 3918925Sroot } 3928925Sroot 3939169Ssam unp_connect(so, nam) 3948925Sroot struct socket *so; 3959169Ssam struct mbuf *nam; 3968925Sroot { 3979169Ssam register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 39837616Smckusick register struct vnode *vp; 39937617Smckusick register struct socket *so2, *so3; 40037617Smckusick register struct nameidata *ndp = &u.u_nd; 40137617Smckusick struct unpcb *unp2, *unp3; 40237616Smckusick int error; 4038925Sroot 40416695Smckusick ndp->ni_dirp = soun->sun_path; 40537617Smckusick if (nam->m_data + nam->m_len == &nam->m_dat[MLEN]) { /* XXX */ 40637617Smckusick if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0) 40737617Smckusick return (EMSGSIZE); 40837617Smckusick } else 40937617Smckusick *(mtod(nam, caddr_t) + nam->m_len) = 0; 41037728Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 41116695Smckusick ndp->ni_segflg = UIO_SYSSPACE; 41237616Smckusick if (error = namei(ndp)) 41337616Smckusick return (error); 41437616Smckusick vp = ndp->ni_vp; 41537616Smckusick if (vp->v_type != VSOCK) { 4168925Sroot error = ENOTSOCK; 4178925Sroot goto bad; 4188925Sroot } 41938396Smckusick if (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)) 42038396Smckusick goto bad; 42137616Smckusick so2 = vp->v_socket; 4228925Sroot if (so2 == 0) { 4238925Sroot error = ECONNREFUSED; 4248925Sroot goto bad; 4258925Sroot } 42613115Ssam if (so->so_type != so2->so_type) { 42713115Ssam error = EPROTOTYPE; 42813115Ssam goto bad; 42913115Ssam } 43037617Smckusick if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 43137617Smckusick if ((so2->so_options & SO_ACCEPTCONN) == 0 || 43240800Ssklower (so3 = sonewconn(so2, 0)) == 0) { 43337617Smckusick error = ECONNREFUSED; 43437617Smckusick goto bad; 43537617Smckusick } 43637617Smckusick unp2 = sotounpcb(so2); 43737617Smckusick unp3 = sotounpcb(so3); 43837617Smckusick if (unp2->unp_addr) 43937617Smckusick unp3->unp_addr = 44037617Smckusick m_copy(unp2->unp_addr, 0, (int)M_COPYALL); 44137617Smckusick so2 = so3; 44213115Ssam } 44326281Skarels error = unp_connect2(so, so2); 44412760Ssam bad: 44537728Smckusick vput(vp); 44612760Ssam return (error); 44712760Ssam } 44812760Ssam 44926281Skarels unp_connect2(so, so2) 45012760Ssam register struct socket *so; 45112760Ssam register struct socket *so2; 45212760Ssam { 45312760Ssam register struct unpcb *unp = sotounpcb(so); 45412760Ssam register struct unpcb *unp2; 45512760Ssam 45612760Ssam if (so2->so_type != so->so_type) 45712760Ssam return (EPROTOTYPE); 45814049Ssam unp2 = sotounpcb(so2); 45914049Ssam unp->unp_conn = unp2; 4608925Sroot switch (so->so_type) { 4618925Sroot 4628925Sroot case SOCK_DGRAM: 4638925Sroot unp->unp_nextref = unp2->unp_refs; 4648925Sroot unp2->unp_refs = unp; 46517543Skarels soisconnected(so); 4668925Sroot break; 4678925Sroot 4688925Sroot case SOCK_STREAM: 4699169Ssam unp2->unp_conn = unp; 47040800Ssklower soisconnected(so); 47114049Ssam soisconnected(so2); 4728925Sroot break; 4738925Sroot 4748925Sroot default: 47512760Ssam panic("unp_connect2"); 4768925Sroot } 4778925Sroot return (0); 4788925Sroot } 4799169Ssam 4809169Ssam unp_disconnect(unp) 4819169Ssam struct unpcb *unp; 4829169Ssam { 4839169Ssam register struct unpcb *unp2 = unp->unp_conn; 4849169Ssam 4859169Ssam if (unp2 == 0) 4869169Ssam return; 4879169Ssam unp->unp_conn = 0; 4889169Ssam switch (unp->unp_socket->so_type) { 4899169Ssam 4909169Ssam case SOCK_DGRAM: 4919169Ssam if (unp2->unp_refs == unp) 4929169Ssam unp2->unp_refs = unp->unp_nextref; 4939169Ssam else { 4949169Ssam unp2 = unp2->unp_refs; 4959169Ssam for (;;) { 4969169Ssam if (unp2 == 0) 4979169Ssam panic("unp_disconnect"); 4989169Ssam if (unp2->unp_nextref == unp) 4999169Ssam break; 5009169Ssam unp2 = unp2->unp_nextref; 5019169Ssam } 5029169Ssam unp2->unp_nextref = unp->unp_nextref; 5039169Ssam } 5049169Ssam unp->unp_nextref = 0; 50521768Skarels unp->unp_socket->so_state &= ~SS_ISCONNECTED; 5069169Ssam break; 5079169Ssam 5089169Ssam case SOCK_STREAM: 50914049Ssam soisdisconnected(unp->unp_socket); 5109169Ssam unp2->unp_conn = 0; 5119169Ssam soisdisconnected(unp2->unp_socket); 5129169Ssam break; 5139169Ssam } 5149169Ssam } 5159169Ssam 51612760Ssam #ifdef notdef 5179169Ssam unp_abort(unp) 5189169Ssam struct unpcb *unp; 5199169Ssam { 5209169Ssam 5219169Ssam unp_detach(unp); 5229169Ssam } 52312760Ssam #endif 5249169Ssam 5259169Ssam /*ARGSUSED*/ 5269169Ssam unp_usrclosed(unp) 5279169Ssam struct unpcb *unp; 5289169Ssam { 5299169Ssam 5309169Ssam } 5319169Ssam 5329169Ssam unp_drop(unp, errno) 5339169Ssam struct unpcb *unp; 5349169Ssam int errno; 5359169Ssam { 53616054Skarels struct socket *so = unp->unp_socket; 5379169Ssam 53816054Skarels so->so_error = errno; 5399169Ssam unp_disconnect(unp); 54016054Skarels if (so->so_head) { 54116054Skarels so->so_pcb = (caddr_t) 0; 54225632Skarels m_freem(unp->unp_addr); 54316054Skarels (void) m_free(dtom(unp)); 54416054Skarels sofree(so); 54516054Skarels } 5469169Ssam } 5479169Ssam 54812760Ssam #ifdef notdef 5499169Ssam unp_drain() 5509169Ssam { 5519169Ssam 5529169Ssam } 55312760Ssam #endif 55412760Ssam 55512760Ssam unp_externalize(rights) 55612760Ssam struct mbuf *rights; 55712760Ssam { 55812760Ssam register int i; 55940800Ssklower register struct cmsghdr *cm = mtod(rights, struct cmsghdr *); 56040800Ssklower register struct file **rp = (struct file **)(cm + 1); 56112760Ssam register struct file *fp; 56240800Ssklower int newfds = (cm->cmsg_len - sizeof(*cm)) / sizeof (int); 56312760Ssam int f; 56412760Ssam 56512760Ssam if (newfds > ufavail()) { 56612760Ssam for (i = 0; i < newfds; i++) { 56712760Ssam fp = *rp; 56812760Ssam unp_discard(fp); 56912760Ssam *rp++ = 0; 57012760Ssam } 57112760Ssam return (EMSGSIZE); 57212760Ssam } 57312760Ssam for (i = 0; i < newfds; i++) { 57437616Smckusick if (ufalloc(0, &f)) 57512760Ssam panic("unp_externalize"); 57612760Ssam fp = *rp; 57712760Ssam u.u_ofile[f] = fp; 57812760Ssam fp->f_msgcount--; 57925632Skarels unp_rights--; 58014927Smckusick *(int *)rp++ = f; 58112760Ssam } 58212760Ssam return (0); 58312760Ssam } 58412760Ssam 58540937Skarels unp_internalize(control) 58640937Skarels struct mbuf *control; 58712760Ssam { 58840937Skarels register struct cmsghdr *cm = mtod(control, struct cmsghdr *); 58912760Ssam register struct file **rp; 59040937Skarels register struct file *fp; 59137728Smckusick register int i, fd; 59240937Skarels int oldfds; 59312760Ssam 59440937Skarels if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET || 59540937Skarels cm->cmsg_len != control->m_len) 59640800Ssklower return (EINVAL); 59740800Ssklower oldfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int); 59840800Ssklower rp = (struct file **)(cm + 1); 59937728Smckusick for (i = 0; i < oldfds; i++) { 60037728Smckusick fd = *(int *)rp++; 60137728Smckusick if ((unsigned)fd >= NOFILE || u.u_ofile[fd] == NULL) 60212760Ssam return (EBADF); 60337728Smckusick } 60440800Ssklower rp = (struct file **)(cm + 1); 60513084Ssam for (i = 0; i < oldfds; i++) { 60637728Smckusick fp = u.u_ofile[*(int *)rp]; 60712760Ssam *rp++ = fp; 60812760Ssam fp->f_count++; 60912760Ssam fp->f_msgcount++; 61025632Skarels unp_rights++; 61112760Ssam } 61212760Ssam return (0); 61312760Ssam } 61412760Ssam 61512760Ssam int unp_defer, unp_gcing; 61612760Ssam int unp_mark(); 61716995Skarels extern struct domain unixdomain; 61812760Ssam 61912760Ssam unp_gc() 62012760Ssam { 62112760Ssam register struct file *fp; 62212760Ssam register struct socket *so; 62312760Ssam 62412760Ssam if (unp_gcing) 62512760Ssam return; 62612760Ssam unp_gcing = 1; 62712760Ssam restart: 62812760Ssam unp_defer = 0; 62912760Ssam for (fp = file; fp < fileNFILE; fp++) 63012760Ssam fp->f_flag &= ~(FMARK|FDEFER); 63112760Ssam do { 63212760Ssam for (fp = file; fp < fileNFILE; fp++) { 63312760Ssam if (fp->f_count == 0) 63412760Ssam continue; 63512760Ssam if (fp->f_flag & FDEFER) { 63612760Ssam fp->f_flag &= ~FDEFER; 63712760Ssam unp_defer--; 63812760Ssam } else { 63912760Ssam if (fp->f_flag & FMARK) 64012760Ssam continue; 64112760Ssam if (fp->f_count == fp->f_msgcount) 64212760Ssam continue; 64312760Ssam fp->f_flag |= FMARK; 64412760Ssam } 64537617Smckusick if (fp->f_type != DTYPE_SOCKET || 64637617Smckusick (so = (struct socket *)fp->f_data) == 0) 64712760Ssam continue; 64816995Skarels if (so->so_proto->pr_domain != &unixdomain || 64921768Skarels (so->so_proto->pr_flags&PR_RIGHTS) == 0) 65012760Ssam continue; 65112760Ssam if (so->so_rcv.sb_flags & SB_LOCK) { 65212760Ssam sbwait(&so->so_rcv); 65312760Ssam goto restart; 65412760Ssam } 65512760Ssam unp_scan(so->so_rcv.sb_mb, unp_mark); 65612760Ssam } 65712760Ssam } while (unp_defer); 65812760Ssam for (fp = file; fp < fileNFILE; fp++) { 65912760Ssam if (fp->f_count == 0) 66012760Ssam continue; 66125632Skarels if (fp->f_count == fp->f_msgcount && (fp->f_flag & FMARK) == 0) 66225632Skarels while (fp->f_msgcount) 66325632Skarels unp_discard(fp); 66412760Ssam } 66512760Ssam unp_gcing = 0; 66612760Ssam } 66712760Ssam 66816995Skarels unp_dispose(m) 66916995Skarels struct mbuf *m; 67016995Skarels { 67116995Skarels int unp_discard(); 67216995Skarels 67317020Skarels if (m) 67417020Skarels unp_scan(m, unp_discard); 67516995Skarels } 67616995Skarels 67716995Skarels unp_scan(m0, op) 67816995Skarels register struct mbuf *m0; 67912760Ssam int (*op)(); 68012760Ssam { 68116995Skarels register struct mbuf *m; 68212760Ssam register struct file **rp; 68340937Skarels register struct cmsghdr *cm; 68412760Ssam register int i; 68517020Skarels int qfds; 68612760Ssam 68716995Skarels while (m0) { 68816995Skarels for (m = m0; m; m = m->m_next) 68940937Skarels if (m->m_type == MT_CONTROL && 69040937Skarels m->m_len >= sizeof(*cm)) { 69140800Ssklower cm = mtod(m, struct cmsghdr *); 69240937Skarels if (cm->cmsg_level != SOL_SOCKET || 69340937Skarels cm->cmsg_type != SCM_RIGHTS) 69440937Skarels continue; 69540800Ssklower qfds = (cm->cmsg_len - sizeof *cm) 69640800Ssklower / sizeof (struct file *); 69740800Ssklower rp = (struct file **)(cm + 1); 69816995Skarels for (i = 0; i < qfds; i++) 69916995Skarels (*op)(*rp++); 70016995Skarels break; /* XXX, but saves time */ 70116995Skarels } 70217020Skarels m0 = m0->m_act; 70312760Ssam } 70412760Ssam } 70512760Ssam 70612760Ssam unp_mark(fp) 70712760Ssam struct file *fp; 70812760Ssam { 70912760Ssam 71012760Ssam if (fp->f_flag & FMARK) 71112760Ssam return; 71212760Ssam unp_defer++; 71312760Ssam fp->f_flag |= (FMARK|FDEFER); 71412760Ssam } 71512760Ssam 71612760Ssam unp_discard(fp) 71712760Ssam struct file *fp; 71812760Ssam { 71912760Ssam 72012760Ssam fp->f_msgcount--; 72125632Skarels unp_rights--; 72239353Smckusick (void) closef(fp); 72312760Ssam } 724