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*69409Smckusick * @(#)uipc_usrreq.c 8.9 (Berkeley) 05/14/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
uipc_usrreq(so,req,m,nam,control)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
unp_attach(so)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
unp_detach(unp)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
unp_bind(unp,nam,p)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);
400*69409Smckusick VOP_UNLOCK(vp, 0, p);
4018925Sroot return (0);
4028925Sroot }
4038925Sroot
40468323Scgd int
unp_connect(so,nam,p)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
unp_connect2(so,so2)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
unp_disconnect(unp)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
unp_abort(unp)5319169Ssam unp_abort(unp)
5329169Ssam struct unpcb *unp;
5339169Ssam {
5349169Ssam
5359169Ssam unp_detach(unp);
5369169Ssam }
53712760Ssam #endif
5389169Ssam
53968171Scgd void
unp_shutdown(unp)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
unp_drop(unp,errno)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
unp_drain()5689169Ssam unp_drain()
5699169Ssam {
5709169Ssam
5719169Ssam }
57212760Ssam #endif
57312760Ssam
57468323Scgd int
unp_externalize(rights)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
unp_internalize(control,p)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
unp_gc()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)
75069142Smckusick closef(*fpp, (struct proc *)NULL);
75155665Smckusick free((caddr_t)extra_ref, M_FILE);
75212760Ssam unp_gcing = 0;
75312760Ssam }
75412760Ssam
75568171Scgd void
unp_dispose(m)75616995Skarels unp_dispose(m)
75716995Skarels struct mbuf *m;
75816995Skarels {
75916995Skarels
76017020Skarels if (m)
76117020Skarels unp_scan(m, unp_discard);
76216995Skarels }
76316995Skarels
76468171Scgd void
unp_scan(m0,op)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
unp_mark(fp)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
unp_discard(fp)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