xref: /csrg-svn/sys/kern/uipc_socket.c (revision 8391)
1*8391Swnj /*	uipc_socket.c	4.52	82/10/09	*/
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"
17*8391Swnj #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 
288300Sroot socreate(dom, aso, type, proto, opt)
294786Swnj 	struct socket **aso;
308300Sroot 	int type, proto;
318300Sroot 	struct socketopt *opt;
324786Swnj {
334786Swnj 	register struct protosw *prp;
344786Swnj 	register struct socket *so;
354786Swnj 	struct mbuf *m;
368300Sroot 	int pf, error;
374786Swnj 
388300Sroot 	pf = dom ? PF_UNIX : PF_INET;		/* should be u.u_protof */
394890Swnj 	if (proto)
404890Swnj 		prp = pffindproto(pf, proto);
414890Swnj 	else
424890Swnj 		prp = pffindtype(pf, type);
434890Swnj 	if (prp == 0)
444890Swnj 		return (EPROTONOSUPPORT);
458300Sroot 	if (prp->pr_type != type)
468300Sroot 		return (EPROTOTYPE);
474890Swnj 	m = m_getclr(M_WAIT);
484786Swnj 	if (m == 0)
494786Swnj 		return (ENOBUFS);
504786Swnj 	so = mtod(m, struct socket *);
518300Sroot 	so->so_options = 0;
526214Swnj 	so->so_state = 0;
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,
578300Sroot 	    (struct mbuf *)0, (struct mbuf *)0, (struct socketopt *)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 
678300Sroot sobind(so, nam, opt)
688300Sroot 	struct socket *so;
698300Sroot 	struct mbuf *nam;
708300Sroot 	struct socketopt *opt;
718300Sroot {
728300Sroot 	int s = splnet();
738300Sroot 	int error;
748300Sroot 
758300Sroot 	error =
768300Sroot 	    (*so->so_proto->pr_usrreq)(so, PRU_BIND,
778300Sroot 		(struct mbuf *)0, nam, opt);
788300Sroot 	splx(s);
798300Sroot 	return (error);
808300Sroot }
818300Sroot 
828300Sroot solisten(so, backlog)
838300Sroot 	struct socket *so;
848300Sroot 	int backlog;
858300Sroot {
868300Sroot 	int s = splnet();
878300Sroot 	int error;
888300Sroot 
898300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_LISTEN,
908300Sroot 	    (struct mbuf *)0, (struct mbuf *)0, (struct socketopt *)0);
918300Sroot 	if (error) {
928300Sroot 		splx(s);
938300Sroot 		return (error);
948300Sroot 	}
958300Sroot 	if (so->so_q == 0) {
968300Sroot 		so->so_q = so;
978300Sroot 		so->so_q0 = so;
988300Sroot 		so->so_options |= SO_ACCEPTCONN;
998300Sroot 	}
1008300Sroot 	if (backlog < 0)
1018300Sroot 		backlog = 0;
1028300Sroot 	so->so_qlimit = backlog < 5 ? backlog : 5;
1038300Sroot 	so->so_options |= SO_NEWFDONCONN;
1048300Sroot 	return (0);
1058300Sroot }
1068300Sroot 
1074916Swnj sofree(so)
1084916Swnj 	struct socket *so;
1094916Swnj {
1104916Swnj 
1117507Sroot 	if (so->so_head) {
1127507Sroot 		if (!soqremque(so, 0) && !soqremque(so, 1))
1137507Sroot 			panic("sofree dq");
1147507Sroot 		so->so_head = 0;
1157507Sroot 	}
1167507Sroot 	if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
1174950Swnj 		return;
1184950Swnj 	sbrelease(&so->so_snd);
1194950Swnj 	sbrelease(&so->so_rcv);
1204971Swnj 	(void) m_free(dtom(so));
1214916Swnj }
1224916Swnj 
1234786Swnj /*
1244890Swnj  * Close a socket on last file table reference removal.
1254890Swnj  * Initiate disconnect if connected.
1264890Swnj  * Free socket when disconnect complete.
1274829Swnj  */
1285580Sroot soclose(so, exiting)
1294829Swnj 	register struct socket *so;
1305580Sroot 	int exiting;
1314829Swnj {
1324890Swnj 	int s = splnet();		/* conservative */
1334829Swnj 
1347507Sroot 	if (so->so_options & SO_ACCEPTCONN) {
1357507Sroot 		while (so->so_q0 != so)
1367507Sroot 			soclose(so->so_q0, 1);
1377507Sroot 		while (so->so_q != so)
1387507Sroot 			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) {
1464927Swnj 			u.u_error = sodisconnect(so, (struct sockaddr *)0);
1474890Swnj 			if (u.u_error) {
1485580Sroot 				if (exiting)
1495580Sroot 					goto drop;
1504890Swnj 				splx(s);
1514890Swnj 				return;
1524890Swnj 			}
1534890Swnj 		}
1545388Sroot 		if ((so->so_options & SO_DONTLINGER) == 0) {
1555281Sroot 			if ((so->so_state & SS_ISDISCONNECTING) &&
1566214Swnj 			    (so->so_state & SS_NBIO) &&
1575580Sroot 			    exiting == 0) {
1585281Sroot 				u.u_error = EINPROGRESS;
1595281Sroot 				splx(s);
1605281Sroot 				return;
1615281Sroot 			}
1625580Sroot 			/* should use tsleep here, for at most linger */
1635281Sroot 			while (so->so_state & SS_ISCONNECTED)
1645281Sroot 				sleep((caddr_t)&so->so_timeo, PZERO+1);
1654890Swnj 		}
1664890Swnj 	}
1675580Sroot drop:
1686880Ssam 	if (so->so_pcb) {
1698300Sroot 		u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH,
1708300Sroot 		    (struct mbuf *)0, (struct mbuf *)0, (struct socketopt *)0);
1716880Ssam 		if (exiting == 0 && u.u_error) {
1726880Ssam 			splx(s);
1736880Ssam 			return;
1746880Ssam 		}
1756880Ssam 	}
1764890Swnj discard:
1777507Sroot 	so->so_state |= SS_NOFDREF;
1784950Swnj 	sofree(so);
1794890Swnj 	splx(s);
1804829Swnj }
1814829Swnj 
1824916Swnj /*ARGSUSED*/
1834890Swnj sostat(so, sb)
1844829Swnj 	struct socket *so;
1854890Swnj 	struct stat *sb;
1864829Swnj {
1874829Swnj 
1885303Sroot 	bzero((caddr_t)sb, sizeof (*sb));		/* XXX */
1895303Sroot 	return (0);					/* XXX */
1904829Swnj }
1914829Swnj 
1928300Sroot soaccept(so, nam, opt)
1934927Swnj 	struct socket *so;
1948300Sroot 	struct mbuf *nam;
1958300Sroot 	struct socketopt *opt;
1964927Swnj {
1974927Swnj 	int s = splnet();
1984927Swnj 	int error;
1994927Swnj 
2008300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT,
2018300Sroot 	    (struct mbuf *)0, nam, opt);
2024927Swnj 	splx(s);
2034927Swnj 	return (error);
2044927Swnj }
2054927Swnj 
2068300Sroot soconnect(so, nam, opt)
2074786Swnj 	struct socket *so;
2088300Sroot 	struct mbuf *nam;
2098300Sroot 	struct socketopt *opt;
2104786Swnj {
2114890Swnj 	int s = splnet();
2124890Swnj 	int error;
2134786Swnj 
2144890Swnj 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
2154890Swnj 		error = EISCONN;
2164890Swnj 		goto bad;
2174890Swnj 	}
2188300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
2198300Sroot 	    (struct mbuf *)0, nam, opt);
2204890Swnj bad:
2214890Swnj 	splx(s);
2224890Swnj 	return (error);
2234786Swnj }
2244786Swnj 
2258300Sroot sodisconnect(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) == 0) {
2334890Swnj 		error = ENOTCONN;
2344890Swnj 		goto bad;
2354890Swnj 	}
2364890Swnj 	if (so->so_state & SS_ISDISCONNECTING) {
2374890Swnj 		error = EALREADY;
2384890Swnj 		goto bad;
2394890Swnj 	}
2408300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT,
2418300Sroot 	    (struct mbuf *)0, nam, (struct socketopt *)0);
2424890Swnj bad:
2434890Swnj 	splx(s);
2444890Swnj 	return (error);
2454786Swnj }
2464786Swnj 
2474786Swnj /*
2484890Swnj  * Send on a socket.
2494890Swnj  * If send must go all at once and message is larger than
2504890Swnj  * send buffering, then hard error.
2514890Swnj  * Lock against other senders.
2524890Swnj  * If must go all at once and not enough room now, then
2534890Swnj  * inform user that this would block and do nothing.
2544786Swnj  */
2558319Sroot sosend(so, nam, uio, flags)
2564786Swnj 	register struct socket *so;
2578300Sroot 	struct mbuf *nam;
2587827Sroot 	struct uio *uio;
2598319Sroot 	int flags;
2604786Swnj {
2614890Swnj 	struct mbuf *top = 0;
2624890Swnj 	register struct mbuf *m, **mp = &top;
2634916Swnj 	register u_int len;
2644916Swnj 	int error = 0, space, s;
2654786Swnj 
2667827Sroot 	if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat)
2674890Swnj 		return (EMSGSIZE);
2686419Sroot restart:
2694890Swnj 	sblock(&so->so_snd);
2704890Swnj #define	snderr(errno)	{ error = errno; splx(s); goto release; }
2714890Swnj 
2728041Sroot 	u.u_ru.ru_msgsnd++;
2736419Sroot again:
2744890Swnj 	s = splnet();
2756419Sroot 	if (so->so_state & SS_CANTSENDMORE) {
2766419Sroot 		psignal(u.u_procp, SIGPIPE);
2776419Sroot 		snderr(EPIPE);
2786419Sroot 	}
2795168Swnj 	if (so->so_error) {
2805168Swnj 		error = so->so_error;
2816419Sroot 		so->so_error = 0;				/* ??? */
2825168Swnj 		splx(s);
2835168Swnj 		goto release;
2845168Swnj 	}
2854890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2864890Swnj 		if (so->so_proto->pr_flags & PR_CONNREQUIRED)
2874890Swnj 			snderr(ENOTCONN);
2888300Sroot 		if (nam == 0)
2894890Swnj 			snderr(EDESTADDRREQ);
2904890Swnj 	}
2914890Swnj 	if (top) {
2928319Sroot 		error = (*so->so_proto->pr_usrreq)(so,
2938319Sroot 		    (flags & SOF_OOB) ? PRU_SENDOOB : PRU_SEND,
2948300Sroot 		    top, (caddr_t)nam, (struct socketopt *)0);
2956419Sroot 		top = 0;
2964890Swnj 		if (error) {
2974890Swnj 			splx(s);
2984786Swnj 			goto release;
2994786Swnj 		}
3004890Swnj 		mp = &top;
3014786Swnj 	}
3027827Sroot 	if (uio->uio_resid == 0) {
3034979Swnj 		splx(s);
3044979Swnj 		goto release;
3054979Swnj 	}
3068319Sroot 	if (flags & SOF_OOB)
3078319Sroot 		space = 1024;
3088319Sroot 	else {
3098319Sroot 		space = sbspace(&so->so_snd);
3108319Sroot 		if (space <= 0 ||
3118319Sroot 		    sosendallatonce(so) && space < uio->uio_resid) {
3128319Sroot 			if (so->so_state & SS_NBIO)
3138319Sroot 				snderr(EWOULDBLOCK);
3148319Sroot 			sbunlock(&so->so_snd);
3158319Sroot 			sbwait(&so->so_snd);
3168319Sroot 			splx(s);
3178319Sroot 			goto restart;
3188319Sroot 		}
3194786Swnj 	}
3204890Swnj 	splx(s);
3217827Sroot 	while (uio->uio_resid > 0 && space > 0) {
3227827Sroot 		register struct iovec *iov = uio->uio_iov;
3237827Sroot 
3247827Sroot 		if (iov->iov_len == 0) {
3257827Sroot 			uio->uio_iov++;
3267827Sroot 			uio->uio_iovcnt--;
3277827Sroot 			if (uio->uio_iovcnt < 0)
3287827Sroot 				panic("sosend");
3297827Sroot 			continue;
3307827Sroot 		}
3314890Swnj 		MGET(m, 1);
3324890Swnj 		if (m == NULL) {
3336419Sroot 			error = ENOBUFS;			/* SIGPIPE? */
3344890Swnj 			goto release;
3354786Swnj 		}
3367827Sroot 		if (iov->iov_len >= CLBYTES && space >= CLBYTES) {
3374890Swnj 			register struct mbuf *p;
3385095Swnj 			MCLGET(p, 1);
3394890Swnj 			if (p == 0)
3404890Swnj 				goto nopages;
3414890Swnj 			m->m_off = (int)p - (int)m;
3425095Swnj 			len = CLBYTES;
3434890Swnj 		} else {
3444786Swnj nopages:
3457827Sroot 			len = MIN(MLEN, iov->iov_len);
3464786Swnj 		}
3477827Sroot 		uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio);
3484890Swnj 		m->m_len = len;
3494890Swnj 		*mp = m;
3504890Swnj 		mp = &m->m_next;
3518319Sroot 		if (flags & SOF_OOB)
3528319Sroot 			space -= len;
3538319Sroot 		else
3548319Sroot 			space = sbspace(&so->so_snd);
3554786Swnj 	}
3564890Swnj 	goto again;
3574890Swnj 
3584786Swnj release:
3594890Swnj 	sbunlock(&so->so_snd);
3606419Sroot 	if (top)
3616419Sroot 		m_freem(top);
3624786Swnj 	return (error);
3634786Swnj }
3644786Swnj 
3658319Sroot soreceive(so, aname, uio, flags)
3664786Swnj 	register struct socket *so;
3678300Sroot 	struct mbuf **aname;
3687747Sroot 	struct uio *uio;
3698319Sroot 	int flags;
3704786Swnj {
3717747Sroot 	register struct iovec *iov;
3724786Swnj 	register struct mbuf *m, *n;
3734916Swnj 	u_int len;
3748319Sroot 	int eor, s, error = 0, moff, tomark;
3754786Swnj 
3768319Sroot 	if (flags & SOF_OOB) {
3778319Sroot 		struct mbuf *m = m_get(M_WAIT);
3788319Sroot 
3798319Sroot 		(*so->so_proto->pr_usrreq)(so, PRU_RCVOOB,
3808319Sroot 		    m, (struct mbuf *)0, (struct socketopt *)0);
3818319Sroot 		len = uio->uio_resid;
3828319Sroot 		do {
3838319Sroot 			if (len > m->m_len)
3848319Sroot 				len = m->m_len;
3858319Sroot 			uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio);
3868319Sroot 			m = m_free(m);
3878319Sroot 		} while (uio->uio_resid && u.u_error == 0 && m);
3888319Sroot 		if (m)
3898319Sroot 			(void) m_freem(m);
3908319Sroot 		return;
3918319Sroot 	}
3928319Sroot 
3934890Swnj restart:
3944890Swnj 	sblock(&so->so_rcv);
3954890Swnj 	s = splnet();
3964890Swnj 
3974890Swnj #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
3984786Swnj 	if (so->so_rcv.sb_cc == 0) {
3995168Swnj 		if (so->so_error) {
4005168Swnj 			error = so->so_error;
4015168Swnj 			so->so_error = 0;
4025168Swnj 			splx(s);
4035168Swnj 			goto release;
4045168Swnj 		}
4054890Swnj 		if (so->so_state & SS_CANTRCVMORE) {
4064890Swnj 			splx(s);
4074890Swnj 			goto release;
4084890Swnj 		}
4095015Sroot 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
4105015Sroot 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
4115015Sroot 			rcverr(ENOTCONN);
4126214Swnj 		if (so->so_state & SS_NBIO)
4135168Swnj 			rcverr(EWOULDBLOCK);
4144890Swnj 		sbunlock(&so->so_rcv);
4154971Swnj 		sbwait(&so->so_rcv);
4165012Swnj 		splx(s);
4174890Swnj 		goto restart;
4184786Swnj 	}
4198041Sroot 	u.u_ru.ru_msgrcv++;
4204829Swnj 	m = so->so_rcv.sb_mb;
4214786Swnj 	if (m == 0)
4224786Swnj 		panic("receive");
4235039Swnj 	if (so->so_proto->pr_flags & PR_ADDR) {
4248319Sroot 		if ((flags & SOF_PREVIEW) == 0) {
4258319Sroot 			so->so_rcv.sb_cc -= m->m_len;
4268319Sroot 			so->so_rcv.sb_mbcnt -= MSIZE;
4278319Sroot 		}
4288300Sroot 		if (aname) {
4298319Sroot 			if (flags & SOF_PREVIEW)
4308319Sroot 				*aname = m_copy(m, 0, m->m_len);
4318319Sroot 			else
4328319Sroot 				*aname = m;
4338300Sroot 			m = m->m_next;
4348300Sroot 			(*aname)->m_next = 0;
4358300Sroot 		} else
4368319Sroot 			if (flags & SOF_PREVIEW)
4378319Sroot 				m = m->m_next;
4388319Sroot 			else
4398319Sroot 				m = m_free(m);
4404890Swnj 		if (m == 0)
4414890Swnj 			panic("receive 2");
4424890Swnj 	}
4434786Swnj 	eor = 0;
4448319Sroot 	moff = 0;
4458319Sroot 	tomark = so->so_oobmark;
4464786Swnj 	do {
4477827Sroot 		if (uio->uio_resid <= 0)
4487747Sroot 			break;
4497827Sroot 		len = uio->uio_resid;
4507747Sroot 		so->so_state &= ~SS_RCVATMARK;
4518319Sroot 		if (tomark && len > tomark)
4528319Sroot 			len = tomark;
4538319Sroot 		if (len > m->m_len - moff)
4548319Sroot 			len = m->m_len - moff;
4554786Swnj 		splx(s);
4568319Sroot 		uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio);
4574786Swnj 		s = splnet();
4584786Swnj 		if (len == m->m_len) {
4596091Sroot 			eor = (int)m->m_act;
4608319Sroot 			if (flags & SOF_PREVIEW)
4618319Sroot 				m = m->m_next;
4628319Sroot 			else {
4638319Sroot 				sbfree(&so->so_rcv, m);
4648319Sroot 				MFREE(m, n);
4658319Sroot 				m = n;
4668319Sroot 			}
4678319Sroot 			moff = 0;
4684786Swnj 		} else {
4698319Sroot 			if (flags & SOF_PREVIEW)
4708319Sroot 				moff += len;
4718319Sroot 			else {
4728319Sroot 				m->m_off += len;
4738319Sroot 				m->m_len -= len;
4748319Sroot 				so->so_rcv.sb_cc -= len;
4758319Sroot 			}
4764786Swnj 		}
4778319Sroot 		if ((flags & SOF_PREVIEW) == 0 && so->so_oobmark) {
4787747Sroot 			so->so_oobmark -= len;
4797747Sroot 			if (so->so_oobmark == 0) {
4807747Sroot 				so->so_state |= SS_RCVATMARK;
4817747Sroot 				break;
4827747Sroot 			}
4837747Sroot 		}
4848319Sroot 		if (tomark) {
4858319Sroot 			tomark -= len;
4868319Sroot 			if (tomark == 0)
4878319Sroot 				break;
4888319Sroot 		}
4898319Sroot 	} while (m && !eor);
4908319Sroot 	if (flags & SOF_PREVIEW)
4918319Sroot 		goto release;
4928319Sroot 	so->so_rcv.sb_mb = m;
4934786Swnj 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
4944786Swnj 		do {
4954786Swnj 			if (m == 0)
4964890Swnj 				panic("receive 3");
4974890Swnj 			sbfree(&so->so_rcv, m);
4984786Swnj 			eor = (int)m->m_act;
4994786Swnj 			so->so_rcv.sb_mb = m->m_next;
5004786Swnj 			MFREE(m, n);
5014890Swnj 			m = n;
5024786Swnj 		} while (eor == 0);
5034890Swnj 	if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
5048300Sroot 		(*so->so_proto->pr_usrreq)(so, PRU_RCVD,
5058300Sroot 		    (struct mbuf *)0, (struct mbuf *)0, (struct socketopt *)0);
5064890Swnj release:
5074916Swnj 	sbunlock(&so->so_rcv);
5084890Swnj 	splx(s);
5094916Swnj 	return (error);
5104786Swnj }
5114786Swnj 
5125423Swnj sohasoutofband(so)
5135423Swnj 	struct socket *so;
5145423Swnj {
5155423Swnj 
5165423Swnj 	if (so->so_pgrp == 0)
5175423Swnj 		return;
5185423Swnj 	if (so->so_pgrp > 0)
5195423Swnj 		gsignal(so->so_pgrp, SIGURG);
5205429Swnj 	else {
5215429Swnj 		struct proc *p = pfind(-so->so_pgrp);
5225429Swnj 
5235429Swnj 		if (p)
5245429Swnj 			psignal(p, SIGURG);
5255429Swnj 	}
5265423Swnj }
5275423Swnj 
5284916Swnj /*ARGSUSED*/
5297627Ssam soioctl(so, cmd, data)
5304829Swnj 	register struct socket *so;
5314829Swnj 	int cmd;
5327627Ssam 	register char *data;
5334786Swnj {
5344786Swnj 
5355358Sroot 	switch (cmd) {
5364829Swnj 
5377627Ssam 	case FIONBIO:
5387627Ssam 		if (*(int *)data)
5396214Swnj 			so->so_state |= SS_NBIO;
5405388Sroot 		else
5416214Swnj 			so->so_state &= ~SS_NBIO;
5425388Sroot 		return;
5435388Sroot 
5447627Ssam 	case FIOASYNC:
5457627Ssam 		if (*(int *)data)
5466214Swnj 			so->so_state |= SS_ASYNC;
5475388Sroot 		else
5486214Swnj 			so->so_state &= ~SS_ASYNC;
5495388Sroot 		return;
5505388Sroot 
5517627Ssam 	case SIOCSKEEP:
5527627Ssam 		if (*(int *)data)
5537507Sroot 			so->so_options &= ~SO_KEEPALIVE;
5547507Sroot 		else
5557491Ssam 			so->so_options |= SO_KEEPALIVE;
5565388Sroot 		return;
5575388Sroot 
5587627Ssam 	case SIOCGKEEP:
5597627Ssam 		*(int *)data = (so->so_options & SO_KEEPALIVE) != 0;
5605388Sroot 		return;
5615388Sroot 
5627627Ssam 	case SIOCSLINGER:
5637627Ssam 		so->so_linger = *(int *)data;
5645388Sroot 		if (so->so_linger)
5655388Sroot 			so->so_options &= ~SO_DONTLINGER;
5665388Sroot 		else
5675388Sroot 			so->so_options |= SO_DONTLINGER;
5685388Sroot 		return;
5695388Sroot 
5707627Ssam 	case SIOCGLINGER:
5717627Ssam 		*(int *)data = so->so_linger;
5725423Swnj 		return;
5735388Sroot 
5747627Ssam 	case SIOCSPGRP:
5757627Ssam 		so->so_pgrp = *(int *)data;
5767627Ssam 		return;
5775423Swnj 
5787627Ssam 	case SIOCGPGRP:
5797627Ssam 		*(int *)data = so->so_pgrp;
5807627Ssam 		return;
5817627Ssam 
5825281Sroot 	case SIOCDONE: {
5837627Ssam 		int flags = *(int *)data;
5847627Ssam 
5855388Sroot 		flags++;
5865281Sroot 		if (flags & FREAD) {
5875281Sroot 			int s = splimp();
5885281Sroot 			socantrcvmore(so);
5895281Sroot 			sbflush(&so->so_rcv);
5906140Ssam 			splx(s);
5915281Sroot 		}
5925281Sroot 		if (flags & FWRITE)
5938300Sroot 			u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN,
5948300Sroot 			    (struct mbuf *)0, (struct mbuf *)0,
5958300Sroot 			    (struct socketopt *)0);
5965281Sroot 		return;
5974829Swnj 	}
5985281Sroot 
5995423Swnj 	case SIOCSENDOOB: {
6007627Ssam 		char oob = *(char *)data;
6018319Sroot 		struct mbuf *m = m_get(M_DONTWAIT);
6027627Ssam 
6035423Swnj 		if (m == 0) {
6045423Swnj 			u.u_error = ENOBUFS;
6055423Swnj 			return;
6065423Swnj 		}
6078319Sroot 		m->m_len = 1;
6087627Ssam 		*mtod(m, char *) = oob;
6098300Sroot 		(*so->so_proto->pr_usrreq)(so, PRU_SENDOOB,
6108300Sroot 		    m, (struct mbuf *)0, (struct socketopt *)0);
6115423Swnj 		return;
6125281Sroot 	}
6135423Swnj 
6145423Swnj 	case SIOCRCVOOB: {
6158319Sroot 		struct mbuf *m = m_get(M_WAIT);
6167627Ssam 
6175423Swnj 		if (m == 0) {
6185423Swnj 			u.u_error = ENOBUFS;
6195423Swnj 			return;
6205423Swnj 		}
6218319Sroot 		*mtod(m, caddr_t) = 0;
6228300Sroot 		(*so->so_proto->pr_usrreq)(so, PRU_RCVOOB,
6238300Sroot 		    m, (struct mbuf *)0, (struct socketopt *)0);
6247627Ssam 		*(char *)data = *mtod(m, char *);
6257627Ssam 		(void) m_free(m);
6265423Swnj 		return;
6275423Swnj 	}
6285423Swnj 
6297627Ssam 	case SIOCATMARK:
6307627Ssam 		*(int *)data = (so->so_state&SS_RCVATMARK) != 0;
6315423Swnj 		return;
6326355Ssam 
6336355Ssam 	/* routing table update calls */
6346355Ssam 	case SIOCADDRT:
6356355Ssam 	case SIOCDELRT:
6366355Ssam 		if (!suser())
6376355Ssam 			return;
6387627Ssam 		u.u_error = rtrequest(cmd, (struct rtentry *)data);
6396355Ssam 		return;
6406355Ssam 
6415445Swnj 	/* type/protocol specific ioctls */
6425423Swnj 	}
6435445Swnj 	u.u_error = EOPNOTSUPP;
6444786Swnj }
645