Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next
[linux-2.6-microblaze.git] / net / netfilter / nf_tables_api.c
index a5f3743..87b2a77 100644 (file)
@@ -74,88 +74,43 @@ static void nft_trans_destroy(struct nft_trans *trans)
        kfree(trans);
 }
 
-/* removal requests are queued in the commit_list, but not acted upon
- * until after all new rules are in place.
- *
- * Therefore, nf_register_net_hook(net, &nat_hook) runs before pending
- * nf_unregister_net_hook().
- *
- * nf_register_net_hook thus fails if a nat hook is already in place
- * even if the conflicting hook is about to be removed.
- *
- * If collision is detected, search commit_log for DELCHAIN matching
- * the new nat hooknum; if we find one collision is temporary:
- *
- * Either transaction is aborted (new/colliding hook is removed), or
- * transaction is committed (old hook is removed).
- */
-static bool nf_tables_allow_nat_conflict(const struct net *net,
-                                        const struct nf_hook_ops *ops)
-{
-       const struct nft_trans *trans;
-       bool ret = false;
-
-       if (!ops->nat_hook)
-               return false;
-
-       list_for_each_entry(trans, &net->nft.commit_list, list) {
-               const struct nf_hook_ops *pending_ops;
-               const struct nft_chain *pending;
-
-               if (trans->msg_type != NFT_MSG_NEWCHAIN &&
-                   trans->msg_type != NFT_MSG_DELCHAIN)
-                       continue;
-
-               pending = trans->ctx.chain;
-               if (!nft_is_base_chain(pending))
-                       continue;
-
-               pending_ops = &nft_base_chain(pending)->ops;
-               if (pending_ops->nat_hook &&
-                   pending_ops->pf == ops->pf &&
-                   pending_ops->hooknum == ops->hooknum) {
-                       /* other hook registration already pending? */
-                       if (trans->msg_type == NFT_MSG_NEWCHAIN)
-                               return false;
-
-                       ret = true;
-               }
-       }
-
-       return ret;
-}
-
 static int nf_tables_register_hook(struct net *net,
                                   const struct nft_table *table,
                                   struct nft_chain *chain)
 {
-       struct nf_hook_ops *ops;
-       int ret;
+       const struct nft_base_chain *basechain;
+       const struct nf_hook_ops *ops;
 
        if (table->flags & NFT_TABLE_F_DORMANT ||
            !nft_is_base_chain(chain))
                return 0;
 
-       ops = &nft_base_chain(chain)->ops;
-       ret = nf_register_net_hook(net, ops);
-       if (ret == -EBUSY && nf_tables_allow_nat_conflict(net, ops)) {
-               ops->nat_hook = false;
-               ret = nf_register_net_hook(net, ops);
-               ops->nat_hook = true;
-       }
+       basechain = nft_base_chain(chain);
+       ops = &basechain->ops;
 
-       return ret;
+       if (basechain->type->ops_register)
+               return basechain->type->ops_register(net, ops);
+
+       return nf_register_net_hook(net, ops);
 }
 
 static void nf_tables_unregister_hook(struct net *net,
                                      const struct nft_table *table,
                                      struct nft_chain *chain)
 {
+       const struct nft_base_chain *basechain;
+       const struct nf_hook_ops *ops;
+
        if (table->flags & NFT_TABLE_F_DORMANT ||
            !nft_is_base_chain(chain))
                return;
+       basechain = nft_base_chain(chain);
+       ops = &basechain->ops;
 
-       nf_unregister_net_hook(net, &nft_base_chain(chain)->ops);
+       if (basechain->type->ops_unregister)
+               return basechain->type->ops_unregister(net, ops);
+
+       nf_unregister_net_hook(net, ops);
 }
 
 static int nft_trans_table_add(struct nft_ctx *ctx, int msg_type)
@@ -1291,8 +1246,6 @@ static void nf_tables_chain_destroy(struct nft_ctx *ctx)
        if (nft_is_base_chain(chain)) {
                struct nft_base_chain *basechain = nft_base_chain(chain);
 
-               if (basechain->type->free)
-                       basechain->type->free(ctx);
                module_put(basechain->type->owner);
                free_percpu(basechain->stats);
                if (basechain->stats)
@@ -1425,9 +1378,6 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
                }
 
                basechain->type = hook.type;
-               if (basechain->type->init)
-                       basechain->type->init(ctx);
-
                chain = &basechain->chain;
 
                ops             = &basechain->ops;
@@ -1438,9 +1388,6 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
                ops->hook       = hook.type->hooks[ops->hooknum];
                ops->dev        = hook.dev;
 
-               if (basechain->type->type == NFT_CHAIN_T_NAT)
-                       ops->nat_hook = true;
-
                chain->flags |= NFT_BASE_CHAIN;
                basechain->policy = policy;
        } else {