xref: /csrg-svn/sys/kern/uipc_usrreq.c (revision 45004)
123443Smckusick /*
237616Smckusick  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
333288Sbostic  * All rights reserved.
423443Smckusick  *
544453Sbostic  * %sccs.include.redist.c%
633288Sbostic  *
7*45004Skarels  *	@(#)uipc_usrreq.c	7.21 (Berkeley) 07/27/90
823443Smckusick  */
98925Sroot 
1017105Sbloom #include "param.h"
1117105Sbloom #include "user.h"
1217105Sbloom #include "domain.h"
1317105Sbloom #include "protosw.h"
1417105Sbloom #include "socket.h"
1517105Sbloom #include "socketvar.h"
1617105Sbloom #include "unpcb.h"
1717105Sbloom #include "un.h"
1837616Smckusick #include "vnode.h"
1917105Sbloom #include "file.h"
2017105Sbloom #include "stat.h"
2141381Smckusick #include "mbuf.h"
228925Sroot 
238925Sroot /*
248925Sroot  * Unix communications domain.
2512760Ssam  *
2612760Ssam  * TODO:
2712760Ssam  *	SEQPACKET, RDM
2813119Ssam  *	rethink name space problems
2912760Ssam  *	need a proper out-of-band
308925Sroot  */
3137617Smckusick struct	sockaddr sun_noname = { sizeof(sun_noname), AF_UNIX };
3240800Ssklower ino_t	unp_ino;			/* prototype for fake inode numbers */
338925Sroot 
348925Sroot /*ARGSUSED*/
3540800Ssklower uipc_usrreq(so, req, m, nam, control)
368925Sroot 	struct socket *so;
378925Sroot 	int req;
3840800Ssklower 	struct mbuf *m, *nam, *control;
398925Sroot {
408925Sroot 	struct unpcb *unp = sotounpcb(so);
418925Sroot 	register struct socket *so2;
4240937Skarels 	register int error = 0;
438925Sroot 
4425555Skarels 	if (req == PRU_CONTROL)
4525555Skarels 		return (EOPNOTSUPP);
4640800Ssklower 	if (req != PRU_SEND && control && control->m_len) {
4712760Ssam 		error = EOPNOTSUPP;
4812760Ssam 		goto release;
4912760Ssam 	}
5012760Ssam 	if (unp == 0 && req != PRU_ATTACH) {
5112760Ssam 		error = EINVAL;
5212760Ssam 		goto release;
5312760Ssam 	}
548925Sroot 	switch (req) {
558925Sroot 
568925Sroot 	case PRU_ATTACH:
578925Sroot 		if (unp) {
589169Ssam 			error = EISCONN;
598925Sroot 			break;
608925Sroot 		}
619028Sroot 		error = unp_attach(so);
628925Sroot 		break;
638925Sroot 
648925Sroot 	case PRU_DETACH:
658925Sroot 		unp_detach(unp);
668925Sroot 		break;
678925Sroot 
689169Ssam 	case PRU_BIND:
699169Ssam 		error = unp_bind(unp, nam);
709169Ssam 		break;
719169Ssam 
729169Ssam 	case PRU_LISTEN:
7337616Smckusick 		if (unp->unp_vnode == 0)
749169Ssam 			error = EINVAL;
759169Ssam 		break;
769169Ssam 
778925Sroot 	case PRU_CONNECT:
789028Sroot 		error = unp_connect(so, nam);
798925Sroot 		break;
808925Sroot 
8112760Ssam 	case PRU_CONNECT2:
8226281Skarels 		error = unp_connect2(so, (struct socket *)nam);
8312760Ssam 		break;
8412760Ssam 
858925Sroot 	case PRU_DISCONNECT:
868925Sroot 		unp_disconnect(unp);
878925Sroot 		break;
888925Sroot 
899169Ssam 	case PRU_ACCEPT:
9025899Skarels 		/*
9125899Skarels 		 * Pass back name of connected socket,
9225899Skarels 		 * if it was bound and we are still connected
9325899Skarels 		 * (our peer may have closed already!).
9425899Skarels 		 */
9525899Skarels 		if (unp->unp_conn && unp->unp_conn->unp_addr) {
9625632Skarels 			nam->m_len = unp->unp_conn->unp_addr->m_len;
9725632Skarels 			bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
9825632Skarels 			    mtod(nam, caddr_t), (unsigned)nam->m_len);
9925632Skarels 		} else {
10025632Skarels 			nam->m_len = sizeof(sun_noname);
10125632Skarels 			*(mtod(nam, struct sockaddr *)) = sun_noname;
10225632Skarels 		}
1038925Sroot 		break;
1048925Sroot 
1058925Sroot 	case PRU_SHUTDOWN:
1068925Sroot 		socantsendmore(so);
107*45004Skarels 		unp_shutdown(unp);
1088925Sroot 		break;
1098925Sroot 
1108925Sroot 	case PRU_RCVD:
1118925Sroot 		switch (so->so_type) {
1128925Sroot 
1138925Sroot 		case SOCK_DGRAM:
1148925Sroot 			panic("uipc 1");
11510139Ssam 			/*NOTREACHED*/
1168925Sroot 
11710139Ssam 		case SOCK_STREAM:
1188925Sroot #define	rcv (&so->so_rcv)
1198925Sroot #define snd (&so2->so_snd)
1208925Sroot 			if (unp->unp_conn == 0)
1218925Sroot 				break;
1228925Sroot 			so2 = unp->unp_conn->unp_socket;
1238925Sroot 			/*
12425632Skarels 			 * Adjust backpressure on sender
1258925Sroot 			 * and wakeup any waiting to write.
1268925Sroot 			 */
12725632Skarels 			snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt;
12825632Skarels 			unp->unp_mbcnt = rcv->sb_mbcnt;
12925632Skarels 			snd->sb_hiwat += unp->unp_cc - rcv->sb_cc;
13025632Skarels 			unp->unp_cc = rcv->sb_cc;
13117543Skarels 			sowwakeup(so2);
1328925Sroot #undef snd
1338925Sroot #undef rcv
1348925Sroot 			break;
1358925Sroot 
1368925Sroot 		default:
1378925Sroot 			panic("uipc 2");
1388925Sroot 		}
1398925Sroot 		break;
1408925Sroot 
1418925Sroot 	case PRU_SEND:
14240937Skarels 		if (control && (error = unp_internalize(control)))
14340937Skarels 			break;
1448925Sroot 		switch (so->so_type) {
1458925Sroot 
14625632Skarels 		case SOCK_DGRAM: {
14725632Skarels 			struct sockaddr *from;
14825632Skarels 
1499028Sroot 			if (nam) {
1508925Sroot 				if (unp->unp_conn) {
1518925Sroot 					error = EISCONN;
1528925Sroot 					break;
1538925Sroot 				}
1549028Sroot 				error = unp_connect(so, nam);
1558925Sroot 				if (error)
1568925Sroot 					break;
1578925Sroot 			} else {
1588925Sroot 				if (unp->unp_conn == 0) {
1598925Sroot 					error = ENOTCONN;
1608925Sroot 					break;
1618925Sroot 				}
1628925Sroot 			}
1638925Sroot 			so2 = unp->unp_conn->unp_socket;
16425632Skarels 			if (unp->unp_addr)
16525632Skarels 				from = mtod(unp->unp_addr, struct sockaddr *);
16625632Skarels 			else
16725632Skarels 				from = &sun_noname;
16840937Skarels 			if (sbappendaddr(&so2->so_rcv, from, m, control)) {
16925632Skarels 				sorwakeup(so2);
17025632Skarels 				m = 0;
17140937Skarels 				control = 0;
17225632Skarels 			} else
17325632Skarels 				error = ENOBUFS;
1749028Sroot 			if (nam)
1759169Ssam 				unp_disconnect(unp);
1768925Sroot 			break;
17725632Skarels 		}
1788925Sroot 
1798925Sroot 		case SOCK_STREAM:
1808925Sroot #define	rcv (&so2->so_rcv)
1818925Sroot #define	snd (&so->so_snd)
18223524Skarels 			if (so->so_state & SS_CANTSENDMORE) {
18323524Skarels 				error = EPIPE;
18423524Skarels 				break;
18523524Skarels 			}
1868925Sroot 			if (unp->unp_conn == 0)
1878925Sroot 				panic("uipc 3");
1888925Sroot 			so2 = unp->unp_conn->unp_socket;
1898925Sroot 			/*
19025632Skarels 			 * Send to paired receive port, and then reduce
19125632Skarels 			 * send buffer hiwater marks to maintain backpressure.
1928925Sroot 			 * Wake up readers.
1938925Sroot 			 */
19440937Skarels 			if (control) {
195*45004Skarels 				if (sbappendcontrol(rcv, m, control))
196*45004Skarels 					control = 0;
19740937Skarels 			} else
19825632Skarels 				sbappend(rcv, m);
19925632Skarels 			snd->sb_mbmax -=
20025632Skarels 			    rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt;
20125632Skarels 			unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt;
20225632Skarels 			snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc;
20325632Skarels 			unp->unp_conn->unp_cc = rcv->sb_cc;
20417543Skarels 			sorwakeup(so2);
20517543Skarels 			m = 0;
2068925Sroot #undef snd
2078925Sroot #undef rcv
2088925Sroot 			break;
2098925Sroot 
2108925Sroot 		default:
2118925Sroot 			panic("uipc 4");
2128925Sroot 		}
2138925Sroot 		break;
2148925Sroot 
2158925Sroot 	case PRU_ABORT:
2168925Sroot 		unp_drop(unp, ECONNABORTED);
2178925Sroot 		break;
2188925Sroot 
2198925Sroot 	case PRU_SENSE:
22016973Skarels 		((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
22116973Skarels 		if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) {
22216973Skarels 			so2 = unp->unp_conn->unp_socket;
22316973Skarels 			((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc;
22416973Skarels 		}
22521110Skarels 		((struct stat *) m)->st_dev = NODEV;
22640800Ssklower 		if (unp->unp_ino == 0)
22740800Ssklower 			unp->unp_ino = unp_ino++;
22840800Ssklower 		((struct stat *) m)->st_ino = unp->unp_ino;
22916973Skarels 		return (0);
2308925Sroot 
2318925Sroot 	case PRU_RCVOOB:
23216774Sbloom 		return (EOPNOTSUPP);
2338925Sroot 
2348925Sroot 	case PRU_SENDOOB:
23517543Skarels 		error = EOPNOTSUPP;
2368925Sroot 		break;
2378925Sroot 
2388925Sroot 	case PRU_SOCKADDR:
23937617Smckusick 		if (unp->unp_addr) {
24037617Smckusick 			nam->m_len = unp->unp_addr->m_len;
24137617Smckusick 			bcopy(mtod(unp->unp_addr, caddr_t),
24237617Smckusick 			    mtod(nam, caddr_t), (unsigned)nam->m_len);
24337617Smckusick 		} else
24437617Smckusick 			nam->m_len = 0;
2458925Sroot 		break;
2468925Sroot 
24714121Ssam 	case PRU_PEERADDR:
24828292Skarels 		if (unp->unp_conn && unp->unp_conn->unp_addr) {
24928292Skarels 			nam->m_len = unp->unp_conn->unp_addr->m_len;
25028292Skarels 			bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
25133287Sbostic 			    mtod(nam, caddr_t), (unsigned)nam->m_len);
25237617Smckusick 		} else
25337617Smckusick 			nam->m_len = 0;
25414121Ssam 		break;
25514121Ssam 
2568925Sroot 	case PRU_SLOWTIMO:
2578925Sroot 		break;
2588925Sroot 
2598925Sroot 	default:
2608925Sroot 		panic("piusrreq");
2618925Sroot 	}
26212760Ssam release:
26340937Skarels 	if (control)
26440937Skarels 		m_freem(control);
26512760Ssam 	if (m)
26612760Ssam 		m_freem(m);
26711709Ssam 	return (error);
2688925Sroot }
2698925Sroot 
27016973Skarels /*
27125632Skarels  * Both send and receive buffers are allocated PIPSIZ bytes of buffering
27225632Skarels  * for stream sockets, although the total for sender and receiver is
27325632Skarels  * actually only PIPSIZ.
27416973Skarels  * Datagram sockets really use the sendspace as the maximum datagram size,
27516973Skarels  * and don't really want to reserve the sendspace.  Their recvspace should
27616973Skarels  * be large enough for at least one max-size datagram plus address.
27716973Skarels  */
27816973Skarels #define	PIPSIZ	4096
27937617Smckusick u_long	unpst_sendspace = PIPSIZ;
28037617Smckusick u_long	unpst_recvspace = PIPSIZ;
28137617Smckusick u_long	unpdg_sendspace = 2*1024;	/* really max datagram size */
28237617Smckusick u_long	unpdg_recvspace = 4*1024;
2838925Sroot 
28425632Skarels int	unp_rights;			/* file descriptors in flight */
28525632Skarels 
2869169Ssam unp_attach(so)
2878925Sroot 	struct socket *so;
2888925Sroot {
2899169Ssam 	register struct mbuf *m;
2908925Sroot 	register struct unpcb *unp;
2918925Sroot 	int error;
2928925Sroot 
29337617Smckusick 	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
29437617Smckusick 		switch (so->so_type) {
29516973Skarels 
29637617Smckusick 		case SOCK_STREAM:
29737617Smckusick 			error = soreserve(so, unpst_sendspace, unpst_recvspace);
29837617Smckusick 			break;
29916973Skarels 
30037617Smckusick 		case SOCK_DGRAM:
30137617Smckusick 			error = soreserve(so, unpdg_sendspace, unpdg_recvspace);
30237617Smckusick 			break;
30337617Smckusick 		}
30437617Smckusick 		if (error)
30537617Smckusick 			return (error);
30616973Skarels 	}
3079637Ssam 	m = m_getclr(M_DONTWAIT, MT_PCB);
30810139Ssam 	if (m == NULL)
30910139Ssam 		return (ENOBUFS);
3108925Sroot 	unp = mtod(m, struct unpcb *);
3118925Sroot 	so->so_pcb = (caddr_t)unp;
3128925Sroot 	unp->unp_socket = so;
3138925Sroot 	return (0);
3148925Sroot }
3158925Sroot 
3168925Sroot unp_detach(unp)
3179169Ssam 	register struct unpcb *unp;
3188925Sroot {
3198925Sroot 
32037616Smckusick 	if (unp->unp_vnode) {
32137616Smckusick 		unp->unp_vnode->v_socket = 0;
32237616Smckusick 		vrele(unp->unp_vnode);
32337616Smckusick 		unp->unp_vnode = 0;
3248925Sroot 	}
3258925Sroot 	if (unp->unp_conn)
3268925Sroot 		unp_disconnect(unp);
3278925Sroot 	while (unp->unp_refs)
3288925Sroot 		unp_drop(unp->unp_refs, ECONNRESET);
3298925Sroot 	soisdisconnected(unp->unp_socket);
3308925Sroot 	unp->unp_socket->so_pcb = 0;
33125632Skarels 	m_freem(unp->unp_addr);
3329169Ssam 	(void) m_free(dtom(unp));
33325632Skarels 	if (unp_rights)
33425632Skarels 		unp_gc();
3358925Sroot }
3368925Sroot 
3379169Ssam unp_bind(unp, nam)
3388925Sroot 	struct unpcb *unp;
3399169Ssam 	struct mbuf *nam;
3408925Sroot {
3419169Ssam 	struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
34237616Smckusick 	register struct vnode *vp;
34316695Smckusick 	register struct nameidata *ndp = &u.u_nd;
34437616Smckusick 	struct vattr vattr;
3458925Sroot 	int error;
3468925Sroot 
34716695Smckusick 	ndp->ni_dirp = soun->sun_path;
34837617Smckusick 	if (unp->unp_vnode != NULL)
34912760Ssam 		return (EINVAL);
35037617Smckusick 	if (nam->m_len == MLEN) {
35137617Smckusick 		if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)
35237617Smckusick 			return (EINVAL);
35337617Smckusick 	} else
35437617Smckusick 		*(mtod(nam, caddr_t) + nam->m_len) = 0;
35512760Ssam /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
35637616Smckusick 	ndp->ni_nameiop = CREATE | FOLLOW | LOCKPARENT;
35716695Smckusick 	ndp->ni_segflg = UIO_SYSSPACE;
35837616Smckusick 	if (error = namei(ndp))
35937616Smckusick 		return (error);
36037616Smckusick 	vp = ndp->ni_vp;
36137616Smckusick 	if (vp != NULL) {
36237728Smckusick 		VOP_ABORTOP(ndp);
36343342Smckusick 		if (ndp->ni_dvp == vp)
36443342Smckusick 			vrele(ndp->ni_dvp);
36543342Smckusick 		else
36643342Smckusick 			vput(ndp->ni_dvp);
36742465Smckusick 		vrele(vp);
36810139Ssam 		return (EADDRINUSE);
3698925Sroot 	}
37041362Smckusick 	VATTR_NULL(&vattr);
37137616Smckusick 	vattr.va_type = VSOCK;
37237616Smckusick 	vattr.va_mode = 0777;
37337728Smckusick 	if (error = VOP_CREATE(ndp, &vattr))
37411828Ssam 		return (error);
37537616Smckusick 	vp = ndp->ni_vp;
37637616Smckusick 	vp->v_socket = unp->unp_socket;
37737616Smckusick 	unp->unp_vnode = vp;
37825632Skarels 	unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL);
37937728Smckusick 	VOP_UNLOCK(vp);
3808925Sroot 	return (0);
3818925Sroot }
3828925Sroot 
3839169Ssam unp_connect(so, nam)
3848925Sroot 	struct socket *so;
3859169Ssam 	struct mbuf *nam;
3868925Sroot {
3879169Ssam 	register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
38837616Smckusick 	register struct vnode *vp;
38937617Smckusick 	register struct socket *so2, *so3;
39037617Smckusick 	register struct nameidata *ndp = &u.u_nd;
39137617Smckusick 	struct unpcb *unp2, *unp3;
39237616Smckusick 	int error;
3938925Sroot 
39416695Smckusick 	ndp->ni_dirp = soun->sun_path;
39537617Smckusick 	if (nam->m_data + nam->m_len == &nam->m_dat[MLEN]) {	/* XXX */
39637617Smckusick 		if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)
39737617Smckusick 			return (EMSGSIZE);
39837617Smckusick 	} else
39937617Smckusick 		*(mtod(nam, caddr_t) + nam->m_len) = 0;
40037728Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
40116695Smckusick 	ndp->ni_segflg = UIO_SYSSPACE;
40237616Smckusick 	if (error = namei(ndp))
40337616Smckusick 		return (error);
40437616Smckusick 	vp = ndp->ni_vp;
40537616Smckusick 	if (vp->v_type != VSOCK) {
4068925Sroot 		error = ENOTSOCK;
4078925Sroot 		goto bad;
4088925Sroot 	}
40938396Smckusick 	if (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))
41038396Smckusick 		goto bad;
41137616Smckusick 	so2 = vp->v_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 	}
42037617Smckusick 	if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
42137617Smckusick 		if ((so2->so_options & SO_ACCEPTCONN) == 0 ||
42240800Ssklower 		    (so3 = sonewconn(so2, 0)) == 0) {
42337617Smckusick 			error = ECONNREFUSED;
42437617Smckusick 			goto bad;
42537617Smckusick 		}
42637617Smckusick 		unp2 = sotounpcb(so2);
42737617Smckusick 		unp3 = sotounpcb(so3);
42837617Smckusick 		if (unp2->unp_addr)
42937617Smckusick 			unp3->unp_addr =
43037617Smckusick 				  m_copy(unp2->unp_addr, 0, (int)M_COPYALL);
43137617Smckusick 		so2 = so3;
43213115Ssam 	}
43326281Skarels 	error = unp_connect2(so, so2);
43412760Ssam bad:
43537728Smckusick 	vput(vp);
43612760Ssam 	return (error);
43712760Ssam }
43812760Ssam 
43926281Skarels unp_connect2(so, so2)
44012760Ssam 	register struct socket *so;
44112760Ssam 	register struct socket *so2;
44212760Ssam {
44312760Ssam 	register struct unpcb *unp = sotounpcb(so);
44412760Ssam 	register struct unpcb *unp2;
44512760Ssam 
44612760Ssam 	if (so2->so_type != so->so_type)
44712760Ssam 		return (EPROTOTYPE);
44814049Ssam 	unp2 = sotounpcb(so2);
44914049Ssam 	unp->unp_conn = unp2;
4508925Sroot 	switch (so->so_type) {
4518925Sroot 
4528925Sroot 	case SOCK_DGRAM:
4538925Sroot 		unp->unp_nextref = unp2->unp_refs;
4548925Sroot 		unp2->unp_refs = unp;
45517543Skarels 		soisconnected(so);
4568925Sroot 		break;
4578925Sroot 
4588925Sroot 	case SOCK_STREAM:
4599169Ssam 		unp2->unp_conn = unp;
46040800Ssklower 		soisconnected(so);
46114049Ssam 		soisconnected(so2);
4628925Sroot 		break;
4638925Sroot 
4648925Sroot 	default:
46512760Ssam 		panic("unp_connect2");
4668925Sroot 	}
4678925Sroot 	return (0);
4688925Sroot }
4699169Ssam 
4709169Ssam unp_disconnect(unp)
4719169Ssam 	struct unpcb *unp;
4729169Ssam {
4739169Ssam 	register struct unpcb *unp2 = unp->unp_conn;
4749169Ssam 
4759169Ssam 	if (unp2 == 0)
4769169Ssam 		return;
4779169Ssam 	unp->unp_conn = 0;
4789169Ssam 	switch (unp->unp_socket->so_type) {
4799169Ssam 
4809169Ssam 	case SOCK_DGRAM:
4819169Ssam 		if (unp2->unp_refs == unp)
4829169Ssam 			unp2->unp_refs = unp->unp_nextref;
4839169Ssam 		else {
4849169Ssam 			unp2 = unp2->unp_refs;
4859169Ssam 			for (;;) {
4869169Ssam 				if (unp2 == 0)
4879169Ssam 					panic("unp_disconnect");
4889169Ssam 				if (unp2->unp_nextref == unp)
4899169Ssam 					break;
4909169Ssam 				unp2 = unp2->unp_nextref;
4919169Ssam 			}
4929169Ssam 			unp2->unp_nextref = unp->unp_nextref;
4939169Ssam 		}
4949169Ssam 		unp->unp_nextref = 0;
49521768Skarels 		unp->unp_socket->so_state &= ~SS_ISCONNECTED;
4969169Ssam 		break;
4979169Ssam 
4989169Ssam 	case SOCK_STREAM:
49914049Ssam 		soisdisconnected(unp->unp_socket);
5009169Ssam 		unp2->unp_conn = 0;
5019169Ssam 		soisdisconnected(unp2->unp_socket);
5029169Ssam 		break;
5039169Ssam 	}
5049169Ssam }
5059169Ssam 
50612760Ssam #ifdef notdef
5079169Ssam unp_abort(unp)
5089169Ssam 	struct unpcb *unp;
5099169Ssam {
5109169Ssam 
5119169Ssam 	unp_detach(unp);
5129169Ssam }
51312760Ssam #endif
5149169Ssam 
515*45004Skarels unp_shutdown(unp)
5169169Ssam 	struct unpcb *unp;
5179169Ssam {
518*45004Skarels 	struct socket *so;
5199169Ssam 
520*45004Skarels 	if (unp->unp_socket->so_type == SOCK_STREAM && unp->unp_conn &&
521*45004Skarels 	    (so = unp->unp_conn->unp_socket))
522*45004Skarels 		socantrcvmore(so);
5239169Ssam }
5249169Ssam 
5259169Ssam unp_drop(unp, errno)
5269169Ssam 	struct unpcb *unp;
5279169Ssam 	int errno;
5289169Ssam {
52916054Skarels 	struct socket *so = unp->unp_socket;
5309169Ssam 
53116054Skarels 	so->so_error = errno;
5329169Ssam 	unp_disconnect(unp);
53316054Skarels 	if (so->so_head) {
53416054Skarels 		so->so_pcb = (caddr_t) 0;
53525632Skarels 		m_freem(unp->unp_addr);
53616054Skarels 		(void) m_free(dtom(unp));
53716054Skarels 		sofree(so);
53816054Skarels 	}
5399169Ssam }
5409169Ssam 
54112760Ssam #ifdef notdef
5429169Ssam unp_drain()
5439169Ssam {
5449169Ssam 
5459169Ssam }
54612760Ssam #endif
54712760Ssam 
54812760Ssam unp_externalize(rights)
54912760Ssam 	struct mbuf *rights;
55012760Ssam {
55112760Ssam 	register int i;
55240800Ssklower 	register struct cmsghdr *cm = mtod(rights, struct cmsghdr *);
55340800Ssklower 	register struct file **rp = (struct file **)(cm + 1);
55412760Ssam 	register struct file *fp;
55540800Ssklower 	int newfds = (cm->cmsg_len - sizeof(*cm)) / sizeof (int);
55612760Ssam 	int f;
55712760Ssam 
55812760Ssam 	if (newfds > ufavail()) {
55912760Ssam 		for (i = 0; i < newfds; i++) {
56012760Ssam 			fp = *rp;
56112760Ssam 			unp_discard(fp);
56212760Ssam 			*rp++ = 0;
56312760Ssam 		}
56412760Ssam 		return (EMSGSIZE);
56512760Ssam 	}
56612760Ssam 	for (i = 0; i < newfds; i++) {
56737616Smckusick 		if (ufalloc(0, &f))
56812760Ssam 			panic("unp_externalize");
56912760Ssam 		fp = *rp;
57012760Ssam 		u.u_ofile[f] = fp;
57112760Ssam 		fp->f_msgcount--;
57225632Skarels 		unp_rights--;
57314927Smckusick 		*(int *)rp++ = f;
57412760Ssam 	}
57512760Ssam 	return (0);
57612760Ssam }
57712760Ssam 
57840937Skarels unp_internalize(control)
57940937Skarels 	struct mbuf *control;
58012760Ssam {
58140937Skarels 	register struct cmsghdr *cm = mtod(control, struct cmsghdr *);
58212760Ssam 	register struct file **rp;
58340937Skarels 	register struct file *fp;
58437728Smckusick 	register int i, fd;
58540937Skarels 	int oldfds;
58612760Ssam 
58740937Skarels 	if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||
58840937Skarels 	    cm->cmsg_len != control->m_len)
58940800Ssklower 		return (EINVAL);
59040800Ssklower 	oldfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int);
59140800Ssklower 	rp = (struct file **)(cm + 1);
59237728Smckusick 	for (i = 0; i < oldfds; i++) {
59337728Smckusick 		fd = *(int *)rp++;
59437728Smckusick 		if ((unsigned)fd >= NOFILE || u.u_ofile[fd] == NULL)
59512760Ssam 			return (EBADF);
59637728Smckusick 	}
59740800Ssklower 	rp = (struct file **)(cm + 1);
59813084Ssam 	for (i = 0; i < oldfds; i++) {
59937728Smckusick 		fp = u.u_ofile[*(int *)rp];
60012760Ssam 		*rp++ = fp;
60112760Ssam 		fp->f_count++;
60212760Ssam 		fp->f_msgcount++;
60325632Skarels 		unp_rights++;
60412760Ssam 	}
60512760Ssam 	return (0);
60612760Ssam }
60712760Ssam 
60812760Ssam int	unp_defer, unp_gcing;
60912760Ssam int	unp_mark();
61016995Skarels extern	struct domain unixdomain;
61112760Ssam 
61212760Ssam unp_gc()
61312760Ssam {
61412760Ssam 	register struct file *fp;
61512760Ssam 	register struct socket *so;
61612760Ssam 
61712760Ssam 	if (unp_gcing)
61812760Ssam 		return;
61912760Ssam 	unp_gcing = 1;
62012760Ssam restart:
62112760Ssam 	unp_defer = 0;
62212760Ssam 	for (fp = file; fp < fileNFILE; fp++)
62312760Ssam 		fp->f_flag &= ~(FMARK|FDEFER);
62412760Ssam 	do {
62512760Ssam 		for (fp = file; fp < fileNFILE; fp++) {
62612760Ssam 			if (fp->f_count == 0)
62712760Ssam 				continue;
62812760Ssam 			if (fp->f_flag & FDEFER) {
62912760Ssam 				fp->f_flag &= ~FDEFER;
63012760Ssam 				unp_defer--;
63112760Ssam 			} else {
63212760Ssam 				if (fp->f_flag & FMARK)
63312760Ssam 					continue;
63412760Ssam 				if (fp->f_count == fp->f_msgcount)
63512760Ssam 					continue;
63612760Ssam 				fp->f_flag |= FMARK;
63712760Ssam 			}
63837617Smckusick 			if (fp->f_type != DTYPE_SOCKET ||
63937617Smckusick 			    (so = (struct socket *)fp->f_data) == 0)
64012760Ssam 				continue;
64116995Skarels 			if (so->so_proto->pr_domain != &unixdomain ||
64221768Skarels 			    (so->so_proto->pr_flags&PR_RIGHTS) == 0)
64312760Ssam 				continue;
644*45004Skarels #ifdef notdef
64512760Ssam 			if (so->so_rcv.sb_flags & SB_LOCK) {
646*45004Skarels 				/*
647*45004Skarels 				 * This is problematical; it's not clear
648*45004Skarels 				 * we need to wait for the sockbuf to be
649*45004Skarels 				 * unlocked (on a uniprocessor, at least),
650*45004Skarels 				 * and it's also not clear what to do
651*45004Skarels 				 * if sbwait returns an error due to receipt
652*45004Skarels 				 * of a signal.  If sbwait does return
653*45004Skarels 				 * an error, we'll go into an infinite
654*45004Skarels 				 * loop.  Delete all of this for now.
655*45004Skarels 				 */
656*45004Skarels 				(void) sbwait(&so->so_rcv);
65712760Ssam 				goto restart;
65812760Ssam 			}
659*45004Skarels #endif
66012760Ssam 			unp_scan(so->so_rcv.sb_mb, unp_mark);
66112760Ssam 		}
66212760Ssam 	} while (unp_defer);
66312760Ssam 	for (fp = file; fp < fileNFILE; fp++) {
66412760Ssam 		if (fp->f_count == 0)
66512760Ssam 			continue;
66625632Skarels 		if (fp->f_count == fp->f_msgcount && (fp->f_flag & FMARK) == 0)
66725632Skarels 			while (fp->f_msgcount)
66825632Skarels 				unp_discard(fp);
66912760Ssam 	}
67012760Ssam 	unp_gcing = 0;
67112760Ssam }
67212760Ssam 
67316995Skarels unp_dispose(m)
67416995Skarels 	struct mbuf *m;
67516995Skarels {
67616995Skarels 	int unp_discard();
67716995Skarels 
67817020Skarels 	if (m)
67917020Skarels 		unp_scan(m, unp_discard);
68016995Skarels }
68116995Skarels 
68216995Skarels unp_scan(m0, op)
68316995Skarels 	register struct mbuf *m0;
68412760Ssam 	int (*op)();
68512760Ssam {
68616995Skarels 	register struct mbuf *m;
68712760Ssam 	register struct file **rp;
68840937Skarels 	register struct cmsghdr *cm;
68912760Ssam 	register int i;
69017020Skarels 	int qfds;
69112760Ssam 
69216995Skarels 	while (m0) {
69316995Skarels 		for (m = m0; m; m = m->m_next)
69440937Skarels 			if (m->m_type == MT_CONTROL &&
69540937Skarels 			    m->m_len >= sizeof(*cm)) {
69640800Ssklower 				cm = mtod(m, struct cmsghdr *);
69740937Skarels 				if (cm->cmsg_level != SOL_SOCKET ||
69840937Skarels 				    cm->cmsg_type != SCM_RIGHTS)
69940937Skarels 					continue;
70040800Ssklower 				qfds = (cm->cmsg_len - sizeof *cm)
70140800Ssklower 						/ sizeof (struct file *);
70240800Ssklower 				rp = (struct file **)(cm + 1);
70316995Skarels 				for (i = 0; i < qfds; i++)
70416995Skarels 					(*op)(*rp++);
70516995Skarels 				break;		/* XXX, but saves time */
70616995Skarels 			}
70717020Skarels 		m0 = m0->m_act;
70812760Ssam 	}
70912760Ssam }
71012760Ssam 
71112760Ssam unp_mark(fp)
71212760Ssam 	struct file *fp;
71312760Ssam {
71412760Ssam 
71512760Ssam 	if (fp->f_flag & FMARK)
71612760Ssam 		return;
71712760Ssam 	unp_defer++;
71812760Ssam 	fp->f_flag |= (FMARK|FDEFER);
71912760Ssam }
72012760Ssam 
72112760Ssam unp_discard(fp)
72212760Ssam 	struct file *fp;
72312760Ssam {
72412760Ssam 
72512760Ssam 	fp->f_msgcount--;
72625632Skarels 	unp_rights--;
72739353Smckusick 	(void) closef(fp);
72812760Ssam }
729