xref: /csrg-svn/sys/kern/uipc_socket.c (revision 6259)
1*6259Sroot /*	uipc_socket.c	4.35	82/03/19	*/
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"
194786Swnj 
204786Swnj /*
214890Swnj  * Socket support routines.
224890Swnj  *
234890Swnj  * DEAL WITH INTERRUPT NOTIFICATION.
244786Swnj  */
254786Swnj 
264786Swnj /*
274786Swnj  * Create a socket.
284786Swnj  */
294927Swnj socreate(aso, type, asp, asa, options)
304786Swnj 	struct socket **aso;
314786Swnj 	int type;
324927Swnj 	struct sockproto *asp;
334927Swnj 	struct sockaddr *asa;
344829Swnj 	int options;
354786Swnj {
364786Swnj 	register struct protosw *prp;
374786Swnj 	register struct socket *so;
384786Swnj 	struct mbuf *m;
394890Swnj 	int pf, proto, error;
404927Swnj COUNT(SOCREATE);
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;
736214Swnj 	so->so_state = 0;
746214Swnj 	if (u.u_uid == 0)
756214Swnj 		so->so_state = SS_PRIV;
764786Swnj 
774786Swnj 	/*
784890Swnj 	 * Attach protocol to socket, initializing
794890Swnj 	 * and reserving resources.
804786Swnj 	 */
814786Swnj 	so->so_proto = prp;
824979Swnj 	error = (*prp->pr_usrreq)(so, PRU_ATTACH, 0, asa);
834979Swnj 	if (error) {
844971Swnj 		(void) m_free(dtom(so));
854890Swnj 		return (error);
864786Swnj 	}
874786Swnj 	*aso = so;
884786Swnj 	return (0);
894786Swnj }
904786Swnj 
914916Swnj sofree(so)
924916Swnj 	struct socket *so;
934916Swnj {
944916Swnj 
954927Swnj COUNT(SOFREE);
964950Swnj 	if (so->so_pcb || (so->so_state & SS_USERGONE) == 0)
974950Swnj 		return;
984950Swnj 	sbrelease(&so->so_snd);
994950Swnj 	sbrelease(&so->so_rcv);
1004971Swnj 	(void) m_free(dtom(so));
1014916Swnj }
1024916Swnj 
1034786Swnj /*
1044890Swnj  * Close a socket on last file table reference removal.
1054890Swnj  * Initiate disconnect if connected.
1064890Swnj  * Free socket when disconnect complete.
1075580Sroot  *
1085580Sroot  * THIS IS REALLY A UNIX INTERFACE ROUTINE
1094829Swnj  */
1105580Sroot soclose(so, exiting)
1114829Swnj 	register struct socket *so;
1125580Sroot 	int exiting;
1134829Swnj {
1144890Swnj 	int s = splnet();		/* conservative */
1154829Swnj 
1164927Swnj COUNT(SOCLOSE);
1174890Swnj 	if (so->so_pcb == 0)
1184890Swnj 		goto discard;
119*6259Sroot 	if (exiting)
120*6259Sroot 		so->so_options |= SO_KEEPALIVE;
1214890Swnj 	if (so->so_state & SS_ISCONNECTED) {
1224890Swnj 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
1234927Swnj 			u.u_error = sodisconnect(so, (struct sockaddr *)0);
1244890Swnj 			if (u.u_error) {
1255580Sroot 				if (exiting)
1265580Sroot 					goto drop;
1274890Swnj 				splx(s);
1284890Swnj 				return;
1294890Swnj 			}
1304890Swnj 		}
1315388Sroot 		if ((so->so_options & SO_DONTLINGER) == 0) {
1325281Sroot 			if ((so->so_state & SS_ISDISCONNECTING) &&
1336214Swnj 			    (so->so_state & SS_NBIO) &&
1345580Sroot 			    exiting == 0) {
1355281Sroot 				u.u_error = EINPROGRESS;
1365281Sroot 				splx(s);
1375281Sroot 				return;
1385281Sroot 			}
1395580Sroot 			/* should use tsleep here, for at most linger */
1405281Sroot 			while (so->so_state & SS_ISCONNECTED)
1415281Sroot 				sleep((caddr_t)&so->so_timeo, PZERO+1);
1424890Swnj 		}
1434890Swnj 	}
1445580Sroot drop:
1454890Swnj 	u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0);
1464890Swnj discard:
1474950Swnj 	so->so_state |= SS_USERGONE;
1484950Swnj 	sofree(so);
1494890Swnj 	splx(s);
1504829Swnj }
1514829Swnj 
1524927Swnj sosplice(pso, so)
1534927Swnj 	struct socket *pso, *so;
1544927Swnj {
1554927Swnj 
1564927Swnj COUNT(SOSPLICE);
1575168Swnj 	if (pso->so_proto->pr_family != PF_UNIX) {
1584927Swnj 		struct socket *tso;
1594927Swnj 		tso = pso; pso = so; so = tso;
1604927Swnj 	}
1615168Swnj 	if (pso->so_proto->pr_family != PF_UNIX)
1624927Swnj 		return (EOPNOTSUPP);
1634927Swnj 	/* check types and buffer space */
1644927Swnj 	/* merge buffers */
1654927Swnj 	return (0);
1664927Swnj }
1674927Swnj 
1684916Swnj /*ARGSUSED*/
1694890Swnj sostat(so, sb)
1704829Swnj 	struct socket *so;
1714890Swnj 	struct stat *sb;
1724829Swnj {
1734829Swnj 
1744927Swnj COUNT(SOSTAT);
1755303Sroot 	bzero((caddr_t)sb, sizeof (*sb));		/* XXX */
1765303Sroot 	return (0);					/* XXX */
1774829Swnj }
1784829Swnj 
1794829Swnj /*
1804927Swnj  * Accept connection on a socket.
1814927Swnj  */
1824927Swnj soaccept(so, asa)
1834927Swnj 	struct socket *so;
1844927Swnj 	struct sockaddr *asa;
1854927Swnj {
1864927Swnj 	int s = splnet();
1874927Swnj 	int error;
1884927Swnj 
1894927Swnj COUNT(SOACCEPT);
1904927Swnj 	if ((so->so_options & SO_ACCEPTCONN) == 0) {
1914927Swnj 		error = EINVAL;			/* XXX */
1924927Swnj 		goto bad;
1934927Swnj 	}
1945265Swnj 	if ((so->so_state & SS_CONNAWAITING) == 0) {
1955265Swnj 		error = ENOTCONN;
1965265Swnj 		goto bad;
1975265Swnj 	}
1985265Swnj 	so->so_state &= ~SS_CONNAWAITING;
1994927Swnj 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa);
2004927Swnj bad:
2014927Swnj 	splx(s);
2024927Swnj 	return (error);
2034927Swnj }
2044927Swnj 
2054927Swnj /*
2064890Swnj  * Connect socket to a specified address.
2074890Swnj  * If already connected or connecting, then avoid
2084890Swnj  * the protocol entry, to keep its job simpler.
2094786Swnj  */
2104927Swnj soconnect(so, asa)
2114786Swnj 	struct socket *so;
2124927Swnj 	struct sockaddr *asa;
2134786Swnj {
2144890Swnj 	int s = splnet();
2154890Swnj 	int error;
2164786Swnj 
2174927Swnj COUNT(SOCONNECT);
2184890Swnj 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
2194890Swnj 		error = EISCONN;
2204890Swnj 		goto bad;
2214890Swnj 	}
2224927Swnj 	error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa);
2234890Swnj bad:
2244890Swnj 	splx(s);
2254890Swnj 	return (error);
2264786Swnj }
2274786Swnj 
2284786Swnj /*
2294890Swnj  * Disconnect from a socket.
2304890Swnj  * Address parameter is from system call for later multicast
2314890Swnj  * protocols.  Check to make sure that connected and no disconnect
2324890Swnj  * in progress (for protocol's sake), and then invoke protocol.
2334786Swnj  */
2344927Swnj sodisconnect(so, asa)
2354786Swnj 	struct socket *so;
2364927Swnj 	struct sockaddr *asa;
2374786Swnj {
2384890Swnj 	int s = splnet();
2394890Swnj 	int error;
2404786Swnj 
2414927Swnj COUNT(SODISCONNECT);
2424890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2434890Swnj 		error = ENOTCONN;
2444890Swnj 		goto bad;
2454890Swnj 	}
2464890Swnj 	if (so->so_state & SS_ISDISCONNECTING) {
2474890Swnj 		error = EALREADY;
2484890Swnj 		goto bad;
2494890Swnj 	}
2504927Swnj 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa);
2514890Swnj bad:
2524890Swnj 	splx(s);
2534890Swnj 	return (error);
2544786Swnj }
2554786Swnj 
2564786Swnj /*
2574890Swnj  * Send on a socket.
2584890Swnj  * If send must go all at once and message is larger than
2594890Swnj  * send buffering, then hard error.
2604890Swnj  * Lock against other senders.
2614890Swnj  * If must go all at once and not enough room now, then
2624890Swnj  * inform user that this would block and do nothing.
2634786Swnj  */
2644927Swnj sosend(so, asa)
2654786Swnj 	register struct socket *so;
2664927Swnj 	struct sockaddr *asa;
2674786Swnj {
2684890Swnj 	struct mbuf *top = 0;
2694890Swnj 	register struct mbuf *m, **mp = ⊤
2704916Swnj 	register u_int len;
2714916Swnj 	int error = 0, space, s;
2724786Swnj 
2734927Swnj COUNT(SOSEND);
2745950Swnj 	if (so->so_state & SS_CANTSENDMORE) {
2755950Swnj 		psignal(u.u_procp, SIGPIPE);
2764890Swnj 		return (EPIPE);
2775950Swnj 	}
2784890Swnj 	if (sosendallatonce(so) && u.u_count > so->so_snd.sb_hiwat)
2794890Swnj 		return (EMSGSIZE);
2806214Swnj 	if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_state & SS_NBIO))
2814890Swnj 		return (EWOULDBLOCK);
2824890Swnj 	sblock(&so->so_snd);
2834890Swnj #define	snderr(errno)	{ error = errno; splx(s); goto release; }
2844890Swnj 
2854890Swnj 	s = splnet();
2864890Swnj again:
2875168Swnj 	if (so->so_error) {
2885168Swnj 		error = so->so_error;
2895168Swnj 		so->so_error = 0;
2905168Swnj 		splx(s);
2915168Swnj 		goto release;
2925168Swnj 	}
2934890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2944890Swnj 		if (so->so_proto->pr_flags & PR_CONNREQUIRED)
2954890Swnj 			snderr(ENOTCONN);
2964927Swnj 		if (asa == 0)
2974890Swnj 			snderr(EDESTADDRREQ);
2984890Swnj 	}
2994890Swnj 	if (top) {
3004927Swnj 		error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa);
3014890Swnj 		if (error) {
3024890Swnj 			splx(s);
3034786Swnj 			goto release;
3044786Swnj 		}
3054890Swnj 		top = 0;
3064890Swnj 		mp = ⊤
3074786Swnj 	}
3084979Swnj 	if (u.u_count == 0) {
3094979Swnj 		splx(s);
3104979Swnj 		goto release;
3114979Swnj 	}
3125018Swnj 	space = sbspace(&so->so_snd);
3135610Swnj 	if (space <= 0 || sosendallatonce(so) && space < u.u_count) {
3146214Swnj 		if (so->so_state & SS_NBIO)
3154890Swnj 			snderr(EWOULDBLOCK);
3164890Swnj 		sbunlock(&so->so_snd);
3174890Swnj 		sbwait(&so->so_snd);
3184890Swnj 		splx(s);
3194786Swnj 		goto again;
3204786Swnj 	}
3214890Swnj 	splx(s);
3225018Swnj 	while (u.u_count && space > 0) {
3234890Swnj 		MGET(m, 1);
3244890Swnj 		if (m == NULL) {
3254890Swnj 			error = ENOBUFS;
3264890Swnj 			m_freem(top);
3274890Swnj 			goto release;
3284786Swnj 		}
3295095Swnj 		if (u.u_count >= CLBYTES && space >= CLBYTES) {
3304890Swnj 			register struct mbuf *p;
3315095Swnj 			MCLGET(p, 1);
3324890Swnj 			if (p == 0)
3334890Swnj 				goto nopages;
3344890Swnj 			m->m_off = (int)p - (int)m;
3355095Swnj 			len = CLBYTES;
3364890Swnj 		} else {
3374786Swnj nopages:
3384890Swnj 			m->m_off = MMINOFF;
3394890Swnj 			len = MIN(MLEN, u.u_count);
3404786Swnj 		}
3414890Swnj 		iomove(mtod(m, caddr_t), len, B_WRITE);
3424890Swnj 		m->m_len = len;
3434890Swnj 		*mp = m;
3444890Swnj 		mp = &m->m_next;
3455018Swnj 		space = sbspace(&so->so_snd);
3464786Swnj 	}
3474890Swnj 	s = splnet();
3484890Swnj 	goto again;
3494890Swnj 
3504786Swnj release:
3514890Swnj 	sbunlock(&so->so_snd);
3524786Swnj 	return (error);
3534786Swnj }
3544786Swnj 
3554927Swnj soreceive(so, asa)
3564786Swnj 	register struct socket *so;
3574927Swnj 	struct sockaddr *asa;
3584786Swnj {
3594786Swnj 	register struct mbuf *m, *n;
3604916Swnj 	u_int len;
3615423Swnj 	int eor, s, error = 0, cnt = u.u_count;
3625423Swnj 	caddr_t base = u.u_base;
3634786Swnj 
3644927Swnj COUNT(SORECEIVE);
3654890Swnj restart:
3664890Swnj 	sblock(&so->so_rcv);
3674890Swnj 	s = splnet();
3684890Swnj 
3694890Swnj #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
3704786Swnj 	if (so->so_rcv.sb_cc == 0) {
3715168Swnj 		if (so->so_error) {
3725168Swnj 			error = so->so_error;
3735168Swnj 			so->so_error = 0;
3745168Swnj 			splx(s);
3755168Swnj 			goto release;
3765168Swnj 		}
3774890Swnj 		if (so->so_state & SS_CANTRCVMORE) {
3784890Swnj 			splx(s);
3794890Swnj 			goto release;
3804890Swnj 		}
3815015Sroot 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
3825015Sroot 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
3835015Sroot 			rcverr(ENOTCONN);
3846214Swnj 		if (so->so_state & SS_NBIO)
3855168Swnj 			rcverr(EWOULDBLOCK);
3864890Swnj 		sbunlock(&so->so_rcv);
3874971Swnj 		sbwait(&so->so_rcv);
3885012Swnj 		splx(s);
3894890Swnj 		goto restart;
3904786Swnj 	}
3914829Swnj 	m = so->so_rcv.sb_mb;
3924786Swnj 	if (m == 0)
3934786Swnj 		panic("receive");
3945039Swnj 	if (so->so_proto->pr_flags & PR_ADDR) {
3955039Swnj 		if (m->m_len != sizeof (struct sockaddr))
3965039Swnj 			panic("soreceive addr");
3975039Swnj 		if (asa)
3985039Swnj 			bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa));
3995039Swnj 		so->so_rcv.sb_cc -= m->m_len;
4005039Swnj 		so->so_rcv.sb_mbcnt -= MSIZE;
4015018Swnj 		m = m_free(m);
4024890Swnj 		if (m == 0)
4034890Swnj 			panic("receive 2");
4045018Swnj 		so->so_rcv.sb_mb = m;
4054890Swnj 	}
4065423Swnj 	so->so_state &= ~SS_RCVATMARK;
4075423Swnj 	if (so->so_oobmark && cnt > so->so_oobmark)
4085423Swnj 		cnt = so->so_oobmark;
4094786Swnj 	eor = 0;
4104786Swnj 	do {
4115423Swnj 		len = MIN(m->m_len, cnt);
4124786Swnj 		splx(s);
4134786Swnj 		iomove(mtod(m, caddr_t), len, B_READ);
4145423Swnj 		cnt -= len;
4154786Swnj 		s = splnet();
4164786Swnj 		if (len == m->m_len) {
4176091Sroot 			eor = (int)m->m_act;
4186091Sroot 			sbfree(&so->so_rcv, m);
4196091Sroot 			so->so_rcv.sb_mb = m->m_next;
4204786Swnj 			MFREE(m, n);
4214786Swnj 		} else {
4224786Swnj 			m->m_off += len;
4234786Swnj 			m->m_len -= len;
4244829Swnj 			so->so_rcv.sb_cc -= len;
4254786Swnj 		}
4265423Swnj 	} while ((m = so->so_rcv.sb_mb) && cnt && !eor);
4274786Swnj 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
4284786Swnj 		do {
4294786Swnj 			if (m == 0)
4304890Swnj 				panic("receive 3");
4314890Swnj 			sbfree(&so->so_rcv, m);
4324786Swnj 			eor = (int)m->m_act;
4334786Swnj 			so->so_rcv.sb_mb = m->m_next;
4344786Swnj 			MFREE(m, n);
4354890Swnj 			m = n;
4364786Swnj 		} while (eor == 0);
4374890Swnj 	if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
4384890Swnj 		(*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0);
4395423Swnj 	if (so->so_oobmark) {
4405423Swnj 		so->so_oobmark -= u.u_base - base;
4415423Swnj 		if (so->so_oobmark == 0)
4425423Swnj 			so->so_state |= SS_RCVATMARK;
4435423Swnj 	}
4444890Swnj release:
4454916Swnj 	sbunlock(&so->so_rcv);
4464890Swnj 	splx(s);
4474916Swnj 	return (error);
4484786Swnj }
4494786Swnj 
4505423Swnj sohasoutofband(so)
4515423Swnj 	struct socket *so;
4525423Swnj {
4535423Swnj 
4545423Swnj 	if (so->so_pgrp == 0)
4555423Swnj 		return;
4565423Swnj 	if (so->so_pgrp > 0)
4575423Swnj 		gsignal(so->so_pgrp, SIGURG);
4585429Swnj 	else {
4595429Swnj 		struct proc *p = pfind(-so->so_pgrp);
4605429Swnj 
4615429Swnj 		if (p)
4625429Swnj 			psignal(p, SIGURG);
4635429Swnj 	}
4645423Swnj }
4655423Swnj 
4664916Swnj /*ARGSUSED*/
4674916Swnj soioctl(so, cmd, cmdp)
4684829Swnj 	register struct socket *so;
4694829Swnj 	int cmd;
4704829Swnj 	register caddr_t cmdp;
4714786Swnj {
4724786Swnj 
4734927Swnj COUNT(SOIOCTL);
4745358Sroot 	switch (cmd) {
4754829Swnj 
4765388Sroot 	case FIONBIO: {
4775388Sroot 		int nbio;
4785388Sroot 		if (copyin(cmdp, (caddr_t)&nbio, sizeof (nbio))) {
4795388Sroot 			u.u_error = EFAULT;
4805388Sroot 			return;
4815388Sroot 		}
4825388Sroot 		if (nbio)
4836214Swnj 			so->so_state |= SS_NBIO;
4845388Sroot 		else
4856214Swnj 			so->so_state &= ~SS_NBIO;
4865388Sroot 		return;
4875388Sroot 	}
4885388Sroot 
4895388Sroot 	case FIOASYNC: {
4905388Sroot 		int async;
4915388Sroot 		if (copyin(cmdp, (caddr_t)&async, sizeof (async))) {
4925388Sroot 			u.u_error = EFAULT;
4935388Sroot 			return;
4945388Sroot 		}
4955388Sroot 		if (async)
4966214Swnj 			so->so_state |= SS_ASYNC;
4975388Sroot 		else
4986214Swnj 			so->so_state &= ~SS_ASYNC;
4995388Sroot 		return;
5005388Sroot 	}
5015388Sroot 
5025388Sroot 	case SIOCSKEEP: {
5035388Sroot 		int keep;
5045388Sroot 		if (copyin(cmdp, (caddr_t)&keep, sizeof (keep))) {
5055388Sroot 			u.u_error = EFAULT;
5065388Sroot 			return;
5075388Sroot 		}
5085388Sroot 		if (keep)
5096214Swnj 			so->so_options &= ~SO_KEEPALIVE;
5105388Sroot 		else
5116214Swnj 			so->so_options |= SO_KEEPALIVE;
5125388Sroot 		return;
5135388Sroot 	}
5145388Sroot 
5155388Sroot 	case SIOCGKEEP: {
5166214Swnj 		int keep = (so->so_options & SO_KEEPALIVE) != 0;
5175388Sroot 		if (copyout((caddr_t)&keep, cmdp, sizeof (keep)))
5185388Sroot 			u.u_error = EFAULT;
5195388Sroot 		return;
5205388Sroot 	}
5215388Sroot 
5225388Sroot 	case SIOCSLINGER: {
5235388Sroot 		int linger;
5245388Sroot 		if (copyin(cmdp, (caddr_t)&linger, sizeof (linger))) {
5255388Sroot 			u.u_error = EFAULT;
5265388Sroot 			return;
5275388Sroot 		}
5285388Sroot 		so->so_linger = linger;
5295388Sroot 		if (so->so_linger)
5305388Sroot 			so->so_options &= ~SO_DONTLINGER;
5315388Sroot 		else
5325388Sroot 			so->so_options |= SO_DONTLINGER;
5335388Sroot 		return;
5345388Sroot 	}
5355388Sroot 
5365388Sroot 	case SIOCGLINGER: {
5375388Sroot 		int linger = so->so_linger;
5385388Sroot 		if (copyout((caddr_t)&linger, cmdp, sizeof (linger))) {
5395388Sroot 			u.u_error = EFAULT;
5405388Sroot 			return;
5415388Sroot 		}
5425388Sroot 	}
5435423Swnj 	case SIOCSPGRP: {
5445423Swnj 		int pgrp;
5455423Swnj 		if (copyin(cmdp, (caddr_t)&pgrp, sizeof (pgrp))) {
5465423Swnj 			u.u_error = EFAULT;
5475423Swnj 			return;
5485423Swnj 		}
5495423Swnj 		so->so_pgrp = pgrp;
5505423Swnj 		return;
5515423Swnj 	}
5525388Sroot 
5535423Swnj 	case SIOCGPGRP: {
5545423Swnj 		int pgrp = so->so_pgrp;
5555423Swnj 		if (copyout((caddr_t)&pgrp, cmdp, sizeof (pgrp))) {
5565423Swnj 			u.u_error = EFAULT;
5575423Swnj 			return;
5585423Swnj 		}
5595423Swnj 	}
5605423Swnj 
5615281Sroot 	case SIOCDONE: {
5625281Sroot 		int flags;
5635281Sroot 		if (copyin(cmdp, (caddr_t)&flags, sizeof (flags))) {
5645281Sroot 			u.u_error = EFAULT;
5655281Sroot 			return;
5665281Sroot 		}
5675388Sroot 		flags++;
5685281Sroot 		if (flags & FREAD) {
5695281Sroot 			int s = splimp();
5705281Sroot 			socantrcvmore(so);
5715281Sroot 			sbflush(&so->so_rcv);
5726140Ssam 			splx(s);
5735281Sroot 		}
5745281Sroot 		if (flags & FWRITE)
5755404Swnj 			u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, (struct mbuf *)0, 0);
5765281Sroot 		return;
5774829Swnj 	}
5785281Sroot 
5795423Swnj 	case SIOCSENDOOB: {
5805423Swnj 		char oob;
5815423Swnj 		struct mbuf *m;
5825423Swnj 		if (copyin(cmdp, (caddr_t)&oob, sizeof (oob))) {
5835423Swnj 			u.u_error = EFAULT;
5845423Swnj 			return;
5855423Swnj 		}
5865423Swnj 		m = m_get(M_DONTWAIT);
5875423Swnj 		if (m == 0) {
5885423Swnj 			u.u_error = ENOBUFS;
5895423Swnj 			return;
5905423Swnj 		}
5915423Swnj 		m->m_off = MMINOFF;
5925423Swnj 		m->m_len = 1;
5935423Swnj 		*mtod(m, caddr_t) = oob;
5945423Swnj 		(*so->so_proto->pr_usrreq)(so, PRU_SENDOOB, m, 0);
5955423Swnj 		return;
5965281Sroot 	}
5975423Swnj 
5985423Swnj 	case SIOCRCVOOB: {
5995423Swnj 		struct mbuf *m = m_get(M_DONTWAIT);
6005423Swnj 		if (m == 0) {
6015423Swnj 			u.u_error = ENOBUFS;
6025423Swnj 			return;
6035423Swnj 		}
6045423Swnj 		m->m_off = MMINOFF; *mtod(m, caddr_t) = 0;
6055423Swnj 		(*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, m, 0);
6065423Swnj 		if (copyout(mtod(m, caddr_t), cmdp, sizeof (char))) {
6075423Swnj 			u.u_error = EFAULT;
6085423Swnj 			return;
6095423Swnj 		}
6105423Swnj 		m_free(m);
6115423Swnj 		return;
6125423Swnj 	}
6135423Swnj 
6145423Swnj 	case SIOCATMARK: {
6155423Swnj 		int atmark = (so->so_state&SS_RCVATMARK) != 0;
6165423Swnj 		if (copyout((caddr_t)&atmark, cmdp, sizeof (atmark))) {
6175423Swnj 			u.u_error = EFAULT;
6185423Swnj 			return;
6195423Swnj 		}
6205423Swnj 		return;
6215423Swnj 	}
6225445Swnj 	/* type/protocol specific ioctls */
6235423Swnj 	}
6245445Swnj 	u.u_error = EOPNOTSUPP;
6254786Swnj }
626