Merge drm/drm-fixes into drm-misc-fixes
[linux-2.6-microblaze.git] / net / netfilter / nf_tables_api.c
index d47469f..d481f9b 100644 (file)
@@ -1715,7 +1715,7 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
                goto err2;
        }
 
-       nft_trans_chain_policy(trans) = -1;
+       nft_trans_chain_policy(trans) = NFT_CHAIN_POLICY_UNSET;
        if (nft_is_base_chain(chain))
                nft_trans_chain_policy(trans) = policy;
 
@@ -2853,7 +2853,7 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
                return nft_table_validate(net, table);
 
        if (chain->flags & NFT_CHAIN_HW_OFFLOAD) {
-               flow = nft_flow_rule_create(rule);
+               flow = nft_flow_rule_create(net, rule);
                if (IS_ERR(flow))
                        return PTR_ERR(flow);
 
@@ -3562,8 +3562,11 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
                              NFT_SET_OBJECT))
                        return -EINVAL;
                /* Only one of these operations is supported */
-               if ((flags & (NFT_SET_MAP | NFT_SET_EVAL | NFT_SET_OBJECT)) ==
-                            (NFT_SET_MAP | NFT_SET_EVAL | NFT_SET_OBJECT))
+               if ((flags & (NFT_SET_MAP | NFT_SET_OBJECT)) ==
+                            (NFT_SET_MAP | NFT_SET_OBJECT))
+                       return -EOPNOTSUPP;
+               if ((flags & (NFT_SET_EVAL | NFT_SET_OBJECT)) ==
+                            (NFT_SET_EVAL | NFT_SET_OBJECT))
                        return -EOPNOTSUPP;
        }
 
@@ -5131,6 +5134,41 @@ nft_obj_type_get(struct net *net, u32 objtype)
        return ERR_PTR(-ENOENT);
 }
 
+static int nf_tables_updobj(const struct nft_ctx *ctx,
+                           const struct nft_object_type *type,
+                           const struct nlattr *attr,
+                           struct nft_object *obj)
+{
+       struct nft_object *newobj;
+       struct nft_trans *trans;
+       int err;
+
+       if (!obj->ops->update)
+               return -EOPNOTSUPP;
+
+       trans = nft_trans_alloc(ctx, NFT_MSG_NEWOBJ,
+                               sizeof(struct nft_trans_obj));
+       if (!trans)
+               return -ENOMEM;
+
+       newobj = nft_obj_init(ctx, type, attr);
+       if (IS_ERR(newobj)) {
+               err = PTR_ERR(newobj);
+               goto err_free_trans;
+       }
+
+       nft_trans_obj(trans) = obj;
+       nft_trans_obj_update(trans) = true;
+       nft_trans_obj_newobj(trans) = newobj;
+       list_add_tail(&trans->list, &ctx->net->nft.commit_list);
+
+       return 0;
+
+err_free_trans:
+       kfree(trans);
+       return err;
+}
+
 static int nf_tables_newobj(struct net *net, struct sock *nlsk,
                            struct sk_buff *skb, const struct nlmsghdr *nlh,
                            const struct nlattr * const nla[],
@@ -5170,7 +5208,13 @@ static int nf_tables_newobj(struct net *net, struct sock *nlsk,
                        NL_SET_BAD_ATTR(extack, nla[NFTA_OBJ_NAME]);
                        return -EEXIST;
                }
-               return 0;
+               if (nlh->nlmsg_flags & NLM_F_REPLACE)
+                       return -EOPNOTSUPP;
+
+               type = nft_obj_type_get(net, objtype);
+               nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla);
+
+               return nf_tables_updobj(&ctx, type, nla[NFTA_OBJ_DATA], obj);
        }
 
        nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla);
@@ -5554,6 +5598,22 @@ struct nft_flowtable *nft_flowtable_lookup(const struct nft_table *table,
 }
 EXPORT_SYMBOL_GPL(nft_flowtable_lookup);
 
+void nf_tables_deactivate_flowtable(const struct nft_ctx *ctx,
+                                   struct nft_flowtable *flowtable,
+                                   enum nft_trans_phase phase)
+{
+       switch (phase) {
+       case NFT_TRANS_PREPARE:
+       case NFT_TRANS_ABORT:
+       case NFT_TRANS_RELEASE:
+               flowtable->use--;
+               /* fall through */
+       default:
+               return;
+       }
+}
+EXPORT_SYMBOL_GPL(nf_tables_deactivate_flowtable);
+
 static struct nft_flowtable *
 nft_flowtable_lookup_byhandle(const struct nft_table *table,
                              const struct nlattr *nla, u8 genmask)
@@ -6431,6 +6491,19 @@ static void nft_chain_commit_update(struct nft_trans *trans)
        }
 }
 
+static void nft_obj_commit_update(struct nft_trans *trans)
+{
+       struct nft_object *newobj;
+       struct nft_object *obj;
+
+       obj = nft_trans_obj(trans);
+       newobj = nft_trans_obj_newobj(trans);
+
+       obj->ops->update(obj, newobj);
+
+       kfree(newobj);
+}
+
 static void nft_commit_release(struct nft_trans *trans)
 {
        switch (trans->msg_type) {
@@ -6795,10 +6868,18 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
                        te->set->ndeact--;
                        break;
                case NFT_MSG_NEWOBJ:
-                       nft_clear(net, nft_trans_obj(trans));
-                       nf_tables_obj_notify(&trans->ctx, nft_trans_obj(trans),
-                                            NFT_MSG_NEWOBJ);
-                       nft_trans_destroy(trans);
+                       if (nft_trans_obj_update(trans)) {
+                               nft_obj_commit_update(trans);
+                               nf_tables_obj_notify(&trans->ctx,
+                                                    nft_trans_obj(trans),
+                                                    NFT_MSG_NEWOBJ);
+                       } else {
+                               nft_clear(net, nft_trans_obj(trans));
+                               nf_tables_obj_notify(&trans->ctx,
+                                                    nft_trans_obj(trans),
+                                                    NFT_MSG_NEWOBJ);
+                               nft_trans_destroy(trans);
+                       }
                        break;
                case NFT_MSG_DELOBJ:
                        nft_obj_del(nft_trans_obj(trans));
@@ -6945,8 +7026,13 @@ static int __nf_tables_abort(struct net *net)
                        nft_trans_destroy(trans);
                        break;
                case NFT_MSG_NEWOBJ:
-                       trans->ctx.table->use--;
-                       nft_obj_del(nft_trans_obj(trans));
+                       if (nft_trans_obj_update(trans)) {
+                               kfree(nft_trans_obj_newobj(trans));
+                               nft_trans_destroy(trans);
+                       } else {
+                               trans->ctx.table->use--;
+                               nft_obj_del(nft_trans_obj(trans));
+                       }
                        break;
                case NFT_MSG_DELOBJ:
                        trans->ctx.table->use++;
@@ -7627,13 +7713,20 @@ static int __init nf_tables_module_init(void)
        if (err < 0)
                goto err4;
 
+       err = nft_offload_init();
+       if (err < 0)
+               goto err5;
+
        /* must be last */
        err = nfnetlink_subsys_register(&nf_tables_subsys);
        if (err < 0)
-               goto err5;
+               goto err6;
 
        nft_chain_route_init();
+
        return err;
+err6:
+       nft_offload_exit();
 err5:
        rhltable_destroy(&nft_objname_ht);
 err4:
@@ -7650,6 +7743,7 @@ err1:
 static void __exit nf_tables_module_exit(void)
 {
        nfnetlink_subsys_unregister(&nf_tables_subsys);
+       nft_offload_exit();
        unregister_netdevice_notifier(&nf_tables_flowtable_notifier);
        nft_chain_filter_fini();
        nft_chain_route_fini();