Loading net/netfilter/nf_tables_api.c +106 −93 Original line number Diff line number Diff line Loading @@ -1335,6 +1335,106 @@ static void nft_chain_release_hook(struct nft_chain_hook *hook) dev_put(hook->dev); } static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask, u8 policy, bool create) { const struct nlattr * const *nla = ctx->nla; struct nft_table *table = ctx->table; struct nft_af_info *afi = ctx->afi; struct nft_base_chain *basechain; struct nft_stats __percpu *stats; struct net *net = ctx->net; struct nft_chain *chain; unsigned int i; int err; if (table->use == UINT_MAX) return -EOVERFLOW; if (nla[NFTA_CHAIN_HOOK]) { struct nft_chain_hook hook; struct nf_hook_ops *ops; nf_hookfn *hookfn; err = nft_chain_parse_hook(net, nla, afi, &hook, create); if (err < 0) return err; basechain = kzalloc(sizeof(*basechain), GFP_KERNEL); if (basechain == NULL) { nft_chain_release_hook(&hook); return -ENOMEM; } if (hook.dev != NULL) strncpy(basechain->dev_name, hook.dev->name, IFNAMSIZ); if (nla[NFTA_CHAIN_COUNTERS]) { stats = nft_stats_alloc(nla[NFTA_CHAIN_COUNTERS]); if (IS_ERR(stats)) { nft_chain_release_hook(&hook); kfree(basechain); return PTR_ERR(stats); } basechain->stats = stats; static_branch_inc(&nft_counters_enabled); } hookfn = hook.type->hooks[hook.num]; basechain->type = hook.type; chain = &basechain->chain; for (i = 0; i < afi->nops; i++) { ops = &basechain->ops[i]; ops->pf = family; ops->hooknum = hook.num; ops->priority = hook.priority; ops->priv = chain; ops->hook = afi->hooks[ops->hooknum]; ops->dev = hook.dev; if (hookfn) ops->hook = hookfn; if (afi->hook_ops_init) afi->hook_ops_init(ops, i); } chain->flags |= NFT_BASE_CHAIN; basechain->policy = policy; } else { chain = kzalloc(sizeof(*chain), GFP_KERNEL); if (chain == NULL) return -ENOMEM; } INIT_LIST_HEAD(&chain->rules); chain->handle = nf_tables_alloc_handle(table); chain->table = table; chain->name = nla_strdup(nla[NFTA_CHAIN_NAME], GFP_KERNEL); if (!chain->name) { err = -ENOMEM; goto err1; } err = nf_tables_register_hooks(net, table, chain, afi->nops); if (err < 0) goto err1; ctx->chain = chain; err = nft_trans_chain_add(ctx, NFT_MSG_NEWCHAIN); if (err < 0) goto err2; table->use++; list_add_tail_rcu(&chain->list, &table->chains); return 0; err2: nf_tables_unregister_hooks(net, table, chain, afi->nops); err1: nf_tables_chain_destroy(chain); return err; } static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy, bool create) { Loading Loading @@ -1433,19 +1533,15 @@ static int nf_tables_newchain(struct net *net, struct sock *nlsk, { const struct nfgenmsg *nfmsg = nlmsg_data(nlh); const struct nlattr * uninitialized_var(name); u8 genmask = nft_genmask_next(net); int family = nfmsg->nfgen_family; struct nft_af_info *afi; struct nft_table *table; struct nft_chain *chain; struct nft_base_chain *basechain = NULL; u8 genmask = nft_genmask_next(net); int family = nfmsg->nfgen_family; u8 policy = NF_ACCEPT; struct nft_ctx ctx; u64 handle = 0; unsigned int i; struct nft_stats __percpu *stats; int err; bool create; struct nft_ctx ctx; create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false; Loading Loading @@ -1493,101 +1589,18 @@ static int nf_tables_newchain(struct net *net, struct sock *nlsk, } } nft_ctx_init(&ctx, net, skb, nlh, afi, table, chain, nla); if (chain != NULL) { if (nlh->nlmsg_flags & NLM_F_EXCL) return -EEXIST; if (nlh->nlmsg_flags & NLM_F_REPLACE) return -EOPNOTSUPP; nft_ctx_init(&ctx, net, skb, nlh, afi, table, chain, nla); return nf_tables_updchain(&ctx, genmask, policy, create); } if (table->use == UINT_MAX) return -EOVERFLOW; if (nla[NFTA_CHAIN_HOOK]) { struct nft_chain_hook hook; struct nf_hook_ops *ops; nf_hookfn *hookfn; err = nft_chain_parse_hook(net, nla, afi, &hook, create); if (err < 0) return err; basechain = kzalloc(sizeof(*basechain), GFP_KERNEL); if (basechain == NULL) { nft_chain_release_hook(&hook); return -ENOMEM; } if (hook.dev != NULL) strncpy(basechain->dev_name, hook.dev->name, IFNAMSIZ); if (nla[NFTA_CHAIN_COUNTERS]) { stats = nft_stats_alloc(nla[NFTA_CHAIN_COUNTERS]); if (IS_ERR(stats)) { nft_chain_release_hook(&hook); kfree(basechain); return PTR_ERR(stats); } basechain->stats = stats; static_branch_inc(&nft_counters_enabled); } hookfn = hook.type->hooks[hook.num]; basechain->type = hook.type; chain = &basechain->chain; for (i = 0; i < afi->nops; i++) { ops = &basechain->ops[i]; ops->pf = family; ops->hooknum = hook.num; ops->priority = hook.priority; ops->priv = chain; ops->hook = afi->hooks[ops->hooknum]; ops->dev = hook.dev; if (hookfn) ops->hook = hookfn; if (afi->hook_ops_init) afi->hook_ops_init(ops, i); } chain->flags |= NFT_BASE_CHAIN; basechain->policy = policy; } else { chain = kzalloc(sizeof(*chain), GFP_KERNEL); if (chain == NULL) return -ENOMEM; } INIT_LIST_HEAD(&chain->rules); chain->handle = nf_tables_alloc_handle(table); chain->table = table; chain->name = nla_strdup(name, GFP_KERNEL); if (!chain->name) { err = -ENOMEM; goto err1; } err = nf_tables_register_hooks(net, table, chain, afi->nops); if (err < 0) goto err1; nft_ctx_init(&ctx, net, skb, nlh, afi, table, chain, nla); err = nft_trans_chain_add(&ctx, NFT_MSG_NEWCHAIN); if (err < 0) goto err2; table->use++; list_add_tail_rcu(&chain->list, &table->chains); return 0; err2: nf_tables_unregister_hooks(net, table, chain, afi->nops); err1: nf_tables_chain_destroy(chain); return err; return nf_tables_addchain(&ctx, family, genmask, policy, create); } static int nf_tables_delchain(struct net *net, struct sock *nlsk, Loading Loading
net/netfilter/nf_tables_api.c +106 −93 Original line number Diff line number Diff line Loading @@ -1335,6 +1335,106 @@ static void nft_chain_release_hook(struct nft_chain_hook *hook) dev_put(hook->dev); } static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask, u8 policy, bool create) { const struct nlattr * const *nla = ctx->nla; struct nft_table *table = ctx->table; struct nft_af_info *afi = ctx->afi; struct nft_base_chain *basechain; struct nft_stats __percpu *stats; struct net *net = ctx->net; struct nft_chain *chain; unsigned int i; int err; if (table->use == UINT_MAX) return -EOVERFLOW; if (nla[NFTA_CHAIN_HOOK]) { struct nft_chain_hook hook; struct nf_hook_ops *ops; nf_hookfn *hookfn; err = nft_chain_parse_hook(net, nla, afi, &hook, create); if (err < 0) return err; basechain = kzalloc(sizeof(*basechain), GFP_KERNEL); if (basechain == NULL) { nft_chain_release_hook(&hook); return -ENOMEM; } if (hook.dev != NULL) strncpy(basechain->dev_name, hook.dev->name, IFNAMSIZ); if (nla[NFTA_CHAIN_COUNTERS]) { stats = nft_stats_alloc(nla[NFTA_CHAIN_COUNTERS]); if (IS_ERR(stats)) { nft_chain_release_hook(&hook); kfree(basechain); return PTR_ERR(stats); } basechain->stats = stats; static_branch_inc(&nft_counters_enabled); } hookfn = hook.type->hooks[hook.num]; basechain->type = hook.type; chain = &basechain->chain; for (i = 0; i < afi->nops; i++) { ops = &basechain->ops[i]; ops->pf = family; ops->hooknum = hook.num; ops->priority = hook.priority; ops->priv = chain; ops->hook = afi->hooks[ops->hooknum]; ops->dev = hook.dev; if (hookfn) ops->hook = hookfn; if (afi->hook_ops_init) afi->hook_ops_init(ops, i); } chain->flags |= NFT_BASE_CHAIN; basechain->policy = policy; } else { chain = kzalloc(sizeof(*chain), GFP_KERNEL); if (chain == NULL) return -ENOMEM; } INIT_LIST_HEAD(&chain->rules); chain->handle = nf_tables_alloc_handle(table); chain->table = table; chain->name = nla_strdup(nla[NFTA_CHAIN_NAME], GFP_KERNEL); if (!chain->name) { err = -ENOMEM; goto err1; } err = nf_tables_register_hooks(net, table, chain, afi->nops); if (err < 0) goto err1; ctx->chain = chain; err = nft_trans_chain_add(ctx, NFT_MSG_NEWCHAIN); if (err < 0) goto err2; table->use++; list_add_tail_rcu(&chain->list, &table->chains); return 0; err2: nf_tables_unregister_hooks(net, table, chain, afi->nops); err1: nf_tables_chain_destroy(chain); return err; } static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy, bool create) { Loading Loading @@ -1433,19 +1533,15 @@ static int nf_tables_newchain(struct net *net, struct sock *nlsk, { const struct nfgenmsg *nfmsg = nlmsg_data(nlh); const struct nlattr * uninitialized_var(name); u8 genmask = nft_genmask_next(net); int family = nfmsg->nfgen_family; struct nft_af_info *afi; struct nft_table *table; struct nft_chain *chain; struct nft_base_chain *basechain = NULL; u8 genmask = nft_genmask_next(net); int family = nfmsg->nfgen_family; u8 policy = NF_ACCEPT; struct nft_ctx ctx; u64 handle = 0; unsigned int i; struct nft_stats __percpu *stats; int err; bool create; struct nft_ctx ctx; create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false; Loading Loading @@ -1493,101 +1589,18 @@ static int nf_tables_newchain(struct net *net, struct sock *nlsk, } } nft_ctx_init(&ctx, net, skb, nlh, afi, table, chain, nla); if (chain != NULL) { if (nlh->nlmsg_flags & NLM_F_EXCL) return -EEXIST; if (nlh->nlmsg_flags & NLM_F_REPLACE) return -EOPNOTSUPP; nft_ctx_init(&ctx, net, skb, nlh, afi, table, chain, nla); return nf_tables_updchain(&ctx, genmask, policy, create); } if (table->use == UINT_MAX) return -EOVERFLOW; if (nla[NFTA_CHAIN_HOOK]) { struct nft_chain_hook hook; struct nf_hook_ops *ops; nf_hookfn *hookfn; err = nft_chain_parse_hook(net, nla, afi, &hook, create); if (err < 0) return err; basechain = kzalloc(sizeof(*basechain), GFP_KERNEL); if (basechain == NULL) { nft_chain_release_hook(&hook); return -ENOMEM; } if (hook.dev != NULL) strncpy(basechain->dev_name, hook.dev->name, IFNAMSIZ); if (nla[NFTA_CHAIN_COUNTERS]) { stats = nft_stats_alloc(nla[NFTA_CHAIN_COUNTERS]); if (IS_ERR(stats)) { nft_chain_release_hook(&hook); kfree(basechain); return PTR_ERR(stats); } basechain->stats = stats; static_branch_inc(&nft_counters_enabled); } hookfn = hook.type->hooks[hook.num]; basechain->type = hook.type; chain = &basechain->chain; for (i = 0; i < afi->nops; i++) { ops = &basechain->ops[i]; ops->pf = family; ops->hooknum = hook.num; ops->priority = hook.priority; ops->priv = chain; ops->hook = afi->hooks[ops->hooknum]; ops->dev = hook.dev; if (hookfn) ops->hook = hookfn; if (afi->hook_ops_init) afi->hook_ops_init(ops, i); } chain->flags |= NFT_BASE_CHAIN; basechain->policy = policy; } else { chain = kzalloc(sizeof(*chain), GFP_KERNEL); if (chain == NULL) return -ENOMEM; } INIT_LIST_HEAD(&chain->rules); chain->handle = nf_tables_alloc_handle(table); chain->table = table; chain->name = nla_strdup(name, GFP_KERNEL); if (!chain->name) { err = -ENOMEM; goto err1; } err = nf_tables_register_hooks(net, table, chain, afi->nops); if (err < 0) goto err1; nft_ctx_init(&ctx, net, skb, nlh, afi, table, chain, nla); err = nft_trans_chain_add(&ctx, NFT_MSG_NEWCHAIN); if (err < 0) goto err2; table->use++; list_add_tail_rcu(&chain->list, &table->chains); return 0; err2: nf_tables_unregister_hooks(net, table, chain, afi->nops); err1: nf_tables_chain_destroy(chain); return err; return nf_tables_addchain(&ctx, family, genmask, policy, create); } static int nf_tables_delchain(struct net *net, struct sock *nlsk, Loading