xref: /csrg-svn/sys/kern/uipc_socket.c (revision 12493)
1*12493Ssam /*	uipc_socket.c	4.74	83/05/18	*/
24786Swnj 
34786Swnj #include "../h/param.h"
44829Swnj #include "../h/systm.h"
54786Swnj #include "../h/dir.h"
64786Swnj #include "../h/user.h"
74829Swnj #include "../h/proc.h"
84829Swnj #include "../h/file.h"
94786Swnj #include "../h/inode.h"
104829Swnj #include "../h/buf.h"
114786Swnj #include "../h/mbuf.h"
124829Swnj #include "../h/protosw.h"
134829Swnj #include "../h/socket.h"
144829Swnj #include "../h/socketvar.h"
154916Swnj #include "../h/stat.h"
165281Sroot #include "../h/ioctl.h"
178391Swnj #include "../h/uio.h"
186355Ssam #include "../net/route.h"
1911571Ssam #include "../net/if.h"
204786Swnj 
214786Swnj /*
228300Sroot  * Socket operation routines.
238300Sroot  * These routines are called by the routines in
248300Sroot  * sys_socket.c or from a system process, and
258300Sroot  * implement the semantics of socket operations by
268300Sroot  * switching out to the protocol specific routines.
274786Swnj  */
284786Swnj 
298594Sroot /*ARGSUSED*/
3010267Ssam socreate(dom, aso, type, proto)
314786Swnj 	struct socket **aso;
328300Sroot 	int type, proto;
334786Swnj {
344786Swnj 	register struct protosw *prp;
354786Swnj 	register struct socket *so;
364786Swnj 	struct mbuf *m;
379168Ssam 	int error;
384786Swnj 
394890Swnj 	if (proto)
409168Ssam 		prp = pffindproto(dom, proto);
414890Swnj 	else
429168Ssam 		prp = pffindtype(dom, type);
434890Swnj 	if (prp == 0)
444890Swnj 		return (EPROTONOSUPPORT);
458300Sroot 	if (prp->pr_type != type)
468300Sroot 		return (EPROTOTYPE);
479635Ssam 	m = m_getclr(M_WAIT, MT_SOCKET);
484786Swnj 	if (m == 0)
494786Swnj 		return (ENOBUFS);
504786Swnj 	so = mtod(m, struct socket *);
5110267Ssam 	so->so_options = SO_LINGER;
526214Swnj 	so->so_state = 0;
539168Ssam 	so->so_type = type;
546214Swnj 	if (u.u_uid == 0)
556214Swnj 		so->so_state = SS_PRIV;
564786Swnj 	so->so_proto = prp;
578300Sroot 	error = (*prp->pr_usrreq)(so, PRU_ATTACH,
5810267Ssam 	    (struct mbuf *)0, (struct mbuf *)0);
594979Swnj 	if (error) {
607507Sroot 		so->so_state |= SS_NOFDREF;
617180Swnj 		sofree(so);
624890Swnj 		return (error);
634786Swnj 	}
644786Swnj 	*aso = so;
654786Swnj 	return (0);
664786Swnj }
674786Swnj 
6810267Ssam sobind(so, nam)
698300Sroot 	struct socket *so;
708300Sroot 	struct mbuf *nam;
718300Sroot {
728300Sroot 	int s = splnet();
738300Sroot 	int error;
748300Sroot 
758300Sroot 	error =
7610267Ssam 	    (*so->so_proto->pr_usrreq)(so, PRU_BIND, (struct mbuf *)0, nam);
778300Sroot 	splx(s);
788300Sroot 	return (error);
798300Sroot }
808300Sroot 
818300Sroot solisten(so, backlog)
828300Sroot 	struct socket *so;
838300Sroot 	int backlog;
848300Sroot {
858300Sroot 	int s = splnet();
868300Sroot 	int error;
878300Sroot 
888300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_LISTEN,
8910267Ssam 	    (struct mbuf *)0, (struct mbuf *)0);
908300Sroot 	if (error) {
918300Sroot 		splx(s);
928300Sroot 		return (error);
938300Sroot 	}
948300Sroot 	if (so->so_q == 0) {
958300Sroot 		so->so_q = so;
968300Sroot 		so->so_q0 = so;
978300Sroot 		so->so_options |= SO_ACCEPTCONN;
988300Sroot 	}
998300Sroot 	if (backlog < 0)
1008300Sroot 		backlog = 0;
10110137Ssam #define	SOMAXCONN	5
10210137Ssam 	so->so_qlimit = MIN(backlog, SOMAXCONN);
1038300Sroot 	so->so_options |= SO_NEWFDONCONN;
104*12493Ssam 	splx(s);
1058300Sroot 	return (0);
1068300Sroot }
1078300Sroot 
1084916Swnj sofree(so)
1094916Swnj 	struct socket *so;
1104916Swnj {
1114916Swnj 
1127507Sroot 	if (so->so_head) {
1137507Sroot 		if (!soqremque(so, 0) && !soqremque(so, 1))
1147507Sroot 			panic("sofree dq");
1157507Sroot 		so->so_head = 0;
1167507Sroot 	}
1177507Sroot 	if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
1184950Swnj 		return;
1194950Swnj 	sbrelease(&so->so_snd);
1204950Swnj 	sbrelease(&so->so_rcv);
1214971Swnj 	(void) m_free(dtom(so));
1224916Swnj }
1234916Swnj 
1244786Swnj /*
1254890Swnj  * Close a socket on last file table reference removal.
1264890Swnj  * Initiate disconnect if connected.
1274890Swnj  * Free socket when disconnect complete.
1284829Swnj  */
1295580Sroot soclose(so, exiting)
1304829Swnj 	register struct socket *so;
1315580Sroot 	int exiting;
1324829Swnj {
1334890Swnj 	int s = splnet();		/* conservative */
1348713Sroot 	int error;
1354829Swnj 
1367507Sroot 	if (so->so_options & SO_ACCEPTCONN) {
1377507Sroot 		while (so->so_q0 != so)
13810399Ssam 			(void) soabort(so->so_q0);
1397507Sroot 		while (so->so_q != so)
14010399Ssam 			(void) soabort(so->so_q);
1417507Sroot 	}
1424890Swnj 	if (so->so_pcb == 0)
1434890Swnj 		goto discard;
1446259Sroot 	if (exiting)
1456259Sroot 		so->so_options |= SO_KEEPALIVE;
1464890Swnj 	if (so->so_state & SS_ISCONNECTED) {
1474890Swnj 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
1488725Sroot 			error = sodisconnect(so, (struct mbuf *)0);
1498713Sroot 			if (error) {
1505580Sroot 				if (exiting)
1515580Sroot 					goto drop;
1524890Swnj 				splx(s);
1538713Sroot 				return (error);
1544890Swnj 			}
1554890Swnj 		}
15610267Ssam 		if (so->so_options & SO_LINGER) {
1575281Sroot 			if ((so->so_state & SS_ISDISCONNECTING) &&
1586214Swnj 			    (so->so_state & SS_NBIO) &&
1598713Sroot 			    exiting == 0)
1608713Sroot 				return (EINPROGRESS);
1615580Sroot 			/* should use tsleep here, for at most linger */
1625281Sroot 			while (so->so_state & SS_ISCONNECTED)
1635281Sroot 				sleep((caddr_t)&so->so_timeo, PZERO+1);
1644890Swnj 		}
1654890Swnj 	}
1665580Sroot drop:
1676880Ssam 	if (so->so_pcb) {
1688713Sroot 		error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH,
16910267Ssam 		    (struct mbuf *)0, (struct mbuf *)0);
1708713Sroot 		if (exiting == 0 && error) {
1716880Ssam 			splx(s);
1728713Sroot 			return (error);
1736880Ssam 		}
1746880Ssam 	}
1754890Swnj discard:
17610399Ssam 	if (so->so_state & SS_NOFDREF)
17710399Ssam 		panic("soclose: NOFDREF");
1787507Sroot 	so->so_state |= SS_NOFDREF;
1794950Swnj 	sofree(so);
1804890Swnj 	splx(s);
1818713Sroot 	return (0);
1824829Swnj }
1834829Swnj 
18410399Ssam /*
18510399Ssam  * Must be called at splnet...
18610399Ssam  */
18710399Ssam soabort(so)
18810399Ssam 	struct socket *so;
18910399Ssam {
19010399Ssam 	int error;
19110399Ssam 
19210399Ssam 	error = (*so->so_proto->pr_usrreq)(so, PRU_ABORT,
19310399Ssam 	   (struct mbuf *)0, (struct mbuf *)0);
19410399Ssam 	return (error);
19510399Ssam }
19610399Ssam 
1974916Swnj /*ARGSUSED*/
1989026Sroot sostat(so, ub)
1994829Swnj 	struct socket *so;
2009026Sroot 	struct stat *ub;
2014829Swnj {
2029026Sroot 	struct stat sb;
2034829Swnj 
2049026Sroot 	bzero((caddr_t)&sb, sizeof (sb));		/* XXX */
2059168Ssam 	(void) copyout((caddr_t)&sb, (caddr_t)ub, sizeof (sb));/* XXX */
2065303Sroot 	return (0);					/* XXX */
2074829Swnj }
2084829Swnj 
20910267Ssam soaccept(so, nam)
2104927Swnj 	struct socket *so;
2118300Sroot 	struct mbuf *nam;
2124927Swnj {
2134927Swnj 	int s = splnet();
2144927Swnj 	int error;
2154927Swnj 
21610399Ssam 	if ((so->so_state & SS_NOFDREF) == 0)
21710399Ssam 		panic("soaccept: !NOFDREF");
21810267Ssam 	so->so_state &= ~SS_NOFDREF;
2198300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT,
22010267Ssam 	    (struct mbuf *)0, nam);
2214927Swnj 	splx(s);
2224927Swnj 	return (error);
2234927Swnj }
2244927Swnj 
22510267Ssam soconnect(so, nam)
2264786Swnj 	struct socket *so;
2278300Sroot 	struct mbuf *nam;
2284786Swnj {
2294890Swnj 	int s = splnet();
2304890Swnj 	int error;
2314786Swnj 
2324890Swnj 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
2334890Swnj 		error = EISCONN;
2344890Swnj 		goto bad;
2354890Swnj 	}
2368300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
23710267Ssam 	    (struct mbuf *)0, nam);
2384890Swnj bad:
2394890Swnj 	splx(s);
2404890Swnj 	return (error);
2414786Swnj }
2424786Swnj 
2438300Sroot sodisconnect(so, nam)
2444786Swnj 	struct socket *so;
2458300Sroot 	struct mbuf *nam;
2464786Swnj {
2474890Swnj 	int s = splnet();
2484890Swnj 	int error;
2494786Swnj 
2504890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2514890Swnj 		error = ENOTCONN;
2524890Swnj 		goto bad;
2534890Swnj 	}
2544890Swnj 	if (so->so_state & SS_ISDISCONNECTING) {
2554890Swnj 		error = EALREADY;
2564890Swnj 		goto bad;
2574890Swnj 	}
2588300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT,
25910267Ssam 	    (struct mbuf *)0, nam);
2604890Swnj bad:
2614890Swnj 	splx(s);
2624890Swnj 	return (error);
2634786Swnj }
2644786Swnj 
2654786Swnj /*
2664890Swnj  * Send on a socket.
2674890Swnj  * If send must go all at once and message is larger than
2684890Swnj  * send buffering, then hard error.
2694890Swnj  * Lock against other senders.
2704890Swnj  * If must go all at once and not enough room now, then
2714890Swnj  * inform user that this would block and do nothing.
2724786Swnj  */
2738319Sroot sosend(so, nam, uio, flags)
2744786Swnj 	register struct socket *so;
2758300Sroot 	struct mbuf *nam;
2767827Sroot 	struct uio *uio;
2778319Sroot 	int flags;
2784786Swnj {
2794890Swnj 	struct mbuf *top = 0;
2804890Swnj 	register struct mbuf *m, **mp = &top;
2818713Sroot 	register int len;
28210267Ssam 	int error = 0, space, s, dontroute;
2834786Swnj 
2847827Sroot 	if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat)
2854890Swnj 		return (EMSGSIZE);
28610267Ssam 	dontroute = (flags & SOF_DONTROUTE) &&
28710267Ssam 		(so->so_options & SO_DONTROUTE) == 0 &&
28810267Ssam 		(so->so_proto->pr_flags & PR_ATOMIC);
2896419Sroot restart:
2904890Swnj 	sblock(&so->so_snd);
2914890Swnj #define	snderr(errno)	{ error = errno; splx(s); goto release; }
2924890Swnj 
2938041Sroot 	u.u_ru.ru_msgsnd++;
2946419Sroot again:
2954890Swnj 	s = splnet();
2966419Sroot 	if (so->so_state & SS_CANTSENDMORE) {
2976419Sroot 		psignal(u.u_procp, SIGPIPE);
2986419Sroot 		snderr(EPIPE);
2996419Sroot 	}
3005168Swnj 	if (so->so_error) {
3015168Swnj 		error = so->so_error;
3026419Sroot 		so->so_error = 0;				/* ??? */
3035168Swnj 		splx(s);
3045168Swnj 		goto release;
3055168Swnj 	}
3064890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
3074890Swnj 		if (so->so_proto->pr_flags & PR_CONNREQUIRED)
3084890Swnj 			snderr(ENOTCONN);
3098300Sroot 		if (nam == 0)
3104890Swnj 			snderr(EDESTADDRREQ);
3114890Swnj 	}
3124890Swnj 	if (top) {
31310267Ssam 		if (dontroute)
31410267Ssam 			so->so_options |= SO_DONTROUTE;
3158319Sroot 		error = (*so->so_proto->pr_usrreq)(so,
3168319Sroot 		    (flags & SOF_OOB) ? PRU_SENDOOB : PRU_SEND,
31710267Ssam 		    top, (caddr_t)nam);
31810267Ssam 		if (dontroute)
31910267Ssam 			so->so_options &= ~SO_DONTROUTE;
3206419Sroot 		top = 0;
3214890Swnj 		if (error) {
3224890Swnj 			splx(s);
3234786Swnj 			goto release;
3244786Swnj 		}
3254890Swnj 		mp = &top;
3264786Swnj 	}
3277827Sroot 	if (uio->uio_resid == 0) {
3284979Swnj 		splx(s);
3294979Swnj 		goto release;
3304979Swnj 	}
3318319Sroot 	if (flags & SOF_OOB)
3328319Sroot 		space = 1024;
3338319Sroot 	else {
3348319Sroot 		space = sbspace(&so->so_snd);
3358319Sroot 		if (space <= 0 ||
3368319Sroot 		    sosendallatonce(so) && space < uio->uio_resid) {
3378319Sroot 			if (so->so_state & SS_NBIO)
3388319Sroot 				snderr(EWOULDBLOCK);
3398319Sroot 			sbunlock(&so->so_snd);
3408319Sroot 			sbwait(&so->so_snd);
3418319Sroot 			splx(s);
3428319Sroot 			goto restart;
3438319Sroot 		}
3444786Swnj 	}
3454890Swnj 	splx(s);
3467827Sroot 	while (uio->uio_resid > 0 && space > 0) {
3477827Sroot 		register struct iovec *iov = uio->uio_iov;
3487827Sroot 
3497827Sroot 		if (iov->iov_len == 0) {
3507827Sroot 			uio->uio_iov++;
3517827Sroot 			uio->uio_iovcnt--;
3527827Sroot 			if (uio->uio_iovcnt < 0)
3537827Sroot 				panic("sosend");
3547827Sroot 			continue;
3557827Sroot 		}
3569635Ssam 		MGET(m, M_WAIT, MT_DATA);
3574890Swnj 		if (m == NULL) {
3586419Sroot 			error = ENOBUFS;			/* SIGPIPE? */
3594890Swnj 			goto release;
3604786Swnj 		}
3617827Sroot 		if (iov->iov_len >= CLBYTES && space >= CLBYTES) {
3624890Swnj 			register struct mbuf *p;
3635095Swnj 			MCLGET(p, 1);
3644890Swnj 			if (p == 0)
3654890Swnj 				goto nopages;
3664890Swnj 			m->m_off = (int)p - (int)m;
3675095Swnj 			len = CLBYTES;
3684890Swnj 		} else {
3694786Swnj nopages:
3707827Sroot 			len = MIN(MLEN, iov->iov_len);
3714786Swnj 		}
3728771Sroot 		(void) uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio);
3734890Swnj 		m->m_len = len;
3744890Swnj 		*mp = m;
3754890Swnj 		mp = &m->m_next;
3768319Sroot 		if (flags & SOF_OOB)
3778319Sroot 			space -= len;
3788319Sroot 		else
3798319Sroot 			space = sbspace(&so->so_snd);
3804786Swnj 	}
3814890Swnj 	goto again;
3824890Swnj 
3834786Swnj release:
3844890Swnj 	sbunlock(&so->so_snd);
3856419Sroot 	if (top)
3866419Sroot 		m_freem(top);
3874786Swnj 	return (error);
3884786Swnj }
3894786Swnj 
3908319Sroot soreceive(so, aname, uio, flags)
3914786Swnj 	register struct socket *so;
3928300Sroot 	struct mbuf **aname;
3937747Sroot 	struct uio *uio;
3948319Sroot 	int flags;
3954786Swnj {
3964786Swnj 	register struct mbuf *m, *n;
3978713Sroot 	int len;
3988319Sroot 	int eor, s, error = 0, moff, tomark;
3994786Swnj 
4008319Sroot 	if (flags & SOF_OOB) {
4019635Ssam 		m = m_get(M_WAIT, MT_DATA);
40210137Ssam 		if (m == NULL)
40310137Ssam 			return (ENOBUFS);
4048594Sroot 		error = (*so->so_proto->pr_usrreq)(so, PRU_RCVOOB,
40510267Ssam 		    m, (struct mbuf *)0);
4068594Sroot 		if (error)
40710137Ssam 			goto bad;
4088319Sroot 		do {
40910137Ssam 			len = uio->uio_resid;
4108319Sroot 			if (len > m->m_len)
4118319Sroot 				len = m->m_len;
4128594Sroot 			error =
4138793Sroot 			    uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio);
4148319Sroot 			m = m_free(m);
4158594Sroot 		} while (uio->uio_resid && error == 0 && m);
41610137Ssam bad:
4178319Sroot 		if (m)
4188771Sroot 			m_freem(m);
4198594Sroot 		return (error);
4208319Sroot 	}
4218319Sroot 
4224890Swnj restart:
4234890Swnj 	sblock(&so->so_rcv);
4248835Sroot 	s = splnet();
4254890Swnj 
4264890Swnj #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
4274786Swnj 	if (so->so_rcv.sb_cc == 0) {
4285168Swnj 		if (so->so_error) {
4295168Swnj 			error = so->so_error;
4305168Swnj 			so->so_error = 0;
4315168Swnj 			splx(s);
4325168Swnj 			goto release;
4335168Swnj 		}
4344890Swnj 		if (so->so_state & SS_CANTRCVMORE) {
4354890Swnj 			splx(s);
4364890Swnj 			goto release;
4374890Swnj 		}
4385015Sroot 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
4395015Sroot 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
4405015Sroot 			rcverr(ENOTCONN);
4416214Swnj 		if (so->so_state & SS_NBIO)
4425168Swnj 			rcverr(EWOULDBLOCK);
4434890Swnj 		sbunlock(&so->so_rcv);
4444971Swnj 		sbwait(&so->so_rcv);
4455012Swnj 		splx(s);
4464890Swnj 		goto restart;
4474786Swnj 	}
4488041Sroot 	u.u_ru.ru_msgrcv++;
4494829Swnj 	m = so->so_rcv.sb_mb;
4504786Swnj 	if (m == 0)
4514786Swnj 		panic("receive");
4525039Swnj 	if (so->so_proto->pr_flags & PR_ADDR) {
4538319Sroot 		if ((flags & SOF_PREVIEW) == 0) {
4548319Sroot 			so->so_rcv.sb_cc -= m->m_len;
4558319Sroot 			so->so_rcv.sb_mbcnt -= MSIZE;
4568319Sroot 		}
4578300Sroot 		if (aname) {
45810137Ssam 			if (flags & SOF_PREVIEW) {
4598319Sroot 				*aname = m_copy(m, 0, m->m_len);
46010137Ssam 				if (*aname == NULL)
46110137Ssam 					panic("receive 2");
46210137Ssam 			} else
4638319Sroot 				*aname = m;
4648300Sroot 			m = m->m_next;
4658300Sroot 			(*aname)->m_next = 0;
4668300Sroot 		} else
4678319Sroot 			if (flags & SOF_PREVIEW)
4688319Sroot 				m = m->m_next;
4698319Sroot 			else
4708319Sroot 				m = m_free(m);
4714890Swnj 		if (m == 0)
47210137Ssam 			panic("receive 3");
4738548Sroot 		if ((flags & SOF_PREVIEW) == 0)
4748548Sroot 			so->so_rcv.sb_mb = m;
4754890Swnj 	}
4764786Swnj 	eor = 0;
4778319Sroot 	moff = 0;
4788319Sroot 	tomark = so->so_oobmark;
4794786Swnj 	do {
4807827Sroot 		if (uio->uio_resid <= 0)
4817747Sroot 			break;
4827827Sroot 		len = uio->uio_resid;
4837747Sroot 		so->so_state &= ~SS_RCVATMARK;
4848319Sroot 		if (tomark && len > tomark)
4858319Sroot 			len = tomark;
4868548Sroot 		if (moff+len > m->m_len - moff)
4878319Sroot 			len = m->m_len - moff;
4884786Swnj 		splx(s);
4898594Sroot 		error =
4908793Sroot 		    uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio);
4914786Swnj 		s = splnet();
4924786Swnj 		if (len == m->m_len) {
4936091Sroot 			eor = (int)m->m_act;
4948319Sroot 			if (flags & SOF_PREVIEW)
4958319Sroot 				m = m->m_next;
4968319Sroot 			else {
4978319Sroot 				sbfree(&so->so_rcv, m);
4988319Sroot 				MFREE(m, n);
4998319Sroot 				m = n;
5008548Sroot 				so->so_rcv.sb_mb = m;
5018319Sroot 			}
5028319Sroot 			moff = 0;
5034786Swnj 		} else {
5048319Sroot 			if (flags & SOF_PREVIEW)
5058319Sroot 				moff += len;
5068319Sroot 			else {
5078319Sroot 				m->m_off += len;
5088319Sroot 				m->m_len -= len;
5098319Sroot 				so->so_rcv.sb_cc -= len;
5108319Sroot 			}
5114786Swnj 		}
5128319Sroot 		if ((flags & SOF_PREVIEW) == 0 && so->so_oobmark) {
5137747Sroot 			so->so_oobmark -= len;
5147747Sroot 			if (so->so_oobmark == 0) {
5157747Sroot 				so->so_state |= SS_RCVATMARK;
5167747Sroot 				break;
5177747Sroot 			}
5187747Sroot 		}
5198319Sroot 		if (tomark) {
5208319Sroot 			tomark -= len;
5218319Sroot 			if (tomark == 0)
5228319Sroot 				break;
5238319Sroot 		}
5248594Sroot 	} while (m && error == 0 && !eor);
5258319Sroot 	if (flags & SOF_PREVIEW)
5268319Sroot 		goto release;
5274786Swnj 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
5284786Swnj 		do {
5294786Swnj 			if (m == 0)
53010137Ssam 				panic("receive 4");
5314890Swnj 			sbfree(&so->so_rcv, m);
5324786Swnj 			eor = (int)m->m_act;
5334786Swnj 			so->so_rcv.sb_mb = m->m_next;
5344786Swnj 			MFREE(m, n);
5354890Swnj 			m = n;
5364786Swnj 		} while (eor == 0);
5374890Swnj 	if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
5388300Sroot 		(*so->so_proto->pr_usrreq)(so, PRU_RCVD,
53910267Ssam 		    (struct mbuf *)0, (struct mbuf *)0);
5404890Swnj release:
5414916Swnj 	sbunlock(&so->so_rcv);
5424890Swnj 	splx(s);
5434916Swnj 	return (error);
5444786Swnj }
5454786Swnj 
54610267Ssam soshutdown(so, how)
54710267Ssam 	struct socket *so;
54810267Ssam 	int how;
54910267Ssam {
55010267Ssam 
55110267Ssam 	how++;
55210267Ssam 	if (how & FREAD) {
55310267Ssam 		int s = splimp();
55410267Ssam 		socantrcvmore(so);
55510267Ssam 		sbflush(&so->so_rcv);
55610267Ssam 		splx(s);
55710267Ssam 	}
55810267Ssam 	if (how & FWRITE)
55910267Ssam 		return ((*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN,
56010267Ssam 		    (struct mbuf *)0, (struct mbuf *)0));
56110267Ssam 	return (0);
56210267Ssam }
56310267Ssam 
56410267Ssam sosetopt(so, level, optname, m)
56510267Ssam 	struct socket *so;
56610267Ssam 	int level, optname;
56710267Ssam 	struct mbuf *m;
56810267Ssam {
56910267Ssam 
57010267Ssam 	if (level != SOL_SOCKET)
57110267Ssam 		return (EINVAL);	/* XXX */
57210267Ssam 	switch (optname) {
57310267Ssam 
57410267Ssam 	case SO_DEBUG:
57510269Ssam 	case SO_KEEPALIVE:
57610599Ssam 	case SO_DONTROUTE:
57710599Ssam 	case SO_USELOOPBACK:
57810599Ssam 	case SO_REUSEADDR:
57910599Ssam 		so->so_options |= optname;
58010269Ssam 		break;
58110269Ssam 
58210267Ssam 	case SO_LINGER:
58310269Ssam 		if (m == NULL || m->m_len != sizeof (int))
58410269Ssam 			return (EINVAL);
58510267Ssam 		so->so_options |= SO_LINGER;
58610269Ssam 		so->so_linger = *mtod(m, int *);
58710267Ssam 		break;
58810267Ssam 
58910267Ssam 	case SO_DONTLINGER:
59010267Ssam 		so->so_options &= ~SO_LINGER;
59110267Ssam 		so->so_linger = 0;
59210267Ssam 		break;
59310267Ssam 
59410267Ssam 	default:
59510267Ssam 		return (EINVAL);
59610267Ssam 	}
59710267Ssam 	return (0);
59810267Ssam }
59910267Ssam 
60010267Ssam sogetopt(so, level, optname, m)
60110267Ssam 	struct socket *so;
60210267Ssam 	int level, optname;
60310267Ssam 	struct mbuf *m;
60410267Ssam {
60510267Ssam 
60610267Ssam 	if (level != SOL_SOCKET)
60710267Ssam 		return (EINVAL);	/* XXX */
60810267Ssam 	switch (optname) {
60910267Ssam 
61010267Ssam 	case SO_USELOOPBACK:
61110267Ssam 	case SO_DONTROUTE:
61210267Ssam 	case SO_DEBUG:
61310267Ssam 	case SO_KEEPALIVE:
61410267Ssam 	case SO_LINGER:
61510599Ssam 	case SO_REUSEADDR:
61610267Ssam 		if ((so->so_options & optname) == 0)
61710267Ssam 			return (ENOPROTOOPT);
61810269Ssam 		if (optname == SO_LINGER && m != NULL) {
61910267Ssam 			*mtod(m, int *) = so->so_linger;
62010267Ssam 			m->m_len = sizeof (so->so_linger);
62110267Ssam 		}
62210267Ssam 		break;
62310267Ssam 
62410267Ssam 	default:
62510267Ssam 		return (EINVAL);
62610267Ssam 	}
62710267Ssam 	return (0);
62810267Ssam }
62910267Ssam 
6305423Swnj sohasoutofband(so)
6315423Swnj 	struct socket *so;
6325423Swnj {
6335423Swnj 
6345423Swnj 	if (so->so_pgrp == 0)
6355423Swnj 		return;
6365423Swnj 	if (so->so_pgrp > 0)
6375423Swnj 		gsignal(so->so_pgrp, SIGURG);
6385429Swnj 	else {
6395429Swnj 		struct proc *p = pfind(-so->so_pgrp);
6405429Swnj 
6415429Swnj 		if (p)
6425429Swnj 			psignal(p, SIGURG);
6435429Swnj 	}
6445423Swnj }
6455423Swnj 
6464916Swnj /*ARGSUSED*/
6477627Ssam soioctl(so, cmd, data)
6484829Swnj 	register struct socket *so;
6494829Swnj 	int cmd;
6507627Ssam 	register char *data;
6514786Swnj {
6524786Swnj 
6535358Sroot 	switch (cmd) {
6544829Swnj 
6557627Ssam 	case FIONBIO:
6567627Ssam 		if (*(int *)data)
6576214Swnj 			so->so_state |= SS_NBIO;
6585388Sroot 		else
6596214Swnj 			so->so_state &= ~SS_NBIO;
6608594Sroot 		break;
6615388Sroot 
6627627Ssam 	case FIOASYNC:
6637627Ssam 		if (*(int *)data)
6646214Swnj 			so->so_state |= SS_ASYNC;
6655388Sroot 		else
6666214Swnj 			so->so_state &= ~SS_ASYNC;
6678594Sroot 		break;
6685388Sroot 
6697627Ssam 	case SIOCSPGRP:
6707627Ssam 		so->so_pgrp = *(int *)data;
6718594Sroot 		break;
6725423Swnj 
6737627Ssam 	case SIOCGPGRP:
6747627Ssam 		*(int *)data = so->so_pgrp;
6758594Sroot 		break;
6767627Ssam 
6777627Ssam 	case SIOCATMARK:
6787627Ssam 		*(int *)data = (so->so_state&SS_RCVATMARK) != 0;
6798594Sroot 		break;
6806355Ssam 
6816355Ssam 	/* routing table update calls */
6826355Ssam 	case SIOCADDRT:
6836355Ssam 	case SIOCDELRT:
6846355Ssam 		if (!suser())
68510137Ssam 			return (u.u_error);
6868560Sroot 		return (rtrequest(cmd, (struct rtentry *)data));
6876355Ssam 
68811571Ssam 	/* interface parameter requests */
68911571Ssam 	case SIOCSIFADDR:
69011571Ssam 	case SIOCSIFFLAGS:
69111632Ssam 	case SIOCSIFDSTADDR:
69211571Ssam 		if (!suser())
69311571Ssam 			return (u.u_error);
69411571Ssam 		return (ifrequest(cmd, data));
69511571Ssam 
69611571Ssam 	case SIOCGIFADDR:
69711571Ssam 	case SIOCGIFFLAGS:
69811632Ssam 	case SIOCGIFDSTADDR:
69911571Ssam 		return (ifrequest(cmd, data));
70011571Ssam 
70111571Ssam 	case SIOCGIFCONF:
70211571Ssam 		return (ifconf(cmd, data));
70311571Ssam 
7045445Swnj 	/* type/protocol specific ioctls */
7058594Sroot 	default:
70610137Ssam 		return (ENOTTY);		/* XXX */
7075423Swnj 	}
7088594Sroot 	return (0);
7094786Swnj }
710