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