2 * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
8 * This software has been sponsored by Sophos Astaro <http://www.sophos.com>
11 #include <linux/kernel.h>
12 #include <linux/init.h>
13 #include <linux/module.h>
14 #include <linux/netlink.h>
15 #include <linux/netfilter.h>
16 #include <linux/netfilter/nfnetlink.h>
17 #include <linux/netfilter/nf_tables.h>
18 #include <linux/netfilter/nf_tables_compat.h>
19 #include <linux/netfilter/x_tables.h>
20 #include <linux/netfilter_ipv4/ip_tables.h>
21 #include <linux/netfilter_ipv6/ip6_tables.h>
22 #include <linux/netfilter_bridge/ebtables.h>
23 #include <linux/netfilter_arp/arp_tables.h>
24 #include <net/netfilter/nf_tables.h>
27 struct list_head head
;
28 struct nft_expr_ops ops
;
32 static void nft_xt_put(struct nft_xt
*xt
)
34 if (--xt
->refcnt
== 0) {
40 static int nft_compat_chain_validate_dependency(const char *tablename
,
41 const struct nft_chain
*chain
)
43 const struct nft_base_chain
*basechain
;
45 if (!tablename
|| !(chain
->flags
& NFT_BASE_CHAIN
))
48 basechain
= nft_base_chain(chain
);
49 if (strcmp(tablename
, "nat") == 0 &&
50 basechain
->type
->type
!= NFT_CHAIN_T_NAT
)
60 struct arpt_entry arp
;
64 nft_compat_set_par(struct xt_action_param
*par
, void *xt
, const void *xt_info
)
67 par
->targinfo
= xt_info
;
71 static void nft_target_eval_xt(const struct nft_expr
*expr
,
72 struct nft_regs
*regs
,
73 const struct nft_pktinfo
*pkt
)
75 void *info
= nft_expr_priv(expr
);
76 struct xt_target
*target
= expr
->ops
->data
;
77 struct sk_buff
*skb
= pkt
->skb
;
80 nft_compat_set_par((struct xt_action_param
*)&pkt
->xt
, target
, info
);
82 ret
= target
->target(skb
, &pkt
->xt
);
89 regs
->verdict
.code
= NFT_CONTINUE
;
92 regs
->verdict
.code
= ret
;
97 static void nft_target_eval_bridge(const struct nft_expr
*expr
,
98 struct nft_regs
*regs
,
99 const struct nft_pktinfo
*pkt
)
101 void *info
= nft_expr_priv(expr
);
102 struct xt_target
*target
= expr
->ops
->data
;
103 struct sk_buff
*skb
= pkt
->skb
;
106 nft_compat_set_par((struct xt_action_param
*)&pkt
->xt
, target
, info
);
108 ret
= target
->target(skb
, &pkt
->xt
);
115 regs
->verdict
.code
= NF_ACCEPT
;
118 regs
->verdict
.code
= NF_DROP
;
121 regs
->verdict
.code
= NFT_CONTINUE
;
124 regs
->verdict
.code
= NFT_RETURN
;
127 regs
->verdict
.code
= ret
;
132 static const struct nla_policy nft_target_policy
[NFTA_TARGET_MAX
+ 1] = {
133 [NFTA_TARGET_NAME
] = { .type
= NLA_NUL_STRING
},
134 [NFTA_TARGET_REV
] = { .type
= NLA_U32
},
135 [NFTA_TARGET_INFO
] = { .type
= NLA_BINARY
},
139 nft_target_set_tgchk_param(struct xt_tgchk_param
*par
,
140 const struct nft_ctx
*ctx
,
141 struct xt_target
*target
, void *info
,
142 union nft_entry
*entry
, u16 proto
, bool inv
)
145 par
->table
= ctx
->table
->name
;
146 switch (ctx
->afi
->family
) {
148 entry
->e4
.ip
.proto
= proto
;
149 entry
->e4
.ip
.invflags
= inv
? IPT_INV_PROTO
: 0;
153 entry
->e6
.ipv6
.flags
|= IP6T_F_PROTO
;
155 entry
->e6
.ipv6
.proto
= proto
;
156 entry
->e6
.ipv6
.invflags
= inv
? IP6T_INV_PROTO
: 0;
159 entry
->ebt
.ethproto
= (__force __be16
)proto
;
160 entry
->ebt
.invflags
= inv
? EBT_IPROTO
: 0;
165 par
->entryinfo
= entry
;
166 par
->target
= target
;
167 par
->targinfo
= info
;
168 if (ctx
->chain
->flags
& NFT_BASE_CHAIN
) {
169 const struct nft_base_chain
*basechain
=
170 nft_base_chain(ctx
->chain
);
171 const struct nf_hook_ops
*ops
= &basechain
->ops
[0];
173 par
->hook_mask
= 1 << ops
->hooknum
;
177 par
->family
= ctx
->afi
->family
;
178 par
->nft_compat
= true;
181 static void target_compat_from_user(struct xt_target
*t
, void *in
, void *out
)
185 memcpy(out
, in
, t
->targetsize
);
186 pad
= XT_ALIGN(t
->targetsize
) - t
->targetsize
;
188 memset(out
+ t
->targetsize
, 0, pad
);
191 static const struct nla_policy nft_rule_compat_policy
[NFTA_RULE_COMPAT_MAX
+ 1] = {
192 [NFTA_RULE_COMPAT_PROTO
] = { .type
= NLA_U32
},
193 [NFTA_RULE_COMPAT_FLAGS
] = { .type
= NLA_U32
},
196 static int nft_parse_compat(const struct nlattr
*attr
, u16
*proto
, bool *inv
)
198 struct nlattr
*tb
[NFTA_RULE_COMPAT_MAX
+1];
202 err
= nla_parse_nested(tb
, NFTA_RULE_COMPAT_MAX
, attr
,
203 nft_rule_compat_policy
);
207 if (!tb
[NFTA_RULE_COMPAT_PROTO
] || !tb
[NFTA_RULE_COMPAT_FLAGS
])
210 flags
= ntohl(nla_get_be32(tb
[NFTA_RULE_COMPAT_FLAGS
]));
211 if (flags
& ~NFT_RULE_COMPAT_F_MASK
)
213 if (flags
& NFT_RULE_COMPAT_F_INV
)
216 *proto
= ntohl(nla_get_be32(tb
[NFTA_RULE_COMPAT_PROTO
]));
221 nft_target_init(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
,
222 const struct nlattr
* const tb
[])
224 void *info
= nft_expr_priv(expr
);
225 struct xt_target
*target
= expr
->ops
->data
;
226 struct xt_tgchk_param par
;
227 size_t size
= XT_ALIGN(nla_len(tb
[NFTA_TARGET_INFO
]));
230 union nft_entry e
= {};
233 ret
= nft_compat_chain_validate_dependency(target
->table
, ctx
->chain
);
237 target_compat_from_user(target
, nla_data(tb
[NFTA_TARGET_INFO
]), info
);
239 if (ctx
->nla
[NFTA_RULE_COMPAT
]) {
240 ret
= nft_parse_compat(ctx
->nla
[NFTA_RULE_COMPAT
], &proto
, &inv
);
245 nft_target_set_tgchk_param(&par
, ctx
, target
, info
, &e
, proto
, inv
);
247 ret
= xt_check_target(&par
, size
, proto
, inv
);
251 /* The standard target cannot be used */
252 if (target
->target
== NULL
) {
259 module_put(target
->me
);
264 nft_target_destroy(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
)
266 struct xt_target
*target
= expr
->ops
->data
;
267 void *info
= nft_expr_priv(expr
);
268 struct xt_tgdtor_param par
;
273 par
.family
= ctx
->afi
->family
;
274 if (par
.target
->destroy
!= NULL
)
275 par
.target
->destroy(&par
);
277 nft_xt_put(container_of(expr
->ops
, struct nft_xt
, ops
));
278 module_put(target
->me
);
281 static int nft_target_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
)
283 const struct xt_target
*target
= expr
->ops
->data
;
284 void *info
= nft_expr_priv(expr
);
286 if (nla_put_string(skb
, NFTA_TARGET_NAME
, target
->name
) ||
287 nla_put_be32(skb
, NFTA_TARGET_REV
, htonl(target
->revision
)) ||
288 nla_put(skb
, NFTA_TARGET_INFO
, XT_ALIGN(target
->targetsize
), info
))
289 goto nla_put_failure
;
297 static int nft_target_validate(const struct nft_ctx
*ctx
,
298 const struct nft_expr
*expr
,
299 const struct nft_data
**data
)
301 struct xt_target
*target
= expr
->ops
->data
;
302 unsigned int hook_mask
= 0;
305 if (ctx
->chain
->flags
& NFT_BASE_CHAIN
) {
306 const struct nft_base_chain
*basechain
=
307 nft_base_chain(ctx
->chain
);
308 const struct nf_hook_ops
*ops
= &basechain
->ops
[0];
310 hook_mask
= 1 << ops
->hooknum
;
311 if (!(hook_mask
& target
->hooks
))
314 ret
= nft_compat_chain_validate_dependency(target
->table
,
322 static void nft_match_eval(const struct nft_expr
*expr
,
323 struct nft_regs
*regs
,
324 const struct nft_pktinfo
*pkt
)
326 void *info
= nft_expr_priv(expr
);
327 struct xt_match
*match
= expr
->ops
->data
;
328 struct sk_buff
*skb
= pkt
->skb
;
331 nft_compat_set_par((struct xt_action_param
*)&pkt
->xt
, match
, info
);
333 ret
= match
->match(skb
, (struct xt_action_param
*)&pkt
->xt
);
335 if (pkt
->xt
.hotdrop
) {
336 regs
->verdict
.code
= NF_DROP
;
340 switch (ret
? 1 : 0) {
342 regs
->verdict
.code
= NFT_CONTINUE
;
345 regs
->verdict
.code
= NFT_BREAK
;
350 static const struct nla_policy nft_match_policy
[NFTA_MATCH_MAX
+ 1] = {
351 [NFTA_MATCH_NAME
] = { .type
= NLA_NUL_STRING
},
352 [NFTA_MATCH_REV
] = { .type
= NLA_U32
},
353 [NFTA_MATCH_INFO
] = { .type
= NLA_BINARY
},
356 /* struct xt_mtchk_param and xt_tgchk_param look very similar */
358 nft_match_set_mtchk_param(struct xt_mtchk_param
*par
, const struct nft_ctx
*ctx
,
359 struct xt_match
*match
, void *info
,
360 union nft_entry
*entry
, u16 proto
, bool inv
)
363 par
->table
= ctx
->table
->name
;
364 switch (ctx
->afi
->family
) {
366 entry
->e4
.ip
.proto
= proto
;
367 entry
->e4
.ip
.invflags
= inv
? IPT_INV_PROTO
: 0;
371 entry
->e6
.ipv6
.flags
|= IP6T_F_PROTO
;
373 entry
->e6
.ipv6
.proto
= proto
;
374 entry
->e6
.ipv6
.invflags
= inv
? IP6T_INV_PROTO
: 0;
377 entry
->ebt
.ethproto
= (__force __be16
)proto
;
378 entry
->ebt
.invflags
= inv
? EBT_IPROTO
: 0;
383 par
->entryinfo
= entry
;
385 par
->matchinfo
= info
;
386 if (ctx
->chain
->flags
& NFT_BASE_CHAIN
) {
387 const struct nft_base_chain
*basechain
=
388 nft_base_chain(ctx
->chain
);
389 const struct nf_hook_ops
*ops
= &basechain
->ops
[0];
391 par
->hook_mask
= 1 << ops
->hooknum
;
395 par
->family
= ctx
->afi
->family
;
396 par
->nft_compat
= true;
399 static void match_compat_from_user(struct xt_match
*m
, void *in
, void *out
)
403 memcpy(out
, in
, m
->matchsize
);
404 pad
= XT_ALIGN(m
->matchsize
) - m
->matchsize
;
406 memset(out
+ m
->matchsize
, 0, pad
);
410 nft_match_init(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
,
411 const struct nlattr
* const tb
[])
413 void *info
= nft_expr_priv(expr
);
414 struct xt_match
*match
= expr
->ops
->data
;
415 struct xt_mtchk_param par
;
416 size_t size
= XT_ALIGN(nla_len(tb
[NFTA_MATCH_INFO
]));
419 union nft_entry e
= {};
422 ret
= nft_compat_chain_validate_dependency(match
->table
, ctx
->chain
);
426 match_compat_from_user(match
, nla_data(tb
[NFTA_MATCH_INFO
]), info
);
428 if (ctx
->nla
[NFTA_RULE_COMPAT
]) {
429 ret
= nft_parse_compat(ctx
->nla
[NFTA_RULE_COMPAT
], &proto
, &inv
);
434 nft_match_set_mtchk_param(&par
, ctx
, match
, info
, &e
, proto
, inv
);
436 ret
= xt_check_match(&par
, size
, proto
, inv
);
442 module_put(match
->me
);
447 nft_match_destroy(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
)
449 struct xt_match
*match
= expr
->ops
->data
;
450 void *info
= nft_expr_priv(expr
);
451 struct xt_mtdtor_param par
;
455 par
.matchinfo
= info
;
456 par
.family
= ctx
->afi
->family
;
457 if (par
.match
->destroy
!= NULL
)
458 par
.match
->destroy(&par
);
460 nft_xt_put(container_of(expr
->ops
, struct nft_xt
, ops
));
461 module_put(match
->me
);
464 static int nft_match_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
)
466 void *info
= nft_expr_priv(expr
);
467 struct xt_match
*match
= expr
->ops
->data
;
469 if (nla_put_string(skb
, NFTA_MATCH_NAME
, match
->name
) ||
470 nla_put_be32(skb
, NFTA_MATCH_REV
, htonl(match
->revision
)) ||
471 nla_put(skb
, NFTA_MATCH_INFO
, XT_ALIGN(match
->matchsize
), info
))
472 goto nla_put_failure
;
480 static int nft_match_validate(const struct nft_ctx
*ctx
,
481 const struct nft_expr
*expr
,
482 const struct nft_data
**data
)
484 struct xt_match
*match
= expr
->ops
->data
;
485 unsigned int hook_mask
= 0;
488 if (ctx
->chain
->flags
& NFT_BASE_CHAIN
) {
489 const struct nft_base_chain
*basechain
=
490 nft_base_chain(ctx
->chain
);
491 const struct nf_hook_ops
*ops
= &basechain
->ops
[0];
493 hook_mask
= 1 << ops
->hooknum
;
494 if (!(hook_mask
& match
->hooks
))
497 ret
= nft_compat_chain_validate_dependency(match
->table
,
506 nfnl_compat_fill_info(struct sk_buff
*skb
, u32 portid
, u32 seq
, u32 type
,
507 int event
, u16 family
, const char *name
,
510 struct nlmsghdr
*nlh
;
511 struct nfgenmsg
*nfmsg
;
512 unsigned int flags
= portid
? NLM_F_MULTI
: 0;
514 event
|= NFNL_SUBSYS_NFT_COMPAT
<< 8;
515 nlh
= nlmsg_put(skb
, portid
, seq
, event
, sizeof(*nfmsg
), flags
);
519 nfmsg
= nlmsg_data(nlh
);
520 nfmsg
->nfgen_family
= family
;
521 nfmsg
->version
= NFNETLINK_V0
;
524 if (nla_put_string(skb
, NFTA_COMPAT_NAME
, name
) ||
525 nla_put_be32(skb
, NFTA_COMPAT_REV
, htonl(rev
)) ||
526 nla_put_be32(skb
, NFTA_COMPAT_TYPE
, htonl(target
)))
527 goto nla_put_failure
;
534 nlmsg_cancel(skb
, nlh
);
538 static int nfnl_compat_get(struct net
*net
, struct sock
*nfnl
,
539 struct sk_buff
*skb
, const struct nlmsghdr
*nlh
,
540 const struct nlattr
* const tb
[])
543 struct nfgenmsg
*nfmsg
;
547 struct sk_buff
*skb2
;
549 if (tb
[NFTA_COMPAT_NAME
] == NULL
||
550 tb
[NFTA_COMPAT_REV
] == NULL
||
551 tb
[NFTA_COMPAT_TYPE
] == NULL
)
554 name
= nla_data(tb
[NFTA_COMPAT_NAME
]);
555 rev
= ntohl(nla_get_be32(tb
[NFTA_COMPAT_REV
]));
556 target
= ntohl(nla_get_be32(tb
[NFTA_COMPAT_TYPE
]));
558 nfmsg
= nlmsg_data(nlh
);
560 switch(nfmsg
->nfgen_family
) {
574 pr_err("nft_compat: unsupported protocol %d\n",
575 nfmsg
->nfgen_family
);
579 try_then_request_module(xt_find_revision(nfmsg
->nfgen_family
, name
,
586 skb2
= nlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
590 /* include the best revision for this extension in the message */
591 if (nfnl_compat_fill_info(skb2
, NETLINK_CB(skb
).portid
,
593 NFNL_MSG_TYPE(nlh
->nlmsg_type
),
596 name
, ret
, target
) <= 0) {
601 ret
= netlink_unicast(nfnl
, skb2
, NETLINK_CB(skb
).portid
,
606 return ret
== -EAGAIN
? -ENOBUFS
: ret
;
609 static const struct nla_policy nfnl_compat_policy_get
[NFTA_COMPAT_MAX
+1] = {
610 [NFTA_COMPAT_NAME
] = { .type
= NLA_NUL_STRING
,
611 .len
= NFT_COMPAT_NAME_MAX
-1 },
612 [NFTA_COMPAT_REV
] = { .type
= NLA_U32
},
613 [NFTA_COMPAT_TYPE
] = { .type
= NLA_U32
},
616 static const struct nfnl_callback nfnl_nft_compat_cb
[NFNL_MSG_COMPAT_MAX
] = {
617 [NFNL_MSG_COMPAT_GET
] = { .call
= nfnl_compat_get
,
618 .attr_count
= NFTA_COMPAT_MAX
,
619 .policy
= nfnl_compat_policy_get
},
622 static const struct nfnetlink_subsystem nfnl_compat_subsys
= {
623 .name
= "nft-compat",
624 .subsys_id
= NFNL_SUBSYS_NFT_COMPAT
,
625 .cb_count
= NFNL_MSG_COMPAT_MAX
,
626 .cb
= nfnl_nft_compat_cb
,
629 static LIST_HEAD(nft_match_list
);
631 static struct nft_expr_type nft_match_type
;
633 static bool nft_match_cmp(const struct xt_match
*match
,
634 const char *name
, u32 rev
, u32 family
)
636 return strcmp(match
->name
, name
) == 0 && match
->revision
== rev
&&
637 (match
->family
== NFPROTO_UNSPEC
|| match
->family
== family
);
640 static const struct nft_expr_ops
*
641 nft_match_select_ops(const struct nft_ctx
*ctx
,
642 const struct nlattr
* const tb
[])
644 struct nft_xt
*nft_match
;
645 struct xt_match
*match
;
650 if (tb
[NFTA_MATCH_NAME
] == NULL
||
651 tb
[NFTA_MATCH_REV
] == NULL
||
652 tb
[NFTA_MATCH_INFO
] == NULL
)
653 return ERR_PTR(-EINVAL
);
655 mt_name
= nla_data(tb
[NFTA_MATCH_NAME
]);
656 rev
= ntohl(nla_get_be32(tb
[NFTA_MATCH_REV
]));
657 family
= ctx
->afi
->family
;
659 /* Re-use the existing match if it's already loaded. */
660 list_for_each_entry(nft_match
, &nft_match_list
, head
) {
661 struct xt_match
*match
= nft_match
->ops
.data
;
663 if (nft_match_cmp(match
, mt_name
, rev
, family
)) {
664 if (!try_module_get(match
->me
))
665 return ERR_PTR(-ENOENT
);
668 return &nft_match
->ops
;
672 match
= xt_request_find_match(family
, mt_name
, rev
);
674 return ERR_PTR(-ENOENT
);
676 if (match
->matchsize
> nla_len(tb
[NFTA_MATCH_INFO
])) {
681 /* This is the first time we use this match, allocate operations */
682 nft_match
= kzalloc(sizeof(struct nft_xt
), GFP_KERNEL
);
683 if (nft_match
== NULL
) {
688 nft_match
->refcnt
= 1;
689 nft_match
->ops
.type
= &nft_match_type
;
690 nft_match
->ops
.size
= NFT_EXPR_SIZE(XT_ALIGN(match
->matchsize
));
691 nft_match
->ops
.eval
= nft_match_eval
;
692 nft_match
->ops
.init
= nft_match_init
;
693 nft_match
->ops
.destroy
= nft_match_destroy
;
694 nft_match
->ops
.dump
= nft_match_dump
;
695 nft_match
->ops
.validate
= nft_match_validate
;
696 nft_match
->ops
.data
= match
;
698 list_add(&nft_match
->head
, &nft_match_list
);
700 return &nft_match
->ops
;
702 module_put(match
->me
);
706 static struct nft_expr_type nft_match_type __read_mostly
= {
708 .select_ops
= nft_match_select_ops
,
709 .policy
= nft_match_policy
,
710 .maxattr
= NFTA_MATCH_MAX
,
711 .owner
= THIS_MODULE
,
714 static LIST_HEAD(nft_target_list
);
716 static struct nft_expr_type nft_target_type
;
718 static bool nft_target_cmp(const struct xt_target
*tg
,
719 const char *name
, u32 rev
, u32 family
)
721 return strcmp(tg
->name
, name
) == 0 && tg
->revision
== rev
&&
722 (tg
->family
== NFPROTO_UNSPEC
|| tg
->family
== family
);
725 static const struct nft_expr_ops
*
726 nft_target_select_ops(const struct nft_ctx
*ctx
,
727 const struct nlattr
* const tb
[])
729 struct nft_xt
*nft_target
;
730 struct xt_target
*target
;
735 if (tb
[NFTA_TARGET_NAME
] == NULL
||
736 tb
[NFTA_TARGET_REV
] == NULL
||
737 tb
[NFTA_TARGET_INFO
] == NULL
)
738 return ERR_PTR(-EINVAL
);
740 tg_name
= nla_data(tb
[NFTA_TARGET_NAME
]);
741 rev
= ntohl(nla_get_be32(tb
[NFTA_TARGET_REV
]));
742 family
= ctx
->afi
->family
;
744 /* Re-use the existing target if it's already loaded. */
745 list_for_each_entry(nft_target
, &nft_target_list
, head
) {
746 struct xt_target
*target
= nft_target
->ops
.data
;
748 if (nft_target_cmp(target
, tg_name
, rev
, family
)) {
749 if (!try_module_get(target
->me
))
750 return ERR_PTR(-ENOENT
);
752 nft_target
->refcnt
++;
753 return &nft_target
->ops
;
757 target
= xt_request_find_target(family
, tg_name
, rev
);
759 return ERR_PTR(-ENOENT
);
761 if (target
->targetsize
> nla_len(tb
[NFTA_TARGET_INFO
])) {
766 /* This is the first time we use this target, allocate operations */
767 nft_target
= kzalloc(sizeof(struct nft_xt
), GFP_KERNEL
);
768 if (nft_target
== NULL
) {
773 nft_target
->refcnt
= 1;
774 nft_target
->ops
.type
= &nft_target_type
;
775 nft_target
->ops
.size
= NFT_EXPR_SIZE(XT_ALIGN(target
->targetsize
));
776 nft_target
->ops
.init
= nft_target_init
;
777 nft_target
->ops
.destroy
= nft_target_destroy
;
778 nft_target
->ops
.dump
= nft_target_dump
;
779 nft_target
->ops
.validate
= nft_target_validate
;
780 nft_target
->ops
.data
= target
;
782 if (family
== NFPROTO_BRIDGE
)
783 nft_target
->ops
.eval
= nft_target_eval_bridge
;
785 nft_target
->ops
.eval
= nft_target_eval_xt
;
787 list_add(&nft_target
->head
, &nft_target_list
);
789 return &nft_target
->ops
;
791 module_put(target
->me
);
795 static struct nft_expr_type nft_target_type __read_mostly
= {
797 .select_ops
= nft_target_select_ops
,
798 .policy
= nft_target_policy
,
799 .maxattr
= NFTA_TARGET_MAX
,
800 .owner
= THIS_MODULE
,
803 static int __init
nft_compat_module_init(void)
807 ret
= nft_register_expr(&nft_match_type
);
811 ret
= nft_register_expr(&nft_target_type
);
815 ret
= nfnetlink_subsys_register(&nfnl_compat_subsys
);
817 pr_err("nft_compat: cannot register with nfnetlink.\n");
821 pr_info("nf_tables_compat: (c) 2012 Pablo Neira Ayuso <pablo@netfilter.org>\n");
826 nft_unregister_expr(&nft_target_type
);
828 nft_unregister_expr(&nft_match_type
);
832 static void __exit
nft_compat_module_exit(void)
834 nfnetlink_subsys_unregister(&nfnl_compat_subsys
);
835 nft_unregister_expr(&nft_target_type
);
836 nft_unregister_expr(&nft_match_type
);
839 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_NFT_COMPAT
);
841 module_init(nft_compat_module_init
);
842 module_exit(nft_compat_module_exit
);
844 MODULE_LICENSE("GPL");
845 MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
846 MODULE_ALIAS_NFT_EXPR("match");
847 MODULE_ALIAS_NFT_EXPR("target");