xref: /csrg-svn/sys/kern/uipc_socket.c (revision 7747)
1*7747Sroot /*	uipc_socket.c	4.47	82/08/14	*/
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"
20*7747Sroot #include "../h/uio.h"
214786Swnj 
224786Swnj /*
234890Swnj  * Socket support routines.
244890Swnj  *
254890Swnj  * DEAL WITH INTERRUPT NOTIFICATION.
264786Swnj  */
274786Swnj 
284786Swnj /*
294786Swnj  * Create a socket.
304786Swnj  */
314927Swnj socreate(aso, type, asp, asa, options)
324786Swnj 	struct socket **aso;
334786Swnj 	int type;
344927Swnj 	struct sockproto *asp;
354927Swnj 	struct sockaddr *asa;
364829Swnj 	int options;
374786Swnj {
384786Swnj 	register struct protosw *prp;
394786Swnj 	register struct socket *so;
404786Swnj 	struct mbuf *m;
414890Swnj 	int pf, proto, error;
424786Swnj 
434786Swnj 	/*
444890Swnj 	 * Use process standard protocol/protocol family if none
454890Swnj 	 * specified by address argument.
464786Swnj 	 */
474927Swnj 	if (asp == 0) {
484890Swnj 		pf = PF_INET;		/* should be u.u_protof */
494786Swnj 		proto = 0;
504786Swnj 	} else {
514927Swnj 		pf = asp->sp_family;
524927Swnj 		proto = asp->sp_protocol;
534786Swnj 	}
544786Swnj 
554786Swnj 	/*
564890Swnj 	 * If protocol specified, look for it, otherwise
574890Swnj 	 * for a protocol of the correct type in the right family.
584890Swnj 	 */
594890Swnj 	if (proto)
604890Swnj 		prp = pffindproto(pf, proto);
614890Swnj 	else
624890Swnj 		prp = pffindtype(pf, type);
634890Swnj 	if (prp == 0)
644890Swnj 		return (EPROTONOSUPPORT);
654890Swnj 
664890Swnj 	/*
674786Swnj 	 * Get a socket structure.
684786Swnj 	 */
694890Swnj 	m = m_getclr(M_WAIT);
704786Swnj 	if (m == 0)
714786Swnj 		return (ENOBUFS);
724786Swnj 	so = mtod(m, struct socket *);
734829Swnj 	so->so_options = options;
747507Sroot 	if (options & SO_ACCEPTCONN) {
757507Sroot 		so->so_q = so;
767507Sroot 		so->so_q0 = so;
777507Sroot 		so->so_qlimit = (so->so_options & SO_NEWFDONCONN) ? 5 : 1;
787507Sroot 	}
796214Swnj 	so->so_state = 0;
806214Swnj 	if (u.u_uid == 0)
816214Swnj 		so->so_state = SS_PRIV;
824786Swnj 
834786Swnj 	/*
844890Swnj 	 * Attach protocol to socket, initializing
854890Swnj 	 * and reserving resources.
864786Swnj 	 */
874786Swnj 	so->so_proto = prp;
884979Swnj 	error = (*prp->pr_usrreq)(so, PRU_ATTACH, 0, asa);
894979Swnj 	if (error) {
907507Sroot 		so->so_state |= SS_NOFDREF;
917180Swnj 		sofree(so);
924890Swnj 		return (error);
934786Swnj 	}
944786Swnj 	*aso = so;
954786Swnj 	return (0);
964786Swnj }
974786Swnj 
984916Swnj sofree(so)
994916Swnj 	struct socket *so;
1004916Swnj {
1014916Swnj 
1027507Sroot 	if (so->so_head) {
1037507Sroot 		if (!soqremque(so, 0) && !soqremque(so, 1))
1047507Sroot 			panic("sofree dq");
1057507Sroot 		so->so_head = 0;
1067507Sroot 	}
1077507Sroot 	if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
1084950Swnj 		return;
1094950Swnj 	sbrelease(&so->so_snd);
1104950Swnj 	sbrelease(&so->so_rcv);
1114971Swnj 	(void) m_free(dtom(so));
1124916Swnj }
1134916Swnj 
1144786Swnj /*
1154890Swnj  * Close a socket on last file table reference removal.
1164890Swnj  * Initiate disconnect if connected.
1174890Swnj  * Free socket when disconnect complete.
1184829Swnj  */
1195580Sroot soclose(so, exiting)
1204829Swnj 	register struct socket *so;
1215580Sroot 	int exiting;
1224829Swnj {
1234890Swnj 	int s = splnet();		/* conservative */
1247507Sroot 	register struct socket *so2;
1254829Swnj 
1267507Sroot 	if (so->so_options & SO_ACCEPTCONN) {
1277507Sroot 		while (so->so_q0 != so)
1287507Sroot 			soclose(so->so_q0, 1);
1297507Sroot 		while (so->so_q != so)
1307507Sroot 			soclose(so->so_q, 1);
1317507Sroot 	}
1324890Swnj 	if (so->so_pcb == 0)
1334890Swnj 		goto discard;
1346259Sroot 	if (exiting)
1356259Sroot 		so->so_options |= SO_KEEPALIVE;
1364890Swnj 	if (so->so_state & SS_ISCONNECTED) {
1374890Swnj 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
1384927Swnj 			u.u_error = sodisconnect(so, (struct sockaddr *)0);
1394890Swnj 			if (u.u_error) {
1405580Sroot 				if (exiting)
1415580Sroot 					goto drop;
1424890Swnj 				splx(s);
1434890Swnj 				return;
1444890Swnj 			}
1454890Swnj 		}
1465388Sroot 		if ((so->so_options & SO_DONTLINGER) == 0) {
1475281Sroot 			if ((so->so_state & SS_ISDISCONNECTING) &&
1486214Swnj 			    (so->so_state & SS_NBIO) &&
1495580Sroot 			    exiting == 0) {
1505281Sroot 				u.u_error = EINPROGRESS;
1515281Sroot 				splx(s);
1525281Sroot 				return;
1535281Sroot 			}
1545580Sroot 			/* should use tsleep here, for at most linger */
1555281Sroot 			while (so->so_state & SS_ISCONNECTED)
1565281Sroot 				sleep((caddr_t)&so->so_timeo, PZERO+1);
1574890Swnj 		}
1584890Swnj 	}
1595580Sroot drop:
1606880Ssam 	if (so->so_pcb) {
1616880Ssam 		u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0);
1626880Ssam 		if (exiting == 0 && u.u_error) {
1636880Ssam 			splx(s);
1646880Ssam 			return;
1656880Ssam 		}
1666880Ssam 	}
1674890Swnj discard:
1687507Sroot 	so->so_state |= SS_NOFDREF;
1694950Swnj 	sofree(so);
1704890Swnj 	splx(s);
1714829Swnj }
1724829Swnj 
1734916Swnj /*ARGSUSED*/
1744890Swnj sostat(so, sb)
1754829Swnj 	struct socket *so;
1764890Swnj 	struct stat *sb;
1774829Swnj {
1784829Swnj 
1795303Sroot 	bzero((caddr_t)sb, sizeof (*sb));		/* XXX */
1805303Sroot 	return (0);					/* XXX */
1814829Swnj }
1824829Swnj 
1834829Swnj /*
1844927Swnj  * Accept connection on a socket.
1854927Swnj  */
1864927Swnj soaccept(so, asa)
1874927Swnj 	struct socket *so;
1884927Swnj 	struct sockaddr *asa;
1894927Swnj {
1904927Swnj 	int s = splnet();
1914927Swnj 	int error;
1924927Swnj 
1934927Swnj 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa);
1944927Swnj 	splx(s);
1954927Swnj 	return (error);
1964927Swnj }
1974927Swnj 
1984927Swnj /*
1994890Swnj  * Connect socket to a specified address.
2004890Swnj  * If already connected or connecting, then avoid
2014890Swnj  * the protocol entry, to keep its job simpler.
2024786Swnj  */
2034927Swnj soconnect(so, asa)
2044786Swnj 	struct socket *so;
2054927Swnj 	struct sockaddr *asa;
2064786Swnj {
2074890Swnj 	int s = splnet();
2084890Swnj 	int error;
2094786Swnj 
2104890Swnj 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
2114890Swnj 		error = EISCONN;
2124890Swnj 		goto bad;
2134890Swnj 	}
2144927Swnj 	error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa);
2154890Swnj bad:
2164890Swnj 	splx(s);
2174890Swnj 	return (error);
2184786Swnj }
2194786Swnj 
2204786Swnj /*
2214890Swnj  * Disconnect from a socket.
2224890Swnj  * Address parameter is from system call for later multicast
2234890Swnj  * protocols.  Check to make sure that connected and no disconnect
2244890Swnj  * in progress (for protocol's sake), and then invoke protocol.
2254786Swnj  */
2264927Swnj sodisconnect(so, asa)
2274786Swnj 	struct socket *so;
2284927Swnj 	struct sockaddr *asa;
2294786Swnj {
2304890Swnj 	int s = splnet();
2314890Swnj 	int error;
2324786Swnj 
2334890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2344890Swnj 		error = ENOTCONN;
2354890Swnj 		goto bad;
2364890Swnj 	}
2374890Swnj 	if (so->so_state & SS_ISDISCONNECTING) {
2384890Swnj 		error = EALREADY;
2394890Swnj 		goto bad;
2404890Swnj 	}
2414927Swnj 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa);
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  */
2554927Swnj sosend(so, asa)
2564786Swnj 	register struct socket *so;
2574927Swnj 	struct sockaddr *asa;
2584786Swnj {
2594890Swnj 	struct mbuf *top = 0;
2604890Swnj 	register struct mbuf *m, **mp = ⊤
2614916Swnj 	register u_int len;
2624916Swnj 	int error = 0, space, s;
2634786Swnj 
2644890Swnj 	if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat)
2654890Swnj 		return (EMSGSIZE);
2666419Sroot #ifdef notdef
2676419Sroot 	/* NEED TO PREVENT BUSY WAITING IN SELECT FOR WRITING */
2686214Swnj 	if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_state & SS_NBIO))
2694890Swnj 		return (EWOULDBLOCK);
2706419Sroot #endif
2716419Sroot restart:
2724890Swnj 	sblock(&so->so_snd);
2734890Swnj #define	snderr(errno)	{ error = errno; splx(s); goto release; }
2744890Swnj 
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);
2904927Swnj 		if (asa == 0)
2914890Swnj 			snderr(EDESTADDRREQ);
2924890Swnj 	}
2934890Swnj 	if (top) {
2944927Swnj 		error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa);
2956419Sroot 		top = 0;
2964890Swnj 		if (error) {
2974890Swnj 			splx(s);
2984786Swnj 			goto release;
2994786Swnj 		}
3004890Swnj 		mp = ⊤
3014786Swnj 	}
3024979Swnj 	if (u.u_count == 0) {
3034979Swnj 		splx(s);
3044979Swnj 		goto release;
3054979Swnj 	}
3065018Swnj 	space = sbspace(&so->so_snd);
3075610Swnj 	if (space <= 0 || sosendallatonce(so) && space < u.u_count) {
3086214Swnj 		if (so->so_state & SS_NBIO)
3094890Swnj 			snderr(EWOULDBLOCK);
3104890Swnj 		sbunlock(&so->so_snd);
3114890Swnj 		sbwait(&so->so_snd);
3124890Swnj 		splx(s);
3136419Sroot 		goto restart;
3144786Swnj 	}
3154890Swnj 	splx(s);
3165018Swnj 	while (u.u_count && space > 0) {
3174890Swnj 		MGET(m, 1);
3184890Swnj 		if (m == NULL) {
3196419Sroot 			error = ENOBUFS;			/* SIGPIPE? */
3204890Swnj 			goto release;
3214786Swnj 		}
3225095Swnj 		if (u.u_count >= CLBYTES && space >= CLBYTES) {
3234890Swnj 			register struct mbuf *p;
3245095Swnj 			MCLGET(p, 1);
3254890Swnj 			if (p == 0)
3264890Swnj 				goto nopages;
3274890Swnj 			m->m_off = (int)p - (int)m;
3285095Swnj 			len = CLBYTES;
3294890Swnj 		} else {
3304786Swnj nopages:
3314890Swnj 			m->m_off = MMINOFF;
3324890Swnj 			len = MIN(MLEN, u.u_count);
3334786Swnj 		}
3344890Swnj 		iomove(mtod(m, caddr_t), len, B_WRITE);
3354890Swnj 		m->m_len = len;
3364890Swnj 		*mp = m;
3374890Swnj 		mp = &m->m_next;
3385018Swnj 		space = sbspace(&so->so_snd);
3394786Swnj 	}
3404890Swnj 	goto again;
3414890Swnj 
3424786Swnj release:
3434890Swnj 	sbunlock(&so->so_snd);
3446419Sroot 	if (top)
3456419Sroot 		m_freem(top);
3464786Swnj 	return (error);
3474786Swnj }
3484786Swnj 
349*7747Sroot soreceive(so, asa, uio)
3504786Swnj 	register struct socket *so;
3514927Swnj 	struct sockaddr *asa;
352*7747Sroot 	struct uio *uio;
3534786Swnj {
354*7747Sroot 	register struct iovec *iov;
3554786Swnj 	register struct mbuf *m, *n;
3564916Swnj 	u_int len;
357*7747Sroot 	int eor, s, error = 0, resid = uio->uio_resid;
358*7747Sroot 	int cnt;
3594786Swnj 
3604890Swnj restart:
3614890Swnj 	sblock(&so->so_rcv);
3624890Swnj 	s = splnet();
3634890Swnj 
3644890Swnj #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
3654786Swnj 	if (so->so_rcv.sb_cc == 0) {
3665168Swnj 		if (so->so_error) {
3675168Swnj 			error = so->so_error;
3685168Swnj 			so->so_error = 0;
3695168Swnj 			splx(s);
3705168Swnj 			goto release;
3715168Swnj 		}
3724890Swnj 		if (so->so_state & SS_CANTRCVMORE) {
3734890Swnj 			splx(s);
3744890Swnj 			goto release;
3754890Swnj 		}
3765015Sroot 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
3775015Sroot 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
3785015Sroot 			rcverr(ENOTCONN);
3796214Swnj 		if (so->so_state & SS_NBIO)
3805168Swnj 			rcverr(EWOULDBLOCK);
3814890Swnj 		sbunlock(&so->so_rcv);
3824971Swnj 		sbwait(&so->so_rcv);
3835012Swnj 		splx(s);
3844890Swnj 		goto restart;
3854786Swnj 	}
3864829Swnj 	m = so->so_rcv.sb_mb;
3874786Swnj 	if (m == 0)
3884786Swnj 		panic("receive");
3895039Swnj 	if (so->so_proto->pr_flags & PR_ADDR) {
3905039Swnj 		if (m->m_len != sizeof (struct sockaddr))
3915039Swnj 			panic("soreceive addr");
3925039Swnj 		if (asa)
3935039Swnj 			bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa));
3945039Swnj 		so->so_rcv.sb_cc -= m->m_len;
3955039Swnj 		so->so_rcv.sb_mbcnt -= MSIZE;
3965018Swnj 		m = m_free(m);
3974890Swnj 		if (m == 0)
3984890Swnj 			panic("receive 2");
3995018Swnj 		so->so_rcv.sb_mb = m;
4004890Swnj 	}
4014786Swnj 	eor = 0;
4024786Swnj 	do {
403*7747Sroot 		if (uio->uio_iovcnt == 0)
404*7747Sroot 			break;
405*7747Sroot 		iov = uio->uio_iov;
406*7747Sroot 		len = iov->iov_len;
407*7747Sroot 		so->so_state &= ~SS_RCVATMARK;
408*7747Sroot 		if (so->so_oobmark && len > so->so_oobmark)
409*7747Sroot 			len = so->so_oobmark;
410*7747Sroot 		if (len > m->m_len)
411*7747Sroot 			len = m->m_len;
4124786Swnj 		splx(s);
413*7747Sroot 		uiomove(mtod(m, caddr_t), len, UIO_WRITETO, uio);
4144786Swnj 		s = splnet();
4154786Swnj 		if (len == m->m_len) {
4166091Sroot 			eor = (int)m->m_act;
4176091Sroot 			sbfree(&so->so_rcv, m);
4186091Sroot 			so->so_rcv.sb_mb = m->m_next;
4194786Swnj 			MFREE(m, n);
4204786Swnj 		} else {
4214786Swnj 			m->m_off += len;
4224786Swnj 			m->m_len -= len;
4234829Swnj 			so->so_rcv.sb_cc -= len;
4244786Swnj 		}
425*7747Sroot 		if (so->so_oobmark) {
426*7747Sroot 			so->so_oobmark -= len;
427*7747Sroot 			if (so->so_oobmark == 0) {
428*7747Sroot 				so->so_state |= SS_RCVATMARK;
429*7747Sroot 				break;
430*7747Sroot 			}
431*7747Sroot 		}
432*7747Sroot 	} while ((m = so->so_rcv.sb_mb) && !eor);
4334786Swnj 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
4344786Swnj 		do {
4354786Swnj 			if (m == 0)
4364890Swnj 				panic("receive 3");
4374890Swnj 			sbfree(&so->so_rcv, m);
4384786Swnj 			eor = (int)m->m_act;
4394786Swnj 			so->so_rcv.sb_mb = m->m_next;
4404786Swnj 			MFREE(m, n);
4414890Swnj 			m = n;
4424786Swnj 		} while (eor == 0);
4434890Swnj 	if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
4444890Swnj 		(*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0);
4454890Swnj release:
4464916Swnj 	sbunlock(&so->so_rcv);
4474890Swnj 	splx(s);
4484916Swnj 	return (error);
4494786Swnj }
4504786Swnj 
4515423Swnj sohasoutofband(so)
4525423Swnj 	struct socket *so;
4535423Swnj {
4545423Swnj 
4555423Swnj 	if (so->so_pgrp == 0)
4565423Swnj 		return;
4575423Swnj 	if (so->so_pgrp > 0)
4585423Swnj 		gsignal(so->so_pgrp, SIGURG);
4595429Swnj 	else {
4605429Swnj 		struct proc *p = pfind(-so->so_pgrp);
4615429Swnj 
4625429Swnj 		if (p)
4635429Swnj 			psignal(p, SIGURG);
4645429Swnj 	}
4655423Swnj }
4665423Swnj 
4674916Swnj /*ARGSUSED*/
4687627Ssam soioctl(so, cmd, data)
4694829Swnj 	register struct socket *so;
4704829Swnj 	int cmd;
4717627Ssam 	register char *data;
4724786Swnj {
4734786Swnj 
4745358Sroot 	switch (cmd) {
4754829Swnj 
4767627Ssam 	case FIONBIO:
4777627Ssam 		if (*(int *)data)
4786214Swnj 			so->so_state |= SS_NBIO;
4795388Sroot 		else
4806214Swnj 			so->so_state &= ~SS_NBIO;
4815388Sroot 		return;
4825388Sroot 
4837627Ssam 	case FIOASYNC:
4847627Ssam 		if (*(int *)data)
4856214Swnj 			so->so_state |= SS_ASYNC;
4865388Sroot 		else
4876214Swnj 			so->so_state &= ~SS_ASYNC;
4885388Sroot 		return;
4895388Sroot 
4907627Ssam 	case SIOCSKEEP:
4917627Ssam 		if (*(int *)data)
4927507Sroot 			so->so_options &= ~SO_KEEPALIVE;
4937507Sroot 		else
4947491Ssam 			so->so_options |= SO_KEEPALIVE;
4955388Sroot 		return;
4965388Sroot 
4977627Ssam 	case SIOCGKEEP:
4987627Ssam 		*(int *)data = (so->so_options & SO_KEEPALIVE) != 0;
4995388Sroot 		return;
5005388Sroot 
5017627Ssam 	case SIOCSLINGER:
5027627Ssam 		so->so_linger = *(int *)data;
5035388Sroot 		if (so->so_linger)
5045388Sroot 			so->so_options &= ~SO_DONTLINGER;
5055388Sroot 		else
5065388Sroot 			so->so_options |= SO_DONTLINGER;
5075388Sroot 		return;
5085388Sroot 
5097627Ssam 	case SIOCGLINGER:
5107627Ssam 		*(int *)data = so->so_linger;
5115423Swnj 		return;
5125388Sroot 
5137627Ssam 	case SIOCSPGRP:
5147627Ssam 		so->so_pgrp = *(int *)data;
5157627Ssam 		return;
5165423Swnj 
5177627Ssam 	case SIOCGPGRP:
5187627Ssam 		*(int *)data = so->so_pgrp;
5197627Ssam 		return;
5207627Ssam 
5215281Sroot 	case SIOCDONE: {
5227627Ssam 		int flags = *(int *)data;
5237627Ssam 
5245388Sroot 		flags++;
5255281Sroot 		if (flags & FREAD) {
5265281Sroot 			int s = splimp();
5275281Sroot 			socantrcvmore(so);
5285281Sroot 			sbflush(&so->so_rcv);
5296140Ssam 			splx(s);
5305281Sroot 		}
5315281Sroot 		if (flags & FWRITE)
5325404Swnj 			u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, (struct mbuf *)0, 0);
5335281Sroot 		return;
5344829Swnj 	}
5355281Sroot 
5365423Swnj 	case SIOCSENDOOB: {
5377627Ssam 		char oob = *(char *)data;
5385423Swnj 		struct mbuf *m;
5397627Ssam 
5405423Swnj 		m = m_get(M_DONTWAIT);
5415423Swnj 		if (m == 0) {
5425423Swnj 			u.u_error = ENOBUFS;
5435423Swnj 			return;
5445423Swnj 		}
5455423Swnj 		m->m_off = MMINOFF;
5467627Ssam 		m->m_len = sizeof (char);
5477627Ssam 		*mtod(m, char *) = oob;
5485423Swnj 		(*so->so_proto->pr_usrreq)(so, PRU_SENDOOB, m, 0);
5495423Swnj 		return;
5505281Sroot 	}
5515423Swnj 
5525423Swnj 	case SIOCRCVOOB: {
5535423Swnj 		struct mbuf *m = m_get(M_DONTWAIT);
5547627Ssam 
5555423Swnj 		if (m == 0) {
5565423Swnj 			u.u_error = ENOBUFS;
5575423Swnj 			return;
5585423Swnj 		}
5595423Swnj 		m->m_off = MMINOFF; *mtod(m, caddr_t) = 0;
5605423Swnj 		(*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, m, 0);
5617627Ssam 		*(char *)data = *mtod(m, char *);
5627627Ssam 		(void) m_free(m);
5635423Swnj 		return;
5645423Swnj 	}
5655423Swnj 
5667627Ssam 	case SIOCATMARK:
5677627Ssam 		*(int *)data = (so->so_state&SS_RCVATMARK) != 0;
5685423Swnj 		return;
5696355Ssam 
5706355Ssam 	/* routing table update calls */
5716355Ssam 	case SIOCADDRT:
5726355Ssam 	case SIOCDELRT:
5736355Ssam 		if (!suser())
5746355Ssam 			return;
5757627Ssam 		u.u_error = rtrequest(cmd, (struct rtentry *)data);
5766355Ssam 		return;
5776355Ssam 
5785445Swnj 	/* type/protocol specific ioctls */
5795423Swnj 	}
5805445Swnj 	u.u_error = EOPNOTSUPP;
5814786Swnj }
582