]>
Commit | Line | Data |
---|---|---|
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 | 31 | static struct proc_dir_entry *proc_batman_dir, *proc_interface_file; |
5beef3c9 AL |
32 | |
33 | static int proc_interfaces_read(struct seq_file *seq, void *offset) | |
34 | { | |
35 | struct batman_if *batman_if; | |
36 | ||
37 | rcu_read_lock(); | |
38 | list_for_each_entry_rcu(batman_if, &if_list, list) { | |
f6497e38 | 39 | seq_printf(seq, "[%8s] %s %s\n", |
5beef3c9 AL |
40 | (batman_if->if_active == IF_ACTIVE ? |
41 | "active" : "inactive"), | |
42 | batman_if->dev, | |
43 | (batman_if->if_active == IF_ACTIVE ? | |
44 | batman_if->addr_str : " ")); | |
45 | } | |
46 | rcu_read_unlock(); | |
47 | ||
48 | return 0; | |
49 | } | |
50 | ||
51 | static int proc_interfaces_open(struct inode *inode, struct file *file) | |
52 | { | |
53 | return single_open(file, proc_interfaces_read, NULL); | |
54 | } | |
55 | ||
56 | static ssize_t proc_interfaces_write(struct file *instance, | |
57 | const char __user *userbuffer, | |
58 | size_t count, loff_t *data) | |
59 | { | |
60 | char *if_string, *colon_ptr = NULL, *cr_ptr = NULL; | |
af71b816 | 61 | int not_copied = 0, if_num = 0, add_success; |
5beef3c9 AL |
62 | struct batman_if *batman_if = NULL; |
63 | ||
64 | if_string = kmalloc(count, GFP_KERNEL); | |
65 | ||
66 | if (!if_string) | |
67 | return -ENOMEM; | |
68 | ||
69 | if (count > IFNAMSIZ - 1) { | |
bad2239e | 70 | printk(KERN_WARNING "batman-adv:Can't add interface: device name is too long\n"); |
5beef3c9 AL |
71 | goto end; |
72 | } | |
73 | ||
74 | not_copied = copy_from_user(if_string, userbuffer, count); | |
75 | if_string[count - not_copied - 1] = 0; | |
76 | ||
77 | colon_ptr = strchr(if_string, ':'); | |
78 | if (colon_ptr) | |
79 | *colon_ptr = 0; | |
80 | ||
81 | if (!colon_ptr) { | |
82 | cr_ptr = strchr(if_string, '\n'); | |
83 | if (cr_ptr) | |
84 | *cr_ptr = 0; | |
85 | } | |
86 | ||
87 | if (strlen(if_string) == 0) { | |
88 | shutdown_module(); | |
89 | num_ifs = 0; | |
90 | goto end; | |
91 | } | |
92 | ||
93 | /* add interface */ | |
94 | rcu_read_lock(); | |
95 | list_for_each_entry_rcu(batman_if, &if_list, list) { | |
96 | if (strncmp(batman_if->dev, if_string, count) == 0) { | |
bad2239e | 97 | printk(KERN_ERR "batman-adv:Given interface is already active: %s\n", if_string); |
5beef3c9 AL |
98 | rcu_read_unlock(); |
99 | goto end; | |
100 | ||
101 | } | |
102 | ||
103 | if_num++; | |
104 | } | |
105 | rcu_read_unlock(); | |
106 | ||
af71b816 ML |
107 | add_success = hardif_add_interface(if_string, if_num); |
108 | if (add_success < 0) | |
109 | goto end; | |
110 | ||
111 | num_ifs = if_num + 1; | |
5beef3c9 AL |
112 | |
113 | if ((atomic_read(&module_state) == MODULE_INACTIVE) && | |
114 | (hardif_get_active_if_num() > 0)) | |
115 | activate_module(); | |
116 | ||
5beef3c9 | 117 | return count; |
5beef3c9 AL |
118 | end: |
119 | kfree(if_string); | |
120 | return count; | |
121 | } | |
122 | ||
5beef3c9 AL |
123 | static const struct file_operations proc_interfaces_fops = { |
124 | .owner = THIS_MODULE, | |
125 | .open = proc_interfaces_open, | |
126 | .read = seq_read, | |
127 | .write = proc_interfaces_write, | |
128 | .llseek = seq_lseek, | |
129 | .release = single_release, | |
130 | }; | |
131 | ||
5beef3c9 AL |
132 | void cleanup_procfs(void) |
133 | { | |
5beef3c9 AL |
134 | if (proc_interface_file) |
135 | remove_proc_entry(PROC_FILE_INTERFACES, proc_batman_dir); | |
136 | ||
5beef3c9 AL |
137 | if (proc_batman_dir) |
138 | #ifdef __NET_NET_NAMESPACE_H | |
139 | remove_proc_entry(PROC_ROOT_DIR, init_net.proc_net); | |
140 | #else | |
141 | remove_proc_entry(PROC_ROOT_DIR, proc_net); | |
142 | #endif | |
143 | } | |
144 | ||
145 | int setup_procfs(void) | |
146 | { | |
147 | #ifdef __NET_NET_NAMESPACE_H | |
148 | proc_batman_dir = proc_mkdir(PROC_ROOT_DIR, init_net.proc_net); | |
149 | #else | |
150 | proc_batman_dir = proc_mkdir(PROC_ROOT_DIR, proc_net); | |
151 | #endif | |
152 | ||
153 | if (!proc_batman_dir) { | |
154 | printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s' folder failed\n", PROC_ROOT_DIR); | |
155 | return -EFAULT; | |
156 | } | |
157 | ||
158 | proc_interface_file = create_proc_entry(PROC_FILE_INTERFACES, | |
159 | S_IWUSR | S_IRUGO, | |
160 | proc_batman_dir); | |
161 | if (proc_interface_file) { | |
162 | proc_interface_file->proc_fops = &proc_interfaces_fops; | |
163 | } else { | |
164 | printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", PROC_ROOT_DIR, PROC_FILE_INTERFACES); | |
165 | cleanup_procfs(); | |
166 | return -EFAULT; | |
167 | } | |
168 | ||
5beef3c9 AL |
169 | return 0; |
170 | } |