• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
20 struct nft_bitwise {
21 	enum nft_registers	sreg:8;
22 	enum nft_registers	dreg:8;
23 	u8			len;
24 	struct nft_data		mask;
25 	struct nft_data		xor;
26 };
27 
nft_bitwise_eval(const struct nft_expr * expr,struct nft_data data[NFT_REG_MAX+1],const struct nft_pktinfo * pkt)28 static void nft_bitwise_eval(const struct nft_expr *expr,
29 			     struct nft_data data[NFT_REG_MAX + 1],
30 			     const struct nft_pktinfo *pkt)
31 {
32 	const struct nft_bitwise *priv = nft_expr_priv(expr);
33 	const struct nft_data *src = &data[priv->sreg];
34 	struct nft_data *dst = &data[priv->dreg];
35 	unsigned int i;
36 
37 	for (i = 0; i < DIV_ROUND_UP(priv->len, 4); i++) {
38 		dst->data[i] = (src->data[i] & priv->mask.data[i]) ^
39 			       priv->xor.data[i];
40 	}
41 }
42 
43 static const struct nla_policy nft_bitwise_policy[NFTA_BITWISE_MAX + 1] = {
44 	[NFTA_BITWISE_SREG]	= { .type = NLA_U32 },
45 	[NFTA_BITWISE_DREG]	= { .type = NLA_U32 },
46 	[NFTA_BITWISE_LEN]	= { .type = NLA_U32 },
47 	[NFTA_BITWISE_MASK]	= { .type = NLA_NESTED },
48 	[NFTA_BITWISE_XOR]	= { .type = NLA_NESTED },
49 };
50 
nft_bitwise_init(const struct nft_ctx * ctx,const struct nft_expr * expr,const struct nlattr * const tb[])51 static int nft_bitwise_init(const struct nft_ctx *ctx,
52 			    const struct nft_expr *expr,
53 			    const struct nlattr * const tb[])
54 {
55 	struct nft_bitwise *priv = nft_expr_priv(expr);
56 	struct nft_data_desc d1, d2;
57 	int err;
58 
59 	if (tb[NFTA_BITWISE_SREG] == NULL ||
60 	    tb[NFTA_BITWISE_DREG] == NULL ||
61 	    tb[NFTA_BITWISE_LEN] == NULL ||
62 	    tb[NFTA_BITWISE_MASK] == NULL ||
63 	    tb[NFTA_BITWISE_XOR] == NULL)
64 		return -EINVAL;
65 
66 	priv->sreg = ntohl(nla_get_be32(tb[NFTA_BITWISE_SREG]));
67 	err = nft_validate_input_register(priv->sreg);
68 	if (err < 0)
69 		return err;
70 
71 	priv->dreg = ntohl(nla_get_be32(tb[NFTA_BITWISE_DREG]));
72 	err = nft_validate_output_register(priv->dreg);
73 	if (err < 0)
74 		return err;
75 	err = nft_validate_data_load(ctx, priv->dreg, NULL, NFT_DATA_VALUE);
76 	if (err < 0)
77 		return err;
78 
79 	priv->len = ntohl(nla_get_be32(tb[NFTA_BITWISE_LEN]));
80 
81 	err = nft_data_init(NULL, &priv->mask, &d1, tb[NFTA_BITWISE_MASK]);
82 	if (err < 0)
83 		return err;
84 	if (d1.len != priv->len)
85 		return -EINVAL;
86 
87 	err = nft_data_init(NULL, &priv->xor, &d2, tb[NFTA_BITWISE_XOR]);
88 	if (err < 0)
89 		return err;
90 	if (d2.len != priv->len)
91 		return -EINVAL;
92 
93 	return 0;
94 }
95 
nft_bitwise_dump(struct sk_buff * skb,const struct nft_expr * expr)96 static int nft_bitwise_dump(struct sk_buff *skb, const struct nft_expr *expr)
97 {
98 	const struct nft_bitwise *priv = nft_expr_priv(expr);
99 
100 	if (nla_put_be32(skb, NFTA_BITWISE_SREG, htonl(priv->sreg)))
101 		goto nla_put_failure;
102 	if (nla_put_be32(skb, NFTA_BITWISE_DREG, htonl(priv->dreg)))
103 		goto nla_put_failure;
104 	if (nla_put_be32(skb, NFTA_BITWISE_LEN, htonl(priv->len)))
105 		goto nla_put_failure;
106 
107 	if (nft_data_dump(skb, NFTA_BITWISE_MASK, &priv->mask,
108 			  NFT_DATA_VALUE, priv->len) < 0)
109 		goto nla_put_failure;
110 
111 	if (nft_data_dump(skb, NFTA_BITWISE_XOR, &priv->xor,
112 			  NFT_DATA_VALUE, priv->len) < 0)
113 		goto nla_put_failure;
114 
115 	return 0;
116 
117 nla_put_failure:
118 	return -1;
119 }
120 
121 static struct nft_expr_type nft_bitwise_type;
122 static const struct nft_expr_ops nft_bitwise_ops = {
123 	.type		= &nft_bitwise_type,
124 	.size		= NFT_EXPR_SIZE(sizeof(struct nft_bitwise)),
125 	.eval		= nft_bitwise_eval,
126 	.init		= nft_bitwise_init,
127 	.dump		= nft_bitwise_dump,
128 };
129 
130 static struct nft_expr_type nft_bitwise_type __read_mostly = {
131 	.name		= "bitwise",
132 	.ops		= &nft_bitwise_ops,
133 	.policy		= nft_bitwise_policy,
134 	.maxattr	= NFTA_BITWISE_MAX,
135 	.owner		= THIS_MODULE,
136 };
137 
nft_bitwise_module_init(void)138 int __init nft_bitwise_module_init(void)
139 {
140 	return nft_register_expr(&nft_bitwise_type);
141 }
142 
nft_bitwise_module_exit(void)143 void nft_bitwise_module_exit(void)
144 {
145 	nft_unregister_expr(&nft_bitwise_type);
146 }
147