[NETFILTER]: nf_conntrack: move expectaton related init code to nf_conntrack_expect.c
[safe/jmp/linux-2.6] / net / netfilter / nf_conntrack_expect.c
1 /* 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>
22
23 #include <net/netfilter/nf_conntrack.h>
24 #include <net/netfilter/nf_conntrack_core.h>
25 #include <net/netfilter/nf_conntrack_expect.h>
26 #include <net/netfilter/nf_conntrack_helper.h>
27 #include <net/netfilter/nf_conntrack_tuple.h>
28
29 LIST_HEAD(nf_ct_expect_list);
30 EXPORT_SYMBOL_GPL(nf_ct_expect_list);
31
32 static struct kmem_cache *nf_ct_expect_cachep __read_mostly;
33 static unsigned int nf_ct_expect_next_id;
34
35 /* nf_conntrack_expect helper functions */
36 void nf_ct_unlink_expect(struct nf_conntrack_expect *exp)
37 {
38         struct nf_conn_help *master_help = nfct_help(exp->master);
39
40         NF_CT_ASSERT(master_help);
41         NF_CT_ASSERT(!timer_pending(&exp->timeout));
42
43         list_del(&exp->list);
44         NF_CT_STAT_INC(expect_delete);
45         master_help->expecting--;
46         nf_ct_expect_put(exp);
47 }
48 EXPORT_SYMBOL_GPL(nf_ct_unlink_expect);
49
50 static void nf_ct_expectation_timed_out(unsigned long ul_expect)
51 {
52         struct nf_conntrack_expect *exp = (void *)ul_expect;
53
54         write_lock_bh(&nf_conntrack_lock);
55         nf_ct_unlink_expect(exp);
56         write_unlock_bh(&nf_conntrack_lock);
57         nf_ct_expect_put(exp);
58 }
59
60 struct nf_conntrack_expect *
61 __nf_ct_expect_find(const struct nf_conntrack_tuple *tuple)
62 {
63         struct nf_conntrack_expect *i;
64
65         list_for_each_entry(i, &nf_ct_expect_list, list) {
66                 if (nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask))
67                         return i;
68         }
69         return NULL;
70 }
71 EXPORT_SYMBOL_GPL(__nf_ct_expect_find);
72
73 /* Just find a expectation corresponding to a tuple. */
74 struct nf_conntrack_expect *
75 nf_ct_expect_find_get(const struct nf_conntrack_tuple *tuple)
76 {
77         struct nf_conntrack_expect *i;
78
79         read_lock_bh(&nf_conntrack_lock);
80         i = __nf_ct_expect_find(tuple);
81         if (i)
82                 atomic_inc(&i->use);
83         read_unlock_bh(&nf_conntrack_lock);
84
85         return i;
86 }
87 EXPORT_SYMBOL_GPL(nf_ct_expect_find_get);
88
89 /* If an expectation for this connection is found, it gets delete from
90  * global list then returned. */
91 struct nf_conntrack_expect *
92 nf_ct_find_expectation(const struct nf_conntrack_tuple *tuple)
93 {
94         struct nf_conntrack_expect *exp;
95
96         exp = __nf_ct_expect_find(tuple);
97         if (!exp)
98                 return NULL;
99
100         /* If master is not in hash table yet (ie. packet hasn't left
101            this machine yet), how can other end know about expected?
102            Hence these are not the droids you are looking for (if
103            master ct never got confirmed, we'd hold a reference to it
104            and weird things would happen to future packets). */
105         if (!nf_ct_is_confirmed(exp->master))
106                 return NULL;
107
108         if (exp->flags & NF_CT_EXPECT_PERMANENT) {
109                 atomic_inc(&exp->use);
110                 return exp;
111         } else if (del_timer(&exp->timeout)) {
112                 nf_ct_unlink_expect(exp);
113                 return exp;
114         }
115
116         return NULL;
117 }
118
119 /* delete all expectations for this conntrack */
120 void nf_ct_remove_expectations(struct nf_conn *ct)
121 {
122         struct nf_conntrack_expect *i, *tmp;
123         struct nf_conn_help *help = nfct_help(ct);
124
125         /* Optimization: most connection never expect any others. */
126         if (!help || help->expecting == 0)
127                 return;
128
129         list_for_each_entry_safe(i, tmp, &nf_ct_expect_list, list) {
130                 if (i->master == ct && del_timer(&i->timeout)) {
131                         nf_ct_unlink_expect(i);
132                         nf_ct_expect_put(i);
133                 }
134         }
135 }
136 EXPORT_SYMBOL_GPL(nf_ct_remove_expectations);
137
138 /* Would two expected things clash? */
139 static inline int expect_clash(const struct nf_conntrack_expect *a,
140                                const struct nf_conntrack_expect *b)
141 {
142         /* Part covered by intersection of masks must be unequal,
143            otherwise they clash */
144         struct nf_conntrack_tuple_mask intersect_mask;
145         int count;
146
147         intersect_mask.src.u.all = a->mask.src.u.all & b->mask.src.u.all;
148
149         for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++){
150                 intersect_mask.src.u3.all[count] =
151                         a->mask.src.u3.all[count] & b->mask.src.u3.all[count];
152         }
153
154         return nf_ct_tuple_mask_cmp(&a->tuple, &b->tuple, &intersect_mask);
155 }
156
157 static inline int expect_matches(const struct nf_conntrack_expect *a,
158                                  const struct nf_conntrack_expect *b)
159 {
160         return a->master == b->master
161                 && nf_ct_tuple_equal(&a->tuple, &b->tuple)
162                 && nf_ct_tuple_mask_equal(&a->mask, &b->mask);
163 }
164
165 /* Generally a bad idea to call this: could have matched already. */
166 void nf_ct_unexpect_related(struct nf_conntrack_expect *exp)
167 {
168         write_lock_bh(&nf_conntrack_lock);
169         if (del_timer(&exp->timeout)) {
170                 nf_ct_unlink_expect(exp);
171                 nf_ct_expect_put(exp);
172         }
173         write_unlock_bh(&nf_conntrack_lock);
174 }
175 EXPORT_SYMBOL_GPL(nf_ct_unexpect_related);
176
177 /* We don't increase the master conntrack refcount for non-fulfilled
178  * conntracks. During the conntrack destruction, the expectations are
179  * always killed before the conntrack itself */
180 struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me)
181 {
182         struct nf_conntrack_expect *new;
183
184         new = kmem_cache_alloc(nf_ct_expect_cachep, GFP_ATOMIC);
185         if (!new)
186                 return NULL;
187
188         new->master = me;
189         atomic_set(&new->use, 1);
190         return new;
191 }
192 EXPORT_SYMBOL_GPL(nf_ct_expect_alloc);
193
194 void nf_ct_expect_init(struct nf_conntrack_expect *exp, int family,
195                        union nf_conntrack_address *saddr,
196                        union nf_conntrack_address *daddr,
197                        u_int8_t proto, __be16 *src, __be16 *dst)
198 {
199         int len;
200
201         if (family == AF_INET)
202                 len = 4;
203         else
204                 len = 16;
205
206         exp->flags = 0;
207         exp->expectfn = NULL;
208         exp->helper = NULL;
209         exp->tuple.src.l3num = family;
210         exp->tuple.dst.protonum = proto;
211
212         if (saddr) {
213                 memcpy(&exp->tuple.src.u3, saddr, len);
214                 if (sizeof(exp->tuple.src.u3) > len)
215                         /* address needs to be cleared for nf_ct_tuple_equal */
216                         memset((void *)&exp->tuple.src.u3 + len, 0x00,
217                                sizeof(exp->tuple.src.u3) - len);
218                 memset(&exp->mask.src.u3, 0xFF, len);
219                 if (sizeof(exp->mask.src.u3) > len)
220                         memset((void *)&exp->mask.src.u3 + len, 0x00,
221                                sizeof(exp->mask.src.u3) - len);
222         } else {
223                 memset(&exp->tuple.src.u3, 0x00, sizeof(exp->tuple.src.u3));
224                 memset(&exp->mask.src.u3, 0x00, sizeof(exp->mask.src.u3));
225         }
226
227         if (src) {
228                 exp->tuple.src.u.all = (__force u16)*src;
229                 exp->mask.src.u.all = 0xFFFF;
230         } else {
231                 exp->tuple.src.u.all = 0;
232                 exp->mask.src.u.all = 0;
233         }
234
235         memcpy(&exp->tuple.dst.u3, daddr, len);
236         if (sizeof(exp->tuple.dst.u3) > len)
237                 /* address needs to be cleared for nf_ct_tuple_equal */
238                 memset((void *)&exp->tuple.dst.u3 + len, 0x00,
239                        sizeof(exp->tuple.dst.u3) - len);
240
241         exp->tuple.dst.u.all = (__force u16)*dst;
242 }
243 EXPORT_SYMBOL_GPL(nf_ct_expect_init);
244
245 void nf_ct_expect_put(struct nf_conntrack_expect *exp)
246 {
247         if (atomic_dec_and_test(&exp->use))
248                 kmem_cache_free(nf_ct_expect_cachep, exp);
249 }
250 EXPORT_SYMBOL_GPL(nf_ct_expect_put);
251
252 static void nf_ct_expect_insert(struct nf_conntrack_expect *exp)
253 {
254         struct nf_conn_help *master_help = nfct_help(exp->master);
255
256         atomic_inc(&exp->use);
257         master_help->expecting++;
258         list_add(&exp->list, &nf_ct_expect_list);
259
260         setup_timer(&exp->timeout, nf_ct_expectation_timed_out,
261                     (unsigned long)exp);
262         exp->timeout.expires = jiffies + master_help->helper->timeout * HZ;
263         add_timer(&exp->timeout);
264
265         exp->id = ++nf_ct_expect_next_id;
266         atomic_inc(&exp->use);
267         NF_CT_STAT_INC(expect_create);
268 }
269
270 /* Race with expectations being used means we could have none to find; OK. */
271 static void evict_oldest_expect(struct nf_conn *master)
272 {
273         struct nf_conntrack_expect *i;
274
275         list_for_each_entry_reverse(i, &nf_ct_expect_list, list) {
276                 if (i->master == master) {
277                         if (del_timer(&i->timeout)) {
278                                 nf_ct_unlink_expect(i);
279                                 nf_ct_expect_put(i);
280                         }
281                         break;
282                 }
283         }
284 }
285
286 static inline int refresh_timer(struct nf_conntrack_expect *i)
287 {
288         struct nf_conn_help *master_help = nfct_help(i->master);
289
290         if (!del_timer(&i->timeout))
291                 return 0;
292
293         i->timeout.expires = jiffies + master_help->helper->timeout*HZ;
294         add_timer(&i->timeout);
295         return 1;
296 }
297
298 int nf_ct_expect_related(struct nf_conntrack_expect *expect)
299 {
300         struct nf_conntrack_expect *i;
301         struct nf_conn *master = expect->master;
302         struct nf_conn_help *master_help = nfct_help(master);
303         int ret;
304
305         NF_CT_ASSERT(master_help);
306
307         write_lock_bh(&nf_conntrack_lock);
308         if (!master_help->helper) {
309                 ret = -ESHUTDOWN;
310                 goto out;
311         }
312         list_for_each_entry(i, &nf_ct_expect_list, list) {
313                 if (expect_matches(i, expect)) {
314                         /* Refresh timer: if it's dying, ignore.. */
315                         if (refresh_timer(i)) {
316                                 ret = 0;
317                                 goto out;
318                         }
319                 } else if (expect_clash(i, expect)) {
320                         ret = -EBUSY;
321                         goto out;
322                 }
323         }
324         /* Will be over limit? */
325         if (master_help->helper->max_expected &&
326             master_help->expecting >= master_help->helper->max_expected)
327                 evict_oldest_expect(master);
328
329         nf_ct_expect_insert(expect);
330         nf_ct_expect_event(IPEXP_NEW, expect);
331         ret = 0;
332 out:
333         write_unlock_bh(&nf_conntrack_lock);
334         return ret;
335 }
336 EXPORT_SYMBOL_GPL(nf_ct_expect_related);
337
338 #ifdef CONFIG_PROC_FS
339 static void *exp_seq_start(struct seq_file *s, loff_t *pos)
340 {
341         struct list_head *e = &nf_ct_expect_list;
342         loff_t i;
343
344         /* strange seq_file api calls stop even if we fail,
345          * thus we need to grab lock since stop unlocks */
346         read_lock_bh(&nf_conntrack_lock);
347
348         if (list_empty(e))
349                 return NULL;
350
351         for (i = 0; i <= *pos; i++) {
352                 e = e->next;
353                 if (e == &nf_ct_expect_list)
354                         return NULL;
355         }
356         return e;
357 }
358
359 static void *exp_seq_next(struct seq_file *s, void *v, loff_t *pos)
360 {
361         struct list_head *e = v;
362
363         ++*pos;
364         e = e->next;
365
366         if (e == &nf_ct_expect_list)
367                 return NULL;
368
369         return e;
370 }
371
372 static void exp_seq_stop(struct seq_file *s, void *v)
373 {
374         read_unlock_bh(&nf_conntrack_lock);
375 }
376
377 static int exp_seq_show(struct seq_file *s, void *v)
378 {
379         struct nf_conntrack_expect *expect = v;
380
381         if (expect->timeout.function)
382                 seq_printf(s, "%ld ", timer_pending(&expect->timeout)
383                            ? (long)(expect->timeout.expires - jiffies)/HZ : 0);
384         else
385                 seq_printf(s, "- ");
386         seq_printf(s, "l3proto = %u proto=%u ",
387                    expect->tuple.src.l3num,
388                    expect->tuple.dst.protonum);
389         print_tuple(s, &expect->tuple,
390                     __nf_ct_l3proto_find(expect->tuple.src.l3num),
391                     __nf_ct_l4proto_find(expect->tuple.src.l3num,
392                                        expect->tuple.dst.protonum));
393         return seq_putc(s, '\n');
394 }
395
396 static struct seq_operations exp_seq_ops = {
397         .start = exp_seq_start,
398         .next = exp_seq_next,
399         .stop = exp_seq_stop,
400         .show = exp_seq_show
401 };
402
403 static int exp_open(struct inode *inode, struct file *file)
404 {
405         return seq_open(file, &exp_seq_ops);
406 }
407
408 const struct file_operations exp_file_ops = {
409         .owner   = THIS_MODULE,
410         .open    = exp_open,
411         .read    = seq_read,
412         .llseek  = seq_lseek,
413         .release = seq_release
414 };
415 #endif /* CONFIG_PROC_FS */
416
417 static int __init exp_proc_init(void)
418 {
419 #ifdef CONFIG_PROC_FS
420         struct proc_dir_entry *proc;
421
422         proc = proc_net_fops_create("nf_conntrack_expect", 0440, &exp_file_ops);
423         if (!proc)
424                 return -ENOMEM;
425 #endif /* CONFIG_PROC_FS */
426         return 0;
427 }
428
429 static void exp_proc_remove(void)
430 {
431 #ifdef CONFIG_PROC_FS
432         proc_net_remove("nf_conntrack_expect");
433 #endif /* CONFIG_PROC_FS */
434 }
435
436 int __init nf_conntrack_expect_init(void)
437 {
438         int err;
439
440         nf_ct_expect_cachep = kmem_cache_create("nf_conntrack_expect",
441                                         sizeof(struct nf_conntrack_expect),
442                                         0, 0, NULL, NULL);
443         if (!nf_ct_expect_cachep)
444                 return -ENOMEM;
445
446         err = exp_proc_init();
447         if (err < 0)
448                 goto err1;
449
450         return 0;
451
452 err1:
453         kmem_cache_destroy(nf_ct_expect_cachep);
454         return err;
455 }
456
457 void nf_conntrack_expect_fini(void)
458 {
459         exp_proc_remove();
460         kmem_cache_destroy(nf_ct_expect_cachep);
461 }