Path: blob/main/sys/contrib/dev/iwlwifi/mvm/tdls.c
48287 views
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause1/*2* Copyright (C) 2014 Intel Mobile Communications GmbH3* Copyright (C) 2017 Intel Deutschland GmbH4* Copyright (C) 2018-2020, 2022-2024 Intel Corporation5*/6#if defined(__FreeBSD__)7#include <linux/delay.h>8#endif9#include <linux/etherdevice.h>10#include "mvm.h"11#include "time-event.h"12#include "iwl-io.h"13#include "iwl-prph.h"1415#define TU_TO_US(x) (x * 1024)16#define TU_TO_MS(x) (TU_TO_US(x) / 1000)1718void iwl_mvm_teardown_tdls_peers(struct iwl_mvm *mvm)19{20struct ieee80211_sta *sta;21struct iwl_mvm_sta *mvmsta;22int i;2324lockdep_assert_held(&mvm->mutex);2526for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) {27sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],28lockdep_is_held(&mvm->mutex));29if (IS_ERR_OR_NULL(sta) || !sta->tdls)30continue;3132mvmsta = iwl_mvm_sta_from_mac80211(sta);33ieee80211_tdls_oper_request(mvmsta->vif, sta->addr,34NL80211_TDLS_TEARDOWN,35WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED,36GFP_KERNEL);37}38}3940int iwl_mvm_tdls_sta_count(struct iwl_mvm *mvm, struct ieee80211_vif *vif)41{42struct ieee80211_sta *sta;43struct iwl_mvm_sta *mvmsta;44int count = 0;45int i;4647lockdep_assert_held(&mvm->mutex);4849for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) {50sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],51lockdep_is_held(&mvm->mutex));52if (IS_ERR_OR_NULL(sta) || !sta->tdls)53continue;5455if (vif) {56mvmsta = iwl_mvm_sta_from_mac80211(sta);57if (mvmsta->vif != vif)58continue;59}6061count++;62}6364return count;65}6667static void iwl_mvm_tdls_config(struct iwl_mvm *mvm, struct ieee80211_vif *vif)68{69struct iwl_rx_packet *pkt;70struct iwl_tdls_config_res *resp;71struct iwl_tdls_config_cmd tdls_cfg_cmd = {};72struct iwl_host_cmd cmd = {73.id = TDLS_CONFIG_CMD,74.flags = CMD_WANT_SKB,75.data = { &tdls_cfg_cmd, },76.len = { sizeof(struct iwl_tdls_config_cmd), },77};78struct ieee80211_sta *sta;79int ret, i, cnt;80struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);8182lockdep_assert_held(&mvm->mutex);8384tdls_cfg_cmd.id_and_color =85cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));86tdls_cfg_cmd.tx_to_ap_tid = IWL_MVM_TDLS_FW_TID;87tdls_cfg_cmd.tx_to_ap_ssn = cpu_to_le16(0); /* not used for now */8889/* for now the Tx cmd is empty and unused */9091/* populate TDLS peer data */92cnt = 0;93for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) {94sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],95lockdep_is_held(&mvm->mutex));96if (IS_ERR_OR_NULL(sta) || !sta->tdls)97continue;9899tdls_cfg_cmd.sta_info[cnt].sta_id = i;100tdls_cfg_cmd.sta_info[cnt].tx_to_peer_tid =101IWL_MVM_TDLS_FW_TID;102tdls_cfg_cmd.sta_info[cnt].tx_to_peer_ssn = cpu_to_le16(0);103tdls_cfg_cmd.sta_info[cnt].is_initiator =104cpu_to_le32(sta->tdls_initiator ? 1 : 0);105106cnt++;107}108109tdls_cfg_cmd.tdls_peer_count = cnt;110IWL_DEBUG_TDLS(mvm, "send TDLS config to FW for %d peers\n", cnt);111112ret = iwl_mvm_send_cmd(mvm, &cmd);113if (WARN_ON_ONCE(ret))114return;115116pkt = cmd.resp_pkt;117118WARN_ON_ONCE(iwl_rx_packet_payload_len(pkt) != sizeof(*resp));119120/* we don't really care about the response at this point */121122iwl_free_resp(&cmd);123}124125void iwl_mvm_recalc_tdls_state(struct iwl_mvm *mvm, struct ieee80211_vif *vif,126bool sta_added)127{128int tdls_sta_cnt = iwl_mvm_tdls_sta_count(mvm, vif);129130/* when the first peer joins, send a power update first */131if (tdls_sta_cnt == 1 && sta_added)132iwl_mvm_power_update_mac(mvm);133134/* Configure the FW with TDLS peer info only if TDLS channel switch135* capability is set.136* TDLS config data is used currently only in TDLS channel switch code.137* Supposed to serve also TDLS buffer station which is not implemneted138* yet in FW*/139if (fw_has_capa(&mvm->fw->ucode_capa,140IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH))141iwl_mvm_tdls_config(mvm, vif);142143/* when the last peer leaves, send a power update last */144if (tdls_sta_cnt == 0 && !sta_added)145iwl_mvm_power_update_mac(mvm);146}147148void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw,149struct ieee80211_vif *vif,150unsigned int link_id)151{152struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);153u32 duration = 2 * vif->bss_conf.dtim_period * vif->bss_conf.beacon_int;154155/* Protect the session to hear the TDLS setup response on the channel */156guard(mvm)(mvm);157if (fw_has_capa(&mvm->fw->ucode_capa,158IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD))159iwl_mvm_schedule_session_protection(mvm, vif, duration,160duration, true, link_id);161else162iwl_mvm_protect_session(mvm, vif, duration,163duration, 100, true);164}165166static const char *167iwl_mvm_tdls_cs_state_str(enum iwl_mvm_tdls_cs_state state)168{169switch (state) {170case IWL_MVM_TDLS_SW_IDLE:171return "IDLE";172case IWL_MVM_TDLS_SW_REQ_SENT:173return "REQ SENT";174case IWL_MVM_TDLS_SW_RESP_RCVD:175return "RESP RECEIVED";176case IWL_MVM_TDLS_SW_REQ_RCVD:177return "REQ RECEIVED";178case IWL_MVM_TDLS_SW_ACTIVE:179return "ACTIVE";180}181182return NULL;183}184185static void iwl_mvm_tdls_update_cs_state(struct iwl_mvm *mvm,186enum iwl_mvm_tdls_cs_state state)187{188if (mvm->tdls_cs.state == state)189return;190191IWL_DEBUG_TDLS(mvm, "TDLS channel switch state: %s -> %s\n",192iwl_mvm_tdls_cs_state_str(mvm->tdls_cs.state),193iwl_mvm_tdls_cs_state_str(state));194mvm->tdls_cs.state = state;195196/* we only send requests to our switching peer - update sent time */197if (state == IWL_MVM_TDLS_SW_REQ_SENT)198mvm->tdls_cs.peer.sent_timestamp = iwl_mvm_get_systime(mvm);199200if (state == IWL_MVM_TDLS_SW_IDLE)201mvm->tdls_cs.cur_sta_id = IWL_INVALID_STA;202}203204void iwl_mvm_rx_tdls_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)205{206struct iwl_rx_packet *pkt = rxb_addr(rxb);207struct iwl_tdls_channel_switch_notif *notif = (void *)pkt->data;208struct ieee80211_sta *sta;209unsigned int delay;210struct iwl_mvm_sta *mvmsta;211struct ieee80211_vif *vif;212u32 sta_id = le32_to_cpu(notif->sta_id);213214lockdep_assert_held(&mvm->mutex);215216/* can fail sometimes */217if (!le32_to_cpu(notif->status)) {218iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_IDLE);219return;220}221222if (WARN_ON(sta_id >= mvm->fw->ucode_capa.num_stations))223return;224225sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],226lockdep_is_held(&mvm->mutex));227/* the station may not be here, but if it is, it must be a TDLS peer */228if (IS_ERR_OR_NULL(sta) || WARN_ON(!sta->tdls))229return;230231mvmsta = iwl_mvm_sta_from_mac80211(sta);232vif = mvmsta->vif;233234/*235* Update state and possibly switch again after this is over (DTIM).236* Also convert TU to msec.237*/238delay = TU_TO_MS(vif->bss_conf.dtim_period * vif->bss_conf.beacon_int);239mod_delayed_work(system_wq, &mvm->tdls_cs.dwork,240msecs_to_jiffies(delay));241242iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_ACTIVE);243}244245static int246iwl_mvm_tdls_check_action(struct iwl_mvm *mvm,247enum iwl_tdls_channel_switch_type type,248const u8 *peer, bool peer_initiator, u32 timestamp)249{250bool same_peer = false;251int ret = 0;252253/* get the existing peer if it's there */254if (mvm->tdls_cs.state != IWL_MVM_TDLS_SW_IDLE &&255mvm->tdls_cs.cur_sta_id != IWL_INVALID_STA) {256struct ieee80211_sta *sta = rcu_dereference_protected(257mvm->fw_id_to_mac_id[mvm->tdls_cs.cur_sta_id],258lockdep_is_held(&mvm->mutex));259if (!IS_ERR_OR_NULL(sta))260same_peer = ether_addr_equal(peer, sta->addr);261}262263switch (mvm->tdls_cs.state) {264case IWL_MVM_TDLS_SW_IDLE:265/*266* might be spurious packet from the peer after the switch is267* already done268*/269if (type == TDLS_MOVE_CH)270ret = -EINVAL;271break;272case IWL_MVM_TDLS_SW_REQ_SENT:273/* only allow requests from the same peer */274if (!same_peer)275ret = -EBUSY;276else if (type == TDLS_SEND_CHAN_SW_RESP_AND_MOVE_CH &&277!peer_initiator)278/*279* We received a ch-switch request while an outgoing280* one is pending. Allow it if the peer is the link281* initiator.282*/283ret = -EBUSY;284else if (type == TDLS_SEND_CHAN_SW_REQ)285/* wait for idle before sending another request */286ret = -EBUSY;287else if (timestamp <= mvm->tdls_cs.peer.sent_timestamp)288/* we got a stale response - ignore it */289ret = -EINVAL;290break;291case IWL_MVM_TDLS_SW_RESP_RCVD:292/*293* we are waiting for the FW to give an "active" notification,294* so ignore requests in the meantime295*/296ret = -EBUSY;297break;298case IWL_MVM_TDLS_SW_REQ_RCVD:299/* as above, allow the link initiator to proceed */300if (type == TDLS_SEND_CHAN_SW_REQ) {301if (!same_peer)302ret = -EBUSY;303else if (peer_initiator) /* they are the initiator */304ret = -EBUSY;305} else if (type == TDLS_MOVE_CH) {306ret = -EINVAL;307}308break;309case IWL_MVM_TDLS_SW_ACTIVE:310/*311* the only valid request when active is a request to return312* to the base channel by the current off-channel peer313*/314if (type != TDLS_MOVE_CH || !same_peer)315ret = -EBUSY;316break;317}318319if (ret)320IWL_DEBUG_TDLS(mvm,321"Invalid TDLS action %d state %d peer %pM same_peer %d initiator %d\n",322type, mvm->tdls_cs.state, peer, same_peer,323peer_initiator);324325return ret;326}327328static int329iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm,330struct ieee80211_vif *vif,331enum iwl_tdls_channel_switch_type type,332const u8 *peer, bool peer_initiator,333u8 oper_class,334struct cfg80211_chan_def *chandef,335u32 timestamp, u16 switch_time,336u16 switch_timeout, struct sk_buff *skb,337u32 ch_sw_tm_ie)338{339struct ieee80211_sta *sta;340struct iwl_mvm_sta *mvmsta;341struct ieee80211_tx_info *info;342struct ieee80211_hdr *hdr;343struct iwl_tdls_channel_switch_cmd cmd = {0};344struct iwl_tdls_channel_switch_cmd_tail *tail =345iwl_mvm_chan_info_cmd_tail(mvm, &cmd.ci);346u16 len = sizeof(cmd) - iwl_mvm_chan_info_padding(mvm);347int ret;348349lockdep_assert_held(&mvm->mutex);350351ret = iwl_mvm_tdls_check_action(mvm, type, peer, peer_initiator,352timestamp);353if (ret)354return ret;355356if (!skb || WARN_ON(skb->len > IWL_TDLS_CH_SW_FRAME_MAX_SIZE)) {357ret = -EINVAL;358goto out;359}360361cmd.switch_type = type;362tail->timing.frame_timestamp = cpu_to_le32(timestamp);363tail->timing.switch_time = cpu_to_le32(switch_time);364tail->timing.switch_timeout = cpu_to_le32(switch_timeout);365366rcu_read_lock();367sta = ieee80211_find_sta(vif, peer);368if (!sta) {369rcu_read_unlock();370ret = -ENOENT;371goto out;372}373mvmsta = iwl_mvm_sta_from_mac80211(sta);374cmd.peer_sta_id = cpu_to_le32(mvmsta->deflink.sta_id);375376if (!chandef) {377if (mvm->tdls_cs.state == IWL_MVM_TDLS_SW_REQ_SENT &&378mvm->tdls_cs.peer.chandef.chan) {379/* actually moving to the channel */380chandef = &mvm->tdls_cs.peer.chandef;381} else if (mvm->tdls_cs.state == IWL_MVM_TDLS_SW_ACTIVE &&382type == TDLS_MOVE_CH) {383/* we need to return to base channel */384struct ieee80211_chanctx_conf *chanctx =385rcu_dereference(vif->bss_conf.chanctx_conf);386387if (WARN_ON_ONCE(!chanctx)) {388rcu_read_unlock();389goto out;390}391392chandef = &chanctx->def;393}394}395396if (chandef)397iwl_mvm_set_chan_info_chandef(mvm, &cmd.ci, chandef);398399/* keep quota calculation simple for now - 50% of DTIM for TDLS */400tail->timing.max_offchan_duration =401cpu_to_le32(TU_TO_US(vif->bss_conf.dtim_period *402vif->bss_conf.beacon_int) / 2);403404/* Switch time is the first element in the switch-timing IE. */405tail->frame.switch_time_offset = cpu_to_le32(ch_sw_tm_ie + 2);406407info = IEEE80211_SKB_CB(skb);408hdr = (void *)skb->data;409if (info->control.hw_key) {410if (info->control.hw_key->cipher != WLAN_CIPHER_SUITE_CCMP) {411rcu_read_unlock();412ret = -EINVAL;413goto out;414}415iwl_mvm_set_tx_cmd_ccmp(info, &tail->frame.tx_cmd);416}417418iwl_mvm_set_tx_cmd(mvm, skb, &tail->frame.tx_cmd, info,419mvmsta->deflink.sta_id);420421iwl_mvm_set_tx_cmd_rate(mvm, &tail->frame.tx_cmd, info, sta,422hdr->frame_control);423rcu_read_unlock();424425memcpy(tail->frame.data, skb->data, skb->len);426427ret = iwl_mvm_send_cmd_pdu(mvm, TDLS_CHANNEL_SWITCH_CMD, 0, len, &cmd);428if (ret) {429IWL_ERR(mvm, "Failed to send TDLS_CHANNEL_SWITCH cmd: %d\n",430ret);431goto out;432}433434/* channel switch has started, update state */435if (type != TDLS_MOVE_CH) {436mvm->tdls_cs.cur_sta_id = mvmsta->deflink.sta_id;437iwl_mvm_tdls_update_cs_state(mvm,438type == TDLS_SEND_CHAN_SW_REQ ?439IWL_MVM_TDLS_SW_REQ_SENT :440IWL_MVM_TDLS_SW_REQ_RCVD);441} else {442iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_RESP_RCVD);443}444445out:446447/* channel switch failed - we are idle */448if (ret)449iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_IDLE);450451return ret;452}453454void iwl_mvm_tdls_ch_switch_work(struct work_struct *work)455{456struct iwl_mvm *mvm;457struct ieee80211_sta *sta;458struct iwl_mvm_sta *mvmsta;459struct ieee80211_vif *vif;460unsigned int delay;461int ret;462463mvm = container_of(work, struct iwl_mvm, tdls_cs.dwork.work);464guard(mvm)(mvm);465466/* called after an active channel switch has finished or timed-out */467iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_IDLE);468469/* station might be gone, in that case do nothing */470if (mvm->tdls_cs.peer.sta_id == IWL_INVALID_STA)471return;472473sta = rcu_dereference_protected(474mvm->fw_id_to_mac_id[mvm->tdls_cs.peer.sta_id],475lockdep_is_held(&mvm->mutex));476/* the station may not be here, but if it is, it must be a TDLS peer */477if (IS_ERR_OR_NULL(sta) || WARN_ON(!sta->tdls))478return;479480mvmsta = iwl_mvm_sta_from_mac80211(sta);481vif = mvmsta->vif;482ret = iwl_mvm_tdls_config_channel_switch(mvm, vif,483TDLS_SEND_CHAN_SW_REQ,484sta->addr,485mvm->tdls_cs.peer.initiator,486mvm->tdls_cs.peer.op_class,487&mvm->tdls_cs.peer.chandef,4880, 0, 0,489mvm->tdls_cs.peer.skb,490mvm->tdls_cs.peer.ch_sw_tm_ie);491if (ret)492IWL_ERR(mvm, "Not sending TDLS channel switch: %d\n", ret);493494/* retry after a DTIM if we failed sending now */495delay = TU_TO_MS(vif->bss_conf.dtim_period * vif->bss_conf.beacon_int);496schedule_delayed_work(&mvm->tdls_cs.dwork, msecs_to_jiffies(delay));497}498499int500iwl_mvm_tdls_channel_switch(struct ieee80211_hw *hw,501struct ieee80211_vif *vif,502struct ieee80211_sta *sta, u8 oper_class,503struct cfg80211_chan_def *chandef,504struct sk_buff *tmpl_skb, u32 ch_sw_tm_ie)505{506struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);507struct iwl_mvm_sta *mvmsta;508unsigned int delay;509int ret;510511guard(mvm)(mvm);512513IWL_DEBUG_TDLS(mvm, "TDLS channel switch with %pM ch %d width %d\n",514sta->addr, chandef->chan->center_freq, chandef->width);515516/* we only support a single peer for channel switching */517if (mvm->tdls_cs.peer.sta_id != IWL_INVALID_STA) {518IWL_DEBUG_TDLS(mvm,519"Existing peer. Can't start switch with %pM\n",520sta->addr);521return -EBUSY;522}523524ret = iwl_mvm_tdls_config_channel_switch(mvm, vif,525TDLS_SEND_CHAN_SW_REQ,526sta->addr, sta->tdls_initiator,527oper_class, chandef, 0, 0, 0,528tmpl_skb, ch_sw_tm_ie);529if (ret)530return ret;531532/*533* Mark the peer as "in tdls switch" for this vif. We only allow a534* single such peer per vif.535*/536mvm->tdls_cs.peer.skb = skb_copy(tmpl_skb, GFP_KERNEL);537if (!mvm->tdls_cs.peer.skb)538return -ENOMEM;539540mvmsta = iwl_mvm_sta_from_mac80211(sta);541mvm->tdls_cs.peer.sta_id = mvmsta->deflink.sta_id;542mvm->tdls_cs.peer.chandef = *chandef;543mvm->tdls_cs.peer.initiator = sta->tdls_initiator;544mvm->tdls_cs.peer.op_class = oper_class;545mvm->tdls_cs.peer.ch_sw_tm_ie = ch_sw_tm_ie;546547/*548* Wait for 2 DTIM periods before attempting the next switch. The next549* switch will be made sooner if the current one completes before that.550*/551delay = 2 * TU_TO_MS(vif->bss_conf.dtim_period *552vif->bss_conf.beacon_int);553mod_delayed_work(system_wq, &mvm->tdls_cs.dwork,554msecs_to_jiffies(delay));555return 0;556}557558void iwl_mvm_tdls_cancel_channel_switch(struct ieee80211_hw *hw,559struct ieee80211_vif *vif,560struct ieee80211_sta *sta)561{562struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);563struct ieee80211_sta *cur_sta;564bool wait_for_phy = false;565566mutex_lock(&mvm->mutex);567568IWL_DEBUG_TDLS(mvm, "TDLS cancel channel switch with %pM\n", sta->addr);569570/* we only support a single peer for channel switching */571if (mvm->tdls_cs.peer.sta_id == IWL_INVALID_STA) {572IWL_DEBUG_TDLS(mvm, "No ch switch peer - %pM\n", sta->addr);573goto out;574}575576cur_sta = rcu_dereference_protected(577mvm->fw_id_to_mac_id[mvm->tdls_cs.peer.sta_id],578lockdep_is_held(&mvm->mutex));579/* make sure it's the same peer */580if (cur_sta != sta)581goto out;582583/*584* If we're currently in a switch because of the now canceled peer,585* wait a DTIM here to make sure the phy is back on the base channel.586* We can't otherwise force it.587*/588if (mvm->tdls_cs.cur_sta_id == mvm->tdls_cs.peer.sta_id &&589mvm->tdls_cs.state != IWL_MVM_TDLS_SW_IDLE)590wait_for_phy = true;591592mvm->tdls_cs.peer.sta_id = IWL_INVALID_STA;593dev_kfree_skb(mvm->tdls_cs.peer.skb);594mvm->tdls_cs.peer.skb = NULL;595596out:597mutex_unlock(&mvm->mutex);598599/* make sure the phy is on the base channel */600if (wait_for_phy)601#if defined(__linux__)602msleep(TU_TO_MS(vif->bss_conf.dtim_period *603#elif defined(__FreeBSD__)604linux_msleep(TU_TO_MS(vif->bss_conf.dtim_period *605#endif606vif->bss_conf.beacon_int));607608/* flush the channel switch state */609flush_delayed_work(&mvm->tdls_cs.dwork);610611IWL_DEBUG_TDLS(mvm, "TDLS ending channel switch with %pM\n", sta->addr);612}613614void615iwl_mvm_tdls_recv_channel_switch(struct ieee80211_hw *hw,616struct ieee80211_vif *vif,617struct ieee80211_tdls_ch_sw_params *params)618{619struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);620enum iwl_tdls_channel_switch_type type;621unsigned int delay;622const char *action_str =623params->action_code == WLAN_TDLS_CHANNEL_SWITCH_REQUEST ?624"REQ" : "RESP";625626guard(mvm)(mvm);627628IWL_DEBUG_TDLS(mvm,629"Received TDLS ch switch action %s from %pM status %d\n",630action_str, params->sta->addr, params->status);631632/*633* we got a non-zero status from a peer we were switching to - move to634* the idle state and retry again later635*/636if (params->action_code == WLAN_TDLS_CHANNEL_SWITCH_RESPONSE &&637params->status != 0 &&638mvm->tdls_cs.state == IWL_MVM_TDLS_SW_REQ_SENT &&639mvm->tdls_cs.cur_sta_id != IWL_INVALID_STA) {640struct ieee80211_sta *cur_sta;641642/* make sure it's the same peer */643cur_sta = rcu_dereference_protected(644mvm->fw_id_to_mac_id[mvm->tdls_cs.cur_sta_id],645lockdep_is_held(&mvm->mutex));646if (cur_sta == params->sta) {647iwl_mvm_tdls_update_cs_state(mvm,648IWL_MVM_TDLS_SW_IDLE);649goto retry;650}651}652653type = (params->action_code == WLAN_TDLS_CHANNEL_SWITCH_REQUEST) ?654TDLS_SEND_CHAN_SW_RESP_AND_MOVE_CH : TDLS_MOVE_CH;655656iwl_mvm_tdls_config_channel_switch(mvm, vif, type, params->sta->addr,657params->sta->tdls_initiator, 0,658params->chandef, params->timestamp,659params->switch_time,660params->switch_timeout,661params->tmpl_skb,662params->ch_sw_tm_ie);663664retry:665/* register a timeout in case we don't succeed in switching */666delay = vif->bss_conf.dtim_period * vif->bss_conf.beacon_int *6671024 / 1000;668mod_delayed_work(system_wq, &mvm->tdls_cs.dwork,669msecs_to_jiffies(delay));670}671672673