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