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