xref: /csrg-svn/sys/kern/uipc_usrreq.c (revision 25555)
123443Smckusick /*
223443Smckusick  * Copyright (c) 1982 Regents of the University of California.
323443Smckusick  * All rights reserved.  The Berkeley software License Agreement
423443Smckusick  * specifies the terms and conditions for redistribution.
523443Smckusick  *
6*25555Skarels  *	@(#)uipc_usrreq.c	6.17 (Berkeley) 11/30/85
723443Smckusick  */
88925Sroot 
917105Sbloom #include "param.h"
1017105Sbloom #include "dir.h"
1117105Sbloom #include "user.h"
1217105Sbloom #include "mbuf.h"
1317105Sbloom #include "domain.h"
1417105Sbloom #include "protosw.h"
1517105Sbloom #include "socket.h"
1617105Sbloom #include "socketvar.h"
1717105Sbloom #include "unpcb.h"
1817105Sbloom #include "un.h"
1917105Sbloom #include "inode.h"
2017105Sbloom #include "file.h"
2117105Sbloom #include "stat.h"
228925Sroot 
238925Sroot /*
248925Sroot  * Unix communications domain.
2512760Ssam  *
2612760Ssam  * TODO:
2712760Ssam  *	SEQPACKET, RDM
2813119Ssam  *	rethink name space problems
2912760Ssam  *	need a proper out-of-band
308925Sroot  */
3113119Ssam struct	sockaddr sun_noname = { AF_UNIX };
3221110Skarels ino_t	unp_ino;				/* fake inode numbers */
338925Sroot 
348925Sroot /*ARGSUSED*/
3512760Ssam uipc_usrreq(so, req, m, nam, rights)
368925Sroot 	struct socket *so;
378925Sroot 	int req;
3812760Ssam 	struct mbuf *m, *nam, *rights;
398925Sroot {
408925Sroot 	struct unpcb *unp = sotounpcb(so);
418925Sroot 	register struct socket *so2;
428925Sroot 	int error = 0;
438925Sroot 
44*25555Skarels 	if (req == PRU_CONTROL)
45*25555Skarels 		return (EOPNOTSUPP);
4612760Ssam 	if (req != PRU_SEND && rights && rights->m_len) {
4712760Ssam 		error = EOPNOTSUPP;
4812760Ssam 		goto release;
4912760Ssam 	}
5012760Ssam 	if (unp == 0 && req != PRU_ATTACH) {
5112760Ssam 		error = EINVAL;
5212760Ssam 		goto release;
5312760Ssam 	}
548925Sroot 	switch (req) {
558925Sroot 
568925Sroot 	case PRU_ATTACH:
578925Sroot 		if (unp) {
589169Ssam 			error = EISCONN;
598925Sroot 			break;
608925Sroot 		}
619028Sroot 		error = unp_attach(so);
628925Sroot 		break;
638925Sroot 
648925Sroot 	case PRU_DETACH:
658925Sroot 		unp_detach(unp);
668925Sroot 		break;
678925Sroot 
689169Ssam 	case PRU_BIND:
699169Ssam 		error = unp_bind(unp, nam);
709169Ssam 		break;
719169Ssam 
729169Ssam 	case PRU_LISTEN:
739169Ssam 		if (unp->unp_inode == 0)
749169Ssam 			error = EINVAL;
759169Ssam 		break;
769169Ssam 
778925Sroot 	case PRU_CONNECT:
789028Sroot 		error = unp_connect(so, nam);
798925Sroot 		break;
808925Sroot 
8112760Ssam 	case PRU_CONNECT2:
8213115Ssam 		error = unp_connect2(so, (struct mbuf *)0,
8313115Ssam 		    (struct socket *)nam);
8412760Ssam 		break;
8512760Ssam 
868925Sroot 	case PRU_DISCONNECT:
878925Sroot 		unp_disconnect(unp);
888925Sroot 		break;
898925Sroot 
909169Ssam 	case PRU_ACCEPT:
919169Ssam 		nam->m_len = unp->unp_remaddr->m_len;
929169Ssam 		bcopy(mtod(unp->unp_remaddr, caddr_t),
939169Ssam 		    mtod(nam, caddr_t), (unsigned)nam->m_len);
948925Sroot 		break;
958925Sroot 
968925Sroot 	case PRU_SHUTDOWN:
978925Sroot 		socantsendmore(so);
988925Sroot 		unp_usrclosed(unp);
998925Sroot 		break;
1008925Sroot 
1018925Sroot 	case PRU_RCVD:
1028925Sroot 		switch (so->so_type) {
1038925Sroot 
1048925Sroot 		case SOCK_DGRAM:
1058925Sroot 			panic("uipc 1");
10610139Ssam 			/*NOTREACHED*/
1078925Sroot 
10810139Ssam 		case SOCK_STREAM:
1098925Sroot #define	rcv (&so->so_rcv)
1108925Sroot #define snd (&so2->so_snd)
1118925Sroot 			if (unp->unp_conn == 0)
1128925Sroot 				break;
1138925Sroot 			so2 = unp->unp_conn->unp_socket;
1148925Sroot 			/*
1158925Sroot 			 * Transfer resources back to send port
1168925Sroot 			 * and wakeup any waiting to write.
1178925Sroot 			 */
1188925Sroot 			snd->sb_mbmax += rcv->sb_mbmax - rcv->sb_mbcnt;
1198925Sroot 			rcv->sb_mbmax = rcv->sb_mbcnt;
1208925Sroot 			snd->sb_hiwat += rcv->sb_hiwat - rcv->sb_cc;
1218925Sroot 			rcv->sb_hiwat = rcv->sb_cc;
12217543Skarels 			sowwakeup(so2);
1238925Sroot #undef snd
1248925Sroot #undef rcv
1258925Sroot 			break;
1268925Sroot 
1278925Sroot 		default:
1288925Sroot 			panic("uipc 2");
1298925Sroot 		}
1308925Sroot 		break;
1318925Sroot 
1328925Sroot 	case PRU_SEND:
1338925Sroot 		switch (so->so_type) {
1348925Sroot 
1358925Sroot 		case SOCK_DGRAM:
1369028Sroot 			if (nam) {
1378925Sroot 				if (unp->unp_conn) {
1388925Sroot 					error = EISCONN;
1398925Sroot 					break;
1408925Sroot 				}
1419028Sroot 				error = unp_connect(so, nam);
1428925Sroot 				if (error)
1438925Sroot 					break;
1448925Sroot 			} else {
1458925Sroot 				if (unp->unp_conn == 0) {
1468925Sroot 					error = ENOTCONN;
1478925Sroot 					break;
1488925Sroot 				}
1498925Sroot 			}
1508925Sroot 			so2 = unp->unp_conn->unp_socket;
1519169Ssam 			/* BEGIN XXX */
15212760Ssam 			if (rights) {
15312760Ssam 				error = unp_internalize(rights);
15412760Ssam 				if (error)
15512760Ssam 					break;
15612760Ssam 			}
15712760Ssam 			if (sbspace(&so2->so_rcv) > 0) {
15813119Ssam 				/*
15913119Ssam 				 * There's no record of source socket's
16013119Ssam 				 * name, so send null name for the moment.
16113119Ssam 				 */
16217543Skarels 				if (sbappendaddr(&so2->so_rcv,
16317543Skarels 				    &sun_noname, m, rights)) {
16417543Skarels 					sorwakeup(so2);
16517543Skarels 					m = 0;
16623524Skarels 				} else
16723524Skarels 					error = ENOBUFS;
16812760Ssam 			}
1699169Ssam 			/* END XXX */
1709028Sroot 			if (nam)
1719169Ssam 				unp_disconnect(unp);
1728925Sroot 			break;
1738925Sroot 
1748925Sroot 		case SOCK_STREAM:
1758925Sroot #define	rcv (&so2->so_rcv)
1768925Sroot #define	snd (&so->so_snd)
17712760Ssam 			if (rights && rights->m_len) {
17812760Ssam 				error = EOPNOTSUPP;
17912760Ssam 				break;
18012760Ssam 			}
18123524Skarels 			if (so->so_state & SS_CANTSENDMORE) {
18223524Skarels 				error = EPIPE;
18323524Skarels 				break;
18423524Skarels 			}
1858925Sroot 			if (unp->unp_conn == 0)
1868925Sroot 				panic("uipc 3");
1878925Sroot 			so2 = unp->unp_conn->unp_socket;
1888925Sroot 			/*
1898925Sroot 			 * Send to paired receive port, and then
1908925Sroot 			 * give it enough resources to hold what it already has.
1918925Sroot 			 * Wake up readers.
1928925Sroot 			 */
1938925Sroot 			sbappend(rcv, m);
1948925Sroot 			snd->sb_mbmax -= rcv->sb_mbcnt - rcv->sb_mbmax;
1958925Sroot 			rcv->sb_mbmax = rcv->sb_mbcnt;
1968925Sroot 			snd->sb_hiwat -= rcv->sb_cc - rcv->sb_hiwat;
1978925Sroot 			rcv->sb_hiwat = rcv->sb_cc;
19817543Skarels 			sorwakeup(so2);
19917543Skarels 			m = 0;
2008925Sroot #undef snd
2018925Sroot #undef rcv
2028925Sroot 			break;
2038925Sroot 
2048925Sroot 		default:
2058925Sroot 			panic("uipc 4");
2068925Sroot 		}
2078925Sroot 		break;
2088925Sroot 
2098925Sroot 	case PRU_ABORT:
2108925Sroot 		unp_drop(unp, ECONNABORTED);
2118925Sroot 		break;
2128925Sroot 
2138925Sroot 	case PRU_SENSE:
21416973Skarels 		((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
21516973Skarels 		if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) {
21616973Skarels 			so2 = unp->unp_conn->unp_socket;
21716973Skarels 			((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc;
21816973Skarels 		}
21921110Skarels 		((struct stat *) m)->st_dev = NODEV;
22021110Skarels 		((struct stat *) m)->st_ino = unp_ino++;
22116973Skarels 		return (0);
2228925Sroot 
2238925Sroot 	case PRU_RCVOOB:
22416774Sbloom 		return (EOPNOTSUPP);
2258925Sroot 
2268925Sroot 	case PRU_SENDOOB:
22717543Skarels 		error = EOPNOTSUPP;
2288925Sroot 		break;
2298925Sroot 
2308925Sroot 	case PRU_SOCKADDR:
2318925Sroot 		break;
2328925Sroot 
23314121Ssam 	case PRU_PEERADDR:
23414121Ssam 		break;
23514121Ssam 
2368925Sroot 	case PRU_SLOWTIMO:
2378925Sroot 		break;
2388925Sroot 
2398925Sroot 	default:
2408925Sroot 		panic("piusrreq");
2418925Sroot 	}
24212760Ssam release:
24312760Ssam 	if (m)
24412760Ssam 		m_freem(m);
24511709Ssam 	return (error);
2468925Sroot }
2478925Sroot 
24816973Skarels /*
24916973Skarels  * We assign all buffering for stream sockets to the source,
25016973Skarels  * as that is where the flow control is implemented.
25116973Skarels  * Datagram sockets really use the sendspace as the maximum datagram size,
25216973Skarels  * and don't really want to reserve the sendspace.  Their recvspace should
25316973Skarels  * be large enough for at least one max-size datagram plus address.
25416973Skarels  */
25516973Skarels #define	PIPSIZ	4096
25616973Skarels int	unpst_sendspace = PIPSIZ;
25716973Skarels int	unpst_recvspace = 0;
25816973Skarels int	unpdg_sendspace = 2*1024;	/* really max datagram size */
25916973Skarels int	unpdg_recvspace = 4*1024;
2608925Sroot 
2619169Ssam unp_attach(so)
2628925Sroot 	struct socket *so;
2638925Sroot {
2649169Ssam 	register struct mbuf *m;
2658925Sroot 	register struct unpcb *unp;
2668925Sroot 	int error;
2678925Sroot 
26816973Skarels 	switch (so->so_type) {
26916973Skarels 
27016973Skarels 	case SOCK_STREAM:
27116973Skarels 		error = soreserve(so, unpst_sendspace, unpst_recvspace);
27216973Skarels 		break;
27316973Skarels 
27416973Skarels 	case SOCK_DGRAM:
27516973Skarels 		error = soreserve(so, unpdg_sendspace, unpdg_recvspace);
27616973Skarels 		break;
27716973Skarels 	}
2788925Sroot 	if (error)
27910139Ssam 		return (error);
2809637Ssam 	m = m_getclr(M_DONTWAIT, MT_PCB);
28110139Ssam 	if (m == NULL)
28210139Ssam 		return (ENOBUFS);
2838925Sroot 	unp = mtod(m, struct unpcb *);
2848925Sroot 	so->so_pcb = (caddr_t)unp;
2858925Sroot 	unp->unp_socket = so;
2868925Sroot 	return (0);
2878925Sroot }
2888925Sroot 
2898925Sroot unp_detach(unp)
2909169Ssam 	register struct unpcb *unp;
2918925Sroot {
2928925Sroot 
2938925Sroot 	if (unp->unp_inode) {
29417020Skarels 		unp->unp_inode->i_socket = 0;
2958925Sroot 		irele(unp->unp_inode);
2968925Sroot 		unp->unp_inode = 0;
2978925Sroot 	}
2988925Sroot 	if (unp->unp_conn)
2998925Sroot 		unp_disconnect(unp);
3008925Sroot 	while (unp->unp_refs)
3018925Sroot 		unp_drop(unp->unp_refs, ECONNRESET);
3028925Sroot 	soisdisconnected(unp->unp_socket);
3038925Sroot 	unp->unp_socket->so_pcb = 0;
3049169Ssam 	m_freem(unp->unp_remaddr);
3059169Ssam 	(void) m_free(dtom(unp));
3068925Sroot }
3078925Sroot 
3089169Ssam unp_bind(unp, nam)
3098925Sroot 	struct unpcb *unp;
3109169Ssam 	struct mbuf *nam;
3118925Sroot {
3129169Ssam 	struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
3138925Sroot 	register struct inode *ip;
31416695Smckusick 	register struct nameidata *ndp = &u.u_nd;
3158925Sroot 	int error;
3168925Sroot 
31716695Smckusick 	ndp->ni_dirp = soun->sun_path;
31825232Smckusick 	if (unp->unp_inode != NULL || nam->m_len == MLEN)
31912760Ssam 		return (EINVAL);
32012760Ssam 	*(mtod(nam, caddr_t) + nam->m_len) = 0;
32112760Ssam /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
32216695Smckusick 	ndp->ni_nameiop = CREATE | FOLLOW;
32316695Smckusick 	ndp->ni_segflg = UIO_SYSSPACE;
32416695Smckusick 	ip = namei(ndp);
3258925Sroot 	if (ip) {
3268925Sroot 		iput(ip);
32710139Ssam 		return (EADDRINUSE);
3288925Sroot 	}
32911828Ssam 	if (error = u.u_error) {
33011828Ssam 		u.u_error = 0;			/* XXX */
33111828Ssam 		return (error);
33211828Ssam 	}
33316695Smckusick 	ip = maknode(IFSOCK | 0777, ndp);
3348925Sroot 	if (ip == NULL) {
3358925Sroot 		error = u.u_error;		/* XXX */
3368925Sroot 		u.u_error = 0;			/* XXX */
3378925Sroot 		return (error);
3388925Sroot 	}
3398925Sroot 	ip->i_socket = unp->unp_socket;
3408925Sroot 	unp->unp_inode = ip;
3418925Sroot 	iunlock(ip);			/* but keep reference */
3428925Sroot 	return (0);
3438925Sroot }
3448925Sroot 
3459169Ssam unp_connect(so, nam)
3468925Sroot 	struct socket *so;
3479169Ssam 	struct mbuf *nam;
3488925Sroot {
3499169Ssam 	register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
3509169Ssam 	register struct inode *ip;
3518925Sroot 	int error;
35212760Ssam 	register struct socket *so2;
35316695Smckusick 	register struct nameidata *ndp = &u.u_nd;
3548925Sroot 
35516695Smckusick 	ndp->ni_dirp = soun->sun_path;
35612760Ssam 	if (nam->m_len + (nam->m_off - MMINOFF) == MLEN)
35712760Ssam 		return (EMSGSIZE);
35812760Ssam 	*(mtod(nam, caddr_t) + nam->m_len) = 0;
35916695Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
36016695Smckusick 	ndp->ni_segflg = UIO_SYSSPACE;
36116695Smckusick 	ip = namei(ndp);
3628925Sroot 	if (ip == 0) {
3638925Sroot 		error = u.u_error;
3648925Sroot 		u.u_error = 0;
36510139Ssam 		return (error);		/* XXX */
3668925Sroot 	}
36717543Skarels 	if (access(ip, IWRITE)) {
36817543Skarels 		error = u.u_error;
36917543Skarels 		u.u_error = 0; 		/* XXX */
37017543Skarels 		goto bad;
37117543Skarels 	}
3728925Sroot 	if ((ip->i_mode&IFMT) != IFSOCK) {
3738925Sroot 		error = ENOTSOCK;
3748925Sroot 		goto bad;
3758925Sroot 	}
3768925Sroot 	so2 = ip->i_socket;
3778925Sroot 	if (so2 == 0) {
3788925Sroot 		error = ECONNREFUSED;
3798925Sroot 		goto bad;
3808925Sroot 	}
38113115Ssam 	if (so->so_type != so2->so_type) {
38213115Ssam 		error = EPROTOTYPE;
38313115Ssam 		goto bad;
38413115Ssam 	}
38513115Ssam 	if (so->so_proto->pr_flags & PR_CONNREQUIRED &&
38613115Ssam 	    ((so2->so_options&SO_ACCEPTCONN) == 0 ||
38713115Ssam 	     (so2 = sonewconn(so2)) == 0)) {
38813115Ssam 		error = ECONNREFUSED;
38913115Ssam 		goto bad;
39013115Ssam 	}
39112760Ssam 	error = unp_connect2(so, nam, so2);
39212760Ssam bad:
39312760Ssam 	iput(ip);
39412760Ssam 	return (error);
39512760Ssam }
39612760Ssam 
39712760Ssam unp_connect2(so, sonam, so2)
39812760Ssam 	register struct socket *so;
39912760Ssam 	struct mbuf *sonam;
40012760Ssam 	register struct socket *so2;
40112760Ssam {
40212760Ssam 	register struct unpcb *unp = sotounpcb(so);
40312760Ssam 	register struct unpcb *unp2;
40412760Ssam 
40512760Ssam 	if (so2->so_type != so->so_type)
40612760Ssam 		return (EPROTOTYPE);
40714049Ssam 	unp2 = sotounpcb(so2);
40814049Ssam 	unp->unp_conn = unp2;
4098925Sroot 	switch (so->so_type) {
4108925Sroot 
4118925Sroot 	case SOCK_DGRAM:
4128925Sroot 		unp->unp_nextref = unp2->unp_refs;
4138925Sroot 		unp2->unp_refs = unp;
41417543Skarels 		soisconnected(so);
4158925Sroot 		break;
4168925Sroot 
4178925Sroot 	case SOCK_STREAM:
4189169Ssam 		unp2->unp_conn = unp;
41912760Ssam 		if (sonam)
42012760Ssam 			unp2->unp_remaddr = m_copy(sonam, 0, (int)M_COPYALL);
42114049Ssam 		soisconnected(so2);
42214049Ssam 		soisconnected(so);
4238925Sroot 		break;
4248925Sroot 
4258925Sroot 	default:
42612760Ssam 		panic("unp_connect2");
4278925Sroot 	}
4288925Sroot 	return (0);
4298925Sroot }
4309169Ssam 
4319169Ssam unp_disconnect(unp)
4329169Ssam 	struct unpcb *unp;
4339169Ssam {
4349169Ssam 	register struct unpcb *unp2 = unp->unp_conn;
4359169Ssam 
4369169Ssam 	if (unp2 == 0)
4379169Ssam 		return;
4389169Ssam 	unp->unp_conn = 0;
4399169Ssam 	switch (unp->unp_socket->so_type) {
4409169Ssam 
4419169Ssam 	case SOCK_DGRAM:
4429169Ssam 		if (unp2->unp_refs == unp)
4439169Ssam 			unp2->unp_refs = unp->unp_nextref;
4449169Ssam 		else {
4459169Ssam 			unp2 = unp2->unp_refs;
4469169Ssam 			for (;;) {
4479169Ssam 				if (unp2 == 0)
4489169Ssam 					panic("unp_disconnect");
4499169Ssam 				if (unp2->unp_nextref == unp)
4509169Ssam 					break;
4519169Ssam 				unp2 = unp2->unp_nextref;
4529169Ssam 			}
4539169Ssam 			unp2->unp_nextref = unp->unp_nextref;
4549169Ssam 		}
4559169Ssam 		unp->unp_nextref = 0;
45621768Skarels 		unp->unp_socket->so_state &= ~SS_ISCONNECTED;
4579169Ssam 		break;
4589169Ssam 
4599169Ssam 	case SOCK_STREAM:
46014049Ssam 		soisdisconnected(unp->unp_socket);
4619169Ssam 		unp2->unp_conn = 0;
4629169Ssam 		soisdisconnected(unp2->unp_socket);
4639169Ssam 		break;
4649169Ssam 	}
4659169Ssam }
4669169Ssam 
46712760Ssam #ifdef notdef
4689169Ssam unp_abort(unp)
4699169Ssam 	struct unpcb *unp;
4709169Ssam {
4719169Ssam 
4729169Ssam 	unp_detach(unp);
4739169Ssam }
47412760Ssam #endif
4759169Ssam 
4769169Ssam /*ARGSUSED*/
4779169Ssam unp_usrclosed(unp)
4789169Ssam 	struct unpcb *unp;
4799169Ssam {
4809169Ssam 
4819169Ssam }
4829169Ssam 
4839169Ssam unp_drop(unp, errno)
4849169Ssam 	struct unpcb *unp;
4859169Ssam 	int errno;
4869169Ssam {
48716054Skarels 	struct socket *so = unp->unp_socket;
4889169Ssam 
48916054Skarels 	so->so_error = errno;
4909169Ssam 	unp_disconnect(unp);
49116054Skarels 	if (so->so_head) {
49216054Skarels 		so->so_pcb = (caddr_t) 0;
49316431Skarels 		m_freem(unp->unp_remaddr);
49416054Skarels 		(void) m_free(dtom(unp));
49516054Skarels 		sofree(so);
49616054Skarels 	}
4979169Ssam }
4989169Ssam 
49912760Ssam #ifdef notdef
5009169Ssam unp_drain()
5019169Ssam {
5029169Ssam 
5039169Ssam }
50412760Ssam #endif
50512760Ssam 
50612760Ssam unp_externalize(rights)
50712760Ssam 	struct mbuf *rights;
50812760Ssam {
50912760Ssam 	int newfds = rights->m_len / sizeof (int);
51012760Ssam 	register int i;
51112760Ssam 	register struct file **rp = mtod(rights, struct file **);
51212760Ssam 	register struct file *fp;
51312760Ssam 	int f;
51412760Ssam 
51512760Ssam 	if (newfds > ufavail()) {
51612760Ssam 		for (i = 0; i < newfds; i++) {
51712760Ssam 			fp = *rp;
51812760Ssam 			unp_discard(fp);
51912760Ssam 			*rp++ = 0;
52012760Ssam 		}
52112760Ssam 		return (EMSGSIZE);
52212760Ssam 	}
52312760Ssam 	for (i = 0; i < newfds; i++) {
52412760Ssam 		f = ufalloc(0);
52512760Ssam 		if (f < 0)
52612760Ssam 			panic("unp_externalize");
52712760Ssam 		fp = *rp;
52812760Ssam 		u.u_ofile[f] = fp;
52912760Ssam 		fp->f_msgcount--;
53014927Smckusick 		*(int *)rp++ = f;
53112760Ssam 	}
53212760Ssam 	return (0);
53312760Ssam }
53412760Ssam 
53512760Ssam unp_internalize(rights)
53612760Ssam 	struct mbuf *rights;
53712760Ssam {
53812760Ssam 	register struct file **rp;
53912760Ssam 	int oldfds = rights->m_len / sizeof (int);
54012760Ssam 	register int i;
54112760Ssam 	register struct file *fp;
54212760Ssam 
54312760Ssam 	rp = mtod(rights, struct file **);
54413084Ssam 	for (i = 0; i < oldfds; i++)
54512760Ssam 		if (getf(*(int *)rp++) == 0)
54612760Ssam 			return (EBADF);
54712760Ssam 	rp = mtod(rights, struct file **);
54813084Ssam 	for (i = 0; i < oldfds; i++) {
54912760Ssam 		fp = getf(*(int *)rp);
55012760Ssam 		*rp++ = fp;
55112760Ssam 		fp->f_count++;
55212760Ssam 		fp->f_msgcount++;
55312760Ssam 	}
55412760Ssam 	return (0);
55512760Ssam }
55612760Ssam 
55712760Ssam int	unp_defer, unp_gcing;
55812760Ssam int	unp_mark();
55916995Skarels extern	struct domain unixdomain;
56012760Ssam 
56112760Ssam unp_gc()
56212760Ssam {
56312760Ssam 	register struct file *fp;
56412760Ssam 	register struct socket *so;
56512760Ssam 
56612760Ssam 	if (unp_gcing)
56712760Ssam 		return;
56812760Ssam 	unp_gcing = 1;
56912760Ssam restart:
57012760Ssam 	unp_defer = 0;
57112760Ssam 	for (fp = file; fp < fileNFILE; fp++)
57212760Ssam 		fp->f_flag &= ~(FMARK|FDEFER);
57312760Ssam 	do {
57412760Ssam 		for (fp = file; fp < fileNFILE; fp++) {
57512760Ssam 			if (fp->f_count == 0)
57612760Ssam 				continue;
57712760Ssam 			if (fp->f_flag & FDEFER) {
57812760Ssam 				fp->f_flag &= ~FDEFER;
57912760Ssam 				unp_defer--;
58012760Ssam 			} else {
58112760Ssam 				if (fp->f_flag & FMARK)
58212760Ssam 					continue;
58312760Ssam 				if (fp->f_count == fp->f_msgcount)
58412760Ssam 					continue;
58512760Ssam 				fp->f_flag |= FMARK;
58612760Ssam 			}
58712760Ssam 			if (fp->f_type != DTYPE_SOCKET)
58812760Ssam 				continue;
58912760Ssam 			so = (struct socket *)fp->f_data;
59016995Skarels 			if (so->so_proto->pr_domain != &unixdomain ||
59121768Skarels 			    (so->so_proto->pr_flags&PR_RIGHTS) == 0)
59212760Ssam 				continue;
59312760Ssam 			if (so->so_rcv.sb_flags & SB_LOCK) {
59412760Ssam 				sbwait(&so->so_rcv);
59512760Ssam 				goto restart;
59612760Ssam 			}
59712760Ssam 			unp_scan(so->so_rcv.sb_mb, unp_mark);
59812760Ssam 		}
59912760Ssam 	} while (unp_defer);
60012760Ssam 	for (fp = file; fp < fileNFILE; fp++) {
60112760Ssam 		if (fp->f_count == 0)
60212760Ssam 			continue;
60312760Ssam 		if (fp->f_count == fp->f_msgcount && (fp->f_flag&FMARK)==0) {
60412760Ssam 			if (fp->f_type != DTYPE_SOCKET)
60512760Ssam 				panic("unp_gc");
60612760Ssam 			(void) soshutdown((struct socket *)fp->f_data, 0);
60712760Ssam 		}
60812760Ssam 	}
60912760Ssam 	unp_gcing = 0;
61012760Ssam }
61112760Ssam 
61216995Skarels unp_dispose(m)
61316995Skarels 	struct mbuf *m;
61416995Skarels {
61516995Skarels 	int unp_discard();
61616995Skarels 
61717020Skarels 	if (m)
61817020Skarels 		unp_scan(m, unp_discard);
61916995Skarels }
62016995Skarels 
62116995Skarels unp_scan(m0, op)
62216995Skarels 	register struct mbuf *m0;
62312760Ssam 	int (*op)();
62412760Ssam {
62516995Skarels 	register struct mbuf *m;
62612760Ssam 	register struct file **rp;
62712760Ssam 	register int i;
62817020Skarels 	int qfds;
62912760Ssam 
63016995Skarels 	while (m0) {
63116995Skarels 		for (m = m0; m; m = m->m_next)
63216995Skarels 			if (m->m_type == MT_RIGHTS && m->m_len) {
63316995Skarels 				qfds = m->m_len / sizeof (struct file *);
63416995Skarels 				rp = mtod(m, struct file **);
63516995Skarels 				for (i = 0; i < qfds; i++)
63616995Skarels 					(*op)(*rp++);
63716995Skarels 				break;		/* XXX, but saves time */
63816995Skarels 			}
63917020Skarels 		m0 = m0->m_act;
64012760Ssam 	}
64112760Ssam }
64212760Ssam 
64312760Ssam unp_mark(fp)
64412760Ssam 	struct file *fp;
64512760Ssam {
64612760Ssam 
64712760Ssam 	if (fp->f_flag & FMARK)
64812760Ssam 		return;
64912760Ssam 	unp_defer++;
65012760Ssam 	fp->f_flag |= (FMARK|FDEFER);
65112760Ssam }
65212760Ssam 
65312760Ssam unp_discard(fp)
65412760Ssam 	struct file *fp;
65512760Ssam {
65612760Ssam 
65712760Ssam 	fp->f_msgcount--;
65813084Ssam 	closef(fp);
65912760Ssam }
660