xref: /original-bsd/sys/kern/uipc_socket.c (revision 3e9e8393)
1 /*
2  * Copyright (c) 1982, 1986 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  *	@(#)uipc_socket.c	7.10 (Berkeley) 06/29/88
18  */
19 
20 #include "param.h"
21 #include "dir.h"
22 #include "user.h"
23 #include "proc.h"
24 #include "file.h"
25 #include "mbuf.h"
26 #include "domain.h"
27 #include "protosw.h"
28 #include "socket.h"
29 #include "socketvar.h"
30 
31 /*
32  * Socket operation routines.
33  * These routines are called by the routines in
34  * sys_socket.c or from a system process, and
35  * implement the semantics of socket operations by
36  * switching out to the protocol specific routines.
37  *
38  * TODO:
39  *	test socketpair
40  *	clean up async
41  *	out-of-band is a kludge
42  */
43 /*ARGSUSED*/
44 socreate(dom, aso, type, proto)
45 	struct socket **aso;
46 	register int type;
47 	int proto;
48 {
49 	register struct protosw *prp;
50 	register struct socket *so;
51 	register struct mbuf *m;
52 	register int error;
53 
54 	if (proto)
55 		prp = pffindproto(dom, proto, type);
56 	else
57 		prp = pffindtype(dom, type);
58 	if (prp == 0)
59 		return (EPROTONOSUPPORT);
60 	if (prp->pr_type != type)
61 		return (EPROTOTYPE);
62 	m = m_getclr(M_WAIT, MT_SOCKET);
63 	so = mtod(m, struct socket *);
64 	so->so_options = 0;
65 	so->so_state = 0;
66 	so->so_type = type;
67 	if (u.u_uid == 0)
68 		so->so_state = SS_PRIV;
69 	so->so_proto = prp;
70 	error =
71 	    (*prp->pr_usrreq)(so, PRU_ATTACH,
72 		(struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0);
73 	if (error) {
74 		so->so_state |= SS_NOFDREF;
75 		sofree(so);
76 		return (error);
77 	}
78 	*aso = so;
79 	return (0);
80 }
81 
82 sobind(so, nam)
83 	struct socket *so;
84 	struct mbuf *nam;
85 {
86 	int s = splnet();
87 	int error;
88 
89 	error =
90 	    (*so->so_proto->pr_usrreq)(so, PRU_BIND,
91 		(struct mbuf *)0, nam, (struct mbuf *)0);
92 	splx(s);
93 	return (error);
94 }
95 
96 solisten(so, backlog)
97 	register struct socket *so;
98 	int backlog;
99 {
100 	int s = splnet(), error;
101 
102 	error =
103 	    (*so->so_proto->pr_usrreq)(so, PRU_LISTEN,
104 		(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
105 	if (error) {
106 		splx(s);
107 		return (error);
108 	}
109 	if (so->so_q == 0) {
110 		so->so_q = so;
111 		so->so_q0 = so;
112 		so->so_options |= SO_ACCEPTCONN;
113 	}
114 	if (backlog < 0)
115 		backlog = 0;
116 	so->so_qlimit = MIN(backlog, SOMAXCONN);
117 	splx(s);
118 	return (0);
119 }
120 
121 sofree(so)
122 	register struct socket *so;
123 {
124 
125 	if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
126 		return;
127 	if (so->so_head) {
128 		if (!soqremque(so, 0) && !soqremque(so, 1))
129 			panic("sofree dq");
130 		so->so_head = 0;
131 	}
132 	sbrelease(&so->so_snd);
133 	sorflush(so);
134 	(void) m_free(dtom(so));
135 }
136 
137 /*
138  * Close a socket on last file table reference removal.
139  * Initiate disconnect if connected.
140  * Free socket when disconnect complete.
141  */
142 soclose(so)
143 	register struct socket *so;
144 {
145 	int s = splnet();		/* conservative */
146 	int error = 0;
147 
148 	if (so->so_options & SO_ACCEPTCONN) {
149 		while (so->so_q0 != so)
150 			(void) soabort(so->so_q0);
151 		while (so->so_q != so)
152 			(void) soabort(so->so_q);
153 	}
154 	if (so->so_pcb == 0)
155 		goto discard;
156 	if (so->so_state & SS_ISCONNECTED) {
157 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
158 			error = sodisconnect(so);
159 			if (error)
160 				goto drop;
161 		}
162 		if (so->so_options & SO_LINGER) {
163 			if ((so->so_state & SS_ISDISCONNECTING) &&
164 			    (so->so_state & SS_NBIO))
165 				goto drop;
166 			while (so->so_state & SS_ISCONNECTED)
167 				sleep((caddr_t)&so->so_timeo, PZERO+1);
168 		}
169 	}
170 drop:
171 	if (so->so_pcb) {
172 		int error2 =
173 		    (*so->so_proto->pr_usrreq)(so, PRU_DETACH,
174 			(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
175 		if (error == 0)
176 			error = error2;
177 	}
178 discard:
179 	if (so->so_state & SS_NOFDREF)
180 		panic("soclose: NOFDREF");
181 	so->so_state |= SS_NOFDREF;
182 	sofree(so);
183 	splx(s);
184 	return (error);
185 }
186 
187 /*
188  * Must be called at splnet...
189  */
190 soabort(so)
191 	struct socket *so;
192 {
193 
194 	return (
195 	    (*so->so_proto->pr_usrreq)(so, PRU_ABORT,
196 		(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
197 }
198 
199 soaccept(so, nam)
200 	register struct socket *so;
201 	struct mbuf *nam;
202 {
203 	int s = splnet();
204 	int error;
205 
206 	if ((so->so_state & SS_NOFDREF) == 0)
207 		panic("soaccept: !NOFDREF");
208 	so->so_state &= ~SS_NOFDREF;
209 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT,
210 	    (struct mbuf *)0, nam, (struct mbuf *)0);
211 	splx(s);
212 	return (error);
213 }
214 
215 soconnect(so, nam)
216 	register struct socket *so;
217 	struct mbuf *nam;
218 {
219 	int s;
220 	int error;
221 
222 	if (so->so_options & SO_ACCEPTCONN)
223 		return (EOPNOTSUPP);
224 	s = splnet();
225 	/*
226 	 * If protocol is connection-based, can only connect once.
227 	 * Otherwise, if connected, try to disconnect first.
228 	 * This allows user to disconnect by connecting to, e.g.,
229 	 * a null address.
230 	 */
231 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) &&
232 	    ((so->so_proto->pr_flags & PR_CONNREQUIRED) ||
233 	    (error = sodisconnect(so))))
234 		error = EISCONN;
235 	else
236 		error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
237 		    (struct mbuf *)0, nam, (struct mbuf *)0);
238 	splx(s);
239 	return (error);
240 }
241 
242 soconnect2(so1, so2)
243 	register struct socket *so1;
244 	struct socket *so2;
245 {
246 	int s = splnet();
247 	int error;
248 
249 	error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2,
250 	    (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0);
251 	splx(s);
252 	return (error);
253 }
254 
255 sodisconnect(so)
256 	register struct socket *so;
257 {
258 	int s = splnet();
259 	int error;
260 
261 	if ((so->so_state & SS_ISCONNECTED) == 0) {
262 		error = ENOTCONN;
263 		goto bad;
264 	}
265 	if (so->so_state & SS_ISDISCONNECTING) {
266 		error = EALREADY;
267 		goto bad;
268 	}
269 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT,
270 	    (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
271 bad:
272 	splx(s);
273 	return (error);
274 }
275 
276 /*
277  * Send on a socket.
278  * If send must go all at once and message is larger than
279  * send buffering, then hard error.
280  * Lock against other senders.
281  * If must go all at once and not enough room now, then
282  * inform user that this would block and do nothing.
283  * Otherwise, if nonblocking, send as much as possible.
284  */
285 sosend(so, nam, uio, flags, rights)
286 	register struct socket *so;
287 	struct mbuf *nam;
288 	register struct uio *uio;
289 	int flags;
290 	struct mbuf *rights;
291 {
292 	struct mbuf *top = 0;
293 	register struct mbuf *m, **mp;
294 	register int space;
295 	int len, rlen = 0, error = 0, s, dontroute, first = 1;
296 
297 	if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat)
298 		return (EMSGSIZE);
299 	dontroute =
300 	    (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
301 	    (so->so_proto->pr_flags & PR_ATOMIC);
302 	u.u_ru.ru_msgsnd++;
303 	if (rights)
304 		rlen = rights->m_len;
305 #define	snderr(errno)	{ error = errno; splx(s); goto release; }
306 
307 restart:
308 	sblock(&so->so_snd);
309 	do {
310 		s = splnet();
311 		if (so->so_state & SS_CANTSENDMORE)
312 			snderr(EPIPE);
313 		if (so->so_error) {
314 			error = so->so_error;
315 			so->so_error = 0;			/* ??? */
316 			splx(s);
317 			goto release;
318 		}
319 		if ((so->so_state & SS_ISCONNECTED) == 0) {
320 			if (so->so_proto->pr_flags & PR_CONNREQUIRED)
321 				snderr(ENOTCONN);
322 			if (nam == 0)
323 				snderr(EDESTADDRREQ);
324 		}
325 		if (flags & MSG_OOB)
326 			space = 1024;
327 		else {
328 			space = sbspace(&so->so_snd);
329 			if (space <= rlen ||
330 			   (sosendallatonce(so) &&
331 				space < uio->uio_resid + rlen) ||
332 			   (uio->uio_resid >= CLBYTES && space < CLBYTES &&
333 			   so->so_snd.sb_cc >= CLBYTES &&
334 			   (so->so_state & SS_NBIO) == 0)) {
335 				if (so->so_state & SS_NBIO) {
336 					if (first)
337 						error = EWOULDBLOCK;
338 					splx(s);
339 					goto release;
340 				}
341 				sbunlock(&so->so_snd);
342 				sbwait(&so->so_snd);
343 				splx(s);
344 				goto restart;
345 			}
346 		}
347 		splx(s);
348 		mp = &top;
349 		space -= rlen;
350 		while (space > 0) {
351 			MGET(m, M_WAIT, MT_DATA);
352 			if (uio->uio_resid >= CLBYTES / 2 && space >= CLBYTES) {
353 				MCLGET(m);
354 				if (m->m_len != CLBYTES)
355 					goto nopages;
356 				len = MIN(CLBYTES, uio->uio_resid);
357 				space -= CLBYTES;
358 			} else {
359 nopages:
360 				len = MIN(MIN(MLEN, uio->uio_resid), space);
361 				space -= len;
362 			}
363 			error = uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio);
364 			m->m_len = len;
365 			*mp = m;
366 			if (error)
367 				goto release;
368 			mp = &m->m_next;
369 			if (uio->uio_resid <= 0)
370 				break;
371 		}
372 		if (dontroute)
373 			so->so_options |= SO_DONTROUTE;
374 		s = splnet();					/* XXX */
375 		error = (*so->so_proto->pr_usrreq)(so,
376 		    (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
377 		    top, (caddr_t)nam, rights);
378 		splx(s);
379 		if (dontroute)
380 			so->so_options &= ~SO_DONTROUTE;
381 		rights = 0;
382 		rlen = 0;
383 		top = 0;
384 		first = 0;
385 		if (error)
386 			break;
387 	} while (uio->uio_resid);
388 
389 release:
390 	sbunlock(&so->so_snd);
391 	if (top)
392 		m_freem(top);
393 	if (error == EPIPE)
394 		psignal(u.u_procp, SIGPIPE);
395 	return (error);
396 }
397 
398 /*
399  * Implement receive operations on a socket.
400  * We depend on the way that records are added to the sockbuf
401  * by sbappend*.  In particular, each record (mbufs linked through m_next)
402  * must begin with an address if the protocol so specifies,
403  * followed by an optional mbuf containing access rights if supported
404  * by the protocol, and then zero or more mbufs of data.
405  * In order to avoid blocking network interrupts for the entire time here,
406  * we splx() while doing the actual copy to user space.
407  * Although the sockbuf is locked, new data may still be appended,
408  * and thus we must maintain consistency of the sockbuf during that time.
409  */
410 soreceive(so, aname, uio, flags, rightsp)
411 	register struct socket *so;
412 	struct mbuf **aname;
413 	register struct uio *uio;
414 	int flags;
415 	struct mbuf **rightsp;
416 {
417 	register struct mbuf *m;
418 	register int len, error = 0, s, offset;
419 	struct protosw *pr = so->so_proto;
420 	struct mbuf *nextrecord;
421 	int moff;
422 
423 	if (rightsp)
424 		*rightsp = 0;
425 	if (aname)
426 		*aname = 0;
427 	if (flags & MSG_OOB) {
428 		m = m_get(M_WAIT, MT_DATA);
429 		error = (*pr->pr_usrreq)(so, PRU_RCVOOB,
430 		    m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0);
431 		if (error)
432 			goto bad;
433 		do {
434 			len = uio->uio_resid;
435 			if (len > m->m_len)
436 				len = m->m_len;
437 			error =
438 			    uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio);
439 			m = m_free(m);
440 		} while (uio->uio_resid && error == 0 && m);
441 bad:
442 		if (m)
443 			m_freem(m);
444 		return (error);
445 	}
446 
447 restart:
448 	sblock(&so->so_rcv);
449 	s = splnet();
450 
451 	if (so->so_rcv.sb_cc == 0) {
452 		if (so->so_error) {
453 			error = so->so_error;
454 			so->so_error = 0;
455 			goto release;
456 		}
457 		if (so->so_state & SS_CANTRCVMORE)
458 			goto release;
459 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
460 		    (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
461 			error = ENOTCONN;
462 			goto release;
463 		}
464 		if (uio->uio_resid == 0)
465 			goto release;
466 		if (so->so_state & SS_NBIO) {
467 			error = EWOULDBLOCK;
468 			goto release;
469 		}
470 		sbunlock(&so->so_rcv);
471 		sbwait(&so->so_rcv);
472 		splx(s);
473 		goto restart;
474 	}
475 	u.u_ru.ru_msgrcv++;
476 	m = so->so_rcv.sb_mb;
477 	if (m == 0)
478 		panic("receive 1");
479 	nextrecord = m->m_act;
480 	if (pr->pr_flags & PR_ADDR) {
481 		if (m->m_type != MT_SONAME)
482 			panic("receive 1a");
483 		if (flags & MSG_PEEK) {
484 			if (aname)
485 				*aname = m_copy(m, 0, m->m_len);
486 			m = m->m_next;
487 		} else {
488 			sbfree(&so->so_rcv, m);
489 			if (aname) {
490 				*aname = m;
491 				m = m->m_next;
492 				(*aname)->m_next = 0;
493 				so->so_rcv.sb_mb = m;
494 			} else {
495 				MFREE(m, so->so_rcv.sb_mb);
496 				m = so->so_rcv.sb_mb;
497 			}
498 			if (m)
499 				m->m_act = nextrecord;
500 		}
501 	}
502 	if (m && m->m_type == MT_RIGHTS) {
503 		if ((pr->pr_flags & PR_RIGHTS) == 0)
504 			panic("receive 2");
505 		if (flags & MSG_PEEK) {
506 			if (rightsp)
507 				*rightsp = m_copy(m, 0, m->m_len);
508 			m = m->m_next;
509 		} else {
510 			sbfree(&so->so_rcv, m);
511 			if (rightsp) {
512 				*rightsp = m;
513 				so->so_rcv.sb_mb = m->m_next;
514 				m->m_next = 0;
515 				m = so->so_rcv.sb_mb;
516 			} else {
517 				MFREE(m, so->so_rcv.sb_mb);
518 				m = so->so_rcv.sb_mb;
519 			}
520 			if (m)
521 				m->m_act = nextrecord;
522 		}
523 	}
524 	moff = 0;
525 	offset = 0;
526 	while (m && uio->uio_resid > 0 && error == 0) {
527 		if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
528 			panic("receive 3");
529 		len = uio->uio_resid;
530 		so->so_state &= ~SS_RCVATMARK;
531 		if (so->so_oobmark && len > so->so_oobmark - offset)
532 			len = so->so_oobmark - offset;
533 		if (len > m->m_len - moff)
534 			len = m->m_len - moff;
535 		splx(s);
536 		error =
537 		    uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio);
538 		s = splnet();
539 		if (len == m->m_len - moff) {
540 			if (flags & MSG_PEEK) {
541 				m = m->m_next;
542 				moff = 0;
543 			} else {
544 				nextrecord = m->m_act;
545 				sbfree(&so->so_rcv, m);
546 				MFREE(m, so->so_rcv.sb_mb);
547 				m = so->so_rcv.sb_mb;
548 				if (m)
549 					m->m_act = nextrecord;
550 			}
551 		} else {
552 			if (flags & MSG_PEEK)
553 				moff += len;
554 			else {
555 				m->m_off += len;
556 				m->m_len -= len;
557 				so->so_rcv.sb_cc -= len;
558 			}
559 		}
560 		if (so->so_oobmark) {
561 			if ((flags & MSG_PEEK) == 0) {
562 				so->so_oobmark -= len;
563 				if (so->so_oobmark == 0) {
564 					so->so_state |= SS_RCVATMARK;
565 					break;
566 				}
567 			} else
568 				offset += len;
569 		}
570 	}
571 	if ((flags & MSG_PEEK) == 0) {
572 		if (m == 0)
573 			so->so_rcv.sb_mb = nextrecord;
574 		else if (pr->pr_flags & PR_ATOMIC)
575 			(void) sbdroprecord(&so->so_rcv);
576 		if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
577 			(*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
578 			    (struct mbuf *)0, (struct mbuf *)0);
579 		if (error == 0 && rightsp && *rightsp &&
580 		    pr->pr_domain->dom_externalize)
581 			error = (*pr->pr_domain->dom_externalize)(*rightsp);
582 	}
583 release:
584 	sbunlock(&so->so_rcv);
585 	splx(s);
586 	return (error);
587 }
588 
589 soshutdown(so, how)
590 	register struct socket *so;
591 	register int how;
592 {
593 	register struct protosw *pr = so->so_proto;
594 
595 	how++;
596 	if (how & FREAD)
597 		sorflush(so);
598 	if (how & FWRITE)
599 		return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN,
600 		    (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
601 	return (0);
602 }
603 
604 sorflush(so)
605 	register struct socket *so;
606 {
607 	register struct sockbuf *sb = &so->so_rcv;
608 	register struct protosw *pr = so->so_proto;
609 	register int s;
610 	struct sockbuf asb;
611 
612 	sblock(sb);
613 	s = splimp();
614 	socantrcvmore(so);
615 	sbunlock(sb);
616 	asb = *sb;
617 	bzero((caddr_t)sb, sizeof (*sb));
618 	splx(s);
619 	if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose)
620 		(*pr->pr_domain->dom_dispose)(asb.sb_mb);
621 	sbrelease(&asb);
622 }
623 
624 sosetopt(so, level, optname, m0)
625 	register struct socket *so;
626 	int level, optname;
627 	struct mbuf *m0;
628 {
629 	int error = 0;
630 	register struct mbuf *m = m0;
631 
632 	if (level != SOL_SOCKET) {
633 		if (so->so_proto && so->so_proto->pr_ctloutput)
634 			return ((*so->so_proto->pr_ctloutput)
635 				  (PRCO_SETOPT, so, level, optname, &m0));
636 		error = ENOPROTOOPT;
637 	} else {
638 		switch (optname) {
639 
640 		case SO_LINGER:
641 			if (m == NULL || m->m_len != sizeof (struct linger)) {
642 				error = EINVAL;
643 				goto bad;
644 			}
645 			so->so_linger = mtod(m, struct linger *)->l_linger;
646 			/* fall thru... */
647 
648 		case SO_DEBUG:
649 		case SO_KEEPALIVE:
650 		case SO_DONTROUTE:
651 		case SO_USELOOPBACK:
652 		case SO_BROADCAST:
653 		case SO_REUSEADDR:
654 		case SO_OOBINLINE:
655 			if (m == NULL || m->m_len < sizeof (int)) {
656 				error = EINVAL;
657 				goto bad;
658 			}
659 			if (*mtod(m, int *))
660 				so->so_options |= optname;
661 			else
662 				so->so_options &= ~optname;
663 			break;
664 
665 		case SO_SNDBUF:
666 		case SO_RCVBUF:
667 		case SO_SNDLOWAT:
668 		case SO_RCVLOWAT:
669 		case SO_SNDTIMEO:
670 		case SO_RCVTIMEO:
671 			if (m == NULL || m->m_len < sizeof (int)) {
672 				error = EINVAL;
673 				goto bad;
674 			}
675 			switch (optname) {
676 
677 			case SO_SNDBUF:
678 			case SO_RCVBUF:
679 				if (sbreserve(optname == SO_SNDBUF ?
680 				    &so->so_snd : &so->so_rcv,
681 				    (u_long) *mtod(m, int *)) == 0) {
682 					error = ENOBUFS;
683 					goto bad;
684 				}
685 				break;
686 
687 			case SO_SNDLOWAT:
688 				so->so_snd.sb_lowat = *mtod(m, int *);
689 				break;
690 			case SO_RCVLOWAT:
691 				so->so_rcv.sb_lowat = *mtod(m, int *);
692 				break;
693 			case SO_SNDTIMEO:
694 				so->so_snd.sb_timeo = *mtod(m, int *);
695 				break;
696 			case SO_RCVTIMEO:
697 				so->so_rcv.sb_timeo = *mtod(m, int *);
698 				break;
699 			}
700 			break;
701 
702 		default:
703 			error = ENOPROTOOPT;
704 			break;
705 		}
706 	}
707 bad:
708 	if (m)
709 		(void) m_free(m);
710 	return (error);
711 }
712 
713 sogetopt(so, level, optname, mp)
714 	register struct socket *so;
715 	int level, optname;
716 	struct mbuf **mp;
717 {
718 	register struct mbuf *m;
719 
720 	if (level != SOL_SOCKET) {
721 		if (so->so_proto && so->so_proto->pr_ctloutput) {
722 			return ((*so->so_proto->pr_ctloutput)
723 				  (PRCO_GETOPT, so, level, optname, mp));
724 		} else
725 			return (ENOPROTOOPT);
726 	} else {
727 		m = m_get(M_WAIT, MT_SOOPTS);
728 		m->m_len = sizeof (int);
729 
730 		switch (optname) {
731 
732 		case SO_LINGER:
733 			m->m_len = sizeof (struct linger);
734 			mtod(m, struct linger *)->l_onoff =
735 				so->so_options & SO_LINGER;
736 			mtod(m, struct linger *)->l_linger = so->so_linger;
737 			break;
738 
739 		case SO_USELOOPBACK:
740 		case SO_DONTROUTE:
741 		case SO_DEBUG:
742 		case SO_KEEPALIVE:
743 		case SO_REUSEADDR:
744 		case SO_BROADCAST:
745 		case SO_OOBINLINE:
746 			*mtod(m, int *) = so->so_options & optname;
747 			break;
748 
749 		case SO_TYPE:
750 			*mtod(m, int *) = so->so_type;
751 			break;
752 
753 		case SO_ERROR:
754 			*mtod(m, int *) = so->so_error;
755 			so->so_error = 0;
756 			break;
757 
758 		case SO_SNDBUF:
759 			*mtod(m, int *) = so->so_snd.sb_hiwat;
760 			break;
761 
762 		case SO_RCVBUF:
763 			*mtod(m, int *) = so->so_rcv.sb_hiwat;
764 			break;
765 
766 		case SO_SNDLOWAT:
767 			*mtod(m, int *) = so->so_snd.sb_lowat;
768 			break;
769 
770 		case SO_RCVLOWAT:
771 			*mtod(m, int *) = so->so_rcv.sb_lowat;
772 			break;
773 
774 		case SO_SNDTIMEO:
775 			*mtod(m, int *) = so->so_snd.sb_timeo;
776 			break;
777 
778 		case SO_RCVTIMEO:
779 			*mtod(m, int *) = so->so_rcv.sb_timeo;
780 			break;
781 
782 		default:
783 			(void)m_free(m);
784 			return (ENOPROTOOPT);
785 		}
786 		*mp = m;
787 		return (0);
788 	}
789 }
790 
791 sohasoutofband(so)
792 	register struct socket *so;
793 {
794 	struct proc *p;
795 
796 	if (so->so_pgrp < 0)
797 		gsignal(-so->so_pgrp, SIGURG);
798 	else if (so->so_pgrp > 0 && (p = pfind(so->so_pgrp)) != 0)
799 		psignal(p, SIGURG);
800 	if (so->so_rcv.sb_sel) {
801 		selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL);
802 		so->so_rcv.sb_sel = 0;
803 		so->so_rcv.sb_flags &= ~SB_COLL;
804 	}
805 }
806