Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next
authorDavid S. Miller <davem@davemloft.net>
Tue, 14 Apr 2015 22:51:19 +0000 (18:51 -0400)
committerDavid S. Miller <davem@davemloft.net>
Tue, 14 Apr 2015 22:51:19 +0000 (18:51 -0400)
Pablo Neira Ayuso says:

====================
Netfilter updates for net-next

A final pull request, I know it's very late but this time I think it's worth a
bit of rush.

The following patchset contains Netfilter/nf_tables updates for net-next, more
specifically concatenation support and dynamic stateful expression
instantiation.

This also comes with a couple of small patches. One to fix the ebtables.h
userspace header and another to get rid of an obsolete example file in tree
that describes a nf_tables expression.

This time, I decided to paste the original descriptions. This will result in a
rather large commit description, but I think these bytes to keep.

Patrick McHardy says:

====================
netfilter: nf_tables: concatenation support

The following patches add support for concatenations, which allow multi
dimensional exact matches in O(1).

The basic idea is to split the data registers, currently consisting of
4 registers of 16 bytes each, into smaller units, 16 registers of 4
bytes each, and making sure each register store always leaves the
full 32 bit in a well defined state, meaning smaller stores will
zero the remaining bits.

Based on that, we can load multiple adjacent registers with different
values, thereby building a concatenated bigger value, and use that
value for set lookups.

Sets are changed to use variable sized extensions for their key and
data values, removing the fixed limit of 16 bytes while saving memory
if less space is needed.

As a side effect, these patches will allow some nice optimizations in
the future, like using jhash2 in nft_hash, removing the masking in
nft_cmp_fast, optimized data comparison using 32 bit word size etc.
These are not done so far however.

The patches are split up as follows:

 * the first five patches add length validation to register loads and
   stores to make sure we stay within bounds and prepare the validation
   functions for the new addressing mode

 * the next patches prepare for changing to 32 bit addressing by
   introducing a struct nft_regs, which holds the verdict register as
   well as the data registers. The verdict members are moved to a new
   struct nft_verdict to allow to pull struct nft_data out of the stack.

 * the next patches contain preparatory conversions of expressions and
   sets to use 32 bit addressing

 * the next patch introduces so far unused register conversion helpers
   for parsing and dumping register numbers over netlink

 * following is the real conversion to 32 bit addressing, consisting of
   replacing struct nft_data in struct nft_regs by an array of u32s and
   actually translating and validating the new register numbers.

 * the final two patches add support for variable sized data items and
   variable sized keys / data in set elements

The patches have been verified to work correctly with nft binaries using
both old and new addressing.
====================

Patrick McHardy says:

====================
netfilter: nf_tables: dynamic stateful expression instantiation

The following patches are the grand finale of my nf_tables set work,
using all the building blocks put in place by the previous patches
to support something like iptables hashlimit, but a lot more powerful.

Sets are extended to allow attaching expressions to set elements.
The dynset expression dynamically instantiates these expressions
based on a template when creating new set elements and evaluates
them for all new or updated set members.

In combination with concatenations this effectively creates state
tables for arbitrary combinations of keys, using the existing
expression types to maintain that state. Regular set GC takes care
of purging expired states.

We currently support two different stateful expressions, counter
and limit. Using limit as a template we can express the functionality
of hashlimit, but completely unrestricted in the combination of keys.
Using counter we can perform accounting for arbitrary flows.

The following examples from patch 5/5 show some possibilities.
Userspace syntax is still WIP, especially the listing of state
tables will most likely be seperated from normal set listings
and use a more structured format:

1. Limit the rate of new SSH connections per host, similar to iptables
   hashlimit:

        flow ip saddr timeout 60s \
        limit 10/second \
        accept

2. Account network traffic between each set of /24 networks:

        flow ip saddr & 255.255.255.0 . ip daddr & 255.255.255.0 \
        counter

3. Account traffic to each host per user:

        flow skuid . ip daddr \
        counter

4. Account traffic for each combination of source address and TCP flags:

        flow ip saddr . tcp flags \
        counter

The resulting set content after a Xmas-scan look like this:

{
        192.168.122.1 . fin | psh | urg : counter packets 1001 bytes 40040,
        192.168.122.1 . ack : counter packets 74 bytes 3848,
        192.168.122.1 . psh | ack : counter packets 35 bytes 3144
}

In the future the "expressions attached to elements" will be extended
to also support user created non-stateful expressions to allow to
efficiently select beween a set of parameter sets, f.i. a set of log
statements with different prefixes based on the interface, which currently
require one rule each. This will most likely have to wait until the next
kernel version though.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
36 files changed:
include/linux/netfilter_bridge/ebtables.h
include/net/netfilter/nf_tables.h
include/net/netfilter/nft_meta.h
include/uapi/linux/netfilter/nf_tables.h
include/uapi/linux/netfilter_bridge/ebtables.h
net/bridge/netfilter/nft_meta_bridge.c
net/bridge/netfilter/nft_reject_bridge.c
net/ipv4/netfilter/nft_masq_ipv4.c
net/ipv4/netfilter/nft_redir_ipv4.c
net/ipv4/netfilter/nft_reject_ipv4.c
net/ipv6/netfilter/nft_masq_ipv6.c
net/ipv6/netfilter/nft_redir_ipv6.c
net/ipv6/netfilter/nft_reject_ipv6.c
net/netfilter/nf_tables_api.c
net/netfilter/nf_tables_core.c
net/netfilter/nft_bitwise.c
net/netfilter/nft_byteorder.c
net/netfilter/nft_cmp.c
net/netfilter/nft_compat.c
net/netfilter/nft_counter.c
net/netfilter/nft_ct.c
net/netfilter/nft_dynset.c
net/netfilter/nft_expr_template.c [deleted file]
net/netfilter/nft_exthdr.c
net/netfilter/nft_hash.c
net/netfilter/nft_immediate.c
net/netfilter/nft_limit.c
net/netfilter/nft_log.c
net/netfilter/nft_lookup.c
net/netfilter/nft_meta.c
net/netfilter/nft_nat.c
net/netfilter/nft_payload.c
net/netfilter/nft_queue.c
net/netfilter/nft_rbtree.c
net/netfilter/nft_redir.c
net/netfilter/nft_reject_inet.c

index 34e7a2b7f8677f9f923fd48a366e09e5d4d643ee..f1bd3962e6b6d2388ff611da201bf87584f7d5b2 100644 (file)
 #ifndef __LINUX_BRIDGE_EFF_H
 #define __LINUX_BRIDGE_EFF_H
 
+#include <linux/if.h>
+#include <linux/if_ether.h>
 #include <uapi/linux/netfilter_bridge/ebtables.h>
 
-
 /* return values for match() functions */
 #define EBT_MATCH 0
 #define EBT_NOMATCH 1
index d6a2f0ed5130582d0489bc372e3b7e033f5267e8..e6bcf55dcf2008b83a8a40896fcce2e011653e1b 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _NET_NF_TABLES_H
 #define _NET_NF_TABLES_H
 
+#include <linux/module.h>
 #include <linux/list.h>
 #include <linux/netfilter.h>
 #include <linux/netfilter/nfnetlink.h>
@@ -36,29 +37,43 @@ static inline void nft_set_pktinfo(struct nft_pktinfo *pkt,
        pkt->xt.family = ops->pf;
 }
 
+/**
+ *     struct nft_verdict - nf_tables verdict
+ *
+ *     @code: nf_tables/netfilter verdict code
+ *     @chain: destination chain for NFT_JUMP/NFT_GOTO
+ */
+struct nft_verdict {
+       u32                             code;
+       struct nft_chain                *chain;
+};
+
 struct nft_data {
        union {
-               u32                             data[4];
-               struct {
-                       u32                     verdict;
-                       struct nft_chain        *chain;
-               };
+               u32                     data[4];
+               struct nft_verdict      verdict;
        };
 } __attribute__((aligned(__alignof__(u64))));
 
-static inline int nft_data_cmp(const struct nft_data *d1,
-                              const struct nft_data *d2,
-                              unsigned int len)
-{
-       return memcmp(d1->data, d2->data, len);
-}
+/**
+ *     struct nft_regs - nf_tables register set
+ *
+ *     @data: data registers
+ *     @verdict: verdict register
+ *
+ *     The first four data registers alias to the verdict register.
+ */
+struct nft_regs {
+       union {
+               u32                     data[20];
+               struct nft_verdict      verdict;
+       };
+};
 
-static inline void nft_data_copy(struct nft_data *dst,
-                                const struct nft_data *src)
+static inline void nft_data_copy(u32 *dst, const struct nft_data *src,
+                                unsigned int len)
 {
-       BUILD_BUG_ON(__alignof__(*dst) != __alignof__(u64));
-       *(u64 *)&dst->data[0] = *(u64 *)&src->data[0];
-       *(u64 *)&dst->data[2] = *(u64 *)&src->data[2];
+       memcpy(dst, src, len);
 }
 
 static inline void nft_data_debug(const struct nft_data *data)
@@ -96,7 +111,8 @@ struct nft_data_desc {
        unsigned int                    len;
 };
 
-int nft_data_init(const struct nft_ctx *ctx, struct nft_data *data,
+int nft_data_init(const struct nft_ctx *ctx,
+                 struct nft_data *data, unsigned int size,
                  struct nft_data_desc *desc, const struct nlattr *nla);
 void nft_data_uninit(const struct nft_data *data, enum nft_data_types type);
 int nft_data_dump(struct sk_buff *skb, int attr, const struct nft_data *data,
@@ -112,12 +128,14 @@ static inline enum nft_registers nft_type_to_reg(enum nft_data_types type)
        return type == NFT_DATA_VERDICT ? NFT_REG_VERDICT : NFT_REG_1;
 }
 
-int nft_validate_input_register(enum nft_registers reg);
-int nft_validate_output_register(enum nft_registers reg);
-int nft_validate_data_load(const struct nft_ctx *ctx, enum nft_registers reg,
-                          const struct nft_data *data,
-                          enum nft_data_types type);
+unsigned int nft_parse_register(const struct nlattr *attr);
+int nft_dump_register(struct sk_buff *skb, unsigned int attr, unsigned int reg);
 
+int nft_validate_register_load(enum nft_registers reg, unsigned int len);
+int nft_validate_register_store(const struct nft_ctx *ctx,
+                               enum nft_registers reg,
+                               const struct nft_data *data,
+                               enum nft_data_types type, unsigned int len);
 
 /**
  *     struct nft_userdata - user defined data associated with an object
@@ -141,7 +159,10 @@ struct nft_userdata {
  *     @priv: element private data and extensions
  */
 struct nft_set_elem {
-       struct nft_data         key;
+       union {
+               u32             buf[NFT_DATA_VALUE_MAXLEN / sizeof(u32)];
+               struct nft_data val;
+       } key;
        void                    *priv;
 };
 
@@ -216,15 +237,15 @@ struct nft_expr;
  */
 struct nft_set_ops {
        bool                            (*lookup)(const struct nft_set *set,
-                                                 const struct nft_data *key,
+                                                 const u32 *key,
                                                  const struct nft_set_ext **ext);
        bool                            (*update)(struct nft_set *set,
-                                                 const struct nft_data *key,
+                                                 const u32 *key,
                                                  void *(*new)(struct nft_set *,
                                                               const struct nft_expr *,
-                                                              struct nft_data []),
+                                                              struct nft_regs *),
                                                  const struct nft_expr *expr,
-                                                 struct nft_data data[],
+                                                 struct nft_regs *regs,
                                                  const struct nft_set_ext **ext);
 
        int                             (*insert)(const struct nft_set *set,
@@ -350,6 +371,7 @@ void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
  *     @NFT_SET_EXT_TIMEOUT: element timeout
  *     @NFT_SET_EXT_EXPIRATION: element expiration time
  *     @NFT_SET_EXT_USERDATA: user data associated with the element
+ *     @NFT_SET_EXT_EXPR: expression assiociated with the element
  *     @NFT_SET_EXT_NUM: number of extension types
  */
 enum nft_set_extensions {
@@ -359,6 +381,7 @@ enum nft_set_extensions {
        NFT_SET_EXT_TIMEOUT,
        NFT_SET_EXT_EXPIRATION,
        NFT_SET_EXT_USERDATA,
+       NFT_SET_EXT_EXPR,
        NFT_SET_EXT_NUM
 };
 
@@ -470,6 +493,11 @@ static inline struct nft_userdata *nft_set_ext_userdata(const struct nft_set_ext
        return nft_set_ext(ext, NFT_SET_EXT_USERDATA);
 }
 
+static inline struct nft_expr *nft_set_ext_expr(const struct nft_set_ext *ext)
+{
+       return nft_set_ext(ext, NFT_SET_EXT_EXPR);
+}
+
 static inline bool nft_set_elem_expired(const struct nft_set_ext *ext)
 {
        return nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION) &&
@@ -484,8 +512,7 @@ static inline struct nft_set_ext *nft_set_elem_ext(const struct nft_set *set,
 
 void *nft_set_elem_init(const struct nft_set *set,
                        const struct nft_set_ext_tmpl *tmpl,
-                       const struct nft_data *key,
-                       const struct nft_data *data,
+                       const u32 *key, const u32 *data,
                        u64 timeout, gfp_t gfp);
 void nft_set_elem_destroy(const struct nft_set *set, void *elem);
 
@@ -556,6 +583,7 @@ static inline void nft_set_gc_batch_add(struct nft_set_gc_batch *gcb,
  *     @policy: netlink attribute policy
  *     @maxattr: highest netlink attribute number
  *     @family: address family for AF-specific types
+ *     @flags: expression type flags
  */
 struct nft_expr_type {
        const struct nft_expr_ops       *(*select_ops)(const struct nft_ctx *,
@@ -567,8 +595,11 @@ struct nft_expr_type {
        const struct nla_policy         *policy;
        unsigned int                    maxattr;
        u8                              family;
+       u8                              flags;
 };
 
+#define NFT_EXPR_STATEFUL              0x1
+
 /**
  *     struct nft_expr_ops - nf_tables expression operations
  *
@@ -584,7 +615,7 @@ struct nft_expr_type {
 struct nft_expr;
 struct nft_expr_ops {
        void                            (*eval)(const struct nft_expr *expr,
-                                               struct nft_data data[NFT_REG_MAX + 1],
+                                               struct nft_regs *regs,
                                                const struct nft_pktinfo *pkt);
        unsigned int                    size;
 
@@ -622,6 +653,18 @@ static inline void *nft_expr_priv(const struct nft_expr *expr)
        return (void *)expr->data;
 }
 
+struct nft_expr *nft_expr_init(const struct nft_ctx *ctx,
+                              const struct nlattr *nla);
+void nft_expr_destroy(const struct nft_ctx *ctx, struct nft_expr *expr);
+int nft_expr_dump(struct sk_buff *skb, unsigned int attr,
+                 const struct nft_expr *expr);
+
+static inline void nft_expr_clone(struct nft_expr *dst, struct nft_expr *src)
+{
+       __module_get(src->ops->type->owner);
+       memcpy(dst, src, src->ops->size);
+}
+
 /**
  *     struct nft_rule - nf_tables rule
  *
index 0ee47c3e2e31c1279ca2435a05281db238e39713..711887a09e9189e5c85e34d4f7608a37c600a097 100644 (file)
@@ -26,11 +26,11 @@ int nft_meta_set_dump(struct sk_buff *skb,
                      const struct nft_expr *expr);
 
 void nft_meta_get_eval(const struct nft_expr *expr,
-                      struct nft_data data[NFT_REG_MAX + 1],
+                      struct nft_regs *regs,
                       const struct nft_pktinfo *pkt);
 
 void nft_meta_set_eval(const struct nft_expr *expr,
-                      struct nft_data data[NFT_REG_MAX + 1],
+                      struct nft_regs *regs,
                       const struct nft_pktinfo *pkt);
 
 #endif
index 05ee1e0804a3f2c8971c1956dc768c416e4cec71..5fa1cd04762e47ac1a1a60d95ed889c6b8afe2a8 100644 (file)
@@ -5,16 +5,45 @@
 #define NFT_CHAIN_MAXNAMELEN   32
 #define NFT_USERDATA_MAXLEN    256
 
+/**
+ * enum nft_registers - nf_tables registers
+ *
+ * nf_tables used to have five registers: a verdict register and four data
+ * registers of size 16. The data registers have been changed to 16 registers
+ * of size 4. For compatibility reasons, the NFT_REG_[1-4] registers still
+ * map to areas of size 16, the 4 byte registers are addressed using
+ * NFT_REG32_00 - NFT_REG32_15.
+ */
 enum nft_registers {
        NFT_REG_VERDICT,
        NFT_REG_1,
        NFT_REG_2,
        NFT_REG_3,
        NFT_REG_4,
-       __NFT_REG_MAX
+       __NFT_REG_MAX,
+
+       NFT_REG32_00    = 8,
+       MFT_REG32_01,
+       NFT_REG32_02,
+       NFT_REG32_03,
+       NFT_REG32_04,
+       NFT_REG32_05,
+       NFT_REG32_06,
+       NFT_REG32_07,
+       NFT_REG32_08,
+       NFT_REG32_09,
+       NFT_REG32_10,
+       NFT_REG32_11,
+       NFT_REG32_12,
+       NFT_REG32_13,
+       NFT_REG32_14,
+       NFT_REG32_15,
 };
 #define NFT_REG_MAX    (__NFT_REG_MAX - 1)
 
+#define NFT_REG_SIZE   16
+#define NFT_REG32_SIZE 4
+
 /**
  * enum nft_verdicts - nf_tables internal verdicts
  *
@@ -209,6 +238,7 @@ enum nft_rule_compat_attributes {
  * @NFT_SET_INTERVAL: set contains intervals
  * @NFT_SET_MAP: set is used as a dictionary
  * @NFT_SET_TIMEOUT: set uses timeouts
+ * @NFT_SET_EVAL: set contains expressions for evaluation
  */
 enum nft_set_flags {
        NFT_SET_ANONYMOUS               = 0x1,
@@ -216,6 +246,7 @@ enum nft_set_flags {
        NFT_SET_INTERVAL                = 0x4,
        NFT_SET_MAP                     = 0x8,
        NFT_SET_TIMEOUT                 = 0x10,
+       NFT_SET_EVAL                    = 0x20,
 };
 
 /**
@@ -293,6 +324,7 @@ enum nft_set_elem_flags {
  * @NFTA_SET_ELEM_TIMEOUT: timeout value (NLA_U64)
  * @NFTA_SET_ELEM_EXPIRATION: expiration time (NLA_U64)
  * @NFTA_SET_ELEM_USERDATA: user data (NLA_BINARY)
+ * @NFTA_SET_ELEM_EXPR: expression (NLA_NESTED: nft_expr_attributes)
  */
 enum nft_set_elem_attributes {
        NFTA_SET_ELEM_UNSPEC,
@@ -302,6 +334,7 @@ enum nft_set_elem_attributes {
        NFTA_SET_ELEM_TIMEOUT,
        NFTA_SET_ELEM_EXPIRATION,
        NFTA_SET_ELEM_USERDATA,
+       NFTA_SET_ELEM_EXPR,
        __NFTA_SET_ELEM_MAX
 };
 #define NFTA_SET_ELEM_MAX      (__NFTA_SET_ELEM_MAX - 1)
@@ -359,6 +392,9 @@ enum nft_data_attributes {
 };
 #define NFTA_DATA_MAX          (__NFTA_DATA_MAX - 1)
 
+/* Maximum length of a value */
+#define NFT_DATA_VALUE_MAXLEN  64
+
 /**
  * enum nft_verdict_attributes - nf_tables verdict netlink attributes
  *
@@ -531,6 +567,7 @@ enum nft_dynset_ops {
  * @NFTA_DYNSET_SREG_KEY: source register of the key (NLA_U32)
  * @NFTA_DYNSET_SREG_DATA: source register of the data (NLA_U32)
  * @NFTA_DYNSET_TIMEOUT: timeout value for the new element (NLA_U64)
+ * @NFTA_DYNSET_EXPR: expression (NLA_NESTED: nft_expr_attributes)
  */
 enum nft_dynset_attributes {
        NFTA_DYNSET_UNSPEC,
@@ -540,6 +577,7 @@ enum nft_dynset_attributes {
        NFTA_DYNSET_SREG_KEY,
        NFTA_DYNSET_SREG_DATA,
        NFTA_DYNSET_TIMEOUT,
+       NFTA_DYNSET_EXPR,
        __NFTA_DYNSET_MAX,
 };
 #define NFTA_DYNSET_MAX                (__NFTA_DYNSET_MAX - 1)
index ba993360dbe908cf08faf81956e2ef23dd68a4af..773dfe8924c7e76a0411e08247663203a69e5306 100644 (file)
@@ -12,9 +12,7 @@
 
 #ifndef _UAPI__LINUX_BRIDGE_EFF_H
 #define _UAPI__LINUX_BRIDGE_EFF_H
-#include <linux/if.h>
 #include <linux/netfilter_bridge.h>
-#include <linux/if_ether.h>
 
 #define EBT_TABLE_MAXNAMELEN 32
 #define EBT_CHAIN_MAXNAMELEN EBT_TABLE_MAXNAMELEN
index 4f02109d708f811bd49f79b08adab4979692130a..a21269b83f16eaf76f73368dc057f9301c403028 100644 (file)
 #include "../br_private.h"
 
 static void nft_meta_bridge_get_eval(const struct nft_expr *expr,
-                                    struct nft_data data[NFT_REG_MAX + 1],
+                                    struct nft_regs *regs,
                                     const struct nft_pktinfo *pkt)
 {
        const struct nft_meta *priv = nft_expr_priv(expr);
        const struct net_device *in = pkt->in, *out = pkt->out;
-       struct nft_data *dest = &data[priv->dreg];
+       u32 *dest = &regs->data[priv->dreg];
        const struct net_bridge_port *p;
 
        switch (priv->key) {
@@ -40,12 +40,12 @@ static void nft_meta_bridge_get_eval(const struct nft_expr *expr,
                goto out;
        }
 
-       strncpy((char *)dest->data, p->br->dev->name, sizeof(dest->data));
+       strncpy((char *)dest, p->br->dev->name, IFNAMSIZ);
        return;
 out:
-       return nft_meta_get_eval(expr, data, pkt);
+       return nft_meta_get_eval(expr, regs, pkt);
 err:
-       data[NFT_REG_VERDICT].verdict = NFT_BREAK;
+       regs->verdict.code = NFT_BREAK;
 }
 
 static int nft_meta_bridge_get_init(const struct nft_ctx *ctx,
@@ -53,27 +53,21 @@ static int nft_meta_bridge_get_init(const struct nft_ctx *ctx,
                                    const struct nlattr * const tb[])
 {
        struct nft_meta *priv = nft_expr_priv(expr);
-       int err;
+       unsigned int len;
 
        priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
        switch (priv->key) {
        case NFT_META_BRI_IIFNAME:
        case NFT_META_BRI_OIFNAME:
+               len = IFNAMSIZ;
                break;
        default:
                return nft_meta_get_init(ctx, expr, tb);
        }
 
-       priv->dreg = ntohl(nla_get_be32(tb[NFTA_META_DREG]));
-       err = nft_validate_output_register(priv->dreg);
-       if (err < 0)
-               return err;
-
-       err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
-       if (err < 0)
-               return err;
-
-       return 0;
+       priv->dreg = nft_parse_register(tb[NFTA_META_DREG]);
+       return nft_validate_register_store(ctx, priv->dreg, NULL,
+                                          NFT_DATA_VALUE, len);
 }
 
 static struct nft_expr_type nft_meta_bridge_type;
index ae8141f409d9dc24d60d603133cc463e2564f895..858d848564ee93a4fa51534a8db512652e93c792 100644 (file)
@@ -257,8 +257,8 @@ static void nft_reject_br_send_v6_unreach(struct net *net,
 }
 
 static void nft_reject_bridge_eval(const struct nft_expr *expr,
-                                struct nft_data data[NFT_REG_MAX + 1],
-                                const struct nft_pktinfo *pkt)
+                                  struct nft_regs *regs,
+                                  const struct nft_pktinfo *pkt)
 {
        struct nft_reject *priv = nft_expr_priv(expr);
        struct net *net = dev_net((pkt->in != NULL) ? pkt->in : pkt->out);
@@ -310,7 +310,7 @@ static void nft_reject_bridge_eval(const struct nft_expr *expr,
                break;
        }
 out:
-       data[NFT_REG_VERDICT].verdict = NF_DROP;
+       regs->verdict.code = NF_DROP;
 }
 
 static int nft_reject_bridge_validate(const struct nft_ctx *ctx,
index 665de06561cd51e0933aa8436438b499d3c5066c..40e414c4ca56b49909fcde487dead284e5463990 100644 (file)
 #include <net/netfilter/ipv4/nf_nat_masquerade.h>
 
 static void nft_masq_ipv4_eval(const struct nft_expr *expr,
-                              struct nft_data data[NFT_REG_MAX + 1],
+                              struct nft_regs *regs,
                               const struct nft_pktinfo *pkt)
 {
        struct nft_masq *priv = nft_expr_priv(expr);
        struct nf_nat_range range;
-       unsigned int verdict;
 
        memset(&range, 0, sizeof(range));
        range.flags = priv->flags;
 
-       verdict = nf_nat_masquerade_ipv4(pkt->skb, pkt->ops->hooknum,
-                                        &range, pkt->out);
-
-       data[NFT_REG_VERDICT].verdict = verdict;
+       regs->verdict.code = nf_nat_masquerade_ipv4(pkt->skb, pkt->ops->hooknum,
+                                                   &range, pkt->out);
 }
 
 static struct nft_expr_type nft_masq_ipv4_type;
index 6ecfce63201a2753d4943813d3eccbb951f34d0b..d8d795df9c13c562880a6f1d074226984e5400de 100644 (file)
 #include <net/netfilter/nft_redir.h>
 
 static void nft_redir_ipv4_eval(const struct nft_expr *expr,
-                               struct nft_data data[NFT_REG_MAX + 1],
+                               struct nft_regs *regs,
                                const struct nft_pktinfo *pkt)
 {
        struct nft_redir *priv = nft_expr_priv(expr);
        struct nf_nat_ipv4_multi_range_compat mr;
-       unsigned int verdict;
 
        memset(&mr, 0, sizeof(mr));
        if (priv->sreg_proto_min) {
                mr.range[0].min.all =
-                       *(__be16 *)&data[priv->sreg_proto_min].data[0];
+                       *(__be16 *)&regs->data[priv->sreg_proto_min];
                mr.range[0].max.all =
-                       *(__be16 *)&data[priv->sreg_proto_max].data[0];
+                       *(__be16 *)&regs->data[priv->sreg_proto_max];
                mr.range[0].flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
        }
 
        mr.range[0].flags |= priv->flags;
 
-       verdict = nf_nat_redirect_ipv4(pkt->skb, &mr, pkt->ops->hooknum);
-       data[NFT_REG_VERDICT].verdict = verdict;
+       regs->verdict.code = nf_nat_redirect_ipv4(pkt->skb, &mr,
+                                                 pkt->ops->hooknum);
 }
 
 static struct nft_expr_type nft_redir_ipv4_type;
index a7621faa96783f31cf178a36a8ac147bedac5f32..b07e58b51158514496ce7b136e04eca3266058ce 100644 (file)
@@ -20,7 +20,7 @@
 #include <net/netfilter/nft_reject.h>
 
 static void nft_reject_ipv4_eval(const struct nft_expr *expr,
-                                struct nft_data data[NFT_REG_MAX + 1],
+                                struct nft_regs *regs,
                                 const struct nft_pktinfo *pkt)
 {
        struct nft_reject *priv = nft_expr_priv(expr);
@@ -37,7 +37,7 @@ static void nft_reject_ipv4_eval(const struct nft_expr *expr,
                break;
        }
 
-       data[NFT_REG_VERDICT].verdict = NF_DROP;
+       regs->verdict.code = NF_DROP;
 }
 
 static struct nft_expr_type nft_reject_ipv4_type;
index 529c119cbb14c9eff00c7a5fb63148ef0bc9f740..cd1ac1637a0512d19fd4d3345011bcc3c9daab9d 100644 (file)
 #include <net/netfilter/ipv6/nf_nat_masquerade.h>
 
 static void nft_masq_ipv6_eval(const struct nft_expr *expr,
-                              struct nft_data data[NFT_REG_MAX + 1],
+                              struct nft_regs *regs,
                               const struct nft_pktinfo *pkt)
 {
        struct nft_masq *priv = nft_expr_priv(expr);
        struct nf_nat_range range;
-       unsigned int verdict;
 
        memset(&range, 0, sizeof(range));
        range.flags = priv->flags;
 
-       verdict = nf_nat_masquerade_ipv6(pkt->skb, &range, pkt->out);
-
-       data[NFT_REG_VERDICT].verdict = verdict;
+       regs->verdict.code = nf_nat_masquerade_ipv6(pkt->skb, &range, pkt->out);
 }
 
 static struct nft_expr_type nft_masq_ipv6_type;
index 11820b6b36130d4ec83af3f173a1ca70df8cbf93..effd393bd51790ff09c241a4fe207b1fb5f8c19b 100644 (file)
 #include <net/netfilter/nf_nat_redirect.h>
 
 static void nft_redir_ipv6_eval(const struct nft_expr *expr,
-                               struct nft_data data[NFT_REG_MAX + 1],
+                               struct nft_regs *regs,
                                const struct nft_pktinfo *pkt)
 {
        struct nft_redir *priv = nft_expr_priv(expr);
        struct nf_nat_range range;
-       unsigned int verdict;
 
        memset(&range, 0, sizeof(range));
        if (priv->sreg_proto_min) {
                range.min_proto.all =
-                       *(__be16 *)&data[priv->sreg_proto_min].data[0];
+                       *(__be16 *)&regs->data[priv->sreg_proto_min],
                range.max_proto.all =
-                       *(__be16 *)&data[priv->sreg_proto_max].data[0];
+                       *(__be16 *)&regs->data[priv->sreg_proto_max],
                range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
        }
 
        range.flags |= priv->flags;
 
-       verdict = nf_nat_redirect_ipv6(pkt->skb, &range, pkt->ops->hooknum);
-       data[NFT_REG_VERDICT].verdict = verdict;
+       regs->verdict.code = nf_nat_redirect_ipv6(pkt->skb, &range,
+                                                 pkt->ops->hooknum);
 }
 
 static struct nft_expr_type nft_redir_ipv6_type;
index 71c7be5ee43a0e067e2d653cb37cee3a92e487bc..d0d1540ecf870a83182354aa64bad36eac354e1b 100644 (file)
@@ -20,7 +20,7 @@
 #include <net/netfilter/ipv6/nf_reject.h>
 
 static void nft_reject_ipv6_eval(const struct nft_expr *expr,
-                                struct nft_data data[NFT_REG_MAX + 1],
+                                struct nft_regs *regs,
                                 const struct nft_pktinfo *pkt)
 {
        struct nft_reject *priv = nft_expr_priv(expr);
@@ -38,7 +38,7 @@ static void nft_reject_ipv6_eval(const struct nft_expr *expr,
                break;
        }
 
-       data[NFT_REG_VERDICT].verdict = NF_DROP;
+       regs->verdict.code = NF_DROP;
 }
 
 static struct nft_expr_type nft_reject_ipv6_type;
index 0b96fa0d64b2f9bf536eed8a0778f36f8aa04508..78af83bc9c8e8dbfcead6e151247a127602ac107 100644 (file)
@@ -1545,6 +1545,23 @@ nla_put_failure:
        return -1;
 };
 
+int nft_expr_dump(struct sk_buff *skb, unsigned int attr,
+                 const struct nft_expr *expr)
+{
+       struct nlattr *nest;
+
+       nest = nla_nest_start(skb, attr);
+       if (!nest)
+               goto nla_put_failure;
+       if (nf_tables_fill_expr_info(skb, expr) < 0)
+               goto nla_put_failure;
+       nla_nest_end(skb, nest);
+       return 0;
+
+nla_put_failure:
+       return -1;
+}
+
 struct nft_expr_info {
        const struct nft_expr_ops       *ops;
        struct nlattr                   *tb[NFT_EXPR_MAXATTR + 1];
@@ -1622,6 +1639,39 @@ static void nf_tables_expr_destroy(const struct nft_ctx *ctx,
        module_put(expr->ops->type->owner);
 }
 
+struct nft_expr *nft_expr_init(const struct nft_ctx *ctx,
+                              const struct nlattr *nla)
+{
+       struct nft_expr_info info;
+       struct nft_expr *expr;
+       int err;
+
+       err = nf_tables_expr_parse(ctx, nla, &info);
+       if (err < 0)
+               goto err1;
+
+       err = -ENOMEM;
+       expr = kzalloc(info.ops->size, GFP_KERNEL);
+       if (expr == NULL)
+               goto err2;
+
+       err = nf_tables_newexpr(ctx, &info, expr);
+       if (err < 0)
+               goto err2;
+
+       return expr;
+err2:
+       module_put(info.ops->type->owner);
+err1:
+       return ERR_PTR(err);
+}
+
+void nft_expr_destroy(const struct nft_ctx *ctx, struct nft_expr *expr)
+{
+       nf_tables_expr_destroy(ctx, expr);
+       kfree(expr);
+}
+
 /*
  * Rules
  */
@@ -1703,12 +1753,8 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, struct net *net,
        if (list == NULL)
                goto nla_put_failure;
        nft_rule_for_each_expr(expr, next, rule) {
-               struct nlattr *elem = nla_nest_start(skb, NFTA_LIST_ELEM);
-               if (elem == NULL)
+               if (nft_expr_dump(skb, NFTA_LIST_ELEM, expr) < 0)
                        goto nla_put_failure;
-               if (nf_tables_fill_expr_info(skb, expr) < 0)
-                       goto nla_put_failure;
-               nla_nest_end(skb, elem);
        }
        nla_nest_end(skb, list);
 
@@ -2608,16 +2654,20 @@ static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb,
        }
 
        desc.klen = ntohl(nla_get_be32(nla[NFTA_SET_KEY_LEN]));
-       if (desc.klen == 0 || desc.klen > FIELD_SIZEOF(struct nft_data, data))
+       if (desc.klen == 0 || desc.klen > NFT_DATA_VALUE_MAXLEN)
                return -EINVAL;
 
        flags = 0;
        if (nla[NFTA_SET_FLAGS] != NULL) {
                flags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
                if (flags & ~(NFT_SET_ANONYMOUS | NFT_SET_CONSTANT |
-                             NFT_SET_INTERVAL | NFT_SET_MAP |
-                             NFT_SET_TIMEOUT))
+                             NFT_SET_INTERVAL | NFT_SET_TIMEOUT |
+                             NFT_SET_MAP | NFT_SET_EVAL))
                        return -EINVAL;
+               /* Only one of both operations is supported */
+               if ((flags & (NFT_SET_MAP | NFT_SET_EVAL)) ==
+                            (NFT_SET_MAP | NFT_SET_EVAL))
+                       return -EOPNOTSUPP;
        }
 
        dtype = 0;
@@ -2634,11 +2684,10 @@ static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb,
                        if (nla[NFTA_SET_DATA_LEN] == NULL)
                                return -EINVAL;
                        desc.dlen = ntohl(nla_get_be32(nla[NFTA_SET_DATA_LEN]));
-                       if (desc.dlen == 0 ||
-                           desc.dlen > FIELD_SIZEOF(struct nft_data, data))
+                       if (desc.dlen == 0 || desc.dlen > NFT_DATA_VALUE_MAXLEN)
                                return -EINVAL;
                } else
-                       desc.dlen = sizeof(struct nft_data);
+                       desc.dlen = sizeof(struct nft_verdict);
        } else if (flags & NFT_SET_MAP)
                return -EINVAL;
 
@@ -2797,9 +2846,10 @@ static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx,
        enum nft_registers dreg;
 
        dreg = nft_type_to_reg(set->dtype);
-       return nft_validate_data_load(ctx, dreg, nft_set_ext_data(ext),
-                                     set->dtype == NFT_DATA_VERDICT ?
-                                     NFT_DATA_VERDICT : NFT_DATA_VALUE);
+       return nft_validate_register_store(ctx, dreg, nft_set_ext_data(ext),
+                                          set->dtype == NFT_DATA_VERDICT ?
+                                          NFT_DATA_VERDICT : NFT_DATA_VALUE,
+                                          set->dlen);
 }
 
 int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
@@ -2853,12 +2903,13 @@ void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
 
 const struct nft_set_ext_type nft_set_ext_types[] = {
        [NFT_SET_EXT_KEY]               = {
-               .len    = sizeof(struct nft_data),
-               .align  = __alignof__(struct nft_data),
+               .align  = __alignof__(u32),
        },
        [NFT_SET_EXT_DATA]              = {
-               .len    = sizeof(struct nft_data),
-               .align  = __alignof__(struct nft_data),
+               .align  = __alignof__(u32),
+       },
+       [NFT_SET_EXT_EXPR]              = {
+               .align  = __alignof__(struct nft_expr),
        },
        [NFT_SET_EXT_FLAGS]             = {
                .len    = sizeof(u8),
@@ -2946,6 +2997,10 @@ static int nf_tables_fill_setelem(struct sk_buff *skb,
                          set->dlen) < 0)
                goto nla_put_failure;
 
+       if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPR) &&
+           nft_expr_dump(skb, NFTA_SET_ELEM_EXPR, nft_set_ext_expr(ext)) < 0)
+               goto nla_put_failure;
+
        if (nft_set_ext_exists(ext, NFT_SET_EXT_FLAGS) &&
            nla_put_be32(skb, NFTA_SET_ELEM_FLAGS,
                         htonl(*nft_set_ext_flags(ext))))
@@ -3200,8 +3255,7 @@ static struct nft_trans *nft_trans_elem_alloc(struct nft_ctx *ctx,
 
 void *nft_set_elem_init(const struct nft_set *set,
                        const struct nft_set_ext_tmpl *tmpl,
-                       const struct nft_data *key,
-                       const struct nft_data *data,
+                       const u32 *key, const u32 *data,
                        u64 timeout, gfp_t gfp)
 {
        struct nft_set_ext *ext;
@@ -3233,6 +3287,8 @@ void nft_set_elem_destroy(const struct nft_set *set, void *elem)
        nft_data_uninit(nft_set_ext_key(ext), NFT_DATA_VALUE);
        if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA))
                nft_data_uninit(nft_set_ext_data(ext), set->dtype);
+       if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPR))
+               nf_tables_expr_destroy(NULL, nft_set_ext_expr(ext));
 
        kfree(elem);
 }
@@ -3299,14 +3355,15 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
                timeout = set->timeout;
        }
 
-       err = nft_data_init(ctx, &elem.key, &d1, nla[NFTA_SET_ELEM_KEY]);
+       err = nft_data_init(ctx, &elem.key.val, sizeof(elem.key), &d1,
+                           nla[NFTA_SET_ELEM_KEY]);
        if (err < 0)
                goto err1;
        err = -EINVAL;
        if (d1.type != NFT_DATA_VALUE || d1.len != set->klen)
                goto err2;
 
-       nft_set_ext_add(&tmpl, NFT_SET_EXT_KEY);
+       nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, d1.len);
        if (timeout > 0) {
                nft_set_ext_add(&tmpl, NFT_SET_EXT_EXPIRATION);
                if (timeout != set->timeout)
@@ -3314,7 +3371,8 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
        }
 
        if (nla[NFTA_SET_ELEM_DATA] != NULL) {
-               err = nft_data_init(ctx, &data, &d2, nla[NFTA_SET_ELEM_DATA]);
+               err = nft_data_init(ctx, &data, sizeof(data), &d2,
+                                   nla[NFTA_SET_ELEM_DATA]);
                if (err < 0)
                        goto err2;
 
@@ -3333,13 +3391,14 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
                        if (!(binding->flags & NFT_SET_MAP))
                                continue;
 
-                       err = nft_validate_data_load(&bind_ctx, dreg,
-                                                    &data, d2.type);
+                       err = nft_validate_register_store(&bind_ctx, dreg,
+                                                         &data,
+                                                         d2.type, d2.len);
                        if (err < 0)
                                goto err3;
                }
 
-               nft_set_ext_add(&tmpl, NFT_SET_EXT_DATA);
+               nft_set_ext_add_length(&tmpl, NFT_SET_EXT_DATA, d2.len);
        }
 
        /* The full maximum length of userdata can exceed the maximum
@@ -3355,7 +3414,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
        }
 
        err = -ENOMEM;
-       elem.priv = nft_set_elem_init(set, &tmpl, &elem.key, &data,
+       elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data, data.data,
                                      timeout, GFP_KERNEL);
        if (elem.priv == NULL)
                goto err3;
@@ -3390,7 +3449,7 @@ err3:
        if (nla[NFTA_SET_ELEM_DATA] != NULL)
                nft_data_uninit(&data, d2.type);
 err2:
-       nft_data_uninit(&elem.key, d1.type);
+       nft_data_uninit(&elem.key.val, d1.type);
 err1:
        return err;
 }
@@ -3457,7 +3516,8 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
        if (nla[NFTA_SET_ELEM_KEY] == NULL)
                goto err1;
 
-       err = nft_data_init(ctx, &elem.key, &desc, nla[NFTA_SET_ELEM_KEY]);
+       err = nft_data_init(ctx, &elem.key.val, sizeof(elem.key), &desc,
+                           nla[NFTA_SET_ELEM_KEY]);
        if (err < 0)
                goto err1;
 
@@ -3484,7 +3544,7 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
 err3:
        kfree(trans);
 err2:
-       nft_data_uninit(&elem.key, desc.type);
+       nft_data_uninit(&elem.key.val, desc.type);
 err1:
        return err;
 }
@@ -4047,10 +4107,10 @@ static int nf_tables_loop_check_setelem(const struct nft_ctx *ctx,
                return 0;
 
        data = nft_set_ext_data(ext);
-       switch (data->verdict) {
+       switch (data->verdict.code) {
        case NFT_JUMP:
        case NFT_GOTO:
-               return nf_tables_check_loops(ctx, data->chain);
+               return nf_tables_check_loops(ctx, data->verdict.chain);
        default:
                return 0;
        }
@@ -4083,10 +4143,11 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx,
                        if (data == NULL)
                                continue;
 
-                       switch (data->verdict) {
+                       switch (data->verdict.code) {
                        case NFT_JUMP:
                        case NFT_GOTO:
-                               err = nf_tables_check_loops(ctx, data->chain);
+                               err = nf_tables_check_loops(ctx,
+                                                       data->verdict.chain);
                                if (err < 0)
                                        return err;
                        default:
@@ -4120,85 +4181,129 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx,
 }
 
 /**
- *     nft_validate_input_register - validate an expressions' input register
+ *     nft_parse_register - parse a register value from a netlink attribute
  *
- *     @reg: the register number
+ *     @attr: netlink attribute
  *
- *     Validate that the input register is one of the general purpose
- *     registers.
+ *     Parse and translate a register value from a netlink attribute.
+ *     Registers used to be 128 bit wide, these register numbers will be
+ *     mapped to the corresponding 32 bit register numbers.
  */
-int nft_validate_input_register(enum nft_registers reg)
+unsigned int nft_parse_register(const struct nlattr *attr)
 {
-       if (reg <= NFT_REG_VERDICT)
-               return -EINVAL;
-       if (reg > NFT_REG_MAX)
-               return -ERANGE;
-       return 0;
+       unsigned int reg;
+
+       reg = ntohl(nla_get_be32(attr));
+       switch (reg) {
+       case NFT_REG_VERDICT...NFT_REG_4:
+               return reg * NFT_REG_SIZE / NFT_REG32_SIZE;
+       default:
+               return reg + NFT_REG_SIZE / NFT_REG32_SIZE - NFT_REG32_00;
+       }
 }
-EXPORT_SYMBOL_GPL(nft_validate_input_register);
+EXPORT_SYMBOL_GPL(nft_parse_register);
 
 /**
- *     nft_validate_output_register - validate an expressions' output register
+ *     nft_dump_register - dump a register value to a netlink attribute
+ *
+ *     @skb: socket buffer
+ *     @attr: attribute number
+ *     @reg: register number
+ *
+ *     Construct a netlink attribute containing the register number. For
+ *     compatibility reasons, register numbers being a multiple of 4 are
+ *     translated to the corresponding 128 bit register numbers.
+ */
+int nft_dump_register(struct sk_buff *skb, unsigned int attr, unsigned int reg)
+{
+       if (reg % (NFT_REG_SIZE / NFT_REG32_SIZE) == 0)
+               reg = reg / (NFT_REG_SIZE / NFT_REG32_SIZE);
+       else
+               reg = reg - NFT_REG_SIZE / NFT_REG32_SIZE + NFT_REG32_00;
+
+       return nla_put_be32(skb, attr, htonl(reg));
+}
+EXPORT_SYMBOL_GPL(nft_dump_register);
+
+/**
+ *     nft_validate_register_load - validate a load from a register
  *
  *     @reg: the register number
+ *     @len: the length of the data
  *
- *     Validate that the output register is one of the general purpose
- *     registers or the verdict register.
+ *     Validate that the input register is one of the general purpose
+ *     registers and that the length of the load is within the bounds.
  */
-int nft_validate_output_register(enum nft_registers reg)
+int nft_validate_register_load(enum nft_registers reg, unsigned int len)
 {
-       if (reg < NFT_REG_VERDICT)
+       if (reg < NFT_REG_1 * NFT_REG_SIZE / NFT_REG32_SIZE)
+               return -EINVAL;
+       if (len == 0)
                return -EINVAL;
-       if (reg > NFT_REG_MAX)
+       if (reg * NFT_REG32_SIZE + len > FIELD_SIZEOF(struct nft_regs, data))
                return -ERANGE;
+
        return 0;
 }
-EXPORT_SYMBOL_GPL(nft_validate_output_register);
+EXPORT_SYMBOL_GPL(nft_validate_register_load);
 
 /**
- *     nft_validate_data_load - validate an expressions' data load
+ *     nft_validate_register_store - validate an expressions' register store
  *
  *     @ctx: context of the expression performing the load
  *     @reg: the destination register number
  *     @data: the data to load
  *     @type: the data type
+ *     @len: the length of the data
  *
  *     Validate that a data load uses the appropriate data type for
- *     the destination register. A value of NULL for the data means
- *     that its runtime gathered data, which is always of type
- *     NFT_DATA_VALUE.
+ *     the destination register and the length is within the bounds.
+ *     A value of NULL for the data means that its runtime gathered
+ *     data.
  */
-int nft_validate_data_load(const struct nft_ctx *ctx, enum nft_registers reg,
-                          const struct nft_data *data,
-                          enum nft_data_types type)
+int nft_validate_register_store(const struct nft_ctx *ctx,
+                               enum nft_registers reg,
+                               const struct nft_data *data,
+                               enum nft_data_types type, unsigned int len)
 {
        int err;
 
        switch (reg) {
        case NFT_REG_VERDICT:
-               if (data == NULL || type != NFT_DATA_VERDICT)
+               if (type != NFT_DATA_VERDICT)
                        return -EINVAL;
 
-               if (data->verdict == NFT_GOTO || data->verdict == NFT_JUMP) {
-                       err = nf_tables_check_loops(ctx, data->chain);
+               if (data != NULL &&
+                   (data->verdict.code == NFT_GOTO ||
+                    data->verdict.code == NFT_JUMP)) {
+                       err = nf_tables_check_loops(ctx, data->verdict.chain);
                        if (err < 0)
                                return err;
 
-                       if (ctx->chain->level + 1 > data->chain->level) {
+                       if (ctx->chain->level + 1 >
+                           data->verdict.chain->level) {
                                if (ctx->chain->level + 1 == NFT_JUMP_STACK_SIZE)
                                        return -EMLINK;
-                               data->chain->level = ctx->chain->level + 1;
+                               data->verdict.chain->level = ctx->chain->level + 1;
                        }
                }
 
                return 0;
        default:
+               if (reg < NFT_REG_1 * NFT_REG_SIZE / NFT_REG32_SIZE)
+                       return -EINVAL;
+               if (len == 0)
+                       return -EINVAL;
+               if (reg * NFT_REG32_SIZE + len >
+                   FIELD_SIZEOF(struct nft_regs, data))
+                       return -ERANGE;
+
                if (data != NULL && type != NFT_DATA_VALUE)
                        return -EINVAL;
                return 0;
        }
 }
-EXPORT_SYMBOL_GPL(nft_validate_data_load);
+EXPORT_SYMBOL_GPL(nft_validate_register_store);
 
 static const struct nla_policy nft_verdict_policy[NFTA_VERDICT_MAX + 1] = {
        [NFTA_VERDICT_CODE]     = { .type = NLA_U32 },
@@ -4219,11 +4324,11 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
 
        if (!tb[NFTA_VERDICT_CODE])
                return -EINVAL;
-       data->verdict = ntohl(nla_get_be32(tb[NFTA_VERDICT_CODE]));
+       data->verdict.code = ntohl(nla_get_be32(tb[NFTA_VERDICT_CODE]));
 
-       switch (data->verdict) {
+       switch (data->verdict.code) {
        default:
-               switch (data->verdict & NF_VERDICT_MASK) {
+               switch (data->verdict.code & NF_VERDICT_MASK) {
                case NF_ACCEPT:
                case NF_DROP:
                case NF_QUEUE:
@@ -4249,7 +4354,7 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
                        return -EOPNOTSUPP;
 
                chain->use++;
-               data->chain = chain;
+               data->verdict.chain = chain;
                desc->len = sizeof(data);
                break;
        }
@@ -4260,10 +4365,10 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
 
 static void nft_verdict_uninit(const struct nft_data *data)
 {
-       switch (data->verdict) {
+       switch (data->verdict.code) {
        case NFT_JUMP:
        case NFT_GOTO:
-               data->chain->use--;
+               data->verdict.chain->use--;
                break;
        }
 }
@@ -4276,13 +4381,14 @@ static int nft_verdict_dump(struct sk_buff *skb, const struct nft_data *data)
        if (!nest)
                goto nla_put_failure;
 
-       if (nla_put_be32(skb, NFTA_VERDICT_CODE, htonl(data->verdict)))
+       if (nla_put_be32(skb, NFTA_VERDICT_CODE, htonl(data->verdict.code)))
                goto nla_put_failure;
 
-       switch (data->verdict) {
+       switch (data->verdict.code) {
        case NFT_JUMP:
        case NFT_GOTO:
-               if (nla_put_string(skb, NFTA_VERDICT_CHAIN, data->chain->name))
+               if (nla_put_string(skb, NFTA_VERDICT_CHAIN,
+                                  data->verdict.chain->name))
                        goto nla_put_failure;
        }
        nla_nest_end(skb, nest);
@@ -4292,7 +4398,8 @@ nla_put_failure:
        return -1;
 }
 
-static int nft_value_init(const struct nft_ctx *ctx, struct nft_data *data,
+static int nft_value_init(const struct nft_ctx *ctx,
+                         struct nft_data *data, unsigned int size,
                          struct nft_data_desc *desc, const struct nlattr *nla)
 {
        unsigned int len;
@@ -4300,10 +4407,10 @@ static int nft_value_init(const struct nft_ctx *ctx, struct nft_data *data,
        len = nla_len(nla);
        if (len == 0)
                return -EINVAL;
-       if (len > sizeof(data->data))
+       if (len > size)
                return -EOVERFLOW;
 
-       nla_memcpy(data->data, nla, sizeof(data->data));
+       nla_memcpy(data->data, nla, len);
        desc->type = NFT_DATA_VALUE;
        desc->len  = len;
        return 0;
@@ -4316,8 +4423,7 @@ static int nft_value_dump(struct sk_buff *skb, const struct nft_data *data,
 }
 
 static const struct nla_policy nft_data_policy[NFTA_DATA_MAX + 1] = {
-       [NFTA_DATA_VALUE]       = { .type = NLA_BINARY,
-                                   .len  = FIELD_SIZEOF(struct nft_data, data) },
+       [NFTA_DATA_VALUE]       = { .type = NLA_BINARY },
        [NFTA_DATA_VERDICT]     = { .type = NLA_NESTED },
 };
 
@@ -4326,6 +4432,7 @@ static const struct nla_policy nft_data_policy[NFTA_DATA_MAX + 1] = {
  *
  *     @ctx: context of the expression using the data
  *     @data: destination struct nft_data
+ *     @size: maximum data length
  *     @desc: data description
  *     @nla: netlink attribute containing data
  *
@@ -4335,7 +4442,8 @@ static const struct nla_policy nft_data_policy[NFTA_DATA_MAX + 1] = {
  *     The caller can indicate that it only wants to accept data of type
  *     NFT_DATA_VALUE by passing NULL for the ctx argument.
  */
-int nft_data_init(const struct nft_ctx *ctx, struct nft_data *data,
+int nft_data_init(const struct nft_ctx *ctx,
+                 struct nft_data *data, unsigned int size,
                  struct nft_data_desc *desc, const struct nlattr *nla)
 {
        struct nlattr *tb[NFTA_DATA_MAX + 1];
@@ -4346,7 +4454,8 @@ int nft_data_init(const struct nft_ctx *ctx, struct nft_data *data,
                return err;
 
        if (tb[NFTA_DATA_VALUE])
-               return nft_value_init(ctx, data, desc, tb[NFTA_DATA_VALUE]);
+               return nft_value_init(ctx, data, size, desc,
+                                     tb[NFTA_DATA_VALUE]);
        if (tb[NFTA_DATA_VERDICT] && ctx != NULL)
                return nft_verdict_init(ctx, data, desc, tb[NFTA_DATA_VERDICT]);
        return -EINVAL;
index 7caf08a9225d29c3621896c881896ac03765827f..f153b07073afba0f544889eb01312a57414f74a6 100644 (file)
@@ -65,23 +65,23 @@ static inline void nft_trace_packet(const struct nft_pktinfo *pkt,
 }
 
 static void nft_cmp_fast_eval(const struct nft_expr *expr,
-                             struct nft_data data[NFT_REG_MAX + 1])
+                             struct nft_regs *regs)
 {
        const struct nft_cmp_fast_expr *priv = nft_expr_priv(expr);
        u32 mask = nft_cmp_fast_mask(priv->len);
 
-       if ((data[priv->sreg].data[0] & mask) == priv->data)
+       if ((regs->data[priv->sreg] & mask) == priv->data)
                return;
-       data[NFT_REG_VERDICT].verdict = NFT_BREAK;
+       regs->verdict.code = NFT_BREAK;
 }
 
 static bool nft_payload_fast_eval(const struct nft_expr *expr,
-                                 struct nft_data data[NFT_REG_MAX + 1],
+                                 struct nft_regs *regs,
                                  const struct nft_pktinfo *pkt)
 {
        const struct nft_payload *priv = nft_expr_priv(expr);
        const struct sk_buff *skb = pkt->skb;
-       struct nft_data *dest = &data[priv->dreg];
+       u32 *dest = &regs->data[priv->dreg];
        unsigned char *ptr;
 
        if (priv->base == NFT_PAYLOAD_NETWORK_HEADER)
@@ -94,12 +94,13 @@ static bool nft_payload_fast_eval(const struct nft_expr *expr,
        if (unlikely(ptr + priv->len >= skb_tail_pointer(skb)))
                return false;
 
+       *dest = 0;
        if (priv->len == 2)
-               *(u16 *)dest->data = *(u16 *)ptr;
+               *(u16 *)dest = *(u16 *)ptr;
        else if (priv->len == 4)
-               *(u32 *)dest->data = *(u32 *)ptr;
+               *(u32 *)dest = *(u32 *)ptr;
        else
-               *(u8 *)dest->data = *(u8 *)ptr;
+               *(u8 *)dest = *(u8 *)ptr;
        return true;
 }
 
@@ -116,7 +117,7 @@ nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops)
        const struct net *net = read_pnet(&nft_base_chain(basechain)->pnet);
        const struct nft_rule *rule;
        const struct nft_expr *expr, *last;
-       struct nft_data data[NFT_REG_MAX + 1];
+       struct nft_regs regs;
        unsigned int stackptr = 0;
        struct nft_jumpstack jumpstack[NFT_JUMP_STACK_SIZE];
        struct nft_stats *stats;
@@ -127,7 +128,7 @@ do_chain:
        rulenum = 0;
        rule = list_entry(&chain->rules, struct nft_rule, list);
 next_rule:
-       data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
+       regs.verdict.code = NFT_CONTINUE;
        list_for_each_entry_continue_rcu(rule, &chain->rules, list) {
 
                /* This rule is not active, skip. */
@@ -138,18 +139,18 @@ next_rule:
 
                nft_rule_for_each_expr(expr, last, rule) {
                        if (expr->ops == &nft_cmp_fast_ops)
-                               nft_cmp_fast_eval(expr, data);
+                               nft_cmp_fast_eval(expr, &regs);
                        else if (expr->ops != &nft_payload_fast_ops ||
-                                !nft_payload_fast_eval(expr, data, pkt))
-                               expr->ops->eval(expr, data, pkt);
+                                !nft_payload_fast_eval(expr, &regs, pkt))
+                               expr->ops->eval(expr, &regs, pkt);
 
-                       if (data[NFT_REG_VERDICT].verdict != NFT_CONTINUE)
+                       if (regs.verdict.code != NFT_CONTINUE)
                                break;
                }
 
-               switch (data[NFT_REG_VERDICT].verdict) {
+               switch (regs.verdict.code) {
                case NFT_BREAK:
-                       data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
+                       regs.verdict.code = NFT_CONTINUE;
                        continue;
                case NFT_CONTINUE:
                        nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
@@ -158,15 +159,15 @@ next_rule:
                break;
        }
 
-       switch (data[NFT_REG_VERDICT].verdict & NF_VERDICT_MASK) {
+       switch (regs.verdict.code & NF_VERDICT_MASK) {
        case NF_ACCEPT:
        case NF_DROP:
        case NF_QUEUE:
                nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
-               return data[NFT_REG_VERDICT].verdict;
+               return regs.verdict.code;
        }
 
-       switch (data[NFT_REG_VERDICT].verdict) {
+       switch (regs.verdict.code) {
        case NFT_JUMP:
                BUG_ON(stackptr >= NFT_JUMP_STACK_SIZE);
                jumpstack[stackptr].chain = chain;
@@ -177,7 +178,7 @@ next_rule:
        case NFT_GOTO:
                nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
 
-               chain = data[NFT_REG_VERDICT].chain;
+               chain = regs.verdict.chain;
                goto do_chain;
        case NFT_CONTINUE:
                rulenum++;
index 4fb6ee2c1106a356775cbad15398ede0047000ed..d71cc18fa35daaee8e2c12cfdbee557d17daf559 100644 (file)
@@ -26,18 +26,16 @@ struct nft_bitwise {
 };
 
 static void nft_bitwise_eval(const struct nft_expr *expr,
-                            struct nft_data data[NFT_REG_MAX + 1],
+                            struct nft_regs *regs,
                             const struct nft_pktinfo *pkt)
 {
        const struct nft_bitwise *priv = nft_expr_priv(expr);
-       const struct nft_data *src = &data[priv->sreg];
-       struct nft_data *dst = &data[priv->dreg];
+       const u32 *src = &regs->data[priv->sreg];
+       u32 *dst = &regs->data[priv->dreg];
        unsigned int i;
 
-       for (i = 0; i < DIV_ROUND_UP(priv->len, 4); i++) {
-               dst->data[i] = (src->data[i] & priv->mask.data[i]) ^
-                              priv->xor.data[i];
-       }
+       for (i = 0; i < DIV_ROUND_UP(priv->len, 4); i++)
+               dst[i] = (src[i] & priv->mask.data[i]) ^ priv->xor.data[i];
 }
 
 static const struct nla_policy nft_bitwise_policy[NFTA_BITWISE_MAX + 1] = {
@@ -63,28 +61,27 @@ static int nft_bitwise_init(const struct nft_ctx *ctx,
            tb[NFTA_BITWISE_XOR] == NULL)
                return -EINVAL;
 
-       priv->sreg = ntohl(nla_get_be32(tb[NFTA_BITWISE_SREG]));
-       err = nft_validate_input_register(priv->sreg);
+       priv->len  = ntohl(nla_get_be32(tb[NFTA_BITWISE_LEN]));
+       priv->sreg = nft_parse_register(tb[NFTA_BITWISE_SREG]);
+       err = nft_validate_register_load(priv->sreg, priv->len);
        if (err < 0)
                return err;
 
-       priv->dreg = ntohl(nla_get_be32(tb[NFTA_BITWISE_DREG]));
-       err = nft_validate_output_register(priv->dreg);
+       priv->dreg = nft_parse_register(tb[NFTA_BITWISE_DREG]);
+       err = nft_validate_register_store(ctx, priv->dreg, NULL,
+                                         NFT_DATA_VALUE, priv->len);
        if (err < 0)
                return err;
-       err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
-       if (err < 0)
-               return err;
-
-       priv->len = ntohl(nla_get_be32(tb[NFTA_BITWISE_LEN]));
 
-       err = nft_data_init(NULL, &priv->mask, &d1, tb[NFTA_BITWISE_MASK]);
+       err = nft_data_init(NULL, &priv->mask, sizeof(priv->mask), &d1,
+                           tb[NFTA_BITWISE_MASK]);
        if (err < 0)
                return err;
        if (d1.len != priv->len)
                return -EINVAL;
 
-       err = nft_data_init(NULL, &priv->xor, &d2, tb[NFTA_BITWISE_XOR]);
+       err = nft_data_init(NULL, &priv->xor, sizeof(priv->xor), &d2,
+                           tb[NFTA_BITWISE_XOR]);
        if (err < 0)
                return err;
        if (d2.len != priv->len)
@@ -97,9 +94,9 @@ static int nft_bitwise_dump(struct sk_buff *skb, const struct nft_expr *expr)
 {
        const struct nft_bitwise *priv = nft_expr_priv(expr);
 
-       if (nla_put_be32(skb, NFTA_BITWISE_SREG, htonl(priv->sreg)))
+       if (nft_dump_register(skb, NFTA_BITWISE_SREG, priv->sreg))
                goto nla_put_failure;
-       if (nla_put_be32(skb, NFTA_BITWISE_DREG, htonl(priv->dreg)))
+       if (nft_dump_register(skb, NFTA_BITWISE_DREG, priv->dreg))
                goto nla_put_failure;
        if (nla_put_be32(skb, NFTA_BITWISE_LEN, htonl(priv->len)))
                goto nla_put_failure;
index c39ed8d29df1716101985000b10c4945f69384c9..fde5145f2e36b989c1d9b951a6cc7d1f85d6b20b 100644 (file)
@@ -26,16 +26,17 @@ struct nft_byteorder {
 };
 
 static void nft_byteorder_eval(const struct nft_expr *expr,
-                              struct nft_data data[NFT_REG_MAX + 1],
+                              struct nft_regs *regs,
                               const struct nft_pktinfo *pkt)
 {
        const struct nft_byteorder *priv = nft_expr_priv(expr);
-       struct nft_data *src = &data[priv->sreg], *dst = &data[priv->dreg];
+       u32 *src = &regs->data[priv->sreg];
+       u32 *dst = &regs->data[priv->dreg];
        union { u32 u32; u16 u16; } *s, *d;
        unsigned int i;
 
-       s = (void *)src->data;
-       d = (void *)dst->data;
+       s = (void *)src;
+       d = (void *)dst;
 
        switch (priv->size) {
        case 4:
@@ -87,19 +88,6 @@ static int nft_byteorder_init(const struct nft_ctx *ctx,
            tb[NFTA_BYTEORDER_OP] == NULL)
                return -EINVAL;
 
-       priv->sreg = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_SREG]));
-       err = nft_validate_input_register(priv->sreg);
-       if (err < 0)
-               return err;
-
-       priv->dreg = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_DREG]));
-       err = nft_validate_output_register(priv->dreg);
-       if (err < 0)
-               return err;
-       err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
-       if (err < 0)
-               return err;
-
        priv->op = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_OP]));
        switch (priv->op) {
        case NFT_BYTEORDER_NTOH:
@@ -109,10 +97,6 @@ static int nft_byteorder_init(const struct nft_ctx *ctx,
                return -EINVAL;
        }
 
-       priv->len = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_LEN]));
-       if (priv->len == 0 || priv->len > FIELD_SIZEOF(struct nft_data, data))
-               return -EINVAL;
-
        priv->size = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_SIZE]));
        switch (priv->size) {
        case 2:
@@ -122,16 +106,24 @@ static int nft_byteorder_init(const struct nft_ctx *ctx,
                return -EINVAL;
        }
 
-       return 0;
+       priv->sreg = nft_parse_register(tb[NFTA_BYTEORDER_SREG]);
+       priv->len  = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_LEN]));
+       err = nft_validate_register_load(priv->sreg, priv->len);
+       if (err < 0)
+               return err;
+
+       priv->dreg = nft_parse_register(tb[NFTA_BYTEORDER_DREG]);
+       return nft_validate_register_store(ctx, priv->dreg, NULL,
+                                          NFT_DATA_VALUE, priv->len);
 }
 
 static int nft_byteorder_dump(struct sk_buff *skb, const struct nft_expr *expr)
 {
        const struct nft_byteorder *priv = nft_expr_priv(expr);
 
-       if (nla_put_be32(skb, NFTA_BYTEORDER_SREG, htonl(priv->sreg)))
+       if (nft_dump_register(skb, NFTA_BYTEORDER_SREG, priv->sreg))
                goto nla_put_failure;
-       if (nla_put_be32(skb, NFTA_BYTEORDER_DREG, htonl(priv->dreg)))
+       if (nft_dump_register(skb, NFTA_BYTEORDER_DREG, priv->dreg))
                goto nla_put_failure;
        if (nla_put_be32(skb, NFTA_BYTEORDER_OP, htonl(priv->op)))
                goto nla_put_failure;
index e2b3f51c81f1df0289d75142689fcd109c351d0b..e25b35d70e4dc8a1f63de86f112f37760c132227 100644 (file)
@@ -25,13 +25,13 @@ struct nft_cmp_expr {
 };
 
 static void nft_cmp_eval(const struct nft_expr *expr,
-                        struct nft_data data[NFT_REG_MAX + 1],
+                        struct nft_regs *regs,
                         const struct nft_pktinfo *pkt)
 {
        const struct nft_cmp_expr *priv = nft_expr_priv(expr);
        int d;
 
-       d = nft_data_cmp(&data[priv->sreg], &priv->data, priv->len);
+       d = memcmp(&regs->data[priv->sreg], &priv->data, priv->len);
        switch (priv->op) {
        case NFT_CMP_EQ:
                if (d != 0)
@@ -59,7 +59,7 @@ static void nft_cmp_eval(const struct nft_expr *expr,
        return;
 
 mismatch:
-       data[NFT_REG_VERDICT].verdict = NFT_BREAK;
+       regs->verdict.code = NFT_BREAK;
 }
 
 static const struct nla_policy nft_cmp_policy[NFTA_CMP_MAX + 1] = {
@@ -75,12 +75,16 @@ static int nft_cmp_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
        struct nft_data_desc desc;
        int err;
 
-       priv->sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG]));
-       priv->op = ntohl(nla_get_be32(tb[NFTA_CMP_OP]));
-
-       err = nft_data_init(NULL, &priv->data, &desc, tb[NFTA_CMP_DATA]);
+       err = nft_data_init(NULL, &priv->data, sizeof(priv->data), &desc,
+                           tb[NFTA_CMP_DATA]);
        BUG_ON(err < 0);
 
+       priv->sreg = nft_parse_register(tb[NFTA_CMP_SREG]);
+       err = nft_validate_register_load(priv->sreg, desc.len);
+       if (err < 0)
+               return err;
+
+       priv->op  = ntohl(nla_get_be32(tb[NFTA_CMP_OP]));
        priv->len = desc.len;
        return 0;
 }
@@ -89,7 +93,7 @@ static int nft_cmp_dump(struct sk_buff *skb, const struct nft_expr *expr)
 {
        const struct nft_cmp_expr *priv = nft_expr_priv(expr);
 
-       if (nla_put_be32(skb, NFTA_CMP_SREG, htonl(priv->sreg)))
+       if (nft_dump_register(skb, NFTA_CMP_SREG, priv->sreg))
                goto nla_put_failure;
        if (nla_put_be32(skb, NFTA_CMP_OP, htonl(priv->op)))
                goto nla_put_failure;
@@ -122,13 +126,18 @@ static int nft_cmp_fast_init(const struct nft_ctx *ctx,
        u32 mask;
        int err;
 
-       priv->sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG]));
-
-       err = nft_data_init(NULL, &data, &desc, tb[NFTA_CMP_DATA]);
+       err = nft_data_init(NULL, &data, sizeof(data), &desc,
+                           tb[NFTA_CMP_DATA]);
        BUG_ON(err < 0);
-       desc.len *= BITS_PER_BYTE;
 
+       priv->sreg = nft_parse_register(tb[NFTA_CMP_SREG]);
+       err = nft_validate_register_load(priv->sreg, desc.len);
+       if (err < 0)
+               return err;
+
+       desc.len *= BITS_PER_BYTE;
        mask = nft_cmp_fast_mask(desc.len);
+
        priv->data = data.data[0] & mask;
        priv->len  = desc.len;
        return 0;
@@ -139,7 +148,7 @@ static int nft_cmp_fast_dump(struct sk_buff *skb, const struct nft_expr *expr)
        const struct nft_cmp_fast_expr *priv = nft_expr_priv(expr);
        struct nft_data data;
 
-       if (nla_put_be32(skb, NFTA_CMP_SREG, htonl(priv->sreg)))
+       if (nft_dump_register(skb, NFTA_CMP_SREG, priv->sreg))
                goto nla_put_failure;
        if (nla_put_be32(skb, NFTA_CMP_OP, htonl(NFT_CMP_EQ)))
                goto nla_put_failure;
@@ -167,7 +176,6 @@ nft_cmp_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[])
 {
        struct nft_data_desc desc;
        struct nft_data data;
-       enum nft_registers sreg;
        enum nft_cmp_ops op;
        int err;
 
@@ -176,11 +184,6 @@ nft_cmp_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[])
            tb[NFTA_CMP_DATA] == NULL)
                return ERR_PTR(-EINVAL);
 
-       sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG]));
-       err = nft_validate_input_register(sreg);
-       if (err < 0)
-               return ERR_PTR(err);
-
        op = ntohl(nla_get_be32(tb[NFTA_CMP_OP]));
        switch (op) {
        case NFT_CMP_EQ:
@@ -194,7 +197,8 @@ nft_cmp_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[])
                return ERR_PTR(-EINVAL);
        }
 
-       err = nft_data_init(NULL, &data, &desc, tb[NFTA_CMP_DATA]);
+       err = nft_data_init(NULL, &data, sizeof(data), &desc,
+                           tb[NFTA_CMP_DATA]);
        if (err < 0)
                return ERR_PTR(err);
 
index 0d137c1ac889ea2cd8f74aaf71238773855198c0..7f29cfc76349f56d7408f4519213a98d564ab135 100644 (file)
@@ -55,7 +55,7 @@ nft_compat_set_par(struct xt_action_param *par, void *xt, const void *xt_info)
 }
 
 static void nft_target_eval_xt(const struct nft_expr *expr,
-                              struct nft_data data[NFT_REG_MAX + 1],
+                              struct nft_regs *regs,
                               const struct nft_pktinfo *pkt)
 {
        void *info = nft_expr_priv(expr);
@@ -72,16 +72,16 @@ static void nft_target_eval_xt(const struct nft_expr *expr,
 
        switch (ret) {
        case XT_CONTINUE:
-               data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
+               regs->verdict.code = NFT_CONTINUE;
                break;
        default:
-               data[NFT_REG_VERDICT].verdict = ret;
+               regs->verdict.code = ret;
                break;
        }
 }
 
 static void nft_target_eval_bridge(const struct nft_expr *expr,
-                                  struct nft_data data[NFT_REG_MAX + 1],
+                                  struct nft_regs *regs,
                                   const struct nft_pktinfo *pkt)
 {
        void *info = nft_expr_priv(expr);
@@ -98,19 +98,19 @@ static void nft_target_eval_bridge(const struct nft_expr *expr,
 
        switch (ret) {
        case EBT_ACCEPT:
-               data[NFT_REG_VERDICT].verdict = NF_ACCEPT;
+               regs->verdict.code = NF_ACCEPT;
                break;
        case EBT_DROP:
-               data[NFT_REG_VERDICT].verdict = NF_DROP;
+               regs->verdict.code = NF_DROP;
                break;
        case EBT_CONTINUE:
-               data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
+               regs->verdict.code = NFT_CONTINUE;
                break;
        case EBT_RETURN:
-               data[NFT_REG_VERDICT].verdict = NFT_RETURN;
+               regs->verdict.code = NFT_RETURN;
                break;
        default:
-               data[NFT_REG_VERDICT].verdict = ret;
+               regs->verdict.code = ret;
                break;
        }
 }
@@ -304,7 +304,7 @@ static int nft_target_validate(const struct nft_ctx *ctx,
 }
 
 static void nft_match_eval(const struct nft_expr *expr,
-                          struct nft_data data[NFT_REG_MAX + 1],
+                          struct nft_regs *regs,
                           const struct nft_pktinfo *pkt)
 {
        void *info = nft_expr_priv(expr);
@@ -317,16 +317,16 @@ static void nft_match_eval(const struct nft_expr *expr,
        ret = match->match(skb, (struct xt_action_param *)&pkt->xt);
 
        if (pkt->xt.hotdrop) {
-               data[NFT_REG_VERDICT].verdict = NF_DROP;
+               regs->verdict.code = NF_DROP;
                return;
        }
 
        switch (ret ? 1 : 0) {
        case 1:
-               data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
+               regs->verdict.code = NFT_CONTINUE;
                break;
        case 0:
-               data[NFT_REG_VERDICT].verdict = NFT_BREAK;
+               regs->verdict.code = NFT_BREAK;
                break;
        }
 }
index c89ee486ce54d6d5ba1064970de0c87805bf0dc9..17591239229f75564b944dc7db61e1dae6a2f1f1 100644 (file)
@@ -24,7 +24,7 @@ struct nft_counter {
 };
 
 static void nft_counter_eval(const struct nft_expr *expr,
-                            struct nft_data data[NFT_REG_MAX + 1],
+                            struct nft_regs *regs,
                             const struct nft_pktinfo *pkt)
 {
        struct nft_counter *priv = nft_expr_priv(expr);
@@ -92,6 +92,7 @@ static struct nft_expr_type nft_counter_type __read_mostly = {
        .ops            = &nft_counter_ops,
        .policy         = nft_counter_policy,
        .maxattr        = NFTA_COUNTER_MAX,
+       .flags          = NFT_EXPR_STATEFUL,
        .owner          = THIS_MODULE,
 };
 
index 18d520e0ca0a73cadeb8cb8efa2565e1169e9980..8cbca3432f90324f8a28df2bd67da88cdaf72b12 100644 (file)
@@ -31,11 +31,11 @@ struct nft_ct {
 };
 
 static void nft_ct_get_eval(const struct nft_expr *expr,
-                           struct nft_data data[NFT_REG_MAX + 1],
+                           struct nft_regs *regs,
                            const struct nft_pktinfo *pkt)
 {
        const struct nft_ct *priv = nft_expr_priv(expr);
-       struct nft_data *dest = &data[priv->dreg];
+       u32 *dest = &regs->data[priv->dreg];
        enum ip_conntrack_info ctinfo;
        const struct nf_conn *ct;
        const struct nf_conn_help *help;
@@ -54,7 +54,7 @@ static void nft_ct_get_eval(const struct nft_expr *expr,
                        state = NF_CT_STATE_UNTRACKED_BIT;
                else
                        state = NF_CT_STATE_BIT(ctinfo);
-               dest->data[0] = state;
+               *dest = state;
                return;
        default:
                break;
@@ -65,26 +65,26 @@ static void nft_ct_get_eval(const struct nft_expr *expr,
 
        switch (priv->key) {
        case NFT_CT_DIRECTION:
-               dest->data[0] = CTINFO2DIR(ctinfo);
+               *dest = CTINFO2DIR(ctinfo);
                return;
        case NFT_CT_STATUS:
-               dest->data[0] = ct->status;
+               *dest = ct->status;
                return;
 #ifdef CONFIG_NF_CONNTRACK_MARK
        case NFT_CT_MARK:
-               dest->data[0] = ct->mark;
+               *dest = ct->mark;
                return;
 #endif
 #ifdef CONFIG_NF_CONNTRACK_SECMARK
        case NFT_CT_SECMARK:
-               dest->data[0] = ct->secmark;
+               *dest = ct->secmark;
                return;
 #endif
        case NFT_CT_EXPIRATION:
                diff = (long)jiffies - (long)ct->timeout.expires;
                if (diff < 0)
                        diff = 0;
-               dest->data[0] = jiffies_to_msecs(diff);
+               *dest = jiffies_to_msecs(diff);
                return;
        case NFT_CT_HELPER:
                if (ct->master == NULL)
@@ -95,9 +95,7 @@ static void nft_ct_get_eval(const struct nft_expr *expr,
                helper = rcu_dereference(help->helper);
                if (helper == NULL)
                        goto err;
-               if (strlen(helper->name) >= sizeof(dest->data))
-                       goto err;
-               strncpy((char *)dest->data, helper->name, sizeof(dest->data));
+               strncpy((char *)dest, helper->name, NF_CT_HELPER_NAME_LEN);
                return;
 #ifdef CONFIG_NF_CONNTRACK_LABELS
        case NFT_CT_LABELS: {
@@ -105,17 +103,15 @@ static void nft_ct_get_eval(const struct nft_expr *expr,
                unsigned int size;
 
                if (!labels) {
-                       memset(dest->data, 0, sizeof(dest->data));
+                       memset(dest, 0, NF_CT_LABELS_MAX_SIZE);
                        return;
                }
 
-               BUILD_BUG_ON(NF_CT_LABELS_MAX_SIZE > sizeof(dest->data));
                size = labels->words * sizeof(long);
-
-               memcpy(dest->data, labels->bits, size);
-               if (size < sizeof(dest->data))
-                       memset(((char *) dest->data) + size, 0,
-                              sizeof(dest->data) - size);
+               memcpy(dest, labels->bits, size);
+               if (size < NF_CT_LABELS_MAX_SIZE)
+                       memset(((char *) dest) + size, 0,
+                              NF_CT_LABELS_MAX_SIZE - size);
                return;
        }
 #endif
@@ -126,41 +122,41 @@ static void nft_ct_get_eval(const struct nft_expr *expr,
        tuple = &ct->tuplehash[priv->dir].tuple;
        switch (priv->key) {
        case NFT_CT_L3PROTOCOL:
-               dest->data[0] = nf_ct_l3num(ct);
+               *dest = nf_ct_l3num(ct);
                return;
        case NFT_CT_SRC:
-               memcpy(dest->data, tuple->src.u3.all,
+               memcpy(dest, tuple->src.u3.all,
                       nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16);
                return;
        case NFT_CT_DST:
-               memcpy(dest->data, tuple->dst.u3.all,
+               memcpy(dest, tuple->dst.u3.all,
                       nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16);
                return;
        case NFT_CT_PROTOCOL:
-               dest->data[0] = nf_ct_protonum(ct);
+               *dest = nf_ct_protonum(ct);
                return;
        case NFT_CT_PROTO_SRC:
-               dest->data[0] = (__force __u16)tuple->src.u.all;
+               *dest = (__force __u16)tuple->src.u.all;
                return;
        case NFT_CT_PROTO_DST:
-               dest->data[0] = (__force __u16)tuple->dst.u.all;
+               *dest = (__force __u16)tuple->dst.u.all;
                return;
        default:
                break;
        }
        return;
 err:
-       data[NFT_REG_VERDICT].verdict = NFT_BREAK;
+       regs->verdict.code = NFT_BREAK;
 }
 
 static void nft_ct_set_eval(const struct nft_expr *expr,
-                           struct nft_data data[NFT_REG_MAX + 1],
+                           struct nft_regs *regs,
                            const struct nft_pktinfo *pkt)
 {
        const struct nft_ct *priv = nft_expr_priv(expr);
        struct sk_buff *skb = pkt->skb;
 #ifdef CONFIG_NF_CONNTRACK_MARK
-       u32 value = data[priv->sreg].data[0];
+       u32 value = regs->data[priv->sreg];
 #endif
        enum ip_conntrack_info ctinfo;
        struct nf_conn *ct;
@@ -228,12 +224,17 @@ static int nft_ct_get_init(const struct nft_ctx *ctx,
                           const struct nlattr * const tb[])
 {
        struct nft_ct *priv = nft_expr_priv(expr);
+       unsigned int len;
        int err;
 
        priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
        switch (priv->key) {
-       case NFT_CT_STATE:
        case NFT_CT_DIRECTION:
+               if (tb[NFTA_CT_DIRECTION] != NULL)
+                       return -EINVAL;
+               len = sizeof(u8);
+               break;
+       case NFT_CT_STATE:
        case NFT_CT_STATUS:
 #ifdef CONFIG_NF_CONNTRACK_MARK
        case NFT_CT_MARK:
@@ -241,22 +242,54 @@ static int nft_ct_get_init(const struct nft_ctx *ctx,
 #ifdef CONFIG_NF_CONNTRACK_SECMARK
        case NFT_CT_SECMARK:
 #endif
+       case NFT_CT_EXPIRATION:
+               if (tb[NFTA_CT_DIRECTION] != NULL)
+                       return -EINVAL;
+               len = sizeof(u32);
+               break;
 #ifdef CONFIG_NF_CONNTRACK_LABELS
        case NFT_CT_LABELS:
+               if (tb[NFTA_CT_DIRECTION] != NULL)
+                       return -EINVAL;
+               len = NF_CT_LABELS_MAX_SIZE;
+               break;
 #endif
-       case NFT_CT_EXPIRATION:
        case NFT_CT_HELPER:
                if (tb[NFTA_CT_DIRECTION] != NULL)
                        return -EINVAL;
+               len = NF_CT_HELPER_NAME_LEN;
                break;
+
        case NFT_CT_L3PROTOCOL:
        case NFT_CT_PROTOCOL:
+               if (tb[NFTA_CT_DIRECTION] == NULL)
+                       return -EINVAL;
+               len = sizeof(u8);
+               break;
        case NFT_CT_SRC:
        case NFT_CT_DST:
+               if (tb[NFTA_CT_DIRECTION] == NULL)
+                       return -EINVAL;
+
+               switch (ctx->afi->family) {
+               case NFPROTO_IPV4:
+                       len = FIELD_SIZEOF(struct nf_conntrack_tuple,
+                                          src.u3.ip);
+                       break;
+               case NFPROTO_IPV6:
+               case NFPROTO_INET:
+                       len = FIELD_SIZEOF(struct nf_conntrack_tuple,
+                                          src.u3.ip6);
+                       break;
+               default:
+                       return -EAFNOSUPPORT;
+               }
+               break;
        case NFT_CT_PROTO_SRC:
        case NFT_CT_PROTO_DST:
                if (tb[NFTA_CT_DIRECTION] == NULL)
                        return -EINVAL;
+               len = FIELD_SIZEOF(struct nf_conntrack_tuple, src.u.all);
                break;
        default:
                return -EOPNOTSUPP;
@@ -273,12 +306,9 @@ static int nft_ct_get_init(const struct nft_ctx *ctx,
                }
        }
 
-       priv->dreg = ntohl(nla_get_be32(tb[NFTA_CT_DREG]));
-       err = nft_validate_output_register(priv->dreg);
-       if (err < 0)
-               return err;
-
-       err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
+       priv->dreg = nft_parse_register(tb[NFTA_CT_DREG]);
+       err = nft_validate_register_store(ctx, priv->dreg, NULL,
+                                         NFT_DATA_VALUE, len);
        if (err < 0)
                return err;
 
@@ -294,20 +324,22 @@ static int nft_ct_set_init(const struct nft_ctx *ctx,
                           const struct nlattr * const tb[])
 {
        struct nft_ct *priv = nft_expr_priv(expr);
+       unsigned int len;
        int err;
 
        priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
        switch (priv->key) {
 #ifdef CONFIG_NF_CONNTRACK_MARK
        case NFT_CT_MARK:
+               len = FIELD_SIZEOF(struct nf_conn, mark);
                break;
 #endif
        default:
                return -EOPNOTSUPP;
        }
 
-       priv->sreg = ntohl(nla_get_be32(tb[NFTA_CT_SREG]));
-       err = nft_validate_input_register(priv->sreg);
+       priv->sreg = nft_parse_register(tb[NFTA_CT_SREG]);
+       err = nft_validate_register_load(priv->sreg, len);
        if (err < 0)
                return err;
 
@@ -328,7 +360,7 @@ static int nft_ct_get_dump(struct sk_buff *skb, const struct nft_expr *expr)
 {
        const struct nft_ct *priv = nft_expr_priv(expr);
 
-       if (nla_put_be32(skb, NFTA_CT_DREG, htonl(priv->dreg)))
+       if (nft_dump_register(skb, NFTA_CT_DREG, priv->dreg))
                goto nla_put_failure;
        if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key)))
                goto nla_put_failure;
@@ -355,7 +387,7 @@ static int nft_ct_set_dump(struct sk_buff *skb, const struct nft_expr *expr)
 {
        const struct nft_ct *priv = nft_expr_priv(expr);
 
-       if (nla_put_be32(skb, NFTA_CT_SREG, htonl(priv->sreg)))
+       if (nft_dump_register(skb, NFTA_CT_SREG, priv->sreg))
                goto nla_put_failure;
        if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key)))
                goto nla_put_failure;
index eeb72dee78ef0d92b65886fb90a8ce1983a60f3b..513a8ef60a5922526eaa7f59fbc5abf1bb0552ba 100644 (file)
@@ -23,13 +23,15 @@ struct nft_dynset {
        enum nft_registers              sreg_key:8;
        enum nft_registers              sreg_data:8;
        u64                             timeout;
+       struct nft_expr                 *expr;
        struct nft_set_binding          binding;
 };
 
 static void *nft_dynset_new(struct nft_set *set, const struct nft_expr *expr,
-                           struct nft_data data[NFT_REG_MAX + 1])
+                           struct nft_regs *regs)
 {
        const struct nft_dynset *priv = nft_expr_priv(expr);
+       struct nft_set_ext *ext;
        u64 timeout;
        void *elem;
 
@@ -38,35 +40,51 @@ static void *nft_dynset_new(struct nft_set *set, const struct nft_expr *expr,
 
        timeout = priv->timeout ? : set->timeout;
        elem = nft_set_elem_init(set, &priv->tmpl,
-                                &data[priv->sreg_key], &data[priv->sreg_data],
+                                &regs->data[priv->sreg_key],
+                                &regs->data[priv->sreg_data],
                                 timeout, GFP_ATOMIC);
        if (elem == NULL) {
                if (set->size)
                        atomic_dec(&set->nelems);
+               return NULL;
        }
+
+       ext = nft_set_elem_ext(set, elem);
+       if (priv->expr != NULL)
+               nft_expr_clone(nft_set_ext_expr(ext), priv->expr);
+
        return elem;
 }
 
 static void nft_dynset_eval(const struct nft_expr *expr,
-                           struct nft_data data[NFT_REG_MAX + 1],
+                           struct nft_regs *regs,
                            const struct nft_pktinfo *pkt)
 {
        const struct nft_dynset *priv = nft_expr_priv(expr);
        struct nft_set *set = priv->set;
        const struct nft_set_ext *ext;
+       const struct nft_expr *sexpr;
        u64 timeout;
 
-       if (set->ops->update(set, &data[priv->sreg_key], nft_dynset_new,
-                            expr, data, &ext)) {
+       if (set->ops->update(set, &regs->data[priv->sreg_key], nft_dynset_new,
+                            expr, regs, &ext)) {
+               sexpr = NULL;
+               if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPR))
+                       sexpr = nft_set_ext_expr(ext);
+
                if (priv->op == NFT_DYNSET_OP_UPDATE &&
                    nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION)) {
                        timeout = priv->timeout ? : set->timeout;
                        *nft_set_ext_expiration(ext) = jiffies + timeout;
-                       return;
-               }
-       }
+               } else if (sexpr == NULL)
+                       goto out;
 
-       data[NFT_REG_VERDICT].verdict = NFT_BREAK;
+               if (sexpr != NULL)
+                       sexpr->ops->eval(sexpr, regs, pkt);
+               return;
+       }
+out:
+       regs->verdict.code = NFT_BREAK;
 }
 
 static const struct nla_policy nft_dynset_policy[NFTA_DYNSET_MAX + 1] = {
@@ -76,6 +94,7 @@ static const struct nla_policy nft_dynset_policy[NFTA_DYNSET_MAX + 1] = {
        [NFTA_DYNSET_SREG_KEY]  = { .type = NLA_U32 },
        [NFTA_DYNSET_SREG_DATA] = { .type = NLA_U32 },
        [NFTA_DYNSET_TIMEOUT]   = { .type = NLA_U64 },
+       [NFTA_DYNSET_EXPR]      = { .type = NLA_NESTED },
 };
 
 static int nft_dynset_init(const struct nft_ctx *ctx,
@@ -123,8 +142,8 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
                timeout = be64_to_cpu(nla_get_be64(tb[NFTA_DYNSET_TIMEOUT]));
        }
 
-       priv->sreg_key = ntohl(nla_get_be32(tb[NFTA_DYNSET_SREG_KEY]));
-       err = nft_validate_input_register(priv->sreg_key);
+       priv->sreg_key = nft_parse_register(tb[NFTA_DYNSET_SREG_KEY]);
+       err = nft_validate_register_load(priv->sreg_key, set->klen);;
        if (err < 0)
                return err;
 
@@ -134,17 +153,36 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
                if (set->dtype == NFT_DATA_VERDICT)
                        return -EOPNOTSUPP;
 
-               priv->sreg_data = ntohl(nla_get_be32(tb[NFTA_DYNSET_SREG_DATA]));
-               err = nft_validate_input_register(priv->sreg_data);
+               priv->sreg_data = nft_parse_register(tb[NFTA_DYNSET_SREG_DATA]);
+               err = nft_validate_register_load(priv->sreg_data, set->dlen);
                if (err < 0)
                        return err;
        } else if (set->flags & NFT_SET_MAP)
                return -EINVAL;
 
+       if (tb[NFTA_DYNSET_EXPR] != NULL) {
+               if (!(set->flags & NFT_SET_EVAL))
+                       return -EINVAL;
+               if (!(set->flags & NFT_SET_ANONYMOUS))
+                       return -EOPNOTSUPP;
+
+               priv->expr = nft_expr_init(ctx, tb[NFTA_DYNSET_EXPR]);
+               if (IS_ERR(priv->expr))
+                       return PTR_ERR(priv->expr);
+
+               err = -EOPNOTSUPP;
+               if (!(priv->expr->ops->type->flags & NFT_EXPR_STATEFUL))
+                       goto err1;
+       } else if (set->flags & NFT_SET_EVAL)
+               return -EINVAL;
+
        nft_set_ext_prepare(&priv->tmpl);
        nft_set_ext_add_length(&priv->tmpl, NFT_SET_EXT_KEY, set->klen);
        if (set->flags & NFT_SET_MAP)
                nft_set_ext_add_length(&priv->tmpl, NFT_SET_EXT_DATA, set->dlen);
+       if (priv->expr != NULL)
+               nft_set_ext_add_length(&priv->tmpl, NFT_SET_EXT_EXPR,
+                                      priv->expr->ops->size);
        if (set->flags & NFT_SET_TIMEOUT) {
                if (timeout || set->timeout)
                        nft_set_ext_add(&priv->tmpl, NFT_SET_EXT_EXPIRATION);
@@ -154,10 +192,15 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
 
        err = nf_tables_bind_set(ctx, set, &priv->binding);
        if (err < 0)
-               return err;
+               goto err1;
 
        priv->set = set;
        return 0;
+
+err1:
+       if (priv->expr != NULL)
+               nft_expr_destroy(ctx, priv->expr);
+       return err;
 }
 
 static void nft_dynset_destroy(const struct nft_ctx *ctx,
@@ -166,16 +209,18 @@ static void nft_dynset_destroy(const struct nft_ctx *ctx,
        struct nft_dynset *priv = nft_expr_priv(expr);
 
        nf_tables_unbind_set(ctx, priv->set, &priv->binding);
+       if (priv->expr != NULL)
+               nft_expr_destroy(ctx, priv->expr);
 }
 
 static int nft_dynset_dump(struct sk_buff *skb, const struct nft_expr *expr)
 {
        const struct nft_dynset *priv = nft_expr_priv(expr);
 
-       if (nla_put_be32(skb, NFTA_DYNSET_SREG_KEY, htonl(priv->sreg_key)))
+       if (nft_dump_register(skb, NFTA_DYNSET_SREG_KEY, priv->sreg_key))
                goto nla_put_failure;
        if (priv->set->flags & NFT_SET_MAP &&
-           nla_put_be32(skb, NFTA_DYNSET_SREG_DATA, htonl(priv->sreg_data)))
+           nft_dump_register(skb, NFTA_DYNSET_SREG_DATA, priv->sreg_data))
                goto nla_put_failure;
        if (nla_put_be32(skb, NFTA_DYNSET_OP, htonl(priv->op)))
                goto nla_put_failure;
@@ -183,6 +228,8 @@ static int nft_dynset_dump(struct sk_buff *skb, const struct nft_expr *expr)
                goto nla_put_failure;
        if (nla_put_be64(skb, NFTA_DYNSET_TIMEOUT, cpu_to_be64(priv->timeout)))
                goto nla_put_failure;
+       if (priv->expr && nft_expr_dump(skb, NFTA_DYNSET_EXPR, priv->expr))
+               goto nla_put_failure;
        return 0;
 
 nla_put_failure:
diff --git a/net/netfilter/nft_expr_template.c b/net/netfilter/nft_expr_template.c
deleted file mode 100644 (file)
index b6eed4d..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Development of this code funded by Astaro AG (http://www.astaro.com/)
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/netlink.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter/nf_tables.h>
-#include <net/netfilter/nf_tables.h>
-
-struct nft_template {
-
-};
-
-static void nft_template_eval(const struct nft_expr *expr,
-                             struct nft_data data[NFT_REG_MAX + 1],
-                             const struct nft_pktinfo *pkt)
-{
-       struct nft_template *priv = nft_expr_priv(expr);
-
-}
-
-static const struct nla_policy nft_template_policy[NFTA_TEMPLATE_MAX + 1] = {
-       [NFTA_TEMPLATE_ATTR]            = { .type = NLA_U32 },
-};
-
-static int nft_template_init(const struct nft_ctx *ctx,
-                          const struct nft_expr *expr,
-                          const struct nlattr * const tb[])
-{
-       struct nft_template *priv = nft_expr_priv(expr);
-
-       return 0;
-}
-
-static void nft_template_destroy(const struct nft_ctx *ctx,
-                              const struct nft_expr *expr)
-{
-       struct nft_template *priv = nft_expr_priv(expr);
-
-}
-
-static int nft_template_dump(struct sk_buff *skb, const struct nft_expr *expr)
-{
-       const struct nft_template *priv = nft_expr_priv(expr);
-
-       NLA_PUT_BE32(skb, NFTA_TEMPLATE_ATTR, priv->field);
-       return 0;
-
-nla_put_failure:
-       return -1;
-}
-
-static struct nft_expr_type nft_template_type;
-static const struct nft_expr_ops nft_template_ops = {
-       .type           = &nft_template_type,
-       .size           = NFT_EXPR_SIZE(sizeof(struct nft_template)),
-       .eval           = nft_template_eval,
-       .init           = nft_template_init,
-       .destroy        = nft_template_destroy,
-       .dump           = nft_template_dump,
-};
-
-static struct nft_expr_type nft_template_type __read_mostly = {
-       .name           = "template",
-       .ops            = &nft_template_ops,
-       .policy         = nft_template_policy,
-       .maxattr        = NFTA_TEMPLATE_MAX,
-       .owner          = THIS_MODULE,
-};
-
-static int __init nft_template_module_init(void)
-{
-       return nft_register_expr(&nft_template_type);
-}
-
-static void __exit nft_template_module_exit(void)
-{
-       nft_unregister_expr(&nft_template_type);
-}
-
-module_init(nft_template_module_init);
-module_exit(nft_template_module_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
-MODULE_ALIAS_NFT_EXPR("template");
index 55c939f5371fabf35ad996efb51ea52a29630703..ba7aed13e1749442d3add6fde2e6b377fd1ad39d 100644 (file)
@@ -26,11 +26,11 @@ struct nft_exthdr {
 };
 
 static void nft_exthdr_eval(const struct nft_expr *expr,
-                           struct nft_data data[NFT_REG_MAX + 1],
+                           struct nft_regs *regs,
                            const struct nft_pktinfo *pkt)
 {
        struct nft_exthdr *priv = nft_expr_priv(expr);
-       struct nft_data *dest = &data[priv->dreg];
+       u32 *dest = &regs->data[priv->dreg];
        unsigned int offset = 0;
        int err;
 
@@ -39,11 +39,12 @@ static void nft_exthdr_eval(const struct nft_expr *expr,
                goto err;
        offset += priv->offset;
 
-       if (skb_copy_bits(pkt->skb, offset, dest->data, priv->len) < 0)
+       dest[priv->len / NFT_REG32_SIZE] = 0;
+       if (skb_copy_bits(pkt->skb, offset, dest, priv->len) < 0)
                goto err;
        return;
 err:
-       data[NFT_REG_VERDICT].verdict = NFT_BREAK;
+       regs->verdict.code = NFT_BREAK;
 }
 
 static const struct nla_policy nft_exthdr_policy[NFTA_EXTHDR_MAX + 1] = {
@@ -58,7 +59,6 @@ static int nft_exthdr_init(const struct nft_ctx *ctx,
                           const struct nlattr * const tb[])
 {
        struct nft_exthdr *priv = nft_expr_priv(expr);
-       int err;
 
        if (tb[NFTA_EXTHDR_DREG] == NULL ||
            tb[NFTA_EXTHDR_TYPE] == NULL ||
@@ -69,22 +69,17 @@ static int nft_exthdr_init(const struct nft_ctx *ctx,
        priv->type   = nla_get_u8(tb[NFTA_EXTHDR_TYPE]);
        priv->offset = ntohl(nla_get_be32(tb[NFTA_EXTHDR_OFFSET]));
        priv->len    = ntohl(nla_get_be32(tb[NFTA_EXTHDR_LEN]));
-       if (priv->len == 0 ||
-           priv->len > FIELD_SIZEOF(struct nft_data, data))
-               return -EINVAL;
+       priv->dreg   = nft_parse_register(tb[NFTA_EXTHDR_DREG]);
 
-       priv->dreg = ntohl(nla_get_be32(tb[NFTA_EXTHDR_DREG]));
-       err = nft_validate_output_register(priv->dreg);
-       if (err < 0)
-               return err;
-       return nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
+       return nft_validate_register_store(ctx, priv->dreg, NULL,
+                                          NFT_DATA_VALUE, priv->len);
 }
 
 static int nft_exthdr_dump(struct sk_buff *skb, const struct nft_expr *expr)
 {
        const struct nft_exthdr *priv = nft_expr_priv(expr);
 
-       if (nla_put_be32(skb, NFTA_EXTHDR_DREG, htonl(priv->dreg)))
+       if (nft_dump_register(skb, NFTA_EXTHDR_DREG, priv->dreg))
                goto nla_put_failure;
        if (nla_put_u8(skb, NFTA_EXTHDR_TYPE, priv->type))
                goto nla_put_failure;
index bc23806b7fbef29005dbb9d4adc35ae4d76ff16e..3f9d45d3d9b7260c3f01842bcbb2a2d2191ee5c0 100644 (file)
@@ -36,7 +36,7 @@ struct nft_hash_elem {
 
 struct nft_hash_cmp_arg {
        const struct nft_set            *set;
-       const struct nft_data           *key;
+       const u32                       *key;
        u8                              genmask;
 };
 
@@ -62,7 +62,7 @@ static inline int nft_hash_cmp(struct rhashtable_compare_arg *arg,
        const struct nft_hash_cmp_arg *x = arg->key;
        const struct nft_hash_elem *he = ptr;
 
-       if (nft_data_cmp(nft_set_ext_key(&he->ext), x->key, x->set->klen))
+       if (memcmp(nft_set_ext_key(&he->ext), x->key, x->set->klen))
                return 1;
        if (nft_set_elem_expired(&he->ext))
                return 1;
@@ -71,8 +71,7 @@ static inline int nft_hash_cmp(struct rhashtable_compare_arg *arg,
        return 0;
 }
 
-static bool nft_hash_lookup(const struct nft_set *set,
-                           const struct nft_data *key,
+static bool nft_hash_lookup(const struct nft_set *set, const u32 *key,
                            const struct nft_set_ext **ext)
 {
        struct nft_hash *priv = nft_set_priv(set);
@@ -90,12 +89,12 @@ static bool nft_hash_lookup(const struct nft_set *set,
        return !!he;
 }
 
-static bool nft_hash_update(struct nft_set *set, const struct nft_data *key,
+static bool nft_hash_update(struct nft_set *set, const u32 *key,
                            void *(*new)(struct nft_set *,
                                         const struct nft_expr *,
-                                        struct nft_data []),
+                                        struct nft_regs *regs),
                            const struct nft_expr *expr,
-                           struct nft_data data[],
+                           struct nft_regs *regs,
                            const struct nft_set_ext **ext)
 {
        struct nft_hash *priv = nft_set_priv(set);
@@ -110,7 +109,7 @@ static bool nft_hash_update(struct nft_set *set, const struct nft_data *key,
        if (he != NULL)
                goto out;
 
-       he = new(set, expr, data);
+       he = new(set, expr, regs);
        if (he == NULL)
                goto err1;
        if (rhashtable_lookup_insert_key(&priv->ht, &arg, &he->node,
@@ -134,7 +133,7 @@ static int nft_hash_insert(const struct nft_set *set,
        struct nft_hash_cmp_arg arg = {
                .genmask = nft_genmask_next(read_pnet(&set->pnet)),
                .set     = set,
-               .key     = &elem->key,
+               .key     = elem->key.val.data,
        };
 
        return rhashtable_lookup_insert_key(&priv->ht, &arg, &he->node,
@@ -158,7 +157,7 @@ static void *nft_hash_deactivate(const struct nft_set *set,
        struct nft_hash_cmp_arg arg = {
                .genmask = nft_genmask_next(read_pnet(&set->pnet)),
                .set     = set,
-               .key     = &elem->key,
+               .key     = elem->key.val.data,
        };
 
        rcu_read_lock();
index 810385eb7249c7be39bcbc0e6c34abc1a6b1708d..db3b746858e35a008ad0668f42e6037e36e1f80e 100644 (file)
@@ -24,12 +24,12 @@ struct nft_immediate_expr {
 };
 
 static void nft_immediate_eval(const struct nft_expr *expr,
-                              struct nft_data data[NFT_REG_MAX + 1],
+                              struct nft_regs *regs,
                               const struct nft_pktinfo *pkt)
 {
        const struct nft_immediate_expr *priv = nft_expr_priv(expr);
 
-       nft_data_copy(&data[priv->dreg], &priv->data);
+       nft_data_copy(&regs->data[priv->dreg], &priv->data, priv->dlen);
 }
 
 static const struct nla_policy nft_immediate_policy[NFTA_IMMEDIATE_MAX + 1] = {
@@ -49,17 +49,15 @@ static int nft_immediate_init(const struct nft_ctx *ctx,
            tb[NFTA_IMMEDIATE_DATA] == NULL)
                return -EINVAL;
 
-       priv->dreg = ntohl(nla_get_be32(tb[NFTA_IMMEDIATE_DREG]));
-       err = nft_validate_output_register(priv->dreg);
-       if (err < 0)
-               return err;
-
-       err = nft_data_init(ctx, &priv->data, &desc, tb[NFTA_IMMEDIATE_DATA]);
+       err = nft_data_init(ctx, &priv->data, sizeof(priv->data), &desc,
+                           tb[NFTA_IMMEDIATE_DATA]);
        if (err < 0)
                return err;
        priv->dlen = desc.len;
 
-       err = nft_validate_data_load(ctx, priv->dreg, &priv->data, desc.type);
+       priv->dreg = nft_parse_register(tb[NFTA_IMMEDIATE_DREG]);
+       err = nft_validate_register_store(ctx, priv->dreg, &priv->data,
+                                         desc.type, desc.len);
        if (err < 0)
                goto err1;
 
@@ -81,7 +79,7 @@ static int nft_immediate_dump(struct sk_buff *skb, const struct nft_expr *expr)
 {
        const struct nft_immediate_expr *priv = nft_expr_priv(expr);
 
-       if (nla_put_be32(skb, NFTA_IMMEDIATE_DREG, htonl(priv->dreg)))
+       if (nft_dump_register(skb, NFTA_IMMEDIATE_DREG, priv->dreg))
                goto nla_put_failure;
 
        return nft_data_dump(skb, NFTA_IMMEDIATE_DATA, &priv->data,
index 85da5bd02f64fcfebad07d1f6d7ea23d40adb260..435c1ccd6c0e6a74266b2054a62f603d038ecb00 100644 (file)
@@ -27,7 +27,7 @@ struct nft_limit {
 };
 
 static void nft_limit_eval(const struct nft_expr *expr,
-                          struct nft_data data[NFT_REG_MAX + 1],
+                          struct nft_regs *regs,
                           const struct nft_pktinfo *pkt)
 {
        struct nft_limit *priv = nft_expr_priv(expr);
@@ -45,7 +45,7 @@ static void nft_limit_eval(const struct nft_expr *expr,
        }
        spin_unlock_bh(&limit_lock);
 
-       data[NFT_REG_VERDICT].verdict = NFT_BREAK;
+       regs->verdict.code = NFT_BREAK;
 }
 
 static const struct nla_policy nft_limit_policy[NFTA_LIMIT_MAX + 1] = {
@@ -98,6 +98,7 @@ static struct nft_expr_type nft_limit_type __read_mostly = {
        .ops            = &nft_limit_ops,
        .policy         = nft_limit_policy,
        .maxattr        = NFTA_LIMIT_MAX,
+       .flags          = NFT_EXPR_STATEFUL,
        .owner          = THIS_MODULE,
 };
 
index e18af9db2f04ec0a58d4ed563af13f7d253b8f0a..a13d6a386d635f00b5715d1b71ba9b0819203544 100644 (file)
@@ -27,7 +27,7 @@ struct nft_log {
 };
 
 static void nft_log_eval(const struct nft_expr *expr,
-                        struct nft_data data[NFT_REG_MAX + 1],
+                        struct nft_regs *regs,
                         const struct nft_pktinfo *pkt)
 {
        const struct nft_log *priv = nft_expr_priv(expr);
index d8cf86fb30fc33fdf657a03da1320f331bc38c9a..b3c31ef8015d2517f594dc60a027c52aac8d41fe 100644 (file)
@@ -26,19 +26,20 @@ struct nft_lookup {
 };
 
 static void nft_lookup_eval(const struct nft_expr *expr,
-                           struct nft_data data[NFT_REG_MAX + 1],
+                           struct nft_regs *regs,
                            const struct nft_pktinfo *pkt)
 {
        const struct nft_lookup *priv = nft_expr_priv(expr);
        const struct nft_set *set = priv->set;
        const struct nft_set_ext *ext;
 
-       if (set->ops->lookup(set, &data[priv->sreg], &ext)) {
+       if (set->ops->lookup(set, &regs->data[priv->sreg], &ext)) {
                if (set->flags & NFT_SET_MAP)
-                       nft_data_copy(&data[priv->dreg], nft_set_ext_data(ext));
+                       nft_data_copy(&regs->data[priv->dreg],
+                                     nft_set_ext_data(ext), set->dlen);
                return;
        }
-       data[NFT_REG_VERDICT].verdict = NFT_BREAK;
+       regs->verdict.code = NFT_BREAK;
 }
 
 static const struct nla_policy nft_lookup_policy[NFTA_LOOKUP_MAX + 1] = {
@@ -70,8 +71,11 @@ static int nft_lookup_init(const struct nft_ctx *ctx,
                        return PTR_ERR(set);
        }
 
-       priv->sreg = ntohl(nla_get_be32(tb[NFTA_LOOKUP_SREG]));
-       err = nft_validate_input_register(priv->sreg);
+       if (set->flags & NFT_SET_EVAL)
+               return -EOPNOTSUPP;
+
+       priv->sreg = nft_parse_register(tb[NFTA_LOOKUP_SREG]);
+       err = nft_validate_register_load(priv->sreg, set->klen);
        if (err < 0)
                return err;
 
@@ -79,16 +83,11 @@ static int nft_lookup_init(const struct nft_ctx *ctx,
                if (!(set->flags & NFT_SET_MAP))
                        return -EINVAL;
 
-               priv->dreg = ntohl(nla_get_be32(tb[NFTA_LOOKUP_DREG]));
-               err = nft_validate_output_register(priv->dreg);
+               priv->dreg = nft_parse_register(tb[NFTA_LOOKUP_DREG]);
+               err = nft_validate_register_store(ctx, priv->dreg, NULL,
+                                                 set->dtype, set->dlen);
                if (err < 0)
                        return err;
-
-               if (priv->dreg == NFT_REG_VERDICT) {
-                       if (set->dtype != NFT_DATA_VERDICT)
-                               return -EINVAL;
-               } else if (set->dtype == NFT_DATA_VERDICT)
-                       return -EINVAL;
        } else if (set->flags & NFT_SET_MAP)
                return -EINVAL;
 
@@ -116,10 +115,10 @@ static int nft_lookup_dump(struct sk_buff *skb, const struct nft_expr *expr)
 
        if (nla_put_string(skb, NFTA_LOOKUP_SET, priv->set->name))
                goto nla_put_failure;
-       if (nla_put_be32(skb, NFTA_LOOKUP_SREG, htonl(priv->sreg)))
+       if (nft_dump_register(skb, NFTA_LOOKUP_SREG, priv->sreg))
                goto nla_put_failure;
        if (priv->set->flags & NFT_SET_MAP)
-               if (nla_put_be32(skb, NFTA_LOOKUP_DREG, htonl(priv->dreg)))
+               if (nft_dump_register(skb, NFTA_LOOKUP_DREG, priv->dreg))
                        goto nla_put_failure;
        return 0;
 
index d79ce88be77f3568aa9e6409f7de20242d9c343f..52561e1c31e26933dd654f095663c0f0a633f007 100644 (file)
 #include <net/netfilter/nft_meta.h>
 
 void nft_meta_get_eval(const struct nft_expr *expr,
-                      struct nft_data data[NFT_REG_MAX + 1],
+                      struct nft_regs *regs,
                       const struct nft_pktinfo *pkt)
 {
        const struct nft_meta *priv = nft_expr_priv(expr);
        const struct sk_buff *skb = pkt->skb;
        const struct net_device *in = pkt->in, *out = pkt->out;
-       struct nft_data *dest = &data[priv->dreg];
+       u32 *dest = &regs->data[priv->dreg];
 
        switch (priv->key) {
        case NFT_META_LEN:
-               dest->data[0] = skb->len;
+               *dest = skb->len;
                break;
        case NFT_META_PROTOCOL:
-               *(__be16 *)dest->data = skb->protocol;
+               *dest = 0;
+               *(__be16 *)dest = skb->protocol;
                break;
        case NFT_META_NFPROTO:
-               dest->data[0] = pkt->ops->pf;
+               *dest = pkt->ops->pf;
                break;
        case NFT_META_L4PROTO:
-               dest->data[0] = pkt->tprot;
+               *dest = pkt->tprot;
                break;
        case NFT_META_PRIORITY:
-               dest->data[0] = skb->priority;
+               *dest = skb->priority;
                break;
        case NFT_META_MARK:
-               dest->data[0] = skb->mark;
+               *dest = skb->mark;
                break;
        case NFT_META_IIF:
                if (in == NULL)
                        goto err;
-               dest->data[0] = in->ifindex;
+               *dest = in->ifindex;
                break;
        case NFT_META_OIF:
                if (out == NULL)
                        goto err;
-               dest->data[0] = out->ifindex;
+               *dest = out->ifindex;
                break;
        case NFT_META_IIFNAME:
                if (in == NULL)
                        goto err;
-               strncpy((char *)dest->data, in->name, sizeof(dest->data));
+               strncpy((char *)dest, in->name, IFNAMSIZ);
                break;
        case NFT_META_OIFNAME:
                if (out == NULL)
                        goto err;
-               strncpy((char *)dest->data, out->name, sizeof(dest->data));
+               strncpy((char *)dest, out->name, IFNAMSIZ);
                break;
        case NFT_META_IIFTYPE:
                if (in == NULL)
                        goto err;
-               *(u16 *)dest->data = in->type;
+               *dest = 0;
+               *(u16 *)dest = in->type;
                break;
        case NFT_META_OIFTYPE:
                if (out == NULL)
                        goto err;
-               *(u16 *)dest->data = out->type;
+               *dest = 0;
+               *(u16 *)dest = out->type;
                break;
        case NFT_META_SKUID:
                if (skb->sk == NULL || !sk_fullsock(skb->sk))
@@ -93,8 +96,7 @@ void nft_meta_get_eval(const struct nft_expr *expr,
                        goto err;
                }
 
-               dest->data[0] =
-                       from_kuid_munged(&init_user_ns,
+               *dest = from_kuid_munged(&init_user_ns,
                                skb->sk->sk_socket->file->f_cred->fsuid);
                read_unlock_bh(&skb->sk->sk_callback_lock);
                break;
@@ -108,8 +110,7 @@ void nft_meta_get_eval(const struct nft_expr *expr,
                        read_unlock_bh(&skb->sk->sk_callback_lock);
                        goto err;
                }
-               dest->data[0] =
-                       from_kgid_munged(&init_user_ns,
+               *dest = from_kgid_munged(&init_user_ns,
                                 skb->sk->sk_socket->file->f_cred->fsgid);
                read_unlock_bh(&skb->sk->sk_callback_lock);
                break;
@@ -119,33 +120,33 @@ void nft_meta_get_eval(const struct nft_expr *expr,
 
                if (dst == NULL)
                        goto err;
-               dest->data[0] = dst->tclassid;
+               *dest = dst->tclassid;
                break;
        }
 #endif
 #ifdef CONFIG_NETWORK_SECMARK
        case NFT_META_SECMARK:
-               dest->data[0] = skb->secmark;
+               *dest = skb->secmark;
                break;
 #endif
        case NFT_META_PKTTYPE:
                if (skb->pkt_type != PACKET_LOOPBACK) {
-                       dest->data[0] = skb->pkt_type;
+                       *dest = skb->pkt_type;
                        break;
                }
 
                switch (pkt->ops->pf) {
                case NFPROTO_IPV4:
                        if (ipv4_is_multicast(ip_hdr(skb)->daddr))
-                               dest->data[0] = PACKET_MULTICAST;
+                               *dest = PACKET_MULTICAST;
                        else
-                               dest->data[0] = PACKET_BROADCAST;
+                               *dest = PACKET_BROADCAST;
                        break;
                case NFPROTO_IPV6:
                        if (ipv6_hdr(skb)->daddr.s6_addr[0] == 0xFF)
-                               dest->data[0] = PACKET_MULTICAST;
+                               *dest = PACKET_MULTICAST;
                        else
-                               dest->data[0] = PACKET_BROADCAST;
+                               *dest = PACKET_BROADCAST;
                        break;
                default:
                        WARN_ON(1);
@@ -153,22 +154,22 @@ void nft_meta_get_eval(const struct nft_expr *expr,
                }
                break;
        case NFT_META_CPU:
-               dest->data[0] = raw_smp_processor_id();
+               *dest = raw_smp_processor_id();
                break;
        case NFT_META_IIFGROUP:
                if (in == NULL)
                        goto err;
-               dest->data[0] = in->group;
+               *dest = in->group;
                break;
        case NFT_META_OIFGROUP:
                if (out == NULL)
                        goto err;
-               dest->data[0] = out->group;
+               *dest = out->group;
                break;
        case NFT_META_CGROUP:
                if (skb->sk == NULL || !sk_fullsock(skb->sk))
                        goto err;
-               dest->data[0] = skb->sk->sk_classid;
+               *dest = skb->sk->sk_classid;
                break;
        default:
                WARN_ON(1);
@@ -177,17 +178,17 @@ void nft_meta_get_eval(const struct nft_expr *expr,
        return;
 
 err:
-       data[NFT_REG_VERDICT].verdict = NFT_BREAK;
+       regs->verdict.code = NFT_BREAK;
 }
 EXPORT_SYMBOL_GPL(nft_meta_get_eval);
 
 void nft_meta_set_eval(const struct nft_expr *expr,
-                      struct nft_data data[NFT_REG_MAX + 1],
+                      struct nft_regs *regs,
                       const struct nft_pktinfo *pkt)
 {
        const struct nft_meta *meta = nft_expr_priv(expr);
        struct sk_buff *skb = pkt->skb;
-       u32 value = data[meta->sreg].data[0];
+       u32 value = regs->data[meta->sreg];
 
        switch (meta->key) {
        case NFT_META_MARK:
@@ -217,22 +218,22 @@ int nft_meta_get_init(const struct nft_ctx *ctx,
                      const struct nlattr * const tb[])
 {
        struct nft_meta *priv = nft_expr_priv(expr);
-       int err;
+       unsigned int len;
 
        priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
        switch (priv->key) {
-       case NFT_META_LEN:
        case NFT_META_PROTOCOL:
+       case NFT_META_IIFTYPE:
+       case NFT_META_OIFTYPE:
+               len = sizeof(u16);
+               break;
        case NFT_META_NFPROTO:
        case NFT_META_L4PROTO:
+       case NFT_META_LEN:
        case NFT_META_PRIORITY:
        case NFT_META_MARK:
        case NFT_META_IIF:
        case NFT_META_OIF:
-       case NFT_META_IIFNAME:
-       case NFT_META_OIFNAME:
-       case NFT_META_IIFTYPE:
-       case NFT_META_OIFTYPE:
        case NFT_META_SKUID:
        case NFT_META_SKGID:
 #ifdef CONFIG_IP_ROUTE_CLASSID
@@ -246,21 +247,19 @@ int nft_meta_get_init(const struct nft_ctx *ctx,
        case NFT_META_IIFGROUP:
        case NFT_META_OIFGROUP:
        case NFT_META_CGROUP:
+               len = sizeof(u32);
+               break;
+       case NFT_META_IIFNAME:
+       case NFT_META_OIFNAME:
+               len = IFNAMSIZ;
                break;
        default:
                return -EOPNOTSUPP;
        }
 
-       priv->dreg = ntohl(nla_get_be32(tb[NFTA_META_DREG]));
-       err = nft_validate_output_register(priv->dreg);
-       if (err < 0)
-               return err;
-
-       err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
-       if (err < 0)
-               return err;
-
-       return 0;
+       priv->dreg = nft_parse_register(tb[NFTA_META_DREG]);
+       return nft_validate_register_store(ctx, priv->dreg, NULL,
+                                          NFT_DATA_VALUE, len);
 }
 EXPORT_SYMBOL_GPL(nft_meta_get_init);
 
@@ -269,20 +268,24 @@ int nft_meta_set_init(const struct nft_ctx *ctx,
                      const struct nlattr * const tb[])
 {
        struct nft_meta *priv = nft_expr_priv(expr);
+       unsigned int len;
        int err;
 
        priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
        switch (priv->key) {
        case NFT_META_MARK:
        case NFT_META_PRIORITY:
+               len = sizeof(u32);
+               break;
        case NFT_META_NFTRACE:
+               len = sizeof(u8);
                break;
        default:
                return -EOPNOTSUPP;
        }
 
-       priv->sreg = ntohl(nla_get_be32(tb[NFTA_META_SREG]));
-       err = nft_validate_input_register(priv->sreg);
+       priv->sreg = nft_parse_register(tb[NFTA_META_SREG]);
+       err = nft_validate_register_load(priv->sreg, len);
        if (err < 0)
                return err;
 
@@ -297,7 +300,7 @@ int nft_meta_get_dump(struct sk_buff *skb,
 
        if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key)))
                goto nla_put_failure;
-       if (nla_put_be32(skb, NFTA_META_DREG, htonl(priv->dreg)))
+       if (nft_dump_register(skb, NFTA_META_DREG, priv->dreg))
                goto nla_put_failure;
        return 0;
 
@@ -313,7 +316,7 @@ int nft_meta_set_dump(struct sk_buff *skb,
 
        if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key)))
                goto nla_put_failure;
-       if (nla_put_be32(skb, NFTA_META_SREG, htonl(priv->sreg)))
+       if (nft_dump_register(skb, NFTA_META_SREG, priv->sreg))
                goto nla_put_failure;
 
        return 0;
index a0837c6c9283dc90b043750ffe1d7217c95ab239..ee2d71753746d0dc074bcf327b25de4791f821e9 100644 (file)
@@ -37,7 +37,7 @@ struct nft_nat {
 };
 
 static void nft_nat_eval(const struct nft_expr *expr,
-                        struct nft_data data[NFT_REG_MAX + 1],
+                        struct nft_regs *regs,
                         const struct nft_pktinfo *pkt)
 {
        const struct nft_nat *priv = nft_expr_priv(expr);
@@ -49,33 +49,32 @@ static void nft_nat_eval(const struct nft_expr *expr,
        if (priv->sreg_addr_min) {
                if (priv->family == AF_INET) {
                        range.min_addr.ip = (__force __be32)
-                                       data[priv->sreg_addr_min].data[0];
+                                       regs->data[priv->sreg_addr_min];
                        range.max_addr.ip = (__force __be32)
-                                       data[priv->sreg_addr_max].data[0];
+                                       regs->data[priv->sreg_addr_max];
 
                } else {
                        memcpy(range.min_addr.ip6,
-                              data[priv->sreg_addr_min].data,
-                              sizeof(struct nft_data));
+                              &regs->data[priv->sreg_addr_min],
+                              sizeof(range.min_addr.ip6));
                        memcpy(range.max_addr.ip6,
-                              data[priv->sreg_addr_max].data,
-                              sizeof(struct nft_data));
+                              &regs->data[priv->sreg_addr_max],
+                              sizeof(range.max_addr.ip6));
                }
                range.flags |= NF_NAT_RANGE_MAP_IPS;
        }
 
        if (priv->sreg_proto_min) {
                range.min_proto.all =
-                       *(__be16 *)&data[priv->sreg_proto_min].data[0];
+                       *(__be16 *)&regs->data[priv->sreg_proto_min];
                range.max_proto.all =
-                       *(__be16 *)&data[priv->sreg_proto_max].data[0];
+                       *(__be16 *)&regs->data[priv->sreg_proto_max];
                range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
        }
 
        range.flags |= priv->flags;
 
-       data[NFT_REG_VERDICT].verdict =
-               nf_nat_setup_info(ct, &range, priv->type);
+       regs->verdict.code = nf_nat_setup_info(ct, &range, priv->type);
 }
 
 static const struct nla_policy nft_nat_policy[NFTA_NAT_MAX + 1] = {
@@ -119,6 +118,7 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
                        const struct nlattr * const tb[])
 {
        struct nft_nat *priv = nft_expr_priv(expr);
+       unsigned int alen, plen;
        u32 family;
        int err;
 
@@ -146,25 +146,34 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
                return -EINVAL;
 
        family = ntohl(nla_get_be32(tb[NFTA_NAT_FAMILY]));
-       if (family != AF_INET && family != AF_INET6)
-               return -EAFNOSUPPORT;
        if (family != ctx->afi->family)
                return -EOPNOTSUPP;
+
+       switch (family) {
+       case NFPROTO_IPV4:
+               alen = FIELD_SIZEOF(struct nf_nat_range, min_addr.ip);
+               break;
+       case NFPROTO_IPV6:
+               alen = FIELD_SIZEOF(struct nf_nat_range, min_addr.ip6);
+               break;
+       default:
+               return -EAFNOSUPPORT;
+       }
        priv->family = family;
 
        if (tb[NFTA_NAT_REG_ADDR_MIN]) {
                priv->sreg_addr_min =
-                       ntohl(nla_get_be32(tb[NFTA_NAT_REG_ADDR_MIN]));
-
-               err = nft_validate_input_register(priv->sreg_addr_min);
+                       nft_parse_register(tb[NFTA_NAT_REG_ADDR_MIN]);
+               err = nft_validate_register_load(priv->sreg_addr_min, alen);
                if (err < 0)
                        return err;
 
                if (tb[NFTA_NAT_REG_ADDR_MAX]) {
                        priv->sreg_addr_max =
-                               ntohl(nla_get_be32(tb[NFTA_NAT_REG_ADDR_MAX]));
+                               nft_parse_register(tb[NFTA_NAT_REG_ADDR_MAX]);
 
-                       err = nft_validate_input_register(priv->sreg_addr_max);
+                       err = nft_validate_register_load(priv->sreg_addr_max,
+                                                        alen);
                        if (err < 0)
                                return err;
                } else {
@@ -172,19 +181,21 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
                }
        }
 
+       plen = FIELD_SIZEOF(struct nf_nat_range, min_addr.all);
        if (tb[NFTA_NAT_REG_PROTO_MIN]) {
                priv->sreg_proto_min =
-                       ntohl(nla_get_be32(tb[NFTA_NAT_REG_PROTO_MIN]));
+                       nft_parse_register(tb[NFTA_NAT_REG_PROTO_MIN]);
 
-               err = nft_validate_input_register(priv->sreg_proto_min);
+               err = nft_validate_register_load(priv->sreg_proto_min, plen);
                if (err < 0)
                        return err;
 
                if (tb[NFTA_NAT_REG_PROTO_MAX]) {
                        priv->sreg_proto_max =
-                               ntohl(nla_get_be32(tb[NFTA_NAT_REG_PROTO_MAX]));
+                               nft_parse_register(tb[NFTA_NAT_REG_PROTO_MAX]);
 
-                       err = nft_validate_input_register(priv->sreg_proto_max);
+                       err = nft_validate_register_load(priv->sreg_proto_max,
+                                                        plen);
                        if (err < 0)
                                return err;
                } else {
@@ -220,18 +231,18 @@ static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr)
                goto nla_put_failure;
 
        if (priv->sreg_addr_min) {
-               if (nla_put_be32(skb, NFTA_NAT_REG_ADDR_MIN,
-                                htonl(priv->sreg_addr_min)) ||
-                   nla_put_be32(skb, NFTA_NAT_REG_ADDR_MAX,
-                                htonl(priv->sreg_addr_max)))
+               if (nft_dump_register(skb, NFTA_NAT_REG_ADDR_MIN,
+                                     priv->sreg_addr_min) ||
+                   nft_dump_register(skb, NFTA_NAT_REG_ADDR_MAX,
+                                     priv->sreg_addr_max))
                        goto nla_put_failure;
        }
 
        if (priv->sreg_proto_min) {
-               if (nla_put_be32(skb, NFTA_NAT_REG_PROTO_MIN,
-                                htonl(priv->sreg_proto_min)) ||
-                   nla_put_be32(skb, NFTA_NAT_REG_PROTO_MAX,
-                                htonl(priv->sreg_proto_max)))
+               if (nft_dump_register(skb, NFTA_NAT_REG_PROTO_MIN,
+                                     priv->sreg_proto_min) ||
+                   nft_dump_register(skb, NFTA_NAT_REG_PROTO_MAX,
+                                     priv->sreg_proto_max))
                        goto nla_put_failure;
        }
 
index 85daa84bfdfee3d65296fb62c723a78e180c4497..94fb3b27a2c54393091602e0e96b2634ff8ceb1b 100644 (file)
 #include <net/netfilter/nf_tables.h>
 
 static void nft_payload_eval(const struct nft_expr *expr,
-                            struct nft_data data[NFT_REG_MAX + 1],
+                            struct nft_regs *regs,
                             const struct nft_pktinfo *pkt)
 {
        const struct nft_payload *priv = nft_expr_priv(expr);
        const struct sk_buff *skb = pkt->skb;
-       struct nft_data *dest = &data[priv->dreg];
+       u32 *dest = &regs->data[priv->dreg];
        int offset;
 
        switch (priv->base) {
@@ -43,11 +43,12 @@ static void nft_payload_eval(const struct nft_expr *expr,
        }
        offset += priv->offset;
 
-       if (skb_copy_bits(skb, offset, dest->data, priv->len) < 0)
+       dest[priv->len / NFT_REG32_SIZE] = 0;
+       if (skb_copy_bits(skb, offset, dest, priv->len) < 0)
                goto err;
        return;
 err:
-       data[NFT_REG_VERDICT].verdict = NFT_BREAK;
+       regs->verdict.code = NFT_BREAK;
 }
 
 static const struct nla_policy nft_payload_policy[NFTA_PAYLOAD_MAX + 1] = {
@@ -62,24 +63,21 @@ static int nft_payload_init(const struct nft_ctx *ctx,
                            const struct nlattr * const tb[])
 {
        struct nft_payload *priv = nft_expr_priv(expr);
-       int err;
 
        priv->base   = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_BASE]));
        priv->offset = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_OFFSET]));
        priv->len    = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN]));
+       priv->dreg   = nft_parse_register(tb[NFTA_PAYLOAD_DREG]);
 
-       priv->dreg = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_DREG]));
-       err = nft_validate_output_register(priv->dreg);
-       if (err < 0)
-               return err;
-       return nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
+       return nft_validate_register_store(ctx, priv->dreg, NULL,
+                                          NFT_DATA_VALUE, priv->len);
 }
 
 static int nft_payload_dump(struct sk_buff *skb, const struct nft_expr *expr)
 {
        const struct nft_payload *priv = nft_expr_priv(expr);
 
-       if (nla_put_be32(skb, NFTA_PAYLOAD_DREG, htonl(priv->dreg)) ||
+       if (nft_dump_register(skb, NFTA_PAYLOAD_DREG, priv->dreg) ||
            nla_put_be32(skb, NFTA_PAYLOAD_BASE, htonl(priv->base)) ||
            nla_put_be32(skb, NFTA_PAYLOAD_OFFSET, htonl(priv->offset)) ||
            nla_put_be32(skb, NFTA_PAYLOAD_LEN, htonl(priv->len)))
@@ -131,9 +129,7 @@ nft_payload_select_ops(const struct nft_ctx *ctx,
        }
 
        offset = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_OFFSET]));
-       len = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN]));
-       if (len == 0 || len > FIELD_SIZEOF(struct nft_data, data))
-               return ERR_PTR(-EINVAL);
+       len    = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN]));
 
        if (len <= 4 && is_power_of_2(len) && IS_ALIGNED(offset, len) &&
            base != NFT_PAYLOAD_LL_HEADER)
index e8ae2f6bf232d8ccef7379f9bb573291da5581b4..96805d21d618b7be7f0b802e4738d4d2afa6de7f 100644 (file)
@@ -28,7 +28,7 @@ struct nft_queue {
 };
 
 static void nft_queue_eval(const struct nft_expr *expr,
-                          struct nft_data data[NFT_REG_MAX + 1],
+                          struct nft_regs *regs,
                           const struct nft_pktinfo *pkt)
 {
        struct nft_queue *priv = nft_expr_priv(expr);
@@ -51,7 +51,7 @@ static void nft_queue_eval(const struct nft_expr *expr,
        if (priv->flags & NFT_QUEUE_FLAG_BYPASS)
                ret |= NF_VERDICT_FLAG_QUEUE_BYPASS;
 
-       data[NFT_REG_VERDICT].verdict = ret;
+       regs->verdict.code = ret;
 }
 
 static const struct nla_policy nft_queue_policy[NFTA_QUEUE_MAX + 1] = {
index 42d0ca45fb9e9e64daf3799aad420f205c5586e0..1c30f41cff5b44c5059e159fe269ed33aea3b824 100644 (file)
@@ -30,8 +30,7 @@ struct nft_rbtree_elem {
 };
 
 
-static bool nft_rbtree_lookup(const struct nft_set *set,
-                             const struct nft_data *key,
+static bool nft_rbtree_lookup(const struct nft_set *set, const u32 *key,
                              const struct nft_set_ext **ext)
 {
        const struct nft_rbtree *priv = nft_set_priv(set);
@@ -45,7 +44,7 @@ static bool nft_rbtree_lookup(const struct nft_set *set,
        while (parent != NULL) {
                rbe = rb_entry(parent, struct nft_rbtree_elem, node);
 
-               d = nft_data_cmp(nft_set_ext_key(&rbe->ext), key, set->klen);
+               d = memcmp(nft_set_ext_key(&rbe->ext), key, set->klen);
                if (d < 0) {
                        parent = parent->rb_left;
                        interval = rbe;
@@ -91,9 +90,9 @@ static int __nft_rbtree_insert(const struct nft_set *set,
        while (*p != NULL) {
                parent = *p;
                rbe = rb_entry(parent, struct nft_rbtree_elem, node);
-               d = nft_data_cmp(nft_set_ext_key(&rbe->ext),
-                                nft_set_ext_key(&new->ext),
-                                set->klen);
+               d = memcmp(nft_set_ext_key(&rbe->ext),
+                          nft_set_ext_key(&new->ext),
+                          set->klen);
                if (d < 0)
                        p = &parent->rb_left;
                else if (d > 0)
@@ -153,8 +152,8 @@ static void *nft_rbtree_deactivate(const struct nft_set *set,
        while (parent != NULL) {
                rbe = rb_entry(parent, struct nft_rbtree_elem, node);
 
-               d = nft_data_cmp(nft_set_ext_key(&rbe->ext), &elem->key,
-                                set->klen);
+               d = memcmp(nft_set_ext_key(&rbe->ext), &elem->key.val,
+                                          set->klen);
                if (d < 0)
                        parent = parent->rb_left;
                else if (d > 0)
index d7e9e93a4e90f498f7a002c33840c928a3ab17e2..03f7bf40ae752d3c8d48425abc5611e4a2af2b63 100644 (file)
@@ -44,25 +44,28 @@ int nft_redir_init(const struct nft_ctx *ctx,
                   const struct nlattr * const tb[])
 {
        struct nft_redir *priv = nft_expr_priv(expr);
+       unsigned int plen;
        int err;
 
        err = nft_redir_validate(ctx, expr, NULL);
        if (err < 0)
                return err;
 
+       plen = FIELD_SIZEOF(struct nf_nat_range, min_addr.all);
        if (tb[NFTA_REDIR_REG_PROTO_MIN]) {
                priv->sreg_proto_min =
-                       ntohl(nla_get_be32(tb[NFTA_REDIR_REG_PROTO_MIN]));
+                       nft_parse_register(tb[NFTA_REDIR_REG_PROTO_MIN]);
 
-               err = nft_validate_input_register(priv->sreg_proto_min);
+               err = nft_validate_register_load(priv->sreg_proto_min, plen);
                if (err < 0)
                        return err;
 
                if (tb[NFTA_REDIR_REG_PROTO_MAX]) {
                        priv->sreg_proto_max =
-                               ntohl(nla_get_be32(tb[NFTA_REDIR_REG_PROTO_MAX]));
+                               nft_parse_register(tb[NFTA_REDIR_REG_PROTO_MAX]);
 
-                       err = nft_validate_input_register(priv->sreg_proto_max);
+                       err = nft_validate_register_load(priv->sreg_proto_max,
+                                                        plen);
                        if (err < 0)
                                return err;
                } else {
@@ -85,11 +88,11 @@ int nft_redir_dump(struct sk_buff *skb, const struct nft_expr *expr)
        const struct nft_redir *priv = nft_expr_priv(expr);
 
        if (priv->sreg_proto_min) {
-               if (nla_put_be32(skb, NFTA_REDIR_REG_PROTO_MIN,
-                                htonl(priv->sreg_proto_min)))
+               if (nft_dump_register(skb, NFTA_REDIR_REG_PROTO_MIN,
+                                     priv->sreg_proto_min))
                        goto nla_put_failure;
-               if (nla_put_be32(skb, NFTA_REDIR_REG_PROTO_MAX,
-                                htonl(priv->sreg_proto_max)))
+               if (nft_dump_register(skb, NFTA_REDIR_REG_PROTO_MAX,
+                                     priv->sreg_proto_max))
                        goto nla_put_failure;
        }
 
index 92877114aff4634b99c0c14d74d7043487bf31cc..62cabee42fbecc93587a0b008b19913a5a8470f9 100644 (file)
@@ -18,7 +18,7 @@
 #include <net/netfilter/ipv6/nf_reject.h>
 
 static void nft_reject_inet_eval(const struct nft_expr *expr,
-                                struct nft_data data[NFT_REG_MAX + 1],
+                                struct nft_regs *regs,
                                 const struct nft_pktinfo *pkt)
 {
        struct nft_reject *priv = nft_expr_priv(expr);
@@ -58,7 +58,8 @@ static void nft_reject_inet_eval(const struct nft_expr *expr,
                }
                break;
        }
-       data[NFT_REG_VERDICT].verdict = NF_DROP;
+
+       regs->verdict.code = NF_DROP;
 }
 
 static int nft_reject_inet_init(const struct nft_ctx *ctx,