xref: /openbmc/linux/net/netfilter/xt_set.c (revision a73f89a6)
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>
4d956798dSJozsef Kadlecsik  * Copyright (C) 2003-2011 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
12d956798dSJozsef Kadlecsik  * for netfilter/iptables. */
13d956798dSJozsef Kadlecsik 
14d956798dSJozsef Kadlecsik #include <linux/module.h>
15d956798dSJozsef Kadlecsik #include <linux/skbuff.h>
16d956798dSJozsef Kadlecsik 
17d956798dSJozsef Kadlecsik #include <linux/netfilter/x_tables.h>
18d956798dSJozsef Kadlecsik #include <linux/netfilter/xt_set.h>
19a73f89a6SJozsef Kadlecsik #include <linux/netfilter/ipset/ip_set_timeout.h>
20d956798dSJozsef Kadlecsik 
21d956798dSJozsef Kadlecsik MODULE_LICENSE("GPL");
22d956798dSJozsef Kadlecsik MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
23d956798dSJozsef Kadlecsik MODULE_DESCRIPTION("Xtables: IP set match and target module");
24d956798dSJozsef Kadlecsik MODULE_ALIAS("xt_SET");
25d956798dSJozsef Kadlecsik MODULE_ALIAS("ipt_set");
26d956798dSJozsef Kadlecsik MODULE_ALIAS("ip6t_set");
27d956798dSJozsef Kadlecsik MODULE_ALIAS("ipt_SET");
28d956798dSJozsef Kadlecsik MODULE_ALIAS("ip6t_SET");
29d956798dSJozsef Kadlecsik 
30d956798dSJozsef Kadlecsik static inline int
31d956798dSJozsef Kadlecsik match_set(ip_set_id_t index, const struct sk_buff *skb,
32b66554cfSJozsef Kadlecsik 	  const struct xt_action_param *par,
33ac8cc925SJozsef Kadlecsik 	  const struct ip_set_adt_opt *opt, int inv)
34d956798dSJozsef Kadlecsik {
35b66554cfSJozsef Kadlecsik 	if (ip_set_test(index, skb, par, opt))
36d956798dSJozsef Kadlecsik 		inv = !inv;
37d956798dSJozsef Kadlecsik 	return inv;
38d956798dSJozsef Kadlecsik }
39d956798dSJozsef Kadlecsik 
40ac8cc925SJozsef Kadlecsik #define ADT_OPT(n, f, d, fs, cfs, t)	\
41ac8cc925SJozsef Kadlecsik const struct ip_set_adt_opt n = {	\
42ac8cc925SJozsef Kadlecsik 	.family	= f,			\
43ac8cc925SJozsef Kadlecsik 	.dim = d,			\
44ac8cc925SJozsef Kadlecsik 	.flags = fs,			\
45ac8cc925SJozsef Kadlecsik 	.cmdflags = cfs,		\
46ac8cc925SJozsef Kadlecsik 	.timeout = t,			\
47ac8cc925SJozsef Kadlecsik }
48127f5591SJozsef Kadlecsik #define ADT_MOPT(n, f, d, fs, cfs, t)	\
49127f5591SJozsef Kadlecsik struct ip_set_adt_opt n = {		\
50127f5591SJozsef Kadlecsik 	.family	= f,			\
51127f5591SJozsef Kadlecsik 	.dim = d,			\
52127f5591SJozsef Kadlecsik 	.flags = fs,			\
53127f5591SJozsef Kadlecsik 	.cmdflags = cfs,		\
54127f5591SJozsef Kadlecsik 	.timeout = t,			\
55127f5591SJozsef Kadlecsik }
56ac8cc925SJozsef Kadlecsik 
57d956798dSJozsef Kadlecsik /* Revision 0 interface: backward compatible with netfilter/iptables */
58d956798dSJozsef Kadlecsik 
59d956798dSJozsef Kadlecsik static bool
60d956798dSJozsef Kadlecsik set_match_v0(const struct sk_buff *skb, struct xt_action_param *par)
61d956798dSJozsef Kadlecsik {
62d956798dSJozsef Kadlecsik 	const struct xt_set_info_match_v0 *info = par->matchinfo;
63ac8cc925SJozsef Kadlecsik 	ADT_OPT(opt, par->family, info->match_set.u.compat.dim,
64ac8cc925SJozsef Kadlecsik 		info->match_set.u.compat.flags, 0, UINT_MAX);
65d956798dSJozsef Kadlecsik 
66b66554cfSJozsef Kadlecsik 	return match_set(info->match_set.index, skb, par, &opt,
67d956798dSJozsef Kadlecsik 			 info->match_set.u.compat.flags & IPSET_INV_MATCH);
68d956798dSJozsef Kadlecsik }
69d956798dSJozsef Kadlecsik 
70d956798dSJozsef Kadlecsik static void
71d956798dSJozsef Kadlecsik compat_flags(struct xt_set_info_v0 *info)
72d956798dSJozsef Kadlecsik {
73d956798dSJozsef Kadlecsik 	u_int8_t i;
74d956798dSJozsef Kadlecsik 
75d956798dSJozsef Kadlecsik 	/* Fill out compatibility data according to enum ip_set_kopt */
76d956798dSJozsef Kadlecsik 	info->u.compat.dim = IPSET_DIM_ZERO;
77d956798dSJozsef Kadlecsik 	if (info->u.flags[0] & IPSET_MATCH_INV)
78d956798dSJozsef Kadlecsik 		info->u.compat.flags |= IPSET_INV_MATCH;
79d956798dSJozsef Kadlecsik 	for (i = 0; i < IPSET_DIM_MAX-1 && info->u.flags[i]; i++) {
80d956798dSJozsef Kadlecsik 		info->u.compat.dim++;
81d956798dSJozsef Kadlecsik 		if (info->u.flags[i] & IPSET_SRC)
82d956798dSJozsef Kadlecsik 			info->u.compat.flags |= (1<<info->u.compat.dim);
83d956798dSJozsef Kadlecsik 	}
84d956798dSJozsef Kadlecsik }
85d956798dSJozsef Kadlecsik 
86d956798dSJozsef Kadlecsik static int
87d956798dSJozsef Kadlecsik set_match_v0_checkentry(const struct xt_mtchk_param *par)
88d956798dSJozsef Kadlecsik {
89d956798dSJozsef Kadlecsik 	struct xt_set_info_match_v0 *info = par->matchinfo;
90d956798dSJozsef Kadlecsik 	ip_set_id_t index;
91d956798dSJozsef Kadlecsik 
92d956798dSJozsef Kadlecsik 	index = ip_set_nfnl_get_byindex(info->match_set.index);
93d956798dSJozsef Kadlecsik 
94d956798dSJozsef Kadlecsik 	if (index == IPSET_INVALID_ID) {
95d956798dSJozsef Kadlecsik 		pr_warning("Cannot find set indentified by id %u to match\n",
96d956798dSJozsef Kadlecsik 			   info->match_set.index);
97d956798dSJozsef Kadlecsik 		return -ENOENT;
98d956798dSJozsef Kadlecsik 	}
99d956798dSJozsef Kadlecsik 	if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) {
100d956798dSJozsef Kadlecsik 		pr_warning("Protocol error: set match dimension "
101d956798dSJozsef Kadlecsik 			   "is over the limit!\n");
102eafbd3fdSJozsef Kadlecsik 		ip_set_nfnl_put(info->match_set.index);
103d956798dSJozsef Kadlecsik 		return -ERANGE;
104d956798dSJozsef Kadlecsik 	}
105d956798dSJozsef Kadlecsik 
106d956798dSJozsef Kadlecsik 	/* Fill out compatibility data */
107d956798dSJozsef Kadlecsik 	compat_flags(&info->match_set);
108d956798dSJozsef Kadlecsik 
109d956798dSJozsef Kadlecsik 	return 0;
110d956798dSJozsef Kadlecsik }
111d956798dSJozsef Kadlecsik 
112d956798dSJozsef Kadlecsik static void
113d956798dSJozsef Kadlecsik set_match_v0_destroy(const struct xt_mtdtor_param *par)
114d956798dSJozsef Kadlecsik {
115d956798dSJozsef Kadlecsik 	struct xt_set_info_match_v0 *info = par->matchinfo;
116d956798dSJozsef Kadlecsik 
117d956798dSJozsef Kadlecsik 	ip_set_nfnl_put(info->match_set.index);
118d956798dSJozsef Kadlecsik }
119d956798dSJozsef Kadlecsik 
120d956798dSJozsef Kadlecsik static unsigned int
121d956798dSJozsef Kadlecsik set_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
122d956798dSJozsef Kadlecsik {
123d956798dSJozsef Kadlecsik 	const struct xt_set_info_target_v0 *info = par->targinfo;
124ac8cc925SJozsef Kadlecsik 	ADT_OPT(add_opt, par->family, info->add_set.u.compat.dim,
125ac8cc925SJozsef Kadlecsik 		info->add_set.u.compat.flags, 0, UINT_MAX);
126ac8cc925SJozsef Kadlecsik 	ADT_OPT(del_opt, par->family, info->del_set.u.compat.dim,
127ac8cc925SJozsef Kadlecsik 		info->del_set.u.compat.flags, 0, UINT_MAX);
128d956798dSJozsef Kadlecsik 
129d956798dSJozsef Kadlecsik 	if (info->add_set.index != IPSET_INVALID_ID)
130b66554cfSJozsef Kadlecsik 		ip_set_add(info->add_set.index, skb, par, &add_opt);
131d956798dSJozsef Kadlecsik 	if (info->del_set.index != IPSET_INVALID_ID)
132b66554cfSJozsef Kadlecsik 		ip_set_del(info->del_set.index, skb, par, &del_opt);
133d956798dSJozsef Kadlecsik 
134d956798dSJozsef Kadlecsik 	return XT_CONTINUE;
135d956798dSJozsef Kadlecsik }
136d956798dSJozsef Kadlecsik 
137d956798dSJozsef Kadlecsik static int
138d956798dSJozsef Kadlecsik set_target_v0_checkentry(const struct xt_tgchk_param *par)
139d956798dSJozsef Kadlecsik {
140d956798dSJozsef Kadlecsik 	struct xt_set_info_target_v0 *info = par->targinfo;
141d956798dSJozsef Kadlecsik 	ip_set_id_t index;
142d956798dSJozsef Kadlecsik 
143d956798dSJozsef Kadlecsik 	if (info->add_set.index != IPSET_INVALID_ID) {
144d956798dSJozsef Kadlecsik 		index = ip_set_nfnl_get_byindex(info->add_set.index);
145d956798dSJozsef Kadlecsik 		if (index == IPSET_INVALID_ID) {
146d956798dSJozsef Kadlecsik 			pr_warning("Cannot find add_set index %u as target\n",
147d956798dSJozsef Kadlecsik 				   info->add_set.index);
148d956798dSJozsef Kadlecsik 			return -ENOENT;
149d956798dSJozsef Kadlecsik 		}
150d956798dSJozsef Kadlecsik 	}
151d956798dSJozsef Kadlecsik 
152d956798dSJozsef Kadlecsik 	if (info->del_set.index != IPSET_INVALID_ID) {
153d956798dSJozsef Kadlecsik 		index = ip_set_nfnl_get_byindex(info->del_set.index);
154d956798dSJozsef Kadlecsik 		if (index == IPSET_INVALID_ID) {
155d956798dSJozsef Kadlecsik 			pr_warning("Cannot find del_set index %u as target\n",
156d956798dSJozsef Kadlecsik 				   info->del_set.index);
157eafbd3fdSJozsef Kadlecsik 			if (info->add_set.index != IPSET_INVALID_ID)
158eafbd3fdSJozsef Kadlecsik 				ip_set_nfnl_put(info->add_set.index);
159d956798dSJozsef Kadlecsik 			return -ENOENT;
160d956798dSJozsef Kadlecsik 		}
161d956798dSJozsef Kadlecsik 	}
162d956798dSJozsef Kadlecsik 	if (info->add_set.u.flags[IPSET_DIM_MAX-1] != 0 ||
163d956798dSJozsef Kadlecsik 	    info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) {
164d956798dSJozsef Kadlecsik 		pr_warning("Protocol error: SET target dimension "
165d956798dSJozsef Kadlecsik 			   "is over the limit!\n");
166eafbd3fdSJozsef Kadlecsik 		if (info->add_set.index != IPSET_INVALID_ID)
167eafbd3fdSJozsef Kadlecsik 			ip_set_nfnl_put(info->add_set.index);
168eafbd3fdSJozsef Kadlecsik 		if (info->del_set.index != IPSET_INVALID_ID)
169eafbd3fdSJozsef Kadlecsik 			ip_set_nfnl_put(info->del_set.index);
170d956798dSJozsef Kadlecsik 		return -ERANGE;
171d956798dSJozsef Kadlecsik 	}
172d956798dSJozsef Kadlecsik 
173d956798dSJozsef Kadlecsik 	/* Fill out compatibility data */
174d956798dSJozsef Kadlecsik 	compat_flags(&info->add_set);
175d956798dSJozsef Kadlecsik 	compat_flags(&info->del_set);
176d956798dSJozsef Kadlecsik 
177d956798dSJozsef Kadlecsik 	return 0;
178d956798dSJozsef Kadlecsik }
179d956798dSJozsef Kadlecsik 
180d956798dSJozsef Kadlecsik static void
181d956798dSJozsef Kadlecsik set_target_v0_destroy(const struct xt_tgdtor_param *par)
182d956798dSJozsef Kadlecsik {
183d956798dSJozsef Kadlecsik 	const struct xt_set_info_target_v0 *info = par->targinfo;
184d956798dSJozsef Kadlecsik 
185d956798dSJozsef Kadlecsik 	if (info->add_set.index != IPSET_INVALID_ID)
186d956798dSJozsef Kadlecsik 		ip_set_nfnl_put(info->add_set.index);
187d956798dSJozsef Kadlecsik 	if (info->del_set.index != IPSET_INVALID_ID)
188d956798dSJozsef Kadlecsik 		ip_set_nfnl_put(info->del_set.index);
189d956798dSJozsef Kadlecsik }
190d956798dSJozsef Kadlecsik 
191ac8cc925SJozsef Kadlecsik /* Revision 1 match and target */
192d956798dSJozsef Kadlecsik 
193d956798dSJozsef Kadlecsik static bool
194ac8cc925SJozsef Kadlecsik set_match_v1(const struct sk_buff *skb, struct xt_action_param *par)
195d956798dSJozsef Kadlecsik {
196ac8cc925SJozsef Kadlecsik 	const struct xt_set_info_match_v1 *info = par->matchinfo;
197ac8cc925SJozsef Kadlecsik 	ADT_OPT(opt, par->family, info->match_set.dim,
198ac8cc925SJozsef Kadlecsik 		info->match_set.flags, 0, UINT_MAX);
199d956798dSJozsef Kadlecsik 
200b66554cfSJozsef Kadlecsik 	return match_set(info->match_set.index, skb, par, &opt,
201d956798dSJozsef Kadlecsik 			 info->match_set.flags & IPSET_INV_MATCH);
202d956798dSJozsef Kadlecsik }
203d956798dSJozsef Kadlecsik 
204d956798dSJozsef Kadlecsik static int
205ac8cc925SJozsef Kadlecsik set_match_v1_checkentry(const struct xt_mtchk_param *par)
206d956798dSJozsef Kadlecsik {
207ac8cc925SJozsef Kadlecsik 	struct xt_set_info_match_v1 *info = par->matchinfo;
208d956798dSJozsef Kadlecsik 	ip_set_id_t index;
209d956798dSJozsef Kadlecsik 
210d956798dSJozsef Kadlecsik 	index = ip_set_nfnl_get_byindex(info->match_set.index);
211d956798dSJozsef Kadlecsik 
212d956798dSJozsef Kadlecsik 	if (index == IPSET_INVALID_ID) {
213d956798dSJozsef Kadlecsik 		pr_warning("Cannot find set indentified by id %u to match\n",
214d956798dSJozsef Kadlecsik 			   info->match_set.index);
215d956798dSJozsef Kadlecsik 		return -ENOENT;
216d956798dSJozsef Kadlecsik 	}
217d956798dSJozsef Kadlecsik 	if (info->match_set.dim > IPSET_DIM_MAX) {
218d956798dSJozsef Kadlecsik 		pr_warning("Protocol error: set match dimension "
219d956798dSJozsef Kadlecsik 			   "is over the limit!\n");
220eafbd3fdSJozsef Kadlecsik 		ip_set_nfnl_put(info->match_set.index);
221d956798dSJozsef Kadlecsik 		return -ERANGE;
222d956798dSJozsef Kadlecsik 	}
223d956798dSJozsef Kadlecsik 
224d956798dSJozsef Kadlecsik 	return 0;
225d956798dSJozsef Kadlecsik }
226d956798dSJozsef Kadlecsik 
227d956798dSJozsef Kadlecsik static void
228ac8cc925SJozsef Kadlecsik set_match_v1_destroy(const struct xt_mtdtor_param *par)
229d956798dSJozsef Kadlecsik {
230ac8cc925SJozsef Kadlecsik 	struct xt_set_info_match_v1 *info = par->matchinfo;
231d956798dSJozsef Kadlecsik 
232d956798dSJozsef Kadlecsik 	ip_set_nfnl_put(info->match_set.index);
233d956798dSJozsef Kadlecsik }
234d956798dSJozsef Kadlecsik 
235d956798dSJozsef Kadlecsik static unsigned int
236ac8cc925SJozsef Kadlecsik set_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
237d956798dSJozsef Kadlecsik {
238ac8cc925SJozsef Kadlecsik 	const struct xt_set_info_target_v1 *info = par->targinfo;
239ac8cc925SJozsef Kadlecsik 	ADT_OPT(add_opt, par->family, info->add_set.dim,
240ac8cc925SJozsef Kadlecsik 		info->add_set.flags, 0, UINT_MAX);
241ac8cc925SJozsef Kadlecsik 	ADT_OPT(del_opt, par->family, info->del_set.dim,
242ac8cc925SJozsef Kadlecsik 		info->del_set.flags, 0, UINT_MAX);
243d956798dSJozsef Kadlecsik 
244d956798dSJozsef Kadlecsik 	if (info->add_set.index != IPSET_INVALID_ID)
245b66554cfSJozsef Kadlecsik 		ip_set_add(info->add_set.index, skb, par, &add_opt);
246d956798dSJozsef Kadlecsik 	if (info->del_set.index != IPSET_INVALID_ID)
247b66554cfSJozsef Kadlecsik 		ip_set_del(info->del_set.index, skb, par, &del_opt);
248d956798dSJozsef Kadlecsik 
249d956798dSJozsef Kadlecsik 	return XT_CONTINUE;
250d956798dSJozsef Kadlecsik }
251d956798dSJozsef Kadlecsik 
252d956798dSJozsef Kadlecsik static int
253ac8cc925SJozsef Kadlecsik set_target_v1_checkentry(const struct xt_tgchk_param *par)
254d956798dSJozsef Kadlecsik {
255ac8cc925SJozsef Kadlecsik 	const struct xt_set_info_target_v1 *info = par->targinfo;
256d956798dSJozsef Kadlecsik 	ip_set_id_t index;
257d956798dSJozsef Kadlecsik 
258d956798dSJozsef Kadlecsik 	if (info->add_set.index != IPSET_INVALID_ID) {
259d956798dSJozsef Kadlecsik 		index = ip_set_nfnl_get_byindex(info->add_set.index);
260d956798dSJozsef Kadlecsik 		if (index == IPSET_INVALID_ID) {
261d956798dSJozsef Kadlecsik 			pr_warning("Cannot find add_set index %u as target\n",
262d956798dSJozsef Kadlecsik 				   info->add_set.index);
263d956798dSJozsef Kadlecsik 			return -ENOENT;
264d956798dSJozsef Kadlecsik 		}
265d956798dSJozsef Kadlecsik 	}
266d956798dSJozsef Kadlecsik 
267d956798dSJozsef Kadlecsik 	if (info->del_set.index != IPSET_INVALID_ID) {
268d956798dSJozsef Kadlecsik 		index = ip_set_nfnl_get_byindex(info->del_set.index);
269d956798dSJozsef Kadlecsik 		if (index == IPSET_INVALID_ID) {
270d956798dSJozsef Kadlecsik 			pr_warning("Cannot find del_set index %u as target\n",
271d956798dSJozsef Kadlecsik 				   info->del_set.index);
272eafbd3fdSJozsef Kadlecsik 			if (info->add_set.index != IPSET_INVALID_ID)
273eafbd3fdSJozsef Kadlecsik 				ip_set_nfnl_put(info->add_set.index);
274d956798dSJozsef Kadlecsik 			return -ENOENT;
275d956798dSJozsef Kadlecsik 		}
276d956798dSJozsef Kadlecsik 	}
277d956798dSJozsef Kadlecsik 	if (info->add_set.dim > IPSET_DIM_MAX ||
278eafbd3fdSJozsef Kadlecsik 	    info->del_set.dim > IPSET_DIM_MAX) {
279d956798dSJozsef Kadlecsik 		pr_warning("Protocol error: SET target dimension "
280d956798dSJozsef Kadlecsik 			   "is over the limit!\n");
281eafbd3fdSJozsef Kadlecsik 		if (info->add_set.index != IPSET_INVALID_ID)
282eafbd3fdSJozsef Kadlecsik 			ip_set_nfnl_put(info->add_set.index);
283eafbd3fdSJozsef Kadlecsik 		if (info->del_set.index != IPSET_INVALID_ID)
284eafbd3fdSJozsef Kadlecsik 			ip_set_nfnl_put(info->del_set.index);
285d956798dSJozsef Kadlecsik 		return -ERANGE;
286d956798dSJozsef Kadlecsik 	}
287d956798dSJozsef Kadlecsik 
288d956798dSJozsef Kadlecsik 	return 0;
289d956798dSJozsef Kadlecsik }
290d956798dSJozsef Kadlecsik 
291d956798dSJozsef Kadlecsik static void
292ac8cc925SJozsef Kadlecsik set_target_v1_destroy(const struct xt_tgdtor_param *par)
293d956798dSJozsef Kadlecsik {
294ac8cc925SJozsef Kadlecsik 	const struct xt_set_info_target_v1 *info = par->targinfo;
295d956798dSJozsef Kadlecsik 
296d956798dSJozsef Kadlecsik 	if (info->add_set.index != IPSET_INVALID_ID)
297d956798dSJozsef Kadlecsik 		ip_set_nfnl_put(info->add_set.index);
298d956798dSJozsef Kadlecsik 	if (info->del_set.index != IPSET_INVALID_ID)
299d956798dSJozsef Kadlecsik 		ip_set_nfnl_put(info->del_set.index);
300d956798dSJozsef Kadlecsik }
301d956798dSJozsef Kadlecsik 
302ac8cc925SJozsef Kadlecsik /* Revision 2 target */
303ac8cc925SJozsef Kadlecsik 
304ac8cc925SJozsef Kadlecsik static unsigned int
305ac8cc925SJozsef Kadlecsik set_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
306ac8cc925SJozsef Kadlecsik {
307ac8cc925SJozsef Kadlecsik 	const struct xt_set_info_target_v2 *info = par->targinfo;
308127f5591SJozsef Kadlecsik 	ADT_MOPT(add_opt, par->family, info->add_set.dim,
309ac8cc925SJozsef Kadlecsik 		 info->add_set.flags, info->flags, info->timeout);
310ac8cc925SJozsef Kadlecsik 	ADT_OPT(del_opt, par->family, info->del_set.dim,
311ac8cc925SJozsef Kadlecsik 		info->del_set.flags, 0, UINT_MAX);
312ac8cc925SJozsef Kadlecsik 
313127f5591SJozsef Kadlecsik 	/* Normalize to fit into jiffies */
314a73f89a6SJozsef Kadlecsik 	if (add_opt.timeout != IPSET_NO_TIMEOUT &&
315a73f89a6SJozsef Kadlecsik 	    add_opt.timeout > UINT_MAX/MSEC_PER_SEC)
316127f5591SJozsef Kadlecsik 		add_opt.timeout = UINT_MAX/MSEC_PER_SEC;
317ac8cc925SJozsef Kadlecsik 	if (info->add_set.index != IPSET_INVALID_ID)
318b66554cfSJozsef Kadlecsik 		ip_set_add(info->add_set.index, skb, par, &add_opt);
319ac8cc925SJozsef Kadlecsik 	if (info->del_set.index != IPSET_INVALID_ID)
320b66554cfSJozsef Kadlecsik 		ip_set_del(info->del_set.index, skb, par, &del_opt);
321ac8cc925SJozsef Kadlecsik 
322ac8cc925SJozsef Kadlecsik 	return XT_CONTINUE;
323ac8cc925SJozsef Kadlecsik }
324ac8cc925SJozsef Kadlecsik 
325ac8cc925SJozsef Kadlecsik #define set_target_v2_checkentry	set_target_v1_checkentry
326ac8cc925SJozsef Kadlecsik #define set_target_v2_destroy		set_target_v1_destroy
327ac8cc925SJozsef Kadlecsik 
328d956798dSJozsef Kadlecsik static struct xt_match set_matches[] __read_mostly = {
329d956798dSJozsef Kadlecsik 	{
330d956798dSJozsef Kadlecsik 		.name		= "set",
331d956798dSJozsef Kadlecsik 		.family		= NFPROTO_IPV4,
332d956798dSJozsef Kadlecsik 		.revision	= 0,
333d956798dSJozsef Kadlecsik 		.match		= set_match_v0,
334d956798dSJozsef Kadlecsik 		.matchsize	= sizeof(struct xt_set_info_match_v0),
335d956798dSJozsef Kadlecsik 		.checkentry	= set_match_v0_checkentry,
336d956798dSJozsef Kadlecsik 		.destroy	= set_match_v0_destroy,
337d956798dSJozsef Kadlecsik 		.me		= THIS_MODULE
338d956798dSJozsef Kadlecsik 	},
339d956798dSJozsef Kadlecsik 	{
340d956798dSJozsef Kadlecsik 		.name		= "set",
341d956798dSJozsef Kadlecsik 		.family		= NFPROTO_IPV4,
342d956798dSJozsef Kadlecsik 		.revision	= 1,
343ac8cc925SJozsef Kadlecsik 		.match		= set_match_v1,
344ac8cc925SJozsef Kadlecsik 		.matchsize	= sizeof(struct xt_set_info_match_v1),
345ac8cc925SJozsef Kadlecsik 		.checkentry	= set_match_v1_checkentry,
346ac8cc925SJozsef Kadlecsik 		.destroy	= set_match_v1_destroy,
347d956798dSJozsef Kadlecsik 		.me		= THIS_MODULE
348d956798dSJozsef Kadlecsik 	},
349d956798dSJozsef Kadlecsik 	{
350d956798dSJozsef Kadlecsik 		.name		= "set",
351d956798dSJozsef Kadlecsik 		.family		= NFPROTO_IPV6,
352d956798dSJozsef Kadlecsik 		.revision	= 1,
353ac8cc925SJozsef Kadlecsik 		.match		= set_match_v1,
354ac8cc925SJozsef Kadlecsik 		.matchsize	= sizeof(struct xt_set_info_match_v1),
355ac8cc925SJozsef Kadlecsik 		.checkentry	= set_match_v1_checkentry,
356ac8cc925SJozsef Kadlecsik 		.destroy	= set_match_v1_destroy,
357d956798dSJozsef Kadlecsik 		.me		= THIS_MODULE
358d956798dSJozsef Kadlecsik 	},
359d956798dSJozsef Kadlecsik };
360d956798dSJozsef Kadlecsik 
361d956798dSJozsef Kadlecsik static struct xt_target set_targets[] __read_mostly = {
362d956798dSJozsef Kadlecsik 	{
363d956798dSJozsef Kadlecsik 		.name		= "SET",
364d956798dSJozsef Kadlecsik 		.revision	= 0,
365d956798dSJozsef Kadlecsik 		.family		= NFPROTO_IPV4,
366d956798dSJozsef Kadlecsik 		.target		= set_target_v0,
367d956798dSJozsef Kadlecsik 		.targetsize	= sizeof(struct xt_set_info_target_v0),
368d956798dSJozsef Kadlecsik 		.checkentry	= set_target_v0_checkentry,
369d956798dSJozsef Kadlecsik 		.destroy	= set_target_v0_destroy,
370d956798dSJozsef Kadlecsik 		.me		= THIS_MODULE
371d956798dSJozsef Kadlecsik 	},
372d956798dSJozsef Kadlecsik 	{
373d956798dSJozsef Kadlecsik 		.name		= "SET",
374d956798dSJozsef Kadlecsik 		.revision	= 1,
375d956798dSJozsef Kadlecsik 		.family		= NFPROTO_IPV4,
376ac8cc925SJozsef Kadlecsik 		.target		= set_target_v1,
377ac8cc925SJozsef Kadlecsik 		.targetsize	= sizeof(struct xt_set_info_target_v1),
378ac8cc925SJozsef Kadlecsik 		.checkentry	= set_target_v1_checkentry,
379ac8cc925SJozsef Kadlecsik 		.destroy	= set_target_v1_destroy,
380d956798dSJozsef Kadlecsik 		.me		= THIS_MODULE
381d956798dSJozsef Kadlecsik 	},
382d956798dSJozsef Kadlecsik 	{
383d956798dSJozsef Kadlecsik 		.name		= "SET",
384d956798dSJozsef Kadlecsik 		.revision	= 1,
385d956798dSJozsef Kadlecsik 		.family		= NFPROTO_IPV6,
386ac8cc925SJozsef Kadlecsik 		.target		= set_target_v1,
387ac8cc925SJozsef Kadlecsik 		.targetsize	= sizeof(struct xt_set_info_target_v1),
388ac8cc925SJozsef Kadlecsik 		.checkentry	= set_target_v1_checkentry,
389ac8cc925SJozsef Kadlecsik 		.destroy	= set_target_v1_destroy,
390ac8cc925SJozsef Kadlecsik 		.me		= THIS_MODULE
391ac8cc925SJozsef Kadlecsik 	},
392ac8cc925SJozsef Kadlecsik 	{
393ac8cc925SJozsef Kadlecsik 		.name		= "SET",
394ac8cc925SJozsef Kadlecsik 		.revision	= 2,
395ac8cc925SJozsef Kadlecsik 		.family		= NFPROTO_IPV4,
396ac8cc925SJozsef Kadlecsik 		.target		= set_target_v2,
397ac8cc925SJozsef Kadlecsik 		.targetsize	= sizeof(struct xt_set_info_target_v2),
398ac8cc925SJozsef Kadlecsik 		.checkentry	= set_target_v2_checkentry,
399ac8cc925SJozsef Kadlecsik 		.destroy	= set_target_v2_destroy,
400ac8cc925SJozsef Kadlecsik 		.me		= THIS_MODULE
401ac8cc925SJozsef Kadlecsik 	},
402ac8cc925SJozsef Kadlecsik 	{
403ac8cc925SJozsef Kadlecsik 		.name		= "SET",
404ac8cc925SJozsef Kadlecsik 		.revision	= 2,
405ac8cc925SJozsef Kadlecsik 		.family		= NFPROTO_IPV6,
406ac8cc925SJozsef Kadlecsik 		.target		= set_target_v2,
407ac8cc925SJozsef Kadlecsik 		.targetsize	= sizeof(struct xt_set_info_target_v2),
408ac8cc925SJozsef Kadlecsik 		.checkentry	= set_target_v2_checkentry,
409ac8cc925SJozsef Kadlecsik 		.destroy	= set_target_v2_destroy,
410d956798dSJozsef Kadlecsik 		.me		= THIS_MODULE
411d956798dSJozsef Kadlecsik 	},
412d956798dSJozsef Kadlecsik };
413d956798dSJozsef Kadlecsik 
414d956798dSJozsef Kadlecsik static int __init xt_set_init(void)
415d956798dSJozsef Kadlecsik {
416d956798dSJozsef Kadlecsik 	int ret = xt_register_matches(set_matches, ARRAY_SIZE(set_matches));
417d956798dSJozsef Kadlecsik 
418d956798dSJozsef Kadlecsik 	if (!ret) {
419d956798dSJozsef Kadlecsik 		ret = xt_register_targets(set_targets,
420d956798dSJozsef Kadlecsik 					  ARRAY_SIZE(set_targets));
421d956798dSJozsef Kadlecsik 		if (ret)
422d956798dSJozsef Kadlecsik 			xt_unregister_matches(set_matches,
423d956798dSJozsef Kadlecsik 					      ARRAY_SIZE(set_matches));
424d956798dSJozsef Kadlecsik 	}
425d956798dSJozsef Kadlecsik 	return ret;
426d956798dSJozsef Kadlecsik }
427d956798dSJozsef Kadlecsik 
428d956798dSJozsef Kadlecsik static void __exit xt_set_fini(void)
429d956798dSJozsef Kadlecsik {
430d956798dSJozsef Kadlecsik 	xt_unregister_matches(set_matches, ARRAY_SIZE(set_matches));
431d956798dSJozsef Kadlecsik 	xt_unregister_targets(set_targets, ARRAY_SIZE(set_targets));
432d956798dSJozsef Kadlecsik }
433d956798dSJozsef Kadlecsik 
434d956798dSJozsef Kadlecsik module_init(xt_set_init);
435d956798dSJozsef Kadlecsik module_exit(xt_set_fini);
436