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