ng_bpf.c revision 171600
154097Sarchie/*
254097Sarchie * ng_bpf.c
3139823Simp */
4139823Simp
5139823Simp/*-
654097Sarchie * Copyright (c) 1999 Whistle Communications, Inc.
754097Sarchie * All rights reserved.
854097Sarchie *
954097Sarchie * Subject to the following obligations and disclaimer of warranty, use and
1054097Sarchie * redistribution of this software, in source or object code forms, with or
1154097Sarchie * without modifications are expressly permitted by Whistle Communications;
1254097Sarchie * provided, however, that:
1354097Sarchie * 1. Any and all reproductions of the source or object code must include the
1454097Sarchie *    copyright notice above and the following disclaimer of warranties; and
1554097Sarchie * 2. No rights are granted, in any manner or form, to use Whistle
1654097Sarchie *    Communications, Inc. trademarks, including the mark "WHISTLE
1754097Sarchie *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
1854097Sarchie *    such appears in the above copyright notice or in the software.
1954097Sarchie *
2054097Sarchie * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
2154097Sarchie * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
2254097Sarchie * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
2354097Sarchie * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
2454097Sarchie * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
2571821Sjulian * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
2654097Sarchie * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
2754097Sarchie * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
2854097Sarchie * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
2954097Sarchie * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
3054097Sarchie * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
3154097Sarchie * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
3254097Sarchie * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
3354097Sarchie * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3454097Sarchie * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3554097Sarchie * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
3654097Sarchie * OF SUCH DAMAGE.
3754097Sarchie *
3867506Sjulian * Author: Archie Cobbs <archie@freebsd.org>
3954097Sarchie *
4054097Sarchie * $FreeBSD: head/sys/netgraph/ng_bpf.c 171600 2007-07-26 18:15:02Z mav $
4154097Sarchie * $Whistle: ng_bpf.c,v 1.3 1999/12/03 20:30:23 archie Exp $
4254097Sarchie */
4354097Sarchie
4454097Sarchie/*
4554097Sarchie * BPF NETGRAPH NODE TYPE
4654097Sarchie *
4754097Sarchie * This node type accepts any number of hook connections.  With each hook
4854097Sarchie * is associated a bpf(4) filter program, and two hook names (each possibly
4954097Sarchie * the empty string).  Incoming packets are compared against the filter;
5054097Sarchie * matching packets are delivered out the first named hook (or dropped if
5154097Sarchie * the empty string), and non-matching packets are delivered out the second
5254097Sarchie * named hook (or dropped if the empty string).
5354097Sarchie *
5454097Sarchie * Each hook also keeps statistics about how many packets have matched, etc.
5554097Sarchie */
5654097Sarchie
57153213Sjkim#include "opt_bpf.h"
58153213Sjkim
5954097Sarchie#include <sys/param.h>
6054097Sarchie#include <sys/systm.h>
6154097Sarchie#include <sys/errno.h>
6254097Sarchie#include <sys/kernel.h>
6354097Sarchie#include <sys/malloc.h>
6454097Sarchie#include <sys/mbuf.h>
6554097Sarchie
6654097Sarchie#include <net/bpf.h>
67153213Sjkim#ifdef BPF_JITTER
68153213Sjkim#include <net/bpf_jitter.h>
69153213Sjkim#endif
7054097Sarchie
7154097Sarchie#include <netgraph/ng_message.h>
7254097Sarchie#include <netgraph/netgraph.h>
7354097Sarchie#include <netgraph/ng_parse.h>
7454097Sarchie#include <netgraph/ng_bpf.h>
7554097Sarchie
7670870Sjulian#ifdef NG_SEPARATE_MALLOC
7770870SjulianMALLOC_DEFINE(M_NETGRAPH_BPF, "netgraph_bpf", "netgraph bpf node ");
7870870Sjulian#else
7970870Sjulian#define M_NETGRAPH_BPF M_NETGRAPH
8070870Sjulian#endif
8170870Sjulian
8254097Sarchie#define OFFSETOF(s, e) ((char *)&((s *)0)->e - (char *)((s *)0))
8354097Sarchie
8454097Sarchie#define ERROUT(x)	do { error = (x); goto done; } while (0)
8554097Sarchie
8654097Sarchie/* Per hook private info */
8754097Sarchiestruct ng_bpf_hookinfo {
8854097Sarchie	node_p			node;
8954097Sarchie	hook_p			hook;
9054097Sarchie	struct ng_bpf_hookprog	*prog;
91153213Sjkim#ifdef BPF_JITTER
92153213Sjkim	bpf_jit_filter		*jit_prog;
93153213Sjkim#endif
9454097Sarchie	struct ng_bpf_hookstat	stats;
9554097Sarchie};
9654097Sarchietypedef struct ng_bpf_hookinfo *hinfo_p;
9754097Sarchie
9854097Sarchie/* Netgraph methods */
9954097Sarchiestatic ng_constructor_t	ng_bpf_constructor;
10054097Sarchiestatic ng_rcvmsg_t	ng_bpf_rcvmsg;
10170700Sjulianstatic ng_shutdown_t	ng_bpf_shutdown;
10254097Sarchiestatic ng_newhook_t	ng_bpf_newhook;
10354097Sarchiestatic ng_rcvdata_t	ng_bpf_rcvdata;
10454097Sarchiestatic ng_disconnect_t	ng_bpf_disconnect;
10554097Sarchie
10654097Sarchie/* Internal helper functions */
10754097Sarchiestatic int	ng_bpf_setprog(hook_p hook, const struct ng_bpf_hookprog *hp);
10854097Sarchie
10954097Sarchie/* Parse type for one struct bfp_insn */
11097685Sarchiestatic const struct ng_parse_struct_field ng_bpf_insn_type_fields[] = {
11164508Sarchie	{ "code",	&ng_parse_hint16_type	},
11264508Sarchie	{ "jt",		&ng_parse_uint8_type	},
11364508Sarchie	{ "jf",		&ng_parse_uint8_type	},
11464508Sarchie	{ "k",		&ng_parse_uint32_type	},
11554097Sarchie	{ NULL }
11654097Sarchie};
11754097Sarchiestatic const struct ng_parse_type ng_bpf_insn_type = {
11854097Sarchie	&ng_parse_struct_type,
11997685Sarchie	&ng_bpf_insn_type_fields
12054097Sarchie};
12154097Sarchie
12254097Sarchie/* Parse type for the field 'bpf_prog' in struct ng_bpf_hookprog */
12354097Sarchiestatic int
12454097Sarchieng_bpf_hookprogary_getLength(const struct ng_parse_type *type,
12554097Sarchie	const u_char *start, const u_char *buf)
12654097Sarchie{
12754097Sarchie	const struct ng_bpf_hookprog *hp;
12854097Sarchie
12954097Sarchie	hp = (const struct ng_bpf_hookprog *)
13054097Sarchie	    (buf - OFFSETOF(struct ng_bpf_hookprog, bpf_prog));
13154097Sarchie	return hp->bpf_prog_len;
13254097Sarchie}
13354097Sarchie
13454097Sarchiestatic const struct ng_parse_array_info ng_bpf_hookprogary_info = {
13554097Sarchie	&ng_bpf_insn_type,
13654097Sarchie	&ng_bpf_hookprogary_getLength,
13754097Sarchie	NULL
13854097Sarchie};
13954097Sarchiestatic const struct ng_parse_type ng_bpf_hookprogary_type = {
14054097Sarchie	&ng_parse_array_type,
14154097Sarchie	&ng_bpf_hookprogary_info
14254097Sarchie};
14354097Sarchie
14454097Sarchie/* Parse type for struct ng_bpf_hookprog */
14597685Sarchiestatic const struct ng_parse_struct_field ng_bpf_hookprog_type_fields[]
14654097Sarchie	= NG_BPF_HOOKPROG_TYPE_INFO(&ng_bpf_hookprogary_type);
14754097Sarchiestatic const struct ng_parse_type ng_bpf_hookprog_type = {
14854097Sarchie	&ng_parse_struct_type,
14997685Sarchie	&ng_bpf_hookprog_type_fields
15054097Sarchie};
15154097Sarchie
15254097Sarchie/* Parse type for struct ng_bpf_hookstat */
15397685Sarchiestatic const struct ng_parse_struct_field ng_bpf_hookstat_type_fields[]
15497685Sarchie	= NG_BPF_HOOKSTAT_TYPE_INFO;
15554097Sarchiestatic const struct ng_parse_type ng_bpf_hookstat_type = {
15654097Sarchie	&ng_parse_struct_type,
15797685Sarchie	&ng_bpf_hookstat_type_fields
15854097Sarchie};
15954097Sarchie
16054097Sarchie/* List of commands and how to convert arguments to/from ASCII */
16154097Sarchiestatic const struct ng_cmdlist ng_bpf_cmdlist[] = {
16254097Sarchie	{
16354097Sarchie	  NGM_BPF_COOKIE,
16454097Sarchie	  NGM_BPF_SET_PROGRAM,
16554097Sarchie	  "setprogram",
16654097Sarchie	  &ng_bpf_hookprog_type,
16754097Sarchie	  NULL
16854097Sarchie	},
16954097Sarchie	{
17054097Sarchie	  NGM_BPF_COOKIE,
17154097Sarchie	  NGM_BPF_GET_PROGRAM,
17254097Sarchie	  "getprogram",
17354097Sarchie	  &ng_parse_hookbuf_type,
17454097Sarchie	  &ng_bpf_hookprog_type
17554097Sarchie	},
17654097Sarchie	{
17754097Sarchie	  NGM_BPF_COOKIE,
17854097Sarchie	  NGM_BPF_GET_STATS,
17954097Sarchie	  "getstats",
18054097Sarchie	  &ng_parse_hookbuf_type,
18154097Sarchie	  &ng_bpf_hookstat_type
18254097Sarchie	},
18354097Sarchie	{
18454097Sarchie	  NGM_BPF_COOKIE,
18554097Sarchie	  NGM_BPF_CLR_STATS,
18654097Sarchie	  "clrstats",
18754097Sarchie	  &ng_parse_hookbuf_type,
18854097Sarchie	  NULL
18954097Sarchie	},
19054097Sarchie	{
19154097Sarchie	  NGM_BPF_COOKIE,
19254097Sarchie	  NGM_BPF_GETCLR_STATS,
19354097Sarchie	  "getclrstats",
19454097Sarchie	  &ng_parse_hookbuf_type,
19554097Sarchie	  &ng_bpf_hookstat_type
19654097Sarchie	},
19754097Sarchie	{ 0 }
19854097Sarchie};
19954097Sarchie
20054097Sarchie/* Netgraph type descriptor */
20154097Sarchiestatic struct ng_type typestruct = {
202129823Sjulian	.version =	NG_ABI_VERSION,
203129823Sjulian	.name =		NG_BPF_NODE_TYPE,
204129823Sjulian	.constructor =	ng_bpf_constructor,
205129823Sjulian	.rcvmsg =	ng_bpf_rcvmsg,
206129823Sjulian	.shutdown =	ng_bpf_shutdown,
207129823Sjulian	.newhook =	ng_bpf_newhook,
208129823Sjulian	.rcvdata =	ng_bpf_rcvdata,
209129823Sjulian	.disconnect =	ng_bpf_disconnect,
210129823Sjulian	.cmdlist =	ng_bpf_cmdlist,
21154097Sarchie};
21254097SarchieNETGRAPH_INIT(bpf, &typestruct);
21354097Sarchie
21454097Sarchie/* Default BPF program for a hook that matches nothing */
21554097Sarchiestatic const struct ng_bpf_hookprog ng_bpf_default_prog = {
21654097Sarchie	{ '\0' },		/* to be filled in at hook creation time */
21754097Sarchie	{ '\0' },
21854097Sarchie	{ '\0' },
21954097Sarchie	1,
22054097Sarchie	{ BPF_STMT(BPF_RET+BPF_K, 0) }
22154097Sarchie};
22254097Sarchie
22354097Sarchie/*
22454097Sarchie * Node constructor
22554097Sarchie *
22654097Sarchie * We don't keep any per-node private data
22770700Sjulian * We go via the hooks.
22854097Sarchie */
22954097Sarchiestatic int
23070700Sjulianng_bpf_constructor(node_p node)
23154097Sarchie{
23270784Sjulian	NG_NODE_SET_PRIVATE(node, NULL);
23354097Sarchie	return (0);
23454097Sarchie}
23554097Sarchie
23654097Sarchie/*
23754097Sarchie * Add a hook
23854097Sarchie */
23954097Sarchiestatic int
24054097Sarchieng_bpf_newhook(node_p node, hook_p hook, const char *name)
24154097Sarchie{
24254097Sarchie	hinfo_p hip;
24354097Sarchie	int error;
24454097Sarchie
24554097Sarchie	/* Create hook private structure */
24670870Sjulian	MALLOC(hip, hinfo_p, sizeof(*hip), M_NETGRAPH_BPF, M_NOWAIT | M_ZERO);
24754097Sarchie	if (hip == NULL)
24854097Sarchie		return (ENOMEM);
24954097Sarchie	hip->hook = hook;
25070784Sjulian	NG_HOOK_SET_PRIVATE(hook, hip);
25154097Sarchie	hip->node = node;
25254097Sarchie
25354097Sarchie	/* Attach the default BPF program */
25454097Sarchie	if ((error = ng_bpf_setprog(hook, &ng_bpf_default_prog)) != 0) {
25570870Sjulian		FREE(hip, M_NETGRAPH_BPF);
25670784Sjulian		NG_HOOK_SET_PRIVATE(hook, NULL);
25754097Sarchie		return (error);
25854097Sarchie	}
25954097Sarchie
26054097Sarchie	/* Set hook name */
26154097Sarchie	strncpy(hip->prog->thisHook, name, sizeof(hip->prog->thisHook) - 1);
26254097Sarchie	hip->prog->thisHook[sizeof(hip->prog->thisHook) - 1] = '\0';
26354097Sarchie	return (0);
26454097Sarchie}
26554097Sarchie
26654097Sarchie/*
26754097Sarchie * Receive a control message
26854097Sarchie */
26954097Sarchiestatic int
27070700Sjulianng_bpf_rcvmsg(node_p node, item_p item, hook_p lasthook)
27154097Sarchie{
27270700Sjulian	struct ng_mesg *msg;
27354097Sarchie	struct ng_mesg *resp = NULL;
27454097Sarchie	int error = 0;
27554097Sarchie
27670700Sjulian	NGI_GET_MSG(item, msg);
27754097Sarchie	switch (msg->header.typecookie) {
27854097Sarchie	case NGM_BPF_COOKIE:
27954097Sarchie		switch (msg->header.cmd) {
28054097Sarchie		case NGM_BPF_SET_PROGRAM:
28154097Sarchie		    {
28254097Sarchie			struct ng_bpf_hookprog *const
28354097Sarchie			    hp = (struct ng_bpf_hookprog *)msg->data;
28454097Sarchie			hook_p hook;
28554097Sarchie
28654097Sarchie			/* Sanity check */
28754097Sarchie			if (msg->header.arglen < sizeof(*hp)
28854214Sarchie			    || msg->header.arglen
28954214Sarchie			      != NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len))
29054097Sarchie				ERROUT(EINVAL);
29154097Sarchie
29254097Sarchie			/* Find hook */
29354097Sarchie			if ((hook = ng_findhook(node, hp->thisHook)) == NULL)
29454097Sarchie				ERROUT(ENOENT);
29554097Sarchie
29654097Sarchie			/* Set new program */
29754097Sarchie			if ((error = ng_bpf_setprog(hook, hp)) != 0)
29854097Sarchie				ERROUT(error);
29954097Sarchie			break;
30054097Sarchie		    }
30154097Sarchie
30254097Sarchie		case NGM_BPF_GET_PROGRAM:
30354097Sarchie		    {
30454214Sarchie			struct ng_bpf_hookprog *hp;
30554097Sarchie			hook_p hook;
30654097Sarchie
30754097Sarchie			/* Sanity check */
30854097Sarchie			if (msg->header.arglen == 0)
30954097Sarchie				ERROUT(EINVAL);
31054097Sarchie			msg->data[msg->header.arglen - 1] = '\0';
31154097Sarchie
31254097Sarchie			/* Find hook */
31354097Sarchie			if ((hook = ng_findhook(node, msg->data)) == NULL)
31454097Sarchie				ERROUT(ENOENT);
31554097Sarchie
31654097Sarchie			/* Build response */
31770784Sjulian			hp = ((hinfo_p)NG_HOOK_PRIVATE(hook))->prog;
31854097Sarchie			NG_MKRESPONSE(resp, msg,
31954214Sarchie			    NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len), M_NOWAIT);
32054097Sarchie			if (resp == NULL)
32154097Sarchie				ERROUT(ENOMEM);
32254214Sarchie			bcopy(hp, resp->data,
32354214Sarchie			   NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len));
32454097Sarchie			break;
32554097Sarchie		    }
32654097Sarchie
32754097Sarchie		case NGM_BPF_GET_STATS:
32854097Sarchie		case NGM_BPF_CLR_STATS:
32954097Sarchie		case NGM_BPF_GETCLR_STATS:
33054097Sarchie		    {
33154097Sarchie			struct ng_bpf_hookstat *stats;
33254097Sarchie			hook_p hook;
33354097Sarchie
33454097Sarchie			/* Sanity check */
33554097Sarchie			if (msg->header.arglen == 0)
33654097Sarchie				ERROUT(EINVAL);
33754097Sarchie			msg->data[msg->header.arglen - 1] = '\0';
33854097Sarchie
33954097Sarchie			/* Find hook */
34054097Sarchie			if ((hook = ng_findhook(node, msg->data)) == NULL)
34154097Sarchie				ERROUT(ENOENT);
34270784Sjulian			stats = &((hinfo_p)NG_HOOK_PRIVATE(hook))->stats;
34354097Sarchie
34454097Sarchie			/* Build response (if desired) */
34554097Sarchie			if (msg->header.cmd != NGM_BPF_CLR_STATS) {
34654097Sarchie				NG_MKRESPONSE(resp,
34754097Sarchie				    msg, sizeof(*stats), M_NOWAIT);
34854097Sarchie				if (resp == NULL)
34954097Sarchie					ERROUT(ENOMEM);
35054097Sarchie				bcopy(stats, resp->data, sizeof(*stats));
35154097Sarchie			}
35254097Sarchie
35354097Sarchie			/* Clear stats (if desired) */
35454097Sarchie			if (msg->header.cmd != NGM_BPF_GET_STATS)
35554097Sarchie				bzero(stats, sizeof(*stats));
35654097Sarchie			break;
35754097Sarchie		    }
35854097Sarchie
35954097Sarchie		default:
36054097Sarchie			error = EINVAL;
36154097Sarchie			break;
36254097Sarchie		}
36354097Sarchie		break;
36454097Sarchie	default:
36554097Sarchie		error = EINVAL;
36654097Sarchie		break;
36754097Sarchie	}
36870933Sjuliandone:
36970700Sjulian	NG_RESPOND_MSG(error, node, item, resp);
37070700Sjulian	NG_FREE_MSG(msg);
37154097Sarchie	return (error);
37254097Sarchie}
37354097Sarchie
37454097Sarchie/*
37554097Sarchie * Receive data on a hook
37654097Sarchie *
37754097Sarchie * Apply the filter, and then drop or forward packet as appropriate.
37854097Sarchie */
37954097Sarchiestatic int
38070700Sjulianng_bpf_rcvdata(hook_p hook, item_p item)
38154097Sarchie{
38270784Sjulian	const hinfo_p hip = NG_HOOK_PRIVATE(hook);
38370700Sjulian	int totlen;
38454097Sarchie	int needfree = 0, error = 0;
385171600Smav	u_char *data;
38654097Sarchie	hinfo_p dhip;
38754097Sarchie	hook_p dest;
38854097Sarchie	u_int len;
38970700Sjulian	struct mbuf *m;
39054097Sarchie
39170700Sjulian	m = NGI_M(item);	/* 'item' still owns it.. we are peeking */
39270700Sjulian	totlen = m->m_pkthdr.len;
39370700Sjulian	/* Update stats on incoming hook. XXX Can we do 64 bits atomically? */
39470700Sjulian	/* atomic_add_int64(&hip->stats.recvFrames, 1); */
39570700Sjulian	/* atomic_add_int64(&hip->stats.recvOctets, totlen); */
39670700Sjulian	hip->stats.recvFrames++;
39754097Sarchie	hip->stats.recvOctets += totlen;
39854097Sarchie
39954097Sarchie	/* Need to put packet in contiguous memory for bpf */
40054097Sarchie	if (m->m_next != NULL) {
401171600Smav		if (totlen > MHLEN) {
40270870Sjulian			MALLOC(data, u_char *, totlen, M_NETGRAPH_BPF, M_NOWAIT);
40354097Sarchie			if (data == NULL) {
40470700Sjulian				NG_FREE_ITEM(item);
40554097Sarchie				return (ENOMEM);
40654097Sarchie			}
40754097Sarchie			needfree = 1;
408171600Smav			m_copydata(m, 0, totlen, (caddr_t)data);
409171600Smav		} else {
410171600Smav			NGI_M(item) = m = m_pullup(m, totlen);
411171600Smav			if (m == NULL) {
412171600Smav				NG_FREE_ITEM(item);
413171600Smav				return (ENOBUFS);
414171600Smav			}
415171600Smav			data = mtod(m, u_char *);
416171600Smav		}
41754097Sarchie	} else
41854097Sarchie		data = mtod(m, u_char *);
41954097Sarchie
42054097Sarchie	/* Run packet through filter */
421130956Sarchie	if (totlen == 0)
422130956Sarchie		len = 0;	/* don't call bpf_filter() with totlen == 0! */
423153213Sjkim	else {
424153213Sjkim#ifdef BPF_JITTER
425153213Sjkim		if (bpf_jitter_enable != 0 && hip->jit_prog != NULL)
426153213Sjkim			len = (*(hip->jit_prog->func))(data, totlen, totlen);
427153213Sjkim		else
428153213Sjkim#endif
429130956Sarchie		len = bpf_filter(hip->prog->bpf_prog, data, totlen, totlen);
430153213Sjkim	}
43154097Sarchie	if (needfree)
43270870Sjulian		FREE(data, M_NETGRAPH_BPF);
43354097Sarchie
43454097Sarchie	/* See if we got a match and find destination hook */
43554097Sarchie	if (len > 0) {
43654097Sarchie
43754097Sarchie		/* Update stats */
43870700Sjulian		/* XXX atomically? */
43954097Sarchie		hip->stats.recvMatchFrames++;
44054097Sarchie		hip->stats.recvMatchOctets += totlen;
44154097Sarchie
44254097Sarchie		/* Truncate packet length if required by the filter */
44370700Sjulian		/* Assume this never changes m */
44454097Sarchie		if (len < totlen) {
44554097Sarchie			m_adj(m, -(totlen - len));
44654097Sarchie			totlen -= len;
44754097Sarchie		}
44854097Sarchie		dest = ng_findhook(hip->node, hip->prog->ifMatch);
44954097Sarchie	} else
45054097Sarchie		dest = ng_findhook(hip->node, hip->prog->ifNotMatch);
45154097Sarchie	if (dest == NULL) {
45270700Sjulian		NG_FREE_ITEM(item);
45354097Sarchie		return (0);
45454097Sarchie	}
45554097Sarchie
45654097Sarchie	/* Deliver frame out destination hook */
45770784Sjulian	dhip = NG_HOOK_PRIVATE(dest);
45854097Sarchie	dhip->stats.xmitOctets += totlen;
45954097Sarchie	dhip->stats.xmitFrames++;
46070784Sjulian	NG_FWD_ITEM_HOOK(error, item, dest);
46154097Sarchie	return (error);
46254097Sarchie}
46354097Sarchie
46454097Sarchie/*
46554097Sarchie * Shutdown processing
46654097Sarchie */
46754097Sarchiestatic int
46870700Sjulianng_bpf_shutdown(node_p node)
46954097Sarchie{
47070784Sjulian	NG_NODE_UNREF(node);
47154097Sarchie	return (0);
47254097Sarchie}
47354097Sarchie
47454097Sarchie/*
47554097Sarchie * Hook disconnection
47654097Sarchie */
47754097Sarchiestatic int
47854097Sarchieng_bpf_disconnect(hook_p hook)
47954097Sarchie{
48070784Sjulian	const hinfo_p hip = NG_HOOK_PRIVATE(hook);
48154097Sarchie
48287599Sobrien	KASSERT(hip != NULL, ("%s: null info", __func__));
48370870Sjulian	FREE(hip->prog, M_NETGRAPH_BPF);
484153213Sjkim#ifdef BPF_JITTER
485153213Sjkim	if (hip->jit_prog != NULL)
486153213Sjkim		bpf_destroy_jit_filter(hip->jit_prog);
487153213Sjkim#endif
48854097Sarchie	bzero(hip, sizeof(*hip));
48970870Sjulian	FREE(hip, M_NETGRAPH_BPF);
49070784Sjulian	NG_HOOK_SET_PRIVATE(hook, NULL);			/* for good measure */
49170784Sjulian	if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
49270784Sjulian	&& (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) {
49370784Sjulian		ng_rmnode_self(NG_HOOK_NODE(hook));
49470700Sjulian	}
49554097Sarchie	return (0);
49654097Sarchie}
49754097Sarchie
49854097Sarchie/************************************************************************
49954097Sarchie			HELPER STUFF
50054097Sarchie ************************************************************************/
50154097Sarchie
50254097Sarchie/*
50354097Sarchie * Set the BPF program associated with a hook
50454097Sarchie */
50554097Sarchiestatic int
50654097Sarchieng_bpf_setprog(hook_p hook, const struct ng_bpf_hookprog *hp0)
50754097Sarchie{
50870784Sjulian	const hinfo_p hip = NG_HOOK_PRIVATE(hook);
50954097Sarchie	struct ng_bpf_hookprog *hp;
510153214Sjkim#ifdef BPF_JITTER
511153213Sjkim	bpf_jit_filter *jit_prog;
512153214Sjkim#endif
51354097Sarchie	int size;
51454097Sarchie
51554097Sarchie	/* Check program for validity */
51654097Sarchie	if (!bpf_validate(hp0->bpf_prog, hp0->bpf_prog_len))
51754097Sarchie		return (EINVAL);
51854097Sarchie
51954097Sarchie	/* Make a copy of the program */
52054214Sarchie	size = NG_BPF_HOOKPROG_SIZE(hp0->bpf_prog_len);
52170870Sjulian	MALLOC(hp, struct ng_bpf_hookprog *, size, M_NETGRAPH_BPF, M_NOWAIT);
52254097Sarchie	if (hp == NULL)
52354097Sarchie		return (ENOMEM);
52454097Sarchie	bcopy(hp0, hp, size);
525153213Sjkim#ifdef BPF_JITTER
526153213Sjkim	jit_prog = bpf_jitter(hp->bpf_prog, hp->bpf_prog_len);
527153213Sjkim#endif
52854097Sarchie
52954097Sarchie	/* Free previous program, if any, and assign new one */
53054097Sarchie	if (hip->prog != NULL)
53170870Sjulian		FREE(hip->prog, M_NETGRAPH_BPF);
53254097Sarchie	hip->prog = hp;
533153213Sjkim#ifdef BPF_JITTER
534153213Sjkim	if (hip->jit_prog != NULL)
535153213Sjkim		bpf_destroy_jit_filter(hip->jit_prog);
536153214Sjkim	hip->jit_prog = jit_prog;
537153213Sjkim#endif
53854097Sarchie	return (0);
53954097Sarchie}
540