diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
commit | fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch) | |
tree | a57612d1888735a2ec7972891b68c1ac5ec8faea /net/batman-adv/bat_sysfs.c | |
parent | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff) |
Diffstat (limited to 'net/batman-adv/bat_sysfs.c')
-rw-r--r-- | net/batman-adv/bat_sysfs.c | 674 |
1 files changed, 674 insertions, 0 deletions
diff --git a/net/batman-adv/bat_sysfs.c b/net/batman-adv/bat_sysfs.c new file mode 100644 index 00000000000..cd15deba60a --- /dev/null +++ b/net/batman-adv/bat_sysfs.c | |||
@@ -0,0 +1,674 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010-2011 B.A.T.M.A.N. contributors: | ||
3 | * | ||
4 | * Marek Lindner | ||
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 "bat_sysfs.h" | ||
24 | #include "translation-table.h" | ||
25 | #include "originator.h" | ||
26 | #include "hard-interface.h" | ||
27 | #include "gateway_common.h" | ||
28 | #include "gateway_client.h" | ||
29 | #include "vis.h" | ||
30 | |||
31 | static struct net_device *kobj_to_netdev(struct kobject *obj) | ||
32 | { | ||
33 | struct device *dev = container_of(obj->parent, struct device, kobj); | ||
34 | return to_net_dev(dev); | ||
35 | } | ||
36 | |||
37 | static struct bat_priv *kobj_to_batpriv(struct kobject *obj) | ||
38 | { | ||
39 | struct net_device *net_dev = kobj_to_netdev(obj); | ||
40 | return netdev_priv(net_dev); | ||
41 | } | ||
42 | |||
43 | #define UEV_TYPE_VAR "BATTYPE=" | ||
44 | #define UEV_ACTION_VAR "BATACTION=" | ||
45 | #define UEV_DATA_VAR "BATDATA=" | ||
46 | |||
47 | static char *uev_action_str[] = { | ||
48 | "add", | ||
49 | "del", | ||
50 | "change" | ||
51 | }; | ||
52 | |||
53 | static char *uev_type_str[] = { | ||
54 | "gw" | ||
55 | }; | ||
56 | |||
57 | /* Use this, if you have customized show and store functions */ | ||
58 | #define BAT_ATTR(_name, _mode, _show, _store) \ | ||
59 | struct bat_attribute bat_attr_##_name = { \ | ||
60 | .attr = {.name = __stringify(_name), \ | ||
61 | .mode = _mode }, \ | ||
62 | .show = _show, \ | ||
63 | .store = _store, \ | ||
64 | }; | ||
65 | |||
66 | #define BAT_ATTR_STORE_BOOL(_name, _post_func) \ | ||
67 | ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \ | ||
68 | char *buff, size_t count) \ | ||
69 | { \ | ||
70 | struct net_device *net_dev = kobj_to_netdev(kobj); \ | ||
71 | struct bat_priv *bat_priv = netdev_priv(net_dev); \ | ||
72 | return __store_bool_attr(buff, count, _post_func, attr, \ | ||
73 | &bat_priv->_name, net_dev); \ | ||
74 | } | ||
75 | |||
76 | #define BAT_ATTR_SHOW_BOOL(_name) \ | ||
77 | ssize_t show_##_name(struct kobject *kobj, struct attribute *attr, \ | ||
78 | char *buff) \ | ||
79 | { \ | ||
80 | struct bat_priv *bat_priv = kobj_to_batpriv(kobj); \ | ||
81 | return sprintf(buff, "%s\n", \ | ||
82 | atomic_read(&bat_priv->_name) == 0 ? \ | ||
83 | "disabled" : "enabled"); \ | ||
84 | } \ | ||
85 | |||
86 | /* Use this, if you are going to turn a [name] in bat_priv on or off */ | ||
87 | #define BAT_ATTR_BOOL(_name, _mode, _post_func) \ | ||
88 | static BAT_ATTR_STORE_BOOL(_name, _post_func) \ | ||
89 | static BAT_ATTR_SHOW_BOOL(_name) \ | ||
90 | static BAT_ATTR(_name, _mode, show_##_name, store_##_name) | ||
91 | |||
92 | |||
93 | #define BAT_ATTR_STORE_UINT(_name, _min, _max, _post_func) \ | ||
94 | ssize_t store_##_name(struct kobject *kobj, struct attribute *attr, \ | ||
95 | char *buff, size_t count) \ | ||
96 | { \ | ||
97 | struct net_device *net_dev = kobj_to_netdev(kobj); \ | ||
98 | struct bat_priv *bat_priv = netdev_priv(net_dev); \ | ||
99 | return __store_uint_attr(buff, count, _min, _max, _post_func, \ | ||
100 | attr, &bat_priv->_name, net_dev); \ | ||
101 | } | ||
102 | |||
103 | #define BAT_ATTR_SHOW_UINT(_name) \ | ||
104 | ssize_t show_##_name(struct kobject *kobj, struct attribute *attr, \ | ||
105 | char *buff) \ | ||
106 | { \ | ||
107 | struct bat_priv *bat_priv = kobj_to_batpriv(kobj); \ | ||
108 | return sprintf(buff, "%i\n", atomic_read(&bat_priv->_name)); \ | ||
109 | } \ | ||
110 | |||
111 | /* Use this, if you are going to set [name] in bat_priv to unsigned integer | ||
112 | * values only */ | ||
113 | #define BAT_ATTR_UINT(_name, _mode, _min, _max, _post_func) \ | ||
114 | static BAT_ATTR_STORE_UINT(_name, _min, _max, _post_func) \ | ||
115 | static BAT_ATTR_SHOW_UINT(_name) \ | ||
116 | static BAT_ATTR(_name, _mode, show_##_name, store_##_name) | ||
117 | |||
118 | |||
119 | static int store_bool_attr(char *buff, size_t count, | ||
120 | struct net_device *net_dev, | ||
121 | const char *attr_name, atomic_t *attr) | ||
122 | { | ||
123 | int enabled = -1; | ||
124 | |||
125 | if (buff[count - 1] == '\n') | ||
126 | buff[count - 1] = '\0'; | ||
127 | |||
128 | if ((strncmp(buff, "1", 2) == 0) || | ||
129 | (strncmp(buff, "enable", 7) == 0) || | ||
130 | (strncmp(buff, "enabled", 8) == 0)) | ||
131 | enabled = 1; | ||
132 | |||
133 | if ((strncmp(buff, "0", 2) == 0) || | ||
134 | (strncmp(buff, "disable", 8) == 0) || | ||
135 | (strncmp(buff, "disabled", 9) == 0)) | ||
136 | enabled = 0; | ||
137 | |||
138 | if (enabled < 0) { | ||
139 | bat_info(net_dev, | ||
140 | "%s: Invalid parameter received: %s\n", | ||
141 | attr_name, buff); | ||
142 | return -EINVAL; | ||
143 | } | ||
144 | |||
145 | if (atomic_read(attr) == enabled) | ||
146 | return count; | ||
147 | |||
148 | bat_info(net_dev, "%s: Changing from: %s to: %s\n", attr_name, | ||
149 | atomic_read(attr) == 1 ? "enabled" : "disabled", | ||
150 | enabled == 1 ? "enabled" : "disabled"); | ||
151 | |||
152 | atomic_set(attr, (unsigned)enabled); | ||
153 | return count; | ||
154 | } | ||
155 | |||
156 | static inline ssize_t __store_bool_attr(char *buff, size_t count, | ||
157 | void (*post_func)(struct net_device *), | ||
158 | struct attribute *attr, | ||
159 | atomic_t *attr_store, struct net_device *net_dev) | ||
160 | { | ||
161 | int ret; | ||
162 | |||
163 | ret = store_bool_attr(buff, count, net_dev, attr->name, attr_store); | ||
164 | if (post_func && ret) | ||
165 | post_func(net_dev); | ||
166 | |||
167 | return ret; | ||
168 | } | ||
169 | |||
170 | static int store_uint_attr(const char *buff, size_t count, | ||
171 | struct net_device *net_dev, const char *attr_name, | ||
172 | unsigned int min, unsigned int max, atomic_t *attr) | ||
173 | { | ||
174 | unsigned long uint_val; | ||
175 | int ret; | ||
176 | |||
177 | ret = strict_strtoul(buff, 10, &uint_val); | ||
178 | if (ret) { | ||
179 | bat_info(net_dev, | ||
180 | "%s: Invalid parameter received: %s\n", | ||
181 | attr_name, buff); | ||
182 | return -EINVAL; | ||
183 | } | ||
184 | |||
185 | if (uint_val < min) { | ||
186 | bat_info(net_dev, "%s: Value is too small: %lu min: %u\n", | ||
187 | attr_name, uint_val, min); | ||
188 | return -EINVAL; | ||
189 | } | ||
190 | |||
191 | if (uint_val > max) { | ||
192 | bat_info(net_dev, "%s: Value is too big: %lu max: %u\n", | ||
193 | attr_name, uint_val, max); | ||
194 | return -EINVAL; | ||
195 | } | ||
196 | |||
197 | if (atomic_read(attr) == uint_val) | ||
198 | return count; | ||
199 | |||
200 | bat_info(net_dev, "%s: Changing from: %i to: %lu\n", | ||
201 | attr_name, atomic_read(attr), uint_val); | ||
202 | |||
203 | atomic_set(attr, uint_val); | ||
204 | return count; | ||
205 | } | ||
206 | |||
207 | static inline ssize_t __store_uint_attr(const char *buff, size_t count, | ||
208 | int min, int max, | ||
209 | void (*post_func)(struct net_device *), | ||
210 | const struct attribute *attr, | ||
211 | atomic_t *attr_store, struct net_device *net_dev) | ||
212 | { | ||
213 | int ret; | ||
214 | |||
215 | ret = store_uint_attr(buff, count, net_dev, attr->name, | ||
216 | min, max, attr_store); | ||
217 | if (post_func && ret) | ||
218 | post_func(net_dev); | ||
219 | |||
220 | return ret; | ||
221 | } | ||
222 | |||
223 | static ssize_t show_vis_mode(struct kobject *kobj, struct attribute *attr, | ||
224 | char *buff) | ||
225 | { | ||
226 | struct bat_priv *bat_priv = kobj_to_batpriv(kobj); | ||
227 | int vis_mode = atomic_read(&bat_priv->vis_mode); | ||
228 | |||
229 | return sprintf(buff, "%s\n", | ||
230 | vis_mode == VIS_TYPE_CLIENT_UPDATE ? | ||
231 | "client" : "server"); | ||
232 | } | ||
233 | |||
234 | static ssize_t store_vis_mode(struct kobject *kobj, struct attribute *attr, | ||
235 | char *buff, size_t count) | ||
236 | { | ||
237 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
238 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
239 | unsigned long val; | ||
240 | int ret, vis_mode_tmp = -1; | ||
241 | |||
242 | ret = strict_strtoul(buff, 10, &val); | ||
243 | |||
244 | if (((count == 2) && (!ret) && (val == VIS_TYPE_CLIENT_UPDATE)) || | ||
245 | (strncmp(buff, "client", 6) == 0) || | ||
246 | (strncmp(buff, "off", 3) == 0)) | ||
247 | vis_mode_tmp = VIS_TYPE_CLIENT_UPDATE; | ||
248 | |||
249 | if (((count == 2) && (!ret) && (val == VIS_TYPE_SERVER_SYNC)) || | ||
250 | (strncmp(buff, "server", 6) == 0)) | ||
251 | vis_mode_tmp = VIS_TYPE_SERVER_SYNC; | ||
252 | |||
253 | if (vis_mode_tmp < 0) { | ||
254 | if (buff[count - 1] == '\n') | ||
255 | buff[count - 1] = '\0'; | ||
256 | |||
257 | bat_info(net_dev, | ||
258 | "Invalid parameter for 'vis mode' setting received: " | ||
259 | "%s\n", buff); | ||
260 | return -EINVAL; | ||
261 | } | ||
262 | |||
263 | if (atomic_read(&bat_priv->vis_mode) == vis_mode_tmp) | ||
264 | return count; | ||
265 | |||
266 | bat_info(net_dev, "Changing vis mode from: %s to: %s\n", | ||
267 | atomic_read(&bat_priv->vis_mode) == VIS_TYPE_CLIENT_UPDATE ? | ||
268 | "client" : "server", vis_mode_tmp == VIS_TYPE_CLIENT_UPDATE ? | ||
269 | "client" : "server"); | ||
270 | |||
271 | atomic_set(&bat_priv->vis_mode, (unsigned)vis_mode_tmp); | ||
272 | return count; | ||
273 | } | ||
274 | |||
275 | static void post_gw_deselect(struct net_device *net_dev) | ||
276 | { | ||
277 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
278 | gw_deselect(bat_priv); | ||
279 | } | ||
280 | |||
281 | static ssize_t show_gw_mode(struct kobject *kobj, struct attribute *attr, | ||
282 | char *buff) | ||
283 | { | ||
284 | struct bat_priv *bat_priv = kobj_to_batpriv(kobj); | ||
285 | int bytes_written; | ||
286 | |||
287 | switch (atomic_read(&bat_priv->gw_mode)) { | ||
288 | case GW_MODE_CLIENT: | ||
289 | bytes_written = sprintf(buff, "%s\n", GW_MODE_CLIENT_NAME); | ||
290 | break; | ||
291 | case GW_MODE_SERVER: | ||
292 | bytes_written = sprintf(buff, "%s\n", GW_MODE_SERVER_NAME); | ||
293 | break; | ||
294 | default: | ||
295 | bytes_written = sprintf(buff, "%s\n", GW_MODE_OFF_NAME); | ||
296 | break; | ||
297 | } | ||
298 | |||
299 | return bytes_written; | ||
300 | } | ||
301 | |||
302 | static ssize_t store_gw_mode(struct kobject *kobj, struct attribute *attr, | ||
303 | char *buff, size_t count) | ||
304 | { | ||
305 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
306 | struct bat_priv *bat_priv = netdev_priv(net_dev); | ||
307 | char *curr_gw_mode_str; | ||
308 | int gw_mode_tmp = -1; | ||
309 | |||
310 | if (buff[count - 1] == '\n') | ||
311 | buff[count - 1] = '\0'; | ||
312 | |||
313 | if (strncmp(buff, GW_MODE_OFF_NAME, strlen(GW_MODE_OFF_NAME)) == 0) | ||
314 | gw_mode_tmp = GW_MODE_OFF; | ||
315 | |||
316 | if (strncmp(buff, GW_MODE_CLIENT_NAME, | ||
317 | strlen(GW_MODE_CLIENT_NAME)) == 0) | ||
318 | gw_mode_tmp = GW_MODE_CLIENT; | ||
319 | |||
320 | if (strncmp(buff, GW_MODE_SERVER_NAME, | ||
321 | strlen(GW_MODE_SERVER_NAME)) == 0) | ||
322 | gw_mode_tmp = GW_MODE_SERVER; | ||
323 | |||
324 | if (gw_mode_tmp < 0) { | ||
325 | bat_info(net_dev, | ||
326 | "Invalid parameter for 'gw mode' setting received: " | ||
327 | "%s\n", buff); | ||
328 | return -EINVAL; | ||
329 | } | ||
330 | |||
331 | if (atomic_read(&bat_priv->gw_mode) == gw_mode_tmp) | ||
332 | return count; | ||
333 | |||
334 | switch (atomic_read(&bat_priv->gw_mode)) { | ||
335 | case GW_MODE_CLIENT: | ||
336 | curr_gw_mode_str = GW_MODE_CLIENT_NAME; | ||
337 | break; | ||
338 | case GW_MODE_SERVER: | ||
339 | curr_gw_mode_str = GW_MODE_SERVER_NAME; | ||
340 | break; | ||
341 | default: | ||
342 | curr_gw_mode_str = GW_MODE_OFF_NAME; | ||
343 | break; | ||
344 | } | ||
345 | |||
346 | bat_info(net_dev, "Changing gw mode from: %s to: %s\n", | ||
347 | curr_gw_mode_str, buff); | ||
348 | |||
349 | gw_deselect(bat_priv); | ||
350 | atomic_set(&bat_priv->gw_mode, (unsigned)gw_mode_tmp); | ||
351 | return count; | ||
352 | } | ||
353 | |||
354 | static ssize_t show_gw_bwidth(struct kobject *kobj, struct attribute *attr, | ||
355 | char *buff) | ||
356 | { | ||
357 | struct bat_priv *bat_priv = kobj_to_batpriv(kobj); | ||
358 | int down, up; | ||
359 | int gw_bandwidth = atomic_read(&bat_priv->gw_bandwidth); | ||
360 | |||
361 | gw_bandwidth_to_kbit(gw_bandwidth, &down, &up); | ||
362 | return sprintf(buff, "%i%s/%i%s\n", | ||
363 | (down > 2048 ? down / 1024 : down), | ||
364 | (down > 2048 ? "MBit" : "KBit"), | ||
365 | (up > 2048 ? up / 1024 : up), | ||
366 | (up > 2048 ? "MBit" : "KBit")); | ||
367 | } | ||
368 | |||
369 | static ssize_t store_gw_bwidth(struct kobject *kobj, struct attribute *attr, | ||
370 | char *buff, size_t count) | ||
371 | { | ||
372 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
373 | |||
374 | if (buff[count - 1] == '\n') | ||
375 | buff[count - 1] = '\0'; | ||
376 | |||
377 | return gw_bandwidth_set(net_dev, buff, count); | ||
378 | } | ||
379 | |||
380 | BAT_ATTR_BOOL(aggregated_ogms, S_IRUGO | S_IWUSR, NULL); | ||
381 | BAT_ATTR_BOOL(bonding, S_IRUGO | S_IWUSR, NULL); | ||
382 | BAT_ATTR_BOOL(fragmentation, S_IRUGO | S_IWUSR, update_min_mtu); | ||
383 | static BAT_ATTR(vis_mode, S_IRUGO | S_IWUSR, show_vis_mode, store_vis_mode); | ||
384 | static BAT_ATTR(gw_mode, S_IRUGO | S_IWUSR, show_gw_mode, store_gw_mode); | ||
385 | BAT_ATTR_UINT(orig_interval, S_IRUGO | S_IWUSR, 2 * JITTER, INT_MAX, NULL); | ||
386 | BAT_ATTR_UINT(hop_penalty, S_IRUGO | S_IWUSR, 0, TQ_MAX_VALUE, NULL); | ||
387 | BAT_ATTR_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, TQ_MAX_VALUE, | ||
388 | post_gw_deselect); | ||
389 | static BAT_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, show_gw_bwidth, | ||
390 | store_gw_bwidth); | ||
391 | #ifdef CONFIG_BATMAN_ADV_DEBUG | ||
392 | BAT_ATTR_UINT(log_level, S_IRUGO | S_IWUSR, 0, 7, NULL); | ||
393 | #endif | ||
394 | |||
395 | static struct bat_attribute *mesh_attrs[] = { | ||
396 | &bat_attr_aggregated_ogms, | ||
397 | &bat_attr_bonding, | ||
398 | &bat_attr_fragmentation, | ||
399 | &bat_attr_vis_mode, | ||
400 | &bat_attr_gw_mode, | ||
401 | &bat_attr_orig_interval, | ||
402 | &bat_attr_hop_penalty, | ||
403 | &bat_attr_gw_sel_class, | ||
404 | &bat_attr_gw_bandwidth, | ||
405 | #ifdef CONFIG_BATMAN_ADV_DEBUG | ||
406 | &bat_attr_log_level, | ||
407 | #endif | ||
408 | NULL, | ||
409 | }; | ||
410 | |||
411 | int sysfs_add_meshif(struct net_device *dev) | ||
412 | { | ||
413 | struct kobject *batif_kobject = &dev->dev.kobj; | ||
414 | struct bat_priv *bat_priv = netdev_priv(dev); | ||
415 | struct bat_attribute **bat_attr; | ||
416 | int err; | ||
417 | |||
418 | bat_priv->mesh_obj = kobject_create_and_add(SYSFS_IF_MESH_SUBDIR, | ||
419 | batif_kobject); | ||
420 | if (!bat_priv->mesh_obj) { | ||
421 | bat_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name, | ||
422 | SYSFS_IF_MESH_SUBDIR); | ||
423 | goto out; | ||
424 | } | ||
425 | |||
426 | for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr) { | ||
427 | err = sysfs_create_file(bat_priv->mesh_obj, | ||
428 | &((*bat_attr)->attr)); | ||
429 | if (err) { | ||
430 | bat_err(dev, "Can't add sysfs file: %s/%s/%s\n", | ||
431 | dev->name, SYSFS_IF_MESH_SUBDIR, | ||
432 | ((*bat_attr)->attr).name); | ||
433 | goto rem_attr; | ||
434 | } | ||
435 | } | ||
436 | |||
437 | return 0; | ||
438 | |||
439 | rem_attr: | ||
440 | for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr) | ||
441 | sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr)); | ||
442 | |||
443 | kobject_put(bat_priv->mesh_obj); | ||
444 | bat_priv->mesh_obj = NULL; | ||
445 | out: | ||
446 | return -ENOMEM; | ||
447 | } | ||
448 | |||
449 | void sysfs_del_meshif(struct net_device *dev) | ||
450 | { | ||
451 | struct bat_priv *bat_priv = netdev_priv(dev); | ||
452 | struct bat_attribute **bat_attr; | ||
453 | |||
454 | for (bat_attr = mesh_attrs; *bat_attr; ++bat_attr) | ||
455 | sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr)); | ||
456 | |||
457 | kobject_put(bat_priv->mesh_obj); | ||
458 | bat_priv->mesh_obj = NULL; | ||
459 | } | ||
460 | |||
461 | static ssize_t show_mesh_iface(struct kobject *kobj, struct attribute *attr, | ||
462 | char *buff) | ||
463 | { | ||
464 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
465 | struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev); | ||
466 | ssize_t length; | ||
467 | |||
468 | if (!hard_iface) | ||
469 | return 0; | ||
470 | |||
471 | length = sprintf(buff, "%s\n", hard_iface->if_status == IF_NOT_IN_USE ? | ||
472 | "none" : hard_iface->soft_iface->name); | ||
473 | |||
474 | hardif_free_ref(hard_iface); | ||
475 | |||
476 | return length; | ||
477 | } | ||
478 | |||
479 | static ssize_t store_mesh_iface(struct kobject *kobj, struct attribute *attr, | ||
480 | char *buff, size_t count) | ||
481 | { | ||
482 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
483 | struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev); | ||
484 | int status_tmp = -1; | ||
485 | int ret = count; | ||
486 | |||
487 | if (!hard_iface) | ||
488 | return count; | ||
489 | |||
490 | if (buff[count - 1] == '\n') | ||
491 | buff[count - 1] = '\0'; | ||
492 | |||
493 | if (strlen(buff) >= IFNAMSIZ) { | ||
494 | pr_err("Invalid parameter for 'mesh_iface' setting received: " | ||
495 | "interface name too long '%s'\n", buff); | ||
496 | hardif_free_ref(hard_iface); | ||
497 | return -EINVAL; | ||
498 | } | ||
499 | |||
500 | if (strncmp(buff, "none", 4) == 0) | ||
501 | status_tmp = IF_NOT_IN_USE; | ||
502 | else | ||
503 | status_tmp = IF_I_WANT_YOU; | ||
504 | |||
505 | if (hard_iface->if_status == status_tmp) | ||
506 | goto out; | ||
507 | |||
508 | if ((hard_iface->soft_iface) && | ||
509 | (strncmp(hard_iface->soft_iface->name, buff, IFNAMSIZ) == 0)) | ||
510 | goto out; | ||
511 | |||
512 | if (!rtnl_trylock()) { | ||
513 | ret = -ERESTARTSYS; | ||
514 | goto out; | ||
515 | } | ||
516 | |||
517 | if (status_tmp == IF_NOT_IN_USE) { | ||
518 | hardif_disable_interface(hard_iface); | ||
519 | goto unlock; | ||
520 | } | ||
521 | |||
522 | /* if the interface already is in use */ | ||
523 | if (hard_iface->if_status != IF_NOT_IN_USE) | ||
524 | hardif_disable_interface(hard_iface); | ||
525 | |||
526 | ret = hardif_enable_interface(hard_iface, buff); | ||
527 | |||
528 | unlock: | ||
529 | rtnl_unlock(); | ||
530 | out: | ||
531 | hardif_free_ref(hard_iface); | ||
532 | return ret; | ||
533 | } | ||
534 | |||
535 | static ssize_t show_iface_status(struct kobject *kobj, struct attribute *attr, | ||
536 | char *buff) | ||
537 | { | ||
538 | struct net_device *net_dev = kobj_to_netdev(kobj); | ||
539 | struct hard_iface *hard_iface = hardif_get_by_netdev(net_dev); | ||
540 | ssize_t length; | ||
541 | |||
542 | if (!hard_iface) | ||
543 | return 0; | ||
544 | |||
545 | switch (hard_iface->if_status) { | ||
546 | case IF_TO_BE_REMOVED: | ||
547 | length = sprintf(buff, "disabling\n"); | ||
548 | break; | ||
549 | case IF_INACTIVE: | ||
550 | length = sprintf(buff, "inactive\n"); | ||
551 | break; | ||
552 | case IF_ACTIVE: | ||
553 | length = sprintf(buff, "active\n"); | ||
554 | break; | ||
555 | case IF_TO_BE_ACTIVATED: | ||
556 | length = sprintf(buff, "enabling\n"); | ||
557 | break; | ||
558 | case IF_NOT_IN_USE: | ||
559 | default: | ||
560 | length = sprintf(buff, "not in use\n"); | ||
561 | break; | ||
562 | } | ||
563 | |||
564 | hardif_free_ref(hard_iface); | ||
565 | |||
566 | return length; | ||
567 | } | ||
568 | |||
569 | static BAT_ATTR(mesh_iface, S_IRUGO | S_IWUSR, | ||
570 | show_mesh_iface, store_mesh_iface); | ||
571 | static BAT_ATTR(iface_status, S_IRUGO, show_iface_status, NULL); | ||
572 | |||
573 | static struct bat_attribute *batman_attrs[] = { | ||
574 | &bat_attr_mesh_iface, | ||
575 | &bat_attr_iface_status, | ||
576 | NULL, | ||
577 | }; | ||
578 | |||
579 | int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev) | ||
580 | { | ||
581 | struct kobject *hardif_kobject = &dev->dev.kobj; | ||
582 | struct bat_attribute **bat_attr; | ||
583 | int err; | ||
584 | |||
585 | *hardif_obj = kobject_create_and_add(SYSFS_IF_BAT_SUBDIR, | ||
586 | hardif_kobject); | ||
587 | |||
588 | if (!*hardif_obj) { | ||
589 | bat_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name, | ||
590 | SYSFS_IF_BAT_SUBDIR); | ||
591 | goto out; | ||
592 | } | ||
593 | |||
594 | for (bat_attr = batman_attrs; *bat_attr; ++bat_attr) { | ||
595 | err = sysfs_create_file(*hardif_obj, &((*bat_attr)->attr)); | ||
596 | if (err) { | ||
597 | bat_err(dev, "Can't add sysfs file: %s/%s/%s\n", | ||
598 | dev->name, SYSFS_IF_BAT_SUBDIR, | ||
599 | ((*bat_attr)->attr).name); | ||
600 | goto rem_attr; | ||
601 | } | ||
602 | } | ||
603 | |||
604 | return 0; | ||
605 | |||
606 | rem_attr: | ||
607 | for (bat_attr = batman_attrs; *bat_attr; ++bat_attr) | ||
608 | sysfs_remove_file(*hardif_obj, &((*bat_attr)->attr)); | ||
609 | out: | ||
610 | return -ENOMEM; | ||
611 | } | ||
612 | |||
613 | void sysfs_del_hardif(struct kobject **hardif_obj) | ||
614 | { | ||
615 | kobject_put(*hardif_obj); | ||
616 | *hardif_obj = NULL; | ||
617 | } | ||
618 | |||
619 | int throw_uevent(struct bat_priv *bat_priv, enum uev_type type, | ||
620 | enum uev_action action, const char *data) | ||
621 | { | ||
622 | int ret = -1; | ||
623 | struct hard_iface *primary_if = NULL; | ||
624 | struct kobject *bat_kobj; | ||
625 | char *uevent_env[4] = { NULL, NULL, NULL, NULL }; | ||
626 | |||
627 | primary_if = primary_if_get_selected(bat_priv); | ||
628 | if (!primary_if) | ||
629 | goto out; | ||
630 | |||
631 | bat_kobj = &primary_if->soft_iface->dev.kobj; | ||
632 | |||
633 | uevent_env[0] = kmalloc(strlen(UEV_TYPE_VAR) + | ||
634 | strlen(uev_type_str[type]) + 1, | ||
635 | GFP_ATOMIC); | ||
636 | if (!uevent_env[0]) | ||
637 | goto out; | ||
638 | |||
639 | sprintf(uevent_env[0], "%s%s", UEV_TYPE_VAR, uev_type_str[type]); | ||
640 | |||
641 | uevent_env[1] = kmalloc(strlen(UEV_ACTION_VAR) + | ||
642 | strlen(uev_action_str[action]) + 1, | ||
643 | GFP_ATOMIC); | ||
644 | if (!uevent_env[1]) | ||
645 | goto out; | ||
646 | |||
647 | sprintf(uevent_env[1], "%s%s", UEV_ACTION_VAR, uev_action_str[action]); | ||
648 | |||
649 | /* If the event is DEL, ignore the data field */ | ||
650 | if (action != UEV_DEL) { | ||
651 | uevent_env[2] = kmalloc(strlen(UEV_DATA_VAR) + | ||
652 | strlen(data) + 1, GFP_ATOMIC); | ||
653 | if (!uevent_env[2]) | ||
654 | goto out; | ||
655 | |||
656 | sprintf(uevent_env[2], "%s%s", UEV_DATA_VAR, data); | ||
657 | } | ||
658 | |||
659 | ret = kobject_uevent_env(bat_kobj, KOBJ_CHANGE, uevent_env); | ||
660 | out: | ||
661 | kfree(uevent_env[0]); | ||
662 | kfree(uevent_env[1]); | ||
663 | kfree(uevent_env[2]); | ||
664 | |||
665 | if (primary_if) | ||
666 | hardif_free_ref(primary_if); | ||
667 | |||
668 | if (ret) | ||
669 | bat_dbg(DBG_BATMAN, bat_priv, "Impossible to send " | ||
670 | "uevent for (%s,%s,%s) event (err: %d)\n", | ||
671 | uev_type_str[type], uev_action_str[action], | ||
672 | (action == UEV_DEL ? "NULL" : data), ret); | ||
673 | return ret; | ||
674 | } | ||