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