diff options
Diffstat (limited to 'net/batman-adv/sysfs.c')
| -rw-r--r-- | net/batman-adv/sysfs.c | 384 | 
1 files changed, 291 insertions, 93 deletions
diff --git a/net/batman-adv/sysfs.c b/net/batman-adv/sysfs.c index 4114b961bc2..fc47baa888c 100644 --- a/net/batman-adv/sysfs.c +++ b/net/batman-adv/sysfs.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2010-2013 B.A.T.M.A.N. contributors: +/* Copyright (C) 2010-2014 B.A.T.M.A.N. contributors:   *   * Marek Lindner   * @@ -12,33 +12,81 @@   * General Public License for more details.   *   * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA + * along with this program; if not, see <http://www.gnu.org/licenses/>.   */  #include "main.h"  #include "sysfs.h"  #include "translation-table.h"  #include "distributed-arp-table.h" +#include "network-coding.h"  #include "originator.h"  #include "hard-interface.h" +#include "soft-interface.h"  #include "gateway_common.h"  #include "gateway_client.h" -#include "vis.h"  static struct net_device *batadv_kobj_to_netdev(struct kobject *obj)  {  	struct device *dev = container_of(obj->parent, struct device, kobj); +  	return to_net_dev(dev);  }  static struct batadv_priv *batadv_kobj_to_batpriv(struct kobject *obj)  {  	struct net_device *net_dev = batadv_kobj_to_netdev(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 = {		\ @@ -60,7 +117,7 @@ struct batadv_attribute batadv_attr_##_name = {		\  		 .mode = _mode },			\  	.show   = _show,				\  	.store  = _store,				\ -}; +}  #define BATADV_ATTR_SIF_STORE_BOOL(_name, _post_func)			\  ssize_t batadv_store_##_name(struct kobject *kobj,			\ @@ -69,6 +126,7 @@ ssize_t batadv_store_##_name(struct kobject *kobj,			\  {									\  	struct net_device *net_dev = batadv_kobj_to_netdev(kobj);	\  	struct batadv_priv *bat_priv = netdev_priv(net_dev);		\ +									\  	return __batadv_store_bool_attr(buff, count, _post_func, attr,	\  					&bat_priv->_name, net_dev);	\  } @@ -78,6 +136,7 @@ ssize_t batadv_show_##_name(struct kobject *kobj,			\  			    struct attribute *attr, char *buff)		\  {									\  	struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj);	\ +									\  	return sprintf(buff, "%s\n",					\  		       atomic_read(&bat_priv->_name) == 0 ?		\  		       "disabled" : "enabled");				\ @@ -100,6 +159,7 @@ ssize_t batadv_store_##_name(struct kobject *kobj,			\  {									\  	struct net_device *net_dev = batadv_kobj_to_netdev(kobj);	\  	struct batadv_priv *bat_priv = netdev_priv(net_dev);		\ +									\  	return __batadv_store_uint_attr(buff, count, _min, _max,	\  					_post_func, attr,		\  					&bat_priv->_name, net_dev);	\ @@ -110,6 +170,7 @@ ssize_t batadv_show_##_name(struct kobject *kobj,			\  			    struct attribute *attr, char *buff)		\  {									\  	struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj);	\ +									\  	return sprintf(buff, "%i\n", atomic_read(&bat_priv->_name));	\  }									\ @@ -122,6 +183,43 @@ 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, @@ -230,85 +328,19 @@ __batadv_store_uint_attr(const char *buff, size_t count,  	return ret;  } -static ssize_t batadv_show_vis_mode(struct kobject *kobj, -				    struct attribute *attr, char *buff) -{ -	struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); -	int vis_mode = atomic_read(&bat_priv->vis_mode); -	const char *mode; - -	if (vis_mode == BATADV_VIS_TYPE_CLIENT_UPDATE) -		mode = "client"; -	else -		mode = "server"; - -	return sprintf(buff, "%s\n", mode); -} - -static ssize_t batadv_store_vis_mode(struct kobject *kobj, -				     struct attribute *attr, char *buff, -				     size_t count) -{ -	struct net_device *net_dev = batadv_kobj_to_netdev(kobj); -	struct batadv_priv *bat_priv = netdev_priv(net_dev); -	unsigned long val; -	int ret, vis_mode_tmp = -1; -	const char *old_mode, *new_mode; - -	ret = kstrtoul(buff, 10, &val); - -	if (((count == 2) && (!ret) && -	     (val == BATADV_VIS_TYPE_CLIENT_UPDATE)) || -	    (strncmp(buff, "client", 6) == 0) || -	    (strncmp(buff, "off", 3) == 0)) -		vis_mode_tmp = BATADV_VIS_TYPE_CLIENT_UPDATE; - -	if (((count == 2) && (!ret) && -	     (val == BATADV_VIS_TYPE_SERVER_SYNC)) || -	    (strncmp(buff, "server", 6) == 0)) -		vis_mode_tmp = BATADV_VIS_TYPE_SERVER_SYNC; - -	if (vis_mode_tmp < 0) { -		if (buff[count - 1] == '\n') -			buff[count - 1] = '\0'; - -		batadv_info(net_dev, -			    "Invalid parameter for 'vis mode' setting received: %s\n", -			    buff); -		return -EINVAL; -	} - -	if (atomic_read(&bat_priv->vis_mode) == vis_mode_tmp) -		return count; - -	if (atomic_read(&bat_priv->vis_mode) == BATADV_VIS_TYPE_CLIENT_UPDATE) -		old_mode =  "client"; -	else -		old_mode = "server"; - -	if (vis_mode_tmp == BATADV_VIS_TYPE_CLIENT_UPDATE) -		new_mode =  "client"; -	else -		new_mode = "server"; - -	batadv_info(net_dev, "Changing vis mode from: %s to: %s\n", old_mode, -		    new_mode); - -	atomic_set(&bat_priv->vis_mode, (unsigned int)vis_mode_tmp); -	return count; -} -  static ssize_t batadv_show_bat_algo(struct kobject *kobj,  				    struct attribute *attr, char *buff)  {  	struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); +  	return sprintf(buff, "%s\n", bat_priv->bat_algo_ops->name);  } -static void batadv_post_gw_deselect(struct net_device *net_dev) +static void batadv_post_gw_reselect(struct net_device *net_dev)  {  	struct batadv_priv *bat_priv = netdev_priv(net_dev); -	batadv_gw_deselect(bat_priv); + +	batadv_gw_reselect(bat_priv);  }  static ssize_t batadv_show_gw_mode(struct kobject *kobj, struct attribute *attr, @@ -384,12 +416,22 @@ static ssize_t batadv_store_gw_mode(struct kobject *kobj,  	batadv_info(net_dev, "Changing gw mode from: %s to: %s\n",  		    curr_gw_mode_str, buff); -	batadv_gw_deselect(bat_priv); +	/* Invoking batadv_gw_reselect() is not enough to really de-select the +	 * current GW. It will only instruct the gateway client code to perform +	 * a re-election the next time that this is needed. +	 * +	 * When gw client mode is being switched off the current GW must be +	 * de-selected explicitly otherwise no GW_ADD uevent is thrown on +	 * client mode re-activation. This is operation is performed in +	 * batadv_gw_check_client_stop(). +	 */ +	batadv_gw_reselect(bat_priv);  	/* always call batadv_gw_check_client_stop() before changing the gateway  	 * state  	 */  	batadv_gw_check_client_stop(bat_priv);  	atomic_set(&bat_priv->gw_mode, (unsigned int)gw_mode_tmp); +	batadv_gw_tvlv_container_update(bat_priv);  	return count;  } @@ -397,15 +439,13 @@ static ssize_t batadv_show_gw_bwidth(struct kobject *kobj,  				     struct attribute *attr, char *buff)  {  	struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); -	int down, up; -	int gw_bandwidth = atomic_read(&bat_priv->gw_bandwidth); +	uint32_t down, up; + +	down = atomic_read(&bat_priv->gw.bandwidth_down); +	up = atomic_read(&bat_priv->gw.bandwidth_up); -	batadv_gw_bandwidth_to_kbit(gw_bandwidth, &down, &up); -	return sprintf(buff, "%i%s/%i%s\n", -		       (down > 2048 ? down / 1024 : down), -		       (down > 2048 ? "MBit" : "KBit"), -		       (up > 2048 ? up / 1024 : up), -		       (up > 2048 ? "MBit" : "KBit")); +	return sprintf(buff, "%u.%u/%u.%u MBit\n", down / 10, +		       down % 10, up / 10, up % 10);  }  static ssize_t batadv_store_gw_bwidth(struct kobject *kobj, @@ -420,18 +460,84 @@ static ssize_t batadv_store_gw_bwidth(struct kobject *kobj,  	return batadv_gw_bandwidth_set(net_dev, buff, count);  } +/** + * batadv_show_isolation_mark - print the current isolation mark/mask + * @kobj: kobject representing the private mesh sysfs directory + * @attr: the batman-adv attribute the user is interacting with + * @buff: the buffer that will contain the data to send back to the user + * + * Returns the number of bytes written into 'buff' on success or a negative + * error code in case of failure + */ +static ssize_t batadv_show_isolation_mark(struct kobject *kobj, +					  struct attribute *attr, char *buff) +{ +	struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); + +	return sprintf(buff, "%#.8x/%#.8x\n", bat_priv->isolation_mark, +		       bat_priv->isolation_mark_mask); +} + +/** + * batadv_store_isolation_mark - parse and store the isolation mark/mask entered + *  by the user + * @kobj: kobject representing the private mesh sysfs directory + * @attr: the batman-adv attribute the user is interacting with + * @buff: the buffer containing the user data + * @count: number of bytes in the buffer + * + * Returns 'count' on success or a negative error code in case of failure + */ +static ssize_t batadv_store_isolation_mark(struct kobject *kobj, +					   struct attribute *attr, char *buff, +					   size_t count) +{ +	struct net_device *net_dev = batadv_kobj_to_netdev(kobj); +	struct batadv_priv *bat_priv = netdev_priv(net_dev); +	uint32_t mark, mask; +	char *mask_ptr; + +	/* parse the mask if it has been specified, otherwise assume the mask is +	 * the biggest possible +	 */ +	mask = 0xFFFFFFFF; +	mask_ptr = strchr(buff, '/'); +	if (mask_ptr) { +		*mask_ptr = '\0'; +		mask_ptr++; + +		/* the mask must be entered in hex base as it is going to be a +		 * bitmask and not a prefix length +		 */ +		if (kstrtou32(mask_ptr, 16, &mask) < 0) +			return -EINVAL; +	} + +	/* the mark can be entered in any base */ +	if (kstrtou32(buff, 0, &mark) < 0) +		return -EINVAL; + +	bat_priv->isolation_mark_mask = mask; +	/* erase bits not covered by the mask */ +	bat_priv->isolation_mark = mark & bat_priv->isolation_mark_mask; + +	batadv_info(net_dev, +		    "New skb mark for extended isolation: %#.8x/%#.8x\n", +		    bat_priv->isolation_mark, bat_priv->isolation_mark_mask); + +	return count; +} +  BATADV_ATTR_SIF_BOOL(aggregated_ogms, S_IRUGO | S_IWUSR, NULL);  BATADV_ATTR_SIF_BOOL(bonding, S_IRUGO | S_IWUSR, NULL);  #ifdef CONFIG_BATMAN_ADV_BLA  BATADV_ATTR_SIF_BOOL(bridge_loop_avoidance, S_IRUGO | S_IWUSR, NULL);  #endif  #ifdef CONFIG_BATMAN_ADV_DAT -BATADV_ATTR_SIF_BOOL(distributed_arp_table, S_IRUGO | S_IWUSR, NULL); +BATADV_ATTR_SIF_BOOL(distributed_arp_table, S_IRUGO | S_IWUSR, +		     batadv_dat_status_update);  #endif  BATADV_ATTR_SIF_BOOL(fragmentation, S_IRUGO | S_IWUSR, batadv_update_min_mtu); -BATADV_ATTR_SIF_BOOL(ap_isolation, S_IRUGO | S_IWUSR, NULL); -static BATADV_ATTR(vis_mode, S_IRUGO | S_IWUSR, batadv_show_vis_mode, -		   batadv_store_vis_mode);  static BATADV_ATTR(routing_algo, S_IRUGO, batadv_show_bat_algo, NULL);  static BATADV_ATTR(gw_mode, S_IRUGO | S_IWUSR, batadv_show_gw_mode,  		   batadv_store_gw_mode); @@ -440,15 +546,21 @@ BATADV_ATTR_SIF_UINT(orig_interval, S_IRUGO | S_IWUSR, 2 * BATADV_JITTER,  BATADV_ATTR_SIF_UINT(hop_penalty, S_IRUGO | S_IWUSR, 0, BATADV_TQ_MAX_VALUE,  		     NULL);  BATADV_ATTR_SIF_UINT(gw_sel_class, S_IRUGO | S_IWUSR, 1, BATADV_TQ_MAX_VALUE, -		     batadv_post_gw_deselect); +		     batadv_post_gw_reselect);  static BATADV_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, batadv_show_gw_bwidth,  		   batadv_store_gw_bwidth); +#ifdef CONFIG_BATMAN_ADV_MCAST +BATADV_ATTR_SIF_BOOL(multicast_mode, S_IRUGO | S_IWUSR, NULL); +#endif  #ifdef CONFIG_BATMAN_ADV_DEBUG  BATADV_ATTR_SIF_UINT(log_level, S_IRUGO | S_IWUSR, 0, BATADV_DBG_ALL, NULL);  #endif  #ifdef CONFIG_BATMAN_ADV_NC -BATADV_ATTR_SIF_BOOL(network_coding, S_IRUGO | S_IWUSR, NULL); +BATADV_ATTR_SIF_BOOL(network_coding, S_IRUGO | S_IWUSR, +		     batadv_nc_status_update);  #endif +static BATADV_ATTR(isolation_mark, S_IRUGO | S_IWUSR, +		   batadv_show_isolation_mark, batadv_store_isolation_mark);  static struct batadv_attribute *batadv_mesh_attrs[] = {  	&batadv_attr_aggregated_ogms, @@ -459,9 +571,10 @@ static struct batadv_attribute *batadv_mesh_attrs[] = {  #ifdef CONFIG_BATMAN_ADV_DAT  	&batadv_attr_distributed_arp_table,  #endif +#ifdef CONFIG_BATMAN_ADV_MCAST +	&batadv_attr_multicast_mode, +#endif  	&batadv_attr_fragmentation, -	&batadv_attr_ap_isolation, -	&batadv_attr_vis_mode,  	&batadv_attr_routing_algo,  	&batadv_attr_gw_mode,  	&batadv_attr_orig_interval, @@ -474,6 +587,17 @@ static struct batadv_attribute *batadv_mesh_attrs[] = {  #ifdef CONFIG_BATMAN_ADV_NC  	&batadv_attr_network_coding,  #endif +	&batadv_attr_isolation_mark, +	NULL, +}; + +BATADV_ATTR_VLAN_BOOL(ap_isolation, S_IRUGO | S_IWUSR, NULL); + +/** + * batadv_vlan_attrs - array of vlan specific sysfs attributes + */ +static struct batadv_attribute *batadv_vlan_attrs[] = { +	&batadv_attr_vlan_ap_isolation,  	NULL,  }; @@ -527,6 +651,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)  {  | 
