123443Smckusick /* 263180Sbostic * Copyright (c) 1982, 1986, 1989, 1991, 1993 363180Sbostic * The Regents of the University of California. All rights reserved. 423443Smckusick * 544453Sbostic * %sccs.include.redist.c% 633288Sbostic * 7*69142Smckusick * @(#)uipc_usrreq.c 8.8 (Berkeley) 05/01/95 823443Smckusick */ 98925Sroot 1056517Sbostic #include <sys/param.h> 1156517Sbostic #include <sys/systm.h> 1256517Sbostic #include <sys/proc.h> 1356517Sbostic #include <sys/filedesc.h> 1456517Sbostic #include <sys/domain.h> 1556517Sbostic #include <sys/protosw.h> 1656517Sbostic #include <sys/socket.h> 1756517Sbostic #include <sys/socketvar.h> 1856517Sbostic #include <sys/unpcb.h> 1956517Sbostic #include <sys/un.h> 2056517Sbostic #include <sys/namei.h> 2156517Sbostic #include <sys/vnode.h> 2256517Sbostic #include <sys/file.h> 2356517Sbostic #include <sys/stat.h> 2456517Sbostic #include <sys/mbuf.h> 258925Sroot 268925Sroot /* 278925Sroot * Unix communications domain. 2812760Ssam * 2912760Ssam * TODO: 3012760Ssam * SEQPACKET, RDM 3113119Ssam * rethink name space problems 3212760Ssam * need a proper out-of-band 338925Sroot */ 3437617Smckusick struct sockaddr sun_noname = { sizeof(sun_noname), AF_UNIX }; 3540800Ssklower ino_t unp_ino; /* prototype for fake inode numbers */ 368925Sroot 378925Sroot /*ARGSUSED*/ 3868323Scgd int 3940800Ssklower uipc_usrreq(so, req, m, nam, control) 408925Sroot struct socket *so; 418925Sroot int req; 4240800Ssklower struct mbuf *m, *nam, *control; 438925Sroot { 448925Sroot struct unpcb *unp = sotounpcb(so); 458925Sroot register struct socket *so2; 4640937Skarels register int error = 0; 4748022Smckusick struct proc *p = curproc; /* XXX */ 488925Sroot 4925555Skarels if (req == PRU_CONTROL) 5025555Skarels return (EOPNOTSUPP); 5140800Ssklower if (req != PRU_SEND && control && control->m_len) { 5212760Ssam error = EOPNOTSUPP; 5312760Ssam goto release; 5412760Ssam } 5512760Ssam if (unp == 0 && req != PRU_ATTACH) { 5612760Ssam error = EINVAL; 5712760Ssam goto release; 5812760Ssam } 598925Sroot switch (req) { 608925Sroot 618925Sroot case PRU_ATTACH: 628925Sroot if (unp) { 639169Ssam error = EISCONN; 648925Sroot break; 658925Sroot } 669028Sroot error = unp_attach(so); 678925Sroot break; 688925Sroot 698925Sroot case PRU_DETACH: 708925Sroot unp_detach(unp); 718925Sroot break; 728925Sroot 739169Ssam case PRU_BIND: 7448022Smckusick error = unp_bind(unp, nam, p); 759169Ssam break; 769169Ssam 779169Ssam case PRU_LISTEN: 7837616Smckusick if (unp->unp_vnode == 0) 799169Ssam error = EINVAL; 809169Ssam break; 819169Ssam 828925Sroot case PRU_CONNECT: 8348022Smckusick error = unp_connect(so, nam, p); 848925Sroot break; 858925Sroot 8612760Ssam case PRU_CONNECT2: 8726281Skarels error = unp_connect2(so, (struct socket *)nam); 8812760Ssam break; 8912760Ssam 908925Sroot case PRU_DISCONNECT: 918925Sroot unp_disconnect(unp); 928925Sroot break; 938925Sroot 949169Ssam case PRU_ACCEPT: 9525899Skarels /* 9625899Skarels * Pass back name of connected socket, 9725899Skarels * if it was bound and we are still connected 9825899Skarels * (our peer may have closed already!). 9925899Skarels */ 10025899Skarels if (unp->unp_conn && unp->unp_conn->unp_addr) { 10125632Skarels nam->m_len = unp->unp_conn->unp_addr->m_len; 10225632Skarels bcopy(mtod(unp->unp_conn->unp_addr, caddr_t), 10325632Skarels mtod(nam, caddr_t), (unsigned)nam->m_len); 10425632Skarels } else { 10525632Skarels nam->m_len = sizeof(sun_noname); 10625632Skarels *(mtod(nam, struct sockaddr *)) = sun_noname; 10725632Skarels } 1088925Sroot break; 1098925Sroot 1108925Sroot case PRU_SHUTDOWN: 1118925Sroot socantsendmore(so); 11245004Skarels unp_shutdown(unp); 1138925Sroot break; 1148925Sroot 1158925Sroot case PRU_RCVD: 1168925Sroot switch (so->so_type) { 1178925Sroot 1188925Sroot case SOCK_DGRAM: 1198925Sroot panic("uipc 1"); 12010139Ssam /*NOTREACHED*/ 1218925Sroot 12210139Ssam case SOCK_STREAM: 1238925Sroot #define rcv (&so->so_rcv) 1248925Sroot #define snd (&so2->so_snd) 1258925Sroot if (unp->unp_conn == 0) 1268925Sroot break; 1278925Sroot so2 = unp->unp_conn->unp_socket; 1288925Sroot /* 12925632Skarels * Adjust backpressure on sender 1308925Sroot * and wakeup any waiting to write. 1318925Sroot */ 13225632Skarels snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt; 13325632Skarels unp->unp_mbcnt = rcv->sb_mbcnt; 13425632Skarels snd->sb_hiwat += unp->unp_cc - rcv->sb_cc; 13525632Skarels unp->unp_cc = rcv->sb_cc; 13617543Skarels sowwakeup(so2); 1378925Sroot #undef snd 1388925Sroot #undef rcv 1398925Sroot break; 1408925Sroot 1418925Sroot default: 1428925Sroot panic("uipc 2"); 1438925Sroot } 1448925Sroot break; 1458925Sroot 1468925Sroot case PRU_SEND: 14748022Smckusick if (control && (error = unp_internalize(control, p))) 14840937Skarels break; 1498925Sroot switch (so->so_type) { 1508925Sroot 15125632Skarels case SOCK_DGRAM: { 15225632Skarels struct sockaddr *from; 15325632Skarels 1549028Sroot if (nam) { 1558925Sroot if (unp->unp_conn) { 1568925Sroot error = EISCONN; 1578925Sroot break; 1588925Sroot } 15948022Smckusick error = unp_connect(so, nam, p); 1608925Sroot if (error) 1618925Sroot break; 1628925Sroot } else { 1638925Sroot if (unp->unp_conn == 0) { 1648925Sroot error = ENOTCONN; 1658925Sroot break; 1668925Sroot } 1678925Sroot } 1688925Sroot so2 = unp->unp_conn->unp_socket; 16925632Skarels if (unp->unp_addr) 17025632Skarels from = mtod(unp->unp_addr, struct sockaddr *); 17125632Skarels else 17225632Skarels from = &sun_noname; 17340937Skarels if (sbappendaddr(&so2->so_rcv, from, m, control)) { 17425632Skarels sorwakeup(so2); 17525632Skarels m = 0; 17640937Skarels control = 0; 17725632Skarels } else 17825632Skarels error = ENOBUFS; 1799028Sroot if (nam) 1809169Ssam unp_disconnect(unp); 1818925Sroot break; 18225632Skarels } 1838925Sroot 1848925Sroot case SOCK_STREAM: 1858925Sroot #define rcv (&so2->so_rcv) 1868925Sroot #define snd (&so->so_snd) 18723524Skarels if (so->so_state & SS_CANTSENDMORE) { 18823524Skarels error = EPIPE; 18923524Skarels break; 19023524Skarels } 1918925Sroot if (unp->unp_conn == 0) 1928925Sroot panic("uipc 3"); 1938925Sroot so2 = unp->unp_conn->unp_socket; 1948925Sroot /* 19525632Skarels * Send to paired receive port, and then reduce 19625632Skarels * send buffer hiwater marks to maintain backpressure. 1978925Sroot * Wake up readers. 1988925Sroot */ 19940937Skarels if (control) { 20045004Skarels if (sbappendcontrol(rcv, m, control)) 20145004Skarels control = 0; 20240937Skarels } else 20325632Skarels sbappend(rcv, m); 20425632Skarels snd->sb_mbmax -= 20525632Skarels rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt; 20625632Skarels unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt; 20725632Skarels snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc; 20825632Skarels unp->unp_conn->unp_cc = rcv->sb_cc; 20917543Skarels sorwakeup(so2); 21017543Skarels m = 0; 2118925Sroot #undef snd 2128925Sroot #undef rcv 2138925Sroot break; 2148925Sroot 2158925Sroot default: 2168925Sroot panic("uipc 4"); 2178925Sroot } 2188925Sroot break; 2198925Sroot 2208925Sroot case PRU_ABORT: 2218925Sroot unp_drop(unp, ECONNABORTED); 2228925Sroot break; 2238925Sroot 2248925Sroot case PRU_SENSE: 22516973Skarels ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat; 22616973Skarels if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) { 22716973Skarels so2 = unp->unp_conn->unp_socket; 22816973Skarels ((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc; 22916973Skarels } 23021110Skarels ((struct stat *) m)->st_dev = NODEV; 23140800Ssklower if (unp->unp_ino == 0) 23240800Ssklower unp->unp_ino = unp_ino++; 23340800Ssklower ((struct stat *) m)->st_ino = unp->unp_ino; 23416973Skarels return (0); 2358925Sroot 2368925Sroot case PRU_RCVOOB: 23716774Sbloom return (EOPNOTSUPP); 2388925Sroot 2398925Sroot case PRU_SENDOOB: 24017543Skarels error = EOPNOTSUPP; 2418925Sroot break; 2428925Sroot 2438925Sroot case PRU_SOCKADDR: 24437617Smckusick if (unp->unp_addr) { 24537617Smckusick nam->m_len = unp->unp_addr->m_len; 24637617Smckusick bcopy(mtod(unp->unp_addr, caddr_t), 24737617Smckusick mtod(nam, caddr_t), (unsigned)nam->m_len); 24837617Smckusick } else 24937617Smckusick nam->m_len = 0; 2508925Sroot break; 2518925Sroot 25214121Ssam case PRU_PEERADDR: 25328292Skarels if (unp->unp_conn && unp->unp_conn->unp_addr) { 25428292Skarels nam->m_len = unp->unp_conn->unp_addr->m_len; 25528292Skarels bcopy(mtod(unp->unp_conn->unp_addr, caddr_t), 25633287Sbostic mtod(nam, caddr_t), (unsigned)nam->m_len); 25737617Smckusick } else 25837617Smckusick nam->m_len = 0; 25914121Ssam break; 26014121Ssam 2618925Sroot case PRU_SLOWTIMO: 2628925Sroot break; 2638925Sroot 2648925Sroot default: 2658925Sroot panic("piusrreq"); 2668925Sroot } 26712760Ssam release: 26840937Skarels if (control) 26940937Skarels m_freem(control); 27012760Ssam if (m) 27112760Ssam m_freem(m); 27211709Ssam return (error); 2738925Sroot } 2748925Sroot 27516973Skarels /* 27625632Skarels * Both send and receive buffers are allocated PIPSIZ bytes of buffering 27725632Skarels * for stream sockets, although the total for sender and receiver is 27825632Skarels * actually only PIPSIZ. 27916973Skarels * Datagram sockets really use the sendspace as the maximum datagram size, 28016973Skarels * and don't really want to reserve the sendspace. Their recvspace should 28116973Skarels * be large enough for at least one max-size datagram plus address. 28216973Skarels */ 28316973Skarels #define PIPSIZ 4096 28437617Smckusick u_long unpst_sendspace = PIPSIZ; 28537617Smckusick u_long unpst_recvspace = PIPSIZ; 28637617Smckusick u_long unpdg_sendspace = 2*1024; /* really max datagram size */ 28737617Smckusick u_long unpdg_recvspace = 4*1024; 2888925Sroot 28925632Skarels int unp_rights; /* file descriptors in flight */ 29025632Skarels 29168323Scgd int 2929169Ssam unp_attach(so) 2938925Sroot struct socket *so; 2948925Sroot { 2959169Ssam register struct mbuf *m; 2968925Sroot register struct unpcb *unp; 2978925Sroot int error; 2988925Sroot 29937617Smckusick if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 30037617Smckusick switch (so->so_type) { 30116973Skarels 30237617Smckusick case SOCK_STREAM: 30337617Smckusick error = soreserve(so, unpst_sendspace, unpst_recvspace); 30437617Smckusick break; 30516973Skarels 30637617Smckusick case SOCK_DGRAM: 30737617Smckusick error = soreserve(so, unpdg_sendspace, unpdg_recvspace); 30837617Smckusick break; 30952921Smckusick 31052921Smckusick default: 31152921Smckusick panic("unp_attach"); 31237617Smckusick } 31337617Smckusick if (error) 31437617Smckusick return (error); 31516973Skarels } 3169637Ssam m = m_getclr(M_DONTWAIT, MT_PCB); 31710139Ssam if (m == NULL) 31810139Ssam return (ENOBUFS); 3198925Sroot unp = mtod(m, struct unpcb *); 3208925Sroot so->so_pcb = (caddr_t)unp; 3218925Sroot unp->unp_socket = so; 3228925Sroot return (0); 3238925Sroot } 3248925Sroot 32568323Scgd void 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)); 34359602Smckusick if (unp_rights) { 34459602Smckusick /* 34559602Smckusick * Normally the receive buffer is flushed later, 34659602Smckusick * in sofree, but if our receive buffer holds references 34759602Smckusick * to descriptors that are now garbage, we will dispose 34859602Smckusick * of those descriptor references after the garbage collector 34959602Smckusick * gets them (resulting in a "panic: closef: count < 0"). 35059602Smckusick */ 35159602Smckusick sorflush(unp->unp_socket); 35225632Skarels unp_gc(); 35359602Smckusick } 3548925Sroot } 3558925Sroot 35668323Scgd int 35748022Smckusick unp_bind(unp, nam, p) 3588925Sroot struct unpcb *unp; 3599169Ssam struct mbuf *nam; 36048022Smckusick struct proc *p; 3618925Sroot { 3629169Ssam struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 36337616Smckusick register struct vnode *vp; 36437616Smckusick struct vattr vattr; 3658925Sroot int error; 36647540Skarels struct nameidata nd; 3678925Sroot 36852309Smckusick NDINIT(&nd, CREATE, FOLLOW | LOCKPARENT, UIO_SYSSPACE, 36968323Scgd soun->sun_path, p); 37037617Smckusick if (unp->unp_vnode != NULL) 37112760Ssam return (EINVAL); 37237617Smckusick if (nam->m_len == MLEN) { 37337617Smckusick if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0) 37437617Smckusick return (EINVAL); 37537617Smckusick } else 37637617Smckusick *(mtod(nam, caddr_t) + nam->m_len) = 0; 37712760Ssam /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */ 37852309Smckusick if (error = namei(&nd)) 37937616Smckusick return (error); 38052309Smckusick vp = nd.ni_vp; 38137616Smckusick if (vp != NULL) { 38252309Smckusick VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); 38352309Smckusick if (nd.ni_dvp == vp) 38452309Smckusick vrele(nd.ni_dvp); 38543342Smckusick else 38652309Smckusick vput(nd.ni_dvp); 38742465Smckusick vrele(vp); 38810139Ssam return (EADDRINUSE); 3898925Sroot } 39041362Smckusick VATTR_NULL(&vattr); 39137616Smckusick vattr.va_type = VSOCK; 39264399Smckusick vattr.va_mode = ACCESSPERMS; 39367654Smckusick VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE); 39452309Smckusick if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr)) 39511828Ssam return (error); 39652309Smckusick vp = nd.ni_vp; 39737616Smckusick vp->v_socket = unp->unp_socket; 39837616Smckusick unp->unp_vnode = vp; 39925632Skarels unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL); 40037728Smckusick VOP_UNLOCK(vp); 4018925Sroot return (0); 4028925Sroot } 4038925Sroot 40468323Scgd int 40548022Smckusick unp_connect(so, nam, p) 4068925Sroot struct socket *so; 4079169Ssam struct mbuf *nam; 40848022Smckusick struct proc *p; 4098925Sroot { 4109169Ssam register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *); 41137616Smckusick register struct vnode *vp; 41237617Smckusick register struct socket *so2, *so3; 41337617Smckusick struct unpcb *unp2, *unp3; 41437616Smckusick int error; 41547540Skarels struct nameidata nd; 4168925Sroot 41752309Smckusick NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, soun->sun_path, p); 41837617Smckusick if (nam->m_data + nam->m_len == &nam->m_dat[MLEN]) { /* XXX */ 41937617Smckusick if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0) 42037617Smckusick return (EMSGSIZE); 42137617Smckusick } else 42237617Smckusick *(mtod(nam, caddr_t) + nam->m_len) = 0; 42352309Smckusick if (error = namei(&nd)) 42437616Smckusick return (error); 42552309Smckusick vp = nd.ni_vp; 42637616Smckusick if (vp->v_type != VSOCK) { 4278925Sroot error = ENOTSOCK; 4288925Sroot goto bad; 4298925Sroot } 43048022Smckusick if (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p)) 43138396Smckusick goto bad; 43237616Smckusick so2 = vp->v_socket; 4338925Sroot if (so2 == 0) { 4348925Sroot error = ECONNREFUSED; 4358925Sroot goto bad; 4368925Sroot } 43713115Ssam if (so->so_type != so2->so_type) { 43813115Ssam error = EPROTOTYPE; 43913115Ssam goto bad; 44013115Ssam } 44137617Smckusick if (so->so_proto->pr_flags & PR_CONNREQUIRED) { 44237617Smckusick if ((so2->so_options & SO_ACCEPTCONN) == 0 || 44340800Ssklower (so3 = sonewconn(so2, 0)) == 0) { 44437617Smckusick error = ECONNREFUSED; 44537617Smckusick goto bad; 44637617Smckusick } 44737617Smckusick unp2 = sotounpcb(so2); 44837617Smckusick unp3 = sotounpcb(so3); 44937617Smckusick if (unp2->unp_addr) 45037617Smckusick unp3->unp_addr = 45137617Smckusick m_copy(unp2->unp_addr, 0, (int)M_COPYALL); 45237617Smckusick so2 = so3; 45313115Ssam } 45426281Skarels error = unp_connect2(so, so2); 45512760Ssam bad: 45637728Smckusick vput(vp); 45712760Ssam return (error); 45812760Ssam } 45912760Ssam 46068323Scgd int 46126281Skarels unp_connect2(so, so2) 46212760Ssam register struct socket *so; 46312760Ssam register struct socket *so2; 46412760Ssam { 46512760Ssam register struct unpcb *unp = sotounpcb(so); 46612760Ssam register struct unpcb *unp2; 46712760Ssam 46812760Ssam if (so2->so_type != so->so_type) 46912760Ssam return (EPROTOTYPE); 47014049Ssam unp2 = sotounpcb(so2); 47114049Ssam unp->unp_conn = unp2; 4728925Sroot switch (so->so_type) { 4738925Sroot 4748925Sroot case SOCK_DGRAM: 4758925Sroot unp->unp_nextref = unp2->unp_refs; 4768925Sroot unp2->unp_refs = unp; 47717543Skarels soisconnected(so); 4788925Sroot break; 4798925Sroot 4808925Sroot case SOCK_STREAM: 4819169Ssam unp2->unp_conn = unp; 48240800Ssklower soisconnected(so); 48314049Ssam soisconnected(so2); 4848925Sroot break; 4858925Sroot 4868925Sroot default: 48712760Ssam panic("unp_connect2"); 4888925Sroot } 4898925Sroot return (0); 4908925Sroot } 4919169Ssam 49268171Scgd void 4939169Ssam unp_disconnect(unp) 4949169Ssam struct unpcb *unp; 4959169Ssam { 4969169Ssam register struct unpcb *unp2 = unp->unp_conn; 4979169Ssam 4989169Ssam if (unp2 == 0) 4999169Ssam return; 5009169Ssam unp->unp_conn = 0; 5019169Ssam switch (unp->unp_socket->so_type) { 5029169Ssam 5039169Ssam case SOCK_DGRAM: 5049169Ssam if (unp2->unp_refs == unp) 5059169Ssam unp2->unp_refs = unp->unp_nextref; 5069169Ssam else { 5079169Ssam unp2 = unp2->unp_refs; 5089169Ssam for (;;) { 5099169Ssam if (unp2 == 0) 5109169Ssam panic("unp_disconnect"); 5119169Ssam if (unp2->unp_nextref == unp) 5129169Ssam break; 5139169Ssam unp2 = unp2->unp_nextref; 5149169Ssam } 5159169Ssam unp2->unp_nextref = unp->unp_nextref; 5169169Ssam } 5179169Ssam unp->unp_nextref = 0; 51821768Skarels unp->unp_socket->so_state &= ~SS_ISCONNECTED; 5199169Ssam break; 5209169Ssam 5219169Ssam case SOCK_STREAM: 52214049Ssam soisdisconnected(unp->unp_socket); 5239169Ssam unp2->unp_conn = 0; 5249169Ssam soisdisconnected(unp2->unp_socket); 5259169Ssam break; 5269169Ssam } 5279169Ssam } 5289169Ssam 52912760Ssam #ifdef notdef 53068323Scgd void 5319169Ssam unp_abort(unp) 5329169Ssam struct unpcb *unp; 5339169Ssam { 5349169Ssam 5359169Ssam unp_detach(unp); 5369169Ssam } 53712760Ssam #endif 5389169Ssam 53968171Scgd void 54045004Skarels unp_shutdown(unp) 5419169Ssam struct unpcb *unp; 5429169Ssam { 54345004Skarels struct socket *so; 5449169Ssam 54545004Skarels if (unp->unp_socket->so_type == SOCK_STREAM && unp->unp_conn && 54645004Skarels (so = unp->unp_conn->unp_socket)) 54745004Skarels socantrcvmore(so); 5489169Ssam } 5499169Ssam 55068171Scgd void 5519169Ssam unp_drop(unp, errno) 5529169Ssam struct unpcb *unp; 5539169Ssam int errno; 5549169Ssam { 55516054Skarels struct socket *so = unp->unp_socket; 5569169Ssam 55716054Skarels so->so_error = errno; 5589169Ssam unp_disconnect(unp); 55916054Skarels if (so->so_head) { 56016054Skarels so->so_pcb = (caddr_t) 0; 56125632Skarels m_freem(unp->unp_addr); 56216054Skarels (void) m_free(dtom(unp)); 56316054Skarels sofree(so); 56416054Skarels } 5659169Ssam } 5669169Ssam 56712760Ssam #ifdef notdef 5689169Ssam unp_drain() 5699169Ssam { 5709169Ssam 5719169Ssam } 57212760Ssam #endif 57312760Ssam 57468323Scgd int 57512760Ssam unp_externalize(rights) 57612760Ssam struct mbuf *rights; 57712760Ssam { 57847540Skarels struct proc *p = curproc; /* XXX */ 57912760Ssam register int i; 58040800Ssklower register struct cmsghdr *cm = mtod(rights, struct cmsghdr *); 58140800Ssklower register struct file **rp = (struct file **)(cm + 1); 58212760Ssam register struct file *fp; 58340800Ssklower int newfds = (cm->cmsg_len - sizeof(*cm)) / sizeof (int); 58412760Ssam int f; 58512760Ssam 58655090Spendry if (!fdavail(p, newfds)) { 58712760Ssam for (i = 0; i < newfds; i++) { 58812760Ssam fp = *rp; 58912760Ssam unp_discard(fp); 59012760Ssam *rp++ = 0; 59112760Ssam } 59212760Ssam return (EMSGSIZE); 59312760Ssam } 59412760Ssam for (i = 0; i < newfds; i++) { 59547540Skarels if (fdalloc(p, 0, &f)) 59612760Ssam panic("unp_externalize"); 59712760Ssam fp = *rp; 59847647Skarels p->p_fd->fd_ofiles[f] = fp; 59912760Ssam fp->f_msgcount--; 60025632Skarels unp_rights--; 60114927Smckusick *(int *)rp++ = f; 60212760Ssam } 60312760Ssam return (0); 60412760Ssam } 60512760Ssam 60668323Scgd int 60748022Smckusick unp_internalize(control, p) 60840937Skarels struct mbuf *control; 60948022Smckusick struct proc *p; 61012760Ssam { 61148022Smckusick struct filedesc *fdp = p->p_fd; 61240937Skarels register struct cmsghdr *cm = mtod(control, struct cmsghdr *); 61312760Ssam register struct file **rp; 61440937Skarels register struct file *fp; 61537728Smckusick register int i, fd; 61640937Skarels int oldfds; 61712760Ssam 61840937Skarels if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET || 61940937Skarels cm->cmsg_len != control->m_len) 62040800Ssklower return (EINVAL); 62140800Ssklower oldfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int); 62240800Ssklower rp = (struct file **)(cm + 1); 62337728Smckusick for (i = 0; i < oldfds; i++) { 62437728Smckusick fd = *(int *)rp++; 62547647Skarels if ((unsigned)fd >= fdp->fd_nfiles || 62647647Skarels fdp->fd_ofiles[fd] == NULL) 62712760Ssam return (EBADF); 62837728Smckusick } 62940800Ssklower rp = (struct file **)(cm + 1); 63013084Ssam for (i = 0; i < oldfds; i++) { 63147647Skarels fp = fdp->fd_ofiles[*(int *)rp]; 63212760Ssam *rp++ = fp; 63312760Ssam fp->f_count++; 63412760Ssam fp->f_msgcount++; 63525632Skarels unp_rights++; 63612760Ssam } 63712760Ssam return (0); 63812760Ssam } 63912760Ssam 64012760Ssam int unp_defer, unp_gcing; 64116995Skarels extern struct domain unixdomain; 64212760Ssam 64368171Scgd void 64412760Ssam unp_gc() 64512760Ssam { 64653484Smckusick register struct file *fp, *nextfp; 64712760Ssam register struct socket *so; 64855665Smckusick struct file **extra_ref, **fpp; 64955665Smckusick int nunref, i; 65012760Ssam 65112760Ssam if (unp_gcing) 65212760Ssam return; 65312760Ssam unp_gcing = 1; 65412760Ssam unp_defer = 0; 65567732Smckusick for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) 65612760Ssam fp->f_flag &= ~(FMARK|FDEFER); 65712760Ssam do { 65867732Smckusick for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) { 65912760Ssam if (fp->f_count == 0) 66012760Ssam continue; 66112760Ssam if (fp->f_flag & FDEFER) { 66212760Ssam fp->f_flag &= ~FDEFER; 66312760Ssam unp_defer--; 66412760Ssam } else { 66512760Ssam if (fp->f_flag & FMARK) 66612760Ssam continue; 66712760Ssam if (fp->f_count == fp->f_msgcount) 66812760Ssam continue; 66912760Ssam fp->f_flag |= FMARK; 67012760Ssam } 67137617Smckusick if (fp->f_type != DTYPE_SOCKET || 67237617Smckusick (so = (struct socket *)fp->f_data) == 0) 67312760Ssam continue; 67416995Skarels if (so->so_proto->pr_domain != &unixdomain || 67521768Skarels (so->so_proto->pr_flags&PR_RIGHTS) == 0) 67612760Ssam continue; 67745004Skarels #ifdef notdef 67812760Ssam if (so->so_rcv.sb_flags & SB_LOCK) { 67945004Skarels /* 68045004Skarels * This is problematical; it's not clear 68145004Skarels * we need to wait for the sockbuf to be 68245004Skarels * unlocked (on a uniprocessor, at least), 68345004Skarels * and it's also not clear what to do 68445004Skarels * if sbwait returns an error due to receipt 68545004Skarels * of a signal. If sbwait does return 68645004Skarels * an error, we'll go into an infinite 68745004Skarels * loop. Delete all of this for now. 68845004Skarels */ 68945004Skarels (void) sbwait(&so->so_rcv); 69012760Ssam goto restart; 69112760Ssam } 69245004Skarels #endif 69312760Ssam unp_scan(so->so_rcv.sb_mb, unp_mark); 69412760Ssam } 69512760Ssam } while (unp_defer); 69655665Smckusick /* 69755665Smckusick * We grab an extra reference to each of the file table entries 69855665Smckusick * that are not otherwise accessible and then free the rights 69955665Smckusick * that are stored in messages on them. 70055665Smckusick * 70155665Smckusick * The bug in the orginal code is a little tricky, so I'll describe 70255665Smckusick * what's wrong with it here. 70355665Smckusick * 70455665Smckusick * It is incorrect to simply unp_discard each entry for f_msgcount 70555665Smckusick * times -- consider the case of sockets A and B that contain 70655665Smckusick * references to each other. On a last close of some other socket, 70755665Smckusick * we trigger a gc since the number of outstanding rights (unp_rights) 70855665Smckusick * is non-zero. If during the sweep phase the gc code un_discards, 70955665Smckusick * we end up doing a (full) closef on the descriptor. A closef on A 71055665Smckusick * results in the following chain. Closef calls soo_close, which 71155665Smckusick * calls soclose. Soclose calls first (through the switch 71255665Smckusick * uipc_usrreq) unp_detach, which re-invokes unp_gc. Unp_gc simply 71355665Smckusick * returns because the previous instance had set unp_gcing, and 71455665Smckusick * we return all the way back to soclose, which marks the socket 71555665Smckusick * with SS_NOFDREF, and then calls sofree. Sofree calls sorflush 71655665Smckusick * to free up the rights that are queued in messages on the socket A, 71755665Smckusick * i.e., the reference on B. The sorflush calls via the dom_dispose 71855665Smckusick * switch unp_dispose, which unp_scans with unp_discard. This second 71955665Smckusick * instance of unp_discard just calls closef on B. 72055665Smckusick * 72155665Smckusick * Well, a similar chain occurs on B, resulting in a sorflush on B, 72255665Smckusick * which results in another closef on A. Unfortunately, A is already 72355665Smckusick * being closed, and the descriptor has already been marked with 72455665Smckusick * SS_NOFDREF, and soclose panics at this point. 72555665Smckusick * 72655665Smckusick * Here, we first take an extra reference to each inaccessible 72755665Smckusick * descriptor. Then, we call sorflush ourself, since we know 72855665Smckusick * it is a Unix domain socket anyhow. After we destroy all the 72955665Smckusick * rights carried in messages, we do a last closef to get rid 73055665Smckusick * of our extra reference. This is the last close, and the 73155665Smckusick * unp_detach etc will shut down the socket. 73255665Smckusick * 73355665Smckusick * 91/09/19, bsy@cs.cmu.edu 73455665Smckusick */ 73555665Smckusick extra_ref = malloc(nfiles * sizeof(struct file *), M_FILE, M_WAITOK); 73667732Smckusick for (nunref = 0, fp = filehead.lh_first, fpp = extra_ref; fp != 0; 73767732Smckusick fp = nextfp) { 73867732Smckusick nextfp = fp->f_list.le_next; 73912760Ssam if (fp->f_count == 0) 74012760Ssam continue; 74155665Smckusick if (fp->f_count == fp->f_msgcount && !(fp->f_flag & FMARK)) { 74255665Smckusick *fpp++ = fp; 74355665Smckusick nunref++; 74455665Smckusick fp->f_count++; 74555665Smckusick } 74612760Ssam } 74755665Smckusick for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp) 74855665Smckusick sorflush((struct socket *)(*fpp)->f_data); 74955665Smckusick for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp) 750*69142Smckusick closef(*fpp, (struct proc *)NULL); 75155665Smckusick free((caddr_t)extra_ref, M_FILE); 75212760Ssam unp_gcing = 0; 75312760Ssam } 75412760Ssam 75568171Scgd void 75616995Skarels unp_dispose(m) 75716995Skarels struct mbuf *m; 75816995Skarels { 75916995Skarels 76017020Skarels if (m) 76117020Skarels unp_scan(m, unp_discard); 76216995Skarels } 76316995Skarels 76468171Scgd void 76516995Skarels unp_scan(m0, op) 76616995Skarels register struct mbuf *m0; 76768323Scgd void (*op) __P((struct file *)); 76812760Ssam { 76916995Skarels register struct mbuf *m; 77012760Ssam register struct file **rp; 77140937Skarels register struct cmsghdr *cm; 77212760Ssam register int i; 77317020Skarels int qfds; 77412760Ssam 77516995Skarels while (m0) { 77616995Skarels for (m = m0; m; m = m->m_next) 77740937Skarels if (m->m_type == MT_CONTROL && 77840937Skarels m->m_len >= sizeof(*cm)) { 77940800Ssklower cm = mtod(m, struct cmsghdr *); 78040937Skarels if (cm->cmsg_level != SOL_SOCKET || 78140937Skarels cm->cmsg_type != SCM_RIGHTS) 78240937Skarels continue; 78340800Ssklower qfds = (cm->cmsg_len - sizeof *cm) 78440800Ssklower / sizeof (struct file *); 78540800Ssklower rp = (struct file **)(cm + 1); 78616995Skarels for (i = 0; i < qfds; i++) 78716995Skarels (*op)(*rp++); 78816995Skarels break; /* XXX, but saves time */ 78916995Skarels } 79017020Skarels m0 = m0->m_act; 79112760Ssam } 79212760Ssam } 79312760Ssam 79468171Scgd void 79512760Ssam unp_mark(fp) 79612760Ssam struct file *fp; 79712760Ssam { 79812760Ssam 79912760Ssam if (fp->f_flag & FMARK) 80012760Ssam return; 80112760Ssam unp_defer++; 80212760Ssam fp->f_flag |= (FMARK|FDEFER); 80312760Ssam } 80412760Ssam 80568171Scgd void 80612760Ssam unp_discard(fp) 80712760Ssam struct file *fp; 80812760Ssam { 80912760Ssam 81012760Ssam fp->f_msgcount--; 81125632Skarels unp_rights--; 81252033Skarels (void) closef(fp, (struct proc *)NULL); 81312760Ssam } 814