1 /* $NetBSD: pfil.c,v 1.26 2008/06/23 00:56:08 dyoung Exp $ */
4 * Copyright (c) 1996 Matthew R. Green
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: pfil.c,v 1.26 2008/06/23 00:56:08 dyoung Exp $");
32 #include <sys/param.h>
33 #include <sys/errno.h>
34 #include <sys/malloc.h>
35 #include <sys/socket.h>
36 #include <sys/socketvar.h>
37 #include <sys/systm.h>
39 #include <sys/queue.h>
44 static int pfil_list_add(pfil_list_t
*,
45 int (*)(void *, struct mbuf
**, struct ifnet
*, int), void *, int);
47 static int pfil_list_remove(pfil_list_t
*,
48 int (*)(void *, struct mbuf
**, struct ifnet
*, int), void *);
50 LIST_HEAD(, pfil_head
) pfil_head_list
=
51 LIST_HEAD_INITIALIZER(&pfil_head_list
);
54 * pfil_run_hooks() runs the specified packet filter hooks.
57 pfil_run_hooks(struct pfil_head
*ph
, struct mbuf
**mp
, struct ifnet
*ifp
,
60 struct packet_filter_hook
*pfh
;
61 struct mbuf
*m
= NULL
;
64 if ((dir
& PFIL_ALL
) && mp
)
66 for (pfh
= pfil_hook_get(dir
, ph
); pfh
!= NULL
;
67 pfh
= TAILQ_NEXT(pfh
, pfil_link
)) {
68 if (pfh
->pfil_func
!= NULL
) {
69 if (pfh
->pfil_flags
& PFIL_ALL
) {
70 rv
= (*pfh
->pfil_func
)(pfh
->pfil_arg
, &m
, ifp
,
72 if (rv
!= 0 || m
== NULL
)
75 rv
= (*pfh
->pfil_func
)(pfh
->pfil_arg
, mp
, ifp
,
83 if ((dir
& PFIL_ALL
) && mp
)
89 * pfil_head_register() registers a pfil_head with the packet filter
93 pfil_head_register(struct pfil_head
*ph
)
95 struct pfil_head
*lph
;
97 LIST_FOREACH(lph
, &pfil_head_list
, ph_list
) {
98 if (ph
->ph_type
== lph
->ph_type
&&
99 ph
->ph_un
.phu_val
== lph
->ph_un
.phu_val
)
103 TAILQ_INIT(&ph
->ph_in
);
104 TAILQ_INIT(&ph
->ph_out
);
105 TAILQ_INIT(&ph
->ph_ifaddr
);
106 TAILQ_INIT(&ph
->ph_ifnetevent
);
108 LIST_INSERT_HEAD(&pfil_head_list
, ph
, ph_list
);
114 * pfil_head_unregister() removes a pfil_head from the packet filter
118 pfil_head_unregister(struct pfil_head
*pfh
)
121 LIST_REMOVE(pfh
, ph_list
);
126 * pfil_head_get() returns the pfil_head for a given key/dlt.
129 pfil_head_get(int type
, u_long val
)
131 struct pfil_head
*ph
;
133 LIST_FOREACH(ph
, &pfil_head_list
, ph_list
) {
134 if (ph
->ph_type
== type
&& ph
->ph_un
.phu_val
== val
)
142 * pfil_add_hook() adds a function to the packet filter hook. the
144 * PFIL_IN call me on incoming packets
145 * PFIL_OUT call me on outgoing packets
146 * PFIL_ALL call me on all of the above
147 * PFIL_IFADDR call me on interface reconfig (mbuf ** is ioctl #)
148 * PFIL_IFNET call me on interface attach/detach
149 * (mbuf ** is PFIL_IFNET_*)
150 * PFIL_WAITOK OK to call malloc with M_WAITOK.
153 pfil_add_hook(int (*func
)(void *, struct mbuf
**, struct ifnet
*, int),
154 void *arg
, int flags
, struct pfil_head
*ph
)
158 if (flags
& PFIL_IN
) {
159 err
= pfil_list_add(&ph
->ph_in
, func
, arg
, flags
& ~PFIL_OUT
);
163 if (flags
& PFIL_OUT
) {
164 err
= pfil_list_add(&ph
->ph_out
, func
, arg
, flags
& ~PFIL_IN
);
167 pfil_list_remove(&ph
->ph_in
, func
, arg
);
171 if (flags
& PFIL_IFADDR
) {
172 err
= pfil_list_add(&ph
->ph_ifaddr
, func
, arg
, flags
);
175 pfil_list_remove(&ph
->ph_in
, func
, arg
);
176 if (flags
& PFIL_OUT
)
177 pfil_list_remove(&ph
->ph_out
, func
, arg
);
181 if (flags
& PFIL_IFNET
) {
182 err
= pfil_list_add(&ph
->ph_ifnetevent
, func
, arg
, flags
);
185 pfil_list_remove(&ph
->ph_in
, func
, arg
);
186 if (flags
& PFIL_OUT
)
187 pfil_list_remove(&ph
->ph_out
, func
, arg
);
188 if (flags
& PFIL_IFADDR
)
189 pfil_list_remove(&ph
->ph_ifaddr
, func
, arg
);
197 pfil_list_add(pfil_list_t
*list
,
198 int (*func
)(void *, struct mbuf
**, struct ifnet
*, int), void *arg
,
201 struct packet_filter_hook
*pfh
;
204 * First make sure the hook is not already there.
206 TAILQ_FOREACH(pfh
, list
, pfil_link
) {
207 if (pfh
->pfil_func
== func
&& pfh
->pfil_arg
== arg
)
211 pfh
= (struct packet_filter_hook
*)malloc(sizeof(*pfh
), M_IFADDR
,
212 (flags
& PFIL_WAITOK
) ? M_WAITOK
: M_NOWAIT
);
216 pfh
->pfil_func
= func
;
218 pfh
->pfil_flags
= flags
;
221 * insert the input list in reverse order of the output list
222 * so that the same path is followed in or out of the kernel.
225 TAILQ_INSERT_HEAD(list
, pfh
, pfil_link
);
227 TAILQ_INSERT_TAIL(list
, pfh
, pfil_link
);
233 * pfil_remove_hook removes a specific function from the packet filter
237 pfil_remove_hook(int (*func
)(void *, struct mbuf
**, struct ifnet
*, int),
238 void *arg
, int flags
, struct pfil_head
*ph
)
243 err
= pfil_list_remove(&ph
->ph_in
, func
, arg
);
244 if ((err
== 0) && (flags
& PFIL_OUT
))
245 err
= pfil_list_remove(&ph
->ph_out
, func
, arg
);
246 if ((err
== 0) && (flags
& PFIL_IFADDR
))
247 err
= pfil_list_remove(&ph
->ph_ifaddr
, func
, arg
);
248 if ((err
== 0) && (flags
& PFIL_IFNET
))
249 err
= pfil_list_remove(&ph
->ph_ifnetevent
, func
, arg
);
254 * pfil_list_remove is an internal function that takes a function off the
258 pfil_list_remove(pfil_list_t
*list
,
259 int (*func
)(void *, struct mbuf
**, struct ifnet
*, int), void *arg
)
261 struct packet_filter_hook
*pfh
;
263 TAILQ_FOREACH(pfh
, list
, pfil_link
) {
264 if (pfh
->pfil_func
== func
&& pfh
->pfil_arg
== arg
) {
265 TAILQ_REMOVE(list
, pfh
, pfil_link
);