Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b9dccdb3 authored by Arik Nemtsov's avatar Arik Nemtsov Committed by Emmanuel Grumbach
Browse files

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: default avatarArik Nemtsov <arikx.nemtsov@intel.com>
Reviewed-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
parent 5cb12701
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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;

+13 −2
Original line number Diff line number Diff line
@@ -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 @@ 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;