xref: /openbmc/linux/net/netfilter/nft_bitwise.c (revision 068ac0db)
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.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.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 };
164