summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorae <ae@FreeBSD.org>2010-06-09 12:25:57 +0000
committerae <ae@FreeBSD.org>2010-06-09 12:25:57 +0000
commit7e4a5049a909e56f254c0d76a7f2cd789a3254f8 (patch)
tree2879e4bf20198fb81dbfc8b7d824548eee01a238 /sys
parent946bad94504213222b8c7a23425b35a0e20a26bd (diff)
downloadFreeBSD-src-7e4a5049a909e56f254c0d76a7f2cd789a3254f8.zip
FreeBSD-src-7e4a5049a909e56f254c0d76a7f2cd789a3254f8.tar.gz
New netgraph node ng_patch(4). It performs data modification of packets
passing through. Modifications are restricted to a subset of C language operations on unsigned integers of 8, 16, 32 or 64 bit size. These are: set to new value (=), addition (+=), subtraction (-=), multiplication (*=), division (/=), negation (= -), bitwise AND (&=), bitwise OR (|=), bitwise eXclusive OR (^=), shift left (<<=), shift right (>>=). Several operations are all applied to a packet sequentially in order they were specified by user. Submitted by: Maxim Ignatenko <gelraen.ua at gmail.com> Vadim Goncharov <vadimnuclight at tpu.ru> Discussed with: net@ Approved by: mav (mentor) MFC after: 1 month
Diffstat (limited to 'sys')
-rw-r--r--sys/conf/NOTES1
-rw-r--r--sys/conf/files1
-rw-r--r--sys/conf/options1
-rw-r--r--sys/modules/netgraph/Makefile1
-rw-r--r--sys/modules/netgraph/patch/Makefile6
-rw-r--r--sys/netgraph/ng_patch.c566
-rw-r--r--sys/netgraph/ng_patch.h107
7 files changed, 683 insertions, 0 deletions
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
index 6d12f99..8cad894 100644
--- a/sys/conf/NOTES
+++ b/sys/conf/NOTES
@@ -706,6 +706,7 @@ options NETGRAPH_MPPC_ENCRYPTION
options NETGRAPH_NETFLOW
options NETGRAPH_NAT
options NETGRAPH_ONE2MANY
+options NETGRAPG_PATCH
options NETGRAPH_PIPE
options NETGRAPH_PPP
options NETGRAPH_PPPOE
diff --git a/sys/conf/files b/sys/conf/files
index 12f5e4d..0808e7f 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -2470,6 +2470,7 @@ netgraph/ng_mppc.c optional netgraph_mppc_compression | \
netgraph/ng_nat.c optional netgraph_nat inet libalias
netgraph/ng_one2many.c optional netgraph_one2many
netgraph/ng_parse.c optional netgraph
+netgraph/ng_patch.c optional netgraph_patch
netgraph/ng_pipe.c optional netgraph_pipe
netgraph/ng_ppp.c optional netgraph_ppp
netgraph/ng_pppoe.c optional netgraph_pppoe
diff --git a/sys/conf/options b/sys/conf/options
index c58d901..9563cc8 100644
--- a/sys/conf/options
+++ b/sys/conf/options
@@ -486,6 +486,7 @@ NETGRAPH_MPPC_ENCRYPTION opt_netgraph.h
NETGRAPH_NAT opt_netgraph.h
NETGRAPH_NETFLOW opt_netgraph.h
NETGRAPH_ONE2MANY opt_netgraph.h
+NETGRAPH_PATCH opt_netgraph.h
NETGRAPH_PIPE opt_netgraph.h
NETGRAPH_PPP opt_netgraph.h
NETGRAPH_PPPOE opt_netgraph.h
diff --git a/sys/modules/netgraph/Makefile b/sys/modules/netgraph/Makefile
index 70861cb..dc44ac7 100644
--- a/sys/modules/netgraph/Makefile
+++ b/sys/modules/netgraph/Makefile
@@ -35,6 +35,7 @@ SUBDIR= async \
netflow \
netgraph \
one2many \
+ patch \
pipe \
ppp \
pppoe \
diff --git a/sys/modules/netgraph/patch/Makefile b/sys/modules/netgraph/patch/Makefile
new file mode 100644
index 0000000..b6c4741
--- /dev/null
+++ b/sys/modules/netgraph/patch/Makefile
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+KMOD= ng_patch
+SRCS= ng_patch.c
+
+.include <bsd.kmod.mk>
diff --git a/sys/netgraph/ng_patch.c b/sys/netgraph/ng_patch.c
new file mode 100644
index 0000000..6969851
--- /dev/null
+++ b/sys/netgraph/ng_patch.c
@@ -0,0 +1,566 @@
+/*-
+ * Copyright (C) 2010 by Maxim Ignatenko <gelraen.ua@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/ctype.h>
+#include <sys/errno.h>
+#include <sys/endian.h> /* be64toh(), htobe64() */
+#include <netgraph/ng_message.h>
+#include <netgraph/ng_parse.h>
+#include <netgraph/ng_patch.h>
+#include <netgraph/netgraph.h>
+
+static ng_constructor_t ng_patch_constructor;
+static ng_rcvmsg_t ng_patch_rcvmsg;
+static ng_shutdown_t ng_patch_shutdown;
+static ng_newhook_t ng_patch_newhook;
+static ng_rcvdata_t ng_patch_rcvdata;
+static ng_disconnect_t ng_patch_disconnect;
+
+#define OFFSETOF(s, e) ((char *)&((s *)0)->e - (char *)((s *)0))
+
+static int
+ng_patch_config_getlen(const struct ng_parse_type *type, const u_char *start,
+ const u_char *buf)
+{
+ const struct ng_patch_config *p;
+
+ p = (const struct ng_patch_config *)(buf -
+ OFFSETOF(struct ng_patch_config, ops));
+ return (p->count);
+}
+
+static const struct ng_parse_struct_field ng_patch_op_type_fields[]
+ = NG_PATCH_OP_TYPE_INFO;
+static const struct ng_parse_type ng_patch_op_type = {
+ &ng_parse_struct_type,
+ &ng_patch_op_type_fields
+};
+
+static const struct ng_parse_array_info ng_patch_confarr_info = {
+ &ng_patch_op_type,
+ &ng_patch_config_getlen
+};
+static const struct ng_parse_type ng_patch_confarr_type = {
+ &ng_parse_array_type,
+ &ng_patch_confarr_info
+};
+
+static const struct ng_parse_struct_field ng_patch_config_type_fields[]
+ = NG_PATCH_CONFIG_TYPE_INFO;
+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;
+static const struct ng_parse_type ng_patch_stats_type = {
+ &ng_parse_struct_type,
+ &ng_patch_stats_fields
+};
+
+static const struct ng_cmdlist ng_patch_cmdlist[] = {
+ {
+ NGM_PATCH_COOKIE,
+ NGM_PATCH_GETCONFIG,
+ "getconfig",
+ NULL,
+ &ng_patch_config_type
+ },
+ {
+ NGM_PATCH_COOKIE,
+ NGM_PATCH_SETCONFIG,
+ "setconfig",
+ &ng_patch_config_type,
+ NULL
+ },
+ {
+ NGM_PATCH_COOKIE,
+ NGM_PATCH_GET_STATS,
+ "getstats",
+ NULL,
+ &ng_patch_stats_type
+ },
+ {
+ NGM_PATCH_COOKIE,
+ NGM_PATCH_CLR_STATS,
+ "clrstats",
+ NULL,
+ NULL
+ },
+ {
+ NGM_PATCH_COOKIE,
+ NGM_PATCH_GETCLR_STATS,
+ "getclrstats",
+ NULL,
+ &ng_patch_stats_type
+ },
+ { 0 }
+};
+
+static struct ng_type typestruct = {
+ .version = NG_ABI_VERSION,
+ .name = NG_PATCH_NODE_TYPE,
+ .constructor = ng_patch_constructor,
+ .rcvmsg = ng_patch_rcvmsg,
+ .shutdown = ng_patch_shutdown,
+ .newhook = ng_patch_newhook,
+ .rcvdata = ng_patch_rcvdata,
+ .disconnect = ng_patch_disconnect,
+ .cmdlist = ng_patch_cmdlist,
+};
+NETGRAPH_INIT(patch, &typestruct);
+
+union patch_val {
+ uint8_t v1;
+ uint16_t v2;
+ uint32_t v4;
+ uint64_t v8;
+};
+
+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_WAIT | M_ZERO);
+ NG_NODE_SET_PRIVATE(node, privdata);
+ privdata->in = NULL;
+ privdata->out = NULL;
+ privdata->config = NULL;
+ return (0);
+}
+
+static int
+ng_patch_newhook(node_p node, hook_p hook, const char *name)
+{
+ const priv_p privp = NG_NODE_PRIVATE(node);
+
+ if (strncmp(name, NG_PATCH_HOOK_IN, strlen(NG_PATCH_HOOK_IN)) == 0) {
+ privp->in = hook;
+ } else if (strncmp(name, NG_PATCH_HOOK_OUT,
+ strlen(NG_PATCH_HOOK_OUT)) == 0) {
+ privp->out = hook;
+ } else
+ return (EINVAL);
+ return(0);
+}
+
+static int
+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;
+ struct ng_mesg *msg;
+ struct ng_mesg *resp = NULL;
+ int i, clear = 0;
+ int error = 0;
+
+ NGI_GET_MSG(item, msg);
+ switch (msg->header.typecookie) {
+ case NGM_PATCH_COOKIE:
+ switch (msg->header.cmd) {
+ case NGM_PATCH_GETCONFIG:
+ if (privp->config == NULL)
+ break;
+ NG_MKRESPONSE(resp, msg,
+ NG_PATCH_CONF_SIZE(privp->config->count), M_WAIT);
+ bcopy(privp->config, resp->data,
+ NG_PATCH_CONF_SIZE(privp->config->count));
+ break;
+ case NGM_PATCH_SETCONFIG:
+ {
+ struct ng_patch_config *newconf;
+ union patch_val *newval;
+
+ if (msg->header.arglen < sizeof(struct ng_patch_config)) {
+ error = EINVAL;
+ break;
+ }
+
+ conf = (struct ng_patch_config *)msg->data;
+ if (msg->header.arglen < NG_PATCH_CONF_SIZE(conf->count)) {
+ error = EINVAL;
+ break;
+ }
+
+ 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;
+ }
+ 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_WAIT);
+ newval = malloc(conf->count * sizeof(union patch_val),
+ M_NETGRAPH, M_WAIT);
+ for(i = 0; i < conf->count; i++) {
+ switch (conf->ops[i].length) {
+ case 1:
+ newval[i].v1 = conf->ops[i].value;
+ break;
+ case 2:
+ newval[i].v2 = conf->ops[i].value;
+ break;
+ case 4:
+ newval[i].v4 = conf->ops[i].value;
+ break;
+ case 8:
+ newval[i].v8 = conf->ops[i].value;
+ break;
+ }
+ }
+ 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;
+ }
+ break;
+ }
+ case NGM_PATCH_GETCLR_STATS:
+ clear = 1;
+ /* FALLTHROUGH */
+ case NGM_PATCH_GET_STATS:
+ NG_MKRESPONSE(resp, msg, sizeof(struct ng_patch_stats),
+ M_WAIT);
+ 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));
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ NG_RESPOND_MSG(error, node, item, resp);
+ NG_FREE_MSG(msg);
+ return(error);
+}
+
+static void
+do_patch(priv_p privp, struct mbuf *m)
+{
+ struct ng_patch_config *conf = privp->config;
+ uint64_t buf;
+ int i, patched = 0;
+
+ for(i = 0; i < conf->count; i++) {
+ if (conf->ops[i].offset + 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;
+ break;
+ case NG_PATCH_MODE_XOR:
+ *((uint64_t *)&buf) ^= privp->val[i].v8;
+ break;
+ case NG_PATCH_MODE_SHL:
+ *((uint64_t *)&buf) <<= privp->val[i].v8;
+ break;
+ case NG_PATCH_MODE_SHR:
+ *((uint64_t *)&buf) >>= privp->val[i].v8;
+ break;
+ }
+ *((int64_t *)&buf) = htobe64(*((int64_t *)&buf));
+ break;
+ }
+
+ m_copyback(m, conf->ops[i].offset, conf->ops[i].length,
+ (caddr_t)&buf);
+ patched = 1;
+ }
+ if (patched > 0)
+ privp->stats.patched++;
+}
+
+static int
+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;
+
+ 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);
+ }
+ do_patch(priv, m);
+ m->m_flags |= priv->config->csum_flags;
+ }
+
+ target = 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);
+ }
+ NG_FWD_NEW_DATA(error, item, target, m);
+ return (error);
+}
+
+static int
+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);
+ free(privdata, M_NETGRAPH);
+ return (0);
+}
+
+static int
+ng_patch_disconnect(hook_p hook)
+{
+ priv_p 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
new file mode 100644
index 0000000..fedde07
--- /dev/null
+++ b/sys/netgraph/ng_patch.h
@@ -0,0 +1,107 @@
+/*-
+ * Copyright (C) 2010 by Maxim Ignatenko <gelraen.ua@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _NETGRAPH_NG_PATCH_H_
+#define _NETGRAPH_NG_PATCH_H_
+
+/* Node type name. */
+#define NG_PATCH_NODE_TYPE "patch"
+
+/* Node type cookie. */
+#define NGM_PATCH_COOKIE 1262445509
+
+/* Hook names */
+#define NG_PATCH_HOOK_IN "in"
+#define NG_PATCH_HOOK_OUT "out"
+
+/* 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
+};
+
+/* Patching modes */
+enum {
+ NG_PATCH_MODE_SET = 1,
+ NG_PATCH_MODE_ADD = 2,
+ NG_PATCH_MODE_SUB = 3,
+ NG_PATCH_MODE_MUL = 4,
+ NG_PATCH_MODE_DIV = 5,
+ NG_PATCH_MODE_NEG = 6,
+ NG_PATCH_MODE_AND = 7,
+ NG_PATCH_MODE_OR = 8,
+ NG_PATCH_MODE_XOR = 9,
+ NG_PATCH_MODE_SHL = 10,
+ 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;
+};
+
+#define NG_PATCH_OP_TYPE_INFO { \
+ { "value", &ng_parse_uint64_type }, \
+ { "offset", &ng_parse_uint32_type }, \
+ { "length", &ng_parse_uint16_type }, \
+ { "mode", &ng_parse_uint16_type }, \
+ { NULL } \
+}
+
+struct ng_patch_config {
+ uint32_t count;
+ uint32_t csum_flags;
+ struct ng_patch_op ops[];
+};
+
+#define NG_PATCH_CONFIG_TYPE_INFO { \
+ { "count", &ng_parse_uint32_type }, \
+ { "csum_flags", &ng_parse_uint32_type }, \
+ { "ops", &ng_patch_confarr_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 } \
+}
+
+#endif /* _NETGRAPH_NG_PATCH_H_ */
OpenPOWER on IntegriCloud