xref: /csrg-svn/sys/kern/uipc_usrreq.c (revision 45914)
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*45914Smckusick  *	@(#)uipc_usrreq.c	7.22 (Berkeley) 01/10/91
823443Smckusick  */
98925Sroot 
1017105Sbloom #include "param.h"
1117105Sbloom #include "user.h"
12*45914Smckusick #include "proc.h"
13*45914Smckusick #include "filedesc.h"
1417105Sbloom #include "domain.h"
1517105Sbloom #include "protosw.h"
1617105Sbloom #include "socket.h"
1717105Sbloom #include "socketvar.h"
1817105Sbloom #include "unpcb.h"
1917105Sbloom #include "un.h"
2037616Smckusick #include "vnode.h"
2117105Sbloom #include "file.h"
2217105Sbloom #include "stat.h"
2341381Smckusick #include "mbuf.h"
248925Sroot 
258925Sroot /*
268925Sroot  * Unix communications domain.
2712760Ssam  *
2812760Ssam  * TODO:
2912760Ssam  *	SEQPACKET, RDM
3013119Ssam  *	rethink name space problems
3112760Ssam  *	need a proper out-of-band
328925Sroot  */
3337617Smckusick struct	sockaddr sun_noname = { sizeof(sun_noname), AF_UNIX };
3440800Ssklower ino_t	unp_ino;			/* prototype for fake inode numbers */
358925Sroot 
368925Sroot /*ARGSUSED*/
3740800Ssklower uipc_usrreq(so, req, m, nam, control)
388925Sroot 	struct socket *so;
398925Sroot 	int req;
4040800Ssklower 	struct mbuf *m, *nam, *control;
418925Sroot {
428925Sroot 	struct unpcb *unp = sotounpcb(so);
438925Sroot 	register struct socket *so2;
4440937Skarels 	register int error = 0;
458925Sroot 
4625555Skarels 	if (req == PRU_CONTROL)
4725555Skarels 		return (EOPNOTSUPP);
4840800Ssklower 	if (req != PRU_SEND && control && control->m_len) {
4912760Ssam 		error = EOPNOTSUPP;
5012760Ssam 		goto release;
5112760Ssam 	}
5212760Ssam 	if (unp == 0 && req != PRU_ATTACH) {
5312760Ssam 		error = EINVAL;
5412760Ssam 		goto release;
5512760Ssam 	}
568925Sroot 	switch (req) {
578925Sroot 
588925Sroot 	case PRU_ATTACH:
598925Sroot 		if (unp) {
609169Ssam 			error = EISCONN;
618925Sroot 			break;
628925Sroot 		}
639028Sroot 		error = unp_attach(so);
648925Sroot 		break;
658925Sroot 
668925Sroot 	case PRU_DETACH:
678925Sroot 		unp_detach(unp);
688925Sroot 		break;
698925Sroot 
709169Ssam 	case PRU_BIND:
719169Ssam 		error = unp_bind(unp, nam);
729169Ssam 		break;
739169Ssam 
749169Ssam 	case PRU_LISTEN:
7537616Smckusick 		if (unp->unp_vnode == 0)
769169Ssam 			error = EINVAL;
779169Ssam 		break;
789169Ssam 
798925Sroot 	case PRU_CONNECT:
809028Sroot 		error = unp_connect(so, nam);
818925Sroot 		break;
828925Sroot 
8312760Ssam 	case PRU_CONNECT2:
8426281Skarels 		error = unp_connect2(so, (struct socket *)nam);
8512760Ssam 		break;
8612760Ssam 
878925Sroot 	case PRU_DISCONNECT:
888925Sroot 		unp_disconnect(unp);
898925Sroot 		break;
908925Sroot 
919169Ssam 	case PRU_ACCEPT:
9225899Skarels 		/*
9325899Skarels 		 * Pass back name of connected socket,
9425899Skarels 		 * if it was bound and we are still connected
9525899Skarels 		 * (our peer may have closed already!).
9625899Skarels 		 */
9725899Skarels 		if (unp->unp_conn && unp->unp_conn->unp_addr) {
9825632Skarels 			nam->m_len = unp->unp_conn->unp_addr->m_len;
9925632Skarels 			bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
10025632Skarels 			    mtod(nam, caddr_t), (unsigned)nam->m_len);
10125632Skarels 		} else {
10225632Skarels 			nam->m_len = sizeof(sun_noname);
10325632Skarels 			*(mtod(nam, struct sockaddr *)) = sun_noname;
10425632Skarels 		}
1058925Sroot 		break;
1068925Sroot 
1078925Sroot 	case PRU_SHUTDOWN:
1088925Sroot 		socantsendmore(so);
10945004Skarels 		unp_shutdown(unp);
1108925Sroot 		break;
1118925Sroot 
1128925Sroot 	case PRU_RCVD:
1138925Sroot 		switch (so->so_type) {
1148925Sroot 
1158925Sroot 		case SOCK_DGRAM:
1168925Sroot 			panic("uipc 1");
11710139Ssam 			/*NOTREACHED*/
1188925Sroot 
11910139Ssam 		case SOCK_STREAM:
1208925Sroot #define	rcv (&so->so_rcv)
1218925Sroot #define snd (&so2->so_snd)
1228925Sroot 			if (unp->unp_conn == 0)
1238925Sroot 				break;
1248925Sroot 			so2 = unp->unp_conn->unp_socket;
1258925Sroot 			/*
12625632Skarels 			 * Adjust backpressure on sender
1278925Sroot 			 * and wakeup any waiting to write.
1288925Sroot 			 */
12925632Skarels 			snd->sb_mbmax += unp->unp_mbcnt - rcv->sb_mbcnt;
13025632Skarels 			unp->unp_mbcnt = rcv->sb_mbcnt;
13125632Skarels 			snd->sb_hiwat += unp->unp_cc - rcv->sb_cc;
13225632Skarels 			unp->unp_cc = rcv->sb_cc;
13317543Skarels 			sowwakeup(so2);
1348925Sroot #undef snd
1358925Sroot #undef rcv
1368925Sroot 			break;
1378925Sroot 
1388925Sroot 		default:
1398925Sroot 			panic("uipc 2");
1408925Sroot 		}
1418925Sroot 		break;
1428925Sroot 
1438925Sroot 	case PRU_SEND:
14440937Skarels 		if (control && (error = unp_internalize(control)))
14540937Skarels 			break;
1468925Sroot 		switch (so->so_type) {
1478925Sroot 
14825632Skarels 		case SOCK_DGRAM: {
14925632Skarels 			struct sockaddr *from;
15025632Skarels 
1519028Sroot 			if (nam) {
1528925Sroot 				if (unp->unp_conn) {
1538925Sroot 					error = EISCONN;
1548925Sroot 					break;
1558925Sroot 				}
1569028Sroot 				error = unp_connect(so, nam);
1578925Sroot 				if (error)
1588925Sroot 					break;
1598925Sroot 			} else {
1608925Sroot 				if (unp->unp_conn == 0) {
1618925Sroot 					error = ENOTCONN;
1628925Sroot 					break;
1638925Sroot 				}
1648925Sroot 			}
1658925Sroot 			so2 = unp->unp_conn->unp_socket;
16625632Skarels 			if (unp->unp_addr)
16725632Skarels 				from = mtod(unp->unp_addr, struct sockaddr *);
16825632Skarels 			else
16925632Skarels 				from = &sun_noname;
17040937Skarels 			if (sbappendaddr(&so2->so_rcv, from, m, control)) {
17125632Skarels 				sorwakeup(so2);
17225632Skarels 				m = 0;
17340937Skarels 				control = 0;
17425632Skarels 			} else
17525632Skarels 				error = ENOBUFS;
1769028Sroot 			if (nam)
1779169Ssam 				unp_disconnect(unp);
1788925Sroot 			break;
17925632Skarels 		}
1808925Sroot 
1818925Sroot 		case SOCK_STREAM:
1828925Sroot #define	rcv (&so2->so_rcv)
1838925Sroot #define	snd (&so->so_snd)
18423524Skarels 			if (so->so_state & SS_CANTSENDMORE) {
18523524Skarels 				error = EPIPE;
18623524Skarels 				break;
18723524Skarels 			}
1888925Sroot 			if (unp->unp_conn == 0)
1898925Sroot 				panic("uipc 3");
1908925Sroot 			so2 = unp->unp_conn->unp_socket;
1918925Sroot 			/*
19225632Skarels 			 * Send to paired receive port, and then reduce
19325632Skarels 			 * send buffer hiwater marks to maintain backpressure.
1948925Sroot 			 * Wake up readers.
1958925Sroot 			 */
19640937Skarels 			if (control) {
19745004Skarels 				if (sbappendcontrol(rcv, m, control))
19845004Skarels 					control = 0;
19940937Skarels 			} else
20025632Skarels 				sbappend(rcv, m);
20125632Skarels 			snd->sb_mbmax -=
20225632Skarels 			    rcv->sb_mbcnt - unp->unp_conn->unp_mbcnt;
20325632Skarels 			unp->unp_conn->unp_mbcnt = rcv->sb_mbcnt;
20425632Skarels 			snd->sb_hiwat -= rcv->sb_cc - unp->unp_conn->unp_cc;
20525632Skarels 			unp->unp_conn->unp_cc = rcv->sb_cc;
20617543Skarels 			sorwakeup(so2);
20717543Skarels 			m = 0;
2088925Sroot #undef snd
2098925Sroot #undef rcv
2108925Sroot 			break;
2118925Sroot 
2128925Sroot 		default:
2138925Sroot 			panic("uipc 4");
2148925Sroot 		}
2158925Sroot 		break;
2168925Sroot 
2178925Sroot 	case PRU_ABORT:
2188925Sroot 		unp_drop(unp, ECONNABORTED);
2198925Sroot 		break;
2208925Sroot 
2218925Sroot 	case PRU_SENSE:
22216973Skarels 		((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
22316973Skarels 		if (so->so_type == SOCK_STREAM && unp->unp_conn != 0) {
22416973Skarels 			so2 = unp->unp_conn->unp_socket;
22516973Skarels 			((struct stat *) m)->st_blksize += so2->so_rcv.sb_cc;
22616973Skarels 		}
22721110Skarels 		((struct stat *) m)->st_dev = NODEV;
22840800Ssklower 		if (unp->unp_ino == 0)
22940800Ssklower 			unp->unp_ino = unp_ino++;
23040800Ssklower 		((struct stat *) m)->st_ino = unp->unp_ino;
23116973Skarels 		return (0);
2328925Sroot 
2338925Sroot 	case PRU_RCVOOB:
23416774Sbloom 		return (EOPNOTSUPP);
2358925Sroot 
2368925Sroot 	case PRU_SENDOOB:
23717543Skarels 		error = EOPNOTSUPP;
2388925Sroot 		break;
2398925Sroot 
2408925Sroot 	case PRU_SOCKADDR:
24137617Smckusick 		if (unp->unp_addr) {
24237617Smckusick 			nam->m_len = unp->unp_addr->m_len;
24337617Smckusick 			bcopy(mtod(unp->unp_addr, caddr_t),
24437617Smckusick 			    mtod(nam, caddr_t), (unsigned)nam->m_len);
24537617Smckusick 		} else
24637617Smckusick 			nam->m_len = 0;
2478925Sroot 		break;
2488925Sroot 
24914121Ssam 	case PRU_PEERADDR:
25028292Skarels 		if (unp->unp_conn && unp->unp_conn->unp_addr) {
25128292Skarels 			nam->m_len = unp->unp_conn->unp_addr->m_len;
25228292Skarels 			bcopy(mtod(unp->unp_conn->unp_addr, caddr_t),
25333287Sbostic 			    mtod(nam, caddr_t), (unsigned)nam->m_len);
25437617Smckusick 		} else
25537617Smckusick 			nam->m_len = 0;
25614121Ssam 		break;
25714121Ssam 
2588925Sroot 	case PRU_SLOWTIMO:
2598925Sroot 		break;
2608925Sroot 
2618925Sroot 	default:
2628925Sroot 		panic("piusrreq");
2638925Sroot 	}
26412760Ssam release:
26540937Skarels 	if (control)
26640937Skarels 		m_freem(control);
26712760Ssam 	if (m)
26812760Ssam 		m_freem(m);
26911709Ssam 	return (error);
2708925Sroot }
2718925Sroot 
27216973Skarels /*
27325632Skarels  * Both send and receive buffers are allocated PIPSIZ bytes of buffering
27425632Skarels  * for stream sockets, although the total for sender and receiver is
27525632Skarels  * actually only PIPSIZ.
27616973Skarels  * Datagram sockets really use the sendspace as the maximum datagram size,
27716973Skarels  * and don't really want to reserve the sendspace.  Their recvspace should
27816973Skarels  * be large enough for at least one max-size datagram plus address.
27916973Skarels  */
28016973Skarels #define	PIPSIZ	4096
28137617Smckusick u_long	unpst_sendspace = PIPSIZ;
28237617Smckusick u_long	unpst_recvspace = PIPSIZ;
28337617Smckusick u_long	unpdg_sendspace = 2*1024;	/* really max datagram size */
28437617Smckusick u_long	unpdg_recvspace = 4*1024;
2858925Sroot 
28625632Skarels int	unp_rights;			/* file descriptors in flight */
28725632Skarels 
2889169Ssam unp_attach(so)
2898925Sroot 	struct socket *so;
2908925Sroot {
2919169Ssam 	register struct mbuf *m;
2928925Sroot 	register struct unpcb *unp;
2938925Sroot 	int error;
2948925Sroot 
29537617Smckusick 	if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
29637617Smckusick 		switch (so->so_type) {
29716973Skarels 
29837617Smckusick 		case SOCK_STREAM:
29937617Smckusick 			error = soreserve(so, unpst_sendspace, unpst_recvspace);
30037617Smckusick 			break;
30116973Skarels 
30237617Smckusick 		case SOCK_DGRAM:
30337617Smckusick 			error = soreserve(so, unpdg_sendspace, unpdg_recvspace);
30437617Smckusick 			break;
30537617Smckusick 		}
30637617Smckusick 		if (error)
30737617Smckusick 			return (error);
30816973Skarels 	}
3099637Ssam 	m = m_getclr(M_DONTWAIT, MT_PCB);
31010139Ssam 	if (m == NULL)
31110139Ssam 		return (ENOBUFS);
3128925Sroot 	unp = mtod(m, struct unpcb *);
3138925Sroot 	so->so_pcb = (caddr_t)unp;
3148925Sroot 	unp->unp_socket = so;
3158925Sroot 	return (0);
3168925Sroot }
3178925Sroot 
3188925Sroot unp_detach(unp)
3199169Ssam 	register struct unpcb *unp;
3208925Sroot {
3218925Sroot 
32237616Smckusick 	if (unp->unp_vnode) {
32337616Smckusick 		unp->unp_vnode->v_socket = 0;
32437616Smckusick 		vrele(unp->unp_vnode);
32537616Smckusick 		unp->unp_vnode = 0;
3268925Sroot 	}
3278925Sroot 	if (unp->unp_conn)
3288925Sroot 		unp_disconnect(unp);
3298925Sroot 	while (unp->unp_refs)
3308925Sroot 		unp_drop(unp->unp_refs, ECONNRESET);
3318925Sroot 	soisdisconnected(unp->unp_socket);
3328925Sroot 	unp->unp_socket->so_pcb = 0;
33325632Skarels 	m_freem(unp->unp_addr);
3349169Ssam 	(void) m_free(dtom(unp));
33525632Skarels 	if (unp_rights)
33625632Skarels 		unp_gc();
3378925Sroot }
3388925Sroot 
3399169Ssam unp_bind(unp, nam)
3408925Sroot 	struct unpcb *unp;
3419169Ssam 	struct mbuf *nam;
3428925Sroot {
3439169Ssam 	struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
34437616Smckusick 	register struct vnode *vp;
34516695Smckusick 	register struct nameidata *ndp = &u.u_nd;
34637616Smckusick 	struct vattr vattr;
3478925Sroot 	int error;
3488925Sroot 
34916695Smckusick 	ndp->ni_dirp = soun->sun_path;
35037617Smckusick 	if (unp->unp_vnode != NULL)
35112760Ssam 		return (EINVAL);
35237617Smckusick 	if (nam->m_len == MLEN) {
35337617Smckusick 		if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)
35437617Smckusick 			return (EINVAL);
35537617Smckusick 	} else
35637617Smckusick 		*(mtod(nam, caddr_t) + nam->m_len) = 0;
35712760Ssam /* SHOULD BE ABLE TO ADOPT EXISTING AND wakeup() ALA FIFO's */
35837616Smckusick 	ndp->ni_nameiop = CREATE | FOLLOW | LOCKPARENT;
35916695Smckusick 	ndp->ni_segflg = UIO_SYSSPACE;
36037616Smckusick 	if (error = namei(ndp))
36137616Smckusick 		return (error);
36237616Smckusick 	vp = ndp->ni_vp;
36337616Smckusick 	if (vp != NULL) {
36437728Smckusick 		VOP_ABORTOP(ndp);
36543342Smckusick 		if (ndp->ni_dvp == vp)
36643342Smckusick 			vrele(ndp->ni_dvp);
36743342Smckusick 		else
36843342Smckusick 			vput(ndp->ni_dvp);
36942465Smckusick 		vrele(vp);
37010139Ssam 		return (EADDRINUSE);
3718925Sroot 	}
37241362Smckusick 	VATTR_NULL(&vattr);
37337616Smckusick 	vattr.va_type = VSOCK;
37437616Smckusick 	vattr.va_mode = 0777;
37537728Smckusick 	if (error = VOP_CREATE(ndp, &vattr))
37611828Ssam 		return (error);
37737616Smckusick 	vp = ndp->ni_vp;
37837616Smckusick 	vp->v_socket = unp->unp_socket;
37937616Smckusick 	unp->unp_vnode = vp;
38025632Skarels 	unp->unp_addr = m_copy(nam, 0, (int)M_COPYALL);
38137728Smckusick 	VOP_UNLOCK(vp);
3828925Sroot 	return (0);
3838925Sroot }
3848925Sroot 
3859169Ssam unp_connect(so, nam)
3868925Sroot 	struct socket *so;
3879169Ssam 	struct mbuf *nam;
3888925Sroot {
3899169Ssam 	register struct sockaddr_un *soun = mtod(nam, struct sockaddr_un *);
39037616Smckusick 	register struct vnode *vp;
39137617Smckusick 	register struct socket *so2, *so3;
39237617Smckusick 	register struct nameidata *ndp = &u.u_nd;
39337617Smckusick 	struct unpcb *unp2, *unp3;
39437616Smckusick 	int error;
3958925Sroot 
39616695Smckusick 	ndp->ni_dirp = soun->sun_path;
39737617Smckusick 	if (nam->m_data + nam->m_len == &nam->m_dat[MLEN]) {	/* XXX */
39837617Smckusick 		if (*(mtod(nam, caddr_t) + nam->m_len - 1) != 0)
39937617Smckusick 			return (EMSGSIZE);
40037617Smckusick 	} else
40137617Smckusick 		*(mtod(nam, caddr_t) + nam->m_len) = 0;
40237728Smckusick 	ndp->ni_nameiop = LOOKUP | FOLLOW | LOCKLEAF;
40316695Smckusick 	ndp->ni_segflg = UIO_SYSSPACE;
40437616Smckusick 	if (error = namei(ndp))
40537616Smckusick 		return (error);
40637616Smckusick 	vp = ndp->ni_vp;
40737616Smckusick 	if (vp->v_type != VSOCK) {
4088925Sroot 		error = ENOTSOCK;
4098925Sroot 		goto bad;
4108925Sroot 	}
41138396Smckusick 	if (error = VOP_ACCESS(vp, VWRITE, ndp->ni_cred))
41238396Smckusick 		goto bad;
41337616Smckusick 	so2 = vp->v_socket;
4148925Sroot 	if (so2 == 0) {
4158925Sroot 		error = ECONNREFUSED;
4168925Sroot 		goto bad;
4178925Sroot 	}
41813115Ssam 	if (so->so_type != so2->so_type) {
41913115Ssam 		error = EPROTOTYPE;
42013115Ssam 		goto bad;
42113115Ssam 	}
42237617Smckusick 	if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
42337617Smckusick 		if ((so2->so_options & SO_ACCEPTCONN) == 0 ||
42440800Ssklower 		    (so3 = sonewconn(so2, 0)) == 0) {
42537617Smckusick 			error = ECONNREFUSED;
42637617Smckusick 			goto bad;
42737617Smckusick 		}
42837617Smckusick 		unp2 = sotounpcb(so2);
42937617Smckusick 		unp3 = sotounpcb(so3);
43037617Smckusick 		if (unp2->unp_addr)
43137617Smckusick 			unp3->unp_addr =
43237617Smckusick 				  m_copy(unp2->unp_addr, 0, (int)M_COPYALL);
43337617Smckusick 		so2 = so3;
43413115Ssam 	}
43526281Skarels 	error = unp_connect2(so, so2);
43612760Ssam bad:
43737728Smckusick 	vput(vp);
43812760Ssam 	return (error);
43912760Ssam }
44012760Ssam 
44126281Skarels unp_connect2(so, so2)
44212760Ssam 	register struct socket *so;
44312760Ssam 	register struct socket *so2;
44412760Ssam {
44512760Ssam 	register struct unpcb *unp = sotounpcb(so);
44612760Ssam 	register struct unpcb *unp2;
44712760Ssam 
44812760Ssam 	if (so2->so_type != so->so_type)
44912760Ssam 		return (EPROTOTYPE);
45014049Ssam 	unp2 = sotounpcb(so2);
45114049Ssam 	unp->unp_conn = unp2;
4528925Sroot 	switch (so->so_type) {
4538925Sroot 
4548925Sroot 	case SOCK_DGRAM:
4558925Sroot 		unp->unp_nextref = unp2->unp_refs;
4568925Sroot 		unp2->unp_refs = unp;
45717543Skarels 		soisconnected(so);
4588925Sroot 		break;
4598925Sroot 
4608925Sroot 	case SOCK_STREAM:
4619169Ssam 		unp2->unp_conn = unp;
46240800Ssklower 		soisconnected(so);
46314049Ssam 		soisconnected(so2);
4648925Sroot 		break;
4658925Sroot 
4668925Sroot 	default:
46712760Ssam 		panic("unp_connect2");
4688925Sroot 	}
4698925Sroot 	return (0);
4708925Sroot }
4719169Ssam 
4729169Ssam unp_disconnect(unp)
4739169Ssam 	struct unpcb *unp;
4749169Ssam {
4759169Ssam 	register struct unpcb *unp2 = unp->unp_conn;
4769169Ssam 
4779169Ssam 	if (unp2 == 0)
4789169Ssam 		return;
4799169Ssam 	unp->unp_conn = 0;
4809169Ssam 	switch (unp->unp_socket->so_type) {
4819169Ssam 
4829169Ssam 	case SOCK_DGRAM:
4839169Ssam 		if (unp2->unp_refs == unp)
4849169Ssam 			unp2->unp_refs = unp->unp_nextref;
4859169Ssam 		else {
4869169Ssam 			unp2 = unp2->unp_refs;
4879169Ssam 			for (;;) {
4889169Ssam 				if (unp2 == 0)
4899169Ssam 					panic("unp_disconnect");
4909169Ssam 				if (unp2->unp_nextref == unp)
4919169Ssam 					break;
4929169Ssam 				unp2 = unp2->unp_nextref;
4939169Ssam 			}
4949169Ssam 			unp2->unp_nextref = unp->unp_nextref;
4959169Ssam 		}
4969169Ssam 		unp->unp_nextref = 0;
49721768Skarels 		unp->unp_socket->so_state &= ~SS_ISCONNECTED;
4989169Ssam 		break;
4999169Ssam 
5009169Ssam 	case SOCK_STREAM:
50114049Ssam 		soisdisconnected(unp->unp_socket);
5029169Ssam 		unp2->unp_conn = 0;
5039169Ssam 		soisdisconnected(unp2->unp_socket);
5049169Ssam 		break;
5059169Ssam 	}
5069169Ssam }
5079169Ssam 
50812760Ssam #ifdef notdef
5099169Ssam unp_abort(unp)
5109169Ssam 	struct unpcb *unp;
5119169Ssam {
5129169Ssam 
5139169Ssam 	unp_detach(unp);
5149169Ssam }
51512760Ssam #endif
5169169Ssam 
51745004Skarels unp_shutdown(unp)
5189169Ssam 	struct unpcb *unp;
5199169Ssam {
52045004Skarels 	struct socket *so;
5219169Ssam 
52245004Skarels 	if (unp->unp_socket->so_type == SOCK_STREAM && unp->unp_conn &&
52345004Skarels 	    (so = unp->unp_conn->unp_socket))
52445004Skarels 		socantrcvmore(so);
5259169Ssam }
5269169Ssam 
5279169Ssam unp_drop(unp, errno)
5289169Ssam 	struct unpcb *unp;
5299169Ssam 	int errno;
5309169Ssam {
53116054Skarels 	struct socket *so = unp->unp_socket;
5329169Ssam 
53316054Skarels 	so->so_error = errno;
5349169Ssam 	unp_disconnect(unp);
53516054Skarels 	if (so->so_head) {
53616054Skarels 		so->so_pcb = (caddr_t) 0;
53725632Skarels 		m_freem(unp->unp_addr);
53816054Skarels 		(void) m_free(dtom(unp));
53916054Skarels 		sofree(so);
54016054Skarels 	}
5419169Ssam }
5429169Ssam 
54312760Ssam #ifdef notdef
5449169Ssam unp_drain()
5459169Ssam {
5469169Ssam 
5479169Ssam }
54812760Ssam #endif
54912760Ssam 
55012760Ssam unp_externalize(rights)
55112760Ssam 	struct mbuf *rights;
55212760Ssam {
553*45914Smckusick 	struct filedesc *fdp = u.u_procp->p_fd;		/* XXX */
55412760Ssam 	register int i;
55540800Ssklower 	register struct cmsghdr *cm = mtod(rights, struct cmsghdr *);
55640800Ssklower 	register struct file **rp = (struct file **)(cm + 1);
55712760Ssam 	register struct file *fp;
55840800Ssklower 	int newfds = (cm->cmsg_len - sizeof(*cm)) / sizeof (int);
55912760Ssam 	int f;
56012760Ssam 
561*45914Smckusick 	if (newfds > ufavail(fdp)) {
56212760Ssam 		for (i = 0; i < newfds; i++) {
56312760Ssam 			fp = *rp;
56412760Ssam 			unp_discard(fp);
56512760Ssam 			*rp++ = 0;
56612760Ssam 		}
56712760Ssam 		return (EMSGSIZE);
56812760Ssam 	}
56912760Ssam 	for (i = 0; i < newfds; i++) {
570*45914Smckusick 		if (ufalloc(fdp, 0, &f))
57112760Ssam 			panic("unp_externalize");
57212760Ssam 		fp = *rp;
573*45914Smckusick 		OFILE(fdp, f) = fp;
57412760Ssam 		fp->f_msgcount--;
57525632Skarels 		unp_rights--;
57614927Smckusick 		*(int *)rp++ = f;
57712760Ssam 	}
57812760Ssam 	return (0);
57912760Ssam }
58012760Ssam 
58140937Skarels unp_internalize(control)
58240937Skarels 	struct mbuf *control;
58312760Ssam {
584*45914Smckusick 	struct filedesc *fdp = u.u_procp->p_fd;		/* XXX */
58540937Skarels 	register struct cmsghdr *cm = mtod(control, struct cmsghdr *);
58612760Ssam 	register struct file **rp;
58740937Skarels 	register struct file *fp;
58837728Smckusick 	register int i, fd;
58940937Skarels 	int oldfds;
59012760Ssam 
59140937Skarels 	if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET ||
59240937Skarels 	    cm->cmsg_len != control->m_len)
59340800Ssklower 		return (EINVAL);
59440800Ssklower 	oldfds = (cm->cmsg_len - sizeof (*cm)) / sizeof (int);
59540800Ssklower 	rp = (struct file **)(cm + 1);
59637728Smckusick 	for (i = 0; i < oldfds; i++) {
59737728Smckusick 		fd = *(int *)rp++;
598*45914Smckusick 		if ((unsigned)fd >= fdp->fd_maxfiles || OFILE(fdp, fd) == NULL)
59912760Ssam 			return (EBADF);
60037728Smckusick 	}
60140800Ssklower 	rp = (struct file **)(cm + 1);
60213084Ssam 	for (i = 0; i < oldfds; i++) {
603*45914Smckusick 		fp = OFILE(fdp, *(int *)rp);
60412760Ssam 		*rp++ = fp;
60512760Ssam 		fp->f_count++;
60612760Ssam 		fp->f_msgcount++;
60725632Skarels 		unp_rights++;
60812760Ssam 	}
60912760Ssam 	return (0);
61012760Ssam }
61112760Ssam 
61212760Ssam int	unp_defer, unp_gcing;
61312760Ssam int	unp_mark();
61416995Skarels extern	struct domain unixdomain;
61512760Ssam 
61612760Ssam unp_gc()
61712760Ssam {
61812760Ssam 	register struct file *fp;
61912760Ssam 	register struct socket *so;
62012760Ssam 
62112760Ssam 	if (unp_gcing)
62212760Ssam 		return;
62312760Ssam 	unp_gcing = 1;
62412760Ssam restart:
62512760Ssam 	unp_defer = 0;
62612760Ssam 	for (fp = file; fp < fileNFILE; fp++)
62712760Ssam 		fp->f_flag &= ~(FMARK|FDEFER);
62812760Ssam 	do {
62912760Ssam 		for (fp = file; fp < fileNFILE; fp++) {
63012760Ssam 			if (fp->f_count == 0)
63112760Ssam 				continue;
63212760Ssam 			if (fp->f_flag & FDEFER) {
63312760Ssam 				fp->f_flag &= ~FDEFER;
63412760Ssam 				unp_defer--;
63512760Ssam 			} else {
63612760Ssam 				if (fp->f_flag & FMARK)
63712760Ssam 					continue;
63812760Ssam 				if (fp->f_count == fp->f_msgcount)
63912760Ssam 					continue;
64012760Ssam 				fp->f_flag |= FMARK;
64112760Ssam 			}
64237617Smckusick 			if (fp->f_type != DTYPE_SOCKET ||
64337617Smckusick 			    (so = (struct socket *)fp->f_data) == 0)
64412760Ssam 				continue;
64516995Skarels 			if (so->so_proto->pr_domain != &unixdomain ||
64621768Skarels 			    (so->so_proto->pr_flags&PR_RIGHTS) == 0)
64712760Ssam 				continue;
64845004Skarels #ifdef notdef
64912760Ssam 			if (so->so_rcv.sb_flags & SB_LOCK) {
65045004Skarels 				/*
65145004Skarels 				 * This is problematical; it's not clear
65245004Skarels 				 * we need to wait for the sockbuf to be
65345004Skarels 				 * unlocked (on a uniprocessor, at least),
65445004Skarels 				 * and it's also not clear what to do
65545004Skarels 				 * if sbwait returns an error due to receipt
65645004Skarels 				 * of a signal.  If sbwait does return
65745004Skarels 				 * an error, we'll go into an infinite
65845004Skarels 				 * loop.  Delete all of this for now.
65945004Skarels 				 */
66045004Skarels 				(void) sbwait(&so->so_rcv);
66112760Ssam 				goto restart;
66212760Ssam 			}
66345004Skarels #endif
66412760Ssam 			unp_scan(so->so_rcv.sb_mb, unp_mark);
66512760Ssam 		}
66612760Ssam 	} while (unp_defer);
66712760Ssam 	for (fp = file; fp < fileNFILE; fp++) {
66812760Ssam 		if (fp->f_count == 0)
66912760Ssam 			continue;
67025632Skarels 		if (fp->f_count == fp->f_msgcount && (fp->f_flag & FMARK) == 0)
67125632Skarels 			while (fp->f_msgcount)
67225632Skarels 				unp_discard(fp);
67312760Ssam 	}
67412760Ssam 	unp_gcing = 0;
67512760Ssam }
67612760Ssam 
67716995Skarels unp_dispose(m)
67816995Skarels 	struct mbuf *m;
67916995Skarels {
68016995Skarels 	int unp_discard();
68116995Skarels 
68217020Skarels 	if (m)
68317020Skarels 		unp_scan(m, unp_discard);
68416995Skarels }
68516995Skarels 
68616995Skarels unp_scan(m0, op)
68716995Skarels 	register struct mbuf *m0;
68812760Ssam 	int (*op)();
68912760Ssam {
69016995Skarels 	register struct mbuf *m;
69112760Ssam 	register struct file **rp;
69240937Skarels 	register struct cmsghdr *cm;
69312760Ssam 	register int i;
69417020Skarels 	int qfds;
69512760Ssam 
69616995Skarels 	while (m0) {
69716995Skarels 		for (m = m0; m; m = m->m_next)
69840937Skarels 			if (m->m_type == MT_CONTROL &&
69940937Skarels 			    m->m_len >= sizeof(*cm)) {
70040800Ssklower 				cm = mtod(m, struct cmsghdr *);
70140937Skarels 				if (cm->cmsg_level != SOL_SOCKET ||
70240937Skarels 				    cm->cmsg_type != SCM_RIGHTS)
70340937Skarels 					continue;
70440800Ssklower 				qfds = (cm->cmsg_len - sizeof *cm)
70540800Ssklower 						/ sizeof (struct file *);
70640800Ssklower 				rp = (struct file **)(cm + 1);
70716995Skarels 				for (i = 0; i < qfds; i++)
70816995Skarels 					(*op)(*rp++);
70916995Skarels 				break;		/* XXX, but saves time */
71016995Skarels 			}
71117020Skarels 		m0 = m0->m_act;
71212760Ssam 	}
71312760Ssam }
71412760Ssam 
71512760Ssam unp_mark(fp)
71612760Ssam 	struct file *fp;
71712760Ssam {
71812760Ssam 
71912760Ssam 	if (fp->f_flag & FMARK)
72012760Ssam 		return;
72112760Ssam 	unp_defer++;
72212760Ssam 	fp->f_flag |= (FMARK|FDEFER);
72312760Ssam }
72412760Ssam 
72512760Ssam unp_discard(fp)
72612760Ssam 	struct file *fp;
72712760Ssam {
72812760Ssam 
72912760Ssam 	fp->f_msgcount--;
73025632Skarels 	unp_rights--;
73139353Smckusick 	(void) closef(fp);
73212760Ssam }
733