xref: /csrg-svn/sys/kern/uipc_socket.c (revision 37478)
123421Smckusick /*
235384Skarels  * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
333185Sbostic  * All rights reserved.
423421Smckusick  *
533185Sbostic  * Redistribution and use in source and binary forms are permitted
634861Sbostic  * provided that the above copyright notice and this paragraph are
734861Sbostic  * duplicated in all such forms and that any documentation,
834861Sbostic  * advertising materials, and other materials related to such
934861Sbostic  * distribution and use acknowledge that the software was developed
1034861Sbostic  * by the University of California, Berkeley.  The name of the
1134861Sbostic  * University may not be used to endorse or promote products derived
1234861Sbostic  * from this software without specific prior written permission.
1334861Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1434861Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1534861Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1633185Sbostic  *
17*37478Ssklower  *	@(#)uipc_socket.c	7.13 (Berkeley) 04/22/89
1823421Smckusick  */
194786Swnj 
2017102Sbloom #include "param.h"
2117102Sbloom #include "dir.h"
2217102Sbloom #include "user.h"
2317102Sbloom #include "proc.h"
2417102Sbloom #include "file.h"
2535384Skarels #include "malloc.h"
2617102Sbloom #include "mbuf.h"
2717102Sbloom #include "domain.h"
2817102Sbloom #include "protosw.h"
2917102Sbloom #include "socket.h"
3017102Sbloom #include "socketvar.h"
314786Swnj 
324786Swnj /*
338300Sroot  * Socket operation routines.
348300Sroot  * These routines are called by the routines in
358300Sroot  * sys_socket.c or from a system process, and
368300Sroot  * implement the semantics of socket operations by
378300Sroot  * switching out to the protocol specific routines.
3812757Ssam  *
3912757Ssam  * TODO:
4012757Ssam  *	test socketpair
4121767Skarels  *	clean up async
4212757Ssam  *	out-of-band is a kludge
434786Swnj  */
448594Sroot /*ARGSUSED*/
4510267Ssam socreate(dom, aso, type, proto)
464786Swnj 	struct socket **aso;
4712757Ssam 	register int type;
4812757Ssam 	int proto;
494786Swnj {
504786Swnj 	register struct protosw *prp;
514786Swnj 	register struct socket *so;
5212757Ssam 	register int error;
534786Swnj 
544890Swnj 	if (proto)
5521767Skarels 		prp = pffindproto(dom, proto, type);
564890Swnj 	else
579168Ssam 		prp = pffindtype(dom, type);
584890Swnj 	if (prp == 0)
594890Swnj 		return (EPROTONOSUPPORT);
608300Sroot 	if (prp->pr_type != type)
618300Sroot 		return (EPROTOTYPE);
62*37478Ssklower 	MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_WAIT);
63*37478Ssklower 	bzero((caddr_t)so, sizeof(*so));
649168Ssam 	so->so_type = type;
656214Swnj 	if (u.u_uid == 0)
666214Swnj 		so->so_state = SS_PRIV;
674786Swnj 	so->so_proto = prp;
6812757Ssam 	error =
6912757Ssam 	    (*prp->pr_usrreq)(so, PRU_ATTACH,
7021767Skarels 		(struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0);
714979Swnj 	if (error) {
727507Sroot 		so->so_state |= SS_NOFDREF;
737180Swnj 		sofree(so);
744890Swnj 		return (error);
754786Swnj 	}
764786Swnj 	*aso = so;
774786Swnj 	return (0);
784786Swnj }
794786Swnj 
8010267Ssam sobind(so, nam)
818300Sroot 	struct socket *so;
828300Sroot 	struct mbuf *nam;
838300Sroot {
848300Sroot 	int s = splnet();
858300Sroot 	int error;
868300Sroot 
878300Sroot 	error =
8812757Ssam 	    (*so->so_proto->pr_usrreq)(so, PRU_BIND,
8912757Ssam 		(struct mbuf *)0, nam, (struct mbuf *)0);
908300Sroot 	splx(s);
918300Sroot 	return (error);
928300Sroot }
938300Sroot 
948300Sroot solisten(so, backlog)
9512757Ssam 	register struct socket *so;
968300Sroot 	int backlog;
978300Sroot {
9812757Ssam 	int s = splnet(), error;
998300Sroot 
10012757Ssam 	error =
10112757Ssam 	    (*so->so_proto->pr_usrreq)(so, PRU_LISTEN,
10212757Ssam 		(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
1038300Sroot 	if (error) {
1048300Sroot 		splx(s);
1058300Sroot 		return (error);
1068300Sroot 	}
1078300Sroot 	if (so->so_q == 0) {
1088300Sroot 		so->so_q = so;
1098300Sroot 		so->so_q0 = so;
1108300Sroot 		so->so_options |= SO_ACCEPTCONN;
1118300Sroot 	}
1128300Sroot 	if (backlog < 0)
1138300Sroot 		backlog = 0;
11435384Skarels 	so->so_qlimit = min(backlog, SOMAXCONN);
11512493Ssam 	splx(s);
1168300Sroot 	return (0);
1178300Sroot }
1188300Sroot 
1194916Swnj sofree(so)
12012757Ssam 	register struct socket *so;
1214916Swnj {
1224916Swnj 
12331810Skarels 	if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
12431810Skarels 		return;
1257507Sroot 	if (so->so_head) {
1267507Sroot 		if (!soqremque(so, 0) && !soqremque(so, 1))
1277507Sroot 			panic("sofree dq");
1287507Sroot 		so->so_head = 0;
1297507Sroot 	}
1304950Swnj 	sbrelease(&so->so_snd);
13112757Ssam 	sorflush(so);
132*37478Ssklower 	FREE(so, M_SOCKET);
1334916Swnj }
1344916Swnj 
1354786Swnj /*
1364890Swnj  * Close a socket on last file table reference removal.
1374890Swnj  * Initiate disconnect if connected.
1384890Swnj  * Free socket when disconnect complete.
1394829Swnj  */
14012757Ssam soclose(so)
1414829Swnj 	register struct socket *so;
1424829Swnj {
1434890Swnj 	int s = splnet();		/* conservative */
14433372Sbostic 	int error = 0;
1454829Swnj 
1467507Sroot 	if (so->so_options & SO_ACCEPTCONN) {
1477507Sroot 		while (so->so_q0 != so)
14810399Ssam 			(void) soabort(so->so_q0);
1497507Sroot 		while (so->so_q != so)
15010399Ssam 			(void) soabort(so->so_q);
1517507Sroot 	}
1524890Swnj 	if (so->so_pcb == 0)
1534890Swnj 		goto discard;
1544890Swnj 	if (so->so_state & SS_ISCONNECTED) {
1554890Swnj 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
15626245Skarels 			error = sodisconnect(so);
15712757Ssam 			if (error)
15812757Ssam 				goto drop;
1594890Swnj 		}
16010267Ssam 		if (so->so_options & SO_LINGER) {
1615281Sroot 			if ((so->so_state & SS_ISDISCONNECTING) &&
16212757Ssam 			    (so->so_state & SS_NBIO))
16312757Ssam 				goto drop;
1645281Sroot 			while (so->so_state & SS_ISCONNECTED)
1655281Sroot 				sleep((caddr_t)&so->so_timeo, PZERO+1);
1664890Swnj 		}
1674890Swnj 	}
1685580Sroot drop:
1696880Ssam 	if (so->so_pcb) {
17012757Ssam 		int error2 =
17112757Ssam 		    (*so->so_proto->pr_usrreq)(so, PRU_DETACH,
17212757Ssam 			(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
17312757Ssam 		if (error == 0)
17412757Ssam 			error = error2;
1756880Ssam 	}
1764890Swnj discard:
17710399Ssam 	if (so->so_state & SS_NOFDREF)
17810399Ssam 		panic("soclose: NOFDREF");
1797507Sroot 	so->so_state |= SS_NOFDREF;
1804950Swnj 	sofree(so);
1814890Swnj 	splx(s);
18212757Ssam 	return (error);
1834829Swnj }
1844829Swnj 
18510399Ssam /*
18610399Ssam  * Must be called at splnet...
18710399Ssam  */
18810399Ssam soabort(so)
18910399Ssam 	struct socket *so;
19010399Ssam {
19110399Ssam 
19212757Ssam 	return (
19312757Ssam 	    (*so->so_proto->pr_usrreq)(so, PRU_ABORT,
19412757Ssam 		(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
19510399Ssam }
19610399Ssam 
19710267Ssam soaccept(so, nam)
19812757Ssam 	register struct socket *so;
1998300Sroot 	struct mbuf *nam;
2004927Swnj {
2014927Swnj 	int s = splnet();
2024927Swnj 	int error;
2034927Swnj 
20410399Ssam 	if ((so->so_state & SS_NOFDREF) == 0)
20510399Ssam 		panic("soaccept: !NOFDREF");
20610267Ssam 	so->so_state &= ~SS_NOFDREF;
2078300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT,
20812757Ssam 	    (struct mbuf *)0, nam, (struct mbuf *)0);
2094927Swnj 	splx(s);
2104927Swnj 	return (error);
2114927Swnj }
2124927Swnj 
21310267Ssam soconnect(so, nam)
21412757Ssam 	register struct socket *so;
2158300Sroot 	struct mbuf *nam;
2164786Swnj {
21730414Skarels 	int s;
2184890Swnj 	int error;
2194786Swnj 
22030414Skarels 	if (so->so_options & SO_ACCEPTCONN)
22130414Skarels 		return (EOPNOTSUPP);
22230414Skarels 	s = splnet();
22324768Skarels 	/*
22424768Skarels 	 * If protocol is connection-based, can only connect once.
22524768Skarels 	 * Otherwise, if connected, try to disconnect first.
22624768Skarels 	 * This allows user to disconnect by connecting to, e.g.,
22724768Skarels 	 * a null address.
22824768Skarels 	 */
22924768Skarels 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) &&
23024768Skarels 	    ((so->so_proto->pr_flags & PR_CONNREQUIRED) ||
23124768Skarels 	    (error = sodisconnect(so))))
2324890Swnj 		error = EISCONN;
23324768Skarels 	else
23424768Skarels 		error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
23524768Skarels 		    (struct mbuf *)0, nam, (struct mbuf *)0);
2364890Swnj 	splx(s);
2374890Swnj 	return (error);
2384786Swnj }
2394786Swnj 
24012757Ssam soconnect2(so1, so2)
24112757Ssam 	register struct socket *so1;
24212757Ssam 	struct socket *so2;
24312757Ssam {
24412757Ssam 	int s = splnet();
24512757Ssam 	int error;
24612757Ssam 
24713113Ssam 	error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2,
24813113Ssam 	    (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0);
24912757Ssam 	splx(s);
25012757Ssam 	return (error);
25112757Ssam }
25212757Ssam 
25326245Skarels sodisconnect(so)
25412757Ssam 	register struct socket *so;
2554786Swnj {
2564890Swnj 	int s = splnet();
2574890Swnj 	int error;
2584786Swnj 
2594890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2604890Swnj 		error = ENOTCONN;
2614890Swnj 		goto bad;
2624890Swnj 	}
2634890Swnj 	if (so->so_state & SS_ISDISCONNECTING) {
2644890Swnj 		error = EALREADY;
2654890Swnj 		goto bad;
2664890Swnj 	}
2678300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT,
26826245Skarels 	    (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
2694890Swnj bad:
2704890Swnj 	splx(s);
2714890Swnj 	return (error);
2724786Swnj }
2734786Swnj 
2744786Swnj /*
2754890Swnj  * Send on a socket.
2764890Swnj  * If send must go all at once and message is larger than
2774890Swnj  * send buffering, then hard error.
2784890Swnj  * Lock against other senders.
2794890Swnj  * If must go all at once and not enough room now, then
2804890Swnj  * inform user that this would block and do nothing.
28116412Skarels  * Otherwise, if nonblocking, send as much as possible.
2824786Swnj  */
28335384Skarels sosend(so, nam, uio, flags, rights, control)
2844786Swnj 	register struct socket *so;
2858300Sroot 	struct mbuf *nam;
28612757Ssam 	register struct uio *uio;
2878319Sroot 	int flags;
28835384Skarels 	struct mbuf *rights, *control;
2894786Swnj {
29035384Skarels 	struct mbuf *top = 0, **mp;
29135384Skarels 	register struct mbuf *m;
29235384Skarels 	register int space, len;
29335384Skarels 	int rlen = 0, error = 0, s, dontroute, first = 1, mlen;
29435384Skarels 	int atomic = sosendallatonce(so);
2954786Swnj 
29635384Skarels 	if (atomic && uio->uio_resid > so->so_snd.sb_hiwat)
2974890Swnj 		return (EMSGSIZE);
29812757Ssam 	dontroute =
29912757Ssam 	    (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
30012757Ssam 	    (so->so_proto->pr_flags & PR_ATOMIC);
30116412Skarels 	u.u_ru.ru_msgsnd++;
30225629Skarels 	if (rights)
30325629Skarels 		rlen = rights->m_len;
30416412Skarels #define	snderr(errno)	{ error = errno; splx(s); goto release; }
30516412Skarels 
3066419Sroot restart:
3074890Swnj 	sblock(&so->so_snd);
30816412Skarels 	do {
30916412Skarels 		s = splnet();
31021108Skarels 		if (so->so_state & SS_CANTSENDMORE)
31116412Skarels 			snderr(EPIPE);
312*37478Ssklower 		if (so->so_error)
313*37478Ssklower 			snderr(so->so_error);
31416412Skarels 		if ((so->so_state & SS_ISCONNECTED) == 0) {
315*37478Ssklower 			if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
316*37478Ssklower 				if (!uio->uio_resid && !rights && control) {
317*37478Ssklower 					snderr((*so->so_proto->pr_usrreq)(so,
318*37478Ssklower 				    (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
319*37478Ssklower 					    top, (caddr_t)0, rights, control));
320*37478Ssklower 				} else if (so->so_state & SS_ISCONFIRMING)
321*37478Ssklower 					/* is ok */;
322*37478Ssklower 				else
323*37478Ssklower 					snderr(ENOTCONN);
324*37478Ssklower 			} else if (nam == 0)
32516412Skarels 				snderr(EDESTADDRREQ);
32616412Skarels 		}
32716412Skarels 		if (flags & MSG_OOB)
32816412Skarels 			space = 1024;
32916412Skarels 		else {
33016412Skarels 			space = sbspace(&so->so_snd);
33125629Skarels 			if (space <= rlen ||
33235384Skarels 			   (atomic && space < uio->uio_resid + rlen) ||
33335384Skarels 			   (uio->uio_resid >= MCLBYTES && space < MCLBYTES &&
33435384Skarels 			   so->so_snd.sb_cc >= MCLBYTES &&
33516992Skarels 			   (so->so_state & SS_NBIO) == 0)) {
33616412Skarels 				if (so->so_state & SS_NBIO) {
33716412Skarels 					if (first)
33816412Skarels 						error = EWOULDBLOCK;
33916412Skarels 					splx(s);
34016412Skarels 					goto release;
34116412Skarels 				}
34216412Skarels 				sbunlock(&so->so_snd);
34316412Skarels 				sbwait(&so->so_snd);
34416412Skarels 				splx(s);
34516412Skarels 				goto restart;
34616412Skarels 			}
34716412Skarels 		}
34816412Skarels 		splx(s);
34916412Skarels 		mp = &top;
35025629Skarels 		space -= rlen;
35135384Skarels 		do {
35235384Skarels 		   do {
35335384Skarels 			if (top == 0) {
35435384Skarels 				MGETHDR(m, M_WAIT, MT_DATA);
35535384Skarels 				mlen = MHLEN;
35635384Skarels 				m->m_pkthdr.len = 0;
35735384Skarels 				m->m_pkthdr.rcvif = (struct ifnet *)0;
35835384Skarels 			} else {
35935384Skarels 				MGET(m, M_WAIT, MT_DATA);
36035384Skarels 				mlen = MLEN;
36135384Skarels 			}
36235384Skarels 			if (uio->uio_resid >= MINCLSIZE && space >= MCLBYTES) {
36335384Skarels 				MCLGET(m, M_WAIT);
36435384Skarels 				if ((m->m_flags & M_EXT) == 0)
36516412Skarels 					goto nopages;
36635384Skarels 				mlen = MCLBYTES;
36735384Skarels #ifdef	MAPPED_MBUFS
36835384Skarels 				len = min(MCLBYTES, uio->uio_resid);
36935384Skarels 				if (len < mlen - max_hdr)
37035384Skarels 					m->m_data += max_hdr;
37135384Skarels #else
37235384Skarels 				len = min(MCLBYTES - max_hdr, uio->uio_resid);
37335384Skarels 				m->m_data += max_hdr;
37435384Skarels #endif
37535384Skarels 				space -= MCLBYTES;
37616412Skarels 			} else {
37716412Skarels nopages:
37835384Skarels 				len = min(min(mlen, uio->uio_resid), space);
37921767Skarels 				space -= len;
38035384Skarels 				/*
38135384Skarels 				 * For datagram protocols, leave room
38235384Skarels 				 * for protocol headers in first mbuf.
38335384Skarels 				 */
38435391Skarels 				if (atomic && top == 0 && len < mlen)
38535384Skarels 					MH_ALIGN(m, len);
38616412Skarels 			}
38716412Skarels 			error = uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio);
38816412Skarels 			m->m_len = len;
38916412Skarels 			*mp = m;
39035384Skarels 			top->m_pkthdr.len += len;
39116412Skarels 			if (error)
39216412Skarels 				goto release;
39316412Skarels 			mp = &m->m_next;
39435384Skarels 			if (uio->uio_resid <= 0) {
39535384Skarels 				if ((flags & MSG_EOR) && top)
39635384Skarels 					top->m_flags |= M_EOR;
39721108Skarels 				break;
39835384Skarels 			}
39935384Skarels 		    } while (space > 0 && atomic);
40035384Skarels 		    if (dontroute)
40135384Skarels 			    so->so_options |= SO_DONTROUTE;
40235384Skarels 		    s = splnet();				/* XXX */
40335384Skarels 		    error = (*so->so_proto->pr_usrreq)(so,
40435384Skarels 			(flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
40535384Skarels 			top, (caddr_t)nam, rights, control);
40635384Skarels 		    splx(s);
40735384Skarels 		    if (dontroute)
40835384Skarels 			    so->so_options &= ~SO_DONTROUTE;
40935384Skarels 		    rights = 0;
41035384Skarels 		    rlen = 0;
41135384Skarels 		    top = 0;
41235384Skarels 		    mp = &top;
41335384Skarels 		    first = 0;
41435384Skarels 		    if (error)
41535384Skarels 			goto release;
41635384Skarels 		} while (uio->uio_resid && space > 0);
41716412Skarels 	} while (uio->uio_resid);
4184890Swnj 
4194786Swnj release:
4204890Swnj 	sbunlock(&so->so_snd);
4216419Sroot 	if (top)
4226419Sroot 		m_freem(top);
42321108Skarels 	if (error == EPIPE)
42421108Skarels 		psignal(u.u_procp, SIGPIPE);
4254786Swnj 	return (error);
4264786Swnj }
4274786Swnj 
42825629Skarels /*
42925629Skarels  * Implement receive operations on a socket.
43025629Skarels  * We depend on the way that records are added to the sockbuf
43125629Skarels  * by sbappend*.  In particular, each record (mbufs linked through m_next)
43225629Skarels  * must begin with an address if the protocol so specifies,
43325629Skarels  * followed by an optional mbuf containing access rights if supported
43425629Skarels  * by the protocol, and then zero or more mbufs of data.
43525629Skarels  * In order to avoid blocking network interrupts for the entire time here,
43625629Skarels  * we splx() while doing the actual copy to user space.
43725629Skarels  * Although the sockbuf is locked, new data may still be appended,
43825629Skarels  * and thus we must maintain consistency of the sockbuf during that time.
43925629Skarels  */
44035384Skarels soreceive(so, aname, uio, flagsp, rightsp, controlp)
4414786Swnj 	register struct socket *so;
4428300Sroot 	struct mbuf **aname;
44312757Ssam 	register struct uio *uio;
44435384Skarels 	int *flagsp;
44535384Skarels 	struct mbuf **rightsp, **controlp;
4464786Swnj {
44726958Skarels 	register struct mbuf *m;
44835384Skarels 	register int flags, len, error = 0, s, offset;
44912757Ssam 	struct protosw *pr = so->so_proto;
45016993Skarels 	struct mbuf *nextrecord;
45112757Ssam 	int moff;
4524786Swnj 
45312757Ssam 	if (rightsp)
45412757Ssam 		*rightsp = 0;
45512757Ssam 	if (aname)
45612757Ssam 		*aname = 0;
45735384Skarels 	if (controlp)
45835384Skarels 		*controlp = 0;
45935384Skarels 	if (flagsp)
46035384Skarels 		flags = *flagsp &~ MSG_EOR;
46135384Skarels 	else
46235384Skarels 		flags = 0;
46312757Ssam 	if (flags & MSG_OOB) {
4649635Ssam 		m = m_get(M_WAIT, MT_DATA);
46512757Ssam 		error = (*pr->pr_usrreq)(so, PRU_RCVOOB,
46624768Skarels 		    m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0);
4678594Sroot 		if (error)
46810137Ssam 			goto bad;
4698319Sroot 		do {
47010137Ssam 			len = uio->uio_resid;
4718319Sroot 			if (len > m->m_len)
4728319Sroot 				len = m->m_len;
4738594Sroot 			error =
4748793Sroot 			    uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio);
4758319Sroot 			m = m_free(m);
4768594Sroot 		} while (uio->uio_resid && error == 0 && m);
47710137Ssam bad:
4788319Sroot 		if (m)
4798771Sroot 			m_freem(m);
4808594Sroot 		return (error);
4818319Sroot 	}
482*37478Ssklower 	if (so->so_state & SS_ISCONFIRMING && uio->uio_resid)
48335384Skarels 		(*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
48435384Skarels 		    (struct mbuf *)0, (struct mbuf *)0);
4858319Sroot 
4864890Swnj restart:
4874890Swnj 	sblock(&so->so_rcv);
4888835Sroot 	s = splnet();
4894890Swnj 
490*37478Ssklower 	m = so->so_rcv.sb_mb;
491*37478Ssklower 	if (m == 0) {
492*37478Ssklower 		if (so->so_rcv.sb_cc)
493*37478Ssklower 			panic("receive 1");
4945168Swnj 		if (so->so_error) {
4955168Swnj 			error = so->so_error;
4965168Swnj 			so->so_error = 0;
4975168Swnj 			goto release;
4985168Swnj 		}
49932567Sbostic 		if (so->so_state & SS_CANTRCVMORE)
5004890Swnj 			goto release;
50132567Sbostic 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
50232567Sbostic 		    (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
50332567Sbostic 			error = ENOTCONN;
50432567Sbostic 			goto release;
5054890Swnj 		}
50625629Skarels 		if (uio->uio_resid == 0)
50725629Skarels 			goto release;
50832567Sbostic 		if (so->so_state & SS_NBIO) {
50932567Sbostic 			error = EWOULDBLOCK;
51032567Sbostic 			goto release;
51132567Sbostic 		}
5124890Swnj 		sbunlock(&so->so_rcv);
5134971Swnj 		sbwait(&so->so_rcv);
5145012Swnj 		splx(s);
5154890Swnj 		goto restart;
5164786Swnj 	}
5178041Sroot 	u.u_ru.ru_msgrcv++;
51835384Skarels if (m->m_type == 0)
51935384Skarels panic("receive 3a");
52035384Skarels 	nextrecord = m->m_nextpkt;
52112757Ssam 	if (pr->pr_flags & PR_ADDR) {
52225629Skarels 		if (m->m_type != MT_SONAME)
52316993Skarels 			panic("receive 1a");
52416993Skarels 		if (flags & MSG_PEEK) {
52516993Skarels 			if (aname)
5268319Sroot 				*aname = m_copy(m, 0, m->m_len);
52725629Skarels 			m = m->m_next;
52816993Skarels 		} else {
52925629Skarels 			sbfree(&so->so_rcv, m);
53016993Skarels 			if (aname) {
53116993Skarels 				*aname = m;
53235384Skarels 				so->so_rcv.sb_mb = m->m_next;
53335384Skarels 				m->m_next = 0;
53435384Skarels 				m = so->so_rcv.sb_mb;
53525629Skarels 			} else {
53626958Skarels 				MFREE(m, so->so_rcv.sb_mb);
53726958Skarels 				m = so->so_rcv.sb_mb;
53825629Skarels 			}
53916993Skarels 		}
54016993Skarels 	}
54116993Skarels 	if (m && m->m_type == MT_RIGHTS) {
54216993Skarels 		if ((pr->pr_flags & PR_RIGHTS) == 0)
54326958Skarels 			panic("receive 2");
54416993Skarels 		if (flags & MSG_PEEK) {
54516993Skarels 			if (rightsp)
54612757Ssam 				*rightsp = m_copy(m, 0, m->m_len);
54725629Skarels 			m = m->m_next;
54816993Skarels 		} else {
54925629Skarels 			sbfree(&so->so_rcv, m);
55016993Skarels 			if (rightsp) {
55116993Skarels 				*rightsp = m;
55226958Skarels 				so->so_rcv.sb_mb = m->m_next;
55325629Skarels 				m->m_next = 0;
55426958Skarels 				m = so->so_rcv.sb_mb;
55525629Skarels 			} else {
55626958Skarels 				MFREE(m, so->so_rcv.sb_mb);
55726958Skarels 				m = so->so_rcv.sb_mb;
55825629Skarels 			}
55912757Ssam 		}
5604890Swnj 	}
56135384Skarels 	if (m && m->m_type == MT_CONTROL) {
56235384Skarels 		if (flags & MSG_PEEK) {
56335384Skarels 			if (controlp)
56435384Skarels 				*controlp = m_copy(m, 0, m->m_len);
56535384Skarels 			m = m->m_next;
56635384Skarels 		} else {
56735384Skarels 			sbfree(&so->so_rcv, m);
56835384Skarels 			if (controlp) {
56935384Skarels 				*controlp = m;
57035384Skarels 				so->so_rcv.sb_mb = m->m_next;
57135384Skarels 				m->m_next = 0;
57235384Skarels 				m = so->so_rcv.sb_mb;
57335384Skarels 			} else {
57435384Skarels 				MFREE(m, so->so_rcv.sb_mb);
57535384Skarels 				m = so->so_rcv.sb_mb;
57635384Skarels 			}
57735384Skarels 		}
57835384Skarels 	}
57935384Skarels 	if (m)
58035384Skarels 		m->m_nextpkt = nextrecord;
5818319Sroot 	moff = 0;
58232092Skarels 	offset = 0;
58316993Skarels 	while (m && uio->uio_resid > 0 && error == 0) {
58435384Skarels 		if (m->m_type == MT_OOBDATA)
58535384Skarels 			flags |= MSG_OOB;
58635384Skarels 		else if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
58725629Skarels 			panic("receive 3");
58835384Skarels 		if (m->m_flags & M_EOR)
58935384Skarels 			flags |= MSG_EOR;
5907827Sroot 		len = uio->uio_resid;
5917747Sroot 		so->so_state &= ~SS_RCVATMARK;
59232092Skarels 		if (so->so_oobmark && len > so->so_oobmark - offset)
59332092Skarels 			len = so->so_oobmark - offset;
59421767Skarels 		if (len > m->m_len - moff)
5958319Sroot 			len = m->m_len - moff;
5964786Swnj 		splx(s);
5978594Sroot 		error =
5988793Sroot 		    uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio);
5994786Swnj 		s = splnet();
60021767Skarels 		if (len == m->m_len - moff) {
60125629Skarels 			if (flags & MSG_PEEK) {
60225629Skarels 				m = m->m_next;
60325629Skarels 				moff = 0;
60425629Skarels 			} else {
60535384Skarels 				nextrecord = m->m_nextpkt;
60625629Skarels 				sbfree(&so->so_rcv, m);
60726958Skarels 				MFREE(m, so->so_rcv.sb_mb);
60826958Skarels 				m = so->so_rcv.sb_mb;
60926958Skarels 				if (m)
61035384Skarels 					m->m_nextpkt = nextrecord;
61125629Skarels 			}
6124786Swnj 		} else {
61312757Ssam 			if (flags & MSG_PEEK)
6148319Sroot 				moff += len;
6158319Sroot 			else {
61635384Skarels 				m->m_data += len;
6178319Sroot 				m->m_len -= len;
6188319Sroot 				so->so_rcv.sb_cc -= len;
6198319Sroot 			}
6204786Swnj 		}
62132092Skarels 		if (so->so_oobmark) {
62232092Skarels 			if ((flags & MSG_PEEK) == 0) {
62332092Skarels 				so->so_oobmark -= len;
62432092Skarels 				if (so->so_oobmark == 0) {
62532092Skarels 					so->so_state |= SS_RCVATMARK;
62632092Skarels 					break;
62732092Skarels 				}
62832092Skarels 			} else
62932092Skarels 				offset += len;
6307747Sroot 		}
63116993Skarels 	}
63235384Skarels 	if (m && (flags & MSG_EOR)) {
63335384Skarels 		flags &= ~MSG_EOR;
63435384Skarels 		if ((flags & MSG_PEEK) == 0)
63535384Skarels 			m->m_flags |= M_EOR;
63635384Skarels 	}
63716993Skarels 	if ((flags & MSG_PEEK) == 0) {
63826500Skarels 		if (m == 0)
63916993Skarels 			so->so_rcv.sb_mb = nextrecord;
64035384Skarels 		else if (pr->pr_flags & PR_ATOMIC) {
64135384Skarels 			flags |= MSG_TRUNC;
64226958Skarels 			(void) sbdroprecord(&so->so_rcv);
64335384Skarels 		}
64416993Skarels 		if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
64516993Skarels 			(*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
646*37478Ssklower 			    (struct mbuf *)flags, (struct mbuf *)0,
647*37478Ssklower 			    (struct mbuf *)0);
64825629Skarels 		if (error == 0 && rightsp && *rightsp &&
64925629Skarels 		    pr->pr_domain->dom_externalize)
65025629Skarels 			error = (*pr->pr_domain->dom_externalize)(*rightsp);
65116993Skarels 	}
65235384Skarels 	if (flagsp)
65335384Skarels 		*flagsp |= flags;
6544890Swnj release:
6554916Swnj 	sbunlock(&so->so_rcv);
6564890Swnj 	splx(s);
6574916Swnj 	return (error);
6584786Swnj }
6594786Swnj 
66010267Ssam soshutdown(so, how)
66112757Ssam 	register struct socket *so;
66212757Ssam 	register int how;
66310267Ssam {
66412757Ssam 	register struct protosw *pr = so->so_proto;
66510267Ssam 
66610267Ssam 	how++;
66712757Ssam 	if (how & FREAD)
66812757Ssam 		sorflush(so);
66910267Ssam 	if (how & FWRITE)
67012757Ssam 		return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN,
67112757Ssam 		    (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
67210267Ssam 	return (0);
67310267Ssam }
67410267Ssam 
67512757Ssam sorflush(so)
67612757Ssam 	register struct socket *so;
67712757Ssam {
67812757Ssam 	register struct sockbuf *sb = &so->so_rcv;
67912757Ssam 	register struct protosw *pr = so->so_proto;
68012757Ssam 	register int s;
68112757Ssam 	struct sockbuf asb;
68212757Ssam 
68312757Ssam 	sblock(sb);
68412757Ssam 	s = splimp();
68512757Ssam 	socantrcvmore(so);
68612757Ssam 	sbunlock(sb);
68712757Ssam 	asb = *sb;
68812757Ssam 	bzero((caddr_t)sb, sizeof (*sb));
68912757Ssam 	splx(s);
69016993Skarels 	if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose)
69116993Skarels 		(*pr->pr_domain->dom_dispose)(asb.sb_mb);
69212757Ssam 	sbrelease(&asb);
69312757Ssam }
69412757Ssam 
69518553Skarels sosetopt(so, level, optname, m0)
69612757Ssam 	register struct socket *so;
69710267Ssam 	int level, optname;
69818553Skarels 	struct mbuf *m0;
69910267Ssam {
70017158Ssam 	int error = 0;
70118553Skarels 	register struct mbuf *m = m0;
70210267Ssam 
70317158Ssam 	if (level != SOL_SOCKET) {
70418369Skarels 		if (so->so_proto && so->so_proto->pr_ctloutput)
70518369Skarels 			return ((*so->so_proto->pr_ctloutput)
70618553Skarels 				  (PRCO_SETOPT, so, level, optname, &m0));
70718369Skarels 		error = ENOPROTOOPT;
70818369Skarels 	} else {
70918369Skarels 		switch (optname) {
71010267Ssam 
71118369Skarels 		case SO_LINGER:
71218369Skarels 			if (m == NULL || m->m_len != sizeof (struct linger)) {
71318369Skarels 				error = EINVAL;
71418369Skarels 				goto bad;
71518369Skarels 			}
71618369Skarels 			so->so_linger = mtod(m, struct linger *)->l_linger;
71718369Skarels 			/* fall thru... */
71817158Ssam 
71918369Skarels 		case SO_DEBUG:
72018369Skarels 		case SO_KEEPALIVE:
72118369Skarels 		case SO_DONTROUTE:
72218369Skarels 		case SO_USELOOPBACK:
72318369Skarels 		case SO_BROADCAST:
72418369Skarels 		case SO_REUSEADDR:
72527191Skarels 		case SO_OOBINLINE:
72618369Skarels 			if (m == NULL || m->m_len < sizeof (int)) {
72718369Skarels 				error = EINVAL;
72818369Skarels 				goto bad;
72918369Skarels 			}
73018369Skarels 			if (*mtod(m, int *))
73118369Skarels 				so->so_options |= optname;
73218369Skarels 			else
73318369Skarels 				so->so_options &= ~optname;
73418369Skarels 			break;
73518369Skarels 
73618369Skarels 		case SO_SNDBUF:
73718369Skarels 		case SO_RCVBUF:
73818369Skarels 		case SO_SNDLOWAT:
73918369Skarels 		case SO_RCVLOWAT:
74018369Skarels 		case SO_SNDTIMEO:
74118369Skarels 		case SO_RCVTIMEO:
74218369Skarels 			if (m == NULL || m->m_len < sizeof (int)) {
74318369Skarels 				error = EINVAL;
74418369Skarels 				goto bad;
74518369Skarels 			}
74618369Skarels 			switch (optname) {
74718369Skarels 
74818369Skarels 			case SO_SNDBUF:
74918369Skarels 			case SO_RCVBUF:
75034492Skarels 				if (sbreserve(optname == SO_SNDBUF ?
75134492Skarels 				    &so->so_snd : &so->so_rcv,
75234492Skarels 				    (u_long) *mtod(m, int *)) == 0) {
75318369Skarels 					error = ENOBUFS;
75418369Skarels 					goto bad;
75518369Skarels 				}
75618369Skarels 				break;
75718369Skarels 
75818369Skarels 			case SO_SNDLOWAT:
75918369Skarels 				so->so_snd.sb_lowat = *mtod(m, int *);
76018369Skarels 				break;
76118369Skarels 			case SO_RCVLOWAT:
76218369Skarels 				so->so_rcv.sb_lowat = *mtod(m, int *);
76318369Skarels 				break;
76418369Skarels 			case SO_SNDTIMEO:
76518369Skarels 				so->so_snd.sb_timeo = *mtod(m, int *);
76618369Skarels 				break;
76718369Skarels 			case SO_RCVTIMEO:
76818369Skarels 				so->so_rcv.sb_timeo = *mtod(m, int *);
76918369Skarels 				break;
77018369Skarels 			}
77118369Skarels 			break;
77218369Skarels 
77318369Skarels 		default:
77418369Skarels 			error = ENOPROTOOPT;
77518369Skarels 			break;
77617158Ssam 		}
77710267Ssam 	}
77817158Ssam bad:
77917158Ssam 	if (m)
78017158Ssam 		(void) m_free(m);
78117158Ssam 	return (error);
78210267Ssam }
78310267Ssam 
78417158Ssam sogetopt(so, level, optname, mp)
78512757Ssam 	register struct socket *so;
78610267Ssam 	int level, optname;
78717158Ssam 	struct mbuf **mp;
78817158Ssam {
78912757Ssam 	register struct mbuf *m;
79010267Ssam 
79118369Skarels 	if (level != SOL_SOCKET) {
79218369Skarels 		if (so->so_proto && so->so_proto->pr_ctloutput) {
79318369Skarels 			return ((*so->so_proto->pr_ctloutput)
79418369Skarels 				  (PRCO_GETOPT, so, level, optname, mp));
79518369Skarels 		} else
79618369Skarels 			return (ENOPROTOOPT);
79718369Skarels 	} else {
79817158Ssam 		m = m_get(M_WAIT, MT_SOOPTS);
79925502Skarels 		m->m_len = sizeof (int);
80025502Skarels 
80118369Skarels 		switch (optname) {
80217158Ssam 
80318369Skarels 		case SO_LINGER:
80418369Skarels 			m->m_len = sizeof (struct linger);
80518369Skarels 			mtod(m, struct linger *)->l_onoff =
80618369Skarels 				so->so_options & SO_LINGER;
80718369Skarels 			mtod(m, struct linger *)->l_linger = so->so_linger;
80818369Skarels 			break;
80910267Ssam 
81018369Skarels 		case SO_USELOOPBACK:
81118369Skarels 		case SO_DONTROUTE:
81218369Skarels 		case SO_DEBUG:
81318369Skarels 		case SO_KEEPALIVE:
81418369Skarels 		case SO_REUSEADDR:
81518369Skarels 		case SO_BROADCAST:
81627191Skarels 		case SO_OOBINLINE:
81718369Skarels 			*mtod(m, int *) = so->so_options & optname;
81818369Skarels 			break;
81918369Skarels 
82025502Skarels 		case SO_TYPE:
82125502Skarels 			*mtod(m, int *) = so->so_type;
82225502Skarels 			break;
82325502Skarels 
82424768Skarels 		case SO_ERROR:
82524768Skarels 			*mtod(m, int *) = so->so_error;
82624768Skarels 			so->so_error = 0;
82724768Skarels 			break;
82824768Skarels 
82918369Skarels 		case SO_SNDBUF:
83018369Skarels 			*mtod(m, int *) = so->so_snd.sb_hiwat;
83118369Skarels 			break;
83218369Skarels 
83318369Skarels 		case SO_RCVBUF:
83418369Skarels 			*mtod(m, int *) = so->so_rcv.sb_hiwat;
83518369Skarels 			break;
83618369Skarels 
83718369Skarels 		case SO_SNDLOWAT:
83818369Skarels 			*mtod(m, int *) = so->so_snd.sb_lowat;
83918369Skarels 			break;
84018369Skarels 
84118369Skarels 		case SO_RCVLOWAT:
84218369Skarels 			*mtod(m, int *) = so->so_rcv.sb_lowat;
84318369Skarels 			break;
84418369Skarels 
84518369Skarels 		case SO_SNDTIMEO:
84618369Skarels 			*mtod(m, int *) = so->so_snd.sb_timeo;
84718369Skarels 			break;
84818369Skarels 
84918369Skarels 		case SO_RCVTIMEO:
85018369Skarels 			*mtod(m, int *) = so->so_rcv.sb_timeo;
85118369Skarels 			break;
85218369Skarels 
85318369Skarels 		default:
85426362Skarels 			(void)m_free(m);
85518369Skarels 			return (ENOPROTOOPT);
85618369Skarels 		}
85718369Skarels 		*mp = m;
85818369Skarels 		return (0);
85910267Ssam 	}
86010267Ssam }
86110267Ssam 
8625423Swnj sohasoutofband(so)
86312757Ssam 	register struct socket *so;
8645423Swnj {
86523233Skarels 	struct proc *p;
8665423Swnj 
867*37478Ssklower 	if (so->so_pgid < 0)
868*37478Ssklower 		gsignal(-so->so_pgid, SIGURG);
869*37478Ssklower 	else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0)
87023233Skarels 		psignal(p, SIGURG);
87124768Skarels 	if (so->so_rcv.sb_sel) {
87224768Skarels 		selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL);
87324768Skarels 		so->so_rcv.sb_sel = 0;
87424768Skarels 		so->so_rcv.sb_flags &= ~SB_COLL;
87524768Skarels 	}
8765423Swnj }
877