]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kpi_socketfilter.c
xnu-3789.31.2.tar.gz
[apple/xnu.git] / bsd / kern / kpi_socketfilter.c
CommitLineData
91447636 1/*
39037602 2 * Copyright (c) 2003-2016 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
39236c6e 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
39236c6e 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
39236c6e 17 *
2d21ac55
A
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
39236c6e 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
91447636
A
27 */
28
29#include <sys/kpi_socketfilter.h>
30
31#include <sys/socket.h>
32#include <sys/param.h>
33#include <sys/errno.h>
34#include <sys/malloc.h>
35#include <sys/protosw.h>
316670eb 36#include <sys/domain.h>
6d2010ae 37#include <sys/proc.h>
91447636 38#include <kern/locks.h>
6d2010ae
A
39#include <kern/thread.h>
40#include <kern/debug.h>
91447636 41#include <net/kext_net.h>
316670eb
A
42#include <net/if.h>
43#include <netinet/in_var.h>
44#include <netinet/ip.h>
45#include <netinet/ip_var.h>
46#include <netinet/tcp.h>
47#include <netinet/tcp_var.h>
48#include <netinet/udp.h>
49#include <netinet/udp_var.h>
91447636 50
c910b4d9 51#include <libkern/libkern.h>
6d2010ae 52#include <libkern/OSAtomic.h>
c910b4d9 53
2d21ac55
A
54#include <string.h>
55
6d2010ae
A
56#define SFEF_ATTACHED 0x1 /* SFE is on socket list */
57#define SFEF_NODETACH 0x2 /* Detach should not be called */
58#define SFEF_NOSOCKET 0x4 /* Socket is gone */
59
60struct socket_filter_entry {
61 struct socket_filter_entry *sfe_next_onsocket;
62 struct socket_filter_entry *sfe_next_onfilter;
63 struct socket_filter_entry *sfe_next_oncleanup;
39236c6e 64
6d2010ae 65 struct socket_filter *sfe_filter;
39236c6e
A
66 struct socket *sfe_socket;
67 void *sfe_cookie;
68
69 uint32_t sfe_flags;
70 int32_t sfe_refcount;
6d2010ae
A
71};
72
73struct socket_filter {
39236c6e 74 TAILQ_ENTRY(socket_filter) sf_protosw_next;
6d2010ae
A
75 TAILQ_ENTRY(socket_filter) sf_global_next;
76 struct socket_filter_entry *sf_entry_head;
39236c6e
A
77
78 struct protosw *sf_proto;
79 struct sflt_filter sf_filter;
80 u_int32_t sf_refcount;
6d2010ae
A
81};
82
83TAILQ_HEAD(socket_filter_list, socket_filter);
84
91447636 85static struct socket_filter_list sock_filter_head;
39236c6e
A
86static lck_rw_t *sock_filter_lock = NULL;
87static lck_mtx_t *sock_filter_cleanup_lock = NULL;
6d2010ae 88static struct socket_filter_entry *sock_filter_cleanup_entries = NULL;
39236c6e 89static thread_t sock_filter_cleanup_thread = NULL;
91447636 90
6d2010ae
A
91static void sflt_cleanup_thread(void *, wait_result_t);
92static void sflt_detach_locked(struct socket_filter_entry *entry);
93
94#pragma mark -- Internal State Management --
3a60a9f5 95
743345f9
A
96__private_extern__ int
97sflt_permission_check(struct inpcb *inp)
98{
99
100 /*
101 * All these permissions only apply to the co-processor interface,
102 * so ignore IPv4.
103 */
104 if (!(inp->inp_vflag & INP_IPV6)) {
105 return (0);
106 }
107 /* Sockets that have this entitlement bypass socket filters. */
108 if (INP_INTCOPROC_ALLOWED(inp)) {
109 return (1);
110 }
111 if ((inp->inp_flags & INP_BOUND_IF) &&
112 IFNET_IS_INTCOPROC(inp->inp_boundifp)) {
113 return (1);
114 }
115 return (0);
116}
117
91447636
A
118__private_extern__ void
119sflt_init(void)
120{
39236c6e
A
121 lck_grp_attr_t *grp_attrib = NULL;
122 lck_attr_t *lck_attrib = NULL;
123 lck_grp_t *lck_group = NULL;
124
91447636 125 TAILQ_INIT(&sock_filter_head);
39236c6e 126
6d2010ae 127 /* Allocate a rw lock */
91447636 128 grp_attrib = lck_grp_attr_alloc_init();
91447636
A
129 lck_group = lck_grp_alloc_init("socket filter lock", grp_attrib);
130 lck_grp_attr_free(grp_attrib);
131 lck_attrib = lck_attr_alloc_init();
6d2010ae
A
132 sock_filter_lock = lck_rw_alloc_init(lck_group, lck_attrib);
133 sock_filter_cleanup_lock = lck_mtx_alloc_init(lck_group, lck_attrib);
91447636
A
134 lck_grp_free(lck_group);
135 lck_attr_free(lck_attrib);
136}
137
6d2010ae 138static void
39236c6e 139sflt_retain_locked(struct socket_filter *filter)
91447636 140{
6d2010ae
A
141 filter->sf_refcount++;
142}
143
144static void
39236c6e 145sflt_release_locked(struct socket_filter *filter)
6d2010ae
A
146{
147 filter->sf_refcount--;
39236c6e
A
148 if (filter->sf_refcount == 0) {
149 /* Call the unregistered function */
6d2010ae
A
150 if (filter->sf_filter.sf_unregistered) {
151 lck_rw_unlock_exclusive(sock_filter_lock);
39236c6e
A
152 filter->sf_filter.sf_unregistered(
153 filter->sf_filter.sf_handle);
6d2010ae
A
154 lck_rw_lock_exclusive(sock_filter_lock);
155 }
39236c6e
A
156
157 /* Free the entry */
6d2010ae
A
158 FREE(filter, M_IFADDR);
159 }
160}
161
162static void
39236c6e 163sflt_entry_retain(struct socket_filter_entry *entry)
6d2010ae 164{
39236c6e 165 if (OSIncrementAtomic(&entry->sfe_refcount) <= 0) {
6d2010ae 166 panic("sflt_entry_retain - sfe_refcount <= 0\n");
39236c6e
A
167 /* NOTREACHED */
168 }
6d2010ae
A
169}
170
171static void
39236c6e 172sflt_entry_release(struct socket_filter_entry *entry)
6d2010ae
A
173{
174 SInt32 old = OSDecrementAtomic(&entry->sfe_refcount);
175 if (old == 1) {
39236c6e
A
176 /* That was the last reference */
177
178 /* Take the cleanup lock */
6d2010ae 179 lck_mtx_lock(sock_filter_cleanup_lock);
39236c6e
A
180
181 /* Put this item on the cleanup list */
6d2010ae
A
182 entry->sfe_next_oncleanup = sock_filter_cleanup_entries;
183 sock_filter_cleanup_entries = entry;
39236c6e
A
184
185 /* If the item is the first item in the list */
6d2010ae
A
186 if (entry->sfe_next_oncleanup == NULL) {
187 if (sock_filter_cleanup_thread == NULL) {
39236c6e
A
188 /* Create a thread */
189 kernel_thread_start(sflt_cleanup_thread,
190 NULL, &sock_filter_cleanup_thread);
6d2010ae 191 } else {
39236c6e 192 /* Wakeup the thread */
6d2010ae
A
193 wakeup(&sock_filter_cleanup_entries);
194 }
195 }
39236c6e
A
196
197 /* Drop the cleanup lock */
6d2010ae 198 lck_mtx_unlock(sock_filter_cleanup_lock);
39236c6e
A
199 } else if (old <= 0) {
200 panic("sflt_entry_release - sfe_refcount (%d) <= 0\n",
201 (int)old);
202 /* NOTREACHED */
6d2010ae
A
203 }
204}
205
39037602 206__attribute__((noreturn))
6d2010ae 207static void
39236c6e 208sflt_cleanup_thread(void *blah, wait_result_t blah2)
6d2010ae 209{
39236c6e 210#pragma unused(blah, blah2)
6d2010ae
A
211 while (1) {
212 lck_mtx_lock(sock_filter_cleanup_lock);
213 while (sock_filter_cleanup_entries == NULL) {
39236c6e
A
214 /* Sleep until we've got something better to do */
215 msleep(&sock_filter_cleanup_entries,
216 sock_filter_cleanup_lock, PWAIT,
217 "sflt_cleanup", NULL);
6d2010ae 218 }
39236c6e
A
219
220 /* Pull the current list of dead items */
221 struct socket_filter_entry *dead = sock_filter_cleanup_entries;
6d2010ae 222 sock_filter_cleanup_entries = NULL;
39236c6e
A
223
224 /* Drop the lock */
6d2010ae 225 lck_mtx_unlock(sock_filter_cleanup_lock);
39236c6e
A
226
227 /* Take the socket filter lock */
6d2010ae 228 lck_rw_lock_exclusive(sock_filter_lock);
39236c6e
A
229
230 /* Cleanup every dead item */
6d2010ae
A
231 struct socket_filter_entry *entry;
232 for (entry = dead; entry; entry = dead) {
233 struct socket_filter_entry **nextpp;
39236c6e 234
6d2010ae 235 dead = entry->sfe_next_oncleanup;
39236c6e
A
236
237 /* Call detach function if necessary - drop the lock */
6d2010ae 238 if ((entry->sfe_flags & SFEF_NODETACH) == 0 &&
39236c6e 239 entry->sfe_filter->sf_filter.sf_detach) {
6d2010ae
A
240 entry->sfe_flags |= SFEF_NODETACH;
241 lck_rw_unlock_exclusive(sock_filter_lock);
39236c6e
A
242
243 /*
244 * Warning - passing a potentially
245 * dead socket may be bad
246 */
247 entry->sfe_filter->sf_filter. sf_detach(
248 entry->sfe_cookie, entry->sfe_socket);
249
6d2010ae
A
250 lck_rw_lock_exclusive(sock_filter_lock);
251 }
39236c6e
A
252
253 /*
254 * Pull entry off the socket list --
255 * if the socket still exists
256 */
6d2010ae 257 if ((entry->sfe_flags & SFEF_NOSOCKET) == 0) {
39236c6e
A
258 for (nextpp = &entry->sfe_socket->so_filt;
259 *nextpp;
260 nextpp = &(*nextpp)->sfe_next_onsocket) {
6d2010ae 261 if (*nextpp == entry) {
39236c6e
A
262 *nextpp =
263 entry->sfe_next_onsocket;
6d2010ae
A
264 break;
265 }
266 }
267 }
39236c6e
A
268
269 /* Pull entry off the filter list */
270 for (nextpp = &entry->sfe_filter->sf_entry_head;
271 *nextpp; nextpp = &(*nextpp)->sfe_next_onfilter) {
6d2010ae
A
272 if (*nextpp == entry) {
273 *nextpp = entry->sfe_next_onfilter;
274 break;
275 }
276 }
39236c6e
A
277
278 /*
279 * Release the filter -- may drop lock, but that's okay
280 */
6d2010ae
A
281 sflt_release_locked(entry->sfe_filter);
282 entry->sfe_socket = NULL;
283 entry->sfe_filter = NULL;
284 FREE(entry, M_IFADDR);
285 }
39236c6e
A
286
287 /* Drop the socket filter lock */
6d2010ae
A
288 lck_rw_unlock_exclusive(sock_filter_lock);
289 }
39236c6e 290 /* NOTREACHED */
6d2010ae
A
291}
292
293static int
39236c6e
A
294sflt_attach_locked(struct socket *so, struct socket_filter *filter,
295 int socklocked)
6d2010ae
A
296{
297 int error = 0;
298 struct socket_filter_entry *entry = NULL;
39236c6e 299
743345f9
A
300 if (sflt_permission_check(sotoinpcb(so)))
301 return (0);
302
6d2010ae 303 if (filter == NULL)
39236c6e 304 return (ENOENT);
316670eb 305
39236c6e 306 for (entry = so->so_filt; entry; entry = entry->sfe_next_onfilter) {
316670eb
A
307 if (entry->sfe_filter->sf_filter.sf_handle ==
308 filter->sf_filter.sf_handle)
39236c6e
A
309 return (EEXIST);
310 }
316670eb 311 /* allocate the socket filter entry */
39236c6e 312 MALLOC(entry, struct socket_filter_entry *, sizeof (*entry), M_IFADDR,
316670eb
A
313 M_WAITOK);
314 if (entry == NULL)
39236c6e
A
315 return (ENOMEM);
316
316670eb
A
317 /* Initialize the socket filter entry */
318 entry->sfe_cookie = NULL;
319 entry->sfe_flags = SFEF_ATTACHED;
39236c6e
A
320 entry->sfe_refcount = 1; /* corresponds to SFEF_ATTACHED flag set */
321
316670eb
A
322 /* Put the entry in the filter list */
323 sflt_retain_locked(filter);
324 entry->sfe_filter = filter;
325 entry->sfe_next_onfilter = filter->sf_entry_head;
326 filter->sf_entry_head = entry;
39236c6e 327
316670eb
A
328 /* Put the entry on the socket filter list */
329 entry->sfe_socket = so;
330 entry->sfe_next_onsocket = so->so_filt;
331 so->so_filt = entry;
332
333 if (entry->sfe_filter->sf_filter.sf_attach) {
39236c6e 334 /* Retain the entry while we call attach */
316670eb 335 sflt_entry_retain(entry);
39236c6e
A
336
337 /*
338 * Release the filter lock --
339 * callers must be aware we will do this
340 */
316670eb 341 lck_rw_unlock_exclusive(sock_filter_lock);
39236c6e
A
342
343 /* Unlock the socket */
316670eb
A
344 if (socklocked)
345 socket_unlock(so, 0);
39236c6e
A
346
347 /* It's finally safe to call the filter function */
348 error = entry->sfe_filter->sf_filter.sf_attach(
349 &entry->sfe_cookie, so);
350
351 /* Lock the socket again */
316670eb
A
352 if (socklocked)
353 socket_lock(so, 0);
39236c6e
A
354
355 /* Lock the filters again */
316670eb 356 lck_rw_lock_exclusive(sock_filter_lock);
39236c6e
A
357
358 /*
359 * If the attach function returns an error,
360 * this filter must be detached
361 */
316670eb 362 if (error) {
39236c6e
A
363 /* don't call sf_detach */
364 entry->sfe_flags |= SFEF_NODETACH;
316670eb 365 sflt_detach_locked(entry);
91447636 366 }
39236c6e
A
367
368 /* Release the retain we held through the attach call */
316670eb 369 sflt_entry_release(entry);
91447636 370 }
39236c6e
A
371
372 return (error);
91447636
A
373}
374
6d2010ae 375errno_t
39236c6e 376sflt_attach_internal(socket_t socket, sflt_handle handle)
91447636 377{
6d2010ae 378 if (socket == NULL || handle == 0)
39236c6e
A
379 return (EINVAL);
380
6d2010ae 381 int result = EINVAL;
39236c6e 382
6d2010ae 383 lck_rw_lock_exclusive(sock_filter_lock);
39236c6e 384
6d2010ae
A
385 struct socket_filter *filter = NULL;
386 TAILQ_FOREACH(filter, &sock_filter_head, sf_global_next) {
387 if (filter->sf_filter.sf_handle == handle) break;
388 }
39236c6e 389
6d2010ae
A
390 if (filter) {
391 result = sflt_attach_locked(socket, filter, 1);
91447636 392 }
39236c6e 393
6d2010ae 394 lck_rw_unlock_exclusive(sock_filter_lock);
39236c6e
A
395
396 return (result);
91447636
A
397}
398
6d2010ae 399static void
39236c6e 400sflt_detach_locked(struct socket_filter_entry *entry)
6d2010ae
A
401{
402 if ((entry->sfe_flags & SFEF_ATTACHED) != 0) {
403 entry->sfe_flags &= ~SFEF_ATTACHED;
404 sflt_entry_release(entry);
405 }
406}
407
408#pragma mark -- Socket Layer Hooks --
409
91447636 410__private_extern__ void
39236c6e 411sflt_initsock(struct socket *so)
91447636 412{
39236c6e
A
413 /*
414 * Point to the real protosw, as so_proto might have been
415 * pointed to a modified version.
416 */
417 struct protosw *proto = so->so_proto->pr_protosw;
418
6d2010ae
A
419 lck_rw_lock_shared(sock_filter_lock);
420 if (TAILQ_FIRST(&proto->pr_filter_head) != NULL) {
39236c6e 421 /* Promote lock to exclusive */
6d2010ae
A
422 if (!lck_rw_lock_shared_to_exclusive(sock_filter_lock))
423 lck_rw_lock_exclusive(sock_filter_lock);
39236c6e
A
424
425 /*
426 * Warning: A filter unregistering will be pulled out of
427 * the list. This could happen while we drop the lock in
428 * sftl_attach_locked or sflt_release_locked. For this
429 * reason we retain a reference on the filter (or next_filter)
430 * while calling this function. This protects us from a panic,
431 * but it could result in a socket being created without all
432 * of the global filters if we're attaching a filter as it
433 * is removed, if that's possible.
434 */
435 struct socket_filter *filter =
436 TAILQ_FIRST(&proto->pr_filter_head);
437
6d2010ae 438 sflt_retain_locked(filter);
39236c6e
A
439
440 while (filter) {
6d2010ae 441 struct socket_filter *filter_next;
39236c6e
A
442 /*
443 * Warning: sflt_attach_private_locked
444 * will drop the lock
445 */
6d2010ae 446 sflt_attach_locked(so, filter, 0);
39236c6e 447
6d2010ae
A
448 filter_next = TAILQ_NEXT(filter, sf_protosw_next);
449 if (filter_next)
450 sflt_retain_locked(filter_next);
39236c6e
A
451
452 /*
453 * Warning: filt_release_locked may remove
454 * the filter from the queue
455 */
6d2010ae
A
456 sflt_release_locked(filter);
457 filter = filter_next;
458 }
459 }
460 lck_rw_done(sock_filter_lock);
91447636
A
461}
462
6d2010ae
A
463/*
464 * sflt_termsock
465 *
466 * Detaches all filters from the socket.
467 */
91447636 468__private_extern__ void
39236c6e 469sflt_termsock(struct socket *so)
91447636 470{
6d2010ae 471 lck_rw_lock_exclusive(sock_filter_lock);
39236c6e 472
6d2010ae 473 struct socket_filter_entry *entry;
39236c6e 474
6d2010ae 475 while ((entry = so->so_filt) != NULL) {
39236c6e 476 /* Pull filter off the socket */
6d2010ae
A
477 so->so_filt = entry->sfe_next_onsocket;
478 entry->sfe_flags |= SFEF_NOSOCKET;
39236c6e
A
479
480 /* Call detach */
6d2010ae 481 sflt_detach_locked(entry);
39236c6e
A
482
483 /*
484 * On sflt_termsock, we can't return until the detach function
485 * has been called. Call the detach function - this is gross
486 * because the socket filter entry could be freed when we drop
487 * the lock, so we make copies on the stack and retain
488 * everything we need before dropping the lock.
489 */
6d2010ae 490 if ((entry->sfe_flags & SFEF_NODETACH) == 0 &&
39236c6e
A
491 entry->sfe_filter->sf_filter.sf_detach) {
492 void *sfe_cookie = entry->sfe_cookie;
493 struct socket_filter *sfe_filter = entry->sfe_filter;
494
495 /* Retain the socket filter */
6d2010ae 496 sflt_retain_locked(sfe_filter);
39236c6e
A
497
498 /* Mark that we've called the detach function */
6d2010ae 499 entry->sfe_flags |= SFEF_NODETACH;
39236c6e
A
500
501 /* Drop the lock before calling the detach function */
6d2010ae
A
502 lck_rw_unlock_exclusive(sock_filter_lock);
503 sfe_filter->sf_filter.sf_detach(sfe_cookie, so);
504 lck_rw_lock_exclusive(sock_filter_lock);
39236c6e
A
505
506 /* Release the filter */
6d2010ae 507 sflt_release_locked(sfe_filter);
91447636
A
508 }
509 }
39236c6e 510
6d2010ae 511 lck_rw_unlock_exclusive(sock_filter_lock);
91447636
A
512}
513
316670eb
A
514
515static void
39236c6e
A
516sflt_notify_internal(struct socket *so, sflt_event_t event, void *param,
517 sflt_handle handle)
91447636 518{
39236c6e
A
519 if (so->so_filt == NULL)
520 return;
521
522 struct socket_filter_entry *entry;
523 int unlocked = 0;
524
6d2010ae
A
525 lck_rw_lock_shared(sock_filter_lock);
526 for (entry = so->so_filt; entry; entry = entry->sfe_next_onsocket) {
39236c6e
A
527 if ((entry->sfe_flags & SFEF_ATTACHED) &&
528 entry->sfe_filter->sf_filter.sf_notify &&
529 ((handle && entry->sfe_filter->sf_filter.sf_handle !=
530 handle) || !handle)) {
531 /*
532 * Retain the filter entry and release
533 * the socket filter lock
534 */
6d2010ae
A
535 sflt_entry_retain(entry);
536 lck_rw_unlock_shared(sock_filter_lock);
39236c6e
A
537
538 /* If the socket isn't already unlocked, unlock it */
6d2010ae
A
539 if (unlocked == 0) {
540 unlocked = 1;
91447636
A
541 socket_unlock(so, 0);
542 }
39236c6e
A
543
544 /* Finally call the filter */
545 entry->sfe_filter->sf_filter.sf_notify(
546 entry->sfe_cookie, so, event, param);
547
548 /*
549 * Take the socket filter lock again
550 * and release the entry
551 */
6d2010ae
A
552 lck_rw_lock_shared(sock_filter_lock);
553 sflt_entry_release(entry);
91447636
A
554 }
555 }
6d2010ae 556 lck_rw_unlock_shared(sock_filter_lock);
39236c6e 557
6d2010ae 558 if (unlocked != 0) {
91447636 559 socket_lock(so, 0);
91447636
A
560 }
561}
562
316670eb 563__private_extern__ void
39236c6e 564sflt_notify(struct socket *so, sflt_event_t event, void *param)
316670eb
A
565{
566 sflt_notify_internal(so, event, param, 0);
567}
568
569static void
39236c6e
A
570sflt_notify_after_register(struct socket *so, sflt_event_t event,
571 sflt_handle handle)
316670eb
A
572{
573 sflt_notify_internal(so, event, NULL, handle);
574}
575
91447636 576__private_extern__ int
39236c6e 577sflt_ioctl(struct socket *so, u_long cmd, caddr_t data)
91447636 578{
743345f9 579 if (so->so_filt == NULL || sflt_permission_check(sotoinpcb(so)))
39236c6e
A
580 return (0);
581
582 struct socket_filter_entry *entry;
583 int unlocked = 0;
584 int error = 0;
585
6d2010ae
A
586 lck_rw_lock_shared(sock_filter_lock);
587 for (entry = so->so_filt; entry && error == 0;
39236c6e
A
588 entry = entry->sfe_next_onsocket) {
589 if ((entry->sfe_flags & SFEF_ATTACHED) &&
590 entry->sfe_filter->sf_filter.sf_ioctl) {
591 /*
592 * Retain the filter entry and release
593 * the socket filter lock
594 */
6d2010ae
A
595 sflt_entry_retain(entry);
596 lck_rw_unlock_shared(sock_filter_lock);
39236c6e
A
597
598 /* If the socket isn't already unlocked, unlock it */
6d2010ae 599 if (unlocked == 0) {
91447636 600 socket_unlock(so, 0);
6d2010ae 601 unlocked = 1;
91447636 602 }
39236c6e
A
603
604 /* Call the filter */
605 error = entry->sfe_filter->sf_filter.sf_ioctl(
606 entry->sfe_cookie, so, cmd, data);
607
608 /*
609 * Take the socket filter lock again
610 * and release the entry
611 */
6d2010ae
A
612 lck_rw_lock_shared(sock_filter_lock);
613 sflt_entry_release(entry);
91447636
A
614 }
615 }
6d2010ae
A
616 lck_rw_unlock_shared(sock_filter_lock);
617
618 if (unlocked) {
91447636 619 socket_lock(so, 0);
91447636 620 }
39236c6e
A
621
622 return (error);
91447636
A
623}
624
91447636 625__private_extern__ int
39236c6e 626sflt_bind(struct socket *so, const struct sockaddr *nam)
91447636 627{
743345f9 628 if (so->so_filt == NULL || sflt_permission_check(sotoinpcb(so)))
39236c6e
A
629 return (0);
630
631 struct socket_filter_entry *entry;
632 int unlocked = 0;
633 int error = 0;
634
6d2010ae
A
635 lck_rw_lock_shared(sock_filter_lock);
636 for (entry = so->so_filt; entry && error == 0;
39236c6e
A
637 entry = entry->sfe_next_onsocket) {
638 if ((entry->sfe_flags & SFEF_ATTACHED) &&
639 entry->sfe_filter->sf_filter.sf_bind) {
640 /*
641 * Retain the filter entry and
642 * release the socket filter lock
643 */
6d2010ae
A
644 sflt_entry_retain(entry);
645 lck_rw_unlock_shared(sock_filter_lock);
39236c6e
A
646
647 /* If the socket isn't already unlocked, unlock it */
6d2010ae
A
648 if (unlocked == 0) {
649 socket_unlock(so, 0);
650 unlocked = 1;
651 }
39236c6e
A
652
653 /* Call the filter */
654 error = entry->sfe_filter->sf_filter.sf_bind(
655 entry->sfe_cookie, so, nam);
656
657 /*
658 * Take the socket filter lock again and
659 * release the entry
660 */
6d2010ae
A
661 lck_rw_lock_shared(sock_filter_lock);
662 sflt_entry_release(entry);
91447636
A
663 }
664 }
6d2010ae
A
665 lck_rw_unlock_shared(sock_filter_lock);
666
667 if (unlocked) {
668 socket_lock(so, 0);
669 }
39236c6e
A
670
671 return (error);
6d2010ae
A
672}
673
674__private_extern__ int
39236c6e 675sflt_listen(struct socket *so)
6d2010ae 676{
743345f9 677 if (so->so_filt == NULL || sflt_permission_check(sotoinpcb(so)))
39236c6e
A
678 return (0);
679
680 struct socket_filter_entry *entry;
681 int unlocked = 0;
682 int error = 0;
683
6d2010ae
A
684 lck_rw_lock_shared(sock_filter_lock);
685 for (entry = so->so_filt; entry && error == 0;
39236c6e
A
686 entry = entry->sfe_next_onsocket) {
687 if ((entry->sfe_flags & SFEF_ATTACHED) &&
688 entry->sfe_filter->sf_filter.sf_listen) {
689 /*
690 * Retain the filter entry and release
691 * the socket filter lock
692 */
6d2010ae
A
693 sflt_entry_retain(entry);
694 lck_rw_unlock_shared(sock_filter_lock);
39236c6e
A
695
696 /* If the socket isn't already unlocked, unlock it */
6d2010ae
A
697 if (unlocked == 0) {
698 socket_unlock(so, 0);
699 unlocked = 1;
700 }
39236c6e
A
701
702 /* Call the filter */
703 error = entry->sfe_filter->sf_filter.sf_listen(
704 entry->sfe_cookie, so);
705
706 /*
707 * Take the socket filter lock again
708 * and release the entry
709 */
6d2010ae
A
710 lck_rw_lock_shared(sock_filter_lock);
711 sflt_entry_release(entry);
91447636
A
712 }
713 }
6d2010ae
A
714 lck_rw_unlock_shared(sock_filter_lock);
715
716 if (unlocked) {
717 socket_lock(so, 0);
718 }
39236c6e
A
719
720 return (error);
6d2010ae
A
721}
722
723__private_extern__ int
39236c6e
A
724sflt_accept(struct socket *head, struct socket *so,
725 const struct sockaddr *local, const struct sockaddr *remote)
6d2010ae 726{
743345f9 727 if (so->so_filt == NULL || sflt_permission_check(sotoinpcb(so)))
39236c6e
A
728 return (0);
729
730 struct socket_filter_entry *entry;
731 int unlocked = 0;
732 int error = 0;
733
6d2010ae
A
734 lck_rw_lock_shared(sock_filter_lock);
735 for (entry = so->so_filt; entry && error == 0;
39236c6e
A
736 entry = entry->sfe_next_onsocket) {
737 if ((entry->sfe_flags & SFEF_ATTACHED) &&
738 entry->sfe_filter->sf_filter.sf_accept) {
739 /*
740 * Retain the filter entry and
741 * release the socket filter lock
742 */
6d2010ae
A
743 sflt_entry_retain(entry);
744 lck_rw_unlock_shared(sock_filter_lock);
39236c6e
A
745
746 /* If the socket isn't already unlocked, unlock it */
6d2010ae
A
747 if (unlocked == 0) {
748 socket_unlock(so, 0);
749 unlocked = 1;
91447636 750 }
39236c6e
A
751
752 /* Call the filter */
753 error = entry->sfe_filter->sf_filter.sf_accept(
754 entry->sfe_cookie, head, so, local, remote);
755
756 /*
757 * Take the socket filter lock again
758 * and release the entry
759 */
6d2010ae
A
760 lck_rw_lock_shared(sock_filter_lock);
761 sflt_entry_release(entry);
91447636
A
762 }
763 }
6d2010ae
A
764 lck_rw_unlock_shared(sock_filter_lock);
765
766 if (unlocked) {
767 socket_lock(so, 0);
91447636 768 }
39236c6e
A
769
770 return (error);
6d2010ae
A
771}
772
773__private_extern__ int
39236c6e 774sflt_getsockname(struct socket *so, struct sockaddr **local)
6d2010ae 775{
743345f9 776 if (so->so_filt == NULL || sflt_permission_check(sotoinpcb(so)))
39236c6e
A
777 return (0);
778
779 struct socket_filter_entry *entry;
780 int unlocked = 0;
781 int error = 0;
782
6d2010ae
A
783 lck_rw_lock_shared(sock_filter_lock);
784 for (entry = so->so_filt; entry && error == 0;
39236c6e
A
785 entry = entry->sfe_next_onsocket) {
786 if ((entry->sfe_flags & SFEF_ATTACHED) &&
787 entry->sfe_filter->sf_filter.sf_getsockname) {
788 /*
789 * Retain the filter entry and
790 * release the socket filter lock
791 */
6d2010ae
A
792 sflt_entry_retain(entry);
793 lck_rw_unlock_shared(sock_filter_lock);
39236c6e
A
794
795 /* If the socket isn't already unlocked, unlock it */
6d2010ae
A
796 if (unlocked == 0) {
797 socket_unlock(so, 0);
798 unlocked = 1;
799 }
39236c6e
A
800
801 /* Call the filter */
802 error = entry->sfe_filter->sf_filter.sf_getsockname(
803 entry->sfe_cookie, so, local);
804
805 /*
806 * Take the socket filter lock again
807 * and release the entry
808 */
6d2010ae
A
809 lck_rw_lock_shared(sock_filter_lock);
810 sflt_entry_release(entry);
811 }
812 }
813 lck_rw_unlock_shared(sock_filter_lock);
814
815 if (unlocked) {
816 socket_lock(so, 0);
91447636 817 }
39236c6e
A
818
819 return (error);
91447636
A
820}
821
6d2010ae 822__private_extern__ int
39236c6e 823sflt_getpeername(struct socket *so, struct sockaddr **remote)
6d2010ae 824{
743345f9 825 if (so->so_filt == NULL || sflt_permission_check(sotoinpcb(so)))
39236c6e
A
826 return (0);
827
828 struct socket_filter_entry *entry;
829 int unlocked = 0;
830 int error = 0;
831
6d2010ae
A
832 lck_rw_lock_shared(sock_filter_lock);
833 for (entry = so->so_filt; entry && error == 0;
39236c6e
A
834 entry = entry->sfe_next_onsocket) {
835 if ((entry->sfe_flags & SFEF_ATTACHED) &&
836 entry->sfe_filter->sf_filter.sf_getpeername) {
837 /*
838 * Retain the filter entry and release
839 * the socket filter lock
840 */
6d2010ae
A
841 sflt_entry_retain(entry);
842 lck_rw_unlock_shared(sock_filter_lock);
39236c6e
A
843
844 /* If the socket isn't already unlocked, unlock it */
6d2010ae
A
845 if (unlocked == 0) {
846 socket_unlock(so, 0);
847 unlocked = 1;
848 }
39236c6e
A
849
850 /* Call the filter */
851 error = entry->sfe_filter->sf_filter.sf_getpeername(
852 entry->sfe_cookie, so, remote);
853
854 /*
855 * Take the socket filter lock again
856 * and release the entry
857 */
6d2010ae
A
858 lck_rw_lock_shared(sock_filter_lock);
859 sflt_entry_release(entry);
860 }
861 }
862 lck_rw_unlock_shared(sock_filter_lock);
91447636 863
6d2010ae
A
864 if (unlocked) {
865 socket_lock(so, 0);
866 }
39236c6e
A
867
868 return (error);
6d2010ae 869}
91447636 870
6d2010ae 871__private_extern__ int
39236c6e 872sflt_connectin(struct socket *so, const struct sockaddr *remote)
91447636 873{
743345f9 874 if (so->so_filt == NULL || sflt_permission_check(sotoinpcb(so)))
39236c6e
A
875 return (0);
876
877 struct socket_filter_entry *entry;
878 int unlocked = 0;
879 int error = 0;
880
6d2010ae
A
881 lck_rw_lock_shared(sock_filter_lock);
882 for (entry = so->so_filt; entry && error == 0;
39236c6e
A
883 entry = entry->sfe_next_onsocket) {
884 if ((entry->sfe_flags & SFEF_ATTACHED) &&
885 entry->sfe_filter->sf_filter.sf_connect_in) {
886 /*
887 * Retain the filter entry and release
888 * the socket filter lock
889 */
6d2010ae
A
890 sflt_entry_retain(entry);
891 lck_rw_unlock_shared(sock_filter_lock);
39236c6e
A
892
893 /* If the socket isn't already unlocked, unlock it */
6d2010ae
A
894 if (unlocked == 0) {
895 socket_unlock(so, 0);
896 unlocked = 1;
4a3eedf9 897 }
39236c6e
A
898
899 /* Call the filter */
900 error = entry->sfe_filter->sf_filter.sf_connect_in(
901 entry->sfe_cookie, so, remote);
902
903 /*
904 * Take the socket filter lock again
905 * and release the entry
906 */
6d2010ae
A
907 lck_rw_lock_shared(sock_filter_lock);
908 sflt_entry_release(entry);
3a60a9f5 909 }
6d2010ae
A
910 }
911 lck_rw_unlock_shared(sock_filter_lock);
912
913 if (unlocked) {
914 socket_lock(so, 0);
915 }
39236c6e
A
916
917 return (error);
6d2010ae
A
918}
919
490019cf
A
920static int
921sflt_connectout_common(struct socket *so, const struct sockaddr *nam)
6d2010ae 922{
39236c6e
A
923 struct socket_filter_entry *entry;
924 int unlocked = 0;
925 int error = 0;
926
6d2010ae
A
927 lck_rw_lock_shared(sock_filter_lock);
928 for (entry = so->so_filt; entry && error == 0;
39236c6e
A
929 entry = entry->sfe_next_onsocket) {
930 if ((entry->sfe_flags & SFEF_ATTACHED) &&
931 entry->sfe_filter->sf_filter.sf_connect_out) {
932 /*
933 * Retain the filter entry and release
934 * the socket filter lock
935 */
6d2010ae
A
936 sflt_entry_retain(entry);
937 lck_rw_unlock_shared(sock_filter_lock);
39236c6e
A
938
939 /* If the socket isn't already unlocked, unlock it */
6d2010ae
A
940 if (unlocked == 0) {
941 socket_unlock(so, 0);
942 unlocked = 1;
91447636 943 }
39236c6e
A
944
945 /* Call the filter */
946 error = entry->sfe_filter->sf_filter.sf_connect_out(
947 entry->sfe_cookie, so, nam);
948
949 /*
950 * Take the socket filter lock again
951 * and release the entry
952 */
6d2010ae
A
953 lck_rw_lock_shared(sock_filter_lock);
954 sflt_entry_release(entry);
91447636 955 }
91447636 956 }
6d2010ae
A
957 lck_rw_unlock_shared(sock_filter_lock);
958
959 if (unlocked) {
960 socket_lock(so, 0);
961 }
39236c6e
A
962
963 return (error);
964}
965
966__private_extern__ int
490019cf 967sflt_connectout(struct socket *so, const struct sockaddr *nam)
39236c6e
A
968{
969 char buf[SOCK_MAXADDRLEN];
490019cf
A
970 struct sockaddr *sa;
971 int error;
972
743345f9 973 if (so->so_filt == NULL || sflt_permission_check(sotoinpcb(so)))
490019cf
A
974 return (0);
975
976 /*
977 * Workaround for rdar://23362120
978 * Always pass a buffer that can hold an IPv6 socket address
979 */
980 bzero(buf, sizeof (buf));
981 bcopy(nam, buf, nam->sa_len);
982 sa = (struct sockaddr *)buf;
983
984 error = sflt_connectout_common(so, sa);
985 if (error != 0)
986 return (error);
987
743345f9 988 /*
490019cf
A
989 * If the address was modified, copy it back
990 */
991 if (bcmp(sa, nam, nam->sa_len) != 0) {
992 bcopy(sa, (struct sockaddr *)(uintptr_t)nam, nam->sa_len);
993 }
994
995 return (0);
996}
997
998__private_extern__ int
999sflt_connectxout(struct socket *so, struct sockaddr_list **dst_sl0)
1000{
39236c6e
A
1001 struct sockaddr_list *dst_sl;
1002 struct sockaddr_entry *se, *tse;
1003 int modified = 0;
1004 int error = 0;
1005
743345f9 1006 if (so->so_filt == NULL || sflt_permission_check(sotoinpcb(so)))
39236c6e
A
1007 return (0);
1008
1009 /* make a copy as sflt_connectout() releases socket lock */
1010 dst_sl = sockaddrlist_dup(*dst_sl0, M_WAITOK);
1011 if (dst_sl == NULL)
1012 return (ENOBUFS);
1013
1014 /*
1015 * Hmm; we don't yet have a connectx socket filter callback,
1016 * so the closest thing to do is to probably call sflt_connectout()
1017 * as many times as there are addresses in the list, and bail
1018 * as soon as we get an error.
1019 */
1020 TAILQ_FOREACH_SAFE(se, &dst_sl->sl_head, se_link, tse) {
490019cf
A
1021 char buf[SOCK_MAXADDRLEN];
1022 struct sockaddr *sa;
1023
1024 VERIFY(se->se_addr != NULL);
39236c6e 1025
490019cf
A
1026 /*
1027 * Workaround for rdar://23362120
1028 * Always pass a buffer that can hold an IPv6 socket address
1029 */
39236c6e 1030 bzero(buf, sizeof (buf));
490019cf
A
1031 bcopy(se->se_addr, buf, se->se_addr->sa_len);
1032 sa = (struct sockaddr *)buf;
39236c6e 1033
490019cf 1034 error = sflt_connectout_common(so, sa);
39236c6e
A
1035 if (error != 0)
1036 break;
1037
743345f9 1038 /*
490019cf
A
1039 * If the address was modified, copy it back
1040 */
1041 if (bcmp(se->se_addr, sa, se->se_addr->sa_len) != 0) {
1042 bcopy(sa, se->se_addr, se->se_addr->sa_len);
39236c6e 1043 modified = 1;
490019cf 1044 }
39236c6e
A
1045 }
1046
1047 if (error != 0 || !modified) {
1048 /* leave the original as is */
1049 sockaddrlist_free(dst_sl);
1050 } else {
1051 /*
1052 * At least one address was modified and there were no errors;
1053 * ditch the original and return the modified list.
1054 */
1055 sockaddrlist_free(*dst_sl0);
1056 *dst_sl0 = dst_sl;
1057 }
1058
1059 return (error);
6d2010ae 1060}
91447636 1061
6d2010ae 1062__private_extern__ int
39236c6e 1063sflt_setsockopt(struct socket *so, struct sockopt *sopt)
6d2010ae 1064{
743345f9 1065 if (so->so_filt == NULL || sflt_permission_check(sotoinpcb(so)))
39236c6e
A
1066 return (0);
1067
1068 struct socket_filter_entry *entry;
1069 int unlocked = 0;
1070 int error = 0;
1071
6d2010ae
A
1072 lck_rw_lock_shared(sock_filter_lock);
1073 for (entry = so->so_filt; entry && error == 0;
39236c6e
A
1074 entry = entry->sfe_next_onsocket) {
1075 if ((entry->sfe_flags & SFEF_ATTACHED) &&
1076 entry->sfe_filter->sf_filter.sf_setoption) {
1077 /*
1078 * Retain the filter entry and release
1079 * the socket filter lock
1080 */
6d2010ae
A
1081 sflt_entry_retain(entry);
1082 lck_rw_unlock_shared(sock_filter_lock);
39236c6e
A
1083
1084 /* If the socket isn't already unlocked, unlock it */
6d2010ae
A
1085 if (unlocked == 0) {
1086 socket_unlock(so, 0);
1087 unlocked = 1;
1088 }
39236c6e
A
1089
1090 /* Call the filter */
1091 error = entry->sfe_filter->sf_filter.sf_setoption(
1092 entry->sfe_cookie, so, sopt);
1093
1094 /*
1095 * Take the socket filter lock again
1096 * and release the entry
1097 */
6d2010ae
A
1098 lck_rw_lock_shared(sock_filter_lock);
1099 sflt_entry_release(entry);
c910b4d9 1100 }
6d2010ae
A
1101 }
1102 lck_rw_unlock_shared(sock_filter_lock);
1103
1104 if (unlocked) {
1105 socket_lock(so, 0);
1106 }
39236c6e
A
1107
1108 return (error);
6d2010ae
A
1109}
1110
1111__private_extern__ int
39236c6e 1112sflt_getsockopt(struct socket *so, struct sockopt *sopt)
6d2010ae 1113{
743345f9 1114 if (so->so_filt == NULL || sflt_permission_check(sotoinpcb(so)))
39236c6e
A
1115 return (0);
1116
1117 struct socket_filter_entry *entry;
1118 int unlocked = 0;
1119 int error = 0;
1120
6d2010ae
A
1121 lck_rw_lock_shared(sock_filter_lock);
1122 for (entry = so->so_filt; entry && error == 0;
39236c6e
A
1123 entry = entry->sfe_next_onsocket) {
1124 if ((entry->sfe_flags & SFEF_ATTACHED) &&
1125 entry->sfe_filter->sf_filter.sf_getoption) {
1126 /*
1127 * Retain the filter entry and release
1128 * the socket filter lock
1129 */
6d2010ae
A
1130 sflt_entry_retain(entry);
1131 lck_rw_unlock_shared(sock_filter_lock);
39236c6e
A
1132
1133 /* If the socket isn't already unlocked, unlock it */
6d2010ae
A
1134 if (unlocked == 0) {
1135 socket_unlock(so, 0);
1136 unlocked = 1;
1137 }
39236c6e
A
1138
1139 /* Call the filter */
1140 error = entry->sfe_filter->sf_filter.sf_getoption(
1141 entry->sfe_cookie, so, sopt);
1142
1143 /*
1144 * Take the socket filter lock again
1145 * and release the entry
1146 */
6d2010ae
A
1147 lck_rw_lock_shared(sock_filter_lock);
1148 sflt_entry_release(entry);
91447636
A
1149 }
1150 }
6d2010ae
A
1151 lck_rw_unlock_shared(sock_filter_lock);
1152
1153 if (unlocked) {
1154 socket_lock(so, 0);
1155 }
39236c6e
A
1156
1157 return (error);
6d2010ae
A
1158}
1159
1160__private_extern__ int
39236c6e
A
1161sflt_data_out(struct socket *so, const struct sockaddr *to, mbuf_t *data,
1162 mbuf_t *control, sflt_data_flag_t flags)
6d2010ae 1163{
743345f9 1164 if (so->so_filt == NULL || sflt_permission_check(sotoinpcb(so)))
39236c6e
A
1165 return (0);
1166
1167 struct socket_filter_entry *entry;
1168 int unlocked = 0;
1169 int setsendthread = 0;
1170 int error = 0;
1171
6d2010ae
A
1172 lck_rw_lock_shared(sock_filter_lock);
1173 for (entry = so->so_filt; entry && error == 0;
39236c6e
A
1174 entry = entry->sfe_next_onsocket) {
1175 /* skip if this is a subflow socket */
1176 if (so->so_flags & SOF_MP_SUBFLOW)
1177 continue;
1178 if ((entry->sfe_flags & SFEF_ATTACHED) &&
1179 entry->sfe_filter->sf_filter.sf_data_out) {
1180 /*
1181 * Retain the filter entry and
1182 * release the socket filter lock
1183 */
6d2010ae
A
1184 sflt_entry_retain(entry);
1185 lck_rw_unlock_shared(sock_filter_lock);
39236c6e
A
1186
1187 /* If the socket isn't already unlocked, unlock it */
6d2010ae
A
1188 if (unlocked == 0) {
1189 if (so->so_send_filt_thread == NULL) {
1190 setsendthread = 1;
39236c6e
A
1191 so->so_send_filt_thread =
1192 current_thread();
6d2010ae
A
1193 }
1194 socket_unlock(so, 0);
1195 unlocked = 1;
1196 }
39236c6e
A
1197
1198 /* Call the filter */
1199 error = entry->sfe_filter->sf_filter.sf_data_out(
1200 entry->sfe_cookie, so, to, data, control, flags);
1201
1202 /*
1203 * Take the socket filter lock again
1204 * and release the entry
1205 */
6d2010ae
A
1206 lck_rw_lock_shared(sock_filter_lock);
1207 sflt_entry_release(entry);
1208 }
91447636 1209 }
6d2010ae 1210 lck_rw_unlock_shared(sock_filter_lock);
3a60a9f5 1211
6d2010ae
A
1212 if (unlocked) {
1213 socket_lock(so, 0);
39236c6e
A
1214 if (setsendthread)
1215 so->so_send_filt_thread = NULL;
6d2010ae 1216 }
39236c6e
A
1217
1218 return (error);
6d2010ae 1219}
3a60a9f5 1220
6d2010ae 1221__private_extern__ int
39236c6e
A
1222sflt_data_in(struct socket *so, const struct sockaddr *from, mbuf_t *data,
1223 mbuf_t *control, sflt_data_flag_t flags)
6d2010ae 1224{
743345f9 1225 if (so->so_filt == NULL || sflt_permission_check(sotoinpcb(so)))
39236c6e
A
1226 return (0);
1227
1228 struct socket_filter_entry *entry;
1229 int error = 0;
1230 int unlocked = 0;
1231
6d2010ae 1232 lck_rw_lock_shared(sock_filter_lock);
39236c6e 1233
6d2010ae 1234 for (entry = so->so_filt; entry && (error == 0);
39236c6e
A
1235 entry = entry->sfe_next_onsocket) {
1236 /* skip if this is a subflow socket */
1237 if (so->so_flags & SOF_MP_SUBFLOW)
1238 continue;
6d2010ae 1239 if ((entry->sfe_flags & SFEF_ATTACHED) &&
39236c6e
A
1240 entry->sfe_filter->sf_filter.sf_data_in) {
1241 /*
1242 * Retain the filter entry and
1243 * release the socket filter lock
1244 */
6d2010ae
A
1245 sflt_entry_retain(entry);
1246 lck_rw_unlock_shared(sock_filter_lock);
39236c6e
A
1247
1248 /* If the socket isn't already unlocked, unlock it */
6d2010ae
A
1249 if (unlocked == 0) {
1250 unlocked = 1;
1251 socket_unlock(so, 0);
1252 }
39236c6e
A
1253
1254 /* Call the filter */
6d2010ae 1255 error = entry->sfe_filter->sf_filter.sf_data_in(
39236c6e
A
1256 entry->sfe_cookie, so, from, data, control, flags);
1257
1258 /*
1259 * Take the socket filter lock again
1260 * and release the entry
1261 */
6d2010ae
A
1262 lck_rw_lock_shared(sock_filter_lock);
1263 sflt_entry_release(entry);
1264 }
1265 }
1266 lck_rw_unlock_shared(sock_filter_lock);
39236c6e 1267
6d2010ae
A
1268 if (unlocked) {
1269 socket_lock(so, 0);
1270 }
39236c6e
A
1271
1272 return (error);
91447636
A
1273}
1274
6d2010ae
A
1275#pragma mark -- KPI --
1276
91447636 1277errno_t
39236c6e 1278sflt_attach(socket_t socket, sflt_handle handle)
91447636 1279{
6d2010ae
A
1280 socket_lock(socket, 1);
1281 errno_t result = sflt_attach_internal(socket, handle);
1282 socket_unlock(socket, 1);
39236c6e 1283 return (result);
91447636
A
1284}
1285
1286errno_t
39236c6e 1287sflt_detach(socket_t socket, sflt_handle handle)
91447636 1288{
39236c6e 1289 struct socket_filter_entry *entry;
91447636 1290 errno_t result = 0;
39236c6e 1291
91447636 1292 if (socket == NULL || handle == 0)
39236c6e
A
1293 return (EINVAL);
1294
6d2010ae 1295 lck_rw_lock_exclusive(sock_filter_lock);
39236c6e 1296 for (entry = socket->so_filt; entry; entry = entry->sfe_next_onsocket) {
6d2010ae 1297 if (entry->sfe_filter->sf_filter.sf_handle == handle &&
39236c6e 1298 (entry->sfe_flags & SFEF_ATTACHED) != 0) {
91447636 1299 break;
6d2010ae 1300 }
91447636 1301 }
39236c6e 1302
6d2010ae
A
1303 if (entry != NULL) {
1304 sflt_detach_locked(entry);
91447636 1305 }
6d2010ae 1306 lck_rw_unlock_exclusive(sock_filter_lock);
39236c6e
A
1307
1308 return (result);
91447636
A
1309}
1310
316670eb
A
1311struct solist {
1312 struct solist *next;
1313 struct socket *so;
1314};
1315
91447636 1316errno_t
39236c6e
A
1317sflt_register(const struct sflt_filter *filter, int domain, int type,
1318 int protocol)
91447636
A
1319{
1320 struct socket_filter *sock_filt = NULL;
1321 struct socket_filter *match = NULL;
1322 int error = 0;
3e170ce0 1323 struct protosw *pr;
2d21ac55 1324 unsigned int len;
316670eb
A
1325 struct socket *so;
1326 struct inpcb *inp;
1327 struct solist *solisthead = NULL, *solist = NULL;
2d21ac55 1328
3e170ce0
A
1329 if ((domain != PF_INET) && (domain != PF_INET6))
1330 return (ENOTSUP);
1331
1332 pr = pffindproto(domain, protocol, type);
2d21ac55 1333 if (pr == NULL)
39236c6e 1334 return (ENOENT);
2d21ac55
A
1335
1336 if (filter->sf_attach == NULL || filter->sf_detach == NULL ||
1337 filter->sf_handle == 0 || filter->sf_name == NULL)
39236c6e 1338 return (EINVAL);
91447636
A
1339
1340 /* Allocate the socket filter */
2d21ac55
A
1341 MALLOC(sock_filt, struct socket_filter *, sizeof (*sock_filt),
1342 M_IFADDR, M_WAITOK);
91447636 1343 if (sock_filt == NULL) {
39236c6e 1344 return (ENOBUFS);
91447636 1345 }
2d21ac55
A
1346
1347 bzero(sock_filt, sizeof (*sock_filt));
1348
1349 /* Legacy sflt_filter length; current structure minus extended */
1350 len = sizeof (*filter) - sizeof (struct sflt_filter_ext);
1351 /*
1352 * Include extended fields if filter defines SFLT_EXTENDED.
1353 * We've zeroed out our internal sflt_filter placeholder,
1354 * so any unused portion would have been taken care of.
1355 */
1356 if (filter->sf_flags & SFLT_EXTENDED) {
1357 unsigned int ext_len = filter->sf_len;
1358
1359 if (ext_len > sizeof (struct sflt_filter_ext))
1360 ext_len = sizeof (struct sflt_filter_ext);
1361
1362 len += ext_len;
1363 }
1364 bcopy(filter, &sock_filt->sf_filter, len);
1365
6d2010ae 1366 lck_rw_lock_exclusive(sock_filter_lock);
91447636
A
1367 /* Look for an existing entry */
1368 TAILQ_FOREACH(match, &sock_filter_head, sf_global_next) {
2d21ac55
A
1369 if (match->sf_filter.sf_handle ==
1370 sock_filt->sf_filter.sf_handle) {
91447636
A
1371 break;
1372 }
1373 }
39236c6e 1374
91447636
A
1375 /* Add the entry only if there was no existing entry */
1376 if (match == NULL) {
1377 TAILQ_INSERT_TAIL(&sock_filter_head, sock_filt, sf_global_next);
1378 if ((sock_filt->sf_filter.sf_flags & SFLT_GLOBAL) != 0) {
2d21ac55
A
1379 TAILQ_INSERT_TAIL(&pr->pr_filter_head, sock_filt,
1380 sf_protosw_next);
91447636
A
1381 sock_filt->sf_proto = pr;
1382 }
6d2010ae 1383 sflt_retain_locked(sock_filt);
91447636 1384 }
6d2010ae 1385 lck_rw_unlock_exclusive(sock_filter_lock);
316670eb 1386
91447636
A
1387 if (match != NULL) {
1388 FREE(sock_filt, M_IFADDR);
39236c6e 1389 return (EEXIST);
91447636 1390 }
2d21ac55 1391
316670eb 1392 if (!(filter->sf_flags & SFLT_EXTENDED_REGISTRY))
39236c6e 1393 return (error);
316670eb
A
1394
1395 /*
1396 * Setup the filter on the TCP and UDP sockets already created.
1397 */
39236c6e 1398#define SOLIST_ADD(_so) do { \
316670eb
A
1399 solist->next = solisthead; \
1400 sock_retain((_so)); \
1401 solist->so = (_so); \
1402 solisthead = solist; \
1403} while (0)
1404 if (protocol == IPPROTO_TCP) {
39236c6e
A
1405 lck_rw_lock_shared(tcbinfo.ipi_lock);
1406 LIST_FOREACH(inp, tcbinfo.ipi_listhead, inp_list) {
316670eb 1407 so = inp->inp_socket;
39236c6e
A
1408 if (so == NULL || (so->so_state & SS_DEFUNCT) ||
1409 (!(so->so_flags & SOF_MP_SUBFLOW) &&
1410 (so->so_state & SS_NOFDREF)) ||
1411 !SOCK_CHECK_DOM(so, domain) ||
1412 !SOCK_CHECK_TYPE(so, type))
316670eb 1413 continue;
39236c6e 1414 MALLOC(solist, struct solist *, sizeof (*solist),
316670eb
A
1415 M_IFADDR, M_NOWAIT);
1416 if (!solist)
1417 continue;
1418 SOLIST_ADD(so);
1419 }
39236c6e 1420 lck_rw_done(tcbinfo.ipi_lock);
316670eb 1421 } else if (protocol == IPPROTO_UDP) {
39236c6e
A
1422 lck_rw_lock_shared(udbinfo.ipi_lock);
1423 LIST_FOREACH(inp, udbinfo.ipi_listhead, inp_list) {
316670eb 1424 so = inp->inp_socket;
39236c6e
A
1425 if (so == NULL || (so->so_state & SS_DEFUNCT) ||
1426 (!(so->so_flags & SOF_MP_SUBFLOW) &&
1427 (so->so_state & SS_NOFDREF)) ||
1428 !SOCK_CHECK_DOM(so, domain) ||
1429 !SOCK_CHECK_TYPE(so, type))
316670eb 1430 continue;
39236c6e 1431 MALLOC(solist, struct solist *, sizeof (*solist),
316670eb
A
1432 M_IFADDR, M_NOWAIT);
1433 if (!solist)
1434 continue;
1435 SOLIST_ADD(so);
1436 }
39236c6e 1437 lck_rw_done(udbinfo.ipi_lock);
316670eb
A
1438 }
1439 /* XXX it's possible to walk the raw socket list as well */
1440#undef SOLIST_ADD
1441
1442 while (solisthead) {
1443 sflt_handle handle = filter->sf_handle;
1444
1445 so = solisthead->so;
fe8ab488 1446 socket_lock(so, 0);
316670eb 1447 sflt_initsock(so);
316670eb
A
1448 if (so->so_state & SS_ISCONNECTING)
1449 sflt_notify_after_register(so, sock_evt_connecting,
1450 handle);
1451 else if (so->so_state & SS_ISCONNECTED)
1452 sflt_notify_after_register(so, sock_evt_connected,
1453 handle);
1454 else if ((so->so_state &
1455 (SS_ISDISCONNECTING|SS_CANTRCVMORE|SS_CANTSENDMORE)) ==
1456 (SS_ISDISCONNECTING|SS_CANTRCVMORE|SS_CANTSENDMORE))
1457 sflt_notify_after_register(so, sock_evt_disconnecting,
1458 handle);
1459 else if ((so->so_state &
1460 (SS_CANTRCVMORE|SS_CANTSENDMORE|SS_ISDISCONNECTED)) ==
1461 (SS_CANTRCVMORE|SS_CANTSENDMORE|SS_ISDISCONNECTED))
1462 sflt_notify_after_register(so, sock_evt_disconnected,
1463 handle);
1464 else if (so->so_state & SS_CANTSENDMORE)
1465 sflt_notify_after_register(so, sock_evt_cantsendmore,
1466 handle);
1467 else if (so->so_state & SS_CANTRCVMORE)
1468 sflt_notify_after_register(so, sock_evt_cantrecvmore,
1469 handle);
fe8ab488 1470 socket_unlock(so, 0);
316670eb
A
1471 /* XXX no easy way to post the sock_evt_closing event */
1472 sock_release(so);
1473 solist = solisthead;
1474 solisthead = solisthead->next;
1475 FREE(solist, M_IFADDR);
1476 }
1477
39236c6e 1478 return (error);
91447636
A
1479}
1480
1481errno_t
39236c6e 1482sflt_unregister(sflt_handle handle)
91447636
A
1483{
1484 struct socket_filter *filter;
6d2010ae 1485 lck_rw_lock_exclusive(sock_filter_lock);
39236c6e 1486
6d2010ae 1487 /* Find the entry by the handle */
91447636
A
1488 TAILQ_FOREACH(filter, &sock_filter_head, sf_global_next) {
1489 if (filter->sf_filter.sf_handle == handle)
1490 break;
1491 }
39236c6e 1492
91447636 1493 if (filter) {
39236c6e 1494 /* Remove it from the global list */
91447636 1495 TAILQ_REMOVE(&sock_filter_head, filter, sf_global_next);
39236c6e
A
1496
1497 /* Remove it from the protosw list */
91447636 1498 if ((filter->sf_filter.sf_flags & SFLT_GLOBAL) != 0) {
39236c6e
A
1499 TAILQ_REMOVE(&filter->sf_proto->pr_filter_head,
1500 filter, sf_protosw_next);
91447636 1501 }
39236c6e
A
1502
1503 /* Detach from any sockets */
6d2010ae 1504 struct socket_filter_entry *entry = NULL;
39236c6e
A
1505
1506 for (entry = filter->sf_entry_head; entry;
1507 entry = entry->sfe_next_onfilter) {
6d2010ae 1508 sflt_detach_locked(entry);
3a60a9f5 1509 }
39236c6e
A
1510
1511 /* Release the filter */
6d2010ae 1512 sflt_release_locked(filter);
91447636 1513 }
39236c6e 1514
6d2010ae 1515 lck_rw_unlock_exclusive(sock_filter_lock);
39236c6e 1516
91447636 1517 if (filter == NULL)
39236c6e
A
1518 return (ENOENT);
1519
1520 return (0);
91447636
A
1521}
1522
1523errno_t
39236c6e
A
1524sock_inject_data_in(socket_t so, const struct sockaddr *from, mbuf_t data,
1525 mbuf_t control, sflt_data_flag_t flags)
91447636
A
1526{
1527 int error = 0;
39236c6e
A
1528
1529 if (so == NULL || data == NULL)
1530 return (EINVAL);
1531
91447636 1532 if (flags & sock_data_filt_flag_oob) {
39236c6e 1533 return (ENOTSUP);
91447636 1534 }
39236c6e 1535
91447636 1536 socket_lock(so, 1);
39236c6e
A
1537
1538 /* reject if this is a subflow socket */
1539 if (so->so_flags & SOF_MP_SUBFLOW) {
1540 error = ENOTSUP;
1541 goto done;
1542 }
1543
91447636 1544 if (from) {
39236c6e
A
1545 if (sbappendaddr(&so->so_rcv,
1546 (struct sockaddr *)(uintptr_t)from, data, control, NULL))
91447636
A
1547 sorwakeup(so);
1548 goto done;
1549 }
39236c6e 1550
91447636
A
1551 if (control) {
1552 if (sbappendcontrol(&so->so_rcv, data, control, NULL))
1553 sorwakeup(so);
1554 goto done;
1555 }
39236c6e 1556
91447636
A
1557 if (flags & sock_data_filt_flag_record) {
1558 if (control || from) {
1559 error = EINVAL;
1560 goto done;
1561 }
39236c6e 1562 if (sbappendrecord(&so->so_rcv, (struct mbuf *)data))
91447636
A
1563 sorwakeup(so);
1564 goto done;
1565 }
39236c6e 1566
91447636
A
1567 if (sbappend(&so->so_rcv, data))
1568 sorwakeup(so);
1569done:
1570 socket_unlock(so, 1);
39236c6e 1571 return (error);
91447636
A
1572}
1573
1574errno_t
39236c6e
A
1575sock_inject_data_out(socket_t so, const struct sockaddr *to, mbuf_t data,
1576 mbuf_t control, sflt_data_flag_t flags)
91447636 1577{
39236c6e
A
1578 int sosendflags = 0;
1579
1580 /* reject if this is a subflow socket */
1581 if (so->so_flags & SOF_MP_SUBFLOW)
1582 return (ENOTSUP);
1583
1584 if (flags & sock_data_filt_flag_oob)
1585 sosendflags = MSG_OOB;
1586 return (sosend(so, (struct sockaddr *)(uintptr_t)to, NULL,
1587 data, control, sosendflags));
91447636
A
1588}
1589
1590sockopt_dir
39236c6e 1591sockopt_direction(sockopt_t sopt)
91447636 1592{
39236c6e 1593 return ((sopt->sopt_dir == SOPT_GET) ? sockopt_get : sockopt_set);
91447636
A
1594}
1595
1596int
39236c6e 1597sockopt_level(sockopt_t sopt)
91447636 1598{
39236c6e 1599 return (sopt->sopt_level);
91447636
A
1600}
1601
1602int
39236c6e 1603sockopt_name(sockopt_t sopt)
91447636 1604{
39236c6e 1605 return (sopt->sopt_name);
91447636
A
1606}
1607
1608size_t
39236c6e 1609sockopt_valsize(sockopt_t sopt)
91447636 1610{
39236c6e 1611 return (sopt->sopt_valsize);
91447636
A
1612}
1613
1614errno_t
39236c6e 1615sockopt_copyin(sockopt_t sopt, void *data, size_t len)
91447636 1616{
39236c6e 1617 return (sooptcopyin(sopt, data, len, len));
91447636
A
1618}
1619
1620errno_t
39236c6e 1621sockopt_copyout(sockopt_t sopt, void *data, size_t len)
91447636 1622{
39236c6e 1623 return (sooptcopyout(sopt, data, len));
91447636 1624}