Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[pandora-kernel.git] / net / ipv4 / netfilter / nf_conntrack_l3proto_ipv4_compat.c
1 /* ip_conntrack proc compat - based on ip_conntrack_standalone.c
2  *
3  * (C) 1999-2001 Paul `Rusty' Russell
4  * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  */
10 #include <linux/types.h>
11 #include <linux/proc_fs.h>
12 #include <linux/seq_file.h>
13 #include <linux/percpu.h>
14 #include <linux/security.h>
15 #include <net/net_namespace.h>
16
17 #include <linux/netfilter.h>
18 #include <net/netfilter/nf_conntrack_core.h>
19 #include <net/netfilter/nf_conntrack_l3proto.h>
20 #include <net/netfilter/nf_conntrack_l4proto.h>
21 #include <net/netfilter/nf_conntrack_expect.h>
22 #include <net/netfilter/nf_conntrack_acct.h>
23 #include <linux/rculist_nulls.h>
24
25 struct ct_iter_state {
26         struct seq_net_private p;
27         unsigned int bucket;
28 };
29
30 static struct hlist_nulls_node *ct_get_first(struct seq_file *seq)
31 {
32         struct net *net = seq_file_net(seq);
33         struct ct_iter_state *st = seq->private;
34         struct hlist_nulls_node *n;
35
36         for (st->bucket = 0;
37              st->bucket < net->ct.htable_size;
38              st->bucket++) {
39                 n = rcu_dereference(
40                         hlist_nulls_first_rcu(&net->ct.hash[st->bucket]));
41                 if (!is_a_nulls(n))
42                         return n;
43         }
44         return NULL;
45 }
46
47 static struct hlist_nulls_node *ct_get_next(struct seq_file *seq,
48                                       struct hlist_nulls_node *head)
49 {
50         struct net *net = seq_file_net(seq);
51         struct ct_iter_state *st = seq->private;
52
53         head = rcu_dereference(hlist_nulls_next_rcu(head));
54         while (is_a_nulls(head)) {
55                 if (likely(get_nulls_value(head) == st->bucket)) {
56                         if (++st->bucket >= net->ct.htable_size)
57                                 return NULL;
58                 }
59                 head = rcu_dereference(
60                         hlist_nulls_first_rcu(&net->ct.hash[st->bucket]));
61         }
62         return head;
63 }
64
65 static struct hlist_nulls_node *ct_get_idx(struct seq_file *seq, loff_t pos)
66 {
67         struct hlist_nulls_node *head = ct_get_first(seq);
68
69         if (head)
70                 while (pos && (head = ct_get_next(seq, head)))
71                         pos--;
72         return pos ? NULL : head;
73 }
74
75 static void *ct_seq_start(struct seq_file *seq, loff_t *pos)
76         __acquires(RCU)
77 {
78         rcu_read_lock();
79         return ct_get_idx(seq, *pos);
80 }
81
82 static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos)
83 {
84         (*pos)++;
85         return ct_get_next(s, v);
86 }
87
88 static void ct_seq_stop(struct seq_file *s, void *v)
89         __releases(RCU)
90 {
91         rcu_read_unlock();
92 }
93
94 #ifdef CONFIG_NF_CONNTRACK_SECMARK
95 static int ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
96 {
97         int ret;
98         u32 len;
99         char *secctx;
100
101         ret = security_secid_to_secctx(ct->secmark, &secctx, &len);
102         if (ret)
103                 return 0;
104
105         ret = seq_printf(s, "secctx=%s ", secctx);
106
107         security_release_secctx(secctx, len);
108         return ret;
109 }
110 #else
111 static inline int ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
112 {
113         return 0;
114 }
115 #endif
116
117 static int ct_seq_show(struct seq_file *s, void *v)
118 {
119         struct nf_conntrack_tuple_hash *hash = v;
120         struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(hash);
121         const struct nf_conntrack_l3proto *l3proto;
122         const struct nf_conntrack_l4proto *l4proto;
123         int ret = 0;
124
125         NF_CT_ASSERT(ct);
126         if (unlikely(!atomic_inc_not_zero(&ct->ct_general.use)))
127                 return 0;
128
129
130         /* we only want to print DIR_ORIGINAL */
131         if (NF_CT_DIRECTION(hash))
132                 goto release;
133         if (nf_ct_l3num(ct) != AF_INET)
134                 goto release;
135
136         l3proto = __nf_ct_l3proto_find(nf_ct_l3num(ct));
137         NF_CT_ASSERT(l3proto);
138         l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct));
139         NF_CT_ASSERT(l4proto);
140
141         ret = -ENOSPC;
142         if (seq_printf(s, "%-8s %u %ld ",
143                       l4proto->name, nf_ct_protonum(ct),
144                       timer_pending(&ct->timeout)
145                       ? (long)(ct->timeout.expires - jiffies)/HZ : 0) != 0)
146                 goto release;
147
148         if (l4proto->print_conntrack && l4proto->print_conntrack(s, ct))
149                 goto release;
150
151         if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
152                         l3proto, l4proto))
153                 goto release;
154
155         if (seq_print_acct(s, ct, IP_CT_DIR_ORIGINAL))
156                 goto release;
157
158         if (!(test_bit(IPS_SEEN_REPLY_BIT, &ct->status)))
159                 if (seq_printf(s, "[UNREPLIED] "))
160                         goto release;
161
162         if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_REPLY].tuple,
163                         l3proto, l4proto))
164                 goto release;
165
166         if (seq_print_acct(s, ct, IP_CT_DIR_REPLY))
167                 goto release;
168
169         if (test_bit(IPS_ASSURED_BIT, &ct->status))
170                 if (seq_printf(s, "[ASSURED] "))
171                         goto release;
172
173 #ifdef CONFIG_NF_CONNTRACK_MARK
174         if (seq_printf(s, "mark=%u ", ct->mark))
175                 goto release;
176 #endif
177
178         if (ct_show_secctx(s, ct))
179                 goto release;
180
181         if (seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use)))
182                 goto release;
183         ret = 0;
184 release:
185         nf_ct_put(ct);
186         return ret;
187 }
188
189 static const struct seq_operations ct_seq_ops = {
190         .start = ct_seq_start,
191         .next  = ct_seq_next,
192         .stop  = ct_seq_stop,
193         .show  = ct_seq_show
194 };
195
196 static int ct_open(struct inode *inode, struct file *file)
197 {
198         return seq_open_net(inode, file, &ct_seq_ops,
199                             sizeof(struct ct_iter_state));
200 }
201
202 static const struct file_operations ct_file_ops = {
203         .owner   = THIS_MODULE,
204         .open    = ct_open,
205         .read    = seq_read,
206         .llseek  = seq_lseek,
207         .release = seq_release_net,
208 };
209
210 /* expects */
211 struct ct_expect_iter_state {
212         struct seq_net_private p;
213         unsigned int bucket;
214 };
215
216 static struct hlist_node *ct_expect_get_first(struct seq_file *seq)
217 {
218         struct net *net = seq_file_net(seq);
219         struct ct_expect_iter_state *st = seq->private;
220         struct hlist_node *n;
221
222         for (st->bucket = 0; st->bucket < nf_ct_expect_hsize; st->bucket++) {
223                 n = rcu_dereference(
224                         hlist_first_rcu(&net->ct.expect_hash[st->bucket]));
225                 if (n)
226                         return n;
227         }
228         return NULL;
229 }
230
231 static struct hlist_node *ct_expect_get_next(struct seq_file *seq,
232                                              struct hlist_node *head)
233 {
234         struct net *net = seq_file_net(seq);
235         struct ct_expect_iter_state *st = seq->private;
236
237         head = rcu_dereference(hlist_next_rcu(head));
238         while (head == NULL) {
239                 if (++st->bucket >= nf_ct_expect_hsize)
240                         return NULL;
241                 head = rcu_dereference(
242                         hlist_first_rcu(&net->ct.expect_hash[st->bucket]));
243         }
244         return head;
245 }
246
247 static struct hlist_node *ct_expect_get_idx(struct seq_file *seq, loff_t pos)
248 {
249         struct hlist_node *head = ct_expect_get_first(seq);
250
251         if (head)
252                 while (pos && (head = ct_expect_get_next(seq, head)))
253                         pos--;
254         return pos ? NULL : head;
255 }
256
257 static void *exp_seq_start(struct seq_file *seq, loff_t *pos)
258         __acquires(RCU)
259 {
260         rcu_read_lock();
261         return ct_expect_get_idx(seq, *pos);
262 }
263
264 static void *exp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
265 {
266         (*pos)++;
267         return ct_expect_get_next(seq, v);
268 }
269
270 static void exp_seq_stop(struct seq_file *seq, void *v)
271         __releases(RCU)
272 {
273         rcu_read_unlock();
274 }
275
276 static int exp_seq_show(struct seq_file *s, void *v)
277 {
278         struct nf_conntrack_expect *exp;
279         const struct hlist_node *n = v;
280
281         exp = hlist_entry(n, struct nf_conntrack_expect, hnode);
282
283         if (exp->tuple.src.l3num != AF_INET)
284                 return 0;
285
286         if (exp->timeout.function)
287                 seq_printf(s, "%ld ", timer_pending(&exp->timeout)
288                            ? (long)(exp->timeout.expires - jiffies)/HZ : 0);
289         else
290                 seq_printf(s, "- ");
291
292         seq_printf(s, "proto=%u ", exp->tuple.dst.protonum);
293
294         print_tuple(s, &exp->tuple,
295                     __nf_ct_l3proto_find(exp->tuple.src.l3num),
296                     __nf_ct_l4proto_find(exp->tuple.src.l3num,
297                                          exp->tuple.dst.protonum));
298         return seq_putc(s, '\n');
299 }
300
301 static const struct seq_operations exp_seq_ops = {
302         .start = exp_seq_start,
303         .next = exp_seq_next,
304         .stop = exp_seq_stop,
305         .show = exp_seq_show
306 };
307
308 static int exp_open(struct inode *inode, struct file *file)
309 {
310         return seq_open_net(inode, file, &exp_seq_ops,
311                             sizeof(struct ct_expect_iter_state));
312 }
313
314 static const struct file_operations ip_exp_file_ops = {
315         .owner   = THIS_MODULE,
316         .open    = exp_open,
317         .read    = seq_read,
318         .llseek  = seq_lseek,
319         .release = seq_release_net,
320 };
321
322 static void *ct_cpu_seq_start(struct seq_file *seq, loff_t *pos)
323 {
324         struct net *net = seq_file_net(seq);
325         int cpu;
326
327         if (*pos == 0)
328                 return SEQ_START_TOKEN;
329
330         for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) {
331                 if (!cpu_possible(cpu))
332                         continue;
333                 *pos = cpu+1;
334                 return per_cpu_ptr(net->ct.stat, cpu);
335         }
336
337         return NULL;
338 }
339
340 static void *ct_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos)
341 {
342         struct net *net = seq_file_net(seq);
343         int cpu;
344
345         for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
346                 if (!cpu_possible(cpu))
347                         continue;
348                 *pos = cpu+1;
349                 return per_cpu_ptr(net->ct.stat, cpu);
350         }
351
352         return NULL;
353 }
354
355 static void ct_cpu_seq_stop(struct seq_file *seq, void *v)
356 {
357 }
358
359 static int ct_cpu_seq_show(struct seq_file *seq, void *v)
360 {
361         struct net *net = seq_file_net(seq);
362         unsigned int nr_conntracks = atomic_read(&net->ct.count);
363         const struct ip_conntrack_stat *st = v;
364
365         if (v == SEQ_START_TOKEN) {
366                 seq_printf(seq, "entries  searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error  expect_new expect_create expect_delete search_restart\n");
367                 return 0;
368         }
369
370         seq_printf(seq, "%08x  %08x %08x %08x %08x %08x %08x %08x "
371                         "%08x %08x %08x %08x %08x  %08x %08x %08x %08x\n",
372                    nr_conntracks,
373                    st->searched,
374                    st->found,
375                    st->new,
376                    st->invalid,
377                    st->ignore,
378                    st->delete,
379                    st->delete_list,
380                    st->insert,
381                    st->insert_failed,
382                    st->drop,
383                    st->early_drop,
384                    st->error,
385
386                    st->expect_new,
387                    st->expect_create,
388                    st->expect_delete,
389                    st->search_restart
390                 );
391         return 0;
392 }
393
394 static const struct seq_operations ct_cpu_seq_ops = {
395         .start  = ct_cpu_seq_start,
396         .next   = ct_cpu_seq_next,
397         .stop   = ct_cpu_seq_stop,
398         .show   = ct_cpu_seq_show,
399 };
400
401 static int ct_cpu_seq_open(struct inode *inode, struct file *file)
402 {
403         return seq_open_net(inode, file, &ct_cpu_seq_ops,
404                             sizeof(struct seq_net_private));
405 }
406
407 static const struct file_operations ct_cpu_seq_fops = {
408         .owner   = THIS_MODULE,
409         .open    = ct_cpu_seq_open,
410         .read    = seq_read,
411         .llseek  = seq_lseek,
412         .release = seq_release_net,
413 };
414
415 static int __net_init ip_conntrack_net_init(struct net *net)
416 {
417         struct proc_dir_entry *proc, *proc_exp, *proc_stat;
418
419         proc = proc_net_fops_create(net, "ip_conntrack", 0440, &ct_file_ops);
420         if (!proc)
421                 goto err1;
422
423         proc_exp = proc_net_fops_create(net, "ip_conntrack_expect", 0440,
424                                         &ip_exp_file_ops);
425         if (!proc_exp)
426                 goto err2;
427
428         proc_stat = proc_create("ip_conntrack", S_IRUGO,
429                                 net->proc_net_stat, &ct_cpu_seq_fops);
430         if (!proc_stat)
431                 goto err3;
432         return 0;
433
434 err3:
435         proc_net_remove(net, "ip_conntrack_expect");
436 err2:
437         proc_net_remove(net, "ip_conntrack");
438 err1:
439         return -ENOMEM;
440 }
441
442 static void __net_exit ip_conntrack_net_exit(struct net *net)
443 {
444         remove_proc_entry("ip_conntrack", net->proc_net_stat);
445         proc_net_remove(net, "ip_conntrack_expect");
446         proc_net_remove(net, "ip_conntrack");
447 }
448
449 static struct pernet_operations ip_conntrack_net_ops = {
450         .init = ip_conntrack_net_init,
451         .exit = ip_conntrack_net_exit,
452 };
453
454 int __init nf_conntrack_ipv4_compat_init(void)
455 {
456         return register_pernet_subsys(&ip_conntrack_net_ops);
457 }
458
459 void __exit nf_conntrack_ipv4_compat_fini(void)
460 {
461         unregister_pernet_subsys(&ip_conntrack_net_ops);
462 }