summaryrefslogtreecommitdiff
path: root/net/netfilter
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2014-04-07 23:49:35 (GMT)
committerScott Wood <scottwood@freescale.com>2014-04-07 23:49:35 (GMT)
commit62b8c978ee6b8d135d9e7953221de58000dba986 (patch)
tree683b04b2e627f6710c22c151b23c8cc9a165315e /net/netfilter
parent78fd82238d0e5716578c326404184a27ba67fd6e (diff)
downloadlinux-fsl-qoriq-62b8c978ee6b8d135d9e7953221de58000dba986.tar.xz
Rewind v3.13-rc3+ (78fd82238d0e5716) to v3.12
Diffstat (limited to 'net/netfilter')
-rw-r--r--net/netfilter/Kconfig54
-rw-r--r--net/netfilter/Makefile18
-rw-r--r--net/netfilter/core.c2
-rw-r--r--net/netfilter/ipset/Kconfig20
-rw-r--r--net/netfilter/ipset/Makefile2
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_gen.h174
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_ip.c125
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_ipmac.c156
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_port.c114
-rw-r--r--net/netfilter/ipset/ip_set_core.c409
-rw-r--r--net/netfilter/ipset/ip_set_getport.c18
-rw-r--r--net/netfilter/ipset/ip_set_hash_gen.h545
-rw-r--r--net/netfilter/ipset/ip_set_hash_ip.c58
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipport.c80
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipportip.c86
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipportnet.c108
-rw-r--r--net/netfilter/ipset/ip_set_hash_net.c85
-rw-r--r--net/netfilter/ipset/ip_set_hash_netiface.c98
-rw-r--r--net/netfilter/ipset/ip_set_hash_netnet.c481
-rw-r--r--net/netfilter/ipset/ip_set_hash_netport.c92
-rw-r--r--net/netfilter/ipset/ip_set_hash_netportnet.c586
-rw-r--r--net/netfilter/ipset/ip_set_list_set.c274
-rw-r--r--net/netfilter/ipvs/ip_vs_core.c95
-rw-r--r--net/netfilter/ipvs/ip_vs_ctl.c35
-rw-r--r--net/netfilter/ipvs/ip_vs_lblc.c2
-rw-r--r--net/netfilter/ipvs/ip_vs_lblcr.c2
-rw-r--r--net/netfilter/ipvs/ip_vs_pe_sip.c8
-rw-r--r--net/netfilter/ipvs/ip_vs_proto_sctp.c48
-rw-r--r--net/netfilter/ipvs/ip_vs_sh.c39
-rw-r--r--net/netfilter/ipvs/ip_vs_sync.c7
-rw-r--r--net/netfilter/nf_conntrack_acct.c12
-rw-r--r--net/netfilter/nf_conntrack_core.c19
-rw-r--r--net/netfilter/nf_conntrack_netlink.c51
-rw-r--r--net/netfilter/nf_conntrack_seqadj.c4
-rw-r--r--net/netfilter/nf_conntrack_sip.c133
-rw-r--r--net/netfilter/nf_internals.h28
-rw-r--r--net/netfilter/nf_nat_core.c20
-rw-r--r--net/netfilter/nf_nat_sip.c35
-rw-r--r--net/netfilter/nf_synproxy_core.c7
-rw-r--r--net/netfilter/nf_tables_api.c3275
-rw-r--r--net/netfilter/nf_tables_core.c270
-rw-r--r--net/netfilter/nfnetlink.c177
-rw-r--r--net/netfilter/nfnetlink_cttimeout.c161
-rw-r--r--net/netfilter/nfnetlink_log.c11
-rw-r--r--net/netfilter/nfnetlink_queue_core.c6
-rw-r--r--net/netfilter/nft_bitwise.c146
-rw-r--r--net/netfilter/nft_byteorder.c173
-rw-r--r--net/netfilter/nft_cmp.c223
-rw-r--r--net/netfilter/nft_compat.c775
-rw-r--r--net/netfilter/nft_counter.c113
-rw-r--r--net/netfilter/nft_ct.c258
-rw-r--r--net/netfilter/nft_expr_template.c94
-rw-r--r--net/netfilter/nft_exthdr.c133
-rw-r--r--net/netfilter/nft_hash.c231
-rw-r--r--net/netfilter/nft_immediate.c132
-rw-r--r--net/netfilter/nft_limit.c119
-rw-r--r--net/netfilter/nft_log.c146
-rw-r--r--net/netfilter/nft_lookup.c141
-rw-r--r--net/netfilter/nft_meta.c228
-rw-r--r--net/netfilter/nft_meta_target.c117
-rw-r--r--net/netfilter/nft_nat.c224
-rw-r--r--net/netfilter/nft_payload.c160
-rw-r--r--net/netfilter/nft_rbtree.c247
-rw-r--r--net/netfilter/x_tables.c7
-rw-r--r--net/netfilter/xt_NFQUEUE.c7
-rw-r--r--net/netfilter/xt_TCPMSS.c72
-rw-r--r--net/netfilter/xt_TPROXY.c2
-rw-r--r--net/netfilter/xt_connbytes.c6
-rw-r--r--net/netfilter/xt_set.c224
-rw-r--r--net/netfilter/xt_socket.c15
70 files changed, 1893 insertions, 10130 deletions
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index c3398cd..6e839b6 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -413,58 +413,6 @@ config NETFILTER_SYNPROXY
endif # NF_CONNTRACK
-config NF_TABLES
- depends on NETFILTER_NETLINK
- tristate "Netfilter nf_tables support"
-
-config NFT_EXTHDR
- depends on NF_TABLES
- tristate "Netfilter nf_tables IPv6 exthdr module"
-
-config NFT_META
- depends on NF_TABLES
- tristate "Netfilter nf_tables meta module"
-
-config NFT_CT
- depends on NF_TABLES
- depends on NF_CONNTRACK
- tristate "Netfilter nf_tables conntrack module"
-
-config NFT_RBTREE
- depends on NF_TABLES
- tristate "Netfilter nf_tables rbtree set module"
-
-config NFT_HASH
- depends on NF_TABLES
- tristate "Netfilter nf_tables hash set module"
-
-config NFT_COUNTER
- depends on NF_TABLES
- tristate "Netfilter nf_tables counter module"
-
-config NFT_LOG
- depends on NF_TABLES
- tristate "Netfilter nf_tables log module"
-
-config NFT_LIMIT
- depends on NF_TABLES
- tristate "Netfilter nf_tables limit module"
-
-config NFT_NAT
- depends on NF_TABLES
- depends on NF_CONNTRACK
- depends on NF_NAT
- tristate "Netfilter nf_tables nat module"
-
-config NFT_COMPAT
- depends on NF_TABLES
- depends on NETFILTER_XTABLES
- tristate "Netfilter x_tables over nf_tables module"
- help
- This is required if you intend to use any of existing
- x_tables match/target extensions over the nf_tables
- framework.
-
config NETFILTER_XTABLES
tristate "Netfilter Xtables support (required for ip_tables)"
default m if NETFILTER_ADVANCED=n
@@ -909,7 +857,7 @@ config NETFILTER_XT_MATCH_CONNLABEL
connection simultaneously.
config NETFILTER_XT_MATCH_CONNLIMIT
- tristate '"connlimit" match support'
+ tristate '"connlimit" match support"'
depends on NF_CONNTRACK
depends on NETFILTER_ADVANCED
---help---
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 394483b..c3a0a12 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -64,24 +64,6 @@ obj-$(CONFIG_NF_NAT_TFTP) += nf_nat_tftp.o
# SYNPROXY
obj-$(CONFIG_NETFILTER_SYNPROXY) += nf_synproxy_core.o
-# nf_tables
-nf_tables-objs += nf_tables_core.o nf_tables_api.o
-nf_tables-objs += nft_immediate.o nft_cmp.o nft_lookup.o
-nf_tables-objs += nft_bitwise.o nft_byteorder.o nft_payload.o
-
-obj-$(CONFIG_NF_TABLES) += nf_tables.o
-obj-$(CONFIG_NFT_COMPAT) += nft_compat.o
-obj-$(CONFIG_NFT_EXTHDR) += nft_exthdr.o
-obj-$(CONFIG_NFT_META) += nft_meta.o
-obj-$(CONFIG_NFT_CT) += nft_ct.o
-obj-$(CONFIG_NFT_LIMIT) += nft_limit.o
-obj-$(CONFIG_NFT_NAT) += nft_nat.o
-#nf_tables-objs += nft_meta_target.o
-obj-$(CONFIG_NFT_RBTREE) += nft_rbtree.o
-obj-$(CONFIG_NFT_HASH) += nft_hash.o
-obj-$(CONFIG_NFT_COUNTER) += nft_counter.o
-obj-$(CONFIG_NFT_LOG) += nft_log.o
-
# generic X tables
obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index 1fbab0c..593b16e 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -146,7 +146,7 @@ unsigned int nf_iterate(struct list_head *head,
/* Optimization: we don't need to hold module
reference here, since function can't sleep. --RR */
repeat:
- verdict = (*elemp)->hook(*elemp, skb, indev, outdev, okfn);
+ verdict = (*elemp)->hook(hook, skb, indev, outdev, okfn);
if (verdict != NF_ACCEPT) {
#ifdef CONFIG_NETFILTER_DEBUG
if (unlikely((verdict & NF_VERDICT_MASK)
diff --git a/net/netfilter/ipset/Kconfig b/net/netfilter/ipset/Kconfig
index a2d6263..ba36c28 100644
--- a/net/netfilter/ipset/Kconfig
+++ b/net/netfilter/ipset/Kconfig
@@ -1,7 +1,7 @@
menuconfig IP_SET
tristate "IP set support"
depends on INET && NETFILTER
- select NETFILTER_NETLINK
+ depends on NETFILTER_NETLINK
help
This option adds IP set support to the kernel.
In order to define and use the sets, you need the userspace utility
@@ -90,15 +90,6 @@ config IP_SET_HASH_IPPORTNET
To compile it as a module, choose M here. If unsure, say N.
-config IP_SET_HASH_NETPORTNET
- tristate "hash:net,port,net set support"
- depends on IP_SET
- help
- This option adds the hash:net,port,net set type support, by which
- one can store two IPv4/IPv6 subnets, and a protocol/port in a set.
-
- To compile it as a module, choose M here. If unsure, say N.
-
config IP_SET_HASH_NET
tristate "hash:net set support"
depends on IP_SET
@@ -108,15 +99,6 @@ config IP_SET_HASH_NET
To compile it as a module, choose M here. If unsure, say N.
-config IP_SET_HASH_NETNET
- tristate "hash:net,net set support"
- depends on IP_SET
- help
- This option adds the hash:net,net set type support, by which
- one can store IPv4/IPv6 network address/prefix pairs in a set.
-
- To compile it as a module, choose M here. If unsure, say N.
-
config IP_SET_HASH_NETPORT
tristate "hash:net,port set support"
depends on IP_SET
diff --git a/net/netfilter/ipset/Makefile b/net/netfilter/ipset/Makefile
index 44b2d38..6e965ec 100644
--- a/net/netfilter/ipset/Makefile
+++ b/net/netfilter/ipset/Makefile
@@ -20,8 +20,6 @@ obj-$(CONFIG_IP_SET_HASH_IPPORTNET) += ip_set_hash_ipportnet.o
obj-$(CONFIG_IP_SET_HASH_NET) += ip_set_hash_net.o
obj-$(CONFIG_IP_SET_HASH_NETPORT) += ip_set_hash_netport.o
obj-$(CONFIG_IP_SET_HASH_NETIFACE) += ip_set_hash_netiface.o
-obj-$(CONFIG_IP_SET_HASH_NETNET) += ip_set_hash_netnet.o
-obj-$(CONFIG_IP_SET_HASH_NETPORTNET) += ip_set_hash_netportnet.o
# list types
obj-$(CONFIG_IP_SET_LIST_SET) += ip_set_list_set.o
diff --git a/net/netfilter/ipset/ip_set_bitmap_gen.h b/net/netfilter/ipset/ip_set_bitmap_gen.h
index f2c7d83..2524337 100644
--- a/net/netfilter/ipset/ip_set_bitmap_gen.h
+++ b/net/netfilter/ipset/ip_set_bitmap_gen.h
@@ -8,32 +8,38 @@
#ifndef __IP_SET_BITMAP_IP_GEN_H
#define __IP_SET_BITMAP_IP_GEN_H
-#define mtype_do_test IPSET_TOKEN(MTYPE, _do_test)
-#define mtype_gc_test IPSET_TOKEN(MTYPE, _gc_test)
-#define mtype_is_filled IPSET_TOKEN(MTYPE, _is_filled)
-#define mtype_do_add IPSET_TOKEN(MTYPE, _do_add)
-#define mtype_ext_cleanup IPSET_TOKEN(MTYPE, _ext_cleanup)
-#define mtype_do_del IPSET_TOKEN(MTYPE, _do_del)
-#define mtype_do_list IPSET_TOKEN(MTYPE, _do_list)
-#define mtype_do_head IPSET_TOKEN(MTYPE, _do_head)
-#define mtype_adt_elem IPSET_TOKEN(MTYPE, _adt_elem)
-#define mtype_add_timeout IPSET_TOKEN(MTYPE, _add_timeout)
-#define mtype_gc_init IPSET_TOKEN(MTYPE, _gc_init)
-#define mtype_kadt IPSET_TOKEN(MTYPE, _kadt)
-#define mtype_uadt IPSET_TOKEN(MTYPE, _uadt)
-#define mtype_destroy IPSET_TOKEN(MTYPE, _destroy)
-#define mtype_flush IPSET_TOKEN(MTYPE, _flush)
-#define mtype_head IPSET_TOKEN(MTYPE, _head)
-#define mtype_same_set IPSET_TOKEN(MTYPE, _same_set)
-#define mtype_elem IPSET_TOKEN(MTYPE, _elem)
-#define mtype_test IPSET_TOKEN(MTYPE, _test)
-#define mtype_add IPSET_TOKEN(MTYPE, _add)
-#define mtype_del IPSET_TOKEN(MTYPE, _del)
-#define mtype_list IPSET_TOKEN(MTYPE, _list)
-#define mtype_gc IPSET_TOKEN(MTYPE, _gc)
+#define CONCAT(a, b) a##b
+#define TOKEN(a,b) CONCAT(a, b)
+
+#define mtype_do_test TOKEN(MTYPE, _do_test)
+#define mtype_gc_test TOKEN(MTYPE, _gc_test)
+#define mtype_is_filled TOKEN(MTYPE, _is_filled)
+#define mtype_do_add TOKEN(MTYPE, _do_add)
+#define mtype_do_del TOKEN(MTYPE, _do_del)
+#define mtype_do_list TOKEN(MTYPE, _do_list)
+#define mtype_do_head TOKEN(MTYPE, _do_head)
+#define mtype_adt_elem TOKEN(MTYPE, _adt_elem)
+#define mtype_add_timeout TOKEN(MTYPE, _add_timeout)
+#define mtype_gc_init TOKEN(MTYPE, _gc_init)
+#define mtype_kadt TOKEN(MTYPE, _kadt)
+#define mtype_uadt TOKEN(MTYPE, _uadt)
+#define mtype_destroy TOKEN(MTYPE, _destroy)
+#define mtype_flush TOKEN(MTYPE, _flush)
+#define mtype_head TOKEN(MTYPE, _head)
+#define mtype_same_set TOKEN(MTYPE, _same_set)
+#define mtype_elem TOKEN(MTYPE, _elem)
+#define mtype_test TOKEN(MTYPE, _test)
+#define mtype_add TOKEN(MTYPE, _add)
+#define mtype_del TOKEN(MTYPE, _del)
+#define mtype_list TOKEN(MTYPE, _list)
+#define mtype_gc TOKEN(MTYPE, _gc)
#define mtype MTYPE
-#define get_ext(set, map, id) ((map)->extensions + (set)->dsize * (id))
+#define ext_timeout(e, m) \
+ (unsigned long *)((e) + (m)->offset[IPSET_OFFSET_TIMEOUT])
+#define ext_counter(e, m) \
+ (struct ip_set_counter *)((e) + (m)->offset[IPSET_OFFSET_COUNTER])
+#define get_ext(map, id) ((map)->extensions + (map)->dsize * (id))
static void
mtype_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))
@@ -43,22 +49,11 @@ mtype_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))
init_timer(&map->gc);
map->gc.data = (unsigned long) set;
map->gc.function = gc;
- map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;
+ map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
add_timer(&map->gc);
}
static void
-mtype_ext_cleanup(struct ip_set *set)
-{
- struct mtype *map = set->data;
- u32 id;
-
- for (id = 0; id < map->elements; id++)
- if (test_bit(id, map->members))
- ip_set_ext_destroy(set, get_ext(set, map, id));
-}
-
-static void
mtype_destroy(struct ip_set *set)
{
struct mtype *map = set->data;
@@ -67,11 +62,8 @@ mtype_destroy(struct ip_set *set)
del_timer_sync(&map->gc);
ip_set_free(map->members);
- if (set->dsize) {
- if (set->extensions & IPSET_EXT_DESTROY)
- mtype_ext_cleanup(set);
+ if (map->dsize)
ip_set_free(map->extensions);
- }
kfree(map);
set->data = NULL;
@@ -82,8 +74,6 @@ mtype_flush(struct ip_set *set)
{
struct mtype *map = set->data;
- if (set->extensions & IPSET_EXT_DESTROY)
- mtype_ext_cleanup(set);
memset(map->members, 0, map->memsize);
}
@@ -101,9 +91,12 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
nla_put_net32(skb, IPSET_ATTR_MEMSIZE,
htonl(sizeof(*map) +
map->memsize +
- set->dsize * map->elements)))
- goto nla_put_failure;
- if (unlikely(ip_set_put_flags(skb, set)))
+ map->dsize * map->elements)) ||
+ (SET_WITH_TIMEOUT(set) &&
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout))) ||
+ (SET_WITH_COUNTER(set) &&
+ nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS,
+ htonl(IPSET_FLAG_WITH_COUNTERS))))
goto nla_put_failure;
ipset_nest_end(skb, nested);
@@ -118,16 +111,16 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext,
{
struct mtype *map = set->data;
const struct mtype_adt_elem *e = value;
- void *x = get_ext(set, map, e->id);
- int ret = mtype_do_test(e, map, set->dsize);
+ void *x = get_ext(map, e->id);
+ int ret = mtype_do_test(e, map);
if (ret <= 0)
return ret;
if (SET_WITH_TIMEOUT(set) &&
- ip_set_timeout_expired(ext_timeout(x, set)))
+ ip_set_timeout_expired(ext_timeout(x, map)))
return 0;
if (SET_WITH_COUNTER(set))
- ip_set_update_counter(ext_counter(x, set), ext, mext, flags);
+ ip_set_update_counter(ext_counter(x, map), ext, mext, flags);
return 1;
}
@@ -137,30 +130,26 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
{
struct mtype *map = set->data;
const struct mtype_adt_elem *e = value;
- void *x = get_ext(set, map, e->id);
- int ret = mtype_do_add(e, map, flags, set->dsize);
+ void *x = get_ext(map, e->id);
+ int ret = mtype_do_add(e, map, flags);
if (ret == IPSET_ADD_FAILED) {
if (SET_WITH_TIMEOUT(set) &&
- ip_set_timeout_expired(ext_timeout(x, set)))
+ ip_set_timeout_expired(ext_timeout(x, map)))
ret = 0;
else if (!(flags & IPSET_FLAG_EXIST))
return -IPSET_ERR_EXIST;
- /* Element is re-added, cleanup extensions */
- ip_set_ext_destroy(set, x);
}
if (SET_WITH_TIMEOUT(set))
#ifdef IP_SET_BITMAP_STORED_TIMEOUT
- mtype_add_timeout(ext_timeout(x, set), e, ext, set, map, ret);
+ mtype_add_timeout(ext_timeout(x, map), e, ext, map, ret);
#else
- ip_set_timeout_set(ext_timeout(x, set), ext->timeout);
+ ip_set_timeout_set(ext_timeout(x, map), ext->timeout);
#endif
if (SET_WITH_COUNTER(set))
- ip_set_init_counter(ext_counter(x, set), ext);
- if (SET_WITH_COMMENT(set))
- ip_set_init_comment(ext_comment(x, set), ext);
+ ip_set_init_counter(ext_counter(x, map), ext);
return 0;
}
@@ -170,27 +159,16 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
{
struct mtype *map = set->data;
const struct mtype_adt_elem *e = value;
- void *x = get_ext(set, map, e->id);
+ const void *x = get_ext(map, e->id);
- if (mtype_do_del(e, map))
- return -IPSET_ERR_EXIST;
-
- ip_set_ext_destroy(set, x);
- if (SET_WITH_TIMEOUT(set) &&
- ip_set_timeout_expired(ext_timeout(x, set)))
+ if (mtype_do_del(e, map) ||
+ (SET_WITH_TIMEOUT(set) &&
+ ip_set_timeout_expired(ext_timeout(x, map))))
return -IPSET_ERR_EXIST;
return 0;
}
-#ifndef IP_SET_BITMAP_STORED_TIMEOUT
-static inline bool
-mtype_is_filled(const struct mtype_elem *x)
-{
- return true;
-}
-#endif
-
static int
mtype_list(const struct ip_set *set,
struct sk_buff *skb, struct netlink_callback *cb)
@@ -198,21 +176,20 @@ mtype_list(const struct ip_set *set,
struct mtype *map = set->data;
struct nlattr *adt, *nested;
void *x;
- u32 id, first = cb->args[IPSET_CB_ARG0];
+ u32 id, first = cb->args[2];
adt = ipset_nest_start(skb, IPSET_ATTR_ADT);
if (!adt)
return -EMSGSIZE;
- for (; cb->args[IPSET_CB_ARG0] < map->elements;
- cb->args[IPSET_CB_ARG0]++) {
- id = cb->args[IPSET_CB_ARG0];
- x = get_ext(set, map, id);
+ for (; cb->args[2] < map->elements; cb->args[2]++) {
+ id = cb->args[2];
+ x = get_ext(map, id);
if (!test_bit(id, map->members) ||
(SET_WITH_TIMEOUT(set) &&
#ifdef IP_SET_BITMAP_STORED_TIMEOUT
mtype_is_filled((const struct mtype_elem *) x) &&
#endif
- ip_set_timeout_expired(ext_timeout(x, set))))
+ ip_set_timeout_expired(ext_timeout(x, map))))
continue;
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested) {
@@ -222,27 +199,40 @@ mtype_list(const struct ip_set *set,
} else
goto nla_put_failure;
}
- if (mtype_do_list(skb, map, id, set->dsize))
+ if (mtype_do_list(skb, map, id))
goto nla_put_failure;
- if (ip_set_put_extensions(skb, set, x,
- mtype_is_filled((const struct mtype_elem *) x)))
+ if (SET_WITH_TIMEOUT(set)) {
+#ifdef IP_SET_BITMAP_STORED_TIMEOUT
+ if (nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
+ htonl(ip_set_timeout_stored(map, id,
+ ext_timeout(x, map)))))
+ goto nla_put_failure;
+#else
+ if (nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
+ htonl(ip_set_timeout_get(
+ ext_timeout(x, map)))))
+ goto nla_put_failure;
+#endif
+ }
+ if (SET_WITH_COUNTER(set) &&
+ ip_set_put_counter(skb, ext_counter(x, map)))
goto nla_put_failure;
ipset_nest_end(skb, nested);
}
ipset_nest_end(skb, adt);
/* Set listing finished */
- cb->args[IPSET_CB_ARG0] = 0;
+ cb->args[2] = 0;
return 0;
nla_put_failure:
nla_nest_cancel(skb, nested);
+ ipset_nest_end(skb, adt);
if (unlikely(id == first)) {
- cb->args[IPSET_CB_ARG0] = 0;
+ cb->args[2] = 0;
return -EMSGSIZE;
}
- ipset_nest_end(skb, adt);
return 0;
}
@@ -251,23 +241,21 @@ mtype_gc(unsigned long ul_set)
{
struct ip_set *set = (struct ip_set *) ul_set;
struct mtype *map = set->data;
- void *x;
+ const void *x;
u32 id;
/* We run parallel with other readers (test element)
* but adding/deleting new entries is locked out */
read_lock_bh(&set->lock);
for (id = 0; id < map->elements; id++)
- if (mtype_gc_test(id, map, set->dsize)) {
- x = get_ext(set, map, id);
- if (ip_set_timeout_expired(ext_timeout(x, set))) {
+ if (mtype_gc_test(id, map)) {
+ x = get_ext(map, id);
+ if (ip_set_timeout_expired(ext_timeout(x, map)))
clear_bit(id, map->members);
- ip_set_ext_destroy(set, x);
- }
}
read_unlock_bh(&set->lock);
- map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;
+ map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
add_timer(&map->gc);
}
diff --git a/net/netfilter/ipset/ip_set_bitmap_ip.c b/net/netfilter/ipset/ip_set_bitmap_ip.c
index 6f1f9f4..f1a8128 100644
--- a/net/netfilter/ipset/ip_set_bitmap_ip.c
+++ b/net/netfilter/ipset/ip_set_bitmap_ip.c
@@ -25,13 +25,12 @@
#include <linux/netfilter/ipset/ip_set.h>
#include <linux/netfilter/ipset/ip_set_bitmap.h>
-#define IPSET_TYPE_REV_MIN 0
-/* 1 Counter support added */
-#define IPSET_TYPE_REV_MAX 2 /* Comment support added */
+#define REVISION_MIN 0
+#define REVISION_MAX 1 /* Counter support added */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
-IP_SET_MODULE_DESC("bitmap:ip", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
+IP_SET_MODULE_DESC("bitmap:ip", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_bitmap:ip");
#define MTYPE bitmap_ip
@@ -45,7 +44,10 @@ struct bitmap_ip {
u32 elements; /* number of max elements in the set */
u32 hosts; /* number of hosts in a subnet */
size_t memsize; /* members size */
+ size_t dsize; /* extensions struct size */
+ size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */
u8 netmask; /* subnet netmask */
+ u32 timeout; /* timeout parameter */
struct timer_list gc; /* garbage collection */
};
@@ -63,21 +65,20 @@ ip_to_id(const struct bitmap_ip *m, u32 ip)
/* Common functions */
static inline int
-bitmap_ip_do_test(const struct bitmap_ip_adt_elem *e,
- struct bitmap_ip *map, size_t dsize)
+bitmap_ip_do_test(const struct bitmap_ip_adt_elem *e, struct bitmap_ip *map)
{
return !!test_bit(e->id, map->members);
}
static inline int
-bitmap_ip_gc_test(u16 id, const struct bitmap_ip *map, size_t dsize)
+bitmap_ip_gc_test(u16 id, const struct bitmap_ip *map)
{
return !!test_bit(id, map->members);
}
static inline int
bitmap_ip_do_add(const struct bitmap_ip_adt_elem *e, struct bitmap_ip *map,
- u32 flags, size_t dsize)
+ u32 flags)
{
return !!test_and_set_bit(e->id, map->members);
}
@@ -89,8 +90,7 @@ bitmap_ip_do_del(const struct bitmap_ip_adt_elem *e, struct bitmap_ip *map)
}
static inline int
-bitmap_ip_do_list(struct sk_buff *skb, const struct bitmap_ip *map, u32 id,
- size_t dsize)
+bitmap_ip_do_list(struct sk_buff *skb, const struct bitmap_ip *map, u32 id)
{
return nla_put_ipaddr4(skb, IPSET_ATTR_IP,
htonl(map->first_ip + id * map->hosts));
@@ -113,7 +113,7 @@ bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb,
struct bitmap_ip *map = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct bitmap_ip_adt_elem e = { };
- struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, map);
u32 ip;
ip = ntohl(ip4addr(skb, opt->flags & IPSET_DIM_ONE_SRC));
@@ -131,9 +131,9 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[],
{
struct bitmap_ip *map = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- u32 ip = 0, ip_to = 0;
+ u32 ip, ip_to;
struct bitmap_ip_adt_elem e = { };
- struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(map);
int ret = 0;
if (unlikely(!tb[IPSET_ATTR_IP] ||
@@ -200,7 +200,7 @@ bitmap_ip_same_set(const struct ip_set *a, const struct ip_set *b)
return x->first_ip == y->first_ip &&
x->last_ip == y->last_ip &&
x->netmask == y->netmask &&
- a->timeout == b->timeout &&
+ x->timeout == y->timeout &&
a->extensions == b->extensions;
}
@@ -209,6 +209,25 @@ bitmap_ip_same_set(const struct ip_set *a, const struct ip_set *b)
struct bitmap_ip_elem {
};
+/* Timeout variant */
+
+struct bitmap_ipt_elem {
+ unsigned long timeout;
+};
+
+/* Plain variant with counter */
+
+struct bitmap_ipc_elem {
+ struct ip_set_counter counter;
+};
+
+/* Timeout variant with counter */
+
+struct bitmap_ipct_elem {
+ unsigned long timeout;
+ struct ip_set_counter counter;
+};
+
#include "ip_set_bitmap_gen.h"
/* Create bitmap:ip type of sets */
@@ -221,8 +240,8 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,
map->members = ip_set_alloc(map->memsize);
if (!map->members)
return false;
- if (set->dsize) {
- map->extensions = ip_set_alloc(set->dsize * elements);
+ if (map->dsize) {
+ map->extensions = ip_set_alloc(map->dsize * elements);
if (!map->extensions) {
kfree(map->members);
return false;
@@ -233,7 +252,7 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,
map->elements = elements;
map->hosts = hosts;
map->netmask = netmask;
- set->timeout = IPSET_NO_TIMEOUT;
+ map->timeout = IPSET_NO_TIMEOUT;
set->data = map;
set->family = NFPROTO_IPV4;
@@ -242,11 +261,10 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,
}
static int
-bitmap_ip_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
- u32 flags)
+bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
{
struct bitmap_ip *map;
- u32 first_ip = 0, last_ip = 0, hosts;
+ u32 first_ip, last_ip, hosts, cadt_flags = 0;
u64 elements;
u8 netmask = 32;
int ret;
@@ -318,15 +336,61 @@ bitmap_ip_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
map->memsize = bitmap_bytes(0, elements - 1);
set->variant = &bitmap_ip;
- set->dsize = ip_set_elem_len(set, tb, 0);
- if (!init_map_ip(set, map, first_ip, last_ip,
- elements, hosts, netmask)) {
- kfree(map);
- return -ENOMEM;
- }
- if (tb[IPSET_ATTR_TIMEOUT]) {
- set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+ if (tb[IPSET_ATTR_CADT_FLAGS])
+ cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
+ if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) {
+ set->extensions |= IPSET_EXT_COUNTER;
+ if (tb[IPSET_ATTR_TIMEOUT]) {
+ map->dsize = sizeof(struct bitmap_ipct_elem);
+ map->offset[IPSET_OFFSET_TIMEOUT] =
+ offsetof(struct bitmap_ipct_elem, timeout);
+ map->offset[IPSET_OFFSET_COUNTER] =
+ offsetof(struct bitmap_ipct_elem, counter);
+
+ if (!init_map_ip(set, map, first_ip, last_ip,
+ elements, hosts, netmask)) {
+ kfree(map);
+ return -ENOMEM;
+ }
+
+ map->timeout = ip_set_timeout_uget(
+ tb[IPSET_ATTR_TIMEOUT]);
+ set->extensions |= IPSET_EXT_TIMEOUT;
+
+ bitmap_ip_gc_init(set, bitmap_ip_gc);
+ } else {
+ map->dsize = sizeof(struct bitmap_ipc_elem);
+ map->offset[IPSET_OFFSET_COUNTER] =
+ offsetof(struct bitmap_ipc_elem, counter);
+
+ if (!init_map_ip(set, map, first_ip, last_ip,
+ elements, hosts, netmask)) {
+ kfree(map);
+ return -ENOMEM;
+ }
+ }
+ } else if (tb[IPSET_ATTR_TIMEOUT]) {
+ map->dsize = sizeof(struct bitmap_ipt_elem);
+ map->offset[IPSET_OFFSET_TIMEOUT] =
+ offsetof(struct bitmap_ipt_elem, timeout);
+
+ if (!init_map_ip(set, map, first_ip, last_ip,
+ elements, hosts, netmask)) {
+ kfree(map);
+ return -ENOMEM;
+ }
+
+ map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+ set->extensions |= IPSET_EXT_TIMEOUT;
+
bitmap_ip_gc_init(set, bitmap_ip_gc);
+ } else {
+ map->dsize = 0;
+ if (!init_map_ip(set, map, first_ip, last_ip,
+ elements, hosts, netmask)) {
+ kfree(map);
+ return -ENOMEM;
+ }
}
return 0;
}
@@ -337,8 +401,8 @@ static struct ip_set_type bitmap_ip_type __read_mostly = {
.features = IPSET_TYPE_IP,
.dimension = IPSET_DIM_ONE,
.family = NFPROTO_IPV4,
- .revision_min = IPSET_TYPE_REV_MIN,
- .revision_max = IPSET_TYPE_REV_MAX,
+ .revision_min = REVISION_MIN,
+ .revision_max = REVISION_MAX,
.create = bitmap_ip_create,
.create_policy = {
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
@@ -356,7 +420,6 @@ static struct ip_set_type bitmap_ip_type __read_mostly = {
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
[IPSET_ATTR_BYTES] = { .type = NLA_U64 },
[IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
- [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
},
.me = THIS_MODULE,
};
diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c
index 740eabe..3b30e0b 100644
--- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c
+++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c
@@ -25,13 +25,12 @@
#include <linux/netfilter/ipset/ip_set.h>
#include <linux/netfilter/ipset/ip_set_bitmap.h>
-#define IPSET_TYPE_REV_MIN 0
-/* 1 Counter support added */
-#define IPSET_TYPE_REV_MAX 2 /* Comment support added */
+#define REVISION_MIN 0
+#define REVISION_MAX 1 /* Counter support added */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
-IP_SET_MODULE_DESC("bitmap:ip,mac", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
+IP_SET_MODULE_DESC("bitmap:ip,mac", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_bitmap:ip,mac");
#define MTYPE bitmap_ipmac
@@ -49,8 +48,11 @@ struct bitmap_ipmac {
u32 first_ip; /* host byte order, included in range */
u32 last_ip; /* host byte order, included in range */
u32 elements; /* number of max elements in the set */
- size_t memsize; /* members size */
+ u32 timeout; /* timeout value */
struct timer_list gc; /* garbage collector */
+ size_t memsize; /* members size */
+ size_t dsize; /* size of element */
+ size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */
};
/* ADT structure for generic function args */
@@ -80,13 +82,13 @@ get_elem(void *extensions, u16 id, size_t dsize)
static inline int
bitmap_ipmac_do_test(const struct bitmap_ipmac_adt_elem *e,
- const struct bitmap_ipmac *map, size_t dsize)
+ const struct bitmap_ipmac *map)
{
const struct bitmap_ipmac_elem *elem;
if (!test_bit(e->id, map->members))
return 0;
- elem = get_elem(map->extensions, e->id, dsize);
+ elem = get_elem(map->extensions, e->id, map->dsize);
if (elem->filled == MAC_FILLED)
return e->ether == NULL ||
ether_addr_equal(e->ether, elem->ether);
@@ -95,13 +97,13 @@ bitmap_ipmac_do_test(const struct bitmap_ipmac_adt_elem *e,
}
static inline int
-bitmap_ipmac_gc_test(u16 id, const struct bitmap_ipmac *map, size_t dsize)
+bitmap_ipmac_gc_test(u16 id, const struct bitmap_ipmac *map)
{
const struct bitmap_ipmac_elem *elem;
if (!test_bit(id, map->members))
return 0;
- elem = get_elem(map->extensions, id, dsize);
+ elem = get_elem(map->extensions, id, map->dsize);
/* Timer not started for the incomplete elements */
return elem->filled == MAC_FILLED;
}
@@ -115,13 +117,13 @@ bitmap_ipmac_is_filled(const struct bitmap_ipmac_elem *elem)
static inline int
bitmap_ipmac_add_timeout(unsigned long *timeout,
const struct bitmap_ipmac_adt_elem *e,
- const struct ip_set_ext *ext, struct ip_set *set,
+ const struct ip_set_ext *ext,
struct bitmap_ipmac *map, int mode)
{
u32 t = ext->timeout;
if (mode == IPSET_ADD_START_STORED_TIMEOUT) {
- if (t == set->timeout)
+ if (t == map->timeout)
/* Timeout was not specified, get stored one */
t = *timeout;
ip_set_timeout_set(timeout, t);
@@ -140,11 +142,11 @@ bitmap_ipmac_add_timeout(unsigned long *timeout,
static inline int
bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e,
- struct bitmap_ipmac *map, u32 flags, size_t dsize)
+ struct bitmap_ipmac *map, u32 flags)
{
struct bitmap_ipmac_elem *elem;
- elem = get_elem(map->extensions, e->id, dsize);
+ elem = get_elem(map->extensions, e->id, map->dsize);
if (test_and_set_bit(e->id, map->members)) {
if (elem->filled == MAC_FILLED) {
if (e->ether && (flags & IPSET_FLAG_EXIST))
@@ -176,12 +178,22 @@ bitmap_ipmac_do_del(const struct bitmap_ipmac_adt_elem *e,
return !test_and_clear_bit(e->id, map->members);
}
+static inline unsigned long
+ip_set_timeout_stored(struct bitmap_ipmac *map, u32 id, unsigned long *timeout)
+{
+ const struct bitmap_ipmac_elem *elem =
+ get_elem(map->extensions, id, map->dsize);
+
+ return elem->filled == MAC_FILLED ? ip_set_timeout_get(timeout) :
+ *timeout;
+}
+
static inline int
bitmap_ipmac_do_list(struct sk_buff *skb, const struct bitmap_ipmac *map,
- u32 id, size_t dsize)
+ u32 id)
{
const struct bitmap_ipmac_elem *elem =
- get_elem(map->extensions, id, dsize);
+ get_elem(map->extensions, id, map->dsize);
return nla_put_ipaddr4(skb, IPSET_ATTR_IP,
htonl(map->first_ip + id)) ||
@@ -204,7 +216,7 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
struct bitmap_ipmac *map = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct bitmap_ipmac_adt_elem e = {};
- struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, map);
u32 ip;
/* MAC can be src only */
@@ -233,8 +245,8 @@ bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[],
const struct bitmap_ipmac *map = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct bitmap_ipmac_adt_elem e = {};
- struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
- u32 ip = 0;
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(map);
+ u32 ip;
int ret = 0;
if (unlikely(!tb[IPSET_ATTR_IP] ||
@@ -273,12 +285,43 @@ bitmap_ipmac_same_set(const struct ip_set *a, const struct ip_set *b)
return x->first_ip == y->first_ip &&
x->last_ip == y->last_ip &&
- a->timeout == b->timeout &&
+ x->timeout == y->timeout &&
a->extensions == b->extensions;
}
/* Plain variant */
+/* Timeout variant */
+
+struct bitmap_ipmact_elem {
+ struct {
+ unsigned char ether[ETH_ALEN];
+ unsigned char filled;
+ } __attribute__ ((aligned));
+ unsigned long timeout;
+};
+
+/* Plain variant with counter */
+
+struct bitmap_ipmacc_elem {
+ struct {
+ unsigned char ether[ETH_ALEN];
+ unsigned char filled;
+ } __attribute__ ((aligned));
+ struct ip_set_counter counter;
+};
+
+/* Timeout variant with counter */
+
+struct bitmap_ipmacct_elem {
+ struct {
+ unsigned char ether[ETH_ALEN];
+ unsigned char filled;
+ } __attribute__ ((aligned));
+ unsigned long timeout;
+ struct ip_set_counter counter;
+};
+
#include "ip_set_bitmap_gen.h"
/* Create bitmap:ip,mac type of sets */
@@ -287,11 +330,11 @@ static bool
init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
u32 first_ip, u32 last_ip, u32 elements)
{
- map->members = ip_set_alloc(map->memsize);
+ map->members = ip_set_alloc((last_ip - first_ip + 1) * map->dsize);
if (!map->members)
return false;
- if (set->dsize) {
- map->extensions = ip_set_alloc(set->dsize * elements);
+ if (map->dsize) {
+ map->extensions = ip_set_alloc(map->dsize * elements);
if (!map->extensions) {
kfree(map->members);
return false;
@@ -300,7 +343,7 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
map->first_ip = first_ip;
map->last_ip = last_ip;
map->elements = elements;
- set->timeout = IPSET_NO_TIMEOUT;
+ map->timeout = IPSET_NO_TIMEOUT;
set->data = map;
set->family = NFPROTO_IPV4;
@@ -309,10 +352,10 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
}
static int
-bitmap_ipmac_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
+bitmap_ipmac_create(struct ip_set *set, struct nlattr *tb[],
u32 flags)
{
- u32 first_ip = 0, last_ip = 0;
+ u32 first_ip, last_ip, cadt_flags = 0;
u64 elements;
struct bitmap_ipmac *map;
int ret;
@@ -356,15 +399,57 @@ bitmap_ipmac_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
map->memsize = bitmap_bytes(0, elements - 1);
set->variant = &bitmap_ipmac;
- set->dsize = ip_set_elem_len(set, tb,
- sizeof(struct bitmap_ipmac_elem));
- if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) {
- kfree(map);
- return -ENOMEM;
- }
- if (tb[IPSET_ATTR_TIMEOUT]) {
- set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+ if (tb[IPSET_ATTR_CADT_FLAGS])
+ cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
+ if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) {
+ set->extensions |= IPSET_EXT_COUNTER;
+ if (tb[IPSET_ATTR_TIMEOUT]) {
+ map->dsize = sizeof(struct bitmap_ipmacct_elem);
+ map->offset[IPSET_OFFSET_TIMEOUT] =
+ offsetof(struct bitmap_ipmacct_elem, timeout);
+ map->offset[IPSET_OFFSET_COUNTER] =
+ offsetof(struct bitmap_ipmacct_elem, counter);
+
+ if (!init_map_ipmac(set, map, first_ip, last_ip,
+ elements)) {
+ kfree(map);
+ return -ENOMEM;
+ }
+ map->timeout = ip_set_timeout_uget(
+ tb[IPSET_ATTR_TIMEOUT]);
+ set->extensions |= IPSET_EXT_TIMEOUT;
+ bitmap_ipmac_gc_init(set, bitmap_ipmac_gc);
+ } else {
+ map->dsize = sizeof(struct bitmap_ipmacc_elem);
+ map->offset[IPSET_OFFSET_COUNTER] =
+ offsetof(struct bitmap_ipmacc_elem, counter);
+
+ if (!init_map_ipmac(set, map, first_ip, last_ip,
+ elements)) {
+ kfree(map);
+ return -ENOMEM;
+ }
+ }
+ } else if (tb[IPSET_ATTR_TIMEOUT]) {
+ map->dsize = sizeof(struct bitmap_ipmact_elem);
+ map->offset[IPSET_OFFSET_TIMEOUT] =
+ offsetof(struct bitmap_ipmact_elem, timeout);
+
+ if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) {
+ kfree(map);
+ return -ENOMEM;
+ }
+ map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+ set->extensions |= IPSET_EXT_TIMEOUT;
bitmap_ipmac_gc_init(set, bitmap_ipmac_gc);
+ } else {
+ map->dsize = sizeof(struct bitmap_ipmac_elem);
+
+ if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) {
+ kfree(map);
+ return -ENOMEM;
+ }
+ set->variant = &bitmap_ipmac;
}
return 0;
}
@@ -375,8 +460,8 @@ static struct ip_set_type bitmap_ipmac_type = {
.features = IPSET_TYPE_IP | IPSET_TYPE_MAC,
.dimension = IPSET_DIM_TWO,
.family = NFPROTO_IPV4,
- .revision_min = IPSET_TYPE_REV_MIN,
- .revision_max = IPSET_TYPE_REV_MAX,
+ .revision_min = REVISION_MIN,
+ .revision_max = REVISION_MAX,
.create = bitmap_ipmac_create,
.create_policy = {
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
@@ -393,7 +478,6 @@ static struct ip_set_type bitmap_ipmac_type = {
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
[IPSET_ATTR_BYTES] = { .type = NLA_U64 },
[IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
- [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
},
.me = THIS_MODULE,
};
diff --git a/net/netfilter/ipset/ip_set_bitmap_port.c b/net/netfilter/ipset/ip_set_bitmap_port.c
index cf99676..8207d1f 100644
--- a/net/netfilter/ipset/ip_set_bitmap_port.c
+++ b/net/netfilter/ipset/ip_set_bitmap_port.c
@@ -20,13 +20,12 @@
#include <linux/netfilter/ipset/ip_set_bitmap.h>
#include <linux/netfilter/ipset/ip_set_getport.h>
-#define IPSET_TYPE_REV_MIN 0
-/* 1 Counter support added */
-#define IPSET_TYPE_REV_MAX 2 /* Comment support added */
+#define REVISION_MIN 0
+#define REVISION_MAX 1 /* Counter support added */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
-IP_SET_MODULE_DESC("bitmap:port", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
+IP_SET_MODULE_DESC("bitmap:port", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_bitmap:port");
#define MTYPE bitmap_port
@@ -39,6 +38,9 @@ struct bitmap_port {
u16 last_port; /* host byte order, included in range */
u32 elements; /* number of max elements in the set */
size_t memsize; /* members size */
+ size_t dsize; /* extensions struct size */
+ size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */
+ u32 timeout; /* timeout parameter */
struct timer_list gc; /* garbage collection */
};
@@ -57,20 +59,20 @@ port_to_id(const struct bitmap_port *m, u16 port)
static inline int
bitmap_port_do_test(const struct bitmap_port_adt_elem *e,
- const struct bitmap_port *map, size_t dsize)
+ const struct bitmap_port *map)
{
return !!test_bit(e->id, map->members);
}
static inline int
-bitmap_port_gc_test(u16 id, const struct bitmap_port *map, size_t dsize)
+bitmap_port_gc_test(u16 id, const struct bitmap_port *map)
{
return !!test_bit(id, map->members);
}
static inline int
bitmap_port_do_add(const struct bitmap_port_adt_elem *e,
- struct bitmap_port *map, u32 flags, size_t dsize)
+ struct bitmap_port *map, u32 flags)
{
return !!test_and_set_bit(e->id, map->members);
}
@@ -83,8 +85,7 @@ bitmap_port_do_del(const struct bitmap_port_adt_elem *e,
}
static inline int
-bitmap_port_do_list(struct sk_buff *skb, const struct bitmap_port *map, u32 id,
- size_t dsize)
+bitmap_port_do_list(struct sk_buff *skb, const struct bitmap_port *map, u32 id)
{
return nla_put_net16(skb, IPSET_ATTR_PORT,
htons(map->first_port + id));
@@ -105,7 +106,7 @@ bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,
struct bitmap_port *map = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct bitmap_port_adt_elem e = {};
- struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, map);
__be16 __port;
u16 port = 0;
@@ -130,7 +131,7 @@ bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[],
struct bitmap_port *map = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct bitmap_port_adt_elem e = {};
- struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(map);
u32 port; /* wraparound */
u16 port_to;
int ret = 0;
@@ -190,7 +191,7 @@ bitmap_port_same_set(const struct ip_set *a, const struct ip_set *b)
return x->first_port == y->first_port &&
x->last_port == y->last_port &&
- a->timeout == b->timeout &&
+ x->timeout == y->timeout &&
a->extensions == b->extensions;
}
@@ -199,6 +200,25 @@ bitmap_port_same_set(const struct ip_set *a, const struct ip_set *b)
struct bitmap_port_elem {
};
+/* Timeout variant */
+
+struct bitmap_portt_elem {
+ unsigned long timeout;
+};
+
+/* Plain variant with counter */
+
+struct bitmap_portc_elem {
+ struct ip_set_counter counter;
+};
+
+/* Timeout variant with counter */
+
+struct bitmap_portct_elem {
+ unsigned long timeout;
+ struct ip_set_counter counter;
+};
+
#include "ip_set_bitmap_gen.h"
/* Create bitmap:ip type of sets */
@@ -210,8 +230,8 @@ init_map_port(struct ip_set *set, struct bitmap_port *map,
map->members = ip_set_alloc(map->memsize);
if (!map->members)
return false;
- if (set->dsize) {
- map->extensions = ip_set_alloc(set->dsize * map->elements);
+ if (map->dsize) {
+ map->extensions = ip_set_alloc(map->dsize * map->elements);
if (!map->extensions) {
kfree(map->members);
return false;
@@ -219,7 +239,7 @@ init_map_port(struct ip_set *set, struct bitmap_port *map,
}
map->first_port = first_port;
map->last_port = last_port;
- set->timeout = IPSET_NO_TIMEOUT;
+ map->timeout = IPSET_NO_TIMEOUT;
set->data = map;
set->family = NFPROTO_UNSPEC;
@@ -228,11 +248,11 @@ init_map_port(struct ip_set *set, struct bitmap_port *map,
}
static int
-bitmap_port_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
- u32 flags)
+bitmap_port_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
{
struct bitmap_port *map;
u16 first_port, last_port;
+ u32 cadt_flags = 0;
if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT_TO) ||
@@ -254,16 +274,55 @@ bitmap_port_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
return -ENOMEM;
map->elements = last_port - first_port + 1;
- map->memsize = bitmap_bytes(0, map->elements);
+ map->memsize = map->elements * sizeof(unsigned long);
set->variant = &bitmap_port;
- set->dsize = ip_set_elem_len(set, tb, 0);
- if (!init_map_port(set, map, first_port, last_port)) {
- kfree(map);
- return -ENOMEM;
- }
- if (tb[IPSET_ATTR_TIMEOUT]) {
- set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+ if (tb[IPSET_ATTR_CADT_FLAGS])
+ cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
+ if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) {
+ set->extensions |= IPSET_EXT_COUNTER;
+ if (tb[IPSET_ATTR_TIMEOUT]) {
+ map->dsize = sizeof(struct bitmap_portct_elem);
+ map->offset[IPSET_OFFSET_TIMEOUT] =
+ offsetof(struct bitmap_portct_elem, timeout);
+ map->offset[IPSET_OFFSET_COUNTER] =
+ offsetof(struct bitmap_portct_elem, counter);
+ if (!init_map_port(set, map, first_port, last_port)) {
+ kfree(map);
+ return -ENOMEM;
+ }
+
+ map->timeout =
+ ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+ set->extensions |= IPSET_EXT_TIMEOUT;
+ bitmap_port_gc_init(set, bitmap_port_gc);
+ } else {
+ map->dsize = sizeof(struct bitmap_portc_elem);
+ map->offset[IPSET_OFFSET_COUNTER] =
+ offsetof(struct bitmap_portc_elem, counter);
+ if (!init_map_port(set, map, first_port, last_port)) {
+ kfree(map);
+ return -ENOMEM;
+ }
+ }
+ } else if (tb[IPSET_ATTR_TIMEOUT]) {
+ map->dsize = sizeof(struct bitmap_portt_elem);
+ map->offset[IPSET_OFFSET_TIMEOUT] =
+ offsetof(struct bitmap_portt_elem, timeout);
+ if (!init_map_port(set, map, first_port, last_port)) {
+ kfree(map);
+ return -ENOMEM;
+ }
+
+ map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+ set->extensions |= IPSET_EXT_TIMEOUT;
bitmap_port_gc_init(set, bitmap_port_gc);
+ } else {
+ map->dsize = 0;
+ if (!init_map_port(set, map, first_port, last_port)) {
+ kfree(map);
+ return -ENOMEM;
+ }
+
}
return 0;
}
@@ -274,8 +333,8 @@ static struct ip_set_type bitmap_port_type = {
.features = IPSET_TYPE_PORT,
.dimension = IPSET_DIM_ONE,
.family = NFPROTO_UNSPEC,
- .revision_min = IPSET_TYPE_REV_MIN,
- .revision_max = IPSET_TYPE_REV_MAX,
+ .revision_min = REVISION_MIN,
+ .revision_max = REVISION_MAX,
.create = bitmap_port_create,
.create_policy = {
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
@@ -290,7 +349,6 @@ static struct ip_set_type bitmap_port_type = {
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
[IPSET_ATTR_BYTES] = { .type = NLA_U64 },
[IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
- [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
},
.me = THIS_MODULE,
};
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
index bac7e01..f2e30fb 100644
--- a/net/netfilter/ipset/ip_set_core.c
+++ b/net/netfilter/ipset/ip_set_core.c
@@ -17,8 +17,6 @@
#include <linux/spinlock.h>
#include <linux/rculist.h>
#include <net/netlink.h>
-#include <net/net_namespace.h>
-#include <net/netns/generic.h>
#include <linux/netfilter.h>
#include <linux/netfilter/x_tables.h>
@@ -29,17 +27,8 @@ static LIST_HEAD(ip_set_type_list); /* all registered set types */
static DEFINE_MUTEX(ip_set_type_mutex); /* protects ip_set_type_list */
static DEFINE_RWLOCK(ip_set_ref_lock); /* protects the set refs */
-struct ip_set_net {
- struct ip_set * __rcu *ip_set_list; /* all individual sets */
- ip_set_id_t ip_set_max; /* max number of sets */
- int is_deleted; /* deleted by ip_set_net_exit */
-};
-static int ip_set_net_id __read_mostly;
-
-static inline struct ip_set_net *ip_set_pernet(struct net *net)
-{
- return net_generic(net, ip_set_net_id);
-}
+static struct ip_set * __rcu *ip_set_list; /* all individual sets */
+static ip_set_id_t ip_set_max = CONFIG_IP_SET_MAX; /* max number of sets */
#define IP_SET_INC 64
#define STREQ(a, b) (strncmp(a, b, IPSET_MAXNAMELEN) == 0)
@@ -56,8 +45,8 @@ MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_IPSET);
/* When the nfnl mutex is held: */
#define nfnl_dereference(p) \
rcu_dereference_protected(p, 1)
-#define nfnl_set(inst, id) \
- nfnl_dereference((inst)->ip_set_list)[id]
+#define nfnl_set(id) \
+ nfnl_dereference(ip_set_list)[id]
/*
* The set types are implemented in modules and registered set types
@@ -326,60 +315,6 @@ ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr)
}
EXPORT_SYMBOL_GPL(ip_set_get_ipaddr6);
-typedef void (*destroyer)(void *);
-/* ipset data extension types, in size order */
-
-const struct ip_set_ext_type ip_set_extensions[] = {
- [IPSET_EXT_ID_COUNTER] = {
- .type = IPSET_EXT_COUNTER,
- .flag = IPSET_FLAG_WITH_COUNTERS,
- .len = sizeof(struct ip_set_counter),
- .align = __alignof__(struct ip_set_counter),
- },
- [IPSET_EXT_ID_TIMEOUT] = {
- .type = IPSET_EXT_TIMEOUT,
- .len = sizeof(unsigned long),
- .align = __alignof__(unsigned long),
- },
- [IPSET_EXT_ID_COMMENT] = {
- .type = IPSET_EXT_COMMENT | IPSET_EXT_DESTROY,
- .flag = IPSET_FLAG_WITH_COMMENT,
- .len = sizeof(struct ip_set_comment),
- .align = __alignof__(struct ip_set_comment),
- .destroy = (destroyer) ip_set_comment_free,
- },
-};
-EXPORT_SYMBOL_GPL(ip_set_extensions);
-
-static inline bool
-add_extension(enum ip_set_ext_id id, u32 flags, struct nlattr *tb[])
-{
- return ip_set_extensions[id].flag ?
- (flags & ip_set_extensions[id].flag) :
- !!tb[IPSET_ATTR_TIMEOUT];
-}
-
-size_t
-ip_set_elem_len(struct ip_set *set, struct nlattr *tb[], size_t len)
-{
- enum ip_set_ext_id id;
- size_t offset = 0;
- u32 cadt_flags = 0;
-
- if (tb[IPSET_ATTR_CADT_FLAGS])
- cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
- for (id = 0; id < IPSET_EXT_ID_MAX; id++) {
- if (!add_extension(id, cadt_flags, tb))
- continue;
- offset += ALIGN(len + offset, ip_set_extensions[id].align);
- set->offset[id] = offset;
- set->extensions |= ip_set_extensions[id].type;
- offset += ip_set_extensions[id].len;
- }
- return len + offset;
-}
-EXPORT_SYMBOL_GPL(ip_set_elem_len);
-
int
ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[],
struct ip_set_ext *ext)
@@ -399,12 +334,6 @@ ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[],
ext->packets = be64_to_cpu(nla_get_be64(
tb[IPSET_ATTR_PACKETS]));
}
- if (tb[IPSET_ATTR_COMMENT]) {
- if (!(set->extensions & IPSET_EXT_COMMENT))
- return -IPSET_ERR_COMMENT;
- ext->comment = ip_set_comment_uget(tb[IPSET_ATTR_COMMENT]);
- }
-
return 0;
}
EXPORT_SYMBOL_GPL(ip_set_get_extensions);
@@ -445,14 +374,13 @@ __ip_set_put(struct ip_set *set)
*/
static inline struct ip_set *
-ip_set_rcu_get(struct net *net, ip_set_id_t index)
+ip_set_rcu_get(ip_set_id_t index)
{
struct ip_set *set;
- struct ip_set_net *inst = ip_set_pernet(net);
rcu_read_lock();
/* ip_set_list itself needs to be protected */
- set = rcu_dereference(inst->ip_set_list)[index];
+ set = rcu_dereference(ip_set_list)[index];
rcu_read_unlock();
return set;
@@ -462,8 +390,7 @@ int
ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
const struct xt_action_param *par, struct ip_set_adt_opt *opt)
{
- struct ip_set *set = ip_set_rcu_get(
- dev_net(par->in ? par->in : par->out), index);
+ struct ip_set *set = ip_set_rcu_get(index);
int ret = 0;
BUG_ON(set == NULL);
@@ -501,8 +428,7 @@ int
ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
const struct xt_action_param *par, struct ip_set_adt_opt *opt)
{
- struct ip_set *set = ip_set_rcu_get(
- dev_net(par->in ? par->in : par->out), index);
+ struct ip_set *set = ip_set_rcu_get(index);
int ret;
BUG_ON(set == NULL);
@@ -524,8 +450,7 @@ int
ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
const struct xt_action_param *par, struct ip_set_adt_opt *opt)
{
- struct ip_set *set = ip_set_rcu_get(
- dev_net(par->in ? par->in : par->out), index);
+ struct ip_set *set = ip_set_rcu_get(index);
int ret = 0;
BUG_ON(set == NULL);
@@ -549,15 +474,14 @@ EXPORT_SYMBOL_GPL(ip_set_del);
*
*/
ip_set_id_t
-ip_set_get_byname(struct net *net, const char *name, struct ip_set **set)
+ip_set_get_byname(const char *name, struct ip_set **set)
{
ip_set_id_t i, index = IPSET_INVALID_ID;
struct ip_set *s;
- struct ip_set_net *inst = ip_set_pernet(net);
rcu_read_lock();
- for (i = 0; i < inst->ip_set_max; i++) {
- s = rcu_dereference(inst->ip_set_list)[i];
+ for (i = 0; i < ip_set_max; i++) {
+ s = rcu_dereference(ip_set_list)[i];
if (s != NULL && STREQ(s->name, name)) {
__ip_set_get(s);
index = i;
@@ -577,26 +501,17 @@ EXPORT_SYMBOL_GPL(ip_set_get_byname);
* to be valid, after calling this function.
*
*/
-
-static inline void
-__ip_set_put_byindex(struct ip_set_net *inst, ip_set_id_t index)
+void
+ip_set_put_byindex(ip_set_id_t index)
{
struct ip_set *set;
rcu_read_lock();
- set = rcu_dereference(inst->ip_set_list)[index];
+ set = rcu_dereference(ip_set_list)[index];
if (set != NULL)
__ip_set_put(set);
rcu_read_unlock();
}
-
-void
-ip_set_put_byindex(struct net *net, ip_set_id_t index)
-{
- struct ip_set_net *inst = ip_set_pernet(net);
-
- __ip_set_put_byindex(inst, index);
-}
EXPORT_SYMBOL_GPL(ip_set_put_byindex);
/*
@@ -607,9 +522,9 @@ EXPORT_SYMBOL_GPL(ip_set_put_byindex);
*
*/
const char *
-ip_set_name_byindex(struct net *net, ip_set_id_t index)
+ip_set_name_byindex(ip_set_id_t index)
{
- const struct ip_set *set = ip_set_rcu_get(net, index);
+ const struct ip_set *set = ip_set_rcu_get(index);
BUG_ON(set == NULL);
BUG_ON(set->ref == 0);
@@ -631,15 +546,14 @@ EXPORT_SYMBOL_GPL(ip_set_name_byindex);
* The nfnl mutex is used in the function.
*/
ip_set_id_t
-ip_set_nfnl_get(struct net *net, const char *name)
+ip_set_nfnl_get(const char *name)
{
ip_set_id_t i, index = IPSET_INVALID_ID;
struct ip_set *s;
- struct ip_set_net *inst = ip_set_pernet(net);
nfnl_lock(NFNL_SUBSYS_IPSET);
- for (i = 0; i < inst->ip_set_max; i++) {
- s = nfnl_set(inst, i);
+ for (i = 0; i < ip_set_max; i++) {
+ s = nfnl_set(i);
if (s != NULL && STREQ(s->name, name)) {
__ip_set_get(s);
index = i;
@@ -659,16 +573,15 @@ EXPORT_SYMBOL_GPL(ip_set_nfnl_get);
* The nfnl mutex is used in the function.
*/
ip_set_id_t
-ip_set_nfnl_get_byindex(struct net *net, ip_set_id_t index)
+ip_set_nfnl_get_byindex(ip_set_id_t index)
{
struct ip_set *set;
- struct ip_set_net *inst = ip_set_pernet(net);
- if (index > inst->ip_set_max)
+ if (index > ip_set_max)
return IPSET_INVALID_ID;
nfnl_lock(NFNL_SUBSYS_IPSET);
- set = nfnl_set(inst, index);
+ set = nfnl_set(index);
if (set)
__ip_set_get(set);
else
@@ -687,17 +600,13 @@ EXPORT_SYMBOL_GPL(ip_set_nfnl_get_byindex);
* The nfnl mutex is used in the function.
*/
void
-ip_set_nfnl_put(struct net *net, ip_set_id_t index)
+ip_set_nfnl_put(ip_set_id_t index)
{
struct ip_set *set;
- struct ip_set_net *inst = ip_set_pernet(net);
-
nfnl_lock(NFNL_SUBSYS_IPSET);
- if (!inst->is_deleted) { /* already deleted from ip_set_net_exit() */
- set = nfnl_set(inst, index);
- if (set != NULL)
- __ip_set_put(set);
- }
+ set = nfnl_set(index);
+ if (set != NULL)
+ __ip_set_put(set);
nfnl_unlock(NFNL_SUBSYS_IPSET);
}
EXPORT_SYMBOL_GPL(ip_set_nfnl_put);
@@ -755,14 +664,14 @@ static const struct nla_policy ip_set_create_policy[IPSET_ATTR_CMD_MAX + 1] = {
};
static struct ip_set *
-find_set_and_id(struct ip_set_net *inst, const char *name, ip_set_id_t *id)
+find_set_and_id(const char *name, ip_set_id_t *id)
{
struct ip_set *set = NULL;
ip_set_id_t i;
*id = IPSET_INVALID_ID;
- for (i = 0; i < inst->ip_set_max; i++) {
- set = nfnl_set(inst, i);
+ for (i = 0; i < ip_set_max; i++) {
+ set = nfnl_set(i);
if (set != NULL && STREQ(set->name, name)) {
*id = i;
break;
@@ -772,23 +681,22 @@ find_set_and_id(struct ip_set_net *inst, const char *name, ip_set_id_t *id)
}
static inline struct ip_set *
-find_set(struct ip_set_net *inst, const char *name)
+find_set(const char *name)
{
ip_set_id_t id;
- return find_set_and_id(inst, name, &id);
+ return find_set_and_id(name, &id);
}
static int
-find_free_id(struct ip_set_net *inst, const char *name, ip_set_id_t *index,
- struct ip_set **set)
+find_free_id(const char *name, ip_set_id_t *index, struct ip_set **set)
{
struct ip_set *s;
ip_set_id_t i;
*index = IPSET_INVALID_ID;
- for (i = 0; i < inst->ip_set_max; i++) {
- s = nfnl_set(inst, i);
+ for (i = 0; i < ip_set_max; i++) {
+ s = nfnl_set(i);
if (s == NULL) {
if (*index == IPSET_INVALID_ID)
*index = i;
@@ -817,8 +725,6 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const attr[])
{
- struct net *net = sock_net(ctnl);
- struct ip_set_net *inst = ip_set_pernet(net);
struct ip_set *set, *clash = NULL;
ip_set_id_t index = IPSET_INVALID_ID;
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1] = {};
@@ -877,7 +783,7 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
goto put_out;
}
- ret = set->type->create(net, set, tb, flags);
+ ret = set->type->create(set, tb, flags);
if (ret != 0)
goto put_out;
@@ -888,7 +794,7 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
* by the nfnl mutex. Find the first free index in ip_set_list
* and check clashing.
*/
- ret = find_free_id(inst, set->name, &index, &clash);
+ ret = find_free_id(set->name, &index, &clash);
if (ret == -EEXIST) {
/* If this is the same set and requested, ignore error */
if ((flags & IPSET_FLAG_EXIST) &&
@@ -901,9 +807,9 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
goto cleanup;
} else if (ret == -IPSET_ERR_MAX_SETS) {
struct ip_set **list, **tmp;
- ip_set_id_t i = inst->ip_set_max + IP_SET_INC;
+ ip_set_id_t i = ip_set_max + IP_SET_INC;
- if (i < inst->ip_set_max || i == IPSET_INVALID_ID)
+ if (i < ip_set_max || i == IPSET_INVALID_ID)
/* Wraparound */
goto cleanup;
@@ -911,14 +817,14 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
if (!list)
goto cleanup;
/* nfnl mutex is held, both lists are valid */
- tmp = nfnl_dereference(inst->ip_set_list);
- memcpy(list, tmp, sizeof(struct ip_set *) * inst->ip_set_max);
- rcu_assign_pointer(inst->ip_set_list, list);
+ tmp = nfnl_dereference(ip_set_list);
+ memcpy(list, tmp, sizeof(struct ip_set *) * ip_set_max);
+ rcu_assign_pointer(ip_set_list, list);
/* Make sure all current packets have passed through */
synchronize_net();
/* Use new list */
- index = inst->ip_set_max;
- inst->ip_set_max = i;
+ index = ip_set_max;
+ ip_set_max = i;
kfree(tmp);
ret = 0;
} else if (ret)
@@ -928,7 +834,7 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
* Finally! Add our shiny new set to the list, and be done.
*/
pr_debug("create: '%s' created with index %u!\n", set->name, index);
- nfnl_set(inst, index) = set;
+ nfnl_set(index) = set;
return ret;
@@ -951,12 +857,12 @@ ip_set_setname_policy[IPSET_ATTR_CMD_MAX + 1] = {
};
static void
-ip_set_destroy_set(struct ip_set_net *inst, ip_set_id_t index)
+ip_set_destroy_set(ip_set_id_t index)
{
- struct ip_set *set = nfnl_set(inst, index);
+ struct ip_set *set = nfnl_set(index);
pr_debug("set: %s\n", set->name);
- nfnl_set(inst, index) = NULL;
+ nfnl_set(index) = NULL;
/* Must call it without holding any lock */
set->variant->destroy(set);
@@ -969,7 +875,6 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const attr[])
{
- struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
struct ip_set *s;
ip_set_id_t i;
int ret = 0;
@@ -989,22 +894,21 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb,
*/
read_lock_bh(&ip_set_ref_lock);
if (!attr[IPSET_ATTR_SETNAME]) {
- for (i = 0; i < inst->ip_set_max; i++) {
- s = nfnl_set(inst, i);
+ for (i = 0; i < ip_set_max; i++) {
+ s = nfnl_set(i);
if (s != NULL && s->ref) {
ret = -IPSET_ERR_BUSY;
goto out;
}
}
read_unlock_bh(&ip_set_ref_lock);
- for (i = 0; i < inst->ip_set_max; i++) {
- s = nfnl_set(inst, i);
+ for (i = 0; i < ip_set_max; i++) {
+ s = nfnl_set(i);
if (s != NULL)
- ip_set_destroy_set(inst, i);
+ ip_set_destroy_set(i);
}
} else {
- s = find_set_and_id(inst, nla_data(attr[IPSET_ATTR_SETNAME]),
- &i);
+ s = find_set_and_id(nla_data(attr[IPSET_ATTR_SETNAME]), &i);
if (s == NULL) {
ret = -ENOENT;
goto out;
@@ -1014,7 +918,7 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb,
}
read_unlock_bh(&ip_set_ref_lock);
- ip_set_destroy_set(inst, i);
+ ip_set_destroy_set(i);
}
return 0;
out:
@@ -1039,7 +943,6 @@ ip_set_flush(struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const attr[])
{
- struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
struct ip_set *s;
ip_set_id_t i;
@@ -1047,13 +950,13 @@ ip_set_flush(struct sock *ctnl, struct sk_buff *skb,
return -IPSET_ERR_PROTOCOL;
if (!attr[IPSET_ATTR_SETNAME]) {
- for (i = 0; i < inst->ip_set_max; i++) {
- s = nfnl_set(inst, i);
+ for (i = 0; i < ip_set_max; i++) {
+ s = nfnl_set(i);
if (s != NULL)
ip_set_flush_set(s);
}
} else {
- s = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME]));
+ s = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
if (s == NULL)
return -ENOENT;
@@ -1079,7 +982,6 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const attr[])
{
- struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
struct ip_set *set, *s;
const char *name2;
ip_set_id_t i;
@@ -1090,7 +992,7 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb,
attr[IPSET_ATTR_SETNAME2] == NULL))
return -IPSET_ERR_PROTOCOL;
- set = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME]));
+ set = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
if (set == NULL)
return -ENOENT;
@@ -1101,8 +1003,8 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb,
}
name2 = nla_data(attr[IPSET_ATTR_SETNAME2]);
- for (i = 0; i < inst->ip_set_max; i++) {
- s = nfnl_set(inst, i);
+ for (i = 0; i < ip_set_max; i++) {
+ s = nfnl_set(i);
if (s != NULL && STREQ(s->name, name2)) {
ret = -IPSET_ERR_EXIST_SETNAME2;
goto out;
@@ -1129,7 +1031,6 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const attr[])
{
- struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
struct ip_set *from, *to;
ip_set_id_t from_id, to_id;
char from_name[IPSET_MAXNAMELEN];
@@ -1139,13 +1040,11 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,
attr[IPSET_ATTR_SETNAME2] == NULL))
return -IPSET_ERR_PROTOCOL;
- from = find_set_and_id(inst, nla_data(attr[IPSET_ATTR_SETNAME]),
- &from_id);
+ from = find_set_and_id(nla_data(attr[IPSET_ATTR_SETNAME]), &from_id);
if (from == NULL)
return -ENOENT;
- to = find_set_and_id(inst, nla_data(attr[IPSET_ATTR_SETNAME2]),
- &to_id);
+ to = find_set_and_id(nla_data(attr[IPSET_ATTR_SETNAME2]), &to_id);
if (to == NULL)
return -IPSET_ERR_EXIST_SETNAME2;
@@ -1162,8 +1061,8 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,
write_lock_bh(&ip_set_ref_lock);
swap(from->ref, to->ref);
- nfnl_set(inst, from_id) = to;
- nfnl_set(inst, to_id) = from;
+ nfnl_set(from_id) = to;
+ nfnl_set(to_id) = from;
write_unlock_bh(&ip_set_ref_lock);
return 0;
@@ -1182,12 +1081,9 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,
static int
ip_set_dump_done(struct netlink_callback *cb)
{
- struct ip_set_net *inst = (struct ip_set_net *)cb->args[IPSET_CB_NET];
- if (cb->args[IPSET_CB_ARG0]) {
- pr_debug("release set %s\n",
- nfnl_set(inst, cb->args[IPSET_CB_INDEX])->name);
- __ip_set_put_byindex(inst,
- (ip_set_id_t) cb->args[IPSET_CB_INDEX]);
+ if (cb->args[2]) {
+ pr_debug("release set %s\n", nfnl_set(cb->args[1])->name);
+ ip_set_put_byindex((ip_set_id_t) cb->args[1]);
}
return 0;
}
@@ -1205,7 +1101,7 @@ dump_attrs(struct nlmsghdr *nlh)
}
static int
-dump_init(struct netlink_callback *cb, struct ip_set_net *inst)
+dump_init(struct netlink_callback *cb)
{
struct nlmsghdr *nlh = nlmsg_hdr(cb->skb);
int min_len = nlmsg_total_size(sizeof(struct nfgenmsg));
@@ -1218,22 +1114,21 @@ dump_init(struct netlink_callback *cb, struct ip_set_net *inst)
nla_parse(cda, IPSET_ATTR_CMD_MAX,
attr, nlh->nlmsg_len - min_len, ip_set_setname_policy);
- /* cb->args[IPSET_CB_NET]: net namespace
- * [IPSET_CB_DUMP]: dump single set/all sets
- * [IPSET_CB_INDEX]: set index
- * [IPSET_CB_ARG0]: type specific
+ /* cb->args[0] : dump single set/all sets
+ * [1] : set index
+ * [..]: type specific
*/
if (cda[IPSET_ATTR_SETNAME]) {
struct ip_set *set;
- set = find_set_and_id(inst, nla_data(cda[IPSET_ATTR_SETNAME]),
+ set = find_set_and_id(nla_data(cda[IPSET_ATTR_SETNAME]),
&index);
if (set == NULL)
return -ENOENT;
dump_type = DUMP_ONE;
- cb->args[IPSET_CB_INDEX] = index;
+ cb->args[1] = index;
} else
dump_type = DUMP_ALL;
@@ -1241,8 +1136,7 @@ dump_init(struct netlink_callback *cb, struct ip_set_net *inst)
u32 f = ip_set_get_h32(cda[IPSET_ATTR_FLAGS]);
dump_type |= (f << 16);
}
- cb->args[IPSET_CB_NET] = (unsigned long)inst;
- cb->args[IPSET_CB_DUMP] = dump_type;
+ cb->args[0] = dump_type;
return 0;
}
@@ -1254,12 +1148,11 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
struct ip_set *set = NULL;
struct nlmsghdr *nlh = NULL;
unsigned int flags = NETLINK_CB(cb->skb).portid ? NLM_F_MULTI : 0;
- struct ip_set_net *inst = ip_set_pernet(sock_net(skb->sk));
u32 dump_type, dump_flags;
int ret = 0;
- if (!cb->args[IPSET_CB_DUMP]) {
- ret = dump_init(cb, inst);
+ if (!cb->args[0]) {
+ ret = dump_init(cb);
if (ret < 0) {
nlh = nlmsg_hdr(cb->skb);
/* We have to create and send the error message
@@ -1270,19 +1163,18 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
}
}
- if (cb->args[IPSET_CB_INDEX] >= inst->ip_set_max)
+ if (cb->args[1] >= ip_set_max)
goto out;
- dump_type = DUMP_TYPE(cb->args[IPSET_CB_DUMP]);
- dump_flags = DUMP_FLAGS(cb->args[IPSET_CB_DUMP]);
- max = dump_type == DUMP_ONE ? cb->args[IPSET_CB_INDEX] + 1
- : inst->ip_set_max;
+ dump_type = DUMP_TYPE(cb->args[0]);
+ dump_flags = DUMP_FLAGS(cb->args[0]);
+ max = dump_type == DUMP_ONE ? cb->args[1] + 1 : ip_set_max;
dump_last:
- pr_debug("dump type, flag: %u %u index: %ld\n",
- dump_type, dump_flags, cb->args[IPSET_CB_INDEX]);
- for (; cb->args[IPSET_CB_INDEX] < max; cb->args[IPSET_CB_INDEX]++) {
- index = (ip_set_id_t) cb->args[IPSET_CB_INDEX];
- set = nfnl_set(inst, index);
+ pr_debug("args[0]: %u %u args[1]: %ld\n",
+ dump_type, dump_flags, cb->args[1]);
+ for (; cb->args[1] < max; cb->args[1]++) {
+ index = (ip_set_id_t) cb->args[1];
+ set = nfnl_set(index);
if (set == NULL) {
if (dump_type == DUMP_ONE) {
ret = -ENOENT;
@@ -1298,7 +1190,7 @@ dump_last:
!!(set->type->features & IPSET_DUMP_LAST)))
continue;
pr_debug("List set: %s\n", set->name);
- if (!cb->args[IPSET_CB_ARG0]) {
+ if (!cb->args[2]) {
/* Start listing: make sure set won't be destroyed */
pr_debug("reference set\n");
__ip_set_get(set);
@@ -1315,7 +1207,7 @@ dump_last:
goto nla_put_failure;
if (dump_flags & IPSET_FLAG_LIST_SETNAME)
goto next_set;
- switch (cb->args[IPSET_CB_ARG0]) {
+ switch (cb->args[2]) {
case 0:
/* Core header data */
if (nla_put_string(skb, IPSET_ATTR_TYPENAME,
@@ -1335,7 +1227,7 @@ dump_last:
read_lock_bh(&set->lock);
ret = set->variant->list(set, skb, cb);
read_unlock_bh(&set->lock);
- if (!cb->args[IPSET_CB_ARG0])
+ if (!cb->args[2])
/* Set is done, proceed with next one */
goto next_set;
goto release_refcount;
@@ -1344,8 +1236,8 @@ dump_last:
/* If we dump all sets, continue with dumping last ones */
if (dump_type == DUMP_ALL) {
dump_type = DUMP_LAST;
- cb->args[IPSET_CB_DUMP] = dump_type | (dump_flags << 16);
- cb->args[IPSET_CB_INDEX] = 0;
+ cb->args[0] = dump_type | (dump_flags << 16);
+ cb->args[1] = 0;
goto dump_last;
}
goto out;
@@ -1354,15 +1246,15 @@ nla_put_failure:
ret = -EFAULT;
next_set:
if (dump_type == DUMP_ONE)
- cb->args[IPSET_CB_INDEX] = IPSET_INVALID_ID;
+ cb->args[1] = IPSET_INVALID_ID;
else
- cb->args[IPSET_CB_INDEX]++;
+ cb->args[1]++;
release_refcount:
/* If there was an error or set is done, release set */
- if (ret || !cb->args[IPSET_CB_ARG0]) {
- pr_debug("release set %s\n", nfnl_set(inst, index)->name);
- __ip_set_put_byindex(inst, index);
- cb->args[IPSET_CB_ARG0] = 0;
+ if (ret || !cb->args[2]) {
+ pr_debug("release set %s\n", nfnl_set(index)->name);
+ ip_set_put_byindex(index);
+ cb->args[2] = 0;
}
out:
if (nlh) {
@@ -1464,7 +1356,6 @@ ip_set_uadd(struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const attr[])
{
- struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
struct ip_set *set;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {};
const struct nlattr *nla;
@@ -1483,7 +1374,7 @@ ip_set_uadd(struct sock *ctnl, struct sk_buff *skb,
attr[IPSET_ATTR_LINENO] == NULL))))
return -IPSET_ERR_PROTOCOL;
- set = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME]));
+ set = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
if (set == NULL)
return -ENOENT;
@@ -1519,7 +1410,6 @@ ip_set_udel(struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const attr[])
{
- struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
struct ip_set *set;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {};
const struct nlattr *nla;
@@ -1538,7 +1428,7 @@ ip_set_udel(struct sock *ctnl, struct sk_buff *skb,
attr[IPSET_ATTR_LINENO] == NULL))))
return -IPSET_ERR_PROTOCOL;
- set = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME]));
+ set = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
if (set == NULL)
return -ENOENT;
@@ -1574,7 +1464,6 @@ ip_set_utest(struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const attr[])
{
- struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
struct ip_set *set;
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {};
int ret = 0;
@@ -1585,7 +1474,7 @@ ip_set_utest(struct sock *ctnl, struct sk_buff *skb,
!flag_nested(attr[IPSET_ATTR_DATA])))
return -IPSET_ERR_PROTOCOL;
- set = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME]));
+ set = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
if (set == NULL)
return -ENOENT;
@@ -1610,7 +1499,6 @@ ip_set_header(struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const attr[])
{
- struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
const struct ip_set *set;
struct sk_buff *skb2;
struct nlmsghdr *nlh2;
@@ -1620,7 +1508,7 @@ ip_set_header(struct sock *ctnl, struct sk_buff *skb,
attr[IPSET_ATTR_SETNAME] == NULL))
return -IPSET_ERR_PROTOCOL;
- set = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME]));
+ set = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
if (set == NULL)
return -ENOENT;
@@ -1845,10 +1733,8 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)
unsigned int *op;
void *data;
int copylen = *len, ret = 0;
- struct net *net = sock_net(sk);
- struct ip_set_net *inst = ip_set_pernet(net);
- if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
+ if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
return -EPERM;
if (optval != SO_IP_SET)
return -EBADF;
@@ -1897,39 +1783,22 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)
}
req_get->set.name[IPSET_MAXNAMELEN - 1] = '\0';
nfnl_lock(NFNL_SUBSYS_IPSET);
- find_set_and_id(inst, req_get->set.name, &id);
+ find_set_and_id(req_get->set.name, &id);
req_get->set.index = id;
nfnl_unlock(NFNL_SUBSYS_IPSET);
goto copy;
}
- case IP_SET_OP_GET_FNAME: {
- struct ip_set_req_get_set_family *req_get = data;
- ip_set_id_t id;
-
- if (*len != sizeof(struct ip_set_req_get_set_family)) {
- ret = -EINVAL;
- goto done;
- }
- req_get->set.name[IPSET_MAXNAMELEN - 1] = '\0';
- nfnl_lock(NFNL_SUBSYS_IPSET);
- find_set_and_id(inst, req_get->set.name, &id);
- req_get->set.index = id;
- if (id != IPSET_INVALID_ID)
- req_get->family = nfnl_set(inst, id)->family;
- nfnl_unlock(NFNL_SUBSYS_IPSET);
- goto copy;
- }
case IP_SET_OP_GET_BYINDEX: {
struct ip_set_req_get_set *req_get = data;
struct ip_set *set;
if (*len != sizeof(struct ip_set_req_get_set) ||
- req_get->set.index >= inst->ip_set_max) {
+ req_get->set.index >= ip_set_max) {
ret = -EINVAL;
goto done;
}
nfnl_lock(NFNL_SUBSYS_IPSET);
- set = nfnl_set(inst, req_get->set.index);
+ set = nfnl_set(req_get->set.index);
strncpy(req_get->set.name, set ? set->name : "",
IPSET_MAXNAMELEN);
nfnl_unlock(NFNL_SUBSYS_IPSET);
@@ -1958,81 +1827,49 @@ static struct nf_sockopt_ops so_set __read_mostly = {
.owner = THIS_MODULE,
};
-static int __net_init
-ip_set_net_init(struct net *net)
+static int __init
+ip_set_init(void)
{
- struct ip_set_net *inst = ip_set_pernet(net);
struct ip_set **list;
+ int ret;
- inst->ip_set_max = max_sets ? max_sets : CONFIG_IP_SET_MAX;
- if (inst->ip_set_max >= IPSET_INVALID_ID)
- inst->ip_set_max = IPSET_INVALID_ID - 1;
+ if (max_sets)
+ ip_set_max = max_sets;
+ if (ip_set_max >= IPSET_INVALID_ID)
+ ip_set_max = IPSET_INVALID_ID - 1;
- list = kzalloc(sizeof(struct ip_set *) * inst->ip_set_max, GFP_KERNEL);
+ list = kzalloc(sizeof(struct ip_set *) * ip_set_max, GFP_KERNEL);
if (!list)
return -ENOMEM;
- inst->is_deleted = 0;
- rcu_assign_pointer(inst->ip_set_list, list);
- pr_notice("ip_set: protocol %u\n", IPSET_PROTOCOL);
- return 0;
-}
-static void __net_exit
-ip_set_net_exit(struct net *net)
-{
- struct ip_set_net *inst = ip_set_pernet(net);
-
- struct ip_set *set = NULL;
- ip_set_id_t i;
-
- inst->is_deleted = 1; /* flag for ip_set_nfnl_put */
-
- for (i = 0; i < inst->ip_set_max; i++) {
- set = nfnl_set(inst, i);
- if (set != NULL)
- ip_set_destroy_set(inst, i);
- }
- kfree(rcu_dereference_protected(inst->ip_set_list, 1));
-}
-
-static struct pernet_operations ip_set_net_ops = {
- .init = ip_set_net_init,
- .exit = ip_set_net_exit,
- .id = &ip_set_net_id,
- .size = sizeof(struct ip_set_net)
-};
-
-
-static int __init
-ip_set_init(void)
-{
- int ret = nfnetlink_subsys_register(&ip_set_netlink_subsys);
+ rcu_assign_pointer(ip_set_list, list);
+ ret = nfnetlink_subsys_register(&ip_set_netlink_subsys);
if (ret != 0) {
pr_err("ip_set: cannot register with nfnetlink.\n");
+ kfree(list);
return ret;
}
ret = nf_register_sockopt(&so_set);
if (ret != 0) {
pr_err("SO_SET registry failed: %d\n", ret);
nfnetlink_subsys_unregister(&ip_set_netlink_subsys);
+ kfree(list);
return ret;
}
- ret = register_pernet_subsys(&ip_set_net_ops);
- if (ret) {
- pr_err("ip_set: cannot register pernet_subsys.\n");
- nf_unregister_sockopt(&so_set);
- nfnetlink_subsys_unregister(&ip_set_netlink_subsys);
- return ret;
- }
+
+ pr_notice("ip_set: protocol %u\n", IPSET_PROTOCOL);
return 0;
}
static void __exit
ip_set_fini(void)
{
- unregister_pernet_subsys(&ip_set_net_ops);
+ struct ip_set **list = rcu_dereference_protected(ip_set_list, 1);
+
+ /* There can't be any existing set */
nf_unregister_sockopt(&so_set);
nfnetlink_subsys_unregister(&ip_set_netlink_subsys);
+ kfree(list);
pr_debug("these are the famous last words\n");
}
diff --git a/net/netfilter/ipset/ip_set_getport.c b/net/netfilter/ipset/ip_set_getport.c
index 29fb01d..dac156f 100644
--- a/net/netfilter/ipset/ip_set_getport.c
+++ b/net/netfilter/ipset/ip_set_getport.c
@@ -102,25 +102,9 @@ ip_set_get_ip4_port(const struct sk_buff *skb, bool src,
int protocol = iph->protocol;
/* See comments at tcp_match in ip_tables.c */
- if (protocol <= 0)
+ if (protocol <= 0 || (ntohs(iph->frag_off) & IP_OFFSET))
return false;
- if (ntohs(iph->frag_off) & IP_OFFSET)
- switch (protocol) {
- case IPPROTO_TCP:
- case IPPROTO_SCTP:
- case IPPROTO_UDP:
- case IPPROTO_UDPLITE:
- case IPPROTO_ICMP:
- /* Port info not available for fragment offset > 0 */
- return false;
- default:
- /* Other protocols doesn't have ports,
- so we can match fragments */
- *proto = protocol;
- return true;
- }
-
return get_port(skb, protocol, protooff, src, port, proto);
}
EXPORT_SYMBOL_GPL(ip_set_get_ip4_port);
diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h
index be6932a..707bc52 100644
--- a/net/netfilter/ipset/ip_set_hash_gen.h
+++ b/net/netfilter/ipset/ip_set_hash_gen.h
@@ -15,7 +15,8 @@
#define rcu_dereference_bh(p) rcu_dereference(p)
#endif
-#define rcu_dereference_bh_nfnl(p) rcu_dereference_bh_check(p, 1)
+#define CONCAT(a, b) a##b
+#define TOKEN(a, b) CONCAT(a, b)
/* Hashing which uses arrays to resolve clashing. The hash table is resized
* (doubled) when searching becomes too long.
@@ -77,14 +78,10 @@ struct htable {
#define hbucket(h, i) (&((h)->bucket[i]))
-#ifndef IPSET_NET_COUNT
-#define IPSET_NET_COUNT 1
-#endif
-
/* Book-keeping of the prefixes added to the set */
struct net_prefixes {
- u32 nets[IPSET_NET_COUNT]; /* number of elements per cidr */
- u8 cidr[IPSET_NET_COUNT]; /* the different cidr values in the set */
+ u8 cidr; /* the different cidr values in the set */
+ u32 nets; /* number of elements per cidr */
};
/* Compute the hash table size */
@@ -117,6 +114,23 @@ htable_bits(u32 hashsize)
return bits;
}
+/* Destroy the hashtable part of the set */
+static void
+ahash_destroy(struct htable *t)
+{
+ struct hbucket *n;
+ u32 i;
+
+ for (i = 0; i < jhash_size(t->htable_bits); i++) {
+ n = hbucket(t, i);
+ if (n->size)
+ /* FIXME: use slab cache */
+ kfree(n->value);
+ }
+
+ ip_set_free(t);
+}
+
static int
hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize)
{
@@ -142,30 +156,30 @@ hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize)
}
#ifdef IP_SET_HASH_WITH_NETS
-#if IPSET_NET_COUNT > 1
-#define __CIDR(cidr, i) (cidr[i])
-#else
-#define __CIDR(cidr, i) (cidr)
-#endif
#ifdef IP_SET_HASH_WITH_NETS_PACKED
/* When cidr is packed with nomatch, cidr - 1 is stored in the entry */
-#define CIDR(cidr, i) (__CIDR(cidr, i) + 1)
+#define CIDR(cidr) (cidr + 1)
#else
-#define CIDR(cidr, i) (__CIDR(cidr, i))
+#define CIDR(cidr) (cidr)
#endif
#define SET_HOST_MASK(family) (family == AF_INET ? 32 : 128)
#ifdef IP_SET_HASH_WITH_MULTI
-#define NLEN(family) (SET_HOST_MASK(family) + 1)
+#define NETS_LENGTH(family) (SET_HOST_MASK(family) + 1)
#else
-#define NLEN(family) SET_HOST_MASK(family)
+#define NETS_LENGTH(family) SET_HOST_MASK(family)
#endif
#else
-#define NLEN(family) 0
+#define NETS_LENGTH(family) 0
#endif /* IP_SET_HASH_WITH_NETS */
+#define ext_timeout(e, h) \
+(unsigned long *)(((void *)(e)) + (h)->offset[IPSET_OFFSET_TIMEOUT])
+#define ext_counter(e, h) \
+(struct ip_set_counter *)(((void *)(e)) + (h)->offset[IPSET_OFFSET_COUNTER])
+
#endif /* _IP_SET_HASH_GEN_H */
/* Family dependent templates */
@@ -180,8 +194,6 @@ hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize)
#undef mtype_data_next
#undef mtype_elem
-#undef mtype_ahash_destroy
-#undef mtype_ext_cleanup
#undef mtype_add_cidr
#undef mtype_del_cidr
#undef mtype_ahash_memsize
@@ -208,43 +220,41 @@ hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize)
#undef HKEY
-#define mtype_data_equal IPSET_TOKEN(MTYPE, _data_equal)
+#define mtype_data_equal TOKEN(MTYPE, _data_equal)
#ifdef IP_SET_HASH_WITH_NETS
-#define mtype_do_data_match IPSET_TOKEN(MTYPE, _do_data_match)
+#define mtype_do_data_match TOKEN(MTYPE, _do_data_match)
#else
#define mtype_do_data_match(d) 1
#endif
-#define mtype_data_set_flags IPSET_TOKEN(MTYPE, _data_set_flags)
-#define mtype_data_reset_elem IPSET_TOKEN(MTYPE, _data_reset_elem)
-#define mtype_data_reset_flags IPSET_TOKEN(MTYPE, _data_reset_flags)
-#define mtype_data_netmask IPSET_TOKEN(MTYPE, _data_netmask)
-#define mtype_data_list IPSET_TOKEN(MTYPE, _data_list)
-#define mtype_data_next IPSET_TOKEN(MTYPE, _data_next)
-#define mtype_elem IPSET_TOKEN(MTYPE, _elem)
-#define mtype_ahash_destroy IPSET_TOKEN(MTYPE, _ahash_destroy)
-#define mtype_ext_cleanup IPSET_TOKEN(MTYPE, _ext_cleanup)
-#define mtype_add_cidr IPSET_TOKEN(MTYPE, _add_cidr)
-#define mtype_del_cidr IPSET_TOKEN(MTYPE, _del_cidr)
-#define mtype_ahash_memsize IPSET_TOKEN(MTYPE, _ahash_memsize)
-#define mtype_flush IPSET_TOKEN(MTYPE, _flush)
-#define mtype_destroy IPSET_TOKEN(MTYPE, _destroy)
-#define mtype_gc_init IPSET_TOKEN(MTYPE, _gc_init)
-#define mtype_same_set IPSET_TOKEN(MTYPE, _same_set)
-#define mtype_kadt IPSET_TOKEN(MTYPE, _kadt)
-#define mtype_uadt IPSET_TOKEN(MTYPE, _uadt)
+#define mtype_data_set_flags TOKEN(MTYPE, _data_set_flags)
+#define mtype_data_reset_flags TOKEN(MTYPE, _data_reset_flags)
+#define mtype_data_netmask TOKEN(MTYPE, _data_netmask)
+#define mtype_data_list TOKEN(MTYPE, _data_list)
+#define mtype_data_next TOKEN(MTYPE, _data_next)
+#define mtype_elem TOKEN(MTYPE, _elem)
+#define mtype_add_cidr TOKEN(MTYPE, _add_cidr)
+#define mtype_del_cidr TOKEN(MTYPE, _del_cidr)
+#define mtype_ahash_memsize TOKEN(MTYPE, _ahash_memsize)
+#define mtype_flush TOKEN(MTYPE, _flush)
+#define mtype_destroy TOKEN(MTYPE, _destroy)
+#define mtype_gc_init TOKEN(MTYPE, _gc_init)
+#define mtype_same_set TOKEN(MTYPE, _same_set)
+#define mtype_kadt TOKEN(MTYPE, _kadt)
+#define mtype_uadt TOKEN(MTYPE, _uadt)
#define mtype MTYPE
-#define mtype_add IPSET_TOKEN(MTYPE, _add)
-#define mtype_del IPSET_TOKEN(MTYPE, _del)
-#define mtype_test_cidrs IPSET_TOKEN(MTYPE, _test_cidrs)
-#define mtype_test IPSET_TOKEN(MTYPE, _test)
-#define mtype_expire IPSET_TOKEN(MTYPE, _expire)
-#define mtype_resize IPSET_TOKEN(MTYPE, _resize)
-#define mtype_head IPSET_TOKEN(MTYPE, _head)
-#define mtype_list IPSET_TOKEN(MTYPE, _list)
-#define mtype_gc IPSET_TOKEN(MTYPE, _gc)
-#define mtype_variant IPSET_TOKEN(MTYPE, _variant)
-#define mtype_data_match IPSET_TOKEN(MTYPE, _data_match)
+#define mtype_elem TOKEN(MTYPE, _elem)
+#define mtype_add TOKEN(MTYPE, _add)
+#define mtype_del TOKEN(MTYPE, _del)
+#define mtype_test_cidrs TOKEN(MTYPE, _test_cidrs)
+#define mtype_test TOKEN(MTYPE, _test)
+#define mtype_expire TOKEN(MTYPE, _expire)
+#define mtype_resize TOKEN(MTYPE, _resize)
+#define mtype_head TOKEN(MTYPE, _head)
+#define mtype_list TOKEN(MTYPE, _list)
+#define mtype_gc TOKEN(MTYPE, _gc)
+#define mtype_variant TOKEN(MTYPE, _variant)
+#define mtype_data_match TOKEN(MTYPE, _data_match)
#ifndef HKEY_DATALEN
#define HKEY_DATALEN sizeof(struct mtype_elem)
@@ -259,10 +269,13 @@ hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize)
/* The generic hash structure */
struct htype {
- struct htable __rcu *table; /* the hash table */
+ struct htable *table; /* the hash table */
u32 maxelem; /* max elements in the hash */
u32 elements; /* current element (vs timeout) */
u32 initval; /* random jhash init value */
+ u32 timeout; /* timeout value, if enabled */
+ size_t dsize; /* data struct size */
+ size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */
struct timer_list gc; /* garbage collection when timeout enabled */
struct mtype_elem next; /* temporary storage for uadd */
#ifdef IP_SET_HASH_WITH_MULTI
@@ -284,49 +297,49 @@ struct htype {
/* Network cidr size book keeping when the hash stores different
* sized networks */
static void
-mtype_add_cidr(struct htype *h, u8 cidr, u8 nets_length, u8 n)
+mtype_add_cidr(struct htype *h, u8 cidr, u8 nets_length)
{
int i, j;
/* Add in increasing prefix order, so larger cidr first */
- for (i = 0, j = -1; i < nets_length && h->nets[i].nets[n]; i++) {
+ for (i = 0, j = -1; i < nets_length && h->nets[i].nets; i++) {
if (j != -1)
continue;
- else if (h->nets[i].cidr[n] < cidr)
+ else if (h->nets[i].cidr < cidr)
j = i;
- else if (h->nets[i].cidr[n] == cidr) {
- h->nets[i].nets[n]++;
+ else if (h->nets[i].cidr == cidr) {
+ h->nets[i].nets++;
return;
}
}
if (j != -1) {
for (; i > j; i--) {
- h->nets[i].cidr[n] = h->nets[i - 1].cidr[n];
- h->nets[i].nets[n] = h->nets[i - 1].nets[n];
+ h->nets[i].cidr = h->nets[i - 1].cidr;
+ h->nets[i].nets = h->nets[i - 1].nets;
}
}
- h->nets[i].cidr[n] = cidr;
- h->nets[i].nets[n] = 1;
+ h->nets[i].cidr = cidr;
+ h->nets[i].nets = 1;
}
static void
-mtype_del_cidr(struct htype *h, u8 cidr, u8 nets_length, u8 n)
+mtype_del_cidr(struct htype *h, u8 cidr, u8 nets_length)
{
u8 i, j, net_end = nets_length - 1;
for (i = 0; i < nets_length; i++) {
- if (h->nets[i].cidr[n] != cidr)
+ if (h->nets[i].cidr != cidr)
continue;
- if (h->nets[i].nets[n] > 1 || i == net_end ||
- h->nets[i + 1].nets[n] == 0) {
- h->nets[i].nets[n]--;
+ if (h->nets[i].nets > 1 || i == net_end ||
+ h->nets[i + 1].nets == 0) {
+ h->nets[i].nets--;
return;
}
- for (j = i; j < net_end && h->nets[j].nets[n]; j++) {
- h->nets[j].cidr[n] = h->nets[j + 1].cidr[n];
- h->nets[j].nets[n] = h->nets[j + 1].nets[n];
+ for (j = i; j < net_end && h->nets[j].nets; j++) {
+ h->nets[j].cidr = h->nets[j + 1].cidr;
+ h->nets[j].nets = h->nets[j + 1].nets;
}
- h->nets[j].nets[n] = 0;
+ h->nets[j].nets = 0;
return;
}
}
@@ -334,10 +347,10 @@ mtype_del_cidr(struct htype *h, u8 cidr, u8 nets_length, u8 n)
/* Calculate the actual memory size of the set data */
static size_t
-mtype_ahash_memsize(const struct htype *h, const struct htable *t,
- u8 nets_length, size_t dsize)
+mtype_ahash_memsize(const struct htype *h, u8 nets_length)
{
u32 i;
+ struct htable *t = h->table;
size_t memsize = sizeof(*h)
+ sizeof(*t)
#ifdef IP_SET_HASH_WITH_NETS
@@ -346,70 +359,35 @@ mtype_ahash_memsize(const struct htype *h, const struct htable *t,
+ jhash_size(t->htable_bits) * sizeof(struct hbucket);
for (i = 0; i < jhash_size(t->htable_bits); i++)
- memsize += t->bucket[i].size * dsize;
+ memsize += t->bucket[i].size * h->dsize;
return memsize;
}
-/* Get the ith element from the array block n */
-#define ahash_data(n, i, dsize) \
- ((struct mtype_elem *)((n)->value + ((i) * (dsize))))
-
-static void
-mtype_ext_cleanup(struct ip_set *set, struct hbucket *n)
-{
- int i;
-
- for (i = 0; i < n->pos; i++)
- ip_set_ext_destroy(set, ahash_data(n, i, set->dsize));
-}
-
/* Flush a hash type of set: destroy all elements */
static void
mtype_flush(struct ip_set *set)
{
struct htype *h = set->data;
- struct htable *t;
+ struct htable *t = h->table;
struct hbucket *n;
u32 i;
- t = rcu_dereference_bh_nfnl(h->table);
for (i = 0; i < jhash_size(t->htable_bits); i++) {
n = hbucket(t, i);
if (n->size) {
- if (set->extensions & IPSET_EXT_DESTROY)
- mtype_ext_cleanup(set, n);
n->size = n->pos = 0;
/* FIXME: use slab cache */
kfree(n->value);
}
}
#ifdef IP_SET_HASH_WITH_NETS
- memset(h->nets, 0, sizeof(struct net_prefixes) * NLEN(set->family));
+ memset(h->nets, 0, sizeof(struct net_prefixes)
+ * NETS_LENGTH(set->family));
#endif
h->elements = 0;
}
-/* Destroy the hashtable part of the set */
-static void
-mtype_ahash_destroy(struct ip_set *set, struct htable *t, bool ext_destroy)
-{
- struct hbucket *n;
- u32 i;
-
- for (i = 0; i < jhash_size(t->htable_bits); i++) {
- n = hbucket(t, i);
- if (n->size) {
- if (set->extensions & IPSET_EXT_DESTROY && ext_destroy)
- mtype_ext_cleanup(set, n);
- /* FIXME: use slab cache */
- kfree(n->value);
- }
- }
-
- ip_set_free(t);
-}
-
/* Destroy a hash type of set */
static void
mtype_destroy(struct ip_set *set)
@@ -419,7 +397,7 @@ mtype_destroy(struct ip_set *set)
if (set->extensions & IPSET_EXT_TIMEOUT)
del_timer_sync(&h->gc);
- mtype_ahash_destroy(set, rcu_dereference_bh_nfnl(h->table), true);
+ ahash_destroy(h->table);
#ifdef IP_SET_HASH_WITH_RBTREE
rbtree_destroy(&h->rbtree);
#endif
@@ -436,10 +414,10 @@ mtype_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))
init_timer(&h->gc);
h->gc.data = (unsigned long) set;
h->gc.function = gc;
- h->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;
+ h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ;
add_timer(&h->gc);
pr_debug("gc initialized, run in every %u\n",
- IPSET_GC_PERIOD(set->timeout));
+ IPSET_GC_PERIOD(h->timeout));
}
static bool
@@ -450,40 +428,37 @@ mtype_same_set(const struct ip_set *a, const struct ip_set *b)
/* Resizing changes htable_bits, so we ignore it */
return x->maxelem == y->maxelem &&
- a->timeout == b->timeout &&
+ x->timeout == y->timeout &&
#ifdef IP_SET_HASH_WITH_NETMASK
x->netmask == y->netmask &&
#endif
a->extensions == b->extensions;
}
+/* Get the ith element from the array block n */
+#define ahash_data(n, i, dsize) \
+ ((struct mtype_elem *)((n)->value + ((i) * (dsize))))
+
/* Delete expired elements from the hashtable */
static void
-mtype_expire(struct ip_set *set, struct htype *h, u8 nets_length, size_t dsize)
+mtype_expire(struct htype *h, u8 nets_length, size_t dsize)
{
- struct htable *t;
+ struct htable *t = h->table;
struct hbucket *n;
struct mtype_elem *data;
u32 i;
int j;
-#ifdef IP_SET_HASH_WITH_NETS
- u8 k;
-#endif
- rcu_read_lock_bh();
- t = rcu_dereference_bh(h->table);
for (i = 0; i < jhash_size(t->htable_bits); i++) {
n = hbucket(t, i);
for (j = 0; j < n->pos; j++) {
data = ahash_data(n, j, dsize);
- if (ip_set_timeout_expired(ext_timeout(data, set))) {
+ if (ip_set_timeout_expired(ext_timeout(data, h))) {
pr_debug("expired %u/%u\n", i, j);
#ifdef IP_SET_HASH_WITH_NETS
- for (k = 0; k < IPSET_NET_COUNT; k++)
- mtype_del_cidr(h, CIDR(data->cidr, k),
- nets_length, k);
+ mtype_del_cidr(h, CIDR(data->cidr),
+ nets_length);
#endif
- ip_set_ext_destroy(set, data);
if (j != n->pos - 1)
/* Not last one */
memcpy(data,
@@ -506,7 +481,6 @@ mtype_expire(struct ip_set *set, struct htype *h, u8 nets_length, size_t dsize)
n->value = tmp;
}
}
- rcu_read_unlock_bh();
}
static void
@@ -517,10 +491,10 @@ mtype_gc(unsigned long ul_set)
pr_debug("called\n");
write_lock_bh(&set->lock);
- mtype_expire(set, h, NLEN(set->family), set->dsize);
+ mtype_expire(h, NETS_LENGTH(set->family), h->dsize);
write_unlock_bh(&set->lock);
- h->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;
+ h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ;
add_timer(&h->gc);
}
@@ -531,7 +505,7 @@ static int
mtype_resize(struct ip_set *set, bool retried)
{
struct htype *h = set->data;
- struct htable *t, *orig = rcu_dereference_bh_nfnl(h->table);
+ struct htable *t, *orig = h->table;
u8 htable_bits = orig->htable_bits;
#ifdef IP_SET_HASH_WITH_NETS
u8 flags;
@@ -546,7 +520,8 @@ mtype_resize(struct ip_set *set, bool retried)
if (SET_WITH_TIMEOUT(set) && !retried) {
i = h->elements;
write_lock_bh(&set->lock);
- mtype_expire(set, set->data, NLEN(set->family), set->dsize);
+ mtype_expire(set->data, NETS_LENGTH(set->family),
+ h->dsize);
write_unlock_bh(&set->lock);
if (h->elements < i)
return 0;
@@ -573,25 +548,25 @@ retry:
for (i = 0; i < jhash_size(orig->htable_bits); i++) {
n = hbucket(orig, i);
for (j = 0; j < n->pos; j++) {
- data = ahash_data(n, j, set->dsize);
+ data = ahash_data(n, j, h->dsize);
#ifdef IP_SET_HASH_WITH_NETS
flags = 0;
mtype_data_reset_flags(data, &flags);
#endif
m = hbucket(t, HKEY(data, h->initval, htable_bits));
- ret = hbucket_elem_add(m, AHASH_MAX(h), set->dsize);
+ ret = hbucket_elem_add(m, AHASH_MAX(h), h->dsize);
if (ret < 0) {
#ifdef IP_SET_HASH_WITH_NETS
mtype_data_reset_flags(data, &flags);
#endif
read_unlock_bh(&set->lock);
- mtype_ahash_destroy(set, t, false);
+ ahash_destroy(t);
if (ret == -EAGAIN)
goto retry;
return ret;
}
- d = ahash_data(m, m->pos++, set->dsize);
- memcpy(d, data, set->dsize);
+ d = ahash_data(m, m->pos++, h->dsize);
+ memcpy(d, data, h->dsize);
#ifdef IP_SET_HASH_WITH_NETS
mtype_data_reset_flags(d, &flags);
#endif
@@ -606,7 +581,7 @@ retry:
pr_debug("set %s resized from %u (%p) to %u (%p)\n", set->name,
orig->htable_bits, orig, t->htable_bits, t);
- mtype_ahash_destroy(set, orig, false);
+ ahash_destroy(orig);
return 0;
}
@@ -629,7 +604,7 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
if (SET_WITH_TIMEOUT(set) && h->elements >= h->maxelem)
/* FIXME: when set is full, we slow down here */
- mtype_expire(set, h, NLEN(set->family), set->dsize);
+ mtype_expire(h, NETS_LENGTH(set->family), h->dsize);
if (h->elements >= h->maxelem) {
if (net_ratelimit())
@@ -643,11 +618,11 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
key = HKEY(value, h->initval, t->htable_bits);
n = hbucket(t, key);
for (i = 0; i < n->pos; i++) {
- data = ahash_data(n, i, set->dsize);
+ data = ahash_data(n, i, h->dsize);
if (mtype_data_equal(data, d, &multi)) {
if (flag_exist ||
(SET_WITH_TIMEOUT(set) &&
- ip_set_timeout_expired(ext_timeout(data, set)))) {
+ ip_set_timeout_expired(ext_timeout(data, h)))) {
/* Just the extensions could be overwritten */
j = i;
goto reuse_slot;
@@ -658,37 +633,30 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
}
/* Reuse first timed out entry */
if (SET_WITH_TIMEOUT(set) &&
- ip_set_timeout_expired(ext_timeout(data, set)) &&
+ ip_set_timeout_expired(ext_timeout(data, h)) &&
j != AHASH_MAX(h) + 1)
j = i;
}
reuse_slot:
if (j != AHASH_MAX(h) + 1) {
/* Fill out reused slot */
- data = ahash_data(n, j, set->dsize);
+ data = ahash_data(n, j, h->dsize);
#ifdef IP_SET_HASH_WITH_NETS
- for (i = 0; i < IPSET_NET_COUNT; i++) {
- mtype_del_cidr(h, CIDR(data->cidr, i),
- NLEN(set->family), i);
- mtype_add_cidr(h, CIDR(d->cidr, i),
- NLEN(set->family), i);
- }
+ mtype_del_cidr(h, CIDR(data->cidr), NETS_LENGTH(set->family));
+ mtype_add_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
#endif
- ip_set_ext_destroy(set, data);
} else {
/* Use/create a new slot */
TUNE_AHASH_MAX(h, multi);
- ret = hbucket_elem_add(n, AHASH_MAX(h), set->dsize);
+ ret = hbucket_elem_add(n, AHASH_MAX(h), h->dsize);
if (ret != 0) {
if (ret == -EAGAIN)
mtype_data_next(&h->next, d);
goto out;
}
- data = ahash_data(n, n->pos++, set->dsize);
+ data = ahash_data(n, n->pos++, h->dsize);
#ifdef IP_SET_HASH_WITH_NETS
- for (i = 0; i < IPSET_NET_COUNT; i++)
- mtype_add_cidr(h, CIDR(d->cidr, i), NLEN(set->family),
- i);
+ mtype_add_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
#endif
h->elements++;
}
@@ -697,11 +665,9 @@ reuse_slot:
mtype_data_set_flags(data, flags);
#endif
if (SET_WITH_TIMEOUT(set))
- ip_set_timeout_set(ext_timeout(data, set), ext->timeout);
+ ip_set_timeout_set(ext_timeout(data, h), ext->timeout);
if (SET_WITH_COUNTER(set))
- ip_set_init_counter(ext_counter(data, set), ext);
- if (SET_WITH_COMMENT(set))
- ip_set_init_comment(ext_comment(data, set), ext);
+ ip_set_init_counter(ext_counter(data, h), ext);
out:
rcu_read_unlock_bh();
@@ -716,60 +682,47 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
struct ip_set_ext *mext, u32 flags)
{
struct htype *h = set->data;
- struct htable *t;
+ struct htable *t = h->table;
const struct mtype_elem *d = value;
struct mtype_elem *data;
struct hbucket *n;
- int i, ret = -IPSET_ERR_EXIST;
-#ifdef IP_SET_HASH_WITH_NETS
- u8 j;
-#endif
+ int i;
u32 key, multi = 0;
- rcu_read_lock_bh();
- t = rcu_dereference_bh(h->table);
key = HKEY(value, h->initval, t->htable_bits);
n = hbucket(t, key);
for (i = 0; i < n->pos; i++) {
- data = ahash_data(n, i, set->dsize);
+ data = ahash_data(n, i, h->dsize);
if (!mtype_data_equal(data, d, &multi))
continue;
if (SET_WITH_TIMEOUT(set) &&
- ip_set_timeout_expired(ext_timeout(data, set)))
- goto out;
+ ip_set_timeout_expired(ext_timeout(data, h)))
+ return -IPSET_ERR_EXIST;
if (i != n->pos - 1)
/* Not last one */
- memcpy(data, ahash_data(n, n->pos - 1, set->dsize),
- set->dsize);
+ memcpy(data, ahash_data(n, n->pos - 1, h->dsize),
+ h->dsize);
n->pos--;
h->elements--;
#ifdef IP_SET_HASH_WITH_NETS
- for (j = 0; j < IPSET_NET_COUNT; j++)
- mtype_del_cidr(h, CIDR(d->cidr, j), NLEN(set->family),
- j);
+ mtype_del_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
#endif
- ip_set_ext_destroy(set, data);
if (n->pos + AHASH_INIT_SIZE < n->size) {
void *tmp = kzalloc((n->size - AHASH_INIT_SIZE)
- * set->dsize,
+ * h->dsize,
GFP_ATOMIC);
- if (!tmp) {
- ret = 0;
- goto out;
- }
+ if (!tmp)
+ return 0;
n->size -= AHASH_INIT_SIZE;
- memcpy(tmp, n->value, n->size * set->dsize);
+ memcpy(tmp, n->value, n->size * h->dsize);
kfree(n->value);
n->value = tmp;
}
- ret = 0;
- goto out;
+ return 0;
}
-out:
- rcu_read_unlock_bh();
- return ret;
+ return -IPSET_ERR_EXIST;
}
static inline int
@@ -777,7 +730,8 @@ mtype_data_match(struct mtype_elem *data, const struct ip_set_ext *ext,
struct ip_set_ext *mext, struct ip_set *set, u32 flags)
{
if (SET_WITH_COUNTER(set))
- ip_set_update_counter(ext_counter(data, set),
+ ip_set_update_counter(ext_counter(data,
+ (struct htype *)(set->data)),
ext, mext, flags);
return mtype_do_data_match(data);
}
@@ -791,38 +745,25 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d,
struct ip_set_ext *mext, u32 flags)
{
struct htype *h = set->data;
- struct htable *t = rcu_dereference_bh(h->table);
+ struct htable *t = h->table;
struct hbucket *n;
struct mtype_elem *data;
-#if IPSET_NET_COUNT == 2
- struct mtype_elem orig = *d;
- int i, j = 0, k;
-#else
int i, j = 0;
-#endif
u32 key, multi = 0;
- u8 nets_length = NLEN(set->family);
+ u8 nets_length = NETS_LENGTH(set->family);
pr_debug("test by nets\n");
- for (; j < nets_length && h->nets[j].nets[0] && !multi; j++) {
-#if IPSET_NET_COUNT == 2
- mtype_data_reset_elem(d, &orig);
- mtype_data_netmask(d, h->nets[j].cidr[0], false);
- for (k = 0; k < nets_length && h->nets[k].nets[1] && !multi;
- k++) {
- mtype_data_netmask(d, h->nets[k].cidr[1], true);
-#else
- mtype_data_netmask(d, h->nets[j].cidr[0]);
-#endif
+ for (; j < nets_length && h->nets[j].nets && !multi; j++) {
+ mtype_data_netmask(d, h->nets[j].cidr);
key = HKEY(d, h->initval, t->htable_bits);
n = hbucket(t, key);
for (i = 0; i < n->pos; i++) {
- data = ahash_data(n, i, set->dsize);
+ data = ahash_data(n, i, h->dsize);
if (!mtype_data_equal(data, d, &multi))
continue;
if (SET_WITH_TIMEOUT(set)) {
if (!ip_set_timeout_expired(
- ext_timeout(data, set)))
+ ext_timeout(data, h)))
return mtype_data_match(data, ext,
mext, set,
flags);
@@ -833,9 +774,6 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d,
return mtype_data_match(data, ext,
mext, set, flags);
}
-#if IPSET_NET_COUNT == 2
- }
-#endif
}
return 0;
}
@@ -847,41 +785,30 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext,
struct ip_set_ext *mext, u32 flags)
{
struct htype *h = set->data;
- struct htable *t;
+ struct htable *t = h->table;
struct mtype_elem *d = value;
struct hbucket *n;
struct mtype_elem *data;
- int i, ret = 0;
+ int i;
u32 key, multi = 0;
- rcu_read_lock_bh();
- t = rcu_dereference_bh(h->table);
#ifdef IP_SET_HASH_WITH_NETS
/* If we test an IP address and not a network address,
* try all possible network sizes */
- for (i = 0; i < IPSET_NET_COUNT; i++)
- if (CIDR(d->cidr, i) != SET_HOST_MASK(set->family))
- break;
- if (i == IPSET_NET_COUNT) {
- ret = mtype_test_cidrs(set, d, ext, mext, flags);
- goto out;
- }
+ if (CIDR(d->cidr) == SET_HOST_MASK(set->family))
+ return mtype_test_cidrs(set, d, ext, mext, flags);
#endif
key = HKEY(d, h->initval, t->htable_bits);
n = hbucket(t, key);
for (i = 0; i < n->pos; i++) {
- data = ahash_data(n, i, set->dsize);
+ data = ahash_data(n, i, h->dsize);
if (mtype_data_equal(data, d, &multi) &&
!(SET_WITH_TIMEOUT(set) &&
- ip_set_timeout_expired(ext_timeout(data, set)))) {
- ret = mtype_data_match(data, ext, mext, set, flags);
- goto out;
- }
+ ip_set_timeout_expired(ext_timeout(data, h))))
+ return mtype_data_match(data, ext, mext, set, flags);
}
-out:
- rcu_read_unlock_bh();
- return ret;
+ return 0;
}
/* Reply a HEADER request: fill out the header part of the set */
@@ -889,18 +816,18 @@ static int
mtype_head(struct ip_set *set, struct sk_buff *skb)
{
const struct htype *h = set->data;
- const struct htable *t;
struct nlattr *nested;
size_t memsize;
- t = rcu_dereference_bh_nfnl(h->table);
- memsize = mtype_ahash_memsize(h, t, NLEN(set->family), set->dsize);
+ read_lock_bh(&set->lock);
+ memsize = mtype_ahash_memsize(h, NETS_LENGTH(set->family));
+ read_unlock_bh(&set->lock);
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested)
goto nla_put_failure;
if (nla_put_net32(skb, IPSET_ATTR_HASHSIZE,
- htonl(jhash_size(t->htable_bits))) ||
+ htonl(jhash_size(h->table->htable_bits))) ||
nla_put_net32(skb, IPSET_ATTR_MAXELEM, htonl(h->maxelem)))
goto nla_put_failure;
#ifdef IP_SET_HASH_WITH_NETMASK
@@ -909,9 +836,12 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
goto nla_put_failure;
#endif
if (nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
- nla_put_net32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)))
- goto nla_put_failure;
- if (unlikely(ip_set_put_flags(skb, set)))
+ nla_put_net32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)) ||
+ ((set->extensions & IPSET_EXT_TIMEOUT) &&
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(h->timeout))) ||
+ ((set->extensions & IPSET_EXT_COUNTER) &&
+ nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS,
+ htonl(IPSET_FLAG_WITH_COUNTERS))))
goto nla_put_failure;
ipset_nest_end(skb, nested);
@@ -926,11 +856,11 @@ mtype_list(const struct ip_set *set,
struct sk_buff *skb, struct netlink_callback *cb)
{
const struct htype *h = set->data;
- const struct htable *t = rcu_dereference_bh_nfnl(h->table);
+ const struct htable *t = h->table;
struct nlattr *atd, *nested;
const struct hbucket *n;
const struct mtype_elem *e;
- u32 first = cb->args[IPSET_CB_ARG0];
+ u32 first = cb->args[2];
/* We assume that one hash bucket fills into one page */
void *incomplete;
int i;
@@ -939,22 +869,20 @@ mtype_list(const struct ip_set *set,
if (!atd)
return -EMSGSIZE;
pr_debug("list hash set %s\n", set->name);
- for (; cb->args[IPSET_CB_ARG0] < jhash_size(t->htable_bits);
- cb->args[IPSET_CB_ARG0]++) {
+ for (; cb->args[2] < jhash_size(t->htable_bits); cb->args[2]++) {
incomplete = skb_tail_pointer(skb);
- n = hbucket(t, cb->args[IPSET_CB_ARG0]);
- pr_debug("cb->arg bucket: %lu, t %p n %p\n",
- cb->args[IPSET_CB_ARG0], t, n);
+ n = hbucket(t, cb->args[2]);
+ pr_debug("cb->args[2]: %lu, t %p n %p\n", cb->args[2], t, n);
for (i = 0; i < n->pos; i++) {
- e = ahash_data(n, i, set->dsize);
+ e = ahash_data(n, i, h->dsize);
if (SET_WITH_TIMEOUT(set) &&
- ip_set_timeout_expired(ext_timeout(e, set)))
+ ip_set_timeout_expired(ext_timeout(e, h)))
continue;
pr_debug("list hash %lu hbucket %p i %u, data %p\n",
- cb->args[IPSET_CB_ARG0], n, i, e);
+ cb->args[2], n, i, e);
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested) {
- if (cb->args[IPSET_CB_ARG0] == first) {
+ if (cb->args[2] == first) {
nla_nest_cancel(skb, atd);
return -EMSGSIZE;
} else
@@ -962,37 +890,43 @@ mtype_list(const struct ip_set *set,
}
if (mtype_data_list(skb, e))
goto nla_put_failure;
- if (ip_set_put_extensions(skb, set, e, true))
+ if (SET_WITH_TIMEOUT(set) &&
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
+ htonl(ip_set_timeout_get(
+ ext_timeout(e, h)))))
+ goto nla_put_failure;
+ if (SET_WITH_COUNTER(set) &&
+ ip_set_put_counter(skb, ext_counter(e, h)))
goto nla_put_failure;
ipset_nest_end(skb, nested);
}
}
ipset_nest_end(skb, atd);
/* Set listing finished */
- cb->args[IPSET_CB_ARG0] = 0;
+ cb->args[2] = 0;
return 0;
nla_put_failure:
nlmsg_trim(skb, incomplete);
- if (unlikely(first == cb->args[IPSET_CB_ARG0])) {
+ ipset_nest_end(skb, atd);
+ if (unlikely(first == cb->args[2])) {
pr_warning("Can't list set %s: one bucket does not fit into "
"a message. Please report it!\n", set->name);
- cb->args[IPSET_CB_ARG0] = 0;
+ cb->args[2] = 0;
return -EMSGSIZE;
}
- ipset_nest_end(skb, atd);
return 0;
}
static int
-IPSET_TOKEN(MTYPE, _kadt)(struct ip_set *set, const struct sk_buff *skb,
- const struct xt_action_param *par,
- enum ipset_adt adt, struct ip_set_adt_opt *opt);
+TOKEN(MTYPE, _kadt)(struct ip_set *set, const struct sk_buff *skb,
+ const struct xt_action_param *par,
+ enum ipset_adt adt, struct ip_set_adt_opt *opt);
static int
-IPSET_TOKEN(MTYPE, _uadt)(struct ip_set *set, struct nlattr *tb[],
- enum ipset_adt adt, u32 *lineno, u32 flags, bool retried);
+TOKEN(MTYPE, _uadt)(struct ip_set *set, struct nlattr *tb[],
+ enum ipset_adt adt, u32 *lineno, u32 flags, bool retried);
static const struct ip_set_type_variant mtype_variant = {
.kadt = mtype_kadt,
@@ -1012,17 +946,16 @@ static const struct ip_set_type_variant mtype_variant = {
#ifdef IP_SET_EMIT_CREATE
static int
-IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
- struct nlattr *tb[], u32 flags)
+TOKEN(HTYPE, _create)(struct ip_set *set, struct nlattr *tb[], u32 flags)
{
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
+ u32 cadt_flags = 0;
u8 hbits;
#ifdef IP_SET_HASH_WITH_NETMASK
u8 netmask;
#endif
size_t hsize;
struct HTYPE *h;
- struct htable *t;
if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
return -IPSET_ERR_INVALID_FAMILY;
@@ -1072,7 +1005,7 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
h->netmask = netmask;
#endif
get_random_bytes(&h->initval, sizeof(h->initval));
- set->timeout = IPSET_NO_TIMEOUT;
+ h->timeout = IPSET_NO_TIMEOUT;
hbits = htable_bits(hashsize);
hsize = htable_size(hbits);
@@ -1080,37 +1013,91 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
kfree(h);
return -ENOMEM;
}
- t = ip_set_alloc(hsize);
- if (!t) {
+ h->table = ip_set_alloc(hsize);
+ if (!h->table) {
kfree(h);
return -ENOMEM;
}
- t->htable_bits = hbits;
- rcu_assign_pointer(h->table, t);
+ h->table->htable_bits = hbits;
set->data = h;
- if (set->family == NFPROTO_IPV4) {
- set->variant = &IPSET_TOKEN(HTYPE, 4_variant);
- set->dsize = ip_set_elem_len(set, tb,
- sizeof(struct IPSET_TOKEN(HTYPE, 4_elem)));
+ if (set->family == NFPROTO_IPV4)
+ set->variant = &TOKEN(HTYPE, 4_variant);
+ else
+ set->variant = &TOKEN(HTYPE, 6_variant);
+
+ if (tb[IPSET_ATTR_CADT_FLAGS])
+ cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
+ if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) {
+ set->extensions |= IPSET_EXT_COUNTER;
+ if (tb[IPSET_ATTR_TIMEOUT]) {
+ h->timeout =
+ ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+ set->extensions |= IPSET_EXT_TIMEOUT;
+ if (set->family == NFPROTO_IPV4) {
+ h->dsize =
+ sizeof(struct TOKEN(HTYPE, 4ct_elem));
+ h->offset[IPSET_OFFSET_TIMEOUT] =
+ offsetof(struct TOKEN(HTYPE, 4ct_elem),
+ timeout);
+ h->offset[IPSET_OFFSET_COUNTER] =
+ offsetof(struct TOKEN(HTYPE, 4ct_elem),
+ counter);
+ TOKEN(HTYPE, 4_gc_init)(set,
+ TOKEN(HTYPE, 4_gc));
+ } else {
+ h->dsize =
+ sizeof(struct TOKEN(HTYPE, 6ct_elem));
+ h->offset[IPSET_OFFSET_TIMEOUT] =
+ offsetof(struct TOKEN(HTYPE, 6ct_elem),
+ timeout);
+ h->offset[IPSET_OFFSET_COUNTER] =
+ offsetof(struct TOKEN(HTYPE, 6ct_elem),
+ counter);
+ TOKEN(HTYPE, 6_gc_init)(set,
+ TOKEN(HTYPE, 6_gc));
+ }
+ } else {
+ if (set->family == NFPROTO_IPV4) {
+ h->dsize =
+ sizeof(struct TOKEN(HTYPE, 4c_elem));
+ h->offset[IPSET_OFFSET_COUNTER] =
+ offsetof(struct TOKEN(HTYPE, 4c_elem),
+ counter);
+ } else {
+ h->dsize =
+ sizeof(struct TOKEN(HTYPE, 6c_elem));
+ h->offset[IPSET_OFFSET_COUNTER] =
+ offsetof(struct TOKEN(HTYPE, 6c_elem),
+ counter);
+ }
+ }
+ } else if (tb[IPSET_ATTR_TIMEOUT]) {
+ h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+ set->extensions |= IPSET_EXT_TIMEOUT;
+ if (set->family == NFPROTO_IPV4) {
+ h->dsize = sizeof(struct TOKEN(HTYPE, 4t_elem));
+ h->offset[IPSET_OFFSET_TIMEOUT] =
+ offsetof(struct TOKEN(HTYPE, 4t_elem),
+ timeout);
+ TOKEN(HTYPE, 4_gc_init)(set, TOKEN(HTYPE, 4_gc));
+ } else {
+ h->dsize = sizeof(struct TOKEN(HTYPE, 6t_elem));
+ h->offset[IPSET_OFFSET_TIMEOUT] =
+ offsetof(struct TOKEN(HTYPE, 6t_elem),
+ timeout);
+ TOKEN(HTYPE, 6_gc_init)(set, TOKEN(HTYPE, 6_gc));
+ }
} else {
- set->variant = &IPSET_TOKEN(HTYPE, 6_variant);
- set->dsize = ip_set_elem_len(set, tb,
- sizeof(struct IPSET_TOKEN(HTYPE, 6_elem)));
- }
- if (tb[IPSET_ATTR_TIMEOUT]) {
- set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
if (set->family == NFPROTO_IPV4)
- IPSET_TOKEN(HTYPE, 4_gc_init)(set,
- IPSET_TOKEN(HTYPE, 4_gc));
+ h->dsize = sizeof(struct TOKEN(HTYPE, 4_elem));
else
- IPSET_TOKEN(HTYPE, 6_gc_init)(set,
- IPSET_TOKEN(HTYPE, 6_gc));
+ h->dsize = sizeof(struct TOKEN(HTYPE, 6_elem));
}
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
- set->name, jhash_size(t->htable_bits),
- t->htable_bits, h->maxelem, set->data, t);
+ set->name, jhash_size(h->table->htable_bits),
+ h->table->htable_bits, h->maxelem, set->data, h->table);
return 0;
}
diff --git a/net/netfilter/ipset/ip_set_hash_ip.c b/net/netfilter/ipset/ip_set_hash_ip.c
index e65fc24..c74e6e1 100644
--- a/net/netfilter/ipset/ip_set_hash_ip.c
+++ b/net/netfilter/ipset/ip_set_hash_ip.c
@@ -23,20 +23,19 @@
#include <linux/netfilter/ipset/ip_set.h>
#include <linux/netfilter/ipset/ip_set_hash.h>
-#define IPSET_TYPE_REV_MIN 0
-/* 1 Counters support */
-#define IPSET_TYPE_REV_MAX 2 /* Comments support */
+#define REVISION_MIN 0
+#define REVISION_MAX 1 /* Counters support */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
-IP_SET_MODULE_DESC("hash:ip", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
+IP_SET_MODULE_DESC("hash:ip", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_hash:ip");
/* Type specific function prefix */
#define HTYPE hash_ip
#define IP_SET_HASH_WITH_NETMASK
-/* IPv4 variant */
+/* IPv4 variants */
/* Member elements */
struct hash_ip4_elem {
@@ -44,6 +43,22 @@ struct hash_ip4_elem {
__be32 ip;
};
+struct hash_ip4t_elem {
+ __be32 ip;
+ unsigned long timeout;
+};
+
+struct hash_ip4c_elem {
+ __be32 ip;
+ struct ip_set_counter counter;
+};
+
+struct hash_ip4ct_elem {
+ __be32 ip;
+ struct ip_set_counter counter;
+ unsigned long timeout;
+};
+
/* Common functions */
static inline bool
@@ -84,7 +99,7 @@ hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct hash_ip *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ip4_elem e = {};
- struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
__be32 ip;
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip);
@@ -103,8 +118,8 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
const struct hash_ip *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ip4_elem e = {};
- struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
- u32 ip = 0, ip_to = 0, hosts;
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
+ u32 ip, ip_to, hosts;
int ret = 0;
if (unlikely(!tb[IPSET_ATTR_IP] ||
@@ -163,13 +178,29 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
return ret;
}
-/* IPv6 variant */
+/* IPv6 variants */
/* Member elements */
struct hash_ip6_elem {
union nf_inet_addr ip;
};
+struct hash_ip6t_elem {
+ union nf_inet_addr ip;
+ unsigned long timeout;
+};
+
+struct hash_ip6c_elem {
+ union nf_inet_addr ip;
+ struct ip_set_counter counter;
+};
+
+struct hash_ip6ct_elem {
+ union nf_inet_addr ip;
+ struct ip_set_counter counter;
+ unsigned long timeout;
+};
+
/* Common functions */
static inline bool
@@ -222,7 +253,7 @@ hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct hash_ip *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ip6_elem e = {};
- struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
hash_ip6_netmask(&e.ip, h->netmask);
@@ -239,7 +270,7 @@ hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[],
const struct hash_ip *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ip6_elem e = {};
- struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
int ret;
if (unlikely(!tb[IPSET_ATTR_IP] ||
@@ -273,8 +304,8 @@ static struct ip_set_type hash_ip_type __read_mostly = {
.features = IPSET_TYPE_IP,
.dimension = IPSET_DIM_ONE,
.family = NFPROTO_UNSPEC,
- .revision_min = IPSET_TYPE_REV_MIN,
- .revision_max = IPSET_TYPE_REV_MAX,
+ .revision_min = REVISION_MIN,
+ .revision_max = REVISION_MAX,
.create = hash_ip_create,
.create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
@@ -293,7 +324,6 @@ static struct ip_set_type hash_ip_type __read_mostly = {
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
[IPSET_ATTR_BYTES] = { .type = NLA_U64 },
[IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
- [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
},
.me = THIS_MODULE,
};
diff --git a/net/netfilter/ipset/ip_set_hash_ipport.c b/net/netfilter/ipset/ip_set_hash_ipport.c
index 525a595..7a2d2bd 100644
--- a/net/netfilter/ipset/ip_set_hash_ipport.c
+++ b/net/netfilter/ipset/ip_set_hash_ipport.c
@@ -24,20 +24,19 @@
#include <linux/netfilter/ipset/ip_set_getport.h>
#include <linux/netfilter/ipset/ip_set_hash.h>
-#define IPSET_TYPE_REV_MIN 0
-/* 1 SCTP and UDPLITE support added */
-/* 2 Counters support added */
-#define IPSET_TYPE_REV_MAX 3 /* Comments support added */
+#define REVISION_MIN 0
+/* 1 SCTP and UDPLITE support added */
+#define REVISION_MAX 2 /* Counters support added */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
-IP_SET_MODULE_DESC("hash:ip,port", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
+IP_SET_MODULE_DESC("hash:ip,port", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_hash:ip,port");
/* Type specific function prefix */
#define HTYPE hash_ipport
-/* IPv4 variant */
+/* IPv4 variants */
/* Member elements */
struct hash_ipport4_elem {
@@ -47,6 +46,31 @@ struct hash_ipport4_elem {
u8 padding;
};
+struct hash_ipport4t_elem {
+ __be32 ip;
+ __be16 port;
+ u8 proto;
+ u8 padding;
+ unsigned long timeout;
+};
+
+struct hash_ipport4c_elem {
+ __be32 ip;
+ __be16 port;
+ u8 proto;
+ u8 padding;
+ struct ip_set_counter counter;
+};
+
+struct hash_ipport4ct_elem {
+ __be32 ip;
+ __be16 port;
+ u8 proto;
+ u8 padding;
+ struct ip_set_counter counter;
+ unsigned long timeout;
+};
+
/* Common functions */
static inline bool
@@ -92,9 +116,10 @@ hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par,
enum ipset_adt adt, struct ip_set_adt_opt *opt)
{
+ const struct hash_ipport *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipport4_elem e = { };
- struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
&e.port, &e.proto))
@@ -111,8 +136,8 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
const struct hash_ipport *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipport4_elem e = { };
- struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
- u32 ip, ip_to = 0, p = 0, port, port_to;
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
+ u32 ip, ip_to, p = 0, port, port_to;
bool with_ports = false;
int ret;
@@ -197,7 +222,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
return ret;
}
-/* IPv6 variant */
+/* IPv6 variants */
struct hash_ipport6_elem {
union nf_inet_addr ip;
@@ -206,6 +231,31 @@ struct hash_ipport6_elem {
u8 padding;
};
+struct hash_ipport6t_elem {
+ union nf_inet_addr ip;
+ __be16 port;
+ u8 proto;
+ u8 padding;
+ unsigned long timeout;
+};
+
+struct hash_ipport6c_elem {
+ union nf_inet_addr ip;
+ __be16 port;
+ u8 proto;
+ u8 padding;
+ struct ip_set_counter counter;
+};
+
+struct hash_ipport6ct_elem {
+ union nf_inet_addr ip;
+ __be16 port;
+ u8 proto;
+ u8 padding;
+ struct ip_set_counter counter;
+ unsigned long timeout;
+};
+
/* Common functions */
static inline bool
@@ -256,9 +306,10 @@ hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par,
enum ipset_adt adt, struct ip_set_adt_opt *opt)
{
+ const struct hash_ipport *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipport6_elem e = { };
- struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
&e.port, &e.proto))
@@ -275,7 +326,7 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
const struct hash_ipport *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipport6_elem e = { };
- struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
u32 port, port_to;
bool with_ports = false;
int ret;
@@ -345,8 +396,8 @@ static struct ip_set_type hash_ipport_type __read_mostly = {
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT,
.dimension = IPSET_DIM_TWO,
.family = NFPROTO_UNSPEC,
- .revision_min = IPSET_TYPE_REV_MIN,
- .revision_max = IPSET_TYPE_REV_MAX,
+ .revision_min = REVISION_MIN,
+ .revision_max = REVISION_MAX,
.create = hash_ipport_create,
.create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
@@ -368,7 +419,6 @@ static struct ip_set_type hash_ipport_type __read_mostly = {
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
[IPSET_ATTR_BYTES] = { .type = NLA_U64 },
[IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
- [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
},
.me = THIS_MODULE,
};
diff --git a/net/netfilter/ipset/ip_set_hash_ipportip.c b/net/netfilter/ipset/ip_set_hash_ipportip.c
index f563663..34e8a1a 100644
--- a/net/netfilter/ipset/ip_set_hash_ipportip.c
+++ b/net/netfilter/ipset/ip_set_hash_ipportip.c
@@ -24,20 +24,19 @@
#include <linux/netfilter/ipset/ip_set_getport.h>
#include <linux/netfilter/ipset/ip_set_hash.h>
-#define IPSET_TYPE_REV_MIN 0
-/* 1 SCTP and UDPLITE support added */
-/* 2 Counters support added */
-#define IPSET_TYPE_REV_MAX 3 /* Comments support added */
+#define REVISION_MIN 0
+/* 1 SCTP and UDPLITE support added */
+#define REVISION_MAX 2 /* Counters support added */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
-IP_SET_MODULE_DESC("hash:ip,port,ip", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
+IP_SET_MODULE_DESC("hash:ip,port,ip", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_hash:ip,port,ip");
/* Type specific function prefix */
#define HTYPE hash_ipportip
-/* IPv4 variant */
+/* IPv4 variants */
/* Member elements */
struct hash_ipportip4_elem {
@@ -48,6 +47,34 @@ struct hash_ipportip4_elem {
u8 padding;
};
+struct hash_ipportip4t_elem {
+ __be32 ip;
+ __be32 ip2;
+ __be16 port;
+ u8 proto;
+ u8 padding;
+ unsigned long timeout;
+};
+
+struct hash_ipportip4c_elem {
+ __be32 ip;
+ __be32 ip2;
+ __be16 port;
+ u8 proto;
+ u8 padding;
+ struct ip_set_counter counter;
+};
+
+struct hash_ipportip4ct_elem {
+ __be32 ip;
+ __be32 ip2;
+ __be16 port;
+ u8 proto;
+ u8 padding;
+ struct ip_set_counter counter;
+ unsigned long timeout;
+};
+
static inline bool
hash_ipportip4_data_equal(const struct hash_ipportip4_elem *ip1,
const struct hash_ipportip4_elem *ip2,
@@ -93,9 +120,10 @@ hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par,
enum ipset_adt adt, struct ip_set_adt_opt *opt)
{
+ const struct hash_ipportip *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipportip4_elem e = { };
- struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
&e.port, &e.proto))
@@ -113,8 +141,8 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
const struct hash_ipportip *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipportip4_elem e = { };
- struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
- u32 ip, ip_to = 0, p = 0, port, port_to;
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
+ u32 ip, ip_to, p = 0, port, port_to;
bool with_ports = false;
int ret;
@@ -203,7 +231,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
return ret;
}
-/* IPv6 variant */
+/* IPv6 variants */
struct hash_ipportip6_elem {
union nf_inet_addr ip;
@@ -213,6 +241,34 @@ struct hash_ipportip6_elem {
u8 padding;
};
+struct hash_ipportip6t_elem {
+ union nf_inet_addr ip;
+ union nf_inet_addr ip2;
+ __be16 port;
+ u8 proto;
+ u8 padding;
+ unsigned long timeout;
+};
+
+struct hash_ipportip6c_elem {
+ union nf_inet_addr ip;
+ union nf_inet_addr ip2;
+ __be16 port;
+ u8 proto;
+ u8 padding;
+ struct ip_set_counter counter;
+};
+
+struct hash_ipportip6ct_elem {
+ union nf_inet_addr ip;
+ union nf_inet_addr ip2;
+ __be16 port;
+ u8 proto;
+ u8 padding;
+ struct ip_set_counter counter;
+ unsigned long timeout;
+};
+
/* Common functions */
static inline bool
@@ -263,9 +319,10 @@ hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par,
enum ipset_adt adt, struct ip_set_adt_opt *opt)
{
+ const struct hash_ipportip *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipportip6_elem e = { };
- struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
&e.port, &e.proto))
@@ -283,7 +340,7 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
const struct hash_ipportip *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipportip6_elem e = { };
- struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
u32 port, port_to;
bool with_ports = false;
int ret;
@@ -357,8 +414,8 @@ static struct ip_set_type hash_ipportip_type __read_mostly = {
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
.dimension = IPSET_DIM_THREE,
.family = NFPROTO_UNSPEC,
- .revision_min = IPSET_TYPE_REV_MIN,
- .revision_max = IPSET_TYPE_REV_MAX,
+ .revision_min = REVISION_MIN,
+ .revision_max = REVISION_MAX,
.create = hash_ipportip_create,
.create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
@@ -380,7 +437,6 @@ static struct ip_set_type hash_ipportip_type __read_mostly = {
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
[IPSET_ATTR_BYTES] = { .type = NLA_U64 },
[IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
- [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
},
.me = THIS_MODULE,
};
diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c
index 5d87fe8..f15f3e2 100644
--- a/net/netfilter/ipset/ip_set_hash_ipportnet.c
+++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c
@@ -24,16 +24,15 @@
#include <linux/netfilter/ipset/ip_set_getport.h>
#include <linux/netfilter/ipset/ip_set_hash.h>
-#define IPSET_TYPE_REV_MIN 0
-/* 1 SCTP and UDPLITE support added */
-/* 2 Range as input support for IPv4 added */
-/* 3 nomatch flag support added */
-/* 4 Counters support added */
-#define IPSET_TYPE_REV_MAX 5 /* Comments support added */
+#define REVISION_MIN 0
+/* 1 SCTP and UDPLITE support added */
+/* 2 Range as input support for IPv4 added */
+/* 3 nomatch flag support added */
+#define REVISION_MAX 4 /* Counters support added */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
-IP_SET_MODULE_DESC("hash:ip,port,net", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
+IP_SET_MODULE_DESC("hash:ip,port,net", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_hash:ip,port,net");
/* Type specific function prefix */
@@ -47,7 +46,7 @@ MODULE_ALIAS("ip_set_hash:ip,port,net");
#define IP_SET_HASH_WITH_PROTO
#define IP_SET_HASH_WITH_NETS
-/* IPv4 variant */
+/* IPv4 variants */
/* Member elements */
struct hash_ipportnet4_elem {
@@ -59,6 +58,37 @@ struct hash_ipportnet4_elem {
u8 proto;
};
+struct hash_ipportnet4t_elem {
+ __be32 ip;
+ __be32 ip2;
+ __be16 port;
+ u8 cidr:7;
+ u8 nomatch:1;
+ u8 proto;
+ unsigned long timeout;
+};
+
+struct hash_ipportnet4c_elem {
+ __be32 ip;
+ __be32 ip2;
+ __be16 port;
+ u8 cidr:7;
+ u8 nomatch:1;
+ u8 proto;
+ struct ip_set_counter counter;
+};
+
+struct hash_ipportnet4ct_elem {
+ __be32 ip;
+ __be32 ip2;
+ __be16 port;
+ u8 cidr:7;
+ u8 nomatch:1;
+ u8 proto;
+ struct ip_set_counter counter;
+ unsigned long timeout;
+};
+
/* Common functions */
static inline bool
@@ -140,9 +170,9 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct hash_ipportnet *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipportnet4_elem e = {
- .cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK) - 1,
+ .cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1
};
- struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
if (adt == IPSET_TEST)
e.cidr = HOST_MASK - 1;
@@ -165,9 +195,9 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
const struct hash_ipportnet *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipportnet4_elem e = { .cidr = HOST_MASK - 1 };
- struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
- u32 ip = 0, ip_to = 0, p = 0, port, port_to;
- u32 ip2_from = 0, ip2_to = 0, ip2_last, ip2;
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
+ u32 ip, ip_to, p = 0, port, port_to;
+ u32 ip2_from, ip2_to, ip2_last, ip2;
bool with_ports = false;
u8 cidr;
int ret;
@@ -242,7 +272,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
if (ip > ip_to)
swap(ip, ip_to);
} else if (tb[IPSET_ATTR_CIDR]) {
- cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
+ u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
if (!cidr || cidr > 32)
return -IPSET_ERR_INVALID_CIDR;
@@ -276,9 +306,9 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
: port;
for (; p <= port_to; p++) {
e.port = htons(p);
- ip2 = retried &&
- ip == ntohl(h->next.ip) &&
- p == ntohs(h->next.port)
+ ip2 = retried
+ && ip == ntohl(h->next.ip)
+ && p == ntohs(h->next.port)
? ntohl(h->next.ip2) : ip2_from;
while (!after(ip2, ip2_to)) {
e.ip2 = htonl(ip2);
@@ -298,7 +328,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
return ret;
}
-/* IPv6 variant */
+/* IPv6 variants */
struct hash_ipportnet6_elem {
union nf_inet_addr ip;
@@ -309,6 +339,37 @@ struct hash_ipportnet6_elem {
u8 proto;
};
+struct hash_ipportnet6t_elem {
+ union nf_inet_addr ip;
+ union nf_inet_addr ip2;
+ __be16 port;
+ u8 cidr:7;
+ u8 nomatch:1;
+ u8 proto;
+ unsigned long timeout;
+};
+
+struct hash_ipportnet6c_elem {
+ union nf_inet_addr ip;
+ union nf_inet_addr ip2;
+ __be16 port;
+ u8 cidr:7;
+ u8 nomatch:1;
+ u8 proto;
+ struct ip_set_counter counter;
+};
+
+struct hash_ipportnet6ct_elem {
+ union nf_inet_addr ip;
+ union nf_inet_addr ip2;
+ __be16 port;
+ u8 cidr:7;
+ u8 nomatch:1;
+ u8 proto;
+ struct ip_set_counter counter;
+ unsigned long timeout;
+};
+
/* Common functions */
static inline bool
@@ -393,9 +454,9 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct hash_ipportnet *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipportnet6_elem e = {
- .cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK) - 1,
+ .cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1
};
- struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
if (adt == IPSET_TEST)
e.cidr = HOST_MASK - 1;
@@ -418,7 +479,7 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
const struct hash_ipportnet *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipportnet6_elem e = { .cidr = HOST_MASK - 1 };
- struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
u32 port, port_to;
bool with_ports = false;
u8 cidr;
@@ -513,8 +574,8 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = {
IPSET_TYPE_NOMATCH,
.dimension = IPSET_DIM_THREE,
.family = NFPROTO_UNSPEC,
- .revision_min = IPSET_TYPE_REV_MIN,
- .revision_max = IPSET_TYPE_REV_MAX,
+ .revision_min = REVISION_MIN,
+ .revision_max = REVISION_MAX,
.create = hash_ipportnet_create,
.create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
@@ -539,7 +600,6 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = {
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
[IPSET_ATTR_BYTES] = { .type = NLA_U64 },
[IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
- [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
},
.me = THIS_MODULE,
};
diff --git a/net/netfilter/ipset/ip_set_hash_net.c b/net/netfilter/ipset/ip_set_hash_net.c
index 8295cf4..223e9f5 100644
--- a/net/netfilter/ipset/ip_set_hash_net.c
+++ b/net/netfilter/ipset/ip_set_hash_net.c
@@ -22,22 +22,21 @@
#include <linux/netfilter/ipset/ip_set.h>
#include <linux/netfilter/ipset/ip_set_hash.h>
-#define IPSET_TYPE_REV_MIN 0
-/* 1 Range as input support for IPv4 added */
-/* 2 nomatch flag support added */
-/* 3 Counters support added */
-#define IPSET_TYPE_REV_MAX 4 /* Comments support added */
+#define REVISION_MIN 0
+/* 1 Range as input support for IPv4 added */
+/* 2 nomatch flag support added */
+#define REVISION_MAX 3 /* Counters support added */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
-IP_SET_MODULE_DESC("hash:net", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
+IP_SET_MODULE_DESC("hash:net", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_hash:net");
/* Type specific function prefix */
#define HTYPE hash_net
#define IP_SET_HASH_WITH_NETS
-/* IPv4 variant */
+/* IPv4 variants */
/* Member elements */
struct hash_net4_elem {
@@ -47,6 +46,31 @@ struct hash_net4_elem {
u8 cidr;
};
+struct hash_net4t_elem {
+ __be32 ip;
+ u16 padding0;
+ u8 nomatch;
+ u8 cidr;
+ unsigned long timeout;
+};
+
+struct hash_net4c_elem {
+ __be32 ip;
+ u16 padding0;
+ u8 nomatch;
+ u8 cidr;
+ struct ip_set_counter counter;
+};
+
+struct hash_net4ct_elem {
+ __be32 ip;
+ u16 padding0;
+ u8 nomatch;
+ u8 cidr;
+ struct ip_set_counter counter;
+ unsigned long timeout;
+};
+
/* Common functions */
static inline bool
@@ -119,9 +143,9 @@ hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct hash_net *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_net4_elem e = {
- .cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
+ .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
};
- struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
if (e.cidr == 0)
return -EINVAL;
@@ -141,8 +165,8 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
const struct hash_net *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_net4_elem e = { .cidr = HOST_MASK };
- struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
- u32 ip = 0, ip_to = 0, last;
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
+ u32 ip = 0, ip_to, last;
int ret;
if (unlikely(!tb[IPSET_ATTR_IP] ||
@@ -204,7 +228,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
return ret;
}
-/* IPv6 variant */
+/* IPv6 variants */
struct hash_net6_elem {
union nf_inet_addr ip;
@@ -213,6 +237,31 @@ struct hash_net6_elem {
u8 cidr;
};
+struct hash_net6t_elem {
+ union nf_inet_addr ip;
+ u16 padding0;
+ u8 nomatch;
+ u8 cidr;
+ unsigned long timeout;
+};
+
+struct hash_net6c_elem {
+ union nf_inet_addr ip;
+ u16 padding0;
+ u8 nomatch;
+ u8 cidr;
+ struct ip_set_counter counter;
+};
+
+struct hash_net6ct_elem {
+ union nf_inet_addr ip;
+ u16 padding0;
+ u8 nomatch;
+ u8 cidr;
+ struct ip_set_counter counter;
+ unsigned long timeout;
+};
+
/* Common functions */
static inline bool
@@ -289,9 +338,9 @@ hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct hash_net *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_net6_elem e = {
- .cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
+ .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
};
- struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
if (e.cidr == 0)
return -EINVAL;
@@ -308,9 +357,10 @@ static int
hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
{
+ const struct hash_net *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_net6_elem e = { .cidr = HOST_MASK };
- struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
int ret;
if (unlikely(!tb[IPSET_ATTR_IP] ||
@@ -356,8 +406,8 @@ static struct ip_set_type hash_net_type __read_mostly = {
.features = IPSET_TYPE_IP | IPSET_TYPE_NOMATCH,
.dimension = IPSET_DIM_ONE,
.family = NFPROTO_UNSPEC,
- .revision_min = IPSET_TYPE_REV_MIN,
- .revision_max = IPSET_TYPE_REV_MAX,
+ .revision_min = REVISION_MIN,
+ .revision_max = REVISION_MAX,
.create = hash_net_create,
.create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
@@ -375,7 +425,6 @@ static struct ip_set_type hash_net_type __read_mostly = {
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
[IPSET_ATTR_BYTES] = { .type = NLA_U64 },
[IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
- [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
},
.me = THIS_MODULE,
};
diff --git a/net/netfilter/ipset/ip_set_hash_netiface.c b/net/netfilter/ipset/ip_set_hash_netiface.c
index 3f64a66..7d798d5 100644
--- a/net/netfilter/ipset/ip_set_hash_netiface.c
+++ b/net/netfilter/ipset/ip_set_hash_netiface.c
@@ -23,15 +23,14 @@
#include <linux/netfilter/ipset/ip_set.h>
#include <linux/netfilter/ipset/ip_set_hash.h>
-#define IPSET_TYPE_REV_MIN 0
-/* 1 nomatch flag support added */
-/* 2 /0 support added */
-/* 3 Counters support added */
-#define IPSET_TYPE_REV_MAX 4 /* Comments support added */
+#define REVISION_MIN 0
+/* 1 nomatch flag support added */
+/* 2 /0 support added */
+#define REVISION_MAX 3 /* Counters support added */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
-IP_SET_MODULE_DESC("hash:net,iface", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
+IP_SET_MODULE_DESC("hash:net,iface", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_hash:net,iface");
/* Interface name rbtree */
@@ -135,7 +134,7 @@ iface_add(struct rb_root *root, const char **iface)
#define STREQ(a, b) (strcmp(a, b) == 0)
-/* IPv4 variant */
+/* IPv4 variants */
struct hash_netiface4_elem_hashed {
__be32 ip;
@@ -145,7 +144,7 @@ struct hash_netiface4_elem_hashed {
u8 elem;
};
-/* Member elements */
+/* Member elements without timeout */
struct hash_netiface4_elem {
__be32 ip;
u8 physdev;
@@ -155,6 +154,37 @@ struct hash_netiface4_elem {
const char *iface;
};
+struct hash_netiface4t_elem {
+ __be32 ip;
+ u8 physdev;
+ u8 cidr;
+ u8 nomatch;
+ u8 elem;
+ const char *iface;
+ unsigned long timeout;
+};
+
+struct hash_netiface4c_elem {
+ __be32 ip;
+ u8 physdev;
+ u8 cidr;
+ u8 nomatch;
+ u8 elem;
+ const char *iface;
+ struct ip_set_counter counter;
+};
+
+struct hash_netiface4ct_elem {
+ __be32 ip;
+ u8 physdev;
+ u8 cidr;
+ u8 nomatch;
+ u8 elem;
+ const char *iface;
+ struct ip_set_counter counter;
+ unsigned long timeout;
+};
+
/* Common functions */
static inline bool
@@ -235,10 +265,10 @@ hash_netiface4_kadt(struct ip_set *set, const struct sk_buff *skb,
struct hash_netiface *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netiface4_elem e = {
- .cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
+ .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK,
.elem = 1,
};
- struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
int ret;
if (e.cidr == 0)
@@ -289,8 +319,8 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
struct hash_netiface *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netiface4_elem e = { .cidr = HOST_MASK, .elem = 1 };
- struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
- u32 ip = 0, ip_to = 0, last;
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
+ u32 ip = 0, ip_to, last;
char iface[IFNAMSIZ];
int ret;
@@ -369,7 +399,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
return ret;
}
-/* IPv6 variant */
+/* IPv6 variants */
struct hash_netiface6_elem_hashed {
union nf_inet_addr ip;
@@ -388,6 +418,37 @@ struct hash_netiface6_elem {
const char *iface;
};
+struct hash_netiface6t_elem {
+ union nf_inet_addr ip;
+ u8 physdev;
+ u8 cidr;
+ u8 nomatch;
+ u8 elem;
+ const char *iface;
+ unsigned long timeout;
+};
+
+struct hash_netiface6c_elem {
+ union nf_inet_addr ip;
+ u8 physdev;
+ u8 cidr;
+ u8 nomatch;
+ u8 elem;
+ const char *iface;
+ struct ip_set_counter counter;
+};
+
+struct hash_netiface6ct_elem {
+ union nf_inet_addr ip;
+ u8 physdev;
+ u8 cidr;
+ u8 nomatch;
+ u8 elem;
+ const char *iface;
+ struct ip_set_counter counter;
+ unsigned long timeout;
+};
+
/* Common functions */
static inline bool
@@ -473,10 +534,10 @@ hash_netiface6_kadt(struct ip_set *set, const struct sk_buff *skb,
struct hash_netiface *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netiface6_elem e = {
- .cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
+ .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK,
.elem = 1,
};
- struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
int ret;
if (e.cidr == 0)
@@ -523,7 +584,7 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
struct hash_netiface *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netiface6_elem e = { .cidr = HOST_MASK, .elem = 1 };
- struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
char iface[IFNAMSIZ];
int ret;
@@ -584,8 +645,8 @@ static struct ip_set_type hash_netiface_type __read_mostly = {
IPSET_TYPE_NOMATCH,
.dimension = IPSET_DIM_TWO,
.family = NFPROTO_UNSPEC,
- .revision_min = IPSET_TYPE_REV_MIN,
- .revision_max = IPSET_TYPE_REV_MAX,
+ .revision_min = REVISION_MIN,
+ .revision_max = REVISION_MAX,
.create = hash_netiface_create,
.create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
@@ -607,7 +668,6 @@ static struct ip_set_type hash_netiface_type __read_mostly = {
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
[IPSET_ATTR_BYTES] = { .type = NLA_U64 },
[IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
- [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
},
.me = THIS_MODULE,
};
diff --git a/net/netfilter/ipset/ip_set_hash_netnet.c b/net/netfilter/ipset/ip_set_hash_netnet.c
deleted file mode 100644
index 2bc2dec..0000000
--- a/net/netfilter/ipset/ip_set_hash_netnet.c
+++ /dev/null
@@ -1,481 +0,0 @@
-/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
- * Copyright (C) 2013 Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>
- *
- * 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.
- */
-
-/* Kernel module implementing an IP set type: the hash:net type */
-
-#include <linux/jhash.h>
-#include <linux/module.h>
-#include <linux/ip.h>
-#include <linux/skbuff.h>
-#include <linux/errno.h>
-#include <linux/random.h>
-#include <net/ip.h>
-#include <net/ipv6.h>
-#include <net/netlink.h>
-
-#include <linux/netfilter.h>
-#include <linux/netfilter/ipset/pfxlen.h>
-#include <linux/netfilter/ipset/ip_set.h>
-#include <linux/netfilter/ipset/ip_set_hash.h>
-
-#define IPSET_TYPE_REV_MIN 0
-#define IPSET_TYPE_REV_MAX 0
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>");
-IP_SET_MODULE_DESC("hash:net,net", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
-MODULE_ALIAS("ip_set_hash:net,net");
-
-/* Type specific function prefix */
-#define HTYPE hash_netnet
-#define IP_SET_HASH_WITH_NETS
-#define IPSET_NET_COUNT 2
-
-/* IPv4 variants */
-
-/* Member elements */
-struct hash_netnet4_elem {
- union {
- __be32 ip[2];
- __be64 ipcmp;
- };
- u8 nomatch;
- union {
- u8 cidr[2];
- u16 ccmp;
- };
-};
-
-/* Common functions */
-
-static inline bool
-hash_netnet4_data_equal(const struct hash_netnet4_elem *ip1,
- const struct hash_netnet4_elem *ip2,
- u32 *multi)
-{
- return ip1->ipcmp == ip2->ipcmp &&
- ip2->ccmp == ip2->ccmp;
-}
-
-static inline int
-hash_netnet4_do_data_match(const struct hash_netnet4_elem *elem)
-{
- return elem->nomatch ? -ENOTEMPTY : 1;
-}
-
-static inline void
-hash_netnet4_data_set_flags(struct hash_netnet4_elem *elem, u32 flags)
-{
- elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
-}
-
-static inline void
-hash_netnet4_data_reset_flags(struct hash_netnet4_elem *elem, u8 *flags)
-{
- swap(*flags, elem->nomatch);
-}
-
-static inline void
-hash_netnet4_data_reset_elem(struct hash_netnet4_elem *elem,
- struct hash_netnet4_elem *orig)
-{
- elem->ip[1] = orig->ip[1];
-}
-
-static inline void
-hash_netnet4_data_netmask(struct hash_netnet4_elem *elem, u8 cidr, bool inner)
-{
- if (inner) {
- elem->ip[1] &= ip_set_netmask(cidr);
- elem->cidr[1] = cidr;
- } else {
- elem->ip[0] &= ip_set_netmask(cidr);
- elem->cidr[0] = cidr;
- }
-}
-
-static bool
-hash_netnet4_data_list(struct sk_buff *skb,
- const struct hash_netnet4_elem *data)
-{
- u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
-
- if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip[0]) ||
- nla_put_ipaddr4(skb, IPSET_ATTR_IP2, data->ip[1]) ||
- nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0]) ||
- nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr[1]) ||
- (flags &&
- nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return 1;
-}
-
-static inline void
-hash_netnet4_data_next(struct hash_netnet4_elem *next,
- const struct hash_netnet4_elem *d)
-{
- next->ipcmp = d->ipcmp;
-}
-
-#define MTYPE hash_netnet4
-#define PF 4
-#define HOST_MASK 32
-#include "ip_set_hash_gen.h"
-
-static int
-hash_netnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
- const struct xt_action_param *par,
- enum ipset_adt adt, struct ip_set_adt_opt *opt)
-{
- const struct hash_netnet *h = set->data;
- ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_netnet4_elem e = { };
- struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
-
- e.cidr[0] = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK);
- e.cidr[1] = IP_SET_INIT_CIDR(h->nets[0].cidr[1], HOST_MASK);
- if (adt == IPSET_TEST)
- e.ccmp = (HOST_MASK << (sizeof(e.cidr[0]) * 8)) | HOST_MASK;
-
- ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0]);
- ip4addrptr(skb, opt->flags & IPSET_DIM_TWO_SRC, &e.ip[1]);
- e.ip[0] &= ip_set_netmask(e.cidr[0]);
- e.ip[1] &= ip_set_netmask(e.cidr[1]);
-
- return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
-}
-
-static int
-hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[],
- enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
-{
- const struct hash_netnet *h = set->data;
- ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_netnet4_elem e = { };
- struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
- u32 ip = 0, ip_to = 0, last;
- u32 ip2 = 0, ip2_from = 0, ip2_to = 0, last2;
- u8 cidr, cidr2;
- int ret;
-
- e.cidr[0] = e.cidr[1] = HOST_MASK;
- if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
- return -IPSET_ERR_PROTOCOL;
-
- if (tb[IPSET_ATTR_LINENO])
- *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
-
- ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip) ||
- ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2], &ip2_from) ||
- ip_set_get_extensions(set, tb, &ext);
- if (ret)
- return ret;
-
- if (tb[IPSET_ATTR_CIDR]) {
- cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
- if (!cidr || cidr > HOST_MASK)
- return -IPSET_ERR_INVALID_CIDR;
- e.cidr[0] = cidr;
- }
-
- if (tb[IPSET_ATTR_CIDR2]) {
- cidr2 = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
- if (!cidr2 || cidr2 > HOST_MASK)
- return -IPSET_ERR_INVALID_CIDR;
- e.cidr[1] = cidr2;
- }
-
- if (tb[IPSET_ATTR_CADT_FLAGS]) {
- u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
- if (cadt_flags & IPSET_FLAG_NOMATCH)
- flags |= (IPSET_FLAG_NOMATCH << 16);
- }
-
- if (adt == IPSET_TEST || !(tb[IPSET_ATTR_IP_TO] &&
- tb[IPSET_ATTR_IP2_TO])) {
- e.ip[0] = htonl(ip & ip_set_hostmask(e.cidr[0]));
- e.ip[1] = htonl(ip2_from & ip_set_hostmask(e.cidr[1]));
- ret = adtfn(set, &e, &ext, &ext, flags);
- return ip_set_enomatch(ret, flags, adt, set) ? -ret :
- ip_set_eexist(ret, flags) ? 0 : ret;
- }
-
- ip_to = ip;
- if (tb[IPSET_ATTR_IP_TO]) {
- ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
- if (ret)
- return ret;
- if (ip_to < ip)
- swap(ip, ip_to);
- if (ip + UINT_MAX == ip_to)
- return -IPSET_ERR_HASH_RANGE;
- }
-
- ip2_to = ip2_from;
- if (tb[IPSET_ATTR_IP2_TO]) {
- ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2_TO], &ip2_to);
- if (ret)
- return ret;
- if (ip2_to < ip2_from)
- swap(ip2_from, ip2_to);
- if (ip2_from + UINT_MAX == ip2_to)
- return -IPSET_ERR_HASH_RANGE;
-
- }
-
- if (retried)
- ip = ntohl(h->next.ip[0]);
-
- while (!after(ip, ip_to)) {
- e.ip[0] = htonl(ip);
- last = ip_set_range_to_cidr(ip, ip_to, &cidr);
- e.cidr[0] = cidr;
- ip2 = (retried &&
- ip == ntohl(h->next.ip[0])) ? ntohl(h->next.ip[1])
- : ip2_from;
- while (!after(ip2, ip2_to)) {
- e.ip[1] = htonl(ip2);
- last2 = ip_set_range_to_cidr(ip2, ip2_to, &cidr2);
- e.cidr[1] = cidr2;
- ret = adtfn(set, &e, &ext, &ext, flags);
- if (ret && !ip_set_eexist(ret, flags))
- return ret;
- else
- ret = 0;
- ip2 = last2 + 1;
- }
- ip = last + 1;
- }
- return ret;
-}
-
-/* IPv6 variants */
-
-struct hash_netnet6_elem {
- union nf_inet_addr ip[2];
- u8 nomatch;
- union {
- u8 cidr[2];
- u16 ccmp;
- };
-};
-
-/* Common functions */
-
-static inline bool
-hash_netnet6_data_equal(const struct hash_netnet6_elem *ip1,
- const struct hash_netnet6_elem *ip2,
- u32 *multi)
-{
- return ipv6_addr_equal(&ip1->ip[0].in6, &ip2->ip[0].in6) &&
- ipv6_addr_equal(&ip1->ip[1].in6, &ip2->ip[1].in6) &&
- ip1->ccmp == ip2->ccmp;
-}
-
-static inline int
-hash_netnet6_do_data_match(const struct hash_netnet6_elem *elem)
-{
- return elem->nomatch ? -ENOTEMPTY : 1;
-}
-
-static inline void
-hash_netnet6_data_set_flags(struct hash_netnet6_elem *elem, u32 flags)
-{
- elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
-}
-
-static inline void
-hash_netnet6_data_reset_flags(struct hash_netnet6_elem *elem, u8 *flags)
-{
- swap(*flags, elem->nomatch);
-}
-
-static inline void
-hash_netnet6_data_reset_elem(struct hash_netnet6_elem *elem,
- struct hash_netnet6_elem *orig)
-{
- elem->ip[1] = orig->ip[1];
-}
-
-static inline void
-hash_netnet6_data_netmask(struct hash_netnet6_elem *elem, u8 cidr, bool inner)
-{
- if (inner) {
- ip6_netmask(&elem->ip[1], cidr);
- elem->cidr[1] = cidr;
- } else {
- ip6_netmask(&elem->ip[0], cidr);
- elem->cidr[0] = cidr;
- }
-}
-
-static bool
-hash_netnet6_data_list(struct sk_buff *skb,
- const struct hash_netnet6_elem *data)
-{
- u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
-
- if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip[0].in6) ||
- nla_put_ipaddr6(skb, IPSET_ATTR_IP2, &data->ip[1].in6) ||
- nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0]) ||
- nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr[1]) ||
- (flags &&
- nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return 1;
-}
-
-static inline void
-hash_netnet6_data_next(struct hash_netnet4_elem *next,
- const struct hash_netnet6_elem *d)
-{
-}
-
-#undef MTYPE
-#undef PF
-#undef HOST_MASK
-
-#define MTYPE hash_netnet6
-#define PF 6
-#define HOST_MASK 128
-#define IP_SET_EMIT_CREATE
-#include "ip_set_hash_gen.h"
-
-static int
-hash_netnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
- const struct xt_action_param *par,
- enum ipset_adt adt, struct ip_set_adt_opt *opt)
-{
- const struct hash_netnet *h = set->data;
- ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_netnet6_elem e = { };
- struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
-
- e.cidr[0] = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK);
- e.cidr[1] = IP_SET_INIT_CIDR(h->nets[0].cidr[1], HOST_MASK);
- if (adt == IPSET_TEST)
- e.ccmp = (HOST_MASK << (sizeof(u8)*8)) | HOST_MASK;
-
- ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0].in6);
- ip6addrptr(skb, opt->flags & IPSET_DIM_TWO_SRC, &e.ip[1].in6);
- ip6_netmask(&e.ip[0], e.cidr[0]);
- ip6_netmask(&e.ip[1], e.cidr[1]);
-
- return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
-}
-
-static int
-hash_netnet6_uadt(struct ip_set *set, struct nlattr *tb[],
- enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
-{
- ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_netnet6_elem e = { };
- struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
- int ret;
-
- e.cidr[0] = e.cidr[1] = HOST_MASK;
- if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
- return -IPSET_ERR_PROTOCOL;
- if (unlikely(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_IP2_TO]))
- return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
-
- if (tb[IPSET_ATTR_LINENO])
- *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
-
- ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip[0]) ||
- ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &e.ip[1]) ||
- ip_set_get_extensions(set, tb, &ext);
- if (ret)
- return ret;
-
- if (tb[IPSET_ATTR_CIDR])
- e.cidr[0] = nla_get_u8(tb[IPSET_ATTR_CIDR]);
-
- if (tb[IPSET_ATTR_CIDR2])
- e.cidr[1] = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
-
- if (!e.cidr[0] || e.cidr[0] > HOST_MASK || !e.cidr[1] ||
- e.cidr[1] > HOST_MASK)
- return -IPSET_ERR_INVALID_CIDR;
-
- ip6_netmask(&e.ip[0], e.cidr[0]);
- ip6_netmask(&e.ip[1], e.cidr[1]);
-
- if (tb[IPSET_ATTR_CADT_FLAGS]) {
- u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
- if (cadt_flags & IPSET_FLAG_NOMATCH)
- flags |= (IPSET_FLAG_NOMATCH << 16);
- }
-
- ret = adtfn(set, &e, &ext, &ext, flags);
-
- return ip_set_enomatch(ret, flags, adt, set) ? -ret :
- ip_set_eexist(ret, flags) ? 0 : ret;
-}
-
-static struct ip_set_type hash_netnet_type __read_mostly = {
- .name = "hash:net,net",
- .protocol = IPSET_PROTOCOL,
- .features = IPSET_TYPE_IP | IPSET_TYPE_IP2 | IPSET_TYPE_NOMATCH,
- .dimension = IPSET_DIM_TWO,
- .family = NFPROTO_UNSPEC,
- .revision_min = IPSET_TYPE_REV_MIN,
- .revision_max = IPSET_TYPE_REV_MAX,
- .create = hash_netnet_create,
- .create_policy = {
- [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
- [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
- [IPSET_ATTR_PROBES] = { .type = NLA_U8 },
- [IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
- [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
- [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
- },
- .adt_policy = {
- [IPSET_ATTR_IP] = { .type = NLA_NESTED },
- [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
- [IPSET_ATTR_IP2] = { .type = NLA_NESTED },
- [IPSET_ATTR_IP2_TO] = { .type = NLA_NESTED },
- [IPSET_ATTR_CIDR] = { .type = NLA_U8 },
- [IPSET_ATTR_CIDR2] = { .type = NLA_U8 },
- [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
- [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
- [IPSET_ATTR_BYTES] = { .type = NLA_U64 },
- [IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
- [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
- },
- .me = THIS_MODULE,
-};
-
-static int __init
-hash_netnet_init(void)
-{
- return ip_set_type_register(&hash_netnet_type);
-}
-
-static void __exit
-hash_netnet_fini(void)
-{
- ip_set_type_unregister(&hash_netnet_type);
-}
-
-module_init(hash_netnet_init);
-module_exit(hash_netnet_fini);
diff --git a/net/netfilter/ipset/ip_set_hash_netport.c b/net/netfilter/ipset/ip_set_hash_netport.c
index 7097fb0..09d6690 100644
--- a/net/netfilter/ipset/ip_set_hash_netport.c
+++ b/net/netfilter/ipset/ip_set_hash_netport.c
@@ -23,16 +23,15 @@
#include <linux/netfilter/ipset/ip_set_getport.h>
#include <linux/netfilter/ipset/ip_set_hash.h>
-#define IPSET_TYPE_REV_MIN 0
-/* 1 SCTP and UDPLITE support added */
-/* 2 Range as input support for IPv4 added */
-/* 3 nomatch flag support added */
-/* 4 Counters support added */
-#define IPSET_TYPE_REV_MAX 5 /* Comments support added */
+#define REVISION_MIN 0
+/* 1 SCTP and UDPLITE support added */
+/* 2 Range as input support for IPv4 added */
+/* 3 nomatch flag support added */
+#define REVISION_MAX 4 /* Counters support added */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
-IP_SET_MODULE_DESC("hash:net,port", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
+IP_SET_MODULE_DESC("hash:net,port", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_hash:net,port");
/* Type specific function prefix */
@@ -46,7 +45,7 @@ MODULE_ALIAS("ip_set_hash:net,port");
*/
#define IP_SET_HASH_WITH_NETS_PACKED
-/* IPv4 variant */
+/* IPv4 variants */
/* Member elements */
struct hash_netport4_elem {
@@ -57,6 +56,34 @@ struct hash_netport4_elem {
u8 nomatch:1;
};
+struct hash_netport4t_elem {
+ __be32 ip;
+ __be16 port;
+ u8 proto;
+ u8 cidr:7;
+ u8 nomatch:1;
+ unsigned long timeout;
+};
+
+struct hash_netport4c_elem {
+ __be32 ip;
+ __be16 port;
+ u8 proto;
+ u8 cidr:7;
+ u8 nomatch:1;
+ struct ip_set_counter counter;
+};
+
+struct hash_netport4ct_elem {
+ __be32 ip;
+ __be16 port;
+ u8 proto;
+ u8 cidr:7;
+ u8 nomatch:1;
+ struct ip_set_counter counter;
+ unsigned long timeout;
+};
+
/* Common functions */
static inline bool
@@ -135,9 +162,9 @@ hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct hash_netport *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netport4_elem e = {
- .cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK) - 1,
+ .cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1
};
- struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
if (adt == IPSET_TEST)
e.cidr = HOST_MASK - 1;
@@ -159,8 +186,8 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
const struct hash_netport *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netport4_elem e = { .cidr = HOST_MASK - 1 };
- struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
- u32 port, port_to, p = 0, ip = 0, ip_to = 0, last;
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
+ u32 port, port_to, p = 0, ip = 0, ip_to, last;
bool with_ports = false;
u8 cidr;
int ret;
@@ -260,7 +287,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
return ret;
}
-/* IPv6 variant */
+/* IPv6 variants */
struct hash_netport6_elem {
union nf_inet_addr ip;
@@ -270,6 +297,34 @@ struct hash_netport6_elem {
u8 nomatch:1;
};
+struct hash_netport6t_elem {
+ union nf_inet_addr ip;
+ __be16 port;
+ u8 proto;
+ u8 cidr:7;
+ u8 nomatch:1;
+ unsigned long timeout;
+};
+
+struct hash_netport6c_elem {
+ union nf_inet_addr ip;
+ __be16 port;
+ u8 proto;
+ u8 cidr:7;
+ u8 nomatch:1;
+ struct ip_set_counter counter;
+};
+
+struct hash_netport6ct_elem {
+ union nf_inet_addr ip;
+ __be16 port;
+ u8 proto;
+ u8 cidr:7;
+ u8 nomatch:1;
+ struct ip_set_counter counter;
+ unsigned long timeout;
+};
+
/* Common functions */
static inline bool
@@ -352,9 +407,9 @@ hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct hash_netport *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netport6_elem e = {
- .cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK) - 1,
+ .cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1,
};
- struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
if (adt == IPSET_TEST)
e.cidr = HOST_MASK - 1;
@@ -376,7 +431,7 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
const struct hash_netport *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netport6_elem e = { .cidr = HOST_MASK - 1 };
- struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
u32 port, port_to;
bool with_ports = false;
u8 cidr;
@@ -463,8 +518,8 @@ static struct ip_set_type hash_netport_type __read_mostly = {
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_NOMATCH,
.dimension = IPSET_DIM_TWO,
.family = NFPROTO_UNSPEC,
- .revision_min = IPSET_TYPE_REV_MIN,
- .revision_max = IPSET_TYPE_REV_MAX,
+ .revision_min = REVISION_MIN,
+ .revision_max = REVISION_MAX,
.create = hash_netport_create,
.create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
@@ -487,7 +542,6 @@ static struct ip_set_type hash_netport_type __read_mostly = {
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
[IPSET_ATTR_BYTES] = { .type = NLA_U64 },
[IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
- [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
},
.me = THIS_MODULE,
};
diff --git a/net/netfilter/ipset/ip_set_hash_netportnet.c b/net/netfilter/ipset/ip_set_hash_netportnet.c
deleted file mode 100644
index 703d119..0000000
--- a/net/netfilter/ipset/ip_set_hash_netportnet.c
+++ /dev/null
@@ -1,586 +0,0 @@
-/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
- *
- * 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.
- */
-
-/* Kernel module implementing an IP set type: the hash:ip,port,net type */
-
-#include <linux/jhash.h>
-#include <linux/module.h>
-#include <linux/ip.h>
-#include <linux/skbuff.h>
-#include <linux/errno.h>
-#include <linux/random.h>
-#include <net/ip.h>
-#include <net/ipv6.h>
-#include <net/netlink.h>
-#include <net/tcp.h>
-
-#include <linux/netfilter.h>
-#include <linux/netfilter/ipset/pfxlen.h>
-#include <linux/netfilter/ipset/ip_set.h>
-#include <linux/netfilter/ipset/ip_set_getport.h>
-#include <linux/netfilter/ipset/ip_set_hash.h>
-
-#define IPSET_TYPE_REV_MIN 0
-#define IPSET_TYPE_REV_MAX 0 /* Comments support added */
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>");
-IP_SET_MODULE_DESC("hash:net,port,net", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
-MODULE_ALIAS("ip_set_hash:net,port,net");
-
-/* Type specific function prefix */
-#define HTYPE hash_netportnet
-#define IP_SET_HASH_WITH_PROTO
-#define IP_SET_HASH_WITH_NETS
-#define IPSET_NET_COUNT 2
-
-/* IPv4 variant */
-
-/* Member elements */
-struct hash_netportnet4_elem {
- union {
- __be32 ip[2];
- __be64 ipcmp;
- };
- __be16 port;
- union {
- u8 cidr[2];
- u16 ccmp;
- };
- u8 nomatch:1;
- u8 proto;
-};
-
-/* Common functions */
-
-static inline bool
-hash_netportnet4_data_equal(const struct hash_netportnet4_elem *ip1,
- const struct hash_netportnet4_elem *ip2,
- u32 *multi)
-{
- return ip1->ipcmp == ip2->ipcmp &&
- ip1->ccmp == ip2->ccmp &&
- ip1->port == ip2->port &&
- ip1->proto == ip2->proto;
-}
-
-static inline int
-hash_netportnet4_do_data_match(const struct hash_netportnet4_elem *elem)
-{
- return elem->nomatch ? -ENOTEMPTY : 1;
-}
-
-static inline void
-hash_netportnet4_data_set_flags(struct hash_netportnet4_elem *elem, u32 flags)
-{
- elem->nomatch = !!((flags >> 16) & IPSET_FLAG_NOMATCH);
-}
-
-static inline void
-hash_netportnet4_data_reset_flags(struct hash_netportnet4_elem *elem, u8 *flags)
-{
- swap(*flags, elem->nomatch);
-}
-
-static inline void
-hash_netportnet4_data_reset_elem(struct hash_netportnet4_elem *elem,
- struct hash_netportnet4_elem *orig)
-{
- elem->ip[1] = orig->ip[1];
-}
-
-static inline void
-hash_netportnet4_data_netmask(struct hash_netportnet4_elem *elem,
- u8 cidr, bool inner)
-{
- if (inner) {
- elem->ip[1] &= ip_set_netmask(cidr);
- elem->cidr[1] = cidr;
- } else {
- elem->ip[0] &= ip_set_netmask(cidr);
- elem->cidr[0] = cidr;
- }
-}
-
-static bool
-hash_netportnet4_data_list(struct sk_buff *skb,
- const struct hash_netportnet4_elem *data)
-{
- u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
-
- if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip[0]) ||
- nla_put_ipaddr4(skb, IPSET_ATTR_IP2, data->ip[1]) ||
- nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
- nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0]) ||
- nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr[1]) ||
- nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
- (flags &&
- nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return 1;
-}
-
-static inline void
-hash_netportnet4_data_next(struct hash_netportnet4_elem *next,
- const struct hash_netportnet4_elem *d)
-{
- next->ipcmp = d->ipcmp;
- next->port = d->port;
-}
-
-#define MTYPE hash_netportnet4
-#define PF 4
-#define HOST_MASK 32
-#include "ip_set_hash_gen.h"
-
-static int
-hash_netportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
- const struct xt_action_param *par,
- enum ipset_adt adt, struct ip_set_adt_opt *opt)
-{
- const struct hash_netportnet *h = set->data;
- ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_netportnet4_elem e = { };
- struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
-
- e.cidr[0] = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK);
- e.cidr[1] = IP_SET_INIT_CIDR(h->nets[0].cidr[1], HOST_MASK);
- if (adt == IPSET_TEST)
- e.ccmp = (HOST_MASK << (sizeof(e.cidr[0]) * 8)) | HOST_MASK;
-
- if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
- &e.port, &e.proto))
- return -EINVAL;
-
- ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0]);
- ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip[1]);
- e.ip[0] &= ip_set_netmask(e.cidr[0]);
- e.ip[1] &= ip_set_netmask(e.cidr[1]);
-
- return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
-}
-
-static int
-hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
- enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
-{
- const struct hash_netportnet *h = set->data;
- ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_netportnet4_elem e = { };
- struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
- u32 ip = 0, ip_to = 0, ip_last, p = 0, port, port_to;
- u32 ip2_from = 0, ip2_to = 0, ip2_last, ip2;
- bool with_ports = false;
- u8 cidr, cidr2;
- int ret;
-
- e.cidr[0] = e.cidr[1] = HOST_MASK;
- if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
- !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
- return -IPSET_ERR_PROTOCOL;
-
- if (tb[IPSET_ATTR_LINENO])
- *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
-
- ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip) ||
- ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2], &ip2_from) ||
- ip_set_get_extensions(set, tb, &ext);
- if (ret)
- return ret;
-
- if (tb[IPSET_ATTR_CIDR]) {
- cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
- if (!cidr || cidr > HOST_MASK)
- return -IPSET_ERR_INVALID_CIDR;
- e.cidr[0] = cidr;
- }
-
- if (tb[IPSET_ATTR_CIDR2]) {
- cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
- if (!cidr || cidr > HOST_MASK)
- return -IPSET_ERR_INVALID_CIDR;
- e.cidr[1] = cidr;
- }
-
- if (tb[IPSET_ATTR_PORT])
- e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
- else
- return -IPSET_ERR_PROTOCOL;
-
- if (tb[IPSET_ATTR_PROTO]) {
- e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
- with_ports = ip_set_proto_with_ports(e.proto);
-
- if (e.proto == 0)
- return -IPSET_ERR_INVALID_PROTO;
- } else
- return -IPSET_ERR_MISSING_PROTO;
-
- if (!(with_ports || e.proto == IPPROTO_ICMP))
- e.port = 0;
-
- if (tb[IPSET_ATTR_CADT_FLAGS]) {
- u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
- if (cadt_flags & IPSET_FLAG_NOMATCH)
- flags |= (IPSET_FLAG_NOMATCH << 16);
- }
-
- with_ports = with_ports && tb[IPSET_ATTR_PORT_TO];
- if (adt == IPSET_TEST ||
- !(tb[IPSET_ATTR_IP_TO] || with_ports || tb[IPSET_ATTR_IP2_TO])) {
- e.ip[0] = htonl(ip & ip_set_hostmask(e.cidr[0]));
- e.ip[1] = htonl(ip2_from & ip_set_hostmask(e.cidr[1]));
- ret = adtfn(set, &e, &ext, &ext, flags);
- return ip_set_enomatch(ret, flags, adt, set) ? -ret :
- ip_set_eexist(ret, flags) ? 0 : ret;
- }
-
- ip_to = ip;
- if (tb[IPSET_ATTR_IP_TO]) {
- ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
- if (ret)
- return ret;
- if (ip > ip_to)
- swap(ip, ip_to);
- if (unlikely(ip + UINT_MAX == ip_to))
- return -IPSET_ERR_HASH_RANGE;
- }
-
- port_to = port = ntohs(e.port);
- if (tb[IPSET_ATTR_PORT_TO]) {
- port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
- if (port > port_to)
- swap(port, port_to);
- }
-
- ip2_to = ip2_from;
- if (tb[IPSET_ATTR_IP2_TO]) {
- ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2_TO], &ip2_to);
- if (ret)
- return ret;
- if (ip2_from > ip2_to)
- swap(ip2_from, ip2_to);
- if (unlikely(ip2_from + UINT_MAX == ip2_to))
- return -IPSET_ERR_HASH_RANGE;
- }
-
- if (retried)
- ip = ntohl(h->next.ip[0]);
-
- while (!after(ip, ip_to)) {
- e.ip[0] = htonl(ip);
- ip_last = ip_set_range_to_cidr(ip, ip_to, &cidr);
- e.cidr[0] = cidr;
- p = retried && ip == ntohl(h->next.ip[0]) ? ntohs(h->next.port)
- : port;
- for (; p <= port_to; p++) {
- e.port = htons(p);
- ip2 = (retried && ip == ntohl(h->next.ip[0]) &&
- p == ntohs(h->next.port)) ? ntohl(h->next.ip[1])
- : ip2_from;
- while (!after(ip2, ip2_to)) {
- e.ip[1] = htonl(ip2);
- ip2_last = ip_set_range_to_cidr(ip2, ip2_to,
- &cidr2);
- e.cidr[1] = cidr2;
- ret = adtfn(set, &e, &ext, &ext, flags);
- if (ret && !ip_set_eexist(ret, flags))
- return ret;
- else
- ret = 0;
- ip2 = ip2_last + 1;
- }
- }
- ip = ip_last + 1;
- }
- return ret;
-}
-
-/* IPv6 variant */
-
-struct hash_netportnet6_elem {
- union nf_inet_addr ip[2];
- __be16 port;
- union {
- u8 cidr[2];
- u16 ccmp;
- };
- u8 nomatch:1;
- u8 proto;
-};
-
-/* Common functions */
-
-static inline bool
-hash_netportnet6_data_equal(const struct hash_netportnet6_elem *ip1,
- const struct hash_netportnet6_elem *ip2,
- u32 *multi)
-{
- return ipv6_addr_equal(&ip1->ip[0].in6, &ip2->ip[0].in6) &&
- ipv6_addr_equal(&ip1->ip[1].in6, &ip2->ip[1].in6) &&
- ip1->ccmp == ip2->ccmp &&
- ip1->port == ip2->port &&
- ip1->proto == ip2->proto;
-}
-
-static inline int
-hash_netportnet6_do_data_match(const struct hash_netportnet6_elem *elem)
-{
- return elem->nomatch ? -ENOTEMPTY : 1;
-}
-
-static inline void
-hash_netportnet6_data_set_flags(struct hash_netportnet6_elem *elem, u32 flags)
-{
- elem->nomatch = !!((flags >> 16) & IPSET_FLAG_NOMATCH);
-}
-
-static inline void
-hash_netportnet6_data_reset_flags(struct hash_netportnet6_elem *elem, u8 *flags)
-{
- swap(*flags, elem->nomatch);
-}
-
-static inline void
-hash_netportnet6_data_reset_elem(struct hash_netportnet6_elem *elem,
- struct hash_netportnet6_elem *orig)
-{
- elem->ip[1] = orig->ip[1];
-}
-
-static inline void
-hash_netportnet6_data_netmask(struct hash_netportnet6_elem *elem,
- u8 cidr, bool inner)
-{
- if (inner) {
- ip6_netmask(&elem->ip[1], cidr);
- elem->cidr[1] = cidr;
- } else {
- ip6_netmask(&elem->ip[0], cidr);
- elem->cidr[0] = cidr;
- }
-}
-
-static bool
-hash_netportnet6_data_list(struct sk_buff *skb,
- const struct hash_netportnet6_elem *data)
-{
- u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
-
- if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip[0].in6) ||
- nla_put_ipaddr6(skb, IPSET_ATTR_IP2, &data->ip[1].in6) ||
- nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
- nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0]) ||
- nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr[1]) ||
- nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
- (flags &&
- nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return 1;
-}
-
-static inline void
-hash_netportnet6_data_next(struct hash_netportnet4_elem *next,
- const struct hash_netportnet6_elem *d)
-{
- next->port = d->port;
-}
-
-#undef MTYPE
-#undef PF
-#undef HOST_MASK
-
-#define MTYPE hash_netportnet6
-#define PF 6
-#define HOST_MASK 128
-#define IP_SET_EMIT_CREATE
-#include "ip_set_hash_gen.h"
-
-static int
-hash_netportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
- const struct xt_action_param *par,
- enum ipset_adt adt, struct ip_set_adt_opt *opt)
-{
- const struct hash_netportnet *h = set->data;
- ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_netportnet6_elem e = { };
- struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
-
- e.cidr[0] = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK);
- e.cidr[1] = IP_SET_INIT_CIDR(h->nets[0].cidr[1], HOST_MASK);
- if (adt == IPSET_TEST)
- e.ccmp = (HOST_MASK << (sizeof(u8) * 8)) | HOST_MASK;
-
- if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
- &e.port, &e.proto))
- return -EINVAL;
-
- ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0].in6);
- ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip[1].in6);
- ip6_netmask(&e.ip[0], e.cidr[0]);
- ip6_netmask(&e.ip[1], e.cidr[1]);
-
- return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
-}
-
-static int
-hash_netportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
- enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
-{
- const struct hash_netportnet *h = set->data;
- ipset_adtfn adtfn = set->variant->adt[adt];
- struct hash_netportnet6_elem e = { };
- struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
- u32 port, port_to;
- bool with_ports = false;
- int ret;
-
- e.cidr[0] = e.cidr[1] = HOST_MASK;
- if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
- !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
- !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
- return -IPSET_ERR_PROTOCOL;
- if (unlikely(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_IP2_TO]))
- return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
-
- if (tb[IPSET_ATTR_LINENO])
- *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
-
- ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip[0]) ||
- ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &e.ip[1]) ||
- ip_set_get_extensions(set, tb, &ext);
- if (ret)
- return ret;
-
- if (tb[IPSET_ATTR_CIDR])
- e.cidr[0] = nla_get_u8(tb[IPSET_ATTR_CIDR]);
-
- if (tb[IPSET_ATTR_CIDR2])
- e.cidr[1] = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
-
- if (unlikely(!e.cidr[0] || e.cidr[0] > HOST_MASK || !e.cidr[1] ||
- e.cidr[1] > HOST_MASK))
- return -IPSET_ERR_INVALID_CIDR;
-
- ip6_netmask(&e.ip[0], e.cidr[0]);
- ip6_netmask(&e.ip[1], e.cidr[1]);
-
- if (tb[IPSET_ATTR_PORT])
- e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
- else
- return -IPSET_ERR_PROTOCOL;
-
- if (tb[IPSET_ATTR_PROTO]) {
- e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
- with_ports = ip_set_proto_with_ports(e.proto);
-
- if (e.proto == 0)
- return -IPSET_ERR_INVALID_PROTO;
- } else
- return -IPSET_ERR_MISSING_PROTO;
-
- if (!(with_ports || e.proto == IPPROTO_ICMPV6))
- e.port = 0;
-
- if (tb[IPSET_ATTR_CADT_FLAGS]) {
- u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
- if (cadt_flags & IPSET_FLAG_NOMATCH)
- flags |= (IPSET_FLAG_NOMATCH << 16);
- }
-
- if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
- ret = adtfn(set, &e, &ext, &ext, flags);
- return ip_set_enomatch(ret, flags, adt, set) ? -ret :
- ip_set_eexist(ret, flags) ? 0 : ret;
- }
-
- port = ntohs(e.port);
- port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
- if (port > port_to)
- swap(port, port_to);
-
- if (retried)
- port = ntohs(h->next.port);
- for (; port <= port_to; port++) {
- e.port = htons(port);
- ret = adtfn(set, &e, &ext, &ext, flags);
-
- if (ret && !ip_set_eexist(ret, flags))
- return ret;
- else
- ret = 0;
- }
- return ret;
-}
-
-static struct ip_set_type hash_netportnet_type __read_mostly = {
- .name = "hash:net,port,net",
- .protocol = IPSET_PROTOCOL,
- .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2 |
- IPSET_TYPE_NOMATCH,
- .dimension = IPSET_DIM_THREE,
- .family = NFPROTO_UNSPEC,
- .revision_min = IPSET_TYPE_REV_MIN,
- .revision_max = IPSET_TYPE_REV_MAX,
- .create = hash_netportnet_create,
- .create_policy = {
- [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
- [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
- [IPSET_ATTR_PROBES] = { .type = NLA_U8 },
- [IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
- [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
- [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
- },
- .adt_policy = {
- [IPSET_ATTR_IP] = { .type = NLA_NESTED },
- [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
- [IPSET_ATTR_IP2] = { .type = NLA_NESTED },
- [IPSET_ATTR_IP2_TO] = { .type = NLA_NESTED },
- [IPSET_ATTR_PORT] = { .type = NLA_U16 },
- [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 },
- [IPSET_ATTR_CIDR] = { .type = NLA_U8 },
- [IPSET_ATTR_CIDR2] = { .type = NLA_U8 },
- [IPSET_ATTR_PROTO] = { .type = NLA_U8 },
- [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
- [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
- [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
- [IPSET_ATTR_BYTES] = { .type = NLA_U64 },
- [IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
- [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
- },
- .me = THIS_MODULE,
-};
-
-static int __init
-hash_netportnet_init(void)
-{
- return ip_set_type_register(&hash_netportnet_type);
-}
-
-static void __exit
-hash_netportnet_fini(void)
-{
- ip_set_type_unregister(&hash_netportnet_type);
-}
-
-module_init(hash_netportnet_init);
-module_exit(hash_netportnet_fini);
diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c
index 3e2317f..979b8c9 100644
--- a/net/netfilter/ipset/ip_set_list_set.c
+++ b/net/netfilter/ipset/ip_set_list_set.c
@@ -15,13 +15,12 @@
#include <linux/netfilter/ipset/ip_set.h>
#include <linux/netfilter/ipset/ip_set_list.h>
-#define IPSET_TYPE_REV_MIN 0
-/* 1 Counters support added */
-#define IPSET_TYPE_REV_MAX 2 /* Comments support added */
+#define REVISION_MIN 0
+#define REVISION_MAX 1 /* Counters support added */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
-IP_SET_MODULE_DESC("list:set", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
+IP_SET_MODULE_DESC("list:set", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_list:set");
/* Member elements */
@@ -29,6 +28,28 @@ struct set_elem {
ip_set_id_t id;
};
+struct sett_elem {
+ struct {
+ ip_set_id_t id;
+ } __attribute__ ((aligned));
+ unsigned long timeout;
+};
+
+struct setc_elem {
+ struct {
+ ip_set_id_t id;
+ } __attribute__ ((aligned));
+ struct ip_set_counter counter;
+};
+
+struct setct_elem {
+ struct {
+ ip_set_id_t id;
+ } __attribute__ ((aligned));
+ struct ip_set_counter counter;
+ unsigned long timeout;
+};
+
struct set_adt_elem {
ip_set_id_t id;
ip_set_id_t refid;
@@ -37,14 +58,24 @@ struct set_adt_elem {
/* Type structure */
struct list_set {
+ size_t dsize; /* element size */
+ size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */
u32 size; /* size of set list array */
+ u32 timeout; /* timeout value */
struct timer_list gc; /* garbage collection */
- struct net *net; /* namespace */
struct set_elem members[0]; /* the set members */
};
-#define list_set_elem(set, map, id) \
- (struct set_elem *)((void *)(map)->members + (id) * (set)->dsize)
+static inline struct set_elem *
+list_set_elem(const struct list_set *map, u32 id)
+{
+ return (struct set_elem *)((void *)map->members + id * map->dsize);
+}
+
+#define ext_timeout(e, m) \
+(unsigned long *)((void *)(e) + (m)->offset[IPSET_OFFSET_TIMEOUT])
+#define ext_counter(e, m) \
+(struct ip_set_counter *)((void *)(e) + (m)->offset[IPSET_OFFSET_COUNTER])
static int
list_set_ktest(struct ip_set *set, const struct sk_buff *skb,
@@ -61,16 +92,16 @@ list_set_ktest(struct ip_set *set, const struct sk_buff *skb,
if (opt->cmdflags & IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE)
opt->cmdflags &= ~IPSET_FLAG_SKIP_COUNTER_UPDATE;
for (i = 0; i < map->size; i++) {
- e = list_set_elem(set, map, i);
+ e = list_set_elem(map, i);
if (e->id == IPSET_INVALID_ID)
return 0;
if (SET_WITH_TIMEOUT(set) &&
- ip_set_timeout_expired(ext_timeout(e, set)))
+ ip_set_timeout_expired(ext_timeout(e, map)))
continue;
ret = ip_set_test(e->id, skb, par, opt);
if (ret > 0) {
if (SET_WITH_COUNTER(set))
- ip_set_update_counter(ext_counter(e, set),
+ ip_set_update_counter(ext_counter(e, map),
ext, &opt->ext,
cmdflags);
return ret;
@@ -90,11 +121,11 @@ list_set_kadd(struct ip_set *set, const struct sk_buff *skb,
int ret;
for (i = 0; i < map->size; i++) {
- e = list_set_elem(set, map, i);
+ e = list_set_elem(map, i);
if (e->id == IPSET_INVALID_ID)
return 0;
if (SET_WITH_TIMEOUT(set) &&
- ip_set_timeout_expired(ext_timeout(e, set)))
+ ip_set_timeout_expired(ext_timeout(e, map)))
continue;
ret = ip_set_add(e->id, skb, par, opt);
if (ret == 0)
@@ -114,11 +145,11 @@ list_set_kdel(struct ip_set *set, const struct sk_buff *skb,
int ret;
for (i = 0; i < map->size; i++) {
- e = list_set_elem(set, map, i);
+ e = list_set_elem(map, i);
if (e->id == IPSET_INVALID_ID)
return 0;
if (SET_WITH_TIMEOUT(set) &&
- ip_set_timeout_expired(ext_timeout(e, set)))
+ ip_set_timeout_expired(ext_timeout(e, map)))
continue;
ret = ip_set_del(e->id, skb, par, opt);
if (ret == 0)
@@ -132,7 +163,8 @@ list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par,
enum ipset_adt adt, struct ip_set_adt_opt *opt)
{
- struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
+ struct list_set *map = set->data;
+ struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, map);
switch (adt) {
case IPSET_TEST:
@@ -156,10 +188,10 @@ id_eq(const struct ip_set *set, u32 i, ip_set_id_t id)
if (i >= map->size)
return 0;
- e = list_set_elem(set, map, i);
+ e = list_set_elem(map, i);
return !!(e->id == id &&
!(SET_WITH_TIMEOUT(set) &&
- ip_set_timeout_expired(ext_timeout(e, set))));
+ ip_set_timeout_expired(ext_timeout(e, map))));
}
static int
@@ -167,36 +199,28 @@ list_set_add(struct ip_set *set, u32 i, struct set_adt_elem *d,
const struct ip_set_ext *ext)
{
struct list_set *map = set->data;
- struct set_elem *e = list_set_elem(set, map, i);
+ struct set_elem *e = list_set_elem(map, i);
if (e->id != IPSET_INVALID_ID) {
- if (i == map->size - 1) {
+ if (i == map->size - 1)
/* Last element replaced: e.g. add new,before,last */
- ip_set_put_byindex(map->net, e->id);
- ip_set_ext_destroy(set, e);
- } else {
- struct set_elem *x = list_set_elem(set, map,
- map->size - 1);
+ ip_set_put_byindex(e->id);
+ else {
+ struct set_elem *x = list_set_elem(map, map->size - 1);
/* Last element pushed off */
- if (x->id != IPSET_INVALID_ID) {
- ip_set_put_byindex(map->net, x->id);
- ip_set_ext_destroy(set, x);
- }
- memmove(list_set_elem(set, map, i + 1), e,
- set->dsize * (map->size - (i + 1)));
- /* Extensions must be initialized to zero */
- memset(e, 0, set->dsize);
+ if (x->id != IPSET_INVALID_ID)
+ ip_set_put_byindex(x->id);
+ memmove(list_set_elem(map, i + 1), e,
+ map->dsize * (map->size - (i + 1)));
}
}
e->id = d->id;
if (SET_WITH_TIMEOUT(set))
- ip_set_timeout_set(ext_timeout(e, set), ext->timeout);
+ ip_set_timeout_set(ext_timeout(e, map), ext->timeout);
if (SET_WITH_COUNTER(set))
- ip_set_init_counter(ext_counter(e, set), ext);
- if (SET_WITH_COMMENT(set))
- ip_set_init_comment(ext_comment(e, set), ext);
+ ip_set_init_counter(ext_counter(e, map), ext);
return 0;
}
@@ -204,17 +228,16 @@ static int
list_set_del(struct ip_set *set, u32 i)
{
struct list_set *map = set->data;
- struct set_elem *e = list_set_elem(set, map, i);
+ struct set_elem *e = list_set_elem(map, i);
- ip_set_put_byindex(map->net, e->id);
- ip_set_ext_destroy(set, e);
+ ip_set_put_byindex(e->id);
if (i < map->size - 1)
- memmove(e, list_set_elem(set, map, i + 1),
- set->dsize * (map->size - (i + 1)));
+ memmove(e, list_set_elem(map, i + 1),
+ map->dsize * (map->size - (i + 1)));
/* Last element */
- e = list_set_elem(set, map, map->size - 1);
+ e = list_set_elem(map, map->size - 1);
e->id = IPSET_INVALID_ID;
return 0;
}
@@ -224,16 +247,13 @@ set_cleanup_entries(struct ip_set *set)
{
struct list_set *map = set->data;
struct set_elem *e;
- u32 i = 0;
+ u32 i;
- while (i < map->size) {
- e = list_set_elem(set, map, i);
+ for (i = 0; i < map->size; i++) {
+ e = list_set_elem(map, i);
if (e->id != IPSET_INVALID_ID &&
- ip_set_timeout_expired(ext_timeout(e, set)))
+ ip_set_timeout_expired(ext_timeout(e, map)))
list_set_del(set, i);
- /* Check element moved to position i in next loop */
- else
- i++;
}
}
@@ -248,11 +268,11 @@ list_set_utest(struct ip_set *set, void *value, const struct ip_set_ext *ext,
int ret;
for (i = 0; i < map->size; i++) {
- e = list_set_elem(set, map, i);
+ e = list_set_elem(map, i);
if (e->id == IPSET_INVALID_ID)
return 0;
else if (SET_WITH_TIMEOUT(set) &&
- ip_set_timeout_expired(ext_timeout(e, set)))
+ ip_set_timeout_expired(ext_timeout(e, map)))
continue;
else if (e->id != d->id)
continue;
@@ -279,14 +299,14 @@ list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext,
bool flag_exist = flags & IPSET_FLAG_EXIST;
u32 i, ret = 0;
- if (SET_WITH_TIMEOUT(set))
- set_cleanup_entries(set);
-
/* Check already added element */
for (i = 0; i < map->size; i++) {
- e = list_set_elem(set, map, i);
+ e = list_set_elem(map, i);
if (e->id == IPSET_INVALID_ID)
goto insert;
+ else if (SET_WITH_TIMEOUT(set) &&
+ ip_set_timeout_expired(ext_timeout(e, map)))
+ continue;
else if (e->id != d->id)
continue;
@@ -299,22 +319,18 @@ list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext,
/* Can't re-add */
return -IPSET_ERR_EXIST;
/* Update extensions */
- ip_set_ext_destroy(set, e);
-
if (SET_WITH_TIMEOUT(set))
- ip_set_timeout_set(ext_timeout(e, set), ext->timeout);
+ ip_set_timeout_set(ext_timeout(e, map), ext->timeout);
if (SET_WITH_COUNTER(set))
- ip_set_init_counter(ext_counter(e, set), ext);
- if (SET_WITH_COMMENT(set))
- ip_set_init_comment(ext_comment(e, set), ext);
+ ip_set_init_counter(ext_counter(e, map), ext);
/* Set is already added to the list */
- ip_set_put_byindex(map->net, d->id);
+ ip_set_put_byindex(d->id);
return 0;
}
insert:
ret = -IPSET_ERR_LIST_FULL;
for (i = 0; i < map->size && ret == -IPSET_ERR_LIST_FULL; i++) {
- e = list_set_elem(set, map, i);
+ e = list_set_elem(map, i);
if (e->id == IPSET_INVALID_ID)
ret = d->before != 0 ? -IPSET_ERR_REF_EXIST
: list_set_add(set, i, d, ext);
@@ -339,12 +355,12 @@ list_set_udel(struct ip_set *set, void *value, const struct ip_set_ext *ext,
u32 i;
for (i = 0; i < map->size; i++) {
- e = list_set_elem(set, map, i);
+ e = list_set_elem(map, i);
if (e->id == IPSET_INVALID_ID)
return d->before != 0 ? -IPSET_ERR_REF_EXIST
: -IPSET_ERR_EXIST;
else if (SET_WITH_TIMEOUT(set) &&
- ip_set_timeout_expired(ext_timeout(e, set)))
+ ip_set_timeout_expired(ext_timeout(e, map)))
continue;
else if (e->id != d->id)
continue;
@@ -370,7 +386,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
struct list_set *map = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
struct set_adt_elem e = { .refid = IPSET_INVALID_ID };
- struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
+ struct ip_set_ext ext = IP_SET_INIT_UEXT(map);
struct ip_set *s;
int ret = 0;
@@ -387,7 +403,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
ret = ip_set_get_extensions(set, tb, &ext);
if (ret)
return ret;
- e.id = ip_set_get_byname(map->net, nla_data(tb[IPSET_ATTR_NAME]), &s);
+ e.id = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAME]), &s);
if (e.id == IPSET_INVALID_ID)
return -IPSET_ERR_NAME;
/* "Loop detection" */
@@ -407,8 +423,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
}
if (tb[IPSET_ATTR_NAMEREF]) {
- e.refid = ip_set_get_byname(map->net,
- nla_data(tb[IPSET_ATTR_NAMEREF]),
+ e.refid = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAMEREF]),
&s);
if (e.refid == IPSET_INVALID_ID) {
ret = -IPSET_ERR_NAMEREF;
@@ -424,9 +439,9 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
finish:
if (e.refid != IPSET_INVALID_ID)
- ip_set_put_byindex(map->net, e.refid);
+ ip_set_put_byindex(e.refid);
if (adt != IPSET_ADD || ret)
- ip_set_put_byindex(map->net, e.id);
+ ip_set_put_byindex(e.id);
return ip_set_eexist(ret, flags) ? 0 : ret;
}
@@ -439,10 +454,9 @@ list_set_flush(struct ip_set *set)
u32 i;
for (i = 0; i < map->size; i++) {
- e = list_set_elem(set, map, i);
+ e = list_set_elem(map, i);
if (e->id != IPSET_INVALID_ID) {
- ip_set_put_byindex(map->net, e->id);
- ip_set_ext_destroy(set, e);
+ ip_set_put_byindex(e->id);
e->id = IPSET_INVALID_ID;
}
}
@@ -471,11 +485,14 @@ list_set_head(struct ip_set *set, struct sk_buff *skb)
if (!nested)
goto nla_put_failure;
if (nla_put_net32(skb, IPSET_ATTR_SIZE, htonl(map->size)) ||
+ (SET_WITH_TIMEOUT(set) &&
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout))) ||
+ (SET_WITH_COUNTER(set) &&
+ nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS,
+ htonl(IPSET_FLAG_WITH_COUNTERS))) ||
nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
nla_put_net32(skb, IPSET_ATTR_MEMSIZE,
- htonl(sizeof(*map) + map->size * set->dsize)))
- goto nla_put_failure;
- if (unlikely(ip_set_put_flags(skb, set)))
+ htonl(sizeof(*map) + map->size * map->dsize)))
goto nla_put_failure;
ipset_nest_end(skb, nested);
@@ -490,20 +507,19 @@ list_set_list(const struct ip_set *set,
{
const struct list_set *map = set->data;
struct nlattr *atd, *nested;
- u32 i, first = cb->args[IPSET_CB_ARG0];
+ u32 i, first = cb->args[2];
const struct set_elem *e;
atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
if (!atd)
return -EMSGSIZE;
- for (; cb->args[IPSET_CB_ARG0] < map->size;
- cb->args[IPSET_CB_ARG0]++) {
- i = cb->args[IPSET_CB_ARG0];
- e = list_set_elem(set, map, i);
+ for (; cb->args[2] < map->size; cb->args[2]++) {
+ i = cb->args[2];
+ e = list_set_elem(map, i);
if (e->id == IPSET_INVALID_ID)
goto finish;
if (SET_WITH_TIMEOUT(set) &&
- ip_set_timeout_expired(ext_timeout(e, set)))
+ ip_set_timeout_expired(ext_timeout(e, map)))
continue;
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested) {
@@ -514,25 +530,31 @@ list_set_list(const struct ip_set *set,
goto nla_put_failure;
}
if (nla_put_string(skb, IPSET_ATTR_NAME,
- ip_set_name_byindex(map->net, e->id)))
+ ip_set_name_byindex(e->id)))
+ goto nla_put_failure;
+ if (SET_WITH_TIMEOUT(set) &&
+ nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
+ htonl(ip_set_timeout_get(
+ ext_timeout(e, map)))))
goto nla_put_failure;
- if (ip_set_put_extensions(skb, set, e, true))
+ if (SET_WITH_COUNTER(set) &&
+ ip_set_put_counter(skb, ext_counter(e, map)))
goto nla_put_failure;
ipset_nest_end(skb, nested);
}
finish:
ipset_nest_end(skb, atd);
/* Set listing finished */
- cb->args[IPSET_CB_ARG0] = 0;
+ cb->args[2] = 0;
return 0;
nla_put_failure:
nla_nest_cancel(skb, nested);
+ ipset_nest_end(skb, atd);
if (unlikely(i == first)) {
- cb->args[IPSET_CB_ARG0] = 0;
+ cb->args[2] = 0;
return -EMSGSIZE;
}
- ipset_nest_end(skb, atd);
return 0;
}
@@ -543,7 +565,7 @@ list_set_same_set(const struct ip_set *a, const struct ip_set *b)
const struct list_set *y = b->data;
return x->size == y->size &&
- a->timeout == b->timeout &&
+ x->timeout == y->timeout &&
a->extensions == b->extensions;
}
@@ -572,7 +594,7 @@ list_set_gc(unsigned long ul_set)
set_cleanup_entries(set);
write_unlock_bh(&set->lock);
- map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;
+ map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
add_timer(&map->gc);
}
@@ -584,40 +606,43 @@ list_set_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))
init_timer(&map->gc);
map->gc.data = (unsigned long) set;
map->gc.function = gc;
- map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;
+ map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
add_timer(&map->gc);
}
/* Create list:set type of sets */
-static bool
-init_list_set(struct net *net, struct ip_set *set, u32 size)
+static struct list_set *
+init_list_set(struct ip_set *set, u32 size, size_t dsize,
+ unsigned long timeout)
{
struct list_set *map;
struct set_elem *e;
u32 i;
- map = kzalloc(sizeof(*map) + size * set->dsize, GFP_KERNEL);
+ map = kzalloc(sizeof(*map) + size * dsize, GFP_KERNEL);
if (!map)
- return false;
+ return NULL;
map->size = size;
- map->net = net;
+ map->dsize = dsize;
+ map->timeout = timeout;
set->data = map;
for (i = 0; i < size; i++) {
- e = list_set_elem(set, map, i);
+ e = list_set_elem(map, i);
e->id = IPSET_INVALID_ID;
}
- return true;
+ return map;
}
static int
-list_set_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
- u32 flags)
+list_set_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
{
- u32 size = IP_SET_LIST_DEFAULT_SIZE;
+ struct list_set *map;
+ u32 size = IP_SET_LIST_DEFAULT_SIZE, cadt_flags = 0;
+ unsigned long timeout = 0;
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_SIZE) ||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
@@ -629,13 +654,45 @@ list_set_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
if (size < IP_SET_LIST_MIN_SIZE)
size = IP_SET_LIST_MIN_SIZE;
+ if (tb[IPSET_ATTR_CADT_FLAGS])
+ cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
+ if (tb[IPSET_ATTR_TIMEOUT])
+ timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
set->variant = &set_variant;
- set->dsize = ip_set_elem_len(set, tb, sizeof(struct set_elem));
- if (!init_list_set(net, set, size))
- return -ENOMEM;
- if (tb[IPSET_ATTR_TIMEOUT]) {
- set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
+ if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) {
+ set->extensions |= IPSET_EXT_COUNTER;
+ if (tb[IPSET_ATTR_TIMEOUT]) {
+ map = init_list_set(set, size,
+ sizeof(struct setct_elem), timeout);
+ if (!map)
+ return -ENOMEM;
+ set->extensions |= IPSET_EXT_TIMEOUT;
+ map->offset[IPSET_OFFSET_TIMEOUT] =
+ offsetof(struct setct_elem, timeout);
+ map->offset[IPSET_OFFSET_COUNTER] =
+ offsetof(struct setct_elem, counter);
+ list_set_gc_init(set, list_set_gc);
+ } else {
+ map = init_list_set(set, size,
+ sizeof(struct setc_elem), 0);
+ if (!map)
+ return -ENOMEM;
+ map->offset[IPSET_OFFSET_COUNTER] =
+ offsetof(struct setc_elem, counter);
+ }
+ } else if (tb[IPSET_ATTR_TIMEOUT]) {
+ map = init_list_set(set, size,
+ sizeof(struct sett_elem), timeout);
+ if (!map)
+ return -ENOMEM;
+ set->extensions |= IPSET_EXT_TIMEOUT;
+ map->offset[IPSET_OFFSET_TIMEOUT] =
+ offsetof(struct sett_elem, timeout);
list_set_gc_init(set, list_set_gc);
+ } else {
+ map = init_list_set(set, size, sizeof(struct set_elem), 0);
+ if (!map)
+ return -ENOMEM;
}
return 0;
}
@@ -646,8 +703,8 @@ static struct ip_set_type list_set_type __read_mostly = {
.features = IPSET_TYPE_NAME | IPSET_DUMP_LAST,
.dimension = IPSET_DIM_ONE,
.family = NFPROTO_UNSPEC,
- .revision_min = IPSET_TYPE_REV_MIN,
- .revision_max = IPSET_TYPE_REV_MAX,
+ .revision_min = REVISION_MIN,
+ .revision_max = REVISION_MAX,
.create = list_set_create,
.create_policy = {
[IPSET_ATTR_SIZE] = { .type = NLA_U32 },
@@ -664,7 +721,6 @@ static struct ip_set_type list_set_type __read_mostly = {
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
[IPSET_ATTR_BYTES] = { .type = NLA_U64 },
[IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
- [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
},
.me = THIS_MODULE,
};
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 4f26ee4..74fd00c 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -1139,6 +1139,12 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af)
ip_vs_fill_iph_skb(af, skb, &iph);
#ifdef CONFIG_IP_VS_IPV6
if (af == AF_INET6) {
+ if (!iph.fragoffs && skb_nfct_reasm(skb)) {
+ struct sk_buff *reasm = skb_nfct_reasm(skb);
+ /* Save fw mark for coming frags */
+ reasm->ipvs_property = 1;
+ reasm->mark = skb->mark;
+ }
if (unlikely(iph.protocol == IPPROTO_ICMPV6)) {
int related;
int verdict = ip_vs_out_icmp_v6(skb, &related,
@@ -1233,11 +1239,11 @@ ip_vs_out(unsigned int hooknum, struct sk_buff *skb, int af)
* Check if packet is reply for established ip_vs_conn.
*/
static unsigned int
-ip_vs_reply4(const struct nf_hook_ops *ops, struct sk_buff *skb,
+ip_vs_reply4(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- return ip_vs_out(ops->hooknum, skb, AF_INET);
+ return ip_vs_out(hooknum, skb, AF_INET);
}
/*
@@ -1245,11 +1251,11 @@ ip_vs_reply4(const struct nf_hook_ops *ops, struct sk_buff *skb,
* Check if packet is reply for established ip_vs_conn.
*/
static unsigned int
-ip_vs_local_reply4(const struct nf_hook_ops *ops, struct sk_buff *skb,
+ip_vs_local_reply4(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- return ip_vs_out(ops->hooknum, skb, AF_INET);
+ return ip_vs_out(hooknum, skb, AF_INET);
}
#ifdef CONFIG_IP_VS_IPV6
@@ -1260,11 +1266,11 @@ ip_vs_local_reply4(const struct nf_hook_ops *ops, struct sk_buff *skb,
* Check if packet is reply for established ip_vs_conn.
*/
static unsigned int
-ip_vs_reply6(const struct nf_hook_ops *ops, struct sk_buff *skb,
+ip_vs_reply6(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- return ip_vs_out(ops->hooknum, skb, AF_INET6);
+ return ip_vs_out(hooknum, skb, AF_INET6);
}
/*
@@ -1272,11 +1278,11 @@ ip_vs_reply6(const struct nf_hook_ops *ops, struct sk_buff *skb,
* Check if packet is reply for established ip_vs_conn.
*/
static unsigned int
-ip_vs_local_reply6(const struct nf_hook_ops *ops, struct sk_buff *skb,
+ip_vs_local_reply6(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- return ip_vs_out(ops->hooknum, skb, AF_INET6);
+ return ip_vs_out(hooknum, skb, AF_INET6);
}
#endif
@@ -1608,6 +1614,12 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
#ifdef CONFIG_IP_VS_IPV6
if (af == AF_INET6) {
+ if (!iph.fragoffs && skb_nfct_reasm(skb)) {
+ struct sk_buff *reasm = skb_nfct_reasm(skb);
+ /* Save fw mark for coming frags. */
+ reasm->ipvs_property = 1;
+ reasm->mark = skb->mark;
+ }
if (unlikely(iph.protocol == IPPROTO_ICMPV6)) {
int related;
int verdict = ip_vs_in_icmp_v6(skb, &related, hooknum,
@@ -1659,8 +1671,9 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
/* sorry, all this trouble for a no-hit :) */
IP_VS_DBG_PKT(12, af, pp, skb, 0,
"ip_vs_in: packet continues traversal as normal");
- if (iph.fragoffs) {
+ if (iph.fragoffs && !skb_nfct_reasm(skb)) {
/* Fragment that couldn't be mapped to a conn entry
+ * and don't have any pointer to a reasm skb
* is missing module nf_defrag_ipv6
*/
IP_VS_DBG_RL("Unhandled frag, load nf_defrag_ipv6\n");
@@ -1720,12 +1733,12 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
* Schedule and forward packets from remote clients
*/
static unsigned int
-ip_vs_remote_request4(const struct nf_hook_ops *ops, struct sk_buff *skb,
+ip_vs_remote_request4(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- return ip_vs_in(ops->hooknum, skb, AF_INET);
+ return ip_vs_in(hooknum, skb, AF_INET);
}
/*
@@ -1733,26 +1746,58 @@ ip_vs_remote_request4(const struct nf_hook_ops *ops, struct sk_buff *skb,
* Schedule and forward packets from local clients
*/
static unsigned int
-ip_vs_local_request4(const struct nf_hook_ops *ops, struct sk_buff *skb,
+ip_vs_local_request4(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- return ip_vs_in(ops->hooknum, skb, AF_INET);
+ return ip_vs_in(hooknum, skb, AF_INET);
}
#ifdef CONFIG_IP_VS_IPV6
/*
+ * AF_INET6 fragment handling
+ * Copy info from first fragment, to the rest of them.
+ */
+static unsigned int
+ip_vs_preroute_frag6(unsigned int hooknum, struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ struct sk_buff *reasm = skb_nfct_reasm(skb);
+ struct net *net;
+
+ /* Skip if not a "replay" from nf_ct_frag6_output or first fragment.
+ * ipvs_property is set when checking first fragment
+ * in ip_vs_in() and ip_vs_out().
+ */
+ if (reasm)
+ IP_VS_DBG(2, "Fragment recv prop:%d\n", reasm->ipvs_property);
+ if (!reasm || !reasm->ipvs_property)
+ return NF_ACCEPT;
+
+ net = skb_net(skb);
+ if (!net_ipvs(net)->enable)
+ return NF_ACCEPT;
+
+ /* Copy stored fw mark, saved in ip_vs_{in,out} */
+ skb->mark = reasm->mark;
+
+ return NF_ACCEPT;
+}
+
+/*
* AF_INET6 handler in NF_INET_LOCAL_IN chain
* Schedule and forward packets from remote clients
*/
static unsigned int
-ip_vs_remote_request6(const struct nf_hook_ops *ops, struct sk_buff *skb,
+ip_vs_remote_request6(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- return ip_vs_in(ops->hooknum, skb, AF_INET6);
+ return ip_vs_in(hooknum, skb, AF_INET6);
}
/*
@@ -1760,11 +1805,11 @@ ip_vs_remote_request6(const struct nf_hook_ops *ops, struct sk_buff *skb,
* Schedule and forward packets from local clients
*/
static unsigned int
-ip_vs_local_request6(const struct nf_hook_ops *ops, struct sk_buff *skb,
+ip_vs_local_request6(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- return ip_vs_in(ops->hooknum, skb, AF_INET6);
+ return ip_vs_in(hooknum, skb, AF_INET6);
}
#endif
@@ -1780,7 +1825,7 @@ ip_vs_local_request6(const struct nf_hook_ops *ops, struct sk_buff *skb,
* and send them to ip_vs_in_icmp.
*/
static unsigned int
-ip_vs_forward_icmp(const struct nf_hook_ops *ops, struct sk_buff *skb,
+ip_vs_forward_icmp(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
@@ -1797,12 +1842,12 @@ ip_vs_forward_icmp(const struct nf_hook_ops *ops, struct sk_buff *skb,
if (unlikely(sysctl_backup_only(ipvs) || !ipvs->enable))
return NF_ACCEPT;
- return ip_vs_in_icmp(skb, &r, ops->hooknum);
+ return ip_vs_in_icmp(skb, &r, hooknum);
}
#ifdef CONFIG_IP_VS_IPV6
static unsigned int
-ip_vs_forward_icmp_v6(const struct nf_hook_ops *ops, struct sk_buff *skb,
+ip_vs_forward_icmp_v6(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
@@ -1821,7 +1866,7 @@ ip_vs_forward_icmp_v6(const struct nf_hook_ops *ops, struct sk_buff *skb,
if (unlikely(sysctl_backup_only(ipvs) || !ipvs->enable))
return NF_ACCEPT;
- return ip_vs_in_icmp_v6(skb, &r, ops->hooknum, &iphdr);
+ return ip_vs_in_icmp_v6(skb, &r, hooknum, &iphdr);
}
#endif
@@ -1879,6 +1924,14 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
.priority = 100,
},
#ifdef CONFIG_IP_VS_IPV6
+ /* After mangle & nat fetch 2:nd fragment and following */
+ {
+ .hook = ip_vs_preroute_frag6,
+ .owner = THIS_MODULE,
+ .pf = NFPROTO_IPV6,
+ .hooknum = NF_INET_PRE_ROUTING,
+ .priority = NF_IP6_PRI_NAT_DST + 1,
+ },
/* After packet filtering, change source only for VS/NAT */
{
.hook = ip_vs_reply6,
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index 35be035..a3df9bd 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -704,7 +704,7 @@ static void ip_vs_dest_free(struct ip_vs_dest *dest)
__ip_vs_dst_cache_reset(dest);
__ip_vs_svc_put(svc, false);
free_percpu(dest->stats.cpustats);
- ip_vs_dest_put_and_free(dest);
+ kfree(dest);
}
/*
@@ -842,7 +842,7 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest,
struct ip_vs_dest **dest_p)
{
struct ip_vs_dest *dest;
- unsigned int atype, i;
+ unsigned int atype;
EnterFunction(2);
@@ -869,12 +869,6 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest,
if (!dest->stats.cpustats)
goto err_alloc;
- for_each_possible_cpu(i) {
- struct ip_vs_cpu_stats *ip_vs_dest_stats;
- ip_vs_dest_stats = per_cpu_ptr(dest->stats.cpustats, i);
- u64_stats_init(&ip_vs_dest_stats->syncp);
- }
-
dest->af = svc->af;
dest->protocol = svc->protocol;
dest->vaddr = svc->addr;
@@ -1140,7 +1134,7 @@ static int
ip_vs_add_service(struct net *net, struct ip_vs_service_user_kern *u,
struct ip_vs_service **svc_p)
{
- int ret = 0, i;
+ int ret = 0;
struct ip_vs_scheduler *sched = NULL;
struct ip_vs_pe *pe = NULL;
struct ip_vs_service *svc = NULL;
@@ -1190,13 +1184,6 @@ ip_vs_add_service(struct net *net, struct ip_vs_service_user_kern *u,
goto out_err;
}
- for_each_possible_cpu(i) {
- struct ip_vs_cpu_stats *ip_vs_stats;
- ip_vs_stats = per_cpu_ptr(svc->stats.cpustats, i);
- u64_stats_init(&ip_vs_stats->syncp);
- }
-
-
/* I'm the first user of the service */
atomic_set(&svc->refcnt, 0);
@@ -3580,7 +3567,7 @@ out:
}
-static const struct genl_ops ip_vs_genl_ops[] __read_mostly = {
+static struct genl_ops ip_vs_genl_ops[] __read_mostly = {
{
.cmd = IPVS_CMD_NEW_SERVICE,
.flags = GENL_ADMIN_PERM,
@@ -3679,7 +3666,7 @@ static const struct genl_ops ip_vs_genl_ops[] __read_mostly = {
static int __init ip_vs_genl_register(void)
{
return genl_register_family_with_ops(&ip_vs_genl_family,
- ip_vs_genl_ops);
+ ip_vs_genl_ops, ARRAY_SIZE(ip_vs_genl_ops));
}
static void ip_vs_genl_unregister(void)
@@ -3793,7 +3780,7 @@ static struct notifier_block ip_vs_dst_notifier = {
int __net_init ip_vs_control_net_init(struct net *net)
{
- int i, idx;
+ int idx;
struct netns_ipvs *ipvs = net_ipvs(net);
/* Initialize rs_table */
@@ -3812,12 +3799,6 @@ int __net_init ip_vs_control_net_init(struct net *net)
if (!ipvs->tot_stats.cpustats)
return -ENOMEM;
- for_each_possible_cpu(i) {
- struct ip_vs_cpu_stats *ipvs_tot_stats;
- ipvs_tot_stats = per_cpu_ptr(ipvs->tot_stats.cpustats, i);
- u64_stats_init(&ipvs_tot_stats->syncp);
- }
-
spin_lock_init(&ipvs->tot_stats.lock);
proc_create("ip_vs", 0, net->proc_net, &ip_vs_info_fops);
@@ -3839,6 +3820,10 @@ void __net_exit ip_vs_control_net_cleanup(struct net *net)
{
struct netns_ipvs *ipvs = net_ipvs(net);
+ /* Some dest can be in grace period even before cleanup, we have to
+ * defer ip_vs_trash_cleanup until ip_vs_dest_wait_readers is called.
+ */
+ rcu_barrier();
ip_vs_trash_cleanup(net);
ip_vs_stop_estimator(net, &ipvs->tot_stats);
ip_vs_control_net_cleanup_sysctl(net);
diff --git a/net/netfilter/ipvs/ip_vs_lblc.c b/net/netfilter/ipvs/ip_vs_lblc.c
index ca056a3..eff13c9 100644
--- a/net/netfilter/ipvs/ip_vs_lblc.c
+++ b/net/netfilter/ipvs/ip_vs_lblc.c
@@ -136,7 +136,7 @@ static void ip_vs_lblc_rcu_free(struct rcu_head *head)
struct ip_vs_lblc_entry,
rcu_head);
- ip_vs_dest_put_and_free(en->dest);
+ ip_vs_dest_put(en->dest);
kfree(en);
}
diff --git a/net/netfilter/ipvs/ip_vs_lblcr.c b/net/netfilter/ipvs/ip_vs_lblcr.c
index 3f21a2f..0b85500 100644
--- a/net/netfilter/ipvs/ip_vs_lblcr.c
+++ b/net/netfilter/ipvs/ip_vs_lblcr.c
@@ -130,7 +130,7 @@ static void ip_vs_lblcr_elem_rcu_free(struct rcu_head *head)
struct ip_vs_dest_set_elem *e;
e = container_of(head, struct ip_vs_dest_set_elem, rcu_head);
- ip_vs_dest_put_and_free(e->dest);
+ ip_vs_dest_put(e->dest);
kfree(e);
}
diff --git a/net/netfilter/ipvs/ip_vs_pe_sip.c b/net/netfilter/ipvs/ip_vs_pe_sip.c
index bed5f70..9ef22bd 100644
--- a/net/netfilter/ipvs/ip_vs_pe_sip.c
+++ b/net/netfilter/ipvs/ip_vs_pe_sip.c
@@ -65,6 +65,7 @@ static int get_callid(const char *dptr, unsigned int dataoff,
static int
ip_vs_sip_fill_param(struct ip_vs_conn_param *p, struct sk_buff *skb)
{
+ struct sk_buff *reasm = skb_nfct_reasm(skb);
struct ip_vs_iphdr iph;
unsigned int dataoff, datalen, matchoff, matchlen;
const char *dptr;
@@ -78,10 +79,15 @@ ip_vs_sip_fill_param(struct ip_vs_conn_param *p, struct sk_buff *skb)
/* todo: IPv6 fragments:
* I think this only should be done for the first fragment. /HS
*/
- dataoff = iph.len + sizeof(struct udphdr);
+ if (reasm) {
+ skb = reasm;
+ dataoff = iph.thoff_reasm + sizeof(struct udphdr);
+ } else
+ dataoff = iph.len + sizeof(struct udphdr);
if (dataoff >= skb->len)
return -EINVAL;
+ /* todo: Check if this will mess-up the reasm skb !!! /HS */
retc = skb_linearize(skb);
if (retc < 0)
return retc;
diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c
index 2f7ea75..23e596e 100644
--- a/net/netfilter/ipvs/ip_vs_proto_sctp.c
+++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c
@@ -20,18 +20,13 @@ sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd,
sctp_sctphdr_t *sh, _sctph;
sh = skb_header_pointer(skb, iph->len, sizeof(_sctph), &_sctph);
- if (sh == NULL) {
- *verdict = NF_DROP;
+ if (sh == NULL)
return 0;
- }
sch = skb_header_pointer(skb, iph->len + sizeof(sctp_sctphdr_t),
sizeof(_schunkh), &_schunkh);
- if (sch == NULL) {
- *verdict = NF_DROP;
+ if (sch == NULL)
return 0;
- }
-
net = skb_net(skb);
ipvs = net_ipvs(net);
rcu_read_lock();
@@ -81,7 +76,6 @@ sctp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
{
sctp_sctphdr_t *sctph;
unsigned int sctphoff = iph->len;
- bool payload_csum = false;
#ifdef CONFIG_IP_VS_IPV6
if (cp->af == AF_INET6 && iph->fragoffs)
@@ -93,31 +87,19 @@ sctp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
return 0;
if (unlikely(cp->app != NULL)) {
- int ret;
-
/* Some checks before mangling */
if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
return 0;
/* Call application helper if needed */
- ret = ip_vs_app_pkt_out(cp, skb);
- if (ret == 0)
+ if (!ip_vs_app_pkt_out(cp, skb))
return 0;
- /* ret=2: csum update is needed after payload mangling */
- if (ret == 2)
- payload_csum = true;
}
sctph = (void *) skb_network_header(skb) + sctphoff;
+ sctph->source = cp->vport;
- /* Only update csum if we really have to */
- if (sctph->source != cp->vport || payload_csum ||
- skb->ip_summed == CHECKSUM_PARTIAL) {
- sctph->source = cp->vport;
- sctp_nat_csum(skb, sctph, sctphoff);
- } else {
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- }
+ sctp_nat_csum(skb, sctph, sctphoff);
return 1;
}
@@ -128,7 +110,6 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
{
sctp_sctphdr_t *sctph;
unsigned int sctphoff = iph->len;
- bool payload_csum = false;
#ifdef CONFIG_IP_VS_IPV6
if (cp->af == AF_INET6 && iph->fragoffs)
@@ -140,32 +121,19 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
return 0;
if (unlikely(cp->app != NULL)) {
- int ret;
-
/* Some checks before mangling */
if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
return 0;
/* Call application helper if needed */
- ret = ip_vs_app_pkt_in(cp, skb);
- if (ret == 0)
+ if (!ip_vs_app_pkt_in(cp, skb))
return 0;
- /* ret=2: csum update is needed after payload mangling */
- if (ret == 2)
- payload_csum = true;
}
sctph = (void *) skb_network_header(skb) + sctphoff;
+ sctph->dest = cp->dport;
- /* Only update csum if we really have to */
- if (sctph->dest != cp->dport || payload_csum ||
- (skb->ip_summed == CHECKSUM_PARTIAL &&
- !(skb_dst(skb)->dev->features & NETIF_F_SCTP_CSUM))) {
- sctph->dest = cp->dport;
- sctp_nat_csum(skb, sctph, sctphoff);
- } else if (skb->ip_summed != CHECKSUM_PARTIAL) {
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- }
+ sctp_nat_csum(skb, sctph, sctphoff);
return 1;
}
diff --git a/net/netfilter/ipvs/ip_vs_sh.c b/net/netfilter/ipvs/ip_vs_sh.c
index cc65b2f..3588fae 100644
--- a/net/netfilter/ipvs/ip_vs_sh.c
+++ b/net/netfilter/ipvs/ip_vs_sh.c
@@ -115,46 +115,27 @@ ip_vs_sh_get(struct ip_vs_service *svc, struct ip_vs_sh_state *s,
}
-/* As ip_vs_sh_get, but with fallback if selected server is unavailable
- *
- * The fallback strategy loops around the table starting from a "random"
- * point (in fact, it is chosen to be the original hash value to make the
- * algorithm deterministic) to find a new server.
- */
+/* As ip_vs_sh_get, but with fallback if selected server is unavailable */
static inline struct ip_vs_dest *
ip_vs_sh_get_fallback(struct ip_vs_service *svc, struct ip_vs_sh_state *s,
const union nf_inet_addr *addr, __be16 port)
{
- unsigned int offset, roffset;
- unsigned int hash, ihash;
+ unsigned int offset;
+ unsigned int hash;
struct ip_vs_dest *dest;
- /* first try the dest it's supposed to go to */
- ihash = ip_vs_sh_hashkey(svc->af, addr, port, 0);
- dest = rcu_dereference(s->buckets[ihash].dest);
- if (!dest)
- return NULL;
- if (!is_unavailable(dest))
- return dest;
-
- IP_VS_DBG_BUF(6, "SH: selected unavailable server %s:%d, reselecting",
- IP_VS_DBG_ADDR(svc->af, &dest->addr), ntohs(dest->port));
-
- /* if the original dest is unavailable, loop around the table
- * starting from ihash to find a new dest
- */
for (offset = 0; offset < IP_VS_SH_TAB_SIZE; offset++) {
- roffset = (offset + ihash) % IP_VS_SH_TAB_SIZE;
- hash = ip_vs_sh_hashkey(svc->af, addr, port, roffset);
+ hash = ip_vs_sh_hashkey(svc->af, addr, port, offset);
dest = rcu_dereference(s->buckets[hash].dest);
if (!dest)
break;
- if (!is_unavailable(dest))
+ if (is_unavailable(dest))
+ IP_VS_DBG_BUF(6, "SH: selected unavailable server "
+ "%s:%d (offset %d)",
+ IP_VS_DBG_ADDR(svc->af, &dest->addr),
+ ntohs(dest->port), offset);
+ else
return dest;
- IP_VS_DBG_BUF(6, "SH: selected unavailable "
- "server %s:%d (offset %d), reselecting",
- IP_VS_DBG_ADDR(svc->af, &dest->addr),
- ntohs(dest->port), roffset);
}
return NULL;
diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c
index f63c238..f448471 100644
--- a/net/netfilter/ipvs/ip_vs_sync.c
+++ b/net/netfilter/ipvs/ip_vs_sync.c
@@ -1637,9 +1637,12 @@ static int sync_thread_master(void *data)
continue;
}
while (ip_vs_send_sync_msg(tinfo->sock, sb->mesg) < 0) {
- int ret = __wait_event_interruptible(*sk_sleep(sk),
+ int ret = 0;
+
+ __wait_event_interruptible(*sk_sleep(sk),
sock_writeable(sk) ||
- kthread_should_stop());
+ kthread_should_stop(),
+ ret);
if (unlikely(kthread_should_stop()))
goto done;
}
diff --git a/net/netfilter/nf_conntrack_acct.c b/net/netfilter/nf_conntrack_acct.c
index a4b5e2a..2d3030a 100644
--- a/net/netfilter/nf_conntrack_acct.c
+++ b/net/netfilter/nf_conntrack_acct.c
@@ -39,23 +39,21 @@ static struct ctl_table acct_sysctl_table[] = {
unsigned int
seq_print_acct(struct seq_file *s, const struct nf_conn *ct, int dir)
{
- struct nf_conn_acct *acct;
- struct nf_conn_counter *counter;
+ struct nf_conn_counter *acct;
acct = nf_conn_acct_find(ct);
if (!acct)
return 0;
- counter = acct->counter;
return seq_printf(s, "packets=%llu bytes=%llu ",
- (unsigned long long)atomic64_read(&counter[dir].packets),
- (unsigned long long)atomic64_read(&counter[dir].bytes));
+ (unsigned long long)atomic64_read(&acct[dir].packets),
+ (unsigned long long)atomic64_read(&acct[dir].bytes));
};
EXPORT_SYMBOL_GPL(seq_print_acct);
static struct nf_ct_ext_type acct_extend __read_mostly = {
- .len = sizeof(struct nf_conn_acct),
- .align = __alignof__(struct nf_conn_acct),
+ .len = sizeof(struct nf_conn_counter[IP_CT_DIR_MAX]),
+ .align = __alignof__(struct nf_conn_counter[IP_CT_DIR_MAX]),
.id = NF_CT_EXT_ACCT,
};
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 43549eb..5d892fe 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -764,10 +764,9 @@ void nf_conntrack_free(struct nf_conn *ct)
struct net *net = nf_ct_net(ct);
nf_ct_ext_destroy(ct);
+ atomic_dec(&net->ct.count);
nf_ct_ext_free(ct);
kmem_cache_free(net->ct.nf_conntrack_cachep, ct);
- smp_mb__before_atomic_dec();
- atomic_dec(&net->ct.count);
}
EXPORT_SYMBOL_GPL(nf_conntrack_free);
@@ -1110,14 +1109,12 @@ void __nf_ct_refresh_acct(struct nf_conn *ct,
acct:
if (do_acct) {
- struct nf_conn_acct *acct;
+ struct nf_conn_counter *acct;
acct = nf_conn_acct_find(ct);
if (acct) {
- struct nf_conn_counter *counter = acct->counter;
-
- atomic64_inc(&counter[CTINFO2DIR(ctinfo)].packets);
- atomic64_add(skb->len, &counter[CTINFO2DIR(ctinfo)].bytes);
+ atomic64_inc(&acct[CTINFO2DIR(ctinfo)].packets);
+ atomic64_add(skb->len, &acct[CTINFO2DIR(ctinfo)].bytes);
}
}
}
@@ -1129,15 +1126,13 @@ bool __nf_ct_kill_acct(struct nf_conn *ct,
int do_acct)
{
if (do_acct) {
- struct nf_conn_acct *acct;
+ struct nf_conn_counter *acct;
acct = nf_conn_acct_find(ct);
if (acct) {
- struct nf_conn_counter *counter = acct->counter;
-
- atomic64_inc(&counter[CTINFO2DIR(ctinfo)].packets);
+ atomic64_inc(&acct[CTINFO2DIR(ctinfo)].packets);
atomic64_add(skb->len - skb_network_offset(skb),
- &counter[CTINFO2DIR(ctinfo)].bytes);
+ &acct[CTINFO2DIR(ctinfo)].bytes);
}
}
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 08870b8..eea936b 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -211,23 +211,13 @@ nla_put_failure:
}
static int
-dump_counters(struct sk_buff *skb, struct nf_conn_acct *acct,
- enum ip_conntrack_dir dir, int type)
+dump_counters(struct sk_buff *skb, u64 pkts, u64 bytes,
+ enum ip_conntrack_dir dir)
{
- enum ctattr_type attr = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG;
- struct nf_conn_counter *counter = acct->counter;
+ enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG;
struct nlattr *nest_count;
- u64 pkts, bytes;
- if (type == IPCTNL_MSG_CT_GET_CTRZERO) {
- pkts = atomic64_xchg(&counter[dir].packets, 0);
- bytes = atomic64_xchg(&counter[dir].bytes, 0);
- } else {
- pkts = atomic64_read(&counter[dir].packets);
- bytes = atomic64_read(&counter[dir].bytes);
- }
-
- nest_count = nla_nest_start(skb, attr | NLA_F_NESTED);
+ nest_count = nla_nest_start(skb, type | NLA_F_NESTED);
if (!nest_count)
goto nla_put_failure;
@@ -244,19 +234,24 @@ nla_put_failure:
}
static int
-ctnetlink_dump_acct(struct sk_buff *skb, const struct nf_conn *ct, int type)
+ctnetlink_dump_counters(struct sk_buff *skb, const struct nf_conn *ct,
+ enum ip_conntrack_dir dir, int type)
{
- struct nf_conn_acct *acct = nf_conn_acct_find(ct);
+ struct nf_conn_counter *acct;
+ u64 pkts, bytes;
+ acct = nf_conn_acct_find(ct);
if (!acct)
return 0;
- if (dump_counters(skb, acct, IP_CT_DIR_ORIGINAL, type) < 0)
- return -1;
- if (dump_counters(skb, acct, IP_CT_DIR_REPLY, type) < 0)
- return -1;
-
- return 0;
+ if (type == IPCTNL_MSG_CT_GET_CTRZERO) {
+ pkts = atomic64_xchg(&acct[dir].packets, 0);
+ bytes = atomic64_xchg(&acct[dir].bytes, 0);
+ } else {
+ pkts = atomic64_read(&acct[dir].packets);
+ bytes = atomic64_read(&acct[dir].bytes);
+ }
+ return dump_counters(skb, pkts, bytes, dir);
}
static int
@@ -493,7 +488,8 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
if (ctnetlink_dump_status(skb, ct) < 0 ||
ctnetlink_dump_timeout(skb, ct) < 0 ||
- ctnetlink_dump_acct(skb, ct, type) < 0 ||
+ ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL, type) < 0 ||
+ ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY, type) < 0 ||
ctnetlink_dump_timestamp(skb, ct) < 0 ||
ctnetlink_dump_protoinfo(skb, ct) < 0 ||
ctnetlink_dump_helpinfo(skb, ct) < 0 ||
@@ -534,7 +530,7 @@ ctnetlink_proto_size(const struct nf_conn *ct)
}
static inline size_t
-ctnetlink_acct_size(const struct nf_conn *ct)
+ctnetlink_counters_size(const struct nf_conn *ct)
{
if (!nf_ct_ext_exist(ct, NF_CT_EXT_ACCT))
return 0;
@@ -583,7 +579,7 @@ ctnetlink_nlmsg_size(const struct nf_conn *ct)
+ 3 * nla_total_size(sizeof(u_int8_t)) /* CTA_PROTO_NUM */
+ nla_total_size(sizeof(u_int32_t)) /* CTA_ID */
+ nla_total_size(sizeof(u_int32_t)) /* CTA_STATUS */
- + ctnetlink_acct_size(ct)
+ + ctnetlink_counters_size(ct)
+ ctnetlink_timestamp_size(ct)
+ nla_total_size(sizeof(u_int32_t)) /* CTA_TIMEOUT */
+ nla_total_size(0) /* CTA_PROTOINFO */
@@ -677,7 +673,10 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
goto nla_put_failure;
if (events & (1 << IPCT_DESTROY)) {
- if (ctnetlink_dump_acct(skb, ct, type) < 0 ||
+ if (ctnetlink_dump_counters(skb, ct,
+ IP_CT_DIR_ORIGINAL, type) < 0 ||
+ ctnetlink_dump_counters(skb, ct,
+ IP_CT_DIR_REPLY, type) < 0 ||
ctnetlink_dump_timestamp(skb, ct) < 0)
goto nla_put_failure;
} else {
diff --git a/net/netfilter/nf_conntrack_seqadj.c b/net/netfilter/nf_conntrack_seqadj.c
index 17c1bcb..5f9bfd0 100644
--- a/net/netfilter/nf_conntrack_seqadj.c
+++ b/net/netfilter/nf_conntrack_seqadj.c
@@ -41,8 +41,8 @@ int nf_ct_seqadj_set(struct nf_conn *ct, enum ip_conntrack_info ctinfo,
spin_lock_bh(&ct->lock);
this_way = &seqadj->seq[dir];
if (this_way->offset_before == this_way->offset_after ||
- before(this_way->correction_pos, ntohl(seq))) {
- this_way->correction_pos = ntohl(seq);
+ before(this_way->correction_pos, seq)) {
+ this_way->correction_pos = seq;
this_way->offset_before = this_way->offset_after;
this_way->offset_after += off;
}
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 466410e..e0c4373 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -52,8 +52,66 @@ module_param(sip_direct_media, int, 0600);
MODULE_PARM_DESC(sip_direct_media, "Expect Media streams between signalling "
"endpoints only (default 1)");
-const struct nf_nat_sip_hooks *nf_nat_sip_hooks;
-EXPORT_SYMBOL_GPL(nf_nat_sip_hooks);
+unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, unsigned int protoff,
+ unsigned int dataoff, const char **dptr,
+ unsigned int *datalen) __read_mostly;
+EXPORT_SYMBOL_GPL(nf_nat_sip_hook);
+
+void (*nf_nat_sip_seq_adjust_hook)(struct sk_buff *skb, unsigned int protoff,
+ s16 off) __read_mostly;
+EXPORT_SYMBOL_GPL(nf_nat_sip_seq_adjust_hook);
+
+unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb,
+ unsigned int protoff,
+ unsigned int dataoff,
+ const char **dptr,
+ unsigned int *datalen,
+ struct nf_conntrack_expect *exp,
+ unsigned int matchoff,
+ unsigned int matchlen) __read_mostly;
+EXPORT_SYMBOL_GPL(nf_nat_sip_expect_hook);
+
+unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb, unsigned int protoff,
+ unsigned int dataoff,
+ const char **dptr,
+ unsigned int *datalen,
+ unsigned int sdpoff,
+ enum sdp_header_types type,
+ enum sdp_header_types term,
+ const union nf_inet_addr *addr)
+ __read_mostly;
+EXPORT_SYMBOL_GPL(nf_nat_sdp_addr_hook);
+
+unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb, unsigned int protoff,
+ unsigned int dataoff,
+ const char **dptr,
+ unsigned int *datalen,
+ unsigned int matchoff,
+ unsigned int matchlen,
+ u_int16_t port) __read_mostly;
+EXPORT_SYMBOL_GPL(nf_nat_sdp_port_hook);
+
+unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb,
+ unsigned int protoff,
+ unsigned int dataoff,
+ const char **dptr,
+ unsigned int *datalen,
+ unsigned int sdpoff,
+ const union nf_inet_addr *addr)
+ __read_mostly;
+EXPORT_SYMBOL_GPL(nf_nat_sdp_session_hook);
+
+unsigned int (*nf_nat_sdp_media_hook)(struct sk_buff *skb, unsigned int protoff,
+ unsigned int dataoff,
+ const char **dptr,
+ unsigned int *datalen,
+ struct nf_conntrack_expect *rtp_exp,
+ struct nf_conntrack_expect *rtcp_exp,
+ unsigned int mediaoff,
+ unsigned int medialen,
+ union nf_inet_addr *rtp_addr)
+ __read_mostly;
+EXPORT_SYMBOL_GPL(nf_nat_sdp_media_hook);
static int string_len(const struct nf_conn *ct, const char *dptr,
const char *limit, int *shift)
@@ -856,7 +914,8 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
int direct_rtp = 0, skip_expect = 0, ret = NF_DROP;
u_int16_t base_port;
__be16 rtp_port, rtcp_port;
- const struct nf_nat_sip_hooks *hooks;
+ typeof(nf_nat_sdp_port_hook) nf_nat_sdp_port;
+ typeof(nf_nat_sdp_media_hook) nf_nat_sdp_media;
saddr = NULL;
if (sip_direct_media) {
@@ -907,23 +966,22 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
#endif
skip_expect = 1;
} while (!skip_expect);
+ rcu_read_unlock();
base_port = ntohs(tuple.dst.u.udp.port) & ~1;
rtp_port = htons(base_port);
rtcp_port = htons(base_port + 1);
if (direct_rtp) {
- hooks = rcu_dereference(nf_nat_sip_hooks);
- if (hooks &&
- !hooks->sdp_port(skb, protoff, dataoff, dptr, datalen,
+ nf_nat_sdp_port = rcu_dereference(nf_nat_sdp_port_hook);
+ if (nf_nat_sdp_port &&
+ !nf_nat_sdp_port(skb, protoff, dataoff, dptr, datalen,
mediaoff, medialen, ntohs(rtp_port)))
goto err1;
}
- if (skip_expect) {
- rcu_read_unlock();
+ if (skip_expect)
return NF_ACCEPT;
- }
rtp_exp = nf_ct_expect_alloc(ct);
if (rtp_exp == NULL)
@@ -937,10 +995,10 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
nf_ct_expect_init(rtcp_exp, class, nf_ct_l3num(ct), saddr, daddr,
IPPROTO_UDP, NULL, &rtcp_port);
- hooks = rcu_dereference(nf_nat_sip_hooks);
- if (hooks && ct->status & IPS_NAT_MASK && !direct_rtp)
- ret = hooks->sdp_media(skb, protoff, dataoff, dptr,
- datalen, rtp_exp, rtcp_exp,
+ nf_nat_sdp_media = rcu_dereference(nf_nat_sdp_media_hook);
+ if (nf_nat_sdp_media && ct->status & IPS_NAT_MASK && !direct_rtp)
+ ret = nf_nat_sdp_media(skb, protoff, dataoff, dptr, datalen,
+ rtp_exp, rtcp_exp,
mediaoff, medialen, daddr);
else {
if (nf_ct_expect_related(rtp_exp) == 0) {
@@ -954,7 +1012,6 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
err2:
nf_ct_expect_put(rtp_exp);
err1:
- rcu_read_unlock();
return ret;
}
@@ -994,12 +1051,13 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff,
unsigned int caddr_len, maddr_len;
unsigned int i;
union nf_inet_addr caddr, maddr, rtp_addr;
- const struct nf_nat_sip_hooks *hooks;
unsigned int port;
const struct sdp_media_type *t;
int ret = NF_ACCEPT;
+ typeof(nf_nat_sdp_addr_hook) nf_nat_sdp_addr;
+ typeof(nf_nat_sdp_session_hook) nf_nat_sdp_session;
- hooks = rcu_dereference(nf_nat_sip_hooks);
+ nf_nat_sdp_addr = rcu_dereference(nf_nat_sdp_addr_hook);
/* Find beginning of session description */
if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen,
@@ -1067,11 +1125,10 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff,
}
/* Update media connection address if present */
- if (maddr_len && hooks && ct->status & IPS_NAT_MASK) {
- ret = hooks->sdp_addr(skb, protoff, dataoff,
+ if (maddr_len && nf_nat_sdp_addr && ct->status & IPS_NAT_MASK) {
+ ret = nf_nat_sdp_addr(skb, protoff, dataoff,
dptr, datalen, mediaoff,
- SDP_HDR_CONNECTION,
- SDP_HDR_MEDIA,
+ SDP_HDR_CONNECTION, SDP_HDR_MEDIA,
&rtp_addr);
if (ret != NF_ACCEPT) {
nf_ct_helper_log(skb, ct, "cannot mangle SDP");
@@ -1082,11 +1139,10 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff,
}
/* Update session connection and owner addresses */
- hooks = rcu_dereference(nf_nat_sip_hooks);
- if (hooks && ct->status & IPS_NAT_MASK)
- ret = hooks->sdp_session(skb, protoff, dataoff,
- dptr, datalen, sdpoff,
- &rtp_addr);
+ nf_nat_sdp_session = rcu_dereference(nf_nat_sdp_session_hook);
+ if (nf_nat_sdp_session && ct->status & IPS_NAT_MASK)
+ ret = nf_nat_sdp_session(skb, protoff, dataoff,
+ dptr, datalen, sdpoff, &rtp_addr);
return ret;
}
@@ -1186,11 +1242,11 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff,
unsigned int matchoff, matchlen;
struct nf_conntrack_expect *exp;
union nf_inet_addr *saddr, daddr;
- const struct nf_nat_sip_hooks *hooks;
__be16 port;
u8 proto;
unsigned int expires = 0;
int ret;
+ typeof(nf_nat_sip_expect_hook) nf_nat_sip_expect;
/* Expected connections can not register again. */
if (ct->status & IPS_EXPECTED)
@@ -1253,10 +1309,10 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff,
exp->helper = nfct_help(ct)->helper;
exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE;
- hooks = rcu_dereference(nf_nat_sip_hooks);
- if (hooks && ct->status & IPS_NAT_MASK)
- ret = hooks->expect(skb, protoff, dataoff, dptr, datalen,
- exp, matchoff, matchlen);
+ nf_nat_sip_expect = rcu_dereference(nf_nat_sip_expect_hook);
+ if (nf_nat_sip_expect && ct->status & IPS_NAT_MASK)
+ ret = nf_nat_sip_expect(skb, protoff, dataoff, dptr, datalen,
+ exp, matchoff, matchlen);
else {
if (nf_ct_expect_related(exp) != 0) {
nf_ct_helper_log(skb, ct, "cannot add expectation");
@@ -1459,7 +1515,7 @@ static int process_sip_msg(struct sk_buff *skb, struct nf_conn *ct,
unsigned int protoff, unsigned int dataoff,
const char **dptr, unsigned int *datalen)
{
- const struct nf_nat_sip_hooks *hooks;
+ typeof(nf_nat_sip_hook) nf_nat_sip;
int ret;
if (strnicmp(*dptr, "SIP/2.0 ", strlen("SIP/2.0 ")) != 0)
@@ -1468,9 +1524,9 @@ static int process_sip_msg(struct sk_buff *skb, struct nf_conn *ct,
ret = process_sip_response(skb, protoff, dataoff, dptr, datalen);
if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) {
- hooks = rcu_dereference(nf_nat_sip_hooks);
- if (hooks && !hooks->msg(skb, protoff, dataoff,
- dptr, datalen)) {
+ nf_nat_sip = rcu_dereference(nf_nat_sip_hook);
+ if (nf_nat_sip && !nf_nat_sip(skb, protoff, dataoff,
+ dptr, datalen)) {
nf_ct_helper_log(skb, ct, "cannot NAT SIP message");
ret = NF_DROP;
}
@@ -1490,6 +1546,7 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff,
s16 diff, tdiff = 0;
int ret = NF_ACCEPT;
bool term;
+ typeof(nf_nat_sip_seq_adjust_hook) nf_nat_sip_seq_adjust;
if (ctinfo != IP_CT_ESTABLISHED &&
ctinfo != IP_CT_ESTABLISHED_REPLY)
@@ -1553,11 +1610,9 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff,
}
if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) {
- const struct nf_nat_sip_hooks *hooks;
-
- hooks = rcu_dereference(nf_nat_sip_hooks);
- if (hooks)
- hooks->seq_adjust(skb, protoff, tdiff);
+ nf_nat_sip_seq_adjust = rcu_dereference(nf_nat_sip_seq_adjust_hook);
+ if (nf_nat_sip_seq_adjust)
+ nf_nat_sip_seq_adjust(skb, protoff, tdiff);
}
return ret;
diff --git a/net/netfilter/nf_internals.h b/net/netfilter/nf_internals.h
index 61a3c92..3deec99 100644
--- a/net/netfilter/nf_internals.h
+++ b/net/netfilter/nf_internals.h
@@ -13,20 +13,26 @@
/* core.c */
-unsigned int nf_iterate(struct list_head *head, struct sk_buff *skb,
- unsigned int hook, const struct net_device *indev,
- const struct net_device *outdev,
- struct nf_hook_ops **elemp,
- int (*okfn)(struct sk_buff *), int hook_thresh);
+extern unsigned int nf_iterate(struct list_head *head,
+ struct sk_buff *skb,
+ unsigned int hook,
+ const struct net_device *indev,
+ const struct net_device *outdev,
+ struct nf_hook_ops **elemp,
+ int (*okfn)(struct sk_buff *),
+ int hook_thresh);
/* nf_queue.c */
-int nf_queue(struct sk_buff *skb, struct nf_hook_ops *elem, u_int8_t pf,
- unsigned int hook, struct net_device *indev,
- struct net_device *outdev, int (*okfn)(struct sk_buff *),
- unsigned int queuenum);
-int __init netfilter_queue_init(void);
+extern int nf_queue(struct sk_buff *skb,
+ struct nf_hook_ops *elem,
+ u_int8_t pf, unsigned int hook,
+ struct net_device *indev,
+ struct net_device *outdev,
+ int (*okfn)(struct sk_buff *),
+ unsigned int queuenum);
+extern int __init netfilter_queue_init(void);
/* nf_log.c */
-int __init netfilter_log_init(void);
+extern int __init netfilter_log_init(void);
#endif
diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c
index 63a8154..6f0f4f7 100644
--- a/net/netfilter/nf_nat_core.c
+++ b/net/netfilter/nf_nat_core.c
@@ -432,26 +432,6 @@ nf_nat_setup_info(struct nf_conn *ct,
}
EXPORT_SYMBOL(nf_nat_setup_info);
-unsigned int
-nf_nat_alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
-{
- /* Force range to this IP; let proto decide mapping for
- * per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED).
- * Use reply in case it's already been mangled (eg local packet).
- */
- union nf_inet_addr ip =
- (HOOK2MANIP(hooknum) == NF_NAT_MANIP_SRC ?
- ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3 :
- ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3);
- struct nf_nat_range range = {
- .flags = NF_NAT_RANGE_MAP_IPS,
- .min_addr = ip,
- .max_addr = ip,
- };
- return nf_nat_setup_info(ct, &range, HOOK2MANIP(hooknum));
-}
-EXPORT_SYMBOL_GPL(nf_nat_alloc_null_binding);
-
/* Do packet manipulations according to nf_nat_setup_info. */
unsigned int nf_nat_packet(struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c
index b4d691d..f979040 100644
--- a/net/netfilter/nf_nat_sip.c
+++ b/net/netfilter/nf_nat_sip.c
@@ -625,26 +625,33 @@ static struct nf_ct_helper_expectfn sip_nat = {
static void __exit nf_nat_sip_fini(void)
{
- RCU_INIT_POINTER(nf_nat_sip_hooks, NULL);
-
+ RCU_INIT_POINTER(nf_nat_sip_hook, NULL);
+ RCU_INIT_POINTER(nf_nat_sip_seq_adjust_hook, NULL);
+ RCU_INIT_POINTER(nf_nat_sip_expect_hook, NULL);
+ RCU_INIT_POINTER(nf_nat_sdp_addr_hook, NULL);
+ RCU_INIT_POINTER(nf_nat_sdp_port_hook, NULL);
+ RCU_INIT_POINTER(nf_nat_sdp_session_hook, NULL);
+ RCU_INIT_POINTER(nf_nat_sdp_media_hook, NULL);
nf_ct_helper_expectfn_unregister(&sip_nat);
synchronize_rcu();
}
-static const struct nf_nat_sip_hooks sip_hooks = {
- .msg = nf_nat_sip,
- .seq_adjust = nf_nat_sip_seq_adjust,
- .expect = nf_nat_sip_expect,
- .sdp_addr = nf_nat_sdp_addr,
- .sdp_port = nf_nat_sdp_port,
- .sdp_session = nf_nat_sdp_session,
- .sdp_media = nf_nat_sdp_media,
-};
-
static int __init nf_nat_sip_init(void)
{
- BUG_ON(nf_nat_sip_hooks != NULL);
- RCU_INIT_POINTER(nf_nat_sip_hooks, &sip_hooks);
+ BUG_ON(nf_nat_sip_hook != NULL);
+ BUG_ON(nf_nat_sip_seq_adjust_hook != NULL);
+ BUG_ON(nf_nat_sip_expect_hook != NULL);
+ BUG_ON(nf_nat_sdp_addr_hook != NULL);
+ BUG_ON(nf_nat_sdp_port_hook != NULL);
+ BUG_ON(nf_nat_sdp_session_hook != NULL);
+ BUG_ON(nf_nat_sdp_media_hook != NULL);
+ RCU_INIT_POINTER(nf_nat_sip_hook, nf_nat_sip);
+ RCU_INIT_POINTER(nf_nat_sip_seq_adjust_hook, nf_nat_sip_seq_adjust);
+ RCU_INIT_POINTER(nf_nat_sip_expect_hook, nf_nat_sip_expect);
+ RCU_INIT_POINTER(nf_nat_sdp_addr_hook, nf_nat_sdp_addr);
+ RCU_INIT_POINTER(nf_nat_sdp_port_hook, nf_nat_sdp_port);
+ RCU_INIT_POINTER(nf_nat_sdp_session_hook, nf_nat_sdp_session);
+ RCU_INIT_POINTER(nf_nat_sdp_media_hook, nf_nat_sdp_media);
nf_ct_helper_expectfn_register(&sip_nat);
return 0;
}
diff --git a/net/netfilter/nf_synproxy_core.c b/net/netfilter/nf_synproxy_core.c
index 9858e3e..cdf4567 100644
--- a/net/netfilter/nf_synproxy_core.c
+++ b/net/netfilter/nf_synproxy_core.c
@@ -151,10 +151,9 @@ void synproxy_init_timestamp_cookie(const struct xt_synproxy_info *info,
opts->tsecr = opts->tsval;
opts->tsval = tcp_time_stamp & ~0x3f;
- if (opts->options & XT_SYNPROXY_OPT_WSCALE) {
- opts->tsval |= opts->wscale;
- opts->wscale = info->wscale;
- } else
+ if (opts->options & XT_SYNPROXY_OPT_WSCALE)
+ opts->tsval |= info->wscale;
+ else
opts->tsval |= 0xf;
if (opts->options & XT_SYNPROXY_OPT_SACK_PERM)
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
deleted file mode 100644
index dcddc49..0000000
--- a/net/netfilter/nf_tables_api.c
+++ /dev/null
@@ -1,3275 +0,0 @@
-/*
- * Copyright (c) 2007-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/module.h>
-#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/skbuff.h>
-#include <linux/netlink.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter/nfnetlink.h>
-#include <linux/netfilter/nf_tables.h>
-#include <net/netfilter/nf_tables_core.h>
-#include <net/netfilter/nf_tables.h>
-#include <net/net_namespace.h>
-#include <net/sock.h>
-
-static LIST_HEAD(nf_tables_expressions);
-
-/**
- * nft_register_afinfo - register nf_tables address family info
- *
- * @afi: address family info to register
- *
- * Register the address family for use with nf_tables. Returns zero on
- * success or a negative errno code otherwise.
- */
-int nft_register_afinfo(struct net *net, struct nft_af_info *afi)
-{
- INIT_LIST_HEAD(&afi->tables);
- nfnl_lock(NFNL_SUBSYS_NFTABLES);
- list_add_tail(&afi->list, &net->nft.af_info);
- nfnl_unlock(NFNL_SUBSYS_NFTABLES);
- return 0;
-}
-EXPORT_SYMBOL_GPL(nft_register_afinfo);
-
-/**
- * nft_unregister_afinfo - unregister nf_tables address family info
- *
- * @afi: address family info to unregister
- *
- * Unregister the address family for use with nf_tables.
- */
-void nft_unregister_afinfo(struct nft_af_info *afi)
-{
- nfnl_lock(NFNL_SUBSYS_NFTABLES);
- list_del(&afi->list);
- nfnl_unlock(NFNL_SUBSYS_NFTABLES);
-}
-EXPORT_SYMBOL_GPL(nft_unregister_afinfo);
-
-static struct nft_af_info *nft_afinfo_lookup(struct net *net, int family)
-{
- struct nft_af_info *afi;
-
- list_for_each_entry(afi, &net->nft.af_info, list) {
- if (afi->family == family)
- return afi;
- }
- return NULL;
-}
-
-static struct nft_af_info *
-nf_tables_afinfo_lookup(struct net *net, int family, bool autoload)
-{
- struct nft_af_info *afi;
-
- afi = nft_afinfo_lookup(net, family);
- if (afi != NULL)
- return afi;
-#ifdef CONFIG_MODULES
- if (autoload) {
- nfnl_unlock(NFNL_SUBSYS_NFTABLES);
- request_module("nft-afinfo-%u", family);
- nfnl_lock(NFNL_SUBSYS_NFTABLES);
- afi = nft_afinfo_lookup(net, family);
- if (afi != NULL)
- return ERR_PTR(-EAGAIN);
- }
-#endif
- return ERR_PTR(-EAFNOSUPPORT);
-}
-
-/*
- * Tables
- */
-
-static struct nft_table *nft_table_lookup(const struct nft_af_info *afi,
- const struct nlattr *nla)
-{
- struct nft_table *table;
-
- list_for_each_entry(table, &afi->tables, list) {
- if (!nla_strcmp(nla, table->name))
- return table;
- }
- return NULL;
-}
-
-static struct nft_table *nf_tables_table_lookup(const struct nft_af_info *afi,
- const struct nlattr *nla)
-{
- struct nft_table *table;
-
- if (nla == NULL)
- return ERR_PTR(-EINVAL);
-
- table = nft_table_lookup(afi, nla);
- if (table != NULL)
- return table;
-
- return ERR_PTR(-ENOENT);
-}
-
-static inline u64 nf_tables_alloc_handle(struct nft_table *table)
-{
- return ++table->hgenerator;
-}
-
-static struct nf_chain_type *chain_type[AF_MAX][NFT_CHAIN_T_MAX];
-
-static int __nf_tables_chain_type_lookup(int family, const struct nlattr *nla)
-{
- int i;
-
- for (i=0; i<NFT_CHAIN_T_MAX; i++) {
- if (chain_type[family][i] != NULL &&
- !nla_strcmp(nla, chain_type[family][i]->name))
- return i;
- }
- return -1;
-}
-
-static int nf_tables_chain_type_lookup(const struct nft_af_info *afi,
- const struct nlattr *nla,
- bool autoload)
-{
- int type;
-
- type = __nf_tables_chain_type_lookup(afi->family, nla);
-#ifdef CONFIG_MODULES
- if (type < 0 && autoload) {
- nfnl_unlock(NFNL_SUBSYS_NFTABLES);
- request_module("nft-chain-%u-%*.s", afi->family,
- nla_len(nla)-1, (const char *)nla_data(nla));
- nfnl_lock(NFNL_SUBSYS_NFTABLES);
- type = __nf_tables_chain_type_lookup(afi->family, nla);
- }
-#endif
- return type;
-}
-
-static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = {
- [NFTA_TABLE_NAME] = { .type = NLA_STRING },
- [NFTA_TABLE_FLAGS] = { .type = NLA_U32 },
-};
-
-static int nf_tables_fill_table_info(struct sk_buff *skb, u32 portid, u32 seq,
- int event, u32 flags, int family,
- const struct nft_table *table)
-{
- struct nlmsghdr *nlh;
- struct nfgenmsg *nfmsg;
-
- event |= NFNL_SUBSYS_NFTABLES << 8;
- nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
- if (nlh == NULL)
- goto nla_put_failure;
-
- nfmsg = nlmsg_data(nlh);
- nfmsg->nfgen_family = family;
- nfmsg->version = NFNETLINK_V0;
- nfmsg->res_id = 0;
-
- if (nla_put_string(skb, NFTA_TABLE_NAME, table->name) ||
- nla_put_be32(skb, NFTA_TABLE_FLAGS, htonl(table->flags)))
- goto nla_put_failure;
-
- return nlmsg_end(skb, nlh);
-
-nla_put_failure:
- nlmsg_trim(skb, nlh);
- return -1;
-}
-
-static int nf_tables_table_notify(const struct sk_buff *oskb,
- const struct nlmsghdr *nlh,
- const struct nft_table *table,
- int event, int family)
-{
- struct sk_buff *skb;
- u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
- u32 seq = nlh ? nlh->nlmsg_seq : 0;
- struct net *net = oskb ? sock_net(oskb->sk) : &init_net;
- bool report;
- int err;
-
- report = nlh ? nlmsg_report(nlh) : false;
- if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
- return 0;
-
- err = -ENOBUFS;
- skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
- if (skb == NULL)
- goto err;
-
- err = nf_tables_fill_table_info(skb, portid, seq, event, 0,
- family, table);
- if (err < 0) {
- kfree_skb(skb);
- goto err;
- }
-
- err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
- GFP_KERNEL);
-err:
- if (err < 0)
- nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
- return err;
-}
-
-static int nf_tables_dump_tables(struct sk_buff *skb,
- struct netlink_callback *cb)
-{
- const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
- const struct nft_af_info *afi;
- const struct nft_table *table;
- unsigned int idx = 0, s_idx = cb->args[0];
- struct net *net = sock_net(skb->sk);
- int family = nfmsg->nfgen_family;
-
- list_for_each_entry(afi, &net->nft.af_info, list) {
- if (family != NFPROTO_UNSPEC && family != afi->family)
- continue;
-
- list_for_each_entry(table, &afi->tables, list) {
- if (idx < s_idx)
- goto cont;
- if (idx > s_idx)
- memset(&cb->args[1], 0,
- sizeof(cb->args) - sizeof(cb->args[0]));
- if (nf_tables_fill_table_info(skb,
- NETLINK_CB(cb->skb).portid,
- cb->nlh->nlmsg_seq,
- NFT_MSG_NEWTABLE,
- NLM_F_MULTI,
- afi->family, table) < 0)
- goto done;
-cont:
- idx++;
- }
- }
-done:
- cb->args[0] = idx;
- return skb->len;
-}
-
-static int nf_tables_gettable(struct sock *nlsk, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const nla[])
-{
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- const struct nft_af_info *afi;
- const struct nft_table *table;
- struct sk_buff *skb2;
- struct net *net = sock_net(skb->sk);
- int family = nfmsg->nfgen_family;
- int err;
-
- if (nlh->nlmsg_flags & NLM_F_DUMP) {
- struct netlink_dump_control c = {
- .dump = nf_tables_dump_tables,
- };
- return netlink_dump_start(nlsk, skb, nlh, &c);
- }
-
- afi = nf_tables_afinfo_lookup(net, family, false);
- if (IS_ERR(afi))
- return PTR_ERR(afi);
-
- table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME]);
- if (IS_ERR(table))
- return PTR_ERR(table);
-
- skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
- if (!skb2)
- return -ENOMEM;
-
- err = nf_tables_fill_table_info(skb2, NETLINK_CB(skb).portid,
- nlh->nlmsg_seq, NFT_MSG_NEWTABLE, 0,
- family, table);
- if (err < 0)
- goto err;
-
- return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
-
-err:
- kfree_skb(skb2);
- return err;
-}
-
-static int nf_tables_table_enable(struct nft_table *table)
-{
- struct nft_chain *chain;
- int err, i = 0;
-
- list_for_each_entry(chain, &table->chains, list) {
- err = nf_register_hook(&nft_base_chain(chain)->ops);
- if (err < 0)
- goto err;
-
- i++;
- }
- return 0;
-err:
- list_for_each_entry(chain, &table->chains, list) {
- if (i-- <= 0)
- break;
-
- nf_unregister_hook(&nft_base_chain(chain)->ops);
- }
- return err;
-}
-
-static int nf_tables_table_disable(struct nft_table *table)
-{
- struct nft_chain *chain;
-
- list_for_each_entry(chain, &table->chains, list)
- nf_unregister_hook(&nft_base_chain(chain)->ops);
-
- return 0;
-}
-
-static int nf_tables_updtable(struct sock *nlsk, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const nla[],
- struct nft_af_info *afi, struct nft_table *table)
-{
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- int family = nfmsg->nfgen_family, ret = 0;
-
- if (nla[NFTA_TABLE_FLAGS]) {
- __be32 flags;
-
- flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS]));
- if (flags & ~NFT_TABLE_F_DORMANT)
- return -EINVAL;
-
- if ((flags & NFT_TABLE_F_DORMANT) &&
- !(table->flags & NFT_TABLE_F_DORMANT)) {
- ret = nf_tables_table_disable(table);
- if (ret >= 0)
- table->flags |= NFT_TABLE_F_DORMANT;
- } else if (!(flags & NFT_TABLE_F_DORMANT) &&
- table->flags & NFT_TABLE_F_DORMANT) {
- ret = nf_tables_table_enable(table);
- if (ret >= 0)
- table->flags &= ~NFT_TABLE_F_DORMANT;
- }
- if (ret < 0)
- goto err;
- }
-
- nf_tables_table_notify(skb, nlh, table, NFT_MSG_NEWTABLE, family);
-err:
- return ret;
-}
-
-static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const nla[])
-{
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- const struct nlattr *name;
- struct nft_af_info *afi;
- struct nft_table *table;
- struct net *net = sock_net(skb->sk);
- int family = nfmsg->nfgen_family;
-
- afi = nf_tables_afinfo_lookup(net, family, true);
- if (IS_ERR(afi))
- return PTR_ERR(afi);
-
- name = nla[NFTA_TABLE_NAME];
- table = nf_tables_table_lookup(afi, name);
- if (IS_ERR(table)) {
- if (PTR_ERR(table) != -ENOENT)
- return PTR_ERR(table);
- table = NULL;
- }
-
- if (table != NULL) {
- if (nlh->nlmsg_flags & NLM_F_EXCL)
- return -EEXIST;
- if (nlh->nlmsg_flags & NLM_F_REPLACE)
- return -EOPNOTSUPP;
- return nf_tables_updtable(nlsk, skb, nlh, nla, afi, table);
- }
-
- table = kzalloc(sizeof(*table) + nla_len(name), GFP_KERNEL);
- if (table == NULL)
- return -ENOMEM;
-
- nla_strlcpy(table->name, name, nla_len(name));
- INIT_LIST_HEAD(&table->chains);
- INIT_LIST_HEAD(&table->sets);
-
- if (nla[NFTA_TABLE_FLAGS]) {
- __be32 flags;
-
- flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS]));
- if (flags & ~NFT_TABLE_F_DORMANT) {
- kfree(table);
- return -EINVAL;
- }
-
- table->flags |= flags;
- }
-
- list_add_tail(&table->list, &afi->tables);
- nf_tables_table_notify(skb, nlh, table, NFT_MSG_NEWTABLE, family);
- return 0;
-}
-
-static int nf_tables_deltable(struct sock *nlsk, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const nla[])
-{
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- struct nft_af_info *afi;
- struct nft_table *table;
- struct net *net = sock_net(skb->sk);
- int family = nfmsg->nfgen_family;
-
- afi = nf_tables_afinfo_lookup(net, family, false);
- if (IS_ERR(afi))
- return PTR_ERR(afi);
-
- table = nf_tables_table_lookup(afi, nla[NFTA_TABLE_NAME]);
- if (IS_ERR(table))
- return PTR_ERR(table);
-
- if (table->use)
- return -EBUSY;
-
- list_del(&table->list);
- nf_tables_table_notify(skb, nlh, table, NFT_MSG_DELTABLE, family);
- kfree(table);
- return 0;
-}
-
-int nft_register_chain_type(struct nf_chain_type *ctype)
-{
- int err = 0;
-
- nfnl_lock(NFNL_SUBSYS_NFTABLES);
- if (chain_type[ctype->family][ctype->type] != NULL) {
- err = -EBUSY;
- goto out;
- }
-
- if (!try_module_get(ctype->me))
- goto out;
-
- chain_type[ctype->family][ctype->type] = ctype;
-out:
- nfnl_unlock(NFNL_SUBSYS_NFTABLES);
- return err;
-}
-EXPORT_SYMBOL_GPL(nft_register_chain_type);
-
-void nft_unregister_chain_type(struct nf_chain_type *ctype)
-{
- nfnl_lock(NFNL_SUBSYS_NFTABLES);
- chain_type[ctype->family][ctype->type] = NULL;
- module_put(ctype->me);
- nfnl_unlock(NFNL_SUBSYS_NFTABLES);
-}
-EXPORT_SYMBOL_GPL(nft_unregister_chain_type);
-
-/*
- * Chains
- */
-
-static struct nft_chain *
-nf_tables_chain_lookup_byhandle(const struct nft_table *table, u64 handle)
-{
- struct nft_chain *chain;
-
- list_for_each_entry(chain, &table->chains, list) {
- if (chain->handle == handle)
- return chain;
- }
-
- return ERR_PTR(-ENOENT);
-}
-
-static struct nft_chain *nf_tables_chain_lookup(const struct nft_table *table,
- const struct nlattr *nla)
-{
- struct nft_chain *chain;
-
- if (nla == NULL)
- return ERR_PTR(-EINVAL);
-
- list_for_each_entry(chain, &table->chains, list) {
- if (!nla_strcmp(nla, chain->name))
- return chain;
- }
-
- return ERR_PTR(-ENOENT);
-}
-
-static const struct nla_policy nft_chain_policy[NFTA_CHAIN_MAX + 1] = {
- [NFTA_CHAIN_TABLE] = { .type = NLA_STRING },
- [NFTA_CHAIN_HANDLE] = { .type = NLA_U64 },
- [NFTA_CHAIN_NAME] = { .type = NLA_STRING,
- .len = NFT_CHAIN_MAXNAMELEN - 1 },
- [NFTA_CHAIN_HOOK] = { .type = NLA_NESTED },
- [NFTA_CHAIN_POLICY] = { .type = NLA_U32 },
- [NFTA_CHAIN_TYPE] = { .type = NLA_NUL_STRING },
- [NFTA_CHAIN_COUNTERS] = { .type = NLA_NESTED },
-};
-
-static const struct nla_policy nft_hook_policy[NFTA_HOOK_MAX + 1] = {
- [NFTA_HOOK_HOOKNUM] = { .type = NLA_U32 },
- [NFTA_HOOK_PRIORITY] = { .type = NLA_U32 },
-};
-
-static int nft_dump_stats(struct sk_buff *skb, struct nft_stats __percpu *stats)
-{
- struct nft_stats *cpu_stats, total;
- struct nlattr *nest;
- int cpu;
-
- memset(&total, 0, sizeof(total));
- for_each_possible_cpu(cpu) {
- cpu_stats = per_cpu_ptr(stats, cpu);
- total.pkts += cpu_stats->pkts;
- total.bytes += cpu_stats->bytes;
- }
- nest = nla_nest_start(skb, NFTA_CHAIN_COUNTERS);
- if (nest == NULL)
- goto nla_put_failure;
-
- if (nla_put_be64(skb, NFTA_COUNTER_PACKETS, cpu_to_be64(total.pkts)) ||
- nla_put_be64(skb, NFTA_COUNTER_BYTES, cpu_to_be64(total.bytes)))
- goto nla_put_failure;
-
- nla_nest_end(skb, nest);
- return 0;
-
-nla_put_failure:
- return -ENOSPC;
-}
-
-static int nf_tables_fill_chain_info(struct sk_buff *skb, u32 portid, u32 seq,
- int event, u32 flags, int family,
- const struct nft_table *table,
- const struct nft_chain *chain)
-{
- struct nlmsghdr *nlh;
- struct nfgenmsg *nfmsg;
-
- event |= NFNL_SUBSYS_NFTABLES << 8;
- nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
- if (nlh == NULL)
- goto nla_put_failure;
-
- nfmsg = nlmsg_data(nlh);
- nfmsg->nfgen_family = family;
- nfmsg->version = NFNETLINK_V0;
- nfmsg->res_id = 0;
-
- if (nla_put_string(skb, NFTA_CHAIN_TABLE, table->name))
- goto nla_put_failure;
- if (nla_put_be64(skb, NFTA_CHAIN_HANDLE, cpu_to_be64(chain->handle)))
- goto nla_put_failure;
- if (nla_put_string(skb, NFTA_CHAIN_NAME, chain->name))
- goto nla_put_failure;
-
- if (chain->flags & NFT_BASE_CHAIN) {
- const struct nft_base_chain *basechain = nft_base_chain(chain);
- const struct nf_hook_ops *ops = &basechain->ops;
- struct nlattr *nest;
-
- nest = nla_nest_start(skb, NFTA_CHAIN_HOOK);
- if (nest == NULL)
- goto nla_put_failure;
- if (nla_put_be32(skb, NFTA_HOOK_HOOKNUM, htonl(ops->hooknum)))
- goto nla_put_failure;
- if (nla_put_be32(skb, NFTA_HOOK_PRIORITY, htonl(ops->priority)))
- goto nla_put_failure;
- nla_nest_end(skb, nest);
-
- if (nla_put_be32(skb, NFTA_CHAIN_POLICY,
- htonl(basechain->policy)))
- goto nla_put_failure;
-
- if (nla_put_string(skb, NFTA_CHAIN_TYPE,
- chain_type[ops->pf][nft_base_chain(chain)->type]->name))
- goto nla_put_failure;
-
- if (nft_dump_stats(skb, nft_base_chain(chain)->stats))
- goto nla_put_failure;
- }
-
- if (nla_put_be32(skb, NFTA_CHAIN_USE, htonl(chain->use)))
- goto nla_put_failure;
-
- return nlmsg_end(skb, nlh);
-
-nla_put_failure:
- nlmsg_trim(skb, nlh);
- return -1;
-}
-
-static int nf_tables_chain_notify(const struct sk_buff *oskb,
- const struct nlmsghdr *nlh,
- const struct nft_table *table,
- const struct nft_chain *chain,
- int event, int family)
-{
- struct sk_buff *skb;
- u32 portid = oskb ? NETLINK_CB(oskb).portid : 0;
- struct net *net = oskb ? sock_net(oskb->sk) : &init_net;
- u32 seq = nlh ? nlh->nlmsg_seq : 0;
- bool report;
- int err;
-
- report = nlh ? nlmsg_report(nlh) : false;
- if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
- return 0;
-
- err = -ENOBUFS;
- skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
- if (skb == NULL)
- goto err;
-
- err = nf_tables_fill_chain_info(skb, portid, seq, event, 0, family,
- table, chain);
- if (err < 0) {
- kfree_skb(skb);
- goto err;
- }
-
- err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
- GFP_KERNEL);
-err:
- if (err < 0)
- nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
- return err;
-}
-
-static int nf_tables_dump_chains(struct sk_buff *skb,
- struct netlink_callback *cb)
-{
- const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
- const struct nft_af_info *afi;
- const struct nft_table *table;
- const struct nft_chain *chain;
- unsigned int idx = 0, s_idx = cb->args[0];
- struct net *net = sock_net(skb->sk);
- int family = nfmsg->nfgen_family;
-
- list_for_each_entry(afi, &net->nft.af_info, list) {
- if (family != NFPROTO_UNSPEC && family != afi->family)
- continue;
-
- list_for_each_entry(table, &afi->tables, list) {
- list_for_each_entry(chain, &table->chains, list) {
- if (idx < s_idx)
- goto cont;
- if (idx > s_idx)
- memset(&cb->args[1], 0,
- sizeof(cb->args) - sizeof(cb->args[0]));
- if (nf_tables_fill_chain_info(skb, NETLINK_CB(cb->skb).portid,
- cb->nlh->nlmsg_seq,
- NFT_MSG_NEWCHAIN,
- NLM_F_MULTI,
- afi->family, table, chain) < 0)
- goto done;
-cont:
- idx++;
- }
- }
- }
-done:
- cb->args[0] = idx;
- return skb->len;
-}
-
-
-static int nf_tables_getchain(struct sock *nlsk, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const nla[])
-{
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- const struct nft_af_info *afi;
- const struct nft_table *table;
- const struct nft_chain *chain;
- struct sk_buff *skb2;
- struct net *net = sock_net(skb->sk);
- int family = nfmsg->nfgen_family;
- int err;
-
- if (nlh->nlmsg_flags & NLM_F_DUMP) {
- struct netlink_dump_control c = {
- .dump = nf_tables_dump_chains,
- };
- return netlink_dump_start(nlsk, skb, nlh, &c);
- }
-
- afi = nf_tables_afinfo_lookup(net, family, false);
- if (IS_ERR(afi))
- return PTR_ERR(afi);
-
- table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
- if (IS_ERR(table))
- return PTR_ERR(table);
-
- chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]);
- if (IS_ERR(chain))
- return PTR_ERR(chain);
-
- skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
- if (!skb2)
- return -ENOMEM;
-
- err = nf_tables_fill_chain_info(skb2, NETLINK_CB(skb).portid,
- nlh->nlmsg_seq, NFT_MSG_NEWCHAIN, 0,
- family, table, chain);
- if (err < 0)
- goto err;
-
- return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
-
-err:
- kfree_skb(skb2);
- return err;
-}
-
-static int
-nf_tables_chain_policy(struct nft_base_chain *chain, const struct nlattr *attr)
-{
- switch (ntohl(nla_get_be32(attr))) {
- case NF_DROP:
- chain->policy = NF_DROP;
- break;
- case NF_ACCEPT:
- chain->policy = NF_ACCEPT;
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static const struct nla_policy nft_counter_policy[NFTA_COUNTER_MAX + 1] = {
- [NFTA_COUNTER_PACKETS] = { .type = NLA_U64 },
- [NFTA_COUNTER_BYTES] = { .type = NLA_U64 },
-};
-
-static int
-nf_tables_counters(struct nft_base_chain *chain, const struct nlattr *attr)
-{
- struct nlattr *tb[NFTA_COUNTER_MAX+1];
- struct nft_stats __percpu *newstats;
- struct nft_stats *stats;
- int err;
-
- err = nla_parse_nested(tb, NFTA_COUNTER_MAX, attr, nft_counter_policy);
- if (err < 0)
- return err;
-
- if (!tb[NFTA_COUNTER_BYTES] || !tb[NFTA_COUNTER_PACKETS])
- return -EINVAL;
-
- newstats = alloc_percpu(struct nft_stats);
- if (newstats == NULL)
- return -ENOMEM;
-
- /* Restore old counters on this cpu, no problem. Per-cpu statistics
- * are not exposed to userspace.
- */
- stats = this_cpu_ptr(newstats);
- stats->bytes = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_BYTES]));
- stats->pkts = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_PACKETS]));
-
- if (chain->stats) {
- /* nfnl_lock is held, add some nfnl function for this, later */
- struct nft_stats __percpu *oldstats =
- rcu_dereference_protected(chain->stats, 1);
-
- rcu_assign_pointer(chain->stats, newstats);
- synchronize_rcu();
- free_percpu(oldstats);
- } else
- rcu_assign_pointer(chain->stats, newstats);
-
- return 0;
-}
-
-static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const nla[])
-{
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- const struct nlattr * uninitialized_var(name);
- const struct nft_af_info *afi;
- struct nft_table *table;
- struct nft_chain *chain;
- struct nft_base_chain *basechain = NULL;
- struct nlattr *ha[NFTA_HOOK_MAX + 1];
- struct net *net = sock_net(skb->sk);
- int family = nfmsg->nfgen_family;
- u64 handle = 0;
- int err;
- bool create;
-
- create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
-
- afi = nf_tables_afinfo_lookup(net, family, true);
- if (IS_ERR(afi))
- return PTR_ERR(afi);
-
- table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
- if (IS_ERR(table))
- return PTR_ERR(table);
-
- if (table->use == UINT_MAX)
- return -EOVERFLOW;
-
- chain = NULL;
- name = nla[NFTA_CHAIN_NAME];
-
- if (nla[NFTA_CHAIN_HANDLE]) {
- handle = be64_to_cpu(nla_get_be64(nla[NFTA_CHAIN_HANDLE]));
- chain = nf_tables_chain_lookup_byhandle(table, handle);
- if (IS_ERR(chain))
- return PTR_ERR(chain);
- } else {
- chain = nf_tables_chain_lookup(table, name);
- if (IS_ERR(chain)) {
- if (PTR_ERR(chain) != -ENOENT)
- return PTR_ERR(chain);
- chain = NULL;
- }
- }
-
- if (chain != NULL) {
- if (nlh->nlmsg_flags & NLM_F_EXCL)
- return -EEXIST;
- if (nlh->nlmsg_flags & NLM_F_REPLACE)
- return -EOPNOTSUPP;
-
- if (nla[NFTA_CHAIN_HANDLE] && name &&
- !IS_ERR(nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME])))
- return -EEXIST;
-
- if (nla[NFTA_CHAIN_POLICY]) {
- if (!(chain->flags & NFT_BASE_CHAIN))
- return -EOPNOTSUPP;
-
- err = nf_tables_chain_policy(nft_base_chain(chain),
- nla[NFTA_CHAIN_POLICY]);
- if (err < 0)
- return err;
- }
-
- if (nla[NFTA_CHAIN_COUNTERS]) {
- if (!(chain->flags & NFT_BASE_CHAIN))
- return -EOPNOTSUPP;
-
- err = nf_tables_counters(nft_base_chain(chain),
- nla[NFTA_CHAIN_COUNTERS]);
- if (err < 0)
- return err;
- }
-
- if (nla[NFTA_CHAIN_HANDLE] && name)
- nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN);
-
- goto notify;
- }
-
- if (nla[NFTA_CHAIN_HOOK]) {
- struct nf_hook_ops *ops;
- nf_hookfn *hookfn;
- u32 hooknum;
- int type = NFT_CHAIN_T_DEFAULT;
-
- if (nla[NFTA_CHAIN_TYPE]) {
- type = nf_tables_chain_type_lookup(afi,
- nla[NFTA_CHAIN_TYPE],
- create);
- if (type < 0)
- return -ENOENT;
- }
-
- err = nla_parse_nested(ha, NFTA_HOOK_MAX, nla[NFTA_CHAIN_HOOK],
- nft_hook_policy);
- if (err < 0)
- return err;
- if (ha[NFTA_HOOK_HOOKNUM] == NULL ||
- ha[NFTA_HOOK_PRIORITY] == NULL)
- return -EINVAL;
-
- hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM]));
- if (hooknum >= afi->nhooks)
- return -EINVAL;
-
- hookfn = chain_type[family][type]->fn[hooknum];
- if (hookfn == NULL)
- return -EOPNOTSUPP;
-
- basechain = kzalloc(sizeof(*basechain), GFP_KERNEL);
- if (basechain == NULL)
- return -ENOMEM;
-
- basechain->type = type;
- chain = &basechain->chain;
-
- ops = &basechain->ops;
- ops->pf = family;
- ops->owner = afi->owner;
- ops->hooknum = ntohl(nla_get_be32(ha[NFTA_HOOK_HOOKNUM]));
- ops->priority = ntohl(nla_get_be32(ha[NFTA_HOOK_PRIORITY]));
- ops->priv = chain;
- ops->hook = hookfn;
- if (afi->hooks[ops->hooknum])
- ops->hook = afi->hooks[ops->hooknum];
-
- chain->flags |= NFT_BASE_CHAIN;
-
- if (nla[NFTA_CHAIN_POLICY]) {
- err = nf_tables_chain_policy(basechain,
- nla[NFTA_CHAIN_POLICY]);
- if (err < 0) {
- free_percpu(basechain->stats);
- kfree(basechain);
- return err;
- }
- } else
- basechain->policy = NF_ACCEPT;
-
- if (nla[NFTA_CHAIN_COUNTERS]) {
- err = nf_tables_counters(basechain,
- nla[NFTA_CHAIN_COUNTERS]);
- if (err < 0) {
- free_percpu(basechain->stats);
- kfree(basechain);
- return err;
- }
- } else {
- struct nft_stats __percpu *newstats;
-
- newstats = alloc_percpu(struct nft_stats);
- if (newstats == NULL)
- return -ENOMEM;
-
- rcu_assign_pointer(nft_base_chain(chain)->stats,
- newstats);
- }
- } else {
- chain = kzalloc(sizeof(*chain), GFP_KERNEL);
- if (chain == NULL)
- return -ENOMEM;
- }
-
- INIT_LIST_HEAD(&chain->rules);
- chain->handle = nf_tables_alloc_handle(table);
- chain->net = net;
- chain->table = table;
- nla_strlcpy(chain->name, name, NFT_CHAIN_MAXNAMELEN);
-
- if (!(table->flags & NFT_TABLE_F_DORMANT) &&
- chain->flags & NFT_BASE_CHAIN) {
- err = nf_register_hook(&nft_base_chain(chain)->ops);
- if (err < 0) {
- free_percpu(basechain->stats);
- kfree(basechain);
- return err;
- }
- }
- list_add_tail(&chain->list, &table->chains);
- table->use++;
-notify:
- nf_tables_chain_notify(skb, nlh, table, chain, NFT_MSG_NEWCHAIN,
- family);
- return 0;
-}
-
-static void nf_tables_rcu_chain_destroy(struct rcu_head *head)
-{
- struct nft_chain *chain = container_of(head, struct nft_chain, rcu_head);
-
- BUG_ON(chain->use > 0);
-
- if (chain->flags & NFT_BASE_CHAIN) {
- free_percpu(nft_base_chain(chain)->stats);
- kfree(nft_base_chain(chain));
- } else
- kfree(chain);
-}
-
-static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const nla[])
-{
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- const struct nft_af_info *afi;
- struct nft_table *table;
- struct nft_chain *chain;
- struct net *net = sock_net(skb->sk);
- int family = nfmsg->nfgen_family;
-
- afi = nf_tables_afinfo_lookup(net, family, false);
- if (IS_ERR(afi))
- return PTR_ERR(afi);
-
- table = nf_tables_table_lookup(afi, nla[NFTA_CHAIN_TABLE]);
- if (IS_ERR(table))
- return PTR_ERR(table);
-
- chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME]);
- if (IS_ERR(chain))
- return PTR_ERR(chain);
-
- if (!list_empty(&chain->rules))
- return -EBUSY;
-
- list_del(&chain->list);
- table->use--;
-
- if (!(table->flags & NFT_TABLE_F_DORMANT) &&
- chain->flags & NFT_BASE_CHAIN)
- nf_unregister_hook(&nft_base_chain(chain)->ops);
-
- nf_tables_chain_notify(skb, nlh, table, chain, NFT_MSG_DELCHAIN,
- family);
-
- /* Make sure all rule references are gone before this is released */
- call_rcu(&chain->rcu_head, nf_tables_rcu_chain_destroy);
- return 0;
-}
-
-static void nft_ctx_init(struct nft_ctx *ctx,
- const struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nft_af_info *afi,
- const struct nft_table *table,
- const struct nft_chain *chain,
- const struct nlattr * const *nla)
-{
- ctx->net = sock_net(skb->sk);
- ctx->skb = skb;
- ctx->nlh = nlh;
- ctx->afi = afi;
- ctx->table = table;
- ctx->chain = chain;
- ctx->nla = nla;
-}
-
-/*
- * Expressions
- */
-
-/**
- * nft_register_expr - register nf_tables expr type
- * @ops: expr type
- *
- * Registers the expr type for use with nf_tables. Returns zero on
- * success or a negative errno code otherwise.
- */
-int nft_register_expr(struct nft_expr_type *type)
-{
- nfnl_lock(NFNL_SUBSYS_NFTABLES);
- list_add_tail(&type->list, &nf_tables_expressions);
- nfnl_unlock(NFNL_SUBSYS_NFTABLES);
- return 0;
-}
-EXPORT_SYMBOL_GPL(nft_register_expr);
-
-/**
- * nft_unregister_expr - unregister nf_tables expr type
- * @ops: expr type
- *
- * Unregisters the expr typefor use with nf_tables.
- */
-void nft_unregister_expr(struct nft_expr_type *type)
-{
- nfnl_lock(NFNL_SUBSYS_NFTABLES);
- list_del(&type->list);
- nfnl_unlock(NFNL_SUBSYS_NFTABLES);
-}
-EXPORT_SYMBOL_GPL(nft_unregister_expr);
-
-static const struct nft_expr_type *__nft_expr_type_get(struct nlattr *nla)
-{
- const struct nft_expr_type *type;
-
- list_for_each_entry(type, &nf_tables_expressions, list) {
- if (!nla_strcmp(nla, type->name))
- return type;
- }
- return NULL;
-}
-
-static const struct nft_expr_type *nft_expr_type_get(struct nlattr *nla)
-{
- const struct nft_expr_type *type;
-
- if (nla == NULL)
- return ERR_PTR(-EINVAL);
-
- type = __nft_expr_type_get(nla);
- if (type != NULL && try_module_get(type->owner))
- return type;
-
-#ifdef CONFIG_MODULES
- if (type == NULL) {
- nfnl_unlock(NFNL_SUBSYS_NFTABLES);
- request_module("nft-expr-%.*s",
- nla_len(nla), (char *)nla_data(nla));
- nfnl_lock(NFNL_SUBSYS_NFTABLES);
- if (__nft_expr_type_get(nla))
- return ERR_PTR(-EAGAIN);
- }
-#endif
- return ERR_PTR(-ENOENT);
-}
-
-static const struct nla_policy nft_expr_policy[NFTA_EXPR_MAX + 1] = {
- [NFTA_EXPR_NAME] = { .type = NLA_STRING },
- [NFTA_EXPR_DATA] = { .type = NLA_NESTED },
-};
-
-static int nf_tables_fill_expr_info(struct sk_buff *skb,
- const struct nft_expr *expr)
-{
- if (nla_put_string(skb, NFTA_EXPR_NAME, expr->ops->type->name))
- goto nla_put_failure;
-
- if (expr->ops->dump) {
- struct nlattr *data = nla_nest_start(skb, NFTA_EXPR_DATA);
- if (data == NULL)
- goto nla_put_failure;
- if (expr->ops->dump(skb, expr) < 0)
- goto nla_put_failure;
- nla_nest_end(skb, data);
- }
-
- return skb->len;
-
-nla_put_failure:
- return -1;
-};
-
-struct nft_expr_info {
- const struct nft_expr_ops *ops;
- struct nlattr *tb[NFT_EXPR_MAXATTR + 1];
-};
-
-static int nf_tables_expr_parse(const struct nft_ctx *ctx,
- const struct nlattr *nla,
- struct nft_expr_info *info)
-{
- const struct nft_expr_type *type;
- const struct nft_expr_ops *ops;
- struct nlattr *tb[NFTA_EXPR_MAX + 1];
- int err;
-
- err = nla_parse_nested(tb, NFTA_EXPR_MAX, nla, nft_expr_policy);
- if (err < 0)
- return err;
-
- type = nft_expr_type_get(tb[NFTA_EXPR_NAME]);
- if (IS_ERR(type))
- return PTR_ERR(type);
-
- if (tb[NFTA_EXPR_DATA]) {
- err = nla_parse_nested(info->tb, type->maxattr,
- tb[NFTA_EXPR_DATA], type->policy);
- if (err < 0)
- goto err1;
- } else
- memset(info->tb, 0, sizeof(info->tb[0]) * (type->maxattr + 1));
-
- if (type->select_ops != NULL) {
- ops = type->select_ops(ctx,
- (const struct nlattr * const *)info->tb);
- if (IS_ERR(ops)) {
- err = PTR_ERR(ops);
- goto err1;
- }
- } else
- ops = type->ops;
-
- info->ops = ops;
- return 0;
-
-err1:
- module_put(type->owner);
- return err;
-}
-
-static int nf_tables_newexpr(const struct nft_ctx *ctx,
- const struct nft_expr_info *info,
- struct nft_expr *expr)
-{
- const struct nft_expr_ops *ops = info->ops;
- int err;
-
- expr->ops = ops;
- if (ops->init) {
- err = ops->init(ctx, expr, (const struct nlattr **)info->tb);
- if (err < 0)
- goto err1;
- }
-
- return 0;
-
-err1:
- expr->ops = NULL;
- return err;
-}
-
-static void nf_tables_expr_destroy(struct nft_expr *expr)
-{
- if (expr->ops->destroy)
- expr->ops->destroy(expr);
- module_put(expr->ops->type->owner);
-}
-
-/*
- * Rules
- */
-
-static struct nft_rule *__nf_tables_rule_lookup(const struct nft_chain *chain,
- u64 handle)
-{
- struct nft_rule *rule;
-
- // FIXME: this sucks
- list_for_each_entry(rule, &chain->rules, list) {
- if (handle == rule->handle)
- return rule;
- }
-
- return ERR_PTR(-ENOENT);
-}
-
-static struct nft_rule *nf_tables_rule_lookup(const struct nft_chain *chain,
- const struct nlattr *nla)
-{
- if (nla == NULL)
- return ERR_PTR(-EINVAL);
-
- return __nf_tables_rule_lookup(chain, be64_to_cpu(nla_get_be64(nla)));
-}
-
-static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
- [NFTA_RULE_TABLE] = { .type = NLA_STRING },
- [NFTA_RULE_CHAIN] = { .type = NLA_STRING,
- .len = NFT_CHAIN_MAXNAMELEN - 1 },
- [NFTA_RULE_HANDLE] = { .type = NLA_U64 },
- [NFTA_RULE_EXPRESSIONS] = { .type = NLA_NESTED },
- [NFTA_RULE_COMPAT] = { .type = NLA_NESTED },
- [NFTA_RULE_POSITION] = { .type = NLA_U64 },
-};
-
-static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq,
- int event, u32 flags, int family,
- const struct nft_table *table,
- const struct nft_chain *chain,
- const struct nft_rule *rule)
-{
- struct nlmsghdr *nlh;
- struct nfgenmsg *nfmsg;
- const struct nft_expr *expr, *next;
- struct nlattr *list;
- const struct nft_rule *prule;
- int type = event | NFNL_SUBSYS_NFTABLES << 8;
-
- nlh = nlmsg_put(skb, portid, seq, type, sizeof(struct nfgenmsg),
- flags);
- if (nlh == NULL)
- goto nla_put_failure;
-
- nfmsg = nlmsg_data(nlh);
- nfmsg->nfgen_family = family;
- nfmsg->version = NFNETLINK_V0;
- nfmsg->res_id = 0;
-
- if (nla_put_string(skb, NFTA_RULE_TABLE, table->name))
- goto nla_put_failure;
- if (nla_put_string(skb, NFTA_RULE_CHAIN, chain->name))
- goto nla_put_failure;
- if (nla_put_be64(skb, NFTA_RULE_HANDLE, cpu_to_be64(rule->handle)))
- goto nla_put_failure;
-
- if ((event != NFT_MSG_DELRULE) && (rule->list.prev != &chain->rules)) {
- prule = list_entry(rule->list.prev, struct nft_rule, list);
- if (nla_put_be64(skb, NFTA_RULE_POSITION,
- cpu_to_be64(prule->handle)))
- goto nla_put_failure;
- }
-
- list = nla_nest_start(skb, NFTA_RULE_EXPRESSIONS);
- if (list == NULL)
- goto nla_put_failure;
- nft_rule_for_each_expr(expr, next, rule) {
- struct nlattr *elem = nla_nest_start(skb, NFTA_LIST_ELEM);
- if (elem == NULL)
- goto nla_put_failure;
- if (nf_tables_fill_expr_info(skb, expr) < 0)
- goto nla_put_failure;
- nla_nest_end(skb, elem);
- }
- nla_nest_end(skb, list);
-
- return nlmsg_end(skb, nlh);
-
-nla_put_failure:
- nlmsg_trim(skb, nlh);
- return -1;
-}
-
-static int nf_tables_rule_notify(const struct sk_buff *oskb,
- const struct nlmsghdr *nlh,
- const struct nft_table *table,
- const struct nft_chain *chain,
- const struct nft_rule *rule,
- int event, u32 flags, int family)
-{
- struct sk_buff *skb;
- u32 portid = NETLINK_CB(oskb).portid;
- struct net *net = oskb ? sock_net(oskb->sk) : &init_net;
- u32 seq = nlh->nlmsg_seq;
- bool report;
- int err;
-
- report = nlmsg_report(nlh);
- if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
- return 0;
-
- err = -ENOBUFS;
- skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
- if (skb == NULL)
- goto err;
-
- err = nf_tables_fill_rule_info(skb, portid, seq, event, flags,
- family, table, chain, rule);
- if (err < 0) {
- kfree_skb(skb);
- goto err;
- }
-
- err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
- GFP_KERNEL);
-err:
- if (err < 0)
- nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
- return err;
-}
-
-static inline bool
-nft_rule_is_active(struct net *net, const struct nft_rule *rule)
-{
- return (rule->genmask & (1 << net->nft.gencursor)) == 0;
-}
-
-static inline int gencursor_next(struct net *net)
-{
- return net->nft.gencursor+1 == 1 ? 1 : 0;
-}
-
-static inline int
-nft_rule_is_active_next(struct net *net, const struct nft_rule *rule)
-{
- return (rule->genmask & (1 << gencursor_next(net))) == 0;
-}
-
-static inline void
-nft_rule_activate_next(struct net *net, struct nft_rule *rule)
-{
- /* Now inactive, will be active in the future */
- rule->genmask = (1 << net->nft.gencursor);
-}
-
-static inline void
-nft_rule_disactivate_next(struct net *net, struct nft_rule *rule)
-{
- rule->genmask = (1 << gencursor_next(net));
-}
-
-static inline void nft_rule_clear(struct net *net, struct nft_rule *rule)
-{
- rule->genmask = 0;
-}
-
-static int nf_tables_dump_rules(struct sk_buff *skb,
- struct netlink_callback *cb)
-{
- const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
- const struct nft_af_info *afi;
- const struct nft_table *table;
- const struct nft_chain *chain;
- const struct nft_rule *rule;
- unsigned int idx = 0, s_idx = cb->args[0];
- struct net *net = sock_net(skb->sk);
- int family = nfmsg->nfgen_family;
- u8 genctr = ACCESS_ONCE(net->nft.genctr);
- u8 gencursor = ACCESS_ONCE(net->nft.gencursor);
-
- list_for_each_entry(afi, &net->nft.af_info, list) {
- if (family != NFPROTO_UNSPEC && family != afi->family)
- continue;
-
- list_for_each_entry(table, &afi->tables, list) {
- list_for_each_entry(chain, &table->chains, list) {
- list_for_each_entry(rule, &chain->rules, list) {
- if (!nft_rule_is_active(net, rule))
- goto cont;
- if (idx < s_idx)
- goto cont;
- if (idx > s_idx)
- memset(&cb->args[1], 0,
- sizeof(cb->args) - sizeof(cb->args[0]));
- if (nf_tables_fill_rule_info(skb, NETLINK_CB(cb->skb).portid,
- cb->nlh->nlmsg_seq,
- NFT_MSG_NEWRULE,
- NLM_F_MULTI | NLM_F_APPEND,
- afi->family, table, chain, rule) < 0)
- goto done;
-cont:
- idx++;
- }
- }
- }
- }
-done:
- /* Invalidate this dump, a transition to the new generation happened */
- if (gencursor != net->nft.gencursor || genctr != net->nft.genctr)
- return -EBUSY;
-
- cb->args[0] = idx;
- return skb->len;
-}
-
-static int nf_tables_getrule(struct sock *nlsk, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const nla[])
-{
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- const struct nft_af_info *afi;
- const struct nft_table *table;
- const struct nft_chain *chain;
- const struct nft_rule *rule;
- struct sk_buff *skb2;
- struct net *net = sock_net(skb->sk);
- int family = nfmsg->nfgen_family;
- int err;
-
- if (nlh->nlmsg_flags & NLM_F_DUMP) {
- struct netlink_dump_control c = {
- .dump = nf_tables_dump_rules,
- };
- return netlink_dump_start(nlsk, skb, nlh, &c);
- }
-
- afi = nf_tables_afinfo_lookup(net, family, false);
- if (IS_ERR(afi))
- return PTR_ERR(afi);
-
- table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
- if (IS_ERR(table))
- return PTR_ERR(table);
-
- chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
- if (IS_ERR(chain))
- return PTR_ERR(chain);
-
- rule = nf_tables_rule_lookup(chain, nla[NFTA_RULE_HANDLE]);
- if (IS_ERR(rule))
- return PTR_ERR(rule);
-
- skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
- if (!skb2)
- return -ENOMEM;
-
- err = nf_tables_fill_rule_info(skb2, NETLINK_CB(skb).portid,
- nlh->nlmsg_seq, NFT_MSG_NEWRULE, 0,
- family, table, chain, rule);
- if (err < 0)
- goto err;
-
- return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
-
-err:
- kfree_skb(skb2);
- return err;
-}
-
-static void nf_tables_rcu_rule_destroy(struct rcu_head *head)
-{
- struct nft_rule *rule = container_of(head, struct nft_rule, rcu_head);
- struct nft_expr *expr;
-
- /*
- * Careful: some expressions might not be initialized in case this
- * is called on error from nf_tables_newrule().
- */
- expr = nft_expr_first(rule);
- while (expr->ops && expr != nft_expr_last(rule)) {
- nf_tables_expr_destroy(expr);
- expr = nft_expr_next(expr);
- }
- kfree(rule);
-}
-
-static void nf_tables_rule_destroy(struct nft_rule *rule)
-{
- call_rcu(&rule->rcu_head, nf_tables_rcu_rule_destroy);
-}
-
-#define NFT_RULE_MAXEXPRS 128
-
-static struct nft_expr_info *info;
-
-static struct nft_rule_trans *
-nf_tables_trans_add(struct nft_rule *rule, const struct nft_ctx *ctx)
-{
- struct nft_rule_trans *rupd;
-
- rupd = kmalloc(sizeof(struct nft_rule_trans), GFP_KERNEL);
- if (rupd == NULL)
- return NULL;
-
- rupd->chain = ctx->chain;
- rupd->table = ctx->table;
- rupd->rule = rule;
- rupd->family = ctx->afi->family;
- rupd->nlh = ctx->nlh;
- list_add_tail(&rupd->list, &ctx->net->nft.commit_list);
-
- return rupd;
-}
-
-static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const nla[])
-{
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- const struct nft_af_info *afi;
- struct net *net = sock_net(skb->sk);
- struct nft_table *table;
- struct nft_chain *chain;
- struct nft_rule *rule, *old_rule = NULL;
- struct nft_rule_trans *repl = NULL;
- struct nft_expr *expr;
- struct nft_ctx ctx;
- struct nlattr *tmp;
- unsigned int size, i, n;
- int err, rem;
- bool create;
- u64 handle, pos_handle;
-
- create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
-
- afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, create);
- if (IS_ERR(afi))
- return PTR_ERR(afi);
-
- table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
- if (IS_ERR(table))
- return PTR_ERR(table);
-
- chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
- if (IS_ERR(chain))
- return PTR_ERR(chain);
-
- if (nla[NFTA_RULE_HANDLE]) {
- handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_HANDLE]));
- rule = __nf_tables_rule_lookup(chain, handle);
- if (IS_ERR(rule))
- return PTR_ERR(rule);
-
- if (nlh->nlmsg_flags & NLM_F_EXCL)
- return -EEXIST;
- if (nlh->nlmsg_flags & NLM_F_REPLACE)
- old_rule = rule;
- else
- return -EOPNOTSUPP;
- } else {
- if (!create || nlh->nlmsg_flags & NLM_F_REPLACE)
- return -EINVAL;
- handle = nf_tables_alloc_handle(table);
- }
-
- if (nla[NFTA_RULE_POSITION]) {
- if (!(nlh->nlmsg_flags & NLM_F_CREATE))
- return -EOPNOTSUPP;
-
- pos_handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_POSITION]));
- old_rule = __nf_tables_rule_lookup(chain, pos_handle);
- if (IS_ERR(old_rule))
- return PTR_ERR(old_rule);
- }
-
- nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
-
- n = 0;
- size = 0;
- if (nla[NFTA_RULE_EXPRESSIONS]) {
- nla_for_each_nested(tmp, nla[NFTA_RULE_EXPRESSIONS], rem) {
- err = -EINVAL;
- if (nla_type(tmp) != NFTA_LIST_ELEM)
- goto err1;
- if (n == NFT_RULE_MAXEXPRS)
- goto err1;
- err = nf_tables_expr_parse(&ctx, tmp, &info[n]);
- if (err < 0)
- goto err1;
- size += info[n].ops->size;
- n++;
- }
- }
-
- err = -ENOMEM;
- rule = kzalloc(sizeof(*rule) + size, GFP_KERNEL);
- if (rule == NULL)
- goto err1;
-
- nft_rule_activate_next(net, rule);
-
- rule->handle = handle;
- rule->dlen = size;
-
- expr = nft_expr_first(rule);
- for (i = 0; i < n; i++) {
- err = nf_tables_newexpr(&ctx, &info[i], expr);
- if (err < 0)
- goto err2;
- info[i].ops = NULL;
- expr = nft_expr_next(expr);
- }
-
- if (nlh->nlmsg_flags & NLM_F_REPLACE) {
- if (nft_rule_is_active_next(net, old_rule)) {
- repl = nf_tables_trans_add(old_rule, &ctx);
- if (repl == NULL) {
- err = -ENOMEM;
- goto err2;
- }
- nft_rule_disactivate_next(net, old_rule);
- list_add_tail(&rule->list, &old_rule->list);
- } else {
- err = -ENOENT;
- goto err2;
- }
- } else if (nlh->nlmsg_flags & NLM_F_APPEND)
- if (old_rule)
- list_add_rcu(&rule->list, &old_rule->list);
- else
- list_add_tail_rcu(&rule->list, &chain->rules);
- else {
- if (old_rule)
- list_add_tail_rcu(&rule->list, &old_rule->list);
- else
- list_add_rcu(&rule->list, &chain->rules);
- }
-
- if (nf_tables_trans_add(rule, &ctx) == NULL) {
- err = -ENOMEM;
- goto err3;
- }
- return 0;
-
-err3:
- list_del_rcu(&rule->list);
- if (repl) {
- list_del_rcu(&repl->rule->list);
- list_del(&repl->list);
- nft_rule_clear(net, repl->rule);
- kfree(repl);
- }
-err2:
- nf_tables_rule_destroy(rule);
-err1:
- for (i = 0; i < n; i++) {
- if (info[i].ops != NULL)
- module_put(info[i].ops->type->owner);
- }
- return err;
-}
-
-static int
-nf_tables_delrule_one(struct nft_ctx *ctx, struct nft_rule *rule)
-{
- /* You cannot delete the same rule twice */
- if (nft_rule_is_active_next(ctx->net, rule)) {
- if (nf_tables_trans_add(rule, ctx) == NULL)
- return -ENOMEM;
- nft_rule_disactivate_next(ctx->net, rule);
- return 0;
- }
- return -ENOENT;
-}
-
-static int nf_tables_delrule(struct sock *nlsk, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const nla[])
-{
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- const struct nft_af_info *afi;
- struct net *net = sock_net(skb->sk);
- const struct nft_table *table;
- struct nft_chain *chain;
- struct nft_rule *rule, *tmp;
- int family = nfmsg->nfgen_family, err = 0;
- struct nft_ctx ctx;
-
- afi = nf_tables_afinfo_lookup(net, family, false);
- if (IS_ERR(afi))
- return PTR_ERR(afi);
-
- table = nf_tables_table_lookup(afi, nla[NFTA_RULE_TABLE]);
- if (IS_ERR(table))
- return PTR_ERR(table);
-
- chain = nf_tables_chain_lookup(table, nla[NFTA_RULE_CHAIN]);
- if (IS_ERR(chain))
- return PTR_ERR(chain);
-
- nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
-
- if (nla[NFTA_RULE_HANDLE]) {
- rule = nf_tables_rule_lookup(chain, nla[NFTA_RULE_HANDLE]);
- if (IS_ERR(rule))
- return PTR_ERR(rule);
-
- err = nf_tables_delrule_one(&ctx, rule);
- } else {
- /* Remove all rules in this chain */
- list_for_each_entry_safe(rule, tmp, &chain->rules, list) {
- err = nf_tables_delrule_one(&ctx, rule);
- if (err < 0)
- break;
- }
- }
-
- return err;
-}
-
-static int nf_tables_commit(struct sk_buff *skb)
-{
- struct net *net = sock_net(skb->sk);
- struct nft_rule_trans *rupd, *tmp;
-
- /* Bump generation counter, invalidate any dump in progress */
- net->nft.genctr++;
-
- /* A new generation has just started */
- net->nft.gencursor = gencursor_next(net);
-
- /* Make sure all packets have left the previous generation before
- * purging old rules.
- */
- synchronize_rcu();
-
- list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) {
- /* Delete this rule from the dirty list */
- list_del(&rupd->list);
-
- /* This rule was inactive in the past and just became active.
- * Clear the next bit of the genmask since its meaning has
- * changed, now it is the future.
- */
- if (nft_rule_is_active(net, rupd->rule)) {
- nft_rule_clear(net, rupd->rule);
- nf_tables_rule_notify(skb, rupd->nlh, rupd->table,
- rupd->chain, rupd->rule,
- NFT_MSG_NEWRULE, 0,
- rupd->family);
- kfree(rupd);
- continue;
- }
-
- /* This rule is in the past, get rid of it */
- list_del_rcu(&rupd->rule->list);
- nf_tables_rule_notify(skb, rupd->nlh, rupd->table, rupd->chain,
- rupd->rule, NFT_MSG_DELRULE, 0,
- rupd->family);
- nf_tables_rule_destroy(rupd->rule);
- kfree(rupd);
- }
-
- return 0;
-}
-
-static int nf_tables_abort(struct sk_buff *skb)
-{
- struct net *net = sock_net(skb->sk);
- struct nft_rule_trans *rupd, *tmp;
-
- list_for_each_entry_safe(rupd, tmp, &net->nft.commit_list, list) {
- /* Delete all rules from the dirty list */
- list_del(&rupd->list);
-
- if (!nft_rule_is_active_next(net, rupd->rule)) {
- nft_rule_clear(net, rupd->rule);
- kfree(rupd);
- continue;
- }
-
- /* This rule is inactive, get rid of it */
- list_del_rcu(&rupd->rule->list);
- nf_tables_rule_destroy(rupd->rule);
- kfree(rupd);
- }
- return 0;
-}
-
-/*
- * Sets
- */
-
-static LIST_HEAD(nf_tables_set_ops);
-
-int nft_register_set(struct nft_set_ops *ops)
-{
- nfnl_lock(NFNL_SUBSYS_NFTABLES);
- list_add_tail(&ops->list, &nf_tables_set_ops);
- nfnl_unlock(NFNL_SUBSYS_NFTABLES);
- return 0;
-}
-EXPORT_SYMBOL_GPL(nft_register_set);
-
-void nft_unregister_set(struct nft_set_ops *ops)
-{
- nfnl_lock(NFNL_SUBSYS_NFTABLES);
- list_del(&ops->list);
- nfnl_unlock(NFNL_SUBSYS_NFTABLES);
-}
-EXPORT_SYMBOL_GPL(nft_unregister_set);
-
-static const struct nft_set_ops *nft_select_set_ops(const struct nlattr * const nla[])
-{
- const struct nft_set_ops *ops;
- u32 features;
-
-#ifdef CONFIG_MODULES
- if (list_empty(&nf_tables_set_ops)) {
- nfnl_unlock(NFNL_SUBSYS_NFTABLES);
- request_module("nft-set");
- nfnl_lock(NFNL_SUBSYS_NFTABLES);
- if (!list_empty(&nf_tables_set_ops))
- return ERR_PTR(-EAGAIN);
- }
-#endif
- features = 0;
- if (nla[NFTA_SET_FLAGS] != NULL) {
- features = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
- features &= NFT_SET_INTERVAL | NFT_SET_MAP;
- }
-
- // FIXME: implement selection properly
- list_for_each_entry(ops, &nf_tables_set_ops, list) {
- if ((ops->features & features) != features)
- continue;
- if (!try_module_get(ops->owner))
- continue;
- return ops;
- }
-
- return ERR_PTR(-EOPNOTSUPP);
-}
-
-static const struct nla_policy nft_set_policy[NFTA_SET_MAX + 1] = {
- [NFTA_SET_TABLE] = { .type = NLA_STRING },
- [NFTA_SET_NAME] = { .type = NLA_STRING },
- [NFTA_SET_FLAGS] = { .type = NLA_U32 },
- [NFTA_SET_KEY_TYPE] = { .type = NLA_U32 },
- [NFTA_SET_KEY_LEN] = { .type = NLA_U32 },
- [NFTA_SET_DATA_TYPE] = { .type = NLA_U32 },
- [NFTA_SET_DATA_LEN] = { .type = NLA_U32 },
-};
-
-static int nft_ctx_init_from_setattr(struct nft_ctx *ctx,
- const struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const nla[])
-{
- struct net *net = sock_net(skb->sk);
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- const struct nft_af_info *afi;
- const struct nft_table *table = NULL;
-
- afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, false);
- if (IS_ERR(afi))
- return PTR_ERR(afi);
-
- if (nla[NFTA_SET_TABLE] != NULL) {
- table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]);
- if (IS_ERR(table))
- return PTR_ERR(table);
- }
-
- nft_ctx_init(ctx, skb, nlh, afi, table, NULL, nla);
- return 0;
-}
-
-struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
- const struct nlattr *nla)
-{
- struct nft_set *set;
-
- if (nla == NULL)
- return ERR_PTR(-EINVAL);
-
- list_for_each_entry(set, &table->sets, list) {
- if (!nla_strcmp(nla, set->name))
- return set;
- }
- return ERR_PTR(-ENOENT);
-}
-
-static int nf_tables_set_alloc_name(struct nft_ctx *ctx, struct nft_set *set,
- const char *name)
-{
- const struct nft_set *i;
- const char *p;
- unsigned long *inuse;
- unsigned int n = 0;
-
- p = strnchr(name, IFNAMSIZ, '%');
- if (p != NULL) {
- if (p[1] != 'd' || strchr(p + 2, '%'))
- return -EINVAL;
-
- inuse = (unsigned long *)get_zeroed_page(GFP_KERNEL);
- if (inuse == NULL)
- return -ENOMEM;
-
- list_for_each_entry(i, &ctx->table->sets, list) {
- if (!sscanf(i->name, name, &n))
- continue;
- if (n < 0 || n > BITS_PER_LONG * PAGE_SIZE)
- continue;
- set_bit(n, inuse);
- }
-
- n = find_first_zero_bit(inuse, BITS_PER_LONG * PAGE_SIZE);
- free_page((unsigned long)inuse);
- }
-
- snprintf(set->name, sizeof(set->name), name, n);
- list_for_each_entry(i, &ctx->table->sets, list) {
- if (!strcmp(set->name, i->name))
- return -ENFILE;
- }
- return 0;
-}
-
-static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
- const struct nft_set *set, u16 event, u16 flags)
-{
- struct nfgenmsg *nfmsg;
- struct nlmsghdr *nlh;
- u32 portid = NETLINK_CB(ctx->skb).portid;
- u32 seq = ctx->nlh->nlmsg_seq;
-
- event |= NFNL_SUBSYS_NFTABLES << 8;
- nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
- flags);
- if (nlh == NULL)
- goto nla_put_failure;
-
- nfmsg = nlmsg_data(nlh);
- nfmsg->nfgen_family = ctx->afi->family;
- nfmsg->version = NFNETLINK_V0;
- nfmsg->res_id = 0;
-
- if (nla_put_string(skb, NFTA_SET_TABLE, ctx->table->name))
- goto nla_put_failure;
- if (nla_put_string(skb, NFTA_SET_NAME, set->name))
- goto nla_put_failure;
- if (set->flags != 0)
- if (nla_put_be32(skb, NFTA_SET_FLAGS, htonl(set->flags)))
- goto nla_put_failure;
-
- if (nla_put_be32(skb, NFTA_SET_KEY_TYPE, htonl(set->ktype)))
- goto nla_put_failure;
- if (nla_put_be32(skb, NFTA_SET_KEY_LEN, htonl(set->klen)))
- goto nla_put_failure;
- if (set->flags & NFT_SET_MAP) {
- if (nla_put_be32(skb, NFTA_SET_DATA_TYPE, htonl(set->dtype)))
- goto nla_put_failure;
- if (nla_put_be32(skb, NFTA_SET_DATA_LEN, htonl(set->dlen)))
- goto nla_put_failure;
- }
-
- return nlmsg_end(skb, nlh);
-
-nla_put_failure:
- nlmsg_trim(skb, nlh);
- return -1;
-}
-
-static int nf_tables_set_notify(const struct nft_ctx *ctx,
- const struct nft_set *set,
- int event)
-{
- struct sk_buff *skb;
- u32 portid = NETLINK_CB(ctx->skb).portid;
- bool report;
- int err;
-
- report = nlmsg_report(ctx->nlh);
- if (!report && !nfnetlink_has_listeners(ctx->net, NFNLGRP_NFTABLES))
- return 0;
-
- err = -ENOBUFS;
- skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
- if (skb == NULL)
- goto err;
-
- err = nf_tables_fill_set(skb, ctx, set, event, 0);
- if (err < 0) {
- kfree_skb(skb);
- goto err;
- }
-
- err = nfnetlink_send(skb, ctx->net, portid, NFNLGRP_NFTABLES, report,
- GFP_KERNEL);
-err:
- if (err < 0)
- nfnetlink_set_err(ctx->net, portid, NFNLGRP_NFTABLES, err);
- return err;
-}
-
-static int nf_tables_dump_sets_table(struct nft_ctx *ctx, struct sk_buff *skb,
- struct netlink_callback *cb)
-{
- const struct nft_set *set;
- unsigned int idx = 0, s_idx = cb->args[0];
-
- if (cb->args[1])
- return skb->len;
-
- list_for_each_entry(set, &ctx->table->sets, list) {
- if (idx < s_idx)
- goto cont;
- if (nf_tables_fill_set(skb, ctx, set, NFT_MSG_NEWSET,
- NLM_F_MULTI) < 0) {
- cb->args[0] = idx;
- goto done;
- }
-cont:
- idx++;
- }
- cb->args[1] = 1;
-done:
- return skb->len;
-}
-
-static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb,
- struct netlink_callback *cb)
-{
- const struct nft_set *set;
- unsigned int idx = 0, s_idx = cb->args[0];
- struct nft_table *table, *cur_table = (struct nft_table *)cb->args[2];
-
- if (cb->args[1])
- return skb->len;
-
- list_for_each_entry(table, &ctx->afi->tables, list) {
- if (cur_table && cur_table != table)
- continue;
-
- ctx->table = table;
- list_for_each_entry(set, &ctx->table->sets, list) {
- if (idx < s_idx)
- goto cont;
- if (nf_tables_fill_set(skb, ctx, set, NFT_MSG_NEWSET,
- NLM_F_MULTI) < 0) {
- cb->args[0] = idx;
- cb->args[2] = (unsigned long) table;
- goto done;
- }
-cont:
- idx++;
- }
- }
- cb->args[1] = 1;
-done:
- return skb->len;
-}
-
-static int nf_tables_dump_sets(struct sk_buff *skb, struct netlink_callback *cb)
-{
- const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
- struct nlattr *nla[NFTA_SET_MAX + 1];
- struct nft_ctx ctx;
- int err, ret;
-
- err = nlmsg_parse(cb->nlh, sizeof(*nfmsg), nla, NFTA_SET_MAX,
- nft_set_policy);
- if (err < 0)
- return err;
-
- err = nft_ctx_init_from_setattr(&ctx, cb->skb, cb->nlh, (void *)nla);
- if (err < 0)
- return err;
-
- if (ctx.table == NULL)
- ret = nf_tables_dump_sets_all(&ctx, skb, cb);
- else
- ret = nf_tables_dump_sets_table(&ctx, skb, cb);
-
- return ret;
-}
-
-static int nf_tables_getset(struct sock *nlsk, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const nla[])
-{
- const struct nft_set *set;
- struct nft_ctx ctx;
- struct sk_buff *skb2;
- int err;
-
- /* Verify existance before starting dump */
- err = nft_ctx_init_from_setattr(&ctx, skb, nlh, nla);
- if (err < 0)
- return err;
-
- if (nlh->nlmsg_flags & NLM_F_DUMP) {
- struct netlink_dump_control c = {
- .dump = nf_tables_dump_sets,
- };
- return netlink_dump_start(nlsk, skb, nlh, &c);
- }
-
- set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
- if (IS_ERR(set))
- return PTR_ERR(set);
-
- skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
- if (skb2 == NULL)
- return -ENOMEM;
-
- err = nf_tables_fill_set(skb2, &ctx, set, NFT_MSG_NEWSET, 0);
- if (err < 0)
- goto err;
-
- return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
-
-err:
- kfree_skb(skb2);
- return err;
-}
-
-static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const nla[])
-{
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- const struct nft_set_ops *ops;
- const struct nft_af_info *afi;
- struct net *net = sock_net(skb->sk);
- struct nft_table *table;
- struct nft_set *set;
- struct nft_ctx ctx;
- char name[IFNAMSIZ];
- unsigned int size;
- bool create;
- u32 ktype, klen, dlen, dtype, flags;
- int err;
-
- if (nla[NFTA_SET_TABLE] == NULL ||
- nla[NFTA_SET_NAME] == NULL ||
- nla[NFTA_SET_KEY_LEN] == NULL)
- return -EINVAL;
-
- ktype = NFT_DATA_VALUE;
- if (nla[NFTA_SET_KEY_TYPE] != NULL) {
- ktype = ntohl(nla_get_be32(nla[NFTA_SET_KEY_TYPE]));
- if ((ktype & NFT_DATA_RESERVED_MASK) == NFT_DATA_RESERVED_MASK)
- return -EINVAL;
- }
-
- klen = ntohl(nla_get_be32(nla[NFTA_SET_KEY_LEN]));
- if (klen == 0 || klen > FIELD_SIZEOF(struct nft_data, data))
- return -EINVAL;
-
- flags = 0;
- if (nla[NFTA_SET_FLAGS] != NULL) {
- flags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
- if (flags & ~(NFT_SET_ANONYMOUS | NFT_SET_CONSTANT |
- NFT_SET_INTERVAL | NFT_SET_MAP))
- return -EINVAL;
- }
-
- dtype = 0;
- dlen = 0;
- if (nla[NFTA_SET_DATA_TYPE] != NULL) {
- if (!(flags & NFT_SET_MAP))
- return -EINVAL;
-
- dtype = ntohl(nla_get_be32(nla[NFTA_SET_DATA_TYPE]));
- if ((dtype & NFT_DATA_RESERVED_MASK) == NFT_DATA_RESERVED_MASK &&
- dtype != NFT_DATA_VERDICT)
- return -EINVAL;
-
- if (dtype != NFT_DATA_VERDICT) {
- if (nla[NFTA_SET_DATA_LEN] == NULL)
- return -EINVAL;
- dlen = ntohl(nla_get_be32(nla[NFTA_SET_DATA_LEN]));
- if (dlen == 0 ||
- dlen > FIELD_SIZEOF(struct nft_data, data))
- return -EINVAL;
- } else
- dlen = sizeof(struct nft_data);
- } else if (flags & NFT_SET_MAP)
- return -EINVAL;
-
- create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
-
- afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, create);
- if (IS_ERR(afi))
- return PTR_ERR(afi);
-
- table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE]);
- if (IS_ERR(table))
- return PTR_ERR(table);
-
- nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla);
-
- set = nf_tables_set_lookup(table, nla[NFTA_SET_NAME]);
- if (IS_ERR(set)) {
- if (PTR_ERR(set) != -ENOENT)
- return PTR_ERR(set);
- set = NULL;
- }
-
- if (set != NULL) {
- if (nlh->nlmsg_flags & NLM_F_EXCL)
- return -EEXIST;
- if (nlh->nlmsg_flags & NLM_F_REPLACE)
- return -EOPNOTSUPP;
- return 0;
- }
-
- if (!(nlh->nlmsg_flags & NLM_F_CREATE))
- return -ENOENT;
-
- ops = nft_select_set_ops(nla);
- if (IS_ERR(ops))
- return PTR_ERR(ops);
-
- size = 0;
- if (ops->privsize != NULL)
- size = ops->privsize(nla);
-
- err = -ENOMEM;
- set = kzalloc(sizeof(*set) + size, GFP_KERNEL);
- if (set == NULL)
- goto err1;
-
- nla_strlcpy(name, nla[NFTA_SET_NAME], sizeof(set->name));
- err = nf_tables_set_alloc_name(&ctx, set, name);
- if (err < 0)
- goto err2;
-
- INIT_LIST_HEAD(&set->bindings);
- set->ops = ops;
- set->ktype = ktype;
- set->klen = klen;
- set->dtype = dtype;
- set->dlen = dlen;
- set->flags = flags;
-
- err = ops->init(set, nla);
- if (err < 0)
- goto err2;
-
- list_add_tail(&set->list, &table->sets);
- nf_tables_set_notify(&ctx, set, NFT_MSG_NEWSET);
- return 0;
-
-err2:
- kfree(set);
-err1:
- module_put(ops->owner);
- return err;
-}
-
-static void nf_tables_set_destroy(const struct nft_ctx *ctx, struct nft_set *set)
-{
- list_del(&set->list);
- if (!(set->flags & NFT_SET_ANONYMOUS))
- nf_tables_set_notify(ctx, set, NFT_MSG_DELSET);
-
- set->ops->destroy(set);
- module_put(set->ops->owner);
- kfree(set);
-}
-
-static int nf_tables_delset(struct sock *nlsk, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const nla[])
-{
- struct nft_set *set;
- struct nft_ctx ctx;
- int err;
-
- if (nla[NFTA_SET_TABLE] == NULL)
- return -EINVAL;
-
- err = nft_ctx_init_from_setattr(&ctx, skb, nlh, nla);
- if (err < 0)
- return err;
-
- set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
- if (IS_ERR(set))
- return PTR_ERR(set);
- if (!list_empty(&set->bindings))
- return -EBUSY;
-
- nf_tables_set_destroy(&ctx, set);
- return 0;
-}
-
-static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx,
- const struct nft_set *set,
- const struct nft_set_iter *iter,
- const struct nft_set_elem *elem)
-{
- enum nft_registers dreg;
-
- dreg = nft_type_to_reg(set->dtype);
- return nft_validate_data_load(ctx, dreg, &elem->data, set->dtype);
-}
-
-int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
- struct nft_set_binding *binding)
-{
- struct nft_set_binding *i;
- struct nft_set_iter iter;
-
- if (!list_empty(&set->bindings) && set->flags & NFT_SET_ANONYMOUS)
- return -EBUSY;
-
- if (set->flags & NFT_SET_MAP) {
- /* If the set is already bound to the same chain all
- * jumps are already validated for that chain.
- */
- list_for_each_entry(i, &set->bindings, list) {
- if (i->chain == binding->chain)
- goto bind;
- }
-
- iter.skip = 0;
- iter.count = 0;
- iter.err = 0;
- iter.fn = nf_tables_bind_check_setelem;
-
- set->ops->walk(ctx, set, &iter);
- if (iter.err < 0) {
- /* Destroy anonymous sets if binding fails */
- if (set->flags & NFT_SET_ANONYMOUS)
- nf_tables_set_destroy(ctx, set);
-
- return iter.err;
- }
- }
-bind:
- binding->chain = ctx->chain;
- list_add_tail(&binding->list, &set->bindings);
- return 0;
-}
-
-void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
- struct nft_set_binding *binding)
-{
- list_del(&binding->list);
-
- if (list_empty(&set->bindings) && set->flags & NFT_SET_ANONYMOUS)
- nf_tables_set_destroy(ctx, set);
-}
-
-/*
- * Set elements
- */
-
-static const struct nla_policy nft_set_elem_policy[NFTA_SET_ELEM_MAX + 1] = {
- [NFTA_SET_ELEM_KEY] = { .type = NLA_NESTED },
- [NFTA_SET_ELEM_DATA] = { .type = NLA_NESTED },
- [NFTA_SET_ELEM_FLAGS] = { .type = NLA_U32 },
-};
-
-static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX + 1] = {
- [NFTA_SET_ELEM_LIST_TABLE] = { .type = NLA_STRING },
- [NFTA_SET_ELEM_LIST_SET] = { .type = NLA_STRING },
- [NFTA_SET_ELEM_LIST_ELEMENTS] = { .type = NLA_NESTED },
-};
-
-static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx,
- const struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const nla[])
-{
- const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
- const struct nft_af_info *afi;
- const struct nft_table *table;
- struct net *net = sock_net(skb->sk);
-
- afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, false);
- if (IS_ERR(afi))
- return PTR_ERR(afi);
-
- table = nf_tables_table_lookup(afi, nla[NFTA_SET_ELEM_LIST_TABLE]);
- if (IS_ERR(table))
- return PTR_ERR(table);
-
- nft_ctx_init(ctx, skb, nlh, afi, table, NULL, nla);
- return 0;
-}
-
-static int nf_tables_fill_setelem(struct sk_buff *skb,
- const struct nft_set *set,
- const struct nft_set_elem *elem)
-{
- unsigned char *b = skb_tail_pointer(skb);
- struct nlattr *nest;
-
- nest = nla_nest_start(skb, NFTA_LIST_ELEM);
- if (nest == NULL)
- goto nla_put_failure;
-
- if (nft_data_dump(skb, NFTA_SET_ELEM_KEY, &elem->key, NFT_DATA_VALUE,
- set->klen) < 0)
- goto nla_put_failure;
-
- if (set->flags & NFT_SET_MAP &&
- !(elem->flags & NFT_SET_ELEM_INTERVAL_END) &&
- nft_data_dump(skb, NFTA_SET_ELEM_DATA, &elem->data,
- set->dtype == NFT_DATA_VERDICT ? NFT_DATA_VERDICT : NFT_DATA_VALUE,
- set->dlen) < 0)
- goto nla_put_failure;
-
- if (elem->flags != 0)
- if (nla_put_be32(skb, NFTA_SET_ELEM_FLAGS, htonl(elem->flags)))
- goto nla_put_failure;
-
- nla_nest_end(skb, nest);
- return 0;
-
-nla_put_failure:
- nlmsg_trim(skb, b);
- return -EMSGSIZE;
-}
-
-struct nft_set_dump_args {
- const struct netlink_callback *cb;
- struct nft_set_iter iter;
- struct sk_buff *skb;
-};
-
-static int nf_tables_dump_setelem(const struct nft_ctx *ctx,
- const struct nft_set *set,
- const struct nft_set_iter *iter,
- const struct nft_set_elem *elem)
-{
- struct nft_set_dump_args *args;
-
- args = container_of(iter, struct nft_set_dump_args, iter);
- return nf_tables_fill_setelem(args->skb, set, elem);
-}
-
-static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
-{
- const struct nft_set *set;
- struct nft_set_dump_args args;
- struct nft_ctx ctx;
- struct nlattr *nla[NFTA_SET_ELEM_LIST_MAX + 1];
- struct nfgenmsg *nfmsg;
- struct nlmsghdr *nlh;
- struct nlattr *nest;
- u32 portid, seq;
- int event, err;
-
- nfmsg = nlmsg_data(cb->nlh);
- err = nlmsg_parse(cb->nlh, sizeof(*nfmsg), nla, NFTA_SET_ELEM_LIST_MAX,
- nft_set_elem_list_policy);
- if (err < 0)
- return err;
-
- err = nft_ctx_init_from_elemattr(&ctx, cb->skb, cb->nlh, (void *)nla);
- if (err < 0)
- return err;
-
- set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
- if (IS_ERR(set))
- return PTR_ERR(set);
-
- event = NFT_MSG_NEWSETELEM;
- event |= NFNL_SUBSYS_NFTABLES << 8;
- portid = NETLINK_CB(cb->skb).portid;
- seq = cb->nlh->nlmsg_seq;
-
- nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
- NLM_F_MULTI);
- if (nlh == NULL)
- goto nla_put_failure;
-
- nfmsg = nlmsg_data(nlh);
- nfmsg->nfgen_family = NFPROTO_UNSPEC;
- nfmsg->version = NFNETLINK_V0;
- nfmsg->res_id = 0;
-
- if (nla_put_string(skb, NFTA_SET_ELEM_LIST_TABLE, ctx.table->name))
- goto nla_put_failure;
- if (nla_put_string(skb, NFTA_SET_ELEM_LIST_SET, set->name))
- goto nla_put_failure;
-
- nest = nla_nest_start(skb, NFTA_SET_ELEM_LIST_ELEMENTS);
- if (nest == NULL)
- goto nla_put_failure;
-
- args.cb = cb;
- args.skb = skb;
- args.iter.skip = cb->args[0];
- args.iter.count = 0;
- args.iter.err = 0;
- args.iter.fn = nf_tables_dump_setelem;
- set->ops->walk(&ctx, set, &args.iter);
-
- nla_nest_end(skb, nest);
- nlmsg_end(skb, nlh);
-
- if (args.iter.err && args.iter.err != -EMSGSIZE)
- return args.iter.err;
- if (args.iter.count == cb->args[0])
- return 0;
-
- cb->args[0] = args.iter.count;
- return skb->len;
-
-nla_put_failure:
- return -ENOSPC;
-}
-
-static int nf_tables_getsetelem(struct sock *nlsk, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const nla[])
-{
- const struct nft_set *set;
- struct nft_ctx ctx;
- int err;
-
- err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla);
- if (err < 0)
- return err;
-
- set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
- if (IS_ERR(set))
- return PTR_ERR(set);
-
- if (nlh->nlmsg_flags & NLM_F_DUMP) {
- struct netlink_dump_control c = {
- .dump = nf_tables_dump_set,
- };
- return netlink_dump_start(nlsk, skb, nlh, &c);
- }
- return -EOPNOTSUPP;
-}
-
-static int nft_add_set_elem(const struct nft_ctx *ctx, struct nft_set *set,
- const struct nlattr *attr)
-{
- struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
- struct nft_data_desc d1, d2;
- struct nft_set_elem elem;
- struct nft_set_binding *binding;
- enum nft_registers dreg;
- int err;
-
- err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr,
- nft_set_elem_policy);
- if (err < 0)
- return err;
-
- if (nla[NFTA_SET_ELEM_KEY] == NULL)
- return -EINVAL;
-
- elem.flags = 0;
- if (nla[NFTA_SET_ELEM_FLAGS] != NULL) {
- elem.flags = ntohl(nla_get_be32(nla[NFTA_SET_ELEM_FLAGS]));
- if (elem.flags & ~NFT_SET_ELEM_INTERVAL_END)
- return -EINVAL;
- }
-
- if (set->flags & NFT_SET_MAP) {
- if (nla[NFTA_SET_ELEM_DATA] == NULL &&
- !(elem.flags & NFT_SET_ELEM_INTERVAL_END))
- return -EINVAL;
- } else {
- if (nla[NFTA_SET_ELEM_DATA] != NULL)
- return -EINVAL;
- }
-
- err = nft_data_init(ctx, &elem.key, &d1, nla[NFTA_SET_ELEM_KEY]);
- if (err < 0)
- goto err1;
- err = -EINVAL;
- if (d1.type != NFT_DATA_VALUE || d1.len != set->klen)
- goto err2;
-
- err = -EEXIST;
- if (set->ops->get(set, &elem) == 0)
- goto err2;
-
- if (nla[NFTA_SET_ELEM_DATA] != NULL) {
- err = nft_data_init(ctx, &elem.data, &d2, nla[NFTA_SET_ELEM_DATA]);
- if (err < 0)
- goto err2;
-
- err = -EINVAL;
- if (set->dtype != NFT_DATA_VERDICT && d2.len != set->dlen)
- goto err3;
-
- dreg = nft_type_to_reg(set->dtype);
- list_for_each_entry(binding, &set->bindings, list) {
- struct nft_ctx bind_ctx = {
- .afi = ctx->afi,
- .table = ctx->table,
- .chain = binding->chain,
- };
-
- err = nft_validate_data_load(&bind_ctx, dreg,
- &elem.data, d2.type);
- if (err < 0)
- goto err3;
- }
- }
-
- err = set->ops->insert(set, &elem);
- if (err < 0)
- goto err3;
-
- return 0;
-
-err3:
- if (nla[NFTA_SET_ELEM_DATA] != NULL)
- nft_data_uninit(&elem.data, d2.type);
-err2:
- nft_data_uninit(&elem.key, d1.type);
-err1:
- return err;
-}
-
-static int nf_tables_newsetelem(struct sock *nlsk, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const nla[])
-{
- const struct nlattr *attr;
- struct nft_set *set;
- struct nft_ctx ctx;
- int rem, err;
-
- err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla);
- if (err < 0)
- return err;
-
- set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
- if (IS_ERR(set))
- return PTR_ERR(set);
- if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
- return -EBUSY;
-
- nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
- err = nft_add_set_elem(&ctx, set, attr);
- if (err < 0)
- return err;
- }
- return 0;
-}
-
-static int nft_del_setelem(const struct nft_ctx *ctx, struct nft_set *set,
- const struct nlattr *attr)
-{
- struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
- struct nft_data_desc desc;
- struct nft_set_elem elem;
- int err;
-
- err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr,
- nft_set_elem_policy);
- if (err < 0)
- goto err1;
-
- err = -EINVAL;
- if (nla[NFTA_SET_ELEM_KEY] == NULL)
- goto err1;
-
- err = nft_data_init(ctx, &elem.key, &desc, nla[NFTA_SET_ELEM_KEY]);
- if (err < 0)
- goto err1;
-
- err = -EINVAL;
- if (desc.type != NFT_DATA_VALUE || desc.len != set->klen)
- goto err2;
-
- err = set->ops->get(set, &elem);
- if (err < 0)
- goto err2;
-
- set->ops->remove(set, &elem);
-
- nft_data_uninit(&elem.key, NFT_DATA_VALUE);
- if (set->flags & NFT_SET_MAP)
- nft_data_uninit(&elem.data, set->dtype);
-
-err2:
- nft_data_uninit(&elem.key, desc.type);
-err1:
- return err;
-}
-
-static int nf_tables_delsetelem(struct sock *nlsk, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const nla[])
-{
- const struct nlattr *attr;
- struct nft_set *set;
- struct nft_ctx ctx;
- int rem, err;
-
- err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla);
- if (err < 0)
- return err;
-
- set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
- if (IS_ERR(set))
- return PTR_ERR(set);
- if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
- return -EBUSY;
-
- nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
- err = nft_del_setelem(&ctx, set, attr);
- if (err < 0)
- return err;
- }
- return 0;
-}
-
-static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
- [NFT_MSG_NEWTABLE] = {
- .call = nf_tables_newtable,
- .attr_count = NFTA_TABLE_MAX,
- .policy = nft_table_policy,
- },
- [NFT_MSG_GETTABLE] = {
- .call = nf_tables_gettable,
- .attr_count = NFTA_TABLE_MAX,
- .policy = nft_table_policy,
- },
- [NFT_MSG_DELTABLE] = {
- .call = nf_tables_deltable,
- .attr_count = NFTA_TABLE_MAX,
- .policy = nft_table_policy,
- },
- [NFT_MSG_NEWCHAIN] = {
- .call = nf_tables_newchain,
- .attr_count = NFTA_CHAIN_MAX,
- .policy = nft_chain_policy,
- },
- [NFT_MSG_GETCHAIN] = {
- .call = nf_tables_getchain,
- .attr_count = NFTA_CHAIN_MAX,
- .policy = nft_chain_policy,
- },
- [NFT_MSG_DELCHAIN] = {
- .call = nf_tables_delchain,
- .attr_count = NFTA_CHAIN_MAX,
- .policy = nft_chain_policy,
- },
- [NFT_MSG_NEWRULE] = {
- .call_batch = nf_tables_newrule,
- .attr_count = NFTA_RULE_MAX,
- .policy = nft_rule_policy,
- },
- [NFT_MSG_GETRULE] = {
- .call = nf_tables_getrule,
- .attr_count = NFTA_RULE_MAX,
- .policy = nft_rule_policy,
- },
- [NFT_MSG_DELRULE] = {
- .call_batch = nf_tables_delrule,
- .attr_count = NFTA_RULE_MAX,
- .policy = nft_rule_policy,
- },
- [NFT_MSG_NEWSET] = {
- .call = nf_tables_newset,
- .attr_count = NFTA_SET_MAX,
- .policy = nft_set_policy,
- },
- [NFT_MSG_GETSET] = {
- .call = nf_tables_getset,
- .attr_count = NFTA_SET_MAX,
- .policy = nft_set_policy,
- },
- [NFT_MSG_DELSET] = {
- .call = nf_tables_delset,
- .attr_count = NFTA_SET_MAX,
- .policy = nft_set_policy,
- },
- [NFT_MSG_NEWSETELEM] = {
- .call = nf_tables_newsetelem,
- .attr_count = NFTA_SET_ELEM_LIST_MAX,
- .policy = nft_set_elem_list_policy,
- },
- [NFT_MSG_GETSETELEM] = {
- .call = nf_tables_getsetelem,
- .attr_count = NFTA_SET_ELEM_LIST_MAX,
- .policy = nft_set_elem_list_policy,
- },
- [NFT_MSG_DELSETELEM] = {
- .call = nf_tables_delsetelem,
- .attr_count = NFTA_SET_ELEM_LIST_MAX,
- .policy = nft_set_elem_list_policy,
- },
-};
-
-static const struct nfnetlink_subsystem nf_tables_subsys = {
- .name = "nf_tables",
- .subsys_id = NFNL_SUBSYS_NFTABLES,
- .cb_count = NFT_MSG_MAX,
- .cb = nf_tables_cb,
- .commit = nf_tables_commit,
- .abort = nf_tables_abort,
-};
-
-/*
- * Loop detection - walk through the ruleset beginning at the destination chain
- * of a new jump until either the source chain is reached (loop) or all
- * reachable chains have been traversed.
- *
- * The loop check is performed whenever a new jump verdict is added to an
- * expression or verdict map or a verdict map is bound to a new chain.
- */
-
-static int nf_tables_check_loops(const struct nft_ctx *ctx,
- const struct nft_chain *chain);
-
-static int nf_tables_loop_check_setelem(const struct nft_ctx *ctx,
- const struct nft_set *set,
- const struct nft_set_iter *iter,
- const struct nft_set_elem *elem)
-{
- switch (elem->data.verdict) {
- case NFT_JUMP:
- case NFT_GOTO:
- return nf_tables_check_loops(ctx, elem->data.chain);
- default:
- return 0;
- }
-}
-
-static int nf_tables_check_loops(const struct nft_ctx *ctx,
- const struct nft_chain *chain)
-{
- const struct nft_rule *rule;
- const struct nft_expr *expr, *last;
- const struct nft_set *set;
- struct nft_set_binding *binding;
- struct nft_set_iter iter;
-
- if (ctx->chain == chain)
- return -ELOOP;
-
- list_for_each_entry(rule, &chain->rules, list) {
- nft_rule_for_each_expr(expr, last, rule) {
- const struct nft_data *data = NULL;
- int err;
-
- if (!expr->ops->validate)
- continue;
-
- err = expr->ops->validate(ctx, expr, &data);
- if (err < 0)
- return err;
-
- if (data == NULL)
- continue;
-
- switch (data->verdict) {
- case NFT_JUMP:
- case NFT_GOTO:
- err = nf_tables_check_loops(ctx, data->chain);
- if (err < 0)
- return err;
- default:
- break;
- }
- }
- }
-
- list_for_each_entry(set, &ctx->table->sets, list) {
- if (!(set->flags & NFT_SET_MAP) ||
- set->dtype != NFT_DATA_VERDICT)
- continue;
-
- list_for_each_entry(binding, &set->bindings, list) {
- if (binding->chain != chain)
- continue;
-
- iter.skip = 0;
- iter.count = 0;
- iter.err = 0;
- iter.fn = nf_tables_loop_check_setelem;
-
- set->ops->walk(ctx, set, &iter);
- if (iter.err < 0)
- return iter.err;
- }
- }
-
- return 0;
-}
-
-/**
- * nft_validate_input_register - validate an expressions' input register
- *
- * @reg: the register number
- *
- * Validate that the input register is one of the general purpose
- * registers.
- */
-int nft_validate_input_register(enum nft_registers reg)
-{
- if (reg <= NFT_REG_VERDICT)
- return -EINVAL;
- if (reg > NFT_REG_MAX)
- return -ERANGE;
- return 0;
-}
-EXPORT_SYMBOL_GPL(nft_validate_input_register);
-
-/**
- * nft_validate_output_register - validate an expressions' output register
- *
- * @reg: the register number
- *
- * Validate that the output register is one of the general purpose
- * registers or the verdict register.
- */
-int nft_validate_output_register(enum nft_registers reg)
-{
- if (reg < NFT_REG_VERDICT)
- return -EINVAL;
- if (reg > NFT_REG_MAX)
- return -ERANGE;
- return 0;
-}
-EXPORT_SYMBOL_GPL(nft_validate_output_register);
-
-/**
- * nft_validate_data_load - validate an expressions' data load
- *
- * @ctx: context of the expression performing the load
- * @reg: the destination register number
- * @data: the data to load
- * @type: the data type
- *
- * Validate that a data load uses the appropriate data type for
- * the destination register. A value of NULL for the data means
- * that its runtime gathered data, which is always of type
- * NFT_DATA_VALUE.
- */
-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 err;
-
- switch (reg) {
- case NFT_REG_VERDICT:
- if (data == NULL || type != NFT_DATA_VERDICT)
- return -EINVAL;
-
- if (data->verdict == NFT_GOTO || data->verdict == NFT_JUMP) {
- err = nf_tables_check_loops(ctx, data->chain);
- if (err < 0)
- return err;
-
- if (ctx->chain->level + 1 > data->chain->level) {
- if (ctx->chain->level + 1 == NFT_JUMP_STACK_SIZE)
- return -EMLINK;
- data->chain->level = ctx->chain->level + 1;
- }
- }
-
- return 0;
- default:
- if (data != NULL && type != NFT_DATA_VALUE)
- return -EINVAL;
- return 0;
- }
-}
-EXPORT_SYMBOL_GPL(nft_validate_data_load);
-
-static const struct nla_policy nft_verdict_policy[NFTA_VERDICT_MAX + 1] = {
- [NFTA_VERDICT_CODE] = { .type = NLA_U32 },
- [NFTA_VERDICT_CHAIN] = { .type = NLA_STRING,
- .len = NFT_CHAIN_MAXNAMELEN - 1 },
-};
-
-static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
- struct nft_data_desc *desc, const struct nlattr *nla)
-{
- struct nlattr *tb[NFTA_VERDICT_MAX + 1];
- struct nft_chain *chain;
- int err;
-
- err = nla_parse_nested(tb, NFTA_VERDICT_MAX, nla, nft_verdict_policy);
- if (err < 0)
- return err;
-
- if (!tb[NFTA_VERDICT_CODE])
- return -EINVAL;
- data->verdict = ntohl(nla_get_be32(tb[NFTA_VERDICT_CODE]));
-
- switch (data->verdict) {
- case NF_ACCEPT:
- case NF_DROP:
- case NF_QUEUE:
- case NFT_CONTINUE:
- case NFT_BREAK:
- case NFT_RETURN:
- desc->len = sizeof(data->verdict);
- break;
- case NFT_JUMP:
- case NFT_GOTO:
- if (!tb[NFTA_VERDICT_CHAIN])
- return -EINVAL;
- chain = nf_tables_chain_lookup(ctx->table,
- tb[NFTA_VERDICT_CHAIN]);
- if (IS_ERR(chain))
- return PTR_ERR(chain);
- if (chain->flags & NFT_BASE_CHAIN)
- return -EOPNOTSUPP;
-
- chain->use++;
- data->chain = chain;
- desc->len = sizeof(data);
- break;
- default:
- return -EINVAL;
- }
-
- desc->type = NFT_DATA_VERDICT;
- return 0;
-}
-
-static void nft_verdict_uninit(const struct nft_data *data)
-{
- switch (data->verdict) {
- case NFT_JUMP:
- case NFT_GOTO:
- data->chain->use--;
- break;
- }
-}
-
-static int nft_verdict_dump(struct sk_buff *skb, const struct nft_data *data)
-{
- struct nlattr *nest;
-
- nest = nla_nest_start(skb, NFTA_DATA_VERDICT);
- if (!nest)
- goto nla_put_failure;
-
- if (nla_put_be32(skb, NFTA_VERDICT_CODE, htonl(data->verdict)))
- goto nla_put_failure;
-
- switch (data->verdict) {
- case NFT_JUMP:
- case NFT_GOTO:
- if (nla_put_string(skb, NFTA_VERDICT_CHAIN, data->chain->name))
- goto nla_put_failure;
- }
- nla_nest_end(skb, nest);
- return 0;
-
-nla_put_failure:
- return -1;
-}
-
-static int nft_value_init(const struct nft_ctx *ctx, struct nft_data *data,
- struct nft_data_desc *desc, const struct nlattr *nla)
-{
- unsigned int len;
-
- len = nla_len(nla);
- if (len == 0)
- return -EINVAL;
- if (len > sizeof(data->data))
- return -EOVERFLOW;
-
- nla_memcpy(data->data, nla, sizeof(data->data));
- desc->type = NFT_DATA_VALUE;
- desc->len = len;
- return 0;
-}
-
-static int nft_value_dump(struct sk_buff *skb, const struct nft_data *data,
- unsigned int len)
-{
- return nla_put(skb, NFTA_DATA_VALUE, len, data->data);
-}
-
-static const struct nla_policy nft_data_policy[NFTA_DATA_MAX + 1] = {
- [NFTA_DATA_VALUE] = { .type = NLA_BINARY,
- .len = FIELD_SIZEOF(struct nft_data, data) },
- [NFTA_DATA_VERDICT] = { .type = NLA_NESTED },
-};
-
-/**
- * nft_data_init - parse nf_tables data netlink attributes
- *
- * @ctx: context of the expression using the data
- * @data: destination struct nft_data
- * @desc: data description
- * @nla: netlink attribute containing data
- *
- * Parse the netlink data attributes and initialize a struct nft_data.
- * The type and length of data are returned in the data description.
- *
- * The caller can indicate that it only wants to accept data of type
- * NFT_DATA_VALUE by passing NULL for the ctx argument.
- */
-int nft_data_init(const struct nft_ctx *ctx, struct nft_data *data,
- struct nft_data_desc *desc, const struct nlattr *nla)
-{
- struct nlattr *tb[NFTA_DATA_MAX + 1];
- int err;
-
- err = nla_parse_nested(tb, NFTA_DATA_MAX, nla, nft_data_policy);
- if (err < 0)
- return err;
-
- if (tb[NFTA_DATA_VALUE])
- return nft_value_init(ctx, data, desc, tb[NFTA_DATA_VALUE]);
- if (tb[NFTA_DATA_VERDICT] && ctx != NULL)
- return nft_verdict_init(ctx, data, desc, tb[NFTA_DATA_VERDICT]);
- return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(nft_data_init);
-
-/**
- * nft_data_uninit - release a nft_data item
- *
- * @data: struct nft_data to release
- * @type: type of data
- *
- * Release a nft_data item. NFT_DATA_VALUE types can be silently discarded,
- * all others need to be released by calling this function.
- */
-void nft_data_uninit(const struct nft_data *data, enum nft_data_types type)
-{
- switch (type) {
- case NFT_DATA_VALUE:
- return;
- case NFT_DATA_VERDICT:
- return nft_verdict_uninit(data);
- default:
- WARN_ON(1);
- }
-}
-EXPORT_SYMBOL_GPL(nft_data_uninit);
-
-int nft_data_dump(struct sk_buff *skb, int attr, const struct nft_data *data,
- enum nft_data_types type, unsigned int len)
-{
- struct nlattr *nest;
- int err;
-
- nest = nla_nest_start(skb, attr);
- if (nest == NULL)
- return -1;
-
- switch (type) {
- case NFT_DATA_VALUE:
- err = nft_value_dump(skb, data, len);
- break;
- case NFT_DATA_VERDICT:
- err = nft_verdict_dump(skb, data);
- break;
- default:
- err = -EINVAL;
- WARN_ON(1);
- }
-
- nla_nest_end(skb, nest);
- return err;
-}
-EXPORT_SYMBOL_GPL(nft_data_dump);
-
-static int nf_tables_init_net(struct net *net)
-{
- INIT_LIST_HEAD(&net->nft.af_info);
- INIT_LIST_HEAD(&net->nft.commit_list);
- return 0;
-}
-
-static struct pernet_operations nf_tables_net_ops = {
- .init = nf_tables_init_net,
-};
-
-static int __init nf_tables_module_init(void)
-{
- int err;
-
- info = kmalloc(sizeof(struct nft_expr_info) * NFT_RULE_MAXEXPRS,
- GFP_KERNEL);
- if (info == NULL) {
- err = -ENOMEM;
- goto err1;
- }
-
- err = nf_tables_core_module_init();
- if (err < 0)
- goto err2;
-
- err = nfnetlink_subsys_register(&nf_tables_subsys);
- if (err < 0)
- goto err3;
-
- pr_info("nf_tables: (c) 2007-2009 Patrick McHardy <kaber@trash.net>\n");
- return register_pernet_subsys(&nf_tables_net_ops);
-err3:
- nf_tables_core_module_exit();
-err2:
- kfree(info);
-err1:
- return err;
-}
-
-static void __exit nf_tables_module_exit(void)
-{
- unregister_pernet_subsys(&nf_tables_net_ops);
- nfnetlink_subsys_unregister(&nf_tables_subsys);
- nf_tables_core_module_exit();
- kfree(info);
-}
-
-module_init(nf_tables_module_init);
-module_exit(nf_tables_module_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
-MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_NFTABLES);
diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c
deleted file mode 100644
index cb9e685..0000000
--- a/net/netfilter/nf_tables_core.c
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright (c) 2008 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/module.h>
-#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/rculist.h>
-#include <linux/skbuff.h>
-#include <linux/netlink.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter/nfnetlink.h>
-#include <linux/netfilter/nf_tables.h>
-#include <net/netfilter/nf_tables_core.h>
-#include <net/netfilter/nf_tables.h>
-#include <net/netfilter/nf_log.h>
-
-static void nft_cmp_fast_eval(const struct nft_expr *expr,
- struct nft_data data[NFT_REG_MAX + 1])
-{
- const struct nft_cmp_fast_expr *priv = nft_expr_priv(expr);
- u32 mask;
-
- mask = ~0U >> (sizeof(priv->data) * BITS_PER_BYTE - priv->len);
- if ((data[priv->sreg].data[0] & mask) == priv->data)
- return;
- data[NFT_REG_VERDICT].verdict = NFT_BREAK;
-}
-
-static bool nft_payload_fast_eval(const struct nft_expr *expr,
- struct nft_data data[NFT_REG_MAX + 1],
- const struct nft_pktinfo *pkt)
-{
- const struct nft_payload *priv = nft_expr_priv(expr);
- const struct sk_buff *skb = pkt->skb;
- struct nft_data *dest = &data[priv->dreg];
- unsigned char *ptr;
-
- if (priv->base == NFT_PAYLOAD_NETWORK_HEADER)
- ptr = skb_network_header(skb);
- else
- ptr = skb_network_header(skb) + pkt->xt.thoff;
-
- ptr += priv->offset;
-
- if (unlikely(ptr + priv->len >= skb_tail_pointer(skb)))
- return false;
-
- if (priv->len == 2)
- *(u16 *)dest->data = *(u16 *)ptr;
- else if (priv->len == 4)
- *(u32 *)dest->data = *(u32 *)ptr;
- else
- *(u8 *)dest->data = *(u8 *)ptr;
- return true;
-}
-
-struct nft_jumpstack {
- const struct nft_chain *chain;
- const struct nft_rule *rule;
- int rulenum;
-};
-
-static inline void
-nft_chain_stats(const struct nft_chain *this, const struct nft_pktinfo *pkt,
- struct nft_jumpstack *jumpstack, unsigned int stackptr)
-{
- struct nft_stats __percpu *stats;
- const struct nft_chain *chain = stackptr ? jumpstack[0].chain : this;
-
- rcu_read_lock_bh();
- stats = rcu_dereference(nft_base_chain(chain)->stats);
- __this_cpu_inc(stats->pkts);
- __this_cpu_add(stats->bytes, pkt->skb->len);
- rcu_read_unlock_bh();
-}
-
-enum nft_trace {
- NFT_TRACE_RULE,
- NFT_TRACE_RETURN,
- NFT_TRACE_POLICY,
-};
-
-static const char *const comments[] = {
- [NFT_TRACE_RULE] = "rule",
- [NFT_TRACE_RETURN] = "return",
- [NFT_TRACE_POLICY] = "policy",
-};
-
-static struct nf_loginfo trace_loginfo = {
- .type = NF_LOG_TYPE_LOG,
- .u = {
- .log = {
- .level = 4,
- .logflags = NF_LOG_MASK,
- },
- },
-};
-
-static inline void nft_trace_packet(const struct nft_pktinfo *pkt,
- const struct nft_chain *chain,
- int rulenum, enum nft_trace type)
-{
- struct net *net = dev_net(pkt->in ? pkt->in : pkt->out);
-
- nf_log_packet(net, pkt->xt.family, pkt->hooknum, pkt->skb, pkt->in,
- pkt->out, &trace_loginfo, "TRACE: %s:%s:%s:%u ",
- chain->table->name, chain->name, comments[type],
- rulenum);
-}
-
-unsigned int
-nft_do_chain_pktinfo(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops)
-{
- const struct nft_chain *chain = ops->priv;
- const struct nft_rule *rule;
- const struct nft_expr *expr, *last;
- struct nft_data data[NFT_REG_MAX + 1];
- unsigned int stackptr = 0;
- struct nft_jumpstack jumpstack[NFT_JUMP_STACK_SIZE];
- int rulenum = 0;
- /*
- * Cache cursor to avoid problems in case that the cursor is updated
- * while traversing the ruleset.
- */
- unsigned int gencursor = ACCESS_ONCE(chain->net->nft.gencursor);
-
-do_chain:
- rule = list_entry(&chain->rules, struct nft_rule, list);
-next_rule:
- data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
- list_for_each_entry_continue_rcu(rule, &chain->rules, list) {
-
- /* This rule is not active, skip. */
- if (unlikely(rule->genmask & (1 << gencursor)))
- continue;
-
- rulenum++;
-
- nft_rule_for_each_expr(expr, last, rule) {
- if (expr->ops == &nft_cmp_fast_ops)
- nft_cmp_fast_eval(expr, data);
- else if (expr->ops != &nft_payload_fast_ops ||
- !nft_payload_fast_eval(expr, data, pkt))
- expr->ops->eval(expr, data, pkt);
-
- if (data[NFT_REG_VERDICT].verdict != NFT_CONTINUE)
- break;
- }
-
- switch (data[NFT_REG_VERDICT].verdict) {
- case NFT_BREAK:
- data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
- /* fall through */
- case NFT_CONTINUE:
- continue;
- }
- break;
- }
-
- switch (data[NFT_REG_VERDICT].verdict) {
- case NF_ACCEPT:
- case NF_DROP:
- case NF_QUEUE:
- if (unlikely(pkt->skb->nf_trace))
- nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
-
- return data[NFT_REG_VERDICT].verdict;
- case NFT_JUMP:
- if (unlikely(pkt->skb->nf_trace))
- nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RULE);
-
- BUG_ON(stackptr >= NFT_JUMP_STACK_SIZE);
- jumpstack[stackptr].chain = chain;
- jumpstack[stackptr].rule = rule;
- jumpstack[stackptr].rulenum = rulenum;
- stackptr++;
- /* fall through */
- case NFT_GOTO:
- chain = data[NFT_REG_VERDICT].chain;
- goto do_chain;
- case NFT_RETURN:
- if (unlikely(pkt->skb->nf_trace))
- nft_trace_packet(pkt, chain, rulenum, NFT_TRACE_RETURN);
-
- /* fall through */
- case NFT_CONTINUE:
- break;
- default:
- WARN_ON(1);
- }
-
- if (stackptr > 0) {
- if (unlikely(pkt->skb->nf_trace))
- nft_trace_packet(pkt, chain, ++rulenum, NFT_TRACE_RETURN);
-
- stackptr--;
- chain = jumpstack[stackptr].chain;
- rule = jumpstack[stackptr].rule;
- rulenum = jumpstack[stackptr].rulenum;
- goto next_rule;
- }
- nft_chain_stats(chain, pkt, jumpstack, stackptr);
-
- if (unlikely(pkt->skb->nf_trace))
- nft_trace_packet(pkt, chain, ++rulenum, NFT_TRACE_POLICY);
-
- return nft_base_chain(chain)->policy;
-}
-EXPORT_SYMBOL_GPL(nft_do_chain_pktinfo);
-
-int __init nf_tables_core_module_init(void)
-{
- int err;
-
- err = nft_immediate_module_init();
- if (err < 0)
- goto err1;
-
- err = nft_cmp_module_init();
- if (err < 0)
- goto err2;
-
- err = nft_lookup_module_init();
- if (err < 0)
- goto err3;
-
- err = nft_bitwise_module_init();
- if (err < 0)
- goto err4;
-
- err = nft_byteorder_module_init();
- if (err < 0)
- goto err5;
-
- err = nft_payload_module_init();
- if (err < 0)
- goto err6;
-
- return 0;
-
-err6:
- nft_byteorder_module_exit();
-err5:
- nft_bitwise_module_exit();
-err4:
- nft_lookup_module_exit();
-err3:
- nft_cmp_module_exit();
-err2:
- nft_immediate_module_exit();
-err1:
- return err;
-}
-
-void nf_tables_core_module_exit(void)
-{
- nft_payload_module_exit();
- nft_byteorder_module_exit();
- nft_bitwise_module_exit();
- nft_lookup_module_exit();
- nft_cmp_module_exit();
- nft_immediate_module_exit();
-}
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index 046aa13..572d87d 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -147,6 +147,9 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
const struct nfnetlink_subsystem *ss;
int type, err;
+ if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
+ return -EPERM;
+
/* All the messages must at least contain nfgenmsg */
if (nlmsg_len(nlh) < sizeof(struct nfgenmsg))
return 0;
@@ -214,181 +217,9 @@ replay:
}
}
-static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh,
- u_int16_t subsys_id)
-{
- struct sk_buff *nskb, *oskb = skb;
- struct net *net = sock_net(skb->sk);
- const struct nfnetlink_subsystem *ss;
- const struct nfnl_callback *nc;
- bool success = true, done = false;
- int err;
-
- if (subsys_id >= NFNL_SUBSYS_COUNT)
- return netlink_ack(skb, nlh, -EINVAL);
-replay:
- nskb = netlink_skb_clone(oskb, GFP_KERNEL);
- if (!nskb)
- return netlink_ack(oskb, nlh, -ENOMEM);
-
- nskb->sk = oskb->sk;
- skb = nskb;
-
- nfnl_lock(subsys_id);
- ss = rcu_dereference_protected(table[subsys_id].subsys,
- lockdep_is_held(&table[subsys_id].mutex));
- if (!ss) {
-#ifdef CONFIG_MODULES
- nfnl_unlock(subsys_id);
- request_module("nfnetlink-subsys-%d", subsys_id);
- nfnl_lock(subsys_id);
- ss = rcu_dereference_protected(table[subsys_id].subsys,
- lockdep_is_held(&table[subsys_id].mutex));
- if (!ss)
-#endif
- {
- nfnl_unlock(subsys_id);
- kfree_skb(nskb);
- return netlink_ack(skb, nlh, -EOPNOTSUPP);
- }
- }
-
- if (!ss->commit || !ss->abort) {
- nfnl_unlock(subsys_id);
- kfree_skb(nskb);
- return netlink_ack(skb, nlh, -EOPNOTSUPP);
- }
-
- while (skb->len >= nlmsg_total_size(0)) {
- int msglen, type;
-
- nlh = nlmsg_hdr(skb);
- err = 0;
-
- if (nlh->nlmsg_len < NLMSG_HDRLEN) {
- err = -EINVAL;
- goto ack;
- }
-
- /* Only requests are handled by the kernel */
- if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) {
- err = -EINVAL;
- goto ack;
- }
-
- type = nlh->nlmsg_type;
- if (type == NFNL_MSG_BATCH_BEGIN) {
- /* Malformed: Batch begin twice */
- success = false;
- goto done;
- } else if (type == NFNL_MSG_BATCH_END) {
- done = true;
- goto done;
- } else if (type < NLMSG_MIN_TYPE) {
- err = -EINVAL;
- goto ack;
- }
-
- /* We only accept a batch with messages for the same
- * subsystem.
- */
- if (NFNL_SUBSYS_ID(type) != subsys_id) {
- err = -EINVAL;
- goto ack;
- }
-
- nc = nfnetlink_find_client(type, ss);
- if (!nc) {
- err = -EINVAL;
- goto ack;
- }
-
- {
- int min_len = nlmsg_total_size(sizeof(struct nfgenmsg));
- u_int8_t cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type);
- struct nlattr *cda[ss->cb[cb_id].attr_count + 1];
- struct nlattr *attr = (void *)nlh + min_len;
- int attrlen = nlh->nlmsg_len - min_len;
-
- err = nla_parse(cda, ss->cb[cb_id].attr_count,
- attr, attrlen, ss->cb[cb_id].policy);
- if (err < 0)
- goto ack;
-
- if (nc->call_batch) {
- err = nc->call_batch(net->nfnl, skb, nlh,
- (const struct nlattr **)cda);
- }
-
- /* The lock was released to autoload some module, we
- * have to abort and start from scratch using the
- * original skb.
- */
- if (err == -EAGAIN) {
- ss->abort(skb);
- nfnl_unlock(subsys_id);
- kfree_skb(nskb);
- goto replay;
- }
- }
-ack:
- if (nlh->nlmsg_flags & NLM_F_ACK || err) {
- /* We don't stop processing the batch on errors, thus,
- * userspace gets all the errors that the batch
- * triggers.
- */
- netlink_ack(skb, nlh, err);
- if (err)
- success = false;
- }
-
- msglen = NLMSG_ALIGN(nlh->nlmsg_len);
- if (msglen > skb->len)
- msglen = skb->len;
- skb_pull(skb, msglen);
- }
-done:
- if (success && done)
- ss->commit(skb);
- else
- ss->abort(skb);
-
- nfnl_unlock(subsys_id);
- kfree_skb(nskb);
-}
-
static void nfnetlink_rcv(struct sk_buff *skb)
{
- struct nlmsghdr *nlh = nlmsg_hdr(skb);
- struct net *net = sock_net(skb->sk);
- int msglen;
-
- if (nlh->nlmsg_len < NLMSG_HDRLEN ||
- skb->len < nlh->nlmsg_len)
- return;
-
- if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) {
- netlink_ack(skb, nlh, -EPERM);
- return;
- }
-
- if (nlh->nlmsg_type == NFNL_MSG_BATCH_BEGIN) {
- struct nfgenmsg *nfgenmsg;
-
- msglen = NLMSG_ALIGN(nlh->nlmsg_len);
- if (msglen > skb->len)
- msglen = skb->len;
-
- if (nlh->nlmsg_len < NLMSG_HDRLEN ||
- skb->len < NLMSG_HDRLEN + sizeof(struct nfgenmsg))
- return;
-
- nfgenmsg = nlmsg_data(nlh);
- skb_pull(skb, msglen);
- nfnetlink_rcv_batch(skb, nlh, nfgenmsg->res_id);
- } else {
- netlink_rcv_skb(skb, &nfnetlink_rcv_msg);
- }
+ netlink_rcv_skb(skb, &nfnetlink_rcv_msg);
}
#ifdef CONFIG_MODULES
diff --git a/net/netfilter/nfnetlink_cttimeout.c b/net/netfilter/nfnetlink_cttimeout.c
index 476accd..5058049 100644
--- a/net/netfilter/nfnetlink_cttimeout.c
+++ b/net/netfilter/nfnetlink_cttimeout.c
@@ -49,8 +49,10 @@ static const struct nla_policy cttimeout_nla_policy[CTA_TIMEOUT_MAX+1] = {
};
static int
-ctnl_timeout_parse_policy(void *timeouts, struct nf_conntrack_l4proto *l4proto,
- struct net *net, const struct nlattr *attr)
+ctnl_timeout_parse_policy(struct ctnl_timeout *timeout,
+ struct nf_conntrack_l4proto *l4proto,
+ struct net *net,
+ const struct nlattr *attr)
{
int ret = 0;
@@ -62,7 +64,8 @@ ctnl_timeout_parse_policy(void *timeouts, struct nf_conntrack_l4proto *l4proto,
if (ret < 0)
return ret;
- ret = l4proto->ctnl_timeout.nlattr_to_obj(tb, net, timeouts);
+ ret = l4proto->ctnl_timeout.nlattr_to_obj(tb, net,
+ &timeout->data);
}
return ret;
}
@@ -120,8 +123,7 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb,
goto err_proto_put;
}
- ret = ctnl_timeout_parse_policy(&matching->data,
- l4proto, net,
+ ret = ctnl_timeout_parse_policy(matching, l4proto, net,
cda[CTA_TIMEOUT_DATA]);
return ret;
}
@@ -136,7 +138,7 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb,
goto err_proto_put;
}
- ret = ctnl_timeout_parse_policy(&timeout->data, l4proto, net,
+ ret = ctnl_timeout_parse_policy(timeout, l4proto, net,
cda[CTA_TIMEOUT_DATA]);
if (ret < 0)
goto err;
@@ -340,147 +342,6 @@ cttimeout_del_timeout(struct sock *ctnl, struct sk_buff *skb,
return ret;
}
-static int
-cttimeout_default_set(struct sock *ctnl, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const cda[])
-{
- __u16 l3num;
- __u8 l4num;
- struct nf_conntrack_l4proto *l4proto;
- struct net *net = sock_net(skb->sk);
- unsigned int *timeouts;
- int ret;
-
- if (!cda[CTA_TIMEOUT_L3PROTO] ||
- !cda[CTA_TIMEOUT_L4PROTO] ||
- !cda[CTA_TIMEOUT_DATA])
- return -EINVAL;
-
- l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO]));
- l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]);
- l4proto = nf_ct_l4proto_find_get(l3num, l4num);
-
- /* This protocol is not supported, skip. */
- if (l4proto->l4proto != l4num) {
- ret = -EOPNOTSUPP;
- goto err;
- }
-
- timeouts = l4proto->get_timeouts(net);
-
- ret = ctnl_timeout_parse_policy(timeouts, l4proto, net,
- cda[CTA_TIMEOUT_DATA]);
- if (ret < 0)
- goto err;
-
- nf_ct_l4proto_put(l4proto);
- return 0;
-err:
- nf_ct_l4proto_put(l4proto);
- return ret;
-}
-
-static int
-cttimeout_default_fill_info(struct net *net, struct sk_buff *skb, u32 portid,
- u32 seq, u32 type, int event,
- struct nf_conntrack_l4proto *l4proto)
-{
- struct nlmsghdr *nlh;
- struct nfgenmsg *nfmsg;
- unsigned int flags = portid ? NLM_F_MULTI : 0;
-
- event |= NFNL_SUBSYS_CTNETLINK_TIMEOUT << 8;
- nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
- if (nlh == NULL)
- goto nlmsg_failure;
-
- nfmsg = nlmsg_data(nlh);
- nfmsg->nfgen_family = AF_UNSPEC;
- nfmsg->version = NFNETLINK_V0;
- nfmsg->res_id = 0;
-
- if (nla_put_be16(skb, CTA_TIMEOUT_L3PROTO, htons(l4proto->l3proto)) ||
- nla_put_u8(skb, CTA_TIMEOUT_L4PROTO, l4proto->l4proto))
- goto nla_put_failure;
-
- if (likely(l4proto->ctnl_timeout.obj_to_nlattr)) {
- struct nlattr *nest_parms;
- unsigned int *timeouts = l4proto->get_timeouts(net);
- int ret;
-
- nest_parms = nla_nest_start(skb,
- CTA_TIMEOUT_DATA | NLA_F_NESTED);
- if (!nest_parms)
- goto nla_put_failure;
-
- ret = l4proto->ctnl_timeout.obj_to_nlattr(skb, timeouts);
- if (ret < 0)
- goto nla_put_failure;
-
- nla_nest_end(skb, nest_parms);
- }
-
- nlmsg_end(skb, nlh);
- return skb->len;
-
-nlmsg_failure:
-nla_put_failure:
- nlmsg_cancel(skb, nlh);
- return -1;
-}
-
-static int cttimeout_default_get(struct sock *ctnl, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
- const struct nlattr * const cda[])
-{
- __u16 l3num;
- __u8 l4num;
- struct nf_conntrack_l4proto *l4proto;
- struct net *net = sock_net(skb->sk);
- struct sk_buff *skb2;
- int ret, err;
-
- if (!cda[CTA_TIMEOUT_L3PROTO] || !cda[CTA_TIMEOUT_L4PROTO])
- return -EINVAL;
-
- l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO]));
- l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]);
- l4proto = nf_ct_l4proto_find_get(l3num, l4num);
-
- /* This protocol is not supported, skip. */
- if (l4proto->l4proto != l4num) {
- err = -EOPNOTSUPP;
- goto err;
- }
-
- skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
- if (skb2 == NULL) {
- err = -ENOMEM;
- goto err;
- }
-
- ret = cttimeout_default_fill_info(net, skb2, NETLINK_CB(skb).portid,
- nlh->nlmsg_seq,
- NFNL_MSG_TYPE(nlh->nlmsg_type),
- IPCTNL_MSG_TIMEOUT_DEFAULT_SET,
- l4proto);
- if (ret <= 0) {
- kfree_skb(skb2);
- err = -ENOMEM;
- goto err;
- }
- ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT);
- if (ret > 0)
- ret = 0;
-
- /* this avoids a loop in nfnetlink. */
- return ret == -EAGAIN ? -ENOBUFS : ret;
-err:
- nf_ct_l4proto_put(l4proto);
- return err;
-}
-
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
static struct ctnl_timeout *ctnl_timeout_find_get(const char *name)
{
@@ -523,12 +384,6 @@ static const struct nfnl_callback cttimeout_cb[IPCTNL_MSG_TIMEOUT_MAX] = {
[IPCTNL_MSG_TIMEOUT_DELETE] = { .call = cttimeout_del_timeout,
.attr_count = CTA_TIMEOUT_MAX,
.policy = cttimeout_nla_policy },
- [IPCTNL_MSG_TIMEOUT_DEFAULT_SET]= { .call = cttimeout_default_set,
- .attr_count = CTA_TIMEOUT_MAX,
- .policy = cttimeout_nla_policy },
- [IPCTNL_MSG_TIMEOUT_DEFAULT_GET]= { .call = cttimeout_default_get,
- .attr_count = CTA_TIMEOUT_MAX,
- .policy = cttimeout_nla_policy },
};
static const struct nfnetlink_subsystem cttimeout_subsys = {
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index 3c4b69e..d92cc31 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -319,8 +319,7 @@ nfulnl_set_flags(struct nfulnl_instance *inst, u_int16_t flags)
}
static struct sk_buff *
-nfulnl_alloc_skb(struct net *net, u32 peer_portid, unsigned int inst_size,
- unsigned int pkt_size)
+nfulnl_alloc_skb(u32 peer_portid, unsigned int inst_size, unsigned int pkt_size)
{
struct sk_buff *skb;
unsigned int n;
@@ -329,13 +328,13 @@ nfulnl_alloc_skb(struct net *net, u32 peer_portid, unsigned int inst_size,
* message. WARNING: has to be <= 128k due to slab restrictions */
n = max(inst_size, pkt_size);
- skb = nfnetlink_alloc_skb(net, n, peer_portid, GFP_ATOMIC);
+ skb = nfnetlink_alloc_skb(&init_net, n, peer_portid, GFP_ATOMIC);
if (!skb) {
if (n > pkt_size) {
/* try to allocate only as much as we need for current
* packet */
- skb = nfnetlink_alloc_skb(net, pkt_size,
+ skb = nfnetlink_alloc_skb(&init_net, pkt_size,
peer_portid, GFP_ATOMIC);
if (!skb)
pr_err("nfnetlink_log: can't even alloc %u bytes\n",
@@ -703,8 +702,8 @@ nfulnl_log_packet(struct net *net,
}
if (!inst->skb) {
- inst->skb = nfulnl_alloc_skb(net, inst->peer_portid,
- inst->nlbufsiz, size);
+ inst->skb = nfulnl_alloc_skb(inst->peer_portid, inst->nlbufsiz,
+ size);
if (!inst->skb)
goto alloc_failure;
}
diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c
index 21258cf..ae2e5c1 100644
--- a/net/netfilter/nfnetlink_queue_core.c
+++ b/net/netfilter/nfnetlink_queue_core.c
@@ -298,7 +298,7 @@ nfqnl_put_packet_info(struct sk_buff *nlskb, struct sk_buff *packet,
}
static struct sk_buff *
-nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
+nfqnl_build_packet_message(struct nfqnl_instance *queue,
struct nf_queue_entry *entry,
__be32 **packet_id_ptr)
{
@@ -372,7 +372,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
if (queue->flags & NFQA_CFG_F_CONNTRACK)
ct = nfqnl_ct_get(entskb, &size, &ctinfo);
- skb = nfnetlink_alloc_skb(net, size, queue->peer_portid,
+ skb = nfnetlink_alloc_skb(&init_net, size, queue->peer_portid,
GFP_ATOMIC);
if (!skb)
return NULL;
@@ -525,7 +525,7 @@ __nfqnl_enqueue_packet(struct net *net, struct nfqnl_instance *queue,
__be32 *packet_id_ptr;
int failopen = 0;
- nskb = nfqnl_build_packet_message(net, queue, entry, &packet_id_ptr);
+ nskb = nfqnl_build_packet_message(queue, entry, &packet_id_ptr);
if (nskb == NULL) {
err = -ENOMEM;
goto err_out;
diff --git a/net/netfilter/nft_bitwise.c b/net/netfilter/nft_bitwise.c
deleted file mode 100644
index 4fb6ee2..0000000
--- a/net/netfilter/nft_bitwise.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Development of this code funded by Astaro AG (http://www.astaro.com/)
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/netlink.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter/nf_tables.h>
-#include <net/netfilter/nf_tables_core.h>
-#include <net/netfilter/nf_tables.h>
-
-struct nft_bitwise {
- enum nft_registers sreg:8;
- enum nft_registers dreg:8;
- u8 len;
- struct nft_data mask;
- struct nft_data xor;
-};
-
-static void nft_bitwise_eval(const struct nft_expr *expr,
- struct nft_data data[NFT_REG_MAX + 1],
- const struct nft_pktinfo *pkt)
-{
- const struct nft_bitwise *priv = nft_expr_priv(expr);
- const struct nft_data *src = &data[priv->sreg];
- struct nft_data *dst = &data[priv->dreg];
- unsigned int i;
-
- for (i = 0; i < DIV_ROUND_UP(priv->len, 4); i++) {
- dst->data[i] = (src->data[i] & priv->mask.data[i]) ^
- priv->xor.data[i];
- }
-}
-
-static const struct nla_policy nft_bitwise_policy[NFTA_BITWISE_MAX + 1] = {
- [NFTA_BITWISE_SREG] = { .type = NLA_U32 },
- [NFTA_BITWISE_DREG] = { .type = NLA_U32 },
- [NFTA_BITWISE_LEN] = { .type = NLA_U32 },
- [NFTA_BITWISE_MASK] = { .type = NLA_NESTED },
- [NFTA_BITWISE_XOR] = { .type = NLA_NESTED },
-};
-
-static int nft_bitwise_init(const struct nft_ctx *ctx,
- const struct nft_expr *expr,
- const struct nlattr * const tb[])
-{
- struct nft_bitwise *priv = nft_expr_priv(expr);
- struct nft_data_desc d1, d2;
- int err;
-
- if (tb[NFTA_BITWISE_SREG] == NULL ||
- tb[NFTA_BITWISE_DREG] == NULL ||
- tb[NFTA_BITWISE_LEN] == NULL ||
- tb[NFTA_BITWISE_MASK] == NULL ||
- tb[NFTA_BITWISE_XOR] == NULL)
- return -EINVAL;
-
- priv->sreg = ntohl(nla_get_be32(tb[NFTA_BITWISE_SREG]));
- err = nft_validate_input_register(priv->sreg);
- if (err < 0)
- return err;
-
- priv->dreg = ntohl(nla_get_be32(tb[NFTA_BITWISE_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->len = ntohl(nla_get_be32(tb[NFTA_BITWISE_LEN]));
-
- err = nft_data_init(NULL, &priv->mask, &d1, tb[NFTA_BITWISE_MASK]);
- if (err < 0)
- return err;
- if (d1.len != priv->len)
- return -EINVAL;
-
- err = nft_data_init(NULL, &priv->xor, &d2, tb[NFTA_BITWISE_XOR]);
- if (err < 0)
- return err;
- if (d2.len != priv->len)
- return -EINVAL;
-
- return 0;
-}
-
-static int nft_bitwise_dump(struct sk_buff *skb, const struct nft_expr *expr)
-{
- const struct nft_bitwise *priv = nft_expr_priv(expr);
-
- if (nla_put_be32(skb, NFTA_BITWISE_SREG, htonl(priv->sreg)))
- goto nla_put_failure;
- if (nla_put_be32(skb, NFTA_BITWISE_DREG, htonl(priv->dreg)))
- goto nla_put_failure;
- if (nla_put_be32(skb, NFTA_BITWISE_LEN, htonl(priv->len)))
- goto nla_put_failure;
-
- if (nft_data_dump(skb, NFTA_BITWISE_MASK, &priv->mask,
- NFT_DATA_VALUE, priv->len) < 0)
- goto nla_put_failure;
-
- if (nft_data_dump(skb, NFTA_BITWISE_XOR, &priv->xor,
- NFT_DATA_VALUE, priv->len) < 0)
- goto nla_put_failure;
-
- return 0;
-
-nla_put_failure:
- return -1;
-}
-
-static struct nft_expr_type nft_bitwise_type;
-static const struct nft_expr_ops nft_bitwise_ops = {
- .type = &nft_bitwise_type,
- .size = NFT_EXPR_SIZE(sizeof(struct nft_bitwise)),
- .eval = nft_bitwise_eval,
- .init = nft_bitwise_init,
- .dump = nft_bitwise_dump,
-};
-
-static struct nft_expr_type nft_bitwise_type __read_mostly = {
- .name = "bitwise",
- .ops = &nft_bitwise_ops,
- .policy = nft_bitwise_policy,
- .maxattr = NFTA_BITWISE_MAX,
- .owner = THIS_MODULE,
-};
-
-int __init nft_bitwise_module_init(void)
-{
- return nft_register_expr(&nft_bitwise_type);
-}
-
-void nft_bitwise_module_exit(void)
-{
- nft_unregister_expr(&nft_bitwise_type);
-}
diff --git a/net/netfilter/nft_byteorder.c b/net/netfilter/nft_byteorder.c
deleted file mode 100644
index c39ed8d..0000000
--- a/net/netfilter/nft_byteorder.c
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Development of this code funded by Astaro AG (http://www.astaro.com/)
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/netlink.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter/nf_tables.h>
-#include <net/netfilter/nf_tables_core.h>
-#include <net/netfilter/nf_tables.h>
-
-struct nft_byteorder {
- enum nft_registers sreg:8;
- enum nft_registers dreg:8;
- enum nft_byteorder_ops op:8;
- u8 len;
- u8 size;
-};
-
-static void nft_byteorder_eval(const struct nft_expr *expr,
- struct nft_data data[NFT_REG_MAX + 1],
- const struct nft_pktinfo *pkt)
-{
- const struct nft_byteorder *priv = nft_expr_priv(expr);
- struct nft_data *src = &data[priv->sreg], *dst = &data[priv->dreg];
- union { u32 u32; u16 u16; } *s, *d;
- unsigned int i;
-
- s = (void *)src->data;
- d = (void *)dst->data;
-
- switch (priv->size) {
- case 4:
- switch (priv->op) {
- case NFT_BYTEORDER_NTOH:
- for (i = 0; i < priv->len / 4; i++)
- d[i].u32 = ntohl((__force __be32)s[i].u32);
- break;
- case NFT_BYTEORDER_HTON:
- for (i = 0; i < priv->len / 4; i++)
- d[i].u32 = (__force __u32)htonl(s[i].u32);
- break;
- }
- break;
- case 2:
- switch (priv->op) {
- case NFT_BYTEORDER_NTOH:
- for (i = 0; i < priv->len / 2; i++)
- d[i].u16 = ntohs((__force __be16)s[i].u16);
- break;
- case NFT_BYTEORDER_HTON:
- for (i = 0; i < priv->len / 2; i++)
- d[i].u16 = (__force __u16)htons(s[i].u16);
- break;
- }
- break;
- }
-}
-
-static const struct nla_policy nft_byteorder_policy[NFTA_BYTEORDER_MAX + 1] = {
- [NFTA_BYTEORDER_SREG] = { .type = NLA_U32 },
- [NFTA_BYTEORDER_DREG] = { .type = NLA_U32 },
- [NFTA_BYTEORDER_OP] = { .type = NLA_U32 },
- [NFTA_BYTEORDER_LEN] = { .type = NLA_U32 },
- [NFTA_BYTEORDER_SIZE] = { .type = NLA_U32 },
-};
-
-static int nft_byteorder_init(const struct nft_ctx *ctx,
- const struct nft_expr *expr,
- const struct nlattr * const tb[])
-{
- struct nft_byteorder *priv = nft_expr_priv(expr);
- int err;
-
- if (tb[NFTA_BYTEORDER_SREG] == NULL ||
- tb[NFTA_BYTEORDER_DREG] == NULL ||
- tb[NFTA_BYTEORDER_LEN] == NULL ||
- tb[NFTA_BYTEORDER_SIZE] == NULL ||
- tb[NFTA_BYTEORDER_OP] == NULL)
- return -EINVAL;
-
- priv->sreg = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_SREG]));
- err = nft_validate_input_register(priv->sreg);
- if (err < 0)
- return err;
-
- priv->dreg = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_DREG]));
- err = nft_validate_output_register(priv->dreg);
- if (err < 0)
- return err;
- err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
- if (err < 0)
- return err;
-
- priv->op = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_OP]));
- switch (priv->op) {
- case NFT_BYTEORDER_NTOH:
- case NFT_BYTEORDER_HTON:
- break;
- default:
- return -EINVAL;
- }
-
- priv->len = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_LEN]));
- if (priv->len == 0 || priv->len > FIELD_SIZEOF(struct nft_data, data))
- return -EINVAL;
-
- priv->size = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_SIZE]));
- switch (priv->size) {
- case 2:
- case 4:
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int nft_byteorder_dump(struct sk_buff *skb, const struct nft_expr *expr)
-{
- const struct nft_byteorder *priv = nft_expr_priv(expr);
-
- if (nla_put_be32(skb, NFTA_BYTEORDER_SREG, htonl(priv->sreg)))
- goto nla_put_failure;
- if (nla_put_be32(skb, NFTA_BYTEORDER_DREG, htonl(priv->dreg)))
- goto nla_put_failure;
- if (nla_put_be32(skb, NFTA_BYTEORDER_OP, htonl(priv->op)))
- goto nla_put_failure;
- if (nla_put_be32(skb, NFTA_BYTEORDER_LEN, htonl(priv->len)))
- goto nla_put_failure;
- if (nla_put_be32(skb, NFTA_BYTEORDER_SIZE, htonl(priv->size)))
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return -1;
-}
-
-static struct nft_expr_type nft_byteorder_type;
-static const struct nft_expr_ops nft_byteorder_ops = {
- .type = &nft_byteorder_type,
- .size = NFT_EXPR_SIZE(sizeof(struct nft_byteorder)),
- .eval = nft_byteorder_eval,
- .init = nft_byteorder_init,
- .dump = nft_byteorder_dump,
-};
-
-static struct nft_expr_type nft_byteorder_type __read_mostly = {
- .name = "byteorder",
- .ops = &nft_byteorder_ops,
- .policy = nft_byteorder_policy,
- .maxattr = NFTA_BYTEORDER_MAX,
- .owner = THIS_MODULE,
-};
-
-int __init nft_byteorder_module_init(void)
-{
- return nft_register_expr(&nft_byteorder_type);
-}
-
-void nft_byteorder_module_exit(void)
-{
- nft_unregister_expr(&nft_byteorder_type);
-}
diff --git a/net/netfilter/nft_cmp.c b/net/netfilter/nft_cmp.c
deleted file mode 100644
index 954925d..0000000
--- a/net/netfilter/nft_cmp.c
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Development of this code funded by Astaro AG (http://www.astaro.com/)
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/netlink.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter/nf_tables.h>
-#include <net/netfilter/nf_tables_core.h>
-#include <net/netfilter/nf_tables.h>
-
-struct nft_cmp_expr {
- struct nft_data data;
- enum nft_registers sreg:8;
- u8 len;
- enum nft_cmp_ops op:8;
-};
-
-static void nft_cmp_eval(const struct nft_expr *expr,
- struct nft_data data[NFT_REG_MAX + 1],
- const struct nft_pktinfo *pkt)
-{
- const struct nft_cmp_expr *priv = nft_expr_priv(expr);
- int d;
-
- d = nft_data_cmp(&data[priv->sreg], &priv->data, priv->len);
- switch (priv->op) {
- case NFT_CMP_EQ:
- if (d != 0)
- goto mismatch;
- break;
- case NFT_CMP_NEQ:
- if (d == 0)
- goto mismatch;
- break;
- case NFT_CMP_LT:
- if (d == 0)
- goto mismatch;
- case NFT_CMP_LTE:
- if (d > 0)
- goto mismatch;
- break;
- case NFT_CMP_GT:
- if (d == 0)
- goto mismatch;
- case NFT_CMP_GTE:
- if (d < 0)
- goto mismatch;
- break;
- }
- return;
-
-mismatch:
- data[NFT_REG_VERDICT].verdict = NFT_BREAK;
-}
-
-static const struct nla_policy nft_cmp_policy[NFTA_CMP_MAX + 1] = {
- [NFTA_CMP_SREG] = { .type = NLA_U32 },
- [NFTA_CMP_OP] = { .type = NLA_U32 },
- [NFTA_CMP_DATA] = { .type = NLA_NESTED },
-};
-
-static int nft_cmp_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
- const struct nlattr * const tb[])
-{
- struct nft_cmp_expr *priv = nft_expr_priv(expr);
- struct nft_data_desc desc;
- int err;
-
- priv->sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG]));
- priv->op = ntohl(nla_get_be32(tb[NFTA_CMP_OP]));
-
- err = nft_data_init(NULL, &priv->data, &desc, tb[NFTA_CMP_DATA]);
- BUG_ON(err < 0);
-
- priv->len = desc.len;
- return 0;
-}
-
-static int nft_cmp_dump(struct sk_buff *skb, const struct nft_expr *expr)
-{
- const struct nft_cmp_expr *priv = nft_expr_priv(expr);
-
- if (nla_put_be32(skb, NFTA_CMP_SREG, htonl(priv->sreg)))
- goto nla_put_failure;
- if (nla_put_be32(skb, NFTA_CMP_OP, htonl(priv->op)))
- goto nla_put_failure;
-
- if (nft_data_dump(skb, NFTA_CMP_DATA, &priv->data,
- NFT_DATA_VALUE, priv->len) < 0)
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return -1;
-}
-
-static struct nft_expr_type nft_cmp_type;
-static const struct nft_expr_ops nft_cmp_ops = {
- .type = &nft_cmp_type,
- .size = NFT_EXPR_SIZE(sizeof(struct nft_cmp_expr)),
- .eval = nft_cmp_eval,
- .init = nft_cmp_init,
- .dump = nft_cmp_dump,
-};
-
-static int nft_cmp_fast_init(const struct nft_ctx *ctx,
- const struct nft_expr *expr,
- const struct nlattr * const tb[])
-{
- struct nft_cmp_fast_expr *priv = nft_expr_priv(expr);
- struct nft_data_desc desc;
- struct nft_data data;
- u32 mask;
- int err;
-
- priv->sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG]));
-
- err = nft_data_init(NULL, &data, &desc, tb[NFTA_CMP_DATA]);
- BUG_ON(err < 0);
- desc.len *= BITS_PER_BYTE;
-
- mask = ~0U >> (sizeof(priv->data) * BITS_PER_BYTE - desc.len);
- priv->data = data.data[0] & mask;
- priv->len = desc.len;
- return 0;
-}
-
-static int nft_cmp_fast_dump(struct sk_buff *skb, const struct nft_expr *expr)
-{
- const struct nft_cmp_fast_expr *priv = nft_expr_priv(expr);
- struct nft_data data;
-
- if (nla_put_be32(skb, NFTA_CMP_SREG, htonl(priv->sreg)))
- goto nla_put_failure;
- if (nla_put_be32(skb, NFTA_CMP_OP, htonl(NFT_CMP_EQ)))
- goto nla_put_failure;
-
- data.data[0] = priv->data;
- if (nft_data_dump(skb, NFTA_CMP_DATA, &data,
- NFT_DATA_VALUE, priv->len / BITS_PER_BYTE) < 0)
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return -1;
-}
-
-const struct nft_expr_ops nft_cmp_fast_ops = {
- .type = &nft_cmp_type,
- .size = NFT_EXPR_SIZE(sizeof(struct nft_cmp_fast_expr)),
- .eval = NULL, /* inlined */
- .init = nft_cmp_fast_init,
- .dump = nft_cmp_fast_dump,
-};
-
-static const struct nft_expr_ops *
-nft_cmp_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[])
-{
- struct nft_data_desc desc;
- struct nft_data data;
- enum nft_registers sreg;
- enum nft_cmp_ops op;
- int err;
-
- if (tb[NFTA_CMP_SREG] == NULL ||
- tb[NFTA_CMP_OP] == NULL ||
- tb[NFTA_CMP_DATA] == NULL)
- return ERR_PTR(-EINVAL);
-
- sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG]));
- err = nft_validate_input_register(sreg);
- if (err < 0)
- return ERR_PTR(err);
-
- op = ntohl(nla_get_be32(tb[NFTA_CMP_OP]));
- switch (op) {
- case NFT_CMP_EQ:
- case NFT_CMP_NEQ:
- case NFT_CMP_LT:
- case NFT_CMP_LTE:
- case NFT_CMP_GT:
- case NFT_CMP_GTE:
- break;
- default:
- return ERR_PTR(-EINVAL);
- }
-
- err = nft_data_init(NULL, &data, &desc, tb[NFTA_CMP_DATA]);
- if (err < 0)
- return ERR_PTR(err);
-
- if (desc.len <= sizeof(u32) && op == NFT_CMP_EQ)
- return &nft_cmp_fast_ops;
- else
- return &nft_cmp_ops;
-}
-
-static struct nft_expr_type nft_cmp_type __read_mostly = {
- .name = "cmp",
- .select_ops = nft_cmp_select_ops,
- .policy = nft_cmp_policy,
- .maxattr = NFTA_CMP_MAX,
- .owner = THIS_MODULE,
-};
-
-int __init nft_cmp_module_init(void)
-{
- return nft_register_expr(&nft_cmp_type);
-}
-
-void nft_cmp_module_exit(void)
-{
- nft_unregister_expr(&nft_cmp_type);
-}
diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c
deleted file mode 100644
index da0c1f4..0000000
--- a/net/netfilter/nft_compat.c
+++ /dev/null
@@ -1,775 +0,0 @@
-/*
- * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
- *
- * 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.
- *
- * This software has been sponsored by Sophos Astaro <http://www.sophos.com>
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/netlink.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter/nfnetlink.h>
-#include <linux/netfilter/nf_tables.h>
-#include <linux/netfilter/nf_tables_compat.h>
-#include <linux/netfilter/x_tables.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
-#include <linux/netfilter_ipv6/ip6_tables.h>
-#include <asm/uaccess.h> /* for set_fs */
-#include <net/netfilter/nf_tables.h>
-
-union nft_entry {
- struct ipt_entry e4;
- struct ip6t_entry e6;
-};
-
-static inline void
-nft_compat_set_par(struct xt_action_param *par, void *xt, const void *xt_info)
-{
- par->target = xt;
- par->targinfo = xt_info;
- par->hotdrop = false;
-}
-
-static void nft_target_eval(const struct nft_expr *expr,
- struct nft_data data[NFT_REG_MAX + 1],
- const struct nft_pktinfo *pkt)
-{
- void *info = nft_expr_priv(expr);
- struct xt_target *target = expr->ops->data;
- struct sk_buff *skb = pkt->skb;
- int ret;
-
- nft_compat_set_par((struct xt_action_param *)&pkt->xt, target, info);
-
- ret = target->target(skb, &pkt->xt);
-
- if (pkt->xt.hotdrop)
- ret = NF_DROP;
-
- switch(ret) {
- case XT_CONTINUE:
- data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
- break;
- default:
- data[NFT_REG_VERDICT].verdict = ret;
- break;
- }
- return;
-}
-
-static const struct nla_policy nft_target_policy[NFTA_TARGET_MAX + 1] = {
- [NFTA_TARGET_NAME] = { .type = NLA_NUL_STRING },
- [NFTA_TARGET_REV] = { .type = NLA_U32 },
- [NFTA_TARGET_INFO] = { .type = NLA_BINARY },
-};
-
-static void
-nft_target_set_tgchk_param(struct xt_tgchk_param *par,
- const struct nft_ctx *ctx,
- struct xt_target *target, void *info,
- union nft_entry *entry, u8 proto, bool inv)
-{
- par->net = &init_net;
- par->table = ctx->table->name;
- switch (ctx->afi->family) {
- case AF_INET:
- entry->e4.ip.proto = proto;
- entry->e4.ip.invflags = inv ? IPT_INV_PROTO : 0;
- break;
- case AF_INET6:
- entry->e6.ipv6.proto = proto;
- entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0;
- break;
- }
- par->entryinfo = entry;
- par->target = target;
- par->targinfo = info;
- if (ctx->chain->flags & NFT_BASE_CHAIN) {
- const struct nft_base_chain *basechain =
- nft_base_chain(ctx->chain);
- const struct nf_hook_ops *ops = &basechain->ops;
-
- par->hook_mask = 1 << ops->hooknum;
- }
- par->family = ctx->afi->family;
-}
-
-static void target_compat_from_user(struct xt_target *t, void *in, void *out)
-{
-#ifdef CONFIG_COMPAT
- if (t->compat_from_user) {
- int pad;
-
- t->compat_from_user(out, in);
- pad = XT_ALIGN(t->targetsize) - t->targetsize;
- if (pad > 0)
- memset(out + t->targetsize, 0, pad);
- } else
-#endif
- memcpy(out, in, XT_ALIGN(t->targetsize));
-}
-
-static inline int nft_compat_target_offset(struct xt_target *target)
-{
-#ifdef CONFIG_COMPAT
- return xt_compat_target_offset(target);
-#else
- return 0;
-#endif
-}
-
-static const struct nla_policy nft_rule_compat_policy[NFTA_RULE_COMPAT_MAX + 1] = {
- [NFTA_RULE_COMPAT_PROTO] = { .type = NLA_U32 },
- [NFTA_RULE_COMPAT_FLAGS] = { .type = NLA_U32 },
-};
-
-static int nft_parse_compat(const struct nlattr *attr, u8 *proto, bool *inv)
-{
- struct nlattr *tb[NFTA_RULE_COMPAT_MAX+1];
- u32 flags;
- int err;
-
- err = nla_parse_nested(tb, NFTA_RULE_COMPAT_MAX, attr,
- nft_rule_compat_policy);
- if (err < 0)
- return err;
-
- if (!tb[NFTA_RULE_COMPAT_PROTO] || !tb[NFTA_RULE_COMPAT_FLAGS])
- return -EINVAL;
-
- flags = ntohl(nla_get_be32(tb[NFTA_RULE_COMPAT_FLAGS]));
- if (flags & ~NFT_RULE_COMPAT_F_MASK)
- return -EINVAL;
- if (flags & NFT_RULE_COMPAT_F_INV)
- *inv = true;
-
- *proto = ntohl(nla_get_be32(tb[NFTA_RULE_COMPAT_PROTO]));
- return 0;
-}
-
-static int
-nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
- const struct nlattr * const tb[])
-{
- void *info = nft_expr_priv(expr);
- struct xt_target *target = expr->ops->data;
- struct xt_tgchk_param par;
- size_t size = XT_ALIGN(nla_len(tb[NFTA_TARGET_INFO]));
- u8 proto = 0;
- bool inv = false;
- union nft_entry e = {};
- int ret;
-
- target_compat_from_user(target, nla_data(tb[NFTA_TARGET_INFO]), info);
-
- if (ctx->nla[NFTA_RULE_COMPAT]) {
- ret = nft_parse_compat(ctx->nla[NFTA_RULE_COMPAT], &proto, &inv);
- if (ret < 0)
- goto err;
- }
-
- nft_target_set_tgchk_param(&par, ctx, target, info, &e, proto, inv);
-
- ret = xt_check_target(&par, size, proto, inv);
- if (ret < 0)
- goto err;
-
- /* The standard target cannot be used */
- if (target->target == NULL) {
- ret = -EINVAL;
- goto err;
- }
-
- return 0;
-err:
- module_put(target->me);
- return ret;
-}
-
-static void
-nft_target_destroy(const struct nft_expr *expr)
-{
- struct xt_target *target = expr->ops->data;
-
- module_put(target->me);
-}
-
-static int
-target_dump_info(struct sk_buff *skb, const struct xt_target *t, const void *in)
-{
- int ret;
-
-#ifdef CONFIG_COMPAT
- if (t->compat_to_user) {
- mm_segment_t old_fs;
- void *out;
-
- out = kmalloc(XT_ALIGN(t->targetsize), GFP_ATOMIC);
- if (out == NULL)
- return -ENOMEM;
-
- /* We want to reuse existing compat_to_user */
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- t->compat_to_user(out, in);
- set_fs(old_fs);
- ret = nla_put(skb, NFTA_TARGET_INFO, XT_ALIGN(t->targetsize), out);
- kfree(out);
- } else
-#endif
- ret = nla_put(skb, NFTA_TARGET_INFO, XT_ALIGN(t->targetsize), in);
-
- return ret;
-}
-
-static int nft_target_dump(struct sk_buff *skb, const struct nft_expr *expr)
-{
- const struct xt_target *target = expr->ops->data;
- void *info = nft_expr_priv(expr);
-
- if (nla_put_string(skb, NFTA_TARGET_NAME, target->name) ||
- nla_put_be32(skb, NFTA_TARGET_REV, htonl(target->revision)) ||
- target_dump_info(skb, target, info))
- goto nla_put_failure;
-
- return 0;
-
-nla_put_failure:
- return -1;
-}
-
-static int nft_target_validate(const struct nft_ctx *ctx,
- const struct nft_expr *expr,
- const struct nft_data **data)
-{
- struct xt_target *target = expr->ops->data;
- unsigned int hook_mask = 0;
-
- if (ctx->chain->flags & NFT_BASE_CHAIN) {
- const struct nft_base_chain *basechain =
- nft_base_chain(ctx->chain);
- const struct nf_hook_ops *ops = &basechain->ops;
-
- hook_mask = 1 << ops->hooknum;
- if (hook_mask & target->hooks)
- return 0;
-
- /* This target is being called from an invalid chain */
- return -EINVAL;
- }
- return 0;
-}
-
-static void nft_match_eval(const struct nft_expr *expr,
- struct nft_data data[NFT_REG_MAX + 1],
- const struct nft_pktinfo *pkt)
-{
- void *info = nft_expr_priv(expr);
- struct xt_match *match = expr->ops->data;
- struct sk_buff *skb = pkt->skb;
- bool ret;
-
- nft_compat_set_par((struct xt_action_param *)&pkt->xt, match, info);
-
- ret = match->match(skb, (struct xt_action_param *)&pkt->xt);
-
- if (pkt->xt.hotdrop) {
- data[NFT_REG_VERDICT].verdict = NF_DROP;
- return;
- }
-
- switch(ret) {
- case true:
- data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
- break;
- case false:
- data[NFT_REG_VERDICT].verdict = NFT_BREAK;
- break;
- }
-}
-
-static const struct nla_policy nft_match_policy[NFTA_MATCH_MAX + 1] = {
- [NFTA_MATCH_NAME] = { .type = NLA_NUL_STRING },
- [NFTA_MATCH_REV] = { .type = NLA_U32 },
- [NFTA_MATCH_INFO] = { .type = NLA_BINARY },
-};
-
-/* struct xt_mtchk_param and xt_tgchk_param look very similar */
-static void
-nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx,
- struct xt_match *match, void *info,
- union nft_entry *entry, u8 proto, bool inv)
-{
- par->net = &init_net;
- par->table = ctx->table->name;
- switch (ctx->afi->family) {
- case AF_INET:
- entry->e4.ip.proto = proto;
- entry->e4.ip.invflags = inv ? IPT_INV_PROTO : 0;
- break;
- case AF_INET6:
- entry->e6.ipv6.proto = proto;
- entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0;
- break;
- }
- par->entryinfo = entry;
- par->match = match;
- par->matchinfo = info;
- if (ctx->chain->flags & NFT_BASE_CHAIN) {
- const struct nft_base_chain *basechain =
- nft_base_chain(ctx->chain);
- const struct nf_hook_ops *ops = &basechain->ops;
-
- par->hook_mask = 1 << ops->hooknum;
- }
- par->family = ctx->afi->family;
-}
-
-static void match_compat_from_user(struct xt_match *m, void *in, void *out)
-{
-#ifdef CONFIG_COMPAT
- if (m->compat_from_user) {
- int pad;
-
- m->compat_from_user(out, in);
- pad = XT_ALIGN(m->matchsize) - m->matchsize;
- if (pad > 0)
- memset(out + m->matchsize, 0, pad);
- } else
-#endif
- memcpy(out, in, XT_ALIGN(m->matchsize));
-}
-
-static int
-nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
- const struct nlattr * const tb[])
-{
- void *info = nft_expr_priv(expr);
- struct xt_match *match = expr->ops->data;
- struct xt_mtchk_param par;
- size_t size = XT_ALIGN(nla_len(tb[NFTA_MATCH_INFO]));
- u8 proto = 0;
- bool inv = false;
- union nft_entry e = {};
- int ret;
-
- match_compat_from_user(match, nla_data(tb[NFTA_MATCH_INFO]), info);
-
- if (ctx->nla[NFTA_RULE_COMPAT]) {
- ret = nft_parse_compat(ctx->nla[NFTA_RULE_COMPAT], &proto, &inv);
- if (ret < 0)
- goto err;
- }
-
- nft_match_set_mtchk_param(&par, ctx, match, info, &e, proto, inv);
-
- ret = xt_check_match(&par, size, proto, inv);
- if (ret < 0)
- goto err;
-
- return 0;
-err:
- module_put(match->me);
- return ret;
-}
-
-static void
-nft_match_destroy(const struct nft_expr *expr)
-{
- struct xt_match *match = expr->ops->data;
-
- module_put(match->me);
-}
-
-static int
-match_dump_info(struct sk_buff *skb, const struct xt_match *m, const void *in)
-{
- int ret;
-
-#ifdef CONFIG_COMPAT
- if (m->compat_to_user) {
- mm_segment_t old_fs;
- void *out;
-
- out = kmalloc(XT_ALIGN(m->matchsize), GFP_ATOMIC);
- if (out == NULL)
- return -ENOMEM;
-
- /* We want to reuse existing compat_to_user */
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- m->compat_to_user(out, in);
- set_fs(old_fs);
- ret = nla_put(skb, NFTA_MATCH_INFO, XT_ALIGN(m->matchsize), out);
- kfree(out);
- } else
-#endif
- ret = nla_put(skb, NFTA_MATCH_INFO, XT_ALIGN(m->matchsize), in);
-
- return ret;
-}
-
-static inline int nft_compat_match_offset(struct xt_match *match)
-{
-#ifdef CONFIG_COMPAT
- return xt_compat_match_offset(match);
-#else
- return 0;
-#endif
-}
-
-static int nft_match_dump(struct sk_buff *skb, const struct nft_expr *expr)
-{
- void *info = nft_expr_priv(expr);
- struct xt_match *match = expr->ops->data;
-
- if (nla_put_string(skb, NFTA_MATCH_NAME, match->name) ||
- nla_put_be32(skb, NFTA_MATCH_REV, htonl(match->revision)) ||
- match_dump_info(skb, match, info))
- goto nla_put_failure;
-
- return 0;
-
-nla_put_failure:
- return -1;
-}
-
-static int nft_match_validate(const struct nft_ctx *ctx,
- const struct nft_expr *expr,
- const struct nft_data **data)
-{
- struct xt_match *match = expr->ops->data;
- unsigned int hook_mask = 0;
-
- if (ctx->chain->flags & NFT_BASE_CHAIN) {
- const struct nft_base_chain *basechain =
- nft_base_chain(ctx->chain);
- const struct nf_hook_ops *ops = &basechain->ops;
-
- hook_mask = 1 << ops->hooknum;
- if (hook_mask & match->hooks)
- return 0;
-
- /* This match is being called from an invalid chain */
- return -EINVAL;
- }
- return 0;
-}
-
-static int
-nfnl_compat_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
- int event, u16 family, const char *name,
- int rev, int target)
-{
- struct nlmsghdr *nlh;
- struct nfgenmsg *nfmsg;
- unsigned int flags = portid ? NLM_F_MULTI : 0;
-
- event |= NFNL_SUBSYS_NFT_COMPAT << 8;
- nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
- if (nlh == NULL)
- goto nlmsg_failure;
-
- nfmsg = nlmsg_data(nlh);
- nfmsg->nfgen_family = family;
- nfmsg->version = NFNETLINK_V0;
- nfmsg->res_id = 0;
-
- if (nla_put_string(skb, NFTA_COMPAT_NAME, name) ||
- nla_put_be32(skb, NFTA_COMPAT_REV, htonl(rev)) ||
- nla_put_be32(skb, NFTA_COMPAT_TYPE, htonl(target)))
- goto nla_put_failure;
-
- nlmsg_end(skb, nlh);
- return skb->len;
-
-nlmsg_failure:
-nla_put_failure:
- nlmsg_cancel(skb, nlh);
- return -1;
-}
-
-static int
-nfnl_compat_get(struct sock *nfnl, struct sk_buff *skb,
- const struct nlmsghdr *nlh, const struct nlattr * const tb[])
-{
- int ret = 0, target;
- struct nfgenmsg *nfmsg;
- const char *fmt;
- const char *name;
- u32 rev;
- struct sk_buff *skb2;
-
- if (tb[NFTA_COMPAT_NAME] == NULL ||
- tb[NFTA_COMPAT_REV] == NULL ||
- tb[NFTA_COMPAT_TYPE] == NULL)
- return -EINVAL;
-
- name = nla_data(tb[NFTA_COMPAT_NAME]);
- rev = ntohl(nla_get_be32(tb[NFTA_COMPAT_REV]));
- target = ntohl(nla_get_be32(tb[NFTA_COMPAT_TYPE]));
-
- nfmsg = nlmsg_data(nlh);
-
- switch(nfmsg->nfgen_family) {
- case AF_INET:
- fmt = "ipt_%s";
- break;
- case AF_INET6:
- fmt = "ip6t_%s";
- break;
- default:
- pr_err("nft_compat: unsupported protocol %d\n",
- nfmsg->nfgen_family);
- return -EINVAL;
- }
-
- try_then_request_module(xt_find_revision(nfmsg->nfgen_family, name,
- rev, target, &ret),
- fmt, name);
-
- if (ret < 0)
- return ret;
-
- skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
- if (skb2 == NULL)
- return -ENOMEM;
-
- /* include the best revision for this extension in the message */
- if (nfnl_compat_fill_info(skb2, NETLINK_CB(skb).portid,
- nlh->nlmsg_seq,
- NFNL_MSG_TYPE(nlh->nlmsg_type),
- NFNL_MSG_COMPAT_GET,
- nfmsg->nfgen_family,
- name, ret, target) <= 0) {
- kfree_skb(skb2);
- return -ENOSPC;
- }
-
- ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid,
- MSG_DONTWAIT);
- if (ret > 0)
- ret = 0;
-
- return ret == -EAGAIN ? -ENOBUFS : ret;
-}
-
-static const struct nla_policy nfnl_compat_policy_get[NFTA_COMPAT_MAX+1] = {
- [NFTA_COMPAT_NAME] = { .type = NLA_NUL_STRING,
- .len = NFT_COMPAT_NAME_MAX-1 },
- [NFTA_COMPAT_REV] = { .type = NLA_U32 },
- [NFTA_COMPAT_TYPE] = { .type = NLA_U32 },
-};
-
-static const struct nfnl_callback nfnl_nft_compat_cb[NFNL_MSG_COMPAT_MAX] = {
- [NFNL_MSG_COMPAT_GET] = { .call = nfnl_compat_get,
- .attr_count = NFTA_COMPAT_MAX,
- .policy = nfnl_compat_policy_get },
-};
-
-static const struct nfnetlink_subsystem nfnl_compat_subsys = {
- .name = "nft-compat",
- .subsys_id = NFNL_SUBSYS_NFT_COMPAT,
- .cb_count = NFNL_MSG_COMPAT_MAX,
- .cb = nfnl_nft_compat_cb,
-};
-
-static LIST_HEAD(nft_match_list);
-
-struct nft_xt {
- struct list_head head;
- struct nft_expr_ops ops;
-};
-
-static struct nft_expr_type nft_match_type;
-
-static const struct nft_expr_ops *
-nft_match_select_ops(const struct nft_ctx *ctx,
- const struct nlattr * const tb[])
-{
- struct nft_xt *nft_match;
- struct xt_match *match;
- char *mt_name;
- __u32 rev, family;
-
- if (tb[NFTA_MATCH_NAME] == NULL ||
- tb[NFTA_MATCH_REV] == NULL ||
- tb[NFTA_MATCH_INFO] == NULL)
- return ERR_PTR(-EINVAL);
-
- mt_name = nla_data(tb[NFTA_MATCH_NAME]);
- rev = ntohl(nla_get_be32(tb[NFTA_MATCH_REV]));
- family = ctx->afi->family;
-
- /* Re-use the existing match if it's already loaded. */
- list_for_each_entry(nft_match, &nft_match_list, head) {
- struct xt_match *match = nft_match->ops.data;
-
- if (strcmp(match->name, mt_name) == 0 &&
- match->revision == rev && match->family == family)
- return &nft_match->ops;
- }
-
- match = xt_request_find_match(family, mt_name, rev);
- if (IS_ERR(match))
- return ERR_PTR(-ENOENT);
-
- /* This is the first time we use this match, allocate operations */
- nft_match = kzalloc(sizeof(struct nft_xt), GFP_KERNEL);
- if (nft_match == NULL)
- return ERR_PTR(-ENOMEM);
-
- nft_match->ops.type = &nft_match_type;
- nft_match->ops.size = NFT_EXPR_SIZE(XT_ALIGN(match->matchsize) +
- nft_compat_match_offset(match));
- nft_match->ops.eval = nft_match_eval;
- nft_match->ops.init = nft_match_init;
- nft_match->ops.destroy = nft_match_destroy;
- nft_match->ops.dump = nft_match_dump;
- nft_match->ops.validate = nft_match_validate;
- nft_match->ops.data = match;
-
- list_add(&nft_match->head, &nft_match_list);
-
- return &nft_match->ops;
-}
-
-static void nft_match_release(void)
-{
- struct nft_xt *nft_match, *tmp;
-
- list_for_each_entry_safe(nft_match, tmp, &nft_match_list, head)
- kfree(nft_match);
-}
-
-static struct nft_expr_type nft_match_type __read_mostly = {
- .name = "match",
- .select_ops = nft_match_select_ops,
- .policy = nft_match_policy,
- .maxattr = NFTA_MATCH_MAX,
- .owner = THIS_MODULE,
-};
-
-static LIST_HEAD(nft_target_list);
-
-static struct nft_expr_type nft_target_type;
-
-static const struct nft_expr_ops *
-nft_target_select_ops(const struct nft_ctx *ctx,
- const struct nlattr * const tb[])
-{
- struct nft_xt *nft_target;
- struct xt_target *target;
- char *tg_name;
- __u32 rev, family;
-
- if (tb[NFTA_TARGET_NAME] == NULL ||
- tb[NFTA_TARGET_REV] == NULL ||
- tb[NFTA_TARGET_INFO] == NULL)
- return ERR_PTR(-EINVAL);
-
- tg_name = nla_data(tb[NFTA_TARGET_NAME]);
- rev = ntohl(nla_get_be32(tb[NFTA_TARGET_REV]));
- family = ctx->afi->family;
-
- /* Re-use the existing target if it's already loaded. */
- list_for_each_entry(nft_target, &nft_match_list, head) {
- struct xt_target *target = nft_target->ops.data;
-
- if (strcmp(target->name, tg_name) == 0 &&
- target->revision == rev && target->family == family)
- return &nft_target->ops;
- }
-
- target = xt_request_find_target(family, tg_name, rev);
- if (IS_ERR(target))
- return ERR_PTR(-ENOENT);
-
- /* This is the first time we use this target, allocate operations */
- nft_target = kzalloc(sizeof(struct nft_xt), GFP_KERNEL);
- if (nft_target == NULL)
- return ERR_PTR(-ENOMEM);
-
- nft_target->ops.type = &nft_target_type;
- nft_target->ops.size = NFT_EXPR_SIZE(XT_ALIGN(target->targetsize) +
- nft_compat_target_offset(target));
- nft_target->ops.eval = nft_target_eval;
- nft_target->ops.init = nft_target_init;
- nft_target->ops.destroy = nft_target_destroy;
- nft_target->ops.dump = nft_target_dump;
- nft_target->ops.validate = nft_target_validate;
- nft_target->ops.data = target;
-
- list_add(&nft_target->head, &nft_target_list);
-
- return &nft_target->ops;
-}
-
-static void nft_target_release(void)
-{
- struct nft_xt *nft_target, *tmp;
-
- list_for_each_entry_safe(nft_target, tmp, &nft_target_list, head)
- kfree(nft_target);
-}
-
-static struct nft_expr_type nft_target_type __read_mostly = {
- .name = "target",
- .select_ops = nft_target_select_ops,
- .policy = nft_target_policy,
- .maxattr = NFTA_TARGET_MAX,
- .owner = THIS_MODULE,
-};
-
-static int __init nft_compat_module_init(void)
-{
- int ret;
-
- ret = nft_register_expr(&nft_match_type);
- if (ret < 0)
- return ret;
-
- ret = nft_register_expr(&nft_target_type);
- if (ret < 0)
- goto err_match;
-
- ret = nfnetlink_subsys_register(&nfnl_compat_subsys);
- if (ret < 0) {
- pr_err("nft_compat: cannot register with nfnetlink.\n");
- goto err_target;
- }
-
- pr_info("nf_tables_compat: (c) 2012 Pablo Neira Ayuso <pablo@netfilter.org>\n");
-
- return ret;
-
-err_target:
- nft_unregister_expr(&nft_target_type);
-err_match:
- nft_unregister_expr(&nft_match_type);
- return ret;
-}
-
-static void __exit nft_compat_module_exit(void)
-{
- nfnetlink_subsys_unregister(&nfnl_compat_subsys);
- nft_unregister_expr(&nft_target_type);
- nft_unregister_expr(&nft_match_type);
- nft_match_release();
- nft_target_release();
-}
-
-MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_NFT_COMPAT);
-
-module_init(nft_compat_module_init);
-module_exit(nft_compat_module_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
-MODULE_ALIAS_NFT_EXPR("match");
-MODULE_ALIAS_NFT_EXPR("target");
diff --git a/net/netfilter/nft_counter.c b/net/netfilter/nft_counter.c
deleted file mode 100644
index c89ee48..0000000
--- a/net/netfilter/nft_counter.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Development of this code funded by Astaro AG (http://www.astaro.com/)
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/seqlock.h>
-#include <linux/netlink.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter/nf_tables.h>
-#include <net/netfilter/nf_tables.h>
-
-struct nft_counter {
- seqlock_t lock;
- u64 bytes;
- u64 packets;
-};
-
-static void nft_counter_eval(const struct nft_expr *expr,
- struct nft_data data[NFT_REG_MAX + 1],
- const struct nft_pktinfo *pkt)
-{
- struct nft_counter *priv = nft_expr_priv(expr);
-
- write_seqlock_bh(&priv->lock);
- priv->bytes += pkt->skb->len;
- priv->packets++;
- write_sequnlock_bh(&priv->lock);
-}
-
-static int nft_counter_dump(struct sk_buff *skb, const struct nft_expr *expr)
-{
- struct nft_counter *priv = nft_expr_priv(expr);
- unsigned int seq;
- u64 bytes;
- u64 packets;
-
- do {
- seq = read_seqbegin(&priv->lock);
- bytes = priv->bytes;
- packets = priv->packets;
- } while (read_seqretry(&priv->lock, seq));
-
- if (nla_put_be64(skb, NFTA_COUNTER_BYTES, cpu_to_be64(bytes)))
- goto nla_put_failure;
- if (nla_put_be64(skb, NFTA_COUNTER_PACKETS, cpu_to_be64(packets)))
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return -1;
-}
-
-static const struct nla_policy nft_counter_policy[NFTA_COUNTER_MAX + 1] = {
- [NFTA_COUNTER_PACKETS] = { .type = NLA_U64 },
- [NFTA_COUNTER_BYTES] = { .type = NLA_U64 },
-};
-
-static int nft_counter_init(const struct nft_ctx *ctx,
- const struct nft_expr *expr,
- const struct nlattr * const tb[])
-{
- struct nft_counter *priv = nft_expr_priv(expr);
-
- if (tb[NFTA_COUNTER_PACKETS])
- priv->packets = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_PACKETS]));
- if (tb[NFTA_COUNTER_BYTES])
- priv->bytes = be64_to_cpu(nla_get_be64(tb[NFTA_COUNTER_BYTES]));
-
- seqlock_init(&priv->lock);
- return 0;
-}
-
-static struct nft_expr_type nft_counter_type;
-static const struct nft_expr_ops nft_counter_ops = {
- .type = &nft_counter_type,
- .size = NFT_EXPR_SIZE(sizeof(struct nft_counter)),
- .eval = nft_counter_eval,
- .init = nft_counter_init,
- .dump = nft_counter_dump,
-};
-
-static struct nft_expr_type nft_counter_type __read_mostly = {
- .name = "counter",
- .ops = &nft_counter_ops,
- .policy = nft_counter_policy,
- .maxattr = NFTA_COUNTER_MAX,
- .owner = THIS_MODULE,
-};
-
-static int __init nft_counter_module_init(void)
-{
- return nft_register_expr(&nft_counter_type);
-}
-
-static void __exit nft_counter_module_exit(void)
-{
- nft_unregister_expr(&nft_counter_type);
-}
-
-module_init(nft_counter_module_init);
-module_exit(nft_counter_module_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
-MODULE_ALIAS_NFT_EXPR("counter");
diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c
deleted file mode 100644
index 955f4e6..0000000
--- a/net/netfilter/nft_ct.c
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Development of this code funded by Astaro AG (http://www.astaro.com/)
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/netlink.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter/nf_tables.h>
-#include <net/netfilter/nf_tables.h>
-#include <net/netfilter/nf_conntrack.h>
-#include <net/netfilter/nf_conntrack_tuple.h>
-#include <net/netfilter/nf_conntrack_helper.h>
-
-struct nft_ct {
- enum nft_ct_keys key:8;
- enum ip_conntrack_dir dir:8;
- enum nft_registers dreg:8;
- uint8_t family;
-};
-
-static void nft_ct_eval(const struct nft_expr *expr,
- struct nft_data data[NFT_REG_MAX + 1],
- const struct nft_pktinfo *pkt)
-{
- const struct nft_ct *priv = nft_expr_priv(expr);
- struct nft_data *dest = &data[priv->dreg];
- enum ip_conntrack_info ctinfo;
- const struct nf_conn *ct;
- const struct nf_conn_help *help;
- const struct nf_conntrack_tuple *tuple;
- const struct nf_conntrack_helper *helper;
- long diff;
- unsigned int state;
-
- ct = nf_ct_get(pkt->skb, &ctinfo);
-
- switch (priv->key) {
- case NFT_CT_STATE:
- if (ct == NULL)
- state = NF_CT_STATE_INVALID_BIT;
- else if (nf_ct_is_untracked(ct))
- state = NF_CT_STATE_UNTRACKED_BIT;
- else
- state = NF_CT_STATE_BIT(ctinfo);
- dest->data[0] = state;
- return;
- }
-
- if (ct == NULL)
- goto err;
-
- switch (priv->key) {
- case NFT_CT_DIRECTION:
- dest->data[0] = CTINFO2DIR(ctinfo);
- return;
- case NFT_CT_STATUS:
- dest->data[0] = ct->status;
- return;
-#ifdef CONFIG_NF_CONNTRACK_MARK
- case NFT_CT_MARK:
- dest->data[0] = ct->mark;
- return;
-#endif
-#ifdef CONFIG_NF_CONNTRACK_SECMARK
- case NFT_CT_SECMARK:
- dest->data[0] = ct->secmark;
- return;
-#endif
- case NFT_CT_EXPIRATION:
- diff = (long)jiffies - (long)ct->timeout.expires;
- if (diff < 0)
- diff = 0;
- dest->data[0] = jiffies_to_msecs(diff);
- return;
- case NFT_CT_HELPER:
- if (ct->master == NULL)
- goto err;
- help = nfct_help(ct->master);
- if (help == NULL)
- goto err;
- helper = rcu_dereference(help->helper);
- if (helper == NULL)
- goto err;
- if (strlen(helper->name) >= sizeof(dest->data))
- goto err;
- strncpy((char *)dest->data, helper->name, sizeof(dest->data));
- return;
- }
-
- tuple = &ct->tuplehash[priv->dir].tuple;
- switch (priv->key) {
- case NFT_CT_L3PROTOCOL:
- dest->data[0] = nf_ct_l3num(ct);
- return;
- case NFT_CT_SRC:
- memcpy(dest->data, tuple->src.u3.all,
- nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16);
- return;
- case NFT_CT_DST:
- memcpy(dest->data, tuple->dst.u3.all,
- nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16);
- return;
- case NFT_CT_PROTOCOL:
- dest->data[0] = nf_ct_protonum(ct);
- return;
- case NFT_CT_PROTO_SRC:
- dest->data[0] = (__force __u16)tuple->src.u.all;
- return;
- case NFT_CT_PROTO_DST:
- dest->data[0] = (__force __u16)tuple->dst.u.all;
- return;
- }
- return;
-err:
- data[NFT_REG_VERDICT].verdict = NFT_BREAK;
-}
-
-static const struct nla_policy nft_ct_policy[NFTA_CT_MAX + 1] = {
- [NFTA_CT_DREG] = { .type = NLA_U32 },
- [NFTA_CT_KEY] = { .type = NLA_U32 },
- [NFTA_CT_DIRECTION] = { .type = NLA_U8 },
-};
-
-static int nft_ct_init(const struct nft_ctx *ctx,
- const struct nft_expr *expr,
- const struct nlattr * const tb[])
-{
- struct nft_ct *priv = nft_expr_priv(expr);
- int err;
-
- if (tb[NFTA_CT_DREG] == NULL ||
- tb[NFTA_CT_KEY] == NULL)
- return -EINVAL;
-
- priv->key = ntohl(nla_get_be32(tb[NFTA_CT_KEY]));
- if (tb[NFTA_CT_DIRECTION] != NULL) {
- priv->dir = nla_get_u8(tb[NFTA_CT_DIRECTION]);
- switch (priv->dir) {
- case IP_CT_DIR_ORIGINAL:
- case IP_CT_DIR_REPLY:
- break;
- default:
- return -EINVAL;
- }
- }
-
- switch (priv->key) {
- case NFT_CT_STATE:
- case NFT_CT_DIRECTION:
- case NFT_CT_STATUS:
-#ifdef CONFIG_NF_CONNTRACK_MARK
- case NFT_CT_MARK:
-#endif
-#ifdef CONFIG_NF_CONNTRACK_SECMARK
- case NFT_CT_SECMARK:
-#endif
- case NFT_CT_EXPIRATION:
- case NFT_CT_HELPER:
- if (tb[NFTA_CT_DIRECTION] != NULL)
- return -EINVAL;
- break;
- case NFT_CT_PROTOCOL:
- case NFT_CT_SRC:
- case NFT_CT_DST:
- case NFT_CT_PROTO_SRC:
- case NFT_CT_PROTO_DST:
- if (tb[NFTA_CT_DIRECTION] == NULL)
- return -EINVAL;
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- err = nf_ct_l3proto_try_module_get(ctx->afi->family);
- if (err < 0)
- return err;
- priv->family = ctx->afi->family;
-
- priv->dreg = ntohl(nla_get_be32(tb[NFTA_CT_DREG]));
- err = nft_validate_output_register(priv->dreg);
- if (err < 0)
- goto err1;
-
- err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
- if (err < 0)
- goto err1;
- return 0;
-
-err1:
- nf_ct_l3proto_module_put(ctx->afi->family);
- return err;
-}
-
-static void nft_ct_destroy(const struct nft_expr *expr)
-{
- struct nft_ct *priv = nft_expr_priv(expr);
-
- nf_ct_l3proto_module_put(priv->family);
-}
-
-static int nft_ct_dump(struct sk_buff *skb, const struct nft_expr *expr)
-{
- const struct nft_ct *priv = nft_expr_priv(expr);
-
- if (nla_put_be32(skb, NFTA_CT_DREG, htonl(priv->dreg)))
- goto nla_put_failure;
- if (nla_put_be32(skb, NFTA_CT_KEY, htonl(priv->key)))
- goto nla_put_failure;
- if (nla_put_u8(skb, NFTA_CT_DIRECTION, priv->dir))
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return -1;
-}
-
-static struct nft_expr_type nft_ct_type;
-static const struct nft_expr_ops nft_ct_ops = {
- .type = &nft_ct_type,
- .size = NFT_EXPR_SIZE(sizeof(struct nft_ct)),
- .eval = nft_ct_eval,
- .init = nft_ct_init,
- .destroy = nft_ct_destroy,
- .dump = nft_ct_dump,
-};
-
-static struct nft_expr_type nft_ct_type __read_mostly = {
- .name = "ct",
- .ops = &nft_ct_ops,
- .policy = nft_ct_policy,
- .maxattr = NFTA_CT_MAX,
- .owner = THIS_MODULE,
-};
-
-static int __init nft_ct_module_init(void)
-{
- return nft_register_expr(&nft_ct_type);
-}
-
-static void __exit nft_ct_module_exit(void)
-{
- nft_unregister_expr(&nft_ct_type);
-}
-
-module_init(nft_ct_module_init);
-module_exit(nft_ct_module_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
-MODULE_ALIAS_NFT_EXPR("ct");
diff --git a/net/netfilter/nft_expr_template.c b/net/netfilter/nft_expr_template.c
deleted file mode 100644
index b6eed4d..0000000
--- a/net/netfilter/nft_expr_template.c
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Development of this code funded by Astaro AG (http://www.astaro.com/)
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/netlink.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter/nf_tables.h>
-#include <net/netfilter/nf_tables.h>
-
-struct nft_template {
-
-};
-
-static void nft_template_eval(const struct nft_expr *expr,
- struct nft_data data[NFT_REG_MAX + 1],
- const struct nft_pktinfo *pkt)
-{
- struct nft_template *priv = nft_expr_priv(expr);
-
-}
-
-static const struct nla_policy nft_template_policy[NFTA_TEMPLATE_MAX + 1] = {
- [NFTA_TEMPLATE_ATTR] = { .type = NLA_U32 },
-};
-
-static int nft_template_init(const struct nft_ctx *ctx,
- const struct nft_expr *expr,
- const struct nlattr * const tb[])
-{
- struct nft_template *priv = nft_expr_priv(expr);
-
- return 0;
-}
-
-static void nft_template_destroy(const struct nft_ctx *ctx,
- const struct nft_expr *expr)
-{
- struct nft_template *priv = nft_expr_priv(expr);
-
-}
-
-static int nft_template_dump(struct sk_buff *skb, const struct nft_expr *expr)
-{
- const struct nft_template *priv = nft_expr_priv(expr);
-
- NLA_PUT_BE32(skb, NFTA_TEMPLATE_ATTR, priv->field);
- return 0;
-
-nla_put_failure:
- return -1;
-}
-
-static struct nft_expr_type nft_template_type;
-static const struct nft_expr_ops nft_template_ops = {
- .type = &nft_template_type,
- .size = NFT_EXPR_SIZE(sizeof(struct nft_template)),
- .eval = nft_template_eval,
- .init = nft_template_init,
- .destroy = nft_template_destroy,
- .dump = nft_template_dump,
-};
-
-static struct nft_expr_type nft_template_type __read_mostly = {
- .name = "template",
- .ops = &nft_template_ops,
- .policy = nft_template_policy,
- .maxattr = NFTA_TEMPLATE_MAX,
- .owner = THIS_MODULE,
-};
-
-static int __init nft_template_module_init(void)
-{
- return nft_register_expr(&nft_template_type);
-}
-
-static void __exit nft_template_module_exit(void)
-{
- nft_unregister_expr(&nft_template_type);
-}
-
-module_init(nft_template_module_init);
-module_exit(nft_template_module_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
-MODULE_ALIAS_NFT_EXPR("template");
diff --git a/net/netfilter/nft_exthdr.c b/net/netfilter/nft_exthdr.c
deleted file mode 100644
index 8e0bb75..0000000
--- a/net/netfilter/nft_exthdr.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (c) 2008 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/module.h>
-#include <linux/netlink.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter/nf_tables.h>
-#include <net/netfilter/nf_tables.h>
-// FIXME:
-#include <net/ipv6.h>
-
-struct nft_exthdr {
- u8 type;
- u8 offset;
- u8 len;
- enum nft_registers dreg:8;
-};
-
-static void nft_exthdr_eval(const struct nft_expr *expr,
- struct nft_data data[NFT_REG_MAX + 1],
- const struct nft_pktinfo *pkt)
-{
- struct nft_exthdr *priv = nft_expr_priv(expr);
- struct nft_data *dest = &data[priv->dreg];
- unsigned int offset;
- int err;
-
- err = ipv6_find_hdr(pkt->skb, &offset, priv->type, NULL, NULL);
- if (err < 0)
- goto err;
- offset += priv->offset;
-
- if (skb_copy_bits(pkt->skb, offset, dest->data, priv->len) < 0)
- goto err;
- return;
-err:
- data[NFT_REG_VERDICT].verdict = NFT_BREAK;
-}
-
-static const struct nla_policy nft_exthdr_policy[NFTA_EXTHDR_MAX + 1] = {
- [NFTA_EXTHDR_DREG] = { .type = NLA_U32 },
- [NFTA_EXTHDR_TYPE] = { .type = NLA_U8 },
- [NFTA_EXTHDR_OFFSET] = { .type = NLA_U32 },
- [NFTA_EXTHDR_LEN] = { .type = NLA_U32 },
-};
-
-static int nft_exthdr_init(const struct nft_ctx *ctx,
- const struct nft_expr *expr,
- const struct nlattr * const tb[])
-{
- struct nft_exthdr *priv = nft_expr_priv(expr);
- int err;
-
- if (tb[NFTA_EXTHDR_DREG] == NULL ||
- tb[NFTA_EXTHDR_TYPE] == NULL ||
- tb[NFTA_EXTHDR_OFFSET] == NULL ||
- tb[NFTA_EXTHDR_LEN] == NULL)
- return -EINVAL;
-
- priv->type = nla_get_u8(tb[NFTA_EXTHDR_TYPE]);
- priv->offset = ntohl(nla_get_be32(tb[NFTA_EXTHDR_OFFSET]));
- priv->len = ntohl(nla_get_be32(tb[NFTA_EXTHDR_LEN]));
- if (priv->len == 0 ||
- priv->len > FIELD_SIZEOF(struct nft_data, data))
- return -EINVAL;
-
- priv->dreg = ntohl(nla_get_be32(tb[NFTA_EXTHDR_DREG]));
- err = nft_validate_output_register(priv->dreg);
- if (err < 0)
- return err;
- return nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
-}
-
-static int nft_exthdr_dump(struct sk_buff *skb, const struct nft_expr *expr)
-{
- const struct nft_exthdr *priv = nft_expr_priv(expr);
-
- if (nla_put_be32(skb, NFTA_EXTHDR_DREG, htonl(priv->dreg)))
- goto nla_put_failure;
- if (nla_put_u8(skb, NFTA_EXTHDR_TYPE, priv->type))
- goto nla_put_failure;
- if (nla_put_be32(skb, NFTA_EXTHDR_OFFSET, htonl(priv->offset)))
- goto nla_put_failure;
- if (nla_put_be32(skb, NFTA_EXTHDR_LEN, htonl(priv->len)))
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return -1;
-}
-
-static struct nft_expr_type nft_exthdr_type;
-static const struct nft_expr_ops nft_exthdr_ops = {
- .type = &nft_exthdr_type,
- .size = NFT_EXPR_SIZE(sizeof(struct nft_exthdr)),
- .eval = nft_exthdr_eval,
- .init = nft_exthdr_init,
- .dump = nft_exthdr_dump,
-};
-
-static struct nft_expr_type nft_exthdr_type __read_mostly = {
- .name = "exthdr",
- .ops = &nft_exthdr_ops,
- .policy = nft_exthdr_policy,
- .maxattr = NFTA_EXTHDR_MAX,
- .owner = THIS_MODULE,
-};
-
-static int __init nft_exthdr_module_init(void)
-{
- return nft_register_expr(&nft_exthdr_type);
-}
-
-static void __exit nft_exthdr_module_exit(void)
-{
- nft_unregister_expr(&nft_exthdr_type);
-}
-
-module_init(nft_exthdr_module_init);
-module_exit(nft_exthdr_module_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
-MODULE_ALIAS_NFT_EXPR("exthdr");
diff --git a/net/netfilter/nft_hash.c b/net/netfilter/nft_hash.c
deleted file mode 100644
index 3d3f8fc..0000000
--- a/net/netfilter/nft_hash.c
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Development of this code funded by Astaro AG (http://www.astaro.com/)
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/list.h>
-#include <linux/jhash.h>
-#include <linux/netlink.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter/nf_tables.h>
-#include <net/netfilter/nf_tables.h>
-
-struct nft_hash {
- struct hlist_head *hash;
- unsigned int hsize;
-};
-
-struct nft_hash_elem {
- struct hlist_node hnode;
- struct nft_data key;
- struct nft_data data[];
-};
-
-static u32 nft_hash_rnd __read_mostly;
-static bool nft_hash_rnd_initted __read_mostly;
-
-static unsigned int nft_hash_data(const struct nft_data *data,
- unsigned int hsize, unsigned int len)
-{
- unsigned int h;
-
- h = jhash(data->data, len, nft_hash_rnd);
- return ((u64)h * hsize) >> 32;
-}
-
-static bool nft_hash_lookup(const struct nft_set *set,
- const struct nft_data *key,
- struct nft_data *data)
-{
- const struct nft_hash *priv = nft_set_priv(set);
- const struct nft_hash_elem *he;
- unsigned int h;
-
- h = nft_hash_data(key, priv->hsize, set->klen);
- hlist_for_each_entry(he, &priv->hash[h], hnode) {
- if (nft_data_cmp(&he->key, key, set->klen))
- continue;
- if (set->flags & NFT_SET_MAP)
- nft_data_copy(data, he->data);
- return true;
- }
- return false;
-}
-
-static void nft_hash_elem_destroy(const struct nft_set *set,
- struct nft_hash_elem *he)
-{
- nft_data_uninit(&he->key, NFT_DATA_VALUE);
- if (set->flags & NFT_SET_MAP)
- nft_data_uninit(he->data, set->dtype);
- kfree(he);
-}
-
-static int nft_hash_insert(const struct nft_set *set,
- const struct nft_set_elem *elem)
-{
- struct nft_hash *priv = nft_set_priv(set);
- struct nft_hash_elem *he;
- unsigned int size, h;
-
- if (elem->flags != 0)
- return -EINVAL;
-
- size = sizeof(*he);
- if (set->flags & NFT_SET_MAP)
- size += sizeof(he->data[0]);
-
- he = kzalloc(size, GFP_KERNEL);
- if (he == NULL)
- return -ENOMEM;
-
- nft_data_copy(&he->key, &elem->key);
- if (set->flags & NFT_SET_MAP)
- nft_data_copy(he->data, &elem->data);
-
- h = nft_hash_data(&he->key, priv->hsize, set->klen);
- hlist_add_head_rcu(&he->hnode, &priv->hash[h]);
- return 0;
-}
-
-static void nft_hash_remove(const struct nft_set *set,
- const struct nft_set_elem *elem)
-{
- struct nft_hash_elem *he = elem->cookie;
-
- hlist_del_rcu(&he->hnode);
- kfree(he);
-}
-
-static int nft_hash_get(const struct nft_set *set, struct nft_set_elem *elem)
-{
- const struct nft_hash *priv = nft_set_priv(set);
- struct nft_hash_elem *he;
- unsigned int h;
-
- h = nft_hash_data(&elem->key, priv->hsize, set->klen);
- hlist_for_each_entry(he, &priv->hash[h], hnode) {
- if (nft_data_cmp(&he->key, &elem->key, set->klen))
- continue;
-
- elem->cookie = he;
- elem->flags = 0;
- if (set->flags & NFT_SET_MAP)
- nft_data_copy(&elem->data, he->data);
- return 0;
- }
- return -ENOENT;
-}
-
-static void nft_hash_walk(const struct nft_ctx *ctx, const struct nft_set *set,
- struct nft_set_iter *iter)
-{
- const struct nft_hash *priv = nft_set_priv(set);
- const struct nft_hash_elem *he;
- struct nft_set_elem elem;
- unsigned int i;
-
- for (i = 0; i < priv->hsize; i++) {
- hlist_for_each_entry(he, &priv->hash[i], hnode) {
- if (iter->count < iter->skip)
- goto cont;
-
- memcpy(&elem.key, &he->key, sizeof(elem.key));
- if (set->flags & NFT_SET_MAP)
- memcpy(&elem.data, he->data, sizeof(elem.data));
- elem.flags = 0;
-
- iter->err = iter->fn(ctx, set, iter, &elem);
- if (iter->err < 0)
- return;
-cont:
- iter->count++;
- }
- }
-}
-
-static unsigned int nft_hash_privsize(const struct nlattr * const nla[])
-{
- return sizeof(struct nft_hash);
-}
-
-static int nft_hash_init(const struct nft_set *set,
- const struct nlattr * const tb[])
-{
- struct nft_hash *priv = nft_set_priv(set);
- unsigned int cnt, i;
-
- if (unlikely(!nft_hash_rnd_initted)) {
- get_random_bytes(&nft_hash_rnd, 4);
- nft_hash_rnd_initted = true;
- }
-
- /* Aim for a load factor of 0.75 */
- // FIXME: temporarily broken until we have set descriptions
- cnt = 100;
- cnt = cnt * 4 / 3;
-
- priv->hash = kcalloc(cnt, sizeof(struct hlist_head), GFP_KERNEL);
- if (priv->hash == NULL)
- return -ENOMEM;
- priv->hsize = cnt;
-
- for (i = 0; i < cnt; i++)
- INIT_HLIST_HEAD(&priv->hash[i]);
-
- return 0;
-}
-
-static void nft_hash_destroy(const struct nft_set *set)
-{
- const struct nft_hash *priv = nft_set_priv(set);
- const struct hlist_node *next;
- struct nft_hash_elem *elem;
- unsigned int i;
-
- for (i = 0; i < priv->hsize; i++) {
- hlist_for_each_entry_safe(elem, next, &priv->hash[i], hnode) {
- hlist_del(&elem->hnode);
- nft_hash_elem_destroy(set, elem);
- }
- }
- kfree(priv->hash);
-}
-
-static struct nft_set_ops nft_hash_ops __read_mostly = {
- .privsize = nft_hash_privsize,
- .init = nft_hash_init,
- .destroy = nft_hash_destroy,
- .get = nft_hash_get,
- .insert = nft_hash_insert,
- .remove = nft_hash_remove,
- .lookup = nft_hash_lookup,
- .walk = nft_hash_walk,
- .features = NFT_SET_MAP,
- .owner = THIS_MODULE,
-};
-
-static int __init nft_hash_module_init(void)
-{
- return nft_register_set(&nft_hash_ops);
-}
-
-static void __exit nft_hash_module_exit(void)
-{
- nft_unregister_set(&nft_hash_ops);
-}
-
-module_init(nft_hash_module_init);
-module_exit(nft_hash_module_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
-MODULE_ALIAS_NFT_SET();
diff --git a/net/netfilter/nft_immediate.c b/net/netfilter/nft_immediate.c
deleted file mode 100644
index f169501..0000000
--- a/net/netfilter/nft_immediate.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Development of this code funded by Astaro AG (http://www.astaro.com/)
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/netlink.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter/nf_tables.h>
-#include <net/netfilter/nf_tables_core.h>
-#include <net/netfilter/nf_tables.h>
-
-struct nft_immediate_expr {
- struct nft_data data;
- enum nft_registers dreg:8;
- u8 dlen;
-};
-
-static void nft_immediate_eval(const struct nft_expr *expr,
- struct nft_data data[NFT_REG_MAX + 1],
- const struct nft_pktinfo *pkt)
-{
- const struct nft_immediate_expr *priv = nft_expr_priv(expr);
-
- nft_data_copy(&data[priv->dreg], &priv->data);
-}
-
-static const struct nla_policy nft_immediate_policy[NFTA_IMMEDIATE_MAX + 1] = {
- [NFTA_IMMEDIATE_DREG] = { .type = NLA_U32 },
- [NFTA_IMMEDIATE_DATA] = { .type = NLA_NESTED },
-};
-
-static int nft_immediate_init(const struct nft_ctx *ctx,
- const struct nft_expr *expr,
- const struct nlattr * const tb[])
-{
- struct nft_immediate_expr *priv = nft_expr_priv(expr);
- struct nft_data_desc desc;
- int err;
-
- if (tb[NFTA_IMMEDIATE_DREG] == NULL ||
- tb[NFTA_IMMEDIATE_DATA] == NULL)
- return -EINVAL;
-
- priv->dreg = ntohl(nla_get_be32(tb[NFTA_IMMEDIATE_DREG]));
- err = nft_validate_output_register(priv->dreg);
- if (err < 0)
- return err;
-
- err = nft_data_init(ctx, &priv->data, &desc, tb[NFTA_IMMEDIATE_DATA]);
- if (err < 0)
- return err;
- priv->dlen = desc.len;
-
- err = nft_validate_data_load(ctx, priv->dreg, &priv->data, desc.type);
- if (err < 0)
- goto err1;
-
- return 0;
-
-err1:
- nft_data_uninit(&priv->data, desc.type);
- return err;
-}
-
-static void nft_immediate_destroy(const struct nft_expr *expr)
-{
- const struct nft_immediate_expr *priv = nft_expr_priv(expr);
- return nft_data_uninit(&priv->data, nft_dreg_to_type(priv->dreg));
-}
-
-static int nft_immediate_dump(struct sk_buff *skb, const struct nft_expr *expr)
-{
- const struct nft_immediate_expr *priv = nft_expr_priv(expr);
-
- if (nla_put_be32(skb, NFTA_IMMEDIATE_DREG, htonl(priv->dreg)))
- goto nla_put_failure;
-
- return nft_data_dump(skb, NFTA_IMMEDIATE_DATA, &priv->data,
- nft_dreg_to_type(priv->dreg), priv->dlen);
-
-nla_put_failure:
- return -1;
-}
-
-static int nft_immediate_validate(const struct nft_ctx *ctx,
- const struct nft_expr *expr,
- const struct nft_data **data)
-{
- const struct nft_immediate_expr *priv = nft_expr_priv(expr);
-
- if (priv->dreg == NFT_REG_VERDICT)
- *data = &priv->data;
-
- return 0;
-}
-
-static struct nft_expr_type nft_imm_type;
-static const struct nft_expr_ops nft_imm_ops = {
- .type = &nft_imm_type,
- .size = NFT_EXPR_SIZE(sizeof(struct nft_immediate_expr)),
- .eval = nft_immediate_eval,
- .init = nft_immediate_init,
- .destroy = nft_immediate_destroy,
- .dump = nft_immediate_dump,
- .validate = nft_immediate_validate,
-};
-
-static struct nft_expr_type nft_imm_type __read_mostly = {
- .name = "immediate",
- .ops = &nft_imm_ops,
- .policy = nft_immediate_policy,
- .maxattr = NFTA_IMMEDIATE_MAX,
- .owner = THIS_MODULE,
-};
-
-int __init nft_immediate_module_init(void)
-{
- return nft_register_expr(&nft_imm_type);
-}
-
-void nft_immediate_module_exit(void)
-{
- nft_unregister_expr(&nft_imm_type);
-}
diff --git a/net/netfilter/nft_limit.c b/net/netfilter/nft_limit.c
deleted file mode 100644
index 85da5bd..0000000
--- a/net/netfilter/nft_limit.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Development of this code funded by Astaro AG (http://www.astaro.com/)
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/netlink.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter/nf_tables.h>
-#include <net/netfilter/nf_tables.h>
-
-static DEFINE_SPINLOCK(limit_lock);
-
-struct nft_limit {
- u64 tokens;
- u64 rate;
- u64 unit;
- unsigned long stamp;
-};
-
-static void nft_limit_eval(const struct nft_expr *expr,
- struct nft_data data[NFT_REG_MAX + 1],
- const struct nft_pktinfo *pkt)
-{
- struct nft_limit *priv = nft_expr_priv(expr);
-
- spin_lock_bh(&limit_lock);
- if (time_after_eq(jiffies, priv->stamp)) {
- priv->tokens = priv->rate;
- priv->stamp = jiffies + priv->unit * HZ;
- }
-
- if (priv->tokens >= 1) {
- priv->tokens--;
- spin_unlock_bh(&limit_lock);
- return;
- }
- spin_unlock_bh(&limit_lock);
-
- data[NFT_REG_VERDICT].verdict = NFT_BREAK;
-}
-
-static const struct nla_policy nft_limit_policy[NFTA_LIMIT_MAX + 1] = {
- [NFTA_LIMIT_RATE] = { .type = NLA_U64 },
- [NFTA_LIMIT_UNIT] = { .type = NLA_U64 },
-};
-
-static int nft_limit_init(const struct nft_ctx *ctx,
- const struct nft_expr *expr,
- const struct nlattr * const tb[])
-{
- struct nft_limit *priv = nft_expr_priv(expr);
-
- if (tb[NFTA_LIMIT_RATE] == NULL ||
- tb[NFTA_LIMIT_UNIT] == NULL)
- return -EINVAL;
-
- priv->rate = be64_to_cpu(nla_get_be64(tb[NFTA_LIMIT_RATE]));
- priv->unit = be64_to_cpu(nla_get_be64(tb[NFTA_LIMIT_UNIT]));
- priv->stamp = jiffies + priv->unit * HZ;
- priv->tokens = priv->rate;
- return 0;
-}
-
-static int nft_limit_dump(struct sk_buff *skb, const struct nft_expr *expr)
-{
- const struct nft_limit *priv = nft_expr_priv(expr);
-
- if (nla_put_be64(skb, NFTA_LIMIT_RATE, cpu_to_be64(priv->rate)))
- goto nla_put_failure;
- if (nla_put_be64(skb, NFTA_LIMIT_UNIT, cpu_to_be64(priv->unit)))
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return -1;
-}
-
-static struct nft_expr_type nft_limit_type;
-static const struct nft_expr_ops nft_limit_ops = {
- .type = &nft_limit_type,
- .size = NFT_EXPR_SIZE(sizeof(struct nft_limit)),
- .eval = nft_limit_eval,
- .init = nft_limit_init,
- .dump = nft_limit_dump,
-};
-
-static struct nft_expr_type nft_limit_type __read_mostly = {
- .name = "limit",
- .ops = &nft_limit_ops,
- .policy = nft_limit_policy,
- .maxattr = NFTA_LIMIT_MAX,
- .owner = THIS_MODULE,
-};
-
-static int __init nft_limit_module_init(void)
-{
- return nft_register_expr(&nft_limit_type);
-}
-
-static void __exit nft_limit_module_exit(void)
-{
- nft_unregister_expr(&nft_limit_type);
-}
-
-module_init(nft_limit_module_init);
-module_exit(nft_limit_module_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
-MODULE_ALIAS_NFT_EXPR("limit");
diff --git a/net/netfilter/nft_log.c b/net/netfilter/nft_log.c
deleted file mode 100644
index 57cad07..0000000
--- a/net/netfilter/nft_log.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Development of this code funded by Astaro AG (http://www.astaro.com/)
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/netlink.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter/nf_tables.h>
-#include <net/netfilter/nf_tables.h>
-#include <net/netfilter/nf_log.h>
-#include <linux/netdevice.h>
-
-static const char *nft_log_null_prefix = "";
-
-struct nft_log {
- struct nf_loginfo loginfo;
- char *prefix;
- int family;
-};
-
-static void nft_log_eval(const struct nft_expr *expr,
- struct nft_data data[NFT_REG_MAX + 1],
- const struct nft_pktinfo *pkt)
-{
- const struct nft_log *priv = nft_expr_priv(expr);
- struct net *net = dev_net(pkt->in ? pkt->in : pkt->out);
-
- nf_log_packet(net, priv->family, pkt->hooknum, pkt->skb, pkt->in,
- pkt->out, &priv->loginfo, "%s", priv->prefix);
-}
-
-static const struct nla_policy nft_log_policy[NFTA_LOG_MAX + 1] = {
- [NFTA_LOG_GROUP] = { .type = NLA_U16 },
- [NFTA_LOG_PREFIX] = { .type = NLA_STRING },
- [NFTA_LOG_SNAPLEN] = { .type = NLA_U32 },
- [NFTA_LOG_QTHRESHOLD] = { .type = NLA_U16 },
-};
-
-static int nft_log_init(const struct nft_ctx *ctx,
- const struct nft_expr *expr,
- const struct nlattr * const tb[])
-{
- struct nft_log *priv = nft_expr_priv(expr);
- struct nf_loginfo *li = &priv->loginfo;
- const struct nlattr *nla;
-
- priv->family = ctx->afi->family;
-
- nla = tb[NFTA_LOG_PREFIX];
- if (nla != NULL) {
- priv->prefix = kmalloc(nla_len(nla) + 1, GFP_KERNEL);
- if (priv->prefix == NULL)
- return -ENOMEM;
- nla_strlcpy(priv->prefix, nla, nla_len(nla) + 1);
- } else
- priv->prefix = (char *)nft_log_null_prefix;
-
- li->type = NF_LOG_TYPE_ULOG;
- if (tb[NFTA_LOG_GROUP] != NULL)
- li->u.ulog.group = ntohs(nla_get_be16(tb[NFTA_LOG_GROUP]));
-
- if (tb[NFTA_LOG_SNAPLEN] != NULL)
- li->u.ulog.copy_len = ntohl(nla_get_be32(tb[NFTA_LOG_SNAPLEN]));
- if (tb[NFTA_LOG_QTHRESHOLD] != NULL) {
- li->u.ulog.qthreshold =
- ntohs(nla_get_be16(tb[NFTA_LOG_QTHRESHOLD]));
- }
-
- return 0;
-}
-
-static void nft_log_destroy(const struct nft_expr *expr)
-{
- struct nft_log *priv = nft_expr_priv(expr);
-
- if (priv->prefix != nft_log_null_prefix)
- kfree(priv->prefix);
-}
-
-static int nft_log_dump(struct sk_buff *skb, const struct nft_expr *expr)
-{
- const struct nft_log *priv = nft_expr_priv(expr);
- const struct nf_loginfo *li = &priv->loginfo;
-
- if (priv->prefix != nft_log_null_prefix)
- if (nla_put_string(skb, NFTA_LOG_PREFIX, priv->prefix))
- goto nla_put_failure;
- if (li->u.ulog.group)
- if (nla_put_be16(skb, NFTA_LOG_GROUP, htons(li->u.ulog.group)))
- goto nla_put_failure;
- if (li->u.ulog.copy_len)
- if (nla_put_be32(skb, NFTA_LOG_SNAPLEN,
- htonl(li->u.ulog.copy_len)))
- goto nla_put_failure;
- if (li->u.ulog.qthreshold)
- if (nla_put_be16(skb, NFTA_LOG_QTHRESHOLD,
- htons(li->u.ulog.qthreshold)))
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return -1;
-}
-
-static struct nft_expr_type nft_log_type;
-static const struct nft_expr_ops nft_log_ops = {
- .type = &nft_log_type,
- .size = NFT_EXPR_SIZE(sizeof(struct nft_log)),
- .eval = nft_log_eval,
- .init = nft_log_init,
- .destroy = nft_log_destroy,
- .dump = nft_log_dump,
-};
-
-static struct nft_expr_type nft_log_type __read_mostly = {
- .name = "log",
- .ops = &nft_log_ops,
- .policy = nft_log_policy,
- .maxattr = NFTA_LOG_MAX,
- .owner = THIS_MODULE,
-};
-
-static int __init nft_log_module_init(void)
-{
- return nft_register_expr(&nft_log_type);
-}
-
-static void __exit nft_log_module_exit(void)
-{
- nft_unregister_expr(&nft_log_type);
-}
-
-module_init(nft_log_module_init);
-module_exit(nft_log_module_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
-MODULE_ALIAS_NFT_EXPR("log");
diff --git a/net/netfilter/nft_lookup.c b/net/netfilter/nft_lookup.c
deleted file mode 100644
index 8a6116b..0000000
--- a/net/netfilter/nft_lookup.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (c) 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/list.h>
-#include <linux/rbtree.h>
-#include <linux/netlink.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter/nf_tables.h>
-#include <net/netfilter/nf_tables.h>
-
-struct nft_lookup {
- struct nft_set *set;
- enum nft_registers sreg:8;
- enum nft_registers dreg:8;
- struct nft_set_binding binding;
-};
-
-static void nft_lookup_eval(const struct nft_expr *expr,
- struct nft_data data[NFT_REG_MAX + 1],
- const struct nft_pktinfo *pkt)
-{
- const struct nft_lookup *priv = nft_expr_priv(expr);
- const struct nft_set *set = priv->set;
-
- if (set->ops->lookup(set, &data[priv->sreg], &data[priv->dreg]))
- return;
- data[NFT_REG_VERDICT].verdict = NFT_BREAK;
-}
-
-static const struct nla_policy nft_lookup_policy[NFTA_LOOKUP_MAX + 1] = {
- [NFTA_LOOKUP_SET] = { .type = NLA_STRING },
- [NFTA_LOOKUP_SREG] = { .type = NLA_U32 },
- [NFTA_LOOKUP_DREG] = { .type = NLA_U32 },
-};
-
-static int nft_lookup_init(const struct nft_ctx *ctx,
- const struct nft_expr *expr,
- const struct nlattr * const tb[])
-{
- struct nft_lookup *priv = nft_expr_priv(expr);
- struct nft_set *set;
- int err;
-
- if (tb[NFTA_LOOKUP_SET] == NULL ||
- tb[NFTA_LOOKUP_SREG] == NULL)
- return -EINVAL;
-
- set = nf_tables_set_lookup(ctx->table, tb[NFTA_LOOKUP_SET]);
- if (IS_ERR(set))
- return PTR_ERR(set);
-
- priv->sreg = ntohl(nla_get_be32(tb[NFTA_LOOKUP_SREG]));
- err = nft_validate_input_register(priv->sreg);
- if (err < 0)
- return err;
-
- if (tb[NFTA_LOOKUP_DREG] != NULL) {
- if (!(set->flags & NFT_SET_MAP))
- return -EINVAL;
-
- priv->dreg = ntohl(nla_get_be32(tb[NFTA_LOOKUP_DREG]));
- err = nft_validate_output_register(priv->dreg);
- if (err < 0)
- return err;
-
- if (priv->dreg == NFT_REG_VERDICT) {
- if (set->dtype != NFT_DATA_VERDICT)
- return -EINVAL;
- } else if (set->dtype == NFT_DATA_VERDICT)
- return -EINVAL;
- } else if (set->flags & NFT_SET_MAP)
- return -EINVAL;
-
- err = nf_tables_bind_set(ctx, set, &priv->binding);
- if (err < 0)
- return err;
-
- priv->set = set;
- return 0;
-}
-
-static void nft_lookup_destroy(const struct nft_expr *expr)
-{
- struct nft_lookup *priv = nft_expr_priv(expr);
-
- nf_tables_unbind_set(NULL, priv->set, &priv->binding);
-}
-
-static int nft_lookup_dump(struct sk_buff *skb, const struct nft_expr *expr)
-{
- const struct nft_lookup *priv = nft_expr_priv(expr);
-
- if (nla_put_string(skb, NFTA_LOOKUP_SET, priv->set->name))
- goto nla_put_failure;
- if (nla_put_be32(skb, NFTA_LOOKUP_SREG, htonl(priv->sreg)))
- goto nla_put_failure;
- if (priv->set->flags & NFT_SET_MAP)
- if (nla_put_be32(skb, NFTA_LOOKUP_DREG, htonl(priv->dreg)))
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return -1;
-}
-
-static struct nft_expr_type nft_lookup_type;
-static const struct nft_expr_ops nft_lookup_ops = {
- .type = &nft_lookup_type,
- .size = NFT_EXPR_SIZE(sizeof(struct nft_lookup)),
- .eval = nft_lookup_eval,
- .init = nft_lookup_init,
- .destroy = nft_lookup_destroy,
- .dump = nft_lookup_dump,
-};
-
-static struct nft_expr_type nft_lookup_type __read_mostly = {
- .name = "lookup",
- .ops = &nft_lookup_ops,
- .policy = nft_lookup_policy,
- .maxattr = NFTA_LOOKUP_MAX,
- .owner = THIS_MODULE,
-};
-
-int __init nft_lookup_module_init(void)
-{
- return nft_register_expr(&nft_lookup_type);
-}
-
-void nft_lookup_module_exit(void)
-{
- nft_unregister_expr(&nft_lookup_type);
-}
diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
deleted file mode 100644
index 8c28220..0000000
--- a/net/netfilter/nft_meta.c
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Development of this code funded by Astaro AG (http://www.astaro.com/)
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/netlink.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter/nf_tables.h>
-#include <net/dst.h>
-#include <net/sock.h>
-#include <net/tcp_states.h> /* for TCP_TIME_WAIT */
-#include <net/netfilter/nf_tables.h>
-
-struct nft_meta {
- enum nft_meta_keys key:8;
- enum nft_registers dreg:8;
-};
-
-static void nft_meta_eval(const struct nft_expr *expr,
- struct nft_data data[NFT_REG_MAX + 1],
- const struct nft_pktinfo *pkt)
-{
- const struct nft_meta *priv = nft_expr_priv(expr);
- const struct sk_buff *skb = pkt->skb;
- const struct net_device *in = pkt->in, *out = pkt->out;
- struct nft_data *dest = &data[priv->dreg];
-
- switch (priv->key) {
- case NFT_META_LEN:
- dest->data[0] = skb->len;
- break;
- case NFT_META_PROTOCOL:
- *(__be16 *)dest->data = skb->protocol;
- break;
- case NFT_META_PRIORITY:
- dest->data[0] = skb->priority;
- break;
- case NFT_META_MARK:
- dest->data[0] = skb->mark;
- break;
- case NFT_META_IIF:
- if (in == NULL)
- goto err;
- dest->data[0] = in->ifindex;
- break;
- case NFT_META_OIF:
- if (out == NULL)
- goto err;
- dest->data[0] = out->ifindex;
- break;
- case NFT_META_IIFNAME:
- if (in == NULL)
- goto err;
- strncpy((char *)dest->data, in->name, sizeof(dest->data));
- break;
- case NFT_META_OIFNAME:
- if (out == NULL)
- goto err;
- strncpy((char *)dest->data, out->name, sizeof(dest->data));
- break;
- case NFT_META_IIFTYPE:
- if (in == NULL)
- goto err;
- *(u16 *)dest->data = in->type;
- break;
- case NFT_META_OIFTYPE:
- if (out == NULL)
- goto err;
- *(u16 *)dest->data = out->type;
- break;
- case NFT_META_SKUID:
- if (skb->sk == NULL || skb->sk->sk_state == TCP_TIME_WAIT)
- goto err;
-
- read_lock_bh(&skb->sk->sk_callback_lock);
- if (skb->sk->sk_socket == NULL ||
- skb->sk->sk_socket->file == NULL) {
- read_unlock_bh(&skb->sk->sk_callback_lock);
- goto err;
- }
-
- dest->data[0] =
- from_kuid_munged(&init_user_ns,
- skb->sk->sk_socket->file->f_cred->fsuid);
- read_unlock_bh(&skb->sk->sk_callback_lock);
- break;
- case NFT_META_SKGID:
- if (skb->sk == NULL || skb->sk->sk_state == TCP_TIME_WAIT)
- goto err;
-
- read_lock_bh(&skb->sk->sk_callback_lock);
- if (skb->sk->sk_socket == NULL ||
- skb->sk->sk_socket->file == NULL) {
- read_unlock_bh(&skb->sk->sk_callback_lock);
- goto err;
- }
- dest->data[0] =
- from_kgid_munged(&init_user_ns,
- skb->sk->sk_socket->file->f_cred->fsgid);
- read_unlock_bh(&skb->sk->sk_callback_lock);
- break;
-#ifdef CONFIG_NET_CLS_ROUTE
- case NFT_META_RTCLASSID: {
- const struct dst_entry *dst = skb_dst(skb);
-
- if (dst == NULL)
- goto err;
- dest->data[0] = dst->tclassid;
- break;
- }
-#endif
-#ifdef CONFIG_NETWORK_SECMARK
- case NFT_META_SECMARK:
- dest->data[0] = skb->secmark;
- break;
-#endif
- default:
- WARN_ON(1);
- goto err;
- }
- return;
-
-err:
- data[NFT_REG_VERDICT].verdict = NFT_BREAK;
-}
-
-static const struct nla_policy nft_meta_policy[NFTA_META_MAX + 1] = {
- [NFTA_META_DREG] = { .type = NLA_U32 },
- [NFTA_META_KEY] = { .type = NLA_U32 },
-};
-
-static int nft_meta_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
- const struct nlattr * const tb[])
-{
- struct nft_meta *priv = nft_expr_priv(expr);
- int err;
-
- if (tb[NFTA_META_DREG] == NULL ||
- tb[NFTA_META_KEY] == NULL)
- return -EINVAL;
-
- priv->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
- switch (priv->key) {
- case NFT_META_LEN:
- case NFT_META_PROTOCOL:
- case NFT_META_PRIORITY:
- case NFT_META_MARK:
- case NFT_META_IIF:
- case NFT_META_OIF:
- case NFT_META_IIFNAME:
- case NFT_META_OIFNAME:
- case NFT_META_IIFTYPE:
- case NFT_META_OIFTYPE:
- case NFT_META_SKUID:
- case NFT_META_SKGID:
-#ifdef CONFIG_NET_CLS_ROUTE
- case NFT_META_RTCLASSID:
-#endif
-#ifdef CONFIG_NETWORK_SECMARK
- case NFT_META_SECMARK:
-#endif
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- priv->dreg = ntohl(nla_get_be32(tb[NFTA_META_DREG]));
- err = nft_validate_output_register(priv->dreg);
- if (err < 0)
- return err;
- return nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
-}
-
-static int nft_meta_dump(struct sk_buff *skb, const struct nft_expr *expr)
-{
- const struct nft_meta *priv = nft_expr_priv(expr);
-
- if (nla_put_be32(skb, NFTA_META_DREG, htonl(priv->dreg)))
- goto nla_put_failure;
- if (nla_put_be32(skb, NFTA_META_KEY, htonl(priv->key)))
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return -1;
-}
-
-static struct nft_expr_type nft_meta_type;
-static const struct nft_expr_ops nft_meta_ops = {
- .type = &nft_meta_type,
- .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)),
- .eval = nft_meta_eval,
- .init = nft_meta_init,
- .dump = nft_meta_dump,
-};
-
-static struct nft_expr_type nft_meta_type __read_mostly = {
- .name = "meta",
- .ops = &nft_meta_ops,
- .policy = nft_meta_policy,
- .maxattr = NFTA_META_MAX,
- .owner = THIS_MODULE,
-};
-
-static int __init nft_meta_module_init(void)
-{
- return nft_register_expr(&nft_meta_type);
-}
-
-static void __exit nft_meta_module_exit(void)
-{
- nft_unregister_expr(&nft_meta_type);
-}
-
-module_init(nft_meta_module_init);
-module_exit(nft_meta_module_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
-MODULE_ALIAS_NFT_EXPR("meta");
diff --git a/net/netfilter/nft_meta_target.c b/net/netfilter/nft_meta_target.c
deleted file mode 100644
index 71177df..0000000
--- a/net/netfilter/nft_meta_target.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (c) 2008 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/list.h>
-#include <linux/rbtree.h>
-#include <linux/netlink.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter/nf_tables.h>
-#include <net/netfilter/nf_tables.h>
-
-struct nft_meta {
- enum nft_meta_keys key;
-};
-
-static void nft_meta_eval(const struct nft_expr *expr,
- struct nft_data *nfres,
- struct nft_data *data,
- const struct nft_pktinfo *pkt)
-{
- const struct nft_meta *meta = nft_expr_priv(expr);
- struct sk_buff *skb = pkt->skb;
- u32 val = data->data[0];
-
- switch (meta->key) {
- case NFT_META_MARK:
- skb->mark = val;
- break;
- case NFT_META_PRIORITY:
- skb->priority = val;
- break;
- case NFT_META_NFTRACE:
- skb->nf_trace = val;
- break;
-#ifdef CONFIG_NETWORK_SECMARK
- case NFT_META_SECMARK:
- skb->secmark = val;
- break;
-#endif
- default:
- WARN_ON(1);
- }
-}
-
-static const struct nla_policy nft_meta_policy[NFTA_META_MAX + 1] = {
- [NFTA_META_KEY] = { .type = NLA_U32 },
-};
-
-static int nft_meta_init(const struct nft_expr *expr, struct nlattr *tb[])
-{
- struct nft_meta *meta = nft_expr_priv(expr);
-
- if (tb[NFTA_META_KEY] == NULL)
- return -EINVAL;
-
- meta->key = ntohl(nla_get_be32(tb[NFTA_META_KEY]));
- switch (meta->key) {
- case NFT_META_MARK:
- case NFT_META_PRIORITY:
- case NFT_META_NFTRACE:
-#ifdef CONFIG_NETWORK_SECMARK
- case NFT_META_SECMARK:
-#endif
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int nft_meta_dump(struct sk_buff *skb, const struct nft_expr *expr)
-{
- struct nft_meta *meta = nft_expr_priv(expr);
-
- NLA_PUT_BE32(skb, NFTA_META_KEY, htonl(meta->key));
- return 0;
-
-nla_put_failure:
- return -1;
-}
-
-static struct nft_expr_ops meta_target __read_mostly = {
- .name = "meta",
- .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)),
- .owner = THIS_MODULE,
- .eval = nft_meta_eval,
- .init = nft_meta_init,
- .dump = nft_meta_dump,
- .policy = nft_meta_policy,
- .maxattr = NFTA_META_MAX,
-};
-
-static int __init nft_meta_target_init(void)
-{
- return nft_register_expr(&meta_target);
-}
-
-static void __exit nft_meta_target_exit(void)
-{
- nft_unregister_expr(&meta_target);
-}
-
-module_init(nft_meta_target_init);
-module_exit(nft_meta_target_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
-MODULE_ALIAS_NFT_EXPR("meta");
diff --git a/net/netfilter/nft_nat.c b/net/netfilter/nft_nat.c
deleted file mode 100644
index d3b1ffe..0000000
--- a/net/netfilter/nft_nat.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
- * Copyright (c) 2012 Pablo Neira Ayuso <pablo@netfilter.org>
- * Copyright (c) 2012 Intel Corporation
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/skbuff.h>
-#include <linux/ip.h>
-#include <linux/string.h>
-#include <linux/netlink.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/netfilter/nfnetlink.h>
-#include <linux/netfilter/nf_tables.h>
-#include <net/netfilter/nf_conntrack.h>
-#include <net/netfilter/nf_nat.h>
-#include <net/netfilter/nf_nat_core.h>
-#include <net/netfilter/nf_tables.h>
-#include <net/netfilter/nf_nat_l3proto.h>
-#include <net/ip.h>
-
-struct nft_nat {
- enum nft_registers sreg_addr_min:8;
- enum nft_registers sreg_addr_max:8;
- enum nft_registers sreg_proto_min:8;
- enum nft_registers sreg_proto_max:8;
- int family;
- enum nf_nat_manip_type type;
-};
-
-static void nft_nat_eval(const struct nft_expr *expr,
- struct nft_data data[NFT_REG_MAX + 1],
- const struct nft_pktinfo *pkt)
-{
- const struct nft_nat *priv = nft_expr_priv(expr);
- enum ip_conntrack_info ctinfo;
- struct nf_conn *ct = nf_ct_get(pkt->skb, &ctinfo);
- struct nf_nat_range range;
-
- memset(&range, 0, sizeof(range));
- if (priv->sreg_addr_min) {
- if (priv->family == AF_INET) {
- range.min_addr.ip = (__force __be32)
- data[priv->sreg_addr_min].data[0];
- range.max_addr.ip = (__force __be32)
- data[priv->sreg_addr_max].data[0];
-
- } else {
- memcpy(range.min_addr.ip6,
- data[priv->sreg_addr_min].data,
- sizeof(struct nft_data));
- memcpy(range.max_addr.ip6,
- data[priv->sreg_addr_max].data,
- sizeof(struct nft_data));
- }
- range.flags |= NF_NAT_RANGE_MAP_IPS;
- }
-
- if (priv->sreg_proto_min) {
- range.min_proto.all = (__force __be16)
- data[priv->sreg_proto_min].data[0];
- range.max_proto.all = (__force __be16)
- data[priv->sreg_proto_max].data[0];
- range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
- }
-
- data[NFT_REG_VERDICT].verdict =
- nf_nat_setup_info(ct, &range, priv->type);
-}
-
-static const struct nla_policy nft_nat_policy[NFTA_NAT_MAX + 1] = {
- [NFTA_NAT_TYPE] = { .type = NLA_U32 },
- [NFTA_NAT_FAMILY] = { .type = NLA_U32 },
- [NFTA_NAT_REG_ADDR_MIN] = { .type = NLA_U32 },
- [NFTA_NAT_REG_ADDR_MAX] = { .type = NLA_U32 },
- [NFTA_NAT_REG_PROTO_MIN] = { .type = NLA_U32 },
- [NFTA_NAT_REG_PROTO_MAX] = { .type = NLA_U32 },
-};
-
-static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
- const struct nlattr * const tb[])
-{
- struct nft_nat *priv = nft_expr_priv(expr);
- int err;
-
- if (tb[NFTA_NAT_TYPE] == NULL)
- return -EINVAL;
-
- switch (ntohl(nla_get_be32(tb[NFTA_NAT_TYPE]))) {
- case NFT_NAT_SNAT:
- priv->type = NF_NAT_MANIP_SRC;
- break;
- case NFT_NAT_DNAT:
- priv->type = NF_NAT_MANIP_DST;
- break;
- default:
- return -EINVAL;
- }
-
- if (tb[NFTA_NAT_FAMILY] == NULL)
- return -EINVAL;
-
- priv->family = ntohl(nla_get_be32(tb[NFTA_NAT_FAMILY]));
- if (priv->family != AF_INET && priv->family != AF_INET6)
- return -EINVAL;
-
- if (tb[NFTA_NAT_REG_ADDR_MIN]) {
- priv->sreg_addr_min = ntohl(nla_get_be32(
- tb[NFTA_NAT_REG_ADDR_MIN]));
- err = nft_validate_input_register(priv->sreg_addr_min);
- if (err < 0)
- return err;
- }
-
- if (tb[NFTA_NAT_REG_ADDR_MAX]) {
- priv->sreg_addr_max = ntohl(nla_get_be32(
- tb[NFTA_NAT_REG_ADDR_MAX]));
- err = nft_validate_input_register(priv->sreg_addr_max);
- if (err < 0)
- return err;
- } else
- priv->sreg_addr_max = priv->sreg_addr_min;
-
- if (tb[NFTA_NAT_REG_PROTO_MIN]) {
- priv->sreg_proto_min = ntohl(nla_get_be32(
- tb[NFTA_NAT_REG_PROTO_MIN]));
- err = nft_validate_input_register(priv->sreg_proto_min);
- if (err < 0)
- return err;
- }
-
- if (tb[NFTA_NAT_REG_PROTO_MAX]) {
- priv->sreg_proto_max = ntohl(nla_get_be32(
- tb[NFTA_NAT_REG_PROTO_MAX]));
- err = nft_validate_input_register(priv->sreg_proto_max);
- if (err < 0)
- return err;
- } else
- priv->sreg_proto_max = priv->sreg_proto_min;
-
- return 0;
-}
-
-static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr)
-{
- const struct nft_nat *priv = nft_expr_priv(expr);
-
- switch (priv->type) {
- case NF_NAT_MANIP_SRC:
- if (nla_put_be32(skb, NFTA_NAT_TYPE, htonl(NFT_NAT_SNAT)))
- goto nla_put_failure;
- break;
- case NF_NAT_MANIP_DST:
- if (nla_put_be32(skb, NFTA_NAT_TYPE, htonl(NFT_NAT_DNAT)))
- goto nla_put_failure;
- break;
- }
-
- if (nla_put_be32(skb, NFTA_NAT_FAMILY, htonl(priv->family)))
- goto nla_put_failure;
- if (nla_put_be32(skb,
- NFTA_NAT_REG_ADDR_MIN, htonl(priv->sreg_addr_min)))
- goto nla_put_failure;
- if (nla_put_be32(skb,
- NFTA_NAT_REG_ADDR_MAX, htonl(priv->sreg_addr_max)))
- goto nla_put_failure;
- if (nla_put_be32(skb,
- NFTA_NAT_REG_PROTO_MIN, htonl(priv->sreg_proto_min)))
- goto nla_put_failure;
- if (nla_put_be32(skb,
- NFTA_NAT_REG_PROTO_MAX, htonl(priv->sreg_proto_max)))
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return -1;
-}
-
-static struct nft_expr_type nft_nat_type;
-static const struct nft_expr_ops nft_nat_ops = {
- .type = &nft_nat_type,
- .size = NFT_EXPR_SIZE(sizeof(struct nft_nat)),
- .eval = nft_nat_eval,
- .init = nft_nat_init,
- .dump = nft_nat_dump,
-};
-
-static struct nft_expr_type nft_nat_type __read_mostly = {
- .name = "nat",
- .ops = &nft_nat_ops,
- .policy = nft_nat_policy,
- .maxattr = NFTA_NAT_MAX,
- .owner = THIS_MODULE,
-};
-
-static int __init nft_nat_module_init(void)
-{
- int err;
-
- err = nft_register_expr(&nft_nat_type);
- if (err < 0)
- return err;
-
- return 0;
-}
-
-static void __exit nft_nat_module_exit(void)
-{
- nft_unregister_expr(&nft_nat_type);
-}
-
-module_init(nft_nat_module_init);
-module_exit(nft_nat_module_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>");
-MODULE_ALIAS_NFT_EXPR("nat");
diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c
deleted file mode 100644
index a2aeb31..0000000
--- a/net/netfilter/nft_payload.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Development of this code funded by Astaro AG (http://www.astaro.com/)
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/netlink.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter/nf_tables.h>
-#include <net/netfilter/nf_tables_core.h>
-#include <net/netfilter/nf_tables.h>
-
-static void nft_payload_eval(const struct nft_expr *expr,
- struct nft_data data[NFT_REG_MAX + 1],
- const struct nft_pktinfo *pkt)
-{
- const struct nft_payload *priv = nft_expr_priv(expr);
- const struct sk_buff *skb = pkt->skb;
- struct nft_data *dest = &data[priv->dreg];
- int offset;
-
- switch (priv->base) {
- case NFT_PAYLOAD_LL_HEADER:
- if (!skb_mac_header_was_set(skb))
- goto err;
- offset = skb_mac_header(skb) - skb->data;
- break;
- case NFT_PAYLOAD_NETWORK_HEADER:
- offset = skb_network_offset(skb);
- break;
- case NFT_PAYLOAD_TRANSPORT_HEADER:
- offset = pkt->xt.thoff;
- break;
- default:
- BUG();
- }
- offset += priv->offset;
-
- if (skb_copy_bits(skb, offset, dest->data, priv->len) < 0)
- goto err;
- return;
-err:
- data[NFT_REG_VERDICT].verdict = NFT_BREAK;
-}
-
-static const struct nla_policy nft_payload_policy[NFTA_PAYLOAD_MAX + 1] = {
- [NFTA_PAYLOAD_DREG] = { .type = NLA_U32 },
- [NFTA_PAYLOAD_BASE] = { .type = NLA_U32 },
- [NFTA_PAYLOAD_OFFSET] = { .type = NLA_U32 },
- [NFTA_PAYLOAD_LEN] = { .type = NLA_U32 },
-};
-
-static int nft_payload_init(const struct nft_ctx *ctx,
- const struct nft_expr *expr,
- const struct nlattr * const tb[])
-{
- struct nft_payload *priv = nft_expr_priv(expr);
- int err;
-
- priv->base = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_BASE]));
- priv->offset = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_OFFSET]));
- priv->len = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN]));
-
- priv->dreg = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_DREG]));
- err = nft_validate_output_register(priv->dreg);
- if (err < 0)
- return err;
- return nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
-}
-
-static int nft_payload_dump(struct sk_buff *skb, const struct nft_expr *expr)
-{
- const struct nft_payload *priv = nft_expr_priv(expr);
-
- if (nla_put_be32(skb, NFTA_PAYLOAD_DREG, htonl(priv->dreg)) ||
- nla_put_be32(skb, NFTA_PAYLOAD_BASE, htonl(priv->base)) ||
- nla_put_be32(skb, NFTA_PAYLOAD_OFFSET, htonl(priv->offset)) ||
- nla_put_be32(skb, NFTA_PAYLOAD_LEN, htonl(priv->len)))
- goto nla_put_failure;
- return 0;
-
-nla_put_failure:
- return -1;
-}
-
-static struct nft_expr_type nft_payload_type;
-static const struct nft_expr_ops nft_payload_ops = {
- .type = &nft_payload_type,
- .size = NFT_EXPR_SIZE(sizeof(struct nft_payload)),
- .eval = nft_payload_eval,
- .init = nft_payload_init,
- .dump = nft_payload_dump,
-};
-
-const struct nft_expr_ops nft_payload_fast_ops = {
- .type = &nft_payload_type,
- .size = NFT_EXPR_SIZE(sizeof(struct nft_payload)),
- .eval = nft_payload_eval,
- .init = nft_payload_init,
- .dump = nft_payload_dump,
-};
-
-static const struct nft_expr_ops *
-nft_payload_select_ops(const struct nft_ctx *ctx,
- const struct nlattr * const tb[])
-{
- enum nft_payload_bases base;
- unsigned int offset, len;
-
- if (tb[NFTA_PAYLOAD_DREG] == NULL ||
- tb[NFTA_PAYLOAD_BASE] == NULL ||
- tb[NFTA_PAYLOAD_OFFSET] == NULL ||
- tb[NFTA_PAYLOAD_LEN] == NULL)
- return ERR_PTR(-EINVAL);
-
- base = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_BASE]));
- switch (base) {
- case NFT_PAYLOAD_LL_HEADER:
- case NFT_PAYLOAD_NETWORK_HEADER:
- case NFT_PAYLOAD_TRANSPORT_HEADER:
- break;
- default:
- return ERR_PTR(-EOPNOTSUPP);
- }
-
- offset = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_OFFSET]));
- len = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN]));
- if (len == 0 || len > FIELD_SIZEOF(struct nft_data, data))
- return ERR_PTR(-EINVAL);
-
- if (len <= 4 && IS_ALIGNED(offset, len) && base != NFT_PAYLOAD_LL_HEADER)
- return &nft_payload_fast_ops;
- else
- return &nft_payload_ops;
-}
-
-static struct nft_expr_type nft_payload_type __read_mostly = {
- .name = "payload",
- .select_ops = nft_payload_select_ops,
- .policy = nft_payload_policy,
- .maxattr = NFTA_PAYLOAD_MAX,
- .owner = THIS_MODULE,
-};
-
-int __init nft_payload_module_init(void)
-{
- return nft_register_expr(&nft_payload_type);
-}
-
-void nft_payload_module_exit(void)
-{
- nft_unregister_expr(&nft_payload_type);
-}
diff --git a/net/netfilter/nft_rbtree.c b/net/netfilter/nft_rbtree.c
deleted file mode 100644
index ca0c1b2..0000000
--- a/net/netfilter/nft_rbtree.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Development of this code funded by Astaro AG (http://www.astaro.com/)
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/list.h>
-#include <linux/rbtree.h>
-#include <linux/netlink.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter/nf_tables.h>
-#include <net/netfilter/nf_tables.h>
-
-struct nft_rbtree {
- struct rb_root root;
-};
-
-struct nft_rbtree_elem {
- struct rb_node node;
- u16 flags;
- struct nft_data key;
- struct nft_data data[];
-};
-
-static bool nft_rbtree_lookup(const struct nft_set *set,
- const struct nft_data *key,
- struct nft_data *data)
-{
- const struct nft_rbtree *priv = nft_set_priv(set);
- const struct nft_rbtree_elem *rbe, *interval = NULL;
- const struct rb_node *parent = priv->root.rb_node;
- int d;
-
- while (parent != NULL) {
- rbe = rb_entry(parent, struct nft_rbtree_elem, node);
-
- d = nft_data_cmp(&rbe->key, key, set->klen);
- if (d < 0) {
- parent = parent->rb_left;
- interval = rbe;
- } else if (d > 0)
- parent = parent->rb_right;
- else {
-found:
- if (rbe->flags & NFT_SET_ELEM_INTERVAL_END)
- goto out;
- if (set->flags & NFT_SET_MAP)
- nft_data_copy(data, rbe->data);
- return true;
- }
- }
-
- if (set->flags & NFT_SET_INTERVAL && interval != NULL) {
- rbe = interval;
- goto found;
- }
-out:
- return false;
-}
-
-static void nft_rbtree_elem_destroy(const struct nft_set *set,
- struct nft_rbtree_elem *rbe)
-{
- nft_data_uninit(&rbe->key, NFT_DATA_VALUE);
- if (set->flags & NFT_SET_MAP)
- nft_data_uninit(rbe->data, set->dtype);
- kfree(rbe);
-}
-
-static int __nft_rbtree_insert(const struct nft_set *set,
- struct nft_rbtree_elem *new)
-{
- struct nft_rbtree *priv = nft_set_priv(set);
- struct nft_rbtree_elem *rbe;
- struct rb_node *parent, **p;
- int d;
-
- parent = NULL;
- p = &priv->root.rb_node;
- while (*p != NULL) {
- parent = *p;
- rbe = rb_entry(parent, struct nft_rbtree_elem, node);
- d = nft_data_cmp(&rbe->key, &new->key, set->klen);
- if (d < 0)
- p = &parent->rb_left;
- else if (d > 0)
- p = &parent->rb_right;
- else
- return -EEXIST;
- }
- rb_link_node(&new->node, parent, p);
- rb_insert_color(&new->node, &priv->root);
- return 0;
-}
-
-static int nft_rbtree_insert(const struct nft_set *set,
- const struct nft_set_elem *elem)
-{
- struct nft_rbtree_elem *rbe;
- unsigned int size;
- int err;
-
- size = sizeof(*rbe);
- if (set->flags & NFT_SET_MAP)
- size += sizeof(rbe->data[0]);
-
- rbe = kzalloc(size, GFP_KERNEL);
- if (rbe == NULL)
- return -ENOMEM;
-
- rbe->flags = elem->flags;
- nft_data_copy(&rbe->key, &elem->key);
- if (set->flags & NFT_SET_MAP)
- nft_data_copy(rbe->data, &elem->data);
-
- err = __nft_rbtree_insert(set, rbe);
- if (err < 0)
- kfree(rbe);
- return err;
-}
-
-static void nft_rbtree_remove(const struct nft_set *set,
- const struct nft_set_elem *elem)
-{
- struct nft_rbtree *priv = nft_set_priv(set);
- struct nft_rbtree_elem *rbe = elem->cookie;
-
- rb_erase(&rbe->node, &priv->root);
- kfree(rbe);
-}
-
-static int nft_rbtree_get(const struct nft_set *set, struct nft_set_elem *elem)
-{
- const struct nft_rbtree *priv = nft_set_priv(set);
- const struct rb_node *parent = priv->root.rb_node;
- struct nft_rbtree_elem *rbe;
- int d;
-
- while (parent != NULL) {
- rbe = rb_entry(parent, struct nft_rbtree_elem, node);
-
- d = nft_data_cmp(&rbe->key, &elem->key, set->klen);
- if (d < 0)
- parent = parent->rb_left;
- else if (d > 0)
- parent = parent->rb_right;
- else {
- elem->cookie = rbe;
- if (set->flags & NFT_SET_MAP)
- nft_data_copy(&elem->data, rbe->data);
- elem->flags = rbe->flags;
- return 0;
- }
- }
- return -ENOENT;
-}
-
-static void nft_rbtree_walk(const struct nft_ctx *ctx,
- const struct nft_set *set,
- struct nft_set_iter *iter)
-{
- const struct nft_rbtree *priv = nft_set_priv(set);
- const struct nft_rbtree_elem *rbe;
- struct nft_set_elem elem;
- struct rb_node *node;
-
- for (node = rb_first(&priv->root); node != NULL; node = rb_next(node)) {
- if (iter->count < iter->skip)
- goto cont;
-
- rbe = rb_entry(node, struct nft_rbtree_elem, node);
- nft_data_copy(&elem.key, &rbe->key);
- if (set->flags & NFT_SET_MAP)
- nft_data_copy(&elem.data, rbe->data);
- elem.flags = rbe->flags;
-
- iter->err = iter->fn(ctx, set, iter, &elem);
- if (iter->err < 0)
- return;
-cont:
- iter->count++;
- }
-}
-
-static unsigned int nft_rbtree_privsize(const struct nlattr * const nla[])
-{
- return sizeof(struct nft_rbtree);
-}
-
-static int nft_rbtree_init(const struct nft_set *set,
- const struct nlattr * const nla[])
-{
- struct nft_rbtree *priv = nft_set_priv(set);
-
- priv->root = RB_ROOT;
- return 0;
-}
-
-static void nft_rbtree_destroy(const struct nft_set *set)
-{
- struct nft_rbtree *priv = nft_set_priv(set);
- struct nft_rbtree_elem *rbe;
- struct rb_node *node;
-
- while ((node = priv->root.rb_node) != NULL) {
- rb_erase(node, &priv->root);
- rbe = rb_entry(node, struct nft_rbtree_elem, node);
- nft_rbtree_elem_destroy(set, rbe);
- }
-}
-
-static struct nft_set_ops nft_rbtree_ops __read_mostly = {
- .privsize = nft_rbtree_privsize,
- .init = nft_rbtree_init,
- .destroy = nft_rbtree_destroy,
- .insert = nft_rbtree_insert,
- .remove = nft_rbtree_remove,
- .get = nft_rbtree_get,
- .lookup = nft_rbtree_lookup,
- .walk = nft_rbtree_walk,
- .features = NFT_SET_INTERVAL | NFT_SET_MAP,
- .owner = THIS_MODULE,
-};
-
-static int __init nft_rbtree_module_init(void)
-{
- return nft_register_set(&nft_rbtree_ops);
-}
-
-static void __exit nft_rbtree_module_exit(void)
-{
- nft_unregister_set(&nft_rbtree_ops);
-}
-
-module_init(nft_rbtree_module_init);
-module_exit(nft_rbtree_module_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
-MODULE_ALIAS_NFT_SET();
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 227aa11..8b03028 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -845,13 +845,8 @@ xt_replace_table(struct xt_table *table,
return NULL;
}
- newinfo->initial_entries = private->initial_entries;
- /*
- * Ensure contents of newinfo are visible before assigning to
- * private.
- */
- smp_wmb();
table->private = newinfo;
+ newinfo->initial_entries = private->initial_entries;
/*
* Even though table entries have now been swapped, other CPU's
diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c
index ed00fef..1e2fae3 100644
--- a/net/netfilter/xt_NFQUEUE.c
+++ b/net/netfilter/xt_NFQUEUE.c
@@ -147,7 +147,6 @@ nfqueue_tg_v3(struct sk_buff *skb, const struct xt_action_param *par)
{
const struct xt_NFQ_info_v3 *info = par->targinfo;
u32 queue = info->queuenum;
- int ret;
if (info->queues_total > 1) {
if (info->flags & NFQ_FLAG_CPU_FANOUT) {
@@ -158,11 +157,7 @@ nfqueue_tg_v3(struct sk_buff *skb, const struct xt_action_param *par)
queue = nfqueue_hash(skb, par);
}
- ret = NF_QUEUE_NR(queue);
- if (info->flags & NFQ_FLAG_BYPASS)
- ret |= NF_VERDICT_FLAG_QUEUE_BYPASS;
-
- return ret;
+ return NF_QUEUE_NR(queue);
}
static struct xt_target nfqueue_tg_reg[] __read_mostly = {
diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c
index e762de5..cd24290 100644
--- a/net/netfilter/xt_TCPMSS.c
+++ b/net/netfilter/xt_TCPMSS.c
@@ -43,42 +43,10 @@ optlen(const u_int8_t *opt, unsigned int offset)
return opt[offset+1];
}
-static u_int32_t tcpmss_reverse_mtu(struct net *net,
- const struct sk_buff *skb,
- unsigned int family)
-{
- struct flowi fl;
- const struct nf_afinfo *ai;
- struct rtable *rt = NULL;
- u_int32_t mtu = ~0U;
-
- if (family == PF_INET) {
- struct flowi4 *fl4 = &fl.u.ip4;
- memset(fl4, 0, sizeof(*fl4));
- fl4->daddr = ip_hdr(skb)->saddr;
- } else {
- struct flowi6 *fl6 = &fl.u.ip6;
-
- memset(fl6, 0, sizeof(*fl6));
- fl6->daddr = ipv6_hdr(skb)->saddr;
- }
- rcu_read_lock();
- ai = nf_get_afinfo(family);
- if (ai != NULL)
- ai->route(net, (struct dst_entry **)&rt, &fl, false);
- rcu_read_unlock();
-
- if (rt != NULL) {
- mtu = dst_mtu(&rt->dst);
- dst_release(&rt->dst);
- }
- return mtu;
-}
-
static int
tcpmss_mangle_packet(struct sk_buff *skb,
const struct xt_action_param *par,
- unsigned int family,
+ unsigned int in_mtu,
unsigned int tcphoff,
unsigned int minlen)
{
@@ -108,9 +76,6 @@ tcpmss_mangle_packet(struct sk_buff *skb,
return -1;
if (info->mss == XT_TCPMSS_CLAMP_PMTU) {
- struct net *net = dev_net(par->in ? par->in : par->out);
- unsigned int in_mtu = tcpmss_reverse_mtu(net, skb, family);
-
if (dst_mtu(skb_dst(skb)) <= minlen) {
net_err_ratelimited("unknown or invalid path-MTU (%u)\n",
dst_mtu(skb_dst(skb)));
@@ -200,6 +165,37 @@ tcpmss_mangle_packet(struct sk_buff *skb,
return TCPOLEN_MSS;
}
+static u_int32_t tcpmss_reverse_mtu(const struct sk_buff *skb,
+ unsigned int family)
+{
+ struct flowi fl;
+ const struct nf_afinfo *ai;
+ struct rtable *rt = NULL;
+ u_int32_t mtu = ~0U;
+
+ if (family == PF_INET) {
+ struct flowi4 *fl4 = &fl.u.ip4;
+ memset(fl4, 0, sizeof(*fl4));
+ fl4->daddr = ip_hdr(skb)->saddr;
+ } else {
+ struct flowi6 *fl6 = &fl.u.ip6;
+
+ memset(fl6, 0, sizeof(*fl6));
+ fl6->daddr = ipv6_hdr(skb)->saddr;
+ }
+ rcu_read_lock();
+ ai = nf_get_afinfo(family);
+ if (ai != NULL)
+ ai->route(&init_net, (struct dst_entry **)&rt, &fl, false);
+ rcu_read_unlock();
+
+ if (rt != NULL) {
+ mtu = dst_mtu(&rt->dst);
+ dst_release(&rt->dst);
+ }
+ return mtu;
+}
+
static unsigned int
tcpmss_tg4(struct sk_buff *skb, const struct xt_action_param *par)
{
@@ -208,7 +204,7 @@ tcpmss_tg4(struct sk_buff *skb, const struct xt_action_param *par)
int ret;
ret = tcpmss_mangle_packet(skb, par,
- PF_INET,
+ tcpmss_reverse_mtu(skb, PF_INET),
iph->ihl * 4,
sizeof(*iph) + sizeof(struct tcphdr));
if (ret < 0)
@@ -237,7 +233,7 @@ tcpmss_tg6(struct sk_buff *skb, const struct xt_action_param *par)
if (tcphoff < 0)
return NF_DROP;
ret = tcpmss_mangle_packet(skb, par,
- PF_INET6,
+ tcpmss_reverse_mtu(skb, PF_INET6),
tcphoff,
sizeof(*ipv6h) + sizeof(struct tcphdr));
if (ret < 0)
diff --git a/net/netfilter/xt_TPROXY.c b/net/netfilter/xt_TPROXY.c
index ef8a926..5d8a3a3 100644
--- a/net/netfilter/xt_TPROXY.c
+++ b/net/netfilter/xt_TPROXY.c
@@ -200,7 +200,7 @@ nf_tproxy_get_sock_v6(struct net *net, const u8 protocol,
in->ifindex);
if (sk) {
int connected = (sk->sk_state == TCP_ESTABLISHED);
- int wildcard = ipv6_addr_any(&sk->sk_v6_rcv_saddr);
+ int wildcard = ipv6_addr_any(&inet6_sk(sk)->rcv_saddr);
/* NOTE: we return listeners even if bound to
* 0.0.0.0, those are filtered out in
diff --git a/net/netfilter/xt_connbytes.c b/net/netfilter/xt_connbytes.c
index 1e63461..e595e07 100644
--- a/net/netfilter/xt_connbytes.c
+++ b/net/netfilter/xt_connbytes.c
@@ -26,18 +26,16 @@ connbytes_mt(const struct sk_buff *skb, struct xt_action_param *par)
u_int64_t what = 0; /* initialize to make gcc happy */
u_int64_t bytes = 0;
u_int64_t pkts = 0;
- const struct nf_conn_acct *acct;
const struct nf_conn_counter *counters;
ct = nf_ct_get(skb, &ctinfo);
if (!ct)
return false;
- acct = nf_conn_acct_find(ct);
- if (!acct)
+ counters = nf_conn_acct_find(ct);
+ if (!counters)
return false;
- counters = acct->counter;
switch (sinfo->what) {
case XT_CONNBYTES_PKTS:
switch (sinfo->direction) {
diff --git a/net/netfilter/xt_set.c b/net/netfilter/xt_set.c
index 80c2e2d..31790e7 100644
--- a/net/netfilter/xt_set.c
+++ b/net/netfilter/xt_set.c
@@ -81,17 +81,17 @@ set_match_v0_checkentry(const struct xt_mtchk_param *par)
struct xt_set_info_match_v0 *info = par->matchinfo;
ip_set_id_t index;
- index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
+ index = ip_set_nfnl_get_byindex(info->match_set.index);
if (index == IPSET_INVALID_ID) {
- pr_warning("Cannot find set identified by id %u to match\n",
+ pr_warning("Cannot find set indentified by id %u to match\n",
info->match_set.index);
return -ENOENT;
}
if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) {
pr_warning("Protocol error: set match dimension "
"is over the limit!\n");
- ip_set_nfnl_put(par->net, info->match_set.index);
+ ip_set_nfnl_put(info->match_set.index);
return -ERANGE;
}
@@ -106,104 +106,9 @@ set_match_v0_destroy(const struct xt_mtdtor_param *par)
{
struct xt_set_info_match_v0 *info = par->matchinfo;
- ip_set_nfnl_put(par->net, info->match_set.index);
+ ip_set_nfnl_put(info->match_set.index);
}
-/* Revision 1 match */
-
-static bool
-set_match_v1(const struct sk_buff *skb, struct xt_action_param *par)
-{
- const struct xt_set_info_match_v1 *info = par->matchinfo;
- ADT_OPT(opt, par->family, info->match_set.dim,
- info->match_set.flags, 0, UINT_MAX);
-
- if (opt.flags & IPSET_RETURN_NOMATCH)
- opt.cmdflags |= IPSET_FLAG_RETURN_NOMATCH;
-
- return match_set(info->match_set.index, skb, par, &opt,
- info->match_set.flags & IPSET_INV_MATCH);
-}
-
-static int
-set_match_v1_checkentry(const struct xt_mtchk_param *par)
-{
- struct xt_set_info_match_v1 *info = par->matchinfo;
- ip_set_id_t index;
-
- index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
-
- if (index == IPSET_INVALID_ID) {
- pr_warning("Cannot find set identified by id %u to match\n",
- info->match_set.index);
- return -ENOENT;
- }
- if (info->match_set.dim > IPSET_DIM_MAX) {
- pr_warning("Protocol error: set match dimension "
- "is over the limit!\n");
- ip_set_nfnl_put(par->net, info->match_set.index);
- return -ERANGE;
- }
-
- return 0;
-}
-
-static void
-set_match_v1_destroy(const struct xt_mtdtor_param *par)
-{
- struct xt_set_info_match_v1 *info = par->matchinfo;
-
- ip_set_nfnl_put(par->net, info->match_set.index);
-}
-
-/* Revision 3 match */
-
-static bool
-match_counter(u64 counter, const struct ip_set_counter_match *info)
-{
- switch (info->op) {
- case IPSET_COUNTER_NONE:
- return true;
- case IPSET_COUNTER_EQ:
- return counter == info->value;
- case IPSET_COUNTER_NE:
- return counter != info->value;
- case IPSET_COUNTER_LT:
- return counter < info->value;
- case IPSET_COUNTER_GT:
- return counter > info->value;
- }
- return false;
-}
-
-static bool
-set_match_v3(const struct sk_buff *skb, struct xt_action_param *par)
-{
- const struct xt_set_info_match_v3 *info = par->matchinfo;
- ADT_OPT(opt, par->family, info->match_set.dim,
- info->match_set.flags, info->flags, UINT_MAX);
- int ret;
-
- if (info->packets.op != IPSET_COUNTER_NONE ||
- info->bytes.op != IPSET_COUNTER_NONE)
- opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS;
-
- ret = match_set(info->match_set.index, skb, par, &opt,
- info->match_set.flags & IPSET_INV_MATCH);
-
- if (!(ret && opt.cmdflags & IPSET_FLAG_MATCH_COUNTERS))
- return ret;
-
- if (!match_counter(opt.ext.packets, &info->packets))
- return 0;
- return match_counter(opt.ext.bytes, &info->bytes);
-}
-
-#define set_match_v3_checkentry set_match_v1_checkentry
-#define set_match_v3_destroy set_match_v1_destroy
-
-/* Revision 0 interface: backward compatible with netfilter/iptables */
-
static unsigned int
set_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
{
@@ -228,7 +133,7 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
ip_set_id_t index;
if (info->add_set.index != IPSET_INVALID_ID) {
- index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
+ index = ip_set_nfnl_get_byindex(info->add_set.index);
if (index == IPSET_INVALID_ID) {
pr_warning("Cannot find add_set index %u as target\n",
info->add_set.index);
@@ -237,12 +142,12 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
}
if (info->del_set.index != IPSET_INVALID_ID) {
- index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
+ index = ip_set_nfnl_get_byindex(info->del_set.index);
if (index == IPSET_INVALID_ID) {
pr_warning("Cannot find del_set index %u as target\n",
info->del_set.index);
if (info->add_set.index != IPSET_INVALID_ID)
- ip_set_nfnl_put(par->net, info->add_set.index);
+ ip_set_nfnl_put(info->add_set.index);
return -ENOENT;
}
}
@@ -251,9 +156,9 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
pr_warning("Protocol error: SET target dimension "
"is over the limit!\n");
if (info->add_set.index != IPSET_INVALID_ID)
- ip_set_nfnl_put(par->net, info->add_set.index);
+ ip_set_nfnl_put(info->add_set.index);
if (info->del_set.index != IPSET_INVALID_ID)
- ip_set_nfnl_put(par->net, info->del_set.index);
+ ip_set_nfnl_put(info->del_set.index);
return -ERANGE;
}
@@ -270,12 +175,57 @@ set_target_v0_destroy(const struct xt_tgdtor_param *par)
const struct xt_set_info_target_v0 *info = par->targinfo;
if (info->add_set.index != IPSET_INVALID_ID)
- ip_set_nfnl_put(par->net, info->add_set.index);
+ ip_set_nfnl_put(info->add_set.index);
if (info->del_set.index != IPSET_INVALID_ID)
- ip_set_nfnl_put(par->net, info->del_set.index);
+ ip_set_nfnl_put(info->del_set.index);
+}
+
+/* Revision 1 match and target */
+
+static bool
+set_match_v1(const struct sk_buff *skb, struct xt_action_param *par)
+{
+ const struct xt_set_info_match_v1 *info = par->matchinfo;
+ ADT_OPT(opt, par->family, info->match_set.dim,
+ info->match_set.flags, 0, UINT_MAX);
+
+ if (opt.flags & IPSET_RETURN_NOMATCH)
+ opt.cmdflags |= IPSET_FLAG_RETURN_NOMATCH;
+
+ return match_set(info->match_set.index, skb, par, &opt,
+ info->match_set.flags & IPSET_INV_MATCH);
+}
+
+static int
+set_match_v1_checkentry(const struct xt_mtchk_param *par)
+{
+ struct xt_set_info_match_v1 *info = par->matchinfo;
+ ip_set_id_t index;
+
+ index = ip_set_nfnl_get_byindex(info->match_set.index);
+
+ if (index == IPSET_INVALID_ID) {
+ pr_warning("Cannot find set indentified by id %u to match\n",
+ info->match_set.index);
+ return -ENOENT;
+ }
+ if (info->match_set.dim > IPSET_DIM_MAX) {
+ pr_warning("Protocol error: set match dimension "
+ "is over the limit!\n");
+ ip_set_nfnl_put(info->match_set.index);
+ return -ERANGE;
+ }
+
+ return 0;
}
-/* Revision 1 target */
+static void
+set_match_v1_destroy(const struct xt_mtdtor_param *par)
+{
+ struct xt_set_info_match_v1 *info = par->matchinfo;
+
+ ip_set_nfnl_put(info->match_set.index);
+}
static unsigned int
set_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
@@ -301,7 +251,7 @@ set_target_v1_checkentry(const struct xt_tgchk_param *par)
ip_set_id_t index;
if (info->add_set.index != IPSET_INVALID_ID) {
- index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
+ index = ip_set_nfnl_get_byindex(info->add_set.index);
if (index == IPSET_INVALID_ID) {
pr_warning("Cannot find add_set index %u as target\n",
info->add_set.index);
@@ -310,12 +260,12 @@ set_target_v1_checkentry(const struct xt_tgchk_param *par)
}
if (info->del_set.index != IPSET_INVALID_ID) {
- index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
+ index = ip_set_nfnl_get_byindex(info->del_set.index);
if (index == IPSET_INVALID_ID) {
pr_warning("Cannot find del_set index %u as target\n",
info->del_set.index);
if (info->add_set.index != IPSET_INVALID_ID)
- ip_set_nfnl_put(par->net, info->add_set.index);
+ ip_set_nfnl_put(info->add_set.index);
return -ENOENT;
}
}
@@ -324,9 +274,9 @@ set_target_v1_checkentry(const struct xt_tgchk_param *par)
pr_warning("Protocol error: SET target dimension "
"is over the limit!\n");
if (info->add_set.index != IPSET_INVALID_ID)
- ip_set_nfnl_put(par->net, info->add_set.index);
+ ip_set_nfnl_put(info->add_set.index);
if (info->del_set.index != IPSET_INVALID_ID)
- ip_set_nfnl_put(par->net, info->del_set.index);
+ ip_set_nfnl_put(info->del_set.index);
return -ERANGE;
}
@@ -339,9 +289,9 @@ set_target_v1_destroy(const struct xt_tgdtor_param *par)
const struct xt_set_info_target_v1 *info = par->targinfo;
if (info->add_set.index != IPSET_INVALID_ID)
- ip_set_nfnl_put(par->net, info->add_set.index);
+ ip_set_nfnl_put(info->add_set.index);
if (info->del_set.index != IPSET_INVALID_ID)
- ip_set_nfnl_put(par->net, info->del_set.index);
+ ip_set_nfnl_put(info->del_set.index);
}
/* Revision 2 target */
@@ -370,6 +320,52 @@ set_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
#define set_target_v2_checkentry set_target_v1_checkentry
#define set_target_v2_destroy set_target_v1_destroy
+/* Revision 3 match */
+
+static bool
+match_counter(u64 counter, const struct ip_set_counter_match *info)
+{
+ switch (info->op) {
+ case IPSET_COUNTER_NONE:
+ return true;
+ case IPSET_COUNTER_EQ:
+ return counter == info->value;
+ case IPSET_COUNTER_NE:
+ return counter != info->value;
+ case IPSET_COUNTER_LT:
+ return counter < info->value;
+ case IPSET_COUNTER_GT:
+ return counter > info->value;
+ }
+ return false;
+}
+
+static bool
+set_match_v3(const struct sk_buff *skb, struct xt_action_param *par)
+{
+ const struct xt_set_info_match_v3 *info = par->matchinfo;
+ ADT_OPT(opt, par->family, info->match_set.dim,
+ info->match_set.flags, info->flags, UINT_MAX);
+ int ret;
+
+ if (info->packets.op != IPSET_COUNTER_NONE ||
+ info->bytes.op != IPSET_COUNTER_NONE)
+ opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS;
+
+ ret = match_set(info->match_set.index, skb, par, &opt,
+ info->match_set.flags & IPSET_INV_MATCH);
+
+ if (!(ret && opt.cmdflags & IPSET_FLAG_MATCH_COUNTERS))
+ return ret;
+
+ if (!match_counter(opt.ext.packets, &info->packets))
+ return 0;
+ return match_counter(opt.ext.bytes, &info->bytes);
+}
+
+#define set_match_v3_checkentry set_match_v1_checkentry
+#define set_match_v3_destroy set_match_v1_destroy
+
static struct xt_match set_matches[] __read_mostly = {
{
.name = "set",
diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c
index 1ba6793..06df2b9 100644
--- a/net/netfilter/xt_socket.c
+++ b/net/netfilter/xt_socket.c
@@ -35,6 +35,15 @@
#include <net/netfilter/nf_conntrack.h>
#endif
+static void
+xt_socket_put_sk(struct sock *sk)
+{
+ if (sk->sk_state == TCP_TIME_WAIT)
+ inet_twsk_put(inet_twsk(sk));
+ else
+ sock_put(sk);
+}
+
static int
extract_icmp4_fields(const struct sk_buff *skb,
u8 *protocol,
@@ -207,7 +216,7 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
inet_twsk(sk)->tw_transparent));
if (sk != skb->sk)
- sock_gen_put(sk);
+ xt_socket_put_sk(sk);
if (wildcard || !transparent)
sk = NULL;
@@ -361,7 +370,7 @@ socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par)
*/
wildcard = (!(info->flags & XT_SOCKET_NOWILDCARD) &&
sk->sk_state != TCP_TIME_WAIT &&
- ipv6_addr_any(&sk->sk_v6_rcv_saddr));
+ ipv6_addr_any(&inet6_sk(sk)->rcv_saddr));
/* Ignore non-transparent sockets,
if XT_SOCKET_TRANSPARENT is used */
@@ -372,7 +381,7 @@ socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par)
inet_twsk(sk)->tw_transparent));
if (sk != skb->sk)
- sock_gen_put(sk);
+ xt_socket_put_sk(sk);
if (wildcard || !transparent)
sk = NULL;