blob: 2f25ff61098298b40f1014988591b10ec0fbae77 [file] [log] [blame]
Martin Josefsson77ab9cf2006-11-29 02:34:58 +01001/* Expectation handling for nf_conntrack. */
2
3/* (C) 1999-2001 Paul `Rusty' Russell
4 * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
5 * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/types.h>
13#include <linux/netfilter.h>
14#include <linux/skbuff.h>
15#include <linux/proc_fs.h>
16#include <linux/seq_file.h>
17#include <linux/stddef.h>
18#include <linux/slab.h>
19#include <linux/err.h>
20#include <linux/percpu.h>
21#include <linux/kernel.h>
Patrick McHardya71c0852007-07-07 22:33:47 -070022#include <linux/jhash.h>
Eric W. Biederman457c4cb2007-09-12 12:01:34 +020023#include <net/net_namespace.h>
Martin Josefsson77ab9cf2006-11-29 02:34:58 +010024
25#include <net/netfilter/nf_conntrack.h>
26#include <net/netfilter/nf_conntrack_core.h>
27#include <net/netfilter/nf_conntrack_expect.h>
28#include <net/netfilter/nf_conntrack_helper.h>
29#include <net/netfilter/nf_conntrack_tuple.h>
30
Patrick McHardya71c0852007-07-07 22:33:47 -070031unsigned int nf_ct_expect_hsize __read_mostly;
32EXPORT_SYMBOL_GPL(nf_ct_expect_hsize);
33
34static unsigned int nf_ct_expect_hash_rnd __read_mostly;
Patrick McHardyf264a7d2007-07-07 22:36:24 -070035unsigned int nf_ct_expect_max __read_mostly;
Patrick McHardya71c0852007-07-07 22:33:47 -070036static int nf_ct_expect_hash_rnd_initted __read_mostly;
Patrick McHardya71c0852007-07-07 22:33:47 -070037
Patrick McHardye9c1b082007-07-07 22:32:53 -070038static struct kmem_cache *nf_ct_expect_cachep __read_mostly;
Martin Josefsson77ab9cf2006-11-29 02:34:58 +010039
40/* nf_conntrack_expect helper functions */
41void nf_ct_unlink_expect(struct nf_conntrack_expect *exp)
42{
43 struct nf_conn_help *master_help = nfct_help(exp->master);
Alexey Dobriyan9b03f382008-10-08 11:35:03 +020044 struct net *net = nf_ct_exp_net(exp);
Martin Josefsson77ab9cf2006-11-29 02:34:58 +010045
46 NF_CT_ASSERT(master_help);
47 NF_CT_ASSERT(!timer_pending(&exp->timeout));
48
Patrick McHardy7d0742d2008-01-31 04:38:19 -080049 hlist_del_rcu(&exp->hnode);
Alexey Dobriyan9b03f382008-10-08 11:35:03 +020050 net->ct.expect_count--;
Patrick McHardya71c0852007-07-07 22:33:47 -070051
Patrick McHardyb5605802007-07-07 22:35:56 -070052 hlist_del(&exp->lnode);
Patrick McHardy6002f2662008-03-25 20:09:15 -070053 master_help->expecting[exp->class]--;
Patrick McHardy68236452007-07-07 22:30:49 -070054 nf_ct_expect_put(exp);
Patrick McHardyb5605802007-07-07 22:35:56 -070055
Alexey Dobriyan0d55af82008-10-08 11:35:07 +020056 NF_CT_STAT_INC(net, expect_delete);
Martin Josefsson77ab9cf2006-11-29 02:34:58 +010057}
Patrick McHardy13b18332006-12-02 22:11:25 -080058EXPORT_SYMBOL_GPL(nf_ct_unlink_expect);
Martin Josefsson77ab9cf2006-11-29 02:34:58 +010059
Patrick McHardy68236452007-07-07 22:30:49 -070060static void nf_ct_expectation_timed_out(unsigned long ul_expect)
Martin Josefsson77ab9cf2006-11-29 02:34:58 +010061{
62 struct nf_conntrack_expect *exp = (void *)ul_expect;
63
Patrick McHardyf8ba1af2008-01-31 04:38:58 -080064 spin_lock_bh(&nf_conntrack_lock);
Martin Josefsson77ab9cf2006-11-29 02:34:58 +010065 nf_ct_unlink_expect(exp);
Patrick McHardyf8ba1af2008-01-31 04:38:58 -080066 spin_unlock_bh(&nf_conntrack_lock);
Patrick McHardy68236452007-07-07 22:30:49 -070067 nf_ct_expect_put(exp);
Martin Josefsson77ab9cf2006-11-29 02:34:58 +010068}
69
Patrick McHardya71c0852007-07-07 22:33:47 -070070static unsigned int nf_ct_expect_dst_hash(const struct nf_conntrack_tuple *tuple)
71{
Patrick McHardy34498822007-12-17 22:45:52 -080072 unsigned int hash;
73
Patrick McHardya71c0852007-07-07 22:33:47 -070074 if (unlikely(!nf_ct_expect_hash_rnd_initted)) {
Hagen Paul Pfeiferaf07d242009-02-20 10:48:06 +010075 get_random_bytes(&nf_ct_expect_hash_rnd,
76 sizeof(nf_ct_expect_hash_rnd));
Patrick McHardya71c0852007-07-07 22:33:47 -070077 nf_ct_expect_hash_rnd_initted = 1;
78 }
79
Patrick McHardy34498822007-12-17 22:45:52 -080080 hash = jhash2(tuple->dst.u3.all, ARRAY_SIZE(tuple->dst.u3.all),
Patrick McHardya71c0852007-07-07 22:33:47 -070081 (((tuple->dst.protonum ^ tuple->src.l3num) << 16) |
Patrick McHardy34498822007-12-17 22:45:52 -080082 (__force __u16)tuple->dst.u.all) ^ nf_ct_expect_hash_rnd);
83 return ((u64)hash * nf_ct_expect_hsize) >> 32;
Patrick McHardya71c0852007-07-07 22:33:47 -070084}
85
Martin Josefsson77ab9cf2006-11-29 02:34:58 +010086struct nf_conntrack_expect *
Alexey Dobriyan9b03f382008-10-08 11:35:03 +020087__nf_ct_expect_find(struct net *net, const struct nf_conntrack_tuple *tuple)
Martin Josefsson77ab9cf2006-11-29 02:34:58 +010088{
89 struct nf_conntrack_expect *i;
Patrick McHardya71c0852007-07-07 22:33:47 -070090 struct hlist_node *n;
91 unsigned int h;
Martin Josefsson77ab9cf2006-11-29 02:34:58 +010092
Alexey Dobriyan9b03f382008-10-08 11:35:03 +020093 if (!net->ct.expect_count)
Patrick McHardya71c0852007-07-07 22:33:47 -070094 return NULL;
95
96 h = nf_ct_expect_dst_hash(tuple);
Alexey Dobriyan9b03f382008-10-08 11:35:03 +020097 hlist_for_each_entry_rcu(i, n, &net->ct.expect_hash[h], hnode) {
Martin Josefsson77ab9cf2006-11-29 02:34:58 +010098 if (nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask))
99 return i;
100 }
101 return NULL;
102}
Patrick McHardy68236452007-07-07 22:30:49 -0700103EXPORT_SYMBOL_GPL(__nf_ct_expect_find);
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100104
105/* Just find a expectation corresponding to a tuple. */
106struct nf_conntrack_expect *
Alexey Dobriyan9b03f382008-10-08 11:35:03 +0200107nf_ct_expect_find_get(struct net *net, const struct nf_conntrack_tuple *tuple)
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100108{
109 struct nf_conntrack_expect *i;
110
Patrick McHardy7d0742d2008-01-31 04:38:19 -0800111 rcu_read_lock();
Alexey Dobriyan9b03f382008-10-08 11:35:03 +0200112 i = __nf_ct_expect_find(net, tuple);
Patrick McHardy7d0742d2008-01-31 04:38:19 -0800113 if (i && !atomic_inc_not_zero(&i->use))
114 i = NULL;
115 rcu_read_unlock();
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100116
117 return i;
118}
Patrick McHardy68236452007-07-07 22:30:49 -0700119EXPORT_SYMBOL_GPL(nf_ct_expect_find_get);
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100120
121/* If an expectation for this connection is found, it gets delete from
122 * global list then returned. */
123struct nf_conntrack_expect *
Alexey Dobriyan9b03f382008-10-08 11:35:03 +0200124nf_ct_find_expectation(struct net *net, const struct nf_conntrack_tuple *tuple)
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100125{
Patrick McHardy359b9ab2008-03-25 20:08:37 -0700126 struct nf_conntrack_expect *i, *exp = NULL;
127 struct hlist_node *n;
128 unsigned int h;
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100129
Alexey Dobriyan9b03f382008-10-08 11:35:03 +0200130 if (!net->ct.expect_count)
Patrick McHardy359b9ab2008-03-25 20:08:37 -0700131 return NULL;
132
133 h = nf_ct_expect_dst_hash(tuple);
Alexey Dobriyan9b03f382008-10-08 11:35:03 +0200134 hlist_for_each_entry(i, n, &net->ct.expect_hash[h], hnode) {
Patrick McHardy359b9ab2008-03-25 20:08:37 -0700135 if (!(i->flags & NF_CT_EXPECT_INACTIVE) &&
136 nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)) {
137 exp = i;
138 break;
139 }
140 }
Yasuyuki Kozakaiece00642006-12-05 13:44:57 -0800141 if (!exp)
142 return NULL;
143
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100144 /* If master is not in hash table yet (ie. packet hasn't left
145 this machine yet), how can other end know about expected?
146 Hence these are not the droids you are looking for (if
147 master ct never got confirmed, we'd hold a reference to it
148 and weird things would happen to future packets). */
Yasuyuki Kozakaiece00642006-12-05 13:44:57 -0800149 if (!nf_ct_is_confirmed(exp->master))
150 return NULL;
151
152 if (exp->flags & NF_CT_EXPECT_PERMANENT) {
153 atomic_inc(&exp->use);
154 return exp;
155 } else if (del_timer(&exp->timeout)) {
156 nf_ct_unlink_expect(exp);
157 return exp;
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100158 }
Yasuyuki Kozakaiece00642006-12-05 13:44:57 -0800159
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100160 return NULL;
161}
162
163/* delete all expectations for this conntrack */
164void nf_ct_remove_expectations(struct nf_conn *ct)
165{
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100166 struct nf_conn_help *help = nfct_help(ct);
Patrick McHardyb5605802007-07-07 22:35:56 -0700167 struct nf_conntrack_expect *exp;
168 struct hlist_node *n, *next;
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100169
170 /* Optimization: most connection never expect any others. */
Patrick McHardy6002f2662008-03-25 20:09:15 -0700171 if (!help)
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100172 return;
173
Patrick McHardyb5605802007-07-07 22:35:56 -0700174 hlist_for_each_entry_safe(exp, n, next, &help->expectations, lnode) {
175 if (del_timer(&exp->timeout)) {
176 nf_ct_unlink_expect(exp);
177 nf_ct_expect_put(exp);
YOSHIFUJI Hideaki601e68e2007-02-12 11:15:49 -0800178 }
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100179 }
180}
Patrick McHardy13b18332006-12-02 22:11:25 -0800181EXPORT_SYMBOL_GPL(nf_ct_remove_expectations);
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100182
183/* Would two expected things clash? */
184static inline int expect_clash(const struct nf_conntrack_expect *a,
185 const struct nf_conntrack_expect *b)
186{
187 /* Part covered by intersection of masks must be unequal,
188 otherwise they clash */
Patrick McHardyd4156e82007-07-07 22:31:32 -0700189 struct nf_conntrack_tuple_mask intersect_mask;
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100190 int count;
191
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100192 intersect_mask.src.u.all = a->mask.src.u.all & b->mask.src.u.all;
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100193
194 for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++){
195 intersect_mask.src.u3.all[count] =
196 a->mask.src.u3.all[count] & b->mask.src.u3.all[count];
197 }
198
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100199 return nf_ct_tuple_mask_cmp(&a->tuple, &b->tuple, &intersect_mask);
200}
201
202static inline int expect_matches(const struct nf_conntrack_expect *a,
203 const struct nf_conntrack_expect *b)
204{
Joe Perchesf64f9e72009-11-29 16:55:45 -0800205 return a->master == b->master && a->class == b->class &&
206 nf_ct_tuple_equal(&a->tuple, &b->tuple) &&
207 nf_ct_tuple_mask_equal(&a->mask, &b->mask);
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100208}
209
210/* Generally a bad idea to call this: could have matched already. */
Patrick McHardy68236452007-07-07 22:30:49 -0700211void nf_ct_unexpect_related(struct nf_conntrack_expect *exp)
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100212{
Patrick McHardyf8ba1af2008-01-31 04:38:58 -0800213 spin_lock_bh(&nf_conntrack_lock);
Patrick McHardy4e1d4e62007-07-07 22:32:03 -0700214 if (del_timer(&exp->timeout)) {
215 nf_ct_unlink_expect(exp);
216 nf_ct_expect_put(exp);
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100217 }
Patrick McHardyf8ba1af2008-01-31 04:38:58 -0800218 spin_unlock_bh(&nf_conntrack_lock);
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100219}
Patrick McHardy68236452007-07-07 22:30:49 -0700220EXPORT_SYMBOL_GPL(nf_ct_unexpect_related);
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100221
222/* We don't increase the master conntrack refcount for non-fulfilled
223 * conntracks. During the conntrack destruction, the expectations are
224 * always killed before the conntrack itself */
Patrick McHardy68236452007-07-07 22:30:49 -0700225struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me)
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100226{
227 struct nf_conntrack_expect *new;
228
Patrick McHardy68236452007-07-07 22:30:49 -0700229 new = kmem_cache_alloc(nf_ct_expect_cachep, GFP_ATOMIC);
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100230 if (!new)
231 return NULL;
232
233 new->master = me;
234 atomic_set(&new->use, 1);
Patrick McHardy7d0742d2008-01-31 04:38:19 -0800235 INIT_RCU_HEAD(&new->rcu);
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100236 return new;
237}
Patrick McHardy68236452007-07-07 22:30:49 -0700238EXPORT_SYMBOL_GPL(nf_ct_expect_alloc);
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100239
Patrick McHardy6002f2662008-03-25 20:09:15 -0700240void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
Jan Engelhardt76108ce2008-10-08 11:35:00 +0200241 u_int8_t family,
Patrick McHardy1d9d7522008-03-25 20:07:58 -0700242 const union nf_inet_addr *saddr,
243 const union nf_inet_addr *daddr,
244 u_int8_t proto, const __be16 *src, const __be16 *dst)
Patrick McHardyd6a9b652006-12-02 22:08:01 -0800245{
246 int len;
247
248 if (family == AF_INET)
249 len = 4;
250 else
251 len = 16;
252
253 exp->flags = 0;
Patrick McHardy6002f2662008-03-25 20:09:15 -0700254 exp->class = class;
Patrick McHardyd6a9b652006-12-02 22:08:01 -0800255 exp->expectfn = NULL;
256 exp->helper = NULL;
257 exp->tuple.src.l3num = family;
258 exp->tuple.dst.protonum = proto;
Patrick McHardyd6a9b652006-12-02 22:08:01 -0800259
260 if (saddr) {
261 memcpy(&exp->tuple.src.u3, saddr, len);
262 if (sizeof(exp->tuple.src.u3) > len)
263 /* address needs to be cleared for nf_ct_tuple_equal */
264 memset((void *)&exp->tuple.src.u3 + len, 0x00,
265 sizeof(exp->tuple.src.u3) - len);
266 memset(&exp->mask.src.u3, 0xFF, len);
267 if (sizeof(exp->mask.src.u3) > len)
268 memset((void *)&exp->mask.src.u3 + len, 0x00,
269 sizeof(exp->mask.src.u3) - len);
270 } else {
271 memset(&exp->tuple.src.u3, 0x00, sizeof(exp->tuple.src.u3));
272 memset(&exp->mask.src.u3, 0x00, sizeof(exp->mask.src.u3));
273 }
274
Patrick McHardyd6a9b652006-12-02 22:08:01 -0800275 if (src) {
Al Viroa34c4582007-07-26 17:33:19 +0100276 exp->tuple.src.u.all = *src;
277 exp->mask.src.u.all = htons(0xFFFF);
Patrick McHardyd6a9b652006-12-02 22:08:01 -0800278 } else {
279 exp->tuple.src.u.all = 0;
280 exp->mask.src.u.all = 0;
281 }
282
Patrick McHardyd4156e82007-07-07 22:31:32 -0700283 memcpy(&exp->tuple.dst.u3, daddr, len);
284 if (sizeof(exp->tuple.dst.u3) > len)
285 /* address needs to be cleared for nf_ct_tuple_equal */
286 memset((void *)&exp->tuple.dst.u3 + len, 0x00,
287 sizeof(exp->tuple.dst.u3) - len);
288
Al Viroa34c4582007-07-26 17:33:19 +0100289 exp->tuple.dst.u.all = *dst;
Patrick McHardyd6a9b652006-12-02 22:08:01 -0800290}
Patrick McHardy68236452007-07-07 22:30:49 -0700291EXPORT_SYMBOL_GPL(nf_ct_expect_init);
Patrick McHardyd6a9b652006-12-02 22:08:01 -0800292
Patrick McHardy7d0742d2008-01-31 04:38:19 -0800293static void nf_ct_expect_free_rcu(struct rcu_head *head)
294{
295 struct nf_conntrack_expect *exp;
296
297 exp = container_of(head, struct nf_conntrack_expect, rcu);
298 kmem_cache_free(nf_ct_expect_cachep, exp);
299}
300
Patrick McHardy68236452007-07-07 22:30:49 -0700301void nf_ct_expect_put(struct nf_conntrack_expect *exp)
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100302{
303 if (atomic_dec_and_test(&exp->use))
Patrick McHardy7d0742d2008-01-31 04:38:19 -0800304 call_rcu(&exp->rcu, nf_ct_expect_free_rcu);
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100305}
Patrick McHardy68236452007-07-07 22:30:49 -0700306EXPORT_SYMBOL_GPL(nf_ct_expect_put);
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100307
Patrick McHardy68236452007-07-07 22:30:49 -0700308static void nf_ct_expect_insert(struct nf_conntrack_expect *exp)
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100309{
310 struct nf_conn_help *master_help = nfct_help(exp->master);
Alexey Dobriyan9b03f382008-10-08 11:35:03 +0200311 struct net *net = nf_ct_exp_net(exp);
Patrick McHardy6002f2662008-03-25 20:09:15 -0700312 const struct nf_conntrack_expect_policy *p;
Patrick McHardya71c0852007-07-07 22:33:47 -0700313 unsigned int h = nf_ct_expect_dst_hash(&exp->tuple);
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100314
315 atomic_inc(&exp->use);
Patrick McHardyb5605802007-07-07 22:35:56 -0700316
317 hlist_add_head(&exp->lnode, &master_help->expectations);
Patrick McHardy6002f2662008-03-25 20:09:15 -0700318 master_help->expecting[exp->class]++;
Patrick McHardya71c0852007-07-07 22:33:47 -0700319
Alexey Dobriyan9b03f382008-10-08 11:35:03 +0200320 hlist_add_head_rcu(&exp->hnode, &net->ct.expect_hash[h]);
321 net->ct.expect_count++;
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100322
Patrick McHardy68236452007-07-07 22:30:49 -0700323 setup_timer(&exp->timeout, nf_ct_expectation_timed_out,
324 (unsigned long)exp);
Patrick McHardy6002f2662008-03-25 20:09:15 -0700325 p = &master_help->helper->expect_policy[exp->class];
326 exp->timeout.expires = jiffies + p->timeout * HZ;
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100327 add_timer(&exp->timeout);
328
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100329 atomic_inc(&exp->use);
Alexey Dobriyan0d55af82008-10-08 11:35:07 +0200330 NF_CT_STAT_INC(net, expect_create);
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100331}
332
333/* Race with expectations being used means we could have none to find; OK. */
Patrick McHardy6002f2662008-03-25 20:09:15 -0700334static void evict_oldest_expect(struct nf_conn *master,
335 struct nf_conntrack_expect *new)
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100336{
Patrick McHardyb5605802007-07-07 22:35:56 -0700337 struct nf_conn_help *master_help = nfct_help(master);
Patrick McHardy6002f2662008-03-25 20:09:15 -0700338 struct nf_conntrack_expect *exp, *last = NULL;
Patrick McHardyb5605802007-07-07 22:35:56 -0700339 struct hlist_node *n;
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100340
Patrick McHardy6002f2662008-03-25 20:09:15 -0700341 hlist_for_each_entry(exp, n, &master_help->expectations, lnode) {
342 if (exp->class == new->class)
343 last = exp;
344 }
Patrick McHardyb5605802007-07-07 22:35:56 -0700345
Patrick McHardy6002f2662008-03-25 20:09:15 -0700346 if (last && del_timer(&last->timeout)) {
347 nf_ct_unlink_expect(last);
348 nf_ct_expect_put(last);
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100349 }
350}
351
352static inline int refresh_timer(struct nf_conntrack_expect *i)
353{
354 struct nf_conn_help *master_help = nfct_help(i->master);
Patrick McHardy6002f2662008-03-25 20:09:15 -0700355 const struct nf_conntrack_expect_policy *p;
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100356
357 if (!del_timer(&i->timeout))
358 return 0;
359
Patrick McHardy6002f2662008-03-25 20:09:15 -0700360 p = &master_help->helper->expect_policy[i->class];
361 i->timeout.expires = jiffies + p->timeout * HZ;
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100362 add_timer(&i->timeout);
363 return 1;
364}
365
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +0100366static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100367{
Patrick McHardy6002f2662008-03-25 20:09:15 -0700368 const struct nf_conntrack_expect_policy *p;
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100369 struct nf_conntrack_expect *i;
370 struct nf_conn *master = expect->master;
371 struct nf_conn_help *master_help = nfct_help(master);
Alexey Dobriyan9b03f382008-10-08 11:35:03 +0200372 struct net *net = nf_ct_exp_net(expect);
Patrick McHardya71c0852007-07-07 22:33:47 -0700373 struct hlist_node *n;
374 unsigned int h;
Pablo Neira Ayuso83731672009-04-06 17:47:20 +0200375 int ret = 1;
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100376
Patrick McHarrdy3c158f72007-06-05 12:55:27 -0700377 if (!master_help->helper) {
378 ret = -ESHUTDOWN;
379 goto out;
380 }
Patrick McHardya71c0852007-07-07 22:33:47 -0700381 h = nf_ct_expect_dst_hash(&expect->tuple);
Alexey Dobriyan9b03f382008-10-08 11:35:03 +0200382 hlist_for_each_entry(i, n, &net->ct.expect_hash[h], hnode) {
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100383 if (expect_matches(i, expect)) {
384 /* Refresh timer: if it's dying, ignore.. */
385 if (refresh_timer(i)) {
386 ret = 0;
387 goto out;
388 }
389 } else if (expect_clash(i, expect)) {
390 ret = -EBUSY;
391 goto out;
392 }
393 }
394 /* Will be over limit? */
Patrick McHardy6002f2662008-03-25 20:09:15 -0700395 p = &master_help->helper->expect_policy[expect->class];
396 if (p->max_expected &&
397 master_help->expecting[expect->class] >= p->max_expected) {
398 evict_oldest_expect(master, expect);
399 if (master_help->expecting[expect->class] >= p->max_expected) {
400 ret = -EMFILE;
401 goto out;
402 }
403 }
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100404
Alexey Dobriyan9b03f382008-10-08 11:35:03 +0200405 if (net->ct.expect_count >= nf_ct_expect_max) {
Patrick McHardyf264a7d2007-07-07 22:36:24 -0700406 if (net_ratelimit())
407 printk(KERN_WARNING
Alexey Dobriyan3d89e9c2008-03-10 16:43:10 -0700408 "nf_conntrack: expectation table full\n");
Patrick McHardyf264a7d2007-07-07 22:36:24 -0700409 ret = -EMFILE;
Patrick McHardyf264a7d2007-07-07 22:36:24 -0700410 }
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +0100411out:
412 return ret;
413}
414
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +0100415int nf_ct_expect_related_report(struct nf_conntrack_expect *expect,
416 u32 pid, int report)
417{
418 int ret;
419
420 spin_lock_bh(&nf_conntrack_lock);
421 ret = __nf_ct_expect_check(expect);
Pablo Neira Ayuso83731672009-04-06 17:47:20 +0200422 if (ret <= 0)
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +0100423 goto out;
Pablo Neira Ayuso83731672009-04-06 17:47:20 +0200424
425 ret = 0;
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +0100426 nf_ct_expect_insert(expect);
Pablo Neira Ayuso83731672009-04-06 17:47:20 +0200427 spin_unlock_bh(&nf_conntrack_lock);
428 nf_ct_expect_event_report(IPEXP_NEW, expect, pid, report);
429 return ret;
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +0100430out:
431 spin_unlock_bh(&nf_conntrack_lock);
Pablo Neira Ayuso19abb7b2008-11-18 11:56:20 +0100432 return ret;
433}
434EXPORT_SYMBOL_GPL(nf_ct_expect_related_report);
435
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100436#ifdef CONFIG_PROC_FS
Patrick McHardy5d08ad42007-07-07 22:34:07 -0700437struct ct_expect_iter_state {
Alexey Dobriyandc5129f2008-10-08 11:35:06 +0200438 struct seq_net_private p;
Patrick McHardy5d08ad42007-07-07 22:34:07 -0700439 unsigned int bucket;
440};
441
442static struct hlist_node *ct_expect_get_first(struct seq_file *seq)
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100443{
Alexey Dobriyandc5129f2008-10-08 11:35:06 +0200444 struct net *net = seq_file_net(seq);
Patrick McHardy5d08ad42007-07-07 22:34:07 -0700445 struct ct_expect_iter_state *st = seq->private;
Patrick McHardy7d0742d2008-01-31 04:38:19 -0800446 struct hlist_node *n;
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100447
Patrick McHardy5d08ad42007-07-07 22:34:07 -0700448 for (st->bucket = 0; st->bucket < nf_ct_expect_hsize; st->bucket++) {
Alexey Dobriyan9b03f382008-10-08 11:35:03 +0200449 n = rcu_dereference(net->ct.expect_hash[st->bucket].first);
Patrick McHardy7d0742d2008-01-31 04:38:19 -0800450 if (n)
451 return n;
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100452 }
Patrick McHardy5d08ad42007-07-07 22:34:07 -0700453 return NULL;
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100454}
455
Patrick McHardy5d08ad42007-07-07 22:34:07 -0700456static struct hlist_node *ct_expect_get_next(struct seq_file *seq,
457 struct hlist_node *head)
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100458{
Alexey Dobriyandc5129f2008-10-08 11:35:06 +0200459 struct net *net = seq_file_net(seq);
Patrick McHardy5d08ad42007-07-07 22:34:07 -0700460 struct ct_expect_iter_state *st = seq->private;
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100461
Patrick McHardy7d0742d2008-01-31 04:38:19 -0800462 head = rcu_dereference(head->next);
Patrick McHardy5d08ad42007-07-07 22:34:07 -0700463 while (head == NULL) {
464 if (++st->bucket >= nf_ct_expect_hsize)
465 return NULL;
Alexey Dobriyan9b03f382008-10-08 11:35:03 +0200466 head = rcu_dereference(net->ct.expect_hash[st->bucket].first);
Patrick McHardy5d08ad42007-07-07 22:34:07 -0700467 }
468 return head;
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100469}
470
Patrick McHardy5d08ad42007-07-07 22:34:07 -0700471static struct hlist_node *ct_expect_get_idx(struct seq_file *seq, loff_t pos)
472{
473 struct hlist_node *head = ct_expect_get_first(seq);
474
475 if (head)
476 while (pos && (head = ct_expect_get_next(seq, head)))
477 pos--;
478 return pos ? NULL : head;
479}
480
481static void *exp_seq_start(struct seq_file *seq, loff_t *pos)
Patrick McHardy7d0742d2008-01-31 04:38:19 -0800482 __acquires(RCU)
Patrick McHardy5d08ad42007-07-07 22:34:07 -0700483{
Patrick McHardy7d0742d2008-01-31 04:38:19 -0800484 rcu_read_lock();
Patrick McHardy5d08ad42007-07-07 22:34:07 -0700485 return ct_expect_get_idx(seq, *pos);
486}
487
488static void *exp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
489{
490 (*pos)++;
491 return ct_expect_get_next(seq, v);
492}
493
494static void exp_seq_stop(struct seq_file *seq, void *v)
Patrick McHardy7d0742d2008-01-31 04:38:19 -0800495 __releases(RCU)
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100496{
Patrick McHardy7d0742d2008-01-31 04:38:19 -0800497 rcu_read_unlock();
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100498}
499
500static int exp_seq_show(struct seq_file *s, void *v)
501{
Patrick McHardy5d08ad42007-07-07 22:34:07 -0700502 struct nf_conntrack_expect *expect;
503 struct hlist_node *n = v;
Patrick McHardy359b9ab2008-03-25 20:08:37 -0700504 char *delim = "";
Patrick McHardy5d08ad42007-07-07 22:34:07 -0700505
506 expect = hlist_entry(n, struct nf_conntrack_expect, hnode);
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100507
508 if (expect->timeout.function)
509 seq_printf(s, "%ld ", timer_pending(&expect->timeout)
510 ? (long)(expect->timeout.expires - jiffies)/HZ : 0);
511 else
512 seq_printf(s, "- ");
513 seq_printf(s, "l3proto = %u proto=%u ",
514 expect->tuple.src.l3num,
515 expect->tuple.dst.protonum);
516 print_tuple(s, &expect->tuple,
517 __nf_ct_l3proto_find(expect->tuple.src.l3num),
Martin Josefsson605dcad2006-11-29 02:35:06 +0100518 __nf_ct_l4proto_find(expect->tuple.src.l3num,
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100519 expect->tuple.dst.protonum));
Patrick McHardy4bb119e2008-03-25 20:08:17 -0700520
Patrick McHardy359b9ab2008-03-25 20:08:37 -0700521 if (expect->flags & NF_CT_EXPECT_PERMANENT) {
522 seq_printf(s, "PERMANENT");
523 delim = ",";
524 }
525 if (expect->flags & NF_CT_EXPECT_INACTIVE)
526 seq_printf(s, "%sINACTIVE", delim);
Patrick McHardy4bb119e2008-03-25 20:08:17 -0700527
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100528 return seq_putc(s, '\n');
529}
530
Philippe De Muyter56b3d972007-07-10 23:07:31 -0700531static const struct seq_operations exp_seq_ops = {
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100532 .start = exp_seq_start,
533 .next = exp_seq_next,
534 .stop = exp_seq_stop,
535 .show = exp_seq_show
536};
537
538static int exp_open(struct inode *inode, struct file *file)
539{
Alexey Dobriyandc5129f2008-10-08 11:35:06 +0200540 return seq_open_net(inode, file, &exp_seq_ops,
Pavel Emelyanove2da5912007-10-10 02:29:58 -0700541 sizeof(struct ct_expect_iter_state));
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100542}
543
Patrick McHardy5d08ad42007-07-07 22:34:07 -0700544static const struct file_operations exp_file_ops = {
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100545 .owner = THIS_MODULE,
546 .open = exp_open,
547 .read = seq_read,
548 .llseek = seq_lseek,
Alexey Dobriyandc5129f2008-10-08 11:35:06 +0200549 .release = seq_release_net,
Martin Josefsson77ab9cf2006-11-29 02:34:58 +0100550};
551#endif /* CONFIG_PROC_FS */
Patrick McHardye9c1b082007-07-07 22:32:53 -0700552
Alexey Dobriyandc5129f2008-10-08 11:35:06 +0200553static int exp_proc_init(struct net *net)
Patrick McHardye9c1b082007-07-07 22:32:53 -0700554{
555#ifdef CONFIG_PROC_FS
556 struct proc_dir_entry *proc;
557
Alexey Dobriyandc5129f2008-10-08 11:35:06 +0200558 proc = proc_net_fops_create(net, "nf_conntrack_expect", 0440, &exp_file_ops);
Patrick McHardye9c1b082007-07-07 22:32:53 -0700559 if (!proc)
560 return -ENOMEM;
561#endif /* CONFIG_PROC_FS */
562 return 0;
563}
564
Alexey Dobriyandc5129f2008-10-08 11:35:06 +0200565static void exp_proc_remove(struct net *net)
Patrick McHardye9c1b082007-07-07 22:32:53 -0700566{
567#ifdef CONFIG_PROC_FS
Alexey Dobriyandc5129f2008-10-08 11:35:06 +0200568 proc_net_remove(net, "nf_conntrack_expect");
Patrick McHardye9c1b082007-07-07 22:32:53 -0700569#endif /* CONFIG_PROC_FS */
570}
571
Alexey Dobriyan13ccdfc2010-02-08 11:17:22 -0800572module_param_named(expect_hashsize, nf_ct_expect_hsize, uint, 0400);
Patrick McHardya71c0852007-07-07 22:33:47 -0700573
Alexey Dobriyan9b03f382008-10-08 11:35:03 +0200574int nf_conntrack_expect_init(struct net *net)
Patrick McHardye9c1b082007-07-07 22:32:53 -0700575{
Patrick McHardya71c0852007-07-07 22:33:47 -0700576 int err = -ENOMEM;
577
Alexey Dobriyan08f65472008-10-08 11:35:09 +0200578 if (net_eq(net, &init_net)) {
579 if (!nf_ct_expect_hsize) {
Patrick McHardyd696c7b2010-02-08 11:18:07 -0800580 nf_ct_expect_hsize = net->ct.htable_size / 256;
Alexey Dobriyan08f65472008-10-08 11:35:09 +0200581 if (!nf_ct_expect_hsize)
582 nf_ct_expect_hsize = 1;
583 }
584 nf_ct_expect_max = nf_ct_expect_hsize * 4;
Patrick McHardya71c0852007-07-07 22:33:47 -0700585 }
586
Alexey Dobriyan9b03f382008-10-08 11:35:03 +0200587 net->ct.expect_count = 0;
588 net->ct.expect_hash = nf_ct_alloc_hashtable(&nf_ct_expect_hsize,
Eric Dumazetea781f12009-03-25 21:05:46 +0100589 &net->ct.expect_vmalloc, 0);
Alexey Dobriyan9b03f382008-10-08 11:35:03 +0200590 if (net->ct.expect_hash == NULL)
Patrick McHardya71c0852007-07-07 22:33:47 -0700591 goto err1;
Patrick McHardye9c1b082007-07-07 22:32:53 -0700592
Alexey Dobriyan08f65472008-10-08 11:35:09 +0200593 if (net_eq(net, &init_net)) {
594 nf_ct_expect_cachep = kmem_cache_create("nf_conntrack_expect",
Patrick McHardye9c1b082007-07-07 22:32:53 -0700595 sizeof(struct nf_conntrack_expect),
Paul Mundt20c2df82007-07-20 10:11:58 +0900596 0, 0, NULL);
Alexey Dobriyan08f65472008-10-08 11:35:09 +0200597 if (!nf_ct_expect_cachep)
598 goto err2;
599 }
Patrick McHardye9c1b082007-07-07 22:32:53 -0700600
Alexey Dobriyandc5129f2008-10-08 11:35:06 +0200601 err = exp_proc_init(net);
Patrick McHardye9c1b082007-07-07 22:32:53 -0700602 if (err < 0)
Patrick McHardya71c0852007-07-07 22:33:47 -0700603 goto err3;
Patrick McHardye9c1b082007-07-07 22:32:53 -0700604
605 return 0;
606
Patrick McHardya71c0852007-07-07 22:33:47 -0700607err3:
Alexey Dobriyan08f65472008-10-08 11:35:09 +0200608 if (net_eq(net, &init_net))
609 kmem_cache_destroy(nf_ct_expect_cachep);
Alexey Dobriyan12293bf2008-05-29 03:19:37 -0700610err2:
Alexey Dobriyan9b03f382008-10-08 11:35:03 +0200611 nf_ct_free_hashtable(net->ct.expect_hash, net->ct.expect_vmalloc,
Patrick McHardya71c0852007-07-07 22:33:47 -0700612 nf_ct_expect_hsize);
Patrick McHardya71c0852007-07-07 22:33:47 -0700613err1:
Patrick McHardye9c1b082007-07-07 22:32:53 -0700614 return err;
615}
616
Alexey Dobriyan9b03f382008-10-08 11:35:03 +0200617void nf_conntrack_expect_fini(struct net *net)
Patrick McHardye9c1b082007-07-07 22:32:53 -0700618{
Alexey Dobriyandc5129f2008-10-08 11:35:06 +0200619 exp_proc_remove(net);
Jesper Dangaard Brouer308ff822009-06-25 16:32:52 +0200620 if (net_eq(net, &init_net)) {
621 rcu_barrier(); /* Wait for call_rcu() before destroy */
Alexey Dobriyan08f65472008-10-08 11:35:09 +0200622 kmem_cache_destroy(nf_ct_expect_cachep);
Jesper Dangaard Brouer308ff822009-06-25 16:32:52 +0200623 }
Alexey Dobriyan9b03f382008-10-08 11:35:03 +0200624 nf_ct_free_hashtable(net->ct.expect_hash, net->ct.expect_vmalloc,
Patrick McHardya71c0852007-07-07 22:33:47 -0700625 nf_ct_expect_hsize);
Patrick McHardye9c1b082007-07-07 22:32:53 -0700626}