xref: /csrg-svn/sys/kern/uipc_usrreq.c (revision 68171)
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*68171Scgd  *	@(#)uipc_usrreq.c	8.6 (Berkeley) 01/09/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*/
3840800Ssklower uipc_usrreq(so, req, m, nam, control)
398925Sroot 	struct socket *so;
408925Sroot 	int req;
4140800Ssklower 	struct mbuf *m, *nam, *control;
428925Sroot {
438925Sroot 	struct unpcb *unp = sotounpcb(so);
448925Sroot 	register struct socket *so2;
4540937Skarels 	register int error = 0;
4648022Smckusick 	struct proc *p = curproc;	/* XXX */
478925Sroot 
4825555Skarels 	if (req == PRU_CONTROL)
4925555Skarels 		return (EOPNOTSUPP);
5040800Ssklower 	if (req != PRU_SEND && control && control->m_len) {
5112760Ssam 		error = EOPNOTSUPP;
5212760Ssam 		goto release;
5312760Ssam 	}
5412760Ssam 	if (unp == 0 && req != PRU_ATTACH) {
5512760Ssam 		error = EINVAL;
5612760Ssam 		goto release;
5712760Ssam 	}
588925Sroot 	switch (req) {
598925Sroot 
608925Sroot 	case PRU_ATTACH:
618925Sroot 		if (unp) {
629169Ssam 			error = EISCONN;
638925Sroot 			break;
648925Sroot 		}
659028Sroot 		error = unp_attach(so);
668925Sroot 		break;
678925Sroot 
688925Sroot 	case PRU_DETACH:
698925Sroot 		unp_detach(unp);
708925Sroot 		break;
718925Sroot 
729169Ssam 	case PRU_BIND:
7348022Smckusick 		error = unp_bind(unp, nam, p);
749169Ssam 		break;
759169Ssam 
769169Ssam 	case PRU_LISTEN:
7737616Smckusick 		if (unp->unp_vnode == 0)
789169Ssam 			error = EINVAL;
799169Ssam 		break;
809169Ssam 
818925Sroot 	case PRU_CONNECT:
8248022Smckusick 		error = unp_connect(so, nam, p);
838925Sroot 		break;
848925Sroot 
8512760Ssam 	case PRU_CONNECT2:
8626281Skarels 		error = unp_connect2(so, (struct socket *)nam);
8712760Ssam 		break;
8812760Ssam 
898925Sroot 	case PRU_DISCONNECT:
908925Sroot 		unp_disconnect(unp);
918925Sroot 		break;
928925Sroot 
939169Ssam 	case PRU_ACCEPT:
9425899Skarels 		/*
9525899Skarels 		 * Pass back name of connected socket,
9625899Skarels 		 * if it was bound and we are still connected
9725899Skarels 		 * (our peer may have closed already!).
9825899Skarels 		 */
9925899Skarels 		if (unp->unp_conn && unp->unp_conn->unp_addr) {
10025632Skarels 			nam->m_len = unp->unp_conn->unp_addr->m_len;
10125632Skarels 			bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
10225632Skarels 			    mtod(nam, caddr_t), (unsigned)nam->m_len);
10325632Skarels 		} else {
10425632Skarels 			nam->m_len = sizeof(sun_noname);
10525632Skarels 			*(mtod(nam, struct sockaddr *)) = sun_noname;
10625632Skarels 		}
1078925Sroot 		break;
1088925Sroot 
1098925Sroot 	case PRU_SHUTDOWN:
1108925Sroot 		socantsendmore(so);
11145004Skarels 		unp_shutdown(unp);
1128925Sroot 		break;
1138925Sroot 
1148925Sroot 	case PRU_RCVD:
1158925Sroot 		switch (so->so_type) {
1168925Sroot 
1178925Sroot 		case SOCK_DGRAM:
1188925Sroot 			panic("uipc 1");
11910139Ssam 			/*NOTREACHED*/
1208925Sroot 
12110139Ssam 		case SOCK_STREAM:
1228925Sroot #define	rcv (&so->so_rcv)
1238925Sroot #define snd (&so2->so_snd)
1248925Sroot 			if (unp->unp_conn == 0)
1258925Sroot 				break;
1268925Sroot 			so2 = unp->unp_conn->unp_socket;
1278925Sroot 			/*
12825632Skarels 			 * Adjust backpressure on sender
1298925Sroot 			 * and wakeup any waiting to write.
1308925Sroot 			 */
13125632Skarels 			snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt;
13225632Skarels 			unp->unp_mbcnt = rcv->sb_mbcnt;
13325632Skarels 			snd->sb_hiwat += unp->unp_cc - rcv->sb_cc;
13425632Skarels 			unp->unp_cc = rcv->sb_cc;
13517543Skarels 			sowwakeup(so2);
1368925Sroot #undef snd
1378925Sroot #undef rcv
1388925Sroot 			break;
1398925Sroot 
1408925Sroot 		default:
1418925Sroot 			panic("uipc 2");
1428925Sroot 		}
1438925Sroot 		break;
1448925Sroot 
1458925Sroot 	case PRU_SEND:
14648022Smckusick 		if (control && (error = unp_internalize(control, p)))
14740937Skarels 			break;
1488925Sroot 		switch (so->so_type) {
1498925Sroot 
15025632Skarels 		case SOCK_DGRAM: {
15125632Skarels 			struct sockaddr *from;
15225632Skarels 
1539028Sroot 			if (nam) {
1548925Sroot 				if (unp->unp_conn) {
1558925Sroot 					error = EISCONN;
1568925Sroot 					break;
1578925Sroot 				}
15848022Smckusick 				error = unp_connect(so, nam, p);
1598925Sroot 				if (error)
1608925Sroot 					break;
1618925Sroot 			} else {
1628925Sroot 				if (unp->unp_conn == 0) {
1638925Sroot 					error = ENOTCONN;
1648925Sroot 					break;
1658925Sroot 				}
1668925Sroot 			}
1678925Sroot 			so2 = unp->unp_conn->unp_socket;
16825632Skarels 			if (unp->unp_addr)
16925632Skarels 				from = mtod(unp->unp_addr, struct sockaddr *);
17025632Skarels 			else
17125632Skarels 				from = &sun_noname;
17240937Skarels 			if (sbappendaddr(&so2->so_rcv, from, m, control)) {
17325632Skarels 				sorwakeup(so2);
17425632Skarels 				m = 0;
17540937Skarels 				control = 0;
17625632Skarels 			} else
17725632Skarels 				error = ENOBUFS;
1789028Sroot 			if (nam)
1799169Ssam 				unp_disconnect(unp);
1808925Sroot 			break;
18125632Skarels 		}
1828925Sroot 
1838925Sroot 		case SOCK_STREAM:
1848925Sroot #define	rcv (&so2->so_rcv)
1858925Sroot #define	snd (&so->so_snd)
18623524Skarels 			if (so->so_state & SS_CANTSENDMORE) {
18723524Skarels 				error = EPIPE;
18823524Skarels 				break;
18923524Skarels 			}
1908925Sroot 			if (unp->unp_conn == 0)
1918925Sroot 				panic("uipc 3");
1928925Sroot 			so2 = unp->unp_conn->unp_socket;
1938925Sroot 			/*
19425632Skarels 			 * Send to paired receive port, and then reduce
19525632Skarels 			 * send buffer hiwater marks to maintain backpressure.
1968925Sroot 			 * Wake up readers.
1978925Sroot 			 */
19840937Skarels 			if (control) {
19945004Skarels 				if (sbappendcontrol(rcv, m, control))
20045004Skarels 					control = 0;
20140937Skarels 			} else
20225632Skarels 				sbappend(rcv, m);
20325632Skarels 			snd->sb_mbmax -=
20425632Skarels 			    rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt;
20525632Skarels 			unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt;
20625632Skarels 			snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc;
20725632Skarels 			unp->unp_conn->unp_cc = rcv->sb_cc;
20817543Skarels 			sorwakeup(so2);
20917543Skarels 			m = 0;
2108925Sroot #undef snd
2118925Sroot #undef rcv
2128925Sroot 			break;
2138925Sroot 
2148925Sroot 		default:
2158925Sroot 			panic("uipc 4");
2168925Sroot 		}
2178925Sroot 		break;
2188925Sroot 
2198925Sroot 	case PRU_ABORT:
2208925Sroot 		unp_drop(unp, ECONNABORTED);
2218925Sroot 		break;
2228925Sroot 
2238925Sroot 	case PRU_SENSE:
22416973Skarels 		((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
22516973Skarels 		if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) {
22616973Skarels 			so2 = unp->unp_conn->unp_socket;
22716973Skarels 			((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc;
22816973Skarels 		}
22921110Skarels 		((struct stat *) m)->st_dev = NODEV;
23040800Ssklower 		if (unp->unp_ino == 0)
23140800Ssklower 			unp->unp_ino = unp_ino++;
23240800Ssklower 		((struct stat *) m)->st_ino = unp->unp_ino;
23316973Skarels 		return (0);
2348925Sroot 
2358925Sroot 	case PRU_RCVOOB:
23616774Sbloom 		return (EOPNOTSUPP);
2378925Sroot 
2388925Sroot 	case PRU_SENDOOB:
23917543Skarels 		error = EOPNOTSUPP;
2408925Sroot 		break;
2418925Sroot 
2428925Sroot 	case PRU_SOCKADDR:
24337617Smckusick 		if (unp->unp_addr) {
24437617Smckusick 			nam->m_len = unp->unp_addr->m_len;
24537617Smckusick 			bcopy(mtod(unp->unp_addr, caddr_t),
24637617Smckusick 			    mtod(nam, caddr_t), (unsigned)nam->m_len);
24737617Smckusick 		} else
24837617Smckusick 			nam->m_len = 0;
2498925Sroot 		break;
2508925Sroot 
25114121Ssam 	case PRU_PEERADDR:
25228292Skarels 		if (unp->unp_conn && unp->unp_conn->unp_addr) {
25328292Skarels 			nam->m_len = unp->unp_conn->unp_addr->m_len;
25428292Skarels 			bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
25533287Sbostic 			    mtod(nam, caddr_t), (unsigned)nam->m_len);
25637617Smckusick 		} else
25737617Smckusick 			nam->m_len = 0;
25814121Ssam 		break;
25914121Ssam 
2608925Sroot 	case PRU_SLOWTIMO:
2618925Sroot 		break;
2628925Sroot 
2638925Sroot 	default:
2648925Sroot 		panic("piusrreq");
2658925Sroot 	}
26612760Ssam release:
26740937Skarels 	if (control)
26840937Skarels 		m_freem(control);
26912760Ssam 	if (m)
27012760Ssam 		m_freem(m);
27111709Ssam 	return (error);
2728925Sroot }
2738925Sroot 
27416973Skarels /*
27525632Skarels  * Both send and receive buffers are allocated PIPSIZ bytes of buffering
27625632Skarels  * for stream sockets, although the total for sender and receiver is
27725632Skarels  * actually only PIPSIZ.
27816973Skarels  * Datagram sockets really use the sendspace as the maximum datagram size,
27916973Skarels  * and don't really want to reserve the sendspace.  Their recvspace should
28016973Skarels  * be large enough for at least one max-size datagram plus address.
28116973Skarels  */
28216973Skarels #define	PIPSIZ	4096
28337617Smckusick u_long	unpst_sendspace = PIPSIZ;
28437617Smckusick u_long	unpst_recvspace = PIPSIZ;
28537617Smckusick u_long	unpdg_sendspace = 2*1024;	/* really max datagram size */
28637617Smckusick u_long	unpdg_recvspace = 4*1024;
2878925Sroot 
28825632Skarels int	unp_rights;			/* file descriptors in flight */
28925632Skarels 
2909169Ssam unp_attach(so)
2918925Sroot 	struct socket *so;
2928925Sroot {
2939169Ssam 	register struct mbuf *m;
2948925Sroot 	register struct unpcb *unp;
2958925Sroot 	int error;
2968925Sroot 
29737617Smckusick 	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
29837617Smckusick 		switch (so->so_type) {
29916973Skarels 
30037617Smckusick 		case SOCK_STREAM:
30137617Smckusick 			error = soreserve(so, unpst_sendspace, unpst_recvspace);
30237617Smckusick 			break;
30316973Skarels 
30437617Smckusick 		case SOCK_DGRAM:
30537617Smckusick 			error = soreserve(so, unpdg_sendspace, unpdg_recvspace);
30637617Smckusick 			break;
30752921Smckusick 
30852921Smckusick 		default:
30952921Smckusick 			panic("unp_attach");
31037617Smckusick 		}
31137617Smckusick 		if (error)
31237617Smckusick 			return (error);
31316973Skarels 	}
3149637Ssam 	m = m_getclr(M_DONTWAIT, MT_PCB);
31510139Ssam 	if (m == NULL)
31610139Ssam 		return (ENOBUFS);
3178925Sroot 	unp = mtod(m, struct unpcb *);
3188925Sroot 	so->so_pcb = (caddr_t)unp;
3198925Sroot 	unp->unp_socket = so;
3208925Sroot 	return (0);
3218925Sroot }
3228925Sroot 
3238925Sroot unp_detach(unp)
3249169Ssam 	register struct unpcb *unp;
3258925Sroot {
3268925Sroot 
32737616Smckusick 	if (unp->unp_vnode) {
32837616Smckusick 		unp->unp_vnode->v_socket = 0;
32937616Smckusick 		vrele(unp->unp_vnode);
33037616Smckusick 		unp->unp_vnode = 0;
3318925Sroot 	}
3328925Sroot 	if (unp->unp_conn)
3338925Sroot 		unp_disconnect(unp);
3348925Sroot 	while (unp->unp_refs)
3358925Sroot 		unp_drop(unp->unp_refs, ECONNRESET);
3368925Sroot 	soisdisconnected(unp->unp_socket);
3378925Sroot 	unp->unp_socket->so_pcb = 0;
33825632Skarels 	m_freem(unp->unp_addr);
3399169Ssam 	(void) m_free(dtom(unp));
34059602Smckusick 	if (unp_rights) {
34159602Smckusick 		/*
34259602Smckusick 		 * Normally the receive buffer is flushed later,
34359602Smckusick 		 * in sofree, but if our receive buffer holds references
34459602Smckusick 		 * to descriptors that are now garbage, we will dispose
34559602Smckusick 		 * of those descriptor references after the garbage collector
34659602Smckusick 		 * gets them (resulting in a "panic: closef: count < 0").
34759602Smckusick 		 */
34859602Smckusick 		sorflush(unp->unp_socket);
34925632Skarels 		unp_gc();
35059602Smckusick 	}
3518925Sroot }
3528925Sroot 
35348022Smckusick unp_bind(unp, nam, p)
3548925Sroot 	struct unpcb *unp;
3559169Ssam 	struct mbuf *nam;
35648022Smckusick 	struct proc *p;
3578925Sroot {
3589169Ssam 	struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
35937616Smckusick 	register struct vnode *vp;
36037616Smckusick 	struct vattr vattr;
3618925Sroot 	int error;
36247540Skarels 	struct nameidata nd;
3638925Sroot 
36452309Smckusick 	NDINIT(&nd, CREATE, FOLLOW | LOCKPARENT, UIO_SYSSPACE,
36552309Smckusick 		soun->sun_path, p);
36637617Smckusick 	if (unp->unp_vnode != NULL)
36712760Ssam 		return (EINVAL);
36837617Smckusick 	if (nam->m_len == MLEN) {
36937617Smckusick 		if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)
37037617Smckusick 			return (EINVAL);
37137617Smckusick 	} else
37237617Smckusick 		*(mtod(nam, caddr_t) + nam->m_len) = 0;
37312760Ssam /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
37452309Smckusick 	if (error = namei(&nd))
37537616Smckusick 		return (error);
37652309Smckusick 	vp = nd.ni_vp;
37737616Smckusick 	if (vp != NULL) {
37852309Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
37952309Smckusick 		if (nd.ni_dvp == vp)
38052309Smckusick 			vrele(nd.ni_dvp);
38143342Smckusick 		else
38252309Smckusick 			vput(nd.ni_dvp);
38342465Smckusick 		vrele(vp);
38410139Ssam 		return (EADDRINUSE);
3858925Sroot 	}
38641362Smckusick 	VATTR_NULL(&vattr);
38737616Smckusick 	vattr.va_type = VSOCK;
38864399Smckusick 	vattr.va_mode = ACCESSPERMS;
38967654Smckusick 	VOP_LEASE(nd.ni_dvp, p, p->p_ucred, LEASE_WRITE);
39052309Smckusick 	if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr))
39111828Ssam 		return (error);
39252309Smckusick 	vp = nd.ni_vp;
39337616Smckusick 	vp->v_socket = unp->unp_socket;
39437616Smckusick 	unp->unp_vnode = vp;
39525632Skarels 	unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL);
39637728Smckusick 	VOP_UNLOCK(vp);
3978925Sroot 	return (0);
3988925Sroot }
3998925Sroot 
40048022Smckusick unp_connect(so, nam, p)
4018925Sroot 	struct socket *so;
4029169Ssam 	struct mbuf *nam;
40348022Smckusick 	struct proc *p;
4048925Sroot {
4059169Ssam 	register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
40637616Smckusick 	register struct vnode *vp;
40737617Smckusick 	register struct socket *so2, *so3;
40837617Smckusick 	struct unpcb *unp2, *unp3;
40937616Smckusick 	int error;
41047540Skarels 	struct nameidata nd;
4118925Sroot 
41252309Smckusick 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, soun->sun_path, p);
41337617Smckusick 	if (nam->m_data + nam->m_len == &nam->m_dat[MLEN]) {	/* XXX */
41437617Smckusick 		if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)
41537617Smckusick 			return (EMSGSIZE);
41637617Smckusick 	} else
41737617Smckusick 		*(mtod(nam, caddr_t) + nam->m_len) = 0;
41852309Smckusick 	if (error = namei(&nd))
41937616Smckusick 		return (error);
42052309Smckusick 	vp = nd.ni_vp;
42137616Smckusick 	if (vp->v_type != VSOCK) {
4228925Sroot 		error = ENOTSOCK;
4238925Sroot 		goto bad;
4248925Sroot 	}
42548022Smckusick 	if (error = VOP_ACCESS(vp, VWRITE, p->p_ucred, p))
42638396Smckusick 		goto bad;
42737616Smckusick 	so2 = vp->v_socket;
4288925Sroot 	if (so2 == 0) {
4298925Sroot 		error = ECONNREFUSED;
4308925Sroot 		goto bad;
4318925Sroot 	}
43213115Ssam 	if (so->so_type != so2->so_type) {
43313115Ssam 		error = EPROTOTYPE;
43413115Ssam 		goto bad;
43513115Ssam 	}
43637617Smckusick 	if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
43737617Smckusick 		if ((so2->so_options & SO_ACCEPTCONN) == 0 ||
43840800Ssklower 		    (so3 = sonewconn(so2, 0)) == 0) {
43937617Smckusick 			error = ECONNREFUSED;
44037617Smckusick 			goto bad;
44137617Smckusick 		}
44237617Smckusick 		unp2 = sotounpcb(so2);
44337617Smckusick 		unp3 = sotounpcb(so3);
44437617Smckusick 		if (unp2->unp_addr)
44537617Smckusick 			unp3->unp_addr =
44637617Smckusick 				  m_copy(unp2->unp_addr, 0, (int)M_COPYALL);
44737617Smckusick 		so2 = so3;
44813115Ssam 	}
44926281Skarels 	error = unp_connect2(so, so2);
45012760Ssam bad:
45137728Smckusick 	vput(vp);
45212760Ssam 	return (error);
45312760Ssam }
45412760Ssam 
45526281Skarels unp_connect2(so, so2)
45612760Ssam 	register struct socket *so;
45712760Ssam 	register struct socket *so2;
45812760Ssam {
45912760Ssam 	register struct unpcb *unp = sotounpcb(so);
46012760Ssam 	register struct unpcb *unp2;
46112760Ssam 
46212760Ssam 	if (so2->so_type != so->so_type)
46312760Ssam 		return (EPROTOTYPE);
46414049Ssam 	unp2 = sotounpcb(so2);
46514049Ssam 	unp->unp_conn = unp2;
4668925Sroot 	switch (so->so_type) {
4678925Sroot 
4688925Sroot 	case SOCK_DGRAM:
4698925Sroot 		unp->unp_nextref = unp2->unp_refs;
4708925Sroot 		unp2->unp_refs = unp;
47117543Skarels 		soisconnected(so);
4728925Sroot 		break;
4738925Sroot 
4748925Sroot 	case SOCK_STREAM:
4759169Ssam 		unp2->unp_conn = unp;
47640800Ssklower 		soisconnected(so);
47714049Ssam 		soisconnected(so2);
4788925Sroot 		break;
4798925Sroot 
4808925Sroot 	default:
48112760Ssam 		panic("unp_connect2");
4828925Sroot 	}
4838925Sroot 	return (0);
4848925Sroot }
4859169Ssam 
486*68171Scgd void
4879169Ssam unp_disconnect(unp)
4889169Ssam 	struct unpcb *unp;
4899169Ssam {
4909169Ssam 	register struct unpcb *unp2 = unp->unp_conn;
4919169Ssam 
4929169Ssam 	if (unp2 == 0)
4939169Ssam 		return;
4949169Ssam 	unp->unp_conn = 0;
4959169Ssam 	switch (unp->unp_socket->so_type) {
4969169Ssam 
4979169Ssam 	case SOCK_DGRAM:
4989169Ssam 		if (unp2->unp_refs == unp)
4999169Ssam 			unp2->unp_refs = unp->unp_nextref;
5009169Ssam 		else {
5019169Ssam 			unp2 = unp2->unp_refs;
5029169Ssam 			for (;;) {
5039169Ssam 				if (unp2 == 0)
5049169Ssam 					panic("unp_disconnect");
5059169Ssam 				if (unp2->unp_nextref == unp)
5069169Ssam 					break;
5079169Ssam 				unp2 = unp2->unp_nextref;
5089169Ssam 			}
5099169Ssam 			unp2->unp_nextref = unp->unp_nextref;
5109169Ssam 		}
5119169Ssam 		unp->unp_nextref = 0;
51221768Skarels 		unp->unp_socket->so_state &= ~SS_ISCONNECTED;
5139169Ssam 		break;
5149169Ssam 
5159169Ssam 	case SOCK_STREAM:
51614049Ssam 		soisdisconnected(unp->unp_socket);
5179169Ssam 		unp2->unp_conn = 0;
5189169Ssam 		soisdisconnected(unp2->unp_socket);
5199169Ssam 		break;
5209169Ssam 	}
5219169Ssam }
5229169Ssam 
52312760Ssam #ifdef notdef
5249169Ssam unp_abort(unp)
5259169Ssam 	struct unpcb *unp;
5269169Ssam {
5279169Ssam 
5289169Ssam 	unp_detach(unp);
5299169Ssam }
53012760Ssam #endif
5319169Ssam 
532*68171Scgd void
53345004Skarels unp_shutdown(unp)
5349169Ssam 	struct unpcb *unp;
5359169Ssam {
53645004Skarels 	struct socket *so;
5379169Ssam 
53845004Skarels 	if (unp->unp_socket->so_type == SOCK_STREAM && unp->unp_conn &&
53945004Skarels 	    (so = unp->unp_conn->unp_socket))
54045004Skarels 		socantrcvmore(so);
5419169Ssam }
5429169Ssam 
543*68171Scgd void
5449169Ssam unp_drop(unp, errno)
5459169Ssam 	struct unpcb *unp;
5469169Ssam 	int errno;
5479169Ssam {
54816054Skarels 	struct socket *so = unp->unp_socket;
5499169Ssam 
55016054Skarels 	so->so_error = errno;
5519169Ssam 	unp_disconnect(unp);
55216054Skarels 	if (so->so_head) {
55316054Skarels 		so->so_pcb = (caddr_t) 0;
55425632Skarels 		m_freem(unp->unp_addr);
55516054Skarels 		(void) m_free(dtom(unp));
55616054Skarels 		sofree(so);
55716054Skarels 	}
5589169Ssam }
5599169Ssam 
56012760Ssam #ifdef notdef
5619169Ssam unp_drain()
5629169Ssam {
5639169Ssam 
5649169Ssam }
56512760Ssam #endif
56612760Ssam 
56712760Ssam unp_externalize(rights)
56812760Ssam 	struct mbuf *rights;
56912760Ssam {
57047540Skarels 	struct proc *p = curproc;		/* XXX */
57112760Ssam 	register int i;
57240800Ssklower 	register struct cmsghdr *cm = mtod(rights, struct cmsghdr *);
57340800Ssklower 	register struct file **rp = (struct file **)(cm + 1);
57412760Ssam 	register struct file *fp;
57540800Ssklower 	int newfds = (cm->cmsg_len - sizeof(*cm)) / sizeof (int);
57612760Ssam 	int f;
57712760Ssam 
57855090Spendry 	if (!fdavail(p, newfds)) {
57912760Ssam 		for (i = 0; i < newfds; i++) {
58012760Ssam 			fp = *rp;
58112760Ssam 			unp_discard(fp);
58212760Ssam 			*rp++ = 0;
58312760Ssam 		}
58412760Ssam 		return (EMSGSIZE);
58512760Ssam 	}
58612760Ssam 	for (i = 0; i < newfds; i++) {
58747540Skarels 		if (fdalloc(p, 0, &f))
58812760Ssam 			panic("unp_externalize");
58912760Ssam 		fp = *rp;
59047647Skarels 		p->p_fd->fd_ofiles[f] = fp;
59112760Ssam 		fp->f_msgcount--;
59225632Skarels 		unp_rights--;
59314927Smckusick 		*(int *)rp++ = f;
59412760Ssam 	}
59512760Ssam 	return (0);
59612760Ssam }
59712760Ssam 
59848022Smckusick unp_internalize(control, p)
59940937Skarels 	struct mbuf *control;
60048022Smckusick 	struct proc *p;
60112760Ssam {
60248022Smckusick 	struct filedesc *fdp = p->p_fd;
60340937Skarels 	register struct cmsghdr *cm = mtod(control, struct cmsghdr *);
60412760Ssam 	register struct file **rp;
60540937Skarels 	register struct file *fp;
60637728Smckusick 	register int i, fd;
60740937Skarels 	int oldfds;
60812760Ssam 
60940937Skarels 	if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||
61040937Skarels 	    cm->cmsg_len != control->m_len)
61140800Ssklower 		return (EINVAL);
61240800Ssklower 	oldfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int);
61340800Ssklower 	rp = (struct file **)(cm + 1);
61437728Smckusick 	for (i = 0; i < oldfds; i++) {
61537728Smckusick 		fd = *(int *)rp++;
61647647Skarels 		if ((unsigned)fd >= fdp->fd_nfiles ||
61747647Skarels 		    fdp->fd_ofiles[fd] == NULL)
61812760Ssam 			return (EBADF);
61937728Smckusick 	}
62040800Ssklower 	rp = (struct file **)(cm + 1);
62113084Ssam 	for (i = 0; i < oldfds; i++) {
62247647Skarels 		fp = fdp->fd_ofiles[*(int *)rp];
62312760Ssam 		*rp++ = fp;
62412760Ssam 		fp->f_count++;
62512760Ssam 		fp->f_msgcount++;
62625632Skarels 		unp_rights++;
62712760Ssam 	}
62812760Ssam 	return (0);
62912760Ssam }
63012760Ssam 
63112760Ssam int	unp_defer, unp_gcing;
63216995Skarels extern	struct domain unixdomain;
63312760Ssam 
634*68171Scgd void
63512760Ssam unp_gc()
63612760Ssam {
63753484Smckusick 	register struct file *fp, *nextfp;
63812760Ssam 	register struct socket *so;
63955665Smckusick 	struct file **extra_ref, **fpp;
64055665Smckusick 	int nunref, i;
64112760Ssam 
64212760Ssam 	if (unp_gcing)
64312760Ssam 		return;
64412760Ssam 	unp_gcing = 1;
64512760Ssam 	unp_defer = 0;
64667732Smckusick 	for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next)
64712760Ssam 		fp->f_flag &= ~(FMARK|FDEFER);
64812760Ssam 	do {
64967732Smckusick 		for (fp = filehead.lh_first; fp != 0; fp = fp->f_list.le_next) {
65012760Ssam 			if (fp->f_count == 0)
65112760Ssam 				continue;
65212760Ssam 			if (fp->f_flag & FDEFER) {
65312760Ssam 				fp->f_flag &= ~FDEFER;
65412760Ssam 				unp_defer--;
65512760Ssam 			} else {
65612760Ssam 				if (fp->f_flag & FMARK)
65712760Ssam 					continue;
65812760Ssam 				if (fp->f_count == fp->f_msgcount)
65912760Ssam 					continue;
66012760Ssam 				fp->f_flag |= FMARK;
66112760Ssam 			}
66237617Smckusick 			if (fp->f_type != DTYPE_SOCKET ||
66337617Smckusick 			    (so = (struct socket *)fp->f_data) == 0)
66412760Ssam 				continue;
66516995Skarels 			if (so->so_proto->pr_domain != &unixdomain ||
66621768Skarels 			    (so->so_proto->pr_flags&PR_RIGHTS) == 0)
66712760Ssam 				continue;
66845004Skarels #ifdef notdef
66912760Ssam 			if (so->so_rcv.sb_flags & SB_LOCK) {
67045004Skarels 				/*
67145004Skarels 				 * This is problematical; it's not clear
67245004Skarels 				 * we need to wait for the sockbuf to be
67345004Skarels 				 * unlocked (on a uniprocessor, at least),
67445004Skarels 				 * and it's also not clear what to do
67545004Skarels 				 * if sbwait returns an error due to receipt
67645004Skarels 				 * of a signal.  If sbwait does return
67745004Skarels 				 * an error, we'll go into an infinite
67845004Skarels 				 * loop.  Delete all of this for now.
67945004Skarels 				 */
68045004Skarels 				(void) sbwait(&so->so_rcv);
68112760Ssam 				goto restart;
68212760Ssam 			}
68345004Skarels #endif
68412760Ssam 			unp_scan(so->so_rcv.sb_mb, unp_mark);
68512760Ssam 		}
68612760Ssam 	} while (unp_defer);
68755665Smckusick 	/*
68855665Smckusick 	 * We grab an extra reference to each of the file table entries
68955665Smckusick 	 * that are not otherwise accessible and then free the rights
69055665Smckusick 	 * that are stored in messages on them.
69155665Smckusick 	 *
69255665Smckusick 	 * The bug in the orginal code is a little tricky, so I'll describe
69355665Smckusick 	 * what's wrong with it here.
69455665Smckusick 	 *
69555665Smckusick 	 * It is incorrect to simply unp_discard each entry for f_msgcount
69655665Smckusick 	 * times -- consider the case of sockets A and B that contain
69755665Smckusick 	 * references to each other.  On a last close of some other socket,
69855665Smckusick 	 * we trigger a gc since the number of outstanding rights (unp_rights)
69955665Smckusick 	 * is non-zero.  If during the sweep phase the gc code un_discards,
70055665Smckusick 	 * we end up doing a (full) closef on the descriptor.  A closef on A
70155665Smckusick 	 * results in the following chain.  Closef calls soo_close, which
70255665Smckusick 	 * calls soclose.   Soclose calls first (through the switch
70355665Smckusick 	 * uipc_usrreq) unp_detach, which re-invokes unp_gc.  Unp_gc simply
70455665Smckusick 	 * returns because the previous instance had set unp_gcing, and
70555665Smckusick 	 * we return all the way back to soclose, which marks the socket
70655665Smckusick 	 * with SS_NOFDREF, and then calls sofree.  Sofree calls sorflush
70755665Smckusick 	 * to free up the rights that are queued in messages on the socket A,
70855665Smckusick 	 * i.e., the reference on B.  The sorflush calls via the dom_dispose
70955665Smckusick 	 * switch unp_dispose, which unp_scans with unp_discard.  This second
71055665Smckusick 	 * instance of unp_discard just calls closef on B.
71155665Smckusick 	 *
71255665Smckusick 	 * Well, a similar chain occurs on B, resulting in a sorflush on B,
71355665Smckusick 	 * which results in another closef on A.  Unfortunately, A is already
71455665Smckusick 	 * being closed, and the descriptor has already been marked with
71555665Smckusick 	 * SS_NOFDREF, and soclose panics at this point.
71655665Smckusick 	 *
71755665Smckusick 	 * Here, we first take an extra reference to each inaccessible
71855665Smckusick 	 * descriptor.  Then, we call sorflush ourself, since we know
71955665Smckusick 	 * it is a Unix domain socket anyhow.  After we destroy all the
72055665Smckusick 	 * rights carried in messages, we do a last closef to get rid
72155665Smckusick 	 * of our extra reference.  This is the last close, and the
72255665Smckusick 	 * unp_detach etc will shut down the socket.
72355665Smckusick 	 *
72455665Smckusick 	 * 91/09/19, bsy@cs.cmu.edu
72555665Smckusick 	 */
72655665Smckusick 	extra_ref = malloc(nfiles * sizeof(struct file *), M_FILE, M_WAITOK);
72767732Smckusick 	for (nunref = 0, fp = filehead.lh_first, fpp = extra_ref; fp != 0;
72867732Smckusick 	    fp = nextfp) {
72967732Smckusick 		nextfp = fp->f_list.le_next;
73012760Ssam 		if (fp->f_count == 0)
73112760Ssam 			continue;
73255665Smckusick 		if (fp->f_count == fp->f_msgcount && !(fp->f_flag & FMARK)) {
73355665Smckusick 			*fpp++ = fp;
73455665Smckusick 			nunref++;
73555665Smckusick 			fp->f_count++;
73655665Smckusick 		}
73712760Ssam 	}
73855665Smckusick 	for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp)
73955665Smckusick 		sorflush((struct socket *)(*fpp)->f_data);
74055665Smckusick 	for (i = nunref, fpp = extra_ref; --i >= 0; ++fpp)
74155665Smckusick 		closef(*fpp);
74255665Smckusick 	free((caddr_t)extra_ref, M_FILE);
74312760Ssam 	unp_gcing = 0;
74412760Ssam }
74512760Ssam 
746*68171Scgd void
74716995Skarels unp_dispose(m)
74816995Skarels 	struct mbuf *m;
74916995Skarels {
75016995Skarels 
75117020Skarels 	if (m)
75217020Skarels 		unp_scan(m, unp_discard);
75316995Skarels }
75416995Skarels 
755*68171Scgd void
75616995Skarels unp_scan(m0, op)
75716995Skarels 	register struct mbuf *m0;
758*68171Scgd 	void (*op)();
75912760Ssam {
76016995Skarels 	register struct mbuf *m;
76112760Ssam 	register struct file **rp;
76240937Skarels 	register struct cmsghdr *cm;
76312760Ssam 	register int i;
76417020Skarels 	int qfds;
76512760Ssam 
76616995Skarels 	while (m0) {
76716995Skarels 		for (m = m0; m; m = m->m_next)
76840937Skarels 			if (m->m_type == MT_CONTROL &&
76940937Skarels 			    m->m_len >= sizeof(*cm)) {
77040800Ssklower 				cm = mtod(m, struct cmsghdr *);
77140937Skarels 				if (cm->cmsg_level != SOL_SOCKET ||
77240937Skarels 				    cm->cmsg_type != SCM_RIGHTS)
77340937Skarels 					continue;
77440800Ssklower 				qfds = (cm->cmsg_len - sizeof *cm)
77540800Ssklower 						/ sizeof (struct file *);
77640800Ssklower 				rp = (struct file **)(cm + 1);
77716995Skarels 				for (i = 0; i < qfds; i++)
77816995Skarels 					(*op)(*rp++);
77916995Skarels 				break;		/* XXX, but saves time */
78016995Skarels 			}
78117020Skarels 		m0 = m0->m_act;
78212760Ssam 	}
78312760Ssam }
78412760Ssam 
785*68171Scgd void
78612760Ssam unp_mark(fp)
78712760Ssam 	struct file *fp;
78812760Ssam {
78912760Ssam 
79012760Ssam 	if (fp->f_flag & FMARK)
79112760Ssam 		return;
79212760Ssam 	unp_defer++;
79312760Ssam 	fp->f_flag |= (FMARK|FDEFER);
79412760Ssam }
79512760Ssam 
796*68171Scgd void
79712760Ssam unp_discard(fp)
79812760Ssam 	struct file *fp;
79912760Ssam {
80012760Ssam 
80112760Ssam 	fp->f_msgcount--;
80225632Skarels 	unp_rights--;
80352033Skarels 	(void) closef(fp, (struct proc *)NULL);
80412760Ssam }
805