Author: ae
Date: Wed Jun  9 12:25:57 2010
New Revision: 208946
URL: http://svn.freebsd.org/changeset/base/208946

Log:
  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

Added:
  head/share/man/man4/ng_patch.4   (contents, props changed)
  head/sys/modules/netgraph/patch/
  head/sys/modules/netgraph/patch/Makefile   (contents, props changed)
  head/sys/netgraph/ng_patch.c   (contents, props changed)
  head/sys/netgraph/ng_patch.h   (contents, props changed)
Modified:
  head/share/man/man4/Makefile
  head/sys/conf/NOTES
  head/sys/conf/files
  head/sys/conf/options
  head/sys/modules/netgraph/Makefile

Modified: head/share/man/man4/Makefile
==============================================================================
--- head/share/man/man4/Makefile        Wed Jun  9 12:06:08 2010        
(r208945)
+++ head/share/man/man4/Makefile        Wed Jun  9 12:25:57 2010        
(r208946)
@@ -274,6 +274,7 @@ MAN=        aac.4 \
        ng_nat.4 \
        ng_netflow.4 \
        ng_one2many.4 \
+       ng_patch.4 \
        ng_ppp.4 \
        ng_pppoe.4 \
        ng_pptpgre.4 \

Added: head/share/man/man4/ng_patch.4
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/share/man/man4/ng_patch.4      Wed Jun  9 12:25:57 2010        
(r208946)
@@ -0,0 +1,235 @@
+.\" Copyright (c) 2010 Maxim Ignatenko <gelraen...@gmail.com>
+.\" Copyright (c) 2010 Vadim Goncharov <vadimnucli...@tpu.ru>
+.\" 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$
+.\"
+.Dd June 9, 2010
+.Dt NG_PATCH 4
+.Os
+.Sh NAME
+.Nm ng_patch
+.Nd "trivial mbuf data modifying netgraph node type"
+.Sh SYNOPSIS
+.In netgraph/ng_patch.h
+.Sh DESCRIPTION
+The
+.Nm patch
+node performs data modification of packets passing through it.
+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 (>>=).
+A negation operation is the one exception: integer is treated as signed
+and second operand (the
+.Va value )
+is not used.
+There may be several modification operations, they are all applied
+to a packet sequentially in order they were specified by user.
+Data payload of packet is viewed as array of bytes, with zero offset
+corresponding to the very first byte of packet headers, and
+.Va length
+bytes beginning from
+.Va offset
+are taken as a single integer in network byte order.
+.Sh HOOKS
+This node type has two hooks:
+.Bl -tag -width indent
+.It Va in
+Packets received on this hook are modified according to rules specified
+in config and then forwarded to
+.Ar out
+hook, if it exists and connected.
+Otherwise they are reflected back to the
+.Ar in
+hook.
+.It Va out
+Packets received on this hook are forwarded to
+.Ar in
+hook without any changes.
+.El
+.Sh CONTROL MESSAGES
+This node type supports the generic control messages, plus the following:
+.Bl -tag -width indent
+.It Dv NGM_PATCH_SETCONFIG Pq Li setconfig
+This command sets the sequence of modify operations
+that will be applied to incoming data on a hook.
+The following
+.Vt "struct ng_patch_config"
+must be supplied as an argument:
+.Bd -literal -offset 4n
+struct ng_patch_op {
+       uint64_t        value;
+       uint32_t        offset;
+       uint16_t        length; /* 1,2,4 or 8 bytes */
+       uint16_t        mode;
+};
+/* Patching modes */
+#define NG_PATCH_MODE_SET      1
+#define NG_PATCH_MODE_ADD      2
+#define NG_PATCH_MODE_SUB      3
+#define NG_PATCH_MODE_MUL      4
+#define NG_PATCH_MODE_DIV      5
+#define NG_PATCH_MODE_NEG      6
+#define NG_PATCH_MODE_AND      7
+#define NG_PATCH_MODE_OR       8
+#define NG_PATCH_MODE_XOR      9
+#define NG_PATCH_MODE_SHL      10
+#define NG_PATCH_MODE_SHR      11
+
+struct ng_patch_config {
+       uint32_t        count;
+       uint32_t        csum_flags;
+       struct ng_patch_op ops[];
+};
+.Ed
+.Pp
+The
+.Va csum_flags
+can be set to any combination of CSUM_IP, CSUM_TCP, CSUM_SCTP and CSUM_UDP
+(other values are ignored) for instructing the IP stack to recalculate the
+corresponding checksum before transmitting packet on output interface.
+The
+.Nm
+node does not do any checksum correction by itself.
+.It Dv NGM_PATCH_GETCONFIG Pq Li getconfig
+This control message obtains current set of modify operations,
+returned as
+.Vt "struct ng_patch_config" .
+.It Dv NGM_PATCH_GET_STATS Pq Li getstats
+Returns node statistics as a
+.Vt "struct ng_patch_stats" .
+.It Dv NGM_PATCH_CLR_STATS Pq Li clrstats
+Clear node statistics.
+.It Dv NGM_PATCH_GETCLR_STATS Pq Li getclrstats
+This command is identical to
+.Dv NGM_PATCH_GET_STATS ,
+except that the statistics are also atomically cleared.
+.El
+.Sh SHUTDOWN
+This node shuts down upon receipt of a
+.Dv NGM_SHUTDOWN
+control message, or when all hooks have been disconnected.
+.Sh EXAMPLES
+The
+.Nm
+node allows to modify TTL and TOS/DSCP fields in IP packets.
+Suppose you have two adjacent simplex links to remote network
+(e.g.\& satellite), so that the packets expiring in between
+will generate unwanted ICMP-replies which have to go forth, not back.
+Thus you need to raise TTL of every packet entering link link by 2
+to ensure the TTL will not reach zero there.
+So you setup
+.Xr ipfw 8
+rule with
+.Cm netgraph
+action to inject packets going to other end of simplex link by the
+following
+.Xr ngctl 8
+script:
+.Bd -literal -offset 4n
+/usr/sbin/ngctl -f- <<-SEQ
+       mkpeer ipfw: patch 200 in
+       name ipfw:200 ttl_add
+       msg ttl_add: setconfig { count=1 csum_flags=1 ops=[     \e
+               { mode=2 value=3 length=1 offset=8 } ] }
+SEQ
+/sbin/ipfw add 150 netgraph 200 ip from any to simplex.remote.net
+.Ed
+.Pp
+Here
+.Dq Li ttl_add
+node of type
+.Nm
+configured to add (mode 
+.Dv NG_PATCH_MODE_ADD )
+a
+.Va value
+of 3 to a one-byte TTL field, which is 9th byte of IP packet header.
+.Pp
+Another example would be two consecutive modifications of packet TOS
+field: say, you need to clear the
+.Dv IPTOS_THROUGHPUT
+bit and set the
+.Dv IPTOS_MINCOST
+bit.
+So you do:
+.Bd -literal -offset 4n
+/usr/sbin/ngctl -f- <<-SEQ
+       mkpeer ipfw: patch 300 in
+       name ipfw:300 tos_chg
+       msg tos_chg: setconfig { count=2 csum_flags=1 ops=[     \e
+               { mode=7 value=0xf7 length=1 offset=1 }         \e
+               { mode=8 value=0x02 length=1 offset=1 } ] }
+SEQ
+/sbin/ipfw add 160 netgraph 600 ip from any to any not dst-port 80
+.Ed
+.Pp
+This first does
+.Dv NG_PATCH_MODE_AND
+clearing the fourth bit and then
+.Dv NG_PATCH_MODE_OR
+setting the third bit.
+.Pp
+In both examples the
+.Va csum_flags
+field indicates that IP checksum (but not TCP or UDP checksum) should be
+recalculated before transmit.
+.Pp
+Note: one should ensure that packets are returned to ipfw after processing
+inside
+.Xr netgraph 4 ,
+by setting appropriate
+.Xr sysctl 8
+variable:
+.Bd -literal -offset 4n
+sysctl net.inet.ip.fw.one_pass=0
+.Ed
+.Sh SEE ALSO
+.Xr netgraph 4 ,
+.Xr ng_ipfw 4 ,
+.Xr ngctl 8
+.Sh HISTORY
+The
+.Nm
+node type was implemented in
+.Fx 8.1 .
+.Sh AUTHORS
+.An "Maxim Ignatenko" Aq gelraen...@gmail.com .
+This manual page was written by
+.An "Vadim Goncharov" Aq vadimnucli...@tpu.ru .
+.Sh BUGS
+Node blindly tries to apply every patching operation to each packet
+(except those which offset if greater than length of the packet),
+so be sure that you supply only the right packets to it (e.g. changing
+bytes in the ARP packets meant to be in IP header could corrupt
+them and make your machine unreachable from the network).
+.Pp
+.Em !!! WARNING !!!
+.Pp
+Output path of the IP stack assumes correct fields and lengths in the
+packets - changing them by mistake to incorrect values can cause
+unpredictable results including kernel panics.

Modified: head/sys/conf/NOTES
==============================================================================
--- head/sys/conf/NOTES Wed Jun  9 12:06:08 2010        (r208945)
+++ head/sys/conf/NOTES Wed Jun  9 12:25:57 2010        (r208946)
@@ -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

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files Wed Jun  9 12:06:08 2010        (r208945)
+++ head/sys/conf/files Wed Jun  9 12:25:57 2010        (r208946)
@@ -2470,6 +2470,7 @@ netgraph/ng_mppc.c                optional netgraph_mp
 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

Modified: head/sys/conf/options
==============================================================================
--- head/sys/conf/options       Wed Jun  9 12:06:08 2010        (r208945)
+++ head/sys/conf/options       Wed Jun  9 12:25:57 2010        (r208946)
@@ -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

Modified: head/sys/modules/netgraph/Makefile
==============================================================================
--- head/sys/modules/netgraph/Makefile  Wed Jun  9 12:06:08 2010        
(r208945)
+++ head/sys/modules/netgraph/Makefile  Wed Jun  9 12:25:57 2010        
(r208946)
@@ -35,6 +35,7 @@ SUBDIR=       async \
        netflow \
        netgraph \
        one2many \
+       patch \
        pipe \
        ppp \
        pppoe \

Added: head/sys/modules/netgraph/patch/Makefile
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/modules/netgraph/patch/Makefile    Wed Jun  9 12:25:57 2010        
(r208946)
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+KMOD=  ng_patch
+SRCS=  ng_patch.c
+
+.include <bsd.kmod.mk>

Added: head/sys/netgraph/ng_patch.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/netgraph/ng_patch.c        Wed Jun  9 12:25:57 2010        
(r208946)
@@ -0,0 +1,566 @@
+/*-
+ * Copyright (C) 2010 by Maxim Ignatenko <gelraen...@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);
+}
+

Added: head/sys/netgraph/ng_patch.h
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/netgraph/ng_patch.h        Wed Jun  9 12:25:57 2010        
(r208946)
@@ -0,0 +1,107 @@
+/*-
+ * Copyright (C) 2010 by Maxim Ignatenko <gelraen...@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_ */
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to