1 /* Copyright (C) 2008-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 as
5 * published by the Free Software Foundation.
6 */
7
8 /* Kernel module implementing an IP set type: the list:set type */
9
10 #include <linux/module.h>
11 #include <linux/ip.h>
12 #include <linux/skbuff.h>
13 #include <linux/errno.h>
14
15 #include <linux/netfilter/ipset/ip_set.h>
16 #include <linux/netfilter/ipset/ip_set_list.h>
17
18 #define IPSET_TYPE_REV_MIN 0
19 /* 1 Counters support added */
20 /* 2 Comments support added */
21 #define IPSET_TYPE_REV_MAX 3 /* skbinfo support added */
22
23 MODULE_LICENSE("GPL");
24 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
25 IP_SET_MODULE_DESC("list:set", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
26 MODULE_ALIAS("ip_set_list:set");
27
28 /* Member elements */
29 struct set_elem {
30 ip_set_id_t id;
31 };
32
33 struct set_adt_elem {
34 ip_set_id_t id;
35 ip_set_id_t refid;
36 int before;
37 };
38
39 /* Type structure */
40 struct list_set {
41 u32 size; /* size of set list array */
42 struct timer_list gc; /* garbage collection */
43 struct net *net; /* namespace */
44 struct set_elem members[0]; /* the set members */
45 };
46
47 #define list_set_elem(set, map, id) \
48 (struct set_elem *)((void *)(map)->members + (id) * (set)->dsize)
49
50 static int
list_set_ktest(struct ip_set * set,const struct sk_buff * skb,const struct xt_action_param * par,struct ip_set_adt_opt * opt,const struct ip_set_ext * ext)51 list_set_ktest(struct ip_set *set, const struct sk_buff *skb,
52 const struct xt_action_param *par,
53 struct ip_set_adt_opt *opt, const struct ip_set_ext *ext)
54 {
55 struct list_set *map = set->data;
56 struct set_elem *e;
57 u32 i, cmdflags = opt->cmdflags;
58 int ret;
59
60 /* Don't lookup sub-counters at all */
61 opt->cmdflags &= ~IPSET_FLAG_MATCH_COUNTERS;
62 if (opt->cmdflags & IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE)
63 opt->cmdflags &= ~IPSET_FLAG_SKIP_COUNTER_UPDATE;
64 for (i = 0; i < map->size; i++) {
65 e = list_set_elem(set, map, i);
66 if (e->id == IPSET_INVALID_ID)
67 return 0;
68 if (SET_WITH_TIMEOUT(set) &&
69 ip_set_timeout_expired(ext_timeout(e, set)))
70 continue;
71 ret = ip_set_test(e->id, skb, par, opt);
72 if (ret > 0) {
73 if (SET_WITH_COUNTER(set))
74 ip_set_update_counter(ext_counter(e, set),
75 ext, &opt->ext,
76 cmdflags);
77 if (SET_WITH_SKBINFO(set))
78 ip_set_get_skbinfo(ext_skbinfo(e, set),
79 ext, &opt->ext,
80 cmdflags);
81 return ret;
82 }
83 }
84 return 0;
85 }
86
87 static int
list_set_kadd(struct ip_set * set,const struct sk_buff * skb,const struct xt_action_param * par,struct ip_set_adt_opt * opt,const struct ip_set_ext * ext)88 list_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)
91 {
92 struct list_set *map = set->data;
93 struct set_elem *e;
94 u32 i;
95 int ret;
96
97 for (i = 0; i < map->size; i++) {
98 e = list_set_elem(set, 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, set)))
103 continue;
104 ret = ip_set_add(e->id, skb, par, opt);
105 if (ret == 0)
106 return ret;
107 }
108 return 0;
109 }
110
111 static int
list_set_kdel(struct ip_set * set,const struct sk_buff * skb,const struct xt_action_param * par,struct ip_set_adt_opt * opt,const struct ip_set_ext * ext)112 list_set_kdel(struct ip_set *set, const struct sk_buff *skb,
113 const struct xt_action_param *par,
114 struct ip_set_adt_opt *opt, const struct ip_set_ext *ext)
115 {
116 struct list_set *map = set->data;
117 struct set_elem *e;
118 u32 i;
119 int ret;
120
121 for (i = 0; i < map->size; i++) {
122 e = list_set_elem(set, map, i);
123 if (e->id == IPSET_INVALID_ID)
124 return 0;
125 if (SET_WITH_TIMEOUT(set) &&
126 ip_set_timeout_expired(ext_timeout(e, set)))
127 continue;
128 ret = ip_set_del(e->id, skb, par, opt);
129 if (ret == 0)
130 return ret;
131 }
132 return 0;
133 }
134
135 static int
list_set_kadt(struct ip_set * set,const struct sk_buff * skb,const struct xt_action_param * par,enum ipset_adt adt,struct ip_set_adt_opt * opt)136 list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
137 const struct xt_action_param *par,
138 enum ipset_adt adt, struct ip_set_adt_opt *opt)
139 {
140 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
141
142 switch (adt) {
143 case IPSET_TEST:
144 return list_set_ktest(set, skb, par, opt, &ext);
145 case IPSET_ADD:
146 return list_set_kadd(set, skb, par, opt, &ext);
147 case IPSET_DEL:
148 return list_set_kdel(set, skb, par, opt, &ext);
149 default:
150 break;
151 }
152 return -EINVAL;
153 }
154
155 static bool
id_eq(const struct ip_set * set,u32 i,ip_set_id_t id)156 id_eq(const struct ip_set *set, u32 i, ip_set_id_t id)
157 {
158 const struct list_set *map = set->data;
159 const struct set_elem *e;
160
161 if (i >= map->size)
162 return 0;
163
164 e = list_set_elem(set, map, i);
165 return !!(e->id == id &&
166 !(SET_WITH_TIMEOUT(set) &&
167 ip_set_timeout_expired(ext_timeout(e, set))));
168 }
169
170 static int
list_set_add(struct ip_set * set,u32 i,struct set_adt_elem * d,const struct ip_set_ext * ext)171 list_set_add(struct ip_set *set, u32 i, struct set_adt_elem *d,
172 const struct ip_set_ext *ext)
173 {
174 struct list_set *map = set->data;
175 struct set_elem *e = list_set_elem(set, map, i);
176
177 if (e->id != IPSET_INVALID_ID) {
178 if (i == map->size - 1) {
179 /* Last element replaced: e.g. add new,before,last */
180 ip_set_put_byindex(map->net, e->id);
181 ip_set_ext_destroy(set, e);
182 } else {
183 struct set_elem *x = list_set_elem(set, map,
184 map->size - 1);
185
186 /* Last element pushed off */
187 if (x->id != IPSET_INVALID_ID) {
188 ip_set_put_byindex(map->net, x->id);
189 ip_set_ext_destroy(set, x);
190 }
191 memmove(list_set_elem(set, map, i + 1), e,
192 set->dsize * (map->size - (i + 1)));
193 /* Extensions must be initialized to zero */
194 memset(e, 0, set->dsize);
195 }
196 }
197
198 e->id = d->id;
199 if (SET_WITH_TIMEOUT(set))
200 ip_set_timeout_set(ext_timeout(e, set), ext->timeout);
201 if (SET_WITH_COUNTER(set))
202 ip_set_init_counter(ext_counter(e, set), ext);
203 if (SET_WITH_COMMENT(set))
204 ip_set_init_comment(ext_comment(e, set), ext);
205 if (SET_WITH_SKBINFO(set))
206 ip_set_init_skbinfo(ext_skbinfo(e, set), ext);
207 return 0;
208 }
209
210 static int
list_set_del(struct ip_set * set,u32 i)211 list_set_del(struct ip_set *set, u32 i)
212 {
213 struct list_set *map = set->data;
214 struct set_elem *e = list_set_elem(set, map, i);
215
216 ip_set_put_byindex(map->net, e->id);
217 ip_set_ext_destroy(set, e);
218
219 if (i < map->size - 1)
220 memmove(e, list_set_elem(set, map, i + 1),
221 set->dsize * (map->size - (i + 1)));
222
223 /* Last element */
224 e = list_set_elem(set, map, map->size - 1);
225 e->id = IPSET_INVALID_ID;
226 return 0;
227 }
228
229 static void
set_cleanup_entries(struct ip_set * set)230 set_cleanup_entries(struct ip_set *set)
231 {
232 struct list_set *map = set->data;
233 struct set_elem *e;
234 u32 i = 0;
235
236 while (i < map->size) {
237 e = list_set_elem(set, map, i);
238 if (e->id != IPSET_INVALID_ID &&
239 ip_set_timeout_expired(ext_timeout(e, set)))
240 list_set_del(set, i);
241 /* Check element moved to position i in next loop */
242 else
243 i++;
244 }
245 }
246
247 static int
list_set_utest(struct ip_set * set,void * value,const struct ip_set_ext * ext,struct ip_set_ext * mext,u32 flags)248 list_set_utest(struct ip_set *set, void *value, const struct ip_set_ext *ext,
249 struct ip_set_ext *mext, u32 flags)
250 {
251 struct list_set *map = set->data;
252 struct set_adt_elem *d = value;
253 struct set_elem *e;
254 u32 i;
255 int ret;
256
257 for (i = 0; i < map->size; i++) {
258 e = list_set_elem(set, map, i);
259 if (e->id == IPSET_INVALID_ID)
260 return 0;
261 else if (SET_WITH_TIMEOUT(set) &&
262 ip_set_timeout_expired(ext_timeout(e, set)))
263 continue;
264 else if (e->id != d->id)
265 continue;
266
267 if (d->before == 0)
268 return 1;
269 else if (d->before > 0)
270 ret = id_eq(set, i + 1, d->refid);
271 else
272 ret = i > 0 && id_eq(set, i - 1, d->refid);
273 return ret;
274 }
275 return 0;
276 }
277
278
279 static int
list_set_uadd(struct ip_set * set,void * value,const struct ip_set_ext * ext,struct ip_set_ext * mext,u32 flags)280 list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext,
281 struct ip_set_ext *mext, u32 flags)
282 {
283 struct list_set *map = set->data;
284 struct set_adt_elem *d = value;
285 struct set_elem *e;
286 bool flag_exist = flags & IPSET_FLAG_EXIST;
287 u32 i, ret = 0;
288
289 if (SET_WITH_TIMEOUT(set))
290 set_cleanup_entries(set);
291
292 /* Check already added element */
293 for (i = 0; i < map->size; i++) {
294 e = list_set_elem(set, map, i);
295 if (e->id == IPSET_INVALID_ID)
296 goto insert;
297 else if (e->id != d->id)
298 continue;
299
300 if ((d->before > 1 && !id_eq(set, i + 1, d->refid)) ||
301 (d->before < 0 &&
302 (i == 0 || !id_eq(set, i - 1, d->refid))))
303 /* Before/after doesn't match */
304 return -IPSET_ERR_REF_EXIST;
305 if (!flag_exist)
306 /* Can't re-add */
307 return -IPSET_ERR_EXIST;
308 /* Update extensions */
309 ip_set_ext_destroy(set, e);
310
311 if (SET_WITH_TIMEOUT(set))
312 ip_set_timeout_set(ext_timeout(e, set), ext->timeout);
313 if (SET_WITH_COUNTER(set))
314 ip_set_init_counter(ext_counter(e, set), ext);
315 if (SET_WITH_COMMENT(set))
316 ip_set_init_comment(ext_comment(e, set), ext);
317 if (SET_WITH_SKBINFO(set))
318 ip_set_init_skbinfo(ext_skbinfo(e, set), ext);
319 /* Set is already added to the list */
320 ip_set_put_byindex(map->net, d->id);
321 return 0;
322 }
323 insert:
324 ret = -IPSET_ERR_LIST_FULL;
325 for (i = 0; i < map->size && ret == -IPSET_ERR_LIST_FULL; i++) {
326 e = list_set_elem(set, map, i);
327 if (e->id == IPSET_INVALID_ID)
328 ret = d->before != 0 ? -IPSET_ERR_REF_EXIST
329 : list_set_add(set, i, d, ext);
330 else if (e->id != d->refid)
331 continue;
332 else if (d->before > 0)
333 ret = list_set_add(set, i, d, ext);
334 else if (i + 1 < map->size)
335 ret = list_set_add(set, i + 1, d, ext);
336 }
337
338 return ret;
339 }
340
341 static int
list_set_udel(struct ip_set * set,void * value,const struct ip_set_ext * ext,struct ip_set_ext * mext,u32 flags)342 list_set_udel(struct ip_set *set, void *value, const struct ip_set_ext *ext,
343 struct ip_set_ext *mext, u32 flags)
344 {
345 struct list_set *map = set->data;
346 struct set_adt_elem *d = value;
347 struct set_elem *e;
348 u32 i;
349
350 for (i = 0; i < map->size; i++) {
351 e = list_set_elem(set, map, i);
352 if (e->id == IPSET_INVALID_ID)
353 return d->before != 0 ? -IPSET_ERR_REF_EXIST
354 : -IPSET_ERR_EXIST;
355 else if (SET_WITH_TIMEOUT(set) &&
356 ip_set_timeout_expired(ext_timeout(e, set)))
357 continue;
358 else if (e->id != d->id)
359 continue;
360
361 if (d->before == 0)
362 return list_set_del(set, i);
363 else if (d->before > 0) {
364 if (!id_eq(set, i + 1, d->refid))
365 return -IPSET_ERR_REF_EXIST;
366 return list_set_del(set, i);
367 } else if (i == 0 || !id_eq(set, i - 1, d->refid))
368 return -IPSET_ERR_REF_EXIST;
369 else
370 return list_set_del(set, i);
371 }
372 return -IPSET_ERR_EXIST;
373 }
374
375 static int
list_set_uadt(struct ip_set * set,struct nlattr * tb[],enum ipset_adt adt,u32 * lineno,u32 flags,bool retried)376 list_set_uadt(struct ip_set *set, struct nlattr *tb[],
377 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
378 {
379 struct list_set *map = set->data;
380 ipset_adtfn adtfn = set->variant->adt[adt];
381 struct set_adt_elem e = { .refid = IPSET_INVALID_ID };
382 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
383 struct ip_set *s;
384 int ret = 0;
385
386 if (unlikely(!tb[IPSET_ATTR_NAME] ||
387 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
388 !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
389 !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
390 !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) ||
391 !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) ||
392 !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) ||
393 !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE)))
394 return -IPSET_ERR_PROTOCOL;
395
396 if (tb[IPSET_ATTR_LINENO])
397 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
398
399 ret = ip_set_get_extensions(set, tb, &ext);
400 if (ret)
401 return ret;
402 e.id = ip_set_get_byname(map->net, nla_data(tb[IPSET_ATTR_NAME]), &s);
403 if (e.id == IPSET_INVALID_ID)
404 return -IPSET_ERR_NAME;
405 /* "Loop detection" */
406 if (s->type->features & IPSET_TYPE_NAME) {
407 ret = -IPSET_ERR_LOOP;
408 goto finish;
409 }
410
411 if (tb[IPSET_ATTR_CADT_FLAGS]) {
412 u32 f = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
413 e.before = f & IPSET_FLAG_BEFORE;
414 }
415
416 if (e.before && !tb[IPSET_ATTR_NAMEREF]) {
417 ret = -IPSET_ERR_BEFORE;
418 goto finish;
419 }
420
421 if (tb[IPSET_ATTR_NAMEREF]) {
422 e.refid = ip_set_get_byname(map->net,
423 nla_data(tb[IPSET_ATTR_NAMEREF]),
424 &s);
425 if (e.refid == IPSET_INVALID_ID) {
426 ret = -IPSET_ERR_NAMEREF;
427 goto finish;
428 }
429 if (!e.before)
430 e.before = -1;
431 }
432 if (adt != IPSET_TEST && SET_WITH_TIMEOUT(set))
433 set_cleanup_entries(set);
434
435 ret = adtfn(set, &e, &ext, &ext, flags);
436
437 finish:
438 if (e.refid != IPSET_INVALID_ID)
439 ip_set_put_byindex(map->net, e.refid);
440 if (adt != IPSET_ADD || ret)
441 ip_set_put_byindex(map->net, e.id);
442
443 return ip_set_eexist(ret, flags) ? 0 : ret;
444 }
445
446 static void
list_set_flush(struct ip_set * set)447 list_set_flush(struct ip_set *set)
448 {
449 struct list_set *map = set->data;
450 struct set_elem *e;
451 u32 i;
452
453 for (i = 0; i < map->size; i++) {
454 e = list_set_elem(set, map, i);
455 if (e->id != IPSET_INVALID_ID) {
456 ip_set_put_byindex(map->net, e->id);
457 ip_set_ext_destroy(set, e);
458 e->id = IPSET_INVALID_ID;
459 }
460 }
461 }
462
463 static void
list_set_destroy(struct ip_set * set)464 list_set_destroy(struct ip_set *set)
465 {
466 struct list_set *map = set->data;
467
468 if (SET_WITH_TIMEOUT(set))
469 del_timer_sync(&map->gc);
470 list_set_flush(set);
471 kfree(map);
472
473 set->data = NULL;
474 }
475
476 static int
list_set_head(struct ip_set * set,struct sk_buff * skb)477 list_set_head(struct ip_set *set, struct sk_buff *skb)
478 {
479 const struct list_set *map = set->data;
480 struct nlattr *nested;
481
482 nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
483 if (!nested)
484 goto nla_put_failure;
485 if (nla_put_net32(skb, IPSET_ATTR_SIZE, htonl(map->size)) ||
486 nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
487 nla_put_net32(skb, IPSET_ATTR_MEMSIZE,
488 htonl(sizeof(*map) + map->size * set->dsize)))
489 goto nla_put_failure;
490 if (unlikely(ip_set_put_flags(skb, set)))
491 goto nla_put_failure;
492 ipset_nest_end(skb, nested);
493
494 return 0;
495 nla_put_failure:
496 return -EMSGSIZE;
497 }
498
499 static int
list_set_list(const struct ip_set * set,struct sk_buff * skb,struct netlink_callback * cb)500 list_set_list(const struct ip_set *set,
501 struct sk_buff *skb, struct netlink_callback *cb)
502 {
503 const struct list_set *map = set->data;
504 struct nlattr *atd, *nested;
505 u32 i, first = cb->args[IPSET_CB_ARG0];
506 const struct set_elem *e;
507
508 atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
509 if (!atd)
510 return -EMSGSIZE;
511 for (; cb->args[IPSET_CB_ARG0] < map->size;
512 cb->args[IPSET_CB_ARG0]++) {
513 i = cb->args[IPSET_CB_ARG0];
514 e = list_set_elem(set, map, i);
515 if (e->id == IPSET_INVALID_ID)
516 goto finish;
517 if (SET_WITH_TIMEOUT(set) &&
518 ip_set_timeout_expired(ext_timeout(e, set)))
519 continue;
520 nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
521 if (!nested) {
522 if (i == first) {
523 nla_nest_cancel(skb, atd);
524 return -EMSGSIZE;
525 } else
526 goto nla_put_failure;
527 }
528 if (nla_put_string(skb, IPSET_ATTR_NAME,
529 ip_set_name_byindex(map->net, e->id)))
530 goto nla_put_failure;
531 if (ip_set_put_extensions(skb, set, e, true))
532 goto nla_put_failure;
533 ipset_nest_end(skb, nested);
534 }
535 finish:
536 ipset_nest_end(skb, atd);
537 /* Set listing finished */
538 cb->args[IPSET_CB_ARG0] = 0;
539 return 0;
540
541 nla_put_failure:
542 nla_nest_cancel(skb, nested);
543 if (unlikely(i == first)) {
544 cb->args[IPSET_CB_ARG0] = 0;
545 return -EMSGSIZE;
546 }
547 ipset_nest_end(skb, atd);
548 return 0;
549 }
550
551 static bool
list_set_same_set(const struct ip_set * a,const struct ip_set * b)552 list_set_same_set(const struct ip_set *a, const struct ip_set *b)
553 {
554 const struct list_set *x = a->data;
555 const struct list_set *y = b->data;
556
557 return x->size == y->size &&
558 a->timeout == b->timeout &&
559 a->extensions == b->extensions;
560 }
561
562 static const struct ip_set_type_variant set_variant = {
563 .kadt = list_set_kadt,
564 .uadt = list_set_uadt,
565 .adt = {
566 [IPSET_ADD] = list_set_uadd,
567 [IPSET_DEL] = list_set_udel,
568 [IPSET_TEST] = list_set_utest,
569 },
570 .destroy = list_set_destroy,
571 .flush = list_set_flush,
572 .head = list_set_head,
573 .list = list_set_list,
574 .same_set = list_set_same_set,
575 };
576
577 static void
list_set_gc(unsigned long ul_set)578 list_set_gc(unsigned long ul_set)
579 {
580 struct ip_set *set = (struct ip_set *) ul_set;
581 struct list_set *map = set->data;
582
583 write_lock_bh(&set->lock);
584 set_cleanup_entries(set);
585 write_unlock_bh(&set->lock);
586
587 map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;
588 add_timer(&map->gc);
589 }
590
591 static void
list_set_gc_init(struct ip_set * set,void (* gc)(unsigned long ul_set))592 list_set_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))
593 {
594 struct list_set *map = set->data;
595
596 init_timer(&map->gc);
597 map->gc.data = (unsigned long) set;
598 map->gc.function = gc;
599 map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;
600 add_timer(&map->gc);
601 }
602
603 /* Create list:set type of sets */
604
605 static bool
init_list_set(struct net * net,struct ip_set * set,u32 size)606 init_list_set(struct net *net, struct ip_set *set, u32 size)
607 {
608 struct list_set *map;
609 struct set_elem *e;
610 u32 i;
611
612 map = kzalloc(sizeof(*map) +
613 min_t(u32, size, IP_SET_LIST_MAX_SIZE) * set->dsize,
614 GFP_KERNEL);
615 if (!map)
616 return false;
617
618 map->size = size;
619 map->net = net;
620 set->data = map;
621
622 for (i = 0; i < size; i++) {
623 e = list_set_elem(set, map, i);
624 e->id = IPSET_INVALID_ID;
625 }
626
627 return true;
628 }
629
630 static int
list_set_create(struct net * net,struct ip_set * set,struct nlattr * tb[],u32 flags)631 list_set_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
632 u32 flags)
633 {
634 u32 size = IP_SET_LIST_DEFAULT_SIZE;
635
636 if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_SIZE) ||
637 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
638 !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
639 return -IPSET_ERR_PROTOCOL;
640
641 if (tb[IPSET_ATTR_SIZE])
642 size = ip_set_get_h32(tb[IPSET_ATTR_SIZE]);
643 if (size < IP_SET_LIST_MIN_SIZE)
644 size = IP_SET_LIST_MIN_SIZE;
645
646 set->variant = &set_variant;
647 set->dsize = ip_set_elem_len(set, tb, sizeof(struct set_elem));
648 if (!init_list_set(net, set, size))
649 return -ENOMEM;
650 if (tb[IPSET_ATTR_TIMEOUT]) {
651 set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
652 list_set_gc_init(set, list_set_gc);
653 }
654 return 0;
655 }
656
657 static struct ip_set_type list_set_type __read_mostly = {
658 .name = "list:set",
659 .protocol = IPSET_PROTOCOL,
660 .features = IPSET_TYPE_NAME | IPSET_DUMP_LAST,
661 .dimension = IPSET_DIM_ONE,
662 .family = NFPROTO_UNSPEC,
663 .revision_min = IPSET_TYPE_REV_MIN,
664 .revision_max = IPSET_TYPE_REV_MAX,
665 .create = list_set_create,
666 .create_policy = {
667 [IPSET_ATTR_SIZE] = { .type = NLA_U32 },
668 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
669 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
670 },
671 .adt_policy = {
672 [IPSET_ATTR_NAME] = { .type = NLA_STRING,
673 .len = IPSET_MAXNAMELEN },
674 [IPSET_ATTR_NAMEREF] = { .type = NLA_STRING,
675 .len = IPSET_MAXNAMELEN },
676 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
677 [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
678 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
679 [IPSET_ATTR_BYTES] = { .type = NLA_U64 },
680 [IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
681 [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
682 [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 },
683 [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 },
684 [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 },
685 },
686 .me = THIS_MODULE,
687 };
688
689 static int __init
list_set_init(void)690 list_set_init(void)
691 {
692 return ip_set_type_register(&list_set_type);
693 }
694
695 static void __exit
list_set_fini(void)696 list_set_fini(void)
697 {
698 ip_set_type_unregister(&list_set_type);
699 }
700
701 module_init(list_set_init);
702 module_exit(list_set_fini);
703