xref: /csrg-svn/sys/kern/uipc_usrreq.c (revision 43342)
123443Smckusick /*
237616Smckusick  * 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
1537616Smckusick  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1633288Sbostic  *
17*43342Smckusick  *	@(#)uipc_usrreq.c	7.19 (Berkeley) 06/21/90
1823443Smckusick  */
198925Sroot 
2017105Sbloom #include "param.h"
2117105Sbloom #include "user.h"
2217105Sbloom #include "domain.h"
2317105Sbloom #include "protosw.h"
2417105Sbloom #include "socket.h"
2517105Sbloom #include "socketvar.h"
2617105Sbloom #include "unpcb.h"
2717105Sbloom #include "un.h"
2837616Smckusick #include "vnode.h"
2917105Sbloom #include "file.h"
3017105Sbloom #include "stat.h"
3141381Smckusick #include "mbuf.h"
328925Sroot 
338925Sroot /*
348925Sroot  * Unix communications domain.
3512760Ssam  *
3612760Ssam  * TODO:
3712760Ssam  *	SEQPACKET, RDM
3813119Ssam  *	rethink name space problems
3912760Ssam  *	need a proper out-of-band
408925Sroot  */
4137617Smckusick struct	sockaddr sun_noname = { sizeof(sun_noname), AF_UNIX };
4240800Ssklower ino_t	unp_ino;			/* prototype for fake inode numbers */
438925Sroot 
448925Sroot /*ARGSUSED*/
4540800Ssklower uipc_usrreq(so, req, m, nam, control)
468925Sroot 	struct socket *so;
478925Sroot 	int req;
4840800Ssklower 	struct mbuf *m, *nam, *control;
498925Sroot {
508925Sroot 	struct unpcb *unp = sotounpcb(so);
518925Sroot 	register struct socket *so2;
5240937Skarels 	register int error = 0;
538925Sroot 
5425555Skarels 	if (req == PRU_CONTROL)
5525555Skarels 		return (EOPNOTSUPP);
5640800Ssklower 	if (req != PRU_SEND && control && control->m_len) {
5712760Ssam 		error = EOPNOTSUPP;
5812760Ssam 		goto release;
5912760Ssam 	}
6012760Ssam 	if (unp == 0 && req != PRU_ATTACH) {
6112760Ssam 		error = EINVAL;
6212760Ssam 		goto release;
6312760Ssam 	}
648925Sroot 	switch (req) {
658925Sroot 
668925Sroot 	case PRU_ATTACH:
678925Sroot 		if (unp) {
689169Ssam 			error = EISCONN;
698925Sroot 			break;
708925Sroot 		}
719028Sroot 		error = unp_attach(so);
728925Sroot 		break;
738925Sroot 
748925Sroot 	case PRU_DETACH:
758925Sroot 		unp_detach(unp);
768925Sroot 		break;
778925Sroot 
789169Ssam 	case PRU_BIND:
799169Ssam 		error = unp_bind(unp, nam);
809169Ssam 		break;
819169Ssam 
829169Ssam 	case PRU_LISTEN:
8337616Smckusick 		if (unp->unp_vnode == 0)
849169Ssam 			error = EINVAL;
859169Ssam 		break;
869169Ssam 
878925Sroot 	case PRU_CONNECT:
889028Sroot 		error = unp_connect(so, nam);
898925Sroot 		break;
908925Sroot 
9112760Ssam 	case PRU_CONNECT2:
9226281Skarels 		error = unp_connect2(so, (struct socket *)nam);
9312760Ssam 		break;
9412760Ssam 
958925Sroot 	case PRU_DISCONNECT:
968925Sroot 		unp_disconnect(unp);
978925Sroot 		break;
988925Sroot 
999169Ssam 	case PRU_ACCEPT:
10025899Skarels 		/*
10125899Skarels 		 * Pass back name of connected socket,
10225899Skarels 		 * if it was bound and we are still connected
10325899Skarels 		 * (our peer may have closed already!).
10425899Skarels 		 */
10525899Skarels 		if (unp->unp_conn && unp->unp_conn->unp_addr) {
10625632Skarels 			nam->m_len = unp->unp_conn->unp_addr->m_len;
10725632Skarels 			bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
10825632Skarels 			    mtod(nam, caddr_t), (unsigned)nam->m_len);
10925632Skarels 		} else {
11025632Skarels 			nam->m_len = sizeof(sun_noname);
11125632Skarels 			*(mtod(nam, struct sockaddr *)) = sun_noname;
11225632Skarels 		}
1138925Sroot 		break;
1148925Sroot 
1158925Sroot 	case PRU_SHUTDOWN:
1168925Sroot 		socantsendmore(so);
1178925Sroot 		unp_usrclosed(unp);
1188925Sroot 		break;
1198925Sroot 
1208925Sroot 	case PRU_RCVD:
1218925Sroot 		switch (so->so_type) {
1228925Sroot 
1238925Sroot 		case SOCK_DGRAM:
1248925Sroot 			panic("uipc 1");
12510139Ssam 			/*NOTREACHED*/
1268925Sroot 
12710139Ssam 		case SOCK_STREAM:
1288925Sroot #define	rcv (&so->so_rcv)
1298925Sroot #define snd (&so2->so_snd)
1308925Sroot 			if (unp->unp_conn == 0)
1318925Sroot 				break;
1328925Sroot 			so2 = unp->unp_conn->unp_socket;
1338925Sroot 			/*
13425632Skarels 			 * Adjust backpressure on sender
1358925Sroot 			 * and wakeup any waiting to write.
1368925Sroot 			 */
13725632Skarels 			snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt;
13825632Skarels 			unp->unp_mbcnt = rcv->sb_mbcnt;
13925632Skarels 			snd->sb_hiwat += unp->unp_cc - rcv->sb_cc;
14025632Skarels 			unp->unp_cc = rcv->sb_cc;
14117543Skarels 			sowwakeup(so2);
1428925Sroot #undef snd
1438925Sroot #undef rcv
1448925Sroot 			break;
1458925Sroot 
1468925Sroot 		default:
1478925Sroot 			panic("uipc 2");
1488925Sroot 		}
1498925Sroot 		break;
1508925Sroot 
1518925Sroot 	case PRU_SEND:
15240937Skarels 		if (control && (error = unp_internalize(control)))
15340937Skarels 			break;
1548925Sroot 		switch (so->so_type) {
1558925Sroot 
15625632Skarels 		case SOCK_DGRAM: {
15725632Skarels 			struct sockaddr *from;
15825632Skarels 
1599028Sroot 			if (nam) {
1608925Sroot 				if (unp->unp_conn) {
1618925Sroot 					error = EISCONN;
1628925Sroot 					break;
1638925Sroot 				}
1649028Sroot 				error = unp_connect(so, nam);
1658925Sroot 				if (error)
1668925Sroot 					break;
1678925Sroot 			} else {
1688925Sroot 				if (unp->unp_conn == 0) {
1698925Sroot 					error = ENOTCONN;
1708925Sroot 					break;
1718925Sroot 				}
1728925Sroot 			}
1738925Sroot 			so2 = unp->unp_conn->unp_socket;
17425632Skarels 			if (unp->unp_addr)
17525632Skarels 				from = mtod(unp->unp_addr, struct sockaddr *);
17625632Skarels 			else
17725632Skarels 				from = &sun_noname;
17840937Skarels 			if (sbappendaddr(&so2->so_rcv, from, m, control)) {
17925632Skarels 				sorwakeup(so2);
18025632Skarels 				m = 0;
18140937Skarels 				control = 0;
18225632Skarels 			} else
18325632Skarels 				error = ENOBUFS;
1849028Sroot 			if (nam)
1859169Ssam 				unp_disconnect(unp);
1868925Sroot 			break;
18725632Skarels 		}
1888925Sroot 
1898925Sroot 		case SOCK_STREAM:
1908925Sroot #define	rcv (&so2->so_rcv)
1918925Sroot #define	snd (&so->so_snd)
19223524Skarels 			if (so->so_state & SS_CANTSENDMORE) {
19323524Skarels 				error = EPIPE;
19423524Skarels 				break;
19523524Skarels 			}
1968925Sroot 			if (unp->unp_conn == 0)
1978925Sroot 				panic("uipc 3");
1988925Sroot 			so2 = unp->unp_conn->unp_socket;
1998925Sroot 			/*
20025632Skarels 			 * Send to paired receive port, and then reduce
20125632Skarels 			 * send buffer hiwater marks to maintain backpressure.
2028925Sroot 			 * Wake up readers.
2038925Sroot 			 */
20440937Skarels 			if (control) {
20540937Skarels 				(void)sbappendcontrol(rcv, m, control);
20640937Skarels 				control = 0;
20740937Skarels 			} else
20825632Skarels 				sbappend(rcv, m);
20925632Skarels 			snd->sb_mbmax -=
21025632Skarels 			    rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt;
21125632Skarels 			unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt;
21225632Skarels 			snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc;
21325632Skarels 			unp->unp_conn->unp_cc = rcv->sb_cc;
21417543Skarels 			sorwakeup(so2);
21517543Skarels 			m = 0;
2168925Sroot #undef snd
2178925Sroot #undef rcv
2188925Sroot 			break;
2198925Sroot 
2208925Sroot 		default:
2218925Sroot 			panic("uipc 4");
2228925Sroot 		}
2238925Sroot 		break;
2248925Sroot 
2258925Sroot 	case PRU_ABORT:
2268925Sroot 		unp_drop(unp, ECONNABORTED);
2278925Sroot 		break;
2288925Sroot 
2298925Sroot 	case PRU_SENSE:
23016973Skarels 		((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
23116973Skarels 		if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) {
23216973Skarels 			so2 = unp->unp_conn->unp_socket;
23316973Skarels 			((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc;
23416973Skarels 		}
23521110Skarels 		((struct stat *) m)->st_dev = NODEV;
23640800Ssklower 		if (unp->unp_ino == 0)
23740800Ssklower 			unp->unp_ino = unp_ino++;
23840800Ssklower 		((struct stat *) m)->st_ino = unp->unp_ino;
23916973Skarels 		return (0);
2408925Sroot 
2418925Sroot 	case PRU_RCVOOB:
24216774Sbloom 		return (EOPNOTSUPP);
2438925Sroot 
2448925Sroot 	case PRU_SENDOOB:
24517543Skarels 		error = EOPNOTSUPP;
2468925Sroot 		break;
2478925Sroot 
2488925Sroot 	case PRU_SOCKADDR:
24937617Smckusick 		if (unp->unp_addr) {
25037617Smckusick 			nam->m_len = unp->unp_addr->m_len;
25137617Smckusick 			bcopy(mtod(unp->unp_addr, caddr_t),
25237617Smckusick 			    mtod(nam, caddr_t), (unsigned)nam->m_len);
25337617Smckusick 		} else
25437617Smckusick 			nam->m_len = 0;
2558925Sroot 		break;
2568925Sroot 
25714121Ssam 	case PRU_PEERADDR:
25828292Skarels 		if (unp->unp_conn && unp->unp_conn->unp_addr) {
25928292Skarels 			nam->m_len = unp->unp_conn->unp_addr->m_len;
26028292Skarels 			bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
26133287Sbostic 			    mtod(nam, caddr_t), (unsigned)nam->m_len);
26237617Smckusick 		} else
26337617Smckusick 			nam->m_len = 0;
26414121Ssam 		break;
26514121Ssam 
2668925Sroot 	case PRU_SLOWTIMO:
2678925Sroot 		break;
2688925Sroot 
2698925Sroot 	default:
2708925Sroot 		panic("piusrreq");
2718925Sroot 	}
27212760Ssam release:
27340937Skarels 	if (control)
27440937Skarels 		m_freem(control);
27512760Ssam 	if (m)
27612760Ssam 		m_freem(m);
27711709Ssam 	return (error);
2788925Sroot }
2798925Sroot 
28016973Skarels /*
28125632Skarels  * Both send and receive buffers are allocated PIPSIZ bytes of buffering
28225632Skarels  * for stream sockets, although the total for sender and receiver is
28325632Skarels  * actually only PIPSIZ.
28416973Skarels  * Datagram sockets really use the sendspace as the maximum datagram size,
28516973Skarels  * and don't really want to reserve the sendspace.  Their recvspace should
28616973Skarels  * be large enough for at least one max-size datagram plus address.
28716973Skarels  */
28816973Skarels #define	PIPSIZ	4096
28937617Smckusick u_long	unpst_sendspace = PIPSIZ;
29037617Smckusick u_long	unpst_recvspace = PIPSIZ;
29137617Smckusick u_long	unpdg_sendspace = 2*1024;	/* really max datagram size */
29237617Smckusick u_long	unpdg_recvspace = 4*1024;
2938925Sroot 
29425632Skarels int	unp_rights;			/* file descriptors in flight */
29525632Skarels 
2969169Ssam unp_attach(so)
2978925Sroot 	struct socket *so;
2988925Sroot {
2999169Ssam 	register struct mbuf *m;
3008925Sroot 	register struct unpcb *unp;
3018925Sroot 	int error;
3028925Sroot 
30337617Smckusick 	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
30437617Smckusick 		switch (so->so_type) {
30516973Skarels 
30637617Smckusick 		case SOCK_STREAM:
30737617Smckusick 			error = soreserve(so, unpst_sendspace, unpst_recvspace);
30837617Smckusick 			break;
30916973Skarels 
31037617Smckusick 		case SOCK_DGRAM:
31137617Smckusick 			error = soreserve(so, unpdg_sendspace, unpdg_recvspace);
31237617Smckusick 			break;
31337617Smckusick 		}
31437617Smckusick 		if (error)
31537617Smckusick 			return (error);
31616973Skarels 	}
3179637Ssam 	m = m_getclr(M_DONTWAIT, MT_PCB);
31810139Ssam 	if (m == NULL)
31910139Ssam 		return (ENOBUFS);
3208925Sroot 	unp = mtod(m, struct unpcb *);
3218925Sroot 	so->so_pcb = (caddr_t)unp;
3228925Sroot 	unp->unp_socket = so;
3238925Sroot 	return (0);
3248925Sroot }
3258925Sroot 
3268925Sroot unp_detach(unp)
3279169Ssam 	register struct unpcb *unp;
3288925Sroot {
3298925Sroot 
33037616Smckusick 	if (unp->unp_vnode) {
33137616Smckusick 		unp->unp_vnode->v_socket = 0;
33237616Smckusick 		vrele(unp->unp_vnode);
33337616Smckusick 		unp->unp_vnode = 0;
3348925Sroot 	}
3358925Sroot 	if (unp->unp_conn)
3368925Sroot 		unp_disconnect(unp);
3378925Sroot 	while (unp->unp_refs)
3388925Sroot 		unp_drop(unp->unp_refs, ECONNRESET);
3398925Sroot 	soisdisconnected(unp->unp_socket);
3408925Sroot 	unp->unp_socket->so_pcb = 0;
34125632Skarels 	m_freem(unp->unp_addr);
3429169Ssam 	(void) m_free(dtom(unp));
34325632Skarels 	if (unp_rights)
34425632Skarels 		unp_gc();
3458925Sroot }
3468925Sroot 
3479169Ssam unp_bind(unp, nam)
3488925Sroot 	struct unpcb *unp;
3499169Ssam 	struct mbuf *nam;
3508925Sroot {
3519169Ssam 	struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
35237616Smckusick 	register struct vnode *vp;
35316695Smckusick 	register struct nameidata *ndp = &u.u_nd;
35437616Smckusick 	struct vattr vattr;
3558925Sroot 	int error;
3568925Sroot 
35716695Smckusick 	ndp->ni_dirp = soun->sun_path;
35837617Smckusick 	if (unp->unp_vnode != NULL)
35912760Ssam 		return (EINVAL);
36037617Smckusick 	if (nam->m_len == MLEN) {
36137617Smckusick 		if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)
36237617Smckusick 			return (EINVAL);
36337617Smckusick 	} else
36437617Smckusick 		*(mtod(nam, caddr_t) + nam->m_len) = 0;
36512760Ssam /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
36637616Smckusick 	ndp->ni_nameiop = CREATE | FOLLOW | LOCKPARENT;
36716695Smckusick 	ndp->ni_segflg = UIO_SYSSPACE;
36837616Smckusick 	if (error = namei(ndp))
36937616Smckusick 		return (error);
37037616Smckusick 	vp = ndp->ni_vp;
37137616Smckusick 	if (vp != NULL) {
37237728Smckusick 		VOP_ABORTOP(ndp);
373*43342Smckusick 		if (ndp->ni_dvp == vp)
374*43342Smckusick 			vrele(ndp->ni_dvp);
375*43342Smckusick 		else
376*43342Smckusick 			vput(ndp->ni_dvp);
37742465Smckusick 		vrele(vp);
37810139Ssam 		return (EADDRINUSE);
3798925Sroot 	}
38041362Smckusick 	VATTR_NULL(&vattr);
38137616Smckusick 	vattr.va_type = VSOCK;
38237616Smckusick 	vattr.va_mode = 0777;
38337728Smckusick 	if (error = VOP_CREATE(ndp, &vattr))
38411828Ssam 		return (error);
38537616Smckusick 	vp = ndp->ni_vp;
38637616Smckusick 	vp->v_socket = unp->unp_socket;
38737616Smckusick 	unp->unp_vnode = vp;
38825632Skarels 	unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL);
38937728Smckusick 	VOP_UNLOCK(vp);
3908925Sroot 	return (0);
3918925Sroot }
3928925Sroot 
3939169Ssam unp_connect(so, nam)
3948925Sroot 	struct socket *so;
3959169Ssam 	struct mbuf *nam;
3968925Sroot {
3979169Ssam 	register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
39837616Smckusick 	register struct vnode *vp;
39937617Smckusick 	register struct socket *so2, *so3;
40037617Smckusick 	register struct nameidata *ndp = &u.u_nd;
40137617Smckusick 	struct unpcb *unp2, *unp3;
40237616Smckusick 	int error;
4038925Sroot 
40416695Smckusick 	ndp->ni_dirp = soun->sun_path;
40537617Smckusick 	if (nam->m_data + nam->m_len == &nam->m_dat[MLEN]) {	/* XXX */
40637617Smckusick 		if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)
40737617Smckusick 			return (EMSGSIZE);
40837617Smckusick 	} else
40937617Smckusick 		*(mtod(nam, caddr_t) + nam->m_len) = 0;
41037728Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
41116695Smckusick 	ndp->ni_segflg = UIO_SYSSPACE;
41237616Smckusick 	if (error = namei(ndp))
41337616Smckusick 		return (error);
41437616Smckusick 	vp = ndp->ni_vp;
41537616Smckusick 	if (vp->v_type != VSOCK) {
4168925Sroot 		error = ENOTSOCK;
4178925Sroot 		goto bad;
4188925Sroot 	}
41938396Smckusick 	if (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))
42038396Smckusick 		goto bad;
42137616Smckusick 	so2 = vp->v_socket;
4228925Sroot 	if (so2 == 0) {
4238925Sroot 		error = ECONNREFUSED;
4248925Sroot 		goto bad;
4258925Sroot 	}
42613115Ssam 	if (so->so_type != so2->so_type) {
42713115Ssam 		error = EPROTOTYPE;
42813115Ssam 		goto bad;
42913115Ssam 	}
43037617Smckusick 	if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
43137617Smckusick 		if ((so2->so_options & SO_ACCEPTCONN) == 0 ||
43240800Ssklower 		    (so3 = sonewconn(so2, 0)) == 0) {
43337617Smckusick 			error = ECONNREFUSED;
43437617Smckusick 			goto bad;
43537617Smckusick 		}
43637617Smckusick 		unp2 = sotounpcb(so2);
43737617Smckusick 		unp3 = sotounpcb(so3);
43837617Smckusick 		if (unp2->unp_addr)
43937617Smckusick 			unp3->unp_addr =
44037617Smckusick 				  m_copy(unp2->unp_addr, 0, (int)M_COPYALL);
44137617Smckusick 		so2 = so3;
44213115Ssam 	}
44326281Skarels 	error = unp_connect2(so, so2);
44412760Ssam bad:
44537728Smckusick 	vput(vp);
44612760Ssam 	return (error);
44712760Ssam }
44812760Ssam 
44926281Skarels unp_connect2(so, so2)
45012760Ssam 	register struct socket *so;
45112760Ssam 	register struct socket *so2;
45212760Ssam {
45312760Ssam 	register struct unpcb *unp = sotounpcb(so);
45412760Ssam 	register struct unpcb *unp2;
45512760Ssam 
45612760Ssam 	if (so2->so_type != so->so_type)
45712760Ssam 		return (EPROTOTYPE);
45814049Ssam 	unp2 = sotounpcb(so2);
45914049Ssam 	unp->unp_conn = unp2;
4608925Sroot 	switch (so->so_type) {
4618925Sroot 
4628925Sroot 	case SOCK_DGRAM:
4638925Sroot 		unp->unp_nextref = unp2->unp_refs;
4648925Sroot 		unp2->unp_refs = unp;
46517543Skarels 		soisconnected(so);
4668925Sroot 		break;
4678925Sroot 
4688925Sroot 	case SOCK_STREAM:
4699169Ssam 		unp2->unp_conn = unp;
47040800Ssklower 		soisconnected(so);
47114049Ssam 		soisconnected(so2);
4728925Sroot 		break;
4738925Sroot 
4748925Sroot 	default:
47512760Ssam 		panic("unp_connect2");
4768925Sroot 	}
4778925Sroot 	return (0);
4788925Sroot }
4799169Ssam 
4809169Ssam unp_disconnect(unp)
4819169Ssam 	struct unpcb *unp;
4829169Ssam {
4839169Ssam 	register struct unpcb *unp2 = unp->unp_conn;
4849169Ssam 
4859169Ssam 	if (unp2 == 0)
4869169Ssam 		return;
4879169Ssam 	unp->unp_conn = 0;
4889169Ssam 	switch (unp->unp_socket->so_type) {
4899169Ssam 
4909169Ssam 	case SOCK_DGRAM:
4919169Ssam 		if (unp2->unp_refs == unp)
4929169Ssam 			unp2->unp_refs = unp->unp_nextref;
4939169Ssam 		else {
4949169Ssam 			unp2 = unp2->unp_refs;
4959169Ssam 			for (;;) {
4969169Ssam 				if (unp2 == 0)
4979169Ssam 					panic("unp_disconnect");
4989169Ssam 				if (unp2->unp_nextref == unp)
4999169Ssam 					break;
5009169Ssam 				unp2 = unp2->unp_nextref;
5019169Ssam 			}
5029169Ssam 			unp2->unp_nextref = unp->unp_nextref;
5039169Ssam 		}
5049169Ssam 		unp->unp_nextref = 0;
50521768Skarels 		unp->unp_socket->so_state &= ~SS_ISCONNECTED;
5069169Ssam 		break;
5079169Ssam 
5089169Ssam 	case SOCK_STREAM:
50914049Ssam 		soisdisconnected(unp->unp_socket);
5109169Ssam 		unp2->unp_conn = 0;
5119169Ssam 		soisdisconnected(unp2->unp_socket);
5129169Ssam 		break;
5139169Ssam 	}
5149169Ssam }
5159169Ssam 
51612760Ssam #ifdef notdef
5179169Ssam unp_abort(unp)
5189169Ssam 	struct unpcb *unp;
5199169Ssam {
5209169Ssam 
5219169Ssam 	unp_detach(unp);
5229169Ssam }
52312760Ssam #endif
5249169Ssam 
5259169Ssam /*ARGSUSED*/
5269169Ssam unp_usrclosed(unp)
5279169Ssam 	struct unpcb *unp;
5289169Ssam {
5299169Ssam 
5309169Ssam }
5319169Ssam 
5329169Ssam unp_drop(unp, errno)
5339169Ssam 	struct unpcb *unp;
5349169Ssam 	int errno;
5359169Ssam {
53616054Skarels 	struct socket *so = unp->unp_socket;
5379169Ssam 
53816054Skarels 	so->so_error = errno;
5399169Ssam 	unp_disconnect(unp);
54016054Skarels 	if (so->so_head) {
54116054Skarels 		so->so_pcb = (caddr_t) 0;
54225632Skarels 		m_freem(unp->unp_addr);
54316054Skarels 		(void) m_free(dtom(unp));
54416054Skarels 		sofree(so);
54516054Skarels 	}
5469169Ssam }
5479169Ssam 
54812760Ssam #ifdef notdef
5499169Ssam unp_drain()
5509169Ssam {
5519169Ssam 
5529169Ssam }
55312760Ssam #endif
55412760Ssam 
55512760Ssam unp_externalize(rights)
55612760Ssam 	struct mbuf *rights;
55712760Ssam {
55812760Ssam 	register int i;
55940800Ssklower 	register struct cmsghdr *cm = mtod(rights, struct cmsghdr *);
56040800Ssklower 	register struct file **rp = (struct file **)(cm + 1);
56112760Ssam 	register struct file *fp;
56240800Ssklower 	int newfds = (cm->cmsg_len - sizeof(*cm)) / sizeof (int);
56312760Ssam 	int f;
56412760Ssam 
56512760Ssam 	if (newfds > ufavail()) {
56612760Ssam 		for (i = 0; i < newfds; i++) {
56712760Ssam 			fp = *rp;
56812760Ssam 			unp_discard(fp);
56912760Ssam 			*rp++ = 0;
57012760Ssam 		}
57112760Ssam 		return (EMSGSIZE);
57212760Ssam 	}
57312760Ssam 	for (i = 0; i < newfds; i++) {
57437616Smckusick 		if (ufalloc(0, &f))
57512760Ssam 			panic("unp_externalize");
57612760Ssam 		fp = *rp;
57712760Ssam 		u.u_ofile[f] = fp;
57812760Ssam 		fp->f_msgcount--;
57925632Skarels 		unp_rights--;
58014927Smckusick 		*(int *)rp++ = f;
58112760Ssam 	}
58212760Ssam 	return (0);
58312760Ssam }
58412760Ssam 
58540937Skarels unp_internalize(control)
58640937Skarels 	struct mbuf *control;
58712760Ssam {
58840937Skarels 	register struct cmsghdr *cm = mtod(control, struct cmsghdr *);
58912760Ssam 	register struct file **rp;
59040937Skarels 	register struct file *fp;
59137728Smckusick 	register int i, fd;
59240937Skarels 	int oldfds;
59312760Ssam 
59440937Skarels 	if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||
59540937Skarels 	    cm->cmsg_len != control->m_len)
59640800Ssklower 		return (EINVAL);
59740800Ssklower 	oldfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int);
59840800Ssklower 	rp = (struct file **)(cm + 1);
59937728Smckusick 	for (i = 0; i < oldfds; i++) {
60037728Smckusick 		fd = *(int *)rp++;
60137728Smckusick 		if ((unsigned)fd >= NOFILE || u.u_ofile[fd] == NULL)
60212760Ssam 			return (EBADF);
60337728Smckusick 	}
60440800Ssklower 	rp = (struct file **)(cm + 1);
60513084Ssam 	for (i = 0; i < oldfds; i++) {
60637728Smckusick 		fp = u.u_ofile[*(int *)rp];
60712760Ssam 		*rp++ = fp;
60812760Ssam 		fp->f_count++;
60912760Ssam 		fp->f_msgcount++;
61025632Skarels 		unp_rights++;
61112760Ssam 	}
61212760Ssam 	return (0);
61312760Ssam }
61412760Ssam 
61512760Ssam int	unp_defer, unp_gcing;
61612760Ssam int	unp_mark();
61716995Skarels extern	struct domain unixdomain;
61812760Ssam 
61912760Ssam unp_gc()
62012760Ssam {
62112760Ssam 	register struct file *fp;
62212760Ssam 	register struct socket *so;
62312760Ssam 
62412760Ssam 	if (unp_gcing)
62512760Ssam 		return;
62612760Ssam 	unp_gcing = 1;
62712760Ssam restart:
62812760Ssam 	unp_defer = 0;
62912760Ssam 	for (fp = file; fp < fileNFILE; fp++)
63012760Ssam 		fp->f_flag &= ~(FMARK|FDEFER);
63112760Ssam 	do {
63212760Ssam 		for (fp = file; fp < fileNFILE; fp++) {
63312760Ssam 			if (fp->f_count == 0)
63412760Ssam 				continue;
63512760Ssam 			if (fp->f_flag & FDEFER) {
63612760Ssam 				fp->f_flag &= ~FDEFER;
63712760Ssam 				unp_defer--;
63812760Ssam 			} else {
63912760Ssam 				if (fp->f_flag & FMARK)
64012760Ssam 					continue;
64112760Ssam 				if (fp->f_count == fp->f_msgcount)
64212760Ssam 					continue;
64312760Ssam 				fp->f_flag |= FMARK;
64412760Ssam 			}
64537617Smckusick 			if (fp->f_type != DTYPE_SOCKET ||
64637617Smckusick 			    (so = (struct socket *)fp->f_data) == 0)
64712760Ssam 				continue;
64816995Skarels 			if (so->so_proto->pr_domain != &unixdomain ||
64921768Skarels 			    (so->so_proto->pr_flags&PR_RIGHTS) == 0)
65012760Ssam 				continue;
65112760Ssam 			if (so->so_rcv.sb_flags & SB_LOCK) {
65212760Ssam 				sbwait(&so->so_rcv);
65312760Ssam 				goto restart;
65412760Ssam 			}
65512760Ssam 			unp_scan(so->so_rcv.sb_mb, unp_mark);
65612760Ssam 		}
65712760Ssam 	} while (unp_defer);
65812760Ssam 	for (fp = file; fp < fileNFILE; fp++) {
65912760Ssam 		if (fp->f_count == 0)
66012760Ssam 			continue;
66125632Skarels 		if (fp->f_count == fp->f_msgcount && (fp->f_flag & FMARK) == 0)
66225632Skarels 			while (fp->f_msgcount)
66325632Skarels 				unp_discard(fp);
66412760Ssam 	}
66512760Ssam 	unp_gcing = 0;
66612760Ssam }
66712760Ssam 
66816995Skarels unp_dispose(m)
66916995Skarels 	struct mbuf *m;
67016995Skarels {
67116995Skarels 	int unp_discard();
67216995Skarels 
67317020Skarels 	if (m)
67417020Skarels 		unp_scan(m, unp_discard);
67516995Skarels }
67616995Skarels 
67716995Skarels unp_scan(m0, op)
67816995Skarels 	register struct mbuf *m0;
67912760Ssam 	int (*op)();
68012760Ssam {
68116995Skarels 	register struct mbuf *m;
68212760Ssam 	register struct file **rp;
68340937Skarels 	register struct cmsghdr *cm;
68412760Ssam 	register int i;
68517020Skarels 	int qfds;
68612760Ssam 
68716995Skarels 	while (m0) {
68816995Skarels 		for (m = m0; m; m = m->m_next)
68940937Skarels 			if (m->m_type == MT_CONTROL &&
69040937Skarels 			    m->m_len >= sizeof(*cm)) {
69140800Ssklower 				cm = mtod(m, struct cmsghdr *);
69240937Skarels 				if (cm->cmsg_level != SOL_SOCKET ||
69340937Skarels 				    cm->cmsg_type != SCM_RIGHTS)
69440937Skarels 					continue;
69540800Ssklower 				qfds = (cm->cmsg_len - sizeof *cm)
69640800Ssklower 						/ sizeof (struct file *);
69740800Ssklower 				rp = (struct file **)(cm + 1);
69816995Skarels 				for (i = 0; i < qfds; i++)
69916995Skarels 					(*op)(*rp++);
70016995Skarels 				break;		/* XXX, but saves time */
70116995Skarels 			}
70217020Skarels 		m0 = m0->m_act;
70312760Ssam 	}
70412760Ssam }
70512760Ssam 
70612760Ssam unp_mark(fp)
70712760Ssam 	struct file *fp;
70812760Ssam {
70912760Ssam 
71012760Ssam 	if (fp->f_flag & FMARK)
71112760Ssam 		return;
71212760Ssam 	unp_defer++;
71312760Ssam 	fp->f_flag |= (FMARK|FDEFER);
71412760Ssam }
71512760Ssam 
71612760Ssam unp_discard(fp)
71712760Ssam 	struct file *fp;
71812760Ssam {
71912760Ssam 
72012760Ssam 	fp->f_msgcount--;
72125632Skarels 	unp_rights--;
72239353Smckusick 	(void) closef(fp);
72312760Ssam }
724