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