2 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
31 #include <sys/kpi_socketfilter.h>
33 #include <sys/socket.h>
34 #include <sys/param.h>
35 #include <sys/errno.h>
36 #include <sys/malloc.h>
37 #include <sys/protosw.h>
38 #include <kern/locks.h>
39 #include <net/kext_net.h>
41 static struct socket_filter_list sock_filter_head
;
42 static lck_mtx_t
*sock_filter_lock
= 0;
44 static void sflt_detach_private(struct socket_filter_entry
*entry
, int unregistering
);
46 __private_extern__
void
49 lck_grp_attr_t
*grp_attrib
= 0;
50 lck_attr_t
*lck_attrib
= 0;
51 lck_grp_t
*lck_group
= 0;
53 TAILQ_INIT(&sock_filter_head
);
55 /* Allocate a spin lock */
56 grp_attrib
= lck_grp_attr_alloc_init();
57 lck_grp_attr_setdefault(grp_attrib
);
58 lck_group
= lck_grp_alloc_init("socket filter lock", grp_attrib
);
59 lck_grp_attr_free(grp_attrib
);
60 lck_attrib
= lck_attr_alloc_init();
61 lck_attr_setdefault(lck_attrib
);
62 lck_attr_setdebug(lck_attrib
);
63 sock_filter_lock
= lck_mtx_alloc_init(lck_group
, lck_attrib
);
64 lck_grp_free(lck_group
);
65 lck_attr_free(lck_attrib
);
68 __private_extern__
void
72 struct protosw
*proto
= so
->so_proto
;
73 struct socket_filter
*filter
;
75 if (TAILQ_FIRST(&proto
->pr_filter_head
) != NULL
) {
76 lck_mtx_lock(sock_filter_lock
);
77 TAILQ_FOREACH(filter
, &proto
->pr_filter_head
, sf_protosw_next
) {
78 sflt_attach_private(so
, filter
, 0, 0);
80 lck_mtx_unlock(sock_filter_lock
);
84 __private_extern__
void
88 struct socket_filter_entry
*filter
;
89 struct socket_filter_entry
*filter_next
;
91 for (filter
= so
->so_filt
; filter
; filter
= filter_next
) {
92 filter_next
= filter
->sfe_next_onsocket
;
93 sflt_detach_private(filter
, 0);
98 __private_extern__
void
105 __private_extern__
void
110 if (so
->so_filteruse
== 0) {
111 struct socket_filter_entry
*filter
;
112 struct socket_filter_entry
*next_filter
;
113 // search for detaching filters
114 for (filter
= so
->so_filt
; filter
; filter
= next_filter
) {
115 next_filter
= filter
->sfe_next_onsocket
;
117 if (filter
->sfe_flags
& SFEF_DETACHUSEZERO
) {
118 sflt_detach_private(filter
, 0);
124 __private_extern__
void
130 struct socket_filter_entry
*filter
;
133 for (filter
= so
->so_filt
; filter
;
134 filter
= filter
->sfe_next_onsocket
) {
135 if (filter
->sfe_filter
->sf_filter
.sf_notify
) {
139 socket_unlock(so
, 0);
141 filter
->sfe_filter
->sf_filter
.sf_notify(
142 filter
->sfe_cookie
, so
, event
, param
);
152 __private_extern__
int
155 const struct sockaddr
*from
,
158 sflt_data_flag_t flags
,
161 struct socket_filter_entry
*filter
;
163 int filtered_storage
;
165 if (filtered
== NULL
)
166 filtered
= &filtered_storage
;
169 for (filter
= so
->so_filt
; filter
&& (error
== 0);
170 filter
= filter
->sfe_next_onsocket
) {
171 if (filter
->sfe_filter
->sf_filter
.sf_data_in
) {
172 if (*filtered
== 0) {
175 socket_unlock(so
, 0);
177 error
= filter
->sfe_filter
->sf_filter
.sf_data_in(
178 filter
->sfe_cookie
, so
, from
, data
, control
, flags
);
182 if (*filtered
!= 0) {
190 /* sflt_attach_private
192 * Assumptions: If filter is not NULL, socket_filter_lock is held.
195 __private_extern__
int
198 struct socket_filter
*filter
,
202 struct socket_filter_entry
*entry
= NULL
;
206 if (filter
== NULL
) {
207 /* Find the filter by the handle */
208 lck_mtx_lock(sock_filter_lock
);
211 TAILQ_FOREACH(filter
, &sock_filter_head
, sf_global_next
) {
212 if (filter
->sf_filter
.sf_handle
== handle
)
221 /* allocate the socket filter entry */
222 MALLOC(entry
, struct socket_filter_entry
*, sizeof(*entry
), M_IFADDR
, M_WAITOK
);
229 /* Initialize the socket filter entry and call the attach function */
230 entry
->sfe_filter
= filter
;
231 entry
->sfe_socket
= so
;
232 entry
->sfe_cookie
= NULL
;
233 entry
->sfe_flags
= 0;
234 if (entry
->sfe_filter
->sf_filter
.sf_attach
) {
235 filter
->sf_usecount
++;
238 socket_unlock(so
, 0);
239 error
= entry
->sfe_filter
->sf_filter
.sf_attach(&entry
->sfe_cookie
, so
);
243 filter
->sf_usecount
--;
245 /* If the attach function returns an error, this filter is not attached */
247 FREE(entry
, M_IFADDR
);
254 /* Put the entry in the socket list */
255 entry
->sfe_next_onsocket
= so
->so_filt
;
258 /* Put the entry in the filter list */
259 entry
->sfe_next_onfilter
= filter
->sf_entry_head
;
260 filter
->sf_entry_head
= entry
;
262 /* Incremenet the parent filter's usecount */
263 filter
->sf_usecount
++;
267 lck_mtx_unlock(sock_filter_lock
);
274 /* sflt_detach_private
276 * Assumptions: if you pass 0 in for the second parameter, you are holding the
277 * socket lock for the socket the entry is attached to. If you pass 1 in for
278 * the second parameter, it is assumed that the entry is not on the filter's
279 * list and the socket lock is not held.
284 struct socket_filter_entry
*entry
,
287 struct socket
*so
= entry
->sfe_socket
;
288 struct socket_filter_entry
**next_ptr
;
293 socket_lock(entry
->sfe_socket
, 0);
297 * Attempt to find the entry on the filter's list and
298 * remove it. This prevents a filter detaching at the
299 * same time from attempting to remove the same entry.
301 lck_mtx_lock(sock_filter_lock
);
302 if (!unregistering
) {
303 if ((entry
->sfe_flags
& SFEF_UNREGISTERING
) != 0) {
305 * Another thread is unregistering the filter, we need to
306 * avoid detaching the filter here so the socket won't go
309 lck_mtx_unlock(sock_filter_lock
);
312 for (next_ptr
= &entry
->sfe_filter
->sf_entry_head
; *next_ptr
;
313 next_ptr
= &((*next_ptr
)->sfe_next_onfilter
)) {
314 if (*next_ptr
== entry
) {
316 *next_ptr
= entry
->sfe_next_onfilter
;
321 if (!found
&& (entry
->sfe_flags
& SFEF_DETACHUSEZERO
) == 0) {
322 lck_mtx_unlock(sock_filter_lock
);
328 * Clear the removing flag. We will perform the detach here or
329 * request a delayed deatch.
331 entry
->sfe_flags
&= ~SFEF_UNREGISTERING
;
334 if (entry
->sfe_socket
->so_filteruse
!= 0) {
335 entry
->sfe_flags
|= SFEF_DETACHUSEZERO
;
336 lck_mtx_unlock(sock_filter_lock
);
341 * Check if we are removing the last attached filter and
342 * the parent filter is being unregistered.
344 entry
->sfe_filter
->sf_usecount
--;
345 if ((entry
->sfe_filter
->sf_usecount
== 0) &&
346 (entry
->sfe_filter
->sf_flags
& SFF_DETACHING
) != 0)
349 lck_mtx_unlock(sock_filter_lock
);
351 /* Remove from the socket list */
352 for (next_ptr
= &entry
->sfe_socket
->so_filt
; *next_ptr
;
353 next_ptr
= &((*next_ptr
)->sfe_next_onsocket
)) {
354 if (*next_ptr
== entry
) {
355 *next_ptr
= entry
->sfe_next_onsocket
;
360 if (entry
->sfe_filter
->sf_filter
.sf_detach
)
361 entry
->sfe_filter
->sf_filter
.sf_detach(entry
->sfe_cookie
, entry
->sfe_socket
);
363 if (detached
&& entry
->sfe_filter
->sf_filter
.sf_unregistered
) {
364 entry
->sfe_filter
->sf_filter
.sf_unregistered(entry
->sfe_filter
->sf_filter
.sf_handle
);
365 FREE(entry
->sfe_filter
, M_IFADDR
);
369 socket_unlock(entry
->sfe_socket
, 1);
371 FREE(entry
, M_IFADDR
);
379 if (socket
== NULL
|| handle
== 0)
382 return sflt_attach_private(socket
, NULL
, handle
, 0);
390 struct socket_filter_entry
*filter
;
393 if (socket
== NULL
|| handle
== 0)
396 socket_lock(socket
, 1);
398 for (filter
= socket
->so_filt
; filter
;
399 filter
= filter
->sfe_next_onsocket
) {
400 if (filter
->sfe_filter
->sf_filter
.sf_handle
== handle
)
404 if (filter
!= NULL
) {
405 sflt_detach_private(filter
, 0);
408 socket
->so_filt
= NULL
;
412 socket_unlock(socket
, 1);
420 const struct sflt_filter
*filter
,
425 struct socket_filter
*sock_filt
= NULL
;
426 struct socket_filter
*match
= NULL
;
428 struct protosw
*pr
= pffindproto(domain
, protocol
, type
);
430 if (pr
== NULL
) return ENOENT
;
432 if (filter
->sf_attach
== NULL
|| filter
->sf_detach
== NULL
) return EINVAL
;
433 if (filter
->sf_handle
== 0) return EINVAL
;
434 if (filter
->sf_name
== NULL
) return EINVAL
;
436 /* Allocate the socket filter */
437 MALLOC(sock_filt
, struct socket_filter
*, sizeof(*sock_filt
), M_IFADDR
, M_WAITOK
);
438 if (sock_filt
== NULL
) {
442 bzero(sock_filt
, sizeof(*sock_filt
));
443 sock_filt
->sf_filter
= *filter
;
445 lck_mtx_lock(sock_filter_lock
);
446 /* Look for an existing entry */
447 TAILQ_FOREACH(match
, &sock_filter_head
, sf_global_next
) {
448 if (match
->sf_filter
.sf_handle
== sock_filt
->sf_filter
.sf_handle
) {
453 /* Add the entry only if there was no existing entry */
455 TAILQ_INSERT_TAIL(&sock_filter_head
, sock_filt
, sf_global_next
);
456 if ((sock_filt
->sf_filter
.sf_flags
& SFLT_GLOBAL
) != 0) {
457 TAILQ_INSERT_TAIL(&pr
->pr_filter_head
, sock_filt
, sf_protosw_next
);
458 sock_filt
->sf_proto
= pr
;
461 lck_mtx_unlock(sock_filter_lock
);
464 FREE(sock_filt
, M_IFADDR
);
475 struct socket_filter
*filter
;
476 struct socket_filter_entry
*entry_head
= NULL
;
477 struct socket_filter_entry
*next_entry
= NULL
;
479 /* Find the entry and remove it from the global and protosw lists */
480 lck_mtx_lock(sock_filter_lock
);
481 TAILQ_FOREACH(filter
, &sock_filter_head
, sf_global_next
) {
482 if (filter
->sf_filter
.sf_handle
== handle
)
487 TAILQ_REMOVE(&sock_filter_head
, filter
, sf_global_next
);
488 if ((filter
->sf_filter
.sf_flags
& SFLT_GLOBAL
) != 0) {
489 TAILQ_REMOVE(&filter
->sf_proto
->pr_filter_head
, filter
, sf_protosw_next
);
491 entry_head
= filter
->sf_entry_head
;
492 filter
->sf_entry_head
= NULL
;
493 filter
->sf_flags
|= SFF_DETACHING
;
495 for (next_entry
= entry_head
; next_entry
;
496 next_entry
= next_entry
->sfe_next_onfilter
) {
497 socket_lock(next_entry
->sfe_socket
, 1);
498 next_entry
->sfe_flags
|= SFEF_UNREGISTERING
;
499 socket_unlock(next_entry
->sfe_socket
, 0); /* Radar 4201550: prevents the socket from being deleted while being unregistered */
503 lck_mtx_unlock(sock_filter_lock
);
508 /* We need to detach the filter from any sockets it's attached to */
509 if (entry_head
== 0) {
510 if (filter
->sf_filter
.sf_unregistered
)
511 filter
->sf_filter
.sf_unregistered(filter
->sf_filter
.sf_handle
);
514 next_entry
= entry_head
->sfe_next_onfilter
;
515 sflt_detach_private(entry_head
, 1);
516 entry_head
= next_entry
;
526 const struct sockaddr
* from
,
529 sflt_data_flag_t flags
)
532 if (so
== NULL
|| data
== NULL
) return EINVAL
;
534 if (flags
& sock_data_filt_flag_oob
) {
541 if (sbappendaddr(&so
->so_rcv
, (struct sockaddr
*)from
, data
,
548 if (sbappendcontrol(&so
->so_rcv
, data
, control
, NULL
))
553 if (flags
& sock_data_filt_flag_record
) {
554 if (control
|| from
) {
558 if (sbappendrecord(&so
->so_rcv
, (struct mbuf
*)data
))
563 if (sbappend(&so
->so_rcv
, data
))
566 socket_unlock(so
, 1);
571 sock_inject_data_out(
573 const struct sockaddr
* to
,
576 sflt_data_flag_t flags
)
579 if (flags
& sock_data_filt_flag_oob
) sosendflags
= MSG_OOB
;
580 return sosend(so
, (const struct sockaddr
*)to
, NULL
,
581 data
, control
, sosendflags
);
588 return (sopt
->sopt_dir
== SOPT_GET
) ? sockopt_get
: sockopt_set
;
595 return sopt
->sopt_level
;
602 return sopt
->sopt_name
;
609 return sopt
->sopt_valsize
;
618 return sooptcopyin(sopt
, data
, len
, len
);
627 return sooptcopyout(sopt
, data
, len
);