xref: /csrg-svn/sys/kern/uipc_socket.c (revision 8300)
1*8300Sroot /*	uipc_socket.c	4.50	82/10/03	*/
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"
207747Sroot #include "../h/uio.h"
214786Swnj 
224786Swnj /*
23*8300Sroot  * Socket operation routines.
24*8300Sroot  * These routines are called by the routines in
25*8300Sroot  * sys_socket.c or from a system process, and
26*8300Sroot  * implement the semantics of socket operations by
27*8300Sroot  * switching out to the protocol specific routines.
284786Swnj  */
294786Swnj 
30*8300Sroot socreate(dom, aso, type, proto, opt)
314786Swnj 	struct socket **aso;
32*8300Sroot 	int type, proto;
33*8300Sroot 	struct socketopt *opt;
344786Swnj {
354786Swnj 	register struct protosw *prp;
364786Swnj 	register struct socket *so;
374786Swnj 	struct mbuf *m;
38*8300Sroot 	int pf, error;
394786Swnj 
40*8300Sroot 	pf = dom ? PF_UNIX : PF_INET;		/* should be u.u_protof */
414890Swnj 	if (proto)
424890Swnj 		prp = pffindproto(pf, proto);
434890Swnj 	else
444890Swnj 		prp = pffindtype(pf, type);
454890Swnj 	if (prp == 0)
464890Swnj 		return (EPROTONOSUPPORT);
47*8300Sroot 	if (prp->pr_type != type)
48*8300Sroot 		return (EPROTOTYPE);
494890Swnj 	m = m_getclr(M_WAIT);
504786Swnj 	if (m == 0)
514786Swnj 		return (ENOBUFS);
524786Swnj 	so = mtod(m, struct socket *);
53*8300Sroot 	so->so_options = 0;
546214Swnj 	so->so_state = 0;
556214Swnj 	if (u.u_uid == 0)
566214Swnj 		so->so_state = SS_PRIV;
574786Swnj 	so->so_proto = prp;
58*8300Sroot 	error = (*prp->pr_usrreq)(so, PRU_ATTACH,
59*8300Sroot 	    (struct mbuf *)0, (struct mbuf *)0, (struct socketopt *)0);
604979Swnj 	if (error) {
617507Sroot 		so->so_state |= SS_NOFDREF;
627180Swnj 		sofree(so);
634890Swnj 		return (error);
644786Swnj 	}
654786Swnj 	*aso = so;
664786Swnj 	return (0);
674786Swnj }
684786Swnj 
69*8300Sroot sobind(so, nam, opt)
70*8300Sroot 	struct socket *so;
71*8300Sroot 	struct mbuf *nam;
72*8300Sroot 	struct socketopt *opt;
73*8300Sroot {
74*8300Sroot 	int s = splnet();
75*8300Sroot 	int error;
76*8300Sroot 
77*8300Sroot 	error =
78*8300Sroot 	    (*so->so_proto->pr_usrreq)(so, PRU_BIND,
79*8300Sroot 		(struct mbuf *)0, nam, opt);
80*8300Sroot 	splx(s);
81*8300Sroot 	return (error);
82*8300Sroot }
83*8300Sroot 
84*8300Sroot solisten(so, backlog)
85*8300Sroot 	struct socket *so;
86*8300Sroot 	int backlog;
87*8300Sroot {
88*8300Sroot 	int s = splnet();
89*8300Sroot 	int error;
90*8300Sroot 
91*8300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_LISTEN,
92*8300Sroot 	    (struct mbuf *)0, (struct mbuf *)0, (struct socketopt *)0);
93*8300Sroot 	if (error) {
94*8300Sroot 		splx(s);
95*8300Sroot 		return (error);
96*8300Sroot 	}
97*8300Sroot 	if (so->so_q == 0) {
98*8300Sroot 		so->so_q = so;
99*8300Sroot 		so->so_q0 = so;
100*8300Sroot 		so->so_options |= SO_ACCEPTCONN;
101*8300Sroot 	}
102*8300Sroot 	if (backlog < 0)
103*8300Sroot 		backlog = 0;
104*8300Sroot 	so->so_qlimit = backlog < 5 ? backlog : 5;
105*8300Sroot 	so->so_options |= SO_NEWFDONCONN;
106*8300Sroot 	return (0);
107*8300Sroot }
108*8300Sroot 
1094916Swnj sofree(so)
1104916Swnj 	struct socket *so;
1114916Swnj {
1124916Swnj 
1137507Sroot 	if (so->so_head) {
1147507Sroot 		if (!soqremque(so, 0) && !soqremque(so, 1))
1157507Sroot 			panic("sofree dq");
1167507Sroot 		so->so_head = 0;
1177507Sroot 	}
1187507Sroot 	if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
1194950Swnj 		return;
1204950Swnj 	sbrelease(&so->so_snd);
1214950Swnj 	sbrelease(&so->so_rcv);
1224971Swnj 	(void) m_free(dtom(so));
1234916Swnj }
1244916Swnj 
1254786Swnj /*
1264890Swnj  * Close a socket on last file table reference removal.
1274890Swnj  * Initiate disconnect if connected.
1284890Swnj  * Free socket when disconnect complete.
1294829Swnj  */
1305580Sroot soclose(so, exiting)
1314829Swnj 	register struct socket *so;
1325580Sroot 	int exiting;
1334829Swnj {
1344890Swnj 	int s = splnet();		/* conservative */
1354829Swnj 
1367507Sroot 	if (so->so_options & SO_ACCEPTCONN) {
1377507Sroot 		while (so->so_q0 != so)
1387507Sroot 			soclose(so->so_q0, 1);
1397507Sroot 		while (so->so_q != so)
1407507Sroot 			soclose(so->so_q, 1);
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) {
1484927Swnj 			u.u_error = sodisconnect(so, (struct sockaddr *)0);
1494890Swnj 			if (u.u_error) {
1505580Sroot 				if (exiting)
1515580Sroot 					goto drop;
1524890Swnj 				splx(s);
1534890Swnj 				return;
1544890Swnj 			}
1554890Swnj 		}
1565388Sroot 		if ((so->so_options & SO_DONTLINGER) == 0) {
1575281Sroot 			if ((so->so_state & SS_ISDISCONNECTING) &&
1586214Swnj 			    (so->so_state & SS_NBIO) &&
1595580Sroot 			    exiting == 0) {
1605281Sroot 				u.u_error = EINPROGRESS;
1615281Sroot 				splx(s);
1625281Sroot 				return;
1635281Sroot 			}
1645580Sroot 			/* should use tsleep here, for at most linger */
1655281Sroot 			while (so->so_state & SS_ISCONNECTED)
1665281Sroot 				sleep((caddr_t)&so->so_timeo, PZERO+1);
1674890Swnj 		}
1684890Swnj 	}
1695580Sroot drop:
1706880Ssam 	if (so->so_pcb) {
171*8300Sroot 		u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH,
172*8300Sroot 		    (struct mbuf *)0, (struct mbuf *)0, (struct socketopt *)0);
1736880Ssam 		if (exiting == 0 && u.u_error) {
1746880Ssam 			splx(s);
1756880Ssam 			return;
1766880Ssam 		}
1776880Ssam 	}
1784890Swnj discard:
1797507Sroot 	so->so_state |= SS_NOFDREF;
1804950Swnj 	sofree(so);
1814890Swnj 	splx(s);
1824829Swnj }
1834829Swnj 
1844916Swnj /*ARGSUSED*/
1854890Swnj sostat(so, sb)
1864829Swnj 	struct socket *so;
1874890Swnj 	struct stat *sb;
1884829Swnj {
1894829Swnj 
1905303Sroot 	bzero((caddr_t)sb, sizeof (*sb));		/* XXX */
1915303Sroot 	return (0);					/* XXX */
1924829Swnj }
1934829Swnj 
194*8300Sroot soaccept(so, nam, opt)
1954927Swnj 	struct socket *so;
196*8300Sroot 	struct mbuf *nam;
197*8300Sroot 	struct socketopt *opt;
1984927Swnj {
1994927Swnj 	int s = splnet();
2004927Swnj 	int error;
2014927Swnj 
202*8300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT,
203*8300Sroot 	    (struct mbuf *)0, nam, opt);
2044927Swnj 	splx(s);
2054927Swnj 	return (error);
2064927Swnj }
2074927Swnj 
208*8300Sroot soconnect(so, nam, opt)
2094786Swnj 	struct socket *so;
210*8300Sroot 	struct mbuf *nam;
211*8300Sroot 	struct socketopt *opt;
2124786Swnj {
2134890Swnj 	int s = splnet();
2144890Swnj 	int error;
2154786Swnj 
2164890Swnj 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
2174890Swnj 		error = EISCONN;
2184890Swnj 		goto bad;
2194890Swnj 	}
220*8300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
221*8300Sroot 	    (struct mbuf *)0, nam, opt);
2224890Swnj bad:
2234890Swnj 	splx(s);
2244890Swnj 	return (error);
2254786Swnj }
2264786Swnj 
227*8300Sroot sodisconnect(so, nam)
2284786Swnj 	struct socket *so;
229*8300Sroot 	struct mbuf *nam;
2304786Swnj {
2314890Swnj 	int s = splnet();
2324890Swnj 	int error;
2334786Swnj 
2344890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2354890Swnj 		error = ENOTCONN;
2364890Swnj 		goto bad;
2374890Swnj 	}
2384890Swnj 	if (so->so_state & SS_ISDISCONNECTING) {
2394890Swnj 		error = EALREADY;
2404890Swnj 		goto bad;
2414890Swnj 	}
242*8300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT,
243*8300Sroot 	    (struct mbuf *)0, nam, (struct socketopt *)0);
2444890Swnj bad:
2454890Swnj 	splx(s);
2464890Swnj 	return (error);
2474786Swnj }
2484786Swnj 
2494786Swnj /*
2504890Swnj  * Send on a socket.
2514890Swnj  * If send must go all at once and message is larger than
2524890Swnj  * send buffering, then hard error.
2534890Swnj  * Lock against other senders.
2544890Swnj  * If must go all at once and not enough room now, then
2554890Swnj  * inform user that this would block and do nothing.
2564786Swnj  */
257*8300Sroot sosend(so, nam, uio)
2584786Swnj 	register struct socket *so;
259*8300Sroot 	struct mbuf *nam;
2607827Sroot 	struct uio *uio;
2614786Swnj {
2624890Swnj 	struct mbuf *top = 0;
2634890Swnj 	register struct mbuf *m, **mp = &top;
2644916Swnj 	register u_int len;
2654916Swnj 	int error = 0, space, s;
2664786Swnj 
2677827Sroot 	if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat)
2684890Swnj 		return (EMSGSIZE);
2696419Sroot #ifdef notdef
2706419Sroot 	/* NEED TO PREVENT BUSY WAITING IN SELECT FOR WRITING */
2716214Swnj 	if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_state & SS_NBIO))
2724890Swnj 		return (EWOULDBLOCK);
2736419Sroot #endif
2746419Sroot restart:
2754890Swnj 	sblock(&so->so_snd);
2764890Swnj #define	snderr(errno)	{ error = errno; splx(s); goto release; }
2774890Swnj 
2788041Sroot 	u.u_ru.ru_msgsnd++;
2796419Sroot again:
2804890Swnj 	s = splnet();
2816419Sroot 	if (so->so_state & SS_CANTSENDMORE) {
2826419Sroot 		psignal(u.u_procp, SIGPIPE);
2836419Sroot 		snderr(EPIPE);
2846419Sroot 	}
2855168Swnj 	if (so->so_error) {
2865168Swnj 		error = so->so_error;
2876419Sroot 		so->so_error = 0;				/* ??? */
2885168Swnj 		splx(s);
2895168Swnj 		goto release;
2905168Swnj 	}
2914890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2924890Swnj 		if (so->so_proto->pr_flags & PR_CONNREQUIRED)
2934890Swnj 			snderr(ENOTCONN);
294*8300Sroot 		if (nam == 0)
2954890Swnj 			snderr(EDESTADDRREQ);
2964890Swnj 	}
2974890Swnj 	if (top) {
298*8300Sroot 		error = (*so->so_proto->pr_usrreq)(so, PRU_SEND,
299*8300Sroot 		    top, (caddr_t)nam, (struct socketopt *)0);
3006419Sroot 		top = 0;
3014890Swnj 		if (error) {
3024890Swnj 			splx(s);
3034786Swnj 			goto release;
3044786Swnj 		}
3054890Swnj 		mp = &top;
3064786Swnj 	}
3077827Sroot 	if (uio->uio_resid == 0) {
3084979Swnj 		splx(s);
3094979Swnj 		goto release;
3104979Swnj 	}
3115018Swnj 	space = sbspace(&so->so_snd);
3127827Sroot 	if (space <= 0 || sosendallatonce(so) && space < uio->uio_resid) {
3136214Swnj 		if (so->so_state & SS_NBIO)
3144890Swnj 			snderr(EWOULDBLOCK);
3154890Swnj 		sbunlock(&so->so_snd);
3164890Swnj 		sbwait(&so->so_snd);
3174890Swnj 		splx(s);
3186419Sroot 		goto restart;
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:
3454890Swnj 			m->m_off = MMINOFF;
3467827Sroot 			len = MIN(MLEN, iov->iov_len);
3474786Swnj 		}
3487827Sroot 		uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio);
3494890Swnj 		m->m_len = len;
3504890Swnj 		*mp = m;
3514890Swnj 		mp = &m->m_next;
3525018Swnj 		space = sbspace(&so->so_snd);
3534786Swnj 	}
3544890Swnj 	goto again;
3554890Swnj 
3564786Swnj release:
3574890Swnj 	sbunlock(&so->so_snd);
3586419Sroot 	if (top)
3596419Sroot 		m_freem(top);
3604786Swnj 	return (error);
3614786Swnj }
3624786Swnj 
363*8300Sroot soreceive(so, aname, uio)
3644786Swnj 	register struct socket *so;
365*8300Sroot 	struct mbuf **aname;
3667747Sroot 	struct uio *uio;
3674786Swnj {
3687747Sroot 	register struct iovec *iov;
3694786Swnj 	register struct mbuf *m, *n;
3704916Swnj 	u_int len;
3717827Sroot 	int eor, s, error = 0;
3724786Swnj 
3734890Swnj restart:
3744890Swnj 	sblock(&so->so_rcv);
3754890Swnj 	s = splnet();
3764890Swnj 
3774890Swnj #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
3784786Swnj 	if (so->so_rcv.sb_cc == 0) {
3795168Swnj 		if (so->so_error) {
3805168Swnj 			error = so->so_error;
3815168Swnj 			so->so_error = 0;
3825168Swnj 			splx(s);
3835168Swnj 			goto release;
3845168Swnj 		}
3854890Swnj 		if (so->so_state & SS_CANTRCVMORE) {
3864890Swnj 			splx(s);
3874890Swnj 			goto release;
3884890Swnj 		}
3895015Sroot 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
3905015Sroot 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
3915015Sroot 			rcverr(ENOTCONN);
3926214Swnj 		if (so->so_state & SS_NBIO)
3935168Swnj 			rcverr(EWOULDBLOCK);
3944890Swnj 		sbunlock(&so->so_rcv);
3954971Swnj 		sbwait(&so->so_rcv);
3965012Swnj 		splx(s);
3974890Swnj 		goto restart;
3984786Swnj 	}
3998041Sroot 	u.u_ru.ru_msgrcv++;
4004829Swnj 	m = so->so_rcv.sb_mb;
4014786Swnj 	if (m == 0)
4024786Swnj 		panic("receive");
4035039Swnj 	if (so->so_proto->pr_flags & PR_ADDR) {
4045039Swnj 		so->so_rcv.sb_cc -= m->m_len;
4055039Swnj 		so->so_rcv.sb_mbcnt -= MSIZE;
406*8300Sroot 		if (aname) {
407*8300Sroot 			*aname = m;
408*8300Sroot 			m = m->m_next;
409*8300Sroot 			(*aname)->m_next = 0;
410*8300Sroot 		} else
411*8300Sroot 			m = m_free(m);
4124890Swnj 		if (m == 0)
4134890Swnj 			panic("receive 2");
4145018Swnj 		so->so_rcv.sb_mb = m;
4154890Swnj 	}
4164786Swnj 	eor = 0;
4174786Swnj 	do {
4187827Sroot 		if (uio->uio_resid <= 0)
4197747Sroot 			break;
4207827Sroot 		len = uio->uio_resid;
4217747Sroot 		so->so_state &= ~SS_RCVATMARK;
4227747Sroot 		if (so->so_oobmark && len > so->so_oobmark)
4237747Sroot 			len = so->so_oobmark;
4247747Sroot 		if (len > m->m_len)
4257747Sroot 			len = m->m_len;
4264786Swnj 		splx(s);
4277827Sroot 		uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio);
4284786Swnj 		s = splnet();
4294786Swnj 		if (len == m->m_len) {
4306091Sroot 			eor = (int)m->m_act;
4316091Sroot 			sbfree(&so->so_rcv, m);
4326091Sroot 			so->so_rcv.sb_mb = m->m_next;
4334786Swnj 			MFREE(m, n);
4344786Swnj 		} else {
4354786Swnj 			m->m_off += len;
4364786Swnj 			m->m_len -= len;
4374829Swnj 			so->so_rcv.sb_cc -= len;
4384786Swnj 		}
4397747Sroot 		if (so->so_oobmark) {
4407747Sroot 			so->so_oobmark -= len;
4417747Sroot 			if (so->so_oobmark == 0) {
4427747Sroot 				so->so_state |= SS_RCVATMARK;
4437747Sroot 				break;
4447747Sroot 			}
4457747Sroot 		}
4467747Sroot 	} while ((m = so->so_rcv.sb_mb) && !eor);
4474786Swnj 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
4484786Swnj 		do {
4494786Swnj 			if (m == 0)
4504890Swnj 				panic("receive 3");
4514890Swnj 			sbfree(&so->so_rcv, m);
4524786Swnj 			eor = (int)m->m_act;
4534786Swnj 			so->so_rcv.sb_mb = m->m_next;
4544786Swnj 			MFREE(m, n);
4554890Swnj 			m = n;
4564786Swnj 		} while (eor == 0);
4574890Swnj 	if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
458*8300Sroot 		(*so->so_proto->pr_usrreq)(so, PRU_RCVD,
459*8300Sroot 		    (struct mbuf *)0, (struct mbuf *)0, (struct socketopt *)0);
4604890Swnj release:
4614916Swnj 	sbunlock(&so->so_rcv);
4624890Swnj 	splx(s);
4634916Swnj 	return (error);
4644786Swnj }
4654786Swnj 
4665423Swnj sohasoutofband(so)
4675423Swnj 	struct socket *so;
4685423Swnj {
4695423Swnj 
4705423Swnj 	if (so->so_pgrp == 0)
4715423Swnj 		return;
4725423Swnj 	if (so->so_pgrp > 0)
4735423Swnj 		gsignal(so->so_pgrp, SIGURG);
4745429Swnj 	else {
4755429Swnj 		struct proc *p = pfind(-so->so_pgrp);
4765429Swnj 
4775429Swnj 		if (p)
4785429Swnj 			psignal(p, SIGURG);
4795429Swnj 	}
4805423Swnj }
4815423Swnj 
4824916Swnj /*ARGSUSED*/
4837627Ssam soioctl(so, cmd, data)
4844829Swnj 	register struct socket *so;
4854829Swnj 	int cmd;
4867627Ssam 	register char *data;
4874786Swnj {
4884786Swnj 
4895358Sroot 	switch (cmd) {
4904829Swnj 
4917627Ssam 	case FIONBIO:
4927627Ssam 		if (*(int *)data)
4936214Swnj 			so->so_state |= SS_NBIO;
4945388Sroot 		else
4956214Swnj 			so->so_state &= ~SS_NBIO;
4965388Sroot 		return;
4975388Sroot 
4987627Ssam 	case FIOASYNC:
4997627Ssam 		if (*(int *)data)
5006214Swnj 			so->so_state |= SS_ASYNC;
5015388Sroot 		else
5026214Swnj 			so->so_state &= ~SS_ASYNC;
5035388Sroot 		return;
5045388Sroot 
5057627Ssam 	case SIOCSKEEP:
5067627Ssam 		if (*(int *)data)
5077507Sroot 			so->so_options &= ~SO_KEEPALIVE;
5087507Sroot 		else
5097491Ssam 			so->so_options |= SO_KEEPALIVE;
5105388Sroot 		return;
5115388Sroot 
5127627Ssam 	case SIOCGKEEP:
5137627Ssam 		*(int *)data = (so->so_options & SO_KEEPALIVE) != 0;
5145388Sroot 		return;
5155388Sroot 
5167627Ssam 	case SIOCSLINGER:
5177627Ssam 		so->so_linger = *(int *)data;
5185388Sroot 		if (so->so_linger)
5195388Sroot 			so->so_options &= ~SO_DONTLINGER;
5205388Sroot 		else
5215388Sroot 			so->so_options |= SO_DONTLINGER;
5225388Sroot 		return;
5235388Sroot 
5247627Ssam 	case SIOCGLINGER:
5257627Ssam 		*(int *)data = so->so_linger;
5265423Swnj 		return;
5275388Sroot 
5287627Ssam 	case SIOCSPGRP:
5297627Ssam 		so->so_pgrp = *(int *)data;
5307627Ssam 		return;
5315423Swnj 
5327627Ssam 	case SIOCGPGRP:
5337627Ssam 		*(int *)data = so->so_pgrp;
5347627Ssam 		return;
5357627Ssam 
5365281Sroot 	case SIOCDONE: {
5377627Ssam 		int flags = *(int *)data;
5387627Ssam 
5395388Sroot 		flags++;
5405281Sroot 		if (flags & FREAD) {
5415281Sroot 			int s = splimp();
5425281Sroot 			socantrcvmore(so);
5435281Sroot 			sbflush(&so->so_rcv);
5446140Ssam 			splx(s);
5455281Sroot 		}
5465281Sroot 		if (flags & FWRITE)
547*8300Sroot 			u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN,
548*8300Sroot 			    (struct mbuf *)0, (struct mbuf *)0,
549*8300Sroot 			    (struct socketopt *)0);
5505281Sroot 		return;
5514829Swnj 	}
5525281Sroot 
5535423Swnj 	case SIOCSENDOOB: {
5547627Ssam 		char oob = *(char *)data;
5555423Swnj 		struct mbuf *m;
5567627Ssam 
5575423Swnj 		m = m_get(M_DONTWAIT);
5585423Swnj 		if (m == 0) {
5595423Swnj 			u.u_error = ENOBUFS;
5605423Swnj 			return;
5615423Swnj 		}
5625423Swnj 		m->m_off = MMINOFF;
5637627Ssam 		m->m_len = sizeof (char);
5647627Ssam 		*mtod(m, char *) = oob;
565*8300Sroot 		(*so->so_proto->pr_usrreq)(so, PRU_SENDOOB,
566*8300Sroot 		    m, (struct mbuf *)0, (struct socketopt *)0);
5675423Swnj 		return;
5685281Sroot 	}
5695423Swnj 
5705423Swnj 	case SIOCRCVOOB: {
5715423Swnj 		struct mbuf *m = m_get(M_DONTWAIT);
5727627Ssam 
5735423Swnj 		if (m == 0) {
5745423Swnj 			u.u_error = ENOBUFS;
5755423Swnj 			return;
5765423Swnj 		}
5775423Swnj 		m->m_off = MMINOFF; *mtod(m, caddr_t) = 0;
578*8300Sroot 		(*so->so_proto->pr_usrreq)(so, PRU_RCVOOB,
579*8300Sroot 		    m, (struct mbuf *)0, (struct socketopt *)0);
5807627Ssam 		*(char *)data = *mtod(m, char *);
5817627Ssam 		(void) m_free(m);
5825423Swnj 		return;
5835423Swnj 	}
5845423Swnj 
5857627Ssam 	case SIOCATMARK:
5867627Ssam 		*(int *)data = (so->so_state&SS_RCVATMARK) != 0;
5875423Swnj 		return;
5886355Ssam 
5896355Ssam 	/* routing table update calls */
5906355Ssam 	case SIOCADDRT:
5916355Ssam 	case SIOCDELRT:
5926355Ssam 		if (!suser())
5936355Ssam 			return;
5947627Ssam 		u.u_error = rtrequest(cmd, (struct rtentry *)data);
5956355Ssam 		return;
5966355Ssam 
5975445Swnj 	/* type/protocol specific ioctls */
5985423Swnj 	}
5995445Swnj 	u.u_error = EOPNOTSUPP;
6004786Swnj }
601