xref: /openbmc/linux/net/netfilter/nft_byteorder.c (revision 013deed3)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
296518518SPatrick McHardy /*
3ef1f7df9SPatrick McHardy  * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
496518518SPatrick McHardy  *
596518518SPatrick McHardy  * Development of this code funded by Astaro AG (http://www.astaro.com/)
696518518SPatrick McHardy  */
796518518SPatrick McHardy 
8ce1e7989SFlorian Westphal #include <asm/unaligned.h>
996518518SPatrick McHardy #include <linux/kernel.h>
1096518518SPatrick McHardy #include <linux/init.h>
1196518518SPatrick McHardy #include <linux/module.h>
1296518518SPatrick McHardy #include <linux/netlink.h>
1396518518SPatrick McHardy #include <linux/netfilter.h>
1496518518SPatrick McHardy #include <linux/netfilter/nf_tables.h>
1596518518SPatrick McHardy #include <net/netfilter/nf_tables_core.h>
1696518518SPatrick McHardy #include <net/netfilter/nf_tables.h>
1796518518SPatrick McHardy 
1896518518SPatrick McHardy struct nft_byteorder {
194f16d25cSPablo Neira Ayuso 	u8			sreg;
20345023b0SPablo Neira Ayuso 	u8			dreg;
2196518518SPatrick McHardy 	enum nft_byteorder_ops	op:8;
2296518518SPatrick McHardy 	u8			len;
2396518518SPatrick McHardy 	u8			size;
2496518518SPatrick McHardy };
2596518518SPatrick McHardy 
nft_byteorder_eval(const struct nft_expr * expr,struct nft_regs * regs,const struct nft_pktinfo * pkt)2610870dd8SFlorian Westphal void nft_byteorder_eval(const struct nft_expr *expr,
27a55e22e9SPatrick McHardy 			struct nft_regs *regs,
2896518518SPatrick McHardy 			const struct nft_pktinfo *pkt)
2996518518SPatrick McHardy {
3096518518SPatrick McHardy 	const struct nft_byteorder *priv = nft_expr_priv(expr);
3149499c3eSPatrick McHardy 	u32 *src = &regs->data[priv->sreg];
3249499c3eSPatrick McHardy 	u32 *dst = &regs->data[priv->dreg];
33caf3ef74SThadeu Lima de Souza Cascardo 	u16 *s16, *d16;
3496518518SPatrick McHardy 	unsigned int i;
3596518518SPatrick McHardy 
36caf3ef74SThadeu Lima de Souza Cascardo 	s16 = (void *)src;
37caf3ef74SThadeu Lima de Souza Cascardo 	d16 = (void *)dst;
3896518518SPatrick McHardy 
3996518518SPatrick McHardy 	switch (priv->size) {
40ce1e7989SFlorian Westphal 	case 8: {
41*013deed3SDan Carpenter 		u64 *dst64 = (void *)dst;
42ce1e7989SFlorian Westphal 		u64 src64;
43ce1e7989SFlorian Westphal 
44ce1e7989SFlorian Westphal 		switch (priv->op) {
45ce1e7989SFlorian Westphal 		case NFT_BYTEORDER_NTOH:
46ce1e7989SFlorian Westphal 			for (i = 0; i < priv->len / 8; i++) {
47a1b840adSAnder Juaristi 				src64 = nft_reg_load64(&src[i]);
48*013deed3SDan Carpenter 				nft_reg_store64(&dst64[i],
49d86473bfSFlorian Westphal 						be64_to_cpu((__force __be64)src64));
50ce1e7989SFlorian Westphal 			}
51ce1e7989SFlorian Westphal 			break;
52ce1e7989SFlorian Westphal 		case NFT_BYTEORDER_HTON:
53ce1e7989SFlorian Westphal 			for (i = 0; i < priv->len / 8; i++) {
54a1b840adSAnder Juaristi 				src64 = (__force __u64)
55a1b840adSAnder Juaristi 					cpu_to_be64(nft_reg_load64(&src[i]));
56*013deed3SDan Carpenter 				nft_reg_store64(&dst64[i], src64);
57ce1e7989SFlorian Westphal 			}
58ce1e7989SFlorian Westphal 			break;
59ce1e7989SFlorian Westphal 		}
60ce1e7989SFlorian Westphal 		break;
61ce1e7989SFlorian Westphal 	}
6296518518SPatrick McHardy 	case 4:
6396518518SPatrick McHardy 		switch (priv->op) {
6496518518SPatrick McHardy 		case NFT_BYTEORDER_NTOH:
6596518518SPatrick McHardy 			for (i = 0; i < priv->len / 4; i++)
66caf3ef74SThadeu Lima de Souza Cascardo 				dst[i] = ntohl((__force __be32)src[i]);
6796518518SPatrick McHardy 			break;
6896518518SPatrick McHardy 		case NFT_BYTEORDER_HTON:
6996518518SPatrick McHardy 			for (i = 0; i < priv->len / 4; i++)
70caf3ef74SThadeu Lima de Souza Cascardo 				dst[i] = (__force __u32)htonl(src[i]);
7196518518SPatrick McHardy 			break;
7296518518SPatrick McHardy 		}
7396518518SPatrick McHardy 		break;
7496518518SPatrick McHardy 	case 2:
7596518518SPatrick McHardy 		switch (priv->op) {
7696518518SPatrick McHardy 		case NFT_BYTEORDER_NTOH:
7796518518SPatrick McHardy 			for (i = 0; i < priv->len / 2; i++)
78caf3ef74SThadeu Lima de Souza Cascardo 				d16[i] = ntohs((__force __be16)s16[i]);
7996518518SPatrick McHardy 			break;
8096518518SPatrick McHardy 		case NFT_BYTEORDER_HTON:
8196518518SPatrick McHardy 			for (i = 0; i < priv->len / 2; i++)
82caf3ef74SThadeu Lima de Souza Cascardo 				d16[i] = (__force __u16)htons(s16[i]);
8396518518SPatrick McHardy 			break;
8496518518SPatrick McHardy 		}
8596518518SPatrick McHardy 		break;
8696518518SPatrick McHardy 	}
8796518518SPatrick McHardy }
8896518518SPatrick McHardy 
8996518518SPatrick McHardy static const struct nla_policy nft_byteorder_policy[NFTA_BYTEORDER_MAX + 1] = {
9096518518SPatrick McHardy 	[NFTA_BYTEORDER_SREG]	= { .type = NLA_U32 },
9196518518SPatrick McHardy 	[NFTA_BYTEORDER_DREG]	= { .type = NLA_U32 },
92a412dbf4SFlorian Westphal 	[NFTA_BYTEORDER_OP]	= NLA_POLICY_MAX(NLA_BE32, 255),
93a412dbf4SFlorian Westphal 	[NFTA_BYTEORDER_LEN]	= NLA_POLICY_MAX(NLA_BE32, 255),
94a412dbf4SFlorian Westphal 	[NFTA_BYTEORDER_SIZE]	= NLA_POLICY_MAX(NLA_BE32, 255),
9596518518SPatrick McHardy };
9696518518SPatrick McHardy 
nft_byteorder_init(const struct nft_ctx * ctx,const struct nft_expr * expr,const struct nlattr * const tb[])9796518518SPatrick McHardy static int nft_byteorder_init(const struct nft_ctx *ctx,
9896518518SPatrick McHardy 			      const struct nft_expr *expr,
9996518518SPatrick McHardy 			      const struct nlattr * const tb[])
10096518518SPatrick McHardy {
10196518518SPatrick McHardy 	struct nft_byteorder *priv = nft_expr_priv(expr);
10236b701faSLaura Garcia Liebana 	u32 size, len;
10396518518SPatrick McHardy 	int err;
10496518518SPatrick McHardy 
10596518518SPatrick McHardy 	if (tb[NFTA_BYTEORDER_SREG] == NULL ||
10696518518SPatrick McHardy 	    tb[NFTA_BYTEORDER_DREG] == NULL ||
10796518518SPatrick McHardy 	    tb[NFTA_BYTEORDER_LEN] == NULL ||
10896518518SPatrick McHardy 	    tb[NFTA_BYTEORDER_SIZE] == NULL ||
10996518518SPatrick McHardy 	    tb[NFTA_BYTEORDER_OP] == NULL)
11096518518SPatrick McHardy 		return -EINVAL;
11196518518SPatrick McHardy 
11296518518SPatrick McHardy 	priv->op = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_OP]));
11396518518SPatrick McHardy 	switch (priv->op) {
11496518518SPatrick McHardy 	case NFT_BYTEORDER_NTOH:
11596518518SPatrick McHardy 	case NFT_BYTEORDER_HTON:
11696518518SPatrick McHardy 		break;
11796518518SPatrick McHardy 	default:
11896518518SPatrick McHardy 		return -EINVAL;
11996518518SPatrick McHardy 	}
12096518518SPatrick McHardy 
12136b701faSLaura Garcia Liebana 	err = nft_parse_u32_check(tb[NFTA_BYTEORDER_SIZE], U8_MAX, &size);
12236b701faSLaura Garcia Liebana 	if (err < 0)
12336b701faSLaura Garcia Liebana 		return err;
12436b701faSLaura Garcia Liebana 
12536b701faSLaura Garcia Liebana 	priv->size = size;
12636b701faSLaura Garcia Liebana 
12796518518SPatrick McHardy 	switch (priv->size) {
12896518518SPatrick McHardy 	case 2:
12996518518SPatrick McHardy 	case 4:
130ce1e7989SFlorian Westphal 	case 8:
13196518518SPatrick McHardy 		break;
13296518518SPatrick McHardy 	default:
13396518518SPatrick McHardy 		return -EINVAL;
13496518518SPatrick McHardy 	}
13596518518SPatrick McHardy 
13636b701faSLaura Garcia Liebana 	err = nft_parse_u32_check(tb[NFTA_BYTEORDER_LEN], U8_MAX, &len);
13736b701faSLaura Garcia Liebana 	if (err < 0)
13836b701faSLaura Garcia Liebana 		return err;
13936b701faSLaura Garcia Liebana 
14036b701faSLaura Garcia Liebana 	priv->len = len;
14136b701faSLaura Garcia Liebana 
1424f16d25cSPablo Neira Ayuso 	err = nft_parse_register_load(tb[NFTA_BYTEORDER_SREG], &priv->sreg,
1434f16d25cSPablo Neira Ayuso 				      priv->len);
14445d9bcdaSPatrick McHardy 	if (err < 0)
14545d9bcdaSPatrick McHardy 		return err;
14645d9bcdaSPatrick McHardy 
147345023b0SPablo Neira Ayuso 	return nft_parse_register_store(ctx, tb[NFTA_BYTEORDER_DREG],
148345023b0SPablo Neira Ayuso 					&priv->dreg, NULL, NFT_DATA_VALUE,
149345023b0SPablo Neira Ayuso 					priv->len);
15096518518SPatrick McHardy }
15196518518SPatrick McHardy 
nft_byteorder_dump(struct sk_buff * skb,const struct nft_expr * expr,bool reset)1527d34aa3eSPhil Sutter static int nft_byteorder_dump(struct sk_buff *skb,
1537d34aa3eSPhil Sutter 			      const struct nft_expr *expr, bool reset)
15496518518SPatrick McHardy {
15596518518SPatrick McHardy 	const struct nft_byteorder *priv = nft_expr_priv(expr);
15696518518SPatrick McHardy 
157b1c96ed3SPatrick McHardy 	if (nft_dump_register(skb, NFTA_BYTEORDER_SREG, priv->sreg))
15896518518SPatrick McHardy 		goto nla_put_failure;
159b1c96ed3SPatrick McHardy 	if (nft_dump_register(skb, NFTA_BYTEORDER_DREG, priv->dreg))
16096518518SPatrick McHardy 		goto nla_put_failure;
16196518518SPatrick McHardy 	if (nla_put_be32(skb, NFTA_BYTEORDER_OP, htonl(priv->op)))
16296518518SPatrick McHardy 		goto nla_put_failure;
16396518518SPatrick McHardy 	if (nla_put_be32(skb, NFTA_BYTEORDER_LEN, htonl(priv->len)))
16496518518SPatrick McHardy 		goto nla_put_failure;
16596518518SPatrick McHardy 	if (nla_put_be32(skb, NFTA_BYTEORDER_SIZE, htonl(priv->size)))
16696518518SPatrick McHardy 		goto nla_put_failure;
16796518518SPatrick McHardy 	return 0;
16896518518SPatrick McHardy 
16996518518SPatrick McHardy nla_put_failure:
17096518518SPatrick McHardy 	return -1;
17196518518SPatrick McHardy }
17296518518SPatrick McHardy 
nft_byteorder_reduce(struct nft_regs_track * track,const struct nft_expr * expr)173f459bfd4SPablo Neira Ayuso static bool nft_byteorder_reduce(struct nft_regs_track *track,
174f459bfd4SPablo Neira Ayuso 				 const struct nft_expr *expr)
175f459bfd4SPablo Neira Ayuso {
176f459bfd4SPablo Neira Ayuso 	struct nft_byteorder *priv = nft_expr_priv(expr);
177f459bfd4SPablo Neira Ayuso 
17834cc9e52SPablo Neira Ayuso 	nft_reg_track_cancel(track, priv->dreg, priv->len);
179f459bfd4SPablo Neira Ayuso 
180f459bfd4SPablo Neira Ayuso 	return false;
181f459bfd4SPablo Neira Ayuso }
182f459bfd4SPablo Neira Ayuso 
183ef1f7df9SPatrick McHardy static const struct nft_expr_ops nft_byteorder_ops = {
184ef1f7df9SPatrick McHardy 	.type		= &nft_byteorder_type,
18596518518SPatrick McHardy 	.size		= NFT_EXPR_SIZE(sizeof(struct nft_byteorder)),
18696518518SPatrick McHardy 	.eval		= nft_byteorder_eval,
18796518518SPatrick McHardy 	.init		= nft_byteorder_init,
18896518518SPatrick McHardy 	.dump		= nft_byteorder_dump,
189f459bfd4SPablo Neira Ayuso 	.reduce		= nft_byteorder_reduce,
190ef1f7df9SPatrick McHardy };
191ef1f7df9SPatrick McHardy 
1924e24877eSLiping Zhang struct nft_expr_type nft_byteorder_type __read_mostly = {
193ef1f7df9SPatrick McHardy 	.name		= "byteorder",
194ef1f7df9SPatrick McHardy 	.ops		= &nft_byteorder_ops,
19596518518SPatrick McHardy 	.policy		= nft_byteorder_policy,
19696518518SPatrick McHardy 	.maxattr	= NFTA_BYTEORDER_MAX,
197ef1f7df9SPatrick McHardy 	.owner		= THIS_MODULE,
19896518518SPatrick McHardy };
199