xref: /csrg-svn/sys/kern/uipc_usrreq.c (revision 16695)
1*16695Smckusick /*	uipc_usrreq.c	6.5	84/07/08	*/
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"
148925Sroot 
158925Sroot /*
168925Sroot  * Unix communications domain.
1712760Ssam  *
1812760Ssam  * TODO:
1912760Ssam  *	SEQPACKET, RDM
2013119Ssam  *	rethink name space problems
2112760Ssam  *	need a proper out-of-band
228925Sroot  */
2313119Ssam struct	sockaddr sun_noname = { AF_UNIX };
248925Sroot 
258925Sroot /*ARGSUSED*/
2612760Ssam uipc_usrreq(so, req, m, nam, rights)
278925Sroot 	struct socket *so;
288925Sroot 	int req;
2912760Ssam 	struct mbuf *m, *nam, *rights;
308925Sroot {
318925Sroot 	struct unpcb *unp = sotounpcb(so);
328925Sroot 	register struct socket *so2;
338925Sroot 	int error = 0;
348925Sroot 
3512760Ssam 	if (req != PRU_SEND && rights && rights->m_len) {
3612760Ssam 		error = EOPNOTSUPP;
3712760Ssam 		goto release;
3812760Ssam 	}
3912760Ssam 	if (unp == 0 && req != PRU_ATTACH) {
4012760Ssam 		error = EINVAL;
4112760Ssam 		goto release;
4212760Ssam 	}
438925Sroot 	switch (req) {
448925Sroot 
458925Sroot 	case PRU_ATTACH:
468925Sroot 		if (unp) {
479169Ssam 			error = EISCONN;
488925Sroot 			break;
498925Sroot 		}
509028Sroot 		error = unp_attach(so);
518925Sroot 		break;
528925Sroot 
538925Sroot 	case PRU_DETACH:
548925Sroot 		unp_detach(unp);
558925Sroot 		break;
568925Sroot 
579169Ssam 	case PRU_BIND:
589169Ssam 		error = unp_bind(unp, nam);
599169Ssam 		break;
609169Ssam 
619169Ssam 	case PRU_LISTEN:
629169Ssam 		if (unp->unp_inode == 0)
639169Ssam 			error = EINVAL;
649169Ssam 		break;
659169Ssam 
668925Sroot 	case PRU_CONNECT:
679028Sroot 		error = unp_connect(so, nam);
688925Sroot 		break;
698925Sroot 
7012760Ssam 	case PRU_CONNECT2:
7113115Ssam 		error = unp_connect2(so, (struct mbuf *)0,
7213115Ssam 		    (struct socket *)nam);
7312760Ssam 		break;
7412760Ssam 
758925Sroot 	case PRU_DISCONNECT:
768925Sroot 		unp_disconnect(unp);
778925Sroot 		break;
788925Sroot 
799169Ssam 	case PRU_ACCEPT:
809169Ssam 		nam->m_len = unp->unp_remaddr->m_len;
819169Ssam 		bcopy(mtod(unp->unp_remaddr, caddr_t),
829169Ssam 		    mtod(nam, caddr_t), (unsigned)nam->m_len);
838925Sroot 		break;
848925Sroot 
858925Sroot 	case PRU_SHUTDOWN:
868925Sroot 		socantsendmore(so);
878925Sroot 		unp_usrclosed(unp);
888925Sroot 		break;
898925Sroot 
908925Sroot 	case PRU_RCVD:
918925Sroot 		switch (so->so_type) {
928925Sroot 
938925Sroot 		case SOCK_DGRAM:
948925Sroot 			panic("uipc 1");
9510139Ssam 			/*NOTREACHED*/
968925Sroot 
9710139Ssam 		case SOCK_STREAM:
988925Sroot #define	rcv (&so->so_rcv)
998925Sroot #define snd (&so2->so_snd)
1008925Sroot 			if (unp->unp_conn == 0)
1018925Sroot 				break;
1028925Sroot 			so2 = unp->unp_conn->unp_socket;
1038925Sroot 			/*
1048925Sroot 			 * Transfer resources back to send port
1058925Sroot 			 * and wakeup any waiting to write.
1068925Sroot 			 */
1078925Sroot 			snd->sb_mbmax += rcv->sb_mbmax - rcv->sb_mbcnt;
1088925Sroot 			rcv->sb_mbmax = rcv->sb_mbcnt;
1098925Sroot 			snd->sb_hiwat += rcv->sb_hiwat - rcv->sb_cc;
1108925Sroot 			rcv->sb_hiwat = rcv->sb_cc;
1118925Sroot 			sbwakeup(snd);
1128925Sroot #undef snd
1138925Sroot #undef rcv
1148925Sroot 			break;
1158925Sroot 
1168925Sroot 		default:
1178925Sroot 			panic("uipc 2");
1188925Sroot 		}
1198925Sroot 		break;
1208925Sroot 
1218925Sroot 	case PRU_SEND:
1228925Sroot 		switch (so->so_type) {
1238925Sroot 
1248925Sroot 		case SOCK_DGRAM:
1259028Sroot 			if (nam) {
1268925Sroot 				if (unp->unp_conn) {
1278925Sroot 					error = EISCONN;
1288925Sroot 					break;
1298925Sroot 				}
1309028Sroot 				error = unp_connect(so, nam);
1318925Sroot 				if (error)
1328925Sroot 					break;
1338925Sroot 			} else {
1348925Sroot 				if (unp->unp_conn == 0) {
1358925Sroot 					error = ENOTCONN;
1368925Sroot 					break;
1378925Sroot 				}
1388925Sroot 			}
1398925Sroot 			so2 = unp->unp_conn->unp_socket;
1409169Ssam 			/* BEGIN XXX */
14112760Ssam 			if (rights) {
14212760Ssam 				error = unp_internalize(rights);
14312760Ssam 				if (error)
14412760Ssam 					break;
14512760Ssam 			}
14612760Ssam 			if (sbspace(&so2->so_rcv) > 0) {
14713119Ssam 				/*
14813119Ssam 				 * There's no record of source socket's
14913119Ssam 				 * name, so send null name for the moment.
15013119Ssam 				 */
1519169Ssam 				(void) sbappendaddr(&so2->so_rcv,
15213119Ssam 				    &sun_noname, m, rights);
15312760Ssam 				sbwakeup(&so2->so_rcv);
15412760Ssam 				m = 0;
15512760Ssam 			}
1569169Ssam 			/* END XXX */
1579028Sroot 			if (nam)
1589169Ssam 				unp_disconnect(unp);
1598925Sroot 			break;
1608925Sroot 
1618925Sroot 		case SOCK_STREAM:
1628925Sroot #define	rcv (&so2->so_rcv)
1638925Sroot #define	snd (&so->so_snd)
16412760Ssam 			if (rights && rights->m_len) {
16512760Ssam 				error = EOPNOTSUPP;
16612760Ssam 				break;
16712760Ssam 			}
1688925Sroot 			if (unp->unp_conn == 0)
1698925Sroot 				panic("uipc 3");
1708925Sroot 			so2 = unp->unp_conn->unp_socket;
1718925Sroot 			/*
1728925Sroot 			 * Send to paired receive port, and then
1738925Sroot 			 * give it enough resources to hold what it already has.
1748925Sroot 			 * Wake up readers.
1758925Sroot 			 */
1768925Sroot 			sbappend(rcv, m);
1778925Sroot 			snd->sb_mbmax -= rcv->sb_mbcnt - rcv->sb_mbmax;
1788925Sroot 			rcv->sb_mbmax = rcv->sb_mbcnt;
1798925Sroot 			snd->sb_hiwat -= rcv->sb_cc - rcv->sb_hiwat;
1808925Sroot 			rcv->sb_hiwat = rcv->sb_cc;
1818925Sroot 			sbwakeup(rcv);
1828925Sroot #undef snd
1838925Sroot #undef rcv
1848925Sroot 			break;
1858925Sroot 
1868925Sroot 		default:
1878925Sroot 			panic("uipc 4");
1888925Sroot 		}
18912760Ssam 		m = 0;
1908925Sroot 		break;
1918925Sroot 
1928925Sroot 	case PRU_ABORT:
1938925Sroot 		unp_drop(unp, ECONNABORTED);
1948925Sroot 		break;
1958925Sroot 
1968925Sroot /* SOME AS YET UNIMPLEMENTED HOOKS */
1978925Sroot 	case PRU_CONTROL:
19813050Ssam 		return (EOPNOTSUPP);
1998925Sroot 
2008925Sroot 	case PRU_SENSE:
2018925Sroot 		error = EOPNOTSUPP;
2028925Sroot 		break;
2038925Sroot /* END UNIMPLEMENTED HOOKS */
2048925Sroot 
2058925Sroot 	case PRU_RCVOOB:
2068925Sroot 		break;
2078925Sroot 
2088925Sroot 	case PRU_SENDOOB:
2098925Sroot 		break;
2108925Sroot 
2118925Sroot 	case PRU_SOCKADDR:
2128925Sroot 		break;
2138925Sroot 
21414121Ssam 	case PRU_PEERADDR:
21514121Ssam 		break;
21614121Ssam 
2178925Sroot 	case PRU_SLOWTIMO:
2188925Sroot 		break;
2198925Sroot 
2208925Sroot 	default:
2218925Sroot 		panic("piusrreq");
2228925Sroot 	}
22312760Ssam release:
22412760Ssam 	if (m)
22512760Ssam 		m_freem(m);
22611709Ssam 	return (error);
2278925Sroot }
2288925Sroot 
22912760Ssam /* SHOULD BE PIPSIZ and 0 */
2308925Sroot int	unp_sendspace = 1024*2;
23116054Skarels int	unp_recvspace = 1024*2 + sizeof(struct sockaddr);
2328925Sroot 
2339169Ssam unp_attach(so)
2348925Sroot 	struct socket *so;
2358925Sroot {
2369169Ssam 	register struct mbuf *m;
2378925Sroot 	register struct unpcb *unp;
2388925Sroot 	int error;
2398925Sroot 
2408925Sroot 	error = soreserve(so, unp_sendspace, unp_recvspace);
2418925Sroot 	if (error)
24210139Ssam 		return (error);
2439637Ssam 	m = m_getclr(M_DONTWAIT, MT_PCB);
24410139Ssam 	if (m == NULL)
24510139Ssam 		return (ENOBUFS);
2468925Sroot 	unp = mtod(m, struct unpcb *);
2478925Sroot 	so->so_pcb = (caddr_t)unp;
2488925Sroot 	unp->unp_socket = so;
2498925Sroot 	return (0);
2508925Sroot }
2518925Sroot 
2528925Sroot unp_detach(unp)
2539169Ssam 	register struct unpcb *unp;
2548925Sroot {
2558925Sroot 
2568925Sroot 	if (unp->unp_inode) {
2578925Sroot 		irele(unp->unp_inode);
2588925Sroot 		unp->unp_inode = 0;
2598925Sroot 	}
2608925Sroot 	if (unp->unp_conn)
2618925Sroot 		unp_disconnect(unp);
2628925Sroot 	while (unp->unp_refs)
2638925Sroot 		unp_drop(unp->unp_refs, ECONNRESET);
2648925Sroot 	soisdisconnected(unp->unp_socket);
2658925Sroot 	unp->unp_socket->so_pcb = 0;
2669169Ssam 	m_freem(unp->unp_remaddr);
2679169Ssam 	(void) m_free(dtom(unp));
2688925Sroot }
2698925Sroot 
2709169Ssam unp_bind(unp, nam)
2718925Sroot 	struct unpcb *unp;
2729169Ssam 	struct mbuf *nam;
2738925Sroot {
2749169Ssam 	struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
2758925Sroot 	register struct inode *ip;
276*16695Smckusick 	register struct nameidata *ndp = &u.u_nd;
2778925Sroot 	int error;
2788925Sroot 
279*16695Smckusick 	ndp->ni_dirp = soun->sun_path;
28012760Ssam 	if (nam->m_len == MLEN)
28112760Ssam 		return (EINVAL);
28212760Ssam 	*(mtod(nam, caddr_t) + nam->m_len) = 0;
28312760Ssam /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
284*16695Smckusick 	ndp->ni_nameiop = CREATE | FOLLOW;
285*16695Smckusick 	ndp->ni_segflg = UIO_SYSSPACE;
286*16695Smckusick 	ip = namei(ndp);
2878925Sroot 	if (ip) {
2888925Sroot 		iput(ip);
28910139Ssam 		return (EADDRINUSE);
2908925Sroot 	}
29111828Ssam 	if (error = u.u_error) {
29211828Ssam 		u.u_error = 0;			/* XXX */
29311828Ssam 		return (error);
29411828Ssam 	}
295*16695Smckusick 	ip = maknode(IFSOCK | 0777, ndp);
2968925Sroot 	if (ip == NULL) {
2978925Sroot 		error = u.u_error;		/* XXX */
2988925Sroot 		u.u_error = 0;			/* XXX */
2998925Sroot 		return (error);
3008925Sroot 	}
3018925Sroot 	ip->i_socket = unp->unp_socket;
3028925Sroot 	unp->unp_inode = ip;
3038925Sroot 	iunlock(ip);			/* but keep reference */
3048925Sroot 	return (0);
3058925Sroot }
3068925Sroot 
3079169Ssam unp_connect(so, nam)
3088925Sroot 	struct socket *so;
3099169Ssam 	struct mbuf *nam;
3108925Sroot {
3119169Ssam 	register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
3129169Ssam 	register struct inode *ip;
3138925Sroot 	int error;
31412760Ssam 	register struct socket *so2;
315*16695Smckusick 	register struct nameidata *ndp = &u.u_nd;
3168925Sroot 
317*16695Smckusick 	ndp->ni_dirp = soun->sun_path;
31812760Ssam 	if (nam->m_len + (nam->m_off - MMINOFF) == MLEN)
31912760Ssam 		return (EMSGSIZE);
32012760Ssam 	*(mtod(nam, caddr_t) + nam->m_len) = 0;
321*16695Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
322*16695Smckusick 	ndp->ni_segflg = UIO_SYSSPACE;
323*16695Smckusick 	ip = namei(ndp);
3248925Sroot 	if (ip == 0) {
3258925Sroot 		error = u.u_error;
3268925Sroot 		u.u_error = 0;
32710139Ssam 		return (error);		/* XXX */
3288925Sroot 	}
3298925Sroot 	if ((ip->i_mode&IFMT) != IFSOCK) {
3308925Sroot 		error = ENOTSOCK;
3318925Sroot 		goto bad;
3328925Sroot 	}
3338925Sroot 	so2 = ip->i_socket;
3348925Sroot 	if (so2 == 0) {
3358925Sroot 		error = ECONNREFUSED;
3368925Sroot 		goto bad;
3378925Sroot 	}
33813115Ssam 	if (so->so_type != so2->so_type) {
33913115Ssam 		error = EPROTOTYPE;
34013115Ssam 		goto bad;
34113115Ssam 	}
34213115Ssam 	if (so->so_proto->pr_flags & PR_CONNREQUIRED &&
34313115Ssam 	    ((so2->so_options&SO_ACCEPTCONN) == 0 ||
34413115Ssam 	     (so2 = sonewconn(so2)) == 0)) {
34513115Ssam 		error = ECONNREFUSED;
34613115Ssam 		goto bad;
34713115Ssam 	}
34812760Ssam 	error = unp_connect2(so, nam, so2);
34912760Ssam bad:
35012760Ssam 	iput(ip);
35112760Ssam 	return (error);
35212760Ssam }
35312760Ssam 
35412760Ssam unp_connect2(so, sonam, so2)
35512760Ssam 	register struct socket *so;
35612760Ssam 	struct mbuf *sonam;
35712760Ssam 	register struct socket *so2;
35812760Ssam {
35912760Ssam 	register struct unpcb *unp = sotounpcb(so);
36012760Ssam 	register struct unpcb *unp2;
36112760Ssam 
36212760Ssam 	if (so2->so_type != so->so_type)
36312760Ssam 		return (EPROTOTYPE);
36414049Ssam 	unp2 = sotounpcb(so2);
36514049Ssam 	unp->unp_conn = unp2;
3668925Sroot 	switch (so->so_type) {
3678925Sroot 
3688925Sroot 	case SOCK_DGRAM:
3698925Sroot 		unp->unp_nextref = unp2->unp_refs;
3708925Sroot 		unp2->unp_refs = unp;
3718925Sroot 		break;
3728925Sroot 
3738925Sroot 	case SOCK_STREAM:
3749169Ssam 		unp2->unp_conn = unp;
37512760Ssam 		if (sonam)
37612760Ssam 			unp2->unp_remaddr = m_copy(sonam, 0, (int)M_COPYALL);
37714049Ssam 		soisconnected(so2);
37814049Ssam 		soisconnected(so);
3798925Sroot 		break;
3808925Sroot 
3818925Sroot 	default:
38212760Ssam 		panic("unp_connect2");
3838925Sroot 	}
3848925Sroot 	return (0);
3858925Sroot }
3869169Ssam 
3879169Ssam unp_disconnect(unp)
3889169Ssam 	struct unpcb *unp;
3899169Ssam {
3909169Ssam 	register struct unpcb *unp2 = unp->unp_conn;
3919169Ssam 
3929169Ssam 	if (unp2 == 0)
3939169Ssam 		return;
3949169Ssam 	unp->unp_conn = 0;
3959169Ssam 	switch (unp->unp_socket->so_type) {
3969169Ssam 
3979169Ssam 	case SOCK_DGRAM:
3989169Ssam 		if (unp2->unp_refs == unp)
3999169Ssam 			unp2->unp_refs = unp->unp_nextref;
4009169Ssam 		else {
4019169Ssam 			unp2 = unp2->unp_refs;
4029169Ssam 			for (;;) {
4039169Ssam 				if (unp2 == 0)
4049169Ssam 					panic("unp_disconnect");
4059169Ssam 				if (unp2->unp_nextref == unp)
4069169Ssam 					break;
4079169Ssam 				unp2 = unp2->unp_nextref;
4089169Ssam 			}
4099169Ssam 			unp2->unp_nextref = unp->unp_nextref;
4109169Ssam 		}
4119169Ssam 		unp->unp_nextref = 0;
4129169Ssam 		break;
4139169Ssam 
4149169Ssam 	case SOCK_STREAM:
41514049Ssam 		soisdisconnected(unp->unp_socket);
4169169Ssam 		unp2->unp_conn = 0;
4179169Ssam 		soisdisconnected(unp2->unp_socket);
4189169Ssam 		break;
4199169Ssam 	}
4209169Ssam }
4219169Ssam 
42212760Ssam #ifdef notdef
4239169Ssam unp_abort(unp)
4249169Ssam 	struct unpcb *unp;
4259169Ssam {
4269169Ssam 
4279169Ssam 	unp_detach(unp);
4289169Ssam }
42912760Ssam #endif
4309169Ssam 
4319169Ssam /*ARGSUSED*/
4329169Ssam unp_usrclosed(unp)
4339169Ssam 	struct unpcb *unp;
4349169Ssam {
4359169Ssam 
4369169Ssam }
4379169Ssam 
4389169Ssam unp_drop(unp, errno)
4399169Ssam 	struct unpcb *unp;
4409169Ssam 	int errno;
4419169Ssam {
44216054Skarels 	struct socket *so = unp->unp_socket;
4439169Ssam 
44416054Skarels 	so->so_error = errno;
4459169Ssam 	unp_disconnect(unp);
44616054Skarels 	if (so->so_head) {
44716054Skarels 		so->so_pcb = (caddr_t) 0;
44816431Skarels 		m_freem(unp->unp_remaddr);
44916054Skarels 		(void) m_free(dtom(unp));
45016054Skarels 		sofree(so);
45116054Skarels 	}
4529169Ssam }
4539169Ssam 
45412760Ssam #ifdef notdef
4559169Ssam unp_drain()
4569169Ssam {
4579169Ssam 
4589169Ssam }
45912760Ssam #endif
46012760Ssam 
46112760Ssam unp_externalize(rights)
46212760Ssam 	struct mbuf *rights;
46312760Ssam {
46412760Ssam 	int newfds = rights->m_len / sizeof (int);
46512760Ssam 	register int i;
46612760Ssam 	register struct file **rp = mtod(rights, struct file **);
46712760Ssam 	register struct file *fp;
46812760Ssam 	int f;
46912760Ssam 
47012760Ssam 	if (newfds > ufavail()) {
47112760Ssam 		for (i = 0; i < newfds; i++) {
47212760Ssam 			fp = *rp;
47312760Ssam 			unp_discard(fp);
47412760Ssam 			*rp++ = 0;
47512760Ssam 		}
47612760Ssam 		return (EMSGSIZE);
47712760Ssam 	}
47812760Ssam 	for (i = 0; i < newfds; i++) {
47912760Ssam 		f = ufalloc(0);
48012760Ssam 		if (f < 0)
48112760Ssam 			panic("unp_externalize");
48212760Ssam 		fp = *rp;
48312760Ssam 		u.u_ofile[f] = fp;
48412760Ssam 		fp->f_msgcount--;
48514927Smckusick 		*(int *)rp++ = f;
48612760Ssam 	}
48712760Ssam 	return (0);
48812760Ssam }
48912760Ssam 
49012760Ssam unp_internalize(rights)
49112760Ssam 	struct mbuf *rights;
49212760Ssam {
49312760Ssam 	register struct file **rp;
49412760Ssam 	int oldfds = rights->m_len / sizeof (int);
49512760Ssam 	register int i;
49612760Ssam 	register struct file *fp;
49712760Ssam 
49812760Ssam 	rp = mtod(rights, struct file **);
49913084Ssam 	for (i = 0; i < oldfds; i++)
50012760Ssam 		if (getf(*(int *)rp++) == 0)
50112760Ssam 			return (EBADF);
50212760Ssam 	rp = mtod(rights, struct file **);
50313084Ssam 	for (i = 0; i < oldfds; i++) {
50412760Ssam 		fp = getf(*(int *)rp);
50512760Ssam 		*rp++ = fp;
50612760Ssam 		fp->f_count++;
50712760Ssam 		fp->f_msgcount++;
50812760Ssam 	}
50912760Ssam 	return (0);
51012760Ssam }
51112760Ssam 
51212760Ssam int	unp_defer, unp_gcing;
51312760Ssam int	unp_mark();
51412760Ssam 
51512760Ssam unp_gc()
51612760Ssam {
51712760Ssam 	register struct file *fp;
51812760Ssam 	register struct socket *so;
51912760Ssam 
52012760Ssam 	if (unp_gcing)
52112760Ssam 		return;
52212760Ssam 	unp_gcing = 1;
52312760Ssam restart:
52412760Ssam 	unp_defer = 0;
52512760Ssam 	for (fp = file; fp < fileNFILE; fp++)
52612760Ssam 		fp->f_flag &= ~(FMARK|FDEFER);
52712760Ssam 	do {
52812760Ssam 		for (fp = file; fp < fileNFILE; fp++) {
52912760Ssam 			if (fp->f_count == 0)
53012760Ssam 				continue;
53112760Ssam 			if (fp->f_flag & FDEFER) {
53212760Ssam 				fp->f_flag &= ~FDEFER;
53312760Ssam 				unp_defer--;
53412760Ssam 			} else {
53512760Ssam 				if (fp->f_flag & FMARK)
53612760Ssam 					continue;
53712760Ssam 				if (fp->f_count == fp->f_msgcount)
53812760Ssam 					continue;
53912760Ssam 				fp->f_flag |= FMARK;
54012760Ssam 			}
54112760Ssam 			if (fp->f_type != DTYPE_SOCKET)
54212760Ssam 				continue;
54312760Ssam 			so = (struct socket *)fp->f_data;
54412760Ssam 			if (so->so_proto->pr_family != AF_UNIX ||
54512760Ssam 			    (so->so_proto->pr_flags&PR_ADDR) == 0)
54612760Ssam 				continue;
54712760Ssam 			if (so->so_rcv.sb_flags & SB_LOCK) {
54812760Ssam 				sbwait(&so->so_rcv);
54912760Ssam 				goto restart;
55012760Ssam 			}
55112760Ssam 			unp_scan(so->so_rcv.sb_mb, unp_mark);
55212760Ssam 		}
55312760Ssam 	} while (unp_defer);
55412760Ssam 	for (fp = file; fp < fileNFILE; fp++) {
55512760Ssam 		if (fp->f_count == 0)
55612760Ssam 			continue;
55712760Ssam 		if (fp->f_count == fp->f_msgcount && (fp->f_flag&FMARK)==0) {
55812760Ssam 			if (fp->f_type != DTYPE_SOCKET)
55912760Ssam 				panic("unp_gc");
56012760Ssam 			(void) soshutdown((struct socket *)fp->f_data, 0);
56112760Ssam 		}
56212760Ssam 	}
56312760Ssam 	unp_gcing = 0;
56412760Ssam }
56512760Ssam 
56612760Ssam unp_scan(m, op)
56712760Ssam 	register struct mbuf *m;
56812760Ssam 	int (*op)();
56912760Ssam {
57012760Ssam 	register struct file **rp;
57112760Ssam 	register int i;
57212760Ssam 	int qfds;
57312760Ssam 
57412760Ssam 	while (m) {
57512760Ssam 		m = m->m_next;
57612760Ssam 		if (m == 0)
57712760Ssam 			goto bad;
57812760Ssam 		if (m->m_len) {
57912760Ssam 			qfds = m->m_len / sizeof (struct file *);
58012760Ssam 			rp = mtod(m, struct file **);
58112760Ssam 			for (i = 0; i < qfds; i++)
58212760Ssam 				(*op)(*rp++);
58312760Ssam 		}
58412760Ssam 		do {
58512760Ssam 			m = m->m_next;
58612760Ssam 			if (m == 0)
58712760Ssam 				goto bad;
58812760Ssam 		} while (m->m_act == 0);
58912760Ssam 		m = m->m_next;
59012760Ssam 	}
59112760Ssam 	return;
59212760Ssam bad:
59312760Ssam 	panic("unp_gcscan");
59412760Ssam }
59512760Ssam 
59612760Ssam unp_mark(fp)
59712760Ssam 	struct file *fp;
59812760Ssam {
59912760Ssam 
60012760Ssam 	if (fp->f_flag & FMARK)
60112760Ssam 		return;
60212760Ssam 	unp_defer++;
60312760Ssam 	fp->f_flag |= (FMARK|FDEFER);
60412760Ssam }
60512760Ssam 
60612760Ssam unp_discard(fp)
60712760Ssam 	struct file *fp;
60812760Ssam {
60912760Ssam 
61012760Ssam 	fp->f_msgcount--;
61113084Ssam 	closef(fp);
61212760Ssam }
613