Merge branches 'acpi-tables', 'acpi-osl', 'acpi-misc' and 'acpi-tools'
[sfrench/cifs-2.6.git] / net / netfilter / xt_set.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
3  *                         Patrick Schaaf <bof@bof.de>
4  *                         Martin Josefsson <gandalf@wlug.westbo.se>
5  * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
6  */
7
8 /* Kernel module which implements the set match and SET target
9  * for netfilter/iptables.
10  */
11
12 #include <linux/module.h>
13 #include <linux/skbuff.h>
14
15 #include <linux/netfilter/x_tables.h>
16 #include <linux/netfilter/ipset/ip_set.h>
17 #include <linux/netfilter/ipset/ip_set_timeout.h>
18 #include <uapi/linux/netfilter/xt_set.h>
19
20 MODULE_LICENSE("GPL");
21 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
22 MODULE_DESCRIPTION("Xtables: IP set match and target module");
23 MODULE_ALIAS("xt_SET");
24 MODULE_ALIAS("ipt_set");
25 MODULE_ALIAS("ip6t_set");
26 MODULE_ALIAS("ipt_SET");
27 MODULE_ALIAS("ip6t_SET");
28
29 static inline int
30 match_set(ip_set_id_t index, const struct sk_buff *skb,
31           const struct xt_action_param *par,
32           struct ip_set_adt_opt *opt, int inv)
33 {
34         if (ip_set_test(index, skb, par, opt))
35                 inv = !inv;
36         return inv;
37 }
38
39 #define ADT_OPT(n, f, d, fs, cfs, t, p, b, po, bo)      \
40 struct ip_set_adt_opt n = {                             \
41         .family = f,                                    \
42         .dim = d,                                       \
43         .flags = fs,                                    \
44         .cmdflags = cfs,                                \
45         .ext.timeout = t,                               \
46         .ext.packets = p,                               \
47         .ext.bytes = b,                                 \
48         .ext.packets_op = po,                           \
49         .ext.bytes_op = bo,                             \
50 }
51
52 /* Revision 0 interface: backward compatible with netfilter/iptables */
53
54 static bool
55 set_match_v0(const struct sk_buff *skb, struct xt_action_param *par)
56 {
57         const struct xt_set_info_match_v0 *info = par->matchinfo;
58
59         ADT_OPT(opt, xt_family(par), info->match_set.u.compat.dim,
60                 info->match_set.u.compat.flags, 0, UINT_MAX,
61                 0, 0, 0, 0);
62
63         return match_set(info->match_set.index, skb, par, &opt,
64                          info->match_set.u.compat.flags & IPSET_INV_MATCH);
65 }
66
67 static void
68 compat_flags(struct xt_set_info_v0 *info)
69 {
70         u_int8_t i;
71
72         /* Fill out compatibility data according to enum ip_set_kopt */
73         info->u.compat.dim = IPSET_DIM_ZERO;
74         if (info->u.flags[0] & IPSET_MATCH_INV)
75                 info->u.compat.flags |= IPSET_INV_MATCH;
76         for (i = 0; i < IPSET_DIM_MAX - 1 && info->u.flags[i]; i++) {
77                 info->u.compat.dim++;
78                 if (info->u.flags[i] & IPSET_SRC)
79                         info->u.compat.flags |= (1 << info->u.compat.dim);
80         }
81 }
82
83 static int
84 set_match_v0_checkentry(const struct xt_mtchk_param *par)
85 {
86         struct xt_set_info_match_v0 *info = par->matchinfo;
87         ip_set_id_t index;
88
89         index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
90
91         if (index == IPSET_INVALID_ID) {
92                 pr_info_ratelimited("Cannot find set identified by id %u to match\n",
93                                     info->match_set.index);
94                 return -ENOENT;
95         }
96         if (info->match_set.u.flags[IPSET_DIM_MAX - 1] != 0) {
97                 pr_info_ratelimited("set match dimension is over the limit!\n");
98                 ip_set_nfnl_put(par->net, info->match_set.index);
99                 return -ERANGE;
100         }
101
102         /* Fill out compatibility data */
103         compat_flags(&info->match_set);
104
105         return 0;
106 }
107
108 static void
109 set_match_v0_destroy(const struct xt_mtdtor_param *par)
110 {
111         struct xt_set_info_match_v0 *info = par->matchinfo;
112
113         ip_set_nfnl_put(par->net, info->match_set.index);
114 }
115
116 /* Revision 1 match */
117
118 static bool
119 set_match_v1(const struct sk_buff *skb, struct xt_action_param *par)
120 {
121         const struct xt_set_info_match_v1 *info = par->matchinfo;
122
123         ADT_OPT(opt, xt_family(par), info->match_set.dim,
124                 info->match_set.flags, 0, UINT_MAX,
125                 0, 0, 0, 0);
126
127         if (opt.flags & IPSET_RETURN_NOMATCH)
128                 opt.cmdflags |= IPSET_FLAG_RETURN_NOMATCH;
129
130         return match_set(info->match_set.index, skb, par, &opt,
131                          info->match_set.flags & IPSET_INV_MATCH);
132 }
133
134 static int
135 set_match_v1_checkentry(const struct xt_mtchk_param *par)
136 {
137         struct xt_set_info_match_v1 *info = par->matchinfo;
138         ip_set_id_t index;
139
140         index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
141
142         if (index == IPSET_INVALID_ID) {
143                 pr_info_ratelimited("Cannot find set identified by id %u to match\n",
144                                     info->match_set.index);
145                 return -ENOENT;
146         }
147         if (info->match_set.dim > IPSET_DIM_MAX) {
148                 pr_info_ratelimited("set match dimension is over the limit!\n");
149                 ip_set_nfnl_put(par->net, info->match_set.index);
150                 return -ERANGE;
151         }
152
153         return 0;
154 }
155
156 static void
157 set_match_v1_destroy(const struct xt_mtdtor_param *par)
158 {
159         struct xt_set_info_match_v1 *info = par->matchinfo;
160
161         ip_set_nfnl_put(par->net, info->match_set.index);
162 }
163
164 /* Revision 3 match */
165
166 static bool
167 set_match_v3(const struct sk_buff *skb, struct xt_action_param *par)
168 {
169         const struct xt_set_info_match_v3 *info = par->matchinfo;
170
171         ADT_OPT(opt, xt_family(par), info->match_set.dim,
172                 info->match_set.flags, info->flags, UINT_MAX,
173                 info->packets.value, info->bytes.value,
174                 info->packets.op, info->bytes.op);
175
176         if (info->packets.op != IPSET_COUNTER_NONE ||
177             info->bytes.op != IPSET_COUNTER_NONE)
178                 opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS;
179
180         return match_set(info->match_set.index, skb, par, &opt,
181                          info->match_set.flags & IPSET_INV_MATCH);
182 }
183
184 #define set_match_v3_checkentry set_match_v1_checkentry
185 #define set_match_v3_destroy    set_match_v1_destroy
186
187 /* Revision 4 match */
188
189 static bool
190 set_match_v4(const struct sk_buff *skb, struct xt_action_param *par)
191 {
192         const struct xt_set_info_match_v4 *info = par->matchinfo;
193
194         ADT_OPT(opt, xt_family(par), info->match_set.dim,
195                 info->match_set.flags, info->flags, UINT_MAX,
196                 info->packets.value, info->bytes.value,
197                 info->packets.op, info->bytes.op);
198
199         if (info->packets.op != IPSET_COUNTER_NONE ||
200             info->bytes.op != IPSET_COUNTER_NONE)
201                 opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS;
202
203         return match_set(info->match_set.index, skb, par, &opt,
204                          info->match_set.flags & IPSET_INV_MATCH);
205 }
206
207 #define set_match_v4_checkentry set_match_v1_checkentry
208 #define set_match_v4_destroy    set_match_v1_destroy
209
210 /* Revision 0 interface: backward compatible with netfilter/iptables */
211
212 static unsigned int
213 set_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
214 {
215         const struct xt_set_info_target_v0 *info = par->targinfo;
216
217         ADT_OPT(add_opt, xt_family(par), info->add_set.u.compat.dim,
218                 info->add_set.u.compat.flags, 0, UINT_MAX,
219                 0, 0, 0, 0);
220         ADT_OPT(del_opt, xt_family(par), info->del_set.u.compat.dim,
221                 info->del_set.u.compat.flags, 0, UINT_MAX,
222                 0, 0, 0, 0);
223
224         if (info->add_set.index != IPSET_INVALID_ID)
225                 ip_set_add(info->add_set.index, skb, par, &add_opt);
226         if (info->del_set.index != IPSET_INVALID_ID)
227                 ip_set_del(info->del_set.index, skb, par, &del_opt);
228
229         return XT_CONTINUE;
230 }
231
232 static int
233 set_target_v0_checkentry(const struct xt_tgchk_param *par)
234 {
235         struct xt_set_info_target_v0 *info = par->targinfo;
236         ip_set_id_t index;
237
238         if (info->add_set.index != IPSET_INVALID_ID) {
239                 index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
240                 if (index == IPSET_INVALID_ID) {
241                         pr_info_ratelimited("Cannot find add_set index %u as target\n",
242                                             info->add_set.index);
243                         return -ENOENT;
244                 }
245         }
246
247         if (info->del_set.index != IPSET_INVALID_ID) {
248                 index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
249                 if (index == IPSET_INVALID_ID) {
250                         pr_info_ratelimited("Cannot find del_set index %u as target\n",
251                                             info->del_set.index);
252                         if (info->add_set.index != IPSET_INVALID_ID)
253                                 ip_set_nfnl_put(par->net, info->add_set.index);
254                         return -ENOENT;
255                 }
256         }
257         if (info->add_set.u.flags[IPSET_DIM_MAX - 1] != 0 ||
258             info->del_set.u.flags[IPSET_DIM_MAX - 1] != 0) {
259                 pr_info_ratelimited("SET target dimension over the limit!\n");
260                 if (info->add_set.index != IPSET_INVALID_ID)
261                         ip_set_nfnl_put(par->net, info->add_set.index);
262                 if (info->del_set.index != IPSET_INVALID_ID)
263                         ip_set_nfnl_put(par->net, info->del_set.index);
264                 return -ERANGE;
265         }
266
267         /* Fill out compatibility data */
268         compat_flags(&info->add_set);
269         compat_flags(&info->del_set);
270
271         return 0;
272 }
273
274 static void
275 set_target_v0_destroy(const struct xt_tgdtor_param *par)
276 {
277         const struct xt_set_info_target_v0 *info = par->targinfo;
278
279         if (info->add_set.index != IPSET_INVALID_ID)
280                 ip_set_nfnl_put(par->net, info->add_set.index);
281         if (info->del_set.index != IPSET_INVALID_ID)
282                 ip_set_nfnl_put(par->net, info->del_set.index);
283 }
284
285 /* Revision 1 target */
286
287 static unsigned int
288 set_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
289 {
290         const struct xt_set_info_target_v1 *info = par->targinfo;
291
292         ADT_OPT(add_opt, xt_family(par), info->add_set.dim,
293                 info->add_set.flags, 0, UINT_MAX,
294                 0, 0, 0, 0);
295         ADT_OPT(del_opt, xt_family(par), info->del_set.dim,
296                 info->del_set.flags, 0, UINT_MAX,
297                 0, 0, 0, 0);
298
299         if (info->add_set.index != IPSET_INVALID_ID)
300                 ip_set_add(info->add_set.index, skb, par, &add_opt);
301         if (info->del_set.index != IPSET_INVALID_ID)
302                 ip_set_del(info->del_set.index, skb, par, &del_opt);
303
304         return XT_CONTINUE;
305 }
306
307 static int
308 set_target_v1_checkentry(const struct xt_tgchk_param *par)
309 {
310         const struct xt_set_info_target_v1 *info = par->targinfo;
311         ip_set_id_t index;
312
313         if (info->add_set.index != IPSET_INVALID_ID) {
314                 index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
315                 if (index == IPSET_INVALID_ID) {
316                         pr_info_ratelimited("Cannot find add_set index %u as target\n",
317                                             info->add_set.index);
318                         return -ENOENT;
319                 }
320         }
321
322         if (info->del_set.index != IPSET_INVALID_ID) {
323                 index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
324                 if (index == IPSET_INVALID_ID) {
325                         pr_info_ratelimited("Cannot find del_set index %u as target\n",
326                                             info->del_set.index);
327                         if (info->add_set.index != IPSET_INVALID_ID)
328                                 ip_set_nfnl_put(par->net, info->add_set.index);
329                         return -ENOENT;
330                 }
331         }
332         if (info->add_set.dim > IPSET_DIM_MAX ||
333             info->del_set.dim > IPSET_DIM_MAX) {
334                 pr_info_ratelimited("SET target dimension over the limit!\n");
335                 if (info->add_set.index != IPSET_INVALID_ID)
336                         ip_set_nfnl_put(par->net, info->add_set.index);
337                 if (info->del_set.index != IPSET_INVALID_ID)
338                         ip_set_nfnl_put(par->net, info->del_set.index);
339                 return -ERANGE;
340         }
341
342         return 0;
343 }
344
345 static void
346 set_target_v1_destroy(const struct xt_tgdtor_param *par)
347 {
348         const struct xt_set_info_target_v1 *info = par->targinfo;
349
350         if (info->add_set.index != IPSET_INVALID_ID)
351                 ip_set_nfnl_put(par->net, info->add_set.index);
352         if (info->del_set.index != IPSET_INVALID_ID)
353                 ip_set_nfnl_put(par->net, info->del_set.index);
354 }
355
356 /* Revision 2 target */
357
358 static unsigned int
359 set_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
360 {
361         const struct xt_set_info_target_v2 *info = par->targinfo;
362
363         ADT_OPT(add_opt, xt_family(par), info->add_set.dim,
364                 info->add_set.flags, info->flags, info->timeout,
365                 0, 0, 0, 0);
366         ADT_OPT(del_opt, xt_family(par), info->del_set.dim,
367                 info->del_set.flags, 0, UINT_MAX,
368                 0, 0, 0, 0);
369
370         /* Normalize to fit into jiffies */
371         if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
372             add_opt.ext.timeout > IPSET_MAX_TIMEOUT)
373                 add_opt.ext.timeout = IPSET_MAX_TIMEOUT;
374         if (info->add_set.index != IPSET_INVALID_ID)
375                 ip_set_add(info->add_set.index, skb, par, &add_opt);
376         if (info->del_set.index != IPSET_INVALID_ID)
377                 ip_set_del(info->del_set.index, skb, par, &del_opt);
378
379         return XT_CONTINUE;
380 }
381
382 #define set_target_v2_checkentry        set_target_v1_checkentry
383 #define set_target_v2_destroy           set_target_v1_destroy
384
385 /* Revision 3 target */
386
387 #define MOPT(opt, member)       ((opt).ext.skbinfo.member)
388
389 static unsigned int
390 set_target_v3(struct sk_buff *skb, const struct xt_action_param *par)
391 {
392         const struct xt_set_info_target_v3 *info = par->targinfo;
393         int ret;
394
395         ADT_OPT(add_opt, xt_family(par), info->add_set.dim,
396                 info->add_set.flags, info->flags, info->timeout,
397                 0, 0, 0, 0);
398         ADT_OPT(del_opt, xt_family(par), info->del_set.dim,
399                 info->del_set.flags, 0, UINT_MAX,
400                 0, 0, 0, 0);
401         ADT_OPT(map_opt, xt_family(par), info->map_set.dim,
402                 info->map_set.flags, 0, UINT_MAX,
403                 0, 0, 0, 0);
404
405         /* Normalize to fit into jiffies */
406         if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
407             add_opt.ext.timeout > IPSET_MAX_TIMEOUT)
408                 add_opt.ext.timeout = IPSET_MAX_TIMEOUT;
409         if (info->add_set.index != IPSET_INVALID_ID)
410                 ip_set_add(info->add_set.index, skb, par, &add_opt);
411         if (info->del_set.index != IPSET_INVALID_ID)
412                 ip_set_del(info->del_set.index, skb, par, &del_opt);
413         if (info->map_set.index != IPSET_INVALID_ID) {
414                 map_opt.cmdflags |= info->flags & (IPSET_FLAG_MAP_SKBMARK |
415                                                    IPSET_FLAG_MAP_SKBPRIO |
416                                                    IPSET_FLAG_MAP_SKBQUEUE);
417                 ret = match_set(info->map_set.index, skb, par, &map_opt,
418                                 info->map_set.flags & IPSET_INV_MATCH);
419                 if (!ret)
420                         return XT_CONTINUE;
421                 if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBMARK)
422                         skb->mark = (skb->mark & ~MOPT(map_opt,skbmarkmask))
423                                     ^ MOPT(map_opt, skbmark);
424                 if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBPRIO)
425                         skb->priority = MOPT(map_opt, skbprio);
426                 if ((map_opt.cmdflags & IPSET_FLAG_MAP_SKBQUEUE) &&
427                     skb->dev &&
428                     skb->dev->real_num_tx_queues > MOPT(map_opt, skbqueue))
429                         skb_set_queue_mapping(skb, MOPT(map_opt, skbqueue));
430         }
431         return XT_CONTINUE;
432 }
433
434 static int
435 set_target_v3_checkentry(const struct xt_tgchk_param *par)
436 {
437         const struct xt_set_info_target_v3 *info = par->targinfo;
438         ip_set_id_t index;
439
440         if (info->add_set.index != IPSET_INVALID_ID) {
441                 index = ip_set_nfnl_get_byindex(par->net,
442                                                 info->add_set.index);
443                 if (index == IPSET_INVALID_ID) {
444                         pr_info_ratelimited("Cannot find add_set index %u as target\n",
445                                             info->add_set.index);
446                         return -ENOENT;
447                 }
448         }
449
450         if (info->del_set.index != IPSET_INVALID_ID) {
451                 index = ip_set_nfnl_get_byindex(par->net,
452                                                 info->del_set.index);
453                 if (index == IPSET_INVALID_ID) {
454                         pr_info_ratelimited("Cannot find del_set index %u as target\n",
455                                             info->del_set.index);
456                         if (info->add_set.index != IPSET_INVALID_ID)
457                                 ip_set_nfnl_put(par->net,
458                                                 info->add_set.index);
459                         return -ENOENT;
460                 }
461         }
462
463         if (info->map_set.index != IPSET_INVALID_ID) {
464                 if (strncmp(par->table, "mangle", 7)) {
465                         pr_info_ratelimited("--map-set only usable from mangle table\n");
466                         return -EINVAL;
467                 }
468                 if (((info->flags & IPSET_FLAG_MAP_SKBPRIO) |
469                      (info->flags & IPSET_FLAG_MAP_SKBQUEUE)) &&
470                      (par->hook_mask & ~(1 << NF_INET_FORWARD |
471                                          1 << NF_INET_LOCAL_OUT |
472                                          1 << NF_INET_POST_ROUTING))) {
473                         pr_info_ratelimited("mapping of prio or/and queue is allowed only from OUTPUT/FORWARD/POSTROUTING chains\n");
474                         return -EINVAL;
475                 }
476                 index = ip_set_nfnl_get_byindex(par->net,
477                                                 info->map_set.index);
478                 if (index == IPSET_INVALID_ID) {
479                         pr_info_ratelimited("Cannot find map_set index %u as target\n",
480                                             info->map_set.index);
481                         if (info->add_set.index != IPSET_INVALID_ID)
482                                 ip_set_nfnl_put(par->net,
483                                                 info->add_set.index);
484                         if (info->del_set.index != IPSET_INVALID_ID)
485                                 ip_set_nfnl_put(par->net,
486                                                 info->del_set.index);
487                         return -ENOENT;
488                 }
489         }
490
491         if (info->add_set.dim > IPSET_DIM_MAX ||
492             info->del_set.dim > IPSET_DIM_MAX ||
493             info->map_set.dim > IPSET_DIM_MAX) {
494                 pr_info_ratelimited("SET target dimension over the limit!\n");
495                 if (info->add_set.index != IPSET_INVALID_ID)
496                         ip_set_nfnl_put(par->net, info->add_set.index);
497                 if (info->del_set.index != IPSET_INVALID_ID)
498                         ip_set_nfnl_put(par->net, info->del_set.index);
499                 if (info->map_set.index != IPSET_INVALID_ID)
500                         ip_set_nfnl_put(par->net, info->map_set.index);
501                 return -ERANGE;
502         }
503
504         return 0;
505 }
506
507 static void
508 set_target_v3_destroy(const struct xt_tgdtor_param *par)
509 {
510         const struct xt_set_info_target_v3 *info = par->targinfo;
511
512         if (info->add_set.index != IPSET_INVALID_ID)
513                 ip_set_nfnl_put(par->net, info->add_set.index);
514         if (info->del_set.index != IPSET_INVALID_ID)
515                 ip_set_nfnl_put(par->net, info->del_set.index);
516         if (info->map_set.index != IPSET_INVALID_ID)
517                 ip_set_nfnl_put(par->net, info->map_set.index);
518 }
519
520 static struct xt_match set_matches[] __read_mostly = {
521         {
522                 .name           = "set",
523                 .family         = NFPROTO_IPV4,
524                 .revision       = 0,
525                 .match          = set_match_v0,
526                 .matchsize      = sizeof(struct xt_set_info_match_v0),
527                 .checkentry     = set_match_v0_checkentry,
528                 .destroy        = set_match_v0_destroy,
529                 .me             = THIS_MODULE
530         },
531         {
532                 .name           = "set",
533                 .family         = NFPROTO_IPV4,
534                 .revision       = 1,
535                 .match          = set_match_v1,
536                 .matchsize      = sizeof(struct xt_set_info_match_v1),
537                 .checkentry     = set_match_v1_checkentry,
538                 .destroy        = set_match_v1_destroy,
539                 .me             = THIS_MODULE
540         },
541         {
542                 .name           = "set",
543                 .family         = NFPROTO_IPV6,
544                 .revision       = 1,
545                 .match          = set_match_v1,
546                 .matchsize      = sizeof(struct xt_set_info_match_v1),
547                 .checkentry     = set_match_v1_checkentry,
548                 .destroy        = set_match_v1_destroy,
549                 .me             = THIS_MODULE
550         },
551         /* --return-nomatch flag support */
552         {
553                 .name           = "set",
554                 .family         = NFPROTO_IPV4,
555                 .revision       = 2,
556                 .match          = set_match_v1,
557                 .matchsize      = sizeof(struct xt_set_info_match_v1),
558                 .checkentry     = set_match_v1_checkentry,
559                 .destroy        = set_match_v1_destroy,
560                 .me             = THIS_MODULE
561         },
562         {
563                 .name           = "set",
564                 .family         = NFPROTO_IPV6,
565                 .revision       = 2,
566                 .match          = set_match_v1,
567                 .matchsize      = sizeof(struct xt_set_info_match_v1),
568                 .checkentry     = set_match_v1_checkentry,
569                 .destroy        = set_match_v1_destroy,
570                 .me             = THIS_MODULE
571         },
572         /* counters support: update, match */
573         {
574                 .name           = "set",
575                 .family         = NFPROTO_IPV4,
576                 .revision       = 3,
577                 .match          = set_match_v3,
578                 .matchsize      = sizeof(struct xt_set_info_match_v3),
579                 .checkentry     = set_match_v3_checkentry,
580                 .destroy        = set_match_v3_destroy,
581                 .me             = THIS_MODULE
582         },
583         {
584                 .name           = "set",
585                 .family         = NFPROTO_IPV6,
586                 .revision       = 3,
587                 .match          = set_match_v3,
588                 .matchsize      = sizeof(struct xt_set_info_match_v3),
589                 .checkentry     = set_match_v3_checkentry,
590                 .destroy        = set_match_v3_destroy,
591                 .me             = THIS_MODULE
592         },
593         /* new revision for counters support: update, match */
594         {
595                 .name           = "set",
596                 .family         = NFPROTO_IPV4,
597                 .revision       = 4,
598                 .match          = set_match_v4,
599                 .matchsize      = sizeof(struct xt_set_info_match_v4),
600                 .checkentry     = set_match_v4_checkentry,
601                 .destroy        = set_match_v4_destroy,
602                 .me             = THIS_MODULE
603         },
604         {
605                 .name           = "set",
606                 .family         = NFPROTO_IPV6,
607                 .revision       = 4,
608                 .match          = set_match_v4,
609                 .matchsize      = sizeof(struct xt_set_info_match_v4),
610                 .checkentry     = set_match_v4_checkentry,
611                 .destroy        = set_match_v4_destroy,
612                 .me             = THIS_MODULE
613         },
614 };
615
616 static struct xt_target set_targets[] __read_mostly = {
617         {
618                 .name           = "SET",
619                 .revision       = 0,
620                 .family         = NFPROTO_IPV4,
621                 .target         = set_target_v0,
622                 .targetsize     = sizeof(struct xt_set_info_target_v0),
623                 .checkentry     = set_target_v0_checkentry,
624                 .destroy        = set_target_v0_destroy,
625                 .me             = THIS_MODULE
626         },
627         {
628                 .name           = "SET",
629                 .revision       = 1,
630                 .family         = NFPROTO_IPV4,
631                 .target         = set_target_v1,
632                 .targetsize     = sizeof(struct xt_set_info_target_v1),
633                 .checkentry     = set_target_v1_checkentry,
634                 .destroy        = set_target_v1_destroy,
635                 .me             = THIS_MODULE
636         },
637         {
638                 .name           = "SET",
639                 .revision       = 1,
640                 .family         = NFPROTO_IPV6,
641                 .target         = set_target_v1,
642                 .targetsize     = sizeof(struct xt_set_info_target_v1),
643                 .checkentry     = set_target_v1_checkentry,
644                 .destroy        = set_target_v1_destroy,
645                 .me             = THIS_MODULE
646         },
647         /* --timeout and --exist flags support */
648         {
649                 .name           = "SET",
650                 .revision       = 2,
651                 .family         = NFPROTO_IPV4,
652                 .target         = set_target_v2,
653                 .targetsize     = sizeof(struct xt_set_info_target_v2),
654                 .checkentry     = set_target_v2_checkentry,
655                 .destroy        = set_target_v2_destroy,
656                 .me             = THIS_MODULE
657         },
658         {
659                 .name           = "SET",
660                 .revision       = 2,
661                 .family         = NFPROTO_IPV6,
662                 .target         = set_target_v2,
663                 .targetsize     = sizeof(struct xt_set_info_target_v2),
664                 .checkentry     = set_target_v2_checkentry,
665                 .destroy        = set_target_v2_destroy,
666                 .me             = THIS_MODULE
667         },
668         /* --map-set support */
669         {
670                 .name           = "SET",
671                 .revision       = 3,
672                 .family         = NFPROTO_IPV4,
673                 .target         = set_target_v3,
674                 .targetsize     = sizeof(struct xt_set_info_target_v3),
675                 .checkentry     = set_target_v3_checkentry,
676                 .destroy        = set_target_v3_destroy,
677                 .me             = THIS_MODULE
678         },
679         {
680                 .name           = "SET",
681                 .revision       = 3,
682                 .family         = NFPROTO_IPV6,
683                 .target         = set_target_v3,
684                 .targetsize     = sizeof(struct xt_set_info_target_v3),
685                 .checkentry     = set_target_v3_checkentry,
686                 .destroy        = set_target_v3_destroy,
687                 .me             = THIS_MODULE
688         },
689 };
690
691 static int __init xt_set_init(void)
692 {
693         int ret = xt_register_matches(set_matches, ARRAY_SIZE(set_matches));
694
695         if (!ret) {
696                 ret = xt_register_targets(set_targets,
697                                           ARRAY_SIZE(set_targets));
698                 if (ret)
699                         xt_unregister_matches(set_matches,
700                                               ARRAY_SIZE(set_matches));
701         }
702         return ret;
703 }
704
705 static void __exit xt_set_fini(void)
706 {
707         xt_unregister_matches(set_matches, ARRAY_SIZE(set_matches));
708         xt_unregister_targets(set_targets, ARRAY_SIZE(set_targets));
709 }
710
711 module_init(xt_set_init);
712 module_exit(xt_set_fini);