2 * Copyright (C) 2007-2009 B.A.T.M.A.N. contributors:
4 * Marek Lindner, Simon Wunderlich
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.
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.
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
25 #include "translation-table.h"
26 #include "hard-interface.h"
32 static uint8_t vis_format
= DOT_DRAW
;
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
;
41 static int proc_interfaces_read(struct seq_file
*seq
, void *offset
)
43 struct batman_if
*batman_if
;
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"),
51 (batman_if
->if_active
== IF_ACTIVE
?
52 batman_if
->addr_str
: " "));
59 static int proc_interfaces_open(struct inode
*inode
, struct file
*file
)
61 return single_open(file
, proc_interfaces_read
, NULL
);
64 static ssize_t
proc_interfaces_write(struct file
*instance
,
65 const char __user
*userbuffer
,
66 size_t count
, loff_t
*data
)
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
;
72 if_string
= kmalloc(count
, GFP_KERNEL
);
77 if (count
> IFNAMSIZ
- 1) {
78 printk(KERN_WARNING
"batman-adv:Can't add interface: device name is too long\n");
82 not_copied
= copy_from_user(if_string
, userbuffer
, count
);
83 if_string
[count
- not_copied
- 1] = 0;
85 colon_ptr
= strchr(if_string
, ':');
90 cr_ptr
= strchr(if_string
, '\n');
95 if (strlen(if_string
) == 0) {
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
);
115 hardif_add_interface(if_string
, if_num
);
117 if ((atomic_read(&module_state
) == MODULE_INACTIVE
) &&
118 (hardif_get_active_if_num() > 0))
122 if (list_empty(&if_list
)) {
128 num_ifs
= if_num
+ 1;
136 static int proc_orig_interval_read(struct seq_file
*seq
, void *offset
)
138 seq_printf(seq
, "%i\n", atomic_read(&originator_interval
));
143 static ssize_t
proc_orig_interval_write(struct file
*file
,
144 const char __user
*buffer
,
145 size_t count
, loff_t
*ppos
)
147 char *interval_string
;
149 unsigned long originator_interval_tmp
;
152 interval_string
= kmalloc(count
, GFP_KERNEL
);
154 if (!interval_string
)
157 not_copied
= copy_from_user(interval_string
, buffer
, count
);
158 interval_string
[count
- not_copied
- 1] = 0;
160 retval
= strict_strtoul(interval_string
, 10, &originator_interval_tmp
);
162 printk(KERN_ERR
"batman-adv:New originator interval invalid\n");
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);
172 printk(KERN_INFO
"batman-adv:Changing originator interval from: %i to: %li\n",
173 atomic_read(&originator_interval
), originator_interval_tmp
);
175 atomic_set(&originator_interval
, originator_interval_tmp
);
178 kfree(interval_string
);
182 static int proc_orig_interval_open(struct inode
*inode
, struct file
*file
)
184 return single_open(file
, proc_orig_interval_read
, NULL
);
187 static int proc_originators_read(struct seq_file
*seq
, void *offset
)
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
];
196 if (list_empty(&if_list
)) {
198 seq_printf(seq
, "BATMAN disabled - please specify interfaces to enable it \n");
202 if (((struct batman_if
*)if_list
.next
)->if_active
!= IF_ACTIVE
) {
204 seq_printf(seq
, "BATMAN disabled - primary interface not active \n");
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
);
216 spin_lock(&orig_hash_lock
);
218 while (hash_iterate(orig_hash
, &hashit
)) {
220 orig_node
= hashit
.bucket
->data
;
222 if (!orig_node
->router
)
225 if (orig_node
->router
->tq_avg
== 0)
230 addr_to_string(orig_str
, orig_node
->orig
);
231 addr_to_string(router_str
, orig_node
->router
->addr
);
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
);
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
);
243 seq_printf(seq
, "\n");
247 spin_unlock(&orig_hash_lock
);
249 if (batman_count
== 0)
250 seq_printf(seq
, "No batman nodes in range ... \n");
256 static int proc_originators_open(struct inode
*inode
, struct file
*file
)
258 return single_open(file
, proc_originators_read
, NULL
);
261 static int proc_transt_local_read(struct seq_file
*seq
, void *offset
)
265 buf
= kmalloc(4096, GFP_KERNEL
);
270 if (list_empty(&if_list
)) {
272 seq_printf(seq
, "BATMAN disabled - please specify interfaces to enable it \n");
278 seq_printf(seq
, "Locally retrieved addresses (from %s) announced via HNA:\n", soft_device
->name
);
280 hna_local_fill_buffer_text(buf
, 4096);
281 seq_printf(seq
, "%s", buf
);
288 static int proc_transt_local_open(struct inode
*inode
, struct file
*file
)
290 return single_open(file
, proc_transt_local_read
, NULL
);
293 static int proc_transt_global_read(struct seq_file
*seq
, void *offset
)
297 buf
= kmalloc(4096, GFP_KERNEL
);
302 if (list_empty(&if_list
)) {
304 seq_printf(seq
, "BATMAN disabled - please specify interfaces to enable it \n");
310 seq_printf(seq
, "Globally announced HNAs received via the mesh (translation table):\n");
312 hna_global_fill_buffer_text(buf
, 4096);
313 seq_printf(seq
, "%s", buf
);
320 static int proc_transt_global_open(struct inode
*inode
, struct file
*file
)
322 return single_open(file
, proc_transt_global_read
, NULL
);
325 /* insert interface to the list of interfaces of one originator */
327 static void proc_vis_insert_interface(const uint8_t *interface
,
328 struct vis_if_list
**if_entry
,
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
)
337 (*if_entry
)->primary
= primary
;
338 (*if_entry
)->next
= NULL
;
339 memcpy((*if_entry
)->addr
, interface
, ETH_ALEN
);
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
)) {
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
)
351 memcpy((*if_entry
)->next
->addr
, interface
, ETH_ALEN
);
352 (*if_entry
)->next
->primary
= primary
;
353 (*if_entry
)->next
->next
= NULL
;
356 *if_entry
= (*if_entry
)->next
;
358 /* Rewind the list to its head */
359 *if_entry
= head_if_entry
;
364 static void proc_vis_read_entry(struct seq_file
*seq
,
365 struct vis_info_entry
*entry
,
366 struct vis_if_list
**if_entry
,
368 uint8_t current_format
,
373 int int_part
, frac_part
;
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",
386 "%s\t{ router : \"%s\", gateway : \"%s\", label : \"HNA\" }",
387 (first_line
? "" : ",\n"), from
, to
);
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
);
395 /* kernel has no printf-support for %f? it'd be better to return
398 int_part
= TQ_MAX_VALUE
/ entry
->quality
;
399 frac_part
= 1000 * TQ_MAX_VALUE
/ entry
->quality
- int_part
* 1000;
401 if (current_format
== DOT_DRAW
) {
403 "\t\"%s\" -> \"%s\" [label=\"%d.%d\"]\n",
404 from
, to
, int_part
, frac_part
);
407 "%s\t{ router : \"%s\", neighbour : \"%s\", label : %d.%d }",
408 (first_line
? "" : ",\n"), from
, to
, int_part
, frac_part
);
414 static int proc_vis_read(struct seq_file
*seq
, void *offset
)
417 struct vis_info
*info
;
418 struct vis_info_entry
*entries
;
419 struct vis_if_list
*if_entries
= NULL
;
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 */
427 current_format
= vis_format
;
430 if (list_empty(&if_list
) || (!is_vis_server())) {
432 if (current_format
== DOT_DRAW
)
433 seq_printf(seq
, "digraph {\n}\n");
439 if (current_format
== DOT_DRAW
)
440 seq_printf(seq
, "digraph {\n");
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
));
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
);
456 #ifndef VIS_SUBCLUSTERS_DISABLED
457 /* Generate subgraphs from the collected items */
458 if (current_format
== DOT_DRAW
) {
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
) {
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
);
468 seq_printf(seq
, "\t\t\"%s\"\n", tmp_addr_str
);
470 /* ... and empty the list while doing this */
471 tmp_if_next
= if_entries
->next
;
473 if_entries
= tmp_if_next
;
475 seq_printf(seq
, "\t}\n");
477 #endif /* VIS_SUBCLUSTERS_DISABLED */
479 spin_unlock(&vis_hash_lock
);
481 if (current_format
== DOT_DRAW
)
482 seq_printf(seq
, "}\n");
484 seq_printf(seq
, "\n");
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
)
493 char *vis_mode_string
;
496 vis_mode_string
= kmalloc(count
, GFP_KERNEL
);
498 if (!vis_mode_string
)
501 not_copied
= copy_from_user(vis_mode_string
, buffer
, count
);
502 vis_mode_string
[count
- not_copied
- 1] = 0;
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
);
511 printk(KERN_ERR
"batman-adv:Unknown VIS mode: %s\n",
514 kfree(vis_mode_string
);
518 static int proc_vis_open(struct inode
*inode
, struct file
*file
)
520 return single_open(file
, proc_vis_read
, NULL
);
523 static int proc_vis_format_read(struct seq_file
*seq
, void *offset
)
525 uint8_t current_format
= vis_format
;
527 seq_printf(seq
, "[%c] %s\n",
528 (current_format
== DOT_DRAW
) ? 'x' : ' ',
530 seq_printf(seq
, "[%c] %s\n",
531 (current_format
== JSON
) ? 'x' : ' ',
532 VIS_FORMAT_JSON_NAME
);
536 static int proc_vis_format_open(struct inode
*inode
, struct file
*file
)
538 return single_open(file
, proc_vis_format_read
, NULL
);
541 static ssize_t
proc_vis_format_write(struct file
*file
,
542 const char __user
*buffer
,
543 size_t count
, loff_t
*ppos
)
545 char *vis_format_string
;
548 vis_format_string
= kmalloc(count
, GFP_KERNEL
);
550 if (!vis_format_string
)
553 not_copied
= copy_from_user(vis_format_string
, buffer
, count
);
554 vis_format_string
[count
- not_copied
- 1] = 0;
556 if (strcmp(vis_format_string
, VIS_FORMAT_DD_NAME
) == 0) {
557 printk(KERN_INFO
"batman-adv:Setting VIS output format to: %s\n",
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
);
565 printk(KERN_ERR
"batman-adv:Unknown VIS output format: %s\n",
568 kfree(vis_format_string
);
572 static int proc_aggr_read(struct seq_file
*seq
, void *offset
)
574 seq_printf(seq
, "%i\n", atomic_read(&aggregation_enabled
));
579 static ssize_t
proc_aggr_write(struct file
*file
, const char __user
*buffer
,
580 size_t count
, loff_t
*ppos
)
584 unsigned long aggregation_enabled_tmp
;
586 aggr_string
= kmalloc(count
, GFP_KERNEL
);
591 not_copied
= copy_from_user(aggr_string
, buffer
, count
);
592 aggr_string
[count
- not_copied
- 1] = 0;
594 strict_strtoul(aggr_string
, 10, &aggregation_enabled_tmp
);
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
);
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
);
608 atomic_set(&aggregation_enabled
, (unsigned)aggregation_enabled_tmp
);
614 static int proc_aggr_open(struct inode
*inode
, struct file
*file
)
616 return single_open(file
, proc_aggr_read
, NULL
);
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
)
626 static const struct file_operations proc_aggr_fops
= {
627 .owner
= THIS_MODULE
,
628 .open
= proc_aggr_open
,
630 .write
= proc_aggr_write
,
632 .release
= single_release
,
635 static const struct file_operations proc_vis_format_fops
= {
636 .owner
= THIS_MODULE
,
637 .open
= proc_vis_format_open
,
639 .write
= proc_vis_format_write
,
641 .release
= single_release
,
644 static const struct file_operations proc_vis_fops
= {
645 .owner
= THIS_MODULE
,
646 .open
= proc_vis_open
,
648 .write
= proc_vis_write
,
650 .release
= single_release
,
653 static const struct file_operations proc_originators_fops
= {
654 .owner
= THIS_MODULE
,
655 .open
= proc_originators_open
,
657 .write
= proc_dummy_write
,
659 .release
= single_release
,
662 static const struct file_operations proc_transt_local_fops
= {
663 .owner
= THIS_MODULE
,
664 .open
= proc_transt_local_open
,
666 .write
= proc_dummy_write
,
668 .release
= single_release
,
671 static const struct file_operations proc_transt_global_fops
= {
672 .owner
= THIS_MODULE
,
673 .open
= proc_transt_global_open
,
675 .write
= proc_dummy_write
,
677 .release
= single_release
,
680 static const struct file_operations proc_interfaces_fops
= {
681 .owner
= THIS_MODULE
,
682 .open
= proc_interfaces_open
,
684 .write
= proc_interfaces_write
,
686 .release
= single_release
,
689 static const struct file_operations proc_orig_interval_fops
= {
690 .owner
= THIS_MODULE
,
691 .open
= proc_orig_interval_open
,
693 .write
= proc_orig_interval_write
,
695 .release
= single_release
,
698 void cleanup_procfs(void)
700 if (proc_transt_global_file
)
701 remove_proc_entry(PROC_FILE_TRANST_GLOBAL
, proc_batman_dir
);
703 if (proc_transt_local_file
)
704 remove_proc_entry(PROC_FILE_TRANST_LOCAL
, proc_batman_dir
);
706 if (proc_originators_file
)
707 remove_proc_entry(PROC_FILE_ORIGINATORS
, proc_batman_dir
);
709 if (proc_orig_interval_file
)
710 remove_proc_entry(PROC_FILE_ORIG_INTERVAL
, proc_batman_dir
);
712 if (proc_interface_file
)
713 remove_proc_entry(PROC_FILE_INTERFACES
, proc_batman_dir
);
716 remove_proc_entry(PROC_FILE_VIS
, proc_batman_dir
);
718 if (proc_vis_format_file
)
719 remove_proc_entry(PROC_FILE_VIS_FORMAT
, proc_batman_dir
);
722 remove_proc_entry(PROC_FILE_AGGR
, proc_batman_dir
);
725 #ifdef __NET_NET_NAMESPACE_H
726 remove_proc_entry(PROC_ROOT_DIR
, init_net
.proc_net
);
728 remove_proc_entry(PROC_ROOT_DIR
, proc_net
);
732 int setup_procfs(void)
734 #ifdef __NET_NET_NAMESPACE_H
735 proc_batman_dir
= proc_mkdir(PROC_ROOT_DIR
, init_net
.proc_net
);
737 proc_batman_dir
= proc_mkdir(PROC_ROOT_DIR
, proc_net
);
740 if (!proc_batman_dir
) {
741 printk(KERN_ERR
"batman-adv: Registering the '/proc/net/%s' folder failed\n", PROC_ROOT_DIR
);
745 proc_interface_file
= create_proc_entry(PROC_FILE_INTERFACES
,
748 if (proc_interface_file
) {
749 proc_interface_file
->proc_fops
= &proc_interfaces_fops
;
751 printk(KERN_ERR
"batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR
, PROC_FILE_INTERFACES
);
756 proc_orig_interval_file
= create_proc_entry(PROC_FILE_ORIG_INTERVAL
,
759 if (proc_orig_interval_file
) {
760 proc_orig_interval_file
->proc_fops
= &proc_orig_interval_fops
;
762 printk(KERN_ERR
"batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR
, PROC_FILE_ORIG_INTERVAL
);
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
;
772 printk(KERN_ERR
"batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR
, PROC_FILE_ORIGINATORS
);
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
;
782 printk(KERN_ERR
"batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR
, PROC_FILE_TRANST_LOCAL
);
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
;
792 printk(KERN_ERR
"batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR
, PROC_FILE_TRANST_GLOBAL
);
797 proc_vis_file
= create_proc_entry(PROC_FILE_VIS
, S_IWUSR
| S_IRUGO
,
800 proc_vis_file
->proc_fops
= &proc_vis_fops
;
802 printk(KERN_ERR
"batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR
, PROC_FILE_VIS
);
807 proc_vis_format_file
= create_proc_entry(PROC_FILE_VIS_FORMAT
,
810 if (proc_vis_format_file
) {
811 proc_vis_format_file
->proc_fops
= &proc_vis_format_fops
;
813 printk(KERN_ERR
"batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR
, PROC_FILE_VIS_FORMAT
);
818 proc_aggr_file
= create_proc_entry(PROC_FILE_AGGR
, S_IWUSR
| S_IRUGO
,
820 if (proc_aggr_file
) {
821 proc_aggr_file
->proc_fops
= &proc_aggr_fops
;
823 printk(KERN_ERR
"batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR
, PROC_FILE_AGGR
);