xref: /csrg-svn/sys/kern/uipc_socket.c (revision 6419)
1*6419Sroot /*	uipc_socket.c	4.38	82/04/01	*/
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;
414927Swnj COUNT(SOCREATE);
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;
746214Swnj 	so->so_state = 0;
756214Swnj 	if (u.u_uid == 0)
766214Swnj 		so->so_state = SS_PRIV;
774786Swnj 
784786Swnj 	/*
794890Swnj 	 * Attach protocol to socket, initializing
804890Swnj 	 * and reserving resources.
814786Swnj 	 */
824786Swnj 	so->so_proto = prp;
834979Swnj 	error = (*prp->pr_usrreq)(so, PRU_ATTACH, 0, asa);
844979Swnj 	if (error) {
854971Swnj 		(void) m_free(dtom(so));
864890Swnj 		return (error);
874786Swnj 	}
884786Swnj 	*aso = so;
894786Swnj 	return (0);
904786Swnj }
914786Swnj 
924916Swnj sofree(so)
934916Swnj 	struct socket *so;
944916Swnj {
954916Swnj 
964927Swnj COUNT(SOFREE);
974950Swnj 	if (so->so_pcb || (so->so_state & SS_USERGONE) == 0)
984950Swnj 		return;
994950Swnj 	sbrelease(&so->so_snd);
1004950Swnj 	sbrelease(&so->so_rcv);
1014971Swnj 	(void) m_free(dtom(so));
1024916Swnj }
1034916Swnj 
1044786Swnj /*
1054890Swnj  * Close a socket on last file table reference removal.
1064890Swnj  * Initiate disconnect if connected.
1074890Swnj  * Free socket when disconnect complete.
1085580Sroot  *
1095580Sroot  * THIS IS REALLY A UNIX INTERFACE ROUTINE
1104829Swnj  */
1115580Sroot soclose(so, exiting)
1124829Swnj 	register struct socket *so;
1135580Sroot 	int exiting;
1144829Swnj {
1154890Swnj 	int s = splnet();		/* conservative */
1164829Swnj 
1174927Swnj COUNT(SOCLOSE);
1184890Swnj 	if (so->so_pcb == 0)
1194890Swnj 		goto discard;
1206259Sroot 	if (exiting)
1216259Sroot 		so->so_options |= SO_KEEPALIVE;
1224890Swnj 	if (so->so_state & SS_ISCONNECTED) {
1234890Swnj 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
1244927Swnj 			u.u_error = sodisconnect(so, (struct sockaddr *)0);
1254890Swnj 			if (u.u_error) {
1265580Sroot 				if (exiting)
1275580Sroot 					goto drop;
1284890Swnj 				splx(s);
1294890Swnj 				return;
1304890Swnj 			}
1314890Swnj 		}
1325388Sroot 		if ((so->so_options & SO_DONTLINGER) == 0) {
1335281Sroot 			if ((so->so_state & SS_ISDISCONNECTING) &&
1346214Swnj 			    (so->so_state & SS_NBIO) &&
1355580Sroot 			    exiting == 0) {
1365281Sroot 				u.u_error = EINPROGRESS;
1375281Sroot 				splx(s);
1385281Sroot 				return;
1395281Sroot 			}
1405580Sroot 			/* should use tsleep here, for at most linger */
1415281Sroot 			while (so->so_state & SS_ISCONNECTED)
1425281Sroot 				sleep((caddr_t)&so->so_timeo, PZERO+1);
1434890Swnj 		}
1444890Swnj 	}
1455580Sroot drop:
1464890Swnj 	u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0);
1474890Swnj discard:
1484950Swnj 	so->so_state |= SS_USERGONE;
1494950Swnj 	sofree(so);
1504890Swnj 	splx(s);
1514829Swnj }
1524829Swnj 
1534916Swnj /*ARGSUSED*/
1544890Swnj sostat(so, sb)
1554829Swnj 	struct socket *so;
1564890Swnj 	struct stat *sb;
1574829Swnj {
1584829Swnj 
1594927Swnj COUNT(SOSTAT);
1605303Sroot 	bzero((caddr_t)sb, sizeof (*sb));		/* XXX */
1615303Sroot 	return (0);					/* XXX */
1624829Swnj }
1634829Swnj 
1644829Swnj /*
1654927Swnj  * Accept connection on a socket.
1664927Swnj  */
1674927Swnj soaccept(so, asa)
1684927Swnj 	struct socket *so;
1694927Swnj 	struct sockaddr *asa;
1704927Swnj {
1714927Swnj 	int s = splnet();
1724927Swnj 	int error;
1734927Swnj 
1744927Swnj COUNT(SOACCEPT);
1754927Swnj 	if ((so->so_options & SO_ACCEPTCONN) == 0) {
1764927Swnj 		error = EINVAL;			/* XXX */
1774927Swnj 		goto bad;
1784927Swnj 	}
1795265Swnj 	if ((so->so_state & SS_CONNAWAITING) == 0) {
1805265Swnj 		error = ENOTCONN;
1815265Swnj 		goto bad;
1825265Swnj 	}
1835265Swnj 	so->so_state &= ~SS_CONNAWAITING;
1844927Swnj 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa);
1854927Swnj bad:
1864927Swnj 	splx(s);
1874927Swnj 	return (error);
1884927Swnj }
1894927Swnj 
1904927Swnj /*
1914890Swnj  * Connect socket to a specified address.
1924890Swnj  * If already connected or connecting, then avoid
1934890Swnj  * the protocol entry, to keep its job simpler.
1944786Swnj  */
1954927Swnj soconnect(so, asa)
1964786Swnj 	struct socket *so;
1974927Swnj 	struct sockaddr *asa;
1984786Swnj {
1994890Swnj 	int s = splnet();
2004890Swnj 	int error;
2014786Swnj 
2024927Swnj COUNT(SOCONNECT);
2034890Swnj 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
2044890Swnj 		error = EISCONN;
2054890Swnj 		goto bad;
2064890Swnj 	}
2074927Swnj 	error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa);
2084890Swnj bad:
2094890Swnj 	splx(s);
2104890Swnj 	return (error);
2114786Swnj }
2124786Swnj 
2134786Swnj /*
2144890Swnj  * Disconnect from a socket.
2154890Swnj  * Address parameter is from system call for later multicast
2164890Swnj  * protocols.  Check to make sure that connected and no disconnect
2174890Swnj  * in progress (for protocol's sake), and then invoke protocol.
2184786Swnj  */
2194927Swnj sodisconnect(so, asa)
2204786Swnj 	struct socket *so;
2214927Swnj 	struct sockaddr *asa;
2224786Swnj {
2234890Swnj 	int s = splnet();
2244890Swnj 	int error;
2254786Swnj 
2264927Swnj COUNT(SODISCONNECT);
2274890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2284890Swnj 		error = ENOTCONN;
2294890Swnj 		goto bad;
2304890Swnj 	}
2314890Swnj 	if (so->so_state & SS_ISDISCONNECTING) {
2324890Swnj 		error = EALREADY;
2334890Swnj 		goto bad;
2344890Swnj 	}
2354927Swnj 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa);
2364890Swnj bad:
2374890Swnj 	splx(s);
2384890Swnj 	return (error);
2394786Swnj }
2404786Swnj 
2414786Swnj /*
2424890Swnj  * Send on a socket.
2434890Swnj  * If send must go all at once and message is larger than
2444890Swnj  * send buffering, then hard error.
2454890Swnj  * Lock against other senders.
2464890Swnj  * If must go all at once and not enough room now, then
2474890Swnj  * inform user that this would block and do nothing.
2484786Swnj  */
2494927Swnj sosend(so, asa)
2504786Swnj 	register struct socket *so;
2514927Swnj 	struct sockaddr *asa;
2524786Swnj {
2534890Swnj 	struct mbuf *top = 0;
2544890Swnj 	register struct mbuf *m, **mp = ⊤
2554916Swnj 	register u_int len;
2564916Swnj 	int error = 0, space, s;
2574786Swnj 
2584927Swnj COUNT(SOSEND);
2594890Swnj 	if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat)
2604890Swnj 		return (EMSGSIZE);
261*6419Sroot #ifdef notdef
262*6419Sroot 	/* NEED TO PREVENT BUSY WAITING IN SELECT FOR WRITING */
2636214Swnj 	if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_state & SS_NBIO))
2644890Swnj 		return (EWOULDBLOCK);
265*6419Sroot #endif
266*6419Sroot restart:
2674890Swnj 	sblock(&so->so_snd);
2684890Swnj #define	snderr(errno)	{ error = errno; splx(s); goto release; }
2694890Swnj 
270*6419Sroot again:
2714890Swnj 	s = splnet();
272*6419Sroot 	if (so->so_state & SS_CANTSENDMORE) {
273*6419Sroot 		psignal(u.u_procp, SIGPIPE);
274*6419Sroot 		snderr(EPIPE);
275*6419Sroot 	}
2765168Swnj 	if (so->so_error) {
2775168Swnj 		error = so->so_error;
278*6419Sroot 		so->so_error = 0;				/* ??? */
2795168Swnj 		splx(s);
2805168Swnj 		goto release;
2815168Swnj 	}
2824890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2834890Swnj 		if (so->so_proto->pr_flags & PR_CONNREQUIRED)
2844890Swnj 			snderr(ENOTCONN);
2854927Swnj 		if (asa == 0)
2864890Swnj 			snderr(EDESTADDRREQ);
2874890Swnj 	}
2884890Swnj 	if (top) {
2894927Swnj 		error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa);
290*6419Sroot 		top = 0;
2914890Swnj 		if (error) {
2924890Swnj 			splx(s);
2934786Swnj 			goto release;
2944786Swnj 		}
2954890Swnj 		mp = ⊤
2964786Swnj 	}
2974979Swnj 	if (u.u_count == 0) {
2984979Swnj 		splx(s);
2994979Swnj 		goto release;
3004979Swnj 	}
3015018Swnj 	space = sbspace(&so->so_snd);
3025610Swnj 	if (space <= 0 || sosendallatonce(so) && space < u.u_count) {
3036214Swnj 		if (so->so_state & SS_NBIO)
3044890Swnj 			snderr(EWOULDBLOCK);
3054890Swnj 		sbunlock(&so->so_snd);
3064890Swnj 		sbwait(&so->so_snd);
3074890Swnj 		splx(s);
308*6419Sroot 		goto restart;
3094786Swnj 	}
3104890Swnj 	splx(s);
3115018Swnj 	while (u.u_count && space > 0) {
3124890Swnj 		MGET(m, 1);
3134890Swnj 		if (m == NULL) {
314*6419Sroot 			error = ENOBUFS;			/* SIGPIPE? */
3154890Swnj 			goto release;
3164786Swnj 		}
3175095Swnj 		if (u.u_count >= CLBYTES && space >= CLBYTES) {
3184890Swnj 			register struct mbuf *p;
3195095Swnj 			MCLGET(p, 1);
3204890Swnj 			if (p == 0)
3214890Swnj 				goto nopages;
3224890Swnj 			m->m_off = (int)p - (int)m;
3235095Swnj 			len = CLBYTES;
3244890Swnj 		} else {
3254786Swnj nopages:
3264890Swnj 			m->m_off = MMINOFF;
3274890Swnj 			len = MIN(MLEN, u.u_count);
3284786Swnj 		}
3294890Swnj 		iomove(mtod(m, caddr_t), len, B_WRITE);
3304890Swnj 		m->m_len = len;
3314890Swnj 		*mp = m;
3324890Swnj 		mp = &m->m_next;
3335018Swnj 		space = sbspace(&so->so_snd);
3344786Swnj 	}
3354890Swnj 	goto again;
3364890Swnj 
3374786Swnj release:
3384890Swnj 	sbunlock(&so->so_snd);
339*6419Sroot 	if (top)
340*6419Sroot 		m_freem(top);
3414786Swnj 	return (error);
3424786Swnj }
3434786Swnj 
3444927Swnj soreceive(so, asa)
3454786Swnj 	register struct socket *so;
3464927Swnj 	struct sockaddr *asa;
3474786Swnj {
3484786Swnj 	register struct mbuf *m, *n;
3494916Swnj 	u_int len;
3505423Swnj 	int eor, s, error = 0, cnt = u.u_count;
3515423Swnj 	caddr_t base = u.u_base;
3524786Swnj 
3534927Swnj COUNT(SORECEIVE);
3544890Swnj restart:
3554890Swnj 	sblock(&so->so_rcv);
3564890Swnj 	s = splnet();
3574890Swnj 
3584890Swnj #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
3594786Swnj 	if (so->so_rcv.sb_cc == 0) {
3605168Swnj 		if (so->so_error) {
3615168Swnj 			error = so->so_error;
3625168Swnj 			so->so_error = 0;
3635168Swnj 			splx(s);
3645168Swnj 			goto release;
3655168Swnj 		}
3664890Swnj 		if (so->so_state & SS_CANTRCVMORE) {
3674890Swnj 			splx(s);
3684890Swnj 			goto release;
3694890Swnj 		}
3705015Sroot 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
3715015Sroot 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
3725015Sroot 			rcverr(ENOTCONN);
3736214Swnj 		if (so->so_state & SS_NBIO)
3745168Swnj 			rcverr(EWOULDBLOCK);
3754890Swnj 		sbunlock(&so->so_rcv);
3764971Swnj 		sbwait(&so->so_rcv);
3775012Swnj 		splx(s);
3784890Swnj 		goto restart;
3794786Swnj 	}
3804829Swnj 	m = so->so_rcv.sb_mb;
3814786Swnj 	if (m == 0)
3824786Swnj 		panic("receive");
3835039Swnj 	if (so->so_proto->pr_flags & PR_ADDR) {
3845039Swnj 		if (m->m_len != sizeof (struct sockaddr))
3855039Swnj 			panic("soreceive addr");
3865039Swnj 		if (asa)
3875039Swnj 			bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa));
3885039Swnj 		so->so_rcv.sb_cc -= m->m_len;
3895039Swnj 		so->so_rcv.sb_mbcnt -= MSIZE;
3905018Swnj 		m = m_free(m);
3914890Swnj 		if (m == 0)
3924890Swnj 			panic("receive 2");
3935018Swnj 		so->so_rcv.sb_mb = m;
3944890Swnj 	}
3955423Swnj 	so->so_state &= ~SS_RCVATMARK;
3965423Swnj 	if (so->so_oobmark && cnt > so->so_oobmark)
3975423Swnj 		cnt = so->so_oobmark;
3984786Swnj 	eor = 0;
3994786Swnj 	do {
4005423Swnj 		len = MIN(m->m_len, cnt);
4014786Swnj 		splx(s);
4024786Swnj 		iomove(mtod(m, caddr_t), len, B_READ);
4035423Swnj 		cnt -= len;
4044786Swnj 		s = splnet();
4054786Swnj 		if (len == m->m_len) {
4066091Sroot 			eor = (int)m->m_act;
4076091Sroot 			sbfree(&so->so_rcv, m);
4086091Sroot 			so->so_rcv.sb_mb = m->m_next;
4094786Swnj 			MFREE(m, n);
4104786Swnj 		} else {
4114786Swnj 			m->m_off += len;
4124786Swnj 			m->m_len -= len;
4134829Swnj 			so->so_rcv.sb_cc -= len;
4144786Swnj 		}
4155423Swnj 	} while ((m = so->so_rcv.sb_mb) && cnt && !eor);
4164786Swnj 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
4174786Swnj 		do {
4184786Swnj 			if (m == 0)
4194890Swnj 				panic("receive 3");
4204890Swnj 			sbfree(&so->so_rcv, m);
4214786Swnj 			eor = (int)m->m_act;
4224786Swnj 			so->so_rcv.sb_mb = m->m_next;
4234786Swnj 			MFREE(m, n);
4244890Swnj 			m = n;
4254786Swnj 		} while (eor == 0);
4264890Swnj 	if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
4274890Swnj 		(*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0);
4285423Swnj 	if (so->so_oobmark) {
4295423Swnj 		so->so_oobmark -= u.u_base - base;
4305423Swnj 		if (so->so_oobmark == 0)
4315423Swnj 			so->so_state |= SS_RCVATMARK;
4325423Swnj 	}
4334890Swnj release:
4344916Swnj 	sbunlock(&so->so_rcv);
4354890Swnj 	splx(s);
4364916Swnj 	return (error);
4374786Swnj }
4384786Swnj 
4395423Swnj sohasoutofband(so)
4405423Swnj 	struct socket *so;
4415423Swnj {
4425423Swnj 
4435423Swnj 	if (so->so_pgrp == 0)
4445423Swnj 		return;
4455423Swnj 	if (so->so_pgrp > 0)
4465423Swnj 		gsignal(so->so_pgrp, SIGURG);
4475429Swnj 	else {
4485429Swnj 		struct proc *p = pfind(-so->so_pgrp);
4495429Swnj 
4505429Swnj 		if (p)
4515429Swnj 			psignal(p, SIGURG);
4525429Swnj 	}
4535423Swnj }
4545423Swnj 
4554916Swnj /*ARGSUSED*/
4564916Swnj soioctl(so, cmd, cmdp)
4574829Swnj 	register struct socket *so;
4584829Swnj 	int cmd;
4594829Swnj 	register caddr_t cmdp;
4604786Swnj {
4614786Swnj 
4624927Swnj COUNT(SOIOCTL);
4635358Sroot 	switch (cmd) {
4644829Swnj 
4655388Sroot 	case FIONBIO: {
4665388Sroot 		int nbio;
4675388Sroot 		if (copyin(cmdp, (caddr_t)&nbio, sizeof (nbio))) {
4685388Sroot 			u.u_error = EFAULT;
4695388Sroot 			return;
4705388Sroot 		}
4715388Sroot 		if (nbio)
4726214Swnj 			so->so_state |= SS_NBIO;
4735388Sroot 		else
4746214Swnj 			so->so_state &= ~SS_NBIO;
4755388Sroot 		return;
4765388Sroot 	}
4775388Sroot 
4785388Sroot 	case FIOASYNC: {
4795388Sroot 		int async;
4805388Sroot 		if (copyin(cmdp, (caddr_t)&async, sizeof (async))) {
4815388Sroot 			u.u_error = EFAULT;
4825388Sroot 			return;
4835388Sroot 		}
4845388Sroot 		if (async)
4856214Swnj 			so->so_state |= SS_ASYNC;
4865388Sroot 		else
4876214Swnj 			so->so_state &= ~SS_ASYNC;
4885388Sroot 		return;
4895388Sroot 	}
4905388Sroot 
4915388Sroot 	case SIOCSKEEP: {
4925388Sroot 		int keep;
4935388Sroot 		if (copyin(cmdp, (caddr_t)&keep, sizeof (keep))) {
4945388Sroot 			u.u_error = EFAULT;
4955388Sroot 			return;
4965388Sroot 		}
4975388Sroot 		if (keep)
4986214Swnj 			so->so_options &= ~SO_KEEPALIVE;
4995388Sroot 		else
5006214Swnj 			so->so_options |= SO_KEEPALIVE;
5015388Sroot 		return;
5025388Sroot 	}
5035388Sroot 
5045388Sroot 	case SIOCGKEEP: {
5056214Swnj 		int keep = (so->so_options & SO_KEEPALIVE) != 0;
5065388Sroot 		if (copyout((caddr_t)&keep, cmdp, sizeof (keep)))
5075388Sroot 			u.u_error = EFAULT;
5085388Sroot 		return;
5095388Sroot 	}
5105388Sroot 
5115388Sroot 	case SIOCSLINGER: {
5125388Sroot 		int linger;
5135388Sroot 		if (copyin(cmdp, (caddr_t)&linger, sizeof (linger))) {
5145388Sroot 			u.u_error = EFAULT;
5155388Sroot 			return;
5165388Sroot 		}
5175388Sroot 		so->so_linger = linger;
5185388Sroot 		if (so->so_linger)
5195388Sroot 			so->so_options &= ~SO_DONTLINGER;
5205388Sroot 		else
5215388Sroot 			so->so_options |= SO_DONTLINGER;
5225388Sroot 		return;
5235388Sroot 	}
5245388Sroot 
5255388Sroot 	case SIOCGLINGER: {
5265388Sroot 		int linger = so->so_linger;
5275388Sroot 		if (copyout((caddr_t)&linger, cmdp, sizeof (linger))) {
5285388Sroot 			u.u_error = EFAULT;
5295388Sroot 			return;
5305388Sroot 		}
5315388Sroot 	}
5325423Swnj 	case SIOCSPGRP: {
5335423Swnj 		int pgrp;
5345423Swnj 		if (copyin(cmdp, (caddr_t)&pgrp, sizeof (pgrp))) {
5355423Swnj 			u.u_error = EFAULT;
5365423Swnj 			return;
5375423Swnj 		}
5385423Swnj 		so->so_pgrp = pgrp;
5395423Swnj 		return;
5405423Swnj 	}
5415388Sroot 
5425423Swnj 	case SIOCGPGRP: {
5435423Swnj 		int pgrp = so->so_pgrp;
5445423Swnj 		if (copyout((caddr_t)&pgrp, cmdp, sizeof (pgrp))) {
5455423Swnj 			u.u_error = EFAULT;
5465423Swnj 			return;
5475423Swnj 		}
5485423Swnj 	}
5495423Swnj 
5505281Sroot 	case SIOCDONE: {
5515281Sroot 		int flags;
5525281Sroot 		if (copyin(cmdp, (caddr_t)&flags, sizeof (flags))) {
5535281Sroot 			u.u_error = EFAULT;
5545281Sroot 			return;
5555281Sroot 		}
5565388Sroot 		flags++;
5575281Sroot 		if (flags & FREAD) {
5585281Sroot 			int s = splimp();
5595281Sroot 			socantrcvmore(so);
5605281Sroot 			sbflush(&so->so_rcv);
5616140Ssam 			splx(s);
5625281Sroot 		}
5635281Sroot 		if (flags & FWRITE)
5645404Swnj 			u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, (struct mbuf *)0, 0);
5655281Sroot 		return;
5664829Swnj 	}
5675281Sroot 
5685423Swnj 	case SIOCSENDOOB: {
5695423Swnj 		char oob;
5705423Swnj 		struct mbuf *m;
5715423Swnj 		if (copyin(cmdp, (caddr_t)&oob, sizeof (oob))) {
5725423Swnj 			u.u_error = EFAULT;
5735423Swnj 			return;
5745423Swnj 		}
5755423Swnj 		m = m_get(M_DONTWAIT);
5765423Swnj 		if (m == 0) {
5775423Swnj 			u.u_error = ENOBUFS;
5785423Swnj 			return;
5795423Swnj 		}
5805423Swnj 		m->m_off = MMINOFF;
5815423Swnj 		m->m_len = 1;
5825423Swnj 		*mtod(m, caddr_t) = oob;
5835423Swnj 		(*so->so_proto->pr_usrreq)(so, PRU_SENDOOB, m, 0);
5845423Swnj 		return;
5855281Sroot 	}
5865423Swnj 
5875423Swnj 	case SIOCRCVOOB: {
5885423Swnj 		struct mbuf *m = m_get(M_DONTWAIT);
5895423Swnj 		if (m == 0) {
5905423Swnj 			u.u_error = ENOBUFS;
5915423Swnj 			return;
5925423Swnj 		}
5935423Swnj 		m->m_off = MMINOFF; *mtod(m, caddr_t) = 0;
5945423Swnj 		(*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, m, 0);
5955423Swnj 		if (copyout(mtod(m, caddr_t), cmdp, sizeof (char))) {
5965423Swnj 			u.u_error = EFAULT;
5975423Swnj 			return;
5985423Swnj 		}
5995423Swnj 		m_free(m);
6005423Swnj 		return;
6015423Swnj 	}
6025423Swnj 
6035423Swnj 	case SIOCATMARK: {
6045423Swnj 		int atmark = (so->so_state&SS_RCVATMARK) != 0;
6055423Swnj 		if (copyout((caddr_t)&atmark, cmdp, sizeof (atmark))) {
6065423Swnj 			u.u_error = EFAULT;
6075423Swnj 			return;
6085423Swnj 		}
6095423Swnj 		return;
6105423Swnj 	}
6116355Ssam 
6126355Ssam 	/* routing table update calls */
6136355Ssam 	case SIOCADDRT:
6146355Ssam 	case SIOCDELRT:
6156355Ssam 	case SIOCCHGRT: {
6166355Ssam 		struct rtentry route;
6176355Ssam #ifdef notdef
6186355Ssam 		if (!suser())
6196355Ssam 			return;
6206355Ssam #endif
6216355Ssam 		if (copyin(cmdp, (caddr_t)&route, sizeof (route))) {
6226355Ssam 			u.u_error = EFAULT;
6236355Ssam 			return;
6246355Ssam 		}
6256355Ssam 		u.u_error = rtrequest(cmd, &route);
6266355Ssam 		return;
6276355Ssam 	}
6286355Ssam 
6295445Swnj 	/* type/protocol specific ioctls */
6305423Swnj 	}
6315445Swnj 	u.u_error = EOPNOTSUPP;
6324786Swnj }
633