xref: /csrg-svn/sys/kern/uipc_usrreq.c (revision 68323)
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*68323Scgd  *	@(#)uipc_usrreq.c	8.7 (Berkeley) 02/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*/
38*68323Scgd 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 
291*68323Scgd 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 
325*68323Scgd 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 
356*68323Scgd 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,
369*68323Scgd 	    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 
404*68323Scgd 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 
460*68323Scgd 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
530*68323Scgd 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 
574*68323Scgd 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 
606*68323Scgd 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)
75055665Smckusick 		closef(*fpp);
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;
767*68323Scgd 	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