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