192a3e552SArchie Cobbs 292a3e552SArchie Cobbs /* 392a3e552SArchie Cobbs * ng_bpf.c 492a3e552SArchie Cobbs * 592a3e552SArchie Cobbs * Copyright (c) 1999 Whistle Communications, Inc. 692a3e552SArchie Cobbs * All rights reserved. 792a3e552SArchie Cobbs * 892a3e552SArchie Cobbs * Subject to the following obligations and disclaimer of warranty, use and 992a3e552SArchie Cobbs * redistribution of this software, in source or object code forms, with or 1092a3e552SArchie Cobbs * without modifications are expressly permitted by Whistle Communications; 1192a3e552SArchie Cobbs * provided, however, that: 1292a3e552SArchie Cobbs * 1. Any and all reproductions of the source or object code must include the 1392a3e552SArchie Cobbs * copyright notice above and the following disclaimer of warranties; and 1492a3e552SArchie Cobbs * 2. No rights are granted, in any manner or form, to use Whistle 1592a3e552SArchie Cobbs * Communications, Inc. trademarks, including the mark "WHISTLE 1692a3e552SArchie Cobbs * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 1792a3e552SArchie Cobbs * such appears in the above copyright notice or in the software. 1892a3e552SArchie Cobbs * 1992a3e552SArchie Cobbs * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 2092a3e552SArchie Cobbs * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 2192a3e552SArchie Cobbs * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 2292a3e552SArchie Cobbs * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 2392a3e552SArchie Cobbs * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 2492a3e552SArchie Cobbs * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANBPF, OR MAKE ANY 2592a3e552SArchie Cobbs * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 2692a3e552SArchie Cobbs * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 2792a3e552SArchie Cobbs * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 2892a3e552SArchie Cobbs * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 2992a3e552SArchie Cobbs * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 3092a3e552SArchie Cobbs * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 3192a3e552SArchie Cobbs * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 3292a3e552SArchie Cobbs * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3392a3e552SArchie Cobbs * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3492a3e552SArchie Cobbs * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 3592a3e552SArchie Cobbs * OF SUCH DAMAGE. 3692a3e552SArchie Cobbs * 37cc3bbd68SJulian Elischer * Author: Archie Cobbs <archie@freebsd.org> 3892a3e552SArchie Cobbs * 3992a3e552SArchie Cobbs * $FreeBSD$ 4092a3e552SArchie Cobbs * $Whistle: ng_bpf.c,v 1.3 1999/12/03 20:30:23 archie Exp $ 4192a3e552SArchie Cobbs */ 4292a3e552SArchie Cobbs 4392a3e552SArchie Cobbs /* 4492a3e552SArchie Cobbs * BPF NETGRAPH NODE TYPE 4592a3e552SArchie Cobbs * 4692a3e552SArchie Cobbs * This node type accepts any number of hook connections. With each hook 4792a3e552SArchie Cobbs * is associated a bpf(4) filter program, and two hook names (each possibly 4892a3e552SArchie Cobbs * the empty string). Incoming packets are compared against the filter; 4992a3e552SArchie Cobbs * matching packets are delivered out the first named hook (or dropped if 5092a3e552SArchie Cobbs * the empty string), and non-matching packets are delivered out the second 5192a3e552SArchie Cobbs * named hook (or dropped if the empty string). 5292a3e552SArchie Cobbs * 5392a3e552SArchie Cobbs * Each hook also keeps statistics about how many packets have matched, etc. 5492a3e552SArchie Cobbs */ 5592a3e552SArchie Cobbs 5692a3e552SArchie Cobbs #include <sys/param.h> 5792a3e552SArchie Cobbs #include <sys/systm.h> 5892a3e552SArchie Cobbs #include <sys/errno.h> 5992a3e552SArchie Cobbs #include <sys/kernel.h> 6092a3e552SArchie Cobbs #include <sys/malloc.h> 6192a3e552SArchie Cobbs #include <sys/mbuf.h> 6292a3e552SArchie Cobbs 6392a3e552SArchie Cobbs #include <net/bpf.h> 6492a3e552SArchie Cobbs 6592a3e552SArchie Cobbs #include <netgraph/ng_message.h> 6692a3e552SArchie Cobbs #include <netgraph/netgraph.h> 6792a3e552SArchie Cobbs #include <netgraph/ng_parse.h> 6892a3e552SArchie Cobbs #include <netgraph/ng_bpf.h> 6992a3e552SArchie Cobbs 7092a3e552SArchie Cobbs #define OFFSETOF(s, e) ((char *)&((s *)0)->e - (char *)((s *)0)) 7192a3e552SArchie Cobbs 7292a3e552SArchie Cobbs #define ERROUT(x) do { error = (x); goto done; } while (0) 7392a3e552SArchie Cobbs 7492a3e552SArchie Cobbs /* Per hook private info */ 7592a3e552SArchie Cobbs struct ng_bpf_hookinfo { 7692a3e552SArchie Cobbs node_p node; 7792a3e552SArchie Cobbs hook_p hook; 7892a3e552SArchie Cobbs struct ng_bpf_hookprog *prog; 7992a3e552SArchie Cobbs struct ng_bpf_hookstat stats; 8092a3e552SArchie Cobbs }; 8192a3e552SArchie Cobbs typedef struct ng_bpf_hookinfo *hinfo_p; 8292a3e552SArchie Cobbs 8392a3e552SArchie Cobbs /* Netgraph methods */ 8492a3e552SArchie Cobbs static ng_constructor_t ng_bpf_constructor; 8592a3e552SArchie Cobbs static ng_rcvmsg_t ng_bpf_rcvmsg; 86069154d5SJulian Elischer static ng_shutdown_t ng_bpf_shutdown; 8792a3e552SArchie Cobbs static ng_newhook_t ng_bpf_newhook; 8892a3e552SArchie Cobbs static ng_rcvdata_t ng_bpf_rcvdata; 8992a3e552SArchie Cobbs static ng_disconnect_t ng_bpf_disconnect; 9092a3e552SArchie Cobbs 9192a3e552SArchie Cobbs /* Internal helper functions */ 9292a3e552SArchie Cobbs static int ng_bpf_setprog(hook_p hook, const struct ng_bpf_hookprog *hp); 9392a3e552SArchie Cobbs 9492a3e552SArchie Cobbs /* Parse type for one struct bfp_insn */ 9592a3e552SArchie Cobbs static const struct ng_parse_struct_info ng_bpf_insn_type_info = { 9692a3e552SArchie Cobbs { 9757b57be3SArchie Cobbs { "code", &ng_parse_hint16_type }, 9857b57be3SArchie Cobbs { "jt", &ng_parse_uint8_type }, 9957b57be3SArchie Cobbs { "jf", &ng_parse_uint8_type }, 10057b57be3SArchie Cobbs { "k", &ng_parse_uint32_type }, 10192a3e552SArchie Cobbs { NULL } 10292a3e552SArchie Cobbs } 10392a3e552SArchie Cobbs }; 10492a3e552SArchie Cobbs static const struct ng_parse_type ng_bpf_insn_type = { 10592a3e552SArchie Cobbs &ng_parse_struct_type, 10692a3e552SArchie Cobbs &ng_bpf_insn_type_info 10792a3e552SArchie Cobbs }; 10892a3e552SArchie Cobbs 10992a3e552SArchie Cobbs /* Parse type for the field 'bpf_prog' in struct ng_bpf_hookprog */ 11092a3e552SArchie Cobbs static int 11192a3e552SArchie Cobbs ng_bpf_hookprogary_getLength(const struct ng_parse_type *type, 11292a3e552SArchie Cobbs const u_char *start, const u_char *buf) 11392a3e552SArchie Cobbs { 11492a3e552SArchie Cobbs const struct ng_bpf_hookprog *hp; 11592a3e552SArchie Cobbs 11692a3e552SArchie Cobbs hp = (const struct ng_bpf_hookprog *) 11792a3e552SArchie Cobbs (buf - OFFSETOF(struct ng_bpf_hookprog, bpf_prog)); 11892a3e552SArchie Cobbs return hp->bpf_prog_len; 11992a3e552SArchie Cobbs } 12092a3e552SArchie Cobbs 12192a3e552SArchie Cobbs static const struct ng_parse_array_info ng_bpf_hookprogary_info = { 12292a3e552SArchie Cobbs &ng_bpf_insn_type, 12392a3e552SArchie Cobbs &ng_bpf_hookprogary_getLength, 12492a3e552SArchie Cobbs NULL 12592a3e552SArchie Cobbs }; 12692a3e552SArchie Cobbs static const struct ng_parse_type ng_bpf_hookprogary_type = { 12792a3e552SArchie Cobbs &ng_parse_array_type, 12892a3e552SArchie Cobbs &ng_bpf_hookprogary_info 12992a3e552SArchie Cobbs }; 13092a3e552SArchie Cobbs 13192a3e552SArchie Cobbs /* Parse type for struct ng_bpf_hookprog */ 13292a3e552SArchie Cobbs static const struct ng_parse_struct_info ng_bpf_hookprog_type_info 13392a3e552SArchie Cobbs = NG_BPF_HOOKPROG_TYPE_INFO(&ng_bpf_hookprogary_type); 13492a3e552SArchie Cobbs static const struct ng_parse_type ng_bpf_hookprog_type = { 13592a3e552SArchie Cobbs &ng_parse_struct_type, 13692a3e552SArchie Cobbs &ng_bpf_hookprog_type_info 13792a3e552SArchie Cobbs }; 13892a3e552SArchie Cobbs 13992a3e552SArchie Cobbs /* Parse type for struct ng_bpf_hookstat */ 14092a3e552SArchie Cobbs static const struct ng_parse_struct_info 14192a3e552SArchie Cobbs ng_bpf_hookstat_type_info = NG_BPF_HOOKSTAT_TYPE_INFO; 14292a3e552SArchie Cobbs static const struct ng_parse_type ng_bpf_hookstat_type = { 14392a3e552SArchie Cobbs &ng_parse_struct_type, 14492a3e552SArchie Cobbs &ng_bpf_hookstat_type_info 14592a3e552SArchie Cobbs }; 14692a3e552SArchie Cobbs 14792a3e552SArchie Cobbs /* List of commands and how to convert arguments to/from ASCII */ 14892a3e552SArchie Cobbs static const struct ng_cmdlist ng_bpf_cmdlist[] = { 14992a3e552SArchie Cobbs { 15092a3e552SArchie Cobbs NGM_BPF_COOKIE, 15192a3e552SArchie Cobbs NGM_BPF_SET_PROGRAM, 15292a3e552SArchie Cobbs "setprogram", 15392a3e552SArchie Cobbs &ng_bpf_hookprog_type, 15492a3e552SArchie Cobbs NULL 15592a3e552SArchie Cobbs }, 15692a3e552SArchie Cobbs { 15792a3e552SArchie Cobbs NGM_BPF_COOKIE, 15892a3e552SArchie Cobbs NGM_BPF_GET_PROGRAM, 15992a3e552SArchie Cobbs "getprogram", 16092a3e552SArchie Cobbs &ng_parse_hookbuf_type, 16192a3e552SArchie Cobbs &ng_bpf_hookprog_type 16292a3e552SArchie Cobbs }, 16392a3e552SArchie Cobbs { 16492a3e552SArchie Cobbs NGM_BPF_COOKIE, 16592a3e552SArchie Cobbs NGM_BPF_GET_STATS, 16692a3e552SArchie Cobbs "getstats", 16792a3e552SArchie Cobbs &ng_parse_hookbuf_type, 16892a3e552SArchie Cobbs &ng_bpf_hookstat_type 16992a3e552SArchie Cobbs }, 17092a3e552SArchie Cobbs { 17192a3e552SArchie Cobbs NGM_BPF_COOKIE, 17292a3e552SArchie Cobbs NGM_BPF_CLR_STATS, 17392a3e552SArchie Cobbs "clrstats", 17492a3e552SArchie Cobbs &ng_parse_hookbuf_type, 17592a3e552SArchie Cobbs NULL 17692a3e552SArchie Cobbs }, 17792a3e552SArchie Cobbs { 17892a3e552SArchie Cobbs NGM_BPF_COOKIE, 17992a3e552SArchie Cobbs NGM_BPF_GETCLR_STATS, 18092a3e552SArchie Cobbs "getclrstats", 18192a3e552SArchie Cobbs &ng_parse_hookbuf_type, 18292a3e552SArchie Cobbs &ng_bpf_hookstat_type 18392a3e552SArchie Cobbs }, 18492a3e552SArchie Cobbs { 0 } 18592a3e552SArchie Cobbs }; 18692a3e552SArchie Cobbs 18792a3e552SArchie Cobbs /* Netgraph type descriptor */ 18892a3e552SArchie Cobbs static struct ng_type typestruct = { 189589f6ed8SJulian Elischer NG_ABI_VERSION, 19092a3e552SArchie Cobbs NG_BPF_NODE_TYPE, 19192a3e552SArchie Cobbs NULL, 19292a3e552SArchie Cobbs ng_bpf_constructor, 19392a3e552SArchie Cobbs ng_bpf_rcvmsg, 194069154d5SJulian Elischer ng_bpf_shutdown, 19592a3e552SArchie Cobbs ng_bpf_newhook, 19692a3e552SArchie Cobbs NULL, 19792a3e552SArchie Cobbs NULL, 19892a3e552SArchie Cobbs ng_bpf_rcvdata, 19992a3e552SArchie Cobbs ng_bpf_disconnect, 20092a3e552SArchie Cobbs ng_bpf_cmdlist 20192a3e552SArchie Cobbs }; 20292a3e552SArchie Cobbs NETGRAPH_INIT(bpf, &typestruct); 20392a3e552SArchie Cobbs 20492a3e552SArchie Cobbs /* Default BPF program for a hook that matches nothing */ 20592a3e552SArchie Cobbs static const struct ng_bpf_hookprog ng_bpf_default_prog = { 20692a3e552SArchie Cobbs { '\0' }, /* to be filled in at hook creation time */ 20792a3e552SArchie Cobbs { '\0' }, 20892a3e552SArchie Cobbs { '\0' }, 20992a3e552SArchie Cobbs 1, 21092a3e552SArchie Cobbs { BPF_STMT(BPF_RET+BPF_K, 0) } 21192a3e552SArchie Cobbs }; 21292a3e552SArchie Cobbs 21392a3e552SArchie Cobbs /* 21492a3e552SArchie Cobbs * Node constructor 21592a3e552SArchie Cobbs * 21692a3e552SArchie Cobbs * We don't keep any per-node private data 217069154d5SJulian Elischer * We go via the hooks. 21892a3e552SArchie Cobbs */ 21992a3e552SArchie Cobbs static int 220069154d5SJulian Elischer ng_bpf_constructor(node_p node) 22192a3e552SArchie Cobbs { 222069154d5SJulian Elischer node->private = NULL; 22392a3e552SArchie Cobbs return (0); 22492a3e552SArchie Cobbs } 22592a3e552SArchie Cobbs 22692a3e552SArchie Cobbs /* 22792a3e552SArchie Cobbs * Add a hook 22892a3e552SArchie Cobbs */ 22992a3e552SArchie Cobbs static int 23092a3e552SArchie Cobbs ng_bpf_newhook(node_p node, hook_p hook, const char *name) 23192a3e552SArchie Cobbs { 23292a3e552SArchie Cobbs hinfo_p hip; 23392a3e552SArchie Cobbs int error; 23492a3e552SArchie Cobbs 23592a3e552SArchie Cobbs /* Create hook private structure */ 23699cdf4ccSDavid Malone MALLOC(hip, hinfo_p, sizeof(*hip), M_NETGRAPH, M_NOWAIT | M_ZERO); 23792a3e552SArchie Cobbs if (hip == NULL) 23892a3e552SArchie Cobbs return (ENOMEM); 23992a3e552SArchie Cobbs hip->hook = hook; 24092a3e552SArchie Cobbs hook->private = hip; 24192a3e552SArchie Cobbs hip->node = node; 24292a3e552SArchie Cobbs 24392a3e552SArchie Cobbs /* Attach the default BPF program */ 24492a3e552SArchie Cobbs if ((error = ng_bpf_setprog(hook, &ng_bpf_default_prog)) != 0) { 24592a3e552SArchie Cobbs FREE(hip, M_NETGRAPH); 24692a3e552SArchie Cobbs hook->private = NULL; 24792a3e552SArchie Cobbs return (error); 24892a3e552SArchie Cobbs } 24992a3e552SArchie Cobbs 25092a3e552SArchie Cobbs /* Set hook name */ 25192a3e552SArchie Cobbs strncpy(hip->prog->thisHook, name, sizeof(hip->prog->thisHook) - 1); 25292a3e552SArchie Cobbs hip->prog->thisHook[sizeof(hip->prog->thisHook) - 1] = '\0'; 25392a3e552SArchie Cobbs return (0); 25492a3e552SArchie Cobbs } 25592a3e552SArchie Cobbs 25692a3e552SArchie Cobbs /* 25792a3e552SArchie Cobbs * Receive a control message 25892a3e552SArchie Cobbs */ 25992a3e552SArchie Cobbs static int 260069154d5SJulian Elischer ng_bpf_rcvmsg(node_p node, item_p item, hook_p lasthook) 26192a3e552SArchie Cobbs { 262069154d5SJulian Elischer struct ng_mesg *msg; 26392a3e552SArchie Cobbs struct ng_mesg *resp = NULL; 26492a3e552SArchie Cobbs int error = 0; 26592a3e552SArchie Cobbs 266069154d5SJulian Elischer NGI_GET_MSG(item, msg); 26792a3e552SArchie Cobbs switch (msg->header.typecookie) { 26892a3e552SArchie Cobbs case NGM_BPF_COOKIE: 26992a3e552SArchie Cobbs switch (msg->header.cmd) { 27092a3e552SArchie Cobbs case NGM_BPF_SET_PROGRAM: 27192a3e552SArchie Cobbs { 27292a3e552SArchie Cobbs struct ng_bpf_hookprog *const 27392a3e552SArchie Cobbs hp = (struct ng_bpf_hookprog *)msg->data; 27492a3e552SArchie Cobbs hook_p hook; 27592a3e552SArchie Cobbs 27692a3e552SArchie Cobbs /* Sanity check */ 27792a3e552SArchie Cobbs if (msg->header.arglen < sizeof(*hp) 278ab0d3c94SArchie Cobbs || msg->header.arglen 279ab0d3c94SArchie Cobbs != NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len)) 28092a3e552SArchie Cobbs ERROUT(EINVAL); 28192a3e552SArchie Cobbs 28292a3e552SArchie Cobbs /* Find hook */ 28392a3e552SArchie Cobbs if ((hook = ng_findhook(node, hp->thisHook)) == NULL) 28492a3e552SArchie Cobbs ERROUT(ENOENT); 28592a3e552SArchie Cobbs 28692a3e552SArchie Cobbs /* Set new program */ 28792a3e552SArchie Cobbs if ((error = ng_bpf_setprog(hook, hp)) != 0) 28892a3e552SArchie Cobbs ERROUT(error); 28992a3e552SArchie Cobbs break; 29092a3e552SArchie Cobbs } 29192a3e552SArchie Cobbs 29292a3e552SArchie Cobbs case NGM_BPF_GET_PROGRAM: 29392a3e552SArchie Cobbs { 294ab0d3c94SArchie Cobbs struct ng_bpf_hookprog *hp; 29592a3e552SArchie Cobbs hook_p hook; 29692a3e552SArchie Cobbs 29792a3e552SArchie Cobbs /* Sanity check */ 29892a3e552SArchie Cobbs if (msg->header.arglen == 0) 29992a3e552SArchie Cobbs ERROUT(EINVAL); 30092a3e552SArchie Cobbs msg->data[msg->header.arglen - 1] = '\0'; 30192a3e552SArchie Cobbs 30292a3e552SArchie Cobbs /* Find hook */ 30392a3e552SArchie Cobbs if ((hook = ng_findhook(node, msg->data)) == NULL) 30492a3e552SArchie Cobbs ERROUT(ENOENT); 30592a3e552SArchie Cobbs 30692a3e552SArchie Cobbs /* Build response */ 307ab0d3c94SArchie Cobbs hp = ((hinfo_p)hook->private)->prog; 30892a3e552SArchie Cobbs NG_MKRESPONSE(resp, msg, 309ab0d3c94SArchie Cobbs NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len), M_NOWAIT); 31092a3e552SArchie Cobbs if (resp == NULL) 31192a3e552SArchie Cobbs ERROUT(ENOMEM); 312ab0d3c94SArchie Cobbs bcopy(hp, resp->data, 313ab0d3c94SArchie Cobbs NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len)); 31492a3e552SArchie Cobbs break; 31592a3e552SArchie Cobbs } 31692a3e552SArchie Cobbs 31792a3e552SArchie Cobbs case NGM_BPF_GET_STATS: 31892a3e552SArchie Cobbs case NGM_BPF_CLR_STATS: 31992a3e552SArchie Cobbs case NGM_BPF_GETCLR_STATS: 32092a3e552SArchie Cobbs { 32192a3e552SArchie Cobbs struct ng_bpf_hookstat *stats; 32292a3e552SArchie Cobbs hook_p hook; 32392a3e552SArchie Cobbs 32492a3e552SArchie Cobbs /* Sanity check */ 32592a3e552SArchie Cobbs if (msg->header.arglen == 0) 32692a3e552SArchie Cobbs ERROUT(EINVAL); 32792a3e552SArchie Cobbs msg->data[msg->header.arglen - 1] = '\0'; 32892a3e552SArchie Cobbs 32992a3e552SArchie Cobbs /* Find hook */ 33092a3e552SArchie Cobbs if ((hook = ng_findhook(node, msg->data)) == NULL) 33192a3e552SArchie Cobbs ERROUT(ENOENT); 33292a3e552SArchie Cobbs stats = &((hinfo_p)hook->private)->stats; 33392a3e552SArchie Cobbs 33492a3e552SArchie Cobbs /* Build response (if desired) */ 33592a3e552SArchie Cobbs if (msg->header.cmd != NGM_BPF_CLR_STATS) { 33692a3e552SArchie Cobbs NG_MKRESPONSE(resp, 33792a3e552SArchie Cobbs msg, sizeof(*stats), M_NOWAIT); 33892a3e552SArchie Cobbs if (resp == NULL) 33992a3e552SArchie Cobbs ERROUT(ENOMEM); 34092a3e552SArchie Cobbs bcopy(stats, resp->data, sizeof(*stats)); 34192a3e552SArchie Cobbs } 34292a3e552SArchie Cobbs 34392a3e552SArchie Cobbs /* Clear stats (if desired) */ 34492a3e552SArchie Cobbs if (msg->header.cmd != NGM_BPF_GET_STATS) 34592a3e552SArchie Cobbs bzero(stats, sizeof(*stats)); 34692a3e552SArchie Cobbs break; 34792a3e552SArchie Cobbs } 34892a3e552SArchie Cobbs 34992a3e552SArchie Cobbs default: 35092a3e552SArchie Cobbs error = EINVAL; 35192a3e552SArchie Cobbs break; 35292a3e552SArchie Cobbs } 35392a3e552SArchie Cobbs break; 35492a3e552SArchie Cobbs default: 35592a3e552SArchie Cobbs error = EINVAL; 35692a3e552SArchie Cobbs break; 35792a3e552SArchie Cobbs } 358069154d5SJulian Elischer NG_RESPOND_MSG(error, node, item, resp); 35992a3e552SArchie Cobbs done: 360069154d5SJulian Elischer if (item) 361069154d5SJulian Elischer NG_FREE_ITEM(item); 362069154d5SJulian Elischer NG_FREE_MSG(msg); 36392a3e552SArchie Cobbs return (error); 36492a3e552SArchie Cobbs } 36592a3e552SArchie Cobbs 36692a3e552SArchie Cobbs /* 36792a3e552SArchie Cobbs * Receive data on a hook 36892a3e552SArchie Cobbs * 36992a3e552SArchie Cobbs * Apply the filter, and then drop or forward packet as appropriate. 37092a3e552SArchie Cobbs */ 37192a3e552SArchie Cobbs static int 372069154d5SJulian Elischer ng_bpf_rcvdata(hook_p hook, item_p item) 37392a3e552SArchie Cobbs { 37492a3e552SArchie Cobbs const hinfo_p hip = hook->private; 375069154d5SJulian Elischer int totlen; 37692a3e552SArchie Cobbs int needfree = 0, error = 0; 37792a3e552SArchie Cobbs u_char *data, buf[256]; 37892a3e552SArchie Cobbs hinfo_p dhip; 37992a3e552SArchie Cobbs hook_p dest; 38092a3e552SArchie Cobbs u_int len; 381069154d5SJulian Elischer struct mbuf *m; 38292a3e552SArchie Cobbs 383069154d5SJulian Elischer m = NGI_M(item); /* 'item' still owns it.. we are peeking */ 384069154d5SJulian Elischer totlen = m->m_pkthdr.len; 385069154d5SJulian Elischer /* Update stats on incoming hook. XXX Can we do 64 bits atomically? */ 386069154d5SJulian Elischer /* atomic_add_int64(&hip->stats.recvFrames, 1); */ 387069154d5SJulian Elischer /* atomic_add_int64(&hip->stats.recvOctets, totlen); */ 38892a3e552SArchie Cobbs hip->stats.recvFrames++; 38992a3e552SArchie Cobbs hip->stats.recvOctets += totlen; 39092a3e552SArchie Cobbs 39192a3e552SArchie Cobbs /* Need to put packet in contiguous memory for bpf */ 39292a3e552SArchie Cobbs if (m->m_next != NULL) { 39392a3e552SArchie Cobbs if (totlen > sizeof(buf)) { 39492a3e552SArchie Cobbs MALLOC(data, u_char *, totlen, M_NETGRAPH, M_NOWAIT); 39592a3e552SArchie Cobbs if (data == NULL) { 396069154d5SJulian Elischer NG_FREE_ITEM(item); 39792a3e552SArchie Cobbs return (ENOMEM); 39892a3e552SArchie Cobbs } 39992a3e552SArchie Cobbs needfree = 1; 40092a3e552SArchie Cobbs } else 40192a3e552SArchie Cobbs data = buf; 40292a3e552SArchie Cobbs m_copydata(m, 0, totlen, (caddr_t)data); 40392a3e552SArchie Cobbs } else 40492a3e552SArchie Cobbs data = mtod(m, u_char *); 40592a3e552SArchie Cobbs 40692a3e552SArchie Cobbs /* Run packet through filter */ 40792a3e552SArchie Cobbs len = bpf_filter(hip->prog->bpf_prog, data, totlen, totlen); 40892a3e552SArchie Cobbs if (needfree) 40992a3e552SArchie Cobbs FREE(data, M_NETGRAPH); 41092a3e552SArchie Cobbs 41192a3e552SArchie Cobbs /* See if we got a match and find destination hook */ 41292a3e552SArchie Cobbs if (len > 0) { 41392a3e552SArchie Cobbs 41492a3e552SArchie Cobbs /* Update stats */ 415069154d5SJulian Elischer /* XXX atomically? */ 41692a3e552SArchie Cobbs hip->stats.recvMatchFrames++; 41792a3e552SArchie Cobbs hip->stats.recvMatchOctets += totlen; 41892a3e552SArchie Cobbs 41992a3e552SArchie Cobbs /* Truncate packet length if required by the filter */ 420069154d5SJulian Elischer /* Assume this never changes m */ 42192a3e552SArchie Cobbs if (len < totlen) { 42292a3e552SArchie Cobbs m_adj(m, -(totlen - len)); 42392a3e552SArchie Cobbs totlen -= len; 42492a3e552SArchie Cobbs } 42592a3e552SArchie Cobbs dest = ng_findhook(hip->node, hip->prog->ifMatch); 42692a3e552SArchie Cobbs } else 42792a3e552SArchie Cobbs dest = ng_findhook(hip->node, hip->prog->ifNotMatch); 42892a3e552SArchie Cobbs if (dest == NULL) { 429069154d5SJulian Elischer NG_FREE_ITEM(item); 43092a3e552SArchie Cobbs return (0); 43192a3e552SArchie Cobbs } 43292a3e552SArchie Cobbs 43392a3e552SArchie Cobbs /* Deliver frame out destination hook */ 43492a3e552SArchie Cobbs dhip = (hinfo_p)dest->private; 43592a3e552SArchie Cobbs dhip->stats.xmitOctets += totlen; 43692a3e552SArchie Cobbs dhip->stats.xmitFrames++; 437069154d5SJulian Elischer NG_FWD_DATA(error, item, dest); 43892a3e552SArchie Cobbs return (error); 43992a3e552SArchie Cobbs } 44092a3e552SArchie Cobbs 44192a3e552SArchie Cobbs /* 44292a3e552SArchie Cobbs * Shutdown processing 44392a3e552SArchie Cobbs */ 44492a3e552SArchie Cobbs static int 445069154d5SJulian Elischer ng_bpf_shutdown(node_p node) 44692a3e552SArchie Cobbs { 44792a3e552SArchie Cobbs node->flags |= NG_INVALID; 44892a3e552SArchie Cobbs ng_unref(node); 44992a3e552SArchie Cobbs return (0); 45092a3e552SArchie Cobbs } 45192a3e552SArchie Cobbs 45292a3e552SArchie Cobbs /* 45392a3e552SArchie Cobbs * Hook disconnection 45492a3e552SArchie Cobbs */ 45592a3e552SArchie Cobbs static int 45692a3e552SArchie Cobbs ng_bpf_disconnect(hook_p hook) 45792a3e552SArchie Cobbs { 45892a3e552SArchie Cobbs const hinfo_p hip = hook->private; 45992a3e552SArchie Cobbs 46092a3e552SArchie Cobbs KASSERT(hip != NULL, ("%s: null info", __FUNCTION__)); 46192a3e552SArchie Cobbs FREE(hip->prog, M_NETGRAPH); 46292a3e552SArchie Cobbs bzero(hip, sizeof(*hip)); 46392a3e552SArchie Cobbs FREE(hip, M_NETGRAPH); 46492a3e552SArchie Cobbs hook->private = NULL; /* for good measure */ 465069154d5SJulian Elischer if ((hook->node->numhooks == 0) 466069154d5SJulian Elischer && ((hook->node->flags && NG_INVALID) == 0)) { 467069154d5SJulian Elischer ng_rmnode_self(hook->node); 468069154d5SJulian Elischer } 46992a3e552SArchie Cobbs return (0); 47092a3e552SArchie Cobbs } 47192a3e552SArchie Cobbs 47292a3e552SArchie Cobbs /************************************************************************ 47392a3e552SArchie Cobbs HELPER STUFF 47492a3e552SArchie Cobbs ************************************************************************/ 47592a3e552SArchie Cobbs 47692a3e552SArchie Cobbs /* 47792a3e552SArchie Cobbs * Set the BPF program associated with a hook 47892a3e552SArchie Cobbs */ 47992a3e552SArchie Cobbs static int 48092a3e552SArchie Cobbs ng_bpf_setprog(hook_p hook, const struct ng_bpf_hookprog *hp0) 48192a3e552SArchie Cobbs { 48292a3e552SArchie Cobbs const hinfo_p hip = hook->private; 48392a3e552SArchie Cobbs struct ng_bpf_hookprog *hp; 48492a3e552SArchie Cobbs int size; 48592a3e552SArchie Cobbs 48692a3e552SArchie Cobbs /* Check program for validity */ 48792a3e552SArchie Cobbs if (!bpf_validate(hp0->bpf_prog, hp0->bpf_prog_len)) 48892a3e552SArchie Cobbs return (EINVAL); 48992a3e552SArchie Cobbs 49092a3e552SArchie Cobbs /* Make a copy of the program */ 491ab0d3c94SArchie Cobbs size = NG_BPF_HOOKPROG_SIZE(hp0->bpf_prog_len); 49265b9a0daSArchie Cobbs MALLOC(hp, struct ng_bpf_hookprog *, size, M_NETGRAPH, M_NOWAIT); 49392a3e552SArchie Cobbs if (hp == NULL) 49492a3e552SArchie Cobbs return (ENOMEM); 49592a3e552SArchie Cobbs bcopy(hp0, hp, size); 49692a3e552SArchie Cobbs 49792a3e552SArchie Cobbs /* Free previous program, if any, and assign new one */ 49892a3e552SArchie Cobbs if (hip->prog != NULL) 49992a3e552SArchie Cobbs FREE(hip->prog, M_NETGRAPH); 50092a3e552SArchie Cobbs hip->prog = hp; 50192a3e552SArchie Cobbs return (0); 50292a3e552SArchie Cobbs } 50392a3e552SArchie Cobbs 504