0001
0002 #include <linux/kernel.h>
0003 #include <linux/init.h>
0004 #include <linux/module.h>
0005 #include <linux/netlink.h>
0006 #include <linux/netfilter.h>
0007 #include <linux/netfilter/nf_tables.h>
0008 #include <net/netfilter/nf_tables_core.h>
0009 #include <net/netfilter/nf_tables.h>
0010
0011 struct nft_last {
0012 unsigned long jiffies;
0013 unsigned int set;
0014 };
0015
0016 struct nft_last_priv {
0017 struct nft_last *last;
0018 };
0019
0020 static const struct nla_policy nft_last_policy[NFTA_LAST_MAX + 1] = {
0021 [NFTA_LAST_SET] = { .type = NLA_U32 },
0022 [NFTA_LAST_MSECS] = { .type = NLA_U64 },
0023 };
0024
0025 static int nft_last_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
0026 const struct nlattr * const tb[])
0027 {
0028 struct nft_last_priv *priv = nft_expr_priv(expr);
0029 struct nft_last *last;
0030 u64 last_jiffies;
0031 int err;
0032
0033 last = kzalloc(sizeof(*last), GFP_KERNEL_ACCOUNT);
0034 if (!last)
0035 return -ENOMEM;
0036
0037 if (tb[NFTA_LAST_SET])
0038 last->set = ntohl(nla_get_be32(tb[NFTA_LAST_SET]));
0039
0040 if (last->set && tb[NFTA_LAST_MSECS]) {
0041 err = nf_msecs_to_jiffies64(tb[NFTA_LAST_MSECS], &last_jiffies);
0042 if (err < 0)
0043 goto err;
0044
0045 last->jiffies = jiffies - (unsigned long)last_jiffies;
0046 }
0047 priv->last = last;
0048
0049 return 0;
0050 err:
0051 kfree(last);
0052
0053 return err;
0054 }
0055
0056 static void nft_last_eval(const struct nft_expr *expr,
0057 struct nft_regs *regs, const struct nft_pktinfo *pkt)
0058 {
0059 struct nft_last_priv *priv = nft_expr_priv(expr);
0060 struct nft_last *last = priv->last;
0061
0062 if (READ_ONCE(last->jiffies) != jiffies)
0063 WRITE_ONCE(last->jiffies, jiffies);
0064 if (READ_ONCE(last->set) == 0)
0065 WRITE_ONCE(last->set, 1);
0066 }
0067
0068 static int nft_last_dump(struct sk_buff *skb, const struct nft_expr *expr)
0069 {
0070 struct nft_last_priv *priv = nft_expr_priv(expr);
0071 struct nft_last *last = priv->last;
0072 unsigned long last_jiffies = READ_ONCE(last->jiffies);
0073 u32 last_set = READ_ONCE(last->set);
0074 __be64 msecs;
0075
0076 if (time_before(jiffies, last_jiffies)) {
0077 WRITE_ONCE(last->set, 0);
0078 last_set = 0;
0079 }
0080
0081 if (last_set)
0082 msecs = nf_jiffies64_to_msecs(jiffies - last_jiffies);
0083 else
0084 msecs = 0;
0085
0086 if (nla_put_be32(skb, NFTA_LAST_SET, htonl(last_set)) ||
0087 nla_put_be64(skb, NFTA_LAST_MSECS, msecs, NFTA_LAST_PAD))
0088 goto nla_put_failure;
0089
0090 return 0;
0091
0092 nla_put_failure:
0093 return -1;
0094 }
0095
0096 static void nft_last_destroy(const struct nft_ctx *ctx,
0097 const struct nft_expr *expr)
0098 {
0099 struct nft_last_priv *priv = nft_expr_priv(expr);
0100
0101 kfree(priv->last);
0102 }
0103
0104 static int nft_last_clone(struct nft_expr *dst, const struct nft_expr *src)
0105 {
0106 struct nft_last_priv *priv_dst = nft_expr_priv(dst);
0107
0108 priv_dst->last = kzalloc(sizeof(*priv_dst->last), GFP_ATOMIC);
0109 if (!priv_dst->last)
0110 return -ENOMEM;
0111
0112 return 0;
0113 }
0114
0115 static const struct nft_expr_ops nft_last_ops = {
0116 .type = &nft_last_type,
0117 .size = NFT_EXPR_SIZE(sizeof(struct nft_last_priv)),
0118 .eval = nft_last_eval,
0119 .init = nft_last_init,
0120 .destroy = nft_last_destroy,
0121 .clone = nft_last_clone,
0122 .dump = nft_last_dump,
0123 .reduce = NFT_REDUCE_READONLY,
0124 };
0125
0126 struct nft_expr_type nft_last_type __read_mostly = {
0127 .name = "last",
0128 .ops = &nft_last_ops,
0129 .policy = nft_last_policy,
0130 .maxattr = NFTA_LAST_MAX,
0131 .flags = NFT_EXPR_STATEFUL,
0132 .owner = THIS_MODULE,
0133 };