xref: /csrg-svn/sys/kern/uipc_socket.c (revision 43097)
1 /*
2  * Copyright (c) 1982, 1986, 1988, 1990 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.19 (Berkeley) 06/14/90
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 				if (error = tsleep((caddr_t)&so->so_timeo,
162 				    PSOCK | PCATCH, netcls, so->so_linger))
163 					break;
164 		}
165 	}
166 drop:
167 	if (so->so_pcb) {
168 		int error2 =
169 		    (*so->so_proto->pr_usrreq)(so, PRU_DETACH,
170 			(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
171 		if (error == 0)
172 			error = error2;
173 	}
174 discard:
175 	if (so->so_state & SS_NOFDREF)
176 		panic("soclose: NOFDREF");
177 	so->so_state |= SS_NOFDREF;
178 	sofree(so);
179 	splx(s);
180 	return (error);
181 }
182 
183 /*
184  * Must be called at splnet...
185  */
186 soabort(so)
187 	struct socket *so;
188 {
189 
190 	return (
191 	    (*so->so_proto->pr_usrreq)(so, PRU_ABORT,
192 		(struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
193 }
194 
195 soaccept(so, nam)
196 	register struct socket *so;
197 	struct mbuf *nam;
198 {
199 	int s = splnet();
200 	int error;
201 
202 	if ((so->so_state & SS_NOFDREF) == 0)
203 		panic("soaccept: !NOFDREF");
204 	so->so_state &= ~SS_NOFDREF;
205 	error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT,
206 	    (struct mbuf *)0, nam, (struct mbuf *)0);
207 	splx(s);
208 	return (error);
209 }
210 
211 soconnect(so, nam)
212 	register struct socket *so;
213 	struct mbuf *nam;
214 {
215 	int s;
216 	int error;
217 
218 	if (so->so_options & SO_ACCEPTCONN)
219 		return (EOPNOTSUPP);
220 	s = splnet();
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)
252 	register struct socket *so;
253 {
254 	int s = splnet();
255 	int error;
256 
257 	if ((so->so_state & SS_ISCONNECTED) == 0) {
258 		error = ENOTCONN;
259 		goto bad;
260 	}
261 	if (so->so_state & SS_ISDISCONNECTING) {
262 		error = EALREADY;
263 		goto bad;
264 	}
265 	error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT,
266 	    (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
267 bad:
268 	splx(s);
269 	return (error);
270 }
271 
272 /*
273  * Send on a socket.
274  * If send must go all at once and message is larger than
275  * send buffering, then hard error.
276  * Lock against other senders.
277  * If must go all at once and not enough room now, then
278  * inform user that this would block and do nothing.
279  * Otherwise, if nonblocking, send as much as possible.
280  * The data to be sent is described by "uio" if nonzero,
281  * otherwise by the mbuf chain "top" (which must be null
282  * if uio is not).  Data provided in mbuf chain must be small
283  * enough to send all at once.
284  *
285  * Returns nonzero on error, timeout or signal; callers
286  * must check for short counts if EINTR/ERESTART are returned.
287  * Data and control buffers are freed on return.
288  */
289 sosend(so, addr, uio, top, control, flags/*, sbwait_func, sbwait_arg*/)
290 	register struct socket *so;
291 	struct mbuf *addr;
292 	struct uio *uio;
293 	struct mbuf *top;
294 	struct mbuf *control;
295 	int flags;
296 /*
297 	int (*sbwait_func)();
298 	caddr_t sbwait_arg;
299 */
300 {
301 	struct mbuf **mp;
302 	register struct mbuf *m;
303 	register long space, len, resid;
304 	int clen = 0, error, s, dontroute, mlen;
305 	int atomic = sosendallatonce(so) || top;
306 
307 	if (uio)
308 		resid = uio->uio_resid;
309 	else
310 		resid = top->m_pkthdr.len;
311 	dontroute =
312 	    (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
313 	    (so->so_proto->pr_flags & PR_ATOMIC);
314 	u.u_ru.ru_msgsnd++;
315 	if (control)
316 		clen = control->m_len;
317 #define	snderr(errno)	{ error = errno; splx(s); goto release; }
318 
319 restart:
320 	if (error = sblock(&so->so_snd))
321 		goto out;
322 	do {
323 		s = splnet();
324 		if (so->so_state & SS_CANTSENDMORE)
325 			snderr(EPIPE);
326 		if (so->so_error)
327 			snderr(so->so_error);
328 		if ((so->so_state & SS_ISCONNECTED) == 0) {
329 			if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
330 				if ((so->so_state & SS_ISCONFIRMING) == 0)
331 					snderr(ENOTCONN);
332 			} else if (addr == 0)
333 				snderr(EDESTADDRREQ);
334 		}
335 		space = sbspace(&so->so_snd);
336 		if (flags & MSG_OOB)
337 			space += 1024;
338 		if (space < resid + clen &&
339 		    (atomic || space < so->so_snd.sb_lowat || space < clen)) {
340 			if (atomic && resid > so->so_snd.sb_hiwat ||
341 			    clen > so->so_snd.sb_hiwat)
342 				snderr(EMSGSIZE);
343 			if (so->so_state & SS_NBIO)
344 				snderr(EWOULDBLOCK);
345 			sbunlock(&so->so_snd);
346 /*
347 			if (sbwait_func)
348 				error = (*sbwait_func)(&so->so_snd, sbwait_arg);
349 			else
350 */
351 				error = sbwait(&so->so_snd);
352 			splx(s);
353 			if (error)
354 				goto out;
355 			goto restart;
356 		}
357 		splx(s);
358 		mp = &top;
359 		space -= clen;
360 		if (uio == NULL) {
361 			/*
362 			 * Data is prepackaged in "top".
363 			 */
364 			resid = 0;
365 			if (flags & MSG_EOR)
366 				top->m_flags |= M_EOR;
367 		} else do {
368 		   do {
369 			if (top == 0) {
370 				MGETHDR(m, M_WAIT, MT_DATA);
371 				mlen = MHLEN;
372 				m->m_pkthdr.len = 0;
373 				m->m_pkthdr.rcvif = (struct ifnet *)0;
374 			} else {
375 				MGET(m, M_WAIT, MT_DATA);
376 				mlen = MLEN;
377 			}
378 			if (resid >= MINCLSIZE && space >= MCLBYTES) {
379 				MCLGET(m, M_WAIT);
380 				if ((m->m_flags & M_EXT) == 0)
381 					goto nopages;
382 				mlen = MCLBYTES;
383 #ifdef	MAPPED_MBUFS
384 				len = min(MCLBYTES, resid);
385 #else
386 				if (top == 0) {
387 					len = min(MCLBYTES - max_hdr, resid);
388 					m->m_data += max_hdr;
389 				}
390 #endif
391 				space -= MCLBYTES;
392 			} else {
393 nopages:
394 				len = min(min(mlen, resid), space);
395 				space -= len;
396 				/*
397 				 * For datagram protocols, leave room
398 				 * for protocol headers in first mbuf.
399 				 */
400 				if (atomic && top == 0 && len < mlen)
401 					MH_ALIGN(m, len);
402 			}
403 			error = uiomove(mtod(m, caddr_t), len, uio);
404 			resid = uio->uio_resid;
405 			m->m_len = len;
406 			*mp = m;
407 			top->m_pkthdr.len += len;
408 			if (error)
409 				goto release;
410 			mp = &m->m_next;
411 			if (resid <= 0) {
412 				if (flags & MSG_EOR)
413 					top->m_flags |= M_EOR;
414 				break;
415 			}
416 		    } while (space > 0 && atomic);
417 		    if (dontroute)
418 			    so->so_options |= SO_DONTROUTE;
419 		    s = splnet();				/* XXX */
420 		    error = (*so->so_proto->pr_usrreq)(so,
421 			(flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
422 			top, addr, control);
423 		    splx(s);
424 		    if (dontroute)
425 			    so->so_options &= ~SO_DONTROUTE;
426 		    clen = 0;
427 		    control = 0;
428 		    top = 0;
429 		    mp = &top;
430 		    if (error)
431 			goto release;
432 		} while (resid && space > 0);
433 	} while (resid);
434 
435 release:
436 	sbunlock(&so->so_snd);
437 out:
438 	if (top)
439 		m_freem(top);
440 	if (control)
441 		m_freem(control);
442 	return (error);
443 }
444 
445 /*
446  * Implement receive operations on a socket.
447  * We depend on the way that records are added to the sockbuf
448  * by sbappend*.  In particular, each record (mbufs linked through m_next)
449  * must begin with an address if the protocol so specifies,
450  * followed by an optional mbuf or mbufs containing ancillary data,
451  * and then zero or more mbufs of data.
452  * In order to avoid blocking network interrupts for the entire time here,
453  * we splx() while doing the actual copy to user space.
454  * Although the sockbuf is locked, new data may still be appended,
455  * and thus we must maintain consistency of the sockbuf during that time.
456  *
457  * The caller may receive the data as a single mbuf chain by supplying
458  * an mbuf **mp for use in returning the chain.  The uio is then used
459  * only for the count in uio_resid.
460  */
461 soreceive(so, paddr, uio, mp, controlp, flagsp/*, sbwait_func, sbwait_arg*/)
462 	register struct socket *so;
463 	struct mbuf **paddr;
464 	struct uio *uio;
465 	struct mbuf **mp;
466 	struct mbuf **controlp;
467 	int *flagsp;
468 /*
469 	int (*sbwait_func)();
470 	caddr_t sbwait_arg;
471 */
472 {
473 	register struct mbuf *m;
474 	register int resid, flags, len, error, s, offset;
475 	struct protosw *pr = so->so_proto;
476 	struct mbuf *nextrecord;
477 	int moff, type;
478 
479 	if (paddr)
480 		*paddr = 0;
481 	if (controlp)
482 		*controlp = 0;
483 	if (flagsp)
484 		flags = *flagsp &~ MSG_EOR;
485 	else
486 		flags = 0;
487 	if (flags & MSG_OOB) {
488 		m = m_get(M_WAIT, MT_DATA);
489 		error = (*pr->pr_usrreq)(so, PRU_RCVOOB,
490 		    m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0);
491 		if (error)
492 			goto bad;
493 		do {
494 			error = uiomove(mtod(m, caddr_t),
495 			    (int) min(uio->uio_resid, m->m_len), uio);
496 			m = m_free(m);
497 		} while (uio->uio_resid && error == 0 && m);
498 bad:
499 		if (m)
500 			m_freem(m);
501 		return (error);
502 	}
503 	if (mp)
504 		*mp = (struct mbuf *)0;
505 	resid = uio->uio_resid;
506 	if (so->so_state & SS_ISCONFIRMING && resid)
507 		(*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
508 		    (struct mbuf *)0, (struct mbuf *)0);
509 
510 restart:
511 	if (error = sblock(&so->so_rcv))
512 		return (error);
513 	s = splnet();
514 
515 	m = so->so_rcv.sb_mb;
516 	if (m == 0 || (so->so_rcv.sb_cc < resid &&
517 	    so->so_rcv.sb_cc < so->so_rcv.sb_lowat)) {
518 #ifdef DIAGNOSTIC
519 		if (m == 0 && so->so_rcv.sb_cc)
520 			panic("receive 1");
521 #endif
522 		if (so->so_error) {
523 			error = so->so_error;
524 			so->so_error = 0;
525 			goto release;
526 		}
527 		if (so->so_state & SS_CANTRCVMORE)
528 			goto release;
529 		if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 &&
530 		    (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
531 			error = ENOTCONN;
532 			goto release;
533 		}
534 		if (resid == 0)
535 			goto release;
536 		if (so->so_state & SS_NBIO) {
537 			error = EWOULDBLOCK;
538 			goto release;
539 		}
540 		sbunlock(&so->so_rcv);
541 /*
542 		if (sbwait_func)
543 			error = (*sbwait_func)(&so->so_rcv, sbwait_arg);
544 		else
545 */
546 			error = sbwait(&so->so_rcv);
547 		splx(s);
548 		if (error)
549 			return (error);
550 		goto restart;
551 	}
552 	u.u_ru.ru_msgrcv++;
553 #ifdef DIAGNOSTIC
554 if (m->m_type == 0)
555 panic("receive 3a");
556 #endif
557 	nextrecord = m->m_nextpkt;
558 	if (pr->pr_flags & PR_ADDR) {
559 #ifdef DIAGNOSTIC
560 		if (m->m_type != MT_SONAME)
561 			panic("receive 1a");
562 #endif
563 		if (flags & MSG_PEEK) {
564 			if (paddr)
565 				*paddr = m_copy(m, 0, m->m_len);
566 			m = m->m_next;
567 		} else {
568 			sbfree(&so->so_rcv, m);
569 			if (paddr) {
570 				*paddr = m;
571 				so->so_rcv.sb_mb = m->m_next;
572 				m->m_next = 0;
573 				m = so->so_rcv.sb_mb;
574 			} else {
575 				MFREE(m, so->so_rcv.sb_mb);
576 				m = so->so_rcv.sb_mb;
577 			}
578 		}
579 	}
580 	while (m && m->m_type == MT_CONTROL && error == 0) {
581 		if (flags & MSG_PEEK) {
582 			if (controlp)
583 				*controlp = m_copy(m, 0, m->m_len);
584 			m = m->m_next;
585 		} else {
586 			sbfree(&so->so_rcv, m);
587 			if (controlp) {
588 				if (pr->pr_domain->dom_externalize &&
589 				    mtod(m, struct cmsghdr *)->cmsg_type ==
590 				    SCM_RIGHTS)
591 				   error = (*pr->pr_domain->dom_externalize)(m);
592 				*controlp = m;
593 				so->so_rcv.sb_mb = m->m_next;
594 				m->m_next = 0;
595 				m = so->so_rcv.sb_mb;
596 			} else {
597 				MFREE(m, so->so_rcv.sb_mb);
598 				m = so->so_rcv.sb_mb;
599 			}
600 		}
601 		if (controlp)
602 			controlp = &(*controlp)->m_next;
603 	}
604 	if (m) {
605 		m->m_nextpkt = nextrecord;
606 		type = m->m_type;
607 	}
608 	moff = 0;
609 	offset = 0;
610 	while (m && m->m_type == type && resid > 0 && error == 0) {
611 		if (m->m_type == MT_OOBDATA)
612 			flags |= MSG_OOB;
613 #ifdef DIAGNOSTIC
614 		else if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
615 			panic("receive 3");
616 #endif
617 		type = m->m_type;
618 		so->so_state &= ~SS_RCVATMARK;
619 		len = resid;
620 		if (so->so_oobmark && len > so->so_oobmark - offset)
621 			len = so->so_oobmark - offset;
622 		if (len > m->m_len - moff)
623 			len = m->m_len - moff;
624 		/*
625 		 * If mp is set, just pass back the mbufs.
626 		 * Otherwise copy them out via the uio, then free.
627 		 * Sockbuf must be consistent here (points to current mbuf,
628 		 * it points to next record) when we drop priority;
629 		 * we must note any additions to the sockbuf when we
630 		 * block interrupts again.
631 		 */
632 		if (mp == 0) {
633 			splx(s);
634 			error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio);
635 			resid = uio->uio_resid;
636 			s = splnet();
637 		}
638 		if (len == m->m_len - moff) {
639 			if (m->m_flags & M_EOR)
640 				flags |= MSG_EOR;
641 			if (flags & MSG_PEEK) {
642 				m = m->m_next;
643 				moff = 0;
644 			} else {
645 				nextrecord = m->m_nextpkt;
646 				sbfree(&so->so_rcv, m);
647 				if (mp) {
648 					*mp = m;
649 					mp = &m->m_next;
650 					m = m->m_next;
651 				} else {
652 					MFREE(m, so->so_rcv.sb_mb);
653 					m = so->so_rcv.sb_mb;
654 				}
655 				if (m)
656 					m->m_nextpkt = nextrecord;
657 			}
658 		} else {
659 			if (flags & MSG_PEEK)
660 				moff += len;
661 			else {
662 				m->m_data += len;
663 				m->m_len -= len;
664 				so->so_rcv.sb_cc -= len;
665 			}
666 		}
667 		if (so->so_oobmark) {
668 			if ((flags & MSG_PEEK) == 0) {
669 				so->so_oobmark -= len;
670 				if (so->so_oobmark == 0) {
671 					so->so_state |= SS_RCVATMARK;
672 					break;
673 				}
674 			} else
675 				offset += len;
676 		}
677 		if (flags & MSG_EOR)
678 			break;
679 		/*
680 		 * If the MSG_WAITALL flag is set (for non-atomic socket),
681 		 * we must not quit until "resid == 0" or an error
682 		 * termination.  If a signal/timeout occurs, return
683 		 * prematurely but without error.
684 		 * Keep sockbuf locked against other readers.
685 		 */
686 		while (flags & MSG_WAITALL && m == 0 && resid > 0 &&
687 		    !sosendallatonce(so)) {
688 			error = sbwait(&so->so_rcv);
689 			if (error) {
690 				sbunlock(&so->so_rcv);
691 				splx(s);
692 				if (mp)
693 					*mp = (struct mbuf *)0;
694 				return (0);
695 			}
696 			if (m = so->so_rcv.sb_mb)
697 				nextrecord = m->m_nextpkt;
698 			if (so->so_error || so->so_state & SS_CANTRCVMORE)
699 				break;
700 			continue;
701 		}
702 	}
703 	if (mp)
704 		*mp = (struct mbuf *)0;
705 	if ((flags & MSG_PEEK) == 0) {
706 		if (m == 0)
707 			so->so_rcv.sb_mb = nextrecord;
708 		else if (pr->pr_flags & PR_ATOMIC) {
709 			flags |= MSG_TRUNC;
710 			(void) sbdroprecord(&so->so_rcv);
711 		}
712 		if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
713 			(*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
714 			    (struct mbuf *)flags, (struct mbuf *)0,
715 			    (struct mbuf *)0);
716 	}
717 	if (flagsp)
718 		*flagsp |= flags;
719 release:
720 	sbunlock(&so->so_rcv);
721 	splx(s);
722 	return (error);
723 }
724 
725 soshutdown(so, how)
726 	register struct socket *so;
727 	register int how;
728 {
729 	register struct protosw *pr = so->so_proto;
730 
731 	how++;
732 	if (how & FREAD)
733 		sorflush(so);
734 	if (how & FWRITE)
735 		return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN,
736 		    (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
737 	return (0);
738 }
739 
740 sorflush(so)
741 	register struct socket *so;
742 {
743 	register struct sockbuf *sb = &so->so_rcv;
744 	register struct protosw *pr = so->so_proto;
745 	register int s;
746 	struct sockbuf asb;
747 
748 	sb->sb_flags |= SB_NOINTR;
749 	(void) sblock(sb);
750 	s = splimp();
751 	socantrcvmore(so);
752 	sbunlock(sb);
753 	asb = *sb;
754 	bzero((caddr_t)sb, sizeof (*sb));
755 	splx(s);
756 	if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose)
757 		(*pr->pr_domain->dom_dispose)(asb.sb_mb);
758 	sbrelease(&asb);
759 }
760 
761 sosetopt(so, level, optname, m0)
762 	register struct socket *so;
763 	int level, optname;
764 	struct mbuf *m0;
765 {
766 	int error = 0;
767 	register struct mbuf *m = m0;
768 
769 	if (level != SOL_SOCKET) {
770 		if (so->so_proto && so->so_proto->pr_ctloutput)
771 			return ((*so->so_proto->pr_ctloutput)
772 				  (PRCO_SETOPT, so, level, optname, &m0));
773 		error = ENOPROTOOPT;
774 	} else {
775 		switch (optname) {
776 
777 		case SO_LINGER:
778 			if (m == NULL || m->m_len != sizeof (struct linger)) {
779 				error = EINVAL;
780 				goto bad;
781 			}
782 			so->so_linger = mtod(m, struct linger *)->l_linger;
783 			/* fall thru... */
784 
785 		case SO_DEBUG:
786 		case SO_KEEPALIVE:
787 		case SO_DONTROUTE:
788 		case SO_USELOOPBACK:
789 		case SO_BROADCAST:
790 		case SO_REUSEADDR:
791 		case SO_OOBINLINE:
792 			if (m == NULL || m->m_len < sizeof (int)) {
793 				error = EINVAL;
794 				goto bad;
795 			}
796 			if (*mtod(m, int *))
797 				so->so_options |= optname;
798 			else
799 				so->so_options &= ~optname;
800 			break;
801 
802 		case SO_SNDBUF:
803 		case SO_RCVBUF:
804 		case SO_SNDLOWAT:
805 		case SO_RCVLOWAT:
806 		case SO_SNDTIMEO:
807 		case SO_RCVTIMEO:
808 			if (m == NULL || m->m_len < sizeof (int)) {
809 				error = EINVAL;
810 				goto bad;
811 			}
812 			switch (optname) {
813 
814 			case SO_SNDBUF:
815 			case SO_RCVBUF:
816 				if (sbreserve(optname == SO_SNDBUF ?
817 				    &so->so_snd : &so->so_rcv,
818 				    (u_long) *mtod(m, int *)) == 0) {
819 					error = ENOBUFS;
820 					goto bad;
821 				}
822 				break;
823 
824 			case SO_SNDLOWAT:
825 				so->so_snd.sb_lowat = *mtod(m, int *);
826 				break;
827 			case SO_RCVLOWAT:
828 				so->so_rcv.sb_lowat = *mtod(m, int *);
829 				break;
830 			case SO_SNDTIMEO:
831 				so->so_snd.sb_timeo = *mtod(m, int *);
832 				break;
833 			case SO_RCVTIMEO:
834 				so->so_rcv.sb_timeo = *mtod(m, int *);
835 				break;
836 			}
837 			break;
838 
839 		default:
840 			error = ENOPROTOOPT;
841 			break;
842 		}
843 	}
844 bad:
845 	if (m)
846 		(void) m_free(m);
847 	return (error);
848 }
849 
850 sogetopt(so, level, optname, mp)
851 	register struct socket *so;
852 	int level, optname;
853 	struct mbuf **mp;
854 {
855 	register struct mbuf *m;
856 
857 	if (level != SOL_SOCKET) {
858 		if (so->so_proto && so->so_proto->pr_ctloutput) {
859 			return ((*so->so_proto->pr_ctloutput)
860 				  (PRCO_GETOPT, so, level, optname, mp));
861 		} else
862 			return (ENOPROTOOPT);
863 	} else {
864 		m = m_get(M_WAIT, MT_SOOPTS);
865 		m->m_len = sizeof (int);
866 
867 		switch (optname) {
868 
869 		case SO_LINGER:
870 			m->m_len = sizeof (struct linger);
871 			mtod(m, struct linger *)->l_onoff =
872 				so->so_options & SO_LINGER;
873 			mtod(m, struct linger *)->l_linger = so->so_linger;
874 			break;
875 
876 		case SO_USELOOPBACK:
877 		case SO_DONTROUTE:
878 		case SO_DEBUG:
879 		case SO_KEEPALIVE:
880 		case SO_REUSEADDR:
881 		case SO_BROADCAST:
882 		case SO_OOBINLINE:
883 			*mtod(m, int *) = so->so_options & optname;
884 			break;
885 
886 		case SO_TYPE:
887 			*mtod(m, int *) = so->so_type;
888 			break;
889 
890 		case SO_ERROR:
891 			*mtod(m, int *) = so->so_error;
892 			so->so_error = 0;
893 			break;
894 
895 		case SO_SNDBUF:
896 			*mtod(m, int *) = so->so_snd.sb_hiwat;
897 			break;
898 
899 		case SO_RCVBUF:
900 			*mtod(m, int *) = so->so_rcv.sb_hiwat;
901 			break;
902 
903 		case SO_SNDLOWAT:
904 			*mtod(m, int *) = so->so_snd.sb_lowat;
905 			break;
906 
907 		case SO_RCVLOWAT:
908 			*mtod(m, int *) = so->so_rcv.sb_lowat;
909 			break;
910 
911 		case SO_SNDTIMEO:
912 			*mtod(m, int *) = so->so_snd.sb_timeo;
913 			break;
914 
915 		case SO_RCVTIMEO:
916 			*mtod(m, int *) = so->so_rcv.sb_timeo;
917 			break;
918 
919 		default:
920 			(void)m_free(m);
921 			return (ENOPROTOOPT);
922 		}
923 		*mp = m;
924 		return (0);
925 	}
926 }
927 
928 sohasoutofband(so)
929 	register struct socket *so;
930 {
931 	struct proc *p;
932 
933 	if (so->so_pgid < 0)
934 		gsignal(-so->so_pgid, SIGURG);
935 	else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0)
936 		psignal(p, SIGURG);
937 	if (so->so_rcv.sb_sel) {
938 		selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL);
939 		so->so_rcv.sb_sel = 0;
940 		so->so_rcv.sb_flags &= ~SB_COLL;
941 	}
942 }
943