386BSD 0.1 development
[unix-history] / usr / src / sys.386bsd / kern / uipc_socket.c
CommitLineData
b688fc87
WJ
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, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)uipc_socket.c 7.28 (Berkeley) 5/4/91
34 */
35
36#include "param.h"
37#include "proc.h"
38#include "file.h"
39#include "malloc.h"
40#include "mbuf.h"
41#include "domain.h"
42#include "kernel.h"
43#include "protosw.h"
44#include "socket.h"
45#include "socketvar.h"
46#include "resourcevar.h"
47
48/*
49 * Socket operation routines.
50 * These routines are called by the routines in
51 * sys_socket.c or from a system process, and
52 * implement the semantics of socket operations by
53 * switching out to the protocol specific routines.
54 */
55/*ARGSUSED*/
56socreate(dom, aso, type, proto)
57 struct socket **aso;
58 register int type;
59 int proto;
60{
61 struct proc *p = curproc; /* XXX */
62 register struct protosw *prp;
63 register struct socket *so;
64 register int error;
65
66 if (proto)
67 prp = pffindproto(dom, proto, type);
68 else
69 prp = pffindtype(dom, type);
70 if (prp == 0)
71 return (EPROTONOSUPPORT);
72 if (prp->pr_type != type)
73 return (EPROTOTYPE);
74 MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_WAIT);
75 bzero((caddr_t)so, sizeof(*so));
76 so->so_type = type;
77 if (p->p_ucred->cr_uid == 0)
78 so->so_state = SS_PRIV;
79 so->so_proto = prp;
80 error =
81 (*prp->pr_usrreq)(so, PRU_ATTACH,
82 (struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0);
83 if (error) {
84 so->so_state |= SS_NOFDREF;
85 sofree(so);
86 return (error);
87 }
88 *aso = so;
89 return (0);
90}
91
92sobind(so, nam)
93 struct socket *so;
94 struct mbuf *nam;
95{
96 int s = splnet();
97 int error;
98
99 error =
100 (*so->so_proto->pr_usrreq)(so, PRU_BIND,
101 (struct mbuf *)0, nam, (struct mbuf *)0);
102 splx(s);
103 return (error);
104}
105
106solisten(so, backlog)
107 register struct socket *so;
108 int backlog;
109{
110 int s = splnet(), error;
111
112 error =
113 (*so->so_proto->pr_usrreq)(so, PRU_LISTEN,
114 (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
115 if (error) {
116 splx(s);
117 return (error);
118 }
119 if (so->so_q == 0)
120 so->so_options |= SO_ACCEPTCONN;
121 if (backlog < 0)
122 backlog = 0;
123 so->so_qlimit = min(backlog, SOMAXCONN);
124 splx(s);
125 return (0);
126}
127
128sofree(so)
129 register struct socket *so;
130{
131
132 if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0)
133 return;
134 if (so->so_head) {
135 if (!soqremque(so, 0) && !soqremque(so, 1))
136 panic("sofree dq");
137 so->so_head = 0;
138 }
139 sbrelease(&so->so_snd);
140 sorflush(so);
141 FREE(so, M_SOCKET);
142}
143
144/*
145 * Close a socket on last file table reference removal.
146 * Initiate disconnect if connected.
147 * Free socket when disconnect complete.
148 */
149soclose(so)
150 register struct socket *so;
151{
152 int s = splnet(); /* conservative */
153 int error = 0;
154
155 if (so->so_options & SO_ACCEPTCONN) {
156 while (so->so_q0)
157 (void) soabort(so->so_q0);
158 while (so->so_q)
159 (void) soabort(so->so_q);
160 }
161 if (so->so_pcb == 0)
162 goto discard;
163 if (so->so_state & SS_ISCONNECTED) {
164 if ((so->so_state & SS_ISDISCONNECTING) == 0) {
165 error = sodisconnect(so);
166 if (error)
167 goto drop;
168 }
169 if (so->so_options & SO_LINGER) {
170 if ((so->so_state & SS_ISDISCONNECTING) &&
171 (so->so_state & SS_NBIO))
172 goto drop;
173 while (so->so_state & SS_ISCONNECTED)
174 if (error = tsleep((caddr_t)&so->so_timeo,
175 PSOCK | PCATCH, netcls, so->so_linger))
176 break;
177 }
178 }
179drop:
180 if (so->so_pcb) {
181 int error2 =
182 (*so->so_proto->pr_usrreq)(so, PRU_DETACH,
183 (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
184 if (error == 0)
185 error = error2;
186 }
187discard:
188 if (so->so_state & SS_NOFDREF)
189 panic("soclose: NOFDREF");
190 so->so_state |= SS_NOFDREF;
191 sofree(so);
192 splx(s);
193 return (error);
194}
195
196/*
197 * Must be called at splnet...
198 */
199soabort(so)
200 struct socket *so;
201{
202
203 return (
204 (*so->so_proto->pr_usrreq)(so, PRU_ABORT,
205 (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
206}
207
208soaccept(so, nam)
209 register struct socket *so;
210 struct mbuf *nam;
211{
212 int s = splnet();
213 int error;
214
215 if ((so->so_state & SS_NOFDREF) == 0)
216 panic("soaccept: !NOFDREF");
217 so->so_state &= ~SS_NOFDREF;
218 error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT,
219 (struct mbuf *)0, nam, (struct mbuf *)0);
220 splx(s);
221 return (error);
222}
223
224soconnect(so, nam)
225 register struct socket *so;
226 struct mbuf *nam;
227{
228 int s;
229 int error;
230
231 if (so->so_options & SO_ACCEPTCONN)
232 return (EOPNOTSUPP);
233 s = splnet();
234 /*
235 * If protocol is connection-based, can only connect once.
236 * Otherwise, if connected, try to disconnect first.
237 * This allows user to disconnect by connecting to, e.g.,
238 * a null address.
239 */
240 if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) &&
241 ((so->so_proto->pr_flags & PR_CONNREQUIRED) ||
242 (error = sodisconnect(so))))
243 error = EISCONN;
244 else
245 error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
246 (struct mbuf *)0, nam, (struct mbuf *)0);
247 splx(s);
248 return (error);
249}
250
251soconnect2(so1, so2)
252 register struct socket *so1;
253 struct socket *so2;
254{
255 int s = splnet();
256 int error;
257
258 error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2,
259 (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0);
260 splx(s);
261 return (error);
262}
263
264sodisconnect(so)
265 register struct socket *so;
266{
267 int s = splnet();
268 int error;
269
270 if ((so->so_state & SS_ISCONNECTED) == 0) {
271 error = ENOTCONN;
272 goto bad;
273 }
274 if (so->so_state & SS_ISDISCONNECTING) {
275 error = EALREADY;
276 goto bad;
277 }
278 error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT,
279 (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0);
280bad:
281 splx(s);
282 return (error);
283}
284
285/*
286 * Send on a socket.
287 * If send must go all at once and message is larger than
288 * send buffering, then hard error.
289 * Lock against other senders.
290 * If must go all at once and not enough room now, then
291 * inform user that this would block and do nothing.
292 * Otherwise, if nonblocking, send as much as possible.
293 * The data to be sent is described by "uio" if nonzero,
294 * otherwise by the mbuf chain "top" (which must be null
295 * if uio is not). Data provided in mbuf chain must be small
296 * enough to send all at once.
297 *
298 * Returns nonzero on error, timeout or signal; callers
299 * must check for short counts if EINTR/ERESTART are returned.
300 * Data and control buffers are freed on return.
301 */
302sosend(so, addr, uio, top, control, flags)
303 register struct socket *so;
304 struct mbuf *addr;
305 struct uio *uio;
306 struct mbuf *top;
307 struct mbuf *control;
308 int flags;
309{
310 struct proc *p = curproc; /* XXX */
311 struct mbuf **mp;
312 register struct mbuf *m;
313 register long space, len, resid;
314 int clen = 0, error, s, dontroute, mlen;
315 int atomic = sosendallatonce(so) || top;
316
317 if (uio)
318 resid = uio->uio_resid;
319 else
320 resid = top->m_pkthdr.len;
321 dontroute =
322 (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
323 (so->so_proto->pr_flags & PR_ATOMIC);
324 p->p_stats->p_ru.ru_msgsnd++;
325 if (control)
326 clen = control->m_len;
327#define snderr(errno) { error = errno; splx(s); goto release; }
328
329restart:
330 if (error = sblock(&so->so_snd))
331 goto out;
332 do {
333 s = splnet();
334 if (so->so_state & SS_CANTSENDMORE)
335 snderr(EPIPE);
336 if (so->so_error)
337 snderr(so->so_error);
338 if ((so->so_state & SS_ISCONNECTED) == 0) {
339 if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
340 if ((so->so_state & SS_ISCONFIRMING) == 0 &&
341 !(resid == 0 && clen != 0))
342 snderr(ENOTCONN);
343 } else if (addr == 0)
344 snderr(EDESTADDRREQ);
345 }
346 space = sbspace(&so->so_snd);
347 if (flags & MSG_OOB)
348 space += 1024;
349 if (space < resid + clen &&
350 (atomic || space < so->so_snd.sb_lowat || space < clen)) {
351 if (atomic && resid > so->so_snd.sb_hiwat ||
352 clen > so->so_snd.sb_hiwat)
353 snderr(EMSGSIZE);
354 if (so->so_state & SS_NBIO)
355 snderr(EWOULDBLOCK);
356 sbunlock(&so->so_snd);
357 error = sbwait(&so->so_snd);
358 splx(s);
359 if (error)
360 goto out;
361 goto restart;
362 }
363 splx(s);
364 mp = &top;
365 space -= clen;
366 do {
367 if (uio == NULL) {
368 /*
369 * Data is prepackaged in "top".
370 */
371 resid = 0;
372 if (flags & MSG_EOR)
373 top->m_flags |= M_EOR;
374 } else do {
375 if (top == 0) {
376 MGETHDR(m, M_WAIT, MT_DATA);
377 mlen = MHLEN;
378 m->m_pkthdr.len = 0;
379 m->m_pkthdr.rcvif = (struct ifnet *)0;
380 } else {
381 MGET(m, M_WAIT, MT_DATA);
382 mlen = MLEN;
383 }
384 if (resid >= MINCLSIZE && space >= MCLBYTES) {
385 MCLGET(m, M_WAIT);
386 if ((m->m_flags & M_EXT) == 0)
387 goto nopages;
388 mlen = MCLBYTES;
389#ifdef MAPPED_MBUFS
390 len = min(MCLBYTES, resid);
391#else
392 if (top == 0) {
393 len = min(MCLBYTES - max_hdr, resid);
394 m->m_data += max_hdr;
395 } else
396 len = min(MCLBYTES, resid);
397#endif
398 space -= MCLBYTES;
399 } else {
400nopages:
401 len = min(min(mlen, resid), space);
402 space -= len;
403 /*
404 * For datagram protocols, leave room
405 * for protocol headers in first mbuf.
406 */
407 if (atomic && top == 0 && len < mlen)
408 MH_ALIGN(m, len);
409 }
410 error = uiomove(mtod(m, caddr_t), (int)len, uio);
411 resid = uio->uio_resid;
412 m->m_len = len;
413 *mp = m;
414 top->m_pkthdr.len += len;
415 if (error)
416 goto release;
417 mp = &m->m_next;
418 if (resid <= 0) {
419 if (flags & MSG_EOR)
420 top->m_flags |= M_EOR;
421 break;
422 }
423 } while (space > 0 && atomic);
424 if (dontroute)
425 so->so_options |= SO_DONTROUTE;
426 s = splnet(); /* XXX */
427 error = (*so->so_proto->pr_usrreq)(so,
428 (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
429 top, addr, control);
430 splx(s);
431 if (dontroute)
432 so->so_options &= ~SO_DONTROUTE;
433 clen = 0;
434 control = 0;
435 top = 0;
436 mp = &top;
437 if (error)
438 goto release;
439 } while (resid && space > 0);
440 } while (resid);
441
442release:
443 sbunlock(&so->so_snd);
444out:
445 if (top)
446 m_freem(top);
447 if (control)
448 m_freem(control);
449 return (error);
450}
451
452/*
453 * Implement receive operations on a socket.
454 * We depend on the way that records are added to the sockbuf
455 * by sbappend*. In particular, each record (mbufs linked through m_next)
456 * must begin with an address if the protocol so specifies,
457 * followed by an optional mbuf or mbufs containing ancillary data,
458 * and then zero or more mbufs of data.
459 * In order to avoid blocking network interrupts for the entire time here,
460 * we splx() while doing the actual copy to user space.
461 * Although the sockbuf is locked, new data may still be appended,
462 * and thus we must maintain consistency of the sockbuf during that time.
463 *
464 * The caller may receive the data as a single mbuf chain by supplying
465 * an mbuf **mp0 for use in returning the chain. The uio is then used
466 * only for the count in uio_resid.
467 */
468soreceive(so, paddr, uio, mp0, controlp, flagsp)
469 register struct socket *so;
470 struct mbuf **paddr;
471 struct uio *uio;
472 struct mbuf **mp0;
473 struct mbuf **controlp;
474 int *flagsp;
475{
476 struct proc *p = curproc; /* XXX */
477 register struct mbuf *m, **mp;
478 register int flags, len, error, s, offset;
479 struct protosw *pr = so->so_proto;
480 struct mbuf *nextrecord;
481 int moff, type;
482
483 mp = mp0;
484 if (paddr)
485 *paddr = 0;
486 if (controlp)
487 *controlp = 0;
488 if (flagsp)
489 flags = *flagsp &~ MSG_EOR;
490 else
491 flags = 0;
492 if (flags & MSG_OOB) {
493 m = m_get(M_WAIT, MT_DATA);
494 error = (*pr->pr_usrreq)(so, PRU_RCVOOB,
495 m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0);
496 if (error)
497 goto bad;
498 do {
499 error = uiomove(mtod(m, caddr_t),
500 (int) min(uio->uio_resid, m->m_len), uio);
501 m = m_free(m);
502 } while (uio->uio_resid && error == 0 && m);
503bad:
504 if (m)
505 m_freem(m);
506 return (error);
507 }
508 if (mp)
509 *mp = (struct mbuf *)0;
510 if (so->so_state & SS_ISCONFIRMING && uio->uio_resid)
511 (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
512 (struct mbuf *)0, (struct mbuf *)0);
513
514restart:
515 if (error = sblock(&so->so_rcv))
516 return (error);
517 s = splnet();
518
519 m = so->so_rcv.sb_mb;
520 /*
521 * If we have less data than requested, block awaiting more
522 * (subject to any timeout) if:
523 * 1. the current count is less than the low water mark, or
524 * 2. MSG_WAITALL is set, and it is possible to do the entire
525 * receive operation at once if we block (resid <= hiwat).
526 * If MSG_WAITALL is set but resid is larger than the receive buffer,
527 * we have to do the receive in sections, and thus risk returning
528 * a short count if a timeout or signal occurs after we start.
529 */
530 while (m == 0 || so->so_rcv.sb_cc < uio->uio_resid &&
531 (so->so_rcv.sb_cc < so->so_rcv.sb_lowat ||
532 ((flags & MSG_WAITALL) && uio->uio_resid <= so->so_rcv.sb_hiwat)) &&
533 m->m_nextpkt == 0) {
534#ifdef DIAGNOSTIC
535 if (m == 0 && so->so_rcv.sb_cc)
536 panic("receive 1");
537#endif
538 if (so->so_error) {
539 if (m)
540 break;
541 error = so->so_error;
542 if ((flags & MSG_PEEK) == 0)
543 so->so_error = 0;
544 goto release;
545 }
546 if (so->so_state & SS_CANTRCVMORE) {
547 if (m)
548 break;
549 else
550 goto release;
551 }
552 for (; m; m = m->m_next)
553 if (m->m_type == MT_OOBDATA || (m->m_flags & M_EOR)) {
554 m = so->so_rcv.sb_mb;
555 goto dontblock;
556 }
557 if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 &&
558 (so->so_proto->pr_flags & PR_CONNREQUIRED)) {
559 error = ENOTCONN;
560 goto release;
561 }
562 if (uio->uio_resid == 0)
563 goto release;
564 if (so->so_state & SS_NBIO) {
565 error = EWOULDBLOCK;
566 goto release;
567 }
568 sbunlock(&so->so_rcv);
569 error = sbwait(&so->so_rcv);
570 splx(s);
571 if (error)
572 return (error);
573 goto restart;
574 }
575dontblock:
576 p->p_stats->p_ru.ru_msgrcv++;
577 nextrecord = m->m_nextpkt;
578 if (pr->pr_flags & PR_ADDR) {
579#ifdef DIAGNOSTIC
580 if (m->m_type != MT_SONAME)
581 panic("receive 1a");
582#endif
583 if (flags & MSG_PEEK) {
584 if (paddr)
585 *paddr = m_copy(m, 0, m->m_len);
586 m = m->m_next;
587 } else {
588 sbfree(&so->so_rcv, m);
589 if (paddr) {
590 *paddr = m;
591 so->so_rcv.sb_mb = m->m_next;
592 m->m_next = 0;
593 m = so->so_rcv.sb_mb;
594 } else {
595 MFREE(m, so->so_rcv.sb_mb);
596 m = so->so_rcv.sb_mb;
597 }
598 }
599 }
600 while (m && m->m_type == MT_CONTROL && error == 0) {
601 if (flags & MSG_PEEK) {
602 if (controlp)
603 *controlp = m_copy(m, 0, m->m_len);
604 m = m->m_next;
605 } else {
606 sbfree(&so->so_rcv, m);
607 if (controlp) {
608 if (pr->pr_domain->dom_externalize &&
609 mtod(m, struct cmsghdr *)->cmsg_type ==
610 SCM_RIGHTS)
611 error = (*pr->pr_domain->dom_externalize)(m);
612 *controlp = m;
613 so->so_rcv.sb_mb = m->m_next;
614 m->m_next = 0;
615 m = so->so_rcv.sb_mb;
616 } else {
617 MFREE(m, so->so_rcv.sb_mb);
618 m = so->so_rcv.sb_mb;
619 }
620 }
621 if (controlp)
622 controlp = &(*controlp)->m_next;
623 }
624 if (m) {
625 if ((flags & MSG_PEEK) == 0)
626 m->m_nextpkt = nextrecord;
627 type = m->m_type;
628 if (type == MT_OOBDATA)
629 flags |= MSG_OOB;
630 }
631 moff = 0;
632 offset = 0;
633 while (m && uio->uio_resid > 0 && error == 0) {
634 if (m->m_type == MT_OOBDATA) {
635 if (type != MT_OOBDATA)
636 break;
637 } else if (type == MT_OOBDATA)
638 break;
639#ifdef DIAGNOSTIC
640 else if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
641 panic("receive 3");
642#endif
643 so->so_state &= ~SS_RCVATMARK;
644 len = uio->uio_resid;
645 if (so->so_oobmark && len > so->so_oobmark - offset)
646 len = so->so_oobmark - offset;
647 if (len > m->m_len - moff)
648 len = m->m_len - moff;
649 /*
650 * If mp is set, just pass back the mbufs.
651 * Otherwise copy them out via the uio, then free.
652 * Sockbuf must be consistent here (points to current mbuf,
653 * it points to next record) when we drop priority;
654 * we must note any additions to the sockbuf when we
655 * block interrupts again.
656 */
657 if (mp == 0) {
658 splx(s);
659 error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio);
660 s = splnet();
661 } else
662 uio->uio_resid -= len;
663 if (len == m->m_len - moff) {
664 if (m->m_flags & M_EOR)
665 flags |= MSG_EOR;
666 if (flags & MSG_PEEK) {
667 m = m->m_next;
668 moff = 0;
669 } else {
670 nextrecord = m->m_nextpkt;
671 sbfree(&so->so_rcv, m);
672 if (mp) {
673 *mp = m;
674 mp = &m->m_next;
675 so->so_rcv.sb_mb = m = m->m_next;
676 *mp = (struct mbuf *)0;
677 } else {
678 MFREE(m, so->so_rcv.sb_mb);
679 m = so->so_rcv.sb_mb;
680 }
681 if (m)
682 m->m_nextpkt = nextrecord;
683 }
684 } else {
685 if (flags & MSG_PEEK)
686 moff += len;
687 else {
688 if (mp)
689 *mp = m_copym(m, 0, len, M_WAIT);
690 m->m_data += len;
691 m->m_len -= len;
692 so->so_rcv.sb_cc -= len;
693 }
694 }
695 if (so->so_oobmark) {
696 if ((flags & MSG_PEEK) == 0) {
697 so->so_oobmark -= len;
698 if (so->so_oobmark == 0) {
699 so->so_state |= SS_RCVATMARK;
700 break;
701 }
702 } else
703 offset += len;
704 }
705 if (flags & MSG_EOR)
706 break;
707 /*
708 * If the MSG_WAITALL flag is set (for non-atomic socket),
709 * we must not quit until "uio->uio_resid == 0" or an error
710 * termination. If a signal/timeout occurs, return
711 * with a short count but without error.
712 * Keep sockbuf locked against other readers.
713 */
714 while (flags & MSG_WAITALL && m == 0 && uio->uio_resid > 0 &&
715 !sosendallatonce(so)) {
716 if (so->so_error || so->so_state & SS_CANTRCVMORE)
717 break;
718 error = sbwait(&so->so_rcv);
719 if (error) {
720 sbunlock(&so->so_rcv);
721 splx(s);
722 return (0);
723 }
724 if (m = so->so_rcv.sb_mb)
725 nextrecord = m->m_nextpkt;
726 }
727 }
728 if ((flags & MSG_PEEK) == 0) {
729 if (m == 0)
730 so->so_rcv.sb_mb = nextrecord;
731 else if (pr->pr_flags & PR_ATOMIC) {
732 flags |= MSG_TRUNC;
733 (void) sbdroprecord(&so->so_rcv);
734 }
735 if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
736 (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
737 (struct mbuf *)flags, (struct mbuf *)0,
738 (struct mbuf *)0);
739 }
740 if (flagsp)
741 *flagsp |= flags;
742release:
743 sbunlock(&so->so_rcv);
744 splx(s);
745 return (error);
746}
747
748soshutdown(so, how)
749 register struct socket *so;
750 register int how;
751{
752 register struct protosw *pr = so->so_proto;
753
754 how++;
755 if (how & FREAD)
756 sorflush(so);
757 if (how & FWRITE)
758 return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN,
759 (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
760 return (0);
761}
762
763sorflush(so)
764 register struct socket *so;
765{
766 register struct sockbuf *sb = &so->so_rcv;
767 register struct protosw *pr = so->so_proto;
768 register int s;
769 struct sockbuf asb;
770
771 sb->sb_flags |= SB_NOINTR;
772 (void) sblock(sb);
773 s = splimp();
774 socantrcvmore(so);
775 sbunlock(sb);
776 asb = *sb;
777 bzero((caddr_t)sb, sizeof (*sb));
778 splx(s);
779 if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose)
780 (*pr->pr_domain->dom_dispose)(asb.sb_mb);
781 sbrelease(&asb);
782}
783
784sosetopt(so, level, optname, m0)
785 register struct socket *so;
786 int level, optname;
787 struct mbuf *m0;
788{
789 int error = 0;
790 register struct mbuf *m = m0;
791
792 if (level != SOL_SOCKET) {
793 if (so->so_proto && so->so_proto->pr_ctloutput)
794 return ((*so->so_proto->pr_ctloutput)
795 (PRCO_SETOPT, so, level, optname, &m0));
796 error = ENOPROTOOPT;
797 } else {
798 switch (optname) {
799
800 case SO_LINGER:
801 if (m == NULL || m->m_len != sizeof (struct linger)) {
802 error = EINVAL;
803 goto bad;
804 }
805 so->so_linger = mtod(m, struct linger *)->l_linger;
806 /* fall thru... */
807
808 case SO_DEBUG:
809 case SO_KEEPALIVE:
810 case SO_DONTROUTE:
811 case SO_USELOOPBACK:
812 case SO_BROADCAST:
813 case SO_REUSEADDR:
814 case SO_OOBINLINE:
815 if (m == NULL || m->m_len < sizeof (int)) {
816 error = EINVAL;
817 goto bad;
818 }
819 if (*mtod(m, int *))
820 so->so_options |= optname;
821 else
822 so->so_options &= ~optname;
823 break;
824
825 case SO_SNDBUF:
826 case SO_RCVBUF:
827 case SO_SNDLOWAT:
828 case SO_RCVLOWAT:
829 if (m == NULL || m->m_len < sizeof (int)) {
830 error = EINVAL;
831 goto bad;
832 }
833 switch (optname) {
834
835 case SO_SNDBUF:
836 case SO_RCVBUF:
837 if (sbreserve(optname == SO_SNDBUF ?
838 &so->so_snd : &so->so_rcv,
839 (u_long) *mtod(m, int *)) == 0) {
840 error = ENOBUFS;
841 goto bad;
842 }
843 break;
844
845 case SO_SNDLOWAT:
846 so->so_snd.sb_lowat = *mtod(m, int *);
847 break;
848 case SO_RCVLOWAT:
849 so->so_rcv.sb_lowat = *mtod(m, int *);
850 break;
851 }
852 break;
853
854 case SO_SNDTIMEO:
855 case SO_RCVTIMEO:
856 {
857 struct timeval *tv;
858 short val;
859
860 if (m == NULL || m->m_len < sizeof (*tv)) {
861 error = EINVAL;
862 goto bad;
863 }
864 tv = mtod(m, struct timeval *);
865 if (tv->tv_sec > SHRT_MAX / hz - hz) {
866 error = EDOM;
867 goto bad;
868 }
869 val = tv->tv_sec * hz + tv->tv_usec / tick;
870
871 switch (optname) {
872
873 case SO_SNDTIMEO:
874 so->so_snd.sb_timeo = val;
875 break;
876 case SO_RCVTIMEO:
877 so->so_rcv.sb_timeo = val;
878 break;
879 }
880 break;
881 }
882
883 default:
884 error = ENOPROTOOPT;
885 break;
886 }
887 }
888bad:
889 if (m)
890 (void) m_free(m);
891 return (error);
892}
893
894sogetopt(so, level, optname, mp)
895 register struct socket *so;
896 int level, optname;
897 struct mbuf **mp;
898{
899 register struct mbuf *m;
900
901 if (level != SOL_SOCKET) {
902 if (so->so_proto && so->so_proto->pr_ctloutput) {
903 return ((*so->so_proto->pr_ctloutput)
904 (PRCO_GETOPT, so, level, optname, mp));
905 } else
906 return (ENOPROTOOPT);
907 } else {
908 m = m_get(M_WAIT, MT_SOOPTS);
909 m->m_len = sizeof (int);
910
911 switch (optname) {
912
913 case SO_LINGER:
914 m->m_len = sizeof (struct linger);
915 mtod(m, struct linger *)->l_onoff =
916 so->so_options & SO_LINGER;
917 mtod(m, struct linger *)->l_linger = so->so_linger;
918 break;
919
920 case SO_USELOOPBACK:
921 case SO_DONTROUTE:
922 case SO_DEBUG:
923 case SO_KEEPALIVE:
924 case SO_REUSEADDR:
925 case SO_BROADCAST:
926 case SO_OOBINLINE:
927 *mtod(m, int *) = so->so_options & optname;
928 break;
929
930 case SO_TYPE:
931 *mtod(m, int *) = so->so_type;
932 break;
933
934 case SO_ERROR:
935 *mtod(m, int *) = so->so_error;
936 so->so_error = 0;
937 break;
938
939 case SO_SNDBUF:
940 *mtod(m, int *) = so->so_snd.sb_hiwat;
941 break;
942
943 case SO_RCVBUF:
944 *mtod(m, int *) = so->so_rcv.sb_hiwat;
945 break;
946
947 case SO_SNDLOWAT:
948 *mtod(m, int *) = so->so_snd.sb_lowat;
949 break;
950
951 case SO_RCVLOWAT:
952 *mtod(m, int *) = so->so_rcv.sb_lowat;
953 break;
954
955 case SO_SNDTIMEO:
956 case SO_RCVTIMEO:
957 {
958 int val = (optname == SO_SNDTIMEO ?
959 so->so_snd.sb_timeo : so->so_rcv.sb_timeo);
960
961 m->m_len = sizeof(struct timeval);
962 mtod(m, struct timeval *)->tv_sec = val / hz;
963 mtod(m, struct timeval *)->tv_usec =
964 (val % hz) / tick;
965 break;
966 }
967
968 default:
969 (void)m_free(m);
970 return (ENOPROTOOPT);
971 }
972 *mp = m;
973 return (0);
974 }
975}
976
977sohasoutofband(so)
978 register struct socket *so;
979{
980 struct proc *p;
981
982 if (so->so_pgid < 0)
983 gsignal(-so->so_pgid, SIGURG);
984 else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0)
985 psignal(p, SIGURG);
986 if (so->so_rcv.sb_sel) {
987 selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL);
988 so->so_rcv.sb_sel = 0;
989 so->so_rcv.sb_flags &= ~SB_COLL;
990 }
991}