diff options
Diffstat (limited to 'net/batman-adv/sysfs.c')
-rw-r--r-- | net/batman-adv/sysfs.c | 787 |
1 files changed, 787 insertions, 0 deletions
diff --git a/net/batman-adv/sysfs.c b/net/batman-adv/sysfs.c new file mode 100644 index 000000000000..66518c75c217 --- /dev/null +++ b/net/batman-adv/sysfs.c | |||
@@ -0,0 +1,787 @@ | |||
1 | /* Copyright (C) 2010-2012 B.A.T.M.A.N. contributors: | ||
2 | * | ||
3 | * Marek Lindner | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of version 2 of the GNU General Public | ||
7 | * License as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but | ||
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | * General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
17 | * 02110-1301, USA | ||
18 | */ | ||
19 | |||
20 | #include "main.h" | ||
21 | #include "sysfs.h" | ||
22 | #include "translation-table.h" | ||
23 | #include "originator.h" | ||
24 | #include "hard-interface.h" | ||
25 | #include "gateway_common.h" | ||
26 | #include "gateway_client.h" | ||
27 | #include "vis.h" | ||
28 | |||
29 | static struct net_device *batadv_kobj_to_netdev(struct kobject *obj) | ||
30 | { | ||
31 | struct device *dev = container_of(obj->parent, struct device, kobj); | ||
32 | return to_net_dev(dev); | ||
33 | } | ||
34 | |||
35 | static struct batadv_priv *batadv_kobj_to_batpriv(struct kobject *obj) | ||
36 | { | ||
37 | struct net_device *net_dev = batadv_kobj_to_netdev(obj); | ||
38 | return netdev_priv(net_dev); | ||
39 | } | ||
40 | |||
41 | #define BATADV_UEV_TYPE_VAR "BATTYPE=" | ||
42 | #define BATADV_UEV_ACTION_VAR "BATACTION=" | ||
43 | #define BATADV_UEV_DATA_VAR "BATDATA=" | ||
44 | |||
45 | static char *batadv_uev_action_str[] = { | ||
46 | "add", | ||
47 | "del", | ||
48 | "change" | ||
49 | }; | ||
50 | |||
51 | static char *batadv_uev_type_str[] = { | ||
52 | "gw" | ||
53 | }; | ||
54 | |||
55 | /* Use this, if you have customized show and store functions */ | ||
56 | #define BATADV_ATTR(_name, _mode, _show, _store) \ | ||
57 | struct batadv_attribute batadv_attr_##_name = { \ | ||
58 | .attr = {.name = __stringify(_name), \ | ||
59 | .mode = _mode }, \ | ||
60 | .show = _show, \ | ||
61 | .store = _store, \ | ||
62 | }; | ||
63 | |||
64 | #define BATADV_ATTR_SIF_STORE_BOOL(_name, _post_func) \ | ||
65 | ssize_t batadv_store_##_name(struct kobject *kobj, \ | ||
66 | struct attribute *attr, char *buff, \ | ||
67 | size_t count) \ | ||
68 | { \ | ||
69 | struct net_device *net_dev = batadv_kobj_to_netdev(kobj); \ | ||
70 | struct batadv_priv *bat_priv = netdev_priv(net_dev); \ | ||
71 | return __batadv_store_bool_attr(buff, count, _post_func, attr, \ | ||
72 | &bat_priv->_name, net_dev); \ | ||
73 | } | ||
74 | |||
75 | #define BATADV_ATTR_SIF_SHOW_BOOL(_name) \ | ||
76 | ssize_t batadv_show_##_name(struct kobject *kobj, \ | ||
77 | struct attribute *attr, char *buff) \ | ||
78 | { \ | ||
79 | struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); \ | ||
80 | return sprintf(buff, "%s\n", \ | ||
81 | atomic_read(&bat_priv->_name) == 0 ? \ | ||
82 | "disabled" : "enabled"); \ | ||
83 | } \ | ||
84 | |||
85 | /* Use this, if you are going to turn a [name] in the soft-interface | ||
86 | * (bat_priv) on or off | ||
87 | */ | ||
88 | #define BATADV_ATTR_SIF_BOOL(_name, _mode, _post_func) \ | ||
89 | static BATADV_ATTR_SIF_STORE_BOOL(_name, _post_func) \ | ||
90 | static BATADV_ATTR_SIF_SHOW_BOOL(_name) \ | ||
91 | static BATADV_ATTR(_name, _mode, batadv_show_##_name, \ | ||
92 | batadv_store_##_name) | ||
93 | |||
94 | |||
95 | #define BATADV_ATTR_SIF_STORE_UINT(_name, _min, _max, _post_func) \ | ||
96 | ssize_t batadv_store_##_name(struct kobject *kobj, \ | ||
97 | struct attribute *attr, char *buff, \ | ||
98 | size_t count) \ | ||
99 | { \ | ||
100 | struct net_device *net_dev = batadv_kobj_to_netdev(kobj); \ | ||
101 | struct batadv_priv *bat_priv = netdev_priv(net_dev); \ | ||
102 | return __batadv_store_uint_attr(buff, count, _min, _max, \ | ||
103 | _post_func, attr, \ | ||
104 | &bat_priv->_name, net_dev); \ | ||
105 | } | ||
106 | |||
107 | #define BATADV_ATTR_SIF_SHOW_UINT(_name) \ | ||
108 | ssize_t batadv_show_##_name(struct kobject *kobj, \ | ||
109 | struct attribute *attr, char *buff) \ | ||
110 | { \ | ||
111 | struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); \ | ||
112 | return sprintf(buff, "%i\n", atomic_read(&bat_priv->_name)); \ | ||
113 | } \ | ||
114 | |||
115 | /* Use this, if you are going to set [name] in the soft-interface | ||
116 | * (bat_priv) to an unsigned integer value | ||
117 | */ | ||
118 | #define BATADV_ATTR_SIF_UINT(_name, _mode, _min, _max, _post_func) \ | ||
119 | static BATADV_ATTR_SIF_STORE_UINT(_name, _min, _max, _post_func)\ | ||
120 | static BATADV_ATTR_SIF_SHOW_UINT(_name) \ | ||
121 | static BATADV_ATTR(_name, _mode, batadv_show_##_name, \ | ||
122 | batadv_store_##_name) | ||
123 | |||
124 | |||
125 | #define BATADV_ATTR_HIF_STORE_UINT(_name, _min, _max, _post_func) \ | ||
126 | ssize_t batadv_store_##_name(struct kobject *kobj, \ | ||
127 | struct attribute *attr, char *buff, \ | ||
128 | size_t count) \ | ||
129 | { \ | ||
130 | struct net_device *net_dev = batadv_kobj_to_netdev(kobj); \ | ||
131 | struct batadv_hard_iface *hard_iface; \ | ||
132 | ssize_t length; \ | ||
133 | \ | ||
134 | hard_iface = batadv_hardif_get_by_netdev(net_dev); \ | ||
135 | if (!hard_iface) \ | ||
136 | return 0; \ | ||
137 | \ | ||
138 | length = __batadv_store_uint_attr(buff, count, _min, _max, \ | ||
139 | _post_func, attr, \ | ||
140 | &hard_iface->_name, net_dev); \ | ||
141 | \ | ||
142 | batadv_hardif_free_ref(hard_iface); \ | ||
143 | return length; \ | ||
144 | } | ||
145 | |||
146 | #define BATADV_ATTR_HIF_SHOW_UINT(_name) \ | ||
147 | ssize_t batadv_show_##_name(struct kobject *kobj, \ | ||
148 | struct attribute *attr, char *buff) \ | ||
149 | { \ | ||
150 | struct net_device *net_dev = batadv_kobj_to_netdev(kobj); \ | ||
151 | struct batadv_hard_iface *hard_iface; \ | ||
152 | ssize_t length; \ | ||
153 | \ | ||
154 | hard_iface = batadv_hardif_get_by_netdev(net_dev); \ | ||
155 | if (!hard_iface) \ | ||
156 | return 0; \ | ||
157 | \ | ||
158 | length = sprintf(buff, "%i\n", atomic_read(&hard_iface->_name));\ | ||
159 | \ | ||
160 | batadv_hardif_free_ref(hard_iface); \ | ||
161 | return length; \ | ||
162 | } | ||
163 | |||
164 | /* Use this, if you are going to set [name] in hard_iface to an | ||
165 | * unsigned integer value | ||
166 | */ | ||
167 | #define BATADV_ATTR_HIF_UINT(_name, _mode, _min, _max, _post_func) \ | ||
168 | static BATADV_ATTR_HIF_STORE_UINT(_name, _min, _max, _post_func)\ | ||
169 | static BATADV_ATTR_HIF_SHOW_UINT(_name) \ | ||
170 | static BATADV_ATTR(_name, _mode, batadv_show_##_name, \ | ||
171 | batadv_store_##_name) | ||
172 | |||
173 | |||
174 | static int batadv_store_bool_attr(char *buff, size_t count, | ||
175 | struct net_device *net_dev, | ||
176 | const char *attr_name, atomic_t *attr) | ||
177 | { | ||
178 | int enabled = -1; | ||
179 | |||
180 | if (buff[count - 1] == '\n') | ||
181 | buff[count - 1] = '\0'; | ||
182 | |||
183 | if ((strncmp(buff, "1", 2) == 0) || | ||
184 | (strncmp(buff, "enable", 7) == 0) || | ||
185 | (strncmp(buff, "enabled", 8) == 0)) | ||
186 | enabled = 1; | ||
187 | |||
188 | if ((strncmp(buff, "0", 2) == 0) || | ||
189 | (strncmp(buff, "disable", 8) == 0) || | ||
190 | (strncmp(buff, "disabled", 9) == 0)) | ||
191 | enabled = 0; | ||
192 | |||
193 | if (enabled < 0) { | ||
194 | batadv_info(net_dev, "%s: Invalid parameter received: %s\n", | ||
195 | attr_name, buff); | ||
196 | return -EINVAL; | ||
197 | } | ||
198 | |||
199 | if (atomic_read(attr) == enabled) | ||
200 | return count; | ||
201 | |||
202 | batadv_info(net_dev, "%s: Changing from: %s to: %s\n", attr_name, | ||
203 | atomic_read(attr) == 1 ? "enabled" : "disabled", | ||
204 | enabled == 1 ? "enabled" : "disabled"); | ||
205 | |||
206 | atomic_set(attr, (unsigned int)enabled); | ||
207 | return count; | ||
208 | } | ||
209 | |||
210 | static inline ssize_t | ||
211 | __batadv_store_bool_attr(char *buff, size_t count, | ||
212 | void (*post_func)(struct net_device *), | ||
213 | struct attribute *attr, | ||
214 | atomic_t *attr_store, struct net_device *net_dev) | ||
215 | { | ||
216 | int ret; | ||
217 | |||
218 | ret = batadv_store_bool_attr(buff, count, net_dev, attr->name, | ||
219 | attr_store); | ||
220 | if (post_func && ret) | ||
221 | post_func(net_dev); | ||
222 | |||
223 | return ret; | ||
224 | } | ||
225 | |||
226 | static int batadv_store_uint_attr(const char *buff, size_t count, | ||
227 | struct net_device *net_dev, | ||
228 | const char *attr_name, | ||
229 | unsigned int min, unsigned int max, | ||
230 | atomic_t *attr) | ||
231 | { | ||
232 | unsigned long uint_val; | ||
233 | int ret; | ||
234 | |||
235 | ret = kstrtoul(buff, 10, &uint_val); | ||
236 | if (ret) { | ||
237 | batadv_info(net_dev, "%s: Invalid parameter received: %s\n", | ||
238 | attr_name, buff); | ||
239 | return -EINVAL; | ||
240 | } | ||
241 | |||
242 | if (uint_val < min) { | ||
243 | batadv_info(net_dev, "%s: Value is too small: %lu min: %u\n", | ||
244 | attr_name, uint_val, min); | ||
245 | return -EINVAL; | ||
246 | } | ||
247 | |||
248 | if (uint_val > max) { | ||
249 | batadv_info(net_dev, "%s: Value is too big: %lu max: %u\n", | ||
250 | attr_name, uint_val, max); | ||
251 | return -EINVAL; | ||
252 | } | ||
253 | |||
254 | if (atomic_read(attr) == uint_val) | ||
255 | return count; | ||
256 | |||
257 | batadv_info(net_dev, "%s: Changing from: %i to: %lu\n", | ||
258 | attr_name, atomic_read(attr), uint_val); | ||
259 | |||
260 | atomic_set(attr, uint_val); | ||
261 | return count; | ||
262 | } | ||
263 | |||
264 | static inline ssize_t | ||
265 | __batadv_store_uint_attr(const char *buff, size_t count, | ||
266 | int min, int max, | ||
267 | void (*post_func)(struct net_device *), | ||
268 | const struct attribute *attr, | ||
269 | atomic_t *attr_store, struct net_device *net_dev) | ||
270 | { | ||
271 | int ret; | ||
272 | |||
273 | ret = batadv_store_uint_attr(buff, count, net_dev, attr->name, min, max, | ||
274 | attr_store); | ||
275 | if (post_func && ret) | ||
276 | post_func(net_dev); | ||
277 | |||
278 | return ret; | ||
279 | } | ||
280 | |||
281 | static ssize_t batadv_show_vis_mode(struct kobject *kobj, | ||
282 | struct attribute *attr, char *buff) | ||
283 | { | ||
284 | struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); | ||
285 | int vis_mode = atomic_read(&bat_priv->vis_mode); | ||
286 | const char *mode; | ||
287 | |||
288 | if (vis_mode == BATADV_VIS_TYPE_CLIENT_UPDATE) | ||
289 | mode = "client"; | ||
290 | else | ||
291 | mode = "server"; | ||
292 | |||
293 | return sprintf(buff, "%s\n", mode); | ||
294 | } | ||
295 | |||
296 | static ssize_t batadv_store_vis_mode(struct kobject *kobj, | ||
297 | struct attribute *attr, char *buff, | ||
298 | size_t count) | ||
299 | { | ||
300 | struct net_device *net_dev = batadv_kobj_to_netdev(kobj); | ||
301 | struct batadv_priv *bat_priv = netdev_priv(net_dev); | ||
302 | unsigned long val; | ||
303 | int ret, vis_mode_tmp = -1; | ||
304 | const char *old_mode, *new_mode; | ||
305 | |||
306 | ret = kstrtoul(buff, 10, &val); | ||
307 | |||
308 | if (((count == 2) && (!ret) && | ||
309 | (val == BATADV_VIS_TYPE_CLIENT_UPDATE)) || | ||
310 | (strncmp(buff, "client", 6) == 0) || | ||
311 | (strncmp(buff, "off", 3) == 0)) | ||
312 | vis_mode_tmp = BATADV_VIS_TYPE_CLIENT_UPDATE; | ||
313 | |||
314 | if (((count == 2) && (!ret) && | ||
315 | (val == BATADV_VIS_TYPE_SERVER_SYNC)) || | ||
316 | (strncmp(buff, "server", 6) == 0)) | ||
317 | vis_mode_tmp = BATADV_VIS_TYPE_SERVER_SYNC; | ||
318 | |||
319 | if (vis_mode_tmp < 0) { | ||
320 | if (buff[count - 1] == '\n') | ||
321 | buff[count - 1] = '\0'; | ||
322 | |||
323 | batadv_info(net_dev, | ||
324 | "Invalid parameter for 'vis mode' setting received: %s\n", | ||
325 | buff); | ||
326 | return -EINVAL; | ||
327 | } | ||
328 | |||
329 | if (atomic_read(&bat_priv->vis_mode) == vis_mode_tmp) | ||
330 | return count; | ||
331 | |||
332 | if (atomic_read(&bat_priv->vis_mode) == BATADV_VIS_TYPE_CLIENT_UPDATE) | ||
333 | old_mode = "client"; | ||
334 | else | ||
335 | old_mode = "server"; | ||
336 | |||
337 | if (vis_mode_tmp == BATADV_VIS_TYPE_CLIENT_UPDATE) | ||
338 | new_mode = "client"; | ||
339 | else | ||
340 | new_mode = "server"; | ||
341 | |||
342 | batadv_info(net_dev, "Changing vis mode from: %s to: %s\n", old_mode, | ||
343 | new_mode); | ||
344 | |||
345 | atomic_set(&bat_priv->vis_mode, (unsigned int)vis_mode_tmp); | ||
346 | return count; | ||
347 | } | ||
348 | |||
349 | static ssize_t batadv_show_bat_algo(struct kobject *kobj, | ||
350 | struct attribute *attr, char *buff) | ||
351 | { | ||
352 | struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); | ||
353 | return sprintf(buff, "%s\n", bat_priv->bat_algo_ops->name); | ||
354 | } | ||
355 | |||
356 | static void batadv_post_gw_deselect(struct net_device *net_dev) | ||
357 | { | ||
358 | struct batadv_priv *bat_priv = netdev_priv(net_dev); | ||
359 | batadv_gw_deselect(bat_priv); | ||
360 | } | ||
361 | |||
362 | static ssize_t batadv_show_gw_mode(struct kobject *kobj, struct attribute *attr, | ||
363 | char *buff) | ||
364 | { | ||
365 | struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); | ||
366 | int bytes_written; | ||
367 | |||
368 | switch (atomic_read(&bat_priv->gw_mode)) { | ||
369 | case BATADV_GW_MODE_CLIENT: | ||
370 | bytes_written = sprintf(buff, "%s\n", | ||
371 | BATADV_GW_MODE_CLIENT_NAME); | ||
372 | break; | ||
373 | case BATADV_GW_MODE_SERVER: | ||
374 | bytes_written = sprintf(buff, "%s\n", | ||
375 | BATADV_GW_MODE_SERVER_NAME); | ||
376 | break; | ||
377 | default: | ||
378 | bytes_written = sprintf(buff, "%s\n", | ||
379 | BATADV_GW_MODE_OFF_NAME); | ||
380 | break; | ||
381 | } | ||
382 | |||
383 | return bytes_written; | ||
384 | } | ||
385 | |||
386 | static ssize_t batadv_store_gw_mode(struct kobject *kobj, | ||
387 | struct attribute *attr, char *buff, | ||
388 | size_t count) | ||
389 | { | ||
390 | struct net_device *net_dev = batadv_kobj_to_netdev(kobj); | ||
391 | struct batadv_priv *bat_priv = netdev_priv(net_dev); | ||
392 | char *curr_gw_mode_str; | ||
393 | int gw_mode_tmp = -1; | ||
394 | |||
395 | if (buff[count - 1] == '\n') | ||
396 | buff[count - 1] = '\0'; | ||
397 | |||
398 | if (strncmp(buff, BATADV_GW_MODE_OFF_NAME, | ||
399 | strlen(BATADV_GW_MODE_OFF_NAME)) == 0) | ||
400 | gw_mode_tmp = BATADV_GW_MODE_OFF; | ||
401 | |||
402 | if (strncmp(buff, BATADV_GW_MODE_CLIENT_NAME, | ||
403 | strlen(BATADV_GW_MODE_CLIENT_NAME)) == 0) | ||
404 | gw_mode_tmp = BATADV_GW_MODE_CLIENT; | ||
405 | |||
406 | if (strncmp(buff, BATADV_GW_MODE_SERVER_NAME, | ||
407 | strlen(BATADV_GW_MODE_SERVER_NAME)) == 0) | ||
408 | gw_mode_tmp = BATADV_GW_MODE_SERVER; | ||
409 | |||
410 | if (gw_mode_tmp < 0) { | ||
411 | batadv_info(net_dev, | ||
412 | "Invalid parameter for 'gw mode' setting received: %s\n", | ||
413 | buff); | ||
414 | return -EINVAL; | ||
415 | } | ||
416 | |||
417 | if (atomic_read(&bat_priv->gw_mode) == gw_mode_tmp) | ||
418 | return count; | ||
419 | |||
420 | switch (atomic_read(&bat_priv->gw_mode)) { | ||
421 | case BATADV_GW_MODE_CLIENT: | ||
422 | curr_gw_mode_str = BATADV_GW_MODE_CLIENT_NAME; | ||
423 | break; | ||
424 | case BATADV_GW_MODE_SERVER: | ||
425 | curr_gw_mode_str = BATADV_GW_MODE_SERVER_NAME; | ||
426 | break; | ||
427 | default: | ||
428 | curr_gw_mode_str = BATADV_GW_MODE_OFF_NAME; | ||
429 | break; | ||
430 | } | ||
431 | |||
432 | batadv_info(net_dev, "Changing gw mode from: %s to: %s\n", | ||
433 | curr_gw_mode_str, buff); | ||
434 | |||
435 | batadv_gw_deselect(bat_priv); | ||
436 | atomic_set(&bat_priv->gw_mode, (unsigned int)gw_mode_tmp); | ||
437 | return count; | ||
438 | } | ||
439 | |||
440 | static ssize_t batadv_show_gw_bwidth(struct kobject *kobj, | ||
441 | struct attribute *attr, char *buff) | ||
442 | { | ||
443 | struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); | ||
444 | int down, up; | ||
445 | int gw_bandwidth = atomic_read(&bat_priv->gw_bandwidth); | ||
446 | |||
447 | batadv_gw_bandwidth_to_kbit(gw_bandwidth, &down, &up); | ||
448 | return sprintf(buff, "%i%s/%i%s\n", | ||
449 | (down > 2048 ? down / 1024 : down), | ||
450 | (down > 2048 ? "MBit" : "KBit"), | ||
451 | (up > 2048 ? up / 1024 : up), | ||
452 | (up > 2048 ? "MBit" : "KBit")); | ||
453 | } | ||
454 | |||
455 | static ssize_t batadv_store_gw_bwidth(struct kobject *kobj, | ||
456 | struct attribute *attr, char *buff, | ||
457 | size_t count) | ||
458 | { | ||
459 | struct net_device *net_dev = batadv_kobj_to_netdev(kobj); | ||
460 | |||
461 | if (buff[count - 1] == '\n') | ||
462 | buff[count - 1] = '\0'; | ||
463 | |||
464 | return batadv_gw_bandwidth_set(net_dev, buff, count); | ||
465 | } | ||
466 | |||
467 | BATADV_ATTR_SIF_BOOL(aggregated_ogms, S_IRUGO | S_IWUSR, NULL); | ||
468 | BATADV_ATTR_SIF_BOOL(bonding, S_IRUGO | S_IWUSR, NULL); | ||
469 | #ifdef CONFIG_BATMAN_ADV_BLA | ||
470 | BATADV_ATTR_SIF_BOOL(bridge_loop_avoidance, S_IRUGO | S_IWUSR, NULL); | ||
471 | #endif | ||
472 | BATADV_ATTR_SIF_BOOL(fragmentation, S_IRUGO | S_IWUSR, batadv_update_min_mtu); | ||
473 | BATADV_ATTR_SIF_BOOL(ap_isolation, S_IRUGO | S_IWUSR, NULL); | ||
474 | static BATADV_ATTR(vis_mode, S_IRUGO | S_IWUSR, batadv_show_vis_mode, | ||
475 | batadv_store_vis_mode); | ||
476 | static BATADV_ATTR(routing_algo, S_IRUGO, batadv_show_bat_algo, NULL); | ||
477 | static BATADV_ATTR(gw_mode, S_IRUGO | S_IWUSR, batadv_show_gw_mode, | ||
478 | batadv_store_gw_mode); | ||
479 | BATADV_ATTR_SIF_UINT(orig_interval, S_IRUGO | S_IWUSR, 2 * BATADV_JITTER, | ||
480 | INT_MAX, NULL); | ||
481 | BATADV_ATTR_SIF_UINT(hop_penalty, S_IRUGO | S_IWUSR, 0, BATADV_TQ_MAX_VALUE, | ||
482 | NULL); | ||
483 | BATADV_ATTR_SIF_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, BATADV_TQ_MAX_VALUE, | ||
484 | batadv_post_gw_deselect); | ||
485 | static BATADV_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, batadv_show_gw_bwidth, | ||
486 | batadv_store_gw_bwidth); | ||
487 | #ifdef CONFIG_BATMAN_ADV_DEBUG | ||
488 | BATADV_ATTR_SIF_UINT(log_level, S_IRUGO | S_IWUSR, 0, BATADV_DBG_ALL, NULL); | ||
489 | #endif | ||
490 | |||
491 | static struct batadv_attribute *batadv_mesh_attrs[] = { | ||
492 | &batadv_attr_aggregated_ogms, | ||
493 | &batadv_attr_bonding, | ||
494 | #ifdef CONFIG_BATMAN_ADV_BLA | ||
495 | &batadv_attr_bridge_loop_avoidance, | ||
496 | #endif | ||
497 | &batadv_attr_fragmentation, | ||
498 | &batadv_attr_ap_isolation, | ||
499 | &batadv_attr_vis_mode, | ||
500 | &batadv_attr_routing_algo, | ||
501 | &batadv_attr_gw_mode, | ||
502 | &batadv_attr_orig_interval, | ||
503 | &batadv_attr_hop_penalty, | ||
504 | &batadv_attr_gw_sel_class, | ||
505 | &batadv_attr_gw_bandwidth, | ||
506 | #ifdef CONFIG_BATMAN_ADV_DEBUG | ||
507 | &batadv_attr_log_level, | ||
508 | #endif | ||
509 | NULL, | ||
510 | }; | ||
511 | |||
512 | int batadv_sysfs_add_meshif(struct net_device *dev) | ||
513 | { | ||
514 | struct kobject *batif_kobject = &dev->dev.kobj; | ||
515 | struct batadv_priv *bat_priv = netdev_priv(dev); | ||
516 | struct batadv_attribute **bat_attr; | ||
517 | int err; | ||
518 | |||
519 | bat_priv->mesh_obj = kobject_create_and_add(BATADV_SYSFS_IF_MESH_SUBDIR, | ||
520 | batif_kobject); | ||
521 | if (!bat_priv->mesh_obj) { | ||
522 | batadv_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name, | ||
523 | BATADV_SYSFS_IF_MESH_SUBDIR); | ||
524 | goto out; | ||
525 | } | ||
526 | |||
527 | for (bat_attr = batadv_mesh_attrs; *bat_attr; ++bat_attr) { | ||
528 | err = sysfs_create_file(bat_priv->mesh_obj, | ||
529 | &((*bat_attr)->attr)); | ||
530 | if (err) { | ||
531 | batadv_err(dev, "Can't add sysfs file: %s/%s/%s\n", | ||
532 | dev->name, BATADV_SYSFS_IF_MESH_SUBDIR, | ||
533 | ((*bat_attr)->attr).name); | ||
534 | goto rem_attr; | ||
535 | } | ||
536 | } | ||
537 | |||
538 | return 0; | ||
539 | |||
540 | rem_attr: | ||
541 | for (bat_attr = batadv_mesh_attrs; *bat_attr; ++bat_attr) | ||
542 | sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr)); | ||
543 | |||
544 | kobject_put(bat_priv->mesh_obj); | ||
545 | bat_priv->mesh_obj = NULL; | ||
546 | out: | ||
547 | return -ENOMEM; | ||
548 | } | ||
549 | |||
550 | void batadv_sysfs_del_meshif(struct net_device *dev) | ||
551 | { | ||
552 | struct batadv_priv *bat_priv = netdev_priv(dev); | ||
553 | struct batadv_attribute **bat_attr; | ||
554 | |||
555 | for (bat_attr = batadv_mesh_attrs; *bat_attr; ++bat_attr) | ||
556 | sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr)); | ||
557 | |||
558 | kobject_put(bat_priv->mesh_obj); | ||
559 | bat_priv->mesh_obj = NULL; | ||
560 | } | ||
561 | |||
562 | static ssize_t batadv_show_mesh_iface(struct kobject *kobj, | ||
563 | struct attribute *attr, char *buff) | ||
564 | { | ||
565 | struct net_device *net_dev = batadv_kobj_to_netdev(kobj); | ||
566 | struct batadv_hard_iface *hard_iface; | ||
567 | ssize_t length; | ||
568 | const char *ifname; | ||
569 | |||
570 | hard_iface = batadv_hardif_get_by_netdev(net_dev); | ||
571 | if (!hard_iface) | ||
572 | return 0; | ||
573 | |||
574 | if (hard_iface->if_status == BATADV_IF_NOT_IN_USE) | ||
575 | ifname = "none"; | ||
576 | else | ||
577 | ifname = hard_iface->soft_iface->name; | ||
578 | |||
579 | length = sprintf(buff, "%s\n", ifname); | ||
580 | |||
581 | batadv_hardif_free_ref(hard_iface); | ||
582 | |||
583 | return length; | ||
584 | } | ||
585 | |||
586 | static ssize_t batadv_store_mesh_iface(struct kobject *kobj, | ||
587 | struct attribute *attr, char *buff, | ||
588 | size_t count) | ||
589 | { | ||
590 | struct net_device *net_dev = batadv_kobj_to_netdev(kobj); | ||
591 | struct batadv_hard_iface *hard_iface; | ||
592 | int status_tmp = -1; | ||
593 | int ret = count; | ||
594 | |||
595 | hard_iface = batadv_hardif_get_by_netdev(net_dev); | ||
596 | if (!hard_iface) | ||
597 | return count; | ||
598 | |||
599 | if (buff[count - 1] == '\n') | ||
600 | buff[count - 1] = '\0'; | ||
601 | |||
602 | if (strlen(buff) >= IFNAMSIZ) { | ||
603 | pr_err("Invalid parameter for 'mesh_iface' setting received: interface name too long '%s'\n", | ||
604 | buff); | ||
605 | batadv_hardif_free_ref(hard_iface); | ||
606 | return -EINVAL; | ||
607 | } | ||
608 | |||
609 | if (strncmp(buff, "none", 4) == 0) | ||
610 | status_tmp = BATADV_IF_NOT_IN_USE; | ||
611 | else | ||
612 | status_tmp = BATADV_IF_I_WANT_YOU; | ||
613 | |||
614 | if (hard_iface->if_status == status_tmp) | ||
615 | goto out; | ||
616 | |||
617 | if ((hard_iface->soft_iface) && | ||
618 | (strncmp(hard_iface->soft_iface->name, buff, IFNAMSIZ) == 0)) | ||
619 | goto out; | ||
620 | |||
621 | if (!rtnl_trylock()) { | ||
622 | ret = -ERESTARTSYS; | ||
623 | goto out; | ||
624 | } | ||
625 | |||
626 | if (status_tmp == BATADV_IF_NOT_IN_USE) { | ||
627 | batadv_hardif_disable_interface(hard_iface); | ||
628 | goto unlock; | ||
629 | } | ||
630 | |||
631 | /* if the interface already is in use */ | ||
632 | if (hard_iface->if_status != BATADV_IF_NOT_IN_USE) | ||
633 | batadv_hardif_disable_interface(hard_iface); | ||
634 | |||
635 | ret = batadv_hardif_enable_interface(hard_iface, buff); | ||
636 | |||
637 | unlock: | ||
638 | rtnl_unlock(); | ||
639 | out: | ||
640 | batadv_hardif_free_ref(hard_iface); | ||
641 | return ret; | ||
642 | } | ||
643 | |||
644 | static ssize_t batadv_show_iface_status(struct kobject *kobj, | ||
645 | struct attribute *attr, char *buff) | ||
646 | { | ||
647 | struct net_device *net_dev = batadv_kobj_to_netdev(kobj); | ||
648 | struct batadv_hard_iface *hard_iface; | ||
649 | ssize_t length; | ||
650 | |||
651 | hard_iface = batadv_hardif_get_by_netdev(net_dev); | ||
652 | if (!hard_iface) | ||
653 | return 0; | ||
654 | |||
655 | switch (hard_iface->if_status) { | ||
656 | case BATADV_IF_TO_BE_REMOVED: | ||
657 | length = sprintf(buff, "disabling\n"); | ||
658 | break; | ||
659 | case BATADV_IF_INACTIVE: | ||
660 | length = sprintf(buff, "inactive\n"); | ||
661 | break; | ||
662 | case BATADV_IF_ACTIVE: | ||
663 | length = sprintf(buff, "active\n"); | ||
664 | break; | ||
665 | case BATADV_IF_TO_BE_ACTIVATED: | ||
666 | length = sprintf(buff, "enabling\n"); | ||
667 | break; | ||
668 | case BATADV_IF_NOT_IN_USE: | ||
669 | default: | ||
670 | length = sprintf(buff, "not in use\n"); | ||
671 | break; | ||
672 | } | ||
673 | |||
674 | batadv_hardif_free_ref(hard_iface); | ||
675 | |||
676 | return length; | ||
677 | } | ||
678 | |||
679 | static BATADV_ATTR(mesh_iface, S_IRUGO | S_IWUSR, batadv_show_mesh_iface, | ||
680 | batadv_store_mesh_iface); | ||
681 | static BATADV_ATTR(iface_status, S_IRUGO, batadv_show_iface_status, NULL); | ||
682 | |||
683 | static struct batadv_attribute *batadv_batman_attrs[] = { | ||
684 | &batadv_attr_mesh_iface, | ||
685 | &batadv_attr_iface_status, | ||
686 | NULL, | ||
687 | }; | ||
688 | |||
689 | int batadv_sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev) | ||
690 | { | ||
691 | struct kobject *hardif_kobject = &dev->dev.kobj; | ||
692 | struct batadv_attribute **bat_attr; | ||
693 | int err; | ||
694 | |||
695 | *hardif_obj = kobject_create_and_add(BATADV_SYSFS_IF_BAT_SUBDIR, | ||
696 | hardif_kobject); | ||
697 | |||
698 | if (!*hardif_obj) { | ||
699 | batadv_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name, | ||
700 | BATADV_SYSFS_IF_BAT_SUBDIR); | ||
701 | goto out; | ||
702 | } | ||
703 | |||
704 | for (bat_attr = batadv_batman_attrs; *bat_attr; ++bat_attr) { | ||
705 | err = sysfs_create_file(*hardif_obj, &((*bat_attr)->attr)); | ||
706 | if (err) { | ||
707 | batadv_err(dev, "Can't add sysfs file: %s/%s/%s\n", | ||
708 | dev->name, BATADV_SYSFS_IF_BAT_SUBDIR, | ||
709 | ((*bat_attr)->attr).name); | ||
710 | goto rem_attr; | ||
711 | } | ||
712 | } | ||
713 | |||
714 | return 0; | ||
715 | |||
716 | rem_attr: | ||
717 | for (bat_attr = batadv_batman_attrs; *bat_attr; ++bat_attr) | ||
718 | sysfs_remove_file(*hardif_obj, &((*bat_attr)->attr)); | ||
719 | out: | ||
720 | return -ENOMEM; | ||
721 | } | ||
722 | |||
723 | void batadv_sysfs_del_hardif(struct kobject **hardif_obj) | ||
724 | { | ||
725 | kobject_put(*hardif_obj); | ||
726 | *hardif_obj = NULL; | ||
727 | } | ||
728 | |||
729 | int batadv_throw_uevent(struct batadv_priv *bat_priv, enum batadv_uev_type type, | ||
730 | enum batadv_uev_action action, const char *data) | ||
731 | { | ||
732 | int ret = -ENOMEM; | ||
733 | struct batadv_hard_iface *primary_if = NULL; | ||
734 | struct kobject *bat_kobj; | ||
735 | char *uevent_env[4] = { NULL, NULL, NULL, NULL }; | ||
736 | |||
737 | primary_if = batadv_primary_if_get_selected(bat_priv); | ||
738 | if (!primary_if) | ||
739 | goto out; | ||
740 | |||
741 | bat_kobj = &primary_if->soft_iface->dev.kobj; | ||
742 | |||
743 | uevent_env[0] = kmalloc(strlen(BATADV_UEV_TYPE_VAR) + | ||
744 | strlen(batadv_uev_type_str[type]) + 1, | ||
745 | GFP_ATOMIC); | ||
746 | if (!uevent_env[0]) | ||
747 | goto out; | ||
748 | |||
749 | sprintf(uevent_env[0], "%s%s", BATADV_UEV_TYPE_VAR, | ||
750 | batadv_uev_type_str[type]); | ||
751 | |||
752 | uevent_env[1] = kmalloc(strlen(BATADV_UEV_ACTION_VAR) + | ||
753 | strlen(batadv_uev_action_str[action]) + 1, | ||
754 | GFP_ATOMIC); | ||
755 | if (!uevent_env[1]) | ||
756 | goto out; | ||
757 | |||
758 | sprintf(uevent_env[1], "%s%s", BATADV_UEV_ACTION_VAR, | ||
759 | batadv_uev_action_str[action]); | ||
760 | |||
761 | /* If the event is DEL, ignore the data field */ | ||
762 | if (action != BATADV_UEV_DEL) { | ||
763 | uevent_env[2] = kmalloc(strlen(BATADV_UEV_DATA_VAR) + | ||
764 | strlen(data) + 1, GFP_ATOMIC); | ||
765 | if (!uevent_env[2]) | ||
766 | goto out; | ||
767 | |||
768 | sprintf(uevent_env[2], "%s%s", BATADV_UEV_DATA_VAR, data); | ||
769 | } | ||
770 | |||
771 | ret = kobject_uevent_env(bat_kobj, KOBJ_CHANGE, uevent_env); | ||
772 | out: | ||
773 | kfree(uevent_env[0]); | ||
774 | kfree(uevent_env[1]); | ||
775 | kfree(uevent_env[2]); | ||
776 | |||
777 | if (primary_if) | ||
778 | batadv_hardif_free_ref(primary_if); | ||
779 | |||
780 | if (ret) | ||
781 | batadv_dbg(BATADV_DBG_BATMAN, bat_priv, | ||
782 | "Impossible to send uevent for (%s,%s,%s) event (err: %d)\n", | ||
783 | batadv_uev_type_str[type], | ||
784 | batadv_uev_action_str[action], | ||
785 | (action == BATADV_UEV_DEL ? "NULL" : data), ret); | ||
786 | return ret; | ||
787 | } | ||