diff --git a/core/hdd/src/wlan_hdd_cm_connect.c b/core/hdd/src/wlan_hdd_cm_connect.c index 4075175b69..2bd43f44d1 100644 --- a/core/hdd/src/wlan_hdd_cm_connect.c +++ b/core/hdd/src/wlan_hdd_cm_connect.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -49,6 +49,7 @@ #include #include "wlan_roam_debug.h" #include +#include "wlan_hdd_hostapd.h" bool hdd_cm_is_vdev_associated(struct hdd_adapter *adapter) { @@ -385,6 +386,189 @@ hdd_get_dot11mode_filter(struct hdd_context *hdd_ctx) return ALLOW_ALL; } +/** + * hdd_get_sap_adapter_of_dfs - Get sap adapter on dfs channel + * @hdd_ctx: HDD context + * + * This function is used to get the sap adapter on dfs channel. + * + * Return: pointer to adapter or null + */ +static struct hdd_adapter +*hdd_get_sap_adapter_of_dfs(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_ADAPTER; + qdf_freq_t chan_freq = 0; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (adapter->device_mode != QDF_SAP_MODE) + goto loop_next; + + /* + * sap is not in started state and also not under doing CAC, + * so it is fine to go ahead with sta. + */ + if (!test_bit(SOFTAP_BSS_STARTED, &(adapter)->event_flags) && + (hdd_ctx->dev_dfs_cac_status != DFS_CAC_IN_PROGRESS)) + goto loop_next; + + chan_freq = wlan_get_operation_chan_freq_vdev_id(hdd_ctx->pdev, + adapter->vdev_id); + + if (chan_freq && wlan_reg_is_dfs_for_freq(hdd_ctx->pdev, + chan_freq)) { + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, dbgid); + + return adapter; + } +loop_next: + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + return NULL; +} + +/** + * wlan_hdd_cm_handle_sap_sta_dfs_conc() - to handle SAP STA DFS conc + * @hdd_ctx: hdd_ctx + * @req: connect req + * + * This routine will move SAP from dfs to non-dfs, if sta is coming up. + * + * Return: false if sta-sap conc is not allowed, else return true + */ +static +bool wlan_hdd_cm_handle_sap_sta_dfs_conc(struct hdd_context *hdd_ctx, + struct cfg80211_connect_params *req) +{ + struct hdd_adapter *ap_adapter; + struct hdd_ap_ctx *hdd_ap_ctx; + struct hdd_hostapd_state *hostapd_state; + QDF_STATUS status; + qdf_freq_t ch_freq = 0; + struct scan_filter *scan_filter; + qdf_list_t *list = NULL; + qdf_list_node_t *cur_lst = NULL; + struct scan_cache_node *cur_node = NULL; + + ap_adapter = hdd_get_sap_adapter_of_dfs(hdd_ctx); + /* probably no dfs sap running, no handling required */ + if (!ap_adapter) + return true; + + /* if sap is currently doing CAC then don't allow sta to go further */ + if (hdd_ctx->dev_dfs_cac_status == DFS_CAC_IN_PROGRESS) { + hdd_err("Concurrent SAP is in CAC state, STA is not allowed"); + return false; + } + + /* + * log and return error, if we allow STA to go through, we don't + * know what is going to happen better stop sta connection + */ + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(ap_adapter); + if (!hdd_ap_ctx) { + hdd_err("AP context not found"); + return false; + } + + if (req->channel && req->channel->center_freq) { + ch_freq = req->channel->center_freq; + goto def_chan; + } + /* + * find out by looking in to scan cache where sta is going to + * connect by passing its ssid amd bssid. + */ + scan_filter = qdf_mem_malloc(sizeof(*scan_filter)); + if (!scan_filter) + goto def_chan; + + if (req->bssid) { + scan_filter->num_of_bssid = 1; + qdf_mem_copy(scan_filter->bssid_list[0].bytes, req->bssid, + QDF_MAC_ADDR_SIZE); + } + scan_filter->num_of_ssid = 1; + scan_filter->ssid_list[0].length = + QDF_MIN(req->ssid_len, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(scan_filter->ssid_list[0].ssid, req->ssid, + scan_filter->ssid_list[0].length); + scan_filter->ignore_auth_enc_type = true; + list = ucfg_scan_get_result(hdd_ctx->pdev, scan_filter); + qdf_mem_free(scan_filter); + + if (!list || (list && !qdf_list_size(list))) { + hdd_debug("scan list empty"); + goto purge_list; + } + qdf_list_peek_front(list, &cur_lst); + if (!cur_lst) + goto purge_list; + + cur_node = qdf_container_of(cur_lst, struct scan_cache_node, node); + ch_freq = cur_node->entry->channel.chan_freq; +purge_list: + if (list) + ucfg_scan_purge_results(list); +def_chan: + /* + * If the STA's channel is 2.4 GHz, then set pcl with only 2.4 GHz + * channels for roaming case. + */ + if (WLAN_REG_IS_24GHZ_CH_FREQ(ch_freq)) { + hdd_info("sap is on dfs, new sta conn on 2.4 is allowed"); + return true; + } + + /* + * If channel is 0 or DFS or LTE unsafe then better to call pcl and + * find out the best channel. If channel is non-dfs 5 GHz then + * better move SAP to STA's channel to make scc, so we have room + * for 3port MCC scenario. + */ + if (!ch_freq || wlan_reg_is_dfs_for_freq(hdd_ctx->pdev, ch_freq) || + !policy_mgr_is_safe_channel(hdd_ctx->psoc, ch_freq)) + ch_freq = policy_mgr_get_nondfs_preferred_channel( + hdd_ctx->psoc, PM_SAP_MODE, true); + + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(ap_adapter); + qdf_event_reset(&hostapd_state->qdf_event); + wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc, ap_adapter->vdev_id, + CSA_REASON_STA_CONNECT_DFS_TO_NON_DFS); + + status = wlansap_set_channel_change_with_csa( + WLAN_HDD_GET_SAP_CTX_PTR(ap_adapter), ch_freq, + hdd_ap_ctx->sap_config.ch_width_orig, false); + + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Set channel with CSA IE failed, can't allow STA"); + return false; + } + + /* + * wait here for SAP to finish the channel switch. When channel + * switch happens, SAP sends few beacons with CSA_IE. After + * successfully Transmission of those beacons, it will move its + * state from started to disconnected and move to new channel. + * once it moves to new channel, sap again moves its state + * machine from disconnected to started and set this event. + * wait for 10 secs to finish this. + */ + status = qdf_wait_for_event_completion(&hostapd_state->qdf_event, + 10000); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("wait for qdf_event failed, STA not allowed!!"); + return false; + } + + return true; +} + int wlan_hdd_cm_connect(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_connect_params *req) @@ -427,6 +611,12 @@ int wlan_hdd_cm_connect(struct wiphy *wiphy, hdd_reg_wait_for_country_change(hdd_ctx); + if (policy_mgr_is_hw_dbs_capable(hdd_ctx->psoc) && + !wlan_hdd_cm_handle_sap_sta_dfs_conc(hdd_ctx, req)) { + hdd_err("sap-sta conc will fail, can't allow sta"); + return -EINVAL; + } + qdf_mem_zero(¶ms, sizeof(params)); ucfg_blm_dump_black_list_ap(hdd_ctx->pdev); vdev = hdd_objmgr_get_vdev_by_user(adapter, WLAN_OSIF_CM_ID);