2 * Copyright (C) 2010 by Maxim Ignatenko <gelraen.ua@gmail.com>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/endian.h>
35 #include <sys/malloc.h>
37 #include <netgraph/ng_message.h>
38 #include <netgraph/ng_parse.h>
39 #include <netgraph/ng_patch.h>
40 #include <netgraph/netgraph.h>
42 static ng_constructor_t ng_patch_constructor;
43 static ng_rcvmsg_t ng_patch_rcvmsg;
44 static ng_shutdown_t ng_patch_shutdown;
45 static ng_newhook_t ng_patch_newhook;
46 static ng_rcvdata_t ng_patch_rcvdata;
47 static ng_disconnect_t ng_patch_disconnect;
50 ng_patch_config_getlen(const struct ng_parse_type *type,
51 const u_char *start, const u_char *buf)
53 const struct ng_patch_config *p;
55 p = (const struct ng_patch_config *)(buf -
56 offsetof(struct ng_patch_config, ops));
60 static const struct ng_parse_struct_field ng_patch_op_type_fields[]
61 = NG_PATCH_OP_TYPE_INFO;
62 static const struct ng_parse_type ng_patch_op_type = {
63 &ng_parse_struct_type,
64 &ng_patch_op_type_fields
67 static const struct ng_parse_array_info ng_patch_confarr_info = {
69 &ng_patch_config_getlen
71 static const struct ng_parse_type ng_patch_confarr_type = {
73 &ng_patch_confarr_info
76 static const struct ng_parse_struct_field ng_patch_config_type_fields[]
77 = NG_PATCH_CONFIG_TYPE_INFO;
78 static const struct ng_parse_type ng_patch_config_type = {
79 &ng_parse_struct_type,
80 &ng_patch_config_type_fields
83 static const struct ng_parse_struct_field ng_patch_stats_fields[]
84 = NG_PATCH_STATS_TYPE_INFO;
85 static const struct ng_parse_type ng_patch_stats_type = {
86 &ng_parse_struct_type,
87 &ng_patch_stats_fields
90 static const struct ng_cmdlist ng_patch_cmdlist[] = {
102 &ng_patch_config_type,
121 NGM_PATCH_GETCLR_STATS,
129 static struct ng_type typestruct = {
130 .version = NG_ABI_VERSION,
131 .name = NG_PATCH_NODE_TYPE,
132 .constructor = ng_patch_constructor,
133 .rcvmsg = ng_patch_rcvmsg,
134 .shutdown = ng_patch_shutdown,
135 .newhook = ng_patch_newhook,
136 .rcvdata = ng_patch_rcvdata,
137 .disconnect = ng_patch_disconnect,
138 .cmdlist = ng_patch_cmdlist,
140 NETGRAPH_INIT(patch, &typestruct);
149 struct ng_patch_priv {
152 struct ng_patch_config *config;
153 union patch_val *val;
154 struct ng_patch_stats stats;
156 typedef struct ng_patch_priv *priv_p;
158 #define NG_PATCH_CONF_SIZE(count) (sizeof(struct ng_patch_config) + \
159 (count) * sizeof(struct ng_patch_op))
161 static void do_patch(priv_p conf, struct mbuf *m);
164 ng_patch_constructor(node_p node)
168 privdata = malloc(sizeof(*privdata), M_NETGRAPH, M_WAIT | M_ZERO);
169 NG_NODE_SET_PRIVATE(node, privdata);
171 privdata->out = NULL;
172 privdata->config = NULL;
177 ng_patch_newhook(node_p node, hook_p hook, const char *name)
179 const priv_p privp = NG_NODE_PRIVATE(node);
181 if (strncmp(name, NG_PATCH_HOOK_IN, strlen(NG_PATCH_HOOK_IN)) == 0) {
183 } else if (strncmp(name, NG_PATCH_HOOK_OUT,
184 strlen(NG_PATCH_HOOK_OUT)) == 0) {
192 ng_patch_rcvmsg(node_p node, item_p item, hook_p lasthook)
194 const priv_p privp = NG_NODE_PRIVATE(node);
195 struct ng_patch_config *conf, *newconf;
196 union patch_val *newval;
198 struct ng_mesg *resp;
203 NGI_GET_MSG(item, msg);
204 switch (msg->header.typecookie) {
205 case NGM_PATCH_COOKIE:
206 switch (msg->header.cmd) {
207 case NGM_PATCH_GETCONFIG:
208 if (privp->config == NULL)
210 NG_MKRESPONSE(resp, msg,
211 NG_PATCH_CONF_SIZE(privp->config->count), M_WAIT);
212 bcopy(privp->config, resp->data,
213 NG_PATCH_CONF_SIZE(privp->config->count));
215 case NGM_PATCH_SETCONFIG:
217 if (msg->header.arglen <
218 sizeof(struct ng_patch_config)) {
223 conf = (struct ng_patch_config *)msg->data;
224 if (msg->header.arglen <
225 NG_PATCH_CONF_SIZE(conf->count)) {
230 for(i = 0; i < conf->count; i++) {
231 switch(conf->ops[i].length) {
245 conf->csum_flags &= CSUM_IP | CSUM_TCP | CSUM_UDP |
250 NG_PATCH_CONF_SIZE(conf->count),
252 newval = malloc(conf->count *
253 sizeof(union patch_val), M_NETGRAPH,
255 for(i = 0; i < conf->count; i++) {
256 switch (conf->ops[i].length) {
276 NG_PATCH_CONF_SIZE(conf->count));
277 if (privp->val != NULL)
278 free(privp->val, M_NETGRAPH);
280 if (privp->config != NULL)
281 free(privp->config, M_NETGRAPH);
282 privp->config = newconf;
286 case NGM_PATCH_GETCLR_STATS:
289 case NGM_PATCH_GET_STATS:
290 NG_MKRESPONSE(resp, msg, sizeof(struct ng_patch_stats),
292 bcopy(&(privp->stats), resp->data,
293 sizeof(struct ng_patch_stats));
296 /* else FALLTHROUGH */
297 case NGM_PATCH_CLR_STATS:
298 bzero(&(privp->stats), sizeof(struct ng_patch_stats));
310 NG_RESPOND_MSG(error, node, item, resp);
316 do_patch(priv_p privp, struct mbuf *m)
318 struct ng_patch_config *conf;
322 conf = privp->config;
324 for(i = 0; i < conf->count; i++) {
325 if (conf->ops[i].offset + conf->ops[i].length >
329 /* for "=" operation we don't need to copy data from mbuf */
330 if (conf->ops[i].mode != NG_PATCH_MODE_SET) {
331 m_copydata(m, conf->ops[i].offset,
332 conf->ops[i].length, (caddr_t)&buf);
335 switch (conf->ops[i].length) {
337 switch (conf->ops[i].mode) {
338 case NG_PATCH_MODE_SET:
339 *((uint8_t *)&buf) = privp->val[i].v1;
341 case NG_PATCH_MODE_ADD:
342 *((uint8_t *)&buf) += privp->val[i].v1;
344 case NG_PATCH_MODE_SUB:
345 *((uint8_t *)&buf) -= privp->val[i].v1;
347 case NG_PATCH_MODE_MUL:
348 *((uint8_t *)&buf) *= privp->val[i].v1;
350 case NG_PATCH_MODE_DIV:
351 *((uint8_t *)&buf) /= privp->val[i].v1;
353 case NG_PATCH_MODE_NEG:
354 *((int8_t *)&buf) = - *((int8_t *)&buf);
356 case NG_PATCH_MODE_AND:
357 *((uint8_t *)&buf) &= privp->val[i].v1;
359 case NG_PATCH_MODE_OR:
360 *((uint8_t *)&buf) |= privp->val[i].v1;
362 case NG_PATCH_MODE_XOR:
363 *((uint8_t *)&buf) ^= privp->val[i].v1;
365 case NG_PATCH_MODE_SHL:
366 *((uint8_t *)&buf) <<= privp->val[i].v1;
368 case NG_PATCH_MODE_SHR:
369 *((uint8_t *)&buf) >>= privp->val[i].v1;
374 *((int16_t *)&buf) = ntohs(*((int16_t *)&buf));
375 switch (conf->ops[i].mode) {
376 case NG_PATCH_MODE_SET:
377 *((uint16_t *)&buf) = privp->val[i].v2;
379 case NG_PATCH_MODE_ADD:
380 *((uint16_t *)&buf) += privp->val[i].v2;
382 case NG_PATCH_MODE_SUB:
383 *((uint16_t *)&buf) -= privp->val[i].v2;
385 case NG_PATCH_MODE_MUL:
386 *((uint16_t *)&buf) *= privp->val[i].v2;
388 case NG_PATCH_MODE_DIV:
389 *((uint16_t *)&buf) /= privp->val[i].v2;
391 case NG_PATCH_MODE_NEG:
392 *((int16_t *)&buf) = - *((int16_t *)&buf);
394 case NG_PATCH_MODE_AND:
395 *((uint16_t *)&buf) &= privp->val[i].v2;
397 case NG_PATCH_MODE_OR:
398 *((uint16_t *)&buf) |= privp->val[i].v2;
400 case NG_PATCH_MODE_XOR:
401 *((uint16_t *)&buf) ^= privp->val[i].v2;
403 case NG_PATCH_MODE_SHL:
404 *((uint16_t *)&buf) <<= privp->val[i].v2;
406 case NG_PATCH_MODE_SHR:
407 *((uint16_t *)&buf) >>= privp->val[i].v2;
410 *((int16_t *)&buf) = htons(*((int16_t *)&buf));
413 *((int32_t *)&buf) = ntohl(*((int32_t *)&buf));
414 switch (conf->ops[i].mode) {
415 case NG_PATCH_MODE_SET:
416 *((uint32_t *)&buf) = privp->val[i].v4;
418 case NG_PATCH_MODE_ADD:
419 *((uint32_t *)&buf) += privp->val[i].v4;
421 case NG_PATCH_MODE_SUB:
422 *((uint32_t *)&buf) -= privp->val[i].v4;
424 case NG_PATCH_MODE_MUL:
425 *((uint32_t *)&buf) *= privp->val[i].v4;
427 case NG_PATCH_MODE_DIV:
428 *((uint32_t *)&buf) /= privp->val[i].v4;
430 case NG_PATCH_MODE_NEG:
431 *((int32_t *)&buf) = - *((int32_t *)&buf);
433 case NG_PATCH_MODE_AND:
434 *((uint32_t *)&buf) &= privp->val[i].v4;
436 case NG_PATCH_MODE_OR:
437 *((uint32_t *)&buf) |= privp->val[i].v4;
439 case NG_PATCH_MODE_XOR:
440 *((uint32_t *)&buf) ^= privp->val[i].v4;
442 case NG_PATCH_MODE_SHL:
443 *((uint32_t *)&buf) <<= privp->val[i].v4;
445 case NG_PATCH_MODE_SHR:
446 *((uint32_t *)&buf) >>= privp->val[i].v4;
449 *((int32_t *)&buf) = htonl(*((int32_t *)&buf));
452 *((int64_t *)&buf) = be64toh(*((int64_t *)&buf));
453 switch (conf->ops[i].mode) {
454 case NG_PATCH_MODE_SET:
455 *((uint64_t *)&buf) = privp->val[i].v8;
457 case NG_PATCH_MODE_ADD:
458 *((uint64_t *)&buf) += privp->val[i].v8;
460 case NG_PATCH_MODE_SUB:
461 *((uint64_t *)&buf) -= privp->val[i].v8;
463 case NG_PATCH_MODE_MUL:
464 *((uint64_t *)&buf) *= privp->val[i].v8;
466 case NG_PATCH_MODE_DIV:
467 *((uint64_t *)&buf) /= privp->val[i].v8;
469 case NG_PATCH_MODE_NEG:
470 *((int64_t *)&buf) = - *((int64_t *)&buf);
472 case NG_PATCH_MODE_AND:
473 *((uint64_t *)&buf) &= privp->val[i].v8;
475 case NG_PATCH_MODE_OR:
476 *((uint64_t *)&buf) |= privp->val[i].v8;
478 case NG_PATCH_MODE_XOR:
479 *((uint64_t *)&buf) ^= privp->val[i].v8;
481 case NG_PATCH_MODE_SHL:
482 *((uint64_t *)&buf) <<= privp->val[i].v8;
484 case NG_PATCH_MODE_SHR:
485 *((uint64_t *)&buf) >>= privp->val[i].v8;
488 *((int64_t *)&buf) = htobe64(*((int64_t *)&buf));
492 m_copyback(m, conf->ops[i].offset, conf->ops[i].length,
497 privp->stats.patched++;
501 ng_patch_rcvdata(hook_p hook, item_p item)
503 const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
508 priv->stats.received++;
510 if (priv->config != NULL && hook == priv->in &&
511 (m->m_flags & M_PKTHDR) != 0) {
512 m = m_unshare(m,M_NOWAIT);
514 priv->stats.dropped++;
519 m->m_flags |= priv->config->csum_flags;
523 if (hook == priv->in) {
524 /* return frames on 'in' hook if 'out' not connected */
525 if (priv->out != NULL)
530 if (hook == priv->out && priv->in != NULL)
533 if (target == NULL) {
534 priv->stats.dropped++;
539 NG_FWD_NEW_DATA(error, item, target, m);
544 ng_patch_shutdown(node_p node)
546 const priv_p privdata = NG_NODE_PRIVATE(node);
548 if (privdata->val != NULL)
549 free(privdata->val, M_NETGRAPH);
550 if (privdata->config != NULL)
551 free(privdata->config, M_NETGRAPH);
552 NG_NODE_SET_PRIVATE(node, NULL);
554 free(privdata, M_NETGRAPH);
559 ng_patch_disconnect(hook_p hook)
563 priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
564 if (hook == priv->in) {
567 if (hook == priv->out) {
570 if (NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0 &&
571 NG_NODE_IS_VALID(NG_HOOK_NODE(hook))) /* already shutting down? */
572 ng_rmnode_self(NG_HOOK_NODE(hook));