xref: /csrg-svn/sys/kern/uipc_usrreq.c (revision 34859)
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
6*34859Sbostic  * provided that the above copyright notice and this paragraph are
7*34859Sbostic  * duplicated in all such forms and that any documentation,
8*34859Sbostic  * advertising materials, and other materials related to such
9*34859Sbostic  * distribution and use acknowledge that the software was developed
10*34859Sbostic  * by the University of California, Berkeley.  The name of the
11*34859Sbostic  * University may not be used to endorse or promote products derived
12*34859Sbostic  * from this software without specific prior written permission.
13*34859Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*34859Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*34859Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1633288Sbostic  *
17*34859Sbostic  *	@(#)uipc_usrreq.c	7.7 (Berkeley) 06/29/88
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"
3017105Sbloom #include "inode.h"
3117105Sbloom #include "file.h"
3217105Sbloom #include "stat.h"
338925Sroot 
348925Sroot /*
358925Sroot  * Unix communications domain.
3612760Ssam  *
3712760Ssam  * TODO:
3812760Ssam  *	SEQPACKET, RDM
3913119Ssam  *	rethink name space problems
4012760Ssam  *	need a proper out-of-band
418925Sroot  */
4213119Ssam struct	sockaddr sun_noname = { AF_UNIX };
4325632Skarels ino_t	unp_ino;			/* prototype for fake inode numbers */
448925Sroot 
458925Sroot /*ARGSUSED*/
4612760Ssam uipc_usrreq(so, req, m, nam, rights)
478925Sroot 	struct socket *so;
488925Sroot 	int req;
4912760Ssam 	struct mbuf *m, *nam, *rights;
508925Sroot {
518925Sroot 	struct unpcb *unp = sotounpcb(so);
528925Sroot 	register struct socket *so2;
538925Sroot 	int error = 0;
548925Sroot 
5525555Skarels 	if (req == PRU_CONTROL)
5625555Skarels 		return (EOPNOTSUPP);
5712760Ssam 	if (req != PRU_SEND && rights && rights->m_len) {
5812760Ssam 		error = EOPNOTSUPP;
5912760Ssam 		goto release;
6012760Ssam 	}
6112760Ssam 	if (unp == 0 && req != PRU_ATTACH) {
6212760Ssam 		error = EINVAL;
6312760Ssam 		goto release;
6412760Ssam 	}
658925Sroot 	switch (req) {
668925Sroot 
678925Sroot 	case PRU_ATTACH:
688925Sroot 		if (unp) {
699169Ssam 			error = EISCONN;
708925Sroot 			break;
718925Sroot 		}
729028Sroot 		error = unp_attach(so);
738925Sroot 		break;
748925Sroot 
758925Sroot 	case PRU_DETACH:
768925Sroot 		unp_detach(unp);
778925Sroot 		break;
788925Sroot 
799169Ssam 	case PRU_BIND:
809169Ssam 		error = unp_bind(unp, nam);
819169Ssam 		break;
829169Ssam 
839169Ssam 	case PRU_LISTEN:
849169Ssam 		if (unp->unp_inode == 0)
859169Ssam 			error = EINVAL;
869169Ssam 		break;
879169Ssam 
888925Sroot 	case PRU_CONNECT:
899028Sroot 		error = unp_connect(so, nam);
908925Sroot 		break;
918925Sroot 
9212760Ssam 	case PRU_CONNECT2:
9326281Skarels 		error = unp_connect2(so, (struct socket *)nam);
9412760Ssam 		break;
9512760Ssam 
968925Sroot 	case PRU_DISCONNECT:
978925Sroot 		unp_disconnect(unp);
988925Sroot 		break;
998925Sroot 
1009169Ssam 	case PRU_ACCEPT:
10125899Skarels 		/*
10225899Skarels 		 * Pass back name of connected socket,
10325899Skarels 		 * if it was bound and we are still connected
10425899Skarels 		 * (our peer may have closed already!).
10525899Skarels 		 */
10625899Skarels 		if (unp->unp_conn && unp->unp_conn->unp_addr) {
10725632Skarels 			nam->m_len = unp->unp_conn->unp_addr->m_len;
10825632Skarels 			bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
10925632Skarels 			    mtod(nam, caddr_t), (unsigned)nam->m_len);
11025632Skarels 		} else {
11125632Skarels 			nam->m_len = sizeof(sun_noname);
11225632Skarels 			*(mtod(nam, struct sockaddr *)) = sun_noname;
11325632Skarels 		}
1148925Sroot 		break;
1158925Sroot 
1168925Sroot 	case PRU_SHUTDOWN:
1178925Sroot 		socantsendmore(so);
1188925Sroot 		unp_usrclosed(unp);
1198925Sroot 		break;
1208925Sroot 
1218925Sroot 	case PRU_RCVD:
1228925Sroot 		switch (so->so_type) {
1238925Sroot 
1248925Sroot 		case SOCK_DGRAM:
1258925Sroot 			panic("uipc 1");
12610139Ssam 			/*NOTREACHED*/
1278925Sroot 
12810139Ssam 		case SOCK_STREAM:
1298925Sroot #define	rcv (&so->so_rcv)
1308925Sroot #define snd (&so2->so_snd)
1318925Sroot 			if (unp->unp_conn == 0)
1328925Sroot 				break;
1338925Sroot 			so2 = unp->unp_conn->unp_socket;
1348925Sroot 			/*
13525632Skarels 			 * Adjust backpressure on sender
1368925Sroot 			 * and wakeup any waiting to write.
1378925Sroot 			 */
13825632Skarels 			snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt;
13925632Skarels 			unp->unp_mbcnt = rcv->sb_mbcnt;
14025632Skarels 			snd->sb_hiwat += unp->unp_cc - rcv->sb_cc;
14125632Skarels 			unp->unp_cc = rcv->sb_cc;
14217543Skarels 			sowwakeup(so2);
1438925Sroot #undef snd
1448925Sroot #undef rcv
1458925Sroot 			break;
1468925Sroot 
1478925Sroot 		default:
1488925Sroot 			panic("uipc 2");
1498925Sroot 		}
1508925Sroot 		break;
1518925Sroot 
1528925Sroot 	case PRU_SEND:
15325632Skarels 		if (rights) {
15425632Skarels 			error = unp_internalize(rights);
15525632Skarels 			if (error)
15625632Skarels 				break;
15725632Skarels 		}
1588925Sroot 		switch (so->so_type) {
1598925Sroot 
16025632Skarels 		case SOCK_DGRAM: {
16125632Skarels 			struct sockaddr *from;
16225632Skarels 
1639028Sroot 			if (nam) {
1648925Sroot 				if (unp->unp_conn) {
1658925Sroot 					error = EISCONN;
1668925Sroot 					break;
1678925Sroot 				}
1689028Sroot 				error = unp_connect(so, nam);
1698925Sroot 				if (error)
1708925Sroot 					break;
1718925Sroot 			} else {
1728925Sroot 				if (unp->unp_conn == 0) {
1738925Sroot 					error = ENOTCONN;
1748925Sroot 					break;
1758925Sroot 				}
1768925Sroot 			}
1778925Sroot 			so2 = unp->unp_conn->unp_socket;
17825632Skarels 			if (unp->unp_addr)
17925632Skarels 				from = mtod(unp->unp_addr, struct sockaddr *);
18025632Skarels 			else
18125632Skarels 				from = &sun_noname;
18225632Skarels 			if (sbspace(&so2->so_rcv) > 0 &&
18325632Skarels 			    sbappendaddr(&so2->so_rcv, from, m, rights)) {
18425632Skarels 				sorwakeup(so2);
18525632Skarels 				m = 0;
18625632Skarels 			} else
18725632Skarels 				error = ENOBUFS;
1889028Sroot 			if (nam)
1899169Ssam 				unp_disconnect(unp);
1908925Sroot 			break;
19125632Skarels 		}
1928925Sroot 
1938925Sroot 		case SOCK_STREAM:
1948925Sroot #define	rcv (&so2->so_rcv)
1958925Sroot #define	snd (&so->so_snd)
19623524Skarels 			if (so->so_state & SS_CANTSENDMORE) {
19723524Skarels 				error = EPIPE;
19823524Skarels 				break;
19923524Skarels 			}
2008925Sroot 			if (unp->unp_conn == 0)
2018925Sroot 				panic("uipc 3");
2028925Sroot 			so2 = unp->unp_conn->unp_socket;
2038925Sroot 			/*
20425632Skarels 			 * Send to paired receive port, and then reduce
20525632Skarels 			 * send buffer hiwater marks to maintain backpressure.
2068925Sroot 			 * Wake up readers.
2078925Sroot 			 */
20825632Skarels 			if (rights)
20926365Skarels 				(void)sbappendrights(rcv, m, rights);
21025632Skarels 			else
21125632Skarels 				sbappend(rcv, m);
21225632Skarels 			snd->sb_mbmax -=
21325632Skarels 			    rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt;
21425632Skarels 			unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt;
21525632Skarels 			snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc;
21625632Skarels 			unp->unp_conn->unp_cc = rcv->sb_cc;
21717543Skarels 			sorwakeup(so2);
21817543Skarels 			m = 0;
2198925Sroot #undef snd
2208925Sroot #undef rcv
2218925Sroot 			break;
2228925Sroot 
2238925Sroot 		default:
2248925Sroot 			panic("uipc 4");
2258925Sroot 		}
2268925Sroot 		break;
2278925Sroot 
2288925Sroot 	case PRU_ABORT:
2298925Sroot 		unp_drop(unp, ECONNABORTED);
2308925Sroot 		break;
2318925Sroot 
2328925Sroot 	case PRU_SENSE:
23316973Skarels 		((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
23416973Skarels 		if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) {
23516973Skarels 			so2 = unp->unp_conn->unp_socket;
23616973Skarels 			((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc;
23716973Skarels 		}
23821110Skarels 		((struct stat *) m)->st_dev = NODEV;
23925632Skarels 		if (unp->unp_ino == 0)
24025632Skarels 			unp->unp_ino = unp_ino++;
24125632Skarels 		((struct stat *) m)->st_ino = unp->unp_ino;
24216973Skarels 		return (0);
2438925Sroot 
2448925Sroot 	case PRU_RCVOOB:
24516774Sbloom 		return (EOPNOTSUPP);
2468925Sroot 
2478925Sroot 	case PRU_SENDOOB:
24817543Skarels 		error = EOPNOTSUPP;
2498925Sroot 		break;
2508925Sroot 
2518925Sroot 	case PRU_SOCKADDR:
25234447Skarels 		if (unp->unp_addr) {
25334447Skarels 			nam->m_len = unp->unp_addr->m_len;
25434447Skarels 			bcopy(mtod(unp->unp_addr, caddr_t),
25534447Skarels 			    mtod(nam, caddr_t), (unsigned)nam->m_len);
25634447Skarels 		} else
25734447Skarels 			nam->m_len = 0;
2588925Sroot 		break;
2598925Sroot 
26014121Ssam 	case PRU_PEERADDR:
26128292Skarels 		if (unp->unp_conn && unp->unp_conn->unp_addr) {
26228292Skarels 			nam->m_len = unp->unp_conn->unp_addr->m_len;
26328292Skarels 			bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
26433287Sbostic 			    mtod(nam, caddr_t), (unsigned)nam->m_len);
26534447Skarels 		} else
26634447Skarels 			nam->m_len = 0;
26714121Ssam 		break;
26814121Ssam 
2698925Sroot 	case PRU_SLOWTIMO:
2708925Sroot 		break;
2718925Sroot 
2728925Sroot 	default:
2738925Sroot 		panic("piusrreq");
2748925Sroot 	}
27512760Ssam release:
27612760Ssam 	if (m)
27712760Ssam 		m_freem(m);
27811709Ssam 	return (error);
2798925Sroot }
2808925Sroot 
28116973Skarels /*
28225632Skarels  * Both send and receive buffers are allocated PIPSIZ bytes of buffering
28325632Skarels  * for stream sockets, although the total for sender and receiver is
28425632Skarels  * actually only PIPSIZ.
28516973Skarels  * Datagram sockets really use the sendspace as the maximum datagram size,
28616973Skarels  * and don't really want to reserve the sendspace.  Their recvspace should
28716973Skarels  * be large enough for at least one max-size datagram plus address.
28816973Skarels  */
28916973Skarels #define	PIPSIZ	4096
29034484Skarels u_long	unpst_sendspace = PIPSIZ;
29134484Skarels u_long	unpst_recvspace = PIPSIZ;
29234484Skarels u_long	unpdg_sendspace = 2*1024;	/* really max datagram size */
29334484Skarels u_long	unpdg_recvspace = 4*1024;
2948925Sroot 
29525632Skarels int	unp_rights;			/* file descriptors in flight */
29625632Skarels 
2979169Ssam unp_attach(so)
2988925Sroot 	struct socket *so;
2998925Sroot {
3009169Ssam 	register struct mbuf *m;
3018925Sroot 	register struct unpcb *unp;
3028925Sroot 	int error;
3038925Sroot 
30434484Skarels 	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
30534484Skarels 		switch (so->so_type) {
30616973Skarels 
30734484Skarels 		case SOCK_STREAM:
30834484Skarels 			error = soreserve(so, unpst_sendspace, unpst_recvspace);
30934484Skarels 			break;
31016973Skarels 
31134484Skarels 		case SOCK_DGRAM:
31234484Skarels 			error = soreserve(so, unpdg_sendspace, unpdg_recvspace);
31334484Skarels 			break;
31434484Skarels 		}
31534484Skarels 		if (error)
31634484Skarels 			return (error);
31716973Skarels 	}
3189637Ssam 	m = m_getclr(M_DONTWAIT, MT_PCB);
31910139Ssam 	if (m == NULL)
32010139Ssam 		return (ENOBUFS);
3218925Sroot 	unp = mtod(m, struct unpcb *);
3228925Sroot 	so->so_pcb = (caddr_t)unp;
3238925Sroot 	unp->unp_socket = so;
3248925Sroot 	return (0);
3258925Sroot }
3268925Sroot 
3278925Sroot unp_detach(unp)
3289169Ssam 	register struct unpcb *unp;
3298925Sroot {
3308925Sroot 
3318925Sroot 	if (unp->unp_inode) {
33217020Skarels 		unp->unp_inode->i_socket = 0;
3338925Sroot 		irele(unp->unp_inode);
3348925Sroot 		unp->unp_inode = 0;
3358925Sroot 	}
3368925Sroot 	if (unp->unp_conn)
3378925Sroot 		unp_disconnect(unp);
3388925Sroot 	while (unp->unp_refs)
3398925Sroot 		unp_drop(unp->unp_refs, ECONNRESET);
3408925Sroot 	soisdisconnected(unp->unp_socket);
3418925Sroot 	unp->unp_socket->so_pcb = 0;
34225632Skarels 	m_freem(unp->unp_addr);
3439169Ssam 	(void) m_free(dtom(unp));
34425632Skarels 	if (unp_rights)
34525632Skarels 		unp_gc();
3468925Sroot }
3478925Sroot 
3489169Ssam unp_bind(unp, nam)
3498925Sroot 	struct unpcb *unp;
3509169Ssam 	struct mbuf *nam;
3518925Sroot {
3529169Ssam 	struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
3538925Sroot 	register struct inode *ip;
35416695Smckusick 	register struct nameidata *ndp = &u.u_nd;
3558925Sroot 	int error;
3568925Sroot 
35716695Smckusick 	ndp->ni_dirp = soun->sun_path;
35825232Smckusick 	if (unp->unp_inode != NULL || nam->m_len == MLEN)
35912760Ssam 		return (EINVAL);
36012760Ssam 	*(mtod(nam, caddr_t) + nam->m_len) = 0;
36112760Ssam /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
36216695Smckusick 	ndp->ni_nameiop = CREATE | FOLLOW;
36316695Smckusick 	ndp->ni_segflg = UIO_SYSSPACE;
36416695Smckusick 	ip = namei(ndp);
3658925Sroot 	if (ip) {
3668925Sroot 		iput(ip);
36710139Ssam 		return (EADDRINUSE);
3688925Sroot 	}
36911828Ssam 	if (error = u.u_error) {
37011828Ssam 		u.u_error = 0;			/* XXX */
37111828Ssam 		return (error);
37211828Ssam 	}
37316695Smckusick 	ip = maknode(IFSOCK | 0777, ndp);
3748925Sroot 	if (ip == NULL) {
3758925Sroot 		error = u.u_error;		/* XXX */
3768925Sroot 		u.u_error = 0;			/* XXX */
3778925Sroot 		return (error);
3788925Sroot 	}
3798925Sroot 	ip->i_socket = unp->unp_socket;
3808925Sroot 	unp->unp_inode = ip;
38125632Skarels 	unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL);
3828925Sroot 	iunlock(ip);			/* but keep reference */
3838925Sroot 	return (0);
3848925Sroot }
3858925Sroot 
3869169Ssam unp_connect(so, nam)
3878925Sroot 	struct socket *so;
3889169Ssam 	struct mbuf *nam;
3898925Sroot {
3909169Ssam 	register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
3919169Ssam 	register struct inode *ip;
39234447Skarels 	register struct socket *so2, *so3;
39334447Skarels 	register struct nameidata *ndp = &u.u_nd;
39434447Skarels 	struct unpcb *unp2, *unp3;
3958925Sroot 	int error;
3968925Sroot 
39716695Smckusick 	ndp->ni_dirp = soun->sun_path;
39812760Ssam 	if (nam->m_len + (nam->m_off - MMINOFF) == MLEN)
39912760Ssam 		return (EMSGSIZE);
40012760Ssam 	*(mtod(nam, caddr_t) + nam->m_len) = 0;
40116695Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW;
40216695Smckusick 	ndp->ni_segflg = UIO_SYSSPACE;
40316695Smckusick 	ip = namei(ndp);
4048925Sroot 	if (ip == 0) {
4058925Sroot 		error = u.u_error;
4068925Sroot 		u.u_error = 0;
40710139Ssam 		return (error);		/* XXX */
4088925Sroot 	}
40917543Skarels 	if (access(ip, IWRITE)) {
41017543Skarels 		error = u.u_error;
41117543Skarels 		u.u_error = 0; 		/* XXX */
41217543Skarels 		goto bad;
41317543Skarels 	}
4148925Sroot 	if ((ip->i_mode&IFMT) != IFSOCK) {
4158925Sroot 		error = ENOTSOCK;
4168925Sroot 		goto bad;
4178925Sroot 	}
4188925Sroot 	so2 = ip->i_socket;
4198925Sroot 	if (so2 == 0) {
4208925Sroot 		error = ECONNREFUSED;
4218925Sroot 		goto bad;
4228925Sroot 	}
42313115Ssam 	if (so->so_type != so2->so_type) {
42413115Ssam 		error = EPROTOTYPE;
42513115Ssam 		goto bad;
42613115Ssam 	}
42734447Skarels 	if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
42834447Skarels 		if ((so2->so_options & SO_ACCEPTCONN) == 0 ||
42934447Skarels 		    (so3 = sonewconn(so2)) == 0) {
43034447Skarels 			error = ECONNREFUSED;
43134447Skarels 			goto bad;
43234447Skarels 		}
43334447Skarels 		unp2 = sotounpcb(so2);
43434447Skarels 		unp3 = sotounpcb(so3);
43534447Skarels 		if (unp2->unp_addr)
43634447Skarels 			unp3->unp_addr = m_copy(unp2->unp_addr, 0, M_COPYALL);
43734447Skarels 		so2 = so3;
43813115Ssam 	}
43926281Skarels 	error = unp_connect2(so, so2);
44012760Ssam bad:
44112760Ssam 	iput(ip);
44212760Ssam 	return (error);
44312760Ssam }
44412760Ssam 
44526281Skarels unp_connect2(so, so2)
44612760Ssam 	register struct socket *so;
44712760Ssam 	register struct socket *so2;
44812760Ssam {
44912760Ssam 	register struct unpcb *unp = sotounpcb(so);
45012760Ssam 	register struct unpcb *unp2;
45112760Ssam 
45212760Ssam 	if (so2->so_type != so->so_type)
45312760Ssam 		return (EPROTOTYPE);
45414049Ssam 	unp2 = sotounpcb(so2);
45514049Ssam 	unp->unp_conn = unp2;
4568925Sroot 	switch (so->so_type) {
4578925Sroot 
4588925Sroot 	case SOCK_DGRAM:
4598925Sroot 		unp->unp_nextref = unp2->unp_refs;
4608925Sroot 		unp2->unp_refs = unp;
46117543Skarels 		soisconnected(so);
4628925Sroot 		break;
4638925Sroot 
4648925Sroot 	case SOCK_STREAM:
4659169Ssam 		unp2->unp_conn = unp;
46614049Ssam 		soisconnected(so2);
46714049Ssam 		soisconnected(so);
4688925Sroot 		break;
4698925Sroot 
4708925Sroot 	default:
47112760Ssam 		panic("unp_connect2");
4728925Sroot 	}
4738925Sroot 	return (0);
4748925Sroot }
4759169Ssam 
4769169Ssam unp_disconnect(unp)
4779169Ssam 	struct unpcb *unp;
4789169Ssam {
4799169Ssam 	register struct unpcb *unp2 = unp->unp_conn;
4809169Ssam 
4819169Ssam 	if (unp2 == 0)
4829169Ssam 		return;
4839169Ssam 	unp->unp_conn = 0;
4849169Ssam 	switch (unp->unp_socket->so_type) {
4859169Ssam 
4869169Ssam 	case SOCK_DGRAM:
4879169Ssam 		if (unp2->unp_refs == unp)
4889169Ssam 			unp2->unp_refs = unp->unp_nextref;
4899169Ssam 		else {
4909169Ssam 			unp2 = unp2->unp_refs;
4919169Ssam 			for (;;) {
4929169Ssam 				if (unp2 == 0)
4939169Ssam 					panic("unp_disconnect");
4949169Ssam 				if (unp2->unp_nextref == unp)
4959169Ssam 					break;
4969169Ssam 				unp2 = unp2->unp_nextref;
4979169Ssam 			}
4989169Ssam 			unp2->unp_nextref = unp->unp_nextref;
4999169Ssam 		}
5009169Ssam 		unp->unp_nextref = 0;
50121768Skarels 		unp->unp_socket->so_state &= ~SS_ISCONNECTED;
5029169Ssam 		break;
5039169Ssam 
5049169Ssam 	case SOCK_STREAM:
50514049Ssam 		soisdisconnected(unp->unp_socket);
5069169Ssam 		unp2->unp_conn = 0;
5079169Ssam 		soisdisconnected(unp2->unp_socket);
5089169Ssam 		break;
5099169Ssam 	}
5109169Ssam }
5119169Ssam 
51212760Ssam #ifdef notdef
5139169Ssam unp_abort(unp)
5149169Ssam 	struct unpcb *unp;
5159169Ssam {
5169169Ssam 
5179169Ssam 	unp_detach(unp);
5189169Ssam }
51912760Ssam #endif
5209169Ssam 
5219169Ssam /*ARGSUSED*/
5229169Ssam unp_usrclosed(unp)
5239169Ssam 	struct unpcb *unp;
5249169Ssam {
5259169Ssam 
5269169Ssam }
5279169Ssam 
5289169Ssam unp_drop(unp, errno)
5299169Ssam 	struct unpcb *unp;
5309169Ssam 	int errno;
5319169Ssam {
53216054Skarels 	struct socket *so = unp->unp_socket;
5339169Ssam 
53416054Skarels 	so->so_error = errno;
5359169Ssam 	unp_disconnect(unp);
53616054Skarels 	if (so->so_head) {
53716054Skarels 		so->so_pcb = (caddr_t) 0;
53825632Skarels 		m_freem(unp->unp_addr);
53916054Skarels 		(void) m_free(dtom(unp));
54016054Skarels 		sofree(so);
54116054Skarels 	}
5429169Ssam }
5439169Ssam 
54412760Ssam #ifdef notdef
5459169Ssam unp_drain()
5469169Ssam {
5479169Ssam 
5489169Ssam }
54912760Ssam #endif
55012760Ssam 
55112760Ssam unp_externalize(rights)
55212760Ssam 	struct mbuf *rights;
55312760Ssam {
55412760Ssam 	int newfds = rights->m_len / sizeof (int);
55512760Ssam 	register int i;
55612760Ssam 	register struct file **rp = mtod(rights, struct file **);
55712760Ssam 	register struct file *fp;
55812760Ssam 	int f;
55912760Ssam 
56012760Ssam 	if (newfds > ufavail()) {
56112760Ssam 		for (i = 0; i < newfds; i++) {
56212760Ssam 			fp = *rp;
56312760Ssam 			unp_discard(fp);
56412760Ssam 			*rp++ = 0;
56512760Ssam 		}
56612760Ssam 		return (EMSGSIZE);
56712760Ssam 	}
56812760Ssam 	for (i = 0; i < newfds; i++) {
56912760Ssam 		f = ufalloc(0);
57012760Ssam 		if (f < 0)
57112760Ssam 			panic("unp_externalize");
57212760Ssam 		fp = *rp;
57312760Ssam 		u.u_ofile[f] = fp;
57412760Ssam 		fp->f_msgcount--;
57525632Skarels 		unp_rights--;
57614927Smckusick 		*(int *)rp++ = f;
57712760Ssam 	}
57812760Ssam 	return (0);
57912760Ssam }
58012760Ssam 
58112760Ssam unp_internalize(rights)
58212760Ssam 	struct mbuf *rights;
58312760Ssam {
58412760Ssam 	register struct file **rp;
58512760Ssam 	int oldfds = rights->m_len / sizeof (int);
58612760Ssam 	register int i;
58712760Ssam 	register struct file *fp;
58812760Ssam 
58912760Ssam 	rp = mtod(rights, struct file **);
59013084Ssam 	for (i = 0; i < oldfds; i++)
59112760Ssam 		if (getf(*(int *)rp++) == 0)
59212760Ssam 			return (EBADF);
59312760Ssam 	rp = mtod(rights, struct file **);
59413084Ssam 	for (i = 0; i < oldfds; i++) {
59512760Ssam 		fp = getf(*(int *)rp);
59612760Ssam 		*rp++ = fp;
59712760Ssam 		fp->f_count++;
59812760Ssam 		fp->f_msgcount++;
59925632Skarels 		unp_rights++;
60012760Ssam 	}
60112760Ssam 	return (0);
60212760Ssam }
60312760Ssam 
60412760Ssam int	unp_defer, unp_gcing;
60512760Ssam int	unp_mark();
60616995Skarels extern	struct domain unixdomain;
60712760Ssam 
60812760Ssam unp_gc()
60912760Ssam {
61012760Ssam 	register struct file *fp;
61112760Ssam 	register struct socket *so;
61212760Ssam 
61312760Ssam 	if (unp_gcing)
61412760Ssam 		return;
61512760Ssam 	unp_gcing = 1;
61612760Ssam restart:
61712760Ssam 	unp_defer = 0;
61812760Ssam 	for (fp = file; fp < fileNFILE; fp++)
61912760Ssam 		fp->f_flag &= ~(FMARK|FDEFER);
62012760Ssam 	do {
62112760Ssam 		for (fp = file; fp < fileNFILE; fp++) {
62212760Ssam 			if (fp->f_count == 0)
62312760Ssam 				continue;
62412760Ssam 			if (fp->f_flag & FDEFER) {
62512760Ssam 				fp->f_flag &= ~FDEFER;
62612760Ssam 				unp_defer--;
62712760Ssam 			} else {
62812760Ssam 				if (fp->f_flag & FMARK)
62912760Ssam 					continue;
63012760Ssam 				if (fp->f_count == fp->f_msgcount)
63112760Ssam 					continue;
63212760Ssam 				fp->f_flag |= FMARK;
63312760Ssam 			}
63433463Skarels 			if (fp->f_type != DTYPE_SOCKET ||
63533463Skarels 			    (so = (struct socket *)fp->f_data) == 0)
63612760Ssam 				continue;
63716995Skarels 			if (so->so_proto->pr_domain != &unixdomain ||
63821768Skarels 			    (so->so_proto->pr_flags&PR_RIGHTS) == 0)
63912760Ssam 				continue;
64012760Ssam 			if (so->so_rcv.sb_flags & SB_LOCK) {
64112760Ssam 				sbwait(&so->so_rcv);
64212760Ssam 				goto restart;
64312760Ssam 			}
64412760Ssam 			unp_scan(so->so_rcv.sb_mb, unp_mark);
64512760Ssam 		}
64612760Ssam 	} while (unp_defer);
64712760Ssam 	for (fp = file; fp < fileNFILE; fp++) {
64812760Ssam 		if (fp->f_count == 0)
64912760Ssam 			continue;
65025632Skarels 		if (fp->f_count == fp->f_msgcount && (fp->f_flag & FMARK) == 0)
65125632Skarels 			while (fp->f_msgcount)
65225632Skarels 				unp_discard(fp);
65312760Ssam 	}
65412760Ssam 	unp_gcing = 0;
65512760Ssam }
65612760Ssam 
65716995Skarels unp_dispose(m)
65816995Skarels 	struct mbuf *m;
65916995Skarels {
66016995Skarels 	int unp_discard();
66116995Skarels 
66217020Skarels 	if (m)
66317020Skarels 		unp_scan(m, unp_discard);
66416995Skarels }
66516995Skarels 
66616995Skarels unp_scan(m0, op)
66716995Skarels 	register struct mbuf *m0;
66812760Ssam 	int (*op)();
66912760Ssam {
67016995Skarels 	register struct mbuf *m;
67112760Ssam 	register struct file **rp;
67212760Ssam 	register int i;
67317020Skarels 	int qfds;
67412760Ssam 
67516995Skarels 	while (m0) {
67616995Skarels 		for (m = m0; m; m = m->m_next)
67716995Skarels 			if (m->m_type == MT_RIGHTS && m->m_len) {
67816995Skarels 				qfds = m->m_len / sizeof (struct file *);
67916995Skarels 				rp = mtod(m, struct file **);
68016995Skarels 				for (i = 0; i < qfds; i++)
68116995Skarels 					(*op)(*rp++);
68216995Skarels 				break;		/* XXX, but saves time */
68316995Skarels 			}
68417020Skarels 		m0 = m0->m_act;
68512760Ssam 	}
68612760Ssam }
68712760Ssam 
68812760Ssam unp_mark(fp)
68912760Ssam 	struct file *fp;
69012760Ssam {
69112760Ssam 
69212760Ssam 	if (fp->f_flag & FMARK)
69312760Ssam 		return;
69412760Ssam 	unp_defer++;
69512760Ssam 	fp->f_flag |= (FMARK|FDEFER);
69612760Ssam }
69712760Ssam 
69812760Ssam unp_discard(fp)
69912760Ssam 	struct file *fp;
70012760Ssam {
70112760Ssam 
70212760Ssam 	fp->f_msgcount--;
70325632Skarels 	unp_rights--;
70413084Ssam 	closef(fp);
70512760Ssam }
706