Deleted Added
full compact
ng_bpf.c (68876) ng_bpf.c (69922)
1
2/*
3 * ng_bpf.c
4 *
5 * Copyright (c) 1999 Whistle Communications, Inc.
6 * All rights reserved.
7 *
8 * Subject to the following obligations and disclaimer of warranty, use and
9 * redistribution of this software, in source or object code forms, with or
10 * without modifications are expressly permitted by Whistle Communications;
11 * provided, however, that:
12 * 1. Any and all reproductions of the source or object code must include the
13 * copyright notice above and the following disclaimer of warranties; and
14 * 2. No rights are granted, in any manner or form, to use Whistle
15 * Communications, Inc. trademarks, including the mark "WHISTLE
16 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
17 * such appears in the above copyright notice or in the software.
18 *
19 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
20 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
21 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
22 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
24 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANBPF, OR MAKE ANY
25 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
26 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
27 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
28 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
29 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
30 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
35 * OF SUCH DAMAGE.
36 *
37 * Author: Archie Cobbs <archie@freebsd.org>
38 *
1
2/*
3 * ng_bpf.c
4 *
5 * Copyright (c) 1999 Whistle Communications, Inc.
6 * All rights reserved.
7 *
8 * Subject to the following obligations and disclaimer of warranty, use and
9 * redistribution of this software, in source or object code forms, with or
10 * without modifications are expressly permitted by Whistle Communications;
11 * provided, however, that:
12 * 1. Any and all reproductions of the source or object code must include the
13 * copyright notice above and the following disclaimer of warranties; and
14 * 2. No rights are granted, in any manner or form, to use Whistle
15 * Communications, Inc. trademarks, including the mark "WHISTLE
16 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
17 * such appears in the above copyright notice or in the software.
18 *
19 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
20 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
21 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
22 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
24 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANBPF, OR MAKE ANY
25 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
26 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
27 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
28 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
29 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
30 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
35 * OF SUCH DAMAGE.
36 *
37 * Author: Archie Cobbs <archie@freebsd.org>
38 *
39 * $FreeBSD: head/sys/netgraph/ng_bpf.c 68876 2000-11-18 15:17:43Z dwmalone $
39 * $FreeBSD: head/sys/netgraph/ng_bpf.c 69922 2000-12-12 18:52:14Z julian $
40 * $Whistle: ng_bpf.c,v 1.3 1999/12/03 20:30:23 archie Exp $
41 */
42
43/*
44 * BPF NETGRAPH NODE TYPE
45 *
46 * This node type accepts any number of hook connections. With each hook
47 * is associated a bpf(4) filter program, and two hook names (each possibly
48 * the empty string). Incoming packets are compared against the filter;
49 * matching packets are delivered out the first named hook (or dropped if
50 * the empty string), and non-matching packets are delivered out the second
51 * named hook (or dropped if the empty string).
52 *
53 * Each hook also keeps statistics about how many packets have matched, etc.
54 */
55
56#include <sys/param.h>
57#include <sys/systm.h>
58#include <sys/errno.h>
59#include <sys/kernel.h>
60#include <sys/malloc.h>
61#include <sys/mbuf.h>
62
63#include <net/bpf.h>
64
65#include <netgraph/ng_message.h>
66#include <netgraph/netgraph.h>
67#include <netgraph/ng_parse.h>
68#include <netgraph/ng_bpf.h>
69
70#define OFFSETOF(s, e) ((char *)&((s *)0)->e - (char *)((s *)0))
71
72#define ERROUT(x) do { error = (x); goto done; } while (0)
73
74/* Per hook private info */
75struct ng_bpf_hookinfo {
76 node_p node;
77 hook_p hook;
78 struct ng_bpf_hookprog *prog;
79 struct ng_bpf_hookstat stats;
80};
81typedef struct ng_bpf_hookinfo *hinfo_p;
82
83/* Netgraph methods */
84static ng_constructor_t ng_bpf_constructor;
85static ng_rcvmsg_t ng_bpf_rcvmsg;
86static ng_shutdown_t ng_bpf_rmnode;
87static ng_newhook_t ng_bpf_newhook;
88static ng_rcvdata_t ng_bpf_rcvdata;
89static ng_disconnect_t ng_bpf_disconnect;
90
91/* Internal helper functions */
92static int ng_bpf_setprog(hook_p hook, const struct ng_bpf_hookprog *hp);
93
94/* Parse type for one struct bfp_insn */
95static const struct ng_parse_struct_info ng_bpf_insn_type_info = {
96 {
97 { "code", &ng_parse_hint16_type },
98 { "jt", &ng_parse_uint8_type },
99 { "jf", &ng_parse_uint8_type },
100 { "k", &ng_parse_uint32_type },
101 { NULL }
102 }
103};
104static const struct ng_parse_type ng_bpf_insn_type = {
105 &ng_parse_struct_type,
106 &ng_bpf_insn_type_info
107};
108
109/* Parse type for the field 'bpf_prog' in struct ng_bpf_hookprog */
110static int
111ng_bpf_hookprogary_getLength(const struct ng_parse_type *type,
112 const u_char *start, const u_char *buf)
113{
114 const struct ng_bpf_hookprog *hp;
115
116 hp = (const struct ng_bpf_hookprog *)
117 (buf - OFFSETOF(struct ng_bpf_hookprog, bpf_prog));
118 return hp->bpf_prog_len;
119}
120
121static const struct ng_parse_array_info ng_bpf_hookprogary_info = {
122 &ng_bpf_insn_type,
123 &ng_bpf_hookprogary_getLength,
124 NULL
125};
126static const struct ng_parse_type ng_bpf_hookprogary_type = {
127 &ng_parse_array_type,
128 &ng_bpf_hookprogary_info
129};
130
131/* Parse type for struct ng_bpf_hookprog */
132static const struct ng_parse_struct_info ng_bpf_hookprog_type_info
133 = NG_BPF_HOOKPROG_TYPE_INFO(&ng_bpf_hookprogary_type);
134static const struct ng_parse_type ng_bpf_hookprog_type = {
135 &ng_parse_struct_type,
136 &ng_bpf_hookprog_type_info
137};
138
139/* Parse type for struct ng_bpf_hookstat */
140static const struct ng_parse_struct_info
141 ng_bpf_hookstat_type_info = NG_BPF_HOOKSTAT_TYPE_INFO;
142static const struct ng_parse_type ng_bpf_hookstat_type = {
143 &ng_parse_struct_type,
144 &ng_bpf_hookstat_type_info
145};
146
147/* List of commands and how to convert arguments to/from ASCII */
148static const struct ng_cmdlist ng_bpf_cmdlist[] = {
149 {
150 NGM_BPF_COOKIE,
151 NGM_BPF_SET_PROGRAM,
152 "setprogram",
153 &ng_bpf_hookprog_type,
154 NULL
155 },
156 {
157 NGM_BPF_COOKIE,
158 NGM_BPF_GET_PROGRAM,
159 "getprogram",
160 &ng_parse_hookbuf_type,
161 &ng_bpf_hookprog_type
162 },
163 {
164 NGM_BPF_COOKIE,
165 NGM_BPF_GET_STATS,
166 "getstats",
167 &ng_parse_hookbuf_type,
168 &ng_bpf_hookstat_type
169 },
170 {
171 NGM_BPF_COOKIE,
172 NGM_BPF_CLR_STATS,
173 "clrstats",
174 &ng_parse_hookbuf_type,
175 NULL
176 },
177 {
178 NGM_BPF_COOKIE,
179 NGM_BPF_GETCLR_STATS,
180 "getclrstats",
181 &ng_parse_hookbuf_type,
182 &ng_bpf_hookstat_type
183 },
184 { 0 }
185};
186
187/* Netgraph type descriptor */
188static struct ng_type typestruct = {
189 NG_VERSION,
190 NG_BPF_NODE_TYPE,
191 NULL,
192 ng_bpf_constructor,
193 ng_bpf_rcvmsg,
194 ng_bpf_rmnode,
195 ng_bpf_newhook,
196 NULL,
197 NULL,
198 ng_bpf_rcvdata,
40 * $Whistle: ng_bpf.c,v 1.3 1999/12/03 20:30:23 archie Exp $
41 */
42
43/*
44 * BPF NETGRAPH NODE TYPE
45 *
46 * This node type accepts any number of hook connections. With each hook
47 * is associated a bpf(4) filter program, and two hook names (each possibly
48 * the empty string). Incoming packets are compared against the filter;
49 * matching packets are delivered out the first named hook (or dropped if
50 * the empty string), and non-matching packets are delivered out the second
51 * named hook (or dropped if the empty string).
52 *
53 * Each hook also keeps statistics about how many packets have matched, etc.
54 */
55
56#include <sys/param.h>
57#include <sys/systm.h>
58#include <sys/errno.h>
59#include <sys/kernel.h>
60#include <sys/malloc.h>
61#include <sys/mbuf.h>
62
63#include <net/bpf.h>
64
65#include <netgraph/ng_message.h>
66#include <netgraph/netgraph.h>
67#include <netgraph/ng_parse.h>
68#include <netgraph/ng_bpf.h>
69
70#define OFFSETOF(s, e) ((char *)&((s *)0)->e - (char *)((s *)0))
71
72#define ERROUT(x) do { error = (x); goto done; } while (0)
73
74/* Per hook private info */
75struct ng_bpf_hookinfo {
76 node_p node;
77 hook_p hook;
78 struct ng_bpf_hookprog *prog;
79 struct ng_bpf_hookstat stats;
80};
81typedef struct ng_bpf_hookinfo *hinfo_p;
82
83/* Netgraph methods */
84static ng_constructor_t ng_bpf_constructor;
85static ng_rcvmsg_t ng_bpf_rcvmsg;
86static ng_shutdown_t ng_bpf_rmnode;
87static ng_newhook_t ng_bpf_newhook;
88static ng_rcvdata_t ng_bpf_rcvdata;
89static ng_disconnect_t ng_bpf_disconnect;
90
91/* Internal helper functions */
92static int ng_bpf_setprog(hook_p hook, const struct ng_bpf_hookprog *hp);
93
94/* Parse type for one struct bfp_insn */
95static const struct ng_parse_struct_info ng_bpf_insn_type_info = {
96 {
97 { "code", &ng_parse_hint16_type },
98 { "jt", &ng_parse_uint8_type },
99 { "jf", &ng_parse_uint8_type },
100 { "k", &ng_parse_uint32_type },
101 { NULL }
102 }
103};
104static const struct ng_parse_type ng_bpf_insn_type = {
105 &ng_parse_struct_type,
106 &ng_bpf_insn_type_info
107};
108
109/* Parse type for the field 'bpf_prog' in struct ng_bpf_hookprog */
110static int
111ng_bpf_hookprogary_getLength(const struct ng_parse_type *type,
112 const u_char *start, const u_char *buf)
113{
114 const struct ng_bpf_hookprog *hp;
115
116 hp = (const struct ng_bpf_hookprog *)
117 (buf - OFFSETOF(struct ng_bpf_hookprog, bpf_prog));
118 return hp->bpf_prog_len;
119}
120
121static const struct ng_parse_array_info ng_bpf_hookprogary_info = {
122 &ng_bpf_insn_type,
123 &ng_bpf_hookprogary_getLength,
124 NULL
125};
126static const struct ng_parse_type ng_bpf_hookprogary_type = {
127 &ng_parse_array_type,
128 &ng_bpf_hookprogary_info
129};
130
131/* Parse type for struct ng_bpf_hookprog */
132static const struct ng_parse_struct_info ng_bpf_hookprog_type_info
133 = NG_BPF_HOOKPROG_TYPE_INFO(&ng_bpf_hookprogary_type);
134static const struct ng_parse_type ng_bpf_hookprog_type = {
135 &ng_parse_struct_type,
136 &ng_bpf_hookprog_type_info
137};
138
139/* Parse type for struct ng_bpf_hookstat */
140static const struct ng_parse_struct_info
141 ng_bpf_hookstat_type_info = NG_BPF_HOOKSTAT_TYPE_INFO;
142static const struct ng_parse_type ng_bpf_hookstat_type = {
143 &ng_parse_struct_type,
144 &ng_bpf_hookstat_type_info
145};
146
147/* List of commands and how to convert arguments to/from ASCII */
148static const struct ng_cmdlist ng_bpf_cmdlist[] = {
149 {
150 NGM_BPF_COOKIE,
151 NGM_BPF_SET_PROGRAM,
152 "setprogram",
153 &ng_bpf_hookprog_type,
154 NULL
155 },
156 {
157 NGM_BPF_COOKIE,
158 NGM_BPF_GET_PROGRAM,
159 "getprogram",
160 &ng_parse_hookbuf_type,
161 &ng_bpf_hookprog_type
162 },
163 {
164 NGM_BPF_COOKIE,
165 NGM_BPF_GET_STATS,
166 "getstats",
167 &ng_parse_hookbuf_type,
168 &ng_bpf_hookstat_type
169 },
170 {
171 NGM_BPF_COOKIE,
172 NGM_BPF_CLR_STATS,
173 "clrstats",
174 &ng_parse_hookbuf_type,
175 NULL
176 },
177 {
178 NGM_BPF_COOKIE,
179 NGM_BPF_GETCLR_STATS,
180 "getclrstats",
181 &ng_parse_hookbuf_type,
182 &ng_bpf_hookstat_type
183 },
184 { 0 }
185};
186
187/* Netgraph type descriptor */
188static struct ng_type typestruct = {
189 NG_VERSION,
190 NG_BPF_NODE_TYPE,
191 NULL,
192 ng_bpf_constructor,
193 ng_bpf_rcvmsg,
194 ng_bpf_rmnode,
195 ng_bpf_newhook,
196 NULL,
197 NULL,
198 ng_bpf_rcvdata,
199 ng_bpf_rcvdata,
200 ng_bpf_disconnect,
201 ng_bpf_cmdlist
202};
203NETGRAPH_INIT(bpf, &typestruct);
204
205/* Default BPF program for a hook that matches nothing */
206static const struct ng_bpf_hookprog ng_bpf_default_prog = {
207 { '\0' }, /* to be filled in at hook creation time */
208 { '\0' },
209 { '\0' },
210 1,
211 { BPF_STMT(BPF_RET+BPF_K, 0) }
212};
213
214/*
215 * Node constructor
216 *
217 * We don't keep any per-node private data
218 */
219static int
220ng_bpf_constructor(node_p *nodep)
221{
222 int error = 0;
223
224 if ((error = ng_make_node_common(&typestruct, nodep)))
225 return (error);
226 (*nodep)->private = NULL;
227 return (0);
228}
229
230/*
231 * Add a hook
232 */
233static int
234ng_bpf_newhook(node_p node, hook_p hook, const char *name)
235{
236 hinfo_p hip;
237 int error;
238
239 /* Create hook private structure */
240 MALLOC(hip, hinfo_p, sizeof(*hip), M_NETGRAPH, M_NOWAIT | M_ZERO);
241 if (hip == NULL)
242 return (ENOMEM);
243 hip->hook = hook;
244 hook->private = hip;
245 hip->node = node;
246
247 /* Attach the default BPF program */
248 if ((error = ng_bpf_setprog(hook, &ng_bpf_default_prog)) != 0) {
249 FREE(hip, M_NETGRAPH);
250 hook->private = NULL;
251 return (error);
252 }
253
254 /* Set hook name */
255 strncpy(hip->prog->thisHook, name, sizeof(hip->prog->thisHook) - 1);
256 hip->prog->thisHook[sizeof(hip->prog->thisHook) - 1] = '\0';
257 return (0);
258}
259
260/*
261 * Receive a control message
262 */
263static int
264ng_bpf_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr,
265 struct ng_mesg **rptr, hook_p lasthook)
266{
267 struct ng_mesg *resp = NULL;
268 int error = 0;
269
270 switch (msg->header.typecookie) {
271 case NGM_BPF_COOKIE:
272 switch (msg->header.cmd) {
273 case NGM_BPF_SET_PROGRAM:
274 {
275 struct ng_bpf_hookprog *const
276 hp = (struct ng_bpf_hookprog *)msg->data;
277 hook_p hook;
278
279 /* Sanity check */
280 if (msg->header.arglen < sizeof(*hp)
281 || msg->header.arglen
282 != NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len))
283 ERROUT(EINVAL);
284
285 /* Find hook */
286 if ((hook = ng_findhook(node, hp->thisHook)) == NULL)
287 ERROUT(ENOENT);
288
289 /* Set new program */
290 if ((error = ng_bpf_setprog(hook, hp)) != 0)
291 ERROUT(error);
292 break;
293 }
294
295 case NGM_BPF_GET_PROGRAM:
296 {
297 struct ng_bpf_hookprog *hp;
298 hook_p hook;
299
300 /* Sanity check */
301 if (msg->header.arglen == 0)
302 ERROUT(EINVAL);
303 msg->data[msg->header.arglen - 1] = '\0';
304
305 /* Find hook */
306 if ((hook = ng_findhook(node, msg->data)) == NULL)
307 ERROUT(ENOENT);
308
309 /* Build response */
310 hp = ((hinfo_p)hook->private)->prog;
311 NG_MKRESPONSE(resp, msg,
312 NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len), M_NOWAIT);
313 if (resp == NULL)
314 ERROUT(ENOMEM);
315 bcopy(hp, resp->data,
316 NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len));
317 break;
318 }
319
320 case NGM_BPF_GET_STATS:
321 case NGM_BPF_CLR_STATS:
322 case NGM_BPF_GETCLR_STATS:
323 {
324 struct ng_bpf_hookstat *stats;
325 hook_p hook;
326
327 /* Sanity check */
328 if (msg->header.arglen == 0)
329 ERROUT(EINVAL);
330 msg->data[msg->header.arglen - 1] = '\0';
331
332 /* Find hook */
333 if ((hook = ng_findhook(node, msg->data)) == NULL)
334 ERROUT(ENOENT);
335 stats = &((hinfo_p)hook->private)->stats;
336
337 /* Build response (if desired) */
338 if (msg->header.cmd != NGM_BPF_CLR_STATS) {
339 NG_MKRESPONSE(resp,
340 msg, sizeof(*stats), M_NOWAIT);
341 if (resp == NULL)
342 ERROUT(ENOMEM);
343 bcopy(stats, resp->data, sizeof(*stats));
344 }
345
346 /* Clear stats (if desired) */
347 if (msg->header.cmd != NGM_BPF_GET_STATS)
348 bzero(stats, sizeof(*stats));
349 break;
350 }
351
352 default:
353 error = EINVAL;
354 break;
355 }
356 break;
357 default:
358 error = EINVAL;
359 break;
360 }
361 if (rptr)
362 *rptr = resp;
363 else if (resp)
364 FREE(resp, M_NETGRAPH);
365
366done:
367 FREE(msg, M_NETGRAPH);
368 return (error);
369}
370
371/*
372 * Receive data on a hook
373 *
374 * Apply the filter, and then drop or forward packet as appropriate.
375 */
376static int
377ng_bpf_rcvdata(hook_p hook, struct mbuf *m, meta_p meta,
199 ng_bpf_disconnect,
200 ng_bpf_cmdlist
201};
202NETGRAPH_INIT(bpf, &typestruct);
203
204/* Default BPF program for a hook that matches nothing */
205static const struct ng_bpf_hookprog ng_bpf_default_prog = {
206 { '\0' }, /* to be filled in at hook creation time */
207 { '\0' },
208 { '\0' },
209 1,
210 { BPF_STMT(BPF_RET+BPF_K, 0) }
211};
212
213/*
214 * Node constructor
215 *
216 * We don't keep any per-node private data
217 */
218static int
219ng_bpf_constructor(node_p *nodep)
220{
221 int error = 0;
222
223 if ((error = ng_make_node_common(&typestruct, nodep)))
224 return (error);
225 (*nodep)->private = NULL;
226 return (0);
227}
228
229/*
230 * Add a hook
231 */
232static int
233ng_bpf_newhook(node_p node, hook_p hook, const char *name)
234{
235 hinfo_p hip;
236 int error;
237
238 /* Create hook private structure */
239 MALLOC(hip, hinfo_p, sizeof(*hip), M_NETGRAPH, M_NOWAIT | M_ZERO);
240 if (hip == NULL)
241 return (ENOMEM);
242 hip->hook = hook;
243 hook->private = hip;
244 hip->node = node;
245
246 /* Attach the default BPF program */
247 if ((error = ng_bpf_setprog(hook, &ng_bpf_default_prog)) != 0) {
248 FREE(hip, M_NETGRAPH);
249 hook->private = NULL;
250 return (error);
251 }
252
253 /* Set hook name */
254 strncpy(hip->prog->thisHook, name, sizeof(hip->prog->thisHook) - 1);
255 hip->prog->thisHook[sizeof(hip->prog->thisHook) - 1] = '\0';
256 return (0);
257}
258
259/*
260 * Receive a control message
261 */
262static int
263ng_bpf_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr,
264 struct ng_mesg **rptr, hook_p lasthook)
265{
266 struct ng_mesg *resp = NULL;
267 int error = 0;
268
269 switch (msg->header.typecookie) {
270 case NGM_BPF_COOKIE:
271 switch (msg->header.cmd) {
272 case NGM_BPF_SET_PROGRAM:
273 {
274 struct ng_bpf_hookprog *const
275 hp = (struct ng_bpf_hookprog *)msg->data;
276 hook_p hook;
277
278 /* Sanity check */
279 if (msg->header.arglen < sizeof(*hp)
280 || msg->header.arglen
281 != NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len))
282 ERROUT(EINVAL);
283
284 /* Find hook */
285 if ((hook = ng_findhook(node, hp->thisHook)) == NULL)
286 ERROUT(ENOENT);
287
288 /* Set new program */
289 if ((error = ng_bpf_setprog(hook, hp)) != 0)
290 ERROUT(error);
291 break;
292 }
293
294 case NGM_BPF_GET_PROGRAM:
295 {
296 struct ng_bpf_hookprog *hp;
297 hook_p hook;
298
299 /* Sanity check */
300 if (msg->header.arglen == 0)
301 ERROUT(EINVAL);
302 msg->data[msg->header.arglen - 1] = '\0';
303
304 /* Find hook */
305 if ((hook = ng_findhook(node, msg->data)) == NULL)
306 ERROUT(ENOENT);
307
308 /* Build response */
309 hp = ((hinfo_p)hook->private)->prog;
310 NG_MKRESPONSE(resp, msg,
311 NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len), M_NOWAIT);
312 if (resp == NULL)
313 ERROUT(ENOMEM);
314 bcopy(hp, resp->data,
315 NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len));
316 break;
317 }
318
319 case NGM_BPF_GET_STATS:
320 case NGM_BPF_CLR_STATS:
321 case NGM_BPF_GETCLR_STATS:
322 {
323 struct ng_bpf_hookstat *stats;
324 hook_p hook;
325
326 /* Sanity check */
327 if (msg->header.arglen == 0)
328 ERROUT(EINVAL);
329 msg->data[msg->header.arglen - 1] = '\0';
330
331 /* Find hook */
332 if ((hook = ng_findhook(node, msg->data)) == NULL)
333 ERROUT(ENOENT);
334 stats = &((hinfo_p)hook->private)->stats;
335
336 /* Build response (if desired) */
337 if (msg->header.cmd != NGM_BPF_CLR_STATS) {
338 NG_MKRESPONSE(resp,
339 msg, sizeof(*stats), M_NOWAIT);
340 if (resp == NULL)
341 ERROUT(ENOMEM);
342 bcopy(stats, resp->data, sizeof(*stats));
343 }
344
345 /* Clear stats (if desired) */
346 if (msg->header.cmd != NGM_BPF_GET_STATS)
347 bzero(stats, sizeof(*stats));
348 break;
349 }
350
351 default:
352 error = EINVAL;
353 break;
354 }
355 break;
356 default:
357 error = EINVAL;
358 break;
359 }
360 if (rptr)
361 *rptr = resp;
362 else if (resp)
363 FREE(resp, M_NETGRAPH);
364
365done:
366 FREE(msg, M_NETGRAPH);
367 return (error);
368}
369
370/*
371 * Receive data on a hook
372 *
373 * Apply the filter, and then drop or forward packet as appropriate.
374 */
375static int
376ng_bpf_rcvdata(hook_p hook, struct mbuf *m, meta_p meta,
378 struct mbuf **ret_m, meta_p *ret_meta)
377 struct mbuf **ret_m, meta_p *ret_meta, struct ng_mesg **resp)
379{
380 const hinfo_p hip = hook->private;
381 int totlen = m->m_pkthdr.len;
382 int needfree = 0, error = 0;
383 u_char *data, buf[256];
384 hinfo_p dhip;
385 hook_p dest;
386 u_int len;
387
388 /* Update stats on incoming hook */
389 hip->stats.recvFrames++;
390 hip->stats.recvOctets += totlen;
391
392 /* Need to put packet in contiguous memory for bpf */
393 if (m->m_next != NULL) {
394 if (totlen > sizeof(buf)) {
395 MALLOC(data, u_char *, totlen, M_NETGRAPH, M_NOWAIT);
396 if (data == NULL) {
397 NG_FREE_DATA(m, meta);
398 return (ENOMEM);
399 }
400 needfree = 1;
401 } else
402 data = buf;
403 m_copydata(m, 0, totlen, (caddr_t)data);
404 } else
405 data = mtod(m, u_char *);
406
407 /* Run packet through filter */
408 len = bpf_filter(hip->prog->bpf_prog, data, totlen, totlen);
409 if (needfree)
410 FREE(data, M_NETGRAPH);
411
412 /* See if we got a match and find destination hook */
413 if (len > 0) {
414
415 /* Update stats */
416 hip->stats.recvMatchFrames++;
417 hip->stats.recvMatchOctets += totlen;
418
419 /* Truncate packet length if required by the filter */
420 if (len < totlen) {
421 m_adj(m, -(totlen - len));
422 totlen -= len;
423 }
424 dest = ng_findhook(hip->node, hip->prog->ifMatch);
425 } else
426 dest = ng_findhook(hip->node, hip->prog->ifNotMatch);
427 if (dest == NULL) {
428 NG_FREE_DATA(m, meta);
429 return (0);
430 }
431
432 /* Deliver frame out destination hook */
433 dhip = (hinfo_p)dest->private;
434 dhip->stats.xmitOctets += totlen;
435 dhip->stats.xmitFrames++;
436 NG_SEND_DATA(error, dest, m, meta);
437 return (error);
438}
439
440/*
441 * Shutdown processing
442 */
443static int
444ng_bpf_rmnode(node_p node)
445{
446 node->flags |= NG_INVALID;
447 ng_cutlinks(node);
448 ng_unname(node);
449 ng_unref(node);
450 return (0);
451}
452
453/*
454 * Hook disconnection
455 */
456static int
457ng_bpf_disconnect(hook_p hook)
458{
459 const hinfo_p hip = hook->private;
460
461 KASSERT(hip != NULL, ("%s: null info", __FUNCTION__));
462 FREE(hip->prog, M_NETGRAPH);
463 bzero(hip, sizeof(*hip));
464 FREE(hip, M_NETGRAPH);
465 hook->private = NULL; /* for good measure */
466 if (hook->node->numhooks == 0)
467 ng_rmnode(hook->node);
468 return (0);
469}
470
471/************************************************************************
472 HELPER STUFF
473 ************************************************************************/
474
475/*
476 * Set the BPF program associated with a hook
477 */
478static int
479ng_bpf_setprog(hook_p hook, const struct ng_bpf_hookprog *hp0)
480{
481 const hinfo_p hip = hook->private;
482 struct ng_bpf_hookprog *hp;
483 int size;
484
485 /* Check program for validity */
486 if (!bpf_validate(hp0->bpf_prog, hp0->bpf_prog_len))
487 return (EINVAL);
488
489 /* Make a copy of the program */
490 size = NG_BPF_HOOKPROG_SIZE(hp0->bpf_prog_len);
491 MALLOC(hp, struct ng_bpf_hookprog *, size, M_NETGRAPH, M_NOWAIT);
492 if (hp == NULL)
493 return (ENOMEM);
494 bcopy(hp0, hp, size);
495
496 /* Free previous program, if any, and assign new one */
497 if (hip->prog != NULL)
498 FREE(hip->prog, M_NETGRAPH);
499 hip->prog = hp;
500 return (0);
501}
502
378{
379 const hinfo_p hip = hook->private;
380 int totlen = m->m_pkthdr.len;
381 int needfree = 0, error = 0;
382 u_char *data, buf[256];
383 hinfo_p dhip;
384 hook_p dest;
385 u_int len;
386
387 /* Update stats on incoming hook */
388 hip->stats.recvFrames++;
389 hip->stats.recvOctets += totlen;
390
391 /* Need to put packet in contiguous memory for bpf */
392 if (m->m_next != NULL) {
393 if (totlen > sizeof(buf)) {
394 MALLOC(data, u_char *, totlen, M_NETGRAPH, M_NOWAIT);
395 if (data == NULL) {
396 NG_FREE_DATA(m, meta);
397 return (ENOMEM);
398 }
399 needfree = 1;
400 } else
401 data = buf;
402 m_copydata(m, 0, totlen, (caddr_t)data);
403 } else
404 data = mtod(m, u_char *);
405
406 /* Run packet through filter */
407 len = bpf_filter(hip->prog->bpf_prog, data, totlen, totlen);
408 if (needfree)
409 FREE(data, M_NETGRAPH);
410
411 /* See if we got a match and find destination hook */
412 if (len > 0) {
413
414 /* Update stats */
415 hip->stats.recvMatchFrames++;
416 hip->stats.recvMatchOctets += totlen;
417
418 /* Truncate packet length if required by the filter */
419 if (len < totlen) {
420 m_adj(m, -(totlen - len));
421 totlen -= len;
422 }
423 dest = ng_findhook(hip->node, hip->prog->ifMatch);
424 } else
425 dest = ng_findhook(hip->node, hip->prog->ifNotMatch);
426 if (dest == NULL) {
427 NG_FREE_DATA(m, meta);
428 return (0);
429 }
430
431 /* Deliver frame out destination hook */
432 dhip = (hinfo_p)dest->private;
433 dhip->stats.xmitOctets += totlen;
434 dhip->stats.xmitFrames++;
435 NG_SEND_DATA(error, dest, m, meta);
436 return (error);
437}
438
439/*
440 * Shutdown processing
441 */
442static int
443ng_bpf_rmnode(node_p node)
444{
445 node->flags |= NG_INVALID;
446 ng_cutlinks(node);
447 ng_unname(node);
448 ng_unref(node);
449 return (0);
450}
451
452/*
453 * Hook disconnection
454 */
455static int
456ng_bpf_disconnect(hook_p hook)
457{
458 const hinfo_p hip = hook->private;
459
460 KASSERT(hip != NULL, ("%s: null info", __FUNCTION__));
461 FREE(hip->prog, M_NETGRAPH);
462 bzero(hip, sizeof(*hip));
463 FREE(hip, M_NETGRAPH);
464 hook->private = NULL; /* for good measure */
465 if (hook->node->numhooks == 0)
466 ng_rmnode(hook->node);
467 return (0);
468}
469
470/************************************************************************
471 HELPER STUFF
472 ************************************************************************/
473
474/*
475 * Set the BPF program associated with a hook
476 */
477static int
478ng_bpf_setprog(hook_p hook, const struct ng_bpf_hookprog *hp0)
479{
480 const hinfo_p hip = hook->private;
481 struct ng_bpf_hookprog *hp;
482 int size;
483
484 /* Check program for validity */
485 if (!bpf_validate(hp0->bpf_prog, hp0->bpf_prog_len))
486 return (EINVAL);
487
488 /* Make a copy of the program */
489 size = NG_BPF_HOOKPROG_SIZE(hp0->bpf_prog_len);
490 MALLOC(hp, struct ng_bpf_hookprog *, size, M_NETGRAPH, M_NOWAIT);
491 if (hp == NULL)
492 return (ENOMEM);
493 bcopy(hp0, hp, size);
494
495 /* Free previous program, if any, and assign new one */
496 if (hip->prog != NULL)
497 FREE(hip->prog, M_NETGRAPH);
498 hip->prog = hp;
499 return (0);
500}
501