xref: /csrg-svn/sys/kern/uipc_socket.c (revision 7627)
17507Sroot /*	socket.c	4.43	82/07/21	*/
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"
175095Swnj #include "../net/in.h"
185095Swnj #include "../net/in_systm.h"
196355Ssam #include "../net/route.h"
204786Swnj 
214786Swnj /*
224890Swnj  * Socket support routines.
234890Swnj  *
244890Swnj  * DEAL WITH INTERRUPT NOTIFICATION.
254786Swnj  */
264786Swnj 
274786Swnj /*
284786Swnj  * Create a socket.
294786Swnj  */
304927Swnj socreate(aso, type, asp, asa, options)
314786Swnj 	struct socket **aso;
324786Swnj 	int type;
334927Swnj 	struct sockproto *asp;
344927Swnj 	struct sockaddr *asa;
354829Swnj 	int options;
364786Swnj {
374786Swnj 	register struct protosw *prp;
384786Swnj 	register struct socket *so;
394786Swnj 	struct mbuf *m;
404890Swnj 	int pf, proto, error;
414786Swnj 
424786Swnj 	/*
434890Swnj 	 * Use process standard protocol/protocol family if none
444890Swnj 	 * specified by address argument.
454786Swnj 	 */
464927Swnj 	if (asp == 0) {
474890Swnj 		pf = PF_INET;		/* should be u.u_protof */
484786Swnj 		proto = 0;
494786Swnj 	} else {
504927Swnj 		pf = asp->sp_family;
514927Swnj 		proto = asp->sp_protocol;
524786Swnj 	}
534786Swnj 
544786Swnj 	/*
554890Swnj 	 * If protocol specified, look for it, otherwise
564890Swnj 	 * for a protocol of the correct type in the right family.
574890Swnj 	 */
584890Swnj 	if (proto)
594890Swnj 		prp = pffindproto(pf, proto);
604890Swnj 	else
614890Swnj 		prp = pffindtype(pf, type);
624890Swnj 	if (prp == 0)
634890Swnj 		return (EPROTONOSUPPORT);
644890Swnj 
654890Swnj 	/*
664786Swnj 	 * Get a socket structure.
674786Swnj 	 */
684890Swnj 	m = m_getclr(M_WAIT);
694786Swnj 	if (m == 0)
704786Swnj 		return (ENOBUFS);
714786Swnj 	so = mtod(m, struct socket *);
724829Swnj 	so->so_options = options;
737507Sroot 	if (options & SO_ACCEPTCONN) {
747507Sroot 		so->so_q = so;
757507Sroot 		so->so_q0 = so;
767507Sroot 		so->so_qlimit = (so->so_options & SO_NEWFDONCONN) ? 5 : 1;
777507Sroot 	}
786214Swnj 	so->so_state = 0;
796214Swnj 	if (u.u_uid == 0)
806214Swnj 		so->so_state = SS_PRIV;
814786Swnj 
824786Swnj 	/*
834890Swnj 	 * Attach protocol to socket, initializing
844890Swnj 	 * and reserving resources.
854786Swnj 	 */
864786Swnj 	so->so_proto = prp;
874979Swnj 	error = (*prp->pr_usrreq)(so, PRU_ATTACH, 0, asa);
884979Swnj 	if (error) {
897507Sroot 		so->so_state |= SS_NOFDREF;
907180Swnj 		sofree(so);
914890Swnj 		return (error);
924786Swnj 	}
934786Swnj 	*aso = so;
944786Swnj 	return (0);
954786Swnj }
964786Swnj 
974916Swnj sofree(so)
984916Swnj 	struct socket *so;
994916Swnj {
1004916Swnj 
1017507Sroot 	if (so->so_head) {
1027507Sroot 		if (!soqremque(so, 0) && !soqremque(so, 1))
1037507Sroot 			panic("sofree dq");
1047507Sroot 		so->so_head = 0;
1057507Sroot 	}
1067507Sroot 	if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
1074950Swnj 		return;
1084950Swnj 	sbrelease(&so->so_snd);
1094950Swnj 	sbrelease(&so->so_rcv);
1104971Swnj 	(void) m_free(dtom(so));
1114916Swnj }
1124916Swnj 
1134786Swnj /*
1144890Swnj  * Close a socket on last file table reference removal.
1154890Swnj  * Initiate disconnect if connected.
1164890Swnj  * Free socket when disconnect complete.
1174829Swnj  */
1185580Sroot soclose(so, exiting)
1194829Swnj 	register struct socket *so;
1205580Sroot 	int exiting;
1214829Swnj {
1224890Swnj 	int s = splnet();		/* conservative */
1237507Sroot 	register struct socket *so2;
1244829Swnj 
1257507Sroot 	if (so->so_options & SO_ACCEPTCONN) {
1267507Sroot 		while (so->so_q0 != so)
1277507Sroot 			soclose(so->so_q0, 1);
1287507Sroot 		while (so->so_q != so)
1297507Sroot 			soclose(so->so_q, 1);
1307507Sroot 	}
1314890Swnj 	if (so->so_pcb == 0)
1324890Swnj 		goto discard;
1336259Sroot 	if (exiting)
1346259Sroot 		so->so_options |= SO_KEEPALIVE;
1354890Swnj 	if (so->so_state & SS_ISCONNECTED) {
1364890Swnj 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
1374927Swnj 			u.u_error = sodisconnect(so, (struct sockaddr *)0);
1384890Swnj 			if (u.u_error) {
1395580Sroot 				if (exiting)
1405580Sroot 					goto drop;
1414890Swnj 				splx(s);
1424890Swnj 				return;
1434890Swnj 			}
1444890Swnj 		}
1455388Sroot 		if ((so->so_options & SO_DONTLINGER) == 0) {
1465281Sroot 			if ((so->so_state & SS_ISDISCONNECTING) &&
1476214Swnj 			    (so->so_state & SS_NBIO) &&
1485580Sroot 			    exiting == 0) {
1495281Sroot 				u.u_error = EINPROGRESS;
1505281Sroot 				splx(s);
1515281Sroot 				return;
1525281Sroot 			}
1535580Sroot 			/* should use tsleep here, for at most linger */
1545281Sroot 			while (so->so_state & SS_ISCONNECTED)
1555281Sroot 				sleep((caddr_t)&so->so_timeo, PZERO+1);
1564890Swnj 		}
1574890Swnj 	}
1585580Sroot drop:
1596880Ssam 	if (so->so_pcb) {
1606880Ssam 		u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0);
1616880Ssam 		if (exiting == 0 && u.u_error) {
1626880Ssam 			splx(s);
1636880Ssam 			return;
1646880Ssam 		}
1656880Ssam 	}
1664890Swnj discard:
1677507Sroot 	so->so_state |= SS_NOFDREF;
1684950Swnj 	sofree(so);
1694890Swnj 	splx(s);
1704829Swnj }
1714829Swnj 
1724916Swnj /*ARGSUSED*/
1734890Swnj sostat(so, sb)
1744829Swnj 	struct socket *so;
1754890Swnj 	struct stat *sb;
1764829Swnj {
1774829Swnj 
1785303Sroot 	bzero((caddr_t)sb, sizeof (*sb));		/* XXX */
1795303Sroot 	return (0);					/* XXX */
1804829Swnj }
1814829Swnj 
1824829Swnj /*
1834927Swnj  * Accept connection on a socket.
1844927Swnj  */
1854927Swnj soaccept(so, asa)
1864927Swnj 	struct socket *so;
1874927Swnj 	struct sockaddr *asa;
1884927Swnj {
1894927Swnj 	int s = splnet();
1904927Swnj 	int error;
1914927Swnj 
1924927Swnj 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa);
1934927Swnj 	splx(s);
1944927Swnj 	return (error);
1954927Swnj }
1964927Swnj 
1974927Swnj /*
1984890Swnj  * Connect socket to a specified address.
1994890Swnj  * If already connected or connecting, then avoid
2004890Swnj  * the protocol entry, to keep its job simpler.
2014786Swnj  */
2024927Swnj soconnect(so, asa)
2034786Swnj 	struct socket *so;
2044927Swnj 	struct sockaddr *asa;
2054786Swnj {
2064890Swnj 	int s = splnet();
2074890Swnj 	int error;
2084786Swnj 
2094890Swnj 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
2104890Swnj 		error = EISCONN;
2114890Swnj 		goto bad;
2124890Swnj 	}
2134927Swnj 	error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa);
2144890Swnj bad:
2154890Swnj 	splx(s);
2164890Swnj 	return (error);
2174786Swnj }
2184786Swnj 
2194786Swnj /*
2204890Swnj  * Disconnect from a socket.
2214890Swnj  * Address parameter is from system call for later multicast
2224890Swnj  * protocols.  Check to make sure that connected and no disconnect
2234890Swnj  * in progress (for protocol's sake), and then invoke protocol.
2244786Swnj  */
2254927Swnj sodisconnect(so, asa)
2264786Swnj 	struct socket *so;
2274927Swnj 	struct sockaddr *asa;
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 	}
2404927Swnj 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa);
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  */
2544927Swnj sosend(so, asa)
2554786Swnj 	register struct socket *so;
2564927Swnj 	struct sockaddr *asa;
2574786Swnj {
2584890Swnj 	struct mbuf *top = 0;
2594890Swnj 	register struct mbuf *m, **mp = ⊤
2604916Swnj 	register u_int len;
2614916Swnj 	int error = 0, space, s;
2624786Swnj 
2634890Swnj 	if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat)
2644890Swnj 		return (EMSGSIZE);
2656419Sroot #ifdef notdef
2666419Sroot 	/* NEED TO PREVENT BUSY WAITING IN SELECT FOR WRITING */
2676214Swnj 	if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_state & SS_NBIO))
2684890Swnj 		return (EWOULDBLOCK);
2696419Sroot #endif
2706419Sroot restart:
2714890Swnj 	sblock(&so->so_snd);
2724890Swnj #define	snderr(errno)	{ error = errno; splx(s); goto release; }
2734890Swnj 
2746419Sroot again:
2754890Swnj 	s = splnet();
2766419Sroot 	if (so->so_state & SS_CANTSENDMORE) {
2776419Sroot 		psignal(u.u_procp, SIGPIPE);
2786419Sroot 		snderr(EPIPE);
2796419Sroot 	}
2805168Swnj 	if (so->so_error) {
2815168Swnj 		error = so->so_error;
2826419Sroot 		so->so_error = 0;				/* ??? */
2835168Swnj 		splx(s);
2845168Swnj 		goto release;
2855168Swnj 	}
2864890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2874890Swnj 		if (so->so_proto->pr_flags & PR_CONNREQUIRED)
2884890Swnj 			snderr(ENOTCONN);
2894927Swnj 		if (asa == 0)
2904890Swnj 			snderr(EDESTADDRREQ);
2914890Swnj 	}
2924890Swnj 	if (top) {
2934927Swnj 		error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa);
2946419Sroot 		top = 0;
2954890Swnj 		if (error) {
2964890Swnj 			splx(s);
2974786Swnj 			goto release;
2984786Swnj 		}
2994890Swnj 		mp = ⊤
3004786Swnj 	}
3014979Swnj 	if (u.u_count == 0) {
3024979Swnj 		splx(s);
3034979Swnj 		goto release;
3044979Swnj 	}
3055018Swnj 	space = sbspace(&so->so_snd);
3065610Swnj 	if (space <= 0 || sosendallatonce(so) && space < u.u_count) {
3076214Swnj 		if (so->so_state & SS_NBIO)
3084890Swnj 			snderr(EWOULDBLOCK);
3094890Swnj 		sbunlock(&so->so_snd);
3104890Swnj 		sbwait(&so->so_snd);
3114890Swnj 		splx(s);
3126419Sroot 		goto restart;
3134786Swnj 	}
3144890Swnj 	splx(s);
3155018Swnj 	while (u.u_count && space > 0) {
3164890Swnj 		MGET(m, 1);
3174890Swnj 		if (m == NULL) {
3186419Sroot 			error = ENOBUFS;			/* SIGPIPE? */
3194890Swnj 			goto release;
3204786Swnj 		}
3215095Swnj 		if (u.u_count >= CLBYTES && space >= CLBYTES) {
3224890Swnj 			register struct mbuf *p;
3235095Swnj 			MCLGET(p, 1);
3244890Swnj 			if (p == 0)
3254890Swnj 				goto nopages;
3264890Swnj 			m->m_off = (int)p - (int)m;
3275095Swnj 			len = CLBYTES;
3284890Swnj 		} else {
3294786Swnj nopages:
3304890Swnj 			m->m_off = MMINOFF;
3314890Swnj 			len = MIN(MLEN, u.u_count);
3324786Swnj 		}
3334890Swnj 		iomove(mtod(m, caddr_t), len, B_WRITE);
3344890Swnj 		m->m_len = len;
3354890Swnj 		*mp = m;
3364890Swnj 		mp = &m->m_next;
3375018Swnj 		space = sbspace(&so->so_snd);
3384786Swnj 	}
3394890Swnj 	goto again;
3404890Swnj 
3414786Swnj release:
3424890Swnj 	sbunlock(&so->so_snd);
3436419Sroot 	if (top)
3446419Sroot 		m_freem(top);
3454786Swnj 	return (error);
3464786Swnj }
3474786Swnj 
3484927Swnj soreceive(so, asa)
3494786Swnj 	register struct socket *so;
3504927Swnj 	struct sockaddr *asa;
3514786Swnj {
3524786Swnj 	register struct mbuf *m, *n;
3534916Swnj 	u_int len;
3545423Swnj 	int eor, s, error = 0, cnt = u.u_count;
3555423Swnj 	caddr_t base = u.u_base;
3564786Swnj 
3574890Swnj restart:
3584890Swnj 	sblock(&so->so_rcv);
3594890Swnj 	s = splnet();
3604890Swnj 
3614890Swnj #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
3624786Swnj 	if (so->so_rcv.sb_cc == 0) {
3635168Swnj 		if (so->so_error) {
3645168Swnj 			error = so->so_error;
3655168Swnj 			so->so_error = 0;
3665168Swnj 			splx(s);
3675168Swnj 			goto release;
3685168Swnj 		}
3694890Swnj 		if (so->so_state & SS_CANTRCVMORE) {
3704890Swnj 			splx(s);
3714890Swnj 			goto release;
3724890Swnj 		}
3735015Sroot 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
3745015Sroot 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
3755015Sroot 			rcverr(ENOTCONN);
3766214Swnj 		if (so->so_state & SS_NBIO)
3775168Swnj 			rcverr(EWOULDBLOCK);
3784890Swnj 		sbunlock(&so->so_rcv);
3794971Swnj 		sbwait(&so->so_rcv);
3805012Swnj 		splx(s);
3814890Swnj 		goto restart;
3824786Swnj 	}
3834829Swnj 	m = so->so_rcv.sb_mb;
3844786Swnj 	if (m == 0)
3854786Swnj 		panic("receive");
3865039Swnj 	if (so->so_proto->pr_flags & PR_ADDR) {
3875039Swnj 		if (m->m_len != sizeof (struct sockaddr))
3885039Swnj 			panic("soreceive addr");
3895039Swnj 		if (asa)
3905039Swnj 			bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa));
3915039Swnj 		so->so_rcv.sb_cc -= m->m_len;
3925039Swnj 		so->so_rcv.sb_mbcnt -= MSIZE;
3935018Swnj 		m = m_free(m);
3944890Swnj 		if (m == 0)
3954890Swnj 			panic("receive 2");
3965018Swnj 		so->so_rcv.sb_mb = m;
3974890Swnj 	}
3985423Swnj 	so->so_state &= ~SS_RCVATMARK;
3995423Swnj 	if (so->so_oobmark && cnt > so->so_oobmark)
4005423Swnj 		cnt = so->so_oobmark;
4014786Swnj 	eor = 0;
4024786Swnj 	do {
4035423Swnj 		len = MIN(m->m_len, cnt);
4044786Swnj 		splx(s);
4054786Swnj 		iomove(mtod(m, caddr_t), len, B_READ);
4065423Swnj 		cnt -= len;
4074786Swnj 		s = splnet();
4084786Swnj 		if (len == m->m_len) {
4096091Sroot 			eor = (int)m->m_act;
4106091Sroot 			sbfree(&so->so_rcv, m);
4116091Sroot 			so->so_rcv.sb_mb = m->m_next;
4124786Swnj 			MFREE(m, n);
4134786Swnj 		} else {
4144786Swnj 			m->m_off += len;
4154786Swnj 			m->m_len -= len;
4164829Swnj 			so->so_rcv.sb_cc -= len;
4174786Swnj 		}
4185423Swnj 	} while ((m = so->so_rcv.sb_mb) && cnt && !eor);
4194786Swnj 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
4204786Swnj 		do {
4214786Swnj 			if (m == 0)
4224890Swnj 				panic("receive 3");
4234890Swnj 			sbfree(&so->so_rcv, m);
4244786Swnj 			eor = (int)m->m_act;
4254786Swnj 			so->so_rcv.sb_mb = m->m_next;
4264786Swnj 			MFREE(m, n);
4274890Swnj 			m = n;
4284786Swnj 		} while (eor == 0);
4294890Swnj 	if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
4304890Swnj 		(*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0);
4315423Swnj 	if (so->so_oobmark) {
4325423Swnj 		so->so_oobmark -= u.u_base - base;
4335423Swnj 		if (so->so_oobmark == 0)
4345423Swnj 			so->so_state |= SS_RCVATMARK;
4355423Swnj 	}
4364890Swnj release:
4374916Swnj 	sbunlock(&so->so_rcv);
4384890Swnj 	splx(s);
4394916Swnj 	return (error);
4404786Swnj }
4414786Swnj 
4425423Swnj sohasoutofband(so)
4435423Swnj 	struct socket *so;
4445423Swnj {
4455423Swnj 
4465423Swnj 	if (so->so_pgrp == 0)
4475423Swnj 		return;
4485423Swnj 	if (so->so_pgrp > 0)
4495423Swnj 		gsignal(so->so_pgrp, SIGURG);
4505429Swnj 	else {
4515429Swnj 		struct proc *p = pfind(-so->so_pgrp);
4525429Swnj 
4535429Swnj 		if (p)
4545429Swnj 			psignal(p, SIGURG);
4555429Swnj 	}
4565423Swnj }
4575423Swnj 
4584916Swnj /*ARGSUSED*/
459*7627Ssam soioctl(so, cmd, data)
4604829Swnj 	register struct socket *so;
4614829Swnj 	int cmd;
462*7627Ssam 	register char *data;
4634786Swnj {
4644786Swnj 
4655358Sroot 	switch (cmd) {
4664829Swnj 
467*7627Ssam 	case FIONBIO:
468*7627Ssam 		if (*(int *)data)
4696214Swnj 			so->so_state |= SS_NBIO;
4705388Sroot 		else
4716214Swnj 			so->so_state &= ~SS_NBIO;
4725388Sroot 		return;
4735388Sroot 
474*7627Ssam 	case FIOASYNC:
475*7627Ssam 		if (*(int *)data)
4766214Swnj 			so->so_state |= SS_ASYNC;
4775388Sroot 		else
4786214Swnj 			so->so_state &= ~SS_ASYNC;
4795388Sroot 		return;
4805388Sroot 
481*7627Ssam 	case SIOCSKEEP:
482*7627Ssam 		if (*(int *)data)
4837507Sroot 			so->so_options &= ~SO_KEEPALIVE;
4847507Sroot 		else
4857491Ssam 			so->so_options |= SO_KEEPALIVE;
4865388Sroot 		return;
4875388Sroot 
488*7627Ssam 	case SIOCGKEEP:
489*7627Ssam 		*(int *)data = (so->so_options & SO_KEEPALIVE) != 0;
4905388Sroot 		return;
4915388Sroot 
492*7627Ssam 	case SIOCSLINGER:
493*7627Ssam 		so->so_linger = *(int *)data;
4945388Sroot 		if (so->so_linger)
4955388Sroot 			so->so_options &= ~SO_DONTLINGER;
4965388Sroot 		else
4975388Sroot 			so->so_options |= SO_DONTLINGER;
4985388Sroot 		return;
4995388Sroot 
500*7627Ssam 	case SIOCGLINGER:
501*7627Ssam 		*(int *)data = so->so_linger;
5025423Swnj 		return;
5035388Sroot 
504*7627Ssam 	case SIOCSPGRP:
505*7627Ssam 		so->so_pgrp = *(int *)data;
506*7627Ssam 		return;
5075423Swnj 
508*7627Ssam 	case SIOCGPGRP:
509*7627Ssam 		*(int *)data = so->so_pgrp;
510*7627Ssam 		return;
511*7627Ssam 
5125281Sroot 	case SIOCDONE: {
513*7627Ssam 		int flags = *(int *)data;
514*7627Ssam 
5155388Sroot 		flags++;
5165281Sroot 		if (flags & FREAD) {
5175281Sroot 			int s = splimp();
5185281Sroot 			socantrcvmore(so);
5195281Sroot 			sbflush(&so->so_rcv);
5206140Ssam 			splx(s);
5215281Sroot 		}
5225281Sroot 		if (flags & FWRITE)
5235404Swnj 			u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, (struct mbuf *)0, 0);
5245281Sroot 		return;
5254829Swnj 	}
5265281Sroot 
5275423Swnj 	case SIOCSENDOOB: {
528*7627Ssam 		char oob = *(char *)data;
5295423Swnj 		struct mbuf *m;
530*7627Ssam 
5315423Swnj 		m = m_get(M_DONTWAIT);
5325423Swnj 		if (m == 0) {
5335423Swnj 			u.u_error = ENOBUFS;
5345423Swnj 			return;
5355423Swnj 		}
5365423Swnj 		m->m_off = MMINOFF;
537*7627Ssam 		m->m_len = sizeof (char);
538*7627Ssam 		*mtod(m, char *) = oob;
5395423Swnj 		(*so->so_proto->pr_usrreq)(so, PRU_SENDOOB, m, 0);
5405423Swnj 		return;
5415281Sroot 	}
5425423Swnj 
5435423Swnj 	case SIOCRCVOOB: {
5445423Swnj 		struct mbuf *m = m_get(M_DONTWAIT);
545*7627Ssam 
5465423Swnj 		if (m == 0) {
5475423Swnj 			u.u_error = ENOBUFS;
5485423Swnj 			return;
5495423Swnj 		}
5505423Swnj 		m->m_off = MMINOFF; *mtod(m, caddr_t) = 0;
5515423Swnj 		(*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, m, 0);
552*7627Ssam 		*(char *)data = *mtod(m, char *);
553*7627Ssam 		(void) m_free(m);
5545423Swnj 		return;
5555423Swnj 	}
5565423Swnj 
557*7627Ssam 	case SIOCATMARK:
558*7627Ssam 		*(int *)data = (so->so_state&SS_RCVATMARK) != 0;
5595423Swnj 		return;
5606355Ssam 
5616355Ssam 	/* routing table update calls */
5626355Ssam 	case SIOCADDRT:
5636355Ssam 	case SIOCDELRT:
5646355Ssam 		if (!suser())
5656355Ssam 			return;
566*7627Ssam 		u.u_error = rtrequest(cmd, (struct rtentry *)data);
5676355Ssam 		return;
5686355Ssam 
5695445Swnj 	/* type/protocol specific ioctls */
5705423Swnj 	}
5715445Swnj 	u.u_error = EOPNOTSUPP;
5724786Swnj }
573