]> bbs.cooldavid.org Git - net-next-2.6.git/blame - drivers/staging/batman-adv/proc.c
Staging: batman-adv: convert multiple /proc files to use sysfs
[net-next-2.6.git] / drivers / staging / batman-adv / proc.c
CommitLineData
5beef3c9 1/*
9b6d10b7 2 * Copyright (C) 2007-2010 B.A.T.M.A.N. contributors:
5beef3c9
AL
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"
5beef3c9
AL
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"
5beef3c9 30
5beef3c9 31static struct proc_dir_entry *proc_batman_dir, *proc_interface_file;
47fdf097 32static struct proc_dir_entry *proc_orig_interval_file;
e9b76450 33static struct proc_dir_entry *proc_vis_srv_file, *proc_vis_data_file;
5beef3c9
AL
34
35static int proc_interfaces_read(struct seq_file *seq, void *offset)
36{
37 struct batman_if *batman_if;
38
39 rcu_read_lock();
40 list_for_each_entry_rcu(batman_if, &if_list, list) {
f6497e38 41 seq_printf(seq, "[%8s] %s %s\n",
5beef3c9
AL
42 (batman_if->if_active == IF_ACTIVE ?
43 "active" : "inactive"),
44 batman_if->dev,
45 (batman_if->if_active == IF_ACTIVE ?
46 batman_if->addr_str : " "));
47 }
48 rcu_read_unlock();
49
50 return 0;
51}
52
53static int proc_interfaces_open(struct inode *inode, struct file *file)
54{
55 return single_open(file, proc_interfaces_read, NULL);
56}
57
58static ssize_t proc_interfaces_write(struct file *instance,
59 const char __user *userbuffer,
60 size_t count, loff_t *data)
61{
62 char *if_string, *colon_ptr = NULL, *cr_ptr = NULL;
af71b816 63 int not_copied = 0, if_num = 0, add_success;
5beef3c9
AL
64 struct batman_if *batman_if = NULL;
65
66 if_string = kmalloc(count, GFP_KERNEL);
67
68 if (!if_string)
69 return -ENOMEM;
70
71 if (count > IFNAMSIZ - 1) {
bad2239e 72 printk(KERN_WARNING "batman-adv:Can't add interface: device name is too long\n");
5beef3c9
AL
73 goto end;
74 }
75
76 not_copied = copy_from_user(if_string, userbuffer, count);
77 if_string[count - not_copied - 1] = 0;
78
79 colon_ptr = strchr(if_string, ':');
80 if (colon_ptr)
81 *colon_ptr = 0;
82
83 if (!colon_ptr) {
84 cr_ptr = strchr(if_string, '\n');
85 if (cr_ptr)
86 *cr_ptr = 0;
87 }
88
89 if (strlen(if_string) == 0) {
90 shutdown_module();
91 num_ifs = 0;
92 goto end;
93 }
94
95 /* add interface */
96 rcu_read_lock();
97 list_for_each_entry_rcu(batman_if, &if_list, list) {
98 if (strncmp(batman_if->dev, if_string, count) == 0) {
bad2239e 99 printk(KERN_ERR "batman-adv:Given interface is already active: %s\n", if_string);
5beef3c9
AL
100 rcu_read_unlock();
101 goto end;
102
103 }
104
105 if_num++;
106 }
107 rcu_read_unlock();
108
af71b816
ML
109 add_success = hardif_add_interface(if_string, if_num);
110 if (add_success < 0)
111 goto end;
112
113 num_ifs = if_num + 1;
5beef3c9
AL
114
115 if ((atomic_read(&module_state) == MODULE_INACTIVE) &&
116 (hardif_get_active_if_num() > 0))
117 activate_module();
118
5beef3c9 119 return count;
5beef3c9
AL
120end:
121 kfree(if_string);
122 return count;
123}
124
125static int proc_orig_interval_read(struct seq_file *seq, void *offset)
126{
127 seq_printf(seq, "%i\n", atomic_read(&originator_interval));
128
129 return 0;
130}
131
132static ssize_t proc_orig_interval_write(struct file *file,
133 const char __user *buffer,
134 size_t count, loff_t *ppos)
135{
136 char *interval_string;
137 int not_copied = 0;
138 unsigned long originator_interval_tmp;
139 int retval;
140
141 interval_string = kmalloc(count, GFP_KERNEL);
142
143 if (!interval_string)
144 return -ENOMEM;
145
146 not_copied = copy_from_user(interval_string, buffer, count);
147 interval_string[count - not_copied - 1] = 0;
148
149 retval = strict_strtoul(interval_string, 10, &originator_interval_tmp);
150 if (retval) {
bad2239e 151 printk(KERN_ERR "batman-adv:New originator interval invalid\n");
5beef3c9
AL
152 goto end;
153 }
154
155 if (originator_interval_tmp <= JITTER * 2) {
bad2239e
AL
156 printk(KERN_WARNING "batman-adv:New originator interval too small: %li (min: %i)\n",
157 originator_interval_tmp, JITTER * 2);
5beef3c9
AL
158 goto end;
159 }
160
bad2239e
AL
161 printk(KERN_INFO "batman-adv:Changing originator interval from: %i to: %li\n",
162 atomic_read(&originator_interval), originator_interval_tmp);
5beef3c9
AL
163
164 atomic_set(&originator_interval, originator_interval_tmp);
165
166end:
167 kfree(interval_string);
168 return count;
169}
170
171static int proc_orig_interval_open(struct inode *inode, struct file *file)
172{
173 return single_open(file, proc_orig_interval_read, NULL);
174}
175
e9b76450
ML
176/* setting the mode of the vis server by the user */
177static ssize_t proc_vis_srv_write(struct file *file, const char __user * buffer,
178 size_t count, loff_t *ppos)
5beef3c9 179{
e9b76450
ML
180 char *vis_mode_string;
181 int not_copied = 0;
b801fede 182
e9b76450 183 vis_mode_string = kmalloc(count, GFP_KERNEL);
5beef3c9 184
e9b76450
ML
185 if (!vis_mode_string)
186 return -ENOMEM;
187
188 not_copied = copy_from_user(vis_mode_string, buffer, count);
189 vis_mode_string[count - not_copied - 1] = 0;
190
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");
837b8248 194 atomic_set(&vis_mode, VIS_TYPE_CLIENT_UPDATE);
e9b76450
ML
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");
837b8248 198 atomic_set(&vis_mode, VIS_TYPE_SERVER_SYNC);
e9b76450
ML
199 } else
200 printk(KERN_ERR "batman-adv:Unknown VIS mode: %s\n",
201 vis_mode_string);
202
203 kfree(vis_mode_string);
204 return count;
b801fede
AL
205}
206
e9b76450 207static int proc_vis_srv_read(struct seq_file *seq, void *offset)
b801fede 208{
837b8248 209 int vis_server = atomic_read(&vis_mode);
b801fede 210
f6497e38 211 seq_printf(seq, "[%c] client mode (server disabled)\n",
837b8248 212 (vis_server == VIS_TYPE_CLIENT_UPDATE) ? 'x' : ' ');
f6497e38 213 seq_printf(seq, "[%c] server mode (server enabled)\n",
837b8248 214 (vis_server == VIS_TYPE_SERVER_SYNC) ? 'x' : ' ');
b801fede 215
e9b76450 216 return 0;
5beef3c9 217}
5beef3c9 218
e9b76450 219static int proc_vis_srv_open(struct inode *inode, struct file *file)
5beef3c9 220{
e9b76450 221 return single_open(file, proc_vis_srv_read, NULL);
5beef3c9
AL
222}
223
e9b76450 224static int proc_vis_data_read(struct seq_file *seq, void *offset)
5beef3c9 225{
b6c35976 226 HASHIT(hashit);
5beef3c9
AL
227 struct vis_info *info;
228 struct vis_info_entry *entries;
b801fede 229 HLIST_HEAD(vis_if_list);
f6497e38
LL
230 struct if_list_entry *entry;
231 struct hlist_node *pos, *n;
5beef3c9 232 int i;
5beef3c9 233 char tmp_addr_str[ETH_STR_LEN];
e7017195 234 unsigned long flags;
837b8248 235 int vis_server = atomic_read(&vis_mode);
5beef3c9 236
5beef3c9 237 rcu_read_lock();
837b8248 238 if (list_empty(&if_list) || (vis_server == VIS_TYPE_CLIENT_UPDATE)) {
5beef3c9 239 rcu_read_unlock();
5beef3c9
AL
240 goto end;
241 }
242
243 rcu_read_unlock();
244
e7017195 245 spin_lock_irqsave(&vis_hash_lock, flags);
b6c35976
SW
246 while (hash_iterate(vis_hash, &hashit)) {
247 info = hashit.bucket->data;
5beef3c9
AL
248 entries = (struct vis_info_entry *)
249 ((char *)info + sizeof(struct vis_info));
250
251 for (i = 0; i < info->packet.entries; i++) {
f6497e38
LL
252 if (entries[i].quality == 0)
253 continue;
254 proc_vis_insert_interface(entries[i].src, &vis_if_list,
255 compare_orig(entries[i].src,
256 info->packet.vis_orig));
5beef3c9
AL
257 }
258
f6497e38
LL
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);
262
263 for (i = 0; i < info->packet.entries; i++)
264 proc_vis_read_entry(seq, &entries[i],
265 entry->addr, entry->primary);
266
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);
270
271 seq_printf(seq, "\n");
272 }
273
274 hlist_for_each_entry_safe(entry, pos, n, &vis_if_list, list) {
275 hlist_del(&entry->list);
276 kfree(entry);
277 }
5beef3c9 278 }
e7017195 279 spin_unlock_irqrestore(&vis_hash_lock, flags);
5beef3c9 280
5beef3c9
AL
281end:
282 return 0;
283}
284
e9b76450 285static int proc_vis_data_open(struct inode *inode, struct file *file)
5beef3c9 286{
e9b76450 287 return single_open(file, proc_vis_data_read, NULL);
5beef3c9
AL
288}
289
5beef3c9
AL
290/* satisfying different prototypes ... */
291static ssize_t proc_dummy_write(struct file *file, const char __user *buffer,
292 size_t count, loff_t *ppos)
293{
294 return count;
295}
296
e9b76450 297static const struct file_operations proc_vis_srv_fops = {
5beef3c9 298 .owner = THIS_MODULE,
e9b76450 299 .open = proc_vis_srv_open,
5beef3c9 300 .read = seq_read,
e9b76450
ML
301 .write = proc_vis_srv_write,
302 .llseek = seq_lseek,
303 .release = single_release,
304};
305
306static const struct file_operations proc_vis_data_fops = {
307 .owner = THIS_MODULE,
308 .open = proc_vis_data_open,
309 .read = seq_read,
310 .write = proc_dummy_write,
5beef3c9
AL
311 .llseek = seq_lseek,
312 .release = single_release,
313};
314
5beef3c9
AL
315static const struct file_operations proc_interfaces_fops = {
316 .owner = THIS_MODULE,
317 .open = proc_interfaces_open,
318 .read = seq_read,
319 .write = proc_interfaces_write,
320 .llseek = seq_lseek,
321 .release = single_release,
322};
323
324static const struct file_operations proc_orig_interval_fops = {
325 .owner = THIS_MODULE,
326 .open = proc_orig_interval_open,
327 .read = seq_read,
328 .write = proc_orig_interval_write,
329 .llseek = seq_lseek,
330 .release = single_release,
331};
332
333void cleanup_procfs(void)
334{
5beef3c9
AL
335 if (proc_orig_interval_file)
336 remove_proc_entry(PROC_FILE_ORIG_INTERVAL, proc_batman_dir);
337
338 if (proc_interface_file)
339 remove_proc_entry(PROC_FILE_INTERFACES, proc_batman_dir);
340
e9b76450
ML
341 if (proc_vis_data_file)
342 remove_proc_entry(PROC_FILE_VIS_DATA, proc_batman_dir);
343
344 if (proc_vis_srv_file)
345 remove_proc_entry(PROC_FILE_VIS_SRV, proc_batman_dir);
5beef3c9 346
5beef3c9
AL
347 if (proc_batman_dir)
348#ifdef __NET_NET_NAMESPACE_H
349 remove_proc_entry(PROC_ROOT_DIR, init_net.proc_net);
350#else
351 remove_proc_entry(PROC_ROOT_DIR, proc_net);
352#endif
353}
354
355int setup_procfs(void)
356{
357#ifdef __NET_NET_NAMESPACE_H
358 proc_batman_dir = proc_mkdir(PROC_ROOT_DIR, init_net.proc_net);
359#else
360 proc_batman_dir = proc_mkdir(PROC_ROOT_DIR, proc_net);
361#endif
362
363 if (!proc_batman_dir) {
364 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s' folder failed\n", PROC_ROOT_DIR);
365 return -EFAULT;
366 }
367
368 proc_interface_file = create_proc_entry(PROC_FILE_INTERFACES,
369 S_IWUSR | S_IRUGO,
370 proc_batman_dir);
371 if (proc_interface_file) {
372 proc_interface_file->proc_fops = &proc_interfaces_fops;
373 } else {
374 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_INTERFACES);
375 cleanup_procfs();
376 return -EFAULT;
377 }
378
379 proc_orig_interval_file = create_proc_entry(PROC_FILE_ORIG_INTERVAL,
380 S_IWUSR | S_IRUGO,
381 proc_batman_dir);
382 if (proc_orig_interval_file) {
383 proc_orig_interval_file->proc_fops = &proc_orig_interval_fops;
384 } else {
385 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_ORIG_INTERVAL);
386 cleanup_procfs();
387 return -EFAULT;
388 }
389
e9b76450
ML
390 proc_vis_srv_file = create_proc_entry(PROC_FILE_VIS_SRV,
391 S_IWUSR | S_IRUGO,
392 proc_batman_dir);
393 if (proc_vis_srv_file) {
394 proc_vis_srv_file->proc_fops = &proc_vis_srv_fops;
395 } else {
396 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_VIS_SRV);
397 cleanup_procfs();
398 return -EFAULT;
399 }
400
401 proc_vis_data_file = create_proc_entry(PROC_FILE_VIS_DATA, S_IRUGO,
5beef3c9 402 proc_batman_dir);
e9b76450
ML
403 if (proc_vis_data_file) {
404 proc_vis_data_file->proc_fops = &proc_vis_data_fops;
5beef3c9 405 } else {
e9b76450 406 printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_VIS_DATA);
5beef3c9
AL
407 cleanup_procfs();
408 return -EFAULT;
409 }
410
5beef3c9
AL
411 return 0;
412}