xref: /csrg-svn/sys/kern/uipc_usrreq.c (revision 16973)
1*16973Skarels /*	uipc_usrreq.c	6.7	84/08/20	*/
28925Sroot 
38925Sroot #include "../h/param.h"
48925Sroot #include "../h/dir.h"
58925Sroot #include "../h/user.h"
68925Sroot #include "../h/mbuf.h"
78925Sroot #include "../h/protosw.h"
88925Sroot #include "../h/socket.h"
98925Sroot #include "../h/socketvar.h"
108925Sroot #include "../h/unpcb.h"
118925Sroot #include "../h/un.h"
128925Sroot #include "../h/inode.h"
1312760Ssam #include "../h/file.h"
14*16973Skarels #include "../h/stat.h"
158925Sroot 
168925Sroot /*
178925Sroot  * Unix communications domain.
1812760Ssam  *
1912760Ssam  * TODO:
2012760Ssam  *	SEQPACKET, RDM
2113119Ssam  *	rethink name space problems
2212760Ssam  *	need a proper out-of-band
238925Sroot  */
2413119Ssam struct	sockaddr sun_noname = { AF_UNIX };
258925Sroot 
268925Sroot /*ARGSUSED*/
2712760Ssam uipc_usrreq(so, req, m, nam, rights)
288925Sroot 	struct socket *so;
298925Sroot 	int req;
3012760Ssam 	struct mbuf *m, *nam, *rights;
318925Sroot {
328925Sroot 	struct unpcb *unp = sotounpcb(so);
338925Sroot 	register struct socket *so2;
348925Sroot 	int error = 0;
358925Sroot 
3612760Ssam 	if (req != PRU_SEND && rights && rights->m_len) {
3712760Ssam 		error = EOPNOTSUPP;
3812760Ssam 		goto release;
3912760Ssam 	}
4012760Ssam 	if (unp == 0 && req != PRU_ATTACH) {
4112760Ssam 		error = EINVAL;
4212760Ssam 		goto release;
4312760Ssam 	}
448925Sroot 	switch (req) {
458925Sroot 
468925Sroot 	case PRU_ATTACH:
478925Sroot 		if (unp) {
489169Ssam 			error = EISCONN;
498925Sroot 			break;
508925Sroot 		}
519028Sroot 		error = unp_attach(so);
528925Sroot 		break;
538925Sroot 
548925Sroot 	case PRU_DETACH:
558925Sroot 		unp_detach(unp);
568925Sroot 		break;
578925Sroot 
589169Ssam 	case PRU_BIND:
599169Ssam 		error = unp_bind(unp, nam);
609169Ssam 		break;
619169Ssam 
629169Ssam 	case PRU_LISTEN:
639169Ssam 		if (unp->unp_inode == 0)
649169Ssam 			error = EINVAL;
659169Ssam 		break;
669169Ssam 
678925Sroot 	case PRU_CONNECT:
689028Sroot 		error = unp_connect(so, nam);
698925Sroot 		break;
708925Sroot 
7112760Ssam 	case PRU_CONNECT2:
7213115Ssam 		error = unp_connect2(so, (struct mbuf *)0,
7313115Ssam 		    (struct socket *)nam);
7412760Ssam 		break;
7512760Ssam 
768925Sroot 	case PRU_DISCONNECT:
778925Sroot 		unp_disconnect(unp);
788925Sroot 		break;
798925Sroot 
809169Ssam 	case PRU_ACCEPT:
819169Ssam 		nam->m_len = unp->unp_remaddr->m_len;
829169Ssam 		bcopy(mtod(unp->unp_remaddr, caddr_t),
839169Ssam 		    mtod(nam, caddr_t), (unsigned)nam->m_len);
848925Sroot 		break;
858925Sroot 
868925Sroot 	case PRU_SHUTDOWN:
878925Sroot 		socantsendmore(so);
888925Sroot 		unp_usrclosed(unp);
898925Sroot 		break;
908925Sroot 
918925Sroot 	case PRU_RCVD:
928925Sroot 		switch (so->so_type) {
938925Sroot 
948925Sroot 		case SOCK_DGRAM:
958925Sroot 			panic("uipc 1");
9610139Ssam 			/*NOTREACHED*/
978925Sroot 
9810139Ssam 		case SOCK_STREAM:
998925Sroot #define	rcv (&so->so_rcv)
1008925Sroot #define snd (&so2->so_snd)
1018925Sroot 			if (unp->unp_conn == 0)
1028925Sroot 				break;
1038925Sroot 			so2 = unp->unp_conn->unp_socket;
1048925Sroot 			/*
1058925Sroot 			 * Transfer resources back to send port
1068925Sroot 			 * and wakeup any waiting to write.
1078925Sroot 			 */
1088925Sroot 			snd->sb_mbmax += rcv->sb_mbmax - rcv->sb_mbcnt;
1098925Sroot 			rcv->sb_mbmax = rcv->sb_mbcnt;
1108925Sroot 			snd->sb_hiwat += rcv->sb_hiwat - rcv->sb_cc;
1118925Sroot 			rcv->sb_hiwat = rcv->sb_cc;
1128925Sroot 			sbwakeup(snd);
1138925Sroot #undef snd
1148925Sroot #undef rcv
1158925Sroot 			break;
1168925Sroot 
1178925Sroot 		default:
1188925Sroot 			panic("uipc 2");
1198925Sroot 		}
1208925Sroot 		break;
1218925Sroot 
1228925Sroot 	case PRU_SEND:
1238925Sroot 		switch (so->so_type) {
1248925Sroot 
1258925Sroot 		case SOCK_DGRAM:
1269028Sroot 			if (nam) {
1278925Sroot 				if (unp->unp_conn) {
1288925Sroot 					error = EISCONN;
1298925Sroot 					break;
1308925Sroot 				}
1319028Sroot 				error = unp_connect(so, nam);
1328925Sroot 				if (error)
1338925Sroot 					break;
1348925Sroot 			} else {
1358925Sroot 				if (unp->unp_conn == 0) {
1368925Sroot 					error = ENOTCONN;
1378925Sroot 					break;
1388925Sroot 				}
1398925Sroot 			}
1408925Sroot 			so2 = unp->unp_conn->unp_socket;
1419169Ssam 			/* BEGIN XXX */
14212760Ssam 			if (rights) {
14312760Ssam 				error = unp_internalize(rights);
14412760Ssam 				if (error)
14512760Ssam 					break;
14612760Ssam 			}
14712760Ssam 			if (sbspace(&so2->so_rcv) > 0) {
14813119Ssam 				/*
14913119Ssam 				 * There's no record of source socket's
15013119Ssam 				 * name, so send null name for the moment.
15113119Ssam 				 */
1529169Ssam 				(void) sbappendaddr(&so2->so_rcv,
15313119Ssam 				    &sun_noname, m, rights);
15412760Ssam 				sbwakeup(&so2->so_rcv);
15512760Ssam 				m = 0;
15612760Ssam 			}
1579169Ssam 			/* END XXX */
1589028Sroot 			if (nam)
1599169Ssam 				unp_disconnect(unp);
1608925Sroot 			break;
1618925Sroot 
1628925Sroot 		case SOCK_STREAM:
1638925Sroot #define	rcv (&so2->so_rcv)
1648925Sroot #define	snd (&so->so_snd)
16512760Ssam 			if (rights && rights->m_len) {
16612760Ssam 				error = EOPNOTSUPP;
16712760Ssam 				break;
16812760Ssam 			}
1698925Sroot 			if (unp->unp_conn == 0)
1708925Sroot 				panic("uipc 3");
1718925Sroot 			so2 = unp->unp_conn->unp_socket;
1728925Sroot 			/*
1738925Sroot 			 * Send to paired receive port, and then
1748925Sroot 			 * give it enough resources to hold what it already has.
1758925Sroot 			 * Wake up readers.
1768925Sroot 			 */
1778925Sroot 			sbappend(rcv, m);
1788925Sroot 			snd->sb_mbmax -= rcv->sb_mbcnt - rcv->sb_mbmax;
1798925Sroot 			rcv->sb_mbmax = rcv->sb_mbcnt;
1808925Sroot 			snd->sb_hiwat -= rcv->sb_cc - rcv->sb_hiwat;
1818925Sroot 			rcv->sb_hiwat = rcv->sb_cc;
1828925Sroot 			sbwakeup(rcv);
1838925Sroot #undef snd
1848925Sroot #undef rcv
1858925Sroot 			break;
1868925Sroot 
1878925Sroot 		default:
1888925Sroot 			panic("uipc 4");
1898925Sroot 		}
19012760Ssam 		m = 0;
1918925Sroot 		break;
1928925Sroot 
1938925Sroot 	case PRU_ABORT:
1948925Sroot 		unp_drop(unp, ECONNABORTED);
1958925Sroot 		break;
1968925Sroot 
1978925Sroot /* SOME AS YET UNIMPLEMENTED HOOKS */
1988925Sroot 	case PRU_CONTROL:
19913050Ssam 		return (EOPNOTSUPP);
2008925Sroot 
201*16973Skarels /* END UNIMPLEMENTED HOOKS */
2028925Sroot 	case PRU_SENSE:
203*16973Skarels 		((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
204*16973Skarels 		if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) {
205*16973Skarels 			so2 = unp->unp_conn->unp_socket;
206*16973Skarels 			((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc;
207*16973Skarels 		}
208*16973Skarels 		return (0);
2098925Sroot 
2108925Sroot 	case PRU_RCVOOB:
21116774Sbloom 		return (EOPNOTSUPP);
2128925Sroot 
2138925Sroot 	case PRU_SENDOOB:
2148925Sroot 		break;
2158925Sroot 
2168925Sroot 	case PRU_SOCKADDR:
2178925Sroot 		break;
2188925Sroot 
21914121Ssam 	case PRU_PEERADDR:
22014121Ssam 		break;
22114121Ssam 
2228925Sroot 	case PRU_SLOWTIMO:
2238925Sroot 		break;
2248925Sroot 
2258925Sroot 	default:
2268925Sroot 		panic("piusrreq");
2278925Sroot 	}
22812760Ssam release:
22912760Ssam 	if (m)
23012760Ssam 		m_freem(m);
23111709Ssam 	return (error);
2328925Sroot }
2338925Sroot 
234*16973Skarels /*
235*16973Skarels  * We assign all buffering for stream sockets to the source,
236*16973Skarels  * as that is where the flow control is implemented.
237*16973Skarels  * Datagram sockets really use the sendspace as the maximum datagram size,
238*16973Skarels  * and don't really want to reserve the sendspace.  Their recvspace should
239*16973Skarels  * be large enough for at least one max-size datagram plus address.
240*16973Skarels  */
241*16973Skarels #define	PIPSIZ	4096
242*16973Skarels int	unpst_sendspace = PIPSIZ;
243*16973Skarels int	unpst_recvspace = 0;
244*16973Skarels int	unpdg_sendspace = 2*1024;	/* really max datagram size */
245*16973Skarels int	unpdg_recvspace = 4*1024;
2468925Sroot 
2479169Ssam unp_attach(so)
2488925Sroot 	struct socket *so;
2498925Sroot {
2509169Ssam 	register struct mbuf *m;
2518925Sroot 	register struct unpcb *unp;
2528925Sroot 	int error;
2538925Sroot 
254*16973Skarels 	switch (so->so_type) {
255*16973Skarels 
256*16973Skarels 	case SOCK_STREAM:
257*16973Skarels 		error = soreserve(so, unpst_sendspace, unpst_recvspace);
258*16973Skarels 		break;
259*16973Skarels 
260*16973Skarels 	case SOCK_DGRAM:
261*16973Skarels 		error = soreserve(so, unpdg_sendspace, unpdg_recvspace);
262*16973Skarels 		break;
263*16973Skarels 	}
2648925Sroot 	if (error)
26510139Ssam 		return (error);
2669637Ssam 	m = m_getclr(M_DONTWAIT, MT_PCB);
26710139Ssam 	if (m == NULL)
26810139Ssam 		return (ENOBUFS);
2698925Sroot 	unp = mtod(m, struct unpcb *);
2708925Sroot 	so->so_pcb = (caddr_t)unp;
2718925Sroot 	unp->unp_socket = so;
2728925Sroot 	return (0);
2738925Sroot }
2748925Sroot 
2758925Sroot unp_detach(unp)
2769169Ssam 	register struct unpcb *unp;
2778925Sroot {
2788925Sroot 
2798925Sroot 	if (unp->unp_inode) {
2808925Sroot 		irele(unp->unp_inode);
2818925Sroot 		unp->unp_inode = 0;
2828925Sroot 	}
2838925Sroot 	if (unp->unp_conn)
2848925Sroot 		unp_disconnect(unp);
2858925Sroot 	while (unp->unp_refs)
2868925Sroot 		unp_drop(unp->unp_refs, ECONNRESET);
2878925Sroot 	soisdisconnected(unp->unp_socket);
2888925Sroot 	unp->unp_socket->so_pcb = 0;
2899169Ssam 	m_freem(unp->unp_remaddr);
2909169Ssam 	(void) m_free(dtom(unp));
2918925Sroot }
2928925Sroot 
2939169Ssam unp_bind(unp, nam)
2948925Sroot 	struct unpcb *unp;
2959169Ssam 	struct mbuf *nam;
2968925Sroot {
2979169Ssam 	struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
2988925Sroot 	register struct inode *ip;
29916695Smckusick 	register struct nameidata *ndp = &u.u_nd;
3008925Sroot 	int error;
3018925Sroot 
30216695Smckusick 	ndp->ni_dirp = soun->sun_path;
30312760Ssam 	if (nam->m_len == MLEN)
30412760Ssam 		return (EINVAL);
30512760Ssam 	*(mtod(nam, caddr_t) + nam->m_len) = 0;
30612760Ssam /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
30716695Smckusick 	ndp->ni_nameiop = CREATE | FOLLOW;
30816695Smckusick 	ndp->ni_segflg = UIO_SYSSPACE;
30916695Smckusick 	ip = namei(ndp);
3108925Sroot 	if (ip) {
3118925Sroot 		iput(ip);
31210139Ssam 		return (EADDRINUSE);
3138925Sroot 	}
31411828Ssam 	if (error = u.u_error) {
31511828Ssam 		u.u_error = 0;			/* XXX */
31611828Ssam 		return (error);
31711828Ssam 	}
31816695Smckusick 	ip = maknode(IFSOCK | 0777, ndp);
3198925Sroot 	if (ip == NULL) {
3208925Sroot 		error = u.u_error;		/* XXX */
3218925Sroot 		u.u_error = 0;			/* XXX */
3228925Sroot 		return (error);
3238925Sroot 	}
3248925Sroot 	ip->i_socket = unp->unp_socket;
3258925Sroot 	unp->unp_inode = ip;
3268925Sroot 	iunlock(ip);			/* but keep reference */
3278925Sroot 	return (0);
3288925Sroot }
3298925Sroot 
3309169Ssam unp_connect(so, nam)
3318925Sroot 	struct socket *so;
3329169Ssam 	struct mbuf *nam;
3338925Sroot {
3349169Ssam 	register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
3359169Ssam 	register struct inode *ip;
3368925Sroot 	int error;
33712760Ssam 	register struct socket *so2;
33816695Smckusick 	register struct nameidata *ndp = &u.u_nd;
3398925Sroot 
34016695Smckusick 	ndp->ni_dirp = soun->sun_path;
34112760Ssam 	if (nam->m_len + (nam->m_off - MMINOFF) == MLEN)
34212760Ssam 		return (EMSGSIZE);
34312760Ssam 	*(mtod(nam, caddr_t) + nam->m_len) = 0;
34416695Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
34516695Smckusick 	ndp->ni_segflg = UIO_SYSSPACE;
34616695Smckusick 	ip = namei(ndp);
3478925Sroot 	if (ip == 0) {
3488925Sroot 		error = u.u_error;
3498925Sroot 		u.u_error = 0;
35010139Ssam 		return (error);		/* XXX */
3518925Sroot 	}
3528925Sroot 	if ((ip->i_mode&IFMT) != IFSOCK) {
3538925Sroot 		error = ENOTSOCK;
3548925Sroot 		goto bad;
3558925Sroot 	}
3568925Sroot 	so2 = ip->i_socket;
3578925Sroot 	if (so2 == 0) {
3588925Sroot 		error = ECONNREFUSED;
3598925Sroot 		goto bad;
3608925Sroot 	}
36113115Ssam 	if (so->so_type != so2->so_type) {
36213115Ssam 		error = EPROTOTYPE;
36313115Ssam 		goto bad;
36413115Ssam 	}
36513115Ssam 	if (so->so_proto->pr_flags & PR_CONNREQUIRED &&
36613115Ssam 	    ((so2->so_options&SO_ACCEPTCONN) == 0 ||
36713115Ssam 	     (so2 = sonewconn(so2)) == 0)) {
36813115Ssam 		error = ECONNREFUSED;
36913115Ssam 		goto bad;
37013115Ssam 	}
37112760Ssam 	error = unp_connect2(so, nam, so2);
37212760Ssam bad:
37312760Ssam 	iput(ip);
37412760Ssam 	return (error);
37512760Ssam }
37612760Ssam 
37712760Ssam unp_connect2(so, sonam, so2)
37812760Ssam 	register struct socket *so;
37912760Ssam 	struct mbuf *sonam;
38012760Ssam 	register struct socket *so2;
38112760Ssam {
38212760Ssam 	register struct unpcb *unp = sotounpcb(so);
38312760Ssam 	register struct unpcb *unp2;
38412760Ssam 
38512760Ssam 	if (so2->so_type != so->so_type)
38612760Ssam 		return (EPROTOTYPE);
38714049Ssam 	unp2 = sotounpcb(so2);
38814049Ssam 	unp->unp_conn = unp2;
3898925Sroot 	switch (so->so_type) {
3908925Sroot 
3918925Sroot 	case SOCK_DGRAM:
3928925Sroot 		unp->unp_nextref = unp2->unp_refs;
3938925Sroot 		unp2->unp_refs = unp;
3948925Sroot 		break;
3958925Sroot 
3968925Sroot 	case SOCK_STREAM:
3979169Ssam 		unp2->unp_conn = unp;
39812760Ssam 		if (sonam)
39912760Ssam 			unp2->unp_remaddr = m_copy(sonam, 0, (int)M_COPYALL);
40014049Ssam 		soisconnected(so2);
40114049Ssam 		soisconnected(so);
4028925Sroot 		break;
4038925Sroot 
4048925Sroot 	default:
40512760Ssam 		panic("unp_connect2");
4068925Sroot 	}
4078925Sroot 	return (0);
4088925Sroot }
4099169Ssam 
4109169Ssam unp_disconnect(unp)
4119169Ssam 	struct unpcb *unp;
4129169Ssam {
4139169Ssam 	register struct unpcb *unp2 = unp->unp_conn;
4149169Ssam 
4159169Ssam 	if (unp2 == 0)
4169169Ssam 		return;
4179169Ssam 	unp->unp_conn = 0;
4189169Ssam 	switch (unp->unp_socket->so_type) {
4199169Ssam 
4209169Ssam 	case SOCK_DGRAM:
4219169Ssam 		if (unp2->unp_refs == unp)
4229169Ssam 			unp2->unp_refs = unp->unp_nextref;
4239169Ssam 		else {
4249169Ssam 			unp2 = unp2->unp_refs;
4259169Ssam 			for (;;) {
4269169Ssam 				if (unp2 == 0)
4279169Ssam 					panic("unp_disconnect");
4289169Ssam 				if (unp2->unp_nextref == unp)
4299169Ssam 					break;
4309169Ssam 				unp2 = unp2->unp_nextref;
4319169Ssam 			}
4329169Ssam 			unp2->unp_nextref = unp->unp_nextref;
4339169Ssam 		}
4349169Ssam 		unp->unp_nextref = 0;
4359169Ssam 		break;
4369169Ssam 
4379169Ssam 	case SOCK_STREAM:
43814049Ssam 		soisdisconnected(unp->unp_socket);
4399169Ssam 		unp2->unp_conn = 0;
4409169Ssam 		soisdisconnected(unp2->unp_socket);
4419169Ssam 		break;
4429169Ssam 	}
4439169Ssam }
4449169Ssam 
44512760Ssam #ifdef notdef
4469169Ssam unp_abort(unp)
4479169Ssam 	struct unpcb *unp;
4489169Ssam {
4499169Ssam 
4509169Ssam 	unp_detach(unp);
4519169Ssam }
45212760Ssam #endif
4539169Ssam 
4549169Ssam /*ARGSUSED*/
4559169Ssam unp_usrclosed(unp)
4569169Ssam 	struct unpcb *unp;
4579169Ssam {
4589169Ssam 
4599169Ssam }
4609169Ssam 
4619169Ssam unp_drop(unp, errno)
4629169Ssam 	struct unpcb *unp;
4639169Ssam 	int errno;
4649169Ssam {
46516054Skarels 	struct socket *so = unp->unp_socket;
4669169Ssam 
46716054Skarels 	so->so_error = errno;
4689169Ssam 	unp_disconnect(unp);
46916054Skarels 	if (so->so_head) {
47016054Skarels 		so->so_pcb = (caddr_t) 0;
47116431Skarels 		m_freem(unp->unp_remaddr);
47216054Skarels 		(void) m_free(dtom(unp));
47316054Skarels 		sofree(so);
47416054Skarels 	}
4759169Ssam }
4769169Ssam 
47712760Ssam #ifdef notdef
4789169Ssam unp_drain()
4799169Ssam {
4809169Ssam 
4819169Ssam }
48212760Ssam #endif
48312760Ssam 
48412760Ssam unp_externalize(rights)
48512760Ssam 	struct mbuf *rights;
48612760Ssam {
48712760Ssam 	int newfds = rights->m_len / sizeof (int);
48812760Ssam 	register int i;
48912760Ssam 	register struct file **rp = mtod(rights, struct file **);
49012760Ssam 	register struct file *fp;
49112760Ssam 	int f;
49212760Ssam 
49312760Ssam 	if (newfds > ufavail()) {
49412760Ssam 		for (i = 0; i < newfds; i++) {
49512760Ssam 			fp = *rp;
49612760Ssam 			unp_discard(fp);
49712760Ssam 			*rp++ = 0;
49812760Ssam 		}
49912760Ssam 		return (EMSGSIZE);
50012760Ssam 	}
50112760Ssam 	for (i = 0; i < newfds; i++) {
50212760Ssam 		f = ufalloc(0);
50312760Ssam 		if (f < 0)
50412760Ssam 			panic("unp_externalize");
50512760Ssam 		fp = *rp;
50612760Ssam 		u.u_ofile[f] = fp;
50712760Ssam 		fp->f_msgcount--;
50814927Smckusick 		*(int *)rp++ = f;
50912760Ssam 	}
51012760Ssam 	return (0);
51112760Ssam }
51212760Ssam 
51312760Ssam unp_internalize(rights)
51412760Ssam 	struct mbuf *rights;
51512760Ssam {
51612760Ssam 	register struct file **rp;
51712760Ssam 	int oldfds = rights->m_len / sizeof (int);
51812760Ssam 	register int i;
51912760Ssam 	register struct file *fp;
52012760Ssam 
52112760Ssam 	rp = mtod(rights, struct file **);
52213084Ssam 	for (i = 0; i < oldfds; i++)
52312760Ssam 		if (getf(*(int *)rp++) == 0)
52412760Ssam 			return (EBADF);
52512760Ssam 	rp = mtod(rights, struct file **);
52613084Ssam 	for (i = 0; i < oldfds; i++) {
52712760Ssam 		fp = getf(*(int *)rp);
52812760Ssam 		*rp++ = fp;
52912760Ssam 		fp->f_count++;
53012760Ssam 		fp->f_msgcount++;
53112760Ssam 	}
53212760Ssam 	return (0);
53312760Ssam }
53412760Ssam 
53512760Ssam int	unp_defer, unp_gcing;
53612760Ssam int	unp_mark();
53712760Ssam 
53812760Ssam unp_gc()
53912760Ssam {
54012760Ssam 	register struct file *fp;
54112760Ssam 	register struct socket *so;
54212760Ssam 
54312760Ssam 	if (unp_gcing)
54412760Ssam 		return;
54512760Ssam 	unp_gcing = 1;
54612760Ssam restart:
54712760Ssam 	unp_defer = 0;
54812760Ssam 	for (fp = file; fp < fileNFILE; fp++)
54912760Ssam 		fp->f_flag &= ~(FMARK|FDEFER);
55012760Ssam 	do {
55112760Ssam 		for (fp = file; fp < fileNFILE; fp++) {
55212760Ssam 			if (fp->f_count == 0)
55312760Ssam 				continue;
55412760Ssam 			if (fp->f_flag & FDEFER) {
55512760Ssam 				fp->f_flag &= ~FDEFER;
55612760Ssam 				unp_defer--;
55712760Ssam 			} else {
55812760Ssam 				if (fp->f_flag & FMARK)
55912760Ssam 					continue;
56012760Ssam 				if (fp->f_count == fp->f_msgcount)
56112760Ssam 					continue;
56212760Ssam 				fp->f_flag |= FMARK;
56312760Ssam 			}
56412760Ssam 			if (fp->f_type != DTYPE_SOCKET)
56512760Ssam 				continue;
56612760Ssam 			so = (struct socket *)fp->f_data;
56712760Ssam 			if (so->so_proto->pr_family != AF_UNIX ||
56812760Ssam 			    (so->so_proto->pr_flags&PR_ADDR) == 0)
56912760Ssam 				continue;
57012760Ssam 			if (so->so_rcv.sb_flags & SB_LOCK) {
57112760Ssam 				sbwait(&so->so_rcv);
57212760Ssam 				goto restart;
57312760Ssam 			}
57412760Ssam 			unp_scan(so->so_rcv.sb_mb, unp_mark);
57512760Ssam 		}
57612760Ssam 	} while (unp_defer);
57712760Ssam 	for (fp = file; fp < fileNFILE; fp++) {
57812760Ssam 		if (fp->f_count == 0)
57912760Ssam 			continue;
58012760Ssam 		if (fp->f_count == fp->f_msgcount && (fp->f_flag&FMARK)==0) {
58112760Ssam 			if (fp->f_type != DTYPE_SOCKET)
58212760Ssam 				panic("unp_gc");
58312760Ssam 			(void) soshutdown((struct socket *)fp->f_data, 0);
58412760Ssam 		}
58512760Ssam 	}
58612760Ssam 	unp_gcing = 0;
58712760Ssam }
58812760Ssam 
58912760Ssam unp_scan(m, op)
59012760Ssam 	register struct mbuf *m;
59112760Ssam 	int (*op)();
59212760Ssam {
59312760Ssam 	register struct file **rp;
59412760Ssam 	register int i;
59512760Ssam 	int qfds;
59612760Ssam 
59712760Ssam 	while (m) {
59812760Ssam 		m = m->m_next;
59912760Ssam 		if (m == 0)
60012760Ssam 			goto bad;
60112760Ssam 		if (m->m_len) {
60212760Ssam 			qfds = m->m_len / sizeof (struct file *);
60312760Ssam 			rp = mtod(m, struct file **);
60412760Ssam 			for (i = 0; i < qfds; i++)
60512760Ssam 				(*op)(*rp++);
60612760Ssam 		}
60712760Ssam 		do {
60812760Ssam 			m = m->m_next;
60912760Ssam 			if (m == 0)
61012760Ssam 				goto bad;
61112760Ssam 		} while (m->m_act == 0);
61212760Ssam 		m = m->m_next;
61312760Ssam 	}
61412760Ssam 	return;
61512760Ssam bad:
61612760Ssam 	panic("unp_gcscan");
61712760Ssam }
61812760Ssam 
61912760Ssam unp_mark(fp)
62012760Ssam 	struct file *fp;
62112760Ssam {
62212760Ssam 
62312760Ssam 	if (fp->f_flag & FMARK)
62412760Ssam 		return;
62512760Ssam 	unp_defer++;
62612760Ssam 	fp->f_flag |= (FMARK|FDEFER);
62712760Ssam }
62812760Ssam 
62912760Ssam unp_discard(fp)
63012760Ssam 	struct file *fp;
63112760Ssam {
63212760Ssam 
63312760Ssam 	fp->f_msgcount--;
63413084Ssam 	closef(fp);
63512760Ssam }
636