xref: /freebsd/sys/netgraph/ng_patch.c (revision 426b3d047a189fc9518c95cf3d7c90b000ff82f8)
1d359a62dSAndrey V. Elsukov /*-
2bf909fc9SJulian Elischer  * Copyright (c) 2010 Maxim Ignatenko <gelraen.ua@gmail.com>
3*426b3d04SJulian Elischer  * Copyright (c) 2015 Dmitry Vagin <daemon.hammer@ya.ru>
4d359a62dSAndrey V. Elsukov  * All rights reserved.
5d359a62dSAndrey V. Elsukov  *
6d359a62dSAndrey V. Elsukov  * Redistribution and use in source and binary forms, with or without
7d359a62dSAndrey V. Elsukov  * modification, are permitted provided that the following conditions
8d359a62dSAndrey V. Elsukov  * are met:
9d359a62dSAndrey V. Elsukov  * 1. Redistributions of source code must retain the above copyright
10d359a62dSAndrey V. Elsukov  *    notice, this list of conditions and the following disclaimer.
11d359a62dSAndrey V. Elsukov  * 2. Redistributions in binary form must reproduce the above copyright
12d359a62dSAndrey V. Elsukov  *    notice, this list of conditions and the following disclaimer in the
13d359a62dSAndrey V. Elsukov  *    documentation and/or other materials provided with the distribution.
14d359a62dSAndrey V. Elsukov  *
15d359a62dSAndrey V. Elsukov  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16d359a62dSAndrey V. Elsukov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17d359a62dSAndrey V. Elsukov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18d359a62dSAndrey V. Elsukov  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19d359a62dSAndrey V. Elsukov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20d359a62dSAndrey V. Elsukov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21d359a62dSAndrey V. Elsukov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22d359a62dSAndrey V. Elsukov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23d359a62dSAndrey V. Elsukov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24d359a62dSAndrey V. Elsukov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25d359a62dSAndrey V. Elsukov  * SUCH DAMAGE.
26d359a62dSAndrey V. Elsukov  *
27d359a62dSAndrey V. Elsukov  */
28d359a62dSAndrey V. Elsukov 
29d359a62dSAndrey V. Elsukov #include <sys/cdefs.h>
30d359a62dSAndrey V. Elsukov __FBSDID("$FreeBSD$");
31d359a62dSAndrey V. Elsukov 
32d359a62dSAndrey V. Elsukov #include <sys/param.h>
33cac2fe69SAndrey V. Elsukov #include <sys/systm.h>
34d359a62dSAndrey V. Elsukov #include <sys/kernel.h>
35cac2fe69SAndrey V. Elsukov #include <sys/endian.h>
366c0a2eb1SAndrey V. Elsukov #include <sys/malloc.h>
376c0a2eb1SAndrey V. Elsukov #include <sys/mbuf.h>
38*426b3d04SJulian Elischer 
39*426b3d04SJulian Elischer #include <net/bpf.h>
40*426b3d04SJulian Elischer #include <net/ethernet.h>
41*426b3d04SJulian Elischer 
42d359a62dSAndrey V. Elsukov #include <netgraph/ng_message.h>
43d359a62dSAndrey V. Elsukov #include <netgraph/ng_parse.h>
44d359a62dSAndrey V. Elsukov #include <netgraph/netgraph.h>
45d359a62dSAndrey V. Elsukov 
46*426b3d04SJulian Elischer #include <netgraph/ng_patch.h>
47*426b3d04SJulian Elischer 
48*426b3d04SJulian Elischer /* private data */
49*426b3d04SJulian Elischer struct ng_patch_priv {
50*426b3d04SJulian Elischer 	hook_p		in;
51*426b3d04SJulian Elischer 	hook_p		out;
52*426b3d04SJulian Elischer 	uint8_t		dlt;	/* DLT_XXX from bpf.h */
53*426b3d04SJulian Elischer 	struct ng_patch_stats stats;
54*426b3d04SJulian Elischer 	struct ng_patch_config *conf;
55*426b3d04SJulian Elischer };
56*426b3d04SJulian Elischer 
57*426b3d04SJulian Elischer typedef struct ng_patch_priv *priv_p;
58*426b3d04SJulian Elischer 
59*426b3d04SJulian Elischer /* Netgraph methods */
60d359a62dSAndrey V. Elsukov static ng_constructor_t	ng_patch_constructor;
61d359a62dSAndrey V. Elsukov static ng_rcvmsg_t	ng_patch_rcvmsg;
62d359a62dSAndrey V. Elsukov static ng_shutdown_t	ng_patch_shutdown;
63d359a62dSAndrey V. Elsukov static ng_newhook_t	ng_patch_newhook;
64d359a62dSAndrey V. Elsukov static ng_rcvdata_t	ng_patch_rcvdata;
65d359a62dSAndrey V. Elsukov static ng_disconnect_t	ng_patch_disconnect;
66d359a62dSAndrey V. Elsukov 
67*426b3d04SJulian Elischer #define ERROUT(x) { error = (x); goto done; }
68*426b3d04SJulian Elischer 
69d359a62dSAndrey V. Elsukov static int
706c0a2eb1SAndrey V. Elsukov ng_patch_config_getlen(const struct ng_parse_type *type,
716c0a2eb1SAndrey V. Elsukov     const u_char *start, const u_char *buf)
72d359a62dSAndrey V. Elsukov {
73bf909fc9SJulian Elischer 	const struct ng_patch_config *conf;
74d359a62dSAndrey V. Elsukov 
75bf909fc9SJulian Elischer 	conf = (const struct ng_patch_config *)(buf -
76cac2fe69SAndrey V. Elsukov 	    offsetof(struct ng_patch_config, ops));
77bf909fc9SJulian Elischer 
78bf909fc9SJulian Elischer 	return (conf->count);
79d359a62dSAndrey V. Elsukov }
80d359a62dSAndrey V. Elsukov 
81d359a62dSAndrey V. Elsukov static const struct ng_parse_struct_field ng_patch_op_type_fields[]
82*426b3d04SJulian Elischer 	= NG_PATCH_OP_TYPE;
83d359a62dSAndrey V. Elsukov static const struct ng_parse_type ng_patch_op_type = {
84d359a62dSAndrey V. Elsukov 	&ng_parse_struct_type,
85d359a62dSAndrey V. Elsukov 	&ng_patch_op_type_fields
86d359a62dSAndrey V. Elsukov };
87d359a62dSAndrey V. Elsukov 
88bf909fc9SJulian Elischer static const struct ng_parse_array_info ng_patch_ops_array_info = {
89d359a62dSAndrey V. Elsukov 	&ng_patch_op_type,
90d359a62dSAndrey V. Elsukov 	&ng_patch_config_getlen
91d359a62dSAndrey V. Elsukov };
92bf909fc9SJulian Elischer static const struct ng_parse_type ng_patch_ops_array_type = {
93d359a62dSAndrey V. Elsukov 	&ng_parse_array_type,
94bf909fc9SJulian Elischer 	&ng_patch_ops_array_info
95d359a62dSAndrey V. Elsukov };
96d359a62dSAndrey V. Elsukov 
97d359a62dSAndrey V. Elsukov static const struct ng_parse_struct_field ng_patch_config_type_fields[]
98*426b3d04SJulian Elischer 	= NG_PATCH_CONFIG_TYPE;
99d359a62dSAndrey V. Elsukov static const struct ng_parse_type ng_patch_config_type = {
100d359a62dSAndrey V. Elsukov 	&ng_parse_struct_type,
101d359a62dSAndrey V. Elsukov 	&ng_patch_config_type_fields
102d359a62dSAndrey V. Elsukov };
103d359a62dSAndrey V. Elsukov 
104d359a62dSAndrey V. Elsukov static const struct ng_parse_struct_field ng_patch_stats_fields[]
105*426b3d04SJulian Elischer 	= NG_PATCH_STATS_TYPE;
106d359a62dSAndrey V. Elsukov static const struct ng_parse_type ng_patch_stats_type = {
107d359a62dSAndrey V. Elsukov 	&ng_parse_struct_type,
108d359a62dSAndrey V. Elsukov 	&ng_patch_stats_fields
109d359a62dSAndrey V. Elsukov };
110d359a62dSAndrey V. Elsukov 
111d359a62dSAndrey V. Elsukov static const struct ng_cmdlist ng_patch_cmdlist[] = {
112d359a62dSAndrey V. Elsukov 	{
113d359a62dSAndrey V. Elsukov 		NGM_PATCH_COOKIE,
114*426b3d04SJulian Elischer 		NGM_PATCH_GETDLT,
115*426b3d04SJulian Elischer 		"getdlt",
116*426b3d04SJulian Elischer 		NULL,
117*426b3d04SJulian Elischer 		&ng_parse_uint8_type
118*426b3d04SJulian Elischer 	},
119*426b3d04SJulian Elischer 	{
120*426b3d04SJulian Elischer 		NGM_PATCH_COOKIE,
121*426b3d04SJulian Elischer 		NGM_PATCH_SETDLT,
122*426b3d04SJulian Elischer 		"setdlt",
123*426b3d04SJulian Elischer 		&ng_parse_uint8_type,
124*426b3d04SJulian Elischer 		NULL
125*426b3d04SJulian Elischer 	},
126*426b3d04SJulian Elischer 	{
127*426b3d04SJulian Elischer 		NGM_PATCH_COOKIE,
128d359a62dSAndrey V. Elsukov 		NGM_PATCH_GETCONFIG,
129d359a62dSAndrey V. Elsukov 		"getconfig",
130d359a62dSAndrey V. Elsukov 		NULL,
131d359a62dSAndrey V. Elsukov 		&ng_patch_config_type
132d359a62dSAndrey V. Elsukov 	},
133d359a62dSAndrey V. Elsukov 	{
134d359a62dSAndrey V. Elsukov 		NGM_PATCH_COOKIE,
135d359a62dSAndrey V. Elsukov 		NGM_PATCH_SETCONFIG,
136d359a62dSAndrey V. Elsukov 		"setconfig",
137d359a62dSAndrey V. Elsukov 		&ng_patch_config_type,
138d359a62dSAndrey V. Elsukov 		NULL
139d359a62dSAndrey V. Elsukov 	},
140d359a62dSAndrey V. Elsukov 	{
141d359a62dSAndrey V. Elsukov 		NGM_PATCH_COOKIE,
142d359a62dSAndrey V. Elsukov 		NGM_PATCH_GET_STATS,
143d359a62dSAndrey V. Elsukov 		"getstats",
144d359a62dSAndrey V. Elsukov 		NULL,
145d359a62dSAndrey V. Elsukov 		&ng_patch_stats_type
146d359a62dSAndrey V. Elsukov 	},
147d359a62dSAndrey V. Elsukov 	{
148d359a62dSAndrey V. Elsukov 		NGM_PATCH_COOKIE,
149d359a62dSAndrey V. Elsukov 		NGM_PATCH_CLR_STATS,
150d359a62dSAndrey V. Elsukov 		"clrstats",
151d359a62dSAndrey V. Elsukov 		NULL,
152d359a62dSAndrey V. Elsukov 		NULL
153d359a62dSAndrey V. Elsukov 	},
154d359a62dSAndrey V. Elsukov 	{
155d359a62dSAndrey V. Elsukov 		NGM_PATCH_COOKIE,
156d359a62dSAndrey V. Elsukov 		NGM_PATCH_GETCLR_STATS,
157d359a62dSAndrey V. Elsukov 		"getclrstats",
158d359a62dSAndrey V. Elsukov 		NULL,
159d359a62dSAndrey V. Elsukov 		&ng_patch_stats_type
160d359a62dSAndrey V. Elsukov 	},
161d359a62dSAndrey V. Elsukov 	{ 0 }
162d359a62dSAndrey V. Elsukov };
163d359a62dSAndrey V. Elsukov 
164d359a62dSAndrey V. Elsukov static struct ng_type typestruct = {
165d359a62dSAndrey V. Elsukov 	.version =	NG_ABI_VERSION,
166d359a62dSAndrey V. Elsukov 	.name =		NG_PATCH_NODE_TYPE,
167d359a62dSAndrey V. Elsukov 	.constructor =	ng_patch_constructor,
168d359a62dSAndrey V. Elsukov 	.rcvmsg =	ng_patch_rcvmsg,
169d359a62dSAndrey V. Elsukov 	.shutdown =	ng_patch_shutdown,
170d359a62dSAndrey V. Elsukov 	.newhook =	ng_patch_newhook,
171d359a62dSAndrey V. Elsukov 	.rcvdata =	ng_patch_rcvdata,
172d359a62dSAndrey V. Elsukov 	.disconnect =	ng_patch_disconnect,
173d359a62dSAndrey V. Elsukov 	.cmdlist =	ng_patch_cmdlist,
174d359a62dSAndrey V. Elsukov };
175bf909fc9SJulian Elischer 
176d359a62dSAndrey V. Elsukov NETGRAPH_INIT(patch, &typestruct);
177d359a62dSAndrey V. Elsukov 
178d359a62dSAndrey V. Elsukov static int
179d359a62dSAndrey V. Elsukov ng_patch_constructor(node_p node)
180d359a62dSAndrey V. Elsukov {
181d359a62dSAndrey V. Elsukov 	priv_p privdata;
182d359a62dSAndrey V. Elsukov 
183ffbfc0aaSAndrey V. Elsukov 	privdata = malloc(sizeof(*privdata), M_NETGRAPH, M_WAITOK | M_ZERO);
184*426b3d04SJulian Elischer 	privdata->dlt = DLT_RAW;
185*426b3d04SJulian Elischer 
186d359a62dSAndrey V. Elsukov 	NG_NODE_SET_PRIVATE(node, privdata);
187*426b3d04SJulian Elischer 
188d359a62dSAndrey V. Elsukov 	return (0);
189d359a62dSAndrey V. Elsukov }
190d359a62dSAndrey V. Elsukov 
191d359a62dSAndrey V. Elsukov static int
192d359a62dSAndrey V. Elsukov ng_patch_newhook(node_p node, hook_p hook, const char *name)
193d359a62dSAndrey V. Elsukov {
194d359a62dSAndrey V. Elsukov 	const priv_p privp = NG_NODE_PRIVATE(node);
195d359a62dSAndrey V. Elsukov 
196d359a62dSAndrey V. Elsukov 	if (strncmp(name, NG_PATCH_HOOK_IN, strlen(NG_PATCH_HOOK_IN)) == 0) {
197d359a62dSAndrey V. Elsukov 		privp->in = hook;
198d359a62dSAndrey V. Elsukov 	} else if (strncmp(name, NG_PATCH_HOOK_OUT,
199d359a62dSAndrey V. Elsukov 	    strlen(NG_PATCH_HOOK_OUT)) == 0) {
200d359a62dSAndrey V. Elsukov 		privp->out = hook;
201d359a62dSAndrey V. Elsukov 	} else
202d359a62dSAndrey V. Elsukov 		return (EINVAL);
203*426b3d04SJulian Elischer 
204d359a62dSAndrey V. Elsukov 	return (0);
205d359a62dSAndrey V. Elsukov }
206d359a62dSAndrey V. Elsukov 
207d359a62dSAndrey V. Elsukov static int
208d359a62dSAndrey V. Elsukov ng_patch_rcvmsg(node_p node, item_p item, hook_p lasthook)
209d359a62dSAndrey V. Elsukov {
210d359a62dSAndrey V. Elsukov 	const priv_p privp = NG_NODE_PRIVATE(node);
2116c0a2eb1SAndrey V. Elsukov 	struct ng_patch_config *conf, *newconf;
212d359a62dSAndrey V. Elsukov 	struct ng_mesg *msg;
213*426b3d04SJulian Elischer 	struct ng_mesg *resp = NULL;
214*426b3d04SJulian Elischer 	int i, error = 0;
215d359a62dSAndrey V. Elsukov 
216d359a62dSAndrey V. Elsukov 	NGI_GET_MSG(item, msg);
217*426b3d04SJulian Elischer 
218*426b3d04SJulian Elischer 	if  (msg->header.typecookie != NGM_PATCH_COOKIE)
219*426b3d04SJulian Elischer 		ERROUT(EINVAL);
220*426b3d04SJulian Elischer 
221*426b3d04SJulian Elischer 	switch (msg->header.cmd)
222d359a62dSAndrey V. Elsukov 	{
223*426b3d04SJulian Elischer 		case NGM_PATCH_GETCONFIG:
224*426b3d04SJulian Elischer 			if (privp->conf == NULL)
225*426b3d04SJulian Elischer 				ERROUT(0);
226*426b3d04SJulian Elischer 
227*426b3d04SJulian Elischer 			NG_MKRESPONSE(resp, msg,
228*426b3d04SJulian Elischer 			    NG_PATCH_CONF_SIZE(privp->conf->count), M_WAITOK);
229*426b3d04SJulian Elischer 
230*426b3d04SJulian Elischer 			if (resp == NULL)
231*426b3d04SJulian Elischer 				ERROUT(ENOMEM);
232*426b3d04SJulian Elischer 
233*426b3d04SJulian Elischer 			bcopy(privp->conf, resp->data,
234*426b3d04SJulian Elischer 			    NG_PATCH_CONF_SIZE(privp->conf->count));
235*426b3d04SJulian Elischer 
236*426b3d04SJulian Elischer 			conf = (struct ng_patch_config *) resp->data;
237*426b3d04SJulian Elischer 
238*426b3d04SJulian Elischer 			for (i = 0; i < conf->count; i++) {
239*426b3d04SJulian Elischer 				switch (conf->ops[i].length)
240*426b3d04SJulian Elischer 				{
241*426b3d04SJulian Elischer 					case 1:
242*426b3d04SJulian Elischer 						conf->ops[i].val.v8 = conf->ops[i].val.v1;
243*426b3d04SJulian Elischer 						break;
244*426b3d04SJulian Elischer 					case 2:
245*426b3d04SJulian Elischer 						conf->ops[i].val.v8 = conf->ops[i].val.v2;
246*426b3d04SJulian Elischer 						break;
247*426b3d04SJulian Elischer 					case 4:
248*426b3d04SJulian Elischer 						conf->ops[i].val.v8 = conf->ops[i].val.v4;
249*426b3d04SJulian Elischer 						break;
250*426b3d04SJulian Elischer 					case 8:
251d359a62dSAndrey V. Elsukov 						break;
252d359a62dSAndrey V. Elsukov 				}
253*426b3d04SJulian Elischer 			}
254d359a62dSAndrey V. Elsukov 
255*426b3d04SJulian Elischer 			break;
256*426b3d04SJulian Elischer 
257*426b3d04SJulian Elischer 		case NGM_PATCH_SETCONFIG:
258d359a62dSAndrey V. Elsukov 			conf = (struct ng_patch_config *) msg->data;
259*426b3d04SJulian Elischer 
260*426b3d04SJulian Elischer 			if (msg->header.arglen < sizeof(struct ng_patch_config) ||
261*426b3d04SJulian Elischer 			    msg->header.arglen < NG_PATCH_CONF_SIZE(conf->count))
262*426b3d04SJulian Elischer 				ERROUT(EINVAL);
263d359a62dSAndrey V. Elsukov 
264d359a62dSAndrey V. Elsukov 			for (i = 0; i < conf->count; i++) {
265*426b3d04SJulian Elischer 				switch (conf->ops[i].length)
266*426b3d04SJulian Elischer 				{
267d359a62dSAndrey V. Elsukov 					case 1:
268*426b3d04SJulian Elischer 						conf->ops[i].val.v1 = (uint8_t) conf->ops[i].val.v8;
269*426b3d04SJulian Elischer 						break;
270d359a62dSAndrey V. Elsukov 					case 2:
271*426b3d04SJulian Elischer 						conf->ops[i].val.v2 = (uint16_t) conf->ops[i].val.v8;
272*426b3d04SJulian Elischer 						break;
273d359a62dSAndrey V. Elsukov 					case 4:
274*426b3d04SJulian Elischer 						conf->ops[i].val.v4 = (uint32_t) conf->ops[i].val.v8;
275*426b3d04SJulian Elischer 						break;
276d359a62dSAndrey V. Elsukov 					case 8:
277d359a62dSAndrey V. Elsukov 						break;
278d359a62dSAndrey V. Elsukov 					default:
279*426b3d04SJulian Elischer 						ERROUT(EINVAL);
280d359a62dSAndrey V. Elsukov 				}
281d359a62dSAndrey V. Elsukov 			}
282d359a62dSAndrey V. Elsukov 
283*426b3d04SJulian Elischer 			conf->csum_flags &= NG_PATCH_CSUM_IPV4|NG_PATCH_CSUM_IPV6;
284*426b3d04SJulian Elischer 			conf->relative_offset = !!conf->relative_offset;
285d359a62dSAndrey V. Elsukov 
286*426b3d04SJulian Elischer 			newconf = malloc(NG_PATCH_CONF_SIZE(conf->count), M_NETGRAPH, M_WAITOK | M_ZERO);
287*426b3d04SJulian Elischer 
288*426b3d04SJulian Elischer 			bcopy(conf, newconf, NG_PATCH_CONF_SIZE(conf->count));
289*426b3d04SJulian Elischer 
290*426b3d04SJulian Elischer 			if (privp->conf)
291*426b3d04SJulian Elischer 				free(privp->conf, M_NETGRAPH);
292*426b3d04SJulian Elischer 
293*426b3d04SJulian Elischer 			privp->conf = newconf;
294*426b3d04SJulian Elischer 
295d359a62dSAndrey V. Elsukov 			break;
296*426b3d04SJulian Elischer 
297d359a62dSAndrey V. Elsukov 		case NGM_PATCH_GET_STATS:
298d359a62dSAndrey V. Elsukov 		case NGM_PATCH_CLR_STATS:
299*426b3d04SJulian Elischer 		case NGM_PATCH_GETCLR_STATS:
300*426b3d04SJulian Elischer 			if (msg->header.cmd != NGM_PATCH_CLR_STATS) {
301*426b3d04SJulian Elischer 				NG_MKRESPONSE(resp, msg, sizeof(struct ng_patch_stats), M_WAITOK);
302*426b3d04SJulian Elischer 
303*426b3d04SJulian Elischer 				if (resp == NULL)
304*426b3d04SJulian Elischer 					ERROUT(ENOMEM);
305*426b3d04SJulian Elischer 
306*426b3d04SJulian Elischer 				bcopy(&(privp->stats), resp->data, sizeof(struct ng_patch_stats));
307d359a62dSAndrey V. Elsukov 			}
308d359a62dSAndrey V. Elsukov 
309*426b3d04SJulian Elischer 			if (msg->header.cmd != NGM_PATCH_GET_STATS)
310*426b3d04SJulian Elischer 				bzero(&(privp->stats), sizeof(struct ng_patch_stats));
311*426b3d04SJulian Elischer 
312*426b3d04SJulian Elischer 			break;
313*426b3d04SJulian Elischer 
314*426b3d04SJulian Elischer 		case NGM_PATCH_GETDLT:
315*426b3d04SJulian Elischer 			NG_MKRESPONSE(resp, msg, sizeof(uint8_t), M_WAITOK);
316*426b3d04SJulian Elischer 
317*426b3d04SJulian Elischer 			if (resp == NULL)
318*426b3d04SJulian Elischer 				ERROUT(ENOMEM);
319*426b3d04SJulian Elischer 
320*426b3d04SJulian Elischer 			*((uint8_t *) resp->data) = privp->dlt;
321*426b3d04SJulian Elischer 
322*426b3d04SJulian Elischer 			break;
323*426b3d04SJulian Elischer 
324*426b3d04SJulian Elischer 		case NGM_PATCH_SETDLT:
325*426b3d04SJulian Elischer 			if (msg->header.arglen != sizeof(uint8_t))
326*426b3d04SJulian Elischer 				ERROUT(EINVAL);
327*426b3d04SJulian Elischer 
328*426b3d04SJulian Elischer 			switch (*(uint8_t *) msg->data)
329*426b3d04SJulian Elischer 			{
330*426b3d04SJulian Elischer 				case DLT_EN10MB:
331*426b3d04SJulian Elischer 				case DLT_RAW:
332*426b3d04SJulian Elischer 					privp->dlt = *(uint8_t *) msg->data;
333*426b3d04SJulian Elischer 					break;
334*426b3d04SJulian Elischer 
335*426b3d04SJulian Elischer 				default:
336*426b3d04SJulian Elischer 					ERROUT(EINVAL);
337*426b3d04SJulian Elischer 			}
338*426b3d04SJulian Elischer 
339*426b3d04SJulian Elischer 			break;
340*426b3d04SJulian Elischer 
341*426b3d04SJulian Elischer 		default:
342*426b3d04SJulian Elischer 			ERROUT(EINVAL);
343*426b3d04SJulian Elischer 	}
344*426b3d04SJulian Elischer 
345*426b3d04SJulian Elischer done:
346d359a62dSAndrey V. Elsukov 	NG_RESPOND_MSG(error, node, item, resp);
347d359a62dSAndrey V. Elsukov 	NG_FREE_MSG(msg);
348*426b3d04SJulian Elischer 
349d359a62dSAndrey V. Elsukov 	return (error);
350d359a62dSAndrey V. Elsukov }
351d359a62dSAndrey V. Elsukov 
352d359a62dSAndrey V. Elsukov static void
353*426b3d04SJulian Elischer do_patch(priv_p privp, struct mbuf *m, int global_offset)
354d359a62dSAndrey V. Elsukov {
355*426b3d04SJulian Elischer 	int i, offset, patched = 0;
356*426b3d04SJulian Elischer 	union ng_patch_op_val val;
357d359a62dSAndrey V. Elsukov 
358*426b3d04SJulian Elischer 	for (i = 0; i < privp->conf->count; i++) {
359*426b3d04SJulian Elischer 		offset = global_offset + privp->conf->ops[i].offset;
360*426b3d04SJulian Elischer 
361*426b3d04SJulian Elischer 		if (offset + privp->conf->ops[i].length > m->m_pkthdr.len)
362d359a62dSAndrey V. Elsukov 			continue;
363d359a62dSAndrey V. Elsukov 
364d359a62dSAndrey V. Elsukov 		/* for "=" operation we don't need to copy data from mbuf */
365*426b3d04SJulian Elischer 		if (privp->conf->ops[i].mode != NG_PATCH_MODE_SET)
366*426b3d04SJulian Elischer 			m_copydata(m, offset, privp->conf->ops[i].length, (caddr_t) &val);
367d359a62dSAndrey V. Elsukov 
368*426b3d04SJulian Elischer 		switch (privp->conf->ops[i].length)
369*426b3d04SJulian Elischer 		{
370d359a62dSAndrey V. Elsukov 			case 1:
371*426b3d04SJulian Elischer 				switch (privp->conf->ops[i].mode)
372*426b3d04SJulian Elischer 				{
373d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_SET:
374*426b3d04SJulian Elischer 						val.v1 = privp->conf->ops[i].val.v1;
375d359a62dSAndrey V. Elsukov 						break;
376d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_ADD:
377*426b3d04SJulian Elischer 						val.v1 += privp->conf->ops[i].val.v1;
378d359a62dSAndrey V. Elsukov 						break;
379d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_SUB:
380*426b3d04SJulian Elischer 						val.v1 -= privp->conf->ops[i].val.v1;
381d359a62dSAndrey V. Elsukov 						break;
382d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_MUL:
383*426b3d04SJulian Elischer 						val.v1 *= privp->conf->ops[i].val.v1;
384d359a62dSAndrey V. Elsukov 						break;
385d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_DIV:
386*426b3d04SJulian Elischer 						val.v1 /= privp->conf->ops[i].val.v1;
387d359a62dSAndrey V. Elsukov 						break;
388d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_NEG:
389*426b3d04SJulian Elischer 						*((int8_t *) &val) = - *((int8_t *) &val);
390d359a62dSAndrey V. Elsukov 						break;
391d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_AND:
392*426b3d04SJulian Elischer 						val.v1 &= privp->conf->ops[i].val.v1;
393d359a62dSAndrey V. Elsukov 						break;
394d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_OR:
395*426b3d04SJulian Elischer 						val.v1 |= privp->conf->ops[i].val.v1;
396d359a62dSAndrey V. Elsukov 						break;
397d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_XOR:
398*426b3d04SJulian Elischer 						val.v1 ^= privp->conf->ops[i].val.v1;
399d359a62dSAndrey V. Elsukov 						break;
400d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_SHL:
401*426b3d04SJulian Elischer 						val.v1 <<= privp->conf->ops[i].val.v1;
402d359a62dSAndrey V. Elsukov 						break;
403d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_SHR:
404*426b3d04SJulian Elischer 						val.v1 >>= privp->conf->ops[i].val.v1;
405d359a62dSAndrey V. Elsukov 						break;
406d359a62dSAndrey V. Elsukov 				}
407d359a62dSAndrey V. Elsukov 				break;
408*426b3d04SJulian Elischer 
409d359a62dSAndrey V. Elsukov 			case 2:
410*426b3d04SJulian Elischer 				val.v2 = ntohs(val.v2);
411*426b3d04SJulian Elischer 
412*426b3d04SJulian Elischer 				switch (privp->conf->ops[i].mode)
413*426b3d04SJulian Elischer 				{
414d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_SET:
415*426b3d04SJulian Elischer 						val.v2 = privp->conf->ops[i].val.v2;
416d359a62dSAndrey V. Elsukov 						break;
417d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_ADD:
418*426b3d04SJulian Elischer 						val.v2 += privp->conf->ops[i].val.v2;
419d359a62dSAndrey V. Elsukov 						break;
420d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_SUB:
421*426b3d04SJulian Elischer 						val.v2 -= privp->conf->ops[i].val.v2;
422d359a62dSAndrey V. Elsukov 						break;
423d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_MUL:
424*426b3d04SJulian Elischer 						val.v2 *= privp->conf->ops[i].val.v2;
425d359a62dSAndrey V. Elsukov 						break;
426d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_DIV:
427*426b3d04SJulian Elischer 						val.v2 /= privp->conf->ops[i].val.v2;
428d359a62dSAndrey V. Elsukov 						break;
429d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_NEG:
430*426b3d04SJulian Elischer 						*((int16_t *) &val) = - *((int16_t *) &val);
431d359a62dSAndrey V. Elsukov 						break;
432d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_AND:
433*426b3d04SJulian Elischer 						val.v2 &= privp->conf->ops[i].val.v2;
434d359a62dSAndrey V. Elsukov 						break;
435d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_OR:
436*426b3d04SJulian Elischer 						val.v2 |= privp->conf->ops[i].val.v2;
437d359a62dSAndrey V. Elsukov 						break;
438d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_XOR:
439*426b3d04SJulian Elischer 						val.v2 ^= privp->conf->ops[i].val.v2;
440d359a62dSAndrey V. Elsukov 						break;
441d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_SHL:
442*426b3d04SJulian Elischer 						val.v2 <<= privp->conf->ops[i].val.v2;
443d359a62dSAndrey V. Elsukov 						break;
444d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_SHR:
445*426b3d04SJulian Elischer 						val.v2 >>= privp->conf->ops[i].val.v2;
446d359a62dSAndrey V. Elsukov 						break;
447d359a62dSAndrey V. Elsukov 				}
448d359a62dSAndrey V. Elsukov 
449*426b3d04SJulian Elischer 				val.v2 = htons(val.v2);
450*426b3d04SJulian Elischer 
451*426b3d04SJulian Elischer 				break;
452*426b3d04SJulian Elischer 
453*426b3d04SJulian Elischer 			case 4:
454*426b3d04SJulian Elischer 				val.v4 = ntohl(val.v4);
455*426b3d04SJulian Elischer 
456*426b3d04SJulian Elischer 				switch (privp->conf->ops[i].mode)
457*426b3d04SJulian Elischer 				{
458*426b3d04SJulian Elischer 					case NG_PATCH_MODE_SET:
459*426b3d04SJulian Elischer 						val.v4 = privp->conf->ops[i].val.v4;
460*426b3d04SJulian Elischer 						break;
461*426b3d04SJulian Elischer 					case NG_PATCH_MODE_ADD:
462*426b3d04SJulian Elischer 						val.v4 += privp->conf->ops[i].val.v4;
463*426b3d04SJulian Elischer 						break;
464*426b3d04SJulian Elischer 					case NG_PATCH_MODE_SUB:
465*426b3d04SJulian Elischer 						val.v4 -= privp->conf->ops[i].val.v4;
466*426b3d04SJulian Elischer 						break;
467*426b3d04SJulian Elischer 					case NG_PATCH_MODE_MUL:
468*426b3d04SJulian Elischer 						val.v4 *= privp->conf->ops[i].val.v4;
469*426b3d04SJulian Elischer 						break;
470*426b3d04SJulian Elischer 					case NG_PATCH_MODE_DIV:
471*426b3d04SJulian Elischer 						val.v4 /= privp->conf->ops[i].val.v4;
472*426b3d04SJulian Elischer 						break;
473*426b3d04SJulian Elischer 					case NG_PATCH_MODE_NEG:
474*426b3d04SJulian Elischer 						*((int32_t *) &val) = - *((int32_t *) &val);
475*426b3d04SJulian Elischer 						break;
476*426b3d04SJulian Elischer 					case NG_PATCH_MODE_AND:
477*426b3d04SJulian Elischer 						val.v4 &= privp->conf->ops[i].val.v4;
478*426b3d04SJulian Elischer 						break;
479*426b3d04SJulian Elischer 					case NG_PATCH_MODE_OR:
480*426b3d04SJulian Elischer 						val.v4 |= privp->conf->ops[i].val.v4;
481*426b3d04SJulian Elischer 						break;
482*426b3d04SJulian Elischer 					case NG_PATCH_MODE_XOR:
483*426b3d04SJulian Elischer 						val.v4 ^= privp->conf->ops[i].val.v4;
484*426b3d04SJulian Elischer 						break;
485*426b3d04SJulian Elischer 					case NG_PATCH_MODE_SHL:
486*426b3d04SJulian Elischer 						val.v4 <<= privp->conf->ops[i].val.v4;
487*426b3d04SJulian Elischer 						break;
488*426b3d04SJulian Elischer 					case NG_PATCH_MODE_SHR:
489*426b3d04SJulian Elischer 						val.v4 >>= privp->conf->ops[i].val.v4;
490*426b3d04SJulian Elischer 						break;
491*426b3d04SJulian Elischer 				}
492*426b3d04SJulian Elischer 
493*426b3d04SJulian Elischer 				val.v4 = htonl(val.v4);
494*426b3d04SJulian Elischer 
495*426b3d04SJulian Elischer 				break;
496*426b3d04SJulian Elischer 
497*426b3d04SJulian Elischer 			case 8:
498*426b3d04SJulian Elischer 				val.v8 = be64toh(val.v8);
499*426b3d04SJulian Elischer 
500*426b3d04SJulian Elischer 				switch (privp->conf->ops[i].mode)
501*426b3d04SJulian Elischer 				{
502*426b3d04SJulian Elischer 					case NG_PATCH_MODE_SET:
503*426b3d04SJulian Elischer 						val.v8 = privp->conf->ops[i].val.v8;
504*426b3d04SJulian Elischer 						break;
505*426b3d04SJulian Elischer 					case NG_PATCH_MODE_ADD:
506*426b3d04SJulian Elischer 						val.v8 += privp->conf->ops[i].val.v8;
507*426b3d04SJulian Elischer 						break;
508*426b3d04SJulian Elischer 					case NG_PATCH_MODE_SUB:
509*426b3d04SJulian Elischer 						val.v8 -= privp->conf->ops[i].val.v8;
510*426b3d04SJulian Elischer 						break;
511*426b3d04SJulian Elischer 					case NG_PATCH_MODE_MUL:
512*426b3d04SJulian Elischer 						val.v8 *= privp->conf->ops[i].val.v8;
513*426b3d04SJulian Elischer 						break;
514*426b3d04SJulian Elischer 					case NG_PATCH_MODE_DIV:
515*426b3d04SJulian Elischer 						val.v8 /= privp->conf->ops[i].val.v8;
516*426b3d04SJulian Elischer 						break;
517*426b3d04SJulian Elischer 					case NG_PATCH_MODE_NEG:
518*426b3d04SJulian Elischer 						*((int64_t *) &val) = - *((int64_t *) &val);
519*426b3d04SJulian Elischer 						break;
520*426b3d04SJulian Elischer 					case NG_PATCH_MODE_AND:
521*426b3d04SJulian Elischer 						val.v8 &= privp->conf->ops[i].val.v8;
522*426b3d04SJulian Elischer 						break;
523*426b3d04SJulian Elischer 					case NG_PATCH_MODE_OR:
524*426b3d04SJulian Elischer 						val.v8 |= privp->conf->ops[i].val.v8;
525*426b3d04SJulian Elischer 						break;
526*426b3d04SJulian Elischer 					case NG_PATCH_MODE_XOR:
527*426b3d04SJulian Elischer 						val.v8 ^= privp->conf->ops[i].val.v8;
528*426b3d04SJulian Elischer 						break;
529*426b3d04SJulian Elischer 					case NG_PATCH_MODE_SHL:
530*426b3d04SJulian Elischer 						val.v8 <<= privp->conf->ops[i].val.v8;
531*426b3d04SJulian Elischer 						break;
532*426b3d04SJulian Elischer 					case NG_PATCH_MODE_SHR:
533*426b3d04SJulian Elischer 						val.v8 >>= privp->conf->ops[i].val.v8;
534*426b3d04SJulian Elischer 						break;
535*426b3d04SJulian Elischer 				}
536*426b3d04SJulian Elischer 
537*426b3d04SJulian Elischer 				val.v8 = htobe64(val.v8);
538*426b3d04SJulian Elischer 
539*426b3d04SJulian Elischer 				break;
540*426b3d04SJulian Elischer 		}
541*426b3d04SJulian Elischer 
542*426b3d04SJulian Elischer 		m_copyback(m, offset, privp->conf->ops[i].length, (caddr_t) &val);
543d359a62dSAndrey V. Elsukov 		patched = 1;
544d359a62dSAndrey V. Elsukov 	}
545*426b3d04SJulian Elischer 
546*426b3d04SJulian Elischer 	if (patched)
547d359a62dSAndrey V. Elsukov 		privp->stats.patched++;
548d359a62dSAndrey V. Elsukov }
549d359a62dSAndrey V. Elsukov 
550d359a62dSAndrey V. Elsukov static int
551d359a62dSAndrey V. Elsukov ng_patch_rcvdata(hook_p hook, item_p item)
552d359a62dSAndrey V. Elsukov {
553d359a62dSAndrey V. Elsukov 	const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
554d359a62dSAndrey V. Elsukov 	struct mbuf *m;
555*426b3d04SJulian Elischer 	hook_p out;
556*426b3d04SJulian Elischer 	int pullup_len = 0;
557*426b3d04SJulian Elischer 	int error = 0;
558d359a62dSAndrey V. Elsukov 
559d359a62dSAndrey V. Elsukov 	priv->stats.received++;
560*426b3d04SJulian Elischer 
561d359a62dSAndrey V. Elsukov 	NGI_GET_M(item, m);
562*426b3d04SJulian Elischer 
563*426b3d04SJulian Elischer #define	PULLUP_CHECK(mbuf, length) do {					\
564*426b3d04SJulian Elischer 	pullup_len += length;						\
565*426b3d04SJulian Elischer 	if (((mbuf)->m_pkthdr.len < pullup_len) ||			\
566*426b3d04SJulian Elischer 	    (pullup_len > MHLEN)) {					\
567*426b3d04SJulian Elischer 		error = EINVAL;						\
568*426b3d04SJulian Elischer 		goto bypass;						\
569*426b3d04SJulian Elischer 	}								\
570*426b3d04SJulian Elischer 	if ((mbuf)->m_len < pullup_len &&				\
571*426b3d04SJulian Elischer 	    (((mbuf) = m_pullup((mbuf), pullup_len)) == NULL)) {	\
572*426b3d04SJulian Elischer 		error = ENOBUFS;					\
573*426b3d04SJulian Elischer 		goto drop;						\
574*426b3d04SJulian Elischer 	}								\
575*426b3d04SJulian Elischer } while (0)
576*426b3d04SJulian Elischer 
577*426b3d04SJulian Elischer 	if (priv->conf && hook == priv->in &&
578*426b3d04SJulian Elischer 	    m && (m->m_flags & M_PKTHDR)) {
579*426b3d04SJulian Elischer 
580d359a62dSAndrey V. Elsukov 		m = m_unshare(m, M_NOWAIT);
581*426b3d04SJulian Elischer 
582*426b3d04SJulian Elischer 		if (m == NULL)
583*426b3d04SJulian Elischer 			ERROUT(ENOMEM);
584*426b3d04SJulian Elischer 
585*426b3d04SJulian Elischer 		if (priv->conf->relative_offset) {
586*426b3d04SJulian Elischer 			struct ether_header *eh;
587*426b3d04SJulian Elischer 			struct ng_patch_vlan_header *vh;
588*426b3d04SJulian Elischer 			uint16_t etype;
589*426b3d04SJulian Elischer 
590*426b3d04SJulian Elischer 			switch (priv->dlt)
591*426b3d04SJulian Elischer 			{
592*426b3d04SJulian Elischer 				case DLT_EN10MB:
593*426b3d04SJulian Elischer 					PULLUP_CHECK(m, sizeof(struct ether_header));
594*426b3d04SJulian Elischer 					eh = mtod(m, struct ether_header *);
595*426b3d04SJulian Elischer 					etype = ntohs(eh->ether_type);
596*426b3d04SJulian Elischer 
597*426b3d04SJulian Elischer 					for (;;) {	/* QinQ support */
598*426b3d04SJulian Elischer 						switch (etype)
599*426b3d04SJulian Elischer 						{
600*426b3d04SJulian Elischer 							case 0x8100:
601*426b3d04SJulian Elischer 							case 0x88A8:
602*426b3d04SJulian Elischer 							case 0x9100:
603*426b3d04SJulian Elischer 								PULLUP_CHECK(m, sizeof(struct ng_patch_vlan_header));
604*426b3d04SJulian Elischer 								vh = (struct ng_patch_vlan_header *) mtodo(m,
605*426b3d04SJulian Elischer 								    pullup_len - sizeof(struct ng_patch_vlan_header));
606*426b3d04SJulian Elischer 								etype = ntohs(vh->etype);
607*426b3d04SJulian Elischer 								break;
608*426b3d04SJulian Elischer 
609*426b3d04SJulian Elischer 							default:
610*426b3d04SJulian Elischer 								goto loopend;
611d359a62dSAndrey V. Elsukov 						}
612*426b3d04SJulian Elischer 					}
613*426b3d04SJulian Elischer loopend:
614*426b3d04SJulian Elischer 					break;
615*426b3d04SJulian Elischer 
616*426b3d04SJulian Elischer 				case DLT_RAW:
617*426b3d04SJulian Elischer 					break;
618*426b3d04SJulian Elischer 
619*426b3d04SJulian Elischer 				default:
620*426b3d04SJulian Elischer 					ERROUT(EINVAL);
621*426b3d04SJulian Elischer 			}
622d359a62dSAndrey V. Elsukov 		}
623d359a62dSAndrey V. Elsukov 
624*426b3d04SJulian Elischer 		do_patch(priv, m, pullup_len);
625*426b3d04SJulian Elischer 
626*426b3d04SJulian Elischer 		m->m_pkthdr.csum_flags |= priv->conf->csum_flags;
627*426b3d04SJulian Elischer 	}
628*426b3d04SJulian Elischer 
629*426b3d04SJulian Elischer #undef	PULLUP_CHECK
630*426b3d04SJulian Elischer 
631*426b3d04SJulian Elischer bypass:
632*426b3d04SJulian Elischer 	out = NULL;
633*426b3d04SJulian Elischer 
634d359a62dSAndrey V. Elsukov 	if (hook == priv->in) {
635d359a62dSAndrey V. Elsukov 		/* return frames on 'in' hook if 'out' not connected */
636*426b3d04SJulian Elischer 		out = priv->out ? priv->out : priv->in;
637*426b3d04SJulian Elischer 	} else if (hook == priv->out && priv->in) {
638*426b3d04SJulian Elischer 		/* pass frames on 'out' hook if 'in' connected */
639*426b3d04SJulian Elischer 		out = priv->in;
640d359a62dSAndrey V. Elsukov 	}
641d359a62dSAndrey V. Elsukov 
642*426b3d04SJulian Elischer 	if (out == NULL)
643*426b3d04SJulian Elischer 		ERROUT(0);
644*426b3d04SJulian Elischer 
645*426b3d04SJulian Elischer 	NG_FWD_NEW_DATA(error, item, out, m);
646*426b3d04SJulian Elischer 
647*426b3d04SJulian Elischer 	return (error);
648*426b3d04SJulian Elischer 
649*426b3d04SJulian Elischer done:
650*426b3d04SJulian Elischer drop:
651d359a62dSAndrey V. Elsukov 	NG_FREE_ITEM(item);
652d359a62dSAndrey V. Elsukov 	NG_FREE_M(m);
653*426b3d04SJulian Elischer 
654*426b3d04SJulian Elischer 	priv->stats.dropped++;
655*426b3d04SJulian Elischer 
656d359a62dSAndrey V. Elsukov 	return (error);
657d359a62dSAndrey V. Elsukov }
658d359a62dSAndrey V. Elsukov 
659d359a62dSAndrey V. Elsukov static int
660d359a62dSAndrey V. Elsukov ng_patch_shutdown(node_p node)
661d359a62dSAndrey V. Elsukov {
662d359a62dSAndrey V. Elsukov 	const priv_p privdata = NG_NODE_PRIVATE(node);
663d359a62dSAndrey V. Elsukov 
664d359a62dSAndrey V. Elsukov 	NG_NODE_SET_PRIVATE(node, NULL);
665d359a62dSAndrey V. Elsukov 	NG_NODE_UNREF(node);
666*426b3d04SJulian Elischer 
667*426b3d04SJulian Elischer 	if (privdata->conf != NULL)
668*426b3d04SJulian Elischer 		free(privdata->conf, M_NETGRAPH);
669*426b3d04SJulian Elischer 
670d359a62dSAndrey V. Elsukov 	free(privdata, M_NETGRAPH);
671*426b3d04SJulian Elischer 
672d359a62dSAndrey V. Elsukov 	return (0);
673d359a62dSAndrey V. Elsukov }
674d359a62dSAndrey V. Elsukov 
675d359a62dSAndrey V. Elsukov static int
676d359a62dSAndrey V. Elsukov ng_patch_disconnect(hook_p hook)
677d359a62dSAndrey V. Elsukov {
6786c0a2eb1SAndrey V. Elsukov 	priv_p priv;
679d359a62dSAndrey V. Elsukov 
6806c0a2eb1SAndrey V. Elsukov 	priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
681*426b3d04SJulian Elischer 
682d359a62dSAndrey V. Elsukov 	if (hook == priv->in) {
683d359a62dSAndrey V. Elsukov 		priv->in = NULL;
684d359a62dSAndrey V. Elsukov 	}
685*426b3d04SJulian Elischer 
686d359a62dSAndrey V. Elsukov 	if (hook == priv->out) {
687d359a62dSAndrey V. Elsukov 		priv->out = NULL;
688d359a62dSAndrey V. Elsukov 	}
689*426b3d04SJulian Elischer 
6906c0a2eb1SAndrey V. Elsukov 	if (NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0 &&
6916c0a2eb1SAndrey V. Elsukov 	    NG_NODE_IS_VALID(NG_HOOK_NODE(hook))) /* already shutting down? */
692d359a62dSAndrey V. Elsukov 		ng_rmnode_self(NG_HOOK_NODE(hook));
693*426b3d04SJulian Elischer 
694d359a62dSAndrey V. Elsukov 	return (0);
695d359a62dSAndrey V. Elsukov }
696