summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/nf_tables_api.c199
1 files changed, 106 insertions, 93 deletions
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index a910544..d95dfaf 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -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)
{
@@ -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;
@@ -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,
OpenPOWER on IntegriCloud