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