Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
 1// SPDX-License-Identifier: GPL-2.0-only
 2#include <linux/kernel.h>
 3#include <linux/init.h>
 4#include <linux/module.h>
 5#include <linux/netlink.h>
 6#include <linux/netfilter.h>
 7#include <linux/netfilter/nf_tables.h>
 8#include <net/netfilter/nf_tables_core.h>
 9#include <net/netfilter/nf_tables.h>
10
11struct nft_last_priv {
12	unsigned long	last_jiffies;
13	unsigned int	last_set;
14};
15
16static const struct nla_policy nft_last_policy[NFTA_LAST_MAX + 1] = {
17	[NFTA_LAST_SET] = { .type = NLA_U32 },
18	[NFTA_LAST_MSECS] = { .type = NLA_U64 },
19};
20
21static int nft_last_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
22			 const struct nlattr * const tb[])
23{
24	struct nft_last_priv *priv = nft_expr_priv(expr);
25	u64 last_jiffies;
26	u32 last_set = 0;
27	int err;
28
29	if (tb[NFTA_LAST_SET]) {
30		last_set = ntohl(nla_get_be32(tb[NFTA_LAST_SET]));
31		if (last_set == 1)
32			priv->last_set = 1;
33	}
34
35	if (last_set && tb[NFTA_LAST_MSECS]) {
36		err = nf_msecs_to_jiffies64(tb[NFTA_LAST_MSECS], &last_jiffies);
37		if (err < 0)
38			return err;
39
40		priv->last_jiffies = jiffies - (unsigned long)last_jiffies;
41	}
42
43	return 0;
44}
45
46static void nft_last_eval(const struct nft_expr *expr,
47			  struct nft_regs *regs, const struct nft_pktinfo *pkt)
48{
49	struct nft_last_priv *priv = nft_expr_priv(expr);
50
51	if (READ_ONCE(priv->last_jiffies) != jiffies)
52		WRITE_ONCE(priv->last_jiffies, jiffies);
53	if (READ_ONCE(priv->last_set) == 0)
54		WRITE_ONCE(priv->last_set, 1);
55}
56
57static int nft_last_dump(struct sk_buff *skb, const struct nft_expr *expr)
58{
59	struct nft_last_priv *priv = nft_expr_priv(expr);
60	unsigned long last_jiffies = READ_ONCE(priv->last_jiffies);
61	u32 last_set = READ_ONCE(priv->last_set);
62	__be64 msecs;
63
64	if (time_before(jiffies, last_jiffies)) {
65		WRITE_ONCE(priv->last_set, 0);
66		last_set = 0;
67	}
68
69	if (last_set)
70		msecs = nf_jiffies64_to_msecs(jiffies - last_jiffies);
71	else
72		msecs = 0;
73
74	if (nla_put_be32(skb, NFTA_LAST_SET, htonl(last_set)) ||
75	    nla_put_be64(skb, NFTA_LAST_MSECS, msecs, NFTA_LAST_PAD))
76		goto nla_put_failure;
77
78	return 0;
79
80nla_put_failure:
81	return -1;
82}
83
84static const struct nft_expr_ops nft_last_ops = {
85	.type		= &nft_last_type,
86	.size		= NFT_EXPR_SIZE(sizeof(struct nft_last_priv)),
87	.eval		= nft_last_eval,
88	.init		= nft_last_init,
89	.dump		= nft_last_dump,
90};
91
92struct nft_expr_type nft_last_type __read_mostly = {
93	.name		= "last",
94	.ops		= &nft_last_ops,
95	.policy		= nft_last_policy,
96	.maxattr	= NFTA_LAST_MAX,
97	.flags		= NFT_EXPR_STATEFUL,
98	.owner		= THIS_MODULE,
99};