17d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik/* Copyright (C) 2008-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
2f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik *
3f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik * This program is free software; you can redistribute it and/or modify
4f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik * it under the terms of the GNU General Public License version 2 as
5f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik * published by the Free Software Foundation.
6f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik */
7f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
8f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik/* Kernel module implementing an IP set type: the list:set type */
9f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
10f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik#include <linux/module.h>
11f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik#include <linux/ip.h>
12f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik#include <linux/skbuff.h>
13f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik#include <linux/errno.h>
14f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
15f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik#include <linux/netfilter/ipset/ip_set.h>
16f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik#include <linux/netfilter/ipset/ip_set_list.h>
17f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
1835b8dcf8c3a0be1feb1c8b29b22e1685ba0c2e14Jozsef Kadlecsik#define IPSET_TYPE_REV_MIN	0
1981b10bb4bd16ea975c007f9bb2c2676cef6ade10Oliver Smith/*				1    Counters support added */
20cbee93d7b71bf9d73382e503a4f60848eec60ea8Anton Danilov/*				2    Comments support added */
21cbee93d7b71bf9d73382e503a4f60848eec60ea8Anton Danilov#define IPSET_TYPE_REV_MAX	3 /* skbinfo support added */
2210111a6ef373c377e87730749a0f68210c3fd062Jozsef Kadlecsik
23f830837f0eed0f9e371b8fd65169365780814bb1Jozsef KadlecsikMODULE_LICENSE("GPL");
24f830837f0eed0f9e371b8fd65169365780814bb1Jozsef KadlecsikMODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
2535b8dcf8c3a0be1feb1c8b29b22e1685ba0c2e14Jozsef KadlecsikIP_SET_MODULE_DESC("list:set", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
26f830837f0eed0f9e371b8fd65169365780814bb1Jozsef KadlecsikMODULE_ALIAS("ip_set_list:set");
27f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
287d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik/* Member elements  */
29f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsikstruct set_elem {
30f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	ip_set_id_t id;
31f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik};
32f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
337d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsikstruct set_adt_elem {
347d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	ip_set_id_t id;
357d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	ip_set_id_t refid;
367d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	int before;
377d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik};
387d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik
39f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik/* Type structure */
40f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsikstruct list_set {
41f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	u32 size;		/* size of set list array */
42f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	struct timer_list gc;	/* garbage collection */
431785e8f473082aa60d62c7165856cf6484077b99Vitaly Lavrov	struct net *net;	/* namespace */
44f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	struct set_elem members[0]; /* the set members */
45f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik};
46f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
47ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik#define list_set_elem(set, map, id)	\
48ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik	(struct set_elem *)((void *)(map)->members + (id) * (set)->dsize)
49f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
507d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsikstatic int
517d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsiklist_set_ktest(struct ip_set *set, const struct sk_buff *skb,
527d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	       const struct xt_action_param *par,
537d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	       struct ip_set_adt_opt *opt, const struct ip_set_ext *ext)
54f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik{
557d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	struct list_set *map = set->data;
567d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	struct set_elem *e;
576e01781d1c80e2e8263471252a631e86165b15c5Jozsef Kadlecsik	u32 i, cmdflags = opt->cmdflags;
587d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	int ret;
59f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
606e01781d1c80e2e8263471252a631e86165b15c5Jozsef Kadlecsik	/* Don't lookup sub-counters at all */
616e01781d1c80e2e8263471252a631e86165b15c5Jozsef Kadlecsik	opt->cmdflags &= ~IPSET_FLAG_MATCH_COUNTERS;
626e01781d1c80e2e8263471252a631e86165b15c5Jozsef Kadlecsik	if (opt->cmdflags & IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE)
636e01781d1c80e2e8263471252a631e86165b15c5Jozsef Kadlecsik		opt->cmdflags &= ~IPSET_FLAG_SKIP_COUNTER_UPDATE;
647d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	for (i = 0; i < map->size; i++) {
65ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik		e = list_set_elem(set, map, i);
667d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		if (e->id == IPSET_INVALID_ID)
677d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			return 0;
687d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		if (SET_WITH_TIMEOUT(set) &&
69ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik		    ip_set_timeout_expired(ext_timeout(e, set)))
707d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			continue;
717d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		ret = ip_set_test(e->id, skb, par, opt);
72de76303c5a30e4754cd566dd4b9f3c26170fcf26Jozsef Kadlecsik		if (ret > 0) {
73de76303c5a30e4754cd566dd4b9f3c26170fcf26Jozsef Kadlecsik			if (SET_WITH_COUNTER(set))
74ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik				ip_set_update_counter(ext_counter(e, set),
75de76303c5a30e4754cd566dd4b9f3c26170fcf26Jozsef Kadlecsik						      ext, &opt->ext,
766e01781d1c80e2e8263471252a631e86165b15c5Jozsef Kadlecsik						      cmdflags);
77cbee93d7b71bf9d73382e503a4f60848eec60ea8Anton Danilov			if (SET_WITH_SKBINFO(set))
78cbee93d7b71bf9d73382e503a4f60848eec60ea8Anton Danilov				ip_set_get_skbinfo(ext_skbinfo(e, set),
79cbee93d7b71bf9d73382e503a4f60848eec60ea8Anton Danilov						   ext, &opt->ext,
80cbee93d7b71bf9d73382e503a4f60848eec60ea8Anton Danilov						   cmdflags);
817d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			return ret;
82de76303c5a30e4754cd566dd4b9f3c26170fcf26Jozsef Kadlecsik		}
837d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	}
847d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	return 0;
85f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik}
86f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
877d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsikstatic int
887d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsiklist_set_kadd(struct ip_set *set, const struct sk_buff *skb,
897d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	      const struct xt_action_param *par,
907d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	      struct ip_set_adt_opt *opt, const struct ip_set_ext *ext)
91f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik{
927d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	struct list_set *map = set->data;
937d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	struct set_elem *e;
947d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	u32 i;
957d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	int ret;
96f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
977d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	for (i = 0; i < map->size; i++) {
98ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik		e = list_set_elem(set, map, i);
997d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		if (e->id == IPSET_INVALID_ID)
1007d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			return 0;
1017d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		if (SET_WITH_TIMEOUT(set) &&
102ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik		    ip_set_timeout_expired(ext_timeout(e, set)))
1037d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			continue;
1047d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		ret = ip_set_add(e->id, skb, par, opt);
1057d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		if (ret == 0)
1067d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			return ret;
1077d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	}
1087d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	return 0;
109f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik}
110f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
111f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsikstatic int
1127d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsiklist_set_kdel(struct ip_set *set, const struct sk_buff *skb,
113b66554cf03fe866b3fb7b9f40f430b8ba09f41c8Jozsef Kadlecsik	      const struct xt_action_param *par,
1147d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	      struct ip_set_adt_opt *opt, const struct ip_set_ext *ext)
115f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik{
116f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	struct list_set *map = set->data;
1177d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	struct set_elem *e;
118f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	u32 i;
119f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	int ret;
120f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
121f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	for (i = 0; i < map->size; i++) {
122ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik		e = list_set_elem(set, map, i);
1237d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		if (e->id == IPSET_INVALID_ID)
124f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik			return 0;
1257d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		if (SET_WITH_TIMEOUT(set) &&
126ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik		    ip_set_timeout_expired(ext_timeout(e, set)))
127f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik			continue;
1287d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		ret = ip_set_del(e->id, skb, par, opt);
1297d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		if (ret == 0)
1307d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			return ret;
1317d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	}
1327d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	return 0;
1337d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik}
1347d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik
1357d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsikstatic int
1367d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsiklist_set_kadt(struct ip_set *set, const struct sk_buff *skb,
1377d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	      const struct xt_action_param *par,
1387d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	      enum ipset_adt adt, struct ip_set_adt_opt *opt)
1397d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik{
140ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
1417d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik
1427d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	switch (adt) {
1437d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	case IPSET_TEST:
1447d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		return list_set_ktest(set, skb, par, opt, &ext);
1457d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	case IPSET_ADD:
1467d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		return list_set_kadd(set, skb, par, opt, &ext);
1477d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	case IPSET_DEL:
1487d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		return list_set_kdel(set, skb, par, opt, &ext);
1497d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	default:
1507d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		break;
151f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	}
152f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	return -EINVAL;
153f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik}
154f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
155f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsikstatic bool
1567d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsikid_eq(const struct ip_set *set, u32 i, ip_set_id_t id)
157f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik{
1587d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	const struct list_set *map = set->data;
1597d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	const struct set_elem *e;
1607d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik
1617d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	if (i >= map->size)
1627d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		return 0;
163f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
164ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik	e = list_set_elem(set, map, i);
1657d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	return !!(e->id == id &&
1667d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		 !(SET_WITH_TIMEOUT(set) &&
167ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik		   ip_set_timeout_expired(ext_timeout(e, set))));
1687d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik}
1697d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik
1707d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsikstatic int
1717d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsiklist_set_add(struct ip_set *set, u32 i, struct set_adt_elem *d,
1727d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	     const struct ip_set_ext *ext)
1737d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik{
1747d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	struct list_set *map = set->data;
175ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik	struct set_elem *e = list_set_elem(set, map, i);
1767d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik
1777d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	if (e->id != IPSET_INVALID_ID) {
17840cd63bf33b21ef4d43776b1d49c605f876fe32cJozsef Kadlecsik		if (i == map->size - 1) {
1797d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			/* Last element replaced: e.g. add new,before,last */
1801785e8f473082aa60d62c7165856cf6484077b99Vitaly Lavrov			ip_set_put_byindex(map->net, e->id);
18140cd63bf33b21ef4d43776b1d49c605f876fe32cJozsef Kadlecsik			ip_set_ext_destroy(set, e);
18240cd63bf33b21ef4d43776b1d49c605f876fe32cJozsef Kadlecsik		} else {
183ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik			struct set_elem *x = list_set_elem(set, map,
184ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik							   map->size - 1);
1857d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik
1867d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			/* Last element pushed off */
18740cd63bf33b21ef4d43776b1d49c605f876fe32cJozsef Kadlecsik			if (x->id != IPSET_INVALID_ID) {
1881785e8f473082aa60d62c7165856cf6484077b99Vitaly Lavrov				ip_set_put_byindex(map->net, x->id);
18940cd63bf33b21ef4d43776b1d49c605f876fe32cJozsef Kadlecsik				ip_set_ext_destroy(set, x);
19040cd63bf33b21ef4d43776b1d49c605f876fe32cJozsef Kadlecsik			}
191ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik			memmove(list_set_elem(set, map, i + 1), e,
192ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik				set->dsize * (map->size - (i + 1)));
1938ec81f9a4db94fa5638c55793365b896dd9daeccJozsef Kadlecsik			/* Extensions must be initialized to zero */
1948ec81f9a4db94fa5638c55793365b896dd9daeccJozsef Kadlecsik			memset(e, 0, set->dsize);
1957d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		}
1965416219e5ca4504ea80d662fdda7337e52e86ee5Jozsef Kadlecsik	}
1975416219e5ca4504ea80d662fdda7337e52e86ee5Jozsef Kadlecsik
1987d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	e->id = d->id;
1997d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	if (SET_WITH_TIMEOUT(set))
200ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik		ip_set_timeout_set(ext_timeout(e, set), ext->timeout);
201de76303c5a30e4754cd566dd4b9f3c26170fcf26Jozsef Kadlecsik	if (SET_WITH_COUNTER(set))
202ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik		ip_set_init_counter(ext_counter(e, set), ext);
2038ec81f9a4db94fa5638c55793365b896dd9daeccJozsef Kadlecsik	if (SET_WITH_COMMENT(set))
20481b10bb4bd16ea975c007f9bb2c2676cef6ade10Oliver Smith		ip_set_init_comment(ext_comment(e, set), ext);
205cbee93d7b71bf9d73382e503a4f60848eec60ea8Anton Danilov	if (SET_WITH_SKBINFO(set))
206cbee93d7b71bf9d73382e503a4f60848eec60ea8Anton Danilov		ip_set_init_skbinfo(ext_skbinfo(e, set), ext);
2075416219e5ca4504ea80d662fdda7337e52e86ee5Jozsef Kadlecsik	return 0;
2085416219e5ca4504ea80d662fdda7337e52e86ee5Jozsef Kadlecsik}
2095416219e5ca4504ea80d662fdda7337e52e86ee5Jozsef Kadlecsik
2107d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsikstatic int
2117d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsiklist_set_del(struct ip_set *set, u32 i)
2125416219e5ca4504ea80d662fdda7337e52e86ee5Jozsef Kadlecsik{
2137d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	struct list_set *map = set->data;
214ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik	struct set_elem *e = list_set_elem(set, map, i);
2155416219e5ca4504ea80d662fdda7337e52e86ee5Jozsef Kadlecsik
2161785e8f473082aa60d62c7165856cf6484077b99Vitaly Lavrov	ip_set_put_byindex(map->net, e->id);
21740cd63bf33b21ef4d43776b1d49c605f876fe32cJozsef Kadlecsik	ip_set_ext_destroy(set, e);
218f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
2197d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	if (i < map->size - 1)
220ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik		memmove(e, list_set_elem(set, map, i + 1),
221ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik			set->dsize * (map->size - (i + 1)));
2227d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik
2237d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	/* Last element */
224ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik	e = list_set_elem(set, map, map->size - 1);
2257d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	e->id = IPSET_INVALID_ID;
226f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	return 0;
227f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik}
228f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
229f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsikstatic void
2307d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsikset_cleanup_entries(struct ip_set *set)
231f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik{
2327d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	struct list_set *map = set->data;
233f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	struct set_elem *e;
234b91b396d5e35eef9938a56e781cb0171a53907caJozsef Kadlecsik	u32 i = 0;
235f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
236b91b396d5e35eef9938a56e781cb0171a53907caJozsef Kadlecsik	while (i < map->size) {
237ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik		e = list_set_elem(set, map, i);
2387d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		if (e->id != IPSET_INVALID_ID &&
239ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik		    ip_set_timeout_expired(ext_timeout(e, set)))
2407d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			list_set_del(set, i);
241b91b396d5e35eef9938a56e781cb0171a53907caJozsef Kadlecsik			/* Check element moved to position i in next loop */
242b91b396d5e35eef9938a56e781cb0171a53907caJozsef Kadlecsik		else
243b91b396d5e35eef9938a56e781cb0171a53907caJozsef Kadlecsik			i++;
244f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	}
245f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik}
246f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
2477d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsikstatic int
2487d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsiklist_set_utest(struct ip_set *set, void *value, const struct ip_set_ext *ext,
2497d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	       struct ip_set_ext *mext, u32 flags)
250f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik{
2517d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	struct list_set *map = set->data;
2527d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	struct set_adt_elem *d = value;
2537d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	struct set_elem *e;
2547d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	u32 i;
2557d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	int ret;
256f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
2577d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	for (i = 0; i < map->size; i++) {
258ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik		e = list_set_elem(set, map, i);
259f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		if (e->id == IPSET_INVALID_ID)
2607d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			return 0;
2617d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		else if (SET_WITH_TIMEOUT(set) &&
262ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik			 ip_set_timeout_expired(ext_timeout(e, set)))
2637d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			continue;
2647d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		else if (e->id != d->id)
2657d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			continue;
2667d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik
2677d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		if (d->before == 0)
2687d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			return 1;
2697d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		else if (d->before > 0)
2707d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			ret = id_eq(set, i + 1, d->refid);
2717d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		else
2727d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			ret = i > 0 && id_eq(set, i - 1, d->refid);
2737d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		return ret;
274f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	}
2757d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	return 0;
276f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik}
277f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
2787d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik
279f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsikstatic int
2807d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsiklist_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext,
2817d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	      struct ip_set_ext *mext, u32 flags)
282f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik{
2837d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	struct list_set *map = set->data;
2847d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	struct set_adt_elem *d = value;
2857d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	struct set_elem *e;
2867d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	bool flag_exist = flags & IPSET_FLAG_EXIST;
2877d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	u32 i, ret = 0;
288f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
28940cd63bf33b21ef4d43776b1d49c605f876fe32cJozsef Kadlecsik	if (SET_WITH_TIMEOUT(set))
29040cd63bf33b21ef4d43776b1d49c605f876fe32cJozsef Kadlecsik		set_cleanup_entries(set);
29140cd63bf33b21ef4d43776b1d49c605f876fe32cJozsef Kadlecsik
2927d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	/* Check already added element */
2937d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	for (i = 0; i < map->size; i++) {
294ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik		e = list_set_elem(set, map, i);
2957d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		if (e->id == IPSET_INVALID_ID)
2967d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			goto insert;
2977d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		else if (e->id != d->id)
2987d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			continue;
29902f815cb6d3f57914228be84df9613ee5a01c2e6Jozsef Kadlecsik
3007d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		if ((d->before > 1 && !id_eq(set, i + 1, d->refid)) ||
3017d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		    (d->before < 0 &&
3027d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		     (i == 0 || !id_eq(set, i - 1, d->refid))))
3037d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			/* Before/after doesn't match */
3047d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			return -IPSET_ERR_REF_EXIST;
3057d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		if (!flag_exist)
3067d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			/* Can't re-add */
3077d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			return -IPSET_ERR_EXIST;
3087d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		/* Update extensions */
30940cd63bf33b21ef4d43776b1d49c605f876fe32cJozsef Kadlecsik		ip_set_ext_destroy(set, e);
31040cd63bf33b21ef4d43776b1d49c605f876fe32cJozsef Kadlecsik
3117d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		if (SET_WITH_TIMEOUT(set))
312ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik			ip_set_timeout_set(ext_timeout(e, set), ext->timeout);
313de76303c5a30e4754cd566dd4b9f3c26170fcf26Jozsef Kadlecsik		if (SET_WITH_COUNTER(set))
314ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik			ip_set_init_counter(ext_counter(e, set), ext);
31581b10bb4bd16ea975c007f9bb2c2676cef6ade10Oliver Smith		if (SET_WITH_COMMENT(set))
31681b10bb4bd16ea975c007f9bb2c2676cef6ade10Oliver Smith			ip_set_init_comment(ext_comment(e, set), ext);
317cbee93d7b71bf9d73382e503a4f60848eec60ea8Anton Danilov		if (SET_WITH_SKBINFO(set))
318cbee93d7b71bf9d73382e503a4f60848eec60ea8Anton Danilov			ip_set_init_skbinfo(ext_skbinfo(e, set), ext);
3197d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		/* Set is already added to the list */
3201785e8f473082aa60d62c7165856cf6484077b99Vitaly Lavrov		ip_set_put_byindex(map->net, d->id);
3217d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		return 0;
3227d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	}
3237d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsikinsert:
3247d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	ret = -IPSET_ERR_LIST_FULL;
3257d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	for (i = 0; i < map->size && ret == -IPSET_ERR_LIST_FULL; i++) {
326ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik		e = list_set_elem(set, map, i);
3277d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		if (e->id == IPSET_INVALID_ID)
3287d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			ret = d->before != 0 ? -IPSET_ERR_REF_EXIST
3297d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik				: list_set_add(set, i, d, ext);
3307d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		else if (e->id != d->refid)
3317d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			continue;
3327d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		else if (d->before > 0)
3337d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			ret = list_set_add(set, i, d, ext);
3347d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		else if (i + 1 < map->size)
3357d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			ret = list_set_add(set, i + 1, d, ext);
33602f815cb6d3f57914228be84df9613ee5a01c2e6Jozsef Kadlecsik	}
337f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
3387d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	return ret;
339f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik}
340f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
341f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsikstatic int
3427d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsiklist_set_udel(struct ip_set *set, void *value, const struct ip_set_ext *ext,
3437d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	      struct ip_set_ext *mext, u32 flags)
344f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik{
3457d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	struct list_set *map = set->data;
3467d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	struct set_adt_elem *d = value;
3477d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	struct set_elem *e;
3485416219e5ca4504ea80d662fdda7337e52e86ee5Jozsef Kadlecsik	u32 i;
3495416219e5ca4504ea80d662fdda7337e52e86ee5Jozsef Kadlecsik
3505416219e5ca4504ea80d662fdda7337e52e86ee5Jozsef Kadlecsik	for (i = 0; i < map->size; i++) {
351ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik		e = list_set_elem(set, map, i);
3527d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		if (e->id == IPSET_INVALID_ID)
3537d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			return d->before != 0 ? -IPSET_ERR_REF_EXIST
3547d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik					      : -IPSET_ERR_EXIST;
3557d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		else if (SET_WITH_TIMEOUT(set) &&
356ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik			 ip_set_timeout_expired(ext_timeout(e, set)))
3577d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			continue;
3587d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		else if (e->id != d->id)
3597d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			continue;
3607d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik
3617d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		if (d->before == 0)
3627d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			return list_set_del(set, i);
3637d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		else if (d->before > 0) {
3647d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			if (!id_eq(set, i + 1, d->refid))
3657d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik				return -IPSET_ERR_REF_EXIST;
3667d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			return list_set_del(set, i);
3677d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		} else if (i == 0 || !id_eq(set, i - 1, d->refid))
3687d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			return -IPSET_ERR_REF_EXIST;
3697d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		else
3707d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			return list_set_del(set, i);
3715416219e5ca4504ea80d662fdda7337e52e86ee5Jozsef Kadlecsik	}
3727d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	return -IPSET_ERR_EXIST;
3735416219e5ca4504ea80d662fdda7337e52e86ee5Jozsef Kadlecsik}
3745416219e5ca4504ea80d662fdda7337e52e86ee5Jozsef Kadlecsik
375f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsikstatic int
376f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsiklist_set_uadt(struct ip_set *set, struct nlattr *tb[],
3773d14b171f004f75c2d1e82e10545966f94132705Jozsef Kadlecsik	      enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
378f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik{
3791785e8f473082aa60d62c7165856cf6484077b99Vitaly Lavrov	struct list_set *map = set->data;
3807d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	ipset_adtfn adtfn = set->variant->adt[adt];
3817d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	struct set_adt_elem e = { .refid = IPSET_INVALID_ID };
382ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik	struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
383f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	struct ip_set *s;
384f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	int ret = 0;
385f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
386f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	if (unlikely(!tb[IPSET_ATTR_NAME] ||
387f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
388de76303c5a30e4754cd566dd4b9f3c26170fcf26Jozsef Kadlecsik		     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
389de76303c5a30e4754cd566dd4b9f3c26170fcf26Jozsef Kadlecsik		     !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
390cbee93d7b71bf9d73382e503a4f60848eec60ea8Anton Danilov		     !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) ||
391cbee93d7b71bf9d73382e503a4f60848eec60ea8Anton Danilov		     !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) ||
392cbee93d7b71bf9d73382e503a4f60848eec60ea8Anton Danilov		     !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) ||
393cbee93d7b71bf9d73382e503a4f60848eec60ea8Anton Danilov		     !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE)))
394f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		return -IPSET_ERR_PROTOCOL;
395f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
396f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	if (tb[IPSET_ATTR_LINENO])
397f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
398f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
3997d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	ret = ip_set_get_extensions(set, tb, &ext);
4007d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	if (ret)
4017d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		return ret;
4021785e8f473082aa60d62c7165856cf6484077b99Vitaly Lavrov	e.id = ip_set_get_byname(map->net, nla_data(tb[IPSET_ATTR_NAME]), &s);
4037d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	if (e.id == IPSET_INVALID_ID)
404f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		return -IPSET_ERR_NAME;
405f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	/* "Loop detection" */
406f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	if (s->type->features & IPSET_TYPE_NAME) {
407f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		ret = -IPSET_ERR_LOOP;
408f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		goto finish;
409f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	}
410f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
411f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	if (tb[IPSET_ATTR_CADT_FLAGS]) {
412f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		u32 f = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
4137d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		e.before = f & IPSET_FLAG_BEFORE;
414f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	}
415f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
4167d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	if (e.before && !tb[IPSET_ATTR_NAMEREF]) {
417f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		ret = -IPSET_ERR_BEFORE;
418f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		goto finish;
419f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	}
420f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
421f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	if (tb[IPSET_ATTR_NAMEREF]) {
4221785e8f473082aa60d62c7165856cf6484077b99Vitaly Lavrov		e.refid = ip_set_get_byname(map->net,
4231785e8f473082aa60d62c7165856cf6484077b99Vitaly Lavrov					    nla_data(tb[IPSET_ATTR_NAMEREF]),
4247d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik					    &s);
4257d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		if (e.refid == IPSET_INVALID_ID) {
426f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik			ret = -IPSET_ERR_NAMEREF;
427f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik			goto finish;
428f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		}
4297d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		if (!e.before)
4307d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			e.before = -1;
431f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	}
4327d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	if (adt != IPSET_TEST && SET_WITH_TIMEOUT(set))
4337d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		set_cleanup_entries(set);
434f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
4357d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	ret = adtfn(set, &e, &ext, &ext, flags);
436f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
437f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsikfinish:
4387d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	if (e.refid != IPSET_INVALID_ID)
4391785e8f473082aa60d62c7165856cf6484077b99Vitaly Lavrov		ip_set_put_byindex(map->net, e.refid);
440f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	if (adt != IPSET_ADD || ret)
4411785e8f473082aa60d62c7165856cf6484077b99Vitaly Lavrov		ip_set_put_byindex(map->net, e.id);
442f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
443f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	return ip_set_eexist(ret, flags) ? 0 : ret;
444f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik}
445f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
446f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsikstatic void
447f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsiklist_set_flush(struct ip_set *set)
448f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik{
449f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	struct list_set *map = set->data;
4507d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	struct set_elem *e;
451f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	u32 i;
452f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
453f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	for (i = 0; i < map->size; i++) {
454ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik		e = list_set_elem(set, map, i);
4557d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		if (e->id != IPSET_INVALID_ID) {
4561785e8f473082aa60d62c7165856cf6484077b99Vitaly Lavrov			ip_set_put_byindex(map->net, e->id);
45740cd63bf33b21ef4d43776b1d49c605f876fe32cJozsef Kadlecsik			ip_set_ext_destroy(set, e);
4587d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik			e->id = IPSET_INVALID_ID;
459f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		}
460f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	}
461f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik}
462f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
463f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsikstatic void
464f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsiklist_set_destroy(struct ip_set *set)
465f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik{
466f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	struct list_set *map = set->data;
467f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
4687d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	if (SET_WITH_TIMEOUT(set))
469f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		del_timer_sync(&map->gc);
470f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	list_set_flush(set);
471f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	kfree(map);
472f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
473f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	set->data = NULL;
474f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik}
475f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
476f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsikstatic int
477f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsiklist_set_head(struct ip_set *set, struct sk_buff *skb)
478f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik{
479f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	const struct list_set *map = set->data;
480f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	struct nlattr *nested;
481f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
482f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
483f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	if (!nested)
484f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		goto nla_put_failure;
4857cf7899d9ee31c88c86ea8459fc4db4bd11cc240David S. Miller	if (nla_put_net32(skb, IPSET_ATTR_SIZE, htonl(map->size)) ||
4867cf7899d9ee31c88c86ea8459fc4db4bd11cc240David S. Miller	    nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
4877cf7899d9ee31c88c86ea8459fc4db4bd11cc240David S. Miller	    nla_put_net32(skb, IPSET_ATTR_MEMSIZE,
488ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik			  htonl(sizeof(*map) + map->size * set->dsize)))
4897cf7899d9ee31c88c86ea8459fc4db4bd11cc240David S. Miller		goto nla_put_failure;
49081b10bb4bd16ea975c007f9bb2c2676cef6ade10Oliver Smith	if (unlikely(ip_set_put_flags(skb, set)))
49181b10bb4bd16ea975c007f9bb2c2676cef6ade10Oliver Smith		goto nla_put_failure;
492f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	ipset_nest_end(skb, nested);
493f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
494f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	return 0;
495f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsiknla_put_failure:
496f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	return -EMSGSIZE;
497f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik}
498f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
499f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsikstatic int
500f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsiklist_set_list(const struct ip_set *set,
501f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	      struct sk_buff *skb, struct netlink_callback *cb)
502f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik{
503f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	const struct list_set *map = set->data;
504f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	struct nlattr *atd, *nested;
50593302880d8a3e5dc6b7da3f9825beb839152c940Jozsef Kadlecsik	u32 i, first = cb->args[IPSET_CB_ARG0];
506f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	const struct set_elem *e;
507f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
508f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
509f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	if (!atd)
510f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		return -EMSGSIZE;
51193302880d8a3e5dc6b7da3f9825beb839152c940Jozsef Kadlecsik	for (; cb->args[IPSET_CB_ARG0] < map->size;
51293302880d8a3e5dc6b7da3f9825beb839152c940Jozsef Kadlecsik	     cb->args[IPSET_CB_ARG0]++) {
51393302880d8a3e5dc6b7da3f9825beb839152c940Jozsef Kadlecsik		i = cb->args[IPSET_CB_ARG0];
514ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik		e = list_set_elem(set, map, i);
515f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		if (e->id == IPSET_INVALID_ID)
516f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik			goto finish;
5177d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		if (SET_WITH_TIMEOUT(set) &&
518ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik		    ip_set_timeout_expired(ext_timeout(e, set)))
519f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik			continue;
520f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
521f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		if (!nested) {
522f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik			if (i == first) {
523f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik				nla_nest_cancel(skb, atd);
524f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik				return -EMSGSIZE;
525f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik			} else
526f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik				goto nla_put_failure;
527f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		}
5287cf7899d9ee31c88c86ea8459fc4db4bd11cc240David S. Miller		if (nla_put_string(skb, IPSET_ATTR_NAME,
5291785e8f473082aa60d62c7165856cf6484077b99Vitaly Lavrov				   ip_set_name_byindex(map->net, e->id)))
5307cf7899d9ee31c88c86ea8459fc4db4bd11cc240David S. Miller			goto nla_put_failure;
5313fd986b3d99e3847f1cce6fc36043d0f16508e1dJozsef Kadlecsik		if (ip_set_put_extensions(skb, set, e, true))
53281b10bb4bd16ea975c007f9bb2c2676cef6ade10Oliver Smith			goto nla_put_failure;
533f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		ipset_nest_end(skb, nested);
534f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	}
535f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsikfinish:
536f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	ipset_nest_end(skb, atd);
537f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	/* Set listing finished */
53893302880d8a3e5dc6b7da3f9825beb839152c940Jozsef Kadlecsik	cb->args[IPSET_CB_ARG0] = 0;
539f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	return 0;
540f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
541f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsiknla_put_failure:
542f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	nla_nest_cancel(skb, nested);
543f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	if (unlikely(i == first)) {
54493302880d8a3e5dc6b7da3f9825beb839152c940Jozsef Kadlecsik		cb->args[IPSET_CB_ARG0] = 0;
545f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		return -EMSGSIZE;
546f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	}
547122ebbf24c33ac13a9243248c9b8da0fa4c012bdJozsef Kadlecsik	ipset_nest_end(skb, atd);
548f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	return 0;
549f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik}
550f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
551f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsikstatic bool
552f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsiklist_set_same_set(const struct ip_set *a, const struct ip_set *b)
553f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik{
554f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	const struct list_set *x = a->data;
555f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	const struct list_set *y = b->data;
556f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
557f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	return x->size == y->size &&
558ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik	       a->timeout == b->timeout &&
5597d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	       a->extensions == b->extensions;
560f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik}
561f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
5627d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsikstatic const struct ip_set_type_variant set_variant = {
563f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	.kadt	= list_set_kadt,
564f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	.uadt	= list_set_uadt,
5657d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	.adt	= {
5667d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		[IPSET_ADD] = list_set_uadd,
5677d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		[IPSET_DEL] = list_set_udel,
5687d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		[IPSET_TEST] = list_set_utest,
5697d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	},
570f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	.destroy = list_set_destroy,
571f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	.flush	= list_set_flush,
572f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	.head	= list_set_head,
573f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	.list	= list_set_list,
574f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	.same_set = list_set_same_set,
575f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik};
576f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
577f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsikstatic void
578f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsiklist_set_gc(unsigned long ul_set)
579f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik{
580f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	struct ip_set *set = (struct ip_set *) ul_set;
581f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	struct list_set *map = set->data;
5822f9f28b212a2bd4948c8ceaaec33ce0123632129Jozsef Kadlecsik
583512d06b5b64fb422d90f199b1be188082729edf9Jozsef Kadlecsik	write_lock_bh(&set->lock);
5847d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	set_cleanup_entries(set);
585512d06b5b64fb422d90f199b1be188082729edf9Jozsef Kadlecsik	write_unlock_bh(&set->lock);
586f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
587ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik	map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;
588f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	add_timer(&map->gc);
589f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik}
590f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
591f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsikstatic void
5927d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsiklist_set_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))
593f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik{
594f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	struct list_set *map = set->data;
595f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
596f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	init_timer(&map->gc);
597f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	map->gc.data = (unsigned long) set;
5987d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	map->gc.function = gc;
599ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik	map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;
600f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	add_timer(&map->gc);
601f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik}
602f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
603f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik/* Create list:set type of sets */
604f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
60503c8b234e61a9a3aab8d970b3bf681934ecfe443Jozsef Kadlecsikstatic bool
6061785e8f473082aa60d62c7165856cf6484077b99Vitaly Lavrovinit_list_set(struct net *net, struct ip_set *set, u32 size)
607f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik{
608f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	struct list_set *map;
609f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	struct set_elem *e;
610f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	u32 i;
611f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
6121b05756c48ea07ced9604ef01d11194d936da163Jozsef Kadlecsik	map = kzalloc(sizeof(*map) +
6131b05756c48ea07ced9604ef01d11194d936da163Jozsef Kadlecsik		      min_t(u32, size, IP_SET_LIST_MAX_SIZE) * set->dsize,
6141b05756c48ea07ced9604ef01d11194d936da163Jozsef Kadlecsik		      GFP_KERNEL);
615f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	if (!map)
61603c8b234e61a9a3aab8d970b3bf681934ecfe443Jozsef Kadlecsik		return false;
617f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
618f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	map->size = size;
6191785e8f473082aa60d62c7165856cf6484077b99Vitaly Lavrov	map->net = net;
620f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	set->data = map;
621f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
622f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	for (i = 0; i < size; i++) {
623ca134ce86451f3f5ac45ffbf1494a1f42110bf93Jozsef Kadlecsik		e = list_set_elem(set, map, i);
624f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		e->id = IPSET_INVALID_ID;
625f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	}
626f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
62703c8b234e61a9a3aab8d970b3bf681934ecfe443Jozsef Kadlecsik	return true;
628f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik}
629f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
630f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsikstatic int
6311785e8f473082aa60d62c7165856cf6484077b99Vitaly Lavrovlist_set_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
6321785e8f473082aa60d62c7165856cf6484077b99Vitaly Lavrov		u32 flags)
633f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik{
63403c8b234e61a9a3aab8d970b3bf681934ecfe443Jozsef Kadlecsik	u32 size = IP_SET_LIST_DEFAULT_SIZE;
635f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
636f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_SIZE) ||
637de76303c5a30e4754cd566dd4b9f3c26170fcf26Jozsef Kadlecsik		     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
638de76303c5a30e4754cd566dd4b9f3c26170fcf26Jozsef Kadlecsik		     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
639f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		return -IPSET_ERR_PROTOCOL;
640f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
641f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	if (tb[IPSET_ATTR_SIZE])
642f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		size = ip_set_get_h32(tb[IPSET_ATTR_SIZE]);
643f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	if (size < IP_SET_LIST_MIN_SIZE)
644f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		size = IP_SET_LIST_MIN_SIZE;
645f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
6467d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik	set->variant = &set_variant;
64703c8b234e61a9a3aab8d970b3bf681934ecfe443Jozsef Kadlecsik	set->dsize = ip_set_elem_len(set, tb, sizeof(struct set_elem));
6481785e8f473082aa60d62c7165856cf6484077b99Vitaly Lavrov	if (!init_list_set(net, set, size))
64903c8b234e61a9a3aab8d970b3bf681934ecfe443Jozsef Kadlecsik		return -ENOMEM;
65003c8b234e61a9a3aab8d970b3bf681934ecfe443Jozsef Kadlecsik	if (tb[IPSET_ATTR_TIMEOUT]) {
65103c8b234e61a9a3aab8d970b3bf681934ecfe443Jozsef Kadlecsik		set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
6527d47d972b5d154e143bb24a795af92bbb3c95532Jozsef Kadlecsik		list_set_gc_init(set, list_set_gc);
653f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	}
654f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	return 0;
655f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik}
656f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
657f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsikstatic struct ip_set_type list_set_type __read_mostly = {
658f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	.name		= "list:set",
659f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	.protocol	= IPSET_PROTOCOL,
660f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	.features	= IPSET_TYPE_NAME | IPSET_DUMP_LAST,
661f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	.dimension	= IPSET_DIM_ONE,
662c15f1c83251049182b1771da004d14f29683ab97Jan Engelhardt	.family		= NFPROTO_UNSPEC,
66335b8dcf8c3a0be1feb1c8b29b22e1685ba0c2e14Jozsef Kadlecsik	.revision_min	= IPSET_TYPE_REV_MIN,
66435b8dcf8c3a0be1feb1c8b29b22e1685ba0c2e14Jozsef Kadlecsik	.revision_max	= IPSET_TYPE_REV_MAX,
665f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	.create		= list_set_create,
666f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	.create_policy	= {
667f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		[IPSET_ATTR_SIZE]	= { .type = NLA_U32 },
668f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		[IPSET_ATTR_TIMEOUT]	= { .type = NLA_U32 },
669de76303c5a30e4754cd566dd4b9f3c26170fcf26Jozsef Kadlecsik		[IPSET_ATTR_CADT_FLAGS]	= { .type = NLA_U32 },
670f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	},
671f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	.adt_policy	= {
672f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		[IPSET_ATTR_NAME]	= { .type = NLA_STRING,
673f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik					    .len = IPSET_MAXNAMELEN },
674f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		[IPSET_ATTR_NAMEREF]	= { .type = NLA_STRING,
675f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik					    .len = IPSET_MAXNAMELEN },
676f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		[IPSET_ATTR_TIMEOUT]	= { .type = NLA_U32 },
677f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		[IPSET_ATTR_LINENO]	= { .type = NLA_U32 },
678f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik		[IPSET_ATTR_CADT_FLAGS]	= { .type = NLA_U32 },
679de76303c5a30e4754cd566dd4b9f3c26170fcf26Jozsef Kadlecsik		[IPSET_ATTR_BYTES]	= { .type = NLA_U64 },
680de76303c5a30e4754cd566dd4b9f3c26170fcf26Jozsef Kadlecsik		[IPSET_ATTR_PACKETS]	= { .type = NLA_U64 },
68181b10bb4bd16ea975c007f9bb2c2676cef6ade10Oliver Smith		[IPSET_ATTR_COMMENT]	= { .type = NLA_NUL_STRING },
682cbee93d7b71bf9d73382e503a4f60848eec60ea8Anton Danilov		[IPSET_ATTR_SKBMARK]	= { .type = NLA_U64 },
683cbee93d7b71bf9d73382e503a4f60848eec60ea8Anton Danilov		[IPSET_ATTR_SKBPRIO]	= { .type = NLA_U32 },
684cbee93d7b71bf9d73382e503a4f60848eec60ea8Anton Danilov		[IPSET_ATTR_SKBQUEUE]	= { .type = NLA_U16 },
685f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	},
686f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	.me		= THIS_MODULE,
687f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik};
688f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
689f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsikstatic int __init
690f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsiklist_set_init(void)
691f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik{
692f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	return ip_set_type_register(&list_set_type);
693f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik}
694f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
695f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsikstatic void __exit
696f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsiklist_set_fini(void)
697f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik{
698f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik	ip_set_type_unregister(&list_set_type);
699f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik}
700f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsik
701f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsikmodule_init(list_set_init);
702f830837f0eed0f9e371b8fd65169365780814bb1Jozsef Kadlecsikmodule_exit(list_set_fini);
703