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:
parent
7a72476766
commit
5c1381ac3f
|
@ -1666,28 +1666,20 @@ static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev,
|
||||||
if (dev == priv->mesh_dev)
|
if (dev == priv->mesh_dev)
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
lbs_deb_enter(LBS_DEB_CFG80211);
|
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case NL80211_IFTYPE_MONITOR:
|
case NL80211_IFTYPE_MONITOR:
|
||||||
ret = lbs_set_monitor_mode(priv, 1);
|
|
||||||
break;
|
|
||||||
case NL80211_IFTYPE_STATION:
|
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:
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -ENOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lbs_deb_enter(LBS_DEB_CFG80211);
|
||||||
|
|
||||||
|
if (priv->iface_running)
|
||||||
|
ret = lbs_set_iface_type(priv, type);
|
||||||
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
priv->wdev->iftype = type;
|
priv->wdev->iftype = type;
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
#include <linux/firmware.h>
|
#include <linux/firmware.h>
|
||||||
|
#include <linux/nl80211.h>
|
||||||
|
|
||||||
/* Should be terminated by a NULL entry */
|
/* Should be terminated by a NULL entry */
|
||||||
struct lbs_fw_table {
|
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_start_iface(struct lbs_private *priv);
|
||||||
int lbs_stop_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);
|
int lbs_rtap_supported(struct lbs_private *priv);
|
||||||
|
|
||||||
|
|
|
@ -99,6 +99,32 @@ u8 lbs_data_rate_to_fw_index(u32 rate)
|
||||||
return 0;
|
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)
|
int lbs_start_iface(struct lbs_private *priv)
|
||||||
{
|
{
|
||||||
struct cmd_ds_802_11_mac_address cmd;
|
struct cmd_ds_802_11_mac_address cmd;
|
||||||
|
@ -120,6 +146,12 @@ int lbs_start_iface(struct lbs_private *priv)
|
||||||
goto err;
|
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);
|
lbs_update_channel(priv);
|
||||||
|
|
||||||
priv->iface_running = true;
|
priv->iface_running = true;
|
||||||
|
|
Loading…
Reference in a new issue