x86/smpboot: Init apic mapping before usage
[cascardo/linux.git] / net / netfilter / nf_tables_api.c
index 221d27f..b70d3ea 100644 (file)
@@ -3483,12 +3483,12 @@ static int nft_setelem_parse_flags(const struct nft_set *set,
 }
 
 static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
-                           const struct nlattr *attr)
+                           const struct nlattr *attr, u32 nlmsg_flags)
 {
        struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
        struct nft_data_desc d1, d2;
        struct nft_set_ext_tmpl tmpl;
-       struct nft_set_ext *ext;
+       struct nft_set_ext *ext, *ext2;
        struct nft_set_elem elem;
        struct nft_set_binding *binding;
        struct nft_userdata *udata;
@@ -3615,9 +3615,19 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
                goto err4;
 
        ext->genmask = nft_genmask_cur(ctx->net) | NFT_SET_ELEM_BUSY_MASK;
-       err = set->ops->insert(ctx->net, set, &elem);
-       if (err < 0)
+       err = set->ops->insert(ctx->net, set, &elem, &ext2);
+       if (err) {
+               if (err == -EEXIST) {
+                       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),
+                                  nft_set_ext_data(ext2), set->dlen) != 0)
+                               err = -EBUSY;
+                       else if (!(nlmsg_flags & NLM_F_EXCL))
+                               err = 0;
+               }
                goto err5;
+       }
 
        nft_trans_elem(trans) = elem;
        list_add_tail(&trans->list, &ctx->net->nft.commit_list);
@@ -3673,7 +3683,7 @@ static int nf_tables_newsetelem(struct net *net, struct sock *nlsk,
                    !atomic_add_unless(&set->nelems, 1, set->size + set->ndeact))
                        return -ENFILE;
 
-               err = nft_add_set_elem(&ctx, set, attr);
+               err = nft_add_set_elem(&ctx, set, attr, nlh->nlmsg_flags);
                if (err < 0) {
                        atomic_dec(&set->nelems);
                        break;
@@ -4399,6 +4409,31 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx,
        return 0;
 }
 
+/**
+ *     nft_parse_u32_check - fetch u32 attribute and check for maximum value
+ *
+ *     @attr: netlink attribute to fetch value from
+ *     @max: maximum value to be stored in dest
+ *     @dest: pointer to the variable
+ *
+ *     Parse, check and store a given u32 netlink attribute into variable.
+ *     This function returns -ERANGE if the value goes over maximum value.
+ *     Otherwise a 0 is returned and the attribute value is stored in the
+ *     destination variable.
+ */
+unsigned int nft_parse_u32_check(const struct nlattr *attr, int max, u32 *dest)
+{
+       int val;
+
+       val = ntohl(nla_get_be32(attr));
+       if (val > max)
+               return -ERANGE;
+
+       *dest = val;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(nft_parse_u32_check);
+
 /**
  *     nft_parse_register - parse a register value from a netlink attribute
  *