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$ 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 77227293Sedstatic MALLOC_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 hook_p hook; 89175974Smav hook_p match; 90175974Smav hook_p nomatch; 9154097Sarchie struct ng_bpf_hookprog *prog; 92153213Sjkim#ifdef BPF_JITTER 93153213Sjkim bpf_jit_filter *jit_prog; 94153213Sjkim#endif 9554097Sarchie struct ng_bpf_hookstat stats; 9654097Sarchie}; 9754097Sarchietypedef struct ng_bpf_hookinfo *hinfo_p; 9854097Sarchie 9954097Sarchie/* Netgraph methods */ 10054097Sarchiestatic ng_constructor_t ng_bpf_constructor; 10154097Sarchiestatic ng_rcvmsg_t ng_bpf_rcvmsg; 10270700Sjulianstatic ng_shutdown_t ng_bpf_shutdown; 10354097Sarchiestatic ng_newhook_t ng_bpf_newhook; 10454097Sarchiestatic ng_rcvdata_t ng_bpf_rcvdata; 10554097Sarchiestatic ng_disconnect_t ng_bpf_disconnect; 10654097Sarchie 107182447Sjkim/* Maximum bpf program instructions */ 108182447Sjkimextern int bpf_maxinsns; 109182447Sjkim 11054097Sarchie/* Internal helper functions */ 11154097Sarchiestatic int ng_bpf_setprog(hook_p hook, const struct ng_bpf_hookprog *hp); 11254097Sarchie 11354097Sarchie/* Parse type for one struct bfp_insn */ 11497685Sarchiestatic const struct ng_parse_struct_field ng_bpf_insn_type_fields[] = { 11564508Sarchie { "code", &ng_parse_hint16_type }, 11664508Sarchie { "jt", &ng_parse_uint8_type }, 11764508Sarchie { "jf", &ng_parse_uint8_type }, 11864508Sarchie { "k", &ng_parse_uint32_type }, 11954097Sarchie { NULL } 12054097Sarchie}; 12154097Sarchiestatic const struct ng_parse_type ng_bpf_insn_type = { 12254097Sarchie &ng_parse_struct_type, 12397685Sarchie &ng_bpf_insn_type_fields 12454097Sarchie}; 12554097Sarchie 12654097Sarchie/* Parse type for the field 'bpf_prog' in struct ng_bpf_hookprog */ 12754097Sarchiestatic int 12854097Sarchieng_bpf_hookprogary_getLength(const struct ng_parse_type *type, 12954097Sarchie const u_char *start, const u_char *buf) 13054097Sarchie{ 13154097Sarchie const struct ng_bpf_hookprog *hp; 13254097Sarchie 13354097Sarchie hp = (const struct ng_bpf_hookprog *) 13454097Sarchie (buf - OFFSETOF(struct ng_bpf_hookprog, bpf_prog)); 13554097Sarchie return hp->bpf_prog_len; 13654097Sarchie} 13754097Sarchie 13854097Sarchiestatic const struct ng_parse_array_info ng_bpf_hookprogary_info = { 13954097Sarchie &ng_bpf_insn_type, 14054097Sarchie &ng_bpf_hookprogary_getLength, 14154097Sarchie NULL 14254097Sarchie}; 14354097Sarchiestatic const struct ng_parse_type ng_bpf_hookprogary_type = { 14454097Sarchie &ng_parse_array_type, 14554097Sarchie &ng_bpf_hookprogary_info 14654097Sarchie}; 14754097Sarchie 14854097Sarchie/* Parse type for struct ng_bpf_hookprog */ 14997685Sarchiestatic const struct ng_parse_struct_field ng_bpf_hookprog_type_fields[] 15054097Sarchie = NG_BPF_HOOKPROG_TYPE_INFO(&ng_bpf_hookprogary_type); 15154097Sarchiestatic const struct ng_parse_type ng_bpf_hookprog_type = { 15254097Sarchie &ng_parse_struct_type, 15397685Sarchie &ng_bpf_hookprog_type_fields 15454097Sarchie}; 15554097Sarchie 15654097Sarchie/* Parse type for struct ng_bpf_hookstat */ 15797685Sarchiestatic const struct ng_parse_struct_field ng_bpf_hookstat_type_fields[] 15897685Sarchie = NG_BPF_HOOKSTAT_TYPE_INFO; 15954097Sarchiestatic const struct ng_parse_type ng_bpf_hookstat_type = { 16054097Sarchie &ng_parse_struct_type, 16197685Sarchie &ng_bpf_hookstat_type_fields 16254097Sarchie}; 16354097Sarchie 16454097Sarchie/* List of commands and how to convert arguments to/from ASCII */ 16554097Sarchiestatic const struct ng_cmdlist ng_bpf_cmdlist[] = { 16654097Sarchie { 16754097Sarchie NGM_BPF_COOKIE, 16854097Sarchie NGM_BPF_SET_PROGRAM, 16954097Sarchie "setprogram", 17054097Sarchie &ng_bpf_hookprog_type, 17154097Sarchie NULL 17254097Sarchie }, 17354097Sarchie { 17454097Sarchie NGM_BPF_COOKIE, 17554097Sarchie NGM_BPF_GET_PROGRAM, 17654097Sarchie "getprogram", 17754097Sarchie &ng_parse_hookbuf_type, 17854097Sarchie &ng_bpf_hookprog_type 17954097Sarchie }, 18054097Sarchie { 18154097Sarchie NGM_BPF_COOKIE, 18254097Sarchie NGM_BPF_GET_STATS, 18354097Sarchie "getstats", 18454097Sarchie &ng_parse_hookbuf_type, 18554097Sarchie &ng_bpf_hookstat_type 18654097Sarchie }, 18754097Sarchie { 18854097Sarchie NGM_BPF_COOKIE, 18954097Sarchie NGM_BPF_CLR_STATS, 19054097Sarchie "clrstats", 19154097Sarchie &ng_parse_hookbuf_type, 19254097Sarchie NULL 19354097Sarchie }, 19454097Sarchie { 19554097Sarchie NGM_BPF_COOKIE, 19654097Sarchie NGM_BPF_GETCLR_STATS, 19754097Sarchie "getclrstats", 19854097Sarchie &ng_parse_hookbuf_type, 19954097Sarchie &ng_bpf_hookstat_type 20054097Sarchie }, 20154097Sarchie { 0 } 20254097Sarchie}; 20354097Sarchie 20454097Sarchie/* Netgraph type descriptor */ 20554097Sarchiestatic struct ng_type typestruct = { 206129823Sjulian .version = NG_ABI_VERSION, 207129823Sjulian .name = NG_BPF_NODE_TYPE, 208129823Sjulian .constructor = ng_bpf_constructor, 209129823Sjulian .rcvmsg = ng_bpf_rcvmsg, 210129823Sjulian .shutdown = ng_bpf_shutdown, 211129823Sjulian .newhook = ng_bpf_newhook, 212129823Sjulian .rcvdata = ng_bpf_rcvdata, 213129823Sjulian .disconnect = ng_bpf_disconnect, 214129823Sjulian .cmdlist = ng_bpf_cmdlist, 21554097Sarchie}; 21654097SarchieNETGRAPH_INIT(bpf, &typestruct); 21754097Sarchie 21854097Sarchie/* Default BPF program for a hook that matches nothing */ 21954097Sarchiestatic const struct ng_bpf_hookprog ng_bpf_default_prog = { 22054097Sarchie { '\0' }, /* to be filled in at hook creation time */ 22154097Sarchie { '\0' }, 22254097Sarchie { '\0' }, 22354097Sarchie 1, 22454097Sarchie { BPF_STMT(BPF_RET+BPF_K, 0) } 22554097Sarchie}; 22654097Sarchie 22754097Sarchie/* 22854097Sarchie * Node constructor 22954097Sarchie * 23054097Sarchie * We don't keep any per-node private data 23170700Sjulian * We go via the hooks. 23254097Sarchie */ 23354097Sarchiestatic int 23470700Sjulianng_bpf_constructor(node_p node) 23554097Sarchie{ 23670784Sjulian NG_NODE_SET_PRIVATE(node, NULL); 23754097Sarchie return (0); 23854097Sarchie} 23954097Sarchie 24054097Sarchie/* 241175974Smav * Callback functions to be used by NG_NODE_FOREACH_HOOK() macro. 242175974Smav */ 243175974Smavstatic int 244175974Smavng_bpf_addrefs(hook_p hook, void* arg) 245175974Smav{ 246175974Smav hinfo_p hip = NG_HOOK_PRIVATE(hook); 247175974Smav hook_p h = (hook_p)arg; 248175974Smav 249175974Smav if (strcmp(hip->prog->ifMatch, NG_HOOK_NAME(h)) == 0) 250175974Smav hip->match = h; 251175974Smav if (strcmp(hip->prog->ifNotMatch, NG_HOOK_NAME(h)) == 0) 252175974Smav hip->nomatch = h; 253175974Smav return (1); 254175974Smav} 255175974Smav 256175974Smavstatic int 257175974Smavng_bpf_remrefs(hook_p hook, void* arg) 258175974Smav{ 259175974Smav hinfo_p hip = NG_HOOK_PRIVATE(hook); 260175974Smav hook_p h = (hook_p)arg; 261175974Smav 262175974Smav if (hip->match == h) 263175974Smav hip->match = NULL; 264175974Smav if (hip->nomatch == h) 265175974Smav hip->nomatch = NULL; 266175974Smav return (1); 267175974Smav} 268175974Smav 269175974Smav/* 27054097Sarchie * Add a hook 27154097Sarchie */ 27254097Sarchiestatic int 27354097Sarchieng_bpf_newhook(node_p node, hook_p hook, const char *name) 27454097Sarchie{ 27554097Sarchie hinfo_p hip; 276175974Smav hook_p tmp; 27754097Sarchie int error; 27854097Sarchie 27954097Sarchie /* Create hook private structure */ 280184205Sdes hip = malloc(sizeof(*hip), M_NETGRAPH_BPF, M_NOWAIT | M_ZERO); 28154097Sarchie if (hip == NULL) 28254097Sarchie return (ENOMEM); 28354097Sarchie hip->hook = hook; 28470784Sjulian NG_HOOK_SET_PRIVATE(hook, hip); 28554097Sarchie 286175974Smav /* Add our reference into other hooks data. */ 287175974Smav NG_NODE_FOREACH_HOOK(node, ng_bpf_addrefs, hook, tmp); 288175974Smav 28954097Sarchie /* Attach the default BPF program */ 29054097Sarchie if ((error = ng_bpf_setprog(hook, &ng_bpf_default_prog)) != 0) { 291184205Sdes free(hip, M_NETGRAPH_BPF); 29270784Sjulian NG_HOOK_SET_PRIVATE(hook, NULL); 29354097Sarchie return (error); 29454097Sarchie } 29554097Sarchie 29654097Sarchie /* Set hook name */ 297175974Smav strlcpy(hip->prog->thisHook, name, sizeof(hip->prog->thisHook)); 29854097Sarchie return (0); 29954097Sarchie} 30054097Sarchie 30154097Sarchie/* 30254097Sarchie * Receive a control message 30354097Sarchie */ 30454097Sarchiestatic int 30570700Sjulianng_bpf_rcvmsg(node_p node, item_p item, hook_p lasthook) 30654097Sarchie{ 30770700Sjulian struct ng_mesg *msg; 30854097Sarchie struct ng_mesg *resp = NULL; 30954097Sarchie int error = 0; 31054097Sarchie 31170700Sjulian NGI_GET_MSG(item, msg); 31254097Sarchie switch (msg->header.typecookie) { 31354097Sarchie case NGM_BPF_COOKIE: 31454097Sarchie switch (msg->header.cmd) { 31554097Sarchie case NGM_BPF_SET_PROGRAM: 31654097Sarchie { 31754097Sarchie struct ng_bpf_hookprog *const 31854097Sarchie hp = (struct ng_bpf_hookprog *)msg->data; 31954097Sarchie hook_p hook; 32054097Sarchie 32154097Sarchie /* Sanity check */ 32254097Sarchie if (msg->header.arglen < sizeof(*hp) 32354214Sarchie || msg->header.arglen 32454214Sarchie != NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len)) 32554097Sarchie ERROUT(EINVAL); 32654097Sarchie 32754097Sarchie /* Find hook */ 32854097Sarchie if ((hook = ng_findhook(node, hp->thisHook)) == NULL) 32954097Sarchie ERROUT(ENOENT); 33054097Sarchie 33154097Sarchie /* Set new program */ 33254097Sarchie if ((error = ng_bpf_setprog(hook, hp)) != 0) 33354097Sarchie ERROUT(error); 33454097Sarchie break; 33554097Sarchie } 33654097Sarchie 33754097Sarchie case NGM_BPF_GET_PROGRAM: 33854097Sarchie { 33954214Sarchie struct ng_bpf_hookprog *hp; 34054097Sarchie hook_p hook; 34154097Sarchie 34254097Sarchie /* Sanity check */ 34354097Sarchie if (msg->header.arglen == 0) 34454097Sarchie ERROUT(EINVAL); 34554097Sarchie msg->data[msg->header.arglen - 1] = '\0'; 34654097Sarchie 34754097Sarchie /* Find hook */ 34854097Sarchie if ((hook = ng_findhook(node, msg->data)) == NULL) 34954097Sarchie ERROUT(ENOENT); 35054097Sarchie 35154097Sarchie /* Build response */ 35270784Sjulian hp = ((hinfo_p)NG_HOOK_PRIVATE(hook))->prog; 35354097Sarchie NG_MKRESPONSE(resp, msg, 35454214Sarchie NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len), M_NOWAIT); 35554097Sarchie if (resp == NULL) 35654097Sarchie ERROUT(ENOMEM); 35754214Sarchie bcopy(hp, resp->data, 35854214Sarchie NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len)); 35954097Sarchie break; 36054097Sarchie } 36154097Sarchie 36254097Sarchie case NGM_BPF_GET_STATS: 36354097Sarchie case NGM_BPF_CLR_STATS: 36454097Sarchie case NGM_BPF_GETCLR_STATS: 36554097Sarchie { 36654097Sarchie struct ng_bpf_hookstat *stats; 36754097Sarchie hook_p hook; 36854097Sarchie 36954097Sarchie /* Sanity check */ 37054097Sarchie if (msg->header.arglen == 0) 37154097Sarchie ERROUT(EINVAL); 37254097Sarchie msg->data[msg->header.arglen - 1] = '\0'; 37354097Sarchie 37454097Sarchie /* Find hook */ 37554097Sarchie if ((hook = ng_findhook(node, msg->data)) == NULL) 37654097Sarchie ERROUT(ENOENT); 37770784Sjulian stats = &((hinfo_p)NG_HOOK_PRIVATE(hook))->stats; 37854097Sarchie 37954097Sarchie /* Build response (if desired) */ 38054097Sarchie if (msg->header.cmd != NGM_BPF_CLR_STATS) { 38154097Sarchie NG_MKRESPONSE(resp, 38254097Sarchie msg, sizeof(*stats), M_NOWAIT); 38354097Sarchie if (resp == NULL) 38454097Sarchie ERROUT(ENOMEM); 38554097Sarchie bcopy(stats, resp->data, sizeof(*stats)); 38654097Sarchie } 38754097Sarchie 38854097Sarchie /* Clear stats (if desired) */ 38954097Sarchie if (msg->header.cmd != NGM_BPF_GET_STATS) 39054097Sarchie bzero(stats, sizeof(*stats)); 39154097Sarchie break; 39254097Sarchie } 39354097Sarchie 39454097Sarchie default: 39554097Sarchie error = EINVAL; 39654097Sarchie break; 39754097Sarchie } 39854097Sarchie break; 39954097Sarchie default: 40054097Sarchie error = EINVAL; 40154097Sarchie break; 40254097Sarchie } 40370933Sjuliandone: 40470700Sjulian NG_RESPOND_MSG(error, node, item, resp); 40570700Sjulian NG_FREE_MSG(msg); 40654097Sarchie return (error); 40754097Sarchie} 40854097Sarchie 40954097Sarchie/* 41054097Sarchie * Receive data on a hook 41154097Sarchie * 41254097Sarchie * Apply the filter, and then drop or forward packet as appropriate. 41354097Sarchie */ 41454097Sarchiestatic int 41570700Sjulianng_bpf_rcvdata(hook_p hook, item_p item) 41654097Sarchie{ 41770784Sjulian const hinfo_p hip = NG_HOOK_PRIVATE(hook); 41870700Sjulian int totlen; 419175776Smav int needfree = 0, error = 0, usejit = 0; 420175776Smav u_char *data = NULL; 42154097Sarchie hinfo_p dhip; 42254097Sarchie hook_p dest; 42354097Sarchie u_int len; 42470700Sjulian struct mbuf *m; 42554097Sarchie 42670700Sjulian m = NGI_M(item); /* 'item' still owns it.. we are peeking */ 42770700Sjulian totlen = m->m_pkthdr.len; 42870700Sjulian /* Update stats on incoming hook. XXX Can we do 64 bits atomically? */ 42970700Sjulian /* atomic_add_int64(&hip->stats.recvFrames, 1); */ 43070700Sjulian /* atomic_add_int64(&hip->stats.recvOctets, totlen); */ 43170700Sjulian hip->stats.recvFrames++; 43254097Sarchie hip->stats.recvOctets += totlen; 43354097Sarchie 434175974Smav /* Don't call bpf_filter() with totlen == 0! */ 435175974Smav if (totlen == 0) { 436175974Smav len = 0; 437175974Smav goto ready; 438175974Smav } 439175974Smav 440175776Smav#ifdef BPF_JITTER 441175776Smav if (bpf_jitter_enable != 0 && hip->jit_prog != NULL) 442175776Smav usejit = 1; 443175776Smav#endif 444175776Smav 44554097Sarchie /* Need to put packet in contiguous memory for bpf */ 446175776Smav if (m->m_next != NULL && totlen > MHLEN) { 447175776Smav if (usejit) { 448184205Sdes data = malloc(totlen, M_NETGRAPH_BPF, M_NOWAIT); 44954097Sarchie if (data == NULL) { 45070700Sjulian NG_FREE_ITEM(item); 45154097Sarchie return (ENOMEM); 45254097Sarchie } 45354097Sarchie needfree = 1; 454171600Smav m_copydata(m, 0, totlen, (caddr_t)data); 455175776Smav } 456175776Smav } else { 457175776Smav if (m->m_next != NULL) { 458171600Smav NGI_M(item) = m = m_pullup(m, totlen); 459171600Smav if (m == NULL) { 460171600Smav NG_FREE_ITEM(item); 461171600Smav return (ENOBUFS); 462171600Smav } 463171600Smav } 46454097Sarchie data = mtod(m, u_char *); 465175776Smav } 46654097Sarchie 46754097Sarchie /* Run packet through filter */ 468153213Sjkim#ifdef BPF_JITTER 469175974Smav if (usejit) 470175974Smav len = (*(hip->jit_prog->func))(data, totlen, totlen); 471175974Smav else 472153213Sjkim#endif 473175974Smav if (data) 474175974Smav len = bpf_filter(hip->prog->bpf_prog, data, totlen, totlen); 475175974Smav else 476175974Smav len = bpf_filter(hip->prog->bpf_prog, (u_char *)m, totlen, 0); 47754097Sarchie if (needfree) 478184205Sdes free(data, M_NETGRAPH_BPF); 479175974Smavready: 48054097Sarchie /* See if we got a match and find destination hook */ 48154097Sarchie if (len > 0) { 48254097Sarchie 48354097Sarchie /* Update stats */ 48470700Sjulian /* XXX atomically? */ 48554097Sarchie hip->stats.recvMatchFrames++; 48654097Sarchie hip->stats.recvMatchOctets += totlen; 48754097Sarchie 48854097Sarchie /* Truncate packet length if required by the filter */ 48970700Sjulian /* Assume this never changes m */ 49054097Sarchie if (len < totlen) { 49154097Sarchie m_adj(m, -(totlen - len)); 492175974Smav totlen = len; 49354097Sarchie } 494175974Smav dest = hip->match; 49554097Sarchie } else 496175974Smav dest = hip->nomatch; 49754097Sarchie if (dest == NULL) { 49870700Sjulian NG_FREE_ITEM(item); 49954097Sarchie return (0); 50054097Sarchie } 50154097Sarchie 50254097Sarchie /* Deliver frame out destination hook */ 50370784Sjulian dhip = NG_HOOK_PRIVATE(dest); 50454097Sarchie dhip->stats.xmitOctets += totlen; 50554097Sarchie dhip->stats.xmitFrames++; 50670784Sjulian NG_FWD_ITEM_HOOK(error, item, dest); 50754097Sarchie return (error); 50854097Sarchie} 50954097Sarchie 51054097Sarchie/* 51154097Sarchie * Shutdown processing 51254097Sarchie */ 51354097Sarchiestatic int 51470700Sjulianng_bpf_shutdown(node_p node) 51554097Sarchie{ 51670784Sjulian NG_NODE_UNREF(node); 51754097Sarchie return (0); 51854097Sarchie} 51954097Sarchie 52054097Sarchie/* 52154097Sarchie * Hook disconnection 52254097Sarchie */ 52354097Sarchiestatic int 52454097Sarchieng_bpf_disconnect(hook_p hook) 52554097Sarchie{ 526175974Smav const node_p node = NG_HOOK_NODE(hook); 52770784Sjulian const hinfo_p hip = NG_HOOK_PRIVATE(hook); 528175974Smav hook_p tmp; 52954097Sarchie 53087599Sobrien KASSERT(hip != NULL, ("%s: null info", __func__)); 531175974Smav 532175974Smav /* Remove our reference from other hooks data. */ 533175974Smav NG_NODE_FOREACH_HOOK(node, ng_bpf_remrefs, hook, tmp); 534175974Smav 535184205Sdes free(hip->prog, M_NETGRAPH_BPF); 536153213Sjkim#ifdef BPF_JITTER 537153213Sjkim if (hip->jit_prog != NULL) 538153213Sjkim bpf_destroy_jit_filter(hip->jit_prog); 539153213Sjkim#endif 540184205Sdes free(hip, M_NETGRAPH_BPF); 541175974Smav if ((NG_NODE_NUMHOOKS(node) == 0) && 542175974Smav (NG_NODE_IS_VALID(node))) { 543175974Smav ng_rmnode_self(node); 54470700Sjulian } 54554097Sarchie return (0); 54654097Sarchie} 54754097Sarchie 54854097Sarchie/************************************************************************ 54954097Sarchie HELPER STUFF 55054097Sarchie ************************************************************************/ 55154097Sarchie 55254097Sarchie/* 55354097Sarchie * Set the BPF program associated with a hook 55454097Sarchie */ 55554097Sarchiestatic int 55654097Sarchieng_bpf_setprog(hook_p hook, const struct ng_bpf_hookprog *hp0) 55754097Sarchie{ 55870784Sjulian const hinfo_p hip = NG_HOOK_PRIVATE(hook); 55954097Sarchie struct ng_bpf_hookprog *hp; 560153214Sjkim#ifdef BPF_JITTER 561153213Sjkim bpf_jit_filter *jit_prog; 562153214Sjkim#endif 56354097Sarchie int size; 56454097Sarchie 56554097Sarchie /* Check program for validity */ 566182447Sjkim if (hp0->bpf_prog_len > bpf_maxinsns || 567182447Sjkim !bpf_validate(hp0->bpf_prog, hp0->bpf_prog_len)) 56854097Sarchie return (EINVAL); 56954097Sarchie 57054097Sarchie /* Make a copy of the program */ 57154214Sarchie size = NG_BPF_HOOKPROG_SIZE(hp0->bpf_prog_len); 572184205Sdes hp = malloc(size, M_NETGRAPH_BPF, M_NOWAIT); 57354097Sarchie if (hp == NULL) 57454097Sarchie return (ENOMEM); 57554097Sarchie bcopy(hp0, hp, size); 576153213Sjkim#ifdef BPF_JITTER 577153213Sjkim jit_prog = bpf_jitter(hp->bpf_prog, hp->bpf_prog_len); 578153213Sjkim#endif 57954097Sarchie 58054097Sarchie /* Free previous program, if any, and assign new one */ 58154097Sarchie if (hip->prog != NULL) 582184205Sdes free(hip->prog, M_NETGRAPH_BPF); 58354097Sarchie hip->prog = hp; 584153213Sjkim#ifdef BPF_JITTER 585153213Sjkim if (hip->jit_prog != NULL) 586153213Sjkim bpf_destroy_jit_filter(hip->jit_prog); 587153214Sjkim hip->jit_prog = jit_prog; 588153213Sjkim#endif 589175974Smav 590175974Smav /* Prepare direct references on target hooks. */ 591175974Smav hip->match = ng_findhook(NG_HOOK_NODE(hook), hip->prog->ifMatch); 592175974Smav hip->nomatch = ng_findhook(NG_HOOK_NODE(hook), hip->prog->ifNotMatch); 59354097Sarchie return (0); 59454097Sarchie} 595