batman-adv: remove FSF address from GPL disclaimer
[linux-2.6-block.git] / net / batman-adv / sysfs.c
CommitLineData
0b873931 1/* Copyright (C) 2010-2013 B.A.T.M.A.N. contributors:
c6c8fea2
SE
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
ebf38fb7 15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
c6c8fea2
SE
16 */
17
18#include "main.h"
b706b13b 19#include "sysfs.h"
c6c8fea2 20#include "translation-table.h"
33af49ad 21#include "distributed-arp-table.h"
3f4841ff 22#include "network-coding.h"
c6c8fea2
SE
23#include "originator.h"
24#include "hard-interface.h"
90f4435d 25#include "soft-interface.h"
c6c8fea2
SE
26#include "gateway_common.h"
27#include "gateway_client.h"
c6c8fea2 28
0ff9b86f 29static struct net_device *batadv_kobj_to_netdev(struct kobject *obj)
3d222bba
SE
30{
31 struct device *dev = container_of(obj->parent, struct device, kobj);
32 return to_net_dev(dev);
33}
34
56303d34 35static struct batadv_priv *batadv_kobj_to_batpriv(struct kobject *obj)
3d222bba 36{
0ff9b86f 37 struct net_device *net_dev = batadv_kobj_to_netdev(obj);
3d222bba
SE
38 return netdev_priv(net_dev);
39}
c6c8fea2 40
90f4435d
AQ
41/**
42 * batadv_vlan_kobj_to_batpriv - convert a vlan kobj in the associated batpriv
43 * @obj: kobject to covert
44 *
45 * Returns the associated batadv_priv struct.
46 */
47static struct batadv_priv *batadv_vlan_kobj_to_batpriv(struct kobject *obj)
48{
49 /* VLAN specific attributes are located in the root sysfs folder if they
50 * refer to the untagged VLAN..
51 */
52 if (!strcmp(BATADV_SYSFS_IF_MESH_SUBDIR, obj->name))
53 return batadv_kobj_to_batpriv(obj);
54
55 /* ..while the attributes for the tagged vlans are located in
56 * the in the corresponding "vlan%VID" subfolder
57 */
58 return batadv_kobj_to_batpriv(obj->parent);
59}
60
61/**
62 * batadv_kobj_to_vlan - convert a kobj in the associated softif_vlan struct
63 * @obj: kobject to covert
64 *
65 * Returns the associated softif_vlan struct if found, NULL otherwise.
66 */
67static struct batadv_softif_vlan *
68batadv_kobj_to_vlan(struct batadv_priv *bat_priv, struct kobject *obj)
69{
70 struct batadv_softif_vlan *vlan_tmp, *vlan = NULL;
71
72 rcu_read_lock();
73 hlist_for_each_entry_rcu(vlan_tmp, &bat_priv->softif_vlan_list, list) {
74 if (vlan_tmp->kobj != obj)
75 continue;
76
77 if (!atomic_inc_not_zero(&vlan_tmp->refcount))
78 continue;
79
80 vlan = vlan_tmp;
81 break;
82 }
83 rcu_read_unlock();
84
85 return vlan;
86}
87
347c80f0
SE
88#define BATADV_UEV_TYPE_VAR "BATTYPE="
89#define BATADV_UEV_ACTION_VAR "BATACTION="
90#define BATADV_UEV_DATA_VAR "BATDATA="
c6bda689 91
0ff9b86f 92static char *batadv_uev_action_str[] = {
c6bda689
AQ
93 "add",
94 "del",
95 "change"
96};
97
0ff9b86f 98static char *batadv_uev_type_str[] = {
c6bda689
AQ
99 "gw"
100};
101
90f4435d
AQ
102/* Use this, if you have customized show and store functions for vlan attrs */
103#define BATADV_ATTR_VLAN(_name, _mode, _show, _store) \
104struct batadv_attribute batadv_attr_vlan_##_name = { \
105 .attr = {.name = __stringify(_name), \
106 .mode = _mode }, \
107 .show = _show, \
108 .store = _store, \
109};
110
c6c8fea2 111/* Use this, if you have customized show and store functions */
347c80f0 112#define BATADV_ATTR(_name, _mode, _show, _store) \
b4d66b87 113struct batadv_attribute batadv_attr_##_name = { \
347c80f0
SE
114 .attr = {.name = __stringify(_name), \
115 .mode = _mode }, \
116 .show = _show, \
117 .store = _store, \
c6c8fea2
SE
118};
119
347c80f0 120#define BATADV_ATTR_SIF_STORE_BOOL(_name, _post_func) \
0ff9b86f
SE
121ssize_t batadv_store_##_name(struct kobject *kobj, \
122 struct attribute *attr, char *buff, \
123 size_t count) \
c6c8fea2 124{ \
0ff9b86f 125 struct net_device *net_dev = batadv_kobj_to_netdev(kobj); \
56303d34 126 struct batadv_priv *bat_priv = netdev_priv(net_dev); \
0ff9b86f
SE
127 return __batadv_store_bool_attr(buff, count, _post_func, attr, \
128 &bat_priv->_name, net_dev); \
c6c8fea2
SE
129}
130
347c80f0 131#define BATADV_ATTR_SIF_SHOW_BOOL(_name) \
0ff9b86f
SE
132ssize_t batadv_show_##_name(struct kobject *kobj, \
133 struct attribute *attr, char *buff) \
c6c8fea2 134{ \
56303d34 135 struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); \
c6c8fea2
SE
136 return sprintf(buff, "%s\n", \
137 atomic_read(&bat_priv->_name) == 0 ? \
138 "disabled" : "enabled"); \
139} \
140
f245c38b 141/* Use this, if you are going to turn a [name] in the soft-interface
9cfc7bd6
SE
142 * (bat_priv) on or off
143 */
347c80f0
SE
144#define BATADV_ATTR_SIF_BOOL(_name, _mode, _post_func) \
145 static BATADV_ATTR_SIF_STORE_BOOL(_name, _post_func) \
146 static BATADV_ATTR_SIF_SHOW_BOOL(_name) \
147 static BATADV_ATTR(_name, _mode, batadv_show_##_name, \
148 batadv_store_##_name)
c6c8fea2
SE
149
150
347c80f0 151#define BATADV_ATTR_SIF_STORE_UINT(_name, _min, _max, _post_func) \
0ff9b86f
SE
152ssize_t batadv_store_##_name(struct kobject *kobj, \
153 struct attribute *attr, char *buff, \
154 size_t count) \
c6c8fea2 155{ \
0ff9b86f 156 struct net_device *net_dev = batadv_kobj_to_netdev(kobj); \
56303d34 157 struct batadv_priv *bat_priv = netdev_priv(net_dev); \
0ff9b86f
SE
158 return __batadv_store_uint_attr(buff, count, _min, _max, \
159 _post_func, attr, \
160 &bat_priv->_name, net_dev); \
c6c8fea2
SE
161}
162
347c80f0 163#define BATADV_ATTR_SIF_SHOW_UINT(_name) \
0ff9b86f
SE
164ssize_t batadv_show_##_name(struct kobject *kobj, \
165 struct attribute *attr, char *buff) \
c6c8fea2 166{ \
56303d34 167 struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); \
c6c8fea2
SE
168 return sprintf(buff, "%i\n", atomic_read(&bat_priv->_name)); \
169} \
170
f245c38b 171/* Use this, if you are going to set [name] in the soft-interface
9cfc7bd6
SE
172 * (bat_priv) to an unsigned integer value
173 */
347c80f0
SE
174#define BATADV_ATTR_SIF_UINT(_name, _mode, _min, _max, _post_func) \
175 static BATADV_ATTR_SIF_STORE_UINT(_name, _min, _max, _post_func)\
176 static BATADV_ATTR_SIF_SHOW_UINT(_name) \
177 static BATADV_ATTR(_name, _mode, batadv_show_##_name, \
178 batadv_store_##_name)
c6c8fea2 179
90f4435d
AQ
180#define BATADV_ATTR_VLAN_STORE_BOOL(_name, _post_func) \
181ssize_t batadv_store_vlan_##_name(struct kobject *kobj, \
182 struct attribute *attr, char *buff, \
183 size_t count) \
184{ \
185 struct batadv_priv *bat_priv = batadv_vlan_kobj_to_batpriv(kobj);\
186 struct batadv_softif_vlan *vlan = batadv_kobj_to_vlan(bat_priv, \
187 kobj); \
188 size_t res = __batadv_store_bool_attr(buff, count, _post_func, \
189 attr, &vlan->_name, \
190 bat_priv->soft_iface); \
191 batadv_softif_vlan_free_ref(vlan); \
192 return res; \
193}
194
195#define BATADV_ATTR_VLAN_SHOW_BOOL(_name) \
196ssize_t batadv_show_vlan_##_name(struct kobject *kobj, \
197 struct attribute *attr, char *buff) \
198{ \
199 struct batadv_priv *bat_priv = batadv_vlan_kobj_to_batpriv(kobj);\
200 struct batadv_softif_vlan *vlan = batadv_kobj_to_vlan(bat_priv, \
201 kobj); \
202 size_t res = sprintf(buff, "%s\n", \
203 atomic_read(&vlan->_name) == 0 ? \
204 "disabled" : "enabled"); \
205 batadv_softif_vlan_free_ref(vlan); \
206 return res; \
207}
208
209/* Use this, if you are going to turn a [name] in the vlan struct on or off */
210#define BATADV_ATTR_VLAN_BOOL(_name, _mode, _post_func) \
211 static BATADV_ATTR_VLAN_STORE_BOOL(_name, _post_func) \
212 static BATADV_ATTR_VLAN_SHOW_BOOL(_name) \
213 static BATADV_ATTR_VLAN(_name, _mode, batadv_show_vlan_##_name, \
214 batadv_store_vlan_##_name)
c6c8fea2 215
0ff9b86f
SE
216static int batadv_store_bool_attr(char *buff, size_t count,
217 struct net_device *net_dev,
218 const char *attr_name, atomic_t *attr)
c6c8fea2
SE
219{
220 int enabled = -1;
221
222 if (buff[count - 1] == '\n')
223 buff[count - 1] = '\0';
224
225 if ((strncmp(buff, "1", 2) == 0) ||
226 (strncmp(buff, "enable", 7) == 0) ||
227 (strncmp(buff, "enabled", 8) == 0))
228 enabled = 1;
229
230 if ((strncmp(buff, "0", 2) == 0) ||
231 (strncmp(buff, "disable", 8) == 0) ||
232 (strncmp(buff, "disabled", 9) == 0))
233 enabled = 0;
234
235 if (enabled < 0) {
3e34819e
SE
236 batadv_info(net_dev, "%s: Invalid parameter received: %s\n",
237 attr_name, buff);
c6c8fea2
SE
238 return -EINVAL;
239 }
240
241 if (atomic_read(attr) == enabled)
242 return count;
243
3e34819e
SE
244 batadv_info(net_dev, "%s: Changing from: %s to: %s\n", attr_name,
245 atomic_read(attr) == 1 ? "enabled" : "disabled",
246 enabled == 1 ? "enabled" : "disabled");
c6c8fea2 247
95c96174 248 atomic_set(attr, (unsigned int)enabled);
c6c8fea2
SE
249 return count;
250}
251
0ff9b86f
SE
252static inline ssize_t
253__batadv_store_bool_attr(char *buff, size_t count,
254 void (*post_func)(struct net_device *),
255 struct attribute *attr,
256 atomic_t *attr_store, struct net_device *net_dev)
c6c8fea2
SE
257{
258 int ret;
259
0ff9b86f
SE
260 ret = batadv_store_bool_attr(buff, count, net_dev, attr->name,
261 attr_store);
c6c8fea2
SE
262 if (post_func && ret)
263 post_func(net_dev);
264
265 return ret;
266}
267
0ff9b86f
SE
268static int batadv_store_uint_attr(const char *buff, size_t count,
269 struct net_device *net_dev,
270 const char *attr_name,
271 unsigned int min, unsigned int max,
272 atomic_t *attr)
c6c8fea2
SE
273{
274 unsigned long uint_val;
275 int ret;
276
25a92b13 277 ret = kstrtoul(buff, 10, &uint_val);
c6c8fea2 278 if (ret) {
3e34819e
SE
279 batadv_info(net_dev, "%s: Invalid parameter received: %s\n",
280 attr_name, buff);
c6c8fea2
SE
281 return -EINVAL;
282 }
283
284 if (uint_val < min) {
3e34819e
SE
285 batadv_info(net_dev, "%s: Value is too small: %lu min: %u\n",
286 attr_name, uint_val, min);
c6c8fea2
SE
287 return -EINVAL;
288 }
289
290 if (uint_val > max) {
3e34819e
SE
291 batadv_info(net_dev, "%s: Value is too big: %lu max: %u\n",
292 attr_name, uint_val, max);
c6c8fea2
SE
293 return -EINVAL;
294 }
295
296 if (atomic_read(attr) == uint_val)
297 return count;
298
3e34819e
SE
299 batadv_info(net_dev, "%s: Changing from: %i to: %lu\n",
300 attr_name, atomic_read(attr), uint_val);
c6c8fea2
SE
301
302 atomic_set(attr, uint_val);
303 return count;
304}
305
0ff9b86f
SE
306static inline ssize_t
307__batadv_store_uint_attr(const char *buff, size_t count,
308 int min, int max,
309 void (*post_func)(struct net_device *),
310 const struct attribute *attr,
311 atomic_t *attr_store, struct net_device *net_dev)
c6c8fea2
SE
312{
313 int ret;
314
0ff9b86f
SE
315 ret = batadv_store_uint_attr(buff, count, net_dev, attr->name, min, max,
316 attr_store);
c6c8fea2
SE
317 if (post_func && ret)
318 post_func(net_dev);
319
320 return ret;
321}
322
0ff9b86f
SE
323static ssize_t batadv_show_bat_algo(struct kobject *kobj,
324 struct attribute *attr, char *buff)
ea3d2fd1 325{
56303d34 326 struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj);
ea3d2fd1
ML
327 return sprintf(buff, "%s\n", bat_priv->bat_algo_ops->name);
328}
329
0ff9b86f 330static void batadv_post_gw_deselect(struct net_device *net_dev)
c6c8fea2 331{
56303d34 332 struct batadv_priv *bat_priv = netdev_priv(net_dev);
7cf06bc6 333 batadv_gw_deselect(bat_priv);
c6c8fea2
SE
334}
335
0ff9b86f
SE
336static ssize_t batadv_show_gw_mode(struct kobject *kobj, struct attribute *attr,
337 char *buff)
c6c8fea2 338{
56303d34 339 struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj);
c6c8fea2
SE
340 int bytes_written;
341
342 switch (atomic_read(&bat_priv->gw_mode)) {
cd646ab1 343 case BATADV_GW_MODE_CLIENT:
97ea4ba1
SE
344 bytes_written = sprintf(buff, "%s\n",
345 BATADV_GW_MODE_CLIENT_NAME);
c6c8fea2 346 break;
cd646ab1 347 case BATADV_GW_MODE_SERVER:
97ea4ba1
SE
348 bytes_written = sprintf(buff, "%s\n",
349 BATADV_GW_MODE_SERVER_NAME);
c6c8fea2
SE
350 break;
351 default:
97ea4ba1
SE
352 bytes_written = sprintf(buff, "%s\n",
353 BATADV_GW_MODE_OFF_NAME);
c6c8fea2
SE
354 break;
355 }
356
357 return bytes_written;
358}
359
0ff9b86f
SE
360static ssize_t batadv_store_gw_mode(struct kobject *kobj,
361 struct attribute *attr, char *buff,
362 size_t count)
c6c8fea2 363{
0ff9b86f 364 struct net_device *net_dev = batadv_kobj_to_netdev(kobj);
56303d34 365 struct batadv_priv *bat_priv = netdev_priv(net_dev);
c6c8fea2
SE
366 char *curr_gw_mode_str;
367 int gw_mode_tmp = -1;
368
369 if (buff[count - 1] == '\n')
370 buff[count - 1] = '\0';
371
97ea4ba1
SE
372 if (strncmp(buff, BATADV_GW_MODE_OFF_NAME,
373 strlen(BATADV_GW_MODE_OFF_NAME)) == 0)
cd646ab1 374 gw_mode_tmp = BATADV_GW_MODE_OFF;
c6c8fea2 375
97ea4ba1
SE
376 if (strncmp(buff, BATADV_GW_MODE_CLIENT_NAME,
377 strlen(BATADV_GW_MODE_CLIENT_NAME)) == 0)
cd646ab1 378 gw_mode_tmp = BATADV_GW_MODE_CLIENT;
c6c8fea2 379
97ea4ba1
SE
380 if (strncmp(buff, BATADV_GW_MODE_SERVER_NAME,
381 strlen(BATADV_GW_MODE_SERVER_NAME)) == 0)
cd646ab1 382 gw_mode_tmp = BATADV_GW_MODE_SERVER;
c6c8fea2
SE
383
384 if (gw_mode_tmp < 0) {
3e34819e
SE
385 batadv_info(net_dev,
386 "Invalid parameter for 'gw mode' setting received: %s\n",
387 buff);
c6c8fea2
SE
388 return -EINVAL;
389 }
390
391 if (atomic_read(&bat_priv->gw_mode) == gw_mode_tmp)
392 return count;
393
394 switch (atomic_read(&bat_priv->gw_mode)) {
cd646ab1 395 case BATADV_GW_MODE_CLIENT:
97ea4ba1 396 curr_gw_mode_str = BATADV_GW_MODE_CLIENT_NAME;
c6c8fea2 397 break;
cd646ab1 398 case BATADV_GW_MODE_SERVER:
97ea4ba1 399 curr_gw_mode_str = BATADV_GW_MODE_SERVER_NAME;
c6c8fea2
SE
400 break;
401 default:
97ea4ba1 402 curr_gw_mode_str = BATADV_GW_MODE_OFF_NAME;
c6c8fea2
SE
403 break;
404 }
405
3e34819e
SE
406 batadv_info(net_dev, "Changing gw mode from: %s to: %s\n",
407 curr_gw_mode_str, buff);
c6c8fea2 408
7cf06bc6 409 batadv_gw_deselect(bat_priv);
c6eaa3f0
AQ
410 /* always call batadv_gw_check_client_stop() before changing the gateway
411 * state
412 */
413 batadv_gw_check_client_stop(bat_priv);
95c96174 414 atomic_set(&bat_priv->gw_mode, (unsigned int)gw_mode_tmp);
414254e3 415 batadv_gw_tvlv_container_update(bat_priv);
c6c8fea2
SE
416 return count;
417}
418
0ff9b86f
SE
419static ssize_t batadv_show_gw_bwidth(struct kobject *kobj,
420 struct attribute *attr, char *buff)
c6c8fea2 421{
56303d34 422 struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj);
414254e3
ML
423 uint32_t down, up;
424
425 down = atomic_read(&bat_priv->gw.bandwidth_down);
426 up = atomic_read(&bat_priv->gw.bandwidth_up);
427
428 return sprintf(buff, "%u.%u/%u.%u MBit\n", down / 10,
429 down % 10, up / 10, up % 10);
c6c8fea2
SE
430}
431
0ff9b86f
SE
432static ssize_t batadv_store_gw_bwidth(struct kobject *kobj,
433 struct attribute *attr, char *buff,
434 size_t count)
c6c8fea2 435{
0ff9b86f 436 struct net_device *net_dev = batadv_kobj_to_netdev(kobj);
c6c8fea2
SE
437
438 if (buff[count - 1] == '\n')
439 buff[count - 1] = '\0';
440
84d5e5e0 441 return batadv_gw_bandwidth_set(net_dev, buff, count);
c6c8fea2
SE
442}
443
347c80f0
SE
444BATADV_ATTR_SIF_BOOL(aggregated_ogms, S_IRUGO | S_IWUSR, NULL);
445BATADV_ATTR_SIF_BOOL(bonding, S_IRUGO | S_IWUSR, NULL);
7a5cc242 446#ifdef CONFIG_BATMAN_ADV_BLA
347c80f0 447BATADV_ATTR_SIF_BOOL(bridge_loop_avoidance, S_IRUGO | S_IWUSR, NULL);
7a5cc242 448#endif
33af49ad 449#ifdef CONFIG_BATMAN_ADV_DAT
17cf0ea4
ML
450BATADV_ATTR_SIF_BOOL(distributed_arp_table, S_IRUGO | S_IWUSR,
451 batadv_dat_status_update);
33af49ad 452#endif
347c80f0 453BATADV_ATTR_SIF_BOOL(fragmentation, S_IRUGO | S_IWUSR, batadv_update_min_mtu);
347c80f0
SE
454static BATADV_ATTR(routing_algo, S_IRUGO, batadv_show_bat_algo, NULL);
455static BATADV_ATTR(gw_mode, S_IRUGO | S_IWUSR, batadv_show_gw_mode,
456 batadv_store_gw_mode);
42d0b044
SE
457BATADV_ATTR_SIF_UINT(orig_interval, S_IRUGO | S_IWUSR, 2 * BATADV_JITTER,
458 INT_MAX, NULL);
459BATADV_ATTR_SIF_UINT(hop_penalty, S_IRUGO | S_IWUSR, 0, BATADV_TQ_MAX_VALUE,
347c80f0 460 NULL);
42d0b044 461BATADV_ATTR_SIF_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, BATADV_TQ_MAX_VALUE,
347c80f0
SE
462 batadv_post_gw_deselect);
463static BATADV_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, batadv_show_gw_bwidth,
464 batadv_store_gw_bwidth);
c6c8fea2 465#ifdef CONFIG_BATMAN_ADV_DEBUG
39c75a51 466BATADV_ATTR_SIF_UINT(log_level, S_IRUGO | S_IWUSR, 0, BATADV_DBG_ALL, NULL);
c6c8fea2 467#endif
d353d8d4 468#ifdef CONFIG_BATMAN_ADV_NC
3f4841ff
ML
469BATADV_ATTR_SIF_BOOL(network_coding, S_IRUGO | S_IWUSR,
470 batadv_nc_status_update);
d353d8d4 471#endif
c6c8fea2 472
b4d66b87 473static struct batadv_attribute *batadv_mesh_attrs[] = {
0ff9b86f
SE
474 &batadv_attr_aggregated_ogms,
475 &batadv_attr_bonding,
7a5cc242 476#ifdef CONFIG_BATMAN_ADV_BLA
0ff9b86f 477 &batadv_attr_bridge_loop_avoidance,
33af49ad
AQ
478#endif
479#ifdef CONFIG_BATMAN_ADV_DAT
480 &batadv_attr_distributed_arp_table,
7a5cc242 481#endif
0ff9b86f 482 &batadv_attr_fragmentation,
0ff9b86f
SE
483 &batadv_attr_routing_algo,
484 &batadv_attr_gw_mode,
485 &batadv_attr_orig_interval,
486 &batadv_attr_hop_penalty,
487 &batadv_attr_gw_sel_class,
488 &batadv_attr_gw_bandwidth,
c6c8fea2 489#ifdef CONFIG_BATMAN_ADV_DEBUG
0ff9b86f 490 &batadv_attr_log_level,
d353d8d4
MH
491#endif
492#ifdef CONFIG_BATMAN_ADV_NC
493 &batadv_attr_network_coding,
c6c8fea2
SE
494#endif
495 NULL,
496};
497
b8cbd81d
AQ
498BATADV_ATTR_VLAN_BOOL(ap_isolation, S_IRUGO | S_IWUSR, NULL);
499
90f4435d
AQ
500/**
501 * batadv_vlan_attrs - array of vlan specific sysfs attributes
502 */
503static struct batadv_attribute *batadv_vlan_attrs[] = {
b8cbd81d 504 &batadv_attr_vlan_ap_isolation,
90f4435d
AQ
505 NULL,
506};
507
5853e22c 508int batadv_sysfs_add_meshif(struct net_device *dev)
c6c8fea2
SE
509{
510 struct kobject *batif_kobject = &dev->dev.kobj;
56303d34 511 struct batadv_priv *bat_priv = netdev_priv(dev);
b4d66b87 512 struct batadv_attribute **bat_attr;
c6c8fea2
SE
513 int err;
514
036cbfeb 515 bat_priv->mesh_obj = kobject_create_and_add(BATADV_SYSFS_IF_MESH_SUBDIR,
c6c8fea2
SE
516 batif_kobject);
517 if (!bat_priv->mesh_obj) {
3e34819e 518 batadv_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name,
036cbfeb 519 BATADV_SYSFS_IF_MESH_SUBDIR);
c6c8fea2
SE
520 goto out;
521 }
522
0ff9b86f 523 for (bat_attr = batadv_mesh_attrs; *bat_attr; ++bat_attr) {
c6c8fea2
SE
524 err = sysfs_create_file(bat_priv->mesh_obj,
525 &((*bat_attr)->attr));
526 if (err) {
3e34819e 527 batadv_err(dev, "Can't add sysfs file: %s/%s/%s\n",
036cbfeb 528 dev->name, BATADV_SYSFS_IF_MESH_SUBDIR,
3e34819e 529 ((*bat_attr)->attr).name);
c6c8fea2
SE
530 goto rem_attr;
531 }
532 }
533
534 return 0;
535
536rem_attr:
0ff9b86f 537 for (bat_attr = batadv_mesh_attrs; *bat_attr; ++bat_attr)
c6c8fea2
SE
538 sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr));
539
540 kobject_put(bat_priv->mesh_obj);
541 bat_priv->mesh_obj = NULL;
542out:
543 return -ENOMEM;
544}
545
5853e22c 546void batadv_sysfs_del_meshif(struct net_device *dev)
c6c8fea2 547{
56303d34 548 struct batadv_priv *bat_priv = netdev_priv(dev);
b4d66b87 549 struct batadv_attribute **bat_attr;
c6c8fea2 550
0ff9b86f 551 for (bat_attr = batadv_mesh_attrs; *bat_attr; ++bat_attr)
c6c8fea2
SE
552 sysfs_remove_file(bat_priv->mesh_obj, &((*bat_attr)->attr));
553
554 kobject_put(bat_priv->mesh_obj);
555 bat_priv->mesh_obj = NULL;
556}
557
90f4435d
AQ
558/**
559 * batadv_sysfs_add_vlan - add all the needed sysfs objects for the new vlan
560 * @dev: netdev of the mesh interface
561 * @vlan: private data of the newly added VLAN interface
562 *
563 * Returns 0 on success and -ENOMEM if any of the structure allocations fails.
564 */
565int batadv_sysfs_add_vlan(struct net_device *dev,
566 struct batadv_softif_vlan *vlan)
567{
568 char vlan_subdir[sizeof(BATADV_SYSFS_VLAN_SUBDIR_PREFIX) + 5];
569 struct batadv_priv *bat_priv = netdev_priv(dev);
570 struct batadv_attribute **bat_attr;
571 int err;
572
573 if (vlan->vid & BATADV_VLAN_HAS_TAG) {
574 sprintf(vlan_subdir, BATADV_SYSFS_VLAN_SUBDIR_PREFIX "%hu",
575 vlan->vid & VLAN_VID_MASK);
576
577 vlan->kobj = kobject_create_and_add(vlan_subdir,
578 bat_priv->mesh_obj);
579 if (!vlan->kobj) {
580 batadv_err(dev, "Can't add sysfs directory: %s/%s\n",
581 dev->name, vlan_subdir);
582 goto out;
583 }
584 } else {
585 /* the untagged LAN uses the root folder to store its "VLAN
586 * specific attributes"
587 */
588 vlan->kobj = bat_priv->mesh_obj;
589 kobject_get(bat_priv->mesh_obj);
590 }
591
592 for (bat_attr = batadv_vlan_attrs; *bat_attr; ++bat_attr) {
593 err = sysfs_create_file(vlan->kobj,
594 &((*bat_attr)->attr));
595 if (err) {
596 batadv_err(dev, "Can't add sysfs file: %s/%s/%s\n",
597 dev->name, vlan_subdir,
598 ((*bat_attr)->attr).name);
599 goto rem_attr;
600 }
601 }
602
603 return 0;
604
605rem_attr:
606 for (bat_attr = batadv_vlan_attrs; *bat_attr; ++bat_attr)
607 sysfs_remove_file(vlan->kobj, &((*bat_attr)->attr));
608
609 kobject_put(vlan->kobj);
610 vlan->kobj = NULL;
611out:
612 return -ENOMEM;
613}
614
615/**
616 * batadv_sysfs_del_vlan - remove all the sysfs objects for a given VLAN
617 * @bat_priv: the bat priv with all the soft interface information
618 * @vlan: the private data of the VLAN to destroy
619 */
620void batadv_sysfs_del_vlan(struct batadv_priv *bat_priv,
621 struct batadv_softif_vlan *vlan)
622{
623 struct batadv_attribute **bat_attr;
624
625 for (bat_attr = batadv_vlan_attrs; *bat_attr; ++bat_attr)
626 sysfs_remove_file(vlan->kobj, &((*bat_attr)->attr));
627
628 kobject_put(vlan->kobj);
629 vlan->kobj = NULL;
630}
631
0ff9b86f
SE
632static ssize_t batadv_show_mesh_iface(struct kobject *kobj,
633 struct attribute *attr, char *buff)
c6c8fea2 634{
0ff9b86f 635 struct net_device *net_dev = batadv_kobj_to_netdev(kobj);
56303d34 636 struct batadv_hard_iface *hard_iface;
c6c8fea2 637 ssize_t length;
e9a4f295 638 const char *ifname;
c6c8fea2 639
56303d34 640 hard_iface = batadv_hardif_get_by_netdev(net_dev);
e6c10f43 641 if (!hard_iface)
c6c8fea2
SE
642 return 0;
643
e9a4f295
SE
644 if (hard_iface->if_status == BATADV_IF_NOT_IN_USE)
645 ifname = "none";
646 else
647 ifname = hard_iface->soft_iface->name;
648
649 length = sprintf(buff, "%s\n", ifname);
c6c8fea2 650
e5d89254 651 batadv_hardif_free_ref(hard_iface);
c6c8fea2
SE
652
653 return length;
654}
655
0ff9b86f
SE
656static ssize_t batadv_store_mesh_iface(struct kobject *kobj,
657 struct attribute *attr, char *buff,
658 size_t count)
c6c8fea2 659{
0ff9b86f 660 struct net_device *net_dev = batadv_kobj_to_netdev(kobj);
56303d34 661 struct batadv_hard_iface *hard_iface;
c6c8fea2 662 int status_tmp = -1;
ed75ccbe 663 int ret = count;
c6c8fea2 664
56303d34 665 hard_iface = batadv_hardif_get_by_netdev(net_dev);
e6c10f43 666 if (!hard_iface)
c6c8fea2
SE
667 return count;
668
669 if (buff[count - 1] == '\n')
670 buff[count - 1] = '\0';
671
672 if (strlen(buff) >= IFNAMSIZ) {
86ceb360
SE
673 pr_err("Invalid parameter for 'mesh_iface' setting received: interface name too long '%s'\n",
674 buff);
e5d89254 675 batadv_hardif_free_ref(hard_iface);
c6c8fea2
SE
676 return -EINVAL;
677 }
678
679 if (strncmp(buff, "none", 4) == 0)
e9a4f295 680 status_tmp = BATADV_IF_NOT_IN_USE;
c6c8fea2 681 else
e9a4f295 682 status_tmp = BATADV_IF_I_WANT_YOU;
c6c8fea2 683
e6c10f43
ML
684 if (hard_iface->if_status == status_tmp)
685 goto out;
686
687 if ((hard_iface->soft_iface) &&
688 (strncmp(hard_iface->soft_iface->name, buff, IFNAMSIZ) == 0))
ed75ccbe 689 goto out;
c6c8fea2 690
ac16d148 691 rtnl_lock();
3a4375a9 692
e9a4f295 693 if (status_tmp == BATADV_IF_NOT_IN_USE) {
a15fd361
SE
694 batadv_hardif_disable_interface(hard_iface,
695 BATADV_IF_CLEANUP_AUTO);
3a4375a9 696 goto unlock;
c6c8fea2
SE
697 }
698
699 /* if the interface already is in use */
e9a4f295 700 if (hard_iface->if_status != BATADV_IF_NOT_IN_USE)
a15fd361
SE
701 batadv_hardif_disable_interface(hard_iface,
702 BATADV_IF_CLEANUP_AUTO);
c6c8fea2 703
9563877e 704 ret = batadv_hardif_enable_interface(hard_iface, buff);
c6c8fea2 705
3a4375a9
SE
706unlock:
707 rtnl_unlock();
ed75ccbe 708out:
e5d89254 709 batadv_hardif_free_ref(hard_iface);
c6c8fea2
SE
710 return ret;
711}
712
0ff9b86f
SE
713static ssize_t batadv_show_iface_status(struct kobject *kobj,
714 struct attribute *attr, char *buff)
c6c8fea2 715{
0ff9b86f 716 struct net_device *net_dev = batadv_kobj_to_netdev(kobj);
56303d34 717 struct batadv_hard_iface *hard_iface;
c6c8fea2
SE
718 ssize_t length;
719
56303d34 720 hard_iface = batadv_hardif_get_by_netdev(net_dev);
e6c10f43 721 if (!hard_iface)
c6c8fea2
SE
722 return 0;
723
e6c10f43 724 switch (hard_iface->if_status) {
e9a4f295 725 case BATADV_IF_TO_BE_REMOVED:
c6c8fea2
SE
726 length = sprintf(buff, "disabling\n");
727 break;
e9a4f295 728 case BATADV_IF_INACTIVE:
c6c8fea2
SE
729 length = sprintf(buff, "inactive\n");
730 break;
e9a4f295 731 case BATADV_IF_ACTIVE:
c6c8fea2
SE
732 length = sprintf(buff, "active\n");
733 break;
e9a4f295 734 case BATADV_IF_TO_BE_ACTIVATED:
c6c8fea2
SE
735 length = sprintf(buff, "enabling\n");
736 break;
e9a4f295 737 case BATADV_IF_NOT_IN_USE:
c6c8fea2
SE
738 default:
739 length = sprintf(buff, "not in use\n");
740 break;
741 }
742
e5d89254 743 batadv_hardif_free_ref(hard_iface);
c6c8fea2
SE
744
745 return length;
746}
747
347c80f0
SE
748static BATADV_ATTR(mesh_iface, S_IRUGO | S_IWUSR, batadv_show_mesh_iface,
749 batadv_store_mesh_iface);
750static BATADV_ATTR(iface_status, S_IRUGO, batadv_show_iface_status, NULL);
c6c8fea2 751
b4d66b87 752static struct batadv_attribute *batadv_batman_attrs[] = {
0ff9b86f
SE
753 &batadv_attr_mesh_iface,
754 &batadv_attr_iface_status,
c6c8fea2
SE
755 NULL,
756};
757
5853e22c 758int batadv_sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev)
c6c8fea2
SE
759{
760 struct kobject *hardif_kobject = &dev->dev.kobj;
b4d66b87 761 struct batadv_attribute **bat_attr;
c6c8fea2
SE
762 int err;
763
036cbfeb
SE
764 *hardif_obj = kobject_create_and_add(BATADV_SYSFS_IF_BAT_SUBDIR,
765 hardif_kobject);
c6c8fea2
SE
766
767 if (!*hardif_obj) {
3e34819e 768 batadv_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name,
036cbfeb 769 BATADV_SYSFS_IF_BAT_SUBDIR);
c6c8fea2
SE
770 goto out;
771 }
772
0ff9b86f 773 for (bat_attr = batadv_batman_attrs; *bat_attr; ++bat_attr) {
c6c8fea2
SE
774 err = sysfs_create_file(*hardif_obj, &((*bat_attr)->attr));
775 if (err) {
3e34819e 776 batadv_err(dev, "Can't add sysfs file: %s/%s/%s\n",
036cbfeb 777 dev->name, BATADV_SYSFS_IF_BAT_SUBDIR,
3e34819e 778 ((*bat_attr)->attr).name);
c6c8fea2
SE
779 goto rem_attr;
780 }
781 }
782
783 return 0;
784
785rem_attr:
0ff9b86f 786 for (bat_attr = batadv_batman_attrs; *bat_attr; ++bat_attr)
c6c8fea2
SE
787 sysfs_remove_file(*hardif_obj, &((*bat_attr)->attr));
788out:
789 return -ENOMEM;
790}
791
5853e22c 792void batadv_sysfs_del_hardif(struct kobject **hardif_obj)
c6c8fea2
SE
793{
794 kobject_put(*hardif_obj);
795 *hardif_obj = NULL;
796}
c6bda689 797
56303d34 798int batadv_throw_uevent(struct batadv_priv *bat_priv, enum batadv_uev_type type,
39c75a51 799 enum batadv_uev_action action, const char *data)
c6bda689 800{
5346c35e 801 int ret = -ENOMEM;
c6bda689
AQ
802 struct kobject *bat_kobj;
803 char *uevent_env[4] = { NULL, NULL, NULL, NULL };
804
736292c2 805 bat_kobj = &bat_priv->soft_iface->dev.kobj;
c6bda689 806
347c80f0 807 uevent_env[0] = kmalloc(strlen(BATADV_UEV_TYPE_VAR) +
0ff9b86f 808 strlen(batadv_uev_type_str[type]) + 1,
c6bda689
AQ
809 GFP_ATOMIC);
810 if (!uevent_env[0])
811 goto out;
812
347c80f0
SE
813 sprintf(uevent_env[0], "%s%s", BATADV_UEV_TYPE_VAR,
814 batadv_uev_type_str[type]);
c6bda689 815
347c80f0 816 uevent_env[1] = kmalloc(strlen(BATADV_UEV_ACTION_VAR) +
0ff9b86f 817 strlen(batadv_uev_action_str[action]) + 1,
c6bda689
AQ
818 GFP_ATOMIC);
819 if (!uevent_env[1])
820 goto out;
821
347c80f0 822 sprintf(uevent_env[1], "%s%s", BATADV_UEV_ACTION_VAR,
0ff9b86f 823 batadv_uev_action_str[action]);
c6bda689
AQ
824
825 /* If the event is DEL, ignore the data field */
39c75a51 826 if (action != BATADV_UEV_DEL) {
347c80f0 827 uevent_env[2] = kmalloc(strlen(BATADV_UEV_DATA_VAR) +
c6bda689
AQ
828 strlen(data) + 1, GFP_ATOMIC);
829 if (!uevent_env[2])
830 goto out;
831
347c80f0 832 sprintf(uevent_env[2], "%s%s", BATADV_UEV_DATA_VAR, data);
c6bda689
AQ
833 }
834
835 ret = kobject_uevent_env(bat_kobj, KOBJ_CHANGE, uevent_env);
836out:
837 kfree(uevent_env[0]);
838 kfree(uevent_env[1]);
839 kfree(uevent_env[2]);
840
c6bda689 841 if (ret)
39c75a51 842 batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
1eda58bf 843 "Impossible to send uevent for (%s,%s,%s) event (err: %d)\n",
0ff9b86f
SE
844 batadv_uev_type_str[type],
845 batadv_uev_action_str[action],
39c75a51 846 (action == BATADV_UEV_DEL ? "NULL" : data), ret);
c6bda689
AQ
847 return ret;
848}