diff options
| author | David S. Miller <davem@davemloft.net> | 2013-10-04 13:26:38 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2013-10-04 13:26:38 -0400 |
| commit | d639feaaf3f40cd90b75a2fec5b7d5c3f96c2c88 (patch) | |
| tree | 1517467ea9853f0bd61923dd619c1c937b80673c | |
| parent | 96f817fedec48b59c9e8b22141cec4e56ad47913 (diff) | |
| parent | 91cb498e6a34b429a032f8cfbb57dde28cd20e0c (diff) | |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next
Pablo Neira Ayuso says:
====================
The following patchset contains Netfilter updates for your net-next tree,
mostly ipset improvements and enhancements features, they are:
* Don't call ip_nest_end needlessly in the error path from me, suggested
by Pablo Neira Ayuso, from Jozsef Kadlecsik.
* Fixed sparse warnings about shadowed variable and missing rcu annotation
and fix of "may be used uninitialized" warnings, also from Jozsef.
* Renamed simple macro names to avoid namespace issues, reported by David
Laight, again from Jozsef.
* Use fix sized type for timeout in the extension part, and cosmetic
ordering of matches and targets separatedly in xt_set.c, from Jozsef.
* Support package fragments for IPv4 protos without ports from Anders K.
Pedersen. For example this allows a hash:ip,port ipset containing the
entry 192.168.0.1,gre:0 to match all package fragments for PPTP VPN
tunnels to/from the host. Without this patch only the first package
fragment (with fragment offset 0) was matched.
* Introduced a new operation to get both setname and family, from Jozsef.
ip[6]tables set match and SET target need to know the family of the set
in order to reject adding rules which refer to a set with a non-mathcing
family. Currently such rules are silently accepted and then ignored
instead of generating an error message to the user.
* Reworked extensions support in ipset types from Jozsef. The approach of
defining structures with all variations is not manageable as the
number of extensions grows. Therefore a blob for the extensions is
introduced, somewhat similar to conntrack. The support of extensions
which need a per data destroy function is added as well.
* When an element timed out in a list:set type of set, the garbage
collector skipped the checking of the next element. So the purging
was delayed to the next run of the gc, fixed by Jozsef.
* A small Kconfig fix: NETFILTER_NETLINK cannot be selected and
ipset requires it.
* hash:net,net type from Oliver Smith. The type provides the ability to
store pairs of subnets in a set.
* Comment for ipset entries from Oliver Smith. This makes possible to
annotate entries in a set with comments, for example:
ipset n foo hash:net,net comment
ipset a foo 10.0.0.0/21,192.168.1.0/24 comment "office nets A and B"
* Fix of hash types resizing with comment extension from Jozsef.
* Fix of new extensions for list:set type when an element is added
into a slot from where another element was pushed away from Jozsef.
* Introduction of a common function for the listing of the element
extensions from Jozsef.
* Net namespace support for ipset from Vitaly Lavrov.
* hash:net,port,net type from Oliver Smith, which makes possible
to store the triples of two subnets and a protocol, port pair in
a set.
* Get xt_TCPMSS working with net namespace, by Gao feng.
* Use the proper net netnamespace to allocate skbs, also by Gao feng.
* A couple of cleanups for the conntrack SIP helper, by Holger
Eitzenberger.
* Extend cttimeout to allow setting default conntrack timeouts via
nfnetlink, so we can get rid of all our sysctl/proc interfaces in
the future for timeout tuning, from me.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
33 files changed, 2677 insertions, 1731 deletions
diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h index 9ac9fbde7b61..7967516adc0d 100644 --- a/include/linux/netfilter/ipset/ip_set.h +++ b/include/linux/netfilter/ipset/ip_set.h | |||
| @@ -49,31 +49,68 @@ enum ip_set_feature { | |||
| 49 | 49 | ||
| 50 | /* Set extensions */ | 50 | /* Set extensions */ |
| 51 | enum ip_set_extension { | 51 | enum ip_set_extension { |
| 52 | IPSET_EXT_NONE = 0, | 52 | IPSET_EXT_BIT_TIMEOUT = 0, |
| 53 | IPSET_EXT_BIT_TIMEOUT = 1, | ||
| 54 | IPSET_EXT_TIMEOUT = (1 << IPSET_EXT_BIT_TIMEOUT), | 53 | IPSET_EXT_TIMEOUT = (1 << IPSET_EXT_BIT_TIMEOUT), |
| 55 | IPSET_EXT_BIT_COUNTER = 2, | 54 | IPSET_EXT_BIT_COUNTER = 1, |
| 56 | IPSET_EXT_COUNTER = (1 << IPSET_EXT_BIT_COUNTER), | 55 | IPSET_EXT_COUNTER = (1 << IPSET_EXT_BIT_COUNTER), |
| 57 | }; | 56 | IPSET_EXT_BIT_COMMENT = 2, |
| 58 | 57 | IPSET_EXT_COMMENT = (1 << IPSET_EXT_BIT_COMMENT), | |
| 59 | /* Extension offsets */ | 58 | /* Mark set with an extension which needs to call destroy */ |
| 60 | enum ip_set_offset { | 59 | IPSET_EXT_BIT_DESTROY = 7, |
| 61 | IPSET_OFFSET_TIMEOUT = 0, | 60 | IPSET_EXT_DESTROY = (1 << IPSET_EXT_BIT_DESTROY), |
| 62 | IPSET_OFFSET_COUNTER, | ||
| 63 | IPSET_OFFSET_MAX, | ||
| 64 | }; | 61 | }; |
| 65 | 62 | ||
| 66 | #define SET_WITH_TIMEOUT(s) ((s)->extensions & IPSET_EXT_TIMEOUT) | 63 | #define SET_WITH_TIMEOUT(s) ((s)->extensions & IPSET_EXT_TIMEOUT) |
| 67 | #define SET_WITH_COUNTER(s) ((s)->extensions & IPSET_EXT_COUNTER) | 64 | #define SET_WITH_COUNTER(s) ((s)->extensions & IPSET_EXT_COUNTER) |
| 65 | #define SET_WITH_COMMENT(s) ((s)->extensions & IPSET_EXT_COMMENT) | ||
| 66 | |||
| 67 | /* Extension id, in size order */ | ||
| 68 | enum ip_set_ext_id { | ||
| 69 | IPSET_EXT_ID_COUNTER = 0, | ||
| 70 | IPSET_EXT_ID_TIMEOUT, | ||
| 71 | IPSET_EXT_ID_COMMENT, | ||
| 72 | IPSET_EXT_ID_MAX, | ||
| 73 | }; | ||
| 74 | |||
| 75 | /* Extension type */ | ||
| 76 | struct ip_set_ext_type { | ||
| 77 | /* Destroy extension private data (can be NULL) */ | ||
| 78 | void (*destroy)(void *ext); | ||
| 79 | enum ip_set_extension type; | ||
| 80 | enum ipset_cadt_flags flag; | ||
| 81 | /* Size and minimal alignment */ | ||
| 82 | u8 len; | ||
| 83 | u8 align; | ||
| 84 | }; | ||
| 85 | |||
| 86 | extern const struct ip_set_ext_type ip_set_extensions[]; | ||
| 68 | 87 | ||
| 69 | struct ip_set_ext { | 88 | struct ip_set_ext { |
| 70 | unsigned long timeout; | ||
| 71 | u64 packets; | 89 | u64 packets; |
| 72 | u64 bytes; | 90 | u64 bytes; |
| 91 | u32 timeout; | ||
| 92 | char *comment; | ||
| 93 | }; | ||
| 94 | |||
| 95 | struct ip_set_counter { | ||
| 96 | atomic64_t bytes; | ||
| 97 | atomic64_t packets; | ||
| 98 | }; | ||
| 99 | |||
| 100 | struct ip_set_comment { | ||
| 101 | char *str; | ||
| 73 | }; | 102 | }; |
| 74 | 103 | ||
| 75 | struct ip_set; | 104 | struct ip_set; |
| 76 | 105 | ||
| 106 | #define ext_timeout(e, s) \ | ||
| 107 | (unsigned long *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_TIMEOUT]) | ||
| 108 | #define ext_counter(e, s) \ | ||
| 109 | (struct ip_set_counter *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_COUNTER]) | ||
| 110 | #define ext_comment(e, s) \ | ||
| 111 | (struct ip_set_comment *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_COMMENT]) | ||
| 112 | |||
| 113 | |||
| 77 | typedef int (*ipset_adtfn)(struct ip_set *set, void *value, | 114 | typedef int (*ipset_adtfn)(struct ip_set *set, void *value, |
| 78 | const struct ip_set_ext *ext, | 115 | const struct ip_set_ext *ext, |
| 79 | struct ip_set_ext *mext, u32 cmdflags); | 116 | struct ip_set_ext *mext, u32 cmdflags); |
| @@ -147,7 +184,8 @@ struct ip_set_type { | |||
| 147 | u8 revision_min, revision_max; | 184 | u8 revision_min, revision_max; |
| 148 | 185 | ||
| 149 | /* Create set */ | 186 | /* Create set */ |
| 150 | int (*create)(struct ip_set *set, struct nlattr *tb[], u32 flags); | 187 | int (*create)(struct net *net, struct ip_set *set, |
| 188 | struct nlattr *tb[], u32 flags); | ||
| 151 | 189 | ||
| 152 | /* Attribute policies */ | 190 | /* Attribute policies */ |
| 153 | const struct nla_policy create_policy[IPSET_ATTR_CREATE_MAX + 1]; | 191 | const struct nla_policy create_policy[IPSET_ATTR_CREATE_MAX + 1]; |
| @@ -179,14 +217,45 @@ struct ip_set { | |||
| 179 | u8 revision; | 217 | u8 revision; |
| 180 | /* Extensions */ | 218 | /* Extensions */ |
| 181 | u8 extensions; | 219 | u8 extensions; |
| 220 | /* Default timeout value, if enabled */ | ||
| 221 | u32 timeout; | ||
| 222 | /* Element data size */ | ||
| 223 | size_t dsize; | ||
| 224 | /* Offsets to extensions in elements */ | ||
| 225 | size_t offset[IPSET_EXT_ID_MAX]; | ||
| 182 | /* The type specific data */ | 226 | /* The type specific data */ |
| 183 | void *data; | 227 | void *data; |
| 184 | }; | 228 | }; |
| 185 | 229 | ||
| 186 | struct ip_set_counter { | 230 | static inline void |
| 187 | atomic64_t bytes; | 231 | ip_set_ext_destroy(struct ip_set *set, void *data) |
| 188 | atomic64_t packets; | 232 | { |
| 189 | }; | 233 | /* Check that the extension is enabled for the set and |
| 234 | * call it's destroy function for its extension part in data. | ||
| 235 | */ | ||
| 236 | if (SET_WITH_COMMENT(set)) | ||
| 237 | ip_set_extensions[IPSET_EXT_ID_COMMENT].destroy( | ||
| 238 | ext_comment(data, set)); | ||
| 239 | } | ||
| 240 | |||
| 241 | static inline int | ||
| 242 | ip_set_put_flags(struct sk_buff *skb, struct ip_set *set) | ||
| 243 | { | ||
| 244 | u32 cadt_flags = 0; | ||
| 245 | |||
| 246 | if (SET_WITH_TIMEOUT(set)) | ||
| 247 | if (unlikely(nla_put_net32(skb, IPSET_ATTR_TIMEOUT, | ||
| 248 | htonl(set->timeout)))) | ||
| 249 | return -EMSGSIZE; | ||
| 250 | if (SET_WITH_COUNTER(set)) | ||
| 251 | cadt_flags |= IPSET_FLAG_WITH_COUNTERS; | ||
| 252 | if (SET_WITH_COMMENT(set)) | ||
| 253 | cadt_flags |= IPSET_FLAG_WITH_COMMENT; | ||
| 254 | |||
| 255 | if (!cadt_flags) | ||
| 256 | return 0; | ||
| 257 | return nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(cadt_flags)); | ||
| 258 | } | ||
| 190 | 259 | ||
| 191 | static inline void | 260 | static inline void |
| 192 | ip_set_add_bytes(u64 bytes, struct ip_set_counter *counter) | 261 | ip_set_add_bytes(u64 bytes, struct ip_set_counter *counter) |
| @@ -248,12 +317,13 @@ ip_set_init_counter(struct ip_set_counter *counter, | |||
| 248 | } | 317 | } |
| 249 | 318 | ||
| 250 | /* register and unregister set references */ | 319 | /* register and unregister set references */ |
| 251 | extern ip_set_id_t ip_set_get_byname(const char *name, struct ip_set **set); | 320 | extern ip_set_id_t ip_set_get_byname(struct net *net, |
| 252 | extern void ip_set_put_byindex(ip_set_id_t index); | 321 | const char *name, struct ip_set **set); |
| 253 | extern const char *ip_set_name_byindex(ip_set_id_t index); | 322 | extern void ip_set_put_byindex(struct net *net, ip_set_id_t index); |
| 254 | extern ip_set_id_t ip_set_nfnl_get(const char *name); | 323 | extern const char *ip_set_name_byindex(struct net *net, ip_set_id_t index); |
| 255 | extern ip_set_id_t ip_set_nfnl_get_byindex(ip_set_id_t index); | 324 | extern ip_set_id_t ip_set_nfnl_get(struct net *net, const char *name); |
| 256 | extern void ip_set_nfnl_put(ip_set_id_t index); | 325 | extern ip_set_id_t ip_set_nfnl_get_byindex(struct net *net, ip_set_id_t index); |
| 326 | extern void ip_set_nfnl_put(struct net *net, ip_set_id_t index); | ||
| 257 | 327 | ||
| 258 | /* API for iptables set match, and SET target */ | 328 | /* API for iptables set match, and SET target */ |
| 259 | 329 | ||
| @@ -272,6 +342,8 @@ extern void *ip_set_alloc(size_t size); | |||
| 272 | extern void ip_set_free(void *members); | 342 | extern void ip_set_free(void *members); |
| 273 | extern int ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr); | 343 | extern int ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr); |
| 274 | extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr); | 344 | extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr); |
| 345 | extern size_t ip_set_elem_len(struct ip_set *set, struct nlattr *tb[], | ||
| 346 | size_t len); | ||
| 275 | extern int ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[], | 347 | extern int ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[], |
| 276 | struct ip_set_ext *ext); | 348 | struct ip_set_ext *ext); |
| 277 | 349 | ||
| @@ -389,13 +461,40 @@ bitmap_bytes(u32 a, u32 b) | |||
| 389 | } | 461 | } |
| 390 | 462 | ||
| 391 | #include <linux/netfilter/ipset/ip_set_timeout.h> | 463 | #include <linux/netfilter/ipset/ip_set_timeout.h> |
| 464 | #include <linux/netfilter/ipset/ip_set_comment.h> | ||
| 392 | 465 | ||
| 393 | #define IP_SET_INIT_KEXT(skb, opt, map) \ | 466 | static inline int |
| 467 | ip_set_put_extensions(struct sk_buff *skb, const struct ip_set *set, | ||
| 468 | const void *e, bool active) | ||
| 469 | { | ||
| 470 | if (SET_WITH_TIMEOUT(set)) { | ||
| 471 | unsigned long *timeout = ext_timeout(e, set); | ||
| 472 | |||
| 473 | if (nla_put_net32(skb, IPSET_ATTR_TIMEOUT, | ||
| 474 | htonl(active ? ip_set_timeout_get(timeout) | ||
| 475 | : *timeout))) | ||
| 476 | return -EMSGSIZE; | ||
| 477 | } | ||
| 478 | if (SET_WITH_COUNTER(set) && | ||
| 479 | ip_set_put_counter(skb, ext_counter(e, set))) | ||
| 480 | return -EMSGSIZE; | ||
| 481 | if (SET_WITH_COMMENT(set) && | ||
| 482 | ip_set_put_comment(skb, ext_comment(e, set))) | ||
| 483 | return -EMSGSIZE; | ||
| 484 | return 0; | ||
| 485 | } | ||
| 486 | |||
| 487 | #define IP_SET_INIT_KEXT(skb, opt, set) \ | ||
| 394 | { .bytes = (skb)->len, .packets = 1, \ | 488 | { .bytes = (skb)->len, .packets = 1, \ |
| 395 | .timeout = ip_set_adt_opt_timeout(opt, map) } | 489 | .timeout = ip_set_adt_opt_timeout(opt, set) } |
| 396 | 490 | ||
| 397 | #define IP_SET_INIT_UEXT(map) \ | 491 | #define IP_SET_INIT_UEXT(set) \ |
| 398 | { .bytes = ULLONG_MAX, .packets = ULLONG_MAX, \ | 492 | { .bytes = ULLONG_MAX, .packets = ULLONG_MAX, \ |
| 399 | .timeout = (map)->timeout } | 493 | .timeout = (set)->timeout } |
| 494 | |||
| 495 | #define IP_SET_INIT_CIDR(a, b) ((a) ? (a) : (b)) | ||
| 496 | |||
| 497 | #define IPSET_CONCAT(a, b) a##b | ||
| 498 | #define IPSET_TOKEN(a, b) IPSET_CONCAT(a, b) | ||
| 400 | 499 | ||
| 401 | #endif /*_IP_SET_H */ | 500 | #endif /*_IP_SET_H */ |
diff --git a/include/linux/netfilter/ipset/ip_set_comment.h b/include/linux/netfilter/ipset/ip_set_comment.h new file mode 100644 index 000000000000..21217ea008d7 --- /dev/null +++ b/include/linux/netfilter/ipset/ip_set_comment.h | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | #ifndef _IP_SET_COMMENT_H | ||
| 2 | #define _IP_SET_COMMENT_H | ||
| 3 | |||
| 4 | /* Copyright (C) 2013 Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifdef __KERNEL__ | ||
| 12 | |||
| 13 | static inline char* | ||
| 14 | ip_set_comment_uget(struct nlattr *tb) | ||
| 15 | { | ||
| 16 | return nla_data(tb); | ||
| 17 | } | ||
| 18 | |||
| 19 | static inline void | ||
| 20 | ip_set_init_comment(struct ip_set_comment *comment, | ||
| 21 | const struct ip_set_ext *ext) | ||
| 22 | { | ||
| 23 | size_t len = ext->comment ? strlen(ext->comment) : 0; | ||
| 24 | |||
| 25 | if (unlikely(comment->str)) { | ||
| 26 | kfree(comment->str); | ||
| 27 | comment->str = NULL; | ||
| 28 | } | ||
| 29 | if (!len) | ||
| 30 | return; | ||
| 31 | if (unlikely(len > IPSET_MAX_COMMENT_SIZE)) | ||
| 32 | len = IPSET_MAX_COMMENT_SIZE; | ||
| 33 | comment->str = kzalloc(len + 1, GFP_ATOMIC); | ||
| 34 | if (unlikely(!comment->str)) | ||
| 35 | return; | ||
| 36 | strlcpy(comment->str, ext->comment, len + 1); | ||
| 37 | } | ||
| 38 | |||
| 39 | static inline int | ||
| 40 | ip_set_put_comment(struct sk_buff *skb, struct ip_set_comment *comment) | ||
| 41 | { | ||
| 42 | if (!comment->str) | ||
| 43 | return 0; | ||
| 44 | return nla_put_string(skb, IPSET_ATTR_COMMENT, comment->str); | ||
| 45 | } | ||
| 46 | |||
| 47 | static inline void | ||
| 48 | ip_set_comment_free(struct ip_set_comment *comment) | ||
| 49 | { | ||
| 50 | if (unlikely(!comment->str)) | ||
| 51 | return; | ||
| 52 | kfree(comment->str); | ||
| 53 | comment->str = NULL; | ||
| 54 | } | ||
| 55 | |||
| 56 | #endif | ||
| 57 | #endif | ||
diff --git a/include/linux/netfilter/ipset/ip_set_timeout.h b/include/linux/netfilter/ipset/ip_set_timeout.h index 3aac04167ca7..83c2f9e0886c 100644 --- a/include/linux/netfilter/ipset/ip_set_timeout.h +++ b/include/linux/netfilter/ipset/ip_set_timeout.h | |||
| @@ -23,8 +23,8 @@ | |||
| 23 | /* Set is defined with timeout support: timeout value may be 0 */ | 23 | /* Set is defined with timeout support: timeout value may be 0 */ |
| 24 | #define IPSET_NO_TIMEOUT UINT_MAX | 24 | #define IPSET_NO_TIMEOUT UINT_MAX |
| 25 | 25 | ||
| 26 | #define ip_set_adt_opt_timeout(opt, map) \ | 26 | #define ip_set_adt_opt_timeout(opt, set) \ |
| 27 | ((opt)->ext.timeout != IPSET_NO_TIMEOUT ? (opt)->ext.timeout : (map)->timeout) | 27 | ((opt)->ext.timeout != IPSET_NO_TIMEOUT ? (opt)->ext.timeout : (set)->timeout) |
| 28 | 28 | ||
| 29 | static inline unsigned int | 29 | static inline unsigned int |
| 30 | ip_set_timeout_uget(struct nlattr *tb) | 30 | ip_set_timeout_uget(struct nlattr *tb) |
diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index 5cac0207b95d..d5af3c27fb7d 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h | |||
| @@ -107,55 +107,64 @@ enum sdp_header_types { | |||
| 107 | SDP_HDR_MEDIA, | 107 | SDP_HDR_MEDIA, |
| 108 | }; | 108 | }; |
| 109 | 109 | ||
| 110 | extern unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, | 110 | struct nf_nat_sip_hooks { |
| 111 | unsigned int protoff, | 111 | unsigned int (*msg)(struct sk_buff *skb, |
| 112 | unsigned int dataoff, | 112 | unsigned int protoff, |
| 113 | const char **dptr, | 113 | unsigned int dataoff, |
| 114 | unsigned int *datalen); | 114 | const char **dptr, |
| 115 | extern void (*nf_nat_sip_seq_adjust_hook)(struct sk_buff *skb, | 115 | unsigned int *datalen); |
| 116 | unsigned int protoff, s16 off); | 116 | |
| 117 | extern unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb, | 117 | void (*seq_adjust)(struct sk_buff *skb, |
| 118 | unsigned int protoff, | 118 | unsigned int protoff, s16 off); |
| 119 | unsigned int dataoff, | 119 | |
| 120 | const char **dptr, | 120 | unsigned int (*expect)(struct sk_buff *skb, |
| 121 | unsigned int *datalen, | 121 | unsigned int protoff, |
| 122 | struct nf_conntrack_expect *exp, | 122 | unsigned int dataoff, |
| 123 | unsigned int matchoff, | 123 | const char **dptr, |
| 124 | unsigned int matchlen); | 124 | unsigned int *datalen, |
| 125 | extern unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb, | 125 | struct nf_conntrack_expect *exp, |
| 126 | unsigned int protoff, | 126 | unsigned int matchoff, |
| 127 | unsigned int dataoff, | 127 | unsigned int matchlen); |
| 128 | const char **dptr, | 128 | |
| 129 | unsigned int *datalen, | 129 | unsigned int (*sdp_addr)(struct sk_buff *skb, |
| 130 | unsigned int sdpoff, | 130 | unsigned int protoff, |
| 131 | enum sdp_header_types type, | 131 | unsigned int dataoff, |
| 132 | enum sdp_header_types term, | 132 | const char **dptr, |
| 133 | const union nf_inet_addr *addr); | 133 | unsigned int *datalen, |
| 134 | extern unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb, | 134 | unsigned int sdpoff, |
| 135 | unsigned int protoff, | 135 | enum sdp_header_types type, |
| 136 | unsigned int dataoff, | 136 | enum sdp_header_types term, |
| 137 | const char **dptr, | 137 | const union nf_inet_addr *addr); |
| 138 | unsigned int *datalen, | 138 | |
| 139 | unsigned int matchoff, | 139 | unsigned int (*sdp_port)(struct sk_buff *skb, |
| 140 | unsigned int matchlen, | 140 | unsigned int protoff, |
| 141 | u_int16_t port); | 141 | unsigned int dataoff, |
| 142 | extern unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb, | 142 | const char **dptr, |
| 143 | unsigned int protoff, | 143 | unsigned int *datalen, |
| 144 | unsigned int dataoff, | 144 | unsigned int matchoff, |
| 145 | const char **dptr, | 145 | unsigned int matchlen, |
| 146 | unsigned int *datalen, | 146 | u_int16_t port); |
| 147 | unsigned int sdpoff, | 147 | |
| 148 | const union nf_inet_addr *addr); | 148 | unsigned int (*sdp_session)(struct sk_buff *skb, |
| 149 | extern unsigned int (*nf_nat_sdp_media_hook)(struct sk_buff *skb, | 149 | unsigned int protoff, |
| 150 | unsigned int protoff, | 150 | unsigned int dataoff, |
| 151 | unsigned int dataoff, | 151 | const char **dptr, |
| 152 | const char **dptr, | 152 | unsigned int *datalen, |
| 153 | unsigned int *datalen, | 153 | unsigned int sdpoff, |
| 154 | struct nf_conntrack_expect *rtp_exp, | 154 | const union nf_inet_addr *addr); |
| 155 | struct nf_conntrack_expect *rtcp_exp, | 155 | |
| 156 | unsigned int mediaoff, | 156 | unsigned int (*sdp_media)(struct sk_buff *skb, |
| 157 | unsigned int medialen, | 157 | unsigned int protoff, |
| 158 | union nf_inet_addr *rtp_addr); | 158 | unsigned int dataoff, |
| 159 | const char **dptr, | ||
| 160 | unsigned int *datalen, | ||
| 161 | struct nf_conntrack_expect *rtp_exp, | ||
| 162 | struct nf_conntrack_expect *rtcp_exp, | ||
| 163 | unsigned int mediaoff, | ||
| 164 | unsigned int medialen, | ||
| 165 | union nf_inet_addr *rtp_addr); | ||
| 166 | }; | ||
| 167 | extern const struct nf_nat_sip_hooks *nf_nat_sip_hooks; | ||
| 159 | 168 | ||
| 160 | int ct_sip_parse_request(const struct nf_conn *ct, const char *dptr, | 169 | int ct_sip_parse_request(const struct nf_conn *ct, const char *dptr, |
| 161 | unsigned int datalen, unsigned int *matchoff, | 170 | unsigned int datalen, unsigned int *matchoff, |
diff --git a/include/uapi/linux/netfilter/ipset/ip_set.h b/include/uapi/linux/netfilter/ipset/ip_set.h index 8024cdf13b70..25d3b2f79c02 100644 --- a/include/uapi/linux/netfilter/ipset/ip_set.h +++ b/include/uapi/linux/netfilter/ipset/ip_set.h | |||
| @@ -10,12 +10,14 @@ | |||
| 10 | #ifndef _UAPI_IP_SET_H | 10 | #ifndef _UAPI_IP_SET_H |
| 11 | #define _UAPI_IP_SET_H | 11 | #define _UAPI_IP_SET_H |
| 12 | 12 | ||
| 13 | |||
| 14 | #include <linux/types.h> | 13 | #include <linux/types.h> |
| 15 | 14 | ||
| 16 | /* The protocol version */ | 15 | /* The protocol version */ |
| 17 | #define IPSET_PROTOCOL 6 | 16 | #define IPSET_PROTOCOL 6 |
| 18 | 17 | ||
| 18 | /* The maximum permissible comment length we will accept over netlink */ | ||
| 19 | #define IPSET_MAX_COMMENT_SIZE 255 | ||
| 20 | |||
| 19 | /* The max length of strings including NUL: set and type identifiers */ | 21 | /* The max length of strings including NUL: set and type identifiers */ |
| 20 | #define IPSET_MAXNAMELEN 32 | 22 | #define IPSET_MAXNAMELEN 32 |
| 21 | 23 | ||
| @@ -110,6 +112,7 @@ enum { | |||
| 110 | IPSET_ATTR_IFACE, | 112 | IPSET_ATTR_IFACE, |
| 111 | IPSET_ATTR_BYTES, | 113 | IPSET_ATTR_BYTES, |
| 112 | IPSET_ATTR_PACKETS, | 114 | IPSET_ATTR_PACKETS, |
| 115 | IPSET_ATTR_COMMENT, | ||
| 113 | __IPSET_ATTR_ADT_MAX, | 116 | __IPSET_ATTR_ADT_MAX, |
| 114 | }; | 117 | }; |
| 115 | #define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1) | 118 | #define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1) |
| @@ -140,6 +143,7 @@ enum ipset_errno { | |||
| 140 | IPSET_ERR_IPADDR_IPV4, | 143 | IPSET_ERR_IPADDR_IPV4, |
| 141 | IPSET_ERR_IPADDR_IPV6, | 144 | IPSET_ERR_IPADDR_IPV6, |
| 142 | IPSET_ERR_COUNTER, | 145 | IPSET_ERR_COUNTER, |
| 146 | IPSET_ERR_COMMENT, | ||
| 143 | 147 | ||
| 144 | /* Type specific error codes */ | 148 | /* Type specific error codes */ |
| 145 | IPSET_ERR_TYPE_SPECIFIC = 4352, | 149 | IPSET_ERR_TYPE_SPECIFIC = 4352, |
| @@ -176,6 +180,8 @@ enum ipset_cadt_flags { | |||
| 176 | IPSET_FLAG_NOMATCH = (1 << IPSET_FLAG_BIT_NOMATCH), | 180 | IPSET_FLAG_NOMATCH = (1 << IPSET_FLAG_BIT_NOMATCH), |
| 177 | IPSET_FLAG_BIT_WITH_COUNTERS = 3, | 181 | IPSET_FLAG_BIT_WITH_COUNTERS = 3, |
| 178 | IPSET_FLAG_WITH_COUNTERS = (1 << IPSET_FLAG_BIT_WITH_COUNTERS), | 182 | IPSET_FLAG_WITH_COUNTERS = (1 << IPSET_FLAG_BIT_WITH_COUNTERS), |
| 183 | IPSET_FLAG_BIT_WITH_COMMENT = 4, | ||
| 184 | IPSET_FLAG_WITH_COMMENT = (1 << IPSET_FLAG_BIT_WITH_COMMENT), | ||
| 179 | IPSET_FLAG_CADT_MAX = 15, | 185 | IPSET_FLAG_CADT_MAX = 15, |
| 180 | }; | 186 | }; |
| 181 | 187 | ||
| @@ -250,6 +256,14 @@ struct ip_set_req_get_set { | |||
| 250 | #define IP_SET_OP_GET_BYINDEX 0x00000007 /* Get set name by index */ | 256 | #define IP_SET_OP_GET_BYINDEX 0x00000007 /* Get set name by index */ |
| 251 | /* Uses ip_set_req_get_set */ | 257 | /* Uses ip_set_req_get_set */ |
| 252 | 258 | ||
| 259 | #define IP_SET_OP_GET_FNAME 0x00000008 /* Get set index and family */ | ||
| 260 | struct ip_set_req_get_set_family { | ||
| 261 | unsigned int op; | ||
| 262 | unsigned int version; | ||
| 263 | unsigned int family; | ||
| 264 | union ip_set_name_index set; | ||
| 265 | }; | ||
| 266 | |||
| 253 | #define IP_SET_OP_VERSION 0x00000100 /* Ask kernel version */ | 267 | #define IP_SET_OP_VERSION 0x00000100 /* Ask kernel version */ |
| 254 | struct ip_set_req_version { | 268 | struct ip_set_req_version { |
| 255 | unsigned int op; | 269 | unsigned int op; |
diff --git a/include/uapi/linux/netfilter/nfnetlink_cttimeout.h b/include/uapi/linux/netfilter/nfnetlink_cttimeout.h index a2810a7c5e30..1ab0b97b3a1e 100644 --- a/include/uapi/linux/netfilter/nfnetlink_cttimeout.h +++ b/include/uapi/linux/netfilter/nfnetlink_cttimeout.h | |||
| @@ -6,6 +6,8 @@ enum ctnl_timeout_msg_types { | |||
| 6 | IPCTNL_MSG_TIMEOUT_NEW, | 6 | IPCTNL_MSG_TIMEOUT_NEW, |
| 7 | IPCTNL_MSG_TIMEOUT_GET, | 7 | IPCTNL_MSG_TIMEOUT_GET, |
| 8 | IPCTNL_MSG_TIMEOUT_DELETE, | 8 | IPCTNL_MSG_TIMEOUT_DELETE, |
| 9 | IPCTNL_MSG_TIMEOUT_DEFAULT_SET, | ||
| 10 | IPCTNL_MSG_TIMEOUT_DEFAULT_GET, | ||
| 9 | 11 | ||
| 10 | IPCTNL_MSG_TIMEOUT_MAX | 12 | IPCTNL_MSG_TIMEOUT_MAX |
| 11 | }; | 13 | }; |
diff --git a/net/netfilter/ipset/Kconfig b/net/netfilter/ipset/Kconfig index ba36c283d837..a2d6263b6c64 100644 --- a/net/netfilter/ipset/Kconfig +++ b/net/netfilter/ipset/Kconfig | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | menuconfig IP_SET | 1 | menuconfig IP_SET |
| 2 | tristate "IP set support" | 2 | tristate "IP set support" |
| 3 | depends on INET && NETFILTER | 3 | depends on INET && NETFILTER |
| 4 | depends on NETFILTER_NETLINK | 4 | select NETFILTER_NETLINK |
| 5 | help | 5 | help |
| 6 | This option adds IP set support to the kernel. | 6 | This option adds IP set support to the kernel. |
| 7 | In order to define and use the sets, you need the userspace utility | 7 | In order to define and use the sets, you need the userspace utility |
| @@ -90,6 +90,15 @@ config IP_SET_HASH_IPPORTNET | |||
| 90 | 90 | ||
| 91 | To compile it as a module, choose M here. If unsure, say N. | 91 | To compile it as a module, choose M here. If unsure, say N. |
| 92 | 92 | ||
| 93 | config IP_SET_HASH_NETPORTNET | ||
| 94 | tristate "hash:net,port,net set support" | ||
| 95 | depends on IP_SET | ||
| 96 | help | ||
| 97 | This option adds the hash:net,port,net set type support, by which | ||
| 98 | one can store two IPv4/IPv6 subnets, and a protocol/port in a set. | ||
| 99 | |||
| 100 | To compile it as a module, choose M here. If unsure, say N. | ||
| 101 | |||
| 93 | config IP_SET_HASH_NET | 102 | config IP_SET_HASH_NET |
| 94 | tristate "hash:net set support" | 103 | tristate "hash:net set support" |
| 95 | depends on IP_SET | 104 | depends on IP_SET |
| @@ -99,6 +108,15 @@ config IP_SET_HASH_NET | |||
| 99 | 108 | ||
| 100 | To compile it as a module, choose M here. If unsure, say N. | 109 | To compile it as a module, choose M here. If unsure, say N. |
| 101 | 110 | ||
| 111 | config IP_SET_HASH_NETNET | ||
| 112 | tristate "hash:net,net set support" | ||
| 113 | depends on IP_SET | ||
| 114 | help | ||
| 115 | This option adds the hash:net,net set type support, by which | ||
| 116 | one can store IPv4/IPv6 network address/prefix pairs in a set. | ||
| 117 | |||
| 118 | To compile it as a module, choose M here. If unsure, say N. | ||
| 119 | |||
| 102 | config IP_SET_HASH_NETPORT | 120 | config IP_SET_HASH_NETPORT |
| 103 | tristate "hash:net,port set support" | 121 | tristate "hash:net,port set support" |
| 104 | depends on IP_SET | 122 | depends on IP_SET |
diff --git a/net/netfilter/ipset/Makefile b/net/netfilter/ipset/Makefile index 6e965ecd5444..44b2d38476fa 100644 --- a/net/netfilter/ipset/Makefile +++ b/net/netfilter/ipset/Makefile | |||
| @@ -20,6 +20,8 @@ obj-$(CONFIG_IP_SET_HASH_IPPORTNET) += ip_set_hash_ipportnet.o | |||
| 20 | obj-$(CONFIG_IP_SET_HASH_NET) += ip_set_hash_net.o | 20 | obj-$(CONFIG_IP_SET_HASH_NET) += ip_set_hash_net.o |
| 21 | obj-$(CONFIG_IP_SET_HASH_NETPORT) += ip_set_hash_netport.o | 21 | obj-$(CONFIG_IP_SET_HASH_NETPORT) += ip_set_hash_netport.o |
| 22 | obj-$(CONFIG_IP_SET_HASH_NETIFACE) += ip_set_hash_netiface.o | 22 | obj-$(CONFIG_IP_SET_HASH_NETIFACE) += ip_set_hash_netiface.o |
| 23 | obj-$(CONFIG_IP_SET_HASH_NETNET) += ip_set_hash_netnet.o | ||
| 24 | obj-$(CONFIG_IP_SET_HASH_NETPORTNET) += ip_set_hash_netportnet.o | ||
| 23 | 25 | ||
| 24 | # list types | 26 | # list types |
| 25 | obj-$(CONFIG_IP_SET_LIST_SET) += ip_set_list_set.o | 27 | 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 25243379b887..a13e15be7911 100644 --- a/net/netfilter/ipset/ip_set_bitmap_gen.h +++ b/net/netfilter/ipset/ip_set_bitmap_gen.h | |||
| @@ -8,38 +8,32 @@ | |||
| 8 | #ifndef __IP_SET_BITMAP_IP_GEN_H | 8 | #ifndef __IP_SET_BITMAP_IP_GEN_H |
| 9 | #define __IP_SET_BITMAP_IP_GEN_H | 9 | #define __IP_SET_BITMAP_IP_GEN_H |
| 10 | 10 | ||
| 11 | #define CONCAT(a, b) a##b | 11 | #define mtype_do_test IPSET_TOKEN(MTYPE, _do_test) |
| 12 | #define TOKEN(a,b) CONCAT(a, b) | 12 | #define mtype_gc_test IPSET_TOKEN(MTYPE, _gc_test) |
| 13 | 13 | #define mtype_is_filled IPSET_TOKEN(MTYPE, _is_filled) | |
| 14 | #define mtype_do_test TOKEN(MTYPE, _do_test) | 14 | #define mtype_do_add IPSET_TOKEN(MTYPE, _do_add) |
| 15 | #define mtype_gc_test TOKEN(MTYPE, _gc_test) | 15 | #define mtype_ext_cleanup IPSET_TOKEN(MTYPE, _ext_cleanup) |
| 16 | #define mtype_is_filled TOKEN(MTYPE, _is_filled) | 16 | #define mtype_do_del IPSET_TOKEN(MTYPE, _do_del) |
| 17 | #define mtype_do_add TOKEN(MTYPE, _do_add) | 17 | #define mtype_do_list IPSET_TOKEN(MTYPE, _do_list) |
| 18 | #define mtype_do_del TOKEN(MTYPE, _do_del) | 18 | #define mtype_do_head IPSET_TOKEN(MTYPE, _do_head) |
| 19 | #define mtype_do_list TOKEN(MTYPE, _do_list) | 19 | #define mtype_adt_elem IPSET_TOKEN(MTYPE, _adt_elem) |
| 20 | #define mtype_do_head TOKEN(MTYPE, _do_head) | 20 | #define mtype_add_timeout IPSET_TOKEN(MTYPE, _add_timeout) |
| 21 | #define mtype_adt_elem TOKEN(MTYPE, _adt_elem) | 21 | #define mtype_gc_init IPSET_TOKEN(MTYPE, _gc_init) |
| 22 | #define mtype_add_timeout TOKEN(MTYPE, _add_timeout) | 22 | #define mtype_kadt IPSET_TOKEN(MTYPE, _kadt) |
| 23 | #define mtype_gc_init TOKEN(MTYPE, _gc_init) | 23 | #define mtype_uadt IPSET_TOKEN(MTYPE, _uadt) |
| 24 | #define mtype_kadt TOKEN(MTYPE, _kadt) | 24 | #define mtype_destroy IPSET_TOKEN(MTYPE, _destroy) |
| 25 | #define mtype_uadt TOKEN(MTYPE, _uadt) | 25 | #define mtype_flush IPSET_TOKEN(MTYPE, _flush) |
| 26 | #define mtype_destroy TOKEN(MTYPE, _destroy) | 26 | #define mtype_head IPSET_TOKEN(MTYPE, _head) |
| 27 | #define mtype_flush TOKEN(MTYPE, _flush) | 27 | #define mtype_same_set IPSET_TOKEN(MTYPE, _same_set) |
| 28 | #define mtype_head TOKEN(MTYPE, _head) | 28 | #define mtype_elem IPSET_TOKEN(MTYPE, _elem) |
| 29 | #define mtype_same_set TOKEN(MTYPE, _same_set) | 29 | #define mtype_test IPSET_TOKEN(MTYPE, _test) |
| 30 | #define mtype_elem TOKEN(MTYPE, _elem) | 30 | #define mtype_add IPSET_TOKEN(MTYPE, _add) |
| 31 | #define mtype_test TOKEN(MTYPE, _test) | 31 | #define mtype_del IPSET_TOKEN(MTYPE, _del) |
| 32 | #define mtype_add TOKEN(MTYPE, _add) | 32 | #define mtype_list IPSET_TOKEN(MTYPE, _list) |
| 33 | #define mtype_del TOKEN(MTYPE, _del) | 33 | #define mtype_gc IPSET_TOKEN(MTYPE, _gc) |
| 34 | #define mtype_list TOKEN(MTYPE, _list) | ||
| 35 | #define mtype_gc TOKEN(MTYPE, _gc) | ||
| 36 | #define mtype MTYPE | 34 | #define mtype MTYPE |
| 37 | 35 | ||
| 38 | #define ext_timeout(e, m) \ | 36 | #define get_ext(set, map, id) ((map)->extensions + (set)->dsize * (id)) |
| 39 | (unsigned long *)((e) + (m)->offset[IPSET_OFFSET_TIMEOUT]) | ||
| 40 | #define ext_counter(e, m) \ | ||
| 41 | (struct ip_set_counter *)((e) + (m)->offset[IPSET_OFFSET_COUNTER]) | ||
| 42 | #define get_ext(map, id) ((map)->extensions + (map)->dsize * (id)) | ||
| 43 | 37 | ||
| 44 | static void | 38 | static void |
| 45 | mtype_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set)) | 39 | mtype_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set)) |
| @@ -49,11 +43,22 @@ mtype_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set)) | |||
| 49 | init_timer(&map->gc); | 43 | init_timer(&map->gc); |
| 50 | map->gc.data = (unsigned long) set; | 44 | map->gc.data = (unsigned long) set; |
| 51 | map->gc.function = gc; | 45 | map->gc.function = gc; |
| 52 | map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ; | 46 | map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ; |
| 53 | add_timer(&map->gc); | 47 | add_timer(&map->gc); |
| 54 | } | 48 | } |
| 55 | 49 | ||
| 56 | static void | 50 | static void |
| 51 | mtype_ext_cleanup(struct ip_set *set) | ||
| 52 | { | ||
| 53 | struct mtype *map = set->data; | ||
| 54 | u32 id; | ||
| 55 | |||
| 56 | for (id = 0; id < map->elements; id++) | ||
| 57 | if (test_bit(id, map->members)) | ||
| 58 | ip_set_ext_destroy(set, get_ext(set, map, id)); | ||
| 59 | } | ||
| 60 | |||
| 61 | static void | ||
| 57 | mtype_destroy(struct ip_set *set) | 62 | mtype_destroy(struct ip_set *set) |
| 58 | { | 63 | { |
| 59 | struct mtype *map = set->data; | 64 | struct mtype *map = set->data; |
| @@ -62,8 +67,11 @@ mtype_destroy(struct ip_set *set) | |||
| 62 | del_timer_sync(&map->gc); | 67 | del_timer_sync(&map->gc); |
| 63 | 68 | ||
| 64 | ip_set_free(map->members); | 69 | ip_set_free(map->members); |
| 65 | if (map->dsize) | 70 | if (set->dsize) { |
| 71 | if (set->extensions & IPSET_EXT_DESTROY) | ||
| 72 | mtype_ext_cleanup(set); | ||
| 66 | ip_set_free(map->extensions); | 73 | ip_set_free(map->extensions); |
| 74 | } | ||
| 67 | kfree(map); | 75 | kfree(map); |
| 68 | 76 | ||
| 69 | set->data = NULL; | 77 | set->data = NULL; |
| @@ -74,6 +82,8 @@ mtype_flush(struct ip_set *set) | |||
| 74 | { | 82 | { |
| 75 | struct mtype *map = set->data; | 83 | struct mtype *map = set->data; |
| 76 | 84 | ||
| 85 | if (set->extensions & IPSET_EXT_DESTROY) | ||
| 86 | mtype_ext_cleanup(set); | ||
| 77 | memset(map->members, 0, map->memsize); | 87 | memset(map->members, 0, map->memsize); |
| 78 | } | 88 | } |
| 79 | 89 | ||
| @@ -91,12 +101,9 @@ mtype_head(struct ip_set *set, struct sk_buff *skb) | |||
| 91 | nla_put_net32(skb, IPSET_ATTR_MEMSIZE, | 101 | nla_put_net32(skb, IPSET_ATTR_MEMSIZE, |
| 92 | htonl(sizeof(*map) + | 102 | htonl(sizeof(*map) + |
| 93 | map->memsize + | 103 | map->memsize + |
| 94 | map->dsize * map->elements)) || | 104 | set->dsize * map->elements))) |
| 95 | (SET_WITH_TIMEOUT(set) && | 105 | goto nla_put_failure; |
| 96 | nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout))) || | 106 | if (unlikely(ip_set_put_flags(skb, set))) |
| 97 | (SET_WITH_COUNTER(set) && | ||
| 98 | nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, | ||
| 99 | htonl(IPSET_FLAG_WITH_COUNTERS)))) | ||
| 100 | goto nla_put_failure; | 107 | goto nla_put_failure; |
| 101 | ipset_nest_end(skb, nested); | 108 | ipset_nest_end(skb, nested); |
| 102 | 109 | ||
| @@ -111,16 +118,16 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext, | |||
| 111 | { | 118 | { |
| 112 | struct mtype *map = set->data; | 119 | struct mtype *map = set->data; |
| 113 | const struct mtype_adt_elem *e = value; | 120 | const struct mtype_adt_elem *e = value; |
| 114 | void *x = get_ext(map, e->id); | 121 | void *x = get_ext(set, map, e->id); |
| 115 | int ret = mtype_do_test(e, map); | 122 | int ret = mtype_do_test(e, map, set->dsize); |
| 116 | 123 | ||
| 117 | if (ret <= 0) | 124 | if (ret <= 0) |
| 118 | return ret; | 125 | return ret; |
| 119 | if (SET_WITH_TIMEOUT(set) && | 126 | if (SET_WITH_TIMEOUT(set) && |
| 120 | ip_set_timeout_expired(ext_timeout(x, map))) | 127 | ip_set_timeout_expired(ext_timeout(x, set))) |
| 121 | return 0; | 128 | return 0; |
| 122 | if (SET_WITH_COUNTER(set)) | 129 | if (SET_WITH_COUNTER(set)) |
| 123 | ip_set_update_counter(ext_counter(x, map), ext, mext, flags); | 130 | ip_set_update_counter(ext_counter(x, set), ext, mext, flags); |
| 124 | return 1; | 131 | return 1; |
| 125 | } | 132 | } |
| 126 | 133 | ||
| @@ -130,26 +137,30 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext, | |||
| 130 | { | 137 | { |
| 131 | struct mtype *map = set->data; | 138 | struct mtype *map = set->data; |
| 132 | const struct mtype_adt_elem *e = value; | 139 | const struct mtype_adt_elem *e = value; |
| 133 | void *x = get_ext(map, e->id); | 140 | void *x = get_ext(set, map, e->id); |
| 134 | int ret = mtype_do_add(e, map, flags); | 141 | int ret = mtype_do_add(e, map, flags, set->dsize); |
| 135 | 142 | ||
| 136 | if (ret == IPSET_ADD_FAILED) { | 143 | if (ret == IPSET_ADD_FAILED) { |
| 137 | if (SET_WITH_TIMEOUT(set) && | 144 | if (SET_WITH_TIMEOUT(set) && |
| 138 | ip_set_timeout_expired(ext_timeout(x, map))) | 145 | ip_set_timeout_expired(ext_timeout(x, set))) |
| 139 | ret = 0; | 146 | ret = 0; |
| 140 | else if (!(flags & IPSET_FLAG_EXIST)) | 147 | else if (!(flags & IPSET_FLAG_EXIST)) |
| 141 | return -IPSET_ERR_EXIST; | 148 | return -IPSET_ERR_EXIST; |
| 149 | /* Element is re-added, cleanup extensions */ | ||
| 150 | ip_set_ext_destroy(set, x); | ||
| 142 | } | 151 | } |
| 143 | 152 | ||
| 144 | if (SET_WITH_TIMEOUT(set)) | 153 | if (SET_WITH_TIMEOUT(set)) |
| 145 | #ifdef IP_SET_BITMAP_STORED_TIMEOUT | 154 | #ifdef IP_SET_BITMAP_STORED_TIMEOUT |
| 146 | mtype_add_timeout(ext_timeout(x, map), e, ext, map, ret); | 155 | mtype_add_timeout(ext_timeout(x, set), e, ext, set, map, ret); |
| 147 | #else | 156 | #else |
| 148 | ip_set_timeout_set(ext_timeout(x, map), ext->timeout); | 157 | ip_set_timeout_set(ext_timeout(x, set), ext->timeout); |
| 149 | #endif | 158 | #endif |
| 150 | 159 | ||
| 151 | if (SET_WITH_COUNTER(set)) | 160 | if (SET_WITH_COUNTER(set)) |
| 152 | ip_set_init_counter(ext_counter(x, map), ext); | 161 | ip_set_init_counter(ext_counter(x, set), ext); |
| 162 | if (SET_WITH_COMMENT(set)) | ||
| 163 | ip_set_init_comment(ext_comment(x, set), ext); | ||
| 153 | return 0; | 164 | return 0; |
| 154 | } | 165 | } |
| 155 | 166 | ||
| @@ -159,16 +170,27 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext, | |||
| 159 | { | 170 | { |
| 160 | struct mtype *map = set->data; | 171 | struct mtype *map = set->data; |
| 161 | const struct mtype_adt_elem *e = value; | 172 | const struct mtype_adt_elem *e = value; |
| 162 | const void *x = get_ext(map, e->id); | 173 | void *x = get_ext(set, map, e->id); |
| 163 | 174 | ||
| 164 | if (mtype_do_del(e, map) || | 175 | if (mtype_do_del(e, map)) |
| 165 | (SET_WITH_TIMEOUT(set) && | 176 | return -IPSET_ERR_EXIST; |
| 166 | ip_set_timeout_expired(ext_timeout(x, map)))) | 177 | |
| 178 | ip_set_ext_destroy(set, x); | ||
| 179 | if (SET_WITH_TIMEOUT(set) && | ||
| 180 | ip_set_timeout_expired(ext_timeout(x, set))) | ||
| 167 | return -IPSET_ERR_EXIST; | 181 | return -IPSET_ERR_EXIST; |
| 168 | 182 | ||
| 169 | return 0; | 183 | return 0; |
| 170 | } | 184 | } |
| 171 | 185 | ||
| 186 | #ifndef IP_SET_BITMAP_STORED_TIMEOUT | ||
| 187 | static inline bool | ||
| 188 | mtype_is_filled(const struct mtype_elem *x) | ||
| 189 | { | ||
| 190 | return true; | ||
| 191 | } | ||
| 192 | #endif | ||
| 193 | |||
| 172 | static int | 194 | static int |
| 173 | mtype_list(const struct ip_set *set, | 195 | mtype_list(const struct ip_set *set, |
| 174 | struct sk_buff *skb, struct netlink_callback *cb) | 196 | struct sk_buff *skb, struct netlink_callback *cb) |
| @@ -183,13 +205,13 @@ mtype_list(const struct ip_set *set, | |||
| 183 | return -EMSGSIZE; | 205 | return -EMSGSIZE; |
| 184 | for (; cb->args[2] < map->elements; cb->args[2]++) { | 206 | for (; cb->args[2] < map->elements; cb->args[2]++) { |
| 185 | id = cb->args[2]; | 207 | id = cb->args[2]; |
| 186 | x = get_ext(map, id); | 208 | x = get_ext(set, map, id); |
| 187 | if (!test_bit(id, map->members) || | 209 | if (!test_bit(id, map->members) || |
| 188 | (SET_WITH_TIMEOUT(set) && | 210 | (SET_WITH_TIMEOUT(set) && |
| 189 | #ifdef IP_SET_BITMAP_STORED_TIMEOUT | 211 | #ifdef IP_SET_BITMAP_STORED_TIMEOUT |
| 190 | mtype_is_filled((const struct mtype_elem *) x) && | 212 | mtype_is_filled((const struct mtype_elem *) x) && |
| 191 | #endif | 213 | #endif |
| 192 | ip_set_timeout_expired(ext_timeout(x, map)))) | 214 | ip_set_timeout_expired(ext_timeout(x, set)))) |
| 193 | continue; | 215 | continue; |
| 194 | nested = ipset_nest_start(skb, IPSET_ATTR_DATA); | 216 | nested = ipset_nest_start(skb, IPSET_ATTR_DATA); |
| 195 | if (!nested) { | 217 | if (!nested) { |
| @@ -199,23 +221,10 @@ mtype_list(const struct ip_set *set, | |||
| 199 | } else | 221 | } else |
| 200 | goto nla_put_failure; | 222 | goto nla_put_failure; |
| 201 | } | 223 | } |
| 202 | if (mtype_do_list(skb, map, id)) | 224 | if (mtype_do_list(skb, map, id, set->dsize)) |
| 203 | goto nla_put_failure; | 225 | goto nla_put_failure; |
| 204 | if (SET_WITH_TIMEOUT(set)) { | 226 | if (ip_set_put_extensions(skb, set, x, |
| 205 | #ifdef IP_SET_BITMAP_STORED_TIMEOUT | 227 | mtype_is_filled((const struct mtype_elem *) x))) |
| 206 | if (nla_put_net32(skb, IPSET_ATTR_TIMEOUT, | ||
| 207 | htonl(ip_set_timeout_stored(map, id, | ||
| 208 | ext_timeout(x, map))))) | ||
| 209 | goto nla_put_failure; | ||
| 210 | #else | ||
| 211 | if (nla_put_net32(skb, IPSET_ATTR_TIMEOUT, | ||
| 212 | htonl(ip_set_timeout_get( | ||
| 213 | ext_timeout(x, map))))) | ||
| 214 | goto nla_put_failure; | ||
| 215 | #endif | ||
| 216 | } | ||
| 217 | if (SET_WITH_COUNTER(set) && | ||
| 218 | ip_set_put_counter(skb, ext_counter(x, map))) | ||
| 219 | goto nla_put_failure; | 228 | goto nla_put_failure; |
| 220 | ipset_nest_end(skb, nested); | 229 | ipset_nest_end(skb, nested); |
| 221 | } | 230 | } |
| @@ -228,11 +237,11 @@ mtype_list(const struct ip_set *set, | |||
| 228 | 237 | ||
| 229 | nla_put_failure: | 238 | nla_put_failure: |
| 230 | nla_nest_cancel(skb, nested); | 239 | nla_nest_cancel(skb, nested); |
| 231 | ipset_nest_end(skb, adt); | ||
| 232 | if (unlikely(id == first)) { | 240 | if (unlikely(id == first)) { |
| 233 | cb->args[2] = 0; | 241 | cb->args[2] = 0; |
| 234 | return -EMSGSIZE; | 242 | return -EMSGSIZE; |
| 235 | } | 243 | } |
| 244 | ipset_nest_end(skb, adt); | ||
| 236 | return 0; | 245 | return 0; |
| 237 | } | 246 | } |
| 238 | 247 | ||
| @@ -241,21 +250,23 @@ mtype_gc(unsigned long ul_set) | |||
| 241 | { | 250 | { |
| 242 | struct ip_set *set = (struct ip_set *) ul_set; | 251 | struct ip_set *set = (struct ip_set *) ul_set; |
| 243 | struct mtype *map = set->data; | 252 | struct mtype *map = set->data; |
| 244 | const void *x; | 253 | void *x; |
| 245 | u32 id; | 254 | u32 id; |
| 246 | 255 | ||
| 247 | /* We run parallel with other readers (test element) | 256 | /* We run parallel with other readers (test element) |
| 248 | * but adding/deleting new entries is locked out */ | 257 | * but adding/deleting new entries is locked out */ |
| 249 | read_lock_bh(&set->lock); | 258 | read_lock_bh(&set->lock); |
| 250 | for (id = 0; id < map->elements; id++) | 259 | for (id = 0; id < map->elements; id++) |
| 251 | if (mtype_gc_test(id, map)) { | 260 | if (mtype_gc_test(id, map, set->dsize)) { |
| 252 | x = get_ext(map, id); | 261 | x = get_ext(set, map, id); |
| 253 | if (ip_set_timeout_expired(ext_timeout(x, map))) | 262 | if (ip_set_timeout_expired(ext_timeout(x, set))) { |
| 254 | clear_bit(id, map->members); | 263 | clear_bit(id, map->members); |
| 264 | ip_set_ext_destroy(set, x); | ||
| 265 | } | ||
| 255 | } | 266 | } |
| 256 | read_unlock_bh(&set->lock); | 267 | read_unlock_bh(&set->lock); |
| 257 | 268 | ||
| 258 | map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ; | 269 | map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ; |
| 259 | add_timer(&map->gc); | 270 | add_timer(&map->gc); |
| 260 | } | 271 | } |
| 261 | 272 | ||
diff --git a/net/netfilter/ipset/ip_set_bitmap_ip.c b/net/netfilter/ipset/ip_set_bitmap_ip.c index f1a8128bef01..6f1f9f494808 100644 --- a/net/netfilter/ipset/ip_set_bitmap_ip.c +++ b/net/netfilter/ipset/ip_set_bitmap_ip.c | |||
| @@ -25,12 +25,13 @@ | |||
| 25 | #include <linux/netfilter/ipset/ip_set.h> | 25 | #include <linux/netfilter/ipset/ip_set.h> |
| 26 | #include <linux/netfilter/ipset/ip_set_bitmap.h> | 26 | #include <linux/netfilter/ipset/ip_set_bitmap.h> |
| 27 | 27 | ||
| 28 | #define REVISION_MIN 0 | 28 | #define IPSET_TYPE_REV_MIN 0 |
| 29 | #define REVISION_MAX 1 /* Counter support added */ | 29 | /* 1 Counter support added */ |
| 30 | #define IPSET_TYPE_REV_MAX 2 /* Comment support added */ | ||
| 30 | 31 | ||
| 31 | MODULE_LICENSE("GPL"); | 32 | MODULE_LICENSE("GPL"); |
| 32 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); | 33 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); |
| 33 | IP_SET_MODULE_DESC("bitmap:ip", REVISION_MIN, REVISION_MAX); | 34 | IP_SET_MODULE_DESC("bitmap:ip", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX); |
| 34 | MODULE_ALIAS("ip_set_bitmap:ip"); | 35 | MODULE_ALIAS("ip_set_bitmap:ip"); |
| 35 | 36 | ||
| 36 | #define MTYPE bitmap_ip | 37 | #define MTYPE bitmap_ip |
| @@ -44,10 +45,7 @@ struct bitmap_ip { | |||
| 44 | u32 elements; /* number of max elements in the set */ | 45 | u32 elements; /* number of max elements in the set */ |
| 45 | u32 hosts; /* number of hosts in a subnet */ | 46 | u32 hosts; /* number of hosts in a subnet */ |
| 46 | size_t memsize; /* members size */ | 47 | size_t memsize; /* members size */ |
| 47 | size_t dsize; /* extensions struct size */ | ||
| 48 | size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */ | ||
| 49 | u8 netmask; /* subnet netmask */ | 48 | u8 netmask; /* subnet netmask */ |
| 50 | u32 timeout; /* timeout parameter */ | ||
| 51 | struct timer_list gc; /* garbage collection */ | 49 | struct timer_list gc; /* garbage collection */ |
| 52 | }; | 50 | }; |
| 53 | 51 | ||
| @@ -65,20 +63,21 @@ ip_to_id(const struct bitmap_ip *m, u32 ip) | |||
| 65 | /* Common functions */ | 63 | /* Common functions */ |
| 66 | 64 | ||
| 67 | static inline int | 65 | static inline int |
| 68 | bitmap_ip_do_test(const struct bitmap_ip_adt_elem *e, struct bitmap_ip *map) | 66 | bitmap_ip_do_test(const struct bitmap_ip_adt_elem *e, |
| 67 | struct bitmap_ip *map, size_t dsize) | ||
| 69 | { | 68 | { |
| 70 | return !!test_bit(e->id, map->members); | 69 | return !!test_bit(e->id, map->members); |
| 71 | } | 70 | } |
| 72 | 71 | ||
| 73 | static inline int | 72 | static inline int |
| 74 | bitmap_ip_gc_test(u16 id, const struct bitmap_ip *map) | 73 | bitmap_ip_gc_test(u16 id, const struct bitmap_ip *map, size_t dsize) |
| 75 | { | 74 | { |
| 76 | return !!test_bit(id, map->members); | 75 | return !!test_bit(id, map->members); |
| 77 | } | 76 | } |
| 78 | 77 | ||
| 79 | static inline int | 78 | static inline int |
| 80 | bitmap_ip_do_add(const struct bitmap_ip_adt_elem *e, struct bitmap_ip *map, | 79 | bitmap_ip_do_add(const struct bitmap_ip_adt_elem *e, struct bitmap_ip *map, |
| 81 | u32 flags) | 80 | u32 flags, size_t dsize) |
| 82 | { | 81 | { |
| 83 | return !!test_and_set_bit(e->id, map->members); | 82 | return !!test_and_set_bit(e->id, map->members); |
| 84 | } | 83 | } |
| @@ -90,7 +89,8 @@ bitmap_ip_do_del(const struct bitmap_ip_adt_elem *e, struct bitmap_ip *map) | |||
| 90 | } | 89 | } |
| 91 | 90 | ||
| 92 | static inline int | 91 | static inline int |
| 93 | bitmap_ip_do_list(struct sk_buff *skb, const struct bitmap_ip *map, u32 id) | 92 | bitmap_ip_do_list(struct sk_buff *skb, const struct bitmap_ip *map, u32 id, |
| 93 | size_t dsize) | ||
| 94 | { | 94 | { |
| 95 | return nla_put_ipaddr4(skb, IPSET_ATTR_IP, | 95 | return nla_put_ipaddr4(skb, IPSET_ATTR_IP, |
| 96 | htonl(map->first_ip + id * map->hosts)); | 96 | htonl(map->first_ip + id * map->hosts)); |
| @@ -113,7 +113,7 @@ bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
| 113 | struct bitmap_ip *map = set->data; | 113 | struct bitmap_ip *map = set->data; |
| 114 | ipset_adtfn adtfn = set->variant->adt[adt]; | 114 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 115 | struct bitmap_ip_adt_elem e = { }; | 115 | struct bitmap_ip_adt_elem e = { }; |
| 116 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, map); | 116 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); |
| 117 | u32 ip; | 117 | u32 ip; |
| 118 | 118 | ||
| 119 | ip = ntohl(ip4addr(skb, opt->flags & IPSET_DIM_ONE_SRC)); | 119 | ip = ntohl(ip4addr(skb, opt->flags & IPSET_DIM_ONE_SRC)); |
| @@ -131,9 +131,9 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 131 | { | 131 | { |
| 132 | struct bitmap_ip *map = set->data; | 132 | struct bitmap_ip *map = set->data; |
| 133 | ipset_adtfn adtfn = set->variant->adt[adt]; | 133 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 134 | u32 ip, ip_to; | 134 | u32 ip = 0, ip_to = 0; |
| 135 | struct bitmap_ip_adt_elem e = { }; | 135 | struct bitmap_ip_adt_elem e = { }; |
| 136 | struct ip_set_ext ext = IP_SET_INIT_UEXT(map); | 136 | struct ip_set_ext ext = IP_SET_INIT_UEXT(set); |
| 137 | int ret = 0; | 137 | int ret = 0; |
| 138 | 138 | ||
| 139 | if (unlikely(!tb[IPSET_ATTR_IP] || | 139 | if (unlikely(!tb[IPSET_ATTR_IP] || |
| @@ -200,7 +200,7 @@ bitmap_ip_same_set(const struct ip_set *a, const struct ip_set *b) | |||
| 200 | return x->first_ip == y->first_ip && | 200 | return x->first_ip == y->first_ip && |
| 201 | x->last_ip == y->last_ip && | 201 | x->last_ip == y->last_ip && |
| 202 | x->netmask == y->netmask && | 202 | x->netmask == y->netmask && |
| 203 | x->timeout == y->timeout && | 203 | a->timeout == b->timeout && |
| 204 | a->extensions == b->extensions; | 204 | a->extensions == b->extensions; |
| 205 | } | 205 | } |
| 206 | 206 | ||
| @@ -209,25 +209,6 @@ bitmap_ip_same_set(const struct ip_set *a, const struct ip_set *b) | |||
| 209 | struct bitmap_ip_elem { | 209 | struct bitmap_ip_elem { |
| 210 | }; | 210 | }; |
| 211 | 211 | ||
| 212 | /* Timeout variant */ | ||
| 213 | |||
| 214 | struct bitmap_ipt_elem { | ||
| 215 | unsigned long timeout; | ||
| 216 | }; | ||
| 217 | |||
| 218 | /* Plain variant with counter */ | ||
| 219 | |||
| 220 | struct bitmap_ipc_elem { | ||
| 221 | struct ip_set_counter counter; | ||
| 222 | }; | ||
| 223 | |||
| 224 | /* Timeout variant with counter */ | ||
| 225 | |||
| 226 | struct bitmap_ipct_elem { | ||
| 227 | unsigned long timeout; | ||
| 228 | struct ip_set_counter counter; | ||
| 229 | }; | ||
| 230 | |||
| 231 | #include "ip_set_bitmap_gen.h" | 212 | #include "ip_set_bitmap_gen.h" |
| 232 | 213 | ||
| 233 | /* Create bitmap:ip type of sets */ | 214 | /* Create bitmap:ip type of sets */ |
| @@ -240,8 +221,8 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map, | |||
| 240 | map->members = ip_set_alloc(map->memsize); | 221 | map->members = ip_set_alloc(map->memsize); |
| 241 | if (!map->members) | 222 | if (!map->members) |
| 242 | return false; | 223 | return false; |
| 243 | if (map->dsize) { | 224 | if (set->dsize) { |
| 244 | map->extensions = ip_set_alloc(map->dsize * elements); | 225 | map->extensions = ip_set_alloc(set->dsize * elements); |
| 245 | if (!map->extensions) { | 226 | if (!map->extensions) { |
| 246 | kfree(map->members); | 227 | kfree(map->members); |
| 247 | return false; | 228 | return false; |
| @@ -252,7 +233,7 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map, | |||
| 252 | map->elements = elements; | 233 | map->elements = elements; |
| 253 | map->hosts = hosts; | 234 | map->hosts = hosts; |
| 254 | map->netmask = netmask; | 235 | map->netmask = netmask; |
| 255 | map->timeout = IPSET_NO_TIMEOUT; | 236 | set->timeout = IPSET_NO_TIMEOUT; |
| 256 | 237 | ||
| 257 | set->data = map; | 238 | set->data = map; |
| 258 | set->family = NFPROTO_IPV4; | 239 | set->family = NFPROTO_IPV4; |
| @@ -261,10 +242,11 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map, | |||
| 261 | } | 242 | } |
| 262 | 243 | ||
| 263 | static int | 244 | static int |
| 264 | bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | 245 | bitmap_ip_create(struct net *net, struct ip_set *set, struct nlattr *tb[], |
| 246 | u32 flags) | ||
| 265 | { | 247 | { |
| 266 | struct bitmap_ip *map; | 248 | struct bitmap_ip *map; |
| 267 | u32 first_ip, last_ip, hosts, cadt_flags = 0; | 249 | u32 first_ip = 0, last_ip = 0, hosts; |
| 268 | u64 elements; | 250 | u64 elements; |
| 269 | u8 netmask = 32; | 251 | u8 netmask = 32; |
| 270 | int ret; | 252 | int ret; |
| @@ -336,61 +318,15 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
| 336 | 318 | ||
| 337 | map->memsize = bitmap_bytes(0, elements - 1); | 319 | map->memsize = bitmap_bytes(0, elements - 1); |
| 338 | set->variant = &bitmap_ip; | 320 | set->variant = &bitmap_ip; |
| 339 | if (tb[IPSET_ATTR_CADT_FLAGS]) | 321 | set->dsize = ip_set_elem_len(set, tb, 0); |
| 340 | cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); | 322 | if (!init_map_ip(set, map, first_ip, last_ip, |
| 341 | if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) { | 323 | elements, hosts, netmask)) { |
| 342 | set->extensions |= IPSET_EXT_COUNTER; | 324 | kfree(map); |
| 343 | if (tb[IPSET_ATTR_TIMEOUT]) { | 325 | return -ENOMEM; |
| 344 | map->dsize = sizeof(struct bitmap_ipct_elem); | 326 | } |
| 345 | map->offset[IPSET_OFFSET_TIMEOUT] = | 327 | if (tb[IPSET_ATTR_TIMEOUT]) { |
| 346 | offsetof(struct bitmap_ipct_elem, timeout); | 328 | set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); |
| 347 | map->offset[IPSET_OFFSET_COUNTER] = | ||
| 348 | offsetof(struct bitmap_ipct_elem, counter); | ||
| 349 | |||
| 350 | if (!init_map_ip(set, map, first_ip, last_ip, | ||
| 351 | elements, hosts, netmask)) { | ||
| 352 | kfree(map); | ||
| 353 | return -ENOMEM; | ||
| 354 | } | ||
| 355 | |||
| 356 | map->timeout = ip_set_timeout_uget( | ||
| 357 | tb[IPSET_ATTR_TIMEOUT]); | ||
| 358 | set->extensions |= IPSET_EXT_TIMEOUT; | ||
| 359 | |||
| 360 | bitmap_ip_gc_init(set, bitmap_ip_gc); | ||
| 361 | } else { | ||
| 362 | map->dsize = sizeof(struct bitmap_ipc_elem); | ||
| 363 | map->offset[IPSET_OFFSET_COUNTER] = | ||
| 364 | offsetof(struct bitmap_ipc_elem, counter); | ||
| 365 | |||
| 366 | if (!init_map_ip(set, map, first_ip, last_ip, | ||
| 367 | elements, hosts, netmask)) { | ||
| 368 | kfree(map); | ||
| 369 | return -ENOMEM; | ||
| 370 | } | ||
| 371 | } | ||
| 372 | } else if (tb[IPSET_ATTR_TIMEOUT]) { | ||
| 373 | map->dsize = sizeof(struct bitmap_ipt_elem); | ||
| 374 | map->offset[IPSET_OFFSET_TIMEOUT] = | ||
| 375 | offsetof(struct bitmap_ipt_elem, timeout); | ||
| 376 | |||
| 377 | if (!init_map_ip(set, map, first_ip, last_ip, | ||
| 378 | elements, hosts, netmask)) { | ||
| 379 | kfree(map); | ||
| 380 | return -ENOMEM; | ||
| 381 | } | ||
| 382 | |||
| 383 | map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | ||
| 384 | set->extensions |= IPSET_EXT_TIMEOUT; | ||
| 385 | |||
| 386 | bitmap_ip_gc_init(set, bitmap_ip_gc); | 329 | bitmap_ip_gc_init(set, bitmap_ip_gc); |
| 387 | } else { | ||
| 388 | map->dsize = 0; | ||
| 389 | if (!init_map_ip(set, map, first_ip, last_ip, | ||
| 390 | elements, hosts, netmask)) { | ||
| 391 | kfree(map); | ||
| 392 | return -ENOMEM; | ||
| 393 | } | ||
| 394 | } | 330 | } |
| 395 | return 0; | 331 | return 0; |
| 396 | } | 332 | } |
| @@ -401,8 +337,8 @@ static struct ip_set_type bitmap_ip_type __read_mostly = { | |||
| 401 | .features = IPSET_TYPE_IP, | 337 | .features = IPSET_TYPE_IP, |
| 402 | .dimension = IPSET_DIM_ONE, | 338 | .dimension = IPSET_DIM_ONE, |
| 403 | .family = NFPROTO_IPV4, | 339 | .family = NFPROTO_IPV4, |
| 404 | .revision_min = REVISION_MIN, | 340 | .revision_min = IPSET_TYPE_REV_MIN, |
| 405 | .revision_max = REVISION_MAX, | 341 | .revision_max = IPSET_TYPE_REV_MAX, |
| 406 | .create = bitmap_ip_create, | 342 | .create = bitmap_ip_create, |
| 407 | .create_policy = { | 343 | .create_policy = { |
| 408 | [IPSET_ATTR_IP] = { .type = NLA_NESTED }, | 344 | [IPSET_ATTR_IP] = { .type = NLA_NESTED }, |
| @@ -420,6 +356,7 @@ static struct ip_set_type bitmap_ip_type __read_mostly = { | |||
| 420 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, | 356 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, |
| 421 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | 357 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, |
| 422 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | 358 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, |
| 359 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | ||
| 423 | }, | 360 | }, |
| 424 | .me = THIS_MODULE, | 361 | .me = THIS_MODULE, |
| 425 | }; | 362 | }; |
diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c index 3b30e0bef890..740eabededd9 100644 --- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c +++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c | |||
| @@ -25,12 +25,13 @@ | |||
| 25 | #include <linux/netfilter/ipset/ip_set.h> | 25 | #include <linux/netfilter/ipset/ip_set.h> |
| 26 | #include <linux/netfilter/ipset/ip_set_bitmap.h> | 26 | #include <linux/netfilter/ipset/ip_set_bitmap.h> |
| 27 | 27 | ||
| 28 | #define REVISION_MIN 0 | 28 | #define IPSET_TYPE_REV_MIN 0 |
| 29 | #define REVISION_MAX 1 /* Counter support added */ | 29 | /* 1 Counter support added */ |
| 30 | #define IPSET_TYPE_REV_MAX 2 /* Comment support added */ | ||
| 30 | 31 | ||
| 31 | MODULE_LICENSE("GPL"); | 32 | MODULE_LICENSE("GPL"); |
| 32 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); | 33 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); |
| 33 | IP_SET_MODULE_DESC("bitmap:ip,mac", REVISION_MIN, REVISION_MAX); | 34 | IP_SET_MODULE_DESC("bitmap:ip,mac", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX); |
| 34 | MODULE_ALIAS("ip_set_bitmap:ip,mac"); | 35 | MODULE_ALIAS("ip_set_bitmap:ip,mac"); |
| 35 | 36 | ||
| 36 | #define MTYPE bitmap_ipmac | 37 | #define MTYPE bitmap_ipmac |
| @@ -48,11 +49,8 @@ struct bitmap_ipmac { | |||
| 48 | u32 first_ip; /* host byte order, included in range */ | 49 | u32 first_ip; /* host byte order, included in range */ |
| 49 | u32 last_ip; /* host byte order, included in range */ | 50 | u32 last_ip; /* host byte order, included in range */ |
| 50 | u32 elements; /* number of max elements in the set */ | 51 | u32 elements; /* number of max elements in the set */ |
| 51 | u32 timeout; /* timeout value */ | ||
| 52 | struct timer_list gc; /* garbage collector */ | ||
| 53 | size_t memsize; /* members size */ | 52 | size_t memsize; /* members size */ |
| 54 | size_t dsize; /* size of element */ | 53 | struct timer_list gc; /* garbage collector */ |
| 55 | size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */ | ||
| 56 | }; | 54 | }; |
| 57 | 55 | ||
| 58 | /* ADT structure for generic function args */ | 56 | /* ADT structure for generic function args */ |
| @@ -82,13 +80,13 @@ get_elem(void *extensions, u16 id, size_t dsize) | |||
| 82 | 80 | ||
| 83 | static inline int | 81 | static inline int |
| 84 | bitmap_ipmac_do_test(const struct bitmap_ipmac_adt_elem *e, | 82 | bitmap_ipmac_do_test(const struct bitmap_ipmac_adt_elem *e, |
| 85 | const struct bitmap_ipmac *map) | 83 | const struct bitmap_ipmac *map, size_t dsize) |
| 86 | { | 84 | { |
| 87 | const struct bitmap_ipmac_elem *elem; | 85 | const struct bitmap_ipmac_elem *elem; |
| 88 | 86 | ||
| 89 | if (!test_bit(e->id, map->members)) | 87 | if (!test_bit(e->id, map->members)) |
| 90 | return 0; | 88 | return 0; |
| 91 | elem = get_elem(map->extensions, e->id, map->dsize); | 89 | elem = get_elem(map->extensions, e->id, dsize); |
| 92 | if (elem->filled == MAC_FILLED) | 90 | if (elem->filled == MAC_FILLED) |
| 93 | return e->ether == NULL || | 91 | return e->ether == NULL || |
| 94 | ether_addr_equal(e->ether, elem->ether); | 92 | ether_addr_equal(e->ether, elem->ether); |
| @@ -97,13 +95,13 @@ bitmap_ipmac_do_test(const struct bitmap_ipmac_adt_elem *e, | |||
| 97 | } | 95 | } |
| 98 | 96 | ||
| 99 | static inline int | 97 | static inline int |
| 100 | bitmap_ipmac_gc_test(u16 id, const struct bitmap_ipmac *map) | 98 | bitmap_ipmac_gc_test(u16 id, const struct bitmap_ipmac *map, size_t dsize) |
| 101 | { | 99 | { |
| 102 | const struct bitmap_ipmac_elem *elem; | 100 | const struct bitmap_ipmac_elem *elem; |
| 103 | 101 | ||
| 104 | if (!test_bit(id, map->members)) | 102 | if (!test_bit(id, map->members)) |
| 105 | return 0; | 103 | return 0; |
| 106 | elem = get_elem(map->extensions, id, map->dsize); | 104 | elem = get_elem(map->extensions, id, dsize); |
| 107 | /* Timer not started for the incomplete elements */ | 105 | /* Timer not started for the incomplete elements */ |
| 108 | return elem->filled == MAC_FILLED; | 106 | return elem->filled == MAC_FILLED; |
| 109 | } | 107 | } |
| @@ -117,13 +115,13 @@ bitmap_ipmac_is_filled(const struct bitmap_ipmac_elem *elem) | |||
| 117 | static inline int | 115 | static inline int |
| 118 | bitmap_ipmac_add_timeout(unsigned long *timeout, | 116 | bitmap_ipmac_add_timeout(unsigned long *timeout, |
| 119 | const struct bitmap_ipmac_adt_elem *e, | 117 | const struct bitmap_ipmac_adt_elem *e, |
| 120 | const struct ip_set_ext *ext, | 118 | const struct ip_set_ext *ext, struct ip_set *set, |
| 121 | struct bitmap_ipmac *map, int mode) | 119 | struct bitmap_ipmac *map, int mode) |
| 122 | { | 120 | { |
| 123 | u32 t = ext->timeout; | 121 | u32 t = ext->timeout; |
| 124 | 122 | ||
| 125 | if (mode == IPSET_ADD_START_STORED_TIMEOUT) { | 123 | if (mode == IPSET_ADD_START_STORED_TIMEOUT) { |
| 126 | if (t == map->timeout) | 124 | if (t == set->timeout) |
| 127 | /* Timeout was not specified, get stored one */ | 125 | /* Timeout was not specified, get stored one */ |
| 128 | t = *timeout; | 126 | t = *timeout; |
| 129 | ip_set_timeout_set(timeout, t); | 127 | ip_set_timeout_set(timeout, t); |
| @@ -142,11 +140,11 @@ bitmap_ipmac_add_timeout(unsigned long *timeout, | |||
| 142 | 140 | ||
| 143 | static inline int | 141 | static inline int |
| 144 | bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e, | 142 | bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e, |
| 145 | struct bitmap_ipmac *map, u32 flags) | 143 | struct bitmap_ipmac *map, u32 flags, size_t dsize) |
| 146 | { | 144 | { |
| 147 | struct bitmap_ipmac_elem *elem; | 145 | struct bitmap_ipmac_elem *elem; |
| 148 | 146 | ||
| 149 | elem = get_elem(map->extensions, e->id, map->dsize); | 147 | elem = get_elem(map->extensions, e->id, dsize); |
| 150 | if (test_and_set_bit(e->id, map->members)) { | 148 | if (test_and_set_bit(e->id, map->members)) { |
| 151 | if (elem->filled == MAC_FILLED) { | 149 | if (elem->filled == MAC_FILLED) { |
| 152 | if (e->ether && (flags & IPSET_FLAG_EXIST)) | 150 | if (e->ether && (flags & IPSET_FLAG_EXIST)) |
| @@ -178,22 +176,12 @@ bitmap_ipmac_do_del(const struct bitmap_ipmac_adt_elem *e, | |||
| 178 | return !test_and_clear_bit(e->id, map->members); | 176 | return !test_and_clear_bit(e->id, map->members); |
| 179 | } | 177 | } |
| 180 | 178 | ||
| 181 | static inline unsigned long | ||
| 182 | ip_set_timeout_stored(struct bitmap_ipmac *map, u32 id, unsigned long *timeout) | ||
| 183 | { | ||
| 184 | const struct bitmap_ipmac_elem *elem = | ||
| 185 | get_elem(map->extensions, id, map->dsize); | ||
| 186 | |||
| 187 | return elem->filled == MAC_FILLED ? ip_set_timeout_get(timeout) : | ||
| 188 | *timeout; | ||
| 189 | } | ||
| 190 | |||
| 191 | static inline int | 179 | static inline int |
| 192 | bitmap_ipmac_do_list(struct sk_buff *skb, const struct bitmap_ipmac *map, | 180 | bitmap_ipmac_do_list(struct sk_buff *skb, const struct bitmap_ipmac *map, |
| 193 | u32 id) | 181 | u32 id, size_t dsize) |
| 194 | { | 182 | { |
| 195 | const struct bitmap_ipmac_elem *elem = | 183 | const struct bitmap_ipmac_elem *elem = |
| 196 | get_elem(map->extensions, id, map->dsize); | 184 | get_elem(map->extensions, id, dsize); |
| 197 | 185 | ||
| 198 | return nla_put_ipaddr4(skb, IPSET_ATTR_IP, | 186 | return nla_put_ipaddr4(skb, IPSET_ATTR_IP, |
| 199 | htonl(map->first_ip + id)) || | 187 | htonl(map->first_ip + id)) || |
| @@ -216,7 +204,7 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
| 216 | struct bitmap_ipmac *map = set->data; | 204 | struct bitmap_ipmac *map = set->data; |
| 217 | ipset_adtfn adtfn = set->variant->adt[adt]; | 205 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 218 | struct bitmap_ipmac_adt_elem e = {}; | 206 | struct bitmap_ipmac_adt_elem e = {}; |
| 219 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, map); | 207 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); |
| 220 | u32 ip; | 208 | u32 ip; |
| 221 | 209 | ||
| 222 | /* MAC can be src only */ | 210 | /* MAC can be src only */ |
| @@ -245,8 +233,8 @@ bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 245 | const struct bitmap_ipmac *map = set->data; | 233 | const struct bitmap_ipmac *map = set->data; |
| 246 | ipset_adtfn adtfn = set->variant->adt[adt]; | 234 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 247 | struct bitmap_ipmac_adt_elem e = {}; | 235 | struct bitmap_ipmac_adt_elem e = {}; |
| 248 | struct ip_set_ext ext = IP_SET_INIT_UEXT(map); | 236 | struct ip_set_ext ext = IP_SET_INIT_UEXT(set); |
| 249 | u32 ip; | 237 | u32 ip = 0; |
| 250 | int ret = 0; | 238 | int ret = 0; |
| 251 | 239 | ||
| 252 | if (unlikely(!tb[IPSET_ATTR_IP] || | 240 | if (unlikely(!tb[IPSET_ATTR_IP] || |
| @@ -285,43 +273,12 @@ bitmap_ipmac_same_set(const struct ip_set *a, const struct ip_set *b) | |||
| 285 | 273 | ||
| 286 | return x->first_ip == y->first_ip && | 274 | return x->first_ip == y->first_ip && |
| 287 | x->last_ip == y->last_ip && | 275 | x->last_ip == y->last_ip && |
| 288 | x->timeout == y->timeout && | 276 | a->timeout == b->timeout && |
| 289 | a->extensions == b->extensions; | 277 | a->extensions == b->extensions; |
| 290 | } | 278 | } |
| 291 | 279 | ||
| 292 | /* Plain variant */ | 280 | /* Plain variant */ |
| 293 | 281 | ||
| 294 | /* Timeout variant */ | ||
| 295 | |||
| 296 | struct bitmap_ipmact_elem { | ||
| 297 | struct { | ||
| 298 | unsigned char ether[ETH_ALEN]; | ||
| 299 | unsigned char filled; | ||
| 300 | } __attribute__ ((aligned)); | ||
| 301 | unsigned long timeout; | ||
| 302 | }; | ||
| 303 | |||
| 304 | /* Plain variant with counter */ | ||
| 305 | |||
| 306 | struct bitmap_ipmacc_elem { | ||
| 307 | struct { | ||
| 308 | unsigned char ether[ETH_ALEN]; | ||
| 309 | unsigned char filled; | ||
| 310 | } __attribute__ ((aligned)); | ||
| 311 | struct ip_set_counter counter; | ||
| 312 | }; | ||
| 313 | |||
| 314 | /* Timeout variant with counter */ | ||
| 315 | |||
| 316 | struct bitmap_ipmacct_elem { | ||
| 317 | struct { | ||
| 318 | unsigned char ether[ETH_ALEN]; | ||
| 319 | unsigned char filled; | ||
| 320 | } __attribute__ ((aligned)); | ||
| 321 | unsigned long timeout; | ||
| 322 | struct ip_set_counter counter; | ||
| 323 | }; | ||
| 324 | |||
| 325 | #include "ip_set_bitmap_gen.h" | 282 | #include "ip_set_bitmap_gen.h" |
| 326 | 283 | ||
| 327 | /* Create bitmap:ip,mac type of sets */ | 284 | /* Create bitmap:ip,mac type of sets */ |
| @@ -330,11 +287,11 @@ static bool | |||
| 330 | init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map, | 287 | init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map, |
| 331 | u32 first_ip, u32 last_ip, u32 elements) | 288 | u32 first_ip, u32 last_ip, u32 elements) |
| 332 | { | 289 | { |
| 333 | map->members = ip_set_alloc((last_ip - first_ip + 1) * map->dsize); | 290 | map->members = ip_set_alloc(map->memsize); |
| 334 | if (!map->members) | 291 | if (!map->members) |
| 335 | return false; | 292 | return false; |
| 336 | if (map->dsize) { | 293 | if (set->dsize) { |
| 337 | map->extensions = ip_set_alloc(map->dsize * elements); | 294 | map->extensions = ip_set_alloc(set->dsize * elements); |
| 338 | if (!map->extensions) { | 295 | if (!map->extensions) { |
| 339 | kfree(map->members); | 296 | kfree(map->members); |
| 340 | return false; | 297 | return false; |
| @@ -343,7 +300,7 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map, | |||
| 343 | map->first_ip = first_ip; | 300 | map->first_ip = first_ip; |
| 344 | map->last_ip = last_ip; | 301 | map->last_ip = last_ip; |
| 345 | map->elements = elements; | 302 | map->elements = elements; |
| 346 | map->timeout = IPSET_NO_TIMEOUT; | 303 | set->timeout = IPSET_NO_TIMEOUT; |
| 347 | 304 | ||
| 348 | set->data = map; | 305 | set->data = map; |
| 349 | set->family = NFPROTO_IPV4; | 306 | set->family = NFPROTO_IPV4; |
| @@ -352,10 +309,10 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map, | |||
| 352 | } | 309 | } |
| 353 | 310 | ||
| 354 | static int | 311 | static int |
| 355 | bitmap_ipmac_create(struct ip_set *set, struct nlattr *tb[], | 312 | bitmap_ipmac_create(struct net *net, struct ip_set *set, struct nlattr *tb[], |
| 356 | u32 flags) | 313 | u32 flags) |
| 357 | { | 314 | { |
| 358 | u32 first_ip, last_ip, cadt_flags = 0; | 315 | u32 first_ip = 0, last_ip = 0; |
| 359 | u64 elements; | 316 | u64 elements; |
| 360 | struct bitmap_ipmac *map; | 317 | struct bitmap_ipmac *map; |
| 361 | int ret; | 318 | int ret; |
| @@ -399,57 +356,15 @@ bitmap_ipmac_create(struct ip_set *set, struct nlattr *tb[], | |||
| 399 | 356 | ||
| 400 | map->memsize = bitmap_bytes(0, elements - 1); | 357 | map->memsize = bitmap_bytes(0, elements - 1); |
| 401 | set->variant = &bitmap_ipmac; | 358 | set->variant = &bitmap_ipmac; |
| 402 | if (tb[IPSET_ATTR_CADT_FLAGS]) | 359 | set->dsize = ip_set_elem_len(set, tb, |
| 403 | cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); | 360 | sizeof(struct bitmap_ipmac_elem)); |
| 404 | if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) { | 361 | if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) { |
| 405 | set->extensions |= IPSET_EXT_COUNTER; | 362 | kfree(map); |
| 406 | if (tb[IPSET_ATTR_TIMEOUT]) { | 363 | return -ENOMEM; |
| 407 | map->dsize = sizeof(struct bitmap_ipmacct_elem); | 364 | } |
| 408 | map->offset[IPSET_OFFSET_TIMEOUT] = | 365 | if (tb[IPSET_ATTR_TIMEOUT]) { |
| 409 | offsetof(struct bitmap_ipmacct_elem, timeout); | 366 | set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); |
| 410 | map->offset[IPSET_OFFSET_COUNTER] = | ||
| 411 | offsetof(struct bitmap_ipmacct_elem, counter); | ||
| 412 | |||
| 413 | if (!init_map_ipmac(set, map, first_ip, last_ip, | ||
| 414 | elements)) { | ||
| 415 | kfree(map); | ||
| 416 | return -ENOMEM; | ||
| 417 | } | ||
| 418 | map->timeout = ip_set_timeout_uget( | ||
| 419 | tb[IPSET_ATTR_TIMEOUT]); | ||
| 420 | set->extensions |= IPSET_EXT_TIMEOUT; | ||
| 421 | bitmap_ipmac_gc_init(set, bitmap_ipmac_gc); | ||
| 422 | } else { | ||
| 423 | map->dsize = sizeof(struct bitmap_ipmacc_elem); | ||
| 424 | map->offset[IPSET_OFFSET_COUNTER] = | ||
| 425 | offsetof(struct bitmap_ipmacc_elem, counter); | ||
| 426 | |||
| 427 | if (!init_map_ipmac(set, map, first_ip, last_ip, | ||
| 428 | elements)) { | ||
| 429 | kfree(map); | ||
| 430 | return -ENOMEM; | ||
| 431 | } | ||
| 432 | } | ||
| 433 | } else if (tb[IPSET_ATTR_TIMEOUT]) { | ||
| 434 | map->dsize = sizeof(struct bitmap_ipmact_elem); | ||
| 435 | map->offset[IPSET_OFFSET_TIMEOUT] = | ||
| 436 | offsetof(struct bitmap_ipmact_elem, timeout); | ||
| 437 | |||
| 438 | if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) { | ||
| 439 | kfree(map); | ||
| 440 | return -ENOMEM; | ||
| 441 | } | ||
| 442 | map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | ||
| 443 | set->extensions |= IPSET_EXT_TIMEOUT; | ||
| 444 | bitmap_ipmac_gc_init(set, bitmap_ipmac_gc); | 367 | bitmap_ipmac_gc_init(set, bitmap_ipmac_gc); |
| 445 | } else { | ||
| 446 | map->dsize = sizeof(struct bitmap_ipmac_elem); | ||
| 447 | |||
| 448 | if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) { | ||
| 449 | kfree(map); | ||
| 450 | return -ENOMEM; | ||
| 451 | } | ||
| 452 | set->variant = &bitmap_ipmac; | ||
| 453 | } | 368 | } |
| 454 | return 0; | 369 | return 0; |
| 455 | } | 370 | } |
| @@ -460,8 +375,8 @@ static struct ip_set_type bitmap_ipmac_type = { | |||
| 460 | .features = IPSET_TYPE_IP | IPSET_TYPE_MAC, | 375 | .features = IPSET_TYPE_IP | IPSET_TYPE_MAC, |
| 461 | .dimension = IPSET_DIM_TWO, | 376 | .dimension = IPSET_DIM_TWO, |
| 462 | .family = NFPROTO_IPV4, | 377 | .family = NFPROTO_IPV4, |
| 463 | .revision_min = REVISION_MIN, | 378 | .revision_min = IPSET_TYPE_REV_MIN, |
| 464 | .revision_max = REVISION_MAX, | 379 | .revision_max = IPSET_TYPE_REV_MAX, |
| 465 | .create = bitmap_ipmac_create, | 380 | .create = bitmap_ipmac_create, |
| 466 | .create_policy = { | 381 | .create_policy = { |
| 467 | [IPSET_ATTR_IP] = { .type = NLA_NESTED }, | 382 | [IPSET_ATTR_IP] = { .type = NLA_NESTED }, |
| @@ -478,6 +393,7 @@ static struct ip_set_type bitmap_ipmac_type = { | |||
| 478 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, | 393 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, |
| 479 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | 394 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, |
| 480 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | 395 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, |
| 396 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | ||
| 481 | }, | 397 | }, |
| 482 | .me = THIS_MODULE, | 398 | .me = THIS_MODULE, |
| 483 | }; | 399 | }; |
diff --git a/net/netfilter/ipset/ip_set_bitmap_port.c b/net/netfilter/ipset/ip_set_bitmap_port.c index 8207d1fda528..e7603c5b53d7 100644 --- a/net/netfilter/ipset/ip_set_bitmap_port.c +++ b/net/netfilter/ipset/ip_set_bitmap_port.c | |||
| @@ -20,12 +20,13 @@ | |||
| 20 | #include <linux/netfilter/ipset/ip_set_bitmap.h> | 20 | #include <linux/netfilter/ipset/ip_set_bitmap.h> |
| 21 | #include <linux/netfilter/ipset/ip_set_getport.h> | 21 | #include <linux/netfilter/ipset/ip_set_getport.h> |
| 22 | 22 | ||
| 23 | #define REVISION_MIN 0 | 23 | #define IPSET_TYPE_REV_MIN 0 |
| 24 | #define REVISION_MAX 1 /* Counter support added */ | 24 | /* 1 Counter support added */ |
| 25 | #define IPSET_TYPE_REV_MAX 2 /* Comment support added */ | ||
| 25 | 26 | ||
| 26 | MODULE_LICENSE("GPL"); | 27 | MODULE_LICENSE("GPL"); |
| 27 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); | 28 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); |
| 28 | IP_SET_MODULE_DESC("bitmap:port", REVISION_MIN, REVISION_MAX); | 29 | IP_SET_MODULE_DESC("bitmap:port", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX); |
| 29 | MODULE_ALIAS("ip_set_bitmap:port"); | 30 | MODULE_ALIAS("ip_set_bitmap:port"); |
| 30 | 31 | ||
| 31 | #define MTYPE bitmap_port | 32 | #define MTYPE bitmap_port |
| @@ -38,9 +39,6 @@ struct bitmap_port { | |||
| 38 | u16 last_port; /* host byte order, included in range */ | 39 | u16 last_port; /* host byte order, included in range */ |
| 39 | u32 elements; /* number of max elements in the set */ | 40 | u32 elements; /* number of max elements in the set */ |
| 40 | size_t memsize; /* members size */ | 41 | size_t memsize; /* members size */ |
| 41 | size_t dsize; /* extensions struct size */ | ||
| 42 | size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */ | ||
| 43 | u32 timeout; /* timeout parameter */ | ||
| 44 | struct timer_list gc; /* garbage collection */ | 42 | struct timer_list gc; /* garbage collection */ |
| 45 | }; | 43 | }; |
| 46 | 44 | ||
| @@ -59,20 +57,20 @@ port_to_id(const struct bitmap_port *m, u16 port) | |||
| 59 | 57 | ||
| 60 | static inline int | 58 | static inline int |
| 61 | bitmap_port_do_test(const struct bitmap_port_adt_elem *e, | 59 | bitmap_port_do_test(const struct bitmap_port_adt_elem *e, |
| 62 | const struct bitmap_port *map) | 60 | const struct bitmap_port *map, size_t dsize) |
| 63 | { | 61 | { |
| 64 | return !!test_bit(e->id, map->members); | 62 | return !!test_bit(e->id, map->members); |
| 65 | } | 63 | } |
| 66 | 64 | ||
| 67 | static inline int | 65 | static inline int |
| 68 | bitmap_port_gc_test(u16 id, const struct bitmap_port *map) | 66 | bitmap_port_gc_test(u16 id, const struct bitmap_port *map, size_t dsize) |
| 69 | { | 67 | { |
| 70 | return !!test_bit(id, map->members); | 68 | return !!test_bit(id, map->members); |
| 71 | } | 69 | } |
| 72 | 70 | ||
| 73 | static inline int | 71 | static inline int |
| 74 | bitmap_port_do_add(const struct bitmap_port_adt_elem *e, | 72 | bitmap_port_do_add(const struct bitmap_port_adt_elem *e, |
| 75 | struct bitmap_port *map, u32 flags) | 73 | struct bitmap_port *map, u32 flags, size_t dsize) |
| 76 | { | 74 | { |
| 77 | return !!test_and_set_bit(e->id, map->members); | 75 | return !!test_and_set_bit(e->id, map->members); |
| 78 | } | 76 | } |
| @@ -85,7 +83,8 @@ bitmap_port_do_del(const struct bitmap_port_adt_elem *e, | |||
| 85 | } | 83 | } |
| 86 | 84 | ||
| 87 | static inline int | 85 | static inline int |
| 88 | bitmap_port_do_list(struct sk_buff *skb, const struct bitmap_port *map, u32 id) | 86 | bitmap_port_do_list(struct sk_buff *skb, const struct bitmap_port *map, u32 id, |
| 87 | size_t dsize) | ||
| 89 | { | 88 | { |
| 90 | return nla_put_net16(skb, IPSET_ATTR_PORT, | 89 | return nla_put_net16(skb, IPSET_ATTR_PORT, |
| 91 | htons(map->first_port + id)); | 90 | htons(map->first_port + id)); |
| @@ -106,7 +105,7 @@ bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
| 106 | struct bitmap_port *map = set->data; | 105 | struct bitmap_port *map = set->data; |
| 107 | ipset_adtfn adtfn = set->variant->adt[adt]; | 106 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 108 | struct bitmap_port_adt_elem e = {}; | 107 | struct bitmap_port_adt_elem e = {}; |
| 109 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, map); | 108 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); |
| 110 | __be16 __port; | 109 | __be16 __port; |
| 111 | u16 port = 0; | 110 | u16 port = 0; |
| 112 | 111 | ||
| @@ -131,7 +130,7 @@ bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 131 | struct bitmap_port *map = set->data; | 130 | struct bitmap_port *map = set->data; |
| 132 | ipset_adtfn adtfn = set->variant->adt[adt]; | 131 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 133 | struct bitmap_port_adt_elem e = {}; | 132 | struct bitmap_port_adt_elem e = {}; |
| 134 | struct ip_set_ext ext = IP_SET_INIT_UEXT(map); | 133 | struct ip_set_ext ext = IP_SET_INIT_UEXT(set); |
| 135 | u32 port; /* wraparound */ | 134 | u32 port; /* wraparound */ |
| 136 | u16 port_to; | 135 | u16 port_to; |
| 137 | int ret = 0; | 136 | int ret = 0; |
| @@ -191,7 +190,7 @@ bitmap_port_same_set(const struct ip_set *a, const struct ip_set *b) | |||
| 191 | 190 | ||
| 192 | return x->first_port == y->first_port && | 191 | return x->first_port == y->first_port && |
| 193 | x->last_port == y->last_port && | 192 | x->last_port == y->last_port && |
| 194 | x->timeout == y->timeout && | 193 | a->timeout == b->timeout && |
| 195 | a->extensions == b->extensions; | 194 | a->extensions == b->extensions; |
| 196 | } | 195 | } |
| 197 | 196 | ||
| @@ -200,25 +199,6 @@ bitmap_port_same_set(const struct ip_set *a, const struct ip_set *b) | |||
| 200 | struct bitmap_port_elem { | 199 | struct bitmap_port_elem { |
| 201 | }; | 200 | }; |
| 202 | 201 | ||
| 203 | /* Timeout variant */ | ||
| 204 | |||
| 205 | struct bitmap_portt_elem { | ||
| 206 | unsigned long timeout; | ||
| 207 | }; | ||
| 208 | |||
| 209 | /* Plain variant with counter */ | ||
| 210 | |||
| 211 | struct bitmap_portc_elem { | ||
| 212 | struct ip_set_counter counter; | ||
| 213 | }; | ||
| 214 | |||
| 215 | /* Timeout variant with counter */ | ||
| 216 | |||
| 217 | struct bitmap_portct_elem { | ||
| 218 | unsigned long timeout; | ||
| 219 | struct ip_set_counter counter; | ||
| 220 | }; | ||
| 221 | |||
| 222 | #include "ip_set_bitmap_gen.h" | 202 | #include "ip_set_bitmap_gen.h" |
| 223 | 203 | ||
| 224 | /* Create bitmap:ip type of sets */ | 204 | /* Create bitmap:ip type of sets */ |
| @@ -230,8 +210,8 @@ init_map_port(struct ip_set *set, struct bitmap_port *map, | |||
| 230 | map->members = ip_set_alloc(map->memsize); | 210 | map->members = ip_set_alloc(map->memsize); |
| 231 | if (!map->members) | 211 | if (!map->members) |
| 232 | return false; | 212 | return false; |
| 233 | if (map->dsize) { | 213 | if (set->dsize) { |
| 234 | map->extensions = ip_set_alloc(map->dsize * map->elements); | 214 | map->extensions = ip_set_alloc(set->dsize * map->elements); |
| 235 | if (!map->extensions) { | 215 | if (!map->extensions) { |
| 236 | kfree(map->members); | 216 | kfree(map->members); |
| 237 | return false; | 217 | return false; |
| @@ -239,7 +219,7 @@ init_map_port(struct ip_set *set, struct bitmap_port *map, | |||
| 239 | } | 219 | } |
| 240 | map->first_port = first_port; | 220 | map->first_port = first_port; |
| 241 | map->last_port = last_port; | 221 | map->last_port = last_port; |
| 242 | map->timeout = IPSET_NO_TIMEOUT; | 222 | set->timeout = IPSET_NO_TIMEOUT; |
| 243 | 223 | ||
| 244 | set->data = map; | 224 | set->data = map; |
| 245 | set->family = NFPROTO_UNSPEC; | 225 | set->family = NFPROTO_UNSPEC; |
| @@ -248,11 +228,11 @@ init_map_port(struct ip_set *set, struct bitmap_port *map, | |||
| 248 | } | 228 | } |
| 249 | 229 | ||
| 250 | static int | 230 | static int |
| 251 | bitmap_port_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | 231 | bitmap_port_create(struct net *net, struct ip_set *set, struct nlattr *tb[], |
| 232 | u32 flags) | ||
| 252 | { | 233 | { |
| 253 | struct bitmap_port *map; | 234 | struct bitmap_port *map; |
| 254 | u16 first_port, last_port; | 235 | u16 first_port, last_port; |
| 255 | u32 cadt_flags = 0; | ||
| 256 | 236 | ||
| 257 | if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || | 237 | if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || |
| 258 | !ip_set_attr_netorder(tb, IPSET_ATTR_PORT_TO) || | 238 | !ip_set_attr_netorder(tb, IPSET_ATTR_PORT_TO) || |
| @@ -276,53 +256,14 @@ bitmap_port_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
| 276 | map->elements = last_port - first_port + 1; | 256 | map->elements = last_port - first_port + 1; |
| 277 | map->memsize = map->elements * sizeof(unsigned long); | 257 | map->memsize = map->elements * sizeof(unsigned long); |
| 278 | set->variant = &bitmap_port; | 258 | set->variant = &bitmap_port; |
| 279 | if (tb[IPSET_ATTR_CADT_FLAGS]) | 259 | set->dsize = ip_set_elem_len(set, tb, 0); |
| 280 | cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); | 260 | if (!init_map_port(set, map, first_port, last_port)) { |
| 281 | if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) { | 261 | kfree(map); |
| 282 | set->extensions |= IPSET_EXT_COUNTER; | 262 | return -ENOMEM; |
| 283 | if (tb[IPSET_ATTR_TIMEOUT]) { | 263 | } |
| 284 | map->dsize = sizeof(struct bitmap_portct_elem); | 264 | if (tb[IPSET_ATTR_TIMEOUT]) { |
| 285 | map->offset[IPSET_OFFSET_TIMEOUT] = | 265 | set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); |
| 286 | offsetof(struct bitmap_portct_elem, timeout); | ||
| 287 | map->offset[IPSET_OFFSET_COUNTER] = | ||
| 288 | offsetof(struct bitmap_portct_elem, counter); | ||
| 289 | if (!init_map_port(set, map, first_port, last_port)) { | ||
| 290 | kfree(map); | ||
| 291 | return -ENOMEM; | ||
| 292 | } | ||
| 293 | |||
| 294 | map->timeout = | ||
| 295 | ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | ||
| 296 | set->extensions |= IPSET_EXT_TIMEOUT; | ||
| 297 | bitmap_port_gc_init(set, bitmap_port_gc); | ||
| 298 | } else { | ||
| 299 | map->dsize = sizeof(struct bitmap_portc_elem); | ||
| 300 | map->offset[IPSET_OFFSET_COUNTER] = | ||
| 301 | offsetof(struct bitmap_portc_elem, counter); | ||
| 302 | if (!init_map_port(set, map, first_port, last_port)) { | ||
| 303 | kfree(map); | ||
| 304 | return -ENOMEM; | ||
| 305 | } | ||
| 306 | } | ||
| 307 | } else if (tb[IPSET_ATTR_TIMEOUT]) { | ||
| 308 | map->dsize = sizeof(struct bitmap_portt_elem); | ||
| 309 | map->offset[IPSET_OFFSET_TIMEOUT] = | ||
| 310 | offsetof(struct bitmap_portt_elem, timeout); | ||
| 311 | if (!init_map_port(set, map, first_port, last_port)) { | ||
| 312 | kfree(map); | ||
| 313 | return -ENOMEM; | ||
| 314 | } | ||
| 315 | |||
| 316 | map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | ||
| 317 | set->extensions |= IPSET_EXT_TIMEOUT; | ||
| 318 | bitmap_port_gc_init(set, bitmap_port_gc); | 266 | bitmap_port_gc_init(set, bitmap_port_gc); |
| 319 | } else { | ||
| 320 | map->dsize = 0; | ||
| 321 | if (!init_map_port(set, map, first_port, last_port)) { | ||
| 322 | kfree(map); | ||
| 323 | return -ENOMEM; | ||
| 324 | } | ||
| 325 | |||
| 326 | } | 267 | } |
| 327 | return 0; | 268 | return 0; |
| 328 | } | 269 | } |
| @@ -333,8 +274,8 @@ static struct ip_set_type bitmap_port_type = { | |||
| 333 | .features = IPSET_TYPE_PORT, | 274 | .features = IPSET_TYPE_PORT, |
| 334 | .dimension = IPSET_DIM_ONE, | 275 | .dimension = IPSET_DIM_ONE, |
| 335 | .family = NFPROTO_UNSPEC, | 276 | .family = NFPROTO_UNSPEC, |
| 336 | .revision_min = REVISION_MIN, | 277 | .revision_min = IPSET_TYPE_REV_MIN, |
| 337 | .revision_max = REVISION_MAX, | 278 | .revision_max = IPSET_TYPE_REV_MAX, |
| 338 | .create = bitmap_port_create, | 279 | .create = bitmap_port_create, |
| 339 | .create_policy = { | 280 | .create_policy = { |
| 340 | [IPSET_ATTR_PORT] = { .type = NLA_U16 }, | 281 | [IPSET_ATTR_PORT] = { .type = NLA_U16 }, |
| @@ -349,6 +290,7 @@ static struct ip_set_type bitmap_port_type = { | |||
| 349 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, | 290 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, |
| 350 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | 291 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, |
| 351 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | 292 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, |
| 293 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | ||
| 352 | }, | 294 | }, |
| 353 | .me = THIS_MODULE, | 295 | .me = THIS_MODULE, |
| 354 | }; | 296 | }; |
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index f2e30fb31e78..dc9284bdd2dd 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c | |||
| @@ -17,6 +17,8 @@ | |||
| 17 | #include <linux/spinlock.h> | 17 | #include <linux/spinlock.h> |
| 18 | #include <linux/rculist.h> | 18 | #include <linux/rculist.h> |
| 19 | #include <net/netlink.h> | 19 | #include <net/netlink.h> |
| 20 | #include <net/net_namespace.h> | ||
| 21 | #include <net/netns/generic.h> | ||
| 20 | 22 | ||
| 21 | #include <linux/netfilter.h> | 23 | #include <linux/netfilter.h> |
| 22 | #include <linux/netfilter/x_tables.h> | 24 | #include <linux/netfilter/x_tables.h> |
| @@ -27,8 +29,17 @@ static LIST_HEAD(ip_set_type_list); /* all registered set types */ | |||
| 27 | static DEFINE_MUTEX(ip_set_type_mutex); /* protects ip_set_type_list */ | 29 | static DEFINE_MUTEX(ip_set_type_mutex); /* protects ip_set_type_list */ |
| 28 | static DEFINE_RWLOCK(ip_set_ref_lock); /* protects the set refs */ | 30 | static DEFINE_RWLOCK(ip_set_ref_lock); /* protects the set refs */ |
| 29 | 31 | ||
| 30 | static struct ip_set * __rcu *ip_set_list; /* all individual sets */ | 32 | struct ip_set_net { |
| 31 | static ip_set_id_t ip_set_max = CONFIG_IP_SET_MAX; /* max number of sets */ | 33 | struct ip_set * __rcu *ip_set_list; /* all individual sets */ |
| 34 | ip_set_id_t ip_set_max; /* max number of sets */ | ||
| 35 | int is_deleted; /* deleted by ip_set_net_exit */ | ||
| 36 | }; | ||
| 37 | static int ip_set_net_id __read_mostly; | ||
| 38 | |||
| 39 | static inline struct ip_set_net *ip_set_pernet(struct net *net) | ||
| 40 | { | ||
| 41 | return net_generic(net, ip_set_net_id); | ||
| 42 | } | ||
| 32 | 43 | ||
| 33 | #define IP_SET_INC 64 | 44 | #define IP_SET_INC 64 |
| 34 | #define STREQ(a, b) (strncmp(a, b, IPSET_MAXNAMELEN) == 0) | 45 | #define STREQ(a, b) (strncmp(a, b, IPSET_MAXNAMELEN) == 0) |
| @@ -45,8 +56,8 @@ MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_IPSET); | |||
| 45 | /* When the nfnl mutex is held: */ | 56 | /* When the nfnl mutex is held: */ |
| 46 | #define nfnl_dereference(p) \ | 57 | #define nfnl_dereference(p) \ |
| 47 | rcu_dereference_protected(p, 1) | 58 | rcu_dereference_protected(p, 1) |
| 48 | #define nfnl_set(id) \ | 59 | #define nfnl_set(inst, id) \ |
| 49 | nfnl_dereference(ip_set_list)[id] | 60 | nfnl_dereference((inst)->ip_set_list)[id] |
| 50 | 61 | ||
| 51 | /* | 62 | /* |
| 52 | * The set types are implemented in modules and registered set types | 63 | * The set types are implemented in modules and registered set types |
| @@ -315,6 +326,60 @@ ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr) | |||
| 315 | } | 326 | } |
| 316 | EXPORT_SYMBOL_GPL(ip_set_get_ipaddr6); | 327 | EXPORT_SYMBOL_GPL(ip_set_get_ipaddr6); |
| 317 | 328 | ||
| 329 | typedef void (*destroyer)(void *); | ||
| 330 | /* ipset data extension types, in size order */ | ||
| 331 | |||
| 332 | const struct ip_set_ext_type ip_set_extensions[] = { | ||
| 333 | [IPSET_EXT_ID_COUNTER] = { | ||
| 334 | .type = IPSET_EXT_COUNTER, | ||
| 335 | .flag = IPSET_FLAG_WITH_COUNTERS, | ||
| 336 | .len = sizeof(struct ip_set_counter), | ||
| 337 | .align = __alignof__(struct ip_set_counter), | ||
| 338 | }, | ||
| 339 | [IPSET_EXT_ID_TIMEOUT] = { | ||
| 340 | .type = IPSET_EXT_TIMEOUT, | ||
| 341 | .len = sizeof(unsigned long), | ||
| 342 | .align = __alignof__(unsigned long), | ||
| 343 | }, | ||
| 344 | [IPSET_EXT_ID_COMMENT] = { | ||
| 345 | .type = IPSET_EXT_COMMENT | IPSET_EXT_DESTROY, | ||
| 346 | .flag = IPSET_FLAG_WITH_COMMENT, | ||
| 347 | .len = sizeof(struct ip_set_comment), | ||
| 348 | .align = __alignof__(struct ip_set_comment), | ||
| 349 | .destroy = (destroyer) ip_set_comment_free, | ||
| 350 | }, | ||
| 351 | }; | ||
| 352 | EXPORT_SYMBOL_GPL(ip_set_extensions); | ||
| 353 | |||
| 354 | static inline bool | ||
| 355 | add_extension(enum ip_set_ext_id id, u32 flags, struct nlattr *tb[]) | ||
| 356 | { | ||
| 357 | return ip_set_extensions[id].flag ? | ||
| 358 | (flags & ip_set_extensions[id].flag) : | ||
| 359 | !!tb[IPSET_ATTR_TIMEOUT]; | ||
| 360 | } | ||
| 361 | |||
| 362 | size_t | ||
| 363 | ip_set_elem_len(struct ip_set *set, struct nlattr *tb[], size_t len) | ||
| 364 | { | ||
| 365 | enum ip_set_ext_id id; | ||
| 366 | size_t offset = 0; | ||
| 367 | u32 cadt_flags = 0; | ||
| 368 | |||
| 369 | if (tb[IPSET_ATTR_CADT_FLAGS]) | ||
| 370 | cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); | ||
| 371 | for (id = 0; id < IPSET_EXT_ID_MAX; id++) { | ||
| 372 | if (!add_extension(id, cadt_flags, tb)) | ||
| 373 | continue; | ||
| 374 | offset += ALIGN(len + offset, ip_set_extensions[id].align); | ||
| 375 | set->offset[id] = offset; | ||
| 376 | set->extensions |= ip_set_extensions[id].type; | ||
| 377 | offset += ip_set_extensions[id].len; | ||
| 378 | } | ||
| 379 | return len + offset; | ||
| 380 | } | ||
| 381 | EXPORT_SYMBOL_GPL(ip_set_elem_len); | ||
| 382 | |||
| 318 | int | 383 | int |
| 319 | ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[], | 384 | ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[], |
| 320 | struct ip_set_ext *ext) | 385 | struct ip_set_ext *ext) |
| @@ -334,6 +399,12 @@ ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[], | |||
| 334 | ext->packets = be64_to_cpu(nla_get_be64( | 399 | ext->packets = be64_to_cpu(nla_get_be64( |
| 335 | tb[IPSET_ATTR_PACKETS])); | 400 | tb[IPSET_ATTR_PACKETS])); |
| 336 | } | 401 | } |
| 402 | if (tb[IPSET_ATTR_COMMENT]) { | ||
| 403 | if (!(set->extensions & IPSET_EXT_COMMENT)) | ||
| 404 | return -IPSET_ERR_COMMENT; | ||
| 405 | ext->comment = ip_set_comment_uget(tb[IPSET_ATTR_COMMENT]); | ||
| 406 | } | ||
| 407 | |||
| 337 | return 0; | 408 | return 0; |
| 338 | } | 409 | } |
| 339 | EXPORT_SYMBOL_GPL(ip_set_get_extensions); | 410 | EXPORT_SYMBOL_GPL(ip_set_get_extensions); |
| @@ -374,13 +445,14 @@ __ip_set_put(struct ip_set *set) | |||
| 374 | */ | 445 | */ |
| 375 | 446 | ||
| 376 | static inline struct ip_set * | 447 | static inline struct ip_set * |
| 377 | ip_set_rcu_get(ip_set_id_t index) | 448 | ip_set_rcu_get(struct net *net, ip_set_id_t index) |
| 378 | { | 449 | { |
| 379 | struct ip_set *set; | 450 | struct ip_set *set; |
| 451 | struct ip_set_net *inst = ip_set_pernet(net); | ||
| 380 | 452 | ||
| 381 | rcu_read_lock(); | 453 | rcu_read_lock(); |
| 382 | /* ip_set_list itself needs to be protected */ | 454 | /* ip_set_list itself needs to be protected */ |
| 383 | set = rcu_dereference(ip_set_list)[index]; | 455 | set = rcu_dereference(inst->ip_set_list)[index]; |
| 384 | rcu_read_unlock(); | 456 | rcu_read_unlock(); |
| 385 | 457 | ||
| 386 | return set; | 458 | return set; |
| @@ -390,7 +462,8 @@ int | |||
| 390 | ip_set_test(ip_set_id_t index, const struct sk_buff *skb, | 462 | ip_set_test(ip_set_id_t index, const struct sk_buff *skb, |
| 391 | const struct xt_action_param *par, struct ip_set_adt_opt *opt) | 463 | const struct xt_action_param *par, struct ip_set_adt_opt *opt) |
| 392 | { | 464 | { |
| 393 | struct ip_set *set = ip_set_rcu_get(index); | 465 | struct ip_set *set = ip_set_rcu_get( |
| 466 | dev_net(par->in ? par->in : par->out), index); | ||
| 394 | int ret = 0; | 467 | int ret = 0; |
| 395 | 468 | ||
| 396 | BUG_ON(set == NULL); | 469 | BUG_ON(set == NULL); |
| @@ -428,7 +501,8 @@ int | |||
| 428 | ip_set_add(ip_set_id_t index, const struct sk_buff *skb, | 501 | ip_set_add(ip_set_id_t index, const struct sk_buff *skb, |
| 429 | const struct xt_action_param *par, struct ip_set_adt_opt *opt) | 502 | const struct xt_action_param *par, struct ip_set_adt_opt *opt) |
| 430 | { | 503 | { |
| 431 | struct ip_set *set = ip_set_rcu_get(index); | 504 | struct ip_set *set = ip_set_rcu_get( |
| 505 | dev_net(par->in ? par->in : par->out), index); | ||
| 432 | int ret; | 506 | int ret; |
| 433 | 507 | ||
| 434 | BUG_ON(set == NULL); | 508 | BUG_ON(set == NULL); |
| @@ -450,7 +524,8 @@ int | |||
| 450 | ip_set_del(ip_set_id_t index, const struct sk_buff *skb, | 524 | ip_set_del(ip_set_id_t index, const struct sk_buff *skb, |
| 451 | const struct xt_action_param *par, struct ip_set_adt_opt *opt) | 525 | const struct xt_action_param *par, struct ip_set_adt_opt *opt) |
| 452 | { | 526 | { |
| 453 | struct ip_set *set = ip_set_rcu_get(index); | 527 | struct ip_set *set = ip_set_rcu_get( |
| 528 | dev_net(par->in ? par->in : par->out), index); | ||
| 454 | int ret = 0; | 529 | int ret = 0; |
| 455 | 530 | ||
| 456 | BUG_ON(set == NULL); | 531 | BUG_ON(set == NULL); |
| @@ -474,14 +549,15 @@ EXPORT_SYMBOL_GPL(ip_set_del); | |||
| 474 | * | 549 | * |
| 475 | */ | 550 | */ |
| 476 | ip_set_id_t | 551 | ip_set_id_t |
| 477 | ip_set_get_byname(const char *name, struct ip_set **set) | 552 | ip_set_get_byname(struct net *net, const char *name, struct ip_set **set) |
| 478 | { | 553 | { |
| 479 | ip_set_id_t i, index = IPSET_INVALID_ID; | 554 | ip_set_id_t i, index = IPSET_INVALID_ID; |
| 480 | struct ip_set *s; | 555 | struct ip_set *s; |
| 556 | struct ip_set_net *inst = ip_set_pernet(net); | ||
| 481 | 557 | ||
| 482 | rcu_read_lock(); | 558 | rcu_read_lock(); |
| 483 | for (i = 0; i < ip_set_max; i++) { | 559 | for (i = 0; i < inst->ip_set_max; i++) { |
| 484 | s = rcu_dereference(ip_set_list)[i]; | 560 | s = rcu_dereference(inst->ip_set_list)[i]; |
| 485 | if (s != NULL && STREQ(s->name, name)) { | 561 | if (s != NULL && STREQ(s->name, name)) { |
| 486 | __ip_set_get(s); | 562 | __ip_set_get(s); |
| 487 | index = i; | 563 | index = i; |
| @@ -501,17 +577,26 @@ EXPORT_SYMBOL_GPL(ip_set_get_byname); | |||
| 501 | * to be valid, after calling this function. | 577 | * to be valid, after calling this function. |
| 502 | * | 578 | * |
| 503 | */ | 579 | */ |
| 504 | void | 580 | |
| 505 | ip_set_put_byindex(ip_set_id_t index) | 581 | static inline void |
| 582 | __ip_set_put_byindex(struct ip_set_net *inst, ip_set_id_t index) | ||
| 506 | { | 583 | { |
| 507 | struct ip_set *set; | 584 | struct ip_set *set; |
| 508 | 585 | ||
| 509 | rcu_read_lock(); | 586 | rcu_read_lock(); |
| 510 | set = rcu_dereference(ip_set_list)[index]; | 587 | set = rcu_dereference(inst->ip_set_list)[index]; |
| 511 | if (set != NULL) | 588 | if (set != NULL) |
| 512 | __ip_set_put(set); | 589 | __ip_set_put(set); |
| 513 | rcu_read_unlock(); | 590 | rcu_read_unlock(); |
| 514 | } | 591 | } |
| 592 | |||
| 593 | void | ||
| 594 | ip_set_put_byindex(struct net *net, ip_set_id_t index) | ||
| 595 | { | ||
| 596 | struct ip_set_net *inst = ip_set_pernet(net); | ||
| 597 | |||
| 598 | __ip_set_put_byindex(inst, index); | ||
| 599 | } | ||
| 515 | EXPORT_SYMBOL_GPL(ip_set_put_byindex); | 600 | EXPORT_SYMBOL_GPL(ip_set_put_byindex); |
| 516 | 601 | ||
| 517 | /* | 602 | /* |
| @@ -522,9 +607,9 @@ EXPORT_SYMBOL_GPL(ip_set_put_byindex); | |||
| 522 | * | 607 | * |
| 523 | */ | 608 | */ |
| 524 | const char * | 609 | const char * |
| 525 | ip_set_name_byindex(ip_set_id_t index) | 610 | ip_set_name_byindex(struct net *net, ip_set_id_t index) |
| 526 | { | 611 | { |
| 527 | const struct ip_set *set = ip_set_rcu_get(index); | 612 | const struct ip_set *set = ip_set_rcu_get(net, index); |
| 528 | 613 | ||
| 529 | BUG_ON(set == NULL); | 614 | BUG_ON(set == NULL); |
| 530 | BUG_ON(set->ref == 0); | 615 | BUG_ON(set->ref == 0); |
| @@ -546,14 +631,15 @@ EXPORT_SYMBOL_GPL(ip_set_name_byindex); | |||
| 546 | * The nfnl mutex is used in the function. | 631 | * The nfnl mutex is used in the function. |
| 547 | */ | 632 | */ |
| 548 | ip_set_id_t | 633 | ip_set_id_t |
| 549 | ip_set_nfnl_get(const char *name) | 634 | ip_set_nfnl_get(struct net *net, const char *name) |
| 550 | { | 635 | { |
| 551 | ip_set_id_t i, index = IPSET_INVALID_ID; | 636 | ip_set_id_t i, index = IPSET_INVALID_ID; |
| 552 | struct ip_set *s; | 637 | struct ip_set *s; |
| 638 | struct ip_set_net *inst = ip_set_pernet(net); | ||
| 553 | 639 | ||
| 554 | nfnl_lock(NFNL_SUBSYS_IPSET); | 640 | nfnl_lock(NFNL_SUBSYS_IPSET); |
| 555 | for (i = 0; i < ip_set_max; i++) { | 641 | for (i = 0; i < inst->ip_set_max; i++) { |
| 556 | s = nfnl_set(i); | 642 | s = nfnl_set(inst, i); |
| 557 | if (s != NULL && STREQ(s->name, name)) { | 643 | if (s != NULL && STREQ(s->name, name)) { |
| 558 | __ip_set_get(s); | 644 | __ip_set_get(s); |
| 559 | index = i; | 645 | index = i; |
| @@ -573,15 +659,16 @@ EXPORT_SYMBOL_GPL(ip_set_nfnl_get); | |||
| 573 | * The nfnl mutex is used in the function. | 659 | * The nfnl mutex is used in the function. |
| 574 | */ | 660 | */ |
| 575 | ip_set_id_t | 661 | ip_set_id_t |
| 576 | ip_set_nfnl_get_byindex(ip_set_id_t index) | 662 | ip_set_nfnl_get_byindex(struct net *net, ip_set_id_t index) |
| 577 | { | 663 | { |
| 578 | struct ip_set *set; | 664 | struct ip_set *set; |
| 665 | struct ip_set_net *inst = ip_set_pernet(net); | ||
| 579 | 666 | ||
| 580 | if (index > ip_set_max) | 667 | if (index > inst->ip_set_max) |
| 581 | return IPSET_INVALID_ID; | 668 | return IPSET_INVALID_ID; |
| 582 | 669 | ||
| 583 | nfnl_lock(NFNL_SUBSYS_IPSET); | 670 | nfnl_lock(NFNL_SUBSYS_IPSET); |
| 584 | set = nfnl_set(index); | 671 | set = nfnl_set(inst, index); |
| 585 | if (set) | 672 | if (set) |
| 586 | __ip_set_get(set); | 673 | __ip_set_get(set); |
| 587 | else | 674 | else |
| @@ -600,13 +687,17 @@ EXPORT_SYMBOL_GPL(ip_set_nfnl_get_byindex); | |||
| 600 | * The nfnl mutex is used in the function. | 687 | * The nfnl mutex is used in the function. |
| 601 | */ | 688 | */ |
| 602 | void | 689 | void |
| 603 | ip_set_nfnl_put(ip_set_id_t index) | 690 | ip_set_nfnl_put(struct net *net, ip_set_id_t index) |
| 604 | { | 691 | { |
| 605 | struct ip_set *set; | 692 | struct ip_set *set; |
| 693 | struct ip_set_net *inst = ip_set_pernet(net); | ||
| 694 | |||
| 606 | nfnl_lock(NFNL_SUBSYS_IPSET); | 695 | nfnl_lock(NFNL_SUBSYS_IPSET); |
| 607 | set = nfnl_set(index); | 696 | if (!inst->is_deleted) { /* already deleted from ip_set_net_exit() */ |
| 608 | if (set != NULL) | 697 | set = nfnl_set(inst, index); |
| 609 | __ip_set_put(set); | 698 | if (set != NULL) |
| 699 | __ip_set_put(set); | ||
| 700 | } | ||
| 610 | nfnl_unlock(NFNL_SUBSYS_IPSET); | 701 | nfnl_unlock(NFNL_SUBSYS_IPSET); |
| 611 | } | 702 | } |
| 612 | EXPORT_SYMBOL_GPL(ip_set_nfnl_put); | 703 | EXPORT_SYMBOL_GPL(ip_set_nfnl_put); |
| @@ -664,14 +755,14 @@ static const struct nla_policy ip_set_create_policy[IPSET_ATTR_CMD_MAX + 1] = { | |||
| 664 | }; | 755 | }; |
| 665 | 756 | ||
| 666 | static struct ip_set * | 757 | static struct ip_set * |
| 667 | find_set_and_id(const char *name, ip_set_id_t *id) | 758 | find_set_and_id(struct ip_set_net *inst, const char *name, ip_set_id_t *id) |
| 668 | { | 759 | { |
| 669 | struct ip_set *set = NULL; | 760 | struct ip_set *set = NULL; |
| 670 | ip_set_id_t i; | 761 | ip_set_id_t i; |
| 671 | 762 | ||
| 672 | *id = IPSET_INVALID_ID; | 763 | *id = IPSET_INVALID_ID; |
| 673 | for (i = 0; i < ip_set_max; i++) { | 764 | for (i = 0; i < inst->ip_set_max; i++) { |
| 674 | set = nfnl_set(i); | 765 | set = nfnl_set(inst, i); |
| 675 | if (set != NULL && STREQ(set->name, name)) { | 766 | if (set != NULL && STREQ(set->name, name)) { |
| 676 | *id = i; | 767 | *id = i; |
| 677 | break; | 768 | break; |
| @@ -681,22 +772,23 @@ find_set_and_id(const char *name, ip_set_id_t *id) | |||
| 681 | } | 772 | } |
| 682 | 773 | ||
| 683 | static inline struct ip_set * | 774 | static inline struct ip_set * |
| 684 | find_set(const char *name) | 775 | find_set(struct ip_set_net *inst, const char *name) |
| 685 | { | 776 | { |
| 686 | ip_set_id_t id; | 777 | ip_set_id_t id; |
| 687 | 778 | ||
| 688 | return find_set_and_id(name, &id); | 779 | return find_set_and_id(inst, name, &id); |
| 689 | } | 780 | } |
| 690 | 781 | ||
| 691 | static int | 782 | static int |
| 692 | find_free_id(const char *name, ip_set_id_t *index, struct ip_set **set) | 783 | find_free_id(struct ip_set_net *inst, const char *name, ip_set_id_t *index, |
| 784 | struct ip_set **set) | ||
| 693 | { | 785 | { |
| 694 | struct ip_set *s; | 786 | struct ip_set *s; |
| 695 | ip_set_id_t i; | 787 | ip_set_id_t i; |
| 696 | 788 | ||
| 697 | *index = IPSET_INVALID_ID; | 789 | *index = IPSET_INVALID_ID; |
| 698 | for (i = 0; i < ip_set_max; i++) { | 790 | for (i = 0; i < inst->ip_set_max; i++) { |
| 699 | s = nfnl_set(i); | 791 | s = nfnl_set(inst, i); |
| 700 | if (s == NULL) { | 792 | if (s == NULL) { |
| 701 | if (*index == IPSET_INVALID_ID) | 793 | if (*index == IPSET_INVALID_ID) |
| 702 | *index = i; | 794 | *index = i; |
| @@ -725,6 +817,8 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb, | |||
| 725 | const struct nlmsghdr *nlh, | 817 | const struct nlmsghdr *nlh, |
| 726 | const struct nlattr * const attr[]) | 818 | const struct nlattr * const attr[]) |
| 727 | { | 819 | { |
| 820 | struct net *net = sock_net(ctnl); | ||
| 821 | struct ip_set_net *inst = ip_set_pernet(net); | ||
| 728 | struct ip_set *set, *clash = NULL; | 822 | struct ip_set *set, *clash = NULL; |
| 729 | ip_set_id_t index = IPSET_INVALID_ID; | 823 | ip_set_id_t index = IPSET_INVALID_ID; |
| 730 | struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1] = {}; | 824 | struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1] = {}; |
| @@ -783,7 +877,7 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb, | |||
| 783 | goto put_out; | 877 | goto put_out; |
| 784 | } | 878 | } |
| 785 | 879 | ||
| 786 | ret = set->type->create(set, tb, flags); | 880 | ret = set->type->create(net, set, tb, flags); |
| 787 | if (ret != 0) | 881 | if (ret != 0) |
| 788 | goto put_out; | 882 | goto put_out; |
| 789 | 883 | ||
| @@ -794,7 +888,7 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb, | |||
| 794 | * by the nfnl mutex. Find the first free index in ip_set_list | 888 | * by the nfnl mutex. Find the first free index in ip_set_list |
| 795 | * and check clashing. | 889 | * and check clashing. |
| 796 | */ | 890 | */ |
| 797 | ret = find_free_id(set->name, &index, &clash); | 891 | ret = find_free_id(inst, set->name, &index, &clash); |
| 798 | if (ret == -EEXIST) { | 892 | if (ret == -EEXIST) { |
| 799 | /* If this is the same set and requested, ignore error */ | 893 | /* If this is the same set and requested, ignore error */ |
| 800 | if ((flags & IPSET_FLAG_EXIST) && | 894 | if ((flags & IPSET_FLAG_EXIST) && |
| @@ -807,9 +901,9 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb, | |||
| 807 | goto cleanup; | 901 | goto cleanup; |
| 808 | } else if (ret == -IPSET_ERR_MAX_SETS) { | 902 | } else if (ret == -IPSET_ERR_MAX_SETS) { |
| 809 | struct ip_set **list, **tmp; | 903 | struct ip_set **list, **tmp; |
| 810 | ip_set_id_t i = ip_set_max + IP_SET_INC; | 904 | ip_set_id_t i = inst->ip_set_max + IP_SET_INC; |
| 811 | 905 | ||
| 812 | if (i < ip_set_max || i == IPSET_INVALID_ID) | 906 | if (i < inst->ip_set_max || i == IPSET_INVALID_ID) |
| 813 | /* Wraparound */ | 907 | /* Wraparound */ |
| 814 | goto cleanup; | 908 | goto cleanup; |
| 815 | 909 | ||
| @@ -817,14 +911,14 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb, | |||
| 817 | if (!list) | 911 | if (!list) |
| 818 | goto cleanup; | 912 | goto cleanup; |
| 819 | /* nfnl mutex is held, both lists are valid */ | 913 | /* nfnl mutex is held, both lists are valid */ |
| 820 | tmp = nfnl_dereference(ip_set_list); | 914 | tmp = nfnl_dereference(inst->ip_set_list); |
| 821 | memcpy(list, tmp, sizeof(struct ip_set *) * ip_set_max); | 915 | memcpy(list, tmp, sizeof(struct ip_set *) * inst->ip_set_max); |
| 822 | rcu_assign_pointer(ip_set_list, list); | 916 | rcu_assign_pointer(inst->ip_set_list, list); |
| 823 | /* Make sure all current packets have passed through */ | 917 | /* Make sure all current packets have passed through */ |
| 824 | synchronize_net(); | 918 | synchronize_net(); |
| 825 | /* Use new list */ | 919 | /* Use new list */ |
| 826 | index = ip_set_max; | 920 | index = inst->ip_set_max; |
| 827 | ip_set_max = i; | 921 | inst->ip_set_max = i; |
| 828 | kfree(tmp); | 922 | kfree(tmp); |
| 829 | ret = 0; | 923 | ret = 0; |
| 830 | } else if (ret) | 924 | } else if (ret) |
| @@ -834,7 +928,7 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb, | |||
| 834 | * Finally! Add our shiny new set to the list, and be done. | 928 | * Finally! Add our shiny new set to the list, and be done. |
| 835 | */ | 929 | */ |
| 836 | pr_debug("create: '%s' created with index %u!\n", set->name, index); | 930 | pr_debug("create: '%s' created with index %u!\n", set->name, index); |
| 837 | nfnl_set(index) = set; | 931 | nfnl_set(inst, index) = set; |
| 838 | 932 | ||
| 839 | return ret; | 933 | return ret; |
| 840 | 934 | ||
| @@ -857,12 +951,12 @@ ip_set_setname_policy[IPSET_ATTR_CMD_MAX + 1] = { | |||
| 857 | }; | 951 | }; |
| 858 | 952 | ||
| 859 | static void | 953 | static void |
| 860 | ip_set_destroy_set(ip_set_id_t index) | 954 | ip_set_destroy_set(struct ip_set_net *inst, ip_set_id_t index) |
| 861 | { | 955 | { |
| 862 | struct ip_set *set = nfnl_set(index); | 956 | struct ip_set *set = nfnl_set(inst, index); |
| 863 | 957 | ||
| 864 | pr_debug("set: %s\n", set->name); | 958 | pr_debug("set: %s\n", set->name); |
| 865 | nfnl_set(index) = NULL; | 959 | nfnl_set(inst, index) = NULL; |
| 866 | 960 | ||
| 867 | /* Must call it without holding any lock */ | 961 | /* Must call it without holding any lock */ |
| 868 | set->variant->destroy(set); | 962 | set->variant->destroy(set); |
| @@ -875,6 +969,7 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb, | |||
| 875 | const struct nlmsghdr *nlh, | 969 | const struct nlmsghdr *nlh, |
| 876 | const struct nlattr * const attr[]) | 970 | const struct nlattr * const attr[]) |
| 877 | { | 971 | { |
| 972 | struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl)); | ||
| 878 | struct ip_set *s; | 973 | struct ip_set *s; |
| 879 | ip_set_id_t i; | 974 | ip_set_id_t i; |
| 880 | int ret = 0; | 975 | int ret = 0; |
| @@ -894,21 +989,22 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb, | |||
| 894 | */ | 989 | */ |
| 895 | read_lock_bh(&ip_set_ref_lock); | 990 | read_lock_bh(&ip_set_ref_lock); |
| 896 | if (!attr[IPSET_ATTR_SETNAME]) { | 991 | if (!attr[IPSET_ATTR_SETNAME]) { |
| 897 | for (i = 0; i < ip_set_max; i++) { | 992 | for (i = 0; i < inst->ip_set_max; i++) { |
| 898 | s = nfnl_set(i); | 993 | s = nfnl_set(inst, i); |
| 899 | if (s != NULL && s->ref) { | 994 | if (s != NULL && s->ref) { |
| 900 | ret = -IPSET_ERR_BUSY; | 995 | ret = -IPSET_ERR_BUSY; |
| 901 | goto out; | 996 | goto out; |
| 902 | } | 997 | } |
| 903 | } | 998 | } |
| 904 | read_unlock_bh(&ip_set_ref_lock); | 999 | read_unlock_bh(&ip_set_ref_lock); |
| 905 | for (i = 0; i < ip_set_max; i++) { | 1000 | for (i = 0; i < inst->ip_set_max; i++) { |
| 906 | s = nfnl_set(i); | 1001 | s = nfnl_set(inst, i); |
| 907 | if (s != NULL) | 1002 | if (s != NULL) |
| 908 | ip_set_destroy_set(i); | 1003 | ip_set_destroy_set(inst, i); |
| 909 | } | 1004 | } |
| 910 | } else { | 1005 | } else { |
| 911 | s = find_set_and_id(nla_data(attr[IPSET_ATTR_SETNAME]), &i); | 1006 | s = find_set_and_id(inst, nla_data(attr[IPSET_ATTR_SETNAME]), |
| 1007 | &i); | ||
| 912 | if (s == NULL) { | 1008 | if (s == NULL) { |
| 913 | ret = -ENOENT; | 1009 | ret = -ENOENT; |
| 914 | goto out; | 1010 | goto out; |
| @@ -918,7 +1014,7 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb, | |||
| 918 | } | 1014 | } |
| 919 | read_unlock_bh(&ip_set_ref_lock); | 1015 | read_unlock_bh(&ip_set_ref_lock); |
| 920 | 1016 | ||
| 921 | ip_set_destroy_set(i); | 1017 | ip_set_destroy_set(inst, i); |
| 922 | } | 1018 | } |
| 923 | return 0; | 1019 | return 0; |
| 924 | out: | 1020 | out: |
| @@ -943,6 +1039,7 @@ ip_set_flush(struct sock *ctnl, struct sk_buff *skb, | |||
| 943 | const struct nlmsghdr *nlh, | 1039 | const struct nlmsghdr *nlh, |
| 944 | const struct nlattr * const attr[]) | 1040 | const struct nlattr * const attr[]) |
| 945 | { | 1041 | { |
| 1042 | struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl)); | ||
| 946 | struct ip_set *s; | 1043 | struct ip_set *s; |
| 947 | ip_set_id_t i; | 1044 | ip_set_id_t i; |
| 948 | 1045 | ||
| @@ -950,13 +1047,13 @@ ip_set_flush(struct sock *ctnl, struct sk_buff *skb, | |||
| 950 | return -IPSET_ERR_PROTOCOL; | 1047 | return -IPSET_ERR_PROTOCOL; |
| 951 | 1048 | ||
| 952 | if (!attr[IPSET_ATTR_SETNAME]) { | 1049 | if (!attr[IPSET_ATTR_SETNAME]) { |
| 953 | for (i = 0; i < ip_set_max; i++) { | 1050 | for (i = 0; i < inst->ip_set_max; i++) { |
| 954 | s = nfnl_set(i); | 1051 | s = nfnl_set(inst, i); |
| 955 | if (s != NULL) | 1052 | if (s != NULL) |
| 956 | ip_set_flush_set(s); | 1053 | ip_set_flush_set(s); |
| 957 | } | 1054 | } |
| 958 | } else { | 1055 | } else { |
| 959 | s = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); | 1056 | s = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME])); |
| 960 | if (s == NULL) | 1057 | if (s == NULL) |
| 961 | return -ENOENT; | 1058 | return -ENOENT; |
| 962 | 1059 | ||
| @@ -982,6 +1079,7 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb, | |||
| 982 | const struct nlmsghdr *nlh, | 1079 | const struct nlmsghdr *nlh, |
| 983 | const struct nlattr * const attr[]) | 1080 | const struct nlattr * const attr[]) |
| 984 | { | 1081 | { |
| 1082 | struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl)); | ||
| 985 | struct ip_set *set, *s; | 1083 | struct ip_set *set, *s; |
| 986 | const char *name2; | 1084 | const char *name2; |
| 987 | ip_set_id_t i; | 1085 | ip_set_id_t i; |
| @@ -992,7 +1090,7 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb, | |||
| 992 | attr[IPSET_ATTR_SETNAME2] == NULL)) | 1090 | attr[IPSET_ATTR_SETNAME2] == NULL)) |
| 993 | return -IPSET_ERR_PROTOCOL; | 1091 | return -IPSET_ERR_PROTOCOL; |
| 994 | 1092 | ||
| 995 | set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); | 1093 | set = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME])); |
| 996 | if (set == NULL) | 1094 | if (set == NULL) |
| 997 | return -ENOENT; | 1095 | return -ENOENT; |
| 998 | 1096 | ||
| @@ -1003,8 +1101,8 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb, | |||
| 1003 | } | 1101 | } |
| 1004 | 1102 | ||
| 1005 | name2 = nla_data(attr[IPSET_ATTR_SETNAME2]); | 1103 | name2 = nla_data(attr[IPSET_ATTR_SETNAME2]); |
| 1006 | for (i = 0; i < ip_set_max; i++) { | 1104 | for (i = 0; i < inst->ip_set_max; i++) { |
| 1007 | s = nfnl_set(i); | 1105 | s = nfnl_set(inst, i); |
| 1008 | if (s != NULL && STREQ(s->name, name2)) { | 1106 | if (s != NULL && STREQ(s->name, name2)) { |
| 1009 | ret = -IPSET_ERR_EXIST_SETNAME2; | 1107 | ret = -IPSET_ERR_EXIST_SETNAME2; |
| 1010 | goto out; | 1108 | goto out; |
| @@ -1031,6 +1129,7 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb, | |||
| 1031 | const struct nlmsghdr *nlh, | 1129 | const struct nlmsghdr *nlh, |
| 1032 | const struct nlattr * const attr[]) | 1130 | const struct nlattr * const attr[]) |
| 1033 | { | 1131 | { |
| 1132 | struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl)); | ||
| 1034 | struct ip_set *from, *to; | 1133 | struct ip_set *from, *to; |
| 1035 | ip_set_id_t from_id, to_id; | 1134 | ip_set_id_t from_id, to_id; |
| 1036 | char from_name[IPSET_MAXNAMELEN]; | 1135 | char from_name[IPSET_MAXNAMELEN]; |
| @@ -1040,11 +1139,13 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb, | |||
| 1040 | attr[IPSET_ATTR_SETNAME2] == NULL)) | 1139 | attr[IPSET_ATTR_SETNAME2] == NULL)) |
| 1041 | return -IPSET_ERR_PROTOCOL; | 1140 | return -IPSET_ERR_PROTOCOL; |
| 1042 | 1141 | ||
| 1043 | from = find_set_and_id(nla_data(attr[IPSET_ATTR_SETNAME]), &from_id); | 1142 | from = find_set_and_id(inst, nla_data(attr[IPSET_ATTR_SETNAME]), |
| 1143 | &from_id); | ||
| 1044 | if (from == NULL) | 1144 | if (from == NULL) |
| 1045 | return -ENOENT; | 1145 | return -ENOENT; |
| 1046 | 1146 | ||
| 1047 | to = find_set_and_id(nla_data(attr[IPSET_ATTR_SETNAME2]), &to_id); | 1147 | to = find_set_and_id(inst, nla_data(attr[IPSET_ATTR_SETNAME2]), |
| 1148 | &to_id); | ||
| 1048 | if (to == NULL) | 1149 | if (to == NULL) |
| 1049 | return -IPSET_ERR_EXIST_SETNAME2; | 1150 | return -IPSET_ERR_EXIST_SETNAME2; |
| 1050 | 1151 | ||
| @@ -1061,8 +1162,8 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb, | |||
| 1061 | 1162 | ||
| 1062 | write_lock_bh(&ip_set_ref_lock); | 1163 | write_lock_bh(&ip_set_ref_lock); |
| 1063 | swap(from->ref, to->ref); | 1164 | swap(from->ref, to->ref); |
| 1064 | nfnl_set(from_id) = to; | 1165 | nfnl_set(inst, from_id) = to; |
| 1065 | nfnl_set(to_id) = from; | 1166 | nfnl_set(inst, to_id) = from; |
| 1066 | write_unlock_bh(&ip_set_ref_lock); | 1167 | write_unlock_bh(&ip_set_ref_lock); |
| 1067 | 1168 | ||
| 1068 | return 0; | 1169 | return 0; |
| @@ -1081,9 +1182,10 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb, | |||
| 1081 | static int | 1182 | static int |
| 1082 | ip_set_dump_done(struct netlink_callback *cb) | 1183 | ip_set_dump_done(struct netlink_callback *cb) |
| 1083 | { | 1184 | { |
| 1185 | struct ip_set_net *inst = (struct ip_set_net *)cb->data; | ||
| 1084 | if (cb->args[2]) { | 1186 | if (cb->args[2]) { |
| 1085 | pr_debug("release set %s\n", nfnl_set(cb->args[1])->name); | 1187 | pr_debug("release set %s\n", nfnl_set(inst, cb->args[1])->name); |
| 1086 | ip_set_put_byindex((ip_set_id_t) cb->args[1]); | 1188 | __ip_set_put_byindex(inst, (ip_set_id_t) cb->args[1]); |
| 1087 | } | 1189 | } |
| 1088 | return 0; | 1190 | return 0; |
| 1089 | } | 1191 | } |
| @@ -1109,6 +1211,7 @@ dump_init(struct netlink_callback *cb) | |||
| 1109 | struct nlattr *attr = (void *)nlh + min_len; | 1211 | struct nlattr *attr = (void *)nlh + min_len; |
| 1110 | u32 dump_type; | 1212 | u32 dump_type; |
| 1111 | ip_set_id_t index; | 1213 | ip_set_id_t index; |
| 1214 | struct ip_set_net *inst = (struct ip_set_net *)cb->data; | ||
| 1112 | 1215 | ||
| 1113 | /* Second pass, so parser can't fail */ | 1216 | /* Second pass, so parser can't fail */ |
| 1114 | nla_parse(cda, IPSET_ATTR_CMD_MAX, | 1217 | nla_parse(cda, IPSET_ATTR_CMD_MAX, |
| @@ -1122,7 +1225,7 @@ dump_init(struct netlink_callback *cb) | |||
| 1122 | if (cda[IPSET_ATTR_SETNAME]) { | 1225 | if (cda[IPSET_ATTR_SETNAME]) { |
| 1123 | struct ip_set *set; | 1226 | struct ip_set *set; |
| 1124 | 1227 | ||
| 1125 | set = find_set_and_id(nla_data(cda[IPSET_ATTR_SETNAME]), | 1228 | set = find_set_and_id(inst, nla_data(cda[IPSET_ATTR_SETNAME]), |
| 1126 | &index); | 1229 | &index); |
| 1127 | if (set == NULL) | 1230 | if (set == NULL) |
| 1128 | return -ENOENT; | 1231 | return -ENOENT; |
| @@ -1150,6 +1253,7 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 1150 | unsigned int flags = NETLINK_CB(cb->skb).portid ? NLM_F_MULTI : 0; | 1253 | unsigned int flags = NETLINK_CB(cb->skb).portid ? NLM_F_MULTI : 0; |
| 1151 | u32 dump_type, dump_flags; | 1254 | u32 dump_type, dump_flags; |
| 1152 | int ret = 0; | 1255 | int ret = 0; |
| 1256 | struct ip_set_net *inst = (struct ip_set_net *)cb->data; | ||
| 1153 | 1257 | ||
| 1154 | if (!cb->args[0]) { | 1258 | if (!cb->args[0]) { |
| 1155 | ret = dump_init(cb); | 1259 | ret = dump_init(cb); |
| @@ -1163,18 +1267,18 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb) | |||
| 1163 | } | 1267 | } |
| 1164 | } | 1268 | } |
| 1165 | 1269 | ||
| 1166 | if (cb->args[1] >= ip_set_max) | 1270 | if (cb->args[1] >= inst->ip_set_max) |
| 1167 | goto out; | 1271 | goto out; |
| 1168 | 1272 | ||
| 1169 | dump_type = DUMP_TYPE(cb->args[0]); | 1273 | dump_type = DUMP_TYPE(cb->args[0]); |
| 1170 | dump_flags = DUMP_FLAGS(cb->args[0]); | 1274 | dump_flags = DUMP_FLAGS(cb->args[0]); |
| 1171 | max = dump_type == DUMP_ONE ? cb->args[1] + 1 : ip_set_max; | 1275 | max = dump_type == DUMP_ONE ? cb->args[1] + 1 : inst->ip_set_max; |
| 1172 | dump_last: | 1276 | dump_last: |
| 1173 | pr_debug("args[0]: %u %u args[1]: %ld\n", | 1277 | pr_debug("args[0]: %u %u args[1]: %ld\n", |
| 1174 | dump_type, dump_flags, cb->args[1]); | 1278 | dump_type, dump_flags, cb->args[1]); |
| 1175 | for (; cb->args[1] < max; cb->args[1]++) { | 1279 | for (; cb->args[1] < max; cb->args[1]++) { |
| 1176 | index = (ip_set_id_t) cb->args[1]; | 1280 | index = (ip_set_id_t) cb->args[1]; |
| 1177 | set = nfnl_set(index); | 1281 | set = nfnl_set(inst, index); |
| 1178 | if (set == NULL) { | 1282 | if (set == NULL) { |
| 1179 | if (dump_type == DUMP_ONE) { | 1283 | if (dump_type == DUMP_ONE) { |
| 1180 | ret = -ENOENT; | 1284 | ret = -ENOENT; |
| @@ -1252,8 +1356,8 @@ next_set: | |||
| 1252 | release_refcount: | 1356 | release_refcount: |
| 1253 | /* If there was an error or set is done, release set */ | 1357 | /* If there was an error or set is done, release set */ |
| 1254 | if (ret || !cb->args[2]) { | 1358 | if (ret || !cb->args[2]) { |
| 1255 | pr_debug("release set %s\n", nfnl_set(index)->name); | 1359 | pr_debug("release set %s\n", nfnl_set(inst, index)->name); |
| 1256 | ip_set_put_byindex(index); | 1360 | __ip_set_put_byindex(inst, index); |
| 1257 | cb->args[2] = 0; | 1361 | cb->args[2] = 0; |
| 1258 | } | 1362 | } |
| 1259 | out: | 1363 | out: |
| @@ -1271,6 +1375,8 @@ ip_set_dump(struct sock *ctnl, struct sk_buff *skb, | |||
| 1271 | const struct nlmsghdr *nlh, | 1375 | const struct nlmsghdr *nlh, |
| 1272 | const struct nlattr * const attr[]) | 1376 | const struct nlattr * const attr[]) |
| 1273 | { | 1377 | { |
| 1378 | struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl)); | ||
| 1379 | |||
| 1274 | if (unlikely(protocol_failed(attr))) | 1380 | if (unlikely(protocol_failed(attr))) |
| 1275 | return -IPSET_ERR_PROTOCOL; | 1381 | return -IPSET_ERR_PROTOCOL; |
| 1276 | 1382 | ||
| @@ -1278,6 +1384,7 @@ ip_set_dump(struct sock *ctnl, struct sk_buff *skb, | |||
| 1278 | struct netlink_dump_control c = { | 1384 | struct netlink_dump_control c = { |
| 1279 | .dump = ip_set_dump_start, | 1385 | .dump = ip_set_dump_start, |
| 1280 | .done = ip_set_dump_done, | 1386 | .done = ip_set_dump_done, |
| 1387 | .data = (void *)inst | ||
| 1281 | }; | 1388 | }; |
| 1282 | return netlink_dump_start(ctnl, skb, nlh, &c); | 1389 | return netlink_dump_start(ctnl, skb, nlh, &c); |
| 1283 | } | 1390 | } |
| @@ -1356,6 +1463,7 @@ ip_set_uadd(struct sock *ctnl, struct sk_buff *skb, | |||
| 1356 | const struct nlmsghdr *nlh, | 1463 | const struct nlmsghdr *nlh, |
| 1357 | const struct nlattr * const attr[]) | 1464 | const struct nlattr * const attr[]) |
| 1358 | { | 1465 | { |
| 1466 | struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl)); | ||
| 1359 | struct ip_set *set; | 1467 | struct ip_set *set; |
| 1360 | struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {}; | 1468 | struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {}; |
| 1361 | const struct nlattr *nla; | 1469 | const struct nlattr *nla; |
| @@ -1374,7 +1482,7 @@ ip_set_uadd(struct sock *ctnl, struct sk_buff *skb, | |||
| 1374 | attr[IPSET_ATTR_LINENO] == NULL)))) | 1482 | attr[IPSET_ATTR_LINENO] == NULL)))) |
| 1375 | return -IPSET_ERR_PROTOCOL; | 1483 | return -IPSET_ERR_PROTOCOL; |
| 1376 | 1484 | ||
| 1377 | set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); | 1485 | set = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME])); |
| 1378 | if (set == NULL) | 1486 | if (set == NULL) |
| 1379 | return -ENOENT; | 1487 | return -ENOENT; |
| 1380 | 1488 | ||
| @@ -1410,6 +1518,7 @@ ip_set_udel(struct sock *ctnl, struct sk_buff *skb, | |||
| 1410 | const struct nlmsghdr *nlh, | 1518 | const struct nlmsghdr *nlh, |
| 1411 | const struct nlattr * const attr[]) | 1519 | const struct nlattr * const attr[]) |
| 1412 | { | 1520 | { |
| 1521 | struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl)); | ||
| 1413 | struct ip_set *set; | 1522 | struct ip_set *set; |
| 1414 | struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {}; | 1523 | struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {}; |
| 1415 | const struct nlattr *nla; | 1524 | const struct nlattr *nla; |
| @@ -1428,7 +1537,7 @@ ip_set_udel(struct sock *ctnl, struct sk_buff *skb, | |||
| 1428 | attr[IPSET_ATTR_LINENO] == NULL)))) | 1537 | attr[IPSET_ATTR_LINENO] == NULL)))) |
| 1429 | return -IPSET_ERR_PROTOCOL; | 1538 | return -IPSET_ERR_PROTOCOL; |
| 1430 | 1539 | ||
| 1431 | set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); | 1540 | set = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME])); |
| 1432 | if (set == NULL) | 1541 | if (set == NULL) |
| 1433 | return -ENOENT; | 1542 | return -ENOENT; |
| 1434 | 1543 | ||
| @@ -1464,6 +1573,7 @@ ip_set_utest(struct sock *ctnl, struct sk_buff *skb, | |||
| 1464 | const struct nlmsghdr *nlh, | 1573 | const struct nlmsghdr *nlh, |
| 1465 | const struct nlattr * const attr[]) | 1574 | const struct nlattr * const attr[]) |
| 1466 | { | 1575 | { |
| 1576 | struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl)); | ||
| 1467 | struct ip_set *set; | 1577 | struct ip_set *set; |
| 1468 | struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {}; | 1578 | struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {}; |
| 1469 | int ret = 0; | 1579 | int ret = 0; |
| @@ -1474,7 +1584,7 @@ ip_set_utest(struct sock *ctnl, struct sk_buff *skb, | |||
| 1474 | !flag_nested(attr[IPSET_ATTR_DATA]))) | 1584 | !flag_nested(attr[IPSET_ATTR_DATA]))) |
| 1475 | return -IPSET_ERR_PROTOCOL; | 1585 | return -IPSET_ERR_PROTOCOL; |
| 1476 | 1586 | ||
| 1477 | set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); | 1587 | set = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME])); |
| 1478 | if (set == NULL) | 1588 | if (set == NULL) |
| 1479 | return -ENOENT; | 1589 | return -ENOENT; |
| 1480 | 1590 | ||
| @@ -1499,6 +1609,7 @@ ip_set_header(struct sock *ctnl, struct sk_buff *skb, | |||
| 1499 | const struct nlmsghdr *nlh, | 1609 | const struct nlmsghdr *nlh, |
| 1500 | const struct nlattr * const attr[]) | 1610 | const struct nlattr * const attr[]) |
| 1501 | { | 1611 | { |
| 1612 | struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl)); | ||
| 1502 | const struct ip_set *set; | 1613 | const struct ip_set *set; |
| 1503 | struct sk_buff *skb2; | 1614 | struct sk_buff *skb2; |
| 1504 | struct nlmsghdr *nlh2; | 1615 | struct nlmsghdr *nlh2; |
| @@ -1508,7 +1619,7 @@ ip_set_header(struct sock *ctnl, struct sk_buff *skb, | |||
| 1508 | attr[IPSET_ATTR_SETNAME] == NULL)) | 1619 | attr[IPSET_ATTR_SETNAME] == NULL)) |
| 1509 | return -IPSET_ERR_PROTOCOL; | 1620 | return -IPSET_ERR_PROTOCOL; |
| 1510 | 1621 | ||
| 1511 | set = find_set(nla_data(attr[IPSET_ATTR_SETNAME])); | 1622 | set = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME])); |
| 1512 | if (set == NULL) | 1623 | if (set == NULL) |
| 1513 | return -ENOENT; | 1624 | return -ENOENT; |
| 1514 | 1625 | ||
| @@ -1733,8 +1844,10 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len) | |||
| 1733 | unsigned int *op; | 1844 | unsigned int *op; |
| 1734 | void *data; | 1845 | void *data; |
| 1735 | int copylen = *len, ret = 0; | 1846 | int copylen = *len, ret = 0; |
| 1847 | struct net *net = sock_net(sk); | ||
| 1848 | struct ip_set_net *inst = ip_set_pernet(net); | ||
| 1736 | 1849 | ||
| 1737 | if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) | 1850 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
| 1738 | return -EPERM; | 1851 | return -EPERM; |
| 1739 | if (optval != SO_IP_SET) | 1852 | if (optval != SO_IP_SET) |
| 1740 | return -EBADF; | 1853 | return -EBADF; |
| @@ -1783,22 +1896,39 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len) | |||
| 1783 | } | 1896 | } |
| 1784 | req_get->set.name[IPSET_MAXNAMELEN - 1] = '\0'; | 1897 | req_get->set.name[IPSET_MAXNAMELEN - 1] = '\0'; |
| 1785 | nfnl_lock(NFNL_SUBSYS_IPSET); | 1898 | nfnl_lock(NFNL_SUBSYS_IPSET); |
| 1786 | find_set_and_id(req_get->set.name, &id); | 1899 | find_set_and_id(inst, req_get->set.name, &id); |
| 1787 | req_get->set.index = id; | 1900 | req_get->set.index = id; |
| 1788 | nfnl_unlock(NFNL_SUBSYS_IPSET); | 1901 | nfnl_unlock(NFNL_SUBSYS_IPSET); |
| 1789 | goto copy; | 1902 | goto copy; |
| 1790 | } | 1903 | } |
| 1904 | case IP_SET_OP_GET_FNAME: { | ||
| 1905 | struct ip_set_req_get_set_family *req_get = data; | ||
| 1906 | ip_set_id_t id; | ||
| 1907 | |||
| 1908 | if (*len != sizeof(struct ip_set_req_get_set_family)) { | ||
| 1909 | ret = -EINVAL; | ||
| 1910 | goto done; | ||
| 1911 | } | ||
| 1912 | req_get->set.name[IPSET_MAXNAMELEN - 1] = '\0'; | ||
| 1913 | nfnl_lock(NFNL_SUBSYS_IPSET); | ||
| 1914 | find_set_and_id(inst, req_get->set.name, &id); | ||
| 1915 | req_get->set.index = id; | ||
| 1916 | if (id != IPSET_INVALID_ID) | ||
| 1917 | req_get->family = nfnl_set(inst, id)->family; | ||
| 1918 | nfnl_unlock(NFNL_SUBSYS_IPSET); | ||
| 1919 | goto copy; | ||
| 1920 | } | ||
| 1791 | case IP_SET_OP_GET_BYINDEX: { | 1921 | case IP_SET_OP_GET_BYINDEX: { |
| 1792 | struct ip_set_req_get_set *req_get = data; | 1922 | struct ip_set_req_get_set *req_get = data; |
| 1793 | struct ip_set *set; | 1923 | struct ip_set *set; |
| 1794 | 1924 | ||
| 1795 | if (*len != sizeof(struct ip_set_req_get_set) || | 1925 | if (*len != sizeof(struct ip_set_req_get_set) || |
| 1796 | req_get->set.index >= ip_set_max) { | 1926 | req_get->set.index >= inst->ip_set_max) { |
| 1797 | ret = -EINVAL; | 1927 | ret = -EINVAL; |
| 1798 | goto done; | 1928 | goto done; |
| 1799 | } | 1929 | } |
| 1800 | nfnl_lock(NFNL_SUBSYS_IPSET); | 1930 | nfnl_lock(NFNL_SUBSYS_IPSET); |
| 1801 | set = nfnl_set(req_get->set.index); | 1931 | set = nfnl_set(inst, req_get->set.index); |
| 1802 | strncpy(req_get->set.name, set ? set->name : "", | 1932 | strncpy(req_get->set.name, set ? set->name : "", |
| 1803 | IPSET_MAXNAMELEN); | 1933 | IPSET_MAXNAMELEN); |
| 1804 | nfnl_unlock(NFNL_SUBSYS_IPSET); | 1934 | nfnl_unlock(NFNL_SUBSYS_IPSET); |
| @@ -1827,49 +1957,82 @@ static struct nf_sockopt_ops so_set __read_mostly = { | |||
| 1827 | .owner = THIS_MODULE, | 1957 | .owner = THIS_MODULE, |
| 1828 | }; | 1958 | }; |
| 1829 | 1959 | ||
| 1830 | static int __init | 1960 | static int __net_init |
| 1831 | ip_set_init(void) | 1961 | ip_set_net_init(struct net *net) |
| 1832 | { | 1962 | { |
| 1963 | struct ip_set_net *inst = ip_set_pernet(net); | ||
| 1964 | |||
| 1833 | struct ip_set **list; | 1965 | struct ip_set **list; |
| 1834 | int ret; | ||
| 1835 | 1966 | ||
| 1836 | if (max_sets) | 1967 | inst->ip_set_max = max_sets ? max_sets : CONFIG_IP_SET_MAX; |
| 1837 | ip_set_max = max_sets; | 1968 | if (inst->ip_set_max >= IPSET_INVALID_ID) |
| 1838 | if (ip_set_max >= IPSET_INVALID_ID) | 1969 | inst->ip_set_max = IPSET_INVALID_ID - 1; |
| 1839 | ip_set_max = IPSET_INVALID_ID - 1; | ||
| 1840 | 1970 | ||
| 1841 | list = kzalloc(sizeof(struct ip_set *) * ip_set_max, GFP_KERNEL); | 1971 | list = kzalloc(sizeof(struct ip_set *) * inst->ip_set_max, GFP_KERNEL); |
| 1842 | if (!list) | 1972 | if (!list) |
| 1843 | return -ENOMEM; | 1973 | return -ENOMEM; |
| 1974 | inst->is_deleted = 0; | ||
| 1975 | rcu_assign_pointer(inst->ip_set_list, list); | ||
| 1976 | pr_notice("ip_set: protocol %u\n", IPSET_PROTOCOL); | ||
| 1977 | return 0; | ||
| 1978 | } | ||
| 1979 | |||
| 1980 | static void __net_exit | ||
| 1981 | ip_set_net_exit(struct net *net) | ||
| 1982 | { | ||
| 1983 | struct ip_set_net *inst = ip_set_pernet(net); | ||
| 1984 | |||
| 1985 | struct ip_set *set = NULL; | ||
| 1986 | ip_set_id_t i; | ||
| 1987 | |||
| 1988 | inst->is_deleted = 1; /* flag for ip_set_nfnl_put */ | ||
| 1989 | |||
| 1990 | for (i = 0; i < inst->ip_set_max; i++) { | ||
| 1991 | set = nfnl_set(inst, i); | ||
| 1992 | if (set != NULL) | ||
| 1993 | ip_set_destroy_set(inst, i); | ||
| 1994 | } | ||
| 1995 | kfree(rcu_dereference_protected(inst->ip_set_list, 1)); | ||
| 1996 | } | ||
| 1997 | |||
| 1998 | static struct pernet_operations ip_set_net_ops = { | ||
| 1999 | .init = ip_set_net_init, | ||
| 2000 | .exit = ip_set_net_exit, | ||
| 2001 | .id = &ip_set_net_id, | ||
| 2002 | .size = sizeof(struct ip_set_net) | ||
| 2003 | }; | ||
| 2004 | |||
| 1844 | 2005 | ||
| 1845 | rcu_assign_pointer(ip_set_list, list); | 2006 | static int __init |
| 1846 | ret = nfnetlink_subsys_register(&ip_set_netlink_subsys); | 2007 | ip_set_init(void) |
| 2008 | { | ||
| 2009 | int ret = nfnetlink_subsys_register(&ip_set_netlink_subsys); | ||
| 1847 | if (ret != 0) { | 2010 | if (ret != 0) { |
| 1848 | pr_err("ip_set: cannot register with nfnetlink.\n"); | 2011 | pr_err("ip_set: cannot register with nfnetlink.\n"); |
| 1849 | kfree(list); | ||
| 1850 | return ret; | 2012 | return ret; |
| 1851 | } | 2013 | } |
| 1852 | ret = nf_register_sockopt(&so_set); | 2014 | ret = nf_register_sockopt(&so_set); |
| 1853 | if (ret != 0) { | 2015 | if (ret != 0) { |
| 1854 | pr_err("SO_SET registry failed: %d\n", ret); | 2016 | pr_err("SO_SET registry failed: %d\n", ret); |
| 1855 | nfnetlink_subsys_unregister(&ip_set_netlink_subsys); | 2017 | nfnetlink_subsys_unregister(&ip_set_netlink_subsys); |
| 1856 | kfree(list); | ||
| 1857 | return ret; | 2018 | return ret; |
| 1858 | } | 2019 | } |
| 1859 | 2020 | ret = register_pernet_subsys(&ip_set_net_ops); | |
| 1860 | pr_notice("ip_set: protocol %u\n", IPSET_PROTOCOL); | 2021 | if (ret) { |
| 2022 | pr_err("ip_set: cannot register pernet_subsys.\n"); | ||
| 2023 | nf_unregister_sockopt(&so_set); | ||
| 2024 | nfnetlink_subsys_unregister(&ip_set_netlink_subsys); | ||
| 2025 | return ret; | ||
| 2026 | } | ||
| 1861 | return 0; | 2027 | return 0; |
| 1862 | } | 2028 | } |
| 1863 | 2029 | ||
| 1864 | static void __exit | 2030 | static void __exit |
| 1865 | ip_set_fini(void) | 2031 | ip_set_fini(void) |
| 1866 | { | 2032 | { |
| 1867 | struct ip_set **list = rcu_dereference_protected(ip_set_list, 1); | 2033 | unregister_pernet_subsys(&ip_set_net_ops); |
| 1868 | |||
| 1869 | /* There can't be any existing set */ | ||
| 1870 | nf_unregister_sockopt(&so_set); | 2034 | nf_unregister_sockopt(&so_set); |
| 1871 | nfnetlink_subsys_unregister(&ip_set_netlink_subsys); | 2035 | nfnetlink_subsys_unregister(&ip_set_netlink_subsys); |
| 1872 | kfree(list); | ||
| 1873 | pr_debug("these are the famous last words\n"); | 2036 | pr_debug("these are the famous last words\n"); |
| 1874 | } | 2037 | } |
| 1875 | 2038 | ||
diff --git a/net/netfilter/ipset/ip_set_getport.c b/net/netfilter/ipset/ip_set_getport.c index dac156f819ac..29fb01ddff93 100644 --- a/net/netfilter/ipset/ip_set_getport.c +++ b/net/netfilter/ipset/ip_set_getport.c | |||
| @@ -102,9 +102,25 @@ ip_set_get_ip4_port(const struct sk_buff *skb, bool src, | |||
| 102 | int protocol = iph->protocol; | 102 | int protocol = iph->protocol; |
| 103 | 103 | ||
| 104 | /* See comments at tcp_match in ip_tables.c */ | 104 | /* See comments at tcp_match in ip_tables.c */ |
| 105 | if (protocol <= 0 || (ntohs(iph->frag_off) & IP_OFFSET)) | 105 | if (protocol <= 0) |
| 106 | return false; | 106 | return false; |
| 107 | 107 | ||
| 108 | if (ntohs(iph->frag_off) & IP_OFFSET) | ||
| 109 | switch (protocol) { | ||
| 110 | case IPPROTO_TCP: | ||
| 111 | case IPPROTO_SCTP: | ||
| 112 | case IPPROTO_UDP: | ||
| 113 | case IPPROTO_UDPLITE: | ||
| 114 | case IPPROTO_ICMP: | ||
| 115 | /* Port info not available for fragment offset > 0 */ | ||
| 116 | return false; | ||
| 117 | default: | ||
| 118 | /* Other protocols doesn't have ports, | ||
| 119 | so we can match fragments */ | ||
| 120 | *proto = protocol; | ||
| 121 | return true; | ||
| 122 | } | ||
| 123 | |||
| 108 | return get_port(skb, protocol, protooff, src, port, proto); | 124 | return get_port(skb, protocol, protooff, src, port, proto); |
| 109 | } | 125 | } |
| 110 | EXPORT_SYMBOL_GPL(ip_set_get_ip4_port); | 126 | 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 707bc520d629..6a80dbd30df7 100644 --- a/net/netfilter/ipset/ip_set_hash_gen.h +++ b/net/netfilter/ipset/ip_set_hash_gen.h | |||
| @@ -15,8 +15,7 @@ | |||
| 15 | #define rcu_dereference_bh(p) rcu_dereference(p) | 15 | #define rcu_dereference_bh(p) rcu_dereference(p) |
| 16 | #endif | 16 | #endif |
| 17 | 17 | ||
| 18 | #define CONCAT(a, b) a##b | 18 | #define rcu_dereference_bh_nfnl(p) rcu_dereference_bh_check(p, 1) |
| 19 | #define TOKEN(a, b) CONCAT(a, b) | ||
| 20 | 19 | ||
| 21 | /* Hashing which uses arrays to resolve clashing. The hash table is resized | 20 | /* Hashing which uses arrays to resolve clashing. The hash table is resized |
| 22 | * (doubled) when searching becomes too long. | 21 | * (doubled) when searching becomes too long. |
| @@ -78,10 +77,14 @@ struct htable { | |||
| 78 | 77 | ||
| 79 | #define hbucket(h, i) (&((h)->bucket[i])) | 78 | #define hbucket(h, i) (&((h)->bucket[i])) |
| 80 | 79 | ||
| 80 | #ifndef IPSET_NET_COUNT | ||
| 81 | #define IPSET_NET_COUNT 1 | ||
| 82 | #endif | ||
| 83 | |||
| 81 | /* Book-keeping of the prefixes added to the set */ | 84 | /* Book-keeping of the prefixes added to the set */ |
| 82 | struct net_prefixes { | 85 | struct net_prefixes { |
| 83 | u8 cidr; /* the different cidr values in the set */ | 86 | u32 nets[IPSET_NET_COUNT]; /* number of elements per cidr */ |
| 84 | u32 nets; /* number of elements per cidr */ | 87 | u8 cidr[IPSET_NET_COUNT]; /* the different cidr values in the set */ |
| 85 | }; | 88 | }; |
| 86 | 89 | ||
| 87 | /* Compute the hash table size */ | 90 | /* Compute the hash table size */ |
| @@ -114,23 +117,6 @@ htable_bits(u32 hashsize) | |||
| 114 | return bits; | 117 | return bits; |
| 115 | } | 118 | } |
| 116 | 119 | ||
| 117 | /* Destroy the hashtable part of the set */ | ||
| 118 | static void | ||
| 119 | ahash_destroy(struct htable *t) | ||
| 120 | { | ||
| 121 | struct hbucket *n; | ||
| 122 | u32 i; | ||
| 123 | |||
| 124 | for (i = 0; i < jhash_size(t->htable_bits); i++) { | ||
| 125 | n = hbucket(t, i); | ||
| 126 | if (n->size) | ||
| 127 | /* FIXME: use slab cache */ | ||
| 128 | kfree(n->value); | ||
| 129 | } | ||
| 130 | |||
| 131 | ip_set_free(t); | ||
| 132 | } | ||
| 133 | |||
| 134 | static int | 120 | static int |
| 135 | hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize) | 121 | hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize) |
| 136 | { | 122 | { |
| @@ -156,30 +142,30 @@ hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize) | |||
| 156 | } | 142 | } |
| 157 | 143 | ||
| 158 | #ifdef IP_SET_HASH_WITH_NETS | 144 | #ifdef IP_SET_HASH_WITH_NETS |
| 145 | #if IPSET_NET_COUNT > 1 | ||
| 146 | #define __CIDR(cidr, i) (cidr[i]) | ||
| 147 | #else | ||
| 148 | #define __CIDR(cidr, i) (cidr) | ||
| 149 | #endif | ||
| 159 | #ifdef IP_SET_HASH_WITH_NETS_PACKED | 150 | #ifdef IP_SET_HASH_WITH_NETS_PACKED |
| 160 | /* When cidr is packed with nomatch, cidr - 1 is stored in the entry */ | 151 | /* When cidr is packed with nomatch, cidr - 1 is stored in the entry */ |
| 161 | #define CIDR(cidr) (cidr + 1) | 152 | #define CIDR(cidr, i) (__CIDR(cidr, i) + 1) |
| 162 | #else | 153 | #else |
| 163 | #define CIDR(cidr) (cidr) | 154 | #define CIDR(cidr, i) (__CIDR(cidr, i)) |
| 164 | #endif | 155 | #endif |
| 165 | 156 | ||
| 166 | #define SET_HOST_MASK(family) (family == AF_INET ? 32 : 128) | 157 | #define SET_HOST_MASK(family) (family == AF_INET ? 32 : 128) |
| 167 | 158 | ||
| 168 | #ifdef IP_SET_HASH_WITH_MULTI | 159 | #ifdef IP_SET_HASH_WITH_MULTI |
| 169 | #define NETS_LENGTH(family) (SET_HOST_MASK(family) + 1) | 160 | #define NLEN(family) (SET_HOST_MASK(family) + 1) |
| 170 | #else | 161 | #else |
| 171 | #define NETS_LENGTH(family) SET_HOST_MASK(family) | 162 | #define NLEN(family) SET_HOST_MASK(family) |
| 172 | #endif | 163 | #endif |
| 173 | 164 | ||
| 174 | #else | 165 | #else |
| 175 | #define NETS_LENGTH(family) 0 | 166 | #define NLEN(family) 0 |
| 176 | #endif /* IP_SET_HASH_WITH_NETS */ | 167 | #endif /* IP_SET_HASH_WITH_NETS */ |
| 177 | 168 | ||
| 178 | #define ext_timeout(e, h) \ | ||
| 179 | (unsigned long *)(((void *)(e)) + (h)->offset[IPSET_OFFSET_TIMEOUT]) | ||
| 180 | #define ext_counter(e, h) \ | ||
| 181 | (struct ip_set_counter *)(((void *)(e)) + (h)->offset[IPSET_OFFSET_COUNTER]) | ||
| 182 | |||
| 183 | #endif /* _IP_SET_HASH_GEN_H */ | 169 | #endif /* _IP_SET_HASH_GEN_H */ |
| 184 | 170 | ||
| 185 | /* Family dependent templates */ | 171 | /* Family dependent templates */ |
| @@ -194,6 +180,8 @@ hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize) | |||
| 194 | #undef mtype_data_next | 180 | #undef mtype_data_next |
| 195 | #undef mtype_elem | 181 | #undef mtype_elem |
| 196 | 182 | ||
| 183 | #undef mtype_ahash_destroy | ||
| 184 | #undef mtype_ext_cleanup | ||
| 197 | #undef mtype_add_cidr | 185 | #undef mtype_add_cidr |
| 198 | #undef mtype_del_cidr | 186 | #undef mtype_del_cidr |
| 199 | #undef mtype_ahash_memsize | 187 | #undef mtype_ahash_memsize |
| @@ -220,41 +208,44 @@ hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize) | |||
| 220 | 208 | ||
| 221 | #undef HKEY | 209 | #undef HKEY |
| 222 | 210 | ||
| 223 | #define mtype_data_equal TOKEN(MTYPE, _data_equal) | 211 | #define mtype_data_equal IPSET_TOKEN(MTYPE, _data_equal) |
| 224 | #ifdef IP_SET_HASH_WITH_NETS | 212 | #ifdef IP_SET_HASH_WITH_NETS |
| 225 | #define mtype_do_data_match TOKEN(MTYPE, _do_data_match) | 213 | #define mtype_do_data_match IPSET_TOKEN(MTYPE, _do_data_match) |
| 226 | #else | 214 | #else |
| 227 | #define mtype_do_data_match(d) 1 | 215 | #define mtype_do_data_match(d) 1 |
| 228 | #endif | 216 | #endif |
| 229 | #define mtype_data_set_flags TOKEN(MTYPE, _data_set_flags) | 217 | #define mtype_data_set_flags IPSET_TOKEN(MTYPE, _data_set_flags) |
| 230 | #define mtype_data_reset_flags TOKEN(MTYPE, _data_reset_flags) | 218 | #define mtype_data_reset_elem IPSET_TOKEN(MTYPE, _data_reset_elem) |
| 231 | #define mtype_data_netmask TOKEN(MTYPE, _data_netmask) | 219 | #define mtype_data_reset_flags IPSET_TOKEN(MTYPE, _data_reset_flags) |
| 232 | #define mtype_data_list TOKEN(MTYPE, _data_list) | 220 | #define mtype_data_netmask IPSET_TOKEN(MTYPE, _data_netmask) |
| 233 | #define mtype_data_next TOKEN(MTYPE, _data_next) | 221 | #define mtype_data_list IPSET_TOKEN(MTYPE, _data_list) |
| 234 | #define mtype_elem TOKEN(MTYPE, _elem) | 222 | #define mtype_data_next IPSET_TOKEN(MTYPE, _data_next) |
| 235 | #define mtype_add_cidr TOKEN(MTYPE, _add_cidr) | 223 | #define mtype_elem IPSET_TOKEN(MTYPE, _elem) |
| 236 | #define mtype_del_cidr TOKEN(MTYPE, _del_cidr) | 224 | #define mtype_ahash_destroy IPSET_TOKEN(MTYPE, _ahash_destroy) |
| 237 | #define mtype_ahash_memsize TOKEN(MTYPE, _ahash_memsize) | 225 | #define mtype_ext_cleanup IPSET_TOKEN(MTYPE, _ext_cleanup) |
| 238 | #define mtype_flush TOKEN(MTYPE, _flush) | 226 | #define mtype_add_cidr IPSET_TOKEN(MTYPE, _add_cidr) |
| 239 | #define mtype_destroy TOKEN(MTYPE, _destroy) | 227 | #define mtype_del_cidr IPSET_TOKEN(MTYPE, _del_cidr) |
| 240 | #define mtype_gc_init TOKEN(MTYPE, _gc_init) | 228 | #define mtype_ahash_memsize IPSET_TOKEN(MTYPE, _ahash_memsize) |
| 241 | #define mtype_same_set TOKEN(MTYPE, _same_set) | 229 | #define mtype_flush IPSET_TOKEN(MTYPE, _flush) |
| 242 | #define mtype_kadt TOKEN(MTYPE, _kadt) | 230 | #define mtype_destroy IPSET_TOKEN(MTYPE, _destroy) |
| 243 | #define mtype_uadt TOKEN(MTYPE, _uadt) | 231 | #define mtype_gc_init IPSET_TOKEN(MTYPE, _gc_init) |
| 232 | #define mtype_same_set IPSET_TOKEN(MTYPE, _same_set) | ||
| 233 | #define mtype_kadt IPSET_TOKEN(MTYPE, _kadt) | ||
| 234 | #define mtype_uadt IPSET_TOKEN(MTYPE, _uadt) | ||
| 244 | #define mtype MTYPE | 235 | #define mtype MTYPE |
| 245 | 236 | ||
| 246 | #define mtype_elem TOKEN(MTYPE, _elem) | 237 | #define mtype_elem IPSET_TOKEN(MTYPE, _elem) |
| 247 | #define mtype_add TOKEN(MTYPE, _add) | 238 | #define mtype_add IPSET_TOKEN(MTYPE, _add) |
| 248 | #define mtype_del TOKEN(MTYPE, _del) | 239 | #define mtype_del IPSET_TOKEN(MTYPE, _del) |
| 249 | #define mtype_test_cidrs TOKEN(MTYPE, _test_cidrs) | 240 | #define mtype_test_cidrs IPSET_TOKEN(MTYPE, _test_cidrs) |
| 250 | #define mtype_test TOKEN(MTYPE, _test) | 241 | #define mtype_test IPSET_TOKEN(MTYPE, _test) |
| 251 | #define mtype_expire TOKEN(MTYPE, _expire) | 242 | #define mtype_expire IPSET_TOKEN(MTYPE, _expire) |
| 252 | #define mtype_resize TOKEN(MTYPE, _resize) | 243 | #define mtype_resize IPSET_TOKEN(MTYPE, _resize) |
| 253 | #define mtype_head TOKEN(MTYPE, _head) | 244 | #define mtype_head IPSET_TOKEN(MTYPE, _head) |
| 254 | #define mtype_list TOKEN(MTYPE, _list) | 245 | #define mtype_list IPSET_TOKEN(MTYPE, _list) |
| 255 | #define mtype_gc TOKEN(MTYPE, _gc) | 246 | #define mtype_gc IPSET_TOKEN(MTYPE, _gc) |
| 256 | #define mtype_variant TOKEN(MTYPE, _variant) | 247 | #define mtype_variant IPSET_TOKEN(MTYPE, _variant) |
| 257 | #define mtype_data_match TOKEN(MTYPE, _data_match) | 248 | #define mtype_data_match IPSET_TOKEN(MTYPE, _data_match) |
| 258 | 249 | ||
| 259 | #ifndef HKEY_DATALEN | 250 | #ifndef HKEY_DATALEN |
| 260 | #define HKEY_DATALEN sizeof(struct mtype_elem) | 251 | #define HKEY_DATALEN sizeof(struct mtype_elem) |
| @@ -269,13 +260,10 @@ hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize) | |||
| 269 | 260 | ||
| 270 | /* The generic hash structure */ | 261 | /* The generic hash structure */ |
| 271 | struct htype { | 262 | struct htype { |
| 272 | struct htable *table; /* the hash table */ | 263 | struct htable __rcu *table; /* the hash table */ |
| 273 | u32 maxelem; /* max elements in the hash */ | 264 | u32 maxelem; /* max elements in the hash */ |
| 274 | u32 elements; /* current element (vs timeout) */ | 265 | u32 elements; /* current element (vs timeout) */ |
| 275 | u32 initval; /* random jhash init value */ | 266 | u32 initval; /* random jhash init value */ |
| 276 | u32 timeout; /* timeout value, if enabled */ | ||
| 277 | size_t dsize; /* data struct size */ | ||
| 278 | size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */ | ||
| 279 | struct timer_list gc; /* garbage collection when timeout enabled */ | 267 | struct timer_list gc; /* garbage collection when timeout enabled */ |
| 280 | struct mtype_elem next; /* temporary storage for uadd */ | 268 | struct mtype_elem next; /* temporary storage for uadd */ |
| 281 | #ifdef IP_SET_HASH_WITH_MULTI | 269 | #ifdef IP_SET_HASH_WITH_MULTI |
| @@ -297,49 +285,49 @@ struct htype { | |||
| 297 | /* Network cidr size book keeping when the hash stores different | 285 | /* Network cidr size book keeping when the hash stores different |
| 298 | * sized networks */ | 286 | * sized networks */ |
| 299 | static void | 287 | static void |
| 300 | mtype_add_cidr(struct htype *h, u8 cidr, u8 nets_length) | 288 | mtype_add_cidr(struct htype *h, u8 cidr, u8 nets_length, u8 n) |
| 301 | { | 289 | { |
| 302 | int i, j; | 290 | int i, j; |
| 303 | 291 | ||
| 304 | /* Add in increasing prefix order, so larger cidr first */ | 292 | /* Add in increasing prefix order, so larger cidr first */ |
| 305 | for (i = 0, j = -1; i < nets_length && h->nets[i].nets; i++) { | 293 | for (i = 0, j = -1; i < nets_length && h->nets[i].nets[n]; i++) { |
| 306 | if (j != -1) | 294 | if (j != -1) |
| 307 | continue; | 295 | continue; |
| 308 | else if (h->nets[i].cidr < cidr) | 296 | else if (h->nets[i].cidr[n] < cidr) |
| 309 | j = i; | 297 | j = i; |
| 310 | else if (h->nets[i].cidr == cidr) { | 298 | else if (h->nets[i].cidr[n] == cidr) { |
| 311 | h->nets[i].nets++; | 299 | h->nets[i].nets[n]++; |
| 312 | return; | 300 | return; |
| 313 | } | 301 | } |
| 314 | } | 302 | } |
| 315 | if (j != -1) { | 303 | if (j != -1) { |
| 316 | for (; i > j; i--) { | 304 | for (; i > j; i--) { |
| 317 | h->nets[i].cidr = h->nets[i - 1].cidr; | 305 | h->nets[i].cidr[n] = h->nets[i - 1].cidr[n]; |
| 318 | h->nets[i].nets = h->nets[i - 1].nets; | 306 | h->nets[i].nets[n] = h->nets[i - 1].nets[n]; |
| 319 | } | 307 | } |
| 320 | } | 308 | } |
| 321 | h->nets[i].cidr = cidr; | 309 | h->nets[i].cidr[n] = cidr; |
| 322 | h->nets[i].nets = 1; | 310 | h->nets[i].nets[n] = 1; |
| 323 | } | 311 | } |
| 324 | 312 | ||
| 325 | static void | 313 | static void |
| 326 | mtype_del_cidr(struct htype *h, u8 cidr, u8 nets_length) | 314 | mtype_del_cidr(struct htype *h, u8 cidr, u8 nets_length, u8 n) |
| 327 | { | 315 | { |
| 328 | u8 i, j, net_end = nets_length - 1; | 316 | u8 i, j, net_end = nets_length - 1; |
| 329 | 317 | ||
| 330 | for (i = 0; i < nets_length; i++) { | 318 | for (i = 0; i < nets_length; i++) { |
| 331 | if (h->nets[i].cidr != cidr) | 319 | if (h->nets[i].cidr[n] != cidr) |
| 332 | continue; | 320 | continue; |
| 333 | if (h->nets[i].nets > 1 || i == net_end || | 321 | if (h->nets[i].nets[n] > 1 || i == net_end || |
| 334 | h->nets[i + 1].nets == 0) { | 322 | h->nets[i + 1].nets[n] == 0) { |
| 335 | h->nets[i].nets--; | 323 | h->nets[i].nets[n]--; |
| 336 | return; | 324 | return; |
| 337 | } | 325 | } |
| 338 | for (j = i; j < net_end && h->nets[j].nets; j++) { | 326 | for (j = i; j < net_end && h->nets[j].nets[n]; j++) { |
| 339 | h->nets[j].cidr = h->nets[j + 1].cidr; | 327 | h->nets[j].cidr[n] = h->nets[j + 1].cidr[n]; |
| 340 | h->nets[j].nets = h->nets[j + 1].nets; | 328 | h->nets[j].nets[n] = h->nets[j + 1].nets[n]; |
| 341 | } | 329 | } |
| 342 | h->nets[j].nets = 0; | 330 | h->nets[j].nets[n] = 0; |
| 343 | return; | 331 | return; |
| 344 | } | 332 | } |
| 345 | } | 333 | } |
| @@ -347,10 +335,10 @@ mtype_del_cidr(struct htype *h, u8 cidr, u8 nets_length) | |||
| 347 | 335 | ||
| 348 | /* Calculate the actual memory size of the set data */ | 336 | /* Calculate the actual memory size of the set data */ |
| 349 | static size_t | 337 | static size_t |
| 350 | mtype_ahash_memsize(const struct htype *h, u8 nets_length) | 338 | mtype_ahash_memsize(const struct htype *h, const struct htable *t, |
| 339 | u8 nets_length, size_t dsize) | ||
| 351 | { | 340 | { |
| 352 | u32 i; | 341 | u32 i; |
| 353 | struct htable *t = h->table; | ||
| 354 | size_t memsize = sizeof(*h) | 342 | size_t memsize = sizeof(*h) |
| 355 | + sizeof(*t) | 343 | + sizeof(*t) |
| 356 | #ifdef IP_SET_HASH_WITH_NETS | 344 | #ifdef IP_SET_HASH_WITH_NETS |
| @@ -359,35 +347,70 @@ mtype_ahash_memsize(const struct htype *h, u8 nets_length) | |||
| 359 | + jhash_size(t->htable_bits) * sizeof(struct hbucket); | 347 | + jhash_size(t->htable_bits) * sizeof(struct hbucket); |
| 360 | 348 | ||
| 361 | for (i = 0; i < jhash_size(t->htable_bits); i++) | 349 | for (i = 0; i < jhash_size(t->htable_bits); i++) |
| 362 | memsize += t->bucket[i].size * h->dsize; | 350 | memsize += t->bucket[i].size * dsize; |
| 363 | 351 | ||
| 364 | return memsize; | 352 | return memsize; |
| 365 | } | 353 | } |
| 366 | 354 | ||
| 355 | /* Get the ith element from the array block n */ | ||
| 356 | #define ahash_data(n, i, dsize) \ | ||
| 357 | ((struct mtype_elem *)((n)->value + ((i) * (dsize)))) | ||
| 358 | |||
| 359 | static void | ||
| 360 | mtype_ext_cleanup(struct ip_set *set, struct hbucket *n) | ||
| 361 | { | ||
| 362 | int i; | ||
| 363 | |||
| 364 | for (i = 0; i < n->pos; i++) | ||
| 365 | ip_set_ext_destroy(set, ahash_data(n, i, set->dsize)); | ||
| 366 | } | ||
| 367 | |||
| 367 | /* Flush a hash type of set: destroy all elements */ | 368 | /* Flush a hash type of set: destroy all elements */ |
| 368 | static void | 369 | static void |
| 369 | mtype_flush(struct ip_set *set) | 370 | mtype_flush(struct ip_set *set) |
| 370 | { | 371 | { |
| 371 | struct htype *h = set->data; | 372 | struct htype *h = set->data; |
| 372 | struct htable *t = h->table; | 373 | struct htable *t; |
| 373 | struct hbucket *n; | 374 | struct hbucket *n; |
| 374 | u32 i; | 375 | u32 i; |
| 375 | 376 | ||
| 377 | t = rcu_dereference_bh_nfnl(h->table); | ||
| 376 | for (i = 0; i < jhash_size(t->htable_bits); i++) { | 378 | for (i = 0; i < jhash_size(t->htable_bits); i++) { |
| 377 | n = hbucket(t, i); | 379 | n = hbucket(t, i); |
| 378 | if (n->size) { | 380 | if (n->size) { |
| 381 | if (set->extensions & IPSET_EXT_DESTROY) | ||
| 382 | mtype_ext_cleanup(set, n); | ||
| 379 | n->size = n->pos = 0; | 383 | n->size = n->pos = 0; |
| 380 | /* FIXME: use slab cache */ | 384 | /* FIXME: use slab cache */ |
| 381 | kfree(n->value); | 385 | kfree(n->value); |
| 382 | } | 386 | } |
| 383 | } | 387 | } |
| 384 | #ifdef IP_SET_HASH_WITH_NETS | 388 | #ifdef IP_SET_HASH_WITH_NETS |
| 385 | memset(h->nets, 0, sizeof(struct net_prefixes) | 389 | memset(h->nets, 0, sizeof(struct net_prefixes) * NLEN(set->family)); |
| 386 | * NETS_LENGTH(set->family)); | ||
| 387 | #endif | 390 | #endif |
| 388 | h->elements = 0; | 391 | h->elements = 0; |
| 389 | } | 392 | } |
| 390 | 393 | ||
| 394 | /* Destroy the hashtable part of the set */ | ||
| 395 | static void | ||
| 396 | mtype_ahash_destroy(struct ip_set *set, struct htable *t, bool ext_destroy) | ||
| 397 | { | ||
| 398 | struct hbucket *n; | ||
| 399 | u32 i; | ||
| 400 | |||
| 401 | for (i = 0; i < jhash_size(t->htable_bits); i++) { | ||
| 402 | n = hbucket(t, i); | ||
| 403 | if (n->size) { | ||
| 404 | if (set->extensions & IPSET_EXT_DESTROY && ext_destroy) | ||
| 405 | mtype_ext_cleanup(set, n); | ||
| 406 | /* FIXME: use slab cache */ | ||
| 407 | kfree(n->value); | ||
| 408 | } | ||
| 409 | } | ||
| 410 | |||
| 411 | ip_set_free(t); | ||
| 412 | } | ||
| 413 | |||
| 391 | /* Destroy a hash type of set */ | 414 | /* Destroy a hash type of set */ |
| 392 | static void | 415 | static void |
| 393 | mtype_destroy(struct ip_set *set) | 416 | mtype_destroy(struct ip_set *set) |
| @@ -397,7 +420,7 @@ mtype_destroy(struct ip_set *set) | |||
| 397 | if (set->extensions & IPSET_EXT_TIMEOUT) | 420 | if (set->extensions & IPSET_EXT_TIMEOUT) |
| 398 | del_timer_sync(&h->gc); | 421 | del_timer_sync(&h->gc); |
| 399 | 422 | ||
| 400 | ahash_destroy(h->table); | 423 | mtype_ahash_destroy(set, rcu_dereference_bh_nfnl(h->table), true); |
| 401 | #ifdef IP_SET_HASH_WITH_RBTREE | 424 | #ifdef IP_SET_HASH_WITH_RBTREE |
| 402 | rbtree_destroy(&h->rbtree); | 425 | rbtree_destroy(&h->rbtree); |
| 403 | #endif | 426 | #endif |
| @@ -414,10 +437,10 @@ mtype_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set)) | |||
| 414 | init_timer(&h->gc); | 437 | init_timer(&h->gc); |
| 415 | h->gc.data = (unsigned long) set; | 438 | h->gc.data = (unsigned long) set; |
| 416 | h->gc.function = gc; | 439 | h->gc.function = gc; |
| 417 | h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ; | 440 | h->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ; |
| 418 | add_timer(&h->gc); | 441 | add_timer(&h->gc); |
| 419 | pr_debug("gc initialized, run in every %u\n", | 442 | pr_debug("gc initialized, run in every %u\n", |
| 420 | IPSET_GC_PERIOD(h->timeout)); | 443 | IPSET_GC_PERIOD(set->timeout)); |
| 421 | } | 444 | } |
| 422 | 445 | ||
| 423 | static bool | 446 | static bool |
| @@ -428,37 +451,40 @@ mtype_same_set(const struct ip_set *a, const struct ip_set *b) | |||
| 428 | 451 | ||
| 429 | /* Resizing changes htable_bits, so we ignore it */ | 452 | /* Resizing changes htable_bits, so we ignore it */ |
| 430 | return x->maxelem == y->maxelem && | 453 | return x->maxelem == y->maxelem && |
| 431 | x->timeout == y->timeout && | 454 | a->timeout == b->timeout && |
| 432 | #ifdef IP_SET_HASH_WITH_NETMASK | 455 | #ifdef IP_SET_HASH_WITH_NETMASK |
| 433 | x->netmask == y->netmask && | 456 | x->netmask == y->netmask && |
| 434 | #endif | 457 | #endif |
| 435 | a->extensions == b->extensions; | 458 | a->extensions == b->extensions; |
| 436 | } | 459 | } |
| 437 | 460 | ||
| 438 | /* Get the ith element from the array block n */ | ||
| 439 | #define ahash_data(n, i, dsize) \ | ||
| 440 | ((struct mtype_elem *)((n)->value + ((i) * (dsize)))) | ||
| 441 | |||
| 442 | /* Delete expired elements from the hashtable */ | 461 | /* Delete expired elements from the hashtable */ |
| 443 | static void | 462 | static void |
| 444 | mtype_expire(struct htype *h, u8 nets_length, size_t dsize) | 463 | mtype_expire(struct ip_set *set, struct htype *h, u8 nets_length, size_t dsize) |
| 445 | { | 464 | { |
| 446 | struct htable *t = h->table; | 465 | struct htable *t; |
| 447 | struct hbucket *n; | 466 | struct hbucket *n; |
| 448 | struct mtype_elem *data; | 467 | struct mtype_elem *data; |
| 449 | u32 i; | 468 | u32 i; |
| 450 | int j; | 469 | int j; |
| 470 | #ifdef IP_SET_HASH_WITH_NETS | ||
| 471 | u8 k; | ||
| 472 | #endif | ||
| 451 | 473 | ||
| 474 | rcu_read_lock_bh(); | ||
| 475 | t = rcu_dereference_bh(h->table); | ||
| 452 | for (i = 0; i < jhash_size(t->htable_bits); i++) { | 476 | for (i = 0; i < jhash_size(t->htable_bits); i++) { |
| 453 | n = hbucket(t, i); | 477 | n = hbucket(t, i); |
| 454 | for (j = 0; j < n->pos; j++) { | 478 | for (j = 0; j < n->pos; j++) { |
| 455 | data = ahash_data(n, j, dsize); | 479 | data = ahash_data(n, j, dsize); |
| 456 | if (ip_set_timeout_expired(ext_timeout(data, h))) { | 480 | if (ip_set_timeout_expired(ext_timeout(data, set))) { |
| 457 | pr_debug("expired %u/%u\n", i, j); | 481 | pr_debug("expired %u/%u\n", i, j); |
| 458 | #ifdef IP_SET_HASH_WITH_NETS | 482 | #ifdef IP_SET_HASH_WITH_NETS |
| 459 | mtype_del_cidr(h, CIDR(data->cidr), | 483 | for (k = 0; k < IPSET_NET_COUNT; k++) |
| 460 | nets_length); | 484 | mtype_del_cidr(h, CIDR(data->cidr, k), |
| 485 | nets_length, k); | ||
| 461 | #endif | 486 | #endif |
| 487 | ip_set_ext_destroy(set, data); | ||
| 462 | if (j != n->pos - 1) | 488 | if (j != n->pos - 1) |
| 463 | /* Not last one */ | 489 | /* Not last one */ |
| 464 | memcpy(data, | 490 | memcpy(data, |
| @@ -481,6 +507,7 @@ mtype_expire(struct htype *h, u8 nets_length, size_t dsize) | |||
| 481 | n->value = tmp; | 507 | n->value = tmp; |
| 482 | } | 508 | } |
| 483 | } | 509 | } |
| 510 | rcu_read_unlock_bh(); | ||
| 484 | } | 511 | } |
| 485 | 512 | ||
| 486 | static void | 513 | static void |
| @@ -491,10 +518,10 @@ mtype_gc(unsigned long ul_set) | |||
| 491 | 518 | ||
| 492 | pr_debug("called\n"); | 519 | pr_debug("called\n"); |
| 493 | write_lock_bh(&set->lock); | 520 | write_lock_bh(&set->lock); |
| 494 | mtype_expire(h, NETS_LENGTH(set->family), h->dsize); | 521 | mtype_expire(set, h, NLEN(set->family), set->dsize); |
| 495 | write_unlock_bh(&set->lock); | 522 | write_unlock_bh(&set->lock); |
| 496 | 523 | ||
| 497 | h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ; | 524 | h->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ; |
| 498 | add_timer(&h->gc); | 525 | add_timer(&h->gc); |
| 499 | } | 526 | } |
| 500 | 527 | ||
| @@ -505,7 +532,7 @@ static int | |||
| 505 | mtype_resize(struct ip_set *set, bool retried) | 532 | mtype_resize(struct ip_set *set, bool retried) |
| 506 | { | 533 | { |
| 507 | struct htype *h = set->data; | 534 | struct htype *h = set->data; |
| 508 | struct htable *t, *orig = h->table; | 535 | struct htable *t, *orig = rcu_dereference_bh_nfnl(h->table); |
| 509 | u8 htable_bits = orig->htable_bits; | 536 | u8 htable_bits = orig->htable_bits; |
| 510 | #ifdef IP_SET_HASH_WITH_NETS | 537 | #ifdef IP_SET_HASH_WITH_NETS |
| 511 | u8 flags; | 538 | u8 flags; |
| @@ -520,8 +547,7 @@ mtype_resize(struct ip_set *set, bool retried) | |||
| 520 | if (SET_WITH_TIMEOUT(set) && !retried) { | 547 | if (SET_WITH_TIMEOUT(set) && !retried) { |
| 521 | i = h->elements; | 548 | i = h->elements; |
| 522 | write_lock_bh(&set->lock); | 549 | write_lock_bh(&set->lock); |
| 523 | mtype_expire(set->data, NETS_LENGTH(set->family), | 550 | mtype_expire(set, set->data, NLEN(set->family), set->dsize); |
| 524 | h->dsize); | ||
| 525 | write_unlock_bh(&set->lock); | 551 | write_unlock_bh(&set->lock); |
| 526 | if (h->elements < i) | 552 | if (h->elements < i) |
| 527 | return 0; | 553 | return 0; |
| @@ -548,25 +574,25 @@ retry: | |||
| 548 | for (i = 0; i < jhash_size(orig->htable_bits); i++) { | 574 | for (i = 0; i < jhash_size(orig->htable_bits); i++) { |
| 549 | n = hbucket(orig, i); | 575 | n = hbucket(orig, i); |
| 550 | for (j = 0; j < n->pos; j++) { | 576 | for (j = 0; j < n->pos; j++) { |
| 551 | data = ahash_data(n, j, h->dsize); | 577 | data = ahash_data(n, j, set->dsize); |
| 552 | #ifdef IP_SET_HASH_WITH_NETS | 578 | #ifdef IP_SET_HASH_WITH_NETS |
| 553 | flags = 0; | 579 | flags = 0; |
| 554 | mtype_data_reset_flags(data, &flags); | 580 | mtype_data_reset_flags(data, &flags); |
| 555 | #endif | 581 | #endif |
| 556 | m = hbucket(t, HKEY(data, h->initval, htable_bits)); | 582 | m = hbucket(t, HKEY(data, h->initval, htable_bits)); |
| 557 | ret = hbucket_elem_add(m, AHASH_MAX(h), h->dsize); | 583 | ret = hbucket_elem_add(m, AHASH_MAX(h), set->dsize); |
| 558 | if (ret < 0) { | 584 | if (ret < 0) { |
| 559 | #ifdef IP_SET_HASH_WITH_NETS | 585 | #ifdef IP_SET_HASH_WITH_NETS |
| 560 | mtype_data_reset_flags(data, &flags); | 586 | mtype_data_reset_flags(data, &flags); |
| 561 | #endif | 587 | #endif |
| 562 | read_unlock_bh(&set->lock); | 588 | read_unlock_bh(&set->lock); |
| 563 | ahash_destroy(t); | 589 | mtype_ahash_destroy(set, t, false); |
| 564 | if (ret == -EAGAIN) | 590 | if (ret == -EAGAIN) |
| 565 | goto retry; | 591 | goto retry; |
| 566 | return ret; | 592 | return ret; |
| 567 | } | 593 | } |
| 568 | d = ahash_data(m, m->pos++, h->dsize); | 594 | d = ahash_data(m, m->pos++, set->dsize); |
| 569 | memcpy(d, data, h->dsize); | 595 | memcpy(d, data, set->dsize); |
| 570 | #ifdef IP_SET_HASH_WITH_NETS | 596 | #ifdef IP_SET_HASH_WITH_NETS |
| 571 | mtype_data_reset_flags(d, &flags); | 597 | mtype_data_reset_flags(d, &flags); |
| 572 | #endif | 598 | #endif |
| @@ -581,7 +607,7 @@ retry: | |||
| 581 | 607 | ||
| 582 | pr_debug("set %s resized from %u (%p) to %u (%p)\n", set->name, | 608 | pr_debug("set %s resized from %u (%p) to %u (%p)\n", set->name, |
| 583 | orig->htable_bits, orig, t->htable_bits, t); | 609 | orig->htable_bits, orig, t->htable_bits, t); |
| 584 | ahash_destroy(orig); | 610 | mtype_ahash_destroy(set, orig, false); |
| 585 | 611 | ||
| 586 | return 0; | 612 | return 0; |
| 587 | } | 613 | } |
| @@ -604,7 +630,7 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext, | |||
| 604 | 630 | ||
| 605 | if (SET_WITH_TIMEOUT(set) && h->elements >= h->maxelem) | 631 | if (SET_WITH_TIMEOUT(set) && h->elements >= h->maxelem) |
| 606 | /* FIXME: when set is full, we slow down here */ | 632 | /* FIXME: when set is full, we slow down here */ |
| 607 | mtype_expire(h, NETS_LENGTH(set->family), h->dsize); | 633 | mtype_expire(set, h, NLEN(set->family), set->dsize); |
| 608 | 634 | ||
| 609 | if (h->elements >= h->maxelem) { | 635 | if (h->elements >= h->maxelem) { |
| 610 | if (net_ratelimit()) | 636 | if (net_ratelimit()) |
| @@ -618,11 +644,11 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext, | |||
| 618 | key = HKEY(value, h->initval, t->htable_bits); | 644 | key = HKEY(value, h->initval, t->htable_bits); |
| 619 | n = hbucket(t, key); | 645 | n = hbucket(t, key); |
| 620 | for (i = 0; i < n->pos; i++) { | 646 | for (i = 0; i < n->pos; i++) { |
| 621 | data = ahash_data(n, i, h->dsize); | 647 | data = ahash_data(n, i, set->dsize); |
| 622 | if (mtype_data_equal(data, d, &multi)) { | 648 | if (mtype_data_equal(data, d, &multi)) { |
| 623 | if (flag_exist || | 649 | if (flag_exist || |
| 624 | (SET_WITH_TIMEOUT(set) && | 650 | (SET_WITH_TIMEOUT(set) && |
| 625 | ip_set_timeout_expired(ext_timeout(data, h)))) { | 651 | ip_set_timeout_expired(ext_timeout(data, set)))) { |
| 626 | /* Just the extensions could be overwritten */ | 652 | /* Just the extensions could be overwritten */ |
| 627 | j = i; | 653 | j = i; |
| 628 | goto reuse_slot; | 654 | goto reuse_slot; |
| @@ -633,30 +659,37 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext, | |||
| 633 | } | 659 | } |
| 634 | /* Reuse first timed out entry */ | 660 | /* Reuse first timed out entry */ |
| 635 | if (SET_WITH_TIMEOUT(set) && | 661 | if (SET_WITH_TIMEOUT(set) && |
| 636 | ip_set_timeout_expired(ext_timeout(data, h)) && | 662 | ip_set_timeout_expired(ext_timeout(data, set)) && |
| 637 | j != AHASH_MAX(h) + 1) | 663 | j != AHASH_MAX(h) + 1) |
| 638 | j = i; | 664 | j = i; |
| 639 | } | 665 | } |
| 640 | reuse_slot: | 666 | reuse_slot: |
| 641 | if (j != AHASH_MAX(h) + 1) { | 667 | if (j != AHASH_MAX(h) + 1) { |
| 642 | /* Fill out reused slot */ | 668 | /* Fill out reused slot */ |
| 643 | data = ahash_data(n, j, h->dsize); | 669 | data = ahash_data(n, j, set->dsize); |
| 644 | #ifdef IP_SET_HASH_WITH_NETS | 670 | #ifdef IP_SET_HASH_WITH_NETS |
| 645 | mtype_del_cidr(h, CIDR(data->cidr), NETS_LENGTH(set->family)); | 671 | for (i = 0; i < IPSET_NET_COUNT; i++) { |
| 646 | mtype_add_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family)); | 672 | mtype_del_cidr(h, CIDR(data->cidr, i), |
| 673 | NLEN(set->family), i); | ||
| 674 | mtype_add_cidr(h, CIDR(d->cidr, i), | ||
| 675 | NLEN(set->family), i); | ||
| 676 | } | ||
| 647 | #endif | 677 | #endif |
| 678 | ip_set_ext_destroy(set, data); | ||
| 648 | } else { | 679 | } else { |
| 649 | /* Use/create a new slot */ | 680 | /* Use/create a new slot */ |
| 650 | TUNE_AHASH_MAX(h, multi); | 681 | TUNE_AHASH_MAX(h, multi); |
| 651 | ret = hbucket_elem_add(n, AHASH_MAX(h), h->dsize); | 682 | ret = hbucket_elem_add(n, AHASH_MAX(h), set->dsize); |
| 652 | if (ret != 0) { | 683 | if (ret != 0) { |
| 653 | if (ret == -EAGAIN) | 684 | if (ret == -EAGAIN) |
| 654 | mtype_data_next(&h->next, d); | 685 | mtype_data_next(&h->next, d); |
| 655 | goto out; | 686 | goto out; |
| 656 | } | 687 | } |
| 657 | data = ahash_data(n, n->pos++, h->dsize); | 688 | data = ahash_data(n, n->pos++, set->dsize); |
| 658 | #ifdef IP_SET_HASH_WITH_NETS | 689 | #ifdef IP_SET_HASH_WITH_NETS |
| 659 | mtype_add_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family)); | 690 | for (i = 0; i < IPSET_NET_COUNT; i++) |
| 691 | mtype_add_cidr(h, CIDR(d->cidr, i), NLEN(set->family), | ||
| 692 | i); | ||
| 660 | #endif | 693 | #endif |
| 661 | h->elements++; | 694 | h->elements++; |
| 662 | } | 695 | } |
| @@ -665,9 +698,11 @@ reuse_slot: | |||
| 665 | mtype_data_set_flags(data, flags); | 698 | mtype_data_set_flags(data, flags); |
| 666 | #endif | 699 | #endif |
| 667 | if (SET_WITH_TIMEOUT(set)) | 700 | if (SET_WITH_TIMEOUT(set)) |
| 668 | ip_set_timeout_set(ext_timeout(data, h), ext->timeout); | 701 | ip_set_timeout_set(ext_timeout(data, set), ext->timeout); |
| 669 | if (SET_WITH_COUNTER(set)) | 702 | if (SET_WITH_COUNTER(set)) |
| 670 | ip_set_init_counter(ext_counter(data, h), ext); | 703 | ip_set_init_counter(ext_counter(data, set), ext); |
| 704 | if (SET_WITH_COMMENT(set)) | ||
| 705 | ip_set_init_comment(ext_comment(data, set), ext); | ||
| 671 | 706 | ||
| 672 | out: | 707 | out: |
| 673 | rcu_read_unlock_bh(); | 708 | rcu_read_unlock_bh(); |
| @@ -682,47 +717,60 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext, | |||
| 682 | struct ip_set_ext *mext, u32 flags) | 717 | struct ip_set_ext *mext, u32 flags) |
| 683 | { | 718 | { |
| 684 | struct htype *h = set->data; | 719 | struct htype *h = set->data; |
| 685 | struct htable *t = h->table; | 720 | struct htable *t; |
| 686 | const struct mtype_elem *d = value; | 721 | const struct mtype_elem *d = value; |
| 687 | struct mtype_elem *data; | 722 | struct mtype_elem *data; |
| 688 | struct hbucket *n; | 723 | struct hbucket *n; |
| 689 | int i; | 724 | int i, ret = -IPSET_ERR_EXIST; |
| 725 | #ifdef IP_SET_HASH_WITH_NETS | ||
| 726 | u8 j; | ||
| 727 | #endif | ||
| 690 | u32 key, multi = 0; | 728 | u32 key, multi = 0; |
| 691 | 729 | ||
| 730 | rcu_read_lock_bh(); | ||
| 731 | t = rcu_dereference_bh(h->table); | ||
| 692 | key = HKEY(value, h->initval, t->htable_bits); | 732 | key = HKEY(value, h->initval, t->htable_bits); |
| 693 | n = hbucket(t, key); | 733 | n = hbucket(t, key); |
| 694 | for (i = 0; i < n->pos; i++) { | 734 | for (i = 0; i < n->pos; i++) { |
| 695 | data = ahash_data(n, i, h->dsize); | 735 | data = ahash_data(n, i, set->dsize); |
| 696 | if (!mtype_data_equal(data, d, &multi)) | 736 | if (!mtype_data_equal(data, d, &multi)) |
| 697 | continue; | 737 | continue; |
| 698 | if (SET_WITH_TIMEOUT(set) && | 738 | if (SET_WITH_TIMEOUT(set) && |
| 699 | ip_set_timeout_expired(ext_timeout(data, h))) | 739 | ip_set_timeout_expired(ext_timeout(data, set))) |
| 700 | return -IPSET_ERR_EXIST; | 740 | goto out; |
| 701 | if (i != n->pos - 1) | 741 | if (i != n->pos - 1) |
| 702 | /* Not last one */ | 742 | /* Not last one */ |
| 703 | memcpy(data, ahash_data(n, n->pos - 1, h->dsize), | 743 | memcpy(data, ahash_data(n, n->pos - 1, set->dsize), |
| 704 | h->dsize); | 744 | set->dsize); |
| 705 | 745 | ||
| 706 | n->pos--; | 746 | n->pos--; |
| 707 | h->elements--; | 747 | h->elements--; |
| 708 | #ifdef IP_SET_HASH_WITH_NETS | 748 | #ifdef IP_SET_HASH_WITH_NETS |
| 709 | mtype_del_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family)); | 749 | for (j = 0; j < IPSET_NET_COUNT; j++) |
| 750 | mtype_del_cidr(h, CIDR(d->cidr, j), NLEN(set->family), | ||
| 751 | j); | ||
| 710 | #endif | 752 | #endif |
| 753 | ip_set_ext_destroy(set, data); | ||
| 711 | if (n->pos + AHASH_INIT_SIZE < n->size) { | 754 | if (n->pos + AHASH_INIT_SIZE < n->size) { |
| 712 | void *tmp = kzalloc((n->size - AHASH_INIT_SIZE) | 755 | void *tmp = kzalloc((n->size - AHASH_INIT_SIZE) |
| 713 | * h->dsize, | 756 | * set->dsize, |
| 714 | GFP_ATOMIC); | 757 | GFP_ATOMIC); |
| 715 | if (!tmp) | 758 | if (!tmp) { |
| 716 | return 0; | 759 | ret = 0; |
| 760 | goto out; | ||
| 761 | } | ||
| 717 | n->size -= AHASH_INIT_SIZE; | 762 | n->size -= AHASH_INIT_SIZE; |
| 718 | memcpy(tmp, n->value, n->size * h->dsize); | 763 | memcpy(tmp, n->value, n->size * set->dsize); |
| 719 | kfree(n->value); | 764 | kfree(n->value); |
| 720 | n->value = tmp; | 765 | n->value = tmp; |
| 721 | } | 766 | } |
| 722 | return 0; | 767 | ret = 0; |
| 768 | goto out; | ||
| 723 | } | 769 | } |
| 724 | 770 | ||
| 725 | return -IPSET_ERR_EXIST; | 771 | out: |
| 772 | rcu_read_unlock_bh(); | ||
| 773 | return ret; | ||
| 726 | } | 774 | } |
| 727 | 775 | ||
| 728 | static inline int | 776 | static inline int |
| @@ -730,8 +778,7 @@ mtype_data_match(struct mtype_elem *data, const struct ip_set_ext *ext, | |||
| 730 | struct ip_set_ext *mext, struct ip_set *set, u32 flags) | 778 | struct ip_set_ext *mext, struct ip_set *set, u32 flags) |
| 731 | { | 779 | { |
| 732 | if (SET_WITH_COUNTER(set)) | 780 | if (SET_WITH_COUNTER(set)) |
| 733 | ip_set_update_counter(ext_counter(data, | 781 | ip_set_update_counter(ext_counter(data, set), |
| 734 | (struct htype *)(set->data)), | ||
| 735 | ext, mext, flags); | 782 | ext, mext, flags); |
| 736 | return mtype_do_data_match(data); | 783 | return mtype_do_data_match(data); |
| 737 | } | 784 | } |
| @@ -745,25 +792,38 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d, | |||
| 745 | struct ip_set_ext *mext, u32 flags) | 792 | struct ip_set_ext *mext, u32 flags) |
| 746 | { | 793 | { |
| 747 | struct htype *h = set->data; | 794 | struct htype *h = set->data; |
| 748 | struct htable *t = h->table; | 795 | struct htable *t = rcu_dereference_bh(h->table); |
| 749 | struct hbucket *n; | 796 | struct hbucket *n; |
| 750 | struct mtype_elem *data; | 797 | struct mtype_elem *data; |
| 798 | #if IPSET_NET_COUNT == 2 | ||
| 799 | struct mtype_elem orig = *d; | ||
| 800 | int i, j = 0, k; | ||
| 801 | #else | ||
| 751 | int i, j = 0; | 802 | int i, j = 0; |
| 803 | #endif | ||
| 752 | u32 key, multi = 0; | 804 | u32 key, multi = 0; |
| 753 | u8 nets_length = NETS_LENGTH(set->family); | 805 | u8 nets_length = NLEN(set->family); |
| 754 | 806 | ||
| 755 | pr_debug("test by nets\n"); | 807 | pr_debug("test by nets\n"); |
| 756 | for (; j < nets_length && h->nets[j].nets && !multi; j++) { | 808 | for (; j < nets_length && h->nets[j].nets[0] && !multi; j++) { |
| 757 | mtype_data_netmask(d, h->nets[j].cidr); | 809 | #if IPSET_NET_COUNT == 2 |
| 810 | mtype_data_reset_elem(d, &orig); | ||
| 811 | mtype_data_netmask(d, h->nets[j].cidr[0], false); | ||
| 812 | for (k = 0; k < nets_length && h->nets[k].nets[1] && !multi; | ||
| 813 | k++) { | ||
| 814 | mtype_data_netmask(d, h->nets[k].cidr[1], true); | ||
| 815 | #else | ||
| 816 | mtype_data_netmask(d, h->nets[j].cidr[0]); | ||
| 817 | #endif | ||
| 758 | key = HKEY(d, h->initval, t->htable_bits); | 818 | key = HKEY(d, h->initval, t->htable_bits); |
| 759 | n = hbucket(t, key); | 819 | n = hbucket(t, key); |
| 760 | for (i = 0; i < n->pos; i++) { | 820 | for (i = 0; i < n->pos; i++) { |
| 761 | data = ahash_data(n, i, h->dsize); | 821 | data = ahash_data(n, i, set->dsize); |
| 762 | if (!mtype_data_equal(data, d, &multi)) | 822 | if (!mtype_data_equal(data, d, &multi)) |
| 763 | continue; | 823 | continue; |
| 764 | if (SET_WITH_TIMEOUT(set)) { | 824 | if (SET_WITH_TIMEOUT(set)) { |
| 765 | if (!ip_set_timeout_expired( | 825 | if (!ip_set_timeout_expired( |
| 766 | ext_timeout(data, h))) | 826 | ext_timeout(data, set))) |
| 767 | return mtype_data_match(data, ext, | 827 | return mtype_data_match(data, ext, |
| 768 | mext, set, | 828 | mext, set, |
| 769 | flags); | 829 | flags); |
| @@ -774,6 +834,9 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d, | |||
| 774 | return mtype_data_match(data, ext, | 834 | return mtype_data_match(data, ext, |
| 775 | mext, set, flags); | 835 | mext, set, flags); |
| 776 | } | 836 | } |
| 837 | #if IPSET_NET_COUNT == 2 | ||
| 838 | } | ||
| 839 | #endif | ||
| 777 | } | 840 | } |
| 778 | return 0; | 841 | return 0; |
| 779 | } | 842 | } |
| @@ -785,30 +848,41 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext, | |||
| 785 | struct ip_set_ext *mext, u32 flags) | 848 | struct ip_set_ext *mext, u32 flags) |
| 786 | { | 849 | { |
| 787 | struct htype *h = set->data; | 850 | struct htype *h = set->data; |
| 788 | struct htable *t = h->table; | 851 | struct htable *t; |
| 789 | struct mtype_elem *d = value; | 852 | struct mtype_elem *d = value; |
| 790 | struct hbucket *n; | 853 | struct hbucket *n; |
| 791 | struct mtype_elem *data; | 854 | struct mtype_elem *data; |
| 792 | int i; | 855 | int i, ret = 0; |
| 793 | u32 key, multi = 0; | 856 | u32 key, multi = 0; |
| 794 | 857 | ||
| 858 | rcu_read_lock_bh(); | ||
| 859 | t = rcu_dereference_bh(h->table); | ||
| 795 | #ifdef IP_SET_HASH_WITH_NETS | 860 | #ifdef IP_SET_HASH_WITH_NETS |
| 796 | /* If we test an IP address and not a network address, | 861 | /* If we test an IP address and not a network address, |
| 797 | * try all possible network sizes */ | 862 | * try all possible network sizes */ |
| 798 | if (CIDR(d->cidr) == SET_HOST_MASK(set->family)) | 863 | for (i = 0; i < IPSET_NET_COUNT; i++) |
| 799 | return mtype_test_cidrs(set, d, ext, mext, flags); | 864 | if (CIDR(d->cidr, i) != SET_HOST_MASK(set->family)) |
| 865 | break; | ||
| 866 | if (i == IPSET_NET_COUNT) { | ||
| 867 | ret = mtype_test_cidrs(set, d, ext, mext, flags); | ||
| 868 | goto out; | ||
| 869 | } | ||
| 800 | #endif | 870 | #endif |
| 801 | 871 | ||
| 802 | key = HKEY(d, h->initval, t->htable_bits); | 872 | key = HKEY(d, h->initval, t->htable_bits); |
| 803 | n = hbucket(t, key); | 873 | n = hbucket(t, key); |
| 804 | for (i = 0; i < n->pos; i++) { | 874 | for (i = 0; i < n->pos; i++) { |
| 805 | data = ahash_data(n, i, h->dsize); | 875 | data = ahash_data(n, i, set->dsize); |
| 806 | if (mtype_data_equal(data, d, &multi) && | 876 | if (mtype_data_equal(data, d, &multi) && |
| 807 | !(SET_WITH_TIMEOUT(set) && | 877 | !(SET_WITH_TIMEOUT(set) && |
| 808 | ip_set_timeout_expired(ext_timeout(data, h)))) | 878 | ip_set_timeout_expired(ext_timeout(data, set)))) { |
| 809 | return mtype_data_match(data, ext, mext, set, flags); | 879 | ret = mtype_data_match(data, ext, mext, set, flags); |
| 880 | goto out; | ||
| 881 | } | ||
| 810 | } | 882 | } |
| 811 | return 0; | 883 | out: |
| 884 | rcu_read_unlock_bh(); | ||
| 885 | return ret; | ||
| 812 | } | 886 | } |
| 813 | 887 | ||
| 814 | /* Reply a HEADER request: fill out the header part of the set */ | 888 | /* Reply a HEADER request: fill out the header part of the set */ |
| @@ -816,18 +890,18 @@ static int | |||
| 816 | mtype_head(struct ip_set *set, struct sk_buff *skb) | 890 | mtype_head(struct ip_set *set, struct sk_buff *skb) |
| 817 | { | 891 | { |
| 818 | const struct htype *h = set->data; | 892 | const struct htype *h = set->data; |
| 893 | const struct htable *t; | ||
| 819 | struct nlattr *nested; | 894 | struct nlattr *nested; |
| 820 | size_t memsize; | 895 | size_t memsize; |
| 821 | 896 | ||
| 822 | read_lock_bh(&set->lock); | 897 | t = rcu_dereference_bh_nfnl(h->table); |
| 823 | memsize = mtype_ahash_memsize(h, NETS_LENGTH(set->family)); | 898 | memsize = mtype_ahash_memsize(h, t, NLEN(set->family), set->dsize); |
| 824 | read_unlock_bh(&set->lock); | ||
| 825 | 899 | ||
| 826 | nested = ipset_nest_start(skb, IPSET_ATTR_DATA); | 900 | nested = ipset_nest_start(skb, IPSET_ATTR_DATA); |
| 827 | if (!nested) | 901 | if (!nested) |
| 828 | goto nla_put_failure; | 902 | goto nla_put_failure; |
| 829 | if (nla_put_net32(skb, IPSET_ATTR_HASHSIZE, | 903 | if (nla_put_net32(skb, IPSET_ATTR_HASHSIZE, |
| 830 | htonl(jhash_size(h->table->htable_bits))) || | 904 | htonl(jhash_size(t->htable_bits))) || |
| 831 | nla_put_net32(skb, IPSET_ATTR_MAXELEM, htonl(h->maxelem))) | 905 | nla_put_net32(skb, IPSET_ATTR_MAXELEM, htonl(h->maxelem))) |
| 832 | goto nla_put_failure; | 906 | goto nla_put_failure; |
| 833 | #ifdef IP_SET_HASH_WITH_NETMASK | 907 | #ifdef IP_SET_HASH_WITH_NETMASK |
| @@ -836,12 +910,9 @@ mtype_head(struct ip_set *set, struct sk_buff *skb) | |||
| 836 | goto nla_put_failure; | 910 | goto nla_put_failure; |
| 837 | #endif | 911 | #endif |
| 838 | if (nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) || | 912 | if (nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) || |
| 839 | nla_put_net32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)) || | 913 | nla_put_net32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize))) |
| 840 | ((set->extensions & IPSET_EXT_TIMEOUT) && | 914 | goto nla_put_failure; |
| 841 | nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(h->timeout))) || | 915 | if (unlikely(ip_set_put_flags(skb, set))) |
| 842 | ((set->extensions & IPSET_EXT_COUNTER) && | ||
| 843 | nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, | ||
| 844 | htonl(IPSET_FLAG_WITH_COUNTERS)))) | ||
| 845 | goto nla_put_failure; | 916 | goto nla_put_failure; |
| 846 | ipset_nest_end(skb, nested); | 917 | ipset_nest_end(skb, nested); |
| 847 | 918 | ||
| @@ -856,7 +927,7 @@ mtype_list(const struct ip_set *set, | |||
| 856 | struct sk_buff *skb, struct netlink_callback *cb) | 927 | struct sk_buff *skb, struct netlink_callback *cb) |
| 857 | { | 928 | { |
| 858 | const struct htype *h = set->data; | 929 | const struct htype *h = set->data; |
| 859 | const struct htable *t = h->table; | 930 | const struct htable *t = rcu_dereference_bh_nfnl(h->table); |
| 860 | struct nlattr *atd, *nested; | 931 | struct nlattr *atd, *nested; |
| 861 | const struct hbucket *n; | 932 | const struct hbucket *n; |
| 862 | const struct mtype_elem *e; | 933 | const struct mtype_elem *e; |
| @@ -874,9 +945,9 @@ mtype_list(const struct ip_set *set, | |||
| 874 | n = hbucket(t, cb->args[2]); | 945 | n = hbucket(t, cb->args[2]); |
| 875 | pr_debug("cb->args[2]: %lu, t %p n %p\n", cb->args[2], t, n); | 946 | pr_debug("cb->args[2]: %lu, t %p n %p\n", cb->args[2], t, n); |
| 876 | for (i = 0; i < n->pos; i++) { | 947 | for (i = 0; i < n->pos; i++) { |
| 877 | e = ahash_data(n, i, h->dsize); | 948 | e = ahash_data(n, i, set->dsize); |
| 878 | if (SET_WITH_TIMEOUT(set) && | 949 | if (SET_WITH_TIMEOUT(set) && |
| 879 | ip_set_timeout_expired(ext_timeout(e, h))) | 950 | ip_set_timeout_expired(ext_timeout(e, set))) |
| 880 | continue; | 951 | continue; |
| 881 | pr_debug("list hash %lu hbucket %p i %u, data %p\n", | 952 | pr_debug("list hash %lu hbucket %p i %u, data %p\n", |
| 882 | cb->args[2], n, i, e); | 953 | cb->args[2], n, i, e); |
| @@ -890,13 +961,7 @@ mtype_list(const struct ip_set *set, | |||
| 890 | } | 961 | } |
| 891 | if (mtype_data_list(skb, e)) | 962 | if (mtype_data_list(skb, e)) |
| 892 | goto nla_put_failure; | 963 | goto nla_put_failure; |
| 893 | if (SET_WITH_TIMEOUT(set) && | 964 | if (ip_set_put_extensions(skb, set, e, true)) |
| 894 | nla_put_net32(skb, IPSET_ATTR_TIMEOUT, | ||
| 895 | htonl(ip_set_timeout_get( | ||
| 896 | ext_timeout(e, h))))) | ||
| 897 | goto nla_put_failure; | ||
| 898 | if (SET_WITH_COUNTER(set) && | ||
| 899 | ip_set_put_counter(skb, ext_counter(e, h))) | ||
| 900 | goto nla_put_failure; | 965 | goto nla_put_failure; |
| 901 | ipset_nest_end(skb, nested); | 966 | ipset_nest_end(skb, nested); |
| 902 | } | 967 | } |
| @@ -909,24 +974,24 @@ mtype_list(const struct ip_set *set, | |||
| 909 | 974 | ||
| 910 | nla_put_failure: | 975 | nla_put_failure: |
| 911 | nlmsg_trim(skb, incomplete); | 976 | nlmsg_trim(skb, incomplete); |
| 912 | ipset_nest_end(skb, atd); | ||
| 913 | if (unlikely(first == cb->args[2])) { | 977 | if (unlikely(first == cb->args[2])) { |
| 914 | pr_warning("Can't list set %s: one bucket does not fit into " | 978 | pr_warning("Can't list set %s: one bucket does not fit into " |
| 915 | "a message. Please report it!\n", set->name); | 979 | "a message. Please report it!\n", set->name); |
| 916 | cb->args[2] = 0; | 980 | cb->args[2] = 0; |
| 917 | return -EMSGSIZE; | 981 | return -EMSGSIZE; |
| 918 | } | 982 | } |
| 983 | ipset_nest_end(skb, atd); | ||
| 919 | return 0; | 984 | return 0; |
| 920 | } | 985 | } |
| 921 | 986 | ||
| 922 | static int | 987 | static int |
| 923 | TOKEN(MTYPE, _kadt)(struct ip_set *set, const struct sk_buff *skb, | 988 | IPSET_TOKEN(MTYPE, _kadt)(struct ip_set *set, const struct sk_buff *skb, |
| 924 | const struct xt_action_param *par, | 989 | const struct xt_action_param *par, |
| 925 | enum ipset_adt adt, struct ip_set_adt_opt *opt); | 990 | enum ipset_adt adt, struct ip_set_adt_opt *opt); |
| 926 | 991 | ||
| 927 | static int | 992 | static int |
| 928 | TOKEN(MTYPE, _uadt)(struct ip_set *set, struct nlattr *tb[], | 993 | IPSET_TOKEN(MTYPE, _uadt)(struct ip_set *set, struct nlattr *tb[], |
| 929 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried); | 994 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried); |
| 930 | 995 | ||
| 931 | static const struct ip_set_type_variant mtype_variant = { | 996 | static const struct ip_set_type_variant mtype_variant = { |
| 932 | .kadt = mtype_kadt, | 997 | .kadt = mtype_kadt, |
| @@ -946,16 +1011,17 @@ static const struct ip_set_type_variant mtype_variant = { | |||
| 946 | 1011 | ||
| 947 | #ifdef IP_SET_EMIT_CREATE | 1012 | #ifdef IP_SET_EMIT_CREATE |
| 948 | static int | 1013 | static int |
| 949 | TOKEN(HTYPE, _create)(struct ip_set *set, struct nlattr *tb[], u32 flags) | 1014 | IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set, |
| 1015 | struct nlattr *tb[], u32 flags) | ||
| 950 | { | 1016 | { |
| 951 | u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; | 1017 | u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; |
| 952 | u32 cadt_flags = 0; | ||
| 953 | u8 hbits; | 1018 | u8 hbits; |
| 954 | #ifdef IP_SET_HASH_WITH_NETMASK | 1019 | #ifdef IP_SET_HASH_WITH_NETMASK |
| 955 | u8 netmask; | 1020 | u8 netmask; |
| 956 | #endif | 1021 | #endif |
| 957 | size_t hsize; | 1022 | size_t hsize; |
| 958 | struct HTYPE *h; | 1023 | struct HTYPE *h; |
| 1024 | struct htable *t; | ||
| 959 | 1025 | ||
| 960 | if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) | 1026 | if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) |
| 961 | return -IPSET_ERR_INVALID_FAMILY; | 1027 | return -IPSET_ERR_INVALID_FAMILY; |
| @@ -1005,7 +1071,7 @@ TOKEN(HTYPE, _create)(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
| 1005 | h->netmask = netmask; | 1071 | h->netmask = netmask; |
| 1006 | #endif | 1072 | #endif |
| 1007 | get_random_bytes(&h->initval, sizeof(h->initval)); | 1073 | get_random_bytes(&h->initval, sizeof(h->initval)); |
| 1008 | h->timeout = IPSET_NO_TIMEOUT; | 1074 | set->timeout = IPSET_NO_TIMEOUT; |
| 1009 | 1075 | ||
| 1010 | hbits = htable_bits(hashsize); | 1076 | hbits = htable_bits(hashsize); |
| 1011 | hsize = htable_size(hbits); | 1077 | hsize = htable_size(hbits); |
| @@ -1013,91 +1079,37 @@ TOKEN(HTYPE, _create)(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
| 1013 | kfree(h); | 1079 | kfree(h); |
| 1014 | return -ENOMEM; | 1080 | return -ENOMEM; |
| 1015 | } | 1081 | } |
| 1016 | h->table = ip_set_alloc(hsize); | 1082 | t = ip_set_alloc(hsize); |
| 1017 | if (!h->table) { | 1083 | if (!t) { |
| 1018 | kfree(h); | 1084 | kfree(h); |
| 1019 | return -ENOMEM; | 1085 | return -ENOMEM; |
| 1020 | } | 1086 | } |
| 1021 | h->table->htable_bits = hbits; | 1087 | t->htable_bits = hbits; |
| 1088 | rcu_assign_pointer(h->table, t); | ||
| 1022 | 1089 | ||
| 1023 | set->data = h; | 1090 | set->data = h; |
| 1024 | if (set->family == NFPROTO_IPV4) | 1091 | if (set->family == NFPROTO_IPV4) { |
| 1025 | set->variant = &TOKEN(HTYPE, 4_variant); | 1092 | set->variant = &IPSET_TOKEN(HTYPE, 4_variant); |
| 1026 | else | 1093 | set->dsize = ip_set_elem_len(set, tb, |
| 1027 | set->variant = &TOKEN(HTYPE, 6_variant); | 1094 | sizeof(struct IPSET_TOKEN(HTYPE, 4_elem))); |
| 1028 | |||
| 1029 | if (tb[IPSET_ATTR_CADT_FLAGS]) | ||
| 1030 | cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); | ||
| 1031 | if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) { | ||
| 1032 | set->extensions |= IPSET_EXT_COUNTER; | ||
| 1033 | if (tb[IPSET_ATTR_TIMEOUT]) { | ||
| 1034 | h->timeout = | ||
| 1035 | ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | ||
| 1036 | set->extensions |= IPSET_EXT_TIMEOUT; | ||
| 1037 | if (set->family == NFPROTO_IPV4) { | ||
| 1038 | h->dsize = | ||
| 1039 | sizeof(struct TOKEN(HTYPE, 4ct_elem)); | ||
| 1040 | h->offset[IPSET_OFFSET_TIMEOUT] = | ||
| 1041 | offsetof(struct TOKEN(HTYPE, 4ct_elem), | ||
| 1042 | timeout); | ||
| 1043 | h->offset[IPSET_OFFSET_COUNTER] = | ||
| 1044 | offsetof(struct TOKEN(HTYPE, 4ct_elem), | ||
| 1045 | counter); | ||
| 1046 | TOKEN(HTYPE, 4_gc_init)(set, | ||
| 1047 | TOKEN(HTYPE, 4_gc)); | ||
| 1048 | } else { | ||
| 1049 | h->dsize = | ||
| 1050 | sizeof(struct TOKEN(HTYPE, 6ct_elem)); | ||
| 1051 | h->offset[IPSET_OFFSET_TIMEOUT] = | ||
| 1052 | offsetof(struct TOKEN(HTYPE, 6ct_elem), | ||
| 1053 | timeout); | ||
| 1054 | h->offset[IPSET_OFFSET_COUNTER] = | ||
| 1055 | offsetof(struct TOKEN(HTYPE, 6ct_elem), | ||
| 1056 | counter); | ||
| 1057 | TOKEN(HTYPE, 6_gc_init)(set, | ||
| 1058 | TOKEN(HTYPE, 6_gc)); | ||
| 1059 | } | ||
| 1060 | } else { | ||
| 1061 | if (set->family == NFPROTO_IPV4) { | ||
| 1062 | h->dsize = | ||
| 1063 | sizeof(struct TOKEN(HTYPE, 4c_elem)); | ||
| 1064 | h->offset[IPSET_OFFSET_COUNTER] = | ||
| 1065 | offsetof(struct TOKEN(HTYPE, 4c_elem), | ||
| 1066 | counter); | ||
| 1067 | } else { | ||
| 1068 | h->dsize = | ||
| 1069 | sizeof(struct TOKEN(HTYPE, 6c_elem)); | ||
| 1070 | h->offset[IPSET_OFFSET_COUNTER] = | ||
| 1071 | offsetof(struct TOKEN(HTYPE, 6c_elem), | ||
| 1072 | counter); | ||
| 1073 | } | ||
| 1074 | } | ||
| 1075 | } else if (tb[IPSET_ATTR_TIMEOUT]) { | ||
| 1076 | h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | ||
| 1077 | set->extensions |= IPSET_EXT_TIMEOUT; | ||
| 1078 | if (set->family == NFPROTO_IPV4) { | ||
| 1079 | h->dsize = sizeof(struct TOKEN(HTYPE, 4t_elem)); | ||
| 1080 | h->offset[IPSET_OFFSET_TIMEOUT] = | ||
| 1081 | offsetof(struct TOKEN(HTYPE, 4t_elem), | ||
| 1082 | timeout); | ||
| 1083 | TOKEN(HTYPE, 4_gc_init)(set, TOKEN(HTYPE, 4_gc)); | ||
| 1084 | } else { | ||
| 1085 | h->dsize = sizeof(struct TOKEN(HTYPE, 6t_elem)); | ||
| 1086 | h->offset[IPSET_OFFSET_TIMEOUT] = | ||
| 1087 | offsetof(struct TOKEN(HTYPE, 6t_elem), | ||
| 1088 | timeout); | ||
| 1089 | TOKEN(HTYPE, 6_gc_init)(set, TOKEN(HTYPE, 6_gc)); | ||
| 1090 | } | ||
| 1091 | } else { | 1095 | } else { |
| 1096 | set->variant = &IPSET_TOKEN(HTYPE, 6_variant); | ||
| 1097 | set->dsize = ip_set_elem_len(set, tb, | ||
| 1098 | sizeof(struct IPSET_TOKEN(HTYPE, 6_elem))); | ||
| 1099 | } | ||
| 1100 | if (tb[IPSET_ATTR_TIMEOUT]) { | ||
| 1101 | set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | ||
| 1092 | if (set->family == NFPROTO_IPV4) | 1102 | if (set->family == NFPROTO_IPV4) |
| 1093 | h->dsize = sizeof(struct TOKEN(HTYPE, 4_elem)); | 1103 | IPSET_TOKEN(HTYPE, 4_gc_init)(set, |
| 1104 | IPSET_TOKEN(HTYPE, 4_gc)); | ||
| 1094 | else | 1105 | else |
| 1095 | h->dsize = sizeof(struct TOKEN(HTYPE, 6_elem)); | 1106 | IPSET_TOKEN(HTYPE, 6_gc_init)(set, |
| 1107 | IPSET_TOKEN(HTYPE, 6_gc)); | ||
| 1096 | } | 1108 | } |
| 1097 | 1109 | ||
| 1098 | pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n", | 1110 | pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n", |
| 1099 | set->name, jhash_size(h->table->htable_bits), | 1111 | set->name, jhash_size(t->htable_bits), |
| 1100 | h->table->htable_bits, h->maxelem, set->data, h->table); | 1112 | t->htable_bits, h->maxelem, set->data, t); |
| 1101 | 1113 | ||
| 1102 | return 0; | 1114 | return 0; |
| 1103 | } | 1115 | } |
diff --git a/net/netfilter/ipset/ip_set_hash_ip.c b/net/netfilter/ipset/ip_set_hash_ip.c index c74e6e14cd93..e65fc2423d56 100644 --- a/net/netfilter/ipset/ip_set_hash_ip.c +++ b/net/netfilter/ipset/ip_set_hash_ip.c | |||
| @@ -23,19 +23,20 @@ | |||
| 23 | #include <linux/netfilter/ipset/ip_set.h> | 23 | #include <linux/netfilter/ipset/ip_set.h> |
| 24 | #include <linux/netfilter/ipset/ip_set_hash.h> | 24 | #include <linux/netfilter/ipset/ip_set_hash.h> |
| 25 | 25 | ||
| 26 | #define REVISION_MIN 0 | 26 | #define IPSET_TYPE_REV_MIN 0 |
| 27 | #define REVISION_MAX 1 /* Counters support */ | 27 | /* 1 Counters support */ |
| 28 | #define IPSET_TYPE_REV_MAX 2 /* Comments support */ | ||
| 28 | 29 | ||
| 29 | MODULE_LICENSE("GPL"); | 30 | MODULE_LICENSE("GPL"); |
| 30 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); | 31 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); |
| 31 | IP_SET_MODULE_DESC("hash:ip", REVISION_MIN, REVISION_MAX); | 32 | IP_SET_MODULE_DESC("hash:ip", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX); |
| 32 | MODULE_ALIAS("ip_set_hash:ip"); | 33 | MODULE_ALIAS("ip_set_hash:ip"); |
| 33 | 34 | ||
| 34 | /* Type specific function prefix */ | 35 | /* Type specific function prefix */ |
| 35 | #define HTYPE hash_ip | 36 | #define HTYPE hash_ip |
| 36 | #define IP_SET_HASH_WITH_NETMASK | 37 | #define IP_SET_HASH_WITH_NETMASK |
| 37 | 38 | ||
| 38 | /* IPv4 variants */ | 39 | /* IPv4 variant */ |
| 39 | 40 | ||
| 40 | /* Member elements */ | 41 | /* Member elements */ |
| 41 | struct hash_ip4_elem { | 42 | struct hash_ip4_elem { |
| @@ -43,22 +44,6 @@ struct hash_ip4_elem { | |||
| 43 | __be32 ip; | 44 | __be32 ip; |
| 44 | }; | 45 | }; |
| 45 | 46 | ||
| 46 | struct hash_ip4t_elem { | ||
| 47 | __be32 ip; | ||
| 48 | unsigned long timeout; | ||
| 49 | }; | ||
| 50 | |||
| 51 | struct hash_ip4c_elem { | ||
| 52 | __be32 ip; | ||
| 53 | struct ip_set_counter counter; | ||
| 54 | }; | ||
| 55 | |||
| 56 | struct hash_ip4ct_elem { | ||
| 57 | __be32 ip; | ||
| 58 | struct ip_set_counter counter; | ||
| 59 | unsigned long timeout; | ||
| 60 | }; | ||
| 61 | |||
| 62 | /* Common functions */ | 47 | /* Common functions */ |
| 63 | 48 | ||
| 64 | static inline bool | 49 | static inline bool |
| @@ -99,7 +84,7 @@ hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
| 99 | const struct hash_ip *h = set->data; | 84 | const struct hash_ip *h = set->data; |
| 100 | ipset_adtfn adtfn = set->variant->adt[adt]; | 85 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 101 | struct hash_ip4_elem e = {}; | 86 | struct hash_ip4_elem e = {}; |
| 102 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h); | 87 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); |
| 103 | __be32 ip; | 88 | __be32 ip; |
| 104 | 89 | ||
| 105 | ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip); | 90 | ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip); |
| @@ -118,8 +103,8 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 118 | const struct hash_ip *h = set->data; | 103 | const struct hash_ip *h = set->data; |
| 119 | ipset_adtfn adtfn = set->variant->adt[adt]; | 104 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 120 | struct hash_ip4_elem e = {}; | 105 | struct hash_ip4_elem e = {}; |
| 121 | struct ip_set_ext ext = IP_SET_INIT_UEXT(h); | 106 | struct ip_set_ext ext = IP_SET_INIT_UEXT(set); |
| 122 | u32 ip, ip_to, hosts; | 107 | u32 ip = 0, ip_to = 0, hosts; |
| 123 | int ret = 0; | 108 | int ret = 0; |
| 124 | 109 | ||
| 125 | if (unlikely(!tb[IPSET_ATTR_IP] || | 110 | if (unlikely(!tb[IPSET_ATTR_IP] || |
| @@ -178,29 +163,13 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 178 | return ret; | 163 | return ret; |
| 179 | } | 164 | } |
| 180 | 165 | ||
| 181 | /* IPv6 variants */ | 166 | /* IPv6 variant */ |
| 182 | 167 | ||
| 183 | /* Member elements */ | 168 | /* Member elements */ |
| 184 | struct hash_ip6_elem { | 169 | struct hash_ip6_elem { |
| 185 | union nf_inet_addr ip; | 170 | union nf_inet_addr ip; |
| 186 | }; | 171 | }; |
| 187 | 172 | ||
| 188 | struct hash_ip6t_elem { | ||
| 189 | union nf_inet_addr ip; | ||
| 190 | unsigned long timeout; | ||
| 191 | }; | ||
| 192 | |||
| 193 | struct hash_ip6c_elem { | ||
| 194 | union nf_inet_addr ip; | ||
| 195 | struct ip_set_counter counter; | ||
| 196 | }; | ||
| 197 | |||
| 198 | struct hash_ip6ct_elem { | ||
| 199 | union nf_inet_addr ip; | ||
| 200 | struct ip_set_counter counter; | ||
| 201 | unsigned long timeout; | ||
| 202 | }; | ||
| 203 | |||
| 204 | /* Common functions */ | 173 | /* Common functions */ |
| 205 | 174 | ||
| 206 | static inline bool | 175 | static inline bool |
| @@ -253,7 +222,7 @@ hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
| 253 | const struct hash_ip *h = set->data; | 222 | const struct hash_ip *h = set->data; |
| 254 | ipset_adtfn adtfn = set->variant->adt[adt]; | 223 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 255 | struct hash_ip6_elem e = {}; | 224 | struct hash_ip6_elem e = {}; |
| 256 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h); | 225 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); |
| 257 | 226 | ||
| 258 | ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6); | 227 | ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6); |
| 259 | hash_ip6_netmask(&e.ip, h->netmask); | 228 | hash_ip6_netmask(&e.ip, h->netmask); |
| @@ -270,7 +239,7 @@ hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 270 | const struct hash_ip *h = set->data; | 239 | const struct hash_ip *h = set->data; |
| 271 | ipset_adtfn adtfn = set->variant->adt[adt]; | 240 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 272 | struct hash_ip6_elem e = {}; | 241 | struct hash_ip6_elem e = {}; |
| 273 | struct ip_set_ext ext = IP_SET_INIT_UEXT(h); | 242 | struct ip_set_ext ext = IP_SET_INIT_UEXT(set); |
| 274 | int ret; | 243 | int ret; |
| 275 | 244 | ||
| 276 | if (unlikely(!tb[IPSET_ATTR_IP] || | 245 | if (unlikely(!tb[IPSET_ATTR_IP] || |
| @@ -304,8 +273,8 @@ static struct ip_set_type hash_ip_type __read_mostly = { | |||
| 304 | .features = IPSET_TYPE_IP, | 273 | .features = IPSET_TYPE_IP, |
| 305 | .dimension = IPSET_DIM_ONE, | 274 | .dimension = IPSET_DIM_ONE, |
| 306 | .family = NFPROTO_UNSPEC, | 275 | .family = NFPROTO_UNSPEC, |
| 307 | .revision_min = REVISION_MIN, | 276 | .revision_min = IPSET_TYPE_REV_MIN, |
| 308 | .revision_max = REVISION_MAX, | 277 | .revision_max = IPSET_TYPE_REV_MAX, |
| 309 | .create = hash_ip_create, | 278 | .create = hash_ip_create, |
| 310 | .create_policy = { | 279 | .create_policy = { |
| 311 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, | 280 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, |
| @@ -324,6 +293,7 @@ static struct ip_set_type hash_ip_type __read_mostly = { | |||
| 324 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, | 293 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, |
| 325 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | 294 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, |
| 326 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | 295 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, |
| 296 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | ||
| 327 | }, | 297 | }, |
| 328 | .me = THIS_MODULE, | 298 | .me = THIS_MODULE, |
| 329 | }; | 299 | }; |
diff --git a/net/netfilter/ipset/ip_set_hash_ipport.c b/net/netfilter/ipset/ip_set_hash_ipport.c index 7a2d2bd98d04..525a595dd1fe 100644 --- a/net/netfilter/ipset/ip_set_hash_ipport.c +++ b/net/netfilter/ipset/ip_set_hash_ipport.c | |||
| @@ -24,19 +24,20 @@ | |||
| 24 | #include <linux/netfilter/ipset/ip_set_getport.h> | 24 | #include <linux/netfilter/ipset/ip_set_getport.h> |
| 25 | #include <linux/netfilter/ipset/ip_set_hash.h> | 25 | #include <linux/netfilter/ipset/ip_set_hash.h> |
| 26 | 26 | ||
| 27 | #define REVISION_MIN 0 | 27 | #define IPSET_TYPE_REV_MIN 0 |
| 28 | /* 1 SCTP and UDPLITE support added */ | 28 | /* 1 SCTP and UDPLITE support added */ |
| 29 | #define REVISION_MAX 2 /* Counters support added */ | 29 | /* 2 Counters support added */ |
| 30 | #define IPSET_TYPE_REV_MAX 3 /* Comments support added */ | ||
| 30 | 31 | ||
| 31 | MODULE_LICENSE("GPL"); | 32 | MODULE_LICENSE("GPL"); |
| 32 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); | 33 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); |
| 33 | IP_SET_MODULE_DESC("hash:ip,port", REVISION_MIN, REVISION_MAX); | 34 | IP_SET_MODULE_DESC("hash:ip,port", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX); |
| 34 | MODULE_ALIAS("ip_set_hash:ip,port"); | 35 | MODULE_ALIAS("ip_set_hash:ip,port"); |
| 35 | 36 | ||
| 36 | /* Type specific function prefix */ | 37 | /* Type specific function prefix */ |
| 37 | #define HTYPE hash_ipport | 38 | #define HTYPE hash_ipport |
| 38 | 39 | ||
| 39 | /* IPv4 variants */ | 40 | /* IPv4 variant */ |
| 40 | 41 | ||
| 41 | /* Member elements */ | 42 | /* Member elements */ |
| 42 | struct hash_ipport4_elem { | 43 | struct hash_ipport4_elem { |
| @@ -46,31 +47,6 @@ struct hash_ipport4_elem { | |||
| 46 | u8 padding; | 47 | u8 padding; |
| 47 | }; | 48 | }; |
| 48 | 49 | ||
| 49 | struct hash_ipport4t_elem { | ||
| 50 | __be32 ip; | ||
| 51 | __be16 port; | ||
| 52 | u8 proto; | ||
| 53 | u8 padding; | ||
| 54 | unsigned long timeout; | ||
| 55 | }; | ||
| 56 | |||
| 57 | struct hash_ipport4c_elem { | ||
| 58 | __be32 ip; | ||
| 59 | __be16 port; | ||
| 60 | u8 proto; | ||
| 61 | u8 padding; | ||
| 62 | struct ip_set_counter counter; | ||
| 63 | }; | ||
| 64 | |||
| 65 | struct hash_ipport4ct_elem { | ||
| 66 | __be32 ip; | ||
| 67 | __be16 port; | ||
| 68 | u8 proto; | ||
| 69 | u8 padding; | ||
| 70 | struct ip_set_counter counter; | ||
| 71 | unsigned long timeout; | ||
| 72 | }; | ||
| 73 | |||
| 74 | /* Common functions */ | 50 | /* Common functions */ |
| 75 | 51 | ||
| 76 | static inline bool | 52 | static inline bool |
| @@ -116,10 +92,9 @@ hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
| 116 | const struct xt_action_param *par, | 92 | const struct xt_action_param *par, |
| 117 | enum ipset_adt adt, struct ip_set_adt_opt *opt) | 93 | enum ipset_adt adt, struct ip_set_adt_opt *opt) |
| 118 | { | 94 | { |
| 119 | const struct hash_ipport *h = set->data; | ||
| 120 | ipset_adtfn adtfn = set->variant->adt[adt]; | 95 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 121 | struct hash_ipport4_elem e = { }; | 96 | struct hash_ipport4_elem e = { }; |
| 122 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h); | 97 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); |
| 123 | 98 | ||
| 124 | if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC, | 99 | if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC, |
| 125 | &e.port, &e.proto)) | 100 | &e.port, &e.proto)) |
| @@ -136,8 +111,8 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 136 | const struct hash_ipport *h = set->data; | 111 | const struct hash_ipport *h = set->data; |
| 137 | ipset_adtfn adtfn = set->variant->adt[adt]; | 112 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 138 | struct hash_ipport4_elem e = { }; | 113 | struct hash_ipport4_elem e = { }; |
| 139 | struct ip_set_ext ext = IP_SET_INIT_UEXT(h); | 114 | struct ip_set_ext ext = IP_SET_INIT_UEXT(set); |
| 140 | u32 ip, ip_to, p = 0, port, port_to; | 115 | u32 ip, ip_to = 0, p = 0, port, port_to; |
| 141 | bool with_ports = false; | 116 | bool with_ports = false; |
| 142 | int ret; | 117 | int ret; |
| 143 | 118 | ||
| @@ -222,7 +197,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 222 | return ret; | 197 | return ret; |
| 223 | } | 198 | } |
| 224 | 199 | ||
| 225 | /* IPv6 variants */ | 200 | /* IPv6 variant */ |
| 226 | 201 | ||
| 227 | struct hash_ipport6_elem { | 202 | struct hash_ipport6_elem { |
| 228 | union nf_inet_addr ip; | 203 | union nf_inet_addr ip; |
| @@ -231,31 +206,6 @@ struct hash_ipport6_elem { | |||
| 231 | u8 padding; | 206 | u8 padding; |
| 232 | }; | 207 | }; |
| 233 | 208 | ||
| 234 | struct hash_ipport6t_elem { | ||
| 235 | union nf_inet_addr ip; | ||
| 236 | __be16 port; | ||
| 237 | u8 proto; | ||
| 238 | u8 padding; | ||
| 239 | unsigned long timeout; | ||
| 240 | }; | ||
| 241 | |||
| 242 | struct hash_ipport6c_elem { | ||
| 243 | union nf_inet_addr ip; | ||
| 244 | __be16 port; | ||
| 245 | u8 proto; | ||
| 246 | u8 padding; | ||
| 247 | struct ip_set_counter counter; | ||
| 248 | }; | ||
| 249 | |||
| 250 | struct hash_ipport6ct_elem { | ||
| 251 | union nf_inet_addr ip; | ||
| 252 | __be16 port; | ||
| 253 | u8 proto; | ||
| 254 | u8 padding; | ||
| 255 | struct ip_set_counter counter; | ||
| 256 | unsigned long timeout; | ||
| 257 | }; | ||
| 258 | |||
| 259 | /* Common functions */ | 209 | /* Common functions */ |
| 260 | 210 | ||
| 261 | static inline bool | 211 | static inline bool |
| @@ -306,10 +256,9 @@ hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
| 306 | const struct xt_action_param *par, | 256 | const struct xt_action_param *par, |
| 307 | enum ipset_adt adt, struct ip_set_adt_opt *opt) | 257 | enum ipset_adt adt, struct ip_set_adt_opt *opt) |
| 308 | { | 258 | { |
| 309 | const struct hash_ipport *h = set->data; | ||
| 310 | ipset_adtfn adtfn = set->variant->adt[adt]; | 259 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 311 | struct hash_ipport6_elem e = { }; | 260 | struct hash_ipport6_elem e = { }; |
| 312 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h); | 261 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); |
| 313 | 262 | ||
| 314 | if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC, | 263 | if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC, |
| 315 | &e.port, &e.proto)) | 264 | &e.port, &e.proto)) |
| @@ -326,7 +275,7 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 326 | const struct hash_ipport *h = set->data; | 275 | const struct hash_ipport *h = set->data; |
| 327 | ipset_adtfn adtfn = set->variant->adt[adt]; | 276 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 328 | struct hash_ipport6_elem e = { }; | 277 | struct hash_ipport6_elem e = { }; |
| 329 | struct ip_set_ext ext = IP_SET_INIT_UEXT(h); | 278 | struct ip_set_ext ext = IP_SET_INIT_UEXT(set); |
| 330 | u32 port, port_to; | 279 | u32 port, port_to; |
| 331 | bool with_ports = false; | 280 | bool with_ports = false; |
| 332 | int ret; | 281 | int ret; |
| @@ -396,8 +345,8 @@ static struct ip_set_type hash_ipport_type __read_mostly = { | |||
| 396 | .features = IPSET_TYPE_IP | IPSET_TYPE_PORT, | 345 | .features = IPSET_TYPE_IP | IPSET_TYPE_PORT, |
| 397 | .dimension = IPSET_DIM_TWO, | 346 | .dimension = IPSET_DIM_TWO, |
| 398 | .family = NFPROTO_UNSPEC, | 347 | .family = NFPROTO_UNSPEC, |
| 399 | .revision_min = REVISION_MIN, | 348 | .revision_min = IPSET_TYPE_REV_MIN, |
| 400 | .revision_max = REVISION_MAX, | 349 | .revision_max = IPSET_TYPE_REV_MAX, |
| 401 | .create = hash_ipport_create, | 350 | .create = hash_ipport_create, |
| 402 | .create_policy = { | 351 | .create_policy = { |
| 403 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, | 352 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, |
| @@ -419,6 +368,7 @@ static struct ip_set_type hash_ipport_type __read_mostly = { | |||
| 419 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, | 368 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, |
| 420 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | 369 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, |
| 421 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | 370 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, |
| 371 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | ||
| 422 | }, | 372 | }, |
| 423 | .me = THIS_MODULE, | 373 | .me = THIS_MODULE, |
| 424 | }; | 374 | }; |
diff --git a/net/netfilter/ipset/ip_set_hash_ipportip.c b/net/netfilter/ipset/ip_set_hash_ipportip.c index 34e8a1acce42..f5636631466e 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportip.c +++ b/net/netfilter/ipset/ip_set_hash_ipportip.c | |||
| @@ -24,19 +24,20 @@ | |||
| 24 | #include <linux/netfilter/ipset/ip_set_getport.h> | 24 | #include <linux/netfilter/ipset/ip_set_getport.h> |
| 25 | #include <linux/netfilter/ipset/ip_set_hash.h> | 25 | #include <linux/netfilter/ipset/ip_set_hash.h> |
| 26 | 26 | ||
| 27 | #define REVISION_MIN 0 | 27 | #define IPSET_TYPE_REV_MIN 0 |
| 28 | /* 1 SCTP and UDPLITE support added */ | 28 | /* 1 SCTP and UDPLITE support added */ |
| 29 | #define REVISION_MAX 2 /* Counters support added */ | 29 | /* 2 Counters support added */ |
| 30 | #define IPSET_TYPE_REV_MAX 3 /* Comments support added */ | ||
| 30 | 31 | ||
| 31 | MODULE_LICENSE("GPL"); | 32 | MODULE_LICENSE("GPL"); |
| 32 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); | 33 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); |
| 33 | IP_SET_MODULE_DESC("hash:ip,port,ip", REVISION_MIN, REVISION_MAX); | 34 | IP_SET_MODULE_DESC("hash:ip,port,ip", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX); |
| 34 | MODULE_ALIAS("ip_set_hash:ip,port,ip"); | 35 | MODULE_ALIAS("ip_set_hash:ip,port,ip"); |
| 35 | 36 | ||
| 36 | /* Type specific function prefix */ | 37 | /* Type specific function prefix */ |
| 37 | #define HTYPE hash_ipportip | 38 | #define HTYPE hash_ipportip |
| 38 | 39 | ||
| 39 | /* IPv4 variants */ | 40 | /* IPv4 variant */ |
| 40 | 41 | ||
| 41 | /* Member elements */ | 42 | /* Member elements */ |
| 42 | struct hash_ipportip4_elem { | 43 | struct hash_ipportip4_elem { |
| @@ -47,34 +48,6 @@ struct hash_ipportip4_elem { | |||
| 47 | u8 padding; | 48 | u8 padding; |
| 48 | }; | 49 | }; |
| 49 | 50 | ||
| 50 | struct hash_ipportip4t_elem { | ||
| 51 | __be32 ip; | ||
| 52 | __be32 ip2; | ||
| 53 | __be16 port; | ||
| 54 | u8 proto; | ||
| 55 | u8 padding; | ||
| 56 | unsigned long timeout; | ||
| 57 | }; | ||
| 58 | |||
| 59 | struct hash_ipportip4c_elem { | ||
| 60 | __be32 ip; | ||
| 61 | __be32 ip2; | ||
| 62 | __be16 port; | ||
| 63 | u8 proto; | ||
| 64 | u8 padding; | ||
| 65 | struct ip_set_counter counter; | ||
| 66 | }; | ||
| 67 | |||
| 68 | struct hash_ipportip4ct_elem { | ||
| 69 | __be32 ip; | ||
| 70 | __be32 ip2; | ||
| 71 | __be16 port; | ||
| 72 | u8 proto; | ||
| 73 | u8 padding; | ||
| 74 | struct ip_set_counter counter; | ||
| 75 | unsigned long timeout; | ||
| 76 | }; | ||
| 77 | |||
| 78 | static inline bool | 51 | static inline bool |
| 79 | hash_ipportip4_data_equal(const struct hash_ipportip4_elem *ip1, | 52 | hash_ipportip4_data_equal(const struct hash_ipportip4_elem *ip1, |
| 80 | const struct hash_ipportip4_elem *ip2, | 53 | const struct hash_ipportip4_elem *ip2, |
| @@ -120,10 +93,9 @@ hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
| 120 | const struct xt_action_param *par, | 93 | const struct xt_action_param *par, |
| 121 | enum ipset_adt adt, struct ip_set_adt_opt *opt) | 94 | enum ipset_adt adt, struct ip_set_adt_opt *opt) |
| 122 | { | 95 | { |
| 123 | const struct hash_ipportip *h = set->data; | ||
| 124 | ipset_adtfn adtfn = set->variant->adt[adt]; | 96 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 125 | struct hash_ipportip4_elem e = { }; | 97 | struct hash_ipportip4_elem e = { }; |
| 126 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h); | 98 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); |
| 127 | 99 | ||
| 128 | if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC, | 100 | if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC, |
| 129 | &e.port, &e.proto)) | 101 | &e.port, &e.proto)) |
| @@ -141,8 +113,8 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 141 | const struct hash_ipportip *h = set->data; | 113 | const struct hash_ipportip *h = set->data; |
| 142 | ipset_adtfn adtfn = set->variant->adt[adt]; | 114 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 143 | struct hash_ipportip4_elem e = { }; | 115 | struct hash_ipportip4_elem e = { }; |
| 144 | struct ip_set_ext ext = IP_SET_INIT_UEXT(h); | 116 | struct ip_set_ext ext = IP_SET_INIT_UEXT(set); |
| 145 | u32 ip, ip_to, p = 0, port, port_to; | 117 | u32 ip, ip_to = 0, p = 0, port, port_to; |
| 146 | bool with_ports = false; | 118 | bool with_ports = false; |
| 147 | int ret; | 119 | int ret; |
| 148 | 120 | ||
| @@ -231,7 +203,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 231 | return ret; | 203 | return ret; |
| 232 | } | 204 | } |
| 233 | 205 | ||
| 234 | /* IPv6 variants */ | 206 | /* IPv6 variant */ |
| 235 | 207 | ||
| 236 | struct hash_ipportip6_elem { | 208 | struct hash_ipportip6_elem { |
| 237 | union nf_inet_addr ip; | 209 | union nf_inet_addr ip; |
| @@ -241,34 +213,6 @@ struct hash_ipportip6_elem { | |||
| 241 | u8 padding; | 213 | u8 padding; |
| 242 | }; | 214 | }; |
| 243 | 215 | ||
| 244 | struct hash_ipportip6t_elem { | ||
| 245 | union nf_inet_addr ip; | ||
| 246 | union nf_inet_addr ip2; | ||
| 247 | __be16 port; | ||
| 248 | u8 proto; | ||
| 249 | u8 padding; | ||
| 250 | unsigned long timeout; | ||
| 251 | }; | ||
| 252 | |||
| 253 | struct hash_ipportip6c_elem { | ||
| 254 | union nf_inet_addr ip; | ||
| 255 | union nf_inet_addr ip2; | ||
| 256 | __be16 port; | ||
| 257 | u8 proto; | ||
| 258 | u8 padding; | ||
| 259 | struct ip_set_counter counter; | ||
| 260 | }; | ||
| 261 | |||
| 262 | struct hash_ipportip6ct_elem { | ||
| 263 | union nf_inet_addr ip; | ||
| 264 | union nf_inet_addr ip2; | ||
| 265 | __be16 port; | ||
| 266 | u8 proto; | ||
| 267 | u8 padding; | ||
| 268 | struct ip_set_counter counter; | ||
| 269 | unsigned long timeout; | ||
| 270 | }; | ||
| 271 | |||
| 272 | /* Common functions */ | 216 | /* Common functions */ |
| 273 | 217 | ||
| 274 | static inline bool | 218 | static inline bool |
| @@ -319,10 +263,9 @@ hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
| 319 | const struct xt_action_param *par, | 263 | const struct xt_action_param *par, |
| 320 | enum ipset_adt adt, struct ip_set_adt_opt *opt) | 264 | enum ipset_adt adt, struct ip_set_adt_opt *opt) |
| 321 | { | 265 | { |
| 322 | const struct hash_ipportip *h = set->data; | ||
| 323 | ipset_adtfn adtfn = set->variant->adt[adt]; | 266 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 324 | struct hash_ipportip6_elem e = { }; | 267 | struct hash_ipportip6_elem e = { }; |
| 325 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h); | 268 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); |
| 326 | 269 | ||
| 327 | if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC, | 270 | if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC, |
| 328 | &e.port, &e.proto)) | 271 | &e.port, &e.proto)) |
| @@ -340,7 +283,7 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 340 | const struct hash_ipportip *h = set->data; | 283 | const struct hash_ipportip *h = set->data; |
| 341 | ipset_adtfn adtfn = set->variant->adt[adt]; | 284 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 342 | struct hash_ipportip6_elem e = { }; | 285 | struct hash_ipportip6_elem e = { }; |
| 343 | struct ip_set_ext ext = IP_SET_INIT_UEXT(h); | 286 | struct ip_set_ext ext = IP_SET_INIT_UEXT(set); |
| 344 | u32 port, port_to; | 287 | u32 port, port_to; |
| 345 | bool with_ports = false; | 288 | bool with_ports = false; |
| 346 | int ret; | 289 | int ret; |
| @@ -414,8 +357,8 @@ static struct ip_set_type hash_ipportip_type __read_mostly = { | |||
| 414 | .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2, | 357 | .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2, |
| 415 | .dimension = IPSET_DIM_THREE, | 358 | .dimension = IPSET_DIM_THREE, |
| 416 | .family = NFPROTO_UNSPEC, | 359 | .family = NFPROTO_UNSPEC, |
| 417 | .revision_min = REVISION_MIN, | 360 | .revision_min = IPSET_TYPE_REV_MIN, |
| 418 | .revision_max = REVISION_MAX, | 361 | .revision_max = IPSET_TYPE_REV_MAX, |
| 419 | .create = hash_ipportip_create, | 362 | .create = hash_ipportip_create, |
| 420 | .create_policy = { | 363 | .create_policy = { |
| 421 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, | 364 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, |
| @@ -437,6 +380,7 @@ static struct ip_set_type hash_ipportip_type __read_mostly = { | |||
| 437 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, | 380 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, |
| 438 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | 381 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, |
| 439 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | 382 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, |
| 383 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | ||
| 440 | }, | 384 | }, |
| 441 | .me = THIS_MODULE, | 385 | .me = THIS_MODULE, |
| 442 | }; | 386 | }; |
diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c index f15f3e28b9c3..5d87fe8a41ff 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportnet.c +++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c | |||
| @@ -24,15 +24,16 @@ | |||
| 24 | #include <linux/netfilter/ipset/ip_set_getport.h> | 24 | #include <linux/netfilter/ipset/ip_set_getport.h> |
| 25 | #include <linux/netfilter/ipset/ip_set_hash.h> | 25 | #include <linux/netfilter/ipset/ip_set_hash.h> |
| 26 | 26 | ||
| 27 | #define REVISION_MIN 0 | 27 | #define IPSET_TYPE_REV_MIN 0 |
| 28 | /* 1 SCTP and UDPLITE support added */ | 28 | /* 1 SCTP and UDPLITE support added */ |
| 29 | /* 2 Range as input support for IPv4 added */ | 29 | /* 2 Range as input support for IPv4 added */ |
| 30 | /* 3 nomatch flag support added */ | 30 | /* 3 nomatch flag support added */ |
| 31 | #define REVISION_MAX 4 /* Counters support added */ | 31 | /* 4 Counters support added */ |
| 32 | #define IPSET_TYPE_REV_MAX 5 /* Comments support added */ | ||
| 32 | 33 | ||
| 33 | MODULE_LICENSE("GPL"); | 34 | MODULE_LICENSE("GPL"); |
| 34 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); | 35 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); |
| 35 | IP_SET_MODULE_DESC("hash:ip,port,net", REVISION_MIN, REVISION_MAX); | 36 | IP_SET_MODULE_DESC("hash:ip,port,net", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX); |
| 36 | MODULE_ALIAS("ip_set_hash:ip,port,net"); | 37 | MODULE_ALIAS("ip_set_hash:ip,port,net"); |
| 37 | 38 | ||
| 38 | /* Type specific function prefix */ | 39 | /* Type specific function prefix */ |
| @@ -46,7 +47,7 @@ MODULE_ALIAS("ip_set_hash:ip,port,net"); | |||
| 46 | #define IP_SET_HASH_WITH_PROTO | 47 | #define IP_SET_HASH_WITH_PROTO |
| 47 | #define IP_SET_HASH_WITH_NETS | 48 | #define IP_SET_HASH_WITH_NETS |
| 48 | 49 | ||
| 49 | /* IPv4 variants */ | 50 | /* IPv4 variant */ |
| 50 | 51 | ||
| 51 | /* Member elements */ | 52 | /* Member elements */ |
| 52 | struct hash_ipportnet4_elem { | 53 | struct hash_ipportnet4_elem { |
| @@ -58,37 +59,6 @@ struct hash_ipportnet4_elem { | |||
| 58 | u8 proto; | 59 | u8 proto; |
| 59 | }; | 60 | }; |
| 60 | 61 | ||
| 61 | struct hash_ipportnet4t_elem { | ||
| 62 | __be32 ip; | ||
| 63 | __be32 ip2; | ||
| 64 | __be16 port; | ||
| 65 | u8 cidr:7; | ||
| 66 | u8 nomatch:1; | ||
| 67 | u8 proto; | ||
| 68 | unsigned long timeout; | ||
| 69 | }; | ||
| 70 | |||
| 71 | struct hash_ipportnet4c_elem { | ||
| 72 | __be32 ip; | ||
| 73 | __be32 ip2; | ||
| 74 | __be16 port; | ||
| 75 | u8 cidr:7; | ||
| 76 | u8 nomatch:1; | ||
| 77 | u8 proto; | ||
| 78 | struct ip_set_counter counter; | ||
| 79 | }; | ||
| 80 | |||
| 81 | struct hash_ipportnet4ct_elem { | ||
| 82 | __be32 ip; | ||
| 83 | __be32 ip2; | ||
| 84 | __be16 port; | ||
| 85 | u8 cidr:7; | ||
| 86 | u8 nomatch:1; | ||
| 87 | u8 proto; | ||
| 88 | struct ip_set_counter counter; | ||
| 89 | unsigned long timeout; | ||
| 90 | }; | ||
| 91 | |||
| 92 | /* Common functions */ | 62 | /* Common functions */ |
| 93 | 63 | ||
| 94 | static inline bool | 64 | static inline bool |
| @@ -170,9 +140,9 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
| 170 | const struct hash_ipportnet *h = set->data; | 140 | const struct hash_ipportnet *h = set->data; |
| 171 | ipset_adtfn adtfn = set->variant->adt[adt]; | 141 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 172 | struct hash_ipportnet4_elem e = { | 142 | struct hash_ipportnet4_elem e = { |
| 173 | .cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1 | 143 | .cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK) - 1, |
| 174 | }; | 144 | }; |
| 175 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h); | 145 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); |
| 176 | 146 | ||
| 177 | if (adt == IPSET_TEST) | 147 | if (adt == IPSET_TEST) |
| 178 | e.cidr = HOST_MASK - 1; | 148 | e.cidr = HOST_MASK - 1; |
| @@ -195,9 +165,9 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 195 | const struct hash_ipportnet *h = set->data; | 165 | const struct hash_ipportnet *h = set->data; |
| 196 | ipset_adtfn adtfn = set->variant->adt[adt]; | 166 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 197 | struct hash_ipportnet4_elem e = { .cidr = HOST_MASK - 1 }; | 167 | struct hash_ipportnet4_elem e = { .cidr = HOST_MASK - 1 }; |
| 198 | struct ip_set_ext ext = IP_SET_INIT_UEXT(h); | 168 | struct ip_set_ext ext = IP_SET_INIT_UEXT(set); |
| 199 | u32 ip, ip_to, p = 0, port, port_to; | 169 | u32 ip = 0, ip_to = 0, p = 0, port, port_to; |
| 200 | u32 ip2_from, ip2_to, ip2_last, ip2; | 170 | u32 ip2_from = 0, ip2_to = 0, ip2_last, ip2; |
| 201 | bool with_ports = false; | 171 | bool with_ports = false; |
| 202 | u8 cidr; | 172 | u8 cidr; |
| 203 | int ret; | 173 | int ret; |
| @@ -272,7 +242,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 272 | if (ip > ip_to) | 242 | if (ip > ip_to) |
| 273 | swap(ip, ip_to); | 243 | swap(ip, ip_to); |
| 274 | } else if (tb[IPSET_ATTR_CIDR]) { | 244 | } else if (tb[IPSET_ATTR_CIDR]) { |
| 275 | u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); | 245 | cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); |
| 276 | 246 | ||
| 277 | if (!cidr || cidr > 32) | 247 | if (!cidr || cidr > 32) |
| 278 | return -IPSET_ERR_INVALID_CIDR; | 248 | return -IPSET_ERR_INVALID_CIDR; |
| @@ -306,9 +276,9 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 306 | : port; | 276 | : port; |
| 307 | for (; p <= port_to; p++) { | 277 | for (; p <= port_to; p++) { |
| 308 | e.port = htons(p); | 278 | e.port = htons(p); |
| 309 | ip2 = retried | 279 | ip2 = retried && |
| 310 | && ip == ntohl(h->next.ip) | 280 | ip == ntohl(h->next.ip) && |
| 311 | && p == ntohs(h->next.port) | 281 | p == ntohs(h->next.port) |
| 312 | ? ntohl(h->next.ip2) : ip2_from; | 282 | ? ntohl(h->next.ip2) : ip2_from; |
| 313 | while (!after(ip2, ip2_to)) { | 283 | while (!after(ip2, ip2_to)) { |
| 314 | e.ip2 = htonl(ip2); | 284 | e.ip2 = htonl(ip2); |
| @@ -328,7 +298,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 328 | return ret; | 298 | return ret; |
| 329 | } | 299 | } |
| 330 | 300 | ||
| 331 | /* IPv6 variants */ | 301 | /* IPv6 variant */ |
| 332 | 302 | ||
| 333 | struct hash_ipportnet6_elem { | 303 | struct hash_ipportnet6_elem { |
| 334 | union nf_inet_addr ip; | 304 | union nf_inet_addr ip; |
| @@ -339,37 +309,6 @@ struct hash_ipportnet6_elem { | |||
| 339 | u8 proto; | 309 | u8 proto; |
| 340 | }; | 310 | }; |
| 341 | 311 | ||
| 342 | struct hash_ipportnet6t_elem { | ||
| 343 | union nf_inet_addr ip; | ||
| 344 | union nf_inet_addr ip2; | ||
| 345 | __be16 port; | ||
| 346 | u8 cidr:7; | ||
| 347 | u8 nomatch:1; | ||
| 348 | u8 proto; | ||
| 349 | unsigned long timeout; | ||
| 350 | }; | ||
| 351 | |||
| 352 | struct hash_ipportnet6c_elem { | ||
| 353 | union nf_inet_addr ip; | ||
| 354 | union nf_inet_addr ip2; | ||
| 355 | __be16 port; | ||
| 356 | u8 cidr:7; | ||
| 357 | u8 nomatch:1; | ||
| 358 | u8 proto; | ||
| 359 | struct ip_set_counter counter; | ||
| 360 | }; | ||
| 361 | |||
| 362 | struct hash_ipportnet6ct_elem { | ||
| 363 | union nf_inet_addr ip; | ||
| 364 | union nf_inet_addr ip2; | ||
| 365 | __be16 port; | ||
| 366 | u8 cidr:7; | ||
| 367 | u8 nomatch:1; | ||
| 368 | u8 proto; | ||
| 369 | struct ip_set_counter counter; | ||
| 370 | unsigned long timeout; | ||
| 371 | }; | ||
| 372 | |||
| 373 | /* Common functions */ | 312 | /* Common functions */ |
| 374 | 313 | ||
| 375 | static inline bool | 314 | static inline bool |
| @@ -454,9 +393,9 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
| 454 | const struct hash_ipportnet *h = set->data; | 393 | const struct hash_ipportnet *h = set->data; |
| 455 | ipset_adtfn adtfn = set->variant->adt[adt]; | 394 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 456 | struct hash_ipportnet6_elem e = { | 395 | struct hash_ipportnet6_elem e = { |
| 457 | .cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1 | 396 | .cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK) - 1, |
| 458 | }; | 397 | }; |
| 459 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h); | 398 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); |
| 460 | 399 | ||
| 461 | if (adt == IPSET_TEST) | 400 | if (adt == IPSET_TEST) |
| 462 | e.cidr = HOST_MASK - 1; | 401 | e.cidr = HOST_MASK - 1; |
| @@ -479,7 +418,7 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 479 | const struct hash_ipportnet *h = set->data; | 418 | const struct hash_ipportnet *h = set->data; |
| 480 | ipset_adtfn adtfn = set->variant->adt[adt]; | 419 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 481 | struct hash_ipportnet6_elem e = { .cidr = HOST_MASK - 1 }; | 420 | struct hash_ipportnet6_elem e = { .cidr = HOST_MASK - 1 }; |
| 482 | struct ip_set_ext ext = IP_SET_INIT_UEXT(h); | 421 | struct ip_set_ext ext = IP_SET_INIT_UEXT(set); |
| 483 | u32 port, port_to; | 422 | u32 port, port_to; |
| 484 | bool with_ports = false; | 423 | bool with_ports = false; |
| 485 | u8 cidr; | 424 | u8 cidr; |
| @@ -574,8 +513,8 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = { | |||
| 574 | IPSET_TYPE_NOMATCH, | 513 | IPSET_TYPE_NOMATCH, |
| 575 | .dimension = IPSET_DIM_THREE, | 514 | .dimension = IPSET_DIM_THREE, |
| 576 | .family = NFPROTO_UNSPEC, | 515 | .family = NFPROTO_UNSPEC, |
| 577 | .revision_min = REVISION_MIN, | 516 | .revision_min = IPSET_TYPE_REV_MIN, |
| 578 | .revision_max = REVISION_MAX, | 517 | .revision_max = IPSET_TYPE_REV_MAX, |
| 579 | .create = hash_ipportnet_create, | 518 | .create = hash_ipportnet_create, |
| 580 | .create_policy = { | 519 | .create_policy = { |
| 581 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, | 520 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, |
| @@ -600,6 +539,7 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = { | |||
| 600 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, | 539 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, |
| 601 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | 540 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, |
| 602 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | 541 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, |
| 542 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | ||
| 603 | }, | 543 | }, |
| 604 | .me = THIS_MODULE, | 544 | .me = THIS_MODULE, |
| 605 | }; | 545 | }; |
diff --git a/net/netfilter/ipset/ip_set_hash_net.c b/net/netfilter/ipset/ip_set_hash_net.c index 223e9f546d0f..8295cf4f9fdc 100644 --- a/net/netfilter/ipset/ip_set_hash_net.c +++ b/net/netfilter/ipset/ip_set_hash_net.c | |||
| @@ -22,21 +22,22 @@ | |||
| 22 | #include <linux/netfilter/ipset/ip_set.h> | 22 | #include <linux/netfilter/ipset/ip_set.h> |
| 23 | #include <linux/netfilter/ipset/ip_set_hash.h> | 23 | #include <linux/netfilter/ipset/ip_set_hash.h> |
| 24 | 24 | ||
| 25 | #define REVISION_MIN 0 | 25 | #define IPSET_TYPE_REV_MIN 0 |
| 26 | /* 1 Range as input support for IPv4 added */ | 26 | /* 1 Range as input support for IPv4 added */ |
| 27 | /* 2 nomatch flag support added */ | 27 | /* 2 nomatch flag support added */ |
| 28 | #define REVISION_MAX 3 /* Counters support added */ | 28 | /* 3 Counters support added */ |
| 29 | #define IPSET_TYPE_REV_MAX 4 /* Comments support added */ | ||
| 29 | 30 | ||
| 30 | MODULE_LICENSE("GPL"); | 31 | MODULE_LICENSE("GPL"); |
| 31 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); | 32 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); |
| 32 | IP_SET_MODULE_DESC("hash:net", REVISION_MIN, REVISION_MAX); | 33 | IP_SET_MODULE_DESC("hash:net", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX); |
| 33 | MODULE_ALIAS("ip_set_hash:net"); | 34 | MODULE_ALIAS("ip_set_hash:net"); |
| 34 | 35 | ||
| 35 | /* Type specific function prefix */ | 36 | /* Type specific function prefix */ |
| 36 | #define HTYPE hash_net | 37 | #define HTYPE hash_net |
| 37 | #define IP_SET_HASH_WITH_NETS | 38 | #define IP_SET_HASH_WITH_NETS |
| 38 | 39 | ||
| 39 | /* IPv4 variants */ | 40 | /* IPv4 variant */ |
| 40 | 41 | ||
| 41 | /* Member elements */ | 42 | /* Member elements */ |
| 42 | struct hash_net4_elem { | 43 | struct hash_net4_elem { |
| @@ -46,31 +47,6 @@ struct hash_net4_elem { | |||
| 46 | u8 cidr; | 47 | u8 cidr; |
| 47 | }; | 48 | }; |
| 48 | 49 | ||
| 49 | struct hash_net4t_elem { | ||
| 50 | __be32 ip; | ||
| 51 | u16 padding0; | ||
| 52 | u8 nomatch; | ||
| 53 | u8 cidr; | ||
| 54 | unsigned long timeout; | ||
| 55 | }; | ||
| 56 | |||
| 57 | struct hash_net4c_elem { | ||
| 58 | __be32 ip; | ||
| 59 | u16 padding0; | ||
| 60 | u8 nomatch; | ||
| 61 | u8 cidr; | ||
| 62 | struct ip_set_counter counter; | ||
| 63 | }; | ||
| 64 | |||
| 65 | struct hash_net4ct_elem { | ||
| 66 | __be32 ip; | ||
| 67 | u16 padding0; | ||
| 68 | u8 nomatch; | ||
| 69 | u8 cidr; | ||
| 70 | struct ip_set_counter counter; | ||
| 71 | unsigned long timeout; | ||
| 72 | }; | ||
| 73 | |||
| 74 | /* Common functions */ | 50 | /* Common functions */ |
| 75 | 51 | ||
| 76 | static inline bool | 52 | static inline bool |
| @@ -143,9 +119,9 @@ hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
| 143 | const struct hash_net *h = set->data; | 119 | const struct hash_net *h = set->data; |
| 144 | ipset_adtfn adtfn = set->variant->adt[adt]; | 120 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 145 | struct hash_net4_elem e = { | 121 | struct hash_net4_elem e = { |
| 146 | .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK | 122 | .cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK), |
| 147 | }; | 123 | }; |
| 148 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h); | 124 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); |
| 149 | 125 | ||
| 150 | if (e.cidr == 0) | 126 | if (e.cidr == 0) |
| 151 | return -EINVAL; | 127 | return -EINVAL; |
| @@ -165,8 +141,8 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 165 | const struct hash_net *h = set->data; | 141 | const struct hash_net *h = set->data; |
| 166 | ipset_adtfn adtfn = set->variant->adt[adt]; | 142 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 167 | struct hash_net4_elem e = { .cidr = HOST_MASK }; | 143 | struct hash_net4_elem e = { .cidr = HOST_MASK }; |
| 168 | struct ip_set_ext ext = IP_SET_INIT_UEXT(h); | 144 | struct ip_set_ext ext = IP_SET_INIT_UEXT(set); |
| 169 | u32 ip = 0, ip_to, last; | 145 | u32 ip = 0, ip_to = 0, last; |
| 170 | int ret; | 146 | int ret; |
| 171 | 147 | ||
| 172 | if (unlikely(!tb[IPSET_ATTR_IP] || | 148 | if (unlikely(!tb[IPSET_ATTR_IP] || |
| @@ -228,7 +204,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 228 | return ret; | 204 | return ret; |
| 229 | } | 205 | } |
| 230 | 206 | ||
| 231 | /* IPv6 variants */ | 207 | /* IPv6 variant */ |
| 232 | 208 | ||
| 233 | struct hash_net6_elem { | 209 | struct hash_net6_elem { |
| 234 | union nf_inet_addr ip; | 210 | union nf_inet_addr ip; |
| @@ -237,31 +213,6 @@ struct hash_net6_elem { | |||
| 237 | u8 cidr; | 213 | u8 cidr; |
| 238 | }; | 214 | }; |
| 239 | 215 | ||
| 240 | struct hash_net6t_elem { | ||
| 241 | union nf_inet_addr ip; | ||
| 242 | u16 padding0; | ||
| 243 | u8 nomatch; | ||
| 244 | u8 cidr; | ||
| 245 | unsigned long timeout; | ||
| 246 | }; | ||
| 247 | |||
| 248 | struct hash_net6c_elem { | ||
| 249 | union nf_inet_addr ip; | ||
| 250 | u16 padding0; | ||
| 251 | u8 nomatch; | ||
| 252 | u8 cidr; | ||
| 253 | struct ip_set_counter counter; | ||
| 254 | }; | ||
| 255 | |||
| 256 | struct hash_net6ct_elem { | ||
| 257 | union nf_inet_addr ip; | ||
| 258 | u16 padding0; | ||
| 259 | u8 nomatch; | ||
| 260 | u8 cidr; | ||
| 261 | struct ip_set_counter counter; | ||
| 262 | unsigned long timeout; | ||
| 263 | }; | ||
| 264 | |||
| 265 | /* Common functions */ | 216 | /* Common functions */ |
| 266 | 217 | ||
| 267 | static inline bool | 218 | static inline bool |
| @@ -338,9 +289,9 @@ hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
| 338 | const struct hash_net *h = set->data; | 289 | const struct hash_net *h = set->data; |
| 339 | ipset_adtfn adtfn = set->variant->adt[adt]; | 290 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 340 | struct hash_net6_elem e = { | 291 | struct hash_net6_elem e = { |
| 341 | .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK | 292 | .cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK), |
| 342 | }; | 293 | }; |
| 343 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h); | 294 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); |
| 344 | 295 | ||
| 345 | if (e.cidr == 0) | 296 | if (e.cidr == 0) |
| 346 | return -EINVAL; | 297 | return -EINVAL; |
| @@ -357,10 +308,9 @@ static int | |||
| 357 | hash_net6_uadt(struct ip_set *set, struct nlattr *tb[], | 308 | hash_net6_uadt(struct ip_set *set, struct nlattr *tb[], |
| 358 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) | 309 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) |
| 359 | { | 310 | { |
| 360 | const struct hash_net *h = set->data; | ||
| 361 | ipset_adtfn adtfn = set->variant->adt[adt]; | 311 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 362 | struct hash_net6_elem e = { .cidr = HOST_MASK }; | 312 | struct hash_net6_elem e = { .cidr = HOST_MASK }; |
| 363 | struct ip_set_ext ext = IP_SET_INIT_UEXT(h); | 313 | struct ip_set_ext ext = IP_SET_INIT_UEXT(set); |
| 364 | int ret; | 314 | int ret; |
| 365 | 315 | ||
| 366 | if (unlikely(!tb[IPSET_ATTR_IP] || | 316 | if (unlikely(!tb[IPSET_ATTR_IP] || |
| @@ -406,8 +356,8 @@ static struct ip_set_type hash_net_type __read_mostly = { | |||
| 406 | .features = IPSET_TYPE_IP | IPSET_TYPE_NOMATCH, | 356 | .features = IPSET_TYPE_IP | IPSET_TYPE_NOMATCH, |
| 407 | .dimension = IPSET_DIM_ONE, | 357 | .dimension = IPSET_DIM_ONE, |
| 408 | .family = NFPROTO_UNSPEC, | 358 | .family = NFPROTO_UNSPEC, |
| 409 | .revision_min = REVISION_MIN, | 359 | .revision_min = IPSET_TYPE_REV_MIN, |
| 410 | .revision_max = REVISION_MAX, | 360 | .revision_max = IPSET_TYPE_REV_MAX, |
| 411 | .create = hash_net_create, | 361 | .create = hash_net_create, |
| 412 | .create_policy = { | 362 | .create_policy = { |
| 413 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, | 363 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, |
| @@ -425,6 +375,7 @@ static struct ip_set_type hash_net_type __read_mostly = { | |||
| 425 | [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, | 375 | [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, |
| 426 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | 376 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, |
| 427 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | 377 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, |
| 378 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | ||
| 428 | }, | 379 | }, |
| 429 | .me = THIS_MODULE, | 380 | .me = THIS_MODULE, |
| 430 | }; | 381 | }; |
diff --git a/net/netfilter/ipset/ip_set_hash_netiface.c b/net/netfilter/ipset/ip_set_hash_netiface.c index 7d798d5d5cd3..3f64a66bf5d9 100644 --- a/net/netfilter/ipset/ip_set_hash_netiface.c +++ b/net/netfilter/ipset/ip_set_hash_netiface.c | |||
| @@ -23,14 +23,15 @@ | |||
| 23 | #include <linux/netfilter/ipset/ip_set.h> | 23 | #include <linux/netfilter/ipset/ip_set.h> |
| 24 | #include <linux/netfilter/ipset/ip_set_hash.h> | 24 | #include <linux/netfilter/ipset/ip_set_hash.h> |
| 25 | 25 | ||
| 26 | #define REVISION_MIN 0 | 26 | #define IPSET_TYPE_REV_MIN 0 |
| 27 | /* 1 nomatch flag support added */ | 27 | /* 1 nomatch flag support added */ |
| 28 | /* 2 /0 support added */ | 28 | /* 2 /0 support added */ |
| 29 | #define REVISION_MAX 3 /* Counters support added */ | 29 | /* 3 Counters support added */ |
| 30 | #define IPSET_TYPE_REV_MAX 4 /* Comments support added */ | ||
| 30 | 31 | ||
| 31 | MODULE_LICENSE("GPL"); | 32 | MODULE_LICENSE("GPL"); |
| 32 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); | 33 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); |
| 33 | IP_SET_MODULE_DESC("hash:net,iface", REVISION_MIN, REVISION_MAX); | 34 | IP_SET_MODULE_DESC("hash:net,iface", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX); |
| 34 | MODULE_ALIAS("ip_set_hash:net,iface"); | 35 | MODULE_ALIAS("ip_set_hash:net,iface"); |
| 35 | 36 | ||
| 36 | /* Interface name rbtree */ | 37 | /* Interface name rbtree */ |
| @@ -134,7 +135,7 @@ iface_add(struct rb_root *root, const char **iface) | |||
| 134 | 135 | ||
| 135 | #define STREQ(a, b) (strcmp(a, b) == 0) | 136 | #define STREQ(a, b) (strcmp(a, b) == 0) |
| 136 | 137 | ||
| 137 | /* IPv4 variants */ | 138 | /* IPv4 variant */ |
| 138 | 139 | ||
| 139 | struct hash_netiface4_elem_hashed { | 140 | struct hash_netiface4_elem_hashed { |
| 140 | __be32 ip; | 141 | __be32 ip; |
| @@ -144,7 +145,7 @@ struct hash_netiface4_elem_hashed { | |||
| 144 | u8 elem; | 145 | u8 elem; |
| 145 | }; | 146 | }; |
| 146 | 147 | ||
| 147 | /* Member elements without timeout */ | 148 | /* Member elements */ |
| 148 | struct hash_netiface4_elem { | 149 | struct hash_netiface4_elem { |
| 149 | __be32 ip; | 150 | __be32 ip; |
| 150 | u8 physdev; | 151 | u8 physdev; |
| @@ -154,37 +155,6 @@ struct hash_netiface4_elem { | |||
| 154 | const char *iface; | 155 | const char *iface; |
| 155 | }; | 156 | }; |
| 156 | 157 | ||
| 157 | struct hash_netiface4t_elem { | ||
| 158 | __be32 ip; | ||
| 159 | u8 physdev; | ||
| 160 | u8 cidr; | ||
| 161 | u8 nomatch; | ||
| 162 | u8 elem; | ||
| 163 | const char *iface; | ||
| 164 | unsigned long timeout; | ||
| 165 | }; | ||
| 166 | |||
| 167 | struct hash_netiface4c_elem { | ||
| 168 | __be32 ip; | ||
| 169 | u8 physdev; | ||
| 170 | u8 cidr; | ||
| 171 | u8 nomatch; | ||
| 172 | u8 elem; | ||
| 173 | const char *iface; | ||
| 174 | struct ip_set_counter counter; | ||
| 175 | }; | ||
| 176 | |||
| 177 | struct hash_netiface4ct_elem { | ||
| 178 | __be32 ip; | ||
| 179 | u8 physdev; | ||
| 180 | u8 cidr; | ||
| 181 | u8 nomatch; | ||
| 182 | u8 elem; | ||
| 183 | const char *iface; | ||
| 184 | struct ip_set_counter counter; | ||
| 185 | unsigned long timeout; | ||
| 186 | }; | ||
| 187 | |||
| 188 | /* Common functions */ | 158 | /* Common functions */ |
| 189 | 159 | ||
| 190 | static inline bool | 160 | static inline bool |
| @@ -265,10 +235,10 @@ hash_netiface4_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
| 265 | struct hash_netiface *h = set->data; | 235 | struct hash_netiface *h = set->data; |
| 266 | ipset_adtfn adtfn = set->variant->adt[adt]; | 236 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 267 | struct hash_netiface4_elem e = { | 237 | struct hash_netiface4_elem e = { |
| 268 | .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK, | 238 | .cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK), |
| 269 | .elem = 1, | 239 | .elem = 1, |
| 270 | }; | 240 | }; |
| 271 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h); | 241 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); |
| 272 | int ret; | 242 | int ret; |
| 273 | 243 | ||
| 274 | if (e.cidr == 0) | 244 | if (e.cidr == 0) |
| @@ -319,8 +289,8 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 319 | struct hash_netiface *h = set->data; | 289 | struct hash_netiface *h = set->data; |
| 320 | ipset_adtfn adtfn = set->variant->adt[adt]; | 290 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 321 | struct hash_netiface4_elem e = { .cidr = HOST_MASK, .elem = 1 }; | 291 | struct hash_netiface4_elem e = { .cidr = HOST_MASK, .elem = 1 }; |
| 322 | struct ip_set_ext ext = IP_SET_INIT_UEXT(h); | 292 | struct ip_set_ext ext = IP_SET_INIT_UEXT(set); |
| 323 | u32 ip = 0, ip_to, last; | 293 | u32 ip = 0, ip_to = 0, last; |
| 324 | char iface[IFNAMSIZ]; | 294 | char iface[IFNAMSIZ]; |
| 325 | int ret; | 295 | int ret; |
| 326 | 296 | ||
| @@ -399,7 +369,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 399 | return ret; | 369 | return ret; |
| 400 | } | 370 | } |
| 401 | 371 | ||
| 402 | /* IPv6 variants */ | 372 | /* IPv6 variant */ |
| 403 | 373 | ||
| 404 | struct hash_netiface6_elem_hashed { | 374 | struct hash_netiface6_elem_hashed { |
| 405 | union nf_inet_addr ip; | 375 | union nf_inet_addr ip; |
| @@ -418,37 +388,6 @@ struct hash_netiface6_elem { | |||
| 418 | const char *iface; | 388 | const char *iface; |
| 419 | }; | 389 | }; |
| 420 | 390 | ||
| 421 | struct hash_netiface6t_elem { | ||
| 422 | union nf_inet_addr ip; | ||
| 423 | u8 physdev; | ||
| 424 | u8 cidr; | ||
| 425 | u8 nomatch; | ||
| 426 | u8 elem; | ||
| 427 | const char *iface; | ||
| 428 | unsigned long timeout; | ||
| 429 | }; | ||
| 430 | |||
| 431 | struct hash_netiface6c_elem { | ||
| 432 | union nf_inet_addr ip; | ||
| 433 | u8 physdev; | ||
| 434 | u8 cidr; | ||
| 435 | u8 nomatch; | ||
| 436 | u8 elem; | ||
| 437 | const char *iface; | ||
| 438 | struct ip_set_counter counter; | ||
| 439 | }; | ||
| 440 | |||
| 441 | struct hash_netiface6ct_elem { | ||
| 442 | union nf_inet_addr ip; | ||
| 443 | u8 physdev; | ||
| 444 | u8 cidr; | ||
| 445 | u8 nomatch; | ||
| 446 | u8 elem; | ||
| 447 | const char *iface; | ||
| 448 | struct ip_set_counter counter; | ||
| 449 | unsigned long timeout; | ||
| 450 | }; | ||
| 451 | |||
| 452 | /* Common functions */ | 391 | /* Common functions */ |
| 453 | 392 | ||
| 454 | static inline bool | 393 | static inline bool |
| @@ -534,10 +473,10 @@ hash_netiface6_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
| 534 | struct hash_netiface *h = set->data; | 473 | struct hash_netiface *h = set->data; |
| 535 | ipset_adtfn adtfn = set->variant->adt[adt]; | 474 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 536 | struct hash_netiface6_elem e = { | 475 | struct hash_netiface6_elem e = { |
| 537 | .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK, | 476 | .cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK), |
| 538 | .elem = 1, | 477 | .elem = 1, |
| 539 | }; | 478 | }; |
| 540 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h); | 479 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); |
| 541 | int ret; | 480 | int ret; |
| 542 | 481 | ||
| 543 | if (e.cidr == 0) | 482 | if (e.cidr == 0) |
| @@ -584,7 +523,7 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 584 | struct hash_netiface *h = set->data; | 523 | struct hash_netiface *h = set->data; |
| 585 | ipset_adtfn adtfn = set->variant->adt[adt]; | 524 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 586 | struct hash_netiface6_elem e = { .cidr = HOST_MASK, .elem = 1 }; | 525 | struct hash_netiface6_elem e = { .cidr = HOST_MASK, .elem = 1 }; |
| 587 | struct ip_set_ext ext = IP_SET_INIT_UEXT(h); | 526 | struct ip_set_ext ext = IP_SET_INIT_UEXT(set); |
| 588 | char iface[IFNAMSIZ]; | 527 | char iface[IFNAMSIZ]; |
| 589 | int ret; | 528 | int ret; |
| 590 | 529 | ||
| @@ -645,8 +584,8 @@ static struct ip_set_type hash_netiface_type __read_mostly = { | |||
| 645 | IPSET_TYPE_NOMATCH, | 584 | IPSET_TYPE_NOMATCH, |
| 646 | .dimension = IPSET_DIM_TWO, | 585 | .dimension = IPSET_DIM_TWO, |
| 647 | .family = NFPROTO_UNSPEC, | 586 | .family = NFPROTO_UNSPEC, |
| 648 | .revision_min = REVISION_MIN, | 587 | .revision_min = IPSET_TYPE_REV_MIN, |
| 649 | .revision_max = REVISION_MAX, | 588 | .revision_max = IPSET_TYPE_REV_MAX, |
| 650 | .create = hash_netiface_create, | 589 | .create = hash_netiface_create, |
| 651 | .create_policy = { | 590 | .create_policy = { |
| 652 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, | 591 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, |
| @@ -668,6 +607,7 @@ static struct ip_set_type hash_netiface_type __read_mostly = { | |||
| 668 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, | 607 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, |
| 669 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | 608 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, |
| 670 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | 609 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, |
| 610 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | ||
| 671 | }, | 611 | }, |
| 672 | .me = THIS_MODULE, | 612 | .me = THIS_MODULE, |
| 673 | }; | 613 | }; |
diff --git a/net/netfilter/ipset/ip_set_hash_netnet.c b/net/netfilter/ipset/ip_set_hash_netnet.c new file mode 100644 index 000000000000..426032706ca9 --- /dev/null +++ b/net/netfilter/ipset/ip_set_hash_netnet.c | |||
| @@ -0,0 +1,483 @@ | |||
| 1 | /* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | ||
| 2 | * Copyright (C) 2013 Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa> | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License version 2 as | ||
| 6 | * published by the Free Software Foundation. | ||
| 7 | */ | ||
| 8 | |||
| 9 | /* Kernel module implementing an IP set type: the hash:net type */ | ||
| 10 | |||
| 11 | #include <linux/jhash.h> | ||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/ip.h> | ||
| 14 | #include <linux/skbuff.h> | ||
| 15 | #include <linux/errno.h> | ||
| 16 | #include <linux/random.h> | ||
| 17 | #include <net/ip.h> | ||
| 18 | #include <net/ipv6.h> | ||
| 19 | #include <net/netlink.h> | ||
| 20 | |||
| 21 | #include <linux/netfilter.h> | ||
| 22 | #include <linux/netfilter/ipset/pfxlen.h> | ||
| 23 | #include <linux/netfilter/ipset/ip_set.h> | ||
| 24 | #include <linux/netfilter/ipset/ip_set_hash.h> | ||
| 25 | |||
| 26 | #define IPSET_TYPE_REV_MIN 0 | ||
| 27 | #define IPSET_TYPE_REV_MAX 0 | ||
| 28 | |||
| 29 | MODULE_LICENSE("GPL"); | ||
| 30 | MODULE_AUTHOR("Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>"); | ||
| 31 | IP_SET_MODULE_DESC("hash:net,net", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX); | ||
| 32 | MODULE_ALIAS("ip_set_hash:net,net"); | ||
| 33 | |||
| 34 | /* Type specific function prefix */ | ||
| 35 | #define HTYPE hash_netnet | ||
| 36 | #define IP_SET_HASH_WITH_NETS | ||
| 37 | #define IPSET_NET_COUNT 2 | ||
| 38 | |||
| 39 | /* IPv4 variants */ | ||
| 40 | |||
| 41 | /* Member elements */ | ||
| 42 | struct hash_netnet4_elem { | ||
| 43 | union { | ||
| 44 | __be32 ip[2]; | ||
| 45 | __be64 ipcmp; | ||
| 46 | }; | ||
| 47 | u8 nomatch; | ||
| 48 | union { | ||
| 49 | u8 cidr[2]; | ||
| 50 | u16 ccmp; | ||
| 51 | }; | ||
| 52 | }; | ||
| 53 | |||
| 54 | /* Common functions */ | ||
| 55 | |||
| 56 | static inline bool | ||
| 57 | hash_netnet4_data_equal(const struct hash_netnet4_elem *ip1, | ||
| 58 | const struct hash_netnet4_elem *ip2, | ||
| 59 | u32 *multi) | ||
| 60 | { | ||
| 61 | return ip1->ipcmp == ip2->ipcmp && | ||
| 62 | ip2->ccmp == ip2->ccmp; | ||
| 63 | } | ||
| 64 | |||
| 65 | static inline int | ||
| 66 | hash_netnet4_do_data_match(const struct hash_netnet4_elem *elem) | ||
| 67 | { | ||
| 68 | return elem->nomatch ? -ENOTEMPTY : 1; | ||
| 69 | } | ||
| 70 | |||
| 71 | static inline void | ||
| 72 | hash_netnet4_data_set_flags(struct hash_netnet4_elem *elem, u32 flags) | ||
| 73 | { | ||
| 74 | elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH; | ||
| 75 | } | ||
| 76 | |||
| 77 | static inline void | ||
| 78 | hash_netnet4_data_reset_flags(struct hash_netnet4_elem *elem, u8 *flags) | ||
| 79 | { | ||
| 80 | swap(*flags, elem->nomatch); | ||
| 81 | } | ||
| 82 | |||
| 83 | static inline void | ||
| 84 | hash_netnet4_data_reset_elem(struct hash_netnet4_elem *elem, | ||
| 85 | struct hash_netnet4_elem *orig) | ||
| 86 | { | ||
| 87 | elem->ip[1] = orig->ip[1]; | ||
| 88 | } | ||
| 89 | |||
| 90 | static inline void | ||
| 91 | hash_netnet4_data_netmask(struct hash_netnet4_elem *elem, u8 cidr, bool inner) | ||
| 92 | { | ||
| 93 | if (inner) { | ||
| 94 | elem->ip[1] &= ip_set_netmask(cidr); | ||
| 95 | elem->cidr[1] = cidr; | ||
| 96 | } else { | ||
| 97 | elem->ip[0] &= ip_set_netmask(cidr); | ||
| 98 | elem->cidr[0] = cidr; | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | static bool | ||
| 103 | hash_netnet4_data_list(struct sk_buff *skb, | ||
| 104 | const struct hash_netnet4_elem *data) | ||
| 105 | { | ||
| 106 | u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; | ||
| 107 | |||
| 108 | if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip[0]) || | ||
| 109 | nla_put_ipaddr4(skb, IPSET_ATTR_IP2, data->ip[1]) || | ||
| 110 | nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0]) || | ||
| 111 | nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr[1]) || | ||
| 112 | (flags && | ||
| 113 | nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)))) | ||
| 114 | goto nla_put_failure; | ||
| 115 | return 0; | ||
| 116 | |||
| 117 | nla_put_failure: | ||
| 118 | return 1; | ||
| 119 | } | ||
| 120 | |||
| 121 | static inline void | ||
| 122 | hash_netnet4_data_next(struct hash_netnet4_elem *next, | ||
| 123 | const struct hash_netnet4_elem *d) | ||
| 124 | { | ||
| 125 | next->ipcmp = d->ipcmp; | ||
| 126 | } | ||
| 127 | |||
| 128 | #define MTYPE hash_netnet4 | ||
| 129 | #define PF 4 | ||
| 130 | #define HOST_MASK 32 | ||
| 131 | #include "ip_set_hash_gen.h" | ||
| 132 | |||
| 133 | static int | ||
| 134 | hash_netnet4_kadt(struct ip_set *set, const struct sk_buff *skb, | ||
| 135 | const struct xt_action_param *par, | ||
| 136 | enum ipset_adt adt, struct ip_set_adt_opt *opt) | ||
| 137 | { | ||
| 138 | const struct hash_netnet *h = set->data; | ||
| 139 | ipset_adtfn adtfn = set->variant->adt[adt]; | ||
| 140 | struct hash_netnet4_elem e = { | ||
| 141 | .cidr[0] = h->nets[0].cidr[0] ? h->nets[0].cidr[0] : HOST_MASK, | ||
| 142 | .cidr[1] = h->nets[0].cidr[1] ? h->nets[0].cidr[1] : HOST_MASK, | ||
| 143 | }; | ||
| 144 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); | ||
| 145 | |||
| 146 | if (adt == IPSET_TEST) | ||
| 147 | e.ccmp = (HOST_MASK << (sizeof(e.cidr[0]) * 8)) | HOST_MASK; | ||
| 148 | |||
| 149 | ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0]); | ||
| 150 | ip4addrptr(skb, opt->flags & IPSET_DIM_TWO_SRC, &e.ip[1]); | ||
| 151 | e.ip[0] &= ip_set_netmask(e.cidr[0]); | ||
| 152 | e.ip[1] &= ip_set_netmask(e.cidr[1]); | ||
| 153 | |||
| 154 | return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); | ||
| 155 | } | ||
| 156 | |||
| 157 | static int | ||
| 158 | hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[], | ||
| 159 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) | ||
| 160 | { | ||
| 161 | const struct hash_netnet *h = set->data; | ||
| 162 | ipset_adtfn adtfn = set->variant->adt[adt]; | ||
| 163 | struct hash_netnet4_elem e = { .cidr[0] = HOST_MASK, | ||
| 164 | .cidr[1] = HOST_MASK }; | ||
| 165 | struct ip_set_ext ext = IP_SET_INIT_UEXT(set); | ||
| 166 | u32 ip = 0, ip_to = 0, last; | ||
| 167 | u32 ip2 = 0, ip2_from = 0, ip2_to = 0, last2; | ||
| 168 | u8 cidr, cidr2; | ||
| 169 | int ret; | ||
| 170 | |||
| 171 | if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || | ||
| 172 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | ||
| 173 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || | ||
| 174 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | ||
| 175 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) | ||
| 176 | return -IPSET_ERR_PROTOCOL; | ||
| 177 | |||
| 178 | if (tb[IPSET_ATTR_LINENO]) | ||
| 179 | *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); | ||
| 180 | |||
| 181 | ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip) || | ||
| 182 | ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2], &ip2_from) || | ||
| 183 | ip_set_get_extensions(set, tb, &ext); | ||
| 184 | if (ret) | ||
| 185 | return ret; | ||
| 186 | |||
| 187 | if (tb[IPSET_ATTR_CIDR]) { | ||
| 188 | cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); | ||
| 189 | if (!cidr || cidr > HOST_MASK) | ||
| 190 | return -IPSET_ERR_INVALID_CIDR; | ||
| 191 | e.cidr[0] = cidr; | ||
| 192 | } | ||
| 193 | |||
| 194 | if (tb[IPSET_ATTR_CIDR2]) { | ||
| 195 | cidr2 = nla_get_u8(tb[IPSET_ATTR_CIDR2]); | ||
| 196 | if (!cidr2 || cidr2 > HOST_MASK) | ||
| 197 | return -IPSET_ERR_INVALID_CIDR; | ||
| 198 | e.cidr[1] = cidr2; | ||
| 199 | } | ||
| 200 | |||
| 201 | if (tb[IPSET_ATTR_CADT_FLAGS]) { | ||
| 202 | u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); | ||
| 203 | if (cadt_flags & IPSET_FLAG_NOMATCH) | ||
| 204 | flags |= (IPSET_FLAG_NOMATCH << 16); | ||
| 205 | } | ||
| 206 | |||
| 207 | if (adt == IPSET_TEST || !(tb[IPSET_ATTR_IP_TO] && | ||
| 208 | tb[IPSET_ATTR_IP2_TO])) { | ||
| 209 | e.ip[0] = htonl(ip & ip_set_hostmask(e.cidr[0])); | ||
| 210 | e.ip[1] = htonl(ip2_from & ip_set_hostmask(e.cidr[1])); | ||
| 211 | ret = adtfn(set, &e, &ext, &ext, flags); | ||
| 212 | return ip_set_enomatch(ret, flags, adt, set) ? -ret : | ||
| 213 | ip_set_eexist(ret, flags) ? 0 : ret; | ||
| 214 | } | ||
| 215 | |||
| 216 | ip_to = ip; | ||
| 217 | if (tb[IPSET_ATTR_IP_TO]) { | ||
| 218 | ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); | ||
| 219 | if (ret) | ||
| 220 | return ret; | ||
| 221 | if (ip_to < ip) | ||
| 222 | swap(ip, ip_to); | ||
| 223 | if (ip + UINT_MAX == ip_to) | ||
| 224 | return -IPSET_ERR_HASH_RANGE; | ||
| 225 | } | ||
| 226 | |||
| 227 | ip2_to = ip2_from; | ||
| 228 | if (tb[IPSET_ATTR_IP2_TO]) { | ||
| 229 | ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2_TO], &ip2_to); | ||
| 230 | if (ret) | ||
| 231 | return ret; | ||
| 232 | if (ip2_to < ip2_from) | ||
| 233 | swap(ip2_from, ip2_to); | ||
| 234 | if (ip2_from + UINT_MAX == ip2_to) | ||
| 235 | return -IPSET_ERR_HASH_RANGE; | ||
| 236 | |||
| 237 | } | ||
| 238 | |||
| 239 | if (retried) | ||
| 240 | ip = ntohl(h->next.ip[0]); | ||
| 241 | |||
| 242 | while (!after(ip, ip_to)) { | ||
| 243 | e.ip[0] = htonl(ip); | ||
| 244 | last = ip_set_range_to_cidr(ip, ip_to, &cidr); | ||
| 245 | e.cidr[0] = cidr; | ||
| 246 | ip2 = (retried && | ||
| 247 | ip == ntohl(h->next.ip[0])) ? ntohl(h->next.ip[1]) | ||
| 248 | : ip2_from; | ||
| 249 | while (!after(ip2, ip2_to)) { | ||
| 250 | e.ip[1] = htonl(ip2); | ||
| 251 | last2 = ip_set_range_to_cidr(ip2, ip2_to, &cidr2); | ||
| 252 | e.cidr[1] = cidr2; | ||
| 253 | ret = adtfn(set, &e, &ext, &ext, flags); | ||
| 254 | if (ret && !ip_set_eexist(ret, flags)) | ||
| 255 | return ret; | ||
| 256 | else | ||
| 257 | ret = 0; | ||
| 258 | ip2 = last2 + 1; | ||
| 259 | } | ||
| 260 | ip = last + 1; | ||
| 261 | } | ||
| 262 | return ret; | ||
| 263 | } | ||
| 264 | |||
| 265 | /* IPv6 variants */ | ||
| 266 | |||
| 267 | struct hash_netnet6_elem { | ||
| 268 | union nf_inet_addr ip[2]; | ||
| 269 | u8 nomatch; | ||
| 270 | union { | ||
| 271 | u8 cidr[2]; | ||
| 272 | u16 ccmp; | ||
| 273 | }; | ||
| 274 | }; | ||
| 275 | |||
| 276 | /* Common functions */ | ||
| 277 | |||
| 278 | static inline bool | ||
| 279 | hash_netnet6_data_equal(const struct hash_netnet6_elem *ip1, | ||
| 280 | const struct hash_netnet6_elem *ip2, | ||
| 281 | u32 *multi) | ||
| 282 | { | ||
| 283 | return ipv6_addr_equal(&ip1->ip[0].in6, &ip2->ip[0].in6) && | ||
| 284 | ipv6_addr_equal(&ip1->ip[1].in6, &ip2->ip[1].in6) && | ||
| 285 | ip1->ccmp == ip2->ccmp; | ||
| 286 | } | ||
| 287 | |||
| 288 | static inline int | ||
| 289 | hash_netnet6_do_data_match(const struct hash_netnet6_elem *elem) | ||
| 290 | { | ||
| 291 | return elem->nomatch ? -ENOTEMPTY : 1; | ||
| 292 | } | ||
| 293 | |||
| 294 | static inline void | ||
| 295 | hash_netnet6_data_set_flags(struct hash_netnet6_elem *elem, u32 flags) | ||
| 296 | { | ||
| 297 | elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH; | ||
| 298 | } | ||
| 299 | |||
| 300 | static inline void | ||
| 301 | hash_netnet6_data_reset_flags(struct hash_netnet6_elem *elem, u8 *flags) | ||
| 302 | { | ||
| 303 | swap(*flags, elem->nomatch); | ||
| 304 | } | ||
| 305 | |||
| 306 | static inline void | ||
| 307 | hash_netnet6_data_reset_elem(struct hash_netnet6_elem *elem, | ||
| 308 | struct hash_netnet6_elem *orig) | ||
| 309 | { | ||
| 310 | elem->ip[1] = orig->ip[1]; | ||
| 311 | } | ||
| 312 | |||
| 313 | static inline void | ||
| 314 | hash_netnet6_data_netmask(struct hash_netnet6_elem *elem, u8 cidr, bool inner) | ||
| 315 | { | ||
| 316 | if (inner) { | ||
| 317 | ip6_netmask(&elem->ip[1], cidr); | ||
| 318 | elem->cidr[1] = cidr; | ||
| 319 | } else { | ||
| 320 | ip6_netmask(&elem->ip[0], cidr); | ||
| 321 | elem->cidr[0] = cidr; | ||
| 322 | } | ||
| 323 | } | ||
| 324 | |||
| 325 | static bool | ||
| 326 | hash_netnet6_data_list(struct sk_buff *skb, | ||
| 327 | const struct hash_netnet6_elem *data) | ||
| 328 | { | ||
| 329 | u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; | ||
| 330 | |||
| 331 | if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip[0].in6) || | ||
| 332 | nla_put_ipaddr6(skb, IPSET_ATTR_IP2, &data->ip[1].in6) || | ||
| 333 | nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0]) || | ||
| 334 | nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr[1]) || | ||
| 335 | (flags && | ||
| 336 | nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)))) | ||
| 337 | goto nla_put_failure; | ||
| 338 | return 0; | ||
| 339 | |||
| 340 | nla_put_failure: | ||
| 341 | return 1; | ||
| 342 | } | ||
| 343 | |||
| 344 | static inline void | ||
| 345 | hash_netnet6_data_next(struct hash_netnet4_elem *next, | ||
| 346 | const struct hash_netnet6_elem *d) | ||
| 347 | { | ||
| 348 | } | ||
| 349 | |||
| 350 | #undef MTYPE | ||
| 351 | #undef PF | ||
| 352 | #undef HOST_MASK | ||
| 353 | |||
| 354 | #define MTYPE hash_netnet6 | ||
| 355 | #define PF 6 | ||
| 356 | #define HOST_MASK 128 | ||
| 357 | #define IP_SET_EMIT_CREATE | ||
| 358 | #include "ip_set_hash_gen.h" | ||
| 359 | |||
| 360 | static int | ||
| 361 | hash_netnet6_kadt(struct ip_set *set, const struct sk_buff *skb, | ||
| 362 | const struct xt_action_param *par, | ||
| 363 | enum ipset_adt adt, struct ip_set_adt_opt *opt) | ||
| 364 | { | ||
| 365 | const struct hash_netnet *h = set->data; | ||
| 366 | ipset_adtfn adtfn = set->variant->adt[adt]; | ||
| 367 | struct hash_netnet6_elem e = { | ||
| 368 | .cidr[0] = h->nets[0].cidr[0] ? h->nets[0].cidr[0] : HOST_MASK, | ||
| 369 | .cidr[1] = h->nets[0].cidr[1] ? h->nets[0].cidr[1] : HOST_MASK | ||
| 370 | }; | ||
| 371 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); | ||
| 372 | |||
| 373 | if (adt == IPSET_TEST) | ||
| 374 | e.ccmp = (HOST_MASK << (sizeof(u8)*8)) | HOST_MASK; | ||
| 375 | |||
| 376 | ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0].in6); | ||
| 377 | ip6addrptr(skb, opt->flags & IPSET_DIM_TWO_SRC, &e.ip[1].in6); | ||
| 378 | ip6_netmask(&e.ip[0], e.cidr[0]); | ||
| 379 | ip6_netmask(&e.ip[1], e.cidr[1]); | ||
| 380 | |||
| 381 | return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); | ||
| 382 | } | ||
| 383 | |||
| 384 | static int | ||
| 385 | hash_netnet6_uadt(struct ip_set *set, struct nlattr *tb[], | ||
| 386 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) | ||
| 387 | { | ||
| 388 | ipset_adtfn adtfn = set->variant->adt[adt]; | ||
| 389 | struct hash_netnet6_elem e = { .cidr[0] = HOST_MASK, | ||
| 390 | .cidr[1] = HOST_MASK }; | ||
| 391 | struct ip_set_ext ext = IP_SET_INIT_UEXT(set); | ||
| 392 | int ret; | ||
| 393 | |||
| 394 | if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || | ||
| 395 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | ||
| 396 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || | ||
| 397 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | ||
| 398 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) | ||
| 399 | return -IPSET_ERR_PROTOCOL; | ||
| 400 | if (unlikely(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_IP2_TO])) | ||
| 401 | return -IPSET_ERR_HASH_RANGE_UNSUPPORTED; | ||
| 402 | |||
| 403 | if (tb[IPSET_ATTR_LINENO]) | ||
| 404 | *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); | ||
| 405 | |||
| 406 | ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip[0]) || | ||
| 407 | ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &e.ip[1]) || | ||
| 408 | ip_set_get_extensions(set, tb, &ext); | ||
| 409 | if (ret) | ||
| 410 | return ret; | ||
| 411 | |||
| 412 | if (tb[IPSET_ATTR_CIDR]) | ||
| 413 | e.cidr[0] = nla_get_u8(tb[IPSET_ATTR_CIDR]); | ||
| 414 | |||
| 415 | if (tb[IPSET_ATTR_CIDR2]) | ||
| 416 | e.cidr[1] = nla_get_u8(tb[IPSET_ATTR_CIDR2]); | ||
| 417 | |||
| 418 | if (!e.cidr[0] || e.cidr[0] > HOST_MASK || !e.cidr[1] || | ||
| 419 | e.cidr[1] > HOST_MASK) | ||
| 420 | return -IPSET_ERR_INVALID_CIDR; | ||
| 421 | |||
| 422 | ip6_netmask(&e.ip[0], e.cidr[0]); | ||
| 423 | ip6_netmask(&e.ip[1], e.cidr[1]); | ||
| 424 | |||
| 425 | if (tb[IPSET_ATTR_CADT_FLAGS]) { | ||
| 426 | u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); | ||
| 427 | if (cadt_flags & IPSET_FLAG_NOMATCH) | ||
| 428 | flags |= (IPSET_FLAG_NOMATCH << 16); | ||
| 429 | } | ||
| 430 | |||
| 431 | ret = adtfn(set, &e, &ext, &ext, flags); | ||
| 432 | |||
| 433 | return ip_set_enomatch(ret, flags, adt, set) ? -ret : | ||
| 434 | ip_set_eexist(ret, flags) ? 0 : ret; | ||
| 435 | } | ||
| 436 | |||
| 437 | static struct ip_set_type hash_netnet_type __read_mostly = { | ||
| 438 | .name = "hash:net,net", | ||
| 439 | .protocol = IPSET_PROTOCOL, | ||
| 440 | .features = IPSET_TYPE_IP | IPSET_TYPE_IP2 | IPSET_TYPE_NOMATCH, | ||
| 441 | .dimension = IPSET_DIM_TWO, | ||
| 442 | .family = NFPROTO_UNSPEC, | ||
| 443 | .revision_min = IPSET_TYPE_REV_MIN, | ||
| 444 | .revision_max = IPSET_TYPE_REV_MAX, | ||
| 445 | .create = hash_netnet_create, | ||
| 446 | .create_policy = { | ||
| 447 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, | ||
| 448 | [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 }, | ||
| 449 | [IPSET_ATTR_PROBES] = { .type = NLA_U8 }, | ||
| 450 | [IPSET_ATTR_RESIZE] = { .type = NLA_U8 }, | ||
| 451 | [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, | ||
| 452 | [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, | ||
| 453 | }, | ||
| 454 | .adt_policy = { | ||
| 455 | [IPSET_ATTR_IP] = { .type = NLA_NESTED }, | ||
| 456 | [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, | ||
| 457 | [IPSET_ATTR_IP2] = { .type = NLA_NESTED }, | ||
| 458 | [IPSET_ATTR_IP2_TO] = { .type = NLA_NESTED }, | ||
| 459 | [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, | ||
| 460 | [IPSET_ATTR_CIDR2] = { .type = NLA_U8 }, | ||
| 461 | [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, | ||
| 462 | [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, | ||
| 463 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | ||
| 464 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | ||
| 465 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | ||
| 466 | }, | ||
| 467 | .me = THIS_MODULE, | ||
| 468 | }; | ||
| 469 | |||
| 470 | static int __init | ||
| 471 | hash_netnet_init(void) | ||
| 472 | { | ||
| 473 | return ip_set_type_register(&hash_netnet_type); | ||
| 474 | } | ||
| 475 | |||
| 476 | static void __exit | ||
| 477 | hash_netnet_fini(void) | ||
| 478 | { | ||
| 479 | ip_set_type_unregister(&hash_netnet_type); | ||
| 480 | } | ||
| 481 | |||
| 482 | module_init(hash_netnet_init); | ||
| 483 | 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 09d6690bee6f..7097fb0141bf 100644 --- a/net/netfilter/ipset/ip_set_hash_netport.c +++ b/net/netfilter/ipset/ip_set_hash_netport.c | |||
| @@ -23,15 +23,16 @@ | |||
| 23 | #include <linux/netfilter/ipset/ip_set_getport.h> | 23 | #include <linux/netfilter/ipset/ip_set_getport.h> |
| 24 | #include <linux/netfilter/ipset/ip_set_hash.h> | 24 | #include <linux/netfilter/ipset/ip_set_hash.h> |
| 25 | 25 | ||
| 26 | #define REVISION_MIN 0 | 26 | #define IPSET_TYPE_REV_MIN 0 |
| 27 | /* 1 SCTP and UDPLITE support added */ | 27 | /* 1 SCTP and UDPLITE support added */ |
| 28 | /* 2 Range as input support for IPv4 added */ | 28 | /* 2 Range as input support for IPv4 added */ |
| 29 | /* 3 nomatch flag support added */ | 29 | /* 3 nomatch flag support added */ |
| 30 | #define REVISION_MAX 4 /* Counters support added */ | 30 | /* 4 Counters support added */ |
| 31 | #define IPSET_TYPE_REV_MAX 5 /* Comments support added */ | ||
| 31 | 32 | ||
| 32 | MODULE_LICENSE("GPL"); | 33 | MODULE_LICENSE("GPL"); |
| 33 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); | 34 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); |
| 34 | IP_SET_MODULE_DESC("hash:net,port", REVISION_MIN, REVISION_MAX); | 35 | IP_SET_MODULE_DESC("hash:net,port", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX); |
| 35 | MODULE_ALIAS("ip_set_hash:net,port"); | 36 | MODULE_ALIAS("ip_set_hash:net,port"); |
| 36 | 37 | ||
| 37 | /* Type specific function prefix */ | 38 | /* Type specific function prefix */ |
| @@ -45,7 +46,7 @@ MODULE_ALIAS("ip_set_hash:net,port"); | |||
| 45 | */ | 46 | */ |
| 46 | #define IP_SET_HASH_WITH_NETS_PACKED | 47 | #define IP_SET_HASH_WITH_NETS_PACKED |
| 47 | 48 | ||
| 48 | /* IPv4 variants */ | 49 | /* IPv4 variant */ |
| 49 | 50 | ||
| 50 | /* Member elements */ | 51 | /* Member elements */ |
| 51 | struct hash_netport4_elem { | 52 | struct hash_netport4_elem { |
| @@ -56,34 +57,6 @@ struct hash_netport4_elem { | |||
| 56 | u8 nomatch:1; | 57 | u8 nomatch:1; |
| 57 | }; | 58 | }; |
| 58 | 59 | ||
| 59 | struct hash_netport4t_elem { | ||
| 60 | __be32 ip; | ||
| 61 | __be16 port; | ||
| 62 | u8 proto; | ||
| 63 | u8 cidr:7; | ||
| 64 | u8 nomatch:1; | ||
| 65 | unsigned long timeout; | ||
| 66 | }; | ||
| 67 | |||
| 68 | struct hash_netport4c_elem { | ||
| 69 | __be32 ip; | ||
| 70 | __be16 port; | ||
| 71 | u8 proto; | ||
| 72 | u8 cidr:7; | ||
| 73 | u8 nomatch:1; | ||
| 74 | struct ip_set_counter counter; | ||
| 75 | }; | ||
| 76 | |||
| 77 | struct hash_netport4ct_elem { | ||
| 78 | __be32 ip; | ||
| 79 | __be16 port; | ||
| 80 | u8 proto; | ||
| 81 | u8 cidr:7; | ||
| 82 | u8 nomatch:1; | ||
| 83 | struct ip_set_counter counter; | ||
| 84 | unsigned long timeout; | ||
| 85 | }; | ||
| 86 | |||
| 87 | /* Common functions */ | 60 | /* Common functions */ |
| 88 | 61 | ||
| 89 | static inline bool | 62 | static inline bool |
| @@ -162,9 +135,9 @@ hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
| 162 | const struct hash_netport *h = set->data; | 135 | const struct hash_netport *h = set->data; |
| 163 | ipset_adtfn adtfn = set->variant->adt[adt]; | 136 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 164 | struct hash_netport4_elem e = { | 137 | struct hash_netport4_elem e = { |
| 165 | .cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1 | 138 | .cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK) - 1, |
| 166 | }; | 139 | }; |
| 167 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h); | 140 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); |
| 168 | 141 | ||
| 169 | if (adt == IPSET_TEST) | 142 | if (adt == IPSET_TEST) |
| 170 | e.cidr = HOST_MASK - 1; | 143 | e.cidr = HOST_MASK - 1; |
| @@ -186,8 +159,8 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 186 | const struct hash_netport *h = set->data; | 159 | const struct hash_netport *h = set->data; |
| 187 | ipset_adtfn adtfn = set->variant->adt[adt]; | 160 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 188 | struct hash_netport4_elem e = { .cidr = HOST_MASK - 1 }; | 161 | struct hash_netport4_elem e = { .cidr = HOST_MASK - 1 }; |
| 189 | struct ip_set_ext ext = IP_SET_INIT_UEXT(h); | 162 | struct ip_set_ext ext = IP_SET_INIT_UEXT(set); |
| 190 | u32 port, port_to, p = 0, ip = 0, ip_to, last; | 163 | u32 port, port_to, p = 0, ip = 0, ip_to = 0, last; |
| 191 | bool with_ports = false; | 164 | bool with_ports = false; |
| 192 | u8 cidr; | 165 | u8 cidr; |
| 193 | int ret; | 166 | int ret; |
| @@ -287,7 +260,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 287 | return ret; | 260 | return ret; |
| 288 | } | 261 | } |
| 289 | 262 | ||
| 290 | /* IPv6 variants */ | 263 | /* IPv6 variant */ |
| 291 | 264 | ||
| 292 | struct hash_netport6_elem { | 265 | struct hash_netport6_elem { |
| 293 | union nf_inet_addr ip; | 266 | union nf_inet_addr ip; |
| @@ -297,34 +270,6 @@ struct hash_netport6_elem { | |||
| 297 | u8 nomatch:1; | 270 | u8 nomatch:1; |
| 298 | }; | 271 | }; |
| 299 | 272 | ||
| 300 | struct hash_netport6t_elem { | ||
| 301 | union nf_inet_addr ip; | ||
| 302 | __be16 port; | ||
| 303 | u8 proto; | ||
| 304 | u8 cidr:7; | ||
| 305 | u8 nomatch:1; | ||
| 306 | unsigned long timeout; | ||
| 307 | }; | ||
| 308 | |||
| 309 | struct hash_netport6c_elem { | ||
| 310 | union nf_inet_addr ip; | ||
| 311 | __be16 port; | ||
| 312 | u8 proto; | ||
| 313 | u8 cidr:7; | ||
| 314 | u8 nomatch:1; | ||
| 315 | struct ip_set_counter counter; | ||
| 316 | }; | ||
| 317 | |||
| 318 | struct hash_netport6ct_elem { | ||
| 319 | union nf_inet_addr ip; | ||
| 320 | __be16 port; | ||
| 321 | u8 proto; | ||
| 322 | u8 cidr:7; | ||
| 323 | u8 nomatch:1; | ||
| 324 | struct ip_set_counter counter; | ||
| 325 | unsigned long timeout; | ||
| 326 | }; | ||
| 327 | |||
| 328 | /* Common functions */ | 273 | /* Common functions */ |
| 329 | 274 | ||
| 330 | static inline bool | 275 | static inline bool |
| @@ -407,9 +352,9 @@ hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
| 407 | const struct hash_netport *h = set->data; | 352 | const struct hash_netport *h = set->data; |
| 408 | ipset_adtfn adtfn = set->variant->adt[adt]; | 353 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 409 | struct hash_netport6_elem e = { | 354 | struct hash_netport6_elem e = { |
| 410 | .cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1, | 355 | .cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK) - 1, |
| 411 | }; | 356 | }; |
| 412 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h); | 357 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); |
| 413 | 358 | ||
| 414 | if (adt == IPSET_TEST) | 359 | if (adt == IPSET_TEST) |
| 415 | e.cidr = HOST_MASK - 1; | 360 | e.cidr = HOST_MASK - 1; |
| @@ -431,7 +376,7 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 431 | const struct hash_netport *h = set->data; | 376 | const struct hash_netport *h = set->data; |
| 432 | ipset_adtfn adtfn = set->variant->adt[adt]; | 377 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 433 | struct hash_netport6_elem e = { .cidr = HOST_MASK - 1 }; | 378 | struct hash_netport6_elem e = { .cidr = HOST_MASK - 1 }; |
| 434 | struct ip_set_ext ext = IP_SET_INIT_UEXT(h); | 379 | struct ip_set_ext ext = IP_SET_INIT_UEXT(set); |
| 435 | u32 port, port_to; | 380 | u32 port, port_to; |
| 436 | bool with_ports = false; | 381 | bool with_ports = false; |
| 437 | u8 cidr; | 382 | u8 cidr; |
| @@ -518,8 +463,8 @@ static struct ip_set_type hash_netport_type __read_mostly = { | |||
| 518 | .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_NOMATCH, | 463 | .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_NOMATCH, |
| 519 | .dimension = IPSET_DIM_TWO, | 464 | .dimension = IPSET_DIM_TWO, |
| 520 | .family = NFPROTO_UNSPEC, | 465 | .family = NFPROTO_UNSPEC, |
| 521 | .revision_min = REVISION_MIN, | 466 | .revision_min = IPSET_TYPE_REV_MIN, |
| 522 | .revision_max = REVISION_MAX, | 467 | .revision_max = IPSET_TYPE_REV_MAX, |
| 523 | .create = hash_netport_create, | 468 | .create = hash_netport_create, |
| 524 | .create_policy = { | 469 | .create_policy = { |
| 525 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, | 470 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, |
| @@ -542,6 +487,7 @@ static struct ip_set_type hash_netport_type __read_mostly = { | |||
| 542 | [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, | 487 | [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, |
| 543 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | 488 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, |
| 544 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | 489 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, |
| 490 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | ||
| 545 | }, | 491 | }, |
| 546 | .me = THIS_MODULE, | 492 | .me = THIS_MODULE, |
| 547 | }; | 493 | }; |
diff --git a/net/netfilter/ipset/ip_set_hash_netportnet.c b/net/netfilter/ipset/ip_set_hash_netportnet.c new file mode 100644 index 000000000000..363fab933d48 --- /dev/null +++ b/net/netfilter/ipset/ip_set_hash_netportnet.c | |||
| @@ -0,0 +1,588 @@ | |||
| 1 | /* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | ||
| 2 | * | ||
| 3 | * This program is free software; you can redistribute it and/or modify | ||
| 4 | * it under the terms of the GNU General Public License version 2 as | ||
| 5 | * published by the Free Software Foundation. | ||
| 6 | */ | ||
| 7 | |||
| 8 | /* Kernel module implementing an IP set type: the hash:ip,port,net type */ | ||
| 9 | |||
| 10 | #include <linux/jhash.h> | ||
| 11 | #include <linux/module.h> | ||
| 12 | #include <linux/ip.h> | ||
| 13 | #include <linux/skbuff.h> | ||
| 14 | #include <linux/errno.h> | ||
| 15 | #include <linux/random.h> | ||
| 16 | #include <net/ip.h> | ||
| 17 | #include <net/ipv6.h> | ||
| 18 | #include <net/netlink.h> | ||
| 19 | #include <net/tcp.h> | ||
| 20 | |||
| 21 | #include <linux/netfilter.h> | ||
| 22 | #include <linux/netfilter/ipset/pfxlen.h> | ||
| 23 | #include <linux/netfilter/ipset/ip_set.h> | ||
| 24 | #include <linux/netfilter/ipset/ip_set_getport.h> | ||
| 25 | #include <linux/netfilter/ipset/ip_set_hash.h> | ||
| 26 | |||
| 27 | #define IPSET_TYPE_REV_MIN 0 | ||
| 28 | #define IPSET_TYPE_REV_MAX 0 /* Comments support added */ | ||
| 29 | |||
| 30 | MODULE_LICENSE("GPL"); | ||
| 31 | MODULE_AUTHOR("Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>"); | ||
| 32 | IP_SET_MODULE_DESC("hash:net,port,net", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX); | ||
| 33 | MODULE_ALIAS("ip_set_hash:net,port,net"); | ||
| 34 | |||
| 35 | /* Type specific function prefix */ | ||
| 36 | #define HTYPE hash_netportnet | ||
| 37 | #define IP_SET_HASH_WITH_PROTO | ||
| 38 | #define IP_SET_HASH_WITH_NETS | ||
| 39 | #define IPSET_NET_COUNT 2 | ||
| 40 | |||
| 41 | /* IPv4 variant */ | ||
| 42 | |||
| 43 | /* Member elements */ | ||
| 44 | struct hash_netportnet4_elem { | ||
| 45 | union { | ||
| 46 | __be32 ip[2]; | ||
| 47 | __be64 ipcmp; | ||
| 48 | }; | ||
| 49 | __be16 port; | ||
| 50 | union { | ||
| 51 | u8 cidr[2]; | ||
| 52 | u16 ccmp; | ||
| 53 | }; | ||
| 54 | u8 nomatch:1; | ||
| 55 | u8 proto; | ||
| 56 | }; | ||
| 57 | |||
| 58 | /* Common functions */ | ||
| 59 | |||
| 60 | static inline bool | ||
| 61 | hash_netportnet4_data_equal(const struct hash_netportnet4_elem *ip1, | ||
| 62 | const struct hash_netportnet4_elem *ip2, | ||
| 63 | u32 *multi) | ||
| 64 | { | ||
| 65 | return ip1->ipcmp == ip2->ipcmp && | ||
| 66 | ip1->ccmp == ip2->ccmp && | ||
| 67 | ip1->port == ip2->port && | ||
| 68 | ip1->proto == ip2->proto; | ||
| 69 | } | ||
| 70 | |||
| 71 | static inline int | ||
| 72 | hash_netportnet4_do_data_match(const struct hash_netportnet4_elem *elem) | ||
| 73 | { | ||
| 74 | return elem->nomatch ? -ENOTEMPTY : 1; | ||
| 75 | } | ||
| 76 | |||
| 77 | static inline void | ||
| 78 | hash_netportnet4_data_set_flags(struct hash_netportnet4_elem *elem, u32 flags) | ||
| 79 | { | ||
| 80 | elem->nomatch = !!((flags >> 16) & IPSET_FLAG_NOMATCH); | ||
| 81 | } | ||
| 82 | |||
| 83 | static inline void | ||
| 84 | hash_netportnet4_data_reset_flags(struct hash_netportnet4_elem *elem, u8 *flags) | ||
| 85 | { | ||
| 86 | swap(*flags, elem->nomatch); | ||
| 87 | } | ||
| 88 | |||
| 89 | static inline void | ||
| 90 | hash_netportnet4_data_reset_elem(struct hash_netportnet4_elem *elem, | ||
| 91 | struct hash_netportnet4_elem *orig) | ||
| 92 | { | ||
| 93 | elem->ip[1] = orig->ip[1]; | ||
| 94 | } | ||
| 95 | |||
| 96 | static inline void | ||
| 97 | hash_netportnet4_data_netmask(struct hash_netportnet4_elem *elem, | ||
| 98 | u8 cidr, bool inner) | ||
| 99 | { | ||
| 100 | if (inner) { | ||
| 101 | elem->ip[1] &= ip_set_netmask(cidr); | ||
| 102 | elem->cidr[1] = cidr; | ||
| 103 | } else { | ||
| 104 | elem->ip[0] &= ip_set_netmask(cidr); | ||
| 105 | elem->cidr[0] = cidr; | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | static bool | ||
| 110 | hash_netportnet4_data_list(struct sk_buff *skb, | ||
| 111 | const struct hash_netportnet4_elem *data) | ||
| 112 | { | ||
| 113 | u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; | ||
| 114 | |||
| 115 | if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip[0]) || | ||
| 116 | nla_put_ipaddr4(skb, IPSET_ATTR_IP2, data->ip[1]) || | ||
| 117 | nla_put_net16(skb, IPSET_ATTR_PORT, data->port) || | ||
| 118 | nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0]) || | ||
| 119 | nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr[1]) || | ||
| 120 | nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) || | ||
| 121 | (flags && | ||
| 122 | nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)))) | ||
| 123 | goto nla_put_failure; | ||
| 124 | return 0; | ||
| 125 | |||
| 126 | nla_put_failure: | ||
| 127 | return 1; | ||
| 128 | } | ||
| 129 | |||
| 130 | static inline void | ||
| 131 | hash_netportnet4_data_next(struct hash_netportnet4_elem *next, | ||
| 132 | const struct hash_netportnet4_elem *d) | ||
| 133 | { | ||
| 134 | next->ipcmp = d->ipcmp; | ||
| 135 | next->port = d->port; | ||
| 136 | } | ||
| 137 | |||
| 138 | #define MTYPE hash_netportnet4 | ||
| 139 | #define PF 4 | ||
| 140 | #define HOST_MASK 32 | ||
| 141 | #include "ip_set_hash_gen.h" | ||
| 142 | |||
| 143 | static int | ||
| 144 | hash_netportnet4_kadt(struct ip_set *set, const struct sk_buff *skb, | ||
| 145 | const struct xt_action_param *par, | ||
| 146 | enum ipset_adt adt, struct ip_set_adt_opt *opt) | ||
| 147 | { | ||
| 148 | const struct hash_netportnet *h = set->data; | ||
| 149 | ipset_adtfn adtfn = set->variant->adt[adt]; | ||
| 150 | struct hash_netportnet4_elem e = { | ||
| 151 | .cidr[0] = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK), | ||
| 152 | .cidr[1] = IP_SET_INIT_CIDR(h->nets[0].cidr[1], HOST_MASK), | ||
| 153 | }; | ||
| 154 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); | ||
| 155 | |||
| 156 | if (adt == IPSET_TEST) | ||
| 157 | e.ccmp = (HOST_MASK << (sizeof(e.cidr[0]) * 8)) | HOST_MASK; | ||
| 158 | |||
| 159 | if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC, | ||
| 160 | &e.port, &e.proto)) | ||
| 161 | return -EINVAL; | ||
| 162 | |||
| 163 | ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0]); | ||
| 164 | ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip[1]); | ||
| 165 | e.ip[0] &= ip_set_netmask(e.cidr[0]); | ||
| 166 | e.ip[1] &= ip_set_netmask(e.cidr[1]); | ||
| 167 | |||
| 168 | return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); | ||
| 169 | } | ||
| 170 | |||
| 171 | static int | ||
| 172 | hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[], | ||
| 173 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) | ||
| 174 | { | ||
| 175 | const struct hash_netportnet *h = set->data; | ||
| 176 | ipset_adtfn adtfn = set->variant->adt[adt]; | ||
| 177 | struct hash_netportnet4_elem e = { .cidr[0] = HOST_MASK, | ||
| 178 | .cidr[1] = HOST_MASK }; | ||
| 179 | struct ip_set_ext ext = IP_SET_INIT_UEXT(set); | ||
| 180 | u32 ip = 0, ip_to = 0, ip_last, p = 0, port, port_to; | ||
| 181 | u32 ip2_from = 0, ip2_to = 0, ip2_last, ip2; | ||
| 182 | bool with_ports = false; | ||
| 183 | u8 cidr, cidr2; | ||
| 184 | int ret; | ||
| 185 | |||
| 186 | if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || | ||
| 187 | !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || | ||
| 188 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || | ||
| 189 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | ||
| 190 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || | ||
| 191 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | ||
| 192 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) | ||
| 193 | return -IPSET_ERR_PROTOCOL; | ||
| 194 | |||
| 195 | if (tb[IPSET_ATTR_LINENO]) | ||
| 196 | *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); | ||
| 197 | |||
| 198 | ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip) || | ||
| 199 | ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2], &ip2_from) || | ||
| 200 | ip_set_get_extensions(set, tb, &ext); | ||
| 201 | if (ret) | ||
| 202 | return ret; | ||
| 203 | |||
| 204 | if (tb[IPSET_ATTR_CIDR]) { | ||
| 205 | cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); | ||
| 206 | if (!cidr || cidr > HOST_MASK) | ||
| 207 | return -IPSET_ERR_INVALID_CIDR; | ||
| 208 | e.cidr[0] = cidr; | ||
| 209 | } | ||
| 210 | |||
| 211 | if (tb[IPSET_ATTR_CIDR2]) { | ||
| 212 | cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]); | ||
| 213 | if (!cidr || cidr > HOST_MASK) | ||
| 214 | return -IPSET_ERR_INVALID_CIDR; | ||
| 215 | e.cidr[1] = cidr; | ||
| 216 | } | ||
| 217 | |||
| 218 | if (tb[IPSET_ATTR_PORT]) | ||
| 219 | e.port = nla_get_be16(tb[IPSET_ATTR_PORT]); | ||
| 220 | else | ||
| 221 | return -IPSET_ERR_PROTOCOL; | ||
| 222 | |||
| 223 | if (tb[IPSET_ATTR_PROTO]) { | ||
| 224 | e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); | ||
| 225 | with_ports = ip_set_proto_with_ports(e.proto); | ||
| 226 | |||
| 227 | if (e.proto == 0) | ||
| 228 | return -IPSET_ERR_INVALID_PROTO; | ||
| 229 | } else | ||
| 230 | return -IPSET_ERR_MISSING_PROTO; | ||
| 231 | |||
| 232 | if (!(with_ports || e.proto == IPPROTO_ICMP)) | ||
| 233 | e.port = 0; | ||
| 234 | |||
| 235 | if (tb[IPSET_ATTR_CADT_FLAGS]) { | ||
| 236 | u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); | ||
| 237 | if (cadt_flags & IPSET_FLAG_NOMATCH) | ||
| 238 | flags |= (IPSET_FLAG_NOMATCH << 16); | ||
| 239 | } | ||
| 240 | |||
| 241 | with_ports = with_ports && tb[IPSET_ATTR_PORT_TO]; | ||
| 242 | if (adt == IPSET_TEST || | ||
| 243 | !(tb[IPSET_ATTR_IP_TO] || with_ports || tb[IPSET_ATTR_IP2_TO])) { | ||
| 244 | e.ip[0] = htonl(ip & ip_set_hostmask(e.cidr[0])); | ||
| 245 | e.ip[1] = htonl(ip2_from & ip_set_hostmask(e.cidr[1])); | ||
| 246 | ret = adtfn(set, &e, &ext, &ext, flags); | ||
| 247 | return ip_set_enomatch(ret, flags, adt, set) ? -ret : | ||
| 248 | ip_set_eexist(ret, flags) ? 0 : ret; | ||
| 249 | } | ||
| 250 | |||
| 251 | ip_to = ip; | ||
| 252 | if (tb[IPSET_ATTR_IP_TO]) { | ||
| 253 | ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); | ||
| 254 | if (ret) | ||
| 255 | return ret; | ||
| 256 | if (ip > ip_to) | ||
| 257 | swap(ip, ip_to); | ||
| 258 | if (unlikely(ip + UINT_MAX == ip_to)) | ||
| 259 | return -IPSET_ERR_HASH_RANGE; | ||
| 260 | } | ||
| 261 | |||
| 262 | port_to = port = ntohs(e.port); | ||
| 263 | if (tb[IPSET_ATTR_PORT_TO]) { | ||
| 264 | port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]); | ||
| 265 | if (port > port_to) | ||
| 266 | swap(port, port_to); | ||
| 267 | } | ||
| 268 | |||
| 269 | ip2_to = ip2_from; | ||
| 270 | if (tb[IPSET_ATTR_IP2_TO]) { | ||
| 271 | ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2_TO], &ip2_to); | ||
| 272 | if (ret) | ||
| 273 | return ret; | ||
| 274 | if (ip2_from > ip2_to) | ||
| 275 | swap(ip2_from, ip2_to); | ||
| 276 | if (unlikely(ip2_from + UINT_MAX == ip2_to)) | ||
| 277 | return -IPSET_ERR_HASH_RANGE; | ||
| 278 | } | ||
| 279 | |||
| 280 | if (retried) | ||
| 281 | ip = ntohl(h->next.ip[0]); | ||
| 282 | |||
| 283 | while (!after(ip, ip_to)) { | ||
| 284 | e.ip[0] = htonl(ip); | ||
| 285 | ip_last = ip_set_range_to_cidr(ip, ip_to, &cidr); | ||
| 286 | e.cidr[0] = cidr; | ||
| 287 | p = retried && ip == ntohl(h->next.ip[0]) ? ntohs(h->next.port) | ||
| 288 | : port; | ||
| 289 | for (; p <= port_to; p++) { | ||
| 290 | e.port = htons(p); | ||
| 291 | ip2 = (retried && ip == ntohl(h->next.ip[0]) && | ||
| 292 | p == ntohs(h->next.port)) ? ntohl(h->next.ip[1]) | ||
| 293 | : ip2_from; | ||
| 294 | while (!after(ip2, ip2_to)) { | ||
| 295 | e.ip[1] = htonl(ip2); | ||
| 296 | ip2_last = ip_set_range_to_cidr(ip2, ip2_to, | ||
| 297 | &cidr2); | ||
| 298 | e.cidr[1] = cidr2; | ||
| 299 | ret = adtfn(set, &e, &ext, &ext, flags); | ||
| 300 | if (ret && !ip_set_eexist(ret, flags)) | ||
| 301 | return ret; | ||
| 302 | else | ||
| 303 | ret = 0; | ||
| 304 | ip2 = ip2_last + 1; | ||
| 305 | } | ||
| 306 | } | ||
| 307 | ip = ip_last + 1; | ||
| 308 | } | ||
| 309 | return ret; | ||
| 310 | } | ||
| 311 | |||
| 312 | /* IPv6 variant */ | ||
| 313 | |||
| 314 | struct hash_netportnet6_elem { | ||
| 315 | union nf_inet_addr ip[2]; | ||
| 316 | __be16 port; | ||
| 317 | union { | ||
| 318 | u8 cidr[2]; | ||
| 319 | u16 ccmp; | ||
| 320 | }; | ||
| 321 | u8 nomatch:1; | ||
| 322 | u8 proto; | ||
| 323 | }; | ||
| 324 | |||
| 325 | /* Common functions */ | ||
| 326 | |||
| 327 | static inline bool | ||
| 328 | hash_netportnet6_data_equal(const struct hash_netportnet6_elem *ip1, | ||
| 329 | const struct hash_netportnet6_elem *ip2, | ||
| 330 | u32 *multi) | ||
| 331 | { | ||
| 332 | return ipv6_addr_equal(&ip1->ip[0].in6, &ip2->ip[0].in6) && | ||
| 333 | ipv6_addr_equal(&ip1->ip[1].in6, &ip2->ip[1].in6) && | ||
| 334 | ip1->ccmp == ip2->ccmp && | ||
| 335 | ip1->port == ip2->port && | ||
| 336 | ip1->proto == ip2->proto; | ||
| 337 | } | ||
| 338 | |||
| 339 | static inline int | ||
| 340 | hash_netportnet6_do_data_match(const struct hash_netportnet6_elem *elem) | ||
| 341 | { | ||
| 342 | return elem->nomatch ? -ENOTEMPTY : 1; | ||
| 343 | } | ||
| 344 | |||
| 345 | static inline void | ||
| 346 | hash_netportnet6_data_set_flags(struct hash_netportnet6_elem *elem, u32 flags) | ||
| 347 | { | ||
| 348 | elem->nomatch = !!((flags >> 16) & IPSET_FLAG_NOMATCH); | ||
| 349 | } | ||
| 350 | |||
| 351 | static inline void | ||
| 352 | hash_netportnet6_data_reset_flags(struct hash_netportnet6_elem *elem, u8 *flags) | ||
| 353 | { | ||
| 354 | swap(*flags, elem->nomatch); | ||
| 355 | } | ||
| 356 | |||
| 357 | static inline void | ||
| 358 | hash_netportnet6_data_reset_elem(struct hash_netportnet6_elem *elem, | ||
| 359 | struct hash_netportnet6_elem *orig) | ||
| 360 | { | ||
| 361 | elem->ip[1] = orig->ip[1]; | ||
| 362 | } | ||
| 363 | |||
| 364 | static inline void | ||
| 365 | hash_netportnet6_data_netmask(struct hash_netportnet6_elem *elem, | ||
| 366 | u8 cidr, bool inner) | ||
| 367 | { | ||
| 368 | if (inner) { | ||
| 369 | ip6_netmask(&elem->ip[1], cidr); | ||
| 370 | elem->cidr[1] = cidr; | ||
| 371 | } else { | ||
| 372 | ip6_netmask(&elem->ip[0], cidr); | ||
| 373 | elem->cidr[0] = cidr; | ||
| 374 | } | ||
| 375 | } | ||
| 376 | |||
| 377 | static bool | ||
| 378 | hash_netportnet6_data_list(struct sk_buff *skb, | ||
| 379 | const struct hash_netportnet6_elem *data) | ||
| 380 | { | ||
| 381 | u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; | ||
| 382 | |||
| 383 | if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip[0].in6) || | ||
| 384 | nla_put_ipaddr6(skb, IPSET_ATTR_IP2, &data->ip[1].in6) || | ||
| 385 | nla_put_net16(skb, IPSET_ATTR_PORT, data->port) || | ||
| 386 | nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0]) || | ||
| 387 | nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr[1]) || | ||
| 388 | nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) || | ||
| 389 | (flags && | ||
| 390 | nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)))) | ||
| 391 | goto nla_put_failure; | ||
| 392 | return 0; | ||
| 393 | |||
| 394 | nla_put_failure: | ||
| 395 | return 1; | ||
| 396 | } | ||
| 397 | |||
| 398 | static inline void | ||
| 399 | hash_netportnet6_data_next(struct hash_netportnet4_elem *next, | ||
| 400 | const struct hash_netportnet6_elem *d) | ||
| 401 | { | ||
| 402 | next->port = d->port; | ||
| 403 | } | ||
| 404 | |||
| 405 | #undef MTYPE | ||
| 406 | #undef PF | ||
| 407 | #undef HOST_MASK | ||
| 408 | |||
| 409 | #define MTYPE hash_netportnet6 | ||
| 410 | #define PF 6 | ||
| 411 | #define HOST_MASK 128 | ||
| 412 | #define IP_SET_EMIT_CREATE | ||
| 413 | #include "ip_set_hash_gen.h" | ||
| 414 | |||
| 415 | static int | ||
| 416 | hash_netportnet6_kadt(struct ip_set *set, const struct sk_buff *skb, | ||
| 417 | const struct xt_action_param *par, | ||
| 418 | enum ipset_adt adt, struct ip_set_adt_opt *opt) | ||
| 419 | { | ||
| 420 | const struct hash_netportnet *h = set->data; | ||
| 421 | ipset_adtfn adtfn = set->variant->adt[adt]; | ||
| 422 | struct hash_netportnet6_elem e = { | ||
| 423 | .cidr[0] = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK), | ||
| 424 | .cidr[1] = IP_SET_INIT_CIDR(h->nets[0].cidr[1], HOST_MASK), | ||
| 425 | }; | ||
| 426 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); | ||
| 427 | |||
| 428 | if (adt == IPSET_TEST) | ||
| 429 | e.ccmp = (HOST_MASK << (sizeof(u8) * 8)) | HOST_MASK; | ||
| 430 | |||
| 431 | if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC, | ||
| 432 | &e.port, &e.proto)) | ||
| 433 | return -EINVAL; | ||
| 434 | |||
| 435 | ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0].in6); | ||
| 436 | ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip[1].in6); | ||
| 437 | ip6_netmask(&e.ip[0], e.cidr[0]); | ||
| 438 | ip6_netmask(&e.ip[1], e.cidr[1]); | ||
| 439 | |||
| 440 | return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); | ||
| 441 | } | ||
| 442 | |||
| 443 | static int | ||
| 444 | hash_netportnet6_uadt(struct ip_set *set, struct nlattr *tb[], | ||
| 445 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) | ||
| 446 | { | ||
| 447 | const struct hash_netportnet *h = set->data; | ||
| 448 | ipset_adtfn adtfn = set->variant->adt[adt]; | ||
| 449 | struct hash_netportnet6_elem e = { .cidr[0] = HOST_MASK, | ||
| 450 | .cidr[1] = HOST_MASK }; | ||
| 451 | struct ip_set_ext ext = IP_SET_INIT_UEXT(set); | ||
| 452 | u32 port, port_to; | ||
| 453 | bool with_ports = false; | ||
| 454 | int ret; | ||
| 455 | |||
| 456 | if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || | ||
| 457 | !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || | ||
| 458 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || | ||
| 459 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | ||
| 460 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || | ||
| 461 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | ||
| 462 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) | ||
| 463 | return -IPSET_ERR_PROTOCOL; | ||
| 464 | if (unlikely(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_IP2_TO])) | ||
| 465 | return -IPSET_ERR_HASH_RANGE_UNSUPPORTED; | ||
| 466 | |||
| 467 | if (tb[IPSET_ATTR_LINENO]) | ||
| 468 | *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); | ||
| 469 | |||
| 470 | ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip[0]) || | ||
| 471 | ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &e.ip[1]) || | ||
| 472 | ip_set_get_extensions(set, tb, &ext); | ||
| 473 | if (ret) | ||
| 474 | return ret; | ||
| 475 | |||
| 476 | if (tb[IPSET_ATTR_CIDR]) | ||
| 477 | e.cidr[0] = nla_get_u8(tb[IPSET_ATTR_CIDR]); | ||
| 478 | |||
| 479 | if (tb[IPSET_ATTR_CIDR2]) | ||
| 480 | e.cidr[1] = nla_get_u8(tb[IPSET_ATTR_CIDR2]); | ||
| 481 | |||
| 482 | if (unlikely(!e.cidr[0] || e.cidr[0] > HOST_MASK || !e.cidr[1] || | ||
| 483 | e.cidr[1] > HOST_MASK)) | ||
| 484 | return -IPSET_ERR_INVALID_CIDR; | ||
| 485 | |||
| 486 | ip6_netmask(&e.ip[0], e.cidr[0]); | ||
| 487 | ip6_netmask(&e.ip[1], e.cidr[1]); | ||
| 488 | |||
| 489 | if (tb[IPSET_ATTR_PORT]) | ||
| 490 | e.port = nla_get_be16(tb[IPSET_ATTR_PORT]); | ||
| 491 | else | ||
| 492 | return -IPSET_ERR_PROTOCOL; | ||
| 493 | |||
| 494 | if (tb[IPSET_ATTR_PROTO]) { | ||
| 495 | e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); | ||
| 496 | with_ports = ip_set_proto_with_ports(e.proto); | ||
| 497 | |||
| 498 | if (e.proto == 0) | ||
| 499 | return -IPSET_ERR_INVALID_PROTO; | ||
| 500 | } else | ||
| 501 | return -IPSET_ERR_MISSING_PROTO; | ||
| 502 | |||
| 503 | if (!(with_ports || e.proto == IPPROTO_ICMPV6)) | ||
| 504 | e.port = 0; | ||
| 505 | |||
| 506 | if (tb[IPSET_ATTR_CADT_FLAGS]) { | ||
| 507 | u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); | ||
| 508 | if (cadt_flags & IPSET_FLAG_NOMATCH) | ||
| 509 | flags |= (IPSET_FLAG_NOMATCH << 16); | ||
| 510 | } | ||
| 511 | |||
| 512 | if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) { | ||
| 513 | ret = adtfn(set, &e, &ext, &ext, flags); | ||
| 514 | return ip_set_enomatch(ret, flags, adt, set) ? -ret : | ||
| 515 | ip_set_eexist(ret, flags) ? 0 : ret; | ||
| 516 | } | ||
| 517 | |||
| 518 | port = ntohs(e.port); | ||
| 519 | port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]); | ||
| 520 | if (port > port_to) | ||
| 521 | swap(port, port_to); | ||
| 522 | |||
| 523 | if (retried) | ||
| 524 | port = ntohs(h->next.port); | ||
| 525 | for (; port <= port_to; port++) { | ||
| 526 | e.port = htons(port); | ||
| 527 | ret = adtfn(set, &e, &ext, &ext, flags); | ||
| 528 | |||
| 529 | if (ret && !ip_set_eexist(ret, flags)) | ||
| 530 | return ret; | ||
| 531 | else | ||
| 532 | ret = 0; | ||
| 533 | } | ||
| 534 | return ret; | ||
| 535 | } | ||
| 536 | |||
| 537 | static struct ip_set_type hash_netportnet_type __read_mostly = { | ||
| 538 | .name = "hash:net,port,net", | ||
| 539 | .protocol = IPSET_PROTOCOL, | ||
| 540 | .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2 | | ||
| 541 | IPSET_TYPE_NOMATCH, | ||
| 542 | .dimension = IPSET_DIM_THREE, | ||
| 543 | .family = NFPROTO_UNSPEC, | ||
| 544 | .revision_min = IPSET_TYPE_REV_MIN, | ||
| 545 | .revision_max = IPSET_TYPE_REV_MAX, | ||
| 546 | .create = hash_netportnet_create, | ||
| 547 | .create_policy = { | ||
| 548 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, | ||
| 549 | [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 }, | ||
| 550 | [IPSET_ATTR_PROBES] = { .type = NLA_U8 }, | ||
| 551 | [IPSET_ATTR_RESIZE] = { .type = NLA_U8 }, | ||
| 552 | [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, | ||
| 553 | [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, | ||
| 554 | }, | ||
| 555 | .adt_policy = { | ||
| 556 | [IPSET_ATTR_IP] = { .type = NLA_NESTED }, | ||
| 557 | [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, | ||
| 558 | [IPSET_ATTR_IP2] = { .type = NLA_NESTED }, | ||
| 559 | [IPSET_ATTR_IP2_TO] = { .type = NLA_NESTED }, | ||
| 560 | [IPSET_ATTR_PORT] = { .type = NLA_U16 }, | ||
| 561 | [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 }, | ||
| 562 | [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, | ||
| 563 | [IPSET_ATTR_CIDR2] = { .type = NLA_U8 }, | ||
| 564 | [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, | ||
| 565 | [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, | ||
| 566 | [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, | ||
| 567 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, | ||
| 568 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | ||
| 569 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | ||
| 570 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | ||
| 571 | }, | ||
| 572 | .me = THIS_MODULE, | ||
| 573 | }; | ||
| 574 | |||
| 575 | static int __init | ||
| 576 | hash_netportnet_init(void) | ||
| 577 | { | ||
| 578 | return ip_set_type_register(&hash_netportnet_type); | ||
| 579 | } | ||
| 580 | |||
| 581 | static void __exit | ||
| 582 | hash_netportnet_fini(void) | ||
| 583 | { | ||
| 584 | ip_set_type_unregister(&hash_netportnet_type); | ||
| 585 | } | ||
| 586 | |||
| 587 | module_init(hash_netportnet_init); | ||
| 588 | 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 979b8c90e422..ec6f6d15dded 100644 --- a/net/netfilter/ipset/ip_set_list_set.c +++ b/net/netfilter/ipset/ip_set_list_set.c | |||
| @@ -15,12 +15,13 @@ | |||
| 15 | #include <linux/netfilter/ipset/ip_set.h> | 15 | #include <linux/netfilter/ipset/ip_set.h> |
| 16 | #include <linux/netfilter/ipset/ip_set_list.h> | 16 | #include <linux/netfilter/ipset/ip_set_list.h> |
| 17 | 17 | ||
| 18 | #define REVISION_MIN 0 | 18 | #define IPSET_TYPE_REV_MIN 0 |
| 19 | #define REVISION_MAX 1 /* Counters support added */ | 19 | /* 1 Counters support added */ |
| 20 | #define IPSET_TYPE_REV_MAX 2 /* Comments support added */ | ||
| 20 | 21 | ||
| 21 | MODULE_LICENSE("GPL"); | 22 | MODULE_LICENSE("GPL"); |
| 22 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); | 23 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); |
| 23 | IP_SET_MODULE_DESC("list:set", REVISION_MIN, REVISION_MAX); | 24 | IP_SET_MODULE_DESC("list:set", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX); |
| 24 | MODULE_ALIAS("ip_set_list:set"); | 25 | MODULE_ALIAS("ip_set_list:set"); |
| 25 | 26 | ||
| 26 | /* Member elements */ | 27 | /* Member elements */ |
| @@ -28,28 +29,6 @@ struct set_elem { | |||
| 28 | ip_set_id_t id; | 29 | ip_set_id_t id; |
| 29 | }; | 30 | }; |
| 30 | 31 | ||
| 31 | struct sett_elem { | ||
| 32 | struct { | ||
| 33 | ip_set_id_t id; | ||
| 34 | } __attribute__ ((aligned)); | ||
| 35 | unsigned long timeout; | ||
| 36 | }; | ||
| 37 | |||
| 38 | struct setc_elem { | ||
| 39 | struct { | ||
| 40 | ip_set_id_t id; | ||
| 41 | } __attribute__ ((aligned)); | ||
| 42 | struct ip_set_counter counter; | ||
| 43 | }; | ||
| 44 | |||
| 45 | struct setct_elem { | ||
| 46 | struct { | ||
| 47 | ip_set_id_t id; | ||
| 48 | } __attribute__ ((aligned)); | ||
| 49 | struct ip_set_counter counter; | ||
| 50 | unsigned long timeout; | ||
| 51 | }; | ||
| 52 | |||
| 53 | struct set_adt_elem { | 32 | struct set_adt_elem { |
| 54 | ip_set_id_t id; | 33 | ip_set_id_t id; |
| 55 | ip_set_id_t refid; | 34 | ip_set_id_t refid; |
| @@ -58,24 +37,14 @@ struct set_adt_elem { | |||
| 58 | 37 | ||
| 59 | /* Type structure */ | 38 | /* Type structure */ |
| 60 | struct list_set { | 39 | struct list_set { |
| 61 | size_t dsize; /* element size */ | ||
| 62 | size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */ | ||
| 63 | u32 size; /* size of set list array */ | 40 | u32 size; /* size of set list array */ |
| 64 | u32 timeout; /* timeout value */ | ||
| 65 | struct timer_list gc; /* garbage collection */ | 41 | struct timer_list gc; /* garbage collection */ |
| 42 | struct net *net; /* namespace */ | ||
| 66 | struct set_elem members[0]; /* the set members */ | 43 | struct set_elem members[0]; /* the set members */ |
| 67 | }; | 44 | }; |
| 68 | 45 | ||
| 69 | static inline struct set_elem * | 46 | #define list_set_elem(set, map, id) \ |
| 70 | list_set_elem(const struct list_set *map, u32 id) | 47 | (struct set_elem *)((void *)(map)->members + (id) * (set)->dsize) |
| 71 | { | ||
| 72 | return (struct set_elem *)((void *)map->members + id * map->dsize); | ||
| 73 | } | ||
| 74 | |||
| 75 | #define ext_timeout(e, m) \ | ||
| 76 | (unsigned long *)((void *)(e) + (m)->offset[IPSET_OFFSET_TIMEOUT]) | ||
| 77 | #define ext_counter(e, m) \ | ||
| 78 | (struct ip_set_counter *)((void *)(e) + (m)->offset[IPSET_OFFSET_COUNTER]) | ||
| 79 | 48 | ||
| 80 | static int | 49 | static int |
| 81 | list_set_ktest(struct ip_set *set, const struct sk_buff *skb, | 50 | list_set_ktest(struct ip_set *set, const struct sk_buff *skb, |
| @@ -92,16 +61,16 @@ list_set_ktest(struct ip_set *set, const struct sk_buff *skb, | |||
| 92 | if (opt->cmdflags & IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE) | 61 | if (opt->cmdflags & IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE) |
| 93 | opt->cmdflags &= ~IPSET_FLAG_SKIP_COUNTER_UPDATE; | 62 | opt->cmdflags &= ~IPSET_FLAG_SKIP_COUNTER_UPDATE; |
| 94 | for (i = 0; i < map->size; i++) { | 63 | for (i = 0; i < map->size; i++) { |
| 95 | e = list_set_elem(map, i); | 64 | e = list_set_elem(set, map, i); |
| 96 | if (e->id == IPSET_INVALID_ID) | 65 | if (e->id == IPSET_INVALID_ID) |
| 97 | return 0; | 66 | return 0; |
| 98 | if (SET_WITH_TIMEOUT(set) && | 67 | if (SET_WITH_TIMEOUT(set) && |
| 99 | ip_set_timeout_expired(ext_timeout(e, map))) | 68 | ip_set_timeout_expired(ext_timeout(e, set))) |
| 100 | continue; | 69 | continue; |
| 101 | ret = ip_set_test(e->id, skb, par, opt); | 70 | ret = ip_set_test(e->id, skb, par, opt); |
| 102 | if (ret > 0) { | 71 | if (ret > 0) { |
| 103 | if (SET_WITH_COUNTER(set)) | 72 | if (SET_WITH_COUNTER(set)) |
| 104 | ip_set_update_counter(ext_counter(e, map), | 73 | ip_set_update_counter(ext_counter(e, set), |
| 105 | ext, &opt->ext, | 74 | ext, &opt->ext, |
| 106 | cmdflags); | 75 | cmdflags); |
| 107 | return ret; | 76 | return ret; |
| @@ -121,11 +90,11 @@ list_set_kadd(struct ip_set *set, const struct sk_buff *skb, | |||
| 121 | int ret; | 90 | int ret; |
| 122 | 91 | ||
| 123 | for (i = 0; i < map->size; i++) { | 92 | for (i = 0; i < map->size; i++) { |
| 124 | e = list_set_elem(map, i); | 93 | e = list_set_elem(set, map, i); |
| 125 | if (e->id == IPSET_INVALID_ID) | 94 | if (e->id == IPSET_INVALID_ID) |
| 126 | return 0; | 95 | return 0; |
| 127 | if (SET_WITH_TIMEOUT(set) && | 96 | if (SET_WITH_TIMEOUT(set) && |
| 128 | ip_set_timeout_expired(ext_timeout(e, map))) | 97 | ip_set_timeout_expired(ext_timeout(e, set))) |
| 129 | continue; | 98 | continue; |
| 130 | ret = ip_set_add(e->id, skb, par, opt); | 99 | ret = ip_set_add(e->id, skb, par, opt); |
| 131 | if (ret == 0) | 100 | if (ret == 0) |
| @@ -145,11 +114,11 @@ list_set_kdel(struct ip_set *set, const struct sk_buff *skb, | |||
| 145 | int ret; | 114 | int ret; |
| 146 | 115 | ||
| 147 | for (i = 0; i < map->size; i++) { | 116 | for (i = 0; i < map->size; i++) { |
| 148 | e = list_set_elem(map, i); | 117 | e = list_set_elem(set, map, i); |
| 149 | if (e->id == IPSET_INVALID_ID) | 118 | if (e->id == IPSET_INVALID_ID) |
| 150 | return 0; | 119 | return 0; |
| 151 | if (SET_WITH_TIMEOUT(set) && | 120 | if (SET_WITH_TIMEOUT(set) && |
| 152 | ip_set_timeout_expired(ext_timeout(e, map))) | 121 | ip_set_timeout_expired(ext_timeout(e, set))) |
| 153 | continue; | 122 | continue; |
| 154 | ret = ip_set_del(e->id, skb, par, opt); | 123 | ret = ip_set_del(e->id, skb, par, opt); |
| 155 | if (ret == 0) | 124 | if (ret == 0) |
| @@ -163,8 +132,7 @@ list_set_kadt(struct ip_set *set, const struct sk_buff *skb, | |||
| 163 | const struct xt_action_param *par, | 132 | const struct xt_action_param *par, |
| 164 | enum ipset_adt adt, struct ip_set_adt_opt *opt) | 133 | enum ipset_adt adt, struct ip_set_adt_opt *opt) |
| 165 | { | 134 | { |
| 166 | struct list_set *map = set->data; | 135 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); |
| 167 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, map); | ||
| 168 | 136 | ||
| 169 | switch (adt) { | 137 | switch (adt) { |
| 170 | case IPSET_TEST: | 138 | case IPSET_TEST: |
| @@ -188,10 +156,10 @@ id_eq(const struct ip_set *set, u32 i, ip_set_id_t id) | |||
| 188 | if (i >= map->size) | 156 | if (i >= map->size) |
| 189 | return 0; | 157 | return 0; |
| 190 | 158 | ||
| 191 | e = list_set_elem(map, i); | 159 | e = list_set_elem(set, map, i); |
| 192 | return !!(e->id == id && | 160 | return !!(e->id == id && |
| 193 | !(SET_WITH_TIMEOUT(set) && | 161 | !(SET_WITH_TIMEOUT(set) && |
| 194 | ip_set_timeout_expired(ext_timeout(e, map)))); | 162 | ip_set_timeout_expired(ext_timeout(e, set)))); |
| 195 | } | 163 | } |
| 196 | 164 | ||
| 197 | static int | 165 | static int |
| @@ -199,28 +167,36 @@ list_set_add(struct ip_set *set, u32 i, struct set_adt_elem *d, | |||
| 199 | const struct ip_set_ext *ext) | 167 | const struct ip_set_ext *ext) |
| 200 | { | 168 | { |
| 201 | struct list_set *map = set->data; | 169 | struct list_set *map = set->data; |
| 202 | struct set_elem *e = list_set_elem(map, i); | 170 | struct set_elem *e = list_set_elem(set, map, i); |
| 203 | 171 | ||
| 204 | if (e->id != IPSET_INVALID_ID) { | 172 | if (e->id != IPSET_INVALID_ID) { |
| 205 | if (i == map->size - 1) | 173 | if (i == map->size - 1) { |
| 206 | /* Last element replaced: e.g. add new,before,last */ | 174 | /* Last element replaced: e.g. add new,before,last */ |
| 207 | ip_set_put_byindex(e->id); | 175 | ip_set_put_byindex(map->net, e->id); |
| 208 | else { | 176 | ip_set_ext_destroy(set, e); |
| 209 | struct set_elem *x = list_set_elem(map, map->size - 1); | 177 | } else { |
| 178 | struct set_elem *x = list_set_elem(set, map, | ||
| 179 | map->size - 1); | ||
| 210 | 180 | ||
| 211 | /* Last element pushed off */ | 181 | /* Last element pushed off */ |
| 212 | if (x->id != IPSET_INVALID_ID) | 182 | if (x->id != IPSET_INVALID_ID) { |
| 213 | ip_set_put_byindex(x->id); | 183 | ip_set_put_byindex(map->net, x->id); |
| 214 | memmove(list_set_elem(map, i + 1), e, | 184 | ip_set_ext_destroy(set, x); |
| 215 | map->dsize * (map->size - (i + 1))); | 185 | } |
| 186 | memmove(list_set_elem(set, map, i + 1), e, | ||
| 187 | set->dsize * (map->size - (i + 1))); | ||
| 188 | /* Extensions must be initialized to zero */ | ||
| 189 | memset(e, 0, set->dsize); | ||
| 216 | } | 190 | } |
| 217 | } | 191 | } |
| 218 | 192 | ||
| 219 | e->id = d->id; | 193 | e->id = d->id; |
| 220 | if (SET_WITH_TIMEOUT(set)) | 194 | if (SET_WITH_TIMEOUT(set)) |
| 221 | ip_set_timeout_set(ext_timeout(e, map), ext->timeout); | 195 | ip_set_timeout_set(ext_timeout(e, set), ext->timeout); |
| 222 | if (SET_WITH_COUNTER(set)) | 196 | if (SET_WITH_COUNTER(set)) |
| 223 | ip_set_init_counter(ext_counter(e, map), ext); | 197 | ip_set_init_counter(ext_counter(e, set), ext); |
| 198 | if (SET_WITH_COMMENT(set)) | ||
| 199 | ip_set_init_comment(ext_comment(e, set), ext); | ||
| 224 | return 0; | 200 | return 0; |
| 225 | } | 201 | } |
| 226 | 202 | ||
| @@ -228,16 +204,17 @@ static int | |||
| 228 | list_set_del(struct ip_set *set, u32 i) | 204 | list_set_del(struct ip_set *set, u32 i) |
| 229 | { | 205 | { |
| 230 | struct list_set *map = set->data; | 206 | struct list_set *map = set->data; |
| 231 | struct set_elem *e = list_set_elem(map, i); | 207 | struct set_elem *e = list_set_elem(set, map, i); |
| 232 | 208 | ||
| 233 | ip_set_put_byindex(e->id); | 209 | ip_set_put_byindex(map->net, e->id); |
| 210 | ip_set_ext_destroy(set, e); | ||
| 234 | 211 | ||
| 235 | if (i < map->size - 1) | 212 | if (i < map->size - 1) |
| 236 | memmove(e, list_set_elem(map, i + 1), | 213 | memmove(e, list_set_elem(set, map, i + 1), |
| 237 | map->dsize * (map->size - (i + 1))); | 214 | set->dsize * (map->size - (i + 1))); |
| 238 | 215 | ||
| 239 | /* Last element */ | 216 | /* Last element */ |
| 240 | e = list_set_elem(map, map->size - 1); | 217 | e = list_set_elem(set, map, map->size - 1); |
| 241 | e->id = IPSET_INVALID_ID; | 218 | e->id = IPSET_INVALID_ID; |
| 242 | return 0; | 219 | return 0; |
| 243 | } | 220 | } |
| @@ -247,13 +224,16 @@ set_cleanup_entries(struct ip_set *set) | |||
| 247 | { | 224 | { |
| 248 | struct list_set *map = set->data; | 225 | struct list_set *map = set->data; |
| 249 | struct set_elem *e; | 226 | struct set_elem *e; |
| 250 | u32 i; | 227 | u32 i = 0; |
| 251 | 228 | ||
| 252 | for (i = 0; i < map->size; i++) { | 229 | while (i < map->size) { |
| 253 | e = list_set_elem(map, i); | 230 | e = list_set_elem(set, map, i); |
| 254 | if (e->id != IPSET_INVALID_ID && | 231 | if (e->id != IPSET_INVALID_ID && |
| 255 | ip_set_timeout_expired(ext_timeout(e, map))) | 232 | ip_set_timeout_expired(ext_timeout(e, set))) |
| 256 | list_set_del(set, i); | 233 | list_set_del(set, i); |
| 234 | /* Check element moved to position i in next loop */ | ||
| 235 | else | ||
| 236 | i++; | ||
| 257 | } | 237 | } |
| 258 | } | 238 | } |
| 259 | 239 | ||
| @@ -268,11 +248,11 @@ list_set_utest(struct ip_set *set, void *value, const struct ip_set_ext *ext, | |||
| 268 | int ret; | 248 | int ret; |
| 269 | 249 | ||
| 270 | for (i = 0; i < map->size; i++) { | 250 | for (i = 0; i < map->size; i++) { |
| 271 | e = list_set_elem(map, i); | 251 | e = list_set_elem(set, map, i); |
| 272 | if (e->id == IPSET_INVALID_ID) | 252 | if (e->id == IPSET_INVALID_ID) |
| 273 | return 0; | 253 | return 0; |
| 274 | else if (SET_WITH_TIMEOUT(set) && | 254 | else if (SET_WITH_TIMEOUT(set) && |
| 275 | ip_set_timeout_expired(ext_timeout(e, map))) | 255 | ip_set_timeout_expired(ext_timeout(e, set))) |
| 276 | continue; | 256 | continue; |
| 277 | else if (e->id != d->id) | 257 | else if (e->id != d->id) |
| 278 | continue; | 258 | continue; |
| @@ -299,14 +279,14 @@ list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext, | |||
| 299 | bool flag_exist = flags & IPSET_FLAG_EXIST; | 279 | bool flag_exist = flags & IPSET_FLAG_EXIST; |
| 300 | u32 i, ret = 0; | 280 | u32 i, ret = 0; |
| 301 | 281 | ||
| 282 | if (SET_WITH_TIMEOUT(set)) | ||
| 283 | set_cleanup_entries(set); | ||
| 284 | |||
| 302 | /* Check already added element */ | 285 | /* Check already added element */ |
| 303 | for (i = 0; i < map->size; i++) { | 286 | for (i = 0; i < map->size; i++) { |
| 304 | e = list_set_elem(map, i); | 287 | e = list_set_elem(set, map, i); |
| 305 | if (e->id == IPSET_INVALID_ID) | 288 | if (e->id == IPSET_INVALID_ID) |
| 306 | goto insert; | 289 | goto insert; |
| 307 | else if (SET_WITH_TIMEOUT(set) && | ||
| 308 | ip_set_timeout_expired(ext_timeout(e, map))) | ||
| 309 | continue; | ||
| 310 | else if (e->id != d->id) | 290 | else if (e->id != d->id) |
| 311 | continue; | 291 | continue; |
| 312 | 292 | ||
| @@ -319,18 +299,22 @@ list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext, | |||
| 319 | /* Can't re-add */ | 299 | /* Can't re-add */ |
| 320 | return -IPSET_ERR_EXIST; | 300 | return -IPSET_ERR_EXIST; |
| 321 | /* Update extensions */ | 301 | /* Update extensions */ |
| 302 | ip_set_ext_destroy(set, e); | ||
| 303 | |||
| 322 | if (SET_WITH_TIMEOUT(set)) | 304 | if (SET_WITH_TIMEOUT(set)) |
| 323 | ip_set_timeout_set(ext_timeout(e, map), ext->timeout); | 305 | ip_set_timeout_set(ext_timeout(e, set), ext->timeout); |
| 324 | if (SET_WITH_COUNTER(set)) | 306 | if (SET_WITH_COUNTER(set)) |
| 325 | ip_set_init_counter(ext_counter(e, map), ext); | 307 | ip_set_init_counter(ext_counter(e, set), ext); |
| 308 | if (SET_WITH_COMMENT(set)) | ||
| 309 | ip_set_init_comment(ext_comment(e, set), ext); | ||
| 326 | /* Set is already added to the list */ | 310 | /* Set is already added to the list */ |
| 327 | ip_set_put_byindex(d->id); | 311 | ip_set_put_byindex(map->net, d->id); |
| 328 | return 0; | 312 | return 0; |
| 329 | } | 313 | } |
| 330 | insert: | 314 | insert: |
| 331 | ret = -IPSET_ERR_LIST_FULL; | 315 | ret = -IPSET_ERR_LIST_FULL; |
| 332 | for (i = 0; i < map->size && ret == -IPSET_ERR_LIST_FULL; i++) { | 316 | for (i = 0; i < map->size && ret == -IPSET_ERR_LIST_FULL; i++) { |
| 333 | e = list_set_elem(map, i); | 317 | e = list_set_elem(set, map, i); |
| 334 | if (e->id == IPSET_INVALID_ID) | 318 | if (e->id == IPSET_INVALID_ID) |
| 335 | ret = d->before != 0 ? -IPSET_ERR_REF_EXIST | 319 | ret = d->before != 0 ? -IPSET_ERR_REF_EXIST |
| 336 | : list_set_add(set, i, d, ext); | 320 | : list_set_add(set, i, d, ext); |
| @@ -355,12 +339,12 @@ list_set_udel(struct ip_set *set, void *value, const struct ip_set_ext *ext, | |||
| 355 | u32 i; | 339 | u32 i; |
| 356 | 340 | ||
| 357 | for (i = 0; i < map->size; i++) { | 341 | for (i = 0; i < map->size; i++) { |
| 358 | e = list_set_elem(map, i); | 342 | e = list_set_elem(set, map, i); |
| 359 | if (e->id == IPSET_INVALID_ID) | 343 | if (e->id == IPSET_INVALID_ID) |
| 360 | return d->before != 0 ? -IPSET_ERR_REF_EXIST | 344 | return d->before != 0 ? -IPSET_ERR_REF_EXIST |
| 361 | : -IPSET_ERR_EXIST; | 345 | : -IPSET_ERR_EXIST; |
| 362 | else if (SET_WITH_TIMEOUT(set) && | 346 | else if (SET_WITH_TIMEOUT(set) && |
| 363 | ip_set_timeout_expired(ext_timeout(e, map))) | 347 | ip_set_timeout_expired(ext_timeout(e, set))) |
| 364 | continue; | 348 | continue; |
| 365 | else if (e->id != d->id) | 349 | else if (e->id != d->id) |
| 366 | continue; | 350 | continue; |
| @@ -386,7 +370,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 386 | struct list_set *map = set->data; | 370 | struct list_set *map = set->data; |
| 387 | ipset_adtfn adtfn = set->variant->adt[adt]; | 371 | ipset_adtfn adtfn = set->variant->adt[adt]; |
| 388 | struct set_adt_elem e = { .refid = IPSET_INVALID_ID }; | 372 | struct set_adt_elem e = { .refid = IPSET_INVALID_ID }; |
| 389 | struct ip_set_ext ext = IP_SET_INIT_UEXT(map); | 373 | struct ip_set_ext ext = IP_SET_INIT_UEXT(set); |
| 390 | struct ip_set *s; | 374 | struct ip_set *s; |
| 391 | int ret = 0; | 375 | int ret = 0; |
| 392 | 376 | ||
| @@ -403,7 +387,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 403 | ret = ip_set_get_extensions(set, tb, &ext); | 387 | ret = ip_set_get_extensions(set, tb, &ext); |
| 404 | if (ret) | 388 | if (ret) |
| 405 | return ret; | 389 | return ret; |
| 406 | e.id = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAME]), &s); | 390 | e.id = ip_set_get_byname(map->net, nla_data(tb[IPSET_ATTR_NAME]), &s); |
| 407 | if (e.id == IPSET_INVALID_ID) | 391 | if (e.id == IPSET_INVALID_ID) |
| 408 | return -IPSET_ERR_NAME; | 392 | return -IPSET_ERR_NAME; |
| 409 | /* "Loop detection" */ | 393 | /* "Loop detection" */ |
| @@ -423,7 +407,8 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 423 | } | 407 | } |
| 424 | 408 | ||
| 425 | if (tb[IPSET_ATTR_NAMEREF]) { | 409 | if (tb[IPSET_ATTR_NAMEREF]) { |
| 426 | e.refid = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAMEREF]), | 410 | e.refid = ip_set_get_byname(map->net, |
| 411 | nla_data(tb[IPSET_ATTR_NAMEREF]), | ||
| 427 | &s); | 412 | &s); |
| 428 | if (e.refid == IPSET_INVALID_ID) { | 413 | if (e.refid == IPSET_INVALID_ID) { |
| 429 | ret = -IPSET_ERR_NAMEREF; | 414 | ret = -IPSET_ERR_NAMEREF; |
| @@ -439,9 +424,9 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[], | |||
| 439 | 424 | ||
| 440 | finish: | 425 | finish: |
| 441 | if (e.refid != IPSET_INVALID_ID) | 426 | if (e.refid != IPSET_INVALID_ID) |
| 442 | ip_set_put_byindex(e.refid); | 427 | ip_set_put_byindex(map->net, e.refid); |
| 443 | if (adt != IPSET_ADD || ret) | 428 | if (adt != IPSET_ADD || ret) |
| 444 | ip_set_put_byindex(e.id); | 429 | ip_set_put_byindex(map->net, e.id); |
| 445 | 430 | ||
| 446 | return ip_set_eexist(ret, flags) ? 0 : ret; | 431 | return ip_set_eexist(ret, flags) ? 0 : ret; |
| 447 | } | 432 | } |
| @@ -454,9 +439,10 @@ list_set_flush(struct ip_set *set) | |||
| 454 | u32 i; | 439 | u32 i; |
| 455 | 440 | ||
| 456 | for (i = 0; i < map->size; i++) { | 441 | for (i = 0; i < map->size; i++) { |
| 457 | e = list_set_elem(map, i); | 442 | e = list_set_elem(set, map, i); |
| 458 | if (e->id != IPSET_INVALID_ID) { | 443 | if (e->id != IPSET_INVALID_ID) { |
| 459 | ip_set_put_byindex(e->id); | 444 | ip_set_put_byindex(map->net, e->id); |
| 445 | ip_set_ext_destroy(set, e); | ||
| 460 | e->id = IPSET_INVALID_ID; | 446 | e->id = IPSET_INVALID_ID; |
| 461 | } | 447 | } |
| 462 | } | 448 | } |
| @@ -485,14 +471,11 @@ list_set_head(struct ip_set *set, struct sk_buff *skb) | |||
| 485 | if (!nested) | 471 | if (!nested) |
| 486 | goto nla_put_failure; | 472 | goto nla_put_failure; |
| 487 | if (nla_put_net32(skb, IPSET_ATTR_SIZE, htonl(map->size)) || | 473 | if (nla_put_net32(skb, IPSET_ATTR_SIZE, htonl(map->size)) || |
| 488 | (SET_WITH_TIMEOUT(set) && | ||
| 489 | nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout))) || | ||
| 490 | (SET_WITH_COUNTER(set) && | ||
| 491 | nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, | ||
| 492 | htonl(IPSET_FLAG_WITH_COUNTERS))) || | ||
| 493 | nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) || | 474 | nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) || |
| 494 | nla_put_net32(skb, IPSET_ATTR_MEMSIZE, | 475 | nla_put_net32(skb, IPSET_ATTR_MEMSIZE, |
| 495 | htonl(sizeof(*map) + map->size * map->dsize))) | 476 | htonl(sizeof(*map) + map->size * set->dsize))) |
| 477 | goto nla_put_failure; | ||
| 478 | if (unlikely(ip_set_put_flags(skb, set))) | ||
| 496 | goto nla_put_failure; | 479 | goto nla_put_failure; |
| 497 | ipset_nest_end(skb, nested); | 480 | ipset_nest_end(skb, nested); |
| 498 | 481 | ||
| @@ -515,11 +498,11 @@ list_set_list(const struct ip_set *set, | |||
| 515 | return -EMSGSIZE; | 498 | return -EMSGSIZE; |
| 516 | for (; cb->args[2] < map->size; cb->args[2]++) { | 499 | for (; cb->args[2] < map->size; cb->args[2]++) { |
| 517 | i = cb->args[2]; | 500 | i = cb->args[2]; |
| 518 | e = list_set_elem(map, i); | 501 | e = list_set_elem(set, map, i); |
| 519 | if (e->id == IPSET_INVALID_ID) | 502 | if (e->id == IPSET_INVALID_ID) |
| 520 | goto finish; | 503 | goto finish; |
| 521 | if (SET_WITH_TIMEOUT(set) && | 504 | if (SET_WITH_TIMEOUT(set) && |
| 522 | ip_set_timeout_expired(ext_timeout(e, map))) | 505 | ip_set_timeout_expired(ext_timeout(e, set))) |
| 523 | continue; | 506 | continue; |
| 524 | nested = ipset_nest_start(skb, IPSET_ATTR_DATA); | 507 | nested = ipset_nest_start(skb, IPSET_ATTR_DATA); |
| 525 | if (!nested) { | 508 | if (!nested) { |
| @@ -530,15 +513,9 @@ list_set_list(const struct ip_set *set, | |||
| 530 | goto nla_put_failure; | 513 | goto nla_put_failure; |
| 531 | } | 514 | } |
| 532 | if (nla_put_string(skb, IPSET_ATTR_NAME, | 515 | if (nla_put_string(skb, IPSET_ATTR_NAME, |
| 533 | ip_set_name_byindex(e->id))) | 516 | ip_set_name_byindex(map->net, e->id))) |
| 534 | goto nla_put_failure; | ||
| 535 | if (SET_WITH_TIMEOUT(set) && | ||
| 536 | nla_put_net32(skb, IPSET_ATTR_TIMEOUT, | ||
| 537 | htonl(ip_set_timeout_get( | ||
| 538 | ext_timeout(e, map))))) | ||
| 539 | goto nla_put_failure; | 517 | goto nla_put_failure; |
| 540 | if (SET_WITH_COUNTER(set) && | 518 | if (ip_set_put_extensions(skb, set, e, true)) |
| 541 | ip_set_put_counter(skb, ext_counter(e, map))) | ||
| 542 | goto nla_put_failure; | 519 | goto nla_put_failure; |
| 543 | ipset_nest_end(skb, nested); | 520 | ipset_nest_end(skb, nested); |
| 544 | } | 521 | } |
| @@ -550,11 +527,11 @@ finish: | |||
| 550 | 527 | ||
| 551 | nla_put_failure: | 528 | nla_put_failure: |
| 552 | nla_nest_cancel(skb, nested); | 529 | nla_nest_cancel(skb, nested); |
| 553 | ipset_nest_end(skb, atd); | ||
| 554 | if (unlikely(i == first)) { | 530 | if (unlikely(i == first)) { |
| 555 | cb->args[2] = 0; | 531 | cb->args[2] = 0; |
| 556 | return -EMSGSIZE; | 532 | return -EMSGSIZE; |
| 557 | } | 533 | } |
| 534 | ipset_nest_end(skb, atd); | ||
| 558 | return 0; | 535 | return 0; |
| 559 | } | 536 | } |
| 560 | 537 | ||
| @@ -565,7 +542,7 @@ list_set_same_set(const struct ip_set *a, const struct ip_set *b) | |||
| 565 | const struct list_set *y = b->data; | 542 | const struct list_set *y = b->data; |
| 566 | 543 | ||
| 567 | return x->size == y->size && | 544 | return x->size == y->size && |
| 568 | x->timeout == y->timeout && | 545 | a->timeout == b->timeout && |
| 569 | a->extensions == b->extensions; | 546 | a->extensions == b->extensions; |
| 570 | } | 547 | } |
| 571 | 548 | ||
| @@ -594,7 +571,7 @@ list_set_gc(unsigned long ul_set) | |||
| 594 | set_cleanup_entries(set); | 571 | set_cleanup_entries(set); |
| 595 | write_unlock_bh(&set->lock); | 572 | write_unlock_bh(&set->lock); |
| 596 | 573 | ||
| 597 | map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ; | 574 | map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ; |
| 598 | add_timer(&map->gc); | 575 | add_timer(&map->gc); |
| 599 | } | 576 | } |
| 600 | 577 | ||
| @@ -606,43 +583,40 @@ list_set_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set)) | |||
| 606 | init_timer(&map->gc); | 583 | init_timer(&map->gc); |
| 607 | map->gc.data = (unsigned long) set; | 584 | map->gc.data = (unsigned long) set; |
| 608 | map->gc.function = gc; | 585 | map->gc.function = gc; |
| 609 | map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ; | 586 | map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ; |
| 610 | add_timer(&map->gc); | 587 | add_timer(&map->gc); |
| 611 | } | 588 | } |
| 612 | 589 | ||
| 613 | /* Create list:set type of sets */ | 590 | /* Create list:set type of sets */ |
| 614 | 591 | ||
| 615 | static struct list_set * | 592 | static bool |
| 616 | init_list_set(struct ip_set *set, u32 size, size_t dsize, | 593 | init_list_set(struct net *net, struct ip_set *set, u32 size) |
| 617 | unsigned long timeout) | ||
| 618 | { | 594 | { |
| 619 | struct list_set *map; | 595 | struct list_set *map; |
| 620 | struct set_elem *e; | 596 | struct set_elem *e; |
| 621 | u32 i; | 597 | u32 i; |
| 622 | 598 | ||
| 623 | map = kzalloc(sizeof(*map) + size * dsize, GFP_KERNEL); | 599 | map = kzalloc(sizeof(*map) + size * set->dsize, GFP_KERNEL); |
| 624 | if (!map) | 600 | if (!map) |
| 625 | return NULL; | 601 | return false; |
| 626 | 602 | ||
| 627 | map->size = size; | 603 | map->size = size; |
| 628 | map->dsize = dsize; | 604 | map->net = net; |
| 629 | map->timeout = timeout; | ||
| 630 | set->data = map; | 605 | set->data = map; |
| 631 | 606 | ||
| 632 | for (i = 0; i < size; i++) { | 607 | for (i = 0; i < size; i++) { |
| 633 | e = list_set_elem(map, i); | 608 | e = list_set_elem(set, map, i); |
| 634 | e->id = IPSET_INVALID_ID; | 609 | e->id = IPSET_INVALID_ID; |
| 635 | } | 610 | } |
| 636 | 611 | ||
| 637 | return map; | 612 | return true; |
| 638 | } | 613 | } |
| 639 | 614 | ||
| 640 | static int | 615 | static int |
| 641 | list_set_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | 616 | list_set_create(struct net *net, struct ip_set *set, struct nlattr *tb[], |
| 617 | u32 flags) | ||
| 642 | { | 618 | { |
| 643 | struct list_set *map; | 619 | u32 size = IP_SET_LIST_DEFAULT_SIZE; |
| 644 | u32 size = IP_SET_LIST_DEFAULT_SIZE, cadt_flags = 0; | ||
| 645 | unsigned long timeout = 0; | ||
| 646 | 620 | ||
| 647 | if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_SIZE) || | 621 | if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_SIZE) || |
| 648 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | 622 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
| @@ -654,45 +628,13 @@ list_set_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |||
| 654 | if (size < IP_SET_LIST_MIN_SIZE) | 628 | if (size < IP_SET_LIST_MIN_SIZE) |
| 655 | size = IP_SET_LIST_MIN_SIZE; | 629 | size = IP_SET_LIST_MIN_SIZE; |
| 656 | 630 | ||
| 657 | if (tb[IPSET_ATTR_CADT_FLAGS]) | ||
| 658 | cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); | ||
| 659 | if (tb[IPSET_ATTR_TIMEOUT]) | ||
| 660 | timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | ||
| 661 | set->variant = &set_variant; | 631 | set->variant = &set_variant; |
| 662 | if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) { | 632 | set->dsize = ip_set_elem_len(set, tb, sizeof(struct set_elem)); |
| 663 | set->extensions |= IPSET_EXT_COUNTER; | 633 | if (!init_list_set(net, set, size)) |
| 664 | if (tb[IPSET_ATTR_TIMEOUT]) { | 634 | return -ENOMEM; |
| 665 | map = init_list_set(set, size, | 635 | if (tb[IPSET_ATTR_TIMEOUT]) { |
| 666 | sizeof(struct setct_elem), timeout); | 636 | set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); |
| 667 | if (!map) | ||
| 668 | return -ENOMEM; | ||
| 669 | set->extensions |= IPSET_EXT_TIMEOUT; | ||
| 670 | map->offset[IPSET_OFFSET_TIMEOUT] = | ||
| 671 | offsetof(struct setct_elem, timeout); | ||
| 672 | map->offset[IPSET_OFFSET_COUNTER] = | ||
| 673 | offsetof(struct setct_elem, counter); | ||
| 674 | list_set_gc_init(set, list_set_gc); | ||
| 675 | } else { | ||
| 676 | map = init_list_set(set, size, | ||
| 677 | sizeof(struct setc_elem), 0); | ||
| 678 | if (!map) | ||
| 679 | return -ENOMEM; | ||
| 680 | map->offset[IPSET_OFFSET_COUNTER] = | ||
| 681 | offsetof(struct setc_elem, counter); | ||
| 682 | } | ||
| 683 | } else if (tb[IPSET_ATTR_TIMEOUT]) { | ||
| 684 | map = init_list_set(set, size, | ||
| 685 | sizeof(struct sett_elem), timeout); | ||
| 686 | if (!map) | ||
| 687 | return -ENOMEM; | ||
| 688 | set->extensions |= IPSET_EXT_TIMEOUT; | ||
| 689 | map->offset[IPSET_OFFSET_TIMEOUT] = | ||
| 690 | offsetof(struct sett_elem, timeout); | ||
| 691 | list_set_gc_init(set, list_set_gc); | 637 | list_set_gc_init(set, list_set_gc); |
| 692 | } else { | ||
| 693 | map = init_list_set(set, size, sizeof(struct set_elem), 0); | ||
| 694 | if (!map) | ||
| 695 | return -ENOMEM; | ||
| 696 | } | 638 | } |
| 697 | return 0; | 639 | return 0; |
| 698 | } | 640 | } |
| @@ -703,8 +645,8 @@ static struct ip_set_type list_set_type __read_mostly = { | |||
| 703 | .features = IPSET_TYPE_NAME | IPSET_DUMP_LAST, | 645 | .features = IPSET_TYPE_NAME | IPSET_DUMP_LAST, |
| 704 | .dimension = IPSET_DIM_ONE, | 646 | .dimension = IPSET_DIM_ONE, |
| 705 | .family = NFPROTO_UNSPEC, | 647 | .family = NFPROTO_UNSPEC, |
| 706 | .revision_min = REVISION_MIN, | 648 | .revision_min = IPSET_TYPE_REV_MIN, |
| 707 | .revision_max = REVISION_MAX, | 649 | .revision_max = IPSET_TYPE_REV_MAX, |
| 708 | .create = list_set_create, | 650 | .create = list_set_create, |
| 709 | .create_policy = { | 651 | .create_policy = { |
| 710 | [IPSET_ATTR_SIZE] = { .type = NLA_U32 }, | 652 | [IPSET_ATTR_SIZE] = { .type = NLA_U32 }, |
| @@ -721,6 +663,7 @@ static struct ip_set_type list_set_type __read_mostly = { | |||
| 721 | [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, | 663 | [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, |
| 722 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | 664 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, |
| 723 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | 665 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, |
| 666 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | ||
| 724 | }, | 667 | }, |
| 725 | .me = THIS_MODULE, | 668 | .me = THIS_MODULE, |
| 726 | }; | 669 | }; |
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index e0c4373b4747..466410eaa482 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c | |||
| @@ -52,66 +52,8 @@ module_param(sip_direct_media, int, 0600); | |||
| 52 | MODULE_PARM_DESC(sip_direct_media, "Expect Media streams between signalling " | 52 | MODULE_PARM_DESC(sip_direct_media, "Expect Media streams between signalling " |
| 53 | "endpoints only (default 1)"); | 53 | "endpoints only (default 1)"); |
| 54 | 54 | ||
| 55 | unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, unsigned int protoff, | 55 | const struct nf_nat_sip_hooks *nf_nat_sip_hooks; |
| 56 | unsigned int dataoff, const char **dptr, | 56 | EXPORT_SYMBOL_GPL(nf_nat_sip_hooks); |
| 57 | unsigned int *datalen) __read_mostly; | ||
| 58 | EXPORT_SYMBOL_GPL(nf_nat_sip_hook); | ||
| 59 | |||
| 60 | void (*nf_nat_sip_seq_adjust_hook)(struct sk_buff *skb, unsigned int protoff, | ||
| 61 | s16 off) __read_mostly; | ||
| 62 | EXPORT_SYMBOL_GPL(nf_nat_sip_seq_adjust_hook); | ||
| 63 | |||
| 64 | unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb, | ||
| 65 | unsigned int protoff, | ||
| 66 | unsigned int dataoff, | ||
| 67 | const char **dptr, | ||
| 68 | unsigned int *datalen, | ||
| 69 | struct nf_conntrack_expect *exp, | ||
| 70 | unsigned int matchoff, | ||
| 71 | unsigned int matchlen) __read_mostly; | ||
| 72 | EXPORT_SYMBOL_GPL(nf_nat_sip_expect_hook); | ||
| 73 | |||
| 74 | unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb, unsigned int protoff, | ||
| 75 | unsigned int dataoff, | ||
| 76 | const char **dptr, | ||
| 77 | unsigned int *datalen, | ||
| 78 | unsigned int sdpoff, | ||
| 79 | enum sdp_header_types type, | ||
| 80 | enum sdp_header_types term, | ||
| 81 | const union nf_inet_addr *addr) | ||
| 82 | __read_mostly; | ||
| 83 | EXPORT_SYMBOL_GPL(nf_nat_sdp_addr_hook); | ||
| 84 | |||
| 85 | unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb, unsigned int protoff, | ||
| 86 | unsigned int dataoff, | ||
| 87 | const char **dptr, | ||
| 88 | unsigned int *datalen, | ||
| 89 | unsigned int matchoff, | ||
| 90 | unsigned int matchlen, | ||
| 91 | u_int16_t port) __read_mostly; | ||
| 92 | EXPORT_SYMBOL_GPL(nf_nat_sdp_port_hook); | ||
| 93 | |||
| 94 | unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb, | ||
| 95 | unsigned int protoff, | ||
| 96 | unsigned int dataoff, | ||
| 97 | const char **dptr, | ||
| 98 | unsigned int *datalen, | ||
| 99 | unsigned int sdpoff, | ||
| 100 | const union nf_inet_addr *addr) | ||
| 101 | __read_mostly; | ||
| 102 | EXPORT_SYMBOL_GPL(nf_nat_sdp_session_hook); | ||
| 103 | |||
| 104 | unsigned int (*nf_nat_sdp_media_hook)(struct sk_buff *skb, unsigned int protoff, | ||
| 105 | unsigned int dataoff, | ||
| 106 | const char **dptr, | ||
| 107 | unsigned int *datalen, | ||
| 108 | struct nf_conntrack_expect *rtp_exp, | ||
| 109 | struct nf_conntrack_expect *rtcp_exp, | ||
| 110 | unsigned int mediaoff, | ||
| 111 | unsigned int medialen, | ||
| 112 | union nf_inet_addr *rtp_addr) | ||
| 113 | __read_mostly; | ||
| 114 | EXPORT_SYMBOL_GPL(nf_nat_sdp_media_hook); | ||
| 115 | 57 | ||
| 116 | static int string_len(const struct nf_conn *ct, const char *dptr, | 58 | static int string_len(const struct nf_conn *ct, const char *dptr, |
| 117 | const char *limit, int *shift) | 59 | const char *limit, int *shift) |
| @@ -914,8 +856,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff, | |||
| 914 | int direct_rtp = 0, skip_expect = 0, ret = NF_DROP; | 856 | int direct_rtp = 0, skip_expect = 0, ret = NF_DROP; |
| 915 | u_int16_t base_port; | 857 | u_int16_t base_port; |
| 916 | __be16 rtp_port, rtcp_port; | 858 | __be16 rtp_port, rtcp_port; |
| 917 | typeof(nf_nat_sdp_port_hook) nf_nat_sdp_port; | 859 | const struct nf_nat_sip_hooks *hooks; |
| 918 | typeof(nf_nat_sdp_media_hook) nf_nat_sdp_media; | ||
| 919 | 860 | ||
| 920 | saddr = NULL; | 861 | saddr = NULL; |
| 921 | if (sip_direct_media) { | 862 | if (sip_direct_media) { |
| @@ -966,22 +907,23 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff, | |||
| 966 | #endif | 907 | #endif |
| 967 | skip_expect = 1; | 908 | skip_expect = 1; |
| 968 | } while (!skip_expect); | 909 | } while (!skip_expect); |
| 969 | rcu_read_unlock(); | ||
| 970 | 910 | ||
| 971 | base_port = ntohs(tuple.dst.u.udp.port) & ~1; | 911 | base_port = ntohs(tuple.dst.u.udp.port) & ~1; |
| 972 | rtp_port = htons(base_port); | 912 | rtp_port = htons(base_port); |
| 973 | rtcp_port = htons(base_port + 1); | 913 | rtcp_port = htons(base_port + 1); |
| 974 | 914 | ||
| 975 | if (direct_rtp) { | 915 | if (direct_rtp) { |
| 976 | nf_nat_sdp_port = rcu_dereference(nf_nat_sdp_port_hook); | 916 | hooks = rcu_dereference(nf_nat_sip_hooks); |
| 977 | if (nf_nat_sdp_port && | 917 | if (hooks && |
| 978 | !nf_nat_sdp_port(skb, protoff, dataoff, dptr, datalen, | 918 | !hooks->sdp_port(skb, protoff, dataoff, dptr, datalen, |
| 979 | mediaoff, medialen, ntohs(rtp_port))) | 919 | mediaoff, medialen, ntohs(rtp_port))) |
| 980 | goto err1; | 920 | goto err1; |
| 981 | } | 921 | } |
| 982 | 922 | ||
| 983 | if (skip_expect) | 923 | if (skip_expect) { |
| 924 | rcu_read_unlock(); | ||
| 984 | return NF_ACCEPT; | 925 | return NF_ACCEPT; |
| 926 | } | ||
| 985 | 927 | ||
| 986 | rtp_exp = nf_ct_expect_alloc(ct); | 928 | rtp_exp = nf_ct_expect_alloc(ct); |
| 987 | if (rtp_exp == NULL) | 929 | if (rtp_exp == NULL) |
| @@ -995,10 +937,10 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff, | |||
| 995 | nf_ct_expect_init(rtcp_exp, class, nf_ct_l3num(ct), saddr, daddr, | 937 | nf_ct_expect_init(rtcp_exp, class, nf_ct_l3num(ct), saddr, daddr, |
| 996 | IPPROTO_UDP, NULL, &rtcp_port); | 938 | IPPROTO_UDP, NULL, &rtcp_port); |
| 997 | 939 | ||
| 998 | nf_nat_sdp_media = rcu_dereference(nf_nat_sdp_media_hook); | 940 | hooks = rcu_dereference(nf_nat_sip_hooks); |
| 999 | if (nf_nat_sdp_media && ct->status & IPS_NAT_MASK && !direct_rtp) | 941 | if (hooks && ct->status & IPS_NAT_MASK && !direct_rtp) |
| 1000 | ret = nf_nat_sdp_media(skb, protoff, dataoff, dptr, datalen, | 942 | ret = hooks->sdp_media(skb, protoff, dataoff, dptr, |
| 1001 | rtp_exp, rtcp_exp, | 943 | datalen, rtp_exp, rtcp_exp, |
| 1002 | mediaoff, medialen, daddr); | 944 | mediaoff, medialen, daddr); |
| 1003 | else { | 945 | else { |
| 1004 | if (nf_ct_expect_related(rtp_exp) == 0) { | 946 | if (nf_ct_expect_related(rtp_exp) == 0) { |
| @@ -1012,6 +954,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff, | |||
| 1012 | err2: | 954 | err2: |
| 1013 | nf_ct_expect_put(rtp_exp); | 955 | nf_ct_expect_put(rtp_exp); |
| 1014 | err1: | 956 | err1: |
| 957 | rcu_read_unlock(); | ||
| 1015 | return ret; | 958 | return ret; |
| 1016 | } | 959 | } |
| 1017 | 960 | ||
| @@ -1051,13 +994,12 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff, | |||
| 1051 | unsigned int caddr_len, maddr_len; | 994 | unsigned int caddr_len, maddr_len; |
| 1052 | unsigned int i; | 995 | unsigned int i; |
| 1053 | union nf_inet_addr caddr, maddr, rtp_addr; | 996 | union nf_inet_addr caddr, maddr, rtp_addr; |
| 997 | const struct nf_nat_sip_hooks *hooks; | ||
| 1054 | unsigned int port; | 998 | unsigned int port; |
| 1055 | const struct sdp_media_type *t; | 999 | const struct sdp_media_type *t; |
| 1056 | int ret = NF_ACCEPT; | 1000 | int ret = NF_ACCEPT; |
| 1057 | typeof(nf_nat_sdp_addr_hook) nf_nat_sdp_addr; | ||
| 1058 | typeof(nf_nat_sdp_session_hook) nf_nat_sdp_session; | ||
| 1059 | 1001 | ||
| 1060 | nf_nat_sdp_addr = rcu_dereference(nf_nat_sdp_addr_hook); | 1002 | hooks = rcu_dereference(nf_nat_sip_hooks); |
| 1061 | 1003 | ||
| 1062 | /* Find beginning of session description */ | 1004 | /* Find beginning of session description */ |
| 1063 | if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, | 1005 | if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, |
| @@ -1125,10 +1067,11 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff, | |||
| 1125 | } | 1067 | } |
| 1126 | 1068 | ||
| 1127 | /* Update media connection address if present */ | 1069 | /* Update media connection address if present */ |
| 1128 | if (maddr_len && nf_nat_sdp_addr && ct->status & IPS_NAT_MASK) { | 1070 | if (maddr_len && hooks && ct->status & IPS_NAT_MASK) { |
| 1129 | ret = nf_nat_sdp_addr(skb, protoff, dataoff, | 1071 | ret = hooks->sdp_addr(skb, protoff, dataoff, |
| 1130 | dptr, datalen, mediaoff, | 1072 | dptr, datalen, mediaoff, |
| 1131 | SDP_HDR_CONNECTION, SDP_HDR_MEDIA, | 1073 | SDP_HDR_CONNECTION, |
| 1074 | SDP_HDR_MEDIA, | ||
| 1132 | &rtp_addr); | 1075 | &rtp_addr); |
| 1133 | if (ret != NF_ACCEPT) { | 1076 | if (ret != NF_ACCEPT) { |
| 1134 | nf_ct_helper_log(skb, ct, "cannot mangle SDP"); | 1077 | nf_ct_helper_log(skb, ct, "cannot mangle SDP"); |
| @@ -1139,10 +1082,11 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff, | |||
| 1139 | } | 1082 | } |
| 1140 | 1083 | ||
| 1141 | /* Update session connection and owner addresses */ | 1084 | /* Update session connection and owner addresses */ |
| 1142 | nf_nat_sdp_session = rcu_dereference(nf_nat_sdp_session_hook); | 1085 | hooks = rcu_dereference(nf_nat_sip_hooks); |
| 1143 | if (nf_nat_sdp_session && ct->status & IPS_NAT_MASK) | 1086 | if (hooks && ct->status & IPS_NAT_MASK) |
| 1144 | ret = nf_nat_sdp_session(skb, protoff, dataoff, | 1087 | ret = hooks->sdp_session(skb, protoff, dataoff, |
| 1145 | dptr, datalen, sdpoff, &rtp_addr); | 1088 | dptr, datalen, sdpoff, |
| 1089 | &rtp_addr); | ||
| 1146 | 1090 | ||
| 1147 | return ret; | 1091 | return ret; |
| 1148 | } | 1092 | } |
| @@ -1242,11 +1186,11 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff, | |||
| 1242 | unsigned int matchoff, matchlen; | 1186 | unsigned int matchoff, matchlen; |
| 1243 | struct nf_conntrack_expect *exp; | 1187 | struct nf_conntrack_expect *exp; |
| 1244 | union nf_inet_addr *saddr, daddr; | 1188 | union nf_inet_addr *saddr, daddr; |
| 1189 | const struct nf_nat_sip_hooks *hooks; | ||
| 1245 | __be16 port; | 1190 | __be16 port; |
| 1246 | u8 proto; | 1191 | u8 proto; |
| 1247 | unsigned int expires = 0; | 1192 | unsigned int expires = 0; |
| 1248 | int ret; | 1193 | int ret; |
| 1249 | typeof(nf_nat_sip_expect_hook) nf_nat_sip_expect; | ||
| 1250 | 1194 | ||
| 1251 | /* Expected connections can not register again. */ | 1195 | /* Expected connections can not register again. */ |
| 1252 | if (ct->status & IPS_EXPECTED) | 1196 | if (ct->status & IPS_EXPECTED) |
| @@ -1309,10 +1253,10 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff, | |||
| 1309 | exp->helper = nfct_help(ct)->helper; | 1253 | exp->helper = nfct_help(ct)->helper; |
| 1310 | exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE; | 1254 | exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE; |
| 1311 | 1255 | ||
| 1312 | nf_nat_sip_expect = rcu_dereference(nf_nat_sip_expect_hook); | 1256 | hooks = rcu_dereference(nf_nat_sip_hooks); |
| 1313 | if (nf_nat_sip_expect && ct->status & IPS_NAT_MASK) | 1257 | if (hooks && ct->status & IPS_NAT_MASK) |
| 1314 | ret = nf_nat_sip_expect(skb, protoff, dataoff, dptr, datalen, | 1258 | ret = hooks->expect(skb, protoff, dataoff, dptr, datalen, |
| 1315 | exp, matchoff, matchlen); | 1259 | exp, matchoff, matchlen); |
| 1316 | else { | 1260 | else { |
| 1317 | if (nf_ct_expect_related(exp) != 0) { | 1261 | if (nf_ct_expect_related(exp) != 0) { |
| 1318 | nf_ct_helper_log(skb, ct, "cannot add expectation"); | 1262 | nf_ct_helper_log(skb, ct, "cannot add expectation"); |
| @@ -1515,7 +1459,7 @@ static int process_sip_msg(struct sk_buff *skb, struct nf_conn *ct, | |||
| 1515 | unsigned int protoff, unsigned int dataoff, | 1459 | unsigned int protoff, unsigned int dataoff, |
| 1516 | const char **dptr, unsigned int *datalen) | 1460 | const char **dptr, unsigned int *datalen) |
| 1517 | { | 1461 | { |
| 1518 | typeof(nf_nat_sip_hook) nf_nat_sip; | 1462 | const struct nf_nat_sip_hooks *hooks; |
| 1519 | int ret; | 1463 | int ret; |
| 1520 | 1464 | ||
| 1521 | if (strnicmp(*dptr, "SIP/2.0 ", strlen("SIP/2.0 ")) != 0) | 1465 | if (strnicmp(*dptr, "SIP/2.0 ", strlen("SIP/2.0 ")) != 0) |
| @@ -1524,9 +1468,9 @@ static int process_sip_msg(struct sk_buff *skb, struct nf_conn *ct, | |||
| 1524 | ret = process_sip_response(skb, protoff, dataoff, dptr, datalen); | 1468 | ret = process_sip_response(skb, protoff, dataoff, dptr, datalen); |
| 1525 | 1469 | ||
| 1526 | if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) { | 1470 | if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) { |
| 1527 | nf_nat_sip = rcu_dereference(nf_nat_sip_hook); | 1471 | hooks = rcu_dereference(nf_nat_sip_hooks); |
| 1528 | if (nf_nat_sip && !nf_nat_sip(skb, protoff, dataoff, | 1472 | if (hooks && !hooks->msg(skb, protoff, dataoff, |
| 1529 | dptr, datalen)) { | 1473 | dptr, datalen)) { |
| 1530 | nf_ct_helper_log(skb, ct, "cannot NAT SIP message"); | 1474 | nf_ct_helper_log(skb, ct, "cannot NAT SIP message"); |
| 1531 | ret = NF_DROP; | 1475 | ret = NF_DROP; |
| 1532 | } | 1476 | } |
| @@ -1546,7 +1490,6 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, | |||
| 1546 | s16 diff, tdiff = 0; | 1490 | s16 diff, tdiff = 0; |
| 1547 | int ret = NF_ACCEPT; | 1491 | int ret = NF_ACCEPT; |
| 1548 | bool term; | 1492 | bool term; |
| 1549 | typeof(nf_nat_sip_seq_adjust_hook) nf_nat_sip_seq_adjust; | ||
| 1550 | 1493 | ||
| 1551 | if (ctinfo != IP_CT_ESTABLISHED && | 1494 | if (ctinfo != IP_CT_ESTABLISHED && |
| 1552 | ctinfo != IP_CT_ESTABLISHED_REPLY) | 1495 | ctinfo != IP_CT_ESTABLISHED_REPLY) |
| @@ -1610,9 +1553,11 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, | |||
| 1610 | } | 1553 | } |
| 1611 | 1554 | ||
| 1612 | if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) { | 1555 | if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) { |
| 1613 | nf_nat_sip_seq_adjust = rcu_dereference(nf_nat_sip_seq_adjust_hook); | 1556 | const struct nf_nat_sip_hooks *hooks; |
| 1614 | if (nf_nat_sip_seq_adjust) | 1557 | |
| 1615 | nf_nat_sip_seq_adjust(skb, protoff, tdiff); | 1558 | hooks = rcu_dereference(nf_nat_sip_hooks); |
| 1559 | if (hooks) | ||
| 1560 | hooks->seq_adjust(skb, protoff, tdiff); | ||
| 1616 | } | 1561 | } |
| 1617 | 1562 | ||
| 1618 | return ret; | 1563 | return ret; |
diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c index f9790405b7ff..b4d691db955e 100644 --- a/net/netfilter/nf_nat_sip.c +++ b/net/netfilter/nf_nat_sip.c | |||
| @@ -625,33 +625,26 @@ static struct nf_ct_helper_expectfn sip_nat = { | |||
| 625 | 625 | ||
| 626 | static void __exit nf_nat_sip_fini(void) | 626 | static void __exit nf_nat_sip_fini(void) |
| 627 | { | 627 | { |
| 628 | RCU_INIT_POINTER(nf_nat_sip_hook, NULL); | 628 | RCU_INIT_POINTER(nf_nat_sip_hooks, NULL); |
| 629 | RCU_INIT_POINTER(nf_nat_sip_seq_adjust_hook, NULL); | 629 | |
| 630 | RCU_INIT_POINTER(nf_nat_sip_expect_hook, NULL); | ||
| 631 | RCU_INIT_POINTER(nf_nat_sdp_addr_hook, NULL); | ||
| 632 | RCU_INIT_POINTER(nf_nat_sdp_port_hook, NULL); | ||
| 633 | RCU_INIT_POINTER(nf_nat_sdp_session_hook, NULL); | ||
| 634 | RCU_INIT_POINTER(nf_nat_sdp_media_hook, NULL); | ||
| 635 | nf_ct_helper_expectfn_unregister(&sip_nat); | 630 | nf_ct_helper_expectfn_unregister(&sip_nat); |
| 636 | synchronize_rcu(); | 631 | synchronize_rcu(); |
| 637 | } | 632 | } |
| 638 | 633 | ||
| 634 | static const struct nf_nat_sip_hooks sip_hooks = { | ||
| 635 | .msg = nf_nat_sip, | ||
| 636 | .seq_adjust = nf_nat_sip_seq_adjust, | ||
| 637 | .expect = nf_nat_sip_expect, | ||
| 638 | .sdp_addr = nf_nat_sdp_addr, | ||
| 639 | .sdp_port = nf_nat_sdp_port, | ||
| 640 | .sdp_session = nf_nat_sdp_session, | ||
| 641 | .sdp_media = nf_nat_sdp_media, | ||
| 642 | }; | ||
| 643 | |||
| 639 | static int __init nf_nat_sip_init(void) | 644 | static int __init nf_nat_sip_init(void) |
| 640 | { | 645 | { |
| 641 | BUG_ON(nf_nat_sip_hook != NULL); | 646 | BUG_ON(nf_nat_sip_hooks != NULL); |
| 642 | BUG_ON(nf_nat_sip_seq_adjust_hook != NULL); | 647 | RCU_INIT_POINTER(nf_nat_sip_hooks, &sip_hooks); |
| 643 | BUG_ON(nf_nat_sip_expect_hook != NULL); | ||
| 644 | BUG_ON(nf_nat_sdp_addr_hook != NULL); | ||
| 645 | BUG_ON(nf_nat_sdp_port_hook != NULL); | ||
| 646 | BUG_ON(nf_nat_sdp_session_hook != NULL); | ||
| 647 | BUG_ON(nf_nat_sdp_media_hook != NULL); | ||
| 648 | RCU_INIT_POINTER(nf_nat_sip_hook, nf_nat_sip); | ||
| 649 | RCU_INIT_POINTER(nf_nat_sip_seq_adjust_hook, nf_nat_sip_seq_adjust); | ||
| 650 | RCU_INIT_POINTER(nf_nat_sip_expect_hook, nf_nat_sip_expect); | ||
| 651 | RCU_INIT_POINTER(nf_nat_sdp_addr_hook, nf_nat_sdp_addr); | ||
| 652 | RCU_INIT_POINTER(nf_nat_sdp_port_hook, nf_nat_sdp_port); | ||
| 653 | RCU_INIT_POINTER(nf_nat_sdp_session_hook, nf_nat_sdp_session); | ||
| 654 | RCU_INIT_POINTER(nf_nat_sdp_media_hook, nf_nat_sdp_media); | ||
| 655 | nf_ct_helper_expectfn_register(&sip_nat); | 648 | nf_ct_helper_expectfn_register(&sip_nat); |
| 656 | return 0; | 649 | return 0; |
| 657 | } | 650 | } |
diff --git a/net/netfilter/nfnetlink_cttimeout.c b/net/netfilter/nfnetlink_cttimeout.c index 50580494148d..476accd17145 100644 --- a/net/netfilter/nfnetlink_cttimeout.c +++ b/net/netfilter/nfnetlink_cttimeout.c | |||
| @@ -49,10 +49,8 @@ static const struct nla_policy cttimeout_nla_policy[CTA_TIMEOUT_MAX+1] = { | |||
| 49 | }; | 49 | }; |
| 50 | 50 | ||
| 51 | static int | 51 | static int |
| 52 | ctnl_timeout_parse_policy(struct ctnl_timeout *timeout, | 52 | ctnl_timeout_parse_policy(void *timeouts, struct nf_conntrack_l4proto *l4proto, |
| 53 | struct nf_conntrack_l4proto *l4proto, | 53 | struct net *net, const struct nlattr *attr) |
| 54 | struct net *net, | ||
| 55 | const struct nlattr *attr) | ||
| 56 | { | 54 | { |
| 57 | int ret = 0; | 55 | int ret = 0; |
| 58 | 56 | ||
| @@ -64,8 +62,7 @@ ctnl_timeout_parse_policy(struct ctnl_timeout *timeout, | |||
| 64 | if (ret < 0) | 62 | if (ret < 0) |
| 65 | return ret; | 63 | return ret; |
| 66 | 64 | ||
| 67 | ret = l4proto->ctnl_timeout.nlattr_to_obj(tb, net, | 65 | ret = l4proto->ctnl_timeout.nlattr_to_obj(tb, net, timeouts); |
| 68 | &timeout->data); | ||
| 69 | } | 66 | } |
| 70 | return ret; | 67 | return ret; |
| 71 | } | 68 | } |
| @@ -123,7 +120,8 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb, | |||
| 123 | goto err_proto_put; | 120 | goto err_proto_put; |
| 124 | } | 121 | } |
| 125 | 122 | ||
| 126 | ret = ctnl_timeout_parse_policy(matching, l4proto, net, | 123 | ret = ctnl_timeout_parse_policy(&matching->data, |
| 124 | l4proto, net, | ||
| 127 | cda[CTA_TIMEOUT_DATA]); | 125 | cda[CTA_TIMEOUT_DATA]); |
| 128 | return ret; | 126 | return ret; |
| 129 | } | 127 | } |
| @@ -138,7 +136,7 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb, | |||
| 138 | goto err_proto_put; | 136 | goto err_proto_put; |
| 139 | } | 137 | } |
| 140 | 138 | ||
| 141 | ret = ctnl_timeout_parse_policy(timeout, l4proto, net, | 139 | ret = ctnl_timeout_parse_policy(&timeout->data, l4proto, net, |
| 142 | cda[CTA_TIMEOUT_DATA]); | 140 | cda[CTA_TIMEOUT_DATA]); |
| 143 | if (ret < 0) | 141 | if (ret < 0) |
| 144 | goto err; | 142 | goto err; |
| @@ -342,6 +340,147 @@ cttimeout_del_timeout(struct sock *ctnl, struct sk_buff *skb, | |||
| 342 | return ret; | 340 | return ret; |
| 343 | } | 341 | } |
| 344 | 342 | ||
| 343 | static int | ||
| 344 | cttimeout_default_set(struct sock *ctnl, struct sk_buff *skb, | ||
| 345 | const struct nlmsghdr *nlh, | ||
| 346 | const struct nlattr * const cda[]) | ||
| 347 | { | ||
| 348 | __u16 l3num; | ||
| 349 | __u8 l4num; | ||
| 350 | struct nf_conntrack_l4proto *l4proto; | ||
| 351 | struct net *net = sock_net(skb->sk); | ||
| 352 | unsigned int *timeouts; | ||
| 353 | int ret; | ||
| 354 | |||
| 355 | if (!cda[CTA_TIMEOUT_L3PROTO] || | ||
| 356 | !cda[CTA_TIMEOUT_L4PROTO] || | ||
| 357 | !cda[CTA_TIMEOUT_DATA]) | ||
| 358 | return -EINVAL; | ||
| 359 | |||
| 360 | l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO])); | ||
| 361 | l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]); | ||
| 362 | l4proto = nf_ct_l4proto_find_get(l3num, l4num); | ||
| 363 | |||
| 364 | /* This protocol is not supported, skip. */ | ||
| 365 | if (l4proto->l4proto != l4num) { | ||
| 366 | ret = -EOPNOTSUPP; | ||
| 367 | goto err; | ||
| 368 | } | ||
| 369 | |||
| 370 | timeouts = l4proto->get_timeouts(net); | ||
| 371 | |||
| 372 | ret = ctnl_timeout_parse_policy(timeouts, l4proto, net, | ||
| 373 | cda[CTA_TIMEOUT_DATA]); | ||
| 374 | if (ret < 0) | ||
| 375 | goto err; | ||
| 376 | |||
| 377 | nf_ct_l4proto_put(l4proto); | ||
| 378 | return 0; | ||
| 379 | err: | ||
| 380 | nf_ct_l4proto_put(l4proto); | ||
| 381 | return ret; | ||
| 382 | } | ||
| 383 | |||
| 384 | static int | ||
| 385 | cttimeout_default_fill_info(struct net *net, struct sk_buff *skb, u32 portid, | ||
| 386 | u32 seq, u32 type, int event, | ||
| 387 | struct nf_conntrack_l4proto *l4proto) | ||
| 388 | { | ||
| 389 | struct nlmsghdr *nlh; | ||
| 390 | struct nfgenmsg *nfmsg; | ||
| 391 | unsigned int flags = portid ? NLM_F_MULTI : 0; | ||
| 392 | |||
| 393 | event |= NFNL_SUBSYS_CTNETLINK_TIMEOUT << 8; | ||
| 394 | nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags); | ||
| 395 | if (nlh == NULL) | ||
| 396 | goto nlmsg_failure; | ||
| 397 | |||
| 398 | nfmsg = nlmsg_data(nlh); | ||
| 399 | nfmsg->nfgen_family = AF_UNSPEC; | ||
| 400 | nfmsg->version = NFNETLINK_V0; | ||
| 401 | nfmsg->res_id = 0; | ||
| 402 | |||
| 403 | if (nla_put_be16(skb, CTA_TIMEOUT_L3PROTO, htons(l4proto->l3proto)) || | ||
| 404 | nla_put_u8(skb, CTA_TIMEOUT_L4PROTO, l4proto->l4proto)) | ||
| 405 | goto nla_put_failure; | ||
| 406 | |||
| 407 | if (likely(l4proto->ctnl_timeout.obj_to_nlattr)) { | ||
| 408 | struct nlattr *nest_parms; | ||
| 409 | unsigned int *timeouts = l4proto->get_timeouts(net); | ||
| 410 | int ret; | ||
| 411 | |||
| 412 | nest_parms = nla_nest_start(skb, | ||
| 413 | CTA_TIMEOUT_DATA | NLA_F_NESTED); | ||
| 414 | if (!nest_parms) | ||
| 415 | goto nla_put_failure; | ||
| 416 | |||
| 417 | ret = l4proto->ctnl_timeout.obj_to_nlattr(skb, timeouts); | ||
| 418 | if (ret < 0) | ||
| 419 | goto nla_put_failure; | ||
| 420 | |||
| 421 | nla_nest_end(skb, nest_parms); | ||
| 422 | } | ||
| 423 | |||
| 424 | nlmsg_end(skb, nlh); | ||
| 425 | return skb->len; | ||
| 426 | |||
| 427 | nlmsg_failure: | ||
| 428 | nla_put_failure: | ||
| 429 | nlmsg_cancel(skb, nlh); | ||
| 430 | return -1; | ||
| 431 | } | ||
| 432 | |||
| 433 | static int cttimeout_default_get(struct sock *ctnl, struct sk_buff *skb, | ||
| 434 | const struct nlmsghdr *nlh, | ||
| 435 | const struct nlattr * const cda[]) | ||
| 436 | { | ||
| 437 | __u16 l3num; | ||
| 438 | __u8 l4num; | ||
| 439 | struct nf_conntrack_l4proto *l4proto; | ||
| 440 | struct net *net = sock_net(skb->sk); | ||
| 441 | struct sk_buff *skb2; | ||
| 442 | int ret, err; | ||
| 443 | |||
| 444 | if (!cda[CTA_TIMEOUT_L3PROTO] || !cda[CTA_TIMEOUT_L4PROTO]) | ||
| 445 | return -EINVAL; | ||
| 446 | |||
| 447 | l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO])); | ||
| 448 | l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]); | ||
| 449 | l4proto = nf_ct_l4proto_find_get(l3num, l4num); | ||
| 450 | |||
| 451 | /* This protocol is not supported, skip. */ | ||
| 452 | if (l4proto->l4proto != l4num) { | ||
| 453 | err = -EOPNOTSUPP; | ||
| 454 | goto err; | ||
| 455 | } | ||
| 456 | |||
| 457 | skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
| 458 | if (skb2 == NULL) { | ||
| 459 | err = -ENOMEM; | ||
| 460 | goto err; | ||
| 461 | } | ||
| 462 | |||
| 463 | ret = cttimeout_default_fill_info(net, skb2, NETLINK_CB(skb).portid, | ||
| 464 | nlh->nlmsg_seq, | ||
| 465 | NFNL_MSG_TYPE(nlh->nlmsg_type), | ||
| 466 | IPCTNL_MSG_TIMEOUT_DEFAULT_SET, | ||
| 467 | l4proto); | ||
| 468 | if (ret <= 0) { | ||
| 469 | kfree_skb(skb2); | ||
| 470 | err = -ENOMEM; | ||
| 471 | goto err; | ||
| 472 | } | ||
| 473 | ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT); | ||
| 474 | if (ret > 0) | ||
| 475 | ret = 0; | ||
| 476 | |||
| 477 | /* this avoids a loop in nfnetlink. */ | ||
| 478 | return ret == -EAGAIN ? -ENOBUFS : ret; | ||
| 479 | err: | ||
| 480 | nf_ct_l4proto_put(l4proto); | ||
| 481 | return err; | ||
| 482 | } | ||
| 483 | |||
| 345 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT | 484 | #ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
| 346 | static struct ctnl_timeout *ctnl_timeout_find_get(const char *name) | 485 | static struct ctnl_timeout *ctnl_timeout_find_get(const char *name) |
| 347 | { | 486 | { |
| @@ -384,6 +523,12 @@ static const struct nfnl_callback cttimeout_cb[IPCTNL_MSG_TIMEOUT_MAX] = { | |||
| 384 | [IPCTNL_MSG_TIMEOUT_DELETE] = { .call = cttimeout_del_timeout, | 523 | [IPCTNL_MSG_TIMEOUT_DELETE] = { .call = cttimeout_del_timeout, |
| 385 | .attr_count = CTA_TIMEOUT_MAX, | 524 | .attr_count = CTA_TIMEOUT_MAX, |
| 386 | .policy = cttimeout_nla_policy }, | 525 | .policy = cttimeout_nla_policy }, |
| 526 | [IPCTNL_MSG_TIMEOUT_DEFAULT_SET]= { .call = cttimeout_default_set, | ||
| 527 | .attr_count = CTA_TIMEOUT_MAX, | ||
| 528 | .policy = cttimeout_nla_policy }, | ||
| 529 | [IPCTNL_MSG_TIMEOUT_DEFAULT_GET]= { .call = cttimeout_default_get, | ||
| 530 | .attr_count = CTA_TIMEOUT_MAX, | ||
| 531 | .policy = cttimeout_nla_policy }, | ||
| 387 | }; | 532 | }; |
| 388 | 533 | ||
| 389 | static const struct nfnetlink_subsystem cttimeout_subsys = { | 534 | static const struct nfnetlink_subsystem cttimeout_subsys = { |
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index d92cc317bf8b..3c4b69e5fe17 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c | |||
| @@ -319,7 +319,8 @@ nfulnl_set_flags(struct nfulnl_instance *inst, u_int16_t flags) | |||
| 319 | } | 319 | } |
| 320 | 320 | ||
| 321 | static struct sk_buff * | 321 | static struct sk_buff * |
| 322 | nfulnl_alloc_skb(u32 peer_portid, unsigned int inst_size, unsigned int pkt_size) | 322 | nfulnl_alloc_skb(struct net *net, u32 peer_portid, unsigned int inst_size, |
| 323 | unsigned int pkt_size) | ||
| 323 | { | 324 | { |
| 324 | struct sk_buff *skb; | 325 | struct sk_buff *skb; |
| 325 | unsigned int n; | 326 | unsigned int n; |
| @@ -328,13 +329,13 @@ nfulnl_alloc_skb(u32 peer_portid, unsigned int inst_size, unsigned int pkt_size) | |||
| 328 | * message. WARNING: has to be <= 128k due to slab restrictions */ | 329 | * message. WARNING: has to be <= 128k due to slab restrictions */ |
| 329 | 330 | ||
| 330 | n = max(inst_size, pkt_size); | 331 | n = max(inst_size, pkt_size); |
| 331 | skb = nfnetlink_alloc_skb(&init_net, n, peer_portid, GFP_ATOMIC); | 332 | skb = nfnetlink_alloc_skb(net, n, peer_portid, GFP_ATOMIC); |
| 332 | if (!skb) { | 333 | if (!skb) { |
| 333 | if (n > pkt_size) { | 334 | if (n > pkt_size) { |
| 334 | /* try to allocate only as much as we need for current | 335 | /* try to allocate only as much as we need for current |
| 335 | * packet */ | 336 | * packet */ |
| 336 | 337 | ||
| 337 | skb = nfnetlink_alloc_skb(&init_net, pkt_size, | 338 | skb = nfnetlink_alloc_skb(net, pkt_size, |
| 338 | peer_portid, GFP_ATOMIC); | 339 | peer_portid, GFP_ATOMIC); |
| 339 | if (!skb) | 340 | if (!skb) |
| 340 | pr_err("nfnetlink_log: can't even alloc %u bytes\n", | 341 | pr_err("nfnetlink_log: can't even alloc %u bytes\n", |
| @@ -702,8 +703,8 @@ nfulnl_log_packet(struct net *net, | |||
| 702 | } | 703 | } |
| 703 | 704 | ||
| 704 | if (!inst->skb) { | 705 | if (!inst->skb) { |
| 705 | inst->skb = nfulnl_alloc_skb(inst->peer_portid, inst->nlbufsiz, | 706 | inst->skb = nfulnl_alloc_skb(net, inst->peer_portid, |
| 706 | size); | 707 | inst->nlbufsiz, size); |
| 707 | if (!inst->skb) | 708 | if (!inst->skb) |
| 708 | goto alloc_failure; | 709 | goto alloc_failure; |
| 709 | } | 710 | } |
diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c index ae2e5c11d01a..21258cf70091 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, | |||
| 298 | } | 298 | } |
| 299 | 299 | ||
| 300 | static struct sk_buff * | 300 | static struct sk_buff * |
| 301 | nfqnl_build_packet_message(struct nfqnl_instance *queue, | 301 | nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, |
| 302 | struct nf_queue_entry *entry, | 302 | struct nf_queue_entry *entry, |
| 303 | __be32 **packet_id_ptr) | 303 | __be32 **packet_id_ptr) |
| 304 | { | 304 | { |
| @@ -372,7 +372,7 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, | |||
| 372 | if (queue->flags & NFQA_CFG_F_CONNTRACK) | 372 | if (queue->flags & NFQA_CFG_F_CONNTRACK) |
| 373 | ct = nfqnl_ct_get(entskb, &size, &ctinfo); | 373 | ct = nfqnl_ct_get(entskb, &size, &ctinfo); |
| 374 | 374 | ||
| 375 | skb = nfnetlink_alloc_skb(&init_net, size, queue->peer_portid, | 375 | skb = nfnetlink_alloc_skb(net, size, queue->peer_portid, |
| 376 | GFP_ATOMIC); | 376 | GFP_ATOMIC); |
| 377 | if (!skb) | 377 | if (!skb) |
| 378 | return NULL; | 378 | return NULL; |
| @@ -525,7 +525,7 @@ __nfqnl_enqueue_packet(struct net *net, struct nfqnl_instance *queue, | |||
| 525 | __be32 *packet_id_ptr; | 525 | __be32 *packet_id_ptr; |
| 526 | int failopen = 0; | 526 | int failopen = 0; |
| 527 | 527 | ||
| 528 | nskb = nfqnl_build_packet_message(queue, entry, &packet_id_ptr); | 528 | nskb = nfqnl_build_packet_message(net, queue, entry, &packet_id_ptr); |
| 529 | if (nskb == NULL) { | 529 | if (nskb == NULL) { |
| 530 | err = -ENOMEM; | 530 | err = -ENOMEM; |
| 531 | goto err_out; | 531 | goto err_out; |
diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c index cd24290f3b2f..e762de5ee89b 100644 --- a/net/netfilter/xt_TCPMSS.c +++ b/net/netfilter/xt_TCPMSS.c | |||
| @@ -43,10 +43,42 @@ optlen(const u_int8_t *opt, unsigned int offset) | |||
| 43 | return opt[offset+1]; | 43 | return opt[offset+1]; |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | static u_int32_t tcpmss_reverse_mtu(struct net *net, | ||
| 47 | const struct sk_buff *skb, | ||
| 48 | unsigned int family) | ||
| 49 | { | ||
| 50 | struct flowi fl; | ||
| 51 | const struct nf_afinfo *ai; | ||
| 52 | struct rtable *rt = NULL; | ||
| 53 | u_int32_t mtu = ~0U; | ||
| 54 | |||
| 55 | if (family == PF_INET) { | ||
| 56 | struct flowi4 *fl4 = &fl.u.ip4; | ||
| 57 | memset(fl4, 0, sizeof(*fl4)); | ||
| 58 | fl4->daddr = ip_hdr(skb)->saddr; | ||
| 59 | } else { | ||
| 60 | struct flowi6 *fl6 = &fl.u.ip6; | ||
| 61 | |||
| 62 | memset(fl6, 0, sizeof(*fl6)); | ||
| 63 | fl6->daddr = ipv6_hdr(skb)->saddr; | ||
| 64 | } | ||
| 65 | rcu_read_lock(); | ||
| 66 | ai = nf_get_afinfo(family); | ||
| 67 | if (ai != NULL) | ||
| 68 | ai->route(net, (struct dst_entry **)&rt, &fl, false); | ||
| 69 | rcu_read_unlock(); | ||
| 70 | |||
| 71 | if (rt != NULL) { | ||
| 72 | mtu = dst_mtu(&rt->dst); | ||
| 73 | dst_release(&rt->dst); | ||
| 74 | } | ||
| 75 | return mtu; | ||
| 76 | } | ||
| 77 | |||
| 46 | static int | 78 | static int |
| 47 | tcpmss_mangle_packet(struct sk_buff *skb, | 79 | tcpmss_mangle_packet(struct sk_buff *skb, |
| 48 | const struct xt_action_param *par, | 80 | const struct xt_action_param *par, |
| 49 | unsigned int in_mtu, | 81 | unsigned int family, |
| 50 | unsigned int tcphoff, | 82 | unsigned int tcphoff, |
| 51 | unsigned int minlen) | 83 | unsigned int minlen) |
| 52 | { | 84 | { |
| @@ -76,6 +108,9 @@ tcpmss_mangle_packet(struct sk_buff *skb, | |||
| 76 | return -1; | 108 | return -1; |
| 77 | 109 | ||
| 78 | if (info->mss == XT_TCPMSS_CLAMP_PMTU) { | 110 | if (info->mss == XT_TCPMSS_CLAMP_PMTU) { |
| 111 | struct net *net = dev_net(par->in ? par->in : par->out); | ||
| 112 | unsigned int in_mtu = tcpmss_reverse_mtu(net, skb, family); | ||
| 113 | |||
| 79 | if (dst_mtu(skb_dst(skb)) <= minlen) { | 114 | if (dst_mtu(skb_dst(skb)) <= minlen) { |
| 80 | net_err_ratelimited("unknown or invalid path-MTU (%u)\n", | 115 | net_err_ratelimited("unknown or invalid path-MTU (%u)\n", |
| 81 | dst_mtu(skb_dst(skb))); | 116 | dst_mtu(skb_dst(skb))); |
| @@ -165,37 +200,6 @@ tcpmss_mangle_packet(struct sk_buff *skb, | |||
| 165 | return TCPOLEN_MSS; | 200 | return TCPOLEN_MSS; |
| 166 | } | 201 | } |
| 167 | 202 | ||
| 168 | static u_int32_t tcpmss_reverse_mtu(const struct sk_buff *skb, | ||
| 169 | unsigned int family) | ||
| 170 | { | ||
| 171 | struct flowi fl; | ||
| 172 | const struct nf_afinfo *ai; | ||
| 173 | struct rtable *rt = NULL; | ||
| 174 | u_int32_t mtu = ~0U; | ||
| 175 | |||
| 176 | if (family == PF_INET) { | ||
| 177 | struct flowi4 *fl4 = &fl.u.ip4; | ||
| 178 | memset(fl4, 0, sizeof(*fl4)); | ||
| 179 | fl4->daddr = ip_hdr(skb)->saddr; | ||
| 180 | } else { | ||
| 181 | struct flowi6 *fl6 = &fl.u.ip6; | ||
| 182 | |||
| 183 | memset(fl6, 0, sizeof(*fl6)); | ||
| 184 | fl6->daddr = ipv6_hdr(skb)->saddr; | ||
| 185 | } | ||
| 186 | rcu_read_lock(); | ||
| 187 | ai = nf_get_afinfo(family); | ||
| 188 | if (ai != NULL) | ||
| 189 | ai->route(&init_net, (struct dst_entry **)&rt, &fl, false); | ||
| 190 | rcu_read_unlock(); | ||
| 191 | |||
| 192 | if (rt != NULL) { | ||
| 193 | mtu = dst_mtu(&rt->dst); | ||
| 194 | dst_release(&rt->dst); | ||
| 195 | } | ||
| 196 | return mtu; | ||
| 197 | } | ||
| 198 | |||
| 199 | static unsigned int | 203 | static unsigned int |
| 200 | tcpmss_tg4(struct sk_buff *skb, const struct xt_action_param *par) | 204 | tcpmss_tg4(struct sk_buff *skb, const struct xt_action_param *par) |
| 201 | { | 205 | { |
| @@ -204,7 +208,7 @@ tcpmss_tg4(struct sk_buff *skb, const struct xt_action_param *par) | |||
| 204 | int ret; | 208 | int ret; |
| 205 | 209 | ||
| 206 | ret = tcpmss_mangle_packet(skb, par, | 210 | ret = tcpmss_mangle_packet(skb, par, |
| 207 | tcpmss_reverse_mtu(skb, PF_INET), | 211 | PF_INET, |
| 208 | iph->ihl * 4, | 212 | iph->ihl * 4, |
| 209 | sizeof(*iph) + sizeof(struct tcphdr)); | 213 | sizeof(*iph) + sizeof(struct tcphdr)); |
| 210 | if (ret < 0) | 214 | if (ret < 0) |
| @@ -233,7 +237,7 @@ tcpmss_tg6(struct sk_buff *skb, const struct xt_action_param *par) | |||
| 233 | if (tcphoff < 0) | 237 | if (tcphoff < 0) |
| 234 | return NF_DROP; | 238 | return NF_DROP; |
| 235 | ret = tcpmss_mangle_packet(skb, par, | 239 | ret = tcpmss_mangle_packet(skb, par, |
| 236 | tcpmss_reverse_mtu(skb, PF_INET6), | 240 | PF_INET6, |
| 237 | tcphoff, | 241 | tcphoff, |
| 238 | sizeof(*ipv6h) + sizeof(struct tcphdr)); | 242 | sizeof(*ipv6h) + sizeof(struct tcphdr)); |
| 239 | if (ret < 0) | 243 | if (ret < 0) |
diff --git a/net/netfilter/xt_set.c b/net/netfilter/xt_set.c index 31790e789e22..e7c4e0e01ff5 100644 --- a/net/netfilter/xt_set.c +++ b/net/netfilter/xt_set.c | |||
| @@ -81,7 +81,7 @@ set_match_v0_checkentry(const struct xt_mtchk_param *par) | |||
| 81 | struct xt_set_info_match_v0 *info = par->matchinfo; | 81 | struct xt_set_info_match_v0 *info = par->matchinfo; |
| 82 | ip_set_id_t index; | 82 | ip_set_id_t index; |
| 83 | 83 | ||
| 84 | index = ip_set_nfnl_get_byindex(info->match_set.index); | 84 | index = ip_set_nfnl_get_byindex(par->net, info->match_set.index); |
| 85 | 85 | ||
| 86 | if (index == IPSET_INVALID_ID) { | 86 | if (index == IPSET_INVALID_ID) { |
| 87 | pr_warning("Cannot find set indentified by id %u to match\n", | 87 | pr_warning("Cannot find set indentified by id %u to match\n", |
| @@ -91,7 +91,7 @@ set_match_v0_checkentry(const struct xt_mtchk_param *par) | |||
| 91 | if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) { | 91 | if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) { |
| 92 | pr_warning("Protocol error: set match dimension " | 92 | pr_warning("Protocol error: set match dimension " |
| 93 | "is over the limit!\n"); | 93 | "is over the limit!\n"); |
| 94 | ip_set_nfnl_put(info->match_set.index); | 94 | ip_set_nfnl_put(par->net, info->match_set.index); |
| 95 | return -ERANGE; | 95 | return -ERANGE; |
| 96 | } | 96 | } |
| 97 | 97 | ||
| @@ -106,9 +106,104 @@ set_match_v0_destroy(const struct xt_mtdtor_param *par) | |||
| 106 | { | 106 | { |
| 107 | struct xt_set_info_match_v0 *info = par->matchinfo; | 107 | struct xt_set_info_match_v0 *info = par->matchinfo; |
| 108 | 108 | ||
| 109 | ip_set_nfnl_put(info->match_set.index); | 109 | ip_set_nfnl_put(par->net, info->match_set.index); |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | /* Revision 1 match */ | ||
| 113 | |||
| 114 | static bool | ||
| 115 | set_match_v1(const struct sk_buff *skb, struct xt_action_param *par) | ||
| 116 | { | ||
| 117 | const struct xt_set_info_match_v1 *info = par->matchinfo; | ||
| 118 | ADT_OPT(opt, par->family, info->match_set.dim, | ||
| 119 | info->match_set.flags, 0, UINT_MAX); | ||
| 120 | |||
| 121 | if (opt.flags & IPSET_RETURN_NOMATCH) | ||
| 122 | opt.cmdflags |= IPSET_FLAG_RETURN_NOMATCH; | ||
| 123 | |||
| 124 | return match_set(info->match_set.index, skb, par, &opt, | ||
| 125 | info->match_set.flags & IPSET_INV_MATCH); | ||
| 126 | } | ||
| 127 | |||
| 128 | static int | ||
| 129 | set_match_v1_checkentry(const struct xt_mtchk_param *par) | ||
| 130 | { | ||
| 131 | struct xt_set_info_match_v1 *info = par->matchinfo; | ||
| 132 | ip_set_id_t index; | ||
| 133 | |||
| 134 | index = ip_set_nfnl_get_byindex(par->net, info->match_set.index); | ||
| 135 | |||
| 136 | if (index == IPSET_INVALID_ID) { | ||
| 137 | pr_warning("Cannot find set indentified by id %u to match\n", | ||
| 138 | info->match_set.index); | ||
| 139 | return -ENOENT; | ||
| 140 | } | ||
| 141 | if (info->match_set.dim > IPSET_DIM_MAX) { | ||
| 142 | pr_warning("Protocol error: set match dimension " | ||
| 143 | "is over the limit!\n"); | ||
| 144 | ip_set_nfnl_put(par->net, info->match_set.index); | ||
| 145 | return -ERANGE; | ||
| 146 | } | ||
| 147 | |||
| 148 | return 0; | ||
| 149 | } | ||
| 150 | |||
| 151 | static void | ||
| 152 | set_match_v1_destroy(const struct xt_mtdtor_param *par) | ||
| 153 | { | ||
| 154 | struct xt_set_info_match_v1 *info = par->matchinfo; | ||
| 155 | |||
| 156 | ip_set_nfnl_put(par->net, info->match_set.index); | ||
| 157 | } | ||
| 158 | |||
| 159 | /* Revision 3 match */ | ||
| 160 | |||
| 161 | static bool | ||
| 162 | match_counter(u64 counter, const struct ip_set_counter_match *info) | ||
| 163 | { | ||
| 164 | switch (info->op) { | ||
| 165 | case IPSET_COUNTER_NONE: | ||
| 166 | return true; | ||
| 167 | case IPSET_COUNTER_EQ: | ||
| 168 | return counter == info->value; | ||
| 169 | case IPSET_COUNTER_NE: | ||
| 170 | return counter != info->value; | ||
| 171 | case IPSET_COUNTER_LT: | ||
| 172 | return counter < info->value; | ||
| 173 | case IPSET_COUNTER_GT: | ||
| 174 | return counter > info->value; | ||
| 175 | } | ||
| 176 | return false; | ||
| 177 | } | ||
| 178 | |||
| 179 | static bool | ||
| 180 | set_match_v3(const struct sk_buff *skb, struct xt_action_param *par) | ||
| 181 | { | ||
| 182 | const struct xt_set_info_match_v3 *info = par->matchinfo; | ||
| 183 | ADT_OPT(opt, par->family, info->match_set.dim, | ||
| 184 | info->match_set.flags, info->flags, UINT_MAX); | ||
| 185 | int ret; | ||
| 186 | |||
| 187 | if (info->packets.op != IPSET_COUNTER_NONE || | ||
| 188 | info->bytes.op != IPSET_COUNTER_NONE) | ||
| 189 | opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS; | ||
| 190 | |||
| 191 | ret = match_set(info->match_set.index, skb, par, &opt, | ||
| 192 | info->match_set.flags & IPSET_INV_MATCH); | ||
| 193 | |||
| 194 | if (!(ret && opt.cmdflags & IPSET_FLAG_MATCH_COUNTERS)) | ||
| 195 | return ret; | ||
| 196 | |||
| 197 | if (!match_counter(opt.ext.packets, &info->packets)) | ||
| 198 | return 0; | ||
| 199 | return match_counter(opt.ext.bytes, &info->bytes); | ||
| 200 | } | ||
| 201 | |||
| 202 | #define set_match_v3_checkentry set_match_v1_checkentry | ||
| 203 | #define set_match_v3_destroy set_match_v1_destroy | ||
| 204 | |||
| 205 | /* Revision 0 interface: backward compatible with netfilter/iptables */ | ||
| 206 | |||
| 112 | static unsigned int | 207 | static unsigned int |
| 113 | set_target_v0(struct sk_buff *skb, const struct xt_action_param *par) | 208 | set_target_v0(struct sk_buff *skb, const struct xt_action_param *par) |
| 114 | { | 209 | { |
| @@ -133,7 +228,7 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par) | |||
| 133 | ip_set_id_t index; | 228 | ip_set_id_t index; |
| 134 | 229 | ||
| 135 | if (info->add_set.index != IPSET_INVALID_ID) { | 230 | if (info->add_set.index != IPSET_INVALID_ID) { |
| 136 | index = ip_set_nfnl_get_byindex(info->add_set.index); | 231 | index = ip_set_nfnl_get_byindex(par->net, info->add_set.index); |
| 137 | if (index == IPSET_INVALID_ID) { | 232 | if (index == IPSET_INVALID_ID) { |
| 138 | pr_warning("Cannot find add_set index %u as target\n", | 233 | pr_warning("Cannot find add_set index %u as target\n", |
| 139 | info->add_set.index); | 234 | info->add_set.index); |
| @@ -142,12 +237,12 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par) | |||
| 142 | } | 237 | } |
| 143 | 238 | ||
| 144 | if (info->del_set.index != IPSET_INVALID_ID) { | 239 | if (info->del_set.index != IPSET_INVALID_ID) { |
| 145 | index = ip_set_nfnl_get_byindex(info->del_set.index); | 240 | index = ip_set_nfnl_get_byindex(par->net, info->del_set.index); |
| 146 | if (index == IPSET_INVALID_ID) { | 241 | if (index == IPSET_INVALID_ID) { |
| 147 | pr_warning("Cannot find del_set index %u as target\n", | 242 | pr_warning("Cannot find del_set index %u as target\n", |
| 148 | info->del_set.index); | 243 | info->del_set.index); |
| 149 | if (info->add_set.index != IPSET_INVALID_ID) | 244 | if (info->add_set.index != IPSET_INVALID_ID) |
| 150 | ip_set_nfnl_put(info->add_set.index); | 245 | ip_set_nfnl_put(par->net, info->add_set.index); |
| 151 | return -ENOENT; | 246 | return -ENOENT; |
| 152 | } | 247 | } |
| 153 | } | 248 | } |
| @@ -156,9 +251,9 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par) | |||
| 156 | pr_warning("Protocol error: SET target dimension " | 251 | pr_warning("Protocol error: SET target dimension " |
| 157 | "is over the limit!\n"); | 252 | "is over the limit!\n"); |
| 158 | if (info->add_set.index != IPSET_INVALID_ID) | 253 | if (info->add_set.index != IPSET_INVALID_ID) |
| 159 | ip_set_nfnl_put(info->add_set.index); | 254 | ip_set_nfnl_put(par->net, info->add_set.index); |
| 160 | if (info->del_set.index != IPSET_INVALID_ID) | 255 | if (info->del_set.index != IPSET_INVALID_ID) |
| 161 | ip_set_nfnl_put(info->del_set.index); | 256 | ip_set_nfnl_put(par->net, info->del_set.index); |
| 162 | return -ERANGE; | 257 | return -ERANGE; |
| 163 | } | 258 | } |
| 164 | 259 | ||
| @@ -175,57 +270,12 @@ set_target_v0_destroy(const struct xt_tgdtor_param *par) | |||
| 175 | const struct xt_set_info_target_v0 *info = par->targinfo; | 270 | const struct xt_set_info_target_v0 *info = par->targinfo; |
| 176 | 271 | ||
| 177 | if (info->add_set.index != IPSET_INVALID_ID) | 272 | if (info->add_set.index != IPSET_INVALID_ID) |
| 178 | ip_set_nfnl_put(info->add_set.index); | 273 | ip_set_nfnl_put(par->net, info->add_set.index); |
| 179 | if (info->del_set.index != IPSET_INVALID_ID) | 274 | if (info->del_set.index != IPSET_INVALID_ID) |
| 180 | ip_set_nfnl_put(info->del_set.index); | 275 | ip_set_nfnl_put(par->net, info->del_set.index); |
| 181 | } | 276 | } |
| 182 | 277 | ||
| 183 | /* Revision 1 match and target */ | 278 | /* Revision 1 target */ |
| 184 | |||
| 185 | static bool | ||
| 186 | set_match_v1(const struct sk_buff *skb, struct xt_action_param *par) | ||
| 187 | { | ||
| 188 | const struct xt_set_info_match_v1 *info = par->matchinfo; | ||
| 189 | ADT_OPT(opt, par->family, info->match_set.dim, | ||
| 190 | info->match_set.flags, 0, UINT_MAX); | ||
| 191 | |||
| 192 | if (opt.flags & IPSET_RETURN_NOMATCH) | ||
| 193 | opt.cmdflags |= IPSET_FLAG_RETURN_NOMATCH; | ||
| 194 | |||
| 195 | return match_set(info->match_set.index, skb, par, &opt, | ||
| 196 | info->match_set.flags & IPSET_INV_MATCH); | ||
| 197 | } | ||
| 198 | |||
| 199 | static int | ||
| 200 | set_match_v1_checkentry(const struct xt_mtchk_param *par) | ||
| 201 | { | ||
| 202 | struct xt_set_info_match_v1 *info = par->matchinfo; | ||
| 203 | ip_set_id_t index; | ||
| 204 | |||
| 205 | index = ip_set_nfnl_get_byindex(info->match_set.index); | ||
| 206 | |||
| 207 | if (index == IPSET_INVALID_ID) { | ||
| 208 | pr_warning("Cannot find set indentified by id %u to match\n", | ||
| 209 | info->match_set.index); | ||
| 210 | return -ENOENT; | ||
| 211 | } | ||
| 212 | if (info->match_set.dim > IPSET_DIM_MAX) { | ||
| 213 | pr_warning("Protocol error: set match dimension " | ||
| 214 | "is over the limit!\n"); | ||
| 215 | ip_set_nfnl_put(info->match_set.index); | ||
| 216 | return -ERANGE; | ||
| 217 | } | ||
| 218 | |||
| 219 | return 0; | ||
| 220 | } | ||
| 221 | |||
| 222 | static void | ||
| 223 | set_match_v1_destroy(const struct xt_mtdtor_param *par) | ||
| 224 | { | ||
| 225 | struct xt_set_info_match_v1 *info = par->matchinfo; | ||
| 226 | |||
| 227 | ip_set_nfnl_put(info->match_set.index); | ||
| 228 | } | ||
| 229 | 279 | ||
| 230 | static unsigned int | 280 | static unsigned int |
| 231 | set_target_v1(struct sk_buff *skb, const struct xt_action_param *par) | 281 | set_target_v1(struct sk_buff *skb, const struct xt_action_param *par) |
| @@ -251,7 +301,7 @@ set_target_v1_checkentry(const struct xt_tgchk_param *par) | |||
| 251 | ip_set_id_t index; | 301 | ip_set_id_t index; |
| 252 | 302 | ||
| 253 | if (info->add_set.index != IPSET_INVALID_ID) { | 303 | if (info->add_set.index != IPSET_INVALID_ID) { |
| 254 | index = ip_set_nfnl_get_byindex(info->add_set.index); | 304 | index = ip_set_nfnl_get_byindex(par->net, info->add_set.index); |
| 255 | if (index == IPSET_INVALID_ID) { | 305 | if (index == IPSET_INVALID_ID) { |
| 256 | pr_warning("Cannot find add_set index %u as target\n", | 306 | pr_warning("Cannot find add_set index %u as target\n", |
| 257 | info->add_set.index); | 307 | info->add_set.index); |
| @@ -260,12 +310,12 @@ set_target_v1_checkentry(const struct xt_tgchk_param *par) | |||
| 260 | } | 310 | } |
| 261 | 311 | ||
| 262 | if (info->del_set.index != IPSET_INVALID_ID) { | 312 | if (info->del_set.index != IPSET_INVALID_ID) { |
| 263 | index = ip_set_nfnl_get_byindex(info->del_set.index); | 313 | index = ip_set_nfnl_get_byindex(par->net, info->del_set.index); |
| 264 | if (index == IPSET_INVALID_ID) { | 314 | if (index == IPSET_INVALID_ID) { |
| 265 | pr_warning("Cannot find del_set index %u as target\n", | 315 | pr_warning("Cannot find del_set index %u as target\n", |
| 266 | info->del_set.index); | 316 | info->del_set.index); |
| 267 | if (info->add_set.index != IPSET_INVALID_ID) | 317 | if (info->add_set.index != IPSET_INVALID_ID) |
| 268 | ip_set_nfnl_put(info->add_set.index); | 318 | ip_set_nfnl_put(par->net, info->add_set.index); |
| 269 | return -ENOENT; | 319 | return -ENOENT; |
| 270 | } | 320 | } |
| 271 | } | 321 | } |
| @@ -274,9 +324,9 @@ set_target_v1_checkentry(const struct xt_tgchk_param *par) | |||
| 274 | pr_warning("Protocol error: SET target dimension " | 324 | pr_warning("Protocol error: SET target dimension " |
| 275 | "is over the limit!\n"); | 325 | "is over the limit!\n"); |
| 276 | if (info->add_set.index != IPSET_INVALID_ID) | 326 | if (info->add_set.index != IPSET_INVALID_ID) |
| 277 | ip_set_nfnl_put(info->add_set.index); | 327 | ip_set_nfnl_put(par->net, info->add_set.index); |
| 278 | if (info->del_set.index != IPSET_INVALID_ID) | 328 | if (info->del_set.index != IPSET_INVALID_ID) |
| 279 | ip_set_nfnl_put(info->del_set.index); | 329 | ip_set_nfnl_put(par->net, info->del_set.index); |
| 280 | return -ERANGE; | 330 | return -ERANGE; |
| 281 | } | 331 | } |
| 282 | 332 | ||
| @@ -289,9 +339,9 @@ set_target_v1_destroy(const struct xt_tgdtor_param *par) | |||
| 289 | const struct xt_set_info_target_v1 *info = par->targinfo; | 339 | const struct xt_set_info_target_v1 *info = par->targinfo; |
| 290 | 340 | ||
| 291 | if (info->add_set.index != IPSET_INVALID_ID) | 341 | if (info->add_set.index != IPSET_INVALID_ID) |
| 292 | ip_set_nfnl_put(info->add_set.index); | 342 | ip_set_nfnl_put(par->net, info->add_set.index); |
| 293 | if (info->del_set.index != IPSET_INVALID_ID) | 343 | if (info->del_set.index != IPSET_INVALID_ID) |
| 294 | ip_set_nfnl_put(info->del_set.index); | 344 | ip_set_nfnl_put(par->net, info->del_set.index); |
| 295 | } | 345 | } |
| 296 | 346 | ||
| 297 | /* Revision 2 target */ | 347 | /* Revision 2 target */ |
| @@ -320,52 +370,6 @@ set_target_v2(struct sk_buff *skb, const struct xt_action_param *par) | |||
| 320 | #define set_target_v2_checkentry set_target_v1_checkentry | 370 | #define set_target_v2_checkentry set_target_v1_checkentry |
| 321 | #define set_target_v2_destroy set_target_v1_destroy | 371 | #define set_target_v2_destroy set_target_v1_destroy |
| 322 | 372 | ||
| 323 | /* Revision 3 match */ | ||
| 324 | |||
| 325 | static bool | ||
| 326 | match_counter(u64 counter, const struct ip_set_counter_match *info) | ||
| 327 | { | ||
| 328 | switch (info->op) { | ||
| 329 | case IPSET_COUNTER_NONE: | ||
| 330 | return true; | ||
| 331 | case IPSET_COUNTER_EQ: | ||
| 332 | return counter == info->value; | ||
| 333 | case IPSET_COUNTER_NE: | ||
| 334 | return counter != info->value; | ||
| 335 | case IPSET_COUNTER_LT: | ||
| 336 | return counter < info->value; | ||
| 337 | case IPSET_COUNTER_GT: | ||
| 338 | return counter > info->value; | ||
| 339 | } | ||
| 340 | return false; | ||
| 341 | } | ||
| 342 | |||
| 343 | static bool | ||
| 344 | set_match_v3(const struct sk_buff *skb, struct xt_action_param *par) | ||
| 345 | { | ||
| 346 | const struct xt_set_info_match_v3 *info = par->matchinfo; | ||
| 347 | ADT_OPT(opt, par->family, info->match_set.dim, | ||
| 348 | info->match_set.flags, info->flags, UINT_MAX); | ||
| 349 | int ret; | ||
| 350 | |||
| 351 | if (info->packets.op != IPSET_COUNTER_NONE || | ||
| 352 | info->bytes.op != IPSET_COUNTER_NONE) | ||
| 353 | opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS; | ||
| 354 | |||
| 355 | ret = match_set(info->match_set.index, skb, par, &opt, | ||
| 356 | info->match_set.flags & IPSET_INV_MATCH); | ||
| 357 | |||
| 358 | if (!(ret && opt.cmdflags & IPSET_FLAG_MATCH_COUNTERS)) | ||
| 359 | return ret; | ||
| 360 | |||
| 361 | if (!match_counter(opt.ext.packets, &info->packets)) | ||
| 362 | return 0; | ||
| 363 | return match_counter(opt.ext.bytes, &info->bytes); | ||
| 364 | } | ||
| 365 | |||
| 366 | #define set_match_v3_checkentry set_match_v1_checkentry | ||
| 367 | #define set_match_v3_destroy set_match_v1_destroy | ||
| 368 | |||
| 369 | static struct xt_match set_matches[] __read_mostly = { | 373 | static struct xt_match set_matches[] __read_mostly = { |
| 370 | { | 374 | { |
| 371 | .name = "set", | 375 | .name = "set", |
diff --git a/net/sched/em_ipset.c b/net/sched/em_ipset.c index 938b7cbf5627..1ac41d3de5c3 100644 --- a/net/sched/em_ipset.c +++ b/net/sched/em_ipset.c | |||
| @@ -24,11 +24,12 @@ static int em_ipset_change(struct tcf_proto *tp, void *data, int data_len, | |||
| 24 | { | 24 | { |
| 25 | struct xt_set_info *set = data; | 25 | struct xt_set_info *set = data; |
| 26 | ip_set_id_t index; | 26 | ip_set_id_t index; |
| 27 | struct net *net = qdisc_dev(tp->q)->nd_net; | ||
| 27 | 28 | ||
| 28 | if (data_len != sizeof(*set)) | 29 | if (data_len != sizeof(*set)) |
| 29 | return -EINVAL; | 30 | return -EINVAL; |
| 30 | 31 | ||
| 31 | index = ip_set_nfnl_get_byindex(set->index); | 32 | index = ip_set_nfnl_get_byindex(net, set->index); |
| 32 | if (index == IPSET_INVALID_ID) | 33 | if (index == IPSET_INVALID_ID) |
| 33 | return -ENOENT; | 34 | return -ENOENT; |
| 34 | 35 | ||
| @@ -37,7 +38,7 @@ static int em_ipset_change(struct tcf_proto *tp, void *data, int data_len, | |||
| 37 | if (em->data) | 38 | if (em->data) |
| 38 | return 0; | 39 | return 0; |
| 39 | 40 | ||
| 40 | ip_set_nfnl_put(index); | 41 | ip_set_nfnl_put(net, index); |
| 41 | return -ENOMEM; | 42 | return -ENOMEM; |
| 42 | } | 43 | } |
| 43 | 44 | ||
| @@ -45,7 +46,7 @@ static void em_ipset_destroy(struct tcf_proto *p, struct tcf_ematch *em) | |||
| 45 | { | 46 | { |
| 46 | const struct xt_set_info *set = (const void *) em->data; | 47 | const struct xt_set_info *set = (const void *) em->data; |
| 47 | if (set) { | 48 | if (set) { |
| 48 | ip_set_nfnl_put(set->index); | 49 | ip_set_nfnl_put(qdisc_dev(p->q)->nd_net, set->index); |
| 49 | kfree((void *) em->data); | 50 | kfree((void *) em->data); |
| 50 | } | 51 | } |
| 51 | } | 52 | } |
