ng_bpf.c revision 64508
1290001Sglebius
2290001Sglebius/*
3290001Sglebius * ng_bpf.c
4290001Sglebius *
5290001Sglebius * Copyright (c) 1999 Whistle Communications, Inc.
6290001Sglebius * All rights reserved.
7290001Sglebius *
8290001Sglebius * Subject to the following obligations and disclaimer of warranty, use and
9294905Sdelphij * redistribution of this software, in source or object code forms, with or
10290001Sglebius * without modifications are expressly permitted by Whistle Communications;
11290001Sglebius * provided, however, that:
12290001Sglebius * 1. Any and all reproductions of the source or object code must include the
13290001Sglebius *    copyright notice above and the following disclaimer of warranties; and
14290001Sglebius * 2. No rights are granted, in any manner or form, to use Whistle
15290001Sglebius *    Communications, Inc. trademarks, including the mark "WHISTLE
16290001Sglebius *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
17290001Sglebius *    such appears in the above copyright notice or in the software.
18290001Sglebius *
19290001Sglebius * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
20290001Sglebius * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
21290001Sglebius * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
22290001Sglebius * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
23290001Sglebius * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
24290001Sglebius * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANBPF, OR MAKE ANY
25290001Sglebius * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
26290001Sglebius * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
27290001Sglebius * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
28290001Sglebius * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
29290001Sglebius * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
30290001Sglebius * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
31290001Sglebius * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
32290001Sglebius * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33290001Sglebius * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34290001Sglebius * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
35290001Sglebius * OF SUCH DAMAGE.
36290001Sglebius *
37290001Sglebius * Author: Archie Cobbs <archie@whistle.com>
38290001Sglebius *
39290001Sglebius * $FreeBSD: head/sys/netgraph/ng_bpf.c 64508 2000-08-10 22:45:54Z archie $
40290001Sglebius * $Whistle: ng_bpf.c,v 1.3 1999/12/03 20:30:23 archie Exp $
41290001Sglebius */
42290001Sglebius
43290001Sglebius/*
44290001Sglebius * BPF NETGRAPH NODE TYPE
45290001Sglebius *
46290001Sglebius * This node type accepts any number of hook connections.  With each hook
47290001Sglebius * is associated a bpf(4) filter program, and two hook names (each possibly
48290001Sglebius * the empty string).  Incoming packets are compared against the filter;
49290001Sglebius * matching packets are delivered out the first named hook (or dropped if
50290001Sglebius * the empty string), and non-matching packets are delivered out the second
51290001Sglebius * named hook (or dropped if the empty string).
52290001Sglebius *
53290001Sglebius * Each hook also keeps statistics about how many packets have matched, etc.
54290001Sglebius */
55290001Sglebius
56290001Sglebius#include <sys/param.h>
57290001Sglebius#include <sys/systm.h>
58290001Sglebius#include <sys/errno.h>
59290001Sglebius#include <sys/kernel.h>
60290001Sglebius#include <sys/malloc.h>
61290001Sglebius#include <sys/mbuf.h>
62290001Sglebius
63290001Sglebius#include <net/bpf.h>
64290001Sglebius
65290001Sglebius#include <netgraph/ng_message.h>
66290001Sglebius#include <netgraph/netgraph.h>
67290001Sglebius#include <netgraph/ng_parse.h>
68290001Sglebius#include <netgraph/ng_bpf.h>
69290001Sglebius
70290001Sglebius#define OFFSETOF(s, e) ((char *)&((s *)0)->e - (char *)((s *)0))
71290001Sglebius
72290001Sglebius#define ERROUT(x)	do { error = (x); goto done; } while (0)
73290001Sglebius
74290001Sglebius/* Per hook private info */
75290001Sglebiusstruct ng_bpf_hookinfo {
76290001Sglebius	node_p			node;
77290001Sglebius	hook_p			hook;
78290001Sglebius	struct ng_bpf_hookprog	*prog;
79290001Sglebius	struct ng_bpf_hookstat	stats;
80290001Sglebius};
81290001Sglebiustypedef struct ng_bpf_hookinfo *hinfo_p;
82290001Sglebius
83290001Sglebius/* Netgraph methods */
84290001Sglebiusstatic ng_constructor_t	ng_bpf_constructor;
85290001Sglebiusstatic ng_rcvmsg_t	ng_bpf_rcvmsg;
86290001Sglebiusstatic ng_shutdown_t	ng_bpf_rmnode;
87290001Sglebiusstatic ng_newhook_t	ng_bpf_newhook;
88290001Sglebiusstatic ng_rcvdata_t	ng_bpf_rcvdata;
89290001Sglebiusstatic ng_disconnect_t	ng_bpf_disconnect;
90290001Sglebius
91290001Sglebius/* Internal helper functions */
92290001Sglebiusstatic int	ng_bpf_setprog(hook_p hook, const struct ng_bpf_hookprog *hp);
93290001Sglebius
94290001Sglebius/* Parse type for one struct bfp_insn */
95290001Sglebiusstatic const struct ng_parse_struct_info ng_bpf_insn_type_info = {
96290001Sglebius    {
97290001Sglebius	{ "code",	&ng_parse_hint16_type	},
98290001Sglebius	{ "jt",		&ng_parse_uint8_type	},
99290001Sglebius	{ "jf",		&ng_parse_uint8_type	},
100290001Sglebius	{ "k",		&ng_parse_uint32_type	},
101290001Sglebius	{ NULL }
102290001Sglebius    }
103290001Sglebius};
104290001Sglebiusstatic const struct ng_parse_type ng_bpf_insn_type = {
105290001Sglebius	&ng_parse_struct_type,
106290001Sglebius	&ng_bpf_insn_type_info
107290001Sglebius};
108290001Sglebius
109290001Sglebius/* Parse type for the field 'bpf_prog' in struct ng_bpf_hookprog */
110290001Sglebiusstatic int
111290001Sglebiusng_bpf_hookprogary_getLength(const struct ng_parse_type *type,
112290001Sglebius	const u_char *start, const u_char *buf)
113290001Sglebius{
114290001Sglebius	const struct ng_bpf_hookprog *hp;
115290001Sglebius
116290001Sglebius	hp = (const struct ng_bpf_hookprog *)
117290001Sglebius	    (buf - OFFSETOF(struct ng_bpf_hookprog, bpf_prog));
118290001Sglebius	return hp->bpf_prog_len;
119290001Sglebius}
120290001Sglebius
121290001Sglebiusstatic const struct ng_parse_array_info ng_bpf_hookprogary_info = {
122290001Sglebius	&ng_bpf_insn_type,
123290001Sglebius	&ng_bpf_hookprogary_getLength,
124290001Sglebius	NULL
125290001Sglebius};
126290001Sglebiusstatic const struct ng_parse_type ng_bpf_hookprogary_type = {
127290001Sglebius	&ng_parse_array_type,
128290001Sglebius	&ng_bpf_hookprogary_info
129290001Sglebius};
130290001Sglebius
131290001Sglebius/* Parse type for struct ng_bpf_hookprog */
132290001Sglebiusstatic const struct ng_parse_struct_info ng_bpf_hookprog_type_info
133290001Sglebius	= NG_BPF_HOOKPROG_TYPE_INFO(&ng_bpf_hookprogary_type);
134290001Sglebiusstatic const struct ng_parse_type ng_bpf_hookprog_type = {
135290001Sglebius	&ng_parse_struct_type,
136290001Sglebius	&ng_bpf_hookprog_type_info
137290001Sglebius};
138290001Sglebius
139290001Sglebius/* Parse type for struct ng_bpf_hookstat */
140290001Sglebiusstatic const struct ng_parse_struct_info
141290001Sglebius	ng_bpf_hookstat_type_info = NG_BPF_HOOKSTAT_TYPE_INFO;
142290001Sglebiusstatic const struct ng_parse_type ng_bpf_hookstat_type = {
143290001Sglebius	&ng_parse_struct_type,
144290001Sglebius	&ng_bpf_hookstat_type_info
145290001Sglebius};
146290001Sglebius
147290001Sglebius/* List of commands and how to convert arguments to/from ASCII */
148290001Sglebiusstatic const struct ng_cmdlist ng_bpf_cmdlist[] = {
149290001Sglebius	{
150290001Sglebius	  NGM_BPF_COOKIE,
151290001Sglebius	  NGM_BPF_SET_PROGRAM,
152290001Sglebius	  "setprogram",
153290001Sglebius	  &ng_bpf_hookprog_type,
154290001Sglebius	  NULL
155290001Sglebius	},
156290001Sglebius	{
157290001Sglebius	  NGM_BPF_COOKIE,
158290001Sglebius	  NGM_BPF_GET_PROGRAM,
159290001Sglebius	  "getprogram",
160290001Sglebius	  &ng_parse_hookbuf_type,
161290001Sglebius	  &ng_bpf_hookprog_type
162290001Sglebius	},
163290001Sglebius	{
164290001Sglebius	  NGM_BPF_COOKIE,
165290001Sglebius	  NGM_BPF_GET_STATS,
166290001Sglebius	  "getstats",
167290001Sglebius	  &ng_parse_hookbuf_type,
168290001Sglebius	  &ng_bpf_hookstat_type
169290001Sglebius	},
170290001Sglebius	{
171290001Sglebius	  NGM_BPF_COOKIE,
172290001Sglebius	  NGM_BPF_CLR_STATS,
173290001Sglebius	  "clrstats",
174290001Sglebius	  &ng_parse_hookbuf_type,
175290001Sglebius	  NULL
176290001Sglebius	},
177290001Sglebius	{
178290001Sglebius	  NGM_BPF_COOKIE,
179290001Sglebius	  NGM_BPF_GETCLR_STATS,
180290001Sglebius	  "getclrstats",
181290001Sglebius	  &ng_parse_hookbuf_type,
182290001Sglebius	  &ng_bpf_hookstat_type
183290001Sglebius	},
184290001Sglebius	{ 0 }
185290001Sglebius};
186290001Sglebius
187290001Sglebius/* Netgraph type descriptor */
188290001Sglebiusstatic struct ng_type typestruct = {
189290001Sglebius	NG_VERSION,
190290001Sglebius	NG_BPF_NODE_TYPE,
191290001Sglebius	NULL,
192290001Sglebius	ng_bpf_constructor,
193290001Sglebius	ng_bpf_rcvmsg,
194290001Sglebius	ng_bpf_rmnode,
195290001Sglebius	ng_bpf_newhook,
196290001Sglebius	NULL,
197290001Sglebius	NULL,
198290001Sglebius	ng_bpf_rcvdata,
199290001Sglebius	ng_bpf_rcvdata,
200290001Sglebius	ng_bpf_disconnect,
201290001Sglebius	ng_bpf_cmdlist
202290001Sglebius};
203290001SglebiusNETGRAPH_INIT(bpf, &typestruct);
204290001Sglebius
205290001Sglebius/* Default BPF program for a hook that matches nothing */
206290001Sglebiusstatic const struct ng_bpf_hookprog ng_bpf_default_prog = {
207290001Sglebius	{ '\0' },		/* to be filled in at hook creation time */
208290001Sglebius	{ '\0' },
209290001Sglebius	{ '\0' },
210290001Sglebius	1,
211290001Sglebius	{ BPF_STMT(BPF_RET+BPF_K, 0) }
212290001Sglebius};
213290001Sglebius
214290001Sglebius/*
215290001Sglebius * Node constructor
216290001Sglebius *
217290001Sglebius * We don't keep any per-node private data
218290001Sglebius */
219290001Sglebiusstatic int
220290001Sglebiusng_bpf_constructor(node_p *nodep)
221290001Sglebius{
222290001Sglebius	int error = 0;
223290001Sglebius
224290001Sglebius	if ((error = ng_make_node_common(&typestruct, nodep)))
225290001Sglebius		return (error);
226290001Sglebius	(*nodep)->private = NULL;
227290001Sglebius	return (0);
228290001Sglebius}
229290001Sglebius
230290001Sglebius/*
231290001Sglebius * Add a hook
232290001Sglebius */
233290001Sglebiusstatic int
234290001Sglebiusng_bpf_newhook(node_p node, hook_p hook, const char *name)
235290001Sglebius{
236290001Sglebius	hinfo_p hip;
237290001Sglebius	int error;
238290001Sglebius
239290001Sglebius	/* Create hook private structure */
240290001Sglebius	MALLOC(hip, hinfo_p, sizeof(*hip), M_NETGRAPH, M_WAITOK);
241290001Sglebius	if (hip == NULL)
242290001Sglebius		return (ENOMEM);
243290001Sglebius	bzero(hip, sizeof(*hip));
244290001Sglebius	hip->hook = hook;
245290001Sglebius	hook->private = hip;
246290001Sglebius	hip->node = node;
247290001Sglebius
248290001Sglebius	/* Attach the default BPF program */
249290001Sglebius	if ((error = ng_bpf_setprog(hook, &ng_bpf_default_prog)) != 0) {
250290001Sglebius		FREE(hip, M_NETGRAPH);
251290001Sglebius		hook->private = NULL;
252290001Sglebius		return (error);
253290001Sglebius	}
254290001Sglebius
255290001Sglebius	/* Set hook name */
256290001Sglebius	strncpy(hip->prog->thisHook, name, sizeof(hip->prog->thisHook) - 1);
257290001Sglebius	hip->prog->thisHook[sizeof(hip->prog->thisHook) - 1] = '\0';
258290001Sglebius	return (0);
259290001Sglebius}
260290001Sglebius
261290001Sglebius/*
262290001Sglebius * Receive a control message
263290001Sglebius */
264290001Sglebiusstatic int
265290001Sglebiusng_bpf_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr,
266290001Sglebius	   struct ng_mesg **rptr, hook_p lasthook)
267290001Sglebius{
268290001Sglebius	struct ng_mesg *resp = NULL;
269290001Sglebius	int error = 0;
270290001Sglebius
271290001Sglebius	switch (msg->header.typecookie) {
272290001Sglebius	case NGM_BPF_COOKIE:
273290001Sglebius		switch (msg->header.cmd) {
274290001Sglebius		case NGM_BPF_SET_PROGRAM:
275290001Sglebius		    {
276290001Sglebius			struct ng_bpf_hookprog *const
277290001Sglebius			    hp = (struct ng_bpf_hookprog *)msg->data;
278290001Sglebius			hook_p hook;
279290001Sglebius
280290001Sglebius			/* Sanity check */
281290001Sglebius			if (msg->header.arglen < sizeof(*hp)
282290001Sglebius			    || msg->header.arglen
283290001Sglebius			      != NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len))
284290001Sglebius				ERROUT(EINVAL);
285290001Sglebius
286290001Sglebius			/* Find hook */
287290001Sglebius			if ((hook = ng_findhook(node, hp->thisHook)) == NULL)
288290001Sglebius				ERROUT(ENOENT);
289290001Sglebius
290290001Sglebius			/* Set new program */
291290001Sglebius			if ((error = ng_bpf_setprog(hook, hp)) != 0)
292290001Sglebius				ERROUT(error);
293290001Sglebius			break;
294290001Sglebius		    }
295290001Sglebius
296290001Sglebius		case NGM_BPF_GET_PROGRAM:
297290001Sglebius		    {
298290001Sglebius			struct ng_bpf_hookprog *hp;
299290001Sglebius			hook_p hook;
300290001Sglebius
301290001Sglebius			/* Sanity check */
302290001Sglebius			if (msg->header.arglen == 0)
303290001Sglebius				ERROUT(EINVAL);
304290001Sglebius			msg->data[msg->header.arglen - 1] = '\0';
305290001Sglebius
306290001Sglebius			/* Find hook */
307290001Sglebius			if ((hook = ng_findhook(node, msg->data)) == NULL)
308290001Sglebius				ERROUT(ENOENT);
309290001Sglebius
310290001Sglebius			/* Build response */
311290001Sglebius			hp = ((hinfo_p)hook->private)->prog;
312290001Sglebius			NG_MKRESPONSE(resp, msg,
313290001Sglebius			    NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len), M_NOWAIT);
314290001Sglebius			if (resp == NULL)
315290001Sglebius				ERROUT(ENOMEM);
316290001Sglebius			bcopy(hp, resp->data,
317290001Sglebius			   NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len));
318290001Sglebius			break;
319290001Sglebius		    }
320290001Sglebius
321290001Sglebius		case NGM_BPF_GET_STATS:
322290001Sglebius		case NGM_BPF_CLR_STATS:
323290001Sglebius		case NGM_BPF_GETCLR_STATS:
324290001Sglebius		    {
325290001Sglebius			struct ng_bpf_hookstat *stats;
326290001Sglebius			hook_p hook;
327290001Sglebius
328290001Sglebius			/* Sanity check */
329290001Sglebius			if (msg->header.arglen == 0)
330290001Sglebius				ERROUT(EINVAL);
331290001Sglebius			msg->data[msg->header.arglen - 1] = '\0';
332290001Sglebius
333290001Sglebius			/* Find hook */
334290001Sglebius			if ((hook = ng_findhook(node, msg->data)) == NULL)
335290001Sglebius				ERROUT(ENOENT);
336290001Sglebius			stats = &((hinfo_p)hook->private)->stats;
337290001Sglebius
338290001Sglebius			/* Build response (if desired) */
339290001Sglebius			if (msg->header.cmd != NGM_BPF_CLR_STATS) {
340290001Sglebius				NG_MKRESPONSE(resp,
341290001Sglebius				    msg, sizeof(*stats), M_NOWAIT);
342290001Sglebius				if (resp == NULL)
343290001Sglebius					ERROUT(ENOMEM);
344290001Sglebius				bcopy(stats, resp->data, sizeof(*stats));
345290001Sglebius			}
346290001Sglebius
347290001Sglebius			/* Clear stats (if desired) */
348290001Sglebius			if (msg->header.cmd != NGM_BPF_GET_STATS)
349290001Sglebius				bzero(stats, sizeof(*stats));
350290001Sglebius			break;
351290001Sglebius		    }
352290001Sglebius
353290001Sglebius		default:
354290001Sglebius			error = EINVAL;
355290001Sglebius			break;
356290001Sglebius		}
357290001Sglebius		break;
358290001Sglebius	default:
359290001Sglebius		error = EINVAL;
360290001Sglebius		break;
361290001Sglebius	}
362290001Sglebius	if (rptr)
363290001Sglebius		*rptr = resp;
364290001Sglebius	else if (resp)
365290001Sglebius		FREE(resp, M_NETGRAPH);
366290001Sglebius
367290001Sglebiusdone:
368290001Sglebius	FREE(msg, M_NETGRAPH);
369290001Sglebius	return (error);
370290001Sglebius}
371290001Sglebius
372290001Sglebius/*
373290001Sglebius * Receive data on a hook
374290001Sglebius *
375290001Sglebius * Apply the filter, and then drop or forward packet as appropriate.
376290001Sglebius */
377290001Sglebiusstatic int
378290001Sglebiusng_bpf_rcvdata(hook_p hook, struct mbuf *m, meta_p meta,
379290001Sglebius		struct mbuf **ret_m, meta_p *ret_meta)
380290001Sglebius{
381290001Sglebius	const hinfo_p hip = hook->private;
382290001Sglebius	int totlen = m->m_pkthdr.len;
383290001Sglebius	int needfree = 0, error = 0;
384290001Sglebius	u_char *data, buf[256];
385290001Sglebius	hinfo_p dhip;
386290001Sglebius	hook_p dest;
387290001Sglebius	u_int len;
388290001Sglebius
389290001Sglebius	/* Update stats on incoming hook */
390290001Sglebius	hip->stats.recvFrames++;
391290001Sglebius	hip->stats.recvOctets += totlen;
392290001Sglebius
393290001Sglebius	/* Need to put packet in contiguous memory for bpf */
394290001Sglebius	if (m->m_next != NULL) {
395290001Sglebius		if (totlen > sizeof(buf)) {
396290001Sglebius			MALLOC(data, u_char *, totlen, M_NETGRAPH, M_NOWAIT);
397290001Sglebius			if (data == NULL) {
398290001Sglebius				NG_FREE_DATA(m, meta);
399290001Sglebius				return (ENOMEM);
400290001Sglebius			}
401290001Sglebius			needfree = 1;
402290001Sglebius		} else
403290001Sglebius			data = buf;
404290001Sglebius		m_copydata(m, 0, totlen, (caddr_t)data);
405290001Sglebius	} else
406290001Sglebius		data = mtod(m, u_char *);
407290001Sglebius
408290001Sglebius	/* Run packet through filter */
409290001Sglebius	len = bpf_filter(hip->prog->bpf_prog, data, totlen, totlen);
410290001Sglebius	if (needfree)
411290001Sglebius		FREE(data, M_NETGRAPH);
412290001Sglebius
413290001Sglebius	/* See if we got a match and find destination hook */
414290001Sglebius	if (len > 0) {
415290001Sglebius
416290001Sglebius		/* Update stats */
417290001Sglebius		hip->stats.recvMatchFrames++;
418290001Sglebius		hip->stats.recvMatchOctets += totlen;
419290001Sglebius
420290001Sglebius		/* Truncate packet length if required by the filter */
421290001Sglebius		if (len < totlen) {
422290001Sglebius			m_adj(m, -(totlen - len));
423290001Sglebius			totlen -= len;
424290001Sglebius		}
425290001Sglebius		dest = ng_findhook(hip->node, hip->prog->ifMatch);
426290001Sglebius	} else
427290001Sglebius		dest = ng_findhook(hip->node, hip->prog->ifNotMatch);
428290001Sglebius	if (dest == NULL) {
429290001Sglebius		NG_FREE_DATA(m, meta);
430290001Sglebius		return (0);
431290001Sglebius	}
432290001Sglebius
433290001Sglebius	/* Deliver frame out destination hook */
434290001Sglebius	dhip = (hinfo_p)dest->private;
435290001Sglebius	dhip->stats.xmitOctets += totlen;
436290001Sglebius	dhip->stats.xmitFrames++;
437290001Sglebius	NG_SEND_DATA(error, dest, m, meta);
438290001Sglebius	return (error);
439290001Sglebius}
440290001Sglebius
441290001Sglebius/*
442290001Sglebius * Shutdown processing
443290001Sglebius */
444290001Sglebiusstatic int
445290001Sglebiusng_bpf_rmnode(node_p node)
446290001Sglebius{
447290001Sglebius	node->flags |= NG_INVALID;
448290001Sglebius	ng_cutlinks(node);
449290001Sglebius	ng_unname(node);
450290001Sglebius	ng_unref(node);
451290001Sglebius	return (0);
452290001Sglebius}
453290001Sglebius
454290001Sglebius/*
455290001Sglebius * Hook disconnection
456290001Sglebius */
457290001Sglebiusstatic int
458290001Sglebiusng_bpf_disconnect(hook_p hook)
459290001Sglebius{
460290001Sglebius	const hinfo_p hip = hook->private;
461290001Sglebius
462290001Sglebius	KASSERT(hip != NULL, ("%s: null info", __FUNCTION__));
463290001Sglebius	FREE(hip->prog, M_NETGRAPH);
464290001Sglebius	bzero(hip, sizeof(*hip));
465290001Sglebius	FREE(hip, M_NETGRAPH);
466290001Sglebius	hook->private = NULL;			/* for good measure */
467290001Sglebius	if (hook->node->numhooks == 0)
468290001Sglebius		ng_rmnode(hook->node);
469290001Sglebius	return (0);
470290001Sglebius}
471290001Sglebius
472290001Sglebius/************************************************************************
473290001Sglebius			HELPER STUFF
474290001Sglebius ************************************************************************/
475290001Sglebius
476290001Sglebius/*
477290001Sglebius * Set the BPF program associated with a hook
478290001Sglebius */
479290001Sglebiusstatic int
480290001Sglebiusng_bpf_setprog(hook_p hook, const struct ng_bpf_hookprog *hp0)
481290001Sglebius{
482290001Sglebius	const hinfo_p hip = hook->private;
483290001Sglebius	struct ng_bpf_hookprog *hp;
484290001Sglebius	int size;
485290001Sglebius
486290001Sglebius	/* Check program for validity */
487290001Sglebius	if (!bpf_validate(hp0->bpf_prog, hp0->bpf_prog_len))
488290001Sglebius		return (EINVAL);
489290001Sglebius
490290001Sglebius	/* Make a copy of the program */
491290001Sglebius	size = NG_BPF_HOOKPROG_SIZE(hp0->bpf_prog_len);
492290001Sglebius	MALLOC(hp, struct ng_bpf_hookprog *, size, M_NETGRAPH, M_WAITOK);
493290001Sglebius	if (hp == NULL)
494290001Sglebius		return (ENOMEM);
495290001Sglebius	bcopy(hp0, hp, size);
496290001Sglebius
497290001Sglebius	/* Free previous program, if any, and assign new one */
498290001Sglebius	if (hip->prog != NULL)
499290001Sglebius		FREE(hip->prog, M_NETGRAPH);
500290001Sglebius	hip->prog = hp;
501290001Sglebius	return (0);
502290001Sglebius}
503290001Sglebius
504290001Sglebius