diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index fc80b7b43b2173e62bcf480b97b478d53e422eb4..ed097268a1bc493e4aaf4c2d5b3cbc31b620482d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -798,6 +798,9 @@ struct iwl_mvm { struct cfg80211_chan_def chandef; struct sk_buff *skb; /* ch sw template */ u32 ch_sw_tm_ie; + + /* timestamp of last ch-sw request sent (GP2 time) */ + u32 sent_timestamp; } peer; } tdls_cs; diff --git a/drivers/net/wireless/iwlwifi/mvm/tdls.c b/drivers/net/wireless/iwlwifi/mvm/tdls.c index ea1831ccc8f310d94ad43a6814b810b4b27dccff..a87b506c8c7272393304824409ae8473d6022277 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tdls.c +++ b/drivers/net/wireless/iwlwifi/mvm/tdls.c @@ -64,6 +64,8 @@ #include #include "mvm.h" #include "time-event.h" +#include "iwl-io.h" +#include "iwl-prph.h" #define TU_TO_US(x) (x * 1024) #define TU_TO_MS(x) (TU_TO_US(x) / 1000) @@ -250,6 +252,11 @@ static void iwl_mvm_tdls_update_cs_state(struct iwl_mvm *mvm, iwl_mvm_tdls_cs_state_str(state)); mvm->tdls_cs.state = state; + /* we only send requests to our switching peer - update sent time */ + if (state == IWL_MVM_TDLS_SW_REQ_SENT) + mvm->tdls_cs.peer.sent_timestamp = + iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG); + if (state == IWL_MVM_TDLS_SW_IDLE) mvm->tdls_cs.cur_sta_id = IWL_MVM_STATION_COUNT; } @@ -302,7 +309,7 @@ int iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, static int iwl_mvm_tdls_check_action(struct iwl_mvm *mvm, enum iwl_tdls_channel_switch_type type, - const u8 *peer, bool peer_initiator) + const u8 *peer, bool peer_initiator, u32 timestamp) { bool same_peer = false; int ret = 0; @@ -341,6 +348,9 @@ iwl_mvm_tdls_check_action(struct iwl_mvm *mvm, else if (type == TDLS_SEND_CHAN_SW_REQ) /* wait for idle before sending another request */ ret = -EBUSY; + else if (timestamp <= mvm->tdls_cs.peer.sent_timestamp) + /* we got a stale response - ignore it */ + ret = -EINVAL; break; case IWL_MVM_TDLS_SW_RESP_RCVD: /* @@ -399,7 +409,8 @@ iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); - ret = iwl_mvm_tdls_check_action(mvm, type, peer, peer_initiator); + ret = iwl_mvm_tdls_check_action(mvm, type, peer, peer_initiator, + timestamp); if (ret) return ret;