79 lines
2.7 KiB
Diff
79 lines
2.7 KiB
Diff
|
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
|
||
|
Date: Fri, 31 Aug 2018 11:31:12 +0300
|
||
|
Subject: [PATCH] mac80211: don't Tx a deauth frame if the AP forbade Tx
|
||
|
|
||
|
If the driver fails to properly prepare for the channel
|
||
|
switch, mac80211 will disconnect. If the CSA IE had mode
|
||
|
set to 1, it means that the clients are not allowed to send
|
||
|
any Tx on the current channel, and that includes the
|
||
|
deauthentication frame.
|
||
|
|
||
|
Make sure that we don't send the deauthentication frame in
|
||
|
this case.
|
||
|
|
||
|
In iwlwifi, this caused a failure to flush queues since the
|
||
|
firmware already closed the queues after having parsed the
|
||
|
CSA IE. Then mac80211 would wait until the deauthentication
|
||
|
frame would go out (drv_flush(drop=false)) and that would
|
||
|
never happen.
|
||
|
|
||
|
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
|
||
|
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
|
||
|
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||
|
---
|
||
|
|
||
|
--- a/net/mac80211/mlme.c
|
||
|
+++ b/net/mac80211/mlme.c
|
||
|
@@ -1267,6 +1267,16 @@ ieee80211_sta_process_chanswitch(struct
|
||
|
cbss->beacon_interval));
|
||
|
return;
|
||
|
drop_connection:
|
||
|
+ /*
|
||
|
+ * This is just so that the disconnect flow will know that
|
||
|
+ * we were trying to switch channel and failed. In case the
|
||
|
+ * mode is 1 (we are not allowed to Tx), we will know not to
|
||
|
+ * send a deauthentication frame. Those two fields will be
|
||
|
+ * reset when the disconnection worker runs.
|
||
|
+ */
|
||
|
+ sdata->vif.csa_active = true;
|
||
|
+ sdata->csa_block_tx = csa_ie.mode;
|
||
|
+
|
||
|
ieee80211_queue_work(&local->hw, &ifmgd->csa_connection_drop_work);
|
||
|
mutex_unlock(&local->chanctx_mtx);
|
||
|
mutex_unlock(&local->mtx);
|
||
|
@@ -2437,6 +2447,7 @@ static void __ieee80211_disconnect(struc
|
||
|
struct ieee80211_local *local = sdata->local;
|
||
|
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
|
||
|
u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
|
||
|
+ bool tx;
|
||
|
|
||
|
sdata_lock(sdata);
|
||
|
if (!ifmgd->associated) {
|
||
|
@@ -2444,6 +2455,8 @@ static void __ieee80211_disconnect(struc
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
+ tx = !sdata->csa_block_tx;
|
||
|
+
|
||
|
/* AP is probably out of range (or not reachable for another reason) so
|
||
|
* remove the bss struct for that AP.
|
||
|
*/
|
||
|
@@ -2451,7 +2464,7 @@ static void __ieee80211_disconnect(struc
|
||
|
|
||
|
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
|
||
|
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
|
||
|
- true, frame_buf);
|
||
|
+ tx, frame_buf);
|
||
|
mutex_lock(&local->mtx);
|
||
|
sdata->vif.csa_active = false;
|
||
|
ifmgd->csa_waiting_bcn = false;
|
||
|
@@ -2462,7 +2475,7 @@ static void __ieee80211_disconnect(struc
|
||
|
}
|
||
|
mutex_unlock(&local->mtx);
|
||
|
|
||
|
- ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true,
|
||
|
+ ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), tx,
|
||
|
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
|
||
|
|
||
|
sdata_unlock(sdata);
|