| Commit | Line | Data |
|---|---|---|
| 984263bc | 1 | /* |
| 6ea1e9b9 | 2 | * Copyright (c) 2004 Jeffrey M. Hsu. All rights reserved. |
| 66d6c637 JH |
3 | * Copyright (c) 2004 The DragonFly Project. All rights reserved. |
| 4 | * | |
| 5 | * This code is derived from software contributed to The DragonFly Project | |
| 6 | * by Jeffrey M. Hsu. | |
| 7 | * | |
| 8 | * Redistribution and use in source and binary forms, with or without | |
| 9 | * modification, are permitted provided that the following conditions | |
| 10 | * are met: | |
| 11 | * 1. Redistributions of source code must retain the above copyright | |
| 12 | * notice, this list of conditions and the following disclaimer. | |
| 13 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 14 | * notice, this list of conditions and the following disclaimer in the | |
| 15 | * documentation and/or other materials provided with the distribution. | |
| 16 | * 3. Neither the name of The DragonFly Project nor the names of its | |
| 17 | * contributors may be used to endorse or promote products derived | |
| 18 | * from this software without specific, prior written permission. | |
| 19 | * | |
| 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| 24 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| 25 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| 26 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| 27 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| 28 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
| 29 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
| 30 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 31 | * SUCH DAMAGE. | |
| 32 | */ | |
| 33 | ||
| 34 | /* | |
| 984263bc MD |
35 | * Copyright (c) 1982, 1986, 1988, 1990, 1993 |
| 36 | * The Regents of the University of California. All rights reserved. | |
| 37 | * | |
| 38 | * Redistribution and use in source and binary forms, with or without | |
| 39 | * modification, are permitted provided that the following conditions | |
| 40 | * are met: | |
| 41 | * 1. Redistributions of source code must retain the above copyright | |
| 42 | * notice, this list of conditions and the following disclaimer. | |
| 43 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 44 | * notice, this list of conditions and the following disclaimer in the | |
| 45 | * documentation and/or other materials provided with the distribution. | |
| 46 | * 3. All advertising materials mentioning features or use of this software | |
| 47 | * must display the following acknowledgement: | |
| 48 | * This product includes software developed by the University of | |
| 49 | * California, Berkeley and its contributors. | |
| 50 | * 4. Neither the name of the University nor the names of its contributors | |
| 51 | * may be used to endorse or promote products derived from this software | |
| 52 | * without specific prior written permission. | |
| 53 | * | |
| 54 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
| 55 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 56 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 57 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
| 58 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 59 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 60 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 61 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 62 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 63 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 64 | * SUCH DAMAGE. | |
| 65 | * | |
| 66 | * @(#)uipc_socket.c 8.3 (Berkeley) 4/15/94 | |
| 7405c902 | 67 | * $FreeBSD: src/sys/kern/uipc_socket.c,v 1.68.2.24 2003/11/11 17:18:18 silby Exp $ |
| 9116be8e | 68 | * $DragonFly: src/sys/kern/uipc_socket.c,v 1.55 2008/09/02 16:17:52 dillon Exp $ |
| 984263bc MD |
69 | */ |
| 70 | ||
| 71 | #include "opt_inet.h" | |
| 78812139 | 72 | #include "opt_sctp.h" |
| 984263bc MD |
73 | |
| 74 | #include <sys/param.h> | |
| 75 | #include <sys/systm.h> | |
| 76 | #include <sys/fcntl.h> | |
| 77 | #include <sys/malloc.h> | |
| 78 | #include <sys/mbuf.h> | |
| 79 | #include <sys/domain.h> | |
| 80 | #include <sys/file.h> /* for struct knote */ | |
| 81 | #include <sys/kernel.h> | |
| 82 | #include <sys/malloc.h> | |
| 83 | #include <sys/event.h> | |
| 984263bc MD |
84 | #include <sys/proc.h> |
| 85 | #include <sys/protosw.h> | |
| 86 | #include <sys/socket.h> | |
| 87 | #include <sys/socketvar.h> | |
| 6b6e0885 | 88 | #include <sys/socketops.h> |
| 984263bc MD |
89 | #include <sys/resourcevar.h> |
| 90 | #include <sys/signalvar.h> | |
| 91 | #include <sys/sysctl.h> | |
| 92 | #include <sys/uio.h> | |
| 93 | #include <sys/jail.h> | |
| 94 | #include <vm/vm_zone.h> | |
| e71a125f | 95 | #include <vm/pmap.h> |
| 984263bc | 96 | |
| e43a034f | 97 | #include <sys/thread2.h> |
| d6cb521d | 98 | #include <sys/socketvar2.h> |
| e43a034f | 99 | |
| 984263bc MD |
100 | #include <machine/limits.h> |
| 101 | ||
| 102 | #ifdef INET | |
| 103 | static int do_setopt_accept_filter(struct socket *so, struct sockopt *sopt); | |
| 104 | #endif /* INET */ | |
| 105 | ||
| 106 | static void filt_sordetach(struct knote *kn); | |
| 107 | static int filt_soread(struct knote *kn, long hint); | |
| 108 | static void filt_sowdetach(struct knote *kn); | |
| 109 | static int filt_sowrite(struct knote *kn, long hint); | |
| 110 | static int filt_solisten(struct knote *kn, long hint); | |
| 111 | ||
| 112 | static struct filterops solisten_filtops = | |
| 4c91dbc9 | 113 | { FILTEROP_ISFD, NULL, filt_sordetach, filt_solisten }; |
| 984263bc | 114 | static struct filterops soread_filtops = |
| 4c91dbc9 | 115 | { FILTEROP_ISFD, NULL, filt_sordetach, filt_soread }; |
| 984263bc | 116 | static struct filterops sowrite_filtops = |
| 4c91dbc9 | 117 | { FILTEROP_ISFD, NULL, filt_sowdetach, filt_sowrite }; |
| 73c344d3 | 118 | static struct filterops soexcept_filtops = |
| 4c91dbc9 | 119 | { FILTEROP_ISFD, NULL, filt_sordetach, filt_soread }; |
| 984263bc | 120 | |
| 69ea5b8d | 121 | MALLOC_DEFINE(M_SOCKET, "socket", "socket struct"); |
| 984263bc MD |
122 | MALLOC_DEFINE(M_SONAME, "soname", "socket name"); |
| 123 | MALLOC_DEFINE(M_PCB, "pcb", "protocol control block"); | |
| 124 | ||
| 984263bc MD |
125 | |
| 126 | static int somaxconn = SOMAXCONN; | |
| 127 | SYSCTL_INT(_kern_ipc, KIPC_SOMAXCONN, somaxconn, CTLFLAG_RW, | |
| 128 | &somaxconn, 0, "Maximum pending socket connection queue size"); | |
| 129 | ||
| 130 | /* | |
| 131 | * Socket operation routines. | |
| 132 | * These routines are called by the routines in | |
| 133 | * sys_socket.c or from a system process, and | |
| 134 | * implement the semantics of socket operations by | |
| 135 | * switching out to the protocol specific routines. | |
| 136 | */ | |
| 137 | ||
| 138 | /* | |
| 69ea5b8d | 139 | * Get a socket structure, and initialize it. |
| 984263bc MD |
140 | * Note that it would probably be better to allocate socket |
| 141 | * and PCB at the same time, but I'm not convinced that all | |
| 142 | * the protocols can be easily modified to do this. | |
| 143 | */ | |
| 144 | struct socket * | |
| c972a82f | 145 | soalloc(int waitok) |
| 984263bc MD |
146 | { |
| 147 | struct socket *so; | |
| 69ea5b8d | 148 | unsigned waitmask; |
| 984263bc | 149 | |
| 69ea5b8d NT |
150 | waitmask = waitok ? M_WAITOK : M_NOWAIT; |
| 151 | so = kmalloc(sizeof(struct socket), M_SOCKET, M_ZERO|waitmask); | |
| 984263bc MD |
152 | if (so) { |
| 153 | /* XXX race condition for reentrant kernel */ | |
| 984263bc | 154 | TAILQ_INIT(&so->so_aiojobq); |
| 5b22f1a7 SG |
155 | TAILQ_INIT(&so->so_rcv.ssb_kq.ki_mlist); |
| 156 | TAILQ_INIT(&so->so_snd.ssb_kq.ki_mlist); | |
| a3c18566 MD |
157 | lwkt_token_init(&so->so_rcv.ssb_token, "rcvtok"); |
| 158 | lwkt_token_init(&so->so_snd.ssb_token, "sndtok"); | |
| 6cef7136 MD |
159 | so->so_state = SS_NOFDREF; |
| 160 | so->so_refs = 1; | |
| 984263bc MD |
161 | } |
| 162 | return so; | |
| 163 | } | |
| 164 | ||
| 165 | int | |
| dadab5e9 MD |
166 | socreate(int dom, struct socket **aso, int type, |
| 167 | int proto, struct thread *td) | |
| 984263bc | 168 | { |
| dadab5e9 MD |
169 | struct proc *p = td->td_proc; |
| 170 | struct protosw *prp; | |
| 171 | struct socket *so; | |
| e4700d00 | 172 | struct pru_attach_info ai; |
| dadab5e9 | 173 | int error; |
| 984263bc MD |
174 | |
| 175 | if (proto) | |
| 176 | prp = pffindproto(dom, proto, type); | |
| 177 | else | |
| 178 | prp = pffindtype(dom, type); | |
| 179 | ||
| 180 | if (prp == 0 || prp->pr_usrreqs->pru_attach == 0) | |
| 181 | return (EPROTONOSUPPORT); | |
| 182 | ||
| 41c20dac | 183 | if (p->p_ucred->cr_prison && jail_socket_unixiproute_only && |
| 984263bc MD |
184 | prp->pr_domain->dom_family != PF_LOCAL && |
| 185 | prp->pr_domain->dom_family != PF_INET && | |
| 3e4150ef | 186 | prp->pr_domain->dom_family != PF_INET6 && |
| 984263bc MD |
187 | prp->pr_domain->dom_family != PF_ROUTE) { |
| 188 | return (EPROTONOSUPPORT); | |
| 189 | } | |
| 190 | ||
| 191 | if (prp->pr_type != type) | |
| 192 | return (EPROTOTYPE); | |
| 193 | so = soalloc(p != 0); | |
| 6cef7136 | 194 | if (so == NULL) |
| 984263bc MD |
195 | return (ENOBUFS); |
| 196 | ||
| 48e7b118 | 197 | /* |
| 6cef7136 MD |
198 | * Callers of socreate() presumably will connect up a descriptor |
| 199 | * and call soclose() if they cannot. This represents our so_refs | |
| 200 | * (which should be 1) from soalloc(). | |
| 201 | */ | |
| 202 | soclrstate(so, SS_NOFDREF); | |
| 203 | ||
| 204 | /* | |
| 48e7b118 MD |
205 | * Set a default port for protocol processing. No action will occur |
| 206 | * on the socket on this port until an inpcb is attached to it and | |
| 207 | * is able to match incoming packets, or until the socket becomes | |
| 208 | * available to userland. | |
| 002c1265 MD |
209 | * |
| 210 | * We normally default the socket to the protocol thread on cpu 0. | |
| 211 | * If PR_SYNC_PORT is set (unix domain sockets) there is no protocol | |
| 212 | * thread and all pr_*()/pru_*() calls are executed synchronously. | |
| 48e7b118 | 213 | */ |
| 002c1265 MD |
214 | if (prp->pr_flags & PR_SYNC_PORT) |
| 215 | so->so_port = &netisr_sync_port; | |
| 216 | else | |
| 217 | so->so_port = cpu_portfn(0); | |
| 48e7b118 | 218 | |
| 984263bc MD |
219 | TAILQ_INIT(&so->so_incomp); |
| 220 | TAILQ_INIT(&so->so_comp); | |
| 221 | so->so_type = type; | |
| e9a372eb | 222 | so->so_cred = crhold(p->p_ucred); |
| 984263bc | 223 | so->so_proto = prp; |
| e4700d00 JH |
224 | ai.sb_rlimit = &p->p_rlimit[RLIMIT_SBSIZE]; |
| 225 | ai.p_ucred = p->p_ucred; | |
| 226 | ai.fd_rdir = p->p_fd->fd_rdir; | |
| 48e7b118 | 227 | |
| 5b0b9fa5 PA |
228 | /* |
| 229 | * Auto-sizing of socket buffers is managed by the protocols and | |
| 230 | * the appropriate flags must be set in the pru_attach function. | |
| 231 | */ | |
| e4700d00 | 232 | error = so_pru_attach(so, proto, &ai); |
| 984263bc | 233 | if (error) { |
| 6cef7136 MD |
234 | sosetstate(so, SS_NOFDREF); |
| 235 | sofree(so); /* from soalloc */ | |
| 236 | return error; | |
| 984263bc | 237 | } |
| 48e7b118 | 238 | |
| 6cef7136 MD |
239 | /* |
| 240 | * NOTE: Returns referenced socket. | |
| 241 | */ | |
| 984263bc MD |
242 | *aso = so; |
| 243 | return (0); | |
| 244 | } | |
| 245 | ||
| 246 | int | |
| dadab5e9 | 247 | sobind(struct socket *so, struct sockaddr *nam, struct thread *td) |
| 984263bc | 248 | { |
| 984263bc MD |
249 | int error; |
| 250 | ||
| 6b6e0885 | 251 | error = so_pru_bind(so, nam, td); |
| 984263bc MD |
252 | return (error); |
| 253 | } | |
| 254 | ||
| 6cef7136 | 255 | static void |
| dadab5e9 | 256 | sodealloc(struct socket *so) |
| 984263bc | 257 | { |
| 6d49aa6f | 258 | if (so->so_rcv.ssb_hiwat) |
| 984263bc | 259 | (void)chgsbsize(so->so_cred->cr_uidinfo, |
| 6d49aa6f MD |
260 | &so->so_rcv.ssb_hiwat, 0, RLIM_INFINITY); |
| 261 | if (so->so_snd.ssb_hiwat) | |
| 984263bc | 262 | (void)chgsbsize(so->so_cred->cr_uidinfo, |
| 6d49aa6f | 263 | &so->so_snd.ssb_hiwat, 0, RLIM_INFINITY); |
| 984263bc | 264 | #ifdef INET |
| 81d59d3d HP |
265 | /* remove accept filter if present */ |
| 266 | if (so->so_accf != NULL) | |
| 267 | do_setopt_accept_filter(so, NULL); | |
| 984263bc MD |
268 | #endif /* INET */ |
| 269 | crfree(so->so_cred); | |
| 69ea5b8d | 270 | kfree(so, M_SOCKET); |
| 984263bc MD |
271 | } |
| 272 | ||
| 273 | int | |
| dadab5e9 | 274 | solisten(struct socket *so, int backlog, struct thread *td) |
| 984263bc | 275 | { |
| e43a034f | 276 | int error; |
| 78812139 EN |
277 | #ifdef SCTP |
| 278 | short oldopt, oldqlimit; | |
| 279 | #endif /* SCTP */ | |
| 984263bc | 280 | |
| 6cef7136 | 281 | if (so->so_state & (SS_ISCONNECTED | SS_ISCONNECTING)) |
| 78812139 | 282 | return (EINVAL); |
| 78812139 EN |
283 | |
| 284 | #ifdef SCTP | |
| 285 | oldopt = so->so_options; | |
| 286 | oldqlimit = so->so_qlimit; | |
| 287 | #endif /* SCTP */ | |
| 288 | ||
| 6cef7136 | 289 | lwkt_gettoken(&so->so_rcv.ssb_token); |
| 984263bc MD |
290 | if (TAILQ_EMPTY(&so->so_comp)) |
| 291 | so->so_options |= SO_ACCEPTCONN; | |
| 6cef7136 | 292 | lwkt_reltoken(&so->so_rcv.ssb_token); |
| 984263bc MD |
293 | if (backlog < 0 || backlog > somaxconn) |
| 294 | backlog = somaxconn; | |
| 295 | so->so_qlimit = backlog; | |
| 78812139 EN |
296 | /* SCTP needs to look at tweak both the inbound backlog parameter AND |
| 297 | * the so_options (UDP model both connect's and gets inbound | |
| 298 | * connections .. implicitly). | |
| 299 | */ | |
| 300 | error = so_pru_listen(so, td); | |
| 301 | if (error) { | |
| 302 | #ifdef SCTP | |
| 303 | /* Restore the params */ | |
| 304 | so->so_options = oldopt; | |
| 305 | so->so_qlimit = oldqlimit; | |
| 306 | #endif /* SCTP */ | |
| 78812139 EN |
307 | return (error); |
| 308 | } | |
| 984263bc MD |
309 | return (0); |
| 310 | } | |
| 311 | ||
| 4402d8a2 MD |
312 | /* |
| 313 | * Destroy a disconnected socket. This routine is a NOP if entities | |
| 314 | * still have a reference on the socket: | |
| 315 | * | |
| 316 | * so_pcb - The protocol stack still has a reference | |
| 317 | * SS_NOFDREF - There is no longer a file pointer reference | |
| 4402d8a2 | 318 | */ |
| 984263bc | 319 | void |
| dadab5e9 | 320 | sofree(struct socket *so) |
| 984263bc | 321 | { |
| 5217bcbc MD |
322 | struct socket *head; |
| 323 | ||
| 324 | /* | |
| 325 | * This is a bit hackish at the moment. We need to interlock | |
| 326 | * any accept queue we are on before we potentially lose the | |
| 327 | * last reference to avoid races against a re-reference from | |
| 328 | * someone operating on the queue. | |
| 329 | */ | |
| 330 | while ((head = so->so_head) != NULL) { | |
| 331 | lwkt_getpooltoken(head); | |
| 332 | if (so->so_head == head) | |
| 333 | break; | |
| 334 | lwkt_relpooltoken(head); | |
| 335 | } | |
| 984263bc | 336 | |
| 6cef7136 MD |
337 | /* |
| 338 | * Arbitrage the last free. | |
| 339 | */ | |
| 340 | KKASSERT(so->so_refs > 0); | |
| 5217bcbc MD |
341 | if (atomic_fetchadd_int(&so->so_refs, -1) != 1) { |
| 342 | if (head) | |
| 343 | lwkt_relpooltoken(head); | |
| 4402d8a2 | 344 | return; |
| 5217bcbc | 345 | } |
| 6cef7136 MD |
346 | |
| 347 | KKASSERT(so->so_pcb == NULL && (so->so_state & SS_NOFDREF)); | |
| e28d8186 | 348 | KKASSERT((so->so_state & SS_ASSERTINPROG) == 0); |
| 6cef7136 MD |
349 | |
| 350 | /* | |
| 5217bcbc MD |
351 | * We're done, remove ourselves from the accept queue we are |
| 352 | * on, if we are on one. | |
| 6cef7136 | 353 | */ |
| 984263bc MD |
354 | if (head != NULL) { |
| 355 | if (so->so_state & SS_INCOMP) { | |
| 356 | TAILQ_REMOVE(&head->so_incomp, so, so_list); | |
| 357 | head->so_incqlen--; | |
| 358 | } else if (so->so_state & SS_COMP) { | |
| 359 | /* | |
| 360 | * We must not decommission a socket that's | |
| 361 | * on the accept(2) queue. If we do, then | |
| 362 | * accept(2) may hang after select(2) indicated | |
| 363 | * that the listening socket was ready. | |
| 364 | */ | |
| 5217bcbc | 365 | lwkt_relpooltoken(head); |
| 984263bc MD |
366 | return; |
| 367 | } else { | |
| 368 | panic("sofree: not queued"); | |
| 369 | } | |
| 6cef7136 | 370 | soclrstate(so, SS_INCOMP); |
| 984263bc | 371 | so->so_head = NULL; |
| 5217bcbc | 372 | lwkt_relpooltoken(head); |
| 984263bc | 373 | } |
| 6d49aa6f | 374 | ssb_release(&so->so_snd, so); |
| 984263bc MD |
375 | sorflush(so); |
| 376 | sodealloc(so); | |
| 377 | } | |
| 378 | ||
| 379 | /* | |
| 380 | * Close a socket on last file table reference removal. | |
| 381 | * Initiate disconnect if connected. | |
| 382 | * Free socket when disconnect complete. | |
| 383 | */ | |
| 384 | int | |
| 9ba76b73 | 385 | soclose(struct socket *so, int fflag) |
| 984263bc | 386 | { |
| 984263bc MD |
387 | int error = 0; |
| 388 | ||
| 58c2553a | 389 | funsetown(&so->so_sigio); |
| 19be7d32 | 390 | if (so->so_pcb == NULL) |
| 984263bc MD |
391 | goto discard; |
| 392 | if (so->so_state & SS_ISCONNECTED) { | |
| 393 | if ((so->so_state & SS_ISDISCONNECTING) == 0) { | |
| 394 | error = sodisconnect(so); | |
| 395 | if (error) | |
| 396 | goto drop; | |
| 397 | } | |
| 398 | if (so->so_options & SO_LINGER) { | |
| 399 | if ((so->so_state & SS_ISDISCONNECTING) && | |
| 9ba76b73 | 400 | (fflag & FNONBLOCK)) |
| 984263bc MD |
401 | goto drop; |
| 402 | while (so->so_state & SS_ISCONNECTED) { | |
| 6cef7136 MD |
403 | error = tsleep(&so->so_timeo, PCATCH, |
| 404 | "soclos", so->so_linger * hz); | |
| 984263bc MD |
405 | if (error) |
| 406 | break; | |
| 407 | } | |
| 408 | } | |
| 409 | } | |
| 410 | drop: | |
| 411 | if (so->so_pcb) { | |
| 6b6e0885 JH |
412 | int error2; |
| 413 | ||
| 414 | error2 = so_pru_detach(so); | |
| 984263bc MD |
415 | if (error == 0) |
| 416 | error = error2; | |
| 417 | } | |
| 418 | discard: | |
| 5217bcbc | 419 | lwkt_getpooltoken(so); |
| 19be7d32 | 420 | if (so->so_options & SO_ACCEPTCONN) { |
| 4402d8a2 | 421 | struct socket *sp; |
| 19be7d32 | 422 | |
| 4402d8a2 MD |
423 | while ((sp = TAILQ_FIRST(&so->so_incomp)) != NULL) { |
| 424 | TAILQ_REMOVE(&so->so_incomp, sp, so_list); | |
| 6cef7136 | 425 | soclrstate(sp, SS_INCOMP); |
| 4402d8a2 MD |
426 | sp->so_head = NULL; |
| 427 | so->so_incqlen--; | |
| 9116be8e | 428 | soaborta(sp); |
| 19be7d32 | 429 | } |
| 4402d8a2 | 430 | while ((sp = TAILQ_FIRST(&so->so_comp)) != NULL) { |
| 19be7d32 | 431 | TAILQ_REMOVE(&so->so_comp, sp, so_list); |
| 6cef7136 | 432 | soclrstate(sp, SS_COMP); |
| 19be7d32 | 433 | sp->so_head = NULL; |
| 4402d8a2 | 434 | so->so_qlen--; |
| 9116be8e | 435 | soaborta(sp); |
| 19be7d32 MD |
436 | } |
| 437 | } | |
| 5217bcbc | 438 | lwkt_relpooltoken(so); |
| 984263bc MD |
439 | if (so->so_state & SS_NOFDREF) |
| 440 | panic("soclose: NOFDREF"); | |
| 6cef7136 MD |
441 | sosetstate(so, SS_NOFDREF); /* take ref */ |
| 442 | sofree(so); /* dispose of ref */ | |
| 984263bc MD |
443 | return (error); |
| 444 | } | |
| 445 | ||
| 446 | /* | |
| 9116be8e MD |
447 | * Abort and destroy a socket. Only one abort can be in progress |
| 448 | * at any given moment. | |
| 984263bc | 449 | */ |
| 4402d8a2 | 450 | void |
| c972a82f | 451 | soabort(struct socket *so) |
| 984263bc | 452 | { |
| 6cef7136 MD |
453 | soreference(so); |
| 454 | so_pru_abort(so); | |
| 4402d8a2 | 455 | } |
| 984263bc | 456 | |
| 4402d8a2 MD |
457 | void |
| 458 | soaborta(struct socket *so) | |
| 459 | { | |
| 6cef7136 MD |
460 | soreference(so); |
| 461 | so_pru_aborta(so); | |
| 984263bc MD |
462 | } |
| 463 | ||
| fd86a41c SZ |
464 | void |
| 465 | soabort_oncpu(struct socket *so) | |
| 466 | { | |
| 6cef7136 MD |
467 | soreference(so); |
| 468 | so_pru_abort_oncpu(so); | |
| fd86a41c SZ |
469 | } |
| 470 | ||
| c19fdb0e MD |
471 | /* |
| 472 | * so is passed in ref'd, which becomes owned by | |
| 473 | * the cleared SS_NOFDREF flag. | |
| 474 | */ | |
| 984263bc | 475 | int |
| dadab5e9 | 476 | soaccept(struct socket *so, struct sockaddr **nam) |
| 984263bc | 477 | { |
| 984263bc MD |
478 | int error; |
| 479 | ||
| 480 | if ((so->so_state & SS_NOFDREF) == 0) | |
| 481 | panic("soaccept: !NOFDREF"); | |
| 6cef7136 | 482 | soclrstate(so, SS_NOFDREF); /* owned by lack of SS_NOFDREF */ |
| 002c1265 | 483 | error = so_pru_accept_direct(so, nam); |
| 984263bc MD |
484 | return (error); |
| 485 | } | |
| 486 | ||
| 487 | int | |
| dadab5e9 | 488 | soconnect(struct socket *so, struct sockaddr *nam, struct thread *td) |
| 984263bc | 489 | { |
| 984263bc MD |
490 | int error; |
| 491 | ||
| 492 | if (so->so_options & SO_ACCEPTCONN) | |
| 493 | return (EOPNOTSUPP); | |
| 984263bc MD |
494 | /* |
| 495 | * If protocol is connection-based, can only connect once. | |
| 496 | * Otherwise, if connected, try to disconnect first. | |
| 497 | * This allows user to disconnect by connecting to, e.g., | |
| 498 | * a null address. | |
| 499 | */ | |
| 500 | if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && | |
| 501 | ((so->so_proto->pr_flags & PR_CONNREQUIRED) || | |
| 59429d28 | 502 | (error = sodisconnect(so)))) { |
| 984263bc | 503 | error = EISCONN; |
| 59429d28 MD |
504 | } else { |
| 505 | /* | |
| 506 | * Prevent accumulated error from previous connection | |
| 507 | * from biting us. | |
| 508 | */ | |
| 509 | so->so_error = 0; | |
| 6b6e0885 | 510 | error = so_pru_connect(so, nam, td); |
| 59429d28 | 511 | } |
| 984263bc MD |
512 | return (error); |
| 513 | } | |
| 514 | ||
| 515 | int | |
| dadab5e9 | 516 | soconnect2(struct socket *so1, struct socket *so2) |
| 984263bc | 517 | { |
| 984263bc MD |
518 | int error; |
| 519 | ||
| 6b6e0885 | 520 | error = so_pru_connect2(so1, so2); |
| 984263bc MD |
521 | return (error); |
| 522 | } | |
| 523 | ||
| 524 | int | |
| dadab5e9 | 525 | sodisconnect(struct socket *so) |
| 984263bc | 526 | { |
| 984263bc MD |
527 | int error; |
| 528 | ||
| 529 | if ((so->so_state & SS_ISCONNECTED) == 0) { | |
| 530 | error = ENOTCONN; | |
| 531 | goto bad; | |
| 532 | } | |
| 533 | if (so->so_state & SS_ISDISCONNECTING) { | |
| 534 | error = EALREADY; | |
| 535 | goto bad; | |
| 536 | } | |
| 6b6e0885 | 537 | error = so_pru_disconnect(so); |
| 984263bc | 538 | bad: |
| 984263bc MD |
539 | return (error); |
| 540 | } | |
| 541 | ||
| 542 | #define SBLOCKWAIT(f) (((f) & MSG_DONTWAIT) ? M_NOWAIT : M_WAITOK) | |
| 543 | /* | |
| 544 | * Send on a socket. | |
| 545 | * If send must go all at once and message is larger than | |
| 546 | * send buffering, then hard error. | |
| 547 | * Lock against other senders. | |
| 548 | * If must go all at once and not enough room now, then | |
| 549 | * inform user that this would block and do nothing. | |
| 550 | * Otherwise, if nonblocking, send as much as possible. | |
| 551 | * The data to be sent is described by "uio" if nonzero, | |
| 552 | * otherwise by the mbuf chain "top" (which must be null | |
| 553 | * if uio is not). Data provided in mbuf chain must be small | |
| 554 | * enough to send all at once. | |
| 555 | * | |
| 556 | * Returns nonzero on error, timeout or signal; callers | |
| 557 | * must check for short counts if EINTR/ERESTART are returned. | |
| 558 | * Data and control buffers are freed on return. | |
| 559 | */ | |
| 560 | int | |
| dadab5e9 MD |
561 | sosend(struct socket *so, struct sockaddr *addr, struct uio *uio, |
| 562 | struct mbuf *top, struct mbuf *control, int flags, | |
| 563 | struct thread *td) | |
| 984263bc MD |
564 | { |
| 565 | struct mbuf **mp; | |
| dadab5e9 | 566 | struct mbuf *m; |
| e54488bb MD |
567 | size_t resid; |
| 568 | int space, len; | |
| e43a034f | 569 | int clen = 0, error, dontroute, mlen; |
| 984263bc | 570 | int atomic = sosendallatonce(so) || top; |
| 6b6e0885 | 571 | int pru_flags; |
| 984263bc | 572 | |
| 5bd48c1d | 573 | if (uio) { |
| 984263bc | 574 | resid = uio->uio_resid; |
| 5bd48c1d | 575 | } else { |
| e54488bb | 576 | resid = (size_t)top->m_pkthdr.len; |
| 5bd48c1d MD |
577 | #ifdef INVARIANTS |
| 578 | len = 0; | |
| 579 | for (m = top; m; m = m->m_next) | |
| 580 | len += m->m_len; | |
| 581 | KKASSERT(top->m_pkthdr.len == len); | |
| 582 | #endif | |
| 583 | } | |
| 48e7b118 | 584 | |
| 984263bc | 585 | /* |
| e54488bb MD |
586 | * WARNING! resid is unsigned, space and len are signed. space |
| 587 | * can wind up negative if the sockbuf is overcommitted. | |
| 984263bc MD |
588 | * |
| 589 | * Also check to make sure that MSG_EOR isn't used on SOCK_STREAM | |
| 590 | * type sockets since that's an error. | |
| 591 | */ | |
| e54488bb | 592 | if (so->so_type == SOCK_STREAM && (flags & MSG_EOR)) { |
| 984263bc MD |
593 | error = EINVAL; |
| 594 | goto out; | |
| 595 | } | |
| 596 | ||
| 597 | dontroute = | |
| 598 | (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && | |
| 599 | (so->so_proto->pr_flags & PR_ATOMIC); | |
| fde7ac71 SS |
600 | if (td->td_lwp != NULL) |
| 601 | td->td_lwp->lwp_ru.ru_msgsnd++; | |
| 984263bc MD |
602 | if (control) |
| 603 | clen = control->m_len; | |
| 6cef7136 | 604 | #define gotoerr(errcode) { error = errcode; goto release; } |
| 984263bc MD |
605 | |
| 606 | restart: | |
| 6d49aa6f | 607 | error = ssb_lock(&so->so_snd, SBLOCKWAIT(flags)); |
| 984263bc MD |
608 | if (error) |
| 609 | goto out; | |
| 48e7b118 | 610 | |
| 984263bc | 611 | do { |
| 984263bc | 612 | if (so->so_state & SS_CANTSENDMORE) |
| 6ea1e9b9 | 613 | gotoerr(EPIPE); |
| 984263bc MD |
614 | if (so->so_error) { |
| 615 | error = so->so_error; | |
| 616 | so->so_error = 0; | |
| 984263bc MD |
617 | goto release; |
| 618 | } | |
| 619 | if ((so->so_state & SS_ISCONNECTED) == 0) { | |
| 620 | /* | |
| 621 | * `sendto' and `sendmsg' is allowed on a connection- | |
| 622 | * based socket if it supports implied connect. | |
| 623 | * Return ENOTCONN if not connected and no address is | |
| 624 | * supplied. | |
| 625 | */ | |
| 626 | if ((so->so_proto->pr_flags & PR_CONNREQUIRED) && | |
| 627 | (so->so_proto->pr_flags & PR_IMPLOPCL) == 0) { | |
| 628 | if ((so->so_state & SS_ISCONFIRMING) == 0 && | |
| 629 | !(resid == 0 && clen != 0)) | |
| 6ea1e9b9 | 630 | gotoerr(ENOTCONN); |
| 984263bc | 631 | } else if (addr == 0) |
| 6ea1e9b9 | 632 | gotoerr(so->so_proto->pr_flags & PR_CONNREQUIRED ? |
| 984263bc MD |
633 | ENOTCONN : EDESTADDRREQ); |
| 634 | } | |
| 3a6117bb MD |
635 | if ((atomic && resid > so->so_snd.ssb_hiwat) || |
| 636 | clen > so->so_snd.ssb_hiwat) { | |
| 637 | gotoerr(EMSGSIZE); | |
| 638 | } | |
| 6d49aa6f | 639 | space = ssb_space(&so->so_snd); |
| 984263bc MD |
640 | if (flags & MSG_OOB) |
| 641 | space += 1024; | |
| e54488bb | 642 | if ((space < 0 || (size_t)space < resid + clen) && uio && |
| 6d49aa6f | 643 | (atomic || space < so->so_snd.ssb_lowat || space < clen)) { |
| 9ba76b73 | 644 | if (flags & (MSG_FNONBLOCKING|MSG_DONTWAIT)) |
| 6ea1e9b9 | 645 | gotoerr(EWOULDBLOCK); |
| 6d49aa6f MD |
646 | ssb_unlock(&so->so_snd); |
| 647 | error = ssb_wait(&so->so_snd); | |
| 984263bc MD |
648 | if (error) |
| 649 | goto out; | |
| 650 | goto restart; | |
| 651 | } | |
| 984263bc MD |
652 | mp = ⊤ |
| 653 | space -= clen; | |
| 654 | do { | |
| 655 | if (uio == NULL) { | |
| 656 | /* | |
| 657 | * Data is prepackaged in "top". | |
| 658 | */ | |
| 659 | resid = 0; | |
| 660 | if (flags & MSG_EOR) | |
| 661 | top->m_flags |= M_EOR; | |
| 662 | } else do { | |
| e54488bb MD |
663 | if (resid > INT_MAX) |
| 664 | resid = INT_MAX; | |
| 665 | m = m_getl((int)resid, MB_WAIT, MT_DATA, | |
| 50503f0f JH |
666 | top == NULL ? M_PKTHDR : 0, &mlen); |
| 667 | if (top == NULL) { | |
| 984263bc | 668 | m->m_pkthdr.len = 0; |
| 60233e58 | 669 | m->m_pkthdr.rcvif = NULL; |
| 984263bc | 670 | } |
| e54488bb | 671 | len = imin((int)szmin(mlen, resid), space); |
| 50503f0f | 672 | if (resid < MINCLSIZE) { |
| 984263bc MD |
673 | /* |
| 674 | * For datagram protocols, leave room | |
| 675 | * for protocol headers in first mbuf. | |
| 676 | */ | |
| 677 | if (atomic && top == 0 && len < mlen) | |
| 678 | MH_ALIGN(m, len); | |
| 679 | } | |
| 680 | space -= len; | |
| e54488bb | 681 | error = uiomove(mtod(m, caddr_t), (size_t)len, uio); |
| 984263bc MD |
682 | resid = uio->uio_resid; |
| 683 | m->m_len = len; | |
| 684 | *mp = m; | |
| 685 | top->m_pkthdr.len += len; | |
| 686 | if (error) | |
| 687 | goto release; | |
| 688 | mp = &m->m_next; | |
| e54488bb | 689 | if (resid == 0) { |
| 984263bc MD |
690 | if (flags & MSG_EOR) |
| 691 | top->m_flags |= M_EOR; | |
| 692 | break; | |
| 693 | } | |
| 694 | } while (space > 0 && atomic); | |
| 695 | if (dontroute) | |
| 696 | so->so_options |= SO_DONTROUTE; | |
| 6b6e0885 JH |
697 | if (flags & MSG_OOB) { |
| 698 | pru_flags = PRUS_OOB; | |
| 699 | } else if ((flags & MSG_EOF) && | |
| 700 | (so->so_proto->pr_flags & PR_IMPLOPCL) && | |
| e54488bb | 701 | (resid == 0)) { |
| 6b6e0885 JH |
702 | /* |
| 703 | * If the user set MSG_EOF, the protocol | |
| 704 | * understands this flag and nothing left to | |
| 705 | * send then use PRU_SEND_EOF instead of PRU_SEND. | |
| 706 | */ | |
| 707 | pru_flags = PRUS_EOF; | |
| 708 | } else if (resid > 0 && space > 0) { | |
| 709 | /* If there is more to send, set PRUS_MORETOCOME */ | |
| 710 | pru_flags = PRUS_MORETOCOME; | |
| 711 | } else { | |
| 712 | pru_flags = 0; | |
| 713 | } | |
| 984263bc MD |
714 | /* |
| 715 | * XXX all the SS_CANTSENDMORE checks previously | |
| 716 | * done could be out of date. We could have recieved | |
| 717 | * a reset packet in an interrupt or maybe we slept | |
| 718 | * while doing page faults in uiomove() etc. We could | |
| 719 | * probably recheck again inside the splnet() protection | |
| 720 | * here, but there are probably other places that this | |
| 721 | * also happens. We must rethink this. | |
| 722 | */ | |
| 6b6e0885 | 723 | error = so_pru_send(so, pru_flags, top, addr, control, td); |
| 984263bc MD |
724 | if (dontroute) |
| 725 | so->so_options &= ~SO_DONTROUTE; | |
| 726 | clen = 0; | |
| 727 | control = 0; | |
| e28d8186 | 728 | top = NULL; |
| 984263bc MD |
729 | mp = ⊤ |
| 730 | if (error) | |
| 6b6e0885 | 731 | goto release; |
| 984263bc MD |
732 | } while (resid && space > 0); |
| 733 | } while (resid); | |
| 734 | ||
| 735 | release: | |
| 6d49aa6f | 736 | ssb_unlock(&so->so_snd); |
| 984263bc MD |
737 | out: |
| 738 | if (top) | |
| 739 | m_freem(top); | |
| 740 | if (control) | |
| 741 | m_freem(control); | |
| 742 | return (error); | |
| 743 | } | |
| 744 | ||
| 745 | /* | |
| 6ea1e9b9 JH |
746 | * A specialization of sosend() for UDP based on protocol-specific knowledge: |
| 747 | * so->so_proto->pr_flags has the PR_ATOMIC field set. This means that | |
| 748 | * sosendallatonce() returns true, | |
| 749 | * the "atomic" variable is true, | |
| 750 | * and sosendudp() blocks until space is available for the entire send. | |
| 751 | * so->so_proto->pr_flags does not have the PR_CONNREQUIRED or | |
| 752 | * PR_IMPLOPCL flags set. | |
| 753 | * UDP has no out-of-band data. | |
| 754 | * UDP has no control data. | |
| 755 | * UDP does not support MSG_EOR. | |
| 756 | */ | |
| 757 | int | |
| 758 | sosendudp(struct socket *so, struct sockaddr *addr, struct uio *uio, | |
| 759 | struct mbuf *top, struct mbuf *control, int flags, struct thread *td) | |
| 760 | { | |
| 6ea1e9b9 | 761 | boolean_t dontroute; /* temporary SO_DONTROUTE setting */ |
| e54488bb MD |
762 | size_t resid; |
| 763 | int error; | |
| 764 | int space; | |
| 6ea1e9b9 | 765 | |
| fde7ac71 SS |
766 | if (td->td_lwp != NULL) |
| 767 | td->td_lwp->lwp_ru.ru_msgsnd++; | |
| 6ea1e9b9 JH |
768 | if (control) |
| 769 | m_freem(control); | |
| 770 | ||
| 771 | KASSERT((uio && !top) || (top && !uio), ("bad arguments to sosendudp")); | |
| e54488bb | 772 | resid = uio ? uio->uio_resid : (size_t)top->m_pkthdr.len; |
| 6ea1e9b9 JH |
773 | |
| 774 | restart: | |
| 6d49aa6f | 775 | error = ssb_lock(&so->so_snd, SBLOCKWAIT(flags)); |
| 6ea1e9b9 JH |
776 | if (error) |
| 777 | goto out; | |
| 778 | ||
| 6ea1e9b9 JH |
779 | if (so->so_state & SS_CANTSENDMORE) |
| 780 | gotoerr(EPIPE); | |
| 781 | if (so->so_error) { | |
| 782 | error = so->so_error; | |
| 783 | so->so_error = 0; | |
| 6ea1e9b9 JH |
784 | goto release; |
| 785 | } | |
| 786 | if (!(so->so_state & SS_ISCONNECTED) && addr == NULL) | |
| 787 | gotoerr(EDESTADDRREQ); | |
| 6d49aa6f | 788 | if (resid > so->so_snd.ssb_hiwat) |
| 6ea1e9b9 | 789 | gotoerr(EMSGSIZE); |
| e54488bb MD |
790 | space = ssb_space(&so->so_snd); |
| 791 | if (uio && (space < 0 || (size_t)space < resid)) { | |
| 9ba76b73 | 792 | if (flags & (MSG_FNONBLOCKING|MSG_DONTWAIT)) |
| 6ea1e9b9 | 793 | gotoerr(EWOULDBLOCK); |
| 6d49aa6f MD |
794 | ssb_unlock(&so->so_snd); |
| 795 | error = ssb_wait(&so->so_snd); | |
| 6ea1e9b9 JH |
796 | if (error) |
| 797 | goto out; | |
| 798 | goto restart; | |
| 799 | } | |
| 6ea1e9b9 JH |
800 | |
| 801 | if (uio) { | |
| e12241e1 | 802 | top = m_uiomove(uio); |
| 6ea1e9b9 JH |
803 | if (top == NULL) |
| 804 | goto release; | |
| 805 | } | |
| 806 | ||
| 807 | dontroute = (flags & MSG_DONTROUTE) && !(so->so_options & SO_DONTROUTE); | |
| 808 | if (dontroute) | |
| 809 | so->so_options |= SO_DONTROUTE; | |
| 810 | ||
| 811 | error = so_pru_send(so, 0, top, addr, NULL, td); | |
| 812 | top = NULL; /* sent or freed in lower layer */ | |
| 813 | ||
| 814 | if (dontroute) | |
| 815 | so->so_options &= ~SO_DONTROUTE; | |
| 816 | ||
| 817 | release: | |
| 6d49aa6f | 818 | ssb_unlock(&so->so_snd); |
| 6ea1e9b9 JH |
819 | out: |
| 820 | if (top) | |
| 821 | m_freem(top); | |
| 822 | return (error); | |
| 823 | } | |
| 824 | ||
| 825 | /* | |
| 984263bc | 826 | * Implement receive operations on a socket. |
| 6cef7136 | 827 | * |
| 6d49aa6f | 828 | * We depend on the way that records are added to the signalsockbuf |
| 984263bc MD |
829 | * by sbappend*. In particular, each record (mbufs linked through m_next) |
| 830 | * must begin with an address if the protocol so specifies, | |
| 831 | * followed by an optional mbuf or mbufs containing ancillary data, | |
| 832 | * and then zero or more mbufs of data. | |
| 6cef7136 MD |
833 | * |
| 834 | * Although the signalsockbuf is locked, new data may still be appended. | |
| 835 | * A token inside the ssb_lock deals with MP issues and still allows | |
| 836 | * the network to access the socket if we block in a uio. | |
| 984263bc MD |
837 | * |
| 838 | * The caller may receive the data as a single mbuf chain by supplying | |
| 839 | * an mbuf **mp0 for use in returning the chain. The uio is then used | |
| 840 | * only for the count in uio_resid. | |
| 841 | */ | |
| 842 | int | |
| c972a82f | 843 | soreceive(struct socket *so, struct sockaddr **psa, struct uio *uio, |
| 6d49aa6f | 844 | struct sockbuf *sio, struct mbuf **controlp, int *flagsp) |
| 984263bc | 845 | { |
| d8a9a23b | 846 | struct mbuf *m, *n; |
| 857caa4a | 847 | struct mbuf *free_chain = NULL; |
| e43a034f | 848 | int flags, len, error, offset; |
| 984263bc | 849 | struct protosw *pr = so->so_proto; |
| 984263bc | 850 | int moff, type = 0; |
| e54488bb | 851 | size_t resid, orig_resid; |
| d8a9a23b MD |
852 | |
| 853 | if (uio) | |
| 854 | resid = uio->uio_resid; | |
| 855 | else | |
| e54488bb | 856 | resid = (size_t)(sio->sb_climit - sio->sb_cc); |
| d8a9a23b | 857 | orig_resid = resid; |
| 984263bc | 858 | |
| 984263bc | 859 | if (psa) |
| 857caa4a | 860 | *psa = NULL; |
| 984263bc | 861 | if (controlp) |
| 857caa4a | 862 | *controlp = NULL; |
| 984263bc MD |
863 | if (flagsp) |
| 864 | flags = *flagsp &~ MSG_EOR; | |
| 865 | else | |
| 866 | flags = 0; | |
| 867 | if (flags & MSG_OOB) { | |
| 74f1caca | 868 | m = m_get(MB_WAIT, MT_DATA); |
| 984263bc MD |
869 | if (m == NULL) |
| 870 | return (ENOBUFS); | |
| 6b6e0885 | 871 | error = so_pru_rcvoob(so, m, flags & MSG_PEEK); |
| 984263bc MD |
872 | if (error) |
| 873 | goto bad; | |
| d8a9a23b MD |
874 | if (sio) { |
| 875 | do { | |
| 6d49aa6f | 876 | sbappend(sio, m); |
| e54488bb MD |
877 | KKASSERT(resid >= (size_t)m->m_len); |
| 878 | resid -= (size_t)m->m_len; | |
| d8a9a23b MD |
879 | } while (resid > 0 && m); |
| 880 | } else { | |
| 881 | do { | |
| 882 | uio->uio_resid = resid; | |
| 883 | error = uiomove(mtod(m, caddr_t), | |
| e54488bb MD |
884 | (int)szmin(resid, m->m_len), |
| 885 | uio); | |
| d8a9a23b MD |
886 | resid = uio->uio_resid; |
| 887 | m = m_free(m); | |
| 888 | } while (uio->uio_resid && error == 0 && m); | |
| 889 | } | |
| 984263bc MD |
890 | bad: |
| 891 | if (m) | |
| 892 | m_freem(m); | |
| 893 | return (error); | |
| 894 | } | |
| e54488bb | 895 | if ((so->so_state & SS_ISCONFIRMING) && resid) |
| 6b6e0885 | 896 | so_pru_rcvd(so, 0); |
| 984263bc | 897 | |
| 20156c7a MD |
898 | /* |
| 899 | * The token interlocks against the protocol thread while | |
| 900 | * ssb_lock is a blocking lock against other userland entities. | |
| 901 | */ | |
| 902 | lwkt_gettoken(&so->so_rcv.ssb_token); | |
| 984263bc | 903 | restart: |
| 6d49aa6f | 904 | error = ssb_lock(&so->so_rcv, SBLOCKWAIT(flags)); |
| 984263bc | 905 | if (error) |
| 857caa4a | 906 | goto done; |
| 984263bc | 907 | |
| 6d49aa6f | 908 | m = so->so_rcv.ssb_mb; |
| 984263bc MD |
909 | /* |
| 910 | * If we have less data than requested, block awaiting more | |
| 911 | * (subject to any timeout) if: | |
| 912 | * 1. the current count is less than the low water mark, or | |
| 913 | * 2. MSG_WAITALL is set, and it is possible to do the entire | |
| 914 | * receive operation at once if we block (resid <= hiwat). | |
| 915 | * 3. MSG_DONTWAIT is not set | |
| 916 | * If MSG_WAITALL is set but resid is larger than the receive buffer, | |
| 917 | * we have to do the receive in sections, and thus risk returning | |
| 918 | * a short count if a timeout or signal occurs after we start. | |
| 919 | */ | |
| 857caa4a | 920 | if (m == NULL || (((flags & MSG_DONTWAIT) == 0 && |
| e54488bb | 921 | (size_t)so->so_rcv.ssb_cc < resid) && |
| 6d49aa6f | 922 | (so->so_rcv.ssb_cc < so->so_rcv.ssb_lowat || |
| e54488bb | 923 | ((flags & MSG_WAITALL) && resid <= (size_t)so->so_rcv.ssb_hiwat)) && |
| 984263bc | 924 | m->m_nextpkt == 0 && (pr->pr_flags & PR_ATOMIC) == 0)) { |
| 6d49aa6f | 925 | KASSERT(m != NULL || !so->so_rcv.ssb_cc, ("receive 1")); |
| 984263bc MD |
926 | if (so->so_error) { |
| 927 | if (m) | |
| 928 | goto dontblock; | |
| 929 | error = so->so_error; | |
| 930 | if ((flags & MSG_PEEK) == 0) | |
| 931 | so->so_error = 0; | |
| 932 | goto release; | |
| 933 | } | |
| 934 | if (so->so_state & SS_CANTRCVMORE) { | |
| 935 | if (m) | |
| 936 | goto dontblock; | |
| 937 | else | |
| 938 | goto release; | |
| 939 | } | |
| 857caa4a | 940 | for (; m; m = m->m_next) { |
| 984263bc | 941 | if (m->m_type == MT_OOBDATA || (m->m_flags & M_EOR)) { |
| 6d49aa6f | 942 | m = so->so_rcv.ssb_mb; |
| 984263bc MD |
943 | goto dontblock; |
| 944 | } | |
| 857caa4a | 945 | } |
| 984263bc | 946 | if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 && |
| 6b6e0885 | 947 | (pr->pr_flags & PR_CONNREQUIRED)) { |
| 984263bc MD |
948 | error = ENOTCONN; |
| 949 | goto release; | |
| 950 | } | |
| d8a9a23b | 951 | if (resid == 0) |
| 984263bc | 952 | goto release; |
| 9ba76b73 | 953 | if (flags & (MSG_FNONBLOCKING|MSG_DONTWAIT)) { |
| 984263bc MD |
954 | error = EWOULDBLOCK; |
| 955 | goto release; | |
| 956 | } | |
| 6d49aa6f MD |
957 | ssb_unlock(&so->so_rcv); |
| 958 | error = ssb_wait(&so->so_rcv); | |
| 984263bc | 959 | if (error) |
| 857caa4a | 960 | goto done; |
| 984263bc MD |
961 | goto restart; |
| 962 | } | |
| 963 | dontblock: | |
| d8a9a23b | 964 | if (uio && uio->uio_td && uio->uio_td->td_proc) |
| fde7ac71 | 965 | uio->uio_td->td_lwp->lwp_ru.ru_msgrcv++; |
| 857caa4a MD |
966 | |
| 967 | /* | |
| 968 | * note: m should be == sb_mb here. Cache the next record while | |
| 969 | * cleaning up. Note that calling m_free*() will break out critical | |
| 970 | * section. | |
| 971 | */ | |
| 6d49aa6f | 972 | KKASSERT(m == so->so_rcv.ssb_mb); |
| 857caa4a MD |
973 | |
| 974 | /* | |
| 975 | * Skip any address mbufs prepending the record. | |
| 976 | */ | |
| 984263bc MD |
977 | if (pr->pr_flags & PR_ADDR) { |
| 978 | KASSERT(m->m_type == MT_SONAME, ("receive 1a")); | |
| 979 | orig_resid = 0; | |
| 980 | if (psa) | |
| cfa2ba21 | 981 | *psa = dup_sockaddr(mtod(m, struct sockaddr *)); |
| 857caa4a | 982 | if (flags & MSG_PEEK) |
| 984263bc | 983 | m = m->m_next; |
| 857caa4a | 984 | else |
| 6d49aa6f | 985 | m = sbunlinkmbuf(&so->so_rcv.sb, m, &free_chain); |
| 984263bc | 986 | } |
| 857caa4a MD |
987 | |
| 988 | /* | |
| 989 | * Skip any control mbufs prepending the record. | |
| 990 | */ | |
| 78812139 EN |
991 | #ifdef SCTP |
| 992 | if (pr->pr_flags & PR_ADDR_OPT) { | |
| 993 | /* | |
| 994 | * For SCTP we may be getting a | |
| 995 | * whole message OR a partial delivery. | |
| 996 | */ | |
| 857caa4a | 997 | if (m && m->m_type == MT_SONAME) { |
| 78812139 EN |
998 | orig_resid = 0; |
| 999 | if (psa) | |
| 1000 | *psa = dup_sockaddr(mtod(m, struct sockaddr *)); | |
| 857caa4a | 1001 | if (flags & MSG_PEEK) |
| 78812139 | 1002 | m = m->m_next; |
| 857caa4a | 1003 | else |
| 6d49aa6f | 1004 | m = sbunlinkmbuf(&so->so_rcv.sb, m, &free_chain); |
| 78812139 EN |
1005 | } |
| 1006 | } | |
| 1007 | #endif /* SCTP */ | |
| 984263bc MD |
1008 | while (m && m->m_type == MT_CONTROL && error == 0) { |
| 1009 | if (flags & MSG_PEEK) { | |
| 1010 | if (controlp) | |
| 1011 | *controlp = m_copy(m, 0, m->m_len); | |
| 857caa4a | 1012 | m = m->m_next; /* XXX race */ |
| 984263bc | 1013 | } else { |
| 984263bc | 1014 | if (controlp) { |
| 6d49aa6f | 1015 | n = sbunlinkmbuf(&so->so_rcv.sb, m, NULL); |
| 984263bc MD |
1016 | if (pr->pr_domain->dom_externalize && |
| 1017 | mtod(m, struct cmsghdr *)->cmsg_type == | |
| 1018 | SCM_RIGHTS) | |
| 1019 | error = (*pr->pr_domain->dom_externalize)(m); | |
| 1020 | *controlp = m; | |
| 857caa4a | 1021 | m = n; |
| 984263bc | 1022 | } else { |
| 6d49aa6f | 1023 | m = sbunlinkmbuf(&so->so_rcv.sb, m, &free_chain); |
| 984263bc MD |
1024 | } |
| 1025 | } | |
| 857caa4a | 1026 | if (controlp && *controlp) { |
| 984263bc MD |
1027 | orig_resid = 0; |
| 1028 | controlp = &(*controlp)->m_next; | |
| 1029 | } | |
| 1030 | } | |
| 857caa4a MD |
1031 | |
| 1032 | /* | |
| 1033 | * flag OOB data. | |
| 1034 | */ | |
| 984263bc | 1035 | if (m) { |
| 984263bc MD |
1036 | type = m->m_type; |
| 1037 | if (type == MT_OOBDATA) | |
| 1038 | flags |= MSG_OOB; | |
| 1039 | } | |
| 857caa4a MD |
1040 | |
| 1041 | /* | |
| 1042 | * Copy to the UIO or mbuf return chain (*mp). | |
| 1043 | */ | |
| 984263bc MD |
1044 | moff = 0; |
| 1045 | offset = 0; | |
| d8a9a23b | 1046 | while (m && resid > 0 && error == 0) { |
| 984263bc MD |
1047 | if (m->m_type == MT_OOBDATA) { |
| 1048 | if (type != MT_OOBDATA) | |
| 1049 | break; | |
| 1050 | } else if (type == MT_OOBDATA) | |
| 1051 | break; | |
| 1052 | else | |
| 1053 | KASSERT(m->m_type == MT_DATA || m->m_type == MT_HEADER, | |
| 1054 | ("receive 3")); | |
| 6cef7136 | 1055 | soclrstate(so, SS_RCVATMARK); |
| e54488bb | 1056 | len = (resid > INT_MAX) ? INT_MAX : resid; |
| 984263bc MD |
1057 | if (so->so_oobmark && len > so->so_oobmark - offset) |
| 1058 | len = so->so_oobmark - offset; | |
| 1059 | if (len > m->m_len - moff) | |
| 1060 | len = m->m_len - moff; | |
| d8a9a23b | 1061 | |
| 984263bc | 1062 | /* |
| d8a9a23b MD |
1063 | * Copy out to the UIO or pass the mbufs back to the SIO. |
| 1064 | * The SIO is dealt with when we eat the mbuf, but deal | |
| 1065 | * with the resid here either way. | |
| 984263bc | 1066 | */ |
| d8a9a23b | 1067 | if (uio) { |
| d8a9a23b MD |
1068 | uio->uio_resid = resid; |
| 1069 | error = uiomove(mtod(m, caddr_t) + moff, len, uio); | |
| 1070 | resid = uio->uio_resid; | |
| 984263bc MD |
1071 | if (error) |
| 1072 | goto release; | |
| 857caa4a | 1073 | } else { |
| e54488bb | 1074 | resid -= (size_t)len; |
| 857caa4a MD |
1075 | } |
| 1076 | ||
| 1077 | /* | |
| 1078 | * Eat the entire mbuf or just a piece of it | |
| 1079 | */ | |
| 984263bc MD |
1080 | if (len == m->m_len - moff) { |
| 1081 | if (m->m_flags & M_EOR) | |
| 1082 | flags |= MSG_EOR; | |
| 78812139 EN |
1083 | #ifdef SCTP |
| 1084 | if (m->m_flags & M_NOTIFICATION) | |
| 1085 | flags |= MSG_NOTIFICATION; | |
| 1086 | #endif /* SCTP */ | |
| 984263bc MD |
1087 | if (flags & MSG_PEEK) { |
| 1088 | m = m->m_next; | |
| 1089 | moff = 0; | |
| 1090 | } else { | |
| d8a9a23b | 1091 | if (sio) { |
| 6d49aa6f MD |
1092 | n = sbunlinkmbuf(&so->so_rcv.sb, m, NULL); |
| 1093 | sbappend(sio, m); | |
| 857caa4a | 1094 | m = n; |
| 984263bc | 1095 | } else { |
| 6d49aa6f | 1096 | m = sbunlinkmbuf(&so->so_rcv.sb, m, &free_chain); |
| 984263bc | 1097 | } |
| 984263bc MD |
1098 | } |
| 1099 | } else { | |
| 857caa4a | 1100 | if (flags & MSG_PEEK) { |
| 984263bc | 1101 | moff += len; |
| 857caa4a | 1102 | } else { |
| d8a9a23b | 1103 | if (sio) { |
| 6d49aa6f MD |
1104 | n = m_copym(m, 0, len, MB_WAIT); |
| 1105 | if (n) | |
| 1106 | sbappend(sio, n); | |
| d8a9a23b | 1107 | } |
| 984263bc MD |
1108 | m->m_data += len; |
| 1109 | m->m_len -= len; | |
| 6d49aa6f | 1110 | so->so_rcv.ssb_cc -= len; |
| 984263bc MD |
1111 | } |
| 1112 | } | |
| 1113 | if (so->so_oobmark) { | |
| 1114 | if ((flags & MSG_PEEK) == 0) { | |
| 1115 | so->so_oobmark -= len; | |
| 1116 | if (so->so_oobmark == 0) { | |
| 6cef7136 | 1117 | sosetstate(so, SS_RCVATMARK); |
| 984263bc MD |
1118 | break; |
| 1119 | } | |
| 1120 | } else { | |
| 1121 | offset += len; | |
| 1122 | if (offset == so->so_oobmark) | |
| 1123 | break; | |
| 1124 | } | |
| 1125 | } | |
| 1126 | if (flags & MSG_EOR) | |
| 1127 | break; | |
| 1128 | /* | |
| 1129 | * If the MSG_WAITALL flag is set (for non-atomic socket), | |
| d8a9a23b | 1130 | * we must not quit until resid == 0 or an error |
| 984263bc MD |
1131 | * termination. If a signal/timeout occurs, return |
| 1132 | * with a short count but without error. | |
| 6d49aa6f | 1133 | * Keep signalsockbuf locked against other readers. |
| 984263bc | 1134 | */ |
| d8a9a23b MD |
1135 | while ((flags & MSG_WAITALL) && m == NULL && |
| 1136 | resid > 0 && !sosendallatonce(so) && | |
| 6d49aa6f | 1137 | so->so_rcv.ssb_mb == NULL) { |
| 984263bc MD |
1138 | if (so->so_error || so->so_state & SS_CANTRCVMORE) |
| 1139 | break; | |
| 1140 | /* | |
| 1141 | * The window might have closed to zero, make | |
| 1142 | * sure we send an ack now that we've drained | |
| 1143 | * the buffer or we might end up blocking until | |
| 1144 | * the idle takes over (5 seconds). | |
| 1145 | */ | |
| 1146 | if (pr->pr_flags & PR_WANTRCVD && so->so_pcb) | |
| 6b6e0885 | 1147 | so_pru_rcvd(so, flags); |
| 6d49aa6f | 1148 | error = ssb_wait(&so->so_rcv); |
| 984263bc | 1149 | if (error) { |
| 6d49aa6f | 1150 | ssb_unlock(&so->so_rcv); |
| 857caa4a MD |
1151 | error = 0; |
| 1152 | goto done; | |
| 984263bc | 1153 | } |
| 6d49aa6f | 1154 | m = so->so_rcv.ssb_mb; |
| 984263bc MD |
1155 | } |
| 1156 | } | |
| 1157 | ||
| 857caa4a MD |
1158 | /* |
| 1159 | * If an atomic read was requested but unread data still remains | |
| 1160 | * in the record, set MSG_TRUNC. | |
| 1161 | */ | |
| bf8a9a6f | 1162 | if (m && pr->pr_flags & PR_ATOMIC) |
| 984263bc | 1163 | flags |= MSG_TRUNC; |
| 857caa4a MD |
1164 | |
| 1165 | /* | |
| 1166 | * Cleanup. If an atomic read was requested drop any unread data. | |
| 1167 | */ | |
| 1168 | if ((flags & MSG_PEEK) == 0) { | |
| 1169 | if (m && (pr->pr_flags & PR_ATOMIC)) | |
| 6d49aa6f | 1170 | sbdroprecord(&so->so_rcv.sb); |
| 857caa4a | 1171 | if ((pr->pr_flags & PR_WANTRCVD) && so->so_pcb) |
| 6b6e0885 | 1172 | so_pru_rcvd(so, flags); |
| 984263bc | 1173 | } |
| bf8a9a6f | 1174 | |
| d8a9a23b | 1175 | if (orig_resid == resid && orig_resid && |
| 984263bc | 1176 | (flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) { |
| 6d49aa6f | 1177 | ssb_unlock(&so->so_rcv); |
| 984263bc MD |
1178 | goto restart; |
| 1179 | } | |
| 1180 | ||
| 1181 | if (flagsp) | |
| 1182 | *flagsp |= flags; | |
| 1183 | release: | |
| 6d49aa6f | 1184 | ssb_unlock(&so->so_rcv); |
| 857caa4a | 1185 | done: |
| 20156c7a | 1186 | lwkt_reltoken(&so->so_rcv.ssb_token); |
| 857caa4a MD |
1187 | if (free_chain) |
| 1188 | m_freem(free_chain); | |
| 984263bc MD |
1189 | return (error); |
| 1190 | } | |
| 1191 | ||
| edf5c732 MD |
1192 | /* |
| 1193 | * Shut a socket down. Note that we do not get a frontend lock as we | |
| 1194 | * want to be able to shut the socket down even if another thread is | |
| 1195 | * blocked in a read(), thus waking it up. | |
| 1196 | */ | |
| 984263bc | 1197 | int |
| c972a82f | 1198 | soshutdown(struct socket *so, int how) |
| 984263bc | 1199 | { |
| 984263bc MD |
1200 | if (!(how == SHUT_RD || how == SHUT_WR || how == SHUT_RDWR)) |
| 1201 | return (EINVAL); | |
| 1202 | ||
| ff518922 | 1203 | if (how != SHUT_WR) { |
| edf5c732 | 1204 | /*ssb_lock(&so->so_rcv, M_WAITOK);*/ |
| 984263bc | 1205 | sorflush(so); |
| edf5c732 | 1206 | /*ssb_unlock(&so->so_rcv);*/ |
| ff518922 | 1207 | } |
| 984263bc | 1208 | if (how != SHUT_RD) |
| 6b6e0885 | 1209 | return (so_pru_shutdown(so)); |
| 984263bc MD |
1210 | return (0); |
| 1211 | } | |
| 1212 | ||
| 1213 | void | |
| c972a82f | 1214 | sorflush(struct socket *so) |
| 984263bc | 1215 | { |
| 6d49aa6f | 1216 | struct signalsockbuf *ssb = &so->so_rcv; |
| 1fd87d54 | 1217 | struct protosw *pr = so->so_proto; |
| 6d49aa6f | 1218 | struct signalsockbuf asb; |
| 984263bc | 1219 | |
| 14343ad3 | 1220 | atomic_set_int(&ssb->ssb_flags, SSB_NOINTR); |
| e43a034f | 1221 | |
| ff518922 | 1222 | lwkt_gettoken(&ssb->ssb_token); |
| 984263bc | 1223 | socantrcvmore(so); |
| 6d49aa6f | 1224 | asb = *ssb; |
| 14343ad3 MD |
1225 | |
| 1226 | /* | |
| 1227 | * Can't just blow up the ssb structure here | |
| 1228 | */ | |
| ff518922 | 1229 | bzero(&ssb->sb, sizeof(ssb->sb)); |
| 14343ad3 | 1230 | ssb->ssb_timeo = 0; |
| 14343ad3 MD |
1231 | ssb->ssb_lowat = 0; |
| 1232 | ssb->ssb_hiwat = 0; | |
| 1233 | ssb->ssb_mbmax = 0; | |
| 1234 | atomic_clear_int(&ssb->ssb_flags, SSB_CLEAR_MASK); | |
| 1235 | ||
| edf5c732 | 1236 | if ((pr->pr_flags & PR_RIGHTS) && pr->pr_domain->dom_dispose) |
| 6d49aa6f MD |
1237 | (*pr->pr_domain->dom_dispose)(asb.ssb_mb); |
| 1238 | ssb_release(&asb, so); | |
| edf5c732 MD |
1239 | |
| 1240 | lwkt_reltoken(&ssb->ssb_token); | |
| 984263bc MD |
1241 | } |
| 1242 | ||
| 1243 | #ifdef INET | |
| 1244 | static int | |
| c972a82f | 1245 | do_setopt_accept_filter(struct socket *so, struct sockopt *sopt) |
| 984263bc MD |
1246 | { |
| 1247 | struct accept_filter_arg *afap = NULL; | |
| 1248 | struct accept_filter *afp; | |
| 1249 | struct so_accf *af = so->so_accf; | |
| 1250 | int error = 0; | |
| 1251 | ||
| 1252 | /* do not set/remove accept filters on non listen sockets */ | |
| 1253 | if ((so->so_options & SO_ACCEPTCONN) == 0) { | |
| 1254 | error = EINVAL; | |
| 1255 | goto out; | |
| 1256 | } | |
| 1257 | ||
| 1258 | /* removing the filter */ | |
| 1259 | if (sopt == NULL) { | |
| 1260 | if (af != NULL) { | |
| 1261 | if (af->so_accept_filter != NULL && | |
| 1262 | af->so_accept_filter->accf_destroy != NULL) { | |
| 1263 | af->so_accept_filter->accf_destroy(so); | |
| 1264 | } | |
| 1265 | if (af->so_accept_filter_str != NULL) { | |
| 1266 | FREE(af->so_accept_filter_str, M_ACCF); | |
| 1267 | } | |
| 1268 | FREE(af, M_ACCF); | |
| 1269 | so->so_accf = NULL; | |
| 1270 | } | |
| 1271 | so->so_options &= ~SO_ACCEPTFILTER; | |
| 1272 | return (0); | |
| 1273 | } | |
| 1274 | /* adding a filter */ | |
| 1275 | /* must remove previous filter first */ | |
| 1276 | if (af != NULL) { | |
| 1277 | error = EINVAL; | |
| 1278 | goto out; | |
| 1279 | } | |
| 1280 | /* don't put large objects on the kernel stack */ | |
| 1281 | MALLOC(afap, struct accept_filter_arg *, sizeof(*afap), M_TEMP, M_WAITOK); | |
| 1282 | error = sooptcopyin(sopt, afap, sizeof *afap, sizeof *afap); | |
| 1283 | afap->af_name[sizeof(afap->af_name)-1] = '\0'; | |
| 1284 | afap->af_arg[sizeof(afap->af_arg)-1] = '\0'; | |
| 1285 | if (error) | |
| 1286 | goto out; | |
| 1287 | afp = accept_filt_get(afap->af_name); | |
| 1288 | if (afp == NULL) { | |
| 1289 | error = ENOENT; | |
| 1290 | goto out; | |
| 1291 | } | |
| e7b4468c | 1292 | MALLOC(af, struct so_accf *, sizeof(*af), M_ACCF, M_WAITOK | M_ZERO); |
| 984263bc MD |
1293 | if (afp->accf_create != NULL) { |
| 1294 | if (afap->af_name[0] != '\0') { | |
| 1295 | int len = strlen(afap->af_name) + 1; | |
| 1296 | ||
| 1297 | MALLOC(af->so_accept_filter_str, char *, len, M_ACCF, M_WAITOK); | |
| 1298 | strcpy(af->so_accept_filter_str, afap->af_name); | |
| 1299 | } | |
| 1300 | af->so_accept_filter_arg = afp->accf_create(so, afap->af_arg); | |
| 1301 | if (af->so_accept_filter_arg == NULL) { | |
| 1302 | FREE(af->so_accept_filter_str, M_ACCF); | |
| 1303 | FREE(af, M_ACCF); | |
| 1304 | so->so_accf = NULL; | |
| 1305 | error = EINVAL; | |
| 1306 | goto out; | |
| 1307 | } | |
| 1308 | } | |
| 1309 | af->so_accept_filter = afp; | |
| 1310 | so->so_accf = af; | |
| 1311 | so->so_options |= SO_ACCEPTFILTER; | |
| 1312 | out: | |
| 1313 | if (afap != NULL) | |
| 1314 | FREE(afap, M_TEMP); | |
| 1315 | return (error); | |
| 1316 | } | |
| 1317 | #endif /* INET */ | |
| 1318 | ||
| 1319 | /* | |
| 1320 | * Perhaps this routine, and sooptcopyout(), below, ought to come in | |
| 1321 | * an additional variant to handle the case where the option value needs | |
| 1322 | * to be some kind of integer, but not a specific size. | |
| 1323 | * In addition to their use here, these functions are also called by the | |
| 1324 | * protocol-level pr_ctloutput() routines. | |
| 1325 | */ | |
| 1326 | int | |
| c972a82f | 1327 | sooptcopyin(struct sockopt *sopt, void *buf, size_t len, size_t minlen) |
| 984263bc | 1328 | { |
| de0003fe AE |
1329 | return soopt_to_kbuf(sopt, buf, len, minlen); |
| 1330 | } | |
| 1331 | ||
| 1332 | int | |
| 1333 | soopt_to_kbuf(struct sockopt *sopt, void *buf, size_t len, size_t minlen) | |
| 1334 | { | |
| 984263bc MD |
1335 | size_t valsize; |
| 1336 | ||
| 792239df | 1337 | KKASSERT(!sopt->sopt_val || kva_p(sopt->sopt_val)); |
| de0003fe AE |
1338 | KKASSERT(kva_p(buf)); |
| 1339 | ||
| 984263bc MD |
1340 | /* |
| 1341 | * If the user gives us more than we wanted, we ignore it, | |
| 1342 | * but if we don't get the minimum length the caller | |
| 1343 | * wants, we return EINVAL. On success, sopt->sopt_valsize | |
| 1344 | * is set to however much we actually retrieved. | |
| 1345 | */ | |
| 1346 | if ((valsize = sopt->sopt_valsize) < minlen) | |
| 1347 | return EINVAL; | |
| 1348 | if (valsize > len) | |
| 1349 | sopt->sopt_valsize = valsize = len; | |
| 1350 | ||
| 984263bc MD |
1351 | bcopy(sopt->sopt_val, buf, valsize); |
| 1352 | return 0; | |
| 1353 | } | |
| 1354 | ||
| e71a125f AE |
1355 | |
| 1356 | int | |
| c972a82f | 1357 | sosetopt(struct socket *so, struct sockopt *sopt) |
| 984263bc MD |
1358 | { |
| 1359 | int error, optval; | |
| 1360 | struct linger l; | |
| 1361 | struct timeval tv; | |
| 1362 | u_long val; | |
| 14343ad3 | 1363 | struct signalsockbuf *sotmp; |
| 984263bc MD |
1364 | |
| 1365 | error = 0; | |
| e79d388f | 1366 | sopt->sopt_dir = SOPT_SET; |
| 984263bc | 1367 | if (sopt->sopt_level != SOL_SOCKET) { |
| 6b6e0885 | 1368 | if (so->so_proto && so->so_proto->pr_ctloutput) { |
| 002c1265 | 1369 | return (so_pr_ctloutput(so, sopt)); |
| 6b6e0885 | 1370 | } |
| 984263bc MD |
1371 | error = ENOPROTOOPT; |
| 1372 | } else { | |
| 1373 | switch (sopt->sopt_name) { | |
| 1374 | #ifdef INET | |
| 1375 | case SO_ACCEPTFILTER: | |
| 1376 | error = do_setopt_accept_filter(so, sopt); | |
| 1377 | if (error) | |
| 1378 | goto bad; | |
| 1379 | break; | |
| 1380 | #endif /* INET */ | |
| 1381 | case SO_LINGER: | |
| 1382 | error = sooptcopyin(sopt, &l, sizeof l, sizeof l); | |
| 1383 | if (error) | |
| 1384 | goto bad; | |
| 1385 | ||
| 1386 | so->so_linger = l.l_linger; | |
| 1387 | if (l.l_onoff) | |
| 1388 | so->so_options |= SO_LINGER; | |
| 1389 | else | |
| 1390 | so->so_options &= ~SO_LINGER; | |
| 1391 | break; | |
| 1392 | ||
| 1393 | case SO_DEBUG: | |
| 1394 | case SO_KEEPALIVE: | |
| 1395 | case SO_DONTROUTE: | |
| 1396 | case SO_USELOOPBACK: | |
| 1397 | case SO_BROADCAST: | |
| 1398 | case SO_REUSEADDR: | |
| 1399 | case SO_REUSEPORT: | |
| 1400 | case SO_OOBINLINE: | |
| 1401 | case SO_TIMESTAMP: | |
| 1402 | error = sooptcopyin(sopt, &optval, sizeof optval, | |
| 1403 | sizeof optval); | |
| 1404 | if (error) | |
| 1405 | goto bad; | |
| 1406 | if (optval) | |
| 1407 | so->so_options |= sopt->sopt_name; | |
| 1408 | else | |
| 1409 | so->so_options &= ~sopt->sopt_name; | |
| 1410 | break; | |
| 1411 | ||
| 1412 | case SO_SNDBUF: | |
| 1413 | case SO_RCVBUF: | |
| 1414 | case SO_SNDLOWAT: | |
| 1415 | case SO_RCVLOWAT: | |
| 1416 | error = sooptcopyin(sopt, &optval, sizeof optval, | |
| 1417 | sizeof optval); | |
| 1418 | if (error) | |
| 1419 | goto bad; | |
| 1420 | ||
| 1421 | /* | |
| 1422 | * Values < 1 make no sense for any of these | |
| 1423 | * options, so disallow them. | |
| 1424 | */ | |
| 1425 | if (optval < 1) { | |
| 1426 | error = EINVAL; | |
| 1427 | goto bad; | |
| 1428 | } | |
| 1429 | ||
| 1430 | switch (sopt->sopt_name) { | |
| 1431 | case SO_SNDBUF: | |
| 1432 | case SO_RCVBUF: | |
| 6d49aa6f | 1433 | if (ssb_reserve(sopt->sopt_name == SO_SNDBUF ? |
| 984263bc | 1434 | &so->so_snd : &so->so_rcv, (u_long)optval, |
| e4700d00 JH |
1435 | so, |
| 1436 | &curproc->p_rlimit[RLIMIT_SBSIZE]) == 0) { | |
| 984263bc MD |
1437 | error = ENOBUFS; |
| 1438 | goto bad; | |
| 1439 | } | |
| 14343ad3 MD |
1440 | sotmp = (sopt->sopt_name == SO_SNDBUF) ? |
| 1441 | &so->so_snd : &so->so_rcv; | |
| 1442 | atomic_clear_int(&sotmp->ssb_flags, | |
| 1443 | SSB_AUTOSIZE); | |
| 984263bc MD |
1444 | break; |
| 1445 | ||
| 1446 | /* | |
| 1447 | * Make sure the low-water is never greater than | |
| 1448 | * the high-water. | |
| 1449 | */ | |
| 1450 | case SO_SNDLOWAT: | |
| 6d49aa6f MD |
1451 | so->so_snd.ssb_lowat = |
| 1452 | (optval > so->so_snd.ssb_hiwat) ? | |
| 1453 | so->so_snd.ssb_hiwat : optval; | |
| 14343ad3 MD |
1454 | atomic_clear_int(&so->so_snd.ssb_flags, |
| 1455 | SSB_AUTOLOWAT); | |
| 984263bc MD |
1456 | break; |
| 1457 | case SO_RCVLOWAT: | |
| 6d49aa6f MD |
1458 | so->so_rcv.ssb_lowat = |
| 1459 | (optval > so->so_rcv.ssb_hiwat) ? | |
| 1460 | so->so_rcv.ssb_hiwat : optval; | |
| 14343ad3 MD |
1461 | atomic_clear_int(&so->so_rcv.ssb_flags, |
| 1462 | SSB_AUTOLOWAT); | |
| 984263bc MD |
1463 | break; |
| 1464 | } | |
| 1465 | break; | |
| 1466 | ||
| 1467 | case SO_SNDTIMEO: | |
| 1468 | case SO_RCVTIMEO: | |
| 1469 | error = sooptcopyin(sopt, &tv, sizeof tv, | |
| 1470 | sizeof tv); | |
| 1471 | if (error) | |
| 1472 | goto bad; | |
| 1473 | ||
| 1474 | /* assert(hz > 0); */ | |
| 45546849 | 1475 | if (tv.tv_sec < 0 || tv.tv_sec > INT_MAX / hz || |
| 984263bc MD |
1476 | tv.tv_usec < 0 || tv.tv_usec >= 1000000) { |
| 1477 | error = EDOM; | |
| 1478 | goto bad; | |
| 1479 | } | |
| 1480 | /* assert(tick > 0); */ | |
| 45546849 | 1481 | /* assert(ULONG_MAX - INT_MAX >= 1000000); */ |
| a591f597 | 1482 | val = (u_long)(tv.tv_sec * hz) + tv.tv_usec / ustick; |
| 45546849 | 1483 | if (val > INT_MAX) { |
| 984263bc MD |
1484 | error = EDOM; |
| 1485 | goto bad; | |
| 1486 | } | |
| 1487 | if (val == 0 && tv.tv_usec != 0) | |
| 1488 | val = 1; | |
| 1489 | ||
| 1490 | switch (sopt->sopt_name) { | |
| 1491 | case SO_SNDTIMEO: | |
| 6d49aa6f | 1492 | so->so_snd.ssb_timeo = val; |
| 984263bc MD |
1493 | break; |
| 1494 | case SO_RCVTIMEO: | |
| 6d49aa6f | 1495 | so->so_rcv.ssb_timeo = val; |
| 984263bc MD |
1496 | break; |
| 1497 | } | |
| 1498 | break; | |
| 1499 | default: | |
| 1500 | error = ENOPROTOOPT; | |
| 1501 | break; | |
| 1502 | } | |
| 1503 | if (error == 0 && so->so_proto && so->so_proto->pr_ctloutput) { | |
| 002c1265 | 1504 | (void) so_pr_ctloutput(so, sopt); |
| 984263bc MD |
1505 | } |
| 1506 | } | |
| 1507 | bad: | |
| 1508 | return (error); | |
| 1509 | } | |
| 1510 | ||
| 1511 | /* Helper routine for getsockopt */ | |
| 1512 | int | |
| f1f552f6 | 1513 | sooptcopyout(struct sockopt *sopt, const void *buf, size_t len) |
| 984263bc | 1514 | { |
| de0003fe AE |
1515 | soopt_from_kbuf(sopt, buf, len); |
| 1516 | return 0; | |
| 1517 | } | |
| 1518 | ||
| 1519 | void | |
| 1520 | soopt_from_kbuf(struct sockopt *sopt, const void *buf, size_t len) | |
| 1521 | { | |
| 984263bc MD |
1522 | size_t valsize; |
| 1523 | ||
| 565d9f6f SZ |
1524 | if (len == 0) { |
| 1525 | sopt->sopt_valsize = 0; | |
| 1526 | return; | |
| 1527 | } | |
| 1528 | ||
| 792239df | 1529 | KKASSERT(!sopt->sopt_val || kva_p(sopt->sopt_val)); |
| de0003fe | 1530 | KKASSERT(kva_p(buf)); |
| 984263bc MD |
1531 | |
| 1532 | /* | |
| 1533 | * Documented get behavior is that we always return a value, | |
| 1534 | * possibly truncated to fit in the user's buffer. | |
| 1535 | * Traditional behavior is that we always tell the user | |
| 1536 | * precisely how much we copied, rather than something useful | |
| 1537 | * like the total amount we had available for her. | |
| 1538 | * Note that this interface is not idempotent; the entire answer must | |
| 1539 | * generated ahead of time. | |
| 1540 | */ | |
| 231d276b | 1541 | valsize = szmin(len, sopt->sopt_valsize); |
| 984263bc MD |
1542 | sopt->sopt_valsize = valsize; |
| 1543 | if (sopt->sopt_val != 0) { | |
| de0003fe | 1544 | bcopy(buf, sopt->sopt_val, valsize); |
| 984263bc | 1545 | } |
| e71a125f AE |
1546 | } |
| 1547 | ||
| 984263bc | 1548 | int |
| c972a82f | 1549 | sogetopt(struct socket *so, struct sockopt *sopt) |
| 984263bc MD |
1550 | { |
| 1551 | int error, optval; | |
| 755c519c | 1552 | long optval_l; |
| 984263bc MD |
1553 | struct linger l; |
| 1554 | struct timeval tv; | |
| 51f4ca92 | 1555 | #ifdef INET |
| 984263bc | 1556 | struct accept_filter_arg *afap; |
| 51f4ca92 | 1557 | #endif |
| 984263bc MD |
1558 | |
| 1559 | error = 0; | |
| e79d388f | 1560 | sopt->sopt_dir = SOPT_GET; |
| 984263bc MD |
1561 | if (sopt->sopt_level != SOL_SOCKET) { |
| 1562 | if (so->so_proto && so->so_proto->pr_ctloutput) { | |
| 002c1265 | 1563 | return (so_pr_ctloutput(so, sopt)); |
| 984263bc MD |
1564 | } else |
| 1565 | return (ENOPROTOOPT); | |
| 1566 | } else { | |
| 1567 | switch (sopt->sopt_name) { | |
| 1568 | #ifdef INET | |
| 1569 | case SO_ACCEPTFILTER: | |
| 1570 | if ((so->so_options & SO_ACCEPTCONN) == 0) | |
| 1571 | return (EINVAL); | |
| 1572 | MALLOC(afap, struct accept_filter_arg *, sizeof(*afap), | |
| e7b4468c | 1573 | M_TEMP, M_WAITOK | M_ZERO); |
| 984263bc MD |
1574 | if ((so->so_options & SO_ACCEPTFILTER) != 0) { |
| 1575 | strcpy(afap->af_name, so->so_accf->so_accept_filter->accf_name); | |
| 1576 | if (so->so_accf->so_accept_filter_str != NULL) | |
| 1577 | strcpy(afap->af_arg, so->so_accf->so_accept_filter_str); | |
| 1578 | } | |
| 1579 | error = sooptcopyout(sopt, afap, sizeof(*afap)); | |
| 1580 | FREE(afap, M_TEMP); | |
| 1581 | break; | |
| 1582 | #endif /* INET */ | |
| 1583 | ||
| 1584 | case SO_LINGER: | |
| 1585 | l.l_onoff = so->so_options & SO_LINGER; | |
| 1586 | l.l_linger = so->so_linger; | |
| 1587 | error = sooptcopyout(sopt, &l, sizeof l); | |
| 1588 | break; | |
| 1589 | ||
| 1590 | case SO_USELOOPBACK: | |
| 1591 | case SO_DONTROUTE: | |
| 1592 | case SO_DEBUG: | |
| 1593 | case SO_KEEPALIVE: | |
| 1594 | case SO_REUSEADDR: | |
| 1595 | case SO_REUSEPORT: | |
| 1596 | case SO_BROADCAST: | |
| 1597 | case SO_OOBINLINE: | |
| 1598 | case SO_TIMESTAMP: | |
| 1599 | optval = so->so_options & sopt->sopt_name; | |
| 1600 | integer: | |
| 1601 | error = sooptcopyout(sopt, &optval, sizeof optval); | |
| 1602 | break; | |
| 1603 | ||
| 1604 | case SO_TYPE: | |
| 1605 | optval = so->so_type; | |
| 1606 | goto integer; | |
| 1607 | ||
| 1608 | case SO_ERROR: | |
| 1609 | optval = so->so_error; | |
| 1610 | so->so_error = 0; | |
| 1611 | goto integer; | |
| 1612 | ||
| 1613 | case SO_SNDBUF: | |
| 6d49aa6f | 1614 | optval = so->so_snd.ssb_hiwat; |
| 984263bc MD |
1615 | goto integer; |
| 1616 | ||
| 1617 | case SO_RCVBUF: | |
| 6d49aa6f | 1618 | optval = so->so_rcv.ssb_hiwat; |
| 984263bc MD |
1619 | goto integer; |
| 1620 | ||
| 1621 | case SO_SNDLOWAT: | |
| 6d49aa6f | 1622 | optval = so->so_snd.ssb_lowat; |
| 984263bc MD |
1623 | goto integer; |
| 1624 | ||
| 1625 | case SO_RCVLOWAT: | |
| 6d49aa6f | 1626 | optval = so->so_rcv.ssb_lowat; |
| 984263bc MD |
1627 | goto integer; |
| 1628 | ||
| 1629 | case SO_SNDTIMEO: | |
| 1630 | case SO_RCVTIMEO: | |
| 1631 | optval = (sopt->sopt_name == SO_SNDTIMEO ? | |
| 6d49aa6f | 1632 | so->so_snd.ssb_timeo : so->so_rcv.ssb_timeo); |
| 984263bc MD |
1633 | |
| 1634 | tv.tv_sec = optval / hz; | |
| a591f597 | 1635 | tv.tv_usec = (optval % hz) * ustick; |
| 984263bc MD |
1636 | error = sooptcopyout(sopt, &tv, sizeof tv); |
| 1637 | break; | |
| 1638 | ||
| 755c519c SZ |
1639 | case SO_SNDSPACE: |
| 1640 | optval_l = ssb_space(&so->so_snd); | |
| 1641 | error = sooptcopyout(sopt, &optval_l, sizeof(optval_l)); | |
| 1642 | break; | |
| 1643 | ||
| 984263bc MD |
1644 | default: |
| 1645 | error = ENOPROTOOPT; | |
| 1646 | break; | |
| 1647 | } | |
| 1648 | return (error); | |
| 1649 | } | |
| 1650 | } | |
| 1651 | ||
| 1652 | /* XXX; prepare mbuf for (__FreeBSD__ < 3) routines. */ | |
| 1653 | int | |
| 1654 | soopt_getm(struct sockopt *sopt, struct mbuf **mp) | |
| 1655 | { | |
| 1656 | struct mbuf *m, *m_prev; | |
| bf6ac9fa JH |
1657 | int sopt_size = sopt->sopt_valsize, msize; |
| 1658 | ||
| 1659 | m = m_getl(sopt_size, sopt->sopt_td ? MB_WAIT : MB_DONTWAIT, MT_DATA, | |
| 1660 | 0, &msize); | |
| 1661 | if (m == NULL) | |
| 1662 | return (ENOBUFS); | |
| 1663 | m->m_len = min(msize, sopt_size); | |
| 984263bc MD |
1664 | sopt_size -= m->m_len; |
| 1665 | *mp = m; | |
| 1666 | m_prev = m; | |
| 1667 | ||
| bf6ac9fa JH |
1668 | while (sopt_size > 0) { |
| 1669 | m = m_getl(sopt_size, sopt->sopt_td ? MB_WAIT : MB_DONTWAIT, | |
| 1670 | MT_DATA, 0, &msize); | |
| 1671 | if (m == NULL) { | |
| 984263bc | 1672 | m_freem(*mp); |
| bf6ac9fa | 1673 | return (ENOBUFS); |
| 984263bc | 1674 | } |
| bf6ac9fa | 1675 | m->m_len = min(msize, sopt_size); |
| 984263bc MD |
1676 | sopt_size -= m->m_len; |
| 1677 | m_prev->m_next = m; | |
| 1678 | m_prev = m; | |
| 1679 | } | |
| bf6ac9fa | 1680 | return (0); |
| 984263bc MD |
1681 | } |
| 1682 | ||
| 1683 | /* XXX; copyin sopt data into mbuf chain for (__FreeBSD__ < 3) routines. */ | |
| 1684 | int | |
| 1685 | soopt_mcopyin(struct sockopt *sopt, struct mbuf *m) | |
| 1686 | { | |
| de0003fe AE |
1687 | soopt_to_mbuf(sopt, m); |
| 1688 | return 0; | |
| 1689 | } | |
| 1690 | ||
| 1691 | void | |
| 1692 | soopt_to_mbuf(struct sockopt *sopt, struct mbuf *m) | |
| 1693 | { | |
| c3e742f9 NT |
1694 | size_t valsize; |
| 1695 | void *val; | |
| 984263bc | 1696 | |
| 792239df | 1697 | KKASSERT(!sopt->sopt_val || kva_p(sopt->sopt_val)); |
| de0003fe | 1698 | KKASSERT(kva_p(m)); |
| 984263bc | 1699 | if (sopt->sopt_val == NULL) |
| 792239df | 1700 | return; |
| c3e742f9 NT |
1701 | val = sopt->sopt_val; |
| 1702 | valsize = sopt->sopt_valsize; | |
| 1703 | while (m != NULL && valsize >= m->m_len) { | |
| de0003fe | 1704 | bcopy(val, mtod(m, char *), m->m_len); |
| c3e742f9 NT |
1705 | valsize -= m->m_len; |
| 1706 | val = (caddr_t)val + m->m_len; | |
| 984263bc MD |
1707 | m = m->m_next; |
| 1708 | } | |
| 1709 | if (m != NULL) /* should be allocated enoughly at ip6_sooptmcopyin() */ | |
| 1710 | panic("ip6_sooptmcopyin"); | |
| 984263bc MD |
1711 | } |
| 1712 | ||
| de0003fe AE |
1713 | /* XXX; copyout mbuf chain data into soopt for (__FreeBSD__ < 3) routines. */ |
| 1714 | int | |
| 1715 | soopt_mcopyout(struct sockopt *sopt, struct mbuf *m) | |
| e71a125f | 1716 | { |
| de0003fe | 1717 | return soopt_from_mbuf(sopt, m); |
| e71a125f AE |
1718 | } |
| 1719 | ||
| 984263bc | 1720 | int |
| de0003fe | 1721 | soopt_from_mbuf(struct sockopt *sopt, struct mbuf *m) |
| 984263bc MD |
1722 | { |
| 1723 | struct mbuf *m0 = m; | |
| 1724 | size_t valsize = 0; | |
| c3e742f9 NT |
1725 | size_t maxsize; |
| 1726 | void *val; | |
| 984263bc | 1727 | |
| 792239df | 1728 | KKASSERT(!sopt->sopt_val || kva_p(sopt->sopt_val)); |
| de0003fe | 1729 | KKASSERT(kva_p(m)); |
| 984263bc MD |
1730 | if (sopt->sopt_val == NULL) |
| 1731 | return 0; | |
| c3e742f9 NT |
1732 | val = sopt->sopt_val; |
| 1733 | maxsize = sopt->sopt_valsize; | |
| 1734 | while (m != NULL && maxsize >= m->m_len) { | |
| de0003fe | 1735 | bcopy(mtod(m, char *), val, m->m_len); |
| c3e742f9 NT |
1736 | maxsize -= m->m_len; |
| 1737 | val = (caddr_t)val + m->m_len; | |
| 984263bc MD |
1738 | valsize += m->m_len; |
| 1739 | m = m->m_next; | |
| 1740 | } | |
| 1741 | if (m != NULL) { | |
| 1742 | /* enough soopt buffer should be given from user-land */ | |
| 1743 | m_freem(m0); | |
| bf6ac9fa | 1744 | return (EINVAL); |
| 984263bc MD |
1745 | } |
| 1746 | sopt->sopt_valsize = valsize; | |
| 1747 | return 0; | |
| 1748 | } | |
| 1749 | ||
| 1750 | void | |
| c972a82f | 1751 | sohasoutofband(struct socket *so) |
| 984263bc MD |
1752 | { |
| 1753 | if (so->so_sigio != NULL) | |
| 1754 | pgsigio(so->so_sigio, SIGURG, 0); | |
| 5b22f1a7 | 1755 | KNOTE(&so->so_rcv.ssb_kq.ki_note, NOTE_OOB); |
| 984263bc MD |
1756 | } |
| 1757 | ||
| 1758 | int | |
| 984263bc MD |
1759 | sokqfilter(struct file *fp, struct knote *kn) |
| 1760 | { | |
| 1761 | struct socket *so = (struct socket *)kn->kn_fp->f_data; | |
| 6d49aa6f | 1762 | struct signalsockbuf *ssb; |
| 984263bc MD |
1763 | |
| 1764 | switch (kn->kn_filter) { | |
| 1765 | case EVFILT_READ: | |
| 1766 | if (so->so_options & SO_ACCEPTCONN) | |
| 1767 | kn->kn_fop = &solisten_filtops; | |
| 1768 | else | |
| 1769 | kn->kn_fop = &soread_filtops; | |
| 6d49aa6f | 1770 | ssb = &so->so_rcv; |
| 984263bc MD |
1771 | break; |
| 1772 | case EVFILT_WRITE: | |
| 1773 | kn->kn_fop = &sowrite_filtops; | |
| 6d49aa6f | 1774 | ssb = &so->so_snd; |
| 984263bc | 1775 | break; |
| 73c344d3 SG |
1776 | case EVFILT_EXCEPT: |
| 1777 | kn->kn_fop = &soexcept_filtops; | |
| 1778 | ssb = &so->so_rcv; | |
| 1779 | break; | |
| 984263bc | 1780 | default: |
| b287d649 | 1781 | return (EOPNOTSUPP); |
| 984263bc MD |
1782 | } |
| 1783 | ||
| 5b22f1a7 | 1784 | knote_insert(&ssb->ssb_kq.ki_note, kn); |
| 14343ad3 | 1785 | atomic_set_int(&ssb->ssb_flags, SSB_KNOTE); |
| 984263bc MD |
1786 | return (0); |
| 1787 | } | |
| 1788 | ||
| 1789 | static void | |
| 1790 | filt_sordetach(struct knote *kn) | |
| 1791 | { | |
| 1792 | struct socket *so = (struct socket *)kn->kn_fp->f_data; | |
| 984263bc | 1793 | |
| 5b22f1a7 SG |
1794 | knote_remove(&so->so_rcv.ssb_kq.ki_note, kn); |
| 1795 | if (SLIST_EMPTY(&so->so_rcv.ssb_kq.ki_note)) | |
| 14343ad3 | 1796 | atomic_clear_int(&so->so_rcv.ssb_flags, SSB_KNOTE); |
| 984263bc MD |
1797 | } |
| 1798 | ||
| 1799 | /*ARGSUSED*/ | |
| 1800 | static int | |
| 1801 | filt_soread(struct knote *kn, long hint) | |
| 1802 | { | |
| 1803 | struct socket *so = (struct socket *)kn->kn_fp->f_data; | |
| 1804 | ||
| 73c344d3 SG |
1805 | if (kn->kn_sfflags & NOTE_OOB) { |
| 1806 | if ((so->so_oobmark || (so->so_state & SS_RCVATMARK))) { | |
| 1807 | kn->kn_fflags |= NOTE_OOB; | |
| 1808 | return (1); | |
| 1809 | } | |
| 1810 | return (0); | |
| 70a4a30f | 1811 | } |
| 6d49aa6f | 1812 | kn->kn_data = so->so_rcv.ssb_cc; |
| 8c4ed426 MD |
1813 | |
| 1814 | /* | |
| 1815 | * Only set EOF if all data has been exhausted. | |
| 1816 | */ | |
| 1817 | if ((so->so_state & SS_CANTRCVMORE) && kn->kn_data == 0) { | |
| 984263bc MD |
1818 | kn->kn_flags |= EV_EOF; |
| 1819 | kn->kn_fflags = so->so_error; | |
| 1820 | return (1); | |
| 1821 | } | |
| 1822 | if (so->so_error) /* temporary udp error */ | |
| 1823 | return (1); | |
| 1824 | if (kn->kn_sfflags & NOTE_LOWAT) | |
| 1825 | return (kn->kn_data >= kn->kn_sdata); | |
| e5857bf7 | 1826 | return ((kn->kn_data >= so->so_rcv.ssb_lowat) || |
| 6cef7136 | 1827 | !TAILQ_EMPTY(&so->so_comp)); |
| 984263bc MD |
1828 | } |
| 1829 | ||
| 1830 | static void | |
| 1831 | filt_sowdetach(struct knote *kn) | |
| 1832 | { | |
| 1833 | struct socket *so = (struct socket *)kn->kn_fp->f_data; | |
| 984263bc | 1834 | |
| 5b22f1a7 SG |
1835 | knote_remove(&so->so_snd.ssb_kq.ki_note, kn); |
| 1836 | if (SLIST_EMPTY(&so->so_snd.ssb_kq.ki_note)) | |
| 14343ad3 | 1837 | atomic_clear_int(&so->so_snd.ssb_flags, SSB_KNOTE); |
| 984263bc MD |
1838 | } |
| 1839 | ||
| 1840 | /*ARGSUSED*/ | |
| 1841 | static int | |
| 1842 | filt_sowrite(struct knote *kn, long hint) | |
| 1843 | { | |
| 1844 | struct socket *so = (struct socket *)kn->kn_fp->f_data; | |
| 1845 | ||
| 6d49aa6f | 1846 | kn->kn_data = ssb_space(&so->so_snd); |
| 984263bc MD |
1847 | if (so->so_state & SS_CANTSENDMORE) { |
| 1848 | kn->kn_flags |= EV_EOF; | |
| 1849 | kn->kn_fflags = so->so_error; | |
| 1850 | return (1); | |
| 1851 | } | |
| 1852 | if (so->so_error) /* temporary udp error */ | |
| 1853 | return (1); | |
| 1854 | if (((so->so_state & SS_ISCONNECTED) == 0) && | |
| 1855 | (so->so_proto->pr_flags & PR_CONNREQUIRED)) | |
| 1856 | return (0); | |
| 1857 | if (kn->kn_sfflags & NOTE_LOWAT) | |
| 1858 | return (kn->kn_data >= kn->kn_sdata); | |
| 6d49aa6f | 1859 | return (kn->kn_data >= so->so_snd.ssb_lowat); |
| 984263bc MD |
1860 | } |
| 1861 | ||
| 1862 | /*ARGSUSED*/ | |
| 1863 | static int | |
| 1864 | filt_solisten(struct knote *kn, long hint) | |
| 1865 | { | |
| 1866 | struct socket *so = (struct socket *)kn->kn_fp->f_data; | |
| 1867 | ||
| 1868 | kn->kn_data = so->so_qlen; | |
| 1869 | return (! TAILQ_EMPTY(&so->so_comp)); | |
| 1870 | } |