xref: /csrg-svn/sys/kern/uipc_usrreq.c (revision 25232)
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*25232Smckusick  *	@(#)uipc_usrreq.c	6.16 (Berkeley) 10/18/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 
4412760Ssam 	if (req != PRU_SEND && rights && rights->m_len) {
4512760Ssam 		error = EOPNOTSUPP;
4612760Ssam 		goto release;
4712760Ssam 	}
4812760Ssam 	if (unp == 0 && req != PRU_ATTACH) {
4912760Ssam 		error = EINVAL;
5012760Ssam 		goto release;
5112760Ssam 	}
528925Sroot 	switch (req) {
538925Sroot 
548925Sroot 	case PRU_ATTACH:
558925Sroot 		if (unp) {
569169Ssam 			error = EISCONN;
578925Sroot 			break;
588925Sroot 		}
599028Sroot 		error = unp_attach(so);
608925Sroot 		break;
618925Sroot 
628925Sroot 	case PRU_DETACH:
638925Sroot 		unp_detach(unp);
648925Sroot 		break;
658925Sroot 
669169Ssam 	case PRU_BIND:
679169Ssam 		error = unp_bind(unp, nam);
689169Ssam 		break;
699169Ssam 
709169Ssam 	case PRU_LISTEN:
719169Ssam 		if (unp->unp_inode == 0)
729169Ssam 			error = EINVAL;
739169Ssam 		break;
749169Ssam 
758925Sroot 	case PRU_CONNECT:
769028Sroot 		error = unp_connect(so, nam);
778925Sroot 		break;
788925Sroot 
7912760Ssam 	case PRU_CONNECT2:
8013115Ssam 		error = unp_connect2(so, (struct mbuf *)0,
8113115Ssam 		    (struct socket *)nam);
8212760Ssam 		break;
8312760Ssam 
848925Sroot 	case PRU_DISCONNECT:
858925Sroot 		unp_disconnect(unp);
868925Sroot 		break;
878925Sroot 
889169Ssam 	case PRU_ACCEPT:
899169Ssam 		nam->m_len = unp->unp_remaddr->m_len;
909169Ssam 		bcopy(mtod(unp->unp_remaddr, caddr_t),
919169Ssam 		    mtod(nam, caddr_t), (unsigned)nam->m_len);
928925Sroot 		break;
938925Sroot 
948925Sroot 	case PRU_SHUTDOWN:
958925Sroot 		socantsendmore(so);
968925Sroot 		unp_usrclosed(unp);
978925Sroot 		break;
988925Sroot 
998925Sroot 	case PRU_RCVD:
1008925Sroot 		switch (so->so_type) {
1018925Sroot 
1028925Sroot 		case SOCK_DGRAM:
1038925Sroot 			panic("uipc 1");
10410139Ssam 			/*NOTREACHED*/
1058925Sroot 
10610139Ssam 		case SOCK_STREAM:
1078925Sroot #define	rcv (&so->so_rcv)
1088925Sroot #define snd (&so2->so_snd)
1098925Sroot 			if (unp->unp_conn == 0)
1108925Sroot 				break;
1118925Sroot 			so2 = unp->unp_conn->unp_socket;
1128925Sroot 			/*
1138925Sroot 			 * Transfer resources back to send port
1148925Sroot 			 * and wakeup any waiting to write.
1158925Sroot 			 */
1168925Sroot 			snd->sb_mbmax += rcv->sb_mbmax - rcv->sb_mbcnt;
1178925Sroot 			rcv->sb_mbmax = rcv->sb_mbcnt;
1188925Sroot 			snd->sb_hiwat += rcv->sb_hiwat - rcv->sb_cc;
1198925Sroot 			rcv->sb_hiwat = rcv->sb_cc;
12017543Skarels 			sowwakeup(so2);
1218925Sroot #undef snd
1228925Sroot #undef rcv
1238925Sroot 			break;
1248925Sroot 
1258925Sroot 		default:
1268925Sroot 			panic("uipc 2");
1278925Sroot 		}
1288925Sroot 		break;
1298925Sroot 
1308925Sroot 	case PRU_SEND:
1318925Sroot 		switch (so->so_type) {
1328925Sroot 
1338925Sroot 		case SOCK_DGRAM:
1349028Sroot 			if (nam) {
1358925Sroot 				if (unp->unp_conn) {
1368925Sroot 					error = EISCONN;
1378925Sroot 					break;
1388925Sroot 				}
1399028Sroot 				error = unp_connect(so, nam);
1408925Sroot 				if (error)
1418925Sroot 					break;
1428925Sroot 			} else {
1438925Sroot 				if (unp->unp_conn == 0) {
1448925Sroot 					error = ENOTCONN;
1458925Sroot 					break;
1468925Sroot 				}
1478925Sroot 			}
1488925Sroot 			so2 = unp->unp_conn->unp_socket;
1499169Ssam 			/* BEGIN XXX */
15012760Ssam 			if (rights) {
15112760Ssam 				error = unp_internalize(rights);
15212760Ssam 				if (error)
15312760Ssam 					break;
15412760Ssam 			}
15512760Ssam 			if (sbspace(&so2->so_rcv) > 0) {
15613119Ssam 				/*
15713119Ssam 				 * There's no record of source socket's
15813119Ssam 				 * name, so send null name for the moment.
15913119Ssam 				 */
16017543Skarels 				if (sbappendaddr(&so2->so_rcv,
16117543Skarels 				    &sun_noname, m, rights)) {
16217543Skarels 					sorwakeup(so2);
16317543Skarels 					m = 0;
16423524Skarels 				} else
16523524Skarels 					error = ENOBUFS;
16612760Ssam 			}
1679169Ssam 			/* END XXX */
1689028Sroot 			if (nam)
1699169Ssam 				unp_disconnect(unp);
1708925Sroot 			break;
1718925Sroot 
1728925Sroot 		case SOCK_STREAM:
1738925Sroot #define	rcv (&so2->so_rcv)
1748925Sroot #define	snd (&so->so_snd)
17512760Ssam 			if (rights && rights->m_len) {
17612760Ssam 				error = EOPNOTSUPP;
17712760Ssam 				break;
17812760Ssam 			}
17923524Skarels 			if (so->so_state & SS_CANTSENDMORE) {
18023524Skarels 				error = EPIPE;
18123524Skarels 				break;
18223524Skarels 			}
1838925Sroot 			if (unp->unp_conn == 0)
1848925Sroot 				panic("uipc 3");
1858925Sroot 			so2 = unp->unp_conn->unp_socket;
1868925Sroot 			/*
1878925Sroot 			 * Send to paired receive port, and then
1888925Sroot 			 * give it enough resources to hold what it already has.
1898925Sroot 			 * Wake up readers.
1908925Sroot 			 */
1918925Sroot 			sbappend(rcv, m);
1928925Sroot 			snd->sb_mbmax -= rcv->sb_mbcnt - rcv->sb_mbmax;
1938925Sroot 			rcv->sb_mbmax = rcv->sb_mbcnt;
1948925Sroot 			snd->sb_hiwat -= rcv->sb_cc - rcv->sb_hiwat;
1958925Sroot 			rcv->sb_hiwat = rcv->sb_cc;
19617543Skarels 			sorwakeup(so2);
19717543Skarels 			m = 0;
1988925Sroot #undef snd
1998925Sroot #undef rcv
2008925Sroot 			break;
2018925Sroot 
2028925Sroot 		default:
2038925Sroot 			panic("uipc 4");
2048925Sroot 		}
2058925Sroot 		break;
2068925Sroot 
2078925Sroot 	case PRU_ABORT:
2088925Sroot 		unp_drop(unp, ECONNABORTED);
2098925Sroot 		break;
2108925Sroot 
2118925Sroot /* SOME AS YET UNIMPLEMENTED HOOKS */
2128925Sroot 	case PRU_CONTROL:
21313050Ssam 		return (EOPNOTSUPP);
2148925Sroot 
21516973Skarels /* END UNIMPLEMENTED HOOKS */
2168925Sroot 	case PRU_SENSE:
21716973Skarels 		((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
21816973Skarels 		if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) {
21916973Skarels 			so2 = unp->unp_conn->unp_socket;
22016973Skarels 			((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc;
22116973Skarels 		}
22221110Skarels 		((struct stat *) m)->st_dev = NODEV;
22321110Skarels 		((struct stat *) m)->st_ino = unp_ino++;
22416973Skarels 		return (0);
2258925Sroot 
2268925Sroot 	case PRU_RCVOOB:
22716774Sbloom 		return (EOPNOTSUPP);
2288925Sroot 
2298925Sroot 	case PRU_SENDOOB:
23017543Skarels 		error = EOPNOTSUPP;
2318925Sroot 		break;
2328925Sroot 
2338925Sroot 	case PRU_SOCKADDR:
2348925Sroot 		break;
2358925Sroot 
23614121Ssam 	case PRU_PEERADDR:
23714121Ssam 		break;
23814121Ssam 
2398925Sroot 	case PRU_SLOWTIMO:
2408925Sroot 		break;
2418925Sroot 
2428925Sroot 	default:
2438925Sroot 		panic("piusrreq");
2448925Sroot 	}
24512760Ssam release:
24612760Ssam 	if (m)
24712760Ssam 		m_freem(m);
24811709Ssam 	return (error);
2498925Sroot }
2508925Sroot 
25116973Skarels /*
25216973Skarels  * We assign all buffering for stream sockets to the source,
25316973Skarels  * as that is where the flow control is implemented.
25416973Skarels  * Datagram sockets really use the sendspace as the maximum datagram size,
25516973Skarels  * and don't really want to reserve the sendspace.  Their recvspace should
25616973Skarels  * be large enough for at least one max-size datagram plus address.
25716973Skarels  */
25816973Skarels #define	PIPSIZ	4096
25916973Skarels int	unpst_sendspace = PIPSIZ;
26016973Skarels int	unpst_recvspace = 0;
26116973Skarels int	unpdg_sendspace = 2*1024;	/* really max datagram size */
26216973Skarels int	unpdg_recvspace = 4*1024;
2638925Sroot 
2649169Ssam unp_attach(so)
2658925Sroot 	struct socket *so;
2668925Sroot {
2679169Ssam 	register struct mbuf *m;
2688925Sroot 	register struct unpcb *unp;
2698925Sroot 	int error;
2708925Sroot 
27116973Skarels 	switch (so->so_type) {
27216973Skarels 
27316973Skarels 	case SOCK_STREAM:
27416973Skarels 		error = soreserve(so, unpst_sendspace, unpst_recvspace);
27516973Skarels 		break;
27616973Skarels 
27716973Skarels 	case SOCK_DGRAM:
27816973Skarels 		error = soreserve(so, unpdg_sendspace, unpdg_recvspace);
27916973Skarels 		break;
28016973Skarels 	}
2818925Sroot 	if (error)
28210139Ssam 		return (error);
2839637Ssam 	m = m_getclr(M_DONTWAIT, MT_PCB);
28410139Ssam 	if (m == NULL)
28510139Ssam 		return (ENOBUFS);
2868925Sroot 	unp = mtod(m, struct unpcb *);
2878925Sroot 	so->so_pcb = (caddr_t)unp;
2888925Sroot 	unp->unp_socket = so;
2898925Sroot 	return (0);
2908925Sroot }
2918925Sroot 
2928925Sroot unp_detach(unp)
2939169Ssam 	register struct unpcb *unp;
2948925Sroot {
2958925Sroot 
2968925Sroot 	if (unp->unp_inode) {
29717020Skarels 		unp->unp_inode->i_socket = 0;
2988925Sroot 		irele(unp->unp_inode);
2998925Sroot 		unp->unp_inode = 0;
3008925Sroot 	}
3018925Sroot 	if (unp->unp_conn)
3028925Sroot 		unp_disconnect(unp);
3038925Sroot 	while (unp->unp_refs)
3048925Sroot 		unp_drop(unp->unp_refs, ECONNRESET);
3058925Sroot 	soisdisconnected(unp->unp_socket);
3068925Sroot 	unp->unp_socket->so_pcb = 0;
3079169Ssam 	m_freem(unp->unp_remaddr);
3089169Ssam 	(void) m_free(dtom(unp));
3098925Sroot }
3108925Sroot 
3119169Ssam unp_bind(unp, nam)
3128925Sroot 	struct unpcb *unp;
3139169Ssam 	struct mbuf *nam;
3148925Sroot {
3159169Ssam 	struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
3168925Sroot 	register struct inode *ip;
31716695Smckusick 	register struct nameidata *ndp = &u.u_nd;
3188925Sroot 	int error;
3198925Sroot 
32016695Smckusick 	ndp->ni_dirp = soun->sun_path;
321*25232Smckusick 	if (unp->unp_inode != NULL || nam->m_len == MLEN)
32212760Ssam 		return (EINVAL);
32312760Ssam 	*(mtod(nam, caddr_t) + nam->m_len) = 0;
32412760Ssam /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
32516695Smckusick 	ndp->ni_nameiop = CREATE | FOLLOW;
32616695Smckusick 	ndp->ni_segflg = UIO_SYSSPACE;
32716695Smckusick 	ip = namei(ndp);
3288925Sroot 	if (ip) {
3298925Sroot 		iput(ip);
33010139Ssam 		return (EADDRINUSE);
3318925Sroot 	}
33211828Ssam 	if (error = u.u_error) {
33311828Ssam 		u.u_error = 0;			/* XXX */
33411828Ssam 		return (error);
33511828Ssam 	}
33616695Smckusick 	ip = maknode(IFSOCK | 0777, ndp);
3378925Sroot 	if (ip == NULL) {
3388925Sroot 		error = u.u_error;		/* XXX */
3398925Sroot 		u.u_error = 0;			/* XXX */
3408925Sroot 		return (error);
3418925Sroot 	}
3428925Sroot 	ip->i_socket = unp->unp_socket;
3438925Sroot 	unp->unp_inode = ip;
3448925Sroot 	iunlock(ip);			/* but keep reference */
3458925Sroot 	return (0);
3468925Sroot }
3478925Sroot 
3489169Ssam unp_connect(so, nam)
3498925Sroot 	struct socket *so;
3509169Ssam 	struct mbuf *nam;
3518925Sroot {
3529169Ssam 	register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
3539169Ssam 	register struct inode *ip;
3548925Sroot 	int error;
35512760Ssam 	register struct socket *so2;
35616695Smckusick 	register struct nameidata *ndp = &u.u_nd;
3578925Sroot 
35816695Smckusick 	ndp->ni_dirp = soun->sun_path;
35912760Ssam 	if (nam->m_len + (nam->m_off - MMINOFF) == MLEN)
36012760Ssam 		return (EMSGSIZE);
36112760Ssam 	*(mtod(nam, caddr_t) + nam->m_len) = 0;
36216695Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
36316695Smckusick 	ndp->ni_segflg = UIO_SYSSPACE;
36416695Smckusick 	ip = namei(ndp);
3658925Sroot 	if (ip == 0) {
3668925Sroot 		error = u.u_error;
3678925Sroot 		u.u_error = 0;
36810139Ssam 		return (error);		/* XXX */
3698925Sroot 	}
37017543Skarels 	if (access(ip, IWRITE)) {
37117543Skarels 		error = u.u_error;
37217543Skarels 		u.u_error = 0; 		/* XXX */
37317543Skarels 		goto bad;
37417543Skarels 	}
3758925Sroot 	if ((ip->i_mode&IFMT) != IFSOCK) {
3768925Sroot 		error = ENOTSOCK;
3778925Sroot 		goto bad;
3788925Sroot 	}
3798925Sroot 	so2 = ip->i_socket;
3808925Sroot 	if (so2 == 0) {
3818925Sroot 		error = ECONNREFUSED;
3828925Sroot 		goto bad;
3838925Sroot 	}
38413115Ssam 	if (so->so_type != so2->so_type) {
38513115Ssam 		error = EPROTOTYPE;
38613115Ssam 		goto bad;
38713115Ssam 	}
38813115Ssam 	if (so->so_proto->pr_flags & PR_CONNREQUIRED &&
38913115Ssam 	    ((so2->so_options&SO_ACCEPTCONN) == 0 ||
39013115Ssam 	     (so2 = sonewconn(so2)) == 0)) {
39113115Ssam 		error = ECONNREFUSED;
39213115Ssam 		goto bad;
39313115Ssam 	}
39412760Ssam 	error = unp_connect2(so, nam, so2);
39512760Ssam bad:
39612760Ssam 	iput(ip);
39712760Ssam 	return (error);
39812760Ssam }
39912760Ssam 
40012760Ssam unp_connect2(so, sonam, so2)
40112760Ssam 	register struct socket *so;
40212760Ssam 	struct mbuf *sonam;
40312760Ssam 	register struct socket *so2;
40412760Ssam {
40512760Ssam 	register struct unpcb *unp = sotounpcb(so);
40612760Ssam 	register struct unpcb *unp2;
40712760Ssam 
40812760Ssam 	if (so2->so_type != so->so_type)
40912760Ssam 		return (EPROTOTYPE);
41014049Ssam 	unp2 = sotounpcb(so2);
41114049Ssam 	unp->unp_conn = unp2;
4128925Sroot 	switch (so->so_type) {
4138925Sroot 
4148925Sroot 	case SOCK_DGRAM:
4158925Sroot 		unp->unp_nextref = unp2->unp_refs;
4168925Sroot 		unp2->unp_refs = unp;
41717543Skarels 		soisconnected(so);
4188925Sroot 		break;
4198925Sroot 
4208925Sroot 	case SOCK_STREAM:
4219169Ssam 		unp2->unp_conn = unp;
42212760Ssam 		if (sonam)
42312760Ssam 			unp2->unp_remaddr = m_copy(sonam, 0, (int)M_COPYALL);
42414049Ssam 		soisconnected(so2);
42514049Ssam 		soisconnected(so);
4268925Sroot 		break;
4278925Sroot 
4288925Sroot 	default:
42912760Ssam 		panic("unp_connect2");
4308925Sroot 	}
4318925Sroot 	return (0);
4328925Sroot }
4339169Ssam 
4349169Ssam unp_disconnect(unp)
4359169Ssam 	struct unpcb *unp;
4369169Ssam {
4379169Ssam 	register struct unpcb *unp2 = unp->unp_conn;
4389169Ssam 
4399169Ssam 	if (unp2 == 0)
4409169Ssam 		return;
4419169Ssam 	unp->unp_conn = 0;
4429169Ssam 	switch (unp->unp_socket->so_type) {
4439169Ssam 
4449169Ssam 	case SOCK_DGRAM:
4459169Ssam 		if (unp2->unp_refs == unp)
4469169Ssam 			unp2->unp_refs = unp->unp_nextref;
4479169Ssam 		else {
4489169Ssam 			unp2 = unp2->unp_refs;
4499169Ssam 			for (;;) {
4509169Ssam 				if (unp2 == 0)
4519169Ssam 					panic("unp_disconnect");
4529169Ssam 				if (unp2->unp_nextref == unp)
4539169Ssam 					break;
4549169Ssam 				unp2 = unp2->unp_nextref;
4559169Ssam 			}
4569169Ssam 			unp2->unp_nextref = unp->unp_nextref;
4579169Ssam 		}
4589169Ssam 		unp->unp_nextref = 0;
45921768Skarels 		unp->unp_socket->so_state &= ~SS_ISCONNECTED;
4609169Ssam 		break;
4619169Ssam 
4629169Ssam 	case SOCK_STREAM:
46314049Ssam 		soisdisconnected(unp->unp_socket);
4649169Ssam 		unp2->unp_conn = 0;
4659169Ssam 		soisdisconnected(unp2->unp_socket);
4669169Ssam 		break;
4679169Ssam 	}
4689169Ssam }
4699169Ssam 
47012760Ssam #ifdef notdef
4719169Ssam unp_abort(unp)
4729169Ssam 	struct unpcb *unp;
4739169Ssam {
4749169Ssam 
4759169Ssam 	unp_detach(unp);
4769169Ssam }
47712760Ssam #endif
4789169Ssam 
4799169Ssam /*ARGSUSED*/
4809169Ssam unp_usrclosed(unp)
4819169Ssam 	struct unpcb *unp;
4829169Ssam {
4839169Ssam 
4849169Ssam }
4859169Ssam 
4869169Ssam unp_drop(unp, errno)
4879169Ssam 	struct unpcb *unp;
4889169Ssam 	int errno;
4899169Ssam {
49016054Skarels 	struct socket *so = unp->unp_socket;
4919169Ssam 
49216054Skarels 	so->so_error = errno;
4939169Ssam 	unp_disconnect(unp);
49416054Skarels 	if (so->so_head) {
49516054Skarels 		so->so_pcb = (caddr_t) 0;
49616431Skarels 		m_freem(unp->unp_remaddr);
49716054Skarels 		(void) m_free(dtom(unp));
49816054Skarels 		sofree(so);
49916054Skarels 	}
5009169Ssam }
5019169Ssam 
50212760Ssam #ifdef notdef
5039169Ssam unp_drain()
5049169Ssam {
5059169Ssam 
5069169Ssam }
50712760Ssam #endif
50812760Ssam 
50912760Ssam unp_externalize(rights)
51012760Ssam 	struct mbuf *rights;
51112760Ssam {
51212760Ssam 	int newfds = rights->m_len / sizeof (int);
51312760Ssam 	register int i;
51412760Ssam 	register struct file **rp = mtod(rights, struct file **);
51512760Ssam 	register struct file *fp;
51612760Ssam 	int f;
51712760Ssam 
51812760Ssam 	if (newfds > ufavail()) {
51912760Ssam 		for (i = 0; i < newfds; i++) {
52012760Ssam 			fp = *rp;
52112760Ssam 			unp_discard(fp);
52212760Ssam 			*rp++ = 0;
52312760Ssam 		}
52412760Ssam 		return (EMSGSIZE);
52512760Ssam 	}
52612760Ssam 	for (i = 0; i < newfds; i++) {
52712760Ssam 		f = ufalloc(0);
52812760Ssam 		if (f < 0)
52912760Ssam 			panic("unp_externalize");
53012760Ssam 		fp = *rp;
53112760Ssam 		u.u_ofile[f] = fp;
53212760Ssam 		fp->f_msgcount--;
53314927Smckusick 		*(int *)rp++ = f;
53412760Ssam 	}
53512760Ssam 	return (0);
53612760Ssam }
53712760Ssam 
53812760Ssam unp_internalize(rights)
53912760Ssam 	struct mbuf *rights;
54012760Ssam {
54112760Ssam 	register struct file **rp;
54212760Ssam 	int oldfds = rights->m_len / sizeof (int);
54312760Ssam 	register int i;
54412760Ssam 	register struct file *fp;
54512760Ssam 
54612760Ssam 	rp = mtod(rights, struct file **);
54713084Ssam 	for (i = 0; i < oldfds; i++)
54812760Ssam 		if (getf(*(int *)rp++) == 0)
54912760Ssam 			return (EBADF);
55012760Ssam 	rp = mtod(rights, struct file **);
55113084Ssam 	for (i = 0; i < oldfds; i++) {
55212760Ssam 		fp = getf(*(int *)rp);
55312760Ssam 		*rp++ = fp;
55412760Ssam 		fp->f_count++;
55512760Ssam 		fp->f_msgcount++;
55612760Ssam 	}
55712760Ssam 	return (0);
55812760Ssam }
55912760Ssam 
56012760Ssam int	unp_defer, unp_gcing;
56112760Ssam int	unp_mark();
56216995Skarels extern	struct domain unixdomain;
56312760Ssam 
56412760Ssam unp_gc()
56512760Ssam {
56612760Ssam 	register struct file *fp;
56712760Ssam 	register struct socket *so;
56812760Ssam 
56912760Ssam 	if (unp_gcing)
57012760Ssam 		return;
57112760Ssam 	unp_gcing = 1;
57212760Ssam restart:
57312760Ssam 	unp_defer = 0;
57412760Ssam 	for (fp = file; fp < fileNFILE; fp++)
57512760Ssam 		fp->f_flag &= ~(FMARK|FDEFER);
57612760Ssam 	do {
57712760Ssam 		for (fp = file; fp < fileNFILE; fp++) {
57812760Ssam 			if (fp->f_count == 0)
57912760Ssam 				continue;
58012760Ssam 			if (fp->f_flag & FDEFER) {
58112760Ssam 				fp->f_flag &= ~FDEFER;
58212760Ssam 				unp_defer--;
58312760Ssam 			} else {
58412760Ssam 				if (fp->f_flag & FMARK)
58512760Ssam 					continue;
58612760Ssam 				if (fp->f_count == fp->f_msgcount)
58712760Ssam 					continue;
58812760Ssam 				fp->f_flag |= FMARK;
58912760Ssam 			}
59012760Ssam 			if (fp->f_type != DTYPE_SOCKET)
59112760Ssam 				continue;
59212760Ssam 			so = (struct socket *)fp->f_data;
59316995Skarels 			if (so->so_proto->pr_domain != &unixdomain ||
59421768Skarels 			    (so->so_proto->pr_flags&PR_RIGHTS) == 0)
59512760Ssam 				continue;
59612760Ssam 			if (so->so_rcv.sb_flags & SB_LOCK) {
59712760Ssam 				sbwait(&so->so_rcv);
59812760Ssam 				goto restart;
59912760Ssam 			}
60012760Ssam 			unp_scan(so->so_rcv.sb_mb, unp_mark);
60112760Ssam 		}
60212760Ssam 	} while (unp_defer);
60312760Ssam 	for (fp = file; fp < fileNFILE; fp++) {
60412760Ssam 		if (fp->f_count == 0)
60512760Ssam 			continue;
60612760Ssam 		if (fp->f_count == fp->f_msgcount && (fp->f_flag&FMARK)==0) {
60712760Ssam 			if (fp->f_type != DTYPE_SOCKET)
60812760Ssam 				panic("unp_gc");
60912760Ssam 			(void) soshutdown((struct socket *)fp->f_data, 0);
61012760Ssam 		}
61112760Ssam 	}
61212760Ssam 	unp_gcing = 0;
61312760Ssam }
61412760Ssam 
61516995Skarels unp_dispose(m)
61616995Skarels 	struct mbuf *m;
61716995Skarels {
61816995Skarels 	int unp_discard();
61916995Skarels 
62017020Skarels 	if (m)
62117020Skarels 		unp_scan(m, unp_discard);
62216995Skarels }
62316995Skarels 
62416995Skarels unp_scan(m0, op)
62516995Skarels 	register struct mbuf *m0;
62612760Ssam 	int (*op)();
62712760Ssam {
62816995Skarels 	register struct mbuf *m;
62912760Ssam 	register struct file **rp;
63012760Ssam 	register int i;
63117020Skarels 	int qfds;
63212760Ssam 
63316995Skarels 	while (m0) {
63416995Skarels 		for (m = m0; m; m = m->m_next)
63516995Skarels 			if (m->m_type == MT_RIGHTS && m->m_len) {
63616995Skarels 				qfds = m->m_len / sizeof (struct file *);
63716995Skarels 				rp = mtod(m, struct file **);
63816995Skarels 				for (i = 0; i < qfds; i++)
63916995Skarels 					(*op)(*rp++);
64016995Skarels 				break;		/* XXX, but saves time */
64116995Skarels 			}
64217020Skarels 		m0 = m0->m_act;
64312760Ssam 	}
64412760Ssam }
64512760Ssam 
64612760Ssam unp_mark(fp)
64712760Ssam 	struct file *fp;
64812760Ssam {
64912760Ssam 
65012760Ssam 	if (fp->f_flag & FMARK)
65112760Ssam 		return;
65212760Ssam 	unp_defer++;
65312760Ssam 	fp->f_flag |= (FMARK|FDEFER);
65412760Ssam }
65512760Ssam 
65612760Ssam unp_discard(fp)
65712760Ssam 	struct file *fp;
65812760Ssam {
65912760Ssam 
66012760Ssam 	fp->f_msgcount--;
66113084Ssam 	closef(fp);
66212760Ssam }
663