qcacld-3.0: Initial snapshot of ihelium wlan driver
qcacld-3.0: Initial snapshot of ihelium wlan driver
to match code-scanned SU Release 5.0.0.139. This is
open-source version of wlan for next Android release.
Change-Id: Icf598ca97da74f84bea607e4e902d1889806f507
diff --git a/core/sme/src/csr/csr_api_scan.c b/core/sme/src/csr/csr_api_scan.c
new file mode 100644
index 0000000..68f0aee
--- /dev/null
+++ b/core/sme/src/csr/csr_api_scan.c
@@ -0,0 +1,6941 @@
+/*
+ * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This file was originally distributed by Qualcomm Atheros, Inc.
+ * under proprietary terms before Copyright ownership was assigned
+ * to the Linux Foundation.
+ */
+
+/** ------------------------------------------------------------------------- *
+ ------------------------------------------------------------------------- *
+
+ \file csr_api_scan.c
+
+ Implementation for the Common Scan interfaces.
+ ========================================================================== */
+
+#include "ani_global.h"
+
+#include "cds_mq.h"
+#include "csr_inside_api.h"
+#include "sme_inside.h"
+#include "sms_debug.h"
+
+#include "csr_support.h"
+
+#include "host_diag_core_log.h"
+#include "host_diag_core_event.h"
+
+#include "cds_reg_service.h"
+#include "wma_types.h"
+#include "cds_utils.h"
+#include "cfg_api.h"
+#include "lim_api.h"
+#include "wma.h"
+
+#include "cds_concurrency.h"
+#include "wlan_hdd_main.h"
+
+#define MIN_CHN_TIME_TO_FIND_GO 100
+#define MAX_CHN_TIME_TO_FIND_GO 100
+#define DIRECT_SSID_LEN 7
+
+/* Purpose of HIDDEN_TIMER
+** When we remove hidden ssid from the profile i.e., forget the SSID via GUI that SSID shouldn't see in the profile
+** For above requirement we used timer limit, logic is explained below
+** Timer value is initialsed to current time when it receives corresponding probe response of hidden SSID (The probe request is
+** received regularly till SSID in the profile. Once it is removed from profile probe request is not sent.) when we receive probe response
+** for broadcast probe request, during update SSID with saved SSID we will diff current time with saved SSID time if it is greater than 1 min
+** then we are not updating with old one
+*/
+
+#define HIDDEN_TIMER (1*60*1000)
+#define CSR_SCAN_RESULT_RSSI_WEIGHT 80 /* must be less than 100, represent the persentage of new RSSI */
+
+#define MAX_ACTIVE_SCAN_FOR_ONE_CHANNEL 140
+#define MIN_ACTIVE_SCAN_FOR_ONE_CHANNEL 120
+
+#define MAX_ACTIVE_SCAN_FOR_ONE_CHANNEL_FASTREASSOC 30
+#define MIN_ACTIVE_SCAN_FOR_ONE_CHANNEL_FASTREASSOC 20
+
+#define PCL_ADVANTAGE 30
+#define PCL_RSSI_THRESHOLD -75
+
+#define CSR_SCAN_IS_OVER_BSS_LIMIT(pMac) \
+ ((pMac)->scan.nBssLimit <= (csr_ll_count(&(pMac)->scan.scanResultList)))
+
+void csr_scan_get_result_timer_handler(void *);
+static void csr_scan_result_cfg_aging_timer_handler(void *pv);
+static void csr_set_default_scan_timing(tpAniSirGlobal pMac, tSirScanType scanType,
+ tCsrScanRequest *pScanRequest);
+#ifdef WLAN_AP_STA_CONCURRENCY
+static void csr_sta_ap_conc_timer_handler(void *);
+#endif
+bool csr_is_supported_channel(tpAniSirGlobal pMac, uint8_t channelId);
+CDF_STATUS csr_scan_channels(tpAniSirGlobal pMac, tSmeCmd *pCommand);
+void csr_set_cfg_valid_channel_list(tpAniSirGlobal pMac, uint8_t *pChannelList,
+ uint8_t NumChannels);
+void csr_save_tx_power_to_cfg(tpAniSirGlobal pMac, tDblLinkList *pList,
+ uint32_t cfgId);
+void csr_set_cfg_country_code(tpAniSirGlobal pMac, uint8_t *countryCode);
+void csr_purge_channel_power(tpAniSirGlobal pMac, tDblLinkList *pChannelList);
+void csr_release_scan_command(tpAniSirGlobal pMac, tSmeCmd *pCommand,
+ eCsrScanStatus scanStatus);
+static bool csr_scan_validate_scan_result(tpAniSirGlobal pMac, uint8_t *pChannels,
+ uint8_t numChn,
+ tSirBssDescription *pBssDesc,
+ tDot11fBeaconIEs **ppIes);
+bool csr_roam_is_valid_channel(tpAniSirGlobal pMac, uint8_t channel);
+void csr_prune_channel_list_for_mode(tpAniSirGlobal pMac,
+ tCsrChannel *pChannelList);
+
+#define CSR_IS_SOCIAL_CHANNEL(channel) \
+ (((channel) == 1) || ((channel) == 6) || ((channel) == 11))
+
+static void csr_release_scan_cmd_pending_list(tpAniSirGlobal pMac)
+{
+ tListElem *pEntry;
+ tSmeCmd *pCommand;
+
+ while ((pEntry =
+ csr_ll_remove_head(&pMac->scan.scanCmdPendingList,
+ LL_ACCESS_LOCK)) != NULL) {
+ pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
+ if (eSmeCsrCommandMask & pCommand->command) {
+ csr_abort_command(pMac, pCommand, true);
+ } else {
+ sms_log(pMac, LOGE, FL("Error: Received command : %d"),
+ pCommand->command);
+ }
+ }
+}
+
+/* pResult is invalid calling this function. */
+void csr_free_scan_result_entry(tpAniSirGlobal pMac, tCsrScanResult *pResult)
+{
+ if (NULL != pResult->Result.pvIes) {
+ cdf_mem_free(pResult->Result.pvIes);
+ }
+ cdf_mem_free(pResult);
+}
+
+static CDF_STATUS csr_ll_scan_purge_result(tpAniSirGlobal pMac,
+ tDblLinkList *pList)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tListElem *pEntry;
+ tCsrScanResult *pBssDesc;
+
+ csr_ll_lock(pList);
+
+ while ((pEntry = csr_ll_remove_head(pList, LL_ACCESS_NOLOCK)) != NULL) {
+ pBssDesc = GET_BASE_ADDR(pEntry, tCsrScanResult, Link);
+ csr_free_scan_result_entry(pMac, pBssDesc);
+ }
+
+ csr_ll_unlock(pList);
+
+ return status;
+}
+
+CDF_STATUS csr_scan_open(tpAniSirGlobal mac_ctx)
+{
+ CDF_STATUS status;
+
+ csr_ll_open(mac_ctx->hHdd, &mac_ctx->scan.scanResultList);
+ csr_ll_open(mac_ctx->hHdd, &mac_ctx->scan.tempScanResults);
+ csr_ll_open(mac_ctx->hHdd, &mac_ctx->scan.channelPowerInfoList24);
+ csr_ll_open(mac_ctx->hHdd, &mac_ctx->scan.channelPowerInfoList5G);
+#ifdef WLAN_AP_STA_CONCURRENCY
+ csr_ll_open(mac_ctx->hHdd, &mac_ctx->scan.scanCmdPendingList);
+#endif
+ mac_ctx->scan.fFullScanIssued = false;
+ mac_ctx->scan.nBssLimit = CSR_MAX_BSS_SUPPORT;
+#ifdef WLAN_AP_STA_CONCURRENCY
+ status = cdf_mc_timer_init(&mac_ctx->scan.hTimerStaApConcTimer,
+ CDF_TIMER_TYPE_SW,
+ csr_sta_ap_conc_timer_handler,
+ mac_ctx);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(mac_ctx, LOGE,
+ FL("Mem Alloc failed for hTimerStaApConcTimer timer"));
+ return status;
+ }
+#endif
+ status = cdf_mc_timer_init(&mac_ctx->scan.hTimerResultCfgAging,
+ CDF_TIMER_TYPE_SW,
+ csr_scan_result_cfg_aging_timer_handler,
+ mac_ctx);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ sms_log(mac_ctx, LOGE,
+ FL("Mem Alloc failed for CFG ResultAging timer"));
+
+ return status;
+}
+
+CDF_STATUS csr_scan_close(tpAniSirGlobal pMac)
+{
+ csr_ll_scan_purge_result(pMac, &pMac->scan.tempScanResults);
+ csr_ll_scan_purge_result(pMac, &pMac->scan.scanResultList);
+#ifdef WLAN_AP_STA_CONCURRENCY
+ csr_release_scan_cmd_pending_list(pMac);
+#endif
+ csr_ll_close(&pMac->scan.scanResultList);
+ csr_ll_close(&pMac->scan.tempScanResults);
+#ifdef WLAN_AP_STA_CONCURRENCY
+ csr_ll_close(&pMac->scan.scanCmdPendingList);
+#endif
+ csr_purge_channel_power(pMac, &pMac->scan.channelPowerInfoList24);
+ csr_purge_channel_power(pMac, &pMac->scan.channelPowerInfoList5G);
+ csr_ll_close(&pMac->scan.channelPowerInfoList24);
+ csr_ll_close(&pMac->scan.channelPowerInfoList5G);
+ csr_scan_disable(pMac);
+ cdf_mc_timer_destroy(&pMac->scan.hTimerResultCfgAging);
+#ifdef WLAN_AP_STA_CONCURRENCY
+ cdf_mc_timer_destroy(&pMac->scan.hTimerStaApConcTimer);
+#endif
+ return CDF_STATUS_SUCCESS;
+}
+
+CDF_STATUS csr_scan_enable(tpAniSirGlobal pMac)
+{
+
+ pMac->scan.fScanEnable = true;
+
+ return CDF_STATUS_SUCCESS;
+}
+
+CDF_STATUS csr_scan_disable(tpAniSirGlobal pMac)
+{
+
+ csr_scan_stop_timers(pMac);
+ pMac->scan.fScanEnable = false;
+
+ return CDF_STATUS_SUCCESS;
+}
+
+/* Set scan timing parameters according to state of other driver sessions */
+/* No validation of the parameters is performed. */
+static void csr_set_default_scan_timing(tpAniSirGlobal pMac, tSirScanType scanType,
+ tCsrScanRequest *pScanRequest)
+{
+#ifdef WLAN_AP_STA_CONCURRENCY
+ if (csr_is_any_session_connected(pMac)) {
+ /* Reset passive scan time as per ini parameter. */
+ cfg_set_int(pMac, WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME,
+ pMac->roam.configParam.nPassiveMaxChnTimeConc);
+ /* If multi-session, use the appropriate default scan times */
+ if (scanType == eSIR_ACTIVE_SCAN) {
+ pScanRequest->maxChnTime =
+ pMac->roam.configParam.nActiveMaxChnTimeConc;
+ pScanRequest->minChnTime =
+ pMac->roam.configParam.nActiveMinChnTimeConc;
+ } else {
+ pScanRequest->maxChnTime =
+ pMac->roam.configParam.nPassiveMaxChnTimeConc;
+ pScanRequest->minChnTime =
+ pMac->roam.configParam.nPassiveMinChnTimeConc;
+ }
+ pScanRequest->restTime = pMac->roam.configParam.nRestTimeConc;
+
+ /* Return so that fields set above will not be overwritten. */
+ return;
+ }
+#endif
+
+ /* This portion of the code executed if multi-session not supported */
+ /* (WLAN_AP_STA_CONCURRENCY not defined) or no multi-session. */
+ /* Use the "regular" (non-concurrency) default scan timing. */
+ cfg_set_int(pMac, WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME,
+ pMac->roam.configParam.nPassiveMaxChnTime);
+ if (pScanRequest->scanType == eSIR_ACTIVE_SCAN) {
+ pScanRequest->maxChnTime =
+ pMac->roam.configParam.nActiveMaxChnTime;
+ pScanRequest->minChnTime =
+ pMac->roam.configParam.nActiveMinChnTime;
+ } else {
+ pScanRequest->maxChnTime =
+ pMac->roam.configParam.nPassiveMaxChnTime;
+ pScanRequest->minChnTime =
+ pMac->roam.configParam.nPassiveMinChnTime;
+ }
+#ifdef WLAN_AP_STA_CONCURRENCY
+ /* No rest time if no sessions are connected. */
+ pScanRequest->restTime = 0;
+#endif
+}
+
+/**
+ * csr_scan_2g_only_request() - This function will update the scan request with
+ * only 2.4GHz valid channel list.
+ * @mac_ctx: Pointer to Global MAC structure
+ * @scan_cmd scan cmd
+ * @scan_req scan req
+ *
+ * This function will update the scan request with only 2.4GHz valid channel
+ * list.
+ *
+ * @Return: status of operation
+ */
+static CDF_STATUS
+csr_scan_2g_only_request(tpAniSirGlobal mac_ctx,
+ tSmeCmd *scan_cmd,
+ tCsrScanRequest *scan_req)
+{
+ uint8_t idx, lst_sz = 0;
+
+ CDF_ASSERT(scan_cmd && scan_req);
+ /* To silence the KW tool null check is added */
+ if ((scan_cmd == NULL) || (scan_req == NULL)) {
+ sms_log(mac_ctx, LOGE,
+ FL(" Scan Cmd or Scan Request is NULL "));
+ return CDF_STATUS_E_INVAL;
+ }
+
+ if (eCSR_SCAN_REQUEST_FULL_SCAN != scan_req->requestType)
+ return CDF_STATUS_SUCCESS;
+
+ sms_log(mac_ctx, LOG1,
+ FL("Scanning only 2G Channels during first scan"));
+
+ /* Contsruct valid Supported 2.4 GHz Channel List */
+ if (NULL == scan_req->ChannelInfo.ChannelList) {
+ scan_req->ChannelInfo.ChannelList =
+ cdf_mem_malloc(NUM_24GHZ_CHANNELS);
+ if (NULL == scan_req->ChannelInfo.ChannelList) {
+ sms_log(mac_ctx, LOGE, FL("Memory allocation failed."));
+ return CDF_STATUS_E_NOMEM;
+ }
+ for (idx = 1; idx <= NUM_24GHZ_CHANNELS; idx++) {
+ if (csr_is_supported_channel(mac_ctx, idx)) {
+ scan_req->ChannelInfo.ChannelList[lst_sz] = idx;
+ lst_sz++;
+ }
+ }
+ } else {
+ for (idx = 0;
+ idx < scan_req->ChannelInfo.numOfChannels;
+ idx++) {
+ if (scan_req->ChannelInfo.ChannelList[idx] <=
+ CDS_24_GHZ_CHANNEL_14
+ && csr_is_supported_channel(mac_ctx,
+ scan_req->ChannelInfo.ChannelList[idx])) {
+ scan_req->ChannelInfo.ChannelList[lst_sz] =
+ scan_req->ChannelInfo.ChannelList[idx];
+ lst_sz++;
+ }
+ }
+ }
+ scan_req->ChannelInfo.numOfChannels = lst_sz;
+ return CDF_STATUS_SUCCESS;
+}
+
+static void
+csr_set_scan_reason(tSmeCmd *scan_cmd, eCsrRequestType req_type)
+{
+ switch (req_type) {
+ case eCSR_SCAN_REQUEST_11D_SCAN:
+ scan_cmd->u.scanCmd.reason = eCsrScan11d1;
+ break;
+#ifdef SOFTAP_CHANNEL_RANGE
+ case eCSR_SCAN_SOFTAP_CHANNEL_RANGE:
+#endif
+ case eCSR_SCAN_REQUEST_FULL_SCAN:
+ case eCSR_SCAN_P2P_DISCOVERY:
+ scan_cmd->u.scanCmd.reason = eCsrScanUserRequest;
+ break;
+ case eCSR_SCAN_HO_PROBE_SCAN:
+ scan_cmd->u.scanCmd.reason = eCsrScanProbeBss;
+ break;
+ case eCSR_SCAN_P2P_FIND_PEER:
+ scan_cmd->u.scanCmd.reason = eCsrScanP2PFindPeer;
+ break;
+ default:
+ break;
+ }
+}
+
+static CDF_STATUS
+csr_issue_11d_scan(tpAniSirGlobal mac_ctx, tSmeCmd *scan_cmd,
+ tCsrScanRequest *scan_req, uint16_t session_id)
+{
+ CDF_STATUS status;
+ tSmeCmd *scan_11d_cmd = NULL;
+ tCsrScanRequest tmp_rq;
+ tCsrChannelInfo *pChnInfo = &tmp_rq.ChannelInfo;
+ uint32_t numChn = mac_ctx->scan.base_channels.numChannels;
+ tCsrRoamSession *csr_session = CSR_GET_SESSION(mac_ctx, session_id);
+
+ if (csr_session == NULL) {
+ sms_log(mac_ctx, LOGE, FL("session %d not found"),
+ session_id);
+ CDF_ASSERT(0);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ if (!(((false == mac_ctx->first_scan_done)
+ && (eCSR_SCAN_REQUEST_11D_SCAN != scan_req->requestType))
+#ifdef SOFTAP_CHANNEL_RANGE
+ && (eCSR_SCAN_SOFTAP_CHANNEL_RANGE != scan_req->requestType)
+#endif
+ && (false == mac_ctx->scan.fEnableBypass11d)))
+ return CDF_STATUS_SUCCESS;
+
+ cdf_mem_set(&tmp_rq, sizeof(tCsrScanRequest), 0);
+ scan_11d_cmd = csr_get_command_buffer(mac_ctx);
+ if (!scan_11d_cmd) {
+ sms_log(mac_ctx, LOGE, FL("scan_11d_cmd failed"));
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ cdf_mem_set(&scan_11d_cmd->u.scanCmd, sizeof(tScanCmd), 0);
+ pChnInfo->ChannelList = cdf_mem_malloc(numChn);
+ if (NULL == pChnInfo->ChannelList) {
+ sms_log(mac_ctx, LOGE, FL("Failed to allocate memory"));
+ return CDF_STATUS_E_NOMEM;
+ }
+ cdf_mem_copy(pChnInfo->ChannelList,
+ mac_ctx->scan.base_channels.channelList, numChn);
+
+ pChnInfo->numOfChannels = (uint8_t) numChn;
+ scan_11d_cmd->command = eSmeCommandScan;
+ scan_11d_cmd->u.scanCmd.callback = mac_ctx->scan.callback11dScanDone;
+ scan_11d_cmd->u.scanCmd.pContext = NULL;
+ wma_get_scan_id(&scan_11d_cmd->u.scanCmd.scanID);
+ tmp_rq.BSSType = eCSR_BSS_TYPE_ANY;
+ tmp_rq.scan_id = scan_11d_cmd->u.scanCmd.scanID;
+
+ status = cdf_mc_timer_init(&scan_cmd->u.scanCmd.csr_scan_timer,
+ CDF_TIMER_TYPE_SW,
+ csr_scan_active_list_timeout_handle, &scan_11d_cmd);
+
+ if (csr_is11d_supported(mac_ctx)) {
+ tmp_rq.bcnRptReqScan = scan_req->bcnRptReqScan;
+ if (scan_req->bcnRptReqScan)
+ tmp_rq.scanType = scan_req->scanType ?
+ eSIR_PASSIVE_SCAN : scan_req->scanType;
+ else
+ tmp_rq.scanType = eSIR_PASSIVE_SCAN;
+ tmp_rq.requestType = eCSR_SCAN_REQUEST_11D_SCAN;
+ scan_11d_cmd->u.scanCmd.reason = eCsrScan11d1;
+ tmp_rq.maxChnTime =
+ mac_ctx->roam.configParam.nPassiveMaxChnTime;
+ tmp_rq.minChnTime =
+ mac_ctx->roam.configParam.nPassiveMinChnTime;
+ } else {
+ tmp_rq.bcnRptReqScan = scan_req->bcnRptReqScan;
+ if (scan_req->bcnRptReqScan)
+ tmp_rq.scanType = scan_req->scanType;
+ else
+ tmp_rq.scanType = eSIR_ACTIVE_SCAN;
+ tmp_rq.requestType = scan_req->requestType;
+ scan_11d_cmd->u.scanCmd.reason = scan_cmd->u.scanCmd.reason;
+ tmp_rq.maxChnTime = mac_ctx->roam.configParam.nActiveMaxChnTime;
+ tmp_rq.minChnTime = mac_ctx->roam.configParam.nActiveMinChnTime;
+ }
+ if (mac_ctx->roam.configParam.nInitialDwellTime) {
+ tmp_rq.maxChnTime = mac_ctx->roam.configParam.nInitialDwellTime;
+ sms_log(mac_ctx, LOG1, FL("11d scan, updating dwell time for first scan %u"),
+ tmp_rq.maxChnTime);
+ }
+
+ status = csr_scan_copy_request(mac_ctx,
+ &scan_11d_cmd->u.scanCmd.u.scanRequest, &tmp_rq);
+ /* Free the channel list */
+ cdf_mem_free(pChnInfo->ChannelList);
+ pChnInfo->ChannelList = NULL;
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(mac_ctx, LOGE, FL("csr_scan_copy_request failed"));
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ mac_ctx->scan.scanProfile.numOfChannels =
+ scan_11d_cmd->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels;
+
+
+ status = csr_queue_sme_command(mac_ctx, scan_11d_cmd, false);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(mac_ctx, LOGE, FL("Failed to send message status = %d"),
+ status);
+ return CDF_STATUS_E_FAILURE;
+ }
+ return CDF_STATUS_SUCCESS;
+}
+
+CDF_STATUS csr_scan_request(tpAniSirGlobal pMac, uint16_t sessionId,
+ tCsrScanRequest *scan_req,
+ csr_scan_completeCallback callback, void *pContext)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ tSmeCmd *scan_cmd = NULL;
+ tCsrScanRequest *pTempScanReq = NULL;
+ tCsrConfig *cfg_prm = &pMac->roam.configParam;
+
+ if (scan_req == NULL) {
+ sms_log(pMac, LOGE, FL("scan_req is NULL"));
+ CDF_ASSERT(0);
+ return status;
+ }
+
+ /*
+ * During group formation, the P2P client scans for GO with the specific
+ * SSID. There will be chances of GO switching to other channels because
+ * of scan or to STA channel in case of STA+GO MCC scenario. So to
+ * increase the possibility of client to find the GO, the dwell time of
+ * scan is increased to 100ms.
+ * If the scan request is for specific SSId the length of SSID will be
+ * greater than 7 as SSID for p2p search contains "DIRECT-")
+ */
+ if (scan_req->p2pSearch
+ && scan_req->SSIDs.numOfSSIDs
+ && (NULL != scan_req->SSIDs.SSIDList)
+ && (scan_req->SSIDs.SSIDList->SSID.length > DIRECT_SSID_LEN)) {
+ sms_log(pMac, LOG1, FL("P2P: Increasing the min and max Dwell time to %d for specific SSID scan %.*s"),
+ MAX_CHN_TIME_TO_FIND_GO,
+ scan_req->SSIDs.SSIDList->SSID.length,
+ scan_req->SSIDs.SSIDList->SSID.ssId);
+ scan_req->maxChnTime = MAX_CHN_TIME_TO_FIND_GO;
+ scan_req->minChnTime = MIN_CHN_TIME_TO_FIND_GO;
+ }
+
+ if (!pMac->scan.fScanEnable) {
+ sms_log(pMac, LOGE, FL("SId: %d Scanning not enabled Scan type=%u, numOfSSIDs=%d P2P search=%d"),
+ sessionId, scan_req->requestType,
+ scan_req->SSIDs.numOfSSIDs,
+ scan_req->p2pSearch);
+ goto release_cmd;
+ }
+
+ scan_cmd = csr_get_command_buffer(pMac);
+ if (!scan_cmd) {
+ sms_log(pMac, LOGE, FL("scan_cmd is NULL"));
+ goto release_cmd;
+ }
+
+ cdf_mem_set(&scan_cmd->u.scanCmd, sizeof(tScanCmd), 0);
+ scan_cmd->command = eSmeCommandScan;
+ scan_cmd->sessionId = sessionId;
+ if (scan_cmd->sessionId >= CSR_ROAM_SESSION_MAX)
+ sms_log(pMac, LOGE, FL("Invalid Sme SessionID: %d"), sessionId);
+ scan_cmd->u.scanCmd.callback = callback;
+ scan_cmd->u.scanCmd.pContext = pContext;
+ csr_set_scan_reason(scan_cmd, scan_req->requestType);
+ if (scan_req->minChnTime == 0 && scan_req->maxChnTime == 0) {
+ /* The caller doesn't set the time correctly. Set it here */
+ csr_set_default_scan_timing(pMac, scan_req->scanType, scan_req);
+ sms_log(pMac, LOG1,
+ FL("Setting default min %d and max %d ChnTime"),
+ scan_req->minChnTime, scan_req->maxChnTime);
+ }
+#ifdef WLAN_AP_STA_CONCURRENCY
+ /* Need to set restTime only if at least one session is connected */
+ if (scan_req->restTime == 0 && csr_is_any_session_connected(pMac)) {
+ scan_req->restTime = cfg_prm->nRestTimeConc;
+ if (scan_req->scanType == eSIR_ACTIVE_SCAN) {
+ scan_req->maxChnTime = cfg_prm->nActiveMaxChnTimeConc;
+ scan_req->minChnTime = cfg_prm->nActiveMinChnTimeConc;
+ } else {
+ scan_req->maxChnTime = cfg_prm->nPassiveMaxChnTimeConc;
+ scan_req->minChnTime = cfg_prm->nPassiveMinChnTimeConc;
+ }
+ }
+#endif
+ /* Increase dwell time in case P2P Search and Miracast is not present */
+ if (scan_req->p2pSearch && scan_req->ChannelInfo.numOfChannels
+ == P2P_SOCIAL_CHANNELS && (!(pMac->sme.miracast_value))) {
+ scan_req->maxChnTime += P2P_SEARCH_DWELL_TIME_INCREASE;
+ }
+ scan_cmd->u.scanCmd.scanID = scan_req->scan_id;
+ /*
+ * If it is the first scan request from HDD, CSR checks if it is for 11d
+ * If it is not, CSR will save the scan request in the pending cmd queue
+ * & issue an 11d scan request to PE.
+ */
+ status = csr_issue_11d_scan(pMac, scan_cmd, scan_req, sessionId);
+ if (status != CDF_STATUS_SUCCESS)
+ goto release_cmd;
+
+ /*
+ * Scan only 2G Channels if set in ini file. This is mainly to reduce
+ * the First Scan duration once we turn on Wifi
+ */
+ if (pMac->scan.fFirstScanOnly2GChnl
+ && false == pMac->first_scan_done) {
+ csr_scan_2g_only_request(pMac, scan_cmd, scan_req);
+ pMac->first_scan_done = true;
+ }
+
+
+ if (cfg_prm->nInitialDwellTime) {
+ scan_req->maxChnTime = cfg_prm->nInitialDwellTime;
+ cfg_prm->nInitialDwellTime = 0;
+ sms_log(pMac, LOG1, FL("updating dwell time for first scan %u"),
+ scan_req->maxChnTime);
+ }
+
+ status = csr_scan_copy_request(pMac, &scan_cmd->u.scanCmd.u.scanRequest,
+ scan_req);
+ /*
+ * Reset the variable after the first scan is queued after loading the
+ * driver. The purpose of this parameter is that DFS channels are
+ * skipped during the first scan after loading the driver. The above API
+ * builds the target scan request in which this variable is used.
+ */
+ cfg_prm->initial_scan_no_dfs_chnl = 0;
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ FL("fail to copy request status = %d"), status);
+ goto release_cmd;
+ }
+
+ pTempScanReq = &scan_cmd->u.scanCmd.u.scanRequest;
+ pMac->scan.scanProfile.numOfChannels =
+ pTempScanReq->ChannelInfo.numOfChannels;
+ status = cdf_mc_timer_init(&scan_cmd->u.scanCmd.csr_scan_timer,
+ CDF_TIMER_TYPE_SW,
+ csr_scan_active_list_timeout_handle, scan_cmd);
+ sms_log(pMac, LOG1,
+ FL("SId=%d scanId=%d Scan reason=%u numSSIDs=%d numChan=%d P2P search=%d minCT=%d maxCT=%d uIEFieldLen=%d"),
+ sessionId, scan_cmd->u.scanCmd.scanID,
+ scan_cmd->u.scanCmd.reason, pTempScanReq->SSIDs.numOfSSIDs,
+ pTempScanReq->ChannelInfo.numOfChannels,
+ pTempScanReq->p2pSearch, pTempScanReq->minChnTime,
+ pTempScanReq->maxChnTime, pTempScanReq->uIEFieldLen);
+
+ status = csr_queue_sme_command(pMac, scan_cmd, false);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ FL("fail to send message status = %d"), status);
+ }
+
+release_cmd:
+ if (!CDF_IS_STATUS_SUCCESS(status) && scan_cmd) {
+ sms_log(pMac, LOGE, FL(" SId: %d Failed with status=%d"
+ " Scan reason=%u numOfSSIDs=%d"
+ " P2P search=%d scanId=%d"),
+ sessionId, status, scan_cmd->u.scanCmd.reason,
+ scan_req->SSIDs.numOfSSIDs, scan_req->p2pSearch,
+ scan_cmd->u.scanCmd.scanID);
+ csr_release_command_scan(pMac, scan_cmd);
+ }
+
+ return status;
+}
+
+CDF_STATUS csr_issue_roam_after_lostlink_scan(tpAniSirGlobal pMac,
+ uint32_t sessionId,
+ eCsrRoamReason reason)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ tScanResultHandle hBSSList = NULL;
+ tCsrScanResultFilter *pScanFilter = NULL;
+ uint32_t roamId = 0;
+ tCsrRoamProfile *pProfile = NULL;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL("session %d not found"), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ sms_log(pMac, LOG1, FL("Entry"));
+ if (pSession->fCancelRoaming) {
+ sms_log(pMac, LOGW, FL("lost link roaming canceled"));
+ status = CDF_STATUS_SUCCESS;
+ goto free_filter;
+ }
+ /* Here is the profile we need to connect to */
+ pScanFilter = cdf_mem_malloc(sizeof(tCsrScanResultFilter));
+ if (NULL == pScanFilter) {
+ status = CDF_STATUS_E_NOMEM;
+ goto free_filter;
+ }
+ cdf_mem_set(pScanFilter, sizeof(tCsrScanResultFilter), 0);
+ if (NULL == pSession->pCurRoamProfile) {
+ pScanFilter->EncryptionType.numEntries = 1;
+ pScanFilter->EncryptionType.encryptionType[0] =
+ eCSR_ENCRYPT_TYPE_NONE;
+ } else {
+ /*
+ * We have to make a copy of pCurRoamProfile because it will
+ * be free inside csr_roam_issue_connect
+ */
+ pProfile = cdf_mem_malloc(sizeof(tCsrRoamProfile));
+ if (NULL == pProfile) {
+ status = CDF_STATUS_E_NOMEM;
+ goto free_filter;
+ }
+ cdf_mem_set(pProfile, sizeof(tCsrRoamProfile), 0);
+ status = csr_roam_copy_profile(pMac, pProfile,
+ pSession->pCurRoamProfile);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ goto free_filter;
+ status = csr_roam_prepare_filter_from_profile(pMac, pProfile,
+ pScanFilter);
+ } /* We have a profile */
+ roamId = GET_NEXT_ROAM_ID(&pMac->roam);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ goto free_filter;
+
+ status = csr_scan_get_result(pMac, pScanFilter, &hBSSList);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ goto free_filter;
+
+ if (eCsrLostLink1 == reason) {
+ /* if possible put the last connected BSS in beginning */
+ csr_move_bss_to_head_from_bssid(pMac,
+ &pSession->connectedProfile.bssid, hBSSList);
+ }
+ status = csr_roam_issue_connect(pMac, sessionId, pProfile, hBSSList,
+ reason, roamId, true, true);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ csr_scan_result_purge(pMac, hBSSList);
+ }
+
+free_filter:
+ if (pScanFilter) {
+ /* we need to free memory for filter if profile exists */
+ csr_free_scan_filter(pMac, pScanFilter);
+ cdf_mem_free(pScanFilter);
+ }
+ if (NULL != pProfile) {
+ csr_release_profile(pMac, pProfile);
+ cdf_mem_free(pProfile);
+ }
+ return status;
+}
+
+CDF_STATUS csr_scan_handle_failed_lostlink1(tpAniSirGlobal pMac,
+ uint32_t sessionId)
+{
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL("session %d not found"), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+ sms_log(pMac, LOGW, "Lost link scan 1 failed");
+ if (pSession->fCancelRoaming)
+ return CDF_STATUS_E_FAILURE;
+ if (!pSession->pCurRoamProfile)
+ return csr_scan_request_lost_link3(pMac, sessionId);
+ /*
+ * We fail lostlink1 but there may be other BSS in the cached result
+ * fit the profile. Give it a try first
+ */
+ if (pSession->pCurRoamProfile->SSIDs.numOfSSIDs == 0 ||
+ pSession->pCurRoamProfile->SSIDs.numOfSSIDs > 1)
+ /* try lostlink scan2 */
+ return csr_scan_request_lost_link2(pMac, sessionId);
+ if (!pSession->pCurRoamProfile->ChannelInfo.ChannelList
+ || pSession->pCurRoamProfile->ChannelInfo.ChannelList[0] == 0) {
+ /* go straight to lostlink scan3 */
+ return csr_scan_request_lost_link3(pMac, sessionId);
+ }
+ return CDF_STATUS_SUCCESS;
+}
+
+CDF_STATUS csr_scan_handle_failed_lostlink2(tpAniSirGlobal pMac,
+ uint32_t sessionId)
+{
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL("session %d not found"), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ sms_log(pMac, LOGW, "Lost link scan 2 failed");
+ if (pSession->fCancelRoaming)
+ return CDF_STATUS_E_FAILURE;
+
+ if (!pSession->pCurRoamProfile
+ || !pSession->pCurRoamProfile->ChannelInfo.ChannelList
+ || pSession->pCurRoamProfile->ChannelInfo.ChannelList[0] == 0) {
+ /* try lostlink scan3 */
+ return csr_scan_request_lost_link3(pMac, sessionId);
+ }
+ return CDF_STATUS_E_FAILURE;
+}
+
+CDF_STATUS csr_scan_handle_failed_lostlink3(tpAniSirGlobal pMac,
+ uint32_t sessionId)
+{
+ sms_log(pMac, LOGW, "Lost link scan 3 failed");
+ return CDF_STATUS_SUCCESS;
+}
+
+static CDF_STATUS
+csr_update_lost_link1_cmd(tpAniSirGlobal mac_ctx, tSmeCmd *cmd,
+ tCsrRoamSession *pSession, uint32_t session_id)
+{
+ uint8_t i, num_ch = 0;
+ tScanResultHandle bss_lst = NULL;
+ tCsrScanResultInfo *scan_result = NULL;
+ tCsrScanResultFilter *scan_filter = NULL;
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tCsrSSIDs *ssid_list = &cmd->u.scanCmd.u.scanRequest.SSIDs;
+ tCsrChannelInfo *ch_info = &cmd->u.scanCmd.u.scanRequest.ChannelInfo;
+
+ cmd->command = eSmeCommandScan;
+ cmd->sessionId = (uint8_t) session_id;
+ cmd->u.scanCmd.reason = eCsrScanLostLink1;
+ cmd->u.scanCmd.callback = NULL;
+ cmd->u.scanCmd.pContext = NULL;
+ cmd->u.scanCmd.u.scanRequest.maxChnTime =
+ mac_ctx->roam.configParam.nActiveMaxChnTime;
+ cmd->u.scanCmd.u.scanRequest.minChnTime =
+ mac_ctx->roam.configParam.nActiveMinChnTime;
+ cmd->u.scanCmd.u.scanRequest.scanType = eSIR_ACTIVE_SCAN;
+ wma_get_scan_id(&cmd->u.scanCmd.scanID);
+ status = cdf_mc_timer_init(&cmd->u.scanCmd.csr_scan_timer,
+ CDF_TIMER_TYPE_SW,
+ csr_scan_active_list_timeout_handle, &cmd);
+ cmd->u.scanCmd.u.scanRequest.scan_id =
+ cmd->u.scanCmd.scanID;
+
+ if (pSession->connectedProfile.SSID.length) {
+ /*
+ * on error: following memory will be released by call to
+ * csr_release_command_scan in the end
+ */
+ ssid_list->SSIDList = cdf_mem_malloc(sizeof(tCsrSSIDInfo));
+ if (NULL == ssid_list->SSIDList)
+ return CDF_STATUS_E_NOMEM;
+ ssid_list->numOfSSIDs = 1;
+ cdf_mem_copy(&ssid_list->SSIDList[0].SSID,
+ &pSession->connectedProfile.SSID,
+ sizeof(tSirMacSSid));
+ } else {
+ ssid_list->numOfSSIDs = 0;
+ }
+
+ if (!pSession->pCurRoamProfile)
+ return CDF_STATUS_SUCCESS;
+
+ scan_filter = cdf_mem_malloc(sizeof(tCsrScanResultFilter));
+ if (NULL == scan_filter)
+ return CDF_STATUS_E_NOMEM;
+
+ cdf_mem_set(scan_filter, sizeof(tCsrScanResultFilter), 0);
+ status = csr_roam_prepare_filter_from_profile(mac_ctx,
+ pSession->pCurRoamProfile, scan_filter);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ goto free_lost_link1_local_mem;
+
+ if (!(CDF_IS_STATUS_SUCCESS(csr_scan_get_result(mac_ctx, scan_filter,
+ &bss_lst)) && bss_lst)) {
+ if (csr_roam_is_channel_valid(mac_ctx,
+ pSession->connectedProfile.operationChannel)) {
+ ch_info->ChannelList = cdf_mem_malloc(1);
+ if (NULL == ch_info->ChannelList) {
+ status = CDF_STATUS_E_NOMEM;
+ goto free_lost_link1_local_mem;
+ }
+ ch_info->ChannelList[0] =
+ pSession->connectedProfile.operationChannel;
+ ch_info->numOfChannels = 1;
+ }
+ return status;
+ }
+
+ /* on error: this mem will be released by csr_release_command_scan */
+ ch_info->ChannelList = cdf_mem_malloc(WNI_CFG_VALID_CHANNEL_LIST_LEN);
+ if (NULL == ch_info->ChannelList) {
+ status = CDF_STATUS_E_NOMEM;
+ goto free_lost_link1_local_mem;
+ }
+
+ scan_result = csr_scan_result_get_next(mac_ctx, bss_lst);
+ while (scan_result != NULL && num_ch < WNI_CFG_VALID_CHANNEL_LIST_LEN) {
+ for (i = 0; i < num_ch; i++) {
+ if (ch_info->ChannelList[i] ==
+ scan_result->BssDescriptor.channelId)
+ break;
+ }
+ if (i == num_ch)
+ ch_info->ChannelList[num_ch++] =
+ scan_result->BssDescriptor.channelId;
+ scan_result = csr_scan_result_get_next(mac_ctx, bss_lst);
+ }
+ /* Include the last connected BSS' channel */
+ if (csr_roam_is_channel_valid(mac_ctx,
+ pSession->connectedProfile.operationChannel)) {
+ for (i = 0; i < num_ch; i++) {
+ if (ch_info->ChannelList[i] ==
+ pSession->connectedProfile.operationChannel)
+ break;
+ }
+ if (i == num_ch)
+ ch_info->ChannelList[num_ch++] =
+ pSession->connectedProfile.operationChannel;
+ }
+ ch_info->numOfChannels = num_ch;
+free_lost_link1_local_mem:
+ if (scan_filter) {
+ csr_free_scan_filter(mac_ctx, scan_filter);
+ cdf_mem_free(scan_filter);
+ }
+ if (bss_lst)
+ csr_scan_result_purge(mac_ctx, bss_lst);
+ return status;
+}
+
+/**
+ * csr_scan_request_lost_link1() - start scan on link lost 1
+ * @mac_ctx: mac global context
+ * @session_id: session id
+ *
+ * Lostlink1 scan is to actively scan the last connected profile's SSID on all
+ * matched BSS channels. If no roam profile (it should not), it is like
+ * lostlinkscan3
+ *
+ * Return: status of operation
+ */
+CDF_STATUS
+csr_scan_request_lost_link1(tpAniSirGlobal mac_ctx, uint32_t session_id)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSmeCmd *cmd = NULL;
+ tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id);
+
+ if (!session) {
+ sms_log(mac_ctx, LOGE, FL("session %d not found"), session_id);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ sms_log(mac_ctx, LOGW, FL("Entry"));
+ cmd = csr_get_command_buffer(mac_ctx);
+ if (!cmd) {
+ status = CDF_STATUS_E_RESOURCES;
+ goto release_lost_link1_cmd;
+ }
+ cdf_mem_set(&cmd->u.scanCmd, sizeof(tScanCmd), 0);
+ status = csr_update_lost_link1_cmd(mac_ctx, cmd, session, session_id);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ goto release_lost_link1_cmd;
+
+ cdf_mem_set(&cmd->u.scanCmd.u.scanRequest.bssid,
+ sizeof(struct cdf_mac_addr), 0xFF);
+ status = csr_queue_sme_command(mac_ctx, cmd, false);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(mac_ctx, LOGE,
+ FL("fail to send message status = %d"), status);
+ }
+
+release_lost_link1_cmd:
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(mac_ctx, LOGW, FL("failed with status %d"), status);
+ if (cmd)
+ csr_release_command_scan(mac_ctx, cmd);
+ status = csr_scan_handle_failed_lostlink1(mac_ctx, session_id);
+ }
+ return status;
+}
+
+static CDF_STATUS
+csr_update_lost_link2_cmd(tpAniSirGlobal mac_ctx, tSmeCmd *cmd,
+ uint32_t session_id, tCsrRoamSession *session)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ uint8_t i, num_ch = 0;
+ tScanResultHandle bss_lst = NULL;
+ tCsrScanResultInfo *scan_result = NULL;
+ tCsrScanResultFilter *scan_fltr = NULL;
+ tCsrChannelInfo *ch_info = &cmd->u.scanCmd.u.scanRequest.ChannelInfo;
+
+ cmd->command = eSmeCommandScan;
+ cmd->sessionId = (uint8_t) session_id;
+ cmd->u.scanCmd.reason = eCsrScanLostLink2;
+ cmd->u.scanCmd.callback = NULL;
+ cmd->u.scanCmd.pContext = NULL;
+ cmd->u.scanCmd.u.scanRequest.maxChnTime =
+ mac_ctx->roam.configParam.nActiveMaxChnTime;
+ cmd->u.scanCmd.u.scanRequest.minChnTime =
+ mac_ctx->roam.configParam.nActiveMinChnTime;
+ cmd->u.scanCmd.u.scanRequest.scanType = eSIR_ACTIVE_SCAN;
+ wma_get_scan_id(&cmd->u.scanCmd.scanID);
+ cmd->u.scanCmd.u.scanRequest.scan_id =
+ cmd->u.scanCmd.scanID;
+ if (!session->pCurRoamProfile)
+ return CDF_STATUS_SUCCESS;
+ status = cdf_mc_timer_init(&cmd->u.scanCmd.csr_scan_timer,
+ CDF_TIMER_TYPE_SW,
+ csr_scan_active_list_timeout_handle, &cmd);
+ scan_fltr = cdf_mem_malloc(sizeof(tCsrScanResultFilter));
+ if (NULL == scan_fltr)
+ return CDF_STATUS_E_NOMEM;
+
+ cdf_mem_set(scan_fltr, sizeof(tCsrScanResultFilter), 0);
+ status = csr_roam_prepare_filter_from_profile(mac_ctx,
+ session->pCurRoamProfile, scan_fltr);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ goto free_lost_link2_local_mem;
+
+ status = csr_scan_get_result(mac_ctx, scan_fltr, &bss_lst);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ goto free_lost_link2_local_mem;
+
+ if (!bss_lst)
+ goto free_lost_link2_local_mem;
+
+ ch_info->ChannelList = cdf_mem_malloc(WNI_CFG_VALID_CHANNEL_LIST_LEN);
+ if (NULL == ch_info->ChannelList) {
+ status = CDF_STATUS_E_NOMEM;
+ goto free_lost_link2_local_mem;
+ }
+ scan_result = csr_scan_result_get_next(mac_ctx, bss_lst);
+ while (scan_result != NULL && num_ch < WNI_CFG_VALID_CHANNEL_LIST_LEN) {
+ for (i = 0; i < num_ch; i++) {
+ if (ch_info->ChannelList[i] ==
+ scan_result->BssDescriptor.channelId)
+ break;
+ }
+ if (i == num_ch)
+ ch_info->ChannelList[num_ch++] =
+ scan_result->BssDescriptor.channelId;
+ scan_result = csr_scan_result_get_next(mac_ctx, bss_lst);
+ }
+ ch_info->numOfChannels = num_ch;
+
+free_lost_link2_local_mem:
+ if (scan_fltr) {
+ csr_free_scan_filter(mac_ctx, scan_fltr);
+ cdf_mem_free(scan_fltr);
+ }
+ if (bss_lst)
+ csr_scan_result_purge(mac_ctx, bss_lst);
+ return status;
+}
+
+/**
+ * csr_scan_request_lost_link2() - start scan on link lost 2
+ * @mac_ctx: mac global context
+ * @session_id: session id
+ *
+ * Lostlink2 scan is to actively scan the all SSIDs of the last roaming
+ * profile's on all matched BSS channels. Since MAC doesn't support multiple
+ * SSID, we scan all SSIDs and filter them afterwards
+ *
+ * Return: status of operation
+ */
+CDF_STATUS
+csr_scan_request_lost_link2(tpAniSirGlobal mac_ctx, uint32_t session_id)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSmeCmd *cmd = NULL;
+ tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id);
+
+ if (!session) {
+ sms_log(mac_ctx, LOGE, FL("session %d not found"), session_id);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ sms_log(mac_ctx, LOGW, FL(" called"));
+ cmd = csr_get_command_buffer(mac_ctx);
+ if (!cmd) {
+ status = CDF_STATUS_E_RESOURCES;
+ goto release_lost_link2_cmd;
+ }
+ cdf_mem_set(&cmd->u.scanCmd, sizeof(tScanCmd), 0);
+ status = csr_update_lost_link2_cmd(mac_ctx, cmd, session_id, session);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ goto release_lost_link2_cmd;
+
+ cdf_mem_set(&cmd->u.scanCmd.u.scanRequest.bssid,
+ sizeof(struct cdf_mac_addr), 0xFF);
+ /* Put to the head in pending queue */
+ status = csr_queue_sme_command(mac_ctx, cmd, true);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(mac_ctx, LOGE,
+ FL("fail to send message status = %d"), status);
+ goto release_lost_link2_cmd;
+ }
+
+release_lost_link2_cmd:
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(mac_ctx, LOGW, FL("failed with status %d"), status);
+ if (cmd)
+ csr_release_command_scan(mac_ctx, cmd);
+ status = csr_scan_handle_failed_lostlink2(mac_ctx, session_id);
+ }
+ return status;
+}
+
+/**
+ * csr_scan_request_lost_link3() - To actively scan all valid channels
+ * @mac_ctx: mac global context
+ * @session_id: session id
+ *
+ * Return: status of operation
+ */
+CDF_STATUS
+csr_scan_request_lost_link3(tpAniSirGlobal mac_ctx, uint32_t session_id)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSmeCmd *cmd;
+
+ sms_log(mac_ctx, LOGW, FL(" called"));
+ do {
+ cmd = csr_get_command_buffer(mac_ctx);
+ if (!cmd) {
+ status = CDF_STATUS_E_RESOURCES;
+ break;
+ }
+ cdf_mem_set(&cmd->u.scanCmd, sizeof(tScanCmd), 0);
+ cmd->command = eSmeCommandScan;
+ cmd->sessionId = (uint8_t) session_id;
+ cmd->u.scanCmd.reason = eCsrScanLostLink3;
+ cmd->u.scanCmd.callback = NULL;
+ cmd->u.scanCmd.pContext = NULL;
+ cmd->u.scanCmd.u.scanRequest.maxChnTime =
+ mac_ctx->roam.configParam.nActiveMaxChnTime;
+ cmd->u.scanCmd.u.scanRequest.minChnTime =
+ mac_ctx->roam.configParam.nActiveMinChnTime;
+ cmd->u.scanCmd.u.scanRequest.scanType = eSIR_ACTIVE_SCAN;
+ wma_get_scan_id(&cmd->u.scanCmd.scanID);
+ status = cdf_mc_timer_init(&cmd->u.scanCmd.csr_scan_timer,
+ CDF_TIMER_TYPE_SW,
+ csr_scan_active_list_timeout_handle, &cmd);
+ cmd->u.scanCmd.u.scanRequest.scan_id =
+ cmd->u.scanCmd.scanID;
+ cdf_set_macaddr_broadcast(&cmd->u.scanCmd.u.scanRequest.bssid);
+ /* Put to the head of pending queue */
+ status = csr_queue_sme_command(mac_ctx, cmd, true);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(mac_ctx, LOGE,
+ FL("fail to send message status = %d"), status);
+ break;
+ }
+ } while (0);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(mac_ctx, LOGW, FL("failed with status %d"), status);
+ if (cmd)
+ csr_release_command_scan(mac_ctx, cmd);
+ }
+
+ return status;
+}
+
+CDF_STATUS csr_scan_handle_search_for_ssid(tpAniSirGlobal pMac,
+ tSmeCmd *pCommand)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ tScanResultHandle hBSSList = CSR_INVALID_SCANRESULT_HANDLE;
+ tCsrScanResultFilter *pScanFilter = NULL;
+ tCsrRoamProfile *pProfile = pCommand->u.scanCmd.pToRoamProfile;
+ uint32_t sessionId = pCommand->sessionId;
+
+ do {
+ /* If this scan is for LFR */
+ if (pMac->roam.neighborRoamInfo[sessionId].uOsRequestedHandoff) {
+ /* notify LFR state m/c */
+ status = csr_neighbor_roam_sssid_scan_done(pMac,
+ sessionId, CDF_STATUS_SUCCESS);
+ if (CDF_STATUS_SUCCESS != status)
+ csr_neighbor_roam_start_lfr_scan(pMac,
+ sessionId);
+ status = CDF_STATUS_SUCCESS;
+ break;
+ }
+ /*
+ * If there is roam command waiting, ignore this roam because
+ * the newer roam command is the one to execute
+ */
+ if (csr_is_roam_command_waiting_for_session(pMac, sessionId)) {
+ sms_log(pMac, LOGW,
+ FL("aborts because roam command waiting"));
+ break;
+ }
+ if (pProfile == NULL)
+ break;
+ pScanFilter = cdf_mem_malloc(sizeof(tCsrScanResultFilter));
+ if (NULL == pScanFilter) {
+ status = CDF_STATUS_E_NOMEM;
+ break;
+ }
+ cdf_mem_set(pScanFilter, sizeof(tCsrScanResultFilter), 0);
+ status = csr_roam_prepare_filter_from_profile(pMac, pProfile,
+ pScanFilter);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ break;
+ status = csr_scan_get_result(pMac, pScanFilter, &hBSSList);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ break;
+ status = csr_roam_issue_connect(pMac, sessionId, pProfile,
+ hBSSList, eCsrHddIssued,
+ pCommand->u.scanCmd.roamId,
+ true, true);
+ } while (0);
+
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ if (CSR_INVALID_SCANRESULT_HANDLE != hBSSList) {
+ csr_scan_result_purge(pMac, hBSSList);
+ }
+ /* We haven't done anything to this profile */
+ csr_roam_call_callback(pMac, sessionId, NULL,
+ pCommand->u.scanCmd.roamId,
+ eCSR_ROAM_ASSOCIATION_FAILURE,
+ eCSR_ROAM_RESULT_FAILURE);
+ }
+ if (pScanFilter) {
+ csr_free_scan_filter(pMac, pScanFilter);
+ cdf_mem_free(pScanFilter);
+ }
+ return status;
+}
+
+CDF_STATUS csr_scan_handle_search_for_ssid_failure(tpAniSirGlobal pMac,
+ tSmeCmd *pCommand)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ uint32_t sessionId = pCommand->sessionId;
+ tCsrRoamProfile *pProfile = pCommand->u.scanCmd.pToRoamProfile;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+ eCsrRoamResult roam_result;
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL("session %d not found"), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+ /* If this scan is for LFR */
+ if (pMac->roam.neighborRoamInfo[sessionId].uOsRequestedHandoff) {
+ /* notify LFR state m/c */
+ status = csr_neighbor_roam_sssid_scan_done(pMac, sessionId,
+ CDF_STATUS_E_FAILURE);
+ if (CDF_STATUS_SUCCESS != status)
+ csr_neighbor_roam_start_lfr_scan(pMac, sessionId);
+ return CDF_STATUS_SUCCESS;
+ }
+#ifdef WLAN_DEBUG
+ if (pCommand->u.scanCmd.u.scanRequest.SSIDs.numOfSSIDs == 1) {
+ char str[36];
+ tSirMacSSid *ptr_ssid =
+ &pCommand->u.scanCmd.u.scanRequest.SSIDs.SSIDList[0].SSID;
+ cdf_mem_copy(str, ptr_ssid->ssId, ptr_ssid->length);
+ str[ptr_ssid->length] = 0;
+ sms_log(pMac, LOGW, FL("SSID = %s"), str);
+ }
+#endif
+ /*
+ * Check whether it is for start ibss. No need to do anything if it
+ * is a JOIN request
+ */
+ if (pProfile && CSR_IS_START_IBSS(pProfile)) {
+ status = csr_roam_issue_connect(pMac, sessionId, pProfile, NULL,
+ eCsrHddIssued, pCommand->u.scanCmd.roamId,
+ true, true);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ FL("failed to issue startIBSS, status: 0x%08X"),
+ status);
+ csr_roam_call_callback(pMac, sessionId, NULL,
+ pCommand->u.scanCmd.roamId, eCSR_ROAM_FAILED,
+ eCSR_ROAM_RESULT_FAILURE);
+ }
+ return status;
+ }
+ roam_result = eCSR_ROAM_RESULT_FAILURE;
+ if (NULL != pProfile && csr_is_bss_type_ibss(pProfile->BSSType)) {
+ roam_result = eCSR_ROAM_RESULT_IBSS_START_FAILED;
+ goto roam_completion;
+ }
+ /* Only indicate assoc_completion if we indicate assoc_start. */
+ if (pSession->bRefAssocStartCnt > 0) {
+ tCsrRoamInfo *pRoamInfo = NULL, roamInfo;
+
+ cdf_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0);
+ pRoamInfo = &roamInfo;
+ if (pCommand->u.roamCmd.pRoamBssEntry) {
+ tCsrScanResult *pScanResult = GET_BASE_ADDR(
+ pCommand->u.roamCmd.pRoamBssEntry,
+ tCsrScanResult, Link);
+ roamInfo.pBssDesc = &pScanResult->Result.BssDescriptor;
+ }
+ roamInfo.statusCode = pSession->joinFailStatusCode.statusCode;
+ roamInfo.reasonCode = pSession->joinFailStatusCode.reasonCode;
+ pSession->bRefAssocStartCnt--;
+ csr_roam_call_callback(pMac, sessionId, pRoamInfo,
+ pCommand->u.scanCmd.roamId,
+ eCSR_ROAM_ASSOCIATION_COMPLETION,
+ eCSR_ROAM_RESULT_FAILURE);
+ } else {
+ csr_roam_call_callback(pMac, sessionId, NULL,
+ pCommand->u.scanCmd.roamId,
+ eCSR_ROAM_ASSOCIATION_FAILURE,
+ eCSR_ROAM_RESULT_FAILURE);
+ }
+roam_completion:
+ csr_roam_completion(pMac, sessionId, NULL, pCommand, roam_result,
+ false);
+ return status;
+}
+
+CDF_STATUS csr_scan_result_purge(tpAniSirGlobal pMac,
+ tScanResultHandle hScanList)
+{
+ CDF_STATUS status = CDF_STATUS_E_INVAL;
+ tScanResultList *pScanList = (tScanResultList *) hScanList;
+
+ if (pScanList) {
+ status = csr_ll_scan_purge_result(pMac, &pScanList->List);
+ csr_ll_close(&pScanList->List);
+ cdf_mem_free(pScanList);
+ }
+ return status;
+}
+
+/**
+ * csr_derive_prefer_value_from_rssi() - to derive prefer value
+ * @mac_ctx: Global MAC Context
+ * @rssi: RSSI of the BSS
+ *
+ * This routine will derive preferred value from given rssi
+ *
+ * Return: value between 0 to 14
+ */
+static int csr_derive_prefer_value_from_rssi(tpAniSirGlobal mac_ctx, int rssi)
+{
+ int i = CSR_NUM_RSSI_CAT - 1, pref_val = 0;
+ while (i >= 0) {
+ if (rssi >= mac_ctx->roam.configParam.RSSICat[i]) {
+ pref_val = mac_ctx->roam.configParam.BssPreferValue[i];
+ break;
+ }
+ i--;
+ };
+ return pref_val;
+}
+
+/**
+ * is_channel_found_in_pcl() - to check if channel is present in pcl
+ * @mac_ctx: Global MAC Context
+ * @channel_id: channel of bss
+ * @filter: pointer to filter created through profile
+ *
+ * to check if provided channel is present in pcl
+ *
+ * Return: true or false
+ */
+static bool is_channel_found_in_pcl(tpAniSirGlobal mac_ctx, int channel_id,
+ tCsrScanResultFilter *filter)
+{
+ int i;
+ bool status = false;
+
+ if (NULL == filter)
+ return status;
+
+ for (i = 0; i < filter->pcl_channels.numChannels; i++) {
+ if (filter->pcl_channels.channelList[i] == channel_id) {
+ status = true;
+ break;
+ }
+ }
+ return status;
+}
+/**
+ * csr_get_altered_rssi() - Artificially increase/decrease RSSI
+ * @mac_ctx: Global MAC Context pointer.
+ * @rssi: Actual RSSI of the AP.
+ * @channel_id: Channel on which the AP is parked.
+ * @bssid: BSSID of the AP to connect to.
+ *
+ * This routine will apply the boost and penalty parameters
+ * if the channel_id is of 5G band and it will also apply
+ * the preferred bssid score if there is a match between
+ * the bssid and the global preferred bssid list.
+ *
+ * Return: The modified RSSI Value
+ */
+static int csr_get_altered_rssi(tpAniSirGlobal mac_ctx, int rssi,
+ uint8_t channel_id, struct cdf_mac_addr *bssid)
+{
+ int modified_rssi;
+ int boost_factor;
+ int penalty_factor;
+ int i;
+ struct roam_ext_params *roam_params;
+ struct cdf_mac_addr fav_bssid;
+ struct cdf_mac_addr local_bssid;
+
+ modified_rssi = rssi;
+ cdf_mem_zero(&local_bssid.bytes, CDF_MAC_ADDR_SIZE);
+ if (bssid)
+ cdf_mem_copy(local_bssid.bytes, bssid->bytes,
+ CDF_MAC_ADDR_SIZE);
+ roam_params = &mac_ctx->roam.configParam.roam_params;
+ /*
+ * If the 5G pref feature is enabled, apply the roaming
+ * parameters to boost or penalize the rssi.
+ * Boost Factor = boost_factor * (Actual RSSI - boost Threshold)
+ * Penalty Factor = penalty factor * (penalty threshold - Actual RSSI)
+ */
+ if (CSR_IS_SELECT_5G_PREFERRED(mac_ctx) &&
+ CDS_IS_CHANNEL_5GHZ(channel_id)) {
+ if (rssi > roam_params->raise_rssi_thresh_5g) {
+ /* Check and boost the threshold*/
+ boost_factor = roam_params->raise_factor_5g *
+ (rssi - roam_params->raise_rssi_thresh_5g);
+ /* Check and penalize the threshold */
+ modified_rssi += CSR_MIN(roam_params->max_raise_rssi_5g,
+ boost_factor);
+ } else if (rssi < roam_params->drop_rssi_thresh_5g) {
+ penalty_factor = roam_params->drop_factor_5g *
+ (roam_params->drop_rssi_thresh_5g - rssi);
+ modified_rssi -= CSR_MAX(roam_params->max_drop_rssi_5g,
+ penalty_factor);
+ }
+ sms_log(mac_ctx, LOG2,
+ FL("5G BSSID"MAC_ADDRESS_STR" AR=%d, MR=%d, ch=%d"),
+ MAC_ADDR_ARRAY(local_bssid.bytes),
+ rssi, modified_rssi, channel_id);
+ }
+ /*
+ * Check if there are preferred bssid and then apply the
+ * preferred score
+ */
+ cdf_mem_zero(&fav_bssid.bytes, CDF_MAC_ADDR_SIZE);
+ if (roam_params->num_bssid_favored) {
+ for (i = 0; i < roam_params->num_bssid_favored; i++) {
+ cdf_mem_copy(fav_bssid.bytes,
+ &roam_params->bssid_favored[i],
+ CDF_MAC_ADDR_SIZE);
+ if (!cdf_is_macaddr_equal(&fav_bssid, bssid))
+ continue;
+ modified_rssi += roam_params->bssid_favored_factor[i];
+ sms_log(mac_ctx, LOG2,
+ FL("Pref"MAC_ADDRESS_STR" AR=%d, MR=%d, ch=%d"),
+ MAC_ADDR_ARRAY(local_bssid.bytes),
+ rssi, modified_rssi, channel_id);
+ }
+ }
+ return modified_rssi;
+}
+
+/**
+ * csr_get_bss_prefer_value() - Get the preference value for BSS
+ * @mac_ctx: Global MAC Context
+ * @rssi: RSSI of the BSS
+ * @bssid: BSSID to which the preference value is returned
+ * @channel_id: Channel on which the AP is parked
+ *
+ * Each BSS descriptor should be assigned a preference value ranging from
+ * 14-0, which will be used as an RSSI bucket score while sorting the
+ * scan results.
+ *
+ * Return: Preference value for the BSSID
+ */
+static uint32_t csr_get_bss_prefer_value(tpAniSirGlobal mac_ctx, int rssi,
+ struct cdf_mac_addr *bssid, int channel_id)
+{
+ uint32_t ret = 0;
+ int modified_rssi;
+
+ /*
+ * The RSSI does not get modified in case the 5G
+ * preference or preferred BSSID is not applicable
+ */
+ modified_rssi = csr_get_altered_rssi(mac_ctx, rssi, channel_id, bssid);
+ ret = csr_derive_prefer_value_from_rssi(mac_ctx, modified_rssi);
+
+ return ret;
+}
+
+/* Return a CapValue base on the capabilities of a BSS */
+static uint32_t csr_get_bss_cap_value(tpAniSirGlobal pMac,
+ tSirBssDescription *pBssDesc,
+ tDot11fBeaconIEs *pIes)
+{
+ uint32_t ret = CSR_BSS_CAP_VALUE_NONE;
+#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR)
+ if (CSR_IS_ROAM_PREFER_5GHZ(pMac) || CSR_IS_SELECT_5G_PREFERRED(pMac)) {
+ if ((pBssDesc) && CDS_IS_CHANNEL_5GHZ(pBssDesc->channelId)) {
+ ret += CSR_BSS_CAP_VALUE_5GHZ;
+ }
+ }
+#endif
+ /*
+ * if strict select 5GHz is non-zero then ignore the capability checking
+ */
+ if (pIes && !CSR_IS_SELECT_5GHZ_MARGIN(pMac)) {
+ /* We only care about 11N capability */
+ if (pIes->VHTCaps.present)
+ ret += CSR_BSS_CAP_VALUE_VHT;
+ else if (pIes->HTCaps.present)
+ ret += CSR_BSS_CAP_VALUE_HT;
+ if (CSR_IS_QOS_BSS(pIes)) {
+ ret += CSR_BSS_CAP_VALUE_WMM;
+ /* Give advantage to UAPSD */
+ if (CSR_IS_UAPSD_BSS(pIes)) {
+ ret += CSR_BSS_CAP_VALUE_UAPSD;
+ }
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * csr_is_better_rssi() - Is bss1 better than bss2
+ * @mac_ctx: Global MAC Context pointer.
+ * @bss1: Pointer to the first BSS.
+ * @bss2: Pointer to the second BSS.
+ *
+ * This routine helps in determining the preference value
+ * of a particular BSS in the scan result which is further
+ * used in the sorting logic of the final candidate AP's.
+ *
+ * Return: true, if bss1 is better than bss2
+ * false, if bss2 is better than bss1.
+ */
+static bool csr_is_better_rssi(tpAniSirGlobal mac_ctx,
+ tCsrScanResult *bss1, tCsrScanResult *bss2)
+{
+ bool ret;
+ int rssi1, rssi2;
+ struct cdf_mac_addr local_mac;
+
+ rssi1 = bss1->Result.BssDescriptor.rssi;
+ rssi2 = bss2->Result.BssDescriptor.rssi;
+ /*
+ * Apply the boost and penlty logic and check
+ * which is the best RSSI
+ */
+ cdf_mem_zero(&local_mac.bytes, CDF_MAC_ADDR_SIZE);
+ cdf_mem_copy(&local_mac.bytes,
+ &bss1->Result.BssDescriptor.bssId, CDF_MAC_ADDR_SIZE);
+ rssi1 = csr_get_altered_rssi(mac_ctx, rssi1,
+ bss1->Result.BssDescriptor.channelId,
+ &local_mac);
+ cdf_mem_copy(&local_mac.bytes,
+ &bss2->Result.BssDescriptor.bssId, CDF_MAC_ADDR_SIZE);
+ rssi2 = csr_get_altered_rssi(mac_ctx, rssi2,
+ bss2->Result.BssDescriptor.channelId,
+ &local_mac);
+ if (CSR_IS_BETTER_RSSI(rssi1, rssi2))
+ ret = true;
+ else
+ ret = false;
+ return ret;
+}
+
+/**
+ * csr_is_better_bss() - Is bss1 better than bss2
+ * @mac_ctx: Global MAC Context pointer.
+ * @bss1: Pointer to the first BSS.
+ * @bss2: Pointer to the second BSS.
+ *
+ * This routine helps in determining the preference value
+ * of a particular BSS in the scan result which is further
+ * used in the sorting logic of the final candidate AP's.
+ *
+ * Return: true, if bss1 is better than bss2
+ * false, if bss2 is better than bss1.
+ */
+static bool csr_is_better_bss(tpAniSirGlobal mac_ctx,
+ tCsrScanResult *bss1, tCsrScanResult *bss2)
+{
+ bool ret;
+
+ if (CSR_IS_BETTER_PREFER_VALUE(bss1->preferValue, bss2->preferValue)) {
+ ret = true;
+ } else if (CSR_IS_EQUAL_PREFER_VALUE
+ (bss1->preferValue, bss2->preferValue)) {
+ if (CSR_IS_BETTER_CAP_VALUE(bss1->capValue, bss2->capValue))
+ ret = true;
+ else if (CSR_IS_EQUAL_CAP_VALUE
+ (bss1->capValue, bss2->capValue)) {
+ if (csr_is_better_rssi(mac_ctx, bss1, bss2))
+ ret = true;
+ else
+ ret = false;
+ } else {
+ ret = false;
+ }
+ } else {
+ ret = false;
+ }
+
+ return ret;
+}
+
+#ifdef FEATURE_WLAN_LFR
+/* Add the channel to the occupiedChannels array */
+static void csr_scan_add_to_occupied_channels(tpAniSirGlobal pMac,
+ tCsrScanResult *pResult,
+ uint8_t sessionId,
+ tCsrChannel *occupied_ch,
+ tDot11fBeaconIEs *pIes)
+{
+ CDF_STATUS status;
+ uint8_t ch;
+ uint8_t num_occupied_ch = occupied_ch->numChannels;
+ uint8_t *occupied_ch_lst = occupied_ch->channelList;
+
+ ch = pResult->Result.BssDescriptor.channelId;
+ if (csr_is_channel_present_in_list(occupied_ch_lst, num_occupied_ch, ch)
+ || !csr_neighbor_roam_connected_profile_match(pMac, sessionId,
+ pResult, pIes))
+ return;
+
+ status = csr_add_to_channel_list_front(occupied_ch_lst,
+ num_occupied_ch, ch);
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ occupied_ch->numChannels++;
+ sms_log(pMac, LOG2,
+ FL("Added channel %d to the list (count=%d)"),
+ ch, occupied_ch->numChannels);
+ if (occupied_ch->numChannels >
+ CSR_BG_SCAN_OCCUPIED_CHANNEL_LIST_LEN)
+ occupied_ch->numChannels =
+ CSR_BG_SCAN_OCCUPIED_CHANNEL_LIST_LEN;
+ }
+}
+#endif
+
+/* Put the BSS into the scan result list */
+/* pIes can not be NULL */
+static void csr_scan_add_result(tpAniSirGlobal pMac, tCsrScanResult *pResult,
+ tDot11fBeaconIEs *pIes, uint32_t sessionId)
+{
+#ifdef FEATURE_WLAN_LFR
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+#endif
+
+ struct cdf_mac_addr bssid;
+ uint8_t channel_id = pResult->Result.BssDescriptor.channelId;
+ cdf_mem_zero(&bssid.bytes, CDF_MAC_ADDR_SIZE);
+ cdf_mem_copy(bssid.bytes, &pResult->Result.BssDescriptor.bssId,
+ CDF_MAC_ADDR_SIZE);
+ pResult->preferValue = csr_get_bss_prefer_value(pMac,
+ (int)pResult->Result.BssDescriptor.rssi,
+ &bssid, channel_id);
+ pResult->capValue = csr_get_bss_cap_value(pMac,
+ &pResult->Result.BssDescriptor, pIes);
+ csr_ll_insert_tail(&pMac->scan.scanResultList, &pResult->Link,
+ LL_ACCESS_LOCK);
+#ifdef FEATURE_WLAN_LFR
+ if (0 == pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels) {
+ /*
+ * Build the occupied channel list, only if
+ * "gNeighborScanChannelList" is NOT set in the cfg.ini file
+ */
+ csr_scan_add_to_occupied_channels(pMac, pResult, sessionId,
+ &pMac->scan.occupiedChannels[sessionId], pIes);
+ }
+#endif
+}
+
+static void
+csr_parser_scan_result_for_5ghz_preference(tpAniSirGlobal pMac,
+ tCsrScanResultFilter *pFilter)
+{
+ bool fMatch;
+ CDF_STATUS status;
+ tListElem *pEntry;
+ tDot11fBeaconIEs *pIes;
+ tCsrScanResult *pBssDesc;
+ uint8_t i = 0;
+
+ /* Find out the best AP Rssi going thru the scan results */
+ pEntry = csr_ll_peek_head(&pMac->scan.scanResultList, LL_ACCESS_NOLOCK);
+ while (NULL != pEntry) {
+ pBssDesc = GET_BASE_ADDR(pEntry, tCsrScanResult, Link);
+ fMatch = false;
+
+ for (i = 0; pFilter && (i < pFilter->SSIDs.numOfSSIDs); i++) {
+ fMatch = csr_is_ssid_match(pMac,
+ pFilter->SSIDs.SSIDList[i].SSID.ssId,
+ pFilter->SSIDs.SSIDList[i].SSID.length,
+ pBssDesc->Result.ssId.ssId,
+ pBssDesc->Result.ssId.length, true);
+ if (!fMatch)
+ continue;
+
+ pIes = (tDot11fBeaconIEs *)(pBssDesc->Result.pvIes);
+ /* At this time, Result.pvIes may be NULL */
+ status = csr_get_parsed_bss_description_ies(pMac,
+ &pBssDesc->Result.BssDescriptor, &pIes);
+ if (!pIes && (!CDF_IS_STATUS_SUCCESS(status)))
+ continue;
+
+ sms_log(pMac, LOG1, FL("SSID Matched"));
+ if (pFilter->bOSENAssociation) {
+ fMatch = true;
+ sms_log(pMac, LOG1, FL("Security Matched"));
+ if ((pBssDesc->Result.pvIes == NULL) && pIes)
+ cdf_mem_free(pIes);
+ continue;
+ }
+#ifdef WLAN_FEATURE_11W
+ fMatch = csr_is_security_match(pMac, &pFilter->authType,
+ &pFilter->EncryptionType,
+ &pFilter->mcEncryptionType,
+ &pFilter->MFPEnabled,
+ &pFilter->MFPRequired,
+ &pFilter->MFPCapable,
+ &pBssDesc->Result.BssDescriptor,
+ pIes, NULL, NULL, NULL);
+#else
+ fMatch = csr_is_security_match(pMac, &pFilter->authType,
+ &pFilter->EncryptionType,
+ &pFilter->mcEncryptionType,
+ NULL, NULL, NULL,
+ &pBssDesc->Result.BssDescriptor,
+ pIes, NULL, NULL, NULL);
+#endif
+ if ((pBssDesc->Result.pvIes == NULL) && pIes)
+ cdf_mem_free(pIes);
+ if (fMatch)
+ sms_log(pMac, LOG1, FL("Security Matched"));
+ } /* for loop ends */
+
+ if (fMatch
+ && (pBssDesc->Result.BssDescriptor.rssi >
+ pMac->scan.inScanResultBestAPRssi)) {
+ sms_log(pMac, LOG1,
+ FL("Best AP Rssi changed from %d to %d"),
+ pMac->scan.inScanResultBestAPRssi,
+ pBssDesc->Result.BssDescriptor.rssi);
+ pMac->scan.inScanResultBestAPRssi =
+ pBssDesc->Result.BssDescriptor.rssi;
+ }
+ pEntry = csr_ll_next(&pMac->scan.scanResultList, pEntry,
+ LL_ACCESS_NOLOCK);
+ }
+}
+
+static void
+csr_prefer_5ghz(tpAniSirGlobal pMac, tCsrScanResultFilter *pFilter)
+{
+ tListElem *pEntry;
+ tCsrScanResult *pBssDesc;
+ struct roam_ext_params *roam_params = NULL;
+
+ if (!pMac->roam.configParam.nSelect5GHzMargin &&
+ !CSR_IS_SELECT_5G_PREFERRED(pMac))
+ return;
+
+ pMac->scan.inScanResultBestAPRssi = -128;
+ roam_params = &pMac->roam.configParam.roam_params;
+#ifdef WLAN_DEBUG_ROAM_OFFLOAD
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ FL("nSelect5GHzMargin"));
+#endif
+ csr_ll_lock(&pMac->scan.scanResultList);
+ /*
+ * For 5G preference feature, there is no
+ * need to check the filter match and also re-program the
+ * RSSI bucket categories, since we use the RSSI values
+ * while setting the preference value for the BSS.
+ * There is no need to check the match for roaming since
+ * it is already done.
+ */
+ if (!CSR_IS_SELECT_5G_PREFERRED(pMac))
+ csr_parser_scan_result_for_5ghz_preference(pMac, pFilter);
+ if (-128 != pMac->scan.inScanResultBestAPRssi ||
+ CSR_IS_SELECT_5G_PREFERRED(pMac)) {
+ sms_log(pMac, LOG1, FL("Best AP Rssi is %d"),
+ pMac->scan.inScanResultBestAPRssi);
+ /* Modify Rssi category based on best AP Rssi */
+ if (-128 != pMac->scan.inScanResultBestAPRssi)
+ csr_assign_rssi_for_category(pMac,
+ pMac->scan.inScanResultBestAPRssi,
+ pMac->roam.configParam.bCatRssiOffset);
+ pEntry = csr_ll_peek_head(&pMac->scan.scanResultList,
+ LL_ACCESS_NOLOCK);
+ while (NULL != pEntry) {
+ pBssDesc = GET_BASE_ADDR(pEntry, tCsrScanResult, Link);
+ /*
+ * re-assign preference value based on modified
+ * rssi bucket (or) 5G Preference feature.
+ */
+ pBssDesc->preferValue = csr_get_bss_prefer_value(pMac,
+ (int)pBssDesc->Result.BssDescriptor.rssi,
+ (struct cdf_mac_addr *)
+ &pBssDesc->Result.BssDescriptor.bssId,
+ pBssDesc->Result.BssDescriptor.channelId);
+
+ sms_log(pMac, LOG2, FL("BSSID("MAC_ADDRESS_STR") Rssi(%d) Chnl(%d) PrefVal(%u) SSID=%.*s"),
+ MAC_ADDR_ARRAY(
+ pBssDesc->Result.BssDescriptor.bssId),
+ pBssDesc->Result.BssDescriptor.rssi,
+ pBssDesc->Result.BssDescriptor.channelId,
+ pBssDesc->preferValue,
+ pBssDesc->Result.ssId.length,
+ pBssDesc->Result.ssId.ssId);
+ pEntry = csr_ll_next(&pMac->scan.scanResultList, pEntry,
+ LL_ACCESS_NOLOCK);
+ }
+ }
+ csr_ll_unlock(&pMac->scan.scanResultList);
+}
+
+static CDF_STATUS
+csr_save_ies(tpAniSirGlobal pMac,
+ tCsrScanResultFilter *pFilter,
+ tCsrScanResult *pBssDesc,
+ tDot11fBeaconIEs **pNewIes,
+ bool *fMatch,
+ eCsrEncryptionType *uc,
+ eCsrEncryptionType *mc,
+ eCsrAuthType *auth)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tDot11fBeaconIEs *pIes = NULL;
+
+ if (!pFilter)
+ return status;
+ *fMatch = csr_match_bss(pMac, &pBssDesc->Result.BssDescriptor,
+ pFilter, auth, uc, mc, &pIes);
+#ifdef WLAN_DEBUG_ROAM_OFFLOAD
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ FL("csr_match_bss fmatch %d"), *fMatch);
+#endif
+ if (NULL == pIes)
+ return status;
+ /* Only save it when matching */
+ if (!(*fMatch) && !pBssDesc->Result.pvIes) {
+ cdf_mem_free(pIes);
+ return status;
+ }
+ if (!pBssDesc->Result.pvIes) {
+ /*
+ * csr_match_bss allocates the memory. Simply pass it and it
+ * is freed later
+ */
+ *pNewIes = pIes;
+ return status;
+ }
+ /*
+ * The pIes is allocated by someone else. make a copy
+ * Only to save parsed IEs if caller provides a filter. Most likely the
+ * caller is using to for association, hence save the parsed IEs
+ */
+ *pNewIes = cdf_mem_malloc(sizeof(tDot11fBeaconIEs));
+ if (NULL == *pNewIes) {
+ status = CDF_STATUS_E_NOMEM;
+ sms_log(pMac, LOGE, FL("fail to allocate memory for IEs"));
+ /* Need to free memory allocated by csr_match_bss */
+ if (!pBssDesc->Result.pvIes)
+ cdf_mem_free(pIes);
+ return status;
+ }
+ cdf_mem_copy(*pNewIes, pIes, sizeof(tDot11fBeaconIEs));
+ return status;
+}
+
+static CDF_STATUS
+csr_save_scan_entry(tpAniSirGlobal pMac,
+ tCsrScanResultFilter *pFilter,
+ bool fMatch,
+ tCsrScanResult *pBssDesc,
+ tDot11fBeaconIEs *pNewIes,
+ tScanResultList *pRetList,
+ uint32_t *count,
+ eCsrEncryptionType uc,
+ eCsrEncryptionType mc,
+ eCsrAuthType *auth)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tCsrScanResult *pResult;
+ uint32_t bssLen, allocLen;
+ /* To sort the list */
+ tListElem *pTmpEntry;
+ tCsrScanResult *pTmpResult;
+
+ if (!(NULL == pFilter || fMatch))
+ return status;
+
+ bssLen = pBssDesc->Result.BssDescriptor.length +
+ sizeof(pBssDesc->Result.BssDescriptor.length);
+ allocLen = sizeof(tCsrScanResult) + bssLen;
+ pResult = cdf_mem_malloc(allocLen);
+ if (NULL == pResult) {
+ status = CDF_STATUS_E_NOMEM;
+ sms_log(pMac, LOGE,
+ FL("fail to allocate memory for scan result, len=%d"),
+ allocLen);
+ if (pNewIes)
+ cdf_mem_free(pNewIes);
+ return status;
+ }
+ cdf_mem_set(pResult, allocLen, 0);
+ pResult->capValue = pBssDesc->capValue;
+ pResult->preferValue = pBssDesc->preferValue;
+ pResult->ucEncryptionType = uc;
+ pResult->mcEncryptionType = mc;
+ pResult->authType = *auth;
+ pResult->Result.ssId = pBssDesc->Result.ssId;
+ pResult->Result.timer = pBssDesc->Result.timer;
+ /* save the pIes for later use */
+ pResult->Result.pvIes = pNewIes;
+ /* save bss description */
+ cdf_mem_copy(&pResult->Result.BssDescriptor,
+ &pBssDesc->Result.BssDescriptor,
+ bssLen);
+ /*
+ * No need to lock pRetList because it is locally allocated and no
+ * outside can access it at this time
+ */
+ if (csr_ll_is_list_empty(&pRetList->List, LL_ACCESS_NOLOCK)) {
+ csr_ll_insert_tail(&pRetList->List, &pResult->Link,
+ LL_ACCESS_NOLOCK);
+ (*count)++;
+ return status;
+ }
+
+ pTmpEntry = csr_ll_peek_head(&pRetList->List, LL_ACCESS_NOLOCK);
+ while (pTmpEntry) {
+ pTmpResult = GET_BASE_ADDR(pTmpEntry, tCsrScanResult, Link);
+ if (csr_is_better_bss(pMac, pResult, pTmpResult)) {
+ csr_ll_insert_entry(&pRetList->List, pTmpEntry,
+ &pResult->Link, LL_ACCESS_NOLOCK);
+ /* To indicate we are done */
+ pResult = NULL;
+ break;
+ }
+ pTmpEntry = csr_ll_next(&pRetList->List,
+ pTmpEntry, LL_ACCESS_NOLOCK);
+ }
+ if (pResult != NULL) {
+ /* This one is not better than any one */
+ csr_ll_insert_tail(&pRetList->List, &pResult->Link,
+ LL_ACCESS_NOLOCK);
+ }
+ (*count)++;
+ return status;
+}
+
+/**
+ * csr_calc_pref_val_by_pcl() - to calculate preferred value
+ * @mac_ctx: mac context
+ * @filter: filter to find match from scan result
+ * @bss_descr: pointer to bss descriptor
+ *
+ * this routine calculates the new preferred value to be given to
+ * provided bss if its channel falls under preferred channel list.
+ * Thump rule is higer the RSSI better the boost.
+ *
+ * Return: success or failure
+ */
+static CDF_STATUS csr_calc_pref_val_by_pcl(tpAniSirGlobal mac_ctx,
+ tCsrScanResultFilter *filter,
+ tCsrScanResult *bss_descr)
+{
+ int temp_rssi = 0, new_pref_val = 0;
+ int orig_pref_val = 0;
+
+ if (NULL == mac_ctx || NULL == bss_descr)
+ return CDF_STATUS_E_FAILURE;
+
+ if (mac_ctx->policy_manager_enabled &&
+ is_channel_found_in_pcl(mac_ctx,
+ bss_descr->Result.BssDescriptor.channelId, filter) &&
+ (bss_descr->Result.BssDescriptor.rssi > PCL_RSSI_THRESHOLD)) {
+ orig_pref_val = csr_derive_prefer_value_from_rssi(mac_ctx,
+ bss_descr->Result.BssDescriptor.rssi);
+ temp_rssi = bss_descr->Result.BssDescriptor.rssi +
+ (PCL_ADVANTAGE/(CSR_NUM_RSSI_CAT -
+ orig_pref_val));
+ if (temp_rssi > 0)
+ temp_rssi = 0;
+ new_pref_val = csr_derive_prefer_value_from_rssi(mac_ctx,
+ temp_rssi);
+
+ sms_log(mac_ctx, LOG1,
+ FL("%pM: rssi:%d org pref=%d temp rssi:%d new pref=%d pref=%d updated pref=%d"),
+ bss_descr->Result.BssDescriptor.bssId,
+ bss_descr->Result.BssDescriptor.rssi,
+ orig_pref_val, temp_rssi, new_pref_val,
+ bss_descr->preferValue,
+ CSR_MAX(new_pref_val, bss_descr->preferValue));
+
+ bss_descr->preferValue =
+ CSR_MAX(new_pref_val, bss_descr->preferValue);
+ }
+ return CDF_STATUS_SUCCESS;
+}
+
+static CDF_STATUS
+csr_parse_scan_results(tpAniSirGlobal pMac,
+ tCsrScanResultFilter *pFilter,
+ tScanResultList *pRetList,
+ uint32_t *count)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tListElem *pEntry;
+ bool fMatch = false;
+ tCsrScanResult *pBssDesc = NULL;
+ tDot11fBeaconIEs *pIes, *pNewIes = NULL;
+ eCsrEncryptionType uc, mc;
+ eCsrAuthType auth = eCSR_AUTH_TYPE_OPEN_SYSTEM;
+ uint32_t len = 0;
+ enum cds_con_mode new_mode;
+
+
+ csr_ll_lock(&pMac->scan.scanResultList);
+
+ if (pFilter) {
+ if (cds_map_concurrency_mode(pMac->hHdd,
+ &pFilter->csrPersona, &new_mode)) {
+ status = cds_get_pcl(pMac->hHdd, new_mode,
+ &pFilter->pcl_channels.channelList[0], &len);
+ pFilter->pcl_channels.numChannels = (uint8_t)len;
+ }
+ }
+
+ if (CDF_STATUS_E_FAILURE == status)
+ sms_log(pMac, CDF_TRACE_LEVEL_ERROR,
+ FL("Retrieving pcl failed from HDD"));
+ pEntry = csr_ll_peek_head(&pMac->scan.scanResultList, LL_ACCESS_NOLOCK);
+ while (pEntry) {
+ pBssDesc = GET_BASE_ADDR(pEntry, tCsrScanResult, Link);
+ pIes = (tDot11fBeaconIEs *) (pBssDesc->Result.pvIes);
+ /*
+ * if pBssDesc->Result.pvIes is NULL, we need to free any memory
+ * allocated by csr_match_bss for any error condition,
+ * otherwiase, it will be freed later
+ */
+ fMatch = false;
+ pNewIes = NULL;
+ status = csr_save_ies(pMac, pFilter, pBssDesc, &pNewIes,
+ &fMatch, &uc, &mc, &auth);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ break;
+ /*
+ * Modify the prefer value to honor PCL list
+ */
+ if (pFilter && pFilter->pcl_channels.numChannels > 0)
+ csr_calc_pref_val_by_pcl(pMac, pFilter, pBssDesc);
+ status = csr_save_scan_entry(pMac, pFilter, fMatch, pBssDesc,
+ pNewIes, pRetList, count, uc, mc,
+ &auth);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ break;
+ pEntry = csr_ll_next(&pMac->scan.scanResultList, pEntry,
+ LL_ACCESS_NOLOCK);
+ } /* while */
+ csr_ll_unlock(&pMac->scan.scanResultList);
+ return status;
+}
+
+CDF_STATUS csr_scan_get_result(tpAniSirGlobal pMac,
+ tCsrScanResultFilter *pFilter,
+ tScanResultHandle *phResult)
+{
+ CDF_STATUS status;
+ tScanResultList *pRetList;
+ uint32_t count = 0;
+
+ if (phResult)
+ *phResult = CSR_INVALID_SCANRESULT_HANDLE;
+
+ csr_prefer_5ghz(pMac, pFilter);
+
+ pRetList = cdf_mem_malloc(sizeof(tScanResultList));
+ if (NULL == pRetList)
+ return CDF_STATUS_E_NOMEM;
+
+ cdf_mem_set(pRetList, sizeof(tScanResultList), 0);
+ csr_ll_open(pMac->hHdd, &pRetList->List);
+ pRetList->pCurEntry = NULL;
+ status = csr_parse_scan_results(pMac, pFilter, pRetList, &count);
+ sms_log(pMac, LOG2, FL("return %d BSS"), csr_ll_count(&pRetList->List));
+ if (!CDF_IS_STATUS_SUCCESS(status) || (phResult == NULL)) {
+ /* Fail or No one wants the result. */
+ csr_scan_result_purge(pMac, (tScanResultHandle) pRetList);
+ } else {
+ if (0 == count) {
+ /* We are here meaning the there is no match */
+ csr_ll_close(&pRetList->List);
+ cdf_mem_free(pRetList);
+ status = CDF_STATUS_E_NULL_VALUE;
+ } else if (phResult) {
+ *phResult = pRetList;
+ }
+ }
+ return status;
+}
+
+/*
+ * NOTE: This routine is being added to make
+ * sure that scan results are not being flushed
+ * while roaming. If the scan results are flushed,
+ * we are unable to recover from
+ * csr_roam_roaming_state_disassoc_rsp_processor.
+ * If it is needed to remove this routine,
+ * first ensure that we recover gracefully from
+ * csr_roam_roaming_state_disassoc_rsp_processor if
+ * csr_scan_get_result returns with a failure because
+ * of not being able to find the roaming BSS.
+ */
+bool csr_scan_flush_denied(tpAniSirGlobal pMac)
+{
+ uint8_t sessionId;
+
+ for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) {
+ if (CSR_IS_SESSION_VALID(pMac, sessionId)) {
+ if (csr_neighbor_middle_of_roaming(pMac, sessionId))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+CDF_STATUS csr_scan_flush_result(tpAniSirGlobal pMac)
+{
+ bool isFlushDenied = csr_scan_flush_denied(pMac);
+
+ if (isFlushDenied) {
+ sms_log(pMac, LOGW, "%s: scan flush denied in roam state %d",
+ __func__, isFlushDenied);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ sms_log(pMac, LOG4, "%s: Flushing all scan results", __func__);
+ csr_ll_scan_purge_result(pMac, &pMac->scan.tempScanResults);
+ csr_ll_scan_purge_result(pMac, &pMac->scan.scanResultList);
+ return CDF_STATUS_SUCCESS;
+}
+
+CDF_STATUS csr_scan_flush_selective_result(tpAniSirGlobal pMac, bool flushP2P)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tListElem *pEntry, *pFreeElem;
+ tCsrScanResult *pBssDesc;
+ tDblLinkList *pList = &pMac->scan.scanResultList;
+
+ csr_ll_lock(pList);
+
+ pEntry = csr_ll_peek_head(pList, LL_ACCESS_NOLOCK);
+ while (pEntry != NULL) {
+ pBssDesc = GET_BASE_ADDR(pEntry, tCsrScanResult, Link);
+ if (flushP2P == cdf_mem_compare(pBssDesc->Result.ssId.ssId,
+ "DIRECT-", 7)) {
+ pFreeElem = pEntry;
+ pEntry = csr_ll_next(pList, pEntry, LL_ACCESS_NOLOCK);
+ csr_ll_remove_entry(pList, pFreeElem, LL_ACCESS_NOLOCK);
+ csr_free_scan_result_entry(pMac, pBssDesc);
+ continue;
+ }
+ pEntry = csr_ll_next(pList, pEntry, LL_ACCESS_NOLOCK);
+ }
+
+ csr_ll_unlock(pList);
+
+ return status;
+}
+
+void csr_scan_flush_bss_entry(tpAniSirGlobal pMac,
+ tpSmeCsaOffloadInd pCsaOffloadInd)
+{
+ tListElem *pEntry, *pFreeElem;
+ tCsrScanResult *pBssDesc;
+ tDblLinkList *pList = &pMac->scan.scanResultList;
+
+ csr_ll_lock(pList);
+
+ pEntry = csr_ll_peek_head(pList, LL_ACCESS_NOLOCK);
+ while (pEntry != NULL) {
+ pBssDesc = GET_BASE_ADDR(pEntry, tCsrScanResult, Link);
+ if (cdf_mem_compare(pBssDesc->Result.BssDescriptor.bssId,
+ pCsaOffloadInd->bssId, sizeof(tSirMacAddr))) {
+ pFreeElem = pEntry;
+ pEntry = csr_ll_next(pList, pEntry, LL_ACCESS_NOLOCK);
+ csr_ll_remove_entry(pList, pFreeElem, LL_ACCESS_NOLOCK);
+ csr_free_scan_result_entry(pMac, pBssDesc);
+ sms_log(pMac, LOG1, FL("Removed BSS entry:%pM"),
+ pCsaOffloadInd->bssId);
+ continue;
+ }
+
+ pEntry = csr_ll_next(pList, pEntry, LL_ACCESS_NOLOCK);
+ }
+
+ csr_ll_unlock(pList);
+}
+
+/**
+ * csr_check11d_channel
+ *
+ ***FUNCTION:
+ * This function is called from csr_scan_filter_results function and
+ * compare channel number with given channel list.
+ *
+ ***LOGIC:
+ * Check Scan result channel number with CFG channel list
+ *
+ ***ASSUMPTIONS:
+ *
+ *
+ ***NOTE:
+ *
+ * @param channelId channel number
+ * @param pChannelList Pointer to channel list
+ * @param numChannels Number of channel in channel list
+ *
+ * @return Status
+ */
+
+CDF_STATUS csr_check11d_channel(uint8_t channelId, uint8_t *pChannelList,
+ uint32_t numChannels)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ uint8_t i = 0;
+
+ for (i = 0; i < numChannels; i++) {
+ if (pChannelList[i] == channelId) {
+ status = CDF_STATUS_SUCCESS;
+ break;
+ }
+ }
+ return status;
+}
+
+/**
+ * csr_scan_filter_results
+ *
+ ***FUNCTION:
+ * This function is called from csr_apply_country_information function and
+ * filter scan result based on valid channel list number.
+ *
+ ***LOGIC:
+ * Get scan result from scan list and Check Scan result channel number
+ * with 11d channel list if channel number is found in 11d channel list
+ * then do not remove scan result entry from scan list
+ *
+ ***ASSUMPTIONS:
+ *
+ *
+ ***NOTE:
+ *
+ * @param pMac Pointer to Global MAC structure
+ *
+ * @return Status
+ */
+
+CDF_STATUS csr_scan_filter_results(tpAniSirGlobal pMac)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tListElem *pEntry, *pTempEntry;
+ tCsrScanResult *pBssDesc;
+ uint32_t len = sizeof(pMac->roam.validChannelList);
+
+ /* Get valid channels list from CFG */
+ if (!CDF_IS_STATUS_SUCCESS(csr_get_cfg_valid_channels(pMac,
+ pMac->roam.
+ validChannelList,
+ &len))) {
+ sms_log(pMac, LOGE, "Failed to get Channel list from CFG");
+ }
+
+ csr_ll_lock(&pMac->scan.scanResultList);
+ pEntry = csr_ll_peek_head(&pMac->scan.scanResultList, LL_ACCESS_NOLOCK);
+ while (pEntry) {
+ pBssDesc = GET_BASE_ADDR(pEntry, tCsrScanResult, Link);
+ pTempEntry = csr_ll_next(&pMac->scan.scanResultList, pEntry,
+ LL_ACCESS_NOLOCK);
+ if (csr_check11d_channel(pBssDesc->Result.BssDescriptor.channelId,
+ pMac->roam.validChannelList, len)) {
+ /* Remove Scan result which does not have 11d channel */
+ if (csr_ll_remove_entry(&pMac->scan.scanResultList,
+ pEntry, LL_ACCESS_NOLOCK)) {
+ csr_free_scan_result_entry(pMac, pBssDesc);
+ }
+ } else {
+ sms_log(pMac, LOG1, FL("%d is a Valid channel"),
+ pBssDesc->Result.BssDescriptor.channelId);
+ }
+ pEntry = pTempEntry;
+ }
+
+ csr_ll_unlock(&pMac->scan.scanResultList);
+ csr_ll_lock(&pMac->scan.tempScanResults);
+
+ pEntry = csr_ll_peek_head(&pMac->scan.tempScanResults,
+ LL_ACCESS_NOLOCK);
+ while (pEntry) {
+ pBssDesc = GET_BASE_ADDR(pEntry, tCsrScanResult, Link);
+ pTempEntry = csr_ll_next(&pMac->scan.tempScanResults, pEntry,
+ LL_ACCESS_NOLOCK);
+ if (csr_check11d_channel(pBssDesc->Result.BssDescriptor.channelId,
+ pMac->roam.validChannelList, len)) {
+ /* Remove Scan result which does not have 11d channel */
+ if (csr_ll_remove_entry
+ (&pMac->scan.tempScanResults, pEntry,
+ LL_ACCESS_NOLOCK)) {
+ csr_free_scan_result_entry(pMac, pBssDesc);
+ }
+ } else {
+ sms_log(pMac, LOG1, FL("%d is a Valid channel"),
+ pBssDesc->Result.BssDescriptor.channelId);
+ }
+ pEntry = pTempEntry;
+ }
+
+ csr_ll_unlock(&pMac->scan.tempScanResults);
+ return status;
+}
+
+CDF_STATUS csr_scan_copy_result_list(tpAniSirGlobal pMac, tScanResultHandle hIn,
+ tScanResultHandle *phResult)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tScanResultList *pRetList, *pInList = (tScanResultList *) hIn;
+ tCsrScanResult *pResult, *pScanResult;
+ uint32_t count = 0;
+ tListElem *pEntry;
+ uint32_t bssLen, allocLen;
+
+ if (phResult) {
+ *phResult = CSR_INVALID_SCANRESULT_HANDLE;
+ }
+ pRetList = cdf_mem_malloc(sizeof(tScanResultList));
+ if (NULL == pRetList)
+ status = CDF_STATUS_E_NOMEM;
+ else {
+ cdf_mem_set(pRetList, sizeof(tScanResultList), 0);
+ csr_ll_open(pMac->hHdd, &pRetList->List);
+ pRetList->pCurEntry = NULL;
+ csr_ll_lock(&pMac->scan.scanResultList);
+ csr_ll_lock(&pInList->List);
+
+ pEntry = csr_ll_peek_head(&pInList->List, LL_ACCESS_NOLOCK);
+ while (pEntry) {
+ pScanResult =
+ GET_BASE_ADDR(pEntry, tCsrScanResult, Link);
+ bssLen =
+ pScanResult->Result.BssDescriptor.length +
+ sizeof(pScanResult->Result.BssDescriptor.length);
+ allocLen = sizeof(tCsrScanResult) + bssLen;
+ pResult = cdf_mem_malloc(allocLen);
+ if (NULL == pResult)
+ status = CDF_STATUS_E_NOMEM;
+ else
+ status = CDF_STATUS_SUCCESS;
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ csr_scan_result_purge(pMac,
+ (tScanResultHandle *)
+ pRetList);
+ count = 0;
+ break;
+ }
+ cdf_mem_set(pResult, allocLen, 0);
+ cdf_mem_copy(&pResult->Result.BssDescriptor,
+ &pScanResult->Result.BssDescriptor,
+ bssLen);
+ if (pScanResult->Result.pvIes) {
+ pResult->Result.pvIes =
+ cdf_mem_malloc(sizeof(tDot11fBeaconIEs));
+ if (NULL == pResult->Result.pvIes)
+ status = CDF_STATUS_E_NOMEM;
+ else
+ status = CDF_STATUS_SUCCESS;
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ /* Free the memory we allocate above first */
+ cdf_mem_free(pResult);
+ csr_scan_result_purge(pMac,
+ (tScanResultHandle *)
+ pRetList);
+ count = 0;
+ break;
+ }
+ cdf_mem_copy(pResult->Result.pvIes,
+ pScanResult->Result.pvIes,
+ sizeof(tDot11fBeaconIEs));
+ }
+ csr_ll_insert_tail(&pRetList->List, &pResult->Link,
+ LL_ACCESS_LOCK);
+ count++;
+ pEntry =
+ csr_ll_next(&pInList->List, pEntry, LL_ACCESS_NOLOCK);
+ } /* while */
+ csr_ll_unlock(&pInList->List);
+ csr_ll_unlock(&pMac->scan.scanResultList);
+
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ if (0 == count) {
+ csr_ll_close(&pRetList->List);
+ cdf_mem_free(pRetList);
+ status = CDF_STATUS_E_NULL_VALUE;
+ } else if (phResult) {
+ *phResult = pRetList;
+ }
+ }
+ } /* Allocated pRetList */
+
+ return status;
+}
+
+CDF_STATUS csr_scanning_state_msg_processor(tpAniSirGlobal pMac,
+ void *pMsgBuf)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSirMbMsg *pMsg = (tSirMbMsg *) pMsgBuf;
+ tCsrRoamSession *pSession;
+ tSirSmeAssocIndToUpperLayerCnf *pUpperLayerAssocCnf;
+ tCsrRoamInfo roamInfo;
+ tCsrRoamInfo *pRoamInfo = NULL;
+ uint32_t sessionId;
+
+ if (eWNI_SME_SCAN_RSP == pMsg->type)
+ return csr_scan_sme_scan_response(pMac, pMsgBuf);
+
+ if (pMsg->type != eWNI_SME_UPPER_LAYER_ASSOC_CNF) {
+ if (csr_is_any_session_in_connect_state(pMac)) {
+ /*
+ * In case of we are connected, we need to check whether
+ * connect status changes because scan may also run
+ * while connected.
+ */
+ csr_roam_check_for_link_status_change(pMac,
+ (tSirSmeRsp *) pMsgBuf);
+ } else {
+ sms_log(pMac, LOGW,
+ FL("Message [0x%04x] received in wrong state"),
+ pMsg->type);
+ }
+ return status;
+ }
+
+ sms_log(pMac, LOG1,
+ FL("Scanning: ASSOC cnf can be given to upper layer"));
+ cdf_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0);
+ pRoamInfo = &roamInfo;
+ pUpperLayerAssocCnf = (tSirSmeAssocIndToUpperLayerCnf *) pMsgBuf;
+ status = csr_roam_get_session_id_from_bssid(pMac,
+ (struct cdf_mac_addr *)pUpperLayerAssocCnf->bssId, &sessionId);
+ pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL("session %d not found"), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ /* send the status code as Success */
+ pRoamInfo->statusCode = eSIR_SME_SUCCESS;
+ pRoamInfo->u.pConnectedProfile = &pSession->connectedProfile;
+ pRoamInfo->staId = (uint8_t) pUpperLayerAssocCnf->aid;
+ pRoamInfo->rsnIELen = (uint8_t) pUpperLayerAssocCnf->rsnIE.length;
+ pRoamInfo->prsnIE = pUpperLayerAssocCnf->rsnIE.rsnIEdata;
+ pRoamInfo->addIELen = (uint8_t) pUpperLayerAssocCnf->addIE.length;
+ pRoamInfo->paddIE = pUpperLayerAssocCnf->addIE.addIEdata;
+ cdf_mem_copy(pRoamInfo->peerMac.bytes,
+ pUpperLayerAssocCnf->peerMacAddr,
+ CDF_MAC_ADDR_SIZE);
+ cdf_mem_copy(&pRoamInfo->bssid.bytes, pUpperLayerAssocCnf->bssId,
+ CDF_MAC_ADDR_SIZE);
+ pRoamInfo->wmmEnabledSta = pUpperLayerAssocCnf->wmmEnabledSta;
+ if (CSR_IS_INFRA_AP(pRoamInfo->u.pConnectedProfile)) {
+ pMac->roam.roamSession[sessionId].connectState =
+ eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED;
+ pRoamInfo->fReassocReq = pUpperLayerAssocCnf->reassocReq;
+ status = csr_roam_call_callback(pMac, sessionId,
+ pRoamInfo, 0,
+ eCSR_ROAM_INFRA_IND,
+ eCSR_ROAM_RESULT_INFRA_ASSOCIATION_CNF);
+ }
+ if (CSR_IS_WDS_AP(pRoamInfo->u.pConnectedProfile)) {
+ cdf_sleep(100);
+ pMac->roam.roamSession[sessionId].connectState =
+ eCSR_ASSOC_STATE_TYPE_WDS_CONNECTED;
+ status = csr_roam_call_callback(pMac, sessionId, pRoamInfo, 0,
+ eCSR_ROAM_WDS_IND,
+ eCSR_ROAM_RESULT_WDS_ASSOCIATION_IND);
+ }
+ return status;
+}
+
+void csr_check_n_save_wsc_ie(tpAniSirGlobal pMac, tSirBssDescription *pNewBssDescr,
+ tSirBssDescription *pOldBssDescr)
+{
+ int idx, len;
+ uint8_t *pbIe;
+
+ /* If failed to remove, assuming someone else got it. */
+ if ((pNewBssDescr->fProbeRsp != pOldBssDescr->fProbeRsp) &&
+ (0 == pNewBssDescr->WscIeLen)) {
+ idx = 0;
+ len = pOldBssDescr->length - sizeof(tSirBssDescription) +
+ sizeof(uint16_t) + sizeof(uint32_t) -
+ DOT11F_IE_WSCPROBERES_MIN_LEN - 2;
+ pbIe = (uint8_t *) pOldBssDescr->ieFields;
+ /* Save WPS IE if it exists */
+ pNewBssDescr->WscIeLen = 0;
+ while (idx < len) {
+ if ((DOT11F_EID_WSCPROBERES == pbIe[0]) &&
+ (0x00 == pbIe[2]) && (0x50 == pbIe[3])
+ && (0xf2 == pbIe[4]) && (0x04 == pbIe[5])) {
+ /* Founrd it */
+ if ((DOT11F_IE_WSCPROBERES_MAX_LEN - 2) >=
+ pbIe[1]) {
+ cdf_mem_copy(pNewBssDescr->
+ WscIeProbeRsp, pbIe,
+ pbIe[1] + 2);
+ pNewBssDescr->WscIeLen = pbIe[1] + 2;
+ }
+ break;
+ }
+ idx += pbIe[1] + 2;
+ pbIe += pbIe[1] + 2;
+ }
+ }
+}
+
+/* pIes may be NULL */
+bool csr_remove_dup_bss_description(tpAniSirGlobal pMac,
+ tSirBssDescription *bss_dscp,
+ tDot11fBeaconIEs *pIes, tAniSSID *pSsid,
+ v_TIME_t *timer, bool fForced)
+{
+ tListElem *pEntry;
+ tCsrScanResult *scan_entry;
+ bool fRC = false;
+ int8_t scan_entry_rssi = 0;
+
+ /*
+ * Walk through all the chained BssDescriptions. If we find a chained
+ * BssDescription that matches the BssID of the BssDescription passed
+ * in, then these must be duplicate scan results for this Bss. In that
+ * case, remove the 'old' Bss description from the linked list.
+ */
+ csr_ll_lock(&pMac->scan.scanResultList);
+ pEntry = csr_ll_peek_head(&pMac->scan.scanResultList, LL_ACCESS_NOLOCK);
+
+ while (pEntry) {
+ scan_entry = GET_BASE_ADDR(pEntry, tCsrScanResult, Link);
+ /*
+ * we have a duplicate scan results only when BSSID, SSID,
+ * Channel and NetworkType matches
+ */
+ if (csr_is_duplicate_bss_description(pMac,
+ &scan_entry->Result.BssDescriptor,
+ bss_dscp, pIes, fForced)) {
+ /*
+ * Following is mathematically a = (aX + b(100-X))/100
+ * where:
+ * a = bss_dscp->rssi, b = scan_entry_rssi
+ * and X = CSR_SCAN_RESULT_RSSI_WEIGHT
+ */
+ scan_entry_rssi = scan_entry->Result.BssDescriptor.rssi;
+ bss_dscp->rssi = (int8_t) ((((int32_t) bss_dscp->rssi *
+ CSR_SCAN_RESULT_RSSI_WEIGHT) +
+ ((int32_t) scan_entry_rssi *
+ (100 - CSR_SCAN_RESULT_RSSI_WEIGHT))) / 100);
+ /* Remove the old entry from the list */
+ if (csr_ll_remove_entry
+ (&pMac->scan.scanResultList, pEntry,
+ LL_ACCESS_NOLOCK)) {
+ /*
+ * we need to free the memory associated with
+ * this node. If failed to remove, assuming
+ * someone else got it.
+ */
+ *pSsid = scan_entry->Result.ssId;
+ *timer = scan_entry->Result.timer;
+ csr_check_n_save_wsc_ie(pMac, bss_dscp,
+ &scan_entry->Result.
+ BssDescriptor);
+ csr_free_scan_result_entry(pMac, scan_entry);
+ } else {
+ sms_log(pMac, LOGW, FL("fail to remove entry"));
+ }
+ fRC = true;
+ /*
+ * If we found a match, we can stop looking through
+ * the list.
+ */
+ break;
+ }
+ pEntry = csr_ll_next(&pMac->scan.scanResultList, pEntry,
+ LL_ACCESS_NOLOCK);
+ }
+
+ csr_ll_unlock(&pMac->scan.scanResultList);
+ return fRC;
+}
+
+CDF_STATUS csr_add_pmkid_candidate_list(tpAniSirGlobal pMac, uint32_t sessionId,
+ tSirBssDescription *pBssDesc,
+ tDot11fBeaconIEs *pIes)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+ tPmkidCandidateInfo *pmkid_info = NULL;
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+ WLAN_HOST_DIAG_EVENT_DEF(secEvent,
+ host_event_wlan_security_payload_type);
+#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ sms_log(pMac, LOGW, FL("NumPmkidCandidate = %d"),
+ pSession->NumPmkidCandidate);
+ if (!pIes)
+ return status;
+ /* check if this is a RSN BSS */
+ if (!pIes->RSN.present)
+ return status;
+
+ if (pSession->NumPmkidCandidate >= CSR_MAX_PMKID_ALLOWED)
+ return CDF_STATUS_E_FAILURE;
+
+ /* BSS is capable of doing pre-authentication */
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+ cdf_mem_set(&secEvent, sizeof(host_event_wlan_security_payload_type),
+ 0);
+ secEvent.eventId = WLAN_SECURITY_EVENT_PMKID_CANDIDATE_FOUND;
+ secEvent.encryptionModeMulticast = (uint8_t)diag_enc_type_from_csr_type(
+ pSession->connectedProfile.mcEncryptionType);
+ secEvent.encryptionModeUnicast = (uint8_t)diag_enc_type_from_csr_type(
+ pSession->connectedProfile.EncryptionType);
+ cdf_mem_copy(secEvent.bssid, pSession->connectedProfile.bssid.bytes,
+ CDF_MAC_ADDR_SIZE);
+ secEvent.authMode = (uint8_t)diag_auth_type_from_csr_type(
+ pSession->connectedProfile.AuthType);
+ WLAN_HOST_DIAG_EVENT_REPORT(&secEvent, EVENT_WLAN_SECURITY);
+#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */
+
+ pmkid_info = &pSession->PmkidCandidateInfo[pSession->NumPmkidCandidate];
+ /* if yes, then add to PMKIDCandidateList */
+ cdf_mem_copy(pmkid_info->BSSID.bytes, pBssDesc->bssId,
+ CDF_MAC_ADDR_SIZE);
+ /* Bit 0 offirst byte - PreAuthentication Capability */
+ if ((pIes->RSN.RSN_Cap[0] >> 0) & 0x1)
+ pmkid_info->preAuthSupported = true;
+ else
+ pmkid_info->preAuthSupported = false;
+ pSession->NumPmkidCandidate++;
+ return status;
+}
+
+/*
+ * This function checks whether new AP is found for the current connected
+ * profile. If it is found, it return the sessionId, else it return invalid
+ * sessionID
+ */
+CDF_STATUS csr_process_bss_desc_for_pmkid_list(tpAniSirGlobal pMac,
+ tSirBssDescription *pBssDesc,
+ tDot11fBeaconIEs *pIes,
+ uint8_t sessionId)
+{
+ tCsrRoamSession *pSession;
+ tDot11fBeaconIEs *pIesLocal = pIes;
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+
+ if (!(pIesLocal ||
+ CDF_IS_STATUS_SUCCESS(
+ csr_get_parsed_bss_description_ies(pMac, pBssDesc,
+ &pIesLocal))))
+ return status;
+
+ if (!CSR_IS_SESSION_VALID(pMac, sessionId)) {
+ if (!pIes)
+ cdf_mem_free(pIesLocal);
+ return status;
+ }
+
+ pSession = CSR_GET_SESSION(pMac, sessionId);
+ if (csr_is_conn_state_connected_infra(pMac, sessionId)
+ && (eCSR_AUTH_TYPE_RSN == pSession->connectedProfile.AuthType)
+ && csr_match_bss_to_connect_profile(pMac,
+ &pSession->connectedProfile,
+ pBssDesc, pIesLocal)) {
+ /* This new BSS fits the current profile connected */
+ status = csr_add_pmkid_candidate_list(pMac, sessionId,
+ pBssDesc, pIesLocal);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ sms_log(pMac, LOGE,
+ FL("csr_add_pmkid_candidate_list failed"));
+ else
+ status = CDF_STATUS_SUCCESS;
+ }
+
+ if (!pIes)
+ cdf_mem_free(pIesLocal);
+
+ return status;
+}
+
+#ifdef FEATURE_WLAN_WAPI
+CDF_STATUS csr_add_bkid_candidate_list(tpAniSirGlobal pMac, uint32_t sessionId,
+ tSirBssDescription *pBssDesc,
+ tDot11fBeaconIEs *pIes)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ sms_log(pMac, LOGW,
+ "csr_add_bkid_candidate_list called pMac->scan.NumBkidCandidate = %d",
+ pSession->NumBkidCandidate);
+ if (pIes) {
+ /* check if this is a WAPI BSS */
+ if (pIes->WAPI.present) {
+ /* Check if the BSS is capable of doing pre-authentication */
+ if (pSession->NumBkidCandidate < CSR_MAX_BKID_ALLOWED) {
+
+ /* if yes, then add to BKIDCandidateList */
+ cdf_mem_copy(pSession->
+ BkidCandidateInfo[pSession->
+ NumBkidCandidate].
+ BSSID.bytes, pBssDesc->bssId,
+ CDF_MAC_ADDR_SIZE);
+ if (pIes->WAPI.preauth) {
+ pSession->BkidCandidateInfo[pSession->
+ NumBkidCandidate].
+ preAuthSupported = true;
+ } else {
+ pSession->BkidCandidateInfo[pSession->
+ NumBkidCandidate].
+ preAuthSupported = false;
+ }
+ pSession->NumBkidCandidate++;
+ } else {
+ status = CDF_STATUS_E_FAILURE;
+ }
+ }
+ }
+
+ return status;
+}
+
+/*
+ * This function checks whether new AP is found for the current connected
+ * profile, if so add to BKIDCandidateList
+ */
+bool csr_process_bss_desc_for_bkid_list(tpAniSirGlobal pMac,
+ tSirBssDescription *pBssDesc,
+ tDot11fBeaconIEs *pIes)
+{
+ bool fRC = false;
+ tDot11fBeaconIEs *pIesLocal = pIes;
+ uint32_t sessionId;
+ tCsrRoamSession *pSession;
+ CDF_STATUS status;
+
+ if (!(pIesLocal ||
+ CDF_IS_STATUS_SUCCESS(
+ csr_get_parsed_bss_description_ies(pMac, pBssDesc,
+ &pIesLocal))))
+ return fRC;
+
+ for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) {
+ if (!CSR_IS_SESSION_VALID(pMac, sessionId))
+ continue;
+ pSession = CSR_GET_SESSION(pMac, sessionId);
+ if (csr_is_conn_state_connected_infra(pMac, sessionId)
+ && (eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE ==
+ pSession->connectedProfile.AuthType)
+ && csr_match_bss_to_connect_profile(pMac,
+ &pSession->connectedProfile,
+ pBssDesc, pIesLocal)) {
+ /* this new BSS fits the current profile connected */
+ status = csr_add_bkid_candidate_list(pMac, sessionId,
+ pBssDesc, pIesLocal);
+ if (CDF_IS_STATUS_SUCCESS(status))
+ fRC = true;
+ }
+ }
+ if (!pIes)
+ cdf_mem_free(pIesLocal);
+ return fRC;
+}
+
+#endif
+
+static void
+csr_remove_from_tmp_list(tpAniSirGlobal mac_ctx,
+ uint8_t reason,
+ uint8_t session_id)
+{
+ CDF_STATUS status;
+ tListElem *entry;
+ tCsrScanResult *bss_dscp;
+ tDot11fBeaconIEs *local_ie = NULL;
+ bool dup_bss;
+ tAniSSID tmpSsid;
+ v_TIME_t timer = 0;
+
+ tmpSsid.length = 0;
+ while ((entry = csr_ll_remove_tail(&mac_ctx->scan.tempScanResults,
+ LL_ACCESS_LOCK)) != NULL) {
+ bss_dscp = GET_BASE_ADDR(entry, tCsrScanResult, Link);
+ sms_log(mac_ctx, LOG2,
+ FL("...Bssid= "MAC_ADDRESS_STR" chan= %d, rssi = -%d"),
+ MAC_ADDR_ARRAY(bss_dscp->Result.BssDescriptor.
+ bssId),
+ bss_dscp->Result.BssDescriptor.channelId,
+ bss_dscp->Result.BssDescriptor.rssi * (-1));
+
+ /* At this time, bss_dscp->Result.pvIes may be NULL */
+ local_ie = (tDot11fBeaconIEs *)(bss_dscp->Result.pvIes);
+ status = csr_get_parsed_bss_description_ies(mac_ctx,
+ &bss_dscp->Result.BssDescriptor, &local_ie);
+ if (!(local_ie || CDF_IS_STATUS_SUCCESS(status))) {
+ sms_log(mac_ctx, LOGE, FL("Cannot pared IEs"));
+ csr_free_scan_result_entry(mac_ctx, bss_dscp);
+ continue;
+ }
+ dup_bss = csr_remove_dup_bss_description(mac_ctx,
+ &bss_dscp->Result.BssDescriptor,
+ local_ie, &tmpSsid, &timer, false);
+ /*
+ * Check whether we have reach out limit, but don't lose the
+ * LFR candidates came from FW
+ */
+ if (CSR_SCAN_IS_OVER_BSS_LIMIT(mac_ctx)) {
+ sms_log(mac_ctx, LOGW, FL("BSS limit reached"));
+ if ((bss_dscp->Result.pvIes == NULL) && local_ie)
+ cdf_mem_free(local_ie);
+ csr_free_scan_result_entry(mac_ctx, bss_dscp);
+ /* Continue because there may be duplicated BSS */
+ continue;
+ }
+ /* check for duplicate scan results */
+ if (!dup_bss) {
+ status = csr_process_bss_desc_for_pmkid_list(mac_ctx,
+ &bss_dscp->Result.BssDescriptor,
+ local_ie, session_id);
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ /* Found a new BSS */
+ csr_roam_call_callback(mac_ctx, session_id,
+ NULL, 0, eCSR_ROAM_SCAN_FOUND_NEW_BSS,
+ eCSR_ROAM_RESULT_NONE);
+ }
+ } else {
+ /*
+ * Check if the new one has SSID it it, if not, use
+ * the older SSID if it exists.
+ *
+ * New BSS has a hidden SSID and old one has the SSID.
+ * Keep the SSID only if diff of saved SSID time and
+ * current time is less than 1 min to avoid side effect
+ * of saving SSID with old one is that if AP changes
+ * its SSID while remain hidden, we may never see it
+ * and also to address the requirement of When we remove
+ * hidden ssid from the profile i.e., forget the SSID
+ * via GUI that SSID shouldn't see in the profile
+ */
+ v_TIME_t time_gap = cdf_mc_timer_get_system_time() -
+ timer;
+ if ((0 == bss_dscp->Result.ssId.length)
+ && (time_gap <= HIDDEN_TIMER)
+ && tmpSsid.length) {
+ bss_dscp->Result.timer = timer;
+ bss_dscp->Result.ssId = tmpSsid;
+ }
+ }
+
+ if (csr_is11d_supported(mac_ctx)
+ && local_ie->Country.present) {
+ csr_add_vote_for_country_info(mac_ctx,
+ local_ie->Country.country);
+ sms_log(mac_ctx, LOGW,
+ FL("11d AP Bssid "MAC_ADDRESS_STR
+ " chan= %d, rssi = -%d, countryCode %c%c"),
+ MAC_ADDR_ARRAY(
+ bss_dscp->Result.BssDescriptor.bssId),
+ bss_dscp->Result.BssDescriptor.channelId,
+ bss_dscp->Result.BssDescriptor.rssi * (-1),
+ local_ie->Country.country[0],
+ local_ie->Country.country[1]);
+ }
+ /* append to main list */
+ csr_scan_add_result(mac_ctx, bss_dscp, local_ie, session_id);
+ if ((bss_dscp->Result.pvIes == NULL) && local_ie)
+ cdf_mem_free(local_ie);
+ } /* end of loop */
+}
+
+static void csr_move_temp_scan_results_to_main_list(tpAniSirGlobal pMac,
+ uint8_t reason,
+ uint8_t sessionId)
+{
+ tCsrRoamSession *pSession;
+ uint32_t i;
+
+ /* remove the BSS descriptions from temporary list */
+ csr_remove_from_tmp_list(pMac, reason, sessionId);
+ /*
+ * We don't need to update CC while connected to an AP which is
+ * advertising CC already
+ */
+ if (!csr_is11d_supported(pMac))
+ return;
+
+ for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
+ if (!CSR_IS_SESSION_VALID(pMac, i))
+ continue;
+ pSession = CSR_GET_SESSION(pMac, i);
+ if (csr_is_conn_state_connected(pMac, i)) {
+ sms_log(pMac, LOGW,
+ FL("No need to update CC in connected state"));
+ return;
+ }
+ }
+ csr_elected_country_info(pMac);
+ csr_learn_11dcountry_information(pMac, NULL, NULL, true);
+}
+
+static tCsrScanResult *csr_scan_save_bss_description(tpAniSirGlobal pMac,
+ tSirBssDescription *
+ pBSSDescription,
+ tDot11fBeaconIEs *pIes,
+ uint8_t sessionId)
+{
+ tCsrScanResult *pCsrBssDescription = NULL;
+ uint32_t cbBSSDesc;
+ uint32_t cbAllocated;
+
+ /* figure out how big the BSS description is (the BSSDesc->length does NOT */
+ /* include the size of the length field itself). */
+ cbBSSDesc = pBSSDescription->length + sizeof(pBSSDescription->length);
+
+ cbAllocated = sizeof(tCsrScanResult) + cbBSSDesc;
+
+ pCsrBssDescription = cdf_mem_malloc(cbAllocated);
+ if (NULL != pCsrBssDescription) {
+ cdf_mem_set(pCsrBssDescription, cbAllocated, 0);
+ pCsrBssDescription->AgingCount =
+ (int32_t) pMac->roam.configParam.agingCount;
+ sms_log(pMac, LOGW,
+ FL(" Set Aging Count = %d for BSS " MAC_ADDRESS_STR " "),
+ pCsrBssDescription->AgingCount,
+ MAC_ADDR_ARRAY(pCsrBssDescription->Result.BssDescriptor.
+ bssId));
+ cdf_mem_copy(&pCsrBssDescription->Result.BssDescriptor,
+ pBSSDescription, cbBSSDesc);
+#if defined(CDF_ENSBALED)
+ if (NULL != pCsrBssDescription->Result.pvIes) {
+ CDF_ASSERT(pCsrBssDescription->Result.pvIes == NULL);
+ return NULL;
+ }
+#endif
+ csr_scan_add_result(pMac, pCsrBssDescription, pIes, sessionId);
+ }
+
+ return pCsrBssDescription;
+}
+
+/* Append a Bss Description... */
+tCsrScanResult *csr_scan_append_bss_description(tpAniSirGlobal pMac,
+ tSirBssDescription *
+ pSirBssDescription,
+ tDot11fBeaconIEs *pIes,
+ bool fForced, uint8_t sessionId)
+{
+ tCsrScanResult *pCsrBssDescription = NULL;
+ tAniSSID tmpSsid;
+ v_TIME_t timer = 0;
+ int result;
+
+ tmpSsid.length = 0;
+ result = csr_remove_dup_bss_description(pMac, pSirBssDescription,
+ pIes, &tmpSsid, &timer,
+ fForced);
+ pCsrBssDescription = csr_scan_save_bss_description(pMac,
+ pSirBssDescription, pIes, sessionId);
+ if (result && (pCsrBssDescription != NULL)) {
+ /*
+ * Check if the new one has SSID it it, if not, use the older
+ * SSID if it exists.
+ */
+ if ((0 == pCsrBssDescription->Result.ssId.length)
+ && tmpSsid.length) {
+ /*
+ * New BSS has a hidden SSID and old one has the SSID.
+ * Keep the SSID only if diff of saved SSID time and
+ * current time is less than 1 min to avoid side effect
+ * of saving SSID with old one is that if AP changes its
+ * SSID while remain hidden, we may never see it and
+ * also to address the requirement of. When we remove
+ * hidden ssid from the profile i.e., forget the SSID
+ * via GUI that SSID shouldn't see in the profile
+ */
+ if ((cdf_mc_timer_get_system_time() - timer) <=
+ HIDDEN_TIMER) {
+ pCsrBssDescription->Result.ssId = tmpSsid;
+ pCsrBssDescription->Result.timer = timer;
+ }
+ }
+ }
+
+ return pCsrBssDescription;
+}
+
+void csr_purge_channel_power(tpAniSirGlobal pMac, tDblLinkList *pChannelList)
+{
+ tCsrChannelPowerInfo *pChannelSet;
+ tListElem *pEntry;
+
+ csr_ll_lock(pChannelList);
+ /*
+ * Remove the channel sets from the learned list and put them
+ * in the free list
+ */
+ while ((pEntry = csr_ll_remove_head(pChannelList,
+ LL_ACCESS_NOLOCK)) != NULL) {
+ pChannelSet = GET_BASE_ADDR(pEntry, tCsrChannelPowerInfo, link);
+ if (pChannelSet)
+ cdf_mem_free(pChannelSet);
+ }
+ csr_ll_unlock(pChannelList);
+ return;
+}
+
+/*
+ * Save the channelList into the ultimate storage as the final stage of channel
+ * Input: pCountryInfo -- the country code (e.g. "USI"), channel list, and power
+ * limit are all stored inside this data structure
+ */
+CDF_STATUS csr_save_to_channel_power2_g_5_g(tpAniSirGlobal pMac,
+ uint32_t tableSize,
+ tSirMacChanInfo *channelTable)
+{
+ uint32_t i = tableSize / sizeof(tSirMacChanInfo);
+ tSirMacChanInfo *pChannelInfo;
+ tCsrChannelPowerInfo *pChannelSet;
+ bool f2GHzInfoFound = false;
+ bool f2GListPurged = false, f5GListPurged = false;
+
+ pChannelInfo = channelTable;
+ /* atleast 3 bytes have to be remaining -- from "countryString" */
+ while (i--) {
+ pChannelSet = cdf_mem_malloc(sizeof(tCsrChannelPowerInfo));
+ if (NULL == pChannelSet) {
+ pChannelInfo++;
+ continue;
+ }
+ cdf_mem_set(pChannelSet, sizeof(tCsrChannelPowerInfo), 0);
+ pChannelSet->firstChannel = pChannelInfo->firstChanNum;
+ pChannelSet->numChannels = pChannelInfo->numChannels;
+ /*
+ * Now set the inter-channel offset based on the frequency band
+ * the channel set lies in
+ */
+ if ((CDS_IS_CHANNEL_24GHZ(pChannelSet->firstChannel)) &&
+ ((pChannelSet->firstChannel +
+ (pChannelSet->numChannels - 1)) <=
+ CDS_MAX_24GHz_CHANNEL_NUMBER)) {
+ pChannelSet->interChannelOffset = 1;
+ f2GHzInfoFound = true;
+ } else if ((CDS_IS_CHANNEL_5GHZ(pChannelSet->firstChannel))
+ && ((pChannelSet->firstChannel +
+ ((pChannelSet->numChannels - 1) * 4)) <=
+ CDS_MAX_5GHz_CHANNEL_NUMBER)) {
+ pChannelSet->interChannelOffset = 4;
+ f2GHzInfoFound = false;
+ } else {
+ sms_log(pMac, LOGW,
+ FL("Invalid Channel %d Present in Country IE"),
+ pChannelSet->firstChannel);
+ cdf_mem_free(pChannelSet);
+ return CDF_STATUS_E_FAILURE;
+ }
+ pChannelSet->txPower = CDF_MIN(pChannelInfo->maxTxPower,
+ pMac->roam.configParam.nTxPowerCap);
+ if (f2GHzInfoFound) {
+ if (!f2GListPurged) {
+ /* purge previous results if found new */
+ csr_purge_channel_power(pMac,
+ &pMac->scan.
+ channelPowerInfoList24);
+ f2GListPurged = true;
+ }
+ if (CSR_IS_OPERATING_BG_BAND(pMac)) {
+ /* add to the list of 2.4 GHz channel sets */
+ csr_ll_insert_tail(&pMac->scan.
+ channelPowerInfoList24,
+ &pChannelSet->link,
+ LL_ACCESS_LOCK);
+ } else {
+ sms_log(pMac, LOGW,
+ FL("Adding 11B/G ch in 11A. 1st ch %d"),
+ pChannelSet->firstChannel);
+ cdf_mem_free(pChannelSet);
+ }
+ } else {
+ /* 5GHz info found */
+ if (!f5GListPurged) {
+ /* purge previous results if found new */
+ csr_purge_channel_power(pMac,
+ &pMac->scan.
+ channelPowerInfoList5G);
+ f5GListPurged = true;
+ }
+ if (CSR_IS_OPERATING_A_BAND(pMac)) {
+ /* add to the list of 5GHz channel sets */
+ csr_ll_insert_tail(&pMac->scan.
+ channelPowerInfoList5G,
+ &pChannelSet->link,
+ LL_ACCESS_LOCK);
+ } else {
+ sms_log(pMac, LOGW,
+ FL("Adding 11A ch in B/G. 1st ch %d"),
+ pChannelSet->firstChannel);
+ cdf_mem_free(pChannelSet);
+ }
+ }
+ pChannelInfo++; /* move to next entry */
+ }
+ return CDF_STATUS_SUCCESS;
+}
+
+static void csr_clear_dfs_channel_list(tpAniSirGlobal pMac)
+{
+ tSirMbMsg *pMsg;
+ uint16_t msgLen;
+
+ msgLen = (uint16_t) (sizeof(tSirMbMsg));
+ pMsg = cdf_mem_malloc(msgLen);
+ if (NULL != pMsg) {
+ cdf_mem_set((void *)pMsg, msgLen, 0);
+ pMsg->type = eWNI_SME_CLEAR_DFS_CHANNEL_LIST;
+ pMsg->msgLen = msgLen;
+ cds_send_mb_message_to_mac(pMsg);
+ }
+}
+
+void csr_apply_power2_current(tpAniSirGlobal pMac)
+{
+ sms_log(pMac, LOG3, FL(" Updating Cfg with power settings"));
+ csr_save_tx_power_to_cfg(pMac, &pMac->scan.channelPowerInfoList24,
+ WNI_CFG_MAX_TX_POWER_2_4);
+ csr_save_tx_power_to_cfg(pMac, &pMac->scan.channelPowerInfoList5G,
+ WNI_CFG_MAX_TX_POWER_5);
+}
+
+void csr_apply_channel_power_info_to_fw(tpAniSirGlobal mac_ctx,
+ tCsrChannel *ch_lst,
+ uint8_t *countryCode)
+{
+ int i;
+ uint8_t num_ch = 0;
+ uint8_t tempNumChannels = 0;
+ tCsrChannel tmp_ch_lst;
+
+ if (ch_lst->numChannels) {
+ tempNumChannels = CSR_MIN(ch_lst->numChannels,
+ WNI_CFG_VALID_CHANNEL_LIST_LEN);
+ for (i = 0; i < tempNumChannels; i++) {
+ tmp_ch_lst.channelList[num_ch] = ch_lst->channelList[i];
+ num_ch++;
+ }
+ tmp_ch_lst.numChannels = num_ch;
+ /* Store the channel+power info in the global place: Cfg */
+ csr_apply_power2_current(mac_ctx);
+ csr_set_cfg_valid_channel_list(mac_ctx, tmp_ch_lst.channelList,
+ tmp_ch_lst.numChannels);
+ /*
+ * extend scan capability, build a scan list based on the
+ * channel list : channel# + active/passive scan
+ */
+ csr_set_cfg_scan_control_list(mac_ctx, countryCode,
+ &tmp_ch_lst);
+ /* Send msg to Lim to clear DFS channel list */
+ csr_clear_dfs_channel_list(mac_ctx);
+ } else {
+ sms_log(mac_ctx, LOGE, FL("11D channel list is empty"));
+ }
+ csr_set_cfg_country_code(mac_ctx, countryCode);
+}
+
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+static void csr_diag_reset_country_information(tpAniSirGlobal pMac)
+{
+
+ host_log_802_11d_pkt_type *p11dLog;
+ int Index;
+ WLAN_HOST_DIAG_LOG_ALLOC(p11dLog, host_log_802_11d_pkt_type,
+ LOG_WLAN_80211D_C);
+ if (!p11dLog)
+ return;
+
+ p11dLog->eventId = WLAN_80211D_EVENT_RESET;
+ cdf_mem_copy(p11dLog->countryCode, pMac->scan.countryCodeCurrent, 3);
+ p11dLog->numChannel = pMac->scan.base_channels.numChannels;
+ if (p11dLog->numChannel <= HOST_LOG_MAX_NUM_CHANNEL) {
+ cdf_mem_copy(p11dLog->Channels,
+ pMac->scan.base_channels.channelList,
+ p11dLog->numChannel);
+ for (Index = 0;
+ Index < pMac->scan.base_channels.numChannels;
+ Index++) {
+ p11dLog->TxPwr[Index] = CDF_MIN(
+ pMac->scan.defaultPowerTable[Index].pwr,
+ pMac->roam.configParam.nTxPowerCap);
+ }
+ }
+ if (!pMac->roam.configParam.Is11dSupportEnabled)
+ p11dLog->supportMultipleDomain = WLAN_80211D_DISABLED;
+ else
+ p11dLog->supportMultipleDomain =
+ WLAN_80211D_SUPPORT_MULTI_DOMAIN;
+ WLAN_HOST_DIAG_LOG_REPORT(p11dLog);
+}
+#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */
+
+/**
+ * csr_apply_channel_power_info_wrapper() - sends channel info to fw
+ * @pMac: main MAC data structure
+ *
+ * This function sends the channel power info to firmware
+ *
+ * Return: none
+ */
+void csr_apply_channel_power_info_wrapper(tpAniSirGlobal pMac)
+{
+
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+ csr_diag_reset_country_information(pMac);
+#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */
+ csr_prune_channel_list_for_mode(pMac, &pMac->scan.base_channels);
+ csr_save_channel_power_for_band(pMac, false);
+ csr_save_channel_power_for_band(pMac, true);
+ /* apply the channel list, power settings, and the country code. */
+ csr_apply_channel_power_info_to_fw(pMac,
+ &pMac->scan.base_channels, pMac->scan.countryCodeCurrent);
+ /* clear the 11d channel list */
+ cdf_mem_set(&pMac->scan.channels11d, sizeof(pMac->scan.channels11d), 0);
+}
+
+void csr_clear_votes_for_country_info(tpAniSirGlobal pMac)
+{
+ pMac->scan.countryCodeCount = 0;
+ cdf_mem_set(pMac->scan.votes11d,
+ sizeof(tCsrVotes11d) * CSR_MAX_NUM_COUNTRY_CODE, 0);
+}
+
+void csr_add_vote_for_country_info(tpAniSirGlobal pMac, uint8_t *pCountryCode)
+{
+ bool match = false;
+ uint8_t i;
+
+ /* convert to UPPER here so we are assured
+ * the strings are always in upper case.
+ */
+ for (i = 0; i < 3; i++) {
+ pCountryCode[i] = (uint8_t) csr_to_upper(pCountryCode[i]);
+ }
+
+ /* Some of the 'old' Cisco 350 series AP's advertise NA as the
+ * country code (for North America ??). NA is not a valid country code
+ * or domain so let's allow this by changing it to the proper
+ * country code (which is US). We've also seen some NETGEAR AP's
+ * that have "XX " as the country code with valid 2.4 GHz US channel
+ * information. If we cannot find the country code advertised in the
+ * 11d information element, let's default to US.
+ */
+
+ if (!CDF_IS_STATUS_SUCCESS(csr_get_regulatory_domain_for_country(pMac,
+ pCountryCode, NULL,
+ COUNTRY_QUERY))) {
+ pCountryCode[0] = '0';
+ pCountryCode[1] = '0';
+ }
+
+ /* We've seen some of the AP's improperly put a 0 for the
+ * third character of the country code. spec says valid charcters are
+ * 'O' (for outdoor), 'I' for Indoor, or ' ' (space; for either).
+ * if we see a 0 in this third character, let's change it to a ' '.
+ */
+ if (0 == pCountryCode[2]) {
+ pCountryCode[2] = ' ';
+ }
+
+ for (i = 0; i < pMac->scan.countryCodeCount; i++) {
+ match = (cdf_mem_compare(pMac->scan.votes11d[i].countryCode,
+ pCountryCode, 2));
+ if (match) {
+ break;
+ }
+ }
+
+ if (match) {
+ pMac->scan.votes11d[i].votes++;
+ } else {
+ cdf_mem_copy(pMac->scan.votes11d[pMac->scan.countryCodeCount].
+ countryCode, pCountryCode, 3);
+ pMac->scan.votes11d[pMac->scan.countryCodeCount].votes = 1;
+ pMac->scan.countryCodeCount++;
+ }
+
+ return;
+}
+
+bool csr_elected_country_info(tpAniSirGlobal pMac)
+{
+ bool fRet = false;
+ uint8_t maxVotes = 0;
+ uint8_t i, j = 0;
+
+ if (!pMac->scan.countryCodeCount) {
+ return fRet;
+ }
+ maxVotes = pMac->scan.votes11d[0].votes;
+ fRet = true;
+
+ for (i = 1; i < pMac->scan.countryCodeCount; i++) {
+ /* If we have a tie for max votes for 2 different country codes,
+ * pick random.we can put some more intelligence - TBD
+ */
+ if (maxVotes < pMac->scan.votes11d[i].votes) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ " Votes for Country %c%c : %d\n",
+ pMac->scan.votes11d[i].countryCode[0],
+ pMac->scan.votes11d[i].countryCode[1],
+ pMac->scan.votes11d[i].votes);
+
+ maxVotes = pMac->scan.votes11d[i].votes;
+ j = i;
+ fRet = true;
+ }
+
+ }
+ if (fRet) {
+ cdf_mem_copy(pMac->scan.countryCodeElected,
+ pMac->scan.votes11d[j].countryCode,
+ WNI_CFG_COUNTRY_CODE_LEN);
+ cdf_mem_copy(pMac->scan.countryCode11d,
+ pMac->scan.votes11d[j].countryCode,
+ WNI_CFG_COUNTRY_CODE_LEN);
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ "Selected Country is %c%c With count %d\n",
+ pMac->scan.votes11d[j].countryCode[0],
+ pMac->scan.votes11d[j].countryCode[1],
+ pMac->scan.votes11d[j].votes);
+ }
+ return fRet;
+}
+
+/**
+ * csr_set_country_code() - Set country code
+ * @pMac: main MAC data structure
+ * @pCountry: ptr to Country Code
+ *
+ * This function sends the channel power info to firmware
+ *
+ * Return: none
+ */
+CDF_STATUS csr_set_country_code(tpAniSirGlobal pMac, uint8_t *pCountry)
+{
+ CDF_STATUS status = CDF_STATUS_E_INVAL;
+ v_REGDOMAIN_t domainId;
+
+ if (pCountry) {
+
+ status = csr_get_regulatory_domain_for_country(pMac, pCountry,
+ &domainId,
+ COUNTRY_USER);
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ cdf_mem_copy(pMac->scan.countryCodeCurrent,
+ pCountry,
+ WNI_CFG_COUNTRY_CODE_LEN);
+ csr_set_cfg_country_code(pMac, pCountry);
+ }
+ }
+ return status;
+}
+
+/* caller allocated memory for pNumChn and pChnPowerInfo */
+/* As input, *pNumChn has the size of the array of pChnPowerInfo */
+/* Upon return, *pNumChn has the number of channels assigned. */
+void csr_get_channel_power_info(tpAniSirGlobal pMac, tDblLinkList *list,
+ uint32_t *num_ch,
+ tChannelListWithPower *chn_pwr_info)
+{
+ tListElem *entry;
+ uint32_t chn_idx = 0, idx;
+ tCsrChannelPowerInfo *ch_set;
+
+ /* Get 2.4Ghz first */
+ entry = csr_ll_peek_head(list, LL_ACCESS_LOCK);
+ while (entry && (chn_idx < *num_ch)) {
+ ch_set = GET_BASE_ADDR(entry, tCsrChannelPowerInfo, link);
+ for (idx = 0; (idx < ch_set->numChannels)
+ && (chn_idx < *num_ch); idx++) {
+ chn_pwr_info[chn_idx].chanId =
+ (uint8_t) (ch_set->firstChannel
+ + (idx * ch_set->interChannelOffset));
+ chn_pwr_info[chn_idx++].pwr = ch_set->txPower;
+ }
+ entry = csr_ll_next(list, entry, LL_ACCESS_LOCK);
+ }
+ *num_ch = chn_idx;
+
+ return;
+}
+
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+void csr_diag_apply_country_info(tpAniSirGlobal mac_ctx)
+{
+ host_log_802_11d_pkt_type *p11dLog;
+ tChannelListWithPower chnPwrInfo[WNI_CFG_VALID_CHANNEL_LIST_LEN];
+ uint32_t nChnInfo = WNI_CFG_VALID_CHANNEL_LIST_LEN, nTmp;
+
+ WLAN_HOST_DIAG_LOG_ALLOC(p11dLog, host_log_802_11d_pkt_type,
+ LOG_WLAN_80211D_C);
+ if (!p11dLog)
+ return;
+
+ p11dLog->eventId = WLAN_80211D_EVENT_COUNTRY_SET;
+ cdf_mem_copy(p11dLog->countryCode, mac_ctx->scan.countryCode11d, 3);
+ p11dLog->numChannel = mac_ctx->scan.channels11d.numChannels;
+ if (p11dLog->numChannel > HOST_LOG_MAX_NUM_CHANNEL)
+ goto diag_end;
+
+ cdf_mem_copy(p11dLog->Channels,
+ mac_ctx->scan.channels11d.channelList,
+ p11dLog->numChannel);
+ csr_get_channel_power_info(mac_ctx,
+ &mac_ctx->scan.channelPowerInfoList24,
+ &nChnInfo, chnPwrInfo);
+ nTmp = nChnInfo;
+ nChnInfo = WNI_CFG_VALID_CHANNEL_LIST_LEN - nTmp;
+ csr_get_channel_power_info(mac_ctx,
+ &mac_ctx->scan.channelPowerInfoList5G,
+ &nChnInfo, &chnPwrInfo[nTmp]);
+ for (nTmp = 0; nTmp < p11dLog->numChannel; nTmp++) {
+ for (nChnInfo = 0;
+ nChnInfo < WNI_CFG_VALID_CHANNEL_LIST_LEN;
+ nChnInfo++) {
+ if (p11dLog->Channels[nTmp] ==
+ chnPwrInfo[nChnInfo].chanId) {
+ p11dLog->TxPwr[nTmp] =
+ chnPwrInfo[nChnInfo].pwr;
+ break;
+ }
+ }
+ }
+diag_end:
+ if (!mac_ctx->roam.configParam.Is11dSupportEnabled)
+ p11dLog->supportMultipleDomain = WLAN_80211D_DISABLED;
+ else
+ p11dLog->supportMultipleDomain =
+ WLAN_80211D_SUPPORT_MULTI_DOMAIN;
+ WLAN_HOST_DIAG_LOG_REPORT(p11dLog);
+}
+#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */
+
+/**
+ * csr_apply_country_information() - apply country code information
+ * @pMac: core MAC data structure
+ *
+ * This function programs the new country code
+ *
+ * Return: none
+ */
+void csr_apply_country_information(tpAniSirGlobal pMac)
+{
+ v_REGDOMAIN_t domainId;
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+
+ if (!csr_is11d_supported(pMac)
+ || 0 == pMac->scan.channelOf11dInfo)
+ return;
+ status = csr_get_regulatory_domain_for_country(pMac,
+ pMac->scan.countryCode11d, &domainId, COUNTRY_QUERY);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ return;
+ /* Check whether we need to enforce default domain */
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+ csr_diag_apply_country_info(pMac);
+#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */
+
+ if (pMac->scan.domainIdCurrent != domainId)
+ return;
+ if (pMac->scan.domainIdCurrent != domainId) {
+ sms_log(pMac, LOGW, FL("Domain Changed Old %d, new %d"),
+ pMac->scan.domainIdCurrent, domainId);
+ status = wma_set_reg_domain(pMac, domainId);
+ }
+ if (status != CDF_STATUS_SUCCESS)
+ sms_log(pMac, LOGE, FL("fail to set regId %d"), domainId);
+ pMac->scan.domainIdCurrent = domainId;
+ /* switch to active scans using this new channel list */
+ pMac->scan.curScanType = eSIR_ACTIVE_SCAN;
+}
+
+void csr_save_channel_power_for_band(tpAniSirGlobal pMac, bool fill_5f)
+{
+ uint32_t idx, count = 0;
+ tSirMacChanInfo *chan_info;
+ tSirMacChanInfo *ch_info_start;
+ int32_t max_ch_idx;
+ bool tmp_bool;
+ uint8_t ch = 0;
+
+ max_ch_idx =
+ (pMac->scan.base_channels.numChannels <
+ WNI_CFG_VALID_CHANNEL_LIST_LEN) ?
+ pMac->scan.base_channels.numChannels :
+ WNI_CFG_VALID_CHANNEL_LIST_LEN;
+
+ chan_info = cdf_mem_malloc(sizeof(tSirMacChanInfo) *
+ WNI_CFG_VALID_CHANNEL_LIST_LEN);
+ if (NULL == chan_info)
+ return;
+
+ cdf_mem_set(chan_info, sizeof(tSirMacChanInfo) *
+ WNI_CFG_VALID_CHANNEL_LIST_LEN, 0);
+ ch_info_start = chan_info;
+ for (idx = 0; idx < max_ch_idx; idx++) {
+ ch = pMac->scan.defaultPowerTable[idx].chanId;
+ tmp_bool = (fill_5f && CDS_IS_CHANNEL_5GHZ(ch))
+ || (!fill_5f && CDS_IS_CHANNEL_24GHZ(ch));
+ if (!tmp_bool)
+ continue;
+
+ if (count >= WNI_CFG_VALID_CHANNEL_LIST_LEN) {
+ sms_log(pMac, LOGW, FL("count(%d) exceeded"), count);
+ break;
+ }
+
+ chan_info->firstChanNum =
+ pMac->scan.defaultPowerTable[idx].chanId;
+ chan_info->numChannels = 1;
+ chan_info->maxTxPower =
+ CDF_MIN(pMac->scan.defaultPowerTable[idx].pwr,
+ pMac->roam.configParam.nTxPowerCap);
+ chan_info++;
+ count++;
+ }
+ if (count) {
+ csr_save_to_channel_power2_g_5_g(pMac,
+ count * sizeof(tSirMacChanInfo), ch_info_start);
+ }
+ cdf_mem_free(ch_info_start);
+}
+
+bool csr_is_supported_channel(tpAniSirGlobal pMac, uint8_t channelId)
+{
+ bool fRet = false;
+ uint32_t i;
+
+ for (i = 0; i < pMac->scan.base_channels.numChannels; i++) {
+ if (channelId ==
+ pMac->scan.base_channels.channelList[i]) {
+ fRet = true;
+ break;
+ }
+ }
+
+ return fRet;
+}
+
+/*
+ * 802.11D only: Gather 11d IE via beacon or Probe response and store them in pAdapter->channels11d
+ */
+bool csr_learn_11dcountry_information(tpAniSirGlobal pMac,
+ tSirBssDescription *pSirBssDesc,
+ tDot11fBeaconIEs *pIes, bool fForce)
+{
+ CDF_STATUS status;
+ uint8_t *pCountryCodeSelected;
+ bool fRet = false;
+ v_REGDOMAIN_t domainId;
+ tDot11fBeaconIEs *pIesLocal = pIes;
+ bool useVoting = false;
+
+ if (CDF_SAP_MODE == cds_get_conparam())
+ return CDF_STATUS_SUCCESS;
+
+ if ((NULL == pSirBssDesc) && (NULL == pIes))
+ useVoting = true;
+
+ /* check if .11d support is enabled */
+ if (!csr_is11d_supported(pMac))
+ goto free_ie;
+
+ if (false == useVoting) {
+ if (!pIesLocal &&
+ (!CDF_IS_STATUS_SUCCESS(
+ csr_get_parsed_bss_description_ies(
+ pMac, pSirBssDesc, &pIesLocal))))
+ goto free_ie;
+ /* check if country information element is present */
+ if (!pIesLocal->Country.present)
+ /* No country info */
+ goto free_ie;
+ status = csr_get_regulatory_domain_for_country(pMac,
+ pIesLocal->Country.country, &domainId,
+ COUNTRY_QUERY);
+ if (CDF_IS_STATUS_SUCCESS(status)
+ && (domainId == REGDOMAIN_WORLD))
+ goto free_ie;
+ } /* useVoting == false */
+
+ if (false == useVoting)
+ pCountryCodeSelected = pIesLocal->Country.country;
+ else
+ pCountryCodeSelected = pMac->scan.countryCodeElected;
+
+ status = csr_get_regulatory_domain_for_country(pMac,
+ pCountryCodeSelected, &domainId, COUNTRY_IE);
+ if (status != CDF_STATUS_SUCCESS) {
+ sms_log(pMac, LOGE, FL("fail to get regId %d"), domainId);
+ fRet = false;
+ goto free_ie;
+ }
+
+ /* updating 11d Country Code with Country code selected. */
+ cdf_mem_copy(pMac->scan.countryCode11d, pCountryCodeSelected,
+ WNI_CFG_COUNTRY_CODE_LEN);
+ fRet = true;
+free_ie:
+ if (!pIes && pIesLocal) {
+ /* locally allocated */
+ cdf_mem_free(pIesLocal);
+ }
+ return fRet;
+}
+
+void csr_save_scan_results(tpAniSirGlobal pMac, uint8_t reason,
+ uint8_t sessionId)
+{
+ sms_log(pMac, LOG4, "%s: Saving scan results", __func__);
+
+ /* initialize this to false. profMoveInterimScanResultsToMainList() routine */
+ /* will set this to the channel where an .11d beacon is seen */
+ pMac->scan.channelOf11dInfo = 0;
+ /* move the scan results from interim list to the main scan list */
+ csr_move_temp_scan_results_to_main_list(pMac, reason, sessionId);
+
+ /* Now check if we gathered any domain/country specific information */
+ /* If so, we should update channel list and apply Tx power settings */
+ if (csr_is11d_supported(pMac)) {
+ csr_apply_country_information(pMac);
+ }
+}
+
+void csr_reinit_scan_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand)
+{
+ switch (pCommand->u.scanCmd.reason) {
+ case eCsrScanAbortNormalScan:
+ default:
+ csr_scan_free_request(pMac, &pCommand->u.scanCmd.u.scanRequest);
+ break;
+ }
+ if (pCommand->u.scanCmd.pToRoamProfile) {
+ csr_release_profile(pMac, pCommand->u.scanCmd.pToRoamProfile);
+ cdf_mem_free(pCommand->u.scanCmd.pToRoamProfile);
+ }
+ cdf_mem_set(&pCommand->u.scanCmd, sizeof(tScanCmd), 0);
+}
+
+eCsrScanCompleteNextCommand csr_scan_get_next_command_state(tpAniSirGlobal pMac,
+ tSmeCmd *pCommand,
+ bool fSuccess)
+{
+ eCsrScanCompleteNextCommand NextCommand = eCsrNextScanNothing;
+
+ switch (pCommand->u.scanCmd.reason) {
+ case eCsrScan11d1:
+ NextCommand =
+ (fSuccess) ? eCsrNext11dScan1Success :
+ eCsrNext11dScan1Failure;
+ break;
+ case eCsrScan11d2:
+ NextCommand =
+ (fSuccess) ? eCsrNext11dScan2Success :
+ eCsrNext11dScan2Failure;
+ break;
+ case eCsrScan11dDone:
+ NextCommand = eCsrNext11dScanComplete;
+ break;
+ case eCsrScanLostLink1:
+ NextCommand =
+ (fSuccess) ? eCsrNextLostLinkScan1Success :
+ eCsrNextLostLinkScan1Failed;
+ break;
+ case eCsrScanLostLink2:
+ NextCommand =
+ (fSuccess) ? eCsrNextLostLinkScan2Success :
+ eCsrNextLostLinkScan2Failed;
+ break;
+ case eCsrScanLostLink3:
+ NextCommand =
+ (fSuccess) ? eCsrNextLostLinkScan3Success :
+ eCsrNextLostLinkScan3Failed;
+ break;
+ case eCsrScanForSsid:
+ NextCommand =
+ (fSuccess) ? eCsrNexteScanForSsidSuccess :
+ eCsrNexteScanForSsidFailure;
+ break;
+ default:
+ NextCommand = eCsrNextScanNothing;
+ break;
+ }
+ return NextCommand;
+}
+
+/* Return whether the pCommand is finished. */
+bool csr_handle_scan11d1_failure(tpAniSirGlobal pMac, tSmeCmd *pCommand)
+{
+ bool fRet = true;
+
+ /* Apply back the default setting and passively scan one more time. */
+ csr_apply_channel_power_info_wrapper(pMac);
+ pCommand->u.scanCmd.reason = eCsrScan11d2;
+ if (CDF_IS_STATUS_SUCCESS(csr_scan_channels(pMac, pCommand))) {
+ fRet = false;
+ }
+
+ return fRet;
+}
+
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+static void
+csr_diag_scan_complete(tpAniSirGlobal pMac,
+ tSmeCmd *pCommand,
+ tSirSmeScanRsp *pScanRsp)
+{
+ host_log_scan_pkt_type *pScanLog = NULL;
+ tScanResultHandle hScanResult;
+ tCsrScanResultInfo *pScanResult;
+ tDot11fBeaconIEs *pIes;
+ int n = 0, c = 0;
+ CDF_STATUS status;
+
+ WLAN_HOST_DIAG_LOG_ALLOC(pScanLog,
+ host_log_scan_pkt_type,
+ LOG_WLAN_SCAN_C);
+ if (!pScanLog)
+ return;
+
+ if (eCsrScanProbeBss == pCommand->u.scanCmd.reason) {
+ pScanLog->eventId = WLAN_SCAN_EVENT_HO_SCAN_RSP;
+ } else {
+ if (eSIR_PASSIVE_SCAN != pMac->scan.curScanType)
+ pScanLog->eventId = WLAN_SCAN_EVENT_ACTIVE_SCAN_RSP;
+ else
+ pScanLog->eventId = WLAN_SCAN_EVENT_PASSIVE_SCAN_RSP;
+ }
+ if (eSIR_SME_SUCCESS != pScanRsp->statusCode) {
+ pScanLog->status = WLAN_SCAN_STATUS_FAILURE;
+ WLAN_HOST_DIAG_LOG_REPORT(pScanLog);
+ return;
+ }
+
+ status = csr_scan_get_result(pMac, NULL, &hScanResult);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ WLAN_HOST_DIAG_LOG_REPORT(pScanLog);
+ return;
+ }
+
+ pScanResult = csr_scan_result_get_next(pMac, hScanResult);
+ while (pScanResult != NULL) {
+ if (n < HOST_LOG_MAX_NUM_BSSID) {
+ status = csr_get_parsed_bss_description_ies(pMac,
+ &pScanResult->BssDescriptor, &pIes);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE, FL("fail to parse IEs"));
+ break;
+ }
+ cdf_mem_copy(pScanLog->bssid[n],
+ pScanResult->BssDescriptor.bssId, 6);
+ if (pIes && pIes->SSID.present &&
+ HOST_LOG_MAX_SSID_SIZE >= pIes->SSID.num_ssid) {
+ cdf_mem_copy(pScanLog->ssid[n],
+ pIes->SSID.ssid,
+ pIes->SSID.num_ssid);
+ }
+ cdf_mem_free(pIes);
+ n++;
+ }
+ c++;
+ pScanResult = csr_scan_result_get_next(pMac, hScanResult);
+ }
+ pScanLog->numSsid = (uint8_t) n;
+ pScanLog->totalSsid = (uint8_t) c;
+ csr_scan_result_purge(pMac, hScanResult);
+ WLAN_HOST_DIAG_LOG_REPORT(pScanLog);
+
+ csr_diag_event_report(pMac, eCSR_EVENT_SCAN_COMPLETE, eSIR_SUCCESS,
+ eSIR_SUCCESS);
+ if (c > 0)
+ csr_diag_event_report(pMac, eCSR_EVENT_SCAN_RES_FOUND,
+ eSIR_SUCCESS, eSIR_SUCCESS);
+}
+#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */
+
+static void
+csr_handle_nxt_cmd(tpAniSirGlobal mac_ctx, tSmeCmd *pCommand,
+ eCsrScanCompleteNextCommand *nxt_cmd,
+ bool *remove_cmd, uint32_t session_id)
+{
+ CDF_STATUS status;
+ switch (*nxt_cmd) {
+ case eCsrNext11dScan1Success:
+ case eCsrNext11dScan2Success:
+ sms_log(mac_ctx, LOG2,
+ FL("11dScan1/3 produced results. Reissue Active scan"));
+ /*
+ * if we found country information, no need to continue scanning
+ * further, bail out
+ */
+ *remove_cmd = true;
+ *nxt_cmd = eCsrNext11dScanComplete;
+ break;
+ case eCsrNext11dScan1Failure:
+ /*
+ * We are not done yet. 11d scan fail once. We will try to reset
+ * anything and do it over again. The only meaningful thing for
+ * this retry is that we cannot find 11d information after a
+ * reset so we clear the "old" 11d info and give it once more
+ * chance
+ */
+ *remove_cmd = csr_handle_scan11d1_failure(mac_ctx, pCommand);
+ if (*remove_cmd)
+ *nxt_cmd = eCsrNext11dScanComplete;
+ break;
+ case eCsrNextLostLinkScan1Success:
+ status = csr_issue_roam_after_lostlink_scan(mac_ctx, session_id,
+ eCsrLostLink1);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ csr_scan_handle_failed_lostlink1(mac_ctx, session_id);
+ break;
+ case eCsrNextLostLinkScan2Success:
+ status = csr_issue_roam_after_lostlink_scan(mac_ctx, session_id,
+ eCsrLostLink2);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ csr_scan_handle_failed_lostlink2(mac_ctx, session_id);
+ break;
+ case eCsrNextLostLinkScan3Success:
+ status = csr_issue_roam_after_lostlink_scan(mac_ctx, session_id,
+ eCsrLostLink3);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ csr_scan_handle_failed_lostlink3(mac_ctx, session_id);
+ break;
+ case eCsrNextLostLinkScan1Failed:
+ csr_scan_handle_failed_lostlink1(mac_ctx, session_id);
+ break;
+ case eCsrNextLostLinkScan2Failed:
+ csr_scan_handle_failed_lostlink2(mac_ctx, session_id);
+ break;
+ case eCsrNextLostLinkScan3Failed:
+ csr_scan_handle_failed_lostlink3(mac_ctx, session_id);
+ break;
+ case eCsrNexteScanForSsidSuccess:
+ csr_scan_handle_search_for_ssid(mac_ctx, pCommand);
+ break;
+ case eCsrNexteScanForSsidFailure:
+ csr_scan_handle_search_for_ssid_failure(mac_ctx, pCommand);
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * csr_get_active_scan_entry() - To get scan entry from active command list
+ *
+ * @mac_ctx - MAC context
+ * @scan_id - Scan identifier of the scan request
+ * @entry - scan entry returned.
+ *
+ * Scan entry in the active scan list mapping to the sent scan id
+ * is returned to the caller.
+ *
+ * Return: CDF_STATUS.
+ */
+CDF_STATUS csr_get_active_scan_entry(tpAniSirGlobal mac_ctx,
+ uint32_t scan_id, tListElem **entry)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ tListElem *localentry;
+ tSmeCmd *cmd;
+ uint32_t cmd_scan_id = 0;
+
+ csr_ll_lock(&mac_ctx->sme.smeScanCmdActiveList);
+
+ if (csr_ll_is_list_empty(&mac_ctx->sme.smeScanCmdActiveList,
+ LL_ACCESS_NOLOCK)) {
+ sms_log(mac_ctx, LOGE,
+ FL(" Active list Empty scanId: %d"), scan_id);
+ return CDF_STATUS_SUCCESS;
+ }
+ localentry = csr_ll_peek_head(&mac_ctx->sme.smeScanCmdActiveList,
+ LL_ACCESS_NOLOCK);
+ do {
+ cmd = GET_BASE_ADDR(localentry, tSmeCmd, Link);
+ if (cmd->command == eSmeCommandScan)
+ cmd_scan_id = cmd->u.scanCmd.u.scanRequest.scan_id;
+ else if (cmd->command == eSmeCommandRemainOnChannel)
+ cmd_scan_id = cmd->u.remainChlCmd.scan_id;
+ if (cmd_scan_id == scan_id) {
+ sms_log(mac_ctx, LOG1, FL(" scanId Matched %d"),
+ scan_id);
+ *entry = localentry;
+ csr_ll_unlock(&mac_ctx->sme.smeScanCmdActiveList);
+ return CDF_STATUS_SUCCESS;
+ }
+ localentry = csr_ll_next(&mac_ctx->sme.smeScanCmdActiveList,
+ localentry, LL_ACCESS_NOLOCK);
+ } while (localentry);
+ csr_ll_unlock(&mac_ctx->sme.smeScanCmdActiveList);
+ return status;
+}
+
+/* Return whether the command should be removed */
+bool csr_scan_complete(tpAniSirGlobal pMac, tSirSmeScanRsp *pScanRsp)
+{
+ eCsrScanCompleteNextCommand NextCommand = eCsrNextScanNothing;
+ tListElem *pEntry = NULL;
+ tSmeCmd *pCommand;
+ bool fRemoveCommand = true;
+ bool fSuccess;
+ uint32_t sessionId = 0;
+
+ csr_get_active_scan_entry(pMac, pScanRsp->scan_id, &pEntry);
+ if (!pEntry) {
+ sms_log(pMac, LOGE,
+ FL("Scan Completion called but NO cmd ACTIVE ..."));
+ return false;
+ }
+
+ pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
+ /*
+ * If the head of the queue is Active and it is a SCAN command, remove
+ * and put this on the Free queue.
+ */
+ if (eSmeCommandScan != pCommand->command) {
+ sms_log(pMac, LOGW,
+ FL("Scan Completion called, but active SCAN cmd"));
+ return false;
+ }
+
+ sessionId = pCommand->sessionId;
+ if (eSIR_SME_SUCCESS != pScanRsp->statusCode) {
+ fSuccess = false;
+ } else {
+ /*
+ * pMac->scan.tempScanResults is not empty meaning the scan
+ * found something. This check only valid here because
+ * csrSaveScanresults is not yet called
+ */
+ fSuccess = (!csr_ll_is_list_empty(&pMac->scan.tempScanResults,
+ LL_ACCESS_LOCK));
+ }
+ if (pCommand->u.scanCmd.abortScanDueToBandChange) {
+ /*
+ * Scan aborted due to band change
+ * The scan results need to be flushed
+ */
+ if (pCommand->u.scanCmd.callback
+ != pMac->scan.callback11dScanDone) {
+ sms_log(pMac, LOG1, FL("Filtering the scan results"));
+ csr_scan_filter_results(pMac);
+ } else {
+ sms_log(pMac, LOG1,
+ FL("11d_scan_done, flushing the scan results"));
+ }
+ pCommand->u.scanCmd.abortScanDueToBandChange = false;
+ }
+ csr_save_scan_results(pMac, pCommand->u.scanCmd.reason, sessionId);
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+ csr_diag_scan_complete(pMac, pCommand, pScanRsp);
+#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */
+ NextCommand = csr_scan_get_next_command_state(pMac, pCommand, fSuccess);
+ /* We reuse the command here instead reissue a new command */
+ csr_handle_nxt_cmd(pMac, pCommand, &NextCommand,
+ &fRemoveCommand, sessionId);
+ return fRemoveCommand;
+}
+
+static void
+csr_scan_remove_dup_bss_description_from_interim_list(tpAniSirGlobal mac_ctx,
+ tSirBssDescription *bss_dscp,
+ tDot11fBeaconIEs *pIes)
+{
+ tListElem *pEntry;
+ tCsrScanResult *scan_bss_dscp;
+ int8_t scan_entry_rssi = 0;
+ /*
+ * Walk through all the chained BssDescriptions. If we find a chained
+ * BssDescription that matches the BssID of the BssDescription passed
+ * in, then these must be duplicate scan results for this Bss. In that
+ * case, remove the 'old' Bss description from the linked list.
+ */
+ sms_log(mac_ctx, LOG4, FL(" for BSS " MAC_ADDRESS_STR " "),
+ MAC_ADDR_ARRAY(bss_dscp->bssId));
+ csr_ll_lock(&mac_ctx->scan.tempScanResults);
+ pEntry = csr_ll_peek_head(&mac_ctx->scan.tempScanResults,
+ LL_ACCESS_NOLOCK);
+ while (pEntry) {
+ scan_bss_dscp = GET_BASE_ADDR(pEntry, tCsrScanResult, Link);
+ /*
+ * we have a duplicate scan results only when BSSID, SSID,
+ * Channel and NetworkType matches
+ */
+ scan_entry_rssi = scan_bss_dscp->Result.BssDescriptor.rssi;
+ if (csr_is_duplicate_bss_description(mac_ctx,
+ &scan_bss_dscp->Result.BssDescriptor, bss_dscp,
+ pIes, false)) {
+ /*
+ * Following is mathematically a = (aX + b(100-X))/100
+ * where:
+ * a = bss_dscp->rssi, b = scan_entry_rssi
+ * and X = CSR_SCAN_RESULT_RSSI_WEIGHT
+ */
+ bss_dscp->rssi = (int8_t) ((((int32_t) bss_dscp->rssi *
+ CSR_SCAN_RESULT_RSSI_WEIGHT) +
+ ((int32_t) scan_entry_rssi *
+ (100 - CSR_SCAN_RESULT_RSSI_WEIGHT))) / 100);
+ /* Remove the 'old' entry from the list */
+ if (csr_ll_remove_entry(&mac_ctx->scan.tempScanResults,
+ pEntry, LL_ACCESS_NOLOCK)) {
+ csr_check_n_save_wsc_ie(mac_ctx, bss_dscp,
+ &scan_bss_dscp->Result.
+ BssDescriptor);
+ /*
+ * we need to free the memory associated with
+ * this node
+ */
+ csr_free_scan_result_entry(mac_ctx,
+ scan_bss_dscp);
+ }
+ /*
+ * If we found a match, we can stop looking through
+ * the list.
+ */
+ break;
+ }
+ pEntry = csr_ll_next(&mac_ctx->scan.tempScanResults, pEntry,
+ LL_ACCESS_NOLOCK);
+ }
+
+ csr_ll_unlock(&mac_ctx->scan.tempScanResults);
+}
+
+/* Caller allocated memory pfNewBssForConn to return whether new candidate for */
+/* current connection is found. Cannot be NULL */
+tCsrScanResult *csr_scan_save_bss_description_to_interim_list(tpAniSirGlobal pMac,
+ tSirBssDescription *
+ pBSSDescription,
+ tDot11fBeaconIEs *pIes)
+{
+ tCsrScanResult *pCsrBssDescription = NULL;
+ uint32_t cbBSSDesc;
+ uint32_t cbAllocated;
+
+ /* figure out how big the BSS description is (the BSSDesc->length does NOT */
+ /* include the size of the length field itself). */
+ cbBSSDesc = pBSSDescription->length + sizeof(pBSSDescription->length);
+
+ cbAllocated = sizeof(tCsrScanResult) + cbBSSDesc;
+
+ sms_log(pMac, LOG4, FL("new BSS description, length %d, cbBSSDesc %d"),
+ cbAllocated, cbBSSDesc);
+ pCsrBssDescription = cdf_mem_malloc(cbAllocated);
+ if (NULL != pCsrBssDescription) {
+ cdf_mem_set(pCsrBssDescription, cbAllocated, 0);
+ cdf_mem_copy(&pCsrBssDescription->Result.BssDescriptor,
+ pBSSDescription, cbBSSDesc);
+ pCsrBssDescription->AgingCount =
+ (int32_t) pMac->roam.configParam.agingCount;
+ sms_log(pMac, LOG4,
+ FL(" Set Aging Count = %d for BSS " MAC_ADDRESS_STR " "),
+ pCsrBssDescription->AgingCount,
+ MAC_ADDR_ARRAY(pCsrBssDescription->Result.BssDescriptor.
+ bssId));
+ /* Save SSID separately for later use */
+ if (pIes->SSID.present
+ && !csr_is_nullssid(pIes->SSID.ssid, pIes->SSID.num_ssid)) {
+ /* SSID not hidden */
+ uint32_t len = pIes->SSID.num_ssid;
+ if (len > SIR_MAC_MAX_SSID_LENGTH) {
+ /* truncate to fit in our struct */
+ len = SIR_MAC_MAX_SSID_LENGTH;
+ }
+ pCsrBssDescription->Result.ssId.length = len;
+ pCsrBssDescription->Result.timer =
+ cdf_mc_timer_get_system_time();
+ cdf_mem_copy(pCsrBssDescription->Result.ssId.ssId,
+ pIes->SSID.ssid, len);
+ }
+ csr_ll_insert_tail(&pMac->scan.tempScanResults,
+ &pCsrBssDescription->Link, LL_ACCESS_LOCK);
+ }
+
+ return pCsrBssDescription;
+}
+
+bool csr_is_duplicate_bss_description(tpAniSirGlobal pMac,
+ tSirBssDescription *pSirBssDesc1,
+ tSirBssDescription *pSirBssDesc2,
+ tDot11fBeaconIEs *pIes2, bool fForced)
+{
+ bool fMatch = false;
+ tSirMacCapabilityInfo *pCap1, *pCap2;
+ tDot11fBeaconIEs *pIes1 = NULL;
+ tDot11fBeaconIEs *pIesTemp = pIes2;
+ CDF_STATUS status;
+
+ pCap1 = (tSirMacCapabilityInfo *) &pSirBssDesc1->capabilityInfo;
+ pCap2 = (tSirMacCapabilityInfo *) &pSirBssDesc2->capabilityInfo;
+
+ if (pCap1->ess != pCap2->ess)
+ goto free_ies;
+
+ if (pCap1->ess &&
+ cdf_is_macaddr_equal((struct cdf_mac_addr *) pSirBssDesc1->bssId,
+ (struct cdf_mac_addr *) pSirBssDesc2->bssId)
+ && (fForced
+ || (cds_chan_to_band(pSirBssDesc1->channelId) ==
+ cds_chan_to_band((pSirBssDesc2->channelId))))) {
+ fMatch = true;
+ /* Check for SSID match, if exists */
+ status = csr_get_parsed_bss_description_ies(pMac, pSirBssDesc1,
+ &pIes1);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ goto free_ies;
+
+ if (NULL == pIesTemp) {
+ status = csr_get_parsed_bss_description_ies(pMac,
+ pSirBssDesc2, &pIesTemp);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ goto free_ies;
+ }
+ if (pIes1->SSID.present && pIesTemp->SSID.present) {
+ fMatch = csr_is_ssid_match(pMac, pIes1->SSID.ssid,
+ pIes1->SSID.num_ssid,
+ pIesTemp->SSID.ssid,
+ pIesTemp->SSID.num_ssid,
+ true);
+ }
+ } else if (pCap1->ibss && (pSirBssDesc1->channelId ==
+ pSirBssDesc2->channelId)) {
+ status = csr_get_parsed_bss_description_ies(pMac, pSirBssDesc1,
+ &pIes1);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ goto free_ies;
+
+ if (NULL == pIesTemp) {
+ status = csr_get_parsed_bss_description_ies(pMac,
+ pSirBssDesc2, &pIesTemp);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ goto free_ies;
+ }
+
+ /* Same channel cannot have same SSID for different IBSS */
+ if (pIes1->SSID.present && pIesTemp->SSID.present) {
+ fMatch = csr_is_ssid_match(pMac, pIes1->SSID.ssid,
+ pIes1->SSID.num_ssid,
+ pIesTemp->SSID.ssid,
+ pIesTemp->SSID.num_ssid,
+ true);
+ }
+ }
+ /* In case of P2P devices, ess and ibss will be set to zero */
+ else if (!pCap1->ess &&
+ cdf_is_macaddr_equal(
+ (struct cdf_mac_addr *) pSirBssDesc1->bssId,
+ (struct cdf_mac_addr *) pSirBssDesc2->bssId)) {
+ fMatch = true;
+ }
+
+free_ies:
+ if (pIes1)
+ cdf_mem_free(pIes1);
+ if ((NULL == pIes2) && pIesTemp)
+ /* locally allocated */
+ cdf_mem_free(pIesTemp);
+ return fMatch;
+}
+
+bool csr_is_network_type_equal(tSirBssDescription *pSirBssDesc1,
+ tSirBssDescription *pSirBssDesc2)
+{
+ return pSirBssDesc1->nwType == pSirBssDesc2->nwType;
+}
+
+/* to check whether the BSS matches the dot11Mode */
+static bool csr_scan_is_bss_allowed(tpAniSirGlobal pMac,
+ tSirBssDescription *pBssDesc,
+ tDot11fBeaconIEs *pIes)
+{
+ bool fAllowed = false;
+ eCsrPhyMode phyMode;
+
+ if (CDF_IS_STATUS_SUCCESS
+ (csr_get_phy_mode_from_bss(pMac, pBssDesc, &phyMode, pIes))) {
+ switch (pMac->roam.configParam.phyMode) {
+ case eCSR_DOT11_MODE_11b:
+ fAllowed = (bool) (eCSR_DOT11_MODE_11a != phyMode);
+ break;
+ case eCSR_DOT11_MODE_11g:
+ fAllowed = (bool) (eCSR_DOT11_MODE_11a != phyMode);
+ break;
+ case eCSR_DOT11_MODE_11g_ONLY:
+ fAllowed = (bool) (eCSR_DOT11_MODE_11g == phyMode);
+ break;
+ case eCSR_DOT11_MODE_11a:
+ fAllowed = (bool) ((eCSR_DOT11_MODE_11b != phyMode)
+ && (eCSR_DOT11_MODE_11g != phyMode));
+ break;
+ case eCSR_DOT11_MODE_11n_ONLY:
+ fAllowed = (bool) ((eCSR_DOT11_MODE_11n == phyMode));
+ break;
+
+#ifdef WLAN_FEATURE_11AC
+ case eCSR_DOT11_MODE_11ac_ONLY:
+ fAllowed = (bool) ((eCSR_DOT11_MODE_11ac == phyMode));
+ break;
+#endif
+ case eCSR_DOT11_MODE_11b_ONLY:
+ fAllowed = (bool) (eCSR_DOT11_MODE_11b == phyMode);
+ break;
+ case eCSR_DOT11_MODE_11n:
+#ifdef WLAN_FEATURE_11AC
+ case eCSR_DOT11_MODE_11ac:
+#endif
+ default:
+ fAllowed = true;
+ break;
+ }
+ }
+
+ return fAllowed;
+}
+
+/* Return pIes to caller for future use when returning true. */
+static bool csr_scan_validate_scan_result(tpAniSirGlobal pMac,
+ uint8_t *pChannels,
+ uint8_t numChn,
+ tSirBssDescription *pBssDesc,
+ tDot11fBeaconIEs **ppIes)
+{
+ bool valid = false;
+ tDot11fBeaconIEs *pIes = NULL;
+ uint8_t index;
+ CDF_STATUS status;
+
+ for (index = 0; index < numChn; index++) {
+ /*
+ * This check relies on the fact that a single BSS description
+ * is returned in each ScanRsp call, which is the way LIM
+ * implemented the scan req/rsp funtions. We changed to this
+ * model when we ran with a large number of APs. If this were to
+ * change, then this check would have to mess with removing the
+ * bssDescription from somewhere in an arbitrary index in the
+ * bssDescription array.
+ */
+ if (pChannels[index] == pBssDesc->channelId) {
+ valid = true;
+ break;
+ }
+ }
+ *ppIes = NULL;
+ if (valid) {
+ status = csr_get_parsed_bss_description_ies(pMac, pBssDesc,
+ &pIes);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ return false;
+
+ valid = csr_scan_is_bss_allowed(pMac, pBssDesc, pIes);
+ if (valid)
+ *ppIes = pIes;
+ else
+ cdf_mem_free(pIes);
+ }
+ return valid;
+}
+
+static void csr_update_scantype(tpAniSirGlobal pMac, tDot11fBeaconIEs *pIes,
+ uint8_t channelId)
+{
+ if (eSIR_PASSIVE_SCAN != pMac->scan.curScanType)
+ return;
+
+ if (csr_is11d_supported(pMac)) {
+ /* Check whether the BSS is acceptable based on
+ * 11d info and our config.
+ */
+ if (!csr_match_country_code(pMac, NULL, pIes))
+ return;
+
+ /* check if channel is acceptable by config */
+ if (csr_is_supported_channel(pMac, channelId))
+ pMac->scan.curScanType = eSIR_ACTIVE_SCAN;
+
+ } else
+ pMac->scan.curScanType = eSIR_ACTIVE_SCAN;
+
+}
+
+/* Return whether last scan result is received */
+static bool csr_scan_process_scan_results(tpAniSirGlobal pMac, tSmeCmd *pCommand,
+ tSirSmeScanRsp *pScanRsp,
+ bool *pfRemoveCommand)
+{
+ bool fRet = false, fRemoveCommand = false;
+
+ sms_log(pMac, LOG1, FL("scan reason = %d, response status code = %d"),
+ pCommand->u.scanCmd.reason, pScanRsp->statusCode);
+ fRemoveCommand = csr_scan_complete(pMac, pScanRsp);
+ fRet = true;
+ if (pfRemoveCommand) {
+ *pfRemoveCommand = fRemoveCommand;
+ }
+ return fRet;
+}
+
+/* csr_scan_process_single_bssdescr() - Add a bssdescriptor to scan table
+ *
+ * @mac_ctx - MAC context
+ * @bssdescr - Pointer to BSS description structure that contains
+ * everything from beacon/probe response frame and additional
+ * information.
+ * @scan_id - Scan identifier of the scan request that was running
+ * when this beacon was received. Reserved for future when
+ * firmware provides that information.
+ * @flags - Reserved for future use.
+ *
+ * Callback routine called by LIM when it receives a beacon or probe response
+ * from the device. 802.11 frame is already converted to internal
+ * tSirBssDescription data structure.
+ *
+ * Return: 0 or other error codes.
+ */
+
+CDF_STATUS csr_scan_process_single_bssdescr(tpAniSirGlobal mac_ctx,
+ tSirBssDescription *bssdescr,
+ uint32_t scan_id, uint32_t flags)
+{
+ tDot11fBeaconIEs *ies = NULL;
+ uint8_t *chanlist = NULL;
+ uint8_t cnt_channels = 0;
+ uint32_t len = sizeof(mac_ctx->roam.validChannelList);
+
+ sms_log(mac_ctx, LOG4, "CSR: Processing single bssdescr");
+ if (CDF_IS_STATUS_SUCCESS(
+ csr_get_cfg_valid_channels(mac_ctx,
+ (uint8_t *) mac_ctx->roam.validChannelList,
+ &len))) {
+ chanlist = mac_ctx->roam.validChannelList;
+ cnt_channels = (uint8_t) len;
+ } else {
+ /* Cannot continue */
+ sms_log(mac_ctx, LOGW,
+ FL("Received results on invalid channel"));
+ return CDF_STATUS_E_INVAL;
+ }
+
+ if (csr_scan_validate_scan_result(mac_ctx, chanlist,
+ cnt_channels, bssdescr, &ies)) {
+ csr_scan_remove_dup_bss_description_from_interim_list
+ (mac_ctx, bssdescr, ies);
+ csr_scan_save_bss_description_to_interim_list
+ (mac_ctx, bssdescr, ies);
+ csr_update_scantype(mac_ctx, ies, bssdescr->channelId);
+ /* Free the resource */
+ if (ies != NULL)
+ cdf_mem_free(ies);
+ }
+ return CDF_STATUS_SUCCESS;
+}
+
+
+bool csr_scan_is_wild_card_scan(tpAniSirGlobal pMac, tSmeCmd *pCommand)
+{
+ uint8_t bssid[CDF_MAC_ADDR_SIZE] = {0};
+ bool f = cdf_mem_compare(pCommand->u.scanCmd.u.scanRequest.bssid.bytes,
+ bssid, sizeof(struct cdf_mac_addr));
+ /*
+ * It is not a wild card scan if the bssid is not broadcast and
+ * the number of SSID is 1.
+ */
+ return (f || (0xff == pCommand->u.scanCmd.u.scanRequest.bssid.bytes[0]))
+ && (pCommand->u.scanCmd.u.scanRequest.SSIDs.numOfSSIDs != 1);
+}
+
+CDF_STATUS csr_scan_sme_scan_response(tpAniSirGlobal pMac,
+ void *pMsgBuf)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tListElem *pEntry = NULL;
+ tSmeCmd *pCommand;
+ eCsrScanStatus scanStatus;
+ tSirSmeScanRsp *pScanRsp = (tSirSmeScanRsp *)pMsgBuf;
+ bool fRemoveCommand = true;
+ eCsrScanReason reason = eCsrScanOther;
+
+ csr_get_active_scan_entry(pMac, pScanRsp->scan_id, &pEntry);
+ if (!pEntry)
+ goto error_handling;
+
+ sms_log(pMac, LOG1, FL("Scan completion called:scan_id %d, entry = %p"),
+ pScanRsp->scan_id, pEntry);
+
+ pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
+ if (eSmeCommandScan != pCommand->command)
+ goto error_handling;
+
+ scanStatus = (eSIR_SME_SUCCESS == pScanRsp->statusCode) ?
+ eCSR_SCAN_SUCCESS : eCSR_SCAN_FAILURE;
+ reason = pCommand->u.scanCmd.reason;
+ switch (pCommand->u.scanCmd.reason) {
+ case eCsrScanAbortNormalScan:
+ break;
+ case eCsrScanP2PFindPeer:
+ scanStatus = (eSIR_SME_SUCCESS == pScanRsp->statusCode) ?
+ eCSR_SCAN_FOUND_PEER : eCSR_SCAN_FAILURE;
+ csr_scan_process_scan_results(pMac, pCommand, pScanRsp, NULL);
+ break;
+ default:
+ if (csr_scan_process_scan_results(pMac, pCommand, pScanRsp,
+ &fRemoveCommand)
+ && csr_scan_is_wild_card_scan(pMac, pCommand)
+ && !pCommand->u.scanCmd.u.scanRequest.p2pSearch) {
+
+ /* Age out logic will be taken care by the age out timer */
+ }
+ break;
+ }
+ if (fRemoveCommand)
+ csr_release_scan_command(pMac, pCommand, scanStatus);
+ sme_process_pending_queue(pMac);
+ return status;
+
+error_handling:
+#ifdef FEATURE_WLAN_SCAN_PNO
+ if (pMac->pnoOffload && pScanRsp->statusCode == eSIR_PNO_SCAN_SUCCESS) {
+ sms_log(pMac, LOGE, FL("PNO Scan completion called."));
+ csr_save_scan_results(pMac, eCsrScanCandidateFound,
+ pScanRsp->sessionId);
+ return CDF_STATUS_SUCCESS;
+ } else {
+ /*
+ * Scan completion was called, PNO is active, but scan
+ * response was not PNO
+ */
+ sms_log(pMac, LOGE,
+ FL("Scan completion called, scan rsp was not PNO."));
+ return CDF_STATUS_E_FAILURE;
+ }
+#endif
+ sms_log(pMac, LOGE, FL("Scan completion called, but no active SCAN command."));
+ return CDF_STATUS_E_FAILURE;
+}
+
+tCsrScanResultInfo *csr_scan_result_get_first(tpAniSirGlobal pMac,
+ tScanResultHandle hScanResult)
+{
+ tListElem *pEntry;
+ tCsrScanResult *pResult;
+ tCsrScanResultInfo *pRet = NULL;
+ tScanResultList *pResultList = (tScanResultList *) hScanResult;
+
+ if (pResultList) {
+ csr_ll_lock(&pResultList->List);
+ pEntry = csr_ll_peek_head(&pResultList->List, LL_ACCESS_NOLOCK);
+ if (pEntry) {
+ pResult = GET_BASE_ADDR(pEntry, tCsrScanResult, Link);
+ pRet = &pResult->Result;
+ }
+ pResultList->pCurEntry = pEntry;
+ csr_ll_unlock(&pResultList->List);
+ }
+
+ return pRet;
+}
+
+tCsrScanResultInfo *csr_scan_result_get_next(tpAniSirGlobal pMac,
+ tScanResultHandle hScanResult)
+{
+ tListElem *pEntry = NULL;
+ tCsrScanResult *pResult = NULL;
+ tCsrScanResultInfo *pRet = NULL;
+ tScanResultList *pResultList = (tScanResultList *) hScanResult;
+
+ if (!pResultList)
+ return NULL;
+
+ csr_ll_lock(&pResultList->List);
+ if (NULL == pResultList->pCurEntry) {
+ pEntry = csr_ll_peek_head(&pResultList->List, LL_ACCESS_NOLOCK);
+ } else {
+ pEntry = csr_ll_next(&pResultList->List, pResultList->pCurEntry,
+ LL_ACCESS_NOLOCK);
+ }
+ if (pEntry) {
+ pResult = GET_BASE_ADDR(pEntry, tCsrScanResult, Link);
+ pRet = &pResult->Result;
+ }
+ pResultList->pCurEntry = pEntry;
+ csr_ll_unlock(&pResultList->List);
+ return pRet;
+}
+
+/*
+ * This function moves the first BSS that matches the bssid to the
+ * head of the result
+ */
+CDF_STATUS csr_move_bss_to_head_from_bssid(tpAniSirGlobal pMac,
+ struct cdf_mac_addr *bssid,
+ tScanResultHandle hScanResult)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ tScanResultList *pResultList = (tScanResultList *) hScanResult;
+ tCsrScanResult *pResult = NULL;
+ tListElem *pEntry = NULL;
+
+ if (!(pResultList && bssid))
+ return status;
+
+ csr_ll_lock(&pResultList->List);
+ pEntry = csr_ll_peek_head(&pResultList->List, LL_ACCESS_NOLOCK);
+ while (pEntry) {
+ pResult = GET_BASE_ADDR(pEntry, tCsrScanResult, Link);
+ if (cdf_mem_compare(bssid, pResult->Result.BssDescriptor.bssId,
+ sizeof(struct cdf_mac_addr))) {
+ status = CDF_STATUS_SUCCESS;
+ csr_ll_remove_entry(&pResultList->List, pEntry,
+ LL_ACCESS_NOLOCK);
+ csr_ll_insert_head(&pResultList->List, pEntry,
+ LL_ACCESS_NOLOCK);
+ break;
+ }
+ pEntry = csr_ll_next(&pResultList->List, pResultList->pCurEntry,
+ LL_ACCESS_NOLOCK);
+ }
+ csr_ll_unlock(&pResultList->List);
+ return status;
+}
+
+/* Remove the BSS if possible. */
+/* Return -- true == the BSS is remove. False == Fail to remove it */
+/* This function is called when list lock is held. Be caution what functions it can call. */
+bool csr_scan_age_out_bss(tpAniSirGlobal pMac, tCsrScanResult *pResult)
+{
+ bool fRet = false;
+ uint32_t i;
+ tCsrRoamSession *pSession;
+ bool isConnBssfound = false;
+
+ for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
+ if (!CSR_IS_SESSION_VALID(pMac, i))
+ continue;
+ pSession = CSR_GET_SESSION(pMac, i);
+ /* Not to remove the BSS we are connected to. */
+ if (csr_is_conn_state_connected_infra(pMac, i)
+ && (NULL != pSession->pConnectBssDesc)
+ && (csr_is_duplicate_bss_description(pMac,
+ &pResult->Result.BssDescriptor,
+ pSession->pConnectBssDesc, NULL, false))) {
+ isConnBssfound = true;
+ break;
+ }
+ }
+ if (isConnBssfound) {
+ /*
+ * Reset the counter so that aging out of connected BSS won't
+ * hapeen too soon
+ */
+ pResult->AgingCount =
+ (int32_t) pMac->roam.configParam.agingCount;
+ sms_log(pMac, LOGW,
+ FL("Connected BSS, Set Aging Count=%d for BSS "
+ MAC_ADDRESS_STR), pResult->AgingCount,
+ MAC_ADDR_ARRAY(pResult->Result.BssDescriptor.bssId));
+ pResult->Result.BssDescriptor.nReceivedTime =
+ (uint32_t) cdf_mc_timer_get_system_ticks();
+ return fRet;
+ }
+ sms_log(pMac, LOGW,
+ "Aging out BSS " MAC_ADDRESS_STR " Channel %d",
+ MAC_ADDR_ARRAY(pResult->Result.BssDescriptor.bssId),
+ pResult->Result.BssDescriptor.channelId);
+ /*
+ * No need to hold the spin lock because caller should hold the lock for
+ * pMac->scan.scanResultList
+ */
+ if (csr_ll_remove_entry(&pMac->scan.scanResultList, &pResult->Link,
+ LL_ACCESS_NOLOCK)) {
+ if (cdf_is_macaddr_equal(
+ (struct cdf_mac_addr *) &pResult->Result.BssDescriptor.bssId,
+ (struct cdf_mac_addr *) &pMac->scan.currentCountryBssid)) {
+ sms_log(pMac, LOGW,
+ FL("Aging out 11d BSS " MAC_ADDRESS_STR),
+ MAC_ADDR_ARRAY(
+ pResult->Result.BssDescriptor.bssId));
+ pMac->scan.currentCountryRSSI = -128;
+ }
+ csr_free_scan_result_entry(pMac, pResult);
+ fRet = true;
+ }
+ return fRet;
+}
+
+CDF_STATUS csr_scan_age_results(tpAniSirGlobal pMac,
+ tSmeGetScanChnRsp *pScanChnInfo)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tListElem *pEntry, *tmpEntry;
+ tCsrScanResult *pResult;
+ tLimScanChn *pChnInfo;
+ uint8_t i;
+
+ csr_ll_lock(&pMac->scan.scanResultList);
+ for (i = 0; i < pScanChnInfo->numChn; i++) {
+ pChnInfo = &pScanChnInfo->scanChn[i];
+ pEntry =
+ csr_ll_peek_head(&pMac->scan.scanResultList, LL_ACCESS_NOLOCK);
+ while (pEntry) {
+ tmpEntry =
+ csr_ll_next(&pMac->scan.scanResultList, pEntry,
+ LL_ACCESS_NOLOCK);
+ pResult = GET_BASE_ADDR(pEntry, tCsrScanResult, Link);
+ if (pResult->Result.BssDescriptor.channelId ==
+ pChnInfo->channelId) {
+ if (pResult->AgingCount <= 0) {
+ sms_log(pMac, LOGW,
+ " age out due to ref count");
+ csr_scan_age_out_bss(pMac, pResult);
+ } else {
+ pResult->AgingCount--;
+ sms_log(pMac, LOGW,
+ FL
+ ("Decremented AgingCount=%d for BSS "
+ MAC_ADDRESS_STR ""),
+ pResult->AgingCount,
+ MAC_ADDR_ARRAY(pResult->Result.
+ BssDescriptor.
+ bssId));
+ }
+ }
+ pEntry = tmpEntry;
+ }
+ }
+ csr_ll_unlock(&pMac->scan.scanResultList);
+
+ return status;
+}
+
+CDF_STATUS csr_send_mb_scan_req(tpAniSirGlobal pMac, uint16_t sessionId,
+ tCsrScanRequest *pScanReq,
+ tScanReqParam *pScanReqParam)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSirSmeScanReq *pMsg;
+ uint16_t msgLen;
+ tSirScanType scanType = pScanReq->scanType;
+ uint32_t minChnTime; /* in units of milliseconds */
+ uint32_t maxChnTime; /* in units of milliseconds */
+ uint32_t i;
+ uint8_t selfMacAddr[CDF_MAC_ADDR_SIZE];
+ uint8_t *pSelfMac = NULL;
+
+ msgLen = (uint16_t) (sizeof(tSirSmeScanReq) -
+ sizeof(pMsg->channelList.channelNumber) +
+ (sizeof(pMsg->channelList.channelNumber) *
+ pScanReq->ChannelInfo.numOfChannels)) +
+ (pScanReq->uIEFieldLen);
+
+ pMsg = cdf_mem_malloc(msgLen);
+ if (NULL == pMsg) {
+ sms_log(pMac, LOGE, FL("memory allocation failed"));
+ sms_log(pMac, LOG1, FL("Failed: SId: %d FirstMatch = %d"
+ " UniqueResult = %d freshScan = %d hiddenSsid = %d"),
+ sessionId, pScanReqParam->bReturnAfter1stMatch,
+ pScanReqParam->fUniqueResult, pScanReqParam->freshScan,
+ pScanReqParam->hiddenSsid);
+ sms_log(pMac, LOG1,
+ FL("scanType = %u BSSType = %u numOfSSIDs = %d"
+ " numOfChannels = %d requestType = %d p2pSearch = %d\n"),
+ pScanReq->scanType, pScanReq->BSSType,
+ pScanReq->SSIDs.numOfSSIDs,
+ pScanReq->ChannelInfo.numOfChannels,
+ pScanReq->requestType, pScanReq->p2pSearch);
+ return CDF_STATUS_E_NOMEM;
+ }
+
+ cdf_mem_set(pMsg, msgLen, 0);
+ pMsg->messageType = eWNI_SME_SCAN_REQ;
+ pMsg->length = msgLen;
+ /* ToDO: Fill in session info when we need to do scan base on session */
+ if ((sessionId != CSR_SESSION_ID_INVALID)) {
+ pMsg->sessionId = sessionId;
+ } else {
+ /* if sessionId == CSR_SESSION_ID_INVALID, then send the scan
+ request on first available session */
+ pMsg->sessionId = 0;
+ }
+ if (pMsg->sessionId >= CSR_ROAM_SESSION_MAX)
+ sms_log(pMac, LOGE, FL(" Invalid Sme Session ID = %d"),
+ pMsg->sessionId);
+ pMsg->transactionId = 0;
+ pMsg->dot11mode = (uint8_t) csr_translate_to_wni_cfg_dot11_mode(pMac,
+ csr_find_best_phy_mode(pMac,
+ pMac->roam.configParam.phyMode));
+ pMsg->bssType = csr_translate_bsstype_to_mac_type(pScanReq->BSSType);
+
+ if (CSR_IS_SESSION_VALID(pMac, sessionId)) {
+ pSelfMac = (uint8_t *)
+ &pMac->roam.roamSession[sessionId].selfMacAddr;
+ } else {
+ /*
+ * Since we don't have session for the scanning, we find a valid
+ * session. In case we fail to do so, get the WNI_CFG_STA_ID
+ */
+ for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
+ if (CSR_IS_SESSION_VALID(pMac, i)) {
+ pSelfMac = (uint8_t *)
+ &pMac->roam.roamSession[i].selfMacAddr;
+ break;
+ }
+ }
+ if (CSR_ROAM_SESSION_MAX == i) {
+ uint32_t len = CDF_MAC_ADDR_SIZE;
+ pSelfMac = selfMacAddr;
+ status = wlan_cfg_get_str(pMac, WNI_CFG_STA_ID,
+ pSelfMac, &len);
+ if (!CDF_IS_STATUS_SUCCESS(status)
+ || (len < CDF_MAC_ADDR_SIZE)) {
+ sms_log(pMac, LOGE,
+ FL("Can't get self MAC address = %d"),
+ status);
+ /* Force failed status */
+ status = CDF_STATUS_E_FAILURE;
+ goto send_scan_req;
+ }
+ }
+ }
+ cdf_mem_copy((uint8_t *) pMsg->selfMacAddr,
+ pSelfMac, sizeof(tSirMacAddr));
+
+ /* sir_copy_mac_addr */
+ cdf_mem_copy(pMsg->bssId, &pScanReq->bssid, sizeof(tSirMacAddr));
+ if (cdf_is_macaddr_zero(&pScanReq->bssid))
+ cdf_mem_set(pMsg->bssId, sizeof(tSirMacAddr), 0xff);
+ else
+ cdf_mem_copy(pMsg->bssId, pScanReq->bssid.bytes,
+ CDF_MAC_ADDR_SIZE);
+ minChnTime = pScanReq->minChnTime;
+ maxChnTime = pScanReq->maxChnTime;
+
+ /*
+ * Verify the scan type first, if the scan is active scan, we need to
+ * make sure we are allowed to do so. if 11d is enabled & we don't see
+ * any beacon around, scan type falls back to passive. But in BT AMP STA
+ * mode we need to send out a directed probe
+ */
+ if ((eSIR_PASSIVE_SCAN != scanType)
+ && (eCSR_SCAN_P2P_DISCOVERY !=
+ pScanReq->requestType)
+ && (eCSR_BSS_TYPE_WDS_STA != pScanReq->BSSType)
+ && (false == pMac->scan.fEnableBypass11d)) {
+ scanType = pMac->scan.curScanType;
+ if (eSIR_PASSIVE_SCAN == pMac->scan.curScanType) {
+ if (minChnTime <
+ pMac->roam.configParam.nPassiveMinChnTime) {
+ minChnTime =
+ pMac->roam.configParam.nPassiveMinChnTime;
+ }
+ if (maxChnTime <
+ pMac->roam.configParam.nPassiveMaxChnTime) {
+ maxChnTime =
+ pMac->roam.configParam.nPassiveMaxChnTime;
+ }
+ }
+ }
+ pMsg->scanType = scanType;
+
+ pMsg->numSsid = (pScanReq->SSIDs.numOfSSIDs < SIR_SCAN_MAX_NUM_SSID) ?
+ pScanReq->SSIDs.numOfSSIDs : SIR_SCAN_MAX_NUM_SSID;
+ if ((pScanReq->SSIDs.numOfSSIDs != 0)
+ && (eSIR_PASSIVE_SCAN != scanType)) {
+ for (i = 0; i < pMsg->numSsid; i++) {
+ cdf_mem_copy(&pMsg->ssId[i],
+ &pScanReq->SSIDs.SSIDList[i].SSID,
+ sizeof(tSirMacSSid));
+ }
+ } else {
+ /* Otherwise we scan all SSID and let the result filter later */
+ for (i = 0; i < SIR_SCAN_MAX_NUM_SSID; i++)
+ pMsg->ssId[i].length = 0;
+ }
+
+ pMsg->minChannelTime = minChnTime;
+ pMsg->maxChannelTime = maxChnTime;
+ /* hidden SSID option */
+ pMsg->hiddenSsid = pScanReqParam->hiddenSsid;
+ /* rest time */
+ pMsg->restTime = pScanReq->restTime;
+ pMsg->returnAfterFirstMatch = pScanReqParam->bReturnAfter1stMatch;
+ /* All the scan results caching will be done by Roaming */
+ /* We do not want LIM to do any caching of scan results, */
+ /* so delete the LIM cache on all scan requests */
+ pMsg->returnFreshResults = pScanReqParam->freshScan;
+ /* Always ask for unique result */
+ pMsg->returnUniqueResults = pScanReqParam->fUniqueResult;
+ pMsg->channelList.numChannels =
+ (uint8_t) pScanReq->ChannelInfo.numOfChannels;
+ if (pScanReq->ChannelInfo.numOfChannels) {
+ /* Assuming the channelNumber is uint8_t (1 byte) */
+ cdf_mem_copy(pMsg->channelList.channelNumber,
+ pScanReq->ChannelInfo.ChannelList,
+ pScanReq->ChannelInfo.numOfChannels);
+ }
+
+ pMsg->uIEFieldLen = (uint16_t) pScanReq->uIEFieldLen;
+ pMsg->uIEFieldOffset = (uint16_t) (sizeof(tSirSmeScanReq) -
+ sizeof(pMsg->channelList.channelNumber) +
+ (sizeof(pMsg->channelList.channelNumber) *
+ pScanReq->ChannelInfo.numOfChannels));
+ if (pScanReq->uIEFieldLen != 0) {
+ cdf_mem_copy((uint8_t *) pMsg + pMsg->uIEFieldOffset,
+ pScanReq->pIEField, pScanReq->uIEFieldLen);
+ }
+ pMsg->p2pSearch = pScanReq->p2pSearch;
+ pMsg->scan_id = pScanReq->scan_id;
+
+send_scan_req:
+ sms_log(pMac, LOG1,
+ FL("scanId %d domainIdCurrent %d scanType %d bssType %d requestType %d numChannels %d"),
+ pMsg->scan_id, pMac->scan.domainIdCurrent, pMsg->scanType,
+ pMsg->bssType, pScanReq->requestType,
+ pMsg->channelList.numChannels);
+
+ for (i = 0; i < pMsg->channelList.numChannels; i++) {
+ sms_log(pMac, LOG1, FL("channelNumber[%d]= %d"), i,
+ pMsg->channelList.channelNumber[i]);
+ }
+
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ status = cds_send_mb_message_to_mac(pMsg);
+ } else {
+ sms_log(pMac, LOGE,
+ FL("failed to send down scan req with status = %d"),
+ status);
+ cdf_mem_free(pMsg);
+ }
+ return status;
+}
+
+CDF_STATUS csr_send_mb_scan_result_req(tpAniSirGlobal pMac,
+ uint32_t sessionId,
+ tScanReqParam *pScanReqParam)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSirSmeScanReq *pMsg;
+ uint16_t msgLen;
+
+ msgLen = (uint16_t) (sizeof(tSirSmeScanReq));
+ pMsg = cdf_mem_malloc(msgLen);
+ if (NULL == pMsg)
+ return CDF_STATUS_E_NOMEM;
+
+ cdf_mem_set(pMsg, msgLen, 0);
+ pMsg->messageType = eWNI_SME_SCAN_REQ;
+ pMsg->length = msgLen;
+ pMsg->sessionId = sessionId;
+ pMsg->transactionId = 0;
+ pMsg->returnFreshResults = pScanReqParam->freshScan;
+ /* Always ask for unique result */
+ pMsg->returnUniqueResults = pScanReqParam->fUniqueResult;
+ pMsg->returnAfterFirstMatch =
+ pScanReqParam->bReturnAfter1stMatch;
+ status = cds_send_mb_message_to_mac(pMsg);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ FL("Failed to send down scan req with status = %d\n"),
+ status);
+ }
+ return status;
+}
+
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+static void csr_diag_scan_channels(tpAniSirGlobal pMac, tSmeCmd *pCommand)
+{
+ host_log_scan_pkt_type *pScanLog = NULL;
+
+ WLAN_HOST_DIAG_LOG_ALLOC(pScanLog,
+ host_log_scan_pkt_type,
+ LOG_WLAN_SCAN_C);
+ if (!pScanLog)
+ return;
+
+ if (eCsrScanProbeBss == pCommand->u.scanCmd.reason) {
+ pScanLog->eventId = WLAN_SCAN_EVENT_HO_SCAN_REQ;
+ } else {
+ if ((eSIR_PASSIVE_SCAN !=
+ pCommand->u.scanCmd.u.scanRequest.scanType)
+ && (eSIR_PASSIVE_SCAN != pMac->scan.curScanType)) {
+ pScanLog->eventId = WLAN_SCAN_EVENT_ACTIVE_SCAN_REQ;
+ } else {
+ pScanLog->eventId = WLAN_SCAN_EVENT_PASSIVE_SCAN_REQ;
+ }
+ }
+ pScanLog->minChnTime =
+ (uint8_t) pCommand->u.scanCmd.u.scanRequest.minChnTime;
+ pScanLog->maxChnTime =
+ (uint8_t) pCommand->u.scanCmd.u.scanRequest.maxChnTime;
+ pScanLog->numChannel =
+ (uint8_t) pCommand->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels;
+ if (pScanLog->numChannel &&
+ (pScanLog->numChannel < HOST_LOG_MAX_NUM_CHANNEL)) {
+ cdf_mem_copy(pScanLog->channels,
+ pCommand->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList,
+ pScanLog->numChannel);
+ }
+ WLAN_HOST_DIAG_LOG_REPORT(pScanLog);
+}
+#else
+#define csr_diag_scan_channels(tpAniSirGlobal pMac, tSmeCmd *pCommand) (void)0;
+#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */
+
+CDF_STATUS csr_scan_channels(tpAniSirGlobal pMac, tSmeCmd *pCommand)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ tScanReqParam scanReq;
+
+ /*
+ * Don't delete cached results. Rome rssi based scan candidates may land
+ * up in scan cache instead of LFR cache. They will be deleted upon
+ * query
+ */
+ scanReq.freshScan = SIR_BG_SCAN_RETURN_FRESH_RESULTS;
+ scanReq.fUniqueResult = true;
+ scanReq.hiddenSsid = SIR_SCAN_NO_HIDDEN_SSID;
+ if (eCsrScanForSsid == pCommand->u.scanCmd.reason) {
+ scanReq.bReturnAfter1stMatch =
+ CSR_SCAN_RETURN_AFTER_FIRST_MATCH;
+ } else {
+ /*
+ * Basically do scan on all channels even for 11D 1st scan case
+ */
+ scanReq.bReturnAfter1stMatch =
+ CSR_SCAN_RETURN_AFTER_ALL_CHANNELS;
+ }
+ if (eCsrScanProbeBss == pCommand->u.scanCmd.reason)
+ scanReq.hiddenSsid = SIR_SCAN_HIDDEN_SSID_PE_DECISION;
+ csr_diag_scan_channels(pMac, pCommand);
+ csr_clear_votes_for_country_info(pMac);
+ status = csr_send_mb_scan_req(pMac, pCommand->sessionId,
+ &pCommand->u.scanCmd.u.scanRequest,
+ &scanReq);
+ return status;
+}
+
+static CDF_STATUS
+csr_issue_user_scan(tpAniSirGlobal mac_ctx, tSmeCmd *cmd)
+{
+ int i, j;
+ CDF_STATUS status;
+ uint32_t len = 0;
+ uint8_t *ch_lst = NULL;
+ tCsrChannelInfo new_ch_info = { 0, NULL };
+
+ if (!mac_ctx->roam.configParam.fScanTwice)
+ return csr_scan_channels(mac_ctx, cmd);
+
+ /* We scan 2.4 channel twice */
+ if (cmd->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels
+ && (NULL != cmd->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList)) {
+ len = cmd->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels;
+ /* allocate twice the channel */
+ new_ch_info.ChannelList = (uint8_t *) cdf_mem_malloc(len * 2);
+ ch_lst = cmd->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList;
+ } else {
+ /* get the valid channel list to scan all. */
+ len = sizeof(mac_ctx->roam.validChannelList);
+ status = csr_get_cfg_valid_channels(mac_ctx,
+ (uint8_t *) mac_ctx->roam.validChannelList, &len);
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ /* allocate twice the channel */
+ new_ch_info.ChannelList =
+ (uint8_t *) cdf_mem_malloc(len * 2);
+ ch_lst = mac_ctx->roam.validChannelList;
+ }
+ }
+ if (NULL == new_ch_info.ChannelList) {
+ new_ch_info.numOfChannels = 0;
+ } else {
+ j = 0;
+ for (i = 0; i < len; i++) {
+ new_ch_info.ChannelList[j++] = ch_lst[i];
+ if (CDS_MAX_24GHz_CHANNEL_NUMBER >= ch_lst[i])
+ new_ch_info.ChannelList[j++] = ch_lst[i];
+ }
+ if (NULL !=
+ cmd->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList) {
+ /*
+ * ch_lst points to the channellist from the command,
+ * free it.
+ */
+ cdf_mem_free(
+ cmd->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList);
+ cmd->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList =
+ NULL;
+ }
+ cmd->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels = j;
+ cmd->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList =
+ new_ch_info.ChannelList;
+ }
+
+ return csr_scan_channels(mac_ctx, cmd);
+}
+
+CDF_STATUS csr_process_scan_command(tpAniSirGlobal pMac, tSmeCmd *pCommand)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+
+ sms_log(pMac, LOG3,
+ FL("starting SCAN cmd in %d state. reason %d"),
+ pCommand->u.scanCmd.lastRoamState[pCommand->sessionId],
+ pCommand->u.scanCmd.reason);
+
+ switch (pCommand->u.scanCmd.reason) {
+ case eCsrScanUserRequest:
+ status = csr_issue_user_scan(pMac, pCommand);
+ break;
+ default:
+ status = csr_scan_channels(pMac, pCommand);
+ break;
+ }
+
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ csr_release_scan_command(pMac, pCommand, eCSR_SCAN_FAILURE);
+ }
+
+ return status;
+}
+
+/**
+ * csr_scan_copy_request_valid_channels_only() - scan request of valid channels
+ * @mac_ctx : pointer to Global Mac Structure
+ * @dst_req: pointer to tCsrScanRequest
+ * @skip_dfs_chnl: 1 - skip dfs channel, 0 - don't skip dfs channel
+ * @src_req: pointer to tCsrScanRequest
+ *
+ * This function makes a copy of scan request with valid channels
+ *
+ * Return: none
+ */
+static void csr_scan_copy_request_valid_channels_only(tpAniSirGlobal mac_ctx,
+ tCsrScanRequest *dst_req, uint8_t skip_dfs_chnl,
+ tCsrScanRequest *src_req)
+{
+ uint32_t index = 0;
+ uint32_t new_index = 0;
+
+ for (index = 0; index < src_req->ChannelInfo.numOfChannels; index++) {
+ /* Allow scan on valid channels only.
+ * If it is p2p scan and valid channel list doesnt contain
+ * social channels, enforce scan on social channels because
+ * that is the only way to find p2p peers.
+ * This can happen only if band is set to 5Ghz mode.
+ */
+ if (src_req->ChannelInfo.ChannelList[index] < MIN_11P_CHANNEL &&
+ ((csr_roam_is_valid_channel(mac_ctx,
+ src_req->ChannelInfo.ChannelList[index])) ||
+ ((eCSR_SCAN_P2P_DISCOVERY == src_req->requestType) &&
+ CSR_IS_SOCIAL_CHANNEL(
+ src_req->ChannelInfo.ChannelList[index])))) {
+ if (((src_req->skipDfsChnlInP2pSearch || skip_dfs_chnl)
+ && (CHANNEL_STATE_DFS ==
+ cds_get_channel_state(src_req->
+ ChannelInfo.
+ ChannelList
+ [index])))
+ ) {
+#ifdef FEATURE_WLAN_LFR
+ sms_log(mac_ctx, LOG2,
+ FL(" reqType=%d, numOfChannels=%d, ignoring DFS channel %d"),
+ src_req->requestType,
+ src_req->ChannelInfo.numOfChannels,
+ src_req->ChannelInfo.ChannelList
+ [index]);
+#endif
+ continue;
+ }
+
+ dst_req->ChannelInfo.ChannelList[new_index] =
+ src_req->ChannelInfo.ChannelList[index];
+ new_index++;
+ }
+ }
+ dst_req->ChannelInfo.numOfChannels = new_index;
+}
+
+/**
+ * csr_scan_copy_request() - Function to copy scan request
+ * @mac_ctx : pointer to Global Mac Structure
+ * @dst_req: pointer to tCsrScanRequest
+ * @src_req: pointer to tCsrScanRequest
+ *
+ * This function makes a copy of scan request
+ *
+ * Return: 0 - Success, Error number - Failure
+ */
+CDF_STATUS csr_scan_copy_request(tpAniSirGlobal mac_ctx,
+ tCsrScanRequest *dst_req,
+ tCsrScanRequest *src_req)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ uint32_t len = sizeof(mac_ctx->roam.validChannelList);
+ uint32_t index = 0;
+ uint32_t new_index = 0;
+ CHANNEL_STATE channel_state;
+ bool skip_dfs_chnl =
+ mac_ctx->roam.configParam.initial_scan_no_dfs_chnl ||
+ !mac_ctx->scan.fEnableDFSChnlScan;
+
+ status = csr_scan_free_request(mac_ctx, dst_req);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ goto complete;
+ cdf_mem_copy(dst_req, src_req, sizeof(tCsrScanRequest));
+ /* Re-initialize the pointers to NULL since we did a copy */
+ dst_req->pIEField = NULL;
+ dst_req->ChannelInfo.ChannelList = NULL;
+ dst_req->SSIDs.SSIDList = NULL;
+
+ if (src_req->uIEFieldLen) {
+ dst_req->pIEField =
+ cdf_mem_malloc(src_req->uIEFieldLen);
+ if (NULL == dst_req->pIEField) {
+ status = CDF_STATUS_E_NOMEM;
+ sms_log(mac_ctx, LOGE,
+ FL("No memory for scanning IE fields"));
+ goto complete;
+ } else {
+ status = CDF_STATUS_SUCCESS;
+ cdf_mem_copy(dst_req->pIEField, src_req->pIEField,
+ src_req->uIEFieldLen);
+ dst_req->uIEFieldLen = src_req->uIEFieldLen;
+ }
+ }
+
+ /* Allocate memory for IE field */
+ if (src_req->ChannelInfo.numOfChannels == 0) {
+ dst_req->ChannelInfo.ChannelList = NULL;
+ dst_req->ChannelInfo.numOfChannels = 0;
+ } else {
+ dst_req->ChannelInfo.ChannelList =
+ cdf_mem_malloc(src_req->ChannelInfo.numOfChannels *
+ sizeof(*dst_req->ChannelInfo.ChannelList));
+ if (NULL == dst_req->ChannelInfo.ChannelList) {
+ status = CDF_STATUS_E_NOMEM;
+ dst_req->ChannelInfo.numOfChannels = 0;
+ sms_log(mac_ctx, LOGE,
+ FL("No memory for scanning Channel List"));
+ goto complete;
+ }
+
+ if ((src_req->scanType == eSIR_PASSIVE_SCAN) &&
+ (src_req->requestType == eCSR_SCAN_REQUEST_11D_SCAN)) {
+ for (index = 0; index < src_req->ChannelInfo.
+ numOfChannels; index++) {
+ channel_state =
+ cds_get_channel_state(src_req->
+ ChannelInfo.
+ ChannelList[index]);
+ if (src_req->ChannelInfo.ChannelList[index] <
+ MIN_11P_CHANNEL &&
+ ((CHANNEL_STATE_ENABLE ==
+ channel_state) ||
+ ((CHANNEL_STATE_DFS == channel_state) &&
+ !skip_dfs_chnl))) {
+ dst_req->ChannelInfo.ChannelList
+ [new_index] =
+ src_req->
+ ChannelInfo.
+ ChannelList
+ [index];
+ new_index++;
+ }
+ }
+ dst_req->ChannelInfo.numOfChannels = new_index;
+ } else if (CDF_IS_STATUS_SUCCESS(
+ csr_get_cfg_valid_channels(mac_ctx,
+ mac_ctx->roam.validChannelList,
+ &len))) {
+ new_index = 0;
+ mac_ctx->roam.numValidChannels = len;
+ csr_scan_copy_request_valid_channels_only(mac_ctx,
+ dst_req, skip_dfs_chnl,
+ src_req);
+ } else {
+ sms_log(mac_ctx, LOGE,
+ FL("Couldn't get the valid Channel List, keeping requester's list"));
+ new_index = 0;
+ for (index = 0; index < src_req->ChannelInfo.
+ numOfChannels; index++) {
+ if (src_req->ChannelInfo.ChannelList[index] <
+ MIN_11P_CHANNEL) {
+ dst_req->ChannelInfo.
+ ChannelList[new_index] =
+ src_req->ChannelInfo.
+ ChannelList[index];
+ new_index++;
+ }
+ }
+ dst_req->ChannelInfo.numOfChannels =
+ new_index;
+ }
+ } /* Allocate memory for Channel List */
+ if (src_req->SSIDs.numOfSSIDs == 0) {
+ dst_req->SSIDs.numOfSSIDs = 0;
+ dst_req->SSIDs.SSIDList = NULL;
+ } else {
+ dst_req->SSIDs.SSIDList =
+ cdf_mem_malloc(src_req->SSIDs.numOfSSIDs *
+ sizeof(*dst_req->SSIDs.SSIDList));
+ if (NULL == dst_req->SSIDs.SSIDList)
+ status = CDF_STATUS_E_NOMEM;
+ else
+ status = CDF_STATUS_SUCCESS;
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ dst_req->SSIDs.numOfSSIDs =
+ src_req->SSIDs.numOfSSIDs;
+ cdf_mem_copy(dst_req->SSIDs.SSIDList,
+ src_req->SSIDs.SSIDList,
+ src_req->SSIDs.numOfSSIDs *
+ sizeof(*dst_req->SSIDs.SSIDList));
+ } else {
+ dst_req->SSIDs.numOfSSIDs = 0;
+ sms_log(mac_ctx, LOGE,
+ FL("No memory for scanning SSID List"));
+ goto complete;
+ }
+ } /* Allocate memory for SSID List */
+ dst_req->p2pSearch = src_req->p2pSearch;
+ dst_req->skipDfsChnlInP2pSearch =
+ src_req->skipDfsChnlInP2pSearch;
+ dst_req->scan_id = src_req->scan_id;
+ dst_req->timestamp = src_req->timestamp;
+
+complete:
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ csr_scan_free_request(mac_ctx, dst_req);
+ }
+
+ return status;
+}
+
+CDF_STATUS csr_scan_free_request(tpAniSirGlobal pMac, tCsrScanRequest *pReq)
+{
+
+ if (pReq->ChannelInfo.ChannelList) {
+ cdf_mem_free(pReq->ChannelInfo.ChannelList);
+ pReq->ChannelInfo.ChannelList = NULL;
+ }
+ pReq->ChannelInfo.numOfChannels = 0;
+ if (pReq->pIEField) {
+ cdf_mem_free(pReq->pIEField);
+ pReq->pIEField = NULL;
+ }
+ pReq->uIEFieldLen = 0;
+ if (pReq->SSIDs.SSIDList) {
+ cdf_mem_free(pReq->SSIDs.SSIDList);
+ pReq->SSIDs.SSIDList = NULL;
+ }
+ pReq->SSIDs.numOfSSIDs = 0;
+
+ return CDF_STATUS_SUCCESS;
+}
+
+void csr_scan_call_callback(tpAniSirGlobal pMac, tSmeCmd *pCommand,
+ eCsrScanStatus scanStatus)
+{
+ if (pCommand->u.scanCmd.callback) {
+ pCommand->u.scanCmd.callback(pMac, pCommand->u.scanCmd.pContext,
+ pCommand->sessionId,
+ pCommand->u.scanCmd.scanID,
+ scanStatus);
+ } else {
+ sms_log(pMac, LOG2, "%s:%d - Callback NULL!!!", __func__,
+ __LINE__);
+ }
+}
+
+void csr_scan_stop_timers(tpAniSirGlobal pMac)
+{
+ if (0 != pMac->scan.scanResultCfgAgingTime) {
+ csr_scan_stop_result_cfg_aging_timer(pMac);
+ }
+
+}
+
+#ifdef WLAN_AP_STA_CONCURRENCY
+/**
+ * csr_sta_ap_conc_timer_handler - Function to handle STA,AP concurrency timer
+ * @pv: pointer variable
+ *
+ * Function handles STA,AP concurrency timer
+ *
+ * Return: none
+ */
+static void csr_sta_ap_conc_timer_handler(void *pv)
+{
+ tpAniSirGlobal mac_ctx = PMAC_STRUCT(pv);
+ tListElem *entry;
+ tSmeCmd *scan_cmd;
+ uint32_t session_id = CSR_SESSION_ID_INVALID;
+ tCsrScanRequest scan_req;
+ tSmeCmd *send_scancmd = NULL;
+ uint8_t num_chn = 0;
+ uint8_t numchan_combinedconc = 0;
+ uint8_t i, j;
+ tCsrChannelInfo *chn_info = NULL;
+ uint8_t channel_to_scan[WNI_CFG_VALID_CHANNEL_LIST_LEN];
+ CDF_STATUS status;
+
+ csr_ll_lock(&mac_ctx->scan.scanCmdPendingList);
+
+ entry = csr_ll_peek_head(&mac_ctx->scan.scanCmdPendingList,
+ LL_ACCESS_NOLOCK);
+
+ if (NULL == entry) {
+ csr_ll_unlock(&mac_ctx->scan.scanCmdPendingList);
+ return;
+ }
+
+
+ chn_info = &scan_req.ChannelInfo;
+ scan_cmd = GET_BASE_ADDR(entry, tSmeCmd, Link);
+ num_chn =
+ scan_cmd->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels;
+ session_id = scan_cmd->sessionId;
+
+ /*
+ * if any session is connected and the number of channels to scan is
+ * greater than 1 then split the scan into multiple scan operations
+ * on each individual channel else continue to perform scan on all
+ * specified channels */
+
+ /*
+ * split scan if number of channels to scan is greater than 1 and
+ * any one of the following:
+ * - STA session is connected and the scan is not a P2P search
+ * - any P2P session is connected
+ * Do not split scans if no concurrent infra connections are
+ * active and if the scan is a BG scan triggered by LFR (OR)
+ * any scan if LFR is in the middle of a BG scan. Splitting
+ * the scan is delaying the time it takes for LFR to find
+ * candidates and resulting in disconnects.
+ */
+
+ if ((csr_is_sta_session_connected(mac_ctx) &&
+ !csr_is_p2p_session_connected(mac_ctx)))
+ numchan_combinedconc =
+ mac_ctx->roam.configParam.nNumStaChanCombinedConc;
+ else if (csr_is_p2p_session_connected(mac_ctx))
+ numchan_combinedconc =
+ mac_ctx->roam.configParam.nNumP2PChanCombinedConc;
+
+ if ((num_chn > numchan_combinedconc) &&
+ ((csr_is_sta_session_connected(mac_ctx) &&
+#ifdef FEATURE_WLAN_LFR
+ (csr_is_concurrent_infra_connected(mac_ctx)) &&
+#endif
+ (scan_cmd->u.scanCmd.u.scanRequest.p2pSearch != 1)) ||
+ (csr_is_p2p_session_connected(mac_ctx)))) {
+ cdf_mem_set(&scan_req, sizeof(tCsrScanRequest), 0);
+
+ /* optimize this to use 2 command buffer only */
+ send_scancmd = csr_get_command_buffer(mac_ctx);
+ if (!send_scancmd) {
+ sms_log(mac_ctx, LOGE,
+ FL(" Failed to get Queue command buffer"));
+ csr_ll_unlock(&mac_ctx->scan.scanCmdPendingList);
+ return;
+ }
+ send_scancmd->command = scan_cmd->command;
+ send_scancmd->sessionId = scan_cmd->sessionId;
+ send_scancmd->u.scanCmd.callback = NULL;
+ send_scancmd->u.scanCmd.pContext =
+ scan_cmd->u.scanCmd.pContext;
+ send_scancmd->u.scanCmd.reason =
+ scan_cmd->u.scanCmd.reason;
+ /* let it wrap around */
+ wma_get_scan_id(&send_scancmd->u.scanCmd.scanID);
+
+ /*
+ * First copy all the parameters to local variable of scan
+ * request
+ */
+ csr_scan_copy_request(mac_ctx, &scan_req,
+ &scan_cmd->u.scanCmd.u.scanRequest);
+
+ /*
+ * Now modify the elements of local var scan request required
+ * to be modified for split scan
+ */
+ if (scan_req.ChannelInfo.ChannelList != NULL) {
+ cdf_mem_free(scan_req.ChannelInfo.ChannelList);
+ scan_req.ChannelInfo.ChannelList = NULL;
+ }
+
+ chn_info->numOfChannels = numchan_combinedconc;
+ cdf_mem_copy(&channel_to_scan[0],
+ &scan_cmd->u.scanCmd.u.scanRequest.ChannelInfo.
+ ChannelList[0], chn_info->numOfChannels
+ * sizeof(uint8_t));
+ chn_info->ChannelList = &channel_to_scan[0];
+
+ for (i = 0, j = numchan_combinedconc;
+ i < (num_chn - numchan_combinedconc);
+ i++, j++) {
+ /* Move all the channels one step */
+ scan_cmd->u.scanCmd.u.scanRequest.ChannelInfo.
+ ChannelList[i] =
+ scan_cmd->u.scanCmd.u.scanRequest.
+ ChannelInfo.ChannelList[j];
+ }
+
+ /* reduce outstanding # of channels to be scanned */
+ scan_cmd->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels =
+ num_chn - numchan_combinedconc;
+
+ scan_req.BSSType = eCSR_BSS_TYPE_ANY;
+ /* Modify callers parameters in case of concurrency */
+ scan_req.scanType = eSIR_ACTIVE_SCAN;
+ /* Use concurrency values for min/maxChnTime. */
+ csr_set_default_scan_timing(mac_ctx, scan_req.scanType,
+ &scan_req);
+
+ status = csr_scan_copy_request(mac_ctx,
+ &send_scancmd->u.scanCmd.u.
+ scanRequest, &scan_req);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(mac_ctx, LOGE,
+ FL(" Failed to get copy csr_scan_request = %d"),
+ status);
+ csr_ll_unlock(&mac_ctx->scan.scanCmdPendingList);
+ return;
+ }
+ /* Clean the local scan variable */
+ scan_req.ChannelInfo.ChannelList = NULL;
+ scan_req.ChannelInfo.numOfChannels = 0;
+ csr_scan_free_request(mac_ctx, &scan_req);
+ } else {
+ /*
+ * no active connected session present or numChn == 1
+ * scan all remaining channels
+ */
+ send_scancmd = scan_cmd;
+ /* remove this command from pending list */
+ if (csr_ll_remove_head(&mac_ctx->scan.scanCmdPendingList,
+ /*
+ * In case between PeekHead and here, the entry
+ * got removed by another thread.
+ */
+ LL_ACCESS_NOLOCK) == NULL) {
+ sms_log(mac_ctx, LOGE,
+ FL(" Failed to remove entry from scanCmdPendingList"));
+ }
+
+ }
+ csr_queue_sme_command(mac_ctx, send_scancmd, false);
+
+
+ csr_ll_unlock(&mac_ctx->scan.scanCmdPendingList);
+
+}
+#endif
+
+CDF_STATUS csr_scan_start_result_cfg_aging_timer(tpAniSirGlobal pMac)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+
+ if (pMac->scan.fScanEnable) {
+ status =
+ cdf_mc_timer_start(&pMac->scan.hTimerResultCfgAging,
+ CSR_SCAN_RESULT_CFG_AGING_INTERVAL /
+ CDF_MC_TIMER_TO_MS_UNIT);
+ }
+ return status;
+}
+
+CDF_STATUS csr_scan_stop_result_cfg_aging_timer(tpAniSirGlobal pMac)
+{
+ return cdf_mc_timer_stop(&pMac->scan.hTimerResultCfgAging);
+}
+
+/**
+ * csr_scan_result_cfg_aging_timer_handler() - Time based scan aging handler
+ * @pv: Global context
+ *
+ * This routine is to handle scan aging based on user configured timer value.
+ *
+ * Return: None
+ */
+static void csr_scan_result_cfg_aging_timer_handler(void *pv)
+{
+ tpAniSirGlobal mac_ctx = PMAC_STRUCT(pv);
+ tListElem *entry, *tmp_entry;
+ tCsrScanResult *result;
+ uint32_t ageout_time =
+ mac_ctx->scan.scanResultCfgAgingTime * CDF_TICKS_PER_SECOND/10;
+ uint32_t cur_time = (uint32_t) cdf_mc_timer_get_system_ticks();
+ uint8_t *bssId;
+
+ csr_ll_lock(&mac_ctx->scan.scanResultList);
+ entry = csr_ll_peek_head(&mac_ctx->scan.scanResultList, LL_ACCESS_NOLOCK);
+ while (entry) {
+ tmp_entry = csr_ll_next(&mac_ctx->scan.scanResultList, entry,
+ LL_ACCESS_NOLOCK);
+ result = GET_BASE_ADDR(entry, tCsrScanResult, Link);
+ /*
+ * cdf_mc_timer_get_system_ticks() returns in 10ms interval.
+ * so ageout time value also updated to 10ms interval value.
+ */
+ if ((cur_time - result->Result.BssDescriptor.nReceivedTime) >
+ ageout_time) {
+ bssId = result->Result.BssDescriptor.bssId;
+ sms_log(mac_ctx, LOGW,
+ FL("age out due to time out"MAC_ADDRESS_STR),
+ MAC_ADDR_ARRAY(bssId));
+ csr_scan_age_out_bss(mac_ctx, result);
+ }
+ entry = tmp_entry;
+ }
+ csr_ll_unlock(&mac_ctx->scan.scanResultList);
+ cdf_mc_timer_start(&mac_ctx->scan.hTimerResultCfgAging,
+ CSR_SCAN_RESULT_CFG_AGING_INTERVAL /
+ CDF_MC_TIMER_TO_MS_UNIT);
+}
+
+bool csr_scan_remove_fresh_scan_command(tpAniSirGlobal pMac, uint8_t sessionId)
+{
+ bool fRet = false;
+ tListElem *pEntry, *pEntryTmp;
+ tSmeCmd *pCommand;
+ tDblLinkList localList;
+ tDblLinkList *pCmdList;
+
+ cdf_mem_zero(&localList, sizeof(tDblLinkList));
+ if (!CDF_IS_STATUS_SUCCESS(csr_ll_open(pMac->hHdd, &localList))) {
+ sms_log(pMac, LOGE, FL(" failed to open list"));
+ return fRet;
+ }
+
+ pCmdList = &pMac->sme.smeScanCmdPendingList;
+
+ csr_ll_lock(pCmdList);
+ pEntry = csr_ll_peek_head(pCmdList, LL_ACCESS_NOLOCK);
+ while (pEntry) {
+ pEntryTmp = csr_ll_next(pCmdList, pEntry, LL_ACCESS_NOLOCK);
+ pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
+ if (!((eSmeCommandScan == pCommand->command)
+ && (sessionId == pCommand->sessionId))) {
+ pEntry = pEntryTmp;
+ continue;
+ }
+ sms_log(pMac, LOGW,
+ FL("-------- abort scan command reason = %d"),
+ pCommand->u.scanCmd.reason);
+ /* The rest are fresh scan requests */
+ if (csr_ll_remove_entry(pCmdList, pEntry,
+ LL_ACCESS_NOLOCK)) {
+ csr_ll_insert_tail(&localList, pEntry,
+ LL_ACCESS_NOLOCK);
+ }
+ fRet = true;
+ pEntry = pEntryTmp;
+ }
+
+ csr_ll_unlock(pCmdList);
+
+ while ((pEntry = csr_ll_remove_head(&localList, LL_ACCESS_NOLOCK))) {
+ pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
+ if (pCommand->u.scanCmd.callback) {
+ /*
+ * User scan request is pending, send response with
+ * status eCSR_SCAN_ABORT
+ */
+ pCommand->u.scanCmd.callback(pMac,
+ pCommand->u.scanCmd.pContext, sessionId,
+ pCommand->u.scanCmd.scanID, eCSR_SCAN_ABORT);
+ }
+ csr_release_command_scan(pMac, pCommand);
+ }
+ csr_ll_close(&localList);
+
+ return fRet;
+}
+
+void csr_release_scan_command(tpAniSirGlobal pMac, tSmeCmd *pCommand,
+ eCsrScanStatus scanStatus)
+{
+ eCsrScanReason reason = pCommand->u.scanCmd.reason;
+ bool status;
+ tDblLinkList *cmd_list = NULL;
+
+ csr_scan_call_callback(pMac, pCommand, scanStatus);
+ sms_log(pMac, LOG1, FL("Remove Scan command reason = %d, scan_id %d"),
+ reason, pCommand->u.scanCmd.scanID);
+ cmd_list = &pMac->sme.smeScanCmdActiveList;
+ status = csr_ll_remove_entry(cmd_list, &pCommand->Link, LL_ACCESS_LOCK);
+ if (!status) {
+ sms_log(pMac, LOGE,
+ FL("cannot release command reason %d scan_id %d"),
+ pCommand->u.scanCmd.reason,
+ pCommand->u.scanCmd.scanID);
+ return;
+ }
+ csr_release_command_scan(pMac, pCommand);
+}
+
+CDF_STATUS csr_scan_get_pmkid_candidate_list(tpAniSirGlobal pMac,
+ uint32_t sessionId,
+ tPmkidCandidateInfo *pPmkidList,
+ uint32_t *pNumItems)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+ tCsrScanResultFilter *pScanFilter;
+ tCsrScanResultInfo *pScanResult;
+ tScanResultHandle hBSSList;
+ uint32_t nItems = *pNumItems;
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ sms_log(pMac, LOGW, FL("pMac->scan.NumPmkidCandidate = %d"),
+ pSession->NumPmkidCandidate);
+ csr_reset_pmkid_candidate_list(pMac, sessionId);
+ if (!(csr_is_conn_state_connected(pMac, sessionId)
+ && pSession->pCurRoamProfile))
+ return status;
+
+ *pNumItems = 0;
+ pScanFilter = cdf_mem_malloc(sizeof(tCsrScanResultFilter));
+ if (NULL == pScanFilter)
+ return CDF_STATUS_E_NOMEM;
+
+ cdf_mem_set(pScanFilter, sizeof(tCsrScanResultFilter), 0);
+ /* Here is the profile we need to connect to */
+ status = csr_roam_prepare_filter_from_profile(pMac,
+ pSession->pCurRoamProfile, pScanFilter);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ cdf_mem_free(pScanFilter);
+ return status;
+ }
+
+ status = csr_scan_get_result(pMac, pScanFilter, &hBSSList);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ csr_free_scan_filter(pMac, pScanFilter);
+ cdf_mem_free(pScanFilter);
+ return status;
+ }
+
+ if (pSession->NumPmkidCandidate < nItems) {
+ pScanResult = csr_scan_result_get_next(pMac, hBSSList);
+ while (pScanResult != NULL) {
+ /* NumPmkidCandidate adds up here */
+ csr_process_bss_desc_for_pmkid_list(pMac,
+ &pScanResult->BssDescriptor,
+ (tDot11fBeaconIEs *)(pScanResult->pvIes),
+ sessionId);
+ pScanResult = csr_scan_result_get_next(pMac, hBSSList);
+ }
+ }
+
+ if (pSession->NumPmkidCandidate) {
+ *pNumItems = pSession->NumPmkidCandidate;
+ cdf_mem_copy(pPmkidList, pSession->PmkidCandidateInfo,
+ pSession->NumPmkidCandidate *
+ sizeof(tPmkidCandidateInfo));
+ }
+
+ csr_scan_result_purge(pMac, hBSSList);
+ csr_free_scan_filter(pMac, pScanFilter);
+ cdf_mem_free(pScanFilter);
+ return status;
+}
+
+#ifdef FEATURE_WLAN_WAPI
+CDF_STATUS csr_scan_get_bkid_candidate_list(tpAniSirGlobal pMac,
+ uint32_t sessionId,
+ tBkidCandidateInfo *pBkidList,
+ uint32_t *pNumItems)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+ tCsrScanResultFilter *pScanFilter;
+ tCsrScanResultInfo *pScanResult;
+ tScanResultHandle hBSSList;
+ uint32_t nItems = *pNumItems;
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ sms_log(pMac, LOGW, FL("pMac->scan.NumBkidCandidate = %d"),
+ pSession->NumBkidCandidate);
+ csr_reset_bkid_candidate_list(pMac, sessionId);
+ if (!(csr_is_conn_state_connected(pMac, sessionId)
+ && pSession->pCurRoamProfile))
+ return status;
+
+ *pNumItems = 0;
+ pScanFilter = cdf_mem_malloc(sizeof(tCsrScanResultFilter));
+ if (NULL == pScanFilter)
+ return CDF_STATUS_E_NOMEM;
+
+ cdf_mem_set(pScanFilter, sizeof(tCsrScanResultFilter), 0);
+ /* Here is the profile we need to connect to */
+ status = csr_roam_prepare_filter_from_profile(pMac,
+ pSession->pCurRoamProfile, pScanFilter);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ cdf_mem_free(pScanFilter);
+ return status;
+ }
+
+ status = csr_scan_get_result(pMac, pScanFilter, &hBSSList);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ csr_free_scan_filter(pMac, pScanFilter);
+ cdf_mem_free(pScanFilter);
+ return status;
+ }
+
+ if (pSession->NumBkidCandidate < nItems) {
+ pScanResult = csr_scan_result_get_next(pMac, hBSSList);
+ while (pScanResult != NULL) {
+ /* pMac->scan.NumBkidCandidate adds up here */
+ csr_process_bss_desc_for_bkid_list(pMac,
+ &pScanResult->BssDescriptor,
+ (tDot11fBeaconIEs *)(pScanResult->pvIes));
+ pScanResult = csr_scan_result_get_next(pMac, hBSSList);
+ }
+ }
+
+ if (pSession->NumBkidCandidate) {
+ *pNumItems = pSession->NumBkidCandidate;
+ cdf_mem_copy(pBkidList, pSession->BkidCandidateInfo,
+ pSession->NumBkidCandidate *
+ sizeof(tBkidCandidateInfo));
+ }
+
+ csr_scan_result_purge(pMac, hBSSList);
+ csr_free_scan_filter(pMac, pScanFilter);
+ cdf_mem_free(pScanFilter);
+ return status;
+}
+#endif /* FEATURE_WLAN_WAPI */
+
+/**
+ * csr_roam_copy_channellist() - Function to copy channel list
+ * @mac_ctx: pointer to Global Mac structure
+ * @profile: pointer to tCsrRoamProfile
+ * @scan_cmd: pointer to tSmeCmd
+ * @index: index for channellist
+ *
+ * Function copies channel list
+ *
+ * Return: none
+ */
+static void csr_roam_copy_channellist(tpAniSirGlobal mac_ctx,
+ tCsrRoamProfile *profile,
+ tSmeCmd *scan_cmd, uint8_t index)
+{
+ tCsrChannelInfo *channel_info =
+ &scan_cmd->u.scanCmd.u.scanRequest.ChannelInfo;
+
+ for (index = 0; index < profile->ChannelInfo.numOfChannels;
+ index++) {
+ if (!csr_roam_is_valid_channel(mac_ctx,
+ profile->ChannelInfo.ChannelList[index])) {
+ sms_log(mac_ctx, LOGW,
+ FL("process a channel (%d) that is invalid"),
+ profile->ChannelInfo.ChannelList[index]);
+ continue;
+ }
+ channel_info->ChannelList[channel_info->numOfChannels] =
+ profile->ChannelInfo.ChannelList[index];
+ scan_cmd->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels++;
+ }
+}
+
+/**
+ * csr_scan_for_ssid() - Function usually used for BSSs that suppresses SSID
+ * @mac_ctx: Pointer to Global Mac structure
+ * @profile: pointer to tCsrRoamProfile
+ * @roam_id: variable representing roam id
+ * @notify: boolean variable
+ *
+ * Function is usually used for BSSs that suppresses SSID so the profile
+ * shall have one and only one SSID.
+ *
+ * Return: Success - CDF_STATUS_SUCCESS, Failure - error number
+ */
+CDF_STATUS csr_scan_for_ssid(tpAniSirGlobal mac_ctx, uint32_t session_id,
+ tCsrRoamProfile *profile, uint32_t roam_id,
+ bool notify)
+{
+ CDF_STATUS status = CDF_STATUS_E_INVAL;
+ tSmeCmd *scan_cmd = NULL;
+ tCsrScanRequest *scan_req = NULL;
+ uint8_t index = 0;
+ uint32_t num_ssid = profile->SSIDs.numOfSSIDs;
+ tpCsrNeighborRoamControlInfo neighbor_roaminfo =
+ &mac_ctx->roam.neighborRoamInfo[session_id];
+ tCsrSSIDs *ssids = NULL;
+
+ sms_log(mac_ctx, LOG2, FL("called"));
+
+ /* For WDS, we use the index 0. There must be at least one in there */
+ if (CSR_IS_WDS_STA(profile) && num_ssid)
+ num_ssid = 1;
+
+ if (!(mac_ctx->scan.fScanEnable) && (num_ssid != 1)) {
+ sms_log(mac_ctx, LOGE,
+ FL("cannot scan because scanEnable (%d) or numSSID (%d) is invalid"),
+ mac_ctx->scan.fScanEnable, profile->SSIDs.numOfSSIDs);
+ return status;
+ }
+
+ scan_cmd = csr_get_command_buffer(mac_ctx);
+
+ if (!scan_cmd) {
+ sms_log(mac_ctx, LOGE,
+ FL("failed to allocate command buffer"));
+ goto error;
+ }
+
+ cdf_mem_set(&scan_cmd->u.scanCmd, sizeof(tScanCmd), 0);
+ scan_cmd->u.scanCmd.pToRoamProfile =
+ cdf_mem_malloc(sizeof(tCsrRoamProfile));
+
+ if (NULL == scan_cmd->u.scanCmd.pToRoamProfile)
+ status = CDF_STATUS_E_NOMEM;
+ else
+ status = csr_roam_copy_profile(mac_ctx,
+ scan_cmd->u.scanCmd.pToRoamProfile,
+ profile);
+
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ goto error;
+
+ scan_cmd->u.scanCmd.roamId = roam_id;
+ scan_cmd->command = eSmeCommandScan;
+ scan_cmd->sessionId = (uint8_t) session_id;
+ scan_cmd->u.scanCmd.callback = NULL;
+ scan_cmd->u.scanCmd.pContext = NULL;
+ scan_cmd->u.scanCmd.reason = eCsrScanForSsid;
+
+ /* let it wrap around */
+ wma_get_scan_id(&scan_cmd->u.scanCmd.scanID);
+ cdf_mem_set(&scan_cmd->u.scanCmd.u.scanRequest,
+ sizeof(tCsrScanRequest), 0);
+ status = cdf_mc_timer_init(&scan_cmd->u.scanCmd.csr_scan_timer,
+ CDF_TIMER_TYPE_SW,
+ csr_scan_active_list_timeout_handle, &scan_cmd);
+ scan_req = &scan_cmd->u.scanCmd.u.scanRequest;
+ scan_req->scanType = eSIR_ACTIVE_SCAN;
+ scan_req->BSSType = profile->BSSType;
+ scan_req->scan_id = scan_cmd->u.scanCmd.scanID;
+ /*
+ * To avoid 11b rate in probe request Set p2pSearch
+ * flag as 1 for P2P Client Mode
+ */
+ if (CDF_P2P_CLIENT_MODE == profile->csrPersona)
+ scan_req->p2pSearch = 1;
+
+ /* Allocate memory for IE field */
+ if (profile->pAddIEScan) {
+ scan_req->pIEField =
+ cdf_mem_malloc(profile->nAddIEScanLength);
+
+ if (NULL == scan_req->pIEField)
+ status = CDF_STATUS_E_NOMEM;
+ else
+ status = CDF_STATUS_SUCCESS;
+
+ cdf_mem_set(scan_req->pIEField,
+ profile->nAddIEScanLength, 0);
+
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ cdf_mem_copy(scan_req->pIEField,
+ profile->pAddIEScan,
+ profile->nAddIEScanLength);
+ scan_req->uIEFieldLen = profile->nAddIEScanLength;
+ } else {
+ sms_log(mac_ctx, LOGE,
+ "No memory for scanning IE fields");
+ }
+ } else
+ scan_req->uIEFieldLen = 0;
+
+ /*
+ * For one channel be good enpugh time to receive beacon
+ * atleast
+ */
+ if (1 == profile->ChannelInfo.numOfChannels) {
+ if (neighbor_roaminfo->handoffReqInfo.src ==
+ FASTREASSOC) {
+ scan_req->maxChnTime =
+ MAX_ACTIVE_SCAN_FOR_ONE_CHANNEL_FASTREASSOC;
+ scan_req->minChnTime =
+ MIN_ACTIVE_SCAN_FOR_ONE_CHANNEL_FASTREASSOC;
+ /* Reset this value */
+ neighbor_roaminfo->handoffReqInfo.src = 0;
+ } else {
+ scan_req->maxChnTime =
+ MAX_ACTIVE_SCAN_FOR_ONE_CHANNEL;
+ scan_req->minChnTime =
+ MIN_ACTIVE_SCAN_FOR_ONE_CHANNEL;
+ }
+ } else {
+ scan_req->maxChnTime =
+ mac_ctx->roam.configParam.nActiveMaxChnTime;
+ scan_req->minChnTime =
+ mac_ctx->roam.configParam.nActiveMinChnTime;
+ }
+
+ if (profile->BSSIDs.numOfBSSIDs == 1)
+ cdf_copy_macaddr(&scan_req->bssid,
+ profile->BSSIDs.bssid);
+ else
+ cdf_set_macaddr_broadcast(&scan_req->bssid);
+
+ if (profile->ChannelInfo.numOfChannels) {
+ scan_req->ChannelInfo.ChannelList =
+ cdf_mem_malloc(sizeof(*scan_req->ChannelInfo.ChannelList) *
+ profile->ChannelInfo.numOfChannels);
+
+ if (NULL == scan_req->ChannelInfo.ChannelList)
+ status = CDF_STATUS_E_NOMEM;
+ else
+ status = CDF_STATUS_SUCCESS;
+
+ scan_req->ChannelInfo.numOfChannels = 0;
+
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ csr_roam_is_channel_valid(mac_ctx,
+ profile->ChannelInfo.ChannelList[0]);
+ csr_roam_copy_channellist(mac_ctx,
+ profile, scan_cmd, index);
+ } else {
+ goto error;
+ }
+ } else {
+ scan_req->ChannelInfo.numOfChannels = 0;
+ }
+
+ if (profile->SSIDs.numOfSSIDs) {
+ scan_req->SSIDs.SSIDList =
+ cdf_mem_malloc(profile->SSIDs.numOfSSIDs *
+ sizeof(tCsrSSIDInfo));
+
+ if (NULL == scan_req->SSIDs.SSIDList)
+ status = CDF_STATUS_E_NOMEM;
+ else
+ status = CDF_STATUS_SUCCESS;
+
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ goto error;
+
+ ssids = &scan_req->SSIDs;
+ ssids->numOfSSIDs = 1;
+
+ cdf_mem_copy(scan_req->SSIDs.SSIDList,
+ profile->SSIDs.SSIDList,
+ sizeof(tCsrSSIDInfo));
+ }
+
+ /* Start process the command */
+ status = csr_queue_sme_command(mac_ctx, scan_cmd, false);
+error:
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(mac_ctx, LOGE,
+ FL(" failed to iniate scan with status = %d"), status);
+ if (scan_cmd)
+ csr_release_command_scan(mac_ctx, scan_cmd);
+ if (notify)
+ csr_roam_call_callback(mac_ctx, session_id, NULL,
+ roam_id, eCSR_ROAM_FAILED,
+ eCSR_ROAM_RESULT_FAILURE);
+ }
+ return status;
+}
+
+void csr_set_cfg_valid_channel_list(tpAniSirGlobal pMac, uint8_t *pChannelList,
+ uint8_t NumChannels)
+{
+ uint32_t dataLen = sizeof(uint8_t) * NumChannels;
+ CDF_STATUS status;
+
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ "%s: dump valid channel list(NumChannels(%d))",
+ __func__, NumChannels);
+ CDF_TRACE_HEX_DUMP(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ pChannelList, NumChannels);
+ cfg_set_str(pMac, WNI_CFG_VALID_CHANNEL_LIST, pChannelList,
+ dataLen);
+
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ "Scan offload is enabled, update default chan list");
+ /*
+ * disable fcc constraint since new country code
+ * is being set
+ */
+ pMac->scan.fcc_constraint = false;
+ status = csr_update_channel_list(pMac);
+ if (CDF_STATUS_SUCCESS != status) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ "failed to update the supported channel list");
+ }
+ return;
+}
+
+/*
+ * The Tx power limits are saved in the cfg for future usage.
+ */
+void csr_save_tx_power_to_cfg(tpAniSirGlobal pMac, tDblLinkList *pList,
+ uint32_t cfgId)
+{
+ tListElem *pEntry;
+ uint32_t cbLen = 0, dataLen, tmp_len;
+ tCsrChannelPowerInfo *ch_set;
+ uint32_t idx;
+ tSirMacChanInfo *ch_pwr_set;
+ uint8_t *pBuf = NULL;
+
+ /* allocate maximum space for all channels */
+ dataLen = WNI_CFG_VALID_CHANNEL_LIST_LEN * sizeof(tSirMacChanInfo);
+ pBuf = cdf_mem_malloc(dataLen);
+ if (pBuf == NULL)
+ return;
+
+ cdf_mem_set(pBuf, dataLen, 0);
+ ch_pwr_set = (tSirMacChanInfo *) (pBuf);
+ pEntry = csr_ll_peek_head(pList, LL_ACCESS_LOCK);
+ /*
+ * write the tuples (startChan, numChan, txPower) for each channel found
+ * in the channel power list.
+ */
+ while (pEntry) {
+ ch_set = GET_BASE_ADDR(pEntry, tCsrChannelPowerInfo, link);
+ if (1 != ch_set->interChannelOffset) {
+ /*
+ * we keep the 5G channel sets internally with an
+ * interchannel offset of 4. Expand these to the right
+ * format. (inter channel offset of 1 is the only option
+ * for the triplets that 11d advertises.
+ */
+ tmp_len = cbLen + (ch_set->numChannels *
+ sizeof(tSirMacChanInfo));
+ if (tmp_len >= dataLen) {
+ /*
+ * expanding this entry will overflow our
+ * allocation
+ */
+ sms_log(pMac, LOGE,
+ FL("Buffer overflow, start %d, num %d, offset %d"),
+ ch_set->firstChannel,
+ ch_set->numChannels,
+ ch_set->interChannelOffset);
+ break;
+ }
+
+ for (idx = 0; idx < ch_set->numChannels; idx++) {
+ ch_pwr_set->firstChanNum = (tSirMacChanNum)
+ (ch_set->firstChannel + (idx *
+ ch_set->interChannelOffset));
+ sms_log(pMac, LOG3,
+ FL("Setting Channel Number %d"),
+ ch_pwr_set->firstChanNum);
+ ch_pwr_set->numChannels = 1;
+ ch_pwr_set->maxTxPower =
+ CDF_MIN(ch_set->txPower,
+ pMac->roam.configParam.nTxPowerCap);
+ sms_log(pMac, LOG3,
+ FL("Setting Max Transmit Power %d"),
+ ch_pwr_set->maxTxPower);
+ cbLen += sizeof(tSirMacChanInfo);
+ ch_pwr_set++;
+ }
+ } else {
+ if (cbLen >= dataLen) {
+ /* this entry will overflow our allocation */
+ sms_log(pMac, LOGE,
+ FL("Buffer overflow, start %d, num %d, offset %d"),
+ ch_set->firstChannel,
+ ch_set->numChannels,
+ ch_set->interChannelOffset);
+ break;
+ }
+ ch_pwr_set->firstChanNum = ch_set->firstChannel;
+ sms_log(pMac, LOG3, FL("Setting Channel Number %d"),
+ ch_pwr_set->firstChanNum);
+ ch_pwr_set->numChannels = ch_set->numChannels;
+ ch_pwr_set->maxTxPower = CDF_MIN(ch_set->txPower,
+ pMac->roam.configParam.nTxPowerCap);
+ sms_log(pMac, LOG3,
+ FL("Setting Max Tx Power %d, nTxPower %d"),
+ ch_pwr_set->maxTxPower,
+ pMac->roam.configParam.nTxPowerCap);
+ cbLen += sizeof(tSirMacChanInfo);
+ ch_pwr_set++;
+ }
+ pEntry = csr_ll_next(pList, pEntry, LL_ACCESS_LOCK);
+ }
+ if (cbLen)
+ cfg_set_str(pMac, cfgId, (uint8_t *) pBuf, cbLen);
+
+ cdf_mem_free(pBuf);
+}
+
+void csr_set_cfg_country_code(tpAniSirGlobal pMac, uint8_t *countryCode)
+{
+ uint8_t cc[WNI_CFG_COUNTRY_CODE_LEN];
+ /* v_REGDOMAIN_t DomainId */
+
+ sms_log(pMac, LOG3, FL("Setting Country Code in Cfg %s"), countryCode);
+ cdf_mem_copy(cc, countryCode, WNI_CFG_COUNTRY_CODE_LEN);
+
+ /*
+ * don't program the bogus country codes that we created for Korea in the
+ * MAC. if we see the bogus country codes, program the MAC with the right
+ * country code.
+ */
+ if (('K' == countryCode[0] && '1' == countryCode[1]) ||
+ ('K' == countryCode[0] && '2' == countryCode[1]) ||
+ ('K' == countryCode[0] && '3' == countryCode[1]) ||
+ ('K' == countryCode[0] && '4' == countryCode[1])) {
+ /*
+ * replace the alternate Korea country codes, 'K1', 'K2', ..
+ * with 'KR' for Korea
+ */
+ cc[1] = 'R';
+ }
+ cfg_set_str(pMac, WNI_CFG_COUNTRY_CODE, cc, WNI_CFG_COUNTRY_CODE_LEN);
+
+ /*
+ * Need to let HALPHY know about the current domain so it can apply some
+ * domain-specific settings (TX filter...)
+ */
+ /*
+ if(CDF_IS_STATUS_SUCCESS(csr_get_regulatory_domain_for_country(
+ pMac, cc, &DomainId))) {
+ halPhySetRegDomain(pMac, DomainId);
+ } */
+}
+
+CDF_STATUS csr_get_country_code(tpAniSirGlobal pMac, uint8_t *pBuf,
+ uint8_t *pbLen)
+{
+ CDF_STATUS status = CDF_STATUS_E_INVAL;
+ uint32_t len;
+
+ if (pBuf && pbLen && (*pbLen >= WNI_CFG_COUNTRY_CODE_LEN)) {
+ len = *pbLen;
+ status = wlan_cfg_get_str(pMac, WNI_CFG_COUNTRY_CODE, pBuf, &len);
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ *pbLen = (uint8_t) len;
+ }
+ }
+
+ return status;
+}
+
+void csr_set_cfg_scan_control_list(tpAniSirGlobal pMac, uint8_t *countryCode,
+ tCsrChannel *pChannelList)
+{
+ uint8_t i, j;
+ bool found = false;
+ uint8_t *pControlList = NULL;
+ uint32_t len = WNI_CFG_SCAN_CONTROL_LIST_LEN;
+
+ pControlList = cdf_mem_malloc(WNI_CFG_SCAN_CONTROL_LIST_LEN);
+ if (pControlList != NULL) {
+ cdf_mem_set((void *)pControlList, WNI_CFG_SCAN_CONTROL_LIST_LEN,
+ 0);
+ if (IS_SIR_STATUS_SUCCESS(wlan_cfg_get_str(pMac,
+ WNI_CFG_SCAN_CONTROL_LIST,
+ pControlList, &len))) {
+ for (i = 0; i < pChannelList->numChannels; i++) {
+ for (j = 0; j < len; j += 2) {
+ if (pControlList[j] ==
+ pChannelList->channelList[i]) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ /* insert a pair(channel#, flag) */
+ pControlList[j + 1] =
+ csr_get_scan_type(pMac,
+ pControlList[j]);
+ found = false; /* reset the flag */
+ }
+
+ }
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ "%s: dump scan control list", __func__);
+ CDF_TRACE_HEX_DUMP(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_INFO, pControlList,
+ len);
+
+ cfg_set_str(pMac, WNI_CFG_SCAN_CONTROL_LIST,
+ pControlList, len);
+ } /* Successfully getting scan control list */
+ cdf_mem_free(pControlList);
+ } /* AllocateMemory */
+}
+
+CDF_STATUS csr_scan_abort_mac_scan(tpAniSirGlobal pMac, uint8_t sessionId,
+ eCsrAbortReason reason)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+
+ pMac->scan.fDropScanCmd = true;
+ csr_remove_cmd_with_session_id_from_pending_list(pMac,
+ sessionId, &pMac->sme.smeScanCmdPendingList,
+ eSmeCommandScan);
+ pMac->scan.fDropScanCmd = false;
+ csr_abort_scan_from_active_list(pMac,
+ &pMac->sme.smeScanCmdActiveList, sessionId,
+ eSmeCommandScan, reason);
+
+ return status;
+}
+
+void csr_remove_cmd_with_session_id_from_pending_list(tpAniSirGlobal pMac,
+ uint8_t sessionId,
+ tDblLinkList *pList,
+ eSmeCommandType commandType)
+{
+ tDblLinkList localList;
+ tListElem *pEntry;
+ tSmeCmd *pCommand;
+ tListElem *pEntryToRemove;
+
+ cdf_mem_zero(&localList, sizeof(tDblLinkList));
+ if (!CDF_IS_STATUS_SUCCESS(csr_ll_open(pMac->hHdd, &localList))) {
+ sms_log(pMac, LOGE, FL("failed to open list"));
+ return;
+ }
+
+ csr_ll_lock(pList);
+ pEntry = csr_ll_peek_head(pList, LL_ACCESS_NOLOCK);
+ if (pEntry) {
+ /*
+ * Have to make sure we don't loop back to the head of the list,
+ * which will happen if the entry is NOT on the list
+ */
+ while (pEntry) {
+ pEntryToRemove = pEntry;
+ pEntry = csr_ll_next(pList, pEntry, LL_ACCESS_NOLOCK);
+ pCommand = GET_BASE_ADDR(pEntryToRemove, tSmeCmd, Link);
+
+ if (!((pCommand->command == commandType) &&
+ (pCommand->sessionId == sessionId)))
+ continue;
+ /* Remove that entry only */
+ if (csr_ll_remove_entry(pList, pEntryToRemove,
+ LL_ACCESS_NOLOCK)) {
+ csr_ll_insert_tail(&localList, pEntryToRemove,
+ LL_ACCESS_NOLOCK);
+ }
+ }
+ }
+ csr_ll_unlock(pList);
+
+ while ((pEntry = csr_ll_remove_head(&localList, LL_ACCESS_NOLOCK))) {
+ pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
+ sms_log(pMac, LOG1, FL("Sending abort for scan command ID %d"),
+ pCommand->u.scanCmd.scanID);
+ csr_abort_command(pMac, pCommand, false);
+ }
+
+ csr_ll_close(&localList);
+}
+
+void csr_remove_cmd_from_pending_list(tpAniSirGlobal pMac,
+ tDblLinkList *pList,
+ eSmeCommandType commandType)
+{
+ tDblLinkList localList;
+ tListElem *pEntry;
+ tSmeCmd *pCommand;
+ tListElem *pEntryToRemove;
+
+ cdf_mem_zero(&localList, sizeof(tDblLinkList));
+ if (!CDF_IS_STATUS_SUCCESS(csr_ll_open(pMac->hHdd, &localList))) {
+ sms_log(pMac, LOGE, FL(" failed to open list"));
+ return;
+ }
+
+ csr_ll_lock(pList);
+ if (!csr_ll_is_list_empty(pList, LL_ACCESS_NOLOCK)) {
+ pEntry = csr_ll_peek_head(pList, LL_ACCESS_NOLOCK);
+ /*
+ * Have to make sure we don't loop back to the head of the list,
+ * which will happen if the entry is NOT on the list...
+ */
+ while (pEntry) {
+ pEntryToRemove = pEntry;
+ pEntry = csr_ll_next(pList, pEntry, LL_ACCESS_NOLOCK);
+ pCommand = GET_BASE_ADDR(pEntryToRemove, tSmeCmd, Link);
+ /* Remove that entry only that matches cmd type */
+ if (pCommand->command == commandType &&
+ csr_ll_remove_entry(pList, pEntryToRemove,
+ LL_ACCESS_NOLOCK)) {
+ csr_ll_insert_tail(&localList, pEntryToRemove,
+ LL_ACCESS_NOLOCK);
+ }
+ }
+ }
+ csr_ll_unlock(pList);
+
+ while ((pEntry = csr_ll_remove_head(&localList, LL_ACCESS_NOLOCK))) {
+ pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
+ csr_abort_command(pMac, pCommand, false);
+ }
+ csr_ll_close(&localList);
+
+}
+
+CDF_STATUS csr_scan_abort_scan_for_ssid(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+
+ pMac->scan.fDropScanCmd = true;
+ csr_remove_scan_for_ssid_from_pending_list(pMac,
+ &pMac->sme.smeScanCmdPendingList, sessionId);
+ pMac->scan.fDropScanCmd = false;
+ csr_abort_scan_from_active_list(pMac, &pMac->sme.smeScanCmdActiveList,
+ sessionId, eSmeCommandScan, eCSR_SCAN_ABORT_SSID_ONLY);
+ return status;
+}
+
+void csr_remove_scan_for_ssid_from_pending_list(tpAniSirGlobal pMac,
+ tDblLinkList *pList,
+ uint32_t sessionId)
+{
+ tDblLinkList localList;
+ tListElem *pEntry;
+ tSmeCmd *pCommand;
+ tListElem *pEntryToRemove;
+
+ cdf_mem_zero(&localList, sizeof(tDblLinkList));
+ if (!CDF_IS_STATUS_SUCCESS(csr_ll_open(pMac->hHdd, &localList))) {
+ sms_log(pMac, LOGE, FL(" failed to open list"));
+ return;
+ }
+ csr_ll_lock(pList);
+ if (!csr_ll_is_list_empty(pList, LL_ACCESS_NOLOCK)) {
+ pEntry = csr_ll_peek_head(pList, LL_ACCESS_NOLOCK);
+ /*
+ * Have to make sure we don't loop back to the head of the list,
+ * which will happen if the entry is NOT on the list...
+ */
+ while (pEntry) {
+ pEntryToRemove = pEntry;
+ pEntry = csr_ll_next(pList, pEntry, LL_ACCESS_NOLOCK);
+ pCommand = GET_BASE_ADDR(pEntryToRemove, tSmeCmd, Link);
+
+ if (!((eSmeCommandScan == pCommand->command) &&
+ (sessionId == pCommand->sessionId)))
+ continue;
+ if (eCsrScanForSsid != pCommand->u.scanCmd.reason)
+ continue;
+ /* Remove that entry only */
+ if (csr_ll_remove_entry(pList, pEntryToRemove,
+ LL_ACCESS_NOLOCK)) {
+ csr_ll_insert_tail(&localList, pEntryToRemove,
+ LL_ACCESS_NOLOCK);
+ }
+ }
+ }
+ csr_ll_unlock(pList);
+ while ((pEntry = csr_ll_remove_head(&localList, LL_ACCESS_NOLOCK))) {
+ pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
+ csr_abort_command(pMac, pCommand, false);
+ }
+ csr_ll_close(&localList);
+}
+
+
+/**
+ * csr_send_scan_abort() - Sends scan abort command to firmware
+ * @mac_ctx: Pointer to Global Mac structure
+ * @session_id: CSR session identification
+ * @scan_id: scan identifier
+ *
+ * .Sends scan abort command to firmware
+ *
+ * Return: None
+ */
+static void csr_send_scan_abort(tpAniSirGlobal mac_ctx,
+ uint32_t session_id, uint32_t scan_id)
+{
+ tSirSmeScanAbortReq *msg;
+ uint16_t msg_len;
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+
+ msg_len = (uint16_t)(sizeof(tSirSmeScanAbortReq));
+ msg = cdf_mem_malloc(msg_len);
+ if (NULL == msg) {
+ sms_log(mac_ctx, LOGE,
+ FL("Failed to alloc memory for SmeScanAbortReq"));
+ return;
+ }
+ cdf_mem_zero((void *)msg, msg_len);
+ msg->type = eWNI_SME_SCAN_ABORT_IND;
+ msg->msgLen = msg_len;
+ msg->sessionId = session_id;
+ msg->scan_id = scan_id;
+ sms_log(mac_ctx, LOG2,
+ FL("Abort scan sent to Firmware scan_id %d session %d"),
+ scan_id, session_id);
+ status = cds_send_mb_message_to_mac(msg);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ cdf_mem_free(msg);
+ sms_log(mac_ctx, LOGE,
+ FL("Failed to send abort scan.scan_id %d session %d"),
+ scan_id, session_id);
+ }
+ return;
+}
+
+/**
+ * csr_abort_scan_from_active_list() - Remove Scan command from active list
+ * @mac_ctx: Pointer to Global Mac structure
+ * @list: pointer to scan active list
+ * @session_id: CSR session identification
+ * @scan_cmd_type: scan command type
+ * @abort_reason: abort reason
+ *
+ * .Remove Scan command from active scan list
+ *
+ * Return: Success - CDF_STATUS_SUCCESS, Failure - error number
+ */
+CDF_STATUS csr_abort_scan_from_active_list(tpAniSirGlobal mac_ctx,
+ tDblLinkList *list, uint32_t session_id,
+ eSmeCommandType scan_cmd_type, eCsrAbortReason abort_reason)
+{
+ tListElem *entry;
+ tSmeCmd *cmd;
+ tListElem *entry_remove;
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+
+ csr_ll_lock(list);
+ if (!csr_ll_is_list_empty(list, LL_ACCESS_NOLOCK)) {
+ entry = csr_ll_peek_head(list, LL_ACCESS_NOLOCK);
+ while (entry) {
+ entry_remove = entry;
+ entry = csr_ll_next(list, entry, LL_ACCESS_NOLOCK);
+ cmd = GET_BASE_ADDR(entry_remove, tSmeCmd, Link);
+
+ /* Skip if command and session id not matched */
+ if (!((scan_cmd_type == cmd->command) &&
+ (session_id == cmd->sessionId)))
+ continue;
+ /*skip if abort reason is for SSID*/
+ if ((abort_reason == eCSR_SCAN_ABORT_SSID_ONLY) &&
+ (eCsrScanForSsid != cmd->u.scanCmd.reason))
+ continue;
+ if (abort_reason == eCSR_SCAN_ABORT_DUE_TO_BAND_CHANGE)
+ cmd->u.scanCmd.abortScanDueToBandChange =
+ true;
+ csr_send_scan_abort(mac_ctx, cmd->sessionId,
+ cmd->u.scanCmd.scanID);
+ }
+ }
+ csr_ll_unlock(list);
+
+ return status;
+}
+
+
+CDF_STATUS csr_scan_abort_mac_scan_not_for_connect(tpAniSirGlobal pMac,
+ uint8_t sessionId)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ if (!csr_is_scan_for_roam_command_active(pMac)) {
+ /*
+ * Only abort the scan if it is not used for other roam/connect
+ * purpose
+ */
+ status = csr_scan_abort_mac_scan(pMac, sessionId,
+ eCSR_SCAN_ABORT_DEFAULT);
+ }
+ return status;
+}
+bool csr_roam_is_valid_channel(tpAniSirGlobal pMac, uint8_t channel)
+{
+ bool fValid = false;
+ uint32_t idx_valid_ch;
+ uint32_t len = pMac->roam.numValidChannels;
+
+ for (idx_valid_ch = 0; (idx_valid_ch < len); idx_valid_ch++) {
+ if (channel == pMac->roam.validChannelList[idx_valid_ch]) {
+ fValid = true;
+ break;
+ }
+ }
+ return fValid;
+}
+
+#ifdef FEATURE_WLAN_SCAN_PNO
+CDF_STATUS csr_scan_save_preferred_network_found(tpAniSirGlobal pMac,
+ tSirPrefNetworkFoundInd *
+ pPrefNetworkFoundInd)
+{
+ uint32_t uLen = 0;
+ tpSirProbeRespBeacon parsed_frm;
+ tCsrScanResult *pScanResult = NULL;
+ tSirBssDescription *pBssDescr = NULL;
+ bool fDupBss;
+ tDot11fBeaconIEs *local_ie = NULL;
+ tAniSSID tmpSsid;
+ v_TIME_t timer = 0;
+ CDF_STATUS status;
+
+ tpSirMacMgmtHdr macHeader =
+ (tpSirMacMgmtHdr) pPrefNetworkFoundInd->data;
+ parsed_frm =
+ (tpSirProbeRespBeacon) cdf_mem_malloc(sizeof(tSirProbeRespBeacon));
+
+ if (NULL == parsed_frm) {
+ sms_log(pMac, LOGE, FL("fail to allocate memory for frame"));
+ return CDF_STATUS_E_NOMEM;
+ }
+ if (pPrefNetworkFoundInd->frameLength <= SIR_MAC_HDR_LEN_3A) {
+ sms_log(pMac, LOGE,
+ FL("Incorrect len(%d)"),
+ pPrefNetworkFoundInd->frameLength);
+ cdf_mem_free(parsed_frm);
+ return CDF_STATUS_E_FAILURE;
+ }
+ if (sir_convert_probe_frame2_struct(pMac,
+ &pPrefNetworkFoundInd->data[SIR_MAC_HDR_LEN_3A],
+ pPrefNetworkFoundInd->frameLength - SIR_MAC_HDR_LEN_3A,
+ parsed_frm) != eSIR_SUCCESS
+ || !parsed_frm->ssidPresent) {
+ sms_log(pMac, LOGE, FL("Parse error ProbeResponse, length=%d"),
+ pPrefNetworkFoundInd->frameLength);
+ cdf_mem_free(parsed_frm);
+ return CDF_STATUS_E_FAILURE;
+ }
+ /* 24 byte MAC header and 12 byte to ssid IE */
+ if (pPrefNetworkFoundInd->frameLength >
+ (SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET)) {
+ uLen = pPrefNetworkFoundInd->frameLength -
+ (SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET);
+ }
+ pScanResult = cdf_mem_malloc(sizeof(tCsrScanResult) + uLen);
+ if (NULL == pScanResult) {
+ sms_log(pMac, LOGE, FL("fail to allocate memory for frame"));
+ cdf_mem_free(parsed_frm);
+ return CDF_STATUS_E_NOMEM;
+ }
+ cdf_mem_set(pScanResult, sizeof(tCsrScanResult) + uLen, 0);
+ pBssDescr = &pScanResult->Result.BssDescriptor;
+ /*
+ * Length of BSS desription is without length of length itself and
+ * length of pointer that holds the next BSS description
+ */
+ pBssDescr->length = (uint16_t) (sizeof(tSirBssDescription) -
+ sizeof(uint16_t) - sizeof(uint32_t) + uLen);
+ if (parsed_frm->dsParamsPresent)
+ pBssDescr->channelId = parsed_frm->channelNumber;
+ else if (parsed_frm->HTInfo.present)
+ pBssDescr->channelId = parsed_frm->HTInfo.primaryChannel;
+ else
+ pBssDescr->channelId = parsed_frm->channelNumber;
+
+ if ((pBssDescr->channelId > 0) && (pBssDescr->channelId < 15)) {
+ int i;
+ /* 11b or 11g packet */
+ /* 11g iff extended Rate IE is present or */
+ /* if there is an A rate in suppRate IE */
+ for (i = 0; i < parsed_frm->supportedRates.numRates; i++) {
+ if (sirIsArate(parsed_frm->supportedRates.rate[i]
+ & 0x7f)) {
+ pBssDescr->nwType = eSIR_11G_NW_TYPE;
+ break;
+ }
+ }
+ if (parsed_frm->extendedRatesPresent)
+ pBssDescr->nwType = eSIR_11G_NW_TYPE;
+ } else {
+ /* 11a packet */
+ pBssDescr->nwType = eSIR_11A_NW_TYPE;
+ }
+ pBssDescr->sinr = 0;
+ pBssDescr->rssi = -1 * pPrefNetworkFoundInd->rssi;
+ pBssDescr->beaconInterval = parsed_frm->beaconInterval;
+ if (!pBssDescr->beaconInterval) {
+ sms_log(pMac, LOGW, FL("Bcn Interval is Zero , default to 100"
+ MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pBssDescr->bssId));
+ pBssDescr->beaconInterval = 100;
+ }
+ pBssDescr->timeStamp[0] = parsed_frm->timeStamp[0];
+ pBssDescr->timeStamp[1] = parsed_frm->timeStamp[1];
+ pBssDescr->capabilityInfo = *((uint16_t *)&parsed_frm->capabilityInfo);
+ cdf_mem_copy((uint8_t *) &pBssDescr->bssId,
+ (uint8_t *) macHeader->bssId, sizeof(tSirMacAddr));
+ pBssDescr->nReceivedTime = (uint32_t) cdf_mc_timer_get_system_ticks();
+ sms_log(pMac, LOG2, FL("Bssid= "MAC_ADDRESS_STR" chan= %d, rssi = %d"),
+ MAC_ADDR_ARRAY(pBssDescr->bssId), pBssDescr->channelId,
+ pBssDescr->rssi);
+ /* IEs */
+ if (uLen) {
+ cdf_mem_copy(&pBssDescr->ieFields,
+ pPrefNetworkFoundInd->data + (SIR_MAC_HDR_LEN_3A +
+ SIR_MAC_B_PR_SSID_OFFSET), uLen);
+ }
+ local_ie = (tDot11fBeaconIEs *) (pScanResult->Result.pvIes);
+ status = csr_get_parsed_bss_description_ies(pMac,
+ &pScanResult->Result.BssDescriptor, &local_ie);
+ if (!(local_ie || CDF_IS_STATUS_SUCCESS(status))) {
+ sms_log(pMac, LOGE, FL("Cannot parse IEs"));
+ csr_free_scan_result_entry(pMac, pScanResult);
+ cdf_mem_free(parsed_frm);
+ return CDF_STATUS_E_RESOURCES;
+ }
+
+ fDupBss = csr_remove_dup_bss_description(pMac,
+ &pScanResult->Result.BssDescriptor,
+ local_ie, &tmpSsid, &timer, false);
+ /* Check whether we have reach out limit */
+ if (CSR_SCAN_IS_OVER_BSS_LIMIT(pMac)) {
+ /* Limit reach */
+ sms_log(pMac, LOGE, FL("BSS limit reached"));
+ /* Free the resources */
+ if ((pScanResult->Result.pvIes == NULL) && local_ie)
+ cdf_mem_free(local_ie);
+ csr_free_scan_result_entry(pMac, pScanResult);
+ cdf_mem_free(parsed_frm);
+ return CDF_STATUS_E_RESOURCES;
+ }
+ /* Add to scan cache */
+ csr_scan_add_result(pMac, pScanResult, local_ie,
+ pPrefNetworkFoundInd->sessionId);
+
+ if ((pScanResult->Result.pvIes == NULL) && local_ie)
+ cdf_mem_free(local_ie);
+ cdf_mem_free(parsed_frm);
+ return CDF_STATUS_SUCCESS;
+}
+#endif /* FEATURE_WLAN_SCAN_PNO */
+
+#ifdef FEATURE_WLAN_LFR
+void csr_init_occupied_channels_list(tpAniSirGlobal pMac, uint8_t sessionId)
+{
+ tListElem *pEntry = NULL;
+ tCsrScanResult *pBssDesc = NULL;
+ tDot11fBeaconIEs *pIes = NULL;
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+
+ if (0 != pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels) {
+ /*
+ * Ini file contains neighbor scan channel list, hence NO need
+ * to build occupied channel list"
+ */
+ sms_log(pMac, LOG1, FL("Ini contains neighbor scan ch list"));
+ return;
+ }
+
+ if (!csr_neighbor_roam_is_new_connected_profile(pMac, sessionId)) {
+ /*
+ * Do not flush occupied list since current roam profile matches
+ * previous
+ */
+ sms_log(pMac, LOG2, FL("Current roam profile matches prev"));
+ return;
+ }
+
+ /* Empty occupied channels here */
+ pMac->scan.occupiedChannels[sessionId].numChannels = 0;
+
+ csr_ll_lock(&pMac->scan.scanResultList);
+ pEntry = csr_ll_peek_head(&pMac->scan.scanResultList, LL_ACCESS_NOLOCK);
+ while (pEntry) {
+ pBssDesc = GET_BASE_ADDR(pEntry, tCsrScanResult, Link);
+ pIes = (tDot11fBeaconIEs *) (pBssDesc->Result.pvIes);
+ /* At this time, pBssDescription->Result.pvIes may be NULL */
+ if (!pIes && !CDF_IS_STATUS_SUCCESS(
+ csr_get_parsed_bss_description_ies(pMac,
+ &pBssDesc->Result.BssDescriptor, &pIes)))
+ continue;
+ csr_scan_add_to_occupied_channels(pMac, pBssDesc, sessionId,
+ &pMac->scan.occupiedChannels[sessionId], pIes);
+ /*
+ * Free the memory allocated for pIes in
+ * csr_get_parsed_bss_description_ies
+ */
+ if ((pBssDesc->Result.pvIes == NULL) && pIes)
+ cdf_mem_free(pIes);
+ pEntry = csr_ll_next(&pMac->scan.scanResultList, pEntry,
+ LL_ACCESS_NOLOCK);
+ } /* while */
+ csr_ll_unlock(&pMac->scan.scanResultList);
+}
+#endif
+
+CDF_STATUS csr_scan_create_entry_in_scan_cache(tpAniSirGlobal pMac,
+ uint32_t sessionId,
+ struct cdf_mac_addr bssid,
+ uint8_t channel)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tDot11fBeaconIEs *pNewIes = NULL;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+ tSirBssDescription *pNewBssDescriptor = NULL;
+ uint32_t size = 0;
+
+ if (NULL == pSession) {
+ status = CDF_STATUS_E_FAILURE;
+ return status;
+ }
+ sms_log(pMac, LOG2, FL("Current bssid::"MAC_ADDRESS_STR),
+ MAC_ADDR_ARRAY(pSession->pConnectBssDesc->bssId));
+ sms_log(pMac, LOG2, FL("My bssid::"MAC_ADDRESS_STR" channel %d"),
+ MAC_ADDR_ARRAY(bssid.bytes), channel);
+
+ if (!CDF_IS_STATUS_SUCCESS(csr_get_parsed_bss_description_ies(
+ pMac, pSession->pConnectBssDesc,
+ &pNewIes))) {
+ sms_log(pMac, LOGE, FL("Failed to parse IEs"));
+ status = CDF_STATUS_E_FAILURE;
+ goto free_mem;
+ }
+ size = pSession->pConnectBssDesc->length +
+ sizeof(pSession->pConnectBssDesc->length);
+ if (!size) {
+ sms_log(pMac, LOGE, FL("length of bss descriptor is 0"));
+ status = CDF_STATUS_E_FAILURE;
+ goto free_mem;
+ }
+ pNewBssDescriptor = cdf_mem_malloc(size);
+ if (NULL == pNewBssDescriptor) {
+ sms_log(pMac, LOGE, FL("memory allocation failed"));
+ status = CDF_STATUS_E_FAILURE;
+ goto free_mem;
+ }
+ cdf_mem_copy(pNewBssDescriptor, pSession->pConnectBssDesc, size);
+ /* change the BSSID & channel as passed */
+ cdf_mem_copy(pNewBssDescriptor->bssId, bssid.bytes,
+ sizeof(tSirMacAddr));
+ pNewBssDescriptor->channelId = channel;
+ if (NULL == csr_scan_append_bss_description(pMac, pNewBssDescriptor,
+ pNewIes, true, sessionId)) {
+ sms_log(pMac, LOGE,
+ FL("csr_scan_append_bss_description failed"));
+ status = CDF_STATUS_E_FAILURE;
+ goto free_mem;
+ }
+ sms_log(pMac, LOGE, FL("entry successfully added in scan cache"));
+
+free_mem:
+ if (pNewIes) {
+ cdf_mem_free(pNewIes);
+ }
+ if (pNewBssDescriptor) {
+ cdf_mem_free(pNewBssDescriptor);
+ }
+ return status;
+}
+
+#ifdef FEATURE_WLAN_ESE
+/* Update the TSF with the difference in system time */
+void update_cckmtsf(uint32_t *timeStamp0, uint32_t *timeStamp1,
+ uint32_t *incr)
+{
+ uint64_t timeStamp64 = ((uint64_t) *timeStamp1 << 32) | (*timeStamp0);
+ timeStamp64 = (uint64_t) (timeStamp64 + (uint64_t) *incr);
+ *timeStamp0 = (uint32_t) (timeStamp64 & 0xffffffff);
+ *timeStamp1 = (uint32_t) ((timeStamp64 >> 32) & 0xffffffff);
+}
+#endif
+
+/**
+ * csr_scan_save_roam_offload_ap_to_scan_cache
+ * This function parses the received beacon/probe response
+ * from the firmware as part of the roam synch indication.
+ * The beacon or the probe response is parsed and is also
+ * saved into the scan cache
+ *
+ * @param pMac Pointer to Global Mac
+ * @param roam_sync_ind_ptr Roam Synch Indication from
+ * firmware which also contains the beacon/probe
+ * response
+ * @return Status
+ */
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+CDF_STATUS csr_scan_save_roam_offload_ap_to_scan_cache(tpAniSirGlobal pMac,
+ roam_offload_synch_ind *roam_sync_ind_ptr)
+{
+ uint32_t length = 0;
+ bool dup_bss;
+ tDot11fBeaconIEs *ies_local_ptr = NULL;
+ tAniSSID tmpSsid;
+ v_TIME_t timer = 0;
+ tCsrScanResult *scan_res_ptr = NULL;
+ uint8_t session_id = roam_sync_ind_ptr->roamedVdevId;
+
+ length = roam_sync_ind_ptr->beaconProbeRespLength -
+ (SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET);
+ scan_res_ptr = cdf_mem_malloc(sizeof(tCsrScanResult) + length);
+ if (scan_res_ptr == NULL) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ " fail to allocate memory for frame");
+ return CDF_STATUS_E_NOMEM;
+ }
+
+ cdf_mem_zero(scan_res_ptr, sizeof(tCsrScanResult) + length);
+ cdf_mem_copy(&scan_res_ptr->Result.BssDescriptor,
+ roam_sync_ind_ptr->bss_desc_ptr,
+ (sizeof(tSirBssDescription) + length));
+ ies_local_ptr = (tDot11fBeaconIEs *)(scan_res_ptr->Result.pvIes);
+ if (!ies_local_ptr &&
+ (!CDF_IS_STATUS_SUCCESS(csr_get_parsed_bss_description_ies(
+ pMac, &scan_res_ptr->Result.
+ BssDescriptor,
+ &ies_local_ptr)))) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ "%s:Cannot Parse IEs", __func__);
+ csr_free_scan_result_entry(pMac, scan_res_ptr);
+ return CDF_STATUS_E_RESOURCES;
+ }
+
+ dup_bss = csr_remove_dup_bss_description(pMac,
+ &scan_res_ptr->Result.BssDescriptor,
+ ies_local_ptr, &tmpSsid, &timer, true);
+ if (CSR_SCAN_IS_OVER_BSS_LIMIT(pMac)) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ "%s:BSS Limit Exceed", __func__);
+ if ((scan_res_ptr->Result.pvIes == NULL) && ies_local_ptr)
+ cdf_mem_free(ies_local_ptr);
+
+ csr_free_scan_result_entry(pMac, scan_res_ptr);
+ return CDF_STATUS_E_RESOURCES;
+ }
+ csr_scan_add_result(pMac, scan_res_ptr, ies_local_ptr, session_id);
+ return CDF_STATUS_SUCCESS;
+}
+#endif
+
+/**
+ * csr_get_bssdescr_from_scan_handle() - This function to extract
+ * first bss description from scan handle
+ * @result_handle: an object for the result.
+ *
+ * This function is written to extract first bss from scan handle.
+ *
+ * Return: first bss descriptor from the scan handle.
+ */
+tSirBssDescription*
+csr_get_bssdescr_from_scan_handle(tScanResultHandle result_handle,
+ tSirBssDescription *bss_descr)
+{
+ tListElem *first_element = NULL;
+ tCsrScanResult *scan_result = NULL;
+ tScanResultList *bss_list = (tScanResultList *)result_handle;
+
+ if (NULL == bss_list) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ FL("Empty bss_list"));
+ return NULL;
+ }
+ if (csr_ll_is_list_empty(&bss_list->List, LL_ACCESS_NOLOCK)) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ FL("bss_list->List is empty"));
+ cdf_mem_free(bss_list);
+ return NULL;
+ }
+ first_element = csr_ll_peek_head(&bss_list->List, LL_ACCESS_NOLOCK);
+ if (first_element) {
+ scan_result = GET_BASE_ADDR(first_element,
+ tCsrScanResult,
+ Link);
+ cdf_mem_copy(bss_descr,
+ &scan_result->Result.BssDescriptor,
+ sizeof(tSirBssDescription));
+ }
+ return bss_descr;
+}
+
+/**
+ * scan_active_list_cmd_timeout_handle() - To handle scan active command timeout
+ * @userData: scan context
+ *
+ * This routine is to handle scan active command timeout
+ *
+ * Return: None
+ */
+void csr_scan_active_list_timeout_handle(void *userData)
+{
+ tSmeCmd *scan_cmd = (tSmeCmd *) userData;
+ tHalHandle *hal_ctx = cds_get_context(CDF_MODULE_ID_PE);
+ tpAniSirGlobal mac_ctx;
+ uint16_t scan_id;
+ tSirSmeScanAbortReq *msg;
+ uint16_t msg_len;
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+
+ if (scan_cmd == NULL) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ FL("Scan Timeout: Scan command is NULL"));
+ return;
+ }
+ mac_ctx = PMAC_STRUCT(hal_ctx);
+ scan_id = scan_cmd->u.scanCmd.scanID;
+ sms_log(mac_ctx, LOGE,
+ FL("Scan Timeout:Sending abort to Firmware ID %d session %d "),
+ scan_id, scan_cmd->sessionId);
+ msg_len = (uint16_t)(sizeof(tSirSmeScanAbortReq));
+ msg = cdf_mem_malloc(msg_len);
+ if (NULL == msg) {
+ sms_log(mac_ctx, LOGE,
+ FL("Failed to alloc memory for SmeScanAbortReq"));
+ return;
+ }
+ cdf_mem_zero((void *)msg, msg_len);
+ msg->type = eWNI_SME_SCAN_ABORT_IND;
+ msg->msgLen = msg_len;
+ msg->sessionId = scan_cmd->sessionId;
+ msg->scan_id = scan_id;
+ status = cds_send_mb_message_to_mac(msg);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(mac_ctx, LOGE,
+ FL(" Failed to post message to LIM"));
+ cdf_mem_free(msg);
+ }
+ csr_release_scan_command(mac_ctx, scan_cmd, eCSR_SCAN_FAILURE);
+ return;
+}