]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kpi_socketfilter.c
xnu-792.22.5.tar.gz
[apple/xnu.git] / bsd / kern / kpi_socketfilter.c
CommitLineData
91447636 1/*
5d5c5d0d
A
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 *
8f6c56a5 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
91447636 5 *
8f6c56a5
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
8ad349bb 24 * limitations under the License.
8f6c56a5
A
25 *
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>
36#include <kern/locks.h>
37#include <net/kext_net.h>
38
39static struct socket_filter_list sock_filter_head;
40static lck_mtx_t *sock_filter_lock = 0;
41
3a60a9f5
A
42static void sflt_detach_private(struct socket_filter_entry *entry, int unregistering);
43
91447636
A
44__private_extern__ void
45sflt_init(void)
46{
47 lck_grp_attr_t *grp_attrib = 0;
48 lck_attr_t *lck_attrib = 0;
49 lck_grp_t *lck_group = 0;
50
51 TAILQ_INIT(&sock_filter_head);
52
53 /* Allocate a spin lock */
54 grp_attrib = lck_grp_attr_alloc_init();
91447636
A
55 lck_group = lck_grp_alloc_init("socket filter lock", grp_attrib);
56 lck_grp_attr_free(grp_attrib);
57 lck_attrib = lck_attr_alloc_init();
91447636
A
58 sock_filter_lock = lck_mtx_alloc_init(lck_group, lck_attrib);
59 lck_grp_free(lck_group);
60 lck_attr_free(lck_attrib);
61}
62
63__private_extern__ void
64sflt_initsock(
65 struct socket *so)
66{
67 struct protosw *proto = so->so_proto;
68 struct socket_filter *filter;
69
70 if (TAILQ_FIRST(&proto->pr_filter_head) != NULL) {
71 lck_mtx_lock(sock_filter_lock);
72 TAILQ_FOREACH(filter, &proto->pr_filter_head, sf_protosw_next) {
73 sflt_attach_private(so, filter, 0, 0);
74 }
75 lck_mtx_unlock(sock_filter_lock);
76 }
77}
78
79__private_extern__ void
80sflt_termsock(
81 struct socket *so)
82{
83 struct socket_filter_entry *filter;
84 struct socket_filter_entry *filter_next;
85
86 for (filter = so->so_filt; filter; filter = filter_next) {
87 filter_next = filter->sfe_next_onsocket;
88 sflt_detach_private(filter, 0);
89 }
3a60a9f5 90 so->so_filt = NULL;
91447636
A
91}
92
93__private_extern__ void
94sflt_use(
95 struct socket *so)
96{
97 so->so_filteruse++;
98}
99
100__private_extern__ void
101sflt_unuse(
102 struct socket *so)
103{
104 so->so_filteruse--;
105 if (so->so_filteruse == 0) {
106 struct socket_filter_entry *filter;
107 struct socket_filter_entry *next_filter;
108 // search for detaching filters
109 for (filter = so->so_filt; filter; filter = next_filter) {
110 next_filter = filter->sfe_next_onsocket;
111
3a60a9f5 112 if (filter->sfe_flags & SFEF_DETACHUSEZERO) {
91447636
A
113 sflt_detach_private(filter, 0);
114 }
115 }
116 }
117}
118
119__private_extern__ void
120sflt_notify(
121 struct socket *so,
122 sflt_event_t event,
123 void *param)
124{
125 struct socket_filter_entry *filter;
126 int filtered = 0;
127
128 for (filter = so->so_filt; filter;
129 filter = filter->sfe_next_onsocket) {
130 if (filter->sfe_filter->sf_filter.sf_notify) {
131 if (filtered == 0) {
132 filtered = 1;
133 sflt_use(so);
134 socket_unlock(so, 0);
135 }
136 filter->sfe_filter->sf_filter.sf_notify(
137 filter->sfe_cookie, so, event, param);
138 }
139 }
140
141 if (filtered != 0) {
142 socket_lock(so, 0);
143 sflt_unuse(so);
144 }
145}
146
147__private_extern__ int
148sflt_data_in(
149 struct socket *so,
150 const struct sockaddr *from,
151 mbuf_t *data,
152 mbuf_t *control,
cc9f6e38
A
153 sflt_data_flag_t flags,
154 int *filtered)
91447636
A
155{
156 struct socket_filter_entry *filter;
91447636 157 int error = 0;
cc9f6e38
A
158 int filtered_storage;
159
160 if (filtered == NULL)
161 filtered = &filtered_storage;
162 *filtered = 0;
91447636 163
b36670ce 164 for (filter = so->so_filt; filter && (error == 0);
91447636
A
165 filter = filter->sfe_next_onsocket) {
166 if (filter->sfe_filter->sf_filter.sf_data_in) {
cc9f6e38
A
167 if (*filtered == 0) {
168 *filtered = 1;
91447636
A
169 sflt_use(so);
170 socket_unlock(so, 0);
171 }
172 error = filter->sfe_filter->sf_filter.sf_data_in(
173 filter->sfe_cookie, so, from, data, control, flags);
174 }
175 }
176
cc9f6e38 177 if (*filtered != 0) {
91447636
A
178 socket_lock(so, 0);
179 sflt_unuse(so);
180 }
181
182 return error;
183}
184
185/* sflt_attach_private
186 *
187 * Assumptions: If filter is not NULL, socket_filter_lock is held.
188 */
189
190__private_extern__ int
191sflt_attach_private(
192 struct socket *so,
193 struct socket_filter *filter,
194 sflt_handle handle,
195 int sock_locked)
196{
197 struct socket_filter_entry *entry = NULL;
198 int didlock = 0;
199 int error = 0;
200
201 if (filter == NULL) {
202 /* Find the filter by the handle */
203 lck_mtx_lock(sock_filter_lock);
204 didlock = 1;
205
206 TAILQ_FOREACH(filter, &sock_filter_head, sf_global_next) {
207 if (filter->sf_filter.sf_handle == handle)
208 break;
209 }
210 }
211
212 if (filter == NULL)
213 error = ENOENT;
214
215 if (error == 0) {
216 /* allocate the socket filter entry */
217 MALLOC(entry, struct socket_filter_entry *, sizeof(*entry), M_IFADDR, M_WAITOK);
218 if (entry == NULL) {
219 error = ENOMEM;
220 }
221 }
222
223 if (error == 0) {
224 /* Initialize the socket filter entry and call the attach function */
225 entry->sfe_filter = filter;
226 entry->sfe_socket = so;
227 entry->sfe_cookie = NULL;
3a60a9f5 228 entry->sfe_flags = 0;
91447636
A
229 if (entry->sfe_filter->sf_filter.sf_attach) {
230 filter->sf_usecount++;
231
232 if (sock_locked)
233 socket_unlock(so, 0);
234 error = entry->sfe_filter->sf_filter.sf_attach(&entry->sfe_cookie, so);
235 if (sock_locked)
236 socket_lock(so, 0);
237
238 filter->sf_usecount--;
239
240 /* If the attach function returns an error, this filter is not attached */
241 if (error) {
242 FREE(entry, M_IFADDR);
243 entry = NULL;
244 }
245 }
246 }
247
248 if (error == 0) {
249 /* Put the entry in the socket list */
250 entry->sfe_next_onsocket = so->so_filt;
251 so->so_filt = entry;
252
253 /* Put the entry in the filter list */
254 entry->sfe_next_onfilter = filter->sf_entry_head;
255 filter->sf_entry_head = entry;
256
91447636
A
257 /* Incremenet the parent filter's usecount */
258 filter->sf_usecount++;
259 }
260
261 if (didlock) {
262 lck_mtx_unlock(sock_filter_lock);
263 }
264
265 return error;
266}
267
268
269/* sflt_detach_private
270 *
271 * Assumptions: if you pass 0 in for the second parameter, you are holding the
272 * socket lock for the socket the entry is attached to. If you pass 1 in for
273 * the second parameter, it is assumed that the entry is not on the filter's
274 * list and the socket lock is not held.
275 */
276
3a60a9f5 277static void
91447636
A
278sflt_detach_private(
279 struct socket_filter_entry *entry,
3a60a9f5 280 int unregistering)
91447636
A
281{
282 struct socket *so = entry->sfe_socket;
283 struct socket_filter_entry **next_ptr;
284 int detached = 0;
285 int found = 0;
286
3a60a9f5 287 if (unregistering) {
91447636
A
288 socket_lock(entry->sfe_socket, 0);
289 }
290
291 /*
292 * Attempt to find the entry on the filter's list and
293 * remove it. This prevents a filter detaching at the
294 * same time from attempting to remove the same entry.
295 */
296 lck_mtx_lock(sock_filter_lock);
3a60a9f5
A
297 if (!unregistering) {
298 if ((entry->sfe_flags & SFEF_UNREGISTERING) != 0) {
299 /*
300 * Another thread is unregistering the filter, we need to
301 * avoid detaching the filter here so the socket won't go
302 * away.
303 */
304 lck_mtx_unlock(sock_filter_lock);
305 return;
306 }
91447636
A
307 for (next_ptr = &entry->sfe_filter->sf_entry_head; *next_ptr;
308 next_ptr = &((*next_ptr)->sfe_next_onfilter)) {
309 if (*next_ptr == entry) {
310 found = 1;
311 *next_ptr = entry->sfe_next_onfilter;
312 break;
313 }
314 }
3a60a9f5
A
315
316 if (!found && (entry->sfe_flags & SFEF_DETACHUSEZERO) == 0) {
317 lck_mtx_unlock(sock_filter_lock);
318 return;
319 }
91447636 320 }
3a60a9f5
A
321 else {
322 /*
323 * Clear the removing flag. We will perform the detach here or
324 * request a delayed deatch.
325 */
326 entry->sfe_flags &= ~SFEF_UNREGISTERING;
91447636
A
327 }
328
329 if (entry->sfe_socket->so_filteruse != 0) {
3a60a9f5 330 entry->sfe_flags |= SFEF_DETACHUSEZERO;
91447636 331 lck_mtx_unlock(sock_filter_lock);
91447636
A
332 return;
333 }
3a60a9f5
A
334 else {
335 /*
336 * Check if we are removing the last attached filter and
337 * the parent filter is being unregistered.
338 */
91447636
A
339 entry->sfe_filter->sf_usecount--;
340 if ((entry->sfe_filter->sf_usecount == 0) &&
341 (entry->sfe_filter->sf_flags & SFF_DETACHING) != 0)
342 detached = 1;
343 }
344 lck_mtx_unlock(sock_filter_lock);
345
346 /* Remove from the socket list */
347 for (next_ptr = &entry->sfe_socket->so_filt; *next_ptr;
348 next_ptr = &((*next_ptr)->sfe_next_onsocket)) {
349 if (*next_ptr == entry) {
350 *next_ptr = entry->sfe_next_onsocket;
351 break;
352 }
353 }
354
355 if (entry->sfe_filter->sf_filter.sf_detach)
356 entry->sfe_filter->sf_filter.sf_detach(entry->sfe_cookie, entry->sfe_socket);
357
358 if (detached && entry->sfe_filter->sf_filter.sf_unregistered) {
359 entry->sfe_filter->sf_filter.sf_unregistered(entry->sfe_filter->sf_filter.sf_handle);
360 FREE(entry->sfe_filter, M_IFADDR);
361 }
3a60a9f5
A
362
363 if (unregistering)
91447636 364 socket_unlock(entry->sfe_socket, 1);
3a60a9f5 365
91447636
A
366 FREE(entry, M_IFADDR);
367}
368
369errno_t
370sflt_attach(
371 socket_t socket,
372 sflt_handle handle)
373{
374 if (socket == NULL || handle == 0)
375 return EINVAL;
376
377 return sflt_attach_private(socket, NULL, handle, 0);
378}
379
380errno_t
381sflt_detach(
382 socket_t socket,
383 sflt_handle handle)
384{
385 struct socket_filter_entry *filter;
386 errno_t result = 0;
387
388 if (socket == NULL || handle == 0)
389 return EINVAL;
390
391 socket_lock(socket, 1);
392
393 for (filter = socket->so_filt; filter;
394 filter = filter->sfe_next_onsocket) {
395 if (filter->sfe_filter->sf_filter.sf_handle == handle)
396 break;
397 }
398
399 if (filter != NULL) {
400 sflt_detach_private(filter, 0);
401 }
402 else {
3a60a9f5 403 socket->so_filt = NULL;
91447636
A
404 result = ENOENT;
405 }
406
407 socket_unlock(socket, 1);
408
409 return result;
410}
411
412
413errno_t
414sflt_register(
415 const struct sflt_filter *filter,
416 int domain,
417 int type,
418 int protocol)
419{
420 struct socket_filter *sock_filt = NULL;
421 struct socket_filter *match = NULL;
422 int error = 0;
423 struct protosw *pr = pffindproto(domain, protocol, type);
424
425 if (pr == NULL) return ENOENT;
426
427 if (filter->sf_attach == NULL || filter->sf_detach == NULL) return EINVAL;
428 if (filter->sf_handle == 0) return EINVAL;
429 if (filter->sf_name == NULL) return EINVAL;
430
431 /* Allocate the socket filter */
432 MALLOC(sock_filt, struct socket_filter*, sizeof(*sock_filt), M_IFADDR, M_WAITOK);
433 if (sock_filt == NULL) {
434 return ENOBUFS;
435 }
436
437 bzero(sock_filt, sizeof(*sock_filt));
438 sock_filt->sf_filter = *filter;
439
440 lck_mtx_lock(sock_filter_lock);
441 /* Look for an existing entry */
442 TAILQ_FOREACH(match, &sock_filter_head, sf_global_next) {
443 if (match->sf_filter.sf_handle == sock_filt->sf_filter.sf_handle) {
444 break;
445 }
446 }
447
448 /* Add the entry only if there was no existing entry */
449 if (match == NULL) {
450 TAILQ_INSERT_TAIL(&sock_filter_head, sock_filt, sf_global_next);
451 if ((sock_filt->sf_filter.sf_flags & SFLT_GLOBAL) != 0) {
452 TAILQ_INSERT_TAIL(&pr->pr_filter_head, sock_filt, sf_protosw_next);
453 sock_filt->sf_proto = pr;
454 }
455 }
456 lck_mtx_unlock(sock_filter_lock);
457
458 if (match != NULL) {
459 FREE(sock_filt, M_IFADDR);
460 return EEXIST;
461 }
462
463 return error;
464}
465
466errno_t
467sflt_unregister(
468 sflt_handle handle)
469{
470 struct socket_filter *filter;
471 struct socket_filter_entry *entry_head = NULL;
3a60a9f5 472 struct socket_filter_entry *next_entry = NULL;
91447636
A
473
474 /* Find the entry and remove it from the global and protosw lists */
475 lck_mtx_lock(sock_filter_lock);
476 TAILQ_FOREACH(filter, &sock_filter_head, sf_global_next) {
477 if (filter->sf_filter.sf_handle == handle)
478 break;
479 }
480
481 if (filter) {
482 TAILQ_REMOVE(&sock_filter_head, filter, sf_global_next);
483 if ((filter->sf_filter.sf_flags & SFLT_GLOBAL) != 0) {
484 TAILQ_REMOVE(&filter->sf_proto->pr_filter_head, filter, sf_protosw_next);
485 }
486 entry_head = filter->sf_entry_head;
487 filter->sf_entry_head = NULL;
488 filter->sf_flags |= SFF_DETACHING;
3a60a9f5
A
489
490 for (next_entry = entry_head; next_entry;
491 next_entry = next_entry->sfe_next_onfilter) {
492 socket_lock(next_entry->sfe_socket, 1);
493 next_entry->sfe_flags |= SFEF_UNREGISTERING;
494 socket_unlock(next_entry->sfe_socket, 0); /* Radar 4201550: prevents the socket from being deleted while being unregistered */
495 }
91447636
A
496 }
497
498 lck_mtx_unlock(sock_filter_lock);
499
500 if (filter == NULL)
501 return ENOENT;
502
503 /* We need to detach the filter from any sockets it's attached to */
504 if (entry_head == 0) {
505 if (filter->sf_filter.sf_unregistered)
506 filter->sf_filter.sf_unregistered(filter->sf_filter.sf_handle);
507 } else {
508 while (entry_head) {
91447636
A
509 next_entry = entry_head->sfe_next_onfilter;
510 sflt_detach_private(entry_head, 1);
511 entry_head = next_entry;
512 }
513 }
514
515 return 0;
516}
517
518errno_t
519sock_inject_data_in(
520 socket_t so,
521 const struct sockaddr* from,
522 mbuf_t data,
523 mbuf_t control,
524 sflt_data_flag_t flags)
525{
526 int error = 0;
527 if (so == NULL || data == NULL) return EINVAL;
528
529 if (flags & sock_data_filt_flag_oob) {
530 return ENOTSUP;
531 }
532
533 socket_lock(so, 1);
534
535 if (from) {
536 if (sbappendaddr(&so->so_rcv, (struct sockaddr*)from, data,
537 control, NULL))
538 sorwakeup(so);
539 goto done;
540 }
541
542 if (control) {
543 if (sbappendcontrol(&so->so_rcv, data, control, NULL))
544 sorwakeup(so);
545 goto done;
546 }
547
548 if (flags & sock_data_filt_flag_record) {
549 if (control || from) {
550 error = EINVAL;
551 goto done;
552 }
553 if (sbappendrecord(&so->so_rcv, (struct mbuf*)data))
554 sorwakeup(so);
555 goto done;
556 }
557
558 if (sbappend(&so->so_rcv, data))
559 sorwakeup(so);
560done:
561 socket_unlock(so, 1);
562 return error;
563}
564
565errno_t
566sock_inject_data_out(
567 socket_t so,
568 const struct sockaddr* to,
569 mbuf_t data,
570 mbuf_t control,
571 sflt_data_flag_t flags)
572{
573 int sosendflags = 0;
574 if (flags & sock_data_filt_flag_oob) sosendflags = MSG_OOB;
575 return sosend(so, (const struct sockaddr*)to, NULL,
576 data, control, sosendflags);
577}
578
579sockopt_dir
580sockopt_direction(
581 sockopt_t sopt)
582{
583 return (sopt->sopt_dir == SOPT_GET) ? sockopt_get : sockopt_set;
584}
585
586int
587sockopt_level(
588 sockopt_t sopt)
589{
590 return sopt->sopt_level;
591}
592
593int
594sockopt_name(
595 sockopt_t sopt)
596{
597 return sopt->sopt_name;
598}
599
600size_t
601sockopt_valsize(
602 sockopt_t sopt)
603{
604 return sopt->sopt_valsize;
605}
606
607errno_t
608sockopt_copyin(
609 sockopt_t sopt,
610 void *data,
611 size_t len)
612{
613 return sooptcopyin(sopt, data, len, len);
614}
615
616errno_t
617sockopt_copyout(
618 sockopt_t sopt,
619 void *data,
620 size_t len)
621{
622 return sooptcopyout(sopt, data, len);
623}