123443Smckusick /* 237616Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 333288Sbostic * All rights reserved. 423443Smckusick * 544453Sbostic * %sccs.include.redist.c% 633288Sbostic * 7*45004Skarels * @(#)uipc_usrreq.c 7.21 (Berkeley) 07/27/90 823443Smckusick */ 98925Sroot 1017105Sbloom #include "param.h" 1117105Sbloom #include "user.h" 1217105Sbloom #include "domain.h" 1317105Sbloom #include "protosw.h" 1417105Sbloom #include "socket.h" 1517105Sbloom #include "socketvar.h" 1617105Sbloom #include "unpcb.h" 1717105Sbloom #include "un.h" 1837616Smckusick #include "vnode.h" 1917105Sbloom #include "file.h" 2017105Sbloom #include "stat.h" 2141381Smckusick #include "mbuf.h" 228925Sroot 238925Sroot /* 248925Sroot * Unix communications domain. 2512760Ssam * 2612760Ssam * TODO: 2712760Ssam * SEQPACKET, RDM 2813119Ssam * rethink name space problems 2912760Ssam * need a proper out-of-band 308925Sroot */ 3137617Smckusick struct sockaddr sun_noname = { sizeof(sun_noname), AF_UNIX }; 3240800Ssklower ino_t unp_ino; /* prototype for fake inode numbers */ 338925Sroot 348925Sroot /*ARGSUSED*/ 3540800Ssklower uipc_usrreq(so, req, m, nam, control) 368925Sroot struct socket *so; 378925Sroot int req; 3840800Ssklower struct mbuf *m, *nam, *control; 398925Sroot { 408925Sroot struct unpcb *unp = sotounpcb(so); 418925Sroot register struct socket *so2; 4240937Skarels register int error = 0; 438925Sroot 4425555Skarels if (req == PRU_CONTROL) 4525555Skarels return (EOPNOTSUPP); 4640800Ssklower if (req != PRU_SEND && control && control->m_len) { 4712760Ssam error = EOPNOTSUPP; 4812760Ssam goto release; 4912760Ssam } 5012760Ssam if (unp == 0 && req != PRU_ATTACH) { 5112760Ssam error = EINVAL; 5212760Ssam goto release; 5312760Ssam } 548925Sroot switch (req) { 558925Sroot 568925Sroot case PRU_ATTACH: 578925Sroot if (unp) { 589169Ssam error = EISCONN; 598925Sroot break; 608925Sroot } 619028Sroot error = unp_attach(so); 628925Sroot break; 638925Sroot 648925Sroot case PRU_DETACH: 658925Sroot unp_detach(unp); 668925Sroot break; 678925Sroot 689169Ssam case PRU_BIND: 699169Ssam error = unp_bind(unp, nam); 709169Ssam break; 719169Ssam 729169Ssam case PRU_LISTEN: 7337616Smckusick if (unp->unp_vnode == 0) 749169Ssam error = EINVAL; 759169Ssam break; 769169Ssam 778925Sroot case PRU_CONNECT: 789028Sroot error = unp_connect(so, nam); 798925Sroot break; 808925Sroot 8112760Ssam case PRU_CONNECT2: 8226281Skarels error = unp_connect2(so, (struct socket *)nam); 8312760Ssam break; 8412760Ssam 858925Sroot case PRU_DISCONNECT: 868925Sroot unp_disconnect(unp); 878925Sroot break; 888925Sroot 899169Ssam case PRU_ACCEPT: 9025899Skarels /* 9125899Skarels * Pass back name of connected socket, 9225899Skarels * if it was bound and we are still connected 9325899Skarels * (our peer may have closed already!). 9425899Skarels */ 9525899Skarels if (unp->unp_conn && unp->unp_conn->unp_addr) { 9625632Skarels nam->m_len = unp->unp_conn->unp_addr->m_len; 9725632Skarels bcopy(mtod(unp->unp_conn->unp_addr, caddr_t), 9825632Skarels mtod(nam, caddr_t), (unsigned)nam->m_len); 9925632Skarels } else { 10025632Skarels nam->m_len = sizeof(sun_noname); 10125632Skarels *(mtod(nam, struct sockaddr *)) = sun_noname; 10225632Skarels } 1038925Sroot break; 1048925Sroot 1058925Sroot case PRU_SHUTDOWN: 1068925Sroot socantsendmore(so); 107*45004Skarels unp_shutdown(unp); 1088925Sroot break; 1098925Sroot 1108925Sroot case PRU_RCVD: 1118925Sroot switch (so->so_type) { 1128925Sroot 1138925Sroot case SOCK_DGRAM: 1148925Sroot panic("uipc 1"); 11510139Ssam /*NOTREACHED*/ 1168925Sroot 11710139Ssam case SOCK_STREAM: 1188925Sroot #define rcv (&so->so_rcv) 1198925Sroot #define snd (&so2->so_snd) 1208925Sroot if (unp->unp_conn == 0) 1218925Sroot break; 1228925Sroot so2 = unp->unp_conn->unp_socket; 1238925Sroot /* 12425632Skarels * Adjust backpressure on sender 1258925Sroot * and wakeup any waiting to write. 1268925Sroot */ 12725632Skarels snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt; 12825632Skarels unp->unp_mbcnt = rcv->sb_mbcnt; 12925632Skarels snd->sb_hiwat += unp->unp_cc - rcv->sb_cc; 13025632Skarels unp->unp_cc = rcv->sb_cc; 13117543Skarels sowwakeup(so2); 1328925Sroot #undef snd 1338925Sroot #undef rcv 1348925Sroot break; 1358925Sroot 1368925Sroot default: 1378925Sroot panic("uipc 2"); 1388925Sroot } 1398925Sroot break; 1408925Sroot 1418925Sroot case PRU_SEND: 14240937Skarels if (control && (error = unp_internalize(control))) 14340937Skarels break; 1448925Sroot switch (so->so_type) { 1458925Sroot 14625632Skarels case SOCK_DGRAM: { 14725632Skarels struct sockaddr *from; 14825632Skarels 1499028Sroot if (nam) { 1508925Sroot if (unp->unp_conn) { 1518925Sroot error = EISCONN; 1528925Sroot break; 1538925Sroot } 1549028Sroot error = unp_connect(so, nam); 1558925Sroot if (error) 1568925Sroot break; 1578925Sroot } else { 1588925Sroot if (unp->unp_conn == 0) { 1598925Sroot error = ENOTCONN; 1608925Sroot break; 1618925Sroot } 1628925Sroot } 1638925Sroot so2 = unp->unp_conn->unp_socket; 16425632Skarels if (unp->unp_addr) 16525632Skarels from = mtod(unp->unp_addr, struct sockaddr *); 16625632Skarels else 16725632Skarels from = &sun_noname; 16840937Skarels if (sbappendaddr(&so2->so_rcv, from, m, control)) { 16925632Skarels sorwakeup(so2); 17025632Skarels m = 0; 17140937Skarels control = 0; 17225632Skarels } else 17325632Skarels error = ENOBUFS; 1749028Sroot if (nam) 1759169Ssam unp_disconnect(unp); 1768925Sroot break; 17725632Skarels } 1788925Sroot 1798925Sroot case SOCK_STREAM: 1808925Sroot #define rcv (&so2->so_rcv) 1818925Sroot #define snd (&so->so_snd) 18223524Skarels if (so->so_state & SS_CANTSENDMORE) { 18323524Skarels error = EPIPE; 18423524Skarels break; 18523524Skarels } 1868925Sroot if (unp->unp_conn == 0) 1878925Sroot panic("uipc 3"); 1888925Sroot so2 = unp->unp_conn->unp_socket; 1898925Sroot /* 19025632Skarels * Send to paired receive port, and then reduce 19125632Skarels * send buffer hiwater marks to maintain backpressure. 1928925Sroot * Wake up readers. 1938925Sroot */ 19440937Skarels if (control) { 195*45004Skarels if (sbappendcontrol(rcv, m, control)) 196*45004Skarels control = 0; 19740937Skarels } else 19825632Skarels sbappend(rcv, m); 19925632Skarels snd->sb_mbmax -= 20025632Skarels rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt; 20125632Skarels unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt; 20225632Skarels snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc; 20325632Skarels unp->unp_conn->unp_cc = rcv->sb_cc; 20417543Skarels sorwakeup(so2); 20517543Skarels m = 0; 2068925Sroot #undef snd 2078925Sroot #undef rcv 2088925Sroot break; 2098925Sroot 2108925Sroot default: 2118925Sroot panic("uipc 4"); 2128925Sroot } 2138925Sroot break; 2148925Sroot 2158925Sroot case PRU_ABORT: 2168925Sroot unp_drop(unp, ECONNABORTED); 2178925Sroot break; 2188925Sroot 2198925Sroot case PRU_SENSE: 22016973Skarels ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat; 22116973Skarels if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) { 22216973Skarels so2 = unp->unp_conn->unp_socket; 22316973Skarels ((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc; 22416973Skarels } 22521110Skarels ((struct stat *) m)->st_dev = NODEV; 22640800Ssklower if (unp->unp_ino == 0) 22740800Ssklower unp->unp_ino = unp_ino++; 22840800Ssklower ((struct stat *) m)->st_ino = unp->unp_ino; 22916973Skarels return (0); 2308925Sroot 2318925Sroot case PRU_RCVOOB: 23216774Sbloom return (EOPNOTSUPP); 2338925Sroot 2348925Sroot case PRU_SENDOOB: 23517543Skarels error = EOPNOTSUPP; 2368925Sroot break; 2378925Sroot 2388925Sroot case PRU_SOCKADDR: 23937617Smckusick if (unp->unp_addr) { 24037617Smckusick nam->m_len = unp->unp_addr->m_len; 24137617Smckusick bcopy(mtod(unp->unp_addr, caddr_t), 24237617Smckusick mtod(nam, caddr_t), (unsigned)nam->m_len); 24337617Smckusick } else 24437617Smckusick nam->m_len = 0; 2458925Sroot break; 2468925Sroot 24714121Ssam case PRU_PEERADDR: 24828292Skarels if (unp->unp_conn && unp->unp_conn->unp_addr) { 24928292Skarels nam->m_len = unp->unp_conn->unp_addr->m_len; 25028292Skarels bcopy(mtod(unp->unp_conn->unp_addr, caddr_t), 25133287Sbostic mtod(nam, caddr_t), (unsigned)nam->m_len); 25237617Smckusick } else 25337617Smckusick nam->m_len = 0; 25414121Ssam break; 25514121Ssam 2568925Sroot case PRU_SLOWTIMO: 2578925Sroot break; 2588925Sroot 2598925Sroot default: 2608925Sroot panic("piusrreq"); 2618925Sroot } 26212760Ssam release: 26340937Skarels if (control) 26440937Skarels m_freem(control); 26512760Ssam if (m) 26612760Ssam m_freem(m); 26711709Ssam return (error); 2688925Sroot } 2698925Sroot 27016973Skarels /* 27125632Skarels * Both send and receive buffers are allocated PIPSIZ bytes of buffering 27225632Skarels * for stream sockets, although the total for sender and receiver is 27325632Skarels * actually only PIPSIZ. 27416973Skarels * Datagram sockets really use the sendspace as the maximum datagram size, 27516973Skarels * and don't really want to reserve the sendspace. Their recvspace should 27616973Skarels * be large enough for at least one max-size datagram plus address. 27716973Skarels */ 27816973Skarels #define PIPSIZ 4096 27937617Smckusick u_long unpst_sendspace = PIPSIZ; 28037617Smckusick u_long unpst_recvspace = PIPSIZ; 28137617Smckusick u_long unpdg_sendspace = 2*1024; /* really max datagram size */ 28237617Smckusick u_long unpdg_recvspace = 4*1024; 2838925Sroot 28425632Skarels int unp_rights; /* file descriptors in flight */ 28525632Skarels 2869169Ssam unp_attach(so) 2878925Sroot struct socket *so; 2888925Sroot { 2899169Ssam register struct mbuf *m; 2908925Sroot register struct unpcb *unp; 2918925Sroot int error; 2928925Sroot 29337617Smckusick if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 29437617Smckusick switch (so->so_type) { 29516973Skarels 29637617Smckusick case SOCK_STREAM: 29737617Smckusick error = soreserve(so, unpst_sendspace, unpst_recvspace); 29837617Smckusick break; 29916973Skarels 30037617Smckusick case SOCK_DGRAM: 30137617Smckusick error = soreserve(so, unpdg_sendspace, unpdg_recvspace); 30237617Smckusick break; 30337617Smckusick } 30437617Smckusick if (error) 30537617Smckusick return (error); 30616973Skarels } 3079637Ssam m = m_getclr(M_DONTWAIT, MT_PCB); 30810139Ssam if (m == NULL) 30910139Ssam return (ENOBUFS); 3108925Sroot unp = mtod(m, struct unpcb *); 3118925Sroot so->so_pcb = (caddr_t)unp; 3128925Sroot unp->unp_socket = so; 3138925Sroot return (0); 3148925Sroot } 3158925Sroot 3168925Sroot unp_detach(unp) 3179169Ssam register struct unpcb *unp; 3188925Sroot { 3198925Sroot 32037616Smckusick if (unp->unp_vnode) { 32137616Smckusick unp->unp_vnode->v_socket = 0; 32237616Smckusick vrele(unp->unp_vnode); 32337616Smckusick unp->unp_vnode = 0; 3248925Sroot } 3258925Sroot if (unp->unp_conn) 3268925Sroot unp_disconnect(unp); 3278925Sroot while (unp->unp_refs) 3288925Sroot unp_drop(unp->unp_refs, ECONNRESET); 3298925Sroot soisdisconnected(unp->unp_socket); 3308925Sroot unp->unp_socket->so_pcb = 0; 33125632Skarels m_freem(unp->unp_addr); 3329169Ssam (void) m_free(dtom(unp)); 33325632Skarels if (unp_rights) 33425632Skarels unp_gc(); 3358925Sroot } 3368925Sroot 3379169Ssam unp_bind(unp, nam) 3388925Sroot struct unpcb *unp; 3399169Ssam struct mbuf *nam; 3408925Sroot { 3419169Ssam struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 34237616Smckusick register struct vnode *vp; 34316695Smckusick register struct nameidata *ndp = &u.u_nd; 34437616Smckusick struct vattr vattr; 3458925Sroot int error; 3468925Sroot 34716695Smckusick ndp->ni_dirp = soun->sun_path; 34837617Smckusick if (unp->unp_vnode != NULL) 34912760Ssam return (EINVAL); 35037617Smckusick if (nam->m_len == MLEN) { 35137617Smckusick if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0) 35237617Smckusick return (EINVAL); 35337617Smckusick } else 35437617Smckusick *(mtod(nam, caddr_t) + nam->m_len) = 0; 35512760Ssam /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ 35637616Smckusick ndp->ni_nameiop = CREATE | FOLLOW | LOCKPARENT; 35716695Smckusick ndp->ni_segflg = UIO_SYSSPACE; 35837616Smckusick if (error = namei(ndp)) 35937616Smckusick return (error); 36037616Smckusick vp = ndp->ni_vp; 36137616Smckusick if (vp != NULL) { 36237728Smckusick VOP_ABORTOP(ndp); 36343342Smckusick if (ndp->ni_dvp == vp) 36443342Smckusick vrele(ndp->ni_dvp); 36543342Smckusick else 36643342Smckusick vput(ndp->ni_dvp); 36742465Smckusick vrele(vp); 36810139Ssam return (EADDRINUSE); 3698925Sroot } 37041362Smckusick VATTR_NULL(&vattr); 37137616Smckusick vattr.va_type = VSOCK; 37237616Smckusick vattr.va_mode = 0777; 37337728Smckusick if (error = VOP_CREATE(ndp, &vattr)) 37411828Ssam return (error); 37537616Smckusick vp = ndp->ni_vp; 37637616Smckusick vp->v_socket = unp->unp_socket; 37737616Smckusick unp->unp_vnode = vp; 37825632Skarels unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL); 37937728Smckusick VOP_UNLOCK(vp); 3808925Sroot return (0); 3818925Sroot } 3828925Sroot 3839169Ssam unp_connect(so, nam) 3848925Sroot struct socket *so; 3859169Ssam struct mbuf *nam; 3868925Sroot { 3879169Ssam register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 38837616Smckusick register struct vnode *vp; 38937617Smckusick register struct socket *so2, *so3; 39037617Smckusick register struct nameidata *ndp = &u.u_nd; 39137617Smckusick struct unpcb *unp2, *unp3; 39237616Smckusick int error; 3938925Sroot 39416695Smckusick ndp->ni_dirp = soun->sun_path; 39537617Smckusick if (nam->m_data + nam->m_len == &nam->m_dat[MLEN]) { /* XXX */ 39637617Smckusick if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0) 39737617Smckusick return (EMSGSIZE); 39837617Smckusick } else 39937617Smckusick *(mtod(nam, caddr_t) + nam->m_len) = 0; 40037728Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF; 40116695Smckusick ndp->ni_segflg = UIO_SYSSPACE; 40237616Smckusick if (error = namei(ndp)) 40337616Smckusick return (error); 40437616Smckusick vp = ndp->ni_vp; 40537616Smckusick if (vp->v_type != VSOCK) { 4068925Sroot error = ENOTSOCK; 4078925Sroot goto bad; 4088925Sroot } 40938396Smckusick if (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred)) 41038396Smckusick goto bad; 41137616Smckusick so2 = vp->v_socket; 4128925Sroot if (so2 == 0) { 4138925Sroot error = ECONNREFUSED; 4148925Sroot goto bad; 4158925Sroot } 41613115Ssam if (so->so_type != so2->so_type) { 41713115Ssam error = EPROTOTYPE; 41813115Ssam goto bad; 41913115Ssam } 42037617Smckusick if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 42137617Smckusick if ((so2->so_options & SO_ACCEPTCONN) == 0 || 42240800Ssklower (so3 = sonewconn(so2, 0)) == 0) { 42337617Smckusick error = ECONNREFUSED; 42437617Smckusick goto bad; 42537617Smckusick } 42637617Smckusick unp2 = sotounpcb(so2); 42737617Smckusick unp3 = sotounpcb(so3); 42837617Smckusick if (unp2->unp_addr) 42937617Smckusick unp3->unp_addr = 43037617Smckusick m_copy(unp2->unp_addr, 0, (int)M_COPYALL); 43137617Smckusick so2 = so3; 43213115Ssam } 43326281Skarels error = unp_connect2(so, so2); 43412760Ssam bad: 43537728Smckusick vput(vp); 43612760Ssam return (error); 43712760Ssam } 43812760Ssam 43926281Skarels unp_connect2(so, so2) 44012760Ssam register struct socket *so; 44112760Ssam register struct socket *so2; 44212760Ssam { 44312760Ssam register struct unpcb *unp = sotounpcb(so); 44412760Ssam register struct unpcb *unp2; 44512760Ssam 44612760Ssam if (so2->so_type != so->so_type) 44712760Ssam return (EPROTOTYPE); 44814049Ssam unp2 = sotounpcb(so2); 44914049Ssam unp->unp_conn = unp2; 4508925Sroot switch (so->so_type) { 4518925Sroot 4528925Sroot case SOCK_DGRAM: 4538925Sroot unp->unp_nextref = unp2->unp_refs; 4548925Sroot unp2->unp_refs = unp; 45517543Skarels soisconnected(so); 4568925Sroot break; 4578925Sroot 4588925Sroot case SOCK_STREAM: 4599169Ssam unp2->unp_conn = unp; 46040800Ssklower soisconnected(so); 46114049Ssam soisconnected(so2); 4628925Sroot break; 4638925Sroot 4648925Sroot default: 46512760Ssam panic("unp_connect2"); 4668925Sroot } 4678925Sroot return (0); 4688925Sroot } 4699169Ssam 4709169Ssam unp_disconnect(unp) 4719169Ssam struct unpcb *unp; 4729169Ssam { 4739169Ssam register struct unpcb *unp2 = unp->unp_conn; 4749169Ssam 4759169Ssam if (unp2 == 0) 4769169Ssam return; 4779169Ssam unp->unp_conn = 0; 4789169Ssam switch (unp->unp_socket->so_type) { 4799169Ssam 4809169Ssam case SOCK_DGRAM: 4819169Ssam if (unp2->unp_refs == unp) 4829169Ssam unp2->unp_refs = unp->unp_nextref; 4839169Ssam else { 4849169Ssam unp2 = unp2->unp_refs; 4859169Ssam for (;;) { 4869169Ssam if (unp2 == 0) 4879169Ssam panic("unp_disconnect"); 4889169Ssam if (unp2->unp_nextref == unp) 4899169Ssam break; 4909169Ssam unp2 = unp2->unp_nextref; 4919169Ssam } 4929169Ssam unp2->unp_nextref = unp->unp_nextref; 4939169Ssam } 4949169Ssam unp->unp_nextref = 0; 49521768Skarels unp->unp_socket->so_state &= ~SS_ISCONNECTED; 4969169Ssam break; 4979169Ssam 4989169Ssam case SOCK_STREAM: 49914049Ssam soisdisconnected(unp->unp_socket); 5009169Ssam unp2->unp_conn = 0; 5019169Ssam soisdisconnected(unp2->unp_socket); 5029169Ssam break; 5039169Ssam } 5049169Ssam } 5059169Ssam 50612760Ssam #ifdef notdef 5079169Ssam unp_abort(unp) 5089169Ssam struct unpcb *unp; 5099169Ssam { 5109169Ssam 5119169Ssam unp_detach(unp); 5129169Ssam } 51312760Ssam #endif 5149169Ssam 515*45004Skarels unp_shutdown(unp) 5169169Ssam struct unpcb *unp; 5179169Ssam { 518*45004Skarels struct socket *so; 5199169Ssam 520*45004Skarels if (unp->unp_socket->so_type == SOCK_STREAM && unp->unp_conn && 521*45004Skarels (so = unp->unp_conn->unp_socket)) 522*45004Skarels socantrcvmore(so); 5239169Ssam } 5249169Ssam 5259169Ssam unp_drop(unp, errno) 5269169Ssam struct unpcb *unp; 5279169Ssam int errno; 5289169Ssam { 52916054Skarels struct socket *so = unp->unp_socket; 5309169Ssam 53116054Skarels so->so_error = errno; 5329169Ssam unp_disconnect(unp); 53316054Skarels if (so->so_head) { 53416054Skarels so->so_pcb = (caddr_t) 0; 53525632Skarels m_freem(unp->unp_addr); 53616054Skarels (void) m_free(dtom(unp)); 53716054Skarels sofree(so); 53816054Skarels } 5399169Ssam } 5409169Ssam 54112760Ssam #ifdef notdef 5429169Ssam unp_drain() 5439169Ssam { 5449169Ssam 5459169Ssam } 54612760Ssam #endif 54712760Ssam 54812760Ssam unp_externalize(rights) 54912760Ssam struct mbuf *rights; 55012760Ssam { 55112760Ssam register int i; 55240800Ssklower register struct cmsghdr *cm = mtod(rights, struct cmsghdr *); 55340800Ssklower register struct file **rp = (struct file **)(cm + 1); 55412760Ssam register struct file *fp; 55540800Ssklower int newfds = (cm->cmsg_len - sizeof(*cm)) / sizeof (int); 55612760Ssam int f; 55712760Ssam 55812760Ssam if (newfds > ufavail()) { 55912760Ssam for (i = 0; i < newfds; i++) { 56012760Ssam fp = *rp; 56112760Ssam unp_discard(fp); 56212760Ssam *rp++ = 0; 56312760Ssam } 56412760Ssam return (EMSGSIZE); 56512760Ssam } 56612760Ssam for (i = 0; i < newfds; i++) { 56737616Smckusick if (ufalloc(0, &f)) 56812760Ssam panic("unp_externalize"); 56912760Ssam fp = *rp; 57012760Ssam u.u_ofile[f] = fp; 57112760Ssam fp->f_msgcount--; 57225632Skarels unp_rights--; 57314927Smckusick *(int *)rp++ = f; 57412760Ssam } 57512760Ssam return (0); 57612760Ssam } 57712760Ssam 57840937Skarels unp_internalize(control) 57940937Skarels struct mbuf *control; 58012760Ssam { 58140937Skarels register struct cmsghdr *cm = mtod(control, struct cmsghdr *); 58212760Ssam register struct file **rp; 58340937Skarels register struct file *fp; 58437728Smckusick register int i, fd; 58540937Skarels int oldfds; 58612760Ssam 58740937Skarels if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET || 58840937Skarels cm->cmsg_len != control->m_len) 58940800Ssklower return (EINVAL); 59040800Ssklower oldfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int); 59140800Ssklower rp = (struct file **)(cm + 1); 59237728Smckusick for (i = 0; i < oldfds; i++) { 59337728Smckusick fd = *(int *)rp++; 59437728Smckusick if ((unsigned)fd >= NOFILE || u.u_ofile[fd] == NULL) 59512760Ssam return (EBADF); 59637728Smckusick } 59740800Ssklower rp = (struct file **)(cm + 1); 59813084Ssam for (i = 0; i < oldfds; i++) { 59937728Smckusick fp = u.u_ofile[*(int *)rp]; 60012760Ssam *rp++ = fp; 60112760Ssam fp->f_count++; 60212760Ssam fp->f_msgcount++; 60325632Skarels unp_rights++; 60412760Ssam } 60512760Ssam return (0); 60612760Ssam } 60712760Ssam 60812760Ssam int unp_defer, unp_gcing; 60912760Ssam int unp_mark(); 61016995Skarels extern struct domain unixdomain; 61112760Ssam 61212760Ssam unp_gc() 61312760Ssam { 61412760Ssam register struct file *fp; 61512760Ssam register struct socket *so; 61612760Ssam 61712760Ssam if (unp_gcing) 61812760Ssam return; 61912760Ssam unp_gcing = 1; 62012760Ssam restart: 62112760Ssam unp_defer = 0; 62212760Ssam for (fp = file; fp < fileNFILE; fp++) 62312760Ssam fp->f_flag &= ~(FMARK|FDEFER); 62412760Ssam do { 62512760Ssam for (fp = file; fp < fileNFILE; fp++) { 62612760Ssam if (fp->f_count == 0) 62712760Ssam continue; 62812760Ssam if (fp->f_flag & FDEFER) { 62912760Ssam fp->f_flag &= ~FDEFER; 63012760Ssam unp_defer--; 63112760Ssam } else { 63212760Ssam if (fp->f_flag & FMARK) 63312760Ssam continue; 63412760Ssam if (fp->f_count == fp->f_msgcount) 63512760Ssam continue; 63612760Ssam fp->f_flag |= FMARK; 63712760Ssam } 63837617Smckusick if (fp->f_type != DTYPE_SOCKET || 63937617Smckusick (so = (struct socket *)fp->f_data) == 0) 64012760Ssam continue; 64116995Skarels if (so->so_proto->pr_domain != &unixdomain || 64221768Skarels (so->so_proto->pr_flags&PR_RIGHTS) == 0) 64312760Ssam continue; 644*45004Skarels #ifdef notdef 64512760Ssam if (so->so_rcv.sb_flags & SB_LOCK) { 646*45004Skarels /* 647*45004Skarels * This is problematical; it's not clear 648*45004Skarels * we need to wait for the sockbuf to be 649*45004Skarels * unlocked (on a uniprocessor, at least), 650*45004Skarels * and it's also not clear what to do 651*45004Skarels * if sbwait returns an error due to receipt 652*45004Skarels * of a signal. If sbwait does return 653*45004Skarels * an error, we'll go into an infinite 654*45004Skarels * loop. Delete all of this for now. 655*45004Skarels */ 656*45004Skarels (void) sbwait(&so->so_rcv); 65712760Ssam goto restart; 65812760Ssam } 659*45004Skarels #endif 66012760Ssam unp_scan(so->so_rcv.sb_mb, unp_mark); 66112760Ssam } 66212760Ssam } while (unp_defer); 66312760Ssam for (fp = file; fp < fileNFILE; fp++) { 66412760Ssam if (fp->f_count == 0) 66512760Ssam continue; 66625632Skarels if (fp->f_count == fp->f_msgcount && (fp->f_flag & FMARK) == 0) 66725632Skarels while (fp->f_msgcount) 66825632Skarels unp_discard(fp); 66912760Ssam } 67012760Ssam unp_gcing = 0; 67112760Ssam } 67212760Ssam 67316995Skarels unp_dispose(m) 67416995Skarels struct mbuf *m; 67516995Skarels { 67616995Skarels int unp_discard(); 67716995Skarels 67817020Skarels if (m) 67917020Skarels unp_scan(m, unp_discard); 68016995Skarels } 68116995Skarels 68216995Skarels unp_scan(m0, op) 68316995Skarels register struct mbuf *m0; 68412760Ssam int (*op)(); 68512760Ssam { 68616995Skarels register struct mbuf *m; 68712760Ssam register struct file **rp; 68840937Skarels register struct cmsghdr *cm; 68912760Ssam register int i; 69017020Skarels int qfds; 69112760Ssam 69216995Skarels while (m0) { 69316995Skarels for (m = m0; m; m = m->m_next) 69440937Skarels if (m->m_type == MT_CONTROL && 69540937Skarels m->m_len >= sizeof(*cm)) { 69640800Ssklower cm = mtod(m, struct cmsghdr *); 69740937Skarels if (cm->cmsg_level != SOL_SOCKET || 69840937Skarels cm->cmsg_type != SCM_RIGHTS) 69940937Skarels continue; 70040800Ssklower qfds = (cm->cmsg_len - sizeof *cm) 70140800Ssklower / sizeof (struct file *); 70240800Ssklower rp = (struct file **)(cm + 1); 70316995Skarels for (i = 0; i < qfds; i++) 70416995Skarels (*op)(*rp++); 70516995Skarels break; /* XXX, but saves time */ 70616995Skarels } 70717020Skarels m0 = m0->m_act; 70812760Ssam } 70912760Ssam } 71012760Ssam 71112760Ssam unp_mark(fp) 71212760Ssam struct file *fp; 71312760Ssam { 71412760Ssam 71512760Ssam if (fp->f_flag & FMARK) 71612760Ssam return; 71712760Ssam unp_defer++; 71812760Ssam fp->f_flag |= (FMARK|FDEFER); 71912760Ssam } 72012760Ssam 72112760Ssam unp_discard(fp) 72212760Ssam struct file *fp; 72312760Ssam { 72412760Ssam 72512760Ssam fp->f_msgcount--; 72625632Skarels unp_rights--; 72739353Smckusick (void) closef(fp); 72812760Ssam } 729