xref: /csrg-svn/sys/kern/uipc_socket.c (revision 37728)
1 /*
2  * Copyright (c) 1982, 1986, 1988 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.14 (Berkeley) 05/09/89
18  */
19 
20 #include "param.h"
21 #include "user.h"
22 #include "proc.h"
23 #include "file.h"
24 #include "malloc.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 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 	MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_WAIT);
62 	bzero((caddr_t)so, sizeof(*so));
63 	so->so_type = type;
64 	if (u.u_uid == 0)
65 		so->so_state = SS_PRIV;
66 	so->so_proto = prp;
67 	error =
68 	    (*prp->pr_usrreq)(so, PRU_ATTACH,
69 		(struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0);
70 	if (error) {
71 		so->so_state |= SS_NOFDREF;
72 		sofree(so);
73 		return (error);
74 	}
75 	*aso = so;
76 	return (0);
77 }
78 
79 sobind(so, nam)
80 	struct socket *so;
81 	struct mbuf *nam;
82 {
83 	int s = splnet();
84 	int error;
85 
86 	error =
87 	    (*so->so_proto->pr_usrreq)(so, PRU_BIND,
88 		(struct mbuf *)0, nam, (struct mbuf *)0);
89 	splx(s);
90 	return (error);
91 }
92 
93 solisten(so, backlog)
94 	register struct socket *so;
95 	int backlog;
96 {
97 	int s = splnet(), error;
98 
99 	error =
100 	    (*so->so_proto->pr_usrreq)(so, PRU_LISTEN,
101 		(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
102 	if (error) {
103 		splx(s);
104 		return (error);
105 	}
106 	if (so->so_q == 0) {
107 		so->so_q = so;
108 		so->so_q0 = so;
109 		so->so_options |= SO_ACCEPTCONN;
110 	}
111 	if (backlog < 0)
112 		backlog = 0;
113 	so->so_qlimit = min(backlog, SOMAXCONN);
114 	splx(s);
115 	return (0);
116 }
117 
118 sofree(so)
119 	register struct socket *so;
120 {
121 
122 	if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
123 		return;
124 	if (so->so_head) {
125 		if (!soqremque(so, 0) && !soqremque(so, 1))
126 			panic("sofree dq");
127 		so->so_head = 0;
128 	}
129 	sbrelease(&so->so_snd);
130 	sorflush(so);
131 	FREE(so, M_SOCKET);
132 }
133 
134 /*
135  * Close a socket on last file table reference removal.
136  * Initiate disconnect if connected.
137  * Free socket when disconnect complete.
138  */
139 soclose(so)
140 	register struct socket *so;
141 {
142 	int s = splnet();		/* conservative */
143 	int error = 0;
144 
145 	if (so->so_options & SO_ACCEPTCONN) {
146 		while (so->so_q0 != so)
147 			(void) soabort(so->so_q0);
148 		while (so->so_q != so)
149 			(void) soabort(so->so_q);
150 	}
151 	if (so->so_pcb == 0)
152 		goto discard;
153 	if (so->so_state & SS_ISCONNECTED) {
154 		if ((so->so_state & SS_ISDISCONNECTING) == 0) {
155 			error = sodisconnect(so);
156 			if (error)
157 				goto drop;
158 		}
159 		if (so->so_options & SO_LINGER) {
160 			if ((so->so_state & SS_ISDISCONNECTING) &&
161 			    (so->so_state & SS_NBIO))
162 				goto drop;
163 			while (so->so_state & SS_ISCONNECTED)
164 				sleep((caddr_t)&so->so_timeo, PZERO+1);
165 		}
166 	}
167 drop:
168 	if (so->so_pcb) {
169 		int error2 =
170 		    (*so->so_proto->pr_usrreq)(so, PRU_DETACH,
171 			(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
172 		if (error == 0)
173 			error = error2;
174 	}
175 discard:
176 	if (so->so_state & SS_NOFDREF)
177 		panic("soclose: NOFDREF");
178 	so->so_state |= SS_NOFDREF;
179 	sofree(so);
180 	splx(s);
181 	return (error);
182 }
183 
184 /*
185  * Must be called at splnet...
186  */
187 soabort(so)
188 	struct socket *so;
189 {
190 
191 	return (
192 	    (*so->so_proto->pr_usrreq)(so, PRU_ABORT,
193 		(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
194 }
195 
196 soaccept(so, nam)
197 	register struct socket *so;
198 	struct mbuf *nam;
199 {
200 	int s = splnet();
201 	int error;
202 
203 	if ((so->so_state & SS_NOFDREF) == 0)
204 		panic("soaccept: !NOFDREF");
205 	so->so_state &= ~SS_NOFDREF;
206 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT,
207 	    (struct mbuf *)0, nam, (struct mbuf *)0);
208 	splx(s);
209 	return (error);
210 }
211 
212 soconnect(so, nam)
213 	register struct socket *so;
214 	struct mbuf *nam;
215 {
216 	int s;
217 	int error;
218 
219 	if (so->so_options & SO_ACCEPTCONN)
220 		return (EOPNOTSUPP);
221 	s = splnet();
222 	/*
223 	 * If protocol is connection-based, can only connect once.
224 	 * Otherwise, if connected, try to disconnect first.
225 	 * This allows user to disconnect by connecting to, e.g.,
226 	 * a null address.
227 	 */
228 	if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) &&
229 	    ((so->so_proto->pr_flags & PR_CONNREQUIRED) ||
230 	    (error = sodisconnect(so))))
231 		error = EISCONN;
232 	else
233 		error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
234 		    (struct mbuf *)0, nam, (struct mbuf *)0);
235 	splx(s);
236 	return (error);
237 }
238 
239 soconnect2(so1, so2)
240 	register struct socket *so1;
241 	struct socket *so2;
242 {
243 	int s = splnet();
244 	int error;
245 
246 	error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2,
247 	    (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0);
248 	splx(s);
249 	return (error);
250 }
251 
252 sodisconnect(so)
253 	register struct socket *so;
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, (struct mbuf *)0, (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, control)
283 	register struct socket *so;
284 	struct mbuf *nam;
285 	register struct uio *uio;
286 	int flags;
287 	struct mbuf *rights, *control;
288 {
289 	struct mbuf *top = 0, **mp;
290 	register struct mbuf *m;
291 	register int space, len;
292 	int rlen = 0, error = 0, s, dontroute, first = 1, mlen;
293 	int atomic = sosendallatonce(so);
294 
295 	if (atomic && uio->uio_resid > so->so_snd.sb_hiwat)
296 		return (EMSGSIZE);
297 	dontroute =
298 	    (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
299 	    (so->so_proto->pr_flags & PR_ATOMIC);
300 	u.u_ru.ru_msgsnd++;
301 	if (rights)
302 		rlen = rights->m_len;
303 #define	snderr(errno)	{ error = errno; splx(s); goto release; }
304 
305 restart:
306 	sblock(&so->so_snd);
307 	do {
308 		s = splnet();
309 		if (so->so_state & SS_CANTSENDMORE)
310 			snderr(EPIPE);
311 		if (so->so_error)
312 			snderr(so->so_error);
313 		if ((so->so_state & SS_ISCONNECTED) == 0) {
314 			if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
315 				if (!uio->uio_resid && !rights && control) {
316 					snderr((*so->so_proto->pr_usrreq)(so,
317 				    (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
318 					    top, (caddr_t)0, rights, control));
319 				} else if (so->so_state & SS_ISCONFIRMING)
320 					/* is ok */;
321 				else
322 					snderr(ENOTCONN);
323 			} else if (nam == 0)
324 				snderr(EDESTADDRREQ);
325 		}
326 		if (flags & MSG_OOB)
327 			space = 1024;
328 		else {
329 			space = sbspace(&so->so_snd);
330 			if (space <= rlen ||
331 			   (atomic && space < uio->uio_resid + rlen) ||
332 			   (uio->uio_resid >= MCLBYTES && space < MCLBYTES &&
333 			   so->so_snd.sb_cc >= MCLBYTES &&
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 		do {
351 		   do {
352 			if (top == 0) {
353 				MGETHDR(m, M_WAIT, MT_DATA);
354 				mlen = MHLEN;
355 				m->m_pkthdr.len = 0;
356 				m->m_pkthdr.rcvif = (struct ifnet *)0;
357 			} else {
358 				MGET(m, M_WAIT, MT_DATA);
359 				mlen = MLEN;
360 			}
361 			if (uio->uio_resid >= MINCLSIZE && space >= MCLBYTES) {
362 				MCLGET(m, M_WAIT);
363 				if ((m->m_flags & M_EXT) == 0)
364 					goto nopages;
365 				mlen = MCLBYTES;
366 #ifdef	MAPPED_MBUFS
367 				len = min(MCLBYTES, uio->uio_resid);
368 				if (len < mlen - max_hdr)
369 					m->m_data += max_hdr;
370 #else
371 				len = min(MCLBYTES - max_hdr, uio->uio_resid);
372 				m->m_data += max_hdr;
373 #endif
374 				space -= MCLBYTES;
375 			} else {
376 nopages:
377 				len = min(min(mlen, uio->uio_resid), space);
378 				space -= len;
379 				/*
380 				 * For datagram protocols, leave room
381 				 * for protocol headers in first mbuf.
382 				 */
383 				if (atomic && top == 0 && len < mlen)
384 					MH_ALIGN(m, len);
385 			}
386 			error = uiomove(mtod(m, caddr_t), len, uio);
387 			m->m_len = len;
388 			*mp = m;
389 			top->m_pkthdr.len += len;
390 			if (error)
391 				goto release;
392 			mp = &m->m_next;
393 			if (uio->uio_resid <= 0) {
394 				if ((flags & MSG_EOR) && top)
395 					top->m_flags |= M_EOR;
396 				break;
397 			}
398 		    } while (space > 0 && atomic);
399 		    if (dontroute)
400 			    so->so_options |= SO_DONTROUTE;
401 		    s = splnet();				/* XXX */
402 		    error = (*so->so_proto->pr_usrreq)(so,
403 			(flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
404 			top, (caddr_t)nam, rights, control);
405 		    splx(s);
406 		    if (dontroute)
407 			    so->so_options &= ~SO_DONTROUTE;
408 		    rights = 0;
409 		    rlen = 0;
410 		    top = 0;
411 		    mp = &top;
412 		    first = 0;
413 		    if (error)
414 			goto release;
415 		} while (uio->uio_resid && space > 0);
416 	} while (uio->uio_resid);
417 
418 release:
419 	sbunlock(&so->so_snd);
420 	if (top)
421 		m_freem(top);
422 	if (error == EPIPE)
423 		psignal(u.u_procp, SIGPIPE);
424 	return (error);
425 }
426 
427 /*
428  * Implement receive operations on a socket.
429  * We depend on the way that records are added to the sockbuf
430  * by sbappend*.  In particular, each record (mbufs linked through m_next)
431  * must begin with an address if the protocol so specifies,
432  * followed by an optional mbuf containing access rights if supported
433  * by the protocol, and then zero or more mbufs of data.
434  * In order to avoid blocking network interrupts for the entire time here,
435  * we splx() while doing the actual copy to user space.
436  * Although the sockbuf is locked, new data may still be appended,
437  * and thus we must maintain consistency of the sockbuf during that time.
438  */
439 soreceive(so, aname, uio, flagsp, rightsp, controlp)
440 	register struct socket *so;
441 	struct mbuf **aname;
442 	register struct uio *uio;
443 	int *flagsp;
444 	struct mbuf **rightsp, **controlp;
445 {
446 	register struct mbuf *m;
447 	register int flags, len, error = 0, s, offset;
448 	struct protosw *pr = so->so_proto;
449 	struct mbuf *nextrecord;
450 	int moff;
451 
452 	if (rightsp)
453 		*rightsp = 0;
454 	if (aname)
455 		*aname = 0;
456 	if (controlp)
457 		*controlp = 0;
458 	if (flagsp)
459 		flags = *flagsp &~ MSG_EOR;
460 	else
461 		flags = 0;
462 	if (flags & MSG_OOB) {
463 		m = m_get(M_WAIT, MT_DATA);
464 		error = (*pr->pr_usrreq)(so, PRU_RCVOOB,
465 		    m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0);
466 		if (error)
467 			goto bad;
468 		do {
469 			len = uio->uio_resid;
470 			if (len > m->m_len)
471 				len = m->m_len;
472 			error = uiomove(mtod(m, caddr_t), (int)len, uio);
473 			m = m_free(m);
474 		} while (uio->uio_resid && error == 0 && m);
475 bad:
476 		if (m)
477 			m_freem(m);
478 		return (error);
479 	}
480 	if (so->so_state & SS_ISCONFIRMING && uio->uio_resid)
481 		(*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
482 		    (struct mbuf *)0, (struct mbuf *)0);
483 
484 restart:
485 	sblock(&so->so_rcv);
486 	s = splnet();
487 
488 	m = so->so_rcv.sb_mb;
489 	if (m == 0) {
490 		if (so->so_rcv.sb_cc)
491 			panic("receive 1");
492 		if (so->so_error) {
493 			error = so->so_error;
494 			so->so_error = 0;
495 			goto release;
496 		}
497 		if (so->so_state & SS_CANTRCVMORE)
498 			goto release;
499 		if ((so->so_state & SS_ISCONNECTED) == 0 &&
500 		    (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
501 			error = ENOTCONN;
502 			goto release;
503 		}
504 		if (uio->uio_resid == 0)
505 			goto release;
506 		if (so->so_state & SS_NBIO) {
507 			error = EWOULDBLOCK;
508 			goto release;
509 		}
510 		sbunlock(&so->so_rcv);
511 		sbwait(&so->so_rcv);
512 		splx(s);
513 		goto restart;
514 	}
515 	u.u_ru.ru_msgrcv++;
516 if (m->m_type == 0)
517 panic("receive 3a");
518 	nextrecord = m->m_nextpkt;
519 	if (pr->pr_flags & PR_ADDR) {
520 		if (m->m_type != MT_SONAME)
521 			panic("receive 1a");
522 		if (flags & MSG_PEEK) {
523 			if (aname)
524 				*aname = m_copy(m, 0, m->m_len);
525 			m = m->m_next;
526 		} else {
527 			sbfree(&so->so_rcv, m);
528 			if (aname) {
529 				*aname = m;
530 				so->so_rcv.sb_mb = m->m_next;
531 				m->m_next = 0;
532 				m = so->so_rcv.sb_mb;
533 			} else {
534 				MFREE(m, so->so_rcv.sb_mb);
535 				m = so->so_rcv.sb_mb;
536 			}
537 		}
538 	}
539 	if (m && m->m_type == MT_RIGHTS) {
540 		if ((pr->pr_flags & PR_RIGHTS) == 0)
541 			panic("receive 2");
542 		if (flags & MSG_PEEK) {
543 			if (rightsp)
544 				*rightsp = m_copy(m, 0, m->m_len);
545 			m = m->m_next;
546 		} else {
547 			sbfree(&so->so_rcv, m);
548 			if (rightsp) {
549 				*rightsp = m;
550 				so->so_rcv.sb_mb = m->m_next;
551 				m->m_next = 0;
552 				m = so->so_rcv.sb_mb;
553 			} else {
554 				MFREE(m, so->so_rcv.sb_mb);
555 				m = so->so_rcv.sb_mb;
556 			}
557 		}
558 	}
559 	if (m && m->m_type == MT_CONTROL) {
560 		if (flags & MSG_PEEK) {
561 			if (controlp)
562 				*controlp = m_copy(m, 0, m->m_len);
563 			m = m->m_next;
564 		} else {
565 			sbfree(&so->so_rcv, m);
566 			if (controlp) {
567 				*controlp = m;
568 				so->so_rcv.sb_mb = m->m_next;
569 				m->m_next = 0;
570 				m = so->so_rcv.sb_mb;
571 			} else {
572 				MFREE(m, so->so_rcv.sb_mb);
573 				m = so->so_rcv.sb_mb;
574 			}
575 		}
576 	}
577 	if (m)
578 		m->m_nextpkt = nextrecord;
579 	moff = 0;
580 	offset = 0;
581 	while (m && uio->uio_resid > 0 && error == 0) {
582 		if (m->m_type == MT_OOBDATA)
583 			flags |= MSG_OOB;
584 		else if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
585 			panic("receive 3");
586 		if (m->m_flags & M_EOR)
587 			flags |= MSG_EOR;
588 		len = uio->uio_resid;
589 		so->so_state &= ~SS_RCVATMARK;
590 		if (so->so_oobmark && len > so->so_oobmark - offset)
591 			len = so->so_oobmark - offset;
592 		if (len > m->m_len - moff)
593 			len = m->m_len - moff;
594 		splx(s);
595 		error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio);
596 		s = splnet();
597 		if (len == m->m_len - moff) {
598 			if (flags & MSG_PEEK) {
599 				m = m->m_next;
600 				moff = 0;
601 			} else {
602 				nextrecord = m->m_nextpkt;
603 				sbfree(&so->so_rcv, m);
604 				MFREE(m, so->so_rcv.sb_mb);
605 				m = so->so_rcv.sb_mb;
606 				if (m)
607 					m->m_nextpkt = nextrecord;
608 			}
609 		} else {
610 			if (flags & MSG_PEEK)
611 				moff += len;
612 			else {
613 				m->m_data += len;
614 				m->m_len -= len;
615 				so->so_rcv.sb_cc -= len;
616 			}
617 		}
618 		if (so->so_oobmark) {
619 			if ((flags & MSG_PEEK) == 0) {
620 				so->so_oobmark -= len;
621 				if (so->so_oobmark == 0) {
622 					so->so_state |= SS_RCVATMARK;
623 					break;
624 				}
625 			} else
626 				offset += len;
627 		}
628 	}
629 	if (m && (flags & MSG_EOR)) {
630 		flags &= ~MSG_EOR;
631 		if ((flags & MSG_PEEK) == 0)
632 			m->m_flags |= M_EOR;
633 	}
634 	if ((flags & MSG_PEEK) == 0) {
635 		if (m == 0)
636 			so->so_rcv.sb_mb = nextrecord;
637 		else if (pr->pr_flags & PR_ATOMIC) {
638 			flags |= MSG_TRUNC;
639 			(void) sbdroprecord(&so->so_rcv);
640 		}
641 		if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
642 			(*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
643 			    (struct mbuf *)flags, (struct mbuf *)0,
644 			    (struct mbuf *)0);
645 		if (error == 0 && rightsp && *rightsp &&
646 		    pr->pr_domain->dom_externalize)
647 			error = (*pr->pr_domain->dom_externalize)(*rightsp);
648 	}
649 	if (flagsp)
650 		*flagsp |= flags;
651 release:
652 	sbunlock(&so->so_rcv);
653 	splx(s);
654 	return (error);
655 }
656 
657 soshutdown(so, how)
658 	register struct socket *so;
659 	register int how;
660 {
661 	register struct protosw *pr = so->so_proto;
662 
663 	how++;
664 	if (how & FREAD)
665 		sorflush(so);
666 	if (how & FWRITE)
667 		return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN,
668 		    (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
669 	return (0);
670 }
671 
672 sorflush(so)
673 	register struct socket *so;
674 {
675 	register struct sockbuf *sb = &so->so_rcv;
676 	register struct protosw *pr = so->so_proto;
677 	register int s;
678 	struct sockbuf asb;
679 
680 	sblock(sb);
681 	s = splimp();
682 	socantrcvmore(so);
683 	sbunlock(sb);
684 	asb = *sb;
685 	bzero((caddr_t)sb, sizeof (*sb));
686 	splx(s);
687 	if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose)
688 		(*pr->pr_domain->dom_dispose)(asb.sb_mb);
689 	sbrelease(&asb);
690 }
691 
692 sosetopt(so, level, optname, m0)
693 	register struct socket *so;
694 	int level, optname;
695 	struct mbuf *m0;
696 {
697 	int error = 0;
698 	register struct mbuf *m = m0;
699 
700 	if (level != SOL_SOCKET) {
701 		if (so->so_proto && so->so_proto->pr_ctloutput)
702 			return ((*so->so_proto->pr_ctloutput)
703 				  (PRCO_SETOPT, so, level, optname, &m0));
704 		error = ENOPROTOOPT;
705 	} else {
706 		switch (optname) {
707 
708 		case SO_LINGER:
709 			if (m == NULL || m->m_len != sizeof (struct linger)) {
710 				error = EINVAL;
711 				goto bad;
712 			}
713 			so->so_linger = mtod(m, struct linger *)->l_linger;
714 			/* fall thru... */
715 
716 		case SO_DEBUG:
717 		case SO_KEEPALIVE:
718 		case SO_DONTROUTE:
719 		case SO_USELOOPBACK:
720 		case SO_BROADCAST:
721 		case SO_REUSEADDR:
722 		case SO_OOBINLINE:
723 			if (m == NULL || m->m_len < sizeof (int)) {
724 				error = EINVAL;
725 				goto bad;
726 			}
727 			if (*mtod(m, int *))
728 				so->so_options |= optname;
729 			else
730 				so->so_options &= ~optname;
731 			break;
732 
733 		case SO_SNDBUF:
734 		case SO_RCVBUF:
735 		case SO_SNDLOWAT:
736 		case SO_RCVLOWAT:
737 		case SO_SNDTIMEO:
738 		case SO_RCVTIMEO:
739 			if (m == NULL || m->m_len < sizeof (int)) {
740 				error = EINVAL;
741 				goto bad;
742 			}
743 			switch (optname) {
744 
745 			case SO_SNDBUF:
746 			case SO_RCVBUF:
747 				if (sbreserve(optname == SO_SNDBUF ?
748 				    &so->so_snd : &so->so_rcv,
749 				    (u_long) *mtod(m, int *)) == 0) {
750 					error = ENOBUFS;
751 					goto bad;
752 				}
753 				break;
754 
755 			case SO_SNDLOWAT:
756 				so->so_snd.sb_lowat = *mtod(m, int *);
757 				break;
758 			case SO_RCVLOWAT:
759 				so->so_rcv.sb_lowat = *mtod(m, int *);
760 				break;
761 			case SO_SNDTIMEO:
762 				so->so_snd.sb_timeo = *mtod(m, int *);
763 				break;
764 			case SO_RCVTIMEO:
765 				so->so_rcv.sb_timeo = *mtod(m, int *);
766 				break;
767 			}
768 			break;
769 
770 		default:
771 			error = ENOPROTOOPT;
772 			break;
773 		}
774 	}
775 bad:
776 	if (m)
777 		(void) m_free(m);
778 	return (error);
779 }
780 
781 sogetopt(so, level, optname, mp)
782 	register struct socket *so;
783 	int level, optname;
784 	struct mbuf **mp;
785 {
786 	register struct mbuf *m;
787 
788 	if (level != SOL_SOCKET) {
789 		if (so->so_proto && so->so_proto->pr_ctloutput) {
790 			return ((*so->so_proto->pr_ctloutput)
791 				  (PRCO_GETOPT, so, level, optname, mp));
792 		} else
793 			return (ENOPROTOOPT);
794 	} else {
795 		m = m_get(M_WAIT, MT_SOOPTS);
796 		m->m_len = sizeof (int);
797 
798 		switch (optname) {
799 
800 		case SO_LINGER:
801 			m->m_len = sizeof (struct linger);
802 			mtod(m, struct linger *)->l_onoff =
803 				so->so_options & SO_LINGER;
804 			mtod(m, struct linger *)->l_linger = so->so_linger;
805 			break;
806 
807 		case SO_USELOOPBACK:
808 		case SO_DONTROUTE:
809 		case SO_DEBUG:
810 		case SO_KEEPALIVE:
811 		case SO_REUSEADDR:
812 		case SO_BROADCAST:
813 		case SO_OOBINLINE:
814 			*mtod(m, int *) = so->so_options & optname;
815 			break;
816 
817 		case SO_TYPE:
818 			*mtod(m, int *) = so->so_type;
819 			break;
820 
821 		case SO_ERROR:
822 			*mtod(m, int *) = so->so_error;
823 			so->so_error = 0;
824 			break;
825 
826 		case SO_SNDBUF:
827 			*mtod(m, int *) = so->so_snd.sb_hiwat;
828 			break;
829 
830 		case SO_RCVBUF:
831 			*mtod(m, int *) = so->so_rcv.sb_hiwat;
832 			break;
833 
834 		case SO_SNDLOWAT:
835 			*mtod(m, int *) = so->so_snd.sb_lowat;
836 			break;
837 
838 		case SO_RCVLOWAT:
839 			*mtod(m, int *) = so->so_rcv.sb_lowat;
840 			break;
841 
842 		case SO_SNDTIMEO:
843 			*mtod(m, int *) = so->so_snd.sb_timeo;
844 			break;
845 
846 		case SO_RCVTIMEO:
847 			*mtod(m, int *) = so->so_rcv.sb_timeo;
848 			break;
849 
850 		default:
851 			(void)m_free(m);
852 			return (ENOPROTOOPT);
853 		}
854 		*mp = m;
855 		return (0);
856 	}
857 }
858 
859 sohasoutofband(so)
860 	register struct socket *so;
861 {
862 	struct proc *p;
863 
864 	if (so->so_pgid < 0)
865 		gsignal(-so->so_pgid, SIGURG);
866 	else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0)
867 		psignal(p, SIGURG);
868 	if (so->so_rcv.sb_sel) {
869 		selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL);
870 		so->so_rcv.sb_sel = 0;
871 		so->so_rcv.sb_flags &= ~SB_COLL;
872 	}
873 }
874