xref: /csrg-svn/sys/kern/uipc_usrreq.c (revision 17543)
1*17543Skarels /*	uipc_usrreq.c	6.11	84/12/20	*/
28925Sroot 
317105Sbloom #include "param.h"
417105Sbloom #include "dir.h"
517105Sbloom #include "user.h"
617105Sbloom #include "mbuf.h"
717105Sbloom #include "domain.h"
817105Sbloom #include "protosw.h"
917105Sbloom #include "socket.h"
1017105Sbloom #include "socketvar.h"
1117105Sbloom #include "unpcb.h"
1217105Sbloom #include "un.h"
1317105Sbloom #include "inode.h"
1417105Sbloom #include "file.h"
1517105Sbloom #include "stat.h"
168925Sroot 
178925Sroot /*
188925Sroot  * Unix communications domain.
1912760Ssam  *
2012760Ssam  * TODO:
2112760Ssam  *	SEQPACKET, RDM
2213119Ssam  *	rethink name space problems
2312760Ssam  *	need a proper out-of-band
248925Sroot  */
2513119Ssam struct	sockaddr sun_noname = { AF_UNIX };
268925Sroot 
278925Sroot /*ARGSUSED*/
2812760Ssam uipc_usrreq(so, req, m, nam, rights)
298925Sroot 	struct socket *so;
308925Sroot 	int req;
3112760Ssam 	struct mbuf *m, *nam, *rights;
328925Sroot {
338925Sroot 	struct unpcb *unp = sotounpcb(so);
348925Sroot 	register struct socket *so2;
358925Sroot 	int error = 0;
368925Sroot 
3712760Ssam 	if (req != PRU_SEND && rights && rights->m_len) {
3812760Ssam 		error = EOPNOTSUPP;
3912760Ssam 		goto release;
4012760Ssam 	}
4112760Ssam 	if (unp == 0 && req != PRU_ATTACH) {
4212760Ssam 		error = EINVAL;
4312760Ssam 		goto release;
4412760Ssam 	}
458925Sroot 	switch (req) {
468925Sroot 
478925Sroot 	case PRU_ATTACH:
488925Sroot 		if (unp) {
499169Ssam 			error = EISCONN;
508925Sroot 			break;
518925Sroot 		}
529028Sroot 		error = unp_attach(so);
538925Sroot 		break;
548925Sroot 
558925Sroot 	case PRU_DETACH:
568925Sroot 		unp_detach(unp);
578925Sroot 		break;
588925Sroot 
599169Ssam 	case PRU_BIND:
609169Ssam 		error = unp_bind(unp, nam);
619169Ssam 		break;
629169Ssam 
639169Ssam 	case PRU_LISTEN:
649169Ssam 		if (unp->unp_inode == 0)
659169Ssam 			error = EINVAL;
669169Ssam 		break;
679169Ssam 
688925Sroot 	case PRU_CONNECT:
699028Sroot 		error = unp_connect(so, nam);
708925Sroot 		break;
718925Sroot 
7212760Ssam 	case PRU_CONNECT2:
7313115Ssam 		error = unp_connect2(so, (struct mbuf *)0,
7413115Ssam 		    (struct socket *)nam);
7512760Ssam 		break;
7612760Ssam 
778925Sroot 	case PRU_DISCONNECT:
788925Sroot 		unp_disconnect(unp);
798925Sroot 		break;
808925Sroot 
819169Ssam 	case PRU_ACCEPT:
829169Ssam 		nam->m_len = unp->unp_remaddr->m_len;
839169Ssam 		bcopy(mtod(unp->unp_remaddr, caddr_t),
849169Ssam 		    mtod(nam, caddr_t), (unsigned)nam->m_len);
858925Sroot 		break;
868925Sroot 
878925Sroot 	case PRU_SHUTDOWN:
888925Sroot 		socantsendmore(so);
898925Sroot 		unp_usrclosed(unp);
908925Sroot 		break;
918925Sroot 
928925Sroot 	case PRU_RCVD:
938925Sroot 		switch (so->so_type) {
948925Sroot 
958925Sroot 		case SOCK_DGRAM:
968925Sroot 			panic("uipc 1");
9710139Ssam 			/*NOTREACHED*/
988925Sroot 
9910139Ssam 		case SOCK_STREAM:
1008925Sroot #define	rcv (&so->so_rcv)
1018925Sroot #define snd (&so2->so_snd)
1028925Sroot 			if (unp->unp_conn == 0)
1038925Sroot 				break;
1048925Sroot 			so2 = unp->unp_conn->unp_socket;
1058925Sroot 			/*
1068925Sroot 			 * Transfer resources back to send port
1078925Sroot 			 * and wakeup any waiting to write.
1088925Sroot 			 */
1098925Sroot 			snd->sb_mbmax += rcv->sb_mbmax - rcv->sb_mbcnt;
1108925Sroot 			rcv->sb_mbmax = rcv->sb_mbcnt;
1118925Sroot 			snd->sb_hiwat += rcv->sb_hiwat - rcv->sb_cc;
1128925Sroot 			rcv->sb_hiwat = rcv->sb_cc;
113*17543Skarels 			sowwakeup(so2);
1148925Sroot #undef snd
1158925Sroot #undef rcv
1168925Sroot 			break;
1178925Sroot 
1188925Sroot 		default:
1198925Sroot 			panic("uipc 2");
1208925Sroot 		}
1218925Sroot 		break;
1228925Sroot 
1238925Sroot 	case PRU_SEND:
1248925Sroot 		switch (so->so_type) {
1258925Sroot 
1268925Sroot 		case SOCK_DGRAM:
1279028Sroot 			if (nam) {
1288925Sroot 				if (unp->unp_conn) {
1298925Sroot 					error = EISCONN;
1308925Sroot 					break;
1318925Sroot 				}
1329028Sroot 				error = unp_connect(so, nam);
1338925Sroot 				if (error)
1348925Sroot 					break;
1358925Sroot 			} else {
1368925Sroot 				if (unp->unp_conn == 0) {
1378925Sroot 					error = ENOTCONN;
1388925Sroot 					break;
1398925Sroot 				}
1408925Sroot 			}
1418925Sroot 			so2 = unp->unp_conn->unp_socket;
1429169Ssam 			/* BEGIN XXX */
14312760Ssam 			if (rights) {
14412760Ssam 				error = unp_internalize(rights);
14512760Ssam 				if (error)
14612760Ssam 					break;
14712760Ssam 			}
14812760Ssam 			if (sbspace(&so2->so_rcv) > 0) {
14913119Ssam 				/*
15013119Ssam 				 * There's no record of source socket's
15113119Ssam 				 * name, so send null name for the moment.
15213119Ssam 				 */
153*17543Skarels 				if (sbappendaddr(&so2->so_rcv,
154*17543Skarels 				    &sun_noname, m, rights)) {
155*17543Skarels 					sorwakeup(so2);
156*17543Skarels 					m = 0;
157*17543Skarels 				}
15812760Ssam 			}
1599169Ssam 			/* END XXX */
1609028Sroot 			if (nam)
1619169Ssam 				unp_disconnect(unp);
1628925Sroot 			break;
1638925Sroot 
1648925Sroot 		case SOCK_STREAM:
1658925Sroot #define	rcv (&so2->so_rcv)
1668925Sroot #define	snd (&so->so_snd)
16712760Ssam 			if (rights && rights->m_len) {
16812760Ssam 				error = EOPNOTSUPP;
16912760Ssam 				break;
17012760Ssam 			}
1718925Sroot 			if (unp->unp_conn == 0)
1728925Sroot 				panic("uipc 3");
1738925Sroot 			so2 = unp->unp_conn->unp_socket;
1748925Sroot 			/*
1758925Sroot 			 * Send to paired receive port, and then
1768925Sroot 			 * give it enough resources to hold what it already has.
1778925Sroot 			 * Wake up readers.
1788925Sroot 			 */
1798925Sroot 			sbappend(rcv, m);
1808925Sroot 			snd->sb_mbmax -= rcv->sb_mbcnt - rcv->sb_mbmax;
1818925Sroot 			rcv->sb_mbmax = rcv->sb_mbcnt;
1828925Sroot 			snd->sb_hiwat -= rcv->sb_cc - rcv->sb_hiwat;
1838925Sroot 			rcv->sb_hiwat = rcv->sb_cc;
184*17543Skarels 			sorwakeup(so2);
185*17543Skarels 			m = 0;
1868925Sroot #undef snd
1878925Sroot #undef rcv
1888925Sroot 			break;
1898925Sroot 
1908925Sroot 		default:
1918925Sroot 			panic("uipc 4");
1928925Sroot 		}
1938925Sroot 		break;
1948925Sroot 
1958925Sroot 	case PRU_ABORT:
1968925Sroot 		unp_drop(unp, ECONNABORTED);
1978925Sroot 		break;
1988925Sroot 
1998925Sroot /* SOME AS YET UNIMPLEMENTED HOOKS */
2008925Sroot 	case PRU_CONTROL:
20113050Ssam 		return (EOPNOTSUPP);
2028925Sroot 
20316973Skarels /* END UNIMPLEMENTED HOOKS */
2048925Sroot 	case PRU_SENSE:
20516973Skarels 		((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
20616973Skarels 		if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) {
20716973Skarels 			so2 = unp->unp_conn->unp_socket;
20816973Skarels 			((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc;
20916973Skarels 		}
21016973Skarels 		return (0);
2118925Sroot 
2128925Sroot 	case PRU_RCVOOB:
21316774Sbloom 		return (EOPNOTSUPP);
2148925Sroot 
2158925Sroot 	case PRU_SENDOOB:
216*17543Skarels 		error = EOPNOTSUPP;
2178925Sroot 		break;
2188925Sroot 
2198925Sroot 	case PRU_SOCKADDR:
2208925Sroot 		break;
2218925Sroot 
22214121Ssam 	case PRU_PEERADDR:
22314121Ssam 		break;
22414121Ssam 
2258925Sroot 	case PRU_SLOWTIMO:
2268925Sroot 		break;
2278925Sroot 
2288925Sroot 	default:
2298925Sroot 		panic("piusrreq");
2308925Sroot 	}
23112760Ssam release:
23212760Ssam 	if (m)
23312760Ssam 		m_freem(m);
23411709Ssam 	return (error);
2358925Sroot }
2368925Sroot 
23716973Skarels /*
23816973Skarels  * We assign all buffering for stream sockets to the source,
23916973Skarels  * as that is where the flow control is implemented.
24016973Skarels  * Datagram sockets really use the sendspace as the maximum datagram size,
24116973Skarels  * and don't really want to reserve the sendspace.  Their recvspace should
24216973Skarels  * be large enough for at least one max-size datagram plus address.
24316973Skarels  */
24416973Skarels #define	PIPSIZ	4096
24516973Skarels int	unpst_sendspace = PIPSIZ;
24616973Skarels int	unpst_recvspace = 0;
24716973Skarels int	unpdg_sendspace = 2*1024;	/* really max datagram size */
24816973Skarels int	unpdg_recvspace = 4*1024;
2498925Sroot 
2509169Ssam unp_attach(so)
2518925Sroot 	struct socket *so;
2528925Sroot {
2539169Ssam 	register struct mbuf *m;
2548925Sroot 	register struct unpcb *unp;
2558925Sroot 	int error;
2568925Sroot 
25716973Skarels 	switch (so->so_type) {
25816973Skarels 
25916973Skarels 	case SOCK_STREAM:
26016973Skarels 		error = soreserve(so, unpst_sendspace, unpst_recvspace);
26116973Skarels 		break;
26216973Skarels 
26316973Skarels 	case SOCK_DGRAM:
26416973Skarels 		error = soreserve(so, unpdg_sendspace, unpdg_recvspace);
26516973Skarels 		break;
26616973Skarels 	}
2678925Sroot 	if (error)
26810139Ssam 		return (error);
2699637Ssam 	m = m_getclr(M_DONTWAIT, MT_PCB);
27010139Ssam 	if (m == NULL)
27110139Ssam 		return (ENOBUFS);
2728925Sroot 	unp = mtod(m, struct unpcb *);
2738925Sroot 	so->so_pcb = (caddr_t)unp;
2748925Sroot 	unp->unp_socket = so;
2758925Sroot 	return (0);
2768925Sroot }
2778925Sroot 
2788925Sroot unp_detach(unp)
2799169Ssam 	register struct unpcb *unp;
2808925Sroot {
2818925Sroot 
2828925Sroot 	if (unp->unp_inode) {
28317020Skarels 		unp->unp_inode->i_socket = 0;
2848925Sroot 		irele(unp->unp_inode);
2858925Sroot 		unp->unp_inode = 0;
2868925Sroot 	}
2878925Sroot 	if (unp->unp_conn)
2888925Sroot 		unp_disconnect(unp);
2898925Sroot 	while (unp->unp_refs)
2908925Sroot 		unp_drop(unp->unp_refs, ECONNRESET);
2918925Sroot 	soisdisconnected(unp->unp_socket);
2928925Sroot 	unp->unp_socket->so_pcb = 0;
2939169Ssam 	m_freem(unp->unp_remaddr);
2949169Ssam 	(void) m_free(dtom(unp));
2958925Sroot }
2968925Sroot 
2979169Ssam unp_bind(unp, nam)
2988925Sroot 	struct unpcb *unp;
2999169Ssam 	struct mbuf *nam;
3008925Sroot {
3019169Ssam 	struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
3028925Sroot 	register struct inode *ip;
30316695Smckusick 	register struct nameidata *ndp = &u.u_nd;
3048925Sroot 	int error;
3058925Sroot 
30616695Smckusick 	ndp->ni_dirp = soun->sun_path;
30712760Ssam 	if (nam->m_len == MLEN)
30812760Ssam 		return (EINVAL);
30912760Ssam 	*(mtod(nam, caddr_t) + nam->m_len) = 0;
31012760Ssam /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
31116695Smckusick 	ndp->ni_nameiop = CREATE | FOLLOW;
31216695Smckusick 	ndp->ni_segflg = UIO_SYSSPACE;
31316695Smckusick 	ip = namei(ndp);
3148925Sroot 	if (ip) {
3158925Sroot 		iput(ip);
31610139Ssam 		return (EADDRINUSE);
3178925Sroot 	}
31811828Ssam 	if (error = u.u_error) {
31911828Ssam 		u.u_error = 0;			/* XXX */
32011828Ssam 		return (error);
32111828Ssam 	}
32216695Smckusick 	ip = maknode(IFSOCK | 0777, ndp);
3238925Sroot 	if (ip == NULL) {
3248925Sroot 		error = u.u_error;		/* XXX */
3258925Sroot 		u.u_error = 0;			/* XXX */
3268925Sroot 		return (error);
3278925Sroot 	}
3288925Sroot 	ip->i_socket = unp->unp_socket;
3298925Sroot 	unp->unp_inode = ip;
3308925Sroot 	iunlock(ip);			/* but keep reference */
3318925Sroot 	return (0);
3328925Sroot }
3338925Sroot 
3349169Ssam unp_connect(so, nam)
3358925Sroot 	struct socket *so;
3369169Ssam 	struct mbuf *nam;
3378925Sroot {
3389169Ssam 	register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
3399169Ssam 	register struct inode *ip;
3408925Sroot 	int error;
34112760Ssam 	register struct socket *so2;
34216695Smckusick 	register struct nameidata *ndp = &u.u_nd;
3438925Sroot 
34416695Smckusick 	ndp->ni_dirp = soun->sun_path;
34512760Ssam 	if (nam->m_len + (nam->m_off - MMINOFF) == MLEN)
34612760Ssam 		return (EMSGSIZE);
34712760Ssam 	*(mtod(nam, caddr_t) + nam->m_len) = 0;
34816695Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
34916695Smckusick 	ndp->ni_segflg = UIO_SYSSPACE;
35016695Smckusick 	ip = namei(ndp);
3518925Sroot 	if (ip == 0) {
3528925Sroot 		error = u.u_error;
3538925Sroot 		u.u_error = 0;
35410139Ssam 		return (error);		/* XXX */
3558925Sroot 	}
356*17543Skarels 	if (access(ip, IWRITE)) {
357*17543Skarels 		error = u.u_error;
358*17543Skarels 		u.u_error = 0; 		/* XXX */
359*17543Skarels 		goto bad;
360*17543Skarels 	}
3618925Sroot 	if ((ip->i_mode&IFMT) != IFSOCK) {
3628925Sroot 		error = ENOTSOCK;
3638925Sroot 		goto bad;
3648925Sroot 	}
3658925Sroot 	so2 = ip->i_socket;
3668925Sroot 	if (so2 == 0) {
3678925Sroot 		error = ECONNREFUSED;
3688925Sroot 		goto bad;
3698925Sroot 	}
37013115Ssam 	if (so->so_type != so2->so_type) {
37113115Ssam 		error = EPROTOTYPE;
37213115Ssam 		goto bad;
37313115Ssam 	}
37413115Ssam 	if (so->so_proto->pr_flags & PR_CONNREQUIRED &&
37513115Ssam 	    ((so2->so_options&SO_ACCEPTCONN) == 0 ||
37613115Ssam 	     (so2 = sonewconn(so2)) == 0)) {
37713115Ssam 		error = ECONNREFUSED;
37813115Ssam 		goto bad;
37913115Ssam 	}
38012760Ssam 	error = unp_connect2(so, nam, so2);
38112760Ssam bad:
38212760Ssam 	iput(ip);
38312760Ssam 	return (error);
38412760Ssam }
38512760Ssam 
38612760Ssam unp_connect2(so, sonam, so2)
38712760Ssam 	register struct socket *so;
38812760Ssam 	struct mbuf *sonam;
38912760Ssam 	register struct socket *so2;
39012760Ssam {
39112760Ssam 	register struct unpcb *unp = sotounpcb(so);
39212760Ssam 	register struct unpcb *unp2;
39312760Ssam 
39412760Ssam 	if (so2->so_type != so->so_type)
39512760Ssam 		return (EPROTOTYPE);
39614049Ssam 	unp2 = sotounpcb(so2);
39714049Ssam 	unp->unp_conn = unp2;
3988925Sroot 	switch (so->so_type) {
3998925Sroot 
4008925Sroot 	case SOCK_DGRAM:
4018925Sroot 		unp->unp_nextref = unp2->unp_refs;
4028925Sroot 		unp2->unp_refs = unp;
403*17543Skarels 		soisconnected(so);
4048925Sroot 		break;
4058925Sroot 
4068925Sroot 	case SOCK_STREAM:
4079169Ssam 		unp2->unp_conn = unp;
40812760Ssam 		if (sonam)
40912760Ssam 			unp2->unp_remaddr = m_copy(sonam, 0, (int)M_COPYALL);
41014049Ssam 		soisconnected(so2);
41114049Ssam 		soisconnected(so);
4128925Sroot 		break;
4138925Sroot 
4148925Sroot 	default:
41512760Ssam 		panic("unp_connect2");
4168925Sroot 	}
4178925Sroot 	return (0);
4188925Sroot }
4199169Ssam 
4209169Ssam unp_disconnect(unp)
4219169Ssam 	struct unpcb *unp;
4229169Ssam {
4239169Ssam 	register struct unpcb *unp2 = unp->unp_conn;
4249169Ssam 
4259169Ssam 	if (unp2 == 0)
4269169Ssam 		return;
4279169Ssam 	unp->unp_conn = 0;
4289169Ssam 	switch (unp->unp_socket->so_type) {
4299169Ssam 
4309169Ssam 	case SOCK_DGRAM:
4319169Ssam 		if (unp2->unp_refs == unp)
4329169Ssam 			unp2->unp_refs = unp->unp_nextref;
4339169Ssam 		else {
4349169Ssam 			unp2 = unp2->unp_refs;
4359169Ssam 			for (;;) {
4369169Ssam 				if (unp2 == 0)
4379169Ssam 					panic("unp_disconnect");
4389169Ssam 				if (unp2->unp_nextref == unp)
4399169Ssam 					break;
4409169Ssam 				unp2 = unp2->unp_nextref;
4419169Ssam 			}
4429169Ssam 			unp2->unp_nextref = unp->unp_nextref;
4439169Ssam 		}
4449169Ssam 		unp->unp_nextref = 0;
4459169Ssam 		break;
4469169Ssam 
4479169Ssam 	case SOCK_STREAM:
44814049Ssam 		soisdisconnected(unp->unp_socket);
4499169Ssam 		unp2->unp_conn = 0;
4509169Ssam 		soisdisconnected(unp2->unp_socket);
4519169Ssam 		break;
4529169Ssam 	}
4539169Ssam }
4549169Ssam 
45512760Ssam #ifdef notdef
4569169Ssam unp_abort(unp)
4579169Ssam 	struct unpcb *unp;
4589169Ssam {
4599169Ssam 
4609169Ssam 	unp_detach(unp);
4619169Ssam }
46212760Ssam #endif
4639169Ssam 
4649169Ssam /*ARGSUSED*/
4659169Ssam unp_usrclosed(unp)
4669169Ssam 	struct unpcb *unp;
4679169Ssam {
4689169Ssam 
4699169Ssam }
4709169Ssam 
4719169Ssam unp_drop(unp, errno)
4729169Ssam 	struct unpcb *unp;
4739169Ssam 	int errno;
4749169Ssam {
47516054Skarels 	struct socket *so = unp->unp_socket;
4769169Ssam 
47716054Skarels 	so->so_error = errno;
4789169Ssam 	unp_disconnect(unp);
47916054Skarels 	if (so->so_head) {
48016054Skarels 		so->so_pcb = (caddr_t) 0;
48116431Skarels 		m_freem(unp->unp_remaddr);
48216054Skarels 		(void) m_free(dtom(unp));
48316054Skarels 		sofree(so);
48416054Skarels 	}
4859169Ssam }
4869169Ssam 
48712760Ssam #ifdef notdef
4889169Ssam unp_drain()
4899169Ssam {
4909169Ssam 
4919169Ssam }
49212760Ssam #endif
49312760Ssam 
49412760Ssam unp_externalize(rights)
49512760Ssam 	struct mbuf *rights;
49612760Ssam {
49712760Ssam 	int newfds = rights->m_len / sizeof (int);
49812760Ssam 	register int i;
49912760Ssam 	register struct file **rp = mtod(rights, struct file **);
50012760Ssam 	register struct file *fp;
50112760Ssam 	int f;
50212760Ssam 
50312760Ssam 	if (newfds > ufavail()) {
50412760Ssam 		for (i = 0; i < newfds; i++) {
50512760Ssam 			fp = *rp;
50612760Ssam 			unp_discard(fp);
50712760Ssam 			*rp++ = 0;
50812760Ssam 		}
50912760Ssam 		return (EMSGSIZE);
51012760Ssam 	}
51112760Ssam 	for (i = 0; i < newfds; i++) {
51212760Ssam 		f = ufalloc(0);
51312760Ssam 		if (f < 0)
51412760Ssam 			panic("unp_externalize");
51512760Ssam 		fp = *rp;
51612760Ssam 		u.u_ofile[f] = fp;
51712760Ssam 		fp->f_msgcount--;
51814927Smckusick 		*(int *)rp++ = f;
51912760Ssam 	}
52012760Ssam 	return (0);
52112760Ssam }
52212760Ssam 
52312760Ssam unp_internalize(rights)
52412760Ssam 	struct mbuf *rights;
52512760Ssam {
52612760Ssam 	register struct file **rp;
52712760Ssam 	int oldfds = rights->m_len / sizeof (int);
52812760Ssam 	register int i;
52912760Ssam 	register struct file *fp;
53012760Ssam 
53112760Ssam 	rp = mtod(rights, struct file **);
53213084Ssam 	for (i = 0; i < oldfds; i++)
53312760Ssam 		if (getf(*(int *)rp++) == 0)
53412760Ssam 			return (EBADF);
53512760Ssam 	rp = mtod(rights, struct file **);
53613084Ssam 	for (i = 0; i < oldfds; i++) {
53712760Ssam 		fp = getf(*(int *)rp);
53812760Ssam 		*rp++ = fp;
53912760Ssam 		fp->f_count++;
54012760Ssam 		fp->f_msgcount++;
54112760Ssam 	}
54212760Ssam 	return (0);
54312760Ssam }
54412760Ssam 
54512760Ssam int	unp_defer, unp_gcing;
54612760Ssam int	unp_mark();
54716995Skarels extern	struct domain unixdomain;
54812760Ssam 
54912760Ssam unp_gc()
55012760Ssam {
55112760Ssam 	register struct file *fp;
55212760Ssam 	register struct socket *so;
55312760Ssam 
55412760Ssam 	if (unp_gcing)
55512760Ssam 		return;
55612760Ssam 	unp_gcing = 1;
55712760Ssam restart:
55812760Ssam 	unp_defer = 0;
55912760Ssam 	for (fp = file; fp < fileNFILE; fp++)
56012760Ssam 		fp->f_flag &= ~(FMARK|FDEFER);
56112760Ssam 	do {
56212760Ssam 		for (fp = file; fp < fileNFILE; fp++) {
56312760Ssam 			if (fp->f_count == 0)
56412760Ssam 				continue;
56512760Ssam 			if (fp->f_flag & FDEFER) {
56612760Ssam 				fp->f_flag &= ~FDEFER;
56712760Ssam 				unp_defer--;
56812760Ssam 			} else {
56912760Ssam 				if (fp->f_flag & FMARK)
57012760Ssam 					continue;
57112760Ssam 				if (fp->f_count == fp->f_msgcount)
57212760Ssam 					continue;
57312760Ssam 				fp->f_flag |= FMARK;
57412760Ssam 			}
57512760Ssam 			if (fp->f_type != DTYPE_SOCKET)
57612760Ssam 				continue;
57712760Ssam 			so = (struct socket *)fp->f_data;
57816995Skarels 			if (so->so_proto->pr_domain != &unixdomain ||
57912760Ssam 			    (so->so_proto->pr_flags&PR_ADDR) == 0)
58012760Ssam 				continue;
58112760Ssam 			if (so->so_rcv.sb_flags & SB_LOCK) {
58212760Ssam 				sbwait(&so->so_rcv);
58312760Ssam 				goto restart;
58412760Ssam 			}
58512760Ssam 			unp_scan(so->so_rcv.sb_mb, unp_mark);
58612760Ssam 		}
58712760Ssam 	} while (unp_defer);
58812760Ssam 	for (fp = file; fp < fileNFILE; fp++) {
58912760Ssam 		if (fp->f_count == 0)
59012760Ssam 			continue;
59112760Ssam 		if (fp->f_count == fp->f_msgcount && (fp->f_flag&FMARK)==0) {
59212760Ssam 			if (fp->f_type != DTYPE_SOCKET)
59312760Ssam 				panic("unp_gc");
59412760Ssam 			(void) soshutdown((struct socket *)fp->f_data, 0);
59512760Ssam 		}
59612760Ssam 	}
59712760Ssam 	unp_gcing = 0;
59812760Ssam }
59912760Ssam 
60016995Skarels unp_dispose(m)
60116995Skarels 	struct mbuf *m;
60216995Skarels {
60316995Skarels 	int unp_discard();
60416995Skarels 
60517020Skarels 	if (m)
60617020Skarels 		unp_scan(m, unp_discard);
60716995Skarels }
60816995Skarels 
60916995Skarels unp_scan(m0, op)
61016995Skarels 	register struct mbuf *m0;
61112760Ssam 	int (*op)();
61212760Ssam {
61316995Skarels 	register struct mbuf *m;
61412760Ssam 	register struct file **rp;
61512760Ssam 	register int i;
61617020Skarels 	int qfds;
61712760Ssam 
61816995Skarels 	while (m0) {
61916995Skarels 		for (m = m0; m; m = m->m_next)
62016995Skarels 			if (m->m_type == MT_RIGHTS && m->m_len) {
62116995Skarels 				qfds = m->m_len / sizeof (struct file *);
62216995Skarels 				rp = mtod(m, struct file **);
62316995Skarels 				for (i = 0; i < qfds; i++)
62416995Skarels 					(*op)(*rp++);
62516995Skarels 				break;		/* XXX, but saves time */
62616995Skarels 			}
62717020Skarels 		m0 = m0->m_act;
62812760Ssam 	}
62912760Ssam }
63012760Ssam 
63112760Ssam unp_mark(fp)
63212760Ssam 	struct file *fp;
63312760Ssam {
63412760Ssam 
63512760Ssam 	if (fp->f_flag & FMARK)
63612760Ssam 		return;
63712760Ssam 	unp_defer++;
63812760Ssam 	fp->f_flag |= (FMARK|FDEFER);
63912760Ssam }
64012760Ssam 
64112760Ssam unp_discard(fp)
64212760Ssam 	struct file *fp;
64312760Ssam {
64412760Ssam 
64512760Ssam 	fp->f_msgcount--;
64613084Ssam 	closef(fp);
64712760Ssam }
648