18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * NXP Wireless LAN device driver: 802.11h 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright 2011-2020 NXP 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This software file (the "File") is distributed by NXP 78c2ecf20Sopenharmony_ci * under the terms of the GNU General Public License Version 2, June 1991 88c2ecf20Sopenharmony_ci * (the "License"). You may use, redistribute and/or modify this File in 98c2ecf20Sopenharmony_ci * accordance with the terms and conditions of the License, a copy of which 108c2ecf20Sopenharmony_ci * is available by writing to the Free Software Foundation, Inc., 118c2ecf20Sopenharmony_ci * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the 128c2ecf20Sopenharmony_ci * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 158c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 168c2ecf20Sopenharmony_ci * ARE EXPRESSLY DISCLAIMED. The License provides additional details about 178c2ecf20Sopenharmony_ci * this warranty disclaimer. 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "main.h" 218c2ecf20Sopenharmony_ci#include "fw.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_civoid mwifiex_init_11h_params(struct mwifiex_private *priv) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci priv->state_11h.is_11h_enabled = true; 278c2ecf20Sopenharmony_ci priv->state_11h.is_11h_active = false; 288c2ecf20Sopenharmony_ci} 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ciinline int mwifiex_is_11h_active(struct mwifiex_private *priv) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci return priv->state_11h.is_11h_active; 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci/* This function appends 11h info to a buffer while joining an 358c2ecf20Sopenharmony_ci * infrastructure BSS 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_cistatic void 388c2ecf20Sopenharmony_cimwifiex_11h_process_infra_join(struct mwifiex_private *priv, u8 **buffer, 398c2ecf20Sopenharmony_ci struct mwifiex_bssdescriptor *bss_desc) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci struct mwifiex_ie_types_header *ie_header; 428c2ecf20Sopenharmony_ci struct mwifiex_ie_types_pwr_capability *cap; 438c2ecf20Sopenharmony_ci struct mwifiex_ie_types_local_pwr_constraint *constraint; 448c2ecf20Sopenharmony_ci struct ieee80211_supported_band *sband; 458c2ecf20Sopenharmony_ci u8 radio_type; 468c2ecf20Sopenharmony_ci int i; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci if (!buffer || !(*buffer)) 498c2ecf20Sopenharmony_ci return; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band); 528c2ecf20Sopenharmony_ci sband = priv->wdev.wiphy->bands[radio_type]; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci cap = (struct mwifiex_ie_types_pwr_capability *)*buffer; 558c2ecf20Sopenharmony_ci cap->header.type = cpu_to_le16(WLAN_EID_PWR_CAPABILITY); 568c2ecf20Sopenharmony_ci cap->header.len = cpu_to_le16(2); 578c2ecf20Sopenharmony_ci cap->min_pwr = 0; 588c2ecf20Sopenharmony_ci cap->max_pwr = 0; 598c2ecf20Sopenharmony_ci *buffer += sizeof(*cap); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci constraint = (struct mwifiex_ie_types_local_pwr_constraint *)*buffer; 628c2ecf20Sopenharmony_ci constraint->header.type = cpu_to_le16(WLAN_EID_PWR_CONSTRAINT); 638c2ecf20Sopenharmony_ci constraint->header.len = cpu_to_le16(2); 648c2ecf20Sopenharmony_ci constraint->chan = bss_desc->channel; 658c2ecf20Sopenharmony_ci constraint->constraint = bss_desc->local_constraint; 668c2ecf20Sopenharmony_ci *buffer += sizeof(*constraint); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci ie_header = (struct mwifiex_ie_types_header *)*buffer; 698c2ecf20Sopenharmony_ci ie_header->type = cpu_to_le16(TLV_TYPE_PASSTHROUGH); 708c2ecf20Sopenharmony_ci ie_header->len = cpu_to_le16(2 * sband->n_channels + 2); 718c2ecf20Sopenharmony_ci *buffer += sizeof(*ie_header); 728c2ecf20Sopenharmony_ci *(*buffer)++ = WLAN_EID_SUPPORTED_CHANNELS; 738c2ecf20Sopenharmony_ci *(*buffer)++ = 2 * sband->n_channels; 748c2ecf20Sopenharmony_ci for (i = 0; i < sband->n_channels; i++) { 758c2ecf20Sopenharmony_ci *(*buffer)++ = ieee80211_frequency_to_channel( 768c2ecf20Sopenharmony_ci sband->channels[i].center_freq); 778c2ecf20Sopenharmony_ci *(*buffer)++ = 1; /* one channel in the subband */ 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/* Enable or disable the 11h extensions in the firmware */ 828c2ecf20Sopenharmony_ciint mwifiex_11h_activate(struct mwifiex_private *priv, bool flag) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci u32 enable = flag; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* enable master mode radar detection on AP interface */ 878c2ecf20Sopenharmony_ci if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) && enable) 888c2ecf20Sopenharmony_ci enable |= MWIFIEX_MASTER_RADAR_DET_MASK; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, 918c2ecf20Sopenharmony_ci HostCmd_ACT_GEN_SET, DOT11H_I, &enable, true); 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci/* This functions processes TLV buffer for a pending BSS Join command. 958c2ecf20Sopenharmony_ci * 968c2ecf20Sopenharmony_ci * Activate 11h functionality in the firmware if the spectrum management 978c2ecf20Sopenharmony_ci * capability bit is found in the network we are joining. Also, necessary 988c2ecf20Sopenharmony_ci * TLVs are set based on requested network's 11h capability. 998c2ecf20Sopenharmony_ci */ 1008c2ecf20Sopenharmony_civoid mwifiex_11h_process_join(struct mwifiex_private *priv, u8 **buffer, 1018c2ecf20Sopenharmony_ci struct mwifiex_bssdescriptor *bss_desc) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci if (bss_desc->sensed_11h) { 1048c2ecf20Sopenharmony_ci /* Activate 11h functions in firmware, turns on capability 1058c2ecf20Sopenharmony_ci * bit 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_ci mwifiex_11h_activate(priv, true); 1088c2ecf20Sopenharmony_ci priv->state_11h.is_11h_active = true; 1098c2ecf20Sopenharmony_ci bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_SPECTRUM_MGMT; 1108c2ecf20Sopenharmony_ci mwifiex_11h_process_infra_join(priv, buffer, bss_desc); 1118c2ecf20Sopenharmony_ci } else { 1128c2ecf20Sopenharmony_ci /* Deactivate 11h functions in the firmware */ 1138c2ecf20Sopenharmony_ci mwifiex_11h_activate(priv, false); 1148c2ecf20Sopenharmony_ci priv->state_11h.is_11h_active = false; 1158c2ecf20Sopenharmony_ci bss_desc->cap_info_bitmap &= ~WLAN_CAPABILITY_SPECTRUM_MGMT; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci/* This is DFS CAC work queue function. 1208c2ecf20Sopenharmony_ci * This delayed work emits CAC finished event for cfg80211 if 1218c2ecf20Sopenharmony_ci * CAC was started earlier. 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_civoid mwifiex_dfs_cac_work_queue(struct work_struct *work) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci struct cfg80211_chan_def chandef; 1268c2ecf20Sopenharmony_ci struct delayed_work *delayed_work = to_delayed_work(work); 1278c2ecf20Sopenharmony_ci struct mwifiex_private *priv = 1288c2ecf20Sopenharmony_ci container_of(delayed_work, struct mwifiex_private, 1298c2ecf20Sopenharmony_ci dfs_cac_work); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci chandef = priv->dfs_chandef; 1328c2ecf20Sopenharmony_ci if (priv->wdev.cac_started) { 1338c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, MSG, 1348c2ecf20Sopenharmony_ci "CAC timer finished; No radar detected\n"); 1358c2ecf20Sopenharmony_ci cfg80211_cac_event(priv->netdev, &chandef, 1368c2ecf20Sopenharmony_ci NL80211_RADAR_CAC_FINISHED, 1378c2ecf20Sopenharmony_ci GFP_KERNEL); 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci/* This function prepares channel report request command to FW for 1428c2ecf20Sopenharmony_ci * starting radar detection. 1438c2ecf20Sopenharmony_ci */ 1448c2ecf20Sopenharmony_ciint mwifiex_cmd_issue_chan_report_request(struct mwifiex_private *priv, 1458c2ecf20Sopenharmony_ci struct host_cmd_ds_command *cmd, 1468c2ecf20Sopenharmony_ci void *data_buf) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci struct host_cmd_ds_chan_rpt_req *cr_req = &cmd->params.chan_rpt_req; 1498c2ecf20Sopenharmony_ci struct mwifiex_radar_params *radar_params = (void *)data_buf; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci cmd->command = cpu_to_le16(HostCmd_CMD_CHAN_REPORT_REQUEST); 1528c2ecf20Sopenharmony_ci cmd->size = cpu_to_le16(S_DS_GEN); 1538c2ecf20Sopenharmony_ci le16_unaligned_add_cpu(&cmd->size, 1548c2ecf20Sopenharmony_ci sizeof(struct host_cmd_ds_chan_rpt_req)); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci cr_req->chan_desc.start_freq = cpu_to_le16(MWIFIEX_A_BAND_START_FREQ); 1578c2ecf20Sopenharmony_ci cr_req->chan_desc.chan_num = radar_params->chandef->chan->hw_value; 1588c2ecf20Sopenharmony_ci cr_req->chan_desc.chan_width = radar_params->chandef->width; 1598c2ecf20Sopenharmony_ci cr_req->msec_dwell_time = cpu_to_le32(radar_params->cac_time_ms); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (radar_params->cac_time_ms) 1628c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, MSG, 1638c2ecf20Sopenharmony_ci "11h: issuing DFS Radar check for channel=%d\n", 1648c2ecf20Sopenharmony_ci radar_params->chandef->chan->hw_value); 1658c2ecf20Sopenharmony_ci else 1668c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, MSG, "cancelling CAC\n"); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci return 0; 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ciint mwifiex_stop_radar_detection(struct mwifiex_private *priv, 1728c2ecf20Sopenharmony_ci struct cfg80211_chan_def *chandef) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci struct mwifiex_radar_params radar_params; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci memset(&radar_params, 0, sizeof(struct mwifiex_radar_params)); 1778c2ecf20Sopenharmony_ci radar_params.chandef = chandef; 1788c2ecf20Sopenharmony_ci radar_params.cac_time_ms = 0; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci return mwifiex_send_cmd(priv, HostCmd_CMD_CHAN_REPORT_REQUEST, 1818c2ecf20Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, &radar_params, true); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci/* This function is to abort ongoing CAC upon stopping AP operations 1858c2ecf20Sopenharmony_ci * or during unload. 1868c2ecf20Sopenharmony_ci */ 1878c2ecf20Sopenharmony_civoid mwifiex_abort_cac(struct mwifiex_private *priv) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci if (priv->wdev.cac_started) { 1908c2ecf20Sopenharmony_ci if (mwifiex_stop_radar_detection(priv, &priv->dfs_chandef)) 1918c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 1928c2ecf20Sopenharmony_ci "failed to stop CAC in FW\n"); 1938c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, MSG, 1948c2ecf20Sopenharmony_ci "Aborting delayed work for CAC.\n"); 1958c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&priv->dfs_cac_work); 1968c2ecf20Sopenharmony_ci cfg80211_cac_event(priv->netdev, &priv->dfs_chandef, 1978c2ecf20Sopenharmony_ci NL80211_RADAR_CAC_ABORTED, GFP_KERNEL); 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci/* This function handles channel report event from FW during CAC period. 2028c2ecf20Sopenharmony_ci * If radar is detected during CAC, driver indicates the same to cfg80211 2038c2ecf20Sopenharmony_ci * and also cancels ongoing delayed work. 2048c2ecf20Sopenharmony_ci */ 2058c2ecf20Sopenharmony_ciint mwifiex_11h_handle_chanrpt_ready(struct mwifiex_private *priv, 2068c2ecf20Sopenharmony_ci struct sk_buff *skb) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci struct host_cmd_ds_chan_rpt_event *rpt_event; 2098c2ecf20Sopenharmony_ci struct mwifiex_ie_types_chan_rpt_data *rpt; 2108c2ecf20Sopenharmony_ci u8 *evt_buf; 2118c2ecf20Sopenharmony_ci u16 event_len, tlv_len; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci rpt_event = (void *)(skb->data + sizeof(u32)); 2148c2ecf20Sopenharmony_ci event_len = skb->len - (sizeof(struct host_cmd_ds_chan_rpt_event)+ 2158c2ecf20Sopenharmony_ci sizeof(u32)); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (le32_to_cpu(rpt_event->result) != HostCmd_RESULT_OK) { 2188c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 2198c2ecf20Sopenharmony_ci "Error in channel report event\n"); 2208c2ecf20Sopenharmony_ci return -1; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci evt_buf = (void *)&rpt_event->tlvbuf; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci while (event_len >= sizeof(struct mwifiex_ie_types_header)) { 2268c2ecf20Sopenharmony_ci rpt = (void *)&rpt_event->tlvbuf; 2278c2ecf20Sopenharmony_ci tlv_len = le16_to_cpu(rpt->header.len); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci switch (le16_to_cpu(rpt->header.type)) { 2308c2ecf20Sopenharmony_ci case TLV_TYPE_CHANRPT_11H_BASIC: 2318c2ecf20Sopenharmony_ci if (rpt->map.radar) { 2328c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, MSG, 2338c2ecf20Sopenharmony_ci "RADAR Detected on channel %d!\n", 2348c2ecf20Sopenharmony_ci priv->dfs_chandef.chan->hw_value); 2358c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&priv->dfs_cac_work); 2368c2ecf20Sopenharmony_ci cfg80211_cac_event(priv->netdev, 2378c2ecf20Sopenharmony_ci &priv->dfs_chandef, 2388c2ecf20Sopenharmony_ci NL80211_RADAR_DETECTED, 2398c2ecf20Sopenharmony_ci GFP_KERNEL); 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci break; 2428c2ecf20Sopenharmony_ci default: 2438c2ecf20Sopenharmony_ci break; 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci evt_buf += (tlv_len + sizeof(rpt->header)); 2478c2ecf20Sopenharmony_ci event_len -= (tlv_len + sizeof(rpt->header)); 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci return 0; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci/* Handler for radar detected event from FW.*/ 2548c2ecf20Sopenharmony_ciint mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv, 2558c2ecf20Sopenharmony_ci struct sk_buff *skb) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci struct mwifiex_radar_det_event *rdr_event; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci rdr_event = (void *)(skb->data + sizeof(u32)); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, MSG, 2628c2ecf20Sopenharmony_ci "radar detected; indicating kernel\n"); 2638c2ecf20Sopenharmony_ci if (mwifiex_stop_radar_detection(priv, &priv->dfs_chandef)) 2648c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 2658c2ecf20Sopenharmony_ci "Failed to stop CAC in FW\n"); 2668c2ecf20Sopenharmony_ci cfg80211_radar_event(priv->adapter->wiphy, &priv->dfs_chandef, 2678c2ecf20Sopenharmony_ci GFP_KERNEL); 2688c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, MSG, "regdomain: %d\n", 2698c2ecf20Sopenharmony_ci rdr_event->reg_domain); 2708c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, MSG, "radar detection type: %d\n", 2718c2ecf20Sopenharmony_ci rdr_event->det_type); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci return 0; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci/* This is work queue function for channel switch handling. 2778c2ecf20Sopenharmony_ci * This function takes care of updating new channel definitin to 2788c2ecf20Sopenharmony_ci * bss config structure, restart AP and indicate channel switch success 2798c2ecf20Sopenharmony_ci * to cfg80211. 2808c2ecf20Sopenharmony_ci */ 2818c2ecf20Sopenharmony_civoid mwifiex_dfs_chan_sw_work_queue(struct work_struct *work) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci struct mwifiex_uap_bss_param *bss_cfg; 2848c2ecf20Sopenharmony_ci struct delayed_work *delayed_work = to_delayed_work(work); 2858c2ecf20Sopenharmony_ci struct mwifiex_private *priv = 2868c2ecf20Sopenharmony_ci container_of(delayed_work, struct mwifiex_private, 2878c2ecf20Sopenharmony_ci dfs_chan_sw_work); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci bss_cfg = &priv->bss_cfg; 2908c2ecf20Sopenharmony_ci if (!bss_cfg->beacon_period) { 2918c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 2928c2ecf20Sopenharmony_ci "channel switch: AP already stopped\n"); 2938c2ecf20Sopenharmony_ci return; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci mwifiex_uap_set_channel(priv, bss_cfg, priv->dfs_chandef); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (mwifiex_config_start_uap(priv, bss_cfg)) { 2998c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 3008c2ecf20Sopenharmony_ci "Failed to start AP after channel switch\n"); 3018c2ecf20Sopenharmony_ci return; 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci mwifiex_dbg(priv->adapter, MSG, 3058c2ecf20Sopenharmony_ci "indicating channel switch completion to kernel\n"); 3068c2ecf20Sopenharmony_ci mutex_lock(&priv->wdev.mtx); 3078c2ecf20Sopenharmony_ci cfg80211_ch_switch_notify(priv->netdev, &priv->dfs_chandef); 3088c2ecf20Sopenharmony_ci mutex_unlock(&priv->wdev.mtx); 3098c2ecf20Sopenharmony_ci} 310