xref: /csrg-svn/sys/kern/uipc_socket.c (revision 10269)
1*10269Ssam /*	uipc_socket.c	4.69	83/01/13	*/
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"
194786Swnj 
204786Swnj /*
218300Sroot  * Socket operation routines.
228300Sroot  * These routines are called by the routines in
238300Sroot  * sys_socket.c or from a system process, and
248300Sroot  * implement the semantics of socket operations by
258300Sroot  * switching out to the protocol specific routines.
264786Swnj  */
274786Swnj 
288594Sroot /*ARGSUSED*/
2910267Ssam socreate(dom, aso, type, proto)
304786Swnj 	struct socket **aso;
318300Sroot 	int type, proto;
324786Swnj {
334786Swnj 	register struct protosw *prp;
344786Swnj 	register struct socket *so;
354786Swnj 	struct mbuf *m;
369168Ssam 	int error;
374786Swnj 
384890Swnj 	if (proto)
399168Ssam 		prp = pffindproto(dom, proto);
404890Swnj 	else
419168Ssam 		prp = pffindtype(dom, type);
424890Swnj 	if (prp == 0)
434890Swnj 		return (EPROTONOSUPPORT);
448300Sroot 	if (prp->pr_type != type)
458300Sroot 		return (EPROTOTYPE);
469635Ssam 	m = m_getclr(M_WAIT, MT_SOCKET);
474786Swnj 	if (m == 0)
484786Swnj 		return (ENOBUFS);
494786Swnj 	so = mtod(m, struct socket *);
5010267Ssam 	so->so_options = SO_LINGER;
516214Swnj 	so->so_state = 0;
529168Ssam 	so->so_type = type;
536214Swnj 	if (u.u_uid == 0)
546214Swnj 		so->so_state = SS_PRIV;
554786Swnj 	so->so_proto = prp;
568300Sroot 	error = (*prp->pr_usrreq)(so, PRU_ATTACH,
5710267Ssam 	    (struct mbuf *)0, (struct mbuf *)0);
584979Swnj 	if (error) {
597507Sroot 		so->so_state |= SS_NOFDREF;
607180Swnj 		sofree(so);
614890Swnj 		return (error);
624786Swnj 	}
634786Swnj 	*aso = so;
644786Swnj 	return (0);
654786Swnj }
664786Swnj 
6710267Ssam sobind(so, nam)
688300Sroot 	struct socket *so;
698300Sroot 	struct mbuf *nam;
708300Sroot {
718300Sroot 	int s = splnet();
728300Sroot 	int error;
738300Sroot 
748300Sroot 	error =
7510267Ssam 	    (*so->so_proto->pr_usrreq)(so, PRU_BIND, (struct mbuf *)0, nam);
768300Sroot 	splx(s);
778300Sroot 	return (error);
788300Sroot }
798300Sroot 
808300Sroot solisten(so, backlog)
818300Sroot 	struct socket *so;
828300Sroot 	int backlog;
838300Sroot {
848300Sroot 	int s = splnet();
858300Sroot 	int error;
868300Sroot 
878300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_LISTEN,
8810267Ssam 	    (struct mbuf *)0, (struct mbuf *)0);
898300Sroot 	if (error) {
908300Sroot 		splx(s);
918300Sroot 		return (error);
928300Sroot 	}
938300Sroot 	if (so->so_q == 0) {
948300Sroot 		so->so_q = so;
958300Sroot 		so->so_q0 = so;
968300Sroot 		so->so_options |= SO_ACCEPTCONN;
978300Sroot 	}
988300Sroot 	if (backlog < 0)
998300Sroot 		backlog = 0;
10010137Ssam #define	SOMAXCONN	5
10110137Ssam 	so->so_qlimit = MIN(backlog, SOMAXCONN);
1028300Sroot 	so->so_options |= SO_NEWFDONCONN;
1038300Sroot 	return (0);
1048300Sroot }
1058300Sroot 
1064916Swnj sofree(so)
1074916Swnj 	struct socket *so;
1084916Swnj {
1094916Swnj 
1107507Sroot 	if (so->so_head) {
1117507Sroot 		if (!soqremque(so, 0) && !soqremque(so, 1))
1127507Sroot 			panic("sofree dq");
1137507Sroot 		so->so_head = 0;
1147507Sroot 	}
1157507Sroot 	if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
1164950Swnj 		return;
1174950Swnj 	sbrelease(&so->so_snd);
1184950Swnj 	sbrelease(&so->so_rcv);
1194971Swnj 	(void) m_free(dtom(so));
1204916Swnj }
1214916Swnj 
1224786Swnj /*
1234890Swnj  * Close a socket on last file table reference removal.
1244890Swnj  * Initiate disconnect if connected.
1254890Swnj  * Free socket when disconnect complete.
1264829Swnj  */
1275580Sroot soclose(so, exiting)
1284829Swnj 	register struct socket *so;
1295580Sroot 	int exiting;
1304829Swnj {
1314890Swnj 	int s = splnet();		/* conservative */
1328713Sroot 	int error;
1334829Swnj 
1347507Sroot 	if (so->so_options & SO_ACCEPTCONN) {
1357507Sroot 		while (so->so_q0 != so)
1368713Sroot 			(void) soclose(so->so_q0, 1);
1377507Sroot 		while (so->so_q != so)
1388713Sroot 			(void) soclose(so->so_q, 1);
1397507Sroot 	}
1404890Swnj 	if (so->so_pcb == 0)
1414890Swnj 		goto discard;
1426259Sroot 	if (exiting)
1436259Sroot 		so->so_options |= SO_KEEPALIVE;
1444890Swnj 	if (so->so_state & SS_ISCONNECTED) {
1454890Swnj 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
1468725Sroot 			error = sodisconnect(so, (struct mbuf *)0);
1478713Sroot 			if (error) {
1485580Sroot 				if (exiting)
1495580Sroot 					goto drop;
1504890Swnj 				splx(s);
1518713Sroot 				return (error);
1524890Swnj 			}
1534890Swnj 		}
15410267Ssam 		if (so->so_options & SO_LINGER) {
1555281Sroot 			if ((so->so_state & SS_ISDISCONNECTING) &&
1566214Swnj 			    (so->so_state & SS_NBIO) &&
1578713Sroot 			    exiting == 0)
1588713Sroot 				return (EINPROGRESS);
1595580Sroot 			/* should use tsleep here, for at most linger */
1605281Sroot 			while (so->so_state & SS_ISCONNECTED)
1615281Sroot 				sleep((caddr_t)&so->so_timeo, PZERO+1);
1624890Swnj 		}
1634890Swnj 	}
1645580Sroot drop:
1656880Ssam 	if (so->so_pcb) {
1668713Sroot 		error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH,
16710267Ssam 		    (struct mbuf *)0, (struct mbuf *)0);
1688713Sroot 		if (exiting == 0 && error) {
1696880Ssam 			splx(s);
1708713Sroot 			return (error);
1716880Ssam 		}
1726880Ssam 	}
1734890Swnj discard:
1747507Sroot 	so->so_state |= SS_NOFDREF;
1754950Swnj 	sofree(so);
1764890Swnj 	splx(s);
1778713Sroot 	return (0);
1784829Swnj }
1794829Swnj 
1804916Swnj /*ARGSUSED*/
1819026Sroot sostat(so, ub)
1824829Swnj 	struct socket *so;
1839026Sroot 	struct stat *ub;
1844829Swnj {
1859026Sroot 	struct stat sb;
1864829Swnj 
1879026Sroot 	bzero((caddr_t)&sb, sizeof (sb));		/* XXX */
1889168Ssam 	(void) copyout((caddr_t)&sb, (caddr_t)ub, sizeof (sb));/* XXX */
1895303Sroot 	return (0);					/* XXX */
1904829Swnj }
1914829Swnj 
19210267Ssam soaccept(so, nam)
1934927Swnj 	struct socket *so;
1948300Sroot 	struct mbuf *nam;
1954927Swnj {
1964927Swnj 	int s = splnet();
1974927Swnj 	int error;
1984927Swnj 
19910267Ssam 	so->so_state &= ~SS_NOFDREF;
2008300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT,
20110267Ssam 	    (struct mbuf *)0, nam);
2024927Swnj 	splx(s);
2034927Swnj 	return (error);
2044927Swnj }
2054927Swnj 
20610267Ssam soconnect(so, nam)
2074786Swnj 	struct socket *so;
2088300Sroot 	struct mbuf *nam;
2094786Swnj {
2104890Swnj 	int s = splnet();
2114890Swnj 	int error;
2124786Swnj 
2134890Swnj 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
2144890Swnj 		error = EISCONN;
2154890Swnj 		goto bad;
2164890Swnj 	}
2178300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
21810267Ssam 	    (struct mbuf *)0, nam);
2194890Swnj bad:
2204890Swnj 	splx(s);
2214890Swnj 	return (error);
2224786Swnj }
2234786Swnj 
2248300Sroot sodisconnect(so, nam)
2254786Swnj 	struct socket *so;
2268300Sroot 	struct mbuf *nam;
2274786Swnj {
2284890Swnj 	int s = splnet();
2294890Swnj 	int error;
2304786Swnj 
2314890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2324890Swnj 		error = ENOTCONN;
2334890Swnj 		goto bad;
2344890Swnj 	}
2354890Swnj 	if (so->so_state & SS_ISDISCONNECTING) {
2364890Swnj 		error = EALREADY;
2374890Swnj 		goto bad;
2384890Swnj 	}
2398300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT,
24010267Ssam 	    (struct mbuf *)0, nam);
2414890Swnj bad:
2424890Swnj 	splx(s);
2434890Swnj 	return (error);
2444786Swnj }
2454786Swnj 
2464786Swnj /*
2474890Swnj  * Send on a socket.
2484890Swnj  * If send must go all at once and message is larger than
2494890Swnj  * send buffering, then hard error.
2504890Swnj  * Lock against other senders.
2514890Swnj  * If must go all at once and not enough room now, then
2524890Swnj  * inform user that this would block and do nothing.
2534786Swnj  */
2548319Sroot sosend(so, nam, uio, flags)
2554786Swnj 	register struct socket *so;
2568300Sroot 	struct mbuf *nam;
2577827Sroot 	struct uio *uio;
2588319Sroot 	int flags;
2594786Swnj {
2604890Swnj 	struct mbuf *top = 0;
2614890Swnj 	register struct mbuf *m, **mp = &top;
2628713Sroot 	register int len;
26310267Ssam 	int error = 0, space, s, dontroute;
2644786Swnj 
2657827Sroot 	if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat)
2664890Swnj 		return (EMSGSIZE);
26710267Ssam 	dontroute = (flags & SOF_DONTROUTE) &&
26810267Ssam 		(so->so_options & SO_DONTROUTE) == 0 &&
26910267Ssam 		(so->so_proto->pr_flags & PR_ATOMIC);
2706419Sroot restart:
2714890Swnj 	sblock(&so->so_snd);
2724890Swnj #define	snderr(errno)	{ error = errno; splx(s); goto release; }
2734890Swnj 
2748041Sroot 	u.u_ru.ru_msgsnd++;
2756419Sroot again:
2764890Swnj 	s = splnet();
2776419Sroot 	if (so->so_state & SS_CANTSENDMORE) {
2786419Sroot 		psignal(u.u_procp, SIGPIPE);
2796419Sroot 		snderr(EPIPE);
2806419Sroot 	}
2815168Swnj 	if (so->so_error) {
2825168Swnj 		error = so->so_error;
2836419Sroot 		so->so_error = 0;				/* ??? */
2845168Swnj 		splx(s);
2855168Swnj 		goto release;
2865168Swnj 	}
2874890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2884890Swnj 		if (so->so_proto->pr_flags & PR_CONNREQUIRED)
2894890Swnj 			snderr(ENOTCONN);
2908300Sroot 		if (nam == 0)
2914890Swnj 			snderr(EDESTADDRREQ);
2924890Swnj 	}
2934890Swnj 	if (top) {
29410267Ssam 		if (dontroute)
29510267Ssam 			so->so_options |= SO_DONTROUTE;
2968319Sroot 		error = (*so->so_proto->pr_usrreq)(so,
2978319Sroot 		    (flags & SOF_OOB) ? PRU_SENDOOB : PRU_SEND,
29810267Ssam 		    top, (caddr_t)nam);
29910267Ssam 		if (dontroute)
30010267Ssam 			so->so_options &= ~SO_DONTROUTE;
3016419Sroot 		top = 0;
3024890Swnj 		if (error) {
3034890Swnj 			splx(s);
3044786Swnj 			goto release;
3054786Swnj 		}
3064890Swnj 		mp = &top;
3074786Swnj 	}
3087827Sroot 	if (uio->uio_resid == 0) {
3094979Swnj 		splx(s);
3104979Swnj 		goto release;
3114979Swnj 	}
3128319Sroot 	if (flags & SOF_OOB)
3138319Sroot 		space = 1024;
3148319Sroot 	else {
3158319Sroot 		space = sbspace(&so->so_snd);
3168319Sroot 		if (space <= 0 ||
3178319Sroot 		    sosendallatonce(so) && space < uio->uio_resid) {
3188319Sroot 			if (so->so_state & SS_NBIO)
3198319Sroot 				snderr(EWOULDBLOCK);
3208319Sroot 			sbunlock(&so->so_snd);
3218319Sroot 			sbwait(&so->so_snd);
3228319Sroot 			splx(s);
3238319Sroot 			goto restart;
3248319Sroot 		}
3254786Swnj 	}
3264890Swnj 	splx(s);
3277827Sroot 	while (uio->uio_resid > 0 && space > 0) {
3287827Sroot 		register struct iovec *iov = uio->uio_iov;
3297827Sroot 
3307827Sroot 		if (iov->iov_len == 0) {
3317827Sroot 			uio->uio_iov++;
3327827Sroot 			uio->uio_iovcnt--;
3337827Sroot 			if (uio->uio_iovcnt < 0)
3347827Sroot 				panic("sosend");
3357827Sroot 			continue;
3367827Sroot 		}
3379635Ssam 		MGET(m, M_WAIT, MT_DATA);
3384890Swnj 		if (m == NULL) {
3396419Sroot 			error = ENOBUFS;			/* SIGPIPE? */
3404890Swnj 			goto release;
3414786Swnj 		}
3427827Sroot 		if (iov->iov_len >= CLBYTES && space >= CLBYTES) {
3434890Swnj 			register struct mbuf *p;
3445095Swnj 			MCLGET(p, 1);
3454890Swnj 			if (p == 0)
3464890Swnj 				goto nopages;
3474890Swnj 			m->m_off = (int)p - (int)m;
3485095Swnj 			len = CLBYTES;
3494890Swnj 		} else {
3504786Swnj nopages:
3517827Sroot 			len = MIN(MLEN, iov->iov_len);
3524786Swnj 		}
3538771Sroot 		(void) uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio);
3544890Swnj 		m->m_len = len;
3554890Swnj 		*mp = m;
3564890Swnj 		mp = &m->m_next;
3578319Sroot 		if (flags & SOF_OOB)
3588319Sroot 			space -= len;
3598319Sroot 		else
3608319Sroot 			space = sbspace(&so->so_snd);
3614786Swnj 	}
3624890Swnj 	goto again;
3634890Swnj 
3644786Swnj release:
3654890Swnj 	sbunlock(&so->so_snd);
3666419Sroot 	if (top)
3676419Sroot 		m_freem(top);
3684786Swnj 	return (error);
3694786Swnj }
3704786Swnj 
3718319Sroot soreceive(so, aname, uio, flags)
3724786Swnj 	register struct socket *so;
3738300Sroot 	struct mbuf **aname;
3747747Sroot 	struct uio *uio;
3758319Sroot 	int flags;
3764786Swnj {
3774786Swnj 	register struct mbuf *m, *n;
3788713Sroot 	int len;
3798319Sroot 	int eor, s, error = 0, moff, tomark;
3804786Swnj 
3818319Sroot 	if (flags & SOF_OOB) {
3829635Ssam 		m = m_get(M_WAIT, MT_DATA);
38310137Ssam 		if (m == NULL)
38410137Ssam 			return (ENOBUFS);
3858594Sroot 		error = (*so->so_proto->pr_usrreq)(so, PRU_RCVOOB,
38610267Ssam 		    m, (struct mbuf *)0);
3878594Sroot 		if (error)
38810137Ssam 			goto bad;
3898319Sroot 		do {
39010137Ssam 			len = uio->uio_resid;
3918319Sroot 			if (len > m->m_len)
3928319Sroot 				len = m->m_len;
3938594Sroot 			error =
3948793Sroot 			    uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio);
3958319Sroot 			m = m_free(m);
3968594Sroot 		} while (uio->uio_resid && error == 0 && m);
39710137Ssam bad:
3988319Sroot 		if (m)
3998771Sroot 			m_freem(m);
4008594Sroot 		return (error);
4018319Sroot 	}
4028319Sroot 
4034890Swnj restart:
4044890Swnj 	sblock(&so->so_rcv);
4058835Sroot 	s = splnet();
4064890Swnj 
4074890Swnj #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
4084786Swnj 	if (so->so_rcv.sb_cc == 0) {
4095168Swnj 		if (so->so_error) {
4105168Swnj 			error = so->so_error;
4115168Swnj 			so->so_error = 0;
4125168Swnj 			splx(s);
4135168Swnj 			goto release;
4145168Swnj 		}
4154890Swnj 		if (so->so_state & SS_CANTRCVMORE) {
4164890Swnj 			splx(s);
4174890Swnj 			goto release;
4184890Swnj 		}
4195015Sroot 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
4205015Sroot 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
4215015Sroot 			rcverr(ENOTCONN);
4226214Swnj 		if (so->so_state & SS_NBIO)
4235168Swnj 			rcverr(EWOULDBLOCK);
4244890Swnj 		sbunlock(&so->so_rcv);
4254971Swnj 		sbwait(&so->so_rcv);
4265012Swnj 		splx(s);
4274890Swnj 		goto restart;
4284786Swnj 	}
4298041Sroot 	u.u_ru.ru_msgrcv++;
4304829Swnj 	m = so->so_rcv.sb_mb;
4314786Swnj 	if (m == 0)
4324786Swnj 		panic("receive");
4335039Swnj 	if (so->so_proto->pr_flags & PR_ADDR) {
4348319Sroot 		if ((flags & SOF_PREVIEW) == 0) {
4358319Sroot 			so->so_rcv.sb_cc -= m->m_len;
4368319Sroot 			so->so_rcv.sb_mbcnt -= MSIZE;
4378319Sroot 		}
4388300Sroot 		if (aname) {
43910137Ssam 			if (flags & SOF_PREVIEW) {
4408319Sroot 				*aname = m_copy(m, 0, m->m_len);
44110137Ssam 				if (*aname == NULL)
44210137Ssam 					panic("receive 2");
44310137Ssam 			} else
4448319Sroot 				*aname = m;
4458300Sroot 			m = m->m_next;
4468300Sroot 			(*aname)->m_next = 0;
4478300Sroot 		} else
4488319Sroot 			if (flags & SOF_PREVIEW)
4498319Sroot 				m = m->m_next;
4508319Sroot 			else
4518319Sroot 				m = m_free(m);
4524890Swnj 		if (m == 0)
45310137Ssam 			panic("receive 3");
4548548Sroot 		if ((flags & SOF_PREVIEW) == 0)
4558548Sroot 			so->so_rcv.sb_mb = m;
4564890Swnj 	}
4574786Swnj 	eor = 0;
4588319Sroot 	moff = 0;
4598319Sroot 	tomark = so->so_oobmark;
4604786Swnj 	do {
4617827Sroot 		if (uio->uio_resid <= 0)
4627747Sroot 			break;
4637827Sroot 		len = uio->uio_resid;
4647747Sroot 		so->so_state &= ~SS_RCVATMARK;
4658319Sroot 		if (tomark && len > tomark)
4668319Sroot 			len = tomark;
4678548Sroot 		if (moff+len > m->m_len - moff)
4688319Sroot 			len = m->m_len - moff;
4694786Swnj 		splx(s);
4708594Sroot 		error =
4718793Sroot 		    uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio);
4724786Swnj 		s = splnet();
4734786Swnj 		if (len == m->m_len) {
4746091Sroot 			eor = (int)m->m_act;
4758319Sroot 			if (flags & SOF_PREVIEW)
4768319Sroot 				m = m->m_next;
4778319Sroot 			else {
4788319Sroot 				sbfree(&so->so_rcv, m);
4798319Sroot 				MFREE(m, n);
4808319Sroot 				m = n;
4818548Sroot 				so->so_rcv.sb_mb = m;
4828319Sroot 			}
4838319Sroot 			moff = 0;
4844786Swnj 		} else {
4858319Sroot 			if (flags & SOF_PREVIEW)
4868319Sroot 				moff += len;
4878319Sroot 			else {
4888319Sroot 				m->m_off += len;
4898319Sroot 				m->m_len -= len;
4908319Sroot 				so->so_rcv.sb_cc -= len;
4918319Sroot 			}
4924786Swnj 		}
4938319Sroot 		if ((flags & SOF_PREVIEW) == 0 && so->so_oobmark) {
4947747Sroot 			so->so_oobmark -= len;
4957747Sroot 			if (so->so_oobmark == 0) {
4967747Sroot 				so->so_state |= SS_RCVATMARK;
4977747Sroot 				break;
4987747Sroot 			}
4997747Sroot 		}
5008319Sroot 		if (tomark) {
5018319Sroot 			tomark -= len;
5028319Sroot 			if (tomark == 0)
5038319Sroot 				break;
5048319Sroot 		}
5058594Sroot 	} while (m && error == 0 && !eor);
5068319Sroot 	if (flags & SOF_PREVIEW)
5078319Sroot 		goto release;
5084786Swnj 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
5094786Swnj 		do {
5104786Swnj 			if (m == 0)
51110137Ssam 				panic("receive 4");
5124890Swnj 			sbfree(&so->so_rcv, m);
5134786Swnj 			eor = (int)m->m_act;
5144786Swnj 			so->so_rcv.sb_mb = m->m_next;
5154786Swnj 			MFREE(m, n);
5164890Swnj 			m = n;
5174786Swnj 		} while (eor == 0);
5184890Swnj 	if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
5198300Sroot 		(*so->so_proto->pr_usrreq)(so, PRU_RCVD,
52010267Ssam 		    (struct mbuf *)0, (struct mbuf *)0);
5214890Swnj release:
5224916Swnj 	sbunlock(&so->so_rcv);
5234890Swnj 	splx(s);
5244916Swnj 	return (error);
5254786Swnj }
5264786Swnj 
52710267Ssam soshutdown(so, how)
52810267Ssam 	struct socket *so;
52910267Ssam 	int how;
53010267Ssam {
53110267Ssam 
53210267Ssam 	how++;
53310267Ssam 	if (how & FREAD) {
53410267Ssam 		int s = splimp();
53510267Ssam 		socantrcvmore(so);
53610267Ssam 		sbflush(&so->so_rcv);
53710267Ssam 		splx(s);
53810267Ssam 	}
53910267Ssam 	if (how & FWRITE)
54010267Ssam 		return ((*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN,
54110267Ssam 		    (struct mbuf *)0, (struct mbuf *)0));
54210267Ssam 	return (0);
54310267Ssam }
54410267Ssam 
54510267Ssam sosetopt(so, level, optname, m)
54610267Ssam 	struct socket *so;
54710267Ssam 	int level, optname;
54810267Ssam 	struct mbuf *m;
54910267Ssam {
55010267Ssam 
55110267Ssam 	if (level != SOL_SOCKET)
55210267Ssam 		return (EINVAL);	/* XXX */
55310267Ssam 	switch (optname) {
55410267Ssam 
55510267Ssam 	case SO_DEBUG:
55610267Ssam 		so->so_options |= SO_DEBUG;
55710267Ssam 		break;
55810267Ssam 
559*10269Ssam 	case SO_KEEPALIVE:
560*10269Ssam 		so->so_options |= SO_KEEPALIVE;
561*10269Ssam 		break;
562*10269Ssam 
56310267Ssam 	case SO_LINGER:
564*10269Ssam 		if (m == NULL || m->m_len != sizeof (int))
565*10269Ssam 			return (EINVAL);
56610267Ssam 		so->so_options |= SO_LINGER;
567*10269Ssam 		so->so_linger = *mtod(m, int *);
56810267Ssam 		break;
56910267Ssam 
57010267Ssam 	case SO_DONTLINGER:
57110267Ssam 		so->so_options &= ~SO_LINGER;
57210267Ssam 		so->so_linger = 0;
57310267Ssam 		break;
57410267Ssam 
57510267Ssam 	case SO_DONTROUTE:
57610267Ssam 		so->so_options |= SO_DONTROUTE;
57710267Ssam 		break;
57810267Ssam 
57910267Ssam 	case SO_USELOOPBACK:
58010267Ssam 		so->so_options |= SO_USELOOPBACK;
58110267Ssam 		break;
58210267Ssam 
58310267Ssam 	default:
58410267Ssam 		return (EINVAL);
58510267Ssam 	}
58610267Ssam 	return (0);
58710267Ssam }
58810267Ssam 
58910267Ssam sogetopt(so, level, optname, m)
59010267Ssam 	struct socket *so;
59110267Ssam 	int level, optname;
59210267Ssam 	struct mbuf *m;
59310267Ssam {
59410267Ssam 
59510267Ssam 	if (level != SOL_SOCKET)
59610267Ssam 		return (EINVAL);	/* XXX */
59710267Ssam 	switch (optname) {
59810267Ssam 
59910267Ssam 	case SO_USELOOPBACK:
60010267Ssam 	case SO_DONTROUTE:
60110267Ssam 	case SO_DEBUG:
60210267Ssam 	case SO_KEEPALIVE:
60310267Ssam 	case SO_LINGER:
60410267Ssam 		if ((so->so_options & optname) == 0)
60510267Ssam 			return (ENOPROTOOPT);
606*10269Ssam 		if (optname == SO_LINGER && m != NULL) {
60710267Ssam 			*mtod(m, int *) = so->so_linger;
60810267Ssam 			m->m_len = sizeof (so->so_linger);
60910267Ssam 		}
61010267Ssam 		break;
61110267Ssam 
61210267Ssam 	default:
61310267Ssam 		return (EINVAL);
61410267Ssam 	}
61510267Ssam 	return (0);
61610267Ssam }
61710267Ssam 
6185423Swnj sohasoutofband(so)
6195423Swnj 	struct socket *so;
6205423Swnj {
6215423Swnj 
6225423Swnj 	if (so->so_pgrp == 0)
6235423Swnj 		return;
6245423Swnj 	if (so->so_pgrp > 0)
6255423Swnj 		gsignal(so->so_pgrp, SIGURG);
6265429Swnj 	else {
6275429Swnj 		struct proc *p = pfind(-so->so_pgrp);
6285429Swnj 
6295429Swnj 		if (p)
6305429Swnj 			psignal(p, SIGURG);
6315429Swnj 	}
6325423Swnj }
6335423Swnj 
6344916Swnj /*ARGSUSED*/
6357627Ssam soioctl(so, cmd, data)
6364829Swnj 	register struct socket *so;
6374829Swnj 	int cmd;
6387627Ssam 	register char *data;
6394786Swnj {
6404786Swnj 
6415358Sroot 	switch (cmd) {
6424829Swnj 
6437627Ssam 	case FIONBIO:
6447627Ssam 		if (*(int *)data)
6456214Swnj 			so->so_state |= SS_NBIO;
6465388Sroot 		else
6476214Swnj 			so->so_state &= ~SS_NBIO;
6488594Sroot 		break;
6495388Sroot 
6507627Ssam 	case FIOASYNC:
6517627Ssam 		if (*(int *)data)
6526214Swnj 			so->so_state |= SS_ASYNC;
6535388Sroot 		else
6546214Swnj 			so->so_state &= ~SS_ASYNC;
6558594Sroot 		break;
6565388Sroot 
6577627Ssam 	case SIOCSPGRP:
6587627Ssam 		so->so_pgrp = *(int *)data;
6598594Sroot 		break;
6605423Swnj 
6617627Ssam 	case SIOCGPGRP:
6627627Ssam 		*(int *)data = so->so_pgrp;
6638594Sroot 		break;
6647627Ssam 
6657627Ssam 	case SIOCATMARK:
6667627Ssam 		*(int *)data = (so->so_state&SS_RCVATMARK) != 0;
6678594Sroot 		break;
6686355Ssam 
6696355Ssam 	/* routing table update calls */
6706355Ssam 	case SIOCADDRT:
6716355Ssam 	case SIOCDELRT:
6726355Ssam 		if (!suser())
67310137Ssam 			return (u.u_error);
6748560Sroot 		return (rtrequest(cmd, (struct rtentry *)data));
6756355Ssam 
6765445Swnj 	/* type/protocol specific ioctls */
6778594Sroot 	default:
67810137Ssam 		return (ENOTTY);		/* XXX */
6795423Swnj 	}
6808594Sroot 	return (0);
6814786Swnj }
682