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