diff options
-rw-r--r-- | net/batman-adv/soft-interface.c | 15 | ||||
-rw-r--r-- | net/batman-adv/soft-interface.h | 3 | ||||
-rw-r--r-- | net/batman-adv/sysfs.c | 173 | ||||
-rw-r--r-- | net/batman-adv/sysfs.h | 10 |
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 | */ |
401 | static void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *softif_vlan) | 401 | void 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 | */ |
415 | static struct batadv_softif_vlan * | 415 | struct batadv_softif_vlan *batadv_softif_vlan_get(struct batadv_priv *bat_priv, |
416 | batadv_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) | |||
443 | int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid) | 443 | int 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); | |||
29 | int batadv_softif_is_valid(const struct net_device *net_dev); | 29 | int batadv_softif_is_valid(const struct net_device *net_dev); |
30 | extern struct rtnl_link_ops batadv_link_ops; | 30 | extern struct rtnl_link_ops batadv_link_ops; |
31 | int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid); | 31 | int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid); |
32 | void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *softif_vlan); | ||
33 | struct 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 | */ | ||
49 | static 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 | */ | ||
69 | static struct batadv_softif_vlan * | ||
70 | batadv_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) \ | ||
106 | struct 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) \ |
58 | struct batadv_attribute batadv_attr_##_name = { \ | 115 | struct 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) \ | ||
183 | ssize_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) \ | ||
198 | ssize_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 | ||
126 | static int batadv_store_bool_attr(char *buff, size_t count, | 218 | static 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 | */ | ||
505 | static struct batadv_attribute *batadv_vlan_attrs[] = { | ||
506 | NULL, | ||
507 | }; | ||
508 | |||
410 | int batadv_sysfs_add_meshif(struct net_device *dev) | 509 | int 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 | */ | ||
566 | int 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 | |||
606 | rem_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; | ||
612 | out: | ||
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 | */ | ||
621 | void 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 | |||
460 | static ssize_t batadv_show_mesh_iface(struct kobject *kobj, | 633 | static 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 | ||
26 | struct batadv_attribute { | 32 | struct batadv_attribute { |
27 | struct attribute attr; | 33 | struct attribute attr; |
@@ -36,6 +42,10 @@ void batadv_sysfs_del_meshif(struct net_device *dev); | |||
36 | int batadv_sysfs_add_hardif(struct kobject **hardif_obj, | 42 | int batadv_sysfs_add_hardif(struct kobject **hardif_obj, |
37 | struct net_device *dev); | 43 | struct net_device *dev); |
38 | void batadv_sysfs_del_hardif(struct kobject **hardif_obj); | 44 | void batadv_sysfs_del_hardif(struct kobject **hardif_obj); |
45 | int batadv_sysfs_add_vlan(struct net_device *dev, | ||
46 | struct batadv_softif_vlan *vlan); | ||
47 | void batadv_sysfs_del_vlan(struct batadv_priv *bat_priv, | ||
48 | struct batadv_softif_vlan *vlan); | ||
39 | int batadv_throw_uevent(struct batadv_priv *bat_priv, enum batadv_uev_type type, | 49 | int 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 | ||