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