Commit bae97d84 authored by David S. Miller's avatar David S. Miller

Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 87ffabb1 97bb43c3
...@@ -12,9 +12,10 @@ ...@@ -12,9 +12,10 @@
#ifndef __LINUX_BRIDGE_EFF_H #ifndef __LINUX_BRIDGE_EFF_H
#define __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> #include <uapi/linux/netfilter_bridge/ebtables.h>
/* return values for match() functions */ /* return values for match() functions */
#define EBT_MATCH 0 #define EBT_MATCH 0
#define EBT_NOMATCH 1 #define EBT_NOMATCH 1
......
#ifndef _NET_NF_TABLES_H #ifndef _NET_NF_TABLES_H
#define _NET_NF_TABLES_H #define _NET_NF_TABLES_H
#include <linux/module.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/netfilter.h> #include <linux/netfilter.h>
#include <linux/netfilter/nfnetlink.h> #include <linux/netfilter/nfnetlink.h>
...@@ -36,29 +37,43 @@ static inline void nft_set_pktinfo(struct nft_pktinfo *pkt, ...@@ -36,29 +37,43 @@ static inline void nft_set_pktinfo(struct nft_pktinfo *pkt,
pkt->xt.family = ops->pf; 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 { struct nft_data {
union { union {
u32 data[4]; u32 data[4];
struct { struct nft_verdict verdict;
u32 verdict;
struct nft_chain *chain;
};
}; };
} __attribute__((aligned(__alignof__(u64)))); } __attribute__((aligned(__alignof__(u64))));
static inline int nft_data_cmp(const struct nft_data *d1, /**
const struct nft_data *d2, * struct nft_regs - nf_tables register set
unsigned int len) *
{ * @data: data registers
return memcmp(d1->data, d2->data, len); * @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, static inline void nft_data_copy(u32 *dst, const struct nft_data *src,
const struct nft_data *src) unsigned int len)
{ {
BUILD_BUG_ON(__alignof__(*dst) != __alignof__(u64)); memcpy(dst, src, len);
*(u64 *)&dst->data[0] = *(u64 *)&src->data[0];
*(u64 *)&dst->data[2] = *(u64 *)&src->data[2];
} }
static inline void nft_data_debug(const struct nft_data *data) static inline void nft_data_debug(const struct nft_data *data)
...@@ -96,7 +111,8 @@ struct nft_data_desc { ...@@ -96,7 +111,8 @@ struct nft_data_desc {
unsigned int len; 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); struct nft_data_desc *desc, const struct nlattr *nla);
void nft_data_uninit(const struct nft_data *data, enum nft_data_types type); 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, 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) ...@@ -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; return type == NFT_DATA_VERDICT ? NFT_REG_VERDICT : NFT_REG_1;
} }
int nft_validate_input_register(enum nft_registers reg); unsigned int nft_parse_register(const struct nlattr *attr);
int nft_validate_output_register(enum nft_registers reg); int nft_dump_register(struct sk_buff *skb, unsigned int attr, unsigned int 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);
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 * struct nft_userdata - user defined data associated with an object
...@@ -141,7 +159,10 @@ struct nft_userdata { ...@@ -141,7 +159,10 @@ struct nft_userdata {
* @priv: element private data and extensions * @priv: element private data and extensions
*/ */
struct nft_set_elem { struct nft_set_elem {
struct nft_data key; union {
u32 buf[NFT_DATA_VALUE_MAXLEN / sizeof(u32)];
struct nft_data val;
} key;
void *priv; void *priv;
}; };
...@@ -216,15 +237,15 @@ struct nft_expr; ...@@ -216,15 +237,15 @@ struct nft_expr;
*/ */
struct nft_set_ops { struct nft_set_ops {
bool (*lookup)(const struct nft_set *set, bool (*lookup)(const struct nft_set *set,
const struct nft_data *key, const u32 *key,
const struct nft_set_ext **ext); const struct nft_set_ext **ext);
bool (*update)(struct nft_set *set, bool (*update)(struct nft_set *set,
const struct nft_data *key, const u32 *key,
void *(*new)(struct nft_set *, void *(*new)(struct nft_set *,
const struct nft_expr *, const struct nft_expr *,
struct nft_data []), struct nft_regs *),
const struct nft_expr *expr, const struct nft_expr *expr,
struct nft_data data[], struct nft_regs *regs,
const struct nft_set_ext **ext); const struct nft_set_ext **ext);
int (*insert)(const struct nft_set *set, 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, ...@@ -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_TIMEOUT: element timeout
* @NFT_SET_EXT_EXPIRATION: element expiration time * @NFT_SET_EXT_EXPIRATION: element expiration time
* @NFT_SET_EXT_USERDATA: user data associated with the element * @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 * @NFT_SET_EXT_NUM: number of extension types
*/ */
enum nft_set_extensions { enum nft_set_extensions {
...@@ -359,6 +381,7 @@ enum nft_set_extensions { ...@@ -359,6 +381,7 @@ enum nft_set_extensions {
NFT_SET_EXT_TIMEOUT, NFT_SET_EXT_TIMEOUT,
NFT_SET_EXT_EXPIRATION, NFT_SET_EXT_EXPIRATION,
NFT_SET_EXT_USERDATA, NFT_SET_EXT_USERDATA,
NFT_SET_EXT_EXPR,
NFT_SET_EXT_NUM NFT_SET_EXT_NUM
}; };
...@@ -470,6 +493,11 @@ static inline struct nft_userdata *nft_set_ext_userdata(const struct nft_set_ext ...@@ -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); 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) static inline bool nft_set_elem_expired(const struct nft_set_ext *ext)
{ {
return nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION) && 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, ...@@ -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, void *nft_set_elem_init(const struct nft_set *set,
const struct nft_set_ext_tmpl *tmpl, const struct nft_set_ext_tmpl *tmpl,
const struct nft_data *key, const u32 *key, const u32 *data,
const struct nft_data *data,
u64 timeout, gfp_t gfp); u64 timeout, gfp_t gfp);
void nft_set_elem_destroy(const struct nft_set *set, void *elem); 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, ...@@ -556,6 +583,7 @@ static inline void nft_set_gc_batch_add(struct nft_set_gc_batch *gcb,
* @policy: netlink attribute policy * @policy: netlink attribute policy
* @maxattr: highest netlink attribute number * @maxattr: highest netlink attribute number
* @family: address family for AF-specific types * @family: address family for AF-specific types
* @flags: expression type flags
*/ */
struct nft_expr_type { struct nft_expr_type {
const struct nft_expr_ops *(*select_ops)(const struct nft_ctx *, const struct nft_expr_ops *(*select_ops)(const struct nft_ctx *,
...@@ -567,8 +595,11 @@ struct nft_expr_type { ...@@ -567,8 +595,11 @@ struct nft_expr_type {
const struct nla_policy *policy; const struct nla_policy *policy;
unsigned int maxattr; unsigned int maxattr;
u8 family; u8 family;
u8 flags;
}; };
#define NFT_EXPR_STATEFUL 0x1
/** /**
* struct nft_expr_ops - nf_tables expression operations * struct nft_expr_ops - nf_tables expression operations
* *
...@@ -584,7 +615,7 @@ struct nft_expr_type { ...@@ -584,7 +615,7 @@ struct nft_expr_type {
struct nft_expr; struct nft_expr;
struct nft_expr_ops { struct nft_expr_ops {
void (*eval)(const struct nft_expr *expr, void (*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_pktinfo *pkt);
unsigned int size; unsigned int size;
...@@ -622,6 +653,18 @@ static inline void *nft_expr_priv(const struct nft_expr *expr) ...@@ -622,6 +653,18 @@ static inline void *nft_expr_priv(const struct nft_expr *expr)
return (void *)expr->data; 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 * struct nft_rule - nf_tables rule
* *
......
...@@ -26,11 +26,11 @@ int nft_meta_set_dump(struct sk_buff *skb, ...@@ -26,11 +26,11 @@ int nft_meta_set_dump(struct sk_buff *skb,
const struct nft_expr *expr); const struct nft_expr *expr);
void nft_meta_get_eval(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); const struct nft_pktinfo *pkt);
void nft_meta_set_eval(const struct nft_expr *expr, 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_pktinfo *pkt);
#endif #endif
...@@ -5,16 +5,45 @@ ...@@ -5,16 +5,45 @@
#define NFT_CHAIN_MAXNAMELEN 32 #define NFT_CHAIN_MAXNAMELEN 32
#define NFT_USERDATA_MAXLEN 256 #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 { enum nft_registers {
NFT_REG_VERDICT, NFT_REG_VERDICT,
NFT_REG_1, NFT_REG_1,
NFT_REG_2, NFT_REG_2,
NFT_REG_3, NFT_REG_3,
NFT_REG_4, 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_MAX (__NFT_REG_MAX - 1)
#define NFT_REG_SIZE 16
#define NFT_REG32_SIZE 4
/** /**
* enum nft_verdicts - nf_tables internal verdicts * enum nft_verdicts - nf_tables internal verdicts
* *
...@@ -209,6 +238,7 @@ enum nft_rule_compat_attributes { ...@@ -209,6 +238,7 @@ enum nft_rule_compat_attributes {
* @NFT_SET_INTERVAL: set contains intervals * @NFT_SET_INTERVAL: set contains intervals
* @NFT_SET_MAP: set is used as a dictionary * @NFT_SET_MAP: set is used as a dictionary
* @NFT_SET_TIMEOUT: set uses timeouts * @NFT_SET_TIMEOUT: set uses timeouts
* @NFT_SET_EVAL: set contains expressions for evaluation
*/ */
enum nft_set_flags { enum nft_set_flags {
NFT_SET_ANONYMOUS = 0x1, NFT_SET_ANONYMOUS = 0x1,
...@@ -216,6 +246,7 @@ enum nft_set_flags { ...@@ -216,6 +246,7 @@ enum nft_set_flags {
NFT_SET_INTERVAL = 0x4, NFT_SET_INTERVAL = 0x4,
NFT_SET_MAP = 0x8, NFT_SET_MAP = 0x8,
NFT_SET_TIMEOUT = 0x10, NFT_SET_TIMEOUT = 0x10,
NFT_SET_EVAL = 0x20,
}; };
/** /**
...@@ -293,6 +324,7 @@ enum nft_set_elem_flags { ...@@ -293,6 +324,7 @@ enum nft_set_elem_flags {
* @NFTA_SET_ELEM_TIMEOUT: timeout value (NLA_U64) * @NFTA_SET_ELEM_TIMEOUT: timeout value (NLA_U64)
* @NFTA_SET_ELEM_EXPIRATION: expiration time (NLA_U64) * @NFTA_SET_ELEM_EXPIRATION: expiration time (NLA_U64)
* @NFTA_SET_ELEM_USERDATA: user data (NLA_BINARY) * @NFTA_SET_ELEM_USERDATA: user data (NLA_BINARY)
* @NFTA_SET_ELEM_EXPR: expression (NLA_NESTED: nft_expr_attributes)
*/ */
enum nft_set_elem_attributes { enum nft_set_elem_attributes {
NFTA_SET_ELEM_UNSPEC, NFTA_SET_ELEM_UNSPEC,
...@@ -302,6 +334,7 @@ enum nft_set_elem_attributes { ...@@ -302,6 +334,7 @@ enum nft_set_elem_attributes {
NFTA_SET_ELEM_TIMEOUT, NFTA_SET_ELEM_TIMEOUT,
NFTA_SET_ELEM_EXPIRATION, NFTA_SET_ELEM_EXPIRATION,
NFTA_SET_ELEM_USERDATA, NFTA_SET_ELEM_USERDATA,
NFTA_SET_ELEM_EXPR,
__NFTA_SET_ELEM_MAX __NFTA_SET_ELEM_MAX
}; };
#define NFTA_SET_ELEM_MAX (__NFTA_SET_ELEM_MAX - 1) #define NFTA_SET_ELEM_MAX (__NFTA_SET_ELEM_MAX - 1)
...@@ -359,6 +392,9 @@ enum nft_data_attributes { ...@@ -359,6 +392,9 @@ enum nft_data_attributes {
}; };
#define NFTA_DATA_MAX (__NFTA_DATA_MAX - 1) #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 * enum nft_verdict_attributes - nf_tables verdict netlink attributes
* *
...@@ -531,6 +567,7 @@ enum nft_dynset_ops { ...@@ -531,6 +567,7 @@ enum nft_dynset_ops {
* @NFTA_DYNSET_SREG_KEY: source register of the key (NLA_U32) * @NFTA_DYNSET_SREG_KEY: source register of the key (NLA_U32)
* @NFTA_DYNSET_SREG_DATA: source register of the data (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_TIMEOUT: timeout value for the new element (NLA_U64)
* @NFTA_DYNSET_EXPR: expression (NLA_NESTED: nft_expr_attributes)
*/ */
enum nft_dynset_attributes { enum nft_dynset_attributes {
NFTA_DYNSET_UNSPEC, NFTA_DYNSET_UNSPEC,
...@@ -540,6 +577,7 @@ enum nft_dynset_attributes { ...@@ -540,6 +577,7 @@ enum nft_dynset_attributes {
NFTA_DYNSET_SREG_KEY, NFTA_DYNSET_SREG_KEY,
NFTA_DYNSET_SREG_DATA, NFTA_DYNSET_SREG_DATA,
NFTA_DYNSET_TIMEOUT, NFTA_DYNSET_TIMEOUT,
NFTA_DYNSET_EXPR,
__NFTA_DYNSET_MAX, __NFTA_DYNSET_MAX,
}; };
#define NFTA_DYNSET_MAX (__NFTA_DYNSET_MAX - 1) #define NFTA_DYNSET_MAX (__NFTA_DYNSET_MAX - 1)
......
...@@ -12,9 +12,7 @@ ...@@ -12,9 +12,7 @@
#ifndef _UAPI__LINUX_BRIDGE_EFF_H #ifndef _UAPI__LINUX_BRIDGE_EFF_H
#define _UAPI__LINUX_BRIDGE_EFF_H #define _UAPI__LINUX_BRIDGE_EFF_H
#include <linux/if.h>
#include <linux/netfilter_bridge.h> #include <linux/netfilter_bridge.h>
#include <linux/if_ether.h>
#define EBT_TABLE_MAXNAMELEN 32 #define EBT_TABLE_MAXNAMELEN 32
#define EBT_CHAIN_MAXNAMELEN EBT_TABLE_MAXNAMELEN #define EBT_CHAIN_MAXNAMELEN EBT_TABLE_MAXNAMELEN
......
...@@ -19,12 +19,12 @@ ...@@ -19,12 +19,12 @@
#include "../br_private.h" #include "../br_private.h"
static void nft_meta_bridge_get_eval(const struct nft_expr *expr, 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_pktinfo *pkt)
{ {
const struct nft_meta *priv = nft_expr_priv(expr); const struct nft_meta *priv = nft_expr_priv(expr);
const struct net_device *in = pkt->in, *out = pkt->out; 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; const struct net_bridge_port *p;
switch (priv->key) { switch (priv->key) {
...@@ -40,12 +40,12 @@ static void nft_meta_bridge_get_eval(const struct nft_expr *expr, ...@@ -40,12 +40,12 @@ static void nft_meta_bridge_get_eval(const struct nft_expr *expr,
goto out; goto out;
} }
strncpy((char *)dest->data, p->br->dev->name, sizeof(dest->data)); strncpy((char *)dest, p->br->dev->name, IFNAMSIZ);
return; return;
out: out:
return nft_meta_get_eval(expr, data, pkt); return nft_meta_get_eval(expr, regs, pkt);
err: 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, 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, ...@@ -53,27 +53,21 @@ static int nft_meta_bridge_get_init(const struct nft_ctx *ctx,
const struct nlattr * const tb[]) const struct nlattr * const tb[])
{ {
struct nft_meta *priv = nft_expr_priv(expr); struct nft_meta *priv = nft_expr_priv(expr);
int err; unsigned int len;
priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY])); priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
switch (priv->key) { switch (priv->key) {
case NFT_META_BRI_IIFNAME: case NFT_META_BRI_IIFNAME:
case NFT_META_BRI_OIFNAME: case NFT_META_BRI_OIFNAME:
len = IFNAMSIZ;
break; break;
default: default:
return nft_meta_get_init(ctx, expr, tb); return nft_meta_get_init(ctx, expr, tb);
} }
priv->dreg = ntohl(nla_get_be32(tb[NFTA_META_DREG])); priv->dreg = nft_parse_register(tb[NFTA_META_DREG]);
err = nft_validate_output_register(priv->dreg); return nft_validate_register_store(ctx, priv->dreg, NULL,
if (err < 0) NFT_DATA_VALUE, len);
return err;
err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
if (err < 0)
return err;
return 0;
} }
static struct nft_expr_type nft_meta_bridge_type; static struct nft_expr_type nft_meta_bridge_type;
......
...@@ -257,8 +257,8 @@ static void nft_reject_br_send_v6_unreach(struct net *net, ...@@ -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, static void nft_reject_bridge_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_pktinfo *pkt)
{ {
struct nft_reject *priv = nft_expr_priv(expr); struct nft_reject *priv = nft_expr_priv(expr);
struct net *net = dev_net((pkt->in != NULL) ? pkt->in : pkt->out); 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, ...@@ -310,7 +310,7 @@ static void nft_reject_bridge_eval(const struct nft_expr *expr,
break; break;
} }
out: out:
data[NFT_REG_VERDICT].verdict = NF_DROP; regs->verdict.code = NF_DROP;
} }
static int nft_reject_bridge_validate(const struct nft_ctx *ctx, static int nft_reject_bridge_validate(const struct nft_ctx *ctx,
......
...@@ -17,20 +17,17 @@ ...@@ -17,20 +17,17 @@
#include <net/netfilter/ipv4/nf_nat_masquerade.h> #include <net/netfilter/ipv4/nf_nat_masquerade.h>
static void nft_masq_ipv4_eval(const struct nft_expr *expr, 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) const struct nft_pktinfo *pkt)
{ {
struct nft_masq *priv = nft_expr_priv(expr); struct nft_masq *priv = nft_expr_priv(expr);
struct nf_nat_range range; struct nf_nat_range range;
unsigned int verdict;
memset(&range, 0, sizeof(range)); memset(&range, 0, sizeof(range));
range.flags = priv->flags; range.flags = priv->flags;
verdict = nf_nat_masquerade_ipv4(pkt->skb, pkt->ops->hooknum, regs->verdict.code = nf_nat_masquerade_ipv4(pkt->skb, pkt->ops->hooknum,
&range, pkt->out); &range, pkt->out);
data[NFT_REG_VERDICT].verdict = verdict;
} }
static struct nft_expr_type nft_masq_ipv4_type; static struct nft_expr_type nft_masq_ipv4_type;
......
...@@ -18,26 +18,25 @@ ...@@ -18,26 +18,25 @@
#include <net/netfilter/nft_redir.h> #include <net/netfilter/nft_redir.h>
static void nft_redir_ipv4_eval(const struct nft_expr *expr, 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) const struct nft_pktinfo *pkt)
{ {
struct nft_redir *priv = nft_expr_priv(expr); struct nft_redir *priv = nft_expr_priv(expr);
struct nf_nat_ipv4_multi_range_compat mr; struct nf_nat_ipv4_multi_range_compat mr;
unsigned int verdict;
memset(&mr, 0, sizeof(mr)); memset(&mr, 0, sizeof(mr));
if (priv->sreg_proto_min) { if (priv->sreg_proto_min) {
mr.range[0].min.all = 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 = 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 |= NF_NAT_RANGE_PROTO_SPECIFIED;
} }
mr.range[0].flags |= priv->flags; mr.range[0].flags |= priv->flags;
verdict = nf_nat_redirect_ipv4(pkt->skb, &mr, pkt->ops->hooknum); regs->verdict.code = nf_nat_redirect_ipv4(pkt->skb, &mr,
data[NFT_REG_VERDICT].verdict = verdict; pkt->ops->hooknum);
} }
static struct nft_expr_type nft_redir_ipv4_type; static struct nft_expr_type nft_redir_ipv4_type;
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#include <net/netfilter/nft_reject.h> #include <net/netfilter/nft_reject.h>
static void nft_reject_ipv4_eval(const struct nft_expr *expr, 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) const struct nft_pktinfo *pkt)
{ {
struct nft_reject *priv = nft_expr_priv(expr); struct nft_reject *priv = nft_expr_priv(expr);
...@@ -37,7 +37,7 @@ static void nft_reject_ipv4_eval(const struct nft_expr *expr, ...@@ -37,7 +37,7 @@ static void nft_reject_ipv4_eval(const struct nft_expr *expr,
break; break;
} }
data[NFT_REG_VERDICT].verdict = NF_DROP; regs->verdict.code = NF_DROP;
} }
static struct nft_expr_type nft_reject_ipv4_type; static struct nft_expr_type nft_reject_ipv4_type;
......
...@@ -18,19 +18,16 @@ ...@@ -18,19 +18,16 @@
#include <net/netfilter/ipv6/nf_nat_masquerade.h> #include <net/netfilter/ipv6/nf_nat_masquerade.h>
static void nft_masq_ipv6_eval(const struct nft_expr *expr, 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) const struct nft_pktinfo *pkt)
{ {
struct nft_masq *priv = nft_expr_priv(expr); struct nft_masq *priv = nft_expr_priv(expr);
struct nf_nat_range range; struct nf_nat_range range;
unsigned int verdict;
memset(&range, 0, sizeof(range)); memset(&range, 0, sizeof(range));
range.flags = priv->flags; range.flags = priv->flags;
verdict = nf_nat_masquerade_ipv6(pkt->skb, &range, pkt->out); regs->verdict.code = nf_nat_masquerade_ipv6(pkt->skb, &range, pkt->out);
data[NFT_REG_VERDICT].verdict = verdict;
} }
static struct nft_expr_type nft_masq_ipv6_type; static struct nft_expr_type nft_masq_ipv6_type;
......
...@@ -18,26 +18,25 @@ ...@@ -18,26 +18,25 @@
#include <net/netfilter/nf_nat_redirect.h> #include <net/netfilter/nf_nat_redirect.h>
static void nft_redir_ipv6_eval(const struct nft_expr *expr, 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) const struct nft_pktinfo *pkt)
{ {
struct nft_redir *priv = nft_expr_priv(expr); struct nft_redir *priv = nft_expr_priv(expr);
struct nf_nat_range range; struct nf_nat_range range;
unsigned int verdict;
memset(&range, 0, sizeof(range)); memset(&range, 0, sizeof(range));
if (priv->sreg_proto_min) { if (priv->sreg_proto_min) {
range.min_proto.all = range.min_proto.all =
*(__be16 *)&data[priv->sreg_proto_min].data[0]; *(__be16 *)&regs->data[priv->sreg_proto_min],
range.max_proto.all = 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 |= NF_NAT_RANGE_PROTO_SPECIFIED;
} }
range.flags |= priv->flags; range.flags |= priv->flags;
verdict = nf_nat_redirect_ipv6(pkt->skb, &range, pkt->ops->hooknum); regs->verdict.code = nf_nat_redirect_ipv6(pkt->skb, &range,
data[NFT_REG_VERDICT].verdict = verdict; pkt->ops->hooknum);
} }
static struct nft_expr_type nft_redir_ipv6_type; static struct nft_expr_type nft_redir_ipv6_type;
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#include <net/netfilter/ipv6/nf_reject.h> #include <net/netfilter/ipv6/nf_reject.h>
static void nft_reject_ipv6_eval(const struct nft_expr *expr, 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) const struct nft_pktinfo *pkt)
{ {
struct nft_reject *priv = nft_expr_priv(expr); struct nft_reject *priv = nft_expr_priv(expr);
...@@ -38,7 +38,7 @@ static void nft_reject_ipv6_eval(const struct nft_expr *expr, ...@@ -38,7 +38,7 @@ static void nft_reject_ipv6_eval(const struct nft_expr *expr,
break; break;
} }
data[NFT_REG_VERDICT].verdict = NF_DROP; regs->verdict.code = NF_DROP;
} }
static struct nft_expr_type nft_reject_ipv6_type; static struct nft_expr_type nft_reject_ipv6_type;
......
This diff is collapsed.
...@@ -65,23 +65,23 @@ static inline void nft_trace_packet(const struct nft_pktinfo *pkt, ...@@ -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, 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); const struct nft_cmp_fast_expr *priv = nft_expr_priv(expr);
u32 mask = nft_cmp_fast_mask(priv->len); 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; return;
data[NFT_REG_VERDICT].verdict = NFT_BREAK; regs->verdict.code = NFT_BREAK;
} }
static bool nft_payload_fast_eval(const struct nft_expr *expr, 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_pktinfo *pkt)
{ {
const struct nft_payload *priv = nft_expr_priv(expr); const struct nft_payload *priv = nft_expr_priv(expr);
const struct sk_buff *skb = pkt->skb; const struct sk_buff *skb = pkt->skb;
struct nft_data *dest = &data[priv->dreg]; u32 *dest = &regs->data[priv->dreg];
unsigned char *ptr; unsigned char *ptr;
if (priv->base == NFT_PAYLOAD_NETWORK_HEADER) if (priv->base == NFT_PAYLOAD_NETWORK_HEADER)
...@@ -94,12 +94,13 @@ static bool nft_payload_fast_eval(const struct nft_expr *expr, ...@@ -94,12 +94,13 @@ static bool nft_payload_fast_eval(const struct nft_expr *expr,
if (unlikely(ptr + priv->len >= skb_tail_pointer(skb))) if (unlikely(ptr + priv->len >= skb_tail_pointer(skb)))
return false; return false;
*dest = 0;
if (priv->len == 2) if (priv->len == 2)
*(u16 *)dest->data = *(u16 *)ptr; *(u16 *)dest = *(u16 *)ptr;
else if (priv->len == 4) else if (priv->len == 4)
*(u32 *)dest->data = *(u32 *)ptr; *(u32 *)dest = *(u32 *)ptr;
else else
*(u8 *)dest->data = *(u8 *)ptr; *(u8 *)dest = *(u8 *)ptr;
return true; return true;
} }
...@@ -116,7 +117,7 @@ nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops) ...@@ -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 net *net = read_pnet(&nft_base_chain(basechain)->pnet);
const struct nft_rule *rule; const struct nft_rule *rule;
const struct nft_expr *expr, *last; const struct nft_expr *expr, *last;
struct nft_data data[NFT_REG_MAX + 1]; struct nft_regs regs;
unsigned int stackptr = 0; unsigned int stackptr = 0;
struct nft_jumpstack jumpstack[NFT_JUMP_STACK_SIZE]; struct nft_jumpstack jumpstack[NFT_JUMP_STACK_SIZE];
struct nft_stats *stats; struct nft_stats *stats;
...@@ -127,7 +128,7 @@ nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops) ...@@ -127,7 +128,7 @@ nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops)
rulenum = 0; rulenum = 0;
rule = list_entry(&chain->rules, struct nft_rule, list); rule = list_entry(&chain->rules, struct nft_rule, list);
next_rule: next_rule:
data[NFT_REG_VERDICT].verdict = NFT_CONTINUE; regs.verdict.code = NFT_CONTINUE;
list_for_each_entry_continue_rcu(rule, &chain->rules, list) { list_for_each_entry_continue_rcu(rule, &chain->rules, list) {
/* This rule is not active, skip. */ /* This rule is not active, skip. */
...@@ -138,18 +139,18 @@ nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops) ...@@ -138,18 +139,18 @@ nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops)
nft_rule_for_each_expr(expr, last, rule) { nft_rule_for_each_expr(expr, last, rule) {
if (expr->ops == &nft_cmp_fast_ops) 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 || else if (expr->ops != &nft_payload_fast_ops ||
!nft_payload_fast_eval(expr, data, pkt)) !nft_payload_fast_eval(expr, &regs, pkt))
expr->ops->eval(expr, data, pkt); expr->ops->eval(expr, &regs, pkt);
if (data[NFT_REG_VERDICT].verdict != NFT_CONTINUE) if (regs.verdict.code != NFT_CONTINUE)
break; break;
} }
switch (data[NFT_REG_VERDICT].verdict) { switch (regs.verdict.code) {
case NFT_BREAK: case NFT_BREAK:
data[NFT_REG_VERDICT].verdict = NFT_CONTINUE; regs.verdict.code = NFT_CONTINUE;
continue; continue;
case NFT_CONTINUE: case NFT_CONTINUE:
nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE); nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
...@@ -158,15 +159,15 @@ nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops) ...@@ -158,15 +159,15 @@ nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops)
break; break;
} }
switch (data[NFT_REG_VERDICT].verdict & NF_VERDICT_MASK) { switch (regs.verdict.code & NF_VERDICT_MASK) {
case NF_ACCEPT: case NF_ACCEPT:
case NF_DROP: case NF_DROP:
case NF_QUEUE: case NF_QUEUE:
nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE); 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: case NFT_JUMP:
BUG_ON(stackptr >= NFT_JUMP_STACK_SIZE); BUG_ON(stackptr >= NFT_JUMP_STACK_SIZE);
jumpstack[stackptr].chain = chain; jumpstack[stackptr].chain = chain;
...@@ -177,7 +178,7 @@ nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops) ...@@ -177,7 +178,7 @@ nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops)
case NFT_GOTO: case NFT_GOTO:
nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE); nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
chain = data[NFT_REG_VERDICT].chain; chain = regs.verdict.chain;
goto do_chain; goto do_chain;
case NFT_CONTINUE: case NFT_CONTINUE:
rulenum++; rulenum++;
......
...@@ -26,18 +26,16 @@ struct nft_bitwise { ...@@ -26,18 +26,16 @@ struct nft_bitwise {
}; };
static void nft_bitwise_eval(const struct nft_expr *expr, 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_pktinfo *pkt)
{ {
const struct nft_bitwise *priv = nft_expr_priv(expr); const struct nft_bitwise *priv = nft_expr_priv(expr);
const struct nft_data *src = &data[priv->sreg]; const u32 *src = &regs->data[priv->sreg];
struct nft_data *dst = &data[priv->dreg]; u32 *dst = &regs->data[priv->dreg];
unsigned int i; unsigned int i;
for (i = 0; i < DIV_ROUND_UP(priv->len, 4); i++) { for (i = 0; i < DIV_ROUND_UP(priv->len, 4); i++)
dst->data[i] = (src->data[i] & priv->mask.data[i]) ^ dst[i] = (src[i] & priv->mask.data[i]) ^ priv->xor.data[i];
priv->xor.data[i];
}
} }
static const struct nla_policy nft_bitwise_policy[NFTA_BITWISE_MAX + 1] = { 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, ...@@ -63,28 +61,27 @@ static int nft_bitwise_init(const struct nft_ctx *ctx,
tb[NFTA_BITWISE_XOR] == NULL) tb[NFTA_BITWISE_XOR] == NULL)
return -EINVAL; return -EINVAL;
priv->sreg = ntohl(nla_get_be32(tb[NFTA_BITWISE_SREG])); priv->len = ntohl(nla_get_be32(tb[NFTA_BITWISE_LEN]));
err = nft_validate_input_register(priv->sreg); priv->sreg = nft_parse_register(tb[NFTA_BITWISE_SREG]);
err = nft_validate_register_load(priv->sreg, priv->len);
if (err < 0) if (err < 0)
return err; return err;
priv->dreg = ntohl(nla_get_be32(tb[NFTA_BITWISE_DREG])); priv->dreg = nft_parse_register(tb[NFTA_BITWISE_DREG]);
err = nft_validate_output_register(priv->dreg); err = nft_validate_register_store(ctx, priv->dreg, NULL,
NFT_DATA_VALUE, priv->len);
if (err < 0) if (err < 0)
return err; 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) if (err < 0)
return err; return err;
if (d1.len != priv->len) if (d1.len != priv->len)
return -EINVAL; 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) if (err < 0)
return err; return err;
if (d2.len != priv->len) if (d2.len != priv->len)
...@@ -97,9 +94,9 @@ static int nft_bitwise_dump(struct sk_buff *skb, const struct nft_expr *expr) ...@@ -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); 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; 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; goto nla_put_failure;
if (nla_put_be32(skb, NFTA_BITWISE_LEN, htonl(priv->len))) if (nla_put_be32(skb, NFTA_BITWISE_LEN, htonl(priv->len)))
goto nla_put_failure; goto nla_put_failure;
......
...@@ -26,16 +26,17 @@ struct nft_byteorder { ...@@ -26,16 +26,17 @@ struct nft_byteorder {
}; };
static void nft_byteorder_eval(const struct nft_expr *expr, 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_pktinfo *pkt)
{ {
const struct nft_byteorder *priv = nft_expr_priv(expr); 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; union { u32 u32; u16 u16; } *s, *d;
unsigned int i; unsigned int i;
s = (void *)src->data; s = (void *)src;
d = (void *)dst->data; d = (void *)dst;
switch (priv->size) { switch (priv->size) {
case 4: case 4:
...@@ -87,19 +88,6 @@ static int nft_byteorder_init(const struct nft_ctx *ctx, ...@@ -87,19 +88,6 @@ static int nft_byteorder_init(const struct nft_ctx *ctx,
tb[NFTA_BYTEORDER_OP] == NULL) tb[NFTA_BYTEORDER_OP] == NULL)
return -EINVAL; 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])); priv->op = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_OP]));
switch (priv->op) { switch (priv->op) {
case NFT_BYTEORDER_NTOH: case NFT_BYTEORDER_NTOH:
...@@ -109,10 +97,6 @@ static int nft_byteorder_init(const struct nft_ctx *ctx, ...@@ -109,10 +97,6 @@ static int nft_byteorder_init(const struct nft_ctx *ctx,
return -EINVAL; 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])); priv->size = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_SIZE]));
switch (priv->size) { switch (priv->size) {
case 2: case 2:
...@@ -122,16 +106,24 @@ static int nft_byteorder_init(const struct nft_ctx *ctx, ...@@ -122,16 +106,24 @@ static int nft_byteorder_init(const struct nft_ctx *ctx,
return -EINVAL; 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) static int nft_byteorder_dump(struct sk_buff *skb, const struct nft_expr *expr)
{ {
const struct nft_byteorder *priv = nft_expr_priv(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; 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; goto nla_put_failure;
if (nla_put_be32(skb, NFTA_BYTEORDER_OP, htonl(priv->op))) if (nla_put_be32(skb, NFTA_BYTEORDER_OP, htonl(priv->op)))
goto nla_put_failure; goto nla_put_failure;
......
...@@ -25,13 +25,13 @@ struct nft_cmp_expr { ...@@ -25,13 +25,13 @@ struct nft_cmp_expr {
}; };
static void nft_cmp_eval(const struct nft_expr *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_pktinfo *pkt)
{ {
const struct nft_cmp_expr *priv = nft_expr_priv(expr); const struct nft_cmp_expr *priv = nft_expr_priv(expr);
int d; 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) { switch (priv->op) {
case NFT_CMP_EQ: case NFT_CMP_EQ:
if (d != 0) if (d != 0)
...@@ -59,7 +59,7 @@ static void nft_cmp_eval(const struct nft_expr *expr, ...@@ -59,7 +59,7 @@ static void nft_cmp_eval(const struct nft_expr *expr,
return; return;
mismatch: 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] = { 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, ...@@ -75,12 +75,16 @@ static int nft_cmp_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
struct nft_data_desc desc; struct nft_data_desc desc;
int err; int err;
priv->sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG])); err = nft_data_init(NULL, &priv->data, sizeof(priv->data), &desc,
priv->op = ntohl(nla_get_be32(tb[NFTA_CMP_OP])); tb[NFTA_CMP_DATA]);
err = nft_data_init(NULL, &priv->data, &desc, tb[NFTA_CMP_DATA]);
BUG_ON(err < 0); 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; priv->len = desc.len;
return 0; return 0;
} }
...@@ -89,7 +93,7 @@ static int nft_cmp_dump(struct sk_buff *skb, const struct nft_expr *expr) ...@@ -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); 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; goto nla_put_failure;
if (nla_put_be32(skb, NFTA_CMP_OP, htonl(priv->op))) if (nla_put_be32(skb, NFTA_CMP_OP, htonl(priv->op)))
goto nla_put_failure; goto nla_put_failure;
...@@ -122,13 +126,18 @@ static int nft_cmp_fast_init(const struct nft_ctx *ctx, ...@@ -122,13 +126,18 @@ static int nft_cmp_fast_init(const struct nft_ctx *ctx,
u32 mask; u32 mask;
int err; int err;
priv->sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG])); err = nft_data_init(NULL, &data, sizeof(data), &desc,
tb[NFTA_CMP_DATA]);
err = nft_data_init(NULL, &data, &desc, tb[NFTA_CMP_DATA]);
BUG_ON(err < 0); 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); mask = nft_cmp_fast_mask(desc.len);
priv->data = data.data[0] & mask; priv->data = data.data[0] & mask;
priv->len = desc.len; priv->len = desc.len;
return 0; return 0;
...@@ -139,7 +148,7 @@ static int nft_cmp_fast_dump(struct sk_buff *skb, const struct nft_expr *expr) ...@@ -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); const struct nft_cmp_fast_expr *priv = nft_expr_priv(expr);
struct nft_data data; 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; goto nla_put_failure;
if (nla_put_be32(skb, NFTA_CMP_OP, htonl(NFT_CMP_EQ))) if (nla_put_be32(skb, NFTA_CMP_OP, htonl(NFT_CMP_EQ)))
goto nla_put_failure; goto nla_put_failure;
...@@ -167,7 +176,6 @@ nft_cmp_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[]) ...@@ -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_desc desc;
struct nft_data data; struct nft_data data;
enum nft_registers sreg;
enum nft_cmp_ops op; enum nft_cmp_ops op;
int err; int err;
...@@ -176,11 +184,6 @@ nft_cmp_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[]) ...@@ -176,11 +184,6 @@ nft_cmp_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[])
tb[NFTA_CMP_DATA] == NULL) tb[NFTA_CMP_DATA] == NULL)
return ERR_PTR(-EINVAL); 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])); op = ntohl(nla_get_be32(tb[NFTA_CMP_OP]));
switch (op) { switch (op) {
case NFT_CMP_EQ: case NFT_CMP_EQ:
...@@ -194,7 +197,8 @@ nft_cmp_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[]) ...@@ -194,7 +197,8 @@ nft_cmp_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[])
return ERR_PTR(-EINVAL); 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) if (err < 0)
return ERR_PTR(err); return ERR_PTR(err);
......
...@@ -55,7 +55,7 @@ nft_compat_set_par(struct xt_action_param *par, void *xt, const void *xt_info) ...@@ -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, 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) const struct nft_pktinfo *pkt)
{ {
void *info = nft_expr_priv(expr); void *info = nft_expr_priv(expr);
...@@ -72,16 +72,16 @@ static void nft_target_eval_xt(const struct nft_expr *expr, ...@@ -72,16 +72,16 @@ static void nft_target_eval_xt(const struct nft_expr *expr,
switch (ret) { switch (ret) {
case XT_CONTINUE: case XT_CONTINUE:
data[NFT_REG_VERDICT].verdict = NFT_CONTINUE; regs->verdict.code = NFT_CONTINUE;
break; break;
default: default:
data[NFT_REG_VERDICT].verdict = ret; regs->verdict.code = ret;
break; break;
} }
} }
static void nft_target_eval_bridge(const struct nft_expr *expr, 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) const struct nft_pktinfo *pkt)
{ {
void *info = nft_expr_priv(expr); void *info = nft_expr_priv(expr);
...@@ -98,19 +98,19 @@ static void nft_target_eval_bridge(const struct nft_expr *expr, ...@@ -98,19 +98,19 @@ static void nft_target_eval_bridge(const struct nft_expr *expr,
switch (ret) { switch (ret) {
case EBT_ACCEPT: case EBT_ACCEPT:
data[NFT_REG_VERDICT].verdict = NF_ACCEPT; regs->verdict.code = NF_ACCEPT;
break; break;
case EBT_DROP: case EBT_DROP:
data[NFT_REG_VERDICT].verdict = NF_DROP; regs->verdict.code = NF_DROP;
break; break;
case EBT_CONTINUE: case EBT_CONTINUE:
data[NFT_REG_VERDICT].verdict = NFT_CONTINUE; regs->verdict.code = NFT_CONTINUE;
break; break;
case EBT_RETURN: case EBT_RETURN:
data[NFT_REG_VERDICT].verdict = NFT_RETURN; regs->verdict.code = NFT_RETURN;
break; break;
default: default:
data[NFT_REG_VERDICT].verdict = ret; regs->verdict.code = ret;
break; break;
} }
} }
...@@ -304,7 +304,7 @@ static int nft_target_validate(const struct nft_ctx *ctx, ...@@ -304,7 +304,7 @@ static int nft_target_validate(const struct nft_ctx *ctx,
} }
static void nft_match_eval(const struct nft_expr *expr, 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) const struct nft_pktinfo *pkt)
{ {
void *info = nft_expr_priv(expr); void *info = nft_expr_priv(expr);
...@@ -317,16 +317,16 @@ static void nft_match_eval(const struct nft_expr *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); ret = match->match(skb, (struct xt_action_param *)&pkt->xt);
if (pkt->xt.hotdrop) { if (pkt->xt.hotdrop) {
data[NFT_REG_VERDICT].verdict = NF_DROP; regs->verdict.code = NF_DROP;
return; return;
} }
switch (ret ? 1 : 0) { switch (ret ? 1 : 0) {
case 1: case 1:
data[NFT_REG_VERDICT].verdict = NFT_CONTINUE; regs->verdict.code = NFT_CONTINUE;
break; break;
case 0: case 0:
data[NFT_REG_VERDICT].verdict = NFT_BREAK; regs->verdict.code = NFT_BREAK;
break; break;
} }
} }
......
...@@ -24,7 +24,7 @@ struct nft_counter { ...@@ -24,7 +24,7 @@ struct nft_counter {
}; };
static void nft_counter_eval(const struct nft_expr *expr, 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) const struct nft_pktinfo *pkt)
{ {
struct nft_counter *priv = nft_expr_priv(expr); struct nft_counter *priv = nft_expr_priv(expr);
...@@ -92,6 +92,7 @@ static struct nft_expr_type nft_counter_type __read_mostly = { ...@@ -92,6 +92,7 @@ static struct nft_expr_type nft_counter_type __read_mostly = {
.ops = &nft_counter_ops, .ops = &nft_counter_ops,
.policy = nft_counter_policy, .policy = nft_counter_policy,
.maxattr = NFTA_COUNTER_MAX, .maxattr = NFTA_COUNTER_MAX,
.flags = NFT_EXPR_STATEFUL,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
......
...@@ -31,11 +31,11 @@ struct nft_ct { ...@@ -31,11 +31,11 @@ struct nft_ct {
}; };
static void nft_ct_get_eval(const struct nft_expr *expr, 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_pktinfo *pkt)
{ {
const struct nft_ct *priv = nft_expr_priv(expr); 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; enum ip_conntrack_info ctinfo;
const struct nf_conn *ct; const struct nf_conn *ct;
const struct nf_conn_help *help; const struct nf_conn_help *help;
...@@ -54,7 +54,7 @@ static void nft_ct_get_eval(const struct nft_expr *expr, ...@@ -54,7 +54,7 @@ static void nft_ct_get_eval(const struct nft_expr *expr,
state = NF_CT_STATE_UNTRACKED_BIT; state = NF_CT_STATE_UNTRACKED_BIT;
else else
state = NF_CT_STATE_BIT(ctinfo); state = NF_CT_STATE_BIT(ctinfo);
dest->data[0] = state; *dest = state;
return; return;
default: default:
break; break;
...@@ -65,26 +65,26 @@ static void nft_ct_get_eval(const struct nft_expr *expr, ...@@ -65,26 +65,26 @@ static void nft_ct_get_eval(const struct nft_expr *expr,
switch (priv->key) { switch (priv->key) {
case NFT_CT_DIRECTION: case NFT_CT_DIRECTION:
dest->data[0] = CTINFO2DIR(ctinfo); *dest = CTINFO2DIR(ctinfo);
return; return;
case NFT_CT_STATUS: case NFT_CT_STATUS:
dest->data[0] = ct->status; *dest = ct->status;
return; return;
#ifdef CONFIG_NF_CONNTRACK_MARK #ifdef CONFIG_NF_CONNTRACK_MARK
case NFT_CT_MARK: case NFT_CT_MARK:
dest->data[0] = ct->mark; *dest = ct->mark;
return; return;
#endif #endif
#ifdef CONFIG_NF_CONNTRACK_SECMARK #ifdef CONFIG_NF_CONNTRACK_SECMARK
case NFT_CT_SECMARK: case NFT_CT_SECMARK:
dest->data[0] = ct->secmark; *dest = ct->secmark;
return; return;
#endif #endif
case NFT_CT_EXPIRATION: case NFT_CT_EXPIRATION:
diff = (long)jiffies - (long)ct->timeout.expires; diff = (long)jiffies - (long)ct->timeout.expires;
if (diff < 0) if (diff < 0)
diff = 0; diff = 0;
dest->data[0] = jiffies_to_msecs(diff); *dest = jiffies_to_msecs(diff);
return; return;
case NFT_CT_HELPER: case NFT_CT_HELPER:
if (ct->master == NULL) if (ct->master == NULL)
...@@ -95,9 +95,7 @@ static void nft_ct_get_eval(const struct nft_expr *expr, ...@@ -95,9 +95,7 @@ static void nft_ct_get_eval(const struct nft_expr *expr,
helper = rcu_dereference(help->helper); helper = rcu_dereference(help->helper);
if (helper == NULL) if (helper == NULL)
goto err; goto err;
if (strlen(helper->name) >= sizeof(dest->data)) strncpy((char *)dest, helper->name, NF_CT_HELPER_NAME_LEN);
goto err;
strncpy((char *)dest->data, helper->name, sizeof(dest->data));
return; return;
#ifdef CONFIG_NF_CONNTRACK_LABELS #ifdef CONFIG_NF_CONNTRACK_LABELS
case NFT_CT_LABELS: { case NFT_CT_LABELS: {
...@@ -105,17 +103,15 @@ static void nft_ct_get_eval(const struct nft_expr *expr, ...@@ -105,17 +103,15 @@ static void nft_ct_get_eval(const struct nft_expr *expr,
unsigned int size; unsigned int size;
if (!labels) { if (!labels) {
memset(dest->data, 0, sizeof(dest->data)); memset(dest, 0, NF_CT_LABELS_MAX_SIZE);
return; return;
} }
BUILD_BUG_ON(NF_CT_LABELS_MAX_SIZE > sizeof(dest->data));
size = labels->words * sizeof(long); size = labels->words * sizeof(long);
memcpy(dest, labels->bits, size);
memcpy(dest->data, labels->bits, size); if (size < NF_CT_LABELS_MAX_SIZE)
if (size < sizeof(dest->data)) memset(((char *) dest) + size, 0,
memset(((char *) dest->data) + size, 0, NF_CT_LABELS_MAX_SIZE - size);
sizeof(dest->data) - size);
return; return;
} }
#endif #endif
...@@ -126,41 +122,41 @@ static void nft_ct_get_eval(const struct nft_expr *expr, ...@@ -126,41 +122,41 @@ static void nft_ct_get_eval(const struct nft_expr *expr,
tuple = &ct->tuplehash[priv->dir].tuple; tuple = &ct->tuplehash[priv->dir].tuple;
switch (priv->key) { switch (priv->key) {
case NFT_CT_L3PROTOCOL: case NFT_CT_L3PROTOCOL:
dest->data[0] = nf_ct_l3num(ct); *dest = nf_ct_l3num(ct);
return; return;
case NFT_CT_SRC: 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); nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16);
return; return;
case NFT_CT_DST: 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); nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16);
return; return;
case NFT_CT_PROTOCOL: case NFT_CT_PROTOCOL:
dest->data[0] = nf_ct_protonum(ct); *dest = nf_ct_protonum(ct);
return; return;
case NFT_CT_PROTO_SRC: case NFT_CT_PROTO_SRC:
dest->data[0] = (__force __u16)tuple->src.u.all; *dest = (__force __u16)tuple->src.u.all;
return; return;
case NFT_CT_PROTO_DST: case NFT_CT_PROTO_DST:
dest->data[0] = (__force __u16)tuple->dst.u.all; *dest = (__force __u16)tuple->dst.u.all;
return; return;
default: default:
break; break;
} }
return; return;
err: err:
data[NFT_REG_VERDICT].verdict = NFT_BREAK; regs->verdict.code = NFT_BREAK;
} }
static void nft_ct_set_eval(const struct nft_expr *expr, 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_pktinfo *pkt)
{ {
const struct nft_ct *priv = nft_expr_priv(expr); const struct nft_ct *priv = nft_expr_priv(expr);
struct sk_buff *skb = pkt->skb; struct sk_buff *skb = pkt->skb;
#ifdef CONFIG_NF_CONNTRACK_MARK #ifdef CONFIG_NF_CONNTRACK_MARK
u32 value = data[priv->sreg].data[0]; u32 value = regs->data[priv->sreg];
#endif #endif
enum ip_conntrack_info ctinfo; enum ip_conntrack_info ctinfo;
struct nf_conn *ct; struct nf_conn *ct;
...@@ -228,12 +224,17 @@ static int nft_ct_get_init(const struct nft_ctx *ctx, ...@@ -228,12 +224,17 @@ static int nft_ct_get_init(const struct nft_ctx *ctx,
const struct nlattr * const tb[]) const struct nlattr * const tb[])
{ {
struct nft_ct *priv = nft_expr_priv(expr); struct nft_ct *priv = nft_expr_priv(expr);
unsigned int len;
int err; int err;
priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY])); priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
switch (priv->key) { switch (priv->key) {
case NFT_CT_STATE:
case NFT_CT_DIRECTION: case NFT_CT_DIRECTION:
if (tb[NFTA_CT_DIRECTION] != NULL)
return -EINVAL;
len = sizeof(u8);
break;
case NFT_CT_STATE:
case NFT_CT_STATUS: case NFT_CT_STATUS:
#ifdef CONFIG_NF_CONNTRACK_MARK #ifdef CONFIG_NF_CONNTRACK_MARK
case NFT_CT_MARK: case NFT_CT_MARK:
...@@ -241,22 +242,54 @@ static int nft_ct_get_init(const struct nft_ctx *ctx, ...@@ -241,22 +242,54 @@ static int nft_ct_get_init(const struct nft_ctx *ctx,
#ifdef CONFIG_NF_CONNTRACK_SECMARK #ifdef CONFIG_NF_CONNTRACK_SECMARK
case NFT_CT_SECMARK: case NFT_CT_SECMARK:
#endif #endif
case NFT_CT_EXPIRATION:
if (tb[NFTA_CT_DIRECTION] != NULL)
return -EINVAL;
len = sizeof(u32);
break;
#ifdef CONFIG_NF_CONNTRACK_LABELS #ifdef CONFIG_NF_CONNTRACK_LABELS
case NFT_CT_LABELS: case NFT_CT_LABELS:
if (tb[NFTA_CT_DIRECTION] != NULL)
return -EINVAL;
len = NF_CT_LABELS_MAX_SIZE;
break;
#endif #endif
case NFT_CT_EXPIRATION:
case NFT_CT_HELPER: case NFT_CT_HELPER:
if (tb[NFTA_CT_DIRECTION] != NULL) if (tb[NFTA_CT_DIRECTION] != NULL)
return -EINVAL; return -EINVAL;
len = NF_CT_HELPER_NAME_LEN;
break; break;
case NFT_CT_L3PROTOCOL: case NFT_CT_L3PROTOCOL:
case NFT_CT_PROTOCOL: case NFT_CT_PROTOCOL:
if (tb[NFTA_CT_DIRECTION] == NULL)
return -EINVAL;
len = sizeof(u8);
break;
case NFT_CT_SRC: case NFT_CT_SRC:
case NFT_CT_DST: 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_SRC:
case NFT_CT_PROTO_DST: case NFT_CT_PROTO_DST:
if (tb[NFTA_CT_DIRECTION] == NULL) if (tb[NFTA_CT_DIRECTION] == NULL)
return -EINVAL; return -EINVAL;
len = FIELD_SIZEOF(struct nf_conntrack_tuple, src.u.all);
break; break;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -273,12 +306,9 @@ static int nft_ct_get_init(const struct nft_ctx *ctx, ...@@ -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])); priv->dreg = nft_parse_register(tb[NFTA_CT_DREG]);
err = nft_validate_output_register(priv->dreg); err = nft_validate_register_store(ctx, priv->dreg, NULL,
if (err < 0) NFT_DATA_VALUE, len);
return err;
err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
if (err < 0) if (err < 0)
return err; return err;
...@@ -294,20 +324,22 @@ static int nft_ct_set_init(const struct nft_ctx *ctx, ...@@ -294,20 +324,22 @@ static int nft_ct_set_init(const struct nft_ctx *ctx,
const struct nlattr * const tb[]) const struct nlattr * const tb[])
{ {
struct nft_ct *priv = nft_expr_priv(expr); struct nft_ct *priv = nft_expr_priv(expr);
unsigned int len;
int err; int err;
priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY])); priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
switch (priv->key) { switch (priv->key) {
#ifdef CONFIG_NF_CONNTRACK_MARK #ifdef CONFIG_NF_CONNTRACK_MARK
case NFT_CT_MARK: case NFT_CT_MARK:
len = FIELD_SIZEOF(struct nf_conn, mark);
break; break;
#endif #endif
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
priv->sreg = ntohl(nla_get_be32(tb[NFTA_CT_SREG])); priv->sreg = nft_parse_register(tb[NFTA_CT_SREG]);
err = nft_validate_input_register(priv->sreg); err = nft_validate_register_load(priv->sreg, len);
if (err < 0) if (err < 0)
return err; return err;
...@@ -328,7 +360,7 @@ static int nft_ct_get_dump(struct sk_buff *skb, const struct nft_expr *expr) ...@@ -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); 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; goto nla_put_failure;
if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key))) if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key)))
goto nla_put_failure; goto nla_put_failure;
...@@ -355,7 +387,7 @@ static int nft_ct_set_dump(struct sk_buff *skb, const struct nft_expr *expr) ...@@ -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); 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; goto nla_put_failure;
if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key))) if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key)))
goto nla_put_failure; goto nla_put_failure;
......
...@@ -23,13 +23,15 @@ struct nft_dynset { ...@@ -23,13 +23,15 @@ struct nft_dynset {
enum nft_registers sreg_key:8; enum nft_registers sreg_key:8;
enum nft_registers sreg_data:8; enum nft_registers sreg_data:8;
u64 timeout; u64 timeout;
struct nft_expr *expr;
struct nft_set_binding binding; struct nft_set_binding binding;
}; };
static void *nft_dynset_new(struct nft_set *set, const struct nft_expr *expr, 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); const struct nft_dynset *priv = nft_expr_priv(expr);
struct nft_set_ext *ext;
u64 timeout; u64 timeout;
void *elem; void *elem;
...@@ -38,35 +40,51 @@ static void *nft_dynset_new(struct nft_set *set, const struct nft_expr *expr, ...@@ -38,35 +40,51 @@ static void *nft_dynset_new(struct nft_set *set, const struct nft_expr *expr,
timeout = priv->timeout ? : set->timeout; timeout = priv->timeout ? : set->timeout;
elem = nft_set_elem_init(set, &priv->tmpl, 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); timeout, GFP_ATOMIC);
if (elem == NULL) { if (elem == NULL) {
if (set->size) if (set->size)
atomic_dec(&set->nelems); 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; return elem;
} }
static void nft_dynset_eval(const struct nft_expr *expr, 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_pktinfo *pkt)
{ {
const struct nft_dynset *priv = nft_expr_priv(expr); const struct nft_dynset *priv = nft_expr_priv(expr);
struct nft_set *set = priv->set; struct nft_set *set = priv->set;
const struct nft_set_ext *ext; const struct nft_set_ext *ext;
const struct nft_expr *sexpr;
u64 timeout; u64 timeout;
if (set->ops->update(set, &data[priv->sreg_key], nft_dynset_new, if (set->ops->update(set, &regs->data[priv->sreg_key], nft_dynset_new,
expr, data, &ext)) { 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 && if (priv->op == NFT_DYNSET_OP_UPDATE &&
nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION)) { nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION)) {
timeout = priv->timeout ? : set->timeout; timeout = priv->timeout ? : set->timeout;
*nft_set_ext_expiration(ext) = jiffies + 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] = { 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] = { ...@@ -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_KEY] = { .type = NLA_U32 },
[NFTA_DYNSET_SREG_DATA] = { .type = NLA_U32 }, [NFTA_DYNSET_SREG_DATA] = { .type = NLA_U32 },
[NFTA_DYNSET_TIMEOUT] = { .type = NLA_U64 }, [NFTA_DYNSET_TIMEOUT] = { .type = NLA_U64 },
[NFTA_DYNSET_EXPR] = { .type = NLA_NESTED },
}; };
static int nft_dynset_init(const struct nft_ctx *ctx, static int nft_dynset_init(const struct nft_ctx *ctx,
...@@ -123,8 +142,8 @@ 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])); timeout = be64_to_cpu(nla_get_be64(tb[NFTA_DYNSET_TIMEOUT]));
} }
priv->sreg_key = ntohl(nla_get_be32(tb[NFTA_DYNSET_SREG_KEY])); priv->sreg_key = nft_parse_register(tb[NFTA_DYNSET_SREG_KEY]);
err = nft_validate_input_register(priv->sreg_key); err = nft_validate_register_load(priv->sreg_key, set->klen);;
if (err < 0) if (err < 0)
return err; return err;
...@@ -134,17 +153,36 @@ static int nft_dynset_init(const struct nft_ctx *ctx, ...@@ -134,17 +153,36 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
if (set->dtype == NFT_DATA_VERDICT) if (set->dtype == NFT_DATA_VERDICT)
return -EOPNOTSUPP; return -EOPNOTSUPP;
priv->sreg_data = ntohl(nla_get_be32(tb[NFTA_DYNSET_SREG_DATA])); priv->sreg_data = nft_parse_register(tb[NFTA_DYNSET_SREG_DATA]);
err = nft_validate_input_register(priv->sreg_data); err = nft_validate_register_load(priv->sreg_data, set->dlen);
if (err < 0) if (err < 0)
return err; return err;
} else if (set->flags & NFT_SET_MAP) } else if (set->flags & NFT_SET_MAP)
return -EINVAL; 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_prepare(&priv->tmpl);
nft_set_ext_add_length(&priv->tmpl, NFT_SET_EXT_KEY, set->klen); nft_set_ext_add_length(&priv->tmpl, NFT_SET_EXT_KEY, set->klen);
if (set->flags & NFT_SET_MAP) if (set->flags & NFT_SET_MAP)
nft_set_ext_add_length(&priv->tmpl, NFT_SET_EXT_DATA, set->dlen); 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 (set->flags & NFT_SET_TIMEOUT) {
if (timeout || set->timeout) if (timeout || set->timeout)
nft_set_ext_add(&priv->tmpl, NFT_SET_EXT_EXPIRATION); nft_set_ext_add(&priv->tmpl, NFT_SET_EXT_EXPIRATION);
...@@ -154,10 +192,15 @@ static int nft_dynset_init(const struct nft_ctx *ctx, ...@@ -154,10 +192,15 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
err = nf_tables_bind_set(ctx, set, &priv->binding); err = nf_tables_bind_set(ctx, set, &priv->binding);
if (err < 0) if (err < 0)
return err; goto err1;
priv->set = set; priv->set = set;
return 0; 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, static void nft_dynset_destroy(const struct nft_ctx *ctx,
...@@ -166,16 +209,18 @@ 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); struct nft_dynset *priv = nft_expr_priv(expr);
nf_tables_unbind_set(ctx, priv->set, &priv->binding); 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) static int nft_dynset_dump(struct sk_buff *skb, const struct nft_expr *expr)
{ {
const struct nft_dynset *priv = nft_expr_priv(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; goto nla_put_failure;
if (priv->set->flags & NFT_SET_MAP && 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; goto nla_put_failure;
if (nla_put_be32(skb, NFTA_DYNSET_OP, htonl(priv->op))) if (nla_put_be32(skb, NFTA_DYNSET_OP, htonl(priv->op)))
goto nla_put_failure; goto nla_put_failure;
...@@ -183,6 +228,8 @@ static int nft_dynset_dump(struct sk_buff *skb, const struct nft_expr *expr) ...@@ -183,6 +228,8 @@ static int nft_dynset_dump(struct sk_buff *skb, const struct nft_expr *expr)
goto nla_put_failure; goto nla_put_failure;
if (nla_put_be64(skb, NFTA_DYNSET_TIMEOUT, cpu_to_be64(priv->timeout))) if (nla_put_be64(skb, NFTA_DYNSET_TIMEOUT, cpu_to_be64(priv->timeout)))
goto nla_put_failure; goto nla_put_failure;
if (priv->expr && nft_expr_dump(skb, NFTA_DYNSET_EXPR, priv->expr))
goto nla_put_failure;
return 0; return 0;
nla_put_failure: nla_put_failure:
......
/*
* 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");
...@@ -26,11 +26,11 @@ struct nft_exthdr { ...@@ -26,11 +26,11 @@ struct nft_exthdr {
}; };
static void nft_exthdr_eval(const struct nft_expr *expr, 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) const struct nft_pktinfo *pkt)
{ {
struct nft_exthdr *priv = nft_expr_priv(expr); 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; unsigned int offset = 0;
int err; int err;
...@@ -39,11 +39,12 @@ static void nft_exthdr_eval(const struct nft_expr *expr, ...@@ -39,11 +39,12 @@ static void nft_exthdr_eval(const struct nft_expr *expr,
goto err; goto err;
offset += priv->offset; 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; goto err;
return; return;
err: 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] = { 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, ...@@ -58,7 +59,6 @@ static int nft_exthdr_init(const struct nft_ctx *ctx,
const struct nlattr * const tb[]) const struct nlattr * const tb[])
{ {
struct nft_exthdr *priv = nft_expr_priv(expr); struct nft_exthdr *priv = nft_expr_priv(expr);
int err;
if (tb[NFTA_EXTHDR_DREG] == NULL || if (tb[NFTA_EXTHDR_DREG] == NULL ||
tb[NFTA_EXTHDR_TYPE] == NULL || tb[NFTA_EXTHDR_TYPE] == NULL ||
...@@ -69,22 +69,17 @@ static int nft_exthdr_init(const struct nft_ctx *ctx, ...@@ -69,22 +69,17 @@ static int nft_exthdr_init(const struct nft_ctx *ctx,
priv->type = nla_get_u8(tb[NFTA_EXTHDR_TYPE]); priv->type = nla_get_u8(tb[NFTA_EXTHDR_TYPE]);
priv->offset = ntohl(nla_get_be32(tb[NFTA_EXTHDR_OFFSET])); priv->offset = ntohl(nla_get_be32(tb[NFTA_EXTHDR_OFFSET]));
priv->len = ntohl(nla_get_be32(tb[NFTA_EXTHDR_LEN])); priv->len = ntohl(nla_get_be32(tb[NFTA_EXTHDR_LEN]));
if (priv->len == 0 || priv->dreg = nft_parse_register(tb[NFTA_EXTHDR_DREG]);
priv->len > FIELD_SIZEOF(struct nft_data, data))
return -EINVAL;
priv->dreg = ntohl(nla_get_be32(tb[NFTA_EXTHDR_DREG])); return nft_validate_register_store(ctx, priv->dreg, NULL,
err = nft_validate_output_register(priv->dreg); NFT_DATA_VALUE, priv->len);
if (err < 0)
return err;
return nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
} }
static int nft_exthdr_dump(struct sk_buff *skb, const struct nft_expr *expr) static int nft_exthdr_dump(struct sk_buff *skb, const struct nft_expr *expr)
{ {
const struct nft_exthdr *priv = nft_expr_priv(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; goto nla_put_failure;
if (nla_put_u8(skb, NFTA_EXTHDR_TYPE, priv->type)) if (nla_put_u8(skb, NFTA_EXTHDR_TYPE, priv->type))
goto nla_put_failure; goto nla_put_failure;
......
...@@ -36,7 +36,7 @@ struct nft_hash_elem { ...@@ -36,7 +36,7 @@ struct nft_hash_elem {
struct nft_hash_cmp_arg { struct nft_hash_cmp_arg {
const struct nft_set *set; const struct nft_set *set;
const struct nft_data *key; const u32 *key;
u8 genmask; u8 genmask;
}; };
...@@ -62,7 +62,7 @@ static inline int nft_hash_cmp(struct rhashtable_compare_arg *arg, ...@@ -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_cmp_arg *x = arg->key;
const struct nft_hash_elem *he = ptr; 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; return 1;
if (nft_set_elem_expired(&he->ext)) if (nft_set_elem_expired(&he->ext))
return 1; return 1;
...@@ -71,8 +71,7 @@ static inline int nft_hash_cmp(struct rhashtable_compare_arg *arg, ...@@ -71,8 +71,7 @@ static inline int nft_hash_cmp(struct rhashtable_compare_arg *arg,
return 0; return 0;
} }
static bool nft_hash_lookup(const struct nft_set *set, static bool nft_hash_lookup(const struct nft_set *set, const u32 *key,
const struct nft_data *key,
const struct nft_set_ext **ext) const struct nft_set_ext **ext)
{ {
struct nft_hash *priv = nft_set_priv(set); struct nft_hash *priv = nft_set_priv(set);
...@@ -90,12 +89,12 @@ static bool nft_hash_lookup(const struct nft_set *set, ...@@ -90,12 +89,12 @@ static bool nft_hash_lookup(const struct nft_set *set,
return !!he; 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 *, void *(*new)(struct nft_set *,
const struct nft_expr *, const struct nft_expr *,
struct nft_data []), struct nft_regs *regs),
const struct nft_expr *expr, const struct nft_expr *expr,
struct nft_data data[], struct nft_regs *regs,
const struct nft_set_ext **ext) const struct nft_set_ext **ext)
{ {
struct nft_hash *priv = nft_set_priv(set); 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, ...@@ -110,7 +109,7 @@ static bool nft_hash_update(struct nft_set *set, const struct nft_data *key,
if (he != NULL) if (he != NULL)
goto out; goto out;
he = new(set, expr, data); he = new(set, expr, regs);
if (he == NULL) if (he == NULL)
goto err1; goto err1;
if (rhashtable_lookup_insert_key(&priv->ht, &arg, &he->node, if (rhashtable_lookup_insert_key(&priv->ht, &arg, &he->node,
...@@ -134,7 +133,7 @@ static int nft_hash_insert(const struct nft_set *set, ...@@ -134,7 +133,7 @@ static int nft_hash_insert(const struct nft_set *set,
struct nft_hash_cmp_arg arg = { struct nft_hash_cmp_arg arg = {
.genmask = nft_genmask_next(read_pnet(&set->pnet)), .genmask = nft_genmask_next(read_pnet(&set->pnet)),
.set = set, .set = set,
.key = &elem->key, .key = elem->key.val.data,
}; };
return rhashtable_lookup_insert_key(&priv->ht, &arg, &he->node, return rhashtable_lookup_insert_key(&priv->ht, &arg, &he->node,
...@@ -158,7 +157,7 @@ static void *nft_hash_deactivate(const struct nft_set *set, ...@@ -158,7 +157,7 @@ static void *nft_hash_deactivate(const struct nft_set *set,
struct nft_hash_cmp_arg arg = { struct nft_hash_cmp_arg arg = {
.genmask = nft_genmask_next(read_pnet(&set->pnet)), .genmask = nft_genmask_next(read_pnet(&set->pnet)),
.set = set, .set = set,
.key = &elem->key, .key = elem->key.val.data,
}; };
rcu_read_lock(); rcu_read_lock();
......
...@@ -24,12 +24,12 @@ struct nft_immediate_expr { ...@@ -24,12 +24,12 @@ struct nft_immediate_expr {
}; };
static void nft_immediate_eval(const struct nft_expr *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_pktinfo *pkt)
{ {
const struct nft_immediate_expr *priv = nft_expr_priv(expr); 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] = { 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, ...@@ -49,17 +49,15 @@ static int nft_immediate_init(const struct nft_ctx *ctx,
tb[NFTA_IMMEDIATE_DATA] == NULL) tb[NFTA_IMMEDIATE_DATA] == NULL)
return -EINVAL; return -EINVAL;
priv->dreg = ntohl(nla_get_be32(tb[NFTA_IMMEDIATE_DREG])); err = nft_data_init(ctx, &priv->data, sizeof(priv->data), &desc,
err = nft_validate_output_register(priv->dreg); tb[NFTA_IMMEDIATE_DATA]);
if (err < 0)
return err;
err = nft_data_init(ctx, &priv->data, &desc, tb[NFTA_IMMEDIATE_DATA]);
if (err < 0) if (err < 0)
return err; return err;
priv->dlen = desc.len; 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) if (err < 0)
goto err1; goto err1;
...@@ -81,7 +79,7 @@ static int nft_immediate_dump(struct sk_buff *skb, const struct nft_expr *expr) ...@@ -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); 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; goto nla_put_failure;
return nft_data_dump(skb, NFTA_IMMEDIATE_DATA, &priv->data, return nft_data_dump(skb, NFTA_IMMEDIATE_DATA, &priv->data,
......
...@@ -27,7 +27,7 @@ struct nft_limit { ...@@ -27,7 +27,7 @@ struct nft_limit {
}; };
static void nft_limit_eval(const struct nft_expr *expr, 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) const struct nft_pktinfo *pkt)
{ {
struct nft_limit *priv = nft_expr_priv(expr); struct nft_limit *priv = nft_expr_priv(expr);
...@@ -45,7 +45,7 @@ static void nft_limit_eval(const struct nft_expr *expr, ...@@ -45,7 +45,7 @@ static void nft_limit_eval(const struct nft_expr *expr,
} }
spin_unlock_bh(&limit_lock); 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] = { 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 = { ...@@ -98,6 +98,7 @@ static struct nft_expr_type nft_limit_type __read_mostly = {
.ops = &nft_limit_ops, .ops = &nft_limit_ops,
.policy = nft_limit_policy, .policy = nft_limit_policy,
.maxattr = NFTA_LIMIT_MAX, .maxattr = NFTA_LIMIT_MAX,
.flags = NFT_EXPR_STATEFUL,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
......
...@@ -27,7 +27,7 @@ struct nft_log { ...@@ -27,7 +27,7 @@ struct nft_log {
}; };
static void nft_log_eval(const struct nft_expr *expr, 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_pktinfo *pkt)
{ {
const struct nft_log *priv = nft_expr_priv(expr); const struct nft_log *priv = nft_expr_priv(expr);
......
...@@ -26,19 +26,20 @@ struct nft_lookup { ...@@ -26,19 +26,20 @@ struct nft_lookup {
}; };
static void nft_lookup_eval(const struct nft_expr *expr, 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_pktinfo *pkt)
{ {
const struct nft_lookup *priv = nft_expr_priv(expr); const struct nft_lookup *priv = nft_expr_priv(expr);
const struct nft_set *set = priv->set; const struct nft_set *set = priv->set;
const struct nft_set_ext *ext; 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) 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; 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] = { 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, ...@@ -70,8 +71,11 @@ static int nft_lookup_init(const struct nft_ctx *ctx,
return PTR_ERR(set); return PTR_ERR(set);
} }
priv->sreg = ntohl(nla_get_be32(tb[NFTA_LOOKUP_SREG])); if (set->flags & NFT_SET_EVAL)
err = nft_validate_input_register(priv->sreg); return -EOPNOTSUPP;
priv->sreg = nft_parse_register(tb[NFTA_LOOKUP_SREG]);
err = nft_validate_register_load(priv->sreg, set->klen);
if (err < 0) if (err < 0)
return err; return err;
...@@ -79,16 +83,11 @@ static int nft_lookup_init(const struct nft_ctx *ctx, ...@@ -79,16 +83,11 @@ static int nft_lookup_init(const struct nft_ctx *ctx,
if (!(set->flags & NFT_SET_MAP)) if (!(set->flags & NFT_SET_MAP))
return -EINVAL; return -EINVAL;
priv->dreg = ntohl(nla_get_be32(tb[NFTA_LOOKUP_DREG])); priv->dreg = nft_parse_register(tb[NFTA_LOOKUP_DREG]);
err = nft_validate_output_register(priv->dreg); err = nft_validate_register_store(ctx, priv->dreg, NULL,
set->dtype, set->dlen);
if (err < 0) if (err < 0)
return err; 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) } else if (set->flags & NFT_SET_MAP)
return -EINVAL; return -EINVAL;
...@@ -116,10 +115,10 @@ static int nft_lookup_dump(struct sk_buff *skb, const struct nft_expr *expr) ...@@ -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)) if (nla_put_string(skb, NFTA_LOOKUP_SET, priv->set->name))
goto nla_put_failure; 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; goto nla_put_failure;
if (priv->set->flags & NFT_SET_MAP) 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; goto nla_put_failure;
return 0; return 0;
......
...@@ -25,62 +25,65 @@ ...@@ -25,62 +25,65 @@
#include <net/netfilter/nft_meta.h> #include <net/netfilter/nft_meta.h>
void nft_meta_get_eval(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) const struct nft_pktinfo *pkt)
{ {
const struct nft_meta *priv = nft_expr_priv(expr); const struct nft_meta *priv = nft_expr_priv(expr);
const struct sk_buff *skb = pkt->skb; const struct sk_buff *skb = pkt->skb;
const struct net_device *in = pkt->in, *out = pkt->out; 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) { switch (priv->key) {
case NFT_META_LEN: case NFT_META_LEN:
dest->data[0] = skb->len; *dest = skb->len;
break; break;
case NFT_META_PROTOCOL: case NFT_META_PROTOCOL:
*(__be16 *)dest->data = skb->protocol; *dest = 0;
*(__be16 *)dest = skb->protocol;
break; break;
case NFT_META_NFPROTO: case NFT_META_NFPROTO:
dest->data[0] = pkt->ops->pf; *dest = pkt->ops->pf;
break; break;
case NFT_META_L4PROTO: case NFT_META_L4PROTO:
dest->data[0] = pkt->tprot; *dest = pkt->tprot;
break; break;
case NFT_META_PRIORITY: case NFT_META_PRIORITY:
dest->data[0] = skb->priority; *dest = skb->priority;
break; break;
case NFT_META_MARK: case NFT_META_MARK:
dest->data[0] = skb->mark; *dest = skb->mark;
break; break;
case NFT_META_IIF: case NFT_META_IIF:
if (in == NULL) if (in == NULL)
goto err; goto err;
dest->data[0] = in->ifindex; *dest = in->ifindex;
break; break;
case NFT_META_OIF: case NFT_META_OIF:
if (out == NULL) if (out == NULL)
goto err; goto err;
dest->data[0] = out->ifindex; *dest = out->ifindex;
break; break;
case NFT_META_IIFNAME: case NFT_META_IIFNAME:
if (in == NULL) if (in == NULL)
goto err; goto err;
strncpy((char *)dest->data, in->name, sizeof(dest->data)); strncpy((char *)dest, in->name, IFNAMSIZ);
break; break;
case NFT_META_OIFNAME: case NFT_META_OIFNAME:
if (out == NULL) if (out == NULL)
goto err; goto err;
strncpy((char *)dest->data, out->name, sizeof(dest->data)); strncpy((char *)dest, out->name, IFNAMSIZ);
break; break;
case NFT_META_IIFTYPE: case NFT_META_IIFTYPE:
if (in == NULL) if (in == NULL)
goto err; goto err;
*(u16 *)dest->data = in->type; *dest = 0;
*(u16 *)dest = in->type;
break; break;
case NFT_META_OIFTYPE: case NFT_META_OIFTYPE:
if (out == NULL) if (out == NULL)
goto err; goto err;
*(u16 *)dest->data = out->type; *dest = 0;
*(u16 *)dest = out->type;
break; break;
case NFT_META_SKUID: case NFT_META_SKUID:
if (skb->sk == NULL || !sk_fullsock(skb->sk)) if (skb->sk == NULL || !sk_fullsock(skb->sk))
...@@ -93,8 +96,7 @@ void nft_meta_get_eval(const struct nft_expr *expr, ...@@ -93,8 +96,7 @@ void nft_meta_get_eval(const struct nft_expr *expr,
goto err; goto err;
} }
dest->data[0] = *dest = from_kuid_munged(&init_user_ns,
from_kuid_munged(&init_user_ns,
skb->sk->sk_socket->file->f_cred->fsuid); skb->sk->sk_socket->file->f_cred->fsuid);
read_unlock_bh(&skb->sk->sk_callback_lock); read_unlock_bh(&skb->sk->sk_callback_lock);
break; break;
...@@ -108,8 +110,7 @@ void nft_meta_get_eval(const struct nft_expr *expr, ...@@ -108,8 +110,7 @@ void nft_meta_get_eval(const struct nft_expr *expr,
read_unlock_bh(&skb->sk->sk_callback_lock); read_unlock_bh(&skb->sk->sk_callback_lock);
goto err; goto err;
} }
dest->data[0] = *dest = from_kgid_munged(&init_user_ns,
from_kgid_munged(&init_user_ns,
skb->sk->sk_socket->file->f_cred->fsgid); skb->sk->sk_socket->file->f_cred->fsgid);
read_unlock_bh(&skb->sk->sk_callback_lock); read_unlock_bh(&skb->sk->sk_callback_lock);
break; break;
...@@ -119,33 +120,33 @@ void nft_meta_get_eval(const struct nft_expr *expr, ...@@ -119,33 +120,33 @@ void nft_meta_get_eval(const struct nft_expr *expr,
if (dst == NULL) if (dst == NULL)
goto err; goto err;
dest->data[0] = dst->tclassid; *dest = dst->tclassid;
break; break;
} }
#endif #endif
#ifdef CONFIG_NETWORK_SECMARK #ifdef CONFIG_NETWORK_SECMARK
case NFT_META_SECMARK: case NFT_META_SECMARK:
dest->data[0] = skb->secmark; *dest = skb->secmark;
break; break;
#endif #endif
case NFT_META_PKTTYPE: case NFT_META_PKTTYPE:
if (skb->pkt_type != PACKET_LOOPBACK) { if (skb->pkt_type != PACKET_LOOPBACK) {
dest->data[0] = skb->pkt_type; *dest = skb->pkt_type;
break; break;
} }
switch (pkt->ops->pf) { switch (pkt->ops->pf) {
case NFPROTO_IPV4: case NFPROTO_IPV4:
if (ipv4_is_multicast(ip_hdr(skb)->daddr)) if (ipv4_is_multicast(ip_hdr(skb)->daddr))
dest->data[0] = PACKET_MULTICAST; *dest = PACKET_MULTICAST;
else else
dest->data[0] = PACKET_BROADCAST; *dest = PACKET_BROADCAST;
break; break;
case NFPROTO_IPV6: case NFPROTO_IPV6:
if (ipv6_hdr(skb)->daddr.s6_addr[0] == 0xFF) if (ipv6_hdr(skb)->daddr.s6_addr[0] == 0xFF)
dest->data[0] = PACKET_MULTICAST; *dest = PACKET_MULTICAST;
else else
dest->data[0] = PACKET_BROADCAST; *dest = PACKET_BROADCAST;
break; break;
default: default:
WARN_ON(1); WARN_ON(1);
...@@ -153,22 +154,22 @@ void nft_meta_get_eval(const struct nft_expr *expr, ...@@ -153,22 +154,22 @@ void nft_meta_get_eval(const struct nft_expr *expr,
} }
break; break;
case NFT_META_CPU: case NFT_META_CPU:
dest->data[0] = raw_smp_processor_id(); *dest = raw_smp_processor_id();
break; break;
case NFT_META_IIFGROUP: case NFT_META_IIFGROUP:
if (in == NULL) if (in == NULL)
goto err; goto err;
dest->data[0] = in->group; *dest = in->group;
break; break;
case NFT_META_OIFGROUP: case NFT_META_OIFGROUP:
if (out == NULL) if (out == NULL)
goto err; goto err;
dest->data[0] = out->group; *dest = out->group;
break; break;
case NFT_META_CGROUP: case NFT_META_CGROUP:
if (skb->sk == NULL || !sk_fullsock(skb->sk)) if (skb->sk == NULL || !sk_fullsock(skb->sk))
goto err; goto err;
dest->data[0] = skb->sk->sk_classid; *dest = skb->sk->sk_classid;
break; break;
default: default:
WARN_ON(1); WARN_ON(1);
...@@ -177,17 +178,17 @@ void nft_meta_get_eval(const struct nft_expr *expr, ...@@ -177,17 +178,17 @@ void nft_meta_get_eval(const struct nft_expr *expr,
return; return;
err: err:
data[NFT_REG_VERDICT].verdict = NFT_BREAK; regs->verdict.code = NFT_BREAK;
} }
EXPORT_SYMBOL_GPL(nft_meta_get_eval); EXPORT_SYMBOL_GPL(nft_meta_get_eval);
void nft_meta_set_eval(const struct nft_expr *expr, 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_pktinfo *pkt)
{ {
const struct nft_meta *meta = nft_expr_priv(expr); const struct nft_meta *meta = nft_expr_priv(expr);
struct sk_buff *skb = pkt->skb; struct sk_buff *skb = pkt->skb;
u32 value = data[meta->sreg].data[0]; u32 value = regs->data[meta->sreg];
switch (meta->key) { switch (meta->key) {
case NFT_META_MARK: case NFT_META_MARK:
...@@ -217,22 +218,22 @@ int nft_meta_get_init(const struct nft_ctx *ctx, ...@@ -217,22 +218,22 @@ int nft_meta_get_init(const struct nft_ctx *ctx,
const struct nlattr * const tb[]) const struct nlattr * const tb[])
{ {
struct nft_meta *priv = nft_expr_priv(expr); struct nft_meta *priv = nft_expr_priv(expr);
int err; unsigned int len;
priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY])); priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
switch (priv->key) { switch (priv->key) {
case NFT_META_LEN:
case NFT_META_PROTOCOL: case NFT_META_PROTOCOL:
case NFT_META_IIFTYPE:
case NFT_META_OIFTYPE:
len = sizeof(u16);
break;
case NFT_META_NFPROTO: case NFT_META_NFPROTO:
case NFT_META_L4PROTO: case NFT_META_L4PROTO:
case NFT_META_LEN:
case NFT_META_PRIORITY: case NFT_META_PRIORITY:
case NFT_META_MARK: case NFT_META_MARK:
case NFT_META_IIF: case NFT_META_IIF:
case NFT_META_OIF: 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_SKUID:
case NFT_META_SKGID: case NFT_META_SKGID:
#ifdef CONFIG_IP_ROUTE_CLASSID #ifdef CONFIG_IP_ROUTE_CLASSID
...@@ -246,21 +247,19 @@ int nft_meta_get_init(const struct nft_ctx *ctx, ...@@ -246,21 +247,19 @@ int nft_meta_get_init(const struct nft_ctx *ctx,
case NFT_META_IIFGROUP: case NFT_META_IIFGROUP:
case NFT_META_OIFGROUP: case NFT_META_OIFGROUP:
case NFT_META_CGROUP: case NFT_META_CGROUP:
len = sizeof(u32);
break;
case NFT_META_IIFNAME:
case NFT_META_OIFNAME:
len = IFNAMSIZ;
break; break;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
priv->dreg = ntohl(nla_get_be32(tb[NFTA_META_DREG])); priv->dreg = nft_parse_register(tb[NFTA_META_DREG]);
err = nft_validate_output_register(priv->dreg); return nft_validate_register_store(ctx, priv->dreg, NULL,
if (err < 0) NFT_DATA_VALUE, len);
return err;
err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
if (err < 0)
return err;
return 0;
} }
EXPORT_SYMBOL_GPL(nft_meta_get_init); EXPORT_SYMBOL_GPL(nft_meta_get_init);
...@@ -269,20 +268,24 @@ int nft_meta_set_init(const struct nft_ctx *ctx, ...@@ -269,20 +268,24 @@ int nft_meta_set_init(const struct nft_ctx *ctx,
const struct nlattr * const tb[]) const struct nlattr * const tb[])
{ {
struct nft_meta *priv = nft_expr_priv(expr); struct nft_meta *priv = nft_expr_priv(expr);
unsigned int len;
int err; int err;
priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY])); priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
switch (priv->key) { switch (priv->key) {
case NFT_META_MARK: case NFT_META_MARK:
case NFT_META_PRIORITY: case NFT_META_PRIORITY:
len = sizeof(u32);
break;
case NFT_META_NFTRACE: case NFT_META_NFTRACE:
len = sizeof(u8);
break; break;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
priv->sreg = ntohl(nla_get_be32(tb[NFTA_META_SREG])); priv->sreg = nft_parse_register(tb[NFTA_META_SREG]);
err = nft_validate_input_register(priv->sreg); err = nft_validate_register_load(priv->sreg, len);
if (err < 0) if (err < 0)
return err; return err;
...@@ -297,7 +300,7 @@ int nft_meta_get_dump(struct sk_buff *skb, ...@@ -297,7 +300,7 @@ int nft_meta_get_dump(struct sk_buff *skb,
if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key))) if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key)))
goto nla_put_failure; 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; goto nla_put_failure;
return 0; return 0;
...@@ -313,7 +316,7 @@ int nft_meta_set_dump(struct sk_buff *skb, ...@@ -313,7 +316,7 @@ int nft_meta_set_dump(struct sk_buff *skb,
if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key))) if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key)))
goto nla_put_failure; 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; goto nla_put_failure;
return 0; return 0;
......
...@@ -37,7 +37,7 @@ struct nft_nat { ...@@ -37,7 +37,7 @@ struct nft_nat {
}; };
static void nft_nat_eval(const struct nft_expr *expr, 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_pktinfo *pkt)
{ {
const struct nft_nat *priv = nft_expr_priv(expr); const struct nft_nat *priv = nft_expr_priv(expr);
...@@ -49,33 +49,32 @@ static void nft_nat_eval(const struct nft_expr *expr, ...@@ -49,33 +49,32 @@ static void nft_nat_eval(const struct nft_expr *expr,
if (priv->sreg_addr_min) { if (priv->sreg_addr_min) {
if (priv->family == AF_INET) { if (priv->family == AF_INET) {
range.min_addr.ip = (__force __be32) 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) range.max_addr.ip = (__force __be32)
data[priv->sreg_addr_max].data[0]; regs->data[priv->sreg_addr_max];
} else { } else {
memcpy(range.min_addr.ip6, memcpy(range.min_addr.ip6,
data[priv->sreg_addr_min].data, &regs->data[priv->sreg_addr_min],
sizeof(struct nft_data)); sizeof(range.min_addr.ip6));
memcpy(range.max_addr.ip6, memcpy(range.max_addr.ip6,
data[priv->sreg_addr_max].data, &regs->data[priv->sreg_addr_max],
sizeof(struct nft_data)); sizeof(range.max_addr.ip6));
} }
range.flags |= NF_NAT_RANGE_MAP_IPS; range.flags |= NF_NAT_RANGE_MAP_IPS;
} }
if (priv->sreg_proto_min) { if (priv->sreg_proto_min) {
range.min_proto.all = range.min_proto.all =
*(__be16 *)&data[priv->sreg_proto_min].data[0]; *(__be16 *)&regs->data[priv->sreg_proto_min];
range.max_proto.all = 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 |= NF_NAT_RANGE_PROTO_SPECIFIED;
} }
range.flags |= priv->flags; range.flags |= priv->flags;
data[NFT_REG_VERDICT].verdict = regs->verdict.code = nf_nat_setup_info(ct, &range, priv->type);
nf_nat_setup_info(ct, &range, priv->type);
} }
static const struct nla_policy nft_nat_policy[NFTA_NAT_MAX + 1] = { 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, ...@@ -119,6 +118,7 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
const struct nlattr * const tb[]) const struct nlattr * const tb[])
{ {
struct nft_nat *priv = nft_expr_priv(expr); struct nft_nat *priv = nft_expr_priv(expr);
unsigned int alen, plen;
u32 family; u32 family;
int err; int err;
...@@ -146,25 +146,34 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr, ...@@ -146,25 +146,34 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
return -EINVAL; return -EINVAL;
family = ntohl(nla_get_be32(tb[NFTA_NAT_FAMILY])); family = ntohl(nla_get_be32(tb[NFTA_NAT_FAMILY]));
if (family != AF_INET && family != AF_INET6)
return -EAFNOSUPPORT;
if (family != ctx->afi->family) if (family != ctx->afi->family)
return -EOPNOTSUPP; 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; priv->family = family;
if (tb[NFTA_NAT_REG_ADDR_MIN]) { if (tb[NFTA_NAT_REG_ADDR_MIN]) {
priv->sreg_addr_min = priv->sreg_addr_min =
ntohl(nla_get_be32(tb[NFTA_NAT_REG_ADDR_MIN])); nft_parse_register(tb[NFTA_NAT_REG_ADDR_MIN]);
err = nft_validate_register_load(priv->sreg_addr_min, alen);
err = nft_validate_input_register(priv->sreg_addr_min);
if (err < 0) if (err < 0)
return err; return err;
if (tb[NFTA_NAT_REG_ADDR_MAX]) { if (tb[NFTA_NAT_REG_ADDR_MAX]) {
priv->sreg_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) if (err < 0)
return err; return err;
} else { } else {
...@@ -172,19 +181,21 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr, ...@@ -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]) { if (tb[NFTA_NAT_REG_PROTO_MIN]) {
priv->sreg_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) if (err < 0)
return err; return err;
if (tb[NFTA_NAT_REG_PROTO_MAX]) { if (tb[NFTA_NAT_REG_PROTO_MAX]) {
priv->sreg_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) if (err < 0)
return err; return err;
} else { } else {
...@@ -220,18 +231,18 @@ static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr) ...@@ -220,18 +231,18 @@ static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr)
goto nla_put_failure; goto nla_put_failure;
if (priv->sreg_addr_min) { if (priv->sreg_addr_min) {
if (nla_put_be32(skb, NFTA_NAT_REG_ADDR_MIN, if (nft_dump_register(skb, NFTA_NAT_REG_ADDR_MIN,
htonl(priv->sreg_addr_min)) || priv->sreg_addr_min) ||
nla_put_be32(skb, NFTA_NAT_REG_ADDR_MAX, nft_dump_register(skb, NFTA_NAT_REG_ADDR_MAX,
htonl(priv->sreg_addr_max))) priv->sreg_addr_max))
goto nla_put_failure; goto nla_put_failure;
} }
if (priv->sreg_proto_min) { if (priv->sreg_proto_min) {
if (nla_put_be32(skb, NFTA_NAT_REG_PROTO_MIN, if (nft_dump_register(skb, NFTA_NAT_REG_PROTO_MIN,
htonl(priv->sreg_proto_min)) || priv->sreg_proto_min) ||
nla_put_be32(skb, NFTA_NAT_REG_PROTO_MAX, nft_dump_register(skb, NFTA_NAT_REG_PROTO_MAX,
htonl(priv->sreg_proto_max))) priv->sreg_proto_max))
goto nla_put_failure; goto nla_put_failure;
} }
......
...@@ -18,12 +18,12 @@ ...@@ -18,12 +18,12 @@
#include <net/netfilter/nf_tables.h> #include <net/netfilter/nf_tables.h>
static void nft_payload_eval(const struct nft_expr *expr, 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_pktinfo *pkt)
{ {
const struct nft_payload *priv = nft_expr_priv(expr); const struct nft_payload *priv = nft_expr_priv(expr);
const struct sk_buff *skb = pkt->skb; const struct sk_buff *skb = pkt->skb;
struct nft_data *dest = &data[priv->dreg]; u32 *dest = &regs->data[priv->dreg];
int offset; int offset;
switch (priv->base) { switch (priv->base) {
...@@ -43,11 +43,12 @@ static void nft_payload_eval(const struct nft_expr *expr, ...@@ -43,11 +43,12 @@ static void nft_payload_eval(const struct nft_expr *expr,
} }
offset += priv->offset; 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; goto err;
return; return;
err: 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] = { 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, ...@@ -62,24 +63,21 @@ static int nft_payload_init(const struct nft_ctx *ctx,
const struct nlattr * const tb[]) const struct nlattr * const tb[])
{ {
struct nft_payload *priv = nft_expr_priv(expr); struct nft_payload *priv = nft_expr_priv(expr);
int err;
priv->base = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_BASE])); priv->base = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_BASE]));
priv->offset = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_OFFSET])); priv->offset = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_OFFSET]));
priv->len = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN])); 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])); return nft_validate_register_store(ctx, priv->dreg, NULL,
err = nft_validate_output_register(priv->dreg); NFT_DATA_VALUE, priv->len);
if (err < 0)
return err;
return nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
} }
static int nft_payload_dump(struct sk_buff *skb, const struct nft_expr *expr) static int nft_payload_dump(struct sk_buff *skb, const struct nft_expr *expr)
{ {
const struct nft_payload *priv = nft_expr_priv(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_BASE, htonl(priv->base)) ||
nla_put_be32(skb, NFTA_PAYLOAD_OFFSET, htonl(priv->offset)) || nla_put_be32(skb, NFTA_PAYLOAD_OFFSET, htonl(priv->offset)) ||
nla_put_be32(skb, NFTA_PAYLOAD_LEN, htonl(priv->len))) nla_put_be32(skb, NFTA_PAYLOAD_LEN, htonl(priv->len)))
...@@ -131,9 +129,7 @@ nft_payload_select_ops(const struct nft_ctx *ctx, ...@@ -131,9 +129,7 @@ nft_payload_select_ops(const struct nft_ctx *ctx,
} }
offset = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_OFFSET])); offset = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_OFFSET]));
len = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN])); len = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN]));
if (len == 0 || len > FIELD_SIZEOF(struct nft_data, data))
return ERR_PTR(-EINVAL);
if (len <= 4 && is_power_of_2(len) && IS_ALIGNED(offset, len) && if (len <= 4 && is_power_of_2(len) && IS_ALIGNED(offset, len) &&
base != NFT_PAYLOAD_LL_HEADER) base != NFT_PAYLOAD_LL_HEADER)
......
...@@ -28,7 +28,7 @@ struct nft_queue { ...@@ -28,7 +28,7 @@ struct nft_queue {
}; };
static void nft_queue_eval(const struct nft_expr *expr, 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) const struct nft_pktinfo *pkt)
{ {
struct nft_queue *priv = nft_expr_priv(expr); struct nft_queue *priv = nft_expr_priv(expr);
...@@ -51,7 +51,7 @@ static void nft_queue_eval(const struct nft_expr *expr, ...@@ -51,7 +51,7 @@ static void nft_queue_eval(const struct nft_expr *expr,
if (priv->flags & NFT_QUEUE_FLAG_BYPASS) if (priv->flags & NFT_QUEUE_FLAG_BYPASS)
ret |= NF_VERDICT_FLAG_QUEUE_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] = { static const struct nla_policy nft_queue_policy[NFTA_QUEUE_MAX + 1] = {
......
...@@ -30,8 +30,7 @@ struct nft_rbtree_elem { ...@@ -30,8 +30,7 @@ struct nft_rbtree_elem {
}; };
static bool nft_rbtree_lookup(const struct nft_set *set, static bool nft_rbtree_lookup(const struct nft_set *set, const u32 *key,
const struct nft_data *key,
const struct nft_set_ext **ext) const struct nft_set_ext **ext)
{ {
const struct nft_rbtree *priv = nft_set_priv(set); const struct nft_rbtree *priv = nft_set_priv(set);
...@@ -45,7 +44,7 @@ static bool nft_rbtree_lookup(const struct nft_set *set, ...@@ -45,7 +44,7 @@ static bool nft_rbtree_lookup(const struct nft_set *set,
while (parent != NULL) { while (parent != NULL) {
rbe = rb_entry(parent, struct nft_rbtree_elem, node); 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) { if (d < 0) {
parent = parent->rb_left; parent = parent->rb_left;
interval = rbe; interval = rbe;
...@@ -91,9 +90,9 @@ static int __nft_rbtree_insert(const struct nft_set *set, ...@@ -91,9 +90,9 @@ static int __nft_rbtree_insert(const struct nft_set *set,
while (*p != NULL) { while (*p != NULL) {
parent = *p; parent = *p;
rbe = rb_entry(parent, struct nft_rbtree_elem, node); rbe = rb_entry(parent, struct nft_rbtree_elem, node);
d = nft_data_cmp(nft_set_ext_key(&rbe->ext), d = memcmp(nft_set_ext_key(&rbe->ext),
nft_set_ext_key(&new->ext), nft_set_ext_key(&new->ext),
set->klen); set->klen);
if (d < 0) if (d < 0)
p = &parent->rb_left; p = &parent->rb_left;
else if (d > 0) else if (d > 0)
...@@ -153,8 +152,8 @@ static void *nft_rbtree_deactivate(const struct nft_set *set, ...@@ -153,8 +152,8 @@ static void *nft_rbtree_deactivate(const struct nft_set *set,
while (parent != NULL) { while (parent != NULL) {
rbe = rb_entry(parent, struct nft_rbtree_elem, node); rbe = rb_entry(parent, struct nft_rbtree_elem, node);
d = nft_data_cmp(nft_set_ext_key(&rbe->ext), &elem->key, d = memcmp(nft_set_ext_key(&rbe->ext), &elem->key.val,
set->klen); set->klen);
if (d < 0) if (d < 0)
parent = parent->rb_left; parent = parent->rb_left;
else if (d > 0) else if (d > 0)
......
...@@ -44,25 +44,28 @@ int nft_redir_init(const struct nft_ctx *ctx, ...@@ -44,25 +44,28 @@ int nft_redir_init(const struct nft_ctx *ctx,
const struct nlattr * const tb[]) const struct nlattr * const tb[])
{ {
struct nft_redir *priv = nft_expr_priv(expr); struct nft_redir *priv = nft_expr_priv(expr);
unsigned int plen;
int err; int err;
err = nft_redir_validate(ctx, expr, NULL); err = nft_redir_validate(ctx, expr, NULL);
if (err < 0) if (err < 0)
return err; return err;
plen = FIELD_SIZEOF(struct nf_nat_range, min_addr.all);
if (tb[NFTA_REDIR_REG_PROTO_MIN]) { if (tb[NFTA_REDIR_REG_PROTO_MIN]) {
priv->sreg_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) if (err < 0)
return err; return err;
if (tb[NFTA_REDIR_REG_PROTO_MAX]) { if (tb[NFTA_REDIR_REG_PROTO_MAX]) {
priv->sreg_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) if (err < 0)
return err; return err;
} else { } else {
...@@ -85,11 +88,11 @@ int nft_redir_dump(struct sk_buff *skb, const struct nft_expr *expr) ...@@ -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); const struct nft_redir *priv = nft_expr_priv(expr);
if (priv->sreg_proto_min) { if (priv->sreg_proto_min) {
if (nla_put_be32(skb, NFTA_REDIR_REG_PROTO_MIN, if (nft_dump_register(skb, NFTA_REDIR_REG_PROTO_MIN,
htonl(priv->sreg_proto_min))) priv->sreg_proto_min))
goto nla_put_failure; goto nla_put_failure;
if (nla_put_be32(skb, NFTA_REDIR_REG_PROTO_MAX, if (nft_dump_register(skb, NFTA_REDIR_REG_PROTO_MAX,
htonl(priv->sreg_proto_max))) priv->sreg_proto_max))
goto nla_put_failure; goto nla_put_failure;
} }
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include <net/netfilter/ipv6/nf_reject.h> #include <net/netfilter/ipv6/nf_reject.h>
static void nft_reject_inet_eval(const struct nft_expr *expr, 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) const struct nft_pktinfo *pkt)
{ {
struct nft_reject *priv = nft_expr_priv(expr); struct nft_reject *priv = nft_expr_priv(expr);
...@@ -58,7 +58,8 @@ static void nft_reject_inet_eval(const struct nft_expr *expr, ...@@ -58,7 +58,8 @@ static void nft_reject_inet_eval(const struct nft_expr *expr,
} }
break; break;
} }
data[NFT_REG_VERDICT].verdict = NF_DROP;
regs->verdict.code = NF_DROP;
} }
static int nft_reject_inet_init(const struct nft_ctx *ctx, static int nft_reject_inet_init(const struct nft_ctx *ctx,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment