xref: /csrg-svn/sys/kern/uipc_usrreq.c (revision 34447)
123443Smckusick /*
229129Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
333288Sbostic  * All rights reserved.
423443Smckusick  *
533288Sbostic  * Redistribution and use in source and binary forms are permitted
633288Sbostic  * provided that this notice is preserved and that due credit is given
733288Sbostic  * to the University of California at Berkeley. The name of the University
833288Sbostic  * may not be used to endorse or promote products derived from this
933288Sbostic  * software without specific prior written permission. This software
1033288Sbostic  * is provided ``as is'' without express or implied warranty.
1133288Sbostic  *
12*34447Skarels  *	@(#)uipc_usrreq.c	7.5 (Berkeley) 05/24/88
1323443Smckusick  */
148925Sroot 
1517105Sbloom #include "param.h"
1617105Sbloom #include "dir.h"
1717105Sbloom #include "user.h"
1817105Sbloom #include "mbuf.h"
1917105Sbloom #include "domain.h"
2017105Sbloom #include "protosw.h"
2117105Sbloom #include "socket.h"
2217105Sbloom #include "socketvar.h"
2317105Sbloom #include "unpcb.h"
2417105Sbloom #include "un.h"
2517105Sbloom #include "inode.h"
2617105Sbloom #include "file.h"
2717105Sbloom #include "stat.h"
288925Sroot 
298925Sroot /*
308925Sroot  * Unix communications domain.
3112760Ssam  *
3212760Ssam  * TODO:
3312760Ssam  *	SEQPACKET, RDM
3413119Ssam  *	rethink name space problems
3512760Ssam  *	need a proper out-of-band
368925Sroot  */
3713119Ssam struct	sockaddr sun_noname = { AF_UNIX };
3825632Skarels ino_t	unp_ino;			/* prototype for fake inode numbers */
398925Sroot 
408925Sroot /*ARGSUSED*/
4112760Ssam uipc_usrreq(so, req, m, nam, rights)
428925Sroot 	struct socket *so;
438925Sroot 	int req;
4412760Ssam 	struct mbuf *m, *nam, *rights;
458925Sroot {
468925Sroot 	struct unpcb *unp = sotounpcb(so);
478925Sroot 	register struct socket *so2;
488925Sroot 	int error = 0;
498925Sroot 
5025555Skarels 	if (req == PRU_CONTROL)
5125555Skarels 		return (EOPNOTSUPP);
5212760Ssam 	if (req != PRU_SEND && rights && rights->m_len) {
5312760Ssam 		error = EOPNOTSUPP;
5412760Ssam 		goto release;
5512760Ssam 	}
5612760Ssam 	if (unp == 0 && req != PRU_ATTACH) {
5712760Ssam 		error = EINVAL;
5812760Ssam 		goto release;
5912760Ssam 	}
608925Sroot 	switch (req) {
618925Sroot 
628925Sroot 	case PRU_ATTACH:
638925Sroot 		if (unp) {
649169Ssam 			error = EISCONN;
658925Sroot 			break;
668925Sroot 		}
679028Sroot 		error = unp_attach(so);
688925Sroot 		break;
698925Sroot 
708925Sroot 	case PRU_DETACH:
718925Sroot 		unp_detach(unp);
728925Sroot 		break;
738925Sroot 
749169Ssam 	case PRU_BIND:
759169Ssam 		error = unp_bind(unp, nam);
769169Ssam 		break;
779169Ssam 
789169Ssam 	case PRU_LISTEN:
799169Ssam 		if (unp->unp_inode == 0)
809169Ssam 			error = EINVAL;
819169Ssam 		break;
829169Ssam 
838925Sroot 	case PRU_CONNECT:
849028Sroot 		error = unp_connect(so, nam);
858925Sroot 		break;
868925Sroot 
8712760Ssam 	case PRU_CONNECT2:
8826281Skarels 		error = unp_connect2(so, (struct socket *)nam);
8912760Ssam 		break;
9012760Ssam 
918925Sroot 	case PRU_DISCONNECT:
928925Sroot 		unp_disconnect(unp);
938925Sroot 		break;
948925Sroot 
959169Ssam 	case PRU_ACCEPT:
9625899Skarels 		/*
9725899Skarels 		 * Pass back name of connected socket,
9825899Skarels 		 * if it was bound and we are still connected
9925899Skarels 		 * (our peer may have closed already!).
10025899Skarels 		 */
10125899Skarels 		if (unp->unp_conn && unp->unp_conn->unp_addr) {
10225632Skarels 			nam->m_len = unp->unp_conn->unp_addr->m_len;
10325632Skarels 			bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
10425632Skarels 			    mtod(nam, caddr_t), (unsigned)nam->m_len);
10525632Skarels 		} else {
10625632Skarels 			nam->m_len = sizeof(sun_noname);
10725632Skarels 			*(mtod(nam, struct sockaddr *)) = sun_noname;
10825632Skarels 		}
1098925Sroot 		break;
1108925Sroot 
1118925Sroot 	case PRU_SHUTDOWN:
1128925Sroot 		socantsendmore(so);
1138925Sroot 		unp_usrclosed(unp);
1148925Sroot 		break;
1158925Sroot 
1168925Sroot 	case PRU_RCVD:
1178925Sroot 		switch (so->so_type) {
1188925Sroot 
1198925Sroot 		case SOCK_DGRAM:
1208925Sroot 			panic("uipc 1");
12110139Ssam 			/*NOTREACHED*/
1228925Sroot 
12310139Ssam 		case SOCK_STREAM:
1248925Sroot #define	rcv (&so->so_rcv)
1258925Sroot #define snd (&so2->so_snd)
1268925Sroot 			if (unp->unp_conn == 0)
1278925Sroot 				break;
1288925Sroot 			so2 = unp->unp_conn->unp_socket;
1298925Sroot 			/*
13025632Skarels 			 * Adjust backpressure on sender
1318925Sroot 			 * and wakeup any waiting to write.
1328925Sroot 			 */
13325632Skarels 			snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt;
13425632Skarels 			unp->unp_mbcnt = rcv->sb_mbcnt;
13525632Skarels 			snd->sb_hiwat += unp->unp_cc - rcv->sb_cc;
13625632Skarels 			unp->unp_cc = rcv->sb_cc;
13717543Skarels 			sowwakeup(so2);
1388925Sroot #undef snd
1398925Sroot #undef rcv
1408925Sroot 			break;
1418925Sroot 
1428925Sroot 		default:
1438925Sroot 			panic("uipc 2");
1448925Sroot 		}
1458925Sroot 		break;
1468925Sroot 
1478925Sroot 	case PRU_SEND:
14825632Skarels 		if (rights) {
14925632Skarels 			error = unp_internalize(rights);
15025632Skarels 			if (error)
15125632Skarels 				break;
15225632Skarels 		}
1538925Sroot 		switch (so->so_type) {
1548925Sroot 
15525632Skarels 		case SOCK_DGRAM: {
15625632Skarels 			struct sockaddr *from;
15725632Skarels 
1589028Sroot 			if (nam) {
1598925Sroot 				if (unp->unp_conn) {
1608925Sroot 					error = EISCONN;
1618925Sroot 					break;
1628925Sroot 				}
1639028Sroot 				error = unp_connect(so, nam);
1648925Sroot 				if (error)
1658925Sroot 					break;
1668925Sroot 			} else {
1678925Sroot 				if (unp->unp_conn == 0) {
1688925Sroot 					error = ENOTCONN;
1698925Sroot 					break;
1708925Sroot 				}
1718925Sroot 			}
1728925Sroot 			so2 = unp->unp_conn->unp_socket;
17325632Skarels 			if (unp->unp_addr)
17425632Skarels 				from = mtod(unp->unp_addr, struct sockaddr *);
17525632Skarels 			else
17625632Skarels 				from = &sun_noname;
17725632Skarels 			if (sbspace(&so2->so_rcv) > 0 &&
17825632Skarels 			    sbappendaddr(&so2->so_rcv, from, m, rights)) {
17925632Skarels 				sorwakeup(so2);
18025632Skarels 				m = 0;
18125632Skarels 			} else
18225632Skarels 				error = ENOBUFS;
1839028Sroot 			if (nam)
1849169Ssam 				unp_disconnect(unp);
1858925Sroot 			break;
18625632Skarels 		}
1878925Sroot 
1888925Sroot 		case SOCK_STREAM:
1898925Sroot #define	rcv (&so2->so_rcv)
1908925Sroot #define	snd (&so->so_snd)
19123524Skarels 			if (so->so_state & SS_CANTSENDMORE) {
19223524Skarels 				error = EPIPE;
19323524Skarels 				break;
19423524Skarels 			}
1958925Sroot 			if (unp->unp_conn == 0)
1968925Sroot 				panic("uipc 3");
1978925Sroot 			so2 = unp->unp_conn->unp_socket;
1988925Sroot 			/*
19925632Skarels 			 * Send to paired receive port, and then reduce
20025632Skarels 			 * send buffer hiwater marks to maintain backpressure.
2018925Sroot 			 * Wake up readers.
2028925Sroot 			 */
20325632Skarels 			if (rights)
20426365Skarels 				(void)sbappendrights(rcv, m, rights);
20525632Skarels 			else
20625632Skarels 				sbappend(rcv, m);
20725632Skarels 			snd->sb_mbmax -=
20825632Skarels 			    rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt;
20925632Skarels 			unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt;
21025632Skarels 			snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc;
21125632Skarels 			unp->unp_conn->unp_cc = rcv->sb_cc;
21217543Skarels 			sorwakeup(so2);
21317543Skarels 			m = 0;
2148925Sroot #undef snd
2158925Sroot #undef rcv
2168925Sroot 			break;
2178925Sroot 
2188925Sroot 		default:
2198925Sroot 			panic("uipc 4");
2208925Sroot 		}
2218925Sroot 		break;
2228925Sroot 
2238925Sroot 	case PRU_ABORT:
2248925Sroot 		unp_drop(unp, ECONNABORTED);
2258925Sroot 		break;
2268925Sroot 
2278925Sroot 	case PRU_SENSE:
22816973Skarels 		((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
22916973Skarels 		if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) {
23016973Skarels 			so2 = unp->unp_conn->unp_socket;
23116973Skarels 			((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc;
23216973Skarels 		}
23321110Skarels 		((struct stat *) m)->st_dev = NODEV;
23425632Skarels 		if (unp->unp_ino == 0)
23525632Skarels 			unp->unp_ino = unp_ino++;
23625632Skarels 		((struct stat *) m)->st_ino = unp->unp_ino;
23716973Skarels 		return (0);
2388925Sroot 
2398925Sroot 	case PRU_RCVOOB:
24016774Sbloom 		return (EOPNOTSUPP);
2418925Sroot 
2428925Sroot 	case PRU_SENDOOB:
24317543Skarels 		error = EOPNOTSUPP;
2448925Sroot 		break;
2458925Sroot 
2468925Sroot 	case PRU_SOCKADDR:
247*34447Skarels 		if (unp->unp_addr) {
248*34447Skarels 			nam->m_len = unp->unp_addr->m_len;
249*34447Skarels 			bcopy(mtod(unp->unp_addr, caddr_t),
250*34447Skarels 			    mtod(nam, caddr_t), (unsigned)nam->m_len);
251*34447Skarels 		} else
252*34447Skarels 			nam->m_len = 0;
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*34447Skarels 		} else
261*34447Skarels 			nam->m_len = 0;
26214121Ssam 		break;
26314121Ssam 
2648925Sroot 	case PRU_SLOWTIMO:
2658925Sroot 		break;
2668925Sroot 
2678925Sroot 	default:
2688925Sroot 		panic("piusrreq");
2698925Sroot 	}
27012760Ssam release:
27112760Ssam 	if (m)
27212760Ssam 		m_freem(m);
27311709Ssam 	return (error);
2748925Sroot }
2758925Sroot 
27616973Skarels /*
27725632Skarels  * Both send and receive buffers are allocated PIPSIZ bytes of buffering
27825632Skarels  * for stream sockets, although the total for sender and receiver is
27925632Skarels  * actually only PIPSIZ.
28016973Skarels  * Datagram sockets really use the sendspace as the maximum datagram size,
28116973Skarels  * and don't really want to reserve the sendspace.  Their recvspace should
28216973Skarels  * be large enough for at least one max-size datagram plus address.
28316973Skarels  */
28416973Skarels #define	PIPSIZ	4096
28516973Skarels int	unpst_sendspace = PIPSIZ;
28625632Skarels int	unpst_recvspace = PIPSIZ;
28716973Skarels int	unpdg_sendspace = 2*1024;	/* really max datagram size */
28816973Skarels int	unpdg_recvspace = 4*1024;
2898925Sroot 
29025632Skarels int	unp_rights;			/* file descriptors in flight */
29125632Skarels 
2929169Ssam unp_attach(so)
2938925Sroot 	struct socket *so;
2948925Sroot {
2959169Ssam 	register struct mbuf *m;
2968925Sroot 	register struct unpcb *unp;
2978925Sroot 	int error;
2988925Sroot 
29916973Skarels 	switch (so->so_type) {
30016973Skarels 
30116973Skarels 	case SOCK_STREAM:
30216973Skarels 		error = soreserve(so, unpst_sendspace, unpst_recvspace);
30316973Skarels 		break;
30416973Skarels 
30516973Skarels 	case SOCK_DGRAM:
30616973Skarels 		error = soreserve(so, unpdg_sendspace, unpdg_recvspace);
30716973Skarels 		break;
30816973Skarels 	}
3098925Sroot 	if (error)
31010139Ssam 		return (error);
3119637Ssam 	m = m_getclr(M_DONTWAIT, MT_PCB);
31210139Ssam 	if (m == NULL)
31310139Ssam 		return (ENOBUFS);
3148925Sroot 	unp = mtod(m, struct unpcb *);
3158925Sroot 	so->so_pcb = (caddr_t)unp;
3168925Sroot 	unp->unp_socket = so;
3178925Sroot 	return (0);
3188925Sroot }
3198925Sroot 
3208925Sroot unp_detach(unp)
3219169Ssam 	register struct unpcb *unp;
3228925Sroot {
3238925Sroot 
3248925Sroot 	if (unp->unp_inode) {
32517020Skarels 		unp->unp_inode->i_socket = 0;
3268925Sroot 		irele(unp->unp_inode);
3278925Sroot 		unp->unp_inode = 0;
3288925Sroot 	}
3298925Sroot 	if (unp->unp_conn)
3308925Sroot 		unp_disconnect(unp);
3318925Sroot 	while (unp->unp_refs)
3328925Sroot 		unp_drop(unp->unp_refs, ECONNRESET);
3338925Sroot 	soisdisconnected(unp->unp_socket);
3348925Sroot 	unp->unp_socket->so_pcb = 0;
33525632Skarels 	m_freem(unp->unp_addr);
3369169Ssam 	(void) m_free(dtom(unp));
33725632Skarels 	if (unp_rights)
33825632Skarels 		unp_gc();
3398925Sroot }
3408925Sroot 
3419169Ssam unp_bind(unp, nam)
3428925Sroot 	struct unpcb *unp;
3439169Ssam 	struct mbuf *nam;
3448925Sroot {
3459169Ssam 	struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
3468925Sroot 	register struct inode *ip;
34716695Smckusick 	register struct nameidata *ndp = &u.u_nd;
3488925Sroot 	int error;
3498925Sroot 
35016695Smckusick 	ndp->ni_dirp = soun->sun_path;
35125232Smckusick 	if (unp->unp_inode != NULL || nam->m_len == MLEN)
35212760Ssam 		return (EINVAL);
35312760Ssam 	*(mtod(nam, caddr_t) + nam->m_len) = 0;
35412760Ssam /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
35516695Smckusick 	ndp->ni_nameiop = CREATE | FOLLOW;
35616695Smckusick 	ndp->ni_segflg = UIO_SYSSPACE;
35716695Smckusick 	ip = namei(ndp);
3588925Sroot 	if (ip) {
3598925Sroot 		iput(ip);
36010139Ssam 		return (EADDRINUSE);
3618925Sroot 	}
36211828Ssam 	if (error = u.u_error) {
36311828Ssam 		u.u_error = 0;			/* XXX */
36411828Ssam 		return (error);
36511828Ssam 	}
36616695Smckusick 	ip = maknode(IFSOCK | 0777, ndp);
3678925Sroot 	if (ip == NULL) {
3688925Sroot 		error = u.u_error;		/* XXX */
3698925Sroot 		u.u_error = 0;			/* XXX */
3708925Sroot 		return (error);
3718925Sroot 	}
3728925Sroot 	ip->i_socket = unp->unp_socket;
3738925Sroot 	unp->unp_inode = ip;
37425632Skarels 	unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL);
3758925Sroot 	iunlock(ip);			/* but keep reference */
3768925Sroot 	return (0);
3778925Sroot }
3788925Sroot 
3799169Ssam unp_connect(so, nam)
3808925Sroot 	struct socket *so;
3819169Ssam 	struct mbuf *nam;
3828925Sroot {
3839169Ssam 	register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
3849169Ssam 	register struct inode *ip;
385*34447Skarels 	register struct socket *so2, *so3;
386*34447Skarels 	register struct nameidata *ndp = &u.u_nd;
387*34447Skarels 	struct unpcb *unp2, *unp3;
3888925Sroot 	int error;
3898925Sroot 
39016695Smckusick 	ndp->ni_dirp = soun->sun_path;
39112760Ssam 	if (nam->m_len + (nam->m_off - MMINOFF) == MLEN)
39212760Ssam 		return (EMSGSIZE);
39312760Ssam 	*(mtod(nam, caddr_t) + nam->m_len) = 0;
39416695Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
39516695Smckusick 	ndp->ni_segflg = UIO_SYSSPACE;
39616695Smckusick 	ip = namei(ndp);
3978925Sroot 	if (ip == 0) {
3988925Sroot 		error = u.u_error;
3998925Sroot 		u.u_error = 0;
40010139Ssam 		return (error);		/* XXX */
4018925Sroot 	}
40217543Skarels 	if (access(ip, IWRITE)) {
40317543Skarels 		error = u.u_error;
40417543Skarels 		u.u_error = 0; 		/* XXX */
40517543Skarels 		goto bad;
40617543Skarels 	}
4078925Sroot 	if ((ip->i_mode&IFMT) != IFSOCK) {
4088925Sroot 		error = ENOTSOCK;
4098925Sroot 		goto bad;
4108925Sroot 	}
4118925Sroot 	so2 = ip->i_socket;
4128925Sroot 	if (so2 == 0) {
4138925Sroot 		error = ECONNREFUSED;
4148925Sroot 		goto bad;
4158925Sroot 	}
41613115Ssam 	if (so->so_type != so2->so_type) {
41713115Ssam 		error = EPROTOTYPE;
41813115Ssam 		goto bad;
41913115Ssam 	}
420*34447Skarels 	if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
421*34447Skarels 		if ((so2->so_options & SO_ACCEPTCONN) == 0 ||
422*34447Skarels 		    (so3 = sonewconn(so2)) == 0) {
423*34447Skarels 			error = ECONNREFUSED;
424*34447Skarels 			goto bad;
425*34447Skarels 		}
426*34447Skarels 		unp2 = sotounpcb(so2);
427*34447Skarels 		unp3 = sotounpcb(so3);
428*34447Skarels 		if (unp2->unp_addr)
429*34447Skarels 			unp3->unp_addr = m_copy(unp2->unp_addr, 0, M_COPYALL);
430*34447Skarels 		so2 = so3;
43113115Ssam 	}
43226281Skarels 	error = unp_connect2(so, so2);
43312760Ssam bad:
43412760Ssam 	iput(ip);
43512760Ssam 	return (error);
43612760Ssam }
43712760Ssam 
43826281Skarels unp_connect2(so, so2)
43912760Ssam 	register struct socket *so;
44012760Ssam 	register struct socket *so2;
44112760Ssam {
44212760Ssam 	register struct unpcb *unp = sotounpcb(so);
44312760Ssam 	register struct unpcb *unp2;
44412760Ssam 
44512760Ssam 	if (so2->so_type != so->so_type)
44612760Ssam 		return (EPROTOTYPE);
44714049Ssam 	unp2 = sotounpcb(so2);
44814049Ssam 	unp->unp_conn = unp2;
4498925Sroot 	switch (so->so_type) {
4508925Sroot 
4518925Sroot 	case SOCK_DGRAM:
4528925Sroot 		unp->unp_nextref = unp2->unp_refs;
4538925Sroot 		unp2->unp_refs = unp;
45417543Skarels 		soisconnected(so);
4558925Sroot 		break;
4568925Sroot 
4578925Sroot 	case SOCK_STREAM:
4589169Ssam 		unp2->unp_conn = unp;
45914049Ssam 		soisconnected(so2);
46014049Ssam 		soisconnected(so);
4618925Sroot 		break;
4628925Sroot 
4638925Sroot 	default:
46412760Ssam 		panic("unp_connect2");
4658925Sroot 	}
4668925Sroot 	return (0);
4678925Sroot }
4689169Ssam 
4699169Ssam unp_disconnect(unp)
4709169Ssam 	struct unpcb *unp;
4719169Ssam {
4729169Ssam 	register struct unpcb *unp2 = unp->unp_conn;
4739169Ssam 
4749169Ssam 	if (unp2 == 0)
4759169Ssam 		return;
4769169Ssam 	unp->unp_conn = 0;
4779169Ssam 	switch (unp->unp_socket->so_type) {
4789169Ssam 
4799169Ssam 	case SOCK_DGRAM:
4809169Ssam 		if (unp2->unp_refs == unp)
4819169Ssam 			unp2->unp_refs = unp->unp_nextref;
4829169Ssam 		else {
4839169Ssam 			unp2 = unp2->unp_refs;
4849169Ssam 			for (;;) {
4859169Ssam 				if (unp2 == 0)
4869169Ssam 					panic("unp_disconnect");
4879169Ssam 				if (unp2->unp_nextref == unp)
4889169Ssam 					break;
4899169Ssam 				unp2 = unp2->unp_nextref;
4909169Ssam 			}
4919169Ssam 			unp2->unp_nextref = unp->unp_nextref;
4929169Ssam 		}
4939169Ssam 		unp->unp_nextref = 0;
49421768Skarels 		unp->unp_socket->so_state &= ~SS_ISCONNECTED;
4959169Ssam 		break;
4969169Ssam 
4979169Ssam 	case SOCK_STREAM:
49814049Ssam 		soisdisconnected(unp->unp_socket);
4999169Ssam 		unp2->unp_conn = 0;
5009169Ssam 		soisdisconnected(unp2->unp_socket);
5019169Ssam 		break;
5029169Ssam 	}
5039169Ssam }
5049169Ssam 
50512760Ssam #ifdef notdef
5069169Ssam unp_abort(unp)
5079169Ssam 	struct unpcb *unp;
5089169Ssam {
5099169Ssam 
5109169Ssam 	unp_detach(unp);
5119169Ssam }
51212760Ssam #endif
5139169Ssam 
5149169Ssam /*ARGSUSED*/
5159169Ssam unp_usrclosed(unp)
5169169Ssam 	struct unpcb *unp;
5179169Ssam {
5189169Ssam 
5199169Ssam }
5209169Ssam 
5219169Ssam unp_drop(unp, errno)
5229169Ssam 	struct unpcb *unp;
5239169Ssam 	int errno;
5249169Ssam {
52516054Skarels 	struct socket *so = unp->unp_socket;
5269169Ssam 
52716054Skarels 	so->so_error = errno;
5289169Ssam 	unp_disconnect(unp);
52916054Skarels 	if (so->so_head) {
53016054Skarels 		so->so_pcb = (caddr_t) 0;
53125632Skarels 		m_freem(unp->unp_addr);
53216054Skarels 		(void) m_free(dtom(unp));
53316054Skarels 		sofree(so);
53416054Skarels 	}
5359169Ssam }
5369169Ssam 
53712760Ssam #ifdef notdef
5389169Ssam unp_drain()
5399169Ssam {
5409169Ssam 
5419169Ssam }
54212760Ssam #endif
54312760Ssam 
54412760Ssam unp_externalize(rights)
54512760Ssam 	struct mbuf *rights;
54612760Ssam {
54712760Ssam 	int newfds = rights->m_len / sizeof (int);
54812760Ssam 	register int i;
54912760Ssam 	register struct file **rp = mtod(rights, struct file **);
55012760Ssam 	register struct file *fp;
55112760Ssam 	int f;
55212760Ssam 
55312760Ssam 	if (newfds > ufavail()) {
55412760Ssam 		for (i = 0; i < newfds; i++) {
55512760Ssam 			fp = *rp;
55612760Ssam 			unp_discard(fp);
55712760Ssam 			*rp++ = 0;
55812760Ssam 		}
55912760Ssam 		return (EMSGSIZE);
56012760Ssam 	}
56112760Ssam 	for (i = 0; i < newfds; i++) {
56212760Ssam 		f = ufalloc(0);
56312760Ssam 		if (f < 0)
56412760Ssam 			panic("unp_externalize");
56512760Ssam 		fp = *rp;
56612760Ssam 		u.u_ofile[f] = fp;
56712760Ssam 		fp->f_msgcount--;
56825632Skarels 		unp_rights--;
56914927Smckusick 		*(int *)rp++ = f;
57012760Ssam 	}
57112760Ssam 	return (0);
57212760Ssam }
57312760Ssam 
57412760Ssam unp_internalize(rights)
57512760Ssam 	struct mbuf *rights;
57612760Ssam {
57712760Ssam 	register struct file **rp;
57812760Ssam 	int oldfds = rights->m_len / sizeof (int);
57912760Ssam 	register int i;
58012760Ssam 	register struct file *fp;
58112760Ssam 
58212760Ssam 	rp = mtod(rights, struct file **);
58313084Ssam 	for (i = 0; i < oldfds; i++)
58412760Ssam 		if (getf(*(int *)rp++) == 0)
58512760Ssam 			return (EBADF);
58612760Ssam 	rp = mtod(rights, struct file **);
58713084Ssam 	for (i = 0; i < oldfds; i++) {
58812760Ssam 		fp = getf(*(int *)rp);
58912760Ssam 		*rp++ = fp;
59012760Ssam 		fp->f_count++;
59112760Ssam 		fp->f_msgcount++;
59225632Skarels 		unp_rights++;
59312760Ssam 	}
59412760Ssam 	return (0);
59512760Ssam }
59612760Ssam 
59712760Ssam int	unp_defer, unp_gcing;
59812760Ssam int	unp_mark();
59916995Skarels extern	struct domain unixdomain;
60012760Ssam 
60112760Ssam unp_gc()
60212760Ssam {
60312760Ssam 	register struct file *fp;
60412760Ssam 	register struct socket *so;
60512760Ssam 
60612760Ssam 	if (unp_gcing)
60712760Ssam 		return;
60812760Ssam 	unp_gcing = 1;
60912760Ssam restart:
61012760Ssam 	unp_defer = 0;
61112760Ssam 	for (fp = file; fp < fileNFILE; fp++)
61212760Ssam 		fp->f_flag &= ~(FMARK|FDEFER);
61312760Ssam 	do {
61412760Ssam 		for (fp = file; fp < fileNFILE; fp++) {
61512760Ssam 			if (fp->f_count == 0)
61612760Ssam 				continue;
61712760Ssam 			if (fp->f_flag & FDEFER) {
61812760Ssam 				fp->f_flag &= ~FDEFER;
61912760Ssam 				unp_defer--;
62012760Ssam 			} else {
62112760Ssam 				if (fp->f_flag & FMARK)
62212760Ssam 					continue;
62312760Ssam 				if (fp->f_count == fp->f_msgcount)
62412760Ssam 					continue;
62512760Ssam 				fp->f_flag |= FMARK;
62612760Ssam 			}
62733463Skarels 			if (fp->f_type != DTYPE_SOCKET ||
62833463Skarels 			    (so = (struct socket *)fp->f_data) == 0)
62912760Ssam 				continue;
63016995Skarels 			if (so->so_proto->pr_domain != &unixdomain ||
63121768Skarels 			    (so->so_proto->pr_flags&PR_RIGHTS) == 0)
63212760Ssam 				continue;
63312760Ssam 			if (so->so_rcv.sb_flags & SB_LOCK) {
63412760Ssam 				sbwait(&so->so_rcv);
63512760Ssam 				goto restart;
63612760Ssam 			}
63712760Ssam 			unp_scan(so->so_rcv.sb_mb, unp_mark);
63812760Ssam 		}
63912760Ssam 	} while (unp_defer);
64012760Ssam 	for (fp = file; fp < fileNFILE; fp++) {
64112760Ssam 		if (fp->f_count == 0)
64212760Ssam 			continue;
64325632Skarels 		if (fp->f_count == fp->f_msgcount && (fp->f_flag & FMARK) == 0)
64425632Skarels 			while (fp->f_msgcount)
64525632Skarels 				unp_discard(fp);
64612760Ssam 	}
64712760Ssam 	unp_gcing = 0;
64812760Ssam }
64912760Ssam 
65016995Skarels unp_dispose(m)
65116995Skarels 	struct mbuf *m;
65216995Skarels {
65316995Skarels 	int unp_discard();
65416995Skarels 
65517020Skarels 	if (m)
65617020Skarels 		unp_scan(m, unp_discard);
65716995Skarels }
65816995Skarels 
65916995Skarels unp_scan(m0, op)
66016995Skarels 	register struct mbuf *m0;
66112760Ssam 	int (*op)();
66212760Ssam {
66316995Skarels 	register struct mbuf *m;
66412760Ssam 	register struct file **rp;
66512760Ssam 	register int i;
66617020Skarels 	int qfds;
66712760Ssam 
66816995Skarels 	while (m0) {
66916995Skarels 		for (m = m0; m; m = m->m_next)
67016995Skarels 			if (m->m_type == MT_RIGHTS && m->m_len) {
67116995Skarels 				qfds = m->m_len / sizeof (struct file *);
67216995Skarels 				rp = mtod(m, struct file **);
67316995Skarels 				for (i = 0; i < qfds; i++)
67416995Skarels 					(*op)(*rp++);
67516995Skarels 				break;		/* XXX, but saves time */
67616995Skarels 			}
67717020Skarels 		m0 = m0->m_act;
67812760Ssam 	}
67912760Ssam }
68012760Ssam 
68112760Ssam unp_mark(fp)
68212760Ssam 	struct file *fp;
68312760Ssam {
68412760Ssam 
68512760Ssam 	if (fp->f_flag & FMARK)
68612760Ssam 		return;
68712760Ssam 	unp_defer++;
68812760Ssam 	fp->f_flag |= (FMARK|FDEFER);
68912760Ssam }
69012760Ssam 
69112760Ssam unp_discard(fp)
69212760Ssam 	struct file *fp;
69312760Ssam {
69412760Ssam 
69512760Ssam 	fp->f_msgcount--;
69625632Skarels 	unp_rights--;
69713084Ssam 	closef(fp);
69812760Ssam }
699