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