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