xref: /csrg-svn/sys/kern/uipc_usrreq.c (revision 37616)
123443Smckusick /*
2*37616Smckusick  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
333288Sbostic  * All rights reserved.
423443Smckusick  *
533288Sbostic  * Redistribution and use in source and binary forms are permitted
634859Sbostic  * provided that the above copyright notice and this paragraph are
734859Sbostic  * duplicated in all such forms and that any documentation,
834859Sbostic  * advertising materials, and other materials related to such
934859Sbostic  * distribution and use acknowledge that the software was developed
1034859Sbostic  * by the University of California, Berkeley.  The name of the
1134859Sbostic  * University may not be used to endorse or promote products derived
1234859Sbostic  * from this software without specific prior written permission.
1334859Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1434859Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*37616Smckusick  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1633288Sbostic  *
17*37616Smckusick  *	@(#)uipc_usrreq.c	7.2.1.1 (Berkeley) 05/02/89
1823443Smckusick  */
198925Sroot 
2017105Sbloom #include "param.h"
2117105Sbloom #include "dir.h"
2217105Sbloom #include "user.h"
2317105Sbloom #include "mbuf.h"
2417105Sbloom #include "domain.h"
2517105Sbloom #include "protosw.h"
2617105Sbloom #include "socket.h"
2717105Sbloom #include "socketvar.h"
2817105Sbloom #include "unpcb.h"
2917105Sbloom #include "un.h"
30*37616Smckusick #include "vnode.h"
31*37616Smckusick #include "mount.h"
3217105Sbloom #include "file.h"
3317105Sbloom #include "stat.h"
348925Sroot 
358925Sroot /*
368925Sroot  * Unix communications domain.
3712760Ssam  *
3812760Ssam  * TODO:
3912760Ssam  *	SEQPACKET, RDM
4013119Ssam  *	rethink name space problems
4112760Ssam  *	need a proper out-of-band
428925Sroot  */
43*37616Smckusick struct	sockaddr sun_noname = { AF_UNIX };
44*37616Smckusick ino_t	unp_vno;			/* prototype for fake vnode numbers */
458925Sroot 
468925Sroot /*ARGSUSED*/
4712760Ssam uipc_usrreq(so, req, m, nam, rights)
488925Sroot 	struct socket *so;
498925Sroot 	int req;
5012760Ssam 	struct mbuf *m, *nam, *rights;
518925Sroot {
528925Sroot 	struct unpcb *unp = sotounpcb(so);
538925Sroot 	register struct socket *so2;
548925Sroot 	int error = 0;
558925Sroot 
5625555Skarels 	if (req == PRU_CONTROL)
5725555Skarels 		return (EOPNOTSUPP);
5812760Ssam 	if (req != PRU_SEND && rights && rights->m_len) {
5912760Ssam 		error = EOPNOTSUPP;
6012760Ssam 		goto release;
6112760Ssam 	}
6212760Ssam 	if (unp == 0 && req != PRU_ATTACH) {
6312760Ssam 		error = EINVAL;
6412760Ssam 		goto release;
6512760Ssam 	}
668925Sroot 	switch (req) {
678925Sroot 
688925Sroot 	case PRU_ATTACH:
698925Sroot 		if (unp) {
709169Ssam 			error = EISCONN;
718925Sroot 			break;
728925Sroot 		}
739028Sroot 		error = unp_attach(so);
748925Sroot 		break;
758925Sroot 
768925Sroot 	case PRU_DETACH:
778925Sroot 		unp_detach(unp);
788925Sroot 		break;
798925Sroot 
809169Ssam 	case PRU_BIND:
819169Ssam 		error = unp_bind(unp, nam);
829169Ssam 		break;
839169Ssam 
849169Ssam 	case PRU_LISTEN:
85*37616Smckusick 		if (unp->unp_vnode == 0)
869169Ssam 			error = EINVAL;
879169Ssam 		break;
889169Ssam 
898925Sroot 	case PRU_CONNECT:
909028Sroot 		error = unp_connect(so, nam);
918925Sroot 		break;
928925Sroot 
9312760Ssam 	case PRU_CONNECT2:
9426281Skarels 		error = unp_connect2(so, (struct socket *)nam);
9512760Ssam 		break;
9612760Ssam 
978925Sroot 	case PRU_DISCONNECT:
988925Sroot 		unp_disconnect(unp);
998925Sroot 		break;
1008925Sroot 
1019169Ssam 	case PRU_ACCEPT:
10225899Skarels 		/*
10325899Skarels 		 * Pass back name of connected socket,
10425899Skarels 		 * if it was bound and we are still connected
10525899Skarels 		 * (our peer may have closed already!).
10625899Skarels 		 */
10725899Skarels 		if (unp->unp_conn && unp->unp_conn->unp_addr) {
10825632Skarels 			nam->m_len = unp->unp_conn->unp_addr->m_len;
10925632Skarels 			bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
11025632Skarels 			    mtod(nam, caddr_t), (unsigned)nam->m_len);
11125632Skarels 		} else {
11225632Skarels 			nam->m_len = sizeof(sun_noname);
11325632Skarels 			*(mtod(nam, struct sockaddr *)) = sun_noname;
11425632Skarels 		}
1158925Sroot 		break;
1168925Sroot 
1178925Sroot 	case PRU_SHUTDOWN:
1188925Sroot 		socantsendmore(so);
1198925Sroot 		unp_usrclosed(unp);
1208925Sroot 		break;
1218925Sroot 
1228925Sroot 	case PRU_RCVD:
1238925Sroot 		switch (so->so_type) {
1248925Sroot 
1258925Sroot 		case SOCK_DGRAM:
1268925Sroot 			panic("uipc 1");
12710139Ssam 			/*NOTREACHED*/
1288925Sroot 
12910139Ssam 		case SOCK_STREAM:
1308925Sroot #define	rcv (&so->so_rcv)
1318925Sroot #define snd (&so2->so_snd)
1328925Sroot 			if (unp->unp_conn == 0)
1338925Sroot 				break;
1348925Sroot 			so2 = unp->unp_conn->unp_socket;
1358925Sroot 			/*
13625632Skarels 			 * Adjust backpressure on sender
1378925Sroot 			 * and wakeup any waiting to write.
1388925Sroot 			 */
13925632Skarels 			snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt;
14025632Skarels 			unp->unp_mbcnt = rcv->sb_mbcnt;
14125632Skarels 			snd->sb_hiwat += unp->unp_cc - rcv->sb_cc;
14225632Skarels 			unp->unp_cc = rcv->sb_cc;
14317543Skarels 			sowwakeup(so2);
1448925Sroot #undef snd
1458925Sroot #undef rcv
1468925Sroot 			break;
1478925Sroot 
1488925Sroot 		default:
1498925Sroot 			panic("uipc 2");
1508925Sroot 		}
1518925Sroot 		break;
1528925Sroot 
1538925Sroot 	case PRU_SEND:
15425632Skarels 		if (rights) {
15525632Skarels 			error = unp_internalize(rights);
15625632Skarels 			if (error)
15725632Skarels 				break;
15825632Skarels 		}
1598925Sroot 		switch (so->so_type) {
1608925Sroot 
16125632Skarels 		case SOCK_DGRAM: {
16225632Skarels 			struct sockaddr *from;
16325632Skarels 
1649028Sroot 			if (nam) {
1658925Sroot 				if (unp->unp_conn) {
1668925Sroot 					error = EISCONN;
1678925Sroot 					break;
1688925Sroot 				}
1699028Sroot 				error = unp_connect(so, nam);
1708925Sroot 				if (error)
1718925Sroot 					break;
1728925Sroot 			} else {
1738925Sroot 				if (unp->unp_conn == 0) {
1748925Sroot 					error = ENOTCONN;
1758925Sroot 					break;
1768925Sroot 				}
1778925Sroot 			}
1788925Sroot 			so2 = unp->unp_conn->unp_socket;
17925632Skarels 			if (unp->unp_addr)
18025632Skarels 				from = mtod(unp->unp_addr, struct sockaddr *);
18125632Skarels 			else
18225632Skarels 				from = &sun_noname;
18325632Skarels 			if (sbspace(&so2->so_rcv) > 0 &&
18425632Skarels 			    sbappendaddr(&so2->so_rcv, from, m, rights)) {
18525632Skarels 				sorwakeup(so2);
18625632Skarels 				m = 0;
18725632Skarels 			} else
18825632Skarels 				error = ENOBUFS;
1899028Sroot 			if (nam)
1909169Ssam 				unp_disconnect(unp);
1918925Sroot 			break;
19225632Skarels 		}
1938925Sroot 
1948925Sroot 		case SOCK_STREAM:
1958925Sroot #define	rcv (&so2->so_rcv)
1968925Sroot #define	snd (&so->so_snd)
19723524Skarels 			if (so->so_state & SS_CANTSENDMORE) {
19823524Skarels 				error = EPIPE;
19923524Skarels 				break;
20023524Skarels 			}
2018925Sroot 			if (unp->unp_conn == 0)
2028925Sroot 				panic("uipc 3");
2038925Sroot 			so2 = unp->unp_conn->unp_socket;
2048925Sroot 			/*
20525632Skarels 			 * Send to paired receive port, and then reduce
20625632Skarels 			 * send buffer hiwater marks to maintain backpressure.
2078925Sroot 			 * Wake up readers.
2088925Sroot 			 */
20925632Skarels 			if (rights)
21026365Skarels 				(void)sbappendrights(rcv, m, rights);
21125632Skarels 			else
21225632Skarels 				sbappend(rcv, m);
21325632Skarels 			snd->sb_mbmax -=
21425632Skarels 			    rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt;
21525632Skarels 			unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt;
21625632Skarels 			snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc;
21725632Skarels 			unp->unp_conn->unp_cc = rcv->sb_cc;
21817543Skarels 			sorwakeup(so2);
21917543Skarels 			m = 0;
2208925Sroot #undef snd
2218925Sroot #undef rcv
2228925Sroot 			break;
2238925Sroot 
2248925Sroot 		default:
2258925Sroot 			panic("uipc 4");
2268925Sroot 		}
2278925Sroot 		break;
2288925Sroot 
2298925Sroot 	case PRU_ABORT:
2308925Sroot 		unp_drop(unp, ECONNABORTED);
2318925Sroot 		break;
2328925Sroot 
2338925Sroot 	case PRU_SENSE:
23416973Skarels 		((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
23516973Skarels 		if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) {
23616973Skarels 			so2 = unp->unp_conn->unp_socket;
23716973Skarels 			((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc;
23816973Skarels 		}
23921110Skarels 		((struct stat *) m)->st_dev = NODEV;
240*37616Smckusick 		if (unp->unp_vno == 0)
241*37616Smckusick 			unp->unp_vno = unp_vno++;
242*37616Smckusick 		((struct stat *) m)->st_ino = unp->unp_vno;
24316973Skarels 		return (0);
2448925Sroot 
2458925Sroot 	case PRU_RCVOOB:
24616774Sbloom 		return (EOPNOTSUPP);
2478925Sroot 
2488925Sroot 	case PRU_SENDOOB:
24917543Skarels 		error = EOPNOTSUPP;
2508925Sroot 		break;
2518925Sroot 
2528925Sroot 	case PRU_SOCKADDR:
2538925Sroot 		break;
2548925Sroot 
25514121Ssam 	case PRU_PEERADDR:
25628292Skarels 		if (unp->unp_conn && unp->unp_conn->unp_addr) {
25728292Skarels 			nam->m_len = unp->unp_conn->unp_addr->m_len;
25828292Skarels 			bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
25933287Sbostic 			    mtod(nam, caddr_t), (unsigned)nam->m_len);
260*37616Smckusick 		}
26114121Ssam 		break;
26214121Ssam 
2638925Sroot 	case PRU_SLOWTIMO:
2648925Sroot 		break;
2658925Sroot 
2668925Sroot 	default:
2678925Sroot 		panic("piusrreq");
2688925Sroot 	}
26912760Ssam release:
27012760Ssam 	if (m)
27112760Ssam 		m_freem(m);
27211709Ssam 	return (error);
2738925Sroot }
2748925Sroot 
27516973Skarels /*
27625632Skarels  * Both send and receive buffers are allocated PIPSIZ bytes of buffering
27725632Skarels  * for stream sockets, although the total for sender and receiver is
27825632Skarels  * actually only PIPSIZ.
27916973Skarels  * Datagram sockets really use the sendspace as the maximum datagram size,
28016973Skarels  * and don't really want to reserve the sendspace.  Their recvspace should
28116973Skarels  * be large enough for at least one max-size datagram plus address.
28216973Skarels  */
28316973Skarels #define	PIPSIZ	4096
284*37616Smckusick int	unpst_sendspace = PIPSIZ;
285*37616Smckusick int	unpst_recvspace = PIPSIZ;
286*37616Smckusick int	unpdg_sendspace = 2*1024;	/* really max datagram size */
287*37616Smckusick int	unpdg_recvspace = 4*1024;
2888925Sroot 
28925632Skarels int	unp_rights;			/* file descriptors in flight */
29025632Skarels 
2919169Ssam unp_attach(so)
2928925Sroot 	struct socket *so;
2938925Sroot {
2949169Ssam 	register struct mbuf *m;
2958925Sroot 	register struct unpcb *unp;
2968925Sroot 	int error;
2978925Sroot 
298*37616Smckusick 	switch (so->so_type) {
29916973Skarels 
300*37616Smckusick 	case SOCK_STREAM:
301*37616Smckusick 		error = soreserve(so, unpst_sendspace, unpst_recvspace);
302*37616Smckusick 		break;
30316973Skarels 
304*37616Smckusick 	case SOCK_DGRAM:
305*37616Smckusick 		error = soreserve(so, unpdg_sendspace, unpdg_recvspace);
306*37616Smckusick 		break;
30716973Skarels 	}
308*37616Smckusick 	if (error)
309*37616Smckusick 		return (error);
3109637Ssam 	m = m_getclr(M_DONTWAIT, MT_PCB);
31110139Ssam 	if (m == NULL)
31210139Ssam 		return (ENOBUFS);
3138925Sroot 	unp = mtod(m, struct unpcb *);
3148925Sroot 	so->so_pcb = (caddr_t)unp;
3158925Sroot 	unp->unp_socket = so;
3168925Sroot 	return (0);
3178925Sroot }
3188925Sroot 
3198925Sroot unp_detach(unp)
3209169Ssam 	register struct unpcb *unp;
3218925Sroot {
3228925Sroot 
323*37616Smckusick 	if (unp->unp_vnode) {
324*37616Smckusick 		unp->unp_vnode->v_socket = 0;
325*37616Smckusick 		vrele(unp->unp_vnode);
326*37616Smckusick 		unp->unp_vnode = 0;
3278925Sroot 	}
3288925Sroot 	if (unp->unp_conn)
3298925Sroot 		unp_disconnect(unp);
3308925Sroot 	while (unp->unp_refs)
3318925Sroot 		unp_drop(unp->unp_refs, ECONNRESET);
3328925Sroot 	soisdisconnected(unp->unp_socket);
3338925Sroot 	unp->unp_socket->so_pcb = 0;
33425632Skarels 	m_freem(unp->unp_addr);
3359169Ssam 	(void) m_free(dtom(unp));
33625632Skarels 	if (unp_rights)
33725632Skarels 		unp_gc();
3388925Sroot }
3398925Sroot 
3409169Ssam unp_bind(unp, nam)
3418925Sroot 	struct unpcb *unp;
3429169Ssam 	struct mbuf *nam;
3438925Sroot {
3449169Ssam 	struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
345*37616Smckusick 	register struct vnode *vp;
34616695Smckusick 	register struct nameidata *ndp = &u.u_nd;
347*37616Smckusick 	struct vattr vattr;
3488925Sroot 	int error;
3498925Sroot 
35016695Smckusick 	ndp->ni_dirp = soun->sun_path;
351*37616Smckusick 	if (unp->unp_vnode != NULL || nam->m_len == MLEN)
35212760Ssam 		return (EINVAL);
353*37616Smckusick 	*(mtod(nam, caddr_t) + nam->m_len) = 0;
35412760Ssam /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
355*37616Smckusick 	ndp->ni_nameiop = CREATE | FOLLOW | LOCKPARENT;
35616695Smckusick 	ndp->ni_segflg = UIO_SYSSPACE;
357*37616Smckusick 	if (error = namei(ndp))
358*37616Smckusick 		return (error);
359*37616Smckusick 	vp = ndp->ni_vp;
360*37616Smckusick 	if (vp != NULL) {
361*37616Smckusick 		vop_abortop(ndp);
36210139Ssam 		return (EADDRINUSE);
3638925Sroot 	}
364*37616Smckusick 	vattr_null(&vattr);
365*37616Smckusick 	vattr.va_type = VSOCK;
366*37616Smckusick 	vattr.va_mode = 0777;
367*37616Smckusick 	if (error = vop_create(ndp, &vattr))
36811828Ssam 		return (error);
369*37616Smckusick 	vp = ndp->ni_vp;
370*37616Smckusick 	vp->v_socket = unp->unp_socket;
371*37616Smckusick 	unp->unp_vnode = vp;
37225632Skarels 	unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL);
373*37616Smckusick 	vop_unlock(vp);
3748925Sroot 	return (0);
3758925Sroot }
3768925Sroot 
3779169Ssam unp_connect(so, nam)
3788925Sroot 	struct socket *so;
3799169Ssam 	struct mbuf *nam;
3808925Sroot {
3819169Ssam 	register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
382*37616Smckusick 	register struct vnode *vp;
383*37616Smckusick 	int error;
384*37616Smckusick 	register struct socket *so2;
38534447Skarels 	register struct nameidata *ndp = &u.u_nd;
3868925Sroot 
38716695Smckusick 	ndp->ni_dirp = soun->sun_path;
388*37616Smckusick 	if (nam->m_len + (nam->m_off - MMINOFF) == MLEN)
389*37616Smckusick 		return (EMSGSIZE);
390*37616Smckusick 	*(mtod(nam, caddr_t) + nam->m_len) = 0;
39116695Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
39216695Smckusick 	ndp->ni_segflg = UIO_SYSSPACE;
393*37616Smckusick 	if (error = namei(ndp))
394*37616Smckusick 		return (error);
395*37616Smckusick 	vp = ndp->ni_vp;
396*37616Smckusick 	if (error = vn_access(vp, VWRITE, u.u_cred))
39717543Skarels 		goto bad;
398*37616Smckusick 	if (vp->v_type != VSOCK) {
3998925Sroot 		error = ENOTSOCK;
4008925Sroot 		goto bad;
4018925Sroot 	}
402*37616Smckusick 	so2 = vp->v_socket;
4038925Sroot 	if (so2 == 0) {
4048925Sroot 		error = ECONNREFUSED;
4058925Sroot 		goto bad;
4068925Sroot 	}
40713115Ssam 	if (so->so_type != so2->so_type) {
40813115Ssam 		error = EPROTOTYPE;
40913115Ssam 		goto bad;
41013115Ssam 	}
411*37616Smckusick 	if (so->so_proto->pr_flags & PR_CONNREQUIRED &&
412*37616Smckusick 	    ((so2->so_options&SO_ACCEPTCONN) == 0 ||
413*37616Smckusick 	     (so2 = sonewconn(so2)) == 0)) {
414*37616Smckusick 		error = ECONNREFUSED;
415*37616Smckusick 		goto bad;
41613115Ssam 	}
41726281Skarels 	error = unp_connect2(so, so2);
41812760Ssam bad:
419*37616Smckusick 	vrele(vp);
42012760Ssam 	return (error);
42112760Ssam }
42212760Ssam 
42326281Skarels unp_connect2(so, so2)
42412760Ssam 	register struct socket *so;
42512760Ssam 	register struct socket *so2;
42612760Ssam {
42712760Ssam 	register struct unpcb *unp = sotounpcb(so);
42812760Ssam 	register struct unpcb *unp2;
42912760Ssam 
43012760Ssam 	if (so2->so_type != so->so_type)
43112760Ssam 		return (EPROTOTYPE);
43214049Ssam 	unp2 = sotounpcb(so2);
43314049Ssam 	unp->unp_conn = unp2;
4348925Sroot 	switch (so->so_type) {
4358925Sroot 
4368925Sroot 	case SOCK_DGRAM:
4378925Sroot 		unp->unp_nextref = unp2->unp_refs;
4388925Sroot 		unp2->unp_refs = unp;
43917543Skarels 		soisconnected(so);
4408925Sroot 		break;
4418925Sroot 
4428925Sroot 	case SOCK_STREAM:
4439169Ssam 		unp2->unp_conn = unp;
44414049Ssam 		soisconnected(so2);
44514049Ssam 		soisconnected(so);
4468925Sroot 		break;
4478925Sroot 
4488925Sroot 	default:
44912760Ssam 		panic("unp_connect2");
4508925Sroot 	}
4518925Sroot 	return (0);
4528925Sroot }
4539169Ssam 
4549169Ssam unp_disconnect(unp)
4559169Ssam 	struct unpcb *unp;
4569169Ssam {
4579169Ssam 	register struct unpcb *unp2 = unp->unp_conn;
4589169Ssam 
4599169Ssam 	if (unp2 == 0)
4609169Ssam 		return;
4619169Ssam 	unp->unp_conn = 0;
4629169Ssam 	switch (unp->unp_socket->so_type) {
4639169Ssam 
4649169Ssam 	case SOCK_DGRAM:
4659169Ssam 		if (unp2->unp_refs == unp)
4669169Ssam 			unp2->unp_refs = unp->unp_nextref;
4679169Ssam 		else {
4689169Ssam 			unp2 = unp2->unp_refs;
4699169Ssam 			for (;;) {
4709169Ssam 				if (unp2 == 0)
4719169Ssam 					panic("unp_disconnect");
4729169Ssam 				if (unp2->unp_nextref == unp)
4739169Ssam 					break;
4749169Ssam 				unp2 = unp2->unp_nextref;
4759169Ssam 			}
4769169Ssam 			unp2->unp_nextref = unp->unp_nextref;
4779169Ssam 		}
4789169Ssam 		unp->unp_nextref = 0;
47921768Skarels 		unp->unp_socket->so_state &= ~SS_ISCONNECTED;
4809169Ssam 		break;
4819169Ssam 
4829169Ssam 	case SOCK_STREAM:
48314049Ssam 		soisdisconnected(unp->unp_socket);
4849169Ssam 		unp2->unp_conn = 0;
4859169Ssam 		soisdisconnected(unp2->unp_socket);
4869169Ssam 		break;
4879169Ssam 	}
4889169Ssam }
4899169Ssam 
49012760Ssam #ifdef notdef
4919169Ssam unp_abort(unp)
4929169Ssam 	struct unpcb *unp;
4939169Ssam {
4949169Ssam 
4959169Ssam 	unp_detach(unp);
4969169Ssam }
49712760Ssam #endif
4989169Ssam 
4999169Ssam /*ARGSUSED*/
5009169Ssam unp_usrclosed(unp)
5019169Ssam 	struct unpcb *unp;
5029169Ssam {
5039169Ssam 
5049169Ssam }
5059169Ssam 
5069169Ssam unp_drop(unp, errno)
5079169Ssam 	struct unpcb *unp;
5089169Ssam 	int errno;
5099169Ssam {
51016054Skarels 	struct socket *so = unp->unp_socket;
5119169Ssam 
51216054Skarels 	so->so_error = errno;
5139169Ssam 	unp_disconnect(unp);
51416054Skarels 	if (so->so_head) {
51516054Skarels 		so->so_pcb = (caddr_t) 0;
51625632Skarels 		m_freem(unp->unp_addr);
51716054Skarels 		(void) m_free(dtom(unp));
51816054Skarels 		sofree(so);
51916054Skarels 	}
5209169Ssam }
5219169Ssam 
52212760Ssam #ifdef notdef
5239169Ssam unp_drain()
5249169Ssam {
5259169Ssam 
5269169Ssam }
52712760Ssam #endif
52812760Ssam 
52912760Ssam unp_externalize(rights)
53012760Ssam 	struct mbuf *rights;
53112760Ssam {
53212760Ssam 	int newfds = rights->m_len / sizeof (int);
53312760Ssam 	register int i;
53412760Ssam 	register struct file **rp = mtod(rights, struct file **);
53512760Ssam 	register struct file *fp;
53612760Ssam 	int f;
53712760Ssam 
53812760Ssam 	if (newfds > ufavail()) {
53912760Ssam 		for (i = 0; i < newfds; i++) {
54012760Ssam 			fp = *rp;
54112760Ssam 			unp_discard(fp);
54212760Ssam 			*rp++ = 0;
54312760Ssam 		}
54412760Ssam 		return (EMSGSIZE);
54512760Ssam 	}
54612760Ssam 	for (i = 0; i < newfds; i++) {
547*37616Smckusick 		if (ufalloc(0, &f))
54812760Ssam 			panic("unp_externalize");
54912760Ssam 		fp = *rp;
55012760Ssam 		u.u_ofile[f] = fp;
55112760Ssam 		fp->f_msgcount--;
55225632Skarels 		unp_rights--;
55314927Smckusick 		*(int *)rp++ = f;
55412760Ssam 	}
55512760Ssam 	return (0);
55612760Ssam }
55712760Ssam 
55812760Ssam unp_internalize(rights)
55912760Ssam 	struct mbuf *rights;
56012760Ssam {
56112760Ssam 	register struct file **rp;
56212760Ssam 	int oldfds = rights->m_len / sizeof (int);
56312760Ssam 	register int i;
56412760Ssam 	register struct file *fp;
56512760Ssam 
56612760Ssam 	rp = mtod(rights, struct file **);
56713084Ssam 	for (i = 0; i < oldfds; i++)
56812760Ssam 		if (getf(*(int *)rp++) == 0)
56912760Ssam 			return (EBADF);
57012760Ssam 	rp = mtod(rights, struct file **);
57113084Ssam 	for (i = 0; i < oldfds; i++) {
57212760Ssam 		fp = getf(*(int *)rp);
57312760Ssam 		*rp++ = fp;
57412760Ssam 		fp->f_count++;
57512760Ssam 		fp->f_msgcount++;
57625632Skarels 		unp_rights++;
57712760Ssam 	}
57812760Ssam 	return (0);
57912760Ssam }
58012760Ssam 
58112760Ssam int	unp_defer, unp_gcing;
58212760Ssam int	unp_mark();
58316995Skarels extern	struct domain unixdomain;
58412760Ssam 
58512760Ssam unp_gc()
58612760Ssam {
58712760Ssam 	register struct file *fp;
58812760Ssam 	register struct socket *so;
58912760Ssam 
59012760Ssam 	if (unp_gcing)
59112760Ssam 		return;
59212760Ssam 	unp_gcing = 1;
59312760Ssam restart:
59412760Ssam 	unp_defer = 0;
59512760Ssam 	for (fp = file; fp < fileNFILE; fp++)
59612760Ssam 		fp->f_flag &= ~(FMARK|FDEFER);
59712760Ssam 	do {
59812760Ssam 		for (fp = file; fp < fileNFILE; fp++) {
59912760Ssam 			if (fp->f_count == 0)
60012760Ssam 				continue;
60112760Ssam 			if (fp->f_flag & FDEFER) {
60212760Ssam 				fp->f_flag &= ~FDEFER;
60312760Ssam 				unp_defer--;
60412760Ssam 			} else {
60512760Ssam 				if (fp->f_flag & FMARK)
60612760Ssam 					continue;
60712760Ssam 				if (fp->f_count == fp->f_msgcount)
60812760Ssam 					continue;
60912760Ssam 				fp->f_flag |= FMARK;
61012760Ssam 			}
611*37616Smckusick 			if (fp->f_type != DTYPE_SOCKET)
61212760Ssam 				continue;
613*37616Smckusick 			so = (struct socket *)fp->f_data;
61416995Skarels 			if (so->so_proto->pr_domain != &unixdomain ||
61521768Skarels 			    (so->so_proto->pr_flags&PR_RIGHTS) == 0)
61612760Ssam 				continue;
61712760Ssam 			if (so->so_rcv.sb_flags & SB_LOCK) {
61812760Ssam 				sbwait(&so->so_rcv);
61912760Ssam 				goto restart;
62012760Ssam 			}
62112760Ssam 			unp_scan(so->so_rcv.sb_mb, unp_mark);
62212760Ssam 		}
62312760Ssam 	} while (unp_defer);
62412760Ssam 	for (fp = file; fp < fileNFILE; fp++) {
62512760Ssam 		if (fp->f_count == 0)
62612760Ssam 			continue;
62725632Skarels 		if (fp->f_count == fp->f_msgcount && (fp->f_flag & FMARK) == 0)
62825632Skarels 			while (fp->f_msgcount)
62925632Skarels 				unp_discard(fp);
63012760Ssam 	}
63112760Ssam 	unp_gcing = 0;
63212760Ssam }
63312760Ssam 
63416995Skarels unp_dispose(m)
63516995Skarels 	struct mbuf *m;
63616995Skarels {
63716995Skarels 	int unp_discard();
63816995Skarels 
63917020Skarels 	if (m)
64017020Skarels 		unp_scan(m, unp_discard);
64116995Skarels }
64216995Skarels 
64316995Skarels unp_scan(m0, op)
64416995Skarels 	register struct mbuf *m0;
64512760Ssam 	int (*op)();
64612760Ssam {
64716995Skarels 	register struct mbuf *m;
64812760Ssam 	register struct file **rp;
64912760Ssam 	register int i;
65017020Skarels 	int qfds;
65112760Ssam 
65216995Skarels 	while (m0) {
65316995Skarels 		for (m = m0; m; m = m->m_next)
65416995Skarels 			if (m->m_type == MT_RIGHTS && m->m_len) {
65516995Skarels 				qfds = m->m_len / sizeof (struct file *);
65616995Skarels 				rp = mtod(m, struct file **);
65716995Skarels 				for (i = 0; i < qfds; i++)
65816995Skarels 					(*op)(*rp++);
65916995Skarels 				break;		/* XXX, but saves time */
66016995Skarels 			}
66117020Skarels 		m0 = m0->m_act;
66212760Ssam 	}
66312760Ssam }
66412760Ssam 
66512760Ssam unp_mark(fp)
66612760Ssam 	struct file *fp;
66712760Ssam {
66812760Ssam 
66912760Ssam 	if (fp->f_flag & FMARK)
67012760Ssam 		return;
67112760Ssam 	unp_defer++;
67212760Ssam 	fp->f_flag |= (FMARK|FDEFER);
67312760Ssam }
67412760Ssam 
67512760Ssam unp_discard(fp)
67612760Ssam 	struct file *fp;
67712760Ssam {
67812760Ssam 
67912760Ssam 	fp->f_msgcount--;
68025632Skarels 	unp_rights--;
68113084Ssam 	closef(fp);
68212760Ssam }
683