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