switch rbd and libceph to p_log-based primitives
[linux-2.6-microblaze.git] / net / netfilter / nft_bitwise.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
4  *
5  * Development of this code funded by Astaro AG (http://www.astaro.com/)
6  */
7
8 #include <linux/kernel.h>
9 #include <linux/init.h>
10 #include <linux/module.h>
11 #include <linux/netlink.h>
12 #include <linux/netfilter.h>
13 #include <linux/netfilter/nf_tables.h>
14 #include <net/netfilter/nf_tables_core.h>
15 #include <net/netfilter/nf_tables.h>
16 #include <net/netfilter/nf_tables_offload.h>
17
18 struct nft_bitwise {
19         enum nft_registers      sreg:8;
20         enum nft_registers      dreg:8;
21         u8                      len;
22         struct nft_data         mask;
23         struct nft_data         xor;
24 };
25
26 void nft_bitwise_eval(const struct nft_expr *expr,
27                       struct nft_regs *regs, const struct nft_pktinfo *pkt)
28 {
29         const struct nft_bitwise *priv = nft_expr_priv(expr);
30         const u32 *src = &regs->data[priv->sreg];
31         u32 *dst = &regs->data[priv->dreg];
32         unsigned int i;
33
34         for (i = 0; i < DIV_ROUND_UP(priv->len, 4); i++)
35                 dst[i] = (src[i] & priv->mask.data[i]) ^ priv->xor.data[i];
36 }
37
38 static const struct nla_policy nft_bitwise_policy[NFTA_BITWISE_MAX + 1] = {
39         [NFTA_BITWISE_SREG]     = { .type = NLA_U32 },
40         [NFTA_BITWISE_DREG]     = { .type = NLA_U32 },
41         [NFTA_BITWISE_LEN]      = { .type = NLA_U32 },
42         [NFTA_BITWISE_MASK]     = { .type = NLA_NESTED },
43         [NFTA_BITWISE_XOR]      = { .type = NLA_NESTED },
44 };
45
46 static int nft_bitwise_init(const struct nft_ctx *ctx,
47                             const struct nft_expr *expr,
48                             const struct nlattr * const tb[])
49 {
50         struct nft_bitwise *priv = nft_expr_priv(expr);
51         struct nft_data_desc d1, d2;
52         u32 len;
53         int err;
54
55         if (tb[NFTA_BITWISE_SREG] == NULL ||
56             tb[NFTA_BITWISE_DREG] == NULL ||
57             tb[NFTA_BITWISE_LEN] == NULL ||
58             tb[NFTA_BITWISE_MASK] == NULL ||
59             tb[NFTA_BITWISE_XOR] == NULL)
60                 return -EINVAL;
61
62         err = nft_parse_u32_check(tb[NFTA_BITWISE_LEN], U8_MAX, &len);
63         if (err < 0)
64                 return err;
65
66         priv->len = len;
67
68         priv->sreg = nft_parse_register(tb[NFTA_BITWISE_SREG]);
69         err = nft_validate_register_load(priv->sreg, priv->len);
70         if (err < 0)
71                 return err;
72
73         priv->dreg = nft_parse_register(tb[NFTA_BITWISE_DREG]);
74         err = nft_validate_register_store(ctx, priv->dreg, NULL,
75                                           NFT_DATA_VALUE, priv->len);
76         if (err < 0)
77                 return err;
78
79         err = nft_data_init(NULL, &priv->mask, sizeof(priv->mask), &d1,
80                             tb[NFTA_BITWISE_MASK]);
81         if (err < 0)
82                 return err;
83         if (d1.type != NFT_DATA_VALUE || d1.len != priv->len) {
84                 err = -EINVAL;
85                 goto err1;
86         }
87
88         err = nft_data_init(NULL, &priv->xor, sizeof(priv->xor), &d2,
89                             tb[NFTA_BITWISE_XOR]);
90         if (err < 0)
91                 goto err1;
92         if (d2.type != NFT_DATA_VALUE || d2.len != priv->len) {
93                 err = -EINVAL;
94                 goto err2;
95         }
96
97         return 0;
98 err2:
99         nft_data_release(&priv->xor, d2.type);
100 err1:
101         nft_data_release(&priv->mask, d1.type);
102         return err;
103 }
104
105 static int nft_bitwise_dump(struct sk_buff *skb, const struct nft_expr *expr)
106 {
107         const struct nft_bitwise *priv = nft_expr_priv(expr);
108
109         if (nft_dump_register(skb, NFTA_BITWISE_SREG, priv->sreg))
110                 goto nla_put_failure;
111         if (nft_dump_register(skb, NFTA_BITWISE_DREG, priv->dreg))
112                 goto nla_put_failure;
113         if (nla_put_be32(skb, NFTA_BITWISE_LEN, htonl(priv->len)))
114                 goto nla_put_failure;
115
116         if (nft_data_dump(skb, NFTA_BITWISE_MASK, &priv->mask,
117                           NFT_DATA_VALUE, priv->len) < 0)
118                 goto nla_put_failure;
119
120         if (nft_data_dump(skb, NFTA_BITWISE_XOR, &priv->xor,
121                           NFT_DATA_VALUE, priv->len) < 0)
122                 goto nla_put_failure;
123
124         return 0;
125
126 nla_put_failure:
127         return -1;
128 }
129
130 static struct nft_data zero;
131
132 static int nft_bitwise_offload(struct nft_offload_ctx *ctx,
133                                struct nft_flow_rule *flow,
134                                const struct nft_expr *expr)
135 {
136         const struct nft_bitwise *priv = nft_expr_priv(expr);
137         struct nft_offload_reg *reg = &ctx->regs[priv->dreg];
138
139         if (memcmp(&priv->xor, &zero, sizeof(priv->xor)) ||
140             priv->sreg != priv->dreg || priv->len != reg->len)
141                 return -EOPNOTSUPP;
142
143         memcpy(&reg->mask, &priv->mask, sizeof(priv->mask));
144
145         return 0;
146 }
147
148 static const struct nft_expr_ops nft_bitwise_ops = {
149         .type           = &nft_bitwise_type,
150         .size           = NFT_EXPR_SIZE(sizeof(struct nft_bitwise)),
151         .eval           = nft_bitwise_eval,
152         .init           = nft_bitwise_init,
153         .dump           = nft_bitwise_dump,
154         .offload        = nft_bitwise_offload,
155 };
156
157 struct nft_expr_type nft_bitwise_type __read_mostly = {
158         .name           = "bitwise",
159         .ops            = &nft_bitwise_ops,
160         .policy         = nft_bitwise_policy,
161         .maxattr        = NFTA_BITWISE_MAX,
162         .owner          = THIS_MODULE,
163 };