xref: /csrg-svn/sys/kern/uipc_socket.c (revision 8594)
1*8594Sroot /*	uipc_socket.c	4.56	82/10/17	*/
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 
28*8594Sroot /*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;
378300Sroot 	int pf, error;
384786Swnj 
398300Sroot 	pf = dom ? PF_UNIX : PF_INET;		/* should be u.u_protof */
404890Swnj 	if (proto)
414890Swnj 		prp = pffindproto(pf, proto);
424890Swnj 	else
434890Swnj 		prp = pffindtype(pf, type);
444890Swnj 	if (prp == 0)
454890Swnj 		return (EPROTONOSUPPORT);
468300Sroot 	if (prp->pr_type != type)
478300Sroot 		return (EPROTOTYPE);
484890Swnj 	m = m_getclr(M_WAIT);
494786Swnj 	if (m == 0)
504786Swnj 		return (ENOBUFS);
514786Swnj 	so = mtod(m, struct socket *);
528300Sroot 	so->so_options = 0;
536214Swnj 	so->so_state = 0;
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,
588300Sroot 	    (struct mbuf *)0, (struct mbuf *)0, (struct socketopt *)0);
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;
1038300Sroot 	so->so_qlimit = backlog < 5 ? backlog : 5;
1048300Sroot 	so->so_options |= SO_NEWFDONCONN;
1058300Sroot 	return (0);
1068300Sroot }
1078300Sroot 
1084916Swnj sofree(so)
1094916Swnj 	struct socket *so;
1104916Swnj {
1114916Swnj 
1127507Sroot 	if (so->so_head) {
1137507Sroot 		if (!soqremque(so, 0) && !soqremque(so, 1))
1147507Sroot 			panic("sofree dq");
1157507Sroot 		so->so_head = 0;
1167507Sroot 	}
1177507Sroot 	if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
1184950Swnj 		return;
1194950Swnj 	sbrelease(&so->so_snd);
1204950Swnj 	sbrelease(&so->so_rcv);
1214971Swnj 	(void) m_free(dtom(so));
1224916Swnj }
1234916Swnj 
1244786Swnj /*
1254890Swnj  * Close a socket on last file table reference removal.
1264890Swnj  * Initiate disconnect if connected.
1274890Swnj  * Free socket when disconnect complete.
1284829Swnj  */
1295580Sroot soclose(so, exiting)
1304829Swnj 	register struct socket *so;
1315580Sroot 	int exiting;
1324829Swnj {
1334890Swnj 	int s = splnet();		/* conservative */
1344829Swnj 
1357507Sroot 	if (so->so_options & SO_ACCEPTCONN) {
1367507Sroot 		while (so->so_q0 != so)
1377507Sroot 			soclose(so->so_q0, 1);
1387507Sroot 		while (so->so_q != so)
1397507Sroot 			soclose(so->so_q, 1);
1407507Sroot 	}
1414890Swnj 	if (so->so_pcb == 0)
1424890Swnj 		goto discard;
1436259Sroot 	if (exiting)
1446259Sroot 		so->so_options |= SO_KEEPALIVE;
1454890Swnj 	if (so->so_state & SS_ISCONNECTED) {
1464890Swnj 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
1474927Swnj 			u.u_error = sodisconnect(so, (struct sockaddr *)0);
1484890Swnj 			if (u.u_error) {
1495580Sroot 				if (exiting)
1505580Sroot 					goto drop;
1514890Swnj 				splx(s);
1524890Swnj 				return;
1534890Swnj 			}
1544890Swnj 		}
1555388Sroot 		if ((so->so_options & SO_DONTLINGER) == 0) {
1565281Sroot 			if ((so->so_state & SS_ISDISCONNECTING) &&
1576214Swnj 			    (so->so_state & SS_NBIO) &&
1585580Sroot 			    exiting == 0) {
1595281Sroot 				u.u_error = EINPROGRESS;
1605281Sroot 				splx(s);
1615281Sroot 				return;
1625281Sroot 			}
1635580Sroot 			/* should use tsleep here, for at most linger */
1645281Sroot 			while (so->so_state & SS_ISCONNECTED)
1655281Sroot 				sleep((caddr_t)&so->so_timeo, PZERO+1);
1664890Swnj 		}
1674890Swnj 	}
1685580Sroot drop:
1696880Ssam 	if (so->so_pcb) {
1708300Sroot 		u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH,
1718300Sroot 		    (struct mbuf *)0, (struct mbuf *)0, (struct socketopt *)0);
1726880Ssam 		if (exiting == 0 && u.u_error) {
1736880Ssam 			splx(s);
1746880Ssam 			return;
1756880Ssam 		}
1766880Ssam 	}
1774890Swnj discard:
1787507Sroot 	so->so_state |= SS_NOFDREF;
1794950Swnj 	sofree(so);
1804890Swnj 	splx(s);
1814829Swnj }
1824829Swnj 
1834916Swnj /*ARGSUSED*/
1844890Swnj sostat(so, sb)
1854829Swnj 	struct socket *so;
1864890Swnj 	struct stat *sb;
1874829Swnj {
1884829Swnj 
1895303Sroot 	bzero((caddr_t)sb, sizeof (*sb));		/* XXX */
1905303Sroot 	return (0);					/* XXX */
1914829Swnj }
1924829Swnj 
1938300Sroot soaccept(so, nam, opt)
1944927Swnj 	struct socket *so;
1958300Sroot 	struct mbuf *nam;
1968300Sroot 	struct socketopt *opt;
1974927Swnj {
1984927Swnj 	int s = splnet();
1994927Swnj 	int error;
2004927Swnj 
2018300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT,
2028300Sroot 	    (struct mbuf *)0, nam, opt);
2034927Swnj 	splx(s);
2044927Swnj 	return (error);
2054927Swnj }
2064927Swnj 
2078300Sroot soconnect(so, nam, opt)
2084786Swnj 	struct socket *so;
2098300Sroot 	struct mbuf *nam;
2108300Sroot 	struct socketopt *opt;
2114786Swnj {
2124890Swnj 	int s = splnet();
2134890Swnj 	int error;
2144786Swnj 
2154890Swnj 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) {
2164890Swnj 		error = EISCONN;
2174890Swnj 		goto bad;
2184890Swnj 	}
2198300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
2208300Sroot 	    (struct mbuf *)0, nam, opt);
2214890Swnj bad:
2224890Swnj 	splx(s);
2234890Swnj 	return (error);
2244786Swnj }
2254786Swnj 
2268300Sroot sodisconnect(so, nam)
2274786Swnj 	struct socket *so;
2288300Sroot 	struct mbuf *nam;
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 	}
2418300Sroot 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT,
2428300Sroot 	    (struct mbuf *)0, nam, (struct socketopt *)0);
2434890Swnj bad:
2444890Swnj 	splx(s);
2454890Swnj 	return (error);
2464786Swnj }
2474786Swnj 
2484786Swnj /*
2494890Swnj  * Send on a socket.
2504890Swnj  * If send must go all at once and message is larger than
2514890Swnj  * send buffering, then hard error.
2524890Swnj  * Lock against other senders.
2534890Swnj  * If must go all at once and not enough room now, then
2544890Swnj  * inform user that this would block and do nothing.
2554786Swnj  */
2568319Sroot sosend(so, nam, uio, flags)
2574786Swnj 	register struct socket *so;
2588300Sroot 	struct mbuf *nam;
2597827Sroot 	struct uio *uio;
2608319Sroot 	int flags;
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 restart:
2704890Swnj 	sblock(&so->so_snd);
2714890Swnj #define	snderr(errno)	{ error = errno; splx(s); goto release; }
2724890Swnj 
2738041Sroot 	u.u_ru.ru_msgsnd++;
2746419Sroot again:
2754890Swnj 	s = splnet();
2766419Sroot 	if (so->so_state & SS_CANTSENDMORE) {
2776419Sroot 		psignal(u.u_procp, SIGPIPE);
2786419Sroot 		snderr(EPIPE);
2796419Sroot 	}
2805168Swnj 	if (so->so_error) {
2815168Swnj 		error = so->so_error;
2826419Sroot 		so->so_error = 0;				/* ??? */
2835168Swnj 		splx(s);
2845168Swnj 		goto release;
2855168Swnj 	}
2864890Swnj 	if ((so->so_state & SS_ISCONNECTED) == 0) {
2874890Swnj 		if (so->so_proto->pr_flags & PR_CONNREQUIRED)
2884890Swnj 			snderr(ENOTCONN);
2898300Sroot 		if (nam == 0)
2904890Swnj 			snderr(EDESTADDRREQ);
2914890Swnj 	}
2924890Swnj 	if (top) {
2938319Sroot 		error = (*so->so_proto->pr_usrreq)(so,
2948319Sroot 		    (flags & SOF_OOB) ? PRU_SENDOOB : PRU_SEND,
2958300Sroot 		    top, (caddr_t)nam, (struct socketopt *)0);
2966419Sroot 		top = 0;
2974890Swnj 		if (error) {
2984890Swnj 			splx(s);
2994786Swnj 			goto release;
3004786Swnj 		}
3014890Swnj 		mp = &top;
3024786Swnj 	}
3037827Sroot 	if (uio->uio_resid == 0) {
3044979Swnj 		splx(s);
3054979Swnj 		goto release;
3064979Swnj 	}
3078319Sroot 	if (flags & SOF_OOB)
3088319Sroot 		space = 1024;
3098319Sroot 	else {
3108319Sroot 		space = sbspace(&so->so_snd);
3118319Sroot 		if (space <= 0 ||
3128319Sroot 		    sosendallatonce(so) && space < uio->uio_resid) {
3138319Sroot 			if (so->so_state & SS_NBIO)
3148319Sroot 				snderr(EWOULDBLOCK);
3158319Sroot 			sbunlock(&so->so_snd);
3168319Sroot 			sbwait(&so->so_snd);
3178319Sroot 			splx(s);
3188319Sroot 			goto restart;
3198319Sroot 		}
3204786Swnj 	}
3214890Swnj 	splx(s);
3227827Sroot 	while (uio->uio_resid > 0 && space > 0) {
3237827Sroot 		register struct iovec *iov = uio->uio_iov;
3247827Sroot 
3257827Sroot 		if (iov->iov_len == 0) {
3267827Sroot 			uio->uio_iov++;
3277827Sroot 			uio->uio_iovcnt--;
3287827Sroot 			if (uio->uio_iovcnt < 0)
3297827Sroot 				panic("sosend");
3307827Sroot 			continue;
3317827Sroot 		}
3324890Swnj 		MGET(m, 1);
3334890Swnj 		if (m == NULL) {
3346419Sroot 			error = ENOBUFS;			/* SIGPIPE? */
3354890Swnj 			goto release;
3364786Swnj 		}
3377827Sroot 		if (iov->iov_len >= CLBYTES && space >= CLBYTES) {
3384890Swnj 			register struct mbuf *p;
3395095Swnj 			MCLGET(p, 1);
3404890Swnj 			if (p == 0)
3414890Swnj 				goto nopages;
3424890Swnj 			m->m_off = (int)p - (int)m;
3435095Swnj 			len = CLBYTES;
3444890Swnj 		} else {
3454786Swnj nopages:
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;
3528319Sroot 		if (flags & SOF_OOB)
3538319Sroot 			space -= len;
3548319Sroot 		else
3558319Sroot 			space = sbspace(&so->so_snd);
3564786Swnj 	}
3574890Swnj 	goto again;
3584890Swnj 
3594786Swnj release:
3604890Swnj 	sbunlock(&so->so_snd);
3616419Sroot 	if (top)
3626419Sroot 		m_freem(top);
3634786Swnj 	return (error);
3644786Swnj }
3654786Swnj 
3668319Sroot soreceive(so, aname, uio, flags)
3674786Swnj 	register struct socket *so;
3688300Sroot 	struct mbuf **aname;
3697747Sroot 	struct uio *uio;
3708319Sroot 	int flags;
3714786Swnj {
3724786Swnj 	register struct mbuf *m, *n;
3734916Swnj 	u_int len;
3748319Sroot 	int eor, s, error = 0, moff, tomark;
3754786Swnj 
3768319Sroot 	if (flags & SOF_OOB) {
377*8594Sroot 		m = m_get(M_WAIT);
378*8594Sroot 		error = (*so->so_proto->pr_usrreq)(so, PRU_RCVOOB,
3798319Sroot 		    m, (struct mbuf *)0, (struct socketopt *)0);
380*8594Sroot 		if (error)
381*8594Sroot 			return;
3828319Sroot 		len = uio->uio_resid;
3838319Sroot 		do {
3848319Sroot 			if (len > m->m_len)
3858319Sroot 				len = m->m_len;
386*8594Sroot 			error =
387*8594Sroot 			    uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio);
3888319Sroot 			m = m_free(m);
389*8594Sroot 		} while (uio->uio_resid && error == 0 && m);
3908319Sroot 		if (m)
3918319Sroot 			(void) m_freem(m);
392*8594Sroot 		return (error);
3938319Sroot 	}
3948319Sroot 
3954890Swnj restart:
3964890Swnj 	sblock(&so->so_rcv);
3978552Sroot SBCHECK(&so->so_rcv, "soreceive restart");
3984890Swnj 	s = splnet();
3994890Swnj 
4004890Swnj #define	rcverr(errno)	{ error = errno; splx(s); goto release; }
4014786Swnj 	if (so->so_rcv.sb_cc == 0) {
4025168Swnj 		if (so->so_error) {
4035168Swnj 			error = so->so_error;
4045168Swnj 			so->so_error = 0;
4055168Swnj 			splx(s);
4065168Swnj 			goto release;
4075168Swnj 		}
4084890Swnj 		if (so->so_state & SS_CANTRCVMORE) {
4094890Swnj 			splx(s);
4104890Swnj 			goto release;
4114890Swnj 		}
4125015Sroot 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
4135015Sroot 		    (so->so_proto->pr_flags & PR_CONNREQUIRED))
4145015Sroot 			rcverr(ENOTCONN);
4156214Swnj 		if (so->so_state & SS_NBIO)
4165168Swnj 			rcverr(EWOULDBLOCK);
4174890Swnj 		sbunlock(&so->so_rcv);
4184971Swnj 		sbwait(&so->so_rcv);
4195012Swnj 		splx(s);
4204890Swnj 		goto restart;
4214786Swnj 	}
4228041Sroot 	u.u_ru.ru_msgrcv++;
4234829Swnj 	m = so->so_rcv.sb_mb;
4244786Swnj 	if (m == 0)
4254786Swnj 		panic("receive");
4268548Sroot SBCHECK(&so->so_snd, "soreceive havecc");
4275039Swnj 	if (so->so_proto->pr_flags & PR_ADDR) {
4288319Sroot 		if ((flags & SOF_PREVIEW) == 0) {
4298319Sroot 			so->so_rcv.sb_cc -= m->m_len;
4308319Sroot 			so->so_rcv.sb_mbcnt -= MSIZE;
4318319Sroot 		}
4328300Sroot 		if (aname) {
4338319Sroot 			if (flags & SOF_PREVIEW)
4348319Sroot 				*aname = m_copy(m, 0, m->m_len);
4358319Sroot 			else
4368319Sroot 				*aname = m;
4378300Sroot 			m = m->m_next;
4388300Sroot 			(*aname)->m_next = 0;
4398300Sroot 		} else
4408319Sroot 			if (flags & SOF_PREVIEW)
4418319Sroot 				m = m->m_next;
4428319Sroot 			else
4438319Sroot 				m = m_free(m);
4444890Swnj 		if (m == 0)
4454890Swnj 			panic("receive 2");
4468548Sroot 		if ((flags & SOF_PREVIEW) == 0)
4478548Sroot 			so->so_rcv.sb_mb = m;
4488548Sroot SBCHECK(&so->so_snd, "soreceive afteraddr");
4494890Swnj 	}
4504786Swnj 	eor = 0;
4518319Sroot 	moff = 0;
4528319Sroot 	tomark = so->so_oobmark;
4534786Swnj 	do {
4547827Sroot 		if (uio->uio_resid <= 0)
4557747Sroot 			break;
4567827Sroot 		len = uio->uio_resid;
4577747Sroot 		so->so_state &= ~SS_RCVATMARK;
4588319Sroot 		if (tomark && len > tomark)
4598319Sroot 			len = tomark;
4608548Sroot 		if (moff+len > m->m_len - moff)
4618319Sroot 			len = m->m_len - moff;
4624786Swnj 		splx(s);
463*8594Sroot 		error =
464*8594Sroot 		    uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio);
4654786Swnj 		s = splnet();
4664786Swnj 		if (len == m->m_len) {
4676091Sroot 			eor = (int)m->m_act;
4688319Sroot 			if (flags & SOF_PREVIEW)
4698319Sroot 				m = m->m_next;
4708319Sroot 			else {
4718319Sroot 				sbfree(&so->so_rcv, m);
4728319Sroot 				MFREE(m, n);
4738319Sroot 				m = n;
4748548Sroot 				so->so_rcv.sb_mb = m;
4758319Sroot 			}
4768319Sroot 			moff = 0;
4774786Swnj 		} else {
4788319Sroot 			if (flags & SOF_PREVIEW)
4798319Sroot 				moff += len;
4808319Sroot 			else {
4818319Sroot 				m->m_off += len;
4828319Sroot 				m->m_len -= len;
4838319Sroot 				so->so_rcv.sb_cc -= len;
4848319Sroot 			}
4854786Swnj 		}
4868319Sroot 		if ((flags & SOF_PREVIEW) == 0 && so->so_oobmark) {
4877747Sroot 			so->so_oobmark -= len;
4887747Sroot 			if (so->so_oobmark == 0) {
4897747Sroot 				so->so_state |= SS_RCVATMARK;
4907747Sroot 				break;
4917747Sroot 			}
4927747Sroot 		}
4938319Sroot 		if (tomark) {
4948319Sroot 			tomark -= len;
4958319Sroot 			if (tomark == 0)
4968319Sroot 				break;
4978319Sroot 		}
4988548Sroot SBCHECK(&so->so_snd, "soreceive rcvloop");
499*8594Sroot 	} while (m && error == 0 && !eor);
5008319Sroot 	if (flags & SOF_PREVIEW)
5018319Sroot 		goto release;
5024786Swnj 	if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0)
5034786Swnj 		do {
5044786Swnj 			if (m == 0)
5054890Swnj 				panic("receive 3");
5064890Swnj 			sbfree(&so->so_rcv, m);
5074786Swnj 			eor = (int)m->m_act;
5084786Swnj 			so->so_rcv.sb_mb = m->m_next;
5094786Swnj 			MFREE(m, n);
5104890Swnj 			m = n;
5118548Sroot SBCHECK(&so->so_snd, "soreceive atomicloop");
5124786Swnj 		} while (eor == 0);
5134890Swnj 	if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb)
5148300Sroot 		(*so->so_proto->pr_usrreq)(so, PRU_RCVD,
5158300Sroot 		    (struct mbuf *)0, (struct mbuf *)0, (struct socketopt *)0);
5164890Swnj release:
5174916Swnj 	sbunlock(&so->so_rcv);
5184890Swnj 	splx(s);
5194916Swnj 	return (error);
5204786Swnj }
5214786Swnj 
5225423Swnj sohasoutofband(so)
5235423Swnj 	struct socket *so;
5245423Swnj {
5255423Swnj 
5265423Swnj 	if (so->so_pgrp == 0)
5275423Swnj 		return;
5285423Swnj 	if (so->so_pgrp > 0)
5295423Swnj 		gsignal(so->so_pgrp, SIGURG);
5305429Swnj 	else {
5315429Swnj 		struct proc *p = pfind(-so->so_pgrp);
5325429Swnj 
5335429Swnj 		if (p)
5345429Swnj 			psignal(p, SIGURG);
5355429Swnj 	}
5365423Swnj }
5375423Swnj 
5384916Swnj /*ARGSUSED*/
5397627Ssam soioctl(so, cmd, data)
5404829Swnj 	register struct socket *so;
5414829Swnj 	int cmd;
5427627Ssam 	register char *data;
5434786Swnj {
5444786Swnj 
5455358Sroot 	switch (cmd) {
5464829Swnj 
5477627Ssam 	case FIONBIO:
5487627Ssam 		if (*(int *)data)
5496214Swnj 			so->so_state |= SS_NBIO;
5505388Sroot 		else
5516214Swnj 			so->so_state &= ~SS_NBIO;
552*8594Sroot 		break;
5535388Sroot 
5547627Ssam 	case FIOASYNC:
5557627Ssam 		if (*(int *)data)
5566214Swnj 			so->so_state |= SS_ASYNC;
5575388Sroot 		else
5586214Swnj 			so->so_state &= ~SS_ASYNC;
559*8594Sroot 		break;
5605388Sroot 
5617627Ssam 	case SIOCSKEEP:
5627627Ssam 		if (*(int *)data)
5637507Sroot 			so->so_options &= ~SO_KEEPALIVE;
5647507Sroot 		else
5657491Ssam 			so->so_options |= SO_KEEPALIVE;
566*8594Sroot 		break;
5675388Sroot 
5687627Ssam 	case SIOCGKEEP:
5697627Ssam 		*(int *)data = (so->so_options & SO_KEEPALIVE) != 0;
570*8594Sroot 		break;
5715388Sroot 
5727627Ssam 	case SIOCSLINGER:
5737627Ssam 		so->so_linger = *(int *)data;
5745388Sroot 		if (so->so_linger)
5755388Sroot 			so->so_options &= ~SO_DONTLINGER;
5765388Sroot 		else
5775388Sroot 			so->so_options |= SO_DONTLINGER;
578*8594Sroot 		break;
5795388Sroot 
5807627Ssam 	case SIOCGLINGER:
5817627Ssam 		*(int *)data = so->so_linger;
582*8594Sroot 		break;
5835388Sroot 
5847627Ssam 	case SIOCSPGRP:
5857627Ssam 		so->so_pgrp = *(int *)data;
586*8594Sroot 		break;
5875423Swnj 
5887627Ssam 	case SIOCGPGRP:
5897627Ssam 		*(int *)data = so->so_pgrp;
590*8594Sroot 		break;
5917627Ssam 
5925281Sroot 	case SIOCDONE: {
5937627Ssam 		int flags = *(int *)data;
5947627Ssam 
5955388Sroot 		flags++;
5965281Sroot 		if (flags & FREAD) {
5975281Sroot 			int s = splimp();
5985281Sroot 			socantrcvmore(so);
5995281Sroot 			sbflush(&so->so_rcv);
6006140Ssam 			splx(s);
6015281Sroot 		}
6025281Sroot 		if (flags & FWRITE)
6038560Sroot 			return ((*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN,
6048300Sroot 			    (struct mbuf *)0, (struct mbuf *)0,
6058560Sroot 			    (struct socketopt *)0));
606*8594Sroot 		break;
6074829Swnj 	}
6085281Sroot 
6095423Swnj 	case SIOCSENDOOB: {
6107627Ssam 		char oob = *(char *)data;
6118319Sroot 		struct mbuf *m = m_get(M_DONTWAIT);
6127627Ssam 
613*8594Sroot 		if (m == 0)
614*8594Sroot 			return (ENOBUFS);
6158319Sroot 		m->m_len = 1;
6167627Ssam 		*mtod(m, char *) = oob;
6178560Sroot 		return ((*so->so_proto->pr_usrreq)(so, PRU_SENDOOB,
6188560Sroot 		    m, (struct mbuf *)0, (struct socketopt *)0));
6195281Sroot 	}
6205423Swnj 
6215423Swnj 	case SIOCRCVOOB: {
6228319Sroot 		struct mbuf *m = m_get(M_WAIT);
6237627Ssam 
624*8594Sroot 		if (m == 0)
625*8594Sroot 			return (ENOBUFS);
6268319Sroot 		*mtod(m, caddr_t) = 0;
6278300Sroot 		(*so->so_proto->pr_usrreq)(so, PRU_RCVOOB,
6288300Sroot 		    m, (struct mbuf *)0, (struct socketopt *)0);
6297627Ssam 		*(char *)data = *mtod(m, char *);
6307627Ssam 		(void) m_free(m);
631*8594Sroot 		break;
6325423Swnj 	}
6335423Swnj 
6347627Ssam 	case SIOCATMARK:
6357627Ssam 		*(int *)data = (so->so_state&SS_RCVATMARK) != 0;
636*8594Sroot 		break;
6376355Ssam 
6386355Ssam 	/* routing table update calls */
6396355Ssam 	case SIOCADDRT:
6406355Ssam 	case SIOCDELRT:
6416355Ssam 		if (!suser())
6428560Sroot 			return (u.u_error);		/* XXX */
6438560Sroot 		return (rtrequest(cmd, (struct rtentry *)data));
6446355Ssam 
6455445Swnj 	/* type/protocol specific ioctls */
646*8594Sroot 	default:
647*8594Sroot 		return (ENOTTY);
6485423Swnj 	}
649*8594Sroot 	return (0);
6504786Swnj }
651