xref: /csrg-svn/sys/kern/uipc_socket.c (revision 18369)
1*18369Skarels /*	uipc_socket.c	6.9	85/03/18	*/
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  *	sostat
3312757Ssam  *	test socketpair
3412757Ssam  *	PR_RIGHTS
3512757Ssam  *	clean up select, async
3612757Ssam  *	out-of-band is a kludge
374786Swnj  */
388594Sroot /*ARGSUSED*/
3910267Ssam socreate(dom, aso, type, proto)
404786Swnj 	struct socket **aso;
4112757Ssam 	register int type;
4212757Ssam 	int proto;
434786Swnj {
444786Swnj 	register struct protosw *prp;
454786Swnj 	register struct socket *so;
4612757Ssam 	register struct mbuf *m;
4712757Ssam 	register int error;
484786Swnj 
494890Swnj 	if (proto)
509168Ssam 		prp = pffindproto(dom, proto);
514890Swnj 	else
529168Ssam 		prp = pffindtype(dom, type);
534890Swnj 	if (prp == 0)
544890Swnj 		return (EPROTONOSUPPORT);
558300Sroot 	if (prp->pr_type != type)
568300Sroot 		return (EPROTOTYPE);
579635Ssam 	m = m_getclr(M_WAIT, MT_SOCKET);
584786Swnj 	if (m == 0)
594786Swnj 		return (ENOBUFS);
604786Swnj 	so = mtod(m, struct socket *);
6112757Ssam 	so->so_options = 0;
626214Swnj 	so->so_state = 0;
639168Ssam 	so->so_type = type;
646214Swnj 	if (u.u_uid == 0)
656214Swnj 		so->so_state = SS_PRIV;
664786Swnj 	so->so_proto = prp;
6712757Ssam 	error =
6812757Ssam 	    (*prp->pr_usrreq)(so, PRU_ATTACH,
6912757Ssam 		(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
704979Swnj 	if (error) {
717507Sroot 		so->so_state |= SS_NOFDREF;
727180Swnj 		sofree(so);
734890Swnj 		return (error);
744786Swnj 	}
754786Swnj 	*aso = so;
764786Swnj 	return (0);
774786Swnj }
784786Swnj 
7910267Ssam sobind(so, nam)
808300Sroot 	struct socket *so;
818300Sroot 	struct mbuf *nam;
828300Sroot {
838300Sroot 	int s = splnet();
848300Sroot 	int error;
858300Sroot 
868300Sroot 	error =
8712757Ssam 	    (*so->so_proto->pr_usrreq)(so, PRU_BIND,
8812757Ssam 		(struct mbuf *)0, nam, (struct mbuf *)0);
898300Sroot 	splx(s);
908300Sroot 	return (error);
918300Sroot }
928300Sroot 
938300Sroot solisten(so, backlog)
9412757Ssam 	register struct socket *so;
958300Sroot 	int backlog;
968300Sroot {
9712757Ssam 	int s = splnet(), error;
988300Sroot 
9912757Ssam 	error =
10012757Ssam 	    (*so->so_proto->pr_usrreq)(so, PRU_LISTEN,
10112757Ssam 		(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
1028300Sroot 	if (error) {
1038300Sroot 		splx(s);
1048300Sroot 		return (error);
1058300Sroot 	}
1068300Sroot 	if (so->so_q == 0) {
1078300Sroot 		so->so_q = so;
1088300Sroot 		so->so_q0 = so;
1098300Sroot 		so->so_options |= SO_ACCEPTCONN;
1108300Sroot 	}
1118300Sroot 	if (backlog < 0)
1128300Sroot 		backlog = 0;
11310137Ssam 	so->so_qlimit = MIN(backlog, SOMAXCONN);
11412493Ssam 	splx(s);
1158300Sroot 	return (0);
1168300Sroot }
1178300Sroot 
1184916Swnj sofree(so)
11912757Ssam 	register struct socket *so;
1204916Swnj {
1214916Swnj 
1227507Sroot 	if (so->so_head) {
1237507Sroot 		if (!soqremque(so, 0) && !soqremque(so, 1))
1247507Sroot 			panic("sofree dq");
1257507Sroot 		so->so_head = 0;
1267507Sroot 	}
1277507Sroot 	if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
1284950Swnj 		return;
1294950Swnj 	sbrelease(&so->so_snd);
13012757Ssam 	sorflush(so);
1314971Swnj 	(void) m_free(dtom(so));
1324916Swnj }
1334916Swnj 
1344786Swnj /*
1354890Swnj  * Close a socket on last file table reference removal.
1364890Swnj  * Initiate disconnect if connected.
1374890Swnj  * Free socket when disconnect complete.
1384829Swnj  */
13912757Ssam soclose(so)
1404829Swnj 	register struct socket *so;
1414829Swnj {
1424890Swnj 	int s = splnet();		/* conservative */
1438713Sroot 	int error;
1444829Swnj 
1457507Sroot 	if (so->so_options & SO_ACCEPTCONN) {
1467507Sroot 		while (so->so_q0 != so)
14710399Ssam 			(void) soabort(so->so_q0);
1487507Sroot 		while (so->so_q != so)
14910399Ssam 			(void) soabort(so->so_q);
1507507Sroot 	}
1514890Swnj 	if (so->so_pcb == 0)
1524890Swnj 		goto discard;
1534890Swnj 	if (so->so_state & SS_ISCONNECTED) {
1544890Swnj 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
1558725Sroot 			error = sodisconnect(so, (struct mbuf *)0);
15612757Ssam 			if (error)
15712757Ssam 				goto drop;
1584890Swnj 		}
15910267Ssam 		if (so->so_options & SO_LINGER) {
1605281Sroot 			if ((so->so_state & SS_ISDISCONNECTING) &&
16112757Ssam 			    (so->so_state & SS_NBIO))
16212757Ssam 				goto drop;
1635281Sroot 			while (so->so_state & SS_ISCONNECTED)
1645281Sroot 				sleep((caddr_t)&so->so_timeo, PZERO+1);
1654890Swnj 		}
1664890Swnj 	}
1675580Sroot drop:
1686880Ssam 	if (so->so_pcb) {
16912757Ssam 		int error2 =
17012757Ssam 		    (*so->so_proto->pr_usrreq)(so, PRU_DETACH,
17112757Ssam 			(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
17212757Ssam 		if (error == 0)
17312757Ssam 			error = error2;
1746880Ssam 	}
1754890Swnj discard:
17610399Ssam 	if (so->so_state & SS_NOFDREF)
17710399Ssam 		panic("soclose: NOFDREF");
1787507Sroot 	so->so_state |= SS_NOFDREF;
1794950Swnj 	sofree(so);
1804890Swnj 	splx(s);
18112757Ssam 	return (error);
1824829Swnj }
1834829Swnj 
18410399Ssam /*
18510399Ssam  * Must be called at splnet...
18610399Ssam  */
18710399Ssam soabort(so)
18810399Ssam 	struct socket *so;
18910399Ssam {
19010399Ssam 
19112757Ssam 	return (
19212757Ssam 	    (*so->so_proto->pr_usrreq)(so, PRU_ABORT,
19312757Ssam 		(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
19410399Ssam }
19510399Ssam 
19610267Ssam soaccept(so, nam)
19712757Ssam 	register struct socket *so;
1988300Sroot 	struct mbuf *nam;
1994927Swnj {
2004927Swnj 	int s = splnet();
2014927Swnj 	int error;
2024927Swnj 
20310399Ssam 	if ((so->so_state & SS_NOFDREF) == 0)
20410399Ssam 		panic("soaccept: !NOFDREF");
20510267Ssam 	so->so_state &= ~SS_NOFDREF;
2068300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT,
20712757Ssam 	    (struct mbuf *)0, nam, (struct mbuf *)0);
2084927Swnj 	splx(s);
2094927Swnj 	return (error);
2104927Swnj }
2114927Swnj 
21210267Ssam soconnect(so, nam)
21312757Ssam 	register struct socket *so;
2148300Sroot 	struct mbuf *nam;
2154786Swnj {
2164890Swnj 	int s = splnet();
2174890Swnj 	int error;
2184786Swnj 
2194890Swnj 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
2204890Swnj 		error = EISCONN;
2214890Swnj 		goto bad;
2224890Swnj 	}
2238300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
22412757Ssam 	    (struct mbuf *)0, nam, (struct mbuf *)0);
2254890Swnj bad:
2264890Swnj 	splx(s);
2274890Swnj 	return (error);
2284786Swnj }
2294786Swnj 
23012757Ssam soconnect2(so1, so2)
23112757Ssam 	register struct socket *so1;
23212757Ssam 	struct socket *so2;
23312757Ssam {
23412757Ssam 	int s = splnet();
23512757Ssam 	int error;
23612757Ssam 
23713113Ssam 	error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2,
23813113Ssam 	    (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0);
23912757Ssam 	splx(s);
24012757Ssam 	return (error);
24112757Ssam }
24212757Ssam 
2438300Sroot sodisconnect(so, nam)
24412757Ssam 	register struct socket *so;
2458300Sroot 	struct mbuf *nam;
2464786Swnj {
2474890Swnj 	int s = splnet();
2484890Swnj 	int error;
2494786Swnj 
2504890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2514890Swnj 		error = ENOTCONN;
2524890Swnj 		goto bad;
2534890Swnj 	}
2544890Swnj 	if (so->so_state & SS_ISDISCONNECTING) {
2554890Swnj 		error = EALREADY;
2564890Swnj 		goto bad;
2574890Swnj 	}
2588300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT,
25912757Ssam 	    (struct mbuf *)0, nam, (struct mbuf *)0);
2604890Swnj bad:
2614890Swnj 	splx(s);
2624890Swnj 	return (error);
2634786Swnj }
2644786Swnj 
2654786Swnj /*
2664890Swnj  * Send on a socket.
2674890Swnj  * If send must go all at once and message is larger than
2684890Swnj  * send buffering, then hard error.
2694890Swnj  * Lock against other senders.
2704890Swnj  * If must go all at once and not enough room now, then
2714890Swnj  * inform user that this would block and do nothing.
27216412Skarels  * Otherwise, if nonblocking, send as much as possible.
2734786Swnj  */
27412757Ssam sosend(so, nam, uio, flags, rights)
2754786Swnj 	register struct socket *so;
2768300Sroot 	struct mbuf *nam;
27712757Ssam 	register struct uio *uio;
2788319Sroot 	int flags;
27912757Ssam 	struct mbuf *rights;
2804786Swnj {
2814890Swnj 	struct mbuf *top = 0;
28216412Skarels 	register struct mbuf *m, **mp;
28312757Ssam 	register int space;
28416412Skarels 	int len, error = 0, s, dontroute, first = 1;
2854786Swnj 
2867827Sroot 	if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat)
2874890Swnj 		return (EMSGSIZE);
28812757Ssam 	dontroute =
28912757Ssam 	    (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
29012757Ssam 	    (so->so_proto->pr_flags & PR_ATOMIC);
29116412Skarels 	u.u_ru.ru_msgsnd++;
29216412Skarels #define	snderr(errno)	{ error = errno; splx(s); goto release; }
29316412Skarels 
2946419Sroot restart:
2954890Swnj 	sblock(&so->so_snd);
29616412Skarels 	do {
29716412Skarels 		s = splnet();
29816412Skarels 		if (so->so_state & SS_CANTSENDMORE) {
29916412Skarels 			psignal(u.u_procp, SIGPIPE);
30016412Skarels 			snderr(EPIPE);
30116412Skarels 		}
30216412Skarels 		if (so->so_error) {
30316412Skarels 			error = so->so_error;
30416412Skarels 			so->so_error = 0;			/* ??? */
30516412Skarels 			splx(s);
30616412Skarels 			goto release;
30716412Skarels 		}
30816412Skarels 		if ((so->so_state & SS_ISCONNECTED) == 0) {
30916412Skarels 			if (so->so_proto->pr_flags & PR_CONNREQUIRED)
31016412Skarels 				snderr(ENOTCONN);
31116412Skarels 			if (nam == 0)
31216412Skarels 				snderr(EDESTADDRREQ);
31316412Skarels 		}
31416412Skarels 		if (flags & MSG_OOB)
31516412Skarels 			space = 1024;
31616412Skarels 		else {
31716412Skarels 			space = sbspace(&so->so_snd);
31816412Skarels 			if (space <= 0 ||
31916992Skarels 			   (sosendallatonce(so) && space < uio->uio_resid) ||
32016992Skarels 			   (uio->uio_resid >= CLBYTES && space < CLBYTES &&
32116992Skarels 			   so->so_snd.sb_cc >= CLBYTES &&
32216992Skarels 			   (so->so_state & SS_NBIO) == 0)) {
32316412Skarels 				if (so->so_state & SS_NBIO) {
32416412Skarels 					if (first)
32516412Skarels 						error = EWOULDBLOCK;
32616412Skarels 					splx(s);
32716412Skarels 					goto release;
32816412Skarels 				}
32916412Skarels 				sbunlock(&so->so_snd);
33016412Skarels 				sbwait(&so->so_snd);
33116412Skarels 				splx(s);
33216412Skarels 				goto restart;
33316412Skarels 			}
33416412Skarels 		}
33516412Skarels 		splx(s);
33616412Skarels 		mp = &top;
33716412Skarels 		while (uio->uio_resid > 0 && space > 0) {
33816412Skarels 			register struct iovec *iov = uio->uio_iov;
3394890Swnj 
34016412Skarels 			if (iov->iov_len == 0) {
34116412Skarels 				uio->uio_iov++;
34216412Skarels 				uio->uio_iovcnt--;
34316412Skarels 				if (uio->uio_iovcnt < 0)
34416412Skarels 					panic("sosend");
34516412Skarels 				continue;
34616412Skarels 			}
34716412Skarels 			MGET(m, M_WAIT, MT_DATA);
348*18369Skarels if (m == NULL) {
349*18369Skarels 	error = ENOBUFS;		/* SIGPIPE? */
350*18369Skarels 	goto release;
351*18369Skarels }
35216412Skarels 			if (iov->iov_len >= CLBYTES && space >= CLBYTES) {
35316412Skarels 				register struct mbuf *p;
35416412Skarels 				MCLGET(p, 1);
35516412Skarels 				if (p == 0)
35616412Skarels 					goto nopages;
35716412Skarels 				m->m_off = (int)p - (int)m;
35816412Skarels 				len = CLBYTES;
35916412Skarels 			} else {
36016412Skarels nopages:
36116412Skarels 				len = MIN(MLEN, iov->iov_len);
36216412Skarels 			}
36316412Skarels 			error = uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio);
36416412Skarels 			m->m_len = len;
36516412Skarels 			*mp = m;
36616412Skarels 			if (error)
36716412Skarels 				goto release;
36816412Skarels 			mp = &m->m_next;
36916412Skarels 			space -= len;
37016412Skarels 		}
37116992Skarels 		if (top) {
37216992Skarels 			if (dontroute)
37316992Skarels 				so->so_options |= SO_DONTROUTE;
37416992Skarels 			s = splnet();
37516992Skarels 			error = (*so->so_proto->pr_usrreq)(so,
37616992Skarels 			    (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
37716992Skarels 			    top, (caddr_t)nam, rights);
37816992Skarels 			splx(s);
37916992Skarels 			if (dontroute)
38016992Skarels 				so->so_options &= ~SO_DONTROUTE;
38116992Skarels 		}
3826419Sroot 		top = 0;
38316412Skarels 		first = 0;
38414781Ssam 		if (error)
38516412Skarels 			break;
38616412Skarels 	} while (uio->uio_resid);
3874890Swnj 
3884786Swnj release:
3894890Swnj 	sbunlock(&so->so_snd);
3906419Sroot 	if (top)
3916419Sroot 		m_freem(top);
3924786Swnj 	return (error);
3934786Swnj }
3944786Swnj 
39512757Ssam soreceive(so, aname, uio, flags, rightsp)
3964786Swnj 	register struct socket *so;
3978300Sroot 	struct mbuf **aname;
39812757Ssam 	register struct uio *uio;
3998319Sroot 	int flags;
40012757Ssam 	struct mbuf **rightsp;
4014786Swnj {
4024786Swnj 	register struct mbuf *m, *n;
40316993Skarels 	register int len, error = 0, s, tomark;
40412757Ssam 	struct protosw *pr = so->so_proto;
40516993Skarels 	struct mbuf *nextrecord;
40612757Ssam 	int moff;
4074786Swnj 
40812757Ssam 	if (rightsp)
40912757Ssam 		*rightsp = 0;
41012757Ssam 	if (aname)
41112757Ssam 		*aname = 0;
41212757Ssam 	if (flags & MSG_OOB) {
4139635Ssam 		m = m_get(M_WAIT, MT_DATA);
41412757Ssam 		if (m == 0)
41510137Ssam 			return (ENOBUFS);
41612757Ssam 		error = (*pr->pr_usrreq)(so, PRU_RCVOOB,
41712757Ssam 		    m, (struct mbuf *)0, (struct mbuf *)0);
4188594Sroot 		if (error)
41910137Ssam 			goto bad;
4208319Sroot 		do {
42110137Ssam 			len = uio->uio_resid;
4228319Sroot 			if (len > m->m_len)
4238319Sroot 				len = m->m_len;
4248594Sroot 			error =
4258793Sroot 			    uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio);
4268319Sroot 			m = m_free(m);
4278594Sroot 		} while (uio->uio_resid && error == 0 && m);
42810137Ssam bad:
4298319Sroot 		if (m)
4308771Sroot 			m_freem(m);
4318594Sroot 		return (error);
4328319Sroot 	}
4338319Sroot 
4344890Swnj restart:
4354890Swnj 	sblock(&so->so_rcv);
4368835Sroot 	s = splnet();
4374890Swnj 
4384890Swnj #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
4394786Swnj 	if (so->so_rcv.sb_cc == 0) {
4405168Swnj 		if (so->so_error) {
4415168Swnj 			error = so->so_error;
4425168Swnj 			so->so_error = 0;
4435168Swnj 			splx(s);
4445168Swnj 			goto release;
4455168Swnj 		}
4464890Swnj 		if (so->so_state & SS_CANTRCVMORE) {
4474890Swnj 			splx(s);
4484890Swnj 			goto release;
4494890Swnj 		}
4505015Sroot 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
4515015Sroot 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
4525015Sroot 			rcverr(ENOTCONN);
4536214Swnj 		if (so->so_state & SS_NBIO)
4545168Swnj 			rcverr(EWOULDBLOCK);
4554890Swnj 		sbunlock(&so->so_rcv);
4564971Swnj 		sbwait(&so->so_rcv);
4575012Swnj 		splx(s);
4584890Swnj 		goto restart;
4594786Swnj 	}
4608041Sroot 	u.u_ru.ru_msgrcv++;
4614829Swnj 	m = so->so_rcv.sb_mb;
46212757Ssam 	if (pr->pr_flags & PR_ADDR) {
46316993Skarels 		if (m == 0 || m->m_type != MT_SONAME)
46416993Skarels 			panic("receive 1a");
46516993Skarels 		if (flags & MSG_PEEK) {
46616993Skarels 			if (aname)
4678319Sroot 				*aname = m_copy(m, 0, m->m_len);
46816993Skarels 			else
46916993Skarels 				m = m->m_act;
47016993Skarels 		} else {
47116993Skarels 			if (aname) {
47216993Skarels 				*aname = m;
47316993Skarels 				sbfree(&so->so_rcv, m);
47416993Skarels if(m->m_next) panic("receive 1b");
47516993Skarels 				so->so_rcv.sb_mb = m = m->m_act;
47610137Ssam 			} else
47716993Skarels 				m = sbdroprecord(&so->so_rcv);
47816993Skarels 		}
47916993Skarels 	}
48016993Skarels 	if (m && m->m_type == MT_RIGHTS) {
48116993Skarels 		if ((pr->pr_flags & PR_RIGHTS) == 0)
48212757Ssam 			panic("receive 2a");
48316993Skarels 		if (flags & MSG_PEEK) {
48416993Skarels 			if (rightsp)
48512757Ssam 				*rightsp = m_copy(m, 0, m->m_len);
48616993Skarels 			else
48716993Skarels 				m = m->m_act;
48816993Skarels 		} else {
48916993Skarels 			if (rightsp) {
49016993Skarels 				*rightsp = m;
49116993Skarels 				sbfree(&so->so_rcv, m);
49216993Skarels if(m->m_next) panic("receive 2b");
49316993Skarels 				so->so_rcv.sb_mb = m = m->m_act;
49416993Skarels 			} else
49516993Skarels 				m = sbdroprecord(&so->so_rcv);
49612757Ssam 		}
4974890Swnj 	}
49816993Skarels 	if (m == 0)
49916993Skarels 		panic("receive 3");
5008319Sroot 	moff = 0;
5018319Sroot 	tomark = so->so_oobmark;
50216993Skarels 	while (m && uio->uio_resid > 0 && error == 0) {
5037827Sroot 		len = uio->uio_resid;
5047747Sroot 		so->so_state &= ~SS_RCVATMARK;
5058319Sroot 		if (tomark && len > tomark)
5068319Sroot 			len = tomark;
5078548Sroot 		if (moff+len > m->m_len - moff)
5088319Sroot 			len = m->m_len - moff;
5094786Swnj 		splx(s);
5108594Sroot 		error =
5118793Sroot 		    uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio);
5124786Swnj 		s = splnet();
5134786Swnj 		if (len == m->m_len) {
51416993Skarels 			if ((flags & MSG_PEEK) == 0) {
51516993Skarels 				nextrecord = m->m_act;
5168319Sroot 				sbfree(&so->so_rcv, m);
5178319Sroot 				MFREE(m, n);
51816993Skarels 				if (m = n)
51916993Skarels 					m->m_act = nextrecord;
5208548Sroot 				so->so_rcv.sb_mb = m;
52116993Skarels 			} else
52216993Skarels 				m = m->m_next;
5238319Sroot 			moff = 0;
5244786Swnj 		} else {
52512757Ssam 			if (flags & MSG_PEEK)
5268319Sroot 				moff += len;
5278319Sroot 			else {
5288319Sroot 				m->m_off += len;
5298319Sroot 				m->m_len -= len;
5308319Sroot 				so->so_rcv.sb_cc -= len;
5318319Sroot 			}
5324786Swnj 		}
53312757Ssam 		if ((flags & MSG_PEEK) == 0 && so->so_oobmark) {
5347747Sroot 			so->so_oobmark -= len;
5357747Sroot 			if (so->so_oobmark == 0) {
5367747Sroot 				so->so_state |= SS_RCVATMARK;
5377747Sroot 				break;
5387747Sroot 			}
5397747Sroot 		}
5408319Sroot 		if (tomark) {
5418319Sroot 			tomark -= len;
5428319Sroot 			if (tomark == 0)
5438319Sroot 				break;
5448319Sroot 		}
54516993Skarels 	}
54616993Skarels 	if ((flags & MSG_PEEK) == 0) {
54716993Skarels 		if (m == 0)
54816993Skarels 			so->so_rcv.sb_mb = nextrecord;
54916993Skarels 		else if (pr->pr_flags & PR_ATOMIC)
55016993Skarels 			(void) sbdroprecord(&so->so_rcv);
55116993Skarels 		if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
55216993Skarels 			(*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
55316993Skarels 			    (struct mbuf *)0, (struct mbuf *)0);
55416993Skarels 	}
5554890Swnj release:
5564916Swnj 	sbunlock(&so->so_rcv);
55716993Skarels 	if (error == 0 && rightsp && *rightsp && pr->pr_domain->dom_externalize)
55816993Skarels 		error = (*pr->pr_domain->dom_externalize)(*rightsp);
5594890Swnj 	splx(s);
5604916Swnj 	return (error);
5614786Swnj }
5624786Swnj 
56310267Ssam soshutdown(so, how)
56412757Ssam 	register struct socket *so;
56512757Ssam 	register int how;
56610267Ssam {
56712757Ssam 	register struct protosw *pr = so->so_proto;
56810267Ssam 
56910267Ssam 	how++;
57012757Ssam 	if (how & FREAD)
57112757Ssam 		sorflush(so);
57210267Ssam 	if (how & FWRITE)
57312757Ssam 		return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN,
57412757Ssam 		    (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
57510267Ssam 	return (0);
57610267Ssam }
57710267Ssam 
57812757Ssam sorflush(so)
57912757Ssam 	register struct socket *so;
58012757Ssam {
58112757Ssam 	register struct sockbuf *sb = &so->so_rcv;
58212757Ssam 	register struct protosw *pr = so->so_proto;
58312757Ssam 	register int s;
58412757Ssam 	struct sockbuf asb;
58512757Ssam 
58612757Ssam 	sblock(sb);
58712757Ssam 	s = splimp();
58812757Ssam 	socantrcvmore(so);
58912757Ssam 	sbunlock(sb);
59012757Ssam 	asb = *sb;
59112757Ssam 	bzero((caddr_t)sb, sizeof (*sb));
59212757Ssam 	splx(s);
59316993Skarels 	if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose)
59416993Skarels 		(*pr->pr_domain->dom_dispose)(asb.sb_mb);
59512757Ssam 	sbrelease(&asb);
59612757Ssam }
59712757Ssam 
59810267Ssam sosetopt(so, level, optname, m)
59912757Ssam 	register struct socket *so;
60010267Ssam 	int level, optname;
60112757Ssam 	register struct mbuf *m;
60210267Ssam {
60317158Ssam 	int error = 0;
60410267Ssam 
60517158Ssam 	if (level != SOL_SOCKET) {
606*18369Skarels 		if (so->so_proto && so->so_proto->pr_ctloutput)
607*18369Skarels 			return ((*so->so_proto->pr_ctloutput)
608*18369Skarels 				  (PRCO_SETOPT, so, level, optname, m));
609*18369Skarels 		error = ENOPROTOOPT;
610*18369Skarels 	} else {
611*18369Skarels 		switch (optname) {
61210267Ssam 
613*18369Skarels 		case SO_LINGER:
614*18369Skarels 			if (m == NULL || m->m_len != sizeof (struct linger)) {
615*18369Skarels 				error = EINVAL;
616*18369Skarels 				goto bad;
617*18369Skarels 			}
618*18369Skarels 			so->so_linger = mtod(m, struct linger *)->l_linger;
619*18369Skarels 			/* fall thru... */
62017158Ssam 
621*18369Skarels 		case SO_DEBUG:
622*18369Skarels 		case SO_KEEPALIVE:
623*18369Skarels 		case SO_DONTROUTE:
624*18369Skarels 		case SO_USELOOPBACK:
625*18369Skarels 		case SO_BROADCAST:
626*18369Skarels 		case SO_REUSEADDR:
627*18369Skarels 			if (m == NULL || m->m_len < sizeof (int)) {
628*18369Skarels 				error = EINVAL;
629*18369Skarels 				goto bad;
630*18369Skarels 			}
631*18369Skarels 			if (*mtod(m, int *))
632*18369Skarels 				so->so_options |= optname;
633*18369Skarels 			else
634*18369Skarels 				so->so_options &= ~optname;
635*18369Skarels 			break;
636*18369Skarels 
637*18369Skarels 		case SO_SNDBUF:
638*18369Skarels 		case SO_RCVBUF:
639*18369Skarels 		case SO_SNDLOWAT:
640*18369Skarels 		case SO_RCVLOWAT:
641*18369Skarels 		case SO_SNDTIMEO:
642*18369Skarels 		case SO_RCVTIMEO:
643*18369Skarels 			if (m == NULL || m->m_len < sizeof (int)) {
644*18369Skarels 				error = EINVAL;
645*18369Skarels 				goto bad;
646*18369Skarels 			}
647*18369Skarels 			switch (optname) {
648*18369Skarels 
649*18369Skarels 			case SO_SNDBUF:
650*18369Skarels 			case SO_RCVBUF:
651*18369Skarels 				if (sbreserve(optname == SO_SNDBUF ? &so->so_snd :
652*18369Skarels 				    &so->so_rcv, *mtod(m, int *)) == 0) {
653*18369Skarels 					error = ENOBUFS;
654*18369Skarels 					goto bad;
655*18369Skarels 				}
656*18369Skarels 				break;
657*18369Skarels 
658*18369Skarels 			case SO_SNDLOWAT:
659*18369Skarels 				so->so_snd.sb_lowat = *mtod(m, int *);
660*18369Skarels 				break;
661*18369Skarels 			case SO_RCVLOWAT:
662*18369Skarels 				so->so_rcv.sb_lowat = *mtod(m, int *);
663*18369Skarels 				break;
664*18369Skarels 			case SO_SNDTIMEO:
665*18369Skarels 				so->so_snd.sb_timeo = *mtod(m, int *);
666*18369Skarels 				break;
667*18369Skarels 			case SO_RCVTIMEO:
668*18369Skarels 				so->so_rcv.sb_timeo = *mtod(m, int *);
669*18369Skarels 				break;
670*18369Skarels 			}
671*18369Skarels 			break;
672*18369Skarels 
673*18369Skarels 		default:
674*18369Skarels 			error = ENOPROTOOPT;
675*18369Skarels 			break;
67617158Ssam 		}
67710267Ssam 	}
67817158Ssam bad:
67917158Ssam 	if (m)
68017158Ssam 		(void) m_free(m);
68117158Ssam 	return (error);
68210267Ssam }
68310267Ssam 
68417158Ssam sogetopt(so, level, optname, mp)
68512757Ssam 	register struct socket *so;
68610267Ssam 	int level, optname;
68717158Ssam 	struct mbuf **mp;
68817158Ssam {
68912757Ssam 	register struct mbuf *m;
69010267Ssam 
691*18369Skarels 	if (level != SOL_SOCKET) {
692*18369Skarels 		if (so->so_proto && so->so_proto->pr_ctloutput) {
693*18369Skarels 			return ((*so->so_proto->pr_ctloutput)
694*18369Skarels 				  (PRCO_GETOPT, so, level, optname, mp));
695*18369Skarels 		} else
696*18369Skarels 			return (ENOPROTOOPT);
697*18369Skarels 	} else {
69817158Ssam 		m = m_get(M_WAIT, MT_SOOPTS);
69917158Ssam 		if (m == NULL)
70017158Ssam 			return (ENOBUFS);
701*18369Skarels 		switch (optname) {
70217158Ssam 
703*18369Skarels 		case SO_LINGER:
704*18369Skarels 			m->m_len = sizeof (struct linger);
705*18369Skarels 			mtod(m, struct linger *)->l_onoff =
706*18369Skarels 				so->so_options & SO_LINGER;
707*18369Skarels 			mtod(m, struct linger *)->l_linger = so->so_linger;
708*18369Skarels 			break;
70910267Ssam 
710*18369Skarels 		case SO_USELOOPBACK:
711*18369Skarels 		case SO_DONTROUTE:
712*18369Skarels 		case SO_DEBUG:
713*18369Skarels 		case SO_KEEPALIVE:
714*18369Skarels 		case SO_REUSEADDR:
715*18369Skarels 		case SO_BROADCAST:
716*18369Skarels 			m->m_len = sizeof (int);
717*18369Skarels 			*mtod(m, int *) = so->so_options & optname;
718*18369Skarels 			break;
719*18369Skarels 
720*18369Skarels 		case SO_SNDBUF:
721*18369Skarels 			*mtod(m, int *) = so->so_snd.sb_hiwat;
722*18369Skarels 			break;
723*18369Skarels 
724*18369Skarels 		case SO_RCVBUF:
725*18369Skarels 			*mtod(m, int *) = so->so_rcv.sb_hiwat;
726*18369Skarels 			break;
727*18369Skarels 
728*18369Skarels 		case SO_SNDLOWAT:
729*18369Skarels 			*mtod(m, int *) = so->so_snd.sb_lowat;
730*18369Skarels 			break;
731*18369Skarels 
732*18369Skarels 		case SO_RCVLOWAT:
733*18369Skarels 			*mtod(m, int *) = so->so_rcv.sb_lowat;
734*18369Skarels 			break;
735*18369Skarels 
736*18369Skarels 		case SO_SNDTIMEO:
737*18369Skarels 			*mtod(m, int *) = so->so_snd.sb_timeo;
738*18369Skarels 			break;
739*18369Skarels 
740*18369Skarels 		case SO_RCVTIMEO:
741*18369Skarels 			*mtod(m, int *) = so->so_rcv.sb_timeo;
742*18369Skarels 			break;
743*18369Skarels 
744*18369Skarels 		default:
745*18369Skarels 			m_free(m);
746*18369Skarels 			return (ENOPROTOOPT);
747*18369Skarels 		}
748*18369Skarels 		*mp = m;
749*18369Skarels 		return (0);
75010267Ssam 	}
75110267Ssam }
75210267Ssam 
7535423Swnj sohasoutofband(so)
75412757Ssam 	register struct socket *so;
7555423Swnj {
7565423Swnj 
7575423Swnj 	if (so->so_pgrp == 0)
7585423Swnj 		return;
7595423Swnj 	if (so->so_pgrp > 0)
7605423Swnj 		gsignal(so->so_pgrp, SIGURG);
7615429Swnj 	else {
7625429Swnj 		struct proc *p = pfind(-so->so_pgrp);
7635429Swnj 
7645429Swnj 		if (p)
7655429Swnj 			psignal(p, SIGURG);
7665429Swnj 	}
7675423Swnj }
768