ng_bpf.c revision 70784
150477Speter 21817Sdg/* 31817Sdg * ng_bpf.c 41541Srgrimes * 51541Srgrimes * Copyright (c) 1999 Whistle Communications, Inc. 61541Srgrimes * All rights reserved. 7160798Sjhb * 81541Srgrimes * Subject to the following obligations and disclaimer of warranty, use and 9146806Srwatson * redistribution of this software, in source or object code forms, with or 10146806Srwatson * without modifications are expressly permitted by Whistle Communications; 11146806Srwatson * provided, however, that: 12146806Srwatson * 1. Any and all reproductions of the source or object code must include the 13146806Srwatson * copyright notice above and the following disclaimer of warranties; and 14194390Sjhb * 2. No rights are granted, in any manner or form, to use Whistle 15203660Sed * Communications, Inc. trademarks, including the mark "WHISTLE 16194390Sjhb * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 17194390Sjhb * such appears in the above copyright notice or in the software. 1811294Sswallace * 1910905Sbde * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 201541Srgrimes * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 2110905Sbde * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 2210905Sbde * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 231541Srgrimes * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 241541Srgrimes * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANBPF, OR MAKE ANY 251541Srgrimes * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 261541Srgrimes * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 271541Srgrimes * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 2899855Salfred * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 29194645Sjhb * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 30194833Sjhb * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 311541Srgrimes * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 321541Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3369449Salfred * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34194383Sjhb * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 35160797Sjhb * OF SUCH DAMAGE. 36181972Sobrien * 37181972Sobrien * Author: Archie Cobbs <archie@freebsd.org> 38183361Sjhb * 39181972Sobrien * $FreeBSD: head/sys/netgraph/ng_bpf.c 70784 2001-01-08 05:34:06Z julian $ 40181972Sobrien * $Whistle: ng_bpf.c,v 1.3 1999/12/03 20:30:23 archie Exp $ 41181972Sobrien */ 42181972Sobrien 43211838Skib/* 44104747Srwatson * BPF NETGRAPH NODE TYPE 45104747Srwatson * 46123408Speter * This node type accepts any number of hook connections. With each hook 47123408Speter * is associated a bpf(4) filter program, and two hook names (each possibly 481541Srgrimes * the empty string). Incoming packets are compared against the filter; 491541Srgrimes * matching packets are delivered out the first named hook (or dropped if 5011294Sswallace * the empty string), and non-matching packets are delivered out the second 5111294Sswallace * named hook (or dropped if the empty string). 5211294Sswallace * 5311294Sswallace * Each hook also keeps statistics about how many packets have matched, etc. 541541Srgrimes */ 551541Srgrimes 561541Srgrimes#include <sys/param.h> 571541Srgrimes#include <sys/systm.h> 581541Srgrimes#include <sys/errno.h> 591541Srgrimes#include <sys/kernel.h> 60160798Sjhb#include <sys/malloc.h> 61160798Sjhb#include <sys/mbuf.h> 62146806Srwatson 63160798Sjhb#include <net/bpf.h> 64160798Sjhb 65146806Srwatson#include <netgraph/ng_message.h> 66160798Sjhb#include <netgraph/netgraph.h> 67146806Srwatson#include <netgraph/ng_parse.h> 68160798Sjhb#include <netgraph/ng_bpf.h> 6912216Sbde 7012216Sbde#define OFFSETOF(s, e) ((char *)&((s *)0)->e - (char *)((s *)0)) 7112216Sbde 72160798Sjhb#define ERROUT(x) do { error = (x); goto done; } while (0) 73160798Sjhb 74146806Srwatson/* Per hook private info */ 75146806Srwatsonstruct ng_bpf_hookinfo { 76162991Srwatson node_p node; 77160798Sjhb hook_p hook; 78160798Sjhb struct ng_bpf_hookprog *prog; 79146806Srwatson struct ng_bpf_hookstat stats; 80160798Sjhb}; 81160798Sjhbtypedef struct ng_bpf_hookinfo *hinfo_p; 82160798Sjhb 83160798Sjhb/* Netgraph methods */ 84160798Sjhbstatic ng_constructor_t ng_bpf_constructor; 85160798Sjhbstatic ng_rcvmsg_t ng_bpf_rcvmsg; 86146806Srwatsonstatic ng_shutdown_t ng_bpf_shutdown; 87160798Sjhbstatic ng_newhook_t ng_bpf_newhook; 88146806Srwatsonstatic ng_rcvdata_t ng_bpf_rcvdata; 89160798Sjhbstatic ng_disconnect_t ng_bpf_disconnect; 90146806Srwatson 91160798Sjhb/* Internal helper functions */ 92160798Sjhbstatic int ng_bpf_setprog(hook_p hook, const struct ng_bpf_hookprog *hp); 93146806Srwatson 9412216Sbde/* Parse type for one struct bfp_insn */ 95160798Sjhbstatic const struct ng_parse_struct_info ng_bpf_insn_type_info = { 96160798Sjhb { 97160798Sjhb { "code", &ng_parse_hint16_type }, 98160798Sjhb { "jt", &ng_parse_uint8_type }, 99160798Sjhb { "jf", &ng_parse_uint8_type }, 100146806Srwatson { "k", &ng_parse_uint32_type }, 101160798Sjhb { NULL } 102146806Srwatson } 103160798Sjhb}; 104146806Srwatsonstatic const struct ng_parse_type ng_bpf_insn_type = { 105160798Sjhb &ng_parse_struct_type, 106146806Srwatson &ng_bpf_insn_type_info 107146806Srwatson}; 108146806Srwatson 109160798Sjhb/* Parse type for the field 'bpf_prog' in struct ng_bpf_hookprog */ 110146806Srwatsonstatic int 111146806Srwatsonng_bpf_hookprogary_getLength(const struct ng_parse_type *type, 112160798Sjhb const u_char *start, const u_char *buf) 113146806Srwatson{ 114146806Srwatson const struct ng_bpf_hookprog *hp; 115160798Sjhb 116146806Srwatson hp = (const struct ng_bpf_hookprog *) 117146806Srwatson (buf - OFFSETOF(struct ng_bpf_hookprog, bpf_prog)); 118160798Sjhb return hp->bpf_prog_len; 119160798Sjhb} 120160798Sjhb 121160798Sjhbstatic const struct ng_parse_array_info ng_bpf_hookprogary_info = { 122160798Sjhb &ng_bpf_insn_type, 123160798Sjhb &ng_bpf_hookprogary_getLength, 124160798Sjhb NULL 125160798Sjhb}; 126160798Sjhbstatic const struct ng_parse_type ng_bpf_hookprogary_type = { 127160798Sjhb &ng_parse_array_type, 128160798Sjhb &ng_bpf_hookprogary_info 129160798Sjhb}; 130146806Srwatson 131160798Sjhb/* Parse type for struct ng_bpf_hookprog */ 132146806Srwatsonstatic const struct ng_parse_struct_info ng_bpf_hookprog_type_info 133160798Sjhb = NG_BPF_HOOKPROG_TYPE_INFO(&ng_bpf_hookprogary_type); 134146806Srwatsonstatic const struct ng_parse_type ng_bpf_hookprog_type = { 135146806Srwatson &ng_parse_struct_type, 136160798Sjhb &ng_bpf_hookprog_type_info 137160798Sjhb}; 13821776Sbde 13921776Sbde/* Parse type for struct ng_bpf_hookstat */ 14021776Sbdestatic const struct ng_parse_struct_info 141160798Sjhb ng_bpf_hookstat_type_info = NG_BPF_HOOKSTAT_TYPE_INFO; 142146806Srwatsonstatic const struct ng_parse_type ng_bpf_hookstat_type = { 143160798Sjhb &ng_parse_struct_type, 144160798Sjhb &ng_bpf_hookstat_type_info 145160798Sjhb}; 146162373Srwatson 147146806Srwatson/* List of commands and how to convert arguments to/from ASCII */ 148160798Sjhbstatic const struct ng_cmdlist ng_bpf_cmdlist[] = { 149146806Srwatson { 150160798Sjhb NGM_BPF_COOKIE, 151160798Sjhb NGM_BPF_SET_PROGRAM, 152160798Sjhb "setprogram", 153176215Sru &ng_bpf_hookprog_type, 154176215Sru NULL 155160798Sjhb }, 156146806Srwatson { 157160798Sjhb NGM_BPF_COOKIE, 158146806Srwatson NGM_BPF_GET_PROGRAM, 159160798Sjhb "getprogram", 160160798Sjhb &ng_parse_hookbuf_type, 161160798Sjhb &ng_bpf_hookprog_type 162146806Srwatson }, 163146806Srwatson { 164162991Srwatson NGM_BPF_COOKIE, 165146806Srwatson NGM_BPF_GET_STATS, 166160798Sjhb "getstats", 167146806Srwatson &ng_parse_hookbuf_type, 168160798Sjhb &ng_bpf_hookstat_type 169146806Srwatson }, 170146806Srwatson { 171160798Sjhb NGM_BPF_COOKIE, 172160798Sjhb NGM_BPF_CLR_STATS, 173160798Sjhb "clrstats", 174146806Srwatson &ng_parse_hookbuf_type, 175160798Sjhb NULL 176146806Srwatson }, 177160798Sjhb { 178160798Sjhb NGM_BPF_COOKIE, 179146806Srwatson NGM_BPF_GETCLR_STATS, 180160798Sjhb "getclrstats", 181146806Srwatson &ng_parse_hookbuf_type, 182146806Srwatson &ng_bpf_hookstat_type 183146806Srwatson }, 184160798Sjhb { 0 } 185146806Srwatson}; 186160798Sjhb 187146806Srwatson/* Netgraph type descriptor */ 188160798Sjhbstatic struct ng_type typestruct = { 189146806Srwatson NG_ABI_VERSION, 190160798Sjhb NG_BPF_NODE_TYPE, 191160798Sjhb NULL, 192160798Sjhb ng_bpf_constructor, 193146806Srwatson ng_bpf_rcvmsg, 194160798Sjhb ng_bpf_shutdown, 195160798Sjhb ng_bpf_newhook, 196160798Sjhb NULL, 197146806Srwatson NULL, 198160798Sjhb ng_bpf_rcvdata, 199146806Srwatson ng_bpf_disconnect, 200146806Srwatson ng_bpf_cmdlist 201160798Sjhb}; 202146806SrwatsonNETGRAPH_INIT(bpf, &typestruct); 203146806Srwatson 204160798Sjhb/* Default BPF program for a hook that matches nothing */ 205160798Sjhbstatic const struct ng_bpf_hookprog ng_bpf_default_prog = { 206146806Srwatson { '\0' }, /* to be filled in at hook creation time */ 207160798Sjhb { '\0' }, 208123750Speter { '\0' }, 20912216Sbde 1, 210160798Sjhb { BPF_STMT(BPF_RET+BPF_K, 0) } 211146806Srwatson}; 212146806Srwatson 213160798Sjhb/* 214160798Sjhb * Node constructor 215146806Srwatson * 216160798Sjhb * We don't keep any per-node private data 217146806Srwatson * We go via the hooks. 218160798Sjhb */ 219146806Srwatsonstatic int 220194390Sjhbng_bpf_constructor(node_p node) 221146806Srwatson{ 222160798Sjhb NG_NODE_SET_PRIVATE(node, NULL); 223160798Sjhb return (0); 224146806Srwatson} 225160798Sjhb 226146806Srwatson/* 227160798Sjhb * Add a hook 228146806Srwatson */ 229160798Sjhbstatic int 230146806Srwatsonng_bpf_newhook(node_p node, hook_p hook, const char *name) 231160798Sjhb{ 232146806Srwatson hinfo_p hip; 233160798Sjhb int error; 234146806Srwatson 235160798Sjhb /* Create hook private structure */ 236146806Srwatson MALLOC(hip, hinfo_p, sizeof(*hip), M_NETGRAPH, M_NOWAIT | M_ZERO); 237160798Sjhb if (hip == NULL) 238160798Sjhb return (ENOMEM); 239160798Sjhb hip->hook = hook; 24021776Sbde NG_HOOK_SET_PRIVATE(hook, hip); 24121776Sbde hip->node = node; 242160798Sjhb 243146806Srwatson /* Attach the default BPF program */ 244160798Sjhb if ((error = ng_bpf_setprog(hook, &ng_bpf_default_prog)) != 0) { 245146806Srwatson FREE(hip, M_NETGRAPH); 246160798Sjhb NG_HOOK_SET_PRIVATE(hook, NULL); 247146806Srwatson return (error); 248146806Srwatson } 249160798Sjhb 250146806Srwatson /* Set hook name */ 251160798Sjhb strncpy(hip->prog->thisHook, name, sizeof(hip->prog->thisHook) - 1); 252146806Srwatson hip->prog->thisHook[sizeof(hip->prog->thisHook) - 1] = '\0'; 253160798Sjhb return (0); 254146806Srwatson} 255146806Srwatson 256160798Sjhb/* 257146806Srwatson * Receive a control message 258160798Sjhb */ 259146806Srwatsonstatic int 260160798Sjhbng_bpf_rcvmsg(node_p node, item_p item, hook_p lasthook) 261146806Srwatson{ 262160798Sjhb struct ng_mesg *msg; 263160798Sjhb struct ng_mesg *resp = NULL; 264194390Sjhb int error = 0; 265146806Srwatson 266146806Srwatson NGI_GET_MSG(item, msg); 267146806Srwatson switch (msg->header.typecookie) { 268160798Sjhb case NGM_BPF_COOKIE: 269160798Sjhb switch (msg->header.cmd) { 270160798Sjhb case NGM_BPF_SET_PROGRAM: 271160798Sjhb { 272160798Sjhb struct ng_bpf_hookprog *const 273160798Sjhb hp = (struct ng_bpf_hookprog *)msg->data; 274160798Sjhb hook_p hook; 275160798Sjhb 276146806Srwatson /* Sanity check */ 277160798Sjhb if (msg->header.arglen < sizeof(*hp) 278160798Sjhb || msg->header.arglen 279146806Srwatson != NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len)) 280160798Sjhb ERROUT(EINVAL); 281160798Sjhb 282160798Sjhb /* Find hook */ 283146806Srwatson if ((hook = ng_findhook(node, hp->thisHook)) == NULL) 284146806Srwatson ERROUT(ENOENT); 285160798Sjhb 286146806Srwatson /* Set new program */ 287160798Sjhb if ((error = ng_bpf_setprog(hook, hp)) != 0) 288146806Srwatson ERROUT(error); 289160798Sjhb break; 290160798Sjhb } 291160798Sjhb 292146806Srwatson case NGM_BPF_GET_PROGRAM: 293160798Sjhb { 294146806Srwatson struct ng_bpf_hookprog *hp; 295160798Sjhb hook_p hook; 296160798Sjhb 297160798Sjhb /* Sanity check */ 298146806Srwatson if (msg->header.arglen == 0) 299160798Sjhb ERROUT(EINVAL); 300194390Sjhb msg->data[msg->header.arglen - 1] = '\0'; 301146806Srwatson 302146806Srwatson /* Find hook */ 3031541Srgrimes if ((hook = ng_findhook(node, msg->data)) == NULL) 3041541Srgrimes ERROUT(ENOENT); 3051541Srgrimes 3061541Srgrimes /* Build response */ 3071541Srgrimes hp = ((hinfo_p)NG_HOOK_PRIVATE(hook))->prog; 308146806Srwatson NG_MKRESPONSE(resp, msg, 309146806Srwatson NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len), M_NOWAIT); 310146806Srwatson if (resp == NULL) 311177633Sdfr ERROUT(ENOMEM); 312177633Sdfr bcopy(hp, resp->data, 31330740Sphk NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len)); 314161325Sjhb break; 315160798Sjhb } 316146806Srwatson 317160798Sjhb case NGM_BPF_GET_STATS: 318146806Srwatson case NGM_BPF_CLR_STATS: 319160798Sjhb case NGM_BPF_GETCLR_STATS: 320146806Srwatson { 321146806Srwatson struct ng_bpf_hookstat *stats; 322160798Sjhb hook_p hook; 323146806Srwatson 324160798Sjhb /* Sanity check */ 325146806Srwatson if (msg->header.arglen == 0) 326184789Sed ERROUT(EINVAL); 327146806Srwatson msg->data[msg->header.arglen - 1] = '\0'; 328184789Sed 329146806Srwatson /* Find hook */ 330184789Sed if ((hook = ng_findhook(node, msg->data)) == NULL) 331161952Srwatson ERROUT(ENOENT); 332161952Srwatson stats = &((hinfo_p)NG_HOOK_PRIVATE(hook))->stats; 333146806Srwatson 334146806Srwatson /* Build response (if desired) */ 335146806Srwatson if (msg->header.cmd != NGM_BPF_CLR_STATS) { 336160798Sjhb NG_MKRESPONSE(resp, 337146806Srwatson msg, sizeof(*stats), M_NOWAIT); 338123750Speter if (resp == NULL) 339160798Sjhb ERROUT(ENOMEM); 340146806Srwatson bcopy(stats, resp->data, sizeof(*stats)); 341123750Speter } 342160798Sjhb 343146806Srwatson /* Clear stats (if desired) */ 344123750Speter if (msg->header.cmd != NGM_BPF_GET_STATS) 345146806Srwatson bzero(stats, sizeof(*stats)); 346171209Speter break; 347146806Srwatson } 348171209Speter 349171209Speter default: 350146806Srwatson error = EINVAL; 351178888Sjulian break; 352161946Srwatson } 353146806Srwatson break; 354146806Srwatson default: 355146806Srwatson error = EINVAL; 356146806Srwatson break; 3571541Srgrimes } 35849428Sjkh NG_RESPOND_MSG(error, node, item, resp); 359160798Sjhbdone: 360160798Sjhb if (item) 361160798Sjhb NG_FREE_ITEM(item); 362146806Srwatson NG_FREE_MSG(msg); 363146806Srwatson return (error); 364146806Srwatson} 365146806Srwatson 366160798Sjhb/* 367160798Sjhb * Receive data on a hook 368160798Sjhb * 369160798Sjhb * Apply the filter, and then drop or forward packet as appropriate. 370160798Sjhb */ 371146806Srwatsonstatic int 372160798Sjhbng_bpf_rcvdata(hook_p hook, item_p item) 373146806Srwatson{ 374146806Srwatson const hinfo_p hip = NG_HOOK_PRIVATE(hook); 375160798Sjhb int totlen; 376146806Srwatson int needfree = 0, error = 0; 377146806Srwatson u_char *data, buf[256]; 378160798Sjhb hinfo_p dhip; 379146806Srwatson hook_p dest; 380171209Speter u_int len; 381171209Speter struct mbuf *m; 382171209Speter 383183361Sjhb m = NGI_M(item); /* 'item' still owns it.. we are peeking */ 384146806Srwatson totlen = m->m_pkthdr.len; 385171209Speter /* Update stats on incoming hook. XXX Can we do 64 bits atomically? */ 386171209Speter /* atomic_add_int64(&hip->stats.recvFrames, 1); */ 387171209Speter /* atomic_add_int64(&hip->stats.recvOctets, totlen); */ 388146806Srwatson hip->stats.recvFrames++; 389171209Speter hip->stats.recvOctets += totlen; 390146806Srwatson 391160798Sjhb /* Need to put packet in contiguous memory for bpf */ 392146806Srwatson if (m->m_next != NULL) { 393146806Srwatson if (totlen > sizeof(buf)) { 394160798Sjhb MALLOC(data, u_char *, totlen, M_NETGRAPH, M_NOWAIT); 395160798Sjhb if (data == NULL) { 396160798Sjhb NG_FREE_ITEM(item); 397160798Sjhb return (ENOMEM); 398160798Sjhb } 399146806Srwatson needfree = 1; 400160798Sjhb } else 401146806Srwatson data = buf; 4022124Sdg m_copydata(m, 0, totlen, (caddr_t)data); 4032124Sdg } else 4042124Sdg data = mtod(m, u_char *); 4052124Sdg 406209579Skib /* Run packet through filter */ 407209579Skib len = bpf_filter(hip->prog->bpf_prog, data, totlen, totlen); 408209579Skib if (needfree) 409209579Skib FREE(data, M_NETGRAPH); 410209579Skib 411209579Skib /* See if we got a match and find destination hook */ 412209579Skib if (len > 0) { 413209579Skib 414209579Skib /* Update stats */ 415209579Skib /* XXX atomically? */ 41612864Speter hip->stats.recvMatchFrames++; 41712864Speter hip->stats.recvMatchOctets += totlen; 41814215Speter 419194910Sjhb /* Truncate packet length if required by the filter */ 420194910Sjhb /* Assume this never changes m */ 421160798Sjhb if (len < totlen) { 422146806Srwatson m_adj(m, -(totlen - len)); 423160798Sjhb totlen -= len; 424146806Srwatson } 425146806Srwatson dest = ng_findhook(hip->node, hip->prog->ifMatch); 426194910Sjhb } else 427194910Sjhb dest = ng_findhook(hip->node, hip->prog->ifNotMatch); 428160798Sjhb if (dest == NULL) { 429160798Sjhb NG_FREE_ITEM(item); 430146806Srwatson return (0); 431160798Sjhb } 432146806Srwatson 433160798Sjhb /* Deliver frame out destination hook */ 434146806Srwatson dhip = NG_HOOK_PRIVATE(dest); 435194910Sjhb dhip->stats.xmitOctets += totlen; 436194910Sjhb dhip->stats.xmitFrames++; 437160798Sjhb NG_FWD_ITEM_HOOK(error, item, dest); 438160798Sjhb return (error); 439146806Srwatson} 44014219Speter 441160798Sjhb/* 442146806Srwatson * Shutdown processing 443161952Srwatson */ 444161952Srwatsonstatic int 445146806Srwatsonng_bpf_shutdown(node_p node) 446160798Sjhb{ 447146806Srwatson NG_NODE_UNREF(node); 448160798Sjhb return (0); 449156134Sdavidxu} 450160798Sjhb 451160798Sjhb/* 452151576Sdavidxu * Hook disconnection 453151576Sdavidxu */ 454160798Sjhbstatic int 455151576Sdavidxung_bpf_disconnect(hook_p hook) 456160798Sjhb{ 457160798Sjhb const hinfo_p hip = NG_HOOK_PRIVATE(hook); 458146806Srwatson 459146806Srwatson KASSERT(hip != NULL, ("%s: null info", __FUNCTION__)); 460146806Srwatson FREE(hip->prog, M_NETGRAPH); 461146806Srwatson bzero(hip, sizeof(*hip)); 462146806Srwatson FREE(hip, M_NETGRAPH); 463146806Srwatson NG_HOOK_SET_PRIVATE(hook, NULL); /* for good measure */ 464146806Srwatson if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) 465146806Srwatson && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) { 466160798Sjhb ng_rmnode_self(NG_HOOK_NODE(hook)); 467146806Srwatson } 46814219Speter return (0); 469160798Sjhb} 470146806Srwatson 471160798Sjhb/************************************************************************ 472160798Sjhb HELPER STUFF 473146806Srwatson ************************************************************************/ 474160798Sjhb 475160798Sjhb/* 476160798Sjhb * Set the BPF program associated with a hook 477160798Sjhb */ 478160798Sjhbstatic int 479151867Sdavidxung_bpf_setprog(hook_p hook, const struct ng_bpf_hookprog *hp0) 480151867Sdavidxu{ 481152845Sdavidxu const hinfo_p hip = NG_HOOK_PRIVATE(hook); 482152845Sdavidxu struct ng_bpf_hookprog *hp; 483152845Sdavidxu int size; 484152845Sdavidxu 485152845Sdavidxu /* Check program for validity */ 486152845Sdavidxu if (!bpf_validate(hp0->bpf_prog, hp0->bpf_prog_len)) 487146806Srwatson return (EINVAL); 488146806Srwatson 489146806Srwatson /* Make a copy of the program */ 490146806Srwatson size = NG_BPF_HOOKPROG_SIZE(hp0->bpf_prog_len); 491146806Srwatson MALLOC(hp, struct ng_bpf_hookprog *, size, M_NETGRAPH, M_NOWAIT); 492146806Srwatson if (hp == NULL) 493146806Srwatson return (ENOMEM); 494146806Srwatson bcopy(hp0, hp, size); 495160798Sjhb 496146806Srwatson /* Free previous program, if any, and assign new one */ 497146806Srwatson if (hip->prog != NULL) 498160798Sjhb FREE(hip->prog, M_NETGRAPH); 499160798Sjhb hip->prog = hp; 500146806Srwatson return (0); 501146806Srwatson} 502160798Sjhb 503146806Srwatson