Staging: batman-adv: fix minor orig table layout bug
[safe/jmp/linux-2.6] / drivers / staging / batman-adv / proc.c
1 /*
2  * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
3  *
4  * Marek Lindner, Simon Wunderlich
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of version 2 of the GNU General Public
8  * License as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18  * 02110-1301, USA
19  *
20  */
21
22 #include "main.h"
23 #include "proc.h"
24 #include "routing.h"
25 #include "translation-table.h"
26 #include "hard-interface.h"
27 #include "types.h"
28 #include "hash.h"
29 #include "vis.h"
30 #include "compat.h"
31
32 static uint8_t vis_format = DOT_DRAW;
33
34 static struct proc_dir_entry *proc_batman_dir, *proc_interface_file;
35 static struct proc_dir_entry *proc_orig_interval_file, *proc_originators_file;
36 static struct proc_dir_entry *proc_transt_local_file;
37 static struct proc_dir_entry *proc_transt_global_file;
38 static struct proc_dir_entry *proc_vis_file, *proc_vis_format_file;
39 static struct proc_dir_entry *proc_aggr_file;
40
41 static int proc_interfaces_read(struct seq_file *seq, void *offset)
42 {
43         struct batman_if *batman_if;
44
45         rcu_read_lock();
46         list_for_each_entry_rcu(batman_if, &if_list, list) {
47                 seq_printf(seq, "[%8s] %s %s \n",
48                            (batman_if->if_active == IF_ACTIVE ?
49                             "active" : "inactive"),
50                            batman_if->dev,
51                            (batman_if->if_active == IF_ACTIVE ?
52                             batman_if->addr_str : " "));
53         }
54         rcu_read_unlock();
55
56         return 0;
57 }
58
59 static int proc_interfaces_open(struct inode *inode, struct file *file)
60 {
61         return single_open(file, proc_interfaces_read, NULL);
62 }
63
64 static ssize_t proc_interfaces_write(struct file *instance,
65                                      const char __user *userbuffer,
66                                      size_t count, loff_t *data)
67 {
68         char *if_string, *colon_ptr = NULL, *cr_ptr = NULL;
69         int not_copied = 0, if_num = 0;
70         struct batman_if *batman_if = NULL;
71
72         if_string = kmalloc(count, GFP_KERNEL);
73
74         if (!if_string)
75                 return -ENOMEM;
76
77         if (count > IFNAMSIZ - 1) {
78                 printk(KERN_WARNING "batman-adv:Can't add interface: device name is too long\n");
79                 goto end;
80         }
81
82         not_copied = copy_from_user(if_string, userbuffer, count);
83         if_string[count - not_copied - 1] = 0;
84
85         colon_ptr = strchr(if_string, ':');
86         if (colon_ptr)
87                 *colon_ptr = 0;
88
89         if (!colon_ptr) {
90                 cr_ptr = strchr(if_string, '\n');
91                 if (cr_ptr)
92                         *cr_ptr = 0;
93         }
94
95         if (strlen(if_string) == 0) {
96                 shutdown_module();
97                 num_ifs = 0;
98                 goto end;
99         }
100
101         /* add interface */
102         rcu_read_lock();
103         list_for_each_entry_rcu(batman_if, &if_list, list) {
104                 if (strncmp(batman_if->dev, if_string, count) == 0) {
105                         printk(KERN_ERR "batman-adv:Given interface is already active: %s\n", if_string);
106                         rcu_read_unlock();
107                         goto end;
108
109                 }
110
111                 if_num++;
112         }
113         rcu_read_unlock();
114
115         hardif_add_interface(if_string, if_num);
116
117         if ((atomic_read(&module_state) == MODULE_INACTIVE) &&
118             (hardif_get_active_if_num() > 0))
119                 activate_module();
120
121         rcu_read_lock();
122         if (list_empty(&if_list)) {
123                 rcu_read_unlock();
124                 goto end;
125         }
126         rcu_read_unlock();
127
128         num_ifs = if_num + 1;
129         return count;
130
131 end:
132         kfree(if_string);
133         return count;
134 }
135
136 static int proc_orig_interval_read(struct seq_file *seq, void *offset)
137 {
138         seq_printf(seq, "%i\n", atomic_read(&originator_interval));
139
140         return 0;
141 }
142
143 static ssize_t proc_orig_interval_write(struct file *file,
144                                         const char __user *buffer,
145                                         size_t count, loff_t *ppos)
146 {
147         char *interval_string;
148         int not_copied = 0;
149         unsigned long originator_interval_tmp;
150         int retval;
151
152         interval_string = kmalloc(count, GFP_KERNEL);
153
154         if (!interval_string)
155                 return -ENOMEM;
156
157         not_copied = copy_from_user(interval_string, buffer, count);
158         interval_string[count - not_copied - 1] = 0;
159
160         retval = strict_strtoul(interval_string, 10, &originator_interval_tmp);
161         if (retval) {
162                 printk(KERN_ERR "batman-adv:New originator interval invalid\n");
163                 goto end;
164         }
165
166         if (originator_interval_tmp <= JITTER * 2) {
167                 printk(KERN_WARNING "batman-adv:New originator interval too small: %li (min: %i)\n",
168                        originator_interval_tmp, JITTER * 2);
169                 goto end;
170         }
171
172         printk(KERN_INFO "batman-adv:Changing originator interval from: %i to: %li\n",
173                atomic_read(&originator_interval), originator_interval_tmp);
174
175         atomic_set(&originator_interval, originator_interval_tmp);
176
177 end:
178         kfree(interval_string);
179         return count;
180 }
181
182 static int proc_orig_interval_open(struct inode *inode, struct file *file)
183 {
184         return single_open(file, proc_orig_interval_read, NULL);
185 }
186
187 static int proc_originators_read(struct seq_file *seq, void *offset)
188 {
189         HASHIT(hashit);
190         struct orig_node *orig_node;
191         struct neigh_node *neigh_node;
192         int batman_count = 0;
193         char orig_str[ETH_STR_LEN], router_str[ETH_STR_LEN];
194
195         rcu_read_lock();
196         if (list_empty(&if_list)) {
197                 rcu_read_unlock();
198                 seq_printf(seq, "BATMAN disabled - please specify interfaces to enable it \n");
199                 goto end;
200         }
201
202         if (((struct batman_if *)if_list.next)->if_active != IF_ACTIVE) {
203                 rcu_read_unlock();
204                 seq_printf(seq, "BATMAN disabled - primary interface not active \n");
205                 goto end;
206         }
207
208         seq_printf(seq,
209                    "  %-14s (%s/%i) %17s [%10s]: %20s ... [B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%s] \n",
210                    "Originator", "#", TQ_MAX_VALUE, "Nexthop", "outgoingIF",
211                    "Potential nexthops", SOURCE_VERSION, REVISION_VERSION_STR,
212                    ((struct batman_if *)if_list.next)->dev,
213                    ((struct batman_if *)if_list.next)->addr_str);
214
215         rcu_read_unlock();
216         spin_lock(&orig_hash_lock);
217
218         while (hash_iterate(orig_hash, &hashit)) {
219
220                 orig_node = hashit.bucket->data;
221
222                 if (!orig_node->router)
223                         continue;
224
225                 if (orig_node->router->tq_avg == 0)
226                         continue;
227
228                 batman_count++;
229
230                 addr_to_string(orig_str, orig_node->orig);
231                 addr_to_string(router_str, orig_node->router->addr);
232
233                 seq_printf(seq, "%-17s  (%3i) %17s [%10s]:",
234                            orig_str, orig_node->router->tq_avg,
235                            router_str, orig_node->router->if_incoming->dev);
236
237                 list_for_each_entry(neigh_node, &orig_node->neigh_list, list) {
238                         addr_to_string(orig_str, neigh_node->addr);
239                         seq_printf(seq, " %17s (%3i)",
240                                    orig_str, neigh_node->tq_avg);
241                 }
242
243                 seq_printf(seq, "\n");
244
245         }
246
247         spin_unlock(&orig_hash_lock);
248
249         if (batman_count == 0)
250                 seq_printf(seq, "No batman nodes in range ... \n");
251
252 end:
253         return 0;
254 }
255
256 static int proc_originators_open(struct inode *inode, struct file *file)
257 {
258         return single_open(file, proc_originators_read, NULL);
259 }
260
261 static int proc_transt_local_read(struct seq_file *seq, void *offset)
262 {
263         char *buf;
264
265         buf = kmalloc(4096, GFP_KERNEL);
266         if (!buf)
267                 return 0;
268
269         rcu_read_lock();
270         if (list_empty(&if_list)) {
271                 rcu_read_unlock();
272                 seq_printf(seq, "BATMAN disabled - please specify interfaces to enable it \n");
273                 goto end;
274         }
275
276         rcu_read_unlock();
277
278         seq_printf(seq, "Locally retrieved addresses (from %s) announced via HNA:\n", soft_device->name);
279
280         hna_local_fill_buffer_text(buf, 4096);
281         seq_printf(seq, "%s", buf);
282
283 end:
284         kfree(buf);
285         return 0;
286 }
287
288 static int proc_transt_local_open(struct inode *inode, struct file *file)
289 {
290         return single_open(file, proc_transt_local_read, NULL);
291 }
292
293 static int proc_transt_global_read(struct seq_file *seq, void *offset)
294 {
295         char *buf;
296
297         buf = kmalloc(4096, GFP_KERNEL);
298         if (!buf)
299                 return 0;
300
301         rcu_read_lock();
302         if (list_empty(&if_list)) {
303                 rcu_read_unlock();
304                 seq_printf(seq, "BATMAN disabled - please specify interfaces to enable it \n");
305                 goto end;
306         }
307         rcu_read_unlock();
308
309
310         seq_printf(seq, "Globally announced HNAs received via the mesh (translation table):\n");
311
312         hna_global_fill_buffer_text(buf, 4096);
313         seq_printf(seq, "%s", buf);
314
315 end:
316         kfree(buf);
317         return 0;
318 }
319
320 static int proc_transt_global_open(struct inode *inode, struct file *file)
321 {
322         return single_open(file, proc_transt_global_read, NULL);
323 }
324
325 /* insert interface to the list of interfaces of one originator */
326
327 static void proc_vis_insert_interface(const uint8_t *interface,
328                                       struct vis_if_list **if_entry,
329                                       bool primary)
330 {
331         /* Did we get an empty list? (then insert imediately) */
332         if (*if_entry == NULL) {
333                 *if_entry = kmalloc(sizeof(struct vis_if_list), GFP_KERNEL);
334                 if (*if_entry == NULL)
335                         return;
336
337                 (*if_entry)->primary = primary;
338                 (*if_entry)->next = NULL;
339                 memcpy((*if_entry)->addr, interface, ETH_ALEN);
340         } else {
341                 struct vis_if_list *head_if_entry = *if_entry;
342                 /* Do we already have this interface in our list? */
343                 while (!compare_orig((*if_entry)->addr, (void *)interface)) {
344
345                         /* Or did we reach the end (then append the interface) */
346                         if ((*if_entry)->next == NULL) {
347                                 (*if_entry)->next = kmalloc(sizeof(struct vis_if_list), GFP_KERNEL);
348                                 if ((*if_entry)->next == NULL)
349                                         return;
350
351                                 memcpy((*if_entry)->next->addr, interface, ETH_ALEN);
352                                 (*if_entry)->next->primary = primary;
353                                 (*if_entry)->next->next = NULL;
354                                 break;
355                         }
356                         *if_entry = (*if_entry)->next;
357                 }
358                 /* Rewind the list to its head */
359                 *if_entry = head_if_entry;
360         }
361 }
362 /* read an entry  */
363
364 static void proc_vis_read_entry(struct seq_file *seq,
365                                 struct vis_info_entry *entry,
366                                 struct vis_if_list **if_entry,
367                                 uint8_t *vis_orig,
368                                 uint8_t current_format,
369                                 uint8_t first_line)
370 {
371         char from[40];
372         char to[40];
373         int int_part, frac_part;
374
375         addr_to_string(to, entry->dest);
376         if (entry->quality == 0) {
377 #ifndef VIS_SUBCLUSTERS_DISABLED
378                 proc_vis_insert_interface(vis_orig, if_entry, true);
379 #endif /* VIS_SUBCLUSTERS_DISABLED */
380                 addr_to_string(from, vis_orig);
381                 if (current_format == DOT_DRAW) {
382                         seq_printf(seq, "\t\"%s\" -> \"%s\" [label=\"HNA\"]\n",
383                                    from, to);
384                 } else {
385                         seq_printf(seq,
386                                    "%s\t{ router : \"%s\", gateway   : \"%s\", label : \"HNA\" }",
387                                    (first_line ? "" : ",\n"), from, to);
388                 }
389         } else {
390 #ifndef VIS_SUBCLUSTERS_DISABLED
391                 proc_vis_insert_interface(entry->src, if_entry, compare_orig(entry->src, vis_orig));
392 #endif /* VIS_SUBCLUSTERS_DISABLED */
393                 addr_to_string(from, entry->src);
394
395                 /* kernel has no printf-support for %f? it'd be better to return
396                  * this in float. */
397
398                 int_part = TQ_MAX_VALUE / entry->quality;
399                 frac_part = 1000 * TQ_MAX_VALUE / entry->quality - int_part * 1000;
400
401                 if (current_format == DOT_DRAW) {
402                         seq_printf(seq,
403                                    "\t\"%s\" -> \"%s\" [label=\"%d.%d\"]\n",
404                                    from, to, int_part, frac_part);
405                 } else {
406                         seq_printf(seq,
407                                    "%s\t{ router : \"%s\", neighbor : \"%s\", label : %d.%d }",
408                                    (first_line ? "" : ",\n"), from, to, int_part, frac_part);
409                 }
410         }
411 }
412
413
414 static int proc_vis_read(struct seq_file *seq, void *offset)
415 {
416         HASHIT(hashit);
417         struct vis_info *info;
418         struct vis_info_entry *entries;
419         struct vis_if_list *if_entries = NULL;
420         int i;
421         uint8_t current_format, first_line = 1;
422 #ifndef VIS_SUBCLUSTERS_DISABLED
423         char tmp_addr_str[ETH_STR_LEN];
424         struct vis_if_list *tmp_if_next;
425 #endif /* VIS_SUBCLUSTERS_DISABLED */
426
427         current_format = vis_format;
428
429         rcu_read_lock();
430         if (list_empty(&if_list) || (!is_vis_server())) {
431                 rcu_read_unlock();
432                 if (current_format == DOT_DRAW)
433                         seq_printf(seq, "digraph {\n}\n");
434                 goto end;
435         }
436
437         rcu_read_unlock();
438
439         if (current_format == DOT_DRAW)
440                 seq_printf(seq, "digraph {\n");
441
442         spin_lock(&vis_hash_lock);
443         while (hash_iterate(vis_hash, &hashit)) {
444                 info = hashit.bucket->data;
445                 entries = (struct vis_info_entry *)
446                         ((char *)info + sizeof(struct vis_info));
447
448                 for (i = 0; i < info->packet.entries; i++) {
449                         proc_vis_read_entry(seq, &entries[i], &if_entries,
450                                             info->packet.vis_orig,
451                                             current_format, first_line);
452                         if (first_line)
453                                 first_line = 0;
454                 }
455
456 #ifndef VIS_SUBCLUSTERS_DISABLED
457                 /* Generate subgraphs from the collected items */
458                 if (current_format == DOT_DRAW) {
459
460                         addr_to_string(tmp_addr_str, info->packet.vis_orig);
461                         seq_printf(seq, "\tsubgraph \"cluster_%s\" {\n", tmp_addr_str);
462                         while (if_entries != NULL) {
463
464                                 addr_to_string(tmp_addr_str, if_entries->addr);
465                                 if (if_entries->primary)
466                                         seq_printf(seq, "\t\t\"%s\" [peripheries=2]\n", tmp_addr_str);
467                                 else
468                                         seq_printf(seq, "\t\t\"%s\"\n", tmp_addr_str);
469
470                                 /* ... and empty the list while doing this */
471                                 tmp_if_next = if_entries->next;
472                                 kfree(if_entries);
473                                 if_entries = tmp_if_next;
474                         }
475                         seq_printf(seq, "\t}\n");
476                 }
477 #endif /* VIS_SUBCLUSTERS_DISABLED */
478         }
479         spin_unlock(&vis_hash_lock);
480
481         if (current_format == DOT_DRAW)
482                 seq_printf(seq, "}\n");
483         else
484                 seq_printf(seq, "\n");
485 end:
486         return 0;
487 }
488
489 /* setting the mode of the vis server by the user */
490 static ssize_t proc_vis_write(struct file *file, const char __user * buffer,
491                               size_t count, loff_t *ppos)
492 {
493         char *vis_mode_string;
494         int not_copied = 0;
495
496         vis_mode_string = kmalloc(count, GFP_KERNEL);
497
498         if (!vis_mode_string)
499                 return -ENOMEM;
500
501         not_copied = copy_from_user(vis_mode_string, buffer, count);
502         vis_mode_string[count - not_copied - 1] = 0;
503
504         if (strcmp(vis_mode_string, "client") == 0) {
505                 printk(KERN_INFO "batman-adv:Setting VIS mode to client\n");
506                 vis_set_mode(VIS_TYPE_CLIENT_UPDATE);
507         } else if (strcmp(vis_mode_string, "server") == 0) {
508                 printk(KERN_INFO "batman-adv:Setting VIS mode to server\n");
509                 vis_set_mode(VIS_TYPE_SERVER_SYNC);
510         } else
511                 printk(KERN_ERR "batman-adv:Unknown VIS mode: %s\n",
512                        vis_mode_string);
513
514         kfree(vis_mode_string);
515         return count;
516 }
517
518 static int proc_vis_open(struct inode *inode, struct file *file)
519 {
520         return single_open(file, proc_vis_read, NULL);
521 }
522
523 static int proc_vis_format_read(struct seq_file *seq, void *offset)
524 {
525         uint8_t current_format = vis_format;
526
527         seq_printf(seq, "[%c] %s\n",
528                    (current_format == DOT_DRAW) ? 'x' : ' ',
529                    VIS_FORMAT_DD_NAME);
530         seq_printf(seq, "[%c] %s\n",
531                    (current_format == JSON) ? 'x' : ' ',
532                    VIS_FORMAT_JSON_NAME);
533         return 0;
534 }
535
536 static int proc_vis_format_open(struct inode *inode, struct file *file)
537 {
538         return single_open(file, proc_vis_format_read, NULL);
539 }
540
541 static ssize_t proc_vis_format_write(struct file *file,
542                                      const char __user *buffer,
543                                      size_t count, loff_t *ppos)
544 {
545         char *vis_format_string;
546         int not_copied = 0;
547
548         vis_format_string = kmalloc(count, GFP_KERNEL);
549
550         if (!vis_format_string)
551                 return -ENOMEM;
552
553         not_copied = copy_from_user(vis_format_string, buffer, count);
554         vis_format_string[count - not_copied - 1] = 0;
555
556         if (strcmp(vis_format_string, VIS_FORMAT_DD_NAME) == 0) {
557                 printk(KERN_INFO "batman-adv:Setting VIS output format to: %s\n",
558                        VIS_FORMAT_DD_NAME);
559                 vis_format = DOT_DRAW;
560         } else if (strcmp(vis_format_string, VIS_FORMAT_JSON_NAME) == 0) {
561                 printk(KERN_INFO "batman-adv:Setting VIS output format to: %s\n",
562                        VIS_FORMAT_JSON_NAME);
563                 vis_format = JSON;
564         } else
565                 printk(KERN_ERR "batman-adv:Unknown VIS output format: %s\n",
566                        vis_format_string);
567
568         kfree(vis_format_string);
569         return count;
570 }
571
572 static int proc_aggr_read(struct seq_file *seq, void *offset)
573 {
574         seq_printf(seq, "%i\n", atomic_read(&aggregation_enabled));
575
576         return 0;
577 }
578
579 static ssize_t proc_aggr_write(struct file *file, const char __user *buffer,
580                                size_t count, loff_t *ppos)
581 {
582         char *aggr_string;
583         int not_copied = 0;
584         unsigned long aggregation_enabled_tmp;
585
586         aggr_string = kmalloc(count, GFP_KERNEL);
587
588         if (!aggr_string)
589                 return -ENOMEM;
590
591         not_copied = copy_from_user(aggr_string, buffer, count);
592         aggr_string[count - not_copied - 1] = 0;
593
594         strict_strtoul(aggr_string, 10, &aggregation_enabled_tmp);
595
596         if ((aggregation_enabled_tmp != 0) && (aggregation_enabled_tmp != 1)) {
597                 printk(KERN_ERR "batman-adv:Aggregation can only be enabled (1) or disabled (0), given value: %li\n", aggregation_enabled_tmp);
598                 goto end;
599         }
600
601         printk(KERN_INFO "batman-adv:Changing aggregation from: %s (%i) to: %s (%li)\n",
602                (atomic_read(&aggregation_enabled) == 1 ?
603                 "enabled" : "disabled"),
604                atomic_read(&aggregation_enabled),
605                (aggregation_enabled_tmp == 1 ? "enabled" : "disabled"),
606                aggregation_enabled_tmp);
607
608         atomic_set(&aggregation_enabled, (unsigned)aggregation_enabled_tmp);
609 end:
610         kfree(aggr_string);
611         return count;
612 }
613
614 static int proc_aggr_open(struct inode *inode, struct file *file)
615 {
616         return single_open(file, proc_aggr_read, NULL);
617 }
618
619 /* satisfying different prototypes ... */
620 static ssize_t proc_dummy_write(struct file *file, const char __user *buffer,
621                                 size_t count, loff_t *ppos)
622 {
623         return count;
624 }
625
626 static const struct file_operations proc_aggr_fops = {
627         .owner          = THIS_MODULE,
628         .open           = proc_aggr_open,
629         .read           = seq_read,
630         .write          = proc_aggr_write,
631         .llseek         = seq_lseek,
632         .release        = single_release,
633 };
634
635 static const struct file_operations proc_vis_format_fops = {
636         .owner          = THIS_MODULE,
637         .open           = proc_vis_format_open,
638         .read           = seq_read,
639         .write          = proc_vis_format_write,
640         .llseek         = seq_lseek,
641         .release        = single_release,
642 };
643
644 static const struct file_operations proc_vis_fops = {
645         .owner          = THIS_MODULE,
646         .open           = proc_vis_open,
647         .read           = seq_read,
648         .write          = proc_vis_write,
649         .llseek         = seq_lseek,
650         .release        = single_release,
651 };
652
653 static const struct file_operations proc_originators_fops = {
654         .owner          = THIS_MODULE,
655         .open           = proc_originators_open,
656         .read           = seq_read,
657         .write          = proc_dummy_write,
658         .llseek         = seq_lseek,
659         .release        = single_release,
660 };
661
662 static const struct file_operations proc_transt_local_fops = {
663         .owner          = THIS_MODULE,
664         .open           = proc_transt_local_open,
665         .read           = seq_read,
666         .write          = proc_dummy_write,
667         .llseek         = seq_lseek,
668         .release        = single_release,
669 };
670
671 static const struct file_operations proc_transt_global_fops = {
672         .owner          = THIS_MODULE,
673         .open           = proc_transt_global_open,
674         .read           = seq_read,
675         .write          = proc_dummy_write,
676         .llseek         = seq_lseek,
677         .release        = single_release,
678 };
679
680 static const struct file_operations proc_interfaces_fops = {
681         .owner          = THIS_MODULE,
682         .open           = proc_interfaces_open,
683         .read           = seq_read,
684         .write          = proc_interfaces_write,
685         .llseek         = seq_lseek,
686         .release        = single_release,
687 };
688
689 static const struct file_operations proc_orig_interval_fops = {
690         .owner          = THIS_MODULE,
691         .open           = proc_orig_interval_open,
692         .read           = seq_read,
693         .write          = proc_orig_interval_write,
694         .llseek         = seq_lseek,
695         .release        = single_release,
696 };
697
698 void cleanup_procfs(void)
699 {
700         if (proc_transt_global_file)
701                 remove_proc_entry(PROC_FILE_TRANST_GLOBAL, proc_batman_dir);
702
703         if (proc_transt_local_file)
704                 remove_proc_entry(PROC_FILE_TRANST_LOCAL, proc_batman_dir);
705
706         if (proc_originators_file)
707                 remove_proc_entry(PROC_FILE_ORIGINATORS, proc_batman_dir);
708
709         if (proc_orig_interval_file)
710                 remove_proc_entry(PROC_FILE_ORIG_INTERVAL, proc_batman_dir);
711
712         if (proc_interface_file)
713                 remove_proc_entry(PROC_FILE_INTERFACES, proc_batman_dir);
714
715         if (proc_vis_file)
716                 remove_proc_entry(PROC_FILE_VIS, proc_batman_dir);
717
718         if (proc_vis_format_file)
719                 remove_proc_entry(PROC_FILE_VIS_FORMAT, proc_batman_dir);
720
721         if (proc_aggr_file)
722                 remove_proc_entry(PROC_FILE_AGGR, proc_batman_dir);
723
724         if (proc_batman_dir)
725 #ifdef __NET_NET_NAMESPACE_H
726                 remove_proc_entry(PROC_ROOT_DIR, init_net.proc_net);
727 #else
728                 remove_proc_entry(PROC_ROOT_DIR, proc_net);
729 #endif
730 }
731
732 int setup_procfs(void)
733 {
734 #ifdef __NET_NET_NAMESPACE_H
735         proc_batman_dir = proc_mkdir(PROC_ROOT_DIR, init_net.proc_net);
736 #else
737         proc_batman_dir = proc_mkdir(PROC_ROOT_DIR, proc_net);
738 #endif
739
740         if (!proc_batman_dir) {
741                 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s' folder failed\n", PROC_ROOT_DIR);
742                 return -EFAULT;
743         }
744
745         proc_interface_file = create_proc_entry(PROC_FILE_INTERFACES,
746                                                 S_IWUSR | S_IRUGO,
747                                                 proc_batman_dir);
748         if (proc_interface_file) {
749                 proc_interface_file->proc_fops = &proc_interfaces_fops;
750         } else {
751                 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_INTERFACES);
752                 cleanup_procfs();
753                 return -EFAULT;
754         }
755
756         proc_orig_interval_file = create_proc_entry(PROC_FILE_ORIG_INTERVAL,
757                                                     S_IWUSR | S_IRUGO,
758                                                     proc_batman_dir);
759         if (proc_orig_interval_file) {
760                 proc_orig_interval_file->proc_fops = &proc_orig_interval_fops;
761         } else {
762                 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_ORIG_INTERVAL);
763                 cleanup_procfs();
764                 return -EFAULT;
765         }
766
767         proc_originators_file = create_proc_entry(PROC_FILE_ORIGINATORS,
768                                                   S_IRUGO, proc_batman_dir);
769         if (proc_originators_file) {
770                 proc_originators_file->proc_fops = &proc_originators_fops;
771         } else {
772                 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_ORIGINATORS);
773                 cleanup_procfs();
774                 return -EFAULT;
775         }
776
777         proc_transt_local_file = create_proc_entry(PROC_FILE_TRANST_LOCAL,
778                                                    S_IRUGO, proc_batman_dir);
779         if (proc_transt_local_file) {
780                 proc_transt_local_file->proc_fops = &proc_transt_local_fops;
781         } else {
782                 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_TRANST_LOCAL);
783                 cleanup_procfs();
784                 return -EFAULT;
785         }
786
787         proc_transt_global_file = create_proc_entry(PROC_FILE_TRANST_GLOBAL,
788                                                     S_IRUGO, proc_batman_dir);
789         if (proc_transt_global_file) {
790                 proc_transt_global_file->proc_fops = &proc_transt_global_fops;
791         } else {
792                 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_TRANST_GLOBAL);
793                 cleanup_procfs();
794                 return -EFAULT;
795         }
796
797         proc_vis_file = create_proc_entry(PROC_FILE_VIS, S_IWUSR | S_IRUGO,
798                                           proc_batman_dir);
799         if (proc_vis_file) {
800                 proc_vis_file->proc_fops = &proc_vis_fops;
801         } else {
802                 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_VIS);
803                 cleanup_procfs();
804                 return -EFAULT;
805         }
806
807         proc_vis_format_file = create_proc_entry(PROC_FILE_VIS_FORMAT,
808                                                  S_IWUSR | S_IRUGO,
809                                                  proc_batman_dir);
810         if (proc_vis_format_file) {
811                 proc_vis_format_file->proc_fops = &proc_vis_format_fops;
812         } else {
813                 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_VIS_FORMAT);
814                 cleanup_procfs();
815                 return -EFAULT;
816         }
817
818         proc_aggr_file = create_proc_entry(PROC_FILE_AGGR, S_IWUSR | S_IRUGO,
819                                            proc_batman_dir);
820         if (proc_aggr_file) {
821                 proc_aggr_file->proc_fops = &proc_aggr_fops;
822         } else {
823                 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_AGGR);
824                 cleanup_procfs();
825                 return -EFAULT;
826         }
827
828         return 0;
829 }
830
831