xref: /csrg-svn/sys/kern/uipc_usrreq.c (revision 21110)
1*21110Skarels /*	uipc_usrreq.c	6.12	85/05/27	*/
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 };
26*21110Skarels ino_t	unp_ino;				/* fake inode numbers */
278925Sroot 
288925Sroot /*ARGSUSED*/
2912760Ssam uipc_usrreq(so, req, m, nam, rights)
308925Sroot 	struct socket *so;
318925Sroot 	int req;
3212760Ssam 	struct mbuf *m, *nam, *rights;
338925Sroot {
348925Sroot 	struct unpcb *unp = sotounpcb(so);
358925Sroot 	register struct socket *so2;
368925Sroot 	int error = 0;
378925Sroot 
3812760Ssam 	if (req != PRU_SEND && rights && rights->m_len) {
3912760Ssam 		error = EOPNOTSUPP;
4012760Ssam 		goto release;
4112760Ssam 	}
4212760Ssam 	if (unp == 0 && req != PRU_ATTACH) {
4312760Ssam 		error = EINVAL;
4412760Ssam 		goto release;
4512760Ssam 	}
468925Sroot 	switch (req) {
478925Sroot 
488925Sroot 	case PRU_ATTACH:
498925Sroot 		if (unp) {
509169Ssam 			error = EISCONN;
518925Sroot 			break;
528925Sroot 		}
539028Sroot 		error = unp_attach(so);
548925Sroot 		break;
558925Sroot 
568925Sroot 	case PRU_DETACH:
578925Sroot 		unp_detach(unp);
588925Sroot 		break;
598925Sroot 
609169Ssam 	case PRU_BIND:
619169Ssam 		error = unp_bind(unp, nam);
629169Ssam 		break;
639169Ssam 
649169Ssam 	case PRU_LISTEN:
659169Ssam 		if (unp->unp_inode == 0)
669169Ssam 			error = EINVAL;
679169Ssam 		break;
689169Ssam 
698925Sroot 	case PRU_CONNECT:
709028Sroot 		error = unp_connect(so, nam);
718925Sroot 		break;
728925Sroot 
7312760Ssam 	case PRU_CONNECT2:
7413115Ssam 		error = unp_connect2(so, (struct mbuf *)0,
7513115Ssam 		    (struct socket *)nam);
7612760Ssam 		break;
7712760Ssam 
788925Sroot 	case PRU_DISCONNECT:
798925Sroot 		unp_disconnect(unp);
808925Sroot 		break;
818925Sroot 
829169Ssam 	case PRU_ACCEPT:
839169Ssam 		nam->m_len = unp->unp_remaddr->m_len;
849169Ssam 		bcopy(mtod(unp->unp_remaddr, caddr_t),
859169Ssam 		    mtod(nam, caddr_t), (unsigned)nam->m_len);
868925Sroot 		break;
878925Sroot 
888925Sroot 	case PRU_SHUTDOWN:
898925Sroot 		socantsendmore(so);
908925Sroot 		unp_usrclosed(unp);
918925Sroot 		break;
928925Sroot 
938925Sroot 	case PRU_RCVD:
948925Sroot 		switch (so->so_type) {
958925Sroot 
968925Sroot 		case SOCK_DGRAM:
978925Sroot 			panic("uipc 1");
9810139Ssam 			/*NOTREACHED*/
998925Sroot 
10010139Ssam 		case SOCK_STREAM:
1018925Sroot #define	rcv (&so->so_rcv)
1028925Sroot #define snd (&so2->so_snd)
1038925Sroot 			if (unp->unp_conn == 0)
1048925Sroot 				break;
1058925Sroot 			so2 = unp->unp_conn->unp_socket;
1068925Sroot 			/*
1078925Sroot 			 * Transfer resources back to send port
1088925Sroot 			 * and wakeup any waiting to write.
1098925Sroot 			 */
1108925Sroot 			snd->sb_mbmax += rcv->sb_mbmax - rcv->sb_mbcnt;
1118925Sroot 			rcv->sb_mbmax = rcv->sb_mbcnt;
1128925Sroot 			snd->sb_hiwat += rcv->sb_hiwat - rcv->sb_cc;
1138925Sroot 			rcv->sb_hiwat = rcv->sb_cc;
11417543Skarels 			sowwakeup(so2);
1158925Sroot #undef snd
1168925Sroot #undef rcv
1178925Sroot 			break;
1188925Sroot 
1198925Sroot 		default:
1208925Sroot 			panic("uipc 2");
1218925Sroot 		}
1228925Sroot 		break;
1238925Sroot 
1248925Sroot 	case PRU_SEND:
1258925Sroot 		switch (so->so_type) {
1268925Sroot 
1278925Sroot 		case SOCK_DGRAM:
1289028Sroot 			if (nam) {
1298925Sroot 				if (unp->unp_conn) {
1308925Sroot 					error = EISCONN;
1318925Sroot 					break;
1328925Sroot 				}
1339028Sroot 				error = unp_connect(so, nam);
1348925Sroot 				if (error)
1358925Sroot 					break;
1368925Sroot 			} else {
1378925Sroot 				if (unp->unp_conn == 0) {
1388925Sroot 					error = ENOTCONN;
1398925Sroot 					break;
1408925Sroot 				}
1418925Sroot 			}
1428925Sroot 			so2 = unp->unp_conn->unp_socket;
1439169Ssam 			/* BEGIN XXX */
14412760Ssam 			if (rights) {
14512760Ssam 				error = unp_internalize(rights);
14612760Ssam 				if (error)
14712760Ssam 					break;
14812760Ssam 			}
14912760Ssam 			if (sbspace(&so2->so_rcv) > 0) {
15013119Ssam 				/*
15113119Ssam 				 * There's no record of source socket's
15213119Ssam 				 * name, so send null name for the moment.
15313119Ssam 				 */
15417543Skarels 				if (sbappendaddr(&so2->so_rcv,
15517543Skarels 				    &sun_noname, m, rights)) {
15617543Skarels 					sorwakeup(so2);
15717543Skarels 					m = 0;
15817543Skarels 				}
15912760Ssam 			}
1609169Ssam 			/* END XXX */
1619028Sroot 			if (nam)
1629169Ssam 				unp_disconnect(unp);
1638925Sroot 			break;
1648925Sroot 
1658925Sroot 		case SOCK_STREAM:
1668925Sroot #define	rcv (&so2->so_rcv)
1678925Sroot #define	snd (&so->so_snd)
16812760Ssam 			if (rights && rights->m_len) {
16912760Ssam 				error = EOPNOTSUPP;
17012760Ssam 				break;
17112760Ssam 			}
172*21110Skarels 			if (so->so_state & SS_CANTSENDMORE)
173*21110Skarels 				return (EPIPE);
1748925Sroot 			if (unp->unp_conn == 0)
1758925Sroot 				panic("uipc 3");
1768925Sroot 			so2 = unp->unp_conn->unp_socket;
1778925Sroot 			/*
1788925Sroot 			 * Send to paired receive port, and then
1798925Sroot 			 * give it enough resources to hold what it already has.
1808925Sroot 			 * Wake up readers.
1818925Sroot 			 */
1828925Sroot 			sbappend(rcv, m);
1838925Sroot 			snd->sb_mbmax -= rcv->sb_mbcnt - rcv->sb_mbmax;
1848925Sroot 			rcv->sb_mbmax = rcv->sb_mbcnt;
1858925Sroot 			snd->sb_hiwat -= rcv->sb_cc - rcv->sb_hiwat;
1868925Sroot 			rcv->sb_hiwat = rcv->sb_cc;
18717543Skarels 			sorwakeup(so2);
18817543Skarels 			m = 0;
1898925Sroot #undef snd
1908925Sroot #undef rcv
1918925Sroot 			break;
1928925Sroot 
1938925Sroot 		default:
1948925Sroot 			panic("uipc 4");
1958925Sroot 		}
1968925Sroot 		break;
1978925Sroot 
1988925Sroot 	case PRU_ABORT:
1998925Sroot 		unp_drop(unp, ECONNABORTED);
2008925Sroot 		break;
2018925Sroot 
2028925Sroot /* SOME AS YET UNIMPLEMENTED HOOKS */
2038925Sroot 	case PRU_CONTROL:
20413050Ssam 		return (EOPNOTSUPP);
2058925Sroot 
20616973Skarels /* END UNIMPLEMENTED HOOKS */
2078925Sroot 	case PRU_SENSE:
20816973Skarels 		((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
20916973Skarels 		if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) {
21016973Skarels 			so2 = unp->unp_conn->unp_socket;
21116973Skarels 			((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc;
21216973Skarels 		}
213*21110Skarels 		((struct stat *) m)->st_dev = NODEV;
214*21110Skarels 		((struct stat *) m)->st_ino = unp_ino++;
21516973Skarels 		return (0);
2168925Sroot 
2178925Sroot 	case PRU_RCVOOB:
21816774Sbloom 		return (EOPNOTSUPP);
2198925Sroot 
2208925Sroot 	case PRU_SENDOOB:
22117543Skarels 		error = EOPNOTSUPP;
2228925Sroot 		break;
2238925Sroot 
2248925Sroot 	case PRU_SOCKADDR:
2258925Sroot 		break;
2268925Sroot 
22714121Ssam 	case PRU_PEERADDR:
22814121Ssam 		break;
22914121Ssam 
2308925Sroot 	case PRU_SLOWTIMO:
2318925Sroot 		break;
2328925Sroot 
2338925Sroot 	default:
2348925Sroot 		panic("piusrreq");
2358925Sroot 	}
23612760Ssam release:
23712760Ssam 	if (m)
23812760Ssam 		m_freem(m);
23911709Ssam 	return (error);
2408925Sroot }
2418925Sroot 
24216973Skarels /*
24316973Skarels  * We assign all buffering for stream sockets to the source,
24416973Skarels  * as that is where the flow control is implemented.
24516973Skarels  * Datagram sockets really use the sendspace as the maximum datagram size,
24616973Skarels  * and don't really want to reserve the sendspace.  Their recvspace should
24716973Skarels  * be large enough for at least one max-size datagram plus address.
24816973Skarels  */
24916973Skarels #define	PIPSIZ	4096
25016973Skarels int	unpst_sendspace = PIPSIZ;
25116973Skarels int	unpst_recvspace = 0;
25216973Skarels int	unpdg_sendspace = 2*1024;	/* really max datagram size */
25316973Skarels int	unpdg_recvspace = 4*1024;
2548925Sroot 
2559169Ssam unp_attach(so)
2568925Sroot 	struct socket *so;
2578925Sroot {
2589169Ssam 	register struct mbuf *m;
2598925Sroot 	register struct unpcb *unp;
2608925Sroot 	int error;
2618925Sroot 
26216973Skarels 	switch (so->so_type) {
26316973Skarels 
26416973Skarels 	case SOCK_STREAM:
26516973Skarels 		error = soreserve(so, unpst_sendspace, unpst_recvspace);
26616973Skarels 		break;
26716973Skarels 
26816973Skarels 	case SOCK_DGRAM:
26916973Skarels 		error = soreserve(so, unpdg_sendspace, unpdg_recvspace);
27016973Skarels 		break;
27116973Skarels 	}
2728925Sroot 	if (error)
27310139Ssam 		return (error);
2749637Ssam 	m = m_getclr(M_DONTWAIT, MT_PCB);
27510139Ssam 	if (m == NULL)
27610139Ssam 		return (ENOBUFS);
2778925Sroot 	unp = mtod(m, struct unpcb *);
2788925Sroot 	so->so_pcb = (caddr_t)unp;
2798925Sroot 	unp->unp_socket = so;
2808925Sroot 	return (0);
2818925Sroot }
2828925Sroot 
2838925Sroot unp_detach(unp)
2849169Ssam 	register struct unpcb *unp;
2858925Sroot {
2868925Sroot 
2878925Sroot 	if (unp->unp_inode) {
28817020Skarels 		unp->unp_inode->i_socket = 0;
2898925Sroot 		irele(unp->unp_inode);
2908925Sroot 		unp->unp_inode = 0;
2918925Sroot 	}
2928925Sroot 	if (unp->unp_conn)
2938925Sroot 		unp_disconnect(unp);
2948925Sroot 	while (unp->unp_refs)
2958925Sroot 		unp_drop(unp->unp_refs, ECONNRESET);
2968925Sroot 	soisdisconnected(unp->unp_socket);
2978925Sroot 	unp->unp_socket->so_pcb = 0;
2989169Ssam 	m_freem(unp->unp_remaddr);
2999169Ssam 	(void) m_free(dtom(unp));
3008925Sroot }
3018925Sroot 
3029169Ssam unp_bind(unp, nam)
3038925Sroot 	struct unpcb *unp;
3049169Ssam 	struct mbuf *nam;
3058925Sroot {
3069169Ssam 	struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
3078925Sroot 	register struct inode *ip;
30816695Smckusick 	register struct nameidata *ndp = &u.u_nd;
3098925Sroot 	int error;
3108925Sroot 
31116695Smckusick 	ndp->ni_dirp = soun->sun_path;
31212760Ssam 	if (nam->m_len == MLEN)
31312760Ssam 		return (EINVAL);
31412760Ssam 	*(mtod(nam, caddr_t) + nam->m_len) = 0;
31512760Ssam /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
31616695Smckusick 	ndp->ni_nameiop = CREATE | FOLLOW;
31716695Smckusick 	ndp->ni_segflg = UIO_SYSSPACE;
31816695Smckusick 	ip = namei(ndp);
3198925Sroot 	if (ip) {
3208925Sroot 		iput(ip);
32110139Ssam 		return (EADDRINUSE);
3228925Sroot 	}
32311828Ssam 	if (error = u.u_error) {
32411828Ssam 		u.u_error = 0;			/* XXX */
32511828Ssam 		return (error);
32611828Ssam 	}
32716695Smckusick 	ip = maknode(IFSOCK | 0777, ndp);
3288925Sroot 	if (ip == NULL) {
3298925Sroot 		error = u.u_error;		/* XXX */
3308925Sroot 		u.u_error = 0;			/* XXX */
3318925Sroot 		return (error);
3328925Sroot 	}
3338925Sroot 	ip->i_socket = unp->unp_socket;
3348925Sroot 	unp->unp_inode = ip;
3358925Sroot 	iunlock(ip);			/* but keep reference */
3368925Sroot 	return (0);
3378925Sroot }
3388925Sroot 
3399169Ssam unp_connect(so, nam)
3408925Sroot 	struct socket *so;
3419169Ssam 	struct mbuf *nam;
3428925Sroot {
3439169Ssam 	register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
3449169Ssam 	register struct inode *ip;
3458925Sroot 	int error;
34612760Ssam 	register struct socket *so2;
34716695Smckusick 	register struct nameidata *ndp = &u.u_nd;
3488925Sroot 
34916695Smckusick 	ndp->ni_dirp = soun->sun_path;
35012760Ssam 	if (nam->m_len + (nam->m_off - MMINOFF) == MLEN)
35112760Ssam 		return (EMSGSIZE);
35212760Ssam 	*(mtod(nam, caddr_t) + nam->m_len) = 0;
35316695Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
35416695Smckusick 	ndp->ni_segflg = UIO_SYSSPACE;
35516695Smckusick 	ip = namei(ndp);
3568925Sroot 	if (ip == 0) {
3578925Sroot 		error = u.u_error;
3588925Sroot 		u.u_error = 0;
35910139Ssam 		return (error);		/* XXX */
3608925Sroot 	}
36117543Skarels 	if (access(ip, IWRITE)) {
36217543Skarels 		error = u.u_error;
36317543Skarels 		u.u_error = 0; 		/* XXX */
36417543Skarels 		goto bad;
36517543Skarels 	}
3668925Sroot 	if ((ip->i_mode&IFMT) != IFSOCK) {
3678925Sroot 		error = ENOTSOCK;
3688925Sroot 		goto bad;
3698925Sroot 	}
3708925Sroot 	so2 = ip->i_socket;
3718925Sroot 	if (so2 == 0) {
3728925Sroot 		error = ECONNREFUSED;
3738925Sroot 		goto bad;
3748925Sroot 	}
37513115Ssam 	if (so->so_type != so2->so_type) {
37613115Ssam 		error = EPROTOTYPE;
37713115Ssam 		goto bad;
37813115Ssam 	}
37913115Ssam 	if (so->so_proto->pr_flags & PR_CONNREQUIRED &&
38013115Ssam 	    ((so2->so_options&SO_ACCEPTCONN) == 0 ||
38113115Ssam 	     (so2 = sonewconn(so2)) == 0)) {
38213115Ssam 		error = ECONNREFUSED;
38313115Ssam 		goto bad;
38413115Ssam 	}
38512760Ssam 	error = unp_connect2(so, nam, so2);
38612760Ssam bad:
38712760Ssam 	iput(ip);
38812760Ssam 	return (error);
38912760Ssam }
39012760Ssam 
39112760Ssam unp_connect2(so, sonam, so2)
39212760Ssam 	register struct socket *so;
39312760Ssam 	struct mbuf *sonam;
39412760Ssam 	register struct socket *so2;
39512760Ssam {
39612760Ssam 	register struct unpcb *unp = sotounpcb(so);
39712760Ssam 	register struct unpcb *unp2;
39812760Ssam 
39912760Ssam 	if (so2->so_type != so->so_type)
40012760Ssam 		return (EPROTOTYPE);
40114049Ssam 	unp2 = sotounpcb(so2);
40214049Ssam 	unp->unp_conn = unp2;
4038925Sroot 	switch (so->so_type) {
4048925Sroot 
4058925Sroot 	case SOCK_DGRAM:
4068925Sroot 		unp->unp_nextref = unp2->unp_refs;
4078925Sroot 		unp2->unp_refs = unp;
40817543Skarels 		soisconnected(so);
4098925Sroot 		break;
4108925Sroot 
4118925Sroot 	case SOCK_STREAM:
4129169Ssam 		unp2->unp_conn = unp;
41312760Ssam 		if (sonam)
41412760Ssam 			unp2->unp_remaddr = m_copy(sonam, 0, (int)M_COPYALL);
41514049Ssam 		soisconnected(so2);
41614049Ssam 		soisconnected(so);
4178925Sroot 		break;
4188925Sroot 
4198925Sroot 	default:
42012760Ssam 		panic("unp_connect2");
4218925Sroot 	}
4228925Sroot 	return (0);
4238925Sroot }
4249169Ssam 
4259169Ssam unp_disconnect(unp)
4269169Ssam 	struct unpcb *unp;
4279169Ssam {
4289169Ssam 	register struct unpcb *unp2 = unp->unp_conn;
4299169Ssam 
4309169Ssam 	if (unp2 == 0)
4319169Ssam 		return;
4329169Ssam 	unp->unp_conn = 0;
4339169Ssam 	switch (unp->unp_socket->so_type) {
4349169Ssam 
4359169Ssam 	case SOCK_DGRAM:
4369169Ssam 		if (unp2->unp_refs == unp)
4379169Ssam 			unp2->unp_refs = unp->unp_nextref;
4389169Ssam 		else {
4399169Ssam 			unp2 = unp2->unp_refs;
4409169Ssam 			for (;;) {
4419169Ssam 				if (unp2 == 0)
4429169Ssam 					panic("unp_disconnect");
4439169Ssam 				if (unp2->unp_nextref == unp)
4449169Ssam 					break;
4459169Ssam 				unp2 = unp2->unp_nextref;
4469169Ssam 			}
4479169Ssam 			unp2->unp_nextref = unp->unp_nextref;
4489169Ssam 		}
4499169Ssam 		unp->unp_nextref = 0;
4509169Ssam 		break;
4519169Ssam 
4529169Ssam 	case SOCK_STREAM:
45314049Ssam 		soisdisconnected(unp->unp_socket);
4549169Ssam 		unp2->unp_conn = 0;
4559169Ssam 		soisdisconnected(unp2->unp_socket);
4569169Ssam 		break;
4579169Ssam 	}
4589169Ssam }
4599169Ssam 
46012760Ssam #ifdef notdef
4619169Ssam unp_abort(unp)
4629169Ssam 	struct unpcb *unp;
4639169Ssam {
4649169Ssam 
4659169Ssam 	unp_detach(unp);
4669169Ssam }
46712760Ssam #endif
4689169Ssam 
4699169Ssam /*ARGSUSED*/
4709169Ssam unp_usrclosed(unp)
4719169Ssam 	struct unpcb *unp;
4729169Ssam {
4739169Ssam 
4749169Ssam }
4759169Ssam 
4769169Ssam unp_drop(unp, errno)
4779169Ssam 	struct unpcb *unp;
4789169Ssam 	int errno;
4799169Ssam {
48016054Skarels 	struct socket *so = unp->unp_socket;
4819169Ssam 
48216054Skarels 	so->so_error = errno;
4839169Ssam 	unp_disconnect(unp);
48416054Skarels 	if (so->so_head) {
48516054Skarels 		so->so_pcb = (caddr_t) 0;
48616431Skarels 		m_freem(unp->unp_remaddr);
48716054Skarels 		(void) m_free(dtom(unp));
48816054Skarels 		sofree(so);
48916054Skarels 	}
4909169Ssam }
4919169Ssam 
49212760Ssam #ifdef notdef
4939169Ssam unp_drain()
4949169Ssam {
4959169Ssam 
4969169Ssam }
49712760Ssam #endif
49812760Ssam 
49912760Ssam unp_externalize(rights)
50012760Ssam 	struct mbuf *rights;
50112760Ssam {
50212760Ssam 	int newfds = rights->m_len / sizeof (int);
50312760Ssam 	register int i;
50412760Ssam 	register struct file **rp = mtod(rights, struct file **);
50512760Ssam 	register struct file *fp;
50612760Ssam 	int f;
50712760Ssam 
50812760Ssam 	if (newfds > ufavail()) {
50912760Ssam 		for (i = 0; i < newfds; i++) {
51012760Ssam 			fp = *rp;
51112760Ssam 			unp_discard(fp);
51212760Ssam 			*rp++ = 0;
51312760Ssam 		}
51412760Ssam 		return (EMSGSIZE);
51512760Ssam 	}
51612760Ssam 	for (i = 0; i < newfds; i++) {
51712760Ssam 		f = ufalloc(0);
51812760Ssam 		if (f < 0)
51912760Ssam 			panic("unp_externalize");
52012760Ssam 		fp = *rp;
52112760Ssam 		u.u_ofile[f] = fp;
52212760Ssam 		fp->f_msgcount--;
52314927Smckusick 		*(int *)rp++ = f;
52412760Ssam 	}
52512760Ssam 	return (0);
52612760Ssam }
52712760Ssam 
52812760Ssam unp_internalize(rights)
52912760Ssam 	struct mbuf *rights;
53012760Ssam {
53112760Ssam 	register struct file **rp;
53212760Ssam 	int oldfds = rights->m_len / sizeof (int);
53312760Ssam 	register int i;
53412760Ssam 	register struct file *fp;
53512760Ssam 
53612760Ssam 	rp = mtod(rights, struct file **);
53713084Ssam 	for (i = 0; i < oldfds; i++)
53812760Ssam 		if (getf(*(int *)rp++) == 0)
53912760Ssam 			return (EBADF);
54012760Ssam 	rp = mtod(rights, struct file **);
54113084Ssam 	for (i = 0; i < oldfds; i++) {
54212760Ssam 		fp = getf(*(int *)rp);
54312760Ssam 		*rp++ = fp;
54412760Ssam 		fp->f_count++;
54512760Ssam 		fp->f_msgcount++;
54612760Ssam 	}
54712760Ssam 	return (0);
54812760Ssam }
54912760Ssam 
55012760Ssam int	unp_defer, unp_gcing;
55112760Ssam int	unp_mark();
55216995Skarels extern	struct domain unixdomain;
55312760Ssam 
55412760Ssam unp_gc()
55512760Ssam {
55612760Ssam 	register struct file *fp;
55712760Ssam 	register struct socket *so;
55812760Ssam 
55912760Ssam 	if (unp_gcing)
56012760Ssam 		return;
56112760Ssam 	unp_gcing = 1;
56212760Ssam restart:
56312760Ssam 	unp_defer = 0;
56412760Ssam 	for (fp = file; fp < fileNFILE; fp++)
56512760Ssam 		fp->f_flag &= ~(FMARK|FDEFER);
56612760Ssam 	do {
56712760Ssam 		for (fp = file; fp < fileNFILE; fp++) {
56812760Ssam 			if (fp->f_count == 0)
56912760Ssam 				continue;
57012760Ssam 			if (fp->f_flag & FDEFER) {
57112760Ssam 				fp->f_flag &= ~FDEFER;
57212760Ssam 				unp_defer--;
57312760Ssam 			} else {
57412760Ssam 				if (fp->f_flag & FMARK)
57512760Ssam 					continue;
57612760Ssam 				if (fp->f_count == fp->f_msgcount)
57712760Ssam 					continue;
57812760Ssam 				fp->f_flag |= FMARK;
57912760Ssam 			}
58012760Ssam 			if (fp->f_type != DTYPE_SOCKET)
58112760Ssam 				continue;
58212760Ssam 			so = (struct socket *)fp->f_data;
58316995Skarels 			if (so->so_proto->pr_domain != &unixdomain ||
58412760Ssam 			    (so->so_proto->pr_flags&PR_ADDR) == 0)
58512760Ssam 				continue;
58612760Ssam 			if (so->so_rcv.sb_flags & SB_LOCK) {
58712760Ssam 				sbwait(&so->so_rcv);
58812760Ssam 				goto restart;
58912760Ssam 			}
59012760Ssam 			unp_scan(so->so_rcv.sb_mb, unp_mark);
59112760Ssam 		}
59212760Ssam 	} while (unp_defer);
59312760Ssam 	for (fp = file; fp < fileNFILE; fp++) {
59412760Ssam 		if (fp->f_count == 0)
59512760Ssam 			continue;
59612760Ssam 		if (fp->f_count == fp->f_msgcount && (fp->f_flag&FMARK)==0) {
59712760Ssam 			if (fp->f_type != DTYPE_SOCKET)
59812760Ssam 				panic("unp_gc");
59912760Ssam 			(void) soshutdown((struct socket *)fp->f_data, 0);
60012760Ssam 		}
60112760Ssam 	}
60212760Ssam 	unp_gcing = 0;
60312760Ssam }
60412760Ssam 
60516995Skarels unp_dispose(m)
60616995Skarels 	struct mbuf *m;
60716995Skarels {
60816995Skarels 	int unp_discard();
60916995Skarels 
61017020Skarels 	if (m)
61117020Skarels 		unp_scan(m, unp_discard);
61216995Skarels }
61316995Skarels 
61416995Skarels unp_scan(m0, op)
61516995Skarels 	register struct mbuf *m0;
61612760Ssam 	int (*op)();
61712760Ssam {
61816995Skarels 	register struct mbuf *m;
61912760Ssam 	register struct file **rp;
62012760Ssam 	register int i;
62117020Skarels 	int qfds;
62212760Ssam 
62316995Skarels 	while (m0) {
62416995Skarels 		for (m = m0; m; m = m->m_next)
62516995Skarels 			if (m->m_type == MT_RIGHTS && m->m_len) {
62616995Skarels 				qfds = m->m_len / sizeof (struct file *);
62716995Skarels 				rp = mtod(m, struct file **);
62816995Skarels 				for (i = 0; i < qfds; i++)
62916995Skarels 					(*op)(*rp++);
63016995Skarels 				break;		/* XXX, but saves time */
63116995Skarels 			}
63217020Skarels 		m0 = m0->m_act;
63312760Ssam 	}
63412760Ssam }
63512760Ssam 
63612760Ssam unp_mark(fp)
63712760Ssam 	struct file *fp;
63812760Ssam {
63912760Ssam 
64012760Ssam 	if (fp->f_flag & FMARK)
64112760Ssam 		return;
64212760Ssam 	unp_defer++;
64312760Ssam 	fp->f_flag |= (FMARK|FDEFER);
64412760Ssam }
64512760Ssam 
64612760Ssam unp_discard(fp)
64712760Ssam 	struct file *fp;
64812760Ssam {
64912760Ssam 
65012760Ssam 	fp->f_msgcount--;
65113084Ssam 	closef(fp);
65212760Ssam }
653