Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
ad787160 C |
2 | * Copyright (c) 1982, 1986, 1988, 1990, 1993 |
3 | * The Regents of the University of California. All rights reserved. | |
da7c5cc6 | 4 | * |
ad787160 C |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * 3. All advertising materials mentioning features or use of this software | |
14 | * must display the following acknowledgement: | |
15 | * This product includes software developed by the University of | |
16 | * California, Berkeley and its contributors. | |
17 | * 4. Neither the name of the University nor the names of its contributors | |
18 | * may be used to endorse or promote products derived from this software | |
19 | * without specific prior written permission. | |
5b519e94 | 20 | * |
ad787160 C |
21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
32 | * | |
33 | * @(#)uipc_socket.c 8.1 (Berkeley) 6/10/93 | |
da7c5cc6 | 34 | */ |
ce9d8eb4 | 35 | |
38a01dbe KB |
36 | #include <sys/param.h> |
37 | #include <sys/systm.h> | |
38 | #include <sys/proc.h> | |
39 | #include <sys/file.h> | |
40 | #include <sys/malloc.h> | |
41 | #include <sys/mbuf.h> | |
42 | #include <sys/domain.h> | |
43 | #include <sys/kernel.h> | |
44 | #include <sys/protosw.h> | |
45 | #include <sys/socket.h> | |
46 | #include <sys/socketvar.h> | |
47 | #include <sys/resourcevar.h> | |
ce9d8eb4 | 48 | |
ce9d8eb4 | 49 | /* |
cf012934 BJ |
50 | * Socket operation routines. |
51 | * These routines are called by the routines in | |
52 | * sys_socket.c or from a system process, and | |
53 | * implement the semantics of socket operations by | |
54 | * switching out to the protocol specific routines. | |
ce9d8eb4 | 55 | */ |
a8d3bf7f | 56 | /*ARGSUSED*/ |
98422daa | 57 | socreate(dom, aso, type, proto) |
39f2b629 | 58 | int dom; |
ce9d8eb4 | 59 | struct socket **aso; |
88a7a62a SL |
60 | register int type; |
61 | int proto; | |
ce9d8eb4 | 62 | { |
dff5c020 | 63 | struct proc *p = curproc; /* XXX */ |
ce9d8eb4 BJ |
64 | register struct protosw *prp; |
65 | register struct socket *so; | |
88a7a62a | 66 | register int error; |
cc15ab5d | 67 | |
cc15ab5d | 68 | if (proto) |
8c0650b0 | 69 | prp = pffindproto(dom, proto, type); |
cc15ab5d | 70 | else |
4f083fd7 | 71 | prp = pffindtype(dom, type); |
2b6d14b8 | 72 | if (prp == 0 || prp->pr_usrreq == 0) |
cc15ab5d | 73 | return (EPROTONOSUPPORT); |
cf012934 BJ |
74 | if (prp->pr_type != type) |
75 | return (EPROTOTYPE); | |
a2aebb63 KS |
76 | MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_WAIT); |
77 | bzero((caddr_t)so, sizeof(*so)); | |
4f083fd7 | 78 | so->so_type = type; |
dff5c020 | 79 | if (p->p_ucred->cr_uid == 0) |
62364f0e | 80 | so->so_state = SS_PRIV; |
ce9d8eb4 | 81 | so->so_proto = prp; |
88a7a62a SL |
82 | error = |
83 | (*prp->pr_usrreq)(so, PRU_ATTACH, | |
8c0650b0 | 84 | (struct mbuf *)0, (struct mbuf *)proto, (struct mbuf *)0); |
b91acce4 | 85 | if (error) { |
90aaea96 | 86 | so->so_state |= SS_NOFDREF; |
de48daf3 | 87 | sofree(so); |
cc15ab5d | 88 | return (error); |
ce9d8eb4 BJ |
89 | } |
90 | *aso = so; | |
91 | return (0); | |
92 | } | |
93 | ||
98422daa | 94 | sobind(so, nam) |
cf012934 BJ |
95 | struct socket *so; |
96 | struct mbuf *nam; | |
cf012934 BJ |
97 | { |
98 | int s = splnet(); | |
99 | int error; | |
100 | ||
7c4ec3aa MK |
101 | error = |
102 | (*so->so_proto->pr_usrreq)(so, PRU_BIND, | |
88a7a62a | 103 | (struct mbuf *)0, nam, (struct mbuf *)0); |
cf012934 BJ |
104 | splx(s); |
105 | return (error); | |
106 | } | |
107 | ||
108 | solisten(so, backlog) | |
88a7a62a | 109 | register struct socket *so; |
cf012934 BJ |
110 | int backlog; |
111 | { | |
88a7a62a | 112 | int s = splnet(), error; |
cf012934 | 113 | |
88a7a62a SL |
114 | error = |
115 | (*so->so_proto->pr_usrreq)(so, PRU_LISTEN, | |
116 | (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); | |
cf012934 BJ |
117 | if (error) { |
118 | splx(s); | |
119 | return (error); | |
120 | } | |
629e51da | 121 | if (so->so_q == 0) |
cf012934 | 122 | so->so_options |= SO_ACCEPTCONN; |
cf012934 BJ |
123 | if (backlog < 0) |
124 | backlog = 0; | |
2557c1fc | 125 | so->so_qlimit = min(backlog, SOMAXCONN); |
9e87be97 | 126 | splx(s); |
cf012934 BJ |
127 | return (0); |
128 | } | |
129 | ||
ae921915 | 130 | sofree(so) |
88a7a62a | 131 | register struct socket *so; |
ae921915 BJ |
132 | { |
133 | ||
bb73a14e MK |
134 | if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) |
135 | return; | |
90aaea96 BJ |
136 | if (so->so_head) { |
137 | if (!soqremque(so, 0) && !soqremque(so, 1)) | |
138 | panic("sofree dq"); | |
139 | so->so_head = 0; | |
140 | } | |
4ad99bae | 141 | sbrelease(&so->so_snd); |
88a7a62a | 142 | sorflush(so); |
a2aebb63 | 143 | FREE(so, M_SOCKET); |
ae921915 BJ |
144 | } |
145 | ||
92a533e6 | 146 | /* |
cc15ab5d BJ |
147 | * Close a socket on last file table reference removal. |
148 | * Initiate disconnect if connected. | |
149 | * Free socket when disconnect complete. | |
92a533e6 | 150 | */ |
88a7a62a | 151 | soclose(so) |
92a533e6 | 152 | register struct socket *so; |
92a533e6 | 153 | { |
cc15ab5d | 154 | int s = splnet(); /* conservative */ |
e58562f2 | 155 | int error = 0; |
cc15ab5d | 156 | |
90aaea96 | 157 | if (so->so_options & SO_ACCEPTCONN) { |
629e51da | 158 | while (so->so_q0) |
26225f25 | 159 | (void) soabort(so->so_q0); |
629e51da | 160 | while (so->so_q) |
26225f25 | 161 | (void) soabort(so->so_q); |
90aaea96 | 162 | } |
cc15ab5d BJ |
163 | if (so->so_pcb == 0) |
164 | goto discard; | |
165 | if (so->so_state & SS_ISCONNECTED) { | |
166 | if ((so->so_state & SS_ISDISCONNECTING) == 0) { | |
dedd6629 | 167 | error = sodisconnect(so); |
88a7a62a SL |
168 | if (error) |
169 | goto drop; | |
cc15ab5d | 170 | } |
98422daa | 171 | if (so->so_options & SO_LINGER) { |
b8acc34d | 172 | if ((so->so_state & SS_ISDISCONNECTING) && |
88a7a62a SL |
173 | (so->so_state & SS_NBIO)) |
174 | goto drop; | |
b8acc34d | 175 | while (so->so_state & SS_ISCONNECTED) |
83866636 MK |
176 | if (error = tsleep((caddr_t)&so->so_timeo, |
177 | PSOCK | PCATCH, netcls, so->so_linger)) | |
178 | break; | |
72857acf | 179 | } |
cc15ab5d | 180 | } |
89900a09 | 181 | drop: |
37c0974a | 182 | if (so->so_pcb) { |
88a7a62a SL |
183 | int error2 = |
184 | (*so->so_proto->pr_usrreq)(so, PRU_DETACH, | |
185 | (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); | |
186 | if (error == 0) | |
187 | error = error2; | |
37c0974a | 188 | } |
cc15ab5d | 189 | discard: |
26225f25 SL |
190 | if (so->so_state & SS_NOFDREF) |
191 | panic("soclose: NOFDREF"); | |
90aaea96 | 192 | so->so_state |= SS_NOFDREF; |
4ad99bae | 193 | sofree(so); |
cc15ab5d | 194 | splx(s); |
88a7a62a | 195 | return (error); |
92a533e6 BJ |
196 | } |
197 | ||
26225f25 SL |
198 | /* |
199 | * Must be called at splnet... | |
200 | */ | |
201 | soabort(so) | |
202 | struct socket *so; | |
203 | { | |
26225f25 | 204 | |
88a7a62a SL |
205 | return ( |
206 | (*so->so_proto->pr_usrreq)(so, PRU_ABORT, | |
207 | (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); | |
92a533e6 BJ |
208 | } |
209 | ||
98422daa | 210 | soaccept(so, nam) |
88a7a62a | 211 | register struct socket *so; |
cf012934 | 212 | struct mbuf *nam; |
2b4b57cd BJ |
213 | { |
214 | int s = splnet(); | |
215 | int error; | |
216 | ||
26225f25 SL |
217 | if ((so->so_state & SS_NOFDREF) == 0) |
218 | panic("soaccept: !NOFDREF"); | |
98422daa | 219 | so->so_state &= ~SS_NOFDREF; |
cf012934 | 220 | error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, |
88a7a62a | 221 | (struct mbuf *)0, nam, (struct mbuf *)0); |
2b4b57cd BJ |
222 | splx(s); |
223 | return (error); | |
224 | } | |
225 | ||
98422daa | 226 | soconnect(so, nam) |
88a7a62a | 227 | register struct socket *so; |
cf012934 | 228 | struct mbuf *nam; |
ce9d8eb4 | 229 | { |
7bcf9d13 | 230 | int s; |
cc15ab5d | 231 | int error; |
ce9d8eb4 | 232 | |
7bcf9d13 MK |
233 | if (so->so_options & SO_ACCEPTCONN) |
234 | return (EOPNOTSUPP); | |
235 | s = splnet(); | |
de2c74a5 MK |
236 | /* |
237 | * If protocol is connection-based, can only connect once. | |
238 | * Otherwise, if connected, try to disconnect first. | |
239 | * This allows user to disconnect by connecting to, e.g., | |
240 | * a null address. | |
241 | */ | |
242 | if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && | |
243 | ((so->so_proto->pr_flags & PR_CONNREQUIRED) || | |
244 | (error = sodisconnect(so)))) | |
cc15ab5d | 245 | error = EISCONN; |
de2c74a5 MK |
246 | else |
247 | error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, | |
248 | (struct mbuf *)0, nam, (struct mbuf *)0); | |
cc15ab5d BJ |
249 | splx(s); |
250 | return (error); | |
ce9d8eb4 BJ |
251 | } |
252 | ||
88a7a62a SL |
253 | soconnect2(so1, so2) |
254 | register struct socket *so1; | |
255 | struct socket *so2; | |
256 | { | |
257 | int s = splnet(); | |
258 | int error; | |
259 | ||
5a48956d SL |
260 | error = (*so1->so_proto->pr_usrreq)(so1, PRU_CONNECT2, |
261 | (struct mbuf *)0, (struct mbuf *)so2, (struct mbuf *)0); | |
88a7a62a SL |
262 | splx(s); |
263 | return (error); | |
264 | } | |
88a7a62a | 265 | |
dedd6629 | 266 | sodisconnect(so) |
88a7a62a | 267 | register struct socket *so; |
ce9d8eb4 | 268 | { |
cc15ab5d BJ |
269 | int s = splnet(); |
270 | int error; | |
ce9d8eb4 | 271 | |
cc15ab5d BJ |
272 | if ((so->so_state & SS_ISCONNECTED) == 0) { |
273 | error = ENOTCONN; | |
274 | goto bad; | |
ce9d8eb4 | 275 | } |
cc15ab5d BJ |
276 | if (so->so_state & SS_ISDISCONNECTING) { |
277 | error = EALREADY; | |
278 | goto bad; | |
ce9d8eb4 | 279 | } |
cf012934 | 280 | error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, |
dedd6629 | 281 | (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0); |
cc15ab5d BJ |
282 | bad: |
283 | splx(s); | |
284 | return (error); | |
ce9d8eb4 BJ |
285 | } |
286 | ||
440c48bf | 287 | #define SBLOCKWAIT(f) (((f) & MSG_DONTWAIT) ? M_NOWAIT : M_WAITOK) |
cc15ab5d BJ |
288 | /* |
289 | * Send on a socket. | |
290 | * If send must go all at once and message is larger than | |
291 | * send buffering, then hard error. | |
292 | * Lock against other senders. | |
293 | * If must go all at once and not enough room now, then | |
294 | * inform user that this would block and do nothing. | |
8250a099 | 295 | * Otherwise, if nonblocking, send as much as possible. |
7c4ec3aa MK |
296 | * The data to be sent is described by "uio" if nonzero, |
297 | * otherwise by the mbuf chain "top" (which must be null | |
298 | * if uio is not). Data provided in mbuf chain must be small | |
299 | * enough to send all at once. | |
300 | * | |
301 | * Returns nonzero on error, timeout or signal; callers | |
302 | * must check for short counts if EINTR/ERESTART are returned. | |
303 | * Data and control buffers are freed on return. | |
cc15ab5d | 304 | */ |
4b9db1f5 | 305 | sosend(so, addr, uio, top, control, flags) |
ce9d8eb4 | 306 | register struct socket *so; |
7c4ec3aa MK |
307 | struct mbuf *addr; |
308 | struct uio *uio; | |
309 | struct mbuf *top; | |
2967f28e | 310 | struct mbuf *control; |
7c4ec3aa | 311 | int flags; |
ce9d8eb4 | 312 | { |
dff5c020 | 313 | struct proc *p = curproc; /* XXX */ |
7c4ec3aa | 314 | struct mbuf **mp; |
2557c1fc | 315 | register struct mbuf *m; |
7c4ec3aa MK |
316 | register long space, len, resid; |
317 | int clen = 0, error, s, dontroute, mlen; | |
318 | int atomic = sosendallatonce(so) || top; | |
ce9d8eb4 | 319 | |
7c4ec3aa MK |
320 | if (uio) |
321 | resid = uio->uio_resid; | |
322 | else | |
323 | resid = top->m_pkthdr.len; | |
88a7a62a SL |
324 | dontroute = |
325 | (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && | |
326 | (so->so_proto->pr_flags & PR_ATOMIC); | |
dff5c020 | 327 | p->p_stats->p_ru.ru_msgsnd++; |
2967f28e | 328 | if (control) |
7c4ec3aa | 329 | clen = control->m_len; |
cc15ab5d BJ |
330 | #define snderr(errno) { error = errno; splx(s); goto release; } |
331 | ||
8250a099 | 332 | restart: |
440c48bf | 333 | if (error = sblock(&so->so_snd, SBLOCKWAIT(flags))) |
7c4ec3aa | 334 | goto out; |
8250a099 MK |
335 | do { |
336 | s = splnet(); | |
af9c562f | 337 | if (so->so_state & SS_CANTSENDMORE) |
8250a099 | 338 | snderr(EPIPE); |
a2aebb63 KS |
339 | if (so->so_error) |
340 | snderr(so->so_error); | |
8250a099 | 341 | if ((so->so_state & SS_ISCONNECTED) == 0) { |
a2aebb63 | 342 | if (so->so_proto->pr_flags & PR_CONNREQUIRED) { |
f3bf27ac KS |
343 | if ((so->so_state & SS_ISCONFIRMING) == 0 && |
344 | !(resid == 0 && clen != 0)) | |
a2aebb63 | 345 | snderr(ENOTCONN); |
7c4ec3aa | 346 | } else if (addr == 0) |
8250a099 MK |
347 | snderr(EDESTADDRREQ); |
348 | } | |
7c4ec3aa | 349 | space = sbspace(&so->so_snd); |
8250a099 | 350 | if (flags & MSG_OOB) |
7c4ec3aa | 351 | space += 1024; |
440c48bf KM |
352 | if (atomic && resid > so->so_snd.sb_hiwat || |
353 | clen > so->so_snd.sb_hiwat) | |
354 | snderr(EMSGSIZE); | |
355 | if (space < resid + clen && uio && | |
7c4ec3aa | 356 | (atomic || space < so->so_snd.sb_lowat || space < clen)) { |
7c4ec3aa MK |
357 | if (so->so_state & SS_NBIO) |
358 | snderr(EWOULDBLOCK); | |
359 | sbunlock(&so->so_snd); | |
4b9db1f5 | 360 | error = sbwait(&so->so_snd); |
7c4ec3aa MK |
361 | splx(s); |
362 | if (error) | |
363 | goto out; | |
364 | goto restart; | |
8250a099 | 365 | } |
4c078bb2 | 366 | splx(s); |
8250a099 | 367 | mp = ⊤ |
7c4ec3aa | 368 | space -= clen; |
4b9db1f5 MK |
369 | do { |
370 | if (uio == NULL) { | |
7c4ec3aa MK |
371 | /* |
372 | * Data is prepackaged in "top". | |
373 | */ | |
374 | resid = 0; | |
375 | if (flags & MSG_EOR) | |
376 | top->m_flags |= M_EOR; | |
4b9db1f5 | 377 | } else do { |
2557c1fc MK |
378 | if (top == 0) { |
379 | MGETHDR(m, M_WAIT, MT_DATA); | |
380 | mlen = MHLEN; | |
381 | m->m_pkthdr.len = 0; | |
382 | m->m_pkthdr.rcvif = (struct ifnet *)0; | |
383 | } else { | |
384 | MGET(m, M_WAIT, MT_DATA); | |
385 | mlen = MLEN; | |
386 | } | |
7c4ec3aa | 387 | if (resid >= MINCLSIZE && space >= MCLBYTES) { |
2557c1fc MK |
388 | MCLGET(m, M_WAIT); |
389 | if ((m->m_flags & M_EXT) == 0) | |
8250a099 | 390 | goto nopages; |
2557c1fc MK |
391 | mlen = MCLBYTES; |
392 | #ifdef MAPPED_MBUFS | |
7c4ec3aa | 393 | len = min(MCLBYTES, resid); |
2557c1fc | 394 | #else |
9859687a | 395 | if (atomic && top == 0) { |
7c4ec3aa MK |
396 | len = min(MCLBYTES - max_hdr, resid); |
397 | m->m_data += max_hdr; | |
415a9324 KS |
398 | } else |
399 | len = min(MCLBYTES, resid); | |
2557c1fc MK |
400 | #endif |
401 | space -= MCLBYTES; | |
8250a099 MK |
402 | } else { |
403 | nopages: | |
7c4ec3aa | 404 | len = min(min(mlen, resid), space); |
8c0650b0 | 405 | space -= len; |
2557c1fc MK |
406 | /* |
407 | * For datagram protocols, leave room | |
408 | * for protocol headers in first mbuf. | |
409 | */ | |
84efcd38 | 410 | if (atomic && top == 0 && len < mlen) |
2557c1fc | 411 | MH_ALIGN(m, len); |
8250a099 | 412 | } |
179cd11f | 413 | error = uiomove(mtod(m, caddr_t), (int)len, uio); |
7c4ec3aa | 414 | resid = uio->uio_resid; |
8250a099 MK |
415 | m->m_len = len; |
416 | *mp = m; | |
2557c1fc | 417 | top->m_pkthdr.len += len; |
8250a099 MK |
418 | if (error) |
419 | goto release; | |
420 | mp = &m->m_next; | |
7c4ec3aa MK |
421 | if (resid <= 0) { |
422 | if (flags & MSG_EOR) | |
2557c1fc | 423 | top->m_flags |= M_EOR; |
af9c562f | 424 | break; |
2557c1fc MK |
425 | } |
426 | } while (space > 0 && atomic); | |
427 | if (dontroute) | |
428 | so->so_options |= SO_DONTROUTE; | |
429 | s = splnet(); /* XXX */ | |
430 | error = (*so->so_proto->pr_usrreq)(so, | |
431 | (flags & MSG_OOB) ? PRU_SENDOOB : PRU_SEND, | |
7c4ec3aa | 432 | top, addr, control); |
2557c1fc MK |
433 | splx(s); |
434 | if (dontroute) | |
435 | so->so_options &= ~SO_DONTROUTE; | |
7c4ec3aa MK |
436 | clen = 0; |
437 | control = 0; | |
2557c1fc MK |
438 | top = 0; |
439 | mp = ⊤ | |
2557c1fc MK |
440 | if (error) |
441 | goto release; | |
7c4ec3aa MK |
442 | } while (resid && space > 0); |
443 | } while (resid); | |
cc15ab5d | 444 | |
ce9d8eb4 | 445 | release: |
cc15ab5d | 446 | sbunlock(&so->so_snd); |
7c4ec3aa | 447 | out: |
0f90f987 BJ |
448 | if (top) |
449 | m_freem(top); | |
7c4ec3aa MK |
450 | if (control) |
451 | m_freem(control); | |
ce9d8eb4 BJ |
452 | return (error); |
453 | } | |
454 | ||
c34d38f4 MK |
455 | /* |
456 | * Implement receive operations on a socket. | |
457 | * We depend on the way that records are added to the sockbuf | |
458 | * by sbappend*. In particular, each record (mbufs linked through m_next) | |
459 | * must begin with an address if the protocol so specifies, | |
7c4ec3aa MK |
460 | * followed by an optional mbuf or mbufs containing ancillary data, |
461 | * and then zero or more mbufs of data. | |
c34d38f4 MK |
462 | * In order to avoid blocking network interrupts for the entire time here, |
463 | * we splx() while doing the actual copy to user space. | |
464 | * Although the sockbuf is locked, new data may still be appended, | |
465 | * and thus we must maintain consistency of the sockbuf during that time. | |
179cd11f | 466 | * |
7c4ec3aa | 467 | * The caller may receive the data as a single mbuf chain by supplying |
4b9db1f5 | 468 | * an mbuf **mp0 for use in returning the chain. The uio is then used |
7c4ec3aa | 469 | * only for the count in uio_resid. |
c34d38f4 | 470 | */ |
4b9db1f5 | 471 | soreceive(so, paddr, uio, mp0, controlp, flagsp) |
ce9d8eb4 | 472 | register struct socket *so; |
7c4ec3aa MK |
473 | struct mbuf **paddr; |
474 | struct uio *uio; | |
4b9db1f5 | 475 | struct mbuf **mp0; |
7c4ec3aa | 476 | struct mbuf **controlp; |
2557c1fc | 477 | int *flagsp; |
ce9d8eb4 | 478 | { |
4b9db1f5 MK |
479 | register struct mbuf *m, **mp; |
480 | register int flags, len, error, s, offset; | |
88a7a62a | 481 | struct protosw *pr = so->so_proto; |
7c4ec3aa MK |
482 | struct mbuf *nextrecord; |
483 | int moff, type; | |
34827683 | 484 | int orig_resid = uio->uio_resid; |
88a7a62a | 485 | |
4b9db1f5 | 486 | mp = mp0; |
7c4ec3aa MK |
487 | if (paddr) |
488 | *paddr = 0; | |
2557c1fc MK |
489 | if (controlp) |
490 | *controlp = 0; | |
491 | if (flagsp) | |
492 | flags = *flagsp &~ MSG_EOR; | |
179cd11f | 493 | else |
2557c1fc | 494 | flags = 0; |
88a7a62a | 495 | if (flags & MSG_OOB) { |
cce93e4b | 496 | m = m_get(M_WAIT, MT_DATA); |
88a7a62a | 497 | error = (*pr->pr_usrreq)(so, PRU_RCVOOB, |
de2c74a5 | 498 | m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0); |
a8d3bf7f | 499 | if (error) |
5fe6f9d1 | 500 | goto bad; |
970108c7 | 501 | do { |
7c4ec3aa MK |
502 | error = uiomove(mtod(m, caddr_t), |
503 | (int) min(uio->uio_resid, m->m_len), uio); | |
970108c7 | 504 | m = m_free(m); |
a8d3bf7f | 505 | } while (uio->uio_resid && error == 0 && m); |
5fe6f9d1 | 506 | bad: |
970108c7 | 507 | if (m) |
39d536e6 | 508 | m_freem(m); |
a8d3bf7f | 509 | return (error); |
970108c7 | 510 | } |
7c4ec3aa MK |
511 | if (mp) |
512 | *mp = (struct mbuf *)0; | |
4b9db1f5 | 513 | if (so->so_state & SS_ISCONFIRMING && uio->uio_resid) |
2557c1fc MK |
514 | (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, |
515 | (struct mbuf *)0, (struct mbuf *)0); | |
ce9d8eb4 | 516 | |
cc15ab5d | 517 | restart: |
440c48bf | 518 | if (error = sblock(&so->so_rcv, SBLOCKWAIT(flags))) |
83866636 | 519 | return (error); |
cc15ab5d BJ |
520 | s = splnet(); |
521 | ||
a2aebb63 | 522 | m = so->so_rcv.sb_mb; |
ba4350f5 MK |
523 | /* |
524 | * If we have less data than requested, block awaiting more | |
525 | * (subject to any timeout) if: | |
526 | * 1. the current count is less than the low water mark, or | |
527 | * 2. MSG_WAITALL is set, and it is possible to do the entire | |
528 | * receive operation at once if we block (resid <= hiwat). | |
440c48bf | 529 | * 3. MSG_DONTWAIT is not set |
ba4350f5 MK |
530 | * If MSG_WAITALL is set but resid is larger than the receive buffer, |
531 | * we have to do the receive in sections, and thus risk returning | |
532 | * a short count if a timeout or signal occurs after we start. | |
533 | */ | |
440c48bf KM |
534 | if (m == 0 || ((flags & MSG_DONTWAIT) == 0 && |
535 | so->so_rcv.sb_cc < uio->uio_resid) && | |
ba4350f5 | 536 | (so->so_rcv.sb_cc < so->so_rcv.sb_lowat || |
ad787160 C |
537 | ((flags & MSG_WAITALL) && uio->uio_resid <= so->so_rcv.sb_hiwat)) && |
538 | m->m_nextpkt == 0 && (pr->pr_flags & PR_ATOMIC) == 0) { | |
7c4ec3aa MK |
539 | #ifdef DIAGNOSTIC |
540 | if (m == 0 && so->so_rcv.sb_cc) | |
a2aebb63 | 541 | panic("receive 1"); |
7c4ec3aa | 542 | #endif |
4c078bb2 | 543 | if (so->so_error) { |
95c435b0 | 544 | if (m) |
d4c3a4dd | 545 | goto dontblock; |
4c078bb2 | 546 | error = so->so_error; |
95c435b0 MK |
547 | if ((flags & MSG_PEEK) == 0) |
548 | so->so_error = 0; | |
4c078bb2 BJ |
549 | goto release; |
550 | } | |
95c435b0 MK |
551 | if (so->so_state & SS_CANTRCVMORE) { |
552 | if (m) | |
d4c3a4dd | 553 | goto dontblock; |
95c435b0 MK |
554 | else |
555 | goto release; | |
556 | } | |
ad787160 C |
557 | for (; m; m = m->m_next) |
558 | if (m->m_type == MT_OOBDATA || (m->m_flags & M_EOR)) { | |
559 | m = so->so_rcv.sb_mb; | |
560 | goto dontblock; | |
561 | } | |
629e51da | 562 | if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 && |
f02d4eaa KB |
563 | (so->so_proto->pr_flags & PR_CONNREQUIRED)) { |
564 | error = ENOTCONN; | |
565 | goto release; | |
566 | } | |
4b9db1f5 | 567 | if (uio->uio_resid == 0) |
c34d38f4 | 568 | goto release; |
440c48bf | 569 | if ((so->so_state & SS_NBIO) || (flags & MSG_DONTWAIT)) { |
f02d4eaa KB |
570 | error = EWOULDBLOCK; |
571 | goto release; | |
572 | } | |
cc15ab5d | 573 | sbunlock(&so->so_rcv); |
4b9db1f5 | 574 | error = sbwait(&so->so_rcv); |
a4f6d93d | 575 | splx(s); |
7c4ec3aa MK |
576 | if (error) |
577 | return (error); | |
cc15ab5d | 578 | goto restart; |
ce9d8eb4 | 579 | } |
ad787160 | 580 | dontblock: |
0904b863 KM |
581 | if (uio->uio_procp) |
582 | uio->uio_procp->p_stats->p_ru.ru_msgrcv++; | |
2557c1fc | 583 | nextrecord = m->m_nextpkt; |
88a7a62a | 584 | if (pr->pr_flags & PR_ADDR) { |
7c4ec3aa | 585 | #ifdef DIAGNOSTIC |
c34d38f4 | 586 | if (m->m_type != MT_SONAME) |
261a8548 | 587 | panic("receive 1a"); |
7c4ec3aa | 588 | #endif |
34827683 | 589 | orig_resid = 0; |
261a8548 | 590 | if (flags & MSG_PEEK) { |
7c4ec3aa MK |
591 | if (paddr) |
592 | *paddr = m_copy(m, 0, m->m_len); | |
c34d38f4 | 593 | m = m->m_next; |
261a8548 | 594 | } else { |
c34d38f4 | 595 | sbfree(&so->so_rcv, m); |
7c4ec3aa MK |
596 | if (paddr) { |
597 | *paddr = m; | |
6ff43975 | 598 | so->so_rcv.sb_mb = m->m_next; |
c34d38f4 | 599 | m->m_next = 0; |
6ff43975 | 600 | m = so->so_rcv.sb_mb; |
c34d38f4 | 601 | } else { |
6ff43975 MK |
602 | MFREE(m, so->so_rcv.sb_mb); |
603 | m = so->so_rcv.sb_mb; | |
c34d38f4 | 604 | } |
88a7a62a | 605 | } |
cc15ab5d | 606 | } |
7c4ec3aa | 607 | while (m && m->m_type == MT_CONTROL && error == 0) { |
2557c1fc MK |
608 | if (flags & MSG_PEEK) { |
609 | if (controlp) | |
610 | *controlp = m_copy(m, 0, m->m_len); | |
611 | m = m->m_next; | |
612 | } else { | |
613 | sbfree(&so->so_rcv, m); | |
614 | if (controlp) { | |
e8f8de91 KS |
615 | if (pr->pr_domain->dom_externalize && |
616 | mtod(m, struct cmsghdr *)->cmsg_type == | |
617 | SCM_RIGHTS) | |
7c4ec3aa | 618 | error = (*pr->pr_domain->dom_externalize)(m); |
2557c1fc MK |
619 | *controlp = m; |
620 | so->so_rcv.sb_mb = m->m_next; | |
621 | m->m_next = 0; | |
622 | m = so->so_rcv.sb_mb; | |
623 | } else { | |
624 | MFREE(m, so->so_rcv.sb_mb); | |
625 | m = so->so_rcv.sb_mb; | |
626 | } | |
627 | } | |
34827683 KM |
628 | if (controlp) { |
629 | orig_resid = 0; | |
7c4ec3aa | 630 | controlp = &(*controlp)->m_next; |
34827683 | 631 | } |
2557c1fc | 632 | } |
7c4ec3aa | 633 | if (m) { |
ba4350f5 MK |
634 | if ((flags & MSG_PEEK) == 0) |
635 | m->m_nextpkt = nextrecord; | |
7c4ec3aa | 636 | type = m->m_type; |
415a9324 KS |
637 | if (type == MT_OOBDATA) |
638 | flags |= MSG_OOB; | |
7c4ec3aa | 639 | } |
970108c7 | 640 | moff = 0; |
dd1ca18d | 641 | offset = 0; |
415a9324 KS |
642 | while (m && uio->uio_resid > 0 && error == 0) { |
643 | if (m->m_type == MT_OOBDATA) { | |
644 | if (type != MT_OOBDATA) | |
645 | break; | |
646 | } else if (type == MT_OOBDATA) | |
647 | break; | |
7c4ec3aa | 648 | #ifdef DIAGNOSTIC |
2557c1fc | 649 | else if (m->m_type != MT_DATA && m->m_type != MT_HEADER) |
c34d38f4 | 650 | panic("receive 3"); |
7c4ec3aa | 651 | #endif |
32a43ee2 | 652 | so->so_state &= ~SS_RCVATMARK; |
4b9db1f5 | 653 | len = uio->uio_resid; |
dd1ca18d MK |
654 | if (so->so_oobmark && len > so->so_oobmark - offset) |
655 | len = so->so_oobmark - offset; | |
8c0650b0 | 656 | if (len > m->m_len - moff) |
970108c7 | 657 | len = m->m_len - moff; |
7c4ec3aa MK |
658 | /* |
659 | * If mp is set, just pass back the mbufs. | |
660 | * Otherwise copy them out via the uio, then free. | |
661 | * Sockbuf must be consistent here (points to current mbuf, | |
662 | * it points to next record) when we drop priority; | |
663 | * we must note any additions to the sockbuf when we | |
664 | * block interrupts again. | |
665 | */ | |
666 | if (mp == 0) { | |
667 | splx(s); | |
668 | error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio); | |
7c4ec3aa | 669 | s = splnet(); |
4b9db1f5 MK |
670 | } else |
671 | uio->uio_resid -= len; | |
8c0650b0 | 672 | if (len == m->m_len - moff) { |
7c4ec3aa MK |
673 | if (m->m_flags & M_EOR) |
674 | flags |= MSG_EOR; | |
c34d38f4 MK |
675 | if (flags & MSG_PEEK) { |
676 | m = m->m_next; | |
677 | moff = 0; | |
678 | } else { | |
2557c1fc | 679 | nextrecord = m->m_nextpkt; |
6ff43975 | 680 | sbfree(&so->so_rcv, m); |
7c4ec3aa MK |
681 | if (mp) { |
682 | *mp = m; | |
683 | mp = &m->m_next; | |
4b9db1f5 MK |
684 | so->so_rcv.sb_mb = m = m->m_next; |
685 | *mp = (struct mbuf *)0; | |
7c4ec3aa MK |
686 | } else { |
687 | MFREE(m, so->so_rcv.sb_mb); | |
688 | m = so->so_rcv.sb_mb; | |
689 | } | |
6ff43975 | 690 | if (m) |
2557c1fc | 691 | m->m_nextpkt = nextrecord; |
c34d38f4 | 692 | } |
ce9d8eb4 | 693 | } else { |
88a7a62a | 694 | if (flags & MSG_PEEK) |
970108c7 BJ |
695 | moff += len; |
696 | else { | |
4b9db1f5 MK |
697 | if (mp) |
698 | *mp = m_copym(m, 0, len, M_WAIT); | |
2557c1fc | 699 | m->m_data += len; |
970108c7 BJ |
700 | m->m_len -= len; |
701 | so->so_rcv.sb_cc -= len; | |
702 | } | |
ce9d8eb4 | 703 | } |
dd1ca18d MK |
704 | if (so->so_oobmark) { |
705 | if ((flags & MSG_PEEK) == 0) { | |
706 | so->so_oobmark -= len; | |
707 | if (so->so_oobmark == 0) { | |
708 | so->so_state |= SS_RCVATMARK; | |
709 | break; | |
710 | } | |
a660cd8d | 711 | } else { |
dd1ca18d | 712 | offset += len; |
a660cd8d CT |
713 | if (offset == so->so_oobmark) |
714 | break; | |
715 | } | |
970108c7 | 716 | } |
7c4ec3aa | 717 | if (flags & MSG_EOR) |
2967f28e | 718 | break; |
7c4ec3aa MK |
719 | /* |
720 | * If the MSG_WAITALL flag is set (for non-atomic socket), | |
4b9db1f5 | 721 | * we must not quit until "uio->uio_resid == 0" or an error |
7c4ec3aa | 722 | * termination. If a signal/timeout occurs, return |
4b9db1f5 | 723 | * with a short count but without error. |
7c4ec3aa MK |
724 | * Keep sockbuf locked against other readers. |
725 | */ | |
4b9db1f5 | 726 | while (flags & MSG_WAITALL && m == 0 && uio->uio_resid > 0 && |
ad787160 | 727 | !sosendallatonce(so) && !nextrecord) { |
95c435b0 MK |
728 | if (so->so_error || so->so_state & SS_CANTRCVMORE) |
729 | break; | |
7c4ec3aa MK |
730 | error = sbwait(&so->so_rcv); |
731 | if (error) { | |
732 | sbunlock(&so->so_rcv); | |
733 | splx(s); | |
7c4ec3aa MK |
734 | return (0); |
735 | } | |
736 | if (m = so->so_rcv.sb_mb) | |
737 | nextrecord = m->m_nextpkt; | |
7c4ec3aa | 738 | } |
261a8548 | 739 | } |
34827683 KM |
740 | |
741 | if (m && pr->pr_flags & PR_ATOMIC) { | |
742 | flags |= MSG_TRUNC; | |
743 | if ((flags & MSG_PEEK) == 0) | |
744 | (void) sbdroprecord(&so->so_rcv); | |
745 | } | |
261a8548 | 746 | if ((flags & MSG_PEEK) == 0) { |
491e9020 | 747 | if (m == 0) |
261a8548 | 748 | so->so_rcv.sb_mb = nextrecord; |
261a8548 MK |
749 | if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) |
750 | (*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0, | |
a2aebb63 KS |
751 | (struct mbuf *)flags, (struct mbuf *)0, |
752 | (struct mbuf *)0); | |
261a8548 | 753 | } |
34827683 KM |
754 | if (orig_resid == uio->uio_resid && orig_resid && |
755 | (flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) { | |
756 | sbunlock(&so->so_rcv); | |
757 | splx(s); | |
758 | goto restart; | |
759 | } | |
760 | ||
2557c1fc MK |
761 | if (flagsp) |
762 | *flagsp |= flags; | |
cc15ab5d | 763 | release: |
ae921915 | 764 | sbunlock(&so->so_rcv); |
cc15ab5d | 765 | splx(s); |
ae921915 | 766 | return (error); |
92a533e6 BJ |
767 | } |
768 | ||
98422daa | 769 | soshutdown(so, how) |
88a7a62a SL |
770 | register struct socket *so; |
771 | register int how; | |
98422daa | 772 | { |
88a7a62a | 773 | register struct protosw *pr = so->so_proto; |
98422daa SL |
774 | |
775 | how++; | |
88a7a62a SL |
776 | if (how & FREAD) |
777 | sorflush(so); | |
98422daa | 778 | if (how & FWRITE) |
88a7a62a SL |
779 | return ((*pr->pr_usrreq)(so, PRU_SHUTDOWN, |
780 | (struct mbuf *)0, (struct mbuf *)0, (struct mbuf *)0)); | |
98422daa SL |
781 | return (0); |
782 | } | |
783 | ||
88a7a62a SL |
784 | sorflush(so) |
785 | register struct socket *so; | |
786 | { | |
787 | register struct sockbuf *sb = &so->so_rcv; | |
788 | register struct protosw *pr = so->so_proto; | |
789 | register int s; | |
790 | struct sockbuf asb; | |
791 | ||
83866636 | 792 | sb->sb_flags |= SB_NOINTR; |
440c48bf | 793 | (void) sblock(sb, M_WAITOK); |
88a7a62a SL |
794 | s = splimp(); |
795 | socantrcvmore(so); | |
796 | sbunlock(sb); | |
797 | asb = *sb; | |
798 | bzero((caddr_t)sb, sizeof (*sb)); | |
799 | splx(s); | |
261a8548 MK |
800 | if (pr->pr_flags & PR_RIGHTS && pr->pr_domain->dom_dispose) |
801 | (*pr->pr_domain->dom_dispose)(asb.sb_mb); | |
88a7a62a SL |
802 | sbrelease(&asb); |
803 | } | |
804 | ||
bc2f5859 | 805 | sosetopt(so, level, optname, m0) |
88a7a62a | 806 | register struct socket *so; |
98422daa | 807 | int level, optname; |
bc2f5859 | 808 | struct mbuf *m0; |
98422daa | 809 | { |
61ec2127 | 810 | int error = 0; |
bc2f5859 | 811 | register struct mbuf *m = m0; |
98422daa | 812 | |
61ec2127 | 813 | if (level != SOL_SOCKET) { |
cbe54390 MK |
814 | if (so->so_proto && so->so_proto->pr_ctloutput) |
815 | return ((*so->so_proto->pr_ctloutput) | |
bc2f5859 | 816 | (PRCO_SETOPT, so, level, optname, &m0)); |
cbe54390 MK |
817 | error = ENOPROTOOPT; |
818 | } else { | |
819 | switch (optname) { | |
98422daa | 820 | |
cbe54390 MK |
821 | case SO_LINGER: |
822 | if (m == NULL || m->m_len != sizeof (struct linger)) { | |
823 | error = EINVAL; | |
824 | goto bad; | |
825 | } | |
826 | so->so_linger = mtod(m, struct linger *)->l_linger; | |
827 | /* fall thru... */ | |
828 | ||
829 | case SO_DEBUG: | |
830 | case SO_KEEPALIVE: | |
831 | case SO_DONTROUTE: | |
832 | case SO_USELOOPBACK: | |
833 | case SO_BROADCAST: | |
834 | case SO_REUSEADDR: | |
f1242a73 | 835 | case SO_REUSEPORT: |
97c8f6a8 | 836 | case SO_OOBINLINE: |
cbe54390 MK |
837 | if (m == NULL || m->m_len < sizeof (int)) { |
838 | error = EINVAL; | |
839 | goto bad; | |
840 | } | |
841 | if (*mtod(m, int *)) | |
842 | so->so_options |= optname; | |
843 | else | |
844 | so->so_options &= ~optname; | |
845 | break; | |
98422daa | 846 | |
cbe54390 | 847 | case SO_SNDBUF: |
83866636 | 848 | case SO_RCVBUF: |
7c4ec3aa | 849 | case SO_SNDLOWAT: |
83866636 | 850 | case SO_RCVLOWAT: |
cbe54390 MK |
851 | if (m == NULL || m->m_len < sizeof (int)) { |
852 | error = EINVAL; | |
853 | goto bad; | |
854 | } | |
855 | switch (optname) { | |
856 | ||
857 | case SO_SNDBUF: | |
858 | case SO_RCVBUF: | |
7c4ec3aa MK |
859 | if (sbreserve(optname == SO_SNDBUF ? |
860 | &so->so_snd : &so->so_rcv, | |
861 | (u_long) *mtod(m, int *)) == 0) { | |
cbe54390 MK |
862 | error = ENOBUFS; |
863 | goto bad; | |
864 | } | |
865 | break; | |
866 | ||
867 | case SO_SNDLOWAT: | |
7c4ec3aa MK |
868 | so->so_snd.sb_lowat = *mtod(m, int *); |
869 | break; | |
cbe54390 | 870 | case SO_RCVLOWAT: |
7c4ec3aa | 871 | so->so_rcv.sb_lowat = *mtod(m, int *); |
cbe54390 | 872 | break; |
fc2cae0b MK |
873 | } |
874 | break; | |
875 | ||
876 | case SO_SNDTIMEO: | |
877 | case SO_RCVTIMEO: | |
878 | { | |
879 | struct timeval *tv; | |
880 | short val; | |
881 | ||
882 | if (m == NULL || m->m_len < sizeof (*tv)) { | |
883 | error = EINVAL; | |
884 | goto bad; | |
885 | } | |
886 | tv = mtod(m, struct timeval *); | |
887 | if (tv->tv_sec > SHRT_MAX / hz - hz) { | |
888 | error = EDOM; | |
889 | goto bad; | |
890 | } | |
891 | val = tv->tv_sec * hz + tv->tv_usec / tick; | |
892 | ||
893 | switch (optname) { | |
894 | ||
cbe54390 | 895 | case SO_SNDTIMEO: |
fc2cae0b | 896 | so->so_snd.sb_timeo = val; |
7c4ec3aa | 897 | break; |
cbe54390 | 898 | case SO_RCVTIMEO: |
fc2cae0b | 899 | so->so_rcv.sb_timeo = val; |
cbe54390 MK |
900 | break; |
901 | } | |
902 | break; | |
fc2cae0b | 903 | } |
cbe54390 MK |
904 | |
905 | default: | |
906 | error = ENOPROTOOPT; | |
907 | break; | |
908 | } | |
d4c3a4dd | 909 | m = 0; |
bfedcc73 KS |
910 | if (error == 0 && so->so_proto && so->so_proto->pr_ctloutput) |
911 | (void) ((*so->so_proto->pr_ctloutput) | |
912 | (PRCO_SETOPT, so, level, optname, &m0)); | |
98422daa | 913 | } |
61ec2127 SL |
914 | bad: |
915 | if (m) | |
916 | (void) m_free(m); | |
917 | return (error); | |
98422daa SL |
918 | } |
919 | ||
61ec2127 | 920 | sogetopt(so, level, optname, mp) |
88a7a62a | 921 | register struct socket *so; |
98422daa | 922 | int level, optname; |
61ec2127 | 923 | struct mbuf **mp; |
98422daa | 924 | { |
61ec2127 | 925 | register struct mbuf *m; |
98422daa | 926 | |
cbe54390 MK |
927 | if (level != SOL_SOCKET) { |
928 | if (so->so_proto && so->so_proto->pr_ctloutput) { | |
929 | return ((*so->so_proto->pr_ctloutput) | |
930 | (PRCO_GETOPT, so, level, optname, mp)); | |
179cd11f | 931 | } else |
cbe54390 MK |
932 | return (ENOPROTOOPT); |
933 | } else { | |
61ec2127 | 934 | m = m_get(M_WAIT, MT_SOOPTS); |
d6e6eea8 MK |
935 | m->m_len = sizeof (int); |
936 | ||
cbe54390 MK |
937 | switch (optname) { |
938 | ||
939 | case SO_LINGER: | |
940 | m->m_len = sizeof (struct linger); | |
941 | mtod(m, struct linger *)->l_onoff = | |
942 | so->so_options & SO_LINGER; | |
943 | mtod(m, struct linger *)->l_linger = so->so_linger; | |
944 | break; | |
945 | ||
946 | case SO_USELOOPBACK: | |
947 | case SO_DONTROUTE: | |
948 | case SO_DEBUG: | |
949 | case SO_KEEPALIVE: | |
950 | case SO_REUSEADDR: | |
f1242a73 | 951 | case SO_REUSEPORT: |
cbe54390 | 952 | case SO_BROADCAST: |
97c8f6a8 | 953 | case SO_OOBINLINE: |
cbe54390 MK |
954 | *mtod(m, int *) = so->so_options & optname; |
955 | break; | |
956 | ||
d6e6eea8 MK |
957 | case SO_TYPE: |
958 | *mtod(m, int *) = so->so_type; | |
959 | break; | |
960 | ||
de2c74a5 MK |
961 | case SO_ERROR: |
962 | *mtod(m, int *) = so->so_error; | |
963 | so->so_error = 0; | |
964 | break; | |
965 | ||
cbe54390 MK |
966 | case SO_SNDBUF: |
967 | *mtod(m, int *) = so->so_snd.sb_hiwat; | |
968 | break; | |
98422daa | 969 | |
cbe54390 MK |
970 | case SO_RCVBUF: |
971 | *mtod(m, int *) = so->so_rcv.sb_hiwat; | |
972 | break; | |
973 | ||
974 | case SO_SNDLOWAT: | |
975 | *mtod(m, int *) = so->so_snd.sb_lowat; | |
976 | break; | |
977 | ||
978 | case SO_RCVLOWAT: | |
979 | *mtod(m, int *) = so->so_rcv.sb_lowat; | |
980 | break; | |
981 | ||
982 | case SO_SNDTIMEO: | |
cbe54390 | 983 | case SO_RCVTIMEO: |
fc2cae0b MK |
984 | { |
985 | int val = (optname == SO_SNDTIMEO ? | |
986 | so->so_snd.sb_timeo : so->so_rcv.sb_timeo); | |
987 | ||
988 | m->m_len = sizeof(struct timeval); | |
989 | mtod(m, struct timeval *)->tv_sec = val / hz; | |
990 | mtod(m, struct timeval *)->tv_usec = | |
991 | (val % hz) / tick; | |
cbe54390 | 992 | break; |
fc2cae0b | 993 | } |
cbe54390 MK |
994 | |
995 | default: | |
8011f5df | 996 | (void)m_free(m); |
cbe54390 MK |
997 | return (ENOPROTOOPT); |
998 | } | |
999 | *mp = m; | |
1000 | return (0); | |
98422daa | 1001 | } |
98422daa SL |
1002 | } |
1003 | ||
edebca28 | 1004 | sohasoutofband(so) |
88a7a62a | 1005 | register struct socket *so; |
edebca28 | 1006 | { |
3d190e86 | 1007 | struct proc *p; |
edebca28 | 1008 | |
a2aebb63 KS |
1009 | if (so->so_pgid < 0) |
1010 | gsignal(-so->so_pgid, SIGURG); | |
1011 | else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0) | |
3d190e86 | 1012 | psignal(p, SIGURG); |
b4f32e56 | 1013 | selwakeup(&so->so_rcv.sb_sel); |
edebca28 | 1014 | } |