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        u32 size, len;
 103        int err;
 104
 105        if (tb[NFTA_BYTEORDER_SREG] == NULL ||
 106            tb[NFTA_BYTEORDER_DREG] == NULL ||
 107            tb[NFTA_BYTEORDER_LEN] == NULL ||
 108            tb[NFTA_BYTEORDER_SIZE] == NULL ||
 109            tb[NFTA_BYTEORDER_OP] == NULL)
 110                return -EINVAL;
 111
 112        priv->op = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_OP]));
 113        switch (priv->op) {
 114        case NFT_BYTEORDER_NTOH:
 115        case NFT_BYTEORDER_HTON:
 116                break;
 117        default:
 118                return -EINVAL;
 119        }
 120
 121        err = nft_parse_u32_check(tb[NFTA_BYTEORDER_SIZE], U8_MAX, &size);
 122        if (err < 0)
 123                return err;
 124
 125        priv->size = size;
 126
 127        switch (priv->size) {
 128        case 2:
 129        case 4:
 130        case 8:
 131                break;
 132        default:
 133                return -EINVAL;
 134        }
 135
 136        priv->sreg = nft_parse_register(tb[NFTA_BYTEORDER_SREG]);
 137        err = nft_parse_u32_check(tb[NFTA_BYTEORDER_LEN], U8_MAX, &len);
 138        if (err < 0)
 139                return err;
 140
 141        priv->len = len;
 142
 143        err = nft_validate_register_load(priv->sreg, priv->len);
 144        if (err < 0)
 145                return err;
 146
 147        priv->dreg = nft_parse_register(tb[NFTA_BYTEORDER_DREG]);
 148        return nft_validate_register_store(ctx, priv->dreg, NULL,
 149                                           NFT_DATA_VALUE, priv->len);
 150}
 151
 152static int nft_byteorder_dump(struct sk_buff *skb, const struct nft_expr *expr)
 153{
 154        const struct nft_byteorder *priv = nft_expr_priv(expr);
 155
 156        if (nft_dump_register(skb, NFTA_BYTEORDER_SREG, priv->sreg))
 157                goto nla_put_failure;
 158        if (nft_dump_register(skb, NFTA_BYTEORDER_DREG, priv->dreg))
 159                goto nla_put_failure;
 160        if (nla_put_be32(skb, NFTA_BYTEORDER_OP, htonl(priv->op)))
 161                goto nla_put_failure;
 162        if (nla_put_be32(skb, NFTA_BYTEORDER_LEN, htonl(priv->len)))
 163                goto nla_put_failure;
 164        if (nla_put_be32(skb, NFTA_BYTEORDER_SIZE, htonl(priv->size)))
 165                goto nla_put_failure;
 166        return 0;
 167
 168nla_put_failure:
 169        return -1;
 170}
 171
 172static struct nft_expr_type nft_byteorder_type;
 173static const struct nft_expr_ops nft_byteorder_ops = {
 174        .type           = &nft_byteorder_type,
 175        .size           = NFT_EXPR_SIZE(sizeof(struct nft_byteorder)),
 176        .eval           = nft_byteorder_eval,
 177        .init           = nft_byteorder_init,
 178        .dump           = nft_byteorder_dump,
 179};
 180
 181static struct nft_expr_type nft_byteorder_type __read_mostly = {
 182        .name           = "byteorder",
 183        .ops            = &nft_byteorder_ops,
 184        .policy         = nft_byteorder_policy,
 185        .maxattr        = NFTA_BYTEORDER_MAX,
 186        .owner          = THIS_MODULE,
 187};
 188
 189int __init nft_byteorder_module_init(void)
 190{
 191        return nft_register_expr(&nft_byteorder_type);
 192}
 193
 194void nft_byteorder_module_exit(void)
 195{
 196        nft_unregister_expr(&nft_byteorder_type);
 197}
 198