diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/tdls.c')
| -rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/tdls.c | 63 | 
1 files changed, 47 insertions, 16 deletions
| diff --git a/drivers/net/wireless/iwlwifi/mvm/tdls.c b/drivers/net/wireless/iwlwifi/mvm/tdls.c index c0e00bae5bd0..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) @@ -228,6 +230,8 @@ iwl_mvm_tdls_cs_state_str(enum iwl_mvm_tdls_cs_state state)  		return "IDLE";  	case IWL_MVM_TDLS_SW_REQ_SENT:  		return "REQ SENT"; +	case IWL_MVM_TDLS_SW_RESP_RCVD: +		return "RESP RECEIVED";  	case IWL_MVM_TDLS_SW_REQ_RCVD:  		return "REQ RECEIVED";  	case IWL_MVM_TDLS_SW_ACTIVE: @@ -248,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;  } @@ -300,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; @@ -325,17 +334,30 @@ iwl_mvm_tdls_check_action(struct iwl_mvm *mvm,  			ret = -EINVAL;  		break;  	case IWL_MVM_TDLS_SW_REQ_SENT: +		/* only allow requests from the same peer */ +		if (!same_peer) +			ret = -EBUSY; +		else if (type == TDLS_SEND_CHAN_SW_RESP_AND_MOVE_CH && +			 !peer_initiator) +			/* +			 * We received a ch-switch request while an outgoing +			 * one is pending. Allow it if the peer is the link +			 * initiator. +			 */ +			ret = -EBUSY; +		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:  		/* -		 * We received a ch-switch request while an outgoing one is -		 * pending. Allow it to proceed if the other peer is the same -		 * one we sent to, and we are not the link initiator. +		 * we are waiting for the FW to give an "active" notification, +		 * so ignore requests in the meantime  		 */ -		if (type == TDLS_SEND_CHAN_SW_RESP_AND_MOVE_CH) { -			if (!same_peer) -				ret = -EBUSY; -			else if (!peer_initiator) /* we are the initiator */ -				ret = -EBUSY; -		} +		ret = -EBUSY;  		break;  	case IWL_MVM_TDLS_SW_REQ_RCVD:  		/* as above, allow the link initiator to proceed */ @@ -349,9 +371,12 @@ iwl_mvm_tdls_check_action(struct iwl_mvm *mvm,  		}  		break;  	case IWL_MVM_TDLS_SW_ACTIVE: -		/* we don't allow initiations during active channel switch */ -		if (type == TDLS_SEND_CHAN_SW_REQ) -			ret = -EINVAL; +		/* +		 * the only valid request when active is a request to return +		 * to the base channel by the current off-channel peer +		 */ +		if (type != TDLS_MOVE_CH || !same_peer) +			ret = -EBUSY;  		break;  	} @@ -384,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; @@ -473,6 +499,8 @@ iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm,  					     type == TDLS_SEND_CHAN_SW_REQ ?  					     IWL_MVM_TDLS_SW_REQ_SENT :  					     IWL_MVM_TDLS_SW_REQ_RCVD); +	} else { +		iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_RESP_RCVD);  	}  out: @@ -657,12 +685,15 @@ iwl_mvm_tdls_recv_channel_switch(struct ieee80211_hw *hw,  	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);  	enum iwl_tdls_channel_switch_type type;  	unsigned int delay; +	const char *action_str = +		params->action_code == WLAN_TDLS_CHANNEL_SWITCH_REQUEST ? +		"REQ" : "RESP";  	mutex_lock(&mvm->mutex);  	IWL_DEBUG_TDLS(mvm, -		       "Received TDLS ch switch action %d from %pM status %d\n", -		       params->action_code, params->sta->addr, params->status); +		       "Received TDLS ch switch action %s from %pM status %d\n", +		       action_str, params->sta->addr, params->status);  	/*  	 * we got a non-zero status from a peer we were switching to - move to |