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