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