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