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