10147868eSNuno Antunes /*
20147868eSNuno Antunes * ng_bpf.c
30147868eSNuno Antunes */
40147868eSNuno Antunes
50147868eSNuno Antunes /*-
60147868eSNuno Antunes * Copyright (c) 1999 Whistle Communications, Inc.
70147868eSNuno Antunes * All rights reserved.
80147868eSNuno Antunes *
90147868eSNuno Antunes * Subject to the following obligations and disclaimer of warranty, use and
100147868eSNuno Antunes * redistribution of this software, in source or object code forms, with or
110147868eSNuno Antunes * without modifications are expressly permitted by Whistle Communications;
120147868eSNuno Antunes * provided, however, that:
130147868eSNuno Antunes * 1. Any and all reproductions of the source or object code must include the
140147868eSNuno Antunes * copyright notice above and the following disclaimer of warranties; and
150147868eSNuno Antunes * 2. No rights are granted, in any manner or form, to use Whistle
160147868eSNuno Antunes * Communications, Inc. trademarks, including the mark "WHISTLE
170147868eSNuno Antunes * COMMUNICATIONS" on advertising, endorsements, or otherwise except as
180147868eSNuno Antunes * such appears in the above copyright notice or in the software.
190147868eSNuno Antunes *
200147868eSNuno Antunes * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
210147868eSNuno Antunes * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
220147868eSNuno Antunes * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
230147868eSNuno Antunes * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
240147868eSNuno Antunes * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
250147868eSNuno Antunes * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
260147868eSNuno Antunes * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
270147868eSNuno Antunes * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
280147868eSNuno Antunes * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
290147868eSNuno Antunes * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
300147868eSNuno Antunes * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
310147868eSNuno Antunes * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
320147868eSNuno Antunes * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
330147868eSNuno Antunes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
340147868eSNuno Antunes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
350147868eSNuno Antunes * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
360147868eSNuno Antunes * OF SUCH DAMAGE.
370147868eSNuno Antunes *
380147868eSNuno Antunes * Author: Archie Cobbs <archie@freebsd.org>
390147868eSNuno Antunes *
400147868eSNuno Antunes * $FreeBSD: src/sys/netgraph/ng_bpf.c,v 1.24 2008/02/04 19:26:53 mav Exp $
410147868eSNuno Antunes * $Whistle: ng_bpf.c,v 1.3 1999/12/03 20:30:23 archie Exp $
420147868eSNuno Antunes */
430147868eSNuno Antunes
440147868eSNuno Antunes /*
450147868eSNuno Antunes * BPF NETGRAPH NODE TYPE
460147868eSNuno Antunes *
470147868eSNuno Antunes * This node type accepts any number of hook connections. With each hook
480147868eSNuno Antunes * is associated a bpf(4) filter program, and two hook names (each possibly
490147868eSNuno Antunes * the empty string). Incoming packets are compared against the filter;
500147868eSNuno Antunes * matching packets are delivered out the first named hook (or dropped if
510147868eSNuno Antunes * the empty string), and non-matching packets are delivered out the second
520147868eSNuno Antunes * named hook (or dropped if the empty string).
530147868eSNuno Antunes *
540147868eSNuno Antunes * Each hook also keeps statistics about how many packets have matched, etc.
550147868eSNuno Antunes */
560147868eSNuno Antunes
570147868eSNuno Antunes #include <sys/param.h>
580147868eSNuno Antunes #include <sys/systm.h>
590147868eSNuno Antunes #include <sys/errno.h>
600147868eSNuno Antunes #include <sys/kernel.h>
610147868eSNuno Antunes #include <sys/malloc.h>
620147868eSNuno Antunes #include <sys/mbuf.h>
630147868eSNuno Antunes
640147868eSNuno Antunes #include <net/bpf.h>
650147868eSNuno Antunes #ifdef BPF_JITTER
660147868eSNuno Antunes #include <net/bpf_jitter.h>
670147868eSNuno Antunes #endif
680147868eSNuno Antunes
690147868eSNuno Antunes #include <netgraph7/ng_message.h>
700147868eSNuno Antunes #include <netgraph7/netgraph.h>
710147868eSNuno Antunes #include <netgraph7/ng_parse.h>
720147868eSNuno Antunes #include "ng_bpf.h"
730147868eSNuno Antunes
740147868eSNuno Antunes #ifdef NG_SEPARATE_MALLOC
750147868eSNuno Antunes MALLOC_DEFINE(M_NETGRAPH_BPF, "netgraph_bpf", "netgraph bpf node ");
760147868eSNuno Antunes #else
770147868eSNuno Antunes #define M_NETGRAPH_BPF M_NETGRAPH
780147868eSNuno Antunes #endif
790147868eSNuno Antunes
800147868eSNuno Antunes #define ERROUT(x) do { error = (x); goto done; } while (0)
810147868eSNuno Antunes
820147868eSNuno Antunes /* Per hook private info */
830147868eSNuno Antunes struct ng_bpf_hookinfo {
840147868eSNuno Antunes hook_p hook;
850147868eSNuno Antunes hook_p match;
860147868eSNuno Antunes hook_p nomatch;
870147868eSNuno Antunes struct ng_bpf_hookprog *prog;
880147868eSNuno Antunes #ifdef BPF_JITTER
890147868eSNuno Antunes bpf_jit_filter *jit_prog;
900147868eSNuno Antunes #endif
910147868eSNuno Antunes struct ng_bpf_hookstat stats;
920147868eSNuno Antunes };
930147868eSNuno Antunes typedef struct ng_bpf_hookinfo *hinfo_p;
940147868eSNuno Antunes
950147868eSNuno Antunes /* Netgraph methods */
960147868eSNuno Antunes static ng_constructor_t ng_bpf_constructor;
970147868eSNuno Antunes static ng_rcvmsg_t ng_bpf_rcvmsg;
980147868eSNuno Antunes static ng_shutdown_t ng_bpf_shutdown;
990147868eSNuno Antunes static ng_newhook_t ng_bpf_newhook;
1000147868eSNuno Antunes static ng_rcvdata_t ng_bpf_rcvdata;
1010147868eSNuno Antunes static ng_disconnect_t ng_bpf_disconnect;
1020147868eSNuno Antunes
1030147868eSNuno Antunes /* Internal helper functions */
1040147868eSNuno Antunes static int ng_bpf_setprog(hook_p hook, const struct ng_bpf_hookprog *hp);
1050147868eSNuno Antunes
1060147868eSNuno Antunes /* Parse type for one struct bfp_insn */
1070147868eSNuno Antunes static const struct ng_parse_struct_field ng_bpf_insn_type_fields[] = {
1080147868eSNuno Antunes { "code", &ng_parse_hint16_type },
1090147868eSNuno Antunes { "jt", &ng_parse_uint8_type },
1100147868eSNuno Antunes { "jf", &ng_parse_uint8_type },
1110147868eSNuno Antunes { "k", &ng_parse_uint32_type },
1120147868eSNuno Antunes { NULL }
1130147868eSNuno Antunes };
1140147868eSNuno Antunes static const struct ng_parse_type ng_bpf_insn_type = {
1150147868eSNuno Antunes &ng_parse_struct_type,
1160147868eSNuno Antunes &ng_bpf_insn_type_fields
1170147868eSNuno Antunes };
1180147868eSNuno Antunes
1190147868eSNuno Antunes /* Parse type for the field 'bpf_prog' in struct ng_bpf_hookprog */
1200147868eSNuno Antunes static int
ng_bpf_hookprogary_getLength(const struct ng_parse_type * type,const u_char * start,const u_char * buf)1210147868eSNuno Antunes ng_bpf_hookprogary_getLength(const struct ng_parse_type *type,
1220147868eSNuno Antunes const u_char *start, const u_char *buf)
1230147868eSNuno Antunes {
1240147868eSNuno Antunes const struct ng_bpf_hookprog *hp;
1250147868eSNuno Antunes
1260147868eSNuno Antunes hp = (const struct ng_bpf_hookprog *)
127858d36ecSSascha Wildner (buf - __offsetof(struct ng_bpf_hookprog, bpf_prog));
1280147868eSNuno Antunes return hp->bpf_prog_len;
1290147868eSNuno Antunes }
1300147868eSNuno Antunes
1310147868eSNuno Antunes static const struct ng_parse_array_info ng_bpf_hookprogary_info = {
1320147868eSNuno Antunes &ng_bpf_insn_type,
1330147868eSNuno Antunes &ng_bpf_hookprogary_getLength,
1340147868eSNuno Antunes NULL
1350147868eSNuno Antunes };
1360147868eSNuno Antunes static const struct ng_parse_type ng_bpf_hookprogary_type = {
1370147868eSNuno Antunes &ng_parse_array_type,
1380147868eSNuno Antunes &ng_bpf_hookprogary_info
1390147868eSNuno Antunes };
1400147868eSNuno Antunes
1410147868eSNuno Antunes /* Parse type for struct ng_bpf_hookprog */
1420147868eSNuno Antunes static const struct ng_parse_struct_field ng_bpf_hookprog_type_fields[]
1430147868eSNuno Antunes = NG_BPF_HOOKPROG_TYPE_INFO(&ng_bpf_hookprogary_type);
1440147868eSNuno Antunes static const struct ng_parse_type ng_bpf_hookprog_type = {
1450147868eSNuno Antunes &ng_parse_struct_type,
1460147868eSNuno Antunes &ng_bpf_hookprog_type_fields
1470147868eSNuno Antunes };
1480147868eSNuno Antunes
1490147868eSNuno Antunes /* Parse type for struct ng_bpf_hookstat */
1500147868eSNuno Antunes static const struct ng_parse_struct_field ng_bpf_hookstat_type_fields[]
1510147868eSNuno Antunes = NG_BPF_HOOKSTAT_TYPE_INFO;
1520147868eSNuno Antunes static const struct ng_parse_type ng_bpf_hookstat_type = {
1530147868eSNuno Antunes &ng_parse_struct_type,
1540147868eSNuno Antunes &ng_bpf_hookstat_type_fields
1550147868eSNuno Antunes };
1560147868eSNuno Antunes
1570147868eSNuno Antunes /* List of commands and how to convert arguments to/from ASCII */
1580147868eSNuno Antunes static const struct ng_cmdlist ng_bpf_cmdlist[] = {
1590147868eSNuno Antunes {
1600147868eSNuno Antunes NGM_BPF_COOKIE,
1610147868eSNuno Antunes NGM_BPF_SET_PROGRAM,
1620147868eSNuno Antunes "setprogram",
1630147868eSNuno Antunes &ng_bpf_hookprog_type,
1640147868eSNuno Antunes NULL
1650147868eSNuno Antunes },
1660147868eSNuno Antunes {
1670147868eSNuno Antunes NGM_BPF_COOKIE,
1680147868eSNuno Antunes NGM_BPF_GET_PROGRAM,
1690147868eSNuno Antunes "getprogram",
1700147868eSNuno Antunes &ng_parse_hookbuf_type,
1710147868eSNuno Antunes &ng_bpf_hookprog_type
1720147868eSNuno Antunes },
1730147868eSNuno Antunes {
1740147868eSNuno Antunes NGM_BPF_COOKIE,
1750147868eSNuno Antunes NGM_BPF_GET_STATS,
1760147868eSNuno Antunes "getstats",
1770147868eSNuno Antunes &ng_parse_hookbuf_type,
1780147868eSNuno Antunes &ng_bpf_hookstat_type
1790147868eSNuno Antunes },
1800147868eSNuno Antunes {
1810147868eSNuno Antunes NGM_BPF_COOKIE,
1820147868eSNuno Antunes NGM_BPF_CLR_STATS,
1830147868eSNuno Antunes "clrstats",
1840147868eSNuno Antunes &ng_parse_hookbuf_type,
1850147868eSNuno Antunes NULL
1860147868eSNuno Antunes },
1870147868eSNuno Antunes {
1880147868eSNuno Antunes NGM_BPF_COOKIE,
1890147868eSNuno Antunes NGM_BPF_GETCLR_STATS,
1900147868eSNuno Antunes "getclrstats",
1910147868eSNuno Antunes &ng_parse_hookbuf_type,
1920147868eSNuno Antunes &ng_bpf_hookstat_type
1930147868eSNuno Antunes },
1940147868eSNuno Antunes { 0 }
1950147868eSNuno Antunes };
1960147868eSNuno Antunes
1970147868eSNuno Antunes /* Netgraph type descriptor */
1980147868eSNuno Antunes static struct ng_type typestruct = {
1990147868eSNuno Antunes .version = NG_ABI_VERSION,
2000147868eSNuno Antunes .name = NG_BPF_NODE_TYPE,
2010147868eSNuno Antunes .constructor = ng_bpf_constructor,
2020147868eSNuno Antunes .rcvmsg = ng_bpf_rcvmsg,
2030147868eSNuno Antunes .shutdown = ng_bpf_shutdown,
2040147868eSNuno Antunes .newhook = ng_bpf_newhook,
2050147868eSNuno Antunes .rcvdata = ng_bpf_rcvdata,
2060147868eSNuno Antunes .disconnect = ng_bpf_disconnect,
2070147868eSNuno Antunes .cmdlist = ng_bpf_cmdlist,
2080147868eSNuno Antunes };
2090147868eSNuno Antunes NETGRAPH_INIT(bpf, &typestruct);
2100147868eSNuno Antunes
2110147868eSNuno Antunes /* Default BPF program for a hook that matches nothing */
2120147868eSNuno Antunes static const struct ng_bpf_hookprog ng_bpf_default_prog = {
2130147868eSNuno Antunes { '\0' }, /* to be filled in at hook creation time */
2140147868eSNuno Antunes { '\0' },
2150147868eSNuno Antunes { '\0' },
2160147868eSNuno Antunes 1,
2170147868eSNuno Antunes { BPF_STMT(BPF_RET+BPF_K, 0) }
2180147868eSNuno Antunes };
2190147868eSNuno Antunes
2200147868eSNuno Antunes /*
2210147868eSNuno Antunes * Node constructor
2220147868eSNuno Antunes *
2230147868eSNuno Antunes * We don't keep any per-node private data
2240147868eSNuno Antunes * We go via the hooks.
2250147868eSNuno Antunes */
2260147868eSNuno Antunes static int
ng_bpf_constructor(node_p node)2270147868eSNuno Antunes ng_bpf_constructor(node_p node)
2280147868eSNuno Antunes {
2290147868eSNuno Antunes NG_NODE_SET_PRIVATE(node, NULL);
2300147868eSNuno Antunes return (0);
2310147868eSNuno Antunes }
2320147868eSNuno Antunes
2330147868eSNuno Antunes /*
2340147868eSNuno Antunes * Callback functions to be used by NG_NODE_FOREACH_HOOK() macro.
2350147868eSNuno Antunes */
2360147868eSNuno Antunes static int
ng_bpf_addrefs(hook_p hook,void * arg)2370147868eSNuno Antunes ng_bpf_addrefs(hook_p hook, void* arg)
2380147868eSNuno Antunes {
2390147868eSNuno Antunes hinfo_p hip = NG_HOOK_PRIVATE(hook);
2400147868eSNuno Antunes hook_p h = (hook_p)arg;
2410147868eSNuno Antunes
2420147868eSNuno Antunes if (strcmp(hip->prog->ifMatch, NG_HOOK_NAME(h)) == 0)
2430147868eSNuno Antunes hip->match = h;
2440147868eSNuno Antunes if (strcmp(hip->prog->ifNotMatch, NG_HOOK_NAME(h)) == 0)
2450147868eSNuno Antunes hip->nomatch = h;
2460147868eSNuno Antunes return (1);
2470147868eSNuno Antunes }
2480147868eSNuno Antunes
2490147868eSNuno Antunes static int
ng_bpf_remrefs(hook_p hook,void * arg)2500147868eSNuno Antunes ng_bpf_remrefs(hook_p hook, void* arg)
2510147868eSNuno Antunes {
2520147868eSNuno Antunes hinfo_p hip = NG_HOOK_PRIVATE(hook);
2530147868eSNuno Antunes hook_p h = (hook_p)arg;
2540147868eSNuno Antunes
2550147868eSNuno Antunes if (hip->match == h)
2560147868eSNuno Antunes hip->match = NULL;
2570147868eSNuno Antunes if (hip->nomatch == h)
2580147868eSNuno Antunes hip->nomatch = NULL;
2590147868eSNuno Antunes return (1);
2600147868eSNuno Antunes }
2610147868eSNuno Antunes
2620147868eSNuno Antunes /*
2630147868eSNuno Antunes * Add a hook
2640147868eSNuno Antunes */
2650147868eSNuno Antunes static int
ng_bpf_newhook(node_p node,hook_p hook,const char * name)2660147868eSNuno Antunes ng_bpf_newhook(node_p node, hook_p hook, const char *name)
2670147868eSNuno Antunes {
2680147868eSNuno Antunes hinfo_p hip;
2690147868eSNuno Antunes hook_p tmp;
2700147868eSNuno Antunes int error;
2710147868eSNuno Antunes
2720147868eSNuno Antunes /* Create hook private structure */
2730147868eSNuno Antunes hip = kmalloc(sizeof(*hip), M_NETGRAPH_BPF,
2740147868eSNuno Antunes M_WAITOK | M_NULLOK | M_ZERO);
2750147868eSNuno Antunes if (hip == NULL)
2760147868eSNuno Antunes return (ENOMEM);
2770147868eSNuno Antunes hip->hook = hook;
2780147868eSNuno Antunes NG_HOOK_SET_PRIVATE(hook, hip);
2790147868eSNuno Antunes
2800147868eSNuno Antunes /* Add our reference into other hooks data. */
2810147868eSNuno Antunes NG_NODE_FOREACH_HOOK(node, ng_bpf_addrefs, hook, tmp);
2820147868eSNuno Antunes
2830147868eSNuno Antunes /* Attach the default BPF program */
2840147868eSNuno Antunes if ((error = ng_bpf_setprog(hook, &ng_bpf_default_prog)) != 0) {
2850147868eSNuno Antunes kfree(hip, M_NETGRAPH_BPF);
2860147868eSNuno Antunes NG_HOOK_SET_PRIVATE(hook, NULL);
2870147868eSNuno Antunes return (error);
2880147868eSNuno Antunes }
2890147868eSNuno Antunes
2900147868eSNuno Antunes /* Set hook name */
2910147868eSNuno Antunes strlcpy(hip->prog->thisHook, name, sizeof(hip->prog->thisHook));
2920147868eSNuno Antunes return (0);
2930147868eSNuno Antunes }
2940147868eSNuno Antunes
2950147868eSNuno Antunes /*
2960147868eSNuno Antunes * Receive a control message
2970147868eSNuno Antunes */
2980147868eSNuno Antunes static int
ng_bpf_rcvmsg(node_p node,item_p item,hook_p lasthook)2990147868eSNuno Antunes ng_bpf_rcvmsg(node_p node, item_p item, hook_p lasthook)
3000147868eSNuno Antunes {
3010147868eSNuno Antunes struct ng_mesg *msg;
3020147868eSNuno Antunes struct ng_mesg *resp = NULL;
3030147868eSNuno Antunes int error = 0;
3040147868eSNuno Antunes
3050147868eSNuno Antunes NGI_GET_MSG(item, msg);
3060147868eSNuno Antunes switch (msg->header.typecookie) {
3070147868eSNuno Antunes case NGM_BPF_COOKIE:
3080147868eSNuno Antunes switch (msg->header.cmd) {
3090147868eSNuno Antunes case NGM_BPF_SET_PROGRAM:
3100147868eSNuno Antunes {
3110147868eSNuno Antunes struct ng_bpf_hookprog *const
3120147868eSNuno Antunes hp = (struct ng_bpf_hookprog *)msg->data;
3130147868eSNuno Antunes hook_p hook;
3140147868eSNuno Antunes
3150147868eSNuno Antunes /* Sanity check */
3160147868eSNuno Antunes if (msg->header.arglen < sizeof(*hp)
3170147868eSNuno Antunes || msg->header.arglen
3180147868eSNuno Antunes != NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len))
3190147868eSNuno Antunes ERROUT(EINVAL);
3200147868eSNuno Antunes
3210147868eSNuno Antunes /* Find hook */
3220147868eSNuno Antunes if ((hook = ng_findhook(node, hp->thisHook)) == NULL)
3230147868eSNuno Antunes ERROUT(ENOENT);
3240147868eSNuno Antunes
3250147868eSNuno Antunes /* Set new program */
3260147868eSNuno Antunes if ((error = ng_bpf_setprog(hook, hp)) != 0)
3270147868eSNuno Antunes ERROUT(error);
3280147868eSNuno Antunes break;
3290147868eSNuno Antunes }
3300147868eSNuno Antunes
3310147868eSNuno Antunes case NGM_BPF_GET_PROGRAM:
3320147868eSNuno Antunes {
3330147868eSNuno Antunes struct ng_bpf_hookprog *hp;
3340147868eSNuno Antunes hook_p hook;
3350147868eSNuno Antunes
3360147868eSNuno Antunes /* Sanity check */
3370147868eSNuno Antunes if (msg->header.arglen == 0)
3380147868eSNuno Antunes ERROUT(EINVAL);
3390147868eSNuno Antunes msg->data[msg->header.arglen - 1] = '\0';
3400147868eSNuno Antunes
3410147868eSNuno Antunes /* Find hook */
3420147868eSNuno Antunes if ((hook = ng_findhook(node, msg->data)) == NULL)
3430147868eSNuno Antunes ERROUT(ENOENT);
3440147868eSNuno Antunes
3450147868eSNuno Antunes /* Build response */
3460147868eSNuno Antunes hp = ((hinfo_p)NG_HOOK_PRIVATE(hook))->prog;
3470147868eSNuno Antunes NG_MKRESPONSE(resp, msg,
3480147868eSNuno Antunes NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len), M_WAITOK | M_NULLOK);
3490147868eSNuno Antunes if (resp == NULL)
3500147868eSNuno Antunes ERROUT(ENOMEM);
3510147868eSNuno Antunes bcopy(hp, resp->data,
3520147868eSNuno Antunes NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len));
3530147868eSNuno Antunes break;
3540147868eSNuno Antunes }
3550147868eSNuno Antunes
3560147868eSNuno Antunes case NGM_BPF_GET_STATS:
3570147868eSNuno Antunes case NGM_BPF_CLR_STATS:
3580147868eSNuno Antunes case NGM_BPF_GETCLR_STATS:
3590147868eSNuno Antunes {
3600147868eSNuno Antunes struct ng_bpf_hookstat *stats;
3610147868eSNuno Antunes hook_p hook;
3620147868eSNuno Antunes
3630147868eSNuno Antunes /* Sanity check */
3640147868eSNuno Antunes if (msg->header.arglen == 0)
3650147868eSNuno Antunes ERROUT(EINVAL);
3660147868eSNuno Antunes msg->data[msg->header.arglen - 1] = '\0';
3670147868eSNuno Antunes
3680147868eSNuno Antunes /* Find hook */
3690147868eSNuno Antunes if ((hook = ng_findhook(node, msg->data)) == NULL)
3700147868eSNuno Antunes ERROUT(ENOENT);
3710147868eSNuno Antunes stats = &((hinfo_p)NG_HOOK_PRIVATE(hook))->stats;
3720147868eSNuno Antunes
3730147868eSNuno Antunes /* Build response (if desired) */
3740147868eSNuno Antunes if (msg->header.cmd != NGM_BPF_CLR_STATS) {
3750147868eSNuno Antunes NG_MKRESPONSE(resp,
3760147868eSNuno Antunes msg, sizeof(*stats), M_WAITOK | M_NULLOK);
3770147868eSNuno Antunes if (resp == NULL)
3780147868eSNuno Antunes ERROUT(ENOMEM);
3790147868eSNuno Antunes bcopy(stats, resp->data, sizeof(*stats));
3800147868eSNuno Antunes }
3810147868eSNuno Antunes
3820147868eSNuno Antunes /* Clear stats (if desired) */
3830147868eSNuno Antunes if (msg->header.cmd != NGM_BPF_GET_STATS)
3840147868eSNuno Antunes bzero(stats, sizeof(*stats));
3850147868eSNuno Antunes break;
3860147868eSNuno Antunes }
3870147868eSNuno Antunes
3880147868eSNuno Antunes default:
3890147868eSNuno Antunes error = EINVAL;
3900147868eSNuno Antunes break;
3910147868eSNuno Antunes }
3920147868eSNuno Antunes break;
3930147868eSNuno Antunes default:
3940147868eSNuno Antunes error = EINVAL;
3950147868eSNuno Antunes break;
3960147868eSNuno Antunes }
3970147868eSNuno Antunes done:
3980147868eSNuno Antunes NG_RESPOND_MSG(error, node, item, resp);
3990147868eSNuno Antunes NG_FREE_MSG(msg);
4000147868eSNuno Antunes return (error);
4010147868eSNuno Antunes }
4020147868eSNuno Antunes
4030147868eSNuno Antunes /*
4040147868eSNuno Antunes * Receive data on a hook
4050147868eSNuno Antunes *
4060147868eSNuno Antunes * Apply the filter, and then drop or forward packet as appropriate.
4070147868eSNuno Antunes */
4080147868eSNuno Antunes static int
ng_bpf_rcvdata(hook_p hook,item_p item)4090147868eSNuno Antunes ng_bpf_rcvdata(hook_p hook, item_p item)
4100147868eSNuno Antunes {
4110147868eSNuno Antunes const hinfo_p hip = NG_HOOK_PRIVATE(hook);
4120147868eSNuno Antunes int totlen;
4130147868eSNuno Antunes int needfree = 0, error = 0, usejit = 0;
4140147868eSNuno Antunes u_char *data = NULL;
4150147868eSNuno Antunes hinfo_p dhip;
4160147868eSNuno Antunes hook_p dest;
4170147868eSNuno Antunes u_int len;
4180147868eSNuno Antunes struct mbuf *m;
4190147868eSNuno Antunes
4200147868eSNuno Antunes m = NGI_M(item); /* 'item' still owns it.. we are peeking */
4210147868eSNuno Antunes totlen = m->m_pkthdr.len;
4220147868eSNuno Antunes /* Update stats on incoming hook. XXX Can we do 64 bits atomically? */
4230147868eSNuno Antunes /* atomic_add_int64(&hip->stats.recvFrames, 1); */
4240147868eSNuno Antunes /* atomic_add_int64(&hip->stats.recvOctets, totlen); */
4250147868eSNuno Antunes hip->stats.recvFrames++;
4260147868eSNuno Antunes hip->stats.recvOctets += totlen;
4270147868eSNuno Antunes
4280147868eSNuno Antunes /* Don't call bpf_filter() with totlen == 0! */
4290147868eSNuno Antunes if (totlen == 0) {
4300147868eSNuno Antunes len = 0;
4310147868eSNuno Antunes goto ready;
4320147868eSNuno Antunes }
4330147868eSNuno Antunes
4340147868eSNuno Antunes #ifdef BPF_JITTER
4350147868eSNuno Antunes if (bpf_jitter_enable != 0 && hip->jit_prog != NULL)
4360147868eSNuno Antunes usejit = 1;
4370147868eSNuno Antunes #endif
4380147868eSNuno Antunes
4390147868eSNuno Antunes /* Need to put packet in contiguous memory for bpf */
4400147868eSNuno Antunes if (m->m_next != NULL && totlen > MHLEN) {
4410147868eSNuno Antunes if (usejit) {
4420147868eSNuno Antunes data = kmalloc(totlen, M_NETGRAPH_BPF, M_NOWAIT);
4430147868eSNuno Antunes if (data == NULL) {
4440147868eSNuno Antunes NG_FREE_ITEM(item);
4450147868eSNuno Antunes return (ENOMEM);
4460147868eSNuno Antunes }
4470147868eSNuno Antunes needfree = 1;
448*05d02a38SAaron LI m_copydata(m, 0, totlen, data);
4490147868eSNuno Antunes }
4500147868eSNuno Antunes } else {
4510147868eSNuno Antunes if (m->m_next != NULL) {
4520147868eSNuno Antunes NGI_M(item) = m = m_pullup(m, totlen);
4530147868eSNuno Antunes if (m == NULL) {
4540147868eSNuno Antunes NG_FREE_ITEM(item);
4550147868eSNuno Antunes return (ENOBUFS);
4560147868eSNuno Antunes }
4570147868eSNuno Antunes }
4580147868eSNuno Antunes data = mtod(m, u_char *);
4590147868eSNuno Antunes }
4600147868eSNuno Antunes
4610147868eSNuno Antunes /* Run packet through filter */
4620147868eSNuno Antunes #ifdef BPF_JITTER
4630147868eSNuno Antunes if (usejit)
4640147868eSNuno Antunes len = (*(hip->jit_prog->func))(data, totlen, totlen);
4650147868eSNuno Antunes else
4660147868eSNuno Antunes #endif
4670147868eSNuno Antunes if (data)
4680147868eSNuno Antunes len = bpf_filter(hip->prog->bpf_prog, data, totlen, totlen);
4690147868eSNuno Antunes else
4700147868eSNuno Antunes len = bpf_filter(hip->prog->bpf_prog, (u_char *)m, totlen, 0);
4710147868eSNuno Antunes if (needfree)
4720147868eSNuno Antunes kfree(data, M_NETGRAPH_BPF);
4730147868eSNuno Antunes ready:
4740147868eSNuno Antunes /* See if we got a match and find destination hook */
4750147868eSNuno Antunes if (len > 0) {
4760147868eSNuno Antunes
4770147868eSNuno Antunes /* Update stats */
4780147868eSNuno Antunes /* XXX atomically? */
4790147868eSNuno Antunes hip->stats.recvMatchFrames++;
4800147868eSNuno Antunes hip->stats.recvMatchOctets += totlen;
4810147868eSNuno Antunes
4820147868eSNuno Antunes /* Truncate packet length if required by the filter */
4830147868eSNuno Antunes /* Assume this never changes m */
4840147868eSNuno Antunes if (len < totlen) {
4850147868eSNuno Antunes m_adj(m, -(totlen - len));
4860147868eSNuno Antunes totlen = len;
4870147868eSNuno Antunes }
4880147868eSNuno Antunes dest = hip->match;
4890147868eSNuno Antunes } else
4900147868eSNuno Antunes dest = hip->nomatch;
4910147868eSNuno Antunes if (dest == NULL) {
4920147868eSNuno Antunes NG_FREE_ITEM(item);
4930147868eSNuno Antunes return (0);
4940147868eSNuno Antunes }
4950147868eSNuno Antunes
4960147868eSNuno Antunes /* Deliver frame out destination hook */
4970147868eSNuno Antunes dhip = NG_HOOK_PRIVATE(dest);
4980147868eSNuno Antunes dhip->stats.xmitOctets += totlen;
4990147868eSNuno Antunes dhip->stats.xmitFrames++;
5000147868eSNuno Antunes NG_FWD_ITEM_HOOK(error, item, dest);
5010147868eSNuno Antunes return (error);
5020147868eSNuno Antunes }
5030147868eSNuno Antunes
5040147868eSNuno Antunes /*
5050147868eSNuno Antunes * Shutdown processing
5060147868eSNuno Antunes */
5070147868eSNuno Antunes static int
ng_bpf_shutdown(node_p node)5080147868eSNuno Antunes ng_bpf_shutdown(node_p node)
5090147868eSNuno Antunes {
5100147868eSNuno Antunes NG_NODE_UNREF(node);
5110147868eSNuno Antunes return (0);
5120147868eSNuno Antunes }
5130147868eSNuno Antunes
5140147868eSNuno Antunes /*
5150147868eSNuno Antunes * Hook disconnection
5160147868eSNuno Antunes */
5170147868eSNuno Antunes static int
ng_bpf_disconnect(hook_p hook)5180147868eSNuno Antunes ng_bpf_disconnect(hook_p hook)
5190147868eSNuno Antunes {
5200147868eSNuno Antunes const node_p node = NG_HOOK_NODE(hook);
5210147868eSNuno Antunes const hinfo_p hip = NG_HOOK_PRIVATE(hook);
5220147868eSNuno Antunes hook_p tmp;
5230147868eSNuno Antunes
5240147868eSNuno Antunes KASSERT(hip != NULL, ("%s: null info", __func__));
5250147868eSNuno Antunes
5260147868eSNuno Antunes /* Remove our reference from other hooks data. */
5270147868eSNuno Antunes NG_NODE_FOREACH_HOOK(node, ng_bpf_remrefs, hook, tmp);
5280147868eSNuno Antunes
5290147868eSNuno Antunes kfree(hip->prog, M_NETGRAPH_BPF);
5300147868eSNuno Antunes #ifdef BPF_JITTER
5310147868eSNuno Antunes if (hip->jit_prog != NULL)
5320147868eSNuno Antunes bpf_destroy_jit_filter(hip->jit_prog);
5330147868eSNuno Antunes #endif
5340147868eSNuno Antunes kfree(hip, M_NETGRAPH_BPF);
5350147868eSNuno Antunes if ((NG_NODE_NUMHOOKS(node) == 0) &&
5360147868eSNuno Antunes (NG_NODE_IS_VALID(node))) {
5370147868eSNuno Antunes ng_rmnode_self(node);
5380147868eSNuno Antunes }
5390147868eSNuno Antunes return (0);
5400147868eSNuno Antunes }
5410147868eSNuno Antunes
5420147868eSNuno Antunes /************************************************************************
5430147868eSNuno Antunes HELPER STUFF
5440147868eSNuno Antunes ************************************************************************/
5450147868eSNuno Antunes
5460147868eSNuno Antunes /*
5470147868eSNuno Antunes * Set the BPF program associated with a hook
5480147868eSNuno Antunes */
5490147868eSNuno Antunes static int
ng_bpf_setprog(hook_p hook,const struct ng_bpf_hookprog * hp0)5500147868eSNuno Antunes ng_bpf_setprog(hook_p hook, const struct ng_bpf_hookprog *hp0)
5510147868eSNuno Antunes {
5520147868eSNuno Antunes const hinfo_p hip = NG_HOOK_PRIVATE(hook);
5530147868eSNuno Antunes struct ng_bpf_hookprog *hp;
5540147868eSNuno Antunes #ifdef BPF_JITTER
5550147868eSNuno Antunes bpf_jit_filter *jit_prog;
5560147868eSNuno Antunes #endif
5570147868eSNuno Antunes int size;
5580147868eSNuno Antunes
5590147868eSNuno Antunes /* Check program for validity */
5600147868eSNuno Antunes if (!bpf_validate(hp0->bpf_prog, hp0->bpf_prog_len))
5610147868eSNuno Antunes return (EINVAL);
5620147868eSNuno Antunes
5630147868eSNuno Antunes /* Make a copy of the program */
5640147868eSNuno Antunes size = NG_BPF_HOOKPROG_SIZE(hp0->bpf_prog_len);
5650147868eSNuno Antunes hp = kmalloc(size, M_NETGRAPH_BPF, M_NOWAIT);
5660147868eSNuno Antunes if (hp == NULL)
5670147868eSNuno Antunes return (ENOMEM);
5680147868eSNuno Antunes bcopy(hp0, hp, size);
5690147868eSNuno Antunes #ifdef BPF_JITTER
5700147868eSNuno Antunes jit_prog = bpf_jitter(hp->bpf_prog, hp->bpf_prog_len);
5710147868eSNuno Antunes #endif
5720147868eSNuno Antunes
5730147868eSNuno Antunes /* Free previous program, if any, and assign new one */
5740147868eSNuno Antunes if (hip->prog != NULL)
5750147868eSNuno Antunes kfree(hip->prog, M_NETGRAPH_BPF);
5760147868eSNuno Antunes hip->prog = hp;
5770147868eSNuno Antunes #ifdef BPF_JITTER
5780147868eSNuno Antunes if (hip->jit_prog != NULL)
5790147868eSNuno Antunes bpf_destroy_jit_filter(hip->jit_prog);
5800147868eSNuno Antunes hip->jit_prog = jit_prog;
5810147868eSNuno Antunes #endif
5820147868eSNuno Antunes
5830147868eSNuno Antunes /* Prepare direct references on target hooks. */
5840147868eSNuno Antunes hip->match = ng_findhook(NG_HOOK_NODE(hook), hip->prog->ifMatch);
5850147868eSNuno Antunes hip->nomatch = ng_findhook(NG_HOOK_NODE(hook), hip->prog->ifNotMatch);
5860147868eSNuno Antunes return (0);
5870147868eSNuno Antunes }
588