linux/net/netfilter/nft_byteorder.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 as
   6 * published by the Free Software Foundation.
   7 *
   8 * Development of this code funded by Astaro AG (http://www.astaro.com/)
   9 */
  10
  11#include <asm/unaligned.h>
  12#include <linux/kernel.h>
  13#include <linux/init.h>
  14#include <linux/module.h>
  15#include <linux/netlink.h>
  16#include <linux/netfilter.h>
  17#include <linux/netfilter/nf_tables.h>
  18#include <net/netfilter/nf_tables_core.h>
  19#include <net/netfilter/nf_tables.h>
  20
  21struct nft_byteorder {
  22        enum nft_registers      sreg:8;
  23        enum nft_registers      dreg:8;
  24        enum nft_byteorder_ops  op:8;
  25        u8                      len;
  26        u8                      size;
  27};
  28
  29static void nft_byteorder_eval(const struct nft_expr *expr,
  30                               struct nft_regs *regs,
  31                               const struct nft_pktinfo *pkt)
  32{
  33        const struct nft_byteorder *priv = nft_expr_priv(expr);
  34        u32 *src = &regs->data[priv->sreg];
  35        u32 *dst = &regs->data[priv->dreg];
  36        union { u32 u32; u16 u16; } *s, *d;
  37        unsigned int i;
  38
  39        s = (void *)src;
  40        d = (void *)dst;
  41
  42        switch (priv->size) {
  43        case 8: {
  44                u64 src64;
  45
  46                switch (priv->op) {
  47                case NFT_BYTEORDER_NTOH:
  48                        for (i = 0; i < priv->len / 8; i++) {
  49                                src64 = get_unaligned((u64 *)&src[i]);
  50                                put_unaligned_be64(src64, &dst[i]);
  51                        }
  52                        break;
  53                case NFT_BYTEORDER_HTON:
  54                        for (i = 0; i < priv->len / 8; i++) {
  55                                src64 = get_unaligned_be64(&src[i]);
  56                                put_unaligned(src64, (u64 *)&dst[i]);
  57                        }
  58                        break;
  59                }
  60                break;
  61        }
  62        case 4:
  63                switch (priv->op) {
  64                case NFT_BYTEORDER_NTOH:
  65                        for (i = 0; i < priv->len / 4; i++)
  66                                d[i].u32 = ntohl((__force __be32)s[i].u32);
  67                        break;
  68                case NFT_BYTEORDER_HTON:
  69                        for (i = 0; i < priv->len / 4; i++)
  70                                d[i].u32 = (__force __u32)htonl(s[i].u32);
  71                        break;
  72                }
  73                break;
  74        case 2:
  75                switch (priv->op) {
  76                case NFT_BYTEORDER_NTOH:
  77                        for (i = 0; i < priv->len / 2; i++)
  78                                d[i].u16 = ntohs((__force __be16)s[i].u16);
  79                        break;
  80                case NFT_BYTEORDER_HTON:
  81                        for (i = 0; i < priv->len / 2; i++)
  82                                d[i].u16 = (__force __u16)htons(s[i].u16);
  83                        break;
  84                }
  85                break;
  86        }
  87}
  88
  89static const struct nla_policy nft_byteorder_policy[NFTA_BYTEORDER_MAX + 1] = {
  90        [NFTA_BYTEORDER_SREG]   = { .type = NLA_U32 },
  91        [NFTA_BYTEORDER_DREG]   = { .type = NLA_U32 },
  92        [NFTA_BYTEORDER_OP]     = { .type = NLA_U32 },
  93        [NFTA_BYTEORDER_LEN]    = { .type = NLA_U32 },
  94        [NFTA_BYTEORDER_SIZE]   = { .type = NLA_U32 },
  95};
  96
  97static int nft_byteorder_init(const struct nft_ctx *ctx,
  98                              const struct nft_expr *expr,
  99                              const struct nlattr * const tb[])
 100{
 101        struct nft_byteorder *priv = nft_expr_priv(expr);
 102        int err;
 103
 104        if (tb[NFTA_BYTEORDER_SREG] == NULL ||
 105            tb[NFTA_BYTEORDER_DREG] == NULL ||
 106            tb[NFTA_BYTEORDER_LEN] == NULL ||
 107            tb[NFTA_BYTEORDER_SIZE] == NULL ||
 108            tb[NFTA_BYTEORDER_OP] == NULL)
 109                return -EINVAL;
 110
 111        priv->op = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_OP]));
 112        switch (priv->op) {
 113        case NFT_BYTEORDER_NTOH:
 114        case NFT_BYTEORDER_HTON:
 115                break;
 116        default:
 117                return -EINVAL;
 118        }
 119
 120        priv->size = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_SIZE]));
 121        switch (priv->size) {
 122        case 2:
 123        case 4:
 124        case 8:
 125                break;
 126        default:
 127                return -EINVAL;
 128        }
 129
 130        priv->sreg = nft_parse_register(tb[NFTA_BYTEORDER_SREG]);
 131        priv->len  = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_LEN]));
 132        err = nft_validate_register_load(priv->sreg, priv->len);
 133        if (err < 0)
 134                return err;
 135
 136        priv->dreg = nft_parse_register(tb[NFTA_BYTEORDER_DREG]);
 137        return nft_validate_register_store(ctx, priv->dreg, NULL,
 138                                           NFT_DATA_VALUE, priv->len);
 139}
 140
 141static int nft_byteorder_dump(struct sk_buff *skb, const struct nft_expr *expr)
 142{
 143        const struct nft_byteorder *priv = nft_expr_priv(expr);
 144
 145        if (nft_dump_register(skb, NFTA_BYTEORDER_SREG, priv->sreg))
 146                goto nla_put_failure;
 147        if (nft_dump_register(skb, NFTA_BYTEORDER_DREG, priv->dreg))
 148                goto nla_put_failure;
 149        if (nla_put_be32(skb, NFTA_BYTEORDER_OP, htonl(priv->op)))
 150                goto nla_put_failure;
 151        if (nla_put_be32(skb, NFTA_BYTEORDER_LEN, htonl(priv->len)))
 152                goto nla_put_failure;
 153        if (nla_put_be32(skb, NFTA_BYTEORDER_SIZE, htonl(priv->size)))
 154                goto nla_put_failure;
 155        return 0;
 156
 157nla_put_failure:
 158        return -1;
 159}
 160
 161static struct nft_expr_type nft_byteorder_type;
 162static const struct nft_expr_ops nft_byteorder_ops = {
 163        .type           = &nft_byteorder_type,
 164        .size           = NFT_EXPR_SIZE(sizeof(struct nft_byteorder)),
 165        .eval           = nft_byteorder_eval,
 166        .init           = nft_byteorder_init,
 167        .dump           = nft_byteorder_dump,
 168};
 169
 170static struct nft_expr_type nft_byteorder_type __read_mostly = {
 171        .name           = "byteorder",
 172        .ops            = &nft_byteorder_ops,
 173        .policy         = nft_byteorder_policy,
 174        .maxattr        = NFTA_BYTEORDER_MAX,
 175        .owner          = THIS_MODULE,
 176};
 177
 178int __init nft_byteorder_module_init(void)
 179{
 180        return nft_register_expr(&nft_byteorder_type);
 181}
 182
 183void nft_byteorder_module_exit(void)
 184{
 185        nft_unregister_expr(&nft_byteorder_type);
 186}
 187