summaryrefslogtreecommitdiffstats
path: root/sys/netgraph
diff options
context:
space:
mode:
authorLuiz Otavio O Souza <luiz@netgate.com>2016-12-30 20:30:00 -0600
committerLuiz Otavio O Souza <luiz@netgate.com>2016-12-30 20:30:00 -0600
commit1af1408e09373ae856cfef567d79849c7e7e0d25 (patch)
tree8a4a2bc017c297dea8c977c53f8c1099e26edbe6 /sys/netgraph
parentba2be30f109cb2d0c83d41dff268b04f085252b4 (diff)
parent0591c0c87ec4e420c1a1e9a0c10f761ff4a832c2 (diff)
downloadFreeBSD-src-1af1408e09373ae856cfef567d79849c7e7e0d25.zip
FreeBSD-src-1af1408e09373ae856cfef567d79849c7e7e0d25.tar.gz
Merge remote-tracking branch 'origin/stable/11' into devel-11
Diffstat (limited to 'sys/netgraph')
-rw-r--r--sys/netgraph/ng_base.c6
-rw-r--r--sys/netgraph/ng_patch.c756
-rw-r--r--sys/netgraph/ng_patch.h74
3 files changed, 491 insertions, 345 deletions
diff --git a/sys/netgraph/ng_base.c b/sys/netgraph/ng_base.c
index 78c0c1b..ed373b2 100644
--- a/sys/netgraph/ng_base.c
+++ b/sys/netgraph/ng_base.c
@@ -3849,7 +3849,11 @@ ng_uncallout(struct callout *c, node_p node)
}
c->c_arg = NULL;
- return (rval);
+ /*
+ * Callers only want to know if the callout was cancelled and
+ * not draining or stopped.
+ */
+ return (rval > 0);
}
/*
diff --git a/sys/netgraph/ng_patch.c b/sys/netgraph/ng_patch.c
index 691bd60..efe4a67 100644
--- a/sys/netgraph/ng_patch.c
+++ b/sys/netgraph/ng_patch.c
@@ -1,5 +1,6 @@
/*-
- * Copyright (c) 2010 Maxim Ignatenko <gelraen.ua@gmail.com>
+ * Copyright (c) 2010 Maxim Ignatenko <gelraen.ua@gmail.com>
+ * Copyright (c) 2015 Dmitry Vagin <daemon.hammer@ya.ru>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -34,11 +35,28 @@ __FBSDID("$FreeBSD$");
#include <sys/endian.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
+
+#include <net/bpf.h>
+#include <net/ethernet.h>
+
#include <netgraph/ng_message.h>
#include <netgraph/ng_parse.h>
-#include <netgraph/ng_patch.h>
#include <netgraph/netgraph.h>
+#include <netgraph/ng_patch.h>
+
+/* private data */
+struct ng_patch_priv {
+ hook_p in;
+ hook_p out;
+ uint8_t dlt; /* DLT_XXX from bpf.h */
+ struct ng_patch_stats stats;
+ struct ng_patch_config *conf;
+};
+
+typedef struct ng_patch_priv *priv_p;
+
+/* Netgraph methods */
static ng_constructor_t ng_patch_constructor;
static ng_rcvmsg_t ng_patch_rcvmsg;
static ng_shutdown_t ng_patch_shutdown;
@@ -46,6 +64,8 @@ static ng_newhook_t ng_patch_newhook;
static ng_rcvdata_t ng_patch_rcvdata;
static ng_disconnect_t ng_patch_disconnect;
+#define ERROUT(x) { error = (x); goto done; }
+
static int
ng_patch_config_getlen(const struct ng_parse_type *type,
const u_char *start, const u_char *buf)
@@ -59,7 +79,7 @@ ng_patch_config_getlen(const struct ng_parse_type *type,
}
static const struct ng_parse_struct_field ng_patch_op_type_fields[]
- = NG_PATCH_OP_TYPE_INFO;
+ = NG_PATCH_OP_TYPE;
static const struct ng_parse_type ng_patch_op_type = {
&ng_parse_struct_type,
&ng_patch_op_type_fields
@@ -75,14 +95,14 @@ static const struct ng_parse_type ng_patch_ops_array_type = {
};
static const struct ng_parse_struct_field ng_patch_config_type_fields[]
- = NG_PATCH_CONFIG_TYPE_INFO;
+ = NG_PATCH_CONFIG_TYPE;
static const struct ng_parse_type ng_patch_config_type = {
&ng_parse_struct_type,
&ng_patch_config_type_fields
};
static const struct ng_parse_struct_field ng_patch_stats_fields[]
- = NG_PATCH_STATS_TYPE_INFO;
+ = NG_PATCH_STATS_TYPE;
static const struct ng_parse_type ng_patch_stats_type = {
&ng_parse_struct_type,
&ng_patch_stats_fields
@@ -91,6 +111,20 @@ static const struct ng_parse_type ng_patch_stats_type = {
static const struct ng_cmdlist ng_patch_cmdlist[] = {
{
NGM_PATCH_COOKIE,
+ NGM_PATCH_GETDLT,
+ "getdlt",
+ NULL,
+ &ng_parse_uint8_type
+ },
+ {
+ NGM_PATCH_COOKIE,
+ NGM_PATCH_SETDLT,
+ "setdlt",
+ &ng_parse_uint8_type,
+ NULL
+ },
+ {
+ NGM_PATCH_COOKIE,
NGM_PATCH_GETCONFIG,
"getconfig",
NULL,
@@ -141,38 +175,16 @@ static struct ng_type typestruct = {
NETGRAPH_INIT(patch, &typestruct);
-union patch_val {
- uint8_t v1;
- uint16_t v2;
- uint32_t v4;
- uint64_t v8;
-};
-
-/* private data */
-struct ng_patch_priv {
- hook_p in;
- hook_p out;
- struct ng_patch_config *config;
- union patch_val *val;
- struct ng_patch_stats stats;
-};
-typedef struct ng_patch_priv *priv_p;
-
-#define NG_PATCH_CONF_SIZE(count) (sizeof(struct ng_patch_config) + \
- (count) * sizeof(struct ng_patch_op))
-
-static void do_patch(priv_p conf, struct mbuf *m);
-
static int
ng_patch_constructor(node_p node)
{
priv_p privdata;
privdata = malloc(sizeof(*privdata), M_NETGRAPH, M_WAITOK | M_ZERO);
+ privdata->dlt = DLT_RAW;
+
NG_NODE_SET_PRIVATE(node, privdata);
- privdata->in = NULL;
- privdata->out = NULL;
- privdata->config = NULL;
+
return (0);
}
@@ -188,7 +200,8 @@ ng_patch_newhook(node_p node, hook_p hook, const char *name)
privp->out = hook;
} else
return (EINVAL);
- return(0);
+
+ return (0);
}
static int
@@ -196,308 +209,341 @@ ng_patch_rcvmsg(node_p node, item_p item, hook_p lasthook)
{
const priv_p privp = NG_NODE_PRIVATE(node);
struct ng_patch_config *conf, *newconf;
- union patch_val *newval;
struct ng_mesg *msg;
- struct ng_mesg *resp;
- int i, clear, error;
+ struct ng_mesg *resp = NULL;
+ int i, error = 0;
- clear = error = 0;
- resp = NULL;
NGI_GET_MSG(item, msg);
- switch (msg->header.typecookie) {
- case NGM_PATCH_COOKIE:
- switch (msg->header.cmd) {
+
+ if (msg->header.typecookie != NGM_PATCH_COOKIE)
+ ERROUT(EINVAL);
+
+ switch (msg->header.cmd)
+ {
case NGM_PATCH_GETCONFIG:
- if (privp->config == NULL)
- break;
+ if (privp->conf == NULL)
+ ERROUT(0);
+
NG_MKRESPONSE(resp, msg,
- NG_PATCH_CONF_SIZE(privp->config->count),
- M_WAITOK);
- bcopy(privp->config, resp->data,
- NG_PATCH_CONF_SIZE(privp->config->count));
- break;
- case NGM_PATCH_SETCONFIG:
- {
- if (msg->header.arglen <
- sizeof(struct ng_patch_config)) {
- error = EINVAL;
- break;
- }
+ NG_PATCH_CONF_SIZE(privp->conf->count), M_WAITOK);
- conf = (struct ng_patch_config *)msg->data;
- if (msg->header.arglen <
- NG_PATCH_CONF_SIZE(conf->count)) {
- error = EINVAL;
- break;
- }
+ if (resp == NULL)
+ ERROUT(ENOMEM);
- for(i = 0; i < conf->count; i++) {
- switch(conf->ops[i].length) {
- case 1:
- case 2:
- case 4:
- case 8:
- break;
- default:
- error = EINVAL;
- break;
+ bcopy(privp->conf, resp->data,
+ NG_PATCH_CONF_SIZE(privp->conf->count));
+
+ conf = (struct ng_patch_config *) resp->data;
+
+ for (i = 0; i < conf->count; i++) {
+ switch (conf->ops[i].length)
+ {
+ case 1:
+ conf->ops[i].val.v8 = conf->ops[i].val.v1;
+ break;
+ case 2:
+ conf->ops[i].val.v8 = conf->ops[i].val.v2;
+ break;
+ case 4:
+ conf->ops[i].val.v8 = conf->ops[i].val.v4;
+ break;
+ case 8:
+ break;
}
- if (error != 0)
- break;
}
- conf->csum_flags &= CSUM_IP | CSUM_TCP | CSUM_UDP |
- CSUM_SCTP;
-
- if (error == 0) {
- newconf = malloc(
- NG_PATCH_CONF_SIZE(conf->count),
- M_NETGRAPH, M_WAITOK);
- newval = malloc(conf->count *
- sizeof(union patch_val), M_NETGRAPH,
- M_WAITOK);
- for(i = 0; i < conf->count; i++) {
- switch (conf->ops[i].length) {
+ break;
+
+ case NGM_PATCH_SETCONFIG:
+ conf = (struct ng_patch_config *) msg->data;
+
+ if (msg->header.arglen < sizeof(struct ng_patch_config) ||
+ msg->header.arglen < NG_PATCH_CONF_SIZE(conf->count))
+ ERROUT(EINVAL);
+
+ for (i = 0; i < conf->count; i++) {
+ switch (conf->ops[i].length)
+ {
case 1:
- newval[i].v1 =
- conf->ops[i].value;
+ conf->ops[i].val.v1 = (uint8_t) conf->ops[i].val.v8;
break;
case 2:
- newval[i].v2 =
- conf->ops[i].value;
+ conf->ops[i].val.v2 = (uint16_t) conf->ops[i].val.v8;
break;
case 4:
- newval[i].v4 =
- conf->ops[i].value;
+ conf->ops[i].val.v4 = (uint32_t) conf->ops[i].val.v8;
break;
case 8:
- newval[i].v8 =
- conf->ops[i].value;
break;
- }
+ default:
+ ERROUT(EINVAL);
}
- bcopy(conf, newconf,
- NG_PATCH_CONF_SIZE(conf->count));
- if (privp->val != NULL)
- free(privp->val, M_NETGRAPH);
- privp->val = newval;
- if (privp->config != NULL)
- free(privp->config, M_NETGRAPH);
- privp->config = newconf;
}
+
+ conf->csum_flags &= NG_PATCH_CSUM_IPV4|NG_PATCH_CSUM_IPV6;
+ conf->relative_offset = !!conf->relative_offset;
+
+ newconf = malloc(NG_PATCH_CONF_SIZE(conf->count), M_NETGRAPH, M_WAITOK | M_ZERO);
+
+ bcopy(conf, newconf, NG_PATCH_CONF_SIZE(conf->count));
+
+ if (privp->conf)
+ free(privp->conf, M_NETGRAPH);
+
+ privp->conf = newconf;
+
break;
- }
- case NGM_PATCH_GETCLR_STATS:
- clear = 1;
- /* FALLTHROUGH */
+
case NGM_PATCH_GET_STATS:
- NG_MKRESPONSE(resp, msg, sizeof(struct ng_patch_stats),
- M_WAITOK);
- bcopy(&(privp->stats), resp->data,
- sizeof(struct ng_patch_stats));
- if (clear == 0)
- break;
- /* else FALLTHROUGH */
case NGM_PATCH_CLR_STATS:
- bzero(&(privp->stats), sizeof(struct ng_patch_stats));
+ case NGM_PATCH_GETCLR_STATS:
+ if (msg->header.cmd != NGM_PATCH_CLR_STATS) {
+ NG_MKRESPONSE(resp, msg, sizeof(struct ng_patch_stats), M_WAITOK);
+
+ if (resp == NULL)
+ ERROUT(ENOMEM);
+
+ bcopy(&(privp->stats), resp->data, sizeof(struct ng_patch_stats));
+ }
+
+ if (msg->header.cmd != NGM_PATCH_GET_STATS)
+ bzero(&(privp->stats), sizeof(struct ng_patch_stats));
+
break;
- default:
- error = EINVAL;
+
+ case NGM_PATCH_GETDLT:
+ NG_MKRESPONSE(resp, msg, sizeof(uint8_t), M_WAITOK);
+
+ if (resp == NULL)
+ ERROUT(ENOMEM);
+
+ *((uint8_t *) resp->data) = privp->dlt;
+
break;
- }
- break;
- default:
- error = EINVAL;
- break;
+
+ case NGM_PATCH_SETDLT:
+ if (msg->header.arglen != sizeof(uint8_t))
+ ERROUT(EINVAL);
+
+ switch (*(uint8_t *) msg->data)
+ {
+ case DLT_EN10MB:
+ case DLT_RAW:
+ privp->dlt = *(uint8_t *) msg->data;
+ break;
+
+ default:
+ ERROUT(EINVAL);
+ }
+
+ break;
+
+ default:
+ ERROUT(EINVAL);
}
+done:
NG_RESPOND_MSG(error, node, item, resp);
NG_FREE_MSG(msg);
- return(error);
+
+ return (error);
}
static void
-do_patch(priv_p privp, struct mbuf *m)
+do_patch(priv_p privp, struct mbuf *m, int global_offset)
{
- struct ng_patch_config *conf;
- uint64_t buf;
- int i, patched;
-
- conf = privp->config;
- patched = 0;
- for(i = 0; i < conf->count; i++) {
- if (conf->ops[i].offset + conf->ops[i].length >
- m->m_pkthdr.len)
+ int i, offset, patched = 0;
+ union ng_patch_op_val val;
+
+ for (i = 0; i < privp->conf->count; i++) {
+ offset = global_offset + privp->conf->ops[i].offset;
+
+ if (offset + privp->conf->ops[i].length > m->m_pkthdr.len)
continue;
/* for "=" operation we don't need to copy data from mbuf */
- if (conf->ops[i].mode != NG_PATCH_MODE_SET) {
- m_copydata(m, conf->ops[i].offset,
- conf->ops[i].length, (caddr_t)&buf);
- }
-
- switch (conf->ops[i].length) {
- case 1:
- switch (conf->ops[i].mode) {
- case NG_PATCH_MODE_SET:
- *((uint8_t *)&buf) = privp->val[i].v1;
- break;
- case NG_PATCH_MODE_ADD:
- *((uint8_t *)&buf) += privp->val[i].v1;
- break;
- case NG_PATCH_MODE_SUB:
- *((uint8_t *)&buf) -= privp->val[i].v1;
- break;
- case NG_PATCH_MODE_MUL:
- *((uint8_t *)&buf) *= privp->val[i].v1;
- break;
- case NG_PATCH_MODE_DIV:
- *((uint8_t *)&buf) /= privp->val[i].v1;
- break;
- case NG_PATCH_MODE_NEG:
- *((int8_t *)&buf) = - *((int8_t *)&buf);
- break;
- case NG_PATCH_MODE_AND:
- *((uint8_t *)&buf) &= privp->val[i].v1;
- break;
- case NG_PATCH_MODE_OR:
- *((uint8_t *)&buf) |= privp->val[i].v1;
- break;
- case NG_PATCH_MODE_XOR:
- *((uint8_t *)&buf) ^= privp->val[i].v1;
- break;
- case NG_PATCH_MODE_SHL:
- *((uint8_t *)&buf) <<= privp->val[i].v1;
- break;
- case NG_PATCH_MODE_SHR:
- *((uint8_t *)&buf) >>= privp->val[i].v1;
- break;
- }
- break;
- case 2:
- *((int16_t *)&buf) = ntohs(*((int16_t *)&buf));
- switch (conf->ops[i].mode) {
- case NG_PATCH_MODE_SET:
- *((uint16_t *)&buf) = privp->val[i].v2;
- break;
- case NG_PATCH_MODE_ADD:
- *((uint16_t *)&buf) += privp->val[i].v2;
- break;
- case NG_PATCH_MODE_SUB:
- *((uint16_t *)&buf) -= privp->val[i].v2;
- break;
- case NG_PATCH_MODE_MUL:
- *((uint16_t *)&buf) *= privp->val[i].v2;
- break;
- case NG_PATCH_MODE_DIV:
- *((uint16_t *)&buf) /= privp->val[i].v2;
- break;
- case NG_PATCH_MODE_NEG:
- *((int16_t *)&buf) = - *((int16_t *)&buf);
- break;
- case NG_PATCH_MODE_AND:
- *((uint16_t *)&buf) &= privp->val[i].v2;
- break;
- case NG_PATCH_MODE_OR:
- *((uint16_t *)&buf) |= privp->val[i].v2;
- break;
- case NG_PATCH_MODE_XOR:
- *((uint16_t *)&buf) ^= privp->val[i].v2;
- break;
- case NG_PATCH_MODE_SHL:
- *((uint16_t *)&buf) <<= privp->val[i].v2;
- break;
- case NG_PATCH_MODE_SHR:
- *((uint16_t *)&buf) >>= privp->val[i].v2;
- break;
- }
- *((int16_t *)&buf) = htons(*((int16_t *)&buf));
- break;
- case 4:
- *((int32_t *)&buf) = ntohl(*((int32_t *)&buf));
- switch (conf->ops[i].mode) {
- case NG_PATCH_MODE_SET:
- *((uint32_t *)&buf) = privp->val[i].v4;
- break;
- case NG_PATCH_MODE_ADD:
- *((uint32_t *)&buf) += privp->val[i].v4;
- break;
- case NG_PATCH_MODE_SUB:
- *((uint32_t *)&buf) -= privp->val[i].v4;
- break;
- case NG_PATCH_MODE_MUL:
- *((uint32_t *)&buf) *= privp->val[i].v4;
- break;
- case NG_PATCH_MODE_DIV:
- *((uint32_t *)&buf) /= privp->val[i].v4;
- break;
- case NG_PATCH_MODE_NEG:
- *((int32_t *)&buf) = - *((int32_t *)&buf);
- break;
- case NG_PATCH_MODE_AND:
- *((uint32_t *)&buf) &= privp->val[i].v4;
- break;
- case NG_PATCH_MODE_OR:
- *((uint32_t *)&buf) |= privp->val[i].v4;
- break;
- case NG_PATCH_MODE_XOR:
- *((uint32_t *)&buf) ^= privp->val[i].v4;
- break;
- case NG_PATCH_MODE_SHL:
- *((uint32_t *)&buf) <<= privp->val[i].v4;
- break;
- case NG_PATCH_MODE_SHR:
- *((uint32_t *)&buf) >>= privp->val[i].v4;
- break;
- }
- *((int32_t *)&buf) = htonl(*((int32_t *)&buf));
- break;
- case 8:
- *((int64_t *)&buf) = be64toh(*((int64_t *)&buf));
- switch (conf->ops[i].mode) {
- case NG_PATCH_MODE_SET:
- *((uint64_t *)&buf) = privp->val[i].v8;
- break;
- case NG_PATCH_MODE_ADD:
- *((uint64_t *)&buf) += privp->val[i].v8;
- break;
- case NG_PATCH_MODE_SUB:
- *((uint64_t *)&buf) -= privp->val[i].v8;
- break;
- case NG_PATCH_MODE_MUL:
- *((uint64_t *)&buf) *= privp->val[i].v8;
- break;
- case NG_PATCH_MODE_DIV:
- *((uint64_t *)&buf) /= privp->val[i].v8;
- break;
- case NG_PATCH_MODE_NEG:
- *((int64_t *)&buf) = - *((int64_t *)&buf);
- break;
- case NG_PATCH_MODE_AND:
- *((uint64_t *)&buf) &= privp->val[i].v8;
- break;
- case NG_PATCH_MODE_OR:
- *((uint64_t *)&buf) |= privp->val[i].v8;
+ if (privp->conf->ops[i].mode != NG_PATCH_MODE_SET)
+ m_copydata(m, offset, privp->conf->ops[i].length, (caddr_t) &val);
+
+ switch (privp->conf->ops[i].length)
+ {
+ case 1:
+ switch (privp->conf->ops[i].mode)
+ {
+ case NG_PATCH_MODE_SET:
+ val.v1 = privp->conf->ops[i].val.v1;
+ break;
+ case NG_PATCH_MODE_ADD:
+ val.v1 += privp->conf->ops[i].val.v1;
+ break;
+ case NG_PATCH_MODE_SUB:
+ val.v1 -= privp->conf->ops[i].val.v1;
+ break;
+ case NG_PATCH_MODE_MUL:
+ val.v1 *= privp->conf->ops[i].val.v1;
+ break;
+ case NG_PATCH_MODE_DIV:
+ val.v1 /= privp->conf->ops[i].val.v1;
+ break;
+ case NG_PATCH_MODE_NEG:
+ *((int8_t *) &val) = - *((int8_t *) &val);
+ break;
+ case NG_PATCH_MODE_AND:
+ val.v1 &= privp->conf->ops[i].val.v1;
+ break;
+ case NG_PATCH_MODE_OR:
+ val.v1 |= privp->conf->ops[i].val.v1;
+ break;
+ case NG_PATCH_MODE_XOR:
+ val.v1 ^= privp->conf->ops[i].val.v1;
+ break;
+ case NG_PATCH_MODE_SHL:
+ val.v1 <<= privp->conf->ops[i].val.v1;
+ break;
+ case NG_PATCH_MODE_SHR:
+ val.v1 >>= privp->conf->ops[i].val.v1;
+ break;
+ }
break;
- case NG_PATCH_MODE_XOR:
- *((uint64_t *)&buf) ^= privp->val[i].v8;
+
+ case 2:
+ val.v2 = ntohs(val.v2);
+
+ switch (privp->conf->ops[i].mode)
+ {
+ case NG_PATCH_MODE_SET:
+ val.v2 = privp->conf->ops[i].val.v2;
+ break;
+ case NG_PATCH_MODE_ADD:
+ val.v2 += privp->conf->ops[i].val.v2;
+ break;
+ case NG_PATCH_MODE_SUB:
+ val.v2 -= privp->conf->ops[i].val.v2;
+ break;
+ case NG_PATCH_MODE_MUL:
+ val.v2 *= privp->conf->ops[i].val.v2;
+ break;
+ case NG_PATCH_MODE_DIV:
+ val.v2 /= privp->conf->ops[i].val.v2;
+ break;
+ case NG_PATCH_MODE_NEG:
+ *((int16_t *) &val) = - *((int16_t *) &val);
+ break;
+ case NG_PATCH_MODE_AND:
+ val.v2 &= privp->conf->ops[i].val.v2;
+ break;
+ case NG_PATCH_MODE_OR:
+ val.v2 |= privp->conf->ops[i].val.v2;
+ break;
+ case NG_PATCH_MODE_XOR:
+ val.v2 ^= privp->conf->ops[i].val.v2;
+ break;
+ case NG_PATCH_MODE_SHL:
+ val.v2 <<= privp->conf->ops[i].val.v2;
+ break;
+ case NG_PATCH_MODE_SHR:
+ val.v2 >>= privp->conf->ops[i].val.v2;
+ break;
+ }
+
+ val.v2 = htons(val.v2);
+
break;
- case NG_PATCH_MODE_SHL:
- *((uint64_t *)&buf) <<= privp->val[i].v8;
+
+ case 4:
+ val.v4 = ntohl(val.v4);
+
+ switch (privp->conf->ops[i].mode)
+ {
+ case NG_PATCH_MODE_SET:
+ val.v4 = privp->conf->ops[i].val.v4;
+ break;
+ case NG_PATCH_MODE_ADD:
+ val.v4 += privp->conf->ops[i].val.v4;
+ break;
+ case NG_PATCH_MODE_SUB:
+ val.v4 -= privp->conf->ops[i].val.v4;
+ break;
+ case NG_PATCH_MODE_MUL:
+ val.v4 *= privp->conf->ops[i].val.v4;
+ break;
+ case NG_PATCH_MODE_DIV:
+ val.v4 /= privp->conf->ops[i].val.v4;
+ break;
+ case NG_PATCH_MODE_NEG:
+ *((int32_t *) &val) = - *((int32_t *) &val);
+ break;
+ case NG_PATCH_MODE_AND:
+ val.v4 &= privp->conf->ops[i].val.v4;
+ break;
+ case NG_PATCH_MODE_OR:
+ val.v4 |= privp->conf->ops[i].val.v4;
+ break;
+ case NG_PATCH_MODE_XOR:
+ val.v4 ^= privp->conf->ops[i].val.v4;
+ break;
+ case NG_PATCH_MODE_SHL:
+ val.v4 <<= privp->conf->ops[i].val.v4;
+ break;
+ case NG_PATCH_MODE_SHR:
+ val.v4 >>= privp->conf->ops[i].val.v4;
+ break;
+ }
+
+ val.v4 = htonl(val.v4);
+
break;
- case NG_PATCH_MODE_SHR:
- *((uint64_t *)&buf) >>= privp->val[i].v8;
+
+ case 8:
+ val.v8 = be64toh(val.v8);
+
+ switch (privp->conf->ops[i].mode)
+ {
+ case NG_PATCH_MODE_SET:
+ val.v8 = privp->conf->ops[i].val.v8;
+ break;
+ case NG_PATCH_MODE_ADD:
+ val.v8 += privp->conf->ops[i].val.v8;
+ break;
+ case NG_PATCH_MODE_SUB:
+ val.v8 -= privp->conf->ops[i].val.v8;
+ break;
+ case NG_PATCH_MODE_MUL:
+ val.v8 *= privp->conf->ops[i].val.v8;
+ break;
+ case NG_PATCH_MODE_DIV:
+ val.v8 /= privp->conf->ops[i].val.v8;
+ break;
+ case NG_PATCH_MODE_NEG:
+ *((int64_t *) &val) = - *((int64_t *) &val);
+ break;
+ case NG_PATCH_MODE_AND:
+ val.v8 &= privp->conf->ops[i].val.v8;
+ break;
+ case NG_PATCH_MODE_OR:
+ val.v8 |= privp->conf->ops[i].val.v8;
+ break;
+ case NG_PATCH_MODE_XOR:
+ val.v8 ^= privp->conf->ops[i].val.v8;
+ break;
+ case NG_PATCH_MODE_SHL:
+ val.v8 <<= privp->conf->ops[i].val.v8;
+ break;
+ case NG_PATCH_MODE_SHR:
+ val.v8 >>= privp->conf->ops[i].val.v8;
+ break;
+ }
+
+ val.v8 = htobe64(val.v8);
+
break;
- }
- *((int64_t *)&buf) = htobe64(*((int64_t *)&buf));
- break;
}
- m_copyback(m, conf->ops[i].offset, conf->ops[i].length,
- (caddr_t)&buf);
+ m_copyback(m, offset, privp->conf->ops[i].length, (caddr_t) &val);
patched = 1;
}
- if (patched > 0)
+
+ if (patched)
privp->stats.patched++;
}
@@ -506,41 +552,107 @@ ng_patch_rcvdata(hook_p hook, item_p item)
{
const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
struct mbuf *m;
- hook_p target;
- int error;
+ hook_p out;
+ int pullup_len = 0;
+ int error = 0;
priv->stats.received++;
+
NGI_GET_M(item, m);
- if (priv->config != NULL && hook == priv->in &&
- (m->m_flags & M_PKTHDR) != 0) {
- m = m_unshare(m,M_NOWAIT);
- if (m == NULL) {
- priv->stats.dropped++;
- NG_FREE_ITEM(item);
- return (ENOMEM);
+
+#define PULLUP_CHECK(mbuf, length) do { \
+ pullup_len += length; \
+ if (((mbuf)->m_pkthdr.len < pullup_len) || \
+ (pullup_len > MHLEN)) { \
+ error = EINVAL; \
+ goto bypass; \
+ } \
+ if ((mbuf)->m_len < pullup_len && \
+ (((mbuf) = m_pullup((mbuf), pullup_len)) == NULL)) { \
+ error = ENOBUFS; \
+ goto drop; \
+ } \
+} while (0)
+
+ if (priv->conf && hook == priv->in &&
+ m && (m->m_flags & M_PKTHDR)) {
+
+ m = m_unshare(m, M_NOWAIT);
+
+ if (m == NULL)
+ ERROUT(ENOMEM);
+
+ if (priv->conf->relative_offset) {
+ struct ether_header *eh;
+ struct ng_patch_vlan_header *vh;
+ uint16_t etype;
+
+ switch (priv->dlt)
+ {
+ case DLT_EN10MB:
+ PULLUP_CHECK(m, sizeof(struct ether_header));
+ eh = mtod(m, struct ether_header *);
+ etype = ntohs(eh->ether_type);
+
+ for (;;) { /* QinQ support */
+ switch (etype)
+ {
+ case 0x8100:
+ case 0x88A8:
+ case 0x9100:
+ PULLUP_CHECK(m, sizeof(struct ng_patch_vlan_header));
+ vh = (struct ng_patch_vlan_header *) mtodo(m,
+ pullup_len - sizeof(struct ng_patch_vlan_header));
+ etype = ntohs(vh->etype);
+ break;
+
+ default:
+ goto loopend;
+ }
+ }
+loopend:
+ break;
+
+ case DLT_RAW:
+ break;
+
+ default:
+ ERROUT(EINVAL);
+ }
}
- do_patch(priv, m);
- m->m_pkthdr.csum_flags |= priv->config->csum_flags;
+
+ do_patch(priv, m, pullup_len);
+
+ m->m_pkthdr.csum_flags |= priv->conf->csum_flags;
}
- target = NULL;
+#undef PULLUP_CHECK
+
+bypass:
+ out = NULL;
+
if (hook == priv->in) {
/* return frames on 'in' hook if 'out' not connected */
- if (priv->out != NULL)
- target = priv->out;
- else
- target = priv->in;
- }
- if (hook == priv->out && priv->in != NULL)
- target = priv->in;
-
- if (target == NULL) {
- priv->stats.dropped++;
- NG_FREE_ITEM(item);
- NG_FREE_M(m);
- return (0);
+ out = priv->out ? priv->out : priv->in;
+ } else if (hook == priv->out && priv->in) {
+ /* pass frames on 'out' hook if 'in' connected */
+ out = priv->in;
}
- NG_FWD_NEW_DATA(error, item, target, m);
+
+ if (out == NULL)
+ ERROUT(0);
+
+ NG_FWD_NEW_DATA(error, item, out, m);
+
+ return (error);
+
+done:
+drop:
+ NG_FREE_ITEM(item);
+ NG_FREE_M(m);
+
+ priv->stats.dropped++;
+
return (error);
}
@@ -549,13 +661,14 @@ ng_patch_shutdown(node_p node)
{
const priv_p privdata = NG_NODE_PRIVATE(node);
- if (privdata->val != NULL)
- free(privdata->val, M_NETGRAPH);
- if (privdata->config != NULL)
- free(privdata->config, M_NETGRAPH);
NG_NODE_SET_PRIVATE(node, NULL);
NG_NODE_UNREF(node);
+
+ if (privdata->conf != NULL)
+ free(privdata->conf, M_NETGRAPH);
+
free(privdata, M_NETGRAPH);
+
return (0);
}
@@ -565,15 +678,18 @@ ng_patch_disconnect(hook_p hook)
priv_p priv;
priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
+
if (hook == priv->in) {
priv->in = NULL;
}
+
if (hook == priv->out) {
priv->out = NULL;
}
+
if (NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0 &&
NG_NODE_IS_VALID(NG_HOOK_NODE(hook))) /* already shutting down? */
ng_rmnode_self(NG_HOOK_NODE(hook));
+
return (0);
}
-
diff --git a/sys/netgraph/ng_patch.h b/sys/netgraph/ng_patch.h
index 7bbe264..4dee92e 100644
--- a/sys/netgraph/ng_patch.h
+++ b/sys/netgraph/ng_patch.h
@@ -1,5 +1,6 @@
/*-
- * Copyright (C) 2010 by Maxim Ignatenko <gelraen.ua@gmail.com>
+ * Copyright (c) 2010 Maxim Ignatenko <gelraen.ua@gmail.com>
+ * Copyright (c) 2015 Dmitry Vagin <daemon.hammer@ya.ru>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -39,13 +40,19 @@
#define NG_PATCH_HOOK_IN "in"
#define NG_PATCH_HOOK_OUT "out"
+/* Checksum flags */
+#define NG_PATCH_CSUM_IPV4 (CSUM_IP|CSUM_TCP|CSUM_UDP|CSUM_SCTP)
+#define NG_PATCH_CSUM_IPV6 (CSUM_TCP_IPV6|CSUM_UDP_IPV6|CSUM_SCTP_IPV6)
+
/* Netgraph commands understood by this node type */
enum {
NGM_PATCH_SETCONFIG = 1,
NGM_PATCH_GETCONFIG,
NGM_PATCH_GET_STATS,
NGM_PATCH_CLR_STATS,
- NGM_PATCH_GETCLR_STATS
+ NGM_PATCH_GETCLR_STATS,
+ NGM_PATCH_GETDLT,
+ NGM_PATCH_SETDLT
};
/* Patching modes */
@@ -63,45 +70,64 @@ enum {
NG_PATCH_MODE_SHR = 11
};
-struct ng_patch_op {
- uint64_t value;
- uint32_t offset;
- uint16_t length; /* 1, 2, 4 or 8 (bytes) */
- uint16_t mode;
-};
+/* Parsing declarations */
-#define NG_PATCH_OP_TYPE_INFO { \
- { "value", &ng_parse_uint64_type }, \
+#define NG_PATCH_CONFIG_TYPE { \
+ { "count", &ng_parse_uint32_type }, \
+ { "csum_flags", &ng_parse_uint64_type }, \
+ { "relative_offset", &ng_parse_uint32_type }, \
+ { "ops", &ng_patch_ops_array_type }, \
+ { NULL } \
+}
+
+#define NG_PATCH_OP_TYPE { \
{ "offset", &ng_parse_uint32_type }, \
{ "length", &ng_parse_uint16_type }, \
{ "mode", &ng_parse_uint16_type }, \
+ { "value", &ng_parse_uint64_type }, \
+ { NULL } \
+}
+
+#define NG_PATCH_STATS_TYPE { \
+ { "Received", &ng_parse_uint64_type }, \
+ { "Patched", &ng_parse_uint64_type }, \
+ { "Dropped", &ng_parse_uint64_type }, \
{ NULL } \
}
+union ng_patch_op_val {
+ uint8_t v1;
+ uint16_t v2;
+ uint32_t v4;
+ uint64_t v8;
+};
+
+struct ng_patch_op {
+ uint32_t offset;
+ uint16_t length; /* 1, 2, 4 or 8 (bytes) */
+ uint16_t mode;
+ union ng_patch_op_val val;
+};
+
struct ng_patch_config {
uint32_t count;
- uint32_t csum_flags;
+ uint64_t csum_flags;
+ uint32_t relative_offset;
struct ng_patch_op ops[];
};
-#define NG_PATCH_CONFIG_TYPE_INFO { \
- { "count", &ng_parse_uint32_type }, \
- { "csum_flags", &ng_parse_uint64_type }, \
- { "ops", &ng_patch_ops_array_type }, \
- { NULL } \
-}
-
struct ng_patch_stats {
uint64_t received;
uint64_t patched;
uint64_t dropped;
};
-#define NG_PATCH_STATS_TYPE_INFO { \
- { "Received", &ng_parse_uint64_type }, \
- { "Patched", &ng_parse_uint64_type }, \
- { "Dropped", &ng_parse_uint64_type }, \
- { NULL } \
-}
+struct ng_patch_vlan_header {
+ u_int16_t tag;
+ u_int16_t etype;
+};
+
+#define NG_PATCH_CONF_SIZE(count) (sizeof(struct ng_patch_config) + \
+ (count) * sizeof(struct ng_patch_op))
#endif /* _NETGRAPH_NG_PATCH_H_ */
OpenPOWER on IntegriCloud