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 a2bb314..87b2a77 100644 (file)
@@ -169,6 +169,34 @@ static int nft_delchain(struct nft_ctx *ctx)
        return err;
 }
 
+static void nft_rule_expr_activate(const struct nft_ctx *ctx,
+                                  struct nft_rule *rule)
+{
+       struct nft_expr *expr;
+
+       expr = nft_expr_first(rule);
+       while (expr != nft_expr_last(rule) && expr->ops) {
+               if (expr->ops->activate)
+                       expr->ops->activate(ctx, expr);
+
+               expr = nft_expr_next(expr);
+       }
+}
+
+static void nft_rule_expr_deactivate(const struct nft_ctx *ctx,
+                                    struct nft_rule *rule)
+{
+       struct nft_expr *expr;
+
+       expr = nft_expr_first(rule);
+       while (expr != nft_expr_last(rule) && expr->ops) {
+               if (expr->ops->deactivate)
+                       expr->ops->deactivate(ctx, expr);
+
+               expr = nft_expr_next(expr);
+       }
+}
+
 static int
 nf_tables_delrule_deactivate(struct nft_ctx *ctx, struct nft_rule *rule)
 {
@@ -214,6 +242,7 @@ static int nft_delrule(struct nft_ctx *ctx, struct nft_rule *rule)
                nft_trans_destroy(trans);
                return err;
        }
+       nft_rule_expr_deactivate(ctx, rule);
 
        return 0;
 }
@@ -2189,6 +2218,13 @@ static void nf_tables_rule_destroy(const struct nft_ctx *ctx,
        kfree(rule);
 }
 
+static void nf_tables_rule_release(const struct nft_ctx *ctx,
+                                  struct nft_rule *rule)
+{
+       nft_rule_expr_deactivate(ctx, rule);
+       nf_tables_rule_destroy(ctx, rule);
+}
+
 #define NFT_RULE_MAXEXPRS      128
 
 static struct nft_expr_info *info;
@@ -2362,7 +2398,7 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
        return 0;
 
 err2:
-       nf_tables_rule_destroy(&ctx, rule);
+       nf_tables_rule_release(&ctx, rule);
 err1:
        for (i = 0; i < n; i++) {
                if (info[i].ops != NULL)
@@ -4045,8 +4081,10 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
                        if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA) ^
                            nft_set_ext_exists(ext2, NFT_SET_EXT_DATA) ||
                            nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF) ^
-                           nft_set_ext_exists(ext2, NFT_SET_EXT_OBJREF))
-                               return -EBUSY;
+                           nft_set_ext_exists(ext2, NFT_SET_EXT_OBJREF)) {
+                               err = -EBUSY;
+                               goto err5;
+                       }
                        if ((nft_set_ext_exists(ext, NFT_SET_EXT_DATA) &&
                             nft_set_ext_exists(ext2, NFT_SET_EXT_DATA) &&
                             memcmp(nft_set_ext_data(ext),
@@ -4132,7 +4170,7 @@ static int nf_tables_newsetelem(struct net *net, struct sock *nlsk,
  *     NFT_GOTO verdicts. This function must be called on active data objects
  *     from the second phase of the commit protocol.
  */
-static void nft_data_hold(const struct nft_data *data, enum nft_data_types type)
+void nft_data_hold(const struct nft_data *data, enum nft_data_types type)
 {
        if (type == NFT_DATA_VERDICT) {
                switch (data->verdict.code) {
@@ -5768,7 +5806,7 @@ static void nft_chain_commit_update(struct nft_trans *trans)
        }
 }
 
-static void nf_tables_commit_release(struct nft_trans *trans)
+static void nft_commit_release(struct nft_trans *trans)
 {
        switch (trans->msg_type) {
        case NFT_MSG_DELTABLE:
@@ -5797,6 +5835,21 @@ static void nf_tables_commit_release(struct nft_trans *trans)
        kfree(trans);
 }
 
+static void nf_tables_commit_release(struct net *net)
+{
+       struct nft_trans *trans, *next;
+
+       if (list_empty(&net->nft.commit_list))
+               return;
+
+       synchronize_rcu();
+
+       list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
+               list_del(&trans->list);
+               nft_commit_release(trans);
+       }
+}
+
 static int nf_tables_commit(struct net *net, struct sk_buff *skb)
 {
        struct nft_trans *trans, *next;
@@ -5927,13 +5980,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
                }
        }
 
-       synchronize_rcu();
-
-       list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
-               list_del(&trans->list);
-               nf_tables_commit_release(trans);
-       }
-
+       nf_tables_commit_release(net);
        nf_tables_gen_notify(net, skb, NFT_MSG_NEWGEN);
 
        return 0;
@@ -6013,10 +6060,12 @@ static int nf_tables_abort(struct net *net, struct sk_buff *skb)
                case NFT_MSG_NEWRULE:
                        trans->ctx.chain->use--;
                        list_del_rcu(&nft_trans_rule(trans)->list);
+                       nft_rule_expr_deactivate(&trans->ctx, nft_trans_rule(trans));
                        break;
                case NFT_MSG_DELRULE:
                        trans->ctx.chain->use++;
                        nft_clear(trans->ctx.net, nft_trans_rule(trans));
+                       nft_rule_expr_activate(&trans->ctx, nft_trans_rule(trans));
                        nft_trans_destroy(trans);
                        break;
                case NFT_MSG_NEWSET:
@@ -6592,7 +6641,7 @@ int __nft_release_basechain(struct nft_ctx *ctx)
        list_for_each_entry_safe(rule, nr, &ctx->chain->rules, list) {
                list_del(&rule->list);
                ctx->chain->use--;
-               nf_tables_rule_destroy(ctx, rule);
+               nf_tables_rule_release(ctx, rule);
        }
        list_del(&ctx->chain->list);
        ctx->table->use--;
@@ -6630,7 +6679,7 @@ static void __nft_release_tables(struct net *net)
                        list_for_each_entry_safe(rule, nr, &chain->rules, list) {
                                list_del(&rule->list);
                                chain->use--;
-                               nf_tables_rule_destroy(&ctx, rule);
+                               nf_tables_rule_release(&ctx, rule);
                        }
                }
                list_for_each_entry_safe(flowtable, nf, &table->flowtables, list) {