xref: /openbmc/linux/net/netfilter/xt_set.c (revision ca0f6a5c)
1d956798dSJozsef Kadlecsik /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
2d956798dSJozsef Kadlecsik  *                         Patrick Schaaf <bof@bof.de>
3d956798dSJozsef Kadlecsik  *                         Martin Josefsson <gandalf@wlug.westbo.se>
4075e64c0SJozsef Kadlecsik  * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
5d956798dSJozsef Kadlecsik  *
6d956798dSJozsef Kadlecsik  * This program is free software; you can redistribute it and/or modify
7d956798dSJozsef Kadlecsik  * it under the terms of the GNU General Public License version 2 as
8d956798dSJozsef Kadlecsik  * published by the Free Software Foundation.
9d956798dSJozsef Kadlecsik  */
10d956798dSJozsef Kadlecsik 
11d956798dSJozsef Kadlecsik /* Kernel module which implements the set match and SET target
12ca0f6a5cSJozsef Kadlecsik  * for netfilter/iptables.
13ca0f6a5cSJozsef Kadlecsik  */
14d956798dSJozsef Kadlecsik 
15d956798dSJozsef Kadlecsik #include <linux/module.h>
16d956798dSJozsef Kadlecsik #include <linux/skbuff.h>
17d956798dSJozsef Kadlecsik 
18d956798dSJozsef Kadlecsik #include <linux/netfilter/x_tables.h>
19a9756e6fSJozsef Kadlecsik #include <linux/netfilter/ipset/ip_set.h>
20a73f89a6SJozsef Kadlecsik #include <linux/netfilter/ipset/ip_set_timeout.h>
21a9756e6fSJozsef Kadlecsik #include <uapi/linux/netfilter/xt_set.h>
22d956798dSJozsef Kadlecsik 
23d956798dSJozsef Kadlecsik MODULE_LICENSE("GPL");
24d956798dSJozsef Kadlecsik MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
25d956798dSJozsef Kadlecsik MODULE_DESCRIPTION("Xtables: IP set match and target module");
26d956798dSJozsef Kadlecsik MODULE_ALIAS("xt_SET");
27d956798dSJozsef Kadlecsik MODULE_ALIAS("ipt_set");
28d956798dSJozsef Kadlecsik MODULE_ALIAS("ip6t_set");
29d956798dSJozsef Kadlecsik MODULE_ALIAS("ipt_SET");
30d956798dSJozsef Kadlecsik MODULE_ALIAS("ip6t_SET");
31d956798dSJozsef Kadlecsik 
32d956798dSJozsef Kadlecsik static inline int
33d956798dSJozsef Kadlecsik match_set(ip_set_id_t index, const struct sk_buff *skb,
34b66554cfSJozsef Kadlecsik 	  const struct xt_action_param *par,
35075e64c0SJozsef Kadlecsik 	  struct ip_set_adt_opt *opt, int inv)
36d956798dSJozsef Kadlecsik {
37b66554cfSJozsef Kadlecsik 	if (ip_set_test(index, skb, par, opt))
38d956798dSJozsef Kadlecsik 		inv = !inv;
39d956798dSJozsef Kadlecsik 	return inv;
40d956798dSJozsef Kadlecsik }
41d956798dSJozsef Kadlecsik 
42ac8cc925SJozsef Kadlecsik #define ADT_OPT(n, f, d, fs, cfs, t)	\
43127f5591SJozsef Kadlecsik struct ip_set_adt_opt n = {		\
44127f5591SJozsef Kadlecsik 	.family	= f,			\
45127f5591SJozsef Kadlecsik 	.dim = d,			\
46127f5591SJozsef Kadlecsik 	.flags = fs,			\
47127f5591SJozsef Kadlecsik 	.cmdflags = cfs,		\
48075e64c0SJozsef Kadlecsik 	.ext.timeout = t,		\
49127f5591SJozsef Kadlecsik }
50ac8cc925SJozsef Kadlecsik 
51d956798dSJozsef Kadlecsik /* Revision 0 interface: backward compatible with netfilter/iptables */
52d956798dSJozsef Kadlecsik 
53d956798dSJozsef Kadlecsik static bool
54d956798dSJozsef Kadlecsik set_match_v0(const struct sk_buff *skb, struct xt_action_param *par)
55d956798dSJozsef Kadlecsik {
56d956798dSJozsef Kadlecsik 	const struct xt_set_info_match_v0 *info = par->matchinfo;
57ca0f6a5cSJozsef Kadlecsik 
58ac8cc925SJozsef Kadlecsik 	ADT_OPT(opt, par->family, info->match_set.u.compat.dim,
59ac8cc925SJozsef Kadlecsik 		info->match_set.u.compat.flags, 0, UINT_MAX);
60d956798dSJozsef Kadlecsik 
61b66554cfSJozsef Kadlecsik 	return match_set(info->match_set.index, skb, par, &opt,
62d956798dSJozsef Kadlecsik 			 info->match_set.u.compat.flags & IPSET_INV_MATCH);
63d956798dSJozsef Kadlecsik }
64d956798dSJozsef Kadlecsik 
65d956798dSJozsef Kadlecsik static void
66d956798dSJozsef Kadlecsik compat_flags(struct xt_set_info_v0 *info)
67d956798dSJozsef Kadlecsik {
68d956798dSJozsef Kadlecsik 	u_int8_t i;
69d956798dSJozsef Kadlecsik 
70d956798dSJozsef Kadlecsik 	/* Fill out compatibility data according to enum ip_set_kopt */
71d956798dSJozsef Kadlecsik 	info->u.compat.dim = IPSET_DIM_ZERO;
72d956798dSJozsef Kadlecsik 	if (info->u.flags[0] & IPSET_MATCH_INV)
73d956798dSJozsef Kadlecsik 		info->u.compat.flags |= IPSET_INV_MATCH;
74d956798dSJozsef Kadlecsik 	for (i = 0; i < IPSET_DIM_MAX - 1 && info->u.flags[i]; i++) {
75d956798dSJozsef Kadlecsik 		info->u.compat.dim++;
76d956798dSJozsef Kadlecsik 		if (info->u.flags[i] & IPSET_SRC)
77d956798dSJozsef Kadlecsik 			info->u.compat.flags |= (1 << info->u.compat.dim);
78d956798dSJozsef Kadlecsik 	}
79d956798dSJozsef Kadlecsik }
80d956798dSJozsef Kadlecsik 
81d956798dSJozsef Kadlecsik static int
82d956798dSJozsef Kadlecsik set_match_v0_checkentry(const struct xt_mtchk_param *par)
83d956798dSJozsef Kadlecsik {
84d956798dSJozsef Kadlecsik 	struct xt_set_info_match_v0 *info = par->matchinfo;
85d956798dSJozsef Kadlecsik 	ip_set_id_t index;
86d956798dSJozsef Kadlecsik 
871785e8f4SVitaly Lavrov 	index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
88d956798dSJozsef Kadlecsik 
89d956798dSJozsef Kadlecsik 	if (index == IPSET_INVALID_ID) {
90b167a37cSJoe Perches 		pr_warn("Cannot find set identified by id %u to match\n",
91d956798dSJozsef Kadlecsik 			info->match_set.index);
92d956798dSJozsef Kadlecsik 		return -ENOENT;
93d956798dSJozsef Kadlecsik 	}
94d956798dSJozsef Kadlecsik 	if (info->match_set.u.flags[IPSET_DIM_MAX - 1] != 0) {
95b167a37cSJoe Perches 		pr_warn("Protocol error: set match dimension is over the limit!\n");
961785e8f4SVitaly Lavrov 		ip_set_nfnl_put(par->net, info->match_set.index);
97d956798dSJozsef Kadlecsik 		return -ERANGE;
98d956798dSJozsef Kadlecsik 	}
99d956798dSJozsef Kadlecsik 
100d956798dSJozsef Kadlecsik 	/* Fill out compatibility data */
101d956798dSJozsef Kadlecsik 	compat_flags(&info->match_set);
102d956798dSJozsef Kadlecsik 
103d956798dSJozsef Kadlecsik 	return 0;
104d956798dSJozsef Kadlecsik }
105d956798dSJozsef Kadlecsik 
106d956798dSJozsef Kadlecsik static void
107d956798dSJozsef Kadlecsik set_match_v0_destroy(const struct xt_mtdtor_param *par)
108d956798dSJozsef Kadlecsik {
109d956798dSJozsef Kadlecsik 	struct xt_set_info_match_v0 *info = par->matchinfo;
110d956798dSJozsef Kadlecsik 
1111785e8f4SVitaly Lavrov 	ip_set_nfnl_put(par->net, info->match_set.index);
112d956798dSJozsef Kadlecsik }
113d956798dSJozsef Kadlecsik 
114bd3129fcSJozsef Kadlecsik /* Revision 1 match */
115bd3129fcSJozsef Kadlecsik 
116bd3129fcSJozsef Kadlecsik static bool
117bd3129fcSJozsef Kadlecsik set_match_v1(const struct sk_buff *skb, struct xt_action_param *par)
118bd3129fcSJozsef Kadlecsik {
119bd3129fcSJozsef Kadlecsik 	const struct xt_set_info_match_v1 *info = par->matchinfo;
120ca0f6a5cSJozsef Kadlecsik 
121bd3129fcSJozsef Kadlecsik 	ADT_OPT(opt, par->family, info->match_set.dim,
122bd3129fcSJozsef Kadlecsik 		info->match_set.flags, 0, UINT_MAX);
123bd3129fcSJozsef Kadlecsik 
124bd3129fcSJozsef Kadlecsik 	if (opt.flags & IPSET_RETURN_NOMATCH)
125bd3129fcSJozsef Kadlecsik 		opt.cmdflags |= IPSET_FLAG_RETURN_NOMATCH;
126bd3129fcSJozsef Kadlecsik 
127bd3129fcSJozsef Kadlecsik 	return match_set(info->match_set.index, skb, par, &opt,
128bd3129fcSJozsef Kadlecsik 			 info->match_set.flags & IPSET_INV_MATCH);
129bd3129fcSJozsef Kadlecsik }
130bd3129fcSJozsef Kadlecsik 
131bd3129fcSJozsef Kadlecsik static int
132bd3129fcSJozsef Kadlecsik set_match_v1_checkentry(const struct xt_mtchk_param *par)
133bd3129fcSJozsef Kadlecsik {
134bd3129fcSJozsef Kadlecsik 	struct xt_set_info_match_v1 *info = par->matchinfo;
135bd3129fcSJozsef Kadlecsik 	ip_set_id_t index;
136bd3129fcSJozsef Kadlecsik 
1371785e8f4SVitaly Lavrov 	index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
138bd3129fcSJozsef Kadlecsik 
139bd3129fcSJozsef Kadlecsik 	if (index == IPSET_INVALID_ID) {
140b167a37cSJoe Perches 		pr_warn("Cannot find set identified by id %u to match\n",
141bd3129fcSJozsef Kadlecsik 			info->match_set.index);
142bd3129fcSJozsef Kadlecsik 		return -ENOENT;
143bd3129fcSJozsef Kadlecsik 	}
144bd3129fcSJozsef Kadlecsik 	if (info->match_set.dim > IPSET_DIM_MAX) {
145b167a37cSJoe Perches 		pr_warn("Protocol error: set match dimension is over the limit!\n");
1461785e8f4SVitaly Lavrov 		ip_set_nfnl_put(par->net, info->match_set.index);
147bd3129fcSJozsef Kadlecsik 		return -ERANGE;
148bd3129fcSJozsef Kadlecsik 	}
149bd3129fcSJozsef Kadlecsik 
150bd3129fcSJozsef Kadlecsik 	return 0;
151bd3129fcSJozsef Kadlecsik }
152bd3129fcSJozsef Kadlecsik 
153bd3129fcSJozsef Kadlecsik static void
154bd3129fcSJozsef Kadlecsik set_match_v1_destroy(const struct xt_mtdtor_param *par)
155bd3129fcSJozsef Kadlecsik {
156bd3129fcSJozsef Kadlecsik 	struct xt_set_info_match_v1 *info = par->matchinfo;
157bd3129fcSJozsef Kadlecsik 
1581785e8f4SVitaly Lavrov 	ip_set_nfnl_put(par->net, info->match_set.index);
159bd3129fcSJozsef Kadlecsik }
160bd3129fcSJozsef Kadlecsik 
161bd3129fcSJozsef Kadlecsik /* Revision 3 match */
162bd3129fcSJozsef Kadlecsik 
163bd3129fcSJozsef Kadlecsik static bool
164a51b9199SJozsef Kadlecsik match_counter0(u64 counter, const struct ip_set_counter_match0 *info)
165bd3129fcSJozsef Kadlecsik {
166bd3129fcSJozsef Kadlecsik 	switch (info->op) {
167bd3129fcSJozsef Kadlecsik 	case IPSET_COUNTER_NONE:
168bd3129fcSJozsef Kadlecsik 		return true;
169bd3129fcSJozsef Kadlecsik 	case IPSET_COUNTER_EQ:
170bd3129fcSJozsef Kadlecsik 		return counter == info->value;
171bd3129fcSJozsef Kadlecsik 	case IPSET_COUNTER_NE:
172bd3129fcSJozsef Kadlecsik 		return counter != info->value;
173bd3129fcSJozsef Kadlecsik 	case IPSET_COUNTER_LT:
174bd3129fcSJozsef Kadlecsik 		return counter < info->value;
175bd3129fcSJozsef Kadlecsik 	case IPSET_COUNTER_GT:
176bd3129fcSJozsef Kadlecsik 		return counter > info->value;
177bd3129fcSJozsef Kadlecsik 	}
178bd3129fcSJozsef Kadlecsik 	return false;
179bd3129fcSJozsef Kadlecsik }
180bd3129fcSJozsef Kadlecsik 
181bd3129fcSJozsef Kadlecsik static bool
182bd3129fcSJozsef Kadlecsik set_match_v3(const struct sk_buff *skb, struct xt_action_param *par)
183bd3129fcSJozsef Kadlecsik {
184bd3129fcSJozsef Kadlecsik 	const struct xt_set_info_match_v3 *info = par->matchinfo;
185ca0f6a5cSJozsef Kadlecsik 	int ret;
186ca0f6a5cSJozsef Kadlecsik 
187bd3129fcSJozsef Kadlecsik 	ADT_OPT(opt, par->family, info->match_set.dim,
188bd3129fcSJozsef Kadlecsik 		info->match_set.flags, info->flags, UINT_MAX);
189bd3129fcSJozsef Kadlecsik 
190bd3129fcSJozsef Kadlecsik 	if (info->packets.op != IPSET_COUNTER_NONE ||
191bd3129fcSJozsef Kadlecsik 	    info->bytes.op != IPSET_COUNTER_NONE)
192bd3129fcSJozsef Kadlecsik 		opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS;
193bd3129fcSJozsef Kadlecsik 
194bd3129fcSJozsef Kadlecsik 	ret = match_set(info->match_set.index, skb, par, &opt,
195bd3129fcSJozsef Kadlecsik 			info->match_set.flags & IPSET_INV_MATCH);
196bd3129fcSJozsef Kadlecsik 
197bd3129fcSJozsef Kadlecsik 	if (!(ret && opt.cmdflags & IPSET_FLAG_MATCH_COUNTERS))
198bd3129fcSJozsef Kadlecsik 		return ret;
199bd3129fcSJozsef Kadlecsik 
200a51b9199SJozsef Kadlecsik 	if (!match_counter0(opt.ext.packets, &info->packets))
2017f73b9f1SWu Fengguang 		return false;
202a51b9199SJozsef Kadlecsik 	return match_counter0(opt.ext.bytes, &info->bytes);
203a51b9199SJozsef Kadlecsik }
204a51b9199SJozsef Kadlecsik 
205a51b9199SJozsef Kadlecsik #define set_match_v3_checkentry	set_match_v1_checkentry
206a51b9199SJozsef Kadlecsik #define set_match_v3_destroy	set_match_v1_destroy
207a51b9199SJozsef Kadlecsik 
208a51b9199SJozsef Kadlecsik /* Revision 4 match */
209a51b9199SJozsef Kadlecsik 
210a51b9199SJozsef Kadlecsik static bool
211a51b9199SJozsef Kadlecsik match_counter(u64 counter, const struct ip_set_counter_match *info)
212a51b9199SJozsef Kadlecsik {
213a51b9199SJozsef Kadlecsik 	switch (info->op) {
214a51b9199SJozsef Kadlecsik 	case IPSET_COUNTER_NONE:
215a51b9199SJozsef Kadlecsik 		return true;
216a51b9199SJozsef Kadlecsik 	case IPSET_COUNTER_EQ:
217a51b9199SJozsef Kadlecsik 		return counter == info->value;
218a51b9199SJozsef Kadlecsik 	case IPSET_COUNTER_NE:
219a51b9199SJozsef Kadlecsik 		return counter != info->value;
220a51b9199SJozsef Kadlecsik 	case IPSET_COUNTER_LT:
221a51b9199SJozsef Kadlecsik 		return counter < info->value;
222a51b9199SJozsef Kadlecsik 	case IPSET_COUNTER_GT:
223a51b9199SJozsef Kadlecsik 		return counter > info->value;
224a51b9199SJozsef Kadlecsik 	}
225a51b9199SJozsef Kadlecsik 	return false;
226a51b9199SJozsef Kadlecsik }
227a51b9199SJozsef Kadlecsik 
228a51b9199SJozsef Kadlecsik static bool
229a51b9199SJozsef Kadlecsik set_match_v4(const struct sk_buff *skb, struct xt_action_param *par)
230a51b9199SJozsef Kadlecsik {
231a51b9199SJozsef Kadlecsik 	const struct xt_set_info_match_v4 *info = par->matchinfo;
232ca0f6a5cSJozsef Kadlecsik 	int ret;
233ca0f6a5cSJozsef Kadlecsik 
234a51b9199SJozsef Kadlecsik 	ADT_OPT(opt, par->family, info->match_set.dim,
235a51b9199SJozsef Kadlecsik 		info->match_set.flags, info->flags, UINT_MAX);
236a51b9199SJozsef Kadlecsik 
237a51b9199SJozsef Kadlecsik 	if (info->packets.op != IPSET_COUNTER_NONE ||
238a51b9199SJozsef Kadlecsik 	    info->bytes.op != IPSET_COUNTER_NONE)
239a51b9199SJozsef Kadlecsik 		opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS;
240a51b9199SJozsef Kadlecsik 
241a51b9199SJozsef Kadlecsik 	ret = match_set(info->match_set.index, skb, par, &opt,
242a51b9199SJozsef Kadlecsik 			info->match_set.flags & IPSET_INV_MATCH);
243a51b9199SJozsef Kadlecsik 
244a51b9199SJozsef Kadlecsik 	if (!(ret && opt.cmdflags & IPSET_FLAG_MATCH_COUNTERS))
245a51b9199SJozsef Kadlecsik 		return ret;
246a51b9199SJozsef Kadlecsik 
247bd3129fcSJozsef Kadlecsik 	if (!match_counter(opt.ext.packets, &info->packets))
2487f73b9f1SWu Fengguang 		return false;
249bd3129fcSJozsef Kadlecsik 	return match_counter(opt.ext.bytes, &info->bytes);
250bd3129fcSJozsef Kadlecsik }
251bd3129fcSJozsef Kadlecsik 
252a51b9199SJozsef Kadlecsik #define set_match_v4_checkentry	set_match_v1_checkentry
253a51b9199SJozsef Kadlecsik #define set_match_v4_destroy	set_match_v1_destroy
254bd3129fcSJozsef Kadlecsik 
255bd3129fcSJozsef Kadlecsik /* Revision 0 interface: backward compatible with netfilter/iptables */
256bd3129fcSJozsef Kadlecsik 
257d956798dSJozsef Kadlecsik static unsigned int
258d956798dSJozsef Kadlecsik set_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
259d956798dSJozsef Kadlecsik {
260d956798dSJozsef Kadlecsik 	const struct xt_set_info_target_v0 *info = par->targinfo;
261ca0f6a5cSJozsef Kadlecsik 
262ac8cc925SJozsef Kadlecsik 	ADT_OPT(add_opt, par->family, info->add_set.u.compat.dim,
263ac8cc925SJozsef Kadlecsik 		info->add_set.u.compat.flags, 0, UINT_MAX);
264ac8cc925SJozsef Kadlecsik 	ADT_OPT(del_opt, par->family, info->del_set.u.compat.dim,
265ac8cc925SJozsef Kadlecsik 		info->del_set.u.compat.flags, 0, UINT_MAX);
266d956798dSJozsef Kadlecsik 
267d956798dSJozsef Kadlecsik 	if (info->add_set.index != IPSET_INVALID_ID)
268b66554cfSJozsef Kadlecsik 		ip_set_add(info->add_set.index, skb, par, &add_opt);
269d956798dSJozsef Kadlecsik 	if (info->del_set.index != IPSET_INVALID_ID)
270b66554cfSJozsef Kadlecsik 		ip_set_del(info->del_set.index, skb, par, &del_opt);
271d956798dSJozsef Kadlecsik 
272d956798dSJozsef Kadlecsik 	return XT_CONTINUE;
273d956798dSJozsef Kadlecsik }
274d956798dSJozsef Kadlecsik 
275d956798dSJozsef Kadlecsik static int
276d956798dSJozsef Kadlecsik set_target_v0_checkentry(const struct xt_tgchk_param *par)
277d956798dSJozsef Kadlecsik {
278d956798dSJozsef Kadlecsik 	struct xt_set_info_target_v0 *info = par->targinfo;
279d956798dSJozsef Kadlecsik 	ip_set_id_t index;
280d956798dSJozsef Kadlecsik 
281d956798dSJozsef Kadlecsik 	if (info->add_set.index != IPSET_INVALID_ID) {
2821785e8f4SVitaly Lavrov 		index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
283d956798dSJozsef Kadlecsik 		if (index == IPSET_INVALID_ID) {
284b167a37cSJoe Perches 			pr_warn("Cannot find add_set index %u as target\n",
285d956798dSJozsef Kadlecsik 				info->add_set.index);
286d956798dSJozsef Kadlecsik 			return -ENOENT;
287d956798dSJozsef Kadlecsik 		}
288d956798dSJozsef Kadlecsik 	}
289d956798dSJozsef Kadlecsik 
290d956798dSJozsef Kadlecsik 	if (info->del_set.index != IPSET_INVALID_ID) {
2911785e8f4SVitaly Lavrov 		index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
292d956798dSJozsef Kadlecsik 		if (index == IPSET_INVALID_ID) {
293b167a37cSJoe Perches 			pr_warn("Cannot find del_set index %u as target\n",
294d956798dSJozsef Kadlecsik 				info->del_set.index);
295eafbd3fdSJozsef Kadlecsik 			if (info->add_set.index != IPSET_INVALID_ID)
2961785e8f4SVitaly Lavrov 				ip_set_nfnl_put(par->net, info->add_set.index);
297d956798dSJozsef Kadlecsik 			return -ENOENT;
298d956798dSJozsef Kadlecsik 		}
299d956798dSJozsef Kadlecsik 	}
300d956798dSJozsef Kadlecsik 	if (info->add_set.u.flags[IPSET_DIM_MAX - 1] != 0 ||
301d956798dSJozsef Kadlecsik 	    info->del_set.u.flags[IPSET_DIM_MAX - 1] != 0) {
302b167a37cSJoe Perches 		pr_warn("Protocol error: SET target dimension is over the limit!\n");
303eafbd3fdSJozsef Kadlecsik 		if (info->add_set.index != IPSET_INVALID_ID)
3041785e8f4SVitaly Lavrov 			ip_set_nfnl_put(par->net, info->add_set.index);
305eafbd3fdSJozsef Kadlecsik 		if (info->del_set.index != IPSET_INVALID_ID)
3061785e8f4SVitaly Lavrov 			ip_set_nfnl_put(par->net, info->del_set.index);
307d956798dSJozsef Kadlecsik 		return -ERANGE;
308d956798dSJozsef Kadlecsik 	}
309d956798dSJozsef Kadlecsik 
310d956798dSJozsef Kadlecsik 	/* Fill out compatibility data */
311d956798dSJozsef Kadlecsik 	compat_flags(&info->add_set);
312d956798dSJozsef Kadlecsik 	compat_flags(&info->del_set);
313d956798dSJozsef Kadlecsik 
314d956798dSJozsef Kadlecsik 	return 0;
315d956798dSJozsef Kadlecsik }
316d956798dSJozsef Kadlecsik 
317d956798dSJozsef Kadlecsik static void
318d956798dSJozsef Kadlecsik set_target_v0_destroy(const struct xt_tgdtor_param *par)
319d956798dSJozsef Kadlecsik {
320d956798dSJozsef Kadlecsik 	const struct xt_set_info_target_v0 *info = par->targinfo;
321d956798dSJozsef Kadlecsik 
322d956798dSJozsef Kadlecsik 	if (info->add_set.index != IPSET_INVALID_ID)
3231785e8f4SVitaly Lavrov 		ip_set_nfnl_put(par->net, info->add_set.index);
324d956798dSJozsef Kadlecsik 	if (info->del_set.index != IPSET_INVALID_ID)
3251785e8f4SVitaly Lavrov 		ip_set_nfnl_put(par->net, info->del_set.index);
326d956798dSJozsef Kadlecsik }
327d956798dSJozsef Kadlecsik 
328bd3129fcSJozsef Kadlecsik /* Revision 1 target */
329d956798dSJozsef Kadlecsik 
330d956798dSJozsef Kadlecsik static unsigned int
331ac8cc925SJozsef Kadlecsik set_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
332d956798dSJozsef Kadlecsik {
333ac8cc925SJozsef Kadlecsik 	const struct xt_set_info_target_v1 *info = par->targinfo;
334ca0f6a5cSJozsef Kadlecsik 
335ac8cc925SJozsef Kadlecsik 	ADT_OPT(add_opt, par->family, info->add_set.dim,
336ac8cc925SJozsef Kadlecsik 		info->add_set.flags, 0, UINT_MAX);
337ac8cc925SJozsef Kadlecsik 	ADT_OPT(del_opt, par->family, info->del_set.dim,
338ac8cc925SJozsef Kadlecsik 		info->del_set.flags, 0, UINT_MAX);
339d956798dSJozsef Kadlecsik 
340d956798dSJozsef Kadlecsik 	if (info->add_set.index != IPSET_INVALID_ID)
341b66554cfSJozsef Kadlecsik 		ip_set_add(info->add_set.index, skb, par, &add_opt);
342d956798dSJozsef Kadlecsik 	if (info->del_set.index != IPSET_INVALID_ID)
343b66554cfSJozsef Kadlecsik 		ip_set_del(info->del_set.index, skb, par, &del_opt);
344d956798dSJozsef Kadlecsik 
345d956798dSJozsef Kadlecsik 	return XT_CONTINUE;
346d956798dSJozsef Kadlecsik }
347d956798dSJozsef Kadlecsik 
348d956798dSJozsef Kadlecsik static int
349ac8cc925SJozsef Kadlecsik set_target_v1_checkentry(const struct xt_tgchk_param *par)
350d956798dSJozsef Kadlecsik {
351ac8cc925SJozsef Kadlecsik 	const struct xt_set_info_target_v1 *info = par->targinfo;
352d956798dSJozsef Kadlecsik 	ip_set_id_t index;
353d956798dSJozsef Kadlecsik 
354d956798dSJozsef Kadlecsik 	if (info->add_set.index != IPSET_INVALID_ID) {
3551785e8f4SVitaly Lavrov 		index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
356d956798dSJozsef Kadlecsik 		if (index == IPSET_INVALID_ID) {
357b167a37cSJoe Perches 			pr_warn("Cannot find add_set index %u as target\n",
358d956798dSJozsef Kadlecsik 				info->add_set.index);
359d956798dSJozsef Kadlecsik 			return -ENOENT;
360d956798dSJozsef Kadlecsik 		}
361d956798dSJozsef Kadlecsik 	}
362d956798dSJozsef Kadlecsik 
363d956798dSJozsef Kadlecsik 	if (info->del_set.index != IPSET_INVALID_ID) {
3641785e8f4SVitaly Lavrov 		index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
365d956798dSJozsef Kadlecsik 		if (index == IPSET_INVALID_ID) {
366b167a37cSJoe Perches 			pr_warn("Cannot find del_set index %u as target\n",
367d956798dSJozsef Kadlecsik 				info->del_set.index);
368eafbd3fdSJozsef Kadlecsik 			if (info->add_set.index != IPSET_INVALID_ID)
3691785e8f4SVitaly Lavrov 				ip_set_nfnl_put(par->net, info->add_set.index);
370d956798dSJozsef Kadlecsik 			return -ENOENT;
371d956798dSJozsef Kadlecsik 		}
372d956798dSJozsef Kadlecsik 	}
373d956798dSJozsef Kadlecsik 	if (info->add_set.dim > IPSET_DIM_MAX ||
374eafbd3fdSJozsef Kadlecsik 	    info->del_set.dim > IPSET_DIM_MAX) {
375b167a37cSJoe Perches 		pr_warn("Protocol error: SET target dimension is over the limit!\n");
376eafbd3fdSJozsef Kadlecsik 		if (info->add_set.index != IPSET_INVALID_ID)
3771785e8f4SVitaly Lavrov 			ip_set_nfnl_put(par->net, info->add_set.index);
378eafbd3fdSJozsef Kadlecsik 		if (info->del_set.index != IPSET_INVALID_ID)
3791785e8f4SVitaly Lavrov 			ip_set_nfnl_put(par->net, info->del_set.index);
380d956798dSJozsef Kadlecsik 		return -ERANGE;
381d956798dSJozsef Kadlecsik 	}
382d956798dSJozsef Kadlecsik 
383d956798dSJozsef Kadlecsik 	return 0;
384d956798dSJozsef Kadlecsik }
385d956798dSJozsef Kadlecsik 
386d956798dSJozsef Kadlecsik static void
387ac8cc925SJozsef Kadlecsik set_target_v1_destroy(const struct xt_tgdtor_param *par)
388d956798dSJozsef Kadlecsik {
389ac8cc925SJozsef Kadlecsik 	const struct xt_set_info_target_v1 *info = par->targinfo;
390d956798dSJozsef Kadlecsik 
391d956798dSJozsef Kadlecsik 	if (info->add_set.index != IPSET_INVALID_ID)
3921785e8f4SVitaly Lavrov 		ip_set_nfnl_put(par->net, info->add_set.index);
393d956798dSJozsef Kadlecsik 	if (info->del_set.index != IPSET_INVALID_ID)
3941785e8f4SVitaly Lavrov 		ip_set_nfnl_put(par->net, info->del_set.index);
395d956798dSJozsef Kadlecsik }
396d956798dSJozsef Kadlecsik 
397ac8cc925SJozsef Kadlecsik /* Revision 2 target */
398ac8cc925SJozsef Kadlecsik 
399ac8cc925SJozsef Kadlecsik static unsigned int
400ac8cc925SJozsef Kadlecsik set_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
401ac8cc925SJozsef Kadlecsik {
402ac8cc925SJozsef Kadlecsik 	const struct xt_set_info_target_v2 *info = par->targinfo;
403ca0f6a5cSJozsef Kadlecsik 
404075e64c0SJozsef Kadlecsik 	ADT_OPT(add_opt, par->family, info->add_set.dim,
405ac8cc925SJozsef Kadlecsik 		info->add_set.flags, info->flags, info->timeout);
406ac8cc925SJozsef Kadlecsik 	ADT_OPT(del_opt, par->family, info->del_set.dim,
407ac8cc925SJozsef Kadlecsik 		info->del_set.flags, 0, UINT_MAX);
408ac8cc925SJozsef Kadlecsik 
409127f5591SJozsef Kadlecsik 	/* Normalize to fit into jiffies */
410075e64c0SJozsef Kadlecsik 	if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
411075e64c0SJozsef Kadlecsik 	    add_opt.ext.timeout > UINT_MAX / MSEC_PER_SEC)
412075e64c0SJozsef Kadlecsik 		add_opt.ext.timeout = UINT_MAX / MSEC_PER_SEC;
413ac8cc925SJozsef Kadlecsik 	if (info->add_set.index != IPSET_INVALID_ID)
414b66554cfSJozsef Kadlecsik 		ip_set_add(info->add_set.index, skb, par, &add_opt);
415ac8cc925SJozsef Kadlecsik 	if (info->del_set.index != IPSET_INVALID_ID)
416b66554cfSJozsef Kadlecsik 		ip_set_del(info->del_set.index, skb, par, &del_opt);
417ac8cc925SJozsef Kadlecsik 
418ac8cc925SJozsef Kadlecsik 	return XT_CONTINUE;
419ac8cc925SJozsef Kadlecsik }
420ac8cc925SJozsef Kadlecsik 
421ac8cc925SJozsef Kadlecsik #define set_target_v2_checkentry	set_target_v1_checkentry
422ac8cc925SJozsef Kadlecsik #define set_target_v2_destroy		set_target_v1_destroy
423ac8cc925SJozsef Kadlecsik 
42476cea410SAnton Danilov /* Revision 3 target */
42576cea410SAnton Danilov 
42676cea410SAnton Danilov static unsigned int
42776cea410SAnton Danilov set_target_v3(struct sk_buff *skb, const struct xt_action_param *par)
42876cea410SAnton Danilov {
42976cea410SAnton Danilov 	const struct xt_set_info_target_v3 *info = par->targinfo;
430ca0f6a5cSJozsef Kadlecsik 	int ret;
431ca0f6a5cSJozsef Kadlecsik 
43276cea410SAnton Danilov 	ADT_OPT(add_opt, par->family, info->add_set.dim,
43376cea410SAnton Danilov 		info->add_set.flags, info->flags, info->timeout);
43476cea410SAnton Danilov 	ADT_OPT(del_opt, par->family, info->del_set.dim,
43576cea410SAnton Danilov 		info->del_set.flags, 0, UINT_MAX);
43676cea410SAnton Danilov 	ADT_OPT(map_opt, par->family, info->map_set.dim,
43776cea410SAnton Danilov 		info->map_set.flags, 0, UINT_MAX);
43876cea410SAnton Danilov 
43976cea410SAnton Danilov 	/* Normalize to fit into jiffies */
44076cea410SAnton Danilov 	if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
44176cea410SAnton Danilov 	    add_opt.ext.timeout > UINT_MAX / MSEC_PER_SEC)
44276cea410SAnton Danilov 		add_opt.ext.timeout = UINT_MAX / MSEC_PER_SEC;
44376cea410SAnton Danilov 	if (info->add_set.index != IPSET_INVALID_ID)
44476cea410SAnton Danilov 		ip_set_add(info->add_set.index, skb, par, &add_opt);
44576cea410SAnton Danilov 	if (info->del_set.index != IPSET_INVALID_ID)
44676cea410SAnton Danilov 		ip_set_del(info->del_set.index, skb, par, &del_opt);
44776cea410SAnton Danilov 	if (info->map_set.index != IPSET_INVALID_ID) {
44876cea410SAnton Danilov 		map_opt.cmdflags |= info->flags & (IPSET_FLAG_MAP_SKBMARK |
44976cea410SAnton Danilov 						   IPSET_FLAG_MAP_SKBPRIO |
45076cea410SAnton Danilov 						   IPSET_FLAG_MAP_SKBQUEUE);
45176cea410SAnton Danilov 		ret = match_set(info->map_set.index, skb, par, &map_opt,
45276cea410SAnton Danilov 				info->map_set.flags & IPSET_INV_MATCH);
45376cea410SAnton Danilov 		if (!ret)
45476cea410SAnton Danilov 			return XT_CONTINUE;
45576cea410SAnton Danilov 		if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBMARK)
45676cea410SAnton Danilov 			skb->mark = (skb->mark & ~(map_opt.ext.skbmarkmask))
45776cea410SAnton Danilov 				    ^ (map_opt.ext.skbmark);
45876cea410SAnton Danilov 		if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBPRIO)
45976cea410SAnton Danilov 			skb->priority = map_opt.ext.skbprio;
46076cea410SAnton Danilov 		if ((map_opt.cmdflags & IPSET_FLAG_MAP_SKBQUEUE) &&
46176cea410SAnton Danilov 		    skb->dev &&
46276cea410SAnton Danilov 		    skb->dev->real_num_tx_queues > map_opt.ext.skbqueue)
46376cea410SAnton Danilov 			skb_set_queue_mapping(skb, map_opt.ext.skbqueue);
46476cea410SAnton Danilov 	}
46576cea410SAnton Danilov 	return XT_CONTINUE;
46676cea410SAnton Danilov }
46776cea410SAnton Danilov 
46876cea410SAnton Danilov static int
46976cea410SAnton Danilov set_target_v3_checkentry(const struct xt_tgchk_param *par)
47076cea410SAnton Danilov {
47176cea410SAnton Danilov 	const struct xt_set_info_target_v3 *info = par->targinfo;
47276cea410SAnton Danilov 	ip_set_id_t index;
47376cea410SAnton Danilov 
47476cea410SAnton Danilov 	if (info->add_set.index != IPSET_INVALID_ID) {
47576cea410SAnton Danilov 		index = ip_set_nfnl_get_byindex(par->net,
47676cea410SAnton Danilov 						info->add_set.index);
47776cea410SAnton Danilov 		if (index == IPSET_INVALID_ID) {
47876cea410SAnton Danilov 			pr_warn("Cannot find add_set index %u as target\n",
47976cea410SAnton Danilov 				info->add_set.index);
48076cea410SAnton Danilov 			return -ENOENT;
48176cea410SAnton Danilov 		}
48276cea410SAnton Danilov 	}
48376cea410SAnton Danilov 
48476cea410SAnton Danilov 	if (info->del_set.index != IPSET_INVALID_ID) {
48576cea410SAnton Danilov 		index = ip_set_nfnl_get_byindex(par->net,
48676cea410SAnton Danilov 						info->del_set.index);
48776cea410SAnton Danilov 		if (index == IPSET_INVALID_ID) {
48876cea410SAnton Danilov 			pr_warn("Cannot find del_set index %u as target\n",
48976cea410SAnton Danilov 				info->del_set.index);
49076cea410SAnton Danilov 			if (info->add_set.index != IPSET_INVALID_ID)
49176cea410SAnton Danilov 				ip_set_nfnl_put(par->net,
49276cea410SAnton Danilov 						info->add_set.index);
49376cea410SAnton Danilov 			return -ENOENT;
49476cea410SAnton Danilov 		}
49576cea410SAnton Danilov 	}
49676cea410SAnton Danilov 
49776cea410SAnton Danilov 	if (info->map_set.index != IPSET_INVALID_ID) {
49876cea410SAnton Danilov 		if (strncmp(par->table, "mangle", 7)) {
49976cea410SAnton Danilov 			pr_warn("--map-set only usable from mangle table\n");
50076cea410SAnton Danilov 			return -EINVAL;
50176cea410SAnton Danilov 		}
50276cea410SAnton Danilov 		if (((info->flags & IPSET_FLAG_MAP_SKBPRIO) |
50376cea410SAnton Danilov 		     (info->flags & IPSET_FLAG_MAP_SKBQUEUE)) &&
50476cea410SAnton Danilov 		     !(par->hook_mask & (1 << NF_INET_FORWARD |
50576cea410SAnton Danilov 					 1 << NF_INET_LOCAL_OUT |
50676cea410SAnton Danilov 					 1 << NF_INET_POST_ROUTING))) {
507ca0f6a5cSJozsef Kadlecsik 			pr_warn("mapping of prio or/and queue is allowed only from OUTPUT/FORWARD/POSTROUTING chains\n");
50876cea410SAnton Danilov 			return -EINVAL;
50976cea410SAnton Danilov 		}
51076cea410SAnton Danilov 		index = ip_set_nfnl_get_byindex(par->net,
51176cea410SAnton Danilov 						info->map_set.index);
51276cea410SAnton Danilov 		if (index == IPSET_INVALID_ID) {
51376cea410SAnton Danilov 			pr_warn("Cannot find map_set index %u as target\n",
51476cea410SAnton Danilov 				info->map_set.index);
51576cea410SAnton Danilov 			if (info->add_set.index != IPSET_INVALID_ID)
51676cea410SAnton Danilov 				ip_set_nfnl_put(par->net,
51776cea410SAnton Danilov 						info->add_set.index);
51876cea410SAnton Danilov 			if (info->del_set.index != IPSET_INVALID_ID)
51976cea410SAnton Danilov 				ip_set_nfnl_put(par->net,
52076cea410SAnton Danilov 						info->del_set.index);
52176cea410SAnton Danilov 			return -ENOENT;
52276cea410SAnton Danilov 		}
52376cea410SAnton Danilov 	}
52476cea410SAnton Danilov 
52576cea410SAnton Danilov 	if (info->add_set.dim > IPSET_DIM_MAX ||
52676cea410SAnton Danilov 	    info->del_set.dim > IPSET_DIM_MAX ||
52776cea410SAnton Danilov 	    info->map_set.dim > IPSET_DIM_MAX) {
528ca0f6a5cSJozsef Kadlecsik 		pr_warn("Protocol error: SET target dimension is over the limit!\n");
52976cea410SAnton Danilov 		if (info->add_set.index != IPSET_INVALID_ID)
53076cea410SAnton Danilov 			ip_set_nfnl_put(par->net, info->add_set.index);
53176cea410SAnton Danilov 		if (info->del_set.index != IPSET_INVALID_ID)
53276cea410SAnton Danilov 			ip_set_nfnl_put(par->net, info->del_set.index);
53376cea410SAnton Danilov 		if (info->map_set.index != IPSET_INVALID_ID)
53476cea410SAnton Danilov 			ip_set_nfnl_put(par->net, info->map_set.index);
53576cea410SAnton Danilov 		return -ERANGE;
53676cea410SAnton Danilov 	}
53776cea410SAnton Danilov 
53876cea410SAnton Danilov 	return 0;
53976cea410SAnton Danilov }
54076cea410SAnton Danilov 
54176cea410SAnton Danilov static void
54276cea410SAnton Danilov set_target_v3_destroy(const struct xt_tgdtor_param *par)
54376cea410SAnton Danilov {
54476cea410SAnton Danilov 	const struct xt_set_info_target_v3 *info = par->targinfo;
54576cea410SAnton Danilov 
54676cea410SAnton Danilov 	if (info->add_set.index != IPSET_INVALID_ID)
54776cea410SAnton Danilov 		ip_set_nfnl_put(par->net, info->add_set.index);
54876cea410SAnton Danilov 	if (info->del_set.index != IPSET_INVALID_ID)
54976cea410SAnton Danilov 		ip_set_nfnl_put(par->net, info->del_set.index);
55076cea410SAnton Danilov 	if (info->map_set.index != IPSET_INVALID_ID)
55176cea410SAnton Danilov 		ip_set_nfnl_put(par->net, info->map_set.index);
55276cea410SAnton Danilov }
55376cea410SAnton Danilov 
554d956798dSJozsef Kadlecsik static struct xt_match set_matches[] __read_mostly = {
555d956798dSJozsef Kadlecsik 	{
556d956798dSJozsef Kadlecsik 		.name		= "set",
557d956798dSJozsef Kadlecsik 		.family		= NFPROTO_IPV4,
558d956798dSJozsef Kadlecsik 		.revision	= 0,
559d956798dSJozsef Kadlecsik 		.match		= set_match_v0,
560d956798dSJozsef Kadlecsik 		.matchsize	= sizeof(struct xt_set_info_match_v0),
561d956798dSJozsef Kadlecsik 		.checkentry	= set_match_v0_checkentry,
562d956798dSJozsef Kadlecsik 		.destroy	= set_match_v0_destroy,
563d956798dSJozsef Kadlecsik 		.me		= THIS_MODULE
564d956798dSJozsef Kadlecsik 	},
565d956798dSJozsef Kadlecsik 	{
566d956798dSJozsef Kadlecsik 		.name		= "set",
567d956798dSJozsef Kadlecsik 		.family		= NFPROTO_IPV4,
568d956798dSJozsef Kadlecsik 		.revision	= 1,
569ac8cc925SJozsef Kadlecsik 		.match		= set_match_v1,
570ac8cc925SJozsef Kadlecsik 		.matchsize	= sizeof(struct xt_set_info_match_v1),
571ac8cc925SJozsef Kadlecsik 		.checkentry	= set_match_v1_checkentry,
572ac8cc925SJozsef Kadlecsik 		.destroy	= set_match_v1_destroy,
573d956798dSJozsef Kadlecsik 		.me		= THIS_MODULE
574d956798dSJozsef Kadlecsik 	},
575d956798dSJozsef Kadlecsik 	{
576d956798dSJozsef Kadlecsik 		.name		= "set",
577d956798dSJozsef Kadlecsik 		.family		= NFPROTO_IPV6,
578d956798dSJozsef Kadlecsik 		.revision	= 1,
579ac8cc925SJozsef Kadlecsik 		.match		= set_match_v1,
580ac8cc925SJozsef Kadlecsik 		.matchsize	= sizeof(struct xt_set_info_match_v1),
581ac8cc925SJozsef Kadlecsik 		.checkentry	= set_match_v1_checkentry,
582ac8cc925SJozsef Kadlecsik 		.destroy	= set_match_v1_destroy,
583d956798dSJozsef Kadlecsik 		.me		= THIS_MODULE
584d956798dSJozsef Kadlecsik 	},
5853e0304a5SJozsef Kadlecsik 	/* --return-nomatch flag support */
5863e0304a5SJozsef Kadlecsik 	{
5873e0304a5SJozsef Kadlecsik 		.name		= "set",
5883e0304a5SJozsef Kadlecsik 		.family		= NFPROTO_IPV4,
5893e0304a5SJozsef Kadlecsik 		.revision	= 2,
5903e0304a5SJozsef Kadlecsik 		.match		= set_match_v1,
5913e0304a5SJozsef Kadlecsik 		.matchsize	= sizeof(struct xt_set_info_match_v1),
5923e0304a5SJozsef Kadlecsik 		.checkentry	= set_match_v1_checkentry,
5933e0304a5SJozsef Kadlecsik 		.destroy	= set_match_v1_destroy,
5943e0304a5SJozsef Kadlecsik 		.me		= THIS_MODULE
5953e0304a5SJozsef Kadlecsik 	},
5963e0304a5SJozsef Kadlecsik 	{
5973e0304a5SJozsef Kadlecsik 		.name		= "set",
5983e0304a5SJozsef Kadlecsik 		.family		= NFPROTO_IPV6,
5993e0304a5SJozsef Kadlecsik 		.revision	= 2,
6003e0304a5SJozsef Kadlecsik 		.match		= set_match_v1,
6013e0304a5SJozsef Kadlecsik 		.matchsize	= sizeof(struct xt_set_info_match_v1),
6023e0304a5SJozsef Kadlecsik 		.checkentry	= set_match_v1_checkentry,
6033e0304a5SJozsef Kadlecsik 		.destroy	= set_match_v1_destroy,
6043e0304a5SJozsef Kadlecsik 		.me		= THIS_MODULE
6053e0304a5SJozsef Kadlecsik 	},
6066e01781dSJozsef Kadlecsik 	/* counters support: update, match */
6076e01781dSJozsef Kadlecsik 	{
6086e01781dSJozsef Kadlecsik 		.name		= "set",
6096e01781dSJozsef Kadlecsik 		.family		= NFPROTO_IPV4,
6106e01781dSJozsef Kadlecsik 		.revision	= 3,
6116e01781dSJozsef Kadlecsik 		.match		= set_match_v3,
6126e01781dSJozsef Kadlecsik 		.matchsize	= sizeof(struct xt_set_info_match_v3),
6136e01781dSJozsef Kadlecsik 		.checkentry	= set_match_v3_checkentry,
6146e01781dSJozsef Kadlecsik 		.destroy	= set_match_v3_destroy,
6156e01781dSJozsef Kadlecsik 		.me		= THIS_MODULE
6166e01781dSJozsef Kadlecsik 	},
6176e01781dSJozsef Kadlecsik 	{
6186e01781dSJozsef Kadlecsik 		.name		= "set",
6196e01781dSJozsef Kadlecsik 		.family		= NFPROTO_IPV6,
6206e01781dSJozsef Kadlecsik 		.revision	= 3,
6216e01781dSJozsef Kadlecsik 		.match		= set_match_v3,
6226e01781dSJozsef Kadlecsik 		.matchsize	= sizeof(struct xt_set_info_match_v3),
6236e01781dSJozsef Kadlecsik 		.checkentry	= set_match_v3_checkentry,
6246e01781dSJozsef Kadlecsik 		.destroy	= set_match_v3_destroy,
6256e01781dSJozsef Kadlecsik 		.me		= THIS_MODULE
6266e01781dSJozsef Kadlecsik 	},
627a51b9199SJozsef Kadlecsik 	/* new revision for counters support: update, match */
628a51b9199SJozsef Kadlecsik 	{
629a51b9199SJozsef Kadlecsik 		.name		= "set",
630a51b9199SJozsef Kadlecsik 		.family		= NFPROTO_IPV4,
631a51b9199SJozsef Kadlecsik 		.revision	= 4,
632a51b9199SJozsef Kadlecsik 		.match		= set_match_v4,
633a51b9199SJozsef Kadlecsik 		.matchsize	= sizeof(struct xt_set_info_match_v4),
634a51b9199SJozsef Kadlecsik 		.checkentry	= set_match_v4_checkentry,
635a51b9199SJozsef Kadlecsik 		.destroy	= set_match_v4_destroy,
636a51b9199SJozsef Kadlecsik 		.me		= THIS_MODULE
637a51b9199SJozsef Kadlecsik 	},
638a51b9199SJozsef Kadlecsik 	{
639a51b9199SJozsef Kadlecsik 		.name		= "set",
640a51b9199SJozsef Kadlecsik 		.family		= NFPROTO_IPV6,
641a51b9199SJozsef Kadlecsik 		.revision	= 4,
642a51b9199SJozsef Kadlecsik 		.match		= set_match_v4,
643a51b9199SJozsef Kadlecsik 		.matchsize	= sizeof(struct xt_set_info_match_v4),
644a51b9199SJozsef Kadlecsik 		.checkentry	= set_match_v4_checkentry,
645a51b9199SJozsef Kadlecsik 		.destroy	= set_match_v4_destroy,
646a51b9199SJozsef Kadlecsik 		.me		= THIS_MODULE
647a51b9199SJozsef Kadlecsik 	},
648d956798dSJozsef Kadlecsik };
649d956798dSJozsef Kadlecsik 
650d956798dSJozsef Kadlecsik static struct xt_target set_targets[] __read_mostly = {
651d956798dSJozsef Kadlecsik 	{
652d956798dSJozsef Kadlecsik 		.name		= "SET",
653d956798dSJozsef Kadlecsik 		.revision	= 0,
654d956798dSJozsef Kadlecsik 		.family		= NFPROTO_IPV4,
655d956798dSJozsef Kadlecsik 		.target		= set_target_v0,
656d956798dSJozsef Kadlecsik 		.targetsize	= sizeof(struct xt_set_info_target_v0),
657d956798dSJozsef Kadlecsik 		.checkentry	= set_target_v0_checkentry,
658d956798dSJozsef Kadlecsik 		.destroy	= set_target_v0_destroy,
659d956798dSJozsef Kadlecsik 		.me		= THIS_MODULE
660d956798dSJozsef Kadlecsik 	},
661d956798dSJozsef Kadlecsik 	{
662d956798dSJozsef Kadlecsik 		.name		= "SET",
663d956798dSJozsef Kadlecsik 		.revision	= 1,
664d956798dSJozsef Kadlecsik 		.family		= NFPROTO_IPV4,
665ac8cc925SJozsef Kadlecsik 		.target		= set_target_v1,
666ac8cc925SJozsef Kadlecsik 		.targetsize	= sizeof(struct xt_set_info_target_v1),
667ac8cc925SJozsef Kadlecsik 		.checkentry	= set_target_v1_checkentry,
668ac8cc925SJozsef Kadlecsik 		.destroy	= set_target_v1_destroy,
669d956798dSJozsef Kadlecsik 		.me		= THIS_MODULE
670d956798dSJozsef Kadlecsik 	},
671d956798dSJozsef Kadlecsik 	{
672d956798dSJozsef Kadlecsik 		.name		= "SET",
673d956798dSJozsef Kadlecsik 		.revision	= 1,
674d956798dSJozsef Kadlecsik 		.family		= NFPROTO_IPV6,
675ac8cc925SJozsef Kadlecsik 		.target		= set_target_v1,
676ac8cc925SJozsef Kadlecsik 		.targetsize	= sizeof(struct xt_set_info_target_v1),
677ac8cc925SJozsef Kadlecsik 		.checkentry	= set_target_v1_checkentry,
678ac8cc925SJozsef Kadlecsik 		.destroy	= set_target_v1_destroy,
679ac8cc925SJozsef Kadlecsik 		.me		= THIS_MODULE
680ac8cc925SJozsef Kadlecsik 	},
6813e0304a5SJozsef Kadlecsik 	/* --timeout and --exist flags support */
682ac8cc925SJozsef Kadlecsik 	{
683ac8cc925SJozsef Kadlecsik 		.name		= "SET",
684ac8cc925SJozsef Kadlecsik 		.revision	= 2,
685ac8cc925SJozsef Kadlecsik 		.family		= NFPROTO_IPV4,
686ac8cc925SJozsef Kadlecsik 		.target		= set_target_v2,
687ac8cc925SJozsef Kadlecsik 		.targetsize	= sizeof(struct xt_set_info_target_v2),
688ac8cc925SJozsef Kadlecsik 		.checkentry	= set_target_v2_checkentry,
689ac8cc925SJozsef Kadlecsik 		.destroy	= set_target_v2_destroy,
690ac8cc925SJozsef Kadlecsik 		.me		= THIS_MODULE
691ac8cc925SJozsef Kadlecsik 	},
692ac8cc925SJozsef Kadlecsik 	{
693ac8cc925SJozsef Kadlecsik 		.name		= "SET",
694ac8cc925SJozsef Kadlecsik 		.revision	= 2,
695ac8cc925SJozsef Kadlecsik 		.family		= NFPROTO_IPV6,
696ac8cc925SJozsef Kadlecsik 		.target		= set_target_v2,
697ac8cc925SJozsef Kadlecsik 		.targetsize	= sizeof(struct xt_set_info_target_v2),
698ac8cc925SJozsef Kadlecsik 		.checkentry	= set_target_v2_checkentry,
699ac8cc925SJozsef Kadlecsik 		.destroy	= set_target_v2_destroy,
700d956798dSJozsef Kadlecsik 		.me		= THIS_MODULE
701d956798dSJozsef Kadlecsik 	},
70276cea410SAnton Danilov 	/* --map-set support */
70376cea410SAnton Danilov 	{
70476cea410SAnton Danilov 		.name		= "SET",
70576cea410SAnton Danilov 		.revision	= 3,
70676cea410SAnton Danilov 		.family		= NFPROTO_IPV4,
70776cea410SAnton Danilov 		.target		= set_target_v3,
70876cea410SAnton Danilov 		.targetsize	= sizeof(struct xt_set_info_target_v3),
70976cea410SAnton Danilov 		.checkentry	= set_target_v3_checkentry,
71076cea410SAnton Danilov 		.destroy	= set_target_v3_destroy,
71176cea410SAnton Danilov 		.me		= THIS_MODULE
71276cea410SAnton Danilov 	},
71376cea410SAnton Danilov 	{
71476cea410SAnton Danilov 		.name		= "SET",
71576cea410SAnton Danilov 		.revision	= 3,
71676cea410SAnton Danilov 		.family		= NFPROTO_IPV6,
71776cea410SAnton Danilov 		.target		= set_target_v3,
71876cea410SAnton Danilov 		.targetsize	= sizeof(struct xt_set_info_target_v3),
71976cea410SAnton Danilov 		.checkentry	= set_target_v3_checkentry,
72076cea410SAnton Danilov 		.destroy	= set_target_v3_destroy,
72176cea410SAnton Danilov 		.me		= THIS_MODULE
72276cea410SAnton Danilov 	},
723d956798dSJozsef Kadlecsik };
724d956798dSJozsef Kadlecsik 
725d956798dSJozsef Kadlecsik static int __init xt_set_init(void)
726d956798dSJozsef Kadlecsik {
727d956798dSJozsef Kadlecsik 	int ret = xt_register_matches(set_matches, ARRAY_SIZE(set_matches));
728d956798dSJozsef Kadlecsik 
729d956798dSJozsef Kadlecsik 	if (!ret) {
730d956798dSJozsef Kadlecsik 		ret = xt_register_targets(set_targets,
731d956798dSJozsef Kadlecsik 					  ARRAY_SIZE(set_targets));
732d956798dSJozsef Kadlecsik 		if (ret)
733d956798dSJozsef Kadlecsik 			xt_unregister_matches(set_matches,
734d956798dSJozsef Kadlecsik 					      ARRAY_SIZE(set_matches));
735d956798dSJozsef Kadlecsik 	}
736d956798dSJozsef Kadlecsik 	return ret;
737d956798dSJozsef Kadlecsik }
738d956798dSJozsef Kadlecsik 
739d956798dSJozsef Kadlecsik static void __exit xt_set_fini(void)
740d956798dSJozsef Kadlecsik {
741d956798dSJozsef Kadlecsik 	xt_unregister_matches(set_matches, ARRAY_SIZE(set_matches));
742d956798dSJozsef Kadlecsik 	xt_unregister_targets(set_targets, ARRAY_SIZE(set_targets));
743d956798dSJozsef Kadlecsik }
744d956798dSJozsef Kadlecsik 
745d956798dSJozsef Kadlecsik module_init(xt_set_init);
746d956798dSJozsef Kadlecsik module_exit(xt_set_fini);
747