libertas: fix changing interface type when interface is down

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@laptop.org>
Acked-by: Dan Williams <dcbw@redhat.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Daniel Drake 2011-10-14 12:05:26 +01:00 committed by John W. Linville
parent 7a72476766
commit 5c1381ac3f
3 changed files with 40 additions and 14 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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;