xref: /csrg-svn/sys/kern/uipc_socket.c (revision 10137)
1*10137Ssam /*	uipc_socket.c	4.67	83/01/04	*/
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"
178391Swnj #include "../h/uio.h"
186355Ssam #include "../net/route.h"
194786Swnj 
204786Swnj /*
218300Sroot  * Socket operation routines.
228300Sroot  * These routines are called by the routines in
238300Sroot  * sys_socket.c or from a system process, and
248300Sroot  * implement the semantics of socket operations by
258300Sroot  * switching out to the protocol specific routines.
264786Swnj  */
274786Swnj 
288594Sroot /*ARGSUSED*/
298300Sroot socreate(dom, aso, type, proto, opt)
304786Swnj 	struct socket **aso;
318300Sroot 	int type, proto;
328300Sroot 	struct socketopt *opt;
334786Swnj {
344786Swnj 	register struct protosw *prp;
354786Swnj 	register struct socket *so;
364786Swnj 	struct mbuf *m;
379168Ssam 	int error;
384786Swnj 
394890Swnj 	if (proto)
409168Ssam 		prp = pffindproto(dom, proto);
414890Swnj 	else
429168Ssam 		prp = pffindtype(dom, type);
434890Swnj 	if (prp == 0)
444890Swnj 		return (EPROTONOSUPPORT);
458300Sroot 	if (prp->pr_type != type)
468300Sroot 		return (EPROTOTYPE);
479635Ssam 	m = m_getclr(M_WAIT, MT_SOCKET);
484786Swnj 	if (m == 0)
494786Swnj 		return (ENOBUFS);
504786Swnj 	so = mtod(m, struct socket *);
518300Sroot 	so->so_options = 0;
526214Swnj 	so->so_state = 0;
539168Ssam 	so->so_type = type;
546214Swnj 	if (u.u_uid == 0)
556214Swnj 		so->so_state = SS_PRIV;
564786Swnj 	so->so_proto = prp;
578300Sroot 	error = (*prp->pr_usrreq)(so, PRU_ATTACH,
58*10137Ssam 	    (struct mbuf *)0, (struct mbuf *)0, opt);
594979Swnj 	if (error) {
607507Sroot 		so->so_state |= SS_NOFDREF;
617180Swnj 		sofree(so);
624890Swnj 		return (error);
634786Swnj 	}
644786Swnj 	*aso = so;
654786Swnj 	return (0);
664786Swnj }
674786Swnj 
688300Sroot sobind(so, nam, opt)
698300Sroot 	struct socket *so;
708300Sroot 	struct mbuf *nam;
718300Sroot 	struct socketopt *opt;
728300Sroot {
738300Sroot 	int s = splnet();
748300Sroot 	int error;
758300Sroot 
768300Sroot 	error =
778300Sroot 	    (*so->so_proto->pr_usrreq)(so, PRU_BIND,
788300Sroot 		(struct mbuf *)0, nam, opt);
798300Sroot 	splx(s);
808300Sroot 	return (error);
818300Sroot }
828300Sroot 
838300Sroot solisten(so, backlog)
848300Sroot 	struct socket *so;
858300Sroot 	int backlog;
868300Sroot {
878300Sroot 	int s = splnet();
888300Sroot 	int error;
898300Sroot 
908300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_LISTEN,
918300Sroot 	    (struct mbuf *)0, (struct mbuf *)0, (struct socketopt *)0);
928300Sroot 	if (error) {
938300Sroot 		splx(s);
948300Sroot 		return (error);
958300Sroot 	}
968300Sroot 	if (so->so_q == 0) {
978300Sroot 		so->so_q = so;
988300Sroot 		so->so_q0 = so;
998300Sroot 		so->so_options |= SO_ACCEPTCONN;
1008300Sroot 	}
1018300Sroot 	if (backlog < 0)
1028300Sroot 		backlog = 0;
103*10137Ssam #define	SOMAXCONN	5
104*10137Ssam 	so->so_qlimit = MIN(backlog, SOMAXCONN);
1058300Sroot 	so->so_options |= SO_NEWFDONCONN;
1068300Sroot 	return (0);
1078300Sroot }
1088300Sroot 
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 */
1358713Sroot 	int error;
1364829Swnj 
1377507Sroot 	if (so->so_options & SO_ACCEPTCONN) {
1387507Sroot 		while (so->so_q0 != so)
1398713Sroot 			(void) soclose(so->so_q0, 1);
1407507Sroot 		while (so->so_q != so)
1418713Sroot 			(void) soclose(so->so_q, 1);
1427507Sroot 	}
1434890Swnj 	if (so->so_pcb == 0)
1444890Swnj 		goto discard;
1456259Sroot 	if (exiting)
1466259Sroot 		so->so_options |= SO_KEEPALIVE;
1474890Swnj 	if (so->so_state & SS_ISCONNECTED) {
1484890Swnj 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
1498725Sroot 			error = sodisconnect(so, (struct mbuf *)0);
1508713Sroot 			if (error) {
1515580Sroot 				if (exiting)
1525580Sroot 					goto drop;
1534890Swnj 				splx(s);
1548713Sroot 				return (error);
1554890Swnj 			}
1564890Swnj 		}
1575388Sroot 		if ((so->so_options & SO_DONTLINGER) == 0) {
1585281Sroot 			if ((so->so_state & SS_ISDISCONNECTING) &&
1596214Swnj 			    (so->so_state & SS_NBIO) &&
1608713Sroot 			    exiting == 0)
1618713Sroot 				return (EINPROGRESS);
1625580Sroot 			/* should use tsleep here, for at most linger */
1635281Sroot 			while (so->so_state & SS_ISCONNECTED)
1645281Sroot 				sleep((caddr_t)&so->so_timeo, PZERO+1);
1654890Swnj 		}
1664890Swnj 	}
1675580Sroot drop:
1686880Ssam 	if (so->so_pcb) {
1698713Sroot 		error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH,
1708300Sroot 		    (struct mbuf *)0, (struct mbuf *)0, (struct socketopt *)0);
1718713Sroot 		if (exiting == 0 && error) {
1726880Ssam 			splx(s);
1738713Sroot 			return (error);
1746880Ssam 		}
1756880Ssam 	}
1764890Swnj discard:
1777507Sroot 	so->so_state |= SS_NOFDREF;
1784950Swnj 	sofree(so);
1794890Swnj 	splx(s);
1808713Sroot 	return (0);
1814829Swnj }
1824829Swnj 
1834916Swnj /*ARGSUSED*/
1849026Sroot sostat(so, ub)
1854829Swnj 	struct socket *so;
1869026Sroot 	struct stat *ub;
1874829Swnj {
1889026Sroot 	struct stat sb;
1894829Swnj 
1909026Sroot 	bzero((caddr_t)&sb, sizeof (sb));		/* XXX */
1919168Ssam 	(void) copyout((caddr_t)&sb, (caddr_t)ub, sizeof (sb));/* XXX */
1925303Sroot 	return (0);					/* XXX */
1934829Swnj }
1944829Swnj 
1958300Sroot soaccept(so, nam, opt)
1964927Swnj 	struct socket *so;
1978300Sroot 	struct mbuf *nam;
1988300Sroot 	struct socketopt *opt;
1994927Swnj {
2004927Swnj 	int s = splnet();
2014927Swnj 	int error;
2024927Swnj 
2038300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT,
2048300Sroot 	    (struct mbuf *)0, nam, opt);
2054927Swnj 	splx(s);
2064927Swnj 	return (error);
2074927Swnj }
2084927Swnj 
2098300Sroot soconnect(so, nam, opt)
2104786Swnj 	struct socket *so;
2118300Sroot 	struct mbuf *nam;
2128300Sroot 	struct socketopt *opt;
2134786Swnj {
2144890Swnj 	int s = splnet();
2154890Swnj 	int error;
2164786Swnj 
2174890Swnj 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
2184890Swnj 		error = EISCONN;
2194890Swnj 		goto bad;
2204890Swnj 	}
2218300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
2228300Sroot 	    (struct mbuf *)0, nam, opt);
2234890Swnj bad:
2244890Swnj 	splx(s);
2254890Swnj 	return (error);
2264786Swnj }
2274786Swnj 
2288300Sroot sodisconnect(so, nam)
2294786Swnj 	struct socket *so;
2308300Sroot 	struct mbuf *nam;
2314786Swnj {
2324890Swnj 	int s = splnet();
2334890Swnj 	int error;
2344786Swnj 
2354890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2364890Swnj 		error = ENOTCONN;
2374890Swnj 		goto bad;
2384890Swnj 	}
2394890Swnj 	if (so->so_state & SS_ISDISCONNECTING) {
2404890Swnj 		error = EALREADY;
2414890Swnj 		goto bad;
2424890Swnj 	}
2438300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT,
2448300Sroot 	    (struct mbuf *)0, nam, (struct socketopt *)0);
2454890Swnj bad:
2464890Swnj 	splx(s);
2474890Swnj 	return (error);
2484786Swnj }
2494786Swnj 
2504786Swnj /*
2514890Swnj  * Send on a socket.
2524890Swnj  * If send must go all at once and message is larger than
2534890Swnj  * send buffering, then hard error.
2544890Swnj  * Lock against other senders.
2554890Swnj  * If must go all at once and not enough room now, then
2564890Swnj  * inform user that this would block and do nothing.
2574786Swnj  */
2588319Sroot sosend(so, nam, uio, flags)
2594786Swnj 	register struct socket *so;
2608300Sroot 	struct mbuf *nam;
2617827Sroot 	struct uio *uio;
2628319Sroot 	int flags;
2634786Swnj {
2644890Swnj 	struct mbuf *top = 0;
2654890Swnj 	register struct mbuf *m, **mp = &top;
2668713Sroot 	register int len;
2674916Swnj 	int error = 0, space, s;
2684786Swnj 
2697827Sroot 	if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat)
2704890Swnj 		return (EMSGSIZE);
2716419Sroot restart:
2724890Swnj 	sblock(&so->so_snd);
2734890Swnj #define	snderr(errno)	{ error = errno; splx(s); goto release; }
2744890Swnj 
2758041Sroot 	u.u_ru.ru_msgsnd++;
2766419Sroot again:
2774890Swnj 	s = splnet();
2786419Sroot 	if (so->so_state & SS_CANTSENDMORE) {
2796419Sroot 		psignal(u.u_procp, SIGPIPE);
2806419Sroot 		snderr(EPIPE);
2816419Sroot 	}
2825168Swnj 	if (so->so_error) {
2835168Swnj 		error = so->so_error;
2846419Sroot 		so->so_error = 0;				/* ??? */
2855168Swnj 		splx(s);
2865168Swnj 		goto release;
2875168Swnj 	}
2884890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2894890Swnj 		if (so->so_proto->pr_flags & PR_CONNREQUIRED)
2904890Swnj 			snderr(ENOTCONN);
2918300Sroot 		if (nam == 0)
2924890Swnj 			snderr(EDESTADDRREQ);
2934890Swnj 	}
2944890Swnj 	if (top) {
2958319Sroot 		error = (*so->so_proto->pr_usrreq)(so,
2968319Sroot 		    (flags & SOF_OOB) ? PRU_SENDOOB : PRU_SEND,
2978300Sroot 		    top, (caddr_t)nam, (struct socketopt *)0);
2986419Sroot 		top = 0;
2994890Swnj 		if (error) {
3004890Swnj 			splx(s);
3014786Swnj 			goto release;
3024786Swnj 		}
3034890Swnj 		mp = &top;
3044786Swnj 	}
3057827Sroot 	if (uio->uio_resid == 0) {
3064979Swnj 		splx(s);
3074979Swnj 		goto release;
3084979Swnj 	}
3098319Sroot 	if (flags & SOF_OOB)
3108319Sroot 		space = 1024;
3118319Sroot 	else {
3128319Sroot 		space = sbspace(&so->so_snd);
3138319Sroot 		if (space <= 0 ||
3148319Sroot 		    sosendallatonce(so) && space < uio->uio_resid) {
3158319Sroot 			if (so->so_state & SS_NBIO)
3168319Sroot 				snderr(EWOULDBLOCK);
3178319Sroot 			sbunlock(&so->so_snd);
3188319Sroot 			sbwait(&so->so_snd);
3198319Sroot 			splx(s);
3208319Sroot 			goto restart;
3218319Sroot 		}
3224786Swnj 	}
3234890Swnj 	splx(s);
3247827Sroot 	while (uio->uio_resid > 0 && space > 0) {
3257827Sroot 		register struct iovec *iov = uio->uio_iov;
3267827Sroot 
3277827Sroot 		if (iov->iov_len == 0) {
3287827Sroot 			uio->uio_iov++;
3297827Sroot 			uio->uio_iovcnt--;
3307827Sroot 			if (uio->uio_iovcnt < 0)
3317827Sroot 				panic("sosend");
3327827Sroot 			continue;
3337827Sroot 		}
3349635Ssam 		MGET(m, M_WAIT, MT_DATA);
3354890Swnj 		if (m == NULL) {
3366419Sroot 			error = ENOBUFS;			/* SIGPIPE? */
3374890Swnj 			goto release;
3384786Swnj 		}
3397827Sroot 		if (iov->iov_len >= CLBYTES && space >= CLBYTES) {
3404890Swnj 			register struct mbuf *p;
3415095Swnj 			MCLGET(p, 1);
3424890Swnj 			if (p == 0)
3434890Swnj 				goto nopages;
3444890Swnj 			m->m_off = (int)p - (int)m;
3455095Swnj 			len = CLBYTES;
3464890Swnj 		} else {
3474786Swnj nopages:
3487827Sroot 			len = MIN(MLEN, iov->iov_len);
3494786Swnj 		}
3508771Sroot 		(void) uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio);
3514890Swnj 		m->m_len = len;
3524890Swnj 		*mp = m;
3534890Swnj 		mp = &m->m_next;
3548319Sroot 		if (flags & SOF_OOB)
3558319Sroot 			space -= len;
3568319Sroot 		else
3578319Sroot 			space = sbspace(&so->so_snd);
3584786Swnj 	}
3594890Swnj 	goto again;
3604890Swnj 
3614786Swnj release:
3624890Swnj 	sbunlock(&so->so_snd);
3636419Sroot 	if (top)
3646419Sroot 		m_freem(top);
3654786Swnj 	return (error);
3664786Swnj }
3674786Swnj 
3688319Sroot soreceive(so, aname, uio, flags)
3694786Swnj 	register struct socket *so;
3708300Sroot 	struct mbuf **aname;
3717747Sroot 	struct uio *uio;
3728319Sroot 	int flags;
3734786Swnj {
3744786Swnj 	register struct mbuf *m, *n;
3758713Sroot 	int len;
3768319Sroot 	int eor, s, error = 0, moff, tomark;
3774786Swnj 
3788319Sroot 	if (flags & SOF_OOB) {
3799635Ssam 		m = m_get(M_WAIT, MT_DATA);
380*10137Ssam 		if (m == NULL)
381*10137Ssam 			return (ENOBUFS);
3828594Sroot 		error = (*so->so_proto->pr_usrreq)(so, PRU_RCVOOB,
3838319Sroot 		    m, (struct mbuf *)0, (struct socketopt *)0);
3848594Sroot 		if (error)
385*10137Ssam 			goto bad;
3868319Sroot 		do {
387*10137Ssam 			len = uio->uio_resid;
3888319Sroot 			if (len > m->m_len)
3898319Sroot 				len = m->m_len;
3908594Sroot 			error =
3918793Sroot 			    uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio);
3928319Sroot 			m = m_free(m);
3938594Sroot 		} while (uio->uio_resid && error == 0 && m);
394*10137Ssam bad:
3958319Sroot 		if (m)
3968771Sroot 			m_freem(m);
3978594Sroot 		return (error);
3988319Sroot 	}
3998319Sroot 
4004890Swnj restart:
4014890Swnj 	sblock(&so->so_rcv);
4028835Sroot 	s = splnet();
4034890Swnj 
4044890Swnj #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
4054786Swnj 	if (so->so_rcv.sb_cc == 0) {
4065168Swnj 		if (so->so_error) {
4075168Swnj 			error = so->so_error;
4085168Swnj 			so->so_error = 0;
4095168Swnj 			splx(s);
4105168Swnj 			goto release;
4115168Swnj 		}
4124890Swnj 		if (so->so_state & SS_CANTRCVMORE) {
4134890Swnj 			splx(s);
4144890Swnj 			goto release;
4154890Swnj 		}
4165015Sroot 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
4175015Sroot 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
4185015Sroot 			rcverr(ENOTCONN);
4196214Swnj 		if (so->so_state & SS_NBIO)
4205168Swnj 			rcverr(EWOULDBLOCK);
4214890Swnj 		sbunlock(&so->so_rcv);
4224971Swnj 		sbwait(&so->so_rcv);
4235012Swnj 		splx(s);
4244890Swnj 		goto restart;
4254786Swnj 	}
4268041Sroot 	u.u_ru.ru_msgrcv++;
4274829Swnj 	m = so->so_rcv.sb_mb;
4284786Swnj 	if (m == 0)
4294786Swnj 		panic("receive");
4305039Swnj 	if (so->so_proto->pr_flags & PR_ADDR) {
4318319Sroot 		if ((flags & SOF_PREVIEW) == 0) {
4328319Sroot 			so->so_rcv.sb_cc -= m->m_len;
4338319Sroot 			so->so_rcv.sb_mbcnt -= MSIZE;
4348319Sroot 		}
4358300Sroot 		if (aname) {
436*10137Ssam 			if (flags & SOF_PREVIEW) {
4378319Sroot 				*aname = m_copy(m, 0, m->m_len);
438*10137Ssam 				if (*aname == NULL)
439*10137Ssam 					panic("receive 2");
440*10137Ssam 			} else
4418319Sroot 				*aname = m;
4428300Sroot 			m = m->m_next;
4438300Sroot 			(*aname)->m_next = 0;
4448300Sroot 		} else
4458319Sroot 			if (flags & SOF_PREVIEW)
4468319Sroot 				m = m->m_next;
4478319Sroot 			else
4488319Sroot 				m = m_free(m);
4494890Swnj 		if (m == 0)
450*10137Ssam 			panic("receive 3");
4518548Sroot 		if ((flags & SOF_PREVIEW) == 0)
4528548Sroot 			so->so_rcv.sb_mb = m;
4534890Swnj 	}
4544786Swnj 	eor = 0;
4558319Sroot 	moff = 0;
4568319Sroot 	tomark = so->so_oobmark;
4574786Swnj 	do {
4587827Sroot 		if (uio->uio_resid <= 0)
4597747Sroot 			break;
4607827Sroot 		len = uio->uio_resid;
4617747Sroot 		so->so_state &= ~SS_RCVATMARK;
4628319Sroot 		if (tomark && len > tomark)
4638319Sroot 			len = tomark;
4648548Sroot 		if (moff+len > m->m_len - moff)
4658319Sroot 			len = m->m_len - moff;
4664786Swnj 		splx(s);
4678594Sroot 		error =
4688793Sroot 		    uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio);
4694786Swnj 		s = splnet();
4704786Swnj 		if (len == m->m_len) {
4716091Sroot 			eor = (int)m->m_act;
4728319Sroot 			if (flags & SOF_PREVIEW)
4738319Sroot 				m = m->m_next;
4748319Sroot 			else {
4758319Sroot 				sbfree(&so->so_rcv, m);
4768319Sroot 				MFREE(m, n);
4778319Sroot 				m = n;
4788548Sroot 				so->so_rcv.sb_mb = m;
4798319Sroot 			}
4808319Sroot 			moff = 0;
4814786Swnj 		} else {
4828319Sroot 			if (flags & SOF_PREVIEW)
4838319Sroot 				moff += len;
4848319Sroot 			else {
4858319Sroot 				m->m_off += len;
4868319Sroot 				m->m_len -= len;
4878319Sroot 				so->so_rcv.sb_cc -= len;
4888319Sroot 			}
4894786Swnj 		}
4908319Sroot 		if ((flags & SOF_PREVIEW) == 0 && so->so_oobmark) {
4917747Sroot 			so->so_oobmark -= len;
4927747Sroot 			if (so->so_oobmark == 0) {
4937747Sroot 				so->so_state |= SS_RCVATMARK;
4947747Sroot 				break;
4957747Sroot 			}
4967747Sroot 		}
4978319Sroot 		if (tomark) {
4988319Sroot 			tomark -= len;
4998319Sroot 			if (tomark == 0)
5008319Sroot 				break;
5018319Sroot 		}
5028594Sroot 	} while (m && error == 0 && !eor);
5038319Sroot 	if (flags & SOF_PREVIEW)
5048319Sroot 		goto release;
5054786Swnj 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
5064786Swnj 		do {
5074786Swnj 			if (m == 0)
508*10137Ssam 				panic("receive 4");
5094890Swnj 			sbfree(&so->so_rcv, m);
5104786Swnj 			eor = (int)m->m_act;
5114786Swnj 			so->so_rcv.sb_mb = m->m_next;
5124786Swnj 			MFREE(m, n);
5134890Swnj 			m = n;
5144786Swnj 		} while (eor == 0);
5154890Swnj 	if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
5168300Sroot 		(*so->so_proto->pr_usrreq)(so, PRU_RCVD,
5178300Sroot 		    (struct mbuf *)0, (struct mbuf *)0, (struct socketopt *)0);
5184890Swnj release:
5194916Swnj 	sbunlock(&so->so_rcv);
5204890Swnj 	splx(s);
5214916Swnj 	return (error);
5224786Swnj }
5234786Swnj 
5245423Swnj sohasoutofband(so)
5255423Swnj 	struct socket *so;
5265423Swnj {
5275423Swnj 
5285423Swnj 	if (so->so_pgrp == 0)
5295423Swnj 		return;
5305423Swnj 	if (so->so_pgrp > 0)
5315423Swnj 		gsignal(so->so_pgrp, SIGURG);
5325429Swnj 	else {
5335429Swnj 		struct proc *p = pfind(-so->so_pgrp);
5345429Swnj 
5355429Swnj 		if (p)
5365429Swnj 			psignal(p, SIGURG);
5375429Swnj 	}
5385423Swnj }
5395423Swnj 
5404916Swnj /*ARGSUSED*/
5417627Ssam soioctl(so, cmd, data)
5424829Swnj 	register struct socket *so;
5434829Swnj 	int cmd;
5447627Ssam 	register char *data;
5454786Swnj {
5464786Swnj 
5475358Sroot 	switch (cmd) {
5484829Swnj 
5497627Ssam 	case FIONBIO:
5507627Ssam 		if (*(int *)data)
5516214Swnj 			so->so_state |= SS_NBIO;
5525388Sroot 		else
5536214Swnj 			so->so_state &= ~SS_NBIO;
5548594Sroot 		break;
5555388Sroot 
5567627Ssam 	case FIOASYNC:
5577627Ssam 		if (*(int *)data)
5586214Swnj 			so->so_state |= SS_ASYNC;
5595388Sroot 		else
5606214Swnj 			so->so_state &= ~SS_ASYNC;
5618594Sroot 		break;
5625388Sroot 
5637627Ssam 	case SIOCSKEEP:
5647627Ssam 		if (*(int *)data)
5657507Sroot 			so->so_options &= ~SO_KEEPALIVE;
5667507Sroot 		else
5677491Ssam 			so->so_options |= SO_KEEPALIVE;
5688594Sroot 		break;
5695388Sroot 
5707627Ssam 	case SIOCGKEEP:
5717627Ssam 		*(int *)data = (so->so_options & SO_KEEPALIVE) != 0;
5728594Sroot 		break;
5735388Sroot 
5747627Ssam 	case SIOCSLINGER:
5757627Ssam 		so->so_linger = *(int *)data;
5765388Sroot 		if (so->so_linger)
5775388Sroot 			so->so_options &= ~SO_DONTLINGER;
5785388Sroot 		else
5795388Sroot 			so->so_options |= SO_DONTLINGER;
5808594Sroot 		break;
5815388Sroot 
5827627Ssam 	case SIOCGLINGER:
5837627Ssam 		*(int *)data = so->so_linger;
5848594Sroot 		break;
5855388Sroot 
5867627Ssam 	case SIOCSPGRP:
5877627Ssam 		so->so_pgrp = *(int *)data;
5888594Sroot 		break;
5895423Swnj 
5907627Ssam 	case SIOCGPGRP:
5917627Ssam 		*(int *)data = so->so_pgrp;
5928594Sroot 		break;
5937627Ssam 
5945281Sroot 	case SIOCDONE: {
5957627Ssam 		int flags = *(int *)data;
5967627Ssam 
5975388Sroot 		flags++;
5985281Sroot 		if (flags & FREAD) {
5995281Sroot 			int s = splimp();
6005281Sroot 			socantrcvmore(so);
6015281Sroot 			sbflush(&so->so_rcv);
6026140Ssam 			splx(s);
6035281Sroot 		}
6045281Sroot 		if (flags & FWRITE)
6058560Sroot 			return ((*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN,
6068300Sroot 			    (struct mbuf *)0, (struct mbuf *)0,
6078560Sroot 			    (struct socketopt *)0));
6088594Sroot 		break;
6094829Swnj 	}
6105281Sroot 
6117627Ssam 	case SIOCATMARK:
6127627Ssam 		*(int *)data = (so->so_state&SS_RCVATMARK) != 0;
6138594Sroot 		break;
6146355Ssam 
6156355Ssam 	/* routing table update calls */
6166355Ssam 	case SIOCADDRT:
6176355Ssam 	case SIOCDELRT:
6186355Ssam 		if (!suser())
619*10137Ssam 			return (u.u_error);
6208560Sroot 		return (rtrequest(cmd, (struct rtentry *)data));
6216355Ssam 
6225445Swnj 	/* type/protocol specific ioctls */
6238594Sroot 	default:
624*10137Ssam 		return (ENOTTY);		/* XXX */
6255423Swnj 	}
6268594Sroot 	return (0);
6274786Swnj }
628