]> git.ipfire.org Git - thirdparty/linux.git/blame - net/netfilter/nft_bitwise.c
netfilter: bitwise: add NFTA_BITWISE_OP netlink attribute.
[thirdparty/linux.git] / net / netfilter / nft_bitwise.c
CommitLineData
d2912cb1 1// SPDX-License-Identifier: GPL-2.0-only
96518518 2/*
ef1f7df9 3 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
96518518 4 *
96518518
PM
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>
bd8699e9 16#include <net/netfilter/nf_tables_offload.h>
96518518
PM
17
18struct nft_bitwise {
19 enum nft_registers sreg:8;
20 enum nft_registers dreg:8;
9d1f9799 21 enum nft_bitwise_ops op:8;
96518518
PM
22 u8 len;
23 struct nft_data mask;
24 struct nft_data xor;
25};
26
10870dd8
FW
27void nft_bitwise_eval(const struct nft_expr *expr,
28 struct nft_regs *regs, const struct nft_pktinfo *pkt)
96518518
PM
29{
30 const struct nft_bitwise *priv = nft_expr_priv(expr);
49499c3e
PM
31 const u32 *src = &regs->data[priv->sreg];
32 u32 *dst = &regs->data[priv->dreg];
96518518
PM
33 unsigned int i;
34
fad136ea
PM
35 for (i = 0; i < DIV_ROUND_UP(priv->len, 4); i++)
36 dst[i] = (src[i] & priv->mask.data[i]) ^ priv->xor.data[i];
96518518
PM
37}
38
39static const struct nla_policy nft_bitwise_policy[NFTA_BITWISE_MAX + 1] = {
40 [NFTA_BITWISE_SREG] = { .type = NLA_U32 },
41 [NFTA_BITWISE_DREG] = { .type = NLA_U32 },
42 [NFTA_BITWISE_LEN] = { .type = NLA_U32 },
43 [NFTA_BITWISE_MASK] = { .type = NLA_NESTED },
44 [NFTA_BITWISE_XOR] = { .type = NLA_NESTED },
9d1f9799 45 [NFTA_BITWISE_OP] = { .type = NLA_U32 },
96518518
PM
46};
47
48static int nft_bitwise_init(const struct nft_ctx *ctx,
49 const struct nft_expr *expr,
50 const struct nlattr * const tb[])
51{
52 struct nft_bitwise *priv = nft_expr_priv(expr);
53 struct nft_data_desc d1, d2;
36b701fa 54 u32 len;
96518518
PM
55 int err;
56
265ec7b0
JS
57 if (!tb[NFTA_BITWISE_SREG] ||
58 !tb[NFTA_BITWISE_DREG] ||
59 !tb[NFTA_BITWISE_LEN] ||
60 !tb[NFTA_BITWISE_MASK] ||
61 !tb[NFTA_BITWISE_XOR])
96518518
PM
62 return -EINVAL;
63
36b701fa
LGL
64 err = nft_parse_u32_check(tb[NFTA_BITWISE_LEN], U8_MAX, &len);
65 if (err < 0)
66 return err;
67
68 priv->len = len;
69
b1c96ed3 70 priv->sreg = nft_parse_register(tb[NFTA_BITWISE_SREG]);
d07db988 71 err = nft_validate_register_load(priv->sreg, priv->len);
96518518
PM
72 if (err < 0)
73 return err;
74
b1c96ed3 75 priv->dreg = nft_parse_register(tb[NFTA_BITWISE_DREG]);
1ec10212
PM
76 err = nft_validate_register_store(ctx, priv->dreg, NULL,
77 NFT_DATA_VALUE, priv->len);
96518518
PM
78 if (err < 0)
79 return err;
80
9d1f9799
JS
81 if (tb[NFTA_BITWISE_OP]) {
82 priv->op = ntohl(nla_get_be32(tb[NFTA_BITWISE_OP]));
83 switch (priv->op) {
84 case NFT_BITWISE_BOOL:
85 break;
86 default:
87 return -EOPNOTSUPP;
88 }
89 } else {
90 priv->op = NFT_BITWISE_BOOL;
91 }
92
d0a11fc3
PM
93 err = nft_data_init(NULL, &priv->mask, sizeof(priv->mask), &d1,
94 tb[NFTA_BITWISE_MASK]);
96518518
PM
95 if (err < 0)
96 return err;
0d2c96af 97 if (d1.type != NFT_DATA_VALUE || d1.len != priv->len) {
71df14b0
PNA
98 err = -EINVAL;
99 goto err1;
100 }
96518518 101
d0a11fc3
PM
102 err = nft_data_init(NULL, &priv->xor, sizeof(priv->xor), &d2,
103 tb[NFTA_BITWISE_XOR]);
96518518 104 if (err < 0)
71df14b0 105 goto err1;
0d2c96af 106 if (d2.type != NFT_DATA_VALUE || d2.len != priv->len) {
71df14b0
PNA
107 err = -EINVAL;
108 goto err2;
109 }
96518518
PM
110
111 return 0;
71df14b0 112err2:
59105446 113 nft_data_release(&priv->xor, d2.type);
71df14b0 114err1:
59105446 115 nft_data_release(&priv->mask, d1.type);
71df14b0 116 return err;
96518518
PM
117}
118
119static int nft_bitwise_dump(struct sk_buff *skb, const struct nft_expr *expr)
120{
121 const struct nft_bitwise *priv = nft_expr_priv(expr);
122
b1c96ed3 123 if (nft_dump_register(skb, NFTA_BITWISE_SREG, priv->sreg))
577c734a 124 return -1;
b1c96ed3 125 if (nft_dump_register(skb, NFTA_BITWISE_DREG, priv->dreg))
577c734a 126 return -1;
96518518 127 if (nla_put_be32(skb, NFTA_BITWISE_LEN, htonl(priv->len)))
577c734a 128 return -1;
9d1f9799
JS
129 if (nla_put_be32(skb, NFTA_BITWISE_OP, htonl(priv->op)))
130 return -1;
96518518
PM
131
132 if (nft_data_dump(skb, NFTA_BITWISE_MASK, &priv->mask,
133 NFT_DATA_VALUE, priv->len) < 0)
577c734a 134 return -1;
96518518
PM
135
136 if (nft_data_dump(skb, NFTA_BITWISE_XOR, &priv->xor,
137 NFT_DATA_VALUE, priv->len) < 0)
577c734a 138 return -1;
96518518
PM
139
140 return 0;
96518518
PM
141}
142
bd8699e9
PNA
143static struct nft_data zero;
144
145static int nft_bitwise_offload(struct nft_offload_ctx *ctx,
fbf19ddf
JS
146 struct nft_flow_rule *flow,
147 const struct nft_expr *expr)
bd8699e9
PNA
148{
149 const struct nft_bitwise *priv = nft_expr_priv(expr);
de2a6052 150 struct nft_offload_reg *reg = &ctx->regs[priv->dreg];
bd8699e9 151
83c156d3 152 if (memcmp(&priv->xor, &zero, sizeof(priv->xor)) ||
de2a6052 153 priv->sreg != priv->dreg || priv->len != reg->len)
bd8699e9
PNA
154 return -EOPNOTSUPP;
155
de2a6052 156 memcpy(&reg->mask, &priv->mask, sizeof(priv->mask));
bd8699e9
PNA
157
158 return 0;
159}
160
ef1f7df9
PM
161static const struct nft_expr_ops nft_bitwise_ops = {
162 .type = &nft_bitwise_type,
96518518 163 .size = NFT_EXPR_SIZE(sizeof(struct nft_bitwise)),
96518518
PM
164 .eval = nft_bitwise_eval,
165 .init = nft_bitwise_init,
166 .dump = nft_bitwise_dump,
bd8699e9 167 .offload = nft_bitwise_offload,
ef1f7df9
PM
168};
169
4e24877e 170struct nft_expr_type nft_bitwise_type __read_mostly = {
ef1f7df9
PM
171 .name = "bitwise",
172 .ops = &nft_bitwise_ops,
96518518
PM
173 .policy = nft_bitwise_policy,
174 .maxattr = NFTA_BITWISE_MAX,
ef1f7df9 175 .owner = THIS_MODULE,
96518518 176};