xref: /csrg-svn/sys/kern/uipc_socket.c (revision 16992)
1*16992Skarels /*	uipc_socket.c	6.5	84/08/21	*/
24786Swnj 
34786Swnj #include "../h/param.h"
44829Swnj #include "../h/systm.h"
54786Swnj #include "../h/dir.h"
64786Swnj #include "../h/user.h"
74829Swnj #include "../h/proc.h"
84829Swnj #include "../h/file.h"
94786Swnj #include "../h/inode.h"
104829Swnj #include "../h/buf.h"
114786Swnj #include "../h/mbuf.h"
1212757Ssam #include "../h/un.h"
134829Swnj #include "../h/protosw.h"
144829Swnj #include "../h/socket.h"
154829Swnj #include "../h/socketvar.h"
164916Swnj #include "../h/stat.h"
175281Sroot #include "../h/ioctl.h"
188391Swnj #include "../h/uio.h"
196355Ssam #include "../net/route.h"
2012757Ssam #include "../netinet/in.h"
2111571Ssam #include "../net/if.h"
224786Swnj 
234786Swnj /*
248300Sroot  * Socket operation routines.
258300Sroot  * These routines are called by the routines in
268300Sroot  * sys_socket.c or from a system process, and
278300Sroot  * implement the semantics of socket operations by
288300Sroot  * switching out to the protocol specific routines.
2912757Ssam  *
3012757Ssam  * TODO:
3112757Ssam  *	sostat
3212757Ssam  *	test socketpair
3312757Ssam  *	PR_RIGHTS
3412757Ssam  *	clean up select, async
3512757Ssam  *	out-of-band is a kludge
364786Swnj  */
378594Sroot /*ARGSUSED*/
3810267Ssam socreate(dom, aso, type, proto)
394786Swnj 	struct socket **aso;
4012757Ssam 	register int type;
4112757Ssam 	int proto;
424786Swnj {
434786Swnj 	register struct protosw *prp;
444786Swnj 	register struct socket *so;
4512757Ssam 	register struct mbuf *m;
4612757Ssam 	register int error;
474786Swnj 
484890Swnj 	if (proto)
499168Ssam 		prp = pffindproto(dom, proto);
504890Swnj 	else
519168Ssam 		prp = pffindtype(dom, type);
524890Swnj 	if (prp == 0)
534890Swnj 		return (EPROTONOSUPPORT);
548300Sroot 	if (prp->pr_type != type)
558300Sroot 		return (EPROTOTYPE);
569635Ssam 	m = m_getclr(M_WAIT, MT_SOCKET);
574786Swnj 	if (m == 0)
584786Swnj 		return (ENOBUFS);
594786Swnj 	so = mtod(m, struct socket *);
6012757Ssam 	so->so_options = 0;
616214Swnj 	so->so_state = 0;
629168Ssam 	so->so_type = type;
636214Swnj 	if (u.u_uid == 0)
646214Swnj 		so->so_state = SS_PRIV;
654786Swnj 	so->so_proto = prp;
6612757Ssam 	error =
6712757Ssam 	    (*prp->pr_usrreq)(so, PRU_ATTACH,
6812757Ssam 		(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
694979Swnj 	if (error) {
707507Sroot 		so->so_state |= SS_NOFDREF;
717180Swnj 		sofree(so);
724890Swnj 		return (error);
734786Swnj 	}
744786Swnj 	*aso = so;
754786Swnj 	return (0);
764786Swnj }
774786Swnj 
7810267Ssam sobind(so, nam)
798300Sroot 	struct socket *so;
808300Sroot 	struct mbuf *nam;
818300Sroot {
828300Sroot 	int s = splnet();
838300Sroot 	int error;
848300Sroot 
858300Sroot 	error =
8612757Ssam 	    (*so->so_proto->pr_usrreq)(so, PRU_BIND,
8712757Ssam 		(struct mbuf *)0, nam, (struct mbuf *)0);
888300Sroot 	splx(s);
898300Sroot 	return (error);
908300Sroot }
918300Sroot 
928300Sroot solisten(so, backlog)
9312757Ssam 	register struct socket *so;
948300Sroot 	int backlog;
958300Sroot {
9612757Ssam 	int s = splnet(), error;
978300Sroot 
9812757Ssam 	error =
9912757Ssam 	    (*so->so_proto->pr_usrreq)(so, PRU_LISTEN,
10012757Ssam 		(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
1018300Sroot 	if (error) {
1028300Sroot 		splx(s);
1038300Sroot 		return (error);
1048300Sroot 	}
1058300Sroot 	if (so->so_q == 0) {
1068300Sroot 		so->so_q = so;
1078300Sroot 		so->so_q0 = so;
1088300Sroot 		so->so_options |= SO_ACCEPTCONN;
1098300Sroot 	}
1108300Sroot 	if (backlog < 0)
1118300Sroot 		backlog = 0;
11210137Ssam 	so->so_qlimit = MIN(backlog, SOMAXCONN);
11312493Ssam 	splx(s);
1148300Sroot 	return (0);
1158300Sroot }
1168300Sroot 
1174916Swnj sofree(so)
11812757Ssam 	register struct socket *so;
1194916Swnj {
1204916Swnj 
1217507Sroot 	if (so->so_head) {
1227507Sroot 		if (!soqremque(so, 0) && !soqremque(so, 1))
1237507Sroot 			panic("sofree dq");
1247507Sroot 		so->so_head = 0;
1257507Sroot 	}
1267507Sroot 	if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
1274950Swnj 		return;
1284950Swnj 	sbrelease(&so->so_snd);
12912757Ssam 	sorflush(so);
1304971Swnj 	(void) m_free(dtom(so));
1314916Swnj }
1324916Swnj 
1334786Swnj /*
1344890Swnj  * Close a socket on last file table reference removal.
1354890Swnj  * Initiate disconnect if connected.
1364890Swnj  * Free socket when disconnect complete.
1374829Swnj  */
13812757Ssam soclose(so)
1394829Swnj 	register struct socket *so;
1404829Swnj {
1414890Swnj 	int s = splnet();		/* conservative */
1428713Sroot 	int error;
1434829Swnj 
1447507Sroot 	if (so->so_options & SO_ACCEPTCONN) {
1457507Sroot 		while (so->so_q0 != so)
14610399Ssam 			(void) soabort(so->so_q0);
1477507Sroot 		while (so->so_q != so)
14810399Ssam 			(void) soabort(so->so_q);
1497507Sroot 	}
1504890Swnj 	if (so->so_pcb == 0)
1514890Swnj 		goto discard;
1524890Swnj 	if (so->so_state & SS_ISCONNECTED) {
1534890Swnj 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
1548725Sroot 			error = sodisconnect(so, (struct mbuf *)0);
15512757Ssam 			if (error)
15612757Ssam 				goto drop;
1574890Swnj 		}
15810267Ssam 		if (so->so_options & SO_LINGER) {
1595281Sroot 			if ((so->so_state & SS_ISDISCONNECTING) &&
16012757Ssam 			    (so->so_state & SS_NBIO))
16112757Ssam 				goto drop;
1625281Sroot 			while (so->so_state & SS_ISCONNECTED)
1635281Sroot 				sleep((caddr_t)&so->so_timeo, PZERO+1);
1644890Swnj 		}
1654890Swnj 	}
1665580Sroot drop:
1676880Ssam 	if (so->so_pcb) {
16812757Ssam 		int error2 =
16912757Ssam 		    (*so->so_proto->pr_usrreq)(so, PRU_DETACH,
17012757Ssam 			(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
17112757Ssam 		if (error == 0)
17212757Ssam 			error = error2;
1736880Ssam 	}
1744890Swnj discard:
17510399Ssam 	if (so->so_state & SS_NOFDREF)
17610399Ssam 		panic("soclose: NOFDREF");
1777507Sroot 	so->so_state |= SS_NOFDREF;
1784950Swnj 	sofree(so);
1794890Swnj 	splx(s);
18012757Ssam 	return (error);
1814829Swnj }
1824829Swnj 
18310399Ssam /*
18410399Ssam  * Must be called at splnet...
18510399Ssam  */
18610399Ssam soabort(so)
18710399Ssam 	struct socket *so;
18810399Ssam {
18910399Ssam 
19012757Ssam 	return (
19112757Ssam 	    (*so->so_proto->pr_usrreq)(so, PRU_ABORT,
19212757Ssam 		(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
19310399Ssam }
19410399Ssam 
19510267Ssam soaccept(so, nam)
19612757Ssam 	register struct socket *so;
1978300Sroot 	struct mbuf *nam;
1984927Swnj {
1994927Swnj 	int s = splnet();
2004927Swnj 	int error;
2014927Swnj 
20210399Ssam 	if ((so->so_state & SS_NOFDREF) == 0)
20310399Ssam 		panic("soaccept: !NOFDREF");
20410267Ssam 	so->so_state &= ~SS_NOFDREF;
2058300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT,
20612757Ssam 	    (struct mbuf *)0, nam, (struct mbuf *)0);
2074927Swnj 	splx(s);
2084927Swnj 	return (error);
2094927Swnj }
2104927Swnj 
21110267Ssam soconnect(so, nam)
21212757Ssam 	register struct socket *so;
2138300Sroot 	struct mbuf *nam;
2144786Swnj {
2154890Swnj 	int s = splnet();
2164890Swnj 	int error;
2174786Swnj 
2184890Swnj 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
2194890Swnj 		error = EISCONN;
2204890Swnj 		goto bad;
2214890Swnj 	}
2228300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
22312757Ssam 	    (struct mbuf *)0, nam, (struct mbuf *)0);
2244890Swnj bad:
2254890Swnj 	splx(s);
2264890Swnj 	return (error);
2274786Swnj }
2284786Swnj 
22912757Ssam soconnect2(so1, so2)
23012757Ssam 	register struct socket *so1;
23112757Ssam 	struct socket *so2;
23212757Ssam {
23312757Ssam 	int s = splnet();
23412757Ssam 	int error;
23512757Ssam 
23613113Ssam 	error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2,
23713113Ssam 	    (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0);
23812757Ssam 	splx(s);
23912757Ssam 	return (error);
24012757Ssam }
24112757Ssam 
2428300Sroot sodisconnect(so, nam)
24312757Ssam 	register struct socket *so;
2448300Sroot 	struct mbuf *nam;
2454786Swnj {
2464890Swnj 	int s = splnet();
2474890Swnj 	int error;
2484786Swnj 
2494890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2504890Swnj 		error = ENOTCONN;
2514890Swnj 		goto bad;
2524890Swnj 	}
2534890Swnj 	if (so->so_state & SS_ISDISCONNECTING) {
2544890Swnj 		error = EALREADY;
2554890Swnj 		goto bad;
2564890Swnj 	}
2578300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT,
25812757Ssam 	    (struct mbuf *)0, nam, (struct mbuf *)0);
2594890Swnj bad:
2604890Swnj 	splx(s);
2614890Swnj 	return (error);
2624786Swnj }
2634786Swnj 
2644786Swnj /*
2654890Swnj  * Send on a socket.
2664890Swnj  * If send must go all at once and message is larger than
2674890Swnj  * send buffering, then hard error.
2684890Swnj  * Lock against other senders.
2694890Swnj  * If must go all at once and not enough room now, then
2704890Swnj  * inform user that this would block and do nothing.
27116412Skarels  * Otherwise, if nonblocking, send as much as possible.
2724786Swnj  */
27312757Ssam sosend(so, nam, uio, flags, rights)
2744786Swnj 	register struct socket *so;
2758300Sroot 	struct mbuf *nam;
27612757Ssam 	register struct uio *uio;
2778319Sroot 	int flags;
27812757Ssam 	struct mbuf *rights;
2794786Swnj {
2804890Swnj 	struct mbuf *top = 0;
28116412Skarels 	register struct mbuf *m, **mp;
28212757Ssam 	register int space;
28316412Skarels 	int len, error = 0, s, dontroute, first = 1;
2844786Swnj 
2857827Sroot 	if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat)
2864890Swnj 		return (EMSGSIZE);
28712757Ssam 	dontroute =
28812757Ssam 	    (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
28912757Ssam 	    (so->so_proto->pr_flags & PR_ATOMIC);
29016412Skarels 	u.u_ru.ru_msgsnd++;
29116412Skarels #define	snderr(errno)	{ error = errno; splx(s); goto release; }
29216412Skarels 
2936419Sroot restart:
2944890Swnj 	sblock(&so->so_snd);
29516412Skarels 	do {
29616412Skarels 		s = splnet();
29716412Skarels 		if (so->so_state & SS_CANTSENDMORE) {
29816412Skarels 			psignal(u.u_procp, SIGPIPE);
29916412Skarels 			snderr(EPIPE);
30016412Skarels 		}
30116412Skarels 		if (so->so_error) {
30216412Skarels 			error = so->so_error;
30316412Skarels 			so->so_error = 0;			/* ??? */
30416412Skarels 			splx(s);
30516412Skarels 			goto release;
30616412Skarels 		}
30716412Skarels 		if ((so->so_state & SS_ISCONNECTED) == 0) {
30816412Skarels 			if (so->so_proto->pr_flags & PR_CONNREQUIRED)
30916412Skarels 				snderr(ENOTCONN);
31016412Skarels 			if (nam == 0)
31116412Skarels 				snderr(EDESTADDRREQ);
31216412Skarels 		}
31316412Skarels 		if (flags & MSG_OOB)
31416412Skarels 			space = 1024;
31516412Skarels 		else {
31616412Skarels 			space = sbspace(&so->so_snd);
31716412Skarels 			if (space <= 0 ||
318*16992Skarels 			   (sosendallatonce(so) && space < uio->uio_resid) ||
319*16992Skarels 			   (uio->uio_resid >= CLBYTES && space < CLBYTES &&
320*16992Skarels 			   so->so_snd.sb_cc >= CLBYTES &&
321*16992Skarels 			   (so->so_state & SS_NBIO) == 0)) {
32216412Skarels 				if (so->so_state & SS_NBIO) {
32316412Skarels 					if (first)
32416412Skarels 						error = EWOULDBLOCK;
32516412Skarels 					splx(s);
32616412Skarels 					goto release;
32716412Skarels 				}
32816412Skarels 				sbunlock(&so->so_snd);
32916412Skarels 				sbwait(&so->so_snd);
33016412Skarels 				splx(s);
33116412Skarels 				goto restart;
33216412Skarels 			}
33316412Skarels 		}
33416412Skarels 		splx(s);
33516412Skarels 		mp = &top;
33616412Skarels 		while (uio->uio_resid > 0 && space > 0) {
33716412Skarels 			register struct iovec *iov = uio->uio_iov;
3384890Swnj 
33916412Skarels 			if (iov->iov_len == 0) {
34016412Skarels 				uio->uio_iov++;
34116412Skarels 				uio->uio_iovcnt--;
34216412Skarels 				if (uio->uio_iovcnt < 0)
34316412Skarels 					panic("sosend");
34416412Skarels 				continue;
34516412Skarels 			}
34616412Skarels 			MGET(m, M_WAIT, MT_DATA);
34716412Skarels 			if (m == NULL) {
34816412Skarels 				error = ENOBUFS;		/* SIGPIPE? */
34916412Skarels 				goto release;
35016412Skarels 			}
35116412Skarels 			if (iov->iov_len >= CLBYTES && space >= CLBYTES) {
35216412Skarels 				register struct mbuf *p;
35316412Skarels 				MCLGET(p, 1);
35416412Skarels 				if (p == 0)
35516412Skarels 					goto nopages;
35616412Skarels 				m->m_off = (int)p - (int)m;
35716412Skarels 				len = CLBYTES;
35816412Skarels 			} else {
35916412Skarels nopages:
36016412Skarels 				len = MIN(MLEN, iov->iov_len);
36116412Skarels 			}
36216412Skarels 			error = uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio);
36316412Skarels 			m->m_len = len;
36416412Skarels 			*mp = m;
36516412Skarels 			if (error)
36616412Skarels 				goto release;
36716412Skarels 			mp = &m->m_next;
36816412Skarels 			space -= len;
36916412Skarels 		}
370*16992Skarels 		if (top) {
371*16992Skarels 			if (dontroute)
372*16992Skarels 				so->so_options |= SO_DONTROUTE;
373*16992Skarels 			s = splnet();
374*16992Skarels 			error = (*so->so_proto->pr_usrreq)(so,
375*16992Skarels 			    (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
376*16992Skarels 			    top, (caddr_t)nam, rights);
377*16992Skarels 			splx(s);
378*16992Skarels 			if (dontroute)
379*16992Skarels 				so->so_options &= ~SO_DONTROUTE;
380*16992Skarels 		}
3816419Sroot 		top = 0;
38216412Skarels 		first = 0;
38314781Ssam 		if (error)
38416412Skarels 			break;
38516412Skarels 	} while (uio->uio_resid);
3864890Swnj 
3874786Swnj release:
3884890Swnj 	sbunlock(&so->so_snd);
3896419Sroot 	if (top)
3906419Sroot 		m_freem(top);
3914786Swnj 	return (error);
3924786Swnj }
3934786Swnj 
39412757Ssam soreceive(so, aname, uio, flags, rightsp)
3954786Swnj 	register struct socket *so;
3968300Sroot 	struct mbuf **aname;
39712757Ssam 	register struct uio *uio;
3988319Sroot 	int flags;
39912757Ssam 	struct mbuf **rightsp;
4004786Swnj {
4014786Swnj 	register struct mbuf *m, *n;
40212757Ssam 	register int len, error = 0, s, eor, tomark;
40312757Ssam 	struct protosw *pr = so->so_proto;
40412757Ssam 	int moff;
4054786Swnj 
40612757Ssam 	if (rightsp)
40712757Ssam 		*rightsp = 0;
40812757Ssam 	if (aname)
40912757Ssam 		*aname = 0;
41012757Ssam 	if (flags & MSG_OOB) {
4119635Ssam 		m = m_get(M_WAIT, MT_DATA);
41212757Ssam 		if (m == 0)
41310137Ssam 			return (ENOBUFS);
41412757Ssam 		error = (*pr->pr_usrreq)(so, PRU_RCVOOB,
41512757Ssam 		    m, (struct mbuf *)0, (struct mbuf *)0);
4168594Sroot 		if (error)
41710137Ssam 			goto bad;
4188319Sroot 		do {
41910137Ssam 			len = uio->uio_resid;
4208319Sroot 			if (len > m->m_len)
4218319Sroot 				len = m->m_len;
4228594Sroot 			error =
4238793Sroot 			    uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio);
4248319Sroot 			m = m_free(m);
4258594Sroot 		} while (uio->uio_resid && error == 0 && m);
42610137Ssam bad:
4278319Sroot 		if (m)
4288771Sroot 			m_freem(m);
4298594Sroot 		return (error);
4308319Sroot 	}
4318319Sroot 
4324890Swnj restart:
4334890Swnj 	sblock(&so->so_rcv);
4348835Sroot 	s = splnet();
4354890Swnj 
4364890Swnj #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
4374786Swnj 	if (so->so_rcv.sb_cc == 0) {
4385168Swnj 		if (so->so_error) {
4395168Swnj 			error = so->so_error;
4405168Swnj 			so->so_error = 0;
4415168Swnj 			splx(s);
4425168Swnj 			goto release;
4435168Swnj 		}
4444890Swnj 		if (so->so_state & SS_CANTRCVMORE) {
4454890Swnj 			splx(s);
4464890Swnj 			goto release;
4474890Swnj 		}
4485015Sroot 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
4495015Sroot 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
4505015Sroot 			rcverr(ENOTCONN);
4516214Swnj 		if (so->so_state & SS_NBIO)
4525168Swnj 			rcverr(EWOULDBLOCK);
4534890Swnj 		sbunlock(&so->so_rcv);
4544971Swnj 		sbwait(&so->so_rcv);
4555012Swnj 		splx(s);
4564890Swnj 		goto restart;
4574786Swnj 	}
4588041Sroot 	u.u_ru.ru_msgrcv++;
4594829Swnj 	m = so->so_rcv.sb_mb;
4604786Swnj 	if (m == 0)
4614786Swnj 		panic("receive");
46212757Ssam 	if (pr->pr_flags & PR_ADDR) {
46312757Ssam 		if ((flags & MSG_PEEK) == 0) {
4648319Sroot 			so->so_rcv.sb_cc -= m->m_len;
4658319Sroot 			so->so_rcv.sb_mbcnt -= MSIZE;
4668319Sroot 		}
4678300Sroot 		if (aname) {
46812757Ssam 			if (flags & MSG_PEEK) {
4698319Sroot 				*aname = m_copy(m, 0, m->m_len);
47010137Ssam 				if (*aname == NULL)
47110137Ssam 					panic("receive 2");
47210137Ssam 			} else
4738319Sroot 				*aname = m;
4748300Sroot 			m = m->m_next;
4758300Sroot 			(*aname)->m_next = 0;
4768300Sroot 		} else
47712757Ssam 			if (flags & MSG_PEEK)
4788319Sroot 				m = m->m_next;
4798319Sroot 			else
4808319Sroot 				m = m_free(m);
4814890Swnj 		if (m == 0)
48212757Ssam 			panic("receive 2a");
48312757Ssam 		if (rightsp) {
48412757Ssam 			if (m->m_len)
48512757Ssam 				*rightsp = m_copy(m, 0, m->m_len);
48612757Ssam 			else {
48712757Ssam 				*rightsp = m_get(M_DONTWAIT, MT_SONAME);
48812757Ssam 				if (*rightsp)
48912757Ssam 					(*rightsp)->m_len = 0;
49012757Ssam 			}
49114813Ssam #ifdef notdef
49212757Ssam 			if (*rightsp == NULL)
49312757Ssam 				panic("receive 2b");
49414813Ssam #endif
49512757Ssam 		}
49612757Ssam 		if (flags & MSG_PEEK)
49712757Ssam 			m = m->m_next;
49812757Ssam 		else {
49912757Ssam 			so->so_rcv.sb_cc -= m->m_len;
50012757Ssam 			so->so_rcv.sb_mbcnt -= MSIZE;
50112757Ssam 			m = m_free(m);
50212757Ssam 		}
50312757Ssam 		if (m == 0)
50410137Ssam 			panic("receive 3");
50512757Ssam 		if ((flags & MSG_PEEK) == 0)
5068548Sroot 			so->so_rcv.sb_mb = m;
5074890Swnj 	}
5084786Swnj 	eor = 0;
5098319Sroot 	moff = 0;
5108319Sroot 	tomark = so->so_oobmark;
5114786Swnj 	do {
5127827Sroot 		if (uio->uio_resid <= 0)
5137747Sroot 			break;
5147827Sroot 		len = uio->uio_resid;
5157747Sroot 		so->so_state &= ~SS_RCVATMARK;
5168319Sroot 		if (tomark && len > tomark)
5178319Sroot 			len = tomark;
5188548Sroot 		if (moff+len > m->m_len - moff)
5198319Sroot 			len = m->m_len - moff;
5204786Swnj 		splx(s);
5218594Sroot 		error =
5228793Sroot 		    uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio);
5234786Swnj 		s = splnet();
5244786Swnj 		if (len == m->m_len) {
5256091Sroot 			eor = (int)m->m_act;
52612757Ssam 			if (flags & MSG_PEEK)
5278319Sroot 				m = m->m_next;
5288319Sroot 			else {
5298319Sroot 				sbfree(&so->so_rcv, m);
5308319Sroot 				MFREE(m, n);
5318319Sroot 				m = n;
5328548Sroot 				so->so_rcv.sb_mb = m;
5338319Sroot 			}
5348319Sroot 			moff = 0;
5354786Swnj 		} else {
53612757Ssam 			if (flags & MSG_PEEK)
5378319Sroot 				moff += len;
5388319Sroot 			else {
5398319Sroot 				m->m_off += len;
5408319Sroot 				m->m_len -= len;
5418319Sroot 				so->so_rcv.sb_cc -= len;
5428319Sroot 			}
5434786Swnj 		}
54412757Ssam 		if ((flags & MSG_PEEK) == 0 && so->so_oobmark) {
5457747Sroot 			so->so_oobmark -= len;
5467747Sroot 			if (so->so_oobmark == 0) {
5477747Sroot 				so->so_state |= SS_RCVATMARK;
5487747Sroot 				break;
5497747Sroot 			}
5507747Sroot 		}
5518319Sroot 		if (tomark) {
5528319Sroot 			tomark -= len;
5538319Sroot 			if (tomark == 0)
5548319Sroot 				break;
5558319Sroot 		}
5568594Sroot 	} while (m && error == 0 && !eor);
55712757Ssam 	if (flags & MSG_PEEK)
5588319Sroot 		goto release;
5594786Swnj 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
5604786Swnj 		do {
5614786Swnj 			if (m == 0)
56210137Ssam 				panic("receive 4");
5634890Swnj 			sbfree(&so->so_rcv, m);
5644786Swnj 			eor = (int)m->m_act;
5654786Swnj 			so->so_rcv.sb_mb = m->m_next;
5664786Swnj 			MFREE(m, n);
5674890Swnj 			m = n;
5684786Swnj 		} while (eor == 0);
5694890Swnj 	if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
5708300Sroot 		(*so->so_proto->pr_usrreq)(so, PRU_RCVD,
57112757Ssam 		    (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
5724890Swnj release:
5734916Swnj 	sbunlock(&so->so_rcv);
57412757Ssam 	if (error == 0 && rightsp &&
57512757Ssam 	    *rightsp && so->so_proto->pr_family == AF_UNIX)
57612757Ssam 		error = unp_externalize(*rightsp);
5774890Swnj 	splx(s);
5784916Swnj 	return (error);
5794786Swnj }
5804786Swnj 
58110267Ssam soshutdown(so, how)
58212757Ssam 	register struct socket *so;
58312757Ssam 	register int how;
58410267Ssam {
58512757Ssam 	register struct protosw *pr = so->so_proto;
58610267Ssam 
58710267Ssam 	how++;
58812757Ssam 	if (how & FREAD)
58912757Ssam 		sorflush(so);
59010267Ssam 	if (how & FWRITE)
59112757Ssam 		return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN,
59212757Ssam 		    (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
59310267Ssam 	return (0);
59410267Ssam }
59510267Ssam 
59612757Ssam sorflush(so)
59712757Ssam 	register struct socket *so;
59812757Ssam {
59912757Ssam 	register struct sockbuf *sb = &so->so_rcv;
60012757Ssam 	register struct protosw *pr = so->so_proto;
60112757Ssam 	register int s;
60212757Ssam 	struct sockbuf asb;
60312757Ssam 
60412757Ssam 	sblock(sb);
60512757Ssam 	s = splimp();
60612757Ssam 	socantrcvmore(so);
60712757Ssam 	sbunlock(sb);
60812757Ssam 	asb = *sb;
60912757Ssam 	bzero((caddr_t)sb, sizeof (*sb));
61012757Ssam 	splx(s);
61112757Ssam 	if (pr->pr_family == AF_UNIX && (pr->pr_flags & PR_RIGHTS))
61212757Ssam 		unp_scan(asb.sb_mb, unp_discard);
61312757Ssam 	sbrelease(&asb);
61412757Ssam }
61512757Ssam 
61610267Ssam sosetopt(so, level, optname, m)
61712757Ssam 	register struct socket *so;
61810267Ssam 	int level, optname;
61912757Ssam 	register struct mbuf *m;
62010267Ssam {
62110267Ssam 
62210267Ssam 	if (level != SOL_SOCKET)
62310267Ssam 		return (EINVAL);	/* XXX */
62410267Ssam 	switch (optname) {
62510267Ssam 
62610267Ssam 	case SO_DEBUG:
62710269Ssam 	case SO_KEEPALIVE:
62810599Ssam 	case SO_DONTROUTE:
62910599Ssam 	case SO_USELOOPBACK:
63010599Ssam 	case SO_REUSEADDR:
63110599Ssam 		so->so_options |= optname;
63210269Ssam 		break;
63310269Ssam 
63410267Ssam 	case SO_LINGER:
63510269Ssam 		if (m == NULL || m->m_len != sizeof (int))
63610269Ssam 			return (EINVAL);
63710267Ssam 		so->so_options |= SO_LINGER;
63810269Ssam 		so->so_linger = *mtod(m, int *);
63910267Ssam 		break;
64010267Ssam 
64110267Ssam 	case SO_DONTLINGER:
64210267Ssam 		so->so_options &= ~SO_LINGER;
64310267Ssam 		so->so_linger = 0;
64410267Ssam 		break;
64510267Ssam 
64610267Ssam 	default:
64710267Ssam 		return (EINVAL);
64810267Ssam 	}
64910267Ssam 	return (0);
65010267Ssam }
65110267Ssam 
65210267Ssam sogetopt(so, level, optname, m)
65312757Ssam 	register struct socket *so;
65410267Ssam 	int level, optname;
65512757Ssam 	register struct mbuf *m;
65610267Ssam {
65710267Ssam 
65810267Ssam 	if (level != SOL_SOCKET)
65910267Ssam 		return (EINVAL);	/* XXX */
66010267Ssam 	switch (optname) {
66110267Ssam 
66210267Ssam 	case SO_USELOOPBACK:
66310267Ssam 	case SO_DONTROUTE:
66410267Ssam 	case SO_DEBUG:
66510267Ssam 	case SO_KEEPALIVE:
66610267Ssam 	case SO_LINGER:
66710599Ssam 	case SO_REUSEADDR:
66810267Ssam 		if ((so->so_options & optname) == 0)
66910267Ssam 			return (ENOPROTOOPT);
67010269Ssam 		if (optname == SO_LINGER && m != NULL) {
67110267Ssam 			*mtod(m, int *) = so->so_linger;
67210267Ssam 			m->m_len = sizeof (so->so_linger);
67310267Ssam 		}
67410267Ssam 		break;
67510267Ssam 
67610267Ssam 	default:
67710267Ssam 		return (EINVAL);
67810267Ssam 	}
67910267Ssam 	return (0);
68010267Ssam }
68110267Ssam 
6825423Swnj sohasoutofband(so)
68312757Ssam 	register struct socket *so;
6845423Swnj {
6855423Swnj 
6865423Swnj 	if (so->so_pgrp == 0)
6875423Swnj 		return;
6885423Swnj 	if (so->so_pgrp > 0)
6895423Swnj 		gsignal(so->so_pgrp, SIGURG);
6905429Swnj 	else {
6915429Swnj 		struct proc *p = pfind(-so->so_pgrp);
6925429Swnj 
6935429Swnj 		if (p)
6945429Swnj 			psignal(p, SIGURG);
6955429Swnj 	}
6965423Swnj }
697