linux/net/netfilter/nft_compat.c
<<
>>
Prefs
   1/*
   2 * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
   3 *
   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.
   7 *
   8 * This software has been sponsored by Sophos Astaro <http://www.sophos.com>
   9 */
  10
  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 <net/netfilter/nf_tables.h>
  23
  24static int nft_compat_chain_validate_dependency(const char *tablename,
  25                                                const struct nft_chain *chain)
  26{
  27        const struct nft_base_chain *basechain;
  28
  29        if (!tablename || !(chain->flags & NFT_BASE_CHAIN))
  30                return 0;
  31
  32        basechain = nft_base_chain(chain);
  33        if (strcmp(tablename, "nat") == 0 &&
  34            basechain->type->type != NFT_CHAIN_T_NAT)
  35                return -EINVAL;
  36
  37        return 0;
  38}
  39
  40union nft_entry {
  41        struct ipt_entry e4;
  42        struct ip6t_entry e6;
  43};
  44
  45static inline void
  46nft_compat_set_par(struct xt_action_param *par, void *xt, const void *xt_info)
  47{
  48        par->target     = xt;
  49        par->targinfo   = xt_info;
  50        par->hotdrop    = false;
  51}
  52
  53static void nft_target_eval(const struct nft_expr *expr,
  54                            struct nft_data data[NFT_REG_MAX + 1],
  55                            const struct nft_pktinfo *pkt)
  56{
  57        void *info = nft_expr_priv(expr);
  58        struct xt_target *target = expr->ops->data;
  59        struct sk_buff *skb = pkt->skb;
  60        int ret;
  61
  62        nft_compat_set_par((struct xt_action_param *)&pkt->xt, target, info);
  63
  64        ret = target->target(skb, &pkt->xt);
  65
  66        if (pkt->xt.hotdrop)
  67                ret = NF_DROP;
  68
  69        switch(ret) {
  70        case XT_CONTINUE:
  71                data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
  72                break;
  73        default:
  74                data[NFT_REG_VERDICT].verdict = ret;
  75                break;
  76        }
  77        return;
  78}
  79
  80static const struct nla_policy nft_target_policy[NFTA_TARGET_MAX + 1] = {
  81        [NFTA_TARGET_NAME]      = { .type = NLA_NUL_STRING },
  82        [NFTA_TARGET_REV]       = { .type = NLA_U32 },
  83        [NFTA_TARGET_INFO]      = { .type = NLA_BINARY },
  84};
  85
  86static void
  87nft_target_set_tgchk_param(struct xt_tgchk_param *par,
  88                           const struct nft_ctx *ctx,
  89                           struct xt_target *target, void *info,
  90                           union nft_entry *entry, u8 proto, bool inv)
  91{
  92        par->net        = ctx->net;
  93        par->table      = ctx->table->name;
  94        switch (ctx->afi->family) {
  95        case AF_INET:
  96                entry->e4.ip.proto = proto;
  97                entry->e4.ip.invflags = inv ? IPT_INV_PROTO : 0;
  98                break;
  99        case AF_INET6:
 100                entry->e6.ipv6.proto = proto;
 101                entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0;
 102                break;
 103        }
 104        par->entryinfo  = entry;
 105        par->target     = target;
 106        par->targinfo   = info;
 107        if (ctx->chain->flags & NFT_BASE_CHAIN) {
 108                const struct nft_base_chain *basechain =
 109                                                nft_base_chain(ctx->chain);
 110                const struct nf_hook_ops *ops = &basechain->ops[0];
 111
 112                par->hook_mask = 1 << ops->hooknum;
 113        } else {
 114                par->hook_mask = 0;
 115        }
 116        par->family     = ctx->afi->family;
 117}
 118
 119static void target_compat_from_user(struct xt_target *t, void *in, void *out)
 120{
 121        int pad;
 122
 123        memcpy(out, in, t->targetsize);
 124        pad = XT_ALIGN(t->targetsize) - t->targetsize;
 125        if (pad > 0)
 126                memset(out + t->targetsize, 0, pad);
 127}
 128
 129static const struct nla_policy nft_rule_compat_policy[NFTA_RULE_COMPAT_MAX + 1] = {
 130        [NFTA_RULE_COMPAT_PROTO]        = { .type = NLA_U32 },
 131        [NFTA_RULE_COMPAT_FLAGS]        = { .type = NLA_U32 },
 132};
 133
 134static int nft_parse_compat(const struct nlattr *attr, u8 *proto, bool *inv)
 135{
 136        struct nlattr *tb[NFTA_RULE_COMPAT_MAX+1];
 137        u32 flags;
 138        int err;
 139
 140        err = nla_parse_nested(tb, NFTA_RULE_COMPAT_MAX, attr,
 141                               nft_rule_compat_policy);
 142        if (err < 0)
 143                return err;
 144
 145        if (!tb[NFTA_RULE_COMPAT_PROTO] || !tb[NFTA_RULE_COMPAT_FLAGS])
 146                return -EINVAL;
 147
 148        flags = ntohl(nla_get_be32(tb[NFTA_RULE_COMPAT_FLAGS]));
 149        if (flags & ~NFT_RULE_COMPAT_F_MASK)
 150                return -EINVAL;
 151        if (flags & NFT_RULE_COMPAT_F_INV)
 152                *inv = true;
 153
 154        *proto = ntohl(nla_get_be32(tb[NFTA_RULE_COMPAT_PROTO]));
 155        return 0;
 156}
 157
 158static int
 159nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
 160                const struct nlattr * const tb[])
 161{
 162        void *info = nft_expr_priv(expr);
 163        struct xt_target *target = expr->ops->data;
 164        struct xt_tgchk_param par;
 165        size_t size = XT_ALIGN(nla_len(tb[NFTA_TARGET_INFO]));
 166        u8 proto = 0;
 167        bool inv = false;
 168        union nft_entry e = {};
 169        int ret;
 170
 171        ret = nft_compat_chain_validate_dependency(target->table, ctx->chain);
 172        if (ret < 0)
 173                goto err;
 174
 175        target_compat_from_user(target, nla_data(tb[NFTA_TARGET_INFO]), info);
 176
 177        if (ctx->nla[NFTA_RULE_COMPAT]) {
 178                ret = nft_parse_compat(ctx->nla[NFTA_RULE_COMPAT], &proto, &inv);
 179                if (ret < 0)
 180                        goto err;
 181        }
 182
 183        nft_target_set_tgchk_param(&par, ctx, target, info, &e, proto, inv);
 184
 185        ret = xt_check_target(&par, size, proto, inv);
 186        if (ret < 0)
 187                goto err;
 188
 189        /* The standard target cannot be used */
 190        if (target->target == NULL) {
 191                ret = -EINVAL;
 192                goto err;
 193        }
 194
 195        return 0;
 196err:
 197        module_put(target->me);
 198        return ret;
 199}
 200
 201static void
 202nft_target_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
 203{
 204        struct xt_target *target = expr->ops->data;
 205        void *info = nft_expr_priv(expr);
 206        struct xt_tgdtor_param par;
 207
 208        par.net = ctx->net;
 209        par.target = target;
 210        par.targinfo = info;
 211        par.family = ctx->afi->family;
 212        if (par.target->destroy != NULL)
 213                par.target->destroy(&par);
 214
 215        module_put(target->me);
 216}
 217
 218static int nft_target_dump(struct sk_buff *skb, const struct nft_expr *expr)
 219{
 220        const struct xt_target *target = expr->ops->data;
 221        void *info = nft_expr_priv(expr);
 222
 223        if (nla_put_string(skb, NFTA_TARGET_NAME, target->name) ||
 224            nla_put_be32(skb, NFTA_TARGET_REV, htonl(target->revision)) ||
 225            nla_put(skb, NFTA_TARGET_INFO, XT_ALIGN(target->targetsize), info))
 226                goto nla_put_failure;
 227
 228        return 0;
 229
 230nla_put_failure:
 231        return -1;
 232}
 233
 234static int nft_target_validate(const struct nft_ctx *ctx,
 235                               const struct nft_expr *expr,
 236                               const struct nft_data **data)
 237{
 238        struct xt_target *target = expr->ops->data;
 239        unsigned int hook_mask = 0;
 240        int ret;
 241
 242        if (ctx->chain->flags & NFT_BASE_CHAIN) {
 243                const struct nft_base_chain *basechain =
 244                                                nft_base_chain(ctx->chain);
 245                const struct nf_hook_ops *ops = &basechain->ops[0];
 246
 247                hook_mask = 1 << ops->hooknum;
 248                if (!(hook_mask & target->hooks))
 249                        return -EINVAL;
 250
 251                ret = nft_compat_chain_validate_dependency(target->table,
 252                                                           ctx->chain);
 253                if (ret < 0)
 254                        return ret;
 255        }
 256        return 0;
 257}
 258
 259static void nft_match_eval(const struct nft_expr *expr,
 260                           struct nft_data data[NFT_REG_MAX + 1],
 261                           const struct nft_pktinfo *pkt)
 262{
 263        void *info = nft_expr_priv(expr);
 264        struct xt_match *match = expr->ops->data;
 265        struct sk_buff *skb = pkt->skb;
 266        bool ret;
 267
 268        nft_compat_set_par((struct xt_action_param *)&pkt->xt, match, info);
 269
 270        ret = match->match(skb, (struct xt_action_param *)&pkt->xt);
 271
 272        if (pkt->xt.hotdrop) {
 273                data[NFT_REG_VERDICT].verdict = NF_DROP;
 274                return;
 275        }
 276
 277        switch(ret) {
 278        case true:
 279                data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
 280                break;
 281        case false:
 282                data[NFT_REG_VERDICT].verdict = NFT_BREAK;
 283                break;
 284        }
 285}
 286
 287static const struct nla_policy nft_match_policy[NFTA_MATCH_MAX + 1] = {
 288        [NFTA_MATCH_NAME]       = { .type = NLA_NUL_STRING },
 289        [NFTA_MATCH_REV]        = { .type = NLA_U32 },
 290        [NFTA_MATCH_INFO]       = { .type = NLA_BINARY },
 291};
 292
 293/* struct xt_mtchk_param and xt_tgchk_param look very similar */
 294static void
 295nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx,
 296                          struct xt_match *match, void *info,
 297                          union nft_entry *entry, u8 proto, bool inv)
 298{
 299        par->net        = ctx->net;
 300        par->table      = ctx->table->name;
 301        switch (ctx->afi->family) {
 302        case AF_INET:
 303                entry->e4.ip.proto = proto;
 304                entry->e4.ip.invflags = inv ? IPT_INV_PROTO : 0;
 305                break;
 306        case AF_INET6:
 307                entry->e6.ipv6.proto = proto;
 308                entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0;
 309                break;
 310        }
 311        par->entryinfo  = entry;
 312        par->match      = match;
 313        par->matchinfo  = info;
 314        if (ctx->chain->flags & NFT_BASE_CHAIN) {
 315                const struct nft_base_chain *basechain =
 316                                                nft_base_chain(ctx->chain);
 317                const struct nf_hook_ops *ops = &basechain->ops[0];
 318
 319                par->hook_mask = 1 << ops->hooknum;
 320        } else {
 321                par->hook_mask = 0;
 322        }
 323        par->family     = ctx->afi->family;
 324}
 325
 326static void match_compat_from_user(struct xt_match *m, void *in, void *out)
 327{
 328        int pad;
 329
 330        memcpy(out, in, m->matchsize);
 331        pad = XT_ALIGN(m->matchsize) - m->matchsize;
 332        if (pad > 0)
 333                memset(out + m->matchsize, 0, pad);
 334}
 335
 336static int
 337nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
 338                const struct nlattr * const tb[])
 339{
 340        void *info = nft_expr_priv(expr);
 341        struct xt_match *match = expr->ops->data;
 342        struct xt_mtchk_param par;
 343        size_t size = XT_ALIGN(nla_len(tb[NFTA_MATCH_INFO]));
 344        u8 proto = 0;
 345        bool inv = false;
 346        union nft_entry e = {};
 347        int ret;
 348
 349        ret = nft_compat_chain_validate_dependency(match->table, ctx->chain);
 350        if (ret < 0)
 351                goto err;
 352
 353        match_compat_from_user(match, nla_data(tb[NFTA_MATCH_INFO]), info);
 354
 355        if (ctx->nla[NFTA_RULE_COMPAT]) {
 356                ret = nft_parse_compat(ctx->nla[NFTA_RULE_COMPAT], &proto, &inv);
 357                if (ret < 0)
 358                        goto err;
 359        }
 360
 361        nft_match_set_mtchk_param(&par, ctx, match, info, &e, proto, inv);
 362
 363        ret = xt_check_match(&par, size, proto, inv);
 364        if (ret < 0)
 365                goto err;
 366
 367        return 0;
 368err:
 369        module_put(match->me);
 370        return ret;
 371}
 372
 373static void
 374nft_match_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
 375{
 376        struct xt_match *match = expr->ops->data;
 377        void *info = nft_expr_priv(expr);
 378        struct xt_mtdtor_param par;
 379
 380        par.net = ctx->net;
 381        par.match = match;
 382        par.matchinfo = info;
 383        par.family = ctx->afi->family;
 384        if (par.match->destroy != NULL)
 385                par.match->destroy(&par);
 386
 387        module_put(match->me);
 388}
 389
 390static int nft_match_dump(struct sk_buff *skb, const struct nft_expr *expr)
 391{
 392        void *info = nft_expr_priv(expr);
 393        struct xt_match *match = expr->ops->data;
 394
 395        if (nla_put_string(skb, NFTA_MATCH_NAME, match->name) ||
 396            nla_put_be32(skb, NFTA_MATCH_REV, htonl(match->revision)) ||
 397            nla_put(skb, NFTA_MATCH_INFO, XT_ALIGN(match->matchsize), info))
 398                goto nla_put_failure;
 399
 400        return 0;
 401
 402nla_put_failure:
 403        return -1;
 404}
 405
 406static int nft_match_validate(const struct nft_ctx *ctx,
 407                              const struct nft_expr *expr,
 408                              const struct nft_data **data)
 409{
 410        struct xt_match *match = expr->ops->data;
 411        unsigned int hook_mask = 0;
 412        int ret;
 413
 414        if (ctx->chain->flags & NFT_BASE_CHAIN) {
 415                const struct nft_base_chain *basechain =
 416                                                nft_base_chain(ctx->chain);
 417                const struct nf_hook_ops *ops = &basechain->ops[0];
 418
 419                hook_mask = 1 << ops->hooknum;
 420                if (!(hook_mask & match->hooks))
 421                        return -EINVAL;
 422
 423                ret = nft_compat_chain_validate_dependency(match->table,
 424                                                           ctx->chain);
 425                if (ret < 0)
 426                        return ret;
 427        }
 428        return 0;
 429}
 430
 431static int
 432nfnl_compat_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
 433                      int event, u16 family, const char *name,
 434                      int rev, int target)
 435{
 436        struct nlmsghdr *nlh;
 437        struct nfgenmsg *nfmsg;
 438        unsigned int flags = portid ? NLM_F_MULTI : 0;
 439
 440        event |= NFNL_SUBSYS_NFT_COMPAT << 8;
 441        nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
 442        if (nlh == NULL)
 443                goto nlmsg_failure;
 444
 445        nfmsg = nlmsg_data(nlh);
 446        nfmsg->nfgen_family = family;
 447        nfmsg->version = NFNETLINK_V0;
 448        nfmsg->res_id = 0;
 449
 450        if (nla_put_string(skb, NFTA_COMPAT_NAME, name) ||
 451            nla_put_be32(skb, NFTA_COMPAT_REV, htonl(rev)) ||
 452            nla_put_be32(skb, NFTA_COMPAT_TYPE, htonl(target)))
 453                goto nla_put_failure;
 454
 455        nlmsg_end(skb, nlh);
 456        return skb->len;
 457
 458nlmsg_failure:
 459nla_put_failure:
 460        nlmsg_cancel(skb, nlh);
 461        return -1;
 462}
 463
 464static int
 465nfnl_compat_get(struct sock *nfnl, struct sk_buff *skb,
 466                const struct nlmsghdr *nlh, const struct nlattr * const tb[])
 467{
 468        int ret = 0, target;
 469        struct nfgenmsg *nfmsg;
 470        const char *fmt;
 471        const char *name;
 472        u32 rev;
 473        struct sk_buff *skb2;
 474
 475        if (tb[NFTA_COMPAT_NAME] == NULL ||
 476            tb[NFTA_COMPAT_REV] == NULL ||
 477            tb[NFTA_COMPAT_TYPE] == NULL)
 478                return -EINVAL;
 479
 480        name = nla_data(tb[NFTA_COMPAT_NAME]);
 481        rev = ntohl(nla_get_be32(tb[NFTA_COMPAT_REV]));
 482        target = ntohl(nla_get_be32(tb[NFTA_COMPAT_TYPE]));
 483
 484        nfmsg = nlmsg_data(nlh);
 485
 486        switch(nfmsg->nfgen_family) {
 487        case AF_INET:
 488                fmt = "ipt_%s";
 489                break;
 490        case AF_INET6:
 491                fmt = "ip6t_%s";
 492                break;
 493        default:
 494                pr_err("nft_compat: unsupported protocol %d\n",
 495                        nfmsg->nfgen_family);
 496                return -EINVAL;
 497        }
 498
 499        try_then_request_module(xt_find_revision(nfmsg->nfgen_family, name,
 500                                                 rev, target, &ret),
 501                                                 fmt, name);
 502
 503        if (ret < 0)
 504                return ret;
 505
 506        skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 507        if (skb2 == NULL)
 508                return -ENOMEM;
 509
 510        /* include the best revision for this extension in the message */
 511        if (nfnl_compat_fill_info(skb2, NETLINK_CB(skb).portid,
 512                                  nlh->nlmsg_seq,
 513                                  NFNL_MSG_TYPE(nlh->nlmsg_type),
 514                                  NFNL_MSG_COMPAT_GET,
 515                                  nfmsg->nfgen_family,
 516                                  name, ret, target) <= 0) {
 517                kfree_skb(skb2);
 518                return -ENOSPC;
 519        }
 520
 521        ret = netlink_unicast(nfnl, skb2, NETLINK_CB(skb).portid,
 522                                MSG_DONTWAIT);
 523        if (ret > 0)
 524                ret = 0;
 525
 526        return ret == -EAGAIN ? -ENOBUFS : ret;
 527}
 528
 529static const struct nla_policy nfnl_compat_policy_get[NFTA_COMPAT_MAX+1] = {
 530        [NFTA_COMPAT_NAME]      = { .type = NLA_NUL_STRING,
 531                                    .len = NFT_COMPAT_NAME_MAX-1 },
 532        [NFTA_COMPAT_REV]       = { .type = NLA_U32 },
 533        [NFTA_COMPAT_TYPE]      = { .type = NLA_U32 },
 534};
 535
 536static const struct nfnl_callback nfnl_nft_compat_cb[NFNL_MSG_COMPAT_MAX] = {
 537        [NFNL_MSG_COMPAT_GET]           = { .call = nfnl_compat_get,
 538                                            .attr_count = NFTA_COMPAT_MAX,
 539                                            .policy = nfnl_compat_policy_get },
 540};
 541
 542static const struct nfnetlink_subsystem nfnl_compat_subsys = {
 543        .name           = "nft-compat",
 544        .subsys_id      = NFNL_SUBSYS_NFT_COMPAT,
 545        .cb_count       = NFNL_MSG_COMPAT_MAX,
 546        .cb             = nfnl_nft_compat_cb,
 547};
 548
 549static LIST_HEAD(nft_match_list);
 550
 551struct nft_xt {
 552        struct list_head        head;
 553        struct nft_expr_ops     ops;
 554};
 555
 556static struct nft_expr_type nft_match_type;
 557
 558static const struct nft_expr_ops *
 559nft_match_select_ops(const struct nft_ctx *ctx,
 560                     const struct nlattr * const tb[])
 561{
 562        struct nft_xt *nft_match;
 563        struct xt_match *match;
 564        char *mt_name;
 565        __u32 rev, family;
 566
 567        if (tb[NFTA_MATCH_NAME] == NULL ||
 568            tb[NFTA_MATCH_REV] == NULL ||
 569            tb[NFTA_MATCH_INFO] == NULL)
 570                return ERR_PTR(-EINVAL);
 571
 572        mt_name = nla_data(tb[NFTA_MATCH_NAME]);
 573        rev = ntohl(nla_get_be32(tb[NFTA_MATCH_REV]));
 574        family = ctx->afi->family;
 575
 576        /* Re-use the existing match if it's already loaded. */
 577        list_for_each_entry(nft_match, &nft_match_list, head) {
 578                struct xt_match *match = nft_match->ops.data;
 579
 580                if (strcmp(match->name, mt_name) == 0 &&
 581                    match->revision == rev && match->family == family)
 582                        return &nft_match->ops;
 583        }
 584
 585        match = xt_request_find_match(family, mt_name, rev);
 586        if (IS_ERR(match))
 587                return ERR_PTR(-ENOENT);
 588
 589        /* This is the first time we use this match, allocate operations */
 590        nft_match = kzalloc(sizeof(struct nft_xt), GFP_KERNEL);
 591        if (nft_match == NULL)
 592                return ERR_PTR(-ENOMEM);
 593
 594        nft_match->ops.type = &nft_match_type;
 595        nft_match->ops.size = NFT_EXPR_SIZE(XT_ALIGN(match->matchsize));
 596        nft_match->ops.eval = nft_match_eval;
 597        nft_match->ops.init = nft_match_init;
 598        nft_match->ops.destroy = nft_match_destroy;
 599        nft_match->ops.dump = nft_match_dump;
 600        nft_match->ops.validate = nft_match_validate;
 601        nft_match->ops.data = match;
 602
 603        list_add(&nft_match->head, &nft_match_list);
 604
 605        return &nft_match->ops;
 606}
 607
 608static void nft_match_release(void)
 609{
 610        struct nft_xt *nft_match, *tmp;
 611
 612        list_for_each_entry_safe(nft_match, tmp, &nft_match_list, head)
 613                kfree(nft_match);
 614}
 615
 616static struct nft_expr_type nft_match_type __read_mostly = {
 617        .name           = "match",
 618        .select_ops     = nft_match_select_ops,
 619        .policy         = nft_match_policy,
 620        .maxattr        = NFTA_MATCH_MAX,
 621        .owner          = THIS_MODULE,
 622};
 623
 624static LIST_HEAD(nft_target_list);
 625
 626static struct nft_expr_type nft_target_type;
 627
 628static const struct nft_expr_ops *
 629nft_target_select_ops(const struct nft_ctx *ctx,
 630                      const struct nlattr * const tb[])
 631{
 632        struct nft_xt *nft_target;
 633        struct xt_target *target;
 634        char *tg_name;
 635        __u32 rev, family;
 636
 637        if (tb[NFTA_TARGET_NAME] == NULL ||
 638            tb[NFTA_TARGET_REV] == NULL ||
 639            tb[NFTA_TARGET_INFO] == NULL)
 640                return ERR_PTR(-EINVAL);
 641
 642        tg_name = nla_data(tb[NFTA_TARGET_NAME]);
 643        rev = ntohl(nla_get_be32(tb[NFTA_TARGET_REV]));
 644        family = ctx->afi->family;
 645
 646        /* Re-use the existing target if it's already loaded. */
 647        list_for_each_entry(nft_target, &nft_target_list, head) {
 648                struct xt_target *target = nft_target->ops.data;
 649
 650                if (strcmp(target->name, tg_name) == 0 &&
 651                    target->revision == rev && target->family == family)
 652                        return &nft_target->ops;
 653        }
 654
 655        target = xt_request_find_target(family, tg_name, rev);
 656        if (IS_ERR(target))
 657                return ERR_PTR(-ENOENT);
 658
 659        /* This is the first time we use this target, allocate operations */
 660        nft_target = kzalloc(sizeof(struct nft_xt), GFP_KERNEL);
 661        if (nft_target == NULL)
 662                return ERR_PTR(-ENOMEM);
 663
 664        nft_target->ops.type = &nft_target_type;
 665        nft_target->ops.size = NFT_EXPR_SIZE(XT_ALIGN(target->targetsize));
 666        nft_target->ops.eval = nft_target_eval;
 667        nft_target->ops.init = nft_target_init;
 668        nft_target->ops.destroy = nft_target_destroy;
 669        nft_target->ops.dump = nft_target_dump;
 670        nft_target->ops.validate = nft_target_validate;
 671        nft_target->ops.data = target;
 672
 673        list_add(&nft_target->head, &nft_target_list);
 674
 675        return &nft_target->ops;
 676}
 677
 678static void nft_target_release(void)
 679{
 680        struct nft_xt *nft_target, *tmp;
 681
 682        list_for_each_entry_safe(nft_target, tmp, &nft_target_list, head)
 683                kfree(nft_target);
 684}
 685
 686static struct nft_expr_type nft_target_type __read_mostly = {
 687        .name           = "target",
 688        .select_ops     = nft_target_select_ops,
 689        .policy         = nft_target_policy,
 690        .maxattr        = NFTA_TARGET_MAX,
 691        .owner          = THIS_MODULE,
 692};
 693
 694static int __init nft_compat_module_init(void)
 695{
 696        int ret;
 697
 698        ret = nft_register_expr(&nft_match_type);
 699        if (ret < 0)
 700                return ret;
 701
 702        ret = nft_register_expr(&nft_target_type);
 703        if (ret < 0)
 704                goto err_match;
 705
 706        ret = nfnetlink_subsys_register(&nfnl_compat_subsys);
 707        if (ret < 0) {
 708                pr_err("nft_compat: cannot register with nfnetlink.\n");
 709                goto err_target;
 710        }
 711
 712        pr_info("nf_tables_compat: (c) 2012 Pablo Neira Ayuso <pablo@netfilter.org>\n");
 713
 714        return ret;
 715
 716err_target:
 717        nft_unregister_expr(&nft_target_type);
 718err_match:
 719        nft_unregister_expr(&nft_match_type);
 720        return ret;
 721}
 722
 723static void __exit nft_compat_module_exit(void)
 724{
 725        nfnetlink_subsys_unregister(&nfnl_compat_subsys);
 726        nft_unregister_expr(&nft_target_type);
 727        nft_unregister_expr(&nft_match_type);
 728        nft_match_release();
 729        nft_target_release();
 730}
 731
 732MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_NFT_COMPAT);
 733
 734module_init(nft_compat_module_init);
 735module_exit(nft_compat_module_exit);
 736
 737MODULE_LICENSE("GPL");
 738MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
 739MODULE_ALIAS_NFT_EXPR("match");
 740MODULE_ALIAS_NFT_EXPR("target");
 741