xref: /csrg-svn/sys/kern/uipc_socket.c (revision 21783)
1*21783Skarels /*	uipc_socket.c	6.13	85/06/03	*/
24786Swnj 
317102Sbloom #include "param.h"
417102Sbloom #include "systm.h"
517102Sbloom #include "dir.h"
617102Sbloom #include "user.h"
717102Sbloom #include "proc.h"
817102Sbloom #include "file.h"
917102Sbloom #include "inode.h"
1017102Sbloom #include "buf.h"
1117102Sbloom #include "mbuf.h"
1217102Sbloom #include "un.h"
1317102Sbloom #include "domain.h"
1417102Sbloom #include "protosw.h"
1517102Sbloom #include "socket.h"
1617102Sbloom #include "socketvar.h"
1717102Sbloom #include "stat.h"
1817102Sbloom #include "ioctl.h"
1917102Sbloom #include "uio.h"
206355Ssam #include "../net/route.h"
2112757Ssam #include "../netinet/in.h"
2211571Ssam #include "../net/if.h"
234786Swnj 
244786Swnj /*
258300Sroot  * Socket operation routines.
268300Sroot  * These routines are called by the routines in
278300Sroot  * sys_socket.c or from a system process, and
288300Sroot  * implement the semantics of socket operations by
298300Sroot  * switching out to the protocol specific routines.
3012757Ssam  *
3112757Ssam  * TODO:
3212757Ssam  *	test socketpair
3321767Skarels  *	clean up async
3412757Ssam  *	out-of-band is a kludge
354786Swnj  */
368594Sroot /*ARGSUSED*/
3710267Ssam socreate(dom, aso, type, proto)
384786Swnj 	struct socket **aso;
3912757Ssam 	register int type;
4012757Ssam 	int proto;
414786Swnj {
424786Swnj 	register struct protosw *prp;
434786Swnj 	register struct socket *so;
4412757Ssam 	register struct mbuf *m;
4512757Ssam 	register int error;
464786Swnj 
474890Swnj 	if (proto)
4821767Skarels 		prp = pffindproto(dom, proto, type);
494890Swnj 	else
509168Ssam 		prp = pffindtype(dom, type);
514890Swnj 	if (prp == 0)
524890Swnj 		return (EPROTONOSUPPORT);
538300Sroot 	if (prp->pr_type != type)
548300Sroot 		return (EPROTOTYPE);
559635Ssam 	m = m_getclr(M_WAIT, MT_SOCKET);
564786Swnj 	so = mtod(m, struct socket *);
5712757Ssam 	so->so_options = 0;
586214Swnj 	so->so_state = 0;
599168Ssam 	so->so_type = type;
606214Swnj 	if (u.u_uid == 0)
616214Swnj 		so->so_state = SS_PRIV;
624786Swnj 	so->so_proto = prp;
6312757Ssam 	error =
6412757Ssam 	    (*prp->pr_usrreq)(so, PRU_ATTACH,
6521767Skarels 		(struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0);
664979Swnj 	if (error) {
677507Sroot 		so->so_state |= SS_NOFDREF;
687180Swnj 		sofree(so);
694890Swnj 		return (error);
704786Swnj 	}
714786Swnj 	*aso = so;
724786Swnj 	return (0);
734786Swnj }
744786Swnj 
7510267Ssam sobind(so, nam)
768300Sroot 	struct socket *so;
778300Sroot 	struct mbuf *nam;
788300Sroot {
798300Sroot 	int s = splnet();
808300Sroot 	int error;
818300Sroot 
828300Sroot 	error =
8312757Ssam 	    (*so->so_proto->pr_usrreq)(so, PRU_BIND,
8412757Ssam 		(struct mbuf *)0, nam, (struct mbuf *)0);
858300Sroot 	splx(s);
868300Sroot 	return (error);
878300Sroot }
888300Sroot 
898300Sroot solisten(so, backlog)
9012757Ssam 	register struct socket *so;
918300Sroot 	int backlog;
928300Sroot {
9312757Ssam 	int s = splnet(), error;
948300Sroot 
9512757Ssam 	error =
9612757Ssam 	    (*so->so_proto->pr_usrreq)(so, PRU_LISTEN,
9712757Ssam 		(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
988300Sroot 	if (error) {
998300Sroot 		splx(s);
1008300Sroot 		return (error);
1018300Sroot 	}
1028300Sroot 	if (so->so_q == 0) {
1038300Sroot 		so->so_q = so;
1048300Sroot 		so->so_q0 = so;
1058300Sroot 		so->so_options |= SO_ACCEPTCONN;
1068300Sroot 	}
1078300Sroot 	if (backlog < 0)
1088300Sroot 		backlog = 0;
10910137Ssam 	so->so_qlimit = MIN(backlog, SOMAXCONN);
11012493Ssam 	splx(s);
1118300Sroot 	return (0);
1128300Sroot }
1138300Sroot 
1144916Swnj sofree(so)
11512757Ssam 	register struct socket *so;
1164916Swnj {
1174916Swnj 
1187507Sroot 	if (so->so_head) {
1197507Sroot 		if (!soqremque(so, 0) && !soqremque(so, 1))
1207507Sroot 			panic("sofree dq");
1217507Sroot 		so->so_head = 0;
1227507Sroot 	}
1237507Sroot 	if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
1244950Swnj 		return;
1254950Swnj 	sbrelease(&so->so_snd);
12612757Ssam 	sorflush(so);
1274971Swnj 	(void) m_free(dtom(so));
1284916Swnj }
1294916Swnj 
1304786Swnj /*
1314890Swnj  * Close a socket on last file table reference removal.
1324890Swnj  * Initiate disconnect if connected.
1334890Swnj  * Free socket when disconnect complete.
1344829Swnj  */
13512757Ssam soclose(so)
1364829Swnj 	register struct socket *so;
1374829Swnj {
1384890Swnj 	int s = splnet();		/* conservative */
1398713Sroot 	int error;
1404829Swnj 
1417507Sroot 	if (so->so_options & SO_ACCEPTCONN) {
1427507Sroot 		while (so->so_q0 != so)
14310399Ssam 			(void) soabort(so->so_q0);
1447507Sroot 		while (so->so_q != so)
14510399Ssam 			(void) soabort(so->so_q);
1467507Sroot 	}
1474890Swnj 	if (so->so_pcb == 0)
1484890Swnj 		goto discard;
1494890Swnj 	if (so->so_state & SS_ISCONNECTED) {
1504890Swnj 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
1518725Sroot 			error = sodisconnect(so, (struct mbuf *)0);
15212757Ssam 			if (error)
15312757Ssam 				goto drop;
1544890Swnj 		}
15510267Ssam 		if (so->so_options & SO_LINGER) {
1565281Sroot 			if ((so->so_state & SS_ISDISCONNECTING) &&
15712757Ssam 			    (so->so_state & SS_NBIO))
15812757Ssam 				goto drop;
1595281Sroot 			while (so->so_state & SS_ISCONNECTED)
1605281Sroot 				sleep((caddr_t)&so->so_timeo, PZERO+1);
1614890Swnj 		}
1624890Swnj 	}
1635580Sroot drop:
1646880Ssam 	if (so->so_pcb) {
16512757Ssam 		int error2 =
16612757Ssam 		    (*so->so_proto->pr_usrreq)(so, PRU_DETACH,
16712757Ssam 			(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
16812757Ssam 		if (error == 0)
16912757Ssam 			error = error2;
1706880Ssam 	}
1714890Swnj discard:
17210399Ssam 	if (so->so_state & SS_NOFDREF)
17310399Ssam 		panic("soclose: NOFDREF");
1747507Sroot 	so->so_state |= SS_NOFDREF;
1754950Swnj 	sofree(so);
1764890Swnj 	splx(s);
17712757Ssam 	return (error);
1784829Swnj }
1794829Swnj 
18010399Ssam /*
18110399Ssam  * Must be called at splnet...
18210399Ssam  */
18310399Ssam soabort(so)
18410399Ssam 	struct socket *so;
18510399Ssam {
18610399Ssam 
18712757Ssam 	return (
18812757Ssam 	    (*so->so_proto->pr_usrreq)(so, PRU_ABORT,
18912757Ssam 		(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
19010399Ssam }
19110399Ssam 
19210267Ssam soaccept(so, nam)
19312757Ssam 	register struct socket *so;
1948300Sroot 	struct mbuf *nam;
1954927Swnj {
1964927Swnj 	int s = splnet();
1974927Swnj 	int error;
1984927Swnj 
19910399Ssam 	if ((so->so_state & SS_NOFDREF) == 0)
20010399Ssam 		panic("soaccept: !NOFDREF");
20110267Ssam 	so->so_state &= ~SS_NOFDREF;
2028300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT,
20312757Ssam 	    (struct mbuf *)0, nam, (struct mbuf *)0);
2044927Swnj 	splx(s);
2054927Swnj 	return (error);
2064927Swnj }
2074927Swnj 
20810267Ssam soconnect(so, nam)
20912757Ssam 	register struct socket *so;
2108300Sroot 	struct mbuf *nam;
2114786Swnj {
2124890Swnj 	int s = splnet();
2134890Swnj 	int error;
2144786Swnj 
2154890Swnj 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
2164890Swnj 		error = EISCONN;
2174890Swnj 		goto bad;
2184890Swnj 	}
2198300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
22012757Ssam 	    (struct mbuf *)0, nam, (struct mbuf *)0);
2214890Swnj bad:
2224890Swnj 	splx(s);
2234890Swnj 	return (error);
2244786Swnj }
2254786Swnj 
22612757Ssam soconnect2(so1, so2)
22712757Ssam 	register struct socket *so1;
22812757Ssam 	struct socket *so2;
22912757Ssam {
23012757Ssam 	int s = splnet();
23112757Ssam 	int error;
23212757Ssam 
23313113Ssam 	error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2,
23413113Ssam 	    (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0);
23512757Ssam 	splx(s);
23612757Ssam 	return (error);
23712757Ssam }
23812757Ssam 
2398300Sroot sodisconnect(so, nam)
24012757Ssam 	register struct socket *so;
2418300Sroot 	struct mbuf *nam;
2424786Swnj {
2434890Swnj 	int s = splnet();
2444890Swnj 	int error;
2454786Swnj 
2464890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2474890Swnj 		error = ENOTCONN;
2484890Swnj 		goto bad;
2494890Swnj 	}
2504890Swnj 	if (so->so_state & SS_ISDISCONNECTING) {
2514890Swnj 		error = EALREADY;
2524890Swnj 		goto bad;
2534890Swnj 	}
2548300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT,
25512757Ssam 	    (struct mbuf *)0, nam, (struct mbuf *)0);
2564890Swnj bad:
2574890Swnj 	splx(s);
2584890Swnj 	return (error);
2594786Swnj }
2604786Swnj 
2614786Swnj /*
2624890Swnj  * Send on a socket.
2634890Swnj  * If send must go all at once and message is larger than
2644890Swnj  * send buffering, then hard error.
2654890Swnj  * Lock against other senders.
2664890Swnj  * If must go all at once and not enough room now, then
2674890Swnj  * inform user that this would block and do nothing.
26816412Skarels  * Otherwise, if nonblocking, send as much as possible.
2694786Swnj  */
27012757Ssam sosend(so, nam, uio, flags, rights)
2714786Swnj 	register struct socket *so;
2728300Sroot 	struct mbuf *nam;
27312757Ssam 	register struct uio *uio;
2748319Sroot 	int flags;
27512757Ssam 	struct mbuf *rights;
2764786Swnj {
2774890Swnj 	struct mbuf *top = 0;
27816412Skarels 	register struct mbuf *m, **mp;
27912757Ssam 	register int space;
28016412Skarels 	int len, error = 0, s, dontroute, first = 1;
2814786Swnj 
2827827Sroot 	if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat)
2834890Swnj 		return (EMSGSIZE);
28412757Ssam 	dontroute =
28512757Ssam 	    (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
28612757Ssam 	    (so->so_proto->pr_flags & PR_ATOMIC);
28716412Skarels 	u.u_ru.ru_msgsnd++;
28816412Skarels #define	snderr(errno)	{ error = errno; splx(s); goto release; }
28916412Skarels 
2906419Sroot restart:
2914890Swnj 	sblock(&so->so_snd);
29216412Skarels 	do {
29316412Skarels 		s = splnet();
29421108Skarels 		if (so->so_state & SS_CANTSENDMORE)
29516412Skarels 			snderr(EPIPE);
29616412Skarels 		if (so->so_error) {
29716412Skarels 			error = so->so_error;
29816412Skarels 			so->so_error = 0;			/* ??? */
29916412Skarels 			splx(s);
30016412Skarels 			goto release;
30116412Skarels 		}
30216412Skarels 		if ((so->so_state & SS_ISCONNECTED) == 0) {
30316412Skarels 			if (so->so_proto->pr_flags & PR_CONNREQUIRED)
30416412Skarels 				snderr(ENOTCONN);
30516412Skarels 			if (nam == 0)
30616412Skarels 				snderr(EDESTADDRREQ);
30716412Skarels 		}
30816412Skarels 		if (flags & MSG_OOB)
30916412Skarels 			space = 1024;
31016412Skarels 		else {
31116412Skarels 			space = sbspace(&so->so_snd);
31216412Skarels 			if (space <= 0 ||
31316992Skarels 			   (sosendallatonce(so) && space < uio->uio_resid) ||
31416992Skarels 			   (uio->uio_resid >= CLBYTES && space < CLBYTES &&
31516992Skarels 			   so->so_snd.sb_cc >= CLBYTES &&
31616992Skarels 			   (so->so_state & SS_NBIO) == 0)) {
31716412Skarels 				if (so->so_state & SS_NBIO) {
31816412Skarels 					if (first)
31916412Skarels 						error = EWOULDBLOCK;
32016412Skarels 					splx(s);
32116412Skarels 					goto release;
32216412Skarels 				}
32316412Skarels 				sbunlock(&so->so_snd);
32416412Skarels 				sbwait(&so->so_snd);
32516412Skarels 				splx(s);
32616412Skarels 				goto restart;
32716412Skarels 			}
32816412Skarels 		}
32916412Skarels 		splx(s);
33016412Skarels 		mp = &top;
33121108Skarels 		while (space > 0) {
33216412Skarels 			register struct iovec *iov = uio->uio_iov;
3334890Swnj 
33416412Skarels 			MGET(m, M_WAIT, MT_DATA);
33521767Skarels 			if (iov->iov_len >= NBPG && space >= CLBYTES) {
33616412Skarels 				register struct mbuf *p;
33716412Skarels 				MCLGET(p, 1);
33816412Skarels 				if (p == 0)
33916412Skarels 					goto nopages;
34016412Skarels 				m->m_off = (int)p - (int)m;
34121767Skarels 				len = min(CLBYTES, iov->iov_len);
34221767Skarels 				space -= CLBYTES;
34316412Skarels 			} else {
34416412Skarels nopages:
34516412Skarels 				len = MIN(MLEN, iov->iov_len);
34621767Skarels 				space -= len;
34716412Skarels 			}
34816412Skarels 			error = uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio);
34916412Skarels 			m->m_len = len;
35016412Skarels 			*mp = m;
35116412Skarels 			if (error)
35216412Skarels 				goto release;
35316412Skarels 			mp = &m->m_next;
35421108Skarels 			if (uio->uio_resid <= 0)
35521108Skarels 				break;
35621108Skarels 			while (uio->uio_iov->iov_len == 0) {
35721108Skarels 				uio->uio_iov++;
35821108Skarels 				uio->uio_iovcnt--;
35921108Skarels 				if (uio->uio_iovcnt <= 0)
36021108Skarels 					panic("sosend");
36121108Skarels 			}
36216412Skarels 		}
36321108Skarels 		if (dontroute)
36421108Skarels 			so->so_options |= SO_DONTROUTE;
36521108Skarels 		s = splnet();					/* XXX */
36621108Skarels 		error = (*so->so_proto->pr_usrreq)(so,
36721108Skarels 		    (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
36821108Skarels 		    top, (caddr_t)nam, rights);
36921108Skarels 		splx(s);
37021108Skarels 		if (dontroute)
37121108Skarels 			so->so_options &= ~SO_DONTROUTE;
37221767Skarels 		rights = 0;
3736419Sroot 		top = 0;
37416412Skarels 		first = 0;
37514781Ssam 		if (error)
37616412Skarels 			break;
37716412Skarels 	} while (uio->uio_resid);
3784890Swnj 
3794786Swnj release:
3804890Swnj 	sbunlock(&so->so_snd);
3816419Sroot 	if (top)
3826419Sroot 		m_freem(top);
38321108Skarels 	if (error == EPIPE)
38421108Skarels 		psignal(u.u_procp, SIGPIPE);
3854786Swnj 	return (error);
3864786Swnj }
3874786Swnj 
38812757Ssam soreceive(so, aname, uio, flags, rightsp)
3894786Swnj 	register struct socket *so;
3908300Sroot 	struct mbuf **aname;
39112757Ssam 	register struct uio *uio;
3928319Sroot 	int flags;
39312757Ssam 	struct mbuf **rightsp;
3944786Swnj {
3954786Swnj 	register struct mbuf *m, *n;
39616993Skarels 	register int len, error = 0, s, tomark;
39712757Ssam 	struct protosw *pr = so->so_proto;
39816993Skarels 	struct mbuf *nextrecord;
39912757Ssam 	int moff;
4004786Swnj 
40112757Ssam 	if (rightsp)
40212757Ssam 		*rightsp = 0;
40312757Ssam 	if (aname)
40412757Ssam 		*aname = 0;
40512757Ssam 	if (flags & MSG_OOB) {
4069635Ssam 		m = m_get(M_WAIT, MT_DATA);
40712757Ssam 		error = (*pr->pr_usrreq)(so, PRU_RCVOOB,
40812757Ssam 		    m, (struct mbuf *)0, (struct mbuf *)0);
4098594Sroot 		if (error)
41010137Ssam 			goto bad;
4118319Sroot 		do {
41210137Ssam 			len = uio->uio_resid;
4138319Sroot 			if (len > m->m_len)
4148319Sroot 				len = m->m_len;
4158594Sroot 			error =
4168793Sroot 			    uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio);
4178319Sroot 			m = m_free(m);
4188594Sroot 		} while (uio->uio_resid && error == 0 && m);
41910137Ssam bad:
4208319Sroot 		if (m)
4218771Sroot 			m_freem(m);
4228594Sroot 		return (error);
4238319Sroot 	}
4248319Sroot 
4254890Swnj restart:
4264890Swnj 	sblock(&so->so_rcv);
4278835Sroot 	s = splnet();
4284890Swnj 
4294890Swnj #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
4304786Swnj 	if (so->so_rcv.sb_cc == 0) {
4315168Swnj 		if (so->so_error) {
4325168Swnj 			error = so->so_error;
4335168Swnj 			so->so_error = 0;
4345168Swnj 			splx(s);
4355168Swnj 			goto release;
4365168Swnj 		}
4374890Swnj 		if (so->so_state & SS_CANTRCVMORE) {
4384890Swnj 			splx(s);
4394890Swnj 			goto release;
4404890Swnj 		}
4415015Sroot 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
4425015Sroot 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
4435015Sroot 			rcverr(ENOTCONN);
4446214Swnj 		if (so->so_state & SS_NBIO)
4455168Swnj 			rcverr(EWOULDBLOCK);
4464890Swnj 		sbunlock(&so->so_rcv);
4474971Swnj 		sbwait(&so->so_rcv);
4485012Swnj 		splx(s);
4494890Swnj 		goto restart;
4504786Swnj 	}
4518041Sroot 	u.u_ru.ru_msgrcv++;
4524829Swnj 	m = so->so_rcv.sb_mb;
45312757Ssam 	if (pr->pr_flags & PR_ADDR) {
45416993Skarels 		if (m == 0 || m->m_type != MT_SONAME)
45516993Skarels 			panic("receive 1a");
45616993Skarels 		if (flags & MSG_PEEK) {
45716993Skarels 			if (aname)
4588319Sroot 				*aname = m_copy(m, 0, m->m_len);
45916993Skarels 			else
46016993Skarels 				m = m->m_act;
46116993Skarels 		} else {
46216993Skarels 			if (aname) {
46316993Skarels 				*aname = m;
46416993Skarels 				sbfree(&so->so_rcv, m);
46516993Skarels if(m->m_next) panic("receive 1b");
46616993Skarels 				so->so_rcv.sb_mb = m = m->m_act;
46710137Ssam 			} else
46816993Skarels 				m = sbdroprecord(&so->so_rcv);
46916993Skarels 		}
47016993Skarels 	}
47116993Skarels 	if (m && m->m_type == MT_RIGHTS) {
47216993Skarels 		if ((pr->pr_flags & PR_RIGHTS) == 0)
47312757Ssam 			panic("receive 2a");
47416993Skarels 		if (flags & MSG_PEEK) {
47516993Skarels 			if (rightsp)
47612757Ssam 				*rightsp = m_copy(m, 0, m->m_len);
47716993Skarels 			else
47816993Skarels 				m = m->m_act;
47916993Skarels 		} else {
48016993Skarels 			if (rightsp) {
48116993Skarels 				*rightsp = m;
48216993Skarels 				sbfree(&so->so_rcv, m);
48316993Skarels if(m->m_next) panic("receive 2b");
48416993Skarels 				so->so_rcv.sb_mb = m = m->m_act;
48516993Skarels 			} else
48616993Skarels 				m = sbdroprecord(&so->so_rcv);
48712757Ssam 		}
4884890Swnj 	}
489*21783Skarels 	if (m == 0 || (m->m_type != MT_DATA && m->m_type != MT_HEADER))
49016993Skarels 		panic("receive 3");
4918319Sroot 	moff = 0;
4928319Sroot 	tomark = so->so_oobmark;
49316993Skarels 	while (m && uio->uio_resid > 0 && error == 0) {
4947827Sroot 		len = uio->uio_resid;
4957747Sroot 		so->so_state &= ~SS_RCVATMARK;
4968319Sroot 		if (tomark && len > tomark)
4978319Sroot 			len = tomark;
49821767Skarels 		if (len > m->m_len - moff)
4998319Sroot 			len = m->m_len - moff;
5004786Swnj 		splx(s);
5018594Sroot 		error =
5028793Sroot 		    uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio);
5034786Swnj 		s = splnet();
50421767Skarels 		if (len == m->m_len - moff) {
50516993Skarels 			if ((flags & MSG_PEEK) == 0) {
50616993Skarels 				nextrecord = m->m_act;
5078319Sroot 				sbfree(&so->so_rcv, m);
5088319Sroot 				MFREE(m, n);
50916993Skarels 				if (m = n)
51016993Skarels 					m->m_act = nextrecord;
5118548Sroot 				so->so_rcv.sb_mb = m;
51216993Skarels 			} else
51316993Skarels 				m = m->m_next;
5148319Sroot 			moff = 0;
5154786Swnj 		} else {
51612757Ssam 			if (flags & MSG_PEEK)
5178319Sroot 				moff += len;
5188319Sroot 			else {
5198319Sroot 				m->m_off += len;
5208319Sroot 				m->m_len -= len;
5218319Sroot 				so->so_rcv.sb_cc -= len;
5228319Sroot 			}
5234786Swnj 		}
52412757Ssam 		if ((flags & MSG_PEEK) == 0 && so->so_oobmark) {
5257747Sroot 			so->so_oobmark -= len;
5267747Sroot 			if (so->so_oobmark == 0) {
5277747Sroot 				so->so_state |= SS_RCVATMARK;
5287747Sroot 				break;
5297747Sroot 			}
5307747Sroot 		}
5318319Sroot 		if (tomark) {
5328319Sroot 			tomark -= len;
5338319Sroot 			if (tomark == 0)
5348319Sroot 				break;
5358319Sroot 		}
53616993Skarels 	}
53716993Skarels 	if ((flags & MSG_PEEK) == 0) {
53816993Skarels 		if (m == 0)
53916993Skarels 			so->so_rcv.sb_mb = nextrecord;
54016993Skarels 		else if (pr->pr_flags & PR_ATOMIC)
54116993Skarels 			(void) sbdroprecord(&so->so_rcv);
54216993Skarels 		if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
54316993Skarels 			(*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
54416993Skarels 			    (struct mbuf *)0, (struct mbuf *)0);
54516993Skarels 	}
5464890Swnj release:
5474916Swnj 	sbunlock(&so->so_rcv);
54816993Skarels 	if (error == 0 && rightsp && *rightsp && pr->pr_domain->dom_externalize)
54916993Skarels 		error = (*pr->pr_domain->dom_externalize)(*rightsp);
5504890Swnj 	splx(s);
5514916Swnj 	return (error);
5524786Swnj }
5534786Swnj 
55410267Ssam soshutdown(so, how)
55512757Ssam 	register struct socket *so;
55612757Ssam 	register int how;
55710267Ssam {
55812757Ssam 	register struct protosw *pr = so->so_proto;
55910267Ssam 
56010267Ssam 	how++;
56112757Ssam 	if (how & FREAD)
56212757Ssam 		sorflush(so);
56310267Ssam 	if (how & FWRITE)
56412757Ssam 		return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN,
56512757Ssam 		    (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
56610267Ssam 	return (0);
56710267Ssam }
56810267Ssam 
56912757Ssam sorflush(so)
57012757Ssam 	register struct socket *so;
57112757Ssam {
57212757Ssam 	register struct sockbuf *sb = &so->so_rcv;
57312757Ssam 	register struct protosw *pr = so->so_proto;
57412757Ssam 	register int s;
57512757Ssam 	struct sockbuf asb;
57612757Ssam 
57712757Ssam 	sblock(sb);
57812757Ssam 	s = splimp();
57912757Ssam 	socantrcvmore(so);
58012757Ssam 	sbunlock(sb);
58112757Ssam 	asb = *sb;
58212757Ssam 	bzero((caddr_t)sb, sizeof (*sb));
58312757Ssam 	splx(s);
58416993Skarels 	if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose)
58516993Skarels 		(*pr->pr_domain->dom_dispose)(asb.sb_mb);
58612757Ssam 	sbrelease(&asb);
58712757Ssam }
58812757Ssam 
58918553Skarels sosetopt(so, level, optname, m0)
59012757Ssam 	register struct socket *so;
59110267Ssam 	int level, optname;
59218553Skarels 	struct mbuf *m0;
59310267Ssam {
59417158Ssam 	int error = 0;
59518553Skarels 	register struct mbuf *m = m0;
59610267Ssam 
59717158Ssam 	if (level != SOL_SOCKET) {
59818369Skarels 		if (so->so_proto && so->so_proto->pr_ctloutput)
59918369Skarels 			return ((*so->so_proto->pr_ctloutput)
60018553Skarels 				  (PRCO_SETOPT, so, level, optname, &m0));
60118369Skarels 		error = ENOPROTOOPT;
60218369Skarels 	} else {
60318369Skarels 		switch (optname) {
60410267Ssam 
60518369Skarels 		case SO_LINGER:
60618369Skarels 			if (m == NULL || m->m_len != sizeof (struct linger)) {
60718369Skarels 				error = EINVAL;
60818369Skarels 				goto bad;
60918369Skarels 			}
61018369Skarels 			so->so_linger = mtod(m, struct linger *)->l_linger;
61118369Skarels 			/* fall thru... */
61217158Ssam 
61318369Skarels 		case SO_DEBUG:
61418369Skarels 		case SO_KEEPALIVE:
61518369Skarels 		case SO_DONTROUTE:
61618369Skarels 		case SO_USELOOPBACK:
61718369Skarels 		case SO_BROADCAST:
61818369Skarels 		case SO_REUSEADDR:
61918369Skarels 			if (m == NULL || m->m_len < sizeof (int)) {
62018369Skarels 				error = EINVAL;
62118369Skarels 				goto bad;
62218369Skarels 			}
62318369Skarels 			if (*mtod(m, int *))
62418369Skarels 				so->so_options |= optname;
62518369Skarels 			else
62618369Skarels 				so->so_options &= ~optname;
62718369Skarels 			break;
62818369Skarels 
62918369Skarels 		case SO_SNDBUF:
63018369Skarels 		case SO_RCVBUF:
63118369Skarels 		case SO_SNDLOWAT:
63218369Skarels 		case SO_RCVLOWAT:
63318369Skarels 		case SO_SNDTIMEO:
63418369Skarels 		case SO_RCVTIMEO:
63518369Skarels 			if (m == NULL || m->m_len < sizeof (int)) {
63618369Skarels 				error = EINVAL;
63718369Skarels 				goto bad;
63818369Skarels 			}
63918369Skarels 			switch (optname) {
64018369Skarels 
64118369Skarels 			case SO_SNDBUF:
64218369Skarels 			case SO_RCVBUF:
64318369Skarels 				if (sbreserve(optname == SO_SNDBUF ? &so->so_snd :
64418369Skarels 				    &so->so_rcv, *mtod(m, int *)) == 0) {
64518369Skarels 					error = ENOBUFS;
64618369Skarels 					goto bad;
64718369Skarels 				}
64818369Skarels 				break;
64918369Skarels 
65018369Skarels 			case SO_SNDLOWAT:
65118369Skarels 				so->so_snd.sb_lowat = *mtod(m, int *);
65218369Skarels 				break;
65318369Skarels 			case SO_RCVLOWAT:
65418369Skarels 				so->so_rcv.sb_lowat = *mtod(m, int *);
65518369Skarels 				break;
65618369Skarels 			case SO_SNDTIMEO:
65718369Skarels 				so->so_snd.sb_timeo = *mtod(m, int *);
65818369Skarels 				break;
65918369Skarels 			case SO_RCVTIMEO:
66018369Skarels 				so->so_rcv.sb_timeo = *mtod(m, int *);
66118369Skarels 				break;
66218369Skarels 			}
66318369Skarels 			break;
66418369Skarels 
66518369Skarels 		default:
66618369Skarels 			error = ENOPROTOOPT;
66718369Skarels 			break;
66817158Ssam 		}
66910267Ssam 	}
67017158Ssam bad:
67117158Ssam 	if (m)
67217158Ssam 		(void) m_free(m);
67317158Ssam 	return (error);
67410267Ssam }
67510267Ssam 
67617158Ssam sogetopt(so, level, optname, mp)
67712757Ssam 	register struct socket *so;
67810267Ssam 	int level, optname;
67917158Ssam 	struct mbuf **mp;
68017158Ssam {
68112757Ssam 	register struct mbuf *m;
68210267Ssam 
68318369Skarels 	if (level != SOL_SOCKET) {
68418369Skarels 		if (so->so_proto && so->so_proto->pr_ctloutput) {
68518369Skarels 			return ((*so->so_proto->pr_ctloutput)
68618369Skarels 				  (PRCO_GETOPT, so, level, optname, mp));
68718369Skarels 		} else
68818369Skarels 			return (ENOPROTOOPT);
68918369Skarels 	} else {
69017158Ssam 		m = m_get(M_WAIT, MT_SOOPTS);
69118369Skarels 		switch (optname) {
69217158Ssam 
69318369Skarels 		case SO_LINGER:
69418369Skarels 			m->m_len = sizeof (struct linger);
69518369Skarels 			mtod(m, struct linger *)->l_onoff =
69618369Skarels 				so->so_options & SO_LINGER;
69718369Skarels 			mtod(m, struct linger *)->l_linger = so->so_linger;
69818369Skarels 			break;
69910267Ssam 
70018369Skarels 		case SO_USELOOPBACK:
70118369Skarels 		case SO_DONTROUTE:
70218369Skarels 		case SO_DEBUG:
70318369Skarels 		case SO_KEEPALIVE:
70418369Skarels 		case SO_REUSEADDR:
70518369Skarels 		case SO_BROADCAST:
70618369Skarels 			m->m_len = sizeof (int);
70718369Skarels 			*mtod(m, int *) = so->so_options & optname;
70818369Skarels 			break;
70918369Skarels 
71018369Skarels 		case SO_SNDBUF:
71118369Skarels 			*mtod(m, int *) = so->so_snd.sb_hiwat;
71218369Skarels 			break;
71318369Skarels 
71418369Skarels 		case SO_RCVBUF:
71518369Skarels 			*mtod(m, int *) = so->so_rcv.sb_hiwat;
71618369Skarels 			break;
71718369Skarels 
71818369Skarels 		case SO_SNDLOWAT:
71918369Skarels 			*mtod(m, int *) = so->so_snd.sb_lowat;
72018369Skarels 			break;
72118369Skarels 
72218369Skarels 		case SO_RCVLOWAT:
72318369Skarels 			*mtod(m, int *) = so->so_rcv.sb_lowat;
72418369Skarels 			break;
72518369Skarels 
72618369Skarels 		case SO_SNDTIMEO:
72718369Skarels 			*mtod(m, int *) = so->so_snd.sb_timeo;
72818369Skarels 			break;
72918369Skarels 
73018369Skarels 		case SO_RCVTIMEO:
73118369Skarels 			*mtod(m, int *) = so->so_rcv.sb_timeo;
73218369Skarels 			break;
73318369Skarels 
73418369Skarels 		default:
73518369Skarels 			m_free(m);
73618369Skarels 			return (ENOPROTOOPT);
73718369Skarels 		}
73818369Skarels 		*mp = m;
73918369Skarels 		return (0);
74010267Ssam 	}
74110267Ssam }
74210267Ssam 
7435423Swnj sohasoutofband(so)
74412757Ssam 	register struct socket *so;
7455423Swnj {
7465423Swnj 
7475423Swnj 	if (so->so_pgrp == 0)
7485423Swnj 		return;
7495423Swnj 	if (so->so_pgrp > 0)
7505423Swnj 		gsignal(so->so_pgrp, SIGURG);
7515429Swnj 	else {
7525429Swnj 		struct proc *p = pfind(-so->so_pgrp);
7535429Swnj 
7545429Swnj 		if (p)
7555429Swnj 			psignal(p, SIGURG);
7565429Swnj 	}
7575423Swnj }
758