[PATCH] libertas: fix changing interface type when interface is down

Dan Williams dcbw at redhat.com
Fri Oct 14 11:00:35 EDT 2011


On Fri, 2011-10-14 at 12:05 +0100, Daniel Drake wrote:
> The recent changes to only power the device when the interface up
> introduced a bug: changing interface type, legal when the interface
> is down, performs device I/O.
> 
> Fix this functionality by validating and recording the interface
> type when the change is requested, but only applying the change
> if/when the interface is brought up.
> 
> Signed-off-by: Daniel Drake <dsd at laptop.org>

Acked-by: Dan Williams <dcbw at redhat.com>

> ---
>  drivers/net/wireless/libertas/cfg.c  |   20 ++++++--------------
>  drivers/net/wireless/libertas/decl.h |    2 ++
>  drivers/net/wireless/libertas/main.c |   32 ++++++++++++++++++++++++++++++++
>  3 files changed, 40 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
> index 610bfce..ff63782 100644
> --- a/drivers/net/wireless/libertas/cfg.c
> +++ b/drivers/net/wireless/libertas/cfg.c
> @@ -1666,28 +1666,20 @@ static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev,
>  	if (dev == priv->mesh_dev)
>  		return -EOPNOTSUPP;
>  
> -	lbs_deb_enter(LBS_DEB_CFG80211);
> -
>  	switch (type) {
>  	case NL80211_IFTYPE_MONITOR:
> -		ret = lbs_set_monitor_mode(priv, 1);
> -		break;
>  	case NL80211_IFTYPE_STATION:
> -		if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
> -			ret = lbs_set_monitor_mode(priv, 0);
> -		if (!ret)
> -			ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 1);
> -		break;
>  	case NL80211_IFTYPE_ADHOC:
> -		if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
> -			ret = lbs_set_monitor_mode(priv, 0);
> -		if (!ret)
> -			ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 2);
>  		break;
>  	default:
> -		ret = -ENOTSUPP;
> +		return -EOPNOTSUPP;
>  	}
>  
> +	lbs_deb_enter(LBS_DEB_CFG80211);
> +
> +	if (priv->iface_running)
> +		ret = lbs_set_iface_type(priv, type);
> +
>  	if (!ret)
>  		priv->wdev->iftype = type;
>  
> diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
> index 9304e6f..bc951ab 100644
> --- a/drivers/net/wireless/libertas/decl.h
> +++ b/drivers/net/wireless/libertas/decl.h
> @@ -9,6 +9,7 @@
>  
>  #include <linux/netdevice.h>
>  #include <linux/firmware.h>
> +#include <linux/nl80211.h>
>  
>  /* Should be terminated by a NULL entry */
>  struct lbs_fw_table {
> @@ -45,6 +46,7 @@ void lbs_host_to_card_done(struct lbs_private *priv);
>  
>  int lbs_start_iface(struct lbs_private *priv);
>  int lbs_stop_iface(struct lbs_private *priv);
> +int lbs_set_iface_type(struct lbs_private *priv, enum nl80211_iftype type);
>  
>  int lbs_rtap_supported(struct lbs_private *priv);
>  
> diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
> index 6a32623..f78afd7 100644
> --- a/drivers/net/wireless/libertas/main.c
> +++ b/drivers/net/wireless/libertas/main.c
> @@ -99,6 +99,32 @@ u8 lbs_data_rate_to_fw_index(u32 rate)
>  	return 0;
>  }
>  
> +int lbs_set_iface_type(struct lbs_private *priv, enum nl80211_iftype type)
> +{
> +	int ret = 0;
> +
> +	switch (type) {
> +	case NL80211_IFTYPE_MONITOR:
> +		ret = lbs_set_monitor_mode(priv, 1);
> +		break;
> +	case NL80211_IFTYPE_STATION:
> +		if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
> +			ret = lbs_set_monitor_mode(priv, 0);
> +		if (!ret)
> +			ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 1);
> +		break;
> +	case NL80211_IFTYPE_ADHOC:
> +		if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)
> +			ret = lbs_set_monitor_mode(priv, 0);
> +		if (!ret)
> +			ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 2);
> +		break;
> +	default:
> +		ret = -ENOTSUPP;
> +	}
> +	return ret;
> +}
> +
>  int lbs_start_iface(struct lbs_private *priv)
>  {
>  	struct cmd_ds_802_11_mac_address cmd;
> @@ -120,6 +146,12 @@ int lbs_start_iface(struct lbs_private *priv)
>  		goto err;
>  	}
>  
> +	ret = lbs_set_iface_type(priv, priv->wdev->iftype);
> +	if (ret) {
> +		lbs_deb_net("set iface type failed\n");
> +		goto err;
> +	}
> +
>  	lbs_update_channel(priv);
>  
>  	priv->iface_running = true;





More information about the libertas-dev mailing list