mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-01 08:21:04 -04:00
iwlwifi: mvm: fix a race in CSA that caused assert 0x3420
When we get a channel switch with a very long quiet period, we schedule a work to disconnect after a while. This work runs in background. In the meanwhile, we keep getting beacons and sending FW modify command for each. This has a potential race, where we modify the CSA after we aborted it. Protect the flow by setting csa_failed to true in case we abort, and check it before sending the modify command. This required a modification to the way we treat csa_failed in iwl_mvm_post_channel_switch: 1. The variable isn't being reset anymore, so we can still look at it in iwl_mvm_channel_switch_rx_beacon. This is fine, since we reset it when starting a new CSA. 2. There is no more early return in case of csa_failed. This is fine, since before this patch csa_failed was set only for GO, and for GO the function is only resetting the power settings, which we want to restore even in case of failure. Signed-off-by: Sara Sharon <sara.sharon@intel.com> Signed-off-by: Luca Coelho <luciano.coelho@intel.com> Link: https://lore.kernel.org/r/iwlwifi.20201209231352.b023856bdf39.I4ed0149e0018fe5e1ae3c2a1cbc614954016063f@changeid Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
This commit is contained in:
@@ -1300,12 +1300,6 @@ static int iwl_mvm_post_channel_switch(struct ieee80211_hw *hw,
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
|
||||
if (mvmvif->csa_failed) {
|
||||
mvmvif->csa_failed = false;
|
||||
ret = -EIO;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_STATION) {
|
||||
struct iwl_mvm_sta *mvmsta;
|
||||
|
||||
@@ -1337,6 +1331,8 @@ static int iwl_mvm_post_channel_switch(struct ieee80211_hw *hw,
|
||||
ret = iwl_mvm_power_update_ps(mvm);
|
||||
|
||||
out_unlock:
|
||||
if (mvmvif->csa_failed)
|
||||
ret = -EIO;
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
||||
return ret;
|
||||
@@ -1364,9 +1360,10 @@ static void iwl_mvm_abort_channel_switch(struct ieee80211_hw *hw,
|
||||
WIDE_ID(MAC_CONF_GROUP,
|
||||
CHANNEL_SWITCH_TIME_EVENT_CMD),
|
||||
0, sizeof(cmd), &cmd));
|
||||
mvmvif->csa_failed = true;
|
||||
mutex_unlock(&mvm->mutex);
|
||||
|
||||
WARN_ON(iwl_mvm_post_channel_switch(hw, vif));
|
||||
iwl_mvm_post_channel_switch(hw, vif);
|
||||
}
|
||||
|
||||
static void iwl_mvm_channel_switch_disconnect_wk(struct work_struct *wk)
|
||||
@@ -4624,12 +4621,17 @@ static void iwl_mvm_channel_switch_rx_beacon(struct ieee80211_hw *hw,
|
||||
}
|
||||
mvmvif->csa_count = chsw->count;
|
||||
|
||||
IWL_DEBUG_MAC80211(mvm, "Modify CSA on mac %d\n", mvmvif->id);
|
||||
mutex_lock(&mvm->mutex);
|
||||
if (mvmvif->csa_failed)
|
||||
goto out_unlock;
|
||||
|
||||
IWL_DEBUG_MAC80211(mvm, "Modify CSA on mac %d\n", mvmvif->id);
|
||||
WARN_ON(iwl_mvm_send_cmd_pdu(mvm,
|
||||
WIDE_ID(MAC_CONF_GROUP,
|
||||
CHANNEL_SWITCH_TIME_EVENT_CMD),
|
||||
CMD_ASYNC, sizeof(cmd), &cmd));
|
||||
0, sizeof(cmd), &cmd));
|
||||
out_unlock:
|
||||
mutex_unlock(&mvm->mutex);
|
||||
}
|
||||
|
||||
static void iwl_mvm_flush_no_vif(struct iwl_mvm *mvm, u32 queues, bool drop)
|
||||
|
||||
Reference in New Issue
Block a user