summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi
diff options
context:
space:
mode:
authorArik Nemtsov2015-01-22 13:24:44 +0100
committerEmmanuel Grumbach2015-02-01 14:57:22 +0100
commitb9dccdb33c4dc86922d025d02e91715ad9510732 (patch)
treefaf8f78fe4483cc81888f0a50029ff5b6ad8db6c /drivers/net/wireless/iwlwifi
parentiwlwifi: mvm: improve TDLS ch-sw state machine (diff)
downloadkernel-qcow2-linux-b9dccdb33c4dc86922d025d02e91715ad9510732.tar.gz
kernel-qcow2-linux-b9dccdb33c4dc86922d025d02e91715ad9510732.tar.xz
kernel-qcow2-linux-b9dccdb33c4dc86922d025d02e91715ad9510732.zip
iwlwifi: mvm: ignore stale TDLS ch-switch responses
During out-of-channel activities (e.g. scan) TDLS ch-switch responses from a peer are kept in FW. These packets arrive only after the out-of-channel activity is complete, which can be in the order of several seconds. Since TDLS ch-sw has no dialog-token-like mechanism for distinguishing sessions, use the GP2 time of the incoming ch-switch response to discern validity. For this purpose record the GP2 time of an outgoing TDLS ch-sw request and compare to the Rx time of the ch-sw response. The methods works in practice since the GP2 time of FW-deferred Rx is accurate and contains the real Rx timestamp. Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com> Reviewed-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h3
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tdls.c15
2 files changed, 16 insertions, 2 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index fc80b7b43b21..ed097268a1bc 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 ea1831ccc8f3..a87b506c8c72 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tdls.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tdls.c
@@ -64,6 +64,8 @@
#include <linux/etherdevice.h>
#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 @@ out:
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;