]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kpi_socketfilter.c
xnu-792.1.5.tar.gz
[apple/xnu.git] / bsd / kern / kpi_socketfilter.c
CommitLineData
91447636
A
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
33static struct socket_filter_list sock_filter_head;
34static lck_mtx_t *sock_filter_lock = 0;
35
36__private_extern__ void
37sflt_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
59sflt_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
75sflt_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
88sflt_use(
89 struct socket *so)
90{
91 so->so_filteruse++;
92}
93
94__private_extern__ void
95sflt_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
114sflt_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
142sflt_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{
149 struct socket_filter_entry *filter;
150 int filtered = 0;
151 int error = 0;
152
b36670ce 153 for (filter = so->so_filt; filter && (error == 0);
91447636
A
154 filter = filter->sfe_next_onsocket) {
155 if (filter->sfe_filter->sf_filter.sf_data_in) {
156 if (filtered == 0) {
157 filtered = 1;
158 sflt_use(so);
159 socket_unlock(so, 0);
160 }
161 error = filter->sfe_filter->sf_filter.sf_data_in(
162 filter->sfe_cookie, so, from, data, control, flags);
163 }
164 }
165
166 if (filtered != 0) {
167 socket_lock(so, 0);
168 sflt_unuse(so);
169 }
170
171 return error;
172}
173
174/* sflt_attach_private
175 *
176 * Assumptions: If filter is not NULL, socket_filter_lock is held.
177 */
178
179__private_extern__ int
180sflt_attach_private(
181 struct socket *so,
182 struct socket_filter *filter,
183 sflt_handle handle,
184 int sock_locked)
185{
186 struct socket_filter_entry *entry = NULL;
187 int didlock = 0;
188 int error = 0;
189
190 if (filter == NULL) {
191 /* Find the filter by the handle */
192 lck_mtx_lock(sock_filter_lock);
193 didlock = 1;
194
195 TAILQ_FOREACH(filter, &sock_filter_head, sf_global_next) {
196 if (filter->sf_filter.sf_handle == handle)
197 break;
198 }
199 }
200
201 if (filter == NULL)
202 error = ENOENT;
203
204 if (error == 0) {
205 /* allocate the socket filter entry */
206 MALLOC(entry, struct socket_filter_entry *, sizeof(*entry), M_IFADDR, M_WAITOK);
207 if (entry == NULL) {
208 error = ENOMEM;
209 }
210 }
211
212 if (error == 0) {
213 /* Initialize the socket filter entry and call the attach function */
214 entry->sfe_filter = filter;
215 entry->sfe_socket = so;
216 entry->sfe_cookie = NULL;
217 if (entry->sfe_filter->sf_filter.sf_attach) {
218 filter->sf_usecount++;
219
220 if (sock_locked)
221 socket_unlock(so, 0);
222 error = entry->sfe_filter->sf_filter.sf_attach(&entry->sfe_cookie, so);
223 if (sock_locked)
224 socket_lock(so, 0);
225
226 filter->sf_usecount--;
227
228 /* If the attach function returns an error, this filter is not attached */
229 if (error) {
230 FREE(entry, M_IFADDR);
231 entry = NULL;
232 }
233 }
234 }
235
236 if (error == 0) {
237 /* Put the entry in the socket list */
238 entry->sfe_next_onsocket = so->so_filt;
239 so->so_filt = entry;
240
241 /* Put the entry in the filter list */
242 entry->sfe_next_onfilter = filter->sf_entry_head;
243 filter->sf_entry_head = entry;
244
245 /* Increment the socket's usecount */
246 so->so_usecount++;
247
248 /* Incremenet the parent filter's usecount */
249 filter->sf_usecount++;
250 }
251
252 if (didlock) {
253 lck_mtx_unlock(sock_filter_lock);
254 }
255
256 return error;
257}
258
259
260/* sflt_detach_private
261 *
262 * Assumptions: if you pass 0 in for the second parameter, you are holding the
263 * socket lock for the socket the entry is attached to. If you pass 1 in for
264 * the second parameter, it is assumed that the entry is not on the filter's
265 * list and the socket lock is not held.
266 */
267
268__private_extern__ void
269sflt_detach_private(
270 struct socket_filter_entry *entry,
271 int filter_detached)
272{
273 struct socket *so = entry->sfe_socket;
274 struct socket_filter_entry **next_ptr;
275 int detached = 0;
276 int found = 0;
277
278 if (filter_detached) {
279 socket_lock(entry->sfe_socket, 0);
280 }
281
282 /*
283 * Attempt to find the entry on the filter's list and
284 * remove it. This prevents a filter detaching at the
285 * same time from attempting to remove the same entry.
286 */
287 lck_mtx_lock(sock_filter_lock);
288 if (!filter_detached) {
289 for (next_ptr = &entry->sfe_filter->sf_entry_head; *next_ptr;
290 next_ptr = &((*next_ptr)->sfe_next_onfilter)) {
291 if (*next_ptr == entry) {
292 found = 1;
293 *next_ptr = entry->sfe_next_onfilter;
294 break;
295 }
296 }
297 }
298
299 if (!filter_detached && !found && (entry->sfe_flags & SFEF_DETACHING) == 0) {
300 lck_mtx_unlock(sock_filter_lock);
301 return;
302 }
303
304 if (entry->sfe_socket->so_filteruse != 0) {
305 lck_mtx_unlock(sock_filter_lock);
306 entry->sfe_flags |= SFEF_DETACHING;
307 return;
308 }
309
310 /*
311 * Check if we are removing the last attached filter and
312 * the parent filter is being unregistered.
313 */
314 if (entry->sfe_socket->so_filteruse == 0) {
315 entry->sfe_filter->sf_usecount--;
316 if ((entry->sfe_filter->sf_usecount == 0) &&
317 (entry->sfe_filter->sf_flags & SFF_DETACHING) != 0)
318 detached = 1;
319 }
320 lck_mtx_unlock(sock_filter_lock);
321
322 /* Remove from the socket list */
323 for (next_ptr = &entry->sfe_socket->so_filt; *next_ptr;
324 next_ptr = &((*next_ptr)->sfe_next_onsocket)) {
325 if (*next_ptr == entry) {
326 *next_ptr = entry->sfe_next_onsocket;
327 break;
328 }
329 }
330
331 if (entry->sfe_filter->sf_filter.sf_detach)
332 entry->sfe_filter->sf_filter.sf_detach(entry->sfe_cookie, entry->sfe_socket);
333
334 if (detached && entry->sfe_filter->sf_filter.sf_unregistered) {
335 entry->sfe_filter->sf_filter.sf_unregistered(entry->sfe_filter->sf_filter.sf_handle);
336 FREE(entry->sfe_filter, M_IFADDR);
337 }
338
339 if (filter_detached) {
340 socket_unlock(entry->sfe_socket, 1);
341 }
342 else {
343 // We need some better way to decrement the usecount
344 so->so_usecount--;
345 }
346 FREE(entry, M_IFADDR);
347}
348
349errno_t
350sflt_attach(
351 socket_t socket,
352 sflt_handle handle)
353{
354 if (socket == NULL || handle == 0)
355 return EINVAL;
356
357 return sflt_attach_private(socket, NULL, handle, 0);
358}
359
360errno_t
361sflt_detach(
362 socket_t socket,
363 sflt_handle handle)
364{
365 struct socket_filter_entry *filter;
366 errno_t result = 0;
367
368 if (socket == NULL || handle == 0)
369 return EINVAL;
370
371 socket_lock(socket, 1);
372
373 for (filter = socket->so_filt; filter;
374 filter = filter->sfe_next_onsocket) {
375 if (filter->sfe_filter->sf_filter.sf_handle == handle)
376 break;
377 }
378
379 if (filter != NULL) {
380 sflt_detach_private(filter, 0);
381 }
382 else {
383 result = ENOENT;
384 }
385
386 socket_unlock(socket, 1);
387
388 return result;
389}
390
391
392errno_t
393sflt_register(
394 const struct sflt_filter *filter,
395 int domain,
396 int type,
397 int protocol)
398{
399 struct socket_filter *sock_filt = NULL;
400 struct socket_filter *match = NULL;
401 int error = 0;
402 struct protosw *pr = pffindproto(domain, protocol, type);
403
404 if (pr == NULL) return ENOENT;
405
406 if (filter->sf_attach == NULL || filter->sf_detach == NULL) return EINVAL;
407 if (filter->sf_handle == 0) return EINVAL;
408 if (filter->sf_name == NULL) return EINVAL;
409
410 /* Allocate the socket filter */
411 MALLOC(sock_filt, struct socket_filter*, sizeof(*sock_filt), M_IFADDR, M_WAITOK);
412 if (sock_filt == NULL) {
413 return ENOBUFS;
414 }
415
416 bzero(sock_filt, sizeof(*sock_filt));
417 sock_filt->sf_filter = *filter;
418
419 lck_mtx_lock(sock_filter_lock);
420 /* Look for an existing entry */
421 TAILQ_FOREACH(match, &sock_filter_head, sf_global_next) {
422 if (match->sf_filter.sf_handle == sock_filt->sf_filter.sf_handle) {
423 break;
424 }
425 }
426
427 /* Add the entry only if there was no existing entry */
428 if (match == NULL) {
429 TAILQ_INSERT_TAIL(&sock_filter_head, sock_filt, sf_global_next);
430 if ((sock_filt->sf_filter.sf_flags & SFLT_GLOBAL) != 0) {
431 TAILQ_INSERT_TAIL(&pr->pr_filter_head, sock_filt, sf_protosw_next);
432 sock_filt->sf_proto = pr;
433 }
434 }
435 lck_mtx_unlock(sock_filter_lock);
436
437 if (match != NULL) {
438 FREE(sock_filt, M_IFADDR);
439 return EEXIST;
440 }
441
442 return error;
443}
444
445errno_t
446sflt_unregister(
447 sflt_handle handle)
448{
449 struct socket_filter *filter;
450 struct socket_filter_entry *entry_head = NULL;
451
452 /* Find the entry and remove it from the global and protosw lists */
453 lck_mtx_lock(sock_filter_lock);
454 TAILQ_FOREACH(filter, &sock_filter_head, sf_global_next) {
455 if (filter->sf_filter.sf_handle == handle)
456 break;
457 }
458
459 if (filter) {
460 TAILQ_REMOVE(&sock_filter_head, filter, sf_global_next);
461 if ((filter->sf_filter.sf_flags & SFLT_GLOBAL) != 0) {
462 TAILQ_REMOVE(&filter->sf_proto->pr_filter_head, filter, sf_protosw_next);
463 }
464 entry_head = filter->sf_entry_head;
465 filter->sf_entry_head = NULL;
466 filter->sf_flags |= SFF_DETACHING;
467 }
468
469 lck_mtx_unlock(sock_filter_lock);
470
471 if (filter == NULL)
472 return ENOENT;
473
474 /* We need to detach the filter from any sockets it's attached to */
475 if (entry_head == 0) {
476 if (filter->sf_filter.sf_unregistered)
477 filter->sf_filter.sf_unregistered(filter->sf_filter.sf_handle);
478 } else {
479 while (entry_head) {
480 struct socket_filter_entry *next_entry;
481 next_entry = entry_head->sfe_next_onfilter;
482 sflt_detach_private(entry_head, 1);
483 entry_head = next_entry;
484 }
485 }
486
487 return 0;
488}
489
490errno_t
491sock_inject_data_in(
492 socket_t so,
493 const struct sockaddr* from,
494 mbuf_t data,
495 mbuf_t control,
496 sflt_data_flag_t flags)
497{
498 int error = 0;
499 if (so == NULL || data == NULL) return EINVAL;
500
501 if (flags & sock_data_filt_flag_oob) {
502 return ENOTSUP;
503 }
504
505 socket_lock(so, 1);
506
507 if (from) {
508 if (sbappendaddr(&so->so_rcv, (struct sockaddr*)from, data,
509 control, NULL))
510 sorwakeup(so);
511 goto done;
512 }
513
514 if (control) {
515 if (sbappendcontrol(&so->so_rcv, data, control, NULL))
516 sorwakeup(so);
517 goto done;
518 }
519
520 if (flags & sock_data_filt_flag_record) {
521 if (control || from) {
522 error = EINVAL;
523 goto done;
524 }
525 if (sbappendrecord(&so->so_rcv, (struct mbuf*)data))
526 sorwakeup(so);
527 goto done;
528 }
529
530 if (sbappend(&so->so_rcv, data))
531 sorwakeup(so);
532done:
533 socket_unlock(so, 1);
534 return error;
535}
536
537errno_t
538sock_inject_data_out(
539 socket_t so,
540 const struct sockaddr* to,
541 mbuf_t data,
542 mbuf_t control,
543 sflt_data_flag_t flags)
544{
545 int sosendflags = 0;
546 if (flags & sock_data_filt_flag_oob) sosendflags = MSG_OOB;
547 return sosend(so, (const struct sockaddr*)to, NULL,
548 data, control, sosendflags);
549}
550
551sockopt_dir
552sockopt_direction(
553 sockopt_t sopt)
554{
555 return (sopt->sopt_dir == SOPT_GET) ? sockopt_get : sockopt_set;
556}
557
558int
559sockopt_level(
560 sockopt_t sopt)
561{
562 return sopt->sopt_level;
563}
564
565int
566sockopt_name(
567 sockopt_t sopt)
568{
569 return sopt->sopt_name;
570}
571
572size_t
573sockopt_valsize(
574 sockopt_t sopt)
575{
576 return sopt->sopt_valsize;
577}
578
579errno_t
580sockopt_copyin(
581 sockopt_t sopt,
582 void *data,
583 size_t len)
584{
585 return sooptcopyin(sopt, data, len, len);
586}
587
588errno_t
589sockopt_copyout(
590 sockopt_t sopt,
591 void *data,
592 size_t len)
593{
594 return sooptcopyout(sopt, data, len);
595}