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 struct proc_dir_entry *proc_batman_dir, *proc_interface_file;
33 static struct proc_dir_entry *proc_orig_interval_file, *proc_originators_file;
34 static struct proc_dir_entry *proc_transt_local_file;
35 static struct proc_dir_entry *proc_transt_global_file;
36 static struct proc_dir_entry *proc_vis_srv_file, *proc_vis_data_file;
37 static struct proc_dir_entry *proc_aggr_file;
39 static int proc_interfaces_read(struct seq_file *seq, void *offset)
41 struct batman_if *batman_if;
44 list_for_each_entry_rcu(batman_if, &if_list, list) {
45 seq_printf(seq, "[%8s] %s %s \n",
46 (batman_if->if_active == IF_ACTIVE ?
47 "active" : "inactive"),
49 (batman_if->if_active == IF_ACTIVE ?
50 batman_if->addr_str : " "));
57 static int proc_interfaces_open(struct inode *inode, struct file *file)
59 return single_open(file, proc_interfaces_read, NULL);
62 static ssize_t proc_interfaces_write(struct file *instance,
63 const char __user *userbuffer,
64 size_t count, loff_t *data)
66 char *if_string, *colon_ptr = NULL, *cr_ptr = NULL;
67 int not_copied = 0, if_num = 0;
68 struct batman_if *batman_if = NULL;
70 if_string = kmalloc(count, GFP_KERNEL);
75 if (count > IFNAMSIZ - 1) {
76 printk(KERN_WARNING "batman-adv:Can't add interface: device name is too long\n");
80 not_copied = copy_from_user(if_string, userbuffer, count);
81 if_string[count - not_copied - 1] = 0;
83 colon_ptr = strchr(if_string, ':');
88 cr_ptr = strchr(if_string, '\n');
93 if (strlen(if_string) == 0) {
101 list_for_each_entry_rcu(batman_if, &if_list, list) {
102 if (strncmp(batman_if->dev, if_string, count) == 0) {
103 printk(KERN_ERR "batman-adv:Given interface is already active: %s\n", if_string);
113 hardif_add_interface(if_string, if_num);
115 if ((atomic_read(&module_state) == MODULE_INACTIVE) &&
116 (hardif_get_active_if_num() > 0))
120 if (list_empty(&if_list)) {
126 num_ifs = if_num + 1;
134 static int proc_orig_interval_read(struct seq_file *seq, void *offset)
136 seq_printf(seq, "%i\n", atomic_read(&originator_interval));
141 static ssize_t proc_orig_interval_write(struct file *file,
142 const char __user *buffer,
143 size_t count, loff_t *ppos)
145 char *interval_string;
147 unsigned long originator_interval_tmp;
150 interval_string = kmalloc(count, GFP_KERNEL);
152 if (!interval_string)
155 not_copied = copy_from_user(interval_string, buffer, count);
156 interval_string[count - not_copied - 1] = 0;
158 retval = strict_strtoul(interval_string, 10, &originator_interval_tmp);
160 printk(KERN_ERR "batman-adv:New originator interval invalid\n");
164 if (originator_interval_tmp <= JITTER * 2) {
165 printk(KERN_WARNING "batman-adv:New originator interval too small: %li (min: %i)\n",
166 originator_interval_tmp, JITTER * 2);
170 printk(KERN_INFO "batman-adv:Changing originator interval from: %i to: %li\n",
171 atomic_read(&originator_interval), originator_interval_tmp);
173 atomic_set(&originator_interval, originator_interval_tmp);
176 kfree(interval_string);
180 static int proc_orig_interval_open(struct inode *inode, struct file *file)
182 return single_open(file, proc_orig_interval_read, NULL);
185 static int proc_originators_read(struct seq_file *seq, void *offset)
188 struct orig_node *orig_node;
189 struct neigh_node *neigh_node;
190 int batman_count = 0;
191 char orig_str[ETH_STR_LEN], router_str[ETH_STR_LEN];
194 if (list_empty(&if_list)) {
196 seq_printf(seq, "BATMAN disabled - please specify interfaces to enable it \n");
200 if (((struct batman_if *)if_list.next)->if_active != IF_ACTIVE) {
202 seq_printf(seq, "BATMAN disabled - primary interface not active \n");
207 " %-14s (%s/%i) %17s [%10s]: %20s ... [B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%s] \n",
208 "Originator", "#", TQ_MAX_VALUE, "Nexthop", "outgoingIF",
209 "Potential nexthops", SOURCE_VERSION, REVISION_VERSION_STR,
210 ((struct batman_if *)if_list.next)->dev,
211 ((struct batman_if *)if_list.next)->addr_str);
214 spin_lock(&orig_hash_lock);
216 while (hash_iterate(orig_hash, &hashit)) {
218 orig_node = hashit.bucket->data;
220 if (!orig_node->router)
223 if (orig_node->router->tq_avg == 0)
228 addr_to_string(orig_str, orig_node->orig);
229 addr_to_string(router_str, orig_node->router->addr);
231 seq_printf(seq, "%-17s (%3i) %17s [%10s]:",
232 orig_str, orig_node->router->tq_avg,
233 router_str, orig_node->router->if_incoming->dev);
235 list_for_each_entry(neigh_node, &orig_node->neigh_list, list) {
236 addr_to_string(orig_str, neigh_node->addr);
237 seq_printf(seq, " %17s (%3i)",
238 orig_str, neigh_node->tq_avg);
241 seq_printf(seq, "\n");
245 spin_unlock(&orig_hash_lock);
247 if (batman_count == 0)
248 seq_printf(seq, "No batman nodes in range ... \n");
254 static int proc_originators_open(struct inode *inode, struct file *file)
256 return single_open(file, proc_originators_read, NULL);
259 static int proc_transt_local_read(struct seq_file *seq, void *offset)
263 buf = kmalloc(4096, GFP_KERNEL);
268 if (list_empty(&if_list)) {
270 seq_printf(seq, "BATMAN disabled - please specify interfaces to enable it \n");
276 seq_printf(seq, "Locally retrieved addresses (from %s) announced via HNA:\n", soft_device->name);
278 hna_local_fill_buffer_text(buf, 4096);
279 seq_printf(seq, "%s", buf);
286 static int proc_transt_local_open(struct inode *inode, struct file *file)
288 return single_open(file, proc_transt_local_read, NULL);
291 static int proc_transt_global_read(struct seq_file *seq, void *offset)
295 buf = kmalloc(4096, GFP_KERNEL);
300 if (list_empty(&if_list)) {
302 seq_printf(seq, "BATMAN disabled - please specify interfaces to enable it \n");
308 seq_printf(seq, "Globally announced HNAs received via the mesh (translation table):\n");
310 hna_global_fill_buffer_text(buf, 4096);
311 seq_printf(seq, "%s", buf);
318 static int proc_transt_global_open(struct inode *inode, struct file *file)
320 return single_open(file, proc_transt_global_read, NULL);
323 /* setting the mode of the vis server by the user */
324 static ssize_t proc_vis_srv_write(struct file *file, const char __user * buffer,
325 size_t count, loff_t *ppos)
327 char *vis_mode_string;
330 vis_mode_string = kmalloc(count, GFP_KERNEL);
332 if (!vis_mode_string)
335 not_copied = copy_from_user(vis_mode_string, buffer, count);
336 vis_mode_string[count - not_copied - 1] = 0;
338 if ((strcmp(vis_mode_string, "client") == 0) ||
339 (strcmp(vis_mode_string, "disabled") == 0)) {
340 printk(KERN_INFO "batman-adv:Setting VIS mode to client (disabling vis server)\n");
341 vis_set_mode(VIS_TYPE_CLIENT_UPDATE);
342 } else if ((strcmp(vis_mode_string, "server") == 0) ||
343 (strcmp(vis_mode_string, "enabled") == 0)) {
344 printk(KERN_INFO "batman-adv:Setting VIS mode to server (enabling vis server)\n");
345 vis_set_mode(VIS_TYPE_SERVER_SYNC);
347 printk(KERN_ERR "batman-adv:Unknown VIS mode: %s\n",
350 kfree(vis_mode_string);
354 static int proc_vis_srv_read(struct seq_file *seq, void *offset)
356 int vis_server = is_vis_server();
358 seq_printf(seq, "[%c] client mode (server disabled) \n",
359 (!vis_server) ? 'x' : ' ');
360 seq_printf(seq, "[%c] server mode (server enabled) \n",
361 (vis_server) ? 'x' : ' ');
366 static int proc_vis_srv_open(struct inode *inode, struct file *file)
368 return single_open(file, proc_vis_srv_read, NULL);
371 static int proc_vis_data_read(struct seq_file *seq, void *offset)
374 struct vis_info *info;
375 struct vis_info_entry *entries;
376 HLIST_HEAD(vis_if_list);
378 char tmp_addr_str[ETH_STR_LEN];
381 if (list_empty(&if_list) || (!is_vis_server())) {
388 spin_lock(&vis_hash_lock);
389 while (hash_iterate(vis_hash, &hashit)) {
390 info = hashit.bucket->data;
391 entries = (struct vis_info_entry *)
392 ((char *)info + sizeof(struct vis_info));
393 addr_to_string(tmp_addr_str, info->packet.vis_orig);
394 seq_printf(seq, "%s,", tmp_addr_str);
396 for (i = 0; i < info->packet.entries; i++) {
397 proc_vis_read_entry(seq, &entries[i], &vis_if_list,
398 info->packet.vis_orig);
401 /* add primary/secondary records */
402 proc_vis_read_prim_sec(seq, &vis_if_list);
403 seq_printf(seq, "\n");
405 spin_unlock(&vis_hash_lock);
411 static int proc_vis_data_open(struct inode *inode, struct file *file)
413 return single_open(file, proc_vis_data_read, NULL);
416 static int proc_aggr_read(struct seq_file *seq, void *offset)
418 seq_printf(seq, "%i\n", atomic_read(&aggregation_enabled));
423 static ssize_t proc_aggr_write(struct file *file, const char __user *buffer,
424 size_t count, loff_t *ppos)
428 unsigned long aggregation_enabled_tmp;
430 aggr_string = kmalloc(count, GFP_KERNEL);
435 not_copied = copy_from_user(aggr_string, buffer, count);
436 aggr_string[count - not_copied - 1] = 0;
438 strict_strtoul(aggr_string, 10, &aggregation_enabled_tmp);
440 if ((aggregation_enabled_tmp != 0) && (aggregation_enabled_tmp != 1)) {
441 printk(KERN_ERR "batman-adv:Aggregation can only be enabled (1) or disabled (0), given value: %li\n", aggregation_enabled_tmp);
445 printk(KERN_INFO "batman-adv:Changing aggregation from: %s (%i) to: %s (%li)\n",
446 (atomic_read(&aggregation_enabled) == 1 ?
447 "enabled" : "disabled"),
448 atomic_read(&aggregation_enabled),
449 (aggregation_enabled_tmp == 1 ? "enabled" : "disabled"),
450 aggregation_enabled_tmp);
452 atomic_set(&aggregation_enabled, (unsigned)aggregation_enabled_tmp);
458 static int proc_aggr_open(struct inode *inode, struct file *file)
460 return single_open(file, proc_aggr_read, NULL);
463 /* satisfying different prototypes ... */
464 static ssize_t proc_dummy_write(struct file *file, const char __user *buffer,
465 size_t count, loff_t *ppos)
470 static const struct file_operations proc_aggr_fops = {
471 .owner = THIS_MODULE,
472 .open = proc_aggr_open,
474 .write = proc_aggr_write,
476 .release = single_release,
479 static const struct file_operations proc_vis_srv_fops = {
480 .owner = THIS_MODULE,
481 .open = proc_vis_srv_open,
483 .write = proc_vis_srv_write,
485 .release = single_release,
488 static const struct file_operations proc_vis_data_fops = {
489 .owner = THIS_MODULE,
490 .open = proc_vis_data_open,
492 .write = proc_dummy_write,
494 .release = single_release,
497 static const struct file_operations proc_originators_fops = {
498 .owner = THIS_MODULE,
499 .open = proc_originators_open,
501 .write = proc_dummy_write,
503 .release = single_release,
506 static const struct file_operations proc_transt_local_fops = {
507 .owner = THIS_MODULE,
508 .open = proc_transt_local_open,
510 .write = proc_dummy_write,
512 .release = single_release,
515 static const struct file_operations proc_transt_global_fops = {
516 .owner = THIS_MODULE,
517 .open = proc_transt_global_open,
519 .write = proc_dummy_write,
521 .release = single_release,
524 static const struct file_operations proc_interfaces_fops = {
525 .owner = THIS_MODULE,
526 .open = proc_interfaces_open,
528 .write = proc_interfaces_write,
530 .release = single_release,
533 static const struct file_operations proc_orig_interval_fops = {
534 .owner = THIS_MODULE,
535 .open = proc_orig_interval_open,
537 .write = proc_orig_interval_write,
539 .release = single_release,
542 void cleanup_procfs(void)
544 if (proc_transt_global_file)
545 remove_proc_entry(PROC_FILE_TRANST_GLOBAL, proc_batman_dir);
547 if (proc_transt_local_file)
548 remove_proc_entry(PROC_FILE_TRANST_LOCAL, proc_batman_dir);
550 if (proc_originators_file)
551 remove_proc_entry(PROC_FILE_ORIGINATORS, proc_batman_dir);
553 if (proc_orig_interval_file)
554 remove_proc_entry(PROC_FILE_ORIG_INTERVAL, proc_batman_dir);
556 if (proc_interface_file)
557 remove_proc_entry(PROC_FILE_INTERFACES, proc_batman_dir);
559 if (proc_vis_data_file)
560 remove_proc_entry(PROC_FILE_VIS_DATA, proc_batman_dir);
562 if (proc_vis_srv_file)
563 remove_proc_entry(PROC_FILE_VIS_SRV, proc_batman_dir);
566 remove_proc_entry(PROC_FILE_AGGR, proc_batman_dir);
569 #ifdef __NET_NET_NAMESPACE_H
570 remove_proc_entry(PROC_ROOT_DIR, init_net.proc_net);
572 remove_proc_entry(PROC_ROOT_DIR, proc_net);
576 int setup_procfs(void)
578 #ifdef __NET_NET_NAMESPACE_H
579 proc_batman_dir = proc_mkdir(PROC_ROOT_DIR, init_net.proc_net);
581 proc_batman_dir = proc_mkdir(PROC_ROOT_DIR, proc_net);
584 if (!proc_batman_dir) {
585 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s' folder failed\n", PROC_ROOT_DIR);
589 proc_interface_file = create_proc_entry(PROC_FILE_INTERFACES,
592 if (proc_interface_file) {
593 proc_interface_file->proc_fops = &proc_interfaces_fops;
595 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_INTERFACES);
600 proc_orig_interval_file = create_proc_entry(PROC_FILE_ORIG_INTERVAL,
603 if (proc_orig_interval_file) {
604 proc_orig_interval_file->proc_fops = &proc_orig_interval_fops;
606 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_ORIG_INTERVAL);
611 proc_originators_file = create_proc_entry(PROC_FILE_ORIGINATORS,
612 S_IRUGO, proc_batman_dir);
613 if (proc_originators_file) {
614 proc_originators_file->proc_fops = &proc_originators_fops;
616 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_ORIGINATORS);
621 proc_transt_local_file = create_proc_entry(PROC_FILE_TRANST_LOCAL,
622 S_IRUGO, proc_batman_dir);
623 if (proc_transt_local_file) {
624 proc_transt_local_file->proc_fops = &proc_transt_local_fops;
626 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_TRANST_LOCAL);
631 proc_transt_global_file = create_proc_entry(PROC_FILE_TRANST_GLOBAL,
632 S_IRUGO, proc_batman_dir);
633 if (proc_transt_global_file) {
634 proc_transt_global_file->proc_fops = &proc_transt_global_fops;
636 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_TRANST_GLOBAL);
641 proc_vis_srv_file = create_proc_entry(PROC_FILE_VIS_SRV,
644 if (proc_vis_srv_file) {
645 proc_vis_srv_file->proc_fops = &proc_vis_srv_fops;
647 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_VIS_SRV);
652 proc_vis_data_file = create_proc_entry(PROC_FILE_VIS_DATA, S_IRUGO,
654 if (proc_vis_data_file) {
655 proc_vis_data_file->proc_fops = &proc_vis_data_fops;
657 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_VIS_DATA);
662 proc_aggr_file = create_proc_entry(PROC_FILE_AGGR, S_IWUSR | S_IRUGO,
664 if (proc_aggr_file) {
665 proc_aggr_file->proc_fops = &proc_aggr_fops;
667 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_AGGR);