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 <linux/kernel.h> 12#include <linux/init.h> 13#include <linux/module.h> 14#include <linux/netlink.h> 15#include <linux/netfilter.h> 16#include <linux/netfilter/nf_tables.h> 17#include <net/netfilter/nf_tables_core.h> 18#include <net/netfilter/nf_tables.h> 19 20struct nft_byteorder { 21 enum nft_registers sreg:8; 22 enum nft_registers dreg:8; 23 enum nft_byteorder_ops op:8; 24 u8 len; 25 u8 size; 26}; 27 28static void nft_byteorder_eval(const struct nft_expr *expr, 29 struct nft_regs *regs, 30 const struct nft_pktinfo *pkt) 31{ 32 const struct nft_byteorder *priv = nft_expr_priv(expr); 33 u32 *src = ®s->data[priv->sreg]; 34 u32 *dst = ®s->data[priv->dreg]; 35 union { u32 u32; u16 u16; } *s, *d; 36 unsigned int i; 37 38 s = (void *)src; 39 d = (void *)dst; 40 41 switch (priv->size) { 42 case 4: 43 switch (priv->op) { 44 case NFT_BYTEORDER_NTOH: 45 for (i = 0; i < priv->len / 4; i++) 46 d[i].u32 = ntohl((__force __be32)s[i].u32); 47 break; 48 case NFT_BYTEORDER_HTON: 49 for (i = 0; i < priv->len / 4; i++) 50 d[i].u32 = (__force __u32)htonl(s[i].u32); 51 break; 52 } 53 break; 54 case 2: 55 switch (priv->op) { 56 case NFT_BYTEORDER_NTOH: 57 for (i = 0; i < priv->len / 2; i++) 58 d[i].u16 = ntohs((__force __be16)s[i].u16); 59 break; 60 case NFT_BYTEORDER_HTON: 61 for (i = 0; i < priv->len / 2; i++) 62 d[i].u16 = (__force __u16)htons(s[i].u16); 63 break; 64 } 65 break; 66 } 67} 68 69static const struct nla_policy nft_byteorder_policy[NFTA_BYTEORDER_MAX + 1] = { 70 [NFTA_BYTEORDER_SREG] = { .type = NLA_U32 }, 71 [NFTA_BYTEORDER_DREG] = { .type = NLA_U32 }, 72 [NFTA_BYTEORDER_OP] = { .type = NLA_U32 }, 73 [NFTA_BYTEORDER_LEN] = { .type = NLA_U32 }, 74 [NFTA_BYTEORDER_SIZE] = { .type = NLA_U32 }, 75}; 76 77static int nft_byteorder_init(const struct nft_ctx *ctx, 78 const struct nft_expr *expr, 79 const struct nlattr * const tb[]) 80{ 81 struct nft_byteorder *priv = nft_expr_priv(expr); 82 int err; 83 84 if (tb[NFTA_BYTEORDER_SREG] == NULL || 85 tb[NFTA_BYTEORDER_DREG] == NULL || 86 tb[NFTA_BYTEORDER_LEN] == NULL || 87 tb[NFTA_BYTEORDER_SIZE] == NULL || 88 tb[NFTA_BYTEORDER_OP] == NULL) 89 return -EINVAL; 90 91 priv->op = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_OP])); 92 switch (priv->op) { 93 case NFT_BYTEORDER_NTOH: 94 case NFT_BYTEORDER_HTON: 95 break; 96 default: 97 return -EINVAL; 98 } 99 100 priv->size = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_SIZE])); 101 switch (priv->size) { 102 case 2: 103 case 4: 104 break; 105 default: 106 return -EINVAL; 107 } 108 109 priv->sreg = nft_parse_register(tb[NFTA_BYTEORDER_SREG]); 110 priv->len = ntohl(nla_get_be32(tb[NFTA_BYTEORDER_LEN])); 111 err = nft_validate_register_load(priv->sreg, priv->len); 112 if (err < 0) 113 return err; 114 115 priv->dreg = nft_parse_register(tb[NFTA_BYTEORDER_DREG]); 116 return nft_validate_register_store(ctx, priv->dreg, NULL, 117 NFT_DATA_VALUE, priv->len); 118} 119 120static int nft_byteorder_dump(struct sk_buff *skb, const struct nft_expr *expr) 121{ 122 const struct nft_byteorder *priv = nft_expr_priv(expr); 123 124 if (nft_dump_register(skb, NFTA_BYTEORDER_SREG, priv->sreg)) 125 goto nla_put_failure; 126 if (nft_dump_register(skb, NFTA_BYTEORDER_DREG, priv->dreg)) 127 goto nla_put_failure; 128 if (nla_put_be32(skb, NFTA_BYTEORDER_OP, htonl(priv->op))) 129 goto nla_put_failure; 130 if (nla_put_be32(skb, NFTA_BYTEORDER_LEN, htonl(priv->len))) 131 goto nla_put_failure; 132 if (nla_put_be32(skb, NFTA_BYTEORDER_SIZE, htonl(priv->size))) 133 goto nla_put_failure; 134 return 0; 135 136nla_put_failure: 137 return -1; 138} 139 140static struct nft_expr_type nft_byteorder_type; 141static const struct nft_expr_ops nft_byteorder_ops = { 142 .type = &nft_byteorder_type, 143 .size = NFT_EXPR_SIZE(sizeof(struct nft_byteorder)), 144 .eval = nft_byteorder_eval, 145 .init = nft_byteorder_init, 146 .dump = nft_byteorder_dump, 147}; 148 149static struct nft_expr_type nft_byteorder_type __read_mostly = { 150 .name = "byteorder", 151 .ops = &nft_byteorder_ops, 152 .policy = nft_byteorder_policy, 153 .maxattr = NFTA_BYTEORDER_MAX, 154 .owner = THIS_MODULE, 155}; 156 157int __init nft_byteorder_module_init(void) 158{ 159 return nft_register_expr(&nft_byteorder_type); 160} 161 162void nft_byteorder_module_exit(void) 163{ 164 nft_unregister_expr(&nft_byteorder_type); 165} 166