xref: /freebsd/sys/netgraph/ng_patch.c (revision 4d846d260e2b9a3d4d0a701462568268cbfe7a5b)
1d359a62dSAndrey V. Elsukov /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3fe267a55SPedro F. Giffuni  *
4bf909fc9SJulian Elischer  * Copyright (c) 2010 Maxim Ignatenko <gelraen.ua@gmail.com>
5426b3d04SJulian Elischer  * Copyright (c) 2015 Dmitry Vagin <daemon.hammer@ya.ru>
6d359a62dSAndrey V. Elsukov  * All rights reserved.
7d359a62dSAndrey V. Elsukov  *
8d359a62dSAndrey V. Elsukov  * Redistribution and use in source and binary forms, with or without
9d359a62dSAndrey V. Elsukov  * modification, are permitted provided that the following conditions
10d359a62dSAndrey V. Elsukov  * are met:
11d359a62dSAndrey V. Elsukov  * 1. Redistributions of source code must retain the above copyright
12d359a62dSAndrey V. Elsukov  *    notice, this list of conditions and the following disclaimer.
13d359a62dSAndrey V. Elsukov  * 2. Redistributions in binary form must reproduce the above copyright
14d359a62dSAndrey V. Elsukov  *    notice, this list of conditions and the following disclaimer in the
15d359a62dSAndrey V. Elsukov  *    documentation and/or other materials provided with the distribution.
16d359a62dSAndrey V. Elsukov  *
17d359a62dSAndrey V. Elsukov  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18d359a62dSAndrey V. Elsukov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19d359a62dSAndrey V. Elsukov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20d359a62dSAndrey V. Elsukov  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21d359a62dSAndrey V. Elsukov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22d359a62dSAndrey V. Elsukov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23d359a62dSAndrey V. Elsukov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24d359a62dSAndrey V. Elsukov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25d359a62dSAndrey V. Elsukov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26d359a62dSAndrey V. Elsukov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27d359a62dSAndrey V. Elsukov  * SUCH DAMAGE.
28d359a62dSAndrey V. Elsukov  *
29d359a62dSAndrey V. Elsukov  */
30d359a62dSAndrey V. Elsukov 
31d359a62dSAndrey V. Elsukov #include <sys/cdefs.h>
32d359a62dSAndrey V. Elsukov __FBSDID("$FreeBSD$");
33d359a62dSAndrey V. Elsukov 
34d359a62dSAndrey V. Elsukov #include <sys/param.h>
35cac2fe69SAndrey V. Elsukov #include <sys/systm.h>
36d359a62dSAndrey V. Elsukov #include <sys/kernel.h>
37cac2fe69SAndrey V. Elsukov #include <sys/endian.h>
386c0a2eb1SAndrey V. Elsukov #include <sys/malloc.h>
396c0a2eb1SAndrey V. Elsukov #include <sys/mbuf.h>
40426b3d04SJulian Elischer 
41426b3d04SJulian Elischer #include <net/bpf.h>
42426b3d04SJulian Elischer #include <net/ethernet.h>
43426b3d04SJulian Elischer 
44d359a62dSAndrey V. Elsukov #include <netgraph/ng_message.h>
45d359a62dSAndrey V. Elsukov #include <netgraph/ng_parse.h>
46d359a62dSAndrey V. Elsukov #include <netgraph/netgraph.h>
47d359a62dSAndrey V. Elsukov 
48426b3d04SJulian Elischer #include <netgraph/ng_patch.h>
49426b3d04SJulian Elischer 
50426b3d04SJulian Elischer /* private data */
51426b3d04SJulian Elischer struct ng_patch_priv {
52426b3d04SJulian Elischer 	hook_p		in;
53426b3d04SJulian Elischer 	hook_p		out;
54426b3d04SJulian Elischer 	uint8_t		dlt;	/* DLT_XXX from bpf.h */
55426b3d04SJulian Elischer 	struct ng_patch_stats stats;
56426b3d04SJulian Elischer 	struct ng_patch_config *conf;
57426b3d04SJulian Elischer };
58426b3d04SJulian Elischer 
59426b3d04SJulian Elischer typedef struct ng_patch_priv *priv_p;
60426b3d04SJulian Elischer 
61426b3d04SJulian Elischer /* Netgraph methods */
62d359a62dSAndrey V. Elsukov static ng_constructor_t	ng_patch_constructor;
63d359a62dSAndrey V. Elsukov static ng_rcvmsg_t	ng_patch_rcvmsg;
64d359a62dSAndrey V. Elsukov static ng_shutdown_t	ng_patch_shutdown;
65d359a62dSAndrey V. Elsukov static ng_newhook_t	ng_patch_newhook;
66d359a62dSAndrey V. Elsukov static ng_rcvdata_t	ng_patch_rcvdata;
67d359a62dSAndrey V. Elsukov static ng_disconnect_t	ng_patch_disconnect;
68426b3d04SJulian Elischer #define ERROUT(x) { error = (x); goto done; }
69426b3d04SJulian Elischer 
70d359a62dSAndrey V. Elsukov static int
716c0a2eb1SAndrey V. Elsukov ng_patch_config_getlen(const struct ng_parse_type *type,
726c0a2eb1SAndrey V. Elsukov     const u_char *start, const u_char *buf)
73d359a62dSAndrey V. Elsukov {
74bf909fc9SJulian Elischer 	const struct ng_patch_config *conf;
75d359a62dSAndrey V. Elsukov 
76bf909fc9SJulian Elischer 	conf = (const struct ng_patch_config *)(buf -
77cac2fe69SAndrey V. Elsukov 	    offsetof(struct ng_patch_config, ops));
78bf909fc9SJulian Elischer 
79bf909fc9SJulian Elischer 	return (conf->count);
80d359a62dSAndrey V. Elsukov }
81d359a62dSAndrey V. Elsukov 
82d359a62dSAndrey V. Elsukov static const struct ng_parse_struct_field ng_patch_op_type_fields[]
83426b3d04SJulian Elischer 	= NG_PATCH_OP_TYPE;
84d359a62dSAndrey V. Elsukov static const struct ng_parse_type ng_patch_op_type = {
85d359a62dSAndrey V. Elsukov 	&ng_parse_struct_type,
86d359a62dSAndrey V. Elsukov 	&ng_patch_op_type_fields
87d359a62dSAndrey V. Elsukov };
88d359a62dSAndrey V. Elsukov 
89bf909fc9SJulian Elischer static const struct ng_parse_array_info ng_patch_ops_array_info = {
90d359a62dSAndrey V. Elsukov 	&ng_patch_op_type,
91d359a62dSAndrey V. Elsukov 	&ng_patch_config_getlen
92d359a62dSAndrey V. Elsukov };
93bf909fc9SJulian Elischer static const struct ng_parse_type ng_patch_ops_array_type = {
94d359a62dSAndrey V. Elsukov 	&ng_parse_array_type,
95bf909fc9SJulian Elischer 	&ng_patch_ops_array_info
96d359a62dSAndrey V. Elsukov };
97d359a62dSAndrey V. Elsukov 
98d359a62dSAndrey V. Elsukov static const struct ng_parse_struct_field ng_patch_config_type_fields[]
99426b3d04SJulian Elischer 	= NG_PATCH_CONFIG_TYPE;
100d359a62dSAndrey V. Elsukov static const struct ng_parse_type ng_patch_config_type = {
101d359a62dSAndrey V. Elsukov 	&ng_parse_struct_type,
102d359a62dSAndrey V. Elsukov 	&ng_patch_config_type_fields
103d359a62dSAndrey V. Elsukov };
104d359a62dSAndrey V. Elsukov 
105d359a62dSAndrey V. Elsukov static const struct ng_parse_struct_field ng_patch_stats_fields[]
106426b3d04SJulian Elischer 	= NG_PATCH_STATS_TYPE;
107d359a62dSAndrey V. Elsukov static const struct ng_parse_type ng_patch_stats_type = {
108d359a62dSAndrey V. Elsukov 	&ng_parse_struct_type,
109d359a62dSAndrey V. Elsukov 	&ng_patch_stats_fields
110d359a62dSAndrey V. Elsukov };
111d359a62dSAndrey V. Elsukov 
112d359a62dSAndrey V. Elsukov static const struct ng_cmdlist ng_patch_cmdlist[] = {
113d359a62dSAndrey V. Elsukov 	{
114d359a62dSAndrey V. Elsukov 		NGM_PATCH_COOKIE,
115426b3d04SJulian Elischer 		NGM_PATCH_GETDLT,
116426b3d04SJulian Elischer 		"getdlt",
117426b3d04SJulian Elischer 		NULL,
118426b3d04SJulian Elischer 		&ng_parse_uint8_type
119426b3d04SJulian Elischer 	},
120426b3d04SJulian Elischer 	{
121426b3d04SJulian Elischer 		NGM_PATCH_COOKIE,
122426b3d04SJulian Elischer 		NGM_PATCH_SETDLT,
123426b3d04SJulian Elischer 		"setdlt",
124426b3d04SJulian Elischer 		&ng_parse_uint8_type,
125426b3d04SJulian Elischer 		NULL
126426b3d04SJulian Elischer 	},
127426b3d04SJulian Elischer 	{
128426b3d04SJulian Elischer 		NGM_PATCH_COOKIE,
129d359a62dSAndrey V. Elsukov 		NGM_PATCH_GETCONFIG,
130d359a62dSAndrey V. Elsukov 		"getconfig",
131d359a62dSAndrey V. Elsukov 		NULL,
132d359a62dSAndrey V. Elsukov 		&ng_patch_config_type
133d359a62dSAndrey V. Elsukov 	},
134d359a62dSAndrey V. Elsukov 	{
135d359a62dSAndrey V. Elsukov 		NGM_PATCH_COOKIE,
136d359a62dSAndrey V. Elsukov 		NGM_PATCH_SETCONFIG,
137d359a62dSAndrey V. Elsukov 		"setconfig",
138d359a62dSAndrey V. Elsukov 		&ng_patch_config_type,
139d359a62dSAndrey V. Elsukov 		NULL
140d359a62dSAndrey V. Elsukov 	},
141d359a62dSAndrey V. Elsukov 	{
142d359a62dSAndrey V. Elsukov 		NGM_PATCH_COOKIE,
143d359a62dSAndrey V. Elsukov 		NGM_PATCH_GET_STATS,
144d359a62dSAndrey V. Elsukov 		"getstats",
145d359a62dSAndrey V. Elsukov 		NULL,
146d359a62dSAndrey V. Elsukov 		&ng_patch_stats_type
147d359a62dSAndrey V. Elsukov 	},
148d359a62dSAndrey V. Elsukov 	{
149d359a62dSAndrey V. Elsukov 		NGM_PATCH_COOKIE,
150d359a62dSAndrey V. Elsukov 		NGM_PATCH_CLR_STATS,
151d359a62dSAndrey V. Elsukov 		"clrstats",
152d359a62dSAndrey V. Elsukov 		NULL,
153d359a62dSAndrey V. Elsukov 		NULL
154d359a62dSAndrey V. Elsukov 	},
155d359a62dSAndrey V. Elsukov 	{
156d359a62dSAndrey V. Elsukov 		NGM_PATCH_COOKIE,
157d359a62dSAndrey V. Elsukov 		NGM_PATCH_GETCLR_STATS,
158d359a62dSAndrey V. Elsukov 		"getclrstats",
159d359a62dSAndrey V. Elsukov 		NULL,
160d359a62dSAndrey V. Elsukov 		&ng_patch_stats_type
161d359a62dSAndrey V. Elsukov 	},
162d359a62dSAndrey V. Elsukov 	{ 0 }
163d359a62dSAndrey V. Elsukov };
164d359a62dSAndrey V. Elsukov 
165d359a62dSAndrey V. Elsukov static struct ng_type typestruct = {
166d359a62dSAndrey V. Elsukov 	.version =	NG_ABI_VERSION,
167d359a62dSAndrey V. Elsukov 	.name =		NG_PATCH_NODE_TYPE,
168d359a62dSAndrey V. Elsukov 	.constructor =	ng_patch_constructor,
169d359a62dSAndrey V. Elsukov 	.rcvmsg =	ng_patch_rcvmsg,
170d359a62dSAndrey V. Elsukov 	.shutdown =	ng_patch_shutdown,
171d359a62dSAndrey V. Elsukov 	.newhook =	ng_patch_newhook,
172d359a62dSAndrey V. Elsukov 	.rcvdata =	ng_patch_rcvdata,
173d359a62dSAndrey V. Elsukov 	.disconnect =	ng_patch_disconnect,
174d359a62dSAndrey V. Elsukov 	.cmdlist =	ng_patch_cmdlist,
175d359a62dSAndrey V. Elsukov };
176bf909fc9SJulian Elischer 
177d359a62dSAndrey V. Elsukov NETGRAPH_INIT(patch, &typestruct);
178d359a62dSAndrey V. Elsukov 
179d359a62dSAndrey V. Elsukov static int
180d359a62dSAndrey V. Elsukov ng_patch_constructor(node_p node)
181d359a62dSAndrey V. Elsukov {
182d359a62dSAndrey V. Elsukov 	priv_p privdata;
183d359a62dSAndrey V. Elsukov 
184ffbfc0aaSAndrey V. Elsukov 	privdata = malloc(sizeof(*privdata), M_NETGRAPH, M_WAITOK | M_ZERO);
185426b3d04SJulian Elischer 	privdata->dlt = DLT_RAW;
186426b3d04SJulian Elischer 
187d359a62dSAndrey V. Elsukov 	NG_NODE_SET_PRIVATE(node, privdata);
188426b3d04SJulian Elischer 
189d359a62dSAndrey V. Elsukov 	return (0);
190d359a62dSAndrey V. Elsukov }
191d359a62dSAndrey V. Elsukov 
192d359a62dSAndrey V. Elsukov static int
193d359a62dSAndrey V. Elsukov ng_patch_newhook(node_p node, hook_p hook, const char *name)
194d359a62dSAndrey V. Elsukov {
195d359a62dSAndrey V. Elsukov 	const priv_p privp = NG_NODE_PRIVATE(node);
196d359a62dSAndrey V. Elsukov 
197d359a62dSAndrey V. Elsukov 	if (strncmp(name, NG_PATCH_HOOK_IN, strlen(NG_PATCH_HOOK_IN)) == 0) {
198d359a62dSAndrey V. Elsukov 		privp->in = hook;
199d359a62dSAndrey V. Elsukov 	} else if (strncmp(name, NG_PATCH_HOOK_OUT,
200d359a62dSAndrey V. Elsukov 	    strlen(NG_PATCH_HOOK_OUT)) == 0) {
201d359a62dSAndrey V. Elsukov 		privp->out = hook;
202d359a62dSAndrey V. Elsukov 	} else
203d359a62dSAndrey V. Elsukov 		return (EINVAL);
204426b3d04SJulian Elischer 
205d359a62dSAndrey V. Elsukov 	return (0);
206d359a62dSAndrey V. Elsukov }
207d359a62dSAndrey V. Elsukov 
208d359a62dSAndrey V. Elsukov static int
209d359a62dSAndrey V. Elsukov ng_patch_rcvmsg(node_p node, item_p item, hook_p lasthook)
210d359a62dSAndrey V. Elsukov {
211d359a62dSAndrey V. Elsukov 	const priv_p privp = NG_NODE_PRIVATE(node);
2126c0a2eb1SAndrey V. Elsukov 	struct ng_patch_config *conf, *newconf;
213d359a62dSAndrey V. Elsukov 	struct ng_mesg *msg;
214426b3d04SJulian Elischer 	struct ng_mesg *resp = NULL;
215426b3d04SJulian Elischer 	int i, error = 0;
216d359a62dSAndrey V. Elsukov 
217d359a62dSAndrey V. Elsukov 	NGI_GET_MSG(item, msg);
218426b3d04SJulian Elischer 
219426b3d04SJulian Elischer 	if  (msg->header.typecookie != NGM_PATCH_COOKIE)
220426b3d04SJulian Elischer 		ERROUT(EINVAL);
221426b3d04SJulian Elischer 
222426b3d04SJulian Elischer 	switch (msg->header.cmd)
223d359a62dSAndrey V. Elsukov 	{
224426b3d04SJulian Elischer 		case NGM_PATCH_GETCONFIG:
225426b3d04SJulian Elischer 			if (privp->conf == NULL)
226426b3d04SJulian Elischer 				ERROUT(0);
227426b3d04SJulian Elischer 
228426b3d04SJulian Elischer 			NG_MKRESPONSE(resp, msg,
229426b3d04SJulian Elischer 			    NG_PATCH_CONF_SIZE(privp->conf->count), M_WAITOK);
230426b3d04SJulian Elischer 
231426b3d04SJulian Elischer 			if (resp == NULL)
232426b3d04SJulian Elischer 				ERROUT(ENOMEM);
233426b3d04SJulian Elischer 
234426b3d04SJulian Elischer 			bcopy(privp->conf, resp->data,
235426b3d04SJulian Elischer 			    NG_PATCH_CONF_SIZE(privp->conf->count));
236426b3d04SJulian Elischer 
237426b3d04SJulian Elischer 			conf = (struct ng_patch_config *) resp->data;
238426b3d04SJulian Elischer 
239426b3d04SJulian Elischer 			for (i = 0; i < conf->count; i++) {
240426b3d04SJulian Elischer 				switch (conf->ops[i].length)
241426b3d04SJulian Elischer 				{
242426b3d04SJulian Elischer 					case 1:
243426b3d04SJulian Elischer 						conf->ops[i].val.v8 = conf->ops[i].val.v1;
244426b3d04SJulian Elischer 						break;
245426b3d04SJulian Elischer 					case 2:
246426b3d04SJulian Elischer 						conf->ops[i].val.v8 = conf->ops[i].val.v2;
247426b3d04SJulian Elischer 						break;
248426b3d04SJulian Elischer 					case 4:
249426b3d04SJulian Elischer 						conf->ops[i].val.v8 = conf->ops[i].val.v4;
250426b3d04SJulian Elischer 						break;
251426b3d04SJulian Elischer 					case 8:
252d359a62dSAndrey V. Elsukov 						break;
253d359a62dSAndrey V. Elsukov 				}
254426b3d04SJulian Elischer 			}
255d359a62dSAndrey V. Elsukov 
256426b3d04SJulian Elischer 			break;
257426b3d04SJulian Elischer 
258426b3d04SJulian Elischer 		case NGM_PATCH_SETCONFIG:
259d359a62dSAndrey V. Elsukov 			conf = (struct ng_patch_config *) msg->data;
260426b3d04SJulian Elischer 
261426b3d04SJulian Elischer 			if (msg->header.arglen < sizeof(struct ng_patch_config) ||
262426b3d04SJulian Elischer 			    msg->header.arglen < NG_PATCH_CONF_SIZE(conf->count))
263426b3d04SJulian Elischer 				ERROUT(EINVAL);
264d359a62dSAndrey V. Elsukov 
265d359a62dSAndrey V. Elsukov 			for (i = 0; i < conf->count; i++) {
266426b3d04SJulian Elischer 				switch (conf->ops[i].length)
267426b3d04SJulian Elischer 				{
268d359a62dSAndrey V. Elsukov 					case 1:
269426b3d04SJulian Elischer 						conf->ops[i].val.v1 = (uint8_t) conf->ops[i].val.v8;
270426b3d04SJulian Elischer 						break;
271d359a62dSAndrey V. Elsukov 					case 2:
272426b3d04SJulian Elischer 						conf->ops[i].val.v2 = (uint16_t) conf->ops[i].val.v8;
273426b3d04SJulian Elischer 						break;
274d359a62dSAndrey V. Elsukov 					case 4:
275426b3d04SJulian Elischer 						conf->ops[i].val.v4 = (uint32_t) conf->ops[i].val.v8;
276426b3d04SJulian Elischer 						break;
277d359a62dSAndrey V. Elsukov 					case 8:
278d359a62dSAndrey V. Elsukov 						break;
279d359a62dSAndrey V. Elsukov 					default:
280426b3d04SJulian Elischer 						ERROUT(EINVAL);
281d359a62dSAndrey V. Elsukov 				}
282d359a62dSAndrey V. Elsukov 			}
283d359a62dSAndrey V. Elsukov 
284426b3d04SJulian Elischer 			conf->csum_flags &= NG_PATCH_CSUM_IPV4|NG_PATCH_CSUM_IPV6;
285426b3d04SJulian Elischer 			conf->relative_offset = !!conf->relative_offset;
286d359a62dSAndrey V. Elsukov 
287426b3d04SJulian Elischer 			newconf = malloc(NG_PATCH_CONF_SIZE(conf->count), M_NETGRAPH, M_WAITOK | M_ZERO);
288426b3d04SJulian Elischer 
289426b3d04SJulian Elischer 			bcopy(conf, newconf, NG_PATCH_CONF_SIZE(conf->count));
290426b3d04SJulian Elischer 
291426b3d04SJulian Elischer 			if (privp->conf)
292426b3d04SJulian Elischer 				free(privp->conf, M_NETGRAPH);
293426b3d04SJulian Elischer 
294426b3d04SJulian Elischer 			privp->conf = newconf;
295426b3d04SJulian Elischer 
296d359a62dSAndrey V. Elsukov 			break;
297426b3d04SJulian Elischer 
298d359a62dSAndrey V. Elsukov 		case NGM_PATCH_GET_STATS:
299d359a62dSAndrey V. Elsukov 		case NGM_PATCH_CLR_STATS:
300426b3d04SJulian Elischer 		case NGM_PATCH_GETCLR_STATS:
301426b3d04SJulian Elischer 			if (msg->header.cmd != NGM_PATCH_CLR_STATS) {
302426b3d04SJulian Elischer 				NG_MKRESPONSE(resp, msg, sizeof(struct ng_patch_stats), M_WAITOK);
303426b3d04SJulian Elischer 
304426b3d04SJulian Elischer 				if (resp == NULL)
305426b3d04SJulian Elischer 					ERROUT(ENOMEM);
306426b3d04SJulian Elischer 
307426b3d04SJulian Elischer 				bcopy(&(privp->stats), resp->data, sizeof(struct ng_patch_stats));
308d359a62dSAndrey V. Elsukov 			}
309d359a62dSAndrey V. Elsukov 
310426b3d04SJulian Elischer 			if (msg->header.cmd != NGM_PATCH_GET_STATS)
311426b3d04SJulian Elischer 				bzero(&(privp->stats), sizeof(struct ng_patch_stats));
312426b3d04SJulian Elischer 
313426b3d04SJulian Elischer 			break;
314426b3d04SJulian Elischer 
315426b3d04SJulian Elischer 		case NGM_PATCH_GETDLT:
316426b3d04SJulian Elischer 			NG_MKRESPONSE(resp, msg, sizeof(uint8_t), M_WAITOK);
317426b3d04SJulian Elischer 
318426b3d04SJulian Elischer 			if (resp == NULL)
319426b3d04SJulian Elischer 				ERROUT(ENOMEM);
320426b3d04SJulian Elischer 
321426b3d04SJulian Elischer 			*((uint8_t *) resp->data) = privp->dlt;
322426b3d04SJulian Elischer 
323426b3d04SJulian Elischer 			break;
324426b3d04SJulian Elischer 
325426b3d04SJulian Elischer 		case NGM_PATCH_SETDLT:
326426b3d04SJulian Elischer 			if (msg->header.arglen != sizeof(uint8_t))
327426b3d04SJulian Elischer 				ERROUT(EINVAL);
328426b3d04SJulian Elischer 
329426b3d04SJulian Elischer 			switch (*(uint8_t *) msg->data)
330426b3d04SJulian Elischer 			{
331426b3d04SJulian Elischer 				case DLT_EN10MB:
332426b3d04SJulian Elischer 				case DLT_RAW:
333426b3d04SJulian Elischer 					privp->dlt = *(uint8_t *) msg->data;
334426b3d04SJulian Elischer 					break;
335426b3d04SJulian Elischer 
336426b3d04SJulian Elischer 				default:
337426b3d04SJulian Elischer 					ERROUT(EINVAL);
338426b3d04SJulian Elischer 			}
339426b3d04SJulian Elischer 
340426b3d04SJulian Elischer 			break;
341426b3d04SJulian Elischer 
342426b3d04SJulian Elischer 		default:
343426b3d04SJulian Elischer 			ERROUT(EINVAL);
344426b3d04SJulian Elischer 	}
345426b3d04SJulian Elischer 
346426b3d04SJulian Elischer done:
347d359a62dSAndrey V. Elsukov 	NG_RESPOND_MSG(error, node, item, resp);
348d359a62dSAndrey V. Elsukov 	NG_FREE_MSG(msg);
349426b3d04SJulian Elischer 
350d359a62dSAndrey V. Elsukov 	return (error);
351d359a62dSAndrey V. Elsukov }
352d359a62dSAndrey V. Elsukov 
353d359a62dSAndrey V. Elsukov static void
354426b3d04SJulian Elischer do_patch(priv_p privp, struct mbuf *m, int global_offset)
355d359a62dSAndrey V. Elsukov {
356426b3d04SJulian Elischer 	int i, offset, patched = 0;
357426b3d04SJulian Elischer 	union ng_patch_op_val val;
358d359a62dSAndrey V. Elsukov 
359426b3d04SJulian Elischer 	for (i = 0; i < privp->conf->count; i++) {
360426b3d04SJulian Elischer 		offset = global_offset + privp->conf->ops[i].offset;
361426b3d04SJulian Elischer 
362426b3d04SJulian Elischer 		if (offset + privp->conf->ops[i].length > m->m_pkthdr.len)
363d359a62dSAndrey V. Elsukov 			continue;
364d359a62dSAndrey V. Elsukov 
365d359a62dSAndrey V. Elsukov 		/* for "=" operation we don't need to copy data from mbuf */
366426b3d04SJulian Elischer 		if (privp->conf->ops[i].mode != NG_PATCH_MODE_SET)
367426b3d04SJulian Elischer 			m_copydata(m, offset, privp->conf->ops[i].length, (caddr_t) &val);
368d359a62dSAndrey V. Elsukov 
369426b3d04SJulian Elischer 		switch (privp->conf->ops[i].length)
370426b3d04SJulian Elischer 		{
371d359a62dSAndrey V. Elsukov 			case 1:
372426b3d04SJulian Elischer 				switch (privp->conf->ops[i].mode)
373426b3d04SJulian Elischer 				{
374d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_SET:
375426b3d04SJulian Elischer 						val.v1 = privp->conf->ops[i].val.v1;
376d359a62dSAndrey V. Elsukov 						break;
377d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_ADD:
378426b3d04SJulian Elischer 						val.v1 += privp->conf->ops[i].val.v1;
379d359a62dSAndrey V. Elsukov 						break;
380d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_SUB:
381426b3d04SJulian Elischer 						val.v1 -= privp->conf->ops[i].val.v1;
382d359a62dSAndrey V. Elsukov 						break;
383d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_MUL:
384426b3d04SJulian Elischer 						val.v1 *= privp->conf->ops[i].val.v1;
385d359a62dSAndrey V. Elsukov 						break;
386d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_DIV:
387426b3d04SJulian Elischer 						val.v1 /= privp->conf->ops[i].val.v1;
388d359a62dSAndrey V. Elsukov 						break;
389d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_NEG:
390426b3d04SJulian Elischer 						*((int8_t *) &val) = - *((int8_t *) &val);
391d359a62dSAndrey V. Elsukov 						break;
392d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_AND:
393426b3d04SJulian Elischer 						val.v1 &= privp->conf->ops[i].val.v1;
394d359a62dSAndrey V. Elsukov 						break;
395d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_OR:
396426b3d04SJulian Elischer 						val.v1 |= privp->conf->ops[i].val.v1;
397d359a62dSAndrey V. Elsukov 						break;
398d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_XOR:
399426b3d04SJulian Elischer 						val.v1 ^= privp->conf->ops[i].val.v1;
400d359a62dSAndrey V. Elsukov 						break;
401d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_SHL:
402426b3d04SJulian Elischer 						val.v1 <<= privp->conf->ops[i].val.v1;
403d359a62dSAndrey V. Elsukov 						break;
404d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_SHR:
405426b3d04SJulian Elischer 						val.v1 >>= privp->conf->ops[i].val.v1;
406d359a62dSAndrey V. Elsukov 						break;
407d359a62dSAndrey V. Elsukov 				}
408d359a62dSAndrey V. Elsukov 				break;
409426b3d04SJulian Elischer 
410d359a62dSAndrey V. Elsukov 			case 2:
411426b3d04SJulian Elischer 				val.v2 = ntohs(val.v2);
412426b3d04SJulian Elischer 
413426b3d04SJulian Elischer 				switch (privp->conf->ops[i].mode)
414426b3d04SJulian Elischer 				{
415d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_SET:
416426b3d04SJulian Elischer 						val.v2 = privp->conf->ops[i].val.v2;
417d359a62dSAndrey V. Elsukov 						break;
418d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_ADD:
419426b3d04SJulian Elischer 						val.v2 += privp->conf->ops[i].val.v2;
420d359a62dSAndrey V. Elsukov 						break;
421d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_SUB:
422426b3d04SJulian Elischer 						val.v2 -= privp->conf->ops[i].val.v2;
423d359a62dSAndrey V. Elsukov 						break;
424d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_MUL:
425426b3d04SJulian Elischer 						val.v2 *= privp->conf->ops[i].val.v2;
426d359a62dSAndrey V. Elsukov 						break;
427d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_DIV:
428426b3d04SJulian Elischer 						val.v2 /= privp->conf->ops[i].val.v2;
429d359a62dSAndrey V. Elsukov 						break;
430d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_NEG:
431426b3d04SJulian Elischer 						*((int16_t *) &val) = - *((int16_t *) &val);
432d359a62dSAndrey V. Elsukov 						break;
433d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_AND:
434426b3d04SJulian Elischer 						val.v2 &= privp->conf->ops[i].val.v2;
435d359a62dSAndrey V. Elsukov 						break;
436d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_OR:
437426b3d04SJulian Elischer 						val.v2 |= privp->conf->ops[i].val.v2;
438d359a62dSAndrey V. Elsukov 						break;
439d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_XOR:
440426b3d04SJulian Elischer 						val.v2 ^= privp->conf->ops[i].val.v2;
441d359a62dSAndrey V. Elsukov 						break;
442d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_SHL:
443426b3d04SJulian Elischer 						val.v2 <<= privp->conf->ops[i].val.v2;
444d359a62dSAndrey V. Elsukov 						break;
445d359a62dSAndrey V. Elsukov 					case NG_PATCH_MODE_SHR:
446426b3d04SJulian Elischer 						val.v2 >>= privp->conf->ops[i].val.v2;
447d359a62dSAndrey V. Elsukov 						break;
448d359a62dSAndrey V. Elsukov 				}
449d359a62dSAndrey V. Elsukov 
450426b3d04SJulian Elischer 				val.v2 = htons(val.v2);
451426b3d04SJulian Elischer 
452426b3d04SJulian Elischer 				break;
453426b3d04SJulian Elischer 
454426b3d04SJulian Elischer 			case 4:
455426b3d04SJulian Elischer 				val.v4 = ntohl(val.v4);
456426b3d04SJulian Elischer 
457426b3d04SJulian Elischer 				switch (privp->conf->ops[i].mode)
458426b3d04SJulian Elischer 				{
459426b3d04SJulian Elischer 					case NG_PATCH_MODE_SET:
460426b3d04SJulian Elischer 						val.v4 = privp->conf->ops[i].val.v4;
461426b3d04SJulian Elischer 						break;
462426b3d04SJulian Elischer 					case NG_PATCH_MODE_ADD:
463426b3d04SJulian Elischer 						val.v4 += privp->conf->ops[i].val.v4;
464426b3d04SJulian Elischer 						break;
465426b3d04SJulian Elischer 					case NG_PATCH_MODE_SUB:
466426b3d04SJulian Elischer 						val.v4 -= privp->conf->ops[i].val.v4;
467426b3d04SJulian Elischer 						break;
468426b3d04SJulian Elischer 					case NG_PATCH_MODE_MUL:
469426b3d04SJulian Elischer 						val.v4 *= privp->conf->ops[i].val.v4;
470426b3d04SJulian Elischer 						break;
471426b3d04SJulian Elischer 					case NG_PATCH_MODE_DIV:
472426b3d04SJulian Elischer 						val.v4 /= privp->conf->ops[i].val.v4;
473426b3d04SJulian Elischer 						break;
474426b3d04SJulian Elischer 					case NG_PATCH_MODE_NEG:
475426b3d04SJulian Elischer 						*((int32_t *) &val) = - *((int32_t *) &val);
476426b3d04SJulian Elischer 						break;
477426b3d04SJulian Elischer 					case NG_PATCH_MODE_AND:
478426b3d04SJulian Elischer 						val.v4 &= privp->conf->ops[i].val.v4;
479426b3d04SJulian Elischer 						break;
480426b3d04SJulian Elischer 					case NG_PATCH_MODE_OR:
481426b3d04SJulian Elischer 						val.v4 |= privp->conf->ops[i].val.v4;
482426b3d04SJulian Elischer 						break;
483426b3d04SJulian Elischer 					case NG_PATCH_MODE_XOR:
484426b3d04SJulian Elischer 						val.v4 ^= privp->conf->ops[i].val.v4;
485426b3d04SJulian Elischer 						break;
486426b3d04SJulian Elischer 					case NG_PATCH_MODE_SHL:
487426b3d04SJulian Elischer 						val.v4 <<= privp->conf->ops[i].val.v4;
488426b3d04SJulian Elischer 						break;
489426b3d04SJulian Elischer 					case NG_PATCH_MODE_SHR:
490426b3d04SJulian Elischer 						val.v4 >>= privp->conf->ops[i].val.v4;
491426b3d04SJulian Elischer 						break;
492426b3d04SJulian Elischer 				}
493426b3d04SJulian Elischer 
494426b3d04SJulian Elischer 				val.v4 = htonl(val.v4);
495426b3d04SJulian Elischer 
496426b3d04SJulian Elischer 				break;
497426b3d04SJulian Elischer 
498426b3d04SJulian Elischer 			case 8:
499426b3d04SJulian Elischer 				val.v8 = be64toh(val.v8);
500426b3d04SJulian Elischer 
501426b3d04SJulian Elischer 				switch (privp->conf->ops[i].mode)
502426b3d04SJulian Elischer 				{
503426b3d04SJulian Elischer 					case NG_PATCH_MODE_SET:
504426b3d04SJulian Elischer 						val.v8 = privp->conf->ops[i].val.v8;
505426b3d04SJulian Elischer 						break;
506426b3d04SJulian Elischer 					case NG_PATCH_MODE_ADD:
507426b3d04SJulian Elischer 						val.v8 += privp->conf->ops[i].val.v8;
508426b3d04SJulian Elischer 						break;
509426b3d04SJulian Elischer 					case NG_PATCH_MODE_SUB:
510426b3d04SJulian Elischer 						val.v8 -= privp->conf->ops[i].val.v8;
511426b3d04SJulian Elischer 						break;
512426b3d04SJulian Elischer 					case NG_PATCH_MODE_MUL:
513426b3d04SJulian Elischer 						val.v8 *= privp->conf->ops[i].val.v8;
514426b3d04SJulian Elischer 						break;
515426b3d04SJulian Elischer 					case NG_PATCH_MODE_DIV:
516426b3d04SJulian Elischer 						val.v8 /= privp->conf->ops[i].val.v8;
517426b3d04SJulian Elischer 						break;
518426b3d04SJulian Elischer 					case NG_PATCH_MODE_NEG:
519426b3d04SJulian Elischer 						*((int64_t *) &val) = - *((int64_t *) &val);
520426b3d04SJulian Elischer 						break;
521426b3d04SJulian Elischer 					case NG_PATCH_MODE_AND:
522426b3d04SJulian Elischer 						val.v8 &= privp->conf->ops[i].val.v8;
523426b3d04SJulian Elischer 						break;
524426b3d04SJulian Elischer 					case NG_PATCH_MODE_OR:
525426b3d04SJulian Elischer 						val.v8 |= privp->conf->ops[i].val.v8;
526426b3d04SJulian Elischer 						break;
527426b3d04SJulian Elischer 					case NG_PATCH_MODE_XOR:
528426b3d04SJulian Elischer 						val.v8 ^= privp->conf->ops[i].val.v8;
529426b3d04SJulian Elischer 						break;
530426b3d04SJulian Elischer 					case NG_PATCH_MODE_SHL:
531426b3d04SJulian Elischer 						val.v8 <<= privp->conf->ops[i].val.v8;
532426b3d04SJulian Elischer 						break;
533426b3d04SJulian Elischer 					case NG_PATCH_MODE_SHR:
534426b3d04SJulian Elischer 						val.v8 >>= privp->conf->ops[i].val.v8;
535426b3d04SJulian Elischer 						break;
536426b3d04SJulian Elischer 				}
537426b3d04SJulian Elischer 
538426b3d04SJulian Elischer 				val.v8 = htobe64(val.v8);
539426b3d04SJulian Elischer 
540426b3d04SJulian Elischer 				break;
541426b3d04SJulian Elischer 		}
542426b3d04SJulian Elischer 
543426b3d04SJulian Elischer 		m_copyback(m, offset, privp->conf->ops[i].length, (caddr_t) &val);
544d359a62dSAndrey V. Elsukov 		patched = 1;
545d359a62dSAndrey V. Elsukov 	}
546426b3d04SJulian Elischer 
547426b3d04SJulian Elischer 	if (patched)
548d359a62dSAndrey V. Elsukov 		privp->stats.patched++;
549d359a62dSAndrey V. Elsukov }
550d359a62dSAndrey V. Elsukov 
551d359a62dSAndrey V. Elsukov static int
552d359a62dSAndrey V. Elsukov ng_patch_rcvdata(hook_p hook, item_p item)
553d359a62dSAndrey V. Elsukov {
554d359a62dSAndrey V. Elsukov 	const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
555d359a62dSAndrey V. Elsukov 	struct mbuf *m;
556426b3d04SJulian Elischer 	hook_p out;
557426b3d04SJulian Elischer 	int pullup_len = 0;
558426b3d04SJulian Elischer 	int error = 0;
559d359a62dSAndrey V. Elsukov 
560d359a62dSAndrey V. Elsukov 	priv->stats.received++;
561426b3d04SJulian Elischer 
562d359a62dSAndrey V. Elsukov 	NGI_GET_M(item, m);
563426b3d04SJulian Elischer 
564426b3d04SJulian Elischer #define	PULLUP_CHECK(mbuf, length) do {					\
565426b3d04SJulian Elischer 	pullup_len += length;						\
566426b3d04SJulian Elischer 	if (((mbuf)->m_pkthdr.len < pullup_len) ||			\
567426b3d04SJulian Elischer 	    (pullup_len > MHLEN)) {					\
568426b3d04SJulian Elischer 		error = EINVAL;						\
569426b3d04SJulian Elischer 		goto bypass;						\
570426b3d04SJulian Elischer 	}								\
571426b3d04SJulian Elischer 	if ((mbuf)->m_len < pullup_len &&				\
572426b3d04SJulian Elischer 	    (((mbuf) = m_pullup((mbuf), pullup_len)) == NULL)) {	\
573426b3d04SJulian Elischer 		error = ENOBUFS;					\
574426b3d04SJulian Elischer 		goto drop;						\
575426b3d04SJulian Elischer 	}								\
576426b3d04SJulian Elischer } while (0)
577426b3d04SJulian Elischer 
578426b3d04SJulian Elischer 	if (priv->conf && hook == priv->in &&
579426b3d04SJulian Elischer 	    m && (m->m_flags & M_PKTHDR)) {
580d359a62dSAndrey V. Elsukov 		m = m_unshare(m, M_NOWAIT);
581426b3d04SJulian Elischer 
582426b3d04SJulian Elischer 		if (m == NULL)
583426b3d04SJulian Elischer 			ERROUT(ENOMEM);
584426b3d04SJulian Elischer 
585426b3d04SJulian Elischer 		if (priv->conf->relative_offset) {
586426b3d04SJulian Elischer 			struct ether_header *eh;
587426b3d04SJulian Elischer 			struct ng_patch_vlan_header *vh;
588426b3d04SJulian Elischer 			uint16_t etype;
589426b3d04SJulian Elischer 
590426b3d04SJulian Elischer 			switch (priv->dlt)
591426b3d04SJulian Elischer 			{
592426b3d04SJulian Elischer 				case DLT_EN10MB:
593426b3d04SJulian Elischer 					PULLUP_CHECK(m, sizeof(struct ether_header));
594426b3d04SJulian Elischer 					eh = mtod(m, struct ether_header *);
595426b3d04SJulian Elischer 					etype = ntohs(eh->ether_type);
596426b3d04SJulian Elischer 
597426b3d04SJulian Elischer 					for (;;) {	/* QinQ support */
598426b3d04SJulian Elischer 						switch (etype)
599426b3d04SJulian Elischer 						{
600426b3d04SJulian Elischer 							case 0x8100:
601426b3d04SJulian Elischer 							case 0x88A8:
602426b3d04SJulian Elischer 							case 0x9100:
603426b3d04SJulian Elischer 								PULLUP_CHECK(m, sizeof(struct ng_patch_vlan_header));
604426b3d04SJulian Elischer 								vh = (struct ng_patch_vlan_header *) mtodo(m,
605426b3d04SJulian Elischer 								    pullup_len - sizeof(struct ng_patch_vlan_header));
606426b3d04SJulian Elischer 								etype = ntohs(vh->etype);
607426b3d04SJulian Elischer 								break;
608426b3d04SJulian Elischer 
609426b3d04SJulian Elischer 							default:
610426b3d04SJulian Elischer 								goto loopend;
611d359a62dSAndrey V. Elsukov 						}
612426b3d04SJulian Elischer 					}
613426b3d04SJulian Elischer loopend:
614426b3d04SJulian Elischer 					break;
615426b3d04SJulian Elischer 
616426b3d04SJulian Elischer 				case DLT_RAW:
617426b3d04SJulian Elischer 					break;
618426b3d04SJulian Elischer 
619426b3d04SJulian Elischer 				default:
620426b3d04SJulian Elischer 					ERROUT(EINVAL);
621426b3d04SJulian Elischer 			}
622d359a62dSAndrey V. Elsukov 		}
623d359a62dSAndrey V. Elsukov 
624426b3d04SJulian Elischer 		do_patch(priv, m, pullup_len);
625426b3d04SJulian Elischer 
626426b3d04SJulian Elischer 		m->m_pkthdr.csum_flags |= priv->conf->csum_flags;
627426b3d04SJulian Elischer 	}
628426b3d04SJulian Elischer 
629426b3d04SJulian Elischer #undef	PULLUP_CHECK
630426b3d04SJulian Elischer 
631426b3d04SJulian Elischer bypass:
632426b3d04SJulian Elischer 	out = NULL;
633426b3d04SJulian Elischer 
634d359a62dSAndrey V. Elsukov 	if (hook == priv->in) {
635d359a62dSAndrey V. Elsukov 		/* return frames on 'in' hook if 'out' not connected */
636426b3d04SJulian Elischer 		out = priv->out ? priv->out : priv->in;
637426b3d04SJulian Elischer 	} else if (hook == priv->out && priv->in) {
638426b3d04SJulian Elischer 		/* pass frames on 'out' hook if 'in' connected */
639426b3d04SJulian Elischer 		out = priv->in;
640d359a62dSAndrey V. Elsukov 	}
641d359a62dSAndrey V. Elsukov 
642426b3d04SJulian Elischer 	if (out == NULL)
643426b3d04SJulian Elischer 		ERROUT(0);
644426b3d04SJulian Elischer 
645426b3d04SJulian Elischer 	NG_FWD_NEW_DATA(error, item, out, m);
646426b3d04SJulian Elischer 
647426b3d04SJulian Elischer 	return (error);
648426b3d04SJulian Elischer 
649426b3d04SJulian Elischer done:
650426b3d04SJulian Elischer drop:
651d359a62dSAndrey V. Elsukov 	NG_FREE_ITEM(item);
652d359a62dSAndrey V. Elsukov 	NG_FREE_M(m);
653426b3d04SJulian Elischer 
654426b3d04SJulian Elischer 	priv->stats.dropped++;
655426b3d04SJulian 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);
666426b3d04SJulian Elischer 
667426b3d04SJulian Elischer 	if (privdata->conf != NULL)
668426b3d04SJulian Elischer 		free(privdata->conf, M_NETGRAPH);
669426b3d04SJulian Elischer 
670d359a62dSAndrey V. Elsukov 	free(privdata, M_NETGRAPH);
671426b3d04SJulian 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));
681426b3d04SJulian Elischer 
682d359a62dSAndrey V. Elsukov 	if (hook == priv->in) {
683d359a62dSAndrey V. Elsukov 		priv->in = NULL;
684d359a62dSAndrey V. Elsukov 	}
685426b3d04SJulian Elischer 
686d359a62dSAndrey V. Elsukov 	if (hook == priv->out) {
687d359a62dSAndrey V. Elsukov 		priv->out = NULL;
688d359a62dSAndrey V. Elsukov 	}
689426b3d04SJulian 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));
693426b3d04SJulian Elischer 
694d359a62dSAndrey V. Elsukov 	return (0);
695d359a62dSAndrey V. Elsukov }
696