summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-03-07 09:52:42 -0800
committerJohn W. Linville <linville@tuxdriver.com>2012-03-08 14:02:29 -0500
commit974205153be8944539890084a170e3ad407164bc (patch)
tree4b8da67657cf324b998ef5ced44c894189e14092
parente6dd5838acf312516fcc4eb34516de5bc45e2980 (diff)
downloadlinux-974205153be8944539890084a170e3ad407164bc.tar.gz
linux-974205153be8944539890084a170e3ad407164bc.tar.xz
linux-974205153be8944539890084a170e3ad407164bc.zip
iwlwifi: don't delete AP station directly
With the mac80211 deauth sequence changes, the station is deleted before the device is set unassociated. This can cause the device to get confused as it expects the station to be there while the associated bit is set. To fix this, do not delete the AP station from the device when mac80211 asks for deletion, instead just mark it as unused and rely on the unassociated RXON to drop it from the station database in the device. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-sta.c35
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-mac80211.c22
3 files changed, 53 insertions, 6 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
index 23e9eab477bb..c4175603864b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
@@ -546,6 +546,41 @@ out_err:
return -EINVAL;
}
+void iwl_deactivate_station(struct iwl_priv *priv, const u8 sta_id,
+ const u8 *addr)
+{
+ u8 tid;
+
+ if (!iwl_is_ready(priv)) {
+ IWL_DEBUG_INFO(priv,
+ "Unable to remove station %pM, device not ready.\n",
+ addr);
+ return;
+ }
+
+ IWL_DEBUG_ASSOC(priv, "Deactivating STA: %pM (%d)\n", addr, sta_id);
+
+ if (WARN_ON_ONCE(sta_id == IWL_INVALID_STATION))
+ return;
+
+ spin_lock_bh(&priv->sta_lock);
+
+ WARN_ON_ONCE(!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE));
+
+ for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++)
+ memset(&priv->tid_data[sta_id][tid], 0,
+ sizeof(priv->tid_data[sta_id][tid]));
+
+ priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
+
+ priv->num_stations--;
+
+ if (WARN_ON_ONCE(priv->num_stations < 0))
+ priv->num_stations = 0;
+
+ spin_unlock_bh(&priv->sta_lock);
+}
+
/**
* iwl_clear_ucode_stations - clear ucode station table bits
*
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index 5410dfd40694..3780a03f2716 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.h
@@ -234,6 +234,8 @@ int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
struct ieee80211_sta *sta, u8 *sta_id_r);
int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
const u8 *addr);
+void iwl_deactivate_station(struct iwl_priv *priv, const u8 sta_id,
+ const u8 *addr);
u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
const u8 *addr, bool is_ap, struct ieee80211_sta *sta);
diff --git a/drivers/net/wireless/iwlwifi/iwl-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c
index 54d3709c0a6c..9212ee3bef9b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-mac80211.c
+++ b/drivers/net/wireless/iwlwifi/iwl-mac80211.c
@@ -724,12 +724,22 @@ static int iwlagn_mac_sta_remove(struct ieee80211_hw *hw,
struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
int ret;
- IWL_DEBUG_INFO(priv, "proceeding to remove station %pM\n",
- sta->addr);
- ret = iwl_remove_station(priv, sta_priv->sta_id, sta->addr);
- if (ret)
- IWL_DEBUG_QUIET_RFKILL(priv, "Error removing station %pM\n",
- sta->addr);
+ IWL_DEBUG_INFO(priv, "proceeding to remove station %pM\n", sta->addr);
+
+ if (vif->type == NL80211_IFTYPE_STATION) {
+ /*
+ * Station will be removed from device when the RXON
+ * is set to unassociated -- just deactivate it here
+ * to avoid re-programming it.
+ */
+ ret = 0;
+ iwl_deactivate_station(priv, sta_priv->sta_id, sta->addr);
+ } else {
+ ret = iwl_remove_station(priv, sta_priv->sta_id, sta->addr);
+ if (ret)
+ IWL_DEBUG_QUIET_RFKILL(priv,
+ "Error removing station %pM\n", sta->addr);
+ }
return ret;
}