0001
0002
0003
0004
0005
0006
0007
0008 #include <asm/unaligned.h>
0009 #include <linux/kernel.h>
0010 #include <linux/init.h>
0011 #include <linux/module.h>
0012 #include <linux/netlink.h>
0013 #include <linux/netfilter.h>
0014 #include <linux/netfilter/nf_tables.h>
0015 #include <net/netfilter/nf_tables_core.h>
0016 #include <net/netfilter/nf_tables.h>
0017
0018 struct nft_byteorder {
0019 u8 sreg;
0020 u8 dreg;
0021 enum nft_byteorder_ops op:8;
0022 u8 len;
0023 u8 size;
0024 };
0025
0026 void nft_byteorder_eval(const struct nft_expr *expr,
0027 struct nft_regs *regs,
0028 const struct nft_pktinfo *pkt)
0029 {
0030 const struct nft_byteorder *priv = nft_expr_priv(expr);
0031 u32 *src = ®s->data[priv->sreg];
0032 u32 *dst = ®s->data[priv->dreg];
0033 union { u32 u32; u16 u16; } *s, *d;
0034 unsigned int i;
0035
0036 s = (void *)src;
0037 d = (void *)dst;
0038
0039 switch (priv->size) {
0040 case 8: {
0041 u64 src64;
0042
0043 switch (priv->op) {
0044 case NFT_BYTEORDER_NTOH:
0045 for (i = 0; i < priv->len / 8; i++) {
0046 src64 = nft_reg_load64(&src[i]);
0047 nft_reg_store64(&dst[i],
0048 be64_to_cpu((__force __be64)src64));
0049 }
0050 break;
0051 case NFT_BYTEORDER_HTON:
0052 for (i = 0; i < priv->len / 8; i++) {
0053 src64 = (__force __u64)
0054 cpu_to_be64(nft_reg_load64(&src[i]));
0055 nft_reg_store64(&dst[i], src64);
0056 }
0057 break;
0058 }
0059 break;
0060 }
0061 case 4:
0062 switch (priv->op) {
0063 case NFT_BYTEORDER_NTOH:
0064 for (i = 0; i < priv->len / 4; i++)
0065 d[i].u32 = ntohl((__force __be32)s[i].u32);
0066 break;
0067 case NFT_BYTEORDER_HTON:
0068 for (i = 0; i < priv->len / 4; i++)
0069 d[i].u32 = (__force __u32)htonl(s[i].u32);
0070 break;
0071 }
0072 break;
0073 case 2:
0074 switch (priv->op) {
0075 case NFT_BYTEORDER_NTOH:
0076 for (i = 0; i < priv->len / 2; i++)
0077 d[i].u16 = ntohs((__force __be16)s[i].u16);
0078 break;
0079 case NFT_BYTEORDER_HTON:
0080 for (i = 0; i < priv->len / 2; i++)
0081 d[i].u16 = (__force __u16)htons(s[i].u16);
0082 break;
0083 }
0084 break;
0085 }
0086 }
0087
0088 static const struct nla_policy nft_byteorder_policy[NFTA_BYTEORDER_MAX + 1] = {
0089 [NFTA_BYTEORDER_SREG] = { .type = NLA_U32 },
0090 [NFTA_BYTEORDER_DREG] = { .type = NLA_U32 },
0091 [NFTA_BYTEORDER_OP] = { .type = NLA_U32 },
0092 [NFTA_BYTEORDER_LEN] = { .type = NLA_U32 },
0093 [NFTA_BYTEORDER_SIZE] = { .type = NLA_U32 },
0094 };
0095
0096 static int nft_byteorder_init(const struct nft_ctx *ctx,
0097 const struct nft_expr *expr,
0098 const struct nlattr * const tb[])
0099 {
0100 struct nft_byteorder *priv = nft_expr_priv(expr);
0101 u32 size, len;
0102 int err;
0103
0104 if (tb[NFTA_BYTEORDER_SREG] == NULL ||
0105 tb[NFTA_BYTEORDER_DREG] == NULL ||
0106 tb[NFTA_BYTEORDER_LEN] == NULL ||
0107 tb[NFTA_BYTEORDER_SIZE] == NULL ||
0108 tb[NFTA_BYTEORDER_OP] == NULL)
0109 return -EINVAL;
0110
0111 priv->op = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_OP]));
0112 switch (priv->op) {
0113 case NFT_BYTEORDER_NTOH:
0114 case NFT_BYTEORDER_HTON:
0115 break;
0116 default:
0117 return -EINVAL;
0118 }
0119
0120 err = nft_parse_u32_check(tb[NFTA_BYTEORDER_SIZE], U8_MAX, &size);
0121 if (err < 0)
0122 return err;
0123
0124 priv->size = size;
0125
0126 switch (priv->size) {
0127 case 2:
0128 case 4:
0129 case 8:
0130 break;
0131 default:
0132 return -EINVAL;
0133 }
0134
0135 err = nft_parse_u32_check(tb[NFTA_BYTEORDER_LEN], U8_MAX, &len);
0136 if (err < 0)
0137 return err;
0138
0139 priv->len = len;
0140
0141 err = nft_parse_register_load(tb[NFTA_BYTEORDER_SREG], &priv->sreg,
0142 priv->len);
0143 if (err < 0)
0144 return err;
0145
0146 return nft_parse_register_store(ctx, tb[NFTA_BYTEORDER_DREG],
0147 &priv->dreg, NULL, NFT_DATA_VALUE,
0148 priv->len);
0149 }
0150
0151 static int nft_byteorder_dump(struct sk_buff *skb, const struct nft_expr *expr)
0152 {
0153 const struct nft_byteorder *priv = nft_expr_priv(expr);
0154
0155 if (nft_dump_register(skb, NFTA_BYTEORDER_SREG, priv->sreg))
0156 goto nla_put_failure;
0157 if (nft_dump_register(skb, NFTA_BYTEORDER_DREG, priv->dreg))
0158 goto nla_put_failure;
0159 if (nla_put_be32(skb, NFTA_BYTEORDER_OP, htonl(priv->op)))
0160 goto nla_put_failure;
0161 if (nla_put_be32(skb, NFTA_BYTEORDER_LEN, htonl(priv->len)))
0162 goto nla_put_failure;
0163 if (nla_put_be32(skb, NFTA_BYTEORDER_SIZE, htonl(priv->size)))
0164 goto nla_put_failure;
0165 return 0;
0166
0167 nla_put_failure:
0168 return -1;
0169 }
0170
0171 static bool nft_byteorder_reduce(struct nft_regs_track *track,
0172 const struct nft_expr *expr)
0173 {
0174 struct nft_byteorder *priv = nft_expr_priv(expr);
0175
0176 nft_reg_track_cancel(track, priv->dreg, priv->len);
0177
0178 return false;
0179 }
0180
0181 static const struct nft_expr_ops nft_byteorder_ops = {
0182 .type = &nft_byteorder_type,
0183 .size = NFT_EXPR_SIZE(sizeof(struct nft_byteorder)),
0184 .eval = nft_byteorder_eval,
0185 .init = nft_byteorder_init,
0186 .dump = nft_byteorder_dump,
0187 .reduce = nft_byteorder_reduce,
0188 };
0189
0190 struct nft_expr_type nft_byteorder_type __read_mostly = {
0191 .name = "byteorder",
0192 .ops = &nft_byteorder_ops,
0193 .policy = nft_byteorder_policy,
0194 .maxattr = NFTA_BYTEORDER_MAX,
0195 .owner = THIS_MODULE,
0196 };