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