aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/ipset/ip_set_list_set.c547
1 files changed, 301 insertions, 246 deletions
diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c
index 09c744aa8982..919eefe713d5 100644
--- a/net/netfilter/ipset/ip_set_list_set.c
+++ b/net/netfilter/ipset/ip_set_list_set.c
@@ -1,4 +1,4 @@
1/* Copyright (C) 2008-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> 1/* Copyright (C) 2008-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
2 * 2 *
3 * This program is free software; you can redistribute it and/or modify 3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 as 4 * it under the terms of the GNU General Public License version 2 as
@@ -13,7 +13,6 @@
13#include <linux/errno.h> 13#include <linux/errno.h>
14 14
15#include <linux/netfilter/ipset/ip_set.h> 15#include <linux/netfilter/ipset/ip_set.h>
16#include <linux/netfilter/ipset/ip_set_timeout.h>
17#include <linux/netfilter/ipset/ip_set_list.h> 16#include <linux/netfilter/ipset/ip_set_list.h>
18 17
19#define REVISION_MIN 0 18#define REVISION_MIN 0
@@ -24,19 +23,28 @@ MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
24IP_SET_MODULE_DESC("list:set", REVISION_MIN, REVISION_MAX); 23IP_SET_MODULE_DESC("list:set", REVISION_MIN, REVISION_MAX);
25MODULE_ALIAS("ip_set_list:set"); 24MODULE_ALIAS("ip_set_list:set");
26 25
27/* Member elements without and with timeout */ 26/* Member elements */
28struct set_elem { 27struct set_elem {
29 ip_set_id_t id; 28 ip_set_id_t id;
30}; 29};
31 30
32struct set_telem { 31struct sett_elem {
33 ip_set_id_t id; 32 struct {
33 ip_set_id_t id;
34 } __attribute__ ((aligned));
34 unsigned long timeout; 35 unsigned long timeout;
35}; 36};
36 37
38struct set_adt_elem {
39 ip_set_id_t id;
40 ip_set_id_t refid;
41 int before;
42};
43
37/* Type structure */ 44/* Type structure */
38struct list_set { 45struct list_set {
39 size_t dsize; /* element size */ 46 size_t dsize; /* element size */
47 size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */
40 u32 size; /* size of set list array */ 48 u32 size; /* size of set list array */
41 u32 timeout; /* timeout value */ 49 u32 timeout; /* timeout value */
42 struct timer_list gc; /* garbage collection */ 50 struct timer_list gc; /* garbage collection */
@@ -49,179 +57,296 @@ list_set_elem(const struct list_set *map, u32 id)
49 return (struct set_elem *)((void *)map->members + id * map->dsize); 57 return (struct set_elem *)((void *)map->members + id * map->dsize);
50} 58}
51 59
52static inline struct set_telem * 60#define ext_timeout(e, m) \
53list_set_telem(const struct list_set *map, u32 id) 61(unsigned long *)((void *)(e) + (m)->offset[IPSET_OFFSET_TIMEOUT])
54{
55 return (struct set_telem *)((void *)map->members + id * map->dsize);
56}
57 62
58static inline bool 63static int
59list_set_timeout(const struct list_set *map, u32 id) 64list_set_ktest(struct ip_set *set, const struct sk_buff *skb,
65 const struct xt_action_param *par,
66 struct ip_set_adt_opt *opt, const struct ip_set_ext *ext)
60{ 67{
61 const struct set_telem *elem = list_set_telem(map, id); 68 struct list_set *map = set->data;
69 struct set_elem *e;
70 u32 i;
71 int ret;
62 72
63 return ip_set_timeout_test(elem->timeout); 73 for (i = 0; i < map->size; i++) {
74 e = list_set_elem(map, i);
75 if (e->id == IPSET_INVALID_ID)
76 return 0;
77 if (SET_WITH_TIMEOUT(set) &&
78 ip_set_timeout_expired(ext_timeout(e, map)))
79 continue;
80 ret = ip_set_test(e->id, skb, par, opt);
81 if (ret > 0)
82 return ret;
83 }
84 return 0;
64} 85}
65 86
66static inline bool 87static int
67list_set_expired(const struct list_set *map, u32 id) 88list_set_kadd(struct ip_set *set, const struct sk_buff *skb,
89 const struct xt_action_param *par,
90 struct ip_set_adt_opt *opt, const struct ip_set_ext *ext)
68{ 91{
69 const struct set_telem *elem = list_set_telem(map, id); 92 struct list_set *map = set->data;
93 struct set_elem *e;
94 u32 i;
95 int ret;
70 96
71 return ip_set_timeout_expired(elem->timeout); 97 for (i = 0; i < map->size; i++) {
98 e = list_set_elem(map, i);
99 if (e->id == IPSET_INVALID_ID)
100 return 0;
101 if (SET_WITH_TIMEOUT(set) &&
102 ip_set_timeout_expired(ext_timeout(e, map)))
103 continue;
104 ret = ip_set_add(e->id, skb, par, opt);
105 if (ret == 0)
106 return ret;
107 }
108 return 0;
72} 109}
73 110
74/* Set list without and with timeout */
75
76static int 111static int
77list_set_kadt(struct ip_set *set, const struct sk_buff *skb, 112list_set_kdel(struct ip_set *set, const struct sk_buff *skb,
78 const struct xt_action_param *par, 113 const struct xt_action_param *par,
79 enum ipset_adt adt, const struct ip_set_adt_opt *opt) 114 struct ip_set_adt_opt *opt, const struct ip_set_ext *ext)
80{ 115{
81 struct list_set *map = set->data; 116 struct list_set *map = set->data;
82 struct set_elem *elem; 117 struct set_elem *e;
83 u32 i; 118 u32 i;
84 int ret; 119 int ret;
85 120
86 for (i = 0; i < map->size; i++) { 121 for (i = 0; i < map->size; i++) {
87 elem = list_set_elem(map, i); 122 e = list_set_elem(map, i);
88 if (elem->id == IPSET_INVALID_ID) 123 if (e->id == IPSET_INVALID_ID)
89 return 0; 124 return 0;
90 if (with_timeout(map->timeout) && list_set_expired(map, i)) 125 if (SET_WITH_TIMEOUT(set) &&
126 ip_set_timeout_expired(ext_timeout(e, map)))
91 continue; 127 continue;
92 switch (adt) { 128 ret = ip_set_del(e->id, skb, par, opt);
93 case IPSET_TEST: 129 if (ret == 0)
94 ret = ip_set_test(elem->id, skb, par, opt); 130 return ret;
95 if (ret > 0) 131 }
96 return ret; 132 return 0;
97 break; 133}
98 case IPSET_ADD: 134
99 ret = ip_set_add(elem->id, skb, par, opt); 135static int
100 if (ret == 0) 136list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
101 return ret; 137 const struct xt_action_param *par,
102 break; 138 enum ipset_adt adt, struct ip_set_adt_opt *opt)
103 case IPSET_DEL: 139{
104 ret = ip_set_del(elem->id, skb, par, opt); 140 struct list_set *map = set->data;
105 if (ret == 0) 141 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, map);
106 return ret; 142
107 break; 143 switch (adt) {
108 default: 144 case IPSET_TEST:
109 break; 145 return list_set_ktest(set, skb, par, opt, &ext);
110 } 146 case IPSET_ADD:
147 return list_set_kadd(set, skb, par, opt, &ext);
148 case IPSET_DEL:
149 return list_set_kdel(set, skb, par, opt, &ext);
150 default:
151 break;
111 } 152 }
112 return -EINVAL; 153 return -EINVAL;
113} 154}
114 155
115static bool 156static bool
116id_eq(const struct list_set *map, u32 i, ip_set_id_t id) 157id_eq(const struct ip_set *set, u32 i, ip_set_id_t id)
117{ 158{
118 const struct set_elem *elem; 159 const struct list_set *map = set->data;
160 const struct set_elem *e;
161
162 if (i >= map->size)
163 return 0;
119 164
120 if (i < map->size) { 165 e = list_set_elem(map, i);
121 elem = list_set_elem(map, i); 166 return !!(e->id == id &&
122 return elem->id == id; 167 !(SET_WITH_TIMEOUT(set) &&
168 ip_set_timeout_expired(ext_timeout(e, map))));
169}
170
171static int
172list_set_add(struct ip_set *set, u32 i, struct set_adt_elem *d,
173 const struct ip_set_ext *ext)
174{
175 struct list_set *map = set->data;
176 struct set_elem *e = list_set_elem(map, i);
177
178 if (e->id != IPSET_INVALID_ID) {
179 if (i == map->size - 1)
180 /* Last element replaced: e.g. add new,before,last */
181 ip_set_put_byindex(e->id);
182 else {
183 struct set_elem *x = list_set_elem(map, map->size - 1);
184
185 /* Last element pushed off */
186 if (x->id != IPSET_INVALID_ID)
187 ip_set_put_byindex(x->id);
188 memmove(list_set_elem(map, i + 1), e,
189 map->dsize * (map->size - (i + 1)));
190 }
123 } 191 }
124 192
193 e->id = d->id;
194 if (SET_WITH_TIMEOUT(set))
195 ip_set_timeout_set(ext_timeout(e, map), ext->timeout);
125 return 0; 196 return 0;
126} 197}
127 198
128static bool 199static int
129id_eq_timeout(const struct list_set *map, u32 i, ip_set_id_t id) 200list_set_del(struct ip_set *set, u32 i)
130{ 201{
131 const struct set_elem *elem; 202 struct list_set *map = set->data;
203 struct set_elem *e = list_set_elem(map, i);
132 204
133 if (i < map->size) { 205 ip_set_put_byindex(e->id);
134 elem = list_set_elem(map, i);
135 return !!(elem->id == id &&
136 !(with_timeout(map->timeout) &&
137 list_set_expired(map, i)));
138 }
139 206
207 if (i < map->size - 1)
208 memmove(e, list_set_elem(map, i + 1),
209 map->dsize * (map->size - (i + 1)));
210
211 /* Last element */
212 e = list_set_elem(map, map->size - 1);
213 e->id = IPSET_INVALID_ID;
140 return 0; 214 return 0;
141} 215}
142 216
143static void 217static void
144list_elem_add(struct list_set *map, u32 i, ip_set_id_t id) 218set_cleanup_entries(struct ip_set *set)
145{ 219{
220 struct list_set *map = set->data;
146 struct set_elem *e; 221 struct set_elem *e;
222 u32 i;
147 223
148 for (; i < map->size; i++) { 224 for (i = 0; i < map->size; i++) {
149 e = list_set_elem(map, i); 225 e = list_set_elem(map, i);
150 swap(e->id, id); 226 if (e->id != IPSET_INVALID_ID &&
151 if (e->id == IPSET_INVALID_ID) 227 ip_set_timeout_expired(ext_timeout(e, map)))
152 break; 228 list_set_del(set, i);
153 } 229 }
154} 230}
155 231
156static void 232static int
157list_elem_tadd(struct list_set *map, u32 i, ip_set_id_t id, 233list_set_utest(struct ip_set *set, void *value, const struct ip_set_ext *ext,
158 unsigned long timeout) 234 struct ip_set_ext *mext, u32 flags)
159{ 235{
160 struct set_telem *e; 236 struct list_set *map = set->data;
237 struct set_adt_elem *d = value;
238 struct set_elem *e;
239 u32 i;
240 int ret;
161 241
162 for (; i < map->size; i++) { 242 for (i = 0; i < map->size; i++) {
163 e = list_set_telem(map, i); 243 e = list_set_elem(map, i);
164 swap(e->id, id);
165 swap(e->timeout, timeout);
166 if (e->id == IPSET_INVALID_ID) 244 if (e->id == IPSET_INVALID_ID)
167 break; 245 return 0;
246 else if (SET_WITH_TIMEOUT(set) &&
247 ip_set_timeout_expired(ext_timeout(e, map)))
248 continue;
249 else if (e->id != d->id)
250 continue;
251
252 if (d->before == 0)
253 return 1;
254 else if (d->before > 0)
255 ret = id_eq(set, i + 1, d->refid);
256 else
257 ret = i > 0 && id_eq(set, i - 1, d->refid);
258 return ret;
168 } 259 }
260 return 0;
169} 261}
170 262
263
171static int 264static int
172list_set_add(struct list_set *map, u32 i, ip_set_id_t id, 265list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext,
173 unsigned long timeout) 266 struct ip_set_ext *mext, u32 flags)
174{ 267{
175 const struct set_elem *e = list_set_elem(map, i); 268 struct list_set *map = set->data;
269 struct set_adt_elem *d = value;
270 struct set_elem *e;
271 bool flag_exist = flags & IPSET_FLAG_EXIST;
272 u32 i, ret = 0;
176 273
177 if (e->id != IPSET_INVALID_ID) { 274 /* Check already added element */
178 const struct set_elem *x = list_set_elem(map, map->size - 1); 275 for (i = 0; i < map->size; i++) {
276 e = list_set_elem(map, i);
277 if (e->id == IPSET_INVALID_ID)
278 goto insert;
279 else if (SET_WITH_TIMEOUT(set) &&
280 ip_set_timeout_expired(ext_timeout(e, map)))
281 continue;
282 else if (e->id != d->id)
283 continue;
179 284
180 /* Last element replaced or pushed off */ 285 if ((d->before > 1 && !id_eq(set, i + 1, d->refid)) ||
181 if (x->id != IPSET_INVALID_ID) 286 (d->before < 0 &&
182 ip_set_put_byindex(x->id); 287 (i == 0 || !id_eq(set, i - 1, d->refid))))
288 /* Before/after doesn't match */
289 return -IPSET_ERR_REF_EXIST;
290 if (!flag_exist)
291 /* Can't re-add */
292 return -IPSET_ERR_EXIST;
293 /* Update extensions */
294 if (SET_WITH_TIMEOUT(set))
295 ip_set_timeout_set(ext_timeout(e, map), ext->timeout);
296 /* Set is already added to the list */
297 ip_set_put_byindex(d->id);
298 return 0;
299 }
300insert:
301 ret = -IPSET_ERR_LIST_FULL;
302 for (i = 0; i < map->size && ret == -IPSET_ERR_LIST_FULL; i++) {
303 e = list_set_elem(map, i);
304 if (e->id == IPSET_INVALID_ID)
305 ret = d->before != 0 ? -IPSET_ERR_REF_EXIST
306 : list_set_add(set, i, d, ext);
307 else if (e->id != d->refid)
308 continue;
309 else if (d->before > 0)
310 ret = list_set_add(set, i, d, ext);
311 else if (i + 1 < map->size)
312 ret = list_set_add(set, i + 1, d, ext);
183 } 313 }
184 if (with_timeout(map->timeout))
185 list_elem_tadd(map, i, id, ip_set_timeout_set(timeout));
186 else
187 list_elem_add(map, i, id);
188 314
189 return 0; 315 return ret;
190} 316}
191 317
192static int 318static int
193list_set_del(struct list_set *map, u32 i) 319list_set_udel(struct ip_set *set, void *value, const struct ip_set_ext *ext,
320 struct ip_set_ext *mext, u32 flags)
194{ 321{
195 struct set_elem *a = list_set_elem(map, i), *b; 322 struct list_set *map = set->data;
196 323 struct set_adt_elem *d = value;
197 ip_set_put_byindex(a->id); 324 struct set_elem *e;
198
199 for (; i < map->size - 1; i++) {
200 b = list_set_elem(map, i + 1);
201 a->id = b->id;
202 if (with_timeout(map->timeout))
203 ((struct set_telem *)a)->timeout =
204 ((struct set_telem *)b)->timeout;
205 a = b;
206 if (a->id == IPSET_INVALID_ID)
207 break;
208 }
209 /* Last element */
210 a->id = IPSET_INVALID_ID;
211 return 0;
212}
213
214static void
215cleanup_entries(struct list_set *map)
216{
217 struct set_telem *e;
218 u32 i; 325 u32 i;
219 326
220 for (i = 0; i < map->size; i++) { 327 for (i = 0; i < map->size; i++) {
221 e = list_set_telem(map, i); 328 e = list_set_elem(map, i);
222 if (e->id != IPSET_INVALID_ID && list_set_expired(map, i)) 329 if (e->id == IPSET_INVALID_ID)
223 list_set_del(map, i); 330 return d->before != 0 ? -IPSET_ERR_REF_EXIST
331 : -IPSET_ERR_EXIST;
332 else if (SET_WITH_TIMEOUT(set) &&
333 ip_set_timeout_expired(ext_timeout(e, map)))
334 continue;
335 else if (e->id != d->id)
336 continue;
337
338 if (d->before == 0)
339 return list_set_del(set, i);
340 else if (d->before > 0) {
341 if (!id_eq(set, i + 1, d->refid))
342 return -IPSET_ERR_REF_EXIST;
343 return list_set_del(set, i);
344 } else if (i == 0 || !id_eq(set, i - 1, d->refid))
345 return -IPSET_ERR_REF_EXIST;
346 else
347 return list_set_del(set, i);
224 } 348 }
349 return -IPSET_ERR_EXIST;
225} 350}
226 351
227static int 352static int
@@ -229,14 +354,10 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
229 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) 354 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
230{ 355{
231 struct list_set *map = set->data; 356 struct list_set *map = set->data;
232 bool with_timeout = with_timeout(map->timeout); 357 ipset_adtfn adtfn = set->variant->adt[adt];
233 bool flag_exist = flags & IPSET_FLAG_EXIST; 358 struct set_adt_elem e = { .refid = IPSET_INVALID_ID };
234 int before = 0; 359 struct ip_set_ext ext = IP_SET_INIT_UEXT(map);
235 u32 timeout = map->timeout;
236 ip_set_id_t id, refid = IPSET_INVALID_ID;
237 const struct set_elem *elem;
238 struct ip_set *s; 360 struct ip_set *s;
239 u32 i;
240 int ret = 0; 361 int ret = 0;
241 362
242 if (unlikely(!tb[IPSET_ATTR_NAME] || 363 if (unlikely(!tb[IPSET_ATTR_NAME] ||
@@ -247,8 +368,11 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
247 if (tb[IPSET_ATTR_LINENO]) 368 if (tb[IPSET_ATTR_LINENO])
248 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); 369 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
249 370
250 id = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAME]), &s); 371 ret = ip_set_get_extensions(set, tb, &ext);
251 if (id == IPSET_INVALID_ID) 372 if (ret)
373 return ret;
374 e.id = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAME]), &s);
375 if (e.id == IPSET_INVALID_ID)
252 return -IPSET_ERR_NAME; 376 return -IPSET_ERR_NAME;
253 /* "Loop detection" */ 377 /* "Loop detection" */
254 if (s->type->features & IPSET_TYPE_NAME) { 378 if (s->type->features & IPSET_TYPE_NAME) {
@@ -258,115 +382,34 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
258 382
259 if (tb[IPSET_ATTR_CADT_FLAGS]) { 383 if (tb[IPSET_ATTR_CADT_FLAGS]) {
260 u32 f = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); 384 u32 f = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
261 before = f & IPSET_FLAG_BEFORE; 385 e.before = f & IPSET_FLAG_BEFORE;
262 } 386 }
263 387
264 if (before && !tb[IPSET_ATTR_NAMEREF]) { 388 if (e.before && !tb[IPSET_ATTR_NAMEREF]) {
265 ret = -IPSET_ERR_BEFORE; 389 ret = -IPSET_ERR_BEFORE;
266 goto finish; 390 goto finish;
267 } 391 }
268 392
269 if (tb[IPSET_ATTR_NAMEREF]) { 393 if (tb[IPSET_ATTR_NAMEREF]) {
270 refid = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAMEREF]), 394 e.refid = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAMEREF]),
271 &s); 395 &s);
272 if (refid == IPSET_INVALID_ID) { 396 if (e.refid == IPSET_INVALID_ID) {
273 ret = -IPSET_ERR_NAMEREF; 397 ret = -IPSET_ERR_NAMEREF;
274 goto finish; 398 goto finish;
275 } 399 }
276 if (!before) 400 if (!e.before)
277 before = -1; 401 e.before = -1;
278 }
279 if (tb[IPSET_ATTR_TIMEOUT]) {
280 if (!with_timeout) {
281 ret = -IPSET_ERR_TIMEOUT;
282 goto finish;
283 }
284 timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
285 } 402 }
286 if (with_timeout && adt != IPSET_TEST) 403 if (adt != IPSET_TEST && SET_WITH_TIMEOUT(set))
287 cleanup_entries(map); 404 set_cleanup_entries(set);
288 405
289 switch (adt) { 406 ret = adtfn(set, &e, &ext, &ext, flags);
290 case IPSET_TEST:
291 for (i = 0; i < map->size && !ret; i++) {
292 elem = list_set_elem(map, i);
293 if (elem->id == IPSET_INVALID_ID ||
294 (before != 0 && i + 1 >= map->size))
295 break;
296 else if (with_timeout && list_set_expired(map, i))
297 continue;
298 else if (before > 0 && elem->id == id)
299 ret = id_eq_timeout(map, i + 1, refid);
300 else if (before < 0 && elem->id == refid)
301 ret = id_eq_timeout(map, i + 1, id);
302 else if (before == 0 && elem->id == id)
303 ret = 1;
304 }
305 break;
306 case IPSET_ADD:
307 for (i = 0; i < map->size; i++) {
308 elem = list_set_elem(map, i);
309 if (elem->id != id)
310 continue;
311 if (!(with_timeout && flag_exist)) {
312 ret = -IPSET_ERR_EXIST;
313 goto finish;
314 } else {
315 struct set_telem *e = list_set_telem(map, i);
316
317 if ((before > 1 &&
318 !id_eq(map, i + 1, refid)) ||
319 (before < 0 &&
320 (i == 0 || !id_eq(map, i - 1, refid)))) {
321 ret = -IPSET_ERR_EXIST;
322 goto finish;
323 }
324 e->timeout = ip_set_timeout_set(timeout);
325 ip_set_put_byindex(id);
326 ret = 0;
327 goto finish;
328 }
329 }
330 ret = -IPSET_ERR_LIST_FULL;
331 for (i = 0; i < map->size && ret == -IPSET_ERR_LIST_FULL; i++) {
332 elem = list_set_elem(map, i);
333 if (elem->id == IPSET_INVALID_ID)
334 ret = before != 0 ? -IPSET_ERR_REF_EXIST
335 : list_set_add(map, i, id, timeout);
336 else if (elem->id != refid)
337 continue;
338 else if (before > 0)
339 ret = list_set_add(map, i, id, timeout);
340 else if (i + 1 < map->size)
341 ret = list_set_add(map, i + 1, id, timeout);
342 }
343 break;
344 case IPSET_DEL:
345 ret = -IPSET_ERR_EXIST;
346 for (i = 0; i < map->size && ret == -IPSET_ERR_EXIST; i++) {
347 elem = list_set_elem(map, i);
348 if (elem->id == IPSET_INVALID_ID) {
349 ret = before != 0 ? -IPSET_ERR_REF_EXIST
350 : -IPSET_ERR_EXIST;
351 break;
352 } else if (elem->id == id &&
353 (before == 0 ||
354 (before > 0 && id_eq(map, i + 1, refid))))
355 ret = list_set_del(map, i);
356 else if (elem->id == refid &&
357 before < 0 && id_eq(map, i + 1, id))
358 ret = list_set_del(map, i + 1);
359 }
360 break;
361 default:
362 break;
363 }
364 407
365finish: 408finish:
366 if (refid != IPSET_INVALID_ID) 409 if (e.refid != IPSET_INVALID_ID)
367 ip_set_put_byindex(refid); 410 ip_set_put_byindex(e.refid);
368 if (adt != IPSET_ADD || ret) 411 if (adt != IPSET_ADD || ret)
369 ip_set_put_byindex(id); 412 ip_set_put_byindex(e.id);
370 413
371 return ip_set_eexist(ret, flags) ? 0 : ret; 414 return ip_set_eexist(ret, flags) ? 0 : ret;
372} 415}
@@ -375,14 +418,14 @@ static void
375list_set_flush(struct ip_set *set) 418list_set_flush(struct ip_set *set)
376{ 419{
377 struct list_set *map = set->data; 420 struct list_set *map = set->data;
378 struct set_elem *elem; 421 struct set_elem *e;
379 u32 i; 422 u32 i;
380 423
381 for (i = 0; i < map->size; i++) { 424 for (i = 0; i < map->size; i++) {
382 elem = list_set_elem(map, i); 425 e = list_set_elem(map, i);
383 if (elem->id != IPSET_INVALID_ID) { 426 if (e->id != IPSET_INVALID_ID) {
384 ip_set_put_byindex(elem->id); 427 ip_set_put_byindex(e->id);
385 elem->id = IPSET_INVALID_ID; 428 e->id = IPSET_INVALID_ID;
386 } 429 }
387 } 430 }
388} 431}
@@ -392,7 +435,7 @@ list_set_destroy(struct ip_set *set)
392{ 435{
393 struct list_set *map = set->data; 436 struct list_set *map = set->data;
394 437
395 if (with_timeout(map->timeout)) 438 if (SET_WITH_TIMEOUT(set))
396 del_timer_sync(&map->gc); 439 del_timer_sync(&map->gc);
397 list_set_flush(set); 440 list_set_flush(set);
398 kfree(map); 441 kfree(map);
@@ -410,7 +453,7 @@ list_set_head(struct ip_set *set, struct sk_buff *skb)
410 if (!nested) 453 if (!nested)
411 goto nla_put_failure; 454 goto nla_put_failure;
412 if (nla_put_net32(skb, IPSET_ATTR_SIZE, htonl(map->size)) || 455 if (nla_put_net32(skb, IPSET_ATTR_SIZE, htonl(map->size)) ||
413 (with_timeout(map->timeout) && 456 (SET_WITH_TIMEOUT(set) &&
414 nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout))) || 457 nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout))) ||
415 nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) || 458 nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
416 nla_put_net32(skb, IPSET_ATTR_MEMSIZE, 459 nla_put_net32(skb, IPSET_ATTR_MEMSIZE,
@@ -440,7 +483,8 @@ list_set_list(const struct ip_set *set,
440 e = list_set_elem(map, i); 483 e = list_set_elem(map, i);
441 if (e->id == IPSET_INVALID_ID) 484 if (e->id == IPSET_INVALID_ID)
442 goto finish; 485 goto finish;
443 if (with_timeout(map->timeout) && list_set_expired(map, i)) 486 if (SET_WITH_TIMEOUT(set) &&
487 ip_set_timeout_expired(ext_timeout(e, map)))
444 continue; 488 continue;
445 nested = ipset_nest_start(skb, IPSET_ATTR_DATA); 489 nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
446 if (!nested) { 490 if (!nested) {
@@ -453,13 +497,11 @@ list_set_list(const struct ip_set *set,
453 if (nla_put_string(skb, IPSET_ATTR_NAME, 497 if (nla_put_string(skb, IPSET_ATTR_NAME,
454 ip_set_name_byindex(e->id))) 498 ip_set_name_byindex(e->id)))
455 goto nla_put_failure; 499 goto nla_put_failure;
456 if (with_timeout(map->timeout)) { 500 if (SET_WITH_TIMEOUT(set) &&
457 const struct set_telem *te = 501 nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
458 (const struct set_telem *) e; 502 htonl(ip_set_timeout_get(
459 __be32 to = htonl(ip_set_timeout_get(te->timeout)); 503 ext_timeout(e, map)))))
460 if (nla_put_net32(skb, IPSET_ATTR_TIMEOUT, to)) 504 goto nla_put_failure;
461 goto nla_put_failure;
462 }
463 ipset_nest_end(skb, nested); 505 ipset_nest_end(skb, nested);
464 } 506 }
465finish: 507finish:
@@ -485,12 +527,18 @@ list_set_same_set(const struct ip_set *a, const struct ip_set *b)
485 const struct list_set *y = b->data; 527 const struct list_set *y = b->data;
486 528
487 return x->size == y->size && 529 return x->size == y->size &&
488 x->timeout == y->timeout; 530 x->timeout == y->timeout &&
531 a->extensions == b->extensions;
489} 532}
490 533
491static const struct ip_set_type_variant list_set = { 534static const struct ip_set_type_variant set_variant = {
492 .kadt = list_set_kadt, 535 .kadt = list_set_kadt,
493 .uadt = list_set_uadt, 536 .uadt = list_set_uadt,
537 .adt = {
538 [IPSET_ADD] = list_set_uadd,
539 [IPSET_DEL] = list_set_udel,
540 [IPSET_TEST] = list_set_utest,
541 },
494 .destroy = list_set_destroy, 542 .destroy = list_set_destroy,
495 .flush = list_set_flush, 543 .flush = list_set_flush,
496 .head = list_set_head, 544 .head = list_set_head,
@@ -505,7 +553,7 @@ list_set_gc(unsigned long ul_set)
505 struct list_set *map = set->data; 553 struct list_set *map = set->data;
506 554
507 write_lock_bh(&set->lock); 555 write_lock_bh(&set->lock);
508 cleanup_entries(map); 556 set_cleanup_entries(set);
509 write_unlock_bh(&set->lock); 557 write_unlock_bh(&set->lock);
510 558
511 map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ; 559 map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
@@ -513,20 +561,20 @@ list_set_gc(unsigned long ul_set)
513} 561}
514 562
515static void 563static void
516list_set_gc_init(struct ip_set *set) 564list_set_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))
517{ 565{
518 struct list_set *map = set->data; 566 struct list_set *map = set->data;
519 567
520 init_timer(&map->gc); 568 init_timer(&map->gc);
521 map->gc.data = (unsigned long) set; 569 map->gc.data = (unsigned long) set;
522 map->gc.function = list_set_gc; 570 map->gc.function = gc;
523 map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ; 571 map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
524 add_timer(&map->gc); 572 add_timer(&map->gc);
525} 573}
526 574
527/* Create list:set type of sets */ 575/* Create list:set type of sets */
528 576
529static bool 577static struct list_set *
530init_list_set(struct ip_set *set, u32 size, size_t dsize, 578init_list_set(struct ip_set *set, u32 size, size_t dsize,
531 unsigned long timeout) 579 unsigned long timeout)
532{ 580{
@@ -536,7 +584,7 @@ init_list_set(struct ip_set *set, u32 size, size_t dsize,
536 584
537 map = kzalloc(sizeof(*map) + size * dsize, GFP_KERNEL); 585 map = kzalloc(sizeof(*map) + size * dsize, GFP_KERNEL);
538 if (!map) 586 if (!map)
539 return false; 587 return NULL;
540 588
541 map->size = size; 589 map->size = size;
542 map->dsize = dsize; 590 map->dsize = dsize;
@@ -548,13 +596,15 @@ init_list_set(struct ip_set *set, u32 size, size_t dsize,
548 e->id = IPSET_INVALID_ID; 596 e->id = IPSET_INVALID_ID;
549 } 597 }
550 598
551 return true; 599 return map;
552} 600}
553 601
554static int 602static int
555list_set_create(struct ip_set *set, struct nlattr *tb[], u32 flags) 603list_set_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
556{ 604{
605 struct list_set *map;
557 u32 size = IP_SET_LIST_DEFAULT_SIZE; 606 u32 size = IP_SET_LIST_DEFAULT_SIZE;
607 unsigned long timeout = 0;
558 608
559 if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_SIZE) || 609 if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_SIZE) ||
560 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) 610 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
@@ -565,18 +615,23 @@ list_set_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
565 if (size < IP_SET_LIST_MIN_SIZE) 615 if (size < IP_SET_LIST_MIN_SIZE)
566 size = IP_SET_LIST_MIN_SIZE; 616 size = IP_SET_LIST_MIN_SIZE;
567 617
618 if (tb[IPSET_ATTR_TIMEOUT])
619 timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
620 set->variant = &set_variant;
568 if (tb[IPSET_ATTR_TIMEOUT]) { 621 if (tb[IPSET_ATTR_TIMEOUT]) {
569 if (!init_list_set(set, size, sizeof(struct set_telem), 622 map = init_list_set(set, size,
570 ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]))) 623 sizeof(struct sett_elem), timeout);
624 if (!map)
571 return -ENOMEM; 625 return -ENOMEM;
572 626 set->extensions |= IPSET_EXT_TIMEOUT;
573 list_set_gc_init(set); 627 map->offset[IPSET_OFFSET_TIMEOUT] =
628 offsetof(struct sett_elem, timeout);
629 list_set_gc_init(set, list_set_gc);
574 } else { 630 } else {
575 if (!init_list_set(set, size, sizeof(struct set_elem), 631 map = init_list_set(set, size, sizeof(struct set_elem), 0);
576 IPSET_NO_TIMEOUT)) 632 if (!map)
577 return -ENOMEM; 633 return -ENOMEM;
578 } 634 }
579 set->variant = &list_set;
580 return 0; 635 return 0;
581} 636}
582 637