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