|
@@ -24,6 +24,7 @@
|
|
|
#include "network-coding.h"
|
|
|
#include "originator.h"
|
|
|
#include "hard-interface.h"
|
|
|
+#include "soft-interface.h"
|
|
|
#include "gateway_common.h"
|
|
|
#include "gateway_client.h"
|
|
|
|
|
@@ -39,6 +40,53 @@ static struct batadv_priv *batadv_kobj_to_batpriv(struct kobject *obj)
|
|
|
return netdev_priv(net_dev);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * batadv_vlan_kobj_to_batpriv - convert a vlan kobj in the associated batpriv
|
|
|
+ * @obj: kobject to covert
|
|
|
+ *
|
|
|
+ * Returns the associated batadv_priv struct.
|
|
|
+ */
|
|
|
+static struct batadv_priv *batadv_vlan_kobj_to_batpriv(struct kobject *obj)
|
|
|
+{
|
|
|
+ /* VLAN specific attributes are located in the root sysfs folder if they
|
|
|
+ * refer to the untagged VLAN..
|
|
|
+ */
|
|
|
+ if (!strcmp(BATADV_SYSFS_IF_MESH_SUBDIR, obj->name))
|
|
|
+ return batadv_kobj_to_batpriv(obj);
|
|
|
+
|
|
|
+ /* ..while the attributes for the tagged vlans are located in
|
|
|
+ * the in the corresponding "vlan%VID" subfolder
|
|
|
+ */
|
|
|
+ return batadv_kobj_to_batpriv(obj->parent);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * batadv_kobj_to_vlan - convert a kobj in the associated softif_vlan struct
|
|
|
+ * @obj: kobject to covert
|
|
|
+ *
|
|
|
+ * Returns the associated softif_vlan struct if found, NULL otherwise.
|
|
|
+ */
|
|
|
+static struct batadv_softif_vlan *
|
|
|
+batadv_kobj_to_vlan(struct batadv_priv *bat_priv, struct kobject *obj)
|
|
|
+{
|
|
|
+ struct batadv_softif_vlan *vlan_tmp, *vlan = NULL;
|
|
|
+
|
|
|
+ rcu_read_lock();
|
|
|
+ hlist_for_each_entry_rcu(vlan_tmp, &bat_priv->softif_vlan_list, list) {
|
|
|
+ if (vlan_tmp->kobj != obj)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (!atomic_inc_not_zero(&vlan_tmp->refcount))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ vlan = vlan_tmp;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ rcu_read_unlock();
|
|
|
+
|
|
|
+ return vlan;
|
|
|
+}
|
|
|
+
|
|
|
#define BATADV_UEV_TYPE_VAR "BATTYPE="
|
|
|
#define BATADV_UEV_ACTION_VAR "BATACTION="
|
|
|
#define BATADV_UEV_DATA_VAR "BATDATA="
|
|
@@ -53,6 +101,15 @@ static char *batadv_uev_type_str[] = {
|
|
|
"gw"
|
|
|
};
|
|
|
|
|
|
+/* Use this, if you have customized show and store functions for vlan attrs */
|
|
|
+#define BATADV_ATTR_VLAN(_name, _mode, _show, _store) \
|
|
|
+struct batadv_attribute batadv_attr_vlan_##_name = { \
|
|
|
+ .attr = {.name = __stringify(_name), \
|
|
|
+ .mode = _mode }, \
|
|
|
+ .show = _show, \
|
|
|
+ .store = _store, \
|
|
|
+};
|
|
|
+
|
|
|
/* Use this, if you have customized show and store functions */
|
|
|
#define BATADV_ATTR(_name, _mode, _show, _store) \
|
|
|
struct batadv_attribute batadv_attr_##_name = { \
|
|
@@ -122,6 +179,41 @@ ssize_t batadv_show_##_name(struct kobject *kobj, \
|
|
|
static BATADV_ATTR(_name, _mode, batadv_show_##_name, \
|
|
|
batadv_store_##_name)
|
|
|
|
|
|
+#define BATADV_ATTR_VLAN_STORE_BOOL(_name, _post_func) \
|
|
|
+ssize_t batadv_store_vlan_##_name(struct kobject *kobj, \
|
|
|
+ struct attribute *attr, char *buff, \
|
|
|
+ size_t count) \
|
|
|
+{ \
|
|
|
+ struct batadv_priv *bat_priv = batadv_vlan_kobj_to_batpriv(kobj);\
|
|
|
+ struct batadv_softif_vlan *vlan = batadv_kobj_to_vlan(bat_priv, \
|
|
|
+ kobj); \
|
|
|
+ size_t res = __batadv_store_bool_attr(buff, count, _post_func, \
|
|
|
+ attr, &vlan->_name, \
|
|
|
+ bat_priv->soft_iface); \
|
|
|
+ batadv_softif_vlan_free_ref(vlan); \
|
|
|
+ return res; \
|
|
|
+}
|
|
|
+
|
|
|
+#define BATADV_ATTR_VLAN_SHOW_BOOL(_name) \
|
|
|
+ssize_t batadv_show_vlan_##_name(struct kobject *kobj, \
|
|
|
+ struct attribute *attr, char *buff) \
|
|
|
+{ \
|
|
|
+ struct batadv_priv *bat_priv = batadv_vlan_kobj_to_batpriv(kobj);\
|
|
|
+ struct batadv_softif_vlan *vlan = batadv_kobj_to_vlan(bat_priv, \
|
|
|
+ kobj); \
|
|
|
+ size_t res = sprintf(buff, "%s\n", \
|
|
|
+ atomic_read(&vlan->_name) == 0 ? \
|
|
|
+ "disabled" : "enabled"); \
|
|
|
+ batadv_softif_vlan_free_ref(vlan); \
|
|
|
+ return res; \
|
|
|
+}
|
|
|
+
|
|
|
+/* Use this, if you are going to turn a [name] in the vlan struct on or off */
|
|
|
+#define BATADV_ATTR_VLAN_BOOL(_name, _mode, _post_func) \
|
|
|
+ static BATADV_ATTR_VLAN_STORE_BOOL(_name, _post_func) \
|
|
|
+ static BATADV_ATTR_VLAN_SHOW_BOOL(_name) \
|
|
|
+ static BATADV_ATTR_VLAN(_name, _mode, batadv_show_vlan_##_name, \
|
|
|
+ batadv_store_vlan_##_name)
|
|
|
|
|
|
static int batadv_store_bool_attr(char *buff, size_t count,
|
|
|
struct net_device *net_dev,
|
|
@@ -407,6 +499,13 @@ static struct batadv_attribute *batadv_mesh_attrs[] = {
|
|
|
NULL,
|
|
|
};
|
|
|
|
|
|
+/**
|
|
|
+ * batadv_vlan_attrs - array of vlan specific sysfs attributes
|
|
|
+ */
|
|
|
+static struct batadv_attribute *batadv_vlan_attrs[] = {
|
|
|
+ NULL,
|
|
|
+};
|
|
|
+
|
|
|
int batadv_sysfs_add_meshif(struct net_device *dev)
|
|
|
{
|
|
|
struct kobject *batif_kobject = &dev->dev.kobj;
|
|
@@ -457,6 +556,80 @@ void batadv_sysfs_del_meshif(struct net_device *dev)
|
|
|
bat_priv->mesh_obj = NULL;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * batadv_sysfs_add_vlan - add all the needed sysfs objects for the new vlan
|
|
|
+ * @dev: netdev of the mesh interface
|
|
|
+ * @vlan: private data of the newly added VLAN interface
|
|
|
+ *
|
|
|
+ * Returns 0 on success and -ENOMEM if any of the structure allocations fails.
|
|
|
+ */
|
|
|
+int batadv_sysfs_add_vlan(struct net_device *dev,
|
|
|
+ struct batadv_softif_vlan *vlan)
|
|
|
+{
|
|
|
+ char vlan_subdir[sizeof(BATADV_SYSFS_VLAN_SUBDIR_PREFIX) + 5];
|
|
|
+ struct batadv_priv *bat_priv = netdev_priv(dev);
|
|
|
+ struct batadv_attribute **bat_attr;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ if (vlan->vid & BATADV_VLAN_HAS_TAG) {
|
|
|
+ sprintf(vlan_subdir, BATADV_SYSFS_VLAN_SUBDIR_PREFIX "%hu",
|
|
|
+ vlan->vid & VLAN_VID_MASK);
|
|
|
+
|
|
|
+ vlan->kobj = kobject_create_and_add(vlan_subdir,
|
|
|
+ bat_priv->mesh_obj);
|
|
|
+ if (!vlan->kobj) {
|
|
|
+ batadv_err(dev, "Can't add sysfs directory: %s/%s\n",
|
|
|
+ dev->name, vlan_subdir);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ /* the untagged LAN uses the root folder to store its "VLAN
|
|
|
+ * specific attributes"
|
|
|
+ */
|
|
|
+ vlan->kobj = bat_priv->mesh_obj;
|
|
|
+ kobject_get(bat_priv->mesh_obj);
|
|
|
+ }
|
|
|
+
|
|
|
+ for (bat_attr = batadv_vlan_attrs; *bat_attr; ++bat_attr) {
|
|
|
+ err = sysfs_create_file(vlan->kobj,
|
|
|
+ &((*bat_attr)->attr));
|
|
|
+ if (err) {
|
|
|
+ batadv_err(dev, "Can't add sysfs file: %s/%s/%s\n",
|
|
|
+ dev->name, vlan_subdir,
|
|
|
+ ((*bat_attr)->attr).name);
|
|
|
+ goto rem_attr;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+rem_attr:
|
|
|
+ for (bat_attr = batadv_vlan_attrs; *bat_attr; ++bat_attr)
|
|
|
+ sysfs_remove_file(vlan->kobj, &((*bat_attr)->attr));
|
|
|
+
|
|
|
+ kobject_put(vlan->kobj);
|
|
|
+ vlan->kobj = NULL;
|
|
|
+out:
|
|
|
+ return -ENOMEM;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * batadv_sysfs_del_vlan - remove all the sysfs objects for a given VLAN
|
|
|
+ * @bat_priv: the bat priv with all the soft interface information
|
|
|
+ * @vlan: the private data of the VLAN to destroy
|
|
|
+ */
|
|
|
+void batadv_sysfs_del_vlan(struct batadv_priv *bat_priv,
|
|
|
+ struct batadv_softif_vlan *vlan)
|
|
|
+{
|
|
|
+ struct batadv_attribute **bat_attr;
|
|
|
+
|
|
|
+ for (bat_attr = batadv_vlan_attrs; *bat_attr; ++bat_attr)
|
|
|
+ sysfs_remove_file(vlan->kobj, &((*bat_attr)->attr));
|
|
|
+
|
|
|
+ kobject_put(vlan->kobj);
|
|
|
+ vlan->kobj = NULL;
|
|
|
+}
|
|
|
+
|
|
|
static ssize_t batadv_show_mesh_iface(struct kobject *kobj,
|
|
|
struct attribute *attr, char *buff)
|
|
|
{
|