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];
195 if (list_empty(&if_list)) {
197 seq_printf(seq, "BATMAN disabled - please specify interfaces to enable it \n");
201 if (((struct batman_if *)if_list.next)->if_active != IF_ACTIVE) {
203 seq_printf(seq, "BATMAN disabled - primary interface not active \n");
208 " %-14s (%s/%i) %17s [%10s]: %20s ... [B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%s] \n",
209 "Originator", "#", TQ_MAX_VALUE, "Nexthop", "outgoingIF",
210 "Potential nexthops", SOURCE_VERSION, REVISION_VERSION_STR,
211 ((struct batman_if *)if_list.next)->dev,
212 ((struct batman_if *)if_list.next)->addr_str);
215 spin_lock_irqsave(&orig_hash_lock, flags);
217 while (hash_iterate(orig_hash, &hashit)) {
219 orig_node = hashit.bucket->data;
221 if (!orig_node->router)
224 if (orig_node->router->tq_avg == 0)
229 addr_to_string(orig_str, orig_node->orig);
230 addr_to_string(router_str, orig_node->router->addr);
232 seq_printf(seq, "%-17s (%3i) %17s [%10s]:",
233 orig_str, orig_node->router->tq_avg,
234 router_str, orig_node->router->if_incoming->dev);
236 list_for_each_entry(neigh_node, &orig_node->neigh_list, list) {
237 addr_to_string(orig_str, neigh_node->addr);
238 seq_printf(seq, " %17s (%3i)",
239 orig_str, neigh_node->tq_avg);
242 seq_printf(seq, "\n");
246 spin_unlock_irqrestore(&orig_hash_lock, flags);
248 if (batman_count == 0)
249 seq_printf(seq, "No batman nodes in range ... \n");
255 static int proc_originators_open(struct inode *inode, struct file *file)
257 return single_open(file, proc_originators_read, NULL);
260 static int proc_transt_local_read(struct seq_file *seq, void *offset)
264 buf = kmalloc(4096, GFP_KERNEL);
269 if (list_empty(&if_list)) {
271 seq_printf(seq, "BATMAN disabled - please specify interfaces to enable it \n");
277 seq_printf(seq, "Locally retrieved addresses (from %s) announced via HNA:\n", soft_device->name);
279 hna_local_fill_buffer_text(buf, 4096);
280 seq_printf(seq, "%s", buf);
287 static int proc_transt_local_open(struct inode *inode, struct file *file)
289 return single_open(file, proc_transt_local_read, NULL);
292 static int proc_transt_global_read(struct seq_file *seq, void *offset)
296 buf = kmalloc(4096, GFP_KERNEL);
301 if (list_empty(&if_list)) {
303 seq_printf(seq, "BATMAN disabled - please specify interfaces to enable it \n");
309 seq_printf(seq, "Globally announced HNAs received via the mesh (translation table):\n");
311 hna_global_fill_buffer_text(buf, 4096);
312 seq_printf(seq, "%s", buf);
319 static int proc_transt_global_open(struct inode *inode, struct file *file)
321 return single_open(file, proc_transt_global_read, NULL);
324 /* setting the mode of the vis server by the user */
325 static ssize_t proc_vis_srv_write(struct file *file, const char __user * buffer,
326 size_t count, loff_t *ppos)
328 char *vis_mode_string;
331 vis_mode_string = kmalloc(count, GFP_KERNEL);
333 if (!vis_mode_string)
336 not_copied = copy_from_user(vis_mode_string, buffer, count);
337 vis_mode_string[count - not_copied - 1] = 0;
339 if ((strcmp(vis_mode_string, "client") == 0) ||
340 (strcmp(vis_mode_string, "disabled") == 0)) {
341 printk(KERN_INFO "batman-adv:Setting VIS mode to client (disabling vis server)\n");
342 vis_set_mode(VIS_TYPE_CLIENT_UPDATE);
343 } else if ((strcmp(vis_mode_string, "server") == 0) ||
344 (strcmp(vis_mode_string, "enabled") == 0)) {
345 printk(KERN_INFO "batman-adv:Setting VIS mode to server (enabling vis server)\n");
346 vis_set_mode(VIS_TYPE_SERVER_SYNC);
348 printk(KERN_ERR "batman-adv:Unknown VIS mode: %s\n",
351 kfree(vis_mode_string);
355 static int proc_vis_srv_read(struct seq_file *seq, void *offset)
357 int vis_server = is_vis_server();
359 seq_printf(seq, "[%c] client mode (server disabled) \n",
360 (!vis_server) ? 'x' : ' ');
361 seq_printf(seq, "[%c] server mode (server enabled) \n",
362 (vis_server) ? 'x' : ' ');
367 static int proc_vis_srv_open(struct inode *inode, struct file *file)
369 return single_open(file, proc_vis_srv_read, NULL);
372 static int proc_vis_data_read(struct seq_file *seq, void *offset)
375 struct vis_info *info;
376 struct vis_info_entry *entries;
377 HLIST_HEAD(vis_if_list);
379 char tmp_addr_str[ETH_STR_LEN];
383 if (list_empty(&if_list) || (!is_vis_server())) {
390 spin_lock_irqsave(&vis_hash_lock, flags);
391 while (hash_iterate(vis_hash, &hashit)) {
392 info = hashit.bucket->data;
393 entries = (struct vis_info_entry *)
394 ((char *)info + sizeof(struct vis_info));
395 addr_to_string(tmp_addr_str, info->packet.vis_orig);
396 seq_printf(seq, "%s,", tmp_addr_str);
398 for (i = 0; i < info->packet.entries; i++) {
399 proc_vis_read_entry(seq, &entries[i], &vis_if_list,
400 info->packet.vis_orig);
403 /* add primary/secondary records */
404 proc_vis_read_prim_sec(seq, &vis_if_list);
405 seq_printf(seq, "\n");
407 spin_unlock_irqrestore(&vis_hash_lock, flags);
413 static int proc_vis_data_open(struct inode *inode, struct file *file)
415 return single_open(file, proc_vis_data_read, NULL);
418 static int proc_aggr_read(struct seq_file *seq, void *offset)
420 seq_printf(seq, "%i\n", atomic_read(&aggregation_enabled));
425 static ssize_t proc_aggr_write(struct file *file, const char __user *buffer,
426 size_t count, loff_t *ppos)
430 unsigned long aggregation_enabled_tmp;
432 aggr_string = kmalloc(count, GFP_KERNEL);
437 not_copied = copy_from_user(aggr_string, buffer, count);
438 aggr_string[count - not_copied - 1] = 0;
440 strict_strtoul(aggr_string, 10, &aggregation_enabled_tmp);
442 if ((aggregation_enabled_tmp != 0) && (aggregation_enabled_tmp != 1)) {
443 printk(KERN_ERR "batman-adv:Aggregation can only be enabled (1) or disabled (0), given value: %li\n", aggregation_enabled_tmp);
447 printk(KERN_INFO "batman-adv:Changing aggregation from: %s (%i) to: %s (%li)\n",
448 (atomic_read(&aggregation_enabled) == 1 ?
449 "enabled" : "disabled"),
450 atomic_read(&aggregation_enabled),
451 (aggregation_enabled_tmp == 1 ? "enabled" : "disabled"),
452 aggregation_enabled_tmp);
454 atomic_set(&aggregation_enabled, (unsigned)aggregation_enabled_tmp);
460 static int proc_aggr_open(struct inode *inode, struct file *file)
462 return single_open(file, proc_aggr_read, NULL);
465 /* satisfying different prototypes ... */
466 static ssize_t proc_dummy_write(struct file *file, const char __user *buffer,
467 size_t count, loff_t *ppos)
472 static const struct file_operations proc_aggr_fops = {
473 .owner = THIS_MODULE,
474 .open = proc_aggr_open,
476 .write = proc_aggr_write,
478 .release = single_release,
481 static const struct file_operations proc_vis_srv_fops = {
482 .owner = THIS_MODULE,
483 .open = proc_vis_srv_open,
485 .write = proc_vis_srv_write,
487 .release = single_release,
490 static const struct file_operations proc_vis_data_fops = {
491 .owner = THIS_MODULE,
492 .open = proc_vis_data_open,
494 .write = proc_dummy_write,
496 .release = single_release,
499 static const struct file_operations proc_originators_fops = {
500 .owner = THIS_MODULE,
501 .open = proc_originators_open,
503 .write = proc_dummy_write,
505 .release = single_release,
508 static const struct file_operations proc_transt_local_fops = {
509 .owner = THIS_MODULE,
510 .open = proc_transt_local_open,
512 .write = proc_dummy_write,
514 .release = single_release,
517 static const struct file_operations proc_transt_global_fops = {
518 .owner = THIS_MODULE,
519 .open = proc_transt_global_open,
521 .write = proc_dummy_write,
523 .release = single_release,
526 static const struct file_operations proc_interfaces_fops = {
527 .owner = THIS_MODULE,
528 .open = proc_interfaces_open,
530 .write = proc_interfaces_write,
532 .release = single_release,
535 static const struct file_operations proc_orig_interval_fops = {
536 .owner = THIS_MODULE,
537 .open = proc_orig_interval_open,
539 .write = proc_orig_interval_write,
541 .release = single_release,
544 void cleanup_procfs(void)
546 if (proc_transt_global_file)
547 remove_proc_entry(PROC_FILE_TRANST_GLOBAL, proc_batman_dir);
549 if (proc_transt_local_file)
550 remove_proc_entry(PROC_FILE_TRANST_LOCAL, proc_batman_dir);
552 if (proc_originators_file)
553 remove_proc_entry(PROC_FILE_ORIGINATORS, proc_batman_dir);
555 if (proc_orig_interval_file)
556 remove_proc_entry(PROC_FILE_ORIG_INTERVAL, proc_batman_dir);
558 if (proc_interface_file)
559 remove_proc_entry(PROC_FILE_INTERFACES, proc_batman_dir);
561 if (proc_vis_data_file)
562 remove_proc_entry(PROC_FILE_VIS_DATA, proc_batman_dir);
564 if (proc_vis_srv_file)
565 remove_proc_entry(PROC_FILE_VIS_SRV, proc_batman_dir);
568 remove_proc_entry(PROC_FILE_AGGR, proc_batman_dir);
571 #ifdef __NET_NET_NAMESPACE_H
572 remove_proc_entry(PROC_ROOT_DIR, init_net.proc_net);
574 remove_proc_entry(PROC_ROOT_DIR, proc_net);
578 int setup_procfs(void)
580 #ifdef __NET_NET_NAMESPACE_H
581 proc_batman_dir = proc_mkdir(PROC_ROOT_DIR, init_net.proc_net);
583 proc_batman_dir = proc_mkdir(PROC_ROOT_DIR, proc_net);
586 if (!proc_batman_dir) {
587 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s' folder failed\n", PROC_ROOT_DIR);
591 proc_interface_file = create_proc_entry(PROC_FILE_INTERFACES,
594 if (proc_interface_file) {
595 proc_interface_file->proc_fops = &proc_interfaces_fops;
597 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_INTERFACES);
602 proc_orig_interval_file = create_proc_entry(PROC_FILE_ORIG_INTERVAL,
605 if (proc_orig_interval_file) {
606 proc_orig_interval_file->proc_fops = &proc_orig_interval_fops;
608 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_ORIG_INTERVAL);
613 proc_originators_file = create_proc_entry(PROC_FILE_ORIGINATORS,
614 S_IRUGO, proc_batman_dir);
615 if (proc_originators_file) {
616 proc_originators_file->proc_fops = &proc_originators_fops;
618 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_ORIGINATORS);
623 proc_transt_local_file = create_proc_entry(PROC_FILE_TRANST_LOCAL,
624 S_IRUGO, proc_batman_dir);
625 if (proc_transt_local_file) {
626 proc_transt_local_file->proc_fops = &proc_transt_local_fops;
628 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_TRANST_LOCAL);
633 proc_transt_global_file = create_proc_entry(PROC_FILE_TRANST_GLOBAL,
634 S_IRUGO, proc_batman_dir);
635 if (proc_transt_global_file) {
636 proc_transt_global_file->proc_fops = &proc_transt_global_fops;
638 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_TRANST_GLOBAL);
643 proc_vis_srv_file = create_proc_entry(PROC_FILE_VIS_SRV,
646 if (proc_vis_srv_file) {
647 proc_vis_srv_file->proc_fops = &proc_vis_srv_fops;
649 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_VIS_SRV);
654 proc_vis_data_file = create_proc_entry(PROC_FILE_VIS_DATA, S_IRUGO,
656 if (proc_vis_data_file) {
657 proc_vis_data_file->proc_fops = &proc_vis_data_fops;
659 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_VIS_DATA);
664 proc_aggr_file = create_proc_entry(PROC_FILE_AGGR, S_IWUSR | S_IRUGO,
666 if (proc_aggr_file) {
667 proc_aggr_file->proc_fops = &proc_aggr_fops;
669 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_AGGR);