xref: /csrg-svn/sys/kern/uipc_socket.c (revision 35384)
123421Smckusick /*
2*35384Skarels  * 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*35384Skarels  *	@(#)uipc_socket.c	7.11 (Berkeley) 08/21/88
1823421Smckusick  */
194786Swnj 
2017102Sbloom #include "param.h"
2117102Sbloom #include "dir.h"
2217102Sbloom #include "user.h"
2317102Sbloom #include "proc.h"
2417102Sbloom #include "file.h"
25*35384Skarels #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 struct mbuf *m;
5312757Ssam 	register int error;
544786Swnj 
554890Swnj 	if (proto)
5621767Skarels 		prp = pffindproto(dom, proto, type);
574890Swnj 	else
589168Ssam 		prp = pffindtype(dom, type);
594890Swnj 	if (prp == 0)
604890Swnj 		return (EPROTONOSUPPORT);
618300Sroot 	if (prp->pr_type != type)
628300Sroot 		return (EPROTOTYPE);
639635Ssam 	m = m_getclr(M_WAIT, MT_SOCKET);
644786Swnj 	so = mtod(m, struct socket *);
6512757Ssam 	so->so_options = 0;
666214Swnj 	so->so_state = 0;
679168Ssam 	so->so_type = type;
686214Swnj 	if (u.u_uid == 0)
696214Swnj 		so->so_state = SS_PRIV;
704786Swnj 	so->so_proto = prp;
7112757Ssam 	error =
7212757Ssam 	    (*prp->pr_usrreq)(so, PRU_ATTACH,
7321767Skarels 		(struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0);
744979Swnj 	if (error) {
757507Sroot 		so->so_state |= SS_NOFDREF;
767180Swnj 		sofree(so);
774890Swnj 		return (error);
784786Swnj 	}
794786Swnj 	*aso = so;
804786Swnj 	return (0);
814786Swnj }
824786Swnj 
8310267Ssam sobind(so, nam)
848300Sroot 	struct socket *so;
858300Sroot 	struct mbuf *nam;
868300Sroot {
878300Sroot 	int s = splnet();
888300Sroot 	int error;
898300Sroot 
908300Sroot 	error =
9112757Ssam 	    (*so->so_proto->pr_usrreq)(so, PRU_BIND,
9212757Ssam 		(struct mbuf *)0, nam, (struct mbuf *)0);
938300Sroot 	splx(s);
948300Sroot 	return (error);
958300Sroot }
968300Sroot 
978300Sroot solisten(so, backlog)
9812757Ssam 	register struct socket *so;
998300Sroot 	int backlog;
1008300Sroot {
10112757Ssam 	int s = splnet(), error;
1028300Sroot 
10312757Ssam 	error =
10412757Ssam 	    (*so->so_proto->pr_usrreq)(so, PRU_LISTEN,
10512757Ssam 		(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
1068300Sroot 	if (error) {
1078300Sroot 		splx(s);
1088300Sroot 		return (error);
1098300Sroot 	}
1108300Sroot 	if (so->so_q == 0) {
1118300Sroot 		so->so_q = so;
1128300Sroot 		so->so_q0 = so;
1138300Sroot 		so->so_options |= SO_ACCEPTCONN;
1148300Sroot 	}
1158300Sroot 	if (backlog < 0)
1168300Sroot 		backlog = 0;
117*35384Skarels 	so->so_qlimit = min(backlog, SOMAXCONN);
11812493Ssam 	splx(s);
1198300Sroot 	return (0);
1208300Sroot }
1218300Sroot 
1224916Swnj sofree(so)
12312757Ssam 	register struct socket *so;
1244916Swnj {
1254916Swnj 
12631810Skarels 	if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
12731810Skarels 		return;
1287507Sroot 	if (so->so_head) {
1297507Sroot 		if (!soqremque(so, 0) && !soqremque(so, 1))
1307507Sroot 			panic("sofree dq");
1317507Sroot 		so->so_head = 0;
1327507Sroot 	}
1334950Swnj 	sbrelease(&so->so_snd);
13412757Ssam 	sorflush(so);
1354971Swnj 	(void) m_free(dtom(so));
1364916Swnj }
1374916Swnj 
1384786Swnj /*
1394890Swnj  * Close a socket on last file table reference removal.
1404890Swnj  * Initiate disconnect if connected.
1414890Swnj  * Free socket when disconnect complete.
1424829Swnj  */
14312757Ssam soclose(so)
1444829Swnj 	register struct socket *so;
1454829Swnj {
1464890Swnj 	int s = splnet();		/* conservative */
14733372Sbostic 	int error = 0;
1484829Swnj 
1497507Sroot 	if (so->so_options & SO_ACCEPTCONN) {
1507507Sroot 		while (so->so_q0 != so)
15110399Ssam 			(void) soabort(so->so_q0);
1527507Sroot 		while (so->so_q != so)
15310399Ssam 			(void) soabort(so->so_q);
1547507Sroot 	}
1554890Swnj 	if (so->so_pcb == 0)
1564890Swnj 		goto discard;
1574890Swnj 	if (so->so_state & SS_ISCONNECTED) {
1584890Swnj 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
15926245Skarels 			error = sodisconnect(so);
16012757Ssam 			if (error)
16112757Ssam 				goto drop;
1624890Swnj 		}
16310267Ssam 		if (so->so_options & SO_LINGER) {
1645281Sroot 			if ((so->so_state & SS_ISDISCONNECTING) &&
16512757Ssam 			    (so->so_state & SS_NBIO))
16612757Ssam 				goto drop;
1675281Sroot 			while (so->so_state & SS_ISCONNECTED)
1685281Sroot 				sleep((caddr_t)&so->so_timeo, PZERO+1);
1694890Swnj 		}
1704890Swnj 	}
1715580Sroot drop:
1726880Ssam 	if (so->so_pcb) {
17312757Ssam 		int error2 =
17412757Ssam 		    (*so->so_proto->pr_usrreq)(so, PRU_DETACH,
17512757Ssam 			(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
17612757Ssam 		if (error == 0)
17712757Ssam 			error = error2;
1786880Ssam 	}
1794890Swnj discard:
18010399Ssam 	if (so->so_state & SS_NOFDREF)
18110399Ssam 		panic("soclose: NOFDREF");
1827507Sroot 	so->so_state |= SS_NOFDREF;
1834950Swnj 	sofree(so);
1844890Swnj 	splx(s);
18512757Ssam 	return (error);
1864829Swnj }
1874829Swnj 
18810399Ssam /*
18910399Ssam  * Must be called at splnet...
19010399Ssam  */
19110399Ssam soabort(so)
19210399Ssam 	struct socket *so;
19310399Ssam {
19410399Ssam 
19512757Ssam 	return (
19612757Ssam 	    (*so->so_proto->pr_usrreq)(so, PRU_ABORT,
19712757Ssam 		(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
19810399Ssam }
19910399Ssam 
20010267Ssam soaccept(so, nam)
20112757Ssam 	register struct socket *so;
2028300Sroot 	struct mbuf *nam;
2034927Swnj {
2044927Swnj 	int s = splnet();
2054927Swnj 	int error;
2064927Swnj 
20710399Ssam 	if ((so->so_state & SS_NOFDREF) == 0)
20810399Ssam 		panic("soaccept: !NOFDREF");
20910267Ssam 	so->so_state &= ~SS_NOFDREF;
2108300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT,
21112757Ssam 	    (struct mbuf *)0, nam, (struct mbuf *)0);
2124927Swnj 	splx(s);
2134927Swnj 	return (error);
2144927Swnj }
2154927Swnj 
21610267Ssam soconnect(so, nam)
21712757Ssam 	register struct socket *so;
2188300Sroot 	struct mbuf *nam;
2194786Swnj {
22030414Skarels 	int s;
2214890Swnj 	int error;
2224786Swnj 
22330414Skarels 	if (so->so_options & SO_ACCEPTCONN)
22430414Skarels 		return (EOPNOTSUPP);
22530414Skarels 	s = splnet();
22624768Skarels 	/*
22724768Skarels 	 * If protocol is connection-based, can only connect once.
22824768Skarels 	 * Otherwise, if connected, try to disconnect first.
22924768Skarels 	 * This allows user to disconnect by connecting to, e.g.,
23024768Skarels 	 * a null address.
23124768Skarels 	 */
23224768Skarels 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) &&
23324768Skarels 	    ((so->so_proto->pr_flags & PR_CONNREQUIRED) ||
23424768Skarels 	    (error = sodisconnect(so))))
2354890Swnj 		error = EISCONN;
23624768Skarels 	else
23724768Skarels 		error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
23824768Skarels 		    (struct mbuf *)0, nam, (struct mbuf *)0);
2394890Swnj 	splx(s);
2404890Swnj 	return (error);
2414786Swnj }
2424786Swnj 
24312757Ssam soconnect2(so1, so2)
24412757Ssam 	register struct socket *so1;
24512757Ssam 	struct socket *so2;
24612757Ssam {
24712757Ssam 	int s = splnet();
24812757Ssam 	int error;
24912757Ssam 
25013113Ssam 	error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2,
25113113Ssam 	    (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0);
25212757Ssam 	splx(s);
25312757Ssam 	return (error);
25412757Ssam }
25512757Ssam 
25626245Skarels sodisconnect(so)
25712757Ssam 	register struct socket *so;
2584786Swnj {
2594890Swnj 	int s = splnet();
2604890Swnj 	int error;
2614786Swnj 
2624890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2634890Swnj 		error = ENOTCONN;
2644890Swnj 		goto bad;
2654890Swnj 	}
2664890Swnj 	if (so->so_state & SS_ISDISCONNECTING) {
2674890Swnj 		error = EALREADY;
2684890Swnj 		goto bad;
2694890Swnj 	}
2708300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT,
27126245Skarels 	    (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
2724890Swnj bad:
2734890Swnj 	splx(s);
2744890Swnj 	return (error);
2754786Swnj }
2764786Swnj 
2774786Swnj /*
2784890Swnj  * Send on a socket.
2794890Swnj  * If send must go all at once and message is larger than
2804890Swnj  * send buffering, then hard error.
2814890Swnj  * Lock against other senders.
2824890Swnj  * If must go all at once and not enough room now, then
2834890Swnj  * inform user that this would block and do nothing.
28416412Skarels  * Otherwise, if nonblocking, send as much as possible.
2854786Swnj  */
286*35384Skarels sosend(so, nam, uio, flags, rights, control)
2874786Swnj 	register struct socket *so;
2888300Sroot 	struct mbuf *nam;
28912757Ssam 	register struct uio *uio;
2908319Sroot 	int flags;
291*35384Skarels 	struct mbuf *rights, *control;
2924786Swnj {
293*35384Skarels 	struct mbuf *top = 0, **mp;
294*35384Skarels 	register struct mbuf *m;
295*35384Skarels 	register int space, len;
296*35384Skarels 	int rlen = 0, error = 0, s, dontroute, first = 1, mlen;
297*35384Skarels 	int atomic = sosendallatonce(so);
2984786Swnj 
299*35384Skarels 	if (atomic && uio->uio_resid > so->so_snd.sb_hiwat)
3004890Swnj 		return (EMSGSIZE);
30112757Ssam 	dontroute =
30212757Ssam 	    (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
30312757Ssam 	    (so->so_proto->pr_flags & PR_ATOMIC);
30416412Skarels 	u.u_ru.ru_msgsnd++;
30525629Skarels 	if (rights)
30625629Skarels 		rlen = rights->m_len;
30716412Skarels #define	snderr(errno)	{ error = errno; splx(s); goto release; }
30816412Skarels 
3096419Sroot restart:
3104890Swnj 	sblock(&so->so_snd);
31116412Skarels 	do {
31216412Skarels 		s = splnet();
31321108Skarels 		if (so->so_state & SS_CANTSENDMORE)
31416412Skarels 			snderr(EPIPE);
31516412Skarels 		if (so->so_error) {
31616412Skarels 			error = so->so_error;
31716412Skarels 			so->so_error = 0;			/* ??? */
31816412Skarels 			splx(s);
31916412Skarels 			goto release;
32016412Skarels 		}
32116412Skarels 		if ((so->so_state & SS_ISCONNECTED) == 0) {
32216412Skarels 			if (so->so_proto->pr_flags & PR_CONNREQUIRED)
32316412Skarels 				snderr(ENOTCONN);
32416412Skarels 			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 ||
332*35384Skarels 			   (atomic && space < uio->uio_resid + rlen) ||
333*35384Skarels 			   (uio->uio_resid >= MCLBYTES && space < MCLBYTES &&
334*35384Skarels 			   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;
351*35384Skarels 		do {
352*35384Skarels 		   do {
353*35384Skarels 			if (top == 0) {
354*35384Skarels 				MGETHDR(m, M_WAIT, MT_DATA);
355*35384Skarels 				mlen = MHLEN;
356*35384Skarels 				m->m_pkthdr.len = 0;
357*35384Skarels 				m->m_pkthdr.rcvif = (struct ifnet *)0;
358*35384Skarels 			} else {
359*35384Skarels 				MGET(m, M_WAIT, MT_DATA);
360*35384Skarels 				mlen = MLEN;
361*35384Skarels 			}
362*35384Skarels 			if (uio->uio_resid >= MINCLSIZE && space >= MCLBYTES) {
363*35384Skarels 				MCLGET(m, M_WAIT);
364*35384Skarels 				if ((m->m_flags & M_EXT) == 0)
36516412Skarels 					goto nopages;
366*35384Skarels 				mlen = MCLBYTES;
367*35384Skarels #ifdef	MAPPED_MBUFS
368*35384Skarels 				len = min(MCLBYTES, uio->uio_resid);
369*35384Skarels 				if (len < mlen - max_hdr)
370*35384Skarels 					m->m_data += max_hdr;
371*35384Skarels #else
372*35384Skarels 				len = min(MCLBYTES - max_hdr, uio->uio_resid);
373*35384Skarels 				m->m_data += max_hdr;
374*35384Skarels #endif
375*35384Skarels 				space -= MCLBYTES;
37616412Skarels 			} else {
37716412Skarels nopages:
378*35384Skarels 				len = min(min(mlen, uio->uio_resid), space);
37921767Skarels 				space -= len;
380*35384Skarels 				/*
381*35384Skarels 				 * For datagram protocols, leave room
382*35384Skarels 				 * for protocol headers in first mbuf.
383*35384Skarels 				 */
384*35384Skarels 				if (atomic && len < mlen)
385*35384Skarels 					MH_ALIGN(m, len);
38616412Skarels 			}
38716412Skarels 			error = uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio);
38816412Skarels 			m->m_len = len;
38916412Skarels 			*mp = m;
390*35384Skarels 			top->m_pkthdr.len += len;
39116412Skarels 			if (error)
39216412Skarels 				goto release;
39316412Skarels 			mp = &m->m_next;
394*35384Skarels 			if (uio->uio_resid <= 0) {
395*35384Skarels 				if ((flags & MSG_EOR) && top)
396*35384Skarels 					top->m_flags |= M_EOR;
39721108Skarels 				break;
398*35384Skarels 			}
399*35384Skarels 		    } while (space > 0 && atomic);
400*35384Skarels 		    if (dontroute)
401*35384Skarels 			    so->so_options |= SO_DONTROUTE;
402*35384Skarels 		    s = splnet();				/* XXX */
403*35384Skarels 		    error = (*so->so_proto->pr_usrreq)(so,
404*35384Skarels 			(flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
405*35384Skarels 			top, (caddr_t)nam, rights, control);
406*35384Skarels 		    splx(s);
407*35384Skarels 		    if (dontroute)
408*35384Skarels 			    so->so_options &= ~SO_DONTROUTE;
409*35384Skarels 		    rights = 0;
410*35384Skarels 		    rlen = 0;
411*35384Skarels 		    top = 0;
412*35384Skarels 		    mp = &top;
413*35384Skarels 		    first = 0;
414*35384Skarels 		    if (error)
415*35384Skarels 			goto release;
416*35384Skarels 		} 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  */
440*35384Skarels soreceive(so, aname, uio, flagsp, rightsp, controlp)
4414786Swnj 	register struct socket *so;
4428300Sroot 	struct mbuf **aname;
44312757Ssam 	register struct uio *uio;
444*35384Skarels 	int *flagsp;
445*35384Skarels 	struct mbuf **rightsp, **controlp;
4464786Swnj {
44726958Skarels 	register struct mbuf *m;
448*35384Skarels 	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;
457*35384Skarels 	if (controlp)
458*35384Skarels 		*controlp = 0;
459*35384Skarels 	if (flagsp)
460*35384Skarels 		flags = *flagsp &~ MSG_EOR;
461*35384Skarels 	else
462*35384Skarels 		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*35384Skarels 	if (so->so_state & SS_ISCONFIRMING)
483*35384Skarels 		(*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
484*35384Skarels 		    (struct mbuf *)0, (struct mbuf *)0);
4858319Sroot 
4864890Swnj restart:
4874890Swnj 	sblock(&so->so_rcv);
4888835Sroot 	s = splnet();
4894890Swnj 
4904786Swnj 	if (so->so_rcv.sb_cc == 0) {
4915168Swnj 		if (so->so_error) {
4925168Swnj 			error = so->so_error;
4935168Swnj 			so->so_error = 0;
4945168Swnj 			goto release;
4955168Swnj 		}
49632567Sbostic 		if (so->so_state & SS_CANTRCVMORE)
4974890Swnj 			goto release;
49832567Sbostic 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
49932567Sbostic 		    (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
50032567Sbostic 			error = ENOTCONN;
50132567Sbostic 			goto release;
5024890Swnj 		}
50325629Skarels 		if (uio->uio_resid == 0)
50425629Skarels 			goto release;
50532567Sbostic 		if (so->so_state & SS_NBIO) {
50632567Sbostic 			error = EWOULDBLOCK;
50732567Sbostic 			goto release;
50832567Sbostic 		}
5094890Swnj 		sbunlock(&so->so_rcv);
5104971Swnj 		sbwait(&so->so_rcv);
5115012Swnj 		splx(s);
5124890Swnj 		goto restart;
5134786Swnj 	}
5148041Sroot 	u.u_ru.ru_msgrcv++;
5154829Swnj 	m = so->so_rcv.sb_mb;
51625629Skarels 	if (m == 0)
51725629Skarels 		panic("receive 1");
518*35384Skarels if (m->m_type == 0)
519*35384Skarels panic("receive 3a");
520*35384Skarels 	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;
532*35384Skarels 				so->so_rcv.sb_mb = m->m_next;
533*35384Skarels 				m->m_next = 0;
534*35384Skarels 				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 	}
561*35384Skarels 	if (m && m->m_type == MT_CONTROL) {
562*35384Skarels 		if (flags & MSG_PEEK) {
563*35384Skarels 			if (controlp)
564*35384Skarels 				*controlp = m_copy(m, 0, m->m_len);
565*35384Skarels 			m = m->m_next;
566*35384Skarels 		} else {
567*35384Skarels 			sbfree(&so->so_rcv, m);
568*35384Skarels 			if (controlp) {
569*35384Skarels 				*controlp = m;
570*35384Skarels 				so->so_rcv.sb_mb = m->m_next;
571*35384Skarels 				m->m_next = 0;
572*35384Skarels 				m = so->so_rcv.sb_mb;
573*35384Skarels 			} else {
574*35384Skarels 				MFREE(m, so->so_rcv.sb_mb);
575*35384Skarels 				m = so->so_rcv.sb_mb;
576*35384Skarels 			}
577*35384Skarels 		}
578*35384Skarels 	}
579*35384Skarels 	if (m)
580*35384Skarels 		m->m_nextpkt = nextrecord;
5818319Sroot 	moff = 0;
58232092Skarels 	offset = 0;
58316993Skarels 	while (m && uio->uio_resid > 0 && error == 0) {
584*35384Skarels 		if (m->m_type == MT_OOBDATA)
585*35384Skarels 			flags |= MSG_OOB;
586*35384Skarels 		else if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
58725629Skarels 			panic("receive 3");
588*35384Skarels 		if (m->m_flags & M_EOR)
589*35384Skarels 			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 {
605*35384Skarels 				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)
610*35384Skarels 					m->m_nextpkt = nextrecord;
61125629Skarels 			}
6124786Swnj 		} else {
61312757Ssam 			if (flags & MSG_PEEK)
6148319Sroot 				moff += len;
6158319Sroot 			else {
616*35384Skarels 				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 	}
632*35384Skarels 	if (m && (flags & MSG_EOR)) {
633*35384Skarels 		flags &= ~MSG_EOR;
634*35384Skarels 		if ((flags & MSG_PEEK) == 0)
635*35384Skarels 			m->m_flags |= M_EOR;
636*35384Skarels 	}
63716993Skarels 	if ((flags & MSG_PEEK) == 0) {
63826500Skarels 		if (m == 0)
63916993Skarels 			so->so_rcv.sb_mb = nextrecord;
640*35384Skarels 		else if (pr->pr_flags & PR_ATOMIC) {
641*35384Skarels 			flags |= MSG_TRUNC;
64226958Skarels 			(void) sbdroprecord(&so->so_rcv);
643*35384Skarels 		}
64416993Skarels 		if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
64516993Skarels 			(*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
64616993Skarels 			    (struct mbuf *)0, (struct mbuf *)0);
64725629Skarels 		if (error == 0 && rightsp && *rightsp &&
64825629Skarels 		    pr->pr_domain->dom_externalize)
64925629Skarels 			error = (*pr->pr_domain->dom_externalize)(*rightsp);
65016993Skarels 	}
651*35384Skarels 	if (flagsp)
652*35384Skarels 		*flagsp |= flags;
6534890Swnj release:
6544916Swnj 	sbunlock(&so->so_rcv);
6554890Swnj 	splx(s);
6564916Swnj 	return (error);
6574786Swnj }
6584786Swnj 
65910267Ssam soshutdown(so, how)
66012757Ssam 	register struct socket *so;
66112757Ssam 	register int how;
66210267Ssam {
66312757Ssam 	register struct protosw *pr = so->so_proto;
66410267Ssam 
66510267Ssam 	how++;
66612757Ssam 	if (how & FREAD)
66712757Ssam 		sorflush(so);
66810267Ssam 	if (how & FWRITE)
66912757Ssam 		return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN,
67012757Ssam 		    (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
67110267Ssam 	return (0);
67210267Ssam }
67310267Ssam 
67412757Ssam sorflush(so)
67512757Ssam 	register struct socket *so;
67612757Ssam {
67712757Ssam 	register struct sockbuf *sb = &so->so_rcv;
67812757Ssam 	register struct protosw *pr = so->so_proto;
67912757Ssam 	register int s;
68012757Ssam 	struct sockbuf asb;
68112757Ssam 
68212757Ssam 	sblock(sb);
68312757Ssam 	s = splimp();
68412757Ssam 	socantrcvmore(so);
68512757Ssam 	sbunlock(sb);
68612757Ssam 	asb = *sb;
68712757Ssam 	bzero((caddr_t)sb, sizeof (*sb));
68812757Ssam 	splx(s);
68916993Skarels 	if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose)
69016993Skarels 		(*pr->pr_domain->dom_dispose)(asb.sb_mb);
69112757Ssam 	sbrelease(&asb);
69212757Ssam }
69312757Ssam 
69418553Skarels sosetopt(so, level, optname, m0)
69512757Ssam 	register struct socket *so;
69610267Ssam 	int level, optname;
69718553Skarels 	struct mbuf *m0;
69810267Ssam {
69917158Ssam 	int error = 0;
70018553Skarels 	register struct mbuf *m = m0;
70110267Ssam 
70217158Ssam 	if (level != SOL_SOCKET) {
70318369Skarels 		if (so->so_proto && so->so_proto->pr_ctloutput)
70418369Skarels 			return ((*so->so_proto->pr_ctloutput)
70518553Skarels 				  (PRCO_SETOPT, so, level, optname, &m0));
70618369Skarels 		error = ENOPROTOOPT;
70718369Skarels 	} else {
70818369Skarels 		switch (optname) {
70910267Ssam 
71018369Skarels 		case SO_LINGER:
71118369Skarels 			if (m == NULL || m->m_len != sizeof (struct linger)) {
71218369Skarels 				error = EINVAL;
71318369Skarels 				goto bad;
71418369Skarels 			}
71518369Skarels 			so->so_linger = mtod(m, struct linger *)->l_linger;
71618369Skarels 			/* fall thru... */
71717158Ssam 
71818369Skarels 		case SO_DEBUG:
71918369Skarels 		case SO_KEEPALIVE:
72018369Skarels 		case SO_DONTROUTE:
72118369Skarels 		case SO_USELOOPBACK:
72218369Skarels 		case SO_BROADCAST:
72318369Skarels 		case SO_REUSEADDR:
72427191Skarels 		case SO_OOBINLINE:
72518369Skarels 			if (m == NULL || m->m_len < sizeof (int)) {
72618369Skarels 				error = EINVAL;
72718369Skarels 				goto bad;
72818369Skarels 			}
72918369Skarels 			if (*mtod(m, int *))
73018369Skarels 				so->so_options |= optname;
73118369Skarels 			else
73218369Skarels 				so->so_options &= ~optname;
73318369Skarels 			break;
73418369Skarels 
73518369Skarels 		case SO_SNDBUF:
73618369Skarels 		case SO_RCVBUF:
73718369Skarels 		case SO_SNDLOWAT:
73818369Skarels 		case SO_RCVLOWAT:
73918369Skarels 		case SO_SNDTIMEO:
74018369Skarels 		case SO_RCVTIMEO:
74118369Skarels 			if (m == NULL || m->m_len < sizeof (int)) {
74218369Skarels 				error = EINVAL;
74318369Skarels 				goto bad;
74418369Skarels 			}
74518369Skarels 			switch (optname) {
74618369Skarels 
74718369Skarels 			case SO_SNDBUF:
74818369Skarels 			case SO_RCVBUF:
74934492Skarels 				if (sbreserve(optname == SO_SNDBUF ?
75034492Skarels 				    &so->so_snd : &so->so_rcv,
75134492Skarels 				    (u_long) *mtod(m, int *)) == 0) {
75218369Skarels 					error = ENOBUFS;
75318369Skarels 					goto bad;
75418369Skarels 				}
75518369Skarels 				break;
75618369Skarels 
75718369Skarels 			case SO_SNDLOWAT:
75818369Skarels 				so->so_snd.sb_lowat = *mtod(m, int *);
75918369Skarels 				break;
76018369Skarels 			case SO_RCVLOWAT:
76118369Skarels 				so->so_rcv.sb_lowat = *mtod(m, int *);
76218369Skarels 				break;
76318369Skarels 			case SO_SNDTIMEO:
76418369Skarels 				so->so_snd.sb_timeo = *mtod(m, int *);
76518369Skarels 				break;
76618369Skarels 			case SO_RCVTIMEO:
76718369Skarels 				so->so_rcv.sb_timeo = *mtod(m, int *);
76818369Skarels 				break;
76918369Skarels 			}
77018369Skarels 			break;
77118369Skarels 
77218369Skarels 		default:
77318369Skarels 			error = ENOPROTOOPT;
77418369Skarels 			break;
77517158Ssam 		}
77610267Ssam 	}
77717158Ssam bad:
77817158Ssam 	if (m)
77917158Ssam 		(void) m_free(m);
78017158Ssam 	return (error);
78110267Ssam }
78210267Ssam 
78317158Ssam sogetopt(so, level, optname, mp)
78412757Ssam 	register struct socket *so;
78510267Ssam 	int level, optname;
78617158Ssam 	struct mbuf **mp;
78717158Ssam {
78812757Ssam 	register struct mbuf *m;
78910267Ssam 
79018369Skarels 	if (level != SOL_SOCKET) {
79118369Skarels 		if (so->so_proto && so->so_proto->pr_ctloutput) {
79218369Skarels 			return ((*so->so_proto->pr_ctloutput)
79318369Skarels 				  (PRCO_GETOPT, so, level, optname, mp));
79418369Skarels 		} else
79518369Skarels 			return (ENOPROTOOPT);
79618369Skarels 	} else {
79717158Ssam 		m = m_get(M_WAIT, MT_SOOPTS);
79825502Skarels 		m->m_len = sizeof (int);
79925502Skarels 
80018369Skarels 		switch (optname) {
80117158Ssam 
80218369Skarels 		case SO_LINGER:
80318369Skarels 			m->m_len = sizeof (struct linger);
80418369Skarels 			mtod(m, struct linger *)->l_onoff =
80518369Skarels 				so->so_options & SO_LINGER;
80618369Skarels 			mtod(m, struct linger *)->l_linger = so->so_linger;
80718369Skarels 			break;
80810267Ssam 
80918369Skarels 		case SO_USELOOPBACK:
81018369Skarels 		case SO_DONTROUTE:
81118369Skarels 		case SO_DEBUG:
81218369Skarels 		case SO_KEEPALIVE:
81318369Skarels 		case SO_REUSEADDR:
81418369Skarels 		case SO_BROADCAST:
81527191Skarels 		case SO_OOBINLINE:
81618369Skarels 			*mtod(m, int *) = so->so_options & optname;
81718369Skarels 			break;
81818369Skarels 
81925502Skarels 		case SO_TYPE:
82025502Skarels 			*mtod(m, int *) = so->so_type;
82125502Skarels 			break;
82225502Skarels 
82324768Skarels 		case SO_ERROR:
82424768Skarels 			*mtod(m, int *) = so->so_error;
82524768Skarels 			so->so_error = 0;
82624768Skarels 			break;
82724768Skarels 
82818369Skarels 		case SO_SNDBUF:
82918369Skarels 			*mtod(m, int *) = so->so_snd.sb_hiwat;
83018369Skarels 			break;
83118369Skarels 
83218369Skarels 		case SO_RCVBUF:
83318369Skarels 			*mtod(m, int *) = so->so_rcv.sb_hiwat;
83418369Skarels 			break;
83518369Skarels 
83618369Skarels 		case SO_SNDLOWAT:
83718369Skarels 			*mtod(m, int *) = so->so_snd.sb_lowat;
83818369Skarels 			break;
83918369Skarels 
84018369Skarels 		case SO_RCVLOWAT:
84118369Skarels 			*mtod(m, int *) = so->so_rcv.sb_lowat;
84218369Skarels 			break;
84318369Skarels 
84418369Skarels 		case SO_SNDTIMEO:
84518369Skarels 			*mtod(m, int *) = so->so_snd.sb_timeo;
84618369Skarels 			break;
84718369Skarels 
84818369Skarels 		case SO_RCVTIMEO:
84918369Skarels 			*mtod(m, int *) = so->so_rcv.sb_timeo;
85018369Skarels 			break;
85118369Skarels 
85218369Skarels 		default:
85326362Skarels 			(void)m_free(m);
85418369Skarels 			return (ENOPROTOOPT);
85518369Skarels 		}
85618369Skarels 		*mp = m;
85718369Skarels 		return (0);
85810267Ssam 	}
85910267Ssam }
86010267Ssam 
8615423Swnj sohasoutofband(so)
86212757Ssam 	register struct socket *so;
8635423Swnj {
86423233Skarels 	struct proc *p;
8655423Swnj 
86623233Skarels 	if (so->so_pgrp < 0)
86723233Skarels 		gsignal(-so->so_pgrp, SIGURG);
86823233Skarels 	else if (so->so_pgrp > 0 && (p = pfind(so->so_pgrp)) != 0)
86923233Skarels 		psignal(p, SIGURG);
87024768Skarels 	if (so->so_rcv.sb_sel) {
87124768Skarels 		selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL);
87224768Skarels 		so->so_rcv.sb_sel = 0;
87324768Skarels 		so->so_rcv.sb_flags &= ~SB_COLL;
87424768Skarels 	}
8755423Swnj }
876