aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2011-06-16 12:40:55 -0400
committerPatrick McHardy <kaber@trash.net>2011-06-16 12:40:55 -0400
commit5416219e5ca4504ea80d662fdda7337e52e86ee5 (patch)
treeb98c31ccbcb1d36fadac61e4862655749998af43
parent619c15171f6f58681013cdd439632505fd563ba6 (diff)
netfilter: ipset: timeout can be modified for already added elements
When an element to a set with timeout added, one can change the timeout by "readding" the element with the "-exist" flag. That means the timeout value is reset to the specified one (or to the default from the set specification if the "timeout n" option is not used). Example ipset add foo 1.2.3.4 timeout 10 ipset add foo 1.2.3.4 timeout 600 -exist 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.h3
-rw-r--r--include/linux/netfilter/ipset/ip_set_ahash.h15
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_ip.c20
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_ipmac.c21
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_port.c20
-rw-r--r--net/netfilter/ipset/ip_set_hash_ip.c10
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipport.c12
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipportip.c12
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipportnet.c12
-rw-r--r--net/netfilter/ipset/ip_set_hash_net.c8
-rw-r--r--net/netfilter/ipset/ip_set_hash_netport.c12
-rw-r--r--net/netfilter/ipset/ip_set_list_set.c92
12 files changed, 136 insertions, 101 deletions
diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h
index 5a262e3ae715..277b7fbc7fb2 100644
--- a/include/linux/netfilter/ipset/ip_set.h
+++ b/include/linux/netfilter/ipset/ip_set.h
@@ -214,7 +214,8 @@ enum ip_set_feature {
214 214
215struct ip_set; 215struct ip_set;
216 216
217typedef int (*ipset_adtfn)(struct ip_set *set, void *value, u32 timeout); 217typedef int (*ipset_adtfn)(struct ip_set *set, void *value,
218 u32 timeout, u32 flags);
218 219
219/* Set type, variant-specific part */ 220/* Set type, variant-specific part */
220struct ip_set_type_variant { 221struct ip_set_type_variant {
diff --git a/include/linux/netfilter/ipset/ip_set_ahash.h b/include/linux/netfilter/ipset/ip_set_ahash.h
index ac3c822eb39a..36cf4dc703bb 100644
--- a/include/linux/netfilter/ipset/ip_set_ahash.h
+++ b/include/linux/netfilter/ipset/ip_set_ahash.h
@@ -349,7 +349,7 @@ retry:
349/* Add an element to a hash and update the internal counters when succeeded, 349/* Add an element to a hash and update the internal counters when succeeded,
350 * otherwise report the proper error code. */ 350 * otherwise report the proper error code. */
351static int 351static int
352type_pf_add(struct ip_set *set, void *value, u32 timeout) 352type_pf_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
353{ 353{
354 struct ip_set_hash *h = set->data; 354 struct ip_set_hash *h = set->data;
355 struct htable *t; 355 struct htable *t;
@@ -388,7 +388,7 @@ out:
388 * and free up space if possible. 388 * and free up space if possible.
389 */ 389 */
390static int 390static int
391type_pf_del(struct ip_set *set, void *value, u32 timeout) 391type_pf_del(struct ip_set *set, void *value, u32 timeout, u32 flags)
392{ 392{
393 struct ip_set_hash *h = set->data; 393 struct ip_set_hash *h = set->data;
394 struct htable *t = h->table; 394 struct htable *t = h->table;
@@ -463,7 +463,7 @@ type_pf_test_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout)
463 463
464/* Test whether the element is added to the set */ 464/* Test whether the element is added to the set */
465static int 465static int
466type_pf_test(struct ip_set *set, void *value, u32 timeout) 466type_pf_test(struct ip_set *set, void *value, u32 timeout, u32 flags)
467{ 467{
468 struct ip_set_hash *h = set->data; 468 struct ip_set_hash *h = set->data;
469 struct htable *t = h->table; 469 struct htable *t = h->table;
@@ -776,7 +776,7 @@ retry:
776} 776}
777 777
778static int 778static int
779type_pf_tadd(struct ip_set *set, void *value, u32 timeout) 779type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
780{ 780{
781 struct ip_set_hash *h = set->data; 781 struct ip_set_hash *h = set->data;
782 struct htable *t = h->table; 782 struct htable *t = h->table;
@@ -784,6 +784,7 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout)
784 struct hbucket *n; 784 struct hbucket *n;
785 struct type_pf_elem *data; 785 struct type_pf_elem *data;
786 int ret = 0, i, j = AHASH_MAX_SIZE + 1; 786 int ret = 0, i, j = AHASH_MAX_SIZE + 1;
787 bool flag_exist = flags & IPSET_FLAG_EXIST;
787 u32 key; 788 u32 key;
788 789
789 if (h->elements >= h->maxelem) 790 if (h->elements >= h->maxelem)
@@ -799,7 +800,7 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout)
799 for (i = 0; i < n->pos; i++) { 800 for (i = 0; i < n->pos; i++) {
800 data = ahash_tdata(n, i); 801 data = ahash_tdata(n, i);
801 if (type_pf_data_equal(data, d)) { 802 if (type_pf_data_equal(data, d)) {
802 if (type_pf_data_expired(data)) 803 if (type_pf_data_expired(data) || flag_exist)
803 j = i; 804 j = i;
804 else { 805 else {
805 ret = -IPSET_ERR_EXIST; 806 ret = -IPSET_ERR_EXIST;
@@ -833,7 +834,7 @@ out:
833} 834}
834 835
835static int 836static int
836type_pf_tdel(struct ip_set *set, void *value, u32 timeout) 837type_pf_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
837{ 838{
838 struct ip_set_hash *h = set->data; 839 struct ip_set_hash *h = set->data;
839 struct htable *t = h->table; 840 struct htable *t = h->table;
@@ -905,7 +906,7 @@ type_pf_ttest_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout)
905#endif 906#endif
906 907
907static int 908static int
908type_pf_ttest(struct ip_set *set, void *value, u32 timeout) 909type_pf_ttest(struct ip_set *set, void *value, u32 timeout, u32 flags)
909{ 910{
910 struct ip_set_hash *h = set->data; 911 struct ip_set_hash *h = set->data;
911 struct htable *t = h->table; 912 struct htable *t = h->table;
diff --git a/net/netfilter/ipset/ip_set_bitmap_ip.c b/net/netfilter/ipset/ip_set_bitmap_ip.c
index ba2d16607f48..85b1cdf0a4b8 100644
--- a/net/netfilter/ipset/ip_set_bitmap_ip.c
+++ b/net/netfilter/ipset/ip_set_bitmap_ip.c
@@ -54,7 +54,7 @@ ip_to_id(const struct bitmap_ip *m, u32 ip)
54} 54}
55 55
56static int 56static int
57bitmap_ip_test(struct ip_set *set, void *value, u32 timeout) 57bitmap_ip_test(struct ip_set *set, void *value, u32 timeout, u32 flags)
58{ 58{
59 const struct bitmap_ip *map = set->data; 59 const struct bitmap_ip *map = set->data;
60 u16 id = *(u16 *)value; 60 u16 id = *(u16 *)value;
@@ -63,7 +63,7 @@ bitmap_ip_test(struct ip_set *set, void *value, u32 timeout)
63} 63}
64 64
65static int 65static int
66bitmap_ip_add(struct ip_set *set, void *value, u32 timeout) 66bitmap_ip_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
67{ 67{
68 struct bitmap_ip *map = set->data; 68 struct bitmap_ip *map = set->data;
69 u16 id = *(u16 *)value; 69 u16 id = *(u16 *)value;
@@ -75,7 +75,7 @@ bitmap_ip_add(struct ip_set *set, void *value, u32 timeout)
75} 75}
76 76
77static int 77static int
78bitmap_ip_del(struct ip_set *set, void *value, u32 timeout) 78bitmap_ip_del(struct ip_set *set, void *value, u32 timeout, u32 flags)
79{ 79{
80 struct bitmap_ip *map = set->data; 80 struct bitmap_ip *map = set->data;
81 u16 id = *(u16 *)value; 81 u16 id = *(u16 *)value;
@@ -131,7 +131,7 @@ nla_put_failure:
131/* Timeout variant */ 131/* Timeout variant */
132 132
133static int 133static int
134bitmap_ip_ttest(struct ip_set *set, void *value, u32 timeout) 134bitmap_ip_ttest(struct ip_set *set, void *value, u32 timeout, u32 flags)
135{ 135{
136 const struct bitmap_ip *map = set->data; 136 const struct bitmap_ip *map = set->data;
137 const unsigned long *members = map->members; 137 const unsigned long *members = map->members;
@@ -141,13 +141,13 @@ bitmap_ip_ttest(struct ip_set *set, void *value, u32 timeout)
141} 141}
142 142
143static int 143static int
144bitmap_ip_tadd(struct ip_set *set, void *value, u32 timeout) 144bitmap_ip_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
145{ 145{
146 struct bitmap_ip *map = set->data; 146 struct bitmap_ip *map = set->data;
147 unsigned long *members = map->members; 147 unsigned long *members = map->members;
148 u16 id = *(u16 *)value; 148 u16 id = *(u16 *)value;
149 149
150 if (ip_set_timeout_test(members[id])) 150 if (ip_set_timeout_test(members[id]) && !(flags & IPSET_FLAG_EXIST))
151 return -IPSET_ERR_EXIST; 151 return -IPSET_ERR_EXIST;
152 152
153 members[id] = ip_set_timeout_set(timeout); 153 members[id] = ip_set_timeout_set(timeout);
@@ -156,7 +156,7 @@ bitmap_ip_tadd(struct ip_set *set, void *value, u32 timeout)
156} 156}
157 157
158static int 158static int
159bitmap_ip_tdel(struct ip_set *set, void *value, u32 timeout) 159bitmap_ip_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
160{ 160{
161 struct bitmap_ip *map = set->data; 161 struct bitmap_ip *map = set->data;
162 unsigned long *members = map->members; 162 unsigned long *members = map->members;
@@ -231,7 +231,7 @@ bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb,
231 231
232 ip = ip_to_id(map, ip); 232 ip = ip_to_id(map, ip);
233 233
234 return adtfn(set, &ip, map->timeout); 234 return adtfn(set, &ip, map->timeout, flags);
235} 235}
236 236
237static int 237static int
@@ -266,7 +266,7 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[],
266 266
267 if (adt == IPSET_TEST) { 267 if (adt == IPSET_TEST) {
268 id = ip_to_id(map, ip); 268 id = ip_to_id(map, ip);
269 return adtfn(set, &id, timeout); 269 return adtfn(set, &id, timeout, flags);
270 } 270 }
271 271
272 if (tb[IPSET_ATTR_IP_TO]) { 272 if (tb[IPSET_ATTR_IP_TO]) {
@@ -293,7 +293,7 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[],
293 293
294 for (; !before(ip_to, ip); ip += map->hosts) { 294 for (; !before(ip_to, ip); ip += map->hosts) {
295 id = ip_to_id(map, ip); 295 id = ip_to_id(map, ip);
296 ret = adtfn(set, &id, timeout); 296 ret = adtfn(set, &id, timeout, flags);
297 297
298 if (ret && !ip_set_eexist(ret, flags)) 298 if (ret && !ip_set_eexist(ret, flags))
299 return ret; 299 return ret;
diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c
index a274300b6a56..913a461382e4 100644
--- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c
+++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c
@@ -99,7 +99,7 @@ bitmap_ipmac_exist(const struct ipmac_telem *elem)
99/* Base variant */ 99/* Base variant */
100 100
101static int 101static int
102bitmap_ipmac_test(struct ip_set *set, void *value, u32 timeout) 102bitmap_ipmac_test(struct ip_set *set, void *value, u32 timeout, u32 flags)
103{ 103{
104 const struct bitmap_ipmac *map = set->data; 104 const struct bitmap_ipmac *map = set->data;
105 const struct ipmac *data = value; 105 const struct ipmac *data = value;
@@ -117,7 +117,7 @@ bitmap_ipmac_test(struct ip_set *set, void *value, u32 timeout)
117} 117}
118 118
119static int 119static int
120bitmap_ipmac_add(struct ip_set *set, void *value, u32 timeout) 120bitmap_ipmac_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
121{ 121{
122 struct bitmap_ipmac *map = set->data; 122 struct bitmap_ipmac *map = set->data;
123 const struct ipmac *data = value; 123 const struct ipmac *data = value;
@@ -146,7 +146,7 @@ bitmap_ipmac_add(struct ip_set *set, void *value, u32 timeout)
146} 146}
147 147
148static int 148static int
149bitmap_ipmac_del(struct ip_set *set, void *value, u32 timeout) 149bitmap_ipmac_del(struct ip_set *set, void *value, u32 timeout, u32 flags)
150{ 150{
151 struct bitmap_ipmac *map = set->data; 151 struct bitmap_ipmac *map = set->data;
152 const struct ipmac *data = value; 152 const struct ipmac *data = value;
@@ -212,7 +212,7 @@ nla_put_failure:
212/* Timeout variant */ 212/* Timeout variant */
213 213
214static int 214static int
215bitmap_ipmac_ttest(struct ip_set *set, void *value, u32 timeout) 215bitmap_ipmac_ttest(struct ip_set *set, void *value, u32 timeout, u32 flags)
216{ 216{
217 const struct bitmap_ipmac *map = set->data; 217 const struct bitmap_ipmac *map = set->data;
218 const struct ipmac *data = value; 218 const struct ipmac *data = value;
@@ -231,15 +231,16 @@ bitmap_ipmac_ttest(struct ip_set *set, void *value, u32 timeout)
231} 231}
232 232
233static int 233static int
234bitmap_ipmac_tadd(struct ip_set *set, void *value, u32 timeout) 234bitmap_ipmac_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
235{ 235{
236 struct bitmap_ipmac *map = set->data; 236 struct bitmap_ipmac *map = set->data;
237 const struct ipmac *data = value; 237 const struct ipmac *data = value;
238 struct ipmac_telem *elem = bitmap_ipmac_elem(map, data->id); 238 struct ipmac_telem *elem = bitmap_ipmac_elem(map, data->id);
239 bool flag_exist = flags & IPSET_FLAG_EXIST;
239 240
240 switch (elem->match) { 241 switch (elem->match) {
241 case MAC_UNSET: 242 case MAC_UNSET:
242 if (!data->ether) 243 if (!(data->ether || flag_exist))
243 /* Already added without ethernet address */ 244 /* Already added without ethernet address */
244 return -IPSET_ERR_EXIST; 245 return -IPSET_ERR_EXIST;
245 /* Fill the MAC address and activate the timer */ 246 /* Fill the MAC address and activate the timer */
@@ -251,7 +252,7 @@ bitmap_ipmac_tadd(struct ip_set *set, void *value, u32 timeout)
251 elem->timeout = ip_set_timeout_set(timeout); 252 elem->timeout = ip_set_timeout_set(timeout);
252 break; 253 break;
253 case MAC_FILLED: 254 case MAC_FILLED:
254 if (!bitmap_expired(map, data->id)) 255 if (!(bitmap_expired(map, data->id) || flag_exist))
255 return -IPSET_ERR_EXIST; 256 return -IPSET_ERR_EXIST;
256 /* Fall through */ 257 /* Fall through */
257 case MAC_EMPTY: 258 case MAC_EMPTY:
@@ -273,7 +274,7 @@ bitmap_ipmac_tadd(struct ip_set *set, void *value, u32 timeout)
273} 274}
274 275
275static int 276static int
276bitmap_ipmac_tdel(struct ip_set *set, void *value, u32 timeout) 277bitmap_ipmac_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
277{ 278{
278 struct bitmap_ipmac *map = set->data; 279 struct bitmap_ipmac *map = set->data;
279 const struct ipmac *data = value; 280 const struct ipmac *data = value;
@@ -359,7 +360,7 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
359 data.id -= map->first_ip; 360 data.id -= map->first_ip;
360 data.ether = eth_hdr(skb)->h_source; 361 data.ether = eth_hdr(skb)->h_source;
361 362
362 return adtfn(set, &data, map->timeout); 363 return adtfn(set, &data, map->timeout, flags);
363} 364}
364 365
365static int 366static int
@@ -399,7 +400,7 @@ bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[],
399 400
400 data.id -= map->first_ip; 401 data.id -= map->first_ip;
401 402
402 ret = adtfn(set, &data, timeout); 403 ret = adtfn(set, &data, timeout, flags);
403 404
404 return ip_set_eexist(ret, flags) ? 0 : ret; 405 return ip_set_eexist(ret, flags) ? 0 : ret;
405} 406}
diff --git a/net/netfilter/ipset/ip_set_bitmap_port.c b/net/netfilter/ipset/ip_set_bitmap_port.c
index 6b38eb8f6ed8..a3935eef76fc 100644
--- a/net/netfilter/ipset/ip_set_bitmap_port.c
+++ b/net/netfilter/ipset/ip_set_bitmap_port.c
@@ -40,7 +40,7 @@ struct bitmap_port {
40/* Base variant */ 40/* Base variant */
41 41
42static int 42static int
43bitmap_port_test(struct ip_set *set, void *value, u32 timeout) 43bitmap_port_test(struct ip_set *set, void *value, u32 timeout, u32 flags)
44{ 44{
45 const struct bitmap_port *map = set->data; 45 const struct bitmap_port *map = set->data;
46 u16 id = *(u16 *)value; 46 u16 id = *(u16 *)value;
@@ -49,7 +49,7 @@ bitmap_port_test(struct ip_set *set, void *value, u32 timeout)
49} 49}
50 50
51static int 51static int
52bitmap_port_add(struct ip_set *set, void *value, u32 timeout) 52bitmap_port_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
53{ 53{
54 struct bitmap_port *map = set->data; 54 struct bitmap_port *map = set->data;
55 u16 id = *(u16 *)value; 55 u16 id = *(u16 *)value;
@@ -61,7 +61,7 @@ bitmap_port_add(struct ip_set *set, void *value, u32 timeout)
61} 61}
62 62
63static int 63static int
64bitmap_port_del(struct ip_set *set, void *value, u32 timeout) 64bitmap_port_del(struct ip_set *set, void *value, u32 timeout, u32 flags)
65{ 65{
66 struct bitmap_port *map = set->data; 66 struct bitmap_port *map = set->data;
67 u16 id = *(u16 *)value; 67 u16 id = *(u16 *)value;
@@ -119,7 +119,7 @@ nla_put_failure:
119/* Timeout variant */ 119/* Timeout variant */
120 120
121static int 121static int
122bitmap_port_ttest(struct ip_set *set, void *value, u32 timeout) 122bitmap_port_ttest(struct ip_set *set, void *value, u32 timeout, u32 flags)
123{ 123{
124 const struct bitmap_port *map = set->data; 124 const struct bitmap_port *map = set->data;
125 const unsigned long *members = map->members; 125 const unsigned long *members = map->members;
@@ -129,13 +129,13 @@ bitmap_port_ttest(struct ip_set *set, void *value, u32 timeout)
129} 129}
130 130
131static int 131static int
132bitmap_port_tadd(struct ip_set *set, void *value, u32 timeout) 132bitmap_port_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
133{ 133{
134 struct bitmap_port *map = set->data; 134 struct bitmap_port *map = set->data;
135 unsigned long *members = map->members; 135 unsigned long *members = map->members;
136 u16 id = *(u16 *)value; 136 u16 id = *(u16 *)value;
137 137
138 if (ip_set_timeout_test(members[id])) 138 if (ip_set_timeout_test(members[id]) && !(flags & IPSET_FLAG_EXIST))
139 return -IPSET_ERR_EXIST; 139 return -IPSET_ERR_EXIST;
140 140
141 members[id] = ip_set_timeout_set(timeout); 141 members[id] = ip_set_timeout_set(timeout);
@@ -144,7 +144,7 @@ bitmap_port_tadd(struct ip_set *set, void *value, u32 timeout)
144} 144}
145 145
146static int 146static int
147bitmap_port_tdel(struct ip_set *set, void *value, u32 timeout) 147bitmap_port_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
148{ 148{
149 struct bitmap_port *map = set->data; 149 struct bitmap_port *map = set->data;
150 unsigned long *members = map->members; 150 unsigned long *members = map->members;
@@ -225,7 +225,7 @@ bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,
225 225
226 port -= map->first_port; 226 port -= map->first_port;
227 227
228 return adtfn(set, &port, map->timeout); 228 return adtfn(set, &port, map->timeout, flags);
229} 229}
230 230
231static int 231static int
@@ -259,7 +259,7 @@ bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[],
259 259
260 if (adt == IPSET_TEST) { 260 if (adt == IPSET_TEST) {
261 id = port - map->first_port; 261 id = port - map->first_port;
262 return adtfn(set, &id, timeout); 262 return adtfn(set, &id, timeout, flags);
263 } 263 }
264 264
265 if (tb[IPSET_ATTR_PORT_TO]) { 265 if (tb[IPSET_ATTR_PORT_TO]) {
@@ -277,7 +277,7 @@ bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[],
277 277
278 for (; port <= port_to; port++) { 278 for (; port <= port_to; port++) {
279 id = port - map->first_port; 279 id = port - map->first_port;
280 ret = adtfn(set, &id, timeout); 280 ret = adtfn(set, &id, timeout, flags);
281 281
282 if (ret && !ip_set_eexist(ret, flags)) 282 if (ret && !ip_set_eexist(ret, flags))
283 return ret; 283 return ret;
diff --git a/net/netfilter/ipset/ip_set_hash_ip.c b/net/netfilter/ipset/ip_set_hash_ip.c
index 43bcce200129..368302001120 100644
--- a/net/netfilter/ipset/ip_set_hash_ip.c
+++ b/net/netfilter/ipset/ip_set_hash_ip.c
@@ -121,7 +121,7 @@ hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
121 if (ip == 0) 121 if (ip == 0)
122 return -EINVAL; 122 return -EINVAL;
123 123
124 return adtfn(set, &ip, h->timeout); 124 return adtfn(set, &ip, h->timeout, flags);
125} 125}
126 126
127static int 127static int
@@ -157,7 +157,7 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
157 nip = htonl(ip); 157 nip = htonl(ip);
158 if (nip == 0) 158 if (nip == 0)
159 return -IPSET_ERR_HASH_ELEM; 159 return -IPSET_ERR_HASH_ELEM;
160 return adtfn(set, &nip, timeout); 160 return adtfn(set, &nip, timeout, flags);
161 } 161 }
162 162
163 if (tb[IPSET_ATTR_IP_TO]) { 163 if (tb[IPSET_ATTR_IP_TO]) {
@@ -182,7 +182,7 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
182 nip = htonl(ip); 182 nip = htonl(ip);
183 if (nip == 0) 183 if (nip == 0)
184 return -IPSET_ERR_HASH_ELEM; 184 return -IPSET_ERR_HASH_ELEM;
185 ret = adtfn(set, &nip, timeout); 185 ret = adtfn(set, &nip, timeout, flags);
186 186
187 if (ret && !ip_set_eexist(ret, flags)) 187 if (ret && !ip_set_eexist(ret, flags))
188 return ret; 188 return ret;
@@ -294,7 +294,7 @@ hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb,
294 if (ipv6_addr_any(&ip.in6)) 294 if (ipv6_addr_any(&ip.in6))
295 return -EINVAL; 295 return -EINVAL;
296 296
297 return adtfn(set, &ip, h->timeout); 297 return adtfn(set, &ip, h->timeout, flags);
298} 298}
299 299
300static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] = { 300static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
@@ -336,7 +336,7 @@ hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[],
336 timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); 336 timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
337 } 337 }
338 338
339 ret = adtfn(set, &ip, timeout); 339 ret = adtfn(set, &ip, timeout, flags);
340 340
341 return ip_set_eexist(ret, flags) ? 0 : ret; 341 return ip_set_eexist(ret, flags) ? 0 : ret;
342} 342}
diff --git a/net/netfilter/ipset/ip_set_hash_ipport.c b/net/netfilter/ipset/ip_set_hash_ipport.c
index 14281b6b8074..65c2ff4b27aa 100644
--- a/net/netfilter/ipset/ip_set_hash_ipport.c
+++ b/net/netfilter/ipset/ip_set_hash_ipport.c
@@ -138,7 +138,7 @@ hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb,
138 138
139 ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip); 139 ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
140 140
141 return adtfn(set, &data, h->timeout); 141 return adtfn(set, &data, h->timeout, flags);
142} 142}
143 143
144static int 144static int
@@ -192,7 +192,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
192 if (adt == IPSET_TEST || 192 if (adt == IPSET_TEST ||
193 !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] || 193 !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
194 tb[IPSET_ATTR_PORT_TO])) { 194 tb[IPSET_ATTR_PORT_TO])) {
195 ret = adtfn(set, &data, timeout); 195 ret = adtfn(set, &data, timeout, flags);
196 return ip_set_eexist(ret, flags) ? 0 : ret; 196 return ip_set_eexist(ret, flags) ? 0 : ret;
197 } 197 }
198 198
@@ -224,7 +224,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
224 for (p = port; p <= port_to; p++) { 224 for (p = port; p <= port_to; p++) {
225 data.ip = htonl(ip); 225 data.ip = htonl(ip);
226 data.port = htons(p); 226 data.port = htons(p);
227 ret = adtfn(set, &data, timeout); 227 ret = adtfn(set, &data, timeout, flags);
228 228
229 if (ret && !ip_set_eexist(ret, flags)) 229 if (ret && !ip_set_eexist(ret, flags))
230 return ret; 230 return ret;
@@ -342,7 +342,7 @@ hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb,
342 342
343 ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6); 343 ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
344 344
345 return adtfn(set, &data, h->timeout); 345 return adtfn(set, &data, h->timeout, flags);
346} 346}
347 347
348static int 348static int
@@ -396,7 +396,7 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
396 } 396 }
397 397
398 if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) { 398 if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
399 ret = adtfn(set, &data, timeout); 399 ret = adtfn(set, &data, timeout, flags);
400 return ip_set_eexist(ret, flags) ? 0 : ret; 400 return ip_set_eexist(ret, flags) ? 0 : ret;
401 } 401 }
402 402
@@ -407,7 +407,7 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
407 407
408 for (; port <= port_to; port++) { 408 for (; port <= port_to; port++) {
409 data.port = htons(port); 409 data.port = htons(port);
410 ret = adtfn(set, &data, timeout); 410 ret = adtfn(set, &data, timeout, flags);
411 411
412 if (ret && !ip_set_eexist(ret, flags)) 412 if (ret && !ip_set_eexist(ret, flags))
413 return ret; 413 return ret;
diff --git a/net/netfilter/ipset/ip_set_hash_ipportip.c b/net/netfilter/ipset/ip_set_hash_ipportip.c
index 401c8a2531db..670e5e4a1232 100644
--- a/net/netfilter/ipset/ip_set_hash_ipportip.c
+++ b/net/netfilter/ipset/ip_set_hash_ipportip.c
@@ -142,7 +142,7 @@ hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb,
142 ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip); 142 ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
143 ip4addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2); 143 ip4addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2);
144 144
145 return adtfn(set, &data, h->timeout); 145 return adtfn(set, &data, h->timeout, flags);
146} 146}
147 147
148static int 148static int
@@ -200,7 +200,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
200 if (adt == IPSET_TEST || 200 if (adt == IPSET_TEST ||
201 !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] || 201 !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
202 tb[IPSET_ATTR_PORT_TO])) { 202 tb[IPSET_ATTR_PORT_TO])) {
203 ret = adtfn(set, &data, timeout); 203 ret = adtfn(set, &data, timeout, flags);
204 return ip_set_eexist(ret, flags) ? 0 : ret; 204 return ip_set_eexist(ret, flags) ? 0 : ret;
205 } 205 }
206 206
@@ -232,7 +232,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
232 for (p = port; p <= port_to; p++) { 232 for (p = port; p <= port_to; p++) {
233 data.ip = htonl(ip); 233 data.ip = htonl(ip);
234 data.port = htons(p); 234 data.port = htons(p);
235 ret = adtfn(set, &data, timeout); 235 ret = adtfn(set, &data, timeout, flags);
236 236
237 if (ret && !ip_set_eexist(ret, flags)) 237 if (ret && !ip_set_eexist(ret, flags))
238 return ret; 238 return ret;
@@ -356,7 +356,7 @@ hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb,
356 ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6); 356 ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
357 ip6addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2.in6); 357 ip6addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
358 358
359 return adtfn(set, &data, h->timeout); 359 return adtfn(set, &data, h->timeout, flags);
360} 360}
361 361
362static int 362static int
@@ -414,7 +414,7 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
414 } 414 }
415 415
416 if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) { 416 if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
417 ret = adtfn(set, &data, timeout); 417 ret = adtfn(set, &data, timeout, flags);
418 return ip_set_eexist(ret, flags) ? 0 : ret; 418 return ip_set_eexist(ret, flags) ? 0 : ret;
419 } 419 }
420 420
@@ -425,7 +425,7 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
425 425
426 for (; port <= port_to; port++) { 426 for (; port <= port_to; port++) {
427 data.port = htons(port); 427 data.port = htons(port);
428 ret = adtfn(set, &data, timeout); 428 ret = adtfn(set, &data, timeout, flags);
429 429
430 if (ret && !ip_set_eexist(ret, flags)) 430 if (ret && !ip_set_eexist(ret, flags))
431 return ret; 431 return ret;
diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c
index 4743e5402522..4bb365c9f3db 100644
--- a/net/netfilter/ipset/ip_set_hash_ipportnet.c
+++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c
@@ -162,7 +162,7 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
162 ip4addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2); 162 ip4addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2);
163 data.ip2 &= ip_set_netmask(data.cidr); 163 data.ip2 &= ip_set_netmask(data.cidr);
164 164
165 return adtfn(set, &data, h->timeout); 165 return adtfn(set, &data, h->timeout, flags);
166} 166}
167 167
168static int 168static int
@@ -228,7 +228,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
228 if (adt == IPSET_TEST || 228 if (adt == IPSET_TEST ||
229 !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] || 229 !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
230 tb[IPSET_ATTR_PORT_TO])) { 230 tb[IPSET_ATTR_PORT_TO])) {
231 ret = adtfn(set, &data, timeout); 231 ret = adtfn(set, &data, timeout, flags);
232 return ip_set_eexist(ret, flags) ? 0 : ret; 232 return ip_set_eexist(ret, flags) ? 0 : ret;
233 } 233 }
234 234
@@ -260,7 +260,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
260 for (p = port; p <= port_to; p++) { 260 for (p = port; p <= port_to; p++) {
261 data.ip = htonl(ip); 261 data.ip = htonl(ip);
262 data.port = htons(p); 262 data.port = htons(p);
263 ret = adtfn(set, &data, timeout); 263 ret = adtfn(set, &data, timeout, flags);
264 264
265 if (ret && !ip_set_eexist(ret, flags)) 265 if (ret && !ip_set_eexist(ret, flags))
266 return ret; 266 return ret;
@@ -410,7 +410,7 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
410 ip6addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2.in6); 410 ip6addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
411 ip6_netmask(&data.ip2, data.cidr); 411 ip6_netmask(&data.ip2, data.cidr);
412 412
413 return adtfn(set, &data, h->timeout); 413 return adtfn(set, &data, h->timeout, flags);
414} 414}
415 415
416static int 416static int
@@ -476,7 +476,7 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
476 } 476 }
477 477
478 if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) { 478 if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
479 ret = adtfn(set, &data, timeout); 479 ret = adtfn(set, &data, timeout, flags);
480 return ip_set_eexist(ret, flags) ? 0 : ret; 480 return ip_set_eexist(ret, flags) ? 0 : ret;
481 } 481 }
482 482
@@ -487,7 +487,7 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
487 487
488 for (; port <= port_to; port++) { 488 for (; port <= port_to; port++) {
489 data.port = htons(port); 489 data.port = htons(port);
490 ret = adtfn(set, &data, timeout); 490 ret = adtfn(set, &data, timeout, flags);
491 491
492 if (ret && !ip_set_eexist(ret, flags)) 492 if (ret && !ip_set_eexist(ret, flags))
493 return ret; 493 return ret;
diff --git a/net/netfilter/ipset/ip_set_hash_net.c b/net/netfilter/ipset/ip_set_hash_net.c
index c4db202b7da4..440b38f9fe3b 100644
--- a/net/netfilter/ipset/ip_set_hash_net.c
+++ b/net/netfilter/ipset/ip_set_hash_net.c
@@ -141,7 +141,7 @@ hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb,
141 ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip); 141 ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
142 data.ip &= ip_set_netmask(data.cidr); 142 data.ip &= ip_set_netmask(data.cidr);
143 143
144 return adtfn(set, &data, h->timeout); 144 return adtfn(set, &data, h->timeout, flags);
145} 145}
146 146
147static int 147static int
@@ -179,7 +179,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
179 timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); 179 timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
180 } 180 }
181 181
182 ret = adtfn(set, &data, timeout); 182 ret = adtfn(set, &data, timeout, flags);
183 183
184 return ip_set_eexist(ret, flags) ? 0 : ret; 184 return ip_set_eexist(ret, flags) ? 0 : ret;
185} 185}
@@ -306,7 +306,7 @@ hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb,
306 ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6); 306 ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
307 ip6_netmask(&data.ip, data.cidr); 307 ip6_netmask(&data.ip, data.cidr);
308 308
309 return adtfn(set, &data, h->timeout); 309 return adtfn(set, &data, h->timeout, flags);
310} 310}
311 311
312static int 312static int
@@ -344,7 +344,7 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
344 timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); 344 timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
345 } 345 }
346 346
347 ret = adtfn(set, &data, timeout); 347 ret = adtfn(set, &data, timeout, flags);
348 348
349 return ip_set_eexist(ret, flags) ? 0 : ret; 349 return ip_set_eexist(ret, flags) ? 0 : ret;
350} 350}
diff --git a/net/netfilter/ipset/ip_set_hash_netport.c b/net/netfilter/ipset/ip_set_hash_netport.c
index d2a40362dd3a..2d31291ba83e 100644
--- a/net/netfilter/ipset/ip_set_hash_netport.c
+++ b/net/netfilter/ipset/ip_set_hash_netport.c
@@ -158,7 +158,7 @@ hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb,
158 ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip); 158 ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
159 data.ip &= ip_set_netmask(data.cidr); 159 data.ip &= ip_set_netmask(data.cidr);
160 160
161 return adtfn(set, &data, h->timeout); 161 return adtfn(set, &data, h->timeout, flags);
162} 162}
163 163
164static int 164static int
@@ -216,7 +216,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
216 } 216 }
217 217
218 if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) { 218 if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
219 ret = adtfn(set, &data, timeout); 219 ret = adtfn(set, &data, timeout, flags);
220 return ip_set_eexist(ret, flags) ? 0 : ret; 220 return ip_set_eexist(ret, flags) ? 0 : ret;
221 } 221 }
222 222
@@ -227,7 +227,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
227 227
228 for (; port <= port_to; port++) { 228 for (; port <= port_to; port++) {
229 data.port = htons(port); 229 data.port = htons(port);
230 ret = adtfn(set, &data, timeout); 230 ret = adtfn(set, &data, timeout, flags);
231 231
232 if (ret && !ip_set_eexist(ret, flags)) 232 if (ret && !ip_set_eexist(ret, flags))
233 return ret; 233 return ret;
@@ -371,7 +371,7 @@ hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb,
371 ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6); 371 ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
372 ip6_netmask(&data.ip, data.cidr); 372 ip6_netmask(&data.ip, data.cidr);
373 373
374 return adtfn(set, &data, h->timeout); 374 return adtfn(set, &data, h->timeout, flags);
375} 375}
376 376
377static int 377static int
@@ -429,7 +429,7 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
429 } 429 }
430 430
431 if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) { 431 if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
432 ret = adtfn(set, &data, timeout); 432 ret = adtfn(set, &data, timeout, flags);
433 return ip_set_eexist(ret, flags) ? 0 : ret; 433 return ip_set_eexist(ret, flags) ? 0 : ret;
434 } 434 }
435 435
@@ -440,7 +440,7 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
440 440
441 for (; port <= port_to; port++) { 441 for (; port <= port_to; port++) {
442 data.port = htons(port); 442 data.port = htons(port);
443 ret = adtfn(set, &data, timeout); 443 ret = adtfn(set, &data, timeout, flags);
444 444
445 if (ret && !ip_set_eexist(ret, flags)) 445 if (ret && !ip_set_eexist(ret, flags))
446 return ret; 446 return ret;
diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c
index e9159e99fc4b..a0290ffad355 100644
--- a/net/netfilter/ipset/ip_set_list_set.c
+++ b/net/netfilter/ipset/ip_set_list_set.c
@@ -109,15 +109,28 @@ list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
109} 109}
110 110
111static bool 111static bool
112next_id_eq(const struct list_set *map, u32 i, ip_set_id_t id) 112id_eq(const struct list_set *map, u32 i, ip_set_id_t id)
113{ 113{
114 const struct set_elem *elem; 114 const struct set_elem *elem;
115 115
116 if (i + 1 < map->size) { 116 if (i < map->size) {
117 elem = list_set_elem(map, i + 1); 117 elem = list_set_elem(map, i);
118 return elem->id == id;
119 }
120
121 return 0;
122}
123
124static bool
125id_eq_timeout(const struct list_set *map, u32 i, ip_set_id_t id)
126{
127 const struct set_elem *elem;
128
129 if (i < map->size) {
130 elem = list_set_elem(map, i);
118 return !!(elem->id == id && 131 return !!(elem->id == id &&
119 !(with_timeout(map->timeout) && 132 !(with_timeout(map->timeout) &&
120 list_set_expired(map, i + 1))); 133 list_set_expired(map, i)));
121 } 134 }
122 135
123 return 0; 136 return 0;
@@ -190,12 +203,26 @@ list_set_del(struct list_set *map, u32 i)
190 return 0; 203 return 0;
191} 204}
192 205
206static void
207cleanup_entries(struct list_set *map)
208{
209 struct set_telem *e;
210 u32 i;
211
212 for (i = 0; i < map->size; i++) {
213 e = list_set_telem(map, i);
214 if (e->id != IPSET_INVALID_ID && list_set_expired(map, i))
215 list_set_del(map, i);
216 }
217}
218
193static int 219static int
194list_set_uadt(struct ip_set *set, struct nlattr *tb[], 220list_set_uadt(struct ip_set *set, struct nlattr *tb[],
195 enum ipset_adt adt, u32 *lineno, u32 flags) 221 enum ipset_adt adt, u32 *lineno, u32 flags)
196{ 222{
197 struct list_set *map = set->data; 223 struct list_set *map = set->data;
198 bool with_timeout = with_timeout(map->timeout); 224 bool with_timeout = with_timeout(map->timeout);
225 bool flag_exist = flags & IPSET_FLAG_EXIST;
199 int before = 0; 226 int before = 0;
200 u32 timeout = map->timeout; 227 u32 timeout = map->timeout;
201 ip_set_id_t id, refid = IPSET_INVALID_ID; 228 ip_set_id_t id, refid = IPSET_INVALID_ID;
@@ -248,6 +275,8 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
248 } 275 }
249 timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); 276 timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
250 } 277 }
278 if (with_timeout && adt != IPSET_TEST)
279 cleanup_entries(map);
251 280
252 switch (adt) { 281 switch (adt) {
253 case IPSET_TEST: 282 case IPSET_TEST:
@@ -259,22 +288,37 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
259 else if (with_timeout && list_set_expired(map, i)) 288 else if (with_timeout && list_set_expired(map, i))
260 continue; 289 continue;
261 else if (before > 0 && elem->id == id) 290 else if (before > 0 && elem->id == id)
262 ret = next_id_eq(map, i, refid); 291 ret = id_eq_timeout(map, i + 1, refid);
263 else if (before < 0 && elem->id == refid) 292 else if (before < 0 && elem->id == refid)
264 ret = next_id_eq(map, i, id); 293 ret = id_eq_timeout(map, i + 1, id);
265 else if (before == 0 && elem->id == id) 294 else if (before == 0 && elem->id == id)
266 ret = 1; 295 ret = 1;
267 } 296 }
268 break; 297 break;
269 case IPSET_ADD: 298 case IPSET_ADD:
270 for (i = 0; i < map->size && !ret; i++) { 299 for (i = 0; i < map->size; i++) {
271 elem = list_set_elem(map, i); 300 elem = list_set_elem(map, i);
272 if (elem->id == id && 301 if (elem->id != id)
273 !(with_timeout && list_set_expired(map, i))) 302 continue;
303 if (!(with_timeout && flag_exist)) {
274 ret = -IPSET_ERR_EXIST; 304 ret = -IPSET_ERR_EXIST;
305 goto finish;
306 } else {
307 struct set_telem *e = list_set_telem(map, i);
308
309 if ((before > 1 &&
310 !id_eq(map, i + 1, refid)) ||
311 (before < 0 &&
312 (i == 0 || !id_eq(map, i - 1, refid)))) {
313 ret = -IPSET_ERR_EXIST;
314 goto finish;
315 }
316 e->timeout = ip_set_timeout_set(timeout);
317 ip_set_put_byindex(id);
318 ret = 0;
319 goto finish;
320 }
275 } 321 }
276 if (ret == -IPSET_ERR_EXIST)
277 break;
278 ret = -IPSET_ERR_LIST_FULL; 322 ret = -IPSET_ERR_LIST_FULL;
279 for (i = 0; i < map->size && ret == -IPSET_ERR_LIST_FULL; i++) { 323 for (i = 0; i < map->size && ret == -IPSET_ERR_LIST_FULL; i++) {
280 elem = list_set_elem(map, i); 324 elem = list_set_elem(map, i);
@@ -283,9 +327,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
283 : list_set_add(map, i, id, timeout); 327 : list_set_add(map, i, id, timeout);
284 else if (elem->id != refid) 328 else if (elem->id != refid)
285 continue; 329 continue;
286 else if (with_timeout && list_set_expired(map, i)) 330 else if (before > 0)
287 ret = -IPSET_ERR_REF_EXIST;
288 else if (before)
289 ret = list_set_add(map, i, id, timeout); 331 ret = list_set_add(map, i, id, timeout);
290 else if (i + 1 < map->size) 332 else if (i + 1 < map->size)
291 ret = list_set_add(map, i + 1, id, timeout); 333 ret = list_set_add(map, i + 1, id, timeout);
@@ -299,16 +341,12 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
299 ret = before != 0 ? -IPSET_ERR_REF_EXIST 341 ret = before != 0 ? -IPSET_ERR_REF_EXIST
300 : -IPSET_ERR_EXIST; 342 : -IPSET_ERR_EXIST;
301 break; 343 break;
302 } else if (with_timeout && list_set_expired(map, i)) 344 } else if (elem->id == id &&
303 continue; 345 (before == 0 ||
304 else if (elem->id == id && 346 (before > 0 && id_eq(map, i + 1, refid))))
305 (before == 0 ||
306 (before > 0 &&
307 next_id_eq(map, i, refid))))
308 ret = list_set_del(map, i); 347 ret = list_set_del(map, i);
309 else if (before < 0 && 348 else if (elem->id == refid &&
310 elem->id == refid && 349 before < 0 && id_eq(map, i + 1, id))
311 next_id_eq(map, i, id))
312 ret = list_set_del(map, i + 1); 350 ret = list_set_del(map, i + 1);
313 } 351 }
314 break; 352 break;
@@ -454,15 +492,9 @@ list_set_gc(unsigned long ul_set)
454{ 492{
455 struct ip_set *set = (struct ip_set *) ul_set; 493 struct ip_set *set = (struct ip_set *) ul_set;
456 struct list_set *map = set->data; 494 struct list_set *map = set->data;
457 struct set_telem *e;
458 u32 i;
459 495
460 write_lock_bh(&set->lock); 496 write_lock_bh(&set->lock);
461 for (i = 0; i < map->size; i++) { 497 cleanup_entries(map);
462 e = list_set_telem(map, i);
463 if (e->id != IPSET_INVALID_ID && list_set_expired(map, i))
464 list_set_del(map, i);
465 }
466 write_unlock_bh(&set->lock); 498 write_unlock_bh(&set->lock);
467 499
468 map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ; 500 map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;