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