aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2011-06-16 12:49:17 -0400
committerPatrick McHardy <kaber@trash.net>2011-06-16 12:49:17 -0400
commit3d14b171f004f75c2d1e82e10545966f94132705 (patch)
tree149f8ac4663f9824c636ccf059664e5e61a920fe
parentc1e2e04388b2539960453689b8e721709f71dc9c (diff)
netfilter: ipset: fix adding ranges to hash types
When ranges are added to hash types, the elements may trigger rehashing the set. However, the last successfully added element was not kept track so the adding started again with the first element after the rehashing. Bug reported by Mr Dash Four. Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> Signed-off-by: Patrick McHardy <kaber@trash.net>
-rw-r--r--include/linux/netfilter/ipset/ip_set.h2
-rw-r--r--include/linux/netfilter/ipset/ip_set_ahash.h22
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_ip.c2
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_ipmac.c2
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_port.c2
-rw-r--r--net/netfilter/ipset/ip_set_core.c11
-rw-r--r--net/netfilter/ipset/ip_set_hash_ip.c17
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipport.c31
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipportip.c31
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipportnet.c31
-rw-r--r--net/netfilter/ipset/ip_set_hash_net.c16
-rw-r--r--net/netfilter/ipset/ip_set_hash_netport.c22
-rw-r--r--net/netfilter/ipset/ip_set_list_set.c2
13 files changed, 157 insertions, 34 deletions
diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h
index e677c4d8f00e..710ba0070298 100644
--- a/include/linux/netfilter/ipset/ip_set.h
+++ b/include/linux/netfilter/ipset/ip_set.h
@@ -244,7 +244,7 @@ struct ip_set_type_variant {
244 * zero for no match/success to add/delete 244 * zero for no match/success to add/delete
245 * positive for matching element */ 245 * positive for matching element */
246 int (*uadt)(struct ip_set *set, struct nlattr *tb[], 246 int (*uadt)(struct ip_set *set, struct nlattr *tb[],
247 enum ipset_adt adt, u32 *lineno, u32 flags); 247 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried);
248 248
249 /* Low level add/del/test functions */ 249 /* Low level add/del/test functions */
250 ipset_adtfn adt[IPSET_ADT_MAX]; 250 ipset_adtfn adt[IPSET_ADT_MAX];
diff --git a/include/linux/netfilter/ipset/ip_set_ahash.h b/include/linux/netfilter/ipset/ip_set_ahash.h
index 6c0219348b43..8709bd950c8b 100644
--- a/include/linux/netfilter/ipset/ip_set_ahash.h
+++ b/include/linux/netfilter/ipset/ip_set_ahash.h
@@ -5,6 +5,11 @@
5#include <linux/jhash.h> 5#include <linux/jhash.h>
6#include <linux/netfilter/ipset/ip_set_timeout.h> 6#include <linux/netfilter/ipset/ip_set_timeout.h>
7 7
8#define CONCAT(a, b, c) a##b##c
9#define TOKEN(a, b, c) CONCAT(a, b, c)
10
11#define type_pf_next TOKEN(TYPE, PF, _elem)
12
8/* Hashing which uses arrays to resolve clashing. The hash table is resized 13/* Hashing which uses arrays to resolve clashing. The hash table is resized
9 * (doubled) when searching becomes too long. 14 * (doubled) when searching becomes too long.
10 * Internally jhash is used with the assumption that the size of the 15 * Internally jhash is used with the assumption that the size of the
@@ -54,6 +59,7 @@ struct ip_set_hash {
54 u32 initval; /* random jhash init value */ 59 u32 initval; /* random jhash init value */
55 u32 timeout; /* timeout value, if enabled */ 60 u32 timeout; /* timeout value, if enabled */
56 struct timer_list gc; /* garbage collection when timeout enabled */ 61 struct timer_list gc; /* garbage collection when timeout enabled */
62 struct type_pf_next next; /* temporary storage for uadd */
57#ifdef IP_SET_HASH_WITH_NETMASK 63#ifdef IP_SET_HASH_WITH_NETMASK
58 u8 netmask; /* netmask value for subnets to store */ 64 u8 netmask; /* netmask value for subnets to store */
59#endif 65#endif
@@ -217,6 +223,7 @@ ip_set_hash_destroy(struct ip_set *set)
217#define type_pf_data_netmask TOKEN(TYPE, PF, _data_netmask) 223#define type_pf_data_netmask TOKEN(TYPE, PF, _data_netmask)
218#define type_pf_data_list TOKEN(TYPE, PF, _data_list) 224#define type_pf_data_list TOKEN(TYPE, PF, _data_list)
219#define type_pf_data_tlist TOKEN(TYPE, PF, _data_tlist) 225#define type_pf_data_tlist TOKEN(TYPE, PF, _data_tlist)
226#define type_pf_data_next TOKEN(TYPE, PF, _data_next)
220 227
221#define type_pf_elem TOKEN(TYPE, PF, _elem) 228#define type_pf_elem TOKEN(TYPE, PF, _elem)
222#define type_pf_telem TOKEN(TYPE, PF, _telem) 229#define type_pf_telem TOKEN(TYPE, PF, _telem)
@@ -346,6 +353,9 @@ retry:
346 return 0; 353 return 0;
347} 354}
348 355
356static inline void
357type_pf_data_next(struct ip_set_hash *h, const struct type_pf_elem *d);
358
349/* Add an element to a hash and update the internal counters when succeeded, 359/* Add an element to a hash and update the internal counters when succeeded,
350 * otherwise report the proper error code. */ 360 * otherwise report the proper error code. */
351static int 361static int
@@ -372,8 +382,11 @@ type_pf_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
372 } 382 }
373 383
374 ret = type_pf_elem_add(n, value); 384 ret = type_pf_elem_add(n, value);
375 if (ret != 0) 385 if (ret != 0) {
386 if (ret == -EAGAIN)
387 type_pf_data_next(h, d);
376 goto out; 388 goto out;
389 }
377 390
378#ifdef IP_SET_HASH_WITH_NETS 391#ifdef IP_SET_HASH_WITH_NETS
379 add_cidr(h, d->cidr, HOST_MASK); 392 add_cidr(h, d->cidr, HOST_MASK);
@@ -589,7 +602,7 @@ type_pf_kadt(struct ip_set *set, const struct sk_buff * skb,
589 enum ipset_adt adt, const struct ip_set_adt_opt *opt); 602 enum ipset_adt adt, const struct ip_set_adt_opt *opt);
590static int 603static int
591type_pf_uadt(struct ip_set *set, struct nlattr *tb[], 604type_pf_uadt(struct ip_set *set, struct nlattr *tb[],
592 enum ipset_adt adt, u32 *lineno, u32 flags); 605 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried);
593 606
594static const struct ip_set_type_variant type_pf_variant = { 607static const struct ip_set_type_variant type_pf_variant = {
595 .kadt = type_pf_kadt, 608 .kadt = type_pf_kadt,
@@ -821,8 +834,11 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
821 goto out; 834 goto out;
822 } 835 }
823 ret = type_pf_elem_tadd(n, d, timeout); 836 ret = type_pf_elem_tadd(n, d, timeout);
824 if (ret != 0) 837 if (ret != 0) {
838 if (ret == -EEXIST)
839 type_pf_data_next(h, d);
825 goto out; 840 goto out;
841 }
826 842
827#ifdef IP_SET_HASH_WITH_NETS 843#ifdef IP_SET_HASH_WITH_NETS
828 add_cidr(h, d->cidr, HOST_MASK); 844 add_cidr(h, d->cidr, HOST_MASK);
diff --git a/net/netfilter/ipset/ip_set_bitmap_ip.c b/net/netfilter/ipset/ip_set_bitmap_ip.c
index 75990b37ca37..3a71c8e41557 100644
--- a/net/netfilter/ipset/ip_set_bitmap_ip.c
+++ b/net/netfilter/ipset/ip_set_bitmap_ip.c
@@ -236,7 +236,7 @@ bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb,
236 236
237static int 237static int
238bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[], 238bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[],
239 enum ipset_adt adt, u32 *lineno, u32 flags) 239 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
240{ 240{
241 struct bitmap_ip *map = set->data; 241 struct bitmap_ip *map = set->data;
242 ipset_adtfn adtfn = set->variant->adt[adt]; 242 ipset_adtfn adtfn = set->variant->adt[adt];
diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c
index cbe77f36650b..fdd5f79d93f3 100644
--- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c
+++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c
@@ -365,7 +365,7 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
365 365
366static int 366static int
367bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[], 367bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[],
368 enum ipset_adt adt, u32 *lineno, u32 flags) 368 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
369{ 369{
370 const struct bitmap_ipmac *map = set->data; 370 const struct bitmap_ipmac *map = set->data;
371 ipset_adtfn adtfn = set->variant->adt[adt]; 371 ipset_adtfn adtfn = set->variant->adt[adt];
diff --git a/net/netfilter/ipset/ip_set_bitmap_port.c b/net/netfilter/ipset/ip_set_bitmap_port.c
index 0b0ae19d0290..a6a5b3558ddc 100644
--- a/net/netfilter/ipset/ip_set_bitmap_port.c
+++ b/net/netfilter/ipset/ip_set_bitmap_port.c
@@ -231,7 +231,7 @@ bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,
231 231
232static int 232static int
233bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[], 233bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[],
234 enum ipset_adt adt, u32 *lineno, u32 flags) 234 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
235{ 235{
236 struct bitmap_port *map = set->data; 236 struct bitmap_port *map = set->data;
237 ipset_adtfn adtfn = set->variant->adt[adt]; 237 ipset_adtfn adtfn = set->variant->adt[adt];
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
index 8446c7d81898..528a9b3933ab 100644
--- a/net/netfilter/ipset/ip_set_core.c
+++ b/net/netfilter/ipset/ip_set_core.c
@@ -1158,17 +1158,18 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set,
1158 struct nlattr *tb[], enum ipset_adt adt, 1158 struct nlattr *tb[], enum ipset_adt adt,
1159 u32 flags, bool use_lineno) 1159 u32 flags, bool use_lineno)
1160{ 1160{
1161 int ret, retried = 0; 1161 int ret;
1162 u32 lineno = 0; 1162 u32 lineno = 0;
1163 bool eexist = flags & IPSET_FLAG_EXIST; 1163 bool eexist = flags & IPSET_FLAG_EXIST, retried = false;
1164 1164
1165 do { 1165 do {
1166 write_lock_bh(&set->lock); 1166 write_lock_bh(&set->lock);
1167 ret = set->variant->uadt(set, tb, adt, &lineno, flags); 1167 ret = set->variant->uadt(set, tb, adt, &lineno, flags, retried);
1168 write_unlock_bh(&set->lock); 1168 write_unlock_bh(&set->lock);
1169 retried = true;
1169 } while (ret == -EAGAIN && 1170 } while (ret == -EAGAIN &&
1170 set->variant->resize && 1171 set->variant->resize &&
1171 (ret = set->variant->resize(set, retried++)) == 0); 1172 (ret = set->variant->resize(set, retried)) == 0);
1172 1173
1173 if (!ret || (ret == -IPSET_ERR_EXIST && eexist)) 1174 if (!ret || (ret == -IPSET_ERR_EXIST && eexist))
1174 return 0; 1175 return 0;
@@ -1341,7 +1342,7 @@ ip_set_utest(struct sock *ctnl, struct sk_buff *skb,
1341 return -IPSET_ERR_PROTOCOL; 1342 return -IPSET_ERR_PROTOCOL;
1342 1343
1343 read_lock_bh(&set->lock); 1344 read_lock_bh(&set->lock);
1344 ret = set->variant->uadt(set, tb, IPSET_TEST, NULL, 0); 1345 ret = set->variant->uadt(set, tb, IPSET_TEST, NULL, 0, 0);
1345 read_unlock_bh(&set->lock); 1346 read_unlock_bh(&set->lock);
1346 /* Userspace can't trigger element to be re-added */ 1347 /* Userspace can't trigger element to be re-added */
1347 if (ret == -EAGAIN) 1348 if (ret == -EAGAIN)
diff --git a/net/netfilter/ipset/ip_set_hash_ip.c b/net/netfilter/ipset/ip_set_hash_ip.c
index 65a445477f64..c99e861ce031 100644
--- a/net/netfilter/ipset/ip_set_hash_ip.c
+++ b/net/netfilter/ipset/ip_set_hash_ip.c
@@ -108,6 +108,12 @@ nla_put_failure:
108#define HOST_MASK 32 108#define HOST_MASK 32
109#include <linux/netfilter/ipset/ip_set_ahash.h> 109#include <linux/netfilter/ipset/ip_set_ahash.h>
110 110
111static inline void
112hash_ip4_data_next(struct ip_set_hash *h, const struct hash_ip4_elem *d)
113{
114 h->next.ip = ntohl(d->ip);
115}
116
111static int 117static int
112hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb, 118hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
113 enum ipset_adt adt, const struct ip_set_adt_opt *opt) 119 enum ipset_adt adt, const struct ip_set_adt_opt *opt)
@@ -126,7 +132,7 @@ hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
126 132
127static int 133static int
128hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], 134hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
129 enum ipset_adt adt, u32 *lineno, u32 flags) 135 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
130{ 136{
131 const struct ip_set_hash *h = set->data; 137 const struct ip_set_hash *h = set->data;
132 ipset_adtfn adtfn = set->variant->adt[adt]; 138 ipset_adtfn adtfn = set->variant->adt[adt];
@@ -178,6 +184,8 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
178 184
179 hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1); 185 hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1);
180 186
187 if (retried)
188 ip = h->next.ip;
181 for (; !before(ip_to, ip); ip += hosts) { 189 for (; !before(ip_to, ip); ip += hosts) {
182 nip = htonl(ip); 190 nip = htonl(ip);
183 if (nip == 0) 191 if (nip == 0)
@@ -281,6 +289,11 @@ nla_put_failure:
281#define HOST_MASK 128 289#define HOST_MASK 128
282#include <linux/netfilter/ipset/ip_set_ahash.h> 290#include <linux/netfilter/ipset/ip_set_ahash.h>
283 291
292static inline void
293hash_ip6_data_next(struct ip_set_hash *h, const struct hash_ip6_elem *d)
294{
295}
296
284static int 297static int
285hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb, 298hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb,
286 enum ipset_adt adt, const struct ip_set_adt_opt *opt) 299 enum ipset_adt adt, const struct ip_set_adt_opt *opt)
@@ -305,7 +318,7 @@ static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
305 318
306static int 319static int
307hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[], 320hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[],
308 enum ipset_adt adt, u32 *lineno, u32 flags) 321 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
309{ 322{
310 const struct ip_set_hash *h = set->data; 323 const struct ip_set_hash *h = set->data;
311 ipset_adtfn adtfn = set->variant->adt[adt]; 324 ipset_adtfn adtfn = set->variant->adt[adt];
diff --git a/net/netfilter/ipset/ip_set_hash_ipport.c b/net/netfilter/ipset/ip_set_hash_ipport.c
index 9f179bb4f13e..aa91b2c73be3 100644
--- a/net/netfilter/ipset/ip_set_hash_ipport.c
+++ b/net/netfilter/ipset/ip_set_hash_ipport.c
@@ -124,6 +124,14 @@ nla_put_failure:
124#define HOST_MASK 32 124#define HOST_MASK 32
125#include <linux/netfilter/ipset/ip_set_ahash.h> 125#include <linux/netfilter/ipset/ip_set_ahash.h>
126 126
127static inline void
128hash_ipport4_data_next(struct ip_set_hash *h,
129 const struct hash_ipport4_elem *d)
130{
131 h->next.ip = ntohl(d->ip);
132 h->next.port = ntohs(d->port);
133}
134
127static int 135static int
128hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb, 136hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb,
129 enum ipset_adt adt, const struct ip_set_adt_opt *opt) 137 enum ipset_adt adt, const struct ip_set_adt_opt *opt)
@@ -143,12 +151,12 @@ hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb,
143 151
144static int 152static int
145hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], 153hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
146 enum ipset_adt adt, u32 *lineno, u32 flags) 154 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
147{ 155{
148 const struct ip_set_hash *h = set->data; 156 const struct ip_set_hash *h = set->data;
149 ipset_adtfn adtfn = set->variant->adt[adt]; 157 ipset_adtfn adtfn = set->variant->adt[adt];
150 struct hash_ipport4_elem data = { }; 158 struct hash_ipport4_elem data = { };
151 u32 ip, ip_to, p, port, port_to; 159 u32 ip, ip_to, p = 0, port, port_to;
152 u32 timeout = h->timeout; 160 u32 timeout = h->timeout;
153 bool with_ports = false; 161 bool with_ports = false;
154 int ret; 162 int ret;
@@ -220,8 +228,11 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
220 swap(port, port_to); 228 swap(port, port_to);
221 } 229 }
222 230
223 for (; !before(ip_to, ip); ip++) 231 if (retried)
224 for (p = port; p <= port_to; p++) { 232 ip = h->next.ip;
233 for (; !before(ip_to, ip); ip++) {
234 p = retried && ip == h->next.ip ? h->next.port : port;
235 for (; p <= port_to; p++) {
225 data.ip = htonl(ip); 236 data.ip = htonl(ip);
226 data.port = htons(p); 237 data.port = htons(p);
227 ret = adtfn(set, &data, timeout, flags); 238 ret = adtfn(set, &data, timeout, flags);
@@ -231,6 +242,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
231 else 242 else
232 ret = 0; 243 ret = 0;
233 } 244 }
245 }
234 return ret; 246 return ret;
235} 247}
236 248
@@ -328,6 +340,13 @@ nla_put_failure:
328#define HOST_MASK 128 340#define HOST_MASK 128
329#include <linux/netfilter/ipset/ip_set_ahash.h> 341#include <linux/netfilter/ipset/ip_set_ahash.h>
330 342
343static inline void
344hash_ipport6_data_next(struct ip_set_hash *h,
345 const struct hash_ipport6_elem *d)
346{
347 h->next.port = ntohs(d->port);
348}
349
331static int 350static int
332hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb, 351hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb,
333 enum ipset_adt adt, const struct ip_set_adt_opt *opt) 352 enum ipset_adt adt, const struct ip_set_adt_opt *opt)
@@ -347,7 +366,7 @@ hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb,
347 366
348static int 367static int
349hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[], 368hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
350 enum ipset_adt adt, u32 *lineno, u32 flags) 369 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
351{ 370{
352 const struct ip_set_hash *h = set->data; 371 const struct ip_set_hash *h = set->data;
353 ipset_adtfn adtfn = set->variant->adt[adt]; 372 ipset_adtfn adtfn = set->variant->adt[adt];
@@ -405,6 +424,8 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
405 if (port > port_to) 424 if (port > port_to)
406 swap(port, port_to); 425 swap(port, port_to);
407 426
427 if (retried)
428 port = h->next.port;
408 for (; port <= port_to; port++) { 429 for (; port <= port_to; port++) {
409 data.port = htons(port); 430 data.port = htons(port);
410 ret = adtfn(set, &data, timeout, flags); 431 ret = adtfn(set, &data, timeout, flags);
diff --git a/net/netfilter/ipset/ip_set_hash_ipportip.c b/net/netfilter/ipset/ip_set_hash_ipportip.c
index 7cfa52b34981..b88e74e0bf06 100644
--- a/net/netfilter/ipset/ip_set_hash_ipportip.c
+++ b/net/netfilter/ipset/ip_set_hash_ipportip.c
@@ -127,6 +127,14 @@ nla_put_failure:
127#define HOST_MASK 32 127#define HOST_MASK 32
128#include <linux/netfilter/ipset/ip_set_ahash.h> 128#include <linux/netfilter/ipset/ip_set_ahash.h>
129 129
130static inline void
131hash_ipportip4_data_next(struct ip_set_hash *h,
132 const struct hash_ipportip4_elem *d)
133{
134 h->next.ip = ntohl(d->ip);
135 h->next.port = ntohs(d->port);
136}
137
130static int 138static int
131hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb, 139hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb,
132 enum ipset_adt adt, const struct ip_set_adt_opt *opt) 140 enum ipset_adt adt, const struct ip_set_adt_opt *opt)
@@ -147,12 +155,12 @@ hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb,
147 155
148static int 156static int
149hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], 157hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
150 enum ipset_adt adt, u32 *lineno, u32 flags) 158 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
151{ 159{
152 const struct ip_set_hash *h = set->data; 160 const struct ip_set_hash *h = set->data;
153 ipset_adtfn adtfn = set->variant->adt[adt]; 161 ipset_adtfn adtfn = set->variant->adt[adt];
154 struct hash_ipportip4_elem data = { }; 162 struct hash_ipportip4_elem data = { };
155 u32 ip, ip_to, p, port, port_to; 163 u32 ip, ip_to, p = 0, port, port_to;
156 u32 timeout = h->timeout; 164 u32 timeout = h->timeout;
157 bool with_ports = false; 165 bool with_ports = false;
158 int ret; 166 int ret;
@@ -228,8 +236,11 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
228 swap(port, port_to); 236 swap(port, port_to);
229 } 237 }
230 238
231 for (; !before(ip_to, ip); ip++) 239 if (retried)
232 for (p = port; p <= port_to; p++) { 240 ip = h->next.ip;
241 for (; !before(ip_to, ip); ip++) {
242 p = retried && ip == h->next.ip ? h->next.port : port;
243 for (; p <= port_to; p++) {
233 data.ip = htonl(ip); 244 data.ip = htonl(ip);
234 data.port = htons(p); 245 data.port = htons(p);
235 ret = adtfn(set, &data, timeout, flags); 246 ret = adtfn(set, &data, timeout, flags);
@@ -239,6 +250,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
239 else 250 else
240 ret = 0; 251 ret = 0;
241 } 252 }
253 }
242 return ret; 254 return ret;
243} 255}
244 256
@@ -341,6 +353,13 @@ nla_put_failure:
341#define HOST_MASK 128 353#define HOST_MASK 128
342#include <linux/netfilter/ipset/ip_set_ahash.h> 354#include <linux/netfilter/ipset/ip_set_ahash.h>
343 355
356static inline void
357hash_ipportip6_data_next(struct ip_set_hash *h,
358 const struct hash_ipportip6_elem *d)
359{
360 h->next.port = ntohs(d->port);
361}
362
344static int 363static int
345hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb, 364hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb,
346 enum ipset_adt adt, const struct ip_set_adt_opt *opt) 365 enum ipset_adt adt, const struct ip_set_adt_opt *opt)
@@ -361,7 +380,7 @@ hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb,
361 380
362static int 381static int
363hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[], 382hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
364 enum ipset_adt adt, u32 *lineno, u32 flags) 383 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
365{ 384{
366 const struct ip_set_hash *h = set->data; 385 const struct ip_set_hash *h = set->data;
367 ipset_adtfn adtfn = set->variant->adt[adt]; 386 ipset_adtfn adtfn = set->variant->adt[adt];
@@ -423,6 +442,8 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
423 if (port > port_to) 442 if (port > port_to)
424 swap(port, port_to); 443 swap(port, port_to);
425 444
445 if (retried)
446 port = h->next.port;
426 for (; port <= port_to; port++) { 447 for (; port <= port_to; port++) {
427 data.port = htons(port); 448 data.port = htons(port);
428 ret = adtfn(set, &data, timeout, flags); 449 ret = adtfn(set, &data, timeout, flags);
diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c
index 104042aba92b..605ef3bf94ef 100644
--- a/net/netfilter/ipset/ip_set_hash_ipportnet.c
+++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c
@@ -140,6 +140,14 @@ nla_put_failure:
140#define HOST_MASK 32 140#define HOST_MASK 32
141#include <linux/netfilter/ipset/ip_set_ahash.h> 141#include <linux/netfilter/ipset/ip_set_ahash.h>
142 142
143static inline void
144hash_ipportnet4_data_next(struct ip_set_hash *h,
145 const struct hash_ipportnet4_elem *d)
146{
147 h->next.ip = ntohl(d->ip);
148 h->next.port = ntohs(d->port);
149}
150
143static int 151static int
144hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb, 152hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
145 enum ipset_adt adt, const struct ip_set_adt_opt *opt) 153 enum ipset_adt adt, const struct ip_set_adt_opt *opt)
@@ -167,12 +175,12 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
167 175
168static int 176static int
169hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], 177hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
170 enum ipset_adt adt, u32 *lineno, u32 flags) 178 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
171{ 179{
172 const struct ip_set_hash *h = set->data; 180 const struct ip_set_hash *h = set->data;
173 ipset_adtfn adtfn = set->variant->adt[adt]; 181 ipset_adtfn adtfn = set->variant->adt[adt];
174 struct hash_ipportnet4_elem data = { .cidr = HOST_MASK }; 182 struct hash_ipportnet4_elem data = { .cidr = HOST_MASK };
175 u32 ip, ip_to, p, port, port_to; 183 u32 ip, ip_to, p = 0, port, port_to;
176 u32 timeout = h->timeout; 184 u32 timeout = h->timeout;
177 bool with_ports = false; 185 bool with_ports = false;
178 int ret; 186 int ret;
@@ -256,8 +264,11 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
256 swap(port, port_to); 264 swap(port, port_to);
257 } 265 }
258 266
259 for (; !before(ip_to, ip); ip++) 267 if (retried)
260 for (p = port; p <= port_to; p++) { 268 ip = h->next.ip;
269 for (; !before(ip_to, ip); ip++) {
270 p = retried && ip == h->next.ip ? h->next.port : port;
271 for (; p <= port_to; p++) {
261 data.ip = htonl(ip); 272 data.ip = htonl(ip);
262 data.port = htons(p); 273 data.port = htons(p);
263 ret = adtfn(set, &data, timeout, flags); 274 ret = adtfn(set, &data, timeout, flags);
@@ -267,6 +278,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
267 else 278 else
268 ret = 0; 279 ret = 0;
269 } 280 }
281 }
270 return ret; 282 return ret;
271} 283}
272 284
@@ -388,6 +400,13 @@ nla_put_failure:
388#define HOST_MASK 128 400#define HOST_MASK 128
389#include <linux/netfilter/ipset/ip_set_ahash.h> 401#include <linux/netfilter/ipset/ip_set_ahash.h>
390 402
403static inline void
404hash_ipportnet6_data_next(struct ip_set_hash *h,
405 const struct hash_ipportnet6_elem *d)
406{
407 h->next.port = ntohs(d->port);
408}
409
391static int 410static int
392hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb, 411hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
393 enum ipset_adt adt, const struct ip_set_adt_opt *opt) 412 enum ipset_adt adt, const struct ip_set_adt_opt *opt)
@@ -415,7 +434,7 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
415 434
416static int 435static int
417hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[], 436hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
418 enum ipset_adt adt, u32 *lineno, u32 flags) 437 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
419{ 438{
420 const struct ip_set_hash *h = set->data; 439 const struct ip_set_hash *h = set->data;
421 ipset_adtfn adtfn = set->variant->adt[adt]; 440 ipset_adtfn adtfn = set->variant->adt[adt];
@@ -485,6 +504,8 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
485 if (port > port_to) 504 if (port > port_to)
486 swap(port, port_to); 505 swap(port, port_to);
487 506
507 if (retried)
508 port = h->next.port;
488 for (; port <= port_to; port++) { 509 for (; port <= port_to; port++) {
489 data.port = htons(port); 510 data.port = htons(port);
490 ret = adtfn(set, &data, timeout, flags); 511 ret = adtfn(set, &data, timeout, flags);
diff --git a/net/netfilter/ipset/ip_set_hash_net.c b/net/netfilter/ipset/ip_set_hash_net.c
index 0024053e409a..e6f8bc5771ca 100644
--- a/net/netfilter/ipset/ip_set_hash_net.c
+++ b/net/netfilter/ipset/ip_set_hash_net.c
@@ -125,6 +125,12 @@ nla_put_failure:
125#define HOST_MASK 32 125#define HOST_MASK 32
126#include <linux/netfilter/ipset/ip_set_ahash.h> 126#include <linux/netfilter/ipset/ip_set_ahash.h>
127 127
128static inline void
129hash_net4_data_next(struct ip_set_hash *h,
130 const struct hash_net4_elem *d)
131{
132}
133
128static int 134static int
129hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb, 135hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb,
130 enum ipset_adt adt, const struct ip_set_adt_opt *opt) 136 enum ipset_adt adt, const struct ip_set_adt_opt *opt)
@@ -146,7 +152,7 @@ hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb,
146 152
147static int 153static int
148hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], 154hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
149 enum ipset_adt adt, u32 *lineno, u32 flags) 155 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
150{ 156{
151 const struct ip_set_hash *h = set->data; 157 const struct ip_set_hash *h = set->data;
152 ipset_adtfn adtfn = set->variant->adt[adt]; 158 ipset_adtfn adtfn = set->variant->adt[adt];
@@ -290,6 +296,12 @@ nla_put_failure:
290#define HOST_MASK 128 296#define HOST_MASK 128
291#include <linux/netfilter/ipset/ip_set_ahash.h> 297#include <linux/netfilter/ipset/ip_set_ahash.h>
292 298
299static inline void
300hash_net6_data_next(struct ip_set_hash *h,
301 const struct hash_net6_elem *d)
302{
303}
304
293static int 305static int
294hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb, 306hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb,
295 enum ipset_adt adt, const struct ip_set_adt_opt *opt) 307 enum ipset_adt adt, const struct ip_set_adt_opt *opt)
@@ -311,7 +323,7 @@ hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb,
311 323
312static int 324static int
313hash_net6_uadt(struct ip_set *set, struct nlattr *tb[], 325hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
314 enum ipset_adt adt, u32 *lineno, u32 flags) 326 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
315{ 327{
316 const struct ip_set_hash *h = set->data; 328 const struct ip_set_hash *h = set->data;
317 ipset_adtfn adtfn = set->variant->adt[adt]; 329 ipset_adtfn adtfn = set->variant->adt[adt];
diff --git a/net/netfilter/ipset/ip_set_hash_netport.c b/net/netfilter/ipset/ip_set_hash_netport.c
index 7a2327b3407d..037b829178dc 100644
--- a/net/netfilter/ipset/ip_set_hash_netport.c
+++ b/net/netfilter/ipset/ip_set_hash_netport.c
@@ -137,6 +137,13 @@ nla_put_failure:
137#define HOST_MASK 32 137#define HOST_MASK 32
138#include <linux/netfilter/ipset/ip_set_ahash.h> 138#include <linux/netfilter/ipset/ip_set_ahash.h>
139 139
140static inline void
141hash_netport4_data_next(struct ip_set_hash *h,
142 const struct hash_netport4_elem *d)
143{
144 h->next.port = ntohs(d->port);
145}
146
140static int 147static int
141hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb, 148hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb,
142 enum ipset_adt adt, const struct ip_set_adt_opt *opt) 149 enum ipset_adt adt, const struct ip_set_adt_opt *opt)
@@ -163,7 +170,7 @@ hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb,
163 170
164static int 171static int
165hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], 172hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
166 enum ipset_adt adt, u32 *lineno, u32 flags) 173 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
167{ 174{
168 const struct ip_set_hash *h = set->data; 175 const struct ip_set_hash *h = set->data;
169 ipset_adtfn adtfn = set->variant->adt[adt]; 176 ipset_adtfn adtfn = set->variant->adt[adt];
@@ -225,6 +232,8 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
225 if (port > port_to) 232 if (port > port_to)
226 swap(port, port_to); 233 swap(port, port_to);
227 234
235 if (retried)
236 port = h->next.port;
228 for (; port <= port_to; port++) { 237 for (; port <= port_to; port++) {
229 data.port = htons(port); 238 data.port = htons(port);
230 ret = adtfn(set, &data, timeout, flags); 239 ret = adtfn(set, &data, timeout, flags);
@@ -350,6 +359,13 @@ nla_put_failure:
350#define HOST_MASK 128 359#define HOST_MASK 128
351#include <linux/netfilter/ipset/ip_set_ahash.h> 360#include <linux/netfilter/ipset/ip_set_ahash.h>
352 361
362static inline void
363hash_netport6_data_next(struct ip_set_hash *h,
364 const struct hash_netport6_elem *d)
365{
366 h->next.port = ntohs(d->port);
367}
368
353static int 369static int
354hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb, 370hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb,
355 enum ipset_adt adt, const struct ip_set_adt_opt *opt) 371 enum ipset_adt adt, const struct ip_set_adt_opt *opt)
@@ -376,7 +392,7 @@ hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb,
376 392
377static int 393static int
378hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[], 394hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
379 enum ipset_adt adt, u32 *lineno, u32 flags) 395 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
380{ 396{
381 const struct ip_set_hash *h = set->data; 397 const struct ip_set_hash *h = set->data;
382 ipset_adtfn adtfn = set->variant->adt[adt]; 398 ipset_adtfn adtfn = set->variant->adt[adt];
@@ -438,6 +454,8 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
438 if (port > port_to) 454 if (port > port_to)
439 swap(port, port_to); 455 swap(port, port_to);
440 456
457 if (retried)
458 port = h->next.port;
441 for (; port <= port_to; port++) { 459 for (; port <= port_to; port++) {
442 data.port = htons(port); 460 data.port = htons(port);
443 ret = adtfn(set, &data, timeout, flags); 461 ret = adtfn(set, &data, timeout, flags);
diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c
index f05e9eb863dc..74f0dcc30d98 100644
--- a/net/netfilter/ipset/ip_set_list_set.c
+++ b/net/netfilter/ipset/ip_set_list_set.c
@@ -218,7 +218,7 @@ cleanup_entries(struct list_set *map)
218 218
219static int 219static int
220list_set_uadt(struct ip_set *set, struct nlattr *tb[], 220list_set_uadt(struct ip_set *set, struct nlattr *tb[],
221 enum ipset_adt adt, u32 *lineno, u32 flags) 221 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
222{ 222{
223 struct list_set *map = set->data; 223 struct list_set *map = set->data;
224 bool with_timeout = with_timeout(map->timeout); 224 bool with_timeout = with_timeout(map->timeout);