]> git.karo-electronics.de Git - karo-tx-linux.git/blob - net/netfilter/nf_tables_core.c
24000182c8e707d1e148cf08148c445399d7622a
[karo-tx-linux.git] / net / netfilter / nf_tables_core.c
1 /*
2  * Copyright (c) 2008 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/module.h>
12 #include <linux/init.h>
13 #include <linux/list.h>
14 #include <linux/rculist.h>
15 #include <linux/skbuff.h>
16 #include <linux/netlink.h>
17 #include <linux/netfilter.h>
18 #include <linux/netfilter/nfnetlink.h>
19 #include <linux/netfilter/nf_tables.h>
20 #include <net/netfilter/nf_tables_core.h>
21 #include <net/netfilter/nf_tables.h>
22
23 static void nft_cmp_fast_eval(const struct nft_expr *expr,
24                               struct nft_data data[NFT_REG_MAX + 1])
25 {
26         const struct nft_cmp_fast_expr *priv = nft_expr_priv(expr);
27         u32 mask;
28
29         mask = ~0U >> (sizeof(priv->data) * BITS_PER_BYTE - priv->len);
30         if ((data[priv->sreg].data[0] & mask) == priv->data)
31                 return;
32         data[NFT_REG_VERDICT].verdict = NFT_BREAK;
33 }
34
35 unsigned int nft_do_chain(const struct nf_hook_ops *ops,
36                           struct sk_buff *skb,
37                           const struct net_device *in,
38                           const struct net_device *out,
39                           int (*okfn)(struct sk_buff *))
40 {
41         const struct nft_chain *chain = ops->priv;
42         const struct nft_rule *rule;
43         const struct nft_expr *expr, *last;
44         struct nft_data data[NFT_REG_MAX + 1];
45         const struct nft_pktinfo pkt = {
46                 .skb            = skb,
47                 .in             = in,
48                 .out            = out,
49                 .hooknum        = ops->hooknum,
50         };
51         unsigned int stackptr = 0;
52         struct {
53                 const struct nft_chain  *chain;
54                 const struct nft_rule   *rule;
55         } jumpstack[NFT_JUMP_STACK_SIZE];
56
57 do_chain:
58         rule = list_entry(&chain->rules, struct nft_rule, list);
59 next_rule:
60         data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
61         list_for_each_entry_continue_rcu(rule, &chain->rules, list) {
62                 nft_rule_for_each_expr(expr, last, rule) {
63                         if (expr->ops == &nft_cmp_fast_ops)
64                                 nft_cmp_fast_eval(expr, data);
65                         else
66                                 expr->ops->eval(expr, data, &pkt);
67
68                         if (data[NFT_REG_VERDICT].verdict != NFT_CONTINUE)
69                                 break;
70                 }
71
72                 switch (data[NFT_REG_VERDICT].verdict) {
73                 case NFT_BREAK:
74                         data[NFT_REG_VERDICT].verdict = NFT_CONTINUE;
75                         /* fall through */
76                 case NFT_CONTINUE:
77                         continue;
78                 }
79                 break;
80         }
81
82         switch (data[NFT_REG_VERDICT].verdict) {
83         case NF_ACCEPT:
84         case NF_DROP:
85         case NF_QUEUE:
86                 return data[NFT_REG_VERDICT].verdict;
87         case NFT_JUMP:
88                 BUG_ON(stackptr >= NFT_JUMP_STACK_SIZE);
89                 jumpstack[stackptr].chain = chain;
90                 jumpstack[stackptr].rule  = rule;
91                 stackptr++;
92                 /* fall through */
93         case NFT_GOTO:
94                 chain = data[NFT_REG_VERDICT].chain;
95                 goto do_chain;
96         case NFT_RETURN:
97         case NFT_CONTINUE:
98                 break;
99         default:
100                 WARN_ON(1);
101         }
102
103         if (stackptr > 0) {
104                 stackptr--;
105                 chain = jumpstack[stackptr].chain;
106                 rule  = jumpstack[stackptr].rule;
107                 goto next_rule;
108         }
109
110         return NF_ACCEPT;
111 }
112 EXPORT_SYMBOL_GPL(nft_do_chain);
113
114 int __init nf_tables_core_module_init(void)
115 {
116         int err;
117
118         err = nft_immediate_module_init();
119         if (err < 0)
120                 goto err1;
121
122         err = nft_cmp_module_init();
123         if (err < 0)
124                 goto err2;
125
126         err = nft_lookup_module_init();
127         if (err < 0)
128                 goto err3;
129
130         err = nft_bitwise_module_init();
131         if (err < 0)
132                 goto err4;
133
134         err = nft_byteorder_module_init();
135         if (err < 0)
136                 goto err5;
137
138         err = nft_payload_module_init();
139         if (err < 0)
140                 goto err6;
141
142         return 0;
143
144 err6:
145         nft_byteorder_module_exit();
146 err5:
147         nft_bitwise_module_exit();
148 err4:
149         nft_lookup_module_exit();
150 err3:
151         nft_cmp_module_exit();
152 err2:
153         nft_immediate_module_exit();
154 err1:
155         return err;
156 }
157
158 void nf_tables_core_module_exit(void)
159 {
160         nft_payload_module_exit();
161         nft_byteorder_module_exit();
162         nft_bitwise_module_exit();
163         nft_lookup_module_exit();
164         nft_cmp_module_exit();
165         nft_immediate_module_exit();
166 }