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