Merge tag 'regulator-fix-v4.9-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git...
[cascardo/linux.git] / net / netfilter / nft_dynset.c
index 0af2669..517f087 100644 (file)
@@ -22,6 +22,7 @@ struct nft_dynset {
        enum nft_dynset_ops             op:8;
        enum nft_registers              sreg_key:8;
        enum nft_registers              sreg_data:8;
+       bool                            invert;
        u64                             timeout;
        struct nft_expr                 *expr;
        struct nft_set_binding          binding;
@@ -82,10 +83,14 @@ static void nft_dynset_eval(const struct nft_expr *expr,
 
                if (sexpr != NULL)
                        sexpr->ops->eval(sexpr, regs, pkt);
+
+               if (priv->invert)
+                       regs->verdict.code = NFT_BREAK;
                return;
        }
 out:
-       regs->verdict.code = NFT_BREAK;
+       if (!priv->invert)
+               regs->verdict.code = NFT_BREAK;
 }
 
 static const struct nla_policy nft_dynset_policy[NFTA_DYNSET_MAX + 1] = {
@@ -96,6 +101,7 @@ static const struct nla_policy nft_dynset_policy[NFTA_DYNSET_MAX + 1] = {
        [NFTA_DYNSET_SREG_DATA] = { .type = NLA_U32 },
        [NFTA_DYNSET_TIMEOUT]   = { .type = NLA_U64 },
        [NFTA_DYNSET_EXPR]      = { .type = NLA_NESTED },
+       [NFTA_DYNSET_FLAGS]     = { .type = NLA_U32 },
 };
 
 static int nft_dynset_init(const struct nft_ctx *ctx,
@@ -113,6 +119,15 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
            tb[NFTA_DYNSET_SREG_KEY] == NULL)
                return -EINVAL;
 
+       if (tb[NFTA_DYNSET_FLAGS]) {
+               u32 flags = ntohl(nla_get_be32(tb[NFTA_DYNSET_FLAGS]));
+
+               if (flags & ~NFT_DYNSET_F_INV)
+                       return -EINVAL;
+               if (flags & NFT_DYNSET_F_INV)
+                       priv->invert = true;
+       }
+
        set = nf_tables_set_lookup(ctx->table, tb[NFTA_DYNSET_SET_NAME],
                                   genmask);
        if (IS_ERR(set)) {
@@ -143,7 +158,8 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
        if (tb[NFTA_DYNSET_TIMEOUT] != NULL) {
                if (!(set->flags & NFT_SET_TIMEOUT))
                        return -EINVAL;
-               timeout = be64_to_cpu(nla_get_be64(tb[NFTA_DYNSET_TIMEOUT]));
+               timeout = msecs_to_jiffies(be64_to_cpu(nla_get_be64(
+                                               tb[NFTA_DYNSET_TIMEOUT])));
        }
 
        priv->sreg_key = nft_parse_register(tb[NFTA_DYNSET_SREG_KEY]);
@@ -220,6 +236,7 @@ static void nft_dynset_destroy(const struct nft_ctx *ctx,
 static int nft_dynset_dump(struct sk_buff *skb, const struct nft_expr *expr)
 {
        const struct nft_dynset *priv = nft_expr_priv(expr);
+       u32 flags = priv->invert ? NFT_DYNSET_F_INV : 0;
 
        if (nft_dump_register(skb, NFTA_DYNSET_SREG_KEY, priv->sreg_key))
                goto nla_put_failure;
@@ -230,11 +247,14 @@ static int nft_dynset_dump(struct sk_buff *skb, const struct nft_expr *expr)
                goto nla_put_failure;
        if (nla_put_string(skb, NFTA_DYNSET_SET_NAME, priv->set->name))
                goto nla_put_failure;
-       if (nla_put_be64(skb, NFTA_DYNSET_TIMEOUT, cpu_to_be64(priv->timeout),
+       if (nla_put_be64(skb, NFTA_DYNSET_TIMEOUT,
+                        cpu_to_be64(jiffies_to_msecs(priv->timeout)),
                         NFTA_DYNSET_PAD))
                goto nla_put_failure;
        if (priv->expr && nft_expr_dump(skb, NFTA_DYNSET_EXPR, priv->expr))
                goto nla_put_failure;
+       if (nla_put_be32(skb, NFTA_DYNSET_FLAGS, htonl(flags)))
+               goto nla_put_failure;
        return 0;
 
 nla_put_failure: