allow select on exceptional conditions to notify of urgent data pending;
[unix-history] / usr / src / sys / kern / uipc_socket.c
CommitLineData
da7c5cc6
KM
1/*
2 * Copyright (c) 1982 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
de2c74a5 6 * @(#)uipc_socket.c 6.17 (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) {
ac76a23d 157 error = sodisconnect(so, (struct mbuf *)0);
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{
cc15ab5d
BJ
218 int s = splnet();
219 int error;
ce9d8eb4 220
de2c74a5
MK
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))))
cc15ab5d 230 error = EISCONN;
de2c74a5
MK
231 else
232 error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT,
233 (struct mbuf *)0, nam, (struct mbuf *)0);
cc15ab5d
BJ
234 splx(s);
235 return (error);
ce9d8eb4
BJ
236}
237
88a7a62a
SL
238soconnect2(so1, so2)
239 register struct socket *so1;
240 struct socket *so2;
241{
242 int s = splnet();
243 int error;
244
5a48956d
SL
245 error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2,
246 (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0);
88a7a62a
SL
247 splx(s);
248 return (error);
249}
88a7a62a 250
cf012934 251sodisconnect(so, nam)
88a7a62a 252 register struct socket *so;
cf012934 253 struct mbuf *nam;
ce9d8eb4 254{
cc15ab5d
BJ
255 int s = splnet();
256 int error;
ce9d8eb4 257
cc15ab5d
BJ
258 if ((so->so_state & SS_ISCONNECTED) == 0) {
259 error = ENOTCONN;
260 goto bad;
ce9d8eb4 261 }
cc15ab5d
BJ
262 if (so->so_state & SS_ISDISCONNECTING) {
263 error = EALREADY;
264 goto bad;
ce9d8eb4 265 }
cf012934 266 error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT,
88a7a62a 267 (struct mbuf *)0, nam, (struct mbuf *)0);
cc15ab5d
BJ
268bad:
269 splx(s);
270 return (error);
ce9d8eb4
BJ
271}
272
cc15ab5d
BJ
273/*
274 * Send on a socket.
275 * If send must go all at once and message is larger than
276 * send buffering, then hard error.
277 * Lock against other senders.
278 * If must go all at once and not enough room now, then
279 * inform user that this would block and do nothing.
8250a099 280 * Otherwise, if nonblocking, send as much as possible.
cc15ab5d 281 */
88a7a62a 282sosend(so, nam, uio, flags, rights)
ce9d8eb4 283 register struct socket *so;
cf012934 284 struct mbuf *nam;
88a7a62a 285 register struct uio *uio;
970108c7 286 int flags;
88a7a62a 287 struct mbuf *rights;
ce9d8eb4 288{
cc15ab5d 289 struct mbuf *top = 0;
8250a099 290 register struct mbuf *m, **mp;
88a7a62a 291 register int space;
8250a099 292 int len, error = 0, s, dontroute, first = 1;
ce9d8eb4 293
5699bf69 294 if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat)
cc15ab5d 295 return (EMSGSIZE);
88a7a62a
SL
296 dontroute =
297 (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
298 (so->so_proto->pr_flags & PR_ATOMIC);
8250a099 299 u.u_ru.ru_msgsnd++;
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);
324 if (space <= 0 ||
09338457
MK
325 (sosendallatonce(so) && space < uio->uio_resid) ||
326 (uio->uio_resid >= CLBYTES && space < CLBYTES &&
327 so->so_snd.sb_cc >= CLBYTES &&
328 (so->so_state & SS_NBIO) == 0)) {
8250a099
MK
329 if (so->so_state & SS_NBIO) {
330 if (first)
331 error = EWOULDBLOCK;
332 splx(s);
333 goto release;
334 }
335 sbunlock(&so->so_snd);
336 sbwait(&so->so_snd);
337 splx(s);
338 goto restart;
339 }
340 }
4c078bb2 341 splx(s);
8250a099 342 mp = &top;
af9c562f 343 while (space > 0) {
8250a099
MK
344 register struct iovec *iov = uio->uio_iov;
345
8250a099 346 MGET(m, M_WAIT, MT_DATA);
8c0650b0 347 if (iov->iov_len >= NBPG && space >= CLBYTES) {
8250a099
MK
348 register struct mbuf *p;
349 MCLGET(p, 1);
350 if (p == 0)
351 goto nopages;
352 m->m_off = (int)p - (int)m;
64ac2a14 353 len = MIN(CLBYTES, iov->iov_len);
8c0650b0 354 space -= CLBYTES;
8250a099
MK
355 } else {
356nopages:
357 len = MIN(MLEN, iov->iov_len);
8c0650b0 358 space -= len;
8250a099
MK
359 }
360 error = uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio);
361 m->m_len = len;
362 *mp = m;
363 if (error)
364 goto release;
365 mp = &m->m_next;
af9c562f
MK
366 if (uio->uio_resid <= 0)
367 break;
368 while (uio->uio_iov->iov_len == 0) {
369 uio->uio_iov++;
370 uio->uio_iovcnt--;
371 if (uio->uio_iovcnt <= 0)
372 panic("sosend");
373 }
8250a099 374 }
af9c562f
MK
375 if (dontroute)
376 so->so_options |= SO_DONTROUTE;
377 s = splnet(); /* XXX */
378 error = (*so->so_proto->pr_usrreq)(so,
379 (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND,
380 top, (caddr_t)nam, rights);
381 splx(s);
382 if (dontroute)
383 so->so_options &= ~SO_DONTROUTE;
8c0650b0 384 rights = 0;
0f90f987 385 top = 0;
8250a099 386 first = 0;
c415b2e3 387 if (error)
8250a099
MK
388 break;
389 } while (uio->uio_resid);
cc15ab5d 390
ce9d8eb4 391release:
cc15ab5d 392 sbunlock(&so->so_snd);
0f90f987
BJ
393 if (top)
394 m_freem(top);
af9c562f
MK
395 if (error == EPIPE)
396 psignal(u.u_procp, SIGPIPE);
ce9d8eb4
BJ
397 return (error);
398}
399
88a7a62a 400soreceive(so, aname, uio, flags, rightsp)
ce9d8eb4 401 register struct socket *so;
cf012934 402 struct mbuf **aname;
88a7a62a 403 register struct uio *uio;
970108c7 404 int flags;
88a7a62a 405 struct mbuf **rightsp;
ce9d8eb4
BJ
406{
407 register struct mbuf *m, *n;
261a8548 408 register int len, error = 0, s, tomark;
88a7a62a 409 struct protosw *pr = so->so_proto;
261a8548 410 struct mbuf *nextrecord;
88a7a62a
SL
411 int moff;
412
413 if (rightsp)
414 *rightsp = 0;
415 if (aname)
416 *aname = 0;
417 if (flags & MSG_OOB) {
cce93e4b 418 m = m_get(M_WAIT, MT_DATA);
88a7a62a 419 error = (*pr->pr_usrreq)(so, PRU_RCVOOB,
de2c74a5 420 m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0);
a8d3bf7f 421 if (error)
5fe6f9d1 422 goto bad;
970108c7 423 do {
5fe6f9d1 424 len = uio->uio_resid;
970108c7
BJ
425 if (len > m->m_len)
426 len = m->m_len;
a8d3bf7f 427 error =
a29f7995 428 uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio);
970108c7 429 m = m_free(m);
a8d3bf7f 430 } while (uio->uio_resid && error == 0 && m);
5fe6f9d1 431bad:
970108c7 432 if (m)
39d536e6 433 m_freem(m);
a8d3bf7f 434 return (error);
970108c7 435 }
ce9d8eb4 436
cc15ab5d
BJ
437restart:
438 sblock(&so->so_rcv);
439 s = splnet();
440
441#define rcverr(errno) { error = errno; splx(s); goto release; }
ce9d8eb4 442 if (so->so_rcv.sb_cc == 0) {
4c078bb2
BJ
443 if (so->so_error) {
444 error = so->so_error;
445 so->so_error = 0;
446 splx(s);
447 goto release;
448 }
cc15ab5d
BJ
449 if (so->so_state & SS_CANTRCVMORE) {
450 splx(s);
451 goto release;
452 }
196d84fd
BJ
453 if ((so->so_state & SS_ISCONNECTED) == 0 &&
454 (so->so_proto->pr_flags & PR_CONNREQUIRED))
455 rcverr(ENOTCONN);
62364f0e 456 if (so->so_state & SS_NBIO)
4c078bb2 457 rcverr(EWOULDBLOCK);
cc15ab5d 458 sbunlock(&so->so_rcv);
2752c877 459 sbwait(&so->so_rcv);
a4f6d93d 460 splx(s);
cc15ab5d 461 goto restart;
ce9d8eb4 462 }
c7256358 463 u.u_ru.ru_msgrcv++;
92a533e6 464 m = so->so_rcv.sb_mb;
88a7a62a 465 if (pr->pr_flags & PR_ADDR) {
261a8548
MK
466 if (m == 0 || m->m_type != MT_SONAME)
467 panic("receive 1a");
468 if (flags & MSG_PEEK) {
469 if (aname)
970108c7 470 *aname = m_copy(m, 0, m->m_len);
970108c7 471 else
261a8548
MK
472 m = m->m_act;
473 } else {
474 if (aname) {
475 *aname = m;
476 sbfree(&so->so_rcv, m);
477if(m->m_next) panic("receive 1b");
478 so->so_rcv.sb_mb = m = m->m_act;
479 } else
480 m = sbdroprecord(&so->so_rcv);
481 }
482 }
483 if (m && m->m_type == MT_RIGHTS) {
484 if ((pr->pr_flags & PR_RIGHTS) == 0)
88a7a62a 485 panic("receive 2a");
261a8548
MK
486 if (flags & MSG_PEEK) {
487 if (rightsp)
88a7a62a 488 *rightsp = m_copy(m, 0, m->m_len);
261a8548
MK
489 else
490 m = m->m_act;
491 } else {
492 if (rightsp) {
493 *rightsp = m;
494 sbfree(&so->so_rcv, m);
495if(m->m_next) panic("receive 2b");
496 so->so_rcv.sb_mb = m = m->m_act;
497 } else
498 m = sbdroprecord(&so->so_rcv);
88a7a62a 499 }
cc15ab5d 500 }
faa9a50d 501 if (m == 0 || (m->m_type != MT_DATA && m->m_type != MT_HEADER))
261a8548 502 panic("receive 3");
970108c7
BJ
503 moff = 0;
504 tomark = so->so_oobmark;
261a8548 505 while (m && uio->uio_resid > 0 && error == 0) {
5699bf69 506 len = uio->uio_resid;
32a43ee2 507 so->so_state &= ~SS_RCVATMARK;
970108c7
BJ
508 if (tomark && len > tomark)
509 len = tomark;
8c0650b0 510 if (len > m->m_len - moff)
970108c7 511 len = m->m_len - moff;
ce9d8eb4 512 splx(s);
a8d3bf7f 513 error =
a29f7995 514 uiomove(mtod(m, caddr_t) + moff, (int)len, UIO_READ, uio);
ce9d8eb4 515 s = splnet();
8c0650b0 516 if (len == m->m_len - moff) {
261a8548
MK
517 if ((flags & MSG_PEEK) == 0) {
518 nextrecord = m->m_act;
970108c7
BJ
519 sbfree(&so->so_rcv, m);
520 MFREE(m, n);
261a8548
MK
521 if (m = n)
522 m->m_act = nextrecord;
e435773e 523 so->so_rcv.sb_mb = m;
261a8548
MK
524 } else
525 m = m->m_next;
970108c7 526 moff = 0;
ce9d8eb4 527 } else {
88a7a62a 528 if (flags & MSG_PEEK)
970108c7
BJ
529 moff += len;
530 else {
531 m->m_off += len;
532 m->m_len -= len;
533 so->so_rcv.sb_cc -= len;
534 }
ce9d8eb4 535 }
88a7a62a 536 if ((flags & MSG_PEEK) == 0 && so->so_oobmark) {
32a43ee2
BJ
537 so->so_oobmark -= len;
538 if (so->so_oobmark == 0) {
539 so->so_state |= SS_RCVATMARK;
540 break;
541 }
542 }
970108c7
BJ
543 if (tomark) {
544 tomark -= len;
545 if (tomark == 0)
546 break;
547 }
261a8548
MK
548 }
549 if ((flags & MSG_PEEK) == 0) {
550 if (m == 0)
551 so->so_rcv.sb_mb = nextrecord;
552 else if (pr->pr_flags & PR_ATOMIC)
553 (void) sbdroprecord(&so->so_rcv);
554 if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
555 (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
556 (struct mbuf *)0, (struct mbuf *)0);
557 }
cc15ab5d 558release:
ae921915 559 sbunlock(&so->so_rcv);
261a8548
MK
560 if (error == 0 && rightsp && *rightsp && pr->pr_domain->dom_externalize)
561 error = (*pr->pr_domain->dom_externalize)(*rightsp);
cc15ab5d 562 splx(s);
ae921915 563 return (error);
92a533e6
BJ
564}
565
98422daa 566soshutdown(so, how)
88a7a62a
SL
567 register struct socket *so;
568 register int how;
98422daa 569{
88a7a62a 570 register struct protosw *pr = so->so_proto;
98422daa
SL
571
572 how++;
88a7a62a
SL
573 if (how & FREAD)
574 sorflush(so);
98422daa 575 if (how & FWRITE)
88a7a62a
SL
576 return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN,
577 (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0));
98422daa
SL
578 return (0);
579}
580
88a7a62a
SL
581sorflush(so)
582 register struct socket *so;
583{
584 register struct sockbuf *sb = &so->so_rcv;
585 register struct protosw *pr = so->so_proto;
586 register int s;
587 struct sockbuf asb;
588
589 sblock(sb);
590 s = splimp();
591 socantrcvmore(so);
592 sbunlock(sb);
593 asb = *sb;
594 bzero((caddr_t)sb, sizeof (*sb));
595 splx(s);
261a8548
MK
596 if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose)
597 (*pr->pr_domain->dom_dispose)(asb.sb_mb);
88a7a62a
SL
598 sbrelease(&asb);
599}
600
bc2f5859 601sosetopt(so, level, optname, m0)
88a7a62a 602 register struct socket *so;
98422daa 603 int level, optname;
bc2f5859 604 struct mbuf *m0;
98422daa 605{
61ec2127 606 int error = 0;
bc2f5859 607 register struct mbuf *m = m0;
98422daa 608
61ec2127 609 if (level != SOL_SOCKET) {
cbe54390
MK
610 if (so->so_proto && so->so_proto->pr_ctloutput)
611 return ((*so->so_proto->pr_ctloutput)
bc2f5859 612 (PRCO_SETOPT, so, level, optname, &m0));
cbe54390
MK
613 error = ENOPROTOOPT;
614 } else {
615 switch (optname) {
98422daa 616
cbe54390
MK
617 case SO_LINGER:
618 if (m == NULL || m->m_len != sizeof (struct linger)) {
619 error = EINVAL;
620 goto bad;
621 }
622 so->so_linger = mtod(m, struct linger *)->l_linger;
623 /* fall thru... */
624
625 case SO_DEBUG:
626 case SO_KEEPALIVE:
627 case SO_DONTROUTE:
628 case SO_USELOOPBACK:
629 case SO_BROADCAST:
630 case SO_REUSEADDR:
631 if (m == NULL || m->m_len < sizeof (int)) {
632 error = EINVAL;
633 goto bad;
634 }
635 if (*mtod(m, int *))
636 so->so_options |= optname;
637 else
638 so->so_options &= ~optname;
639 break;
98422daa 640
cbe54390
MK
641 case SO_SNDBUF:
642 case SO_RCVBUF:
643 case SO_SNDLOWAT:
644 case SO_RCVLOWAT:
645 case SO_SNDTIMEO:
646 case SO_RCVTIMEO:
647 if (m == NULL || m->m_len < sizeof (int)) {
648 error = EINVAL;
649 goto bad;
650 }
651 switch (optname) {
652
653 case SO_SNDBUF:
654 case SO_RCVBUF:
655 if (sbreserve(optname == SO_SNDBUF ? &so->so_snd :
656 &so->so_rcv, *mtod(m, int *)) == 0) {
657 error = ENOBUFS;
658 goto bad;
659 }
660 break;
661
662 case SO_SNDLOWAT:
663 so->so_snd.sb_lowat = *mtod(m, int *);
664 break;
665 case SO_RCVLOWAT:
666 so->so_rcv.sb_lowat = *mtod(m, int *);
667 break;
668 case SO_SNDTIMEO:
669 so->so_snd.sb_timeo = *mtod(m, int *);
670 break;
671 case SO_RCVTIMEO:
672 so->so_rcv.sb_timeo = *mtod(m, int *);
673 break;
674 }
675 break;
676
677 default:
678 error = ENOPROTOOPT;
679 break;
680 }
98422daa 681 }
61ec2127
SL
682bad:
683 if (m)
684 (void) m_free(m);
685 return (error);
98422daa
SL
686}
687
61ec2127 688sogetopt(so, level, optname, mp)
88a7a62a 689 register struct socket *so;
98422daa 690 int level, optname;
61ec2127 691 struct mbuf **mp;
98422daa 692{
61ec2127 693 register struct mbuf *m;
98422daa 694
cbe54390
MK
695 if (level != SOL_SOCKET) {
696 if (so->so_proto && so->so_proto->pr_ctloutput) {
697 return ((*so->so_proto->pr_ctloutput)
698 (PRCO_GETOPT, so, level, optname, mp));
699 } else
700 return (ENOPROTOOPT);
701 } else {
61ec2127 702 m = m_get(M_WAIT, MT_SOOPTS);
cbe54390
MK
703 switch (optname) {
704
705 case SO_LINGER:
706 m->m_len = sizeof (struct linger);
707 mtod(m, struct linger *)->l_onoff =
708 so->so_options & SO_LINGER;
709 mtod(m, struct linger *)->l_linger = so->so_linger;
710 break;
711
712 case SO_USELOOPBACK:
713 case SO_DONTROUTE:
714 case SO_DEBUG:
715 case SO_KEEPALIVE:
716 case SO_REUSEADDR:
717 case SO_BROADCAST:
718 m->m_len = sizeof (int);
719 *mtod(m, int *) = so->so_options & optname;
720 break;
721
de2c74a5
MK
722 case SO_ERROR:
723 *mtod(m, int *) = so->so_error;
724 so->so_error = 0;
725 break;
726
cbe54390
MK
727 case SO_SNDBUF:
728 *mtod(m, int *) = so->so_snd.sb_hiwat;
729 break;
98422daa 730
cbe54390
MK
731 case SO_RCVBUF:
732 *mtod(m, int *) = so->so_rcv.sb_hiwat;
733 break;
734
735 case SO_SNDLOWAT:
736 *mtod(m, int *) = so->so_snd.sb_lowat;
737 break;
738
739 case SO_RCVLOWAT:
740 *mtod(m, int *) = so->so_rcv.sb_lowat;
741 break;
742
743 case SO_SNDTIMEO:
744 *mtod(m, int *) = so->so_snd.sb_timeo;
745 break;
746
747 case SO_RCVTIMEO:
748 *mtod(m, int *) = so->so_rcv.sb_timeo;
749 break;
750
751 default:
752 m_free(m);
753 return (ENOPROTOOPT);
754 }
755 *mp = m;
756 return (0);
98422daa 757 }
98422daa
SL
758}
759
edebca28 760sohasoutofband(so)
88a7a62a 761 register struct socket *so;
edebca28 762{
3d190e86 763 struct proc *p;
edebca28 764
3d190e86
MK
765 if (so->so_pgrp < 0)
766 gsignal(-so->so_pgrp, SIGURG);
767 else if (so->so_pgrp > 0 && (p = pfind(so->so_pgrp)) != 0)
768 psignal(p, SIGURG);
de2c74a5
MK
769 if (so->so_rcv.sb_sel) {
770 selwakeup(so->so_rcv.sb_sel, so->so_rcv.sb_flags & SB_COLL);
771 so->so_rcv.sb_sel = 0;
772 so->so_rcv.sb_flags &= ~SB_COLL;
773 }
edebca28 774}