xref: /csrg-svn/sys/kern/uipc_socket.c (revision 25629)
123421Smckusick /*
223421Smckusick  * Copyright (c) 1982 Regents of the University of California.
323421Smckusick  * All rights reserved.  The Berkeley software License Agreement
423421Smckusick  * specifies the terms and conditions for redistribution.
523421Smckusick  *
6*25629Skarels  *	@(#)uipc_socket.c	6.19 (Berkeley) 12/19/85
723421Smckusick  */
84786Swnj 
917102Sbloom #include "param.h"
1017102Sbloom #include "systm.h"
1117102Sbloom #include "dir.h"
1217102Sbloom #include "user.h"
1317102Sbloom #include "proc.h"
1417102Sbloom #include "file.h"
1517102Sbloom #include "inode.h"
1617102Sbloom #include "buf.h"
1717102Sbloom #include "mbuf.h"
1817102Sbloom #include "un.h"
1917102Sbloom #include "domain.h"
2017102Sbloom #include "protosw.h"
2117102Sbloom #include "socket.h"
2217102Sbloom #include "socketvar.h"
2317102Sbloom #include "stat.h"
2417102Sbloom #include "ioctl.h"
2517102Sbloom #include "uio.h"
266355Ssam #include "../net/route.h"
2712757Ssam #include "../netinet/in.h"
2811571Ssam #include "../net/if.h"
294786Swnj 
304786Swnj /*
318300Sroot  * Socket operation routines.
328300Sroot  * These routines are called by the routines in
338300Sroot  * sys_socket.c or from a system process, and
348300Sroot  * implement the semantics of socket operations by
358300Sroot  * switching out to the protocol specific routines.
3612757Ssam  *
3712757Ssam  * TODO:
3812757Ssam  *	test socketpair
3921767Skarels  *	clean up async
4012757Ssam  *	out-of-band is a kludge
414786Swnj  */
428594Sroot /*ARGSUSED*/
4310267Ssam socreate(dom, aso, type, proto)
444786Swnj 	struct socket **aso;
4512757Ssam 	register int type;
4612757Ssam 	int proto;
474786Swnj {
484786Swnj 	register struct protosw *prp;
494786Swnj 	register struct socket *so;
5012757Ssam 	register struct mbuf *m;
5112757Ssam 	register int error;
524786Swnj 
534890Swnj 	if (proto)
5421767Skarels 		prp = pffindproto(dom, proto, type);
554890Swnj 	else
569168Ssam 		prp = pffindtype(dom, type);
574890Swnj 	if (prp == 0)
584890Swnj 		return (EPROTONOSUPPORT);
598300Sroot 	if (prp->pr_type != type)
608300Sroot 		return (EPROTOTYPE);
619635Ssam 	m = m_getclr(M_WAIT, MT_SOCKET);
624786Swnj 	so = mtod(m, struct socket *);
6312757Ssam 	so->so_options = 0;
646214Swnj 	so->so_state = 0;
659168Ssam 	so->so_type = type;
666214Swnj 	if (u.u_uid == 0)
676214Swnj 		so->so_state = SS_PRIV;
684786Swnj 	so->so_proto = prp;
6912757Ssam 	error =
7012757Ssam 	    (*prp->pr_usrreq)(so, PRU_ATTACH,
7121767Skarels 		(struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0);
724979Swnj 	if (error) {
737507Sroot 		so->so_state |= SS_NOFDREF;
747180Swnj 		sofree(so);
754890Swnj 		return (error);
764786Swnj 	}
774786Swnj 	*aso = so;
784786Swnj 	return (0);
794786Swnj }
804786Swnj 
8110267Ssam sobind(so, nam)
828300Sroot 	struct socket *so;
838300Sroot 	struct mbuf *nam;
848300Sroot {
858300Sroot 	int s = splnet();
868300Sroot 	int error;
878300Sroot 
888300Sroot 	error =
8912757Ssam 	    (*so->so_proto->pr_usrreq)(so, PRU_BIND,
9012757Ssam 		(struct mbuf *)0, nam, (struct mbuf *)0);
918300Sroot 	splx(s);
928300Sroot 	return (error);
938300Sroot }
948300Sroot 
958300Sroot solisten(so, backlog)
9612757Ssam 	register struct socket *so;
978300Sroot 	int backlog;
988300Sroot {
9912757Ssam 	int s = splnet(), error;
1008300Sroot 
10112757Ssam 	error =
10212757Ssam 	    (*so->so_proto->pr_usrreq)(so, PRU_LISTEN,
10312757Ssam 		(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
1048300Sroot 	if (error) {
1058300Sroot 		splx(s);
1068300Sroot 		return (error);
1078300Sroot 	}
1088300Sroot 	if (so->so_q == 0) {
1098300Sroot 		so->so_q = so;
1108300Sroot 		so->so_q0 = so;
1118300Sroot 		so->so_options |= SO_ACCEPTCONN;
1128300Sroot 	}
1138300Sroot 	if (backlog < 0)
1148300Sroot 		backlog = 0;
11510137Ssam 	so->so_qlimit = MIN(backlog, SOMAXCONN);
11612493Ssam 	splx(s);
1178300Sroot 	return (0);
1188300Sroot }
1198300Sroot 
1204916Swnj sofree(so)
12112757Ssam 	register struct socket *so;
1224916Swnj {
1234916Swnj 
1247507Sroot 	if (so->so_head) {
1257507Sroot 		if (!soqremque(so, 0) && !soqremque(so, 1))
1267507Sroot 			panic("sofree dq");
1277507Sroot 		so->so_head = 0;
1287507Sroot 	}
1297507Sroot 	if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
1304950Swnj 		return;
1314950Swnj 	sbrelease(&so->so_snd);
13212757Ssam 	sorflush(so);
1334971Swnj 	(void) m_free(dtom(so));
1344916Swnj }
1354916Swnj 
1364786Swnj /*
1374890Swnj  * Close a socket on last file table reference removal.
1384890Swnj  * Initiate disconnect if connected.
1394890Swnj  * Free socket when disconnect complete.
1404829Swnj  */
14112757Ssam soclose(so)
1424829Swnj 	register struct socket *so;
1434829Swnj {
1444890Swnj 	int s = splnet();		/* conservative */
1458713Sroot 	int error;
1464829Swnj 
1477507Sroot 	if (so->so_options & SO_ACCEPTCONN) {
1487507Sroot 		while (so->so_q0 != so)
14910399Ssam 			(void) soabort(so->so_q0);
1507507Sroot 		while (so->so_q != so)
15110399Ssam 			(void) soabort(so->so_q);
1527507Sroot 	}
1534890Swnj 	if (so->so_pcb == 0)
1544890Swnj 		goto discard;
1554890Swnj 	if (so->so_state & SS_ISCONNECTED) {
1564890Swnj 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
1578725Sroot 			error = sodisconnect(so, (struct mbuf *)0);
15812757Ssam 			if (error)
15912757Ssam 				goto drop;
1604890Swnj 		}
16110267Ssam 		if (so->so_options & SO_LINGER) {
1625281Sroot 			if ((so->so_state & SS_ISDISCONNECTING) &&
16312757Ssam 			    (so->so_state & SS_NBIO))
16412757Ssam 				goto drop;
1655281Sroot 			while (so->so_state & SS_ISCONNECTED)
1665281Sroot 				sleep((caddr_t)&so->so_timeo, PZERO+1);
1674890Swnj 		}
1684890Swnj 	}
1695580Sroot drop:
1706880Ssam 	if (so->so_pcb) {
17112757Ssam 		int error2 =
17212757Ssam 		    (*so->so_proto->pr_usrreq)(so, PRU_DETACH,
17312757Ssam 			(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
17412757Ssam 		if (error == 0)
17512757Ssam 			error = error2;
1766880Ssam 	}
1774890Swnj discard:
17810399Ssam 	if (so->so_state & SS_NOFDREF)
17910399Ssam 		panic("soclose: NOFDREF");
1807507Sroot 	so->so_state |= SS_NOFDREF;
1814950Swnj 	sofree(so);
1824890Swnj 	splx(s);
18312757Ssam 	return (error);
1844829Swnj }
1854829Swnj 
18610399Ssam /*
18710399Ssam  * Must be called at splnet...
18810399Ssam  */
18910399Ssam soabort(so)
19010399Ssam 	struct socket *so;
19110399Ssam {
19210399Ssam 
19312757Ssam 	return (
19412757Ssam 	    (*so->so_proto->pr_usrreq)(so, PRU_ABORT,
19512757Ssam 		(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
19610399Ssam }
19710399Ssam 
19810267Ssam soaccept(so, nam)
19912757Ssam 	register struct socket *so;
2008300Sroot 	struct mbuf *nam;
2014927Swnj {
2024927Swnj 	int s = splnet();
2034927Swnj 	int error;
2044927Swnj 
20510399Ssam 	if ((so->so_state & SS_NOFDREF) == 0)
20610399Ssam 		panic("soaccept: !NOFDREF");
20710267Ssam 	so->so_state &= ~SS_NOFDREF;
2088300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT,
20912757Ssam 	    (struct mbuf *)0, nam, (struct mbuf *)0);
2104927Swnj 	splx(s);
2114927Swnj 	return (error);
2124927Swnj }
2134927Swnj 
21410267Ssam soconnect(so, nam)
21512757Ssam 	register struct socket *so;
2168300Sroot 	struct mbuf *nam;
2174786Swnj {
2184890Swnj 	int s = splnet();
2194890Swnj 	int error;
2204786Swnj 
22124768Skarels 	/*
22224768Skarels 	 * If protocol is connection-based, can only connect once.
22324768Skarels 	 * Otherwise, if connected, try to disconnect first.
22424768Skarels 	 * This allows user to disconnect by connecting to, e.g.,
22524768Skarels 	 * a null address.
22624768Skarels 	 */
22724768Skarels 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) &&
22824768Skarels 	    ((so->so_proto->pr_flags & PR_CONNREQUIRED) ||
22924768Skarels 	    (error = sodisconnect(so))))
2304890Swnj 		error = EISCONN;
23124768Skarels 	else
23224768Skarels 		error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
23324768Skarels 		    (struct mbuf *)0, nam, (struct mbuf *)0);
2344890Swnj 	splx(s);
2354890Swnj 	return (error);
2364786Swnj }
2374786Swnj 
23812757Ssam soconnect2(so1, so2)
23912757Ssam 	register struct socket *so1;
24012757Ssam 	struct socket *so2;
24112757Ssam {
24212757Ssam 	int s = splnet();
24312757Ssam 	int error;
24412757Ssam 
24513113Ssam 	error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2,
24613113Ssam 	    (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0);
24712757Ssam 	splx(s);
24812757Ssam 	return (error);
24912757Ssam }
25012757Ssam 
2518300Sroot sodisconnect(so, nam)
25212757Ssam 	register struct socket *so;
2538300Sroot 	struct mbuf *nam;
2544786Swnj {
2554890Swnj 	int s = splnet();
2564890Swnj 	int error;
2574786Swnj 
2584890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2594890Swnj 		error = ENOTCONN;
2604890Swnj 		goto bad;
2614890Swnj 	}
2624890Swnj 	if (so->so_state & SS_ISDISCONNECTING) {
2634890Swnj 		error = EALREADY;
2644890Swnj 		goto bad;
2654890Swnj 	}
2668300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT,
26712757Ssam 	    (struct mbuf *)0, nam, (struct mbuf *)0);
2684890Swnj bad:
2694890Swnj 	splx(s);
2704890Swnj 	return (error);
2714786Swnj }
2724786Swnj 
2734786Swnj /*
2744890Swnj  * Send on a socket.
2754890Swnj  * If send must go all at once and message is larger than
2764890Swnj  * send buffering, then hard error.
2774890Swnj  * Lock against other senders.
2784890Swnj  * If must go all at once and not enough room now, then
2794890Swnj  * inform user that this would block and do nothing.
28016412Skarels  * Otherwise, if nonblocking, send as much as possible.
2814786Swnj  */
28212757Ssam sosend(so, nam, uio, flags, rights)
2834786Swnj 	register struct socket *so;
2848300Sroot 	struct mbuf *nam;
28512757Ssam 	register struct uio *uio;
2868319Sroot 	int flags;
28712757Ssam 	struct mbuf *rights;
2884786Swnj {
2894890Swnj 	struct mbuf *top = 0;
29016412Skarels 	register struct mbuf *m, **mp;
29112757Ssam 	register int space;
292*25629Skarels 	int len, rlen = 0, error = 0, s, dontroute, first = 1;
2934786Swnj 
2947827Sroot 	if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat)
2954890Swnj 		return (EMSGSIZE);
29612757Ssam 	dontroute =
29712757Ssam 	    (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
29812757Ssam 	    (so->so_proto->pr_flags & PR_ATOMIC);
29916412Skarels 	u.u_ru.ru_msgsnd++;
300*25629Skarels 	if (rights)
301*25629Skarels 		rlen = rights->m_len;
30216412Skarels #define	snderr(errno)	{ error = errno; splx(s); goto release; }
30316412Skarels 
3046419Sroot restart:
3054890Swnj 	sblock(&so->so_snd);
30616412Skarels 	do {
30716412Skarels 		s = splnet();
30821108Skarels 		if (so->so_state & SS_CANTSENDMORE)
30916412Skarels 			snderr(EPIPE);
31016412Skarels 		if (so->so_error) {
31116412Skarels 			error = so->so_error;
31216412Skarels 			so->so_error = 0;			/* ??? */
31316412Skarels 			splx(s);
31416412Skarels 			goto release;
31516412Skarels 		}
31616412Skarels 		if ((so->so_state & SS_ISCONNECTED) == 0) {
31716412Skarels 			if (so->so_proto->pr_flags & PR_CONNREQUIRED)
31816412Skarels 				snderr(ENOTCONN);
31916412Skarels 			if (nam == 0)
32016412Skarels 				snderr(EDESTADDRREQ);
32116412Skarels 		}
32216412Skarels 		if (flags & MSG_OOB)
32316412Skarels 			space = 1024;
32416412Skarels 		else {
32516412Skarels 			space = sbspace(&so->so_snd);
326*25629Skarels 			if (space <= rlen ||
327*25629Skarels 			   (sosendallatonce(so) &&
328*25629Skarels 				space < uio->uio_resid + rlen) ||
32916992Skarels 			   (uio->uio_resid >= CLBYTES && space < CLBYTES &&
33016992Skarels 			   so->so_snd.sb_cc >= CLBYTES &&
33116992Skarels 			   (so->so_state & SS_NBIO) == 0)) {
33216412Skarels 				if (so->so_state & SS_NBIO) {
33316412Skarels 					if (first)
33416412Skarels 						error = EWOULDBLOCK;
33516412Skarels 					splx(s);
33616412Skarels 					goto release;
33716412Skarels 				}
33816412Skarels 				sbunlock(&so->so_snd);
33916412Skarels 				sbwait(&so->so_snd);
34016412Skarels 				splx(s);
34116412Skarels 				goto restart;
34216412Skarels 			}
34316412Skarels 		}
34416412Skarels 		splx(s);
34516412Skarels 		mp = &top;
346*25629Skarels 		space -= rlen;
34721108Skarels 		while (space > 0) {
34816412Skarels 			register struct iovec *iov = uio->uio_iov;
3494890Swnj 
35016412Skarels 			MGET(m, M_WAIT, MT_DATA);
35121767Skarels 			if (iov->iov_len >= NBPG && 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;
35724518Skarels 				len = MIN(CLBYTES, iov->iov_len);
35821767Skarels 				space -= CLBYTES;
35916412Skarels 			} else {
36016412Skarels nopages:
361*25629Skarels 				len = MIN(MIN(MLEN, iov->iov_len), space);
36221767Skarels 				space -= len;
36316412Skarels 			}
36416412Skarels 			error = uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio);
36516412Skarels 			m->m_len = len;
36616412Skarels 			*mp = m;
36716412Skarels 			if (error)
36816412Skarels 				goto release;
36916412Skarels 			mp = &m->m_next;
37021108Skarels 			if (uio->uio_resid <= 0)
37121108Skarels 				break;
37221108Skarels 			while (uio->uio_iov->iov_len == 0) {
37321108Skarels 				uio->uio_iov++;
37421108Skarels 				uio->uio_iovcnt--;
37521108Skarels 				if (uio->uio_iovcnt <= 0)
37621108Skarels 					panic("sosend");
37721108Skarels 			}
37816412Skarels 		}
37921108Skarels 		if (dontroute)
38021108Skarels 			so->so_options |= SO_DONTROUTE;
38121108Skarels 		s = splnet();					/* XXX */
38221108Skarels 		error = (*so->so_proto->pr_usrreq)(so,
38321108Skarels 		    (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
38421108Skarels 		    top, (caddr_t)nam, rights);
38521108Skarels 		splx(s);
38621108Skarels 		if (dontroute)
38721108Skarels 			so->so_options &= ~SO_DONTROUTE;
38821767Skarels 		rights = 0;
389*25629Skarels 		rlen = 0;
3906419Sroot 		top = 0;
39116412Skarels 		first = 0;
39214781Ssam 		if (error)
39316412Skarels 			break;
39416412Skarels 	} while (uio->uio_resid);
3954890Swnj 
3964786Swnj release:
3974890Swnj 	sbunlock(&so->so_snd);
3986419Sroot 	if (top)
3996419Sroot 		m_freem(top);
40021108Skarels 	if (error == EPIPE)
40121108Skarels 		psignal(u.u_procp, SIGPIPE);
4024786Swnj 	return (error);
4034786Swnj }
4044786Swnj 
405*25629Skarels /*
406*25629Skarels  * Implement receive operations on a socket.
407*25629Skarels  * We depend on the way that records are added to the sockbuf
408*25629Skarels  * by sbappend*.  In particular, each record (mbufs linked through m_next)
409*25629Skarels  * must begin with an address if the protocol so specifies,
410*25629Skarels  * followed by an optional mbuf containing access rights if supported
411*25629Skarels  * by the protocol, and then zero or more mbufs of data.
412*25629Skarels  * In order to avoid blocking network interrupts for the entire time here,
413*25629Skarels  * we splx() while doing the actual copy to user space.
414*25629Skarels  * Although the sockbuf is locked, new data may still be appended,
415*25629Skarels  * and thus we must maintain consistency of the sockbuf during that time.
416*25629Skarels  */
41712757Ssam soreceive(so, aname, uio, flags, rightsp)
4184786Swnj 	register struct socket *so;
4198300Sroot 	struct mbuf **aname;
42012757Ssam 	register struct uio *uio;
4218319Sroot 	int flags;
42212757Ssam 	struct mbuf **rightsp;
4234786Swnj {
4244786Swnj 	register struct mbuf *m, *n;
42516993Skarels 	register int len, error = 0, s, tomark;
42612757Ssam 	struct protosw *pr = so->so_proto;
42716993Skarels 	struct mbuf *nextrecord;
42812757Ssam 	int moff;
4294786Swnj 
43012757Ssam 	if (rightsp)
43112757Ssam 		*rightsp = 0;
43212757Ssam 	if (aname)
43312757Ssam 		*aname = 0;
43412757Ssam 	if (flags & MSG_OOB) {
4359635Ssam 		m = m_get(M_WAIT, MT_DATA);
43612757Ssam 		error = (*pr->pr_usrreq)(so, PRU_RCVOOB,
43724768Skarels 		    m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0);
4388594Sroot 		if (error)
43910137Ssam 			goto bad;
4408319Sroot 		do {
44110137Ssam 			len = uio->uio_resid;
4428319Sroot 			if (len > m->m_len)
4438319Sroot 				len = m->m_len;
4448594Sroot 			error =
4458793Sroot 			    uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio);
4468319Sroot 			m = m_free(m);
4478594Sroot 		} while (uio->uio_resid && error == 0 && m);
44810137Ssam bad:
4498319Sroot 		if (m)
4508771Sroot 			m_freem(m);
4518594Sroot 		return (error);
4528319Sroot 	}
4538319Sroot 
4544890Swnj restart:
4554890Swnj 	sblock(&so->so_rcv);
4568835Sroot 	s = splnet();
4574890Swnj 
4584890Swnj #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
4594786Swnj 	if (so->so_rcv.sb_cc == 0) {
4605168Swnj 		if (so->so_error) {
4615168Swnj 			error = so->so_error;
4625168Swnj 			so->so_error = 0;
4635168Swnj 			splx(s);
4645168Swnj 			goto release;
4655168Swnj 		}
4664890Swnj 		if (so->so_state & SS_CANTRCVMORE) {
4674890Swnj 			splx(s);
4684890Swnj 			goto release;
4694890Swnj 		}
4705015Sroot 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
4715015Sroot 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
4725015Sroot 			rcverr(ENOTCONN);
473*25629Skarels 		if (uio->uio_resid == 0)
474*25629Skarels 			goto release;
4756214Swnj 		if (so->so_state & SS_NBIO)
4765168Swnj 			rcverr(EWOULDBLOCK);
4774890Swnj 		sbunlock(&so->so_rcv);
4784971Swnj 		sbwait(&so->so_rcv);
4795012Swnj 		splx(s);
4804890Swnj 		goto restart;
4814786Swnj 	}
4828041Sroot 	u.u_ru.ru_msgrcv++;
4834829Swnj 	m = so->so_rcv.sb_mb;
484*25629Skarels 	if (m == 0)
485*25629Skarels 		panic("receive 1");
486*25629Skarels 	nextrecord = m->m_act;
48712757Ssam 	if (pr->pr_flags & PR_ADDR) {
488*25629Skarels 		if (m->m_type != MT_SONAME)
48916993Skarels 			panic("receive 1a");
49016993Skarels 		if (flags & MSG_PEEK) {
49116993Skarels 			if (aname)
4928319Sroot 				*aname = m_copy(m, 0, m->m_len);
493*25629Skarels 			m = m->m_next;
49416993Skarels 		} else {
495*25629Skarels 			sbfree(&so->so_rcv, m);
49616993Skarels 			if (aname) {
49716993Skarels 				*aname = m;
498*25629Skarels 				m = m->m_next;
499*25629Skarels 				(*aname)->m_next = 0;
500*25629Skarels 			} else {
501*25629Skarels 				MFREE(m, n);
502*25629Skarels 				nextrecord = m->m_act;
503*25629Skarels 				m = n;
504*25629Skarels 			}
50516993Skarels 		}
50616993Skarels 	}
50716993Skarels 	if (m && m->m_type == MT_RIGHTS) {
50816993Skarels 		if ((pr->pr_flags & PR_RIGHTS) == 0)
50912757Ssam 			panic("receive 2a");
51016993Skarels 		if (flags & MSG_PEEK) {
51116993Skarels 			if (rightsp)
51212757Ssam 				*rightsp = m_copy(m, 0, m->m_len);
513*25629Skarels 			m = m->m_next;
51416993Skarels 		} else {
515*25629Skarels 			sbfree(&so->so_rcv, m);
51616993Skarels 			if (rightsp) {
51716993Skarels 				*rightsp = m;
518*25629Skarels 				n = m->m_next;
519*25629Skarels 				m->m_next = 0;
520*25629Skarels 				m = n;
521*25629Skarels 			} else {
522*25629Skarels 				MFREE(m, n);
523*25629Skarels 				m = n;
524*25629Skarels 			}
52512757Ssam 		}
5264890Swnj 	}
5278319Sroot 	moff = 0;
5288319Sroot 	tomark = so->so_oobmark;
52916993Skarels 	while (m && uio->uio_resid > 0 && error == 0) {
530*25629Skarels 		if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
531*25629Skarels 			panic("receive 3");
5327827Sroot 		len = uio->uio_resid;
5337747Sroot 		so->so_state &= ~SS_RCVATMARK;
5348319Sroot 		if (tomark && len > tomark)
5358319Sroot 			len = tomark;
53621767Skarels 		if (len > m->m_len - moff)
5378319Sroot 			len = m->m_len - moff;
538*25629Skarels 		so->so_rcv.sb_mb = m;
539*25629Skarels 		m->m_act = nextrecord;
5404786Swnj 		splx(s);
5418594Sroot 		error =
5428793Sroot 		    uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio);
5434786Swnj 		s = splnet();
54421767Skarels 		if (len == m->m_len - moff) {
545*25629Skarels 			if (flags & MSG_PEEK) {
546*25629Skarels 				m = m->m_next;
547*25629Skarels 				moff = 0;
548*25629Skarels 			} else {
549*25629Skarels 				sbfree(&so->so_rcv, m);
55016993Skarels 				nextrecord = m->m_act;
5518319Sroot 				MFREE(m, n);
552*25629Skarels 				so->so_rcv.sb_mb = m = n;
553*25629Skarels 			}
5544786Swnj 		} else {
55512757Ssam 			if (flags & MSG_PEEK)
5568319Sroot 				moff += len;
5578319Sroot 			else {
5588319Sroot 				m->m_off += len;
5598319Sroot 				m->m_len -= len;
5608319Sroot 				so->so_rcv.sb_cc -= len;
5618319Sroot 			}
5624786Swnj 		}
56312757Ssam 		if ((flags & MSG_PEEK) == 0 && so->so_oobmark) {
5647747Sroot 			so->so_oobmark -= len;
5657747Sroot 			if (so->so_oobmark == 0) {
5667747Sroot 				so->so_state |= SS_RCVATMARK;
5677747Sroot 				break;
5687747Sroot 			}
5697747Sroot 		}
5708319Sroot 		if (tomark) {
5718319Sroot 			tomark -= len;
5728319Sroot 			if (tomark == 0)
5738319Sroot 				break;
5748319Sroot 		}
57516993Skarels 	}
57616993Skarels 	if ((flags & MSG_PEEK) == 0) {
577*25629Skarels 		if (so->so_rcv.sb_mb == 0)
57816993Skarels 			so->so_rcv.sb_mb = nextrecord;
57916993Skarels 		else if (pr->pr_flags & PR_ATOMIC)
58016993Skarels 			(void) sbdroprecord(&so->so_rcv);
58116993Skarels 		if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
58216993Skarels 			(*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
58316993Skarels 			    (struct mbuf *)0, (struct mbuf *)0);
584*25629Skarels 		if (error == 0 && rightsp && *rightsp &&
585*25629Skarels 		    pr->pr_domain->dom_externalize)
586*25629Skarels 			error = (*pr->pr_domain->dom_externalize)(*rightsp);
58716993Skarels 	}
5884890Swnj release:
5894916Swnj 	sbunlock(&so->so_rcv);
5904890Swnj 	splx(s);
5914916Swnj 	return (error);
5924786Swnj }
5934786Swnj 
59410267Ssam soshutdown(so, how)
59512757Ssam 	register struct socket *so;
59612757Ssam 	register int how;
59710267Ssam {
59812757Ssam 	register struct protosw *pr = so->so_proto;
59910267Ssam 
60010267Ssam 	how++;
60112757Ssam 	if (how & FREAD)
60212757Ssam 		sorflush(so);
60310267Ssam 	if (how & FWRITE)
60412757Ssam 		return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN,
60512757Ssam 		    (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
60610267Ssam 	return (0);
60710267Ssam }
60810267Ssam 
60912757Ssam sorflush(so)
61012757Ssam 	register struct socket *so;
61112757Ssam {
61212757Ssam 	register struct sockbuf *sb = &so->so_rcv;
61312757Ssam 	register struct protosw *pr = so->so_proto;
61412757Ssam 	register int s;
61512757Ssam 	struct sockbuf asb;
61612757Ssam 
61712757Ssam 	sblock(sb);
61812757Ssam 	s = splimp();
61912757Ssam 	socantrcvmore(so);
62012757Ssam 	sbunlock(sb);
62112757Ssam 	asb = *sb;
62212757Ssam 	bzero((caddr_t)sb, sizeof (*sb));
62312757Ssam 	splx(s);
62416993Skarels 	if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose)
62516993Skarels 		(*pr->pr_domain->dom_dispose)(asb.sb_mb);
62612757Ssam 	sbrelease(&asb);
62712757Ssam }
62812757Ssam 
62918553Skarels sosetopt(so, level, optname, m0)
63012757Ssam 	register struct socket *so;
63110267Ssam 	int level, optname;
63218553Skarels 	struct mbuf *m0;
63310267Ssam {
63417158Ssam 	int error = 0;
63518553Skarels 	register struct mbuf *m = m0;
63610267Ssam 
63717158Ssam 	if (level != SOL_SOCKET) {
63818369Skarels 		if (so->so_proto && so->so_proto->pr_ctloutput)
63918369Skarels 			return ((*so->so_proto->pr_ctloutput)
64018553Skarels 				  (PRCO_SETOPT, so, level, optname, &m0));
64118369Skarels 		error = ENOPROTOOPT;
64218369Skarels 	} else {
64318369Skarels 		switch (optname) {
64410267Ssam 
64518369Skarels 		case SO_LINGER:
64618369Skarels 			if (m == NULL || m->m_len != sizeof (struct linger)) {
64718369Skarels 				error = EINVAL;
64818369Skarels 				goto bad;
64918369Skarels 			}
65018369Skarels 			so->so_linger = mtod(m, struct linger *)->l_linger;
65118369Skarels 			/* fall thru... */
65217158Ssam 
65318369Skarels 		case SO_DEBUG:
65418369Skarels 		case SO_KEEPALIVE:
65518369Skarels 		case SO_DONTROUTE:
65618369Skarels 		case SO_USELOOPBACK:
65718369Skarels 		case SO_BROADCAST:
65818369Skarels 		case SO_REUSEADDR:
65918369Skarels 			if (m == NULL || m->m_len < sizeof (int)) {
66018369Skarels 				error = EINVAL;
66118369Skarels 				goto bad;
66218369Skarels 			}
66318369Skarels 			if (*mtod(m, int *))
66418369Skarels 				so->so_options |= optname;
66518369Skarels 			else
66618369Skarels 				so->so_options &= ~optname;
66718369Skarels 			break;
66818369Skarels 
66918369Skarels 		case SO_SNDBUF:
67018369Skarels 		case SO_RCVBUF:
67118369Skarels 		case SO_SNDLOWAT:
67218369Skarels 		case SO_RCVLOWAT:
67318369Skarels 		case SO_SNDTIMEO:
67418369Skarels 		case SO_RCVTIMEO:
67518369Skarels 			if (m == NULL || m->m_len < sizeof (int)) {
67618369Skarels 				error = EINVAL;
67718369Skarels 				goto bad;
67818369Skarels 			}
67918369Skarels 			switch (optname) {
68018369Skarels 
68118369Skarels 			case SO_SNDBUF:
68218369Skarels 			case SO_RCVBUF:
68318369Skarels 				if (sbreserve(optname == SO_SNDBUF ? &so->so_snd :
68418369Skarels 				    &so->so_rcv, *mtod(m, int *)) == 0) {
68518369Skarels 					error = ENOBUFS;
68618369Skarels 					goto bad;
68718369Skarels 				}
68818369Skarels 				break;
68918369Skarels 
69018369Skarels 			case SO_SNDLOWAT:
69118369Skarels 				so->so_snd.sb_lowat = *mtod(m, int *);
69218369Skarels 				break;
69318369Skarels 			case SO_RCVLOWAT:
69418369Skarels 				so->so_rcv.sb_lowat = *mtod(m, int *);
69518369Skarels 				break;
69618369Skarels 			case SO_SNDTIMEO:
69718369Skarels 				so->so_snd.sb_timeo = *mtod(m, int *);
69818369Skarels 				break;
69918369Skarels 			case SO_RCVTIMEO:
70018369Skarels 				so->so_rcv.sb_timeo = *mtod(m, int *);
70118369Skarels 				break;
70218369Skarels 			}
70318369Skarels 			break;
70418369Skarels 
70518369Skarels 		default:
70618369Skarels 			error = ENOPROTOOPT;
70718369Skarels 			break;
70817158Ssam 		}
70910267Ssam 	}
71017158Ssam bad:
71117158Ssam 	if (m)
71217158Ssam 		(void) m_free(m);
71317158Ssam 	return (error);
71410267Ssam }
71510267Ssam 
71617158Ssam sogetopt(so, level, optname, mp)
71712757Ssam 	register struct socket *so;
71810267Ssam 	int level, optname;
71917158Ssam 	struct mbuf **mp;
72017158Ssam {
72112757Ssam 	register struct mbuf *m;
72210267Ssam 
72318369Skarels 	if (level != SOL_SOCKET) {
72418369Skarels 		if (so->so_proto && so->so_proto->pr_ctloutput) {
72518369Skarels 			return ((*so->so_proto->pr_ctloutput)
72618369Skarels 				  (PRCO_GETOPT, so, level, optname, mp));
72718369Skarels 		} else
72818369Skarels 			return (ENOPROTOOPT);
72918369Skarels 	} else {
73017158Ssam 		m = m_get(M_WAIT, MT_SOOPTS);
73125502Skarels 		m->m_len = sizeof (int);
73225502Skarels 
73318369Skarels 		switch (optname) {
73417158Ssam 
73518369Skarels 		case SO_LINGER:
73618369Skarels 			m->m_len = sizeof (struct linger);
73718369Skarels 			mtod(m, struct linger *)->l_onoff =
73818369Skarels 				so->so_options & SO_LINGER;
73918369Skarels 			mtod(m, struct linger *)->l_linger = so->so_linger;
74018369Skarels 			break;
74110267Ssam 
74218369Skarels 		case SO_USELOOPBACK:
74318369Skarels 		case SO_DONTROUTE:
74418369Skarels 		case SO_DEBUG:
74518369Skarels 		case SO_KEEPALIVE:
74618369Skarels 		case SO_REUSEADDR:
74718369Skarels 		case SO_BROADCAST:
74818369Skarels 			*mtod(m, int *) = so->so_options & optname;
74918369Skarels 			break;
75018369Skarels 
75125502Skarels 		case SO_TYPE:
75225502Skarels 			*mtod(m, int *) = so->so_type;
75325502Skarels 			break;
75425502Skarels 
75524768Skarels 		case SO_ERROR:
75624768Skarels 			*mtod(m, int *) = so->so_error;
75724768Skarels 			so->so_error = 0;
75824768Skarels 			break;
75924768Skarels 
76018369Skarels 		case SO_SNDBUF:
76118369Skarels 			*mtod(m, int *) = so->so_snd.sb_hiwat;
76218369Skarels 			break;
76318369Skarels 
76418369Skarels 		case SO_RCVBUF:
76518369Skarels 			*mtod(m, int *) = so->so_rcv.sb_hiwat;
76618369Skarels 			break;
76718369Skarels 
76818369Skarels 		case SO_SNDLOWAT:
76918369Skarels 			*mtod(m, int *) = so->so_snd.sb_lowat;
77018369Skarels 			break;
77118369Skarels 
77218369Skarels 		case SO_RCVLOWAT:
77318369Skarels 			*mtod(m, int *) = so->so_rcv.sb_lowat;
77418369Skarels 			break;
77518369Skarels 
77618369Skarels 		case SO_SNDTIMEO:
77718369Skarels 			*mtod(m, int *) = so->so_snd.sb_timeo;
77818369Skarels 			break;
77918369Skarels 
78018369Skarels 		case SO_RCVTIMEO:
78118369Skarels 			*mtod(m, int *) = so->so_rcv.sb_timeo;
78218369Skarels 			break;
78318369Skarels 
78418369Skarels 		default:
78518369Skarels 			m_free(m);
78618369Skarels 			return (ENOPROTOOPT);
78718369Skarels 		}
78818369Skarels 		*mp = m;
78918369Skarels 		return (0);
79010267Ssam 	}
79110267Ssam }
79210267Ssam 
7935423Swnj sohasoutofband(so)
79412757Ssam 	register struct socket *so;
7955423Swnj {
79623233Skarels 	struct proc *p;
7975423Swnj 
79823233Skarels 	if (so->so_pgrp < 0)
79923233Skarels 		gsignal(-so->so_pgrp, SIGURG);
80023233Skarels 	else if (so->so_pgrp > 0 && (p = pfind(so->so_pgrp)) != 0)
80123233Skarels 		psignal(p, SIGURG);
80224768Skarels 	if (so->so_rcv.sb_sel) {
80324768Skarels 		selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL);
80424768Skarels 		so->so_rcv.sb_sel = 0;
80524768Skarels 		so->so_rcv.sb_flags &= ~SB_COLL;
80624768Skarels 	}
8075423Swnj }
808