aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/batman-adv/soft-interface.c15
-rw-r--r--net/batman-adv/soft-interface.h3
-rw-r--r--net/batman-adv/sysfs.c173
-rw-r--r--net/batman-adv/sysfs.h10
4 files changed, 198 insertions, 3 deletions
diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index 936b83bb02de..f74200c7e553 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -398,7 +398,7 @@ out:
398 * possibly free it 398 * possibly free it
399 * @softif_vlan: the vlan object to release 399 * @softif_vlan: the vlan object to release
400 */ 400 */
401static void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *softif_vlan) 401void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *softif_vlan)
402{ 402{
403 if (atomic_dec_and_test(&softif_vlan->refcount)) 403 if (atomic_dec_and_test(&softif_vlan->refcount))
404 kfree_rcu(softif_vlan, rcu); 404 kfree_rcu(softif_vlan, rcu);
@@ -412,8 +412,8 @@ static void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *softif_vlan)
412 * Returns the private data of the vlan matching the vid passed as argument or 412 * Returns the private data of the vlan matching the vid passed as argument or
413 * NULL otherwise. The refcounter of the returned object is incremented by 1. 413 * NULL otherwise. The refcounter of the returned object is incremented by 1.
414 */ 414 */
415static struct batadv_softif_vlan * 415struct batadv_softif_vlan *batadv_softif_vlan_get(struct batadv_priv *bat_priv,
416batadv_softif_vlan_get(struct batadv_priv *bat_priv, unsigned short vid) 416 unsigned short vid)
417{ 417{
418 struct batadv_softif_vlan *vlan_tmp, *vlan = NULL; 418 struct batadv_softif_vlan *vlan_tmp, *vlan = NULL;
419 419
@@ -443,6 +443,7 @@ batadv_softif_vlan_get(struct batadv_priv *bat_priv, unsigned short vid)
443int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid) 443int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
444{ 444{
445 struct batadv_softif_vlan *vlan; 445 struct batadv_softif_vlan *vlan;
446 int err;
446 447
447 vlan = batadv_softif_vlan_get(bat_priv, vid); 448 vlan = batadv_softif_vlan_get(bat_priv, vid);
448 if (vlan) { 449 if (vlan) {
@@ -457,6 +458,12 @@ int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
457 vlan->vid = vid; 458 vlan->vid = vid;
458 atomic_set(&vlan->refcount, 1); 459 atomic_set(&vlan->refcount, 1);
459 460
461 err = batadv_sysfs_add_vlan(bat_priv->soft_iface, vlan);
462 if (err) {
463 kfree(vlan);
464 return err;
465 }
466
460 /* add a new TT local entry. This one will be marked with the NOPURGE 467 /* add a new TT local entry. This one will be marked with the NOPURGE
461 * flag 468 * flag
462 */ 469 */
@@ -483,6 +490,8 @@ static void batadv_softif_destroy_vlan(struct batadv_priv *bat_priv,
483 hlist_del_rcu(&vlan->list); 490 hlist_del_rcu(&vlan->list);
484 spin_unlock_bh(&bat_priv->softif_vlan_list_lock); 491 spin_unlock_bh(&bat_priv->softif_vlan_list_lock);
485 492
493 batadv_sysfs_del_vlan(bat_priv, vlan);
494
486 /* explicitly remove the associated TT local entry because it is marked 495 /* explicitly remove the associated TT local entry because it is marked
487 * with the NOPURGE flag 496 * with the NOPURGE flag
488 */ 497 */
diff --git a/net/batman-adv/soft-interface.h b/net/batman-adv/soft-interface.h
index 16d9be6df647..06fc91ff5a02 100644
--- a/net/batman-adv/soft-interface.h
+++ b/net/batman-adv/soft-interface.h
@@ -29,5 +29,8 @@ void batadv_softif_destroy_sysfs(struct net_device *soft_iface);
29int batadv_softif_is_valid(const struct net_device *net_dev); 29int batadv_softif_is_valid(const struct net_device *net_dev);
30extern struct rtnl_link_ops batadv_link_ops; 30extern struct rtnl_link_ops batadv_link_ops;
31int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid); 31int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid);
32void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *softif_vlan);
33struct batadv_softif_vlan *batadv_softif_vlan_get(struct batadv_priv *bat_priv,
34 unsigned short vid);
32 35
33#endif /* _NET_BATMAN_ADV_SOFT_INTERFACE_H_ */ 36#endif /* _NET_BATMAN_ADV_SOFT_INTERFACE_H_ */
diff --git a/net/batman-adv/sysfs.c b/net/batman-adv/sysfs.c
index 869eb46329cb..f419d218890d 100644
--- a/net/batman-adv/sysfs.c
+++ b/net/batman-adv/sysfs.c
@@ -24,6 +24,7 @@
24#include "network-coding.h" 24#include "network-coding.h"
25#include "originator.h" 25#include "originator.h"
26#include "hard-interface.h" 26#include "hard-interface.h"
27#include "soft-interface.h"
27#include "gateway_common.h" 28#include "gateway_common.h"
28#include "gateway_client.h" 29#include "gateway_client.h"
29 30
@@ -39,6 +40,53 @@ static struct batadv_priv *batadv_kobj_to_batpriv(struct kobject *obj)
39 return netdev_priv(net_dev); 40 return netdev_priv(net_dev);
40} 41}
41 42
43/**
44 * batadv_vlan_kobj_to_batpriv - convert a vlan kobj in the associated batpriv
45 * @obj: kobject to covert
46 *
47 * Returns the associated batadv_priv struct.
48 */
49static struct batadv_priv *batadv_vlan_kobj_to_batpriv(struct kobject *obj)
50{
51 /* VLAN specific attributes are located in the root sysfs folder if they
52 * refer to the untagged VLAN..
53 */
54 if (!strcmp(BATADV_SYSFS_IF_MESH_SUBDIR, obj->name))
55 return batadv_kobj_to_batpriv(obj);
56
57 /* ..while the attributes for the tagged vlans are located in
58 * the in the corresponding "vlan%VID" subfolder
59 */
60 return batadv_kobj_to_batpriv(obj->parent);
61}
62
63/**
64 * batadv_kobj_to_vlan - convert a kobj in the associated softif_vlan struct
65 * @obj: kobject to covert
66 *
67 * Returns the associated softif_vlan struct if found, NULL otherwise.
68 */
69static struct batadv_softif_vlan *
70batadv_kobj_to_vlan(struct batadv_priv *bat_priv, struct kobject *obj)
71{
72 struct batadv_softif_vlan *vlan_tmp, *vlan = NULL;
73
74 rcu_read_lock();
75 hlist_for_each_entry_rcu(vlan_tmp, &bat_priv->softif_vlan_list, list) {
76 if (vlan_tmp->kobj != obj)
77 continue;
78
79 if (!atomic_inc_not_zero(&vlan_tmp->refcount))
80 continue;
81
82 vlan = vlan_tmp;
83 break;
84 }
85 rcu_read_unlock();
86
87 return vlan;
88}
89
42#define BATADV_UEV_TYPE_VAR "BATTYPE=" 90#define BATADV_UEV_TYPE_VAR "BATTYPE="
43#define BATADV_UEV_ACTION_VAR "BATACTION=" 91#define BATADV_UEV_ACTION_VAR "BATACTION="
44#define BATADV_UEV_DATA_VAR "BATDATA=" 92#define BATADV_UEV_DATA_VAR "BATDATA="
@@ -53,6 +101,15 @@ static char *batadv_uev_type_str[] = {
53 "gw" 101 "gw"
54}; 102};
55 103
104/* Use this, if you have customized show and store functions for vlan attrs */
105#define BATADV_ATTR_VLAN(_name, _mode, _show, _store) \
106struct batadv_attribute batadv_attr_vlan_##_name = { \
107 .attr = {.name = __stringify(_name), \
108 .mode = _mode }, \
109 .show = _show, \
110 .store = _store, \
111};
112
56/* Use this, if you have customized show and store functions */ 113/* Use this, if you have customized show and store functions */
57#define BATADV_ATTR(_name, _mode, _show, _store) \ 114#define BATADV_ATTR(_name, _mode, _show, _store) \
58struct batadv_attribute batadv_attr_##_name = { \ 115struct batadv_attribute batadv_attr_##_name = { \
@@ -122,6 +179,41 @@ ssize_t batadv_show_##_name(struct kobject *kobj, \
122 static BATADV_ATTR(_name, _mode, batadv_show_##_name, \ 179 static BATADV_ATTR(_name, _mode, batadv_show_##_name, \
123 batadv_store_##_name) 180 batadv_store_##_name)
124 181
182#define BATADV_ATTR_VLAN_STORE_BOOL(_name, _post_func) \
183ssize_t batadv_store_vlan_##_name(struct kobject *kobj, \
184 struct attribute *attr, char *buff, \
185 size_t count) \
186{ \
187 struct batadv_priv *bat_priv = batadv_vlan_kobj_to_batpriv(kobj);\
188 struct batadv_softif_vlan *vlan = batadv_kobj_to_vlan(bat_priv, \
189 kobj); \
190 size_t res = __batadv_store_bool_attr(buff, count, _post_func, \
191 attr, &vlan->_name, \
192 bat_priv->soft_iface); \
193 batadv_softif_vlan_free_ref(vlan); \
194 return res; \
195}
196
197#define BATADV_ATTR_VLAN_SHOW_BOOL(_name) \
198ssize_t batadv_show_vlan_##_name(struct kobject *kobj, \
199 struct attribute *attr, char *buff) \
200{ \
201 struct batadv_priv *bat_priv = batadv_vlan_kobj_to_batpriv(kobj);\
202 struct batadv_softif_vlan *vlan = batadv_kobj_to_vlan(bat_priv, \
203 kobj); \
204 size_t res = sprintf(buff, "%s\n", \
205 atomic_read(&vlan->_name) == 0 ? \
206 "disabled" : "enabled"); \
207 batadv_softif_vlan_free_ref(vlan); \
208 return res; \
209}
210
211/* Use this, if you are going to turn a [name] in the vlan struct on or off */
212#define BATADV_ATTR_VLAN_BOOL(_name, _mode, _post_func) \
213 static BATADV_ATTR_VLAN_STORE_BOOL(_name, _post_func) \
214 static BATADV_ATTR_VLAN_SHOW_BOOL(_name) \
215 static BATADV_ATTR_VLAN(_name, _mode, batadv_show_vlan_##_name, \
216 batadv_store_vlan_##_name)
125 217
126static int batadv_store_bool_attr(char *buff, size_t count, 218static int batadv_store_bool_attr(char *buff, size_t count,
127 struct net_device *net_dev, 219 struct net_device *net_dev,
@@ -407,6 +499,13 @@ static struct batadv_attribute *batadv_mesh_attrs[] = {
407 NULL, 499 NULL,
408}; 500};
409 501
502/**
503 * batadv_vlan_attrs - array of vlan specific sysfs attributes
504 */
505static struct batadv_attribute *batadv_vlan_attrs[] = {
506 NULL,
507};
508
410int batadv_sysfs_add_meshif(struct net_device *dev) 509int batadv_sysfs_add_meshif(struct net_device *dev)
411{ 510{
412 struct kobject *batif_kobject = &dev->dev.kobj; 511 struct kobject *batif_kobject = &dev->dev.kobj;
@@ -457,6 +556,80 @@ void batadv_sysfs_del_meshif(struct net_device *dev)
457 bat_priv->mesh_obj = NULL; 556 bat_priv->mesh_obj = NULL;
458} 557}
459 558
559/**
560 * batadv_sysfs_add_vlan - add all the needed sysfs objects for the new vlan
561 * @dev: netdev of the mesh interface
562 * @vlan: private data of the newly added VLAN interface
563 *
564 * Returns 0 on success and -ENOMEM if any of the structure allocations fails.
565 */
566int batadv_sysfs_add_vlan(struct net_device *dev,
567 struct batadv_softif_vlan *vlan)
568{
569 char vlan_subdir[sizeof(BATADV_SYSFS_VLAN_SUBDIR_PREFIX) + 5];
570 struct batadv_priv *bat_priv = netdev_priv(dev);
571 struct batadv_attribute **bat_attr;
572 int err;
573
574 if (vlan->vid & BATADV_VLAN_HAS_TAG) {
575 sprintf(vlan_subdir, BATADV_SYSFS_VLAN_SUBDIR_PREFIX "%hu",
576 vlan->vid & VLAN_VID_MASK);
577
578 vlan->kobj = kobject_create_and_add(vlan_subdir,
579 bat_priv->mesh_obj);
580 if (!vlan->kobj) {
581 batadv_err(dev, "Can't add sysfs directory: %s/%s\n",
582 dev->name, vlan_subdir);
583 goto out;
584 }
585 } else {
586 /* the untagged LAN uses the root folder to store its "VLAN
587 * specific attributes"
588 */
589 vlan->kobj = bat_priv->mesh_obj;
590 kobject_get(bat_priv->mesh_obj);
591 }
592
593 for (bat_attr = batadv_vlan_attrs; *bat_attr; ++bat_attr) {
594 err = sysfs_create_file(vlan->kobj,
595 &((*bat_attr)->attr));
596 if (err) {
597 batadv_err(dev, "Can't add sysfs file: %s/%s/%s\n",
598 dev->name, vlan_subdir,
599 ((*bat_attr)->attr).name);
600 goto rem_attr;
601 }
602 }
603
604 return 0;
605
606rem_attr:
607 for (bat_attr = batadv_vlan_attrs; *bat_attr; ++bat_attr)
608 sysfs_remove_file(vlan->kobj, &((*bat_attr)->attr));
609
610 kobject_put(vlan->kobj);
611 vlan->kobj = NULL;
612out:
613 return -ENOMEM;
614}
615
616/**
617 * batadv_sysfs_del_vlan - remove all the sysfs objects for a given VLAN
618 * @bat_priv: the bat priv with all the soft interface information
619 * @vlan: the private data of the VLAN to destroy
620 */
621void batadv_sysfs_del_vlan(struct batadv_priv *bat_priv,
622 struct batadv_softif_vlan *vlan)
623{
624 struct batadv_attribute **bat_attr;
625
626 for (bat_attr = batadv_vlan_attrs; *bat_attr; ++bat_attr)
627 sysfs_remove_file(vlan->kobj, &((*bat_attr)->attr));
628
629 kobject_put(vlan->kobj);
630 vlan->kobj = NULL;
631}
632
460static ssize_t batadv_show_mesh_iface(struct kobject *kobj, 633static ssize_t batadv_show_mesh_iface(struct kobject *kobj,
461 struct attribute *attr, char *buff) 634 struct attribute *attr, char *buff)
462{ 635{
diff --git a/net/batman-adv/sysfs.h b/net/batman-adv/sysfs.h
index 479acf4c16f4..c7d725de50ad 100644
--- a/net/batman-adv/sysfs.h
+++ b/net/batman-adv/sysfs.h
@@ -22,6 +22,12 @@
22 22
23#define BATADV_SYSFS_IF_MESH_SUBDIR "mesh" 23#define BATADV_SYSFS_IF_MESH_SUBDIR "mesh"
24#define BATADV_SYSFS_IF_BAT_SUBDIR "batman_adv" 24#define BATADV_SYSFS_IF_BAT_SUBDIR "batman_adv"
25/**
26 * BATADV_SYSFS_VLAN_SUBDIR_PREFIX - prefix of the subfolder that will be
27 * created in the sysfs hierarchy for each VLAN interface. The subfolder will
28 * be named "BATADV_SYSFS_VLAN_SUBDIR_PREFIX%vid".
29 */
30#define BATADV_SYSFS_VLAN_SUBDIR_PREFIX "vlan"
25 31
26struct batadv_attribute { 32struct batadv_attribute {
27 struct attribute attr; 33 struct attribute attr;
@@ -36,6 +42,10 @@ void batadv_sysfs_del_meshif(struct net_device *dev);
36int batadv_sysfs_add_hardif(struct kobject **hardif_obj, 42int batadv_sysfs_add_hardif(struct kobject **hardif_obj,
37 struct net_device *dev); 43 struct net_device *dev);
38void batadv_sysfs_del_hardif(struct kobject **hardif_obj); 44void batadv_sysfs_del_hardif(struct kobject **hardif_obj);
45int batadv_sysfs_add_vlan(struct net_device *dev,
46 struct batadv_softif_vlan *vlan);
47void batadv_sysfs_del_vlan(struct batadv_priv *bat_priv,
48 struct batadv_softif_vlan *vlan);
39int batadv_throw_uevent(struct batadv_priv *bat_priv, enum batadv_uev_type type, 49int batadv_throw_uevent(struct batadv_priv *bat_priv, enum batadv_uev_type type,
40 enum batadv_uev_action action, const char *data); 50 enum batadv_uev_action action, const char *data);
41 51