diff options
-rw-r--r-- | include/linux/netfilter/ipset/ip_set.h | 2 | ||||
-rw-r--r-- | include/linux/netfilter/ipset/ip_set_ahash.h | 22 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_bitmap_ip.c | 2 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_bitmap_ipmac.c | 2 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_bitmap_port.c | 2 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_core.c | 11 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_ip.c | 17 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_ipport.c | 31 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_ipportip.c | 31 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_ipportnet.c | 31 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_net.c | 16 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_netport.c | 22 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_list_set.c | 2 |
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 | ||
356 | static inline void | ||
357 | type_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. */ |
351 | static int | 361 | static 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); |
590 | static int | 603 | static int |
591 | type_pf_uadt(struct ip_set *set, struct nlattr *tb[], | 604 | type_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 | ||
594 | static const struct ip_set_type_variant type_pf_variant = { | 607 | static 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 | ||
237 | static int | 237 | static int |
238 | bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[], | 238 | bitmap_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 | ||
366 | static int | 366 | static int |
367 | bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[], | 367 | bitmap_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 | ||
232 | static int | 232 | static int |
233 | bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[], | 233 | bitmap_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 | ||
111 | static inline void | ||
112 | hash_ip4_data_next(struct ip_set_hash *h, const struct hash_ip4_elem *d) | ||
113 | { | ||
114 | h->next.ip = ntohl(d->ip); | ||
115 | } | ||
116 | |||
111 | static int | 117 | static int |
112 | hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb, | 118 | hash_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 | ||
127 | static int | 133 | static int |
128 | hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], | 134 | hash_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 | ||
292 | static inline void | ||
293 | hash_ip6_data_next(struct ip_set_hash *h, const struct hash_ip6_elem *d) | ||
294 | { | ||
295 | } | ||
296 | |||
284 | static int | 297 | static int |
285 | hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb, | 298 | hash_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 | ||
306 | static int | 319 | static int |
307 | hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[], | 320 | hash_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 | ||
127 | static inline void | ||
128 | hash_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 | |||
127 | static int | 135 | static int |
128 | hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb, | 136 | hash_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 | ||
144 | static int | 152 | static int |
145 | hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], | 153 | hash_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 | ||
343 | static inline void | ||
344 | hash_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 | |||
331 | static int | 350 | static int |
332 | hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb, | 351 | hash_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 | ||
348 | static int | 367 | static int |
349 | hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[], | 368 | hash_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 | ||
130 | static inline void | ||
131 | hash_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 | |||
130 | static int | 138 | static int |
131 | hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb, | 139 | hash_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 | ||
148 | static int | 156 | static int |
149 | hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], | 157 | hash_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 | ||
356 | static inline void | ||
357 | hash_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 | |||
344 | static int | 363 | static int |
345 | hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb, | 364 | hash_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 | ||
362 | static int | 381 | static int |
363 | hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[], | 382 | hash_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 | ||
143 | static inline void | ||
144 | hash_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 | |||
143 | static int | 151 | static int |
144 | hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb, | 152 | hash_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 | ||
168 | static int | 176 | static int |
169 | hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], | 177 | hash_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 | ||
403 | static inline void | ||
404 | hash_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 | |||
391 | static int | 410 | static int |
392 | hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb, | 411 | hash_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 | ||
416 | static int | 435 | static int |
417 | hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[], | 436 | hash_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 | ||
128 | static inline void | ||
129 | hash_net4_data_next(struct ip_set_hash *h, | ||
130 | const struct hash_net4_elem *d) | ||
131 | { | ||
132 | } | ||
133 | |||
128 | static int | 134 | static int |
129 | hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb, | 135 | hash_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 | ||
147 | static int | 153 | static int |
148 | hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], | 154 | hash_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 | ||
299 | static inline void | ||
300 | hash_net6_data_next(struct ip_set_hash *h, | ||
301 | const struct hash_net6_elem *d) | ||
302 | { | ||
303 | } | ||
304 | |||
293 | static int | 305 | static int |
294 | hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb, | 306 | hash_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 | ||
312 | static int | 324 | static int |
313 | hash_net6_uadt(struct ip_set *set, struct nlattr *tb[], | 325 | hash_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 | ||
140 | static inline void | ||
141 | hash_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 | |||
140 | static int | 147 | static int |
141 | hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb, | 148 | hash_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 | ||
164 | static int | 171 | static int |
165 | hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], | 172 | hash_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 | ||
362 | static inline void | ||
363 | hash_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 | |||
353 | static int | 369 | static int |
354 | hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb, | 370 | hash_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 | ||
377 | static int | 393 | static int |
378 | hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[], | 394 | hash_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 | ||
219 | static int | 219 | static int |
220 | list_set_uadt(struct ip_set *set, struct nlattr *tb[], | 220 | list_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); |