ng_bpf.c revision 64508
1290001Sglebius 2290001Sglebius/* 3290001Sglebius * ng_bpf.c 4290001Sglebius * 5290001Sglebius * Copyright (c) 1999 Whistle Communications, Inc. 6290001Sglebius * All rights reserved. 7290001Sglebius * 8290001Sglebius * Subject to the following obligations and disclaimer of warranty, use and 9294905Sdelphij * redistribution of this software, in source or object code forms, with or 10290001Sglebius * without modifications are expressly permitted by Whistle Communications; 11290001Sglebius * provided, however, that: 12290001Sglebius * 1. Any and all reproductions of the source or object code must include the 13290001Sglebius * copyright notice above and the following disclaimer of warranties; and 14290001Sglebius * 2. No rights are granted, in any manner or form, to use Whistle 15290001Sglebius * Communications, Inc. trademarks, including the mark "WHISTLE 16290001Sglebius * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 17290001Sglebius * such appears in the above copyright notice or in the software. 18290001Sglebius * 19290001Sglebius * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 20290001Sglebius * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 21290001Sglebius * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 22290001Sglebius * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 23290001Sglebius * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 24290001Sglebius * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANBPF, OR MAKE ANY 25290001Sglebius * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 26290001Sglebius * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 27290001Sglebius * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 28290001Sglebius * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 29290001Sglebius * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 30290001Sglebius * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 31290001Sglebius * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 32290001Sglebius * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33290001Sglebius * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34290001Sglebius * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 35290001Sglebius * OF SUCH DAMAGE. 36290001Sglebius * 37290001Sglebius * Author: Archie Cobbs <archie@whistle.com> 38290001Sglebius * 39290001Sglebius * $FreeBSD: head/sys/netgraph/ng_bpf.c 64508 2000-08-10 22:45:54Z archie $ 40290001Sglebius * $Whistle: ng_bpf.c,v 1.3 1999/12/03 20:30:23 archie Exp $ 41290001Sglebius */ 42290001Sglebius 43290001Sglebius/* 44290001Sglebius * BPF NETGRAPH NODE TYPE 45290001Sglebius * 46290001Sglebius * This node type accepts any number of hook connections. With each hook 47290001Sglebius * is associated a bpf(4) filter program, and two hook names (each possibly 48290001Sglebius * the empty string). Incoming packets are compared against the filter; 49290001Sglebius * matching packets are delivered out the first named hook (or dropped if 50290001Sglebius * the empty string), and non-matching packets are delivered out the second 51290001Sglebius * named hook (or dropped if the empty string). 52290001Sglebius * 53290001Sglebius * Each hook also keeps statistics about how many packets have matched, etc. 54290001Sglebius */ 55290001Sglebius 56290001Sglebius#include <sys/param.h> 57290001Sglebius#include <sys/systm.h> 58290001Sglebius#include <sys/errno.h> 59290001Sglebius#include <sys/kernel.h> 60290001Sglebius#include <sys/malloc.h> 61290001Sglebius#include <sys/mbuf.h> 62290001Sglebius 63290001Sglebius#include <net/bpf.h> 64290001Sglebius 65290001Sglebius#include <netgraph/ng_message.h> 66290001Sglebius#include <netgraph/netgraph.h> 67290001Sglebius#include <netgraph/ng_parse.h> 68290001Sglebius#include <netgraph/ng_bpf.h> 69290001Sglebius 70290001Sglebius#define OFFSETOF(s, e) ((char *)&((s *)0)->e - (char *)((s *)0)) 71290001Sglebius 72290001Sglebius#define ERROUT(x) do { error = (x); goto done; } while (0) 73290001Sglebius 74290001Sglebius/* Per hook private info */ 75290001Sglebiusstruct ng_bpf_hookinfo { 76290001Sglebius node_p node; 77290001Sglebius hook_p hook; 78290001Sglebius struct ng_bpf_hookprog *prog; 79290001Sglebius struct ng_bpf_hookstat stats; 80290001Sglebius}; 81290001Sglebiustypedef struct ng_bpf_hookinfo *hinfo_p; 82290001Sglebius 83290001Sglebius/* Netgraph methods */ 84290001Sglebiusstatic ng_constructor_t ng_bpf_constructor; 85290001Sglebiusstatic ng_rcvmsg_t ng_bpf_rcvmsg; 86290001Sglebiusstatic ng_shutdown_t ng_bpf_rmnode; 87290001Sglebiusstatic ng_newhook_t ng_bpf_newhook; 88290001Sglebiusstatic ng_rcvdata_t ng_bpf_rcvdata; 89290001Sglebiusstatic ng_disconnect_t ng_bpf_disconnect; 90290001Sglebius 91290001Sglebius/* Internal helper functions */ 92290001Sglebiusstatic int ng_bpf_setprog(hook_p hook, const struct ng_bpf_hookprog *hp); 93290001Sglebius 94290001Sglebius/* Parse type for one struct bfp_insn */ 95290001Sglebiusstatic const struct ng_parse_struct_info ng_bpf_insn_type_info = { 96290001Sglebius { 97290001Sglebius { "code", &ng_parse_hint16_type }, 98290001Sglebius { "jt", &ng_parse_uint8_type }, 99290001Sglebius { "jf", &ng_parse_uint8_type }, 100290001Sglebius { "k", &ng_parse_uint32_type }, 101290001Sglebius { NULL } 102290001Sglebius } 103290001Sglebius}; 104290001Sglebiusstatic const struct ng_parse_type ng_bpf_insn_type = { 105290001Sglebius &ng_parse_struct_type, 106290001Sglebius &ng_bpf_insn_type_info 107290001Sglebius}; 108290001Sglebius 109290001Sglebius/* Parse type for the field 'bpf_prog' in struct ng_bpf_hookprog */ 110290001Sglebiusstatic int 111290001Sglebiusng_bpf_hookprogary_getLength(const struct ng_parse_type *type, 112290001Sglebius const u_char *start, const u_char *buf) 113290001Sglebius{ 114290001Sglebius const struct ng_bpf_hookprog *hp; 115290001Sglebius 116290001Sglebius hp = (const struct ng_bpf_hookprog *) 117290001Sglebius (buf - OFFSETOF(struct ng_bpf_hookprog, bpf_prog)); 118290001Sglebius return hp->bpf_prog_len; 119290001Sglebius} 120290001Sglebius 121290001Sglebiusstatic const struct ng_parse_array_info ng_bpf_hookprogary_info = { 122290001Sglebius &ng_bpf_insn_type, 123290001Sglebius &ng_bpf_hookprogary_getLength, 124290001Sglebius NULL 125290001Sglebius}; 126290001Sglebiusstatic const struct ng_parse_type ng_bpf_hookprogary_type = { 127290001Sglebius &ng_parse_array_type, 128290001Sglebius &ng_bpf_hookprogary_info 129290001Sglebius}; 130290001Sglebius 131290001Sglebius/* Parse type for struct ng_bpf_hookprog */ 132290001Sglebiusstatic const struct ng_parse_struct_info ng_bpf_hookprog_type_info 133290001Sglebius = NG_BPF_HOOKPROG_TYPE_INFO(&ng_bpf_hookprogary_type); 134290001Sglebiusstatic const struct ng_parse_type ng_bpf_hookprog_type = { 135290001Sglebius &ng_parse_struct_type, 136290001Sglebius &ng_bpf_hookprog_type_info 137290001Sglebius}; 138290001Sglebius 139290001Sglebius/* Parse type for struct ng_bpf_hookstat */ 140290001Sglebiusstatic const struct ng_parse_struct_info 141290001Sglebius ng_bpf_hookstat_type_info = NG_BPF_HOOKSTAT_TYPE_INFO; 142290001Sglebiusstatic const struct ng_parse_type ng_bpf_hookstat_type = { 143290001Sglebius &ng_parse_struct_type, 144290001Sglebius &ng_bpf_hookstat_type_info 145290001Sglebius}; 146290001Sglebius 147290001Sglebius/* List of commands and how to convert arguments to/from ASCII */ 148290001Sglebiusstatic const struct ng_cmdlist ng_bpf_cmdlist[] = { 149290001Sglebius { 150290001Sglebius NGM_BPF_COOKIE, 151290001Sglebius NGM_BPF_SET_PROGRAM, 152290001Sglebius "setprogram", 153290001Sglebius &ng_bpf_hookprog_type, 154290001Sglebius NULL 155290001Sglebius }, 156290001Sglebius { 157290001Sglebius NGM_BPF_COOKIE, 158290001Sglebius NGM_BPF_GET_PROGRAM, 159290001Sglebius "getprogram", 160290001Sglebius &ng_parse_hookbuf_type, 161290001Sglebius &ng_bpf_hookprog_type 162290001Sglebius }, 163290001Sglebius { 164290001Sglebius NGM_BPF_COOKIE, 165290001Sglebius NGM_BPF_GET_STATS, 166290001Sglebius "getstats", 167290001Sglebius &ng_parse_hookbuf_type, 168290001Sglebius &ng_bpf_hookstat_type 169290001Sglebius }, 170290001Sglebius { 171290001Sglebius NGM_BPF_COOKIE, 172290001Sglebius NGM_BPF_CLR_STATS, 173290001Sglebius "clrstats", 174290001Sglebius &ng_parse_hookbuf_type, 175290001Sglebius NULL 176290001Sglebius }, 177290001Sglebius { 178290001Sglebius NGM_BPF_COOKIE, 179290001Sglebius NGM_BPF_GETCLR_STATS, 180290001Sglebius "getclrstats", 181290001Sglebius &ng_parse_hookbuf_type, 182290001Sglebius &ng_bpf_hookstat_type 183290001Sglebius }, 184290001Sglebius { 0 } 185290001Sglebius}; 186290001Sglebius 187290001Sglebius/* Netgraph type descriptor */ 188290001Sglebiusstatic struct ng_type typestruct = { 189290001Sglebius NG_VERSION, 190290001Sglebius NG_BPF_NODE_TYPE, 191290001Sglebius NULL, 192290001Sglebius ng_bpf_constructor, 193290001Sglebius ng_bpf_rcvmsg, 194290001Sglebius ng_bpf_rmnode, 195290001Sglebius ng_bpf_newhook, 196290001Sglebius NULL, 197290001Sglebius NULL, 198290001Sglebius ng_bpf_rcvdata, 199290001Sglebius ng_bpf_rcvdata, 200290001Sglebius ng_bpf_disconnect, 201290001Sglebius ng_bpf_cmdlist 202290001Sglebius}; 203290001SglebiusNETGRAPH_INIT(bpf, &typestruct); 204290001Sglebius 205290001Sglebius/* Default BPF program for a hook that matches nothing */ 206290001Sglebiusstatic const struct ng_bpf_hookprog ng_bpf_default_prog = { 207290001Sglebius { '\0' }, /* to be filled in at hook creation time */ 208290001Sglebius { '\0' }, 209290001Sglebius { '\0' }, 210290001Sglebius 1, 211290001Sglebius { BPF_STMT(BPF_RET+BPF_K, 0) } 212290001Sglebius}; 213290001Sglebius 214290001Sglebius/* 215290001Sglebius * Node constructor 216290001Sglebius * 217290001Sglebius * We don't keep any per-node private data 218290001Sglebius */ 219290001Sglebiusstatic int 220290001Sglebiusng_bpf_constructor(node_p *nodep) 221290001Sglebius{ 222290001Sglebius int error = 0; 223290001Sglebius 224290001Sglebius if ((error = ng_make_node_common(&typestruct, nodep))) 225290001Sglebius return (error); 226290001Sglebius (*nodep)->private = NULL; 227290001Sglebius return (0); 228290001Sglebius} 229290001Sglebius 230290001Sglebius/* 231290001Sglebius * Add a hook 232290001Sglebius */ 233290001Sglebiusstatic int 234290001Sglebiusng_bpf_newhook(node_p node, hook_p hook, const char *name) 235290001Sglebius{ 236290001Sglebius hinfo_p hip; 237290001Sglebius int error; 238290001Sglebius 239290001Sglebius /* Create hook private structure */ 240290001Sglebius MALLOC(hip, hinfo_p, sizeof(*hip), M_NETGRAPH, M_WAITOK); 241290001Sglebius if (hip == NULL) 242290001Sglebius return (ENOMEM); 243290001Sglebius bzero(hip, sizeof(*hip)); 244290001Sglebius hip->hook = hook; 245290001Sglebius hook->private = hip; 246290001Sglebius hip->node = node; 247290001Sglebius 248290001Sglebius /* Attach the default BPF program */ 249290001Sglebius if ((error = ng_bpf_setprog(hook, &ng_bpf_default_prog)) != 0) { 250290001Sglebius FREE(hip, M_NETGRAPH); 251290001Sglebius hook->private = NULL; 252290001Sglebius return (error); 253290001Sglebius } 254290001Sglebius 255290001Sglebius /* Set hook name */ 256290001Sglebius strncpy(hip->prog->thisHook, name, sizeof(hip->prog->thisHook) - 1); 257290001Sglebius hip->prog->thisHook[sizeof(hip->prog->thisHook) - 1] = '\0'; 258290001Sglebius return (0); 259290001Sglebius} 260290001Sglebius 261290001Sglebius/* 262290001Sglebius * Receive a control message 263290001Sglebius */ 264290001Sglebiusstatic int 265290001Sglebiusng_bpf_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr, 266290001Sglebius struct ng_mesg **rptr, hook_p lasthook) 267290001Sglebius{ 268290001Sglebius struct ng_mesg *resp = NULL; 269290001Sglebius int error = 0; 270290001Sglebius 271290001Sglebius switch (msg->header.typecookie) { 272290001Sglebius case NGM_BPF_COOKIE: 273290001Sglebius switch (msg->header.cmd) { 274290001Sglebius case NGM_BPF_SET_PROGRAM: 275290001Sglebius { 276290001Sglebius struct ng_bpf_hookprog *const 277290001Sglebius hp = (struct ng_bpf_hookprog *)msg->data; 278290001Sglebius hook_p hook; 279290001Sglebius 280290001Sglebius /* Sanity check */ 281290001Sglebius if (msg->header.arglen < sizeof(*hp) 282290001Sglebius || msg->header.arglen 283290001Sglebius != NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len)) 284290001Sglebius ERROUT(EINVAL); 285290001Sglebius 286290001Sglebius /* Find hook */ 287290001Sglebius if ((hook = ng_findhook(node, hp->thisHook)) == NULL) 288290001Sglebius ERROUT(ENOENT); 289290001Sglebius 290290001Sglebius /* Set new program */ 291290001Sglebius if ((error = ng_bpf_setprog(hook, hp)) != 0) 292290001Sglebius ERROUT(error); 293290001Sglebius break; 294290001Sglebius } 295290001Sglebius 296290001Sglebius case NGM_BPF_GET_PROGRAM: 297290001Sglebius { 298290001Sglebius struct ng_bpf_hookprog *hp; 299290001Sglebius hook_p hook; 300290001Sglebius 301290001Sglebius /* Sanity check */ 302290001Sglebius if (msg->header.arglen == 0) 303290001Sglebius ERROUT(EINVAL); 304290001Sglebius msg->data[msg->header.arglen - 1] = '\0'; 305290001Sglebius 306290001Sglebius /* Find hook */ 307290001Sglebius if ((hook = ng_findhook(node, msg->data)) == NULL) 308290001Sglebius ERROUT(ENOENT); 309290001Sglebius 310290001Sglebius /* Build response */ 311290001Sglebius hp = ((hinfo_p)hook->private)->prog; 312290001Sglebius NG_MKRESPONSE(resp, msg, 313290001Sglebius NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len), M_NOWAIT); 314290001Sglebius if (resp == NULL) 315290001Sglebius ERROUT(ENOMEM); 316290001Sglebius bcopy(hp, resp->data, 317290001Sglebius NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len)); 318290001Sglebius break; 319290001Sglebius } 320290001Sglebius 321290001Sglebius case NGM_BPF_GET_STATS: 322290001Sglebius case NGM_BPF_CLR_STATS: 323290001Sglebius case NGM_BPF_GETCLR_STATS: 324290001Sglebius { 325290001Sglebius struct ng_bpf_hookstat *stats; 326290001Sglebius hook_p hook; 327290001Sglebius 328290001Sglebius /* Sanity check */ 329290001Sglebius if (msg->header.arglen == 0) 330290001Sglebius ERROUT(EINVAL); 331290001Sglebius msg->data[msg->header.arglen - 1] = '\0'; 332290001Sglebius 333290001Sglebius /* Find hook */ 334290001Sglebius if ((hook = ng_findhook(node, msg->data)) == NULL) 335290001Sglebius ERROUT(ENOENT); 336290001Sglebius stats = &((hinfo_p)hook->private)->stats; 337290001Sglebius 338290001Sglebius /* Build response (if desired) */ 339290001Sglebius if (msg->header.cmd != NGM_BPF_CLR_STATS) { 340290001Sglebius NG_MKRESPONSE(resp, 341290001Sglebius msg, sizeof(*stats), M_NOWAIT); 342290001Sglebius if (resp == NULL) 343290001Sglebius ERROUT(ENOMEM); 344290001Sglebius bcopy(stats, resp->data, sizeof(*stats)); 345290001Sglebius } 346290001Sglebius 347290001Sglebius /* Clear stats (if desired) */ 348290001Sglebius if (msg->header.cmd != NGM_BPF_GET_STATS) 349290001Sglebius bzero(stats, sizeof(*stats)); 350290001Sglebius break; 351290001Sglebius } 352290001Sglebius 353290001Sglebius default: 354290001Sglebius error = EINVAL; 355290001Sglebius break; 356290001Sglebius } 357290001Sglebius break; 358290001Sglebius default: 359290001Sglebius error = EINVAL; 360290001Sglebius break; 361290001Sglebius } 362290001Sglebius if (rptr) 363290001Sglebius *rptr = resp; 364290001Sglebius else if (resp) 365290001Sglebius FREE(resp, M_NETGRAPH); 366290001Sglebius 367290001Sglebiusdone: 368290001Sglebius FREE(msg, M_NETGRAPH); 369290001Sglebius return (error); 370290001Sglebius} 371290001Sglebius 372290001Sglebius/* 373290001Sglebius * Receive data on a hook 374290001Sglebius * 375290001Sglebius * Apply the filter, and then drop or forward packet as appropriate. 376290001Sglebius */ 377290001Sglebiusstatic int 378290001Sglebiusng_bpf_rcvdata(hook_p hook, struct mbuf *m, meta_p meta, 379290001Sglebius struct mbuf **ret_m, meta_p *ret_meta) 380290001Sglebius{ 381290001Sglebius const hinfo_p hip = hook->private; 382290001Sglebius int totlen = m->m_pkthdr.len; 383290001Sglebius int needfree = 0, error = 0; 384290001Sglebius u_char *data, buf[256]; 385290001Sglebius hinfo_p dhip; 386290001Sglebius hook_p dest; 387290001Sglebius u_int len; 388290001Sglebius 389290001Sglebius /* Update stats on incoming hook */ 390290001Sglebius hip->stats.recvFrames++; 391290001Sglebius hip->stats.recvOctets += totlen; 392290001Sglebius 393290001Sglebius /* Need to put packet in contiguous memory for bpf */ 394290001Sglebius if (m->m_next != NULL) { 395290001Sglebius if (totlen > sizeof(buf)) { 396290001Sglebius MALLOC(data, u_char *, totlen, M_NETGRAPH, M_NOWAIT); 397290001Sglebius if (data == NULL) { 398290001Sglebius NG_FREE_DATA(m, meta); 399290001Sglebius return (ENOMEM); 400290001Sglebius } 401290001Sglebius needfree = 1; 402290001Sglebius } else 403290001Sglebius data = buf; 404290001Sglebius m_copydata(m, 0, totlen, (caddr_t)data); 405290001Sglebius } else 406290001Sglebius data = mtod(m, u_char *); 407290001Sglebius 408290001Sglebius /* Run packet through filter */ 409290001Sglebius len = bpf_filter(hip->prog->bpf_prog, data, totlen, totlen); 410290001Sglebius if (needfree) 411290001Sglebius FREE(data, M_NETGRAPH); 412290001Sglebius 413290001Sglebius /* See if we got a match and find destination hook */ 414290001Sglebius if (len > 0) { 415290001Sglebius 416290001Sglebius /* Update stats */ 417290001Sglebius hip->stats.recvMatchFrames++; 418290001Sglebius hip->stats.recvMatchOctets += totlen; 419290001Sglebius 420290001Sglebius /* Truncate packet length if required by the filter */ 421290001Sglebius if (len < totlen) { 422290001Sglebius m_adj(m, -(totlen - len)); 423290001Sglebius totlen -= len; 424290001Sglebius } 425290001Sglebius dest = ng_findhook(hip->node, hip->prog->ifMatch); 426290001Sglebius } else 427290001Sglebius dest = ng_findhook(hip->node, hip->prog->ifNotMatch); 428290001Sglebius if (dest == NULL) { 429290001Sglebius NG_FREE_DATA(m, meta); 430290001Sglebius return (0); 431290001Sglebius } 432290001Sglebius 433290001Sglebius /* Deliver frame out destination hook */ 434290001Sglebius dhip = (hinfo_p)dest->private; 435290001Sglebius dhip->stats.xmitOctets += totlen; 436290001Sglebius dhip->stats.xmitFrames++; 437290001Sglebius NG_SEND_DATA(error, dest, m, meta); 438290001Sglebius return (error); 439290001Sglebius} 440290001Sglebius 441290001Sglebius/* 442290001Sglebius * Shutdown processing 443290001Sglebius */ 444290001Sglebiusstatic int 445290001Sglebiusng_bpf_rmnode(node_p node) 446290001Sglebius{ 447290001Sglebius node->flags |= NG_INVALID; 448290001Sglebius ng_cutlinks(node); 449290001Sglebius ng_unname(node); 450290001Sglebius ng_unref(node); 451290001Sglebius return (0); 452290001Sglebius} 453290001Sglebius 454290001Sglebius/* 455290001Sglebius * Hook disconnection 456290001Sglebius */ 457290001Sglebiusstatic int 458290001Sglebiusng_bpf_disconnect(hook_p hook) 459290001Sglebius{ 460290001Sglebius const hinfo_p hip = hook->private; 461290001Sglebius 462290001Sglebius KASSERT(hip != NULL, ("%s: null info", __FUNCTION__)); 463290001Sglebius FREE(hip->prog, M_NETGRAPH); 464290001Sglebius bzero(hip, sizeof(*hip)); 465290001Sglebius FREE(hip, M_NETGRAPH); 466290001Sglebius hook->private = NULL; /* for good measure */ 467290001Sglebius if (hook->node->numhooks == 0) 468290001Sglebius ng_rmnode(hook->node); 469290001Sglebius return (0); 470290001Sglebius} 471290001Sglebius 472290001Sglebius/************************************************************************ 473290001Sglebius HELPER STUFF 474290001Sglebius ************************************************************************/ 475290001Sglebius 476290001Sglebius/* 477290001Sglebius * Set the BPF program associated with a hook 478290001Sglebius */ 479290001Sglebiusstatic int 480290001Sglebiusng_bpf_setprog(hook_p hook, const struct ng_bpf_hookprog *hp0) 481290001Sglebius{ 482290001Sglebius const hinfo_p hip = hook->private; 483290001Sglebius struct ng_bpf_hookprog *hp; 484290001Sglebius int size; 485290001Sglebius 486290001Sglebius /* Check program for validity */ 487290001Sglebius if (!bpf_validate(hp0->bpf_prog, hp0->bpf_prog_len)) 488290001Sglebius return (EINVAL); 489290001Sglebius 490290001Sglebius /* Make a copy of the program */ 491290001Sglebius size = NG_BPF_HOOKPROG_SIZE(hp0->bpf_prog_len); 492290001Sglebius MALLOC(hp, struct ng_bpf_hookprog *, size, M_NETGRAPH, M_WAITOK); 493290001Sglebius if (hp == NULL) 494290001Sglebius return (ENOMEM); 495290001Sglebius bcopy(hp0, hp, size); 496290001Sglebius 497290001Sglebius /* Free previous program, if any, and assign new one */ 498290001Sglebius if (hip->prog != NULL) 499290001Sglebius FREE(hip->prog, M_NETGRAPH); 500290001Sglebius hip->prog = hp; 501290001Sglebius return (0); 502290001Sglebius} 503290001Sglebius 504290001Sglebius