xref: /csrg-svn/sys/kern/uipc_socket.c (revision 33372)
123421Smckusick /*
229126Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
333185Sbostic  * All rights reserved.
423421Smckusick  *
533185Sbostic  * Redistribution and use in source and binary forms are permitted
633185Sbostic  * provided that this notice is preserved and that due credit is given
733185Sbostic  * to the University of California at Berkeley. The name of the University
833185Sbostic  * may not be used to endorse or promote products derived from this
933185Sbostic  * software without specific prior written permission. This software
1033185Sbostic  * is provided ``as is'' without express or implied warranty.
1133185Sbostic  *
12*33372Sbostic  *	@(#)uipc_socket.c	7.8 (Berkeley) 01/20/88
1323421Smckusick  */
144786Swnj 
1517102Sbloom #include "param.h"
1617102Sbloom #include "dir.h"
1717102Sbloom #include "user.h"
1817102Sbloom #include "proc.h"
1917102Sbloom #include "file.h"
2017102Sbloom #include "mbuf.h"
2117102Sbloom #include "domain.h"
2217102Sbloom #include "protosw.h"
2317102Sbloom #include "socket.h"
2417102Sbloom #include "socketvar.h"
254786Swnj 
264786Swnj /*
278300Sroot  * Socket operation routines.
288300Sroot  * These routines are called by the routines in
298300Sroot  * sys_socket.c or from a system process, and
308300Sroot  * implement the semantics of socket operations by
318300Sroot  * switching out to the protocol specific routines.
3212757Ssam  *
3312757Ssam  * TODO:
3412757Ssam  *	test socketpair
3521767Skarels  *	clean up 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)
5021767Skarels 		prp = pffindproto(dom, proto, type);
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 	so = mtod(m, struct socket *);
5912757Ssam 	so->so_options = 0;
606214Swnj 	so->so_state = 0;
619168Ssam 	so->so_type = type;
626214Swnj 	if (u.u_uid == 0)
636214Swnj 		so->so_state = SS_PRIV;
644786Swnj 	so->so_proto = prp;
6512757Ssam 	error =
6612757Ssam 	    (*prp->pr_usrreq)(so, PRU_ATTACH,
6721767Skarels 		(struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0);
684979Swnj 	if (error) {
697507Sroot 		so->so_state |= SS_NOFDREF;
707180Swnj 		sofree(so);
714890Swnj 		return (error);
724786Swnj 	}
734786Swnj 	*aso = so;
744786Swnj 	return (0);
754786Swnj }
764786Swnj 
7710267Ssam sobind(so, nam)
788300Sroot 	struct socket *so;
798300Sroot 	struct mbuf *nam;
808300Sroot {
818300Sroot 	int s = splnet();
828300Sroot 	int error;
838300Sroot 
848300Sroot 	error =
8512757Ssam 	    (*so->so_proto->pr_usrreq)(so, PRU_BIND,
8612757Ssam 		(struct mbuf *)0, nam, (struct mbuf *)0);
878300Sroot 	splx(s);
888300Sroot 	return (error);
898300Sroot }
908300Sroot 
918300Sroot solisten(so, backlog)
9212757Ssam 	register struct socket *so;
938300Sroot 	int backlog;
948300Sroot {
9512757Ssam 	int s = splnet(), error;
968300Sroot 
9712757Ssam 	error =
9812757Ssam 	    (*so->so_proto->pr_usrreq)(so, PRU_LISTEN,
9912757Ssam 		(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
1008300Sroot 	if (error) {
1018300Sroot 		splx(s);
1028300Sroot 		return (error);
1038300Sroot 	}
1048300Sroot 	if (so->so_q == 0) {
1058300Sroot 		so->so_q = so;
1068300Sroot 		so->so_q0 = so;
1078300Sroot 		so->so_options |= SO_ACCEPTCONN;
1088300Sroot 	}
1098300Sroot 	if (backlog < 0)
1108300Sroot 		backlog = 0;
11110137Ssam 	so->so_qlimit = MIN(backlog, SOMAXCONN);
11212493Ssam 	splx(s);
1138300Sroot 	return (0);
1148300Sroot }
1158300Sroot 
1164916Swnj sofree(so)
11712757Ssam 	register struct socket *so;
1184916Swnj {
1194916Swnj 
12031810Skarels 	if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
12131810Skarels 		return;
1227507Sroot 	if (so->so_head) {
1237507Sroot 		if (!soqremque(so, 0) && !soqremque(so, 1))
1247507Sroot 			panic("sofree dq");
1257507Sroot 		so->so_head = 0;
1267507Sroot 	}
1274950Swnj 	sbrelease(&so->so_snd);
12812757Ssam 	sorflush(so);
1294971Swnj 	(void) m_free(dtom(so));
1304916Swnj }
1314916Swnj 
1324786Swnj /*
1334890Swnj  * Close a socket on last file table reference removal.
1344890Swnj  * Initiate disconnect if connected.
1354890Swnj  * Free socket when disconnect complete.
1364829Swnj  */
13712757Ssam soclose(so)
1384829Swnj 	register struct socket *so;
1394829Swnj {
1404890Swnj 	int s = splnet();		/* conservative */
141*33372Sbostic 	int error = 0;
1424829Swnj 
1437507Sroot 	if (so->so_options & SO_ACCEPTCONN) {
1447507Sroot 		while (so->so_q0 != so)
14510399Ssam 			(void) soabort(so->so_q0);
1467507Sroot 		while (so->so_q != so)
14710399Ssam 			(void) soabort(so->so_q);
1487507Sroot 	}
1494890Swnj 	if (so->so_pcb == 0)
1504890Swnj 		goto discard;
1514890Swnj 	if (so->so_state & SS_ISCONNECTED) {
1524890Swnj 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
15326245Skarels 			error = sodisconnect(so);
15412757Ssam 			if (error)
15512757Ssam 				goto drop;
1564890Swnj 		}
15710267Ssam 		if (so->so_options & SO_LINGER) {
1585281Sroot 			if ((so->so_state & SS_ISDISCONNECTING) &&
15912757Ssam 			    (so->so_state & SS_NBIO))
16012757Ssam 				goto drop;
1615281Sroot 			while (so->so_state & SS_ISCONNECTED)
1625281Sroot 				sleep((caddr_t)&so->so_timeo, PZERO+1);
1634890Swnj 		}
1644890Swnj 	}
1655580Sroot drop:
1666880Ssam 	if (so->so_pcb) {
16712757Ssam 		int error2 =
16812757Ssam 		    (*so->so_proto->pr_usrreq)(so, PRU_DETACH,
16912757Ssam 			(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
17012757Ssam 		if (error == 0)
17112757Ssam 			error = error2;
1726880Ssam 	}
1734890Swnj discard:
17410399Ssam 	if (so->so_state & SS_NOFDREF)
17510399Ssam 		panic("soclose: NOFDREF");
1767507Sroot 	so->so_state |= SS_NOFDREF;
1774950Swnj 	sofree(so);
1784890Swnj 	splx(s);
17912757Ssam 	return (error);
1804829Swnj }
1814829Swnj 
18210399Ssam /*
18310399Ssam  * Must be called at splnet...
18410399Ssam  */
18510399Ssam soabort(so)
18610399Ssam 	struct socket *so;
18710399Ssam {
18810399Ssam 
18912757Ssam 	return (
19012757Ssam 	    (*so->so_proto->pr_usrreq)(so, PRU_ABORT,
19112757Ssam 		(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
19210399Ssam }
19310399Ssam 
19410267Ssam soaccept(so, nam)
19512757Ssam 	register struct socket *so;
1968300Sroot 	struct mbuf *nam;
1974927Swnj {
1984927Swnj 	int s = splnet();
1994927Swnj 	int error;
2004927Swnj 
20110399Ssam 	if ((so->so_state & SS_NOFDREF) == 0)
20210399Ssam 		panic("soaccept: !NOFDREF");
20310267Ssam 	so->so_state &= ~SS_NOFDREF;
2048300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT,
20512757Ssam 	    (struct mbuf *)0, nam, (struct mbuf *)0);
2064927Swnj 	splx(s);
2074927Swnj 	return (error);
2084927Swnj }
2094927Swnj 
21010267Ssam soconnect(so, nam)
21112757Ssam 	register struct socket *so;
2128300Sroot 	struct mbuf *nam;
2134786Swnj {
21430414Skarels 	int s;
2154890Swnj 	int error;
2164786Swnj 
21730414Skarels 	if (so->so_options & SO_ACCEPTCONN)
21830414Skarels 		return (EOPNOTSUPP);
21930414Skarels 	s = splnet();
22024768Skarels 	/*
22124768Skarels 	 * If protocol is connection-based, can only connect once.
22224768Skarels 	 * Otherwise, if connected, try to disconnect first.
22324768Skarels 	 * This allows user to disconnect by connecting to, e.g.,
22424768Skarels 	 * a null address.
22524768Skarels 	 */
22624768Skarels 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) &&
22724768Skarels 	    ((so->so_proto->pr_flags & PR_CONNREQUIRED) ||
22824768Skarels 	    (error = sodisconnect(so))))
2294890Swnj 		error = EISCONN;
23024768Skarels 	else
23124768Skarels 		error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
23224768Skarels 		    (struct mbuf *)0, nam, (struct mbuf *)0);
2334890Swnj 	splx(s);
2344890Swnj 	return (error);
2354786Swnj }
2364786Swnj 
23712757Ssam soconnect2(so1, so2)
23812757Ssam 	register struct socket *so1;
23912757Ssam 	struct socket *so2;
24012757Ssam {
24112757Ssam 	int s = splnet();
24212757Ssam 	int error;
24312757Ssam 
24413113Ssam 	error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2,
24513113Ssam 	    (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0);
24612757Ssam 	splx(s);
24712757Ssam 	return (error);
24812757Ssam }
24912757Ssam 
25026245Skarels sodisconnect(so)
25112757Ssam 	register struct socket *so;
2524786Swnj {
2534890Swnj 	int s = splnet();
2544890Swnj 	int error;
2554786Swnj 
2564890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2574890Swnj 		error = ENOTCONN;
2584890Swnj 		goto bad;
2594890Swnj 	}
2604890Swnj 	if (so->so_state & SS_ISDISCONNECTING) {
2614890Swnj 		error = EALREADY;
2624890Swnj 		goto bad;
2634890Swnj 	}
2648300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT,
26526245Skarels 	    (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
2664890Swnj bad:
2674890Swnj 	splx(s);
2684890Swnj 	return (error);
2694786Swnj }
2704786Swnj 
2714786Swnj /*
2724890Swnj  * Send on a socket.
2734890Swnj  * If send must go all at once and message is larger than
2744890Swnj  * send buffering, then hard error.
2754890Swnj  * Lock against other senders.
2764890Swnj  * If must go all at once and not enough room now, then
2774890Swnj  * inform user that this would block and do nothing.
27816412Skarels  * Otherwise, if nonblocking, send as much as possible.
2794786Swnj  */
28012757Ssam sosend(so, nam, uio, flags, rights)
2814786Swnj 	register struct socket *so;
2828300Sroot 	struct mbuf *nam;
28312757Ssam 	register struct uio *uio;
2848319Sroot 	int flags;
28512757Ssam 	struct mbuf *rights;
2864786Swnj {
2874890Swnj 	struct mbuf *top = 0;
28816412Skarels 	register struct mbuf *m, **mp;
28912757Ssam 	register int space;
29025629Skarels 	int len, rlen = 0, error = 0, s, dontroute, first = 1;
2914786Swnj 
2927827Sroot 	if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat)
2934890Swnj 		return (EMSGSIZE);
29412757Ssam 	dontroute =
29512757Ssam 	    (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
29612757Ssam 	    (so->so_proto->pr_flags & PR_ATOMIC);
29716412Skarels 	u.u_ru.ru_msgsnd++;
29825629Skarels 	if (rights)
29925629Skarels 		rlen = rights->m_len;
30016412Skarels #define	snderr(errno)	{ error = errno; splx(s); goto release; }
30116412Skarels 
3026419Sroot restart:
3034890Swnj 	sblock(&so->so_snd);
30416412Skarels 	do {
30516412Skarels 		s = splnet();
30621108Skarels 		if (so->so_state & SS_CANTSENDMORE)
30716412Skarels 			snderr(EPIPE);
30816412Skarels 		if (so->so_error) {
30916412Skarels 			error = so->so_error;
31016412Skarels 			so->so_error = 0;			/* ??? */
31116412Skarels 			splx(s);
31216412Skarels 			goto release;
31316412Skarels 		}
31416412Skarels 		if ((so->so_state & SS_ISCONNECTED) == 0) {
31516412Skarels 			if (so->so_proto->pr_flags & PR_CONNREQUIRED)
31616412Skarels 				snderr(ENOTCONN);
31716412Skarels 			if (nam == 0)
31816412Skarels 				snderr(EDESTADDRREQ);
31916412Skarels 		}
32016412Skarels 		if (flags & MSG_OOB)
32116412Skarels 			space = 1024;
32216412Skarels 		else {
32316412Skarels 			space = sbspace(&so->so_snd);
32425629Skarels 			if (space <= rlen ||
32525629Skarels 			   (sosendallatonce(so) &&
32625629Skarels 				space < uio->uio_resid + rlen) ||
32716992Skarels 			   (uio->uio_resid >= CLBYTES && space < CLBYTES &&
32816992Skarels 			   so->so_snd.sb_cc >= CLBYTES &&
32916992Skarels 			   (so->so_state & SS_NBIO) == 0)) {
33016412Skarels 				if (so->so_state & SS_NBIO) {
33116412Skarels 					if (first)
33216412Skarels 						error = EWOULDBLOCK;
33316412Skarels 					splx(s);
33416412Skarels 					goto release;
33516412Skarels 				}
33616412Skarels 				sbunlock(&so->so_snd);
33716412Skarels 				sbwait(&so->so_snd);
33816412Skarels 				splx(s);
33916412Skarels 				goto restart;
34016412Skarels 			}
34116412Skarels 		}
34216412Skarels 		splx(s);
34316412Skarels 		mp = &top;
34425629Skarels 		space -= rlen;
34521108Skarels 		while (space > 0) {
34616412Skarels 			MGET(m, M_WAIT, MT_DATA);
34726958Skarels 			if (uio->uio_resid >= CLBYTES / 2 && space >= CLBYTES) {
34826228Skarels 				MCLGET(m);
34926228Skarels 				if (m->m_len != CLBYTES)
35016412Skarels 					goto nopages;
35126958Skarels 				len = MIN(CLBYTES, uio->uio_resid);
35221767Skarels 				space -= CLBYTES;
35316412Skarels 			} else {
35416412Skarels nopages:
35526958Skarels 				len = MIN(MIN(MLEN, uio->uio_resid), space);
35621767Skarels 				space -= len;
35716412Skarels 			}
35816412Skarels 			error = uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio);
35916412Skarels 			m->m_len = len;
36016412Skarels 			*mp = m;
36116412Skarels 			if (error)
36216412Skarels 				goto release;
36316412Skarels 			mp = &m->m_next;
36421108Skarels 			if (uio->uio_resid <= 0)
36521108Skarels 				break;
36616412Skarels 		}
36721108Skarels 		if (dontroute)
36821108Skarels 			so->so_options |= SO_DONTROUTE;
36921108Skarels 		s = splnet();					/* XXX */
37021108Skarels 		error = (*so->so_proto->pr_usrreq)(so,
37121108Skarels 		    (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
37221108Skarels 		    top, (caddr_t)nam, rights);
37321108Skarels 		splx(s);
37421108Skarels 		if (dontroute)
37521108Skarels 			so->so_options &= ~SO_DONTROUTE;
37621767Skarels 		rights = 0;
37725629Skarels 		rlen = 0;
3786419Sroot 		top = 0;
37916412Skarels 		first = 0;
38014781Ssam 		if (error)
38116412Skarels 			break;
38216412Skarels 	} while (uio->uio_resid);
3834890Swnj 
3844786Swnj release:
3854890Swnj 	sbunlock(&so->so_snd);
3866419Sroot 	if (top)
3876419Sroot 		m_freem(top);
38821108Skarels 	if (error == EPIPE)
38921108Skarels 		psignal(u.u_procp, SIGPIPE);
3904786Swnj 	return (error);
3914786Swnj }
3924786Swnj 
39325629Skarels /*
39425629Skarels  * Implement receive operations on a socket.
39525629Skarels  * We depend on the way that records are added to the sockbuf
39625629Skarels  * by sbappend*.  In particular, each record (mbufs linked through m_next)
39725629Skarels  * must begin with an address if the protocol so specifies,
39825629Skarels  * followed by an optional mbuf containing access rights if supported
39925629Skarels  * by the protocol, and then zero or more mbufs of data.
40025629Skarels  * In order to avoid blocking network interrupts for the entire time here,
40125629Skarels  * we splx() while doing the actual copy to user space.
40225629Skarels  * Although the sockbuf is locked, new data may still be appended,
40325629Skarels  * and thus we must maintain consistency of the sockbuf during that time.
40425629Skarels  */
40512757Ssam soreceive(so, aname, uio, flags, rightsp)
4064786Swnj 	register struct socket *so;
4078300Sroot 	struct mbuf **aname;
40812757Ssam 	register struct uio *uio;
4098319Sroot 	int flags;
41012757Ssam 	struct mbuf **rightsp;
4114786Swnj {
41226958Skarels 	register struct mbuf *m;
41332092Skarels 	register int len, error = 0, s, offset;
41412757Ssam 	struct protosw *pr = so->so_proto;
41516993Skarels 	struct mbuf *nextrecord;
41612757Ssam 	int moff;
4174786Swnj 
41812757Ssam 	if (rightsp)
41912757Ssam 		*rightsp = 0;
42012757Ssam 	if (aname)
42112757Ssam 		*aname = 0;
42212757Ssam 	if (flags & MSG_OOB) {
4239635Ssam 		m = m_get(M_WAIT, MT_DATA);
42412757Ssam 		error = (*pr->pr_usrreq)(so, PRU_RCVOOB,
42524768Skarels 		    m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0);
4268594Sroot 		if (error)
42710137Ssam 			goto bad;
4288319Sroot 		do {
42910137Ssam 			len = uio->uio_resid;
4308319Sroot 			if (len > m->m_len)
4318319Sroot 				len = m->m_len;
4328594Sroot 			error =
4338793Sroot 			    uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio);
4348319Sroot 			m = m_free(m);
4358594Sroot 		} while (uio->uio_resid && error == 0 && m);
43610137Ssam bad:
4378319Sroot 		if (m)
4388771Sroot 			m_freem(m);
4398594Sroot 		return (error);
4408319Sroot 	}
4418319Sroot 
4424890Swnj restart:
4434890Swnj 	sblock(&so->so_rcv);
4448835Sroot 	s = splnet();
4454890Swnj 
4464786Swnj 	if (so->so_rcv.sb_cc == 0) {
4475168Swnj 		if (so->so_error) {
4485168Swnj 			error = so->so_error;
4495168Swnj 			so->so_error = 0;
4505168Swnj 			goto release;
4515168Swnj 		}
45232567Sbostic 		if (so->so_state & SS_CANTRCVMORE)
4534890Swnj 			goto release;
45432567Sbostic 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
45532567Sbostic 		    (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
45632567Sbostic 			error = ENOTCONN;
45732567Sbostic 			goto release;
4584890Swnj 		}
45925629Skarels 		if (uio->uio_resid == 0)
46025629Skarels 			goto release;
46132567Sbostic 		if (so->so_state & SS_NBIO) {
46232567Sbostic 			error = EWOULDBLOCK;
46332567Sbostic 			goto release;
46432567Sbostic 		}
4654890Swnj 		sbunlock(&so->so_rcv);
4664971Swnj 		sbwait(&so->so_rcv);
4675012Swnj 		splx(s);
4684890Swnj 		goto restart;
4694786Swnj 	}
4708041Sroot 	u.u_ru.ru_msgrcv++;
4714829Swnj 	m = so->so_rcv.sb_mb;
47225629Skarels 	if (m == 0)
47325629Skarels 		panic("receive 1");
47425629Skarels 	nextrecord = m->m_act;
47512757Ssam 	if (pr->pr_flags & PR_ADDR) {
47625629Skarels 		if (m->m_type != MT_SONAME)
47716993Skarels 			panic("receive 1a");
47816993Skarels 		if (flags & MSG_PEEK) {
47916993Skarels 			if (aname)
4808319Sroot 				*aname = m_copy(m, 0, m->m_len);
48125629Skarels 			m = m->m_next;
48216993Skarels 		} else {
48325629Skarels 			sbfree(&so->so_rcv, m);
48416993Skarels 			if (aname) {
48516993Skarels 				*aname = m;
48625629Skarels 				m = m->m_next;
48725629Skarels 				(*aname)->m_next = 0;
48826958Skarels 				so->so_rcv.sb_mb = m;
48925629Skarels 			} else {
49026958Skarels 				MFREE(m, so->so_rcv.sb_mb);
49126958Skarels 				m = so->so_rcv.sb_mb;
49225629Skarels 			}
49326958Skarels 			if (m)
49426958Skarels 				m->m_act = nextrecord;
49516993Skarels 		}
49616993Skarels 	}
49716993Skarels 	if (m && m->m_type == MT_RIGHTS) {
49816993Skarels 		if ((pr->pr_flags & PR_RIGHTS) == 0)
49926958Skarels 			panic("receive 2");
50016993Skarels 		if (flags & MSG_PEEK) {
50116993Skarels 			if (rightsp)
50212757Ssam 				*rightsp = m_copy(m, 0, m->m_len);
50325629Skarels 			m = m->m_next;
50416993Skarels 		} else {
50525629Skarels 			sbfree(&so->so_rcv, m);
50616993Skarels 			if (rightsp) {
50716993Skarels 				*rightsp = m;
50826958Skarels 				so->so_rcv.sb_mb = m->m_next;
50925629Skarels 				m->m_next = 0;
51026958Skarels 				m = so->so_rcv.sb_mb;
51125629Skarels 			} else {
51226958Skarels 				MFREE(m, so->so_rcv.sb_mb);
51326958Skarels 				m = so->so_rcv.sb_mb;
51425629Skarels 			}
51526958Skarels 			if (m)
51626958Skarels 				m->m_act = nextrecord;
51712757Ssam 		}
5184890Swnj 	}
5198319Sroot 	moff = 0;
52032092Skarels 	offset = 0;
52116993Skarels 	while (m && uio->uio_resid > 0 && error == 0) {
52225629Skarels 		if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
52325629Skarels 			panic("receive 3");
5247827Sroot 		len = uio->uio_resid;
5257747Sroot 		so->so_state &= ~SS_RCVATMARK;
52632092Skarels 		if (so->so_oobmark && len > so->so_oobmark - offset)
52732092Skarels 			len = so->so_oobmark - offset;
52821767Skarels 		if (len > m->m_len - moff)
5298319Sroot 			len = m->m_len - moff;
5304786Swnj 		splx(s);
5318594Sroot 		error =
5328793Sroot 		    uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio);
5334786Swnj 		s = splnet();
53421767Skarels 		if (len == m->m_len - moff) {
53525629Skarels 			if (flags & MSG_PEEK) {
53625629Skarels 				m = m->m_next;
53725629Skarels 				moff = 0;
53825629Skarels 			} else {
53926958Skarels 				nextrecord = m->m_act;
54025629Skarels 				sbfree(&so->so_rcv, m);
54126958Skarels 				MFREE(m, so->so_rcv.sb_mb);
54226958Skarels 				m = so->so_rcv.sb_mb;
54326958Skarels 				if (m)
54426958Skarels 					m->m_act = nextrecord;
54525629Skarels 			}
5464786Swnj 		} else {
54712757Ssam 			if (flags & MSG_PEEK)
5488319Sroot 				moff += len;
5498319Sroot 			else {
5508319Sroot 				m->m_off += len;
5518319Sroot 				m->m_len -= len;
5528319Sroot 				so->so_rcv.sb_cc -= len;
5538319Sroot 			}
5544786Swnj 		}
55532092Skarels 		if (so->so_oobmark) {
55632092Skarels 			if ((flags & MSG_PEEK) == 0) {
55732092Skarels 				so->so_oobmark -= len;
55832092Skarels 				if (so->so_oobmark == 0) {
55932092Skarels 					so->so_state |= SS_RCVATMARK;
56032092Skarels 					break;
56132092Skarels 				}
56232092Skarels 			} else
56332092Skarels 				offset += len;
5647747Sroot 		}
56516993Skarels 	}
56616993Skarels 	if ((flags & MSG_PEEK) == 0) {
56726500Skarels 		if (m == 0)
56816993Skarels 			so->so_rcv.sb_mb = nextrecord;
56926958Skarels 		else if (pr->pr_flags & PR_ATOMIC)
57026958Skarels 			(void) sbdroprecord(&so->so_rcv);
57116993Skarels 		if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
57216993Skarels 			(*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
57316993Skarels 			    (struct mbuf *)0, (struct mbuf *)0);
57425629Skarels 		if (error == 0 && rightsp && *rightsp &&
57525629Skarels 		    pr->pr_domain->dom_externalize)
57625629Skarels 			error = (*pr->pr_domain->dom_externalize)(*rightsp);
57716993Skarels 	}
5784890Swnj release:
5794916Swnj 	sbunlock(&so->so_rcv);
5804890Swnj 	splx(s);
5814916Swnj 	return (error);
5824786Swnj }
5834786Swnj 
58410267Ssam soshutdown(so, how)
58512757Ssam 	register struct socket *so;
58612757Ssam 	register int how;
58710267Ssam {
58812757Ssam 	register struct protosw *pr = so->so_proto;
58910267Ssam 
59010267Ssam 	how++;
59112757Ssam 	if (how & FREAD)
59212757Ssam 		sorflush(so);
59310267Ssam 	if (how & FWRITE)
59412757Ssam 		return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN,
59512757Ssam 		    (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
59610267Ssam 	return (0);
59710267Ssam }
59810267Ssam 
59912757Ssam sorflush(so)
60012757Ssam 	register struct socket *so;
60112757Ssam {
60212757Ssam 	register struct sockbuf *sb = &so->so_rcv;
60312757Ssam 	register struct protosw *pr = so->so_proto;
60412757Ssam 	register int s;
60512757Ssam 	struct sockbuf asb;
60612757Ssam 
60712757Ssam 	sblock(sb);
60812757Ssam 	s = splimp();
60912757Ssam 	socantrcvmore(so);
61012757Ssam 	sbunlock(sb);
61112757Ssam 	asb = *sb;
61212757Ssam 	bzero((caddr_t)sb, sizeof (*sb));
61312757Ssam 	splx(s);
61416993Skarels 	if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose)
61516993Skarels 		(*pr->pr_domain->dom_dispose)(asb.sb_mb);
61612757Ssam 	sbrelease(&asb);
61712757Ssam }
61812757Ssam 
61918553Skarels sosetopt(so, level, optname, m0)
62012757Ssam 	register struct socket *so;
62110267Ssam 	int level, optname;
62218553Skarels 	struct mbuf *m0;
62310267Ssam {
62417158Ssam 	int error = 0;
62518553Skarels 	register struct mbuf *m = m0;
62610267Ssam 
62717158Ssam 	if (level != SOL_SOCKET) {
62818369Skarels 		if (so->so_proto && so->so_proto->pr_ctloutput)
62918369Skarels 			return ((*so->so_proto->pr_ctloutput)
63018553Skarels 				  (PRCO_SETOPT, so, level, optname, &m0));
63118369Skarels 		error = ENOPROTOOPT;
63218369Skarels 	} else {
63318369Skarels 		switch (optname) {
63410267Ssam 
63518369Skarels 		case SO_LINGER:
63618369Skarels 			if (m == NULL || m->m_len != sizeof (struct linger)) {
63718369Skarels 				error = EINVAL;
63818369Skarels 				goto bad;
63918369Skarels 			}
64018369Skarels 			so->so_linger = mtod(m, struct linger *)->l_linger;
64118369Skarels 			/* fall thru... */
64217158Ssam 
64318369Skarels 		case SO_DEBUG:
64418369Skarels 		case SO_KEEPALIVE:
64518369Skarels 		case SO_DONTROUTE:
64618369Skarels 		case SO_USELOOPBACK:
64718369Skarels 		case SO_BROADCAST:
64818369Skarels 		case SO_REUSEADDR:
64927191Skarels 		case SO_OOBINLINE:
65018369Skarels 			if (m == NULL || m->m_len < sizeof (int)) {
65118369Skarels 				error = EINVAL;
65218369Skarels 				goto bad;
65318369Skarels 			}
65418369Skarels 			if (*mtod(m, int *))
65518369Skarels 				so->so_options |= optname;
65618369Skarels 			else
65718369Skarels 				so->so_options &= ~optname;
65818369Skarels 			break;
65918369Skarels 
66018369Skarels 		case SO_SNDBUF:
66118369Skarels 		case SO_RCVBUF:
66218369Skarels 		case SO_SNDLOWAT:
66318369Skarels 		case SO_RCVLOWAT:
66418369Skarels 		case SO_SNDTIMEO:
66518369Skarels 		case SO_RCVTIMEO:
66618369Skarels 			if (m == NULL || m->m_len < sizeof (int)) {
66718369Skarels 				error = EINVAL;
66818369Skarels 				goto bad;
66918369Skarels 			}
67018369Skarels 			switch (optname) {
67118369Skarels 
67218369Skarels 			case SO_SNDBUF:
67318369Skarels 			case SO_RCVBUF:
67418369Skarels 				if (sbreserve(optname == SO_SNDBUF ? &so->so_snd :
67518369Skarels 				    &so->so_rcv, *mtod(m, int *)) == 0) {
67618369Skarels 					error = ENOBUFS;
67718369Skarels 					goto bad;
67818369Skarels 				}
67918369Skarels 				break;
68018369Skarels 
68118369Skarels 			case SO_SNDLOWAT:
68218369Skarels 				so->so_snd.sb_lowat = *mtod(m, int *);
68318369Skarels 				break;
68418369Skarels 			case SO_RCVLOWAT:
68518369Skarels 				so->so_rcv.sb_lowat = *mtod(m, int *);
68618369Skarels 				break;
68718369Skarels 			case SO_SNDTIMEO:
68818369Skarels 				so->so_snd.sb_timeo = *mtod(m, int *);
68918369Skarels 				break;
69018369Skarels 			case SO_RCVTIMEO:
69118369Skarels 				so->so_rcv.sb_timeo = *mtod(m, int *);
69218369Skarels 				break;
69318369Skarels 			}
69418369Skarels 			break;
69518369Skarels 
69618369Skarels 		default:
69718369Skarels 			error = ENOPROTOOPT;
69818369Skarels 			break;
69917158Ssam 		}
70010267Ssam 	}
70117158Ssam bad:
70217158Ssam 	if (m)
70317158Ssam 		(void) m_free(m);
70417158Ssam 	return (error);
70510267Ssam }
70610267Ssam 
70717158Ssam sogetopt(so, level, optname, mp)
70812757Ssam 	register struct socket *so;
70910267Ssam 	int level, optname;
71017158Ssam 	struct mbuf **mp;
71117158Ssam {
71212757Ssam 	register struct mbuf *m;
71310267Ssam 
71418369Skarels 	if (level != SOL_SOCKET) {
71518369Skarels 		if (so->so_proto && so->so_proto->pr_ctloutput) {
71618369Skarels 			return ((*so->so_proto->pr_ctloutput)
71718369Skarels 				  (PRCO_GETOPT, so, level, optname, mp));
71818369Skarels 		} else
71918369Skarels 			return (ENOPROTOOPT);
72018369Skarels 	} else {
72117158Ssam 		m = m_get(M_WAIT, MT_SOOPTS);
72225502Skarels 		m->m_len = sizeof (int);
72325502Skarels 
72418369Skarels 		switch (optname) {
72517158Ssam 
72618369Skarels 		case SO_LINGER:
72718369Skarels 			m->m_len = sizeof (struct linger);
72818369Skarels 			mtod(m, struct linger *)->l_onoff =
72918369Skarels 				so->so_options & SO_LINGER;
73018369Skarels 			mtod(m, struct linger *)->l_linger = so->so_linger;
73118369Skarels 			break;
73210267Ssam 
73318369Skarels 		case SO_USELOOPBACK:
73418369Skarels 		case SO_DONTROUTE:
73518369Skarels 		case SO_DEBUG:
73618369Skarels 		case SO_KEEPALIVE:
73718369Skarels 		case SO_REUSEADDR:
73818369Skarels 		case SO_BROADCAST:
73927191Skarels 		case SO_OOBINLINE:
74018369Skarels 			*mtod(m, int *) = so->so_options & optname;
74118369Skarels 			break;
74218369Skarels 
74325502Skarels 		case SO_TYPE:
74425502Skarels 			*mtod(m, int *) = so->so_type;
74525502Skarels 			break;
74625502Skarels 
74724768Skarels 		case SO_ERROR:
74824768Skarels 			*mtod(m, int *) = so->so_error;
74924768Skarels 			so->so_error = 0;
75024768Skarels 			break;
75124768Skarels 
75218369Skarels 		case SO_SNDBUF:
75318369Skarels 			*mtod(m, int *) = so->so_snd.sb_hiwat;
75418369Skarels 			break;
75518369Skarels 
75618369Skarels 		case SO_RCVBUF:
75718369Skarels 			*mtod(m, int *) = so->so_rcv.sb_hiwat;
75818369Skarels 			break;
75918369Skarels 
76018369Skarels 		case SO_SNDLOWAT:
76118369Skarels 			*mtod(m, int *) = so->so_snd.sb_lowat;
76218369Skarels 			break;
76318369Skarels 
76418369Skarels 		case SO_RCVLOWAT:
76518369Skarels 			*mtod(m, int *) = so->so_rcv.sb_lowat;
76618369Skarels 			break;
76718369Skarels 
76818369Skarels 		case SO_SNDTIMEO:
76918369Skarels 			*mtod(m, int *) = so->so_snd.sb_timeo;
77018369Skarels 			break;
77118369Skarels 
77218369Skarels 		case SO_RCVTIMEO:
77318369Skarels 			*mtod(m, int *) = so->so_rcv.sb_timeo;
77418369Skarels 			break;
77518369Skarels 
77618369Skarels 		default:
77726362Skarels 			(void)m_free(m);
77818369Skarels 			return (ENOPROTOOPT);
77918369Skarels 		}
78018369Skarels 		*mp = m;
78118369Skarels 		return (0);
78210267Ssam 	}
78310267Ssam }
78410267Ssam 
7855423Swnj sohasoutofband(so)
78612757Ssam 	register struct socket *so;
7875423Swnj {
78823233Skarels 	struct proc *p;
7895423Swnj 
79023233Skarels 	if (so->so_pgrp < 0)
79123233Skarels 		gsignal(-so->so_pgrp, SIGURG);
79223233Skarels 	else if (so->so_pgrp > 0 && (p = pfind(so->so_pgrp)) != 0)
79323233Skarels 		psignal(p, SIGURG);
79424768Skarels 	if (so->so_rcv.sb_sel) {
79524768Skarels 		selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL);
79624768Skarels 		so->so_rcv.sb_sel = 0;
79724768Skarels 		so->so_rcv.sb_flags &= ~SB_COLL;
79824768Skarels 	}
7995423Swnj }
800