2 * Copyright (C) 2007-2010 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"
31 static struct proc_dir_entry *proc_batman_dir, *proc_interface_file;
32 static struct proc_dir_entry *proc_orig_interval_file;
33 static struct proc_dir_entry *proc_vis_srv_file, *proc_vis_data_file;
35 static int proc_interfaces_read(struct seq_file *seq, void *offset)
37 struct batman_if *batman_if;
40 list_for_each_entry_rcu(batman_if, &if_list, list) {
41 seq_printf(seq, "[%8s] %s %s\n",
42 (batman_if->if_active == IF_ACTIVE ?
43 "active" : "inactive"),
45 (batman_if->if_active == IF_ACTIVE ?
46 batman_if->addr_str : " "));
53 static int proc_interfaces_open(struct inode *inode, struct file *file)
55 return single_open(file, proc_interfaces_read, NULL);
58 static ssize_t proc_interfaces_write(struct file *instance,
59 const char __user *userbuffer,
60 size_t count, loff_t *data)
62 char *if_string, *colon_ptr = NULL, *cr_ptr = NULL;
63 int not_copied = 0, if_num = 0, add_success;
64 struct batman_if *batman_if = NULL;
66 if_string = kmalloc(count, GFP_KERNEL);
71 if (count > IFNAMSIZ - 1) {
72 printk(KERN_WARNING "batman-adv:Can't add interface: device name is too long\n");
76 not_copied = copy_from_user(if_string, userbuffer, count);
77 if_string[count - not_copied - 1] = 0;
79 colon_ptr = strchr(if_string, ':');
84 cr_ptr = strchr(if_string, '\n');
89 if (strlen(if_string) == 0) {
97 list_for_each_entry_rcu(batman_if, &if_list, list) {
98 if (strncmp(batman_if->dev, if_string, count) == 0) {
99 printk(KERN_ERR "batman-adv:Given interface is already active: %s\n", if_string);
109 add_success = hardif_add_interface(if_string, if_num);
113 num_ifs = if_num + 1;
115 if ((atomic_read(&module_state) == MODULE_INACTIVE) &&
116 (hardif_get_active_if_num() > 0))
125 static int proc_orig_interval_read(struct seq_file *seq, void *offset)
127 seq_printf(seq, "%i\n", atomic_read(&originator_interval));
132 static ssize_t proc_orig_interval_write(struct file *file,
133 const char __user *buffer,
134 size_t count, loff_t *ppos)
136 char *interval_string;
138 unsigned long originator_interval_tmp;
141 interval_string = kmalloc(count, GFP_KERNEL);
143 if (!interval_string)
146 not_copied = copy_from_user(interval_string, buffer, count);
147 interval_string[count - not_copied - 1] = 0;
149 retval = strict_strtoul(interval_string, 10, &originator_interval_tmp);
151 printk(KERN_ERR "batman-adv:New originator interval invalid\n");
155 if (originator_interval_tmp <= JITTER * 2) {
156 printk(KERN_WARNING "batman-adv:New originator interval too small: %li (min: %i)\n",
157 originator_interval_tmp, JITTER * 2);
161 printk(KERN_INFO "batman-adv:Changing originator interval from: %i to: %li\n",
162 atomic_read(&originator_interval), originator_interval_tmp);
164 atomic_set(&originator_interval, originator_interval_tmp);
167 kfree(interval_string);
171 static int proc_orig_interval_open(struct inode *inode, struct file *file)
173 return single_open(file, proc_orig_interval_read, NULL);
176 /* setting the mode of the vis server by the user */
177 static ssize_t proc_vis_srv_write(struct file *file, const char __user * buffer,
178 size_t count, loff_t *ppos)
180 char *vis_mode_string;
183 vis_mode_string = kmalloc(count, GFP_KERNEL);
185 if (!vis_mode_string)
188 not_copied = copy_from_user(vis_mode_string, buffer, count);
189 vis_mode_string[count - not_copied - 1] = 0;
191 if ((strcmp(vis_mode_string, "client") == 0) ||
192 (strcmp(vis_mode_string, "disabled") == 0)) {
193 printk(KERN_INFO "batman-adv:Setting VIS mode to client (disabling vis server)\n");
194 atomic_set(&vis_mode, VIS_TYPE_CLIENT_UPDATE);
195 } else if ((strcmp(vis_mode_string, "server") == 0) ||
196 (strcmp(vis_mode_string, "enabled") == 0)) {
197 printk(KERN_INFO "batman-adv:Setting VIS mode to server (enabling vis server)\n");
198 atomic_set(&vis_mode, VIS_TYPE_SERVER_SYNC);
200 printk(KERN_ERR "batman-adv:Unknown VIS mode: %s\n",
203 kfree(vis_mode_string);
207 static int proc_vis_srv_read(struct seq_file *seq, void *offset)
209 int vis_server = atomic_read(&vis_mode);
211 seq_printf(seq, "[%c] client mode (server disabled)\n",
212 (vis_server == VIS_TYPE_CLIENT_UPDATE) ? 'x' : ' ');
213 seq_printf(seq, "[%c] server mode (server enabled)\n",
214 (vis_server == VIS_TYPE_SERVER_SYNC) ? 'x' : ' ');
219 static int proc_vis_srv_open(struct inode *inode, struct file *file)
221 return single_open(file, proc_vis_srv_read, NULL);
224 static int proc_vis_data_read(struct seq_file *seq, void *offset)
227 struct vis_info *info;
228 struct vis_info_entry *entries;
229 HLIST_HEAD(vis_if_list);
230 struct if_list_entry *entry;
231 struct hlist_node *pos, *n;
233 char tmp_addr_str[ETH_STR_LEN];
235 int vis_server = atomic_read(&vis_mode);
238 if (list_empty(&if_list) || (vis_server == VIS_TYPE_CLIENT_UPDATE)) {
245 spin_lock_irqsave(&vis_hash_lock, flags);
246 while (hash_iterate(vis_hash, &hashit)) {
247 info = hashit.bucket->data;
248 entries = (struct vis_info_entry *)
249 ((char *)info + sizeof(struct vis_info));
251 for (i = 0; i < info->packet.entries; i++) {
252 if (entries[i].quality == 0)
254 proc_vis_insert_interface(entries[i].src, &vis_if_list,
255 compare_orig(entries[i].src,
256 info->packet.vis_orig));
259 hlist_for_each_entry(entry, pos, &vis_if_list, list) {
260 addr_to_string(tmp_addr_str, entry->addr);
261 seq_printf(seq, "%s,", tmp_addr_str);
263 for (i = 0; i < info->packet.entries; i++)
264 proc_vis_read_entry(seq, &entries[i],
265 entry->addr, entry->primary);
267 /* add primary/secondary records */
268 if (compare_orig(entry->addr, info->packet.vis_orig))
269 proc_vis_read_prim_sec(seq, &vis_if_list);
271 seq_printf(seq, "\n");
274 hlist_for_each_entry_safe(entry, pos, n, &vis_if_list, list) {
275 hlist_del(&entry->list);
279 spin_unlock_irqrestore(&vis_hash_lock, flags);
285 static int proc_vis_data_open(struct inode *inode, struct file *file)
287 return single_open(file, proc_vis_data_read, NULL);
290 /* satisfying different prototypes ... */
291 static ssize_t proc_dummy_write(struct file *file, const char __user *buffer,
292 size_t count, loff_t *ppos)
297 static const struct file_operations proc_vis_srv_fops = {
298 .owner = THIS_MODULE,
299 .open = proc_vis_srv_open,
301 .write = proc_vis_srv_write,
303 .release = single_release,
306 static const struct file_operations proc_vis_data_fops = {
307 .owner = THIS_MODULE,
308 .open = proc_vis_data_open,
310 .write = proc_dummy_write,
312 .release = single_release,
315 static const struct file_operations proc_interfaces_fops = {
316 .owner = THIS_MODULE,
317 .open = proc_interfaces_open,
319 .write = proc_interfaces_write,
321 .release = single_release,
324 static const struct file_operations proc_orig_interval_fops = {
325 .owner = THIS_MODULE,
326 .open = proc_orig_interval_open,
328 .write = proc_orig_interval_write,
330 .release = single_release,
333 void cleanup_procfs(void)
335 if (proc_orig_interval_file)
336 remove_proc_entry(PROC_FILE_ORIG_INTERVAL, proc_batman_dir);
338 if (proc_interface_file)
339 remove_proc_entry(PROC_FILE_INTERFACES, proc_batman_dir);
341 if (proc_vis_data_file)
342 remove_proc_entry(PROC_FILE_VIS_DATA, proc_batman_dir);
344 if (proc_vis_srv_file)
345 remove_proc_entry(PROC_FILE_VIS_SRV, proc_batman_dir);
348 #ifdef __NET_NET_NAMESPACE_H
349 remove_proc_entry(PROC_ROOT_DIR, init_net.proc_net);
351 remove_proc_entry(PROC_ROOT_DIR, proc_net);
355 int setup_procfs(void)
357 #ifdef __NET_NET_NAMESPACE_H
358 proc_batman_dir = proc_mkdir(PROC_ROOT_DIR, init_net.proc_net);
360 proc_batman_dir = proc_mkdir(PROC_ROOT_DIR, proc_net);
363 if (!proc_batman_dir) {
364 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s' folder failed\n", PROC_ROOT_DIR);
368 proc_interface_file = create_proc_entry(PROC_FILE_INTERFACES,
371 if (proc_interface_file) {
372 proc_interface_file->proc_fops = &proc_interfaces_fops;
374 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_INTERFACES);
379 proc_orig_interval_file = create_proc_entry(PROC_FILE_ORIG_INTERVAL,
382 if (proc_orig_interval_file) {
383 proc_orig_interval_file->proc_fops = &proc_orig_interval_fops;
385 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_ORIG_INTERVAL);
390 proc_vis_srv_file = create_proc_entry(PROC_FILE_VIS_SRV,
393 if (proc_vis_srv_file) {
394 proc_vis_srv_file->proc_fops = &proc_vis_srv_fops;
396 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_VIS_SRV);
401 proc_vis_data_file = create_proc_entry(PROC_FILE_VIS_DATA, S_IRUGO,
403 if (proc_vis_data_file) {
404 proc_vis_data_file->proc_fops = &proc_vis_data_fops;
406 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_VIS_DATA);