brintos

brintos / linux-shallow public Read only

0
0
Text · 18.5 KiB · 3d25ff5 Raw
665 lines · c
1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause2/*3 * Copyright (C) 2014 Intel Mobile Communications GmbH4 * Copyright (C) 2017 Intel Deutschland GmbH5 * Copyright (C) 2018-2020, 2022-2024 Intel Corporation6 */7#include <linux/etherdevice.h>8#include "mvm.h"9#include "time-event.h"10#include "iwl-io.h"11#include "iwl-prph.h"12 13#define TU_TO_US(x) (x * 1024)14#define TU_TO_MS(x) (TU_TO_US(x) / 1000)15 16void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm)17{18	struct ieee80211_sta *sta;19	struct iwl_mvm_sta *mvmsta;20	int i;21 22	lockdep_assert_held(&mvm->mutex);23 24	for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) {25		sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],26						lockdep_is_held(&mvm->mutex));27		if (!sta || IS_ERR(sta) || !sta->tdls)28			continue;29 30		mvmsta = iwl_mvm_sta_from_mac80211(sta);31		ieee80211_tdls_oper_request(mvmsta->vif, sta->addr,32				NL80211_TDLS_TEARDOWN,33				WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED,34				GFP_KERNEL);35	}36}37 38int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif)39{40	struct ieee80211_sta *sta;41	struct iwl_mvm_sta *mvmsta;42	int count = 0;43	int i;44 45	lockdep_assert_held(&mvm->mutex);46 47	for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) {48		sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],49						lockdep_is_held(&mvm->mutex));50		if (!sta || IS_ERR(sta) || !sta->tdls)51			continue;52 53		if (vif) {54			mvmsta = iwl_mvm_sta_from_mac80211(sta);55			if (mvmsta->vif != vif)56				continue;57		}58 59		count++;60	}61 62	return count;63}64 65static void iwl_mvm_tdls_config(struct iwl_mvm *mvm, struct ieee80211_vif *vif)66{67	struct iwl_rx_packet *pkt;68	struct iwl_tdls_config_res *resp;69	struct iwl_tdls_config_cmd tdls_cfg_cmd = {};70	struct iwl_host_cmd cmd = {71		.id = TDLS_CONFIG_CMD,72		.flags = CMD_WANT_SKB,73		.data = { &tdls_cfg_cmd, },74		.len = { sizeof(struct iwl_tdls_config_cmd), },75	};76	struct ieee80211_sta *sta;77	int ret, i, cnt;78	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);79 80	lockdep_assert_held(&mvm->mutex);81 82	tdls_cfg_cmd.id_and_color =83		cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));84	tdls_cfg_cmd.tx_to_ap_tid = IWL_MVM_TDLS_FW_TID;85	tdls_cfg_cmd.tx_to_ap_ssn = cpu_to_le16(0); /* not used for now */86 87	/* for now the Tx cmd is empty and unused */88 89	/* populate TDLS peer data */90	cnt = 0;91	for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) {92		sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],93						lockdep_is_held(&mvm->mutex));94		if (IS_ERR_OR_NULL(sta) || !sta->tdls)95			continue;96 97		tdls_cfg_cmd.sta_info[cnt].sta_id = i;98		tdls_cfg_cmd.sta_info[cnt].tx_to_peer_tid =99							IWL_MVM_TDLS_FW_TID;100		tdls_cfg_cmd.sta_info[cnt].tx_to_peer_ssn = cpu_to_le16(0);101		tdls_cfg_cmd.sta_info[cnt].is_initiator =102				cpu_to_le32(sta->tdls_initiator ? 1 : 0);103 104		cnt++;105	}106 107	tdls_cfg_cmd.tdls_peer_count = cnt;108	IWL_DEBUG_TDLS(mvm, "send TDLS config to FW for %d peers\n", cnt);109 110	ret = iwl_mvm_send_cmd(mvm, &cmd);111	if (WARN_ON_ONCE(ret))112		return;113 114	pkt = cmd.resp_pkt;115 116	WARN_ON_ONCE(iwl_rx_packet_payload_len(pkt) != sizeof(*resp));117 118	/* we don't really care about the response at this point */119 120	iwl_free_resp(&cmd);121}122 123void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, struct ieee80211_vif *vif,124			       bool sta_added)125{126	int tdls_sta_cnt = iwl_mvm_tdls_sta_count(mvm, vif);127 128	/* when the first peer joins, send a power update first */129	if (tdls_sta_cnt == 1 && sta_added)130		iwl_mvm_power_update_mac(mvm);131 132	/* Configure the FW with TDLS peer info only if TDLS channel switch133	 * capability is set.134	 * TDLS config data is used currently only in TDLS channel switch code.135	 * Supposed to serve also TDLS buffer station which is not implemneted136	 * yet in FW*/137	if (fw_has_capa(&mvm->fw->ucode_capa,138			IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH))139		iwl_mvm_tdls_config(mvm, vif);140 141	/* when the last peer leaves, send a power update last */142	if (tdls_sta_cnt == 0 && !sta_added)143		iwl_mvm_power_update_mac(mvm);144}145 146void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw,147					   struct ieee80211_vif *vif,148					   unsigned int link_id)149{150	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);151	u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int;152 153	/* Protect the session to hear the TDLS setup response on the channel */154	guard(mvm)(mvm);155	if (fw_has_capa(&mvm->fw->ucode_capa,156			IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD))157		iwl_mvm_schedule_session_protection(mvm, vif, duration,158						    duration, true, link_id);159	else160		iwl_mvm_protect_session(mvm, vif, duration,161					duration, 100, true);162}163 164static const char *165iwl_mvm_tdls_cs_state_str(enum iwl_mvm_tdls_cs_state state)166{167	switch (state) {168	case IWL_MVM_TDLS_SW_IDLE:169		return "IDLE";170	case IWL_MVM_TDLS_SW_REQ_SENT:171		return "REQ SENT";172	case IWL_MVM_TDLS_SW_RESP_RCVD:173		return "RESP RECEIVED";174	case IWL_MVM_TDLS_SW_REQ_RCVD:175		return "REQ RECEIVED";176	case IWL_MVM_TDLS_SW_ACTIVE:177		return "ACTIVE";178	}179 180	return NULL;181}182 183static void iwl_mvm_tdls_update_cs_state(struct iwl_mvm *mvm,184					 enum iwl_mvm_tdls_cs_state state)185{186	if (mvm->tdls_cs.state == state)187		return;188 189	IWL_DEBUG_TDLS(mvm, "TDLS channel switch state: %s -> %s\n",190		       iwl_mvm_tdls_cs_state_str(mvm->tdls_cs.state),191		       iwl_mvm_tdls_cs_state_str(state));192	mvm->tdls_cs.state = state;193 194	/* we only send requests to our switching peer - update sent time */195	if (state == IWL_MVM_TDLS_SW_REQ_SENT)196		mvm->tdls_cs.peer.sent_timestamp = iwl_mvm_get_systime(mvm);197 198	if (state == IWL_MVM_TDLS_SW_IDLE)199		mvm->tdls_cs.cur_sta_id = IWL_MVM_INVALID_STA;200}201 202void iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)203{204	struct iwl_rx_packet *pkt = rxb_addr(rxb);205	struct iwl_tdls_channel_switch_notif *notif = (void *)pkt->data;206	struct ieee80211_sta *sta;207	unsigned int delay;208	struct iwl_mvm_sta *mvmsta;209	struct ieee80211_vif *vif;210	u32 sta_id = le32_to_cpu(notif->sta_id);211 212	lockdep_assert_held(&mvm->mutex);213 214	/* can fail sometimes */215	if (!le32_to_cpu(notif->status)) {216		iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_IDLE);217		return;218	}219 220	if (WARN_ON(sta_id >= mvm->fw->ucode_capa.num_stations))221		return;222 223	sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],224					lockdep_is_held(&mvm->mutex));225	/* the station may not be here, but if it is, it must be a TDLS peer */226	if (IS_ERR_OR_NULL(sta) || WARN_ON(!sta->tdls))227		return;228 229	mvmsta = iwl_mvm_sta_from_mac80211(sta);230	vif = mvmsta->vif;231 232	/*233	 * Update state and possibly switch again after this is over (DTIM).234	 * Also convert TU to msec.235	 */236	delay = TU_TO_MS(vif->bss_conf.dtim_period * vif->bss_conf.beacon_int);237	mod_delayed_work(system_wq, &mvm->tdls_cs.dwork,238			 msecs_to_jiffies(delay));239 240	iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_ACTIVE);241}242 243static int244iwl_mvm_tdls_check_action(struct iwl_mvm *mvm,245			  enum iwl_tdls_channel_switch_type type,246			  const u8 *peer, bool peer_initiator, u32 timestamp)247{248	bool same_peer = false;249	int ret = 0;250 251	/* get the existing peer if it's there */252	if (mvm->tdls_cs.state != IWL_MVM_TDLS_SW_IDLE &&253	    mvm->tdls_cs.cur_sta_id != IWL_MVM_INVALID_STA) {254		struct ieee80211_sta *sta = rcu_dereference_protected(255				mvm->fw_id_to_mac_id[mvm->tdls_cs.cur_sta_id],256				lockdep_is_held(&mvm->mutex));257		if (!IS_ERR_OR_NULL(sta))258			same_peer = ether_addr_equal(peer, sta->addr);259	}260 261	switch (mvm->tdls_cs.state) {262	case IWL_MVM_TDLS_SW_IDLE:263		/*264		 * might be spurious packet from the peer after the switch is265		 * already done266		 */267		if (type == TDLS_MOVE_CH)268			ret = -EINVAL;269		break;270	case IWL_MVM_TDLS_SW_REQ_SENT:271		/* only allow requests from the same peer */272		if (!same_peer)273			ret = -EBUSY;274		else if (type == TDLS_SEND_CHAN_SW_RESP_AND_MOVE_CH &&275			 !peer_initiator)276			/*277			 * We received a ch-switch request while an outgoing278			 * one is pending. Allow it if the peer is the link279			 * initiator.280			 */281			ret = -EBUSY;282		else if (type == TDLS_SEND_CHAN_SW_REQ)283			/* wait for idle before sending another request */284			ret = -EBUSY;285		else if (timestamp <= mvm->tdls_cs.peer.sent_timestamp)286			/* we got a stale response - ignore it */287			ret = -EINVAL;288		break;289	case IWL_MVM_TDLS_SW_RESP_RCVD:290		/*291		 * we are waiting for the FW to give an "active" notification,292		 * so ignore requests in the meantime293		 */294		ret = -EBUSY;295		break;296	case IWL_MVM_TDLS_SW_REQ_RCVD:297		/* as above, allow the link initiator to proceed */298		if (type == TDLS_SEND_CHAN_SW_REQ) {299			if (!same_peer)300				ret = -EBUSY;301			else if (peer_initiator) /* they are the initiator */302				ret = -EBUSY;303		} else if (type == TDLS_MOVE_CH) {304			ret = -EINVAL;305		}306		break;307	case IWL_MVM_TDLS_SW_ACTIVE:308		/*309		 * the only valid request when active is a request to return310		 * to the base channel by the current off-channel peer311		 */312		if (type != TDLS_MOVE_CH || !same_peer)313			ret = -EBUSY;314		break;315	}316 317	if (ret)318		IWL_DEBUG_TDLS(mvm,319			       "Invalid TDLS action %d state %d peer %pM same_peer %d initiator %d\n",320			       type, mvm->tdls_cs.state, peer, same_peer,321			       peer_initiator);322 323	return ret;324}325 326static int327iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm,328				   struct ieee80211_vif *vif,329				   enum iwl_tdls_channel_switch_type type,330				   const u8 *peer, bool peer_initiator,331				   u8 oper_class,332				   struct cfg80211_chan_def *chandef,333				   u32 timestamp, u16 switch_time,334				   u16 switch_timeout, struct sk_buff *skb,335				   u32 ch_sw_tm_ie)336{337	struct ieee80211_sta *sta;338	struct iwl_mvm_sta *mvmsta;339	struct ieee80211_tx_info *info;340	struct ieee80211_hdr *hdr;341	struct iwl_tdls_channel_switch_cmd cmd = {0};342	struct iwl_tdls_channel_switch_cmd_tail *tail =343		iwl_mvm_chan_info_cmd_tail(mvm, &cmd.ci);344	u16 len = sizeof(cmd) - iwl_mvm_chan_info_padding(mvm);345	int ret;346 347	lockdep_assert_held(&mvm->mutex);348 349	ret = iwl_mvm_tdls_check_action(mvm, type, peer, peer_initiator,350					timestamp);351	if (ret)352		return ret;353 354	if (!skb || WARN_ON(skb->len > IWL_TDLS_CH_SW_FRAME_MAX_SIZE)) {355		ret = -EINVAL;356		goto out;357	}358 359	cmd.switch_type = type;360	tail->timing.frame_timestamp = cpu_to_le32(timestamp);361	tail->timing.switch_time = cpu_to_le32(switch_time);362	tail->timing.switch_timeout = cpu_to_le32(switch_timeout);363 364	rcu_read_lock();365	sta = ieee80211_find_sta(vif, peer);366	if (!sta) {367		rcu_read_unlock();368		ret = -ENOENT;369		goto out;370	}371	mvmsta = iwl_mvm_sta_from_mac80211(sta);372	cmd.peer_sta_id = cpu_to_le32(mvmsta->deflink.sta_id);373 374	if (!chandef) {375		if (mvm->tdls_cs.state == IWL_MVM_TDLS_SW_REQ_SENT &&376		    mvm->tdls_cs.peer.chandef.chan) {377			/* actually moving to the channel */378			chandef = &mvm->tdls_cs.peer.chandef;379		} else if (mvm->tdls_cs.state == IWL_MVM_TDLS_SW_ACTIVE &&380			   type == TDLS_MOVE_CH) {381			/* we need to return to base channel */382			struct ieee80211_chanctx_conf *chanctx =383					rcu_dereference(vif->bss_conf.chanctx_conf);384 385			if (WARN_ON_ONCE(!chanctx)) {386				rcu_read_unlock();387				goto out;388			}389 390			chandef = &chanctx->def;391		}392	}393 394	if (chandef)395		iwl_mvm_set_chan_info_chandef(mvm, &cmd.ci, chandef);396 397	/* keep quota calculation simple for now - 50% of DTIM for TDLS */398	tail->timing.max_offchan_duration =399			cpu_to_le32(TU_TO_US(vif->bss_conf.dtim_period *400					     vif->bss_conf.beacon_int) / 2);401 402	/* Switch time is the first element in the switch-timing IE. */403	tail->frame.switch_time_offset = cpu_to_le32(ch_sw_tm_ie + 2);404 405	info = IEEE80211_SKB_CB(skb);406	hdr = (void *)skb->data;407	if (info->control.hw_key) {408		if (info->control.hw_key->cipher != WLAN_CIPHER_SUITE_CCMP) {409			rcu_read_unlock();410			ret = -EINVAL;411			goto out;412		}413		iwl_mvm_set_tx_cmd_ccmp(info, &tail->frame.tx_cmd);414	}415 416	iwl_mvm_set_tx_cmd(mvm, skb, &tail->frame.tx_cmd, info,417			   mvmsta->deflink.sta_id);418 419	iwl_mvm_set_tx_cmd_rate(mvm, &tail->frame.tx_cmd, info, sta,420				hdr->frame_control);421	rcu_read_unlock();422 423	memcpy(tail->frame.data, skb->data, skb->len);424 425	ret = iwl_mvm_send_cmd_pdu(mvm, TDLS_CHANNEL_SWITCH_CMD, 0, len, &cmd);426	if (ret) {427		IWL_ERR(mvm, "Failed to send TDLS_CHANNEL_SWITCH cmd: %d\n",428			ret);429		goto out;430	}431 432	/* channel switch has started, update state */433	if (type != TDLS_MOVE_CH) {434		mvm->tdls_cs.cur_sta_id = mvmsta->deflink.sta_id;435		iwl_mvm_tdls_update_cs_state(mvm,436					     type == TDLS_SEND_CHAN_SW_REQ ?437					     IWL_MVM_TDLS_SW_REQ_SENT :438					     IWL_MVM_TDLS_SW_REQ_RCVD);439	} else {440		iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_RESP_RCVD);441	}442 443out:444 445	/* channel switch failed - we are idle */446	if (ret)447		iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_IDLE);448 449	return ret;450}451 452void iwl_mvm_tdls_ch_switch_work(struct work_struct *work)453{454	struct iwl_mvm *mvm;455	struct ieee80211_sta *sta;456	struct iwl_mvm_sta *mvmsta;457	struct ieee80211_vif *vif;458	unsigned int delay;459	int ret;460 461	mvm = container_of(work, struct iwl_mvm, tdls_cs.dwork.work);462	guard(mvm)(mvm);463 464	/* called after an active channel switch has finished or timed-out */465	iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_IDLE);466 467	/* station might be gone, in that case do nothing */468	if (mvm->tdls_cs.peer.sta_id == IWL_MVM_INVALID_STA)469		return;470 471	sta = rcu_dereference_protected(472				mvm->fw_id_to_mac_id[mvm->tdls_cs.peer.sta_id],473				lockdep_is_held(&mvm->mutex));474	/* the station may not be here, but if it is, it must be a TDLS peer */475	if (!sta || IS_ERR(sta) || WARN_ON(!sta->tdls))476		return;477 478	mvmsta = iwl_mvm_sta_from_mac80211(sta);479	vif = mvmsta->vif;480	ret = iwl_mvm_tdls_config_channel_switch(mvm, vif,481						 TDLS_SEND_CHAN_SW_REQ,482						 sta->addr,483						 mvm->tdls_cs.peer.initiator,484						 mvm->tdls_cs.peer.op_class,485						 &mvm->tdls_cs.peer.chandef,486						 0, 0, 0,487						 mvm->tdls_cs.peer.skb,488						 mvm->tdls_cs.peer.ch_sw_tm_ie);489	if (ret)490		IWL_ERR(mvm, "Not sending TDLS channel switch: %d\n", ret);491 492	/* retry after a DTIM if we failed sending now */493	delay = TU_TO_MS(vif->bss_conf.dtim_period * vif->bss_conf.beacon_int);494	schedule_delayed_work(&mvm->tdls_cs.dwork, msecs_to_jiffies(delay));495}496 497int498iwl_mvm_tdls_channel_switch(struct ieee80211_hw *hw,499			    struct ieee80211_vif *vif,500			    struct ieee80211_sta *sta, u8 oper_class,501			    struct cfg80211_chan_def *chandef,502			    struct sk_buff *tmpl_skb, u32 ch_sw_tm_ie)503{504	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);505	struct iwl_mvm_sta *mvmsta;506	unsigned int delay;507	int ret;508 509	guard(mvm)(mvm);510 511	IWL_DEBUG_TDLS(mvm, "TDLS channel switch with %pM ch %d width %d\n",512		       sta->addr, chandef->chan->center_freq, chandef->width);513 514	/* we only support a single peer for channel switching */515	if (mvm->tdls_cs.peer.sta_id != IWL_MVM_INVALID_STA) {516		IWL_DEBUG_TDLS(mvm,517			       "Existing peer. Can't start switch with %pM\n",518			       sta->addr);519		return -EBUSY;520	}521 522	ret = iwl_mvm_tdls_config_channel_switch(mvm, vif,523						 TDLS_SEND_CHAN_SW_REQ,524						 sta->addr, sta->tdls_initiator,525						 oper_class, chandef, 0, 0, 0,526						 tmpl_skb, ch_sw_tm_ie);527	if (ret)528		return ret;529 530	/*531	 * Mark the peer as "in tdls switch" for this vif. We only allow a532	 * single such peer per vif.533	 */534	mvm->tdls_cs.peer.skb = skb_copy(tmpl_skb, GFP_KERNEL);535	if (!mvm->tdls_cs.peer.skb)536		return -ENOMEM;537 538	mvmsta = iwl_mvm_sta_from_mac80211(sta);539	mvm->tdls_cs.peer.sta_id = mvmsta->deflink.sta_id;540	mvm->tdls_cs.peer.chandef = *chandef;541	mvm->tdls_cs.peer.initiator = sta->tdls_initiator;542	mvm->tdls_cs.peer.op_class = oper_class;543	mvm->tdls_cs.peer.ch_sw_tm_ie = ch_sw_tm_ie;544 545	/*546	 * Wait for 2 DTIM periods before attempting the next switch. The next547	 * switch will be made sooner if the current one completes before that.548	 */549	delay = 2 * TU_TO_MS(vif->bss_conf.dtim_period *550			     vif->bss_conf.beacon_int);551	mod_delayed_work(system_wq, &mvm->tdls_cs.dwork,552			 msecs_to_jiffies(delay));553	return 0;554}555 556void iwl_mvm_tdls_cancel_channel_switch(struct ieee80211_hw *hw,557					struct ieee80211_vif *vif,558					struct ieee80211_sta *sta)559{560	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);561	struct ieee80211_sta *cur_sta;562	bool wait_for_phy = false;563 564	mutex_lock(&mvm->mutex);565 566	IWL_DEBUG_TDLS(mvm, "TDLS cancel channel switch with %pM\n", sta->addr);567 568	/* we only support a single peer for channel switching */569	if (mvm->tdls_cs.peer.sta_id == IWL_MVM_INVALID_STA) {570		IWL_DEBUG_TDLS(mvm, "No ch switch peer - %pM\n", sta->addr);571		goto out;572	}573 574	cur_sta = rcu_dereference_protected(575				mvm->fw_id_to_mac_id[mvm->tdls_cs.peer.sta_id],576				lockdep_is_held(&mvm->mutex));577	/* make sure it's the same peer */578	if (cur_sta != sta)579		goto out;580 581	/*582	 * If we're currently in a switch because of the now canceled peer,583	 * wait a DTIM here to make sure the phy is back on the base channel.584	 * We can't otherwise force it.585	 */586	if (mvm->tdls_cs.cur_sta_id == mvm->tdls_cs.peer.sta_id &&587	    mvm->tdls_cs.state != IWL_MVM_TDLS_SW_IDLE)588		wait_for_phy = true;589 590	mvm->tdls_cs.peer.sta_id = IWL_MVM_INVALID_STA;591	dev_kfree_skb(mvm->tdls_cs.peer.skb);592	mvm->tdls_cs.peer.skb = NULL;593 594out:595	mutex_unlock(&mvm->mutex);596 597	/* make sure the phy is on the base channel */598	if (wait_for_phy)599		msleep(TU_TO_MS(vif->bss_conf.dtim_period *600				vif->bss_conf.beacon_int));601 602	/* flush the channel switch state */603	flush_delayed_work(&mvm->tdls_cs.dwork);604 605	IWL_DEBUG_TDLS(mvm, "TDLS ending channel switch with %pM\n", sta->addr);606}607 608void609iwl_mvm_tdls_recv_channel_switch(struct ieee80211_hw *hw,610				 struct ieee80211_vif *vif,611				 struct ieee80211_tdls_ch_sw_params *params)612{613	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);614	enum iwl_tdls_channel_switch_type type;615	unsigned int delay;616	const char *action_str =617		params->action_code == WLAN_TDLS_CHANNEL_SWITCH_REQUEST ?618		"REQ" : "RESP";619 620	guard(mvm)(mvm);621 622	IWL_DEBUG_TDLS(mvm,623		       "Received TDLS ch switch action %s from %pM status %d\n",624		       action_str, params->sta->addr, params->status);625 626	/*627	 * we got a non-zero status from a peer we were switching to - move to628	 * the idle state and retry again later629	 */630	if (params->action_code == WLAN_TDLS_CHANNEL_SWITCH_RESPONSE &&631	    params->status != 0 &&632	    mvm->tdls_cs.state == IWL_MVM_TDLS_SW_REQ_SENT &&633	    mvm->tdls_cs.cur_sta_id != IWL_MVM_INVALID_STA) {634		struct ieee80211_sta *cur_sta;635 636		/* make sure it's the same peer */637		cur_sta = rcu_dereference_protected(638				mvm->fw_id_to_mac_id[mvm->tdls_cs.cur_sta_id],639				lockdep_is_held(&mvm->mutex));640		if (cur_sta == params->sta) {641			iwl_mvm_tdls_update_cs_state(mvm,642						     IWL_MVM_TDLS_SW_IDLE);643			goto retry;644		}645	}646 647	type = (params->action_code == WLAN_TDLS_CHANNEL_SWITCH_REQUEST) ?648	       TDLS_SEND_CHAN_SW_RESP_AND_MOVE_CH : TDLS_MOVE_CH;649 650	iwl_mvm_tdls_config_channel_switch(mvm, vif, type, params->sta->addr,651					   params->sta->tdls_initiator, 0,652					   params->chandef, params->timestamp,653					   params->switch_time,654					   params->switch_timeout,655					   params->tmpl_skb,656					   params->ch_sw_tm_ie);657 658retry:659	/* register a timeout in case we don't succeed in switching */660	delay = vif->bss_conf.dtim_period * vif->bss_conf.beacon_int *661		1024 / 1000;662	mod_delayed_work(system_wq, &mvm->tdls_cs.dwork,663			 msecs_to_jiffies(delay));664}665