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_roam.c b/core/sme/src/csr/csr_api_roam.c
new file mode 100644
index 0000000..9074f37
--- /dev/null
+++ b/core/sme/src/csr/csr_api_roam.c
@@ -0,0 +1,18860 @@
+/*
+ * Copyright (c) 2012-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_roam.c
+
+ Implementation for the Common Roaming interfaces.
+ ========================================================================== */
+#include "ani_global.h" /* for tpAniSirGlobal */
+#include "wma_types.h"
+#include "wma_if.h" /* for STA_INVALID_IDX. */
+#include "lim_utils.h"
+#include "cds_mq.h"
+#include "csr_inside_api.h"
+#include "sms_debug.h"
+#include "sme_qos_internal.h"
+#include "sme_inside.h"
+#include "host_diag_core_event.h"
+#include "host_diag_core_log.h"
+#include "csr_api.h"
+#include "csr_internal.h"
+#include "cds_reg_service.h"
+#include "mac_trace.h"
+#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING
+#include "csr_neighbor_roam.h"
+#endif /* WLAN_FEATURE_NEIGHBOR_ROAMING */
+#include "cds_regdomain_common.h"
+#include "cds_utils.h"
+#include "sir_types.h"
+#include "cfg_api.h"
+#include "sme_power_save_api.h"
+#include "wma.h"
+#include "cds_concurrency.h"
+
+#define CSR_NUM_IBSS_START_CHANNELS_50 4
+#define CSR_NUM_IBSS_START_CHANNELS_24 3
+/* 5 seconds, for WPA, WPA2, CCKM */
+#define CSR_WAIT_FOR_KEY_TIMEOUT_PERIOD (5 * CDF_MC_TIMER_TO_SEC_UNIT)
+/* 120 seconds, for WPS */
+#define CSR_WAIT_FOR_WPS_KEY_TIMEOUT_PERIOD (120 * CDF_MC_TIMER_TO_SEC_UNIT)
+
+/*---------------------------------------------------------------------------
+ OBIWAN recommends [8 10]% : pick 9%
+ ---------------------------------------------------------------------------*/
+#define CSR_VCC_UL_MAC_LOSS_THRESHOLD 9
+/*---------------------------------------------------------------------------
+ OBIWAN recommends -85dBm
+ ---------------------------------------------------------------------------*/
+#define CSR_VCC_RSSI_THRESHOLD 80
+#define CSR_MIN_GLOBAL_STAT_QUERY_PERIOD 500 /* ms */
+#define CSR_MIN_GLOBAL_STAT_QUERY_PERIOD_IN_BMPS 2000 /* ms */
+#define CSR_MIN_TL_STAT_QUERY_PERIOD 500 /* ms */
+/* Flag to send/do not send disassoc frame over the air */
+#define CSR_DONT_SEND_DISASSOC_OVER_THE_AIR 1
+#define RSSI_HACK_BMPS (-40)
+#define MAX_CB_VALUE_IN_INI (2)
+
+#define MAX_SOCIAL_CHANNELS 3
+/* Choose the largest possible value that can be accomodates in 8 bit signed */
+/* variable. */
+#define SNR_HACK_BMPS (127)
+
+static bool b_roam_scan_offload_started;
+
+/*--------------------------------------------------------------------------
+ Static Type declarations
+ ------------------------------------------------------------------------*/
+static tCsrRoamSession csr_roam_roam_session[CSR_ROAM_SESSION_MAX];
+
+/*--------------------------------------------------------------------------
+ Type declarations
+ ------------------------------------------------------------------------*/
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+int diag_auth_type_from_csr_type(eCsrAuthType authType)
+{
+ int n = AUTH_OPEN;
+ switch (authType) {
+ case eCSR_AUTH_TYPE_SHARED_KEY:
+ n = AUTH_SHARED;
+ break;
+ case eCSR_AUTH_TYPE_WPA:
+ n = AUTH_WPA_EAP;
+ break;
+ case eCSR_AUTH_TYPE_WPA_PSK:
+ n = AUTH_WPA_PSK;
+ break;
+ case eCSR_AUTH_TYPE_RSN:
+#ifdef WLAN_FEATURE_11W
+ case eCSR_AUTH_TYPE_RSN_8021X_SHA256:
+#endif
+ n = AUTH_WPA2_EAP;
+ break;
+ case eCSR_AUTH_TYPE_RSN_PSK:
+#ifdef WLAN_FEATURE_11W
+ case eCSR_AUTH_TYPE_RSN_PSK_SHA256:
+#endif
+ n = AUTH_WPA2_PSK;
+ break;
+#ifdef FEATURE_WLAN_WAPI
+ case eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE:
+ n = AUTH_WAPI_CERT;
+ break;
+ case eCSR_AUTH_TYPE_WAPI_WAI_PSK:
+ n = AUTH_WAPI_PSK;
+ break;
+#endif /* FEATURE_WLAN_WAPI */
+ default:
+ break;
+ }
+ return n;
+}
+
+int diag_enc_type_from_csr_type(eCsrEncryptionType encType)
+{
+ int n = ENC_MODE_OPEN;
+ switch (encType) {
+ case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY:
+ case eCSR_ENCRYPT_TYPE_WEP40:
+ n = ENC_MODE_WEP40;
+ break;
+ case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY:
+ case eCSR_ENCRYPT_TYPE_WEP104:
+ n = ENC_MODE_WEP104;
+ break;
+ case eCSR_ENCRYPT_TYPE_TKIP:
+ n = ENC_MODE_TKIP;
+ break;
+ case eCSR_ENCRYPT_TYPE_AES:
+ n = ENC_MODE_AES;
+ break;
+#ifdef FEATURE_WLAN_WAPI
+ case eCSR_ENCRYPT_TYPE_WPI:
+ n = ENC_MODE_SMS4;
+ break;
+#endif /* FEATURE_WLAN_WAPI */
+ default:
+ break;
+ }
+ return n;
+}
+#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */
+static const uint8_t
+ csr_start_ibss_channels50[CSR_NUM_IBSS_START_CHANNELS_50] = { 36, 40, 44, 48 };
+static const uint8_t
+ csr_start_ibss_channels24[CSR_NUM_IBSS_START_CHANNELS_24] = { 1, 6, 11 };
+static void init_config_param(tpAniSirGlobal pMac);
+static bool csr_roam_process_results(tpAniSirGlobal pMac, tSmeCmd *pCommand,
+ eCsrRoamCompleteResult Result,
+ void *Context);
+static CDF_STATUS csr_roam_start_ibss(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamProfile *pProfile,
+ bool *pfSameIbss);
+static void csr_roam_update_connected_profile_from_new_bss(tpAniSirGlobal pMac,
+ uint32_t sessionId,
+ tSirSmeNewBssInfo *
+ pNewBss);
+static void csr_roam_prepare_bss_params(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamProfile *pProfile,
+ tSirBssDescription *pBssDesc,
+ tBssConfigParam *pBssConfig,
+ tDot11fBeaconIEs *pIes);
+static ePhyChanBondState csr_get_cb_mode_from_ies(tpAniSirGlobal pMac,
+ uint8_t primaryChn,
+ tDot11fBeaconIEs *pIes);
+
+static void csr_roaming_state_config_cnf_processor(tpAniSirGlobal pMac,
+ uint32_t result);
+CDF_STATUS csr_roam_open(tpAniSirGlobal pMac);
+CDF_STATUS csr_roam_close(tpAniSirGlobal pMac);
+void csr_roamMICErrorTimerHandler(void *pv);
+void csr_roamTKIPCounterMeasureTimerHandler(void *pv);
+bool csr_roam_is_same_profile_keys(tpAniSirGlobal pMac,
+ tCsrRoamConnectedProfile *pConnProfile,
+ tCsrRoamProfile *pProfile2);
+
+static CDF_STATUS csr_roam_start_roaming_timer(tpAniSirGlobal pMac,
+ uint32_t sessionId,
+ uint32_t interval);
+static CDF_STATUS csr_roam_stop_roaming_timer(tpAniSirGlobal pMac,
+ uint32_t sessionId);
+static void csr_roam_roaming_timer_handler(void *pv);
+CDF_STATUS csr_roam_start_wait_for_key_timer(tpAniSirGlobal pMac, uint32_t interval);
+CDF_STATUS csr_roam_stop_wait_for_key_timer(tpAniSirGlobal pMac);
+static void csr_roam_wait_for_key_time_out_handler(void *pv);
+static CDF_STATUS csr_init11d_info(tpAniSirGlobal pMac, tCsr11dinfo *ps11dinfo);
+static CDF_STATUS csr_init_channel_power_list(tpAniSirGlobal pMac,
+ tCsr11dinfo *ps11dinfo);
+static CDF_STATUS csr_roam_free_connected_info(tpAniSirGlobal pMac,
+ tCsrRoamConnectedInfo *
+ pConnectedInfo);
+CDF_STATUS csr_send_mb_set_context_req_msg(tpAniSirGlobal pMac, uint32_t sessionId,
+ tSirMacAddr peerMacAddr, uint8_t numKeys,
+ tAniEdType edType, bool fUnicast,
+ tAniKeyDirection aniKeyDirection,
+ uint8_t keyId, uint8_t keyLength,
+ uint8_t *pKey, uint8_t paeRole,
+ uint8_t *pKeyRsc);
+static CDF_STATUS csr_roam_issue_reassociate(tpAniSirGlobal pMac,
+ uint32_t sessionId,
+ tSirBssDescription *pSirBssDesc,
+ tDot11fBeaconIEs *pIes,
+ tCsrRoamProfile *pProfile);
+void csr_roamStatisticsTimerHandler(void *pv);
+void csr_roamStatsGlobalClassDTimerHandler(void *pv);
+static void csr_roam_link_up(tpAniSirGlobal pMac, struct cdf_mac_addr bssid);
+static void csr_roam_link_down(tpAniSirGlobal pMac, uint32_t sessionId);
+void csr_roam_vcc_trigger(tpAniSirGlobal pMac);
+CDF_STATUS csr_send_mb_stats_req_msg(tpAniSirGlobal pMac, uint32_t statsMask,
+ uint8_t staId, uint8_t sessionId);
+/*
+ pStaEntry is no longer invalid upon the return of this function.
+ */
+static void csr_roam_remove_stat_list_entry(tpAniSirGlobal pMac, tListElem *pEntry);
+static eCsrCfgDot11Mode csr_roam_get_phy_mode_band_for_bss(tpAniSirGlobal pMac,
+ tCsrRoamProfile *pProfile,
+ uint8_t operationChn,
+ eCsrBand *pBand);
+static CDF_STATUS csr_roam_get_qos_info_from_bss(tpAniSirGlobal pMac,
+ tSirBssDescription *pBssDesc);
+tCsrStatsClientReqInfo *csr_roam_insert_entry_into_list(tpAniSirGlobal pMac,
+ tDblLinkList *pStaList,
+ tCsrStatsClientReqInfo *
+ pStaEntry);
+void csr_roam_stats_client_timer_handler(void *pv);
+tCsrPeStatsReqInfo *csr_roam_check_pe_stats_req_list(tpAniSirGlobal pMac,
+ uint32_t statsMask,
+ uint32_t periodicity,
+ bool *pFound, uint8_t staId,
+ uint8_t sessionId);
+void csr_roam_report_statistics(tpAniSirGlobal pMac, uint32_t statsMask,
+ tCsrStatsCallback callback, uint8_t staId,
+ void *pContext);
+void csr_roam_tl_stats_timer_handler(void *pv);
+void csr_roam_pe_stats_timer_handler(void *pv);
+tListElem *csr_roam_check_client_req_list(tpAniSirGlobal pMac, uint32_t statsMask);
+void csr_roam_remove_entry_from_pe_stats_req_list(tpAniSirGlobal pMac,
+ tCsrPeStatsReqInfo *pPeStaEntry);
+tListElem *csr_roam_find_in_pe_stats_req_list(tpAniSirGlobal pMac, uint32_t statsMask);
+CDF_STATUS csr_roam_dereg_statistics_req(tpAniSirGlobal pMac);
+static uint32_t csr_find_ibss_session(tpAniSirGlobal pMac);
+static uint32_t csr_find_session_by_type(tpAniSirGlobal, tCDF_CON_MODE);
+static bool csr_is_conn_allow_2g_band(tpAniSirGlobal pMac, uint32_t chnl);
+static bool csr_is_conn_allow_5g_band(tpAniSirGlobal pMac, uint32_t chnl);
+static CDF_STATUS csr_roam_start_wds(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamProfile *pProfile,
+ tSirBssDescription *pBssDesc);
+static void csr_init_session(tpAniSirGlobal pMac, uint32_t sessionId);
+static CDF_STATUS csr_roam_issue_set_key_command(tpAniSirGlobal pMac,
+ uint32_t sessionId,
+ tCsrRoamSetKey *pSetKey,
+ uint32_t roamId);
+static CDF_STATUS csr_roam_get_qos_info_from_bss(tpAniSirGlobal pMac,
+ tSirBssDescription *pBssDesc);
+void csr_roam_reissue_roam_command(tpAniSirGlobal pMac);
+static void csr_ser_des_unpack_diassoc_rsp(uint8_t *pBuf,
+ tSirSmeDisassocRsp *pRsp);
+void csr_reinit_preauth_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand);
+void csr_init_operating_classes(tHalHandle hHal);
+
+/* Initialize global variables */
+static void csr_roam_init_globals(tpAniSirGlobal pMac)
+{
+ if (pMac) {
+ cdf_mem_zero(&csr_roam_roam_session, sizeof(csr_roam_roam_session));
+ pMac->roam.roamSession = csr_roam_roam_session;
+ }
+ return;
+}
+
+static void csr_roam_de_init_globals(tpAniSirGlobal pMac)
+{
+ if (pMac) {
+ pMac->roam.roamSession = NULL;
+ }
+ return;
+}
+
+CDF_STATUS csr_open(tpAniSirGlobal pMac)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ uint32_t i;
+
+ do {
+ /* Initialize CSR Roam Globals */
+ csr_roam_init_globals(pMac);
+ for (i = 0; i < CSR_ROAM_SESSION_MAX; i++)
+ csr_roam_state_change(pMac, eCSR_ROAMING_STATE_STOP, i);
+
+ init_config_param(pMac);
+ status = csr_scan_open(pMac);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ break;
+ status = csr_roam_open(pMac);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ break;
+ pMac->roam.nextRoamId = 1; /* Must not be 0 */
+ if (!CDF_IS_STATUS_SUCCESS
+ (csr_ll_open(pMac->hHdd,
+ &pMac->roam.statsClientReqList)))
+ break;
+ if (!CDF_IS_STATUS_SUCCESS
+ (csr_ll_open(pMac->hHdd,
+ &pMac->roam.peStatsReqList)))
+ break;
+ if (!CDF_IS_STATUS_SUCCESS
+ (csr_ll_open(pMac->hHdd,
+ &pMac->roam.roamCmdPendingList)))
+ break;
+ } while (0);
+
+ return status;
+}
+
+CDF_STATUS csr_init_chan_list(tpAniSirGlobal mac, uint8_t *alpha2)
+{
+ CDF_STATUS status;
+ v_REGDOMAIN_t reg_id;
+ v_CountryInfoSource_t source = COUNTRY_INIT;
+
+ mac->scan.countryCodeDefault[0] = alpha2[0];
+ mac->scan.countryCodeDefault[1] = alpha2[1];
+ mac->scan.countryCodeDefault[2] = alpha2[2];
+
+ sms_log(mac, LOGE, FL("init time country code %.2s"),
+ mac->scan.countryCodeDefault);
+
+ status = csr_get_regulatory_domain_for_country(mac,
+ mac->scan.countryCodeDefault,
+ ®_id, source);
+ if (status != CDF_STATUS_SUCCESS) {
+ sms_log(mac, LOGE,
+ FL("csr_get_regulatory_domain_for_country failed"));
+ return status;
+ }
+
+ if (cds_set_reg_domain(mac, reg_id) != CDF_STATUS_SUCCESS) {
+ sms_log(mac, LOGE, FL("cds_set_reg_domain failed"));
+ return CDF_STATUS_E_FAILURE;
+ }
+ mac->scan.domainIdDefault = reg_id;
+ mac->scan.domainIdCurrent = mac->scan.domainIdDefault;
+ cdf_mem_copy(mac->scan.countryCodeCurrent,
+ mac->scan.countryCodeDefault, WNI_CFG_COUNTRY_CODE_LEN);
+ cdf_mem_copy(mac->scan.countryCodeElected,
+ mac->scan.countryCodeDefault, WNI_CFG_COUNTRY_CODE_LEN);
+ status = csr_get_channel_and_power_list(mac);
+ csr_clear_votes_for_country_info(mac);
+ return status;
+}
+
+CDF_STATUS csr_set_reg_info(tHalHandle hHal, uint8_t *apCntryCode)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ v_REGDOMAIN_t regId;
+ uint8_t cntryCodeLength;
+ if (NULL == apCntryCode) {
+ sms_log(pMac, LOGE, FL(" Invalid country Code Pointer"));
+ return CDF_STATUS_E_FAILURE;
+ }
+ sms_log(pMac, LOG1, FL(" country Code %.2s"), apCntryCode);
+
+ cntryCodeLength = WNI_CFG_COUNTRY_CODE_LEN;
+ status = csr_get_regulatory_domain_for_country(pMac, apCntryCode, ®Id,
+ COUNTRY_USER);
+ if (status != CDF_STATUS_SUCCESS) {
+ sms_log(pMac, LOGE,
+ FL(" fail to get regId for country Code %.2s"),
+ apCntryCode);
+ return status;
+ }
+ status = wma_set_reg_domain(hHal, regId);
+ if (status != CDF_STATUS_SUCCESS) {
+ sms_log(pMac, LOGE,
+ FL(" fail to get regId for country Code %.2s"),
+ apCntryCode);
+ return status;
+ }
+ pMac->scan.domainIdDefault = regId;
+ pMac->scan.domainIdCurrent = pMac->scan.domainIdDefault;
+ /* Clear CC field */
+ cdf_mem_set(pMac->scan.countryCodeDefault, WNI_CFG_COUNTRY_CODE_LEN, 0);
+
+ /* Copy 2 or 3 bytes country code */
+ cdf_mem_copy(pMac->scan.countryCodeDefault, apCntryCode,
+ cntryCodeLength);
+
+ /* If 2 bytes country code, 3rd byte must be filled with space */
+ if ((WNI_CFG_COUNTRY_CODE_LEN - 1) == cntryCodeLength) {
+ cdf_mem_set(pMac->scan.countryCodeDefault + 2, 1, 0x20);
+ }
+ cdf_mem_copy(pMac->scan.countryCodeCurrent,
+ pMac->scan.countryCodeDefault, WNI_CFG_COUNTRY_CODE_LEN);
+ status = csr_get_channel_and_power_list(pMac);
+ return status;
+}
+
+CDF_STATUS csr_set_channels(tHalHandle hHal, tCsrConfigParam *pParam)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ uint8_t index = 0;
+ cdf_mem_copy(pParam->Csr11dinfo.countryCode,
+ pMac->scan.countryCodeCurrent, WNI_CFG_COUNTRY_CODE_LEN);
+ for (index = 0; index < pMac->scan.base_channels.numChannels;
+ index++) {
+ pParam->Csr11dinfo.Channels.channelList[index] =
+ pMac->scan.base_channels.channelList[index];
+ pParam->Csr11dinfo.ChnPower[index].firstChannel =
+ pMac->scan.base_channels.channelList[index];
+ pParam->Csr11dinfo.ChnPower[index].numChannels = 1;
+ pParam->Csr11dinfo.ChnPower[index].maxtxPower =
+ pMac->scan.defaultPowerTable[index].pwr;
+ }
+ pParam->Csr11dinfo.Channels.numChannels =
+ pMac->scan.base_channels.numChannels;
+
+ return status;
+}
+
+CDF_STATUS csr_close(tpAniSirGlobal pMac)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+
+ csr_roam_close(pMac);
+ csr_scan_close(pMac);
+ csr_ll_close(&pMac->roam.statsClientReqList);
+ csr_ll_close(&pMac->roam.peStatsReqList);
+ csr_ll_close(&pMac->roam.roamCmdPendingList);
+ /* DeInit Globals */
+ csr_roam_de_init_globals(pMac);
+ return status;
+}
+
+static tPowerdBm csr_find_channel_pwr(tChannelListWithPower *
+ pdefaultPowerTable,
+ uint8_t ChannelNum)
+{
+ uint8_t i;
+ /* TODO: if defaultPowerTable is guaranteed to be in ascending */
+ /* order of channel numbers, we can employ binary search */
+ for (i = 0; i < WNI_CFG_VALID_CHANNEL_LIST_LEN; i++) {
+ if (pdefaultPowerTable[i].chanId == ChannelNum)
+ return pdefaultPowerTable[i].pwr;
+ }
+ /* could not find the channel list in default list */
+ /* this should not have occured */
+ CDF_ASSERT(0);
+ return 0;
+}
+
+CDF_STATUS csr_update_channel_list(tpAniSirGlobal pMac)
+{
+ tSirUpdateChanList *pChanList;
+ tCsrScanStruct *pScan = &pMac->scan;
+ uint8_t numChan = pScan->base_channels.numChannels;
+ uint8_t num_channel = 0;
+ uint32_t bufLen;
+ cds_msg_t msg;
+ uint8_t i, j, social_channel[MAX_SOCIAL_CHANNELS] = { 1, 6, 11 };
+ uint8_t channel_state;
+
+ if (CSR_IS_5G_BAND_ONLY(pMac)) {
+ for (i = 0; i < MAX_SOCIAL_CHANNELS; i++) {
+ if (cds_get_channel_state(social_channel[i])
+ == CHANNEL_STATE_ENABLE)
+ numChan++;
+ }
+ }
+
+ bufLen = sizeof(tSirUpdateChanList) +
+ (sizeof(tSirUpdateChanParam) * (numChan));
+
+ csr_init_operating_classes((tHalHandle) pMac);
+ pChanList = (tSirUpdateChanList *) cdf_mem_malloc(bufLen);
+ if (!pChanList) {
+ CDF_TRACE(CDF_MODULE_ID_CDF, CDF_TRACE_LEVEL_ERROR,
+ "Failed to allocate memory for tSirUpdateChanList");
+ return CDF_STATUS_E_NOMEM;
+ }
+ cdf_mem_zero(pChanList, bufLen);
+
+ for (i = 0; i < pScan->base_channels.numChannels; i++) {
+ /* Scan is not performed on DSRC channels*/
+ if (pScan->base_channels.channelList[i] >= MIN_11P_CHANNEL)
+ continue;
+ if (pScan->fcc_constraint) {
+ if (pScan->base_channels.channelList[i] == 12)
+ continue;
+ if (pScan->base_channels.channelList[i] == 13)
+ continue;
+ }
+ channel_state =
+ cds_get_channel_state(
+ pScan->base_channels.channelList[i]);
+ if ((CHANNEL_STATE_ENABLE == channel_state) ||
+ pMac->scan.fEnableDFSChnlScan) {
+ pChanList->chanParam[num_channel].chanId =
+ pScan->base_channels.channelList[i];
+ pChanList->chanParam[num_channel].pwr =
+ csr_find_channel_pwr(pScan->defaultPowerTable,
+ pChanList->chanParam[num_channel].chanId);
+ if (CHANNEL_STATE_ENABLE == channel_state)
+ pChanList->chanParam[num_channel].dfsSet =
+ false;
+ else
+ pChanList->chanParam[num_channel].dfsSet =
+ true;
+ num_channel++;
+ }
+ }
+
+ if (CSR_IS_5G_BAND_ONLY(pMac)) {
+ for (j = 0; j < MAX_SOCIAL_CHANNELS; j++) {
+ if (cds_get_channel_state(social_channel[j])
+ == CHANNEL_STATE_ENABLE) {
+ pChanList->chanParam[num_channel].chanId =
+ social_channel[j];
+ pChanList->chanParam[num_channel].pwr =
+ csr_find_channel_pwr(pScan->defaultPowerTable,
+ social_channel[j]);
+ pChanList->chanParam[num_channel].dfsSet = false;
+ num_channel++;
+ }
+ }
+ }
+
+ msg.type = WMA_UPDATE_CHAN_LIST_REQ;
+ msg.reserved = 0;
+ msg.bodyptr = pChanList;
+ pChanList->numChan = num_channel;
+
+ if (CDF_STATUS_SUCCESS != cds_mq_post_message(CDF_MODULE_ID_WMA, &msg)) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL,
+ "%s: Failed to post msg to WMA", __func__);
+ cdf_mem_free(pChanList);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ return CDF_STATUS_SUCCESS;
+}
+
+CDF_STATUS csr_start(tpAniSirGlobal pMac)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ uint32_t i;
+
+ do {
+ /* save the global cds context */
+ pMac->roam.g_cds_context = cds_get_global_context();
+ for (i = 0; i < CSR_ROAM_SESSION_MAX; i++)
+ csr_roam_state_change(pMac, eCSR_ROAMING_STATE_IDLE, i);
+
+ status = csr_roam_start(pMac);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ break;
+
+ pMac->roam.sPendingCommands = 0;
+ csr_scan_enable(pMac);
+#if defined WLAN_FEATURE_NEIGHBOR_ROAMING
+ for (i = 0; i < CSR_ROAM_SESSION_MAX; i++)
+ status = csr_neighbor_roam_init(pMac, i);
+#endif /* WLAN_FEATURE_NEIGHBOR_ROAMING */
+ pMac->roam.tlStatsReqInfo.numClient = 0;
+ pMac->roam.tlStatsReqInfo.periodicity = 0;
+ pMac->roam.tlStatsReqInfo.timerRunning = false;
+ /* init the link quality indication also */
+ pMac->roam.vccLinkQuality = eCSR_ROAM_LINK_QUAL_MIN_IND;
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGW,
+ " csr_start: Couldn't Init HO control blk ");
+ break;
+ }
+
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ "Scan offload is enabled, update default chan list");
+ status = csr_update_channel_list(pMac);
+
+ } while (0);
+ return status;
+}
+
+CDF_STATUS csr_stop(tpAniSirGlobal pMac, tHalStopType stopType)
+{
+ uint32_t sessionId;
+
+ for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) {
+ csr_roam_close_session(pMac, sessionId, true, NULL, NULL);
+ }
+ csr_scan_disable(pMac);
+ pMac->scan.fCancelIdleScan = false;
+ pMac->scan.fRestartIdleScan = false;
+ csr_ll_purge(&pMac->roam.roamCmdPendingList, true);
+
+#if defined WLAN_FEATURE_NEIGHBOR_ROAMING
+ for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++)
+ csr_neighbor_roam_close(pMac, sessionId);
+#endif
+ for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++)
+ if (CSR_IS_SESSION_VALID(pMac, sessionId))
+ csr_scan_flush_result(pMac);
+
+ /* Reset the domain back to the deault */
+ pMac->scan.domainIdCurrent = pMac->scan.domainIdDefault;
+
+ for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) {
+ csr_roam_state_change(pMac, eCSR_ROAMING_STATE_STOP, sessionId);
+ pMac->roam.curSubState[sessionId] = eCSR_ROAM_SUBSTATE_NONE;
+ }
+
+ /* When HAL resets all the context information
+ * in HAL is lost, so we might need to send the
+ * scan offload request again when it comes
+ * out of reset for scan offload to be functional
+ */
+ if (HAL_STOP_TYPE_SYS_RESET == stopType) {
+ b_roam_scan_offload_started = false;
+ }
+
+ return CDF_STATUS_SUCCESS;
+}
+
+CDF_STATUS csr_ready(tpAniSirGlobal pMac)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ /* If the gScanAgingTime is set to '0' then scan results aging timeout
+ based on timer feature is not enabled */
+
+ if (0 != pMac->scan.scanResultCfgAgingTime) {
+ csr_scan_start_result_cfg_aging_timer(pMac);
+ }
+ status = csr_apply_channel_and_power_list(pMac);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ "csr_apply_channel_and_power_list failed during csr_ready with status=%d",
+ status);
+ }
+ return status;
+}
+
+void csr_set_default_dot11_mode(tpAniSirGlobal pMac)
+{
+ uint32_t wniDot11mode = 0;
+ wniDot11mode =
+ csr_translate_to_wni_cfg_dot11_mode(pMac,
+ pMac->roam.configParam.uCfgDot11Mode);
+ cfg_set_int(pMac, WNI_CFG_DOT11_MODE, wniDot11mode);
+}
+
+void csr_set_global_cfgs(tpAniSirGlobal pMac)
+{
+
+ cfg_set_int(pMac, WNI_CFG_FRAGMENTATION_THRESHOLD,
+ csr_get_frag_thresh(pMac));
+ cfg_set_int(pMac, WNI_CFG_RTS_THRESHOLD, csr_get_rts_thresh(pMac));
+ cfg_set_int(pMac, WNI_CFG_11D_ENABLED,
+ ((pMac->roam.configParam.Is11hSupportEnabled) ? pMac->roam.
+ configParam.Is11dSupportEnabled : pMac->roam.configParam.
+ Is11dSupportEnabled));
+ cfg_set_int(pMac, WNI_CFG_11H_ENABLED,
+ pMac->roam.configParam.Is11hSupportEnabled);
+ /* For now we will just use the 5GHz CB mode ini parameter to decide whether CB supported or not in Probes when there is no session
+ * Once session is established we will use the session related params stored in PE session for CB mode
+ */
+ cfg_set_int(pMac, WNI_CFG_CHANNEL_BONDING_MODE,
+ !!(pMac->roam.configParam.channelBondingMode5GHz));
+ cfg_set_int(pMac, WNI_CFG_HEART_BEAT_THRESHOLD,
+ pMac->roam.configParam.HeartbeatThresh24);
+
+ /* Update the operating mode to configured value during initialization, */
+ /* So that client can advertise full capabilities in Probe request frame. */
+ csr_set_default_dot11_mode(pMac);
+}
+
+CDF_STATUS csr_roam_open(tpAniSirGlobal pMac)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ uint32_t i;
+ tCsrRoamSession *pSession;
+ do {
+ for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
+ pSession = CSR_GET_SESSION(pMac, i);
+ pSession->roamingTimerInfo.pMac = pMac;
+ pSession->roamingTimerInfo.sessionId =
+ CSR_SESSION_ID_INVALID;
+ }
+ pMac->roam.WaitForKeyTimerInfo.pMac = pMac;
+ pMac->roam.WaitForKeyTimerInfo.sessionId =
+ CSR_SESSION_ID_INVALID;
+ status =
+ cdf_mc_timer_init(&pMac->roam.hTimerWaitForKey,
+ CDF_TIMER_TYPE_SW,
+ csr_roam_wait_for_key_time_out_handler,
+ &pMac->roam.WaitForKeyTimerInfo);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ FL
+ ("cannot allocate memory for WaitForKey time out timer"));
+ break;
+ }
+ status =
+ cdf_mc_timer_init(&pMac->roam.tlStatsReqInfo.hTlStatsTimer,
+ CDF_TIMER_TYPE_SW,
+ csr_roam_tl_stats_timer_handler, pMac);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ FL
+ ("cannot allocate memory for summary Statistics timer"));
+ return CDF_STATUS_E_FAILURE;
+ }
+ } while (0);
+ return status;
+}
+
+CDF_STATUS csr_roam_close(tpAniSirGlobal pMac)
+{
+ uint32_t sessionId;
+ for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) {
+ csr_roam_close_session(pMac, sessionId, true, NULL, NULL);
+ }
+ cdf_mc_timer_stop(&pMac->roam.hTimerWaitForKey);
+ cdf_mc_timer_destroy(&pMac->roam.hTimerWaitForKey);
+ cdf_mc_timer_stop(&pMac->roam.tlStatsReqInfo.hTlStatsTimer);
+ cdf_mc_timer_destroy(&pMac->roam.tlStatsReqInfo.hTlStatsTimer);
+ return CDF_STATUS_SUCCESS;
+}
+
+CDF_STATUS csr_roam_start(tpAniSirGlobal pMac)
+{
+ (void)pMac;
+ return CDF_STATUS_SUCCESS;
+}
+
+void csr_roam_stop(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ csr_roam_stop_roaming_timer(pMac, sessionId);
+ /* deregister the clients requesting stats from PE/TL & also stop the corresponding timers */
+ csr_roam_dereg_statistics_req(pMac);
+}
+
+CDF_STATUS csr_roam_get_connect_state(tpAniSirGlobal pMac, uint32_t sessionId,
+ eCsrConnectState *pState)
+{
+ CDF_STATUS status = CDF_STATUS_E_INVAL;
+ if (CSR_IS_SESSION_VALID(pMac, sessionId) && (NULL != pState)) {
+ status = CDF_STATUS_SUCCESS;
+ *pState = pMac->roam.roamSession[sessionId].connectState;
+ }
+ return status;
+}
+
+CDF_STATUS csr_roam_copy_connect_profile(tpAniSirGlobal pMac,
+ uint32_t sessionId, tCsrRoamConnectedProfile *pProfile)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ uint32_t size = 0;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+ tCsrRoamConnectedProfile *connected_prof;
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+ if (!pProfile) {
+ sms_log(pMac, LOGE, FL("profile not found"));
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ if (pSession->pConnectBssDesc) {
+ size = pSession->pConnectBssDesc->length +
+ sizeof(pSession->pConnectBssDesc->length);
+ if (size) {
+ pProfile->pBssDesc = cdf_mem_malloc(size);
+ if (NULL != pProfile->pBssDesc) {
+ cdf_mem_copy(pProfile->pBssDesc,
+ pSession->pConnectBssDesc,
+ size);
+ status = CDF_STATUS_SUCCESS;
+ } else {
+ return CDF_STATUS_E_FAILURE;
+ }
+ } else {
+ pProfile->pBssDesc = NULL;
+ }
+ connected_prof = &(pSession->connectedProfile);
+ pProfile->AuthType = connected_prof->AuthType;
+ pProfile->EncryptionType = connected_prof->EncryptionType;
+ pProfile->mcEncryptionType = connected_prof->mcEncryptionType;
+ pProfile->BSSType = connected_prof->BSSType;
+ pProfile->operationChannel = connected_prof->operationChannel;
+ pProfile->CBMode = connected_prof->CBMode;
+ cdf_mem_copy(&pProfile->bssid, &connected_prof->bssid,
+ sizeof(struct cdf_mac_addr));
+ cdf_mem_copy(&pProfile->SSID, &connected_prof->SSID,
+ sizeof(tSirMacSSid));
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ if (connected_prof->MDID.mdiePresent) {
+ pProfile->MDID.mdiePresent = 1;
+ pProfile->MDID.mobilityDomain =
+ connected_prof->MDID.mobilityDomain;
+ } else {
+ pProfile->MDID.mdiePresent = 0;
+ pProfile->MDID.mobilityDomain = 0;
+ }
+#endif
+#ifdef FEATURE_WLAN_ESE
+ pProfile->isESEAssoc = connected_prof->isESEAssoc;
+ if (csr_is_auth_type_ese(connected_prof->AuthType)) {
+ cdf_mem_copy(pProfile->eseCckmInfo.krk,
+ connected_prof->eseCckmInfo.krk,
+ SIR_KRK_KEY_LEN);
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+ cdf_mem_copy(pProfile->eseCckmInfo.btk,
+ connected_prof->eseCckmInfo.btk,
+ SIR_BTK_KEY_LEN);
+#endif
+ pProfile->eseCckmInfo.reassoc_req_num =
+ connected_prof->eseCckmInfo.reassoc_req_num;
+ pProfile->eseCckmInfo.krk_plumbed =
+ connected_prof->eseCckmInfo.krk_plumbed;
+ }
+#endif
+ }
+ return status;
+}
+
+CDF_STATUS csr_roam_get_connect_profile(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamConnectedProfile *pProfile)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+
+ if ((csr_is_conn_state_connected(pMac, sessionId)) ||
+ (csr_is_conn_state_ibss(pMac, sessionId))) {
+ if (pProfile) {
+ status =
+ csr_roam_copy_connect_profile(pMac, sessionId,
+ pProfile);
+ }
+ }
+ return status;
+}
+
+CDF_STATUS csr_roam_free_connect_profile(tpAniSirGlobal pMac,
+ tCsrRoamConnectedProfile *pProfile)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+
+ if (pProfile->pBssDesc) {
+ cdf_mem_free(pProfile->pBssDesc);
+ }
+ if (pProfile->pAddIEAssoc) {
+ cdf_mem_free(pProfile->pAddIEAssoc);
+ }
+ cdf_mem_set(pProfile, sizeof(tCsrRoamConnectedProfile), 0);
+
+ pProfile->AuthType = eCSR_AUTH_TYPE_UNKNOWN;
+ return status;
+}
+
+static CDF_STATUS csr_roam_free_connected_info(tpAniSirGlobal pMac,
+ tCsrRoamConnectedInfo *
+ pConnectedInfo)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ if (pConnectedInfo->pbFrames) {
+ cdf_mem_free(pConnectedInfo->pbFrames);
+ pConnectedInfo->pbFrames = NULL;
+ }
+ pConnectedInfo->nBeaconLength = 0;
+ pConnectedInfo->nAssocReqLength = 0;
+ pConnectedInfo->nAssocRspLength = 0;
+ pConnectedInfo->staId = 0;
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ pConnectedInfo->nRICRspLength = 0;
+#endif
+#ifdef FEATURE_WLAN_ESE
+ pConnectedInfo->nTspecIeLength = 0;
+#endif
+ return status;
+}
+
+void csr_release_command_preauth(tpAniSirGlobal pMac, tSmeCmd *pCommand)
+{
+ csr_reinit_preauth_cmd(pMac, pCommand);
+ csr_release_command(pMac, pCommand);
+}
+
+void csr_release_command_roam(tpAniSirGlobal pMac, tSmeCmd *pCommand)
+{
+ csr_reinit_roam_cmd(pMac, pCommand);
+ csr_release_command(pMac, pCommand);
+}
+
+void csr_release_command_scan(tpAniSirGlobal pMac, tSmeCmd *pCommand)
+{
+ cdf_mc_timer_stop(&pCommand->u.scanCmd.csr_scan_timer);
+ cdf_mc_timer_destroy(&pCommand->u.scanCmd.csr_scan_timer);
+ csr_reinit_scan_cmd(pMac, pCommand);
+ csr_release_command(pMac, pCommand);
+}
+
+void csr_release_command_wm_status_change(tpAniSirGlobal pMac, tSmeCmd *pCommand)
+{
+ csr_reinit_wm_status_change_cmd(pMac, pCommand);
+ csr_release_command(pMac, pCommand);
+}
+
+void csr_reinit_set_key_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand)
+{
+ cdf_mem_set(&pCommand->u.setKeyCmd, sizeof(tSetKeyCmd), 0);
+}
+
+void csr_release_command_set_key(tpAniSirGlobal pMac, tSmeCmd *pCommand)
+{
+ csr_reinit_set_key_cmd(pMac, pCommand);
+ csr_release_command(pMac, pCommand);
+}
+
+/**
+ * csr_release_roc_req_cmd() - Release the command
+ * @mac_ctx: Global MAC Context
+ *
+ * Release the remain on channel request command from the queue
+ *
+ * Return: None
+ */
+void csr_release_roc_req_cmd(tpAniSirGlobal mac_ctx)
+{
+ tListElem *entry;
+ tSmeCmd *cmd = NULL;
+
+ entry = csr_ll_peek_head(&mac_ctx->sme.smeCmdActiveList,
+ LL_ACCESS_LOCK);
+ if (entry) {
+ cmd = GET_BASE_ADDR(entry, tSmeCmd, Link);
+ if (eSmeCommandRemainOnChannel == cmd->command) {
+ remainOnChanCallback callback =
+ cmd->u.remainChlCmd.callback;
+ /* process the msg */
+ if (callback)
+ callback(mac_ctx,
+ cmd->u.remainChlCmd.callbackCtx, 0,
+ cmd->u.remainChlCmd.scan_id);
+ sms_log(mac_ctx, LOGE,
+ FL("Remove RoC Request from Active Cmd List"));
+ /* Put this cmd back on the available command list */
+ if (csr_ll_remove_entry(&mac_ctx->sme.smeCmdActiveList,
+ entry, LL_ACCESS_LOCK))
+ sme_release_command(mac_ctx, cmd);
+ }
+ }
+}
+
+void csr_abort_command(tpAniSirGlobal pMac, tSmeCmd *pCommand, bool fStopping)
+{
+
+ if (eSmeCsrCommandMask & pCommand->command) {
+ switch (pCommand->command) {
+ case eSmeCommandScan:
+ /* We need to inform the requester before dropping the scan command */
+ sms_log(pMac, LOGW,
+ "%s: Drop scan reason %d callback %p", __func__,
+ pCommand->u.scanCmd.reason,
+ pCommand->u.scanCmd.callback);
+ if (NULL != pCommand->u.scanCmd.callback) {
+ sms_log(pMac, LOGW, "%s callback scan requester",
+ __func__);
+ csr_scan_call_callback(pMac, pCommand,
+ eCSR_SCAN_ABORT);
+ }
+ csr_release_command_scan(pMac, pCommand);
+ break;
+ case eSmeCommandRoam:
+ csr_release_command_roam(pMac, pCommand);
+ break;
+
+ case eSmeCommandWmStatusChange:
+ csr_release_command_wm_status_change(pMac, pCommand);
+ break;
+
+ case eSmeCommandSetKey:
+ csr_release_command_set_key(pMac, pCommand);
+ break;
+
+ default:
+ sms_log(pMac, LOGW, " CSR abort standard command %d",
+ pCommand->command);
+ csr_release_command(pMac, pCommand);
+ break;
+ }
+ }
+}
+
+void csr_roam_substate_change(tpAniSirGlobal pMac, eCsrRoamSubState NewSubstate,
+ uint32_t sessionId)
+{
+ sms_log(pMac, LOG1, FL("CSR RoamSubstate: [ %s <== %s ]"),
+ mac_trace_getcsr_roam_sub_state(NewSubstate),
+ mac_trace_getcsr_roam_sub_state(pMac->roam.curSubState[sessionId]));
+ if (pMac->roam.curSubState[sessionId] == NewSubstate) {
+ return;
+ }
+ pMac->roam.curSubState[sessionId] = NewSubstate;
+}
+
+eCsrRoamState csr_roam_state_change(tpAniSirGlobal pMac,
+ eCsrRoamState NewRoamState, uint8_t sessionId)
+{
+ eCsrRoamState PreviousState;
+
+ sms_log(pMac, LOG1, FL("CSR RoamState[%hu]: [ %s <== %s ]"), sessionId,
+ mac_trace_getcsr_roam_state(NewRoamState),
+ mac_trace_getcsr_roam_state(pMac->roam.curState[sessionId]));
+ PreviousState = pMac->roam.curState[sessionId];
+
+ if (NewRoamState != pMac->roam.curState[sessionId]) {
+ /* Whenever we transition OUT of the Roaming state, clear the Roaming substate... */
+ if (CSR_IS_ROAM_JOINING(pMac, sessionId)) {
+ csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_NONE,
+ sessionId);
+ }
+
+ pMac->roam.curState[sessionId] = NewRoamState;
+ }
+ return PreviousState;
+}
+
+void csr_assign_rssi_for_category(tpAniSirGlobal pMac, int8_t bestApRssi,
+ uint8_t catOffset)
+{
+ int i;
+ if (catOffset) {
+ pMac->roam.configParam.bCatRssiOffset = catOffset;
+ for (i = 0; i < CSR_NUM_RSSI_CAT; i++) {
+ pMac->roam.configParam.RSSICat[CSR_NUM_RSSI_CAT - i -
+ 1] =
+ (int)bestApRssi -
+ pMac->roam.configParam.nSelect5GHzMargin -
+ (int)(i * catOffset);
+ }
+ }
+}
+
+static void init_config_param(tpAniSirGlobal pMac)
+{
+ int i;
+ pMac->roam.configParam.agingCount = CSR_AGING_COUNT;
+ pMac->roam.configParam.channelBondingMode24GHz =
+ WNI_CFG_CHANNEL_BONDING_MODE_DISABLE;
+ pMac->roam.configParam.channelBondingMode5GHz =
+ WNI_CFG_CHANNEL_BONDING_MODE_ENABLE;
+
+ pMac->roam.configParam.phyMode = eCSR_DOT11_MODE_AUTO;
+ pMac->roam.configParam.eBand = eCSR_BAND_ALL;
+ pMac->roam.configParam.uCfgDot11Mode = eCSR_CFG_DOT11_MODE_AUTO;
+ pMac->roam.configParam.FragmentationThreshold =
+ eCSR_DOT11_FRAG_THRESH_DEFAULT;
+ pMac->roam.configParam.HeartbeatThresh24 = 40;
+ pMac->roam.configParam.HeartbeatThresh50 = 40;
+ pMac->roam.configParam.Is11dSupportEnabled = false;
+ pMac->roam.configParam.Is11dSupportEnabledOriginal = false;
+ pMac->roam.configParam.Is11eSupportEnabled = true;
+ pMac->roam.configParam.Is11hSupportEnabled = true;
+ pMac->roam.configParam.RTSThreshold = 2346;
+ pMac->roam.configParam.shortSlotTime = true;
+ pMac->roam.configParam.WMMSupportMode = eCsrRoamWmmAuto;
+ pMac->roam.configParam.ProprietaryRatesEnabled = true;
+ pMac->roam.configParam.TxRate = eCSR_TX_RATE_AUTO;
+ pMac->roam.configParam.scanAgeTimeNCNPS =
+ CSR_SCAN_AGING_TIME_NOT_CONNECT_NO_PS;
+ pMac->roam.configParam.scanAgeTimeNCPS =
+ CSR_SCAN_AGING_TIME_NOT_CONNECT_W_PS;
+ pMac->roam.configParam.scanAgeTimeCNPS =
+ CSR_SCAN_AGING_TIME_CONNECT_NO_PS;
+ pMac->roam.configParam.scanAgeTimeCPS =
+ CSR_SCAN_AGING_TIME_CONNECT_W_PS;
+ for (i = 0; i < CSR_NUM_RSSI_CAT; i++) {
+ pMac->roam.configParam.BssPreferValue[i] = i;
+ }
+ csr_assign_rssi_for_category(pMac, CSR_BEST_RSSI_VALUE,
+ CSR_DEFAULT_RSSI_DB_GAP);
+ pMac->roam.configParam.nRoamingTime = CSR_DEFAULT_ROAMING_TIME;
+ pMac->roam.configParam.fSupplicantCountryCodeHasPriority = false;
+ pMac->roam.configParam.nActiveMaxChnTime = CSR_ACTIVE_MAX_CHANNEL_TIME;
+ pMac->roam.configParam.nActiveMinChnTime = CSR_ACTIVE_MIN_CHANNEL_TIME;
+ pMac->roam.configParam.nPassiveMaxChnTime =
+ CSR_PASSIVE_MAX_CHANNEL_TIME;
+ pMac->roam.configParam.nPassiveMinChnTime =
+ CSR_PASSIVE_MIN_CHANNEL_TIME;
+#ifdef WLAN_AP_STA_CONCURRENCY
+ pMac->roam.configParam.nActiveMaxChnTimeConc =
+ CSR_ACTIVE_MAX_CHANNEL_TIME_CONC;
+ pMac->roam.configParam.nActiveMinChnTimeConc =
+ CSR_ACTIVE_MIN_CHANNEL_TIME_CONC;
+ pMac->roam.configParam.nPassiveMaxChnTimeConc =
+ CSR_PASSIVE_MAX_CHANNEL_TIME_CONC;
+ pMac->roam.configParam.nPassiveMinChnTimeConc =
+ CSR_PASSIVE_MIN_CHANNEL_TIME_CONC;
+ pMac->roam.configParam.nRestTimeConc = CSR_REST_TIME_CONC;
+ pMac->roam.configParam.nNumStaChanCombinedConc =
+ CSR_NUM_STA_CHAN_COMBINED_CONC;
+ pMac->roam.configParam.nNumP2PChanCombinedConc =
+ CSR_NUM_P2P_CHAN_COMBINED_CONC;
+#endif
+ pMac->roam.configParam.nTxPowerCap = CSR_MAX_TX_POWER;
+ pMac->roam.configParam.statsReqPeriodicity =
+ CSR_MIN_GLOBAL_STAT_QUERY_PERIOD;
+ pMac->roam.configParam.statsReqPeriodicityInPS =
+ CSR_MIN_GLOBAL_STAT_QUERY_PERIOD_IN_BMPS;
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ pMac->roam.configParam.csr11rConfig.IsFTResourceReqSupported = 0;
+#endif
+#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING
+ pMac->roam.configParam.neighborRoamConfig.nMaxNeighborRetries = 3;
+ pMac->roam.configParam.neighborRoamConfig.nNeighborLookupRssiThreshold =
+ 120;
+ pMac->roam.configParam.neighborRoamConfig.nOpportunisticThresholdDiff =
+ 30;
+ pMac->roam.configParam.neighborRoamConfig.nRoamRescanRssiDiff = 5;
+ pMac->roam.configParam.neighborRoamConfig.nNeighborScanMinChanTime = 20;
+ pMac->roam.configParam.neighborRoamConfig.nNeighborScanMaxChanTime = 40;
+ pMac->roam.configParam.neighborRoamConfig.nNeighborScanTimerPeriod =
+ 200;
+ pMac->roam.configParam.neighborRoamConfig.neighborScanChanList.
+ numChannels = 3;
+ pMac->roam.configParam.neighborRoamConfig.neighborScanChanList.
+ channelList[0] = 1;
+ pMac->roam.configParam.neighborRoamConfig.neighborScanChanList.
+ channelList[1] = 6;
+ pMac->roam.configParam.neighborRoamConfig.neighborScanChanList.
+ channelList[2] = 11;
+ pMac->roam.configParam.neighborRoamConfig.nNeighborResultsRefreshPeriod = 20000; /* 20 seconds */
+ pMac->roam.configParam.neighborRoamConfig.nEmptyScanRefreshPeriod = 0;
+ pMac->roam.configParam.neighborRoamConfig.nRoamBmissFirstBcnt = 10;
+ pMac->roam.configParam.neighborRoamConfig.nRoamBmissFinalBcnt = 10;
+ pMac->roam.configParam.neighborRoamConfig.nRoamBeaconRssiWeight = 14;
+#endif
+#ifdef WLAN_FEATURE_11AC
+ pMac->roam.configParam.nVhtChannelWidth =
+ WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ + 1;
+#endif
+
+ pMac->roam.configParam.addTSWhenACMIsOff = 0;
+ pMac->roam.configParam.fScanTwice = false;
+
+ /* Remove this code once SLM_Sessionization is supported */
+ /* BMPS_WORKAROUND_NOT_NEEDED */
+ pMac->roam.configParam.doBMPSWorkaround = 0;
+
+ pMac->roam.configParam.nInitialDwellTime = 0;
+ pMac->roam.configParam.initial_scan_no_dfs_chnl = 0;
+}
+
+eCsrBand csr_get_current_band(tHalHandle hHal)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ return pMac->roam.configParam.bandCapability;
+}
+
+#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD)
+/*
+ This function flushes the roam scan cache
+ */
+CDF_STATUS csr_flush_roam_scan_roam_channel_list(tpAniSirGlobal pMac,
+ uint8_t sessionId)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo
+ = &pMac->roam.neighborRoamInfo[sessionId];
+ /* Free up the memory first (if required) */
+ if (NULL !=
+ pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.
+ ChannelList) {
+ cdf_mem_free(pNeighborRoamInfo->roamChannelInfo.
+ currentChannelListInfo.ChannelList);
+ pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.
+ ChannelList = NULL;
+ pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.
+ numOfChannels = 0;
+ }
+ return status;
+}
+#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */
+
+#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR)
+/*
+ This function flushes the roam scan cache
+ */
+CDF_STATUS csr_flush_cfg_bg_scan_roam_channel_list(tpAniSirGlobal pMac,
+ uint8_t sessionId)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+
+ /* Free up the memory first (if required) */
+ if (NULL != pNeighborRoamInfo->cfgParams.channelInfo.ChannelList) {
+ cdf_mem_free(pNeighborRoamInfo->cfgParams.channelInfo.
+ ChannelList);
+ pNeighborRoamInfo->cfgParams.channelInfo.ChannelList = NULL;
+ pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels = 0;
+ }
+ return status;
+}
+
+/*
+ This function flushes the roam scan cache and creates fresh cache
+ based on the input channel list
+ */
+CDF_STATUS csr_create_bg_scan_roam_channel_list(tpAniSirGlobal pMac,
+ uint8_t sessionId,
+ const uint8_t *pChannelList,
+ const uint8_t numChannels)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+
+ pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels = numChannels;
+
+ pNeighborRoamInfo->cfgParams.channelInfo.ChannelList =
+ cdf_mem_malloc(pNeighborRoamInfo->cfgParams.channelInfo.
+ numOfChannels);
+
+ if (NULL == pNeighborRoamInfo->cfgParams.channelInfo.ChannelList) {
+ sms_log(pMac, LOGE,
+ FL("Memory Allocation for CFG Channel List failed"));
+ pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels = 0;
+ return CDF_STATUS_E_NOMEM;
+ }
+
+ /* Update the roam global structure */
+ cdf_mem_copy(pNeighborRoamInfo->cfgParams.channelInfo.ChannelList,
+ pChannelList,
+ pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels);
+ return status;
+}
+
+#endif
+
+#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD)
+/*
+ * This function modifies the roam scan channel list as per AP neighbor
+ * report; AP neighbor report may be empty or may include only other AP
+ * channels; in any case, we merge the channel list with the learned occupied
+ * channels list.
+ * if the band is 2.4G, then make sure channel list contains only 2.4G
+ * valid channels if the band is 5G, then make sure channel list contains
+ * only 5G valid channels
+ */
+CDF_STATUS csr_create_roam_scan_channel_list(tpAniSirGlobal pMac,
+ uint8_t sessionId,
+ uint8_t *pChannelList,
+ uint8_t numChannels,
+ const eCsrBand eBand)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo
+ = &pMac->roam.neighborRoamInfo[sessionId];
+ uint8_t outNumChannels = 0;
+ uint8_t inNumChannels = numChannels;
+ uint8_t *inPtr = pChannelList;
+ uint8_t i = 0;
+ uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
+ uint8_t tmpChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 };
+ uint8_t mergedOutputNumOfChannels = 0;
+ tpCsrChannelInfo currChannelListInfo
+ = &pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo;
+ /*
+ * Create a Union of occupied channel list learnt by the DUT along
+ * with the Neighbor report Channels. This increases the chances of
+ * the DUT to get a candidate AP while roaming even if the Neighbor
+ * Report is not able to provide sufficient information.
+ */
+ if (pMac->scan.occupiedChannels[sessionId].numChannels) {
+ csr_neighbor_roam_merge_channel_lists(pMac,
+ &pMac->scan.
+ occupiedChannels[sessionId].
+ channelList[0],
+ pMac->scan.
+ occupiedChannels[sessionId].
+ numChannels, inPtr,
+ inNumChannels,
+ &mergedOutputNumOfChannels);
+ inNumChannels = mergedOutputNumOfChannels;
+ }
+ if (eCSR_BAND_24 == eBand) {
+ for (i = 0; i < inNumChannels; i++) {
+ if (CDS_IS_CHANNEL_24GHZ(inPtr[i])
+ && csr_roam_is_channel_valid(pMac, inPtr[i])) {
+ ChannelList[outNumChannels++] = inPtr[i];
+ }
+ }
+ } else if (eCSR_BAND_5G == eBand) {
+ for (i = 0; i < inNumChannels; i++) {
+ /* Add 5G Non-DFS channel */
+ if (CDS_IS_CHANNEL_5GHZ(inPtr[i]) &&
+ csr_roam_is_channel_valid(pMac, inPtr[i]) &&
+ !CDS_IS_DFS_CH(inPtr[i])) {
+ ChannelList[outNumChannels++] = inPtr[i];
+ }
+ }
+ } else if (eCSR_BAND_ALL == eBand) {
+ for (i = 0; i < inNumChannels; i++) {
+ if (csr_roam_is_channel_valid(pMac, inPtr[i]) &&
+ !CDS_IS_DFS_CH(inPtr[i])) {
+ ChannelList[outNumChannels++] = inPtr[i];
+ }
+ }
+ } else {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_WARN,
+ "Invalid band, No operation carried out (Band %d)",
+ eBand);
+ return CDF_STATUS_E_INVAL;
+ }
+ /*
+ * if roaming within band is enabled, then select only the
+ * in band channels .
+ * This is required only if the band capability is set to ALL,
+ * E.g., if band capability is only 2.4G then all the channels in the
+ * list are already filtered for 2.4G channels, hence ignore this check
+ */
+ if ((eCSR_BAND_ALL == eBand) && CSR_IS_ROAM_INTRA_BAND_ENABLED(pMac)) {
+ csr_neighbor_roam_channels_filter_by_current_band(pMac,
+ sessionId,
+ ChannelList,
+ outNumChannels,
+ tmpChannelList,
+ &outNumChannels);
+ cdf_mem_copy(ChannelList, tmpChannelList, outNumChannels);
+ }
+ /* Prepare final roam scan channel list */
+ if (outNumChannels) {
+ /* Clear the channel list first */
+ if (NULL != currChannelListInfo->ChannelList) {
+ cdf_mem_free(currChannelListInfo->ChannelList);
+ currChannelListInfo->ChannelList = NULL;
+ currChannelListInfo->numOfChannels = 0;
+ }
+ currChannelListInfo->ChannelList
+ = cdf_mem_malloc(outNumChannels * sizeof(uint8_t));
+ if (NULL == currChannelListInfo->ChannelList) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL,
+ "Failed to allocate memory for roam scan channel list");
+ currChannelListInfo->numOfChannels = 0;
+ return CDF_STATUS_E_NOMEM;
+ }
+ cdf_mem_copy(currChannelListInfo->ChannelList,
+ ChannelList, outNumChannels);
+ }
+ return status;
+}
+#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */
+
+CDF_STATUS csr_set_band(tHalHandle hHal, uint8_t sessionId, eCsrBand eBand)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ if (CSR_IS_PHY_MODE_A_ONLY(pMac) && (eBand == eCSR_BAND_24)) {
+ /* DOT11 mode configured to 11a only and received
+ request to change the band to 2.4 GHz */
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ "failed to set band cfg80211 = %u, band = %u",
+ pMac->roam.configParam.uCfgDot11Mode, eBand);
+ return CDF_STATUS_E_INVAL;
+ }
+ if ((CSR_IS_PHY_MODE_B_ONLY(pMac) ||
+ CSR_IS_PHY_MODE_G_ONLY(pMac)) && (eBand == eCSR_BAND_5G)) {
+ /* DOT11 mode configured to 11b/11g only and received
+ request to change the band to 5 GHz */
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ "failed to set band dot11mode = %u, band = %u",
+ pMac->roam.configParam.uCfgDot11Mode, eBand);
+ return CDF_STATUS_E_INVAL;
+ }
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ "Band changed to %u (0 - ALL, 1 - 2.4 GHZ, 2 - 5GHZ)", eBand);
+ pMac->roam.configParam.eBand = eBand;
+ pMac->roam.configParam.bandCapability = eBand;
+
+ status = csr_get_channel_and_power_list(pMac);
+ if (CDF_STATUS_SUCCESS == status)
+ csr_apply_channel_and_power_list(pMac);
+ return status;
+}
+
+/* The funcns csr_convert_cb_ini_value_to_phy_cb_state and csr_convert_phy_cb_state_to_ini_value have been
+ * introduced to convert the ini value to the ENUM used in csr and MAC for CB state
+ * Ideally we should have kept the ini value and enum value same and representing the same
+ * cb values as in 11n standard i.e.
+ * Set to 1 (SCA) if the secondary channel is above the primary channel
+ * Set to 3 (SCB) if the secondary channel is below the primary channel
+ * Set to 0 (SCN) if no secondary channel is present
+ * However, since our driver is already distributed we will keep the ini definition as it is which is:
+ * 0 - secondary none
+ * 1 - secondary LOW
+ * 2 - secondary HIGH
+ * and convert to enum value used within the driver in csr_change_default_config_param using this funcn
+ * The enum values are as follows:
+ * PHY_SINGLE_CHANNEL_CENTERED = 0
+ * PHY_DOUBLE_CHANNEL_LOW_PRIMARY = 1
+ * PHY_DOUBLE_CHANNEL_HIGH_PRIMARY = 3
+ */
+ePhyChanBondState csr_convert_cb_ini_value_to_phy_cb_state(uint32_t cbIniValue)
+{
+
+ ePhyChanBondState phyCbState;
+ switch (cbIniValue) {
+ /* secondary none */
+ case eCSR_INI_SINGLE_CHANNEL_CENTERED:
+ phyCbState = PHY_SINGLE_CHANNEL_CENTERED;
+ break;
+ /* secondary LOW */
+ case eCSR_INI_DOUBLE_CHANNEL_HIGH_PRIMARY:
+ phyCbState = PHY_DOUBLE_CHANNEL_HIGH_PRIMARY;
+ break;
+ /* secondary HIGH */
+ case eCSR_INI_DOUBLE_CHANNEL_LOW_PRIMARY:
+ phyCbState = PHY_DOUBLE_CHANNEL_LOW_PRIMARY;
+ break;
+#ifdef WLAN_FEATURE_11AC
+ case eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED:
+ phyCbState = PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED;
+ break;
+ case eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED:
+ phyCbState =
+ PHY_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED;
+ break;
+ case eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED:
+ phyCbState = PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED;
+ break;
+ case eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW:
+ phyCbState = PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW;
+ break;
+ case eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW:
+ phyCbState = PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW;
+ break;
+ case eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH:
+ phyCbState = PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH;
+ break;
+ case eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH:
+ phyCbState = PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH;
+ break;
+#endif
+ default:
+ /* If an invalid value is passed, disable CHANNEL BONDING */
+ phyCbState = PHY_SINGLE_CHANNEL_CENTERED;
+ break;
+ }
+ return phyCbState;
+}
+
+uint32_t csr_convert_phy_cb_state_to_ini_value(ePhyChanBondState phyCbState)
+{
+
+ uint32_t cbIniValue;
+ switch (phyCbState) {
+ /* secondary none */
+ case PHY_SINGLE_CHANNEL_CENTERED:
+ cbIniValue = eCSR_INI_SINGLE_CHANNEL_CENTERED;
+ break;
+ /* secondary LOW */
+ case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY:
+ cbIniValue = eCSR_INI_DOUBLE_CHANNEL_HIGH_PRIMARY;
+ break;
+ /* secondary HIGH */
+ case PHY_DOUBLE_CHANNEL_LOW_PRIMARY:
+ cbIniValue = eCSR_INI_DOUBLE_CHANNEL_LOW_PRIMARY;
+ break;
+#ifdef WLAN_FEATURE_11AC
+ case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED:
+ cbIniValue =
+ eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED;
+ break;
+ case PHY_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED:
+ cbIniValue =
+ eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED;
+ break;
+ case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED:
+ cbIniValue =
+ eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED;
+ break;
+ case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW:
+ cbIniValue = eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW;
+ break;
+ case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW:
+ cbIniValue = eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW;
+ break;
+ case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH:
+ cbIniValue = eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH;
+ break;
+ case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH:
+ cbIniValue = eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH;
+ break;
+#endif
+ default:
+ /* return some invalid value */
+ cbIniValue = eCSR_INI_CHANNEL_BONDING_STATE_MAX;
+ break;
+ }
+ return cbIniValue;
+}
+
+CDF_STATUS csr_change_default_config_param(tpAniSirGlobal pMac,
+ tCsrConfigParam *pParam)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+
+ if (pParam) {
+ pMac->roam.configParam.WMMSupportMode = pParam->WMMSupportMode;
+ cfg_set_int(pMac, WNI_CFG_WME_ENABLED,
+ (pParam->WMMSupportMode == eCsrRoamWmmNoQos) ? 0 : 1);
+ pMac->roam.configParam.Is11eSupportEnabled =
+ pParam->Is11eSupportEnabled;
+ pMac->roam.configParam.FragmentationThreshold =
+ pParam->FragmentationThreshold;
+ pMac->roam.configParam.Is11dSupportEnabled =
+ pParam->Is11dSupportEnabled;
+ pMac->roam.configParam.Is11dSupportEnabledOriginal =
+ pParam->Is11dSupportEnabled;
+ pMac->roam.configParam.Is11hSupportEnabled =
+ pParam->Is11hSupportEnabled;
+
+ pMac->roam.configParam.fenableMCCMode = pParam->fEnableMCCMode;
+ pMac->roam.configParam.mcc_rts_cts_prot_enable =
+ pParam->mcc_rts_cts_prot_enable;
+ pMac->roam.configParam.mcc_bcast_prob_resp_enable =
+ pParam->mcc_bcast_prob_resp_enable;
+ pMac->roam.configParam.fAllowMCCGODiffBI =
+ pParam->fAllowMCCGODiffBI;
+
+ /* channelBondingMode5GHz plays a dual role right now
+ * INFRA STA will use this non zero value as CB enabled and SOFTAP will use this non-zero value to determine the secondary channel offset
+ * This is how channelBondingMode5GHz works now and this is kept intact to avoid any cfg.ini change
+ */
+ if (pParam->channelBondingMode24GHz > MAX_CB_VALUE_IN_INI) {
+ sms_log(pMac, LOGW,
+ "Invalid CB value from ini in 2.4GHz band %d, CB DISABLED",
+ pParam->channelBondingMode24GHz);
+ }
+ pMac->roam.configParam.channelBondingMode24GHz =
+ csr_convert_cb_ini_value_to_phy_cb_state(pParam->
+ channelBondingMode24GHz);
+ if (pParam->channelBondingMode5GHz > MAX_CB_VALUE_IN_INI) {
+ sms_log(pMac, LOGW,
+ "Invalid CB value from ini in 5GHz band %d, CB DISABLED",
+ pParam->channelBondingMode5GHz);
+ }
+ pMac->roam.configParam.channelBondingMode5GHz =
+ csr_convert_cb_ini_value_to_phy_cb_state(pParam->
+ channelBondingMode5GHz);
+ pMac->roam.configParam.RTSThreshold = pParam->RTSThreshold;
+ pMac->roam.configParam.phyMode = pParam->phyMode;
+ pMac->roam.configParam.shortSlotTime = pParam->shortSlotTime;
+ pMac->roam.configParam.HeartbeatThresh24 =
+ pParam->HeartbeatThresh24;
+ pMac->roam.configParam.HeartbeatThresh50 =
+ pParam->HeartbeatThresh50;
+ pMac->roam.configParam.ProprietaryRatesEnabled =
+ pParam->ProprietaryRatesEnabled;
+ pMac->roam.configParam.TxRate = pParam->TxRate;
+ pMac->roam.configParam.AdHocChannel24 = pParam->AdHocChannel24;
+ pMac->roam.configParam.AdHocChannel5G = pParam->AdHocChannel5G;
+ pMac->roam.configParam.bandCapability = pParam->bandCapability;
+ pMac->roam.configParam.cbChoice = pParam->cbChoice;
+ pMac->roam.configParam.neighborRoamConfig.
+ delay_before_vdev_stop =
+ pParam->neighborRoamConfig.delay_before_vdev_stop;
+
+ /* if HDD passed down non zero values then only update, */
+ /* otherwise keep using the defaults */
+ if (pParam->initial_scan_no_dfs_chnl) {
+ pMac->roam.configParam.initial_scan_no_dfs_chnl =
+ pParam->initial_scan_no_dfs_chnl;
+ }
+ if (pParam->nInitialDwellTime) {
+ pMac->roam.configParam.nInitialDwellTime =
+ pParam->nInitialDwellTime;
+ }
+ if (pParam->nActiveMaxChnTime) {
+ pMac->roam.configParam.nActiveMaxChnTime =
+ pParam->nActiveMaxChnTime;
+ cfg_set_int(pMac, WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME,
+ pParam->nActiveMaxChnTime);
+ }
+ if (pParam->nActiveMinChnTime) {
+ pMac->roam.configParam.nActiveMinChnTime =
+ pParam->nActiveMinChnTime;
+ cfg_set_int(pMac, WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME,
+ pParam->nActiveMinChnTime);
+ }
+ if (pParam->nPassiveMaxChnTime) {
+ pMac->roam.configParam.nPassiveMaxChnTime =
+ pParam->nPassiveMaxChnTime;
+ cfg_set_int(pMac, WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME,
+ pParam->nPassiveMaxChnTime);
+ }
+ if (pParam->nPassiveMinChnTime) {
+ pMac->roam.configParam.nPassiveMinChnTime =
+ pParam->nPassiveMinChnTime;
+ cfg_set_int(pMac, WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME,
+ pParam->nPassiveMinChnTime);
+ }
+#ifdef WLAN_AP_STA_CONCURRENCY
+ if (pParam->nActiveMaxChnTimeConc) {
+ pMac->roam.configParam.nActiveMaxChnTimeConc =
+ pParam->nActiveMaxChnTimeConc;
+ }
+ if (pParam->nActiveMinChnTimeConc) {
+ pMac->roam.configParam.nActiveMinChnTimeConc =
+ pParam->nActiveMinChnTimeConc;
+ }
+ if (pParam->nPassiveMaxChnTimeConc) {
+ pMac->roam.configParam.nPassiveMaxChnTimeConc =
+ pParam->nPassiveMaxChnTimeConc;
+ }
+ if (pParam->nPassiveMinChnTimeConc) {
+ pMac->roam.configParam.nPassiveMinChnTimeConc =
+ pParam->nPassiveMinChnTimeConc;
+ }
+ if (pParam->nRestTimeConc) {
+ pMac->roam.configParam.nRestTimeConc =
+ pParam->nRestTimeConc;
+ }
+ if (pParam->nNumStaChanCombinedConc) {
+ pMac->roam.configParam.nNumStaChanCombinedConc =
+ pParam->nNumStaChanCombinedConc;
+ }
+ if (pParam->nNumP2PChanCombinedConc) {
+ pMac->roam.configParam.nNumP2PChanCombinedConc =
+ pParam->nNumP2PChanCombinedConc;
+ }
+#endif
+ pMac->roam.configParam.eBand = pParam->eBand;
+ pMac->roam.configParam.uCfgDot11Mode =
+ csr_get_cfg_dot11_mode_from_csr_phy_mode(NULL,
+ pMac->roam.configParam.
+ phyMode,
+ pMac->roam.configParam.
+ ProprietaryRatesEnabled);
+ /* if HDD passed down non zero values for age params, then only update, */
+ /* otherwise keep using the defaults */
+ if (pParam->nScanResultAgeCount) {
+ pMac->roam.configParam.agingCount =
+ pParam->nScanResultAgeCount;
+ }
+ if (pParam->scanAgeTimeNCNPS) {
+ pMac->roam.configParam.scanAgeTimeNCNPS =
+ pParam->scanAgeTimeNCNPS;
+ }
+ if (pParam->scanAgeTimeNCPS) {
+ pMac->roam.configParam.scanAgeTimeNCPS =
+ pParam->scanAgeTimeNCPS;
+ }
+ if (pParam->scanAgeTimeCNPS) {
+ pMac->roam.configParam.scanAgeTimeCNPS =
+ pParam->scanAgeTimeCNPS;
+ }
+ if (pParam->scanAgeTimeCPS) {
+ pMac->roam.configParam.scanAgeTimeCPS =
+ pParam->scanAgeTimeCPS;
+ }
+
+ csr_assign_rssi_for_category(pMac, CSR_BEST_RSSI_VALUE,
+ pParam->bCatRssiOffset);
+ pMac->roam.configParam.nRoamingTime = pParam->nRoamingTime;
+ pMac->roam.configParam.fSupplicantCountryCodeHasPriority =
+ pParam->fSupplicantCountryCodeHasPriority;
+ pMac->roam.configParam.vccRssiThreshold =
+ pParam->vccRssiThreshold;
+ pMac->roam.configParam.vccUlMacLossThreshold =
+ pParam->vccUlMacLossThreshold;
+ pMac->roam.configParam.statsReqPeriodicity =
+ pParam->statsReqPeriodicity;
+ pMac->roam.configParam.statsReqPeriodicityInPS =
+ pParam->statsReqPeriodicityInPS;
+ /* Assign this before calling csr_init11d_info */
+ pMac->roam.configParam.nTxPowerCap = pParam->nTxPowerCap;
+ if (csr_is11d_supported(pMac)) {
+ status = csr_init11d_info(pMac, &pParam->Csr11dinfo);
+ } else {
+ pMac->scan.curScanType = eSIR_ACTIVE_SCAN;
+ }
+
+ /* Initialize the power + channel information if 11h is enabled.
+ If 11d is enabled this information has already been initialized */
+ if (csr_is11h_supported(pMac) && !csr_is11d_supported(pMac)) {
+ csr_init_channel_power_list(pMac, &pParam->Csr11dinfo);
+ }
+
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ cdf_mem_copy(&pMac->roam.configParam.csr11rConfig,
+ &pParam->csr11rConfig,
+ sizeof(tCsr11rConfigParams));
+ sms_log(pMac, LOG1, "IsFTResourceReqSupp = %d",
+ pMac->roam.configParam.csr11rConfig.
+ IsFTResourceReqSupported);
+#endif
+#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR)
+ pMac->roam.configParam.isFastTransitionEnabled =
+ pParam->isFastTransitionEnabled;
+ pMac->roam.configParam.RoamRssiDiff = pParam->RoamRssiDiff;
+ pMac->roam.configParam.nRoamPrefer5GHz =
+ pParam->nRoamPrefer5GHz;
+ pMac->roam.configParam.nRoamIntraBand = pParam->nRoamIntraBand;
+ pMac->roam.configParam.isWESModeEnabled =
+ pParam->isWESModeEnabled;
+ pMac->roam.configParam.nProbes = pParam->nProbes;
+ pMac->roam.configParam.nRoamScanHomeAwayTime =
+ pParam->nRoamScanHomeAwayTime;
+#endif
+ pMac->roam.configParam.isRoamOffloadScanEnabled =
+ pParam->isRoamOffloadScanEnabled;
+ pMac->roam.configParam.bFastRoamInConIniFeatureEnabled =
+ pParam->bFastRoamInConIniFeatureEnabled;
+#ifdef FEATURE_WLAN_LFR
+ pMac->roam.configParam.isFastRoamIniFeatureEnabled =
+ pParam->isFastRoamIniFeatureEnabled;
+ pMac->roam.configParam.MAWCEnabled = pParam->MAWCEnabled;
+#endif
+
+#ifdef FEATURE_WLAN_ESE
+ pMac->roam.configParam.isEseIniFeatureEnabled =
+ pParam->isEseIniFeatureEnabled;
+#endif
+#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING
+ cdf_mem_copy(&pMac->roam.configParam.neighborRoamConfig,
+ &pParam->neighborRoamConfig,
+ sizeof(tCsrNeighborRoamConfigParams));
+ sms_log(pMac, LOG1, "nNeighborScanTimerPerioid = %d",
+ pMac->roam.configParam.neighborRoamConfig.
+ nNeighborScanTimerPeriod);
+ sms_log(pMac, LOG1, "nNeighborLookupRssiThreshold = %d",
+ pMac->roam.configParam.neighborRoamConfig.
+ nNeighborLookupRssiThreshold);
+ sms_log(pMac, LOG1, "nOpportunisticThresholdDiff = %d",
+ pMac->roam.configParam.neighborRoamConfig.
+ nOpportunisticThresholdDiff);
+ sms_log(pMac, LOG1, "nRoamRescanRssiDiff = %d",
+ pMac->roam.configParam.neighborRoamConfig.
+ nRoamRescanRssiDiff);
+ sms_log(pMac, LOG1, "nNeighborScanMinChanTime = %d",
+ pMac->roam.configParam.neighborRoamConfig.
+ nNeighborScanMinChanTime);
+ sms_log(pMac, LOG1, "nNeighborScanMaxChanTime = %d",
+ pMac->roam.configParam.neighborRoamConfig.
+ nNeighborScanMaxChanTime);
+ sms_log(pMac, LOG1, "nMaxNeighborRetries = %d",
+ pMac->roam.configParam.neighborRoamConfig.
+ nMaxNeighborRetries);
+ sms_log(pMac, LOG1, "nNeighborResultsRefreshPeriod = %d",
+ pMac->roam.configParam.neighborRoamConfig.
+ nNeighborResultsRefreshPeriod);
+ sms_log(pMac, LOG1, "nEmptyScanRefreshPeriod = %d",
+ pMac->roam.configParam.neighborRoamConfig.
+ nEmptyScanRefreshPeriod);
+ {
+ int i;
+ sms_log(pMac, LOG1,
+ FL("Num of Channels in CFG Channel List: %d"),
+ pMac->roam.configParam.neighborRoamConfig.
+ neighborScanChanList.numChannels);
+ for (i = 0;
+ i <
+ pMac->roam.configParam.neighborRoamConfig.
+ neighborScanChanList.numChannels; i++) {
+ sms_log(pMac, LOG1, "%d ",
+ pMac->roam.configParam.
+ neighborRoamConfig.neighborScanChanList.
+ channelList[i]);
+ }
+ }
+ sms_log(pMac, LOG1, "nRoamBmissFirstBcnt = %d",
+ pMac->roam.configParam.neighborRoamConfig.
+ nRoamBmissFirstBcnt);
+ sms_log(pMac, LOG1, "nRoamBmissFinalBcnt = %d",
+ pMac->roam.configParam.neighborRoamConfig.
+ nRoamBmissFinalBcnt);
+ sms_log(pMac, LOG1, "nRoamBeaconRssiWeight = %d",
+ pMac->roam.configParam.neighborRoamConfig.
+ nRoamBeaconRssiWeight);
+#endif
+ pMac->roam.configParam.addTSWhenACMIsOff =
+ pParam->addTSWhenACMIsOff;
+ pMac->scan.fValidateList = pParam->fValidateList;
+ pMac->scan.fEnableBypass11d = pParam->fEnableBypass11d;
+ pMac->scan.fEnableDFSChnlScan = pParam->fEnableDFSChnlScan;
+ pMac->scan.scanResultCfgAgingTime = pParam->scanCfgAgingTime;
+ pMac->roam.configParam.fScanTwice = pParam->fScanTwice;
+ pMac->scan.fFirstScanOnly2GChnl = pParam->fFirstScanOnly2GChnl;
+ pMac->scan.max_scan_count = pParam->max_scan_count;
+ /* This parameter is not available in cfg and not passed from upper layers. Instead it is initialized here
+ * This paramtere is used in concurrency to determine if there are concurrent active sessions.
+ * Is used as a temporary fix to disconnect all active sessions when BMPS enabled so the active session if Infra STA
+ * will automatically connect back and resume BMPS since resume BMPS is not working when moving from concurrent to
+ * single session
+ */
+ /* Remove this code once SLM_Sessionization is supported */
+ /* BMPS_WORKAROUND_NOT_NEEDED */
+ pMac->roam.configParam.doBMPSWorkaround = 0;
+
+#ifdef WLAN_FEATURE_11AC
+ pMac->roam.configParam.nVhtChannelWidth =
+ pParam->nVhtChannelWidth;
+ pMac->roam.configParam.txBFEnable = pParam->enableTxBF;
+ pMac->roam.configParam.txBFCsnValue = pParam->txBFCsnValue;
+ pMac->roam.configParam.enable2x2 = pParam->enable2x2;
+ pMac->roam.configParam.enableVhtFor24GHz =
+ pParam->enableVhtFor24GHz;
+ pMac->roam.configParam.txMuBformee = pParam->enableMuBformee;
+ pMac->roam.configParam.enableVhtpAid = pParam->enableVhtpAid;
+ pMac->roam.configParam.enableVhtGid = pParam->enableVhtGid;
+#endif
+ pMac->roam.configParam.enableAmpduPs = pParam->enableAmpduPs;
+ pMac->roam.configParam.enableHtSmps = pParam->enableHtSmps;
+ pMac->roam.configParam.htSmps = pParam->htSmps;
+ pMac->roam.configParam.txLdpcEnable = pParam->enableTxLdpc;
+ pMac->roam.configParam.ignore_peer_erp_info =
+ pParam->ignore_peer_erp_info;
+ pMac->roam.configParam.isAmsduSupportInAMPDU =
+ pParam->isAmsduSupportInAMPDU;
+ pMac->roam.configParam.nSelect5GHzMargin =
+ pParam->nSelect5GHzMargin;
+ pMac->roam.configParam.isCoalesingInIBSSAllowed =
+ pParam->isCoalesingInIBSSAllowed;
+#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH
+ pMac->roam.configParam.cc_switch_mode = pParam->cc_switch_mode;
+#endif
+ pMac->roam.configParam.allowDFSChannelRoam =
+ pParam->allowDFSChannelRoam;
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+ pMac->roam.configParam.isRoamOffloadEnabled =
+ pParam->isRoamOffloadEnabled;
+#endif
+ pMac->roam.configParam.obssEnabled = pParam->obssEnabled;
+ pMac->roam.configParam.conc_custom_rule1 =
+ pParam->conc_custom_rule1;
+ pMac->roam.configParam.conc_custom_rule2 =
+ pParam->conc_custom_rule2;
+ pMac->roam.configParam.is_sta_connection_in_5gz_enabled =
+ pParam->is_sta_connection_in_5gz_enabled;
+ pMac->roam.configParam.sendDeauthBeforeCon =
+ pParam->sendDeauthBeforeCon;
+
+ pMac->enable_dot11p = pParam->enable_dot11p;
+ }
+
+ return status;
+}
+
+CDF_STATUS csr_get_config_param(tpAniSirGlobal pMac, tCsrConfigParam *pParam)
+{
+ int i;
+ tCsrConfig *cfg_params = &pMac->roam.configParam;
+
+ if (!pParam)
+ return CDF_STATUS_E_INVAL;
+
+ pParam->WMMSupportMode = cfg_params->WMMSupportMode;
+ pParam->Is11eSupportEnabled = cfg_params->Is11eSupportEnabled;
+ pParam->FragmentationThreshold = cfg_params->FragmentationThreshold;
+ pParam->Is11dSupportEnabled = cfg_params->Is11dSupportEnabled;
+ pParam->Is11dSupportEnabledOriginal =
+ cfg_params->Is11dSupportEnabledOriginal;
+ pParam->Is11hSupportEnabled = cfg_params->Is11hSupportEnabled;
+ pParam->channelBondingMode24GHz = csr_convert_phy_cb_state_to_ini_value(
+ cfg_params->channelBondingMode24GHz);
+ pParam->channelBondingMode5GHz = csr_convert_phy_cb_state_to_ini_value(
+ cfg_params->channelBondingMode5GHz);
+ pParam->RTSThreshold = cfg_params->RTSThreshold;
+ pParam->phyMode = cfg_params->phyMode;
+ pParam->shortSlotTime = cfg_params->shortSlotTime;
+ pParam->HeartbeatThresh24 = cfg_params->HeartbeatThresh24;
+ pParam->HeartbeatThresh50 = cfg_params->HeartbeatThresh50;
+ pParam->ProprietaryRatesEnabled = cfg_params->ProprietaryRatesEnabled;
+ pParam->TxRate = cfg_params->TxRate;
+ pParam->AdHocChannel24 = cfg_params->AdHocChannel24;
+ pParam->AdHocChannel5G = cfg_params->AdHocChannel5G;
+ pParam->bandCapability = cfg_params->bandCapability;
+ pParam->cbChoice = cfg_params->cbChoice;
+ pParam->nActiveMaxChnTime = cfg_params->nActiveMaxChnTime;
+ pParam->nActiveMinChnTime = cfg_params->nActiveMinChnTime;
+ pParam->nPassiveMaxChnTime = cfg_params->nPassiveMaxChnTime;
+ pParam->nPassiveMinChnTime = cfg_params->nPassiveMinChnTime;
+#ifdef WLAN_AP_STA_CONCURRENCY
+ pParam->nActiveMaxChnTimeConc = cfg_params->nActiveMaxChnTimeConc;
+ pParam->nActiveMinChnTimeConc = cfg_params->nActiveMinChnTimeConc;
+ pParam->nPassiveMaxChnTimeConc = cfg_params->nPassiveMaxChnTimeConc;
+ pParam->nPassiveMinChnTimeConc = cfg_params->nPassiveMinChnTimeConc;
+ pParam->nRestTimeConc = cfg_params->nRestTimeConc;
+ pParam->nNumStaChanCombinedConc = cfg_params->nNumStaChanCombinedConc;
+ pParam->nNumP2PChanCombinedConc = cfg_params->nNumP2PChanCombinedConc;
+#endif
+ pParam->eBand = cfg_params->eBand;
+ pParam->nScanResultAgeCount = cfg_params->agingCount;
+ pParam->scanAgeTimeNCNPS = cfg_params->scanAgeTimeNCNPS;
+ pParam->scanAgeTimeNCPS = cfg_params->scanAgeTimeNCPS;
+ pParam->scanAgeTimeCNPS = cfg_params->scanAgeTimeCNPS;
+ pParam->scanAgeTimeCPS = cfg_params->scanAgeTimeCPS;
+ pParam->bCatRssiOffset = cfg_params->bCatRssiOffset;
+ pParam->nRoamingTime = cfg_params->nRoamingTime;
+ pParam->fSupplicantCountryCodeHasPriority =
+ cfg_params->fSupplicantCountryCodeHasPriority;
+ pParam->vccRssiThreshold = cfg_params->vccRssiThreshold;
+ pParam->vccUlMacLossThreshold = cfg_params->vccUlMacLossThreshold;
+ pParam->nTxPowerCap = cfg_params->nTxPowerCap;
+ pParam->statsReqPeriodicity = cfg_params->statsReqPeriodicity;
+ pParam->statsReqPeriodicityInPS = cfg_params->statsReqPeriodicityInPS;
+ pParam->addTSWhenACMIsOff = cfg_params->addTSWhenACMIsOff;
+ pParam->fValidateList = cfg_params->fValidateList;
+ pParam->fEnableBypass11d = pMac->scan.fEnableBypass11d;
+ pParam->fEnableDFSChnlScan = pMac->scan.fEnableDFSChnlScan;
+ pParam->fScanTwice = cfg_params->fScanTwice;
+ pParam->fFirstScanOnly2GChnl = pMac->scan.fFirstScanOnly2GChnl;
+ pParam->fEnableMCCMode = cfg_params->fenableMCCMode;
+ pParam->fAllowMCCGODiffBI = cfg_params->fAllowMCCGODiffBI;
+ pParam->scanCfgAgingTime = pMac->scan.scanResultCfgAgingTime;
+#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING
+ cdf_mem_copy(&pParam->neighborRoamConfig,
+ &cfg_params->neighborRoamConfig,
+ sizeof(tCsrNeighborRoamConfigParams));
+#endif
+#ifdef WLAN_FEATURE_11AC
+ pParam->nVhtChannelWidth = cfg_params->nVhtChannelWidth;
+ pParam->enableTxBF = cfg_params->txBFEnable;
+ pParam->txBFCsnValue = cfg_params->txBFCsnValue;
+ pParam->enableMuBformee = cfg_params->txMuBformee;
+ pParam->enableVhtFor24GHz = cfg_params->enableVhtFor24GHz;
+ pParam->ignore_peer_erp_info = cfg_params->ignore_peer_erp_info;
+ pParam->enable2x2 = cfg_params->enable2x2;
+#endif
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ cdf_mem_copy(&cfg_params->csr11rConfig, &pParam->csr11rConfig,
+ sizeof(tCsr11rConfigParams));
+#endif
+#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR)
+ pParam->isFastTransitionEnabled = cfg_params->isFastTransitionEnabled;
+ pParam->RoamRssiDiff = cfg_params->RoamRssiDiff;
+ pParam->nRoamPrefer5GHz = cfg_params->nRoamPrefer5GHz;
+ pParam->nRoamIntraBand = cfg_params->nRoamIntraBand;
+ pParam->isWESModeEnabled = cfg_params->isWESModeEnabled;
+ pParam->nProbes = cfg_params->nProbes;
+ pParam->nRoamScanHomeAwayTime = cfg_params->nRoamScanHomeAwayTime;
+#endif
+ pParam->isRoamOffloadScanEnabled = cfg_params->isRoamOffloadScanEnabled;
+ pParam->bFastRoamInConIniFeatureEnabled =
+ cfg_params->bFastRoamInConIniFeatureEnabled;
+#ifdef FEATURE_WLAN_LFR
+ pParam->isFastRoamIniFeatureEnabled =
+ cfg_params->isFastRoamIniFeatureEnabled;
+#endif
+#ifdef FEATURE_WLAN_ESE
+ pParam->isEseIniFeatureEnabled = cfg_params->isEseIniFeatureEnabled;
+#endif
+#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING
+ cdf_mem_copy(&pParam->neighborRoamConfig,
+ &cfg_params->neighborRoamConfig,
+ sizeof(tCsrNeighborRoamConfigParams));
+ sms_log(pMac, LOG1,
+ FL("Num of Channels in CFG Channel List: %d"),
+ cfg_params->neighborRoamConfig.
+ neighborScanChanList.numChannels);
+ for (i = 0; i < cfg_params->neighborRoamConfig.
+ neighborScanChanList.numChannels; i++) {
+ sms_log(pMac, LOG1, "%d ",
+ cfg_params->neighborRoamConfig.
+ neighborScanChanList.channelList[i]);
+ }
+#endif
+
+#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH
+ pParam->cc_switch_mode = cfg_params->cc_switch_mode;
+#endif
+ pParam->enableTxLdpc = cfg_params->txLdpcEnable;
+ pParam->isAmsduSupportInAMPDU = cfg_params->isAmsduSupportInAMPDU;
+ pParam->nSelect5GHzMargin = cfg_params->nSelect5GHzMargin;
+ pParam->isCoalesingInIBSSAllowed = cfg_params->isCoalesingInIBSSAllowed;
+ pParam->allowDFSChannelRoam = cfg_params->allowDFSChannelRoam;
+ pParam->nInitialDwellTime = cfg_params->nInitialDwellTime;
+ pParam->initial_scan_no_dfs_chnl = cfg_params->initial_scan_no_dfs_chnl;
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+ pParam->isRoamOffloadEnabled = cfg_params->isRoamOffloadEnabled;
+#endif
+ pParam->enable_dot11p = pMac->enable_dot11p;
+ csr_set_channels(pMac, pParam);
+ pParam->obssEnabled = cfg_params->obssEnabled;
+ pParam->conc_custom_rule1 = cfg_params->conc_custom_rule1;
+ pParam->conc_custom_rule2 = cfg_params->conc_custom_rule2;
+ pParam->is_sta_connection_in_5gz_enabled =
+ cfg_params->is_sta_connection_in_5gz_enabled;
+ pParam->sendDeauthBeforeCon =
+ cfg_params->sendDeauthBeforeCon;
+ pParam->max_scan_count = pMac->scan.max_scan_count;
+ return CDF_STATUS_SUCCESS;
+}
+
+CDF_STATUS csr_set_phy_mode(tHalHandle hHal, uint32_t phyMode, eCsrBand eBand,
+ bool *pfRestartNeeded)
+{
+ CDF_STATUS status = CDF_STATUS_E_INVAL;
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ bool fRestartNeeded = false;
+ eCsrPhyMode newPhyMode = eCSR_DOT11_MODE_AUTO;
+ if (eCSR_BAND_24 == eBand) {
+ if (CSR_IS_RADIO_A_ONLY(pMac))
+ goto end;
+ if (eCSR_DOT11_MODE_11a & phyMode)
+ goto end;
+ }
+ if (eCSR_BAND_5G == eBand) {
+ if (CSR_IS_RADIO_BG_ONLY(pMac))
+ goto end;
+ if ((eCSR_DOT11_MODE_11b & phyMode)
+ || (eCSR_DOT11_MODE_11b_ONLY & phyMode)
+ || (eCSR_DOT11_MODE_11g & phyMode)
+ || (eCSR_DOT11_MODE_11g_ONLY & phyMode))
+ goto end;
+ }
+ if (eCSR_DOT11_MODE_AUTO & phyMode)
+ newPhyMode = eCSR_DOT11_MODE_AUTO;
+ else {
+ /* Check for dual band and higher capability first */
+ if (eCSR_DOT11_MODE_11n_ONLY & phyMode) {
+ if (eCSR_DOT11_MODE_11n_ONLY != phyMode)
+ goto end;
+ newPhyMode = eCSR_DOT11_MODE_11n_ONLY;
+ } else if (eCSR_DOT11_MODE_11g_ONLY & phyMode) {
+ if (eCSR_DOT11_MODE_11g_ONLY != phyMode)
+ goto end;
+ if (eCSR_BAND_5G == eBand)
+ goto end;
+ newPhyMode = eCSR_DOT11_MODE_11g_ONLY;
+ eBand = eCSR_BAND_24;
+ } else if (eCSR_DOT11_MODE_11b_ONLY & phyMode) {
+ if (eCSR_DOT11_MODE_11b_ONLY != phyMode)
+ goto end;
+ if (eCSR_BAND_5G == eBand)
+ goto end;
+ newPhyMode = eCSR_DOT11_MODE_11b_ONLY;
+ eBand = eCSR_BAND_24;
+ } else if (eCSR_DOT11_MODE_11n & phyMode) {
+ newPhyMode = eCSR_DOT11_MODE_11n;
+ } else if (eCSR_DOT11_MODE_abg & phyMode) {
+ newPhyMode = eCSR_DOT11_MODE_abg;
+ } else if (eCSR_DOT11_MODE_11a & phyMode) {
+ if ((eCSR_DOT11_MODE_11g & phyMode)
+ || (eCSR_DOT11_MODE_11b & phyMode)) {
+ if (eCSR_BAND_ALL == eBand)
+ newPhyMode = eCSR_DOT11_MODE_abg;
+ else
+ goto end;
+ } else {
+ newPhyMode = eCSR_DOT11_MODE_11a;
+ eBand = eCSR_BAND_5G;
+ }
+ } else if (eCSR_DOT11_MODE_11g & phyMode) {
+ newPhyMode = eCSR_DOT11_MODE_11g;
+ eBand = eCSR_BAND_24;
+ } else if (eCSR_DOT11_MODE_11b & phyMode) {
+ newPhyMode = eCSR_DOT11_MODE_11b;
+ eBand = eCSR_BAND_24;
+ } else {
+ /* We will never be here */
+ sms_log(pMac, LOGE,
+ FL("can't recognize phymode 0x%08X"),
+ phyMode);
+ newPhyMode = eCSR_DOT11_MODE_AUTO;
+ }
+ }
+ /* Done validating */
+ status = CDF_STATUS_SUCCESS;
+ /* Now we need to check whether a restart is needed. */
+ if (eBand != pMac->roam.configParam.eBand) {
+ fRestartNeeded = true;
+ goto end;
+ }
+ if (newPhyMode != pMac->roam.configParam.phyMode) {
+ fRestartNeeded = true;
+ goto end;
+ }
+end:
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ pMac->roam.configParam.eBand = eBand;
+ pMac->roam.configParam.phyMode = newPhyMode;
+ if (pfRestartNeeded)
+ *pfRestartNeeded = fRestartNeeded;
+ }
+ return status;
+}
+
+/**
+ * csr_prune_ch_list() - prunes the channel list to keep only a type of channels
+ * @ch_lst: existing channel list
+ * @is_24_GHz: indicates if 2.5 GHz or 5 GHz channels are required
+ *
+ * Return: void
+ */
+void csr_prune_ch_list(tCsrChannel *ch_lst, bool is_24_GHz)
+{
+ uint8_t idx = 0, num_channels = 0;
+ for ( ; idx < ch_lst->numChannels; idx++) {
+ if (is_24_GHz) {
+ if (CDS_IS_CHANNEL_24GHZ(ch_lst->channelList[idx])) {
+ ch_lst->channelList[num_channels] =
+ ch_lst->channelList[idx];
+ num_channels++;
+ }
+ } else {
+ if (CDS_IS_CHANNEL_5GHZ(ch_lst->channelList[idx])) {
+ ch_lst->channelList[num_channels] =
+ ch_lst->channelList[idx];
+ num_channels++;
+ }
+ }
+ }
+ /*
+ * Cleanup the rest of channels. Note we only need to clean up the
+ * channels if we had to trim the list. Calling cdf_mem_set() with a 0
+ * size is going to throw asserts on the debug builds so let's be a bit
+ * smarter about that. Zero out the reset of the channels only if we
+ * need to. The amount of memory to clear is the number of channesl that
+ * we trimmed (ch_lst->numChannels - num_channels) times the size of a
+ * channel in the structure.
+ */
+ if (ch_lst->numChannels > num_channels) {
+ cdf_mem_set(&ch_lst->channelList[num_channels],
+ sizeof(ch_lst->channelList[0]) *
+ (ch_lst->numChannels - num_channels), 0);
+ }
+ ch_lst->numChannels = num_channels;
+}
+
+/**
+ * csr_prune_channel_list_for_mode() - prunes the channel list
+ * @mac_ctx: global mac context
+ * @ch_lst: existing channel list
+ *
+ * Prunes the channel list according to band stored in mac_ctx
+ *
+ * Return: void
+ */
+void csr_prune_channel_list_for_mode(tpAniSirGlobal mac_ctx,
+ tCsrChannel *ch_lst)
+{
+ /* for dual band NICs, don't need to trim the channel list.... */
+ if (CSR_IS_OPEARTING_DUAL_BAND(mac_ctx))
+ return;
+ /*
+ * 2.4 GHz band operation requires the channel list to be trimmed to
+ * the 2.4 GHz channels only
+ */
+ if (CSR_IS_24_BAND_ONLY(mac_ctx))
+ csr_prune_ch_list(ch_lst, true);
+ else if (CSR_IS_5G_BAND_ONLY(mac_ctx))
+ csr_prune_ch_list(ch_lst, false);
+}
+
+#define INFRA_AP_DEFAULT_CHANNEL 6
+CDF_STATUS csr_is_valid_channel(tpAniSirGlobal pMac, uint8_t chnNum)
+{
+ uint8_t index = 0;
+ CDF_STATUS status = CDF_STATUS_E_NOSUPPORT;
+
+ /* regulatory check */
+ for (index = 0; index < pMac->scan.base_channels.numChannels;
+ index++) {
+ if (pMac->scan.base_channels.channelList[index] == chnNum) {
+ status = CDF_STATUS_SUCCESS;
+ break;
+ }
+ }
+
+ if (status == CDF_STATUS_SUCCESS) {
+ /* dfs nol */
+ for (index = 0;
+ index <
+ pMac->sap.SapDfsInfo.numCurrentRegDomainDfsChannels;
+ index++) {
+ tSapDfsNolInfo *dfsChan =
+ &pMac->sap.SapDfsInfo.sapDfsChannelNolList[index];
+ if ((dfsChan->dfs_channel_number == chnNum)
+ && (dfsChan->radar_status_flag ==
+ eSAP_DFS_CHANNEL_UNAVAILABLE)) {
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_ERROR,
+ FL("channel %d is in dfs nol"),
+ chnNum);
+ status = CDF_STATUS_E_FAILURE;
+ break;
+ }
+ }
+ }
+
+ if (CDF_STATUS_SUCCESS != status) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ FL("channel %d is not available"), chnNum);
+ }
+
+ return status;
+}
+
+CDF_STATUS csr_get_channel_and_power_list(tpAniSirGlobal pMac)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ uint8_t num20MHzChannelsFound = 0;
+ CDF_STATUS cdf_status;
+ uint8_t Index = 0;
+ uint8_t num40MHzChannelsFound = 0;
+
+ /* TODO: this interface changed to include the 40MHz channel list */
+ /* this needs to be tied into the adapter structure somehow and referenced appropriately for CB operation */
+ /* Read the scan channel list (including the power limit) from EEPROM */
+ cdf_status =
+ cds_get_channel_list_with_power(pMac->scan.defaultPowerTable,
+ &num20MHzChannelsFound,
+ pMac->scan.defaultPowerTable40MHz,
+ &num40MHzChannelsFound);
+ if ((CDF_STATUS_SUCCESS != cdf_status) || (num20MHzChannelsFound == 0)) {
+ sms_log(pMac, LOGE, FL("failed to get channels "));
+ status = CDF_STATUS_E_FAILURE;
+ } else {
+ if (num20MHzChannelsFound > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
+ num20MHzChannelsFound = WNI_CFG_VALID_CHANNEL_LIST_LEN;
+ }
+ pMac->scan.numChannelsDefault = num20MHzChannelsFound;
+ /* Move the channel list to the global data */
+ /* structure -- this will be used as the scan list */
+ for (Index = 0; Index < num20MHzChannelsFound; Index++) {
+ pMac->scan.base_channels.channelList[Index] =
+ pMac->scan.defaultPowerTable[Index].chanId;
+ }
+ pMac->scan.base_channels.numChannels =
+ num20MHzChannelsFound;
+ if (num40MHzChannelsFound > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
+ num40MHzChannelsFound = WNI_CFG_VALID_CHANNEL_LIST_LEN;
+ }
+ for (Index = 0; Index < num40MHzChannelsFound; Index++) {
+ pMac->scan.base40MHzChannels.channelList[Index] =
+ pMac->scan.defaultPowerTable40MHz[Index].chanId;
+ }
+ pMac->scan.base40MHzChannels.numChannels =
+ num40MHzChannelsFound;
+ }
+ return status;
+}
+
+CDF_STATUS csr_apply_channel_and_power_list(tpAniSirGlobal pMac)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+
+ 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 base channel list, power info, and set the Country code... */
+ csr_apply_channel_power_info_to_fw(pMac,
+ &pMac->scan.base_channels,
+ pMac->scan.countryCodeCurrent);
+
+ csr_init_operating_classes((tHalHandle) pMac);
+ return status;
+}
+
+CDF_STATUS csr_change_config_params(tpAniSirGlobal pMac,
+ tCsrUpdateConfigParam *pUpdateConfigParam)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ tCsr11dinfo *ps11dinfo = NULL;
+ ps11dinfo = &pUpdateConfigParam->Csr11dinfo;
+ status = csr_init11d_info(pMac, ps11dinfo);
+ return status;
+}
+
+static CDF_STATUS csr_init11d_info(tpAniSirGlobal pMac, tCsr11dinfo *ps11dinfo)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ uint8_t index;
+ uint32_t count = 0;
+ tSirMacChanInfo *pChanInfo;
+ tSirMacChanInfo *pChanInfoStart;
+ bool applyConfig = true;
+
+ pMac->scan.currentCountryRSSI = -128;
+ if (!ps11dinfo) {
+ return status;
+ }
+ if (ps11dinfo->Channels.numChannels
+ && (WNI_CFG_VALID_CHANNEL_LIST_LEN >=
+ ps11dinfo->Channels.numChannels)) {
+ pMac->scan.base_channels.numChannels =
+ ps11dinfo->Channels.numChannels;
+ cdf_mem_copy(pMac->scan.base_channels.channelList,
+ ps11dinfo->Channels.channelList,
+ ps11dinfo->Channels.numChannels);
+ } else {
+ /* No change */
+ return CDF_STATUS_SUCCESS;
+ }
+ /* legacy maintenance */
+
+ cdf_mem_copy(pMac->scan.countryCodeDefault, ps11dinfo->countryCode,
+ WNI_CFG_COUNTRY_CODE_LEN);
+
+ /* Tush: at csropen get this initialized with default, during csr reset if this */
+ /* already set with some value no need initilaize with default again */
+ if (0 == pMac->scan.countryCodeCurrent[0]) {
+ cdf_mem_copy(pMac->scan.countryCodeCurrent,
+ ps11dinfo->countryCode, WNI_CFG_COUNTRY_CODE_LEN);
+ }
+ /* need to add the max power channel list */
+ pChanInfo =
+ cdf_mem_malloc(sizeof(tSirMacChanInfo) *
+ WNI_CFG_VALID_CHANNEL_LIST_LEN);
+ if (pChanInfo != NULL) {
+ cdf_mem_set(pChanInfo,
+ sizeof(tSirMacChanInfo) *
+ WNI_CFG_VALID_CHANNEL_LIST_LEN, 0);
+
+ pChanInfoStart = pChanInfo;
+ for (index = 0; index < ps11dinfo->Channels.numChannels;
+ index++) {
+ pChanInfo->firstChanNum =
+ ps11dinfo->ChnPower[index].firstChannel;
+ pChanInfo->numChannels =
+ ps11dinfo->ChnPower[index].numChannels;
+ pChanInfo->maxTxPower =
+ CDF_MIN(ps11dinfo->ChnPower[index].maxtxPower,
+ pMac->roam.configParam.nTxPowerCap);
+ pChanInfo++;
+ count++;
+ }
+ if (count) {
+ csr_save_to_channel_power2_g_5_g(pMac,
+ count *
+ sizeof(tSirMacChanInfo),
+ pChanInfoStart);
+ }
+ cdf_mem_free(pChanInfoStart);
+ }
+ /* Only apply them to CFG when not in STOP state. Otherwise they will be applied later */
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ for (index = 0; index < CSR_ROAM_SESSION_MAX; index++) {
+ if ((CSR_IS_SESSION_VALID(pMac, index))
+ && CSR_IS_ROAM_STOP(pMac, index)) {
+ applyConfig = false;
+ }
+ }
+
+ if (true == applyConfig) {
+ /* Apply the base channel list, power info, and set the Country code... */
+ csr_apply_channel_power_info_to_fw(pMac,
+ &pMac->scan.
+ base_channels,
+ pMac->scan.
+ countryCodeCurrent);
+ }
+ }
+ return status;
+}
+
+/* Initialize the Channel + Power List in the local cache and in the CFG */
+CDF_STATUS csr_init_channel_power_list(tpAniSirGlobal pMac, tCsr11dinfo *ps11dinfo)
+{
+ uint8_t index;
+ uint32_t count = 0;
+ tSirMacChanInfo *pChanInfo;
+ tSirMacChanInfo *pChanInfoStart;
+
+ if (!ps11dinfo || !pMac) {
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ pChanInfo =
+ cdf_mem_malloc(sizeof(tSirMacChanInfo) *
+ WNI_CFG_VALID_CHANNEL_LIST_LEN);
+ if (pChanInfo != NULL) {
+ cdf_mem_set(pChanInfo,
+ sizeof(tSirMacChanInfo) *
+ WNI_CFG_VALID_CHANNEL_LIST_LEN, 0);
+ pChanInfoStart = pChanInfo;
+
+ for (index = 0; index < ps11dinfo->Channels.numChannels;
+ index++) {
+ pChanInfo->firstChanNum =
+ ps11dinfo->ChnPower[index].firstChannel;
+ pChanInfo->numChannels =
+ ps11dinfo->ChnPower[index].numChannels;
+ pChanInfo->maxTxPower =
+ CDF_MIN(ps11dinfo->ChnPower[index].maxtxPower,
+ pMac->roam.configParam.nTxPowerCap);
+ pChanInfo++;
+ count++;
+ }
+ if (count) {
+ csr_save_to_channel_power2_g_5_g(pMac,
+ count *
+ sizeof(tSirMacChanInfo),
+ pChanInfoStart);
+ }
+ cdf_mem_free(pChanInfoStart);
+ }
+
+ return CDF_STATUS_SUCCESS;
+}
+
+/* pCommand may be NULL */
+/* Pass in sessionId in case pCommand is NULL. sessionId is not used in case pCommand is not NULL. */
+void csr_roam_remove_duplicate_command(tpAniSirGlobal pMac, uint32_t sessionId,
+ tSmeCmd *pCommand,
+ eCsrRoamReason eRoamReason)
+{
+ tListElem *pEntry, *pNextEntry;
+ tSmeCmd *pDupCommand;
+ tDblLinkList localList;
+
+ 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(&pMac->sme.smeCmdPendingList);
+ pEntry = csr_ll_peek_head(&pMac->sme.smeCmdPendingList, LL_ACCESS_NOLOCK);
+ while (pEntry) {
+ pNextEntry =
+ csr_ll_next(&pMac->sme.smeCmdPendingList, pEntry,
+ LL_ACCESS_NOLOCK);
+ pDupCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
+ /* Remove the previous command if.. */
+ /* - the new roam command is for the same RoamReason... */
+ /* - the new roam command is a NewProfileList. */
+ /* - the new roam command is a Forced Dissoc */
+ /* - the new roam command is from an 802.11 OID (OID_SSID or OID_BSSID). */
+ if ((pCommand && (pCommand->sessionId == pDupCommand->sessionId)
+ && ((pCommand->command == pDupCommand->command) &&
+ /*
+ * This peermac check is requried for Softap/GO
+ * scenarios. For STA scenario below OR check will
+ * suffice as pCommand will always be NULL for STA
+ * scenarios
+ */
+ (cdf_mem_compare
+ (pDupCommand->u.roamCmd.peerMac,
+ pCommand->u.roamCmd.peerMac,
+ CDF_MAC_ADDR_SIZE))
+ && (pCommand->u.roamCmd.roamReason ==
+ pDupCommand->u.roamCmd.roamReason
+ || eCsrForcedDisassoc ==
+ pCommand->u.roamCmd.roamReason
+ || eCsrHddIssued ==
+ pCommand->u.roamCmd.roamReason)))
+ ||
+ /* below the pCommand is NULL */
+ ((sessionId == pDupCommand->sessionId) &&
+ (eSmeCommandRoam == pDupCommand->command) &&
+ ((eCsrForcedDisassoc == eRoamReason) ||
+ (eCsrHddIssued == eRoamReason))
+ )
+ ) {
+ sms_log(pMac, LOGW, FL(" roamReason = %d"),
+ pDupCommand->u.roamCmd.roamReason);
+ /* Remove the 'stale' roam command from the pending list... */
+ if (csr_ll_remove_entry
+ (&pMac->sme.smeCmdPendingList, pEntry,
+ LL_ACCESS_NOLOCK)) {
+ csr_ll_insert_tail(&localList, pEntry,
+ LL_ACCESS_NOLOCK);
+ }
+ }
+ pEntry = pNextEntry;
+ }
+ csr_ll_unlock(&pMac->sme.smeCmdPendingList);
+
+ while ((pEntry = csr_ll_remove_head(&localList, LL_ACCESS_NOLOCK))) {
+ pDupCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
+ /* Tell caller that the command is cancelled */
+ csr_roam_call_callback(pMac, pDupCommand->sessionId, NULL,
+ pDupCommand->u.roamCmd.roamId,
+ eCSR_ROAM_CANCELLED, eCSR_ROAM_RESULT_NONE);
+ csr_release_command_roam(pMac, pDupCommand);
+ }
+ csr_ll_close(&localList);
+}
+
+/**
+ * csr_roam_populate_channels() - Helper function to populate channels
+ * @beacon_ies: pointer to beacon ie
+ * @roam_info: Roaming related information
+ * @chan1: center freq 1
+ * @chan2: center freq2
+ *
+ * This function will issue populate chan1 and chan2 based on beacon ie
+ *
+ * Return: none.
+ */
+static void csr_roam_populate_channels(tDot11fBeaconIEs *beacon_ies,
+ tCsrRoamInfo *roam_info,
+ uint8_t *chan1, uint8_t *chan2)
+{
+ ePhyChanBondState phy_state;
+ if (beacon_ies->VHTOperation.present) {
+ *chan1 = beacon_ies->VHTOperation.chanCenterFreqSeg1;
+ *chan2 = beacon_ies->VHTOperation.chanCenterFreqSeg2;
+ roam_info->chan_info.info = MODE_11AC_VHT80;
+ } else if (beacon_ies->HTInfo.present) {
+ if (beacon_ies->HTInfo.recommendedTxWidthSet ==
+ eHT_CHANNEL_WIDTH_40MHZ) {
+ phy_state = beacon_ies->HTInfo.secondaryChannelOffset;
+ if (phy_state == PHY_DOUBLE_CHANNEL_LOW_PRIMARY)
+ *chan1 = beacon_ies->HTInfo.primaryChannel +
+ CSR_CB_CENTER_CHANNEL_OFFSET;
+ else if (phy_state == PHY_DOUBLE_CHANNEL_HIGH_PRIMARY)
+ *chan1 = beacon_ies->HTInfo.primaryChannel -
+ CSR_CB_CENTER_CHANNEL_OFFSET;
+ else
+ *chan1 = beacon_ies->HTInfo.primaryChannel;
+
+ roam_info->chan_info.info = MODE_11NA_HT40;
+ } else {
+ *chan1 = beacon_ies->HTInfo.primaryChannel;
+ roam_info->chan_info.info = MODE_11NA_HT20;
+ }
+ *chan2 = 0;
+ } else {
+ *chan1 = 0;
+ *chan2 = 0;
+ roam_info->chan_info.info = MODE_11A;
+ }
+}
+
+CDF_STATUS csr_roam_call_callback(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamInfo *pRoamInfo, uint32_t roamId,
+ eRoamCmdStatus u1, eCsrRoamResult u2)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+ uint32_t rssi = 0;
+ WLAN_HOST_DIAG_EVENT_DEF(connectionStatus,
+ host_event_wlan_status_payload_type);
+#endif
+ tCsrRoamSession *pSession;
+ tDot11fBeaconIEs *beacon_ies = NULL;
+ uint8_t chan1, chan2;
+
+ if (!CSR_IS_SESSION_VALID(pMac, sessionId)) {
+ sms_log(pMac, LOGE, "Session ID:%d is not valid", sessionId);
+ CDF_ASSERT(0);
+ return CDF_STATUS_E_FAILURE;
+ }
+ pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (false == pSession->sessionActive) {
+ sms_log(pMac, LOG1, "%s Session is not Active", __func__);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ sms_log(pMac, LOG4, "Received RoamCmdStatus %d with Roam Result %d", u1,
+ u2);
+
+ if (eCSR_ROAM_ASSOCIATION_COMPLETION == u1 &&
+ eCSR_ROAM_RESULT_ASSOCIATED == u2 && pRoamInfo) {
+ sms_log(pMac, LOGW,
+ FL("Assoc complete result=%d status=%d reason=%d"),
+ u2, pRoamInfo->statusCode, pRoamInfo->reasonCode);
+ beacon_ies = cdf_mem_malloc(sizeof(tDot11fBeaconIEs));
+ if ((NULL != beacon_ies) && (NULL != pRoamInfo->pBssDesc)) {
+ status = csr_parse_bss_description_ies(
+ (tHalHandle) pMac, pRoamInfo->pBssDesc,
+ beacon_ies);
+ csr_roam_populate_channels(beacon_ies, pRoamInfo,
+ &chan1, &chan2);
+ if (0 != chan1)
+ pRoamInfo->chan_info.band_center_freq1 =
+ cds_chan_to_freq(chan1);
+ else
+ pRoamInfo->chan_info.band_center_freq1 = 0;
+ if (0 != chan2)
+ pRoamInfo->chan_info.band_center_freq2 =
+ cds_chan_to_freq(chan2);
+ else
+ pRoamInfo->chan_info.band_center_freq2 = 0;
+ } else {
+ pRoamInfo->chan_info.band_center_freq1 = 0;
+ pRoamInfo->chan_info.band_center_freq2 = 0;
+ pRoamInfo->chan_info.info = 0;
+ }
+ pRoamInfo->chan_info.chan_id =
+ pRoamInfo->u.pConnectedProfile->operationChannel;
+ pRoamInfo->chan_info.mhz =
+ cds_chan_to_freq(pRoamInfo->chan_info.chan_id);
+ pRoamInfo->chan_info.reg_info_1 =
+ (csr_get_cfg_max_tx_power(pMac,
+ pRoamInfo->chan_info.chan_id) << 16);
+ pRoamInfo->chan_info.reg_info_2 =
+ (csr_get_cfg_max_tx_power(pMac,
+ pRoamInfo->chan_info.chan_id) << 8);
+ cdf_mem_free(beacon_ies);
+ } else if ((u1 == eCSR_ROAM_FT_REASSOC_FAILED)
+ && (pSession->bRefAssocStartCnt)) {
+ /*
+ * Decrement bRefAssocStartCnt for FT reassoc failure.
+ * Reason: For FT reassoc failures, we first call
+ * csr_roam_call_callback before notifying a failed roam
+ * completion through csr_roam_complete. The latter in
+ * turn calls csr_roam_process_results which tries to
+ * once again call csr_roam_call_callback if bRefAssocStartCnt
+ * is non-zero. Since this is redundant for FT reassoc
+ * failure, decrement bRefAssocStartCnt.
+ */
+ pSession->bRefAssocStartCnt--;
+ } else if (u1 == eCSR_ROAM_SET_CHANNEL_RSP && u2 ==
+ eCSR_ROAM_RESULT_CHANNEL_CHANGE_SUCCESS)
+ pSession->connectedProfile.operationChannel =
+ pRoamInfo->channelChangeRespEvent->newChannelNumber;
+
+ if (NULL != pSession->callback) {
+ if (pRoamInfo) {
+ pRoamInfo->sessionId = (uint8_t) sessionId;
+ /*
+ * the reasonCode will be passed to supplicant by
+ * cfg80211_disconnected. Based on the document,
+ * the reason code passed to supplicant needs to set
+ * to 0 if unknow. eSIR_BEACON_MISSED reason code is not
+ * recognizable so that we set to 0 instead.
+ */
+ pRoamInfo->reasonCode =
+ (pRoamInfo->reasonCode == eSIR_BEACON_MISSED) ?
+ 0 : pRoamInfo->reasonCode;
+ }
+ status = pSession->callback(pSession->pContext, pRoamInfo,
+ roamId, u1, u2);
+ }
+ /*
+ * EVENT_WLAN_STATUS: eCSR_ROAM_ASSOCIATION_COMPLETION,
+ * eCSR_ROAM_LOSTLINK,
+ * eCSR_ROAM_DISASSOCIATED,
+ */
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+ cdf_mem_set(&connectionStatus,
+ sizeof(host_event_wlan_status_payload_type), 0);
+
+ if ((eCSR_ROAM_ASSOCIATION_COMPLETION == u1)
+ && (eCSR_ROAM_RESULT_ASSOCIATED == u2) && pRoamInfo) {
+ connectionStatus.eventId = eCSR_WLAN_STATUS_CONNECT;
+ connectionStatus.bssType =
+ pRoamInfo->u.pConnectedProfile->BSSType;
+
+ if (NULL != pRoamInfo->pBssDesc) {
+ connectionStatus.rssi =
+ pRoamInfo->pBssDesc->rssi * (-1);
+ connectionStatus.channel =
+ pRoamInfo->pBssDesc->channelId;
+ }
+ if (cfg_set_int(pMac, WNI_CFG_CURRENT_RSSI,
+ connectionStatus.rssi) == eSIR_FAILURE)
+ sms_log(pMac, LOGE,
+ FL("Can't pass WNI_CFG_CURRENT_RSSI to cfg"));
+
+ connectionStatus.qosCapability =
+ pRoamInfo->u.pConnectedProfile->qosConnection;
+ connectionStatus.authType =
+ (uint8_t) diag_auth_type_from_csr_type(
+ pRoamInfo->u.pConnectedProfile->AuthType);
+ connectionStatus.encryptionType =
+ (uint8_t) diag_enc_type_from_csr_type(
+ pRoamInfo->u.pConnectedProfile->EncryptionType);
+ cdf_mem_copy(connectionStatus.ssid,
+ pRoamInfo->u.pConnectedProfile->SSID.ssId, 6);
+
+ connectionStatus.reason = eCSR_REASON_UNSPECIFIED;
+ cdf_mem_copy(&pMac->sme.eventPayload, &connectionStatus,
+ sizeof(host_event_wlan_status_payload_type));
+ WLAN_HOST_DIAG_EVENT_REPORT(&connectionStatus,
+ EVENT_WLAN_STATUS);
+ }
+ if ((eCSR_ROAM_MIC_ERROR_IND == u1)
+ || (eCSR_ROAM_RESULT_MIC_FAILURE == u2)) {
+ cdf_mem_copy(&connectionStatus, &pMac->sme.eventPayload,
+ sizeof(host_event_wlan_status_payload_type));
+ if (IS_SIR_STATUS_SUCCESS(wlan_cfg_get_int(pMac,
+ WNI_CFG_CURRENT_RSSI, &rssi)))
+ connectionStatus.rssi = rssi;
+
+ connectionStatus.eventId = eCSR_WLAN_STATUS_DISCONNECT;
+ connectionStatus.reason = eCSR_REASON_MIC_ERROR;
+ WLAN_HOST_DIAG_EVENT_REPORT(&connectionStatus,
+ EVENT_WLAN_STATUS);
+ }
+ if (eCSR_ROAM_RESULT_FORCED == u2) {
+ cdf_mem_copy(&connectionStatus, &pMac->sme.eventPayload,
+ sizeof(host_event_wlan_status_payload_type));
+ if (IS_SIR_STATUS_SUCCESS(wlan_cfg_get_int(pMac,
+ WNI_CFG_CURRENT_RSSI, &rssi)))
+ connectionStatus.rssi = rssi;
+
+ connectionStatus.eventId = eCSR_WLAN_STATUS_DISCONNECT;
+ connectionStatus.reason = eCSR_REASON_USER_REQUESTED;
+ WLAN_HOST_DIAG_EVENT_REPORT(&connectionStatus,
+ EVENT_WLAN_STATUS);
+ }
+ if (eCSR_ROAM_RESULT_DISASSOC_IND == u2) {
+ cdf_mem_copy(&connectionStatus, &pMac->sme.eventPayload,
+ sizeof(host_event_wlan_status_payload_type));
+ if (IS_SIR_STATUS_SUCCESS(wlan_cfg_get_int(pMac,
+ WNI_CFG_CURRENT_RSSI, &rssi)))
+ connectionStatus.rssi = rssi;
+
+ connectionStatus.eventId = eCSR_WLAN_STATUS_DISCONNECT;
+ connectionStatus.reason = eCSR_REASON_DISASSOC;
+ if (pRoamInfo)
+ connectionStatus.reasonDisconnect =
+ pRoamInfo->reasonCode;
+
+ WLAN_HOST_DIAG_EVENT_REPORT(&connectionStatus,
+ EVENT_WLAN_STATUS);
+ }
+ if (eCSR_ROAM_RESULT_DEAUTH_IND == u2) {
+ cdf_mem_copy(&connectionStatus, &pMac->sme.eventPayload,
+ sizeof(host_event_wlan_status_payload_type));
+ if (IS_SIR_STATUS_SUCCESS(wlan_cfg_get_int(pMac,
+ WNI_CFG_CURRENT_RSSI, &rssi)))
+ connectionStatus.rssi = rssi;
+
+ connectionStatus.eventId = eCSR_WLAN_STATUS_DISCONNECT;
+ connectionStatus.reason = eCSR_REASON_DEAUTH;
+ if (pRoamInfo)
+ connectionStatus.reasonDisconnect =
+ pRoamInfo->reasonCode;
+ WLAN_HOST_DIAG_EVENT_REPORT(&connectionStatus,
+ EVENT_WLAN_STATUS);
+ }
+#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */
+ return status;
+}
+
+/* Returns whether handoff is currently in progress or not */
+bool csr_roam_is_handoff_in_progress(tpAniSirGlobal pMac, uint8_t sessionId)
+{
+#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING
+ return csr_neighbor_roam_is_handoff_in_progress(pMac, sessionId);
+#else
+ return false;
+#endif
+}
+
+CDF_STATUS csr_roam_issue_disassociate(tpAniSirGlobal pMac, uint32_t sessionId,
+ eCsrRoamSubState NewSubstate,
+ bool fMICFailure)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ struct cdf_mac_addr bssId = CDF_MAC_ADDR_BROADCAST_INITIALIZER;
+ uint16_t reasonCode;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ if (fMICFailure) {
+ reasonCode = eSIR_MAC_MIC_FAILURE_REASON;
+ } else if (NewSubstate == eCSR_ROAM_SUBSTATE_DISASSOC_HANDOFF) {
+ reasonCode = eSIR_MAC_DISASSOC_DUE_TO_FTHANDOFF_REASON;
+ } else if (eCSR_ROAM_SUBSTATE_DISASSOC_STA_HAS_LEFT == NewSubstate) {
+ reasonCode = eSIR_MAC_DISASSOC_LEAVING_BSS_REASON;
+ NewSubstate = eCSR_ROAM_SUBSTATE_DISASSOC_FORCED;
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ FL
+ ("set to reason code eSIR_MAC_DISASSOC_LEAVING_BSS_REASON"
+ " and set back NewSubstate"));
+ } else {
+ reasonCode = eSIR_MAC_UNSPEC_FAILURE_REASON;
+ }
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ if ((csr_roam_is_handoff_in_progress(pMac, sessionId)) &&
+ (NewSubstate != eCSR_ROAM_SUBSTATE_DISASSOC_HANDOFF)) {
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+ cdf_copy_macaddr(&bssId,
+ pNeighborRoamInfo->csrNeighborRoamProfile.BSSIDs.
+ bssid);
+ } else
+#endif
+ if (pSession->pConnectBssDesc) {
+ cdf_mem_copy(&bssId.bytes, pSession->pConnectBssDesc->bssId,
+ sizeof(struct cdf_mac_addr));
+ }
+
+ sms_log(pMac, LOG2,
+ FL("CSR Attempting to Disassociate Bssid=" MAC_ADDRESS_STR
+ " subState = %s reason=%d"), MAC_ADDR_ARRAY(bssId.bytes),
+ mac_trace_getcsr_roam_sub_state(NewSubstate), reasonCode);
+
+ csr_roam_substate_change(pMac, NewSubstate, sessionId);
+
+ status = csr_send_mb_disassoc_req_msg(pMac, sessionId, bssId.bytes,
+ reasonCode);
+
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ csr_roam_link_down(pMac, sessionId);
+#ifndef WLAN_MDM_CODE_REDUCTION_OPT
+ /* no need to tell QoS that we are disassociating, it will be taken care off in assoc req for HO */
+ if (eCSR_ROAM_SUBSTATE_DISASSOC_HANDOFF != NewSubstate) {
+ /* notify QoS module that disassoc happening */
+ sme_qos_csr_event_ind(pMac, (uint8_t) sessionId,
+ SME_QOS_CSR_DISCONNECT_REQ, NULL);
+ }
+#endif
+ } else {
+ sms_log(pMac, LOGW,
+ FL("csr_send_mb_disassoc_req_msg failed with status %d"),
+ status);
+ }
+
+ return status;
+}
+
+/* ---------------------------------------------------------------------------
+ \fn csr_roam_issue_disassociate_sta_cmd
+ \brief csr function that HDD calls to disassociate a associated station
+ \param sessionId - session Id for Soft AP
+ \param pPeerMacAddr - MAC of associated station to delete
+ \param reason - reason code, be one of the tSirMacReasonCodes
+ \return CDF_STATUS
+ ---------------------------------------------------------------------------*/
+CDF_STATUS csr_roam_issue_disassociate_sta_cmd(tpAniSirGlobal pMac,
+ uint32_t sessionId,
+ const uint8_t *pPeerMacAddr,
+ uint32_t reason)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSmeCmd *pCommand;
+
+ do {
+ pCommand = csr_get_command_buffer(pMac);
+ if (!pCommand) {
+ sms_log(pMac, LOGE, FL(" fail to get command buffer"));
+ status = CDF_STATUS_E_RESOURCES;
+ break;
+ }
+ pCommand->command = eSmeCommandRoam;
+ pCommand->sessionId = (uint8_t) sessionId;
+ pCommand->u.roamCmd.roamReason = eCsrForcedDisassocSta;
+ cdf_mem_copy(pCommand->u.roamCmd.peerMac, pPeerMacAddr, 6);
+ pCommand->u.roamCmd.reason = (tSirMacReasonCodes) reason;
+ status = csr_queue_sme_command(pMac, pCommand, false);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ FL(" fail to send message status = %d"), status);
+ csr_release_command_roam(pMac, pCommand);
+ }
+ } while (0);
+
+ return status;
+}
+
+/**
+ * csr_roam_issue_deauthSta() - delete a associated station
+ * @sessionId: Session Id for Soft AP
+ * @pDelStaParams: Pointer to parameters of the station to deauthenticate
+ *
+ * CSR function that HDD calls to delete a associated station
+ *
+ * Return: CDF_STATUS_SUCCESS on success or another CDF_STATUS_* on error
+ */
+CDF_STATUS csr_roam_issue_deauth_sta_cmd(tpAniSirGlobal pMac,
+ uint32_t sessionId,
+ struct tagCsrDelStaParams *pDelStaParams)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSmeCmd *pCommand;
+
+ do {
+ pCommand = csr_get_command_buffer(pMac);
+ if (!pCommand) {
+ sms_log(pMac, LOGE, FL(" fail to get command buffer"));
+ status = CDF_STATUS_E_RESOURCES;
+ break;
+ }
+ pCommand->command = eSmeCommandRoam;
+ pCommand->sessionId = (uint8_t) sessionId;
+ pCommand->u.roamCmd.roamReason = eCsrForcedDeauthSta;
+ cdf_mem_copy(pCommand->u.roamCmd.peerMac,
+ pDelStaParams->peerMacAddr.bytes,
+ sizeof(tSirMacAddr));
+ pCommand->u.roamCmd.reason =
+ (tSirMacReasonCodes)pDelStaParams->reason_code;
+ status = csr_queue_sme_command(pMac, pCommand, false);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ FL(" fail to send message status = %d"), status);
+ csr_release_command_roam(pMac, pCommand);
+ }
+ } while (0);
+
+ return status;
+}
+
+CDF_STATUS
+csr_roam_issue_tkip_counter_measures(tpAniSirGlobal pMac, uint32_t sessionId,
+ bool bEnable)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ struct cdf_mac_addr bssId = CDF_MAC_ADDR_BROADCAST_INITIALIZER;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+ if (!pSession) {
+ sms_log(pMac, LOGE,
+ "csr_roam_issue_tkip_counter_measures:CSR Session not found");
+ return status;
+ }
+ if (pSession->pConnectBssDesc) {
+ cdf_mem_copy(bssId.bytes, pSession->pConnectBssDesc->bssId,
+ sizeof(struct cdf_mac_addr));
+ } else {
+ sms_log(pMac, LOGE,
+ "csr_roam_issue_tkip_counter_measures:Connected BSS Description in CSR Session not found");
+ return status;
+ }
+ sms_log(pMac, LOG2,
+ "CSR issuing tkip counter measures for Bssid = " MAC_ADDRESS_STR
+ ", Enable = %d", MAC_ADDR_ARRAY(bssId.bytes), bEnable);
+ status =
+ csr_send_mb_tkip_counter_measures_req_msg(pMac, sessionId,
+ bEnable, bssId.bytes);
+ return status;
+}
+
+CDF_STATUS
+csr_roam_get_associated_stas(tpAniSirGlobal pMac, uint32_t sessionId,
+ CDF_MODULE_ID modId, void *pUsrContext,
+ void *pfnSapEventCallback, uint8_t *pAssocStasBuf)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ struct cdf_mac_addr bssId = CDF_MAC_ADDR_BROADCAST_INITIALIZER;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+ if (!pSession) {
+ sms_log(pMac, LOGE,
+ "csr_roam_get_associated_stas:CSR Session not found");
+ return status;
+ }
+ if (pSession->pConnectBssDesc) {
+ cdf_mem_copy(bssId.bytes, pSession->pConnectBssDesc->bssId,
+ sizeof(struct cdf_mac_addr));
+ } else {
+ sms_log(pMac, LOGE,
+ "csr_roam_get_associated_stas:Connected BSS Description in CSR Session not found");
+ return status;
+ }
+ sms_log(pMac, LOG2,
+ "CSR getting associated stations for Bssid = " MAC_ADDRESS_STR,
+ MAC_ADDR_ARRAY(bssId.bytes));
+ status =
+ csr_send_mb_get_associated_stas_req_msg(pMac, sessionId, modId,
+ bssId.bytes,
+ pUsrContext,
+ pfnSapEventCallback,
+ pAssocStasBuf);
+ return status;
+}
+
+CDF_STATUS
+csr_roam_get_wps_session_overlap(tpAniSirGlobal pMac, uint32_t sessionId,
+ void *pUsrContext, void *pfnSapEventCallback,
+ struct cdf_mac_addr pRemoveMac)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ struct cdf_mac_addr bssId = CDF_MAC_ADDR_BROADCAST_INITIALIZER;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE,
+ "csr_roam_get_wps_session_overlap:CSR Session not found");
+ return status;
+ }
+ if (pSession->pConnectBssDesc) {
+ cdf_mem_copy(bssId.bytes, pSession->pConnectBssDesc->bssId,
+ sizeof(struct cdf_mac_addr));
+ } else {
+ sms_log(pMac, LOGE,
+ "csr_roam_get_wps_session_overlap:Connected BSS Description in CSR Session not found");
+ return status;
+ }
+ sms_log(pMac, LOG2,
+ "CSR getting WPS Session Overlap for Bssid = " MAC_ADDRESS_STR,
+ MAC_ADDR_ARRAY(bssId.bytes));
+
+ status =
+ csr_send_mb_get_wpspbc_sessions(pMac, sessionId, bssId.bytes, pUsrContext,
+ pfnSapEventCallback, pRemoveMac);
+
+ return status;
+}
+
+CDF_STATUS csr_roam_issue_deauth(tpAniSirGlobal pMac, uint32_t sessionId,
+ eCsrRoamSubState NewSubstate)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ struct cdf_mac_addr bssId = CDF_MAC_ADDR_BROADCAST_INITIALIZER;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ if (pSession->pConnectBssDesc) {
+ cdf_mem_copy(bssId.bytes, pSession->pConnectBssDesc->bssId,
+ sizeof(struct cdf_mac_addr));
+ }
+ sms_log(pMac, LOG2, "CSR Attempting to Deauth Bssid= " MAC_ADDRESS_STR,
+ MAC_ADDR_ARRAY(bssId.bytes));
+ csr_roam_substate_change(pMac, NewSubstate, sessionId);
+
+ status =
+ csr_send_mb_deauth_req_msg(pMac, sessionId, bssId.bytes,
+ eSIR_MAC_DEAUTH_LEAVING_BSS_REASON);
+ if (CDF_IS_STATUS_SUCCESS(status))
+ csr_roam_link_down(pMac, sessionId);
+ else {
+ sms_log(pMac, LOGE,
+ FL
+ ("csr_send_mb_deauth_req_msg failed with status %d Session ID: %d"
+ MAC_ADDRESS_STR), status, sessionId,
+ MAC_ADDR_ARRAY(bssId.bytes));
+ }
+
+ return status;
+}
+
+CDF_STATUS csr_roam_save_connected_bss_desc(tpAniSirGlobal pMac, uint32_t sessionId,
+ tSirBssDescription *pBssDesc)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+ uint32_t size;
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+ /* If no BSS description was found in this connection (happens with start IBSS), then */
+ /* nix the BSS description that we keep around for the connected BSS) and get out... */
+ if (NULL == pBssDesc) {
+ csr_free_connect_bss_desc(pMac, sessionId);
+ } else {
+ size = pBssDesc->length + sizeof(pBssDesc->length);
+ if (NULL != pSession->pConnectBssDesc) {
+ if (((pSession->pConnectBssDesc->length) +
+ sizeof(pSession->pConnectBssDesc->length)) <
+ size) {
+ /* not enough room for the new BSS, pMac->roam.pConnectBssDesc is freed inside */
+ csr_free_connect_bss_desc(pMac, sessionId);
+ }
+ }
+ if (NULL == pSession->pConnectBssDesc) {
+ pSession->pConnectBssDesc = cdf_mem_malloc(size);
+ }
+ if (NULL == pSession->pConnectBssDesc)
+ status = CDF_STATUS_E_NOMEM;
+ else
+ cdf_mem_copy(pSession->pConnectBssDesc, pBssDesc, size);
+ }
+ return status;
+}
+
+CDF_STATUS csr_roam_prepare_bss_config(tpAniSirGlobal pMac,
+ tCsrRoamProfile *pProfile,
+ tSirBssDescription *pBssDesc,
+ tBssConfigParam *pBssConfig,
+ tDot11fBeaconIEs *pIes)
+{
+ eCsrCfgDot11Mode cfgDot11Mode;
+ CDF_ASSERT(pIes != NULL);
+ if (pIes == NULL)
+ return CDF_STATUS_E_FAILURE;
+
+ cdf_mem_copy(&pBssConfig->BssCap, &pBssDesc->capabilityInfo,
+ sizeof(tSirMacCapabilityInfo));
+ /* get qos */
+ pBssConfig->qosType = csr_get_qo_s_from_bss_desc(pMac, pBssDesc, pIes);
+ /* get SSID */
+ if (pIes->SSID.present) {
+ cdf_mem_copy(&pBssConfig->SSID.ssId, pIes->SSID.ssid,
+ pIes->SSID.num_ssid);
+ pBssConfig->SSID.length = pIes->SSID.num_ssid;
+ } else
+ pBssConfig->SSID.length = 0;
+ if (csr_is_nullssid(pBssConfig->SSID.ssId, pBssConfig->SSID.length)) {
+ sms_log(pMac, LOGW, FL("BSS desc SSID is a wild card"));
+ /* Return failed if profile doesn't have an SSID either. */
+ if (pProfile->SSIDs.numOfSSIDs == 0) {
+ sms_log(pMac, LOGW,
+ FL("BSS desc and profile doesn't have SSID"));
+ return CDF_STATUS_E_FAILURE;
+ }
+ }
+ if (CDS_IS_CHANNEL_5GHZ(pBssDesc->channelId))
+ pBssConfig->eBand = eCSR_BAND_5G;
+ else
+ pBssConfig->eBand = eCSR_BAND_24;
+ /* phymode */
+ if (csr_is_phy_mode_match(pMac, pProfile->phyMode, pBssDesc,
+ pProfile, &cfgDot11Mode, pIes)) {
+ pBssConfig->uCfgDot11Mode = cfgDot11Mode;
+ } else {
+ sms_log(pMac, LOGW, "Can not find match phy mode");
+ /* force it */
+ if (eCSR_BAND_24 == pBssConfig->eBand)
+ pBssConfig->uCfgDot11Mode = eCSR_CFG_DOT11_MODE_11G;
+ else
+ pBssConfig->uCfgDot11Mode = eCSR_CFG_DOT11_MODE_11A;
+ }
+ /* Qos */
+ if ((pBssConfig->uCfgDot11Mode != eCSR_CFG_DOT11_MODE_11N) &&
+ (pMac->roam.configParam.WMMSupportMode == eCsrRoamWmmNoQos)) {
+ /*
+ * Joining BSS is not 11n capable and WMM is disabled on client.
+ * Disable QoS and WMM
+ */
+ pBssConfig->qosType = eCSR_MEDIUM_ACCESS_DCF;
+ }
+
+ if (((pBssConfig->uCfgDot11Mode == eCSR_CFG_DOT11_MODE_11N)
+ || (pBssConfig->uCfgDot11Mode == eCSR_CFG_DOT11_MODE_11AC))
+ && ((pBssConfig->qosType != eCSR_MEDIUM_ACCESS_WMM_eDCF_DSCP)
+ || (pBssConfig->qosType != eCSR_MEDIUM_ACCESS_11e_HCF)
+ || (pBssConfig->qosType != eCSR_MEDIUM_ACCESS_11e_eDCF))) {
+ /* Joining BSS is 11n capable and WMM is disabled on AP. */
+ /* Assume all HT AP's are QOS AP's and enable WMM */
+ pBssConfig->qosType = eCSR_MEDIUM_ACCESS_WMM_eDCF_DSCP;
+ }
+ /* auth type */
+ switch (pProfile->negotiatedAuthType) {
+ default:
+ case eCSR_AUTH_TYPE_WPA:
+ case eCSR_AUTH_TYPE_WPA_PSK:
+ case eCSR_AUTH_TYPE_WPA_NONE:
+ case eCSR_AUTH_TYPE_OPEN_SYSTEM:
+ pBssConfig->authType = eSIR_OPEN_SYSTEM;
+ break;
+ case eCSR_AUTH_TYPE_SHARED_KEY:
+ pBssConfig->authType = eSIR_SHARED_KEY;
+ break;
+ case eCSR_AUTH_TYPE_AUTOSWITCH:
+ pBssConfig->authType = eSIR_AUTO_SWITCH;
+ break;
+ }
+ /* short slot time */
+ if (eCSR_CFG_DOT11_MODE_11B != cfgDot11Mode)
+ pBssConfig->uShortSlotTime =
+ pMac->roam.configParam.shortSlotTime;
+ else
+ pBssConfig->uShortSlotTime = 0;
+
+ if (pBssConfig->BssCap.ibss)
+ /* We don't support 11h on IBSS */
+ pBssConfig->f11hSupport = false;
+ else
+ pBssConfig->f11hSupport =
+ pMac->roam.configParam.Is11hSupportEnabled;
+ /* power constraint */
+ pBssConfig->uPowerLimit =
+ csr_get11h_power_constraint(pMac, &pIes->PowerConstraints);
+ /* heartbeat */
+ if (CSR_IS_11A_BSS(pBssDesc))
+ pBssConfig->uHeartBeatThresh =
+ pMac->roam.configParam.HeartbeatThresh50;
+ else
+ pBssConfig->uHeartBeatThresh =
+ pMac->roam.configParam.HeartbeatThresh24;
+
+ /*
+ * Join timeout: if we find a BeaconInterval in the BssDescription,
+ * then set the Join Timeout to be 10 x the BeaconInterval.
+ */
+ if (pBssDesc->beaconInterval)
+ /* Make sure it is bigger than the minimal */
+ pBssConfig->uJoinTimeOut =
+ CDF_MAX(10 * pBssDesc->beaconInterval,
+ CSR_JOIN_FAILURE_TIMEOUT_MIN);
+ else
+ pBssConfig->uJoinTimeOut =
+ CSR_JOIN_FAILURE_TIMEOUT_DEFAULT;
+ /* validate CB */
+ pBssConfig->cbMode = csr_get_cb_mode_from_ies(pMac, pBssDesc->channelId,
+ pIes);
+
+ return CDF_STATUS_SUCCESS;
+}
+
+static CDF_STATUS csr_roam_prepare_bss_config_from_profile(tpAniSirGlobal pMac,
+ tCsrRoamProfile *pProfile,
+ tBssConfigParam *
+ pBssConfig,
+ tSirBssDescription *
+ pBssDesc)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ uint8_t operationChannel = 0;
+ uint8_t qAPisEnabled = false;
+ /* SSID */
+ pBssConfig->SSID.length = 0;
+ if (pProfile->SSIDs.numOfSSIDs) {
+ /* only use the first one */
+ cdf_mem_copy(&pBssConfig->SSID,
+ &pProfile->SSIDs.SSIDList[0].SSID,
+ sizeof(tSirMacSSid));
+ } else {
+ /* SSID must present */
+ return CDF_STATUS_E_FAILURE;
+ }
+ /* Settomg up the capabilities */
+ if (csr_is_bss_type_ibss(pProfile->BSSType)) {
+ pBssConfig->BssCap.ibss = 1;
+ } else {
+ pBssConfig->BssCap.ess = 1;
+ }
+ if (eCSR_ENCRYPT_TYPE_NONE !=
+ pProfile->EncryptionType.encryptionType[0]) {
+ pBssConfig->BssCap.privacy = 1;
+ }
+ pBssConfig->eBand = pMac->roam.configParam.eBand;
+ /* phymode */
+ if (pProfile->ChannelInfo.ChannelList) {
+ operationChannel = pProfile->ChannelInfo.ChannelList[0];
+ }
+ pBssConfig->uCfgDot11Mode =
+ csr_roam_get_phy_mode_band_for_bss(pMac, pProfile, operationChannel,
+ &pBssConfig->eBand);
+ /* QOS */
+ /* Is this correct to always set to this // *** */
+ if (pBssConfig->BssCap.ess == 1) {
+ /*For Softap case enable WMM */
+ if (CSR_IS_INFRA_AP(pProfile)
+ && (eCsrRoamWmmNoQos !=
+ pMac->roam.configParam.WMMSupportMode)) {
+ qAPisEnabled = true;
+ } else
+ if (csr_roam_get_qos_info_from_bss(pMac, pBssDesc) ==
+ CDF_STATUS_SUCCESS) {
+ qAPisEnabled = true;
+ } else {
+ qAPisEnabled = false;
+ }
+ } else {
+ qAPisEnabled = true;
+ }
+ if ((eCsrRoamWmmNoQos != pMac->roam.configParam.WMMSupportMode &&
+ qAPisEnabled) ||
+ ((eCSR_CFG_DOT11_MODE_11N == pBssConfig->uCfgDot11Mode &&
+ qAPisEnabled))) {
+ pBssConfig->qosType = eCSR_MEDIUM_ACCESS_WMM_eDCF_DSCP;
+ } else {
+ pBssConfig->qosType = eCSR_MEDIUM_ACCESS_DCF;
+ }
+
+ /* auth type */
+ /* Take the preferred Auth type. */
+ switch (pProfile->AuthType.authType[0]) {
+ default:
+ case eCSR_AUTH_TYPE_WPA:
+ case eCSR_AUTH_TYPE_WPA_PSK:
+ case eCSR_AUTH_TYPE_WPA_NONE:
+ case eCSR_AUTH_TYPE_OPEN_SYSTEM:
+ pBssConfig->authType = eSIR_OPEN_SYSTEM;
+ break;
+ case eCSR_AUTH_TYPE_SHARED_KEY:
+ pBssConfig->authType = eSIR_SHARED_KEY;
+ break;
+ case eCSR_AUTH_TYPE_AUTOSWITCH:
+ pBssConfig->authType = eSIR_AUTO_SWITCH;
+ break;
+ }
+ /* short slot time */
+ if (WNI_CFG_PHY_MODE_11B != pBssConfig->uCfgDot11Mode) {
+ pBssConfig->uShortSlotTime =
+ pMac->roam.configParam.shortSlotTime;
+ } else {
+ pBssConfig->uShortSlotTime = 0;
+ }
+ /* power constraint. We don't support 11h on IBSS */
+ pBssConfig->f11hSupport = false;
+ pBssConfig->uPowerLimit = 0;
+ /* heartbeat */
+ if (eCSR_BAND_5G == pBssConfig->eBand) {
+ pBssConfig->uHeartBeatThresh =
+ pMac->roam.configParam.HeartbeatThresh50;
+ } else {
+ pBssConfig->uHeartBeatThresh =
+ pMac->roam.configParam.HeartbeatThresh24;
+ }
+ /* Join timeout */
+ pBssConfig->uJoinTimeOut = CSR_JOIN_FAILURE_TIMEOUT_DEFAULT;
+
+ return status;
+}
+
+static CDF_STATUS csr_roam_get_qos_info_from_bss(tpAniSirGlobal pMac,
+ tSirBssDescription *pBssDesc)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ tDot11fBeaconIEs *pIes = NULL;
+
+ do {
+ if (!CDF_IS_STATUS_SUCCESS(
+ csr_get_parsed_bss_description_ies(
+ pMac, pBssDesc, &pIes))) {
+ /* err msg */
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ "csr_roam_get_qos_info_from_bss() failed");
+ break;
+ }
+ /* check if the AP is QAP & it supports APSD */
+ if (CSR_IS_QOS_BSS(pIes)) {
+ status = CDF_STATUS_SUCCESS;
+ }
+ } while (0);
+
+ if (NULL != pIes) {
+ cdf_mem_free(pIes);
+ }
+
+ return status;
+}
+
+void csr_set_cfg_privacy(tpAniSirGlobal pMac, tCsrRoamProfile *pProfile,
+ bool fPrivacy)
+{
+ /*
+ * the only difference between this function and
+ * the csr_set_cfg_privacyFromProfile() is the setting of the privacy
+ * CFG based on the advertised privacy setting from the AP for WPA
+ * associations. See note below in this function...
+ */
+ uint32_t PrivacyEnabled = 0, RsnEnabled = 0, WepDefaultKeyId = 0;
+ uint32_t WepKeyLength = WNI_CFG_WEP_KEY_LENGTH_5;
+ uint32_t Key0Length = 0, Key1Length = 0, Key2Length = 0, Key3Length = 0;
+
+ /* Reserve for the biggest key */
+ uint8_t Key0[WNI_CFG_WEP_DEFAULT_KEY_1_LEN];
+ uint8_t Key1[WNI_CFG_WEP_DEFAULT_KEY_2_LEN];
+ uint8_t Key2[WNI_CFG_WEP_DEFAULT_KEY_3_LEN];
+ uint8_t Key3[WNI_CFG_WEP_DEFAULT_KEY_4_LEN];
+
+ switch (pProfile->negotiatedUCEncryptionType) {
+ case eCSR_ENCRYPT_TYPE_NONE:
+ /* for NO encryption, turn off Privacy and Rsn. */
+ PrivacyEnabled = 0;
+ RsnEnabled = 0;
+ /* clear out the WEP keys that may be hanging around. */
+ Key0Length = 0;
+ Key1Length = 0;
+ Key2Length = 0;
+ Key3Length = 0;
+ break;
+
+ case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY:
+ case eCSR_ENCRYPT_TYPE_WEP40:
+
+ /* Privacy is ON. NO RSN for Wep40 static key. */
+ PrivacyEnabled = 1;
+ RsnEnabled = 0;
+ /* Set the Wep default key ID. */
+ WepDefaultKeyId = pProfile->Keys.defaultIndex;
+ /* Wep key size if 5 bytes (40 bits). */
+ WepKeyLength = WNI_CFG_WEP_KEY_LENGTH_5;
+ /*
+ * set encryption keys in the CFG database or
+ * clear those that are not present in this profile.
+ */
+ if (pProfile->Keys.KeyLength[0]) {
+ cdf_mem_copy(Key0,
+ pProfile->Keys.KeyMaterial[0],
+ WNI_CFG_WEP_KEY_LENGTH_5);
+ Key0Length = WNI_CFG_WEP_KEY_LENGTH_5;
+ } else {
+ Key0Length = 0;
+ }
+
+ if (pProfile->Keys.KeyLength[1]) {
+ cdf_mem_copy(Key1,
+ pProfile->Keys.KeyMaterial[1],
+ WNI_CFG_WEP_KEY_LENGTH_5);
+ Key1Length = WNI_CFG_WEP_KEY_LENGTH_5;
+ } else {
+ Key1Length = 0;
+ }
+
+ if (pProfile->Keys.KeyLength[2]) {
+ cdf_mem_copy(Key2,
+ pProfile->Keys.KeyMaterial[2],
+ WNI_CFG_WEP_KEY_LENGTH_5);
+ Key2Length = WNI_CFG_WEP_KEY_LENGTH_5;
+ } else {
+ Key2Length = 0;
+ }
+
+ if (pProfile->Keys.KeyLength[3]) {
+ cdf_mem_copy(Key3,
+ pProfile->Keys.KeyMaterial[3],
+ WNI_CFG_WEP_KEY_LENGTH_5);
+ Key3Length = WNI_CFG_WEP_KEY_LENGTH_5;
+ } else {
+ Key3Length = 0;
+ }
+ break;
+
+ case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY:
+ case eCSR_ENCRYPT_TYPE_WEP104:
+
+ /* Privacy is ON. NO RSN for Wep40 static key. */
+ PrivacyEnabled = 1;
+ RsnEnabled = 0;
+ /* Set the Wep default key ID. */
+ WepDefaultKeyId = pProfile->Keys.defaultIndex;
+ /* Wep key size if 13 bytes (104 bits). */
+ WepKeyLength = WNI_CFG_WEP_KEY_LENGTH_13;
+ /*
+ * set encryption keys in the CFG database or clear
+ * those that are not present in this profile.
+ */
+ if (pProfile->Keys.KeyLength[0]) {
+ cdf_mem_copy(Key0,
+ pProfile->Keys.KeyMaterial[0],
+ WNI_CFG_WEP_KEY_LENGTH_13);
+ Key0Length = WNI_CFG_WEP_KEY_LENGTH_13;
+ } else {
+ Key0Length = 0;
+ }
+
+ if (pProfile->Keys.KeyLength[1]) {
+ cdf_mem_copy(Key1,
+ pProfile->Keys.KeyMaterial[1],
+ WNI_CFG_WEP_KEY_LENGTH_13);
+ Key1Length = WNI_CFG_WEP_KEY_LENGTH_13;
+ } else {
+ Key1Length = 0;
+ }
+
+ if (pProfile->Keys.KeyLength[2]) {
+ cdf_mem_copy(Key2,
+ pProfile->Keys.KeyMaterial[2],
+ WNI_CFG_WEP_KEY_LENGTH_13);
+ Key2Length = WNI_CFG_WEP_KEY_LENGTH_13;
+ } else {
+ Key2Length = 0;
+ }
+
+ if (pProfile->Keys.KeyLength[3]) {
+ cdf_mem_copy(Key3,
+ pProfile->Keys.KeyMaterial[3],
+ WNI_CFG_WEP_KEY_LENGTH_13);
+ Key3Length = WNI_CFG_WEP_KEY_LENGTH_13;
+ } else {
+ Key3Length = 0;
+ }
+ break;
+
+ case eCSR_ENCRYPT_TYPE_TKIP:
+ case eCSR_ENCRYPT_TYPE_AES:
+#ifdef FEATURE_WLAN_WAPI
+ case eCSR_ENCRYPT_TYPE_WPI:
+#endif /* FEATURE_WLAN_WAPI */
+ /*
+ * this is the only difference between this function and
+ * the csr_set_cfg_privacyFromProfile().
+ * (setting of the privacy CFG based on the advertised
+ * privacy setting from AP for WPA/WAPI associations).
+ */
+ PrivacyEnabled = (0 != fPrivacy);
+ /* turn on RSN enabled for WPA associations */
+ RsnEnabled = 1;
+ /* clear static WEP keys that may be hanging around. */
+ Key0Length = 0;
+ Key1Length = 0;
+ Key2Length = 0;
+ Key3Length = 0;
+ break;
+ default:
+ PrivacyEnabled = 0;
+ RsnEnabled = 0;
+ break;
+ }
+
+ cfg_set_int(pMac, WNI_CFG_PRIVACY_ENABLED, PrivacyEnabled);
+ cfg_set_int(pMac, WNI_CFG_RSN_ENABLED, RsnEnabled);
+ cfg_set_str(pMac, WNI_CFG_WEP_DEFAULT_KEY_1, Key0, Key0Length);
+ cfg_set_str(pMac, WNI_CFG_WEP_DEFAULT_KEY_2, Key1, Key1Length);
+ cfg_set_str(pMac, WNI_CFG_WEP_DEFAULT_KEY_3, Key2, Key2Length);
+ cfg_set_str(pMac, WNI_CFG_WEP_DEFAULT_KEY_4, Key3, Key3Length);
+ cfg_set_int(pMac, WNI_CFG_WEP_KEY_LENGTH, WepKeyLength);
+ cfg_set_int(pMac, WNI_CFG_WEP_DEFAULT_KEYID, WepDefaultKeyId);
+}
+
+static void csr_set_cfg_ssid(tpAniSirGlobal pMac, tSirMacSSid *pSSID)
+{
+ uint32_t len = 0;
+ if (pSSID->length <= WNI_CFG_SSID_LEN) {
+ len = pSSID->length;
+ }
+ cfg_set_str(pMac, WNI_CFG_SSID, (uint8_t *) pSSID->ssId, len);
+}
+
+CDF_STATUS csr_set_qos_to_cfg(tpAniSirGlobal pMac, uint32_t sessionId,
+ eCsrMediaAccessType qosType)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ uint32_t QoSEnabled;
+ uint32_t WmeEnabled;
+ /* set the CFG enable/disable variables based on the qosType being configured... */
+ switch (qosType) {
+ case eCSR_MEDIUM_ACCESS_WMM_eDCF_802dot1p:
+ QoSEnabled = false;
+ WmeEnabled = true;
+ break;
+ case eCSR_MEDIUM_ACCESS_WMM_eDCF_DSCP:
+ QoSEnabled = false;
+ WmeEnabled = true;
+ break;
+ case eCSR_MEDIUM_ACCESS_WMM_eDCF_NoClassify:
+ QoSEnabled = false;
+ WmeEnabled = true;
+ break;
+ case eCSR_MEDIUM_ACCESS_11e_eDCF:
+ QoSEnabled = true;
+ WmeEnabled = false;
+ break;
+ case eCSR_MEDIUM_ACCESS_11e_HCF:
+ QoSEnabled = true;
+ WmeEnabled = false;
+ break;
+ default:
+ case eCSR_MEDIUM_ACCESS_DCF:
+ QoSEnabled = false;
+ WmeEnabled = false;
+ break;
+ }
+ /* save the WMM setting for later use */
+ pMac->roam.roamSession[sessionId].fWMMConnection = (bool) WmeEnabled;
+ pMac->roam.roamSession[sessionId].fQOSConnection = (bool) QoSEnabled;
+ return status;
+}
+
+static CDF_STATUS csr_get_rate_set(tpAniSirGlobal pMac,
+ tCsrRoamProfile *pProfile, eCsrPhyMode phyMode,
+ tSirBssDescription *pBssDesc,
+ tDot11fBeaconIEs *pIes,
+ tSirMacRateSet *pOpRateSet,
+ tSirMacRateSet *pExRateSet)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ int i;
+ eCsrCfgDot11Mode cfgDot11Mode;
+ uint8_t *pDstRate;
+ uint16_t rateBitmap = 0;
+ cdf_mem_set(pOpRateSet, sizeof(tSirMacRateSet), 0);
+ cdf_mem_set(pExRateSet, sizeof(tSirMacRateSet), 0);
+ CDF_ASSERT(pIes != NULL);
+
+ if (NULL == pIes) {
+ sms_log(pMac, LOGE, FL("failed to parse BssDesc"));
+ return status;
+ }
+
+ csr_is_phy_mode_match(pMac, phyMode, pBssDesc, pProfile,
+ &cfgDot11Mode, pIes);
+ /*
+ * Originally, we thought that for 11a networks, the 11a rates
+ * are always in the Operational Rate set & for 11b and 11g
+ * networks, the 11b rates appear in the Operational Rate set.
+ * Consequently, in either case, we would blindly put the rates
+ * we support into our Operational Rate set.
+ * (including the basic rates, which we've already verified are
+ * supported earlier in the roaming decision).
+ * However, it turns out that this is not always the case.
+ * Some AP's (e.g. D-Link DI-784) ram 11g rates into the
+ * Operational Rate set too. Now, we're a little more careful.
+ */
+ pDstRate = pOpRateSet->rate;
+ if (pIes->SuppRates.present) {
+ for (i = 0; i < pIes->SuppRates.num_rates; i++) {
+ if (csr_rates_is_dot11_rate_supported(pMac,
+ pIes->SuppRates.rates[i]) &&
+ !csr_check_rate_bitmap(
+ pIes->SuppRates.rates[i],
+ rateBitmap)) {
+ csr_add_rate_bitmap(pIes->SuppRates.
+ rates[i], &rateBitmap);
+ *pDstRate++ = pIes->SuppRates.rates[i];
+ pOpRateSet->numRates++;
+ }
+ }
+ }
+ if ((eCSR_CFG_DOT11_MODE_11G == cfgDot11Mode ||
+ eCSR_CFG_DOT11_MODE_11N == cfgDot11Mode ||
+ eCSR_CFG_DOT11_MODE_ABG == cfgDot11Mode
+#ifdef WLAN_FEATURE_11AC
+ || eCSR_CFG_DOT11_MODE_11AC == cfgDot11Mode
+#endif
+ ) && pIes->ExtSuppRates.present) {
+ /*
+ * If there are extended rates in the beacon,
+ * we will reflect those extended rates that we support in our
+ * extended operational rate
+ */
+ pDstRate = pExRateSet->rate;
+ for (i = 0; i < pIes->ExtSuppRates.num_rates; i++) {
+ if (csr_rates_is_dot11_rate_supported(pMac,
+ pIes->ExtSuppRates.rates[i]) &&
+ !csr_check_rate_bitmap(
+ pIes->ExtSuppRates.rates[i],
+ rateBitmap)) {
+ *pDstRate++ = pIes->ExtSuppRates.rates[i];
+ pExRateSet->numRates++;
+ }
+ }
+ }
+ if (pOpRateSet->numRates > 0 || pExRateSet->numRates > 0)
+ status = CDF_STATUS_SUCCESS;
+ return status;
+}
+
+static void csr_set_cfg_rate_set(tpAniSirGlobal pMac, eCsrPhyMode phyMode,
+ tCsrRoamProfile *pProfile,
+ tSirBssDescription *pBssDesc,
+ tDot11fBeaconIEs *pIes)
+{
+ int i;
+ uint8_t *pDstRate;
+ eCsrCfgDot11Mode cfgDot11Mode;
+ uint8_t OperationalRates[CSR_DOT11_SUPPORTED_RATES_MAX]; /* leave enough room for the max number of rates */
+ uint32_t OperationalRatesLength = 0;
+ uint8_t ExtendedOperationalRates[CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX]; /* leave enough room for the max number of rates */
+ uint32_t ExtendedOperationalRatesLength = 0;
+ uint8_t MCSRateIdxSet[SIZE_OF_SUPPORTED_MCS_SET];
+ uint32_t MCSRateLength = 0;
+ CDF_ASSERT(pIes != NULL);
+ if (NULL != pIes) {
+ csr_is_phy_mode_match(pMac, phyMode, pBssDesc, pProfile,
+ &cfgDot11Mode, pIes);
+ /* Originally, we thought that for 11a networks, the 11a rates are always */
+ /* in the Operational Rate set & for 11b and 11g networks, the 11b rates */
+ /* appear in the Operational Rate set. Consequently, in either case, we */
+ /* would blindly put the rates we support into our Operational Rate set */
+ /* (including the basic rates, which we have already verified are */
+ /* supported earlier in the roaming decision). */
+ /* However, it turns out that this is not always the case. Some AP's */
+ /* (e.g. D-Link DI-784) ram 11g rates into the Operational Rate set, */
+ /* too. Now, we're a little more careful: */
+ pDstRate = OperationalRates;
+ if (pIes->SuppRates.present) {
+ for (i = 0; i < pIes->SuppRates.num_rates; i++) {
+ if (csr_rates_is_dot11_rate_supported
+ (pMac, pIes->SuppRates.rates[i])
+ && (OperationalRatesLength <
+ CSR_DOT11_SUPPORTED_RATES_MAX)) {
+ *pDstRate++ = pIes->SuppRates.rates[i];
+ OperationalRatesLength++;
+ }
+ }
+ }
+ if (eCSR_CFG_DOT11_MODE_11G == cfgDot11Mode ||
+ eCSR_CFG_DOT11_MODE_11N == cfgDot11Mode ||
+ eCSR_CFG_DOT11_MODE_ABG == cfgDot11Mode) {
+ /* If there are Extended Rates in the beacon, we will reflect those */
+ /* extended rates that we support in out Extended Operational Rate */
+ /* set: */
+ pDstRate = ExtendedOperationalRates;
+ if (pIes->ExtSuppRates.present) {
+ for (i = 0; i < pIes->ExtSuppRates.num_rates;
+ i++) {
+ if (csr_rates_is_dot11_rate_supported
+ (pMac, pIes->ExtSuppRates.rates[i])
+ && (ExtendedOperationalRatesLength <
+ CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX)) {
+ *pDstRate++ =
+ pIes->ExtSuppRates.rates[i];
+ ExtendedOperationalRatesLength++;
+ }
+ }
+ }
+ }
+ /* Enable proprietary MAC features if peer node is Airgo node and STA */
+ /* user wants to use them */
+ /* For ANI network companions, we need to populate the proprietary rate */
+ /* set with any proprietary rates we found in the beacon, only if user */
+ /* allows them... */
+ /* No proprietary modes... */
+ /* Get MCS Rate */
+ pDstRate = MCSRateIdxSet;
+ if (pIes->HTCaps.present) {
+ for (i = 0; i < VALID_MAX_MCS_INDEX; i++) {
+ if ((unsigned int)pIes->HTCaps.
+ supportedMCSSet[0] & (1 << i)) {
+ MCSRateLength++;
+ *pDstRate++ = i;
+ }
+ }
+ }
+ /* Set the operational rate set CFG variables... */
+ cfg_set_str(pMac, WNI_CFG_OPERATIONAL_RATE_SET,
+ OperationalRates, OperationalRatesLength);
+ cfg_set_str(pMac, WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET,
+ ExtendedOperationalRates,
+ ExtendedOperationalRatesLength);
+ cfg_set_str(pMac, WNI_CFG_CURRENT_MCS_SET, MCSRateIdxSet,
+ MCSRateLength);
+ } /* Parsing BSSDesc */
+ else {
+ sms_log(pMac, LOGE, FL("failed to parse BssDesc"));
+ }
+}
+
+static void csr_set_cfg_rate_set_from_profile(tpAniSirGlobal pMac,
+ tCsrRoamProfile *pProfile)
+{
+ tSirMacRateSetIE DefaultSupportedRates11a = { SIR_MAC_RATESET_EID,
+ {8,
+ {SIR_MAC_RATE_6,
+ SIR_MAC_RATE_9,
+ SIR_MAC_RATE_12,
+ SIR_MAC_RATE_18,
+ SIR_MAC_RATE_24,
+ SIR_MAC_RATE_36,
+ SIR_MAC_RATE_48,
+ SIR_MAC_RATE_54} } };
+ tSirMacRateSetIE DefaultSupportedRates11b = { SIR_MAC_RATESET_EID,
+ {4,
+ {SIR_MAC_RATE_1,
+ SIR_MAC_RATE_2,
+ SIR_MAC_RATE_5_5,
+ SIR_MAC_RATE_11} } };
+
+ tSirMacPropRateSet DefaultSupportedPropRates = { 3,
+ {SIR_MAC_RATE_72,
+ SIR_MAC_RATE_96,
+ SIR_MAC_RATE_108} };
+ eCsrCfgDot11Mode cfgDot11Mode;
+ eCsrBand eBand;
+ /* leave enough room for the max number of rates */
+ uint8_t OperationalRates[CSR_DOT11_SUPPORTED_RATES_MAX];
+ uint32_t OperationalRatesLength = 0;
+ /* leave enough room for the max number of rates */
+ uint8_t ExtendedOperationalRates[CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX];
+ uint32_t ExtendedOperationalRatesLength = 0;
+ /* leave enough room for the max number of proprietary rates */
+ uint8_t ProprietaryOperationalRates[4];
+ uint32_t ProprietaryOperationalRatesLength = 0;
+ uint32_t PropRatesEnable = 0;
+ uint8_t operationChannel = 0;
+ if (pProfile->ChannelInfo.ChannelList) {
+ operationChannel = pProfile->ChannelInfo.ChannelList[0];
+ }
+ cfgDot11Mode =
+ csr_roam_get_phy_mode_band_for_bss(pMac, pProfile, operationChannel,
+ &eBand);
+ /* For 11a networks, the 11a rates go into the Operational Rate set. For 11b and 11g */
+ /* networks, the 11b rates appear in the Operational Rate set. In either case, */
+ /* we can blindly put the rates we support into our Operational Rate set */
+ /* (including the basic rates, which we have already verified are supported */
+ /* earlier in the roaming decision). */
+ if (eCSR_BAND_5G == eBand) {
+ /* 11a rates into the Operational Rate Set. */
+ OperationalRatesLength =
+ DefaultSupportedRates11a.supportedRateSet.numRates *
+ sizeof(*DefaultSupportedRates11a.supportedRateSet.rate);
+ cdf_mem_copy(OperationalRates,
+ DefaultSupportedRates11a.supportedRateSet.rate,
+ OperationalRatesLength);
+
+ /* Nothing in the Extended rate set. */
+ ExtendedOperationalRatesLength = 0;
+ /* populate proprietary rates if user allows them */
+ if (pMac->roam.configParam.ProprietaryRatesEnabled) {
+ ProprietaryOperationalRatesLength =
+ DefaultSupportedPropRates.numPropRates *
+ sizeof(*DefaultSupportedPropRates.propRate);
+ cdf_mem_copy(ProprietaryOperationalRates,
+ DefaultSupportedPropRates.propRate,
+ ProprietaryOperationalRatesLength);
+ } else {
+ /* No proprietary modes */
+ ProprietaryOperationalRatesLength = 0;
+ }
+ } else if (eCSR_CFG_DOT11_MODE_11B == cfgDot11Mode) {
+ /* 11b rates into the Operational Rate Set. */
+ OperationalRatesLength =
+ DefaultSupportedRates11b.supportedRateSet.numRates *
+ sizeof(*DefaultSupportedRates11b.supportedRateSet.rate);
+ cdf_mem_copy(OperationalRates,
+ DefaultSupportedRates11b.supportedRateSet.rate,
+ OperationalRatesLength);
+ /* Nothing in the Extended rate set. */
+ ExtendedOperationalRatesLength = 0;
+ /* No proprietary modes */
+ ProprietaryOperationalRatesLength = 0;
+ } else {
+ /* 11G */
+
+ /* 11b rates into the Operational Rate Set. */
+ OperationalRatesLength =
+ DefaultSupportedRates11b.supportedRateSet.numRates *
+ sizeof(*DefaultSupportedRates11b.supportedRateSet.rate);
+ cdf_mem_copy(OperationalRates,
+ DefaultSupportedRates11b.supportedRateSet.rate,
+ OperationalRatesLength);
+
+ /* 11a rates go in the Extended rate set. */
+ ExtendedOperationalRatesLength =
+ DefaultSupportedRates11a.supportedRateSet.numRates *
+ sizeof(*DefaultSupportedRates11a.supportedRateSet.rate);
+ cdf_mem_copy(ExtendedOperationalRates,
+ DefaultSupportedRates11a.supportedRateSet.rate,
+ ExtendedOperationalRatesLength);
+
+ /* populate proprietary rates if user allows them */
+ if (pMac->roam.configParam.ProprietaryRatesEnabled) {
+ ProprietaryOperationalRatesLength =
+ DefaultSupportedPropRates.numPropRates *
+ sizeof(*DefaultSupportedPropRates.propRate);
+ cdf_mem_copy(ProprietaryOperationalRates,
+ DefaultSupportedPropRates.propRate,
+ ProprietaryOperationalRatesLength);
+ } else {
+ /* No proprietary modes */
+ ProprietaryOperationalRatesLength = 0;
+ }
+ }
+ /* set this to 1 if prop. rates need to be advertised in to the IBSS beacon and user wants to use them */
+ if (ProprietaryOperationalRatesLength
+ && pMac->roam.configParam.ProprietaryRatesEnabled) {
+ PropRatesEnable = 1;
+ } else {
+ PropRatesEnable = 0;
+ }
+
+ /* Set the operational rate set CFG variables... */
+ cfg_set_str(pMac, WNI_CFG_OPERATIONAL_RATE_SET, OperationalRates,
+ OperationalRatesLength);
+ cfg_set_str(pMac, WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET,
+ ExtendedOperationalRates, ExtendedOperationalRatesLength);
+ cfg_set_str(pMac, WNI_CFG_PROPRIETARY_OPERATIONAL_RATE_SET,
+ ProprietaryOperationalRates,
+ ProprietaryOperationalRatesLength);
+}
+
+void csr_roam_ccm_cfg_set_callback(tpAniSirGlobal pMac, int32_t result)
+{
+ tListElem *pEntry =
+ csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK);
+ uint32_t sessionId;
+ tSmeCmd *pCommand = NULL;
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+ tCsrRoamSession *pSession = NULL;
+#endif
+ if (NULL == pEntry) {
+ sms_log(pMac, LOGW, "CFG_CNF with active list empty");
+ return;
+ }
+ pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
+ sessionId = pCommand->sessionId;
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+ pSession = &pMac->roam.roamSession[sessionId];
+ if (pSession->roamOffloadSynchParams.bRoamSynchInProgress) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ "LFR3:csr_roam_cfg_set_callback");
+ }
+#endif
+
+ if (CSR_IS_ROAM_JOINING(pMac, sessionId)
+ && CSR_IS_ROAM_SUBSTATE_CONFIG(pMac, sessionId)) {
+ csr_roaming_state_config_cnf_processor(pMac, (uint32_t) result);
+ }
+}
+
+/* This function is very dump. It is here because PE still need WNI_CFG_PHY_MODE */
+uint32_t csr_roam_get_phy_mode_from_dot11_mode(eCsrCfgDot11Mode dot11Mode,
+ eCsrBand band)
+{
+ if (eCSR_CFG_DOT11_MODE_11B == dot11Mode) {
+ return WNI_CFG_PHY_MODE_11B;
+ } else {
+ if (eCSR_BAND_24 == band)
+ return WNI_CFG_PHY_MODE_11G;
+ }
+ return WNI_CFG_PHY_MODE_11A;
+}
+
+#ifdef WLAN_FEATURE_11AC
+ePhyChanBondState csr_get_htcb_state_from_vhtcb_state(ePhyChanBondState aniCBMode)
+{
+ switch (aniCBMode) {
+ case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW:
+ case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED:
+ case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH:
+ return PHY_DOUBLE_CHANNEL_HIGH_PRIMARY;
+ case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW:
+ case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED:
+ case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH:
+ return PHY_DOUBLE_CHANNEL_LOW_PRIMARY;
+ case PHY_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED:
+ default:
+ return PHY_SINGLE_CHANNEL_CENTERED;
+ }
+}
+#endif
+
+/* pIes may be NULL */
+CDF_STATUS csr_roam_set_bss_config_cfg(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamProfile *pProfile,
+ tSirBssDescription *pBssDesc,
+ tBssConfigParam *pBssConfig,
+ tDot11fBeaconIEs *pIes, bool resetCountry)
+{
+ tSirRetStatus status;
+ uint32_t cfgCb = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE;
+ uint8_t channel = 0;
+ /* Make sure we have the domain info for the BSS we try to connect to. */
+ /* Do we need to worry about sequence for OSs that are not Windows?? */
+ if (pBssDesc) {
+ if (csr_learn_11dcountry_information(pMac, pBssDesc, pIes, true)) {
+ csr_apply_country_information(pMac);
+ }
+ if ((csr_is11d_supported(pMac)) && pIes) {
+ if (!pIes->Country.present) {
+ csr_apply_channel_power_info_wrapper(pMac);
+ } else {
+ /* Let's also update the below to make sure we don't update CC while */
+ /* connected to an AP which is advertising some CC */
+ cdf_mem_copy(pMac->scan.currentCountryBssid.bytes,
+ pBssDesc->bssId,
+ sizeof(tSirMacAddr));
+ }
+ }
+ }
+ /* Qos */
+ csr_set_qos_to_cfg(pMac, sessionId, pBssConfig->qosType);
+ /* SSID */
+ csr_set_cfg_ssid(pMac, &pBssConfig->SSID);
+
+ /* Auth type */
+ cfg_set_int(pMac, WNI_CFG_AUTHENTICATION_TYPE, pBssConfig->authType);
+ /* encryption type */
+ csr_set_cfg_privacy(pMac, pProfile, (bool) pBssConfig->BssCap.privacy);
+ /* short slot time */
+ cfg_set_int(pMac, WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED,
+ pBssConfig->uShortSlotTime);
+ /* 11d */
+ cfg_set_int(pMac, WNI_CFG_11D_ENABLED,
+ ((pBssConfig->f11hSupport) ? pBssConfig->f11hSupport :
+ pProfile->ieee80211d));
+ cfg_set_int(pMac, WNI_CFG_LOCAL_POWER_CONSTRAINT,
+ pBssConfig->uPowerLimit);
+ /* CB */
+
+ if (CSR_IS_INFRA_AP(pProfile) || CSR_IS_WDS_AP(pProfile)
+ || CSR_IS_IBSS(pProfile)) {
+ channel = pProfile->operationChannel;
+ } else {
+ if (pBssDesc) {
+ channel = pBssDesc->channelId;
+ }
+ }
+ if (0 != channel) {
+ if (CDS_IS_CHANNEL_24GHZ(channel)) { /* for now if we are on 2.4 Ghz, CB will be always disabled */
+ cfgCb = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE;
+ } else {
+ cfgCb = pBssConfig->cbMode;
+ }
+ }
+ /* Rate */
+ /* Fixed Rate */
+ if (pBssDesc) {
+ csr_set_cfg_rate_set(pMac, (eCsrPhyMode) pProfile->phyMode,
+ pProfile, pBssDesc, pIes);
+ } else {
+ csr_set_cfg_rate_set_from_profile(pMac, pProfile);
+ }
+ /* Make this the last CFG to set. The callback will trigger a join_req */
+ /* Join time out */
+ csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_CONFIG, sessionId);
+
+ status = cfg_set_int(pMac, WNI_CFG_JOIN_FAILURE_TIMEOUT,
+ pBssConfig->uJoinTimeOut);
+ csr_roam_ccm_cfg_set_callback(pMac, status);
+ return CDF_STATUS_SUCCESS;
+}
+
+CDF_STATUS csr_roam_stop_network(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamProfile *pProfile,
+ tSirBssDescription *pBssDesc,
+ tDot11fBeaconIEs *pIes)
+{
+ CDF_STATUS status;
+ tBssConfigParam *pBssConfig;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ pBssConfig = cdf_mem_malloc(sizeof(tBssConfigParam));
+ if (NULL == pBssConfig)
+ return CDF_STATUS_E_NOMEM;
+
+ cdf_mem_set(pBssConfig, sizeof(tBssConfigParam), 0);
+ status = csr_roam_prepare_bss_config(pMac, pProfile, pBssDesc,
+ pBssConfig, pIes);
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ eCsrRoamSubState substate;
+ substate = eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING;
+ pSession->bssParams.uCfgDot11Mode = pBssConfig->uCfgDot11Mode;
+ /* This will allow to pass cbMode during join req */
+ pSession->bssParams.cbMode = pBssConfig->cbMode;
+ /* For IBSS, we need to prepare some more information */
+ if (csr_is_bss_type_ibss(pProfile->BSSType) ||
+ CSR_IS_WDS(pProfile) ||
+ CSR_IS_INFRA_AP(pProfile))
+ csr_roam_prepare_bss_params(pMac, sessionId, pProfile,
+ pBssDesc, pBssConfig, pIes);
+
+ /*
+ * If we are in an IBSS, then stop the IBSS...
+ * Not worry about WDS connection for now
+ */
+ if (csr_is_conn_state_ibss(pMac, sessionId)) {
+ status = csr_roam_issue_stop_bss(pMac, sessionId,
+ substate);
+ } else if (csr_is_conn_state_infra(pMac, sessionId)) {
+ /*
+ * the new Bss is an Ibss OR we are roaming from
+ * Infra to Infra across SSIDs
+ * (roaming to a new SSID)...
+ * Not worry about WDS connection for now
+ */
+ if (pBssDesc && (csr_is_ibss_bss_desc(pBssDesc) ||
+ !csr_is_ssid_equal(pMac,
+ pSession->pConnectBssDesc,
+ pBssDesc, pIes)))
+ status = csr_roam_issue_disassociate(pMac,
+ sessionId, substate, false);
+ else if (pBssDesc)
+ /*
+ * In an infra & going to an infra network with
+ * the same SSID. This calls for a reassoc seq.
+ * So issue the CFG sets for this new AP. Set
+ * parameters for this Bss.
+ */
+ status = csr_roam_set_bss_config_cfg(pMac,
+ sessionId, pProfile, pBssDesc,
+ pBssConfig, pIes, false);
+ } else if (pBssDesc || CSR_IS_WDS_AP(pProfile) ||
+ CSR_IS_INFRA_AP(pProfile)) {
+ /*
+ * Neither in IBSS nor in Infra. We can go ahead and set
+ * the cfg for tne new network... nothing to stop.
+ */
+ bool is11rRoamingFlag = false;
+ is11rRoamingFlag = csr_roam_is11r_assoc(pMac,
+ sessionId);
+ /* Set parameters for this Bss. */
+ status = csr_roam_set_bss_config_cfg(pMac, sessionId,
+ pProfile, pBssDesc, pBssConfig, pIes,
+ is11rRoamingFlag);
+ }
+ } /* Success getting BSS config info */
+ cdf_mem_free(pBssConfig);
+ return status;
+}
+
+/**
+ * csr_roam_state_for_same_profile() - Determine roam state for same profile
+ * @mac_ctx: pointer to mac context
+ * @profile: Roam profile
+ * @session: Roam session
+ * @session_id: session id
+ * @ies_local: local ies
+ * @bss_descr: bss description
+ *
+ * This function will determine the roam state for same profile
+ *
+ * Return: Roaming state.
+ */
+static eCsrJoinState csr_roam_state_for_same_profile(tpAniSirGlobal mac_ctx,
+ tCsrRoamProfile *profile, tCsrRoamSession *session,
+ uint32_t session_id, tDot11fBeaconIEs *ies_local,
+ tSirBssDescription *bss_descr)
+{
+ CDF_STATUS status;
+ tBssConfigParam bssConfig;
+ if (csr_roam_is_same_profile_keys(mac_ctx, &session->connectedProfile,
+ profile))
+ return eCsrReassocToSelfNoCapChange;
+ /* The key changes */
+ cdf_mem_set(&bssConfig, sizeof(bssConfig), 0);
+ status = csr_roam_prepare_bss_config(mac_ctx, profile, bss_descr,
+ &bssConfig, ies_local);
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ session->bssParams.uCfgDot11Mode =
+ bssConfig.uCfgDot11Mode;
+ session->bssParams.cbMode =
+ bssConfig.cbMode;
+ /* reapply the cfg including keys so reassoc happens. */
+ status = csr_roam_set_bss_config_cfg(mac_ctx, session_id,
+ profile, bss_descr, &bssConfig,
+ ies_local, false);
+ if (CDF_IS_STATUS_SUCCESS(status))
+ return eCsrContinueRoaming;
+ }
+
+ return eCsrStopRoaming;
+
+}
+
+eCsrJoinState csr_roam_join(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrScanResultInfo *pScanResult,
+ tCsrRoamProfile *pProfile)
+{
+ eCsrJoinState eRoamState = eCsrContinueRoaming;
+ tSirBssDescription *pBssDesc = &pScanResult->BssDescriptor;
+ tDot11fBeaconIEs *pIesLocal = (tDot11fBeaconIEs *) (pScanResult->pvIes);
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL("session %d not found"), sessionId);
+ return eCsrStopRoaming;
+ }
+
+ if (CSR_IS_WDS_STA(pProfile) &&
+ !CDF_IS_STATUS_SUCCESS(csr_roam_start_wds(pMac, sessionId,
+ pProfile, pBssDesc)))
+ return eCsrStopRoaming;
+ if (!pIesLocal &&
+ !CDF_IS_STATUS_SUCCESS(csr_get_parsed_bss_description_ies(pMac,
+ pBssDesc, &pIesLocal))) {
+ sms_log(pMac, LOGE, FL("fail to parse IEs"));
+ return eCsrStopRoaming;
+ }
+ if (csr_is_infra_bss_desc(pBssDesc)) {
+ /*
+ * If we are connected in infra mode and the join bss descr is
+ * for the same BssID, then we are attempting to join the AP we
+ * are already connected with. In that case, see if the Bss or
+ * sta capabilities have changed and handle the changes
+ * without disturbing the current association
+ */
+
+ if (csr_is_conn_state_connected_infra(pMac, sessionId) &&
+ csr_is_bss_id_equal(pMac,
+ pBssDesc, pSession->pConnectBssDesc) &&
+ csr_is_ssid_equal(pMac, pSession->pConnectBssDesc,
+ pBssDesc, pIesLocal)) {
+ /*
+ * Check to see if the Auth type has changed in the
+ * profile. If so, we don't want to reassociate with
+ * authenticating first. To force this, stop the
+ * current association (Disassociate) and then re 'Join'
+ * the AP, wihch will force an Authentication (with the
+ * new Auth type) followed by a new Association.
+ */
+ if (csr_is_same_profile(pMac,
+ &pSession->connectedProfile, pProfile)) {
+ sms_log(pMac, LOGW,
+ FL("detect same profile"));
+ eRoamState =
+ csr_roam_state_for_same_profile(pMac,
+ pProfile, pSession, sessionId,
+ pIesLocal, pBssDesc);
+ } else if (!CDF_IS_STATUS_SUCCESS(
+ csr_roam_issue_disassociate(pMac,
+ sessionId,
+ eCSR_ROAM_SUBSTATE_DISASSOC_REQ,
+ false))) {
+ sms_log(pMac, LOGE,
+ FL("fail disassoc session %d"),
+ sessionId);
+ eRoamState = eCsrStopRoaming;
+ }
+ } else if (!CDF_IS_STATUS_SUCCESS(csr_roam_stop_network(pMac,
+ sessionId, pProfile, pBssDesc, pIesLocal))) {
+ /* we used to pre-auth here with open auth
+ * networks but that wasn't working so well.
+ * stop the existing network before attempting
+ * to join the new network... */
+ eRoamState = eCsrStopRoaming;
+ }
+ } else if (!CDF_IS_STATUS_SUCCESS(csr_roam_stop_network(pMac, sessionId,
+ pProfile, pBssDesc,
+ pIesLocal))) {
+ eRoamState = eCsrStopRoaming;
+ }
+
+ if (pIesLocal && !pScanResult->pvIes)
+ cdf_mem_free(pIesLocal);
+ return eRoamState;
+}
+
+CDF_STATUS csr_roam_should_roam(tpAniSirGlobal pMac, uint32_t sessionId,
+ tSirBssDescription *pBssDesc, uint32_t roamId)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tCsrRoamInfo roamInfo;
+ cdf_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0);
+ roamInfo.pBssDesc = pBssDesc;
+ status =
+ csr_roam_call_callback(pMac, sessionId, &roamInfo, roamId,
+ eCSR_ROAM_SHOULD_ROAM, eCSR_ROAM_RESULT_NONE);
+ return status;
+}
+
+/* In case no matching BSS is found, use whatever default we can find */
+static void csr_roam_assign_default_param(tpAniSirGlobal pMac, tSmeCmd *pCommand)
+{
+ /* Need to get all negotiated types in place first */
+ /* auth type */
+ /* Take the preferred Auth type. */
+ switch (pCommand->u.roamCmd.roamProfile.AuthType.authType[0]) {
+ default:
+ case eCSR_AUTH_TYPE_WPA:
+ case eCSR_AUTH_TYPE_WPA_PSK:
+ case eCSR_AUTH_TYPE_WPA_NONE:
+ case eCSR_AUTH_TYPE_OPEN_SYSTEM:
+ pCommand->u.roamCmd.roamProfile.negotiatedAuthType =
+ eCSR_AUTH_TYPE_OPEN_SYSTEM;
+ break;
+
+ case eCSR_AUTH_TYPE_SHARED_KEY:
+ pCommand->u.roamCmd.roamProfile.negotiatedAuthType =
+ eCSR_AUTH_TYPE_SHARED_KEY;
+ break;
+
+ case eCSR_AUTH_TYPE_AUTOSWITCH:
+ pCommand->u.roamCmd.roamProfile.negotiatedAuthType =
+ eCSR_AUTH_TYPE_AUTOSWITCH;
+ break;
+ }
+ pCommand->u.roamCmd.roamProfile.negotiatedUCEncryptionType =
+ pCommand->u.roamCmd.roamProfile.EncryptionType.encryptionType[0];
+ /* In this case, the multicast encryption needs to follow the uncast ones. */
+ pCommand->u.roamCmd.roamProfile.negotiatedMCEncryptionType =
+ pCommand->u.roamCmd.roamProfile.EncryptionType.encryptionType[0];
+}
+
+static void csr_set_abort_roaming_command(tpAniSirGlobal pMac, tSmeCmd *pCommand)
+{
+ switch (pCommand->u.roamCmd.roamReason) {
+ case eCsrLostLink1:
+ pCommand->u.roamCmd.roamReason = eCsrLostLink1Abort;
+ break;
+ case eCsrLostLink2:
+ pCommand->u.roamCmd.roamReason = eCsrLostLink2Abort;
+ break;
+ case eCsrLostLink3:
+ pCommand->u.roamCmd.roamReason = eCsrLostLink3Abort;
+ break;
+ default:
+ sms_log(pMac, LOGE,
+ FL(" aborting roaming reason %d not recognized"),
+ pCommand->u.roamCmd.roamReason);
+ break;
+ }
+}
+
+/**
+ * csr_roam_select_bss() - Handle join scenario based on profile
+ * @mac_ctx: Global MAC Context
+ * @roam_bss_entry: The next BSS to join
+ * @csr_result_info: Result of join
+ * @csr_scan_result: Global scan result
+ * @session_id: SME Session ID
+ * @roam_id: Roaming ID
+ * @roam_state: Current roaming state
+ * @bss_list: BSS List
+ *
+ * Return: true if the entire BSS list is done, false otherwise.
+ */
+static bool csr_roam_select_bss(tpAniSirGlobal mac_ctx,
+ tListElem *roam_bss_entry, tCsrScanResultInfo **csr_result_info,
+ tCsrScanResult **csr_scan_result, uint32_t session_id,
+ uint32_t roam_id, eCsrJoinState *roam_state,
+ tScanResultList *bss_list)
+{
+ uint8_t conc_channel = 0;
+ bool status = false;
+ tCsrScanResult *scan_result = NULL;
+ tCsrScanResultInfo *result = NULL;
+
+ while (roam_bss_entry) {
+ scan_result = GET_BASE_ADDR(roam_bss_entry, tCsrScanResult,
+ Link);
+ /*
+ * If concurrency enabled take the
+ * concurrent connected channel first.
+ * Valid multichannel concurrent
+ * sessions exempted
+ */
+ result = &scan_result->Result;
+ if (cds_concurrent_open_sessions_running() &&
+ !csr_is_valid_mc_concurrent_session(mac_ctx,
+ session_id, &result->BssDescriptor)) {
+ conc_channel = csr_get_concurrent_operation_channel(
+ mac_ctx);
+ sms_log(mac_ctx, LOG1, FL("csr Conc Channel = %d"),
+ conc_channel);
+ if ((conc_channel) && (conc_channel ==
+ result->BssDescriptor.channelId)) {
+ /*
+ * make this 0 because we do not want the below
+ * check to pass as we don't want to connect on
+ * other channel
+ */
+ sms_log(mac_ctx, LOG1, FL("Conc chnl match=%d"),
+ conc_channel);
+ conc_channel = 0;
+ }
+ }
+
+ /* Ok to roam this */
+ if (!conc_channel &&
+ CDF_IS_STATUS_SUCCESS(csr_roam_should_roam(mac_ctx,
+ session_id, &result->BssDescriptor, roam_id))) {
+ status = false;
+ break;
+ } else {
+ *roam_state = eCsrStopRoamingDueToConcurrency;
+ status = true;
+ }
+ roam_bss_entry = csr_ll_next(&bss_list->List, roam_bss_entry,
+ LL_ACCESS_LOCK);
+ }
+ *csr_result_info = result;
+ *csr_scan_result = scan_result;
+ return status;
+}
+
+/**
+ * csr_roam_join_handle_profile() - Handle join scenario based on profile
+ * @mac_ctx: Global MAC Context
+ * @session_id: SME Session ID
+ * @cmd: Command
+ * @roam_info_ptr: Pointed to the roaming info for join
+ * @roam_state: Current roaming state
+ * @result: Result of join
+ * @scan_result: Global scan result
+ *
+ * Return: None
+ */
+static void csr_roam_join_handle_profile(tpAniSirGlobal mac_ctx,
+ uint32_t session_id, tSmeCmd *cmd, tCsrRoamInfo *roam_info_ptr,
+ eCsrJoinState *roam_state, tCsrScanResultInfo *result,
+ tCsrScanResult *scan_result)
+{
+#ifndef WLAN_MDM_CODE_REDUCTION_OPT
+ uint8_t acm_mask = 0;
+#endif
+ CDF_STATUS status;
+ tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id);
+ tCsrRoamProfile *profile = &cmd->u.roamCmd.roamProfile;
+ tDot11fBeaconIEs *ies_local = NULL;
+ /*
+ * We have something to roam, tell HDD when it is infra.
+ * For IBSS, the indication goes back to HDD via eCSR_ROAM_IBSS_IND
+ * For WDS, the indication is eCSR_ROAM_WDS_IND
+ */
+ if (CSR_IS_INFRASTRUCTURE(profile)) {
+ if (roam_info_ptr && session->bRefAssocStartCnt) {
+ session->bRefAssocStartCnt--;
+ roam_info_ptr->pProfile = profile;
+ /*
+ * Complete the last assoc attempt as a
+ * new one is about to be tried
+ */
+ csr_roam_call_callback(mac_ctx, session_id,
+ roam_info_ptr, cmd->u.roamCmd.roamId,
+ eCSR_ROAM_ASSOCIATION_COMPLETION,
+ eCSR_ROAM_RESULT_NOT_ASSOCIATED);
+ }
+ /* If roaming has stopped, don't continue the roaming command */
+ if (!CSR_IS_ROAMING(session) && CSR_IS_ROAMING_COMMAND(cmd)) {
+ /* No need to complete roaming as it already complete */
+ sms_log(mac_ctx, LOGW,
+ FL(
+ "Roam cmd(reason %d)aborted as roam complete"),
+ cmd->u.roamCmd.roamReason);
+ *roam_state = eCsrStopRoaming;
+ csr_set_abort_roaming_command(mac_ctx, cmd);
+ return;
+ }
+ cdf_mem_set(roam_info_ptr, sizeof(tCsrRoamInfo), 0);
+ if (!scan_result)
+ cmd->u.roamCmd.roamProfile.uapsd_mask = 0;
+ else
+ ies_local = scan_result->Result.pvIes;
+
+ if (scan_result && !ies_local &&
+ (!CDF_IS_STATUS_SUCCESS(
+ csr_get_parsed_bss_description_ies(
+ mac_ctx,
+ &result->BssDescriptor,
+ &ies_local)))) {
+ sms_log(mac_ctx, LOGE, FL(" cannot parse IEs"));
+ *roam_state = eCsrStopRoaming;
+ return;
+ }
+ roam_info_ptr->pBssDesc = &result->BssDescriptor;
+ cmd->u.roamCmd.pLastRoamBss = roam_info_ptr->pBssDesc;
+ /* dont put uapsd_mask if BSS doesn't support uAPSD */
+ if (scan_result && cmd->u.roamCmd.roamProfile.uapsd_mask
+ && CSR_IS_QOS_BSS(ies_local)
+ && CSR_IS_UAPSD_BSS(ies_local)) {
+#ifndef WLAN_MDM_CODE_REDUCTION_OPT
+ acm_mask = sme_qos_get_acm_mask(mac_ctx,
+ &result->BssDescriptor, ies_local);
+#endif /* WLAN_MDM_CODE_REDUCTION_OPT */
+ } else {
+ cmd->u.roamCmd.roamProfile.uapsd_mask = 0;
+ }
+ if (ies_local && !result->pvIes)
+ cdf_mem_free(ies_local);
+ roam_info_ptr->pProfile = profile;
+ session->bRefAssocStartCnt++;
+ csr_roam_call_callback(mac_ctx, session_id, roam_info_ptr,
+ cmd->u.roamCmd.roamId, eCSR_ROAM_ASSOCIATION_START,
+ eCSR_ROAM_RESULT_NONE);
+ }
+ if (NULL != cmd->u.roamCmd.pRoamBssEntry) {
+ /*
+ * We have BSS
+ * Need to assign these value because
+ * they are used in csr_is_same_profile
+ */
+ scan_result = GET_BASE_ADDR(cmd->u.roamCmd.pRoamBssEntry,
+ tCsrScanResult, Link);
+ /*
+ * The OSEN IE doesn't provide the cipher suite.Therefore set
+ * to constant value of AES
+ */
+ if (cmd->u.roamCmd.roamProfile.bOSENAssociation) {
+ cmd->u.roamCmd.roamProfile.negotiatedUCEncryptionType =
+ eCSR_ENCRYPT_TYPE_AES;
+ cmd->u.roamCmd.roamProfile.negotiatedMCEncryptionType =
+ eCSR_ENCRYPT_TYPE_AES;
+ } else {
+ /* Negotiated while building scan result. */
+ cmd->u.roamCmd.roamProfile.negotiatedUCEncryptionType =
+ scan_result->ucEncryptionType;
+ cmd->u.roamCmd.roamProfile.negotiatedMCEncryptionType =
+ scan_result->mcEncryptionType;
+ }
+ cmd->u.roamCmd.roamProfile.negotiatedAuthType =
+ scan_result->authType;
+ if (CSR_IS_START_IBSS(&cmd->u.roamCmd.roamProfile)) {
+ if (csr_is_same_profile(mac_ctx,
+ &session->connectedProfile, profile)) {
+ *roam_state = eCsrStartIbssSameIbss;
+ return;
+ }
+ }
+ if (cmd->u.roamCmd.fReassocToSelfNoCapChange) {
+ /* trying to connect to the one already connected */
+ cmd->u.roamCmd.fReassocToSelfNoCapChange = false;
+ *roam_state = eCsrReassocToSelfNoCapChange;
+ return;
+ }
+ /* Attempt to Join this Bss... */
+ *roam_state = csr_roam_join(mac_ctx, session_id,
+ &scan_result->Result, profile);
+ return;
+ }
+
+ /* For an IBSS profile, then we need to start the IBSS. */
+ if (CSR_IS_START_IBSS(profile)) {
+ bool same_ibss = false;
+ /* Attempt to start this IBSS... */
+ csr_roam_assign_default_param(mac_ctx, cmd);
+ status = csr_roam_start_ibss(mac_ctx, session_id,
+ profile, &same_ibss);
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ if (same_ibss)
+ *roam_state = eCsrStartIbssSameIbss;
+ else
+ *roam_state = eCsrContinueRoaming;
+ } else {
+ /* it somehow fail need to stop */
+ *roam_state = eCsrStopRoaming;
+ }
+ return;
+ } else if ((CSR_IS_WDS_AP(profile)) ||
+ (CSR_IS_INFRA_AP(profile))) {
+ /* Attempt to start this WDS... */
+ csr_roam_assign_default_param(mac_ctx, cmd);
+ /* For AP WDS, we dont have any BSSDescription */
+ status = csr_roam_start_wds(mac_ctx, session_id, profile, NULL);
+ if (CDF_IS_STATUS_SUCCESS(status))
+ *roam_state = eCsrContinueRoaming;
+ else
+ *roam_state = eCsrStopRoaming;
+ } else {
+ /* Nothing we can do */
+ sms_log(mac_ctx, LOGW, FL("cannot continue without BSS list"));
+ *roam_state = eCsrStopRoaming;
+ return;
+ }
+
+}
+/**
+ * csr_roam_join_next_bss() - Pick the next BSS for join
+ * @mac_ctx: Global MAC Context
+ * @cmd: Command
+ * @use_same_bss: Use Same BSS to Join
+ *
+ * Return: The Join State
+ */
+static eCsrJoinState csr_roam_join_next_bss(tpAniSirGlobal mac_ctx,
+ tSmeCmd *cmd, bool use_same_bss)
+{
+ tCsrScanResult *scan_result = NULL;
+ eCsrJoinState roam_state = eCsrStopRoaming;
+ tScanResultList *bss_list =
+ (tScanResultList *) cmd->u.roamCmd.hBSSList;
+ bool done = false;
+ tCsrRoamInfo roam_info, *roam_info_ptr = NULL;
+ uint32_t session_id = cmd->sessionId;
+ tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id);
+ tCsrRoamProfile *profile = &cmd->u.roamCmd.roamProfile;
+ tCsrRoamJoinStatus *join_status;
+ tCsrScanResultInfo *result = NULL;
+
+ if (!session) {
+ sms_log(mac_ctx, LOGE, FL("session %d not found"), session_id);
+ return eCsrStopRoaming;
+ }
+
+ cdf_mem_set(&roam_info, sizeof(roam_info), 0);
+ cdf_mem_copy(&roam_info.bssid, &session->joinFailStatusCode.bssId,
+ sizeof(tSirMacAddr));
+ /*
+ * When handling AP's capability change, continue to associate
+ * to same BSS and make sure pRoamBssEntry is not Null.
+ */
+ if ((NULL != bss_list) &&
+ ((false == use_same_bss) ||
+ (cmd->u.roamCmd.pRoamBssEntry == NULL))) {
+ if (cmd->u.roamCmd.pRoamBssEntry == NULL) {
+ /* Try the first BSS */
+ cmd->u.roamCmd.pLastRoamBss = NULL;
+ cmd->u.roamCmd.pRoamBssEntry =
+ csr_ll_peek_head(&bss_list->List,
+ LL_ACCESS_LOCK);
+ } else {
+ cmd->u.roamCmd.pRoamBssEntry =
+ csr_ll_next(&bss_list->List,
+ cmd->u.roamCmd.pRoamBssEntry,
+ LL_ACCESS_LOCK);
+ /*
+ * Done with all the BSSs.
+ * In this case, will tell HDD the
+ * completion
+ */
+ if (NULL == cmd->u.roamCmd.pRoamBssEntry)
+ goto end;
+ /*
+ * We need to indicate to HDD that we
+ * are done with this one.
+ */
+ roam_info.pBssDesc = cmd->u.roamCmd.pLastRoamBss;
+ join_status = &session->joinFailStatusCode;
+ roam_info.statusCode = join_status->statusCode;
+ roam_info.reasonCode = join_status->reasonCode;
+ roam_info_ptr = &roam_info;
+ }
+ done = csr_roam_select_bss(mac_ctx,
+ cmd->u.roamCmd.pRoamBssEntry, &result,
+ &scan_result, session_id, cmd->u.roamCmd.roamId,
+ &roam_state, bss_list);
+ if (done)
+ goto end;
+ }
+ if (!roam_info_ptr)
+ roam_info_ptr = &roam_info;
+ roam_info_ptr->u.pConnectedProfile = &session->connectedProfile;
+ csr_roam_join_handle_profile(mac_ctx, session_id, cmd, roam_info_ptr,
+ &roam_state, result, scan_result);
+end:
+ if ((eCsrStopRoaming == roam_state) && CSR_IS_INFRASTRUCTURE(profile) &&
+ (session->bRefAssocStartCnt > 0)) {
+ /*
+ * Need to indicate association_completion if association_start
+ * has been done
+ */
+ session->bRefAssocStartCnt--;
+ /*
+ * Complete the last assoc attempte as a
+ * new one is about to be tried
+ */
+ roam_info_ptr = &roam_info;
+ roam_info_ptr->pProfile = profile;
+ csr_roam_call_callback(mac_ctx, session_id,
+ roam_info_ptr, cmd->u.roamCmd.roamId,
+ eCSR_ROAM_ASSOCIATION_COMPLETION,
+ eCSR_ROAM_RESULT_NOT_ASSOCIATED);
+ }
+
+ return roam_state;
+}
+
+static CDF_STATUS csr_roam(tpAniSirGlobal pMac, tSmeCmd *pCommand)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ eCsrJoinState RoamState;
+ eCsrRoamSubState substate;
+ uint32_t sessionId = pCommand->sessionId;
+
+ /* Attept to join a Bss... */
+ RoamState = csr_roam_join_next_bss(pMac, pCommand, false);
+
+ /* if nothing to join.. */
+ if ((eCsrStopRoaming == RoamState) ||
+ (eCsrStopRoamingDueToConcurrency == RoamState)) {
+ bool fComplete = false;
+ /* and if connected in Infrastructure mode... */
+ if (csr_is_conn_state_infra(pMac, sessionId)) {
+ /* ... then we need to issue a disassociation */
+ substate = eCSR_ROAM_SUBSTATE_DISASSOC_NOTHING_TO_JOIN;
+ status = csr_roam_issue_disassociate(pMac, sessionId,
+ substate, false);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGW,
+ FL("fail issuing disassoc status = %d"),
+ status);
+ /*
+ * roam command is completed by caller in the
+ * failed case
+ */
+ fComplete = true;
+ }
+ } else if (csr_is_conn_state_ibss(pMac, sessionId)) {
+ status = csr_roam_issue_stop_bss(pMac, sessionId,
+ eCSR_ROAM_SUBSTATE_STOP_BSS_REQ);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGW,
+ FL("fail issuing stop bss status = %d"),
+ status);
+ /*
+ * roam command is completed by caller in the
+ * failed case
+ */
+ fComplete = true;
+ }
+ } else if (csr_is_conn_state_connected_infra_ap(pMac,
+ sessionId)) {
+ substate = eCSR_ROAM_SUBSTATE_STOP_BSS_REQ;
+ status = csr_roam_issue_stop_bss(pMac, sessionId,
+ substate);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGW,
+ FL("fail issuing stop bss status = %d"),
+ status);
+ /*
+ * roam command is completed by caller in the
+ * failed case
+ */
+ fComplete = true;
+ }
+ } else {
+ fComplete = true;
+ }
+
+ if (fComplete) {
+ /* otherwise, we can complete the Roam command here. */
+ if (eCsrStopRoamingDueToConcurrency == RoamState)
+ csr_roam_complete(pMac,
+ eCsrJoinFailureDueToConcurrency, NULL);
+ else
+ csr_roam_complete(pMac,
+ eCsrNothingToJoin, NULL);
+ }
+ } else if (eCsrReassocToSelfNoCapChange == RoamState) {
+ csr_roam_complete(pMac, eCsrSilentlyStopRoamingSaveState,
+ NULL);
+ } else if (eCsrStartIbssSameIbss == RoamState) {
+ csr_roam_complete(pMac, eCsrSilentlyStopRoaming, NULL);
+ }
+
+ return status;
+}
+
+CDF_STATUS csr_process_ft_reassoc_roam_command(tpAniSirGlobal pMac,
+ tSmeCmd *pCommand)
+{
+ uint32_t sessionId;
+ tCsrRoamSession *pSession;
+ tCsrScanResult *pScanResult = NULL;
+ tSirBssDescription *pBssDesc = NULL;
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ sessionId = pCommand->sessionId;
+ pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ if (CSR_IS_ROAMING(pSession) && pSession->fCancelRoaming) {
+ /* the roaming is cancelled. Simply complete the command */
+ sms_log(pMac, LOG1, FL("Roam command canceled"));
+ csr_roam_complete(pMac, eCsrNothingToJoin, NULL);
+ return CDF_STATUS_E_FAILURE;
+ }
+ if (pCommand->u.roamCmd.pRoamBssEntry) {
+ pScanResult =
+ GET_BASE_ADDR(pCommand->u.roamCmd.pRoamBssEntry,
+ tCsrScanResult, Link);
+ pBssDesc = &pScanResult->Result.BssDescriptor;
+ } else {
+ /* the roaming is cancelled. Simply complete the command */
+ sms_log(pMac, LOG1, FL("Roam command canceled"));
+ csr_roam_complete(pMac, eCsrNothingToJoin, NULL);
+ return CDF_STATUS_E_FAILURE;
+ }
+ status = csr_roam_issue_reassociate(pMac, sessionId, pBssDesc,
+ (tDot11fBeaconIEs *) (pScanResult->
+ Result.pvIes),
+ &pCommand->u.roamCmd.roamProfile);
+ return status;
+}
+
+/**
+ * csr_roam_trigger_reassociate() - Helper function to trigger reassociate
+ * @mac_ctx: pointer to mac context
+ * @cmd: sme command
+ * @roam_info: Roaming infor structure
+ * @session_ptr: session pointer
+ * @session_id: session id
+ *
+ * This function will trigger reassociate.
+ *
+ * Return: CDF_STATUS for success or failure.
+ */
+static CDF_STATUS csr_roam_trigger_reassociate(tpAniSirGlobal mac_ctx,
+ tSmeCmd *cmd, tCsrRoamInfo *roam_info,
+ tCsrRoamSession *session_ptr, uint32_t session_id)
+{
+ tDot11fBeaconIEs *pIes = NULL;
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+
+ if (session_ptr->pConnectBssDesc) {
+ status = csr_get_parsed_bss_description_ies(mac_ctx,
+ session_ptr->pConnectBssDesc, &pIes);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(mac_ctx, LOGE, FL("fail to parse IEs"));
+ } else {
+ roam_info->reasonCode =
+ eCsrRoamReasonStaCapabilityChanged;
+ csr_roam_call_callback(mac_ctx, session_ptr->sessionId,
+ roam_info, 0, eCSR_ROAM_ROAMING_START,
+ eCSR_ROAM_RESULT_NONE);
+ session_ptr->roamingReason = eCsrReassocRoaming;
+ roam_info->pBssDesc = session_ptr->pConnectBssDesc;
+ roam_info->pProfile = &cmd->u.roamCmd.roamProfile;
+ session_ptr->bRefAssocStartCnt++;
+ csr_roam_call_callback(mac_ctx, session_id, roam_info,
+ cmd->u.roamCmd.roamId,
+ eCSR_ROAM_ASSOCIATION_START,
+ eCSR_ROAM_RESULT_NONE);
+
+ sms_log(mac_ctx, LOG1,
+ FL("calling csr_roam_issue_reassociate"));
+ status = csr_roam_issue_reassociate(mac_ctx, session_id,
+ session_ptr->pConnectBssDesc, pIes,
+ &cmd->u.roamCmd.roamProfile);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(mac_ctx, LOGE, FL("failed status %d"),
+ status);
+ csr_release_command_roam(mac_ctx, cmd);
+ }
+
+ cdf_mem_free(pIes);
+ pIes = NULL;
+ }
+ } else {
+ sms_log(mac_ctx, LOGE, FL
+ ("reassoc to same AP failed as connected BSS is NULL"));
+ status = CDF_STATUS_E_FAILURE;
+ }
+ return status;
+}
+
+CDF_STATUS csr_roam_process_command(tpAniSirGlobal pMac, tSmeCmd *pCommand)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tCsrRoamInfo roamInfo;
+ uint32_t sessionId = pCommand->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, LOG1, FL("Roam Reason : %d, sessionId: %d"),
+ pCommand->u.roamCmd.roamReason, sessionId);
+
+ switch (pCommand->u.roamCmd.roamReason) {
+ case eCsrForcedDisassoc:
+ if (eCSR_ROAMING_STATE_IDLE == pMac->roam.curState[sessionId]) {
+ sms_log(pMac, LOGE,
+ FL("Ignore eCsrForcedDisassoc cmd on roam state"
+ " %d"), eCSR_ROAMING_STATE_IDLE);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ status = csr_roam_process_disassoc_deauth(pMac, pCommand,
+ true, false);
+ csr_free_roam_profile(pMac, sessionId);
+ break;
+ case eCsrSmeIssuedDisassocForHandoff:
+ /* Not to free pMac->roam.pCurRoamProfile (via
+ * csr_free_roam_profile) because its needed after disconnect */
+ status = csr_roam_process_disassoc_deauth(pMac, pCommand,
+ true, false);
+
+ break;
+ case eCsrForcedDisassocMICFailure:
+ status = csr_roam_process_disassoc_deauth(pMac, pCommand,
+ true, true);
+ csr_free_roam_profile(pMac, sessionId);
+ break;
+ case eCsrForcedDeauth:
+ status = csr_roam_process_disassoc_deauth(pMac, pCommand,
+ false, false);
+ csr_free_roam_profile(pMac, sessionId);
+ break;
+ case eCsrHddIssuedReassocToSameAP:
+ case eCsrSmeIssuedReassocToSameAP:
+ status = csr_roam_trigger_reassociate(pMac, pCommand, &roamInfo,
+ pSession, sessionId);
+ break;
+ case eCsrCapsChange:
+ sms_log(pMac, LOGE, FL("received eCsrCapsChange "));
+ csr_roam_state_change(pMac, eCSR_ROAMING_STATE_JOINING,
+ sessionId);
+ status = csr_roam_issue_disassociate(pMac, sessionId,
+ eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING,
+ false);
+ break;
+ case eCsrSmeIssuedFTReassoc:
+ sms_log(pMac, LOG1, FL("received FT Reassoc Req "));
+ status = csr_process_ft_reassoc_roam_command(pMac, pCommand);
+ break;
+
+ case eCsrStopBss:
+ csr_roam_state_change(pMac, eCSR_ROAMING_STATE_JOINING,
+ sessionId);
+ status = csr_roam_issue_stop_bss(pMac, sessionId,
+ eCSR_ROAM_SUBSTATE_STOP_BSS_REQ);
+ break;
+
+ case eCsrForcedDisassocSta:
+ csr_roam_state_change(pMac, eCSR_ROAMING_STATE_JOINING,
+ sessionId);
+ csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_DISASSOC_REQ,
+ sessionId);
+ status = csr_send_mb_disassoc_req_msg(pMac, sessionId,
+ pCommand->u.roamCmd.peerMac,
+ pCommand->u.roamCmd.reason);
+ break;
+
+ case eCsrForcedDeauthSta:
+ csr_roam_state_change(pMac, eCSR_ROAMING_STATE_JOINING,
+ sessionId);
+ csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_DEAUTH_REQ,
+ sessionId);
+ status = csr_send_mb_deauth_req_msg(pMac, sessionId,
+ pCommand->u.roamCmd.peerMac,
+ pCommand->u.roamCmd.reason);
+ break;
+
+ case eCsrPerformPreauth:
+ sms_log(pMac, LOG1, FL("Attempting FT PreAuth Req"));
+ status = csr_roam_issue_ft_preauth_req(pMac, sessionId,
+ pCommand->u.roamCmd.pLastRoamBss);
+ break;
+ default:
+ csr_roam_state_change(pMac, eCSR_ROAMING_STATE_JOINING,
+ sessionId);
+
+ if (pCommand->u.roamCmd.fUpdateCurRoamProfile) {
+ /* Remember the roaming profile */
+ csr_free_roam_profile(pMac, sessionId);
+ pSession->pCurRoamProfile =
+ cdf_mem_malloc(sizeof(tCsrRoamProfile));
+ if (NULL != pSession->pCurRoamProfile) {
+ cdf_mem_set(pSession->pCurRoamProfile,
+ sizeof(tCsrRoamProfile), 0);
+ csr_roam_copy_profile(pMac,
+ pSession->pCurRoamProfile,
+ &pCommand->u.roamCmd.roamProfile);
+ }
+ }
+ /*
+ * At this point original uapsd_mask is saved in
+ * pCurRoamProfile. uapsd_mask in the pCommand may change from
+ * this point on. Attempt to roam with the new scan results
+ * (if we need to..)
+ */
+ status = csr_roam(pMac, pCommand);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ sms_log(pMac, LOGW,
+ FL("csr_roam() failed with status = 0x%08X"),
+ status);
+ break;
+ }
+ return status;
+}
+
+void csr_reinit_preauth_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand)
+{
+ pCommand->u.roamCmd.pLastRoamBss = NULL;
+ pCommand->u.roamCmd.pRoamBssEntry = NULL;
+ /* Because u.roamCmd is union and share with scanCmd and StatusChange */
+ cdf_mem_set(&pCommand->u.roamCmd, sizeof(tRoamCmd), 0);
+}
+
+void csr_reinit_roam_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand)
+{
+ if (pCommand->u.roamCmd.fReleaseBssList) {
+ csr_scan_result_purge(pMac, pCommand->u.roamCmd.hBSSList);
+ pCommand->u.roamCmd.fReleaseBssList = false;
+ pCommand->u.roamCmd.hBSSList = CSR_INVALID_SCANRESULT_HANDLE;
+ }
+ if (pCommand->u.roamCmd.fReleaseProfile) {
+ csr_release_profile(pMac, &pCommand->u.roamCmd.roamProfile);
+ pCommand->u.roamCmd.fReleaseProfile = false;
+ }
+ pCommand->u.roamCmd.pRoamBssEntry = NULL;
+ /* Because u.roamCmd is union and share with scanCmd and StatusChange */
+ cdf_mem_set(&pCommand->u.roamCmd, sizeof(tRoamCmd), 0);
+}
+
+void csr_reinit_wm_status_change_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand)
+{
+ cdf_mem_set(&pCommand->u.wmStatusChangeCmd, sizeof(tWmStatusChangeCmd),
+ 0);
+}
+
+void csr_roam_complete(tpAniSirGlobal pMac, eCsrRoamCompleteResult Result,
+ void *Context)
+{
+ tListElem *pEntry;
+ tSmeCmd *pCommand;
+ bool fReleaseCommand = true;
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ "%s: Roam Completion ...", __func__);
+ pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK);
+ if (pEntry) {
+ pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
+ /* If the head of the queue is Active and it is a ROAM command, remove */
+ /* and put this on the Free queue. */
+ if (eSmeCommandRoam == pCommand->command) {
+ /* we need to process the result first before removing it from active list because state changes */
+ /* still happening insides roamQProcessRoamResults so no other roam command should be issued */
+ fReleaseCommand =
+ csr_roam_process_results(pMac, pCommand, Result,
+ Context);
+ if (fReleaseCommand) {
+ if (csr_ll_remove_entry
+ (&pMac->sme.smeCmdActiveList, pEntry,
+ LL_ACCESS_LOCK)) {
+ csr_release_command_roam(pMac, pCommand);
+ } else {
+ sms_log(pMac, LOGE,
+ " **********csr_roam_complete fail to release command reason %d",
+ pCommand->u.roamCmd.roamReason);
+ }
+ } else {
+ sms_log(pMac, LOGE,
+ " **********csr_roam_complete fail to release command reason %d",
+ pCommand->u.roamCmd.roamReason);
+ }
+ } else {
+ sms_log(pMac, LOGW,
+ "CSR: Roam Completion called but ROAM command is not ACTIVE ...");
+ }
+ } else {
+ sms_log(pMac, LOGW,
+ "CSR: Roam Completion called but NO commands are ACTIVE ...");
+ }
+ if (fReleaseCommand) {
+ sme_process_pending_queue(pMac);
+ }
+}
+
+void csr_reset_pmkid_candidate_list(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_mem_set(&(pSession->PmkidCandidateInfo[0]),
+ sizeof(tPmkidCandidateInfo) * CSR_MAX_PMKID_ALLOWED, 0);
+ pSession->NumPmkidCandidate = 0;
+}
+
+#ifdef FEATURE_WLAN_WAPI
+void csr_reset_bkid_candidate_list(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_mem_set(&(pSession->BkidCandidateInfo[0]),
+ sizeof(tBkidCandidateInfo) * CSR_MAX_BKID_ALLOWED, 0);
+ pSession->NumBkidCandidate = 0;
+}
+#endif /* FEATURE_WLAN_WAPI */
+extern uint8_t csr_wpa_oui[][CSR_WPA_OUI_SIZE];
+
+/**
+ * csr_roam_save_params() - Helper function to save params
+ * @mac_ctx: pointer to mac context
+ * @session_ptr: Session pointer
+ * @auth_type: auth type
+ * @ie_ptr: pointer to ie
+ * @ie_local: pointr to local ie
+ *
+ * This function will save params to session
+ *
+ * Return: none.
+ */
+static CDF_STATUS csr_roam_save_params(tpAniSirGlobal mac_ctx,
+ tCsrRoamSession *session_ptr,
+ eCsrAuthType auth_type,
+ tDot11fBeaconIEs *ie_ptr,
+ tDot11fBeaconIEs *ie_local)
+{
+ uint32_t nIeLen;
+ uint8_t *pIeBuf;
+
+ if ((eCSR_AUTH_TYPE_RSN == auth_type) ||
+#if defined WLAN_FEATURE_VOWIFI_11R
+ (eCSR_AUTH_TYPE_FT_RSN == auth_type) ||
+ (eCSR_AUTH_TYPE_FT_RSN_PSK == auth_type) ||
+#endif /* WLAN_FEATURE_VOWIFI_11R */
+#if defined WLAN_FEATURE_11W
+ (eCSR_AUTH_TYPE_RSN_PSK_SHA256 == auth_type) ||
+ (eCSR_AUTH_TYPE_RSN_8021X_SHA256 == auth_type) ||
+#endif
+ (eCSR_AUTH_TYPE_RSN_PSK == auth_type)) {
+ if (ie_local->RSN.present) {
+ tDot11fIERSN *rsnie = &ie_local->RSN;
+ /*
+ * Calculate the actual length
+ * version + gp_cipher_suite + pwise_cipher_suite_count
+ * + akm_suite_count + reserved + pwise_cipher_suites
+ */
+ nIeLen = 8 + 2 + 2
+ + (rsnie->pwise_cipher_suite_count * 4)
+ + (rsnie->akm_suite_count * 4);
+ if (rsnie->pmkid_count)
+ /* pmkid */
+ nIeLen += 2 + rsnie->pmkid_count * 4;
+
+ /* nIeLen doesn't count EID and length fields */
+ session_ptr->pWpaRsnRspIE = cdf_mem_malloc(nIeLen + 2);
+ if (NULL == session_ptr->pWpaRsnRspIE)
+ return CDF_STATUS_E_NOMEM;
+
+ cdf_mem_set(session_ptr->pWpaRsnRspIE,
+ nIeLen + 2, 0);
+ session_ptr->pWpaRsnRspIE[0] = DOT11F_EID_RSN;
+ session_ptr->pWpaRsnRspIE[1] = (uint8_t) nIeLen;
+ /* copy upto akm_suites */
+ pIeBuf = session_ptr->pWpaRsnRspIE + 2;
+ cdf_mem_copy(pIeBuf, &rsnie->version,
+ sizeof(rsnie->version));
+ pIeBuf += sizeof(rsnie->version);
+ cdf_mem_copy(pIeBuf, &rsnie->gp_cipher_suite,
+ sizeof(rsnie->gp_cipher_suite));
+ pIeBuf += sizeof(rsnie->gp_cipher_suite);
+ cdf_mem_copy(pIeBuf, &rsnie->pwise_cipher_suite_count,
+ sizeof(rsnie->pwise_cipher_suite_count));
+ pIeBuf += sizeof(rsnie->pwise_cipher_suite_count);
+ if (rsnie->pwise_cipher_suite_count) {
+ /* copy pwise_cipher_suites */
+ cdf_mem_copy(pIeBuf, rsnie->pwise_cipher_suites,
+ rsnie->pwise_cipher_suite_count * 4);
+ pIeBuf += rsnie->pwise_cipher_suite_count * 4;
+ }
+ cdf_mem_copy(pIeBuf, &rsnie->akm_suite_count, 2);
+ pIeBuf += 2;
+ if (rsnie->akm_suite_count) {
+ /* copy akm_suites */
+ cdf_mem_copy(pIeBuf, rsnie->akm_suites,
+ rsnie->akm_suite_count * 4);
+ pIeBuf += rsnie->akm_suite_count * 4;
+ }
+ /* copy the rest */
+ cdf_mem_copy(pIeBuf, rsnie->akm_suites +
+ rsnie->akm_suite_count * 4,
+ 2 + rsnie->pmkid_count * 4);
+ session_ptr->nWpaRsnRspIeLength = nIeLen + 2;
+ }
+ } else if ((eCSR_AUTH_TYPE_WPA == auth_type) ||
+ (eCSR_AUTH_TYPE_WPA_PSK == auth_type)) {
+ if (ie_local->WPA.present) {
+ tDot11fIEWPA *wpaie = &ie_local->WPA;
+ /* Calculate the actual length wpaie */
+ nIeLen = 12 + 2 /* auth_suite_count */
+ + wpaie->unicast_cipher_count * 4
+ + wpaie->auth_suite_count * 4;
+
+ /* The WPA capabilities follows the Auth Suite
+ * (two octects)-- this field is optional, and
+ * we always "send" zero, so just remove it. This is
+ * consistent with our assumptions in the frames
+ * compiler; nIeLen doesn't count EID & length fields */
+ session_ptr->pWpaRsnRspIE = cdf_mem_malloc(nIeLen + 2);
+ if (NULL == session_ptr->pWpaRsnRspIE)
+ return CDF_STATUS_E_NOMEM;
+ session_ptr->pWpaRsnRspIE[0] = DOT11F_EID_WPA;
+ session_ptr->pWpaRsnRspIE[1] = (uint8_t) nIeLen;
+ pIeBuf = session_ptr->pWpaRsnRspIE + 2;
+ /* Copy WPA OUI */
+ cdf_mem_copy(pIeBuf, &csr_wpa_oui[1], 4);
+ pIeBuf += 4;
+ cdf_mem_copy(pIeBuf, &wpaie->version,
+ 8 + wpaie->unicast_cipher_count * 4);
+ pIeBuf += 8 + wpaie->unicast_cipher_count * 4;
+ cdf_mem_copy(pIeBuf, &wpaie->auth_suite_count,
+ 2 + wpaie->auth_suite_count * 4);
+ pIeBuf += wpaie->auth_suite_count * 4;
+ session_ptr->nWpaRsnRspIeLength = nIeLen + 2;
+ }
+ }
+#ifdef FEATURE_WLAN_WAPI
+ else if ((eCSR_AUTH_TYPE_WAPI_WAI_PSK == auth_type) ||
+ (eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE ==
+ auth_type)) {
+ if (ie_local->WAPI.present) {
+ tDot11fIEWAPI *wapi_ie = &ie_local->WAPI;
+ /* Calculate the actual length of wapi ie*/
+ nIeLen = 4 + 2 /* pwise_cipher_suite_count */
+ + wapi_ie->akm_suite_count * 4
+ + wapi_ie->unicast_cipher_suite_count * 4
+ + 6; /* gp_cipher_suite + preauth + reserved */
+
+ if (wapi_ie->bkid_count)
+ nIeLen += 2 + wapi_ie->bkid_count * 4;
+
+ /* nIeLen doesn't count EID and length fields */
+ session_ptr->pWapiRspIE =
+ cdf_mem_malloc(nIeLen + 2);
+ if (NULL == session_ptr->pWapiRspIE)
+ return CDF_STATUS_E_NOMEM;
+ session_ptr->pWapiRspIE[0] = DOT11F_EID_WAPI;
+ session_ptr->pWapiRspIE[1] = (uint8_t) nIeLen;
+ pIeBuf = session_ptr->pWapiRspIE + 2;
+ /* copy upto akm_suite_count */
+ cdf_mem_copy(pIeBuf, &wapi_ie->version, 2);
+ pIeBuf += 4;
+ if (wapi_ie->akm_suite_count) {
+ /* copy akm_suites */
+ cdf_mem_copy(pIeBuf,
+ wapi_ie->akm_suites,
+ wapi_ie->akm_suite_count * 4);
+ pIeBuf += wapi_ie->akm_suite_count * 4;
+ }
+ cdf_mem_copy(pIeBuf,
+ &wapi_ie->unicast_cipher_suite_count, 2);
+ pIeBuf += 2;
+ if (wapi_ie->unicast_cipher_suite_count) {
+ uint16_t suite_size =
+ wapi_ie->unicast_cipher_suite_count * 4;
+ /* copy pwise_cipher_suites */
+ cdf_mem_copy(pIeBuf,
+ wapi_ie->unicast_cipher_suites,
+ suite_size);
+ pIeBuf += suite_size;
+ }
+ /* gp_cipher_suite */
+ cdf_mem_copy(pIeBuf,
+ wapi_ie->multicast_cipher_suite, 4);
+ pIeBuf += 4;
+ /* preauth + reserved */
+ cdf_mem_copy(pIeBuf,
+ wapi_ie->multicast_cipher_suite + 4, 2);
+ pIeBuf += 2;
+ if (wapi_ie->bkid_count) {
+ /* bkid_count */
+ cdf_mem_copy(pIeBuf, &wapi_ie->bkid_count, 2);
+ pIeBuf += 2;
+ /* copy akm_suites */
+ cdf_mem_copy(pIeBuf, wapi_ie->bkid,
+ wapi_ie->bkid_count * 4);
+ pIeBuf += wapi_ie->bkid_count * 4;
+ }
+ session_ptr->nWapiRspIeLength = nIeLen + 2;
+ }
+ }
+#endif /* FEATURE_WLAN_WAPI */
+ return CDF_STATUS_SUCCESS;
+}
+
+static CDF_STATUS csr_roam_save_security_rsp_ie(tpAniSirGlobal pMac,
+ uint32_t sessionId,
+ eCsrAuthType authType,
+ tSirBssDescription *pSirBssDesc,
+ tDot11fBeaconIEs *pIes)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+ tDot11fBeaconIEs *pIesLocal = pIes;
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL("session %d not found"), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+ if (pSession->roamOffloadSynchParams.bRoamSynchInProgress) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ FL("LFR3:csr_roam_save_security_rsp_ie"));
+ }
+#endif
+
+ if ((eCSR_AUTH_TYPE_WPA == authType) ||
+ (eCSR_AUTH_TYPE_WPA_PSK == authType) ||
+ (eCSR_AUTH_TYPE_RSN == authType) ||
+ (eCSR_AUTH_TYPE_RSN_PSK == authType)
+#if defined WLAN_FEATURE_VOWIFI_11R
+ || (eCSR_AUTH_TYPE_FT_RSN == authType) ||
+ (eCSR_AUTH_TYPE_FT_RSN_PSK == authType)
+#endif /* FEATURE_WLAN_WAPI */
+#ifdef FEATURE_WLAN_WAPI
+ || (eCSR_AUTH_TYPE_WAPI_WAI_PSK == authType) ||
+ (eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE == authType)
+#endif /* FEATURE_WLAN_WAPI */
+#ifdef WLAN_FEATURE_11W
+ || (eCSR_AUTH_TYPE_RSN_PSK_SHA256 == authType) ||
+ (eCSR_AUTH_TYPE_RSN_8021X_SHA256 == authType)
+#endif /* FEATURE_WLAN_WAPI */
+ ) {
+ if (!pIesLocal && !CDF_IS_STATUS_SUCCESS
+ (csr_get_parsed_bss_description_ies(pMac,
+ pSirBssDesc, &pIesLocal)))
+ sms_log(pMac, LOGE, FL(" cannot parse IEs"));
+ if (pIesLocal) {
+ status = csr_roam_save_params(pMac, pSession, authType,
+ pIes, pIesLocal);
+ if (!pIes)
+ /* locally allocated */
+ cdf_mem_free(pIesLocal);
+ }
+ }
+ return status;
+}
+
+#ifdef WLAN_FEATURE_VOWIFI_11R
+/* Returns whether the current association is a 11r assoc or not */
+bool csr_roam_is11r_assoc(tpAniSirGlobal pMac, uint8_t sessionId)
+{
+#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING
+ return csr_neighbor_roam_is11r_assoc(pMac, sessionId);
+#else
+ return false;
+#endif
+}
+#endif
+#ifdef FEATURE_WLAN_ESE
+/* Returns whether the current association is a ESE assoc or not */
+bool csr_roam_is_ese_assoc(tpAniSirGlobal pMac, uint8_t sessionId)
+{
+#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING
+ return csr_neighbor_roam_is_ese_assoc(pMac, sessionId);
+#else
+ return false;
+#endif
+}
+#endif
+#ifdef FEATURE_WLAN_LFR
+/* Returns whether "Legacy Fast Roaming" is currently enabled...or not */
+bool csr_roam_is_fast_roam_enabled(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ tCsrRoamSession *pSession = NULL;
+
+ if (CSR_IS_SESSION_VALID(pMac, sessionId)) {
+ pSession = CSR_GET_SESSION(pMac, sessionId);
+ if (NULL != pSession->pCurRoamProfile) {
+ if (pSession->pCurRoamProfile->csrPersona !=
+ CDF_STA_MODE) {
+ return false;
+ }
+ }
+ }
+ if (true == CSR_IS_FASTROAM_IN_CONCURRENCY_INI_FEATURE_ENABLED(pMac)) {
+ return pMac->roam.configParam.isFastRoamIniFeatureEnabled;
+ } else {
+ return pMac->roam.configParam.isFastRoamIniFeatureEnabled &&
+ (!csr_is_concurrent_session_running(pMac));
+ }
+}
+
+#ifdef FEATURE_WLAN_ESE
+/**
+ * csr_neighbor_roam_is_ese_assoc() - Check the Association type
+ * @mac_ctx: Global MAC Context
+ * @session_id: Session ID on which the check should be done
+ *
+ * This function returns whether the current association
+ * is a ESE assoc or not
+ *
+ * Return: True if ESE association, false otherwise.
+ **/
+bool csr_neighbor_roam_is_ese_assoc(tpAniSirGlobal mac_ctx, uint8_t session_id)
+{
+ return mac_ctx->roam.neighborRoamInfo[session_id].isESEAssoc;
+}
+#endif /* FEATURE_WLAN_ESE */
+
+/* Returns whether "FW based BG scan" is currently enabled...or not */
+bool csr_roam_is_roam_offload_scan_enabled(tpAniSirGlobal pMac)
+{
+ return pMac->roam.configParam.isRoamOffloadScanEnabled;
+}
+#endif
+
+#if defined(FEATURE_WLAN_ESE)
+bool csr_roam_is_ese_ini_feature_enabled(tpAniSirGlobal pMac)
+{
+ return pMac->roam.configParam.isEseIniFeatureEnabled;
+}
+#endif /*FEATURE_WLAN_ESE */
+
+#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH
+eCsrPhyMode csr_roamdot11mode_to_phymode(uint8_t dot11mode)
+{
+ eCsrPhyMode phymode = eCSR_DOT11_MODE_abg;
+
+ switch (dot11mode) {
+ case WNI_CFG_DOT11_MODE_ALL:
+ phymode = eCSR_DOT11_MODE_abg;
+ break;
+ case WNI_CFG_DOT11_MODE_11A:
+ phymode = eCSR_DOT11_MODE_11a;
+ break;
+ case WNI_CFG_DOT11_MODE_11B:
+ phymode = eCSR_DOT11_MODE_11b;
+ break;
+ case WNI_CFG_DOT11_MODE_11G:
+ phymode = eCSR_DOT11_MODE_11g;
+ break;
+ case WNI_CFG_DOT11_MODE_11N:
+ phymode = eCSR_DOT11_MODE_11n;
+ break;
+ case WNI_CFG_DOT11_MODE_11G_ONLY:
+ phymode = eCSR_DOT11_MODE_11g_ONLY;
+ break;
+ case WNI_CFG_DOT11_MODE_11N_ONLY:
+ phymode = eCSR_DOT11_MODE_11n_ONLY;
+ break;
+ case WNI_CFG_DOT11_MODE_11AC:
+ phymode = eCSR_DOT11_MODE_11ac;
+ break;
+ case WNI_CFG_DOT11_MODE_11AC_ONLY:
+ phymode = eCSR_DOT11_MODE_11ac_ONLY;
+ break;
+ default:
+ break;
+ }
+
+ return phymode;
+}
+#endif
+
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+CDF_STATUS csr_roam_offload_send_synch_cnf(tpAniSirGlobal pMac, uint8_t sessionId)
+{
+ tpSirSmeRoamOffloadSynchCnf pRoamOffloadSynchCnf;
+ cds_msg_t msg;
+ tCsrRoamSession *pSession = &pMac->roam.roamSession[sessionId];
+ pRoamOffloadSynchCnf =
+ cdf_mem_malloc(sizeof(tSirSmeRoamOffloadSynchCnf));
+ if (NULL == pRoamOffloadSynchCnf) {
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_ERROR,
+ "%s: not able to allocate memory for roam"
+ "offload synch confirmation data", __func__);
+ pSession->roamOffloadSynchParams.bRoamSynchInProgress =
+ false;
+ return CDF_STATUS_E_NOMEM;
+ }
+ pRoamOffloadSynchCnf->sessionId = sessionId;
+ msg.type = WMA_ROAM_OFFLOAD_SYNCH_CNF;
+ msg.reserved = 0;
+ msg.bodyptr = pRoamOffloadSynchCnf;
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ "LFR3: Posting WMA_ROAM_OFFLOAD_SYNCH_CNF");
+ if (!CDF_IS_STATUS_SUCCESS
+ (cds_mq_post_message(CDF_MODULE_ID_WMA, &msg))) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ "%s: Not able to post WMA_ROAM_OFFLOAD_SYNCH_CNF message to WMA",
+ __func__);
+ cdf_mem_free(pRoamOffloadSynchCnf);
+ pSession->roamOffloadSynchParams.bRoamSynchInProgress =
+ false;
+ return CDF_STATUS_E_FAILURE;
+ }
+ pSession->roamOffloadSynchParams.bRoamSynchInProgress = false;
+ return CDF_STATUS_SUCCESS;
+}
+
+void csr_roam_synch_clean_up (tpAniSirGlobal mac, uint8_t session_id)
+{
+ cds_msg_t msg;
+ struct roam_offload_synch_fail *roam_offload_failed = NULL;
+ tCsrRoamSession *session = &mac->roam.roamSession[session_id];
+
+ /* Clean up the roam synch in progress for LFR3 */
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ "%s: Roam Synch Failed, Clean Up", __func__);
+ session->roamOffloadSynchParams.bRoamSynchInProgress = false;
+
+ roam_offload_failed = cdf_mem_malloc(
+ sizeof(struct roam_offload_synch_fail));
+ if (NULL == roam_offload_failed) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ "%s: unable to allocate memory for roam synch fail" ,
+ __func__);
+ return;
+ }
+
+ roam_offload_failed->session_id = session_id;
+ msg.type = WMA_ROAM_OFFLOAD_SYNCH_FAIL;
+ msg.reserved = 0;
+ msg.bodyptr = roam_offload_failed;
+ if (!CDF_IS_STATUS_SUCCESS(cds_mq_post_message(CDF_MODULE_ID_WMA,
+ &msg))) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ "%s: Unable to post WMA_ROAM_OFFLOAD_SYNCH_FAIL to WMA",
+ __func__);
+ cdf_mem_free(roam_offload_failed);
+ }
+}
+#endif
+
+#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH
+/**
+ * csr_roam_copy_ht_profile() - Copy from src to dst
+ * @dst_profile: Destination HT profile
+ * @src_profile: Source HT profile
+ *
+ * Copy the HT profile from the given source to destination
+ *
+ * Return: None
+ */
+static void csr_roam_copy_ht_profile(tCsrRoamHTProfile *dst_profile,
+ tSirSmeHTProfile *src_profile)
+{
+ dst_profile->phymode =
+ csr_roamdot11mode_to_phymode(src_profile->dot11mode);
+ dst_profile->htCapability = src_profile->htCapability;
+ dst_profile->htSupportedChannelWidthSet =
+ src_profile->htSupportedChannelWidthSet;
+ dst_profile->htRecommendedTxWidthSet =
+ src_profile->htRecommendedTxWidthSet;
+ dst_profile->htSecondaryChannelOffset =
+ src_profile->htSecondaryChannelOffset;
+#ifdef WLAN_FEATURE_11AC
+ dst_profile->vhtCapability = src_profile->vhtCapability;
+ dst_profile->vhtTxChannelWidthSet = src_profile->vhtTxChannelWidthSet;
+ dst_profile->apCenterChan = src_profile->apCenterChan;
+ dst_profile->apChanWidth = src_profile->apChanWidth;
+#endif
+}
+#endif
+
+/**
+ * csr_roam_process_results_default() - Process the result for start bss
+ * @mac_ctx: Global MAC Context
+ * @cmd: Command to be processed
+ * @context: Additional data in context of the cmd
+ *
+ * Return: None
+ */
+static void csr_roam_process_results_default(tpAniSirGlobal mac_ctx,
+ tSmeCmd *cmd, void *context, eCsrRoamCompleteResult res)
+{
+ uint32_t session_id = cmd->sessionId;
+ tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id);
+ tCsrRoamInfo roam_info;
+ CDF_STATUS status;
+
+ sms_log(mac_ctx, LOGW, FL("receives no association indication"));
+ sms_log(mac_ctx, LOG1, FL("Assoc ref count %d"),
+ session->bRefAssocStartCnt);
+ if (CSR_IS_INFRASTRUCTURE(&session->connectedProfile)
+ || CSR_IS_ROAM_SUBSTATE_STOP_BSS_REQ(mac_ctx, session_id)) {
+ /*
+ * do not free for the other profiles as we need
+ * to send down stop BSS later
+ */
+ csr_free_connect_bss_desc(mac_ctx, session_id);
+ csr_roam_free_connect_profile(mac_ctx,
+ &session->connectedProfile);
+ csr_roam_free_connected_info(mac_ctx, &session->connectedInfo);
+ csr_set_default_dot11_mode(mac_ctx);
+ }
+
+ switch (cmd->u.roamCmd.roamReason) {
+ /*
+ * If this transition is because of an 802.11 OID, then we
+ * transition back to INIT state so we sit waiting for more
+ * OIDs to be issued and we don't start the IDLE timer.
+ */
+ case eCsrSmeIssuedFTReassoc:
+ case eCsrSmeIssuedAssocToSimilarAP:
+ case eCsrHddIssued:
+ case eCsrSmeIssuedDisassocForHandoff:
+ csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_IDLE,
+ session_id);
+ cdf_mem_set(&roam_info, sizeof(tCsrRoamInfo), 0);
+ roam_info.pBssDesc = cmd->u.roamCmd.pLastRoamBss;
+ roam_info.pProfile = &cmd->u.roamCmd.roamProfile;
+ roam_info.statusCode = session->joinFailStatusCode.statusCode;
+ roam_info.reasonCode = session->joinFailStatusCode.reasonCode;
+ cdf_mem_copy(&roam_info.bssid,
+ &session->joinFailStatusCode.bssId,
+ sizeof(struct cdf_mac_addr));
+
+#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING
+ /*
+ * If Join fails while Handoff is in progress, indicate
+ * disassociated event to supplicant to reconnect
+ */
+ if (csr_roam_is_handoff_in_progress(mac_ctx, session_id)) {
+ csr_neighbor_roam_indicate_connect(mac_ctx,
+ (uint8_t)session_id, CDF_STATUS_E_FAILURE);
+ }
+#endif
+ if (session->bRefAssocStartCnt > 0) {
+ session->bRefAssocStartCnt--;
+ if (eCsrJoinFailureDueToConcurrency == res)
+ csr_roam_call_callback(mac_ctx, session_id,
+ &roam_info, cmd->u.roamCmd.roamId,
+ eCSR_ROAM_ASSOCIATION_COMPLETION,
+ eCSR_ROAM_RESULT_ASSOC_FAIL_CON_CHANNEL);
+ else
+ csr_roam_call_callback(mac_ctx, session_id,
+ &roam_info, cmd->u.roamCmd.roamId,
+ eCSR_ROAM_ASSOCIATION_COMPLETION,
+ eCSR_ROAM_RESULT_FAILURE);
+ } else {
+ /*
+ * bRefAssocStartCnt is not incremented when
+ * eRoamState == eCsrStopRoamingDueToConcurrency
+ * in csr_roam_join_next_bss API. so handle this in
+ * else case by sending assoc failure
+ */
+ csr_roam_call_callback(mac_ctx, session_id,
+ &roam_info, cmd->u.scanCmd.roamId,
+ eCSR_ROAM_ASSOCIATION_FAILURE,
+ eCSR_ROAM_RESULT_FAILURE);
+ }
+ sms_log(mac_ctx, LOG1, FL("roam(reason %d) failed"),
+ cmd->u.roamCmd.roamReason);
+#ifndef WLAN_MDM_CODE_REDUCTION_OPT
+ sme_qos_update_hand_off((uint8_t) session_id, false);
+ sme_qos_csr_event_ind(mac_ctx, (uint8_t) session_id,
+ SME_QOS_CSR_DISCONNECT_IND, NULL);
+#endif
+ csr_roam_completion(mac_ctx, session_id, NULL, cmd,
+ eCSR_ROAM_RESULT_FAILURE, false);
+#ifdef FEATURE_WLAN_BTAMP_UT_RF
+ /*
+ * For WDS STA. To fix the issue where the WDS AP side may
+ * be too busy by BT activity and not able to receive
+ * WLAN traffic. Retry the join
+ */
+ if (CSR_IS_WDS_STA(profile))
+ csr_roam_start_join_retry_timer(mac_ctx, session_id,
+ CSR_JOIN_RETRY_TIMEOUT_PERIOD);
+#endif
+ break;
+ case eCsrHddIssuedReassocToSameAP:
+ case eCsrSmeIssuedReassocToSameAP:
+ csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_IDLE,
+ session_id);
+
+ csr_roam_call_callback(mac_ctx, session_id, NULL,
+ cmd->u.roamCmd.roamId, eCSR_ROAM_DISASSOCIATED,
+ eCSR_ROAM_RESULT_FORCED);
+#ifndef WLAN_MDM_CODE_REDUCTION_OPT
+ sme_qos_csr_event_ind(mac_ctx, (uint8_t) session_id,
+ SME_QOS_CSR_DISCONNECT_IND, NULL);
+#endif
+ csr_roam_completion(mac_ctx, session_id, NULL, cmd,
+ eCSR_ROAM_RESULT_FAILURE, false);
+ break;
+ case eCsrForcedDisassoc:
+ case eCsrForcedDeauth:
+ case eCsrSmeIssuedIbssJoinFailure:
+ csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_IDLE,
+ session_id);
+
+ if (eCsrSmeIssuedIbssJoinFailure == cmd->u.roamCmd.roamReason)
+ /* notify HDD that IBSS join failed */
+ csr_roam_call_callback(mac_ctx, session_id, NULL, 0,
+ eCSR_ROAM_IBSS_IND,
+ eCSR_ROAM_RESULT_IBSS_JOIN_FAILED);
+ else
+ csr_roam_call_callback(mac_ctx, session_id, NULL,
+ cmd->u.roamCmd.roamId, eCSR_ROAM_DISASSOCIATED,
+ eCSR_ROAM_RESULT_FORCED);
+#ifndef WLAN_MDM_CODE_REDUCTION_OPT
+ sme_qos_csr_event_ind(mac_ctx, (uint8_t) session_id,
+ SME_QOS_CSR_DISCONNECT_IND,
+ NULL);
+#endif
+ csr_roam_link_down(mac_ctx, session_id);
+
+ if (mac_ctx->roam.deauthRspStatus == eSIR_SME_DEAUTH_STATUS) {
+ sms_log(mac_ctx, LOGW,
+ FL("FW still in connected state"));
+ break;
+ }
+ break;
+ case eCsrForcedIbssLeave:
+ csr_roam_call_callback(mac_ctx, session_id, NULL,
+ cmd->u.roamCmd.roamId, eCSR_ROAM_IBSS_LEAVE,
+ eCSR_ROAM_RESULT_IBSS_STOP);
+ break;
+ case eCsrForcedDisassocMICFailure:
+ csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_IDLE,
+ session_id);
+
+ csr_roam_call_callback(mac_ctx, session_id, NULL,
+ cmd->u.roamCmd.roamId, eCSR_ROAM_DISASSOCIATED,
+ eCSR_ROAM_RESULT_MIC_FAILURE);
+#ifndef WLAN_MDM_CODE_REDUCTION_OPT
+ sme_qos_csr_event_ind(mac_ctx, (uint8_t) session_id,
+ SME_QOS_CSR_DISCONNECT_REQ, NULL);
+#endif
+ break;
+ case eCsrStopBss:
+ csr_roam_call_callback(mac_ctx, session_id, NULL,
+ cmd->u.roamCmd.roamId, eCSR_ROAM_INFRA_IND,
+ eCSR_ROAM_RESULT_INFRA_STOPPED);
+ break;
+ case eCsrForcedDisassocSta:
+ case eCsrForcedDeauthSta:
+ csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_JOINED,
+ session_id);
+ session = CSR_GET_SESSION(mac_ctx, session_id);
+ if (CSR_IS_SESSION_VALID(mac_ctx, session_id) &&
+ CSR_IS_INFRA_AP(&session->connectedProfile)) {
+ roam_info.u.pConnectedProfile =
+ &session->connectedProfile;
+ cdf_mem_copy(roam_info.peerMac.bytes,
+ cmd->u.roamCmd.peerMac,
+ sizeof(tSirMacAddr));
+ roam_info.reasonCode = eCSR_ROAM_RESULT_FORCED;
+ roam_info.statusCode = eSIR_SME_SUCCESS;
+ status = csr_roam_call_callback(mac_ctx, session_id,
+ &roam_info, cmd->u.roamCmd.roamId,
+ eCSR_ROAM_LOSTLINK,
+ eCSR_ROAM_RESULT_FORCED);
+ }
+ break;
+ case eCsrLostLink1:
+ /* if lost link roam1 failed, then issue lost link Scan2 ... */
+ csr_scan_request_lost_link2(mac_ctx, session_id);
+ break;
+ case eCsrLostLink2:
+ /* if lost link roam2 failed, then issue lost link scan3 ... */
+ csr_scan_request_lost_link3(mac_ctx, session_id);
+ break;
+ case eCsrLostLink3:
+ default:
+ csr_roam_state_change(mac_ctx,
+ eCSR_ROAMING_STATE_IDLE, session_id);
+
+ /* We are done with one round of lostlink roaming here */
+ csr_scan_handle_failed_lostlink3(mac_ctx, session_id);
+ break;
+ }
+}
+
+/**
+ * csr_roam_process_start_bss_success() - Process the result for start bss
+ * @mac_ctx: Global MAC Context
+ * @cmd: Command to be processed
+ * @context: Additional data in context of the cmd
+ *
+ * Return: None
+ */
+static void csr_roam_process_start_bss_success(tpAniSirGlobal mac_ctx,
+ tSmeCmd *cmd, void *context)
+{
+ uint32_t session_id = cmd->sessionId;
+ tCsrRoamProfile *profile = &cmd->u.roamCmd.roamProfile;
+ tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id);
+ tSirBssDescription *bss_desc = NULL;
+ tCsrRoamInfo roam_info;
+ tSirSmeStartBssRsp *start_bss_rsp = NULL;
+ tCsrScanResult *scan_res = NULL;
+ eRoamCmdStatus roam_status;
+ eCsrRoamResult roam_result;
+ tDot11fBeaconIEs *ies_ptr = NULL;
+ tSirMacAddr bcast_mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ CDF_STATUS status;
+ host_log_ibss_pkt_type *ibss_log;
+ uint32_t bi;
+#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH
+ tSirSmeHTProfile *src_profile = NULL;
+ tCsrRoamHTProfile *dst_profile = NULL;
+#endif
+
+ /*
+ * on the StartBss Response, LIM is returning the Bss Description that
+ * we are beaconing. Add this Bss Description to our scan results and
+ * chain the Profile to this Bss Description. On a Start BSS, there was
+ * no detected Bss description (no partner) so we issued the Start Bss
+ * to start the Ibss without any Bss description. Lim was kind enough
+ * to return the Bss Description that we start beaconing for the newly
+ * started Ibss.
+ */
+ sms_log(mac_ctx, LOG2, FL("receives start BSS ok indication"));
+ status = CDF_STATUS_E_FAILURE;
+ start_bss_rsp = (tSirSmeStartBssRsp *) context;
+ cdf_mem_set(&roam_info, sizeof(tCsrRoamInfo), 0);
+ if (CSR_IS_IBSS(profile))
+ session->connectState = eCSR_ASSOC_STATE_TYPE_IBSS_DISCONNECTED;
+ else if (CSR_IS_INFRA_AP(profile))
+ session->connectState =
+ eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTED;
+ else
+ session->connectState = eCSR_ASSOC_STATE_TYPE_WDS_DISCONNECTED;
+ if (!CSR_IS_WDS_STA(profile)) {
+ csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_JOINED,
+ session_id);
+ bss_desc = &start_bss_rsp->bssDescription;
+ if (!CDF_IS_STATUS_SUCCESS
+ (csr_get_parsed_bss_description_ies(mac_ctx, bss_desc,
+ &ies_ptr))) {
+ sms_log(mac_ctx, LOGW, FL("cannot parse IBSS IEs"));
+ roam_info.pBssDesc = bss_desc;
+ csr_roam_call_callback(mac_ctx, session_id, &roam_info,
+ cmd->u.roamCmd.roamId, eCSR_ROAM_IBSS_IND,
+ eCSR_ROAM_RESULT_IBSS_START_FAILED);
+ return;
+ }
+ if (!CSR_IS_INFRA_AP(profile)) {
+ scan_res =
+ csr_scan_append_bss_description(mac_ctx,
+ bss_desc, ies_ptr, false,
+ session_id);
+ }
+ csr_roam_save_connected_bss_desc(mac_ctx, session_id, bss_desc);
+ csr_roam_free_connect_profile(mac_ctx,
+ &session->connectedProfile);
+ csr_roam_free_connected_info(mac_ctx,
+ &session->connectedInfo);
+ if (bss_desc) {
+ csr_roam_save_connected_infomation(mac_ctx, session_id,
+ profile, bss_desc, ies_ptr);
+ cdf_mem_copy(&roam_info.bssid, &bss_desc->bssId,
+ sizeof(struct cdf_mac_addr));
+ }
+ /* We are done with the IEs so free it */
+ cdf_mem_free(ies_ptr);
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+ WLAN_HOST_DIAG_LOG_ALLOC(ibss_log,
+ host_log_ibss_pkt_type, LOG_WLAN_IBSS_C);
+ if (ibss_log) {
+ if (CSR_INVALID_SCANRESULT_HANDLE ==
+ cmd->u.roamCmd.hBSSList) {
+ /*
+ * We start the IBSS (didn't find any
+ * matched IBSS out there)
+ */
+ ibss_log->eventId =
+ WLAN_IBSS_EVENT_START_IBSS_RSP;
+ } else {
+ ibss_log->eventId =
+ WLAN_IBSS_EVENT_JOIN_IBSS_RSP;
+ }
+ if (bss_desc) {
+ cdf_mem_copy(ibss_log->bssid,
+ bss_desc->bssId, 6);
+ ibss_log->operatingChannel =
+ bss_desc->channelId;
+ }
+ if (IS_SIR_STATUS_SUCCESS(wlan_cfg_get_int(
+ mac_ctx,
+ WNI_CFG_BEACON_INTERVAL,
+ &bi)))
+ /* U8 is not enough for BI */
+ ibss_log->beaconInterval = (uint8_t) bi;
+ WLAN_HOST_DIAG_LOG_REPORT(ibss_log);
+ }
+#endif
+ /*
+ * Only set context for non-WDS_STA. We don't even need it for
+ * WDS_AP. But since the encryption.
+ * is WPA2-PSK so it won't matter.
+ */
+ if (CSR_IS_ENC_TYPE_STATIC(profile->negotiatedUCEncryptionType)
+ && session->pCurRoamProfile
+ && !CSR_IS_INFRA_AP(session->pCurRoamProfile)) {
+ /*
+ * Issue the set Context request to LIM to establish
+ * the Broadcast STA context for the Ibss. In Rome IBSS
+ * case, dummy key installation will break proper BSS
+ * key installation, so skip it.
+ */
+ if (!CSR_IS_IBSS(session->pCurRoamProfile)) {
+ /* NO keys. these key parameters don't matter */
+ csr_roam_issue_set_context_req(mac_ctx,
+ session_id,
+ profile->negotiatedMCEncryptionType,
+ bss_desc, &bcast_mac, false,
+ false, eSIR_TX_RX, 0, 0, NULL, 0);
+ }
+
+ }
+ } else {
+ /*
+ * Keep the state to eCSR_ROAMING_STATE_JOINING.
+ * Need to send join_req.
+ */
+ if (cmd->u.roamCmd.pRoamBssEntry) {
+ scan_res = GET_BASE_ADDR(cmd->u.roamCmd.
+ pRoamBssEntry, tCsrScanResult, Link);
+ if (scan_res) {
+ bss_desc = &scan_res->Result.BssDescriptor;
+ ies_ptr = (tDot11fBeaconIEs *)
+ (scan_res->Result.pvIes);
+ /* Set the roaming substate to join attempt */
+ csr_roam_substate_change(mac_ctx,
+ eCSR_ROAM_SUBSTATE_JOIN_REQ,
+ session_id);
+ status = csr_send_join_req_msg(mac_ctx,
+ session_id, bss_desc,
+ profile, ies_ptr,
+ eWNI_SME_JOIN_REQ);
+ }
+ } else {
+ sms_log(mac_ctx, LOGE,
+ "StartBSS for WDS station with no BssDesc");
+ CDF_ASSERT(0);
+ }
+ }
+ /*
+ * Only tell upper layer is we start the BSS because Vista doesn't like
+ * multiple connection indications. If we don't start the BSS ourself,
+ * handler of eSIR_SME_JOINED_NEW_BSS will trigger the connection start
+ * indication in Vista
+ */
+ if (!CSR_IS_JOIN_TO_IBSS(profile)) {
+ roam_status = eCSR_ROAM_IBSS_IND;
+ roam_result = eCSR_ROAM_RESULT_IBSS_STARTED;
+ if (CSR_IS_WDS(profile)) {
+ roam_status = eCSR_ROAM_WDS_IND;
+ roam_result = eCSR_ROAM_RESULT_WDS_STARTED;
+ }
+ if (CSR_IS_INFRA_AP(profile)) {
+ roam_status = eCSR_ROAM_INFRA_IND;
+ roam_result = eCSR_ROAM_RESULT_INFRA_STARTED;
+ }
+ /*
+ * Only tell upper layer is we start the BSS because Vista
+ * doesn't like multiple connection indications. If we don't
+ * start the BSS ourself, handler of eSIR_SME_JOINED_NEW_BSS
+ * will trigger the connection start indication in Vista
+ */
+ cdf_mem_set(&roam_info, sizeof(tCsrRoamInfo), 0);
+ roam_info.statusCode = session->joinFailStatusCode.statusCode;
+ roam_info.reasonCode = session->joinFailStatusCode.reasonCode;
+ /* We start the IBSS (didn't find any matched IBSS out there) */
+ roam_info.pBssDesc = bss_desc;
+ roam_info.staId = (uint8_t) start_bss_rsp->staId;
+ cdf_mem_copy(roam_info.bssid.bytes, bss_desc->bssId,
+ sizeof(struct cdf_mac_addr));
+ if (!IS_FEATURE_SUPPORTED_BY_FW(SLM_SESSIONIZATION) &&
+ (csr_is_concurrent_session_running(mac_ctx))) {
+ mac_ctx->roam.configParam.doBMPSWorkaround = 1;
+ }
+#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH
+ dst_profile = &session->connectedProfile.HTProfile;
+ src_profile = &start_bss_rsp->HTProfile;
+ if (mac_ctx->roam.configParam.cc_switch_mode
+ != CDF_MCC_TO_SCC_SWITCH_DISABLE)
+ csr_roam_copy_ht_profile(dst_profile, src_profile);
+#endif
+ csr_roam_call_callback(mac_ctx, session_id, &roam_info,
+ cmd->u.roamCmd.roamId,
+ roam_status, roam_result);
+ }
+
+
+ if (CSR_IS_WDS_STA(profile)) {
+ /* need to send stop BSS because we fail to send join_req */
+ csr_roam_issue_disassociate_cmd(mac_ctx, session_id,
+ eCSR_DISCONNECT_REASON_UNSPECIFIED);
+ csr_roam_call_callback(mac_ctx, session_id, &roam_info,
+ cmd->u.roamCmd.roamId,
+ eCSR_ROAM_WDS_IND,
+ eCSR_ROAM_RESULT_WDS_STOPPED);
+ }
+}
+
+/**
+ * csr_roam_process_join_res() - Process the Join results
+ * @mac_ctx: Global MAC Context
+ * @result: Result after the command was processed
+ * @cmd: Command to be processed
+ * @context: Additional data in context of the cmd
+ *
+ * Process the join results which are obtained in a succesful join
+ *
+ * Return: None
+ */
+static void csr_roam_process_join_res(tpAniSirGlobal mac_ctx,
+ eCsrRoamCompleteResult res, tSmeCmd *cmd, void *context)
+{
+ tSirMacAddr bcast_mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ sme_QosAssocInfo assoc_info;
+ uint32_t key_timeout_interval = 0;
+ uint8_t acm_mask = 0; /* HDD needs ACM mask in assoc rsp callback */
+ uint32_t session_id = cmd->sessionId;
+ tCsrRoamProfile *profile = &cmd->u.roamCmd.roamProfile;
+ tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id);
+ tSirBssDescription *bss_desc = NULL;
+ tCsrScanResult *scan_res = NULL;
+ sme_qos_csr_event_indType ind_qos;
+ csr_roam_offload_synch_params *roam_offload_params = NULL;
+#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH
+ tSirSmeHTProfile *src_profile = NULL;
+ tCsrRoamHTProfile *dst_profile = NULL;
+#endif
+ tCsrRoamConnectedProfile *conn_profile = NULL;
+ tDot11fBeaconIEs *ies_ptr = NULL;
+ tCsrRoamInfo roam_info;
+ struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info;
+ tSirSmeJoinRsp *join_rsp = (tSirSmeJoinRsp *) context;
+ uint32_t len;
+
+ roam_offload_params = &session->roamOffloadSynchParams;
+ conn_profile = &session->connectedProfile;
+ if (eCsrReassocSuccess == res)
+ ind_qos = SME_QOS_CSR_REASSOC_COMPLETE;
+ else
+ ind_qos = SME_QOS_CSR_ASSOC_COMPLETE;
+ sms_log(mac_ctx, LOGW, FL("receives association indication"));
+ cdf_mem_set(&roam_info, sizeof(roam_info), 0);
+ /* always free the memory here */
+ if (session->pWpaRsnRspIE) {
+ session->nWpaRsnRspIeLength = 0;
+ cdf_mem_free(session->pWpaRsnRspIE);
+ session->pWpaRsnRspIE = NULL;
+ }
+#ifdef FEATURE_WLAN_WAPI
+ if (session->pWapiRspIE) {
+ session->nWapiRspIeLength = 0;
+ cdf_mem_free(session->pWapiRspIE);
+ session->pWapiRspIE = NULL;
+ }
+#endif /* FEATURE_WLAN_WAPI */
+#ifdef FEATURE_WLAN_BTAMP_UT_RF
+ session->maxRetryCount = 0;
+ csr_roam_stop_join_retry_timer(mac_ctx, session_id);
+#endif
+ /*
+ * Reset remain_in_power_active_till_dhcp as
+ * it might have been set by last failed secured connection.
+ * It should be set only for secured connection.
+ */
+ ps_global_info->remain_in_power_active_till_dhcp = false;
+ if (CSR_IS_INFRASTRUCTURE(profile))
+ session->connectState = eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED;
+ else
+ session->connectState = eCSR_ASSOC_STATE_TYPE_WDS_CONNECTED;
+ /*
+ * Use the last connected bssdesc for reassoc-ing to the same AP.
+ * NOTE: What to do when reassoc to a different AP???
+ */
+ if ((eCsrHddIssuedReassocToSameAP == cmd->u.roamCmd.roamReason)
+ || (eCsrSmeIssuedReassocToSameAP ==
+ cmd->u.roamCmd.roamReason)) {
+ bss_desc = session->pConnectBssDesc;
+ if (bss_desc)
+ cdf_mem_copy(&roam_info.bssid, &bss_desc->bssId,
+ sizeof(struct cdf_mac_addr));
+ } else {
+ if (cmd->u.roamCmd.pRoamBssEntry) {
+ scan_res = GET_BASE_ADDR(cmd->u.roamCmd.pRoamBssEntry,
+ tCsrScanResult, Link);
+ if (scan_res != NULL) {
+ bss_desc = &scan_res->Result.BssDescriptor;
+ ies_ptr = (tDot11fBeaconIEs *)
+ (scan_res->Result.pvIes);
+ cdf_mem_copy(&roam_info.bssid, &bss_desc->bssId,
+ sizeof(struct cdf_mac_addr));
+ }
+ }
+ }
+ if (bss_desc) {
+ roam_info.staId = STA_INVALID_IDX;
+ csr_roam_save_connected_infomation(mac_ctx, session_id,
+ profile, bss_desc, ies_ptr);
+ /* Save WPA/RSN IE */
+ csr_roam_save_security_rsp_ie(mac_ctx, session_id,
+ profile->negotiatedAuthType, bss_desc, ies_ptr);
+#ifdef FEATURE_WLAN_ESE
+ roam_info.isESEAssoc = conn_profile->isESEAssoc;
+#endif
+
+ /*
+ * csr_roam_state_change also affects sub-state.
+ * Hence, csr_roam_state_change happens first and then
+ * substate change.
+ * Moving even save profile above so that below
+ * mentioned conditon is also met.
+ * JEZ100225: Moved to after saving the profile.
+ * Fix needed in main/latest
+ */
+ csr_roam_state_change(mac_ctx,
+ eCSR_ROAMING_STATE_JOINED, session_id);
+
+ /*
+ * Make sure the Set Context is issued before link
+ * indication to NDIS. After link indication is
+ * made to NDIS, frames could start flowing.
+ * If we have not set context with LIM, the frames
+ * will be dropped for the security context may not
+ * be set properly.
+ *
+ * this was causing issues in the 2c_wlan_wep WHQL test
+ * when the SetContext was issued after the link
+ * indication. (Link Indication happens in the
+ * profFSMSetConnectedInfra call).
+ *
+ * this reordering was done on titan_prod_usb branch
+ * and is being replicated here.
+ */
+
+ if (CSR_IS_ENC_TYPE_STATIC
+ (profile->negotiatedUCEncryptionType) &&
+ !profile->bWPSAssociation) {
+ /*
+ * Issue the set Context request to LIM to establish
+ * the Unicast STA context
+ */
+ if (!CDF_IS_STATUS_SUCCESS(
+ csr_roam_issue_set_context_req(mac_ctx,
+ session_id,
+ profile->negotiatedUCEncryptionType,
+ bss_desc, &(bss_desc->bssId),
+ false, true,
+ eSIR_TX_RX, 0, 0, NULL, 0))) {
+ /* NO keys. these key parameters don't matter */
+ sms_log(mac_ctx, LOGE,
+ FL("Set context for unicast fail"));
+ csr_roam_substate_change(mac_ctx,
+ eCSR_ROAM_SUBSTATE_NONE, session_id);
+ }
+ /*
+ * Issue the set Context request to LIM
+ * to establish the Broadcast STA context
+ * NO keys. these key parameters don't matter
+ */
+ csr_roam_issue_set_context_req(mac_ctx, session_id,
+ profile->negotiatedMCEncryptionType,
+ bss_desc, &bcast_mac, false, false,
+ eSIR_TX_RX, 0, 0, NULL, 0);
+ } else {
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+ if (roam_offload_params->bRoamSynchInProgress
+ && (roam_offload_params->authStatus
+ == CSR_ROAM_AUTH_STATUS_AUTHENTICATED)) {
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_DEBUG,
+ FL("LFR3:Don't start waitforkey timer"));
+ csr_roam_substate_change(mac_ctx,
+ eCSR_ROAM_SUBSTATE_NONE, session_id);
+ } else {
+#endif
+ /* Need to wait for supplicant authtication */
+ roam_info.fAuthRequired = true;
+ /*
+ * Set the substate to WaitForKey in case
+ * authentiation is needed
+ */
+ csr_roam_substate_change(mac_ctx,
+ eCSR_ROAM_SUBSTATE_WAIT_FOR_KEY,
+ session_id);
+
+ /*
+ * Set remain_in_power_active_till_dhcp to make
+ * sure we wait for until keys are set before
+ * going into BMPS.
+ */
+ ps_global_info->remain_in_power_active_till_dhcp
+ = true;
+
+ if (profile->bWPSAssociation)
+ key_timeout_interval =
+ CSR_WAIT_FOR_WPS_KEY_TIMEOUT_PERIOD;
+ else
+ key_timeout_interval =
+ CSR_WAIT_FOR_KEY_TIMEOUT_PERIOD;
+
+ /* Save session_id in case of timeout */
+ mac_ctx->roam.WaitForKeyTimerInfo.sessionId =
+ (uint8_t) session_id;
+ /*
+ * This time should be long enough for the rest
+ * of the process plus setting key
+ */
+ if (!CDF_IS_STATUS_SUCCESS
+ (csr_roam_start_wait_for_key_timer(
+ mac_ctx, key_timeout_interval))
+ ) {
+ /* Reset state so nothing is blocked. */
+ sms_log(mac_ctx, LOGE, FL
+ ("Failed preauth timer start"));
+ csr_roam_substate_change(mac_ctx,
+ eCSR_ROAM_SUBSTATE_NONE,
+ session_id);
+ }
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+ }
+#endif
+ }
+
+ assoc_info.pBssDesc = bss_desc; /* could be NULL */
+ assoc_info.pProfile = profile;
+ if (context) {
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+ if (roam_offload_params->bRoamSynchInProgress)
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_DEBUG,
+ FL("LFR3:Clear Connected info"));
+#endif
+ csr_roam_free_connected_info(mac_ctx,
+ &session->connectedInfo);
+ len = join_rsp->assocReqLength +
+ join_rsp->assocRspLength +
+ join_rsp->beaconLength;
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ len += join_rsp->parsedRicRspLen;
+#endif /* WLAN_FEATURE_VOWIFI_11R */
+#ifdef FEATURE_WLAN_ESE
+ len += join_rsp->tspecIeLen;
+#endif
+ if (len) {
+ session->connectedInfo.pbFrames =
+ cdf_mem_malloc(len);
+ if (session->connectedInfo.pbFrames !=
+ NULL) {
+ cdf_mem_copy(
+ session->connectedInfo.pbFrames,
+ join_rsp->frames, len);
+ session->connectedInfo.nAssocReqLength =
+ join_rsp->assocReqLength;
+ session->connectedInfo.nAssocRspLength =
+ join_rsp->assocRspLength;
+ session->connectedInfo.nBeaconLength =
+ join_rsp->beaconLength;
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ session->connectedInfo.nRICRspLength =
+ join_rsp->parsedRicRspLen;
+#endif /* WLAN_FEATURE_VOWIFI_11R */
+#ifdef FEATURE_WLAN_ESE
+ session->connectedInfo.nTspecIeLength =
+ join_rsp->tspecIeLen;
+#endif
+ roam_info.nAssocReqLength =
+ join_rsp->assocReqLength;
+ roam_info.nAssocRspLength =
+ join_rsp->assocRspLength;
+ roam_info.nBeaconLength =
+ join_rsp->beaconLength;
+ roam_info.pbFrames =
+ session->connectedInfo.pbFrames;
+ }
+ }
+ if (cmd->u.roamCmd.fReassoc)
+ roam_info.fReassocReq =
+ roam_info.fReassocRsp = true;
+ conn_profile->vht_channel_width =
+ join_rsp->vht_channel_width;
+ session->connectedInfo.staId =
+ (uint8_t) join_rsp->staId;
+ roam_info.staId = (uint8_t) join_rsp->staId;
+ roam_info.ucastSig = (uint8_t) join_rsp->ucastSig;
+ roam_info.bcastSig = (uint8_t) join_rsp->bcastSig;
+ roam_info.timingMeasCap = join_rsp->timingMeasCap;
+#ifdef FEATURE_WLAN_TDLS
+ roam_info.tdls_prohibited = join_rsp->tdls_prohibited;
+ roam_info.tdls_chan_swit_prohibited =
+ join_rsp->tdls_chan_swit_prohibited;
+ sms_log(mac_ctx, LOG1,
+ FL("tdls:prohibit: %d, chan_swit_prohibit: %d"),
+ roam_info.tdls_prohibited,
+ roam_info.tdls_chan_swit_prohibited);
+#endif
+#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH
+ src_profile = &join_rsp->HTProfile;
+ dst_profile = &conn_profile->HTProfile;
+ if (mac_ctx->roam.configParam.cc_switch_mode
+ != CDF_MCC_TO_SCC_SWITCH_DISABLE)
+ csr_roam_copy_ht_profile(dst_profile,
+ src_profile);
+#endif
+ } else {
+ if (cmd->u.roamCmd.fReassoc) {
+ roam_info.fReassocReq =
+ roam_info.fReassocRsp = true;
+ roam_info.nAssocReqLength =
+ session->connectedInfo.nAssocReqLength;
+ roam_info.nAssocRspLength =
+ session->connectedInfo.nAssocRspLength;
+ roam_info.nBeaconLength =
+ session->connectedInfo.nBeaconLength;
+ roam_info.pbFrames =
+ session->connectedInfo.pbFrames;
+ }
+ }
+
+ /*
+ * Update the staId from the previous connected profile info
+ * as the reassociation is triggred at SME/HDD
+ */
+
+ if ((eCsrHddIssuedReassocToSameAP ==
+ cmd->u.roamCmd.roamReason) ||
+ (eCsrSmeIssuedReassocToSameAP ==
+ cmd->u.roamCmd.roamReason))
+ roam_info.staId = session->connectedInfo.staId;
+
+#ifndef WLAN_MDM_CODE_REDUCTION_OPT
+ /*
+ * Indicate SME-QOS with reassoc success event,
+ * only after copying the frames
+ */
+ sme_qos_csr_event_ind(mac_ctx, (uint8_t) session_id, ind_qos,
+ &assoc_info);
+#endif
+ roam_info.pBssDesc = bss_desc;
+ roam_info.statusCode =
+ session->joinFailStatusCode.statusCode;
+ roam_info.reasonCode =
+ session->joinFailStatusCode.reasonCode;
+#ifndef WLAN_MDM_CODE_REDUCTION_OPT
+ acm_mask = sme_qos_get_acm_mask(mac_ctx, bss_desc, NULL);
+#endif
+ conn_profile->acm_mask = acm_mask;
+ /*
+ * start UAPSD if uapsd_mask is not 0 because HDD will
+ * configure for trigger frame It may be better to let QoS do
+ * this????
+ */
+ if (conn_profile->modifyProfileFields.uapsd_mask) {
+ sms_log(mac_ctx, LOGE,
+ " uapsd_mask (0x%X) set, request UAPSD now",
+ conn_profile->modifyProfileFields.uapsd_mask);
+ sme_ps_start_uapsd(mac_ctx, session_id,
+ NULL, NULL);
+ }
+ conn_profile->dot11Mode = session->bssParams.uCfgDot11Mode;
+ roam_info.u.pConnectedProfile = conn_profile;
+
+ if (session->bRefAssocStartCnt > 0) {
+ session->bRefAssocStartCnt--;
+ if (!IS_FEATURE_SUPPORTED_BY_FW
+ (SLM_SESSIONIZATION) &&
+ (csr_is_concurrent_session_running(mac_ctx))) {
+ mac_ctx->roam.configParam.doBMPSWorkaround = 1;
+ }
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+ if (roam_offload_params->bRoamSynchInProgress) {
+ roam_info.roamSynchInProgress = 1;
+ roam_info.synchAuthStatus =
+ roam_offload_params->authStatus;
+ cdf_mem_copy(roam_info.kck,
+ roam_offload_params->kck,
+ SIR_KCK_KEY_LEN);
+ cdf_mem_copy(roam_info.kek,
+ roam_offload_params->kek,
+ SIR_KEK_KEY_LEN);
+ cdf_mem_copy(roam_info.replay_ctr,
+ roam_offload_params->replay_ctr,
+ SIR_REPLAY_CTR_LEN);
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_DEBUG,
+ FL
+ ("LFR3: Copy KCK, KEK and Replay Ctr"));
+ }
+#endif
+ csr_roam_call_callback(mac_ctx, session_id, &roam_info,
+ cmd->u.roamCmd.roamId,
+ eCSR_ROAM_ASSOCIATION_COMPLETION,
+ eCSR_ROAM_RESULT_ASSOCIATED);
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+ if (roam_offload_params->bRoamSynchInProgress
+ && (roam_offload_params->authStatus
+ == CSR_ROAM_AUTH_STATUS_CONNECTED)) {
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_DEBUG,
+ FL("LFR3:Send Synch Cnf for Auth status connected"));
+ csr_roam_offload_send_synch_cnf(mac_ctx,
+ session_id);
+ }
+#endif
+ }
+
+ csr_roam_completion(mac_ctx, session_id, NULL, cmd,
+ eCSR_ROAM_RESULT_NONE, true);
+ csr_reset_pmkid_candidate_list(mac_ctx, session_id);
+#ifdef FEATURE_WLAN_WAPI
+ csr_reset_bkid_candidate_list(mac_ctx, session_id);
+#endif
+ } else {
+ sms_log(mac_ctx, LOGW,
+ "Roam command doesn't have a BSS desc");
+ }
+ /* Not to signal link up because keys are yet to be set.
+ * The linkup function will overwrite the sub-state that
+ * we need to keep at this point.
+ */
+ if (!CSR_IS_WAIT_FOR_KEY(mac_ctx, session_id)) {
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+ if (roam_offload_params->bRoamSynchInProgress) {
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_DEBUG,
+ FL
+ ("NO CSR_IS_WAIT_FOR_KEY -> csr_roam_link_up"));
+ }
+#endif
+ csr_roam_link_up(mac_ctx, conn_profile->bssid);
+ }
+}
+
+/**
+ * csr_roam_process_results() - Process the Roam Results
+ * @mac_ctx: Global MAC Context
+ * @cmd: Command that has been processed
+ * @res: Results available after processing the command
+ * @context: Context
+ *
+ * Process the available results and make an appropriate decision
+ *
+ * Return: true if the command can be released, else not.
+ */
+static bool csr_roam_process_results(tpAniSirGlobal mac_ctx, tSmeCmd *cmd,
+ eCsrRoamCompleteResult res, void *context)
+{
+ bool release_cmd = true;
+ tSirBssDescription *bss_desc = NULL;
+ tCsrRoamInfo roam_info;
+ uint32_t session_id = cmd->sessionId;
+ tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id);
+ tCsrRoamProfile *profile = &cmd->u.roamCmd.roamProfile;
+ eRoamCmdStatus roam_status;
+ eCsrRoamResult roam_result;
+ host_log_ibss_pkt_type *ibss_log;
+
+ if (!session) {
+ sms_log(mac_ctx, LOGE, FL("session %d not found "), session_id);
+ return false;
+ }
+ sms_log(mac_ctx, LOG1, FL("Processing ROAM results..."));
+ switch (res) {
+ case eCsrJoinSuccess:
+ case eCsrReassocSuccess:
+ csr_roam_process_join_res(mac_ctx, res, cmd, context);
+ break;
+ case eCsrStartBssSuccess:
+ csr_roam_process_start_bss_success(mac_ctx, cmd, context);
+ break;
+ case eCsrStartBssFailure:
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+ WLAN_HOST_DIAG_LOG_ALLOC(ibss_log,
+ host_log_ibss_pkt_type, LOG_WLAN_IBSS_C);
+ if (ibss_log) {
+ ibss_log->status = WLAN_IBSS_STATUS_FAILURE;
+ WLAN_HOST_DIAG_LOG_REPORT(ibss_log);
+ }
+#endif
+ roam_status = eCSR_ROAM_IBSS_IND;
+ roam_result = eCSR_ROAM_RESULT_IBSS_STARTED;
+ if (CSR_IS_WDS(profile)) {
+ roam_status = eCSR_ROAM_WDS_IND;
+ roam_result = eCSR_ROAM_RESULT_WDS_STARTED;
+ }
+ if (CSR_IS_INFRA_AP(profile)) {
+ roam_status = eCSR_ROAM_INFRA_IND;
+ roam_result = eCSR_ROAM_RESULT_INFRA_START_FAILED;
+ }
+ if (context) {
+ bss_desc = (tSirBssDescription *) context;
+ } else {
+ bss_desc = NULL;
+ }
+ cdf_mem_set(&roam_info, sizeof(tCsrRoamInfo), 0);
+ roam_info.pBssDesc = bss_desc;
+ csr_roam_call_callback(mac_ctx, session_id, &roam_info,
+ cmd->u.roamCmd.roamId, roam_status,
+ roam_result);
+ csr_set_default_dot11_mode(mac_ctx);
+ break;
+ case eCsrSilentlyStopRoaming:
+ /*
+ * We are here because we try to start the same IBSS.
+ * No message to PE. return the roaming state to Joined.
+ */
+ sms_log(mac_ctx, LOGW, FL("receives silently stop roam ind"));
+ csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_JOINED,
+ session_id);
+ csr_roam_substate_change(mac_ctx, eCSR_ROAM_SUBSTATE_NONE,
+ session_id);
+ cdf_mem_set(&roam_info, sizeof(tCsrRoamInfo), 0);
+ roam_info.pBssDesc = session->pConnectBssDesc;
+ if (roam_info.pBssDesc)
+ cdf_mem_copy(&roam_info.bssid,
+ &roam_info.pBssDesc->bssId,
+ sizeof(struct cdf_mac_addr));
+ /*
+ * Since there is no change in the current state, simply pass
+ * back no result otherwise HDD may be mistakenly mark to
+ * disconnected state.
+ */
+ csr_roam_call_callback(mac_ctx, session_id, &roam_info,
+ cmd->u.roamCmd.roamId,
+ eCSR_ROAM_IBSS_IND, eCSR_ROAM_RESULT_NONE);
+ break;
+ case eCsrSilentlyStopRoamingSaveState:
+ /* We are here because we try to connect to the same AP */
+ /* No message to PE */
+ sms_log(mac_ctx, LOGW,
+ FL("receives silently stop roaming indication"));
+ cdf_mem_set(&roam_info, sizeof(roam_info), 0);
+
+ /* to aviod resetting the substate to NONE */
+ mac_ctx->roam.curState[session_id] = eCSR_ROAMING_STATE_JOINED;
+ /*
+ * No need to change substate to wai_for_key because there
+ * is no state change
+ */
+ roam_info.pBssDesc = session->pConnectBssDesc;
+ if (roam_info.pBssDesc)
+ cdf_mem_copy(&roam_info.bssid,
+ &roam_info.pBssDesc->bssId,
+ sizeof(struct cdf_mac_addr));
+ roam_info.statusCode = session->joinFailStatusCode.statusCode;
+ roam_info.reasonCode = session->joinFailStatusCode.reasonCode;
+ roam_info.nBeaconLength = session->connectedInfo.nBeaconLength;
+ roam_info.nAssocReqLength =
+ session->connectedInfo.nAssocReqLength;
+ roam_info.nAssocRspLength =
+ session->connectedInfo.nAssocRspLength;
+ roam_info.pbFrames = session->connectedInfo.pbFrames;
+ roam_info.staId = session->connectedInfo.staId;
+ roam_info.u.pConnectedProfile = &session->connectedProfile;
+ if (0 == roam_info.staId) {
+ CDF_ASSERT(0);
+ return false;
+ }
+ session->bRefAssocStartCnt--;
+ csr_roam_call_callback(mac_ctx, session_id, &roam_info,
+ cmd->u.roamCmd.roamId,
+ eCSR_ROAM_ASSOCIATION_COMPLETION,
+ eCSR_ROAM_RESULT_ASSOCIATED);
+ csr_roam_completion(mac_ctx, session_id, NULL, cmd,
+ eCSR_ROAM_RESULT_ASSOCIATED, true);
+ break;
+ case eCsrReassocFailure:
+#ifndef WLAN_MDM_CODE_REDUCTION_OPT
+ sme_qos_csr_event_ind(mac_ctx, (uint8_t) session_id,
+ SME_QOS_CSR_REASSOC_FAILURE, NULL);
+#endif
+ case eCsrJoinWdsFailure:
+ sms_log(mac_ctx, LOGW, FL("failed to join WDS"));
+ csr_free_connect_bss_desc(mac_ctx, session_id);
+ csr_roam_free_connect_profile(mac_ctx,
+ &session->connectedProfile);
+ csr_roam_free_connected_info(mac_ctx, &session->connectedInfo);
+ cdf_mem_set(&roam_info, sizeof(tCsrRoamInfo), 0);
+ roam_info.pBssDesc = cmd->u.roamCmd.pLastRoamBss;
+ roam_info.statusCode = session->joinFailStatusCode.statusCode;
+ roam_info.reasonCode = session->joinFailStatusCode.reasonCode;
+ csr_roam_call_callback(mac_ctx, session_id, &roam_info,
+ cmd->u.roamCmd.roamId, eCSR_ROAM_WDS_IND,
+ eCSR_ROAM_RESULT_WDS_NOT_ASSOCIATED);
+ /* Need to issue stop_bss */
+ break;
+ case eCsrJoinFailure:
+ case eCsrNothingToJoin:
+ case eCsrJoinFailureDueToConcurrency:
+ default:
+ csr_roam_process_results_default(mac_ctx, cmd, context, res);
+ break;
+ }
+ return release_cmd;
+}
+
+CDF_STATUS csr_roam_copy_profile(tpAniSirGlobal pMac,
+ tCsrRoamProfile *pDstProfile,
+ tCsrRoamProfile *pSrcProfile)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ uint32_t size = 0;
+
+ cdf_mem_set(pDstProfile, sizeof(tCsrRoamProfile), 0);
+ if (pSrcProfile->BSSIDs.numOfBSSIDs) {
+ size = sizeof(struct cdf_mac_addr) * pSrcProfile->BSSIDs.numOfBSSIDs;
+ pDstProfile->BSSIDs.bssid = cdf_mem_malloc(size);
+ if (NULL == pDstProfile->BSSIDs.bssid) {
+ status = CDF_STATUS_E_NOMEM;
+ goto end;
+ }
+ pDstProfile->BSSIDs.numOfBSSIDs =
+ pSrcProfile->BSSIDs.numOfBSSIDs;
+ cdf_mem_copy(pDstProfile->BSSIDs.bssid,
+ pSrcProfile->BSSIDs.bssid, size);
+ }
+ if (pSrcProfile->SSIDs.numOfSSIDs) {
+ size = sizeof(tCsrSSIDInfo) * pSrcProfile->SSIDs.numOfSSIDs;
+ pDstProfile->SSIDs.SSIDList = cdf_mem_malloc(size);
+ if (NULL == pDstProfile->SSIDs.SSIDList) {
+ status = CDF_STATUS_E_NOMEM;
+ goto end;
+ }
+ pDstProfile->SSIDs.numOfSSIDs =
+ pSrcProfile->SSIDs.numOfSSIDs;
+ cdf_mem_copy(pDstProfile->SSIDs.SSIDList,
+ pSrcProfile->SSIDs.SSIDList, size);
+ }
+ if (pSrcProfile->nWPAReqIELength) {
+ pDstProfile->pWPAReqIE =
+ cdf_mem_malloc(pSrcProfile->nWPAReqIELength);
+ if (NULL == pDstProfile->pWPAReqIE) {
+ status = CDF_STATUS_E_NOMEM;
+ goto end;
+ }
+ pDstProfile->nWPAReqIELength =
+ pSrcProfile->nWPAReqIELength;
+ cdf_mem_copy(pDstProfile->pWPAReqIE, pSrcProfile->pWPAReqIE,
+ pSrcProfile->nWPAReqIELength);
+ }
+ if (pSrcProfile->nRSNReqIELength) {
+ pDstProfile->pRSNReqIE =
+ cdf_mem_malloc(pSrcProfile->nRSNReqIELength);
+ if (NULL == pDstProfile->pRSNReqIE) {
+ status = CDF_STATUS_E_NOMEM;
+ goto end;
+ }
+ pDstProfile->nRSNReqIELength =
+ pSrcProfile->nRSNReqIELength;
+ cdf_mem_copy(pDstProfile->pRSNReqIE, pSrcProfile->pRSNReqIE,
+ pSrcProfile->nRSNReqIELength);
+ }
+#ifdef FEATURE_WLAN_WAPI
+ if (pSrcProfile->nWAPIReqIELength) {
+ pDstProfile->pWAPIReqIE =
+ cdf_mem_malloc(pSrcProfile->nWAPIReqIELength);
+ if (NULL == pDstProfile->pWAPIReqIE) {
+ status = CDF_STATUS_E_NOMEM;
+ goto end;
+ }
+ pDstProfile->nWAPIReqIELength =
+ pSrcProfile->nWAPIReqIELength;
+ cdf_mem_copy(pDstProfile->pWAPIReqIE, pSrcProfile->pWAPIReqIE,
+ pSrcProfile->nWAPIReqIELength);
+ }
+#endif /* FEATURE_WLAN_WAPI */
+ if (pSrcProfile->nAddIEScanLength) {
+ pDstProfile->pAddIEScan =
+ cdf_mem_malloc(pSrcProfile->nAddIEScanLength);
+ if (NULL == pDstProfile->pAddIEScan) {
+ status = CDF_STATUS_E_NOMEM;
+ goto end;
+ }
+ pDstProfile->nAddIEScanLength =
+ pSrcProfile->nAddIEScanLength;
+ cdf_mem_copy(pDstProfile->pAddIEScan, pSrcProfile->pAddIEScan,
+ pSrcProfile->nAddIEScanLength);
+ }
+ if (pSrcProfile->nAddIEAssocLength) {
+ pDstProfile->pAddIEAssoc =
+ cdf_mem_malloc(pSrcProfile->nAddIEAssocLength);
+ if (NULL == pDstProfile->pAddIEAssoc) {
+ status = CDF_STATUS_E_NOMEM;
+ goto end;
+ }
+ pDstProfile->nAddIEAssocLength =
+ pSrcProfile->nAddIEAssocLength;
+ cdf_mem_copy(pDstProfile->pAddIEAssoc, pSrcProfile->pAddIEAssoc,
+ pSrcProfile->nAddIEAssocLength);
+ }
+ if (pSrcProfile->ChannelInfo.ChannelList) {
+ pDstProfile->ChannelInfo.ChannelList =
+ cdf_mem_malloc(pSrcProfile->ChannelInfo.
+ numOfChannels);
+ if (NULL == pDstProfile->ChannelInfo.ChannelList) {
+ status = CDF_STATUS_E_NOMEM;
+ goto end;
+ }
+ pDstProfile->ChannelInfo.numOfChannels =
+ pSrcProfile->ChannelInfo.numOfChannels;
+ cdf_mem_copy(pDstProfile->ChannelInfo.ChannelList,
+ pSrcProfile->ChannelInfo.ChannelList,
+ pSrcProfile->ChannelInfo.numOfChannels);
+ }
+ pDstProfile->AuthType = pSrcProfile->AuthType;
+ pDstProfile->EncryptionType = pSrcProfile->EncryptionType;
+ pDstProfile->mcEncryptionType = pSrcProfile->mcEncryptionType;
+ pDstProfile->negotiatedUCEncryptionType =
+ pSrcProfile->negotiatedUCEncryptionType;
+ pDstProfile->negotiatedMCEncryptionType =
+ pSrcProfile->negotiatedMCEncryptionType;
+ pDstProfile->negotiatedAuthType = pSrcProfile->negotiatedAuthType;
+#ifdef WLAN_FEATURE_11W
+ pDstProfile->MFPEnabled = pSrcProfile->MFPEnabled;
+ pDstProfile->MFPRequired = pSrcProfile->MFPRequired;
+ pDstProfile->MFPCapable = pSrcProfile->MFPCapable;
+#endif
+ pDstProfile->BSSType = pSrcProfile->BSSType;
+ pDstProfile->phyMode = pSrcProfile->phyMode;
+ pDstProfile->csrPersona = pSrcProfile->csrPersona;
+
+#ifdef FEATURE_WLAN_WAPI
+ if (csr_is_profile_wapi(pSrcProfile))
+ if (pDstProfile->phyMode & eCSR_DOT11_MODE_11n)
+ pDstProfile->phyMode &= ~eCSR_DOT11_MODE_11n;
+#endif /* FEATURE_WLAN_WAPI */
+ pDstProfile->CBMode = pSrcProfile->CBMode;
+ pDstProfile->ch_params.ch_width = pSrcProfile->ch_params.ch_width;
+ pDstProfile->ch_params.center_freq_seg0 =
+ pSrcProfile->ch_params.center_freq_seg0;
+ pDstProfile->ch_params.center_freq_seg1 =
+ pSrcProfile->ch_params.center_freq_seg1;
+ pDstProfile->ch_params.sec_ch_offset =
+ pSrcProfile->ch_params.sec_ch_offset;
+ /*Save the WPS info */
+ pDstProfile->bWPSAssociation = pSrcProfile->bWPSAssociation;
+ pDstProfile->bOSENAssociation = pSrcProfile->bOSENAssociation;
+ pDstProfile->uapsd_mask = pSrcProfile->uapsd_mask;
+ pDstProfile->beaconInterval = pSrcProfile->beaconInterval;
+ pDstProfile->privacy = pSrcProfile->privacy;
+ pDstProfile->fwdWPSPBCProbeReq = pSrcProfile->fwdWPSPBCProbeReq;
+ pDstProfile->csr80211AuthType = pSrcProfile->csr80211AuthType;
+ pDstProfile->dtimPeriod = pSrcProfile->dtimPeriod;
+ pDstProfile->ApUapsdEnable = pSrcProfile->ApUapsdEnable;
+ pDstProfile->SSIDs.SSIDList[0].ssidHidden =
+ pSrcProfile->SSIDs.SSIDList[0].ssidHidden;
+ pDstProfile->protEnabled = pSrcProfile->protEnabled;
+ pDstProfile->obssProtEnabled = pSrcProfile->obssProtEnabled;
+ pDstProfile->cfg_protection = pSrcProfile->cfg_protection;
+ pDstProfile->wps_state = pSrcProfile->wps_state;
+ pDstProfile->ieee80211d = pSrcProfile->ieee80211d;
+ pDstProfile->sap_dot11mc = pSrcProfile->sap_dot11mc;
+ cdf_mem_copy(&pDstProfile->Keys, &pSrcProfile->Keys,
+ sizeof(pDstProfile->Keys));
+#ifdef WLAN_FEATURE_11W
+ pDstProfile->MFPEnabled = pSrcProfile->MFPEnabled;
+ pDstProfile->MFPRequired = pSrcProfile->MFPRequired;
+ pDstProfile->MFPCapable = pSrcProfile->MFPCapable;
+#endif
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ if (pSrcProfile->MDID.mdiePresent) {
+ pDstProfile->MDID.mdiePresent = 1;
+ pDstProfile->MDID.mobilityDomain =
+ pSrcProfile->MDID.mobilityDomain;
+ }
+#endif
+ cdf_mem_copy(&pDstProfile->addIeParams, &pSrcProfile->addIeParams,
+ sizeof(tSirAddIeParams));
+end:
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ csr_release_profile(pMac, pDstProfile);
+ pDstProfile = NULL;
+ }
+
+ return status;
+}
+
+CDF_STATUS csr_roam_copy_connected_profile(tpAniSirGlobal pMac,
+ uint32_t sessionId, tCsrRoamProfile *pDstProfile)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tCsrRoamConnectedProfile *pSrcProfile =
+ &pMac->roam.roamSession[sessionId].connectedProfile;
+
+ cdf_mem_set(pDstProfile, sizeof(tCsrRoamProfile), 0);
+
+ pDstProfile->BSSIDs.bssid = cdf_mem_malloc(sizeof(struct cdf_mac_addr));
+ if (NULL == pDstProfile->BSSIDs.bssid) {
+ status = CDF_STATUS_E_NOMEM;
+ sms_log(pMac, LOGE,
+ FL("failed to allocate memory for BSSID "
+ MAC_ADDRESS_STR),
+ MAC_ADDR_ARRAY(pSrcProfile->bssid.bytes));
+ goto end;
+ }
+ pDstProfile->BSSIDs.numOfBSSIDs = 1;
+ cdf_copy_macaddr(pDstProfile->BSSIDs.bssid, &pSrcProfile->bssid);
+
+ if (pSrcProfile->SSID.ssId) {
+ pDstProfile->SSIDs.SSIDList =
+ cdf_mem_malloc(sizeof(tCsrSSIDInfo));
+ if (NULL == pDstProfile->SSIDs.SSIDList) {
+ status = CDF_STATUS_E_NOMEM;
+ sms_log(pMac, LOGE,
+ FL("failed to allocate memory for SSID "
+ MAC_ADDRESS_STR),
+ MAC_ADDR_ARRAY(pSrcProfile->bssid.bytes));
+ goto end;
+ }
+ pDstProfile->SSIDs.numOfSSIDs = 1;
+ pDstProfile->SSIDs.SSIDList[0].handoffPermitted =
+ pSrcProfile->handoffPermitted;
+ pDstProfile->SSIDs.SSIDList[0].ssidHidden =
+ pSrcProfile->ssidHidden;
+ cdf_mem_copy(&pDstProfile->SSIDs.SSIDList[0].SSID,
+ &pSrcProfile->SSID, sizeof(tSirMacSSid));
+ }
+ if (pSrcProfile->nAddIEAssocLength) {
+ pDstProfile->pAddIEAssoc =
+ cdf_mem_malloc(pSrcProfile->nAddIEAssocLength);
+ if (NULL == pDstProfile->pAddIEAssoc) {
+ status = CDF_STATUS_E_NOMEM;
+ sms_log(pMac, LOGE,
+ FL("failed to allocate mem for additional ie"));
+ goto end;
+ }
+ pDstProfile->nAddIEAssocLength = pSrcProfile->nAddIEAssocLength;
+ cdf_mem_copy(pDstProfile->pAddIEAssoc, pSrcProfile->pAddIEAssoc,
+ pSrcProfile->nAddIEAssocLength);
+ }
+ pDstProfile->ChannelInfo.ChannelList = cdf_mem_malloc(1);
+ if (NULL == pDstProfile->ChannelInfo.ChannelList) {
+ status = CDF_STATUS_E_NOMEM;
+ goto end;
+ }
+ pDstProfile->ChannelInfo.numOfChannels = 1;
+ pDstProfile->ChannelInfo.ChannelList[0] = pSrcProfile->operationChannel;
+ pDstProfile->AuthType.numEntries = 1;
+ pDstProfile->AuthType.authType[0] = pSrcProfile->AuthType;
+ pDstProfile->negotiatedAuthType = pSrcProfile->AuthType;
+ pDstProfile->EncryptionType.numEntries = 1;
+ pDstProfile->EncryptionType.encryptionType[0] =
+ pSrcProfile->EncryptionType;
+ pDstProfile->negotiatedUCEncryptionType =
+ pSrcProfile->EncryptionType;
+ pDstProfile->mcEncryptionType.numEntries = 1;
+ pDstProfile->mcEncryptionType.encryptionType[0] =
+ pSrcProfile->mcEncryptionType;
+ pDstProfile->negotiatedMCEncryptionType =
+ pSrcProfile->mcEncryptionType;
+ pDstProfile->BSSType = pSrcProfile->BSSType;
+ pDstProfile->CBMode = pSrcProfile->CBMode;
+ cdf_mem_copy(&pDstProfile->Keys, &pSrcProfile->Keys,
+ sizeof(pDstProfile->Keys));
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ if (pSrcProfile->MDID.mdiePresent) {
+ pDstProfile->MDID.mdiePresent = 1;
+ pDstProfile->MDID.mobilityDomain =
+ pSrcProfile->MDID.mobilityDomain;
+ }
+#endif
+
+end:
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ csr_release_profile(pMac, pDstProfile);
+ pDstProfile = NULL;
+ }
+
+ return status;
+}
+
+CDF_STATUS csr_roam_issue_connect(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamProfile *pProfile,
+ tScanResultHandle hBSSList,
+ eCsrRoamReason reason, uint32_t roamId,
+ bool fImediate, bool fClearScan)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSmeCmd *pCommand;
+
+ pCommand = csr_get_command_buffer(pMac);
+ if (NULL == pCommand) {
+ sms_log(pMac, LOGE, FL(" fail to get command buffer"));
+ status = CDF_STATUS_E_RESOURCES;
+ } else {
+ if (fClearScan) {
+ csr_scan_abort_mac_scan_not_for_connect(pMac, sessionId);
+ }
+ pCommand->u.roamCmd.fReleaseProfile = false;
+ if (NULL == pProfile) {
+ /* We can roam now */
+ /* Since pProfile is NULL, we need to build our own profile, set everything to default */
+ /* We can only support open and no encryption */
+ pCommand->u.roamCmd.roamProfile.AuthType.numEntries = 1;
+ pCommand->u.roamCmd.roamProfile.AuthType.authType[0] =
+ eCSR_AUTH_TYPE_OPEN_SYSTEM;
+ pCommand->u.roamCmd.roamProfile.EncryptionType.
+ numEntries = 1;
+ pCommand->u.roamCmd.roamProfile.EncryptionType.
+ encryptionType[0] = eCSR_ENCRYPT_TYPE_NONE;
+ pCommand->u.roamCmd.roamProfile.csrPersona =
+ CDF_STA_MODE;
+ } else {
+ /* make a copy of the profile */
+ status =
+ csr_roam_copy_profile(pMac,
+ &pCommand->u.roamCmd.roamProfile,
+ pProfile);
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ pCommand->u.roamCmd.fReleaseProfile = true;
+ }
+ }
+
+ pCommand->command = eSmeCommandRoam;
+ pCommand->sessionId = (uint8_t) sessionId;
+ pCommand->u.roamCmd.hBSSList = hBSSList;
+ pCommand->u.roamCmd.roamId = roamId;
+ pCommand->u.roamCmd.roamReason = reason;
+ /* We need to free the BssList when the command is done */
+ pCommand->u.roamCmd.fReleaseBssList = true;
+ pCommand->u.roamCmd.fUpdateCurRoamProfile = true;
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ FL("CSR PERSONA=%d"),
+ pCommand->u.roamCmd.roamProfile.csrPersona);
+ status = csr_queue_sme_command(pMac, pCommand, fImediate);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ FL(" fail to send message status = %d"), status);
+ csr_release_command_roam(pMac, pCommand);
+ }
+ }
+
+ return status;
+}
+
+CDF_STATUS csr_roam_issue_reassoc(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamProfile *pProfile,
+ tCsrRoamModifyProfileFields *pMmodProfileFields,
+ eCsrRoamReason reason, uint32_t roamId,
+ bool fImediate)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSmeCmd *pCommand;
+
+ pCommand = csr_get_command_buffer(pMac);
+ if (NULL == pCommand) {
+ sms_log(pMac, LOGE, FL(" fail to get command buffer"));
+ status = CDF_STATUS_E_RESOURCES;
+ } else {
+ csr_scan_abort_mac_scan_not_for_connect(pMac, sessionId);
+ if (pProfile) {
+ /* This is likely trying to reassoc to different profile */
+ pCommand->u.roamCmd.fReleaseProfile = false;
+ /* make a copy of the profile */
+ status =
+ csr_roam_copy_profile(pMac,
+ &pCommand->u.roamCmd.roamProfile,
+ pProfile);
+ pCommand->u.roamCmd.fUpdateCurRoamProfile = true;
+ } else {
+ status =
+ csr_roam_copy_connected_profile(pMac, sessionId,
+ &pCommand->u.roamCmd.
+ roamProfile);
+ /* how to update WPA/WPA2 info in roamProfile?? */
+ pCommand->u.roamCmd.roamProfile.uapsd_mask =
+ pMmodProfileFields->uapsd_mask;
+ }
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ pCommand->u.roamCmd.fReleaseProfile = true;
+ }
+ pCommand->command = eSmeCommandRoam;
+ pCommand->sessionId = (uint8_t) sessionId;
+ pCommand->u.roamCmd.roamId = roamId;
+ pCommand->u.roamCmd.roamReason = reason;
+ /* We need to free the BssList when the command is done */
+ /* For reassoc there is no BSS list, so the bool set to false */
+ pCommand->u.roamCmd.hBSSList = CSR_INVALID_SCANRESULT_HANDLE;
+ pCommand->u.roamCmd.fReleaseBssList = false;
+ pCommand->u.roamCmd.fReassoc = true;
+ csr_roam_remove_duplicate_command(pMac, sessionId, pCommand,
+ reason);
+ status = csr_queue_sme_command(pMac, pCommand, fImediate);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ FL(" fail to send message status = %d"), status);
+ csr_roam_completion(pMac, sessionId, NULL, pCommand,
+ eCSR_ROAM_RESULT_FAILURE, false);
+ csr_release_command_roam(pMac, pCommand);
+ }
+ }
+ return status;
+}
+
+CDF_STATUS csr_roam_enqueue_preauth(tpAniSirGlobal pMac, uint32_t sessionId,
+ tpSirBssDescription pBssDescription,
+ eCsrRoamReason reason, bool fImmediate)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSmeCmd *pCommand;
+
+ pCommand = csr_get_command_buffer(pMac);
+ if (NULL == pCommand) {
+ sms_log(pMac, LOGE, FL(" fail to get command buffer"));
+ status = CDF_STATUS_E_RESOURCES;
+ } else {
+ if (pBssDescription) {
+ /* copy over the parameters we need later */
+ pCommand->command = eSmeCommandRoam;
+ pCommand->sessionId = (uint8_t) sessionId;
+ pCommand->u.roamCmd.roamReason = reason;
+ /* this is the important parameter */
+ /* in this case we are using this field for the "next" BSS */
+ pCommand->u.roamCmd.pLastRoamBss = pBssDescription;
+ status = csr_queue_sme_command(pMac, pCommand, fImmediate);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ FL
+ (" fail to enqueue preauth command, status = %d"),
+ status);
+ csr_release_command_preauth(pMac, pCommand);
+ }
+ } else {
+ /* Return failure */
+ status = CDF_STATUS_E_RESOURCES;
+ }
+ }
+ return status;
+}
+
+CDF_STATUS csr_dequeue_roam_command(tpAniSirGlobal pMac, eCsrRoamReason reason)
+{
+ tListElem *pEntry;
+ tSmeCmd *pCommand;
+ pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK);
+ if (pEntry) {
+ pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
+ if ((eSmeCommandRoam == pCommand->command) &&
+ (eCsrPerformPreauth == reason)) {
+ sms_log(pMac, LOG1, FL("DQ-Command = %d, Reason = %d"),
+ pCommand->command,
+ pCommand->u.roamCmd.roamReason);
+ if (csr_ll_remove_entry
+ (&pMac->sme.smeCmdActiveList, pEntry,
+ LL_ACCESS_LOCK)) {
+ csr_release_command_preauth(pMac, pCommand);
+ }
+ } else if ((eSmeCommandRoam == pCommand->command) &&
+ (eCsrSmeIssuedFTReassoc == reason)) {
+ sms_log(pMac, LOG1, FL("DQ-Command = %d, Reason = %d"),
+ pCommand->command,
+ pCommand->u.roamCmd.roamReason);
+ if (csr_ll_remove_entry
+ (&pMac->sme.smeCmdActiveList, pEntry,
+ LL_ACCESS_LOCK)) {
+ csr_release_command_roam(pMac, pCommand);
+ }
+ } else {
+ sms_log(pMac, LOGE, FL("Command = %d, Reason = %d "),
+ pCommand->command,
+ pCommand->u.roamCmd.roamReason);
+ }
+ } else {
+ sms_log(pMac, LOGE,
+ FL("pEntry NULL for eWNI_SME_FT_PRE_AUTH_RSP"));
+ }
+ sme_process_pending_queue(pMac);
+ return CDF_STATUS_SUCCESS;
+}
+
+CDF_STATUS csr_roam_connect(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamProfile *pProfile,
+ uint32_t *pRoamId)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tScanResultHandle hBSSList;
+ tCsrScanResultFilter *pScanFilter;
+ uint32_t roamId = 0;
+ bool fCallCallback = false;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+ tSirBssDescription first_ap_profile;
+
+ if (NULL == pSession) {
+ sms_log(pMac, LOGE,
+ FL("session does not exist for given sessionId:%d"),
+ sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ if (NULL == pProfile) {
+ sms_log(pMac, LOGP, FL("No profile specified"));
+ return CDF_STATUS_E_FAILURE;
+ }
+ /* Initialize the count before proceeding with the Join requests */
+ pSession->join_bssid_count = 0;
+ sms_log(pMac, LOG1,
+ FL("called BSSType = %d authtype = %d encryType = %d"),
+ pProfile->BSSType, pProfile->AuthType.authType[0],
+ pProfile->EncryptionType.encryptionType[0]);
+ csr_roam_cancel_roaming(pMac, sessionId);
+ csr_scan_remove_fresh_scan_command(pMac, sessionId);
+ /* Only abort the scan if its not used for other roam/connect purpose */
+ csr_scan_abort_mac_scan(pMac, sessionId, eCSR_SCAN_ABORT_DEFAULT);
+ csr_roam_remove_duplicate_command(pMac, sessionId, NULL, eCsrHddIssued);
+ /* Check whether ssid changes */
+ if (csr_is_conn_state_connected(pMac, sessionId) &&
+ pProfile->SSIDs.numOfSSIDs && !csr_is_ssid_in_list(pMac,
+ &pSession->connectedProfile.SSID, &pProfile->SSIDs))
+ csr_roam_issue_disassociate_cmd(pMac, sessionId,
+ eCSR_DISCONNECT_REASON_UNSPECIFIED);
+#ifdef FEATURE_WLAN_BTAMP_UT_RF
+ pSession->maxRetryCount = CSR_JOIN_MAX_RETRY_COUNT;
+#endif
+ pScanFilter = cdf_mem_malloc(sizeof(tCsrScanResultFilter));
+ if (NULL == pScanFilter) {
+ status = CDF_STATUS_E_NOMEM;
+ goto end;
+ }
+
+ cdf_mem_set(pScanFilter, sizeof(tCsrScanResultFilter),
+ 0);
+ /* Try to connect to any BSS */
+ if (NULL == pProfile) {
+ /* No encryption */
+ pScanFilter->EncryptionType.numEntries = 1;
+ pScanFilter->EncryptionType.encryptionType[0] =
+ eCSR_ENCRYPT_TYPE_NONE;
+ } else {
+ /* Here is the profile we need to connect to */
+ status = csr_roam_prepare_filter_from_profile(pMac,
+ pProfile, pScanFilter);
+ }
+ roamId = GET_NEXT_ROAM_ID(&pMac->roam);
+ if (pRoamId)
+ *pRoamId = roamId;
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ cdf_mem_free(pScanFilter);
+ goto end;
+ }
+
+ /*Save the WPS info */
+ if (NULL != pProfile) {
+ pScanFilter->bWPSAssociation =
+ pProfile->bWPSAssociation;
+ pScanFilter->bOSENAssociation =
+ pProfile->bOSENAssociation;
+ } else {
+ pScanFilter->bWPSAssociation = 0;
+ pScanFilter->bOSENAssociation = 0;
+ }
+ if ((pProfile && CSR_IS_WDS_AP(pProfile)) || (pProfile
+ && CSR_IS_INFRA_AP(pProfile))) {
+ /* This can be started right away */
+ status = csr_roam_issue_connect(pMac, sessionId, pProfile, NULL,
+ eCsrHddIssued, roamId, false, false);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ FL("CSR failed to issue start BSS cmd with status = 0x%08X"),
+ status);
+ fCallCallback = true;
+ } else {
+ sms_log(pMac, LOG1,
+ FL("Connect request to proceed for sap mode"));
+ }
+
+ csr_free_scan_filter(pMac, pScanFilter);
+ cdf_mem_free(pScanFilter);
+ goto end;
+ }
+ status = csr_scan_get_result(pMac, pScanFilter, &hBSSList);
+ sms_log(pMac, LOG1,
+ FL("******* csr_scan_get_result Status ****** %d"), status);
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ /* check if set hw mode needs to be done */
+ if ((pMac->policy_manager_enabled) &&
+ (pScanFilter->csrPersona == CDF_STA_MODE)) {
+ csr_get_bssdescr_from_scan_handle(hBSSList,
+ &first_ap_profile);
+ if (!cds_handle_conc_multiport(sessionId,
+ first_ap_profile.channelId)) {
+ sms_log(pMac, LOG1, FL("conc multiport error"));
+ csr_scan_result_purge(pMac, hBSSList);
+ fCallCallback = true;
+ goto error;
+ }
+ }
+
+ status = csr_roam_issue_connect(pMac, sessionId, pProfile,
+ hBSSList, eCsrHddIssued, roamId, false, false);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ FL("CSR failed to issue connect cmd with status = 0x%08X"),
+ status);
+ csr_scan_result_purge(pMac, hBSSList);
+ fCallCallback = true;
+ }
+ } else if (NULL != pProfile) {
+ /* Check whether it is for start ibss */
+ if (CSR_IS_START_IBSS(pProfile)) {
+ status = csr_roam_issue_connect(pMac, sessionId,
+ pProfile, NULL, eCsrHddIssued,
+ roamId, false, false);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ FL("CSR failed to issue startIBSS cmd with status = 0x%08X"),
+ status);
+ fCallCallback = true;
+ }
+ } else {
+ /* scan for this SSID */
+ status = csr_scan_for_ssid(pMac, sessionId, pProfile,
+ roamId, true);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ FL("CSR failed to issue SSID scan cmd with status = 0x%08X"),
+ status);
+ fCallCallback = true;
+ } else {
+ sms_log(pMac, LOG1,
+ FL("SSID scan requested"));
+ }
+ }
+ } else {
+ fCallCallback = true;
+ }
+
+error:
+ if (NULL != pProfile)
+ /*
+ * we need to free memory for filter
+ * if profile exists
+ */
+ csr_free_scan_filter(pMac, pScanFilter);
+
+ cdf_mem_free(pScanFilter);
+end:
+ /* tell the caller if we fail to trigger a join request */
+ if (fCallCallback) {
+ csr_roam_call_callback(pMac, sessionId, NULL, roamId,
+ eCSR_ROAM_FAILED, eCSR_ROAM_RESULT_FAILURE);
+ }
+ return status;
+}
+
+/**
+ * csr_roam_reassoc() - process reassoc command
+ * @mac_ctx: mac global context
+ * @session_id: session id
+ * @profile: roam profile
+ * @mod_fields: AC info being modified in reassoc
+ * @roam_id: roam id to be populated
+ *
+ * Return: status of operation
+ */
+CDF_STATUS
+csr_roam_reassoc(tpAniSirGlobal mac_ctx, uint32_t session_id,
+ tCsrRoamProfile *profile,
+ tCsrRoamModifyProfileFields mod_fields,
+ uint32_t *roam_id)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ bool fCallCallback = true;
+ uint32_t roamId = 0;
+
+ tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id);
+ if (NULL == profile) {
+ sms_log(mac_ctx, LOGP, FL("No profile specified"));
+ return CDF_STATUS_E_FAILURE;
+ }
+ sms_log(mac_ctx, LOG1,
+ FL("called BSSType = %d authtype = %d encryType = %d"),
+ profile->BSSType, profile->AuthType.authType[0],
+ profile->EncryptionType.encryptionType[0]);
+ csr_roam_cancel_roaming(mac_ctx, session_id);
+ csr_scan_remove_fresh_scan_command(mac_ctx, session_id);
+ csr_scan_abort_mac_scan_not_for_connect(mac_ctx, session_id);
+ csr_roam_remove_duplicate_command(mac_ctx, session_id, NULL,
+ eCsrHddIssuedReassocToSameAP);
+ if (csr_is_conn_state_connected(mac_ctx, session_id)) {
+ if (profile) {
+ if (profile->SSIDs.numOfSSIDs &&
+ csr_is_ssid_in_list(mac_ctx,
+ &session->connectedProfile.SSID,
+ &profile->SSIDs)) {
+ fCallCallback = false;
+ } else {
+ /*
+ * Connected SSID did not match with what is
+ * asked in profile
+ */
+ sms_log(mac_ctx, LOG1, FL("SSID mismatch"));
+ }
+ } else if (!cdf_mem_compare(&mod_fields,
+ &session->connectedProfile.modifyProfileFields,
+ sizeof(tCsrRoamModifyProfileFields))) {
+ fCallCallback = false;
+ } else {
+ sms_log(mac_ctx, LOG1,
+ /*
+ * Either the profile is NULL or none of the
+ * fields in tCsrRoamModifyProfileFields got
+ * modified
+ */
+ FL("Profile NULL or nothing to modify."));
+ }
+ } else {
+ sms_log(mac_ctx, LOG1, FL("Not connected! No need to reassoc"));
+ }
+ if (!fCallCallback) {
+ roamId = GET_NEXT_ROAM_ID(&mac_ctx->roam);
+ if (roam_id)
+ *roam_id = roamId;
+ status = csr_roam_issue_reassoc(mac_ctx, session_id, profile,
+ &mod_fields, eCsrHddIssuedReassocToSameAP,
+ roamId, false);
+ } else {
+ status = csr_roam_call_callback(mac_ctx, session_id, NULL,
+ roamId, eCSR_ROAM_FAILED,
+ eCSR_ROAM_RESULT_FAILURE);
+ }
+ return status;
+}
+
+CDF_STATUS csr_roam_join_last_profile(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ tScanResultHandle hBSSList = NULL;
+ tCsrScanResultFilter *pScanFilter = NULL;
+ uint32_t roamId;
+ 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;
+ }
+
+ if (pSession->pCurRoamProfile) {
+ csr_scan_abort_mac_scan_not_for_connect(pMac, sessionId);
+ /* 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 end;
+ }
+ cdf_mem_set(pProfile, sizeof(tCsrRoamProfile), 0);
+ status = csr_roam_copy_profile(pMac, pProfile,
+ pSession->pCurRoamProfile);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ goto end;
+ pScanFilter = cdf_mem_malloc(sizeof(tCsrScanResultFilter));
+ if (NULL == pScanFilter) {
+ status = CDF_STATUS_E_NOMEM;
+ goto end;
+ }
+ cdf_mem_set(pScanFilter, sizeof(tCsrScanResultFilter), 0);
+ status = csr_roam_prepare_filter_from_profile(pMac, pProfile,
+ pScanFilter);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ goto end;
+ roamId = GET_NEXT_ROAM_ID(&pMac->roam);
+ status = csr_scan_get_result(pMac, pScanFilter, &hBSSList);
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ /* we want to put the last connected BSS to the
+ * very beginning, if possible */
+ csr_move_bss_to_head_from_bssid(pMac,
+ &pSession->connectedProfile.bssid, hBSSList);
+ status = csr_roam_issue_connect(pMac, sessionId,
+ pProfile, hBSSList, eCsrHddIssued,
+ roamId, false, false);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ csr_scan_result_purge(pMac, hBSSList);
+ goto end;
+ }
+ } else {
+ /* scan for this SSID only incase AP suppresses SSID */
+ status = csr_scan_for_ssid(pMac, sessionId, pProfile,
+ roamId, true);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ goto end;
+ }
+ } /* We have a profile */
+ else {
+ sms_log(pMac, LOGW, FL("cannot find a roaming profile"));
+ goto end;
+ }
+end:
+ if (pScanFilter) {
+ 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_roam_reconnect(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ if (csr_is_conn_state_connected(pMac, sessionId)) {
+ status =
+ csr_roam_issue_disassociate_cmd(pMac, sessionId,
+ eCSR_DISCONNECT_REASON_UNSPECIFIED);
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ status = csr_roam_join_last_profile(pMac, sessionId);
+ }
+ }
+ return status;
+}
+
+CDF_STATUS csr_roam_connect_to_last_profile(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ sms_log(pMac, LOGW, FL("is called"));
+ csr_roam_cancel_roaming(pMac, sessionId);
+ csr_roam_remove_duplicate_command(pMac, sessionId, NULL, eCsrHddIssued);
+ if (csr_is_conn_state_disconnected(pMac, sessionId)) {
+ status = csr_roam_join_last_profile(pMac, sessionId);
+ }
+ return status;
+}
+
+CDF_STATUS csr_roam_process_disassoc_deauth(tpAniSirGlobal pMac, tSmeCmd *pCommand,
+ bool fDisassoc, bool fMICFailure)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ bool fComplete = false;
+ eCsrRoamSubState NewSubstate;
+ uint32_t sessionId = pCommand->sessionId;
+
+ if (CSR_IS_WAIT_FOR_KEY(pMac, sessionId)) {
+ sms_log(pMac, LOG1,
+ FL(" Stop Wait for key timer and change substate to"
+ " eCSR_ROAM_SUBSTATE_NONE"));
+ csr_roam_stop_wait_for_key_timer(pMac);
+ csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_NONE, sessionId);
+ }
+ /* change state to 'Roaming'... */
+ csr_roam_state_change(pMac, eCSR_ROAMING_STATE_JOINING, sessionId);
+
+ if (csr_is_conn_state_ibss(pMac, sessionId)) {
+ /* If we are in an IBSS, then stop the IBSS... */
+ status =
+ csr_roam_issue_stop_bss(pMac, sessionId,
+ eCSR_ROAM_SUBSTATE_STOP_BSS_REQ);
+ fComplete = (!CDF_IS_STATUS_SUCCESS(status));
+ } else if (csr_is_conn_state_infra(pMac, sessionId)) {
+ /*
+ * in Infrastructure, we need to disassociate from the
+ * Infrastructure network...
+ */
+ NewSubstate = eCSR_ROAM_SUBSTATE_DISASSOC_FORCED;
+ if (eCsrSmeIssuedDisassocForHandoff ==
+ pCommand->u.roamCmd.roamReason) {
+ NewSubstate = eCSR_ROAM_SUBSTATE_DISASSOC_HANDOFF;
+ } else
+ if ((eCsrForcedDisassoc == pCommand->u.roamCmd.roamReason)
+ && (eSIR_MAC_DISASSOC_LEAVING_BSS_REASON ==
+ pCommand->u.roamCmd.reason)) {
+ NewSubstate = eCSR_ROAM_SUBSTATE_DISASSOC_STA_HAS_LEFT;
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ FL
+ ("set to substate eCSR_ROAM_SUBSTATE_DISASSOC_STA_HAS_LEFT"));
+ }
+ if (fDisassoc) {
+ status =
+ csr_roam_issue_disassociate(pMac, sessionId,
+ NewSubstate, fMICFailure);
+ } else {
+ status =
+ csr_roam_issue_deauth(pMac, sessionId,
+ eCSR_ROAM_SUBSTATE_DEAUTH_REQ);
+ }
+ fComplete = (!CDF_IS_STATUS_SUCCESS(status));
+ } else if (csr_is_conn_state_wds(pMac, sessionId)) {
+ if (CSR_IS_WDS_AP
+ (&pMac->roam.roamSession[sessionId].connectedProfile)) {
+ status =
+ csr_roam_issue_stop_bss(pMac, sessionId,
+ eCSR_ROAM_SUBSTATE_STOP_BSS_REQ);
+ fComplete = (!CDF_IS_STATUS_SUCCESS(status));
+ }
+ /* This has to be WDS station */
+ else if (csr_is_conn_state_connected_wds(pMac, sessionId)) {
+ /* This has to be WDS station */
+ pCommand->u.roamCmd.fStopWds = true;
+ if (fDisassoc) {
+ status =
+ csr_roam_issue_disassociate(pMac, sessionId,
+ eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING,
+ fMICFailure);
+ fComplete = (!CDF_IS_STATUS_SUCCESS(status));
+ }
+ }
+ } else {
+ /* we got a dis-assoc request while not connected to any peer */
+ /* just complete the command */
+ fComplete = true;
+ status = CDF_STATUS_E_FAILURE;
+ }
+ if (fComplete) {
+ csr_roam_complete(pMac, eCsrNothingToJoin, NULL);
+ }
+
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ if (csr_is_conn_state_infra(pMac, sessionId)) {
+ /* Set the state to disconnect here */
+ pMac->roam.roamSession[sessionId].connectState =
+ eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED;
+ }
+ } else {
+ sms_log(pMac, LOGW, FL(" failed with status %d"), status);
+ }
+ return status;
+}
+
+/**
+ * csr_prepare_disconnect_command() - function to prepare disconnect command
+ * @mac: pointer to global mac structure
+ * @session_id: sme session index
+ * @sme_cmd: pointer to sme command being prepared
+ *
+ * Function to prepare internal sme disconnect command
+ * Return: CDF_STATUS_SUCCESS on success else CDF_STATUS_E_RESOURCES on failure
+ */
+
+CDF_STATUS csr_prepare_disconnect_command(tpAniSirGlobal mac,
+ uint32_t session_id, tSmeCmd **sme_cmd)
+{
+ tSmeCmd *command;
+
+ command = csr_get_command_buffer(mac);
+ if (!command) {
+ sms_log(mac, LOGE, FL("fail to get command buffer"));
+ return CDF_STATUS_E_RESOURCES;
+ }
+
+ command->command = eSmeCommandRoam;
+ command->sessionId = (uint8_t)session_id;
+ command->u.roamCmd.roamReason = eCsrForcedDisassoc;
+
+ *sme_cmd = command;
+ return CDF_STATUS_SUCCESS;
+}
+
+CDF_STATUS csr_roam_issue_disassociate_cmd(tpAniSirGlobal pMac, uint32_t sessionId,
+ eCsrRoamDisconnectReason reason)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSmeCmd *pCommand;
+ bool fHighPriority = false;
+ do {
+ pCommand = csr_get_command_buffer(pMac);
+ if (!pCommand) {
+ sms_log(pMac, LOGE, FL(" fail to get command buffer"));
+ status = CDF_STATUS_E_RESOURCES;
+ break;
+ }
+ /* Change the substate in case it is wait-for-key */
+ if (CSR_IS_WAIT_FOR_KEY(pMac, sessionId)) {
+ csr_roam_stop_wait_for_key_timer(pMac);
+ csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_NONE,
+ sessionId);
+ }
+ pCommand->command = eSmeCommandRoam;
+ pCommand->sessionId = (uint8_t) sessionId;
+ sms_log(pMac, LOG1,
+ FL("Disassociate reason: %d, sessionId: %d"),
+ reason, sessionId);
+ switch (reason) {
+ case eCSR_DISCONNECT_REASON_MIC_ERROR:
+ pCommand->u.roamCmd.roamReason =
+ eCsrForcedDisassocMICFailure;
+ break;
+ case eCSR_DISCONNECT_REASON_DEAUTH:
+ pCommand->u.roamCmd.roamReason = eCsrForcedDeauth;
+ break;
+ case eCSR_DISCONNECT_REASON_HANDOFF:
+ fHighPriority = true;
+ pCommand->u.roamCmd.roamReason =
+ eCsrSmeIssuedDisassocForHandoff;
+ break;
+ case eCSR_DISCONNECT_REASON_UNSPECIFIED:
+ case eCSR_DISCONNECT_REASON_DISASSOC:
+ pCommand->u.roamCmd.roamReason = eCsrForcedDisassoc;
+ break;
+ case eCSR_DISCONNECT_REASON_IBSS_JOIN_FAILURE:
+ pCommand->u.roamCmd.roamReason =
+ eCsrSmeIssuedIbssJoinFailure;
+ break;
+ case eCSR_DISCONNECT_REASON_IBSS_LEAVE:
+ pCommand->u.roamCmd.roamReason = eCsrForcedIbssLeave;
+ break;
+ case eCSR_DISCONNECT_REASON_STA_HAS_LEFT:
+ pCommand->u.roamCmd.roamReason = eCsrForcedDisassoc;
+ pCommand->u.roamCmd.reason =
+ eSIR_MAC_DISASSOC_LEAVING_BSS_REASON;
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ FL
+ ("SME convert to internal reason code eCsrStaHasLeft"));
+ break;
+ default:
+ break;
+ }
+ status = csr_queue_sme_command(pMac, pCommand, fHighPriority);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ FL(" fail to send message status = %d"), status);
+ csr_release_command_roam(pMac, pCommand);
+ }
+ } while (0);
+ return status;
+}
+
+CDF_STATUS csr_roam_issue_stop_bss_cmd(tpAniSirGlobal pMac, uint32_t sessionId,
+ bool fHighPriority)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSmeCmd *pCommand;
+ pCommand = csr_get_command_buffer(pMac);
+ if (NULL != pCommand) {
+ /* Change the substate in case it is wait-for-key */
+ if (CSR_IS_WAIT_FOR_KEY(pMac, sessionId)) {
+ csr_roam_stop_wait_for_key_timer(pMac);
+ csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_NONE,
+ sessionId);
+ }
+ pCommand->command = eSmeCommandRoam;
+ pCommand->sessionId = (uint8_t) sessionId;
+ pCommand->u.roamCmd.roamReason = eCsrStopBss;
+ status = csr_queue_sme_command(pMac, pCommand, fHighPriority);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ FL(" fail to send message status = %d"), status);
+ csr_release_command_roam(pMac, pCommand);
+ }
+ } else {
+ sms_log(pMac, LOGE, FL(" fail to get command buffer"));
+ status = CDF_STATUS_E_RESOURCES;
+ }
+ return status;
+}
+
+CDF_STATUS csr_roam_disconnect_internal(tpAniSirGlobal pMac, uint32_t sessionId,
+ eCsrRoamDisconnectReason reason)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+#ifdef FEATURE_WLAN_BTAMP_UT_RF
+ /* Stop the retry */
+ pSession->maxRetryCount = 0;
+ csr_roam_stop_join_retry_timer(pMac, sessionId);
+#endif
+ /* Not to call cancel roaming here */
+ /* Only issue disconnect when necessary */
+ if (csr_is_conn_state_connected(pMac, sessionId)
+ || csr_is_bss_type_ibss(pSession->connectedProfile.BSSType)
+ || csr_is_bss_type_wds(pSession->connectedProfile.BSSType)
+ || csr_is_roam_command_waiting_for_session(pMac, sessionId)) {
+ sms_log(pMac, LOG2, FL("called"));
+ status = csr_roam_issue_disassociate_cmd(pMac, sessionId,
+ reason);
+ } else {
+ csr_scan_abort_scan_for_ssid(pMac, sessionId);
+ status = CDF_STATUS_CMD_NOT_QUEUED;
+ sms_log(pMac, LOG1,
+ FL
+ (" Disconnect cmd not queued, Roam command is not present"
+ " return with status %d"), status);
+ }
+ return status;
+}
+
+CDF_STATUS csr_roam_disconnect(tpAniSirGlobal pMac, uint32_t sessionId,
+ eCsrRoamDisconnectReason reason)
+{
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ csr_roam_cancel_roaming(pMac, sessionId);
+ csr_roam_remove_duplicate_command(pMac, sessionId, NULL,
+ eCsrForcedDisassoc);
+
+ return csr_roam_disconnect_internal(pMac, sessionId, reason);
+}
+
+CDF_STATUS csr_roam_save_connected_infomation(tpAniSirGlobal pMac,
+ uint32_t sessionId,
+ tCsrRoamProfile *pProfile,
+ tSirBssDescription *pSirBssDesc,
+ tDot11fBeaconIEs *pIes)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tDot11fBeaconIEs *pIesTemp = pIes;
+ uint8_t index;
+ tCsrRoamSession *pSession = NULL;
+ tCsrRoamConnectedProfile *pConnectProfile = NULL;
+
+ pSession = CSR_GET_SESSION(pMac, sessionId);
+ if (NULL == pSession) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ FL("session %d not found"), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+ pConnectProfile = &pSession->connectedProfile;
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+ if (pSession->roamOffloadSynchParams.bRoamSynchInProgress) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ FL("csr_roam_save_connected_infomation"));
+ }
+#endif
+ if (pConnectProfile->pAddIEAssoc) {
+ cdf_mem_free(pConnectProfile->pAddIEAssoc);
+ pConnectProfile->pAddIEAssoc = NULL;
+ }
+ cdf_mem_set(&pSession->connectedProfile,
+ sizeof(tCsrRoamConnectedProfile), 0);
+ pConnectProfile->AuthType = pProfile->negotiatedAuthType;
+ pConnectProfile->AuthInfo = pProfile->AuthType;
+ pConnectProfile->CBMode = pProfile->CBMode; /* *** this may not be valid */
+ pConnectProfile->EncryptionType = pProfile->negotiatedUCEncryptionType;
+ pConnectProfile->EncryptionInfo = pProfile->EncryptionType;
+ pConnectProfile->mcEncryptionType =
+ pProfile->negotiatedMCEncryptionType;
+ pConnectProfile->mcEncryptionInfo = pProfile->mcEncryptionType;
+ pConnectProfile->BSSType = pProfile->BSSType;
+ pConnectProfile->modifyProfileFields.uapsd_mask = pProfile->uapsd_mask;
+ pConnectProfile->operationChannel = pSirBssDesc->channelId;
+ pConnectProfile->beaconInterval = pSirBssDesc->beaconInterval;
+ if (!pConnectProfile->beaconInterval) {
+ sms_log(pMac, LOGW, FL("ERROR: Beacon interval is ZERO"));
+ }
+ cdf_mem_copy(&pConnectProfile->Keys, &pProfile->Keys, sizeof(tCsrKeys));
+ /* saving the addional IE`s like Hot spot indication element and extended capabilities */
+ if (pProfile->nAddIEAssocLength) {
+ pConnectProfile->pAddIEAssoc =
+ cdf_mem_malloc(pProfile->nAddIEAssocLength);
+ if (NULL == pConnectProfile->pAddIEAssoc)
+ status = CDF_STATUS_E_NOMEM;
+ else
+ status = CDF_STATUS_SUCCESS;
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ FL
+ ("Failed to allocate memory for additional IEs"));
+ return CDF_STATUS_E_FAILURE;
+ }
+ pConnectProfile->nAddIEAssocLength =
+ pProfile->nAddIEAssocLength;
+ cdf_mem_copy(pConnectProfile->pAddIEAssoc,
+ pProfile->pAddIEAssoc,
+ pProfile->nAddIEAssocLength);
+ }
+#ifdef WLAN_FEATURE_11W
+ pConnectProfile->MFPEnabled = pProfile->MFPEnabled;
+ pConnectProfile->MFPRequired = pProfile->MFPRequired;
+ pConnectProfile->MFPCapable = pProfile->MFPCapable;
+#endif
+ /* Save bssid */
+ csr_get_bss_id_bss_desc(pMac, pSirBssDesc, &pConnectProfile->bssid);
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ if (pSirBssDesc->mdiePresent) {
+ pConnectProfile->MDID.mdiePresent = 1;
+ pConnectProfile->MDID.mobilityDomain =
+ (pSirBssDesc->mdie[1] << 8) | (pSirBssDesc->mdie[0]);
+ }
+#endif
+ if (NULL == pIesTemp) {
+ status =
+ csr_get_parsed_bss_description_ies(pMac, pSirBssDesc,
+ &pIesTemp);
+ }
+#ifdef FEATURE_WLAN_ESE
+ if ((csr_is_profile_ese(pProfile) ||
+ (CDF_IS_STATUS_SUCCESS(status) && (pIesTemp->ESEVersion.present)
+ && (pProfile->negotiatedAuthType == eCSR_AUTH_TYPE_OPEN_SYSTEM)))
+ && (pMac->roam.configParam.isEseIniFeatureEnabled)) {
+ pConnectProfile->isESEAssoc = 1;
+ }
+#endif
+ /* save ssid */
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ if (pIesTemp->SSID.present) {
+ pConnectProfile->SSID.length = pIesTemp->SSID.num_ssid;
+ cdf_mem_copy(pConnectProfile->SSID.ssId,
+ pIesTemp->SSID.ssid,
+ pIesTemp->SSID.num_ssid);
+ }
+ /* Save the bss desc */
+ status =
+ csr_roam_save_connected_bss_desc(pMac, sessionId, pSirBssDesc);
+
+ if (CSR_IS_QOS_BSS(pIesTemp) || pIesTemp->HTCaps.present) {
+ /* Some HT AP's dont send WMM IE so in that case we assume all HT Ap's are Qos Enabled AP's */
+ pConnectProfile->qap = true;
+ } else {
+ pConnectProfile->qap = false;
+ }
+
+ if (pIesTemp->ExtCap.present) {
+ struct s_ext_cap *p_ext_cap = (struct s_ext_cap *)
+ pIesTemp->ExtCap.bytes;
+ pConnectProfile->proxyARPService = p_ext_cap->
+ proxy_arp_service;
+ }
+
+ if (NULL == pIes) {
+ /* Free memory if it allocated locally */
+ cdf_mem_free(pIesTemp);
+ }
+ }
+ /* Save Qos connection */
+ pConnectProfile->qosConnection =
+ pMac->roam.roamSession[sessionId].fWMMConnection;
+
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ csr_free_connect_bss_desc(pMac, sessionId);
+ }
+ for (index = 0; index < pProfile->SSIDs.numOfSSIDs; index++) {
+ if ((pProfile->SSIDs.SSIDList[index].SSID.length ==
+ pConnectProfile->SSID.length)
+ && cdf_mem_compare(pProfile->SSIDs.SSIDList[index].SSID.
+ ssId, pConnectProfile->SSID.ssId,
+ pConnectProfile->SSID.length)) {
+ pConnectProfile->handoffPermitted =
+ pProfile->SSIDs.SSIDList[index].handoffPermitted;
+ break;
+ }
+ pConnectProfile->handoffPermitted = false;
+ }
+
+ return status;
+}
+
+
+static bool is_disconnect_pending(tpAniSirGlobal pmac,
+ uint8_t sessionid)
+{
+ tListElem *entry = NULL;
+ tListElem *next_entry = NULL;
+ tSmeCmd *command = NULL;
+ bool disconnect_cmd_exist = false;
+
+ csr_ll_lock(&pmac->sme.smeCmdPendingList);
+ entry = csr_ll_peek_head(&pmac->sme.smeCmdPendingList, LL_ACCESS_NOLOCK);
+ while (entry) {
+ next_entry = csr_ll_next(&pmac->sme.smeCmdPendingList,
+ entry, LL_ACCESS_NOLOCK);
+
+ command = GET_BASE_ADDR(entry, tSmeCmd, Link);
+ if (command && CSR_IS_DISCONNECT_COMMAND(command) &&
+ command->sessionId == sessionid){
+ disconnect_cmd_exist = true;
+ break;
+ }
+ entry = next_entry;
+ }
+ csr_ll_unlock(&pmac->sme.smeCmdPendingList);
+ return disconnect_cmd_exist;
+}
+
+static void csr_roam_join_rsp_processor(tpAniSirGlobal pMac,
+ tSirSmeJoinRsp *pSmeJoinRsp)
+{
+ tListElem *pEntry = NULL;
+ tSmeCmd *pCommand = NULL;
+ tCsrRoamSession *session_ptr;
+
+ if (pSmeJoinRsp) {
+ session_ptr = CSR_GET_SESSION(pMac, pSmeJoinRsp->sessionId);
+ } else {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ FL("Sme Join Response is NULL"));
+ return;
+ }
+ if (!session_ptr) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ FL("session %d not found"), pSmeJoinRsp->sessionId);
+ return;
+ }
+ /* The head of the active list is the request we sent */
+ pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK);
+ if (pEntry) {
+ pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
+ }
+ if (eSIR_SME_SUCCESS == pSmeJoinRsp->statusCode) {
+ if (pCommand
+ && eCsrSmeIssuedAssocToSimilarAP ==
+ pCommand->u.roamCmd.roamReason) {
+#ifndef WLAN_MDM_CODE_REDUCTION_OPT
+ sme_qos_csr_event_ind(pMac, pSmeJoinRsp->sessionId,
+ SME_QOS_CSR_HANDOFF_COMPLETE, NULL);
+#endif
+ }
+ /* *
+ * The join bssid count can be reset as soon as
+ * we are done with the join requests and returning
+ * the response to upper layers
+ * */
+ session_ptr->join_bssid_count = 0;
+ csr_roam_complete(pMac, eCsrJoinSuccess, (void *)pSmeJoinRsp);
+ } else {
+ uint32_t roamId = 0;
+ bool is_dis_pending;
+
+ /* The head of the active list is the request we sent */
+ /* Try to get back the same profile and roam again */
+ if (pCommand) {
+ roamId = pCommand->u.roamCmd.roamId;
+ }
+ session_ptr->joinFailStatusCode.statusCode =
+ pSmeJoinRsp->statusCode;
+ session_ptr->joinFailStatusCode.reasonCode =
+ pSmeJoinRsp->protStatusCode;
+ sms_log(pMac, LOGW,
+ "SmeJoinReq failed with statusCode= 0x%08X [%d]",
+ pSmeJoinRsp->statusCode, pSmeJoinRsp->statusCode);
+#if defined WLAN_FEATURE_NEIGHBOR_ROAMING
+ /* If Join fails while Handoff is in progress, indicate disassociated event to supplicant to reconnect */
+ if (csr_roam_is_handoff_in_progress(pMac, pSmeJoinRsp->sessionId)) {
+ csr_roam_call_callback(pMac, pSmeJoinRsp->sessionId, NULL,
+ roamId, eCSR_ROAM_DISASSOCIATED,
+ eCSR_ROAM_RESULT_FORCED);
+ /* Should indicate neighbor roam algorithm about the connect failure here */
+ csr_neighbor_roam_indicate_connect(pMac,
+ pSmeJoinRsp->sessionId,
+ CDF_STATUS_E_FAILURE);
+ }
+#endif
+ /*
+ * if userspace has issued disconnection,
+ * driver should not continue connecting
+ */
+ is_dis_pending = is_disconnect_pending(pMac, session_ptr->sessionId);
+ if (pCommand && (session_ptr->join_bssid_count <
+ CSR_MAX_BSSID_COUNT) && !is_dis_pending) {
+ if (CSR_IS_WDS_STA(&pCommand->u.roamCmd.roamProfile)) {
+ pCommand->u.roamCmd.fStopWds = true;
+ session_ptr->connectedProfile.BSSType =
+ eCSR_BSS_TYPE_WDS_STA;
+ csr_roam_reissue_roam_command(pMac);
+ } else if (CSR_IS_WDS(&pCommand->u.roamCmd.roamProfile)) {
+ session_ptr->join_bssid_count = 0;
+ csr_roam_complete(pMac, eCsrNothingToJoin, NULL);
+ } else {
+ csr_roam(pMac, pCommand);
+ }
+ } else {
+ /* ****************************************************
+ * When the upper layers issue a connect command, there
+ * is a roam command with reason eCsrHddIssued that
+ * gets enqueued and an associated timer for the SME
+ * command timeout is started which is currently 120
+ * seconds. This command would be dequeued only upon
+ * succesfull connections. In case of join failures, if
+ * there are too many BSS in the cache, and if we fail
+ * Join requests with all of them, there is a chance of
+ * timing out the above timer.
+ * ***************************************************/
+ if (session_ptr->join_bssid_count >=
+ CSR_MAX_BSSID_COUNT)
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_ERROR,
+ FL("Excessive Join Req Failures"));
+
+ if (is_dis_pending)
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_ERROR,
+ FL("disconnect is pending, complete roam"));
+
+ session_ptr->join_bssid_count = 0;
+ csr_roam_complete(pMac, eCsrNothingToJoin, NULL);
+ }
+ } /*else: ( eSIR_SME_SUCCESS == pSmeJoinRsp->statusCode ) */
+}
+
+CDF_STATUS csr_roam_issue_join(tpAniSirGlobal pMac, uint32_t sessionId,
+ tSirBssDescription *pSirBssDesc,
+ tDot11fBeaconIEs *pIes, tCsrRoamProfile *pProfile,
+ uint32_t roamId)
+{
+ CDF_STATUS status;
+ sms_log(pMac, LOG1, "Attempting to Join Bssid= " MAC_ADDRESS_STR,
+ MAC_ADDR_ARRAY(pSirBssDesc->bssId));
+
+ /* Set the roaming substate to 'join attempt'... */
+ csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_JOIN_REQ, sessionId);
+ /* attempt to Join this BSS... */
+ status =
+ csr_send_join_req_msg(pMac, sessionId, pSirBssDesc, pProfile, pIes,
+ eWNI_SME_JOIN_REQ);
+ return status;
+}
+
+static CDF_STATUS csr_roam_issue_reassociate(tpAniSirGlobal pMac,
+ uint32_t sessionId,
+ tSirBssDescription *pSirBssDesc,
+ tDot11fBeaconIEs *pIes,
+ tCsrRoamProfile *pProfile)
+{
+ csr_roam_state_change(pMac, eCSR_ROAMING_STATE_JOINING, sessionId);
+ /* Set the roaming substate to 'join attempt'... */
+ csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_REASSOC_REQ, sessionId);
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ FL(" calling csr_send_join_req_msg (eWNI_SME_REASSOC_REQ)"));
+ /* attempt to Join this BSS... */
+ return csr_send_join_req_msg(pMac, sessionId, pSirBssDesc, pProfile, pIes,
+ eWNI_SME_REASSOC_REQ);
+}
+
+void csr_roam_reissue_roam_command(tpAniSirGlobal pMac)
+{
+ tListElem *pEntry;
+ tSmeCmd *pCommand;
+ tCsrRoamInfo roamInfo;
+ uint32_t sessionId;
+ tCsrRoamSession *pSession;
+
+ pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK);
+ if (NULL == pEntry) {
+ sms_log(pMac, LOGE,
+ FL("Disassoc rsp can't continue, no active CMD"));
+ return;
+ }
+ pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
+ if (eSmeCommandRoam != pCommand->command) {
+ sms_log(pMac, LOGW, FL("Active cmd, is not a roaming CMD"));
+ return;
+ }
+ sessionId = pCommand->sessionId;
+ pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL("session %d not found"), sessionId);
+ return;
+ }
+
+ if (!pCommand->u.roamCmd.fStopWds) {
+ if (pSession->bRefAssocStartCnt > 0) {
+ /*
+ * bRefAssocStartCnt was incremented in
+ * csr_roam_join_next_bss when the roam command issued
+ * previously. As part of reissuing the roam command
+ * again csr_roam_join_next_bss is going increment
+ * RefAssocStartCnt. So make sure to decrement the
+ * bRefAssocStartCnt
+ */
+ pSession->bRefAssocStartCnt--;
+ }
+ if (eCsrStopRoaming == csr_roam_join_next_bss(pMac, pCommand,
+ true)) {
+ sms_log(pMac, LOGW,
+ FL("Failed to reissue join command"));
+ csr_roam_complete(pMac, eCsrNothingToJoin, NULL);
+ }
+ return;
+ }
+ cdf_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0);
+ roamInfo.pBssDesc = pCommand->u.roamCmd.pLastRoamBss;
+ roamInfo.statusCode = pSession->joinFailStatusCode.statusCode;
+ roamInfo.reasonCode = pSession->joinFailStatusCode.reasonCode;
+ if (CSR_IS_WDS(&pSession->connectedProfile)) {
+ pSession->connectState = eCSR_ASSOC_STATE_TYPE_WDS_DISCONNECTED;
+ csr_roam_call_callback(pMac, sessionId, &roamInfo,
+ pCommand->u.roamCmd.roamId,
+ eCSR_ROAM_WDS_IND,
+ eCSR_ROAM_RESULT_WDS_DISASSOCIATED);
+ } else if (CSR_IS_INFRA_AP(&pSession->connectedProfile)) {
+ pSession->connectState =
+ eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTED;
+ csr_roam_call_callback(pMac, sessionId, &roamInfo,
+ pCommand->u.roamCmd.roamId,
+ eCSR_ROAM_INFRA_IND,
+ eCSR_ROAM_RESULT_INFRA_DISASSOCIATED);
+ }
+
+ if (!CDF_IS_STATUS_SUCCESS(csr_roam_issue_stop_bss(pMac, sessionId,
+ eCSR_ROAM_SUBSTATE_STOP_BSS_REQ))) {
+ sms_log(pMac, LOGE,
+ FL("Failed to reissue stop_bss command for WDS"));
+ csr_roam_complete(pMac, eCsrNothingToJoin, NULL);
+ }
+}
+
+bool csr_is_roam_command_waiting_for_session(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ bool fRet = false;
+ tListElem *pEntry;
+ tSmeCmd *pCommand = NULL;
+ /* alwasy lock active list before locking pending list */
+ csr_ll_lock(&pMac->sme.smeCmdActiveList);
+ pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_NOLOCK);
+ if (pEntry) {
+ pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
+ if ((eSmeCommandRoam == pCommand->command)
+ && (sessionId == pCommand->sessionId)) {
+ fRet = true;
+ }
+ }
+ if (false == fRet) {
+ csr_ll_lock(&pMac->sme.smeCmdPendingList);
+ pEntry =
+ csr_ll_peek_head(&pMac->sme.smeCmdPendingList,
+ LL_ACCESS_NOLOCK);
+ while (pEntry) {
+ pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
+ if ((eSmeCommandRoam == pCommand->command)
+ && (sessionId == pCommand->sessionId)) {
+ fRet = true;
+ break;
+ }
+ pEntry =
+ csr_ll_next(&pMac->sme.smeCmdPendingList, pEntry,
+ LL_ACCESS_NOLOCK);
+ }
+ csr_ll_unlock(&pMac->sme.smeCmdPendingList);
+ }
+ if (false == fRet) {
+ csr_ll_lock(&pMac->roam.roamCmdPendingList);
+ pEntry =
+ csr_ll_peek_head(&pMac->roam.roamCmdPendingList,
+ LL_ACCESS_NOLOCK);
+ while (pEntry) {
+ pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
+ if ((eSmeCommandRoam == pCommand->command)
+ && (sessionId == pCommand->sessionId)) {
+ fRet = true;
+ break;
+ }
+ pEntry =
+ csr_ll_next(&pMac->roam.roamCmdPendingList, pEntry,
+ LL_ACCESS_NOLOCK);
+ }
+ csr_ll_unlock(&pMac->roam.roamCmdPendingList);
+ }
+ csr_ll_unlock(&pMac->sme.smeCmdActiveList);
+ return fRet;
+}
+
+bool csr_is_roam_command_waiting(tpAniSirGlobal pMac)
+{
+ bool fRet = false;
+ uint32_t i;
+ for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
+ fRet = csr_is_roam_command_waiting_for_session(pMac, i);
+ if (CSR_IS_SESSION_VALID(pMac, i)
+ && (fRet)) {
+ break;
+ }
+ }
+ return fRet;
+}
+
+bool csr_is_command_waiting(tpAniSirGlobal pMac)
+{
+ bool fRet = false;
+ /* alwasy lock active list before locking pending list */
+ csr_ll_lock(&pMac->sme.smeCmdActiveList);
+ fRet = csr_ll_is_list_empty(&pMac->sme.smeCmdActiveList, LL_ACCESS_NOLOCK);
+ if (false == fRet) {
+ fRet =
+ csr_ll_is_list_empty(&pMac->sme.smeCmdPendingList,
+ LL_ACCESS_LOCK);
+ }
+ csr_ll_unlock(&pMac->sme.smeCmdActiveList);
+ return fRet;
+}
+
+bool csr_is_scan_for_roam_command_active(tpAniSirGlobal pMac)
+{
+ bool fRet = false;
+ tListElem *pEntry;
+ tCsrCmd *pCommand;
+ /* alwasy lock active list before locking pending list */
+ csr_ll_lock(&pMac->sme.smeCmdActiveList);
+ pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_NOLOCK);
+ if (pEntry) {
+ pCommand = GET_BASE_ADDR(pEntry, tCsrCmd, Link);
+ if ((eCsrRoamCommandScan == pCommand->command) &&
+ ((eCsrScanForSsid == pCommand->u.scanCmd.reason) ||
+ (eCsrScanP2PFindPeer == pCommand->u.scanCmd.reason))) {
+ fRet = true;
+ }
+ }
+ csr_ll_unlock(&pMac->sme.smeCmdActiveList);
+ return fRet;
+}
+
+CDF_STATUS csr_roam_issue_reassociate_cmd(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSmeCmd *pCommand = NULL;
+ bool fHighPriority = true;
+ bool fRemoveCmd = false;
+ tListElem *pEntry;
+ /* Delete the old assoc command. All is setup for reassoc to be serialized */
+ pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK);
+ if (pEntry) {
+ pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
+ if (!pCommand) {
+ sms_log(pMac, LOGE, FL(" fail to get command buffer"));
+ return CDF_STATUS_E_RESOURCES;
+ }
+ if (eSmeCommandRoam == pCommand->command) {
+ if (pCommand->u.roamCmd.roamReason ==
+ eCsrSmeIssuedAssocToSimilarAP) {
+ fRemoveCmd =
+ csr_ll_remove_entry(&pMac->sme.
+ smeCmdActiveList, pEntry,
+ LL_ACCESS_LOCK);
+ } else {
+ sms_log(pMac, LOGE,
+ FL
+ (" Unexpected active roam command present "));
+ }
+ if (fRemoveCmd == false) {
+ /* Implies we did not get the serialized assoc command we */
+ /* were expecting */
+ pCommand = NULL;
+ }
+ }
+ }
+ if (NULL == pCommand) {
+ sms_log(pMac, LOGE,
+ FL
+ (" fail to get command buffer as expected based on previous connect roam command"));
+ return CDF_STATUS_E_RESOURCES;
+ }
+ do {
+ /* Change the substate in case it is wait-for-key */
+ if (CSR_IS_WAIT_FOR_KEY(pMac, sessionId)) {
+ csr_roam_stop_wait_for_key_timer(pMac);
+ csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_NONE,
+ sessionId);
+ }
+ pCommand->command = eSmeCommandRoam;
+ pCommand->sessionId = (uint8_t) sessionId;
+ pCommand->u.roamCmd.roamReason = eCsrSmeIssuedFTReassoc;
+ status = csr_queue_sme_command(pMac, pCommand, fHighPriority);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ FL(" fail to send message status = %d"), status);
+ csr_release_command_roam(pMac, pCommand);
+ }
+ } while (0);
+
+ return status;
+}
+
+static void
+csr_roaming_state_config_cnf_processor(tpAniSirGlobal mac_ctx,
+ uint32_t result)
+{
+ tListElem *entry = csr_ll_peek_head(&mac_ctx->sme.smeCmdActiveList,
+ LL_ACCESS_LOCK);
+ tCsrScanResult *scan_result = NULL;
+ tSirBssDescription *bss_desc = NULL;
+ tSmeCmd *cmd = NULL;
+ uint32_t session_id;
+ tCsrRoamSession *session;
+ tDot11fBeaconIEs *local_ies = NULL;
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+
+ if (NULL == entry) {
+ sms_log(mac_ctx, LOGE, FL("CFG_CNF with active list empty"));
+ return;
+ }
+ cmd = GET_BASE_ADDR(entry, tSmeCmd, Link);
+ session_id = cmd->sessionId;
+ session = CSR_GET_SESSION(mac_ctx, session_id);
+
+ if (!session) {
+ sms_log(mac_ctx, LOGE, FL("session %d not found"), session_id);
+ return;
+ }
+
+ if (CSR_IS_ROAMING(session) && session->fCancelRoaming) {
+ /* the roaming is cancelled. Simply complete the command */
+ sms_log(mac_ctx, LOGW, FL("Roam command canceled"));
+ csr_roam_complete(mac_ctx, eCsrNothingToJoin, NULL);
+ return;
+ }
+
+ /* If the roaming has stopped, not to continue the roaming command */
+ if (!CSR_IS_ROAMING(session) && CSR_IS_ROAMING_COMMAND(cmd)) {
+ /* No need to complete roaming here as it already completes */
+ sms_log(mac_ctx, LOGW,
+ FL("Roam cmd (reason %d) aborted(roaming completed)"),
+ cmd->u.roamCmd.roamReason);
+ csr_set_abort_roaming_command(mac_ctx, cmd);
+ csr_roam_complete(mac_ctx, eCsrNothingToJoin, NULL);
+ return;
+ }
+
+ if (!IS_SIR_STATUS_SUCCESS(result)) {
+ /*
+ * In the event the configuration failed, for infra let the roam
+ * processor attempt to join something else...
+ */
+ if (cmd->u.roamCmd.pRoamBssEntry
+ && CSR_IS_INFRASTRUCTURE(&cmd->u.roamCmd.roamProfile)) {
+ csr_roam(mac_ctx, cmd);
+ } else {
+ /* We need to complete the command */
+ if (csr_is_bss_type_ibss
+ (cmd->u.roamCmd.roamProfile.BSSType)) {
+ csr_roam_complete(mac_ctx, eCsrStartBssFailure,
+ NULL);
+ } else {
+ csr_roam_complete(mac_ctx, eCsrNothingToJoin,
+ NULL);
+ }
+ }
+ return;
+ }
+
+ /* we have active entry */
+ sms_log(mac_ctx, LOG2, "Cfg sequence complete");
+ /*
+ * Successfully set the configuration parameters for the new Bss.
+ * Attempt to join the roaming Bss
+ */
+ if (cmd->u.roamCmd.pRoamBssEntry) {
+ scan_result = GET_BASE_ADDR(cmd->u.roamCmd.pRoamBssEntry,
+ tCsrScanResult,
+ Link);
+ bss_desc = &scan_result->Result.BssDescriptor;
+ }
+ if (csr_is_bss_type_ibss(cmd->u.roamCmd.roamProfile.BSSType)
+ || CSR_IS_WDS(&cmd->u.roamCmd.roamProfile)
+ || CSR_IS_INFRA_AP(&cmd->u.roamCmd.roamProfile)) {
+ if (!CDF_IS_STATUS_SUCCESS(csr_roam_issue_start_bss(mac_ctx,
+ session_id, &session->bssParams,
+ &cmd->u.roamCmd.roamProfile,
+ bss_desc,
+ cmd->u.roamCmd.roamId))) {
+ sms_log(mac_ctx, LOGE, FL("CSR start BSS failed"));
+ /* We need to complete the command */
+ csr_roam_complete(mac_ctx, eCsrStartBssFailure, NULL);
+ }
+ return;
+ }
+
+ if (!cmd->u.roamCmd.pRoamBssEntry) {
+ sms_log(mac_ctx, LOGE, FL("pRoamBssEntry is NULL"));
+ /* We need to complete the command */
+ csr_roam_complete(mac_ctx, eCsrJoinFailure, NULL);
+ return;
+ }
+
+ if (NULL == scan_result) {
+ /* If we are roaming TO an Infrastructure BSS... */
+ CDF_ASSERT(scan_result != NULL);
+ return;
+ }
+
+ if (!csr_is_infra_bss_desc(bss_desc)) {
+ sms_log(mac_ctx, LOGW,
+ FL("found BSSType mismatching the one in BSS descp"));
+ return;
+ }
+
+ local_ies = (tDot11fBeaconIEs *) scan_result->Result.pvIes;
+ if (!local_ies) {
+ status = csr_get_parsed_bss_description_ies(mac_ctx, bss_desc,
+ &local_ies);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ return;
+ }
+
+ if (csr_is_conn_state_connected_infra(mac_ctx, session_id)) {
+ if (csr_is_ssid_equal(mac_ctx, session->pConnectBssDesc,
+ bss_desc, local_ies)) {
+ cmd->u.roamCmd.fReassoc = true;
+ csr_roam_issue_reassociate(mac_ctx, session_id,
+ bss_desc, local_ies,
+ &cmd->u.roamCmd.roamProfile);
+ } else {
+ /*
+ * otherwise, we have to issue a new Join request to LIM
+ * because we disassociated from the previously
+ * associated AP.
+ */
+ status = csr_roam_issue_join(mac_ctx, session_id,
+ bss_desc, local_ies,
+ &cmd->u.roamCmd.roamProfile,
+ cmd->u.roamCmd.roamId);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ /* try something else */
+ csr_roam(mac_ctx, cmd);
+ }
+ }
+ } else {
+ status = CDF_STATUS_SUCCESS;
+ /*
+ * We need to come with other way to figure out that this is
+ * because of HO in BMP The below API will be only available for
+ * Android as it uses a different HO algorithm. Reassoc request
+ * will be used only for ESE and 11r handoff whereas other
+ * legacy roaming should use join request
+ */
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ if (csr_roam_is_handoff_in_progress(mac_ctx, session_id)
+ && csr_roam_is11r_assoc(mac_ctx, session_id)) {
+ status = csr_roam_issue_reassociate(mac_ctx,
+ session_id, bss_desc,
+ (tDot11fBeaconIEs *)
+ (scan_result->Result.pvIes),
+ &cmd->u.roamCmd.roamProfile);
+ } else
+#endif
+#ifdef FEATURE_WLAN_ESE
+ if (csr_roam_is_handoff_in_progress(mac_ctx, session_id)
+ && csr_roam_is_ese_assoc(mac_ctx, session_id)) {
+ /* Now serialize the reassoc command. */
+ status = csr_roam_issue_reassociate_cmd(mac_ctx,
+ session_id);
+ } else
+#endif
+#ifdef FEATURE_WLAN_LFR
+ if (csr_roam_is_handoff_in_progress(mac_ctx, session_id)
+ && csr_roam_is_fast_roam_enabled(mac_ctx, session_id)) {
+ /* Now serialize the reassoc command. */
+ status = csr_roam_issue_reassociate_cmd(mac_ctx,
+ session_id);
+ } else
+#endif
+ {
+ /*
+ * else we are not connected and attempting to Join. Issue the
+ * Join request.
+ */
+ status = csr_roam_issue_join(mac_ctx, session_id,
+ bss_desc,
+ (tDot11fBeaconIEs *)
+ (scan_result->Result.pvIes),
+ &cmd->u.roamCmd.roamProfile,
+ cmd->u.roamCmd.roamId);
+ }
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ /* try something else */
+ csr_roam(mac_ctx, cmd);
+ }
+ }
+ if (!scan_result->Result.pvIes) {
+ /* Locally allocated */
+ cdf_mem_free(local_ies);
+ }
+}
+
+static void csr_roam_roaming_state_reassoc_rsp_processor(tpAniSirGlobal pMac,
+ tpSirSmeJoinRsp pSmeJoinRsp)
+{
+ eCsrRoamCompleteResult result;
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[pSmeJoinRsp->sessionId];
+ tCsrRoamInfo roamInfo;
+ uint32_t roamId = 0;
+
+ if (eSIR_SME_SUCCESS == pSmeJoinRsp->statusCode) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ FL("CSR SmeReassocReq Successful"));
+ result = eCsrReassocSuccess;
+ /* Defeaturize this part later if needed */
+#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING
+ /* Since the neighbor roam algorithm uses reassoc req for handoff instead of join,
+ * we need the response contents while processing the result in csr_roam_process_results() */
+ if (csr_roam_is_handoff_in_progress(pMac, pSmeJoinRsp->sessionId)) {
+ /* Need to dig more on indicating events to SME QoS module */
+ sme_qos_csr_event_ind(pMac, pSmeJoinRsp->sessionId,
+ SME_QOS_CSR_HANDOFF_COMPLETE, NULL);
+ csr_roam_complete(pMac, result, pSmeJoinRsp);
+ } else
+#endif
+ {
+ csr_roam_complete(pMac, result, NULL);
+ }
+ }
+ /* Should we handle this similar to handling the join failure? Is it ok
+ * to call csr_roam_complete() with state as CsrJoinFailure */
+ else {
+ sms_log(pMac, LOGW,
+ "CSR SmeReassocReq failed with statusCode= 0x%08X [%d]",
+ pSmeJoinRsp->statusCode, pSmeJoinRsp->statusCode);
+ result = eCsrReassocFailure;
+#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) || \
+ defined(FEATURE_WLAN_LFR)
+ if ((eSIR_SME_FT_REASSOC_TIMEOUT_FAILURE ==
+ pSmeJoinRsp->statusCode)
+ || (eSIR_SME_FT_REASSOC_FAILURE ==
+ pSmeJoinRsp->statusCode)
+ || (eSIR_SME_INVALID_PARAMETERS ==
+ pSmeJoinRsp->statusCode)) {
+ /* Inform HDD to turn off FT flag in HDD */
+ if (pNeighborRoamInfo) {
+ cdf_mem_zero(&roamInfo, sizeof(tCsrRoamInfo));
+ csr_roam_call_callback(pMac,
+ pSmeJoinRsp->sessionId,
+ &roamInfo, roamId,
+ eCSR_ROAM_FT_REASSOC_FAILED,
+ eSIR_SME_SUCCESS);
+ /*
+ * Since the above callback sends a disconnect
+ * to HDD, we should clean-up our state
+ * machine as well to be in sync with the upper
+ * layers. There is no need to send a disassoc
+ * since: 1) we will never reassoc to the current
+ * AP in LFR, and 2) there is no need to issue a
+ * disassoc to the AP with which we were trying
+ * to reassoc.
+ */
+ csr_roam_complete(pMac, eCsrJoinFailure, NULL);
+ return;
+ }
+ }
+#endif
+ /* In the event that the Reassociation fails, then we need to Disassociate the current association and keep */
+ /* roaming. Note that we will attempt to Join the AP instead of a Reassoc since we may have attempted a */
+ /* 'Reassoc to self', which AP's that don't support Reassoc will force a Disassoc. */
+ /* The disassoc rsp message will remove the command from active list */
+ if (!CDF_IS_STATUS_SUCCESS
+ (csr_roam_issue_disassociate
+ (pMac, pSmeJoinRsp->sessionId,
+ eCSR_ROAM_SUBSTATE_DISASSOC_REASSOC_FAILURE, false))) {
+ csr_roam_complete(pMac, eCsrJoinFailure, NULL);
+ }
+ }
+}
+
+static void csr_roam_roaming_state_stop_bss_rsp_processor(tpAniSirGlobal pMac,
+ tSirSmeRsp *pSmeRsp)
+{
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+ {
+ host_log_ibss_pkt_type *pIbssLog;
+ WLAN_HOST_DIAG_LOG_ALLOC(pIbssLog, host_log_ibss_pkt_type,
+ LOG_WLAN_IBSS_C);
+ if (pIbssLog) {
+ pIbssLog->eventId = WLAN_IBSS_EVENT_STOP_RSP;
+ if (eSIR_SME_SUCCESS != pSmeRsp->statusCode) {
+ pIbssLog->status = WLAN_IBSS_STATUS_FAILURE;
+ }
+ WLAN_HOST_DIAG_LOG_REPORT(pIbssLog);
+ }
+ }
+#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */
+ pMac->roam.roamSession[pSmeRsp->sessionId].connectState =
+ eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED;
+ if (CSR_IS_ROAM_SUBSTATE_STOP_BSS_REQ(pMac, pSmeRsp->sessionId)) {
+ csr_roam_complete(pMac, eCsrNothingToJoin, NULL);
+ } else
+ if (CSR_IS_ROAM_SUBSTATE_DISCONNECT_CONTINUE
+ (pMac, pSmeRsp->sessionId)) {
+ csr_roam_reissue_roam_command(pMac);
+ }
+}
+
+/**
+ * csr_dequeue_command() - removes a command from active cmd list
+ * @pMac: mac global context
+ *
+ * Return: void
+ */
+static void
+csr_dequeue_command(tpAniSirGlobal mac_ctx)
+{
+ bool fRemoveCmd;
+ tSmeCmd *cmd = NULL;
+ tListElem *entry = csr_ll_peek_head(&mac_ctx->sme.smeCmdActiveList,
+ LL_ACCESS_LOCK);
+ if (!entry) {
+ sms_log(mac_ctx, LOGE, FL("NO commands are active"));
+ return;
+ }
+
+ cmd = GET_BASE_ADDR(entry, tSmeCmd, Link);
+ /*
+ * If the head of the queue is Active and it is a given cmd type, remove
+ * and put this on the Free queue.
+ */
+ if (eSmeCommandRoam != cmd->command) {
+ sms_log(mac_ctx, LOGE, FL("Roam command not active"));
+ return;
+ }
+ /*
+ * we need to process the result first before removing it from active
+ * list because state changes still happening insides
+ * roamQProcessRoamResults so no other roam command should be issued.
+ */
+ fRemoveCmd = csr_ll_remove_entry(&mac_ctx->sme.smeCmdActiveList, entry,
+ LL_ACCESS_LOCK);
+ if (cmd->u.roamCmd.fReleaseProfile) {
+ csr_release_profile(mac_ctx, &cmd->u.roamCmd.roamProfile);
+ cmd->u.roamCmd.fReleaseProfile = false;
+ }
+ if (fRemoveCmd)
+ csr_release_command_roam(mac_ctx, cmd);
+ else
+ sms_log(mac_ctx, LOGE, FL("fail to remove cmd reason %d"),
+ cmd->u.roamCmd.roamReason);
+}
+
+/**
+ * csr_post_roam_failure() - post roam failure back to csr and issues a disassoc
+ * @pMac: mac global context
+ * @session_id: session id
+ * @roam_info: roam info struct
+ * @scan_filter: scan filter to free
+ * @cur_roam_profile: current csr roam profile
+ *
+ * Return: void
+ */
+static void
+csr_post_roam_failure(tpAniSirGlobal mac_ctx,
+ uint32_t session_id,
+ tCsrRoamInfo *roam_info,
+ tCsrScanResultFilter *scan_filter,
+ tCsrRoamProfile *cur_roam_profile)
+{
+ CDF_STATUS status;
+
+ if (scan_filter) {
+ csr_free_scan_filter(mac_ctx, scan_filter);
+ cdf_mem_free(scan_filter);
+ }
+ if (cur_roam_profile)
+ cdf_mem_free(cur_roam_profile);
+
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+ csr_roam_synch_clean_up(mac_ctx, session_id);
+#endif
+ /* Inform the upper layers that the reassoc failed */
+ cdf_mem_zero(roam_info, sizeof(tCsrRoamInfo));
+ csr_roam_call_callback(mac_ctx, session_id, roam_info, 0,
+ eCSR_ROAM_FT_REASSOC_FAILED, eSIR_SME_SUCCESS);
+ /*
+ * Issue a disassoc request so that PE/LIM uses this to clean-up the FT
+ * session. Upon success, we would re-enter this routine after receiving
+ * the disassoc response and will fall into the reassoc fail sub-state.
+ * And, eventually call csr_roam_complete which would remove the roam
+ * command from SME active queue.
+ */
+ status = csr_roam_issue_disassociate(mac_ctx, session_id,
+ eCSR_ROAM_SUBSTATE_DISASSOC_REASSOC_FAILURE, false);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(mac_ctx, LOGE,
+ FL("csr_roam_issue_disassociate failed, status %d"),
+ status);
+ csr_roam_complete(mac_ctx, eCsrJoinFailure, NULL);
+ }
+}
+
+/**
+ * csr_check_profile_in_scan_cache() - finds if roam profile is present in scan
+ * cache or not
+ * @pMac: mac global context
+ * @scan_filter: out param, scan filter
+ * @neighbor_roam_info: roam info struct
+ * @hBSSList: scan result
+ *
+ * Return: true if found else false.
+ */
+static bool
+csr_check_profile_in_scan_cache(tpAniSirGlobal mac_ctx,
+ tCsrScanResultFilter **scan_filter,
+ tpCsrNeighborRoamControlInfo neighbor_roam_info,
+ tScanResultHandle *hBSSList)
+{
+ CDF_STATUS status;
+ *scan_filter = cdf_mem_malloc(sizeof(tCsrScanResultFilter));
+ if (NULL == *scan_filter) {
+ sms_log(mac_ctx, LOGE, FL("alloc for ScanFilter failed."));
+ return false;
+ }
+ cdf_mem_set(*scan_filter, sizeof(tCsrScanResultFilter), 0);
+ (*scan_filter)->scan_filter_for_roam = 1;
+ status = csr_roam_prepare_filter_from_profile(mac_ctx,
+ &neighbor_roam_info->csrNeighborRoamProfile,
+ *scan_filter);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(mac_ctx, LOGE,
+ FL("failed to prepare scan filter, status %d"),
+ status);
+ return false;
+ }
+ status = csr_scan_get_result(mac_ctx, *scan_filter, hBSSList);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(mac_ctx, LOGE,
+ FL("csr_scan_get_result failed, status %d"),
+ status);
+ return false;
+ }
+ return true;
+}
+
+void csr_roam_roaming_state_disassoc_rsp_processor(tpAniSirGlobal pMac,
+ tSirSmeDisassocRsp *pSmeRsp)
+{
+#if defined WLAN_FEATURE_NEIGHBOR_ROAMING
+ tScanResultHandle hBSSList;
+ tCsrRoamInfo roamInfo;
+ tCsrScanResultFilter *pScanFilter = NULL;
+ uint32_t roamId = 0;
+ tCsrRoamProfile *pCurRoamProfile = NULL;
+#endif
+ CDF_STATUS status;
+ uint32_t sessionId;
+ tCsrRoamSession *pSession;
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL;
+ tSirSmeDisassocRsp SmeDisassocRsp;
+
+ csr_ser_des_unpack_diassoc_rsp((uint8_t *) pSmeRsp, &SmeDisassocRsp);
+ sessionId = SmeDisassocRsp.sessionId;
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, FL("sessionId %d"),
+ sessionId);
+
+ if (csr_is_conn_state_infra(pMac, sessionId)) {
+ pMac->roam.roamSession[sessionId].connectState =
+ eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED;
+ }
+
+ pSession = CSR_GET_SESSION(pMac, sessionId);
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL("session %d not found"), sessionId);
+ return;
+ }
+
+ if (CSR_IS_ROAM_SUBSTATE_DISASSOC_NO_JOIN(pMac, sessionId)) {
+ sms_log(pMac, LOG2, "***eCsrNothingToJoin***");
+ csr_roam_complete(pMac, eCsrNothingToJoin, NULL);
+ } else if (CSR_IS_ROAM_SUBSTATE_DISASSOC_FORCED(pMac, sessionId) ||
+ CSR_IS_ROAM_SUBSTATE_DISASSOC_REQ(pMac, sessionId)) {
+ if (eSIR_SME_SUCCESS == SmeDisassocRsp.statusCode) {
+ sms_log(pMac, LOG2,
+ FL("CSR force disassociated successful"));
+ /*
+ * A callback to HDD will be issued from
+ * csr_roam_complete so no need to do anything here
+ */
+ }
+ csr_roam_complete(pMac, eCsrNothingToJoin, NULL);
+ } else if (CSR_IS_ROAM_SUBSTATE_DISASSOC_HO(pMac, sessionId)) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ FL("CSR SmeDisassocReq due to HO on session %d"),
+ sessionId);
+ pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[sessionId];
+#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING
+ /*
+ * First ensure if the roam profile is in the scan cache.
+ * If not, post a reassoc failure and disconnect.
+ */
+ if (!csr_check_profile_in_scan_cache(pMac, &pScanFilter,
+ pNeighborRoamInfo, &hBSSList))
+ goto POST_ROAM_FAILURE;
+
+ /*
+ * After ensuring that the roam profile is in the scan result
+ * list, dequeue the command from the active list.
+ */
+ csr_dequeue_command(pMac);
+
+ /* notify HDD about handoff and provide the BSSID too */
+ roamInfo.reasonCode = eCsrRoamReasonBetterAP;
+
+ cdf_copy_macaddr(&roamInfo.bssid,
+ pNeighborRoamInfo->csrNeighborRoamProfile.BSSIDs.bssid);
+
+ csr_roam_call_callback(pMac, sessionId, &roamInfo, 0,
+ eCSR_ROAM_ROAMING_START,
+ eCSR_ROAM_RESULT_NONE);
+
+ /*
+ * Copy the connected profile to apply the same for this
+ * connection as well
+ */
+ pCurRoamProfile = cdf_mem_malloc(sizeof(tCsrRoamProfile));
+ if (pCurRoamProfile != NULL) {
+ /*
+ * notify sub-modules like QoS etc. that handoff
+ * happening
+ */
+ sme_qos_csr_event_ind(pMac, sessionId,
+ SME_QOS_CSR_HANDOFF_ASSOC_REQ,
+ NULL);
+ cdf_mem_set(pCurRoamProfile, sizeof(tCsrRoamProfile),
+ 0);
+ csr_roam_copy_profile(pMac, pCurRoamProfile,
+ pSession->pCurRoamProfile);
+ /* make sure to put it at the head of the cmd queue */
+ status = csr_roam_issue_connect(pMac, sessionId,
+ pCurRoamProfile, hBSSList,
+ eCsrSmeIssuedAssocToSimilarAP,
+ roamId, true, false);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ sms_log(pMac, LOGE,
+ FL("issue_connect failed. status %d"),
+ status);
+
+ csr_release_profile(pMac, pCurRoamProfile);
+ cdf_mem_free(pCurRoamProfile);
+ csr_free_scan_filter(pMac, pScanFilter);
+ cdf_mem_free(pScanFilter);
+ return;
+ }
+
+POST_ROAM_FAILURE:
+ csr_post_roam_failure(pMac, sessionId, &roamInfo,
+ pScanFilter, pCurRoamProfile);
+#endif
+ } /* else if ( CSR_IS_ROAM_SUBSTATE_DISASSOC_HO( pMac ) ) */
+ else if (CSR_IS_ROAM_SUBSTATE_REASSOC_FAIL(pMac, sessionId)) {
+ /* Disassoc due to Reassoc failure falls into this codepath */
+ csr_roam_complete(pMac, eCsrJoinFailure, NULL);
+ } else {
+ if (eSIR_SME_SUCCESS == SmeDisassocRsp.statusCode) {
+ /*
+ * Successfully disassociated from the 'old' Bss.
+ * We get Disassociate response in three conditions.
+ * 1) The case where we are disasociating from an Infra
+ * Bss to start an IBSS.
+ * 2) When we are disassociating from an Infra Bss to
+ * join an IBSS or a new infra network.
+ * 3) Where we are doing an Infra to Infra roam between
+ * networks with different SSIDs.
+ * In all cases, we set the new Bss configuration here
+ * and attempt to join
+ */
+ sms_log(pMac, LOG2,
+ FL("Disassociated successfully"));
+ } else {
+ sms_log(pMac, LOGE,
+ FL("DisassocReq failed, statusCode= 0x%08X"),
+ SmeDisassocRsp.statusCode);
+ }
+ /* We are not done yet. Get the data and continue roaming */
+ csr_roam_reissue_roam_command(pMac);
+ }
+}
+
+static void csr_roam_roaming_state_deauth_rsp_processor(tpAniSirGlobal pMac,
+ tSirSmeDeauthRsp *pSmeRsp)
+{
+ tSirResultCodes statusCode;
+ /* No one is sending eWNI_SME_DEAUTH_REQ to PE. */
+ sms_log(pMac, LOGW, FL("is no-op"));
+ statusCode = csr_get_de_auth_rsp_status_code(pSmeRsp);
+ pMac->roam.deauthRspStatus = statusCode;
+ if (CSR_IS_ROAM_SUBSTATE_DEAUTH_REQ(pMac, pSmeRsp->sessionId)) {
+ csr_roam_complete(pMac, eCsrNothingToJoin, NULL);
+ } else {
+ if (eSIR_SME_SUCCESS == statusCode) {
+ /* Successfully deauth from the 'old' Bss... */
+ /* */
+ sms_log(pMac, LOG2,
+ "CSR SmeDeauthReq disassociated Successfully");
+ } else {
+ sms_log(pMac, LOGW,
+ "SmeDeauthReq failed with statusCode= 0x%08X",
+ statusCode);
+ }
+ /* We are not done yet. Get the data and continue roaming */
+ csr_roam_reissue_roam_command(pMac);
+ }
+}
+
+static void csr_roam_roaming_state_start_bss_rsp_processor(tpAniSirGlobal pMac,
+ tSirSmeStartBssRsp *
+ pSmeStartBssRsp)
+{
+ eCsrRoamCompleteResult result;
+
+ if (eSIR_SME_SUCCESS == pSmeStartBssRsp->statusCode) {
+ sms_log(pMac, LOGW, "SmeStartBssReq Successful");
+ result = eCsrStartBssSuccess;
+ } else {
+ sms_log(pMac, LOGW,
+ "SmeStartBssReq failed with statusCode= 0x%08X",
+ pSmeStartBssRsp->statusCode);
+ /* Let csr_roam_complete decide what to do */
+ result = eCsrStartBssFailure;
+ }
+ csr_roam_complete(pMac, result, pSmeStartBssRsp);
+}
+
+/**
+ * csr_roaming_state_msg_processor() - process roaming messages
+ * @pMac: mac global context
+ * @pMsgBuf: message buffer
+ *
+ * We need to be careful on whether to cast pMsgBuf (pSmeRsp) to other type of
+ * strucutres. It depends on how the message is constructed. If the message is
+ * sent by lim_send_sme_rsp, the pMsgBuf is only a generic response and can only
+ * be used as pointer to tSirSmeRsp. For the messages where sender allocates
+ * memory for specific structures, then it can be cast accordingly.
+ *
+ * Return: status of operation
+ */
+void csr_roaming_state_msg_processor(tpAniSirGlobal pMac, void *pMsgBuf)
+{
+ tSirSmeRsp *pSmeRsp;
+ tSmeIbssPeerInd *pIbssPeerInd;
+ tCsrRoamInfo roamInfo;
+ pSmeRsp = (tSirSmeRsp *) pMsgBuf;
+ sms_log(pMac, LOG2, FL("Message %d[0x%04X] received in substate %s"),
+ pSmeRsp->messageType, pSmeRsp->messageType,
+ mac_trace_getcsr_roam_sub_state(
+ pMac->roam.curSubState[pSmeRsp->sessionId]));
+ pSmeRsp->messageType = pSmeRsp->messageType;
+ pSmeRsp->length = pSmeRsp->length;
+ pSmeRsp->statusCode = pSmeRsp->statusCode;
+
+ switch (pSmeRsp->messageType) {
+
+ case eWNI_SME_JOIN_RSP:
+ /* in Roaming state, process the Join response message... */
+ if (CSR_IS_ROAM_SUBSTATE_JOIN_REQ(pMac, pSmeRsp->sessionId))
+ /* We sent a JOIN_REQ */
+ csr_roam_join_rsp_processor(pMac,
+ (tSirSmeJoinRsp *) pSmeRsp);
+ break;
+ case eWNI_SME_REASSOC_RSP:
+ /* or the Reassociation response message... */
+ if (CSR_IS_ROAM_SUBSTATE_REASSOC_REQ(pMac, pSmeRsp->sessionId))
+ csr_roam_roaming_state_reassoc_rsp_processor(pMac,
+ (tpSirSmeJoinRsp) pSmeRsp);
+ break;
+ case eWNI_SME_STOP_BSS_RSP:
+ /* or the Stop Bss response message... */
+ csr_roam_roaming_state_stop_bss_rsp_processor(pMac, pSmeRsp);
+ break;
+ case eWNI_SME_DISASSOC_RSP:
+ /* or the Disassociate response message... */
+ if (CSR_IS_ROAM_SUBSTATE_DISASSOC_REQ(pMac, pSmeRsp->sessionId)
+ || CSR_IS_ROAM_SUBSTATE_DISASSOC_NO_JOIN(pMac,
+ pSmeRsp->sessionId)
+ || CSR_IS_ROAM_SUBSTATE_REASSOC_FAIL(pMac,
+ pSmeRsp->sessionId)
+ || CSR_IS_ROAM_SUBSTATE_DISASSOC_FORCED(pMac,
+ pSmeRsp->sessionId)
+ || CSR_IS_ROAM_SUBSTATE_DISCONNECT_CONTINUE(pMac,
+ pSmeRsp->sessionId)
+ || CSR_IS_ROAM_SUBSTATE_DISASSOC_HO(pMac,
+ pSmeRsp->sessionId)) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ FL("eWNI_SME_DISASSOC_RSP subState = %s"),
+ mac_trace_getcsr_roam_sub_state(
+ pMac->roam.curSubState[pSmeRsp->sessionId]));
+ csr_roam_roaming_state_disassoc_rsp_processor(pMac,
+ (tSirSmeDisassocRsp *) pSmeRsp);
+ }
+ break;
+ case eWNI_SME_DEAUTH_RSP:
+ /* or the Deauthentication response message... */
+ if (CSR_IS_ROAM_SUBSTATE_DEAUTH_REQ(pMac, pSmeRsp->sessionId))
+ csr_roam_roaming_state_deauth_rsp_processor(pMac,
+ (tSirSmeDeauthRsp *) pSmeRsp);
+ break;
+ case eWNI_SME_START_BSS_RSP:
+ /* or the Start BSS response message... */
+ if (CSR_IS_ROAM_SUBSTATE_START_BSS_REQ(pMac,
+ pSmeRsp->sessionId))
+ csr_roam_roaming_state_start_bss_rsp_processor(pMac,
+ (tSirSmeStartBssRsp *) pSmeRsp);
+ break;
+ /* In case CSR issues STOP_BSS, we need to tell HDD about peer departed
+ * becasue PE is removing them
+ */
+ case eWNI_SME_IBSS_PEER_DEPARTED_IND:
+ pIbssPeerInd = (tSmeIbssPeerInd *) pSmeRsp;
+ sms_log(pMac, LOGE,
+ FL("Peer departed ntf from LIM in joining state"));
+ cdf_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0);
+ roamInfo.staId = (uint8_t) pIbssPeerInd->staId;
+ roamInfo.ucastSig = (uint8_t) pIbssPeerInd->ucastSig;
+ roamInfo.bcastSig = (uint8_t) pIbssPeerInd->bcastSig;
+ cdf_mem_copy(&roamInfo.peerMac, pIbssPeerInd->peerAddr,
+ sizeof(struct cdf_mac_addr));
+ csr_roam_call_callback(pMac, pSmeRsp->sessionId, &roamInfo, 0,
+ eCSR_ROAM_CONNECT_STATUS_UPDATE,
+ eCSR_ROAM_RESULT_IBSS_PEER_DEPARTED);
+ break;
+ case eWNI_SME_GET_RSSI_REQ:
+ {
+ tAniGetRssiReq *pGetRssiReq = (tAniGetRssiReq *) pMsgBuf;
+ if (NULL != pGetRssiReq->rssiCallback)
+ ((tCsrRssiCallback) pGetRssiReq->rssiCallback)
+ (pGetRssiReq->lastRSSI, pGetRssiReq->staId,
+ pGetRssiReq->pDevContext);
+ else
+ sms_log(pMac, LOGE,
+ FL("pGetRssiReq->rssiCallback is NULL"));
+ }
+ break;
+ default:
+ sms_log(pMac, LOG1,
+ FL("Unexpected message type = %d[0x%X] received in substate %s"),
+ pSmeRsp->messageType, pSmeRsp->messageType,
+ mac_trace_getcsr_roam_sub_state(
+ pMac->roam.curSubState[pSmeRsp->sessionId]));
+ /* If we are connected, check the link status change */
+ if (!csr_is_conn_state_disconnected(pMac, pSmeRsp->sessionId))
+ csr_roam_check_for_link_status_change(pMac, pSmeRsp);
+ break;
+ }
+}
+
+void csr_roam_joined_state_msg_processor(tpAniSirGlobal pMac, void *pMsgBuf)
+{
+ tSirSmeRsp *pSirMsg = (tSirSmeRsp *) pMsgBuf;
+ switch (pSirMsg->messageType) {
+ case eWNI_SME_GET_STATISTICS_RSP:
+ sms_log(pMac, LOG2, FL("Stats rsp from PE"));
+ csr_roam_stats_rsp_processor(pMac, pSirMsg);
+ break;
+ case eWNI_SME_UPPER_LAYER_ASSOC_CNF:
+ {
+ tCsrRoamSession *pSession;
+ tSirSmeAssocIndToUpperLayerCnf *pUpperLayerAssocCnf;
+ tCsrRoamInfo roamInfo;
+ tCsrRoamInfo *pRoamInfo = NULL;
+ uint32_t sessionId;
+ CDF_STATUS status;
+ sms_log(pMac, LOG1,
+ FL
+ ("ASSOCIATION confirmation 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;
+ }
+
+ pRoamInfo->statusCode = eSIR_SME_SUCCESS; /* send the status code as Success */
+ pRoamInfo->u.pConnectedProfile =
+ &pSession->connectedProfile;
+ pRoamInfo->staId = (uint8_t) pUpperLayerAssocCnf->aid;
+ pRoamInfo->rsnIELen =
+ (uint8_t) pUpperLayerAssocCnf->rsnIE.length;
+ pRoamInfo->prsnIE =
+ pUpperLayerAssocCnf->rsnIE.rsnIEdata;
+#ifdef FEATURE_WLAN_WAPI
+ pRoamInfo->wapiIELen =
+ (uint8_t) pUpperLayerAssocCnf->wapiIE.length;
+ pRoamInfo->pwapiIE =
+ pUpperLayerAssocCnf->wapiIE.wapiIEdata;
+#endif
+ pRoamInfo->addIELen =
+ (uint8_t) pUpperLayerAssocCnf->addIE.length;
+ pRoamInfo->paddIE =
+ pUpperLayerAssocCnf->addIE.addIEdata;
+ cdf_mem_copy(pRoamInfo->peerMac.bytes,
+ pUpperLayerAssocCnf->peerMacAddr,
+ sizeof(tSirMacAddr));
+ cdf_mem_copy(&pRoamInfo->bssid,
+ pUpperLayerAssocCnf->bssId,
+ sizeof(struct cdf_mac_addr));
+ pRoamInfo->wmmEnabledSta =
+ pUpperLayerAssocCnf->wmmEnabledSta;
+ pRoamInfo->timingMeasCap =
+ pUpperLayerAssocCnf->timingMeasCap;
+ cdf_mem_copy(&pRoamInfo->chan_info,
+ &pUpperLayerAssocCnf->chan_info,
+ sizeof(tSirSmeChanInfo));
+ 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; /* Sta */
+ status = csr_roam_call_callback(pMac, sessionId, pRoamInfo, 0, eCSR_ROAM_WDS_IND, eCSR_ROAM_RESULT_WDS_ASSOCIATION_IND); /* Sta */
+ }
+
+ }
+ break;
+ default:
+ csr_roam_check_for_link_status_change(pMac, pSirMsg);
+ break;
+ }
+}
+
+CDF_STATUS csr_roam_issue_set_context_req(tpAniSirGlobal pMac,
+ uint32_t sessionId,
+ eCsrEncryptionType EncryptType,
+ tSirBssDescription *pBssDescription,
+ tSirMacAddr *bssId, bool addKey,
+ bool fUnicast,
+ tAniKeyDirection aniKeyDirection,
+ uint8_t keyId, uint16_t keyLength,
+ uint8_t *pKey, uint8_t paeRole)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tAniEdType edType;
+
+ if (eCSR_ENCRYPT_TYPE_UNKNOWN == EncryptType) {
+ EncryptType = eCSR_ENCRYPT_TYPE_NONE;
+ }
+
+ edType = csr_translate_encrypt_type_to_ed_type(EncryptType);
+
+ /*
+ * Allow 0 keys to be set for the non-WPA encrypt types. For WPA encrypt
+ * types, the num keys must be non-zero or LIM will reject the set
+ * context (assumes the SET_CONTEXT does not occur until the keys are
+ * distrubuted).
+ */
+ if (CSR_IS_ENC_TYPE_STATIC(EncryptType) || addKey) {
+ tCsrRoamSetKey setKey;
+ setKey.encType = EncryptType;
+ setKey.keyDirection = aniKeyDirection;
+ cdf_mem_copy(&setKey.peerMac, bssId, sizeof(struct cdf_mac_addr));
+ /* 0 for supplicant */
+ setKey.paeRole = paeRole;
+ /* Key index */
+ setKey.keyId = keyId;
+ setKey.keyLength = keyLength;
+ if (keyLength) {
+ cdf_mem_copy(setKey.Key, pKey, keyLength);
+ }
+ status = csr_roam_issue_set_key_command(pMac, sessionId,
+ &setKey, 0);
+ }
+ return status;
+}
+
+/**
+ * csr_update_key_cmd() - update key info in set key command
+ * @mac_ctx: mac global context
+ * @session: roam session
+ * @set_key: input set key command
+ * @set_key_cmd: set key command to update
+ * @enqueue_cmd: indicates if command need to be enqueued to sme
+ *
+ * This function will validate the key length, adjust if too long. Tt will
+ * update bool enqueue_cmd, to false if some error has occured key are local.
+ *
+ * Return: status of operation
+ */
+static CDF_STATUS
+csr_update_key_cmd(tpAniSirGlobal mac_ctx, tCsrRoamSession *session,
+ tCsrRoamSetKey *set_key, tSmeCmd *set_key_cmd,
+ bool *enqueue_cmd)
+{
+ switch (set_key->encType) {
+ case eCSR_ENCRYPT_TYPE_WEP40:
+ case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY:
+ /* KeyLength maybe 0 for static WEP */
+ if (set_key->keyLength) {
+ if (set_key->keyLength < CSR_WEP40_KEY_LEN) {
+ sms_log(mac_ctx, LOGW,
+ FL("Invalid WEP40 keylength [= %d]"),
+ set_key->keyLength);
+ *enqueue_cmd = false;
+ return CDF_STATUS_E_INVAL;
+ }
+
+ set_key_cmd->u.setKeyCmd.keyLength = CSR_WEP40_KEY_LEN;
+ cdf_mem_copy(set_key_cmd->u.setKeyCmd.Key, set_key->Key,
+ CSR_WEP40_KEY_LEN);
+ }
+ *enqueue_cmd = true;
+ break;
+ case eCSR_ENCRYPT_TYPE_WEP104:
+ case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY:
+ /* KeyLength maybe 0 for static WEP */
+ if (set_key->keyLength) {
+ if (set_key->keyLength < CSR_WEP104_KEY_LEN) {
+ sms_log(mac_ctx, LOGW,
+ FL("Invalid WEP104 keylength [= %d]"),
+ set_key->keyLength);
+ *enqueue_cmd = false;
+ return CDF_STATUS_E_INVAL;
+ }
+
+ set_key_cmd->u.setKeyCmd.keyLength = CSR_WEP104_KEY_LEN;
+ cdf_mem_copy(set_key_cmd->u.setKeyCmd.Key, set_key->Key,
+ CSR_WEP104_KEY_LEN);
+ }
+ *enqueue_cmd = true;
+ break;
+ case eCSR_ENCRYPT_TYPE_TKIP:
+ if (set_key->keyLength < CSR_TKIP_KEY_LEN) {
+ sms_log(mac_ctx, LOGW,
+ FL("Invalid TKIP keylength [= %d]"),
+ set_key->keyLength);
+ *enqueue_cmd = false;
+ return CDF_STATUS_E_INVAL;
+ }
+ set_key_cmd->u.setKeyCmd.keyLength = CSR_TKIP_KEY_LEN;
+ cdf_mem_copy(set_key_cmd->u.setKeyCmd.Key, set_key->Key,
+ CSR_TKIP_KEY_LEN);
+ *enqueue_cmd = true;
+ break;
+ case eCSR_ENCRYPT_TYPE_AES:
+ if (set_key->keyLength < CSR_AES_KEY_LEN) {
+ sms_log(mac_ctx, LOGW,
+ FL("Invalid AES/CCMP keylength [= %d]"),
+ set_key->keyLength);
+ *enqueue_cmd = false;
+ return CDF_STATUS_E_INVAL;
+ }
+ set_key_cmd->u.setKeyCmd.keyLength = CSR_AES_KEY_LEN;
+ cdf_mem_copy(set_key_cmd->u.setKeyCmd.Key, set_key->Key,
+ CSR_AES_KEY_LEN);
+ *enqueue_cmd = true;
+ break;
+#ifdef FEATURE_WLAN_WAPI
+ case eCSR_ENCRYPT_TYPE_WPI:
+ if (set_key->keyLength < CSR_WAPI_KEY_LEN) {
+ sms_log(mac_ctx, LOGW,
+ FL("Invalid WAPI keylength [= %d]"),
+ set_key->keyLength);
+ *enqueue_cmd = false;
+ return CDF_STATUS_E_INVAL;
+ }
+ set_key_cmd->u.setKeyCmd.keyLength = CSR_WAPI_KEY_LEN;
+ cdf_mem_copy(set_key_cmd->u.setKeyCmd.Key, set_key->Key,
+ CSR_WAPI_KEY_LEN);
+ if (session->pCurRoamProfile) {
+ session->pCurRoamProfile->negotiatedUCEncryptionType =
+ eCSR_ENCRYPT_TYPE_WPI;
+ } else {
+ sms_log(mac_ctx, LOGW,
+ FL("pCurRoamProfile is NULL."));
+ *enqueue_cmd = false;
+ return CDF_STATUS_E_INVAL;
+ }
+ *enqueue_cmd = true;
+ break;
+#endif /* FEATURE_WLAN_WAPI */
+#ifdef FEATURE_WLAN_ESE
+ case eCSR_ENCRYPT_TYPE_KRK:
+ /* no need to enqueue KRK key request, since they are local */
+ *enqueue_cmd = false;
+ if (set_key->keyLength < CSR_KRK_KEY_LEN) {
+ sms_log(mac_ctx, LOGW,
+ FL("Invalid KRK keylength [= %d]"),
+ set_key->keyLength);
+ return CDF_STATUS_E_INVAL;
+ }
+ cdf_mem_copy(session->eseCckmInfo.krk, set_key->Key,
+ CSR_KRK_KEY_LEN);
+ session->eseCckmInfo.reassoc_req_num = 1;
+ session->eseCckmInfo.krk_plumbed = true;
+ break;
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+ case eCSR_ENCRYPT_TYPE_BTK:
+ /* no need to enqueue KRK key request, since they are local */
+ *enqueue_cmd = false;
+ if (set_key->keyLength < SIR_BTK_KEY_LEN) {
+ sms_log(mac_ctx, LOGW,
+ FL("LFR3:Invalid BTK keylength [= %d]"),
+ set_key->keyLength);
+ return CDF_STATUS_E_INVAL;
+ }
+ cdf_mem_copy(session->eseCckmInfo.btk, set_key->Key,
+ SIR_BTK_KEY_LEN);
+ break;
+#endif
+#endif /* FEATURE_WLAN_ESE */
+#ifdef WLAN_FEATURE_11W
+ /* Check for 11w BIP */
+ case eCSR_ENCRYPT_TYPE_AES_CMAC:
+ if (set_key->keyLength < CSR_AES_KEY_LEN) {
+ sms_log(mac_ctx, LOGW,
+ FL("Invalid AES/CCMP keylength [= %d]"),
+ set_key->keyLength);
+ *enqueue_cmd = false;
+ return CDF_STATUS_E_INVAL;
+ }
+ set_key_cmd->u.setKeyCmd.keyLength = CSR_AES_KEY_LEN;
+ cdf_mem_copy(set_key_cmd->u.setKeyCmd.Key, set_key->Key,
+ CSR_AES_KEY_LEN);
+ *enqueue_cmd = true;
+ break;
+#endif /* WLAN_FEATURE_11W */
+ default:
+ /* for open security also we want to enqueue command */
+ *enqueue_cmd = true;
+ return CDF_STATUS_SUCCESS;
+ } /* end of switch */
+ return CDF_STATUS_SUCCESS;
+}
+
+
+static CDF_STATUS csr_roam_issue_set_key_command(tpAniSirGlobal pMac,
+ uint32_t sessionId,
+ tCsrRoamSetKey *pSetKey,
+ uint32_t roamId)
+{
+ CDF_STATUS status = CDF_STATUS_E_INVAL;
+ bool enqueue_cmd = true;
+ tSmeCmd *pCommand = NULL;
+#if defined(FEATURE_WLAN_ESE) || defined (FEATURE_WLAN_WAPI)
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+ if (NULL == pSession) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ FL("session %d not found"), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+#endif /* FEATURE_WLAN_ESE */
+
+ pCommand = csr_get_command_buffer(pMac);
+ if (NULL == pCommand) {
+ sms_log(pMac, LOGE, FL(" fail to get command buffer"));
+ return CDF_STATUS_E_RESOURCES;
+ }
+ cdf_mem_zero(pCommand, sizeof(tSmeCmd));
+ pCommand->command = eSmeCommandSetKey;
+ pCommand->sessionId = (uint8_t) sessionId;
+ /*
+ * following function will validate the key length, Adjust if too long.
+ * for static WEP the keys are not set thru' SetContextReq
+ *
+ * it will update bool enqueue_cmd, to false if some error has occured
+ * key are local. enqueue sme command only if enqueue_cmd is true
+ * status is indication of success or failure and will be returned to
+ * called of current function if command is not enqueued due to key req
+ * being local
+ */
+ status = csr_update_key_cmd(pMac, pSession, pSetKey,
+ pCommand, &enqueue_cmd);
+ if (enqueue_cmd) {
+ pCommand->u.setKeyCmd.roamId = roamId;
+ pCommand->u.setKeyCmd.encType = pSetKey->encType;
+ pCommand->u.setKeyCmd.keyDirection = pSetKey->keyDirection;
+ cdf_mem_copy(&pCommand->u.setKeyCmd.peerMac, &pSetKey->peerMac,
+ sizeof(struct cdf_mac_addr));
+ /* 0 for supplicant */
+ pCommand->u.setKeyCmd.paeRole = pSetKey->paeRole;
+ pCommand->u.setKeyCmd.keyId = pSetKey->keyId;
+ cdf_mem_copy(pCommand->u.setKeyCmd.keyRsc, pSetKey->keyRsc,
+ CSR_MAX_RSC_LEN);
+ /*
+ * Always put set key to the head of the Q because it is the
+ * only thing to get executed in case of WT_KEY state
+ */
+
+ status = csr_queue_sme_command(pMac, pCommand, true);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ FL("fail to send message status = %d"), status);
+ /* update to false so that command can be freed */
+ enqueue_cmd = false;
+ }
+ }
+
+ /*
+ * Free the command if enqueue_cmd == false:
+ * this means that command was not enqueued because either there has
+ * been a failure, or it is a "local" operation like the set ESE CCKM
+ * KRK key.
+ */
+ if (false == enqueue_cmd)
+ csr_release_command_set_key(pMac, pCommand);
+
+ return status;
+}
+
+CDF_STATUS csr_roam_process_set_key_command(tpAniSirGlobal pMac, tSmeCmd *pCommand)
+{
+ CDF_STATUS status;
+ uint8_t numKeys = (pCommand->u.setKeyCmd.keyLength) ? 1 : 0;
+ tAniEdType edType =
+ csr_translate_encrypt_type_to_ed_type(pCommand->u.setKeyCmd.encType);
+ bool fUnicast =
+ (pCommand->u.setKeyCmd.peerMac[0] == 0xFF) ? false : true;
+ uint32_t sessionId = pCommand->sessionId;
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+ WLAN_HOST_DIAG_EVENT_DEF(setKeyEvent,
+ host_event_wlan_security_payload_type);
+
+ if (NULL == pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ if (eSIR_ED_NONE != edType) {
+ cdf_mem_set(&setKeyEvent,
+ sizeof(host_event_wlan_security_payload_type), 0);
+ if (*((uint8_t *) &pCommand->u.setKeyCmd.peerMac) & 0x01) {
+ setKeyEvent.eventId = WLAN_SECURITY_EVENT_SET_GTK_REQ;
+ setKeyEvent.encryptionModeMulticast =
+ (uint8_t) diag_enc_type_from_csr_type(pCommand->u.
+ setKeyCmd.encType);
+ setKeyEvent.encryptionModeUnicast =
+ (uint8_t) diag_enc_type_from_csr_type(pSession->
+ connectedProfile.
+ EncryptionType);
+ } else {
+ setKeyEvent.eventId = WLAN_SECURITY_EVENT_SET_PTK_REQ;
+ setKeyEvent.encryptionModeUnicast =
+ (uint8_t) diag_enc_type_from_csr_type(pCommand->u.
+ setKeyCmd.encType);
+ setKeyEvent.encryptionModeMulticast =
+ (uint8_t) diag_enc_type_from_csr_type(pSession->
+ connectedProfile.
+ mcEncryptionType);
+ }
+ cdf_mem_copy(setKeyEvent.bssid,
+ pSession->connectedProfile.bssid.bytes,
+ CDF_MAC_ADDR_SIZE);
+ if (CSR_IS_ENC_TYPE_STATIC(pCommand->u.setKeyCmd.encType)) {
+ uint32_t defKeyId;
+ /* It has to be static WEP here */
+ if (IS_SIR_STATUS_SUCCESS
+ (wlan_cfg_get_int
+ (pMac, WNI_CFG_WEP_DEFAULT_KEYID, &defKeyId))) {
+ setKeyEvent.keyId = (uint8_t) defKeyId;
+ }
+ } else {
+ setKeyEvent.keyId = pCommand->u.setKeyCmd.keyId;
+ }
+ setKeyEvent.authMode =
+ (uint8_t) diag_auth_type_from_csr_type(pSession->
+ connectedProfile.
+ AuthType);
+ WLAN_HOST_DIAG_EVENT_REPORT(&setKeyEvent, EVENT_WLAN_SECURITY);
+ }
+#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */
+ if (csr_is_set_key_allowed(pMac, sessionId)) {
+ status = csr_send_mb_set_context_req_msg(pMac, sessionId,
+ (uint8_t *) &pCommand->u.
+ setKeyCmd.peerMac, numKeys,
+ edType, fUnicast,
+ pCommand->u.setKeyCmd.
+ keyDirection,
+ pCommand->u.setKeyCmd.keyId,
+ pCommand->u.setKeyCmd.
+ keyLength,
+ pCommand->u.setKeyCmd.Key,
+ pCommand->u.setKeyCmd.
+ paeRole,
+ pCommand->u.setKeyCmd.
+ keyRsc);
+ } else {
+ sms_log(pMac, LOGW, FL(" cannot process not connected"));
+ /* Set this status so the error handling take care of the case. */
+ status = CDF_STATUS_CSR_WRONG_STATE;
+ }
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE, FL(" error status %d"), status);
+ csr_roam_call_callback(pMac, sessionId, NULL,
+ pCommand->u.setKeyCmd.roamId,
+ eCSR_ROAM_SET_KEY_COMPLETE,
+ eCSR_ROAM_RESULT_FAILURE);
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+ if (eSIR_ED_NONE != edType) {
+ if (*((uint8_t *) &pCommand->u.setKeyCmd.peerMac) &
+ 0x01) {
+ setKeyEvent.eventId =
+ WLAN_SECURITY_EVENT_SET_GTK_RSP;
+ } else {
+ setKeyEvent.eventId =
+ WLAN_SECURITY_EVENT_SET_PTK_RSP;
+ }
+ setKeyEvent.status = WLAN_SECURITY_STATUS_FAILURE;
+ WLAN_HOST_DIAG_EVENT_REPORT(&setKeyEvent,
+ EVENT_WLAN_SECURITY);
+ }
+#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */
+ }
+ return status;
+}
+
+CDF_STATUS csr_roam_set_key(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamSetKey *pSetKey, uint32_t roamId)
+{
+ CDF_STATUS status;
+
+ if (!csr_is_set_key_allowed(pMac, sessionId)) {
+ status = CDF_STATUS_CSR_WRONG_STATE;
+ } else {
+ status =
+ csr_roam_issue_set_key_command(pMac, sessionId, pSetKey, roamId);
+ }
+ return status;
+}
+
+/*
+ Prepare a filter base on a profile for parsing the scan results.
+ Upon successful return, caller MUST call csr_free_scan_filter on
+ pScanFilter when it is done with the filter.
+ */
+CDF_STATUS
+csr_roam_prepare_filter_from_profile(tpAniSirGlobal mac_ctx,
+ tCsrRoamProfile *profile,
+ tCsrScanResultFilter *scan_fltr)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ uint32_t size = 0;
+ uint8_t idx = 0;
+ tCsrChannelInfo *fltr_ch_info = &scan_fltr->ChannelInfo;
+ tCsrChannelInfo *profile_ch_info = &profile->ChannelInfo;
+ struct roam_ext_params *roam_params;
+ uint8_t i;
+
+ roam_params = &mac_ctx->roam.configParam.roam_params;
+
+ if (profile->BSSIDs.numOfBSSIDs) {
+ size = sizeof(struct cdf_mac_addr) * profile->BSSIDs.numOfBSSIDs;
+ scan_fltr->BSSIDs.bssid = cdf_mem_malloc(size);
+ if (NULL == scan_fltr->BSSIDs.bssid) {
+ status = CDF_STATUS_E_NOMEM;
+ goto free_filter;
+ }
+ scan_fltr->BSSIDs.numOfBSSIDs = profile->BSSIDs.numOfBSSIDs;
+ cdf_mem_copy(scan_fltr->BSSIDs.bssid,
+ profile->BSSIDs.bssid, size);
+ }
+
+ if (profile->SSIDs.numOfSSIDs) {
+ if (!CSR_IS_WDS_STA(profile)) {
+ scan_fltr->SSIDs.numOfSSIDs = profile->SSIDs.numOfSSIDs;
+ } else {
+ /*
+ * For WDS station we always use idx 1 for self SSID.
+ * Index 0 for peer's SSID that we want to join
+ */
+ scan_fltr->SSIDs.numOfSSIDs = 1;
+ }
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ FL("No of Allowed List:%d"),
+ roam_params->num_ssid_allowed_list);
+ if (scan_fltr->scan_filter_for_roam
+ && roam_params->num_ssid_allowed_list) {
+ scan_fltr->SSIDs.numOfSSIDs =
+ roam_params->num_ssid_allowed_list;
+ size = sizeof(tCsrSSIDInfo) *
+ scan_fltr->SSIDs.numOfSSIDs;
+ scan_fltr->SSIDs.SSIDList = cdf_mem_malloc(size);
+ if (NULL == scan_fltr->SSIDs.SSIDList)
+ status = CDF_STATUS_E_FAILURE;
+ else
+ status = CDF_STATUS_SUCCESS;
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ goto free_filter;
+ for (i = 0;
+ i < roam_params->num_ssid_allowed_list;
+ i++) {
+ cdf_mem_copy((void *)
+ scan_fltr->SSIDs.SSIDList[i].SSID.ssId,
+ roam_params->ssid_allowed_list[i].ssId,
+ roam_params->ssid_allowed_list[i].length);
+ scan_fltr->SSIDs.SSIDList[i].SSID.length =
+ roam_params->ssid_allowed_list[i].length;
+ scan_fltr->SSIDs.SSIDList[i].handoffPermitted =
+ 1;
+ scan_fltr->SSIDs.SSIDList[i].ssidHidden = 0;
+ }
+ } else {
+ size = sizeof(tCsrSSIDInfo) *
+ profile->SSIDs.numOfSSIDs;
+ scan_fltr->SSIDs.SSIDList = cdf_mem_malloc(size);
+ if (NULL == scan_fltr->SSIDs.SSIDList) {
+ status = CDF_STATUS_E_NOMEM;
+ goto free_filter;
+ }
+ cdf_mem_copy(scan_fltr->SSIDs.SSIDList,
+ profile->SSIDs.SSIDList, size);
+ }
+ }
+
+ if (!profile_ch_info->ChannelList
+ || (profile_ch_info->ChannelList[0] == 0)) {
+ fltr_ch_info->numOfChannels = 0;
+ fltr_ch_info->ChannelList = NULL;
+ } else if (profile_ch_info->numOfChannels) {
+ fltr_ch_info->numOfChannels = 0;
+ fltr_ch_info->ChannelList =
+ cdf_mem_malloc(sizeof(*(fltr_ch_info->ChannelList)) *
+ profile_ch_info->numOfChannels);
+ if (NULL == fltr_ch_info->ChannelList) {
+ status = CDF_STATUS_E_NOMEM;
+ goto free_filter;
+ }
+
+ for (idx = 0; idx < profile_ch_info->numOfChannels; idx++) {
+ if (csr_roam_is_channel_valid(mac_ctx,
+ profile_ch_info->ChannelList[idx])) {
+ fltr_ch_info->
+ ChannelList[fltr_ch_info->numOfChannels]
+ = profile_ch_info->ChannelList[idx];
+ fltr_ch_info->numOfChannels++;
+ } else {
+ sms_log(mac_ctx, LOG1,
+ FL("Channel (%d) is invalid"),
+ profile_ch_info->ChannelList[idx]);
+ }
+ }
+ } else {
+ sms_log(mac_ctx, LOGE, FL("Channel list empty"));
+ status = CDF_STATUS_E_FAILURE;
+ goto free_filter;
+ }
+ scan_fltr->uapsd_mask = profile->uapsd_mask;
+ scan_fltr->authType = profile->AuthType;
+ scan_fltr->EncryptionType = profile->EncryptionType;
+ scan_fltr->mcEncryptionType = profile->mcEncryptionType;
+ scan_fltr->BSSType = profile->BSSType;
+ scan_fltr->phyMode = profile->phyMode;
+#ifdef FEATURE_WLAN_WAPI
+ /*
+ * check if user asked for WAPI with 11n or auto mode, in that
+ * case modify the phymode to 11g
+ */
+ if (csr_is_profile_wapi(profile)) {
+ if (scan_fltr->phyMode & eCSR_DOT11_MODE_11n)
+ scan_fltr->phyMode &= ~eCSR_DOT11_MODE_11n;
+ if (scan_fltr->phyMode & eCSR_DOT11_MODE_AUTO)
+ scan_fltr->phyMode &= ~eCSR_DOT11_MODE_AUTO;
+ if (!scan_fltr->phyMode)
+ scan_fltr->phyMode = eCSR_DOT11_MODE_11g;
+ }
+#endif /* FEATURE_WLAN_WAPI */
+ /*Save the WPS info */
+ scan_fltr->bWPSAssociation = profile->bWPSAssociation;
+ scan_fltr->bOSENAssociation = profile->bOSENAssociation;
+ if (profile->countryCode[0]) {
+ /*
+ * This causes the matching function to use countryCode as one
+ * of the criteria.
+ */
+ cdf_mem_copy(scan_fltr->countryCode, profile->countryCode,
+ WNI_CFG_COUNTRY_CODE_LEN);
+ }
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ if (profile->MDID.mdiePresent) {
+ scan_fltr->MDID.mdiePresent = 1;
+ scan_fltr->MDID.mobilityDomain = profile->MDID.mobilityDomain;
+ }
+#endif
+
+#ifdef WLAN_FEATURE_11W
+ /* Management Frame Protection */
+ scan_fltr->MFPEnabled = profile->MFPEnabled;
+ scan_fltr->MFPRequired = profile->MFPRequired;
+ scan_fltr->MFPCapable = profile->MFPCapable;
+#endif
+ scan_fltr->csrPersona = profile->csrPersona;
+
+free_filter:
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ csr_free_scan_filter(mac_ctx, scan_fltr);
+
+ return status;
+}
+
+bool csr_roam_issue_wm_status_change(tpAniSirGlobal pMac, uint32_t sessionId,
+ eCsrRoamWmStatusChangeTypes Type,
+ tSirSmeRsp *pSmeRsp)
+{
+ bool fCommandQueued = false;
+ tSmeCmd *pCommand;
+ do {
+ /* Validate the type is ok... */
+ if ((eCsrDisassociated != Type)
+ && (eCsrDeauthenticated != Type))
+ break;
+ pCommand = csr_get_command_buffer(pMac);
+ if (!pCommand) {
+ sms_log(pMac, LOGE, FL(" fail to get command buffer"));
+ break;
+ }
+ /* Change the substate in case it is waiting for key */
+ if (CSR_IS_WAIT_FOR_KEY(pMac, sessionId)) {
+ csr_roam_stop_wait_for_key_timer(pMac);
+ csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_NONE,
+ sessionId);
+ }
+ pCommand->command = eSmeCommandWmStatusChange;
+ pCommand->sessionId = (uint8_t) sessionId;
+ pCommand->u.wmStatusChangeCmd.Type = Type;
+ if (eCsrDisassociated == Type) {
+ cdf_mem_copy(&pCommand->u.wmStatusChangeCmd.u.
+ DisassocIndMsg, pSmeRsp,
+ sizeof(pCommand->u.wmStatusChangeCmd.u.
+ DisassocIndMsg));
+ } else {
+ cdf_mem_copy(&pCommand->u.wmStatusChangeCmd.u.
+ DeauthIndMsg, pSmeRsp,
+ sizeof(pCommand->u.wmStatusChangeCmd.u.
+ DeauthIndMsg));
+ }
+ if (CDF_IS_STATUS_SUCCESS
+ (csr_queue_sme_command(pMac, pCommand, true))) {
+ fCommandQueued = true;
+ } else {
+ sms_log(pMac, LOGE, FL(" fail to send message "));
+ csr_release_command_wm_status_change(pMac, pCommand);
+ }
+
+ /* AP has issued Dissac/Deauth, Set the operating mode value to configured value */
+ csr_set_default_dot11_mode(pMac);
+ } while (0);
+ return fCommandQueued;
+}
+
+static CDF_STATUS csr_send_snr_request(void *pGetRssiReq)
+{
+ void *wma_handle;
+
+ wma_handle = cds_get_context(CDF_MODULE_ID_WMA);
+ if (!wma_handle) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ "wma_handle is NULL");
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ if (CDF_STATUS_SUCCESS !=
+ wma_send_snr_request(wma_handle, pGetRssiReq)) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ "Failed to Trigger wma stats request");
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ /* dont send success, otherwise call back
+ * will released with out values */
+ return CDF_STATUS_E_BUSY;
+}
+
+static void csr_update_rssi(tpAniSirGlobal pMac, void *pMsg)
+{
+ int8_t rssi = 0;
+ tAniGetRssiReq *pGetRssiReq = (tAniGetRssiReq *) pMsg;
+ CDF_STATUS cdf_status = CDF_STATUS_SUCCESS;
+ if (pGetRssiReq) {
+ if (NULL != pGetRssiReq->p_cds_context) {
+ cdf_status = csr_send_snr_request(pGetRssiReq);
+ } else {
+ sms_log(pMac, LOGE,
+ FL("pGetRssiReq->p_cds_context is NULL"));
+ return;
+ }
+
+ if (NULL != pGetRssiReq->rssiCallback) {
+ if (cdf_status != CDF_STATUS_E_BUSY)
+ ((tCsrRssiCallback) (pGetRssiReq->rssiCallback))
+ (rssi, pGetRssiReq->staId,
+ pGetRssiReq->pDevContext);
+ else
+ sms_log(pMac, LOG1,
+ FL
+ ("rssi request is posted. waiting for reply"));
+ } else {
+ sms_log(pMac, LOGE,
+ FL("pGetRssiReq->rssiCallback is NULL"));
+ return;
+ }
+ } else {
+ sms_log(pMac, LOGE, FL("pGetRssiReq is NULL"));
+ }
+ return;
+
+}
+
+static void csr_update_snr(tpAniSirGlobal pMac, void *pMsg)
+{
+ tAniGetSnrReq *pGetSnrReq = (tAniGetSnrReq *) pMsg;
+
+ if (pGetSnrReq) {
+ if (CDF_STATUS_SUCCESS != wma_get_snr(pGetSnrReq)) {
+ sms_log(pMac, LOGE, FL("Error in wma_get_snr"));
+ return;
+ }
+
+ } else {
+ sms_log(pMac, LOGE, FL("pGetSnrReq is NULL"));
+ }
+ return;
+}
+
+#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD)
+void csr_tsm_stats_rsp_processor(tpAniSirGlobal pMac, void *pMsg)
+{
+ tAniGetTsmStatsRsp *pTsmStatsRsp = (tAniGetTsmStatsRsp *) pMsg;
+
+ if (NULL != pTsmStatsRsp) {
+ /* Get roam Rssi request is backed up and passed back to the response,
+ Extract the request message to fetch callback */
+ tpAniGetTsmStatsReq reqBkp
+ = (tAniGetTsmStatsReq *) pTsmStatsRsp->tsmStatsReq;
+
+ if (NULL != reqBkp) {
+ if (NULL != reqBkp->tsmStatsCallback) {
+ ((tCsrTsmStatsCallback)
+ (reqBkp->tsmStatsCallback))(pTsmStatsRsp->
+ tsmMetrics,
+ pTsmStatsRsp->
+ staId,
+ reqBkp->
+ pDevContext);
+ reqBkp->tsmStatsCallback = NULL;
+ }
+ cdf_mem_free(reqBkp);
+ pTsmStatsRsp->tsmStatsReq = NULL;
+ } else {
+ sms_log(pMac, LOGE, FL("reqBkp is NULL"));
+ if (NULL != reqBkp) {
+ cdf_mem_free(reqBkp);
+ pTsmStatsRsp->tsmStatsReq = NULL;
+ }
+ }
+ } else {
+ sms_log(pMac, LOGE, FL("pTsmStatsRsp is NULL"));
+ }
+ return;
+}
+
+void csr_send_ese_adjacent_ap_rep_ind(tpAniSirGlobal pMac, tCsrRoamSession *pSession)
+{
+ uint32_t roamTS2 = 0;
+ tCsrRoamInfo roamInfo;
+ tpPESession pSessionEntry = NULL;
+ uint8_t sessionId = CSR_SESSION_ID_INVALID;
+
+ if (NULL == pSession) {
+ sms_log(pMac, LOGE, FL("pSession is NULL"));
+ return;
+ }
+
+ roamTS2 = cdf_mc_timer_get_system_time();
+ roamInfo.tsmRoamDelay = roamTS2 - pSession->roamTS1;
+ sms_log(pMac, LOG1, "Bssid(" MAC_ADDRESS_STR ") Roaming Delay(%u ms)",
+ MAC_ADDR_ARRAY(pSession->connectedProfile.bssid.bytes),
+ roamInfo.tsmRoamDelay);
+
+ pSessionEntry = pe_find_session_by_bssid(pMac,
+ pSession->connectedProfile.bssid.bytes,
+ &sessionId);
+ if (NULL == pSessionEntry) {
+ sms_log(pMac, LOGE, FL("session %d not found"), sessionId);
+ return;
+ }
+
+ pSessionEntry->eseContext.tsm.tsmMetrics.RoamingDly
+ = roamInfo.tsmRoamDelay;
+
+ csr_roam_call_callback(pMac, pSession->sessionId, &roamInfo,
+ 0, eCSR_ROAM_ESE_ADJ_AP_REPORT_IND, 0);
+}
+#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */
+
+CDF_STATUS csr_send_reset_ap_caps_changed(tpAniSirGlobal pMac, tSirMacAddr *bssId)
+{
+ tpSirResetAPCapsChange pMsg;
+ uint16_t len;
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+
+ /* Create the message and send to lim */
+ len = sizeof(tSirResetAPCapsChange);
+ pMsg = cdf_mem_malloc(len);
+ if (NULL == pMsg)
+ status = CDF_STATUS_E_NOMEM;
+ else
+ status = CDF_STATUS_SUCCESS;
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ cdf_mem_set(pMsg, sizeof(tSirResetAPCapsChange), 0);
+ pMsg->messageType = eWNI_SME_RESET_AP_CAPS_CHANGED;
+ pMsg->length = len;
+ cdf_mem_copy(pMsg->bssId, bssId, sizeof(tSirMacAddr));
+ sms_log(pMac, LOG1,
+ FL("CSR reset caps change for Bssid= " MAC_ADDRESS_STR),
+ MAC_ADDR_ARRAY(pMsg->bssId));
+ status = cds_send_mb_message_to_mac(pMsg);
+ } else {
+ sms_log(pMac, LOGE, FL("Memory allocation failed\n"));
+ }
+ return status;
+}
+
+static void
+csr_roam_chk_lnk_assoc_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr)
+{
+ tCsrRoamSession *session;
+ uint32_t sessionId = CSR_SESSION_ID_INVALID;
+ CDF_STATUS status;
+ tCsrRoamInfo *roam_info_ptr = NULL;
+ tSirSmeAssocInd *pAssocInd;
+ tCsrRoamInfo roam_info;
+ cdf_mem_set(&roam_info, sizeof(roam_info), 0);
+
+ sms_log(mac_ctx, LOG1, FL("Receive WNI_SME_ASSOC_IND from SME"));
+ pAssocInd = (tSirSmeAssocInd *) msg_ptr;
+ status = csr_roam_get_session_id_from_bssid(mac_ctx,
+ (struct cdf_mac_addr *) pAssocInd->bssId, &sessionId);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(mac_ctx, LOG1,
+ FL("Couldn't find session_id for given BSSID"));
+ return;
+ }
+ session = CSR_GET_SESSION(mac_ctx, sessionId);
+ if (!session) {
+ sms_log(mac_ctx, LOGE, FL("session %d not found"), sessionId);
+ return;
+ }
+ roam_info_ptr = &roam_info;
+ /* Required for indicating the frames to upper layer */
+ roam_info_ptr->assocReqLength = pAssocInd->assocReqLength;
+ roam_info_ptr->assocReqPtr = pAssocInd->assocReqPtr;
+ roam_info_ptr->beaconPtr = pAssocInd->beaconPtr;
+ roam_info_ptr->beaconLength = pAssocInd->beaconLength;
+ roam_info_ptr->statusCode = eSIR_SME_SUCCESS;
+ roam_info_ptr->u.pConnectedProfile = &session->connectedProfile;
+ roam_info_ptr->staId = (uint8_t) pAssocInd->staId;
+ roam_info_ptr->rsnIELen = (uint8_t) pAssocInd->rsnIE.length;
+ roam_info_ptr->prsnIE = pAssocInd->rsnIE.rsnIEdata;
+#ifdef FEATURE_WLAN_WAPI
+ roam_info_ptr->wapiIELen = (uint8_t) pAssocInd->wapiIE.length;
+ roam_info_ptr->pwapiIE = pAssocInd->wapiIE.wapiIEdata;
+#endif
+ roam_info_ptr->addIELen = (uint8_t) pAssocInd->addIE.length;
+ roam_info_ptr->paddIE = pAssocInd->addIE.addIEdata;
+ cdf_mem_copy(roam_info_ptr->peerMac.bytes,
+ pAssocInd->peerMacAddr,
+ sizeof(tSirMacAddr));
+ cdf_mem_copy(roam_info_ptr->bssid.bytes,
+ pAssocInd->bssId,
+ sizeof(struct cdf_mac_addr));
+ roam_info_ptr->wmmEnabledSta = pAssocInd->wmmEnabledSta;
+ roam_info_ptr->timingMeasCap = pAssocInd->timingMeasCap;
+ cdf_mem_copy(&roam_info_ptr->chan_info,
+ &pAssocInd->chan_info,
+ sizeof(tSirSmeChanInfo));
+ if (CSR_IS_WDS_AP(roam_info_ptr->u.pConnectedProfile))
+ status = csr_roam_call_callback(mac_ctx, sessionId,
+ roam_info_ptr, 0, eCSR_ROAM_WDS_IND,
+ eCSR_ROAM_RESULT_WDS_ASSOCIATION_IND);
+ if (CSR_IS_INFRA_AP(roam_info_ptr->u.pConnectedProfile)) {
+ if (session->pCurRoamProfile &&
+ CSR_IS_ENC_TYPE_STATIC(
+ session->pCurRoamProfile->negotiatedUCEncryptionType)) {
+ /* NO keys... these key parameters don't matter. */
+ csr_roam_issue_set_context_req(mac_ctx, sessionId,
+ session->pCurRoamProfile->negotiatedUCEncryptionType,
+ session->pConnectBssDesc,
+ &(roam_info_ptr->peerMac.bytes),
+ false, true, eSIR_TX_RX, 0, 0, NULL, 0);
+ roam_info_ptr->fAuthRequired = false;
+ } else {
+ roam_info_ptr->fAuthRequired = true;
+ }
+ status = csr_roam_call_callback(mac_ctx, sessionId,
+ roam_info_ptr, 0, eCSR_ROAM_INFRA_IND,
+ eCSR_ROAM_RESULT_INFRA_ASSOCIATION_IND);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ /* Refused due to Mac filtering */
+ roam_info_ptr->statusCode = eSIR_SME_ASSOC_REFUSED;
+ }
+
+ /* Send Association completion message to PE */
+ status = csr_send_assoc_cnf_msg(mac_ctx, pAssocInd, status);
+ /*
+ * send a message to CSR itself just to avoid the EAPOL frames going
+ * OTA before association response
+ */
+ if (CSR_IS_WDS_AP(roam_info_ptr->u.pConnectedProfile)) {
+ status = csr_send_assoc_ind_to_upper_layer_cnf_msg(mac_ctx,
+ pAssocInd, status, sessionId);
+ } else if (CSR_IS_INFRA_AP(roam_info_ptr->u.pConnectedProfile)
+ && (roam_info_ptr->statusCode != eSIR_SME_ASSOC_REFUSED)) {
+ roam_info_ptr->fReassocReq = pAssocInd->reassocReq;
+ status = csr_send_assoc_ind_to_upper_layer_cnf_msg(mac_ctx,
+ pAssocInd, status, sessionId);
+ }
+}
+
+static void
+csr_roam_chk_lnk_disassoc_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr)
+{
+ tCsrRoamSession *session;
+ uint32_t sessionId = CSR_SESSION_ID_INVALID;
+ CDF_STATUS status;
+ tCsrRoamInfo *roam_info_ptr = NULL;
+ tSirSmeDisassocInd *pDisassocInd;
+ tSmeCmd cmd;
+ tCsrRoamInfo roam_info;
+
+ /*
+ * Check if AP dis-associated us because of MIC failure. If so,
+ * then we need to take action immediately and not wait till the
+ * the WmStatusChange requests is pushed and processed
+ */
+ pDisassocInd = (tSirSmeDisassocInd *) msg_ptr;
+ cdf_mem_set(&roam_info, sizeof(roam_info), 0);
+ status = csr_roam_get_session_id_from_bssid(mac_ctx,
+ (struct cdf_mac_addr *) pDisassocInd->bssId, &sessionId);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(mac_ctx, LOGE, FL("Session Id not found for BSSID "
+ MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pDisassocInd->bssId));
+ return;
+ }
+
+ sms_log(mac_ctx, LOGE,
+ FL("DISASSOCIATION Indication from MAC for session %d "),
+ sessionId);
+ sms_log(mac_ctx, LOGE,
+ FL("DISASSOCIATION from peer =" MAC_ADDRESS_STR
+ " " " reason = %d status = %d "),
+ MAC_ADDR_ARRAY(pDisassocInd->peerMacAddr),
+ pDisassocInd->reasonCode,
+ pDisassocInd->statusCode);
+ /*
+ * If we are in neighbor preauth done state then on receiving
+ * disassoc or deauth we dont roam instead we just disassoc
+ * from current ap and then go to disconnected state
+ * This happens for ESE and 11r FT connections ONLY.
+ */
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ if (csr_roam_is11r_assoc(mac_ctx, sessionId) &&
+ (csr_neighbor_roam_state_preauth_done(mac_ctx, sessionId)))
+ csr_neighbor_roam_tranistion_preauth_done_to_disconnected(
+ mac_ctx, sessionId);
+#endif
+#ifdef FEATURE_WLAN_ESE
+ if (csr_roam_is_ese_assoc(mac_ctx, sessionId) &&
+ (csr_neighbor_roam_state_preauth_done(mac_ctx, sessionId)))
+ csr_neighbor_roam_tranistion_preauth_done_to_disconnected(
+ mac_ctx, sessionId);
+#endif
+#ifdef FEATURE_WLAN_LFR
+ if (csr_roam_is_fast_roam_enabled(mac_ctx, sessionId) &&
+ (csr_neighbor_roam_state_preauth_done(mac_ctx, sessionId)))
+ csr_neighbor_roam_tranistion_preauth_done_to_disconnected(
+ mac_ctx, sessionId);
+#endif
+ session = CSR_GET_SESSION(mac_ctx, sessionId);
+ if (!session) {
+ sms_log(mac_ctx, LOGE, FL("session %d not found"), sessionId);
+ return;
+ }
+ if (csr_is_conn_state_infra(mac_ctx, sessionId))
+ session->connectState = eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED;
+#ifndef WLAN_MDM_CODE_REDUCTION_OPT
+ sme_qos_csr_event_ind(mac_ctx, (uint8_t) sessionId,
+ SME_QOS_CSR_DISCONNECT_IND, NULL);
+#endif
+ csr_roam_link_down(mac_ctx, sessionId);
+ csr_roam_issue_wm_status_change(mac_ctx, sessionId,
+ eCsrDisassociated, msg_ptr);
+ if (CSR_IS_INFRA_AP(&session->connectedProfile)) {
+ roam_info_ptr = &roam_info;
+ roam_info_ptr->statusCode = pDisassocInd->statusCode;
+ roam_info_ptr->reasonCode = pDisassocInd->reasonCode;
+ roam_info_ptr->u.pConnectedProfile = &session->connectedProfile;
+ roam_info_ptr->staId = (uint8_t) pDisassocInd->staId;
+ cdf_mem_copy(roam_info_ptr->peerMac.bytes,
+ pDisassocInd->peerMacAddr,
+ sizeof(tSirMacAddr));
+ cdf_mem_copy(&roam_info_ptr->bssid.bytes,
+ pDisassocInd->bssId,
+ sizeof(struct cdf_mac_addr));
+ status = csr_roam_call_callback(mac_ctx, sessionId,
+ roam_info_ptr, 0,
+ eCSR_ROAM_INFRA_IND,
+ eCSR_ROAM_RESULT_DISASSOC_IND);
+ /*
+ * STA/P2P client got disassociated so remove any pending
+ * deauth commands in sme pending list
+ */
+ cmd.command = eSmeCommandRoam;
+ cmd.sessionId = (uint8_t) sessionId;
+ cmd.u.roamCmd.roamReason = eCsrForcedDeauthSta;
+ cdf_mem_copy(cmd.u.roamCmd.peerMac,
+ pDisassocInd->peerMacAddr,
+ sizeof(tSirMacAddr));
+ csr_roam_remove_duplicate_command(mac_ctx, sessionId, &cmd,
+ eCsrForcedDeauthSta);
+ }
+}
+
+static void
+csr_roam_chk_lnk_deauth_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr)
+{
+ tCsrRoamSession *session;
+ uint32_t sessionId = CSR_SESSION_ID_INVALID;
+ CDF_STATUS status;
+ tCsrRoamInfo *roam_info_ptr = NULL;
+ tSirSmeDeauthInd *pDeauthInd;
+ tCsrRoamInfo roam_info;
+
+ cdf_mem_set(&roam_info, sizeof(roam_info), 0);
+ sms_log(mac_ctx, LOG1, FL("DEAUTHENTICATION Indication from MAC"));
+ pDeauthInd = (tpSirSmeDeauthInd) msg_ptr;
+ status = csr_roam_get_session_id_from_bssid(mac_ctx,
+ (struct cdf_mac_addr *) pDeauthInd->
+ bssId, &sessionId);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ return;
+ /* If we are in neighbor preauth done state then on receiving
+ * disassoc or deauth we dont roam instead we just disassoc
+ * from current ap and then go to disconnected state
+ * This happens for ESE and 11r FT connections ONLY.
+ */
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ if (csr_roam_is11r_assoc(mac_ctx, sessionId) &&
+ (csr_neighbor_roam_state_preauth_done(mac_ctx, sessionId)))
+ csr_neighbor_roam_tranistion_preauth_done_to_disconnected(
+ mac_ctx, sessionId);
+#endif
+#ifdef FEATURE_WLAN_ESE
+ if (csr_roam_is_ese_assoc(mac_ctx, sessionId) &&
+ (csr_neighbor_roam_state_preauth_done(mac_ctx, sessionId)))
+ csr_neighbor_roam_tranistion_preauth_done_to_disconnected(
+ mac_ctx, sessionId);
+#endif
+#ifdef FEATURE_WLAN_LFR
+ if (csr_roam_is_fast_roam_enabled(mac_ctx, sessionId) &&
+ (csr_neighbor_roam_state_preauth_done(mac_ctx, sessionId)))
+ csr_neighbor_roam_tranistion_preauth_done_to_disconnected(
+ mac_ctx, sessionId);
+#endif
+ session = CSR_GET_SESSION(mac_ctx, sessionId);
+ if (!session) {
+ sms_log(mac_ctx, LOGE, FL("session %d not found"), sessionId);
+ return;
+ }
+
+ if (csr_is_conn_state_infra(mac_ctx, sessionId))
+ session->connectState = eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED;
+#ifndef WLAN_MDM_CODE_REDUCTION_OPT
+ sme_qos_csr_event_ind(mac_ctx, (uint8_t) sessionId,
+ SME_QOS_CSR_DISCONNECT_IND, NULL);
+#endif
+ csr_roam_link_down(mac_ctx, sessionId);
+ csr_roam_issue_wm_status_change(mac_ctx, sessionId,
+ eCsrDeauthenticated,
+ msg_ptr);
+ if (CSR_IS_INFRA_AP(&session->connectedProfile)) {
+ roam_info_ptr = &roam_info;
+ roam_info_ptr->statusCode = pDeauthInd->statusCode;
+ roam_info_ptr->reasonCode = pDeauthInd->reasonCode;
+ roam_info_ptr->u.pConnectedProfile = &session->connectedProfile;
+ roam_info_ptr->staId = (uint8_t) pDeauthInd->staId;
+ cdf_mem_copy(roam_info_ptr->peerMac.bytes,
+ pDeauthInd->peerMacAddr,
+ sizeof(tSirMacAddr));
+ cdf_mem_copy(&roam_info_ptr->bssid.bytes,
+ pDeauthInd->bssId,
+ sizeof(struct cdf_mac_addr));
+ status = csr_roam_call_callback(mac_ctx, sessionId,
+ roam_info_ptr, 0,
+ eCSR_ROAM_INFRA_IND,
+ eCSR_ROAM_RESULT_DEAUTH_IND);
+ }
+}
+
+static void
+csr_roam_chk_lnk_swt_ch_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr)
+{
+ tCsrRoamSession *session;
+ uint32_t sessionId = CSR_SESSION_ID_INVALID;
+ CDF_STATUS status;
+ tpSirSmeSwitchChannelInd pSwitchChnInd;
+
+ /* in case of STA, the SWITCH_CHANNEL originates from its AP */
+ sms_log(mac_ctx, LOGW, FL("eWNI_SME_SWITCH_CHL_IND from SME"));
+ pSwitchChnInd = (tpSirSmeSwitchChannelInd) msg_ptr;
+ /* Update with the new channel id. The channel id is hidden in the
+ * statusCode.
+ */
+ status = csr_roam_get_session_id_from_bssid(mac_ctx,
+ (struct cdf_mac_addr *) pSwitchChnInd->bssId, &sessionId);
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ session = CSR_GET_SESSION(mac_ctx, sessionId);
+ if (!session) {
+ sms_log(mac_ctx, LOGE,
+ FL("session %d not found"), sessionId);
+ return;
+ }
+ session->connectedProfile.operationChannel =
+ (uint8_t) pSwitchChnInd->newChannelId;
+ if (session->pConnectBssDesc) {
+ session->pConnectBssDesc->channelId =
+ (uint8_t) pSwitchChnInd->newChannelId;
+ }
+ }
+}
+
+static void
+csr_roam_chk_lnk_deauth_rsp(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr)
+{
+ tCsrRoamSession *session;
+ uint32_t sessionId = CSR_SESSION_ID_INVALID;
+ CDF_STATUS status;
+ tCsrRoamInfo *roam_info_ptr = NULL;
+ tSirSmeDeauthRsp *pDeauthRsp = (tSirSmeDeauthRsp *) msg_ptr;
+ tCsrRoamInfo roam_info;
+
+ cdf_mem_set(&roam_info, sizeof(roam_info), 0);
+ sms_log(mac_ctx, LOGW, FL("eWNI_SME_DEAUTH_RSP from SME"));
+ sessionId = pDeauthRsp->sessionId;
+ if (!CSR_IS_SESSION_VALID(mac_ctx, sessionId))
+ return;
+ session = CSR_GET_SESSION(mac_ctx, sessionId);
+ if (CSR_IS_INFRA_AP(&session->connectedProfile)) {
+ roam_info_ptr = &roam_info;
+ roam_info_ptr->u.pConnectedProfile = &session->connectedProfile;
+ cdf_mem_copy(roam_info_ptr->peerMac.bytes,
+ pDeauthRsp->peerMacAddr,
+ sizeof(tSirMacAddr));
+ roam_info_ptr->reasonCode = eCSR_ROAM_RESULT_FORCED;
+ roam_info_ptr->statusCode = pDeauthRsp->statusCode;
+ status = csr_roam_call_callback(mac_ctx, sessionId,
+ roam_info_ptr, 0,
+ eCSR_ROAM_LOSTLINK,
+ eCSR_ROAM_RESULT_FORCED);
+ }
+}
+
+static void
+csr_roam_chk_lnk_disassoc_rsp(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr)
+{
+ tCsrRoamSession *session;
+ uint32_t sessionId = CSR_SESSION_ID_INVALID;
+ CDF_STATUS status;
+ tCsrRoamInfo *roam_info_ptr = NULL;
+ tCsrRoamInfo roam_info;
+ /*
+ * session id is invalid here so cant use it to access the array
+ * curSubstate as index
+ */
+ tSirSmeDisassocRsp *pDisassocRsp = (tSirSmeDisassocRsp *) msg_ptr;
+
+ cdf_mem_set(&roam_info, sizeof(roam_info), 0);
+ sms_log(mac_ctx, LOGW, FL("eWNI_SME_DISASSOC_RSP from SME "));
+ sessionId = pDisassocRsp->sessionId;
+ if (!CSR_IS_SESSION_VALID(mac_ctx, sessionId))
+ return;
+ session = CSR_GET_SESSION(mac_ctx, sessionId);
+ if (CSR_IS_INFRA_AP(&session->connectedProfile)) {
+ roam_info_ptr = &roam_info;
+ roam_info_ptr->u.pConnectedProfile = &session->connectedProfile;
+ cdf_mem_copy(roam_info_ptr->peerMac.bytes,
+ pDisassocRsp->peerMacAddr,
+ sizeof(tSirMacAddr));
+ roam_info_ptr->reasonCode = eCSR_ROAM_RESULT_FORCED;
+ roam_info_ptr->statusCode = pDisassocRsp->statusCode;
+ status = csr_roam_call_callback(mac_ctx, sessionId,
+ roam_info_ptr, 0,
+ eCSR_ROAM_LOSTLINK,
+ eCSR_ROAM_RESULT_FORCED);
+ }
+}
+
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+static void
+csr_roam_diag_mic_fail(tpAniSirGlobal mac_ctx, uint32_t sessionId)
+{
+ WLAN_HOST_DIAG_EVENT_DEF(secEvent,
+ host_event_wlan_security_payload_type);
+ tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, sessionId);
+ if (!session) {
+ sms_log(mac_ctx, LOGE, FL("session %d not found"), sessionId);
+ return;
+ }
+ cdf_mem_set(&secEvent, sizeof(host_event_wlan_security_payload_type),
+ 0);
+ secEvent.eventId = WLAN_SECURITY_EVENT_MIC_ERROR;
+ secEvent.encryptionModeMulticast =
+ (uint8_t) diag_enc_type_from_csr_type(
+ session->connectedProfile.mcEncryptionType);
+ secEvent.encryptionModeUnicast =
+ (uint8_t) diag_enc_type_from_csr_type(
+ session->connectedProfile.EncryptionType);
+ secEvent.authMode =
+ (uint8_t) diag_auth_type_from_csr_type(
+ session->connectedProfile.AuthType);
+ cdf_mem_copy(secEvent.bssid, session->connectedProfile.bssid.bytes,
+ CDF_MAC_ADDR_SIZE);
+ WLAN_HOST_DIAG_EVENT_REPORT(&secEvent, EVENT_WLAN_SECURITY);
+}
+#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */
+
+static void
+csr_roam_chk_lnk_mic_fail_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr)
+{
+ uint32_t sessionId = CSR_SESSION_ID_INVALID;
+ CDF_STATUS status;
+ tCsrRoamInfo *roam_info_ptr = NULL;
+ tCsrRoamInfo roam_info;
+ tpSirSmeMicFailureInd pMicInd = (tpSirSmeMicFailureInd) msg_ptr;
+ eCsrRoamResult result = eCSR_ROAM_RESULT_MIC_ERROR_UNICAST;
+
+ cdf_mem_set(&roam_info, sizeof(roam_info), 0);
+ status = csr_roam_get_session_id_from_bssid(mac_ctx,
+ (struct cdf_mac_addr *) pMicInd->bssId, &sessionId);
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ cdf_mem_set(&roam_info, sizeof(tCsrRoamInfo), 0);
+ roam_info.u.pMICFailureInfo = &pMicInd->info;
+ roam_info_ptr = &roam_info;
+ if (pMicInd->info.multicast)
+ result = eCSR_ROAM_RESULT_MIC_ERROR_GROUP;
+ else
+ result = eCSR_ROAM_RESULT_MIC_ERROR_UNICAST;
+ csr_roam_call_callback(mac_ctx, sessionId, roam_info_ptr, 0,
+ eCSR_ROAM_MIC_ERROR_IND, result);
+ }
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+ csr_roam_diag_mic_fail(mac_ctx, sessionId);
+#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */
+}
+
+static void
+csr_roam_chk_lnk_pbs_probe_req_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr)
+{
+ uint32_t sessionId = CSR_SESSION_ID_INVALID;
+ CDF_STATUS status;
+ tCsrRoamInfo roam_info;
+ tpSirSmeProbeReqInd pProbeReqInd = (tpSirSmeProbeReqInd) msg_ptr;
+
+ cdf_mem_set(&roam_info, sizeof(roam_info), 0);
+ sms_log(mac_ctx, LOG1, FL("WPS PBC Probe request Indication from SME"));
+
+ status = csr_roam_get_session_id_from_bssid(mac_ctx,
+ (struct cdf_mac_addr *)pProbeReqInd->bssId, &sessionId);
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ cdf_mem_set(&roam_info, sizeof(tCsrRoamInfo), 0);
+ roam_info.u.pWPSPBCProbeReq = &pProbeReqInd->WPSPBCProbeReq;
+ csr_roam_call_callback(mac_ctx, sessionId, &roam_info,
+ 0, eCSR_ROAM_WPS_PBC_PROBE_REQ_IND,
+ eCSR_ROAM_RESULT_WPS_PBC_PROBE_REQ_IND);
+ }
+}
+
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+static void
+csr_roam_diag_joined_new_bss(tpAniSirGlobal mac_ctx,
+ tSirSmeNewBssInfo *pNewBss)
+{
+ host_log_ibss_pkt_type *pIbssLog;
+ uint32_t bi;
+ WLAN_HOST_DIAG_LOG_ALLOC(pIbssLog, host_log_ibss_pkt_type,
+ LOG_WLAN_IBSS_C);
+ if (!pIbssLog)
+ return;
+ pIbssLog->eventId = WLAN_IBSS_EVENT_COALESCING;
+ if (pNewBss) {
+ cdf_mem_copy(pIbssLog->bssid, pNewBss->bssId, 6);
+ if (pNewBss->ssId.length)
+ cdf_mem_copy(pIbssLog->ssid, pNewBss->ssId.ssId,
+ pNewBss->ssId.length);
+ pIbssLog->operatingChannel = pNewBss->channelNumber;
+ }
+ if (IS_SIR_STATUS_SUCCESS(wlan_cfg_get_int(mac_ctx,
+ WNI_CFG_BEACON_INTERVAL,
+ &bi)))
+ /* U8 is not enough for beacon interval */
+ pIbssLog->beaconInterval = (uint8_t) bi;
+ WLAN_HOST_DIAG_LOG_REPORT(pIbssLog);
+}
+#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */
+
+static void
+csr_roam_chk_lnk_wm_status_change_ntf(tpAniSirGlobal mac_ctx,
+ tSirSmeRsp *msg_ptr)
+{
+ tCsrRoamSession *session;
+ uint32_t sessionId = CSR_SESSION_ID_INVALID;
+ CDF_STATUS status;
+ tCsrRoamInfo *roam_info_ptr = NULL;
+ tSirSmeWmStatusChangeNtf *pStatusChangeMsg;
+ tCsrRoamInfo roam_info;
+ tSirSmeApNewCaps *pApNewCaps;
+ eCsrRoamResult result = eCSR_ROAM_RESULT_NONE;
+ tSirMacAddr Broadcastaddr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+ tSirSmeNewBssInfo *pNewBss;
+ eRoamCmdStatus roamStatus = eCSR_ROAM_FAILED;
+
+ cdf_mem_set(&roam_info, sizeof(roam_info), 0);
+ pStatusChangeMsg = (tSirSmeWmStatusChangeNtf *) msg_ptr;
+ switch (pStatusChangeMsg->statusChangeCode) {
+ case eSIR_SME_IBSS_ACTIVE:
+ sessionId = csr_find_ibss_session(mac_ctx);
+ if (CSR_SESSION_ID_INVALID == sessionId)
+ break;
+ session = CSR_GET_SESSION(mac_ctx, sessionId);
+ if (!session) {
+ sms_log(mac_ctx, LOGE, FL("session %d not found"),
+ sessionId);
+ return;
+ }
+ session->connectState = eCSR_ASSOC_STATE_TYPE_IBSS_CONNECTED;
+ if (session->pConnectBssDesc) {
+ cdf_mem_copy(&roam_info.bssid,
+ session->pConnectBssDesc->bssId,
+ sizeof(struct cdf_mac_addr));
+ roam_info.u.pConnectedProfile =
+ &session->connectedProfile;
+ roam_info_ptr = &roam_info;
+ } else {
+ sms_log(mac_ctx, LOGE,
+ FL("CSR: connected BSS is empty"));
+ }
+ result = eCSR_ROAM_RESULT_IBSS_CONNECT;
+ roamStatus = eCSR_ROAM_CONNECT_STATUS_UPDATE;
+ break;
+
+ case eSIR_SME_IBSS_INACTIVE:
+ sessionId = csr_find_ibss_session(mac_ctx);
+ if (CSR_SESSION_ID_INVALID != sessionId) {
+ session = CSR_GET_SESSION(mac_ctx, sessionId);
+ if (!session) {
+ sms_log(mac_ctx, LOGE,
+ FL("session %d not found"), sessionId);
+ return;
+ }
+ session->connectState =
+ eCSR_ASSOC_STATE_TYPE_IBSS_DISCONNECTED;
+ result = eCSR_ROAM_RESULT_IBSS_INACTIVE;
+ roamStatus = eCSR_ROAM_CONNECT_STATUS_UPDATE;
+ }
+ break;
+
+ case eSIR_SME_JOINED_NEW_BSS:
+ /* IBSS coalescing. */
+ sms_log(mac_ctx, LOGW,
+ FL("CSR: eSIR_SME_JOINED_NEW_BSS received from PE"));
+ sessionId = csr_find_ibss_session(mac_ctx);
+ if (CSR_SESSION_ID_INVALID == sessionId)
+ break;
+ session = CSR_GET_SESSION(mac_ctx, sessionId);
+ if (!session) {
+ sms_log(mac_ctx, LOGE, FL("session %d not found"),
+ sessionId);
+ return;
+ }
+ /* update the connection state information */
+ pNewBss = &pStatusChangeMsg->statusChangeInfo.newBssInfo;
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+ csr_roam_diag_joined_new_bss(mac_ctx, pNewBss);
+#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */
+ csr_roam_update_connected_profile_from_new_bss(mac_ctx,
+ sessionId,
+ pNewBss);
+
+ if ((eCSR_ENCRYPT_TYPE_NONE ==
+ session->connectedProfile.EncryptionType)) {
+ csr_roam_issue_set_context_req(mac_ctx,
+ sessionId,
+ session->connectedProfile.EncryptionType,
+ session->pConnectBssDesc,
+ &Broadcastaddr, false, false,
+ eSIR_TX_RX, 0, 0, NULL, 0);
+ }
+ result = eCSR_ROAM_RESULT_IBSS_COALESCED;
+ roamStatus = eCSR_ROAM_IBSS_IND;
+ cdf_mem_copy(&roam_info.bssid, &pNewBss->bssId,
+ sizeof(struct cdf_mac_addr));
+ roam_info_ptr = &roam_info;
+ /* This BSSID is the real BSSID, save it */
+ if (session->pConnectBssDesc)
+ cdf_mem_copy(session->pConnectBssDesc->bssId,
+ &pNewBss->bssId, sizeof(struct cdf_mac_addr));
+ break;
+
+ /*
+ * detection by LIM that the capabilities of the associated
+ * AP have changed.
+ */
+ case eSIR_SME_AP_CAPS_CHANGED:
+ pApNewCaps = &pStatusChangeMsg->statusChangeInfo.apNewCaps;
+ sms_log(mac_ctx, LOGW,
+ FL("CSR handling eSIR_SME_AP_CAPS_CHANGED"));
+ status = csr_roam_get_session_id_from_bssid(mac_ctx,
+ (struct cdf_mac_addr *)pApNewCaps->bssId, &sessionId);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ break;
+ if (eCSR_ROAMING_STATE_JOINED ==
+ mac_ctx->roam.curState[sessionId]
+ && ((eCSR_ROAM_SUBSTATE_JOINED_REALTIME_TRAFFIC
+ == mac_ctx->roam.curSubState[sessionId])
+ || (eCSR_ROAM_SUBSTATE_NONE ==
+ mac_ctx->roam.curSubState[sessionId])
+ || (eCSR_ROAM_SUBSTATE_JOINED_NON_REALTIME_TRAFFIC
+ == mac_ctx->roam.curSubState[sessionId])
+ || (eCSR_ROAM_SUBSTATE_JOINED_NO_TRAFFIC ==
+ mac_ctx->roam.curSubState[sessionId]))) {
+ sms_log(mac_ctx, LOGW,
+ FL("Calling csr_roam_disconnect_internal"));
+ csr_roam_disconnect_internal(mac_ctx, sessionId,
+ eCSR_DISCONNECT_REASON_UNSPECIFIED);
+ } else {
+ sms_log(mac_ctx, LOGW,
+ FL("Skipping the new scan as CSR is in state %s and sub-state %s"),
+ mac_trace_getcsr_roam_state(
+ mac_ctx->roam.curState[sessionId]),
+ mac_trace_getcsr_roam_sub_state(
+ mac_ctx->roam.curSubState[sessionId]));
+ /* We ignore the caps change event if CSR is not in full
+ * connected state. Send one event to PE to reset
+ * limSentCapsChangeNtf Once limSentCapsChangeNtf set
+ * 0, lim can send sub sequent CAPS change event
+ * otherwise lim cannot send any CAPS change events to
+ * SME
+ */
+ csr_send_reset_ap_caps_changed(mac_ctx,
+ &pApNewCaps->bssId);
+ }
+ break;
+
+ default:
+ roamStatus = eCSR_ROAM_FAILED;
+ result = eCSR_ROAM_RESULT_NONE;
+ break;
+ } /* end switch on statusChangeCode */
+ if (eCSR_ROAM_RESULT_NONE != result) {
+ csr_roam_call_callback(mac_ctx, sessionId, roam_info_ptr, 0,
+ roamStatus, result);
+ }
+}
+
+static void
+csr_roam_chk_lnk_ibss_new_peer_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr)
+{
+ tCsrRoamSession *session;
+ uint32_t sessionId = CSR_SESSION_ID_INVALID;
+ CDF_STATUS status;
+ tCsrRoamInfo *roam_info_ptr = NULL;
+ tSmeIbssPeerInd *pIbssPeerInd = (tSmeIbssPeerInd *) msg_ptr;
+ tCsrRoamInfo roam_info;
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+ host_log_ibss_pkt_type *pIbssLog;
+ WLAN_HOST_DIAG_LOG_ALLOC(pIbssLog, host_log_ibss_pkt_type,
+ LOG_WLAN_IBSS_C);
+ if (pIbssLog) {
+ pIbssLog->eventId = WLAN_IBSS_EVENT_PEER_JOIN;
+ cdf_mem_copy(pIbssLog->peerMacAddr, &pIbssPeerInd->peerAddr, 6);
+ WLAN_HOST_DIAG_LOG_REPORT(pIbssLog);
+ }
+#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */
+
+ cdf_mem_set(&roam_info, sizeof(roam_info), 0);
+ sessionId = csr_find_ibss_session(mac_ctx);
+ if (CSR_SESSION_ID_INVALID == sessionId)
+ return;
+ session = CSR_GET_SESSION(mac_ctx, sessionId);
+ if (!session) {
+ sms_log(mac_ctx, LOGE, FL("session %d not found"), sessionId);
+ return;
+ }
+ /*
+ * Issue the set Context request to LIM to establish the Unicast STA
+ * context for the new peer...
+ */
+ if (!session->pConnectBssDesc) {
+ sms_log(mac_ctx, LOGW, FL("CSR: connected BSS is empty"));
+ goto callback_and_free;
+ }
+ cdf_mem_copy(&roam_info.peerMac, pIbssPeerInd->peerAddr,
+ sizeof(struct cdf_mac_addr));
+ cdf_mem_copy(&roam_info.bssid, session->pConnectBssDesc->bssId,
+ sizeof(struct cdf_mac_addr));
+ if (pIbssPeerInd->mesgLen > sizeof(tSmeIbssPeerInd)) {
+ roam_info.pbFrames = cdf_mem_malloc((pIbssPeerInd->mesgLen -
+ sizeof(tSmeIbssPeerInd)));
+ if (NULL == roam_info.pbFrames) {
+ status = CDF_STATUS_E_NOMEM;
+ } else {
+ status = CDF_STATUS_SUCCESS;
+ roam_info.nBeaconLength = pIbssPeerInd->mesgLen -
+ sizeof(tSmeIbssPeerInd);
+ cdf_mem_copy(roam_info.pbFrames,
+ ((uint8_t *) pIbssPeerInd) +
+ sizeof(tSmeIbssPeerInd),
+ roam_info.nBeaconLength);
+ }
+ roam_info.staId = (uint8_t) pIbssPeerInd->staId;
+ roam_info.ucastSig = (uint8_t) pIbssPeerInd->ucastSig;
+ roam_info.bcastSig = (uint8_t) pIbssPeerInd->bcastSig;
+ roam_info.pBssDesc = cdf_mem_malloc(
+ session->pConnectBssDesc->length);
+ if (NULL == roam_info.pBssDesc) {
+ status = CDF_STATUS_E_NOMEM;
+ if (roam_info.pbFrames)
+ cdf_mem_free(roam_info.pbFrames);
+ if (roam_info.pBssDesc)
+ cdf_mem_free(roam_info.pBssDesc);
+ } else {
+ status = CDF_STATUS_SUCCESS;
+ cdf_mem_copy(roam_info.pBssDesc,
+ session->pConnectBssDesc,
+ session->pConnectBssDesc->length);
+ roam_info_ptr = &roam_info;
+ }
+ } else {
+ roam_info_ptr = &roam_info;
+ }
+ if ((eCSR_ENCRYPT_TYPE_NONE ==
+ session->connectedProfile.EncryptionType)) {
+ /* NO keys. these key parameters don't matter */
+ csr_roam_issue_set_context_req(mac_ctx, sessionId,
+ session->connectedProfile.EncryptionType,
+ session->pConnectBssDesc, &(pIbssPeerInd->peerAddr),
+ false, true, eSIR_TX_RX, 0, 0, NULL, 0);
+ }
+
+callback_and_free:
+ /* send up the sec type for the new peer */
+ if (roam_info_ptr)
+ roam_info_ptr->u.pConnectedProfile = &session->connectedProfile;
+ csr_roam_call_callback(mac_ctx, sessionId, roam_info_ptr, 0,
+ eCSR_ROAM_CONNECT_STATUS_UPDATE,
+ eCSR_ROAM_RESULT_IBSS_NEW_PEER);
+ if (roam_info_ptr) {
+ if (roam_info.pbFrames)
+ cdf_mem_free(roam_info.pbFrames);
+ if (roam_info.pBssDesc)
+ cdf_mem_free(roam_info.pBssDesc);
+ }
+}
+
+static void
+csr_roam_chk_lnk_ibss_peer_departed_ind(tpAniSirGlobal mac_ctx,
+ tSirSmeRsp *msg_ptr)
+{
+ uint32_t sessionId = CSR_SESSION_ID_INVALID;
+ tCsrRoamInfo roam_info;
+ tSmeIbssPeerInd *pIbssPeerInd;
+
+ if (NULL == msg_ptr) {
+ sms_log(mac_ctx, LOGE, FL("IBSS peer ind. message is NULL"));
+ return;
+ }
+ cdf_mem_set(&roam_info, sizeof(roam_info), 0);
+ pIbssPeerInd = (tSmeIbssPeerInd *) msg_ptr;
+ sessionId = csr_find_ibss_session(mac_ctx);
+ if (CSR_SESSION_ID_INVALID != sessionId) {
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+ host_log_ibss_pkt_type *pIbssLog;
+ WLAN_HOST_DIAG_LOG_ALLOC(pIbssLog, host_log_ibss_pkt_type,
+ LOG_WLAN_IBSS_C);
+ if (pIbssLog) {
+ pIbssLog->eventId = WLAN_IBSS_EVENT_PEER_LEAVE;
+ if (pIbssPeerInd) {
+ cdf_mem_copy(pIbssLog->peerMacAddr,
+ &pIbssPeerInd->peerAddr, 6);
+ }
+ WLAN_HOST_DIAG_LOG_REPORT(pIbssLog);
+ }
+#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */
+ sms_log(mac_ctx, LOGW,
+ FL("CSR: Peer departed notification from LIM"));
+ roam_info.staId = (uint8_t) pIbssPeerInd->staId;
+ roam_info.ucastSig = (uint8_t) pIbssPeerInd->ucastSig;
+ roam_info.bcastSig = (uint8_t) pIbssPeerInd->bcastSig;
+ cdf_mem_copy(&roam_info.peerMac, pIbssPeerInd->peerAddr,
+ sizeof(struct cdf_mac_addr));
+ csr_roam_call_callback(mac_ctx, sessionId, &roam_info, 0,
+ eCSR_ROAM_CONNECT_STATUS_UPDATE,
+ eCSR_ROAM_RESULT_IBSS_PEER_DEPARTED);
+ }
+}
+
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+static void
+csr_roam_diag_set_ctx_rsp(tpAniSirGlobal mac_ctx,
+ tCsrRoamSession *session,
+ tSirSmeSetContextRsp *pRsp)
+{
+ WLAN_HOST_DIAG_EVENT_DEF(setKeyEvent,
+ host_event_wlan_security_payload_type);
+ if (eCSR_ENCRYPT_TYPE_NONE ==
+ session->connectedProfile.EncryptionType)
+ return;
+ cdf_mem_set(&setKeyEvent,
+ sizeof(host_event_wlan_security_payload_type), 0);
+ if (pRsp->peerMacAddr[0] & 0x01)
+ setKeyEvent.eventId = WLAN_SECURITY_EVENT_SET_GTK_RSP;
+ else
+ setKeyEvent.eventId = WLAN_SECURITY_EVENT_SET_PTK_RSP;
+ setKeyEvent.encryptionModeMulticast =
+ (uint8_t) diag_enc_type_from_csr_type(
+ session->connectedProfile.mcEncryptionType);
+ setKeyEvent.encryptionModeUnicast =
+ (uint8_t) diag_enc_type_from_csr_type(
+ session->connectedProfile.EncryptionType);
+ cdf_mem_copy(setKeyEvent.bssid, session->connectedProfile.bssid.bytes,
+ CDF_MAC_ADDR_SIZE);
+ setKeyEvent.authMode =
+ (uint8_t) diag_auth_type_from_csr_type(
+ session->connectedProfile.AuthType);
+ if (eSIR_SME_SUCCESS != pRsp->statusCode)
+ setKeyEvent.status = WLAN_SECURITY_STATUS_FAILURE;
+ WLAN_HOST_DIAG_EVENT_REPORT(&setKeyEvent, EVENT_WLAN_SECURITY);
+}
+#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */
+
+static void
+csr_roam_chk_lnk_set_ctx_rsp(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr)
+{
+ tCsrRoamSession *session;
+ uint32_t sessionId = CSR_SESSION_ID_INVALID;
+ CDF_STATUS status;
+ tCsrRoamInfo *roam_info_ptr = NULL;
+ tSmeCmd *cmd;
+ tCsrRoamInfo roam_info;
+ eCsrRoamResult result = eCSR_ROAM_RESULT_NONE;
+ tSirSmeSetContextRsp *pRsp = (tSirSmeSetContextRsp *) msg_ptr;
+ tListElem *entry;
+ tSirMacAddr Broadcastaddr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+
+ cdf_mem_set(&roam_info, sizeof(roam_info), 0);
+ entry = csr_ll_peek_head(&mac_ctx->sme.smeCmdActiveList,
+ LL_ACCESS_LOCK);
+ if (!entry) {
+ sms_log(mac_ctx, LOGE, FL("CSR: NO commands are ACTIVE ..."));
+ goto process_pending_n_exit;
+ }
+
+ cmd = GET_BASE_ADDR(entry, tSmeCmd, Link);
+ if (eSmeCommandSetKey != cmd->command) {
+ sms_log(mac_ctx, LOGE, FL("CSR: setkey cmd is not ACTIVE ..."));
+ goto process_pending_n_exit;
+ }
+ sessionId = cmd->sessionId;
+ session = CSR_GET_SESSION(mac_ctx, sessionId);
+ if (!session) {
+ sms_log(mac_ctx, LOGE, FL("session %d not found"), sessionId);
+ return;
+ }
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+ csr_roam_diag_set_ctx_rsp(mac_ctx, session, pRsp);
+#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */
+ if (CSR_IS_WAIT_FOR_KEY(mac_ctx, sessionId)) {
+ csr_roam_stop_wait_for_key_timer(mac_ctx);
+ /* We are done with authentication, whethere succeed or not */
+ csr_roam_substate_change(mac_ctx, eCSR_ROAM_SUBSTATE_NONE,
+ sessionId);
+ /* We do it here because this linkup function is not called
+ * after association when a key needs to be set.
+ */
+ if (csr_is_conn_state_connected_infra(mac_ctx, sessionId))
+ csr_roam_link_up(mac_ctx,
+ session->connectedProfile.bssid);
+ }
+ if (eSIR_SME_SUCCESS == pRsp->statusCode) {
+ cdf_mem_copy(&roam_info.peerMac, &pRsp->peerMacAddr,
+ sizeof(struct cdf_mac_addr));
+ /* Make sure we install the GTK before indicating to HDD as
+ * authenticated. This is to prevent broadcast packets go out
+ * after PTK and before GTK.
+ */
+ if (cdf_mem_compare(&Broadcastaddr, pRsp->peerMacAddr,
+ sizeof(tSirMacAddr))) {
+ tpSirSetActiveModeSetBncFilterReq pMsg;
+ pMsg = cdf_mem_malloc(
+ sizeof(tSirSetActiveModeSetBncFilterReq));
+ pMsg->messageType = eWNI_SME_SET_BCN_FILTER_REQ;
+ pMsg->length = sizeof(uint8_t);
+ pMsg->seesionId = sessionId;
+ status = cds_send_mb_message_to_mac(pMsg);
+ result = eCSR_ROAM_RESULT_AUTHENTICATED;
+ } else {
+ result = eCSR_ROAM_RESULT_NONE;
+ }
+ roam_info_ptr = &roam_info;
+ } else {
+ result = eCSR_ROAM_RESULT_FAILURE;
+ sms_log(mac_ctx, LOGE,
+ FL("CSR: setkey command failed(%d) PeerMac "
+ MAC_ADDRESS_STR),
+ pRsp->statusCode, MAC_ADDR_ARRAY(pRsp->peerMacAddr));
+ }
+ csr_roam_call_callback(mac_ctx, sessionId, &roam_info,
+ cmd->u.setKeyCmd.roamId,
+ eCSR_ROAM_SET_KEY_COMPLETE, result);
+ /* Indicate SME_QOS that the SET_KEY is completed, so that SME_QOS
+ * can go ahead and initiate the TSPEC if any are pending
+ */
+ sme_qos_csr_event_ind(mac_ctx, (uint8_t) sessionId,
+ SME_QOS_CSR_SET_KEY_SUCCESS_IND, NULL);
+#ifdef FEATURE_WLAN_ESE
+ /* Send Adjacent AP repot to new AP. */
+ if (result == eCSR_ROAM_RESULT_AUTHENTICATED
+ && session->isPrevApInfoValid
+ && session->connectedProfile.isESEAssoc) {
+#ifdef FEATURE_WLAN_ESE_UPLOAD
+ csr_send_ese_adjacent_ap_rep_ind(mac_ctx, session);
+#else
+ csr_ese_send_adjacent_ap_rep_msg(mac_ctx, session);
+#endif
+ session->isPrevApInfoValid = false;
+ }
+#endif
+ if (csr_ll_remove_entry(&mac_ctx->sme.smeCmdActiveList, entry,
+ LL_ACCESS_LOCK))
+ csr_release_command_set_key(mac_ctx, cmd);
+
+process_pending_n_exit:
+ sme_process_pending_queue(mac_ctx);
+}
+
+
+static void
+csr_roam_chk_lnk_max_assoc_exceeded(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr)
+{
+ uint32_t sessionId = CSR_SESSION_ID_INVALID;
+ tSmeMaxAssocInd *pSmeMaxAssocInd;
+ tCsrRoamInfo roam_info;
+
+ cdf_mem_set(&roam_info, sizeof(roam_info), 0);
+ pSmeMaxAssocInd = (tSmeMaxAssocInd *) msg_ptr;
+ sms_log(mac_ctx, LOG1,
+ FL("max assoc have been reached, new peer cannot be accepted"));
+ sessionId = pSmeMaxAssocInd->sessionId;
+ roam_info.sessionId = sessionId;
+ cdf_mem_copy(&roam_info.peerMac, pSmeMaxAssocInd->peerMac,
+ sizeof(struct cdf_mac_addr));
+ csr_roam_call_callback(mac_ctx, sessionId, &roam_info, 0,
+ eCSR_ROAM_INFRA_IND,
+ eCSR_ROAM_RESULT_MAX_ASSOC_EXCEEDED);
+}
+
+void csr_roam_check_for_link_status_change(tpAniSirGlobal pMac, tSirSmeRsp *pSirMsg)
+{
+ if (NULL == pSirMsg) {
+ sms_log(pMac, LOGE, FL("pSirMsg is NULL"));
+ return;
+ }
+ switch (pSirMsg->messageType) {
+ case eWNI_SME_ASSOC_IND:
+ csr_roam_chk_lnk_assoc_ind(pMac, pSirMsg);
+ break;
+ case eWNI_SME_DISASSOC_IND:
+ csr_roam_chk_lnk_disassoc_ind(pMac, pSirMsg);
+ break;
+ case eWNI_SME_DEAUTH_IND:
+ csr_roam_chk_lnk_deauth_ind(pMac, pSirMsg);
+ break;
+ case eWNI_SME_SWITCH_CHL_IND:
+ csr_roam_chk_lnk_swt_ch_ind(pMac, pSirMsg);
+ break;
+ case eWNI_SME_DEAUTH_RSP:
+ csr_roam_chk_lnk_deauth_rsp(pMac, pSirMsg);
+ break;
+ case eWNI_SME_DISASSOC_RSP:
+ csr_roam_chk_lnk_disassoc_rsp(pMac, pSirMsg);
+ break;
+ case eWNI_SME_MIC_FAILURE_IND:
+ csr_roam_chk_lnk_mic_fail_ind(pMac, pSirMsg);
+ break;
+ case eWNI_SME_WPS_PBC_PROBE_REQ_IND:
+ csr_roam_chk_lnk_pbs_probe_req_ind(pMac, pSirMsg);
+ break;
+ case eWNI_SME_WM_STATUS_CHANGE_NTF:
+ csr_roam_chk_lnk_wm_status_change_ntf(pMac, pSirMsg);
+ break;
+ case eWNI_SME_IBSS_NEW_PEER_IND:
+ csr_roam_chk_lnk_ibss_new_peer_ind(pMac, pSirMsg);
+ break;
+ case eWNI_SME_IBSS_PEER_DEPARTED_IND:
+ csr_roam_chk_lnk_ibss_peer_departed_ind(pMac, pSirMsg);
+ break;
+ case eWNI_SME_SETCONTEXT_RSP:
+ csr_roam_chk_lnk_set_ctx_rsp(pMac, pSirMsg);
+ break;
+ case eWNI_SME_GET_STATISTICS_RSP:
+ sms_log(pMac, LOG2, FL("Stats rsp from PE"));
+ csr_roam_stats_rsp_processor(pMac, pSirMsg);
+ break;
+#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD)
+ case eWNI_SME_GET_TSM_STATS_RSP:
+ sms_log(pMac, LOG2, FL("TSM Stats rsp from PE"));
+ csr_tsm_stats_rsp_processor(pMac, pSirMsg);
+ break;
+#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */
+ case eWNI_SME_GET_RSSI_REQ:
+ sms_log(pMac, LOG2, FL("GetRssiReq from self"));
+ csr_update_rssi(pMac, pSirMsg);
+ break;
+ case eWNI_SME_GET_SNR_REQ:
+ sms_log(pMac, LOG2, FL("GetSnrReq from self"));
+ csr_update_snr(pMac, pSirMsg);
+ break;
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ case eWNI_SME_FT_PRE_AUTH_RSP:
+ csr_roam_ft_pre_auth_rsp_processor(pMac, (tpSirFTPreAuthRsp) pSirMsg);
+ break;
+#endif
+ case eWNI_SME_MAX_ASSOC_EXCEEDED:
+ csr_roam_chk_lnk_max_assoc_exceeded(pMac, pSirMsg);
+ break;
+ case eWNI_SME_CANDIDATE_FOUND_IND:
+ sms_log(pMac, LOG2, FL("Candidate found indication from PE"));
+ csr_neighbor_roam_candidate_found_ind_hdlr(pMac, pSirMsg);
+ break;
+ case eWNI_SME_HANDOFF_REQ:
+ sms_log(pMac, LOG2, FL("Handoff Req from self"));
+ csr_neighbor_roam_handoff_req_hdlr(pMac, pSirMsg);
+ break;
+ default:
+ break;
+ } /* end switch on message type */
+}
+
+void csr_call_roaming_completion_callback(tpAniSirGlobal pMac,
+ tCsrRoamSession *pSession,
+ tCsrRoamInfo *pRoamInfo, uint32_t roamId,
+ eCsrRoamResult roamResult)
+{
+ if (pSession) {
+ if (pSession->bRefAssocStartCnt) {
+ pSession->bRefAssocStartCnt--;
+
+ if (0 != pSession->bRefAssocStartCnt) {
+ CDF_ASSERT(pSession->bRefAssocStartCnt == 0);
+ return;
+ }
+ /* Need to call association_completion because there is an assoc_start pending. */
+ csr_roam_call_callback(pMac, pSession->sessionId, NULL,
+ roamId,
+ eCSR_ROAM_ASSOCIATION_COMPLETION,
+ eCSR_ROAM_RESULT_FAILURE);
+ }
+ csr_roam_call_callback(pMac, pSession->sessionId, pRoamInfo,
+ roamId, eCSR_ROAM_ROAMING_COMPLETION,
+ roamResult);
+ } else {
+ sms_log(pMac, LOGW, FL(" pSession is NULL"));
+ }
+}
+
+CDF_STATUS csr_roam_start_roaming(tpAniSirGlobal pMac, uint32_t sessionId,
+ eCsrRoamingReason roamingReason)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ if (CSR_IS_LOSTLINK_ROAMING(roamingReason) &&
+ (false == pMac->roam.roamSession[sessionId].fCancelRoaming)) {
+ status = csr_scan_request_lost_link1(pMac, sessionId);
+ }
+ return status;
+}
+
+/* return a bool to indicate whether roaming completed or continue. */
+bool csr_roam_complete_roaming(tpAniSirGlobal pMac, uint32_t sessionId,
+ bool fForce, eCsrRoamResult roamResult)
+{
+ bool fCompleted = true;
+ uint32_t roamTime =
+ (uint32_t) (pMac->roam.configParam.nRoamingTime *
+ CDF_TICKS_PER_SECOND);
+ uint32_t curTime = (uint32_t) cdf_mc_timer_get_system_ticks();
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return false;
+ }
+ /* Check whether time is up */
+ if (pSession->fCancelRoaming || fForce ||
+ ((curTime - pSession->roamingStartTime) > roamTime) ||
+ eCsrReassocRoaming == pSession->roamingReason ||
+ eCsrDynamicRoaming == pSession->roamingReason) {
+ sms_log(pMac, LOGW, FL(" indicates roaming completion"));
+ if (pSession->fCancelRoaming
+ && CSR_IS_LOSTLINK_ROAMING(pSession->roamingReason)) {
+ /* roaming is cancelled, tell HDD to indicate disconnect */
+ /* Because LIM overload deauth_ind for both deauth frame and missed beacon */
+ /* we need to use this logic to detinguish it. For missed beacon, LIM set reason */
+ /* to be eSIR_BEACON_MISSED */
+ if (eSIR_BEACON_MISSED == pSession->roamingStatusCode) {
+ roamResult = eCSR_ROAM_RESULT_LOSTLINK;
+ } else if (eCsrLostlinkRoamingDisassoc ==
+ pSession->roamingReason) {
+ roamResult = eCSR_ROAM_RESULT_DISASSOC_IND;
+ } else if (eCsrLostlinkRoamingDeauth ==
+ pSession->roamingReason) {
+ roamResult = eCSR_ROAM_RESULT_DEAUTH_IND;
+ } else {
+ roamResult = eCSR_ROAM_RESULT_LOSTLINK;
+ }
+ }
+ csr_call_roaming_completion_callback(pMac, pSession, NULL, 0,
+ roamResult);
+ pSession->roamingReason = eCsrNotRoaming;
+ } else {
+ pSession->roamResult = roamResult;
+ if (!CDF_IS_STATUS_SUCCESS
+ (csr_roam_start_roaming_timer
+ (pMac, sessionId, CDF_MC_TIMER_TO_SEC_UNIT))) {
+ csr_call_roaming_completion_callback(pMac, pSession, NULL,
+ 0, roamResult);
+ pSession->roamingReason = eCsrNotRoaming;
+ } else {
+ fCompleted = false;
+ }
+ }
+ return fCompleted;
+}
+
+void csr_roam_cancel_roaming(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;
+ }
+
+ if (CSR_IS_ROAMING(pSession)) {
+ sms_log(pMac, LOGW, "Cancel roaming");
+ pSession->fCancelRoaming = true;
+ if (CSR_IS_ROAM_JOINING(pMac, sessionId)
+ && CSR_IS_ROAM_SUBSTATE_CONFIG(pMac, sessionId)) {
+ /* No need to do anything in here because the handler takes care of it */
+ } else {
+ eCsrRoamResult roamResult =
+ CSR_IS_LOSTLINK_ROAMING(pSession->
+ roamingReason) ?
+ eCSR_ROAM_RESULT_LOSTLINK : eCSR_ROAM_RESULT_NONE;
+ /* Roaming is stopped after here */
+ csr_roam_complete_roaming(pMac, sessionId, true,
+ roamResult);
+ /* Since CSR may be in lostlink roaming situation, abort all roaming related activities */
+ csr_scan_abort_mac_scan(pMac, sessionId,
+ eCSR_SCAN_ABORT_DEFAULT);
+ csr_roam_stop_roaming_timer(pMac, sessionId);
+ }
+ }
+}
+
+void csr_roam_roaming_timer_handler(void *pv)
+{
+ tCsrTimerInfo *pInfo = (tCsrTimerInfo *) pv;
+ tpAniSirGlobal pMac = pInfo->pMac;
+ uint32_t sessionId = pInfo->sessionId;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return;
+ }
+
+ if (false == pSession->fCancelRoaming) {
+ if (!CDF_IS_STATUS_SUCCESS
+ (csr_roam_start_roaming
+ (pMac, sessionId, pSession->roamingReason))) {
+ csr_call_roaming_completion_callback(pMac, pSession, NULL,
+ 0,
+ pSession->roamResult);
+ pSession->roamingReason = eCsrNotRoaming;
+ }
+ }
+}
+
+CDF_STATUS csr_roam_start_roaming_timer(tpAniSirGlobal pMac, uint32_t sessionId,
+ uint32_t interval)
+{
+ CDF_STATUS status;
+ 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, " csrScanStartRoamingTimer");
+ pSession->roamingTimerInfo.sessionId = (uint8_t) sessionId;
+ status = cdf_mc_timer_start(&pSession->hTimerRoaming,
+ interval / CDF_MC_TIMER_TO_MS_UNIT);
+
+ return status;
+}
+
+CDF_STATUS csr_roam_stop_roaming_timer(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ return cdf_mc_timer_stop
+ (&pMac->roam.roamSession[sessionId].hTimerRoaming);
+}
+
+void csr_roam_wait_for_key_time_out_handler(void *pv)
+{
+ tCsrTimerInfo *pInfo = (tCsrTimerInfo *) pv;
+ tpAniSirGlobal pMac = pInfo->pMac;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, pInfo->sessionId);
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+
+ if (pSession == NULL) {
+ sms_log(pMac, LOGE, "%s: session not found", __func__);
+ return;
+ }
+
+ sms_log(pMac, LOGW,
+ FL("WaitForKey timer expired in state=%s sub-state=%s"),
+ mac_trace_get_neighbour_roam_state(pMac->roam.
+ neighborRoamInfo[pInfo->sessionId].
+ neighborRoamState),
+ mac_trace_getcsr_roam_sub_state(pMac->roam.
+ curSubState[pInfo->sessionId]));
+
+ if (CSR_IS_WAIT_FOR_KEY(pMac, pInfo->sessionId)) {
+#ifdef FEATURE_WLAN_LFR
+ if (csr_neighbor_roam_is_handoff_in_progress(pMac, pInfo->sessionId)) {
+ /*
+ * Enable heartbeat timer when hand-off is in progress
+ * and Key Wait timer expired.
+ */
+ sms_log(pMac, LOG2,
+ "Enabling HB timer after WaitKey expiry"
+ " (nHBCount=%d)",
+ pMac->roam.configParam.HeartbeatThresh24);
+ cfg_set_int(pMac, WNI_CFG_HEART_BEAT_THRESHOLD,
+ pMac->roam.configParam.HeartbeatThresh24);
+ }
+#endif
+ sms_log(pMac, LOGE, " SME pre-auth state timeout. ");
+
+ /* Change the substate so command queue is unblocked. */
+ if (CSR_ROAM_SESSION_MAX > pInfo->sessionId) {
+ csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_NONE,
+ pInfo->sessionId);
+ }
+
+ if (csr_is_conn_state_connected_infra(pMac, pInfo->sessionId)) {
+ csr_roam_link_up(pMac,
+ pSession->connectedProfile.bssid);
+ sme_process_pending_queue(pMac);
+ status = sme_acquire_global_lock(&pMac->sme);
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ csr_roam_disconnect(pMac, pInfo->sessionId,
+ eCSR_DISCONNECT_REASON_UNSPECIFIED);
+ sme_release_global_lock(&pMac->sme);
+ }
+ } else {
+ sms_log(pMac, LOGE, "%s: session not found", __func__);
+ }
+ }
+
+}
+
+CDF_STATUS csr_roam_start_wait_for_key_timer(tpAniSirGlobal pMac, uint32_t interval)
+{
+ CDF_STATUS status;
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[pMac->roam.WaitForKeyTimerInfo.
+ sessionId];
+#ifdef FEATURE_WLAN_LFR
+ if (csr_neighbor_roam_is_handoff_in_progress(pMac,
+ pMac->roam.WaitForKeyTimerInfo.
+ sessionId)) {
+ /* Disable heartbeat timer when hand-off is in progress */
+ sms_log(pMac, LOG2,
+ FL("disabling HB timer in state=%s sub-state=%s"),
+ mac_trace_get_neighbour_roam_state(pNeighborRoamInfo->
+ neighborRoamState),
+ mac_trace_getcsr_roam_sub_state(pMac->roam.
+ curSubState[pMac->roam.
+ WaitForKeyTimerInfo.
+ sessionId]
+ ));
+ cfg_set_int(pMac, WNI_CFG_HEART_BEAT_THRESHOLD, 0);
+ }
+#endif
+ sms_log(pMac, LOG1, " csrScanStartWaitForKeyTimer");
+ status = cdf_mc_timer_start(&pMac->roam.hTimerWaitForKey,
+ interval / CDF_MC_TIMER_TO_MS_UNIT);
+
+ return status;
+}
+
+CDF_STATUS csr_roam_stop_wait_for_key_timer(tpAniSirGlobal pMac)
+{
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[pMac->roam.WaitForKeyTimerInfo.
+ sessionId];
+
+ sms_log(pMac, LOG2,
+ FL("WaitForKey timer stopped in state=%s sub-state=%s"),
+ mac_trace_get_neighbour_roam_state(pNeighborRoamInfo->
+ neighborRoamState),
+ mac_trace_getcsr_roam_sub_state(pMac->roam.
+ curSubState[pMac->roam.
+ WaitForKeyTimerInfo.
+ sessionId]));
+#ifdef FEATURE_WLAN_LFR
+ if (csr_neighbor_roam_is_handoff_in_progress(pMac,
+ pMac->roam.WaitForKeyTimerInfo.
+ sessionId)) {
+ /*
+ * Enable heartbeat timer when hand-off is in progress
+ * and Key Wait timer got stopped for some reason
+ */
+ sms_log(pMac, LOG2, "Enabling HB timer after WaitKey stop"
+ " (nHBCount=%d)",
+ pMac->roam.configParam.HeartbeatThresh24);
+ cfg_set_int(pMac, WNI_CFG_HEART_BEAT_THRESHOLD,
+ pMac->roam.configParam.HeartbeatThresh24);
+ }
+#endif
+ return cdf_mc_timer_stop(&pMac->roam.hTimerWaitForKey);
+}
+
+void csr_roam_completion(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamInfo *pRoamInfo, tSmeCmd *pCommand,
+ eCsrRoamResult roamResult, bool fSuccess)
+{
+ eRoamCmdStatus roamStatus = csr_get_roam_complete_status(pMac, sessionId);
+ uint32_t roamId = 0;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return;
+ }
+
+ if (pCommand) {
+ roamId = pCommand->u.roamCmd.roamId;
+ if (sessionId != pCommand->sessionId) {
+ CDF_ASSERT(sessionId == pCommand->sessionId);
+ return;
+ }
+ }
+ if (eCSR_ROAM_ROAMING_COMPLETION == roamStatus) {
+ /* if success, force roaming completion */
+ csr_roam_complete_roaming(pMac, sessionId, fSuccess, roamResult);
+ } else {
+ if (pSession->bRefAssocStartCnt != 0) {
+ CDF_ASSERT(pSession->bRefAssocStartCnt == 0);
+ return;
+ }
+ sms_log(pMac, LOGW,
+ FL
+ (" indicates association completion. roamResult = %d"),
+ roamResult);
+ csr_roam_call_callback(pMac, sessionId, pRoamInfo, roamId,
+ roamStatus, roamResult);
+ }
+}
+
+CDF_STATUS csr_roam_lost_link(tpAniSirGlobal pMac, uint32_t sessionId,
+ uint32_t type, tSirSmeRsp *pSirMsg)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSirSmeDeauthInd *pDeauthIndMsg = NULL;
+ tSirSmeDisassocInd *pDisassocIndMsg = NULL;
+ eCsrRoamResult result = eCSR_ROAM_RESULT_LOSTLINK;
+ tCsrRoamInfo *pRoamInfo = NULL;
+ tCsrRoamInfo roamInfo;
+ bool fToRoam;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+ /* Only need to roam for infra station. In this case P2P client will roam as well */
+ fToRoam = CSR_IS_INFRASTRUCTURE(&pSession->connectedProfile);
+ pSession->fCancelRoaming = false;
+ if (eWNI_SME_DISASSOC_IND == type) {
+ result = eCSR_ROAM_RESULT_DISASSOC_IND;
+ pDisassocIndMsg = (tSirSmeDisassocInd *) pSirMsg;
+ pSession->roamingStatusCode = pDisassocIndMsg->statusCode;
+ pSession->joinFailStatusCode.reasonCode =
+ pDisassocIndMsg->reasonCode;
+ } else if (eWNI_SME_DEAUTH_IND == type) {
+ result = eCSR_ROAM_RESULT_DEAUTH_IND;
+ pDeauthIndMsg = (tSirSmeDeauthInd *) pSirMsg;
+ pSession->roamingStatusCode = pDeauthIndMsg->statusCode;
+ /* Convert into proper reason code */
+ if ((pDeauthIndMsg->reasonCode == eSIR_BEACON_MISSED) ||
+ (pDeauthIndMsg->reasonCode ==
+ eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON))
+ pSession->joinFailStatusCode.reasonCode = 0;
+ else
+ pSession->joinFailStatusCode.reasonCode =
+ pDeauthIndMsg->reasonCode;
+ /*
+ * cfg layer expects 0 as reason code if
+ * the driver dosent know the reason code
+ * eSIR_BEACON_MISSED is defined as locally
+ */
+ } else {
+ sms_log(pMac, LOGW, FL("gets an unknown type (%d)"), type);
+ result = eCSR_ROAM_RESULT_NONE;
+ pSession->joinFailStatusCode.reasonCode = 1;
+ }
+
+ /* call profile lost link routine here */
+ if (!CSR_IS_INFRA_AP(&pSession->connectedProfile)) {
+ csr_roam_call_callback(pMac, sessionId, NULL, 0,
+ eCSR_ROAM_LOSTLINK_DETECTED, result);
+ /*Move the state to Idle after disconnection */
+ csr_roam_state_change(pMac, eCSR_ROAMING_STATE_IDLE, sessionId);
+
+ }
+
+ if (eWNI_SME_DISASSOC_IND == type) {
+ status = csr_send_mb_disassoc_cnf_msg(pMac, pDisassocIndMsg);
+ } else if (eWNI_SME_DEAUTH_IND == type) {
+ status = csr_send_mb_deauth_cnf_msg(pMac, pDeauthIndMsg);
+ }
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ /* If fail to send confirmation to PE, not to trigger roaming */
+ fToRoam = false;
+ }
+ /* prepare to tell HDD to disconnect */
+ cdf_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0);
+ roamInfo.statusCode = (tSirResultCodes) pSession->roamingStatusCode;
+ roamInfo.reasonCode = pSession->joinFailStatusCode.reasonCode;
+ if (eWNI_SME_DISASSOC_IND == type) {
+ /* staMacAddr */
+ cdf_mem_copy(roamInfo.peerMac.bytes,
+ pDisassocIndMsg->peerMacAddr,
+ sizeof(tSirMacAddr));
+ roamInfo.staId = (uint8_t) pDisassocIndMsg->staId;
+ roamInfo.reasonCode = pDisassocIndMsg->reasonCode;
+ } else if (eWNI_SME_DEAUTH_IND == type) {
+ /* staMacAddr */
+ cdf_mem_copy(roamInfo.peerMac.bytes,
+ pDeauthIndMsg->peerMacAddr,
+ sizeof(tSirMacAddr));
+ roamInfo.staId = (uint8_t) pDeauthIndMsg->staId;
+ roamInfo.reasonCode = pDeauthIndMsg->reasonCode;
+ }
+ sms_log(pMac, LOGW, FL("roamInfo.staId (%d)"), roamInfo.staId);
+
+ /* See if we can possibly roam. If so, start the roaming process and notify HDD
+ that we are roaming. But if we cannot possibly roam, or if we are unable to
+ currently roam, then notify HDD of the lost link */
+ if (fToRoam) {
+ /* Only remove the connected BSS in infrastructure mode */
+ csr_roam_remove_connected_bss_from_scan_cache(pMac,
+ &pSession->
+ connectedProfile);
+ /* Not to do anying for lostlink with WDS */
+ status = csr_roam_start_roaming(pMac, sessionId,
+ (eWNI_SME_DEAUTH_IND == type) ?
+ eCsrLostlinkRoamingDeauth :
+ eCsrLostlinkRoamingDisassoc);
+ if (pMac->roam.configParam.nRoamingTime) {
+ status = csr_roam_start_roaming(pMac, sessionId,
+ (eWNI_SME_DEAUTH_IND == type) ?
+ eCsrLostlinkRoamingDeauth :
+ eCsrLostlinkRoamingDisassoc);
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ cdf_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0);
+ /* For IBSS, we need to give some more info to HDD */
+ if (csr_is_bss_type_ibss
+ (pSession->connectedProfile.BSSType)) {
+ roamInfo.u.pConnectedProfile =
+ &pSession->connectedProfile;
+ roamInfo.statusCode =
+ (tSirResultCodes) pSession->
+ roamingStatusCode;
+ roamInfo.reasonCode =
+ pSession->joinFailStatusCode.
+ reasonCode;
+ } else {
+ roamInfo.reasonCode =
+ eCsrRoamReasonSmeIssuedForLostLink;
+ }
+ pRoamInfo = &roamInfo;
+ pSession->roamingReason =
+ (eWNI_SME_DEAUTH_IND ==
+ type) ? eCsrLostlinkRoamingDeauth :
+ eCsrLostlinkRoamingDisassoc;
+ pSession->roamingStartTime =
+ (uint32_t) cdf_mc_timer_get_system_ticks();
+ csr_roam_call_callback(pMac, sessionId, pRoamInfo,
+ 0, eCSR_ROAM_ROAMING_START,
+ eCSR_ROAM_RESULT_LOSTLINK);
+ } else {
+ sms_log(pMac, LOGW,
+ " %s Fail to start roaming, status = %d",
+ __func__, status);
+ fToRoam = false;
+ }
+ } else {
+ /* We are told not to roam, indicate lostlink */
+ fToRoam = false;
+ }
+ }
+ if (!fToRoam) {
+ /* Tell HDD about the lost link */
+ if (!CSR_IS_INFRA_AP(&pSession->connectedProfile)) {
+ /* Don't call csr_roam_call_callback for GO/SoftAp case as this indication
+ * was already given as part of eWNI_SME_DISASSOC_IND msg handling in
+ * csr_roam_check_for_link_status_change API.
+ */
+ csr_roam_call_callback(pMac, sessionId, &roamInfo, 0,
+ eCSR_ROAM_LOSTLINK, result);
+ }
+
+ }
+
+ return status;
+}
+
+CDF_STATUS csr_roam_lost_link_afterhandoff_failure(tpAniSirGlobal pMac,
+ uint32_t sessionId)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tListElem *pEntry = NULL;
+ tSmeCmd *pCommand = 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;
+ }
+
+ pSession->fCancelRoaming = false;
+ /* Only remove the connected BSS in infrastructure mode */
+ csr_roam_remove_connected_bss_from_scan_cache(pMac,
+ &pSession->connectedProfile);
+ if (pMac->roam.configParam.nRoamingTime) {
+ status = csr_roam_start_roaming(pMac, sessionId,
+ pSession->roamingReason);
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ /*
+ * before starting the lost link logic release
+ * the roam command for handoff
+ */
+ pEntry =
+ csr_ll_peek_head(&pMac->sme.smeCmdActiveList,
+ LL_ACCESS_LOCK);
+ if (pEntry) {
+ pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
+ }
+ if (pCommand) {
+ if ((eSmeCommandRoam == pCommand->command) &&
+ (eCsrSmeIssuedAssocToSimilarAP ==
+ pCommand->u.roamCmd.roamReason)) {
+ if (csr_ll_remove_entry
+ (&pMac->sme.smeCmdActiveList,
+ pEntry, LL_ACCESS_LOCK)) {
+ csr_release_command_roam(pMac,
+ pCommand);
+ }
+ }
+ }
+ sms_log(pMac, LOGW, "Lost link roaming started ...");
+ }
+ } else {
+ /* We are told not to roam, indicate lostlink */
+ status = CDF_STATUS_E_FAILURE;
+ }
+
+ return status;
+}
+
+void csr_roam_wm_status_change_complete(tpAniSirGlobal pMac)
+{
+ tListElem *pEntry;
+ tSmeCmd *pCommand;
+ pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK);
+ if (pEntry) {
+ pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
+ if (eSmeCommandWmStatusChange == pCommand->command) {
+ /* Nothing to process in a Lost Link completion.... It just kicks off a */
+ /* roaming sequence. */
+ if (csr_ll_remove_entry
+ (&pMac->sme.smeCmdActiveList, pEntry,
+ LL_ACCESS_LOCK)) {
+ csr_release_command_wm_status_change(pMac, pCommand);
+ } else {
+ sms_log(pMac, LOGE,
+ " ******csr_roam_wm_status_change_complete fail to release command");
+ }
+
+ } else {
+ sms_log(pMac, LOGW,
+ "CSR: WmStatusChange Completion called but LOST LINK command is not ACTIVE ...");
+ }
+ } else {
+ sms_log(pMac, LOGW,
+ "CSR: WmStatusChange Completion called but NO commands are ACTIVE ...");
+ }
+ sme_process_pending_queue(pMac);
+}
+
+void csr_roam_process_wm_status_change_command(tpAniSirGlobal pMac,
+ tSmeCmd *pCommand)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ tSirSmeRsp *pSirSmeMsg;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, pCommand->sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "),
+ pCommand->sessionId);
+ return;
+ }
+ sms_log(pMac, LOG1, FL("session:%d, CmdType : %d"),
+ pCommand->sessionId, pCommand->u.wmStatusChangeCmd.Type);
+
+ switch (pCommand->u.wmStatusChangeCmd.Type) {
+ case eCsrDisassociated:
+ pSirSmeMsg =
+ (tSirSmeRsp *) &pCommand->u.wmStatusChangeCmd.u.
+ DisassocIndMsg;
+ status =
+ csr_roam_lost_link(pMac, pCommand->sessionId,
+ eWNI_SME_DISASSOC_IND, pSirSmeMsg);
+ break;
+ case eCsrDeauthenticated:
+ pSirSmeMsg =
+ (tSirSmeRsp *) &pCommand->u.wmStatusChangeCmd.u.
+ DeauthIndMsg;
+ status =
+ csr_roam_lost_link(pMac, pCommand->sessionId,
+ eWNI_SME_DEAUTH_IND, pSirSmeMsg);
+ break;
+ default:
+ sms_log(pMac, LOGW, FL("gets an unknown command %d"),
+ pCommand->u.wmStatusChangeCmd.Type);
+ break;
+ }
+ /* For WDS, we want to stop BSS as well when it is indicated that it is disconnected. */
+ if (CSR_IS_CONN_WDS(&pSession->connectedProfile)) {
+ if (!CDF_IS_STATUS_SUCCESS
+ (csr_roam_issue_stop_bss_cmd(pMac, pCommand->sessionId, true))) {
+ /* This is not good */
+ sms_log(pMac, LOGE,
+ FL(" failed to issue stopBSS command"));
+ }
+ }
+ /* Lost Link just triggers a roaming sequence. We can complte the Lost Link */
+ /* command here since there is nothing else to do. */
+ csr_roam_wm_status_change_complete(pMac);
+}
+
+
+/**
+ * csr_compute_mode_and_band() - computes dot11mode
+ * @pMac: mac global context
+ * @dot11_mode: out param, do11 mode calculated
+ * @band: out param, band caclculated
+ * @opr_ch: operating channels
+ *
+ * This function finds dot11 mode based on current mode, operating channel and
+ * fw supported modes.
+ *
+ * Return: void
+ */
+static void
+csr_compute_mode_and_band(tpAniSirGlobal mac_ctx,
+ eCsrCfgDot11Mode *dot11_mode,
+ eCsrBand *band,
+ uint8_t opr_ch)
+{
+ bool vht_24_ghz = mac_ctx->roam.configParam.enableVhtFor24GHz;
+ switch (mac_ctx->roam.configParam.uCfgDot11Mode) {
+ case eCSR_CFG_DOT11_MODE_11A:
+ *dot11_mode = eCSR_CFG_DOT11_MODE_11A;
+ *band = eCSR_BAND_5G;
+ break;
+ case eCSR_CFG_DOT11_MODE_11B:
+ *dot11_mode = eCSR_CFG_DOT11_MODE_11B;
+ *band = eCSR_BAND_24;
+ break;
+ case eCSR_CFG_DOT11_MODE_11G:
+ *dot11_mode = eCSR_CFG_DOT11_MODE_11G;
+ *band = eCSR_BAND_24;
+ break;
+ case eCSR_CFG_DOT11_MODE_11N:
+ *dot11_mode = eCSR_CFG_DOT11_MODE_11N;
+ *band = CSR_GET_BAND(opr_ch);
+ break;
+#ifdef WLAN_FEATURE_11AC
+ case eCSR_CFG_DOT11_MODE_11AC:
+ if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) {
+ /*
+ * If the operating channel is in 2.4 GHz band, check
+ * for INI item to disable VHT operation in 2.4 GHz band
+ */
+ if (CDS_IS_CHANNEL_24GHZ(opr_ch) && !vht_24_ghz)
+ /* Disable 11AC operation */
+ *dot11_mode = eCSR_CFG_DOT11_MODE_11N;
+ else
+ *dot11_mode = eCSR_CFG_DOT11_MODE_11AC;
+ } else {
+ *dot11_mode = eCSR_CFG_DOT11_MODE_11N;
+ }
+ *band = CSR_GET_BAND(opr_ch);
+ break;
+ case eCSR_CFG_DOT11_MODE_11AC_ONLY:
+ if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) {
+ /*
+ * If the operating channel is in 2.4 GHz band, check
+ * for INI item to disable VHT operation in 2.4 GHz band
+ */
+ if (CDS_IS_CHANNEL_24GHZ(opr_ch) && !vht_24_ghz)
+ /* Disable 11AC operation */
+ *dot11_mode = eCSR_CFG_DOT11_MODE_11N;
+ else
+ *dot11_mode = eCSR_CFG_DOT11_MODE_11AC_ONLY;
+ } else {
+ *dot11_mode = eCSR_CFG_DOT11_MODE_11N;
+ }
+ *band = CSR_GET_BAND(opr_ch);
+ break;
+#endif
+ case eCSR_CFG_DOT11_MODE_AUTO:
+#ifdef WLAN_FEATURE_11AC
+ if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) {
+ /*
+ * If the operating channel is in 2.4 GHz band,
+ * check for INI item to disable VHT operation
+ * in 2.4 GHz band
+ */
+ if (CDS_IS_CHANNEL_24GHZ(opr_ch)
+ && !vht_24_ghz)
+ /* Disable 11AC operation */
+ *dot11_mode = eCSR_CFG_DOT11_MODE_11N;
+ else
+ *dot11_mode = eCSR_CFG_DOT11_MODE_11AC;
+ } else {
+ *dot11_mode = eCSR_CFG_DOT11_MODE_11N;
+ }
+#else
+ *dot11_mode = eCSR_CFG_DOT11_MODE_11N;
+#endif
+ *band = CSR_GET_BAND(opr_ch);
+ break;
+ default:
+ /*
+ * Global dot11 Mode setting is 11a/b/g. use the channel number
+ * to determine the Mode setting.
+ */
+ if (eCSR_OPERATING_CHANNEL_AUTO == opr_ch) {
+ *band = mac_ctx->roam.configParam.eBand;
+ if (eCSR_BAND_24 == *band) {
+ /*
+ * See reason in else if ( CDS_IS_CHANNEL_24GHZ
+ * (opr_ch) ) to pick 11B
+ */
+ *dot11_mode = eCSR_CFG_DOT11_MODE_11B;
+ } else {
+ /* prefer 5GHz */
+ *band = eCSR_BAND_5G;
+ *dot11_mode = eCSR_CFG_DOT11_MODE_11A;
+ }
+ } else if (CDS_IS_CHANNEL_24GHZ(opr_ch)) {
+ /*
+ * WiFi tests require IBSS networks to start in 11b mode
+ * without any change to the default parameter settings
+ * on the adapter. We use ACU to start an IBSS through
+ * creation of a startIBSS profile. This startIBSS
+ * profile has Auto MACProtocol and the adapter property
+ * setting for dot11Mode is also AUTO. So in this case,
+ * let's start the IBSS network in 11b mode instead of
+ * 11g mode. So this is for Auto=profile->MacProtocol &&
+ * Auto=Global. dot11Mode && profile->channel is < 14,
+ * then start the IBSS in b mode.
+ *
+ * Note: we used to have this start as an 11g IBSS for
+ * best performance. now to specify that the user will
+ * have to set the do11Mode in the property page to 11g
+ * to force it.
+ */
+ *dot11_mode = eCSR_CFG_DOT11_MODE_11B;
+ *band = eCSR_BAND_24;
+ } else {
+ /* else, it's a 5.0GHz channel. Set mode to 11a. */
+ *dot11_mode = eCSR_CFG_DOT11_MODE_11A;
+ *band = eCSR_BAND_5G;
+ }
+ break;
+ } /* switch */
+}
+
+/**
+ * csr_roam_get_phy_mode_band_for_bss() - This function returns band and mode
+ * information.
+ * @mac_ctx: mac global context
+ * @profile: bss profile
+ * @band: out param, band caclculated
+ * @opr_ch: operating channels
+ *
+ * This function finds dot11 mode based on current mode, operating channel and
+ * fw supported modes. The only tricky part is that if phyMode is set to 11abg,
+ * this function may return eCSR_CFG_DOT11_MODE_11B instead of
+ * eCSR_CFG_DOT11_MODE_11G if everything is set to auto-pick.
+ *
+ * Return: dot11mode
+ */
+static eCsrCfgDot11Mode
+csr_roam_get_phy_mode_band_for_bss(tpAniSirGlobal mac_ctx,
+ tCsrRoamProfile *profile,
+ uint8_t opr_chn,
+ eCsrBand *p_band)
+{
+ eCsrBand band;
+ eCsrCfgDot11Mode curr_mode = mac_ctx->roam.configParam.uCfgDot11Mode;
+ eCsrCfgDot11Mode cfg_dot11_mode =
+ csr_get_cfg_dot11_mode_from_csr_phy_mode(profile,
+ (eCsrPhyMode) profile->phyMode,
+ mac_ctx->roam.configParam.ProprietaryRatesEnabled);
+
+ /*
+ * If the global setting for dot11Mode is set to auto/abg, we overwrite
+ * the setting in the profile.
+ */
+ if (((!CSR_IS_INFRA_AP(profile) && !CSR_IS_WDS(profile))
+ && ((eCSR_CFG_DOT11_MODE_AUTO == curr_mode)
+ || (eCSR_CFG_DOT11_MODE_ABG == curr_mode)))
+ || (eCSR_CFG_DOT11_MODE_AUTO == cfg_dot11_mode)
+ || (eCSR_CFG_DOT11_MODE_ABG == cfg_dot11_mode)) {
+ csr_compute_mode_and_band(mac_ctx, &cfg_dot11_mode,
+ &band, opr_chn);
+ } /* if( eCSR_CFG_DOT11_MODE_ABG == cfg_dot11_mode ) */
+ else {
+ /* dot11 mode is set, lets pick the band */
+ if (eCSR_OPERATING_CHANNEL_AUTO == opr_chn) {
+ /* channel is Auto also. */
+ band = mac_ctx->roam.configParam.eBand;
+ if (eCSR_BAND_ALL == band) {
+ /* prefer 5GHz */
+ band = eCSR_BAND_5G;
+ }
+ } else{
+ band = CSR_GET_BAND(opr_chn);
+ }
+ }
+ if (p_band)
+ *p_band = band;
+
+ if (opr_chn == 14) {
+ sms_log(mac_ctx, LOGE, FL("Switching to Dot11B mode"));
+ cfg_dot11_mode = eCSR_CFG_DOT11_MODE_11B;
+ }
+
+ /*
+ * Incase of WEP Security encryption type is coming as part of add key.
+ * So while STart BSS dont have information
+ */
+ if ((!CSR_IS_11n_ALLOWED(profile->EncryptionType.encryptionType[0])
+ || ((profile->privacy == 1)
+ && (profile->EncryptionType.encryptionType[0] ==
+ eCSR_ENCRYPT_TYPE_NONE)))
+ && ((eCSR_CFG_DOT11_MODE_11N == cfg_dot11_mode) ||
+#ifdef WLAN_FEATURE_11AC
+ (eCSR_CFG_DOT11_MODE_11AC == cfg_dot11_mode)
+#endif
+ )) {
+ /* We cannot do 11n here */
+ if (CDS_IS_CHANNEL_24GHZ(opr_chn))
+ cfg_dot11_mode = eCSR_CFG_DOT11_MODE_11G;
+ else
+ cfg_dot11_mode = eCSR_CFG_DOT11_MODE_11A;
+ }
+ return cfg_dot11_mode;
+}
+
+CDF_STATUS csr_roam_issue_stop_bss(tpAniSirGlobal pMac, uint32_t sessionId,
+ eCsrRoamSubState NewSubstate)
+{
+ CDF_STATUS status;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+ {
+ host_log_ibss_pkt_type *pIbssLog;
+ WLAN_HOST_DIAG_LOG_ALLOC(pIbssLog, host_log_ibss_pkt_type,
+ LOG_WLAN_IBSS_C);
+ if (pIbssLog) {
+ pIbssLog->eventId = WLAN_IBSS_EVENT_STOP_REQ;
+ WLAN_HOST_DIAG_LOG_REPORT(pIbssLog);
+ }
+ }
+#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */
+ /* Set the roaming substate to 'stop Bss request'... */
+ csr_roam_substate_change(pMac, NewSubstate, sessionId);
+
+ /* attempt to stop the Bss (reason code is ignored...) */
+ status = csr_send_mb_stop_bss_req_msg(pMac, sessionId);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGW,
+ FL("csr_send_mb_stop_bss_req_msg failed with status %d"),
+ status);
+ }
+ return status;
+}
+
+/* pNumChan is a caller allocated space with the sizeof pChannels */
+CDF_STATUS csr_get_cfg_valid_channels(tpAniSirGlobal pMac, uint8_t *pChannels,
+ uint32_t *pNumChan)
+{
+ if (!IS_SIR_STATUS_SUCCESS(wlan_cfg_get_str(pMac,
+ WNI_CFG_VALID_CHANNEL_LIST,
+ (uint8_t *) pChannels, pNumChan)))
+ return CDF_STATUS_E_FAILURE;
+ return CDF_STATUS_SUCCESS;
+}
+
+tPowerdBm csr_get_cfg_max_tx_power(tpAniSirGlobal pMac, uint8_t channel)
+{
+ uint32_t cfgLength = 0;
+ uint16_t cfgId = 0;
+ tPowerdBm maxTxPwr = 0;
+ uint8_t *pCountryInfo = NULL;
+ CDF_STATUS status;
+ uint8_t count = 0;
+ uint8_t firstChannel;
+ uint8_t maxChannels;
+
+ if (CDS_IS_CHANNEL_5GHZ(channel)) {
+ cfgId = WNI_CFG_MAX_TX_POWER_5;
+ cfgLength = WNI_CFG_MAX_TX_POWER_5_LEN;
+ } else if (CDS_IS_CHANNEL_24GHZ(channel)) {
+ cfgId = WNI_CFG_MAX_TX_POWER_2_4;
+ cfgLength = WNI_CFG_MAX_TX_POWER_2_4_LEN;
+ } else
+ return maxTxPwr;
+
+ pCountryInfo = cdf_mem_malloc(cfgLength);
+ if (NULL == pCountryInfo)
+ status = CDF_STATUS_E_NOMEM;
+ else
+ status = CDF_STATUS_SUCCESS;
+ if (status != CDF_STATUS_SUCCESS) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ FL("%s: failed to allocate memory, status = %d"),
+ __FUNCTION__, status);
+ goto error;
+ }
+ if (wlan_cfg_get_str(pMac, cfgId, (uint8_t *)pCountryInfo,
+ &cfgLength) != eSIR_SUCCESS) {
+ goto error;
+ }
+ /* Identify the channel and maxtxpower */
+ while (count <= (cfgLength - (sizeof(tSirMacChanInfo)))) {
+ firstChannel = pCountryInfo[count++];
+ maxChannels = pCountryInfo[count++];
+ maxTxPwr = pCountryInfo[count++];
+
+ if ((channel >= firstChannel) &&
+ (channel < (firstChannel + maxChannels))) {
+ break;
+ }
+ }
+
+error:
+ if (NULL != pCountryInfo)
+ cdf_mem_free(pCountryInfo);
+
+ return maxTxPwr;
+}
+
+bool csr_roam_is_channel_valid(tpAniSirGlobal pMac, uint8_t channel)
+{
+ bool fValid = false;
+ uint32_t idxValidChannels;
+ uint32_t len = sizeof(pMac->roam.validChannelList);
+
+ if (CDF_IS_STATUS_SUCCESS
+ (csr_get_cfg_valid_channels(pMac, pMac->roam.validChannelList, &len))) {
+ for (idxValidChannels = 0; (idxValidChannels < len);
+ idxValidChannels++) {
+ if (channel ==
+ pMac->roam.validChannelList[idxValidChannels]) {
+ fValid = true;
+ break;
+ }
+ }
+ }
+ pMac->roam.numValidChannels = len;
+ return fValid;
+}
+
+bool csr_roam_is_valid40_mhz_channel(tpAniSirGlobal pMac, uint8_t channel)
+{
+ bool fValid = false;
+ uint8_t i;
+ for (i = 0; i < pMac->scan.base40MHzChannels.numChannels; i++) {
+ if (channel == pMac->scan.base40MHzChannels.channelList[i]) {
+ fValid = true;
+ break;
+ }
+ }
+ return fValid;
+}
+
+/* This function check and validate whether the NIC can do CB (40MHz) */
+static ePhyChanBondState csr_get_cb_mode_from_ies(tpAniSirGlobal pMac,
+ uint8_t primaryChn,
+ tDot11fBeaconIEs *pIes)
+{
+ ePhyChanBondState eRet = PHY_SINGLE_CHANNEL_CENTERED;
+ uint8_t centerChn;
+ uint32_t ChannelBondingMode;
+ if (CDS_IS_CHANNEL_24GHZ(primaryChn)) {
+ /*
+ * gChannelBondingMode24GHz configuration item is common for
+ * SAP and STA mode and currently MDM does not support
+ * HT40 in 2.4Ghz STA mode.
+ * So disabling the HT40 in 2.4GHz station mode
+ */
+#ifdef QCA_HT_20_24G_STA_ONLY
+ ChannelBondingMode = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE;
+#else
+ ChannelBondingMode =
+ pMac->roam.configParam.channelBondingMode24GHz;
+#endif
+ } else {
+ ChannelBondingMode =
+ pMac->roam.configParam.channelBondingMode5GHz;
+ }
+
+ if (WNI_CFG_CHANNEL_BONDING_MODE_DISABLE == ChannelBondingMode)
+ return PHY_SINGLE_CHANNEL_CENTERED;
+
+ /* Figure what the other side's CB mode */
+ if (!(pIes->HTCaps.present && (eHT_CHANNEL_WIDTH_40MHZ ==
+ pIes->HTCaps.supportedChannelWidthSet))) {
+ return PHY_SINGLE_CHANNEL_CENTERED;
+ }
+
+ /* Check set as TKIP or not. */
+ if (((NULL != &(pIes->RSN.pwise_cipher_suites[0][0]) &&
+ (pIes->RSN.pwise_cipher_suite_count == 1)) &&
+ !memcmp(&(pIes->RSN.pwise_cipher_suites[0][0]),
+ "\x00\x0f\xac\x02", 4))
+ || (((NULL != &(pIes->WPA)) &&
+ (pIes->WPA.unicast_cipher_count == 1))
+ && ((NULL != &(pIes->WPA.unicast_ciphers[0]))
+ && !memcmp(&(pIes->WPA.unicast_ciphers[0]),
+ "\x00\x0f\xac\x02", 4)))) {
+ sms_log(pMac, LOGW,
+ " No channel bonding in TKIP mode ");
+ return PHY_SINGLE_CHANNEL_CENTERED;
+ }
+
+ if (!pIes->HTInfo.present)
+ return PHY_SINGLE_CHANNEL_CENTERED;
+
+ /*
+ * This is called during INFRA STA/CLIENT and should use the merged
+ * value of supported channel width and recommended tx width as per
+ * standard
+ */
+ sms_log(pMac, LOG1, "scws %u rtws %u sco %u",
+ pIes->HTCaps.supportedChannelWidthSet,
+ pIes->HTInfo.recommendedTxWidthSet,
+ pIes->HTInfo.secondaryChannelOffset);
+
+ if (pIes->HTInfo.recommendedTxWidthSet == eHT_CHANNEL_WIDTH_40MHZ)
+ eRet = (ePhyChanBondState)pIes->HTInfo.secondaryChannelOffset;
+ else
+ eRet = PHY_SINGLE_CHANNEL_CENTERED;
+
+ switch (eRet) {
+ case PHY_DOUBLE_CHANNEL_LOW_PRIMARY:
+ centerChn = primaryChn + CSR_CB_CENTER_CHANNEL_OFFSET;
+ break;
+ case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY:
+ centerChn = primaryChn - CSR_CB_CENTER_CHANNEL_OFFSET;
+ break;
+ case PHY_SINGLE_CHANNEL_CENTERED:
+ default:
+ centerChn = primaryChn;
+ break;
+ }
+
+ if ((PHY_SINGLE_CHANNEL_CENTERED != eRet)
+ && !csr_roam_is_valid40_mhz_channel(pMac, centerChn)) {
+ sms_log(pMac, LOGE,
+ "Invalid center channel (%d), disable 40MHz mode",
+ centerChn);
+ eRet = PHY_SINGLE_CHANNEL_CENTERED;
+ }
+ return eRet;
+}
+
+bool csr_is_encryption_in_list(tpAniSirGlobal pMac,
+ tCsrEncryptionList *pCipherList,
+ eCsrEncryptionType encryptionType)
+{
+ bool fFound = false;
+ uint32_t idx;
+ for (idx = 0; idx < pCipherList->numEntries; idx++) {
+ if (pCipherList->encryptionType[idx] == encryptionType) {
+ fFound = true;
+ break;
+ }
+ }
+ return fFound;
+}
+
+bool csr_is_auth_in_list(tpAniSirGlobal pMac, tCsrAuthList *pAuthList,
+ eCsrAuthType authType)
+{
+ bool fFound = false;
+ uint32_t idx;
+ for (idx = 0; idx < pAuthList->numEntries; idx++) {
+ if (pAuthList->authType[idx] == authType) {
+ fFound = true;
+ break;
+ }
+ }
+ return fFound;
+}
+
+bool csr_is_same_profile(tpAniSirGlobal pMac,
+ tCsrRoamConnectedProfile *pProfile1,
+ tCsrRoamProfile *pProfile2)
+{
+ uint32_t i;
+ bool fCheck = false;
+ tCsrScanResultFilter *pScanFilter = NULL;
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+
+ if (!(pProfile1 && pProfile2))
+ return fCheck;
+ pScanFilter = cdf_mem_malloc(sizeof(tCsrScanResultFilter));
+ if (NULL == pScanFilter)
+ return fCheck;
+
+ cdf_mem_set(pScanFilter, sizeof(tCsrScanResultFilter), 0);
+ status = csr_roam_prepare_filter_from_profile(pMac, pProfile2,
+ pScanFilter);
+ if (!(CDF_IS_STATUS_SUCCESS(status)))
+ goto free_scan_filter;
+
+ for (i = 0; i < pScanFilter->SSIDs.numOfSSIDs; i++) {
+ fCheck = csr_is_ssid_match(pMac,
+ pScanFilter->SSIDs.SSIDList[i].SSID.ssId,
+ pScanFilter->SSIDs.SSIDList[i].SSID.length,
+ pProfile1->SSID.ssId,
+ pProfile1->SSID.length,
+ false);
+ if (fCheck)
+ break;
+ }
+ if (!fCheck)
+ goto free_scan_filter;
+
+ if (!csr_is_auth_in_list(pMac, &pProfile2->AuthType,
+ pProfile1->AuthType)
+ || (pProfile2->BSSType != pProfile1->BSSType)
+ || !csr_is_encryption_in_list(pMac, &pProfile2->EncryptionType,
+ pProfile1->EncryptionType)) {
+ fCheck = false;
+ goto free_scan_filter;
+ }
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ if (pProfile1->MDID.mdiePresent || pProfile2->MDID.mdiePresent) {
+ if (pProfile1->MDID.mobilityDomain
+ != pProfile2->MDID.mobilityDomain) {
+ fCheck = false;
+ goto free_scan_filter;
+ }
+ }
+#endif
+ /* Match found */
+ fCheck = true;
+free_scan_filter:
+ csr_free_scan_filter(pMac, pScanFilter);
+ cdf_mem_free(pScanFilter);
+ return fCheck;
+}
+
+bool csr_roam_is_same_profile_keys(tpAniSirGlobal pMac,
+ tCsrRoamConnectedProfile *pConnProfile,
+ tCsrRoamProfile *pProfile2)
+{
+ bool fCheck = false;
+ int i;
+ do {
+ /* Only check for static WEP */
+ if (!csr_is_encryption_in_list
+ (pMac, &pProfile2->EncryptionType,
+ eCSR_ENCRYPT_TYPE_WEP40_STATICKEY)
+ && !csr_is_encryption_in_list(pMac,
+ &pProfile2->EncryptionType,
+ eCSR_ENCRYPT_TYPE_WEP104_STATICKEY)) {
+ fCheck = true;
+ break;
+ }
+ if (!csr_is_encryption_in_list
+ (pMac, &pProfile2->EncryptionType,
+ pConnProfile->EncryptionType))
+ break;
+ if (pConnProfile->Keys.defaultIndex !=
+ pProfile2->Keys.defaultIndex)
+ break;
+ for (i = 0; i < CSR_MAX_NUM_KEY; i++) {
+ if (pConnProfile->Keys.KeyLength[i] !=
+ pProfile2->Keys.KeyLength[i])
+ break;
+ if (!cdf_mem_compare(&pConnProfile->Keys.KeyMaterial[i],
+ &pProfile2->Keys.KeyMaterial[i],
+ pProfile2->Keys.KeyLength[i])) {
+ break;
+ }
+ }
+ if (i == CSR_MAX_NUM_KEY) {
+ fCheck = true;
+ }
+ } while (0);
+ return fCheck;
+}
+
+/* IBSS */
+
+uint8_t csr_roam_get_ibss_start_channel_number50(tpAniSirGlobal pMac)
+{
+ uint8_t channel = 0;
+ uint32_t idx;
+ uint32_t idxValidChannels;
+ bool fFound = false;
+ uint32_t len = sizeof(pMac->roam.validChannelList);
+
+ if (eCSR_OPERATING_CHANNEL_ANY != pMac->roam.configParam.AdHocChannel5G) {
+ channel = pMac->roam.configParam.AdHocChannel5G;
+ if (!csr_roam_is_channel_valid(pMac, channel)) {
+ channel = 0;
+ }
+ }
+ if (0 == channel
+ &&
+ CDF_IS_STATUS_SUCCESS(csr_get_cfg_valid_channels
+ (pMac,
+ (uint8_t *) pMac->roam.validChannelList,
+ &len))) {
+ for (idx = 0; (idx < CSR_NUM_IBSS_START_CHANNELS_50) && !fFound;
+ idx++) {
+ for (idxValidChannels = 0;
+ (idxValidChannels < len) && !fFound;
+ idxValidChannels++) {
+ if (csr_start_ibss_channels50[idx] ==
+ pMac->roam.
+ validChannelList[idxValidChannels]) {
+ fFound = true;
+ channel = csr_start_ibss_channels50[idx];
+ }
+ }
+ }
+ /*
+ * this is rare, but if it does happen,
+ * we find anyone in 11a bandwidth and
+ * return the first 11a channel found!
+ */
+ if (!fFound) {
+ for (idxValidChannels = 0; idxValidChannels < len;
+ idxValidChannels++) {
+ if (CDS_IS_CHANNEL_5GHZ(pMac->roam.
+ validChannelList[idxValidChannels])) {
+ /* the max channel# in 11g is 14 */
+ if (idxValidChannels <
+ CSR_NUM_IBSS_START_CHANNELS_50) {
+ channel =
+ pMac->roam.validChannelList
+ [idxValidChannels];
+ }
+ break;
+ }
+ }
+ }
+ } /* if */
+
+ return channel;
+}
+
+uint8_t csr_roam_get_ibss_start_channel_number24(tpAniSirGlobal pMac)
+{
+ uint8_t channel = 1;
+ uint32_t idx;
+ uint32_t idxValidChannels;
+ bool fFound = false;
+ uint32_t len = sizeof(pMac->roam.validChannelList);
+
+ if (eCSR_OPERATING_CHANNEL_ANY != pMac->roam.configParam.AdHocChannel24) {
+ channel = pMac->roam.configParam.AdHocChannel24;
+ if (!csr_roam_is_channel_valid(pMac, channel)) {
+ channel = 0;
+ }
+ }
+
+ if (0 == channel
+ &&
+ CDF_IS_STATUS_SUCCESS(csr_get_cfg_valid_channels
+ (pMac,
+ (uint8_t *) pMac->roam.validChannelList,
+ &len))) {
+ for (idx = 0; (idx < CSR_NUM_IBSS_START_CHANNELS_24) && !fFound;
+ idx++) {
+ for (idxValidChannels = 0;
+ (idxValidChannels < len) && !fFound;
+ idxValidChannels++) {
+ if (csr_start_ibss_channels24[idx] ==
+ pMac->roam.
+ validChannelList[idxValidChannels]) {
+ fFound = true;
+ channel = csr_start_ibss_channels24[idx];
+ }
+ }
+ }
+ }
+
+ return channel;
+}
+
+/**
+ * csr_populate_basic_rates() - populates OFDM or CCK rates
+ * @rates: rate struct to populate
+ * @type: true: ofdm rates, false: cck rates
+ * @masked: indicates if rates are to be masked with
+ * CSR_DOT11_BASIC_RATE_MASK
+ *
+ * This function will populate OFDM or CCK rates
+ *
+ * Return: void
+ */
+static void
+csr_populate_basic_rates(tSirMacRateSet *rate_set, bool type, bool masked)
+{
+ uint8_t ofdm_rates[8] = {
+ SIR_MAC_RATE_6,
+ SIR_MAC_RATE_9,
+ SIR_MAC_RATE_12,
+ SIR_MAC_RATE_18,
+ SIR_MAC_RATE_24,
+ SIR_MAC_RATE_36,
+ SIR_MAC_RATE_48,
+ SIR_MAC_RATE_54
+ };
+ uint8_t cck_rates[4] = {
+ SIR_MAC_RATE_1,
+ SIR_MAC_RATE_2,
+ SIR_MAC_RATE_5_5,
+ SIR_MAC_RATE_11
+ };
+
+ if (type == true) {
+ rate_set->numRates = 8;
+ cdf_mem_copy(rate_set->rate, ofdm_rates, sizeof(ofdm_rates));
+ if (masked) {
+ rate_set->rate[0] |= CSR_DOT11_BASIC_RATE_MASK;
+ rate_set->rate[2] |= CSR_DOT11_BASIC_RATE_MASK;
+ rate_set->rate[4] |= CSR_DOT11_BASIC_RATE_MASK;
+ }
+ } else {
+ rate_set->numRates = 4;
+ cdf_mem_copy(rate_set->rate, cck_rates, sizeof(cck_rates));
+ if (masked) {
+ rate_set->rate[0] |= CSR_DOT11_BASIC_RATE_MASK;
+ rate_set->rate[1] |= CSR_DOT11_BASIC_RATE_MASK;
+ rate_set->rate[2] |= CSR_DOT11_BASIC_RATE_MASK;
+ rate_set->rate[3] |= CSR_DOT11_BASIC_RATE_MASK;
+ }
+ }
+}
+
+/**
+ * csr_convert_mode_to_nw_type() - convert mode into network type
+ * @dot11_mode: dot11_mode
+ * @band: 2.4 or 5 GHz
+ *
+ * Return: tSirNwType
+ */
+static tSirNwType
+csr_convert_mode_to_nw_type(eCsrCfgDot11Mode dot11_mode, eCsrBand band)
+{
+ switch (dot11_mode) {
+ case eCSR_CFG_DOT11_MODE_11G:
+ return eSIR_11G_NW_TYPE;
+ case eCSR_CFG_DOT11_MODE_11B:
+ return eSIR_11B_NW_TYPE;
+ case eCSR_CFG_DOT11_MODE_11A:
+ return eSIR_11A_NW_TYPE;
+ case eCSR_CFG_DOT11_MODE_11N:
+ default:
+ /*
+ * Because LIM only verifies it against 11a, 11b or 11g, set
+ * only 11g or 11a here
+ */
+ if (eCSR_BAND_24 == band)
+ return eSIR_11G_NW_TYPE;
+ else
+ return eSIR_11A_NW_TYPE;
+ }
+ return eSIR_DONOT_USE_NW_TYPE;
+}
+
+/**
+ * csr_roam_get_bss_start_parms() - get bss start param from profile
+ * @pMac: mac global context
+ * @pProfile: roam profile
+ * @pParam: out param, start bss params
+ *
+ * This function populates start bss param from roam profile
+ *
+ * Return: void
+ */
+static void
+csr_roam_get_bss_start_parms(tpAniSirGlobal pMac,
+ tCsrRoamProfile *pProfile,
+ tCsrRoamStartBssParams *pParam)
+{
+ eCsrBand band;
+ uint8_t opr_ch = 0;
+ tSirNwType nw_type;
+ uint8_t tmp_opr_ch = 0;
+ tSirMacRateSet *opr_rates = &pParam->operationalRateSet;
+ tSirMacRateSet *ext_rates = &pParam->extendedRateSet;
+
+ if (pProfile->ChannelInfo.numOfChannels
+ && pProfile->ChannelInfo.ChannelList) {
+ tmp_opr_ch = pProfile->ChannelInfo.ChannelList[0];
+ }
+
+ pParam->uCfgDot11Mode = csr_roam_get_phy_mode_band_for_bss(pMac,
+ pProfile, tmp_opr_ch, &band);
+
+ if (((pProfile->csrPersona == CDF_P2P_CLIENT_MODE)
+ || (pProfile->csrPersona == CDF_P2P_GO_MODE))
+ && (pParam->uCfgDot11Mode == eCSR_CFG_DOT11_MODE_11B)) {
+ /* This should never happen */
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL,
+ FL("For P2P (persona %d) dot11_mode is 11B"),
+ pProfile->csrPersona);
+ CDF_ASSERT(0);
+ }
+
+ nw_type = csr_convert_mode_to_nw_type(pParam->uCfgDot11Mode, band);
+ ext_rates->numRates = 0;
+
+ switch (nw_type) {
+ default:
+ sms_log(pMac, LOGE, FL("sees an unknown pSirNwType (%d)"),
+ nw_type);
+ case eSIR_11A_NW_TYPE:
+ csr_populate_basic_rates(opr_rates, true, true);
+ if (eCSR_OPERATING_CHANNEL_ANY != tmp_opr_ch) {
+ opr_ch = tmp_opr_ch;
+ break;
+ }
+ opr_ch = csr_roam_get_ibss_start_channel_number50(pMac);
+ if (0 == opr_ch &&
+ CSR_IS_PHY_MODE_DUAL_BAND(pProfile->phyMode) &&
+ CSR_IS_PHY_MODE_DUAL_BAND(pMac->roam.configParam.phyMode)) {
+ /*
+ * We could not find a 5G channel by auto pick, let's
+ * try 2.4G channels. We only do this here because
+ * csr_roam_get_phy_mode_band_for_bss always picks 11a
+ * for AUTO
+ */
+ nw_type = eSIR_11B_NW_TYPE;
+ opr_ch = csr_roam_get_ibss_start_channel_number24(pMac);
+ csr_populate_basic_rates(opr_rates, false, true);
+ }
+ break;
+ case eSIR_11B_NW_TYPE:
+ csr_populate_basic_rates(opr_rates, false, true);
+ if (eCSR_OPERATING_CHANNEL_ANY == tmp_opr_ch)
+ opr_ch = csr_roam_get_ibss_start_channel_number24(pMac);
+ else
+ opr_ch = tmp_opr_ch;
+ break;
+ case eSIR_11G_NW_TYPE:
+ /* For P2P Client and P2P GO, disable 11b rates */
+ if ((pProfile->csrPersona == CDF_P2P_CLIENT_MODE)
+ || (pProfile->csrPersona == CDF_P2P_GO_MODE)
+ || (eCSR_CFG_DOT11_MODE_11G_ONLY ==
+ pParam->uCfgDot11Mode)) {
+ csr_populate_basic_rates(opr_rates, true, true);
+ } else {
+ csr_populate_basic_rates(opr_rates, false, true);
+ csr_populate_basic_rates(ext_rates, true, false);
+ }
+
+ if (eCSR_OPERATING_CHANNEL_ANY == tmp_opr_ch)
+ opr_ch = csr_roam_get_ibss_start_channel_number24(pMac);
+ else
+ opr_ch = tmp_opr_ch;
+ break;
+ }
+ pParam->operationChn = opr_ch;
+ pParam->sirNwType = nw_type;
+ pParam->ch_params.ch_width = pProfile->ch_params.ch_width;
+ pParam->ch_params.center_freq_seg0 =
+ pProfile->ch_params.center_freq_seg0;
+ pParam->ch_params.center_freq_seg1 =
+ pProfile->ch_params.center_freq_seg1;
+ pParam->ch_params.sec_ch_offset =
+ pProfile->ch_params.sec_ch_offset;
+}
+
+static void
+csr_roam_get_bss_start_parms_from_bss_desc(tpAniSirGlobal pMac,
+ tSirBssDescription *pBssDesc,
+ tDot11fBeaconIEs *pIes,
+ tCsrRoamStartBssParams *pParam)
+{
+ if (!pParam) {
+ sms_log(pMac, LOGE, FL("BSS param's pointer is NULL"));
+ return;
+ }
+
+ pParam->sirNwType = pBssDesc->nwType;
+ pParam->cbMode = PHY_SINGLE_CHANNEL_CENTERED;
+ pParam->operationChn = pBssDesc->channelId;
+ cdf_mem_copy(&pParam->bssid, pBssDesc->bssId, sizeof(struct cdf_mac_addr));
+
+ if (!pIes) {
+ pParam->ssId.length = 0;
+ pParam->operationalRateSet.numRates = 0;
+ sms_log(pMac, LOGE, FL("IEs struct pointer is NULL"));
+ return;
+ }
+
+ if (pIes->SuppRates.present) {
+ pParam->operationalRateSet.numRates = pIes->SuppRates.num_rates;
+ if (pIes->SuppRates.num_rates > SIR_MAC_RATESET_EID_MAX) {
+ sms_log(pMac, LOGE,
+ FL("num_rates: %d > max val, resetting"),
+ pIes->SuppRates.num_rates);
+ pIes->SuppRates.num_rates = SIR_MAC_RATESET_EID_MAX;
+ }
+ cdf_mem_copy(pParam->operationalRateSet.rate,
+ pIes->SuppRates.rates,
+ sizeof(*pIes->SuppRates.rates) *
+ pIes->SuppRates.num_rates);
+ }
+ if (pIes->ExtSuppRates.present) {
+ pParam->extendedRateSet.numRates = pIes->ExtSuppRates.num_rates;
+ if (pIes->ExtSuppRates.num_rates > SIR_MAC_RATESET_EID_MAX) {
+ sms_log(pMac, LOGE,
+ FL("num_rates: %d > max val, resetting"),
+ pIes->ExtSuppRates.num_rates);
+ pIes->ExtSuppRates.num_rates = SIR_MAC_RATESET_EID_MAX;
+ }
+ cdf_mem_copy(pParam->extendedRateSet.rate,
+ pIes->ExtSuppRates.rates,
+ sizeof(*pIes->ExtSuppRates.rates) *
+ pIes->ExtSuppRates.num_rates);
+ }
+ if (pIes->SSID.present) {
+ pParam->ssId.length = pIes->SSID.num_ssid;
+ cdf_mem_copy(pParam->ssId.ssId, pIes->SSID.ssid,
+ pParam->ssId.length);
+ }
+ pParam->cbMode = csr_get_cb_mode_from_ies(pMac, pParam->operationChn,
+ pIes);
+}
+
+static void csr_roam_determine_max_rate_for_ad_hoc(tpAniSirGlobal pMac,
+ tSirMacRateSet *pSirRateSet)
+{
+ uint8_t MaxRate = 0;
+ uint32_t i;
+ uint8_t *pRate;
+
+ pRate = pSirRateSet->rate;
+ for (i = 0; i < pSirRateSet->numRates; i++) {
+ MaxRate =
+ CSR_MAX(MaxRate, (pRate[i] & (~CSR_DOT11_BASIC_RATE_MASK)));
+ }
+
+ /* Save the max rate in the connected state information... */
+
+ /* modify LastRates variable as well */
+
+ return;
+}
+
+CDF_STATUS csr_roam_issue_start_bss(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamStartBssParams *pParam,
+ tCsrRoamProfile *pProfile,
+ tSirBssDescription *pBssDesc, uint32_t roamId)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ eCsrBand eBand;
+ /* Set the roaming substate to 'Start BSS attempt'... */
+ csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_START_BSS_REQ,
+ sessionId);
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+ /* Need to figure out whether we need to log WDS??? */
+ if (CSR_IS_IBSS(pProfile)) {
+ host_log_ibss_pkt_type *pIbssLog;
+ WLAN_HOST_DIAG_LOG_ALLOC(pIbssLog, host_log_ibss_pkt_type,
+ LOG_WLAN_IBSS_C);
+ if (pIbssLog) {
+ if (pBssDesc) {
+ pIbssLog->eventId =
+ WLAN_IBSS_EVENT_JOIN_IBSS_REQ;
+ cdf_mem_copy(pIbssLog->bssid, pBssDesc->bssId,
+ 6);
+ } else {
+ pIbssLog->eventId =
+ WLAN_IBSS_EVENT_START_IBSS_REQ;
+ }
+ cdf_mem_copy(pIbssLog->ssid, pParam->ssId.ssId,
+ pParam->ssId.length);
+ if (pProfile->ChannelInfo.numOfChannels == 0) {
+ pIbssLog->channelSetting = AUTO_PICK;
+ } else {
+ pIbssLog->channelSetting = SPECIFIED;
+ }
+ pIbssLog->operatingChannel = pParam->operationChn;
+ WLAN_HOST_DIAG_LOG_REPORT(pIbssLog);
+ }
+ }
+#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */
+ /* Put RSN information in for Starting BSS */
+ pParam->nRSNIELength = (uint16_t) pProfile->nRSNReqIELength;
+ pParam->pRSNIE = pProfile->pRSNReqIE;
+
+ pParam->privacy = pProfile->privacy;
+ pParam->fwdWPSPBCProbeReq = pProfile->fwdWPSPBCProbeReq;
+ pParam->authType = pProfile->csr80211AuthType;
+ pParam->beaconInterval = pProfile->beaconInterval;
+ pParam->dtimPeriod = pProfile->dtimPeriod;
+ pParam->ApUapsdEnable = pProfile->ApUapsdEnable;
+ pParam->ssidHidden = pProfile->SSIDs.SSIDList[0].ssidHidden;
+ if (CSR_IS_INFRA_AP(pProfile) && (pParam->operationChn != 0)) {
+ if (csr_is_valid_channel(pMac, pParam->operationChn) !=
+ CDF_STATUS_SUCCESS) {
+ pParam->operationChn = INFRA_AP_DEFAULT_CHANNEL;
+ }
+ }
+ pParam->protEnabled = pProfile->protEnabled;
+ pParam->obssProtEnabled = pProfile->obssProtEnabled;
+ pParam->ht_protection = pProfile->cfg_protection;
+ pParam->wps_state = pProfile->wps_state;
+
+ pParam->uCfgDot11Mode =
+ csr_roam_get_phy_mode_band_for_bss(pMac, pProfile,
+ pParam->
+ operationChn,
+ &eBand);
+ pParam->bssPersona = pProfile->csrPersona;
+
+#ifdef WLAN_FEATURE_11W
+ pParam->mfpCapable = (0 != pProfile->MFPCapable);
+ pParam->mfpRequired = (0 != pProfile->MFPRequired);
+#endif
+
+ pParam->addIeParams.probeRespDataLen =
+ pProfile->addIeParams.probeRespDataLen;
+ pParam->addIeParams.probeRespData_buff =
+ pProfile->addIeParams.probeRespData_buff;
+
+ pParam->addIeParams.assocRespDataLen =
+ pProfile->addIeParams.assocRespDataLen;
+ pParam->addIeParams.assocRespData_buff =
+ pProfile->addIeParams.assocRespData_buff;
+
+ if (CSR_IS_IBSS(pProfile)) {
+ pParam->addIeParams.probeRespBCNDataLen =
+ pProfile->nWPAReqIELength;
+ pParam->addIeParams.probeRespBCNData_buff = pProfile->pWPAReqIE;
+ } else {
+ pParam->addIeParams.probeRespBCNDataLen =
+ pProfile->addIeParams.probeRespBCNDataLen;
+ pParam->addIeParams.probeRespBCNData_buff =
+ pProfile->addIeParams.probeRespBCNData_buff;
+ }
+ pParam->sap_dot11mc = pProfile->sap_dot11mc;
+
+ /* When starting an IBSS, start on the channel from the Profile. */
+ status =
+ csr_send_mb_start_bss_req_msg(pMac, sessionId, pProfile->BSSType, pParam,
+ pBssDesc);
+ return status;
+}
+
+static void csr_roam_prepare_bss_params(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamProfile *pProfile,
+ tSirBssDescription *pBssDesc,
+ tBssConfigParam *pBssConfig,
+ tDot11fBeaconIEs *pIes)
+{
+ uint8_t Channel;
+ ePhyChanBondState cbMode = PHY_SINGLE_CHANNEL_CENTERED;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return;
+ }
+
+ if (pBssDesc) {
+ csr_roam_get_bss_start_parms_from_bss_desc(pMac, pBssDesc, pIes,
+ &pSession->bssParams);
+ /* Since csr_roam_get_bss_start_parms_from_bss_desc fills in the bssid for pSession->bssParams */
+ /* The following code has to be do after that. */
+ /* For WDS station, use selfMac as the self BSSID */
+ if (CSR_IS_WDS_STA(pProfile)) {
+ cdf_mem_copy(&pSession->bssParams.bssid,
+ &pSession->selfMacAddr,
+ sizeof(struct cdf_mac_addr));
+ }
+ } else {
+ csr_roam_get_bss_start_parms(pMac, pProfile, &pSession->bssParams);
+ /* Use the first SSID */
+ if (pProfile->SSIDs.numOfSSIDs) {
+ cdf_mem_copy(&pSession->bssParams.ssId,
+ pProfile->SSIDs.SSIDList,
+ sizeof(tSirMacSSid));
+ }
+ /* For WDS station, use selfMac as the self BSSID */
+ if (CSR_IS_WDS_STA(pProfile)) {
+ cdf_mem_copy(&pSession->bssParams.bssid,
+ &pSession->selfMacAddr,
+ sizeof(struct cdf_mac_addr));
+ }
+ /* Use the first BSSID */
+ else if (pProfile->BSSIDs.numOfBSSIDs) {
+ cdf_mem_copy(&pSession->bssParams.bssid,
+ pProfile->BSSIDs.bssid,
+ sizeof(struct cdf_mac_addr));
+ } else {
+ cdf_mem_set(&pSession->bssParams.bssid,
+ sizeof(struct cdf_mac_addr), 0);
+ }
+ }
+ Channel = pSession->bssParams.operationChn;
+ /* Set operating channel in pProfile which will be used */
+ /* in csr_roam_set_bss_config_cfg() to determine channel bonding */
+ /* mode and will be configured in CFG later */
+ pProfile->operationChannel = Channel;
+
+ if (Channel == 0) {
+ sms_log(pMac, LOGE,
+ " CSR cannot find a channel to start IBSS");
+ } else {
+
+ csr_roam_determine_max_rate_for_ad_hoc(pMac,
+ &pSession->bssParams.
+ operationalRateSet);
+ if (CSR_IS_INFRA_AP(pProfile) || CSR_IS_START_IBSS(pProfile)) {
+ if (CDS_IS_CHANNEL_24GHZ(Channel)) {
+ cbMode =
+ pMac->roam.configParam.
+ channelBondingMode24GHz;
+ } else {
+ cbMode =
+ pMac->roam.configParam.
+ channelBondingMode5GHz;
+ }
+ sms_log(pMac, LOG1, "## cbMode %d", cbMode);
+ pBssConfig->cbMode = cbMode;
+ pSession->bssParams.cbMode = cbMode;
+ }
+ }
+}
+
+static CDF_STATUS csr_roam_start_ibss(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamProfile *pProfile,
+ bool *pfSameIbss)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ bool fSameIbss = false;
+
+ if (csr_is_conn_state_ibss(pMac, sessionId)) {
+ /* Check if any profile parameter has changed ? If any profile parameter */
+ /* has changed then stop old BSS and start a new one with new parameters */
+ if (csr_is_same_profile
+ (pMac, &pMac->roam.roamSession[sessionId].connectedProfile,
+ pProfile)) {
+ fSameIbss = true;
+ } else {
+ status =
+ csr_roam_issue_stop_bss(pMac, sessionId,
+ eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING);
+ }
+ } else if (csr_is_conn_state_connected_infra(pMac, sessionId)) {
+ /* Disassociate from the connected Infrastructure network... */
+ status =
+ csr_roam_issue_disassociate(pMac, sessionId,
+ eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING,
+ false);
+ } else {
+ tBssConfigParam *pBssConfig;
+
+ pBssConfig = cdf_mem_malloc(sizeof(tBssConfigParam));
+ if (NULL == pBssConfig)
+ status = CDF_STATUS_E_NOMEM;
+ else
+ status = CDF_STATUS_SUCCESS;
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ cdf_mem_set(pBssConfig, sizeof(tBssConfigParam), 0);
+ /* there is no Bss description before we start an IBSS so we need to adopt */
+ /* all Bss configuration parameters from the Profile. */
+ status =
+ csr_roam_prepare_bss_config_from_profile(pMac, pProfile,
+ pBssConfig,
+ NULL);
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ /* save dotMode */
+ pMac->roam.roamSession[sessionId].bssParams.
+ uCfgDot11Mode = pBssConfig->uCfgDot11Mode;
+ /* Prepare some more parameters for this IBSS */
+ csr_roam_prepare_bss_params(pMac, sessionId,
+ pProfile, NULL,
+ pBssConfig, NULL);
+ status =
+ csr_roam_set_bss_config_cfg(pMac, sessionId,
+ pProfile, NULL,
+ pBssConfig, NULL,
+ false);
+ }
+
+ cdf_mem_free(pBssConfig);
+ } /* Allocate memory */
+ }
+
+ if (pfSameIbss) {
+ *pfSameIbss = fSameIbss;
+ }
+ return status;
+}
+
+static void csr_roam_update_connected_profile_from_new_bss(tpAniSirGlobal pMac,
+ uint32_t sessionId,
+ tSirSmeNewBssInfo *pNewBss)
+{
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return;
+ }
+
+ if (pNewBss) {
+ /* Set the operating channel. */
+ pSession->connectedProfile.operationChannel =
+ pNewBss->channelNumber;
+ /* move the BSSId from the BSS description into the connected state information. */
+ cdf_mem_copy(&pSession->connectedProfile.bssid.bytes,
+ &(pNewBss->bssId), sizeof(struct cdf_mac_addr));
+ }
+ return;
+}
+
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+CDF_STATUS csr_roam_set_psk_pmk(tpAniSirGlobal pMac, uint32_t sessionId,
+ uint8_t *pPSK_PMK, size_t pmk_len)
+{
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL("session %d not found"), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+ cdf_mem_copy(pSession->psk_pmk, pPSK_PMK, sizeof(pSession->psk_pmk));
+ pSession->pmk_len = pmk_len;
+ return CDF_STATUS_SUCCESS;
+}
+#endif /* WLAN_FEATURE_ROAM_OFFLOAD */
+
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+static void
+csr_roam_diag_set_pmkid(tCsrRoamSession *pSession)
+{
+ WLAN_HOST_DIAG_EVENT_DEF(secEvent,
+ host_event_wlan_security_payload_type);
+ cdf_mem_set(&secEvent,
+ sizeof(host_event_wlan_security_payload_type), 0);
+ secEvent.eventId = WLAN_SECURITY_EVENT_PMKID_UPDATE;
+ 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 /* FEATURE_WLAN_DIAG_SUPPORT_CSR */
+
+CDF_STATUS
+csr_roam_set_pmkid_cache(tpAniSirGlobal pMac, uint32_t sessionId,
+ tPmkidCacheInfo *pPMKIDCache, uint32_t numItems,
+ bool update_entire_cache)
+{
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+ uint32_t i = 0;
+ tPmkidCacheInfo *pmksa;
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL("session %d not found"), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ sms_log(pMac, LOGW, FL("numItems = %d"), numItems);
+
+ if (numItems > CSR_MAX_PMKID_ALLOWED)
+ return CDF_STATUS_E_INVAL;
+
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+ csr_roam_diag_set_pmkid(pSession);
+#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */
+
+ if (update_entire_cache) {
+ if (numItems && pPMKIDCache) {
+ pSession->NumPmkidCache = (uint16_t) numItems;
+ cdf_mem_copy(pSession->PmkidCacheInfo, pPMKIDCache,
+ sizeof(tPmkidCacheInfo) * numItems);
+ pSession->curr_cache_idx = (uint16_t)numItems;
+ }
+ return CDF_STATUS_SUCCESS;
+ }
+
+ for (i = 0; i < numItems; i++) {
+ pmksa = &pPMKIDCache[i];
+
+ /* Delete the entry if present */
+ csr_roam_del_pmkid_from_cache(pMac, sessionId,
+ pmksa->BSSID.bytes, false);
+
+ /* Add entry to the cache */
+ cdf_copy_macaddr(
+ &pSession->PmkidCacheInfo[pSession->curr_cache_idx].BSSID,
+ &pmksa->BSSID);
+ cdf_mem_copy(
+ pSession->PmkidCacheInfo[pSession->curr_cache_idx].PMKID,
+ pmksa->PMKID, CSR_RSN_PMKID_SIZE);
+
+ /* Increment the CSR local cache index */
+ if (pSession->curr_cache_idx < (CSR_MAX_PMKID_ALLOWED - 1))
+ pSession->curr_cache_idx++;
+ else
+ pSession->curr_cache_idx = 0;
+
+ pSession->NumPmkidCache++;
+ if (pSession->NumPmkidCache > CSR_MAX_PMKID_ALLOWED)
+ pSession->NumPmkidCache = CSR_MAX_PMKID_ALLOWED;
+ }
+ return CDF_STATUS_SUCCESS;
+}
+
+CDF_STATUS csr_roam_del_pmkid_from_cache(tpAniSirGlobal pMac,
+ uint32_t sessionId,
+ const uint8_t *pBSSId,
+ bool flush_cache)
+{
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+ bool fMatchFound = false;
+ uint32_t Index;
+ uint32_t curr_idx;
+ uint32_t i;
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ /* Check if there are no entries to delete */
+ if (0 == pSession->NumPmkidCache) {
+ sms_log(pMac, LOG1, FL("No entries to delete/Flush"));
+ return CDF_STATUS_SUCCESS;
+ }
+
+ if (flush_cache) {
+ /* Flush the entire cache */
+ cdf_mem_zero(pSession->PmkidCacheInfo,
+ sizeof(tPmkidCacheInfo) * CSR_MAX_PMKID_ALLOWED);
+ pSession->NumPmkidCache = 0;
+ pSession->curr_cache_idx = 0;
+ return CDF_STATUS_SUCCESS;
+ }
+
+ /* !flush_cache - so look up in the cache */
+ for (Index = 0; Index < CSR_MAX_PMKID_ALLOWED; Index++) {
+ if (cdf_mem_compare(pSession->PmkidCacheInfo[Index].BSSID.bytes,
+ pBSSId, CDF_MAC_ADDR_SIZE)) {
+ fMatchFound = 1;
+
+ /* Clear this - the matched entry */
+ cdf_mem_zero(&pSession->PmkidCacheInfo[Index],
+ sizeof(tPmkidCacheInfo));
+ break;
+ }
+ }
+
+ if (Index == CSR_MAX_PMKID_ALLOWED && !fMatchFound) {
+ sms_log(pMac, LOG1, FL("No such PMKSA entry exists"
+ MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pBSSId));
+ return CDF_STATUS_SUCCESS;
+ }
+
+ /* Match Found, Readjust the other entries */
+ curr_idx = pSession->curr_cache_idx;
+ if (Index < curr_idx) {
+ for (i = Index; i < (curr_idx - 1); i++) {
+ cdf_mem_copy(&pSession->PmkidCacheInfo[i],
+ &pSession->PmkidCacheInfo[i + 1],
+ sizeof(tPmkidCacheInfo));
+ }
+
+ pSession->curr_cache_idx--;
+ cdf_mem_zero(&pSession->PmkidCacheInfo
+ [pSession->curr_cache_idx],
+ sizeof(tPmkidCacheInfo));
+ } else if (Index > curr_idx) {
+ for (i = Index; i > (curr_idx); i--) {
+ cdf_mem_copy(&pSession->PmkidCacheInfo[i],
+ &pSession->PmkidCacheInfo[i - 1],
+ sizeof(tPmkidCacheInfo));
+ }
+
+ cdf_mem_zero(&pSession->PmkidCacheInfo
+ [pSession->curr_cache_idx],
+ sizeof(tPmkidCacheInfo));
+ }
+
+ /* Decrement the count since an entry has been deleted */
+ pSession->NumPmkidCache--;
+ return CDF_STATUS_SUCCESS;
+}
+
+uint32_t csr_roam_get_num_pmkid_cache(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ return pMac->roam.roamSession[sessionId].NumPmkidCache;
+}
+
+CDF_STATUS csr_roam_get_pmkid_cache(tpAniSirGlobal pMac, uint32_t sessionId,
+ uint32_t *pNum, tPmkidCacheInfo *pPmkidCache)
+{
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+ tPmkidCacheInfo *pmksa;
+ uint16_t i, j;
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL("session %d not found "), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ if (!pNum || !pPmkidCache) {
+ sms_log(pMac, LOGE, FL("Either pNum or pPmkidCache is NULL"));
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ if (pSession->NumPmkidCache == 0) {
+ *pNum = 0;
+ return CDF_STATUS_SUCCESS;
+ }
+
+ if (*pNum < pSession->NumPmkidCache) {
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ if (pSession->NumPmkidCache > CSR_MAX_PMKID_ALLOWED) {
+ sms_log(pMac, LOGE,
+ FL(
+ "NumPmkidCache :%d is more than CSR_MAX_PMKID_ALLOWED, resetting to CSR_MAX_PMKID_ALLOWED"),
+ pSession->NumPmkidCache);
+ pSession->NumPmkidCache = CSR_MAX_PMKID_ALLOWED;
+ }
+
+ for (i = 0, j = 0; ((j < pSession->NumPmkidCache) &&
+ (i < CSR_MAX_PMKID_ALLOWED)); i++) {
+ /* Fill the valid entries */
+ pmksa = &pSession->PmkidCacheInfo[i];
+ if (!cdf_is_macaddr_zero(&pmksa->BSSID)) {
+ cdf_mem_copy(pPmkidCache, pmksa,
+ sizeof(tPmkidCacheInfo));
+ pPmkidCache++;
+ j++;
+ }
+ }
+
+ *pNum = pSession->NumPmkidCache;
+ return CDF_STATUS_SUCCESS;
+}
+
+CDF_STATUS csr_roam_get_wpa_rsn_req_ie(tpAniSirGlobal pMac, uint32_t sessionId,
+ uint32_t *pLen, uint8_t *pBuf)
+{
+ CDF_STATUS status = CDF_STATUS_E_INVAL;
+ uint32_t len;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ if (pLen) {
+ len = *pLen;
+ *pLen = pSession->nWpaRsnReqIeLength;
+ if (pBuf) {
+ if (len >= pSession->nWpaRsnReqIeLength) {
+ cdf_mem_copy(pBuf, pSession->pWpaRsnReqIE,
+ pSession->nWpaRsnReqIeLength);
+ status = CDF_STATUS_SUCCESS;
+ }
+ }
+ }
+ return status;
+}
+
+CDF_STATUS csr_roam_get_wpa_rsn_rsp_ie(tpAniSirGlobal pMac, uint32_t sessionId,
+ uint32_t *pLen, uint8_t *pBuf)
+{
+ CDF_STATUS status = CDF_STATUS_E_INVAL;
+ uint32_t len;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ if (pLen) {
+ len = *pLen;
+ *pLen = pSession->nWpaRsnRspIeLength;
+ if (pBuf) {
+ if (len >= pSession->nWpaRsnRspIeLength) {
+ cdf_mem_copy(pBuf, pSession->pWpaRsnRspIE,
+ pSession->nWpaRsnRspIeLength);
+ status = CDF_STATUS_SUCCESS;
+ }
+ }
+ }
+ return status;
+}
+
+#ifdef FEATURE_WLAN_WAPI
+CDF_STATUS csr_roam_get_wapi_req_ie(tpAniSirGlobal pMac, uint32_t sessionId,
+ uint32_t *pLen, uint8_t *pBuf)
+{
+ CDF_STATUS status = CDF_STATUS_E_INVAL;
+ uint32_t len;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ if (pLen) {
+ len = *pLen;
+ *pLen = pSession->nWapiReqIeLength;
+ if (pBuf) {
+ if (len >= pSession->nWapiReqIeLength) {
+ cdf_mem_copy(pBuf, pSession->pWapiReqIE,
+ pSession->nWapiReqIeLength);
+ status = CDF_STATUS_SUCCESS;
+ }
+ }
+ }
+ return status;
+}
+
+CDF_STATUS csr_roam_get_wapi_rsp_ie(tpAniSirGlobal pMac, uint32_t sessionId,
+ uint32_t *pLen, uint8_t *pBuf)
+{
+ CDF_STATUS status = CDF_STATUS_E_INVAL;
+ uint32_t len;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ if (pLen) {
+ len = *pLen;
+ *pLen = pSession->nWapiRspIeLength;
+ if (pBuf) {
+ if (len >= pSession->nWapiRspIeLength) {
+ cdf_mem_copy(pBuf, pSession->pWapiRspIE,
+ pSession->nWapiRspIeLength);
+ status = CDF_STATUS_SUCCESS;
+ }
+ }
+ }
+ return status;
+}
+#endif /* FEATURE_WLAN_WAPI */
+eRoamCmdStatus csr_get_roam_complete_status(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ eRoamCmdStatus retStatus = eCSR_ROAM_CONNECT_COMPLETION;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return retStatus;
+ }
+
+ if (CSR_IS_ROAMING(pSession)) {
+ retStatus = eCSR_ROAM_ROAMING_COMPLETION;
+ pSession->fRoaming = false;
+ }
+ return retStatus;
+}
+
+/* This function remove the connected BSS from te cached scan result */
+CDF_STATUS
+csr_roam_remove_connected_bss_from_scan_cache(tpAniSirGlobal pMac,
+ tCsrRoamConnectedProfile *pConnProfile)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ tCsrScanResultFilter *pScanFilter = NULL;
+ tListElem *pEntry;
+ tCsrScanResult *pResult;
+ tDot11fBeaconIEs *pIes;
+ bool fMatch;
+
+ if ((cdf_is_macaddr_zero(&pConnProfile->bssid) ||
+ cdf_is_macaddr_broadcast(&pConnProfile->bssid)))
+ return status;
+ /*
+ * Prepare the filter. Only fill in the necessary fields. Not all fields
+ * are needed
+ */
+ pScanFilter = cdf_mem_malloc(sizeof(tCsrScanResultFilter));
+ if (NULL == pScanFilter)
+ return CDF_STATUS_E_NOMEM;
+
+ cdf_mem_set(pScanFilter, sizeof(tCsrScanResultFilter), 0);
+ pScanFilter->BSSIDs.bssid = cdf_mem_malloc(sizeof(struct cdf_mac_addr));
+ if (NULL == pScanFilter->BSSIDs.bssid) {
+ cdf_mem_free(pScanFilter);
+ return CDF_STATUS_E_NOMEM;
+ }
+ cdf_mem_copy(pScanFilter->BSSIDs.bssid,
+ &pConnProfile->bssid, sizeof(struct cdf_mac_addr));
+ pScanFilter->BSSIDs.numOfBSSIDs = 1;
+ if (!csr_is_nullssid(pConnProfile->SSID.ssId,
+ pConnProfile->SSID.length)) {
+ pScanFilter->SSIDs.SSIDList = cdf_mem_malloc(
+ sizeof(tCsrSSIDInfo));
+ if (NULL == pScanFilter->SSIDs.SSIDList) {
+ csr_free_scan_filter(pMac, pScanFilter);
+ cdf_mem_free(pScanFilter);
+ return CDF_STATUS_E_NOMEM;
+ }
+ cdf_mem_copy(&pScanFilter->SSIDs.SSIDList[0].SSID,
+ &pConnProfile->SSID, sizeof(tSirMacSSid));
+ }
+ pScanFilter->authType.numEntries = 1;
+ pScanFilter->authType.authType[0] = pConnProfile->AuthType;
+ pScanFilter->BSSType = pConnProfile->BSSType;
+ pScanFilter->EncryptionType.numEntries = 1;
+ pScanFilter->EncryptionType.encryptionType[0] =
+ pConnProfile->EncryptionType;
+ pScanFilter->mcEncryptionType.numEntries = 1;
+ pScanFilter->mcEncryptionType.encryptionType[0] =
+ pConnProfile->mcEncryptionType;
+ /* We ignore the channel for now, BSSID should be enough */
+ pScanFilter->ChannelInfo.numOfChannels = 0;
+ /* Also ignore the following fields */
+ pScanFilter->uapsd_mask = 0;
+ pScanFilter->bWPSAssociation = false;
+ pScanFilter->bOSENAssociation = false;
+ pScanFilter->countryCode[0] = 0;
+ pScanFilter->phyMode = eCSR_DOT11_MODE_AUTO;
+ csr_ll_lock(&pMac->scan.scanResultList);
+ pEntry = csr_ll_peek_head(&pMac->scan.scanResultList, LL_ACCESS_NOLOCK);
+ while (pEntry) {
+ pResult = GET_BASE_ADDR(pEntry, tCsrScanResult, Link);
+ pIes = (tDot11fBeaconIEs *) (pResult->Result.pvIes);
+ fMatch = csr_match_bss(pMac, &pResult->Result.BssDescriptor,
+ pScanFilter, NULL, NULL, NULL, &pIes);
+ /* Release the IEs allocated by csr_match_bss is needed */
+ if (!pResult->Result.pvIes) {
+ /*
+ * need to free the IEs since it is allocated
+ * by csr_match_bss
+ */
+ cdf_mem_free(pIes);
+ }
+ if (fMatch) {
+ /* We found the one */
+ if (csr_ll_remove_entry(&pMac->scan.scanResultList,
+ pEntry, LL_ACCESS_NOLOCK))
+ /* Free the memory */
+ csr_free_scan_result_entry(pMac, pResult);
+ break;
+ }
+ pEntry = csr_ll_next(&pMac->scan.scanResultList,
+ pEntry, LL_ACCESS_NOLOCK);
+ } /* while */
+ csr_ll_unlock(&pMac->scan.scanResultList);
+ csr_free_scan_filter(pMac, pScanFilter);
+ cdf_mem_free(pScanFilter);
+ return status;
+}
+
+static CDF_STATUS csr_roam_start_wds(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamProfile *pProfile,
+ tSirBssDescription *pBssDesc)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+ tBssConfigParam bssConfig;
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ if (csr_is_conn_state_ibss(pMac, sessionId)) {
+ status =
+ csr_roam_issue_stop_bss(pMac, sessionId,
+ eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING);
+ } else if (csr_is_conn_state_connected_infra(pMac, sessionId)) {
+ /* Disassociate from the connected Infrastructure network... */
+ status =
+ csr_roam_issue_disassociate(pMac, sessionId,
+ eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING,
+ false);
+ } else {
+ /* We don't expect Bt-AMP HDD not to disconnect the last connection first at this time. */
+ /* Otherwise we need to add code to handle the */
+ /* situation just like IBSS. Though for WDS station, we need to send disassoc to PE first then */
+ /* send stop_bss to PE, before we can continue. */
+
+ if (csr_is_conn_state_wds(pMac, sessionId)) {
+ CDF_ASSERT(0);
+ return CDF_STATUS_E_FAILURE;
+ }
+ cdf_mem_set(&bssConfig, sizeof(tBssConfigParam), 0);
+ /* Assume HDD provide bssid in profile */
+ cdf_copy_macaddr(&pSession->bssParams.bssid,
+ pProfile->BSSIDs.bssid);
+ /* there is no Bss description before we start an WDS so we need */
+ /* to adopt all Bss configuration parameters from the Profile. */
+ status =
+ csr_roam_prepare_bss_config_from_profile(pMac, pProfile,
+ &bssConfig, pBssDesc);
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ /* Save profile for late use */
+ csr_free_roam_profile(pMac, sessionId);
+ pSession->pCurRoamProfile =
+ cdf_mem_malloc(sizeof(tCsrRoamProfile));
+ if (pSession->pCurRoamProfile != NULL) {
+ cdf_mem_set(pSession->pCurRoamProfile,
+ sizeof(tCsrRoamProfile), 0);
+ csr_roam_copy_profile(pMac,
+ pSession->pCurRoamProfile,
+ pProfile);
+ }
+ /* Prepare some more parameters for this WDS */
+ csr_roam_prepare_bss_params(pMac, sessionId, pProfile, NULL,
+ &bssConfig, NULL);
+ status =
+ csr_roam_set_bss_config_cfg(pMac, sessionId, pProfile,
+ NULL, &bssConfig, NULL,
+ false);
+ }
+ }
+
+ return status;
+}
+
+/**
+ * csr_add_supported_5Ghz_channels()- Add valid 5Ghz channels
+ * in Join req.
+ * @mac_ctx: pointer to global mac structure
+ * @csr_join_req: join req sent to lim
+ *
+ * This function is called to update valid 5Ghz channels
+ * in Join req.
+ *
+ * Return: void
+ */
+static void csr_add_supported_5Ghz_channels(tpAniSirGlobal mac_ctx,
+ tSirSmeJoinReq *csr_join_req)
+{
+ uint16_t i, j;
+ uint32_t size = 0;
+
+ if (!csr_join_req) {
+ sms_log(mac_ctx, LOGE, FL(" csr_join_reqis NULL"));
+ return;
+ }
+
+ size = sizeof(mac_ctx->roam.validChannelList);
+ if (CDF_IS_STATUS_SUCCESS
+ (csr_get_cfg_valid_channels(mac_ctx,
+ (uint8_t *) mac_ctx->roam.validChannelList,
+ &size))) {
+ for (i = 0, j = 0; i < size; i++) {
+ /* Only add 5ghz channels.*/
+ if (CDS_IS_CHANNEL_5GHZ
+ (mac_ctx->roam.validChannelList[i])) {
+ csr_join_req->supportedChannels.channelList[j] =
+ mac_ctx->roam.validChannelList[i];
+ j++;
+ }
+ }
+ csr_join_req->supportedChannels.numChnl = j;
+ } else {
+ sms_log(mac_ctx, LOGE,
+ FL("can not find any valid channel"));
+ csr_join_req->supportedChannels.numChnl = 0;
+ }
+}
+
+/**
+ * The communication between HDD and LIM is thru mailbox (MB).
+ * Both sides will access the data structure "tSirSmeJoinReq".
+ * The rule is, while the components of "tSirSmeJoinReq" can be accessed in the
+ * regular way like tSirSmeJoinReq.assocType, this guideline stops at component
+ * tSirRSNie;
+ * any acces to the components after tSirRSNie is forbidden because the space
+ * from tSirRSNie is squeezed with the component "tSirBssDescription" and since
+ * the size of actual 'tSirBssDescription' varies, the receiving side should
+ * keep in mind not to access the components DIRECTLY after tSirRSNie.
+ */
+CDF_STATUS csr_send_join_req_msg(tpAniSirGlobal pMac, uint32_t sessionId,
+ tSirBssDescription *pBssDescription,
+ tCsrRoamProfile *pProfile,
+ tDot11fBeaconIEs *pIes, uint16_t messageType)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ uint8_t acm_mask = 0, uapsd_mask;
+ uint16_t msgLen, ieLen;
+ tSirMacRateSet OpRateSet;
+ tSirMacRateSet ExRateSet;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+ uint32_t dwTmp, ucDot11Mode = 0;
+ /* RSN MAX is bigger than WPA MAX */
+ uint8_t wpaRsnIE[DOT11F_IE_RSN_MAX_LEN];
+ uint8_t txBFCsnValue = 0;
+ tSirSmeJoinReq *csr_join_req;
+ tSirMacCapabilityInfo *pAP_capabilityInfo;
+ tAniBool fTmp;
+ int8_t pwrLimit = 0;
+ struct ps_global_info *ps_global_info = &pMac->sme.ps_global_info;
+ struct ps_params *ps_param = &ps_global_info->ps_params[sessionId];
+ uint8_t ese_config = 0;
+
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+ /* To satisfy klockworks */
+ if (NULL == pBssDescription) {
+ sms_log(pMac, LOGE, FL(" pBssDescription is NULL"));
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ do {
+ pSession->joinFailStatusCode.statusCode = eSIR_SME_SUCCESS;
+ pSession->joinFailStatusCode.reasonCode = 0;
+ cdf_mem_copy(&pSession->joinFailStatusCode.bssId,
+ &pBssDescription->bssId, sizeof(tSirMacAddr));
+ /*
+ * the tSirSmeJoinReq which includes a single
+ * bssDescription. it includes a single uint32_t for the
+ * IE fields, but the length field in the bssDescription
+ * needs to be interpreted to determine length of IE fields
+ * So, take the size of the tSirSmeJoinReq, subtract size of
+ * bssDescription, add the number of bytes indicated by the
+ * length field of the bssDescription, add the size of length
+ * field because it not included in the lenghth field.
+ */
+ msgLen = sizeof(tSirSmeJoinReq) - sizeof(*pBssDescription) +
+ pBssDescription->length +
+ sizeof(pBssDescription->length) +
+ /*
+ * add in the size of the WPA IE that
+ * we may build.
+ */
+ sizeof(tCsrWpaIe) + sizeof(tCsrWpaAuthIe) +
+ sizeof(uint16_t);
+ csr_join_req = cdf_mem_malloc(msgLen);
+ if (NULL == csr_join_req)
+ status = CDF_STATUS_E_NOMEM;
+ else
+ status = CDF_STATUS_SUCCESS;
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ break;
+ cdf_mem_set(csr_join_req, msgLen, 0);
+ csr_join_req->messageType = messageType;
+ csr_join_req->length = msgLen;
+ csr_join_req->sessionId = (uint8_t) sessionId;
+ csr_join_req->transactionId = 0;
+ if (pIes->SSID.present && pIes->SSID.num_ssid) {
+ csr_join_req->ssId.length = pIes->SSID.num_ssid;
+ cdf_mem_copy(&csr_join_req->ssId.ssId, pIes->SSID.ssid,
+ pIes->SSID.num_ssid);
+ } else
+ csr_join_req->ssId.length = 0;
+ cdf_mem_copy(&csr_join_req->selfMacAddr, &pSession->selfMacAddr,
+ sizeof(tSirMacAddr));
+ /* bsstype */
+ dwTmp = csr_translate_bsstype_to_mac_type
+ (pProfile->BSSType);
+ /* Override BssType for BTAMP */
+ if (dwTmp == eSIR_BTAMP_STA_MODE)
+ dwTmp = eSIR_BTAMP_AP_MODE;
+ csr_join_req->bsstype = dwTmp;
+ /* dot11mode */
+ ucDot11Mode =
+ csr_translate_to_wni_cfg_dot11_mode(pMac,
+ pSession->bssParams.
+ uCfgDot11Mode);
+ if (pBssDescription->channelId <= 14
+ && false == pMac->roam.configParam.enableVhtFor24GHz
+ && WNI_CFG_DOT11_MODE_11AC == ucDot11Mode) {
+ /* Need to disable VHT operation in 2.4 GHz band */
+ ucDot11Mode = WNI_CFG_DOT11_MODE_11N;
+ }
+ csr_join_req->dot11mode = (uint8_t) ucDot11Mode;
+#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH
+ csr_join_req->cc_switch_mode =
+ pMac->roam.configParam.cc_switch_mode;
+#endif
+ csr_join_req->staPersona = (uint8_t) pProfile->csrPersona;
+ csr_join_req->cbMode = (uint8_t) pSession->bssParams.cbMode;
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ FL("CSR PERSONA=%d CSR CbMode %d"),
+ pProfile->csrPersona, pSession->bssParams.cbMode);
+ csr_join_req->uapsdPerAcBitmask = pProfile->uapsd_mask;
+ status =
+ csr_get_rate_set(pMac, pProfile,
+ (eCsrPhyMode) pProfile->phyMode,
+ pBssDescription, pIes, &OpRateSet,
+ &ExRateSet);
+ ps_param->uapsd_per_ac_bit_mask =
+ pProfile->uapsd_mask;
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ /* OperationalRateSet */
+ if (OpRateSet.numRates) {
+ csr_join_req->operationalRateSet.numRates =
+ OpRateSet.numRates;
+ cdf_mem_copy(&csr_join_req->operationalRateSet.
+ rate, OpRateSet.rate,
+ OpRateSet.numRates);
+ } else
+ csr_join_req->operationalRateSet.numRates = 0;
+
+ /* ExtendedRateSet */
+ if (ExRateSet.numRates) {
+ csr_join_req->extendedRateSet.numRates =
+ ExRateSet.numRates;
+ cdf_mem_copy(&csr_join_req->extendedRateSet.
+ rate, ExRateSet.rate,
+ ExRateSet.numRates);
+ } else
+ csr_join_req->extendedRateSet.numRates = 0;
+ } else {
+ csr_join_req->operationalRateSet.numRates = 0;
+ csr_join_req->extendedRateSet.numRates = 0;
+ }
+ /* rsnIE */
+ if (csr_is_profile_wpa(pProfile)) {
+ /* Insert the Wpa IE into the join request */
+ ieLen =
+ csr_retrieve_wpa_ie(pMac, pProfile,
+ pBssDescription, pIes,
+ (tCsrWpaIe *) (wpaRsnIE));
+ } else if (csr_is_profile_rsn(pProfile)) {
+ /* Insert the RSN IE into the join request */
+ ieLen =
+ csr_retrieve_rsn_ie(pMac, sessionId, pProfile,
+ pBssDescription, pIes,
+ (tCsrRSNIe *) (wpaRsnIE));
+ }
+#ifdef FEATURE_WLAN_WAPI
+ else if (csr_is_profile_wapi(pProfile)) {
+ /* Insert the WAPI IE into the join request */
+ ieLen =
+ csr_retrieve_wapi_ie(pMac, sessionId, pProfile,
+ pBssDescription, pIes,
+ (tCsrWapiIe *) (wpaRsnIE));
+ }
+#endif /* FEATURE_WLAN_WAPI */
+ else {
+ ieLen = 0;
+ }
+ /* remember the IE for future use */
+ if (ieLen) {
+ if (ieLen > DOT11F_IE_RSN_MAX_LEN) {
+ sms_log(pMac, LOGE,
+ FL
+ (" WPA RSN IE length :%d is more than DOT11F_IE_RSN_MAX_LEN, resetting to %d"),
+ ieLen, DOT11F_IE_RSN_MAX_LEN);
+ ieLen = DOT11F_IE_RSN_MAX_LEN;
+ }
+#ifdef FEATURE_WLAN_WAPI
+ if (csr_is_profile_wapi(pProfile)) {
+ /* Check whether we need to allocate more mem */
+ if (ieLen > pSession->nWapiReqIeLength) {
+ if (pSession->pWapiReqIE
+ && pSession->nWapiReqIeLength) {
+ cdf_mem_free(pSession->
+ pWapiReqIE);
+ }
+ pSession->pWapiReqIE =
+ cdf_mem_malloc(ieLen);
+ if (NULL == pSession->pWapiReqIE)
+ status = CDF_STATUS_E_NOMEM;
+ else
+ status = CDF_STATUS_SUCCESS;
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ break;
+ }
+ pSession->nWapiReqIeLength = ieLen;
+ cdf_mem_copy(pSession->pWapiReqIE, wpaRsnIE,
+ ieLen);
+ csr_join_req->rsnIE.length = ieLen;
+ cdf_mem_copy(&csr_join_req->rsnIE.rsnIEdata,
+ wpaRsnIE, ieLen);
+ } else /* should be WPA/WPA2 otherwise */
+#endif /* FEATURE_WLAN_WAPI */
+ {
+ /* Check whether we need to allocate more mem */
+ if (ieLen > pSession->nWpaRsnReqIeLength) {
+ if (pSession->pWpaRsnReqIE
+ && pSession->nWpaRsnReqIeLength) {
+ cdf_mem_free(pSession->
+ pWpaRsnReqIE);
+ }
+ pSession->pWpaRsnReqIE =
+ cdf_mem_malloc(ieLen);
+ if (NULL == pSession->pWpaRsnReqIE)
+ status = CDF_STATUS_E_NOMEM;
+ else
+ status = CDF_STATUS_SUCCESS;
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ break;
+ }
+ pSession->nWpaRsnReqIeLength = ieLen;
+ cdf_mem_copy(pSession->pWpaRsnReqIE, wpaRsnIE,
+ ieLen);
+ csr_join_req->rsnIE.length = ieLen;
+ cdf_mem_copy(&csr_join_req->rsnIE.rsnIEdata,
+ wpaRsnIE, ieLen);
+ }
+ } else {
+ /* free whatever old info */
+ pSession->nWpaRsnReqIeLength = 0;
+ if (pSession->pWpaRsnReqIE) {
+ cdf_mem_free(pSession->pWpaRsnReqIE);
+ pSession->pWpaRsnReqIE = NULL;
+ }
+#ifdef FEATURE_WLAN_WAPI
+ pSession->nWapiReqIeLength = 0;
+ if (pSession->pWapiReqIE) {
+ cdf_mem_free(pSession->pWapiReqIE);
+ pSession->pWapiReqIE = NULL;
+ }
+#endif /* FEATURE_WLAN_WAPI */
+ csr_join_req->rsnIE.length = 0;
+ }
+#ifdef FEATURE_WLAN_ESE
+ if (eWNI_SME_JOIN_REQ == messageType)
+ csr_join_req->cckmIE.length = 0;
+ else if (eWNI_SME_REASSOC_REQ == messageType) {
+ /* cckmIE */
+ if (csr_is_profile_ese(pProfile)) {
+ /* Insert the CCKM IE into the join request */
+#ifdef FEATURE_WLAN_ESE_UPLOAD
+ ieLen = pSession->suppCckmIeInfo.cckmIeLen;
+ cdf_mem_copy((void *)(wpaRsnIE),
+ pSession->suppCckmIeInfo.cckmIe,
+ ieLen);
+#else
+ ieLen = csrConstructEseCckmIe(pMac,
+ pSession,
+ pProfile,
+ pBssDescription,
+ pSession->
+ pWpaRsnReqIE,
+ pSession->
+ nWpaRsnReqIeLength,
+ (void *)(wpaRsnIE));
+#endif /* FEATURE_WLAN_ESE_UPLOAD */
+ } else
+ ieLen = 0;
+ /*
+ * If present, copy the IE into the
+ * eWNI_SME_REASSOC_REQ message buffer
+ */
+ if (ieLen) {
+ /*
+ * Copy the CCKM IE over from the temp
+ * buffer (wpaRsnIE)
+ */
+ csr_join_req->cckmIE.length = ieLen;
+ cdf_mem_copy(&csr_join_req->cckmIE.cckmIEdata,
+ wpaRsnIE, ieLen);
+ } else
+ csr_join_req->cckmIE.length = 0;
+ }
+#endif /* FEATURE_WLAN_ESE */
+ /* addIEScan */
+ if (pProfile->nAddIEScanLength && pProfile->pAddIEScan) {
+ ieLen = pProfile->nAddIEScanLength;
+ if (ieLen > pSession->nAddIEScanLength) {
+ if (pSession->pAddIEScan
+ && pSession->nAddIEScanLength) {
+ cdf_mem_free(pSession->pAddIEScan);
+ }
+ pSession->pAddIEScan = cdf_mem_malloc(ieLen);
+ if (NULL == pSession->pAddIEScan)
+ status = CDF_STATUS_E_NOMEM;
+ else
+ status = CDF_STATUS_SUCCESS;
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ break;
+ }
+ pSession->nAddIEScanLength = ieLen;
+ cdf_mem_copy(pSession->pAddIEScan, pProfile->pAddIEScan,
+ ieLen);
+ csr_join_req->addIEScan.length = ieLen;
+ cdf_mem_copy(&csr_join_req->addIEScan.addIEdata,
+ pProfile->pAddIEScan, ieLen);
+ } else {
+ pSession->nAddIEScanLength = 0;
+ if (pSession->pAddIEScan) {
+ cdf_mem_free(pSession->pAddIEScan);
+ pSession->pAddIEScan = NULL;
+ }
+ csr_join_req->addIEScan.length = 0;
+ }
+ /* addIEAssoc */
+ if (pProfile->nAddIEAssocLength && pProfile->pAddIEAssoc) {
+ ieLen = pProfile->nAddIEAssocLength;
+ if (ieLen > pSession->nAddIEAssocLength) {
+ if (pSession->pAddIEAssoc
+ && pSession->nAddIEAssocLength) {
+ cdf_mem_free(pSession->pAddIEAssoc);
+ }
+ pSession->pAddIEAssoc = cdf_mem_malloc(ieLen);
+ if (NULL == pSession->pAddIEAssoc)
+ status = CDF_STATUS_E_NOMEM;
+ else
+ status = CDF_STATUS_SUCCESS;
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ break;
+ }
+ pSession->nAddIEAssocLength = ieLen;
+ cdf_mem_copy(pSession->pAddIEAssoc,
+ pProfile->pAddIEAssoc, ieLen);
+ csr_join_req->addIEAssoc.length = ieLen;
+ cdf_mem_copy(&csr_join_req->addIEAssoc.addIEdata,
+ pProfile->pAddIEAssoc, ieLen);
+ } else {
+ pSession->nAddIEAssocLength = 0;
+ if (pSession->pAddIEAssoc) {
+ cdf_mem_free(pSession->pAddIEAssoc);
+ pSession->pAddIEAssoc = NULL;
+ }
+ csr_join_req->addIEAssoc.length = 0;
+ }
+
+ if (eWNI_SME_REASSOC_REQ == messageType) {
+ /* Unmask any AC in reassoc that is ACM-set */
+ uapsd_mask = (uint8_t) pProfile->uapsd_mask;
+ if (uapsd_mask && (NULL != pBssDescription)) {
+ if (CSR_IS_QOS_BSS(pIes)
+ && CSR_IS_UAPSD_BSS(pIes))
+#ifndef WLAN_MDM_CODE_REDUCTION_OPT
+ acm_mask =
+ sme_qos_get_acm_mask(pMac,
+ pBssDescription,
+ pIes);
+#endif /* WLAN_MDM_CODE_REDUCTION_OPT */
+ else
+ uapsd_mask = 0;
+ }
+ }
+
+ csr_join_req->UCEncryptionType =
+ csr_translate_encrypt_type_to_ed_type
+ (pProfile->negotiatedUCEncryptionType);
+
+ csr_join_req->MCEncryptionType =
+ csr_translate_encrypt_type_to_ed_type
+ (pProfile->negotiatedMCEncryptionType);
+#ifdef WLAN_FEATURE_11W
+ if (pProfile->MFPEnabled)
+ csr_join_req->MgmtEncryptionType = eSIR_ED_AES_128_CMAC;
+ else
+ csr_join_req->MgmtEncryptionType = eSIR_ED_NONE;
+#endif
+#ifdef FEATURE_WLAN_ESE
+ ese_config = pMac->roam.configParam.isEseIniFeatureEnabled;
+#endif
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ pProfile->MDID.mdiePresent = pBssDescription->mdiePresent;
+ if (csr_is_profile11r(pProfile)
+#ifdef FEATURE_WLAN_ESE
+ &&
+ !((pProfile->negotiatedAuthType ==
+ eCSR_AUTH_TYPE_OPEN_SYSTEM) && (pIes->ESEVersion.present)
+ && (ese_config))
+#endif
+ )
+ csr_join_req->is11Rconnection = true;
+ else
+ csr_join_req->is11Rconnection = false;
+#endif
+#ifdef FEATURE_WLAN_ESE
+ if (true == ese_config)
+ csr_join_req->isESEFeatureIniEnabled = true;
+ else
+ csr_join_req->isESEFeatureIniEnabled = false;
+
+ /* A profile can not be both ESE and 11R. But an 802.11R AP
+ * may be advertising support for ESE as well. So if we are
+ * associating Open or explicitly ESE then we will get ESE.
+ * If we are associating explictly 11R only then we will get
+ * 11R.
+ */
+ if ((csr_is_profile_ese(pProfile) ||
+ ((pIes->ESEVersion.present) &&
+ (pProfile->negotiatedAuthType ==
+ eCSR_AUTH_TYPE_OPEN_SYSTEM)))
+ && (ese_config))
+ csr_join_req->isESEconnection = true;
+ else
+ csr_join_req->isESEconnection = false;
+
+ if (eWNI_SME_JOIN_REQ == messageType) {
+ tESETspecInfo eseTspec;
+ /*
+ * ESE-Tspec IEs in the ASSOC request is presently not
+ * supported. so nullify the TSPEC parameters
+ */
+ cdf_mem_set(&eseTspec, sizeof(tESETspecInfo), 0);
+ cdf_mem_copy(&csr_join_req->eseTspecInfo,
+ &eseTspec, sizeof(tESETspecInfo));
+ } else if (eWNI_SME_REASSOC_REQ == messageType) {
+ if ((csr_is_profile_ese(pProfile) ||
+ ((pIes->ESEVersion.present)
+ && (pProfile->negotiatedAuthType ==
+ eCSR_AUTH_TYPE_OPEN_SYSTEM))) &&
+ (ese_config)) {
+ tESETspecInfo eseTspec;
+ cdf_mem_set(&eseTspec, sizeof(tESETspecInfo),
+ 0);
+ eseTspec.numTspecs =
+ sme_qos_ese_retrieve_tspec_info(pMac,
+ sessionId,
+ (tTspecInfo *) &eseTspec.
+ tspec[0]);
+ csr_join_req->eseTspecInfo.numTspecs =
+ eseTspec.numTspecs;
+ if (eseTspec.numTspecs) {
+ cdf_mem_copy(&csr_join_req->eseTspecInfo
+ .tspec[0],
+ &eseTspec.tspec[0],
+ (eseTspec.numTspecs *
+ sizeof(tTspecInfo)));
+ }
+ } else {
+ tESETspecInfo eseTspec;
+ /**
+ * ESE-Tspec IEs in the ASSOC request is
+ * presently not supported. so nullify the TSPEC
+ * parameters
+ */
+ cdf_mem_set(&eseTspec, sizeof(tESETspecInfo),
+ 0);
+ cdf_mem_copy(&csr_join_req->eseTspecInfo,
+ &eseTspec,
+ sizeof(tESETspecInfo));
+ }
+ }
+#endif /* FEATURE_WLAN_ESE */
+#if defined WLAN_FEATURE_VOWIFI_11R || defined FEATURE_WLAN_ESE || defined(FEATURE_WLAN_LFR)
+ if (ese_config
+#ifdef FEATURE_WLAN_LFR
+ || csr_roam_is_fast_roam_enabled(pMac, sessionId)
+#endif
+ ) {
+ csr_join_req->isFastTransitionEnabled = true;
+ } else {
+ csr_join_req->isFastTransitionEnabled = false;
+ }
+#endif
+#ifdef FEATURE_WLAN_LFR
+ if (csr_roam_is_fast_roam_enabled(pMac, sessionId))
+ csr_join_req->isFastRoamIniFeatureEnabled = true;
+ else
+ csr_join_req->isFastRoamIniFeatureEnabled = false;
+#endif
+
+ csr_join_req->txLdpcIniFeatureEnabled =
+ (uint8_t) pMac->roam.configParam.txLdpcEnable;
+
+ if ((csr_is11h_supported(pMac))
+ && (CDS_IS_CHANNEL_5GHZ(pBssDescription->channelId))
+ && (pIes->Country.present)
+ && (!pMac->roam.configParam.
+ fSupplicantCountryCodeHasPriority)) {
+ csr_save_to_channel_power2_g_5_g(pMac,
+ pIes->Country.num_triplets *
+ sizeof(tSirMacChanInfo),
+ (tSirMacChanInfo *)
+ (&pIes->Country.triplets[0]));
+ csr_apply_power2_current(pMac);
+ }
+ cdf_mem_copy(&csr_join_req->htConfig,
+ &pSession->htConfig, sizeof(tSirHTConfig));
+#ifdef WLAN_FEATURE_11AC
+ csr_join_req->txBFIniFeatureEnabled =
+ (uint8_t) pMac->roam.configParam.txBFEnable;
+
+ if (pMac->roam.configParam.txBFEnable) {
+ txBFCsnValue =
+ (uint8_t)pMac->roam.configParam.txBFCsnValue;
+ if (IS_BSS_VHT_CAPABLE(pIes->VHTCaps) &&
+ pIes->VHTCaps.numSoundingDim)
+ txBFCsnValue = CDF_MIN(txBFCsnValue,
+ pIes->VHTCaps.numSoundingDim);
+ else if (IS_BSS_VHT_CAPABLE(pIes->vendor2_ie.VHTCaps)
+ && pIes->vendor2_ie.VHTCaps.numSoundingDim)
+ txBFCsnValue = CDF_MIN(txBFCsnValue,
+ pIes->vendor2_ie.VHTCaps.numSoundingDim);
+ }
+ csr_join_req->txBFCsnValue = txBFCsnValue;
+
+ csr_join_req->txMuBformee =
+ (uint8_t) pMac->roam.configParam.txMuBformee;
+
+ csr_join_req->enableVhtpAid =
+ (uint8_t) pMac->roam.configParam.enableVhtpAid;
+
+ csr_join_req->enableVhtGid =
+ (uint8_t) pMac->roam.configParam.enableVhtGid;
+
+#endif
+ csr_join_req->enableAmpduPs =
+ (uint8_t) pMac->roam.configParam.enableAmpduPs;
+
+ csr_join_req->enableHtSmps =
+ (uint8_t) pMac->roam.configParam.enableHtSmps;
+
+ csr_join_req->htSmps = (uint8_t) pMac->roam.configParam.htSmps;
+
+ csr_join_req->isAmsduSupportInAMPDU =
+ (uint8_t) pMac->roam.configParam.isAmsduSupportInAMPDU;
+
+ if (pMac->roam.roamSession[sessionId].fWMMConnection)
+ csr_join_req->isWMEenabled = true;
+ else
+ csr_join_req->isWMEenabled = false;
+
+ if (pMac->roam.roamSession[sessionId].fQOSConnection)
+ csr_join_req->isQosEnabled = true;
+ else
+ csr_join_req->isQosEnabled = false;
+
+ if (pProfile->bOSENAssociation)
+ csr_join_req->isOSENConnection = true;
+ else
+ csr_join_req->isOSENConnection = false;
+
+ pAP_capabilityInfo =
+ (tSirMacCapabilityInfo *)
+ &pBssDescription->capabilityInfo;
+ /*
+ * tell the target AP my 11H capability only if both AP and STA
+ * support
+ * 11H and the channel being used is 11a
+ */
+ if (csr_is11h_supported(pMac) && pAP_capabilityInfo->spectrumMgt
+ && eSIR_11A_NW_TYPE == pBssDescription->nwType) {
+ fTmp = (tAniBool) 1;
+ } else
+ fTmp = (tAniBool) 0;
+
+ csr_join_req->spectrumMgtIndicator = fTmp;
+ csr_join_req->powerCap.minTxPower = MIN_TX_PWR_CAP;
+ /*
+ * This is required for 11k test VoWiFi Ent: Test 2.
+ * We need the power capabilities for Assoc Req.
+ * This macro is provided by the halPhyCfg.h. We pick our
+ * max and min capability by the halPhy provided macros
+ */
+ pwrLimit = csr_get_cfg_max_tx_power(pMac,
+ pBssDescription->channelId);
+ if (0 != pwrLimit)
+ csr_join_req->powerCap.maxTxPower = pwrLimit;
+ else
+ csr_join_req->powerCap.maxTxPower = MAX_TX_PWR_CAP;
+
+ csr_add_supported_5Ghz_channels(pMac, csr_join_req);
+
+ csr_join_req->uapsdPerAcBitmask = (uint8_t)pProfile->uapsd_mask;
+ /* Move the entire BssDescription into the join request. */
+ cdf_mem_copy(&csr_join_req->bssDescription, pBssDescription,
+ pBssDescription->length +
+ sizeof(pBssDescription->length));
+
+ /*
+ * conc_custom_rule1:
+ * If SAP comes up first and STA comes up later then SAP
+ * need to follow STA's channel in 2.4Ghz. In following if
+ * condition we are adding sanity check, just to make sure that
+ * if this rule is enabled then don't allow STA to connect on
+ * 5gz channel and also by this time SAP's channel should be the
+ * same as STA's channel.
+ */
+ if (pMac->roam.configParam.conc_custom_rule1) {
+ if ((0 ==
+ pMac->
+ roam.configParam.is_sta_connection_in_5gz_enabled)
+ && CDS_IS_CHANNEL_5GHZ(pBssDescription->
+ channelId)) {
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_ERROR,
+ FL("STA-conn on 5G isn't allowed"));
+ status = CDF_STATUS_E_FAILURE;
+ break;
+ }
+ if (!CDS_IS_CHANNEL_5GHZ(pBssDescription->channelId) &&
+ (false == csr_is_conn_allow_2g_band(pMac,
+ pBssDescription->channelId))) {
+ status = CDF_STATUS_E_FAILURE;
+ break;
+ }
+ }
+
+ /*
+ * conc_custom_rule2:
+ * If P2PGO comes up first and STA comes up later then P2PGO
+ * need to follow STA's channel in 5Ghz. In following if
+ * condition we are just adding sanity check to make sure that
+ * by this time P2PGO's channel is same as STA's channel.
+ */
+ if (pMac->roam.configParam.conc_custom_rule2) {
+ if (!CDS_IS_CHANNEL_24GHZ(pBssDescription->channelId) &&
+ (false == csr_is_conn_allow_5g_band(pMac,
+ pBssDescription->channelId))) {
+ status = CDF_STATUS_E_FAILURE;
+ break;
+ }
+ }
+ status = cds_send_mb_message_to_mac(csr_join_req);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ /*
+ * cds_send_mb_message_to_mac would've released the mem
+ * allocated by csr_join_req. Let's make it defensive by
+ * assigning NULL to the pointer.
+ */
+ csr_join_req = NULL;
+ break;
+ } else {
+#ifndef WLAN_MDM_CODE_REDUCTION_OPT
+ if (eWNI_SME_JOIN_REQ == messageType) {
+ /* Notify QoS module that join happening */
+ pSession->join_bssid_count++;
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_DEBUG,
+ "BSSID Count = %d",
+ pSession->join_bssid_count);
+ sme_qos_csr_event_ind(pMac, (uint8_t) sessionId,
+ SME_QOS_CSR_JOIN_REQ, NULL);
+ } else if (eWNI_SME_REASSOC_REQ == messageType) {
+ /* Notify QoS module that reassoc happening */
+ sme_qos_csr_event_ind(pMac, (uint8_t) sessionId,
+ SME_QOS_CSR_REASSOC_REQ,
+ NULL);
+ }
+#endif
+ }
+ } while (0);
+
+ /* Clean up the memory in case of any failure */
+ if (!CDF_IS_STATUS_SUCCESS(status) && (NULL != csr_join_req))
+ cdf_mem_free(csr_join_req);
+
+ return status;
+}
+
+/* */
+CDF_STATUS csr_send_mb_disassoc_req_msg(tpAniSirGlobal pMac, uint32_t sessionId,
+ tSirMacAddr bssId, uint16_t reasonCode)
+{
+ tSirSmeDisassocReq *pMsg;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!CSR_IS_SESSION_VALID(pMac, sessionId))
+ return CDF_STATUS_E_FAILURE;
+
+ pMsg = cdf_mem_malloc(sizeof(tSirSmeDisassocReq));
+ if (NULL == pMsg)
+ return CDF_STATUS_E_NOMEM;
+
+ cdf_mem_set(pMsg, sizeof(tSirSmeDisassocReq), 0);
+ pMsg->messageType = eWNI_SME_DISASSOC_REQ;
+ pMsg->length = sizeof(tSirSmeDisassocReq);
+ pMsg->sessionId = sessionId;
+ pMsg->transactionId = 0;
+ if ((pSession->pCurRoamProfile != NULL)
+ && ((CSR_IS_INFRA_AP(pSession->pCurRoamProfile))
+ || (CSR_IS_WDS_AP(pSession->pCurRoamProfile)))) {
+ cdf_mem_copy(&pMsg->bssId,
+ &pSession->selfMacAddr,
+ sizeof(tSirMacAddr));
+ cdf_mem_copy(&pMsg->peerMacAddr,
+ bssId,
+ sizeof(tSirMacAddr));
+ } else {
+ cdf_mem_copy(&pMsg->bssId,
+ bssId,
+ sizeof(tSirMacAddr));
+ cdf_mem_copy(&pMsg->peerMacAddr,
+ bssId,
+ sizeof(tSirMacAddr));
+ }
+ pMsg->reasonCode = reasonCode;
+ /*
+ * The state will be DISASSOC_HANDOFF only when we are doing
+ * handoff. Here we should not send the disassoc over the air
+ * to the AP
+ */
+ if (CSR_IS_ROAM_SUBSTATE_DISASSOC_HO(pMac, sessionId)
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ && csr_roam_is11r_assoc(pMac, sessionId)
+#endif
+ ) {
+ /* Set DoNotSendOverTheAir flag to 1 only for handoff case */
+ pMsg->doNotSendOverTheAir = CSR_DONT_SEND_DISASSOC_OVER_THE_AIR;
+ }
+ return cds_send_mb_message_to_mac(pMsg);
+}
+
+CDF_STATUS csr_send_mb_tkip_counter_measures_req_msg(tpAniSirGlobal pMac,
+ uint32_t sessionId, bool bEnable,
+ tSirMacAddr bssId)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSirSmeTkipCntrMeasReq *pMsg;
+ do {
+ pMsg = cdf_mem_malloc(sizeof(tSirSmeTkipCntrMeasReq));
+ if (NULL == pMsg)
+ status = CDF_STATUS_E_NOMEM;
+ else
+ status = CDF_STATUS_SUCCESS;
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ break;
+ cdf_mem_set(pMsg, sizeof(tSirSmeTkipCntrMeasReq), 0);
+ pMsg->messageType = eWNI_SME_TKIP_CNTR_MEAS_REQ;
+ pMsg->length = sizeof(tSirSmeTkipCntrMeasReq);
+ pMsg->sessionId = sessionId;
+ pMsg->transactionId = 0;
+ cdf_mem_copy(pMsg->bssId, bssId, sizeof(tSirMacAddr));
+ pMsg->bEnable = bEnable;
+ status = cds_send_mb_message_to_mac(pMsg);
+ } while (0);
+ return status;
+}
+
+CDF_STATUS
+csr_send_mb_get_associated_stas_req_msg(tpAniSirGlobal pMac, uint32_t sessionId,
+ CDF_MODULE_ID modId, tSirMacAddr bssId,
+ void *pUsrContext, void *pfnSapEventCallback,
+ uint8_t *pAssocStasBuf)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSirSmeGetAssocSTAsReq *pMsg;
+ do {
+ pMsg = cdf_mem_malloc(sizeof(tSirSmeGetAssocSTAsReq));
+ if (NULL == pMsg)
+ status = CDF_STATUS_E_NOMEM;
+ else
+ status = CDF_STATUS_SUCCESS;
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ break;
+ cdf_mem_set(pMsg, sizeof(tSirSmeGetAssocSTAsReq), 0);
+ pMsg->messageType = eWNI_SME_GET_ASSOC_STAS_REQ;
+ cdf_mem_copy(pMsg->bssId, bssId, sizeof(tSirMacAddr));
+ pMsg->modId = modId;
+ cdf_mem_copy(pMsg->pUsrContext,
+ pUsrContext, sizeof(void *));
+ cdf_mem_copy(pMsg->pSapEventCallback,
+ pfnSapEventCallback, sizeof(void *));
+ cdf_mem_copy(pMsg->pAssocStasArray,
+ pAssocStasBuf, sizeof(void *));
+ pMsg->length = sizeof(struct sSirSmeGetAssocSTAsReq);
+ status = cds_send_mb_message_to_mac(pMsg);
+ } while (0);
+ return status;
+}
+
+CDF_STATUS
+csr_send_mb_get_wpspbc_sessions(tpAniSirGlobal pMac, uint32_t sessionId,
+ tSirMacAddr bssId, void *pUsrContext,
+ void *pfnSapEventCallback,
+ struct cdf_mac_addr pRemoveMac)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSirSmeGetWPSPBCSessionsReq *pMsg;
+
+ do {
+ pMsg = cdf_mem_malloc(sizeof(tSirSmeGetWPSPBCSessionsReq));
+ if (NULL == pMsg)
+ status = CDF_STATUS_E_NOMEM;
+ else
+ status = CDF_STATUS_SUCCESS;
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ break;
+ cdf_mem_set(pMsg, sizeof(tSirSmeGetWPSPBCSessionsReq), 0);
+ pMsg->messageType = eWNI_SME_GET_WPSPBC_SESSION_REQ;
+ cdf_mem_copy(pMsg->pUsrContext, pUsrContext, sizeof(void *));
+ cdf_mem_copy(pMsg->pSapEventCallback, pfnSapEventCallback,
+ sizeof(void *));
+ cdf_mem_copy(pMsg->bssId, bssId, sizeof(tSirMacAddr));
+ cdf_mem_copy(pMsg->pRemoveMac, pRemoveMac.bytes,
+ CDF_MAC_ADDR_SIZE);
+ pMsg->length = sizeof(struct sSirSmeGetWPSPBCSessionsReq);
+ status = cds_send_mb_message_to_mac(pMsg);
+ } while (0);
+ return status;
+}
+
+CDF_STATUS csr_send_chng_mcc_beacon_interval(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ tpSirChangeBIParams pMsg;
+ uint16_t len = 0;
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+ /* NO need to update the Beacon Params if update beacon parameter flag is not set */
+ if (!pMac->roam.roamSession[sessionId].bssParams.updatebeaconInterval)
+ return CDF_STATUS_SUCCESS;
+
+ pMac->roam.roamSession[sessionId].bssParams.updatebeaconInterval =
+ false;
+
+ /* Create the message and send to lim */
+ len = sizeof(tSirChangeBIParams);
+ pMsg = cdf_mem_malloc(len);
+ if (NULL == pMsg)
+ status = CDF_STATUS_E_NOMEM;
+ else
+ status = CDF_STATUS_SUCCESS;
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ cdf_mem_set(pMsg, sizeof(tSirChangeBIParams), 0);
+ pMsg->messageType = eWNI_SME_CHNG_MCC_BEACON_INTERVAL;
+ pMsg->length = len;
+
+ /* bssId */
+ cdf_mem_copy((tSirMacAddr *) pMsg->bssId,
+ &pSession->selfMacAddr, sizeof(tSirMacAddr));
+ sms_log(pMac, LOG1,
+ FL("CSR Attempting to change BI for Bssid= "
+ MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pMsg->bssId));
+ pMsg->sessionId = sessionId;
+ sms_log(pMac, LOG1, FL(" session %d BeaconInterval %d"),
+ sessionId,
+ pMac->roam.roamSession[sessionId].bssParams.
+ beaconInterval);
+ pMsg->beaconInterval =
+ pMac->roam.roamSession[sessionId].bssParams.beaconInterval;
+ status = cds_send_mb_message_to_mac(pMsg);
+ }
+ return status;
+}
+
+#ifdef QCA_HT_2040_COEX
+CDF_STATUS csr_set_ht2040_mode(tpAniSirGlobal pMac, uint32_t sessionId,
+ ePhyChanBondState cbMode, bool obssEnabled)
+{
+ tpSirSetHT2040Mode pMsg;
+ uint16_t len = 0;
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ /* Create the message and send to lim */
+ len = sizeof(tSirSetHT2040Mode);
+ pMsg = cdf_mem_malloc(len);
+ if (NULL == pMsg)
+ status = CDF_STATUS_E_NOMEM;
+ else
+ status = CDF_STATUS_SUCCESS;
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ cdf_mem_set(pMsg, sizeof(tSirSetHT2040Mode), 0);
+ pMsg->messageType = eWNI_SME_SET_HT_2040_MODE;
+ pMsg->length = len;
+
+ /* bssId */
+ cdf_mem_copy((tSirMacAddr *) pMsg->bssId,
+ &pSession->selfMacAddr, sizeof(tSirMacAddr));
+ sms_log(pMac, LOG1,
+ FL("CSR Attempting to set HT20/40 mode for Bssid= "
+ MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pMsg->bssId));
+ pMsg->sessionId = sessionId;
+ sms_log(pMac, LOG1, FL(" session %d HT20/40 mode %d"),
+ sessionId, cbMode);
+ pMsg->cbMode = cbMode;
+ pMsg->obssEnabled = obssEnabled;
+ status = cds_send_mb_message_to_mac(pMsg);
+ }
+ return status;
+}
+#endif
+
+CDF_STATUS csr_send_mb_deauth_req_msg(tpAniSirGlobal pMac, uint32_t sessionId,
+ tSirMacAddr bssId, uint16_t reasonCode)
+{
+ tSirSmeDeauthReq *pMsg;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!CSR_IS_SESSION_VALID(pMac, sessionId))
+ return CDF_STATUS_E_FAILURE;
+
+ pMsg = cdf_mem_malloc(sizeof(tSirSmeDeauthReq));
+ if (NULL == pMsg)
+ return CDF_STATUS_E_NOMEM;
+
+ cdf_mem_set(pMsg, sizeof(tSirSmeDeauthReq), 0);
+ pMsg->messageType = eWNI_SME_DEAUTH_REQ;
+ pMsg->length = sizeof(tSirSmeDeauthReq);
+ pMsg->sessionId = sessionId;
+ pMsg->transactionId = 0;
+
+ if ((pSession->pCurRoamProfile != NULL)
+ && ((CSR_IS_INFRA_AP(pSession->pCurRoamProfile))
+ || (CSR_IS_WDS_AP(pSession->pCurRoamProfile)))) {
+ cdf_mem_copy(&pMsg->bssId,
+ &pSession->selfMacAddr,
+ sizeof(tSirMacAddr));
+ } else {
+ cdf_mem_copy(&pMsg->bssId,
+ bssId,
+ sizeof(tSirMacAddr));
+ }
+
+ /* Set the peer MAC address before sending the message to LIM */
+ cdf_mem_copy(&pMsg->peerMacAddr,
+ bssId,
+ sizeof(tSirMacAddr));
+ pMsg->reasonCode = reasonCode;
+
+ return cds_send_mb_message_to_mac(pMsg);
+}
+
+CDF_STATUS csr_send_mb_disassoc_cnf_msg(tpAniSirGlobal pMac,
+ tpSirSmeDisassocInd pDisassocInd)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSirSmeDisassocCnf *pMsg;
+ do {
+ pMsg = cdf_mem_malloc(sizeof(tSirSmeDisassocCnf));
+ if (NULL == pMsg)
+ status = CDF_STATUS_E_NOMEM;
+ else
+ status = CDF_STATUS_SUCCESS;
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ break;
+ cdf_mem_set(pMsg, sizeof(tSirSmeDisassocCnf), 0);
+ pMsg->messageType = eWNI_SME_DISASSOC_CNF;
+ pMsg->statusCode = eSIR_SME_SUCCESS;
+ pMsg->length = sizeof(tSirSmeDisassocCnf);
+ cdf_mem_copy(pMsg->peerMacAddr, pDisassocInd->peerMacAddr,
+ sizeof(pMsg->peerMacAddr));
+ status = CDF_STATUS_SUCCESS;
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ cdf_mem_free(pMsg);
+ break;
+ }
+
+ cdf_mem_copy(pMsg->bssId, pDisassocInd->bssId,
+ sizeof(pMsg->peerMacAddr));
+ status = CDF_STATUS_SUCCESS;
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ cdf_mem_free(pMsg);
+ break;
+ }
+
+ status = cds_send_mb_message_to_mac(pMsg);
+ } while (0);
+ return status;
+}
+
+CDF_STATUS csr_send_mb_deauth_cnf_msg(tpAniSirGlobal pMac,
+ tpSirSmeDeauthInd pDeauthInd)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSirSmeDeauthCnf *pMsg;
+ do {
+ pMsg = cdf_mem_malloc(sizeof(tSirSmeDeauthCnf));
+ if (NULL == pMsg)
+ status = CDF_STATUS_E_NOMEM;
+ else
+ status = CDF_STATUS_SUCCESS;
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ break;
+ cdf_mem_set(pMsg, sizeof(tSirSmeDeauthCnf), 0);
+ pMsg->messageType = eWNI_SME_DEAUTH_CNF;
+ pMsg->statusCode = eSIR_SME_SUCCESS;
+ pMsg->length = sizeof(tSirSmeDeauthCnf);
+ cdf_mem_copy(pMsg->bssId, pDeauthInd->bssId,
+ sizeof(pMsg->bssId));
+ status = CDF_STATUS_SUCCESS;
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ cdf_mem_free(pMsg);
+ break;
+ }
+ cdf_mem_copy(pMsg->peerMacAddr, pDeauthInd->peerMacAddr,
+ sizeof(pMsg->peerMacAddr));
+ status = CDF_STATUS_SUCCESS;
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ cdf_mem_free(pMsg);
+ break;
+ }
+ status = cds_send_mb_message_to_mac(pMsg);
+ } while (0);
+ return status;
+}
+
+CDF_STATUS csr_send_assoc_cnf_msg(tpAniSirGlobal pMac, tpSirSmeAssocInd pAssocInd,
+ CDF_STATUS Halstatus)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSirSmeAssocCnf *pMsg;
+
+ sms_log(pMac, LOG1,
+ FL("Posting eWNI_SME_ASSOC_CNF to LIM.HalStatus :%d"),
+ Halstatus);
+ do {
+ pMsg = cdf_mem_malloc(sizeof(tSirSmeAssocCnf));
+ if (NULL == pMsg)
+ return CDF_STATUS_E_NOMEM;
+ cdf_mem_set(pMsg, sizeof(tSirSmeAssocCnf), 0);
+ pMsg->messageType = eWNI_SME_ASSOC_CNF;
+ pMsg->length = sizeof(tSirSmeAssocCnf);
+ if (CDF_IS_STATUS_SUCCESS(Halstatus))
+ pMsg->statusCode = eSIR_SME_SUCCESS;
+ else
+ pMsg->statusCode = eSIR_SME_ASSOC_REFUSED;
+ /* bssId */
+ cdf_mem_copy(pMsg->bssId, pAssocInd->bssId,
+ sizeof(tSirMacAddr));
+ /* peerMacAddr */
+ cdf_mem_copy(pMsg->peerMacAddr, pAssocInd->peerMacAddr,
+ sizeof(tSirMacAddr));
+ /* aid */
+ pMsg->aid = pAssocInd->aid;
+ /* alternateBssId */
+ cdf_mem_copy(pMsg->alternateBssId, pAssocInd->bssId,
+ sizeof(tSirMacAddr));
+ /* alternateChannelId */
+ pMsg->alternateChannelId = 11;
+ /* pMsg is freed by cds_send_mb_message_to_mac in anycase*/
+ status = cds_send_mb_message_to_mac(pMsg);
+ } while (0);
+ return status;
+}
+
+CDF_STATUS csr_send_assoc_ind_to_upper_layer_cnf_msg(tpAniSirGlobal pMac,
+ tpSirSmeAssocInd pAssocInd,
+ CDF_STATUS Halstatus,
+ uint8_t sessionId)
+{
+ tSirMsgQ msgQ;
+ tSirSmeAssocIndToUpperLayerCnf *pMsg;
+ uint8_t *pBuf;
+ tSirResultCodes statusCode;
+ uint16_t wTmp;
+ do {
+ pMsg = cdf_mem_malloc(sizeof(tSirSmeAssocIndToUpperLayerCnf));
+ if (NULL == pMsg)
+ return CDF_STATUS_E_NOMEM;
+ cdf_mem_set(pMsg, sizeof(tSirSmeAssocIndToUpperLayerCnf), 0);
+
+ pMsg->messageType = eWNI_SME_UPPER_LAYER_ASSOC_CNF;
+ pMsg->length = sizeof(tSirSmeAssocIndToUpperLayerCnf);
+
+ pMsg->sessionId = sessionId;
+
+ pBuf = (uint8_t *) &pMsg->statusCode;
+ if (CDF_IS_STATUS_SUCCESS(Halstatus))
+ statusCode = eSIR_SME_SUCCESS;
+ else
+ statusCode = eSIR_SME_ASSOC_REFUSED;
+ cdf_mem_copy(pBuf, &statusCode, sizeof(tSirResultCodes));
+ pBuf += sizeof(tSirResultCodes);
+ /* bssId */
+ cdf_mem_copy((tSirMacAddr *) pBuf, pAssocInd->bssId,
+ sizeof(tSirMacAddr));
+ pBuf += sizeof(tSirMacAddr);
+ /* peerMacAddr */
+ cdf_mem_copy((tSirMacAddr *) pBuf, pAssocInd->peerMacAddr,
+ sizeof(tSirMacAddr));
+ pBuf += sizeof(tSirMacAddr);
+ /* StaId */
+ wTmp = pAssocInd->staId;
+ cdf_mem_copy(pBuf, &wTmp, sizeof(uint16_t));
+ pBuf += sizeof(uint16_t);
+ /* alternateBssId */
+ cdf_mem_copy((tSirMacAddr *) pBuf, pAssocInd->bssId,
+ sizeof(tSirMacAddr));
+ pBuf += sizeof(tSirMacAddr);
+ /* alternateChannelId */
+ *pBuf = 11;
+ pBuf += sizeof(uint8_t);
+ /* Instead of copying roam Info, we just copy only WmmEnabled, RsnIE information */
+ /* Wmm */
+ *pBuf = pAssocInd->wmmEnabledSta;
+ pBuf += sizeof(uint8_t);
+ /* RSN IE */
+ cdf_mem_copy((tSirRSNie *) pBuf, &pAssocInd->rsnIE,
+ sizeof(tSirRSNie));
+ pBuf += sizeof(tSirRSNie);
+#ifdef FEATURE_WLAN_WAPI
+ /* WAPI IE */
+ cdf_mem_copy((tSirWAPIie *) pBuf, &pAssocInd->wapiIE,
+ sizeof(tSirWAPIie));
+ pBuf += sizeof(tSirWAPIie);
+#endif
+ /* Additional IE */
+ cdf_mem_copy((void *)pBuf, &pAssocInd->addIE,
+ sizeof(tSirAddie));
+ pBuf += sizeof(tSirAddie);
+ /* reassocReq */
+ *pBuf = pAssocInd->reassocReq;
+ pBuf += sizeof(uint8_t);
+ /* timingMeasCap */
+ *pBuf = pAssocInd->timingMeasCap;
+ pBuf += sizeof(uint8_t);
+ cdf_mem_copy((void *)pBuf, &pAssocInd->chan_info,
+ sizeof(tSirSmeChanInfo));
+ msgQ.type = eWNI_SME_UPPER_LAYER_ASSOC_CNF;
+ msgQ.bodyptr = pMsg;
+ msgQ.bodyval = 0;
+ sys_process_mmh_msg(pMac, &msgQ);
+ } while (0);
+ return CDF_STATUS_SUCCESS;
+}
+
+CDF_STATUS csr_send_mb_set_context_req_msg(tpAniSirGlobal pMac, uint32_t sessionId,
+ tSirMacAddr peerMacAddr, uint8_t numKeys,
+ tAniEdType edType, bool fUnicast,
+ tAniKeyDirection aniKeyDirection,
+ uint8_t keyId, uint8_t keyLength,
+ uint8_t *pKey, uint8_t paeRole,
+ uint8_t *pKeyRsc)
+{
+ tSirSmeSetContextReq *pMsg;
+ uint16_t msgLen;
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+ sms_log(pMac, LOG1, FL("keylength is %d, Encry type is : %d"),
+ keyLength, edType);
+ do {
+ if ((1 != numKeys) && (0 != numKeys))
+ break;
+ /*
+ * All of these fields appear in every SET_CONTEXT message.
+ * Below we'll add in the size for each key set. Since we only support
+ * up to one key, we always allocate memory for 1 key.
+ */
+ msgLen = sizeof(struct sSirSmeSetContextReq);
+
+ pMsg = cdf_mem_malloc(msgLen);
+ if (NULL == pMsg)
+ return CDF_STATUS_E_NOMEM;
+ cdf_mem_set(pMsg, msgLen, 0);
+ pMsg->messageType = eWNI_SME_SETCONTEXT_REQ;
+ pMsg->length = msgLen;
+ pMsg->sessionId = (uint8_t) sessionId;
+ pMsg->transactionId = 0;
+ cdf_mem_copy(pMsg->peerMacAddr, peerMacAddr,
+ sizeof(tSirMacAddr));
+ cdf_mem_copy(pMsg->bssId,
+ pSession->connectedProfile.bssid.bytes,
+ sizeof(tSirMacAddr));
+
+ /**
+ * Set the pMsg->keyMaterial.length field
+ * (this length is defined as all data that follows the
+ * edType field in the tSirKeyMaterial keyMaterial; field).
+ *
+ * NOTE: This keyMaterial.length contains the length of a
+ * MAX size key, though the keyLength can be shorter than this
+ * max size. Is LIM interpreting this ok ?
+ */
+ pMsg->keyMaterial.length =
+ sizeof(pMsg->keyMaterial.numKeys) +
+ (numKeys * sizeof(pMsg->keyMaterial.key));
+ pMsg->keyMaterial.edType = edType;
+ pMsg->keyMaterial.numKeys = numKeys;
+ pMsg->keyMaterial.key[0].keyId = keyId;
+ pMsg->keyMaterial.key[0].unicast = fUnicast;
+ pMsg->keyMaterial.key[0].keyDirection = aniKeyDirection;
+ cdf_mem_copy(pMsg->keyMaterial.key[0].keyRsc,
+ pKeyRsc, CSR_MAX_RSC_LEN);
+ /* 0 is Supplicant */
+ pMsg->keyMaterial.key[0].paeRole = paeRole;
+ pMsg->keyMaterial.key[0].keyLength = keyLength;
+ if (keyLength && pKey) {
+ cdf_mem_copy(pMsg->keyMaterial.key[0].key,
+ pKey, keyLength);
+ sms_log(pMac, LOG1,
+ FL("SME set keyIndx (%d) encType (%d) key"),
+ keyId, edType);
+ sir_dump_buf(pMac, SIR_SMS_MODULE_ID, LOG1, pKey,
+ keyLength);
+ }
+ status = cds_send_mb_message_to_mac(pMsg);
+ } while (0);
+ return status;
+}
+
+CDF_STATUS csr_send_mb_start_bss_req_msg(tpAniSirGlobal pMac, uint32_t sessionId,
+ eCsrRoamBssType bssType,
+ tCsrRoamStartBssParams *pParam,
+ tSirBssDescription *pBssDesc)
+{
+ tSirSmeStartBssReq *pMsg;
+ uint16_t wTmp;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ pSession->joinFailStatusCode.statusCode = eSIR_SME_SUCCESS;
+ pSession->joinFailStatusCode.reasonCode = 0;
+ pMsg = cdf_mem_malloc(sizeof(tSirSmeStartBssReq));
+ if (NULL == pMsg)
+ return CDF_STATUS_E_NOMEM;
+
+ cdf_mem_set(pMsg, sizeof(tSirSmeStartBssReq), 0);
+ pMsg->messageType = eWNI_SME_START_BSS_REQ;
+ pMsg->sessionId = sessionId;
+ pMsg->length = sizeof(tSirSmeStartBssReq);
+ pMsg->transactionId = 0;
+ cdf_mem_copy(pMsg->bssId, pParam->bssid.bytes, sizeof(tSirMacAddr));
+ /* selfMacAddr */
+ cdf_mem_copy(pMsg->selfMacAddr,
+ pSession->selfMacAddr.bytes,
+ sizeof(tSirMacAddr));
+ /* beaconInterval */
+ if (pBssDesc && pBssDesc->beaconInterval)
+ wTmp = pBssDesc->beaconInterval;
+ else if (pParam->beaconInterval)
+ wTmp = pParam->beaconInterval;
+ else
+ wTmp = WNI_CFG_BEACON_INTERVAL_STADEF;
+
+ if (csr_isconcurrentsession_valid(pMac, sessionId, pParam->bssPersona)
+ == CDF_STATUS_SUCCESS) {
+ csr_validate_mcc_beacon_interval(pMac,
+ pParam->operationChn,
+ &wTmp,
+ sessionId,
+ pParam->bssPersona);
+ /* Update the beacon Interval */
+ pParam->beaconInterval = wTmp;
+ } else {
+ sms_log(pMac, LOGE,
+ FL("****Start BSS failed persona already exists***"));
+ cdf_mem_free(pMsg);
+ return CDF_STATUS_E_FAILURE;
+ }
+ pMsg->beaconInterval = wTmp;
+ pMsg->dot11mode =
+ csr_translate_to_wni_cfg_dot11_mode(pMac,
+ pParam->uCfgDot11Mode);
+#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH
+ pMsg->cc_switch_mode = pMac->roam.configParam.cc_switch_mode;
+#endif
+ pMsg->bssType = csr_translate_bsstype_to_mac_type(bssType);
+ cdf_mem_copy(&pMsg->ssId, &pParam->ssId, sizeof(pParam->ssId));
+ pMsg->channelId = pParam->operationChn;
+ /* What should we really do for the cbmode. */
+ pMsg->cbMode = (ePhyChanBondState) pParam->cbMode;
+ pMsg->vht_channel_width = pParam->ch_params.ch_width;
+ pMsg->center_freq_seg0 = pParam->ch_params.center_freq_seg0;
+ pMsg->center_freq_seg1 = pParam->ch_params.center_freq_seg1;
+ pMsg->sec_ch_offset = pParam->ch_params.sec_ch_offset;
+ pMsg->privacy = pParam->privacy;
+ pMsg->apUapsdEnable = pParam->ApUapsdEnable;
+ pMsg->ssidHidden = pParam->ssidHidden;
+ pMsg->fwdWPSPBCProbeReq = (uint8_t) pParam->fwdWPSPBCProbeReq;
+ pMsg->protEnabled = (uint8_t) pParam->protEnabled;
+ pMsg->obssProtEnabled = (uint8_t) pParam->obssProtEnabled;
+ /* set cfg related to protection */
+ pMsg->ht_capab = pParam->ht_protection;
+ pMsg->authType = pParam->authType;
+ pMsg->dtimPeriod = pParam->dtimPeriod;
+ pMsg->wps_state = pParam->wps_state;
+ pMsg->isCoalesingInIBSSAllowed = pMac->isCoalesingInIBSSAllowed;
+ pMsg->bssPersona = pParam->bssPersona;
+ pMsg->txLdpcIniFeatureEnabled = pMac->roam.configParam.txLdpcEnable;
+#ifdef WLAN_FEATURE_11W
+ pMsg->pmfCapable = pParam->mfpCapable;
+ pMsg->pmfRequired = pParam->mfpRequired;
+#endif
+
+ if (pParam->nRSNIELength > sizeof(pMsg->rsnIE.rsnIEdata)) {
+ cdf_mem_free(pMsg);
+ return CDF_STATUS_E_INVAL;
+ }
+ pMsg->rsnIE.length = pParam->nRSNIELength;
+ cdf_mem_copy(pMsg->rsnIE.rsnIEdata,
+ pParam->pRSNIE,
+ pParam->nRSNIELength);
+ pMsg->nwType = (tSirNwType)pParam->sirNwType;
+ cdf_mem_copy(&pMsg->operationalRateSet,
+ &pParam->operationalRateSet,
+ sizeof(tSirMacRateSet));
+ cdf_mem_copy(&pMsg->extendedRateSet,
+ &pParam->extendedRateSet,
+ sizeof(tSirMacRateSet));
+ cdf_mem_copy(&pMsg->htConfig,
+ &pSession->htConfig,
+ sizeof(tSirHTConfig));
+ cdf_mem_copy(&pMsg->addIeParams,
+ &pParam->addIeParams,
+ sizeof(pParam->addIeParams));
+ pMsg->obssEnabled = pMac->roam.configParam.obssEnabled;
+ pMsg->sap_dot11mc = pParam->sap_dot11mc;
+
+ return cds_send_mb_message_to_mac(pMsg);
+}
+
+CDF_STATUS csr_send_mb_stop_bss_req_msg(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ tSirSmeStopBssReq *pMsg;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ pMsg = cdf_mem_malloc(sizeof(tSirSmeStopBssReq));
+ if (NULL == pMsg)
+ return CDF_STATUS_E_NOMEM;
+ cdf_mem_set(pMsg, sizeof(tSirSmeStopBssReq), 0);
+ pMsg->messageType = eWNI_SME_STOP_BSS_REQ;
+ pMsg->sessionId = sessionId;
+ pMsg->length = sizeof(tSirSmeStopBssReq);
+ pMsg->transactionId = 0;
+ pMsg->reasonCode = 0;
+ /*
+ * if BSSType is WDS sta, use selfmacAddr as bssid,
+ * else use bssid in connectedProfile
+ */
+ if (CSR_IS_CONN_WDS_STA(&pSession->connectedProfile))
+ cdf_mem_copy(&pMsg->bssId,
+ &pSession->selfMacAddr.bytes,
+ sizeof(tSirMacAddr));
+ else
+ cdf_mem_copy(&pMsg->bssId,
+ &pSession->connectedProfile.bssid.bytes,
+ sizeof(tSirMacAddr));
+ return cds_send_mb_message_to_mac(pMsg);
+}
+
+CDF_STATUS csr_reassoc(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamModifyProfileFields *pModProfileFields,
+ uint32_t *pRoamId, bool fForce)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ uint32_t roamId = 0;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+ if ((csr_is_conn_state_connected(pMac, sessionId)) &&
+ (fForce || (!cdf_mem_compare(&pModProfileFields,
+ &pSession->connectedProfile.
+ modifyProfileFields,
+ sizeof(tCsrRoamModifyProfileFields))))) {
+ roamId = GET_NEXT_ROAM_ID(&pMac->roam);
+ if (pRoamId) {
+ *pRoamId = roamId;
+ }
+
+ status =
+ csr_roam_issue_reassoc(pMac, sessionId, NULL,
+ pModProfileFields,
+ eCsrSmeIssuedReassocToSameAP,
+ roamId, false);
+ }
+ return status;
+}
+
+static CDF_STATUS csr_roam_session_opened(tpAniSirGlobal pMac,
+ uint32_t sessionId)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tCsrRoamInfo roamInfo;
+ cdf_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0);
+ status = csr_roam_call_callback(pMac, sessionId, &roamInfo, 0,
+ eCSR_ROAM_SESSION_OPENED,
+ eCSR_ROAM_RESULT_NONE);
+ return status;
+}
+
+CDF_STATUS csr_process_add_sta_session_rsp(tpAniSirGlobal pMac, uint8_t *pMsg)
+{
+ tListElem *pEntry = NULL;
+ tSmeCmd *pCommand = NULL;
+ struct add_sta_self_params *rsp;
+ struct send_extcap_ie *msg;
+ CDF_STATUS status;
+
+ if (pMsg == NULL) {
+ sms_log(pMac, LOGE, "in %s msg ptr is NULL", __func__);
+ return CDF_STATUS_E_FAILURE;
+ }
+ pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK);
+ if (!pEntry) {
+ sms_log(pMac, LOGE, "in %s NO commands are ACTIVE ...",
+ __func__);
+ return CDF_STATUS_E_FAILURE;
+ }
+ pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
+ if (eSmeCommandAddStaSession != pCommand->command) {
+ sms_log(pMac, LOGE, "in %s Cmd not in active list ...",
+ __func__);
+ return CDF_STATUS_E_FAILURE;
+ }
+ rsp = (struct add_sta_self_params *) pMsg;
+ sms_log(pMac, LOG1, "Add Sta self rsp status = %d", rsp->status);
+
+ if (CDF_STATUS_SUCCESS == rsp->status &&
+ (WMI_VDEV_TYPE_STA == rsp->type ||
+ (WMI_VDEV_TYPE_AP == rsp->type &&
+ WMI_UNIFIED_VDEV_SUBTYPE_P2P_DEVICE == rsp->sub_type))) {
+ sms_log(pMac, LOG1, FL("send SET IE msg to PE"));
+ msg = cdf_mem_malloc(sizeof(*msg));
+ if (NULL == msg) {
+ sms_log(pMac, LOGE, FL("Memory allocation failed"));
+ return CDF_STATUS_E_NOMEM;
+ }
+
+ cdf_mem_set(msg, sizeof(*msg), 0);
+ msg->msg_type = eWNI_SME_SET_IE_REQ;
+ msg->session_id = rsp->session_id;
+ msg->length = sizeof(*msg);
+ status = cds_send_mb_message_to_mac(msg);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ sms_log(pMac, LOGE,
+ FL("Failed to send down the set IE req "));
+ }
+
+ csr_roam_session_opened(pMac, pCommand->sessionId);
+ /* Remove this command out of the active list */
+ if (csr_ll_remove_entry(&pMac->sme.smeCmdActiveList, pEntry,
+ LL_ACCESS_LOCK)) {
+ /* Now put this command back on the avilable command list */
+ csr_release_command(pMac, pCommand);
+ }
+ sme_process_pending_queue(pMac);
+ return CDF_STATUS_SUCCESS;
+}
+
+CDF_STATUS csr_issue_add_sta_for_session_req(tpAniSirGlobal pMac, uint32_t sessionId,
+ tSirMacAddr sessionMacAddr,
+ uint32_t type, uint32_t subType)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSmeCmd *pCommand;
+ pCommand = csr_get_command_buffer(pMac);
+ if (NULL == pCommand) {
+ status = CDF_STATUS_E_RESOURCES;
+ } else {
+ pCommand->command = eSmeCommandAddStaSession;
+ pCommand->sessionId = (uint8_t) sessionId;
+ cdf_mem_copy(pCommand->u.addStaSessionCmd.selfMacAddr,
+ sessionMacAddr, sizeof(tSirMacAddr));
+ pCommand->u.addStaSessionCmd.currDeviceMode =
+ pMac->sme.currDeviceMode;
+ pCommand->u.addStaSessionCmd.type = type;
+ pCommand->u.addStaSessionCmd.subType = subType;
+ status = csr_queue_sme_command(pMac, pCommand, true);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ /* Should be panic?? */
+ sms_log(pMac, LOGE,
+ FL(" fail to send message status = %d"), status);
+ }
+ }
+ return status;
+}
+
+CDF_STATUS csr_process_add_sta_session_command(tpAniSirGlobal pMac,
+ tSmeCmd *pCommand)
+{
+ tAddStaForSessionCmd *pAddStaReq =
+ &pCommand->u.addStaSessionCmd;
+ uint8_t sessionId = pCommand->sessionId;
+ struct add_sta_self_params *add_sta_self_req;
+ CDF_STATUS status = CDF_STATUS_E_NOMEM;
+ tSirMsgQ msg;
+
+ add_sta_self_req = cdf_mem_malloc(sizeof(struct add_sta_self_params));
+ if (NULL == add_sta_self_req) {
+ lim_log(pMac, LOGP,
+ FL
+ ("Unable to allocate memory for tAddSelfStaParams"));
+ return status;
+ }
+
+ cdf_mem_copy(add_sta_self_req->self_mac_addr, pAddStaReq->selfMacAddr,
+ sizeof(tSirMacAddr));
+ add_sta_self_req->curr_device_mode = pAddStaReq->currDeviceMode;
+ add_sta_self_req->session_id = sessionId;
+ add_sta_self_req->type = pAddStaReq->type;
+ add_sta_self_req->sub_type = pAddStaReq->subType;
+
+ msg.type = WMA_ADD_STA_SELF_REQ;
+ msg.reserved = 0;
+ msg.bodyptr = add_sta_self_req;
+ msg.bodyval = 0;
+
+ lim_log(pMac, LOG1,
+ FL
+ ("Send WMA_ADD_STA_SELF_REQ for selfMac=" MAC_ADDRESS_STR),
+ MAC_ADDR_ARRAY(add_sta_self_req->self_mac_addr));
+ MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msg.type));
+ status = wma_post_ctrl_msg(pMac, &msg);
+
+ if (status != CDF_STATUS_SUCCESS) {
+ lim_log(pMac, LOGP, FL("wma_post_ctrl_msg failed"));
+ cdf_mem_free(add_sta_self_req);
+ add_sta_self_req = NULL;
+ }
+ return status;
+}
+
+CDF_STATUS csr_roam_open_session(tpAniSirGlobal pMac,
+ csr_roam_completeCallback callback,
+ void *pContext,
+ uint8_t *pSelfMacAddr, uint8_t *pbSessionId,
+ uint32_t type, uint32_t subType)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ uint32_t i, value = 0;
+ union {
+ uint16_t nCfgValue16;
+ tSirMacHTCapabilityInfo htCapInfo;
+ } uHTCapabilityInfo;
+ tCsrRoamSession *pSession;
+ *pbSessionId = CSR_SESSION_ID_INVALID;
+
+ for (i = 0; i < pMac->sme.max_intf_count; i++) {
+ if (!CSR_IS_SESSION_VALID(pMac, i)) {
+ pSession = CSR_GET_SESSION(pMac, i);
+ if (!pSession) {
+ sms_log(pMac, LOGE,
+ FL
+ ("Session does not exist for interface %d"),
+ i);
+ break;
+ }
+ status = CDF_STATUS_SUCCESS;
+ pSession->sessionActive = true;
+ pSession->sessionId = (uint8_t) i;
+
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ /* Initialize FT related data structures only in STA mode */
+ sme_ft_open(pMac, pSession->sessionId);
+#endif
+
+ pSession->callback = callback;
+ pSession->pContext = pContext;
+ cdf_mem_copy(&pSession->selfMacAddr, pSelfMacAddr,
+ sizeof(struct cdf_mac_addr));
+ *pbSessionId = (uint8_t) i;
+ status =
+ cdf_mc_timer_init(&pSession->hTimerRoaming,
+ CDF_TIMER_TYPE_SW,
+ csr_roam_roaming_timer_handler,
+ &pSession->roamingTimerInfo);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ FL
+ ("cannot allocate memory for Roaming timer"));
+ break;
+ }
+ /* get the HT capability info */
+ if (wlan_cfg_get_int(pMac, WNI_CFG_HT_CAP_INFO, &value)
+ != eSIR_SUCCESS) {
+ CDF_TRACE(CDF_MODULE_ID_CDF,
+ CDF_TRACE_LEVEL_ERROR,
+ "%s: could not get HT capability info",
+ __func__);
+ break;
+ }
+#ifdef FEATURE_WLAN_BTAMP_UT_RF
+ status = cdf_mc_timer_init(&pSession->hTimerJoinRetry,
+ CDF_TIMER_TYPE_SW,
+ csr_roam_join_retry_timer_handler,
+ &pSession->
+ joinRetryTimerInfo);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ FL
+ ("cannot allocate memory for join retry timer"));
+ break;
+ }
+#endif
+ uHTCapabilityInfo.nCfgValue16 = 0xFFFF & value;
+ pSession->htConfig.ht_rx_ldpc =
+ uHTCapabilityInfo.htCapInfo.advCodingCap;
+ pSession->htConfig.ht_tx_stbc =
+ uHTCapabilityInfo.htCapInfo.txSTBC;
+ pSession->htConfig.ht_rx_stbc =
+ uHTCapabilityInfo.htCapInfo.rxSTBC;
+ pSession->htConfig.ht_sgi = true;
+ status =
+ csr_issue_add_sta_for_session_req(pMac, i, pSelfMacAddr,
+ type, subType);
+ break;
+ }
+ }
+ if (pMac->sme.max_intf_count == i) {
+ /* No session is available */
+ sms_log(pMac, LOGE,
+ "%s: Reached max interfaces: %d! Session creation will fail",
+ __func__, pMac->sme.max_intf_count);
+ status = CDF_STATUS_E_RESOURCES;
+ }
+ return status;
+}
+
+CDF_STATUS csr_process_del_sta_session_rsp(tpAniSirGlobal pMac, uint8_t *pMsg)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ tListElem *pEntry = NULL;
+ tSmeCmd *pCommand = NULL;
+ struct del_sta_self_params *rsp;
+ uint8_t sessionId;
+
+ if (pMsg == NULL) {
+ sms_log(pMac, LOGE, FL("msg ptr is NULL"));
+ return status;
+ }
+ pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK);
+ if (!pEntry) {
+ sms_log(pMac, LOGE, FL("NO commands are ACTIVE ..."));
+ return status;
+ }
+ pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
+ sessionId = pCommand->sessionId;
+ if (eSmeCommandDelStaSession != pCommand->command) {
+ sms_log(pMac, LOGE, FL("NO Del sta session command ACTIVE"));
+ return status;
+ }
+ rsp = (struct del_sta_self_params *) pMsg;
+ sms_log(pMac, LOG1, FL("Del Sta rsp status = %d"), rsp->status);
+ /* This session is done. */
+ csr_cleanup_session(pMac, sessionId);
+ if (pCommand->u.delStaSessionCmd.callback) {
+ status = sme_release_global_lock(&pMac->sme);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ sms_log(pMac, LOG1, FL("Failed to Release Lock"));
+ else {
+ pCommand->u.delStaSessionCmd.
+ callback(pCommand->u.delStaSessionCmd.pContext);
+ status = sme_acquire_global_lock(&pMac->sme);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOG1, FL("Failed to get Lock"));
+ return status;
+ }
+ }
+ }
+ /* Remove this command out of the active list */
+ if (csr_ll_remove_entry(&pMac->sme.smeCmdActiveList, pEntry,
+ LL_ACCESS_LOCK)) {
+ /* Now put this command back on the avilable command list */
+ csr_release_command(pMac, pCommand);
+ }
+ sme_process_pending_queue(pMac);
+ status = CDF_STATUS_SUCCESS;
+ return status;
+}
+
+
+CDF_STATUS csr_issue_del_sta_for_session_req(tpAniSirGlobal pMac, uint32_t sessionId,
+ tSirMacAddr sessionMacAddr,
+ csr_roamSessionCloseCallback callback,
+ void *pContext)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSmeCmd *pCommand;
+ pCommand = csr_get_command_buffer(pMac);
+ if (NULL == pCommand) {
+ status = CDF_STATUS_E_RESOURCES;
+ } else {
+ pCommand->command = eSmeCommandDelStaSession;
+ pCommand->sessionId = (uint8_t) sessionId;
+ pCommand->u.delStaSessionCmd.callback = callback;
+ pCommand->u.delStaSessionCmd.pContext = pContext;
+ cdf_mem_copy(pCommand->u.delStaSessionCmd.selfMacAddr,
+ sessionMacAddr, sizeof(tSirMacAddr));
+ status = csr_queue_sme_command(pMac, pCommand, true);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ /* Should be panic?? */
+ sms_log(pMac, LOGE,
+ FL(" fail to send message status = %d"), status);
+ }
+ }
+ return status;
+}
+
+CDF_STATUS csr_process_del_sta_session_command(tpAniSirGlobal pMac,
+ tSmeCmd *pCommand)
+{
+ struct del_sta_self_params *del_sta_self_req;
+ tSirMsgQ msg;
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ del_sta_self_req = cdf_mem_malloc(sizeof(struct del_sta_self_params));
+ if (NULL == del_sta_self_req) {
+ lim_log(pMac, LOGP,
+ FL(" mem alloc failed for tDelStaSelfParams"));
+ return CDF_STATUS_E_NOMEM;
+ }
+
+ cdf_mem_copy(del_sta_self_req->self_mac_addr,
+ pCommand->u.delStaSessionCmd.selfMacAddr,
+ sizeof(tSirMacAddr));
+
+ del_sta_self_req->session_id = pCommand->sessionId;
+ msg.type = WMA_DEL_STA_SELF_REQ;
+ msg.reserved = 0;
+ msg.bodyptr = del_sta_self_req;
+ msg.bodyval = 0;
+
+ sms_log(pMac, LOG1,
+ FL("sending WMA_DEL_STA_SELF_REQ"));
+ MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msg.type));
+ status = wma_post_ctrl_msg(pMac, &msg);
+ if (status != CDF_STATUS_SUCCESS) {
+ sms_log(pMac, LOGP, FL("wma_post_ctrl_msg failed"));
+ cdf_mem_free(del_sta_self_req);
+ }
+ return status;
+}
+
+static void purge_csr_session_cmd_list(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ tDblLinkList *pList = &pMac->roam.roamCmdPendingList;
+ tListElem *pEntry, *pNext;
+ tSmeCmd *pCommand;
+ tDblLinkList localList;
+
+ 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);
+ while (pEntry != NULL) {
+ pNext = csr_ll_next(pList, pEntry, LL_ACCESS_NOLOCK);
+ pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
+ if (pCommand->sessionId == sessionId) {
+ if (csr_ll_remove_entry(pList, pEntry, LL_ACCESS_NOLOCK)) {
+ csr_ll_insert_tail(&localList, pEntry,
+ LL_ACCESS_NOLOCK);
+ }
+ }
+ pEntry = pNext;
+ }
+ 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, true);
+ }
+ csr_ll_close(&localList);
+}
+
+void csr_cleanup_session(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ if (CSR_IS_SESSION_VALID(pMac, sessionId)) {
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ csr_roam_stop(pMac, sessionId);
+
+ /* Clean up FT related data structures */
+#if defined WLAN_FEATURE_VOWIFI_11R
+ sme_ft_close(pMac, sessionId);
+#endif
+ csr_free_connect_bss_desc(pMac, sessionId);
+ csr_roam_free_connect_profile(pMac, &pSession->connectedProfile);
+ csr_roam_free_connected_info(pMac, &pSession->connectedInfo);
+ cdf_mc_timer_destroy(&pSession->hTimerRoaming);
+#ifdef FEATURE_WLAN_BTAMP_UT_RF
+ cdf_mc_timer_destroy(&pSession->hTimerJoinRetry);
+#endif
+ purge_sme_session_cmd_list(pMac, sessionId,
+ &pMac->sme.smeCmdPendingList);
+ purge_sme_session_cmd_list(pMac, sessionId,
+ &pMac->sme.
+ smeScanCmdPendingList);
+
+ purge_csr_session_cmd_list(pMac, sessionId);
+ csr_init_session(pMac, sessionId);
+ }
+}
+
+CDF_STATUS csr_roam_close_session(tpAniSirGlobal pMac, uint32_t sessionId,
+ bool fSync,
+ csr_roamSessionCloseCallback callback,
+ void *pContext)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ if (CSR_IS_SESSION_VALID(pMac, sessionId)) {
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+ if (fSync) {
+ csr_cleanup_session(pMac, sessionId);
+ } else {
+ purge_sme_session_cmd_list(pMac, sessionId,
+ &pMac->sme.smeCmdPendingList);
+ purge_sme_session_cmd_list(pMac, sessionId,
+ &pMac->sme.smeScanCmdPendingList);
+
+ purge_csr_session_cmd_list(pMac, sessionId);
+ status = csr_issue_del_sta_for_session_req(pMac,
+ sessionId,
+ pSession->selfMacAddr.bytes,
+ callback, pContext);
+ }
+ } else {
+ status = CDF_STATUS_E_INVAL;
+ }
+ return status;
+}
+
+static void csr_init_session(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;
+ }
+
+ pSession->sessionActive = false;
+ pSession->sessionId = CSR_SESSION_ID_INVALID;
+ pSession->callback = NULL;
+ pSession->pContext = NULL;
+ pSession->connectState = eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED;
+ csr_free_roam_profile(pMac, sessionId);
+ csr_roam_free_connect_profile(pMac, &pSession->connectedProfile);
+ csr_roam_free_connected_info(pMac, &pSession->connectedInfo);
+ csr_free_connect_bss_desc(pMac, sessionId);
+ csr_scan_enable(pMac);
+ cdf_mem_set(&pSession->selfMacAddr, sizeof(struct cdf_mac_addr), 0);
+ if (pSession->pWpaRsnReqIE) {
+ cdf_mem_free(pSession->pWpaRsnReqIE);
+ pSession->pWpaRsnReqIE = NULL;
+ }
+ pSession->nWpaRsnReqIeLength = 0;
+ if (pSession->pWpaRsnRspIE) {
+ cdf_mem_free(pSession->pWpaRsnRspIE);
+ pSession->pWpaRsnRspIE = NULL;
+ }
+ pSession->nWpaRsnRspIeLength = 0;
+#ifdef FEATURE_WLAN_WAPI
+ if (pSession->pWapiReqIE) {
+ cdf_mem_free(pSession->pWapiReqIE);
+ pSession->pWapiReqIE = NULL;
+ }
+ pSession->nWapiReqIeLength = 0;
+ if (pSession->pWapiRspIE) {
+ cdf_mem_free(pSession->pWapiRspIE);
+ pSession->pWapiRspIE = NULL;
+ }
+ pSession->nWapiRspIeLength = 0;
+#endif /* FEATURE_WLAN_WAPI */
+ if (pSession->pAddIEScan) {
+ cdf_mem_free(pSession->pAddIEScan);
+ pSession->pAddIEScan = NULL;
+ }
+ pSession->nAddIEScanLength = 0;
+ if (pSession->pAddIEAssoc) {
+ cdf_mem_free(pSession->pAddIEAssoc);
+ pSession->pAddIEAssoc = NULL;
+ }
+ pSession->nAddIEAssocLength = 0;
+}
+
+CDF_STATUS csr_roam_get_session_id_from_bssid(tpAniSirGlobal pMac,
+ struct cdf_mac_addr *bssid,
+ uint32_t *pSessionId)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ uint32_t i;
+ for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
+ if (CSR_IS_SESSION_VALID(pMac, i)) {
+ if (cdf_is_macaddr_equal(bssid,
+ &pMac->roam.roamSession[i].connectedProfile.
+ bssid)) {
+ /* Found it */
+ status = CDF_STATUS_SUCCESS;
+ *pSessionId = i;
+ break;
+ }
+ }
+ }
+ return status;
+}
+
+/* This function assumes that we only support one IBSS session. We cannot use BSSID to identify */
+/* session because for IBSS, the bssid changes. */
+static uint32_t csr_find_ibss_session(tpAniSirGlobal pMac)
+{
+ uint32_t i, nRet = CSR_SESSION_ID_INVALID;
+ tCsrRoamSession *pSession;
+ for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
+ if (CSR_IS_SESSION_VALID(pMac, i)) {
+ pSession = CSR_GET_SESSION(pMac, i);
+ if (pSession->pCurRoamProfile
+ &&
+ (csr_is_bss_type_ibss
+ (pSession->connectedProfile.BSSType))) {
+ /* Found it */
+ nRet = i;
+ break;
+ }
+ }
+ }
+ return nRet;
+}
+
+static void csr_roam_link_up(tpAniSirGlobal pMac, struct cdf_mac_addr bssid)
+{
+ /* Update the current BSS info in ho control block based on connected
+ profile info from pmac global structure */
+
+ sms_log(pMac, LOGW,
+ " csr_roam_link_up: WLAN link UP with AP= " MAC_ADDRESS_STR,
+ MAC_ADDR_ARRAY(bssid.bytes));
+ /* Check for user misconfig of RSSI trigger threshold */
+ pMac->roam.configParam.vccRssiThreshold =
+ (0 == pMac->roam.configParam.vccRssiThreshold) ?
+ CSR_VCC_RSSI_THRESHOLD : pMac->roam.configParam.vccRssiThreshold;
+ pMac->roam.vccLinkQuality = eCSR_ROAM_LINK_QUAL_POOR_IND;
+ /* Check for user misconfig of UL MAC Loss trigger threshold */
+ pMac->roam.configParam.vccUlMacLossThreshold =
+ (0 == pMac->roam.configParam.vccUlMacLossThreshold) ?
+ CSR_VCC_UL_MAC_LOSS_THRESHOLD : pMac->roam.configParam.
+ vccUlMacLossThreshold;
+#if defined WLAN_FEATURE_NEIGHBOR_ROAMING
+ {
+ uint32_t sessionId = 0;
+ /* Indicate the neighbor roal algorithm about the connect indication */
+ csr_roam_get_session_id_from_bssid(pMac, &bssid,
+ &sessionId);
+ csr_neighbor_roam_indicate_connect(pMac, sessionId,
+ CDF_STATUS_SUCCESS);
+ }
+#endif
+}
+
+static void csr_roam_link_down(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;
+ }
+ /* Only to handle the case for Handover on infra link */
+ if (eCSR_BSS_TYPE_INFRASTRUCTURE != pSession->connectedProfile.BSSType) {
+ return;
+ }
+ /*
+ * Incase of station mode, immediately stop data transmission whenever
+ * link down is detected.
+ */
+ if (csr_roam_is_sta_mode(pMac, sessionId)
+ && !CSR_IS_ROAM_SUBSTATE_DISASSOC_HO(pMac, sessionId)
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ && !csr_roam_is11r_assoc(pMac, sessionId)
+#endif
+ ) {
+ sms_log(pMac, LOG1, FL("Inform Link lost for session %d"),
+ sessionId);
+ csr_roam_call_callback(pMac, sessionId, NULL, 0,
+ eCSR_ROAM_LOSTLINK,
+ eCSR_ROAM_RESULT_LOSTLINK);
+ }
+ /* deregister the clients requesting stats from PE/TL & also stop the corresponding timers */
+ csr_roam_dereg_statistics_req(pMac);
+ pMac->roam.vccLinkQuality = eCSR_ROAM_LINK_QUAL_POOR_IND;
+#if defined WLAN_FEATURE_NEIGHBOR_ROAMING
+ /* Indicate the neighbor roal algorithm about the disconnect indication */
+ csr_neighbor_roam_indicate_disconnect(pMac, sessionId);
+#endif
+
+ /* Remove this code once SLM_Sessionization is supported */
+ /* BMPS_WORKAROUND_NOT_NEEDED */
+ if (!IS_FEATURE_SUPPORTED_BY_FW(SLM_SESSIONIZATION) &&
+ csr_is_infra_ap_started(pMac) &&
+ pMac->roam.configParam.doBMPSWorkaround) {
+ pMac->roam.configParam.doBMPSWorkaround = 0;
+ }
+
+}
+
+void csr_roam_tl_stats_timer_handler(void *pv)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(pv);
+ CDF_STATUS status;
+ pMac->roam.tlStatsReqInfo.timerRunning = false;
+
+ sms_log(pMac, LOG1,
+ FL
+ (" TL stat timer is no-op. It needs to support multiple stations"));
+
+ if (!pMac->roam.tlStatsReqInfo.timerRunning) {
+ if (pMac->roam.tlStatsReqInfo.periodicity) {
+ /* start timer */
+ status =
+ cdf_mc_timer_start(&pMac->roam.tlStatsReqInfo.
+ hTlStatsTimer,
+ pMac->roam.tlStatsReqInfo.
+ periodicity);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ FL
+ ("csr_roam_tl_stats_timer_handler:cannot start TlStatsTimer timer"));
+ return;
+ }
+ pMac->roam.tlStatsReqInfo.timerRunning = true;
+ }
+ }
+}
+
+void csr_roam_pe_stats_timer_handler(void *pv)
+{
+ tCsrPeStatsReqInfo *pPeStatsReqListEntry = (tCsrPeStatsReqInfo *) pv;
+ CDF_STATUS status;
+ tpAniSirGlobal pMac = pPeStatsReqListEntry->pMac;
+ CDF_STATUS cdf_status;
+ pPeStatsReqListEntry->timerRunning = false;
+ if (pPeStatsReqListEntry->timerStopFailed == true) {
+ /* If we entered here, meaning the timer could not be successfully */
+ /* stopped in csr_roam_remove_entry_from_pe_stats_req_list(). So do it here. */
+
+ /* Destroy the timer */
+ cdf_status =
+ cdf_mc_timer_destroy(&pPeStatsReqListEntry->hPeStatsTimer);
+ if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
+ sms_log(pMac, LOGE,
+ FL
+ ("csr_roam_pe_stats_timer_handler:failed to destroy hPeStatsTimer timer"));
+ }
+ /* Free the entry */
+ cdf_mem_free(pPeStatsReqListEntry);
+ pPeStatsReqListEntry = NULL;
+ } else {
+ if (!pPeStatsReqListEntry->rspPending) {
+ status =
+ csr_send_mb_stats_req_msg(pMac,
+ pPeStatsReqListEntry->
+ statsMask & ~(1 <<
+ eCsrGlobalClassDStats),
+ pPeStatsReqListEntry->staId,
+ pPeStatsReqListEntry->
+ sessionId);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ FL
+ ("csr_roam_pe_stats_timer_handler:failed to send down stats req to PE"));
+ } else {
+ pPeStatsReqListEntry->rspPending = true;
+ }
+ }
+ /* send down a req */
+ if (pPeStatsReqListEntry->periodicity &&
+ (CDF_TIMER_STATE_STOPPED ==
+ cdf_mc_timer_get_current_state(&pPeStatsReqListEntry->
+ hPeStatsTimer))) {
+ if (pPeStatsReqListEntry->periodicity <
+ pMac->roam.configParam.
+ statsReqPeriodicityInPS) {
+ pPeStatsReqListEntry->periodicity =
+ pMac->roam.configParam.
+ statsReqPeriodicityInPS;
+ }
+ /* start timer */
+ cdf_status =
+ cdf_mc_timer_start(&pPeStatsReqListEntry->
+ hPeStatsTimer,
+ pPeStatsReqListEntry->
+ periodicity);
+ if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
+ sms_log(pMac, LOGE,
+ FL
+ ("csr_roam_pe_stats_timer_handler:cannot start hPeStatsTimer timer"));
+ return;
+ }
+ pPeStatsReqListEntry->timerRunning = true;
+
+ }
+
+ }
+}
+
+void csr_roam_stats_client_timer_handler(void *pv)
+{
+ tCsrStatsClientReqInfo *pStaEntry = (tCsrStatsClientReqInfo *) pv;
+ if (CDF_TIMER_STATE_STOPPED ==
+ cdf_mc_timer_get_current_state(&pStaEntry->timer)) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ FL("roam stats client timer is stopped"));
+ }
+}
+
+CDF_STATUS csr_send_mb_stats_req_msg(tpAniSirGlobal pMac, uint32_t statsMask,
+ uint8_t staId, uint8_t sessionId)
+{
+ tAniGetPEStatsReq *pMsg;
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ pMsg = cdf_mem_malloc(sizeof(tAniGetPEStatsReq));
+ if (NULL == pMsg) {
+ sms_log(pMac, LOGE, FL("Failed to allocate mem for stats req "));
+ return CDF_STATUS_E_NOMEM;
+ }
+ /* need to initiate a stats request to PE */
+ pMsg->msgType = eWNI_SME_GET_STATISTICS_REQ;
+ pMsg->msgLen = (uint16_t) sizeof(tAniGetPEStatsReq);
+ pMsg->staId = staId;
+ pMsg->statsMask = statsMask;
+ pMsg->sessionId = sessionId;
+ status = cds_send_mb_message_to_mac(pMsg);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOG1, FL("Failed to send down the stats req "));
+ }
+ return status;
+}
+
+/**
+ * csr_update_stats() - updates correct stats struct in mac_ctx
+ * @mac: mac global context
+ * @stats_type: stats type
+ * @sme_stats_rsp: stats rsp msg packet
+ * @stats: input stats data buffer to fill in mac_ctx struct
+ * @length: out param - stats length
+ *
+ * This function fills corresponding stats struct in mac_cts based on stats type
+ * passed
+ *
+ * Return: void
+ */
+static void
+csr_update_stats(tpAniSirGlobal mac, uint8_t stats_type,
+ tAniGetPEStatsRsp *sme_stats_rsp,
+ uint8_t **stats, uint32_t *length)
+{
+ switch (stats_type) {
+ case eCsrSummaryStats:
+ sms_log(mac, LOG2, FL("summary stats"));
+ cdf_mem_copy((uint8_t *) &mac->roam.summaryStatsInfo, *stats,
+ sizeof(tCsrSummaryStatsInfo));
+ *stats += sizeof(tCsrSummaryStatsInfo);
+ *length -= sizeof(tCsrSummaryStatsInfo);
+ break;
+ case eCsrGlobalClassAStats:
+ sms_log(mac, LOG2, FL("ClassA stats"));
+ cdf_mem_copy((uint8_t *) &mac->roam.classAStatsInfo, *stats,
+ sizeof(tCsrGlobalClassAStatsInfo));
+ *stats += sizeof(tCsrGlobalClassAStatsInfo);
+ *length -= sizeof(tCsrGlobalClassAStatsInfo);
+ break;
+ case eCsrGlobalClassBStats:
+ sms_log(mac, LOG2, FL("ClassB stats"));
+ cdf_mem_copy((uint8_t *) &mac->roam.classBStatsInfo, *stats,
+ sizeof(tCsrGlobalClassBStatsInfo));
+ *stats += sizeof(tCsrGlobalClassBStatsInfo);
+ *length -= sizeof(tCsrGlobalClassBStatsInfo);
+ break;
+ case eCsrGlobalClassCStats:
+ sms_log(mac, LOG2, FL("ClassC stats"));
+ cdf_mem_copy((uint8_t *) &mac->roam.classCStatsInfo, *stats,
+ sizeof(tCsrGlobalClassCStatsInfo));
+ *stats += sizeof(tCsrGlobalClassCStatsInfo);
+ *length -= sizeof(tCsrGlobalClassCStatsInfo);
+ break;
+ case eCsrPerStaStats:
+ sms_log(mac, LOG2, FL("PerSta stats"));
+ if (CSR_MAX_STA > sme_stats_rsp->staId) {
+ cdf_mem_copy(
+ &mac->roam.perStaStatsInfo[sme_stats_rsp->staId],
+ *stats, sizeof(tCsrPerStaStatsInfo));
+ } else {
+ sms_log(mac, LOGE, FL("out bound staId:%d. failed to copy PerSta stats"),
+ sme_stats_rsp->staId);
+ CDF_ASSERT(0);
+ }
+ *stats += sizeof(tCsrPerStaStatsInfo);
+ *length -= sizeof(tCsrPerStaStatsInfo);
+ break;
+ default:
+ sms_log(mac, LOGW, FL("unknown stats type"));
+ break;
+ }
+}
+
+/**
+ * csr_roam_stats_rsp_processor() - processes stats rsp msg
+ * @pMac mac global context
+ * @pSirMsg: incoming message
+ *
+ * Return: void
+ */
+void csr_roam_stats_rsp_processor(tpAniSirGlobal pMac, tSirSmeRsp *pSirMsg)
+{
+ tAniGetPEStatsRsp *pSmeStatsRsp;
+ tListElem *pEntry = NULL;
+ tCsrStatsClientReqInfo *pTempStaEntry = NULL;
+ tCsrPeStatsReqInfo *pPeStaEntry = NULL;
+ uint32_t tempMask = 0;
+ uint8_t counter = 0;
+ uint8_t *pStats = NULL;
+ uint32_t length = 0;
+ void *p_cds_gctx;
+ int8_t rssi = 0, snr = 0;
+ uint32_t *pRssi = NULL, *pSnr = NULL;
+ uint32_t linkCapacity;
+ pSmeStatsRsp = (tAniGetPEStatsRsp *) pSirMsg;
+
+ if (pSmeStatsRsp->rc) {
+ sms_log(pMac, LOGW, FL("stats rsp from PE shows failure"));
+ goto post_update;
+ }
+ tempMask = pSmeStatsRsp->statsMask;
+ pStats = ((uint8_t *) &pSmeStatsRsp->statsMask) +
+ sizeof(pSmeStatsRsp->statsMask);
+ /*
+ * subtract all statistics from this length, and after processing the
+ * entire 'stat' part of the message, if the length is not zero, then
+ * rssi is piggy packed in this 'stats' message.
+ */
+ length = pSmeStatsRsp->msgLen - sizeof(tAniGetPEStatsRsp);
+ /* new stats info from PE, fill up the stats strucutres in PMAC */
+ while (tempMask) {
+ if (tempMask & 1) {
+ csr_update_stats(pMac, counter, pSmeStatsRsp,
+ &pStats, &length);
+ }
+ tempMask >>= 1;
+ counter++;
+ }
+ p_cds_gctx = cds_get_global_context();
+ if (length != 0) {
+ pRssi = (uint32_t *) pStats;
+ rssi = (int8_t) *pRssi;
+ pStats += sizeof(uint32_t);
+ length -= sizeof(uint32_t);
+ } else {
+ /* If riva is not sending rssi, continue to use the hack */
+ rssi = RSSI_HACK_BMPS;
+ }
+
+ if (length != 0) {
+ linkCapacity = *(uint32_t *) pStats;
+ pStats += sizeof(uint32_t);
+ length -= sizeof(uint32_t);
+ } else {
+ linkCapacity = 0;
+ }
+
+ if (length != 0) {
+ pSnr = (uint32_t *) pStats;
+ snr = (int8_t) *pSnr;
+ } else {
+ snr = SNR_HACK_BMPS;
+ }
+
+post_update:
+ /* make sure to update the pe stats req list */
+ pEntry = csr_roam_find_in_pe_stats_req_list(pMac, pSmeStatsRsp->statsMask);
+ if (pEntry) {
+ pPeStaEntry = GET_BASE_ADDR(pEntry, tCsrPeStatsReqInfo, link);
+ pPeStaEntry->rspPending = false;
+
+ }
+ /* check the one timer cases */
+ pEntry = csr_roam_check_client_req_list(pMac, pSmeStatsRsp->statsMask);
+ if (pEntry) {
+ pTempStaEntry =
+ GET_BASE_ADDR(pEntry, tCsrStatsClientReqInfo, link);
+ if (pTempStaEntry->timerExpired) {
+ /* send up the stats report */
+ csr_roam_report_statistics(pMac, pTempStaEntry->statsMask,
+ pTempStaEntry->callback,
+ pTempStaEntry->staId,
+ pTempStaEntry->pContext);
+ /* also remove from the client list */
+ csr_roam_remove_stat_list_entry(pMac, pEntry);
+ pTempStaEntry = NULL;
+ }
+ }
+}
+
+tListElem *csr_roam_find_in_pe_stats_req_list(tpAniSirGlobal pMac, uint32_t statsMask)
+{
+ tListElem *pEntry = NULL;
+ tCsrPeStatsReqInfo *pTempStaEntry = NULL;
+ pEntry = csr_ll_peek_head(&pMac->roam.peStatsReqList, LL_ACCESS_LOCK);
+ if (!pEntry) {
+ /* list empty */
+ sms_log(pMac, LOG2,
+ "csr_roam_find_in_pe_stats_req_list: List empty, no request to PE");
+ return NULL;
+ }
+ while (pEntry) {
+ pTempStaEntry = GET_BASE_ADDR(pEntry, tCsrPeStatsReqInfo, link);
+ if (pTempStaEntry->statsMask == statsMask) {
+ sms_log(pMac, LOG3,
+ "csr_roam_find_in_pe_stats_req_list: match found");
+ break;
+ }
+ pEntry =
+ csr_ll_next(&pMac->roam.peStatsReqList, pEntry,
+ LL_ACCESS_NOLOCK);
+ }
+ return pEntry;
+}
+
+tListElem *csr_roam_checkn_update_client_req_list(tpAniSirGlobal pMac,
+ tCsrStatsClientReqInfo *pStaEntry,
+ bool update)
+{
+ tListElem *pEntry;
+ tCsrStatsClientReqInfo *pTempStaEntry;
+ pEntry = csr_ll_peek_head(&pMac->roam.statsClientReqList, LL_ACCESS_LOCK);
+ if (!pEntry) {
+ /* list empty */
+ sms_log(pMac, LOG2,
+ "csr_roam_checkn_update_client_req_list: List empty, no request from "
+ "upper layer client(s)");
+ return NULL;
+ }
+ while (pEntry) {
+ pTempStaEntry =
+ GET_BASE_ADDR(pEntry, tCsrStatsClientReqInfo, link);
+ if ((pTempStaEntry->requesterId == pStaEntry->requesterId)
+ && (pTempStaEntry->statsMask == pStaEntry->statsMask)) {
+ sms_log(pMac, LOG3,
+ "csr_roam_checkn_update_client_req_list: match found");
+ if (update) {
+ pTempStaEntry->periodicity =
+ pStaEntry->periodicity;
+ pTempStaEntry->callback = pStaEntry->callback;
+ pTempStaEntry->pContext = pStaEntry->pContext;
+ }
+ break;
+ }
+ pEntry =
+ csr_ll_next(&pMac->roam.statsClientReqList, pEntry,
+ LL_ACCESS_NOLOCK);
+ }
+ return pEntry;
+}
+
+tListElem *csr_roam_check_client_req_list(tpAniSirGlobal pMac, uint32_t statsMask)
+{
+ tListElem *pEntry;
+ tCsrStatsClientReqInfo *pTempStaEntry;
+ pEntry = csr_ll_peek_head(&pMac->roam.statsClientReqList, LL_ACCESS_LOCK);
+ if (!pEntry) {
+ /* list empty */
+ sms_log(pMac, LOG2,
+ "csr_roam_check_client_req_list: List empty, no request from "
+ "upper layer client(s)");
+ return NULL;
+ }
+ while (pEntry) {
+ pTempStaEntry =
+ GET_BASE_ADDR(pEntry, tCsrStatsClientReqInfo, link);
+ if ((pTempStaEntry->
+ statsMask & ~(1 << eCsrGlobalClassDStats)) == statsMask) {
+ sms_log(pMac, LOG3,
+ "csr_roam_check_client_req_list: match found");
+ break;
+ }
+ pEntry =
+ csr_ll_next(&pMac->roam.statsClientReqList, pEntry,
+ LL_ACCESS_NOLOCK);
+ }
+ return pEntry;
+}
+
+void csr_roam_vcc_trigger(tpAniSirGlobal pMac)
+{
+ eCsrRoamLinkQualityInd newVccLinkQuality;
+ uint32_t ul_mac_loss = 0;
+ uint32_t ul_mac_loss_trigger_threshold;
+ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+ /*-------------------------------------------------------------------------
+ Link quality is currently binary based on OBIWAN recommended triggers
+ Check for a change in link quality and notify client if necessary
+ -------------------------------------------------------------------------*/
+ ul_mac_loss_trigger_threshold =
+ pMac->roam.configParam.vccUlMacLossThreshold;
+ if (0 == ul_mac_loss_trigger_threshold) {
+ CDF_ASSERT(ul_mac_loss_trigger_threshold != 0);
+ return;
+ }
+ sms_log(pMac, LOGW, "csr_roam_vcc_trigger: UL_MAC_LOSS_THRESHOLD is %d",
+ ul_mac_loss_trigger_threshold);
+ if (ul_mac_loss_trigger_threshold < ul_mac_loss) {
+ sms_log(pMac, LOGW, "csr_roam_vcc_trigger: link quality is POOR ");
+ newVccLinkQuality = eCSR_ROAM_LINK_QUAL_POOR_IND;
+ } else {
+ sms_log(pMac, LOGW, "csr_roam_vcc_trigger: link quality is GOOD");
+ newVccLinkQuality = eCSR_ROAM_LINK_QUAL_GOOD_IND;
+ }
+ sms_log(pMac, LOGW,
+ "csr_roam_vcc_trigger: link qual : *** UL_MAC_LOSS %d *** ",
+ ul_mac_loss);
+ if (newVccLinkQuality != pMac->roam.vccLinkQuality) {
+ sms_log(pMac, LOGW,
+ "csr_roam_vcc_trigger: link quality changed: trigger necessary");
+ if (NULL != pMac->roam.linkQualityIndInfo.callback) {
+ sms_log(pMac, LOGW,
+ "csr_roam_vcc_trigger: link quality indication %d",
+ newVccLinkQuality);
+
+ /* we now invoke the callback once to notify client of initial value */
+ pMac->roam.linkQualityIndInfo.
+ callback(newVccLinkQuality,
+ pMac->roam.linkQualityIndInfo.context);
+ /* event: EVENT_WLAN_VCC */
+ }
+ }
+ pMac->roam.vccLinkQuality = newVccLinkQuality;
+
+}
+
+tCsrStatsClientReqInfo *csr_roam_insert_entry_into_list(tpAniSirGlobal pMac,
+ tDblLinkList *pStaList,
+ tCsrStatsClientReqInfo *
+ pStaEntry)
+{
+ tCsrStatsClientReqInfo *pNewStaEntry = NULL;
+ /* if same entity requested for same set of stats with different periodicity & */
+ /* callback update it */
+ if (NULL == csr_roam_checkn_update_client_req_list(pMac, pStaEntry, true)) {
+
+ pNewStaEntry = cdf_mem_malloc(sizeof(tCsrStatsClientReqInfo));
+ if (NULL == pNewStaEntry) {
+ sms_log(pMac, LOGW,
+ "csr_roam_insert_entry_into_list: couldn't allocate memory for the "
+ "entry");
+ return NULL;
+ }
+
+ pNewStaEntry->callback = pStaEntry->callback;
+ pNewStaEntry->pContext = pStaEntry->pContext;
+ pNewStaEntry->periodicity = pStaEntry->periodicity;
+ pNewStaEntry->requesterId = pStaEntry->requesterId;
+ pNewStaEntry->statsMask = pStaEntry->statsMask;
+ pNewStaEntry->pPeStaEntry = pStaEntry->pPeStaEntry;
+ pNewStaEntry->pMac = pStaEntry->pMac;
+ pNewStaEntry->staId = pStaEntry->staId;
+ pNewStaEntry->timerExpired = pStaEntry->timerExpired;
+
+ csr_ll_insert_tail(pStaList, &pNewStaEntry->link, LL_ACCESS_LOCK);
+ }
+ return pNewStaEntry;
+}
+
+tCsrPeStatsReqInfo *csr_roam_insert_entry_into_pe_stats_req_list(tpAniSirGlobal pMac,
+ tDblLinkList *
+ pStaList,
+ tCsrPeStatsReqInfo *
+ pStaEntry)
+{
+ tCsrPeStatsReqInfo *pNewStaEntry = NULL;
+ pNewStaEntry = cdf_mem_malloc(sizeof(tCsrPeStatsReqInfo));
+ if (NULL == pNewStaEntry) {
+ sms_log(pMac, LOGW,
+ "csr_roam_insert_entry_into_pe_stats_req_list: couldn't allocate memory for the "
+ "entry");
+ return NULL;
+ }
+
+ pNewStaEntry->hPeStatsTimer = pStaEntry->hPeStatsTimer;
+ pNewStaEntry->numClient = pStaEntry->numClient;
+ pNewStaEntry->periodicity = pStaEntry->periodicity;
+ pNewStaEntry->statsMask = pStaEntry->statsMask;
+ pNewStaEntry->pMac = pStaEntry->pMac;
+ pNewStaEntry->staId = pStaEntry->staId;
+ pNewStaEntry->timerRunning = pStaEntry->timerRunning;
+ pNewStaEntry->rspPending = pStaEntry->rspPending;
+
+ csr_ll_insert_tail(pStaList, &pNewStaEntry->link, LL_ACCESS_LOCK);
+ return pNewStaEntry;
+}
+
+CDF_STATUS csr_get_rssi(tpAniSirGlobal pMac,
+ tCsrRssiCallback callback,
+ uint8_t staId,
+ struct cdf_mac_addr bssId,
+ int8_t lastRSSI, void *pContext, void *p_cds_context)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ cds_msg_t msg;
+ uint32_t sessionId;
+
+ tAniGetRssiReq *pMsg;
+ sms_log(pMac, LOG2, FL("called"));
+
+ status = csr_roam_get_session_id_from_bssid(pMac, &bssId, &sessionId);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ callback(lastRSSI, staId, pContext);
+ sms_log(pMac, LOGE, FL("Failed to get SessionId"));
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ pMsg = cdf_mem_malloc(sizeof(tAniGetRssiReq));
+ if (NULL == pMsg) {
+ sms_log(pMac, LOGE,
+ " csr_get_rssi: failed to allocate mem for req ");
+ return CDF_STATUS_E_NOMEM;
+ }
+
+ pMsg->msgType = eWNI_SME_GET_RSSI_REQ;
+ pMsg->msgLen = (uint16_t) sizeof(tAniGetRssiReq);
+ pMsg->sessionId = sessionId;
+ pMsg->staId = staId;
+ pMsg->rssiCallback = callback;
+ pMsg->pDevContext = pContext;
+ pMsg->p_cds_context = p_cds_context;
+ /*
+ * store RSSI at time of calling, so that if RSSI request cannot
+ * be sent to firmware, this value can be used to return immediately
+ */
+ pMsg->lastRSSI = lastRSSI;
+ msg.type = eWNI_SME_GET_RSSI_REQ;
+ msg.bodyptr = pMsg;
+ msg.reserved = 0;
+ if (CDF_STATUS_SUCCESS != cds_mq_post_message(CDS_MQ_ID_SME, &msg)) {
+ sms_log(pMac, LOGE, " csr_get_rssi failed to post msg to self ");
+ cdf_mem_free((void *)pMsg);
+ status = CDF_STATUS_E_FAILURE;
+ }
+ sms_log(pMac, LOG2, FL("returned"));
+ return status;
+}
+
+CDF_STATUS csr_get_snr(tpAniSirGlobal pMac,
+ tCsrSnrCallback callback,
+ uint8_t staId, struct cdf_mac_addr bssId, void *pContext)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ cds_msg_t msg;
+ uint32_t sessionId;
+
+ tAniGetSnrReq *pMsg;
+
+ sms_log(pMac, LOG2, FL("called"));
+
+ pMsg = (tAniGetSnrReq *) cdf_mem_malloc(sizeof(tAniGetSnrReq));
+ if (NULL == pMsg) {
+ sms_log(pMac, LOGE, "%s: failed to allocate mem for req",
+ __func__);
+ return CDF_STATUS_E_NOMEM;
+ }
+
+ csr_roam_get_session_id_from_bssid(pMac, &bssId, &sessionId);
+
+ pMsg->msgType = eWNI_SME_GET_SNR_REQ;
+ pMsg->msgLen = (uint16_t) sizeof(tAniGetSnrReq);
+ pMsg->sessionId = sessionId;
+ pMsg->staId = staId;
+ pMsg->snrCallback = callback;
+ pMsg->pDevContext = pContext;
+ msg.type = eWNI_SME_GET_SNR_REQ;
+ msg.bodyptr = pMsg;
+ msg.reserved = 0;
+
+ if (CDF_STATUS_SUCCESS != cds_mq_post_message(CDS_MQ_ID_SME, &msg)) {
+ sms_log(pMac, LOGE, "%s failed to post msg to self", __func__);
+ cdf_mem_free((void *)pMsg);
+ status = CDF_STATUS_E_FAILURE;
+ }
+
+ sms_log(pMac, LOG2, FL("returned"));
+ return status;
+}
+
+#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD)
+CDF_STATUS csr_get_tsm_stats(tpAniSirGlobal pMac,
+ tCsrTsmStatsCallback callback,
+ uint8_t staId,
+ struct cdf_mac_addr bssId,
+ void *pContext, void *p_cds_context, uint8_t tid)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tAniGetTsmStatsReq *pMsg = NULL;
+ pMsg = cdf_mem_malloc(sizeof(tAniGetTsmStatsReq));
+ if (!pMsg) {
+ sms_log(pMac, LOGE,
+ "csr_get_tsm_stats: failed to allocate mem for req");
+ return CDF_STATUS_E_NOMEM;
+ }
+ /* need to initiate a stats request to PE */
+ pMsg->msgType = eWNI_SME_GET_TSM_STATS_REQ;
+ pMsg->msgLen = (uint16_t) sizeof(tAniGetTsmStatsReq);
+ pMsg->staId = staId;
+ pMsg->tid = tid;
+ cdf_mem_copy(pMsg->bssId, bssId.bytes, sizeof(tSirMacAddr));
+ pMsg->tsmStatsCallback = callback;
+ pMsg->pDevContext = pContext;
+ pMsg->p_cds_context = p_cds_context;
+ status = cds_send_mb_message_to_mac(pMsg);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOG1,
+ " csr_get_tsm_stats: failed to send down the rssi req");
+ /* pMsg is freed by cds_send_mb_message_to_mac */
+ status = CDF_STATUS_E_FAILURE;
+ }
+ return status;
+}
+#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */
+
+/**
+ * csr_deregister_client_request() - deregisters a get stats request
+ * @mac_ctx: mac global context
+ * @sta_entry: stats request entry
+ *
+ * Return: status of operation
+ */
+static CDF_STATUS
+csr_deregister_client_request(tpAniSirGlobal mac_ctx,
+ tCsrStatsClientReqInfo *sta_entry)
+{
+ CDF_STATUS status;
+ tListElem *entry = NULL;
+ tCsrStatsClientReqInfo *ptr_sta_entry = NULL;
+
+ entry = csr_roam_checkn_update_client_req_list(mac_ctx, sta_entry,
+ false);
+ if (!entry) {
+ sms_log(mac_ctx, LOGW,
+ FL("callback is empty in the request & couldn't find any existing request in statsClientReqList"));
+ return CDF_STATUS_E_FAILURE;
+ }
+ /* clean up & return */
+ ptr_sta_entry = GET_BASE_ADDR(entry, tCsrStatsClientReqInfo, link);
+ if (NULL != ptr_sta_entry->pPeStaEntry) {
+ ptr_sta_entry->pPeStaEntry->numClient--;
+ /* check if we need to delete the entry from peStatsReqList */
+ if (!ptr_sta_entry->pPeStaEntry->numClient)
+ csr_roam_remove_entry_from_pe_stats_req_list(mac_ctx,
+ ptr_sta_entry->pPeStaEntry);
+ }
+ /* check if we need to stop the tl stats timer too */
+ mac_ctx->roam.tlStatsReqInfo.numClient--;
+ if (!mac_ctx->roam.tlStatsReqInfo.numClient) {
+ if (mac_ctx->roam.tlStatsReqInfo.timerRunning) {
+ status = cdf_mc_timer_stop(
+ &mac_ctx->roam.tlStatsReqInfo.hTlStatsTimer);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(mac_ctx, LOGE,
+ FL("cannot stop TlStatsTimer timer"));
+ return status;
+ }
+ }
+ mac_ctx->roam.tlStatsReqInfo.periodicity = 0;
+ mac_ctx->roam.tlStatsReqInfo.timerRunning = false;
+ }
+ cdf_mc_timer_stop(&ptr_sta_entry->timer);
+ /* Destroy the cdf timer... */
+ status = cdf_mc_timer_destroy(&ptr_sta_entry->timer);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ sms_log(mac_ctx, LOGE,
+ FL("failed to destroy Client req timer"));
+
+ csr_roam_remove_stat_list_entry(mac_ctx, entry);
+ return CDF_STATUS_SUCCESS;
+}
+
+/**
+ * csr_insert_stats_request_to_list() - inserts request to existing list
+ * @mac_ctx: mac global context
+ * @sta_entry: stats request entry
+ * @periodicity: periodicity of stats
+ *
+ * Return: status of operation
+ */
+static CDF_STATUS
+csr_insert_stats_request_to_list(tpAniSirGlobal mac_ctx,
+ tCsrStatsClientReqInfo *sta_entry,
+ uint32_t periodicity)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tCsrStatsClientReqInfo *ptr_sta_entry = csr_roam_insert_entry_into_list(
+ mac_ctx, &mac_ctx->roam.statsClientReqList,
+ sta_entry);
+ if (!ptr_sta_entry) {
+ sms_log(mac_ctx, LOGW,
+ FL("Failed to insert req in statsClientReqList"));
+ return CDF_STATUS_E_FAILURE;
+ }
+ /* Init & start timer if needed */
+ ptr_sta_entry->periodicity = periodicity;
+ if (ptr_sta_entry->periodicity) {
+ status = cdf_mc_timer_init(&ptr_sta_entry->timer,
+ CDF_TIMER_TYPE_SW,
+ csr_roam_stats_client_timer_handler,
+ ptr_sta_entry);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(mac_ctx, LOGE,
+ FL("cannot init StatsClient timer"));
+ return CDF_STATUS_E_FAILURE;
+ }
+ status = cdf_mc_timer_start(&ptr_sta_entry->timer,
+ ptr_sta_entry->periodicity);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(mac_ctx, LOGE,
+ FL("cannot start StatsClient timer"));
+ return CDF_STATUS_E_FAILURE;
+ }
+ }
+ return status;
+}
+
+/**
+ * csr_get_statistics_from_tl() - fetch stats from tl layer
+ * @mac_ctx: mac global context
+ * @cache: indicate if cached stats are required
+ * @staId: station id
+ * @periodicity: periodicity of stats
+ *
+ * Return: status of operation
+ */
+static CDF_STATUS
+csr_get_statistics_from_tl(tpAniSirGlobal mac_ctx,
+ bool cache,
+ uint8_t staId,
+ uint32_t periodicity)
+{
+ CDF_STATUS status;
+
+ if (cache && mac_ctx->roam.tlStatsReqInfo.numClient) {
+ sms_log(mac_ctx, LOGE, FL("Looking for cached stats from TL"));
+ mac_ctx->roam.tlStatsReqInfo.numClient++;
+ return CDF_STATUS_SUCCESS;
+ }
+
+ /* update periodicity */
+ if (mac_ctx->roam.tlStatsReqInfo.periodicity)
+ mac_ctx->roam.tlStatsReqInfo.periodicity =
+ CDF_MIN(periodicity,
+ mac_ctx->roam.tlStatsReqInfo.periodicity);
+ else
+ mac_ctx->roam.tlStatsReqInfo.periodicity = periodicity;
+
+ if (mac_ctx->roam.tlStatsReqInfo.periodicity
+ < CSR_MIN_TL_STAT_QUERY_PERIOD) {
+ mac_ctx->roam.tlStatsReqInfo.periodicity =
+ CSR_MIN_TL_STAT_QUERY_PERIOD;
+ }
+
+ if (!mac_ctx->roam.tlStatsReqInfo.timerRunning) {
+
+ if (mac_ctx->roam.tlStatsReqInfo.periodicity) {
+ /* start timer */
+ status = cdf_mc_timer_start(
+ &mac_ctx->roam.tlStatsReqInfo.hTlStatsTimer,
+ mac_ctx->roam.tlStatsReqInfo.periodicity);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(mac_ctx, LOGE,
+ FL("cannot start TlStatsTimer timer"));
+ return CDF_STATUS_E_FAILURE;
+ }
+ mac_ctx->roam.tlStatsReqInfo.timerRunning = true;
+ }
+ }
+ mac_ctx->roam.tlStatsReqInfo.numClient++;
+ return CDF_STATUS_SUCCESS;
+}
+
+CDF_STATUS csr_get_statistics(tpAniSirGlobal pMac,
+ eCsrStatsRequesterType requesterId,
+ uint32_t statsMask,
+ tCsrStatsCallback callback,
+ uint32_t periodicity,
+ bool cache,
+ uint8_t staId,
+ void *pContext,
+ uint8_t sessionId)
+{
+ tCsrStatsClientReqInfo staEntry;
+ tCsrPeStatsReqInfo *pPeStaEntry = NULL;
+ bool found = false;
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ bool insertInClientList = false;
+ uint32_t temp_mask = 0;
+
+ if (csr_is_all_session_disconnected(pMac))
+ return CDF_STATUS_E_FAILURE;
+
+ if (csr_neighbor_middle_of_roaming(pMac, sessionId)) {
+ sms_log(pMac, LOG1, FL("in the middle of roaming states"));
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ if ((!statsMask) && (!callback)) {
+ sms_log(pMac, LOGW,
+ FL("statsMask & callback empty in the request"));
+ return CDF_STATUS_E_FAILURE;
+ }
+ /* for the search list method for deregister */
+ staEntry.requesterId = requesterId;
+ staEntry.statsMask = statsMask;
+ /* requester wants to deregister or just an error */
+ if ((statsMask) && (!callback))
+ return csr_deregister_client_request(pMac, &staEntry);
+
+ if (cache && !periodicity) {
+ /* return the cached stats */
+ csr_roam_report_statistics(pMac, statsMask, callback, staId,
+ pContext);
+ return CDF_STATUS_SUCCESS;
+ }
+ /* add the request in the client req list */
+ staEntry.callback = callback;
+ staEntry.pContext = pContext;
+ staEntry.periodicity = periodicity;
+ staEntry.pPeStaEntry = NULL;
+ staEntry.staId = staId;
+ staEntry.pMac = pMac;
+ staEntry.timerExpired = false;
+ staEntry.sessionId = sessionId;
+
+ /* if periodic report requested with non cached result from PE/TL */
+ if (periodicity) {
+ /* if looking for stats from PE */
+ temp_mask = statsMask & ~(1 << eCsrGlobalClassDStats);
+ if (temp_mask) {
+ /* check if same req made already & waiting for rsp */
+ pPeStaEntry = csr_roam_check_pe_stats_req_list(pMac,
+ temp_mask, periodicity, &found,
+ staId, sessionId);
+ if (!pPeStaEntry)
+ /* bail out, maxed out on num of req for PE */
+ return CDF_STATUS_E_FAILURE;
+ else
+ staEntry.pPeStaEntry = pPeStaEntry;
+ }
+ /*
+ * request stats from TL rightaway if requested by client,
+ * update tlStatsReqInfo if needed
+ */
+ temp_mask = statsMask & (1 << eCsrGlobalClassDStats);
+ if (temp_mask) {
+ status = csr_get_statistics_from_tl(pMac, cache, staId,
+ periodicity);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ return status;
+ }
+ insertInClientList = true;
+ }
+ /* if one time report requested with non cached result from PE/TL */
+ else if (!cache && !periodicity) {
+ temp_mask = statsMask & ~(1 << eCsrGlobalClassDStats);
+ if (temp_mask) {
+ /* send down a req */
+ status = csr_send_mb_stats_req_msg(pMac,
+ temp_mask, staId, sessionId);
+ if (!CDF_IS_STATUS_SUCCESS(status))
+ sms_log(pMac, LOGE,
+ FL("failed to send down stats req"));
+ /*
+ * so that when the stats rsp comes back from PE we
+ * respond to upper layer right away
+ */
+ staEntry.timerExpired = true;
+ insertInClientList = true;
+ }
+ /* if looking for stats from TL only */
+ if (!insertInClientList) {
+ /* return the stats */
+ csr_roam_report_statistics(pMac, statsMask, callback,
+ staId, pContext);
+ return CDF_STATUS_SUCCESS;
+ }
+ }
+ if (insertInClientList)
+ return csr_insert_stats_request_to_list(pMac, &staEntry,
+ periodicity);
+
+ return CDF_STATUS_SUCCESS;
+}
+
+static tSirRetStatus
+csr_roam_scan_offload_populate_mac_header(tpAniSirGlobal pMac,
+ uint8_t *pBD,
+ uint8_t type,
+ uint8_t subType,
+ tSirMacAddr peerAddr,
+ tSirMacAddr selfMacAddr)
+{
+ tSirRetStatus statusCode = eSIR_SUCCESS;
+ tpSirMacMgmtHdr pMacHdr;
+
+ /* Prepare MAC management header */
+ pMacHdr = (tpSirMacMgmtHdr) (pBD);
+
+ /* Prepare FC */
+ pMacHdr->fc.protVer = SIR_MAC_PROTOCOL_VERSION;
+ pMacHdr->fc.type = type;
+ pMacHdr->fc.subType = subType;
+
+ /* Prepare Address 1 */
+ cdf_mem_copy((uint8_t *) pMacHdr->da, (uint8_t *) peerAddr,
+ sizeof(tSirMacAddr));
+
+ sir_copy_mac_addr(pMacHdr->sa, selfMacAddr);
+
+ /* Prepare Address 3 */
+ cdf_mem_copy((uint8_t *) pMacHdr->bssId, (uint8_t *) peerAddr,
+ sizeof(tSirMacAddr));
+ return statusCode;
+} /*** csr_roam_scan_offload_populate_mac_header() ***/
+
+static tSirRetStatus
+csr_roam_scan_offload_prepare_probe_req_template(tpAniSirGlobal pMac,
+ uint8_t nChannelNum,
+ uint32_t dot11mode,
+ tSirMacAddr selfMacAddr,
+ uint8_t *pFrame,
+ uint16_t *pusLen,
+ tCsrRoamSession *psession)
+{
+ tDot11fProbeRequest pr;
+ uint32_t nStatus, nBytes, nPayload;
+ tSirRetStatus nSirStatus;
+ /*Bcast tx */
+ tSirMacAddr bssId = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+ /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+ cdf_mem_set((uint8_t *) &pr, sizeof(pr), 0);
+
+ populate_dot11f_supp_rates(pMac, nChannelNum, &pr.SuppRates, NULL);
+
+ if (WNI_CFG_DOT11_MODE_11B != dot11mode) {
+ populate_dot11f_ext_supp_rates1(pMac, nChannelNum,
+ &pr.ExtSuppRates);
+ }
+
+ if (IS_DOT11_MODE_HT(dot11mode)) {
+ populate_dot11f_ht_caps(pMac, NULL, &pr.HTCaps);
+ pr.HTCaps.advCodingCap = psession->htConfig.ht_rx_ldpc;
+ pr.HTCaps.txSTBC = psession->htConfig.ht_tx_stbc;
+ pr.HTCaps.rxSTBC = psession->htConfig.ht_rx_stbc;
+ if (!psession->htConfig.ht_sgi) {
+ pr.HTCaps.shortGI20MHz = pr.HTCaps.shortGI40MHz = 0;
+ }
+ }
+
+ nStatus = dot11f_get_packed_probe_request_size(pMac, &pr, &nPayload);
+ if (DOT11F_FAILED(nStatus)) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ "Failed to calculate the packed size f"
+ "or a Probe Request (0x%08x).\n", nStatus);
+
+ nPayload = sizeof(tDot11fProbeRequest);
+ } else if (DOT11F_WARNED(nStatus)) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ "There were warnings while calculating"
+ "the packed size for a Probe Request ("
+ "0x%08x).\n", nStatus);
+ }
+
+ nBytes = nPayload + sizeof(tSirMacMgmtHdr);
+
+ /* Prepare outgoing frame */
+ cdf_mem_set(pFrame, nBytes, 0);
+
+ nSirStatus =
+ csr_roam_scan_offload_populate_mac_header(pMac, pFrame,
+ SIR_MAC_MGMT_FRAME,
+ SIR_MAC_MGMT_PROBE_REQ, bssId,
+ selfMacAddr);
+
+ if (eSIR_SUCCESS != nSirStatus) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ "Failed to populate the buffer descriptor for a Probe Request (%d).\n",
+ nSirStatus);
+ return nSirStatus;
+ }
+
+ nStatus = dot11f_pack_probe_request(pMac, &pr, pFrame +
+ sizeof(tSirMacMgmtHdr),
+ nPayload, &nPayload);
+ if (DOT11F_FAILED(nStatus)) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ "Failed to pack a Probe Request (0x%08x).\n",
+ nStatus);
+ return eSIR_FAILURE;
+ } else if (DOT11F_WARNED(nStatus)) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ "There were warnings while packing a Probe Request (0x%08x).\n",
+ nStatus);
+ }
+
+ *pusLen = nPayload + sizeof(tSirMacMgmtHdr);
+ return eSIR_SUCCESS;
+}
+
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+CDF_STATUS csr_roam_set_key_mgmt_offload(tpAniSirGlobal pMac,
+ uint32_t sessionId,
+ bool nRoamKeyMgmtOffloadEnabled)
+{
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL("session %d not found"), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+ pSession->RoamKeyMgmtOffloadEnabled = nRoamKeyMgmtOffloadEnabled;
+ return CDF_STATUS_SUCCESS;
+}
+
+/**
+ * csr_update_roam_scan_offload_request() - updates req msg with roam offload
+ * paramters
+ * @pMac: mac global context
+ * @req_buf: out param, roam offload scan request packet
+ * @session: roam session
+ *
+ * Return: void
+ */
+static void
+csr_update_roam_scan_offload_request(tpAniSirGlobal mac_ctx,
+ tSirRoamOffloadScanReq *req_buf,
+ tCsrRoamSession *session)
+{
+ cdf_mem_copy(req_buf->PSK_PMK, session->psk_pmk,
+ sizeof(req_buf->PSK_PMK));
+ req_buf->pmk_len = session->pmk_len;
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ "LFR3: PMK Length = %d", req_buf->pmk_len);
+ req_buf->R0KH_ID_Length = session->ftSmeContext.r0kh_id_len;
+ cdf_mem_copy(req_buf->R0KH_ID,
+ session->ftSmeContext.r0kh_id,
+ req_buf->R0KH_ID_Length);
+ req_buf->Prefer5GHz = mac_ctx->roam.configParam.nRoamPrefer5GHz;
+ req_buf->RoamRssiCatGap = mac_ctx->roam.configParam.bCatRssiOffset;
+ req_buf->Select5GHzMargin = mac_ctx->roam.configParam.nSelect5GHzMargin;
+ if (wlan_cfg_get_int(mac_ctx, WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT,
+ (uint32_t *) &req_buf->ReassocFailureTimeout)
+ != eSIR_SUCCESS) {
+ sms_log(mac_ctx, LOGE,
+ FL("could not retrieve ReassocFailureTimeout value"));
+ req_buf->ReassocFailureTimeout =
+ DEFAULT_REASSOC_FAILURE_TIMEOUT;
+ }
+#ifdef FEATURE_WLAN_ESE
+ if (csr_is_auth_type_ese(req_buf->ConnectedNetwork.authentication)) {
+ cdf_mem_copy(req_buf->KRK, session->eseCckmInfo.krk,
+ SIR_KRK_KEY_LEN);
+ cdf_mem_copy(req_buf->BTK, session->eseCckmInfo.btk,
+ SIR_BTK_KEY_LEN);
+ }
+#endif
+ req_buf->AcUapsd.acbe_uapsd =
+ SIR_UAPSD_GET(ACBE, mac_ctx->lim.gUapsdPerAcBitmask);
+ req_buf->AcUapsd.acbk_uapsd =
+ SIR_UAPSD_GET(ACBK, mac_ctx->lim.gUapsdPerAcBitmask);
+ req_buf->AcUapsd.acvi_uapsd =
+ SIR_UAPSD_GET(ACVI, mac_ctx->lim.gUapsdPerAcBitmask);
+ req_buf->AcUapsd.acvo_uapsd =
+ SIR_UAPSD_GET(ACVO, mac_ctx->lim.gUapsdPerAcBitmask);
+}
+#endif /* WLAN_FEATURE_ROAM_OFFLOAD */
+
+/**
+ * csr_check_band_channel_match() - check if passed band and channel match
+ * paramters
+ * @band: band to match with channel
+ * @channel: channel to match with band
+ *
+ * Return: bool if match else false
+ */
+static bool
+csr_check_band_channel_match(eCsrBand band, uint8_t channel)
+{
+ if (eCSR_BAND_ALL == band)
+ return true;
+
+ if (eCSR_BAND_24 == band && CDS_IS_CHANNEL_24GHZ(channel))
+ return true;
+
+ if (eCSR_BAND_5G == band && CDS_IS_CHANNEL_5GHZ(channel))
+ return true;
+
+ return false;
+}
+
+/**
+ * csr_fetch_ch_lst_from_ini() - fetch channel list from ini and update req msg
+ * paramters
+ * @mac_ctx: global mac ctx
+ * @roam_info: roam info struct
+ * @req_buf: out param, roam offload scan request packet
+ *
+ * Return: result of operation
+ */
+static CDF_STATUS
+csr_fetch_ch_lst_from_ini(tpAniSirGlobal mac_ctx,
+ tpCsrNeighborRoamControlInfo roam_info,
+ tSirRoamOffloadScanReq *req_buf)
+{
+ eCsrBand band;
+ uint8_t i = 0;
+ uint8_t num_channels = 0;
+ uint8_t *ch_lst = roam_info->cfgParams.channelInfo.ChannelList;
+ /*
+ * The INI channels need to be filtered with respect to the current band
+ * that is supported.
+ */
+ band = mac_ctx->roam.configParam.bandCapability;
+ if ((eCSR_BAND_24 != band) && (eCSR_BAND_5G != band)
+ && (eCSR_BAND_ALL != band)) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ FL("Invalid band(%d), roam scan offload req aborted"),
+ band);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ for (i = 0; i < roam_info->cfgParams.channelInfo.numOfChannels; i++) {
+ if (!csr_check_band_channel_match(band, *ch_lst))
+ continue;
+ /* Allow DFS channels only if the DFS roaming is enabled */
+ if (((mac_ctx->roam.configParam.allowDFSChannelRoam !=
+ CSR_ROAMING_DFS_CHANNEL_DISABLED)
+ || (!CDS_IS_DFS_CH(*ch_lst)))
+ && csr_roam_is_channel_valid(mac_ctx, *ch_lst)
+ && *ch_lst && (num_channels < SIR_ROAM_MAX_CHANNELS)) {
+ req_buf->ConnectedNetwork.ChannelCache[num_channels++] =
+ *ch_lst;
+ }
+ ch_lst++;
+ }
+ req_buf->ConnectedNetwork.ChannelCount = num_channels;
+ req_buf->ChannelCacheType = CHANNEL_LIST_STATIC;
+ return CDF_STATUS_SUCCESS;
+}
+
+/**
+ * csr_fetch_ch_lst_from_occupied_lst() - fetch channel list from occupied list
+ * and update req msg
+ * paramters
+ * @mac_ctx: global mac ctx
+ * @session_id: session id
+ * @reason: reason to roam
+ * @req_buf: out param, roam offload scan request packet
+ * @roam_info: roam info struct
+ *
+ * Return: void
+ */
+static void
+csr_fetch_ch_lst_from_occupied_lst(tpAniSirGlobal mac_ctx,
+ uint8_t session_id,
+ uint8_t reason,
+ tSirRoamOffloadScanReq *req_buf,
+ tpCsrNeighborRoamControlInfo roam_info)
+{
+ uint8_t i = 0;
+ uint8_t num_channels = 0;
+ uint8_t *ch_lst =
+ mac_ctx->scan.occupiedChannels[session_id].channelList;
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ "Num of channels before filtering=%d",
+ mac_ctx->scan.occupiedChannels[session_id].numChannels);
+ for (i = 0; i < mac_ctx->scan.occupiedChannels[session_id].numChannels;
+ i++) {
+ if (((mac_ctx->roam.configParam.allowDFSChannelRoam !=
+ CSR_ROAMING_DFS_CHANNEL_DISABLED)
+ || (!CDS_IS_DFS_CH(*ch_lst)))
+ && *ch_lst && (num_channels < SIR_ROAM_MAX_CHANNELS)) {
+ req_buf->ConnectedNetwork.ChannelCache[num_channels++] =
+ *ch_lst;
+ }
+ if (*ch_lst)
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ "DFSRoam=%d, ChnlState=%d, Chnl=%d, num_ch=%d",
+ mac_ctx->roam.configParam.allowDFSChannelRoam,
+ cds_get_channel_state(*ch_lst), *ch_lst,
+ num_channels);
+ ch_lst++;
+ }
+ req_buf->ConnectedNetwork.ChannelCount = num_channels;
+ /*
+ * If the profile changes as to what it was earlier, inform the FW
+ * through FLUSH as ChannelCacheType in which case, the FW will flush
+ * the occupied channels for the earlier profile and try to learn them
+ * afresh
+ */
+ if (reason == REASON_FLUSH_CHANNEL_LIST)
+ req_buf->ChannelCacheType = CHANNEL_LIST_DYNAMIC_FLUSH;
+ else {
+ if (csr_neighbor_roam_is_new_connected_profile(mac_ctx,
+ session_id))
+ req_buf->ChannelCacheType = CHANNEL_LIST_DYNAMIC_INIT;
+ else
+ req_buf->ChannelCacheType = CHANNEL_LIST_DYNAMIC_UPDATE;
+ }
+}
+
+#ifdef FEATURE_WLAN_ESE
+/**
+ * csr_fetch_ch_lst_from_received_list() - fetch channel list from received list
+ * and update req msg
+ * paramters
+ * @mac_ctx: global mac ctx
+ * @roam_info: roam info struct
+ * @curr_ch_lst_info: current channel list info
+ * @req_buf: out param, roam offload scan request packet
+ *
+ * Return: void
+ */
+static void
+csr_fetch_ch_lst_from_received_list(tpAniSirGlobal mac_ctx,
+ tpCsrNeighborRoamControlInfo roam_info,
+ tpCsrChannelInfo curr_ch_lst_info,
+ tSirRoamOffloadScanReq *req_buf)
+{
+ uint8_t i = 0;
+ uint8_t num_channels = 0;
+ uint8_t *ch_lst = NULL;
+
+ if (curr_ch_lst_info->numOfChannels == 0)
+ return;
+
+ ch_lst = curr_ch_lst_info->ChannelList;
+ for (i = 0; i < curr_ch_lst_info->numOfChannels; i++) {
+ if (((mac_ctx->roam.configParam.allowDFSChannelRoam
+ != CSR_ROAMING_DFS_CHANNEL_DISABLED) ||
+ (!CDS_IS_DFS_CH(*ch_lst))) && *ch_lst) {
+ req_buf->ConnectedNetwork.ChannelCache[num_channels++] =
+ *ch_lst;
+ }
+ ch_lst++;
+ }
+ req_buf->ConnectedNetwork.ChannelCount = num_channels;
+ req_buf->ChannelCacheType = CHANNEL_LIST_DYNAMIC_UPDATE;
+}
+#endif
+
+/**
+ * csr_fetch_valid_ch_lst() - fetch channel list from valid channel list and
+ * update req msg
+ * paramters
+ * @mac_ctx: global mac ctx
+ * @req_buf: out param, roam offload scan request packet
+ *
+ * Return: void
+ */
+static CDF_STATUS
+csr_fetch_valid_ch_lst(tpAniSirGlobal mac_ctx,
+ tSirRoamOffloadScanReq *req_buf)
+{
+ CDF_STATUS status;
+ uint32_t host_channels = 0;
+ uint8_t *ch_lst = NULL;
+ uint8_t i = 0, num_channels = 0;
+
+ host_channels = sizeof(mac_ctx->roam.validChannelList);
+ status = csr_get_cfg_valid_channels(mac_ctx,
+ mac_ctx->roam.validChannelList,
+ &host_channels);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ FL("Failed to get the valid channel list"));
+ return status;
+ }
+ ch_lst = mac_ctx->roam.validChannelList;
+ mac_ctx->roam.numValidChannels = host_channels;
+ for (i = 0; i < mac_ctx->roam.numValidChannels; i++) {
+ if (((mac_ctx->roam.configParam.allowDFSChannelRoam
+ != CSR_ROAMING_DFS_CHANNEL_DISABLED) ||
+ (!CDS_IS_DFS_CH(*ch_lst))) && *ch_lst) {
+ req_buf->ValidChannelList[num_channels++] = *ch_lst;
+ }
+ ch_lst++;
+ }
+ req_buf->ValidChannelCount = num_channels;
+ return status;
+}
+
+/**
+ * csr_create_roam_scan_offload_request() - init roam offload scan request
+ *
+ * paramters
+ * @mac_ctx: global mac ctx
+ * @command: roam scan offload command input
+ * @session_id: session id
+ * @reason: reason to roam
+ * @session: roam session
+ * @roam_info: roam info struct
+ *
+ * Return: roam offload scan request packet buffer
+ */
+static tSirRoamOffloadScanReq *
+csr_create_roam_scan_offload_request(tpAniSirGlobal mac_ctx,
+ uint8_t command,
+ uint8_t session_id,
+ uint8_t reason,
+ tCsrRoamSession *session,
+ tpCsrNeighborRoamControlInfo roam_info)
+{
+ CDF_STATUS status;
+ uint8_t i, j, dot11_mode;
+ bool ese_neighbor_list_recvd = false;
+ uint8_t ch_cache_str[128] = { 0 };
+ tSirRoamOffloadScanReq *req_buf = NULL;
+ tpCsrChannelInfo curr_ch_lst_info =
+ &roam_info->roamChannelInfo.currentChannelListInfo;
+#ifdef FEATURE_WLAN_ESE
+ /*
+ * this flag will be true if connection is ESE and no neighbor
+ * list received or if the connection is not ESE
+ */
+ ese_neighbor_list_recvd = ((roam_info->isESEAssoc)
+ && (roam_info->roamChannelInfo.IAPPNeighborListReceived
+ == false))
+ || (roam_info->isESEAssoc == false);
+#endif /* FEATURE_WLAN_ESE */
+
+ req_buf = cdf_mem_malloc(sizeof(tSirRoamOffloadScanReq));
+ if (NULL == req_buf) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ FL("Mem alloc for roam scan offload req failed."));
+ return NULL;
+ }
+ cdf_mem_zero(req_buf, sizeof(tSirRoamOffloadScanReq));
+ req_buf->Command = command;
+ /*
+ * If command is STOP, then pass down ScanOffloadEnabled as Zero. This
+ * will handle the case of host driver reloads, but Riva still up and
+ * running
+ */
+ if (command == ROAM_SCAN_OFFLOAD_STOP) {
+ /*
+ * clear the roaming parameters that are per connection.
+ * For a new connection, they have to be programmed again.
+ */
+ if (csr_neighbor_middle_of_roaming((tHalHandle)mac_ctx,
+ session_id))
+ req_buf->middle_of_roaming = 1;
+ else
+ csr_roam_reset_roam_params(mac_ctx);
+ req_buf->RoamScanOffloadEnabled = 0;
+ } else {
+ req_buf->RoamScanOffloadEnabled =
+ mac_ctx->roam.configParam.isRoamOffloadScanEnabled;
+ }
+ cdf_mem_copy(req_buf->ConnectedNetwork.currAPbssid,
+ roam_info->currAPbssid.bytes, sizeof(struct cdf_mac_addr));
+ req_buf->ConnectedNetwork.ssId.length =
+ mac_ctx->roam.roamSession[session_id].
+ connectedProfile.SSID.length;
+ cdf_mem_copy(req_buf->ConnectedNetwork.ssId.ssId,
+ mac_ctx->roam.roamSession[session_id].
+ connectedProfile.SSID.ssId,
+ req_buf->ConnectedNetwork.ssId.length);
+ req_buf->ConnectedNetwork.authentication =
+ mac_ctx->roam.roamSession[session_id].connectedProfile.AuthType;
+ req_buf->ConnectedNetwork.encryption =
+ mac_ctx->roam.roamSession[session_id].
+ connectedProfile.EncryptionType;
+ req_buf->ConnectedNetwork.mcencryption =
+ mac_ctx->roam.roamSession[session_id].
+ connectedProfile.mcEncryptionType;
+#ifdef WLAN_FEATURE_11W
+ req_buf->ConnectedNetwork.mfp_enabled =
+ mac_ctx->roam.roamSession[session_id].connectedProfile.MFPEnabled;
+#endif
+ req_buf->delay_before_vdev_stop =
+ roam_info->cfgParams.delay_before_vdev_stop;
+ req_buf->OpportunisticScanThresholdDiff =
+ roam_info->cfgParams.nOpportunisticThresholdDiff;
+ req_buf->RoamRescanRssiDiff =
+ roam_info->cfgParams.nRoamRescanRssiDiff;
+ req_buf->RoamRssiDiff = mac_ctx->roam.configParam.RoamRssiDiff;
+ req_buf->reason = reason;
+ req_buf->NeighborScanTimerPeriod =
+ roam_info->cfgParams.neighborScanPeriod;
+ req_buf->NeighborRoamScanRefreshPeriod =
+ roam_info->cfgParams.neighborResultsRefreshPeriod;
+ req_buf->NeighborScanChannelMinTime =
+ roam_info->cfgParams.minChannelScanTime;
+ req_buf->NeighborScanChannelMaxTime =
+ roam_info->cfgParams.maxChannelScanTime;
+ req_buf->EmptyRefreshScanPeriod =
+ roam_info->cfgParams.emptyScanRefreshPeriod;
+ req_buf->RoamBmissFirstBcnt =
+ roam_info->cfgParams.nRoamBmissFirstBcnt;
+ req_buf->RoamBmissFinalBcnt =
+ roam_info->cfgParams.nRoamBmissFinalBcnt;
+ req_buf->RoamBeaconRssiWeight =
+ roam_info->cfgParams.nRoamBeaconRssiWeight;
+ /* MAWC feature */
+ req_buf->MAWCEnabled = mac_ctx->roam.configParam.MAWCEnabled;
+#ifdef FEATURE_WLAN_ESE
+ req_buf->IsESEAssoc =
+ csr_neighbor_roam_is_ese_assoc(mac_ctx, session_id) &&
+ ((req_buf->ConnectedNetwork.authentication ==
+ eCSR_AUTH_TYPE_OPEN_SYSTEM) ||
+ (csr_is_auth_type_ese(req_buf->
+ ConnectedNetwork.authentication)));
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ FL("LFR3:IsEseAssoc=%d\n"), req_buf->IsESEAssoc);
+#endif
+ if (ese_neighbor_list_recvd || curr_ch_lst_info->numOfChannels == 0) {
+ /*
+ * Retrieve the Channel Cache either from ini or from the
+ * occupied channels list. Give Preference to INI Channels
+ */
+ if (roam_info->cfgParams.channelInfo.numOfChannels) {
+ status = csr_fetch_ch_lst_from_ini(mac_ctx, roam_info,
+ req_buf);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ cdf_mem_free(req_buf);
+ return NULL;
+ }
+ } else {
+ csr_fetch_ch_lst_from_occupied_lst(mac_ctx, session_id,
+ reason, req_buf, roam_info);
+ }
+ }
+#ifdef FEATURE_WLAN_ESE
+ else {
+ /*
+ * If ESE is enabled, and a neighbor Report is received,then
+ * Ignore the INI Channels or the Occupied Channel List.
+ * Consider the channels in the neighbor list sent by the ESE AP
+ */
+ csr_fetch_ch_lst_from_received_list(mac_ctx, roam_info,
+ curr_ch_lst_info, req_buf);
+ }
+#endif
+ for (i = 0, j = 0; i < req_buf->ConnectedNetwork.ChannelCount; i++) {
+ if (j < sizeof(ch_cache_str)) {
+ j += snprintf(ch_cache_str + j,
+ sizeof(ch_cache_str) - j, " %d",
+ req_buf->ConnectedNetwork.
+ ChannelCache[i]);
+ } else
+ break;
+ }
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ FL("ChnlCacheType:%d, No of Chnls:%d,Channels: %s"),
+ req_buf->ChannelCacheType,
+ req_buf->ConnectedNetwork.ChannelCount, ch_cache_str);
+
+ /* Maintain the Valid Channels List */
+ status = csr_fetch_valid_ch_lst(mac_ctx, req_buf);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ cdf_mem_free(req_buf);
+ return NULL;
+ }
+
+ req_buf->MDID.mdiePresent =
+ mac_ctx->roam.roamSession[session_id].
+ connectedProfile.MDID.mdiePresent;
+ req_buf->MDID.mobilityDomain =
+ mac_ctx->roam.roamSession[session_id].
+ connectedProfile.MDID.mobilityDomain;
+ req_buf->sessionId = session_id;
+ req_buf->nProbes = mac_ctx->roam.configParam.nProbes;
+ req_buf->HomeAwayTime = mac_ctx->roam.configParam.nRoamScanHomeAwayTime;
+
+ /*
+ * Home Away Time should be at least equal to (MaxDwell time + (2*RFS)),
+ * where RFS is the RF Switching time. It is twice RFS to consider the
+ * time to go off channel and return to the home channel.
+ */
+ if (req_buf->HomeAwayTime < (req_buf->NeighborScanChannelMaxTime +
+ (2 * CSR_ROAM_SCAN_CHANNEL_SWITCH_TIME))) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_WARN,
+ FL("Invalid config, Home away time(%d) is less than (twice RF switching time + channel max time)(%d). Hence enforcing home away time to disable (0)"),
+ req_buf->HomeAwayTime,
+ (req_buf->NeighborScanChannelMaxTime +
+ (2 * CSR_ROAM_SCAN_CHANNEL_SWITCH_TIME)));
+ req_buf->HomeAwayTime = 0;
+ }
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ FL("HomeAwayTime:%d"), req_buf->HomeAwayTime);
+
+ /*Prepare a probe request for 2.4GHz band and one for 5GHz band */
+ dot11_mode = (uint8_t) csr_translate_to_wni_cfg_dot11_mode(mac_ctx,
+ csr_find_best_phy_mode(mac_ctx,
+ mac_ctx->roam.configParam.phyMode));
+ csr_roam_scan_offload_prepare_probe_req_template(mac_ctx,
+ SIR_ROAM_SCAN_24G_DEFAULT_CH, dot11_mode,
+ session->selfMacAddr.bytes, req_buf->p24GProbeTemplate,
+ &req_buf->us24GProbeTemplateLen, session);
+
+ csr_roam_scan_offload_prepare_probe_req_template(mac_ctx,
+ SIR_ROAM_SCAN_5G_DEFAULT_CH, dot11_mode,
+ session->selfMacAddr.bytes,
+ req_buf->p5GProbeTemplate, &req_buf->us5GProbeTemplateLen,
+ session);
+ req_buf->allowDFSChannelRoam =
+ mac_ctx->roam.configParam.allowDFSChannelRoam;
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+ req_buf->RoamOffloadEnabled = csr_roamIsRoamOffloadEnabled(mac_ctx);
+ req_buf->RoamKeyMgmtOffloadEnabled = session->RoamKeyMgmtOffloadEnabled;
+ /* Roam Offload piggybacks upon the Roam Scan offload command. */
+ if (req_buf->RoamOffloadEnabled)
+ csr_update_roam_scan_offload_request(mac_ctx, req_buf, session);
+ cdf_mem_copy(&req_buf->roam_params,
+ &mac_ctx->roam.configParam.roam_params,
+ sizeof(req_buf->roam_params));
+#endif
+ return req_buf;
+}
+/**
+ * check_allowed_ssid_list() - Check the WhiteList
+ * @req_buffer: Buffer which contains the connected profile SSID.
+ * @roam_params: Buffer which contains the whitelist SSID's.
+ *
+ * Check if the connected profile SSID exists in the whitelist.
+ * It is assumed that the framework provides this also in the whitelist.
+ * If it exists there is no issue. Otherwise add it to the list.
+ *
+ * Return: None
+ */
+static void check_allowed_ssid_list(tSirRoamOffloadScanReq *req_buffer,
+ struct roam_ext_params *roam_params)
+{
+ int i = 0;
+ bool match = false;
+ for (i = 0; i < roam_params->num_ssid_allowed_list; i++) {
+ if ((roam_params->ssid_allowed_list[i].length ==
+ req_buffer->ConnectedNetwork.ssId.length) &&
+ cdf_mem_compare(roam_params->ssid_allowed_list[i].ssId,
+ req_buffer->ConnectedNetwork.ssId.ssId,
+ roam_params->ssid_allowed_list[i].length)) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ "Whitelist contains connected profile SSID");
+ match = true;
+ break;
+ }
+ }
+ if (!match) {
+ if (roam_params->num_ssid_allowed_list >=
+ MAX_SSID_ALLOWED_LIST) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ "Whitelist is FULL. Cannot Add another entry");
+ return;
+ }
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ "Adding Connected profile SSID to whitelist");
+ /* i is the next available index to add the entry.*/
+ i = roam_params->num_ssid_allowed_list;
+ cdf_mem_copy(roam_params->ssid_allowed_list[i].ssId,
+ req_buffer->ConnectedNetwork.ssId.ssId,
+ req_buffer->ConnectedNetwork.ssId.length);
+ roam_params->ssid_allowed_list[i].length =
+ req_buffer->ConnectedNetwork.ssId.length;
+ roam_params->num_ssid_allowed_list++;
+ }
+}
+
+/*
+ * Below Table describe whether RSO command can be send down to fimrware or not.
+ * Host check it on the basis of previous RSO command sent down to firmware.
+ *||==========================================================================||
+ *|| New cmd | LAST SENT COMMAND ---> ||
+ *||====|=====================================================================||
+ *|| V | RSO_START | RSO_STOP | RSO_RESTART | RSO_UPDATE_CFG||
+ *|| -------------------------------------------------------------------------||
+ *|| RSO_START | NO | YES | NO | NO ||
+ *|| RSO_STOP | YES | YES | YES | YES ||
+ *|| RSO_RESTART | YES | NO | NO | YES ||
+ *|| RSO_UPDATE_CFG | YES | NO | YES | YES ||
+ *||==========================================================================||
+ **/
+#define RSO_START_BIT (1<<ROAM_SCAN_OFFLOAD_START)
+#define RSO_STOP_BIT (1<<ROAM_SCAN_OFFLOAD_STOP)
+#define RSO_RESTART_BIT (1<<ROAM_SCAN_OFFLOAD_RESTART)
+#define RSO_UPDATE_CFG_BIT (1<<ROAM_SCAN_OFFLOAD_UPDATE_CFG)
+#define RSO_START_ALLOW_MASK (RSO_STOP_BIT)
+#define RSO_STOP_ALLOW_MASK (RSO_UPDATE_CFG_BIT | RSO_RESTART_BIT | \
+ RSO_STOP_BIT | RSO_START_BIT)
+#define RSO_RESTART_ALLOW_MASK (RSO_UPDATE_CFG_BIT | RSO_START_BIT)
+#define RSO_UPDATE_CFG_ALLOW_MASK (RSO_UPDATE_CFG_BIT | RSO_STOP_BIT | \
+ RSO_START_BIT)
+
+bool csr_is_RSO_cmd_allowed(tpAniSirGlobal mac_ctx, uint8_t command,
+ uint8_t session_id)
+{
+ tpCsrNeighborRoamControlInfo neigh_roam_info =
+ &mac_ctx->roam.neighborRoamInfo[session_id];
+ uint8_t desiredMask = 0;
+ bool ret_val;
+
+ switch (command) {
+ case ROAM_SCAN_OFFLOAD_START:
+ desiredMask = RSO_START_ALLOW_MASK;
+ break;
+ case ROAM_SCAN_OFFLOAD_STOP:
+ desiredMask = RSO_STOP_ALLOW_MASK;
+ break;
+ case ROAM_SCAN_OFFLOAD_RESTART:
+ desiredMask = RSO_RESTART_ALLOW_MASK;
+ break;
+ case ROAM_SCAN_OFFLOAD_UPDATE_CFG:
+ desiredMask = RSO_UPDATE_CFG_ALLOW_MASK;
+ break;
+ default:
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ FL("Wrong RSO command %d, not allowed"), command);
+ return 0;/*Cmd Not allowed*/
+ }
+ ret_val = desiredMask & (1 << neigh_roam_info->last_sent_cmd);
+ return ret_val;
+}
+
+/**
+ * csr_roam_offload_scan() - populates roam offload scan request and sends to
+ * WMA
+ *
+ * paramters
+ * @mac_ctx: global mac ctx
+ * @session_id: session id
+ * @command: roam scan offload command input
+ * @reason: reason to roam
+ *
+ * Return: result of operation
+ */
+CDF_STATUS
+csr_roam_offload_scan(tpAniSirGlobal mac_ctx, uint8_t session_id,
+ uint8_t command, uint8_t reason)
+{
+ uint8_t *state = NULL;
+ cds_msg_t msg;
+ tSirRoamOffloadScanReq *req_buf;
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id);
+ tpCsrNeighborRoamControlInfo roam_info =
+ &mac_ctx->roam.neighborRoamInfo[session_id];
+ struct roam_ext_params *roam_params_dst;
+ struct roam_ext_params *roam_params_src;
+ uint8_t i;
+
+ if (NULL == session) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ FL("session is null"));
+ return CDF_STATUS_E_FAILURE;
+ }
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+ if (session->roamOffloadSynchParams.bRoamSynchInProgress
+ && (ROAM_SCAN_OFFLOAD_STOP == command)) {
+ /*
+ * When roam synch is in progress for propagation, there is no
+ * need to send down the STOP command since the firmware is not
+ * expecting any WMI commands when the roam synch is in progress
+ */
+ b_roam_scan_offload_started = false;
+ return CDF_STATUS_SUCCESS;
+ }
+#endif
+ if (0 == csr_roam_is_roam_offload_scan_enabled(mac_ctx)) {
+ sms_log(mac_ctx, LOGE, "isRoamOffloadScanEnabled not set");
+ return CDF_STATUS_E_FAILURE;
+ }
+ if (!csr_is_RSO_cmd_allowed(mac_ctx, command, session_id) &&
+ reason != REASON_ROAM_SET_BLACKLIST_BSSID) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ FL("RSO out-of-sync command %d lastSentCmd %d"),
+ command, roam_info->last_sent_cmd);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ if ((true == b_roam_scan_offload_started)
+ && (ROAM_SCAN_OFFLOAD_START == command)) {
+ sms_log(mac_ctx, LOGE, "Roam Scan Offload is already started");
+ return CDF_STATUS_E_FAILURE;
+ }
+ /*
+ * The Dynamic Config Items Update may happen even if the state is in
+ * INIT. It is important to ensure that the command is passed down to
+ * the FW only if the Infra Station is in a connected state.A connected
+ * station could also be in a PREAUTH or REASSOC states.So, consider not
+ * sending the command down in INIT state. We also have to ensure that
+ * if there is a STOP command we always have to inform Riva,
+ * irrespective of whichever state we are in
+ */
+
+ if ((roam_info->neighborRoamState ==
+ eCSR_NEIGHBOR_ROAM_STATE_INIT) &&
+ (command != ROAM_SCAN_OFFLOAD_STOP) &&
+ (reason != REASON_ROAM_SET_BLACKLIST_BSSID)) {
+ state = mac_trace_get_neighbour_roam_state(
+ roam_info->neighborRoamState);
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ FL("Scan Command not sent to FW state=%s and cmd=%d"),
+ state, command);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ req_buf = csr_create_roam_scan_offload_request(mac_ctx, command,
+ session_id, reason,
+ session, roam_info);
+ if (!req_buf) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ FL("Failed to create req packet"));
+ return CDF_STATUS_E_FAILURE;
+ }
+ roam_params_dst = &req_buf->roam_params;
+ roam_params_src = &mac_ctx->roam.configParam.roam_params;
+ if (reason == REASON_ROAM_SET_SSID_ALLOWED)
+ check_allowed_ssid_list(req_buf, roam_params_src);
+ /*
+ * Configure the lookup threshold either from INI or from framework.
+ * If both are present, give higher priority to the one from framework.
+ */
+ if (roam_params_src->alert_rssi_threshold)
+ req_buf->LookupThreshold =
+ roam_params_src->alert_rssi_threshold;
+ else
+ req_buf->LookupThreshold =
+ (int8_t)roam_info->cfgParams.neighborLookupThreshold *
+ (-1);
+ cdf_mem_copy(roam_params_dst, roam_params_src,
+ sizeof(struct roam_ext_params));
+ /*
+ * rssi_diff which is updated via framework is equivalent to the
+ * INI RoamRssiDiff parameter and hence should be updated.
+ */
+ if (roam_params_src->rssi_diff)
+ req_buf->RoamRssiDiff = roam_params_src->rssi_diff;
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ "num_bssid_avoid_list: %d, num_ssid_allowed_list: %d, "
+ "num_bssid_favored: %d, raise_rssi_thresh_5g: %d, "
+ "drop_rssi_thresh_5g: %d, raise_rssi_type_5g: %d, "
+ "raise_factor_5g: %d, drop_rssi_type_5g: %d, "
+ "drop_factor_5g: %d, max_raise_rssi_5g: %d, "
+ "max_drop_rssi_5g: %d, rssi_diff: %d, alert_rssi_threshold:%d",
+ roam_params_dst->num_bssid_avoid_list,
+ roam_params_dst->num_ssid_allowed_list,
+ roam_params_dst->num_bssid_favored,
+ roam_params_dst->raise_rssi_thresh_5g,
+ roam_params_dst->drop_rssi_thresh_5g,
+ roam_params_dst->raise_rssi_type_5g,
+ roam_params_dst->raise_factor_5g,
+ roam_params_dst->drop_rssi_type_5g,
+ roam_params_dst->drop_factor_5g,
+ roam_params_dst->max_raise_rssi_5g,
+ roam_params_dst->max_drop_rssi_5g,
+ req_buf->RoamRssiDiff, roam_params_dst->alert_rssi_threshold);
+
+ for (i = 0; i < roam_params_dst->num_bssid_avoid_list; i++) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ "Blacklist Bssid: ("MAC_ADDRESS_STR")",
+ MAC_ADDR_ARRAY(roam_params_dst->bssid_avoid_list[i]));
+ }
+ for (i = 0; i < roam_params_dst->num_ssid_allowed_list; i++) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ "Whitelist: %.*s",
+ roam_params_dst->ssid_allowed_list[i].length,
+ roam_params_dst->ssid_allowed_list[i].ssId);
+ }
+ for (i = 0; i < roam_params_dst->num_bssid_favored; i++) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ "Preferred Bssid: ("MAC_ADDRESS_STR") score: %d",
+ MAC_ADDR_ARRAY(roam_params_dst->bssid_favored[i]),
+ roam_params_dst->bssid_favored_factor[i]);
+ }
+
+ req_buf->hi_rssi_scan_max_count =
+ roam_info->cfgParams.hi_rssi_scan_max_count;
+ req_buf->hi_rssi_scan_rssi_delta =
+ roam_info->cfgParams.hi_rssi_scan_rssi_delta;
+ req_buf->hi_rssi_scan_delay =
+ roam_info->cfgParams.hi_rssi_scan_delay;
+ req_buf->hi_rssi_scan_rssi_ub =
+ roam_info->cfgParams.hi_rssi_scan_rssi_ub;
+
+ msg.type = WMA_ROAM_SCAN_OFFLOAD_REQ;
+ msg.reserved = 0;
+ msg.bodyptr = req_buf;
+ if (!CDF_IS_STATUS_SUCCESS
+ (cds_mq_post_message(CDF_MODULE_ID_WMA, &msg))) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ "%s: Not able to post message to WMA",
+ __func__);
+ cdf_mem_free(req_buf);
+ return CDF_STATUS_E_FAILURE;
+ } else {
+ if (ROAM_SCAN_OFFLOAD_START == command)
+ b_roam_scan_offload_started = true;
+ else if (ROAM_SCAN_OFFLOAD_STOP == command)
+ b_roam_scan_offload_started = false;
+ }
+ /* update the last sent cmd */
+ roam_info->last_sent_cmd = command;
+
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ "Roam Scan Offload Command %d, Reason %d", command, reason);
+ return status;
+}
+
+CDF_STATUS csr_roam_offload_scan_rsp_hdlr(tpAniSirGlobal pMac,
+ tpSirRoamOffloadScanRsp scanOffloadRsp)
+{
+ switch (scanOffloadRsp->reason) {
+ case 0:
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ "Rsp for Roam Scan Offload with failure status");
+ break;
+ case REASON_OS_REQUESTED_ROAMING_NOW:
+ csr_neighbor_roam_proceed_with_handoff_req(pMac,
+ scanOffloadRsp->sessionId);
+ break;
+
+ default:
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ "Rsp for Roam Scan Offload with reason %d",
+ scanOffloadRsp->reason);
+ }
+ return CDF_STATUS_SUCCESS;
+}
+
+tCsrPeStatsReqInfo *csr_roam_check_pe_stats_req_list(tpAniSirGlobal pMac,
+ uint32_t statsMask,
+ uint32_t periodicity,
+ bool *pFound,
+ uint8_t staId, uint8_t sessionId)
+{
+ bool found = false;
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tCsrPeStatsReqInfo staEntry;
+ tCsrPeStatsReqInfo *pTempStaEntry = NULL;
+ tListElem *pStaEntry = NULL;
+ CDF_STATUS cdf_status;
+ *pFound = false;
+
+ pStaEntry = csr_roam_find_in_pe_stats_req_list(pMac, statsMask);
+ if (pStaEntry) {
+ pTempStaEntry =
+ GET_BASE_ADDR(pStaEntry, tCsrPeStatsReqInfo, link);
+ if (pTempStaEntry->periodicity) {
+ pTempStaEntry->periodicity =
+ CDF_MIN(periodicity,
+ pTempStaEntry->periodicity);
+ } else {
+ pTempStaEntry->periodicity = periodicity;
+ }
+ pTempStaEntry->numClient++;
+ found = true;
+ } else {
+ cdf_mem_set(&staEntry, sizeof(tCsrPeStatsReqInfo), 0);
+ staEntry.numClient = 1;
+ staEntry.periodicity = periodicity;
+ staEntry.pMac = pMac;
+ staEntry.rspPending = false;
+ staEntry.staId = staId;
+ staEntry.statsMask = statsMask;
+ staEntry.timerRunning = false;
+ staEntry.sessionId = sessionId;
+ pTempStaEntry =
+ csr_roam_insert_entry_into_pe_stats_req_list(pMac,
+ &pMac->roam.
+ peStatsReqList,
+ &staEntry);
+ if (!pTempStaEntry) {
+ /* msg */
+ sms_log(pMac, LOGW,
+ "csr_roam_check_pe_stats_req_list: Failed to insert req in peStatsReqList");
+ return NULL;
+ }
+ }
+ pTempStaEntry->periodicity =
+ pMac->roam.configParam.statsReqPeriodicityInPS;
+
+ if (!pTempStaEntry->timerRunning) {
+ /* send down a req in case of one time req, for periodic ones wait for timer to expire */
+ if (!pTempStaEntry->rspPending && !pTempStaEntry->periodicity) {
+ status = csr_send_mb_stats_req_msg(pMac,
+ statsMask & ~(1 <<
+ eCsrGlobalClassDStats),
+ staId, sessionId);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ FL
+ ("csr_roam_check_pe_stats_req_list:failed to send down stats req to PE"));
+ } else {
+ pTempStaEntry->rspPending = true;
+ }
+ }
+ if (pTempStaEntry->periodicity) {
+ if (!found) {
+
+ cdf_status =
+ cdf_mc_timer_init(&pTempStaEntry->
+ hPeStatsTimer,
+ CDF_TIMER_TYPE_SW,
+ csr_roam_pe_stats_timer_handler,
+ pTempStaEntry);
+ if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
+ sms_log(pMac, LOGE,
+ FL
+ ("csr_roam_check_pe_stats_req_list:cannot init hPeStatsTimer timer"));
+ return NULL;
+ }
+ }
+ /* start timer */
+ sms_log(pMac, LOG1,
+ "csr_roam_check_pe_stats_req_list:peStatsTimer period %d",
+ pTempStaEntry->periodicity);
+ cdf_status =
+ cdf_mc_timer_start(&pTempStaEntry->hPeStatsTimer,
+ pTempStaEntry->periodicity);
+ if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
+ sms_log(pMac, LOGE,
+ FL
+ ("csr_roam_check_pe_stats_req_list:cannot start hPeStatsTimer timer"));
+ return NULL;
+ }
+ pTempStaEntry->timerRunning = true;
+ }
+ }
+ *pFound = found;
+ return pTempStaEntry;
+}
+
+/*
+ pStaEntry is no longer invalid upon the return of this function.
+ */
+static void csr_roam_remove_stat_list_entry(tpAniSirGlobal pMac, tListElem *pEntry)
+{
+ if (pEntry) {
+ if (csr_ll_remove_entry
+ (&pMac->roam.statsClientReqList, pEntry, LL_ACCESS_LOCK)) {
+ cdf_mem_free(GET_BASE_ADDR
+ (pEntry, tCsrStatsClientReqInfo, link));
+ }
+ }
+}
+
+void csr_roam_remove_entry_from_pe_stats_req_list(tpAniSirGlobal pMac,
+ tCsrPeStatsReqInfo *pPeStaEntry)
+{
+ tListElem *pEntry;
+ tCsrPeStatsReqInfo *pTempStaEntry;
+ CDF_STATUS cdf_status;
+ pEntry = csr_ll_peek_head(&pMac->roam.peStatsReqList, LL_ACCESS_LOCK);
+ if (!pEntry) {
+ sms_log(pMac, LOGE, FL(" List empty, no stats req for PE"));
+ return;
+ }
+ while (pEntry) {
+ pTempStaEntry = GET_BASE_ADDR(pEntry, tCsrPeStatsReqInfo, link);
+ if (NULL == pTempStaEntry
+ || (pTempStaEntry->statsMask !=
+ pPeStaEntry->statsMask)) {
+ pEntry = csr_ll_next(&pMac->roam.peStatsReqList, pEntry,
+ LL_ACCESS_NOLOCK);
+ continue;
+ }
+ sms_log(pMac, LOGW, FL("Match found"));
+ if (pTempStaEntry->timerRunning) {
+ cdf_status = cdf_mc_timer_stop(
+ &pTempStaEntry->hPeStatsTimer);
+ /*
+ * If we are not able to stop the timer here, just
+ * remove the entry from the linked list. Destroy the
+ * timer object and free the memory in the timer CB
+ */
+ if (cdf_status == CDF_STATUS_SUCCESS) {
+ /* the timer is successfully stopped */
+ pTempStaEntry->timerRunning = false;
+ /* Destroy the timer */
+ cdf_status = cdf_mc_timer_destroy(
+ &pTempStaEntry->hPeStatsTimer);
+ } else {
+ /*
+ * the timer could not be stopped. Hence destroy
+ * and free the memory for the PE stat entry in
+ * the timer CB.
+ */
+ pTempStaEntry->timerStopFailed = true;
+ }
+ if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
+ sms_log(pMac, LOGE,
+ FL("failed to stop/destroy timer"));
+ }
+ }
+
+ if (csr_ll_remove_entry(&pMac->roam.peStatsReqList, pEntry,
+ LL_ACCESS_LOCK)) {
+ /*
+ * Only free the memory if we could stop the timer
+ * successfully
+ */
+ if (!pTempStaEntry->timerStopFailed) {
+ cdf_mem_free(pTempStaEntry);
+ pTempStaEntry = NULL;
+ }
+ break;
+ }
+ pEntry = csr_ll_next(&pMac->roam.peStatsReqList, pEntry,
+ LL_ACCESS_NOLOCK);
+ } /* end of while loop */
+ return;
+}
+
+void csr_roam_report_statistics(tpAniSirGlobal pMac, uint32_t statsMask,
+ tCsrStatsCallback callback, uint8_t staId,
+ void *pContext)
+{
+ uint8_t stats[500];
+ uint8_t *pStats = NULL;
+ uint32_t tempMask = 0;
+ uint8_t counter = 0;
+ if (!callback) {
+ sms_log(pMac, LOGE, FL("Cannot report callback NULL"));
+ return;
+ }
+ if (!statsMask) {
+ sms_log(pMac, LOGE, FL("Cannot report statsMask is 0"));
+ return;
+ }
+ pStats = stats;
+ tempMask = statsMask;
+ while (tempMask) {
+ if (tempMask & 1) {
+ /* new stats info from PE, fill up the stats strucutres in PMAC */
+ switch (counter) {
+ case eCsrSummaryStats:
+ sms_log(pMac, LOG2, FL("Summary stats"));
+ cdf_mem_copy(pStats,
+ (uint8_t *) &pMac->roam.
+ summaryStatsInfo,
+ sizeof(tCsrSummaryStatsInfo));
+ pStats += sizeof(tCsrSummaryStatsInfo);
+ break;
+ case eCsrGlobalClassAStats:
+ sms_log(pMac, LOG2, FL("ClassA stats"));
+ cdf_mem_copy(pStats,
+ (uint8_t *) &pMac->roam.
+ classAStatsInfo,
+ sizeof(tCsrGlobalClassAStatsInfo));
+ pStats += sizeof(tCsrGlobalClassAStatsInfo);
+ break;
+ case eCsrGlobalClassBStats:
+ sms_log(pMac, LOG2, FL("ClassB stats"));
+ cdf_mem_copy(pStats,
+ (uint8_t *) &pMac->roam.
+ classBStatsInfo,
+ sizeof(tCsrGlobalClassBStatsInfo));
+ pStats += sizeof(tCsrGlobalClassBStatsInfo);
+ break;
+ case eCsrGlobalClassCStats:
+ sms_log(pMac, LOG2, FL("ClassC stats"));
+ cdf_mem_copy(pStats,
+ (uint8_t *) &pMac->roam.
+ classCStatsInfo,
+ sizeof(tCsrGlobalClassCStatsInfo));
+ pStats += sizeof(tCsrGlobalClassCStatsInfo);
+ break;
+ case eCsrGlobalClassDStats:
+ sms_log(pMac, LOG2, FL("ClassD stats"));
+ cdf_mem_copy(pStats,
+ (uint8_t *) &pMac->roam.
+ classDStatsInfo,
+ sizeof(tCsrGlobalClassDStatsInfo));
+ pStats += sizeof(tCsrGlobalClassDStatsInfo);
+ break;
+ case eCsrPerStaStats:
+ sms_log(pMac, LOG2, FL("PerSta stats"));
+ cdf_mem_copy(pStats,
+ (uint8_t *) &pMac->roam.
+ perStaStatsInfo[staId],
+ sizeof(tCsrPerStaStatsInfo));
+ pStats += sizeof(tCsrPerStaStatsInfo);
+ break;
+ default:
+ sms_log(pMac, LOGE,
+ FL("Unknown stats type and counter %d"),
+ counter);
+ break;
+ }
+ }
+ tempMask >>= 1;
+ counter++;
+ }
+ callback(stats, pContext);
+}
+
+CDF_STATUS csr_roam_dereg_statistics_req(tpAniSirGlobal pMac)
+{
+ tListElem *pEntry = NULL;
+ tListElem *pPrevEntry = NULL;
+ tCsrStatsClientReqInfo *pTempStaEntry = NULL;
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ CDF_STATUS cdf_status;
+ pEntry = csr_ll_peek_head(&pMac->roam.statsClientReqList, LL_ACCESS_LOCK);
+ if (!pEntry) {
+ /* list empty */
+ sms_log(pMac, LOGW,
+ "csr_roam_dereg_statistics_req: List empty, no request from "
+ "upper layer client(s)");
+ return status;
+ }
+ while (pEntry) {
+ if (pPrevEntry) {
+ pTempStaEntry =
+ GET_BASE_ADDR(pPrevEntry, tCsrStatsClientReqInfo,
+ link);
+ /* send up the stats report */
+ csr_roam_report_statistics(pMac, pTempStaEntry->statsMask,
+ pTempStaEntry->callback,
+ pTempStaEntry->staId,
+ pTempStaEntry->pContext);
+ csr_roam_remove_stat_list_entry(pMac, pPrevEntry);
+ }
+ pTempStaEntry =
+ GET_BASE_ADDR(pEntry, tCsrStatsClientReqInfo, link);
+ if (pTempStaEntry->pPeStaEntry) {
+ /* pPeStaEntry can be NULL */
+ pTempStaEntry->pPeStaEntry->numClient--;
+ /* check if we need to delete the entry from peStatsReqList too */
+ if (!pTempStaEntry->pPeStaEntry->numClient) {
+ csr_roam_remove_entry_from_pe_stats_req_list(pMac,
+ pTempStaEntry->
+ pPeStaEntry);
+ }
+ }
+ /* check if we need to stop the tl stats timer too */
+ pMac->roam.tlStatsReqInfo.numClient--;
+ if (!pMac->roam.tlStatsReqInfo.numClient) {
+ if (pMac->roam.tlStatsReqInfo.timerRunning) {
+ status =
+ cdf_mc_timer_stop(&pMac->roam.
+ tlStatsReqInfo.
+ hTlStatsTimer);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ FL
+ ("csr_roam_dereg_statistics_req:cannot stop TlStatsTimer timer"));
+ /* we will continue */
+ }
+ }
+ pMac->roam.tlStatsReqInfo.periodicity = 0;
+ pMac->roam.tlStatsReqInfo.timerRunning = false;
+ }
+ if (pTempStaEntry->periodicity) {
+ /* While creating StaEntry in csr_get_statistics, */
+ /* Initializing and starting timer only when periodicity is set. */
+ /* So Stop and Destroy timer only when periodicity is set. */
+
+ cdf_mc_timer_stop(&pTempStaEntry->timer);
+ /* Destroy the cdf timer... */
+ cdf_status =
+ cdf_mc_timer_destroy(&pTempStaEntry->timer);
+ if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
+ sms_log(pMac, LOGE,
+ FL
+ ("csr_roam_dereg_statistics_req:failed to destroy Client req timer"));
+ }
+ }
+
+ pPrevEntry = pEntry;
+ pEntry =
+ csr_ll_next(&pMac->roam.statsClientReqList, pEntry,
+ LL_ACCESS_NOLOCK);
+ }
+ /* the last one */
+ if (pPrevEntry) {
+ pTempStaEntry =
+ GET_BASE_ADDR(pPrevEntry, tCsrStatsClientReqInfo, link);
+ /* send up the stats report */
+ csr_roam_report_statistics(pMac, pTempStaEntry->statsMask,
+ pTempStaEntry->callback,
+ pTempStaEntry->staId,
+ pTempStaEntry->pContext);
+ csr_roam_remove_stat_list_entry(pMac, pPrevEntry);
+ }
+ return status;
+
+}
+
+tSmeCmd *csr_get_command_buffer(tpAniSirGlobal pMac)
+{
+ tSmeCmd *pCmd = sme_get_command_buffer(pMac);
+ if (pCmd) {
+ pMac->roam.sPendingCommands++;
+ }
+ return pCmd;
+}
+
+void csr_release_command(tpAniSirGlobal pMac, tSmeCmd *pCommand)
+{
+ if (pMac->roam.sPendingCommands > 0) {
+ /* All command allocated through csr_get_command_buffer need to */
+ /* decrement the pending count when releasing. */
+ pMac->roam.sPendingCommands--;
+ sme_release_command(pMac, pCommand);
+ } else {
+ sms_log(pMac, LOGE, FL("no pending commands"));
+ CDF_ASSERT(0);
+ }
+}
+
+/* Return SUCCESS is the command is queued, failed */
+CDF_STATUS csr_queue_sme_command(tpAniSirGlobal pMac, tSmeCmd *pCommand,
+ bool fHighPriority)
+{
+ bool fNoCmdPending;
+
+ if (!SME_IS_START(pMac)) {
+ sms_log(pMac, LOGE, FL("Sme in stop state"));
+ CDF_ASSERT(0);
+ return CDF_STATUS_E_PERM;
+ }
+
+ if ((eSmeCommandScan == pCommand->command) && pMac->scan.fDropScanCmd) {
+ sms_log(pMac, LOGW, FL(" drop scan (scan reason %d) command"),
+ pCommand->u.scanCmd.reason);
+ return CDF_STATUS_CSR_WRONG_STATE;
+ }
+
+ if ((pCommand->command == eSmeCommandScan)
+ || (pCommand->command == eSmeCommandRemainOnChannel)) {
+ sms_log(pMac, LOGW,
+ FL("scan pending list count %d scan_id %d"),
+ pMac->sme.smeScanCmdPendingList.Count,
+ pCommand->u.scanCmd.scanID);
+ csr_ll_insert_tail(&pMac->sme.smeScanCmdPendingList,
+ &pCommand->Link, LL_ACCESS_LOCK);
+ /* process the command queue... */
+ sme_process_pending_queue(pMac);
+ return CDF_STATUS_SUCCESS;
+ }
+ /* Make sure roamCmdPendingList is not empty first */
+ fNoCmdPending =
+ csr_ll_is_list_empty(&pMac->roam.roamCmdPendingList, false);
+ if (fNoCmdPending) {
+ sme_push_command(pMac, pCommand, fHighPriority);
+ } else {
+ /* no list lock is needed since SME lock is held */
+ if (!fHighPriority) {
+ csr_ll_insert_tail(&pMac->roam.roamCmdPendingList,
+ &pCommand->Link, false);
+ } else {
+ csr_ll_insert_head(&pMac->roam.roamCmdPendingList,
+ &pCommand->Link, false);
+ }
+ }
+ return CDF_STATUS_SUCCESS;
+}
+
+CDF_STATUS csr_roam_update_apwpsie(tpAniSirGlobal pMac, uint32_t sessionId,
+ tSirAPWPSIEs *pAPWPSIES)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSirUpdateAPWPSIEsReq *pMsg;
+
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+ if (NULL == pSession) {
+ sms_log(pMac, LOGE,
+ FL(" Session does not exist for session id %d"),
+ sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ do {
+ pMsg = cdf_mem_malloc(sizeof(tSirUpdateAPWPSIEsReq));
+ if (NULL == pMsg)
+ return CDF_STATUS_E_NOMEM;
+ cdf_mem_set(pMsg, sizeof(tSirUpdateAPWPSIEsReq), 0);
+ pMsg->messageType = eWNI_SME_UPDATE_APWPSIE_REQ;
+ pMsg->transactionId = 0;
+ cdf_mem_copy(pMsg->bssId, &pSession->selfMacAddr,
+ sizeof(tSirMacAddr));
+ pMsg->sessionId = sessionId;
+ cdf_mem_copy(&pMsg->APWPSIEs, pAPWPSIES,
+ sizeof(tSirAPWPSIEs));
+ pMsg->length = sizeof(struct sSirUpdateAPWPSIEsReq);
+ status = cds_send_mb_message_to_mac(pMsg);
+ } while (0);
+ return status;
+}
+
+CDF_STATUS csr_roam_update_wparsni_es(tpAniSirGlobal pMac, uint32_t sessionId,
+ tSirRSNie *pAPSirRSNie)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSirUpdateAPWPARSNIEsReq *pMsg;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+ if (NULL == pSession) {
+ sms_log(pMac, LOGE,
+ FL(" Session does not exist for session id %d"),
+ sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+ do {
+ pMsg = cdf_mem_malloc(sizeof(tSirUpdateAPWPARSNIEsReq));
+ if (NULL == pMsg)
+ return CDF_STATUS_E_NOMEM;
+ cdf_mem_set(pMsg, sizeof(tSirUpdateAPWPARSNIEsReq), 0);
+ pMsg->messageType = eWNI_SME_SET_APWPARSNIEs_REQ;
+ pMsg->transactionId = 0;
+ cdf_mem_copy(pMsg->bssId, &pSession->selfMacAddr,
+ sizeof(tSirMacAddr));
+ pMsg->sessionId = sessionId;
+ cdf_mem_copy(&pMsg->APWPARSNIEs, pAPSirRSNie,
+ sizeof(tSirRSNie));
+ pMsg->length = sizeof(struct sSirUpdateAPWPARSNIEsReq);
+ status = cds_send_mb_message_to_mac(pMsg);
+ } while (0);
+ return status;
+}
+
+#ifdef WLAN_FEATURE_VOWIFI_11R
+CDF_STATUS
+csr_roam_issue_ft_preauth_req(tHalHandle hHal, uint32_t sessionId,
+ tpSirBssDescription pBssDescription)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ tpSirFTPreAuthReq pftPreAuthReq;
+ uint16_t auth_req_len = 0;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (NULL == pSession) {
+ sms_log(pMac, LOGE,
+ FL("Session does not exist for session id(%d)"),
+ sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ auth_req_len = sizeof(tSirFTPreAuthReq);
+ pftPreAuthReq = (tpSirFTPreAuthReq) cdf_mem_malloc(auth_req_len);
+ if (NULL == pftPreAuthReq) {
+ sms_log(pMac, LOGE,
+ FL("Memory allocation for FT Preauth request failed"));
+ return CDF_STATUS_E_NOMEM;
+ }
+ /* Save the SME Session ID here. We need it while processing the preauth response */
+ pSession->ftSmeContext.smeSessionId = sessionId;
+ cdf_mem_zero(pftPreAuthReq, auth_req_len);
+
+ pftPreAuthReq->pbssDescription =
+ (tpSirBssDescription) cdf_mem_malloc(sizeof(pBssDescription->length)
+ + pBssDescription->length);
+ if (NULL == pftPreAuthReq->pbssDescription) {
+ sms_log(pMac, LOGE,
+ FL("Memory allocation for FT Preauth request failed"));
+ return CDF_STATUS_E_NOMEM;
+ }
+
+ pftPreAuthReq->messageType = eWNI_SME_FT_PRE_AUTH_REQ;
+
+ pftPreAuthReq->preAuthchannelNum = pBssDescription->channelId;
+
+ cdf_mem_copy((void *)&pftPreAuthReq->currbssId,
+ (void *)pSession->connectedProfile.bssid.bytes,
+ sizeof(tSirMacAddr));
+ cdf_mem_copy((void *)&pftPreAuthReq->preAuthbssId,
+ (void *)pBssDescription->bssId, sizeof(tSirMacAddr));
+
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ if (csr_roam_is11r_assoc(pMac, sessionId) &&
+ (pMac->roam.roamSession[sessionId].connectedProfile.AuthType !=
+ eCSR_AUTH_TYPE_OPEN_SYSTEM)) {
+ pftPreAuthReq->ft_ies_length =
+ (uint16_t) pSession->ftSmeContext.auth_ft_ies_length;
+ cdf_mem_copy(pftPreAuthReq->ft_ies,
+ pSession->ftSmeContext.auth_ft_ies,
+ pSession->ftSmeContext.auth_ft_ies_length);
+ } else
+#endif
+ {
+ pftPreAuthReq->ft_ies_length = 0;
+ }
+ cdf_mem_copy(pftPreAuthReq->pbssDescription, pBssDescription,
+ sizeof(pBssDescription->length) + pBssDescription->length);
+ pftPreAuthReq->length = auth_req_len;
+ return cds_send_mb_message_to_mac(pftPreAuthReq);
+}
+
+/*--------------------------------------------------------------------------
+ * This will receive and process the FT Pre Auth Rsp from the current
+ * associated ap.
+ *
+ * This will invoke the hdd call back. This is so that hdd can now
+ * send the FTIEs from the Auth Rsp (Auth Seq 2) to the supplicant.
+ ------------------------------------------------------------------------*/
+void csr_roam_ft_pre_auth_rsp_processor(tHalHandle hHal,
+ tpSirFTPreAuthRsp pFTPreAuthRsp)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+#if defined(FEATURE_WLAN_LFR) || defined(FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_ESE_UPLOAD)
+ tCsrRoamInfo roamInfo;
+#endif
+ eCsrAuthType conn_Auth_type;
+ uint32_t sessionId = pFTPreAuthRsp->smeSessionId;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (NULL == pSession) {
+ sms_log(pMac, LOGE, FL("pSession is NULL"));
+ return;
+ }
+#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING
+ status =
+ csr_neighbor_roam_preauth_rsp_handler(pMac, pFTPreAuthRsp->smeSessionId,
+ pFTPreAuthRsp->status);
+ if (status != CDF_STATUS_SUCCESS) {
+ /*
+ * Bail out if pre-auth was not even processed.
+ */
+ sms_log(pMac, LOGE,
+ FL("Preauth was not processed: %d SessionID: %d"),
+ status, sessionId);
+ return;
+ }
+#endif
+
+ /* The below function calls/timers should be invoked only if the pre-auth is successful */
+ if (CDF_STATUS_SUCCESS != (CDF_STATUS) pFTPreAuthRsp->status)
+ return;
+ /* Implies a success */
+ pSession->ftSmeContext.FTState = eFT_AUTH_COMPLETE;
+ /* Indicate SME QoS module the completion of Preauth success. This will trigger the creation of RIC IEs */
+ pSession->ftSmeContext.psavedFTPreAuthRsp = pFTPreAuthRsp;
+ /* No need to notify qos module if this is a non 11r & ESE roam */
+ if (csr_roam_is11r_assoc(pMac, pFTPreAuthRsp->smeSessionId)
+#if defined(FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_ESE_UPLOAD)
+ || csr_roam_is_ese_assoc(pMac, pFTPreAuthRsp->smeSessionId)
+#endif
+ ) {
+ sme_qos_csr_event_ind(pMac,
+ pSession->ftSmeContext.smeSessionId,
+ SME_QOS_CSR_PREAUTH_SUCCESS_IND, NULL);
+ }
+ /* Start the pre-auth reassoc interval timer with a period of 400ms. When this expires,
+ * actual transition from the current to handoff AP is triggered */
+ status =
+ cdf_mc_timer_start(&pSession->ftSmeContext.preAuthReassocIntvlTimer,
+ 60);
+ if (CDF_STATUS_SUCCESS != status) {
+ sms_log(pMac, LOGE,
+ FL
+ ("Preauth reassoc interval timer start failed to start with status %d"),
+ status);
+ return;
+ }
+ /* Save the received response */
+ cdf_mem_copy((void *)&pSession->ftSmeContext.preAuthbssId,
+ (void *)pFTPreAuthRsp->preAuthbssId, sizeof(struct cdf_mac_addr));
+ if (csr_roam_is11r_assoc(pMac, pFTPreAuthRsp->smeSessionId))
+ csr_roam_call_callback(pMac, pFTPreAuthRsp->smeSessionId, NULL, 0,
+ eCSR_ROAM_FT_RESPONSE,
+ eCSR_ROAM_RESULT_NONE);
+
+#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD)
+ if (csr_roam_is_ese_assoc(pMac, pFTPreAuthRsp->smeSessionId)) {
+ /* read TSF */
+ csr_roam_read_tsf(pMac, (uint8_t *) roamInfo.timestamp,
+ pFTPreAuthRsp->smeSessionId);
+ /* Save the bssid from the received response */
+ cdf_mem_copy((void *)&roamInfo.bssid,
+ (void *)pFTPreAuthRsp->preAuthbssId,
+ sizeof(struct cdf_mac_addr));
+ csr_roam_call_callback(pMac, pFTPreAuthRsp->smeSessionId,
+ &roamInfo, 0, eCSR_ROAM_CCKM_PREAUTH_NOTIFY,
+ 0);
+ }
+#endif /* FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */
+
+#ifdef FEATURE_WLAN_LFR
+ /* If Legacy Fast Roaming is enabled, signal the supplicant */
+ /* So he can send us a PMK-ID for this candidate AP. */
+ if (csr_roam_is_fast_roam_enabled(pMac, pFTPreAuthRsp->smeSessionId)) {
+ /* Save the bssid from the received response */
+ cdf_mem_copy((void *)&roamInfo.bssid,
+ (void *)pFTPreAuthRsp->preAuthbssId,
+ sizeof(struct cdf_mac_addr));
+ csr_roam_call_callback(pMac, pFTPreAuthRsp->smeSessionId,
+ &roamInfo, 0, eCSR_ROAM_PMK_NOTIFY, 0);
+ }
+#endif
+
+ /* If its an Open Auth, FT IEs are not provided by supplicant */
+ /* Hence populate them here */
+ conn_Auth_type =
+ pMac->roam.roamSession[sessionId].connectedProfile.AuthType;
+
+ pSession->ftSmeContext.addMDIE = false;
+ if (csr_roam_is11r_assoc(pMac, pFTPreAuthRsp->smeSessionId) &&
+ (conn_Auth_type == eCSR_AUTH_TYPE_OPEN_SYSTEM)) {
+ uint16_t ft_ies_length;
+ ft_ies_length = pFTPreAuthRsp->ric_ies_length;
+
+ if ((pSession->ftSmeContext.reassoc_ft_ies) &&
+ (pSession->ftSmeContext.reassoc_ft_ies_length)) {
+ cdf_mem_free(pSession->ftSmeContext.reassoc_ft_ies);
+ pSession->ftSmeContext.reassoc_ft_ies_length = 0;
+ pSession->ftSmeContext.reassoc_ft_ies = NULL;
+ }
+
+ pSession->ftSmeContext.reassoc_ft_ies =
+ cdf_mem_malloc(ft_ies_length);
+ if (NULL == pSession->ftSmeContext.reassoc_ft_ies) {
+ sms_log(pMac, LOGE,
+ FL("Memory allocation failed for ft_ies"));
+ return;
+ } else {
+ /* Copy the RIC IEs to reassoc IEs */
+ cdf_mem_copy(((uint8_t *) pSession->ftSmeContext.
+ reassoc_ft_ies),
+ (uint8_t *) pFTPreAuthRsp->ric_ies,
+ pFTPreAuthRsp->ric_ies_length);
+ pSession->ftSmeContext.reassoc_ft_ies_length =
+ ft_ies_length;
+ pSession->ftSmeContext.addMDIE = true;
+ }
+ }
+ /* Done with it, init it. */
+ pSession->ftSmeContext.psavedFTPreAuthRsp = NULL;
+}
+#endif
+
+
+/*
+ pBuf points to the beginning of the message
+ LIM packs disassoc rsp as below,
+ messageType - 2 bytes
+ messageLength - 2 bytes
+ sessionId - 1 byte
+ transactionId - 2 bytes (uint16_t)
+ reasonCode - 4 bytes (sizeof(tSirResultCodes))
+ peerMacAddr - 6 bytes
+ The rest is conditionally defined of (WNI_POLARIS_FW_PRODUCT == AP) and not used
+ */
+static void csr_ser_des_unpack_diassoc_rsp(uint8_t *pBuf, tSirSmeDisassocRsp *pRsp)
+{
+ if (pBuf && pRsp) {
+ pBuf += 4; /* skip type and length */
+ pRsp->sessionId = *pBuf++;
+ cdf_get_u16(pBuf, (uint16_t *) &pRsp->transactionId);
+ pBuf += 2;
+ cdf_get_u32(pBuf, (uint32_t *) &pRsp->statusCode);
+ pBuf += 4;
+ cdf_mem_copy(pRsp->peerMacAddr, pBuf, 6);
+ }
+}
+
+/* Returns whether a session is in CDF_STA_MODE...or not */
+bool csr_roam_is_sta_mode(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ tCsrRoamSession *pSession = NULL;
+ pSession = CSR_GET_SESSION(pMac, sessionId);
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" %s: session %d not found "), __func__,
+ sessionId);
+ return false;
+ }
+ if (!CSR_IS_SESSION_VALID(pMac, sessionId)) {
+ sms_log(pMac, LOGE, FL(" %s: Inactive session"), __func__);
+ return false;
+ }
+ if (eCSR_BSS_TYPE_INFRASTRUCTURE != pSession->connectedProfile.BSSType) {
+ return false;
+ }
+ /* There is a possibility that the above check may fail,because
+ * P2P CLI also uses the same BSSType (eCSR_BSS_TYPE_INFRASTRUCTURE)
+ * when it is connected.So,we may sneak through the above check even
+ * if we are not a STA mode INFRA station. So, if we sneak through
+ * the above condition, we can use the following check if we are
+ * really in STA Mode.*/
+
+ if (NULL != pSession->pCurRoamProfile) {
+ if (pSession->pCurRoamProfile->csrPersona == CDF_STA_MODE) {
+ return true;
+ } else {
+ sms_log(pMac, LOGE, FL(" %s: pCurRoamProfile is NULL\n"),
+ __func__);
+ return false;
+ }
+ }
+
+ return false;
+}
+
+CDF_STATUS csr_handoff_request(tpAniSirGlobal pMac,
+ uint8_t sessionId,
+ tCsrHandoffRequest *pHandoffInfo)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ cds_msg_t msg;
+
+ tAniHandoffReq *pMsg;
+ pMsg = cdf_mem_malloc(sizeof(tAniHandoffReq));
+ if (NULL == pMsg) {
+ sms_log(pMac, LOGE,
+ " csr_handoff_request: failed to allocate mem for req ");
+ return CDF_STATUS_E_NOMEM;
+ }
+ pMsg->msgType = eWNI_SME_HANDOFF_REQ;
+ pMsg->msgLen = (uint16_t) sizeof(tAniHandoffReq);
+ pMsg->sessionId = sessionId;
+ pMsg->channel = pHandoffInfo->channel;
+ pMsg->handoff_src = pHandoffInfo->src;
+ cdf_mem_copy(pMsg->bssid, pHandoffInfo->bssid.bytes, CDF_MAC_ADDR_SIZE);
+ msg.type = eWNI_SME_HANDOFF_REQ;
+ msg.bodyptr = pMsg;
+ msg.reserved = 0;
+ if (CDF_STATUS_SUCCESS != cds_mq_post_message(CDS_MQ_ID_SME, &msg)) {
+ sms_log(pMac, LOGE,
+ " csr_handoff_request failed to post msg to self ");
+ cdf_mem_free((void *)pMsg);
+ status = CDF_STATUS_E_FAILURE;
+ }
+ return status;
+}
+
+#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD)
+/* ---------------------------------------------------------------------------
+ \fn csr_set_cckm_ie
+ \brief This function stores the CCKM IE passed by the supplicant
+ in a place holder data structure and this IE will be packed inside
+ reassociation request
+ \param pMac - pMac global structure
+ \param sessionId - Current session id
+ \param pCckmIe - pointer to CCKM IE data
+ \param ccKmIeLen - length of the CCKM IE
+ \- return Success or failure
+ -------------------------------------------------------------------------*/
+CDF_STATUS csr_set_cckm_ie(tpAniSirGlobal pMac, const uint8_t sessionId,
+ const uint8_t *pCckmIe, const uint8_t ccKmIeLen)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return CDF_STATUS_E_FAILURE;
+ }
+ cdf_mem_copy(pSession->suppCckmIeInfo.cckmIe, pCckmIe, ccKmIeLen);
+ pSession->suppCckmIeInfo.cckmIeLen = ccKmIeLen;
+ return status;
+}
+
+/* ---------------------------------------------------------------------------
+ \fn csr_roam_read_tsf
+ \brief This function reads the TSF; and also add the time elapsed since
+ last beacon or probe response reception from the hand off AP to arrive at
+ the latest TSF value.
+ \param pMac - pMac global structure
+ \param pTimestamp - output TSF timestamp
+ \- return Success or failure
+ -------------------------------------------------------------------------*/
+CDF_STATUS csr_roam_read_tsf(tpAniSirGlobal pMac, uint8_t *pTimestamp,
+ uint8_t sessionId)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tCsrNeighborRoamBSSInfo handoffNode;
+ uint32_t timer_diff = 0;
+ uint32_t timeStamp[2];
+ tpSirBssDescription pBssDescription = NULL;
+ csr_neighbor_roam_get_handoff_ap_info(pMac, &handoffNode, sessionId);
+ pBssDescription = handoffNode.pBssDescription;
+ /* Get the time diff in milli seconds */
+ timer_diff =
+ cdf_mc_timer_get_system_time() - pBssDescription->scanSysTimeMsec;
+ /* Convert msec to micro sec timer */
+ timer_diff = (uint32_t) (timer_diff * SYSTEM_TIME_MSEC_TO_USEC);
+ timeStamp[0] = pBssDescription->timeStamp[0];
+ timeStamp[1] = pBssDescription->timeStamp[1];
+ update_cckmtsf(&(timeStamp[0]), &(timeStamp[1]), &timer_diff);
+ cdf_mem_copy(pTimestamp, (void *)&timeStamp[0], sizeof(uint32_t) * 2);
+ return status;
+}
+#endif /*FEATURE_WLAN_ESE && FEATURE_WLAN_ESE_UPLOAD */
+
+/*
+ * Post Channel Change Request to LIM
+ * This API is primarily used to post
+ * Channel Change Req for SAP
+ */
+CDF_STATUS
+csr_roam_channel_change_req(tpAniSirGlobal pMac, struct cdf_mac_addr bssid,
+ uint8_t cbMode, tCsrRoamProfile *profile)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSirChanChangeRequest *pMsg;
+ tCsrRoamStartBssParams param;
+
+ csr_roam_get_bss_start_parms(pMac, profile, ¶m);
+ pMsg = cdf_mem_malloc(sizeof(tSirChanChangeRequest));
+ if (!pMsg) {
+ return CDF_STATUS_E_NOMEM;
+ }
+
+ cdf_mem_set((void *)pMsg, sizeof(tSirChanChangeRequest), 0);
+
+ pMsg->messageType = eWNI_SME_CHANNEL_CHANGE_REQ;
+ pMsg->messageLen = sizeof(tSirChanChangeRequest);
+ pMsg->targetChannel = profile->ChannelInfo.ChannelList[0];
+ pMsg->cbMode = cbMode;
+ pMsg->channel_width = profile->ch_params.ch_width;
+ pMsg->dot11mode = csr_translate_to_wni_cfg_dot11_mode(pMac,
+ pMac->roam.configParam.uCfgDot11Mode);
+ pMsg->center_freq_seg_0 = pMsg->targetChannel;
+ pMsg->center_freq_seg_1 = 0;
+ cdf_mem_copy(pMsg->bssid, bssid.bytes, CDF_MAC_ADDR_SIZE);
+ cdf_mem_copy(&pMsg->operational_rateset,
+ ¶m.operationalRateSet, sizeof(pMsg->operational_rateset));
+ cdf_mem_copy(&pMsg->extended_rateset,
+ ¶m.extendedRateSet, sizeof(pMsg->extended_rateset));
+ status = cds_send_mb_message_to_mac(pMsg);
+
+ return status;
+}
+
+/*
+ * Post Beacon Tx Start request to LIM
+ * immediately after SAP CAC WAIT is
+ * completed without any RADAR indications.
+ */
+CDF_STATUS csr_roam_start_beacon_req(tpAniSirGlobal pMac,
+ struct cdf_mac_addr bssid,
+ uint8_t dfsCacWaitStatus)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSirStartBeaconIndication *pMsg;
+
+ pMsg = cdf_mem_malloc(sizeof(tSirStartBeaconIndication));
+
+ if (!pMsg) {
+ return CDF_STATUS_E_NOMEM;
+ }
+
+ cdf_mem_set((void *)pMsg, sizeof(tSirStartBeaconIndication), 0);
+ pMsg->messageType = eWNI_SME_START_BEACON_REQ;
+ pMsg->messageLen = sizeof(tSirStartBeaconIndication);
+ pMsg->beaconStartStatus = dfsCacWaitStatus;
+ cdf_mem_copy(pMsg->bssid, bssid.bytes, CDF_MAC_ADDR_SIZE);
+
+ status = cds_send_mb_message_to_mac(pMsg);
+
+ return status;
+}
+
+/*----------------------------------------------------------------------------
+ \fn csr_roam_modify_add_ies
+ \brief This function sends msg to modify the additional IE buffers in PE
+ \param pMac - pMac global structure
+ \param pModifyIE - pointer to tSirModifyIE structure
+ \param updateType - Type of buffer
+ \- return Success or failure
+ -----------------------------------------------------------------------------*/
+CDF_STATUS
+csr_roam_modify_add_ies(tpAniSirGlobal pMac,
+ tSirModifyIE *pModifyIE, eUpdateIEsType updateType)
+{
+ tpSirModifyIEsInd pModifyAddIEInd = NULL;
+ uint8_t *pLocalBuffer = NULL;
+ CDF_STATUS status;
+
+ /* following buffer will be freed by consumer (PE) */
+ pLocalBuffer = cdf_mem_malloc(pModifyIE->ieBufferlength);
+
+ if (NULL == pLocalBuffer) {
+ sms_log(pMac, LOGE, FL("Memory Allocation Failure!!!"));
+ return CDF_STATUS_E_NOMEM;
+ }
+
+ pModifyAddIEInd = cdf_mem_malloc(sizeof(tSirModifyIEsInd));
+ if (NULL == pModifyAddIEInd) {
+ sms_log(pMac, LOGE, FL("Memory Allocation Failure!!!"));
+ cdf_mem_free(pLocalBuffer);
+ return CDF_STATUS_E_NOMEM;
+ }
+
+ /*copy the IE buffer */
+ cdf_mem_copy(pLocalBuffer, pModifyIE->pIEBuffer,
+ pModifyIE->ieBufferlength);
+ cdf_mem_zero(pModifyAddIEInd, sizeof(tSirModifyIEsInd));
+
+ pModifyAddIEInd->msgType = eWNI_SME_MODIFY_ADDITIONAL_IES;
+ pModifyAddIEInd->msgLen = sizeof(tSirModifyIEsInd);
+
+ cdf_mem_copy(pModifyAddIEInd->modifyIE.bssid, pModifyIE->bssid,
+ sizeof(tSirMacAddr));
+
+ pModifyAddIEInd->modifyIE.smeSessionId = pModifyIE->smeSessionId;
+ pModifyAddIEInd->modifyIE.notify = pModifyIE->notify;
+ pModifyAddIEInd->modifyIE.ieID = pModifyIE->ieID;
+ pModifyAddIEInd->modifyIE.ieIDLen = pModifyIE->ieIDLen;
+ pModifyAddIEInd->modifyIE.pIEBuffer = pLocalBuffer;
+ pModifyAddIEInd->modifyIE.ieBufferlength = pModifyIE->ieBufferlength;
+
+ pModifyAddIEInd->updateType = updateType;
+
+ status = cds_send_mb_message_to_mac(pModifyAddIEInd);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ FL("Failed to send eWNI_SME_UPDATE_ADDTIONAL_IES msg"
+ "!!! status %d"), status);
+ cdf_mem_free(pLocalBuffer);
+ }
+ return status;
+}
+
+/*----------------------------------------------------------------------------
+ \fn csr_roam_update_add_ies
+ \brief This function sends msg to updates the additional IE buffers in PE
+ \param pMac - pMac global structure
+ \param sessionId - SME session id
+ \param bssid - BSSID
+ \param additionIEBuffer - buffer containing addition IE from hostapd
+ \param length - length of buffer
+ \param updateType - Type of buffer
+ \param append - append or replace completely
+ \- return Success or failure
+ -----------------------------------------------------------------------------*/
+CDF_STATUS
+csr_roam_update_add_ies(tpAniSirGlobal pMac,
+ tSirUpdateIE *pUpdateIE, eUpdateIEsType updateType)
+{
+ tpSirUpdateIEsInd pUpdateAddIEs = NULL;
+ uint8_t *pLocalBuffer = NULL;
+ CDF_STATUS status;
+
+ if (pUpdateIE->ieBufferlength != 0) {
+ /* Following buffer will be freed by consumer (PE) */
+ pLocalBuffer = cdf_mem_malloc(pUpdateIE->ieBufferlength);
+ if (NULL == pLocalBuffer) {
+ sms_log(pMac, LOGE, FL("Memory Allocation Failure!!!"));
+ return CDF_STATUS_E_NOMEM;
+ }
+ cdf_mem_copy(pLocalBuffer, pUpdateIE->pAdditionIEBuffer,
+ pUpdateIE->ieBufferlength);
+ }
+
+ pUpdateAddIEs = cdf_mem_malloc(sizeof(tSirUpdateIEsInd));
+ if (NULL == pUpdateAddIEs) {
+ sms_log(pMac, LOGE, FL("Memory Allocation Failure!!!"));
+ if (pLocalBuffer != NULL) {
+ cdf_mem_free(pLocalBuffer);
+ }
+ return CDF_STATUS_E_NOMEM;
+ }
+
+ cdf_mem_zero(pUpdateAddIEs, sizeof(tSirUpdateIEsInd));
+
+ pUpdateAddIEs->msgType = eWNI_SME_UPDATE_ADDITIONAL_IES;
+ pUpdateAddIEs->msgLen = sizeof(tSirUpdateIEsInd);
+
+ cdf_mem_copy(pUpdateAddIEs->updateIE.bssid, pUpdateIE->bssid,
+ sizeof(tSirMacAddr));
+
+ pUpdateAddIEs->updateIE.smeSessionId = pUpdateIE->smeSessionId;
+ pUpdateAddIEs->updateIE.append = pUpdateIE->append;
+ pUpdateAddIEs->updateIE.notify = pUpdateIE->notify;
+ pUpdateAddIEs->updateIE.ieBufferlength = pUpdateIE->ieBufferlength;
+ pUpdateAddIEs->updateIE.pAdditionIEBuffer = pLocalBuffer;
+
+ pUpdateAddIEs->updateType = updateType;
+
+ status = cds_send_mb_message_to_mac(pUpdateAddIEs);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE,
+ FL("Failed to send eWNI_SME_UPDATE_ADDTIONAL_IES msg"
+ "!!! status %d"), status);
+ cdf_mem_free(pLocalBuffer);
+ }
+ return status;
+}
+
+/**
+ * csr_roam_send_chan_sw_ie_request() - Request to transmit CSA IE
+ * @mac_ctx: Global MAC context
+ * @bssid: BSSID
+ * @target_channel: Channel on which to send the IE
+ * @csa_ie_reqd: Include/Exclude CSA IE.
+ * @ch_bandwidth: Channel offset
+ *
+ * This function sends request to transmit channel switch announcement
+ * IE to lower layers
+ *
+ * Return: success or failure
+ **/
+CDF_STATUS
+csr_roam_send_chan_sw_ie_request(tpAniSirGlobal mac_ctx,
+ struct cdf_mac_addr bssid, uint8_t target_channel,
+ uint8_t csa_ie_reqd, uint8_t ch_bandwidth)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSirDfsCsaIeRequest *msg;
+
+ msg = cdf_mem_malloc(sizeof(tSirDfsCsaIeRequest));
+ if (!msg) {
+ return CDF_STATUS_E_NOMEM;
+ }
+
+ cdf_mem_set((void *)msg, sizeof(tSirDfsCsaIeRequest), 0);
+ msg->msgType = eWNI_SME_DFS_BEACON_CHAN_SW_IE_REQ;
+ msg->msgLen = sizeof(tSirDfsCsaIeRequest);
+
+ msg->targetChannel = target_channel;
+ msg->csaIeRequired = csa_ie_reqd;
+ cdf_mem_copy(msg->bssid, bssid.bytes, CDF_MAC_ADDR_SIZE);
+ msg->ch_bandwidth = ch_bandwidth;
+
+ status = cds_send_mb_message_to_mac(msg);
+
+ return status;
+}
+
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+/*----------------------------------------------------------------------------
+* fn csr_process_roam_offload_synch_ind
+* brief This will process the roam synch indication received from
+* lower layers.This function also calls another API to
+* parse the beacon IE and fill the appropriate fields
+* param pMac - pMac global structure
+* param pMsgBuf - Message buffer received from lower layers
+* --------------------------------------------------------------------------*/
+void csr_process_roam_offload_synch_ind(tHalHandle hHal,
+ roam_offload_synch_ind *roam_synch_ind_ptr)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ tCsrRoamSession *session_ptr = NULL;
+ uint8_t session_id = roam_synch_ind_ptr->roamedVdevId;
+ session_ptr = CSR_GET_SESSION(pMac, roam_synch_ind_ptr->roamedVdevId);
+ if (!session_ptr) {
+ sms_log(pMac, LOGE, FL("LFR3: session %d not found "),
+ roam_synch_ind_ptr->roamedVdevId);
+ goto err_synch_rsp;
+ }
+ if (!CDF_IS_STATUS_SUCCESS(csr_scan_save_roam_offload_ap_to_scan_cache(
+ pMac, roam_synch_ind_ptr))) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ "fail to save roam offload AP to scan cache");
+ goto err_synch_rsp;
+ }
+ session_ptr->roamOffloadSynchParams.rssi = roam_synch_ind_ptr->rssi;
+ session_ptr->roamOffloadSynchParams.roamReason =
+ roam_synch_ind_ptr->roamReason;
+ session_ptr->roamOffloadSynchParams.roamedVdevId =
+ roam_synch_ind_ptr->roamedVdevId;
+ cdf_mem_copy(session_ptr->roamOffloadSynchParams.bssid,
+ roam_synch_ind_ptr->bssId, sizeof(tSirMacAddr));
+ session_ptr->roamOffloadSynchParams.txMgmtPower =
+ roam_synch_ind_ptr->txMgmtPower;
+ session_ptr->roamOffloadSynchParams.authStatus =
+ roam_synch_ind_ptr->authStatus;
+ session_ptr->roamOffloadSynchParams.bRoamSynchInProgress = true;
+ /*Save the BSS descriptor for later use*/
+ session_ptr->roamOffloadSynchParams.bss_desc_ptr =
+ roam_synch_ind_ptr->bss_desc_ptr;
+ pMac->roam.reassocRespLen = roam_synch_ind_ptr->reassocRespLength;
+ pMac->roam.pReassocResp =
+ cdf_mem_malloc(pMac->roam.reassocRespLen);
+ if (NULL == pMac->roam.pReassocResp) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ "Memory allocation for reassoc response failed");
+ goto err_synch_rsp;
+ }
+ cdf_mem_copy(pMac->roam.pReassocResp,
+ (uint8_t *)roam_synch_ind_ptr +
+ roam_synch_ind_ptr->reassocRespOffset,
+ pMac->roam.reassocRespLen);
+
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ "LFR3:%s: the reassoc resp frame data:", __func__);
+ CDF_TRACE_HEX_DUMP(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ pMac->roam.pReassocResp, pMac->roam.reassocRespLen);
+
+ cdf_mem_copy(session_ptr->roamOffloadSynchParams.kck,
+ roam_synch_ind_ptr->kck, SIR_KCK_KEY_LEN);
+ cdf_mem_copy(session_ptr->roamOffloadSynchParams.kek,
+ roam_synch_ind_ptr->kek, SIR_KEK_KEY_LEN);
+ cdf_mem_copy(session_ptr->roamOffloadSynchParams.replay_ctr,
+ roam_synch_ind_ptr->replay_ctr, SIR_REPLAY_CTR_LEN);
+ if (CDF_STATUS_SUCCESS != csr_neighbor_roam_offload_update_preauth_list(
+ pMac, roam_synch_ind_ptr, session_id)) {
+ /**
+ *Bail out if Roam Offload Synch Response was not even handled.
+ **/
+ sms_log(pMac, LOGE, FL("Roam Offload Synch Response "
+ "was not processed"));
+ goto err_synch_rsp;
+ }
+
+ csr_neighbor_roam_request_handoff(pMac, session_id);
+
+err_synch_rsp:
+ cdf_mem_free(roam_synch_ind_ptr->bss_desc_ptr);
+ roam_synch_ind_ptr->bss_desc_ptr = NULL;
+}
+
+/*----------------------------------------------------------------------------
+* fn csr_process_ho_fail_ind
+* brief This function will process the Hand Off Failure indication
+* received from the firmware. It will trigger a disconnect on
+* the session which the firmware reported a hand off failure
+* param pMac global structure
+* param pMsgBuf - Contains the session ID for which the handler should apply
+* --------------------------------------------------------------------------*/
+void csr_process_ho_fail_ind(tpAniSirGlobal pMac, void *pMsgBuf)
+{
+ tSirSmeHOFailureInd *pSmeHOFailInd = (tSirSmeHOFailureInd *) pMsgBuf;
+ uint32_t sessionId;
+
+ if (pSmeHOFailInd)
+ sessionId = pSmeHOFailInd->sessionId;
+ else {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ "LFR3: Hand-Off Failure Ind is NULL");
+ return;
+ }
+ /* Roaming is supported only on Infra STA Mode. */
+ if (!csr_roam_is_sta_mode(pMac, sessionId)) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ "LFR3:HO Fail cannot be handled for session %d",
+ sessionId);
+ return;
+ }
+ csr_roam_synch_clean_up(pMac, sessionId);
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ "LFR3:Issue Disconnect on session %d", sessionId);
+ csr_roam_disconnect(pMac, sessionId, eCSR_DISCONNECT_REASON_UNSPECIFIED);
+}
+#endif /* WLAN_FEATURE_ROAM_OFFLOAD */
+
+/**
+ * csr_update_op_class_array() - update op class for each band
+ * @mac_ctx: mac global context
+ * @op_classes: out param, operating class array to update
+ * @channel_info: channel info
+ * @ch_name: channel band name to display in debug messages
+ * @i: out param, stores number of operating classes
+ *
+ * Return: void
+ */
+static void
+csr_update_op_class_array(tpAniSirGlobal mac_ctx,
+ uint8_t *op_classes,
+ tCsrChannel *channel_info,
+ char *ch_name,
+ uint8_t *i)
+{
+ uint8_t j = 0, idx = 0, class = 0;
+ bool found = false;
+ uint8_t num_channels = channel_info->numChannels;
+
+ sms_log(mac_ctx, LOG1,
+ FL("Num of %s channels, %d"),
+ ch_name, num_channels);
+
+ for (idx = 0; idx < num_channels
+ && *i < (SIR_MAC_MAX_SUPP_OPER_CLASSES - 1); idx++) {
+ class = cds_regdm_get_opclass_from_channel(
+ mac_ctx->scan.countryCodeCurrent,
+ channel_info->channelList[idx],
+ BWALL);
+ sms_log(mac_ctx, LOG4, FL("for chan %d, op class: %d"),
+ channel_info->channelList[idx], class);
+
+ found = false;
+ for (j = 0; j < SIR_MAC_MAX_SUPP_OPER_CLASSES - 1; j++) {
+ if (op_classes[j] == class) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ op_classes[*i] = class;
+ *i = *i + 1;
+ }
+ }
+}
+
+/**
+ * csr_update_op_class_array() - update op class for all bands
+ * @hHal: global hal context
+ *
+ * Return: void
+ */
+void csr_init_operating_classes(tHalHandle hHal)
+{
+ uint8_t i = 0;
+ uint8_t j = 0;
+ uint8_t swap = 0;
+ uint8_t numClasses = 0;
+ uint8_t opClasses[SIR_MAC_MAX_SUPP_OPER_CLASSES] = {0,};
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+
+ sms_log(pMac, LOG1, FL("Current Country = %c%c"),
+ pMac->scan.countryCodeCurrent[0],
+ pMac->scan.countryCodeCurrent[1]);
+
+ csr_update_op_class_array(pMac, opClasses,
+ &pMac->scan.base_channels, "20MHz", &i);
+ csr_update_op_class_array(pMac, opClasses,
+ &pMac->scan.base40MHzChannels, "40MHz", &i);
+ numClasses = i;
+
+ /* As per spec the operating classes should be in ascending order.
+ * Bubble sort is fine since we don't have many classes
+ */
+ for (i = 0; i < (numClasses - 1); i++) {
+ for (j = 0; j < (numClasses - i - 1); j++) {
+ /* For decreasing order use < */
+ if (opClasses[j] > opClasses[j + 1]) {
+ swap = opClasses[j];
+ opClasses[j] = opClasses[j + 1];
+ opClasses[j + 1] = swap;
+ }
+ }
+ }
+
+ sms_log(pMac, LOG1, FL("Number of unique supported op classes %d"),
+ numClasses);
+ for (i = 0; i < numClasses; i++) {
+ sms_log(pMac, LOG1, FL("supported opClasses[%d] = %d"), i,
+ opClasses[i]);
+ }
+
+ /* Set the ordered list of op classes in regdomain
+ * for use by other modules
+ */
+ cds_regdm_set_curr_opclasses(numClasses, &opClasses[0]);
+}
+
+/**
+ * csr_find_session_by_type() - This function will find given session type from
+ * all sessions.
+ * @mac_ctx: pointer to mac context.
+ * @type: session type
+ *
+ * Return: session id for give session type.
+ **/
+static uint32_t
+csr_find_session_by_type(tpAniSirGlobal mac_ctx, tCDF_CON_MODE type)
+{
+ uint32_t i, session_id = CSR_SESSION_ID_INVALID;
+ tCsrRoamSession *session_ptr;
+ for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
+ if (!CSR_IS_SESSION_VALID(mac_ctx, i))
+ continue;
+
+ session_ptr = CSR_GET_SESSION(mac_ctx, i);
+ if (type == session_ptr->bssParams.bssPersona) {
+ session_id = i;
+ break;
+ }
+ }
+ return session_id;
+}
+/**
+ * csr_is_conn_allow_2g_band() - This function will check if station's conn
+ * is allowed in 2.4Ghz band.
+ * @mac_ctx: pointer to mac context.
+ * @chnl: station's channel.
+ *
+ * This function will check if station's connection is allowed in 5Ghz band
+ * after comparing it with SAP's operating channel. If SAP's operating
+ * channel and Station's channel is different than this function will return
+ * false else true.
+ *
+ * Return: true or false.
+ **/
+static bool csr_is_conn_allow_2g_band(tpAniSirGlobal mac_ctx, uint32_t chnl)
+{
+ uint32_t sap_session_id;
+ tCsrRoamSession *sap_session;
+
+ if (0 == chnl) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ FL("channel is zero, connection not allowed"));
+
+ return false;
+ }
+
+ sap_session_id = csr_find_session_by_type(mac_ctx, CDF_SAP_MODE);
+ if (CSR_SESSION_ID_INVALID != sap_session_id) {
+ sap_session = CSR_GET_SESSION(mac_ctx, sap_session_id);
+ if ((0 != sap_session->bssParams.operationChn) &&
+ (sap_session->bssParams.operationChn != chnl)) {
+
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ FL
+ ("Can't allow STA to connect, chnls not same"));
+ return false;
+ }
+ }
+ return true;
+}
+
+/**
+ * csr_is_conn_allow_5g_band() - This function will check if station's conn
+ * is allowed in 5Ghz band.
+ * @mac_ctx: pointer to mac context.
+ * @chnl: station's channel.
+ *
+ * This function will check if station's connection is allowed in 5Ghz band
+ * after comparing it with P2PGO's operating channel. If P2PGO's operating
+ * channel and Station's channel is different than this function will return
+ * false else true.
+ *
+ * Return: true or false.
+ **/
+static bool csr_is_conn_allow_5g_band(tpAniSirGlobal mac_ctx, uint32_t chnl)
+{
+ uint32_t p2pgo_session_id;
+ tCsrRoamSession *p2pgo_session;
+
+ if (0 == chnl) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ FL
+ ("channel is zero, connection not allowed"));
+ return false;
+ }
+
+ p2pgo_session_id = csr_find_session_by_type(mac_ctx, CDF_P2P_GO_MODE);
+ if (CSR_SESSION_ID_INVALID != p2pgo_session_id) {
+ p2pgo_session = CSR_GET_SESSION(mac_ctx, p2pgo_session_id);
+ if ((0 != p2pgo_session->bssParams.operationChn) &&
+ (eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED !=
+ p2pgo_session->connectState) &&
+ (p2pgo_session->bssParams.operationChn !=
+ chnl)) {
+
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ FL
+ ("Can't allow STA to connect, chnls not same"));
+ return false;
+ }
+ }
+ return true;
+}
+
+/**
+ * csr_clear_joinreq_param() - This function will clear station's params
+ * for stored join request to csr.
+ * @hal_handle: pointer to hal context.
+ * @session_id: station's session id.
+ *
+ * This function will clear station's allocated memory for cached join
+ * request.
+ *
+ * Return: true or false based on function's overall success.
+ **/
+bool csr_clear_joinreq_param(tpAniSirGlobal mac_ctx,
+ uint32_t session_id)
+{
+ tCsrRoamSession *sta_session;
+ tScanResultList *bss_list;
+
+ if (NULL == mac_ctx)
+ return false;
+
+ sta_session = CSR_GET_SESSION(mac_ctx, session_id);
+ if (NULL == sta_session)
+ return false;
+
+ /* Release the memory allocated by previous join request */
+ bss_list =
+ (tScanResultList *)&sta_session->stored_roam_profile.
+ bsslist_handle;
+ if (NULL != bss_list) {
+ csr_scan_result_purge(mac_ctx,
+ sta_session->stored_roam_profile.bsslist_handle);
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ FL("bss list is released for session %d"), session_id);
+ sta_session->stored_roam_profile.bsslist_handle = NULL;
+ }
+ sta_session->stored_roam_profile.bsslist_handle = NULL;
+ csr_release_profile(mac_ctx, &sta_session->stored_roam_profile.profile);
+ sta_session->stored_roam_profile.reason = 0;
+ sta_session->stored_roam_profile.roam_id = 0;
+ sta_session->stored_roam_profile.imediate_flag = false;
+ sta_session->stored_roam_profile.clear_flag = false;
+ return true;
+}
+
+/**
+ * csr_store_joinreq_param() - This function will store station's join
+ * request to that station's session.
+ * @mac_ctx: pointer to mac context.
+ * @profile: pointer to station's roam profile.
+ * @scan_cache: pointer to station's scan cache.
+ * @roam_id: reference to roam_id variable being passed.
+ * @session_id: station's session id.
+ *
+ * This function will store station's join request to one of the
+ * csr structure and add it to station's session.
+ *
+ * Return: true or false based on function's overall success.
+ **/
+bool csr_store_joinreq_param(tpAniSirGlobal mac_ctx,
+ tCsrRoamProfile *profile,
+ tScanResultHandle scan_cache,
+ uint32_t *roam_id,
+ uint32_t session_id)
+{
+ tCsrRoamSession *sta_session;
+
+ if (NULL == mac_ctx)
+ return false;
+
+ sta_session = CSR_GET_SESSION(mac_ctx, session_id);
+ if (NULL == sta_session)
+ return false;
+
+ sta_session->stored_roam_profile.session_id = session_id;
+ csr_roam_copy_profile(mac_ctx,
+ &sta_session->stored_roam_profile.profile, profile);
+ /* new bsslist_handle's memory will be relased later */
+ sta_session->stored_roam_profile.bsslist_handle = scan_cache;
+ sta_session->stored_roam_profile.reason = eCsrHddIssued;
+ sta_session->stored_roam_profile.roam_id = *roam_id;
+ sta_session->stored_roam_profile.imediate_flag = false;
+ sta_session->stored_roam_profile.clear_flag = false;
+
+ return true;
+}
+
+/**
+ * csr_issue_stored_joinreq() - This function will issues station's stored
+ * the join request.
+ * @mac_ctx: pointer to mac context.
+ * @roam_id: reference to roam_id variable being passed.
+ * @session_id: station's session id.
+ *
+ * This function will issue station's stored join request, from this point
+ * onwards the flow will be just like normal connect request.
+ *
+ * Return: CDF_STATUS_SUCCESS or CDF_STATUS_E_FAILURE.
+ **/
+CDF_STATUS csr_issue_stored_joinreq(tpAniSirGlobal mac_ctx,
+ uint32_t *roam_id,
+ uint32_t session_id)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tCsrRoamSession *sta_session;
+ uint32_t new_roam_id;
+
+ sta_session = CSR_GET_SESSION(mac_ctx, session_id);
+ if (NULL == sta_session)
+ return CDF_STATUS_E_FAILURE;
+ new_roam_id = GET_NEXT_ROAM_ID(&mac_ctx->roam);
+ *roam_id = new_roam_id;
+ status = csr_roam_issue_connect(mac_ctx,
+ sta_session->stored_roam_profile.session_id,
+ &sta_session->stored_roam_profile.profile,
+ sta_session->stored_roam_profile.bsslist_handle,
+ sta_session->stored_roam_profile.reason,
+ new_roam_id,
+ sta_session->stored_roam_profile.imediate_flag,
+ sta_session->stored_roam_profile.clear_flag);
+ if (CDF_STATUS_SUCCESS != status) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ FL
+ ("CSR failed issuing connect cmd with status = 0x%08X"),
+ status);
+ csr_clear_joinreq_param(mac_ctx, session_id);
+ }
+ return status;
+}
+
+/**
+ * csr_process_set_hw_mode() - Set HW mode command to PE
+ * @mac: Globacl MAC pointer
+ * @command: Command received from SME
+ *
+ * Posts the set HW mode command to PE. This message passing
+ * through PE is required for PE's internal management
+ *
+ * Return: None
+ */
+void csr_process_set_hw_mode(tpAniSirGlobal mac, tSmeCmd *command)
+{
+ uint32_t len;
+ struct s_sir_set_hw_mode *cmd;
+ CDF_STATUS status;
+ tSirMsgQ msg;
+ struct sir_set_hw_mode_resp *param;
+
+ /* Setting HW mode is for the entire system.
+ * So, no need to check session
+ */
+
+ if (!command) {
+ sms_log(mac, LOGE, FL("Set HW mode param is NULL"));
+ goto fail;
+ }
+
+ len = sizeof(*cmd);
+ cmd = cdf_mem_malloc(len);
+ if (!cmd) {
+ sms_log(mac, LOGE, FL("Memory allocation failed"));
+ /* Probably the fail response will also fail during malloc.
+ * Still proceeding to send response!
+ */
+ goto fail;
+ }
+
+ cdf_mem_set(cmd, len, 0);
+
+ cmd->messageType = eWNI_SME_SET_HW_MODE_REQ;
+ cmd->length = len;
+ cmd->set_hw.hw_mode_index = command->u.set_hw_mode_cmd.hw_mode_index;
+ /*
+ * Below callback and context info are not needed for PE as of now.
+ * Storing the passed value in the same s_sir_set_hw_mode format.
+ */
+ cmd->set_hw.set_hw_mode_cb = command->u.set_hw_mode_cmd.set_hw_mode_cb;
+
+ sms_log(mac, LOG1,
+ FL("Posting eWNI_SME_SET_HW_MODE_REQ to PE"));
+
+ status = cds_send_mb_message_to_mac(cmd);
+ if (CDF_STATUS_SUCCESS != status) {
+ sms_log(mac, LOGE, FL("Posting to PE failed"));
+ return;
+ }
+ return;
+fail:
+ param = cdf_mem_malloc(sizeof(*param));
+ if (!param) {
+ sms_log(mac, LOGE,
+ FL("Malloc fail: Fail to send response to SME"));
+ return;
+ }
+ sms_log(mac, LOGE, FL("Sending set HW fail response to SME"));
+ param->status = SET_HW_MODE_STATUS_ECANCELED;
+ param->cfgd_hw_mode_index = 0;
+ param->num_vdev_mac_entries = 0;
+ msg.type = eWNI_SME_SET_HW_MODE_RESP;
+ msg.bodyptr = param;
+ msg.bodyval = 0;
+ sys_process_mmh_msg(mac, &msg);
+}
+
+/**
+ * csr_process_set_dual_mac_config() - Set HW mode command to PE
+ * @mac: Global MAC pointer
+ * @command: Command received from SME
+ *
+ * Posts the set dual mac config command to PE.
+ *
+ * Return: None
+ */
+void csr_process_set_dual_mac_config(tpAniSirGlobal mac, tSmeCmd *command)
+{
+ uint32_t len;
+ struct sir_set_dual_mac_cfg *cmd;
+ CDF_STATUS status;
+ tSirMsgQ msg;
+ struct sir_dual_mac_config_resp *param;
+
+ /* Setting MAC configuration is for the entire system.
+ * So, no need to check session
+ */
+
+ if (!command) {
+ sms_log(mac, LOGE, FL("Set HW mode param is NULL"));
+ goto fail;
+ }
+
+ len = sizeof(*cmd);
+ cmd = cdf_mem_malloc(len);
+ if (!cmd) {
+ sms_log(mac, LOGE, FL("Memory allocation failed"));
+ /* Probably the fail response will also fail during malloc.
+ * Still proceeding to send response!
+ */
+ goto fail;
+ }
+
+ cmd->message_type = eWNI_SME_SET_DUAL_MAC_CFG_REQ;
+ cmd->length = len;
+ cmd->set_dual_mac.scan_config = command->u.set_dual_mac_cmd.scan_config;
+ cmd->set_dual_mac.fw_mode_config =
+ command->u.set_dual_mac_cmd.fw_mode_config;
+ /*
+ * Below callback and context info are not needed for PE as of now.
+ * Storing the passed value in the same sir_set_dual_mac_cfg format.
+ */
+ cmd->set_dual_mac.set_dual_mac_cb =
+ command->u.set_dual_mac_cmd.set_dual_mac_cb;
+
+ sms_log(mac, LOG1,
+ FL("Posting eWNI_SME_SET_DUAL_MAC_CFG_REQ to PE: %x %x"),
+ cmd->set_dual_mac.scan_config,
+ cmd->set_dual_mac.fw_mode_config);
+
+ status = cds_send_mb_message_to_mac(cmd);
+ if (CDF_STATUS_SUCCESS != status) {
+ sms_log(mac, LOGE, FL("Posting to PE failed"));
+ return;
+ }
+ return;
+fail:
+ param = cdf_mem_malloc(sizeof(*param));
+ if (!param) {
+ sms_log(mac, LOGE,
+ FL("Malloc fail: Fail to send response to SME"));
+ return;
+ }
+ sms_log(mac, LOGE, FL("Sending set dual mac fail response to SME"));
+ param->status = SET_HW_MODE_STATUS_ECANCELED;
+ msg.type = eWNI_SME_SET_DUAL_MAC_CFG_RESP;
+ msg.bodyptr = param;
+ msg.bodyval = 0;
+ sys_process_mmh_msg(mac, &msg);
+}
+
+/**
+ * csr_process_nss_update_req() - Update nss command to PE
+ * @mac: Globacl MAC pointer
+ * @command: Command received from SME
+ *
+ * Posts the nss update command to PE. This message passing
+ * through PE is required for PE's internal management
+ *
+ * Return: None
+ */
+void csr_process_nss_update_req(tpAniSirGlobal mac, tSmeCmd *command)
+{
+ uint32_t len;
+ struct sir_nss_update_request *msg;
+ CDF_STATUS status;
+ tSirMsgQ msg_return;
+ struct sir_beacon_tx_complete_rsp *param;
+
+ tCsrRoamSession *session =
+ CSR_GET_SESSION(mac, command->sessionId);
+
+ if (!session) {
+ sms_log(mac, LOGE, FL("Session not found"));
+ goto fail;
+ }
+
+ if (!command) {
+ sms_log(mac, LOGE, FL("nss update param is NULL"));
+ goto fail;
+ }
+
+ len = sizeof(*msg);
+ msg = cdf_mem_malloc(len);
+ if (!msg) {
+ sms_log(mac, LOGE, FL("Memory allocation failed"));
+ /* Probably the fail response is also fail during malloc.
+ * Still proceeding to send response!
+ */
+ goto fail;
+ }
+
+ cdf_mem_set((void *)msg, sizeof(*msg), 0);
+ msg->msgType = eWNI_SME_NSS_UPDATE_REQ;
+ msg->msgLen = sizeof(*msg);
+
+ msg->new_nss = command->u.nss_update_cmd.new_nss;
+ msg->vdev_id = command->u.nss_update_cmd.session_id;
+
+ sms_log(mac, LOG1,
+ FL("Posting eWNI_SME_NSS_UPDATE_REQ to PE"));
+
+ status = cds_send_mb_message_to_mac(msg);
+ if (CDF_STATUS_SUCCESS != status) {
+ sms_log(mac, LOGE, FL("Posting to PE failed"));
+ return;
+ }
+ return;
+fail:
+ param = cdf_mem_malloc(sizeof(*param));
+ if (!param) {
+ sms_log(mac, LOGE,
+ FL("Malloc fail: Fail to send response to SME"));
+ return;
+ }
+ sms_log(mac, LOGE, FL("Sending nss update fail response to SME"));
+ param->tx_status = CDF_STATUS_E_FAILURE;
+ param->session_id = command->u.nss_update_cmd.session_id;
+ msg_return.type = eWNI_SME_NSS_UPDATE_RSP;
+ msg_return.bodyptr = param;
+ msg_return.bodyval = 0;
+ sys_process_mmh_msg(mac, &msg_return);
+}
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;
+}
diff --git a/core/sme/src/csr/csr_cmd_process.c b/core/sme/src/csr/csr_cmd_process.c
new file mode 100644
index 0000000..7fa7ec8
--- /dev/null
+++ b/core/sme/src/csr/csr_cmd_process.c
@@ -0,0 +1,189 @@
+/*
+ * 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_cmd_process.c
+
+ Implementation for processing various commands.
+ ========================================================================== */
+
+#include "ani_global.h"
+
+#include "csr_inside_api.h"
+#include "sme_inside.h"
+#include "sms_debug.h"
+#include "mac_trace.h"
+
+/**
+ * csr_msg_processor() - To process all csr msg
+ * @mac_ctx: mac context
+ * @msg_buf: message buffer
+ *
+ * This routine will handle all the message for csr to process
+ *
+ * Return: CDF_STATUS
+ */
+CDF_STATUS csr_msg_processor(tpAniSirGlobal mac_ctx, void *msg_buf)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tSirSmeRsp *sme_rsp = (tSirSmeRsp *) msg_buf;
+#ifdef FEATURE_WLAN_SCAN_PNO
+ tSirMbMsg *msg = (tSirMbMsg *) msg_buf;
+ tCsrRoamSession *session;
+#endif
+ uint8_t session_id = sme_rsp->sessionId;
+ eCsrRoamState cur_state = mac_ctx->roam.curState[session_id];
+
+ sms_log(mac_ctx, LOG2,
+ FL("msg %d[0x%04X] recvd in curstate %s & substate %s id(%d)"),
+ sme_rsp->messageType, sme_rsp->messageType,
+ mac_trace_getcsr_roam_state(cur_state),
+ mac_trace_getcsr_roam_sub_state(
+ mac_ctx->roam.curSubState[session_id]),
+ session_id);
+
+#ifdef FEATURE_WLAN_SCAN_PNO
+ /*
+ * PNO scan responses have to be handled irrespective of CSR roam state.
+ * Check if PNO has been started & only then process the PNO scan result
+ * Also note that normal scan isn't allowed when PNO scan is in progress
+ * and so the scan responses reaching here when PNO is started must be
+ * PNO responses. For normal scan, the PNO started flag will be false
+ * and it'll be processed as usual based on the current CSR roam state.
+ */
+ session = CSR_GET_SESSION(mac_ctx, session_id);
+ if (!session) {
+ sms_log(mac_ctx, LOGE, FL("session %d not found, msgType : %d"),
+ session_id, msg->type);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ if (eWNI_SME_SCAN_RSP == msg->type) {
+ status = csr_scanning_state_msg_processor(mac_ctx, msg_buf);
+ if (CDF_STATUS_SUCCESS != status)
+ sms_log(mac_ctx, LOGE,
+ FL("handling PNO scan resp 0x%X CSR state %d"),
+ sme_rsp->messageType, cur_state);
+ return status;
+ }
+#endif
+
+ /* Process the message based on the state of the roaming states... */
+#if defined(ANI_RTT_DEBUG)
+ if (!pAdapter->fRttModeEnabled) {
+#endif
+ switch (cur_state) {
+ case eCSR_ROAMING_STATE_JOINED:
+ /* are we in joined state */
+ csr_roam_joined_state_msg_processor(mac_ctx, msg_buf);
+ break;
+ case eCSR_ROAMING_STATE_JOINING:
+ /* are we in roaming states */
+#if defined(ANI_EMUL_ASSOC)
+ emulRoamingStateMsgProcessor(pAdapter, pMBBufHdr);
+#endif
+ csr_roaming_state_msg_processor(mac_ctx, msg_buf);
+ break;
+
+ default:
+ /*
+ * For all other messages, we ignore it
+ * To work-around an issue where checking for set/remove
+ * key base on connection state is no longer workable
+ * due to failure or finding the condition meets both
+ * SAP and infra/IBSS requirement.
+ */
+ if (eWNI_SME_SETCONTEXT_RSP == sme_rsp->messageType) {
+ sms_log(mac_ctx, LOGW,
+ FL("handling msg 0x%X CSR state is %d"),
+ sme_rsp->messageType, cur_state);
+ csr_roam_check_for_link_status_change(mac_ctx,
+ sme_rsp);
+ } else if (eWNI_SME_GET_RSSI_REQ ==
+ sme_rsp->messageType) {
+ tAniGetRssiReq *pGetRssiReq =
+ (tAniGetRssiReq *) msg_buf;
+ if (NULL == pGetRssiReq->rssiCallback) {
+ sms_log(mac_ctx, LOGE,
+ FL("rssiCallback is NULL"));
+ return status;
+ }
+ sms_log(mac_ctx, LOGW,
+ FL("msg eWNI_SME_GET_RSSI_REQ is not handled by CSR in state %d. calling RSSI callback"),
+ cur_state);
+ ((tCsrRssiCallback)(pGetRssiReq->rssiCallback))(
+ pGetRssiReq->lastRSSI,
+ pGetRssiReq->staId,
+ pGetRssiReq->pDevContext);
+ } else {
+ sms_log(mac_ctx, LOGE,
+ FL("Message 0x%04X is not handled by CSR state is %d session Id %d"),
+ sme_rsp->messageType, cur_state,
+ session_id);
+
+ if (eWNI_SME_FT_PRE_AUTH_RSP ==
+ sme_rsp->messageType) {
+ sms_log(mac_ctx, LOGE,
+ FL("Dequeue eSmeCommandRoam command with reason eCsrPerformPreauth"));
+ csr_dequeue_roam_command(mac_ctx,
+ eCsrPerformPreauth);
+ } else if (eWNI_SME_REASSOC_RSP ==
+ sme_rsp->messageType) {
+ sms_log(mac_ctx, LOGE,
+ FL("Dequeue eSmeCommandRoam command with reason eCsrSmeIssuedFTReassoc"));
+ csr_dequeue_roam_command(mac_ctx,
+ eCsrSmeIssuedFTReassoc);
+ }
+ }
+ break;
+ } /* switch */
+#if defined(ANI_RTT_DEBUG)
+ }
+#endif
+ return status;
+}
+
+bool csr_check_ps_ready(void *pv)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(pv);
+
+ if (pMac->roam.sPendingCommands < 0) {
+ CDF_ASSERT(pMac->roam.sPendingCommands >= 0);
+ return 0;
+ }
+ return pMac->roam.sPendingCommands == 0;
+}
+
+bool csr_check_ps_offload_ready(void *pv, uint32_t sessionId)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(pv);
+
+ CDF_ASSERT(pMac->roam.sPendingCommands >= 0);
+ return pMac->roam.sPendingCommands == 0;
+}
+
diff --git a/core/sme/src/csr/csr_inside_api.h b/core/sme/src/csr/csr_inside_api.h
new file mode 100644
index 0000000..1679784
--- /dev/null
+++ b/core/sme/src/csr/csr_inside_api.h
@@ -0,0 +1,1070 @@
+/*
+ * 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_inside_api.h
+
+ Define interface only used by CSR.
+ ========================================================================== */
+#ifndef CSR_INSIDE_API_H__
+#define CSR_INSIDE_API_H__
+
+#include "csr_support.h"
+#include "sme_inside.h"
+#include "cds_reg_service.h"
+
+#define CSR_PASSIVE_MAX_CHANNEL_TIME 110
+#define CSR_PASSIVE_MIN_CHANNEL_TIME 60
+
+#define CSR_ACTIVE_MAX_CHANNEL_TIME 40
+#define CSR_ACTIVE_MIN_CHANNEL_TIME 20
+
+#ifdef WLAN_AP_STA_CONCURRENCY
+#define CSR_PASSIVE_MAX_CHANNEL_TIME_CONC 110
+#define CSR_PASSIVE_MIN_CHANNEL_TIME_CONC 60
+
+#define CSR_ACTIVE_MAX_CHANNEL_TIME_CONC 27
+#define CSR_ACTIVE_MIN_CHANNEL_TIME_CONC 20
+
+#define CSR_REST_TIME_CONC 100
+
+#define CSR_NUM_STA_CHAN_COMBINED_CONC 3
+#define CSR_NUM_P2P_CHAN_COMBINED_CONC 1
+#endif
+
+#define CSR_MAX_NUM_SUPPORTED_CHANNELS 55
+
+#define CSR_MAX_2_4_GHZ_SUPPORTED_CHANNELS 14
+
+#define CSR_MAX_BSS_SUPPORT 300
+#define SYSTEM_TIME_MSEC_TO_USEC 1000
+
+/* This number minus 1 means the number of times a channel is scanned before a BSS is remvoed from */
+/* cache scan result */
+#define CSR_AGING_COUNT 3
+#define CSR_SCAN_GET_RESULT_INTERVAL (5 * CDF_MC_TIMER_TO_SEC_UNIT) /* 5 seconds */
+#define CSR_MIC_ERROR_TIMEOUT (60 * CDF_MC_TIMER_TO_SEC_UNIT) /* 60 seconds */
+#define CSR_TKIP_COUNTER_MEASURE_TIMEOUT (60 * CDF_MC_TIMER_TO_SEC_UNIT) /* 60 seconds */
+
+#define CSR_SCAN_RESULT_CFG_AGING_INTERVAL (CDF_MC_TIMER_TO_SEC_UNIT) /* 1 second */
+/* the following defines are NOT used by palTimer */
+#define CSR_SCAN_AGING_TIME_NOT_CONNECT_NO_PS 50 /* 50 seconds */
+#define CSR_SCAN_AGING_TIME_NOT_CONNECT_W_PS 300 /* 300 seconds */
+#define CSR_SCAN_AGING_TIME_CONNECT_NO_PS 150 /* 150 seconds */
+#define CSR_SCAN_AGING_TIME_CONNECT_W_PS 600 /* 600 seconds */
+#define CSR_JOIN_FAILURE_TIMEOUT_DEFAULT (3000)
+#define CSR_JOIN_FAILURE_TIMEOUT_MIN (1000) /* minimal value */
+/* These are going against the signed RSSI (int8_t) so it is between -+127 */
+#define CSR_BEST_RSSI_VALUE (-30) /* RSSI >= this is in CAT4 */
+#define CSR_DEFAULT_RSSI_DB_GAP 30 /* every 30 dbm for one category */
+#define CSR_BSS_CAP_VALUE_NONE 0 /* not much value */
+#define CSR_BSS_CAP_VALUE_HT 1
+#define CSR_BSS_CAP_VALUE_VHT 2
+#define CSR_BSS_CAP_VALUE_WMM 1
+#define CSR_BSS_CAP_VALUE_UAPSD 1
+#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR)
+#define CSR_BSS_CAP_VALUE_5GHZ 2
+#endif
+#define CSR_DEFAULT_ROAMING_TIME 10 /* 10 seconds */
+
+#define CSR_ROAMING_DFS_CHANNEL_DISABLED (0)
+#define CSR_ROAMING_DFS_CHANNEL_ENABLED_NORMAL (1)
+#define CSR_ROAMING_DFS_CHANNEL_ENABLED_ACTIVE (2)
+
+/* ***************************************************************************
+ * The MAX BSSID Count should be lower than the command timeout value and it
+ * can be of a fraction of 3/4 of the total command timeout value.
+ * ***************************************************************************/
+#define CSR_ACTIVE_LIST_CMD_TIMEOUT_VALUE (1000*30*4)
+#define CSR_ACTIVE_SCAN_LIST_CMD_TIMEOUT (1000*30)
+
+#define CSR_MAX_BSSID_COUNT ((CSR_ACTIVE_LIST_CMD_TIMEOUT_VALUE/4000) * 3)
+#define CSR_CUSTOM_CONC_GO_BI 100
+#define MIN_11P_CHANNEL (rf_channels[MIN_5_9GHZ_CHANNEL].channelNum)
+
+typedef enum {
+ eCsrNextScanNothing,
+ eCsrNextLostLinkScan1Success,
+ eCsrNextLostLinkScan1Failed,
+ eCsrNextLostLinkScan2Success,
+ eCsrNextLostLinkScan2Failed,
+ eCsrNextLostLinkScan3Success,
+ eCsrNexteScanForSsidSuccess,
+ eCsrNextLostLinkScan3Failed,
+ eCsrNext11dScan1Failure,
+ eCsrNext11dScan1Success,
+ eCsrNext11dScan2Failure,
+ eCsrNext11dScan2Success,
+ eCsrNext11dScanComplete,
+ eCsrNexteScanForSsidFailure,
+
+} eCsrScanCompleteNextCommand;
+
+typedef enum {
+ eCsrJoinSuccess,
+ eCsrJoinFailure,
+ eCsrReassocSuccess,
+ eCsrReassocFailure,
+ eCsrNothingToJoin,
+ eCsrStartBssSuccess,
+ eCsrStartBssFailure,
+ eCsrSilentlyStopRoaming,
+ eCsrSilentlyStopRoamingSaveState,
+ eCsrJoinWdsFailure,
+ eCsrJoinFailureDueToConcurrency,
+
+} eCsrRoamCompleteResult;
+
+typedef struct tagScanReqParam {
+ uint8_t bReturnAfter1stMatch;
+ uint8_t fUniqueResult;
+ uint8_t freshScan;
+ uint8_t hiddenSsid;
+ uint8_t reserved;
+} tScanReqParam;
+
+typedef struct tagCsrScanResult {
+ tListElem Link;
+ int32_t AgingCount; /* This BSS is removed when it reaches 0 or less */
+ uint32_t preferValue; /* The bigger the number, the better the BSS. This value override capValue */
+ uint32_t capValue; /* The biggger the better. This value is in use only if we have equal preferValue */
+ /* This member must be the last in the structure because the end of tSirBssDescription (inside) is an */
+ /* array with nonknown size at this time */
+
+ eCsrEncryptionType ucEncryptionType; /* Preferred Encryption type that matched with profile. */
+ eCsrEncryptionType mcEncryptionType;
+ eCsrAuthType authType; /* Preferred auth type that matched with the profile. */
+
+ tCsrScanResultInfo Result;
+} tCsrScanResult;
+
+typedef struct {
+ tDblLinkList List;
+ tListElem *pCurEntry;
+} tScanResultList;
+
+#define CSR_IS_ROAM_REASON(pCmd, reason) ((reason) == (pCmd)->roamCmd.roamReason)
+#define CSR_IS_BETTER_PREFER_VALUE(v1, v2) ((v1) > (v2))
+#define CSR_IS_EQUAL_PREFER_VALUE(v1, v2) ((v1) == (v2))
+#define CSR_IS_BETTER_CAP_VALUE(v1, v2) ((v1) > (v2))
+#define CSR_IS_EQUAL_CAP_VALUE(v1, v2) ((v1) == (v2))
+#define CSR_IS_BETTER_RSSI(v1, v2) ((v1) > (v2))
+#define CSR_IS_ENC_TYPE_STATIC(encType) ((eCSR_ENCRYPT_TYPE_NONE == (encType)) || \
+ (eCSR_ENCRYPT_TYPE_WEP40_STATICKEY == (encType)) || \
+ (eCSR_ENCRYPT_TYPE_WEP104_STATICKEY == (encType)))
+#define CSR_IS_WAIT_FOR_KEY(pMac, sessionId) \
+ (CSR_IS_ROAM_JOINED(pMac, sessionId) && \
+ CSR_IS_ROAM_SUBSTATE_WAITFORKEY(pMac, sessionId))
+/* WIFI has a test case for not using HT rates with TKIP as encryption */
+/* We may need to add WEP but for now, TKIP only. */
+
+#define CSR_IS_11n_ALLOWED(encType) ((eCSR_ENCRYPT_TYPE_TKIP != (encType)) && \
+ (eCSR_ENCRYPT_TYPE_WEP40_STATICKEY != (encType)) && \
+ (eCSR_ENCRYPT_TYPE_WEP104_STATICKEY != (encType)) && \
+ (eCSR_ENCRYPT_TYPE_WEP40 != (encType)) && \
+ (eCSR_ENCRYPT_TYPE_WEP104 != (encType)))
+
+#define CSR_IS_DISCONNECT_COMMAND(pCommand) ((eSmeCommandRoam == (pCommand)->command) && \
+ ((eCsrForcedDisassoc == (pCommand)->u.roamCmd.roamReason) || \
+ (eCsrForcedDeauth == (pCommand)->u.roamCmd.roamReason) || \
+ (eCsrSmeIssuedDisassocForHandoff == \
+ (pCommand)->u.roamCmd.roamReason) || \
+ (eCsrForcedDisassocMICFailure == \
+ (pCommand)->u.roamCmd.roamReason)))
+
+extern const tRfChannelProps rf_channels[NUM_RF_CHANNELS];
+eCsrRoamState csr_roam_state_change(tpAniSirGlobal pMac,
+ eCsrRoamState NewRoamState, uint8_t sessionId);
+CDF_STATUS csr_scanning_state_msg_processor(tpAniSirGlobal pMac, void *pMsgBuf);
+void csr_roaming_state_msg_processor(tpAniSirGlobal pMac, void *pMsgBuf);
+void csr_roam_joined_state_msg_processor(tpAniSirGlobal pMac, void *pMsgBuf);
+bool csr_scan_complete(tpAniSirGlobal pMac, tSirSmeScanRsp *pScanRsp);
+void csr_release_command_roam(tpAniSirGlobal pMac, tSmeCmd *pCommand);
+void csr_release_command_scan(tpAniSirGlobal pMac, tSmeCmd *pCommand);
+void csr_release_command_wm_status_change(tpAniSirGlobal pMac, tSmeCmd *pCommand);
+extern void csr_release_roc_req_cmd(tpAniSirGlobal mac_ctx);
+
+bool csr_is_duplicate_bss_description(tpAniSirGlobal pMac,
+ tSirBssDescription *pSirBssDesc1,
+ tSirBssDescription *pSirBssDesc2,
+ tDot11fBeaconIEs *pIes2, bool fForced);
+CDF_STATUS csr_roam_save_connected_bss_desc(tpAniSirGlobal pMac, uint32_t sessionId,
+ tSirBssDescription *pBssDesc);
+bool csr_is_network_type_equal(tSirBssDescription *pSirBssDesc1,
+ tSirBssDescription *pSirBssDesc2);
+CDF_STATUS csr_scan_sme_scan_response(tpAniSirGlobal pMac, void *pMsgBuf);
+/*
+ Prepare a filter base on a profile for parsing the scan results.
+ Upon successful return, caller MUST call csr_free_scan_filter on
+ pScanFilter when it is done with the filter.
+ */
+CDF_STATUS csr_roam_prepare_filter_from_profile(tpAniSirGlobal pMac,
+ tCsrRoamProfile *pProfile,
+ tCsrScanResultFilter *pScanFilter);
+CDF_STATUS csr_roam_copy_profile(tpAniSirGlobal pMac,
+ tCsrRoamProfile *pDstProfile,
+ tCsrRoamProfile *pSrcProfile);
+CDF_STATUS csr_roam_start(tpAniSirGlobal pMac);
+void csr_roam_stop(tpAniSirGlobal pMac, uint32_t sessionId);
+void csr_roam_startMICFailureTimer(tpAniSirGlobal pMac);
+void csr_roam_stopMICFailureTimer(tpAniSirGlobal pMac);
+void csr_roam_startTKIPCounterMeasureTimer(tpAniSirGlobal pMac);
+void csr_roam_stopTKIPCounterMeasureTimer(tpAniSirGlobal pMac);
+
+CDF_STATUS csr_scan_open(tpAniSirGlobal pMac);
+CDF_STATUS csr_scan_close(tpAniSirGlobal pMac);
+CDF_STATUS csr_scan_request_lost_link1(tpAniSirGlobal pMac, uint32_t sessionId);
+CDF_STATUS csr_scan_request_lost_link2(tpAniSirGlobal pMac, uint32_t sessionId);
+CDF_STATUS csr_scan_request_lost_link3(tpAniSirGlobal pMac, uint32_t sessionId);
+CDF_STATUS csr_scan_handle_failed_lostlink1(tpAniSirGlobal pMac,
+ uint32_t sessionId);
+CDF_STATUS csr_scan_handle_failed_lostlink2(tpAniSirGlobal pMac,
+ uint32_t sessionId);
+CDF_STATUS csr_scan_handle_failed_lostlink3(tpAniSirGlobal pMac,
+ uint32_t sessionId);
+tCsrScanResult *csr_scan_append_bss_description(tpAniSirGlobal pMac,
+ tSirBssDescription *
+ pSirBssDescription,
+ tDot11fBeaconIEs *pIes,
+ bool fForced, uint8_t sessionId);
+void csr_scan_call_callback(tpAniSirGlobal pMac, tSmeCmd *pCommand,
+ eCsrScanStatus scanStatus);
+CDF_STATUS csr_scan_copy_request(tpAniSirGlobal pMac, tCsrScanRequest *pDstReq,
+ tCsrScanRequest *pSrcReq);
+CDF_STATUS csr_scan_free_request(tpAniSirGlobal pMac, tCsrScanRequest *pReq);
+CDF_STATUS csr_scan_copy_result_list(tpAniSirGlobal pMac, tScanResultHandle hIn,
+ tScanResultHandle *phResult);
+CDF_STATUS csr_scan_for_ssid(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamProfile *pProfile, uint32_t roamId,
+ bool notify);
+CDF_STATUS csr_scan_start_result_cfg_aging_timer(tpAniSirGlobal pMac);
+CDF_STATUS csr_scan_stop_result_cfg_aging_timer(tpAniSirGlobal pMac);
+void csr_scan_stop_timers(tpAniSirGlobal pMac);
+/* To remove fresh scan commands from the pending queue */
+bool csr_scan_remove_fresh_scan_command(tpAniSirGlobal pMac, uint8_t sessionId);
+CDF_STATUS csr_scan_abort_mac_scan(tpAniSirGlobal pMac, uint8_t sessionId,
+ eCsrAbortReason reason);
+void csr_remove_cmd_from_pending_list(tpAniSirGlobal pMac, tDblLinkList *pList,
+ eSmeCommandType commandType);
+void csr_remove_cmd_with_session_id_from_pending_list(tpAniSirGlobal pMac,
+ uint8_t sessionId,
+ tDblLinkList *pList,
+ eSmeCommandType commandType);
+CDF_STATUS csr_scan_abort_mac_scan_not_for_connect(tpAniSirGlobal pMac,
+ uint8_t sessionId);
+CDF_STATUS csr_scan_abort_scan_for_ssid(tpAniSirGlobal pMac, uint32_t sessionId);
+void csr_remove_scan_for_ssid_from_pending_list(tpAniSirGlobal pMac,
+ tDblLinkList *pList,
+ uint32_t sessionId);
+
+CDF_STATUS csr_abort_scan_from_active_list(tpAniSirGlobal pMac,
+ tDblLinkList *pList, uint32_t sessionId,
+ eSmeCommandType scan_cmd_type, eCsrAbortReason abort_reason);
+
+/* To age out scan results base. tSmeGetScanChnRsp is a pointer returned by LIM that */
+/* has the information regarding scanned channels. */
+/* The logic is that whenever CSR add a BSS to scan result, it set the age count to */
+/* a value. This function deduct the age count if channelId matches the BSS' channelId */
+/* The BSS is remove if the count reaches 0. */
+CDF_STATUS csr_scan_age_results(tpAniSirGlobal pMac,
+ tSmeGetScanChnRsp *pScanChnInfo);
+
+/* If fForce is true we will save the new String that is learn't. */
+/* Typically it will be true in case of Join or user initiated ioctl */
+bool csr_learn_11dcountry_information(tpAniSirGlobal pMac,
+ tSirBssDescription *pSirBssDesc,
+ tDot11fBeaconIEs *pIes, bool fForce);
+void csr_apply_country_information(tpAniSirGlobal pMac);
+void csr_set_cfg_scan_control_list(tpAniSirGlobal pMac, uint8_t *countryCode,
+ tCsrChannel *pChannelList);
+void csr_reinit_scan_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand);
+void csr_free_scan_result_entry(tpAniSirGlobal pMac, tCsrScanResult *pResult);
+
+CDF_STATUS csr_roam_call_callback(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamInfo *pRoamInfo, uint32_t roamId,
+ eRoamCmdStatus u1, eCsrRoamResult u2);
+CDF_STATUS csr_roam_issue_connect(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamProfile *pProfile,
+ tScanResultHandle hBSSList,
+ eCsrRoamReason reason, uint32_t roamId,
+ bool fImediate, bool fClearScan);
+CDF_STATUS csr_roam_issue_reassoc(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamProfile *pProfile,
+ tCsrRoamModifyProfileFields *pModProfileFields,
+ eCsrRoamReason reason, uint32_t roamId,
+ bool fImediate);
+void csr_roam_complete(tpAniSirGlobal pMac, eCsrRoamCompleteResult Result,
+ void *Context);
+CDF_STATUS csr_roam_issue_set_context_req(tpAniSirGlobal pMac, uint32_t sessionId,
+ eCsrEncryptionType EncryptType,
+ tSirBssDescription *pBssDescription,
+ tSirMacAddr *bssId, bool addKey,
+ bool fUnicast,
+ tAniKeyDirection aniKeyDirection,
+ uint8_t keyId, uint16_t keyLength,
+ uint8_t *pKey, uint8_t paeRole);
+CDF_STATUS csr_roam_process_disassoc_deauth(tpAniSirGlobal pMac, tSmeCmd *pCommand,
+ bool fDisassoc, bool fMICFailure);
+CDF_STATUS csr_roam_save_connected_infomation(tpAniSirGlobal pMac,
+ uint32_t sessionId,
+ tCsrRoamProfile *pProfile,
+ tSirBssDescription *pSirBssDesc,
+ tDot11fBeaconIEs *pIes);
+void csr_roam_check_for_link_status_change(tpAniSirGlobal pMac, tSirSmeRsp *pSirMsg);
+void csr_roam_stats_rsp_processor(tpAniSirGlobal pMac, tSirSmeRsp *pSirMsg);
+CDF_STATUS csr_roam_issue_start_bss(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamStartBssParams *pParam,
+ tCsrRoamProfile *pProfile,
+ tSirBssDescription *pBssDesc, uint32_t roamId);
+CDF_STATUS csr_roam_issue_stop_bss(tpAniSirGlobal pMac, uint32_t sessionId,
+ eCsrRoamSubState NewSubstate);
+bool csr_is_same_profile(tpAniSirGlobal pMac, tCsrRoamConnectedProfile *pProfile1,
+ tCsrRoamProfile *pProfile2);
+bool csr_is_roam_command_waiting(tpAniSirGlobal pMac);
+bool csr_is_roam_command_waiting_for_session(tpAniSirGlobal pMac, uint32_t sessionId);
+bool csr_is_scan_for_roam_command_active(tpAniSirGlobal pMac);
+eRoamCmdStatus csr_get_roam_complete_status(tpAniSirGlobal pMac,
+ uint32_t sessionId);
+/* pBand can be NULL if caller doesn't need to get it */
+CDF_STATUS csr_roam_issue_disassociate_cmd(tpAniSirGlobal pMac, uint32_t sessionId,
+ eCsrRoamDisconnectReason reason);
+CDF_STATUS csr_roam_disconnect_internal(tpAniSirGlobal pMac, uint32_t sessionId,
+ eCsrRoamDisconnectReason reason);
+/* pCommand may be NULL */
+void csr_roam_remove_duplicate_command(tpAniSirGlobal pMac, uint32_t sessionId,
+ tSmeCmd *pCommand,
+ eCsrRoamReason eRoamReason);
+
+CDF_STATUS csr_send_join_req_msg(tpAniSirGlobal pMac, uint32_t sessionId,
+ tSirBssDescription *pBssDescription,
+ tCsrRoamProfile *pProfile,
+ tDot11fBeaconIEs *pIes, uint16_t messageType);
+CDF_STATUS csr_send_mb_disassoc_req_msg(tpAniSirGlobal pMac, uint32_t sessionId,
+ tSirMacAddr bssId, uint16_t reasonCode);
+CDF_STATUS csr_send_mb_deauth_req_msg(tpAniSirGlobal pMac, uint32_t sessionId,
+ tSirMacAddr bssId, uint16_t reasonCode);
+CDF_STATUS csr_send_mb_disassoc_cnf_msg(tpAniSirGlobal pMac,
+ tpSirSmeDisassocInd pDisassocInd);
+CDF_STATUS csr_send_mb_deauth_cnf_msg(tpAniSirGlobal pMac,
+ tpSirSmeDeauthInd pDeauthInd);
+CDF_STATUS csr_send_assoc_cnf_msg(tpAniSirGlobal pMac, tpSirSmeAssocInd pAssocInd,
+ CDF_STATUS status);
+CDF_STATUS csr_send_assoc_ind_to_upper_layer_cnf_msg(tpAniSirGlobal pMac,
+ tpSirSmeAssocInd pAssocInd,
+ CDF_STATUS Halstatus,
+ uint8_t sessionId);
+CDF_STATUS csr_send_mb_start_bss_req_msg(tpAniSirGlobal pMac, uint32_t sessionId,
+ eCsrRoamBssType bssType,
+ tCsrRoamStartBssParams *pParam,
+ tSirBssDescription *pBssDesc);
+CDF_STATUS csr_send_mb_stop_bss_req_msg(tpAniSirGlobal pMac, uint32_t sessionId);
+
+/* Caller should put the BSS' ssid to fiedl bssSsid when comparing SSID for a BSS. */
+bool csr_is_ssid_match(tpAniSirGlobal pMac, uint8_t *ssid1, uint8_t ssid1Len,
+ uint8_t *bssSsid, uint8_t bssSsidLen, bool fSsidRequired);
+bool csr_is_phy_mode_match(tpAniSirGlobal pMac, uint32_t phyMode,
+ tSirBssDescription *pSirBssDesc,
+ tCsrRoamProfile *pProfile,
+ eCsrCfgDot11Mode *pReturnCfgDot11Mode,
+ tDot11fBeaconIEs *pIes);
+bool csr_roam_is_channel_valid(tpAniSirGlobal pMac, uint8_t channel);
+
+/* pNumChan is a caller allocated space with the sizeof pChannels */
+CDF_STATUS csr_get_cfg_valid_channels(tpAniSirGlobal pMac, uint8_t *pChannels,
+ uint32_t *pNumChan);
+void csr_roam_ccm_cfg_set_callback(tpAniSirGlobal pMac, int32_t result);
+
+tPowerdBm csr_get_cfg_max_tx_power(tpAniSirGlobal pMac, uint8_t channel);
+
+/* To free the last roaming profile */
+void csr_free_roam_profile(tpAniSirGlobal pMac, uint32_t sessionId);
+void csr_free_connect_bss_desc(tpAniSirGlobal pMac, uint32_t sessionId);
+CDF_STATUS csr_move_bss_to_head_from_bssid(tpAniSirGlobal pMac,
+ struct cdf_mac_addr *bssid,
+ tScanResultHandle hScanResult);
+bool csr_check_ps_ready(void *pv);
+bool csr_check_ps_offload_ready(void *pv, uint32_t sessionId);
+
+/* to free memory allocated inside the profile structure */
+void csr_release_profile(tpAniSirGlobal pMac, tCsrRoamProfile *pProfile);
+/* To free memory allocated inside scanFilter */
+void csr_free_scan_filter(tpAniSirGlobal pMac, tCsrScanResultFilter *pScanFilter);
+eCsrCfgDot11Mode csr_get_cfg_dot11_mode_from_csr_phy_mode(tCsrRoamProfile *pProfile,
+ eCsrPhyMode phyMode,
+ bool fProprietary);
+uint32_t csr_translate_to_wni_cfg_dot11_mode(tpAniSirGlobal pMac,
+ eCsrCfgDot11Mode csrDot11Mode);
+void csr_save_channel_power_for_band(tpAniSirGlobal pMac, bool fPopulate5GBand);
+void csr_apply_channel_power_info_to_fw(tpAniSirGlobal pMac,
+ tCsrChannel *pChannelList,
+ uint8_t *countryCode);
+void csr_apply_power2_current(tpAniSirGlobal pMac);
+void csr_assign_rssi_for_category(tpAniSirGlobal pMac, int8_t bestApRssi,
+ uint8_t catOffset);
+CDF_STATUS csr_roam_remove_connected_bss_from_scan_cache(tpAniSirGlobal pMac,
+ tCsrRoamConnectedProfile *
+ pConnProfile);
+CDF_STATUS csr_roam_start_roaming(tpAniSirGlobal pMac, uint32_t sessionId,
+ eCsrRoamingReason roamingReason);
+/* return a bool to indicate whether roaming completed or continue. */
+bool csr_roam_complete_roaming(tpAniSirGlobal pMac, uint32_t sessionId,
+ bool fForce, eCsrRoamResult roamResult);
+void csr_roam_completion(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamInfo *pRoamInfo, tSmeCmd *pCommand,
+ eCsrRoamResult roamResult, bool fSuccess);
+void csr_roam_cancel_roaming(tpAniSirGlobal pMac, uint32_t sessionId);
+void csr_apply_channel_power_info_wrapper(tpAniSirGlobal pMac);
+void csr_reset_pmkid_candidate_list(tpAniSirGlobal pMac, uint32_t sessionId);
+#ifdef FEATURE_WLAN_WAPI
+void csr_reset_bkid_candidate_list(tpAniSirGlobal pMac, uint32_t sessionId);
+#endif /* FEATURE_WLAN_WAPI */
+CDF_STATUS csr_save_to_channel_power2_g_5_g(tpAniSirGlobal pMac, uint32_t tableSize,
+ tSirMacChanInfo *channelTable);
+
+/* To check whether a country code matches the one in the IE */
+/* Only check the first two characters, ignoring in/outdoor */
+/* pCountry -- caller allocated buffer contain the country code that is checking against */
+/* the one in pIes. It can be NULL. */
+/* caller must provide pIes, it cannot be NULL */
+/* This function always return true if 11d support is not turned on. */
+/* pIes cannot be NULL */
+bool csr_match_country_code(tpAniSirGlobal pMac, uint8_t *pCountry,
+ tDot11fBeaconIEs *pIes);
+CDF_STATUS csr_roam_set_key(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamSetKey *pSetKey, uint32_t roamId);
+CDF_STATUS csr_roam_open_session(tpAniSirGlobal pMac,
+ csr_roam_completeCallback callback, void *pContext,
+ uint8_t *pSelfMacAddr, uint8_t *pbSessionId,
+ uint32_t type, uint32_t subType);
+/* fSync: true means cleanupneeds to handle synchronously. */
+CDF_STATUS csr_roam_close_session(tpAniSirGlobal pMac, uint32_t sessionId,
+ bool fSync,
+ csr_roamSessionCloseCallback callback,
+ void *pContext);
+void csr_cleanup_session(tpAniSirGlobal pMac, uint32_t sessionId);
+CDF_STATUS csr_roam_get_session_id_from_bssid(tpAniSirGlobal pMac, struct cdf_mac_addr *bssid,
+ uint32_t *pSessionId);
+eCsrCfgDot11Mode csr_find_best_phy_mode(tpAniSirGlobal pMac, uint32_t phyMode);
+
+/* ---------------------------------------------------------------------------
+ \fn csr_scan_enable
+ \brief Enable the scanning feature of CSR. It must be called before any scan request can be performed.
+ \param tHalHandle - HAL context handle
+ \return CDF_STATUS
+ -------------------------------------------------------------------------------*/
+CDF_STATUS csr_scan_enable(tpAniSirGlobal);
+
+/* ---------------------------------------------------------------------------
+ \fn csr_scan_disable
+ \brief Disableing the scanning feature of CSR. After this function return success, no scan is performed until
+ a successfull to csr_scan_enable
+ \param tHalHandle - HAL context handle
+ \return CDF_STATUS
+ -------------------------------------------------------------------------------*/
+CDF_STATUS csr_scan_disable(tpAniSirGlobal);
+/* ---------------------------------------------------------------------------
+ \fn csr_scan_request
+ \brief Request a 11d or full scan.
+ \param callback - a callback function that scan calls upon finish, will not be called if csr_scan_request returns error
+ \param pContext - a pointer passed in for the callback
+ \return CDF_STATUS
+ -------------------------------------------------------------------------------*/
+CDF_STATUS csr_scan_request(tpAniSirGlobal, uint16_t, tCsrScanRequest *,
+ csr_scan_completeCallback callback, void *pContext);
+
+/* ---------------------------------------------------------------------------
+ \fn csrScanAbort
+ \brief If a scan request is abort, the scan complete callback will be called first before csrScanAbort returns.
+ \param pScanRequestID - The request ID returned from csr_scan_request
+ \return CDF_STATUS
+ -------------------------------------------------------------------------------*/
+CDF_STATUS csrScanAbort(tpAniSirGlobal, uint32_t scanRequestID);
+
+/* ---------------------------------------------------------------------------
+ \fn csr_scan_get_result
+ \brief Return scan results.
+ \param pFilter - If pFilter is NULL, all cached results are returned
+ \param phResult - an object for the result.
+ \return CDF_STATUS
+ -------------------------------------------------------------------------------*/
+CDF_STATUS csr_scan_get_result(tpAniSirGlobal, tCsrScanResultFilter *pFilter,
+ tScanResultHandle *phResult);
+
+/* ---------------------------------------------------------------------------
+ \fn csr_scan_flush_result
+ \brief Clear scan results.
+ \param pMac - pMac global pointer
+ \param sessionId - Session Identifier
+ \return CDF_STATUS
+ -------------------------------------------------------------------------------*/
+CDF_STATUS csr_scan_flush_result(tpAniSirGlobal);
+/* ---------------------------------------------------------------------------
+ * \fn csr_scan_filter_results
+ * \brief Filter scan results based on valid channel list.
+ * \param pMac - Pointer to Global MAC structure
+ * \return CDF_STATUS
+ ***-------------------------------------------------------------------------------
+ */
+CDF_STATUS csr_scan_filter_results(tpAniSirGlobal pMac);
+
+void csr_save_scan_results(tpAniSirGlobal pMac, uint8_t reason,
+ uint8_t sessionId);
+
+CDF_STATUS csr_scan_flush_selective_result(tpAniSirGlobal, bool flushP2P);
+
+/* ---------------------------------------------------------------------------
+ \fn csr_scan_result_get_first
+ \brief Returns the first element of scan result.
+ \param hScanResult - returned from csr_scan_get_result
+ \return tCsrScanResultInfo * - NULL if no result
+ -------------------------------------------------------------------------------*/
+tCsrScanResultInfo *csr_scan_result_get_first(tpAniSirGlobal,
+ tScanResultHandle hScanResult);
+/* ---------------------------------------------------------------------------
+ \fn csr_scan_result_get_next
+ \brief Returns the next element of scan result. It can be called without calling csr_scan_result_get_first first
+ \param hScanResult - returned from csr_scan_get_result
+ \return Null if no result or reach the end
+ -------------------------------------------------------------------------------*/
+tCsrScanResultInfo *csr_scan_result_get_next(tpAniSirGlobal,
+ tScanResultHandle hScanResult);
+
+/* ---------------------------------------------------------------------------
+ \fn csr_get_country_code
+ \brief this function is to get the country code current being used
+ \param pBuf - Caller allocated buffer with at least 3 bytes, upon success return, this has the country code
+ \param pbLen - Caller allocated, as input, it indicates the length of pBuf. Upon success return,
+ this contains the length of the data in pBuf
+ \return CDF_STATUS
+ -------------------------------------------------------------------------------*/
+CDF_STATUS csr_get_country_code(tpAniSirGlobal pMac, uint8_t *pBuf,
+ uint8_t *pbLen);
+
+/* ---------------------------------------------------------------------------
+ \fn csr_set_country_code
+ \brief this function is to set the country code so channel/power setting matches the countrycode and
+ the domain it belongs to.
+ \param pCountry - Caller allocated buffer with at least 3 bytes specifying the country code
+ \return CDF_STATUS
+ -------------------------------------------------------------------------------*/
+CDF_STATUS csr_set_country_code(tpAniSirGlobal pMac, uint8_t *pCountry);
+
+/* ---------------------------------------------------------------------------
+ \fn csr_get_regulatory_domain_for_country
+ \brief this function is to get the regulatory domain for a country.
+ This function must be called after CFG is downloaded and all the band/mode setting already passed into
+ CSR.
+ \param pCountry - Caller allocated buffer with at least 3 bytes specifying the country code
+ \param pDomainId - Caller allocated buffer to get the return domain ID upon success return. Can be NULL.
+ \param source - the source of country information.
+ \return CDF_STATUS
+ -------------------------------------------------------------------------------*/
+CDF_STATUS csr_get_regulatory_domain_for_country(tpAniSirGlobal pMac,
+ uint8_t *pCountry,
+ v_REGDOMAIN_t *pDomainId,
+ v_CountryInfoSource_t source);
+
+/* some support functions */
+bool csr_is11d_supported(tpAniSirGlobal pMac);
+bool csr_is11h_supported(tpAniSirGlobal pMac);
+bool csr_is11e_supported(tpAniSirGlobal pMac);
+bool csr_is_wmm_supported(tpAniSirGlobal pMac);
+bool csr_is_mcc_supported(tpAniSirGlobal pMac);
+
+/* Return SUCCESS is the command is queued, failed */
+CDF_STATUS csr_queue_sme_command(tpAniSirGlobal pMac, tSmeCmd *pCommand,
+ bool fHighPriority);
+tSmeCmd *csr_get_command_buffer(tpAniSirGlobal pMac);
+void csr_release_command(tpAniSirGlobal pMac, tSmeCmd *pCommand);
+void csr_scan_flush_bss_entry(tpAniSirGlobal pMac,
+ tpSmeCsaOffloadInd pCsaOffloadInd);
+CDF_STATUS csr_get_active_scan_entry(tpAniSirGlobal mac, uint32_t scan_id,
+ tListElem **entry);
+
+#ifdef FEATURE_WLAN_WAPI
+bool csr_is_profile_wapi(tCsrRoamProfile *pProfile);
+#endif /* FEATURE_WLAN_WAPI */
+
+#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR
+
+/* Security */
+#define WLAN_SECURITY_EVENT_SET_PTK_REQ 1
+#define WLAN_SECURITY_EVENT_SET_PTK_RSP 2
+#define WLAN_SECURITY_EVENT_SET_GTK_REQ 3
+#define WLAN_SECURITY_EVENT_SET_GTK_RSP 4
+#define WLAN_SECURITY_EVENT_REMOVE_KEY_REQ 5
+#define WLAN_SECURITY_EVENT_REMOVE_KEY_RSP 6
+#define WLAN_SECURITY_EVENT_PMKID_CANDIDATE_FOUND 7
+#define WLAN_SECURITY_EVENT_PMKID_UPDATE 8
+#define WLAN_SECURITY_EVENT_MIC_ERROR 9
+
+#define AUTH_OPEN 0
+#define AUTH_SHARED 1
+#define AUTH_WPA_EAP 2
+#define AUTH_WPA_PSK 3
+#define AUTH_WPA2_EAP 4
+#define AUTH_WPA2_PSK 5
+#ifdef FEATURE_WLAN_WAPI
+#define AUTH_WAPI_CERT 6
+#define AUTH_WAPI_PSK 7
+#endif /* FEATURE_WLAN_WAPI */
+
+#define ENC_MODE_OPEN 0
+#define ENC_MODE_WEP40 1
+#define ENC_MODE_WEP104 2
+#define ENC_MODE_TKIP 3
+#define ENC_MODE_AES 4
+#ifdef FEATURE_WLAN_WAPI
+#define ENC_MODE_SMS4 5 /* WAPI */
+#endif /* FEATURE_WLAN_WAPI */
+
+#define NO_MATCH 0
+#define MATCH 1
+
+#define WLAN_SECURITY_STATUS_SUCCESS 0
+#define WLAN_SECURITY_STATUS_FAILURE 1
+
+/* Scan */
+#define WLAN_SCAN_EVENT_ACTIVE_SCAN_REQ 1
+#define WLAN_SCAN_EVENT_ACTIVE_SCAN_RSP 2
+#define WLAN_SCAN_EVENT_PASSIVE_SCAN_REQ 3
+#define WLAN_SCAN_EVENT_PASSIVE_SCAN_RSP 4
+#define WLAN_SCAN_EVENT_HO_SCAN_REQ 5
+#define WLAN_SCAN_EVENT_HO_SCAN_RSP 6
+
+#define WLAN_SCAN_STATUS_SUCCESS 0
+#define WLAN_SCAN_STATUS_FAILURE 1
+#define WLAN_SCAN_STATUS_ABORT 2
+
+/* Ibss */
+#define WLAN_IBSS_EVENT_START_IBSS_REQ 0
+#define WLAN_IBSS_EVENT_START_IBSS_RSP 1
+#define WLAN_IBSS_EVENT_JOIN_IBSS_REQ 2
+#define WLAN_IBSS_EVENT_JOIN_IBSS_RSP 3
+#define WLAN_IBSS_EVENT_COALESCING 4
+#define WLAN_IBSS_EVENT_PEER_JOIN 5
+#define WLAN_IBSS_EVENT_PEER_LEAVE 6
+#define WLAN_IBSS_EVENT_STOP_REQ 7
+#define WLAN_IBSS_EVENT_STOP_RSP 8
+
+#define AUTO_PICK 0
+#define SPECIFIED 1
+
+#define WLAN_IBSS_STATUS_SUCCESS 0
+#define WLAN_IBSS_STATUS_FAILURE 1
+
+/* 11d */
+#define WLAN_80211D_EVENT_COUNTRY_SET 0
+#define WLAN_80211D_EVENT_RESET 1
+
+#define WLAN_80211D_DISABLED 0
+#define WLAN_80211D_SUPPORT_MULTI_DOMAIN 1
+#define WLAN_80211D_NOT_SUPPORT_MULTI_DOMAIN 2
+
+int diag_auth_type_from_csr_type(eCsrAuthType authType);
+int diag_enc_type_from_csr_type(eCsrEncryptionType encType);
+#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */
+/* ---------------------------------------------------------------------------
+ \fn csr_scan_result_purge
+ \brief remove all items(tCsrScanResult) in the list and free memory for each item
+ \param hScanResult - returned from csr_scan_get_result. hScanResult is considered gone by
+ calling this function and even before this function reutrns.
+ \return CDF_STATUS
+ -------------------------------------------------------------------------------*/
+CDF_STATUS csr_scan_result_purge(tpAniSirGlobal pMac,
+ tScanResultHandle hScanResult);
+
+/* /////////////////////////////////////////Common Scan ends */
+
+/* ---------------------------------------------------------------------------
+ \fn csr_roam_connect
+ \brief To inititiate an association
+ \param pProfile - can be NULL to join to any open ones
+ \param pRoamId - to get back the request ID
+ \return CDF_STATUS
+ -------------------------------------------------------------------------------*/
+CDF_STATUS csr_roam_connect(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamProfile *pProfile,
+ uint32_t *pRoamId);
+
+/* ---------------------------------------------------------------------------
+ \fn csr_roam_reassoc
+ \brief To inititiate a re-association
+ \param pProfile - can be NULL to join the currently connected AP. In that
+ case modProfileFields should carry the modified field(s) which could trigger
+ reassoc
+ \param modProfileFields - fields which are part of tCsrRoamConnectedProfile
+ that might need modification dynamically once STA is up & running and this
+ could trigger a reassoc
+ \param pRoamId - to get back the request ID
+ \return CDF_STATUS
+ -------------------------------------------------------------------------------*/
+CDF_STATUS csr_roam_reassoc(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamProfile *pProfile,
+ tCsrRoamModifyProfileFields modProfileFields,
+ uint32_t *pRoamId);
+
+/* ---------------------------------------------------------------------------
+ \fn csr_roam_reconnect
+ \brief To disconnect and reconnect with the same profile
+ \return CDF_STATUS. It returns fail if currently not connected
+ -------------------------------------------------------------------------------*/
+CDF_STATUS csr_roam_reconnect(tpAniSirGlobal pMac, uint32_t sessionId);
+
+/* ---------------------------------------------------------------------------
+ \fn csr_roam_set_pmkid_cache
+ \brief return the PMKID candidate list
+ \param pPMKIDCache - caller allocated buffer point to an array of tPmkidCacheInfo
+ \param numItems - a variable that has the number of tPmkidCacheInfo allocated
+ when retruning, this is either the number needed or number of items put into pPMKIDCache
+ \return CDF_STATUS - when fail, it usually means the buffer allocated is not big enough and pNumItems
+ has the number of tPmkidCacheInfo.
+ \Note: pNumItems is a number of tPmkidCacheInfo, not sizeof(tPmkidCacheInfo) * something
+ -------------------------------------------------------------------------------*/
+CDF_STATUS csr_roam_set_pmkid_cache(tpAniSirGlobal pMac, uint32_t sessionId,
+ tPmkidCacheInfo *pPMKIDCache,
+ uint32_t numItems, bool update_entire_cache);
+
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+/* ---------------------------------------------------------------------------
+ *\fn csr_roam_set_psk_pmk
+ *\brief store PSK/PMK
+ *\param pMac - pointer to global structure for MAC
+ *\param sessionId - Sme session id
+ *\param pPSK_PMK - pointer to an array of Psk/Pmk
+ *\return CDF_STATUS - usually it succeed unless sessionId is not found
+ *\Note:
+ *-------------------------------------------------------------------------------*/
+CDF_STATUS csr_roam_set_psk_pmk(tpAniSirGlobal pMac, uint32_t sessionId,
+ uint8_t *pPSK_PMK, size_t pmk_len);
+
+/* ---------------------------------------------------------------------------
+ *\fn csr_roam_set_key_mgmt_offload
+ *\brief sets nRoamKeyMgmtOffloadEnabled
+ *\param pMac - pointer to global structure for MAC
+ *\param sessionId - Sme session id
+ *\param nRoamKeyMgmtOffloadEnabled - value of key mgmt offload enable
+ *\return CDF_STATUS - usually it succeed unless sessionId is not found
+ *\Note:
+ *-------------------------------------------------------------------------------*/
+CDF_STATUS csr_roam_set_key_mgmt_offload(tpAniSirGlobal pMac,
+ uint32_t sessionId,
+ bool nRoamKeyMgmtOffloadEnabled);
+#endif
+/* ---------------------------------------------------------------------------
+ \fn csr_roam_get_wpa_rsn_req_ie
+ \brief return the WPA or RSN IE CSR passes to PE to JOIN request or START_BSS request
+ \param pLen - caller allocated memory that has the length of pBuf as input. Upon returned, *pLen has the
+ needed or IE length in pBuf.
+ \param pBuf - Caller allocated memory that contain the IE field, if any, upon return
+ \return CDF_STATUS - when fail, it usually means the buffer allocated is not big enough
+ -------------------------------------------------------------------------------*/
+CDF_STATUS csr_roam_get_wpa_rsn_req_ie(tpAniSirGlobal pMac, uint32_t sessionId,
+ uint32_t *pLen, uint8_t *pBuf);
+
+/* ---------------------------------------------------------------------------
+ \fn csr_roam_get_wpa_rsn_rsp_ie
+ \brief return the WPA or RSN IE from the beacon or probe rsp if connected
+ \param pLen - caller allocated memory that has the length of pBuf as input. Upon returned, *pLen has the
+ needed or IE length in pBuf.
+ \param pBuf - Caller allocated memory that contain the IE field, if any, upon return
+ \return CDF_STATUS - when fail, it usually means the buffer allocated is not big enough
+ -------------------------------------------------------------------------------*/
+CDF_STATUS csr_roam_get_wpa_rsn_rsp_ie(tpAniSirGlobal pMac, uint32_t sessionId,
+ uint32_t *pLen, uint8_t *pBuf);
+
+/* ---------------------------------------------------------------------------
+ \fn csr_roam_get_num_pmkid_cache
+ \brief return number of PMKID cache entries
+ \return uint32_t - the number of PMKID cache entries
+ -------------------------------------------------------------------------------*/
+uint32_t csr_roam_get_num_pmkid_cache(tpAniSirGlobal pMac, uint32_t sessionId);
+
+/* ---------------------------------------------------------------------------
+ \fn csr_roam_get_pmkid_cache
+ \brief return PMKID cache from CSR
+ \param pNum - caller allocated memory that has the space of the number of pBuf tPmkidCacheInfo as input. Upon returned, *pNum has the
+ needed or actually number in tPmkidCacheInfo.
+ \param pPmkidCache - Caller allocated memory that contains PMKID cache, if any, upon return
+ \return CDF_STATUS - when fail, it usually means the buffer allocated is not big enough
+ -------------------------------------------------------------------------------*/
+CDF_STATUS csr_roam_get_pmkid_cache(tpAniSirGlobal pMac, uint32_t sessionId,
+ uint32_t *pNum, tPmkidCacheInfo *pPmkidCache);
+
+/**
+ * csr_roam_get_connect_profile() - To return the current connect profile,
+ * caller must call csr_roam_free_connect_profile after it is done and before
+ * reuse for another csr_roam_get_connect_profile call.
+ *
+ * @pMac: pointer to global adapter context
+ * @sessionId: session ID
+ * @pProfile: pointer to a caller allocated structure
+ * tCsrRoamConnectedProfile
+ *
+ * Return: CDF_STATUS. Failure if not connected, success otherwise
+ */
+CDF_STATUS csr_roam_get_connect_profile(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamConnectedProfile *pProfile);
+
+/* ---------------------------------------------------------------------------
+ \fn csr_roam_get_connect_state
+ \brief To return the current connect state of Roaming
+ \return CDF_STATUS
+ -------------------------------------------------------------------------------*/
+CDF_STATUS csr_roam_get_connect_state(tpAniSirGlobal pMac, uint32_t sessionId,
+ eCsrConnectState *pState);
+
+/* ---------------------------------------------------------------------------
+ \fn csr_roam_free_connect_profile
+ \brief To free and reinitialize the profile return previous by csr_roam_get_connect_profile.
+ \param pProfile - pointer to a caller allocated structure tCsrRoamConnectedProfile
+ \return CDF_STATUS.
+ -------------------------------------------------------------------------------*/
+CDF_STATUS csr_roam_free_connect_profile(tpAniSirGlobal pMac,
+ tCsrRoamConnectedProfile *pProfile);
+
+/* ---------------------------------------------------------------------------
+ \fn csr_apply_channel_and_power_list
+ \brief HDD calls this function to set the WNI_CFG_VALID_CHANNEL_LIST base on the band/mode settings.
+ This function must be called after CFG is downloaded and all the band/mode setting already passed into
+ CSR.
+ \return CDF_STATUS
+ -------------------------------------------------------------------------------*/
+CDF_STATUS csr_apply_channel_and_power_list(tpAniSirGlobal pMac);
+
+/**
+ * csr_change_config_params() - The CSR API exposed for HDD to provide config
+ * params to CSR during SMEs stop -> start sequence.
+ *
+ * @pMac: pointer to global adapter context
+ * @pUpdateConfigParam: a pointer to a structure (tCsrUpdateConfigParam) that
+ * currently provides 11d related information like country code, Regulatory
+ * domain, valid channel list, Tx power per channel, a list with active/passive
+ * scan allowed per valid channel.
+ *
+ * If HDD changed the domain that will cause a reset. This function will
+ * provide the new set of 11d information for the new domain. Currrently this
+ * API provides info regarding 11d only at reset but we can extend this for
+ * other params (PMC, QoS) which needs to be initialized again at reset.
+ *
+ * Return: CDF_STATUS. status of operation
+ */
+CDF_STATUS csr_change_config_params(tpAniSirGlobal pMac,
+ tCsrUpdateConfigParam *pUpdateConfigParam);
+
+/* ---------------------------------------------------------------------------
+ \fn csr_roam_connect_to_last_profile
+ \brief To disconnect and reconnect with the same profile
+ \return CDF_STATUS. It returns fail if currently connected
+ -------------------------------------------------------------------------------*/
+CDF_STATUS csr_roam_connect_to_last_profile(tpAniSirGlobal pMac, uint32_t sessionId);
+
+/* ---------------------------------------------------------------------------
+ \fn csr_roam_disconnect
+ \brief To disconnect from a network
+ \param reason -- To indicate the reason for disconnecting. Currently, only eCSR_DISCONNECT_REASON_MIC_ERROR is meanful.
+ \return CDF_STATUS
+ -------------------------------------------------------------------------------*/
+CDF_STATUS csr_roam_disconnect(tpAniSirGlobal pMac, uint32_t sessionId,
+ eCsrRoamDisconnectReason reason);
+
+/* ---------------------------------------------------------------------------
+ \fn csr_scan_get_pmkid_candidate_list
+ \brief return the PMKID candidate list
+ \param pPmkidList - caller allocated buffer point to an array of tPmkidCandidateInfo
+ \param pNumItems - pointer to a variable that has the number of tPmkidCandidateInfo allocated
+ when retruning, this is either the number needed or number of items put into pPmkidList
+ \return CDF_STATUS - when fail, it usually means the buffer allocated is not big enough and pNumItems
+ has the number of tPmkidCandidateInfo.
+ \Note: pNumItems is a number of tPmkidCandidateInfo, not sizeof(tPmkidCandidateInfo) * something
+ -------------------------------------------------------------------------------*/
+CDF_STATUS csr_scan_get_pmkid_candidate_list(tpAniSirGlobal pMac, uint32_t sessionId,
+ tPmkidCandidateInfo *pPmkidList,
+ uint32_t *pNumItems);
+
+/* This function is used to stop a BSS. It is similar of csr_roamIssueDisconnect but this function */
+/* doesn't have any logic other than blindly trying to stop BSS */
+CDF_STATUS csr_roam_issue_stop_bss_cmd(tpAniSirGlobal pMac, uint32_t sessionId,
+ bool fHighPriority);
+
+void csr_call_roaming_completion_callback(tpAniSirGlobal pMac,
+ tCsrRoamSession *pSession,
+ tCsrRoamInfo *pRoamInfo, uint32_t roamId,
+ eCsrRoamResult roamResult);
+
+/* ---------------------------------------------------------------------------
+ \fn csr_roam_issue_disassociate_sta_cmd
+ \brief csr function that HDD calls to disassociate a associated station
+ \param sessionId - session Id for Soft AP
+ \param pPeerMacAddr - MAC of associated station to delete
+ \param reason - reason code, be one of the tSirMacReasonCodes
+ \return CDF_STATUS
+ ---------------------------------------------------------------------------*/
+CDF_STATUS csr_roam_issue_disassociate_sta_cmd(tpAniSirGlobal pMac,
+ uint32_t sessionId,
+ const uint8_t *pPeerMacAddr,
+ uint32_t reason);
+
+/**
+ * csr_roam_issue_deauth_sta_cmd() - issue deauthenticate station command
+ * @pMac: Pointer to global structure for MAC
+ * @sessionId: Session Id for Soft AP
+ * @pDelStaParams: Pointer to parameters of the station to deauthenticate
+ *
+ * CSR function that HDD calls to issue a deauthenticate station command
+ *
+ * Return: CDF_STATUS_SUCCESS on success or another CDF_STATUS_* on error
+ */
+CDF_STATUS csr_roam_issue_deauth_sta_cmd(tpAniSirGlobal pMac,
+ uint32_t sessionId,
+ struct tagCsrDelStaParams *pDelStaParams);
+
+/* ---------------------------------------------------------------------------
+ \fn csr_roam_issue_tkip_counter_measures
+ \brief csr function that HDD calls to start and stop tkip countermeasures
+ \param sessionId - session Id for Soft AP
+ \param bEnable - Flag to start/stop countermeasures
+ \return CDF_STATUS
+ ---------------------------------------------------------------------------*/
+CDF_STATUS csr_roam_issue_tkip_counter_measures(tpAniSirGlobal pMac,
+ uint32_t sessionId, bool bEnable);
+
+CDF_STATUS csr_send_mb_tkip_counter_measures_req_msg(tpAniSirGlobal pMac,
+ uint32_t sessinId, bool bEnable,
+ tSirMacAddr bssId);
+
+/* ---------------------------------------------------------------------------
+ \fn csr_roam_get_associated_stas
+ \brief csr function that HDD calls to get list of associated stations based on module ID
+ \param sessionId - session Id for Soft AP
+ \param modId - module ID - PE/HAL/TL
+ \param pUsrContext - Opaque HDD context
+ \param pfnSapEventCallback - Sap event callback in HDD
+ \param pAssocStasBuf - Caller allocated memory to be filled with associatd stations info
+ \return CDF_STATUS
+ ---------------------------------------------------------------------------*/
+CDF_STATUS csr_roam_get_associated_stas(tpAniSirGlobal pMac, uint32_t sessionId,
+ CDF_MODULE_ID modId, void *pUsrContext,
+ void *pfnSapEventCallback,
+ uint8_t *pAssocStasBuf);
+
+CDF_STATUS csr_send_mb_get_associated_stas_req_msg(tpAniSirGlobal pMac,
+ uint32_t sessionId,
+ CDF_MODULE_ID modId,
+ tSirMacAddr bssId,
+ void *pUsrContext,
+ void *pfnSapEventCallback,
+ uint8_t *pAssocStasBuf);
+
+/* ---------------------------------------------------------------------------
+ \fn csr_roam_get_wps_session_overlap
+ \brief csr function that HDD calls to get WPS PBC session overlap information
+ \param sessionId - session Id for Soft AP
+ \param pUsrContext - Opaque HDD context
+ \param pfnSapEventCallback - Sap event callback in HDD
+ \param pRemoveMac - pointer to MAC address of session to be removed
+ \return CDF_STATUS
+ ---------------------------------------------------------------------------*/
+CDF_STATUS csr_roam_get_wps_session_overlap(tpAniSirGlobal pMac, uint32_t sessionId,
+ void *pUsrContext,
+ void *pfnSapEventCallback,
+ struct cdf_mac_addr pRemoveMac);
+
+CDF_STATUS csr_send_mb_get_wpspbc_sessions(tpAniSirGlobal pMac, uint32_t sessionId,
+ tSirMacAddr bssId, void *pUsrContext,
+ void *pfnSapEventCallback,
+ struct cdf_mac_addr pRemoveMac);
+
+/* ---------------------------------------------------------------------------
+ \fn csr_send_chng_mcc_beacon_interval
+ \brief csr function that HDD calls to send Update beacon interval
+ \param sessionId - session Id for Soft AP
+ \return CDF_STATUS
+ ---------------------------------------------------------------------------*/
+CDF_STATUS
+csr_send_chng_mcc_beacon_interval(tpAniSirGlobal pMac, uint32_t sessionId);
+
+#ifdef WLAN_FEATURE_VOWIFI_11R
+/* ---------------------------------------------------------------------------
+ \fn csr_roam_ft_pre_auth_rsp_processor
+ \brief csr function that handles pre auth response from LIM
+ ---------------------------------------------------------------------------*/
+void csr_roam_ft_pre_auth_rsp_processor(tHalHandle hHal,
+ tpSirFTPreAuthRsp pFTPreAuthRsp);
+#endif
+
+
+#if defined(FEATURE_WLAN_ESE)
+void update_cckmtsf(uint32_t *timeStamp0, uint32_t *timeStamp1,
+ uint32_t *incr);
+#endif
+
+CDF_STATUS csr_roam_enqueue_preauth(tpAniSirGlobal pMac, uint32_t sessionId,
+ tpSirBssDescription pBssDescription,
+ eCsrRoamReason reason, bool fImmediate);
+CDF_STATUS csr_dequeue_roam_command(tpAniSirGlobal pMac, eCsrRoamReason reason);
+#ifdef FEATURE_WLAN_LFR
+void csr_init_occupied_channels_list(tpAniSirGlobal pMac, uint8_t sessionId);
+bool csr_neighbor_roam_is_new_connected_profile(tpAniSirGlobal pMac,
+ uint8_t sessionId);
+bool csr_neighbor_roam_connected_profile_match(tpAniSirGlobal pMac,
+ uint8_t sessionId,
+ tCsrScanResult *pResult,
+ tDot11fBeaconIEs *pIes);
+#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 csr_update_channel_list(tpAniSirGlobal pMac);
+CDF_STATUS csr_roam_del_pmkid_from_cache(tpAniSirGlobal pMac,
+ uint32_t sessionId,
+ const uint8_t *pBSSId,
+ bool flush_cache);
+
+bool csr_elected_country_info(tpAniSirGlobal pMac);
+void csr_add_vote_for_country_info(tpAniSirGlobal pMac, uint8_t *pCountryCode);
+void csr_clear_votes_for_country_info(tpAniSirGlobal pMac);
+
+#endif
+
+#ifdef QCA_HT_2040_COEX
+CDF_STATUS csr_set_ht2040_mode(tpAniSirGlobal pMac, uint32_t sessionId,
+ ePhyChanBondState cbMode, bool obssEnabled);
+#endif
+tSirBssDescription*
+csr_get_bssdescr_from_scan_handle(tScanResultHandle result_handle,
+ tSirBssDescription *bss_descr);
+void csr_release_scan_command(tpAniSirGlobal pMac, tSmeCmd *pCommand,
+ eCsrScanStatus scanStatus);
+void csr_scan_active_list_timeout_handle(void *userData);
+CDF_STATUS csr_prepare_disconnect_command(tpAniSirGlobal mac,
+ uint32_t session_id, tSmeCmd **sme_cmd);
diff --git a/core/sme/src/csr/csr_link_list.c b/core/sme/src/csr/csr_link_list.c
new file mode 100644
index 0000000..1fa0b8b
--- /dev/null
+++ b/core/sme/src/csr/csr_link_list.c
@@ -0,0 +1,571 @@
+/*
+ * Copyright (c) 2011-2012, 2014-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_link_list.c
+
+ Implementation for the Common link list interfaces.
+ ========================================================================== */
+
+#include "csr_link_list.h"
+#include "cdf_lock.h"
+#include "cdf_memory.h"
+#include "cdf_trace.h"
+#include "cdf_mc_timer.h"
+
+CDF_INLINE_FN void csr_list_init(tListElem *pList)
+{
+ pList->last = pList->next = pList;
+}
+
+CDF_INLINE_FN void csr_list_remove_entry(tListElem *pEntry)
+{
+ tListElem *pLast;
+ tListElem *pNext;
+
+ pLast = pEntry->last;
+ pNext = pEntry->next;
+ pLast->next = pNext;
+ pNext->last = pLast;
+}
+
+CDF_INLINE_FN tListElem *csr_list_remove_head(tListElem *pHead)
+{
+ tListElem *pEntry;
+ tListElem *pNext;
+
+ pEntry = pHead->next;
+ pNext = pEntry->next;
+ pHead->next = pNext;
+ pNext->last = pHead;
+
+ return pEntry;
+}
+
+CDF_INLINE_FN tListElem *csr_list_remove_tail(tListElem *pHead)
+{
+ tListElem *pEntry;
+ tListElem *pLast;
+
+ pEntry = pHead->last;
+ pLast = pEntry->last;
+ pHead->last = pLast;
+ pLast->next = pHead;
+
+ return pEntry;
+}
+
+CDF_INLINE_FN void csr_list_insert_tail(tListElem *pHead, tListElem *pEntry)
+{
+ tListElem *pLast;
+
+ pLast = pHead->last;
+ pEntry->last = pLast;
+ pEntry->next = pHead;
+ pLast->next = pEntry;
+ pHead->last = pEntry;
+}
+
+CDF_INLINE_FN void csr_list_insert_head(tListElem *pHead, tListElem *pEntry)
+{
+ tListElem *pNext;
+
+ pNext = pHead->next;
+ pEntry->next = pNext;
+ pEntry->last = pHead;
+ pNext->last = pEntry;
+ pHead->next = pEntry;
+}
+
+/* Insert pNewEntry before pEntry */
+void csr_list_insert_entry(tListElem *pEntry, tListElem *pNewEntry)
+{
+ tListElem *pLast;
+ if (!pEntry) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL,
+ "%s: Error!! pEntry is Null", __func__);
+ return;
+ }
+
+ pLast = pEntry->last;
+ pLast->next = pNewEntry;
+ pEntry->last = pNewEntry;
+ pNewEntry->next = pEntry;
+ pNewEntry->last = pLast;
+}
+
+uint32_t csr_ll_count(tDblLinkList *pList)
+{
+ uint32_t c = 0;
+
+ if (!pList) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL,
+ "%s: Error!! pList is Null", __func__);
+ return c;
+ }
+
+ if (pList && (LIST_FLAG_OPEN == pList->Flag)) {
+ c = pList->Count;
+ }
+
+ return c;
+}
+
+void csr_ll_lock(tDblLinkList *pList)
+{
+
+ if (!pList) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL,
+ "%s: Error!! pList is Null", __func__);
+ return;
+ }
+
+ if (LIST_FLAG_OPEN == pList->Flag) {
+ cdf_mutex_acquire(&pList->Lock);
+ }
+}
+
+void csr_ll_unlock(tDblLinkList *pList)
+{
+
+ if (!pList) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL,
+ "%s: Error!! pList is Null", __func__);
+ return;
+ }
+
+ if (LIST_FLAG_OPEN == pList->Flag) {
+ cdf_mutex_release(&pList->Lock);
+ }
+}
+
+bool csr_ll_is_list_empty(tDblLinkList *pList, bool fInterlocked)
+{
+ bool fEmpty = true;
+
+ if (!pList) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL,
+ "%s: Error!! pList is Null", __func__);
+ return fEmpty;
+ }
+
+ if (LIST_FLAG_OPEN == pList->Flag) {
+ if (fInterlocked) {
+ csr_ll_lock(pList);
+ }
+
+ fEmpty = csrIsListEmpty(&pList->ListHead);
+
+ if (fInterlocked) {
+ csr_ll_unlock(pList);
+ }
+ }
+ return fEmpty;
+}
+
+bool csr_ll_find_entry(tDblLinkList *pList, tListElem *pEntryToFind)
+{
+ bool fFound = false;
+ tListElem *pEntry;
+
+ if (!pList) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL,
+ "%s: Error!! pList is Null", __func__);
+ return fFound;
+ }
+
+ if (LIST_FLAG_OPEN == pList->Flag) {
+ 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 && (pEntry != &pList->ListHead)) {
+ if (pEntry == pEntryToFind) {
+ fFound = true;
+ break;
+ }
+ pEntry = pEntry->next;
+ }
+
+ }
+ return fFound;
+}
+
+CDF_STATUS csr_ll_open(tHddHandle hHdd, tDblLinkList *pList)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ CDF_STATUS cdf_status;
+
+ if (!pList) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL,
+ "%s: Error!! pList is Null", __func__);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ if (LIST_FLAG_OPEN != pList->Flag) {
+ pList->Count = 0;
+ pList->cmdTimeoutTimer = NULL;
+ cdf_status = cdf_mutex_init(&pList->Lock);
+
+ if (CDF_IS_STATUS_SUCCESS(cdf_status)) {
+ csr_list_init(&pList->ListHead);
+ pList->Flag = LIST_FLAG_OPEN;
+ pList->hHdd = hHdd;
+ } else {
+ status = CDF_STATUS_E_FAILURE;
+ }
+ }
+ return status;
+}
+
+void csr_ll_close(tDblLinkList *pList)
+{
+ if (!pList) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL,
+ "%s: Error!! pList is Null", __func__);
+ return;
+ }
+
+ if (LIST_FLAG_OPEN == pList->Flag) {
+ /* Make sure the list is empty... */
+ csr_ll_purge(pList, LL_ACCESS_LOCK);
+ cdf_mutex_destroy(&pList->Lock);
+ pList->Flag = LIST_FLAG_CLOSE;
+ }
+}
+
+void csr_ll_insert_tail(tDblLinkList *pList, tListElem *pEntry,
+ bool fInterlocked)
+{
+ if (!pList) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL,
+ "%s: Error!! pList is Null", __func__);
+ return;
+ }
+
+ if (LIST_FLAG_OPEN == pList->Flag) {
+ if (fInterlocked) {
+ csr_ll_lock(pList);
+ }
+ csr_list_insert_tail(&pList->ListHead, pEntry);
+ pList->Count++;
+ if (fInterlocked) {
+ csr_ll_unlock(pList);
+ }
+ }
+}
+
+void csr_ll_insert_head(tDblLinkList *pList, tListElem *pEntry,
+ bool fInterlocked)
+{
+
+ if (!pList) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL,
+ "%s: Error!! pList is Null", __func__);
+ return;
+ }
+
+ if (LIST_FLAG_OPEN == pList->Flag) {
+ if (fInterlocked) {
+ csr_ll_lock(pList);
+ }
+ csr_list_insert_head(&pList->ListHead, pEntry);
+ pList->Count++;
+ if (fInterlocked) {
+ csr_ll_unlock(pList);
+ }
+ if (pList->cmdTimeoutTimer && pList->cmdTimeoutDuration) {
+ /* timer to detect pending command in activelist */
+ cdf_mc_timer_start(pList->cmdTimeoutTimer,
+ pList->cmdTimeoutDuration);
+ }
+ }
+}
+
+void csr_ll_insert_entry(tDblLinkList *pList, tListElem *pEntry,
+ tListElem *pNewEntry, bool fInterlocked)
+{
+ if (!pList) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL,
+ "%s: Error!! pList is Null", __func__);
+ return;
+ }
+
+ if (LIST_FLAG_OPEN == pList->Flag) {
+ if (fInterlocked) {
+ csr_ll_lock(pList);
+ }
+ csr_list_insert_entry(pEntry, pNewEntry);
+ pList->Count++;
+ if (fInterlocked) {
+ csr_ll_unlock(pList);
+ }
+ }
+}
+
+tListElem *csr_ll_remove_tail(tDblLinkList *pList, bool fInterlocked)
+{
+ tListElem *pEntry = NULL;
+
+ if (!pList) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL,
+ "%s: Error!! pList is Null", __func__);
+ return pEntry;
+ }
+
+ if (LIST_FLAG_OPEN == pList->Flag) {
+ if (fInterlocked) {
+ csr_ll_lock(pList);
+ }
+
+ if (!csrIsListEmpty(&pList->ListHead)) {
+
+ pEntry = csr_list_remove_tail(&pList->ListHead);
+ pList->Count--;
+ }
+ if (fInterlocked) {
+ csr_ll_unlock(pList);
+ }
+ }
+
+ return pEntry;
+}
+
+tListElem *csr_ll_peek_tail(tDblLinkList *pList, bool fInterlocked)
+{
+ tListElem *pEntry = NULL;
+
+ if (!pList) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL,
+ "%s: Error!! pList is Null", __func__);
+ return pEntry;
+ }
+
+ if (LIST_FLAG_OPEN == pList->Flag) {
+ if (fInterlocked) {
+ csr_ll_lock(pList);
+ }
+
+ if (!csrIsListEmpty(&pList->ListHead)) {
+ pEntry = pList->ListHead.last;
+ }
+ if (fInterlocked) {
+ csr_ll_unlock(pList);
+ }
+ }
+
+ return pEntry;
+}
+
+tListElem *csr_ll_remove_head(tDblLinkList *pList, bool fInterlocked)
+{
+ tListElem *pEntry = NULL;
+
+ if (!pList) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL,
+ "%s: Error!! pList is Null", __func__);
+ return pEntry;
+ }
+
+ if (LIST_FLAG_OPEN == pList->Flag) {
+ if (fInterlocked) {
+ csr_ll_lock(pList);
+ }
+
+ if (!csrIsListEmpty(&pList->ListHead)) {
+ pEntry = csr_list_remove_head(&pList->ListHead);
+ pList->Count--;
+ }
+
+ if (fInterlocked) {
+ csr_ll_unlock(pList);
+ }
+ }
+
+ return pEntry;
+}
+
+tListElem *csr_ll_peek_head(tDblLinkList *pList, bool fInterlocked)
+{
+ tListElem *pEntry = NULL;
+
+ if (!pList) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL,
+ "%s: Error!! pList is Null", __func__);
+ return pEntry;
+ }
+
+ if (LIST_FLAG_OPEN == pList->Flag) {
+ if (fInterlocked) {
+ csr_ll_lock(pList);
+ }
+
+ if (!csrIsListEmpty(&pList->ListHead)) {
+ pEntry = pList->ListHead.next;
+ }
+ if (fInterlocked) {
+ csr_ll_unlock(pList);
+ }
+ }
+
+ return pEntry;
+}
+
+void csr_ll_purge(tDblLinkList *pList, bool fInterlocked)
+{
+ tListElem *pEntry;
+
+ if (!pList) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL,
+ "%s: Error!! pList is Null", __func__);
+ return;
+ }
+
+ if (LIST_FLAG_OPEN == pList->Flag) {
+ if (fInterlocked) {
+ csr_ll_lock(pList);
+ }
+ while ((pEntry = csr_ll_remove_head(pList, LL_ACCESS_NOLOCK))) {
+ /* just remove everything from the list until */
+ /* nothing left on the list. */
+ }
+ if (fInterlocked) {
+ csr_ll_unlock(pList);
+ }
+ }
+}
+
+bool csr_ll_remove_entry(tDblLinkList *pList, tListElem *pEntryToRemove,
+ bool fInterlocked)
+{
+ bool fFound = false;
+ tListElem *pEntry;
+
+ if (!pList) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL,
+ "%s: Error!! pList is Null", __func__);
+ return fFound;
+ }
+
+ if (LIST_FLAG_OPEN == pList->Flag) {
+ if (fInterlocked) {
+ csr_ll_lock(pList);
+ }
+
+ 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 && (pEntry != &pList->ListHead)) {
+ if (pEntry == pEntryToRemove) {
+ csr_list_remove_entry(pEntry);
+ pList->Count--;
+
+ fFound = true;
+ break;
+ }
+
+ pEntry = pEntry->next;
+ }
+ if (fInterlocked) {
+ csr_ll_unlock(pList);
+ }
+ if (pList->cmdTimeoutTimer) {
+ cdf_mc_timer_stop(pList->cmdTimeoutTimer);
+ }
+ }
+
+ return fFound;
+}
+
+tListElem *csr_ll_next(tDblLinkList *pList, tListElem *pEntry,
+ bool fInterlocked)
+{
+ tListElem *pNextEntry = NULL;
+
+ if (!pList) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL,
+ "%s: Error!! pList is Null", __func__);
+ return pNextEntry;
+ }
+
+ if (LIST_FLAG_OPEN == pList->Flag) {
+ if (fInterlocked) {
+ csr_ll_lock(pList);
+ }
+
+ if (!csrIsListEmpty(&pList->ListHead)
+ && csr_ll_find_entry(pList, pEntry)) {
+ pNextEntry = pEntry->next;
+ /* Make sure we don't walk past the head */
+ if (pNextEntry == &pList->ListHead) {
+ pNextEntry = NULL;
+ }
+ }
+
+ if (fInterlocked) {
+ csr_ll_unlock(pList);
+ }
+ }
+
+ return pNextEntry;
+}
+
+tListElem *csr_ll_previous(tDblLinkList *pList, tListElem *pEntry,
+ bool fInterlocked)
+{
+ tListElem *pNextEntry = NULL;
+
+ if (!pList) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL,
+ "%s: Error!! pList is Null", __func__);
+ return pNextEntry;
+ }
+
+ if (LIST_FLAG_OPEN == pList->Flag) {
+ if (fInterlocked) {
+ csr_ll_lock(pList);
+ }
+
+ if (!csrIsListEmpty(&pList->ListHead)
+ && csr_ll_find_entry(pList, pEntry)) {
+ pNextEntry = pEntry->last;
+ /* Make sure we don't walk past the head */
+ if (pNextEntry == &pList->ListHead) {
+ pNextEntry = NULL;
+ }
+ }
+
+ if (fInterlocked) {
+ csr_ll_unlock(pList);
+ }
+ }
+
+ return pNextEntry;
+}
diff --git a/core/sme/src/csr/csr_neighbor_roam.c b/core/sme/src/csr/csr_neighbor_roam.c
new file mode 100644
index 0000000..5aef6cf
--- /dev/null
+++ b/core/sme/src/csr/csr_neighbor_roam.c
@@ -0,0 +1,3541 @@
+/*
+ * 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_neighbor_roam.c
+
+ Implementation for the simple roaming algorithm for 802.11r Fast
+ transitions and Legacy roaming for Android platform.
+ ========================================================================== */
+
+#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING
+#include "wma_types.h"
+#include "cds_mq.h"
+#include "csr_inside_api.h"
+#include "sms_debug.h"
+#include "sme_qos_internal.h"
+#include "sme_inside.h"
+#include "host_diag_core_event.h"
+#include "host_diag_core_log.h"
+#include "csr_api.h"
+#include "sme_api.h"
+#include "csr_neighbor_roam.h"
+#include "mac_trace.h"
+
+#define WLAN_FEATURE_NEIGHBOR_ROAMING_DEBUG 1
+#ifdef WLAN_FEATURE_NEIGHBOR_ROAMING_DEBUG
+#define NEIGHBOR_ROAM_DEBUG sms_log
+#else
+#define NEIGHBOR_ROAM_DEBUG(x ...)
+#endif
+
+static void csr_neighbor_roam_reset_channel_info(tpCsrNeighborRoamChannelInfo
+ rChInfo);
+static void csr_neighbor_roam_reset_preauth_control_info(tpAniSirGlobal pMac,
+ uint8_t sessionId);
+
+CDF_STATUS csr_roam_copy_connected_profile(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamProfile *pDstProfile);
+
+#ifdef WLAN_FEATURE_VOWIFI_11R
+static CDF_STATUS csr_neighbor_roam_issue_preauth_req(tpAniSirGlobal pMac,
+ uint8_t sessionId);
+#endif
+
+#define CSR_NEIGHBOR_ROAM_STATE_TRANSITION(mac_ctx, newstate, session) \
+{ \
+ mac_ctx->roam.neighborRoamInfo[session].prevNeighborRoamState = \
+ mac_ctx->roam.neighborRoamInfo[session].neighborRoamState; \
+ mac_ctx->roam.neighborRoamInfo[session].neighborRoamState = newstate; \
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, \
+ FL("Sessionid (%d) NeighborRoam transition from %s to %s"), \
+ session, csr_neighbor_roam_state_to_string( \
+ mac_ctx->roam.neighborRoamInfo[session].prevNeighborRoamState),\
+ csr_neighbor_roam_state_to_string(newstate)); \
+}
+
+uint8_t *csr_neighbor_roam_state_to_string(uint8_t state)
+{
+ switch (state) {
+ CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_CLOSED);
+ CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_INIT);
+ CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_CONNECTED);
+ CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING);
+ CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING);
+ CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE);
+ default:
+ return "eCSR_NEIGHBOR_ROAM_STATE_UNKNOWN";
+ }
+
+}
+
+#ifdef FEATURE_WLAN_LFR_METRICS
+/**
+ * csr_neighbor_roam_send_lfr_metric_event() - Send event of LFR metric
+ * @mac_ctx: Handle returned by mac_open.
+ * @session_id: Session information
+ * @bssid: BSSID of attempted AP
+ * @status: Result of LFR operation
+ *
+ * LFR metrics - pre-auth completion metric
+ * Send the event to supplicant indicating pre-auth result
+ *
+ * Return: void
+ */
+
+static void csr_neighbor_roam_send_lfr_metric_event(
+ tpAniSirGlobal mac_ctx,
+ uint8_t session_id,
+ tSirMacAddr bssid,
+ eRoamCmdStatus status)
+{
+ tCsrRoamInfo *roam_info;
+
+ roam_info = cdf_mem_malloc(sizeof(tCsrRoamInfo));
+ if (NULL == roam_info) {
+ sms_log(mac_ctx, LOG1, FL("Memory allocation failed!"));
+ } else {
+ cdf_mem_copy((void *)roam_info->bssid,
+ (void *)bssid, sizeof(*roam_info));
+ csr_roam_call_callback(mac_ctx, session_id, roam_info, 0,
+ status, 0);
+ cdf_mem_free(roam_info);
+ }
+}
+#else
+/* Empty inline function will be a no-op */
+static inline void csr_neighbor_roam_send_lfr_metric_event(
+ tpAniSirGlobal mac_ctx,
+ uint8_t session_id,
+ tSirMacAddr bssid,
+ eRoamCmdStatus status)
+{
+ ;
+}
+#endif
+
+/**
+ * csr_neighbor_roam_free_neighbor_roam_bss_node()
+ *
+ * @mac_ctx: Pointer to Global MAC structure
+ * @neighborRoamBSSNode: Neighbor Roam BSS Node to be freed
+ *
+ * This function frees all the internal pointers CSR NeighborRoam BSS Info
+ * and also frees the node itself
+ *
+ * Return: None
+ */
+void csr_neighbor_roam_free_neighbor_roam_bss_node(tpAniSirGlobal pMac,
+ tpCsrNeighborRoamBSSInfo
+ neighborRoamBSSNode)
+{
+ if (neighborRoamBSSNode) {
+ if (neighborRoamBSSNode->pBssDescription) {
+ cdf_mem_free(neighborRoamBSSNode->pBssDescription);
+ neighborRoamBSSNode->pBssDescription = NULL;
+ }
+ cdf_mem_free(neighborRoamBSSNode);
+ neighborRoamBSSNode = NULL;
+ }
+
+ return;
+}
+
+/**
+ * csr_neighbor_roam_remove_roamable_ap_list_entry()
+ *
+ * @mac_ctx: Pointer to Global MAC structure
+ * @pList: The list from which the entry should be removed
+ * @pNeighborEntry: Neighbor Roam BSS Node to be removed
+ *
+ * This function removes a given entry from the given list
+ *
+ * Return: true if successfully removed, else false
+ */
+bool csr_neighbor_roam_remove_roamable_ap_list_entry(tpAniSirGlobal pMac,
+ tDblLinkList *pList,
+ tpCsrNeighborRoamBSSInfo
+ pNeighborEntry)
+{
+ if (pList) {
+ return csr_ll_remove_entry(pList, &pNeighborEntry->List,
+ LL_ACCESS_LOCK);
+ }
+
+ sms_log(pMac, LOGE,
+ FL
+ ("Removing neighbor BSS node from list failed. Current count = %d"),
+ csr_ll_count(pList));
+
+ return false;
+}
+
+/**
+ * csr_neighbor_roam_next_roamable_ap() - Get next AP from roamable AP list
+ * @mac_ctx - The handle returned by mac_open.
+ * @plist - The list from which the entry should be returned
+ * @neighbor_entry - Neighbor Roam BSS Node whose next entry should be returned
+ *
+ * Gets the entry next to passed entry. If NULL is passed, return the entry
+ * in the head of the list
+ *
+ * Return: Neighbor Roam BSS Node to be returned
+ */
+tpCsrNeighborRoamBSSInfo csr_neighbor_roam_next_roamable_ap(
+ tpAniSirGlobal mac_ctx, tDblLinkList *llist,
+ tpCsrNeighborRoamBSSInfo neighbor_entry)
+{
+ tListElem *entry = NULL;
+ tpCsrNeighborRoamBSSInfo result = NULL;
+
+ if (llist) {
+ if (NULL == neighbor_entry)
+ entry = csr_ll_peek_head(llist, LL_ACCESS_LOCK);
+ else
+ entry = csr_ll_next(llist, &neighbor_entry->List,
+ LL_ACCESS_LOCK);
+ if (entry)
+ result = GET_BASE_ADDR(entry, tCsrNeighborRoamBSSInfo,
+ List);
+ }
+
+ return result;
+}
+
+/**
+ * csr_neighbor_roam_free_roamable_bss_list() - Frees roamable APs list
+ * @mac_ctx: The handle returned by mac_open.
+ * @llist: Neighbor Roam BSS List to be emptied
+ *
+ * Empties and frees all the nodes in the roamable AP list
+ *
+ * Return: none
+ */
+void csr_neighbor_roam_free_roamable_bss_list(tpAniSirGlobal mac_ctx,
+ tDblLinkList *llist)
+{
+ tpCsrNeighborRoamBSSInfo result = NULL;
+
+ NEIGHBOR_ROAM_DEBUG(mac_ctx, LOG2,
+ FL("Emptying the BSS list. Current count = %d"),
+ csr_ll_count(llist));
+
+ /*
+ * Pick up the head, remove and free the node till
+ * the list becomes empty
+ */
+ while ((result = csr_neighbor_roam_next_roamable_ap(mac_ctx, llist,
+ NULL)) != NULL) {
+ csr_neighbor_roam_remove_roamable_ap_list_entry(mac_ctx,
+ llist, result);
+ csr_neighbor_roam_free_neighbor_roam_bss_node(mac_ctx, result);
+ }
+ return;
+}
+
+static void csr_neighbor_roam_trigger_handoff(tpAniSirGlobal pMac,
+ uint8_t sessionId)
+{
+ if (csr_roam_is_fast_roam_enabled(pMac, sessionId)) {
+ csr_neighbor_roam_issue_preauth_req(pMac, sessionId);
+ } else {
+ sms_log(pMac, LOGE, FL("Roaming is diisabled"));
+ }
+}
+
+CDF_STATUS
+csr_neighbor_roam_update_fast_roaming_enabled(tpAniSirGlobal pMac,
+ uint8_t sessionId,
+ const bool fastRoamEnabled)
+{
+ CDF_STATUS cdf_status = CDF_STATUS_SUCCESS;
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+ /* set fast roam enable/disable flag */
+ pMac->roam.configParam.isFastRoamIniFeatureEnabled = fastRoamEnabled;
+
+ switch (pNeighborRoamInfo->neighborRoamState) {
+ case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED:
+ if (true == fastRoamEnabled) {
+ csr_roam_offload_scan(pMac, sessionId,
+ ROAM_SCAN_OFFLOAD_START,
+ REASON_CONNECT);
+ } else {
+ csr_roam_offload_scan(pMac, sessionId,
+ ROAM_SCAN_OFFLOAD_STOP,
+ REASON_DISCONNECTED);
+ }
+ break;
+ case eCSR_NEIGHBOR_ROAM_STATE_INIT:
+ NEIGHBOR_ROAM_DEBUG(pMac, LOG2,
+ FL
+ ("Currently in INIT state, Nothing to do"));
+ break;
+ default:
+ NEIGHBOR_ROAM_DEBUG(pMac, LOGE,
+ FL
+ ("Unexpected state %s, returning failure"),
+ mac_trace_get_neighbour_roam_state
+ (pNeighborRoamInfo->neighborRoamState));
+ cdf_status = CDF_STATUS_E_FAILURE;
+ break;
+ }
+ return cdf_status;
+}
+
+#ifdef FEATURE_WLAN_ESE
+CDF_STATUS csr_neighbor_roam_update_ese_mode_enabled(tpAniSirGlobal pMac,
+ uint8_t sessionId,
+ const bool eseMode)
+{
+ CDF_STATUS cdf_status = CDF_STATUS_SUCCESS;
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+
+ switch (pNeighborRoamInfo->neighborRoamState) {
+ case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED:
+ if (true == eseMode) {
+ csr_roam_offload_scan(pMac, sessionId,
+ ROAM_SCAN_OFFLOAD_START,
+ REASON_CONNECT);
+ } else if (false == eseMode) {
+ csr_roam_offload_scan(pMac, sessionId,
+ ROAM_SCAN_OFFLOAD_STOP,
+ REASON_DISCONNECTED);
+ }
+ break;
+
+ case eCSR_NEIGHBOR_ROAM_STATE_INIT:
+ NEIGHBOR_ROAM_DEBUG(pMac,
+ LOG2,
+ FL
+ ("Currently in INIT state, Nothing to do"));
+ break;
+
+ default:
+ NEIGHBOR_ROAM_DEBUG(pMac, LOGE,
+ FL
+ ("Unexpected state %d, returning failure"),
+ pNeighborRoamInfo->neighborRoamState);
+ break;
+ }
+ return cdf_status;
+}
+#endif
+
+CDF_STATUS csr_neighbor_roam_set_lookup_rssi_threshold(tpAniSirGlobal pMac,
+ uint8_t sessionId,
+ uint8_t
+ neighborLookupRssiThreshold)
+{
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+ CDF_STATUS cdf_status = CDF_STATUS_SUCCESS;
+
+ switch (pNeighborRoamInfo->neighborRoamState) {
+ case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED:
+ NEIGHBOR_ROAM_DEBUG(pMac, LOG2,
+ FL("Currently in CONNECTED state, "
+ "sending ROAM_SCAN_OFFLOAD_UPDATE_CFG."));
+ pNeighborRoamInfo->cfgParams.neighborLookupThreshold =
+ neighborLookupRssiThreshold;
+ pNeighborRoamInfo->currentNeighborLookupThreshold =
+ pNeighborRoamInfo->cfgParams.neighborLookupThreshold;
+ csr_roam_offload_scan(pMac, sessionId,
+ ROAM_SCAN_OFFLOAD_UPDATE_CFG,
+ REASON_LOOKUP_THRESH_CHANGED);
+ break;
+
+ case eCSR_NEIGHBOR_ROAM_STATE_INIT:
+ NEIGHBOR_ROAM_DEBUG(pMac, LOG2,
+ FL("Currently in INIT state, "
+ "just set lookupRssi threshold."));
+ pNeighborRoamInfo->cfgParams.neighborLookupThreshold =
+ neighborLookupRssiThreshold;
+ pNeighborRoamInfo->currentNeighborLookupThreshold =
+ pNeighborRoamInfo->cfgParams.neighborLookupThreshold;
+ break;
+
+ default:
+ NEIGHBOR_ROAM_DEBUG(pMac, LOGE,
+ FL
+ ("Unexpected state %s, returning failure"),
+ mac_trace_get_neighbour_roam_state
+ (pNeighborRoamInfo->neighborRoamState));
+ cdf_status = CDF_STATUS_E_FAILURE;
+ break;
+ }
+ return cdf_status;
+}
+
+CDF_STATUS
+csr_neighbor_roam_set_opportunistic_scan_threshold_diff(tpAniSirGlobal pMac,
+ uint8_t sessionId,
+ uint8_t
+ nOpportunisticThresholdDiff)
+{
+ CDF_STATUS cdf_status = CDF_STATUS_SUCCESS;
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+
+ switch (pNeighborRoamInfo->neighborRoamState) {
+ case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED:
+ NEIGHBOR_ROAM_DEBUG(pMac, LOG2,
+ FL("Currently in CONNECTED state, "
+ "sending ROAM_SCAN_OFFLOAD_UPDATE_CFG"));
+ pNeighborRoamInfo->cfgParams.nOpportunisticThresholdDiff =
+ nOpportunisticThresholdDiff;
+ pNeighborRoamInfo->currentOpportunisticThresholdDiff =
+ nOpportunisticThresholdDiff;
+
+ csr_roam_offload_scan(pMac,
+ sessionId,
+ ROAM_SCAN_OFFLOAD_UPDATE_CFG,
+ REASON_OPPORTUNISTIC_THRESH_DIFF_CHANGED);
+ break;
+
+ case eCSR_NEIGHBOR_ROAM_STATE_INIT:
+ NEIGHBOR_ROAM_DEBUG(pMac, LOG2,
+ FL("Currently in INIT state, "
+ "just set opportunistic threshold diff"));
+ pNeighborRoamInfo->cfgParams.nOpportunisticThresholdDiff =
+ nOpportunisticThresholdDiff;
+ pNeighborRoamInfo->currentOpportunisticThresholdDiff =
+ nOpportunisticThresholdDiff;
+ break;
+
+ default:
+ NEIGHBOR_ROAM_DEBUG(pMac, LOGE,
+ FL("Unexpected state %d returning failure"),
+ pNeighborRoamInfo->neighborRoamState);
+ cdf_status = CDF_STATUS_E_FAILURE;
+ break;
+ }
+ return cdf_status;
+}
+
+CDF_STATUS
+csr_neighbor_roam_set_roam_rescan_rssi_diff(tpAniSirGlobal pMac,
+ uint8_t sessionId,
+ uint8_t nRoamRescanRssiDiff)
+{
+ CDF_STATUS cdf_status = CDF_STATUS_SUCCESS;
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+
+ switch (pNeighborRoamInfo->neighborRoamState) {
+ case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED:
+ NEIGHBOR_ROAM_DEBUG(pMac, LOG2,
+ FL("Currently in CONNECTED state, "
+ "sending ROAM_SCAN_OFFLOAD_UPDATE_CFG."));
+ pNeighborRoamInfo->cfgParams.nRoamRescanRssiDiff =
+ nRoamRescanRssiDiff;
+ pNeighborRoamInfo->currentRoamRescanRssiDiff =
+ nRoamRescanRssiDiff;
+ csr_roam_offload_scan(pMac, sessionId,
+ ROAM_SCAN_OFFLOAD_UPDATE_CFG,
+ REASON_ROAM_RESCAN_RSSI_DIFF_CHANGED);
+ break;
+
+ case eCSR_NEIGHBOR_ROAM_STATE_INIT:
+ NEIGHBOR_ROAM_DEBUG(pMac, LOG2,
+ FL("Currently in INIT state, "
+ "just set rescan rssi diff"));
+ pNeighborRoamInfo->cfgParams.nRoamRescanRssiDiff =
+ nRoamRescanRssiDiff;
+ pNeighborRoamInfo->currentRoamRescanRssiDiff =
+ nRoamRescanRssiDiff;
+ break;
+
+ default:
+ NEIGHBOR_ROAM_DEBUG(pMac, LOGE,
+ FL("Unexpected state %d returning failure"),
+ pNeighborRoamInfo->neighborRoamState);
+ cdf_status = CDF_STATUS_E_FAILURE;
+ break;
+ }
+ return cdf_status;
+}
+
+CDF_STATUS
+csr_neighbor_roam_set_roam_bmiss_first_bcnt(tpAniSirGlobal pMac,
+ uint8_t sessionId,
+ uint8_t nRoamBmissFirstBcnt)
+{
+ CDF_STATUS cdf_status = CDF_STATUS_SUCCESS;
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+
+ switch (pNeighborRoamInfo->neighborRoamState) {
+ case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED:
+ NEIGHBOR_ROAM_DEBUG(pMac, LOG2,
+ FL("Currently in CONNECTED state, "
+ "sending ROAM_SCAN_OFFLOAD_UPDATE_CFG."));
+ pNeighborRoamInfo->cfgParams.nRoamBmissFirstBcnt =
+ nRoamBmissFirstBcnt;
+ pNeighborRoamInfo->currentRoamBmissFirstBcnt =
+ nRoamBmissFirstBcnt;
+
+ csr_roam_offload_scan(pMac,
+ sessionId,
+ ROAM_SCAN_OFFLOAD_UPDATE_CFG,
+ REASON_ROAM_BMISS_FIRST_BCNT_CHANGED);
+ break;
+
+ case eCSR_NEIGHBOR_ROAM_STATE_INIT:
+ NEIGHBOR_ROAM_DEBUG(pMac,
+ LOG2, FL
+ ("Currently in INIT state, safe to set roam rescan rssi diff"));
+ pNeighborRoamInfo->cfgParams.nRoamBmissFirstBcnt =
+ nRoamBmissFirstBcnt;
+ pNeighborRoamInfo->currentRoamBmissFirstBcnt =
+ nRoamBmissFirstBcnt;
+ break;
+
+ default:
+ NEIGHBOR_ROAM_DEBUG(pMac,
+ LOGE,
+ FL("Unexpected state %d returning failure"),
+ pNeighborRoamInfo->neighborRoamState);
+ cdf_status = CDF_STATUS_E_FAILURE;
+ break;
+ }
+ return cdf_status;
+}
+
+CDF_STATUS
+csr_neighbor_roam_set_roam_bmiss_final_bcnt(tpAniSirGlobal pMac,
+ uint8_t sessionId,
+ uint8_t nRoamBmissFinalBcnt)
+{
+ CDF_STATUS cdf_status = CDF_STATUS_SUCCESS;
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+
+ switch (pNeighborRoamInfo->neighborRoamState) {
+ case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED:
+ NEIGHBOR_ROAM_DEBUG(pMac, LOG2,
+ FL("Currently in CONNECTED state, "
+ "sending ROAM_SCAN_OFFLOAD_UPDATE_CFG."));
+ pNeighborRoamInfo->cfgParams.nRoamBmissFinalBcnt =
+ nRoamBmissFinalBcnt;
+ pNeighborRoamInfo->currentRoamBmissFinalBcnt =
+ nRoamBmissFinalBcnt;
+
+ csr_roam_offload_scan(pMac, sessionId,
+ ROAM_SCAN_OFFLOAD_UPDATE_CFG,
+ REASON_ROAM_BMISS_FINAL_BCNT_CHANGED);
+ break;
+
+ case eCSR_NEIGHBOR_ROAM_STATE_INIT:
+ NEIGHBOR_ROAM_DEBUG(pMac, LOG2,
+ FL("Currently in INIT state, "
+ "just set roam fianl bmiss count"));
+ pNeighborRoamInfo->cfgParams.nRoamBmissFinalBcnt =
+ nRoamBmissFinalBcnt;
+ pNeighborRoamInfo->currentRoamBmissFinalBcnt =
+ nRoamBmissFinalBcnt;
+ break;
+
+ default:
+ NEIGHBOR_ROAM_DEBUG(pMac,
+ LOGE,
+ FL("Unexpected state %d returning failure"),
+ pNeighborRoamInfo->neighborRoamState);
+ cdf_status = CDF_STATUS_E_FAILURE;
+ break;
+ }
+ return cdf_status;
+}
+
+CDF_STATUS
+csr_neighbor_roam_set_roam_beacon_rssi_weight(tpAniSirGlobal pMac,
+ uint8_t sessionId,
+ uint8_t nRoamBeaconRssiWeight)
+{
+ CDF_STATUS cdf_status = CDF_STATUS_SUCCESS;
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+
+ switch (pNeighborRoamInfo->neighborRoamState) {
+ case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED:
+ NEIGHBOR_ROAM_DEBUG(pMac, LOG2,
+ FL("Currently in CONNECTED state, "
+ "sending ROAM_SCAN_OFFLOAD_UPDATE_CFG."));
+ pNeighborRoamInfo->cfgParams.nRoamBeaconRssiWeight =
+ nRoamBeaconRssiWeight;
+ pNeighborRoamInfo->currentRoamBeaconRssiWeight =
+ nRoamBeaconRssiWeight;
+
+ csr_roam_offload_scan(pMac, sessionId,
+ ROAM_SCAN_OFFLOAD_UPDATE_CFG,
+ REASON_ROAM_BEACON_RSSI_WEIGHT_CHANGED);
+ break;
+
+ case eCSR_NEIGHBOR_ROAM_STATE_INIT:
+ NEIGHBOR_ROAM_DEBUG(pMac, LOG2,
+ FL("Currently in INIT state, "
+ "just set roam beacon rssi weight"));
+ pNeighborRoamInfo->cfgParams.nRoamBeaconRssiWeight =
+ nRoamBeaconRssiWeight;
+ pNeighborRoamInfo->currentRoamBeaconRssiWeight =
+ nRoamBeaconRssiWeight;
+ break;
+
+ default:
+ NEIGHBOR_ROAM_DEBUG(pMac,
+ LOGE,
+ FL("Unexpected state %d returning failure"),
+ pNeighborRoamInfo->neighborRoamState);
+ cdf_status = CDF_STATUS_E_FAILURE;
+ break;
+ }
+ return cdf_status;
+}
+
+/*CleanUP Routines*/
+static void csr_neighbor_roam_reset_channel_info(tpCsrNeighborRoamChannelInfo
+ rChInfo)
+{
+ if ((rChInfo->IAPPNeighborListReceived == false) &&
+ (rChInfo->currentChannelListInfo.numOfChannels)) {
+ rChInfo->currentChanIndex =
+ CSR_NEIGHBOR_ROAM_INVALID_CHANNEL_INDEX;
+ rChInfo->currentChannelListInfo.numOfChannels = 0;
+
+ if (rChInfo->currentChannelListInfo.ChannelList)
+ cdf_mem_free(rChInfo->currentChannelListInfo.
+ ChannelList);
+
+ rChInfo->currentChannelListInfo.ChannelList = NULL;
+ } else {
+ rChInfo->currentChanIndex = 0;
+ }
+}
+
+static void csr_neighbor_roam_reset_preauth_control_info(tpAniSirGlobal pMac,
+ uint8_t sessionId)
+{
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+
+#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR)
+ pNeighborRoamInfo->is11rAssoc = false;
+ /* Purge pre-auth fail list */
+ csr_neighbor_roam_purge_preauth_failed_list(pMac);
+#endif
+
+ pNeighborRoamInfo->FTRoamInfo.preauthRspPending = false;
+ pNeighborRoamInfo->FTRoamInfo.numPreAuthRetries = 0;
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ /* Do not free up the preauth done list here */
+ pNeighborRoamInfo->FTRoamInfo.currentNeighborRptRetryNum = 0;
+ pNeighborRoamInfo->FTRoamInfo.neighborRptPending = false;
+ pNeighborRoamInfo->FTRoamInfo.numBssFromNeighborReport = 0;
+ cdf_mem_zero(pNeighborRoamInfo->FTRoamInfo.neighboReportBssInfo,
+ sizeof(tCsrNeighborReportBssInfo) *
+ MAX_BSS_IN_NEIGHBOR_RPT);
+#endif
+ pNeighborRoamInfo->uOsRequestedHandoff = 0;
+ cdf_mem_zero(&pNeighborRoamInfo->handoffReqInfo,
+ sizeof(tCsrHandoffRequest));
+}
+
+/**
+ * csr_neighbor_roam_reset_connected_state_control_info()
+ *
+ * @mac_ctx: Pointer to Global MAC structure
+ * @sessionId : session id
+ *
+ * This function will reset the neighbor roam control info data structures.
+ * This function should be invoked whenever we move to CONNECTED state from
+ * any state other than INIT state
+ *
+ * Return: None
+ */
+void csr_neighbor_roam_reset_connected_state_control_info(tpAniSirGlobal pMac,
+ uint8_t sessionId)
+{
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+
+ csr_neighbor_roam_reset_channel_info(&pNeighborRoamInfo->roamChannelInfo);
+ csr_neighbor_roam_free_roamable_bss_list(pMac,
+ &pNeighborRoamInfo->roamableAPList);
+
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ /* Do not free up the preauth done list here */
+ pNeighborRoamInfo->FTRoamInfo.currentNeighborRptRetryNum = 0;
+ pNeighborRoamInfo->FTRoamInfo.neighborRptPending = false;
+ pNeighborRoamInfo->FTRoamInfo.numPreAuthRetries = 0;
+ pNeighborRoamInfo->FTRoamInfo.numBssFromNeighborReport = 0;
+ pNeighborRoamInfo->FTRoamInfo.preauthRspPending = 0;
+ cdf_mem_zero(pNeighborRoamInfo->FTRoamInfo.neighboReportBssInfo,
+ sizeof(tCsrNeighborReportBssInfo) *
+ MAX_BSS_IN_NEIGHBOR_RPT);
+#endif
+ pNeighborRoamInfo->uOsRequestedHandoff = 0;
+ cdf_mem_zero(&pNeighborRoamInfo->handoffReqInfo,
+ sizeof(tCsrHandoffRequest));
+}
+
+void csr_neighbor_roam_reset_report_scan_state_control_info(tpAniSirGlobal pMac,
+ uint8_t sessionId)
+{
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+
+ cdf_zero_macaddr(&pNeighborRoamInfo->currAPbssid);
+#ifdef FEATURE_WLAN_ESE
+ pNeighborRoamInfo->isESEAssoc = false;
+ pNeighborRoamInfo->isVOAdmitted = false;
+ pNeighborRoamInfo->MinQBssLoadRequired = 0;
+#endif
+
+ /* Purge roamable AP list */
+ csr_neighbor_roam_free_roamable_bss_list(pMac,
+ &pNeighborRoamInfo->roamableAPList);
+ return;
+}
+
+/**
+ * csr_neighbor_roam_reset_init_state_control_info()
+ *
+ * @mac_ctx: Pointer to Global MAC structure
+ * @sessionId : session id
+ *
+ * This function will reset the neighbor roam control info data structures.
+ * This function should be invoked whenever we move to CONNECTED state from
+ * INIT state
+ *
+ * Return: None
+ */
+void csr_neighbor_roam_reset_init_state_control_info(tpAniSirGlobal pMac,
+ uint8_t sessionId)
+{
+ csr_neighbor_roam_reset_connected_state_control_info(pMac, sessionId);
+
+ /* In addition to the above resets,
+ we should clear off the curAPBssId/Session ID in the timers */
+ csr_neighbor_roam_reset_report_scan_state_control_info(pMac, sessionId);
+}
+
+#ifdef WLAN_FEATURE_VOWIFI_11R
+/* ---------------------------------------------------------------------------
+
+ \fn csr_neighbor_roam_purge_preauth_fail_list
+
+ \brief This function empties the preauth fail list
+
+ \param pMac - The handle returned by mac_open.
+
+ \return VOID
+
+ ---------------------------------------------------------------------------*/
+void csr_neighbor_roam_purge_preauth_fail_list(tpAniSirGlobal pMac)
+{
+ uint8_t i;
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL;
+
+ NEIGHBOR_ROAM_DEBUG(pMac, LOGE, FL("Purging the preauth fail list"));
+ for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
+ pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[i];
+ while (pNeighborRoamInfo->FTRoamInfo.preAuthFailList.
+ numMACAddress) {
+ cdf_mem_zero(pNeighborRoamInfo->FTRoamInfo.
+ preAuthFailList.
+ macAddress[pNeighborRoamInfo->FTRoamInfo.
+ preAuthFailList.numMACAddress -
+ 1], sizeof(tSirMacAddr));
+ pNeighborRoamInfo->FTRoamInfo.preAuthFailList.
+ numMACAddress--;
+ }
+ }
+ return;
+}
+
+/**
+ * csr_neighbor_roam_add_preauth_fail() - add bssid to preauth failed list
+ * @mac_ctx: The handle returned by mac_open.
+ * @bssid: BSSID to be added to the preauth fail list
+ *
+ * This function adds the given BSSID to the Preauth fail list
+ *
+ * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_FAILURE otherwise
+ */
+CDF_STATUS csr_neighbor_roam_add_preauth_fail(tpAniSirGlobal mac_ctx,
+ uint8_t session_id,
+ tSirMacAddr bssid)
+{
+ uint8_t i = 0;
+ tpCsrNeighborRoamControlInfo neighbor_roam_info =
+ &mac_ctx->roam.neighborRoamInfo[session_id];
+ uint8_t num_mac_addr = neighbor_roam_info->FTRoamInfo.preAuthFailList.
+ numMACAddress;
+
+ NEIGHBOR_ROAM_DEBUG(mac_ctx, LOGE,
+ FL(" Added BSSID " MAC_ADDRESS_STR " to Preauth failed list"),
+ MAC_ADDR_ARRAY(bssid));
+
+ for (i = 0;
+ i < neighbor_roam_info->FTRoamInfo.preAuthFailList.numMACAddress;
+ i++) {
+ if (true == cdf_mem_compare(
+ neighbor_roam_info->FTRoamInfo.preAuthFailList.macAddress[i],
+ bssid, sizeof(tSirMacAddr))) {
+ sms_log(mac_ctx, LOGW, FL("BSSID "MAC_ADDRESS_STR" already present in preauth fail list"),
+ MAC_ADDR_ARRAY(bssid));
+ return CDF_STATUS_SUCCESS;
+ }
+ }
+
+ if ((num_mac_addr + 1) > MAX_NUM_PREAUTH_FAIL_LIST_ADDRESS) {
+ sms_log(mac_ctx, LOGE,
+ FL("Cannot add, preauth fail list is full."));
+ return CDF_STATUS_E_FAILURE;
+ }
+ cdf_mem_copy(neighbor_roam_info->FTRoamInfo.preAuthFailList.
+ macAddress[num_mac_addr], bssid, sizeof(tSirMacAddr));
+ neighbor_roam_info->FTRoamInfo.preAuthFailList.numMACAddress++;
+
+ return CDF_STATUS_SUCCESS;
+}
+
+/**
+ * csr_neighbor_roam_is_preauth_candidate()
+ *
+ * @mac_ctx: Pointer to Global MAC structure
+ * @bssId : BSSID of the candidate
+ *
+ * This function checks whether the given MAC address is already present
+ * in the preauth fail list and returns true/false accordingly
+ *
+ * Return: true if preauth candidate, false otherwise
+ */
+bool csr_neighbor_roam_is_preauth_candidate(tpAniSirGlobal pMac,
+ uint8_t sessionId, tSirMacAddr bssId)
+{
+ uint8_t i = 0;
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+
+ if (csr_roam_is_roam_offload_scan_enabled(pMac)) {
+ return true;
+ }
+ if (0 == pNeighborRoamInfo->FTRoamInfo.preAuthFailList.numMACAddress)
+ return true;
+
+ for (i = 0;
+ i < pNeighborRoamInfo->FTRoamInfo.preAuthFailList.numMACAddress;
+ i++) {
+ if (true ==
+ cdf_mem_compare(pNeighborRoamInfo->FTRoamInfo.
+ preAuthFailList.macAddress[i], bssId,
+ sizeof(tSirMacAddr))) {
+ NEIGHBOR_ROAM_DEBUG(pMac, LOGE,
+ FL("BSSID " MAC_ADDRESS_STR
+ " already present in preauth fail list"),
+ MAC_ADDR_ARRAY(bssId));
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/**
+ * csr_neighbor_roam_issue_preauth_req() - Send preauth request to first AP
+ * @mac_ctx: The handle returned by mac_open.
+ * @session_id: Session information
+ *
+ * This function issues preauth request to PE with the 1st AP entry in the
+ * roamable AP list
+ *
+ * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_FAILURE otherwise
+ */
+static CDF_STATUS csr_neighbor_roam_issue_preauth_req(tpAniSirGlobal mac_ctx,
+ uint8_t session_id)
+{
+ tpCsrNeighborRoamControlInfo neighbor_roam_info =
+ &mac_ctx->roam.neighborRoamInfo[session_id];
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ tpCsrNeighborRoamBSSInfo neighbor_bss_node;
+
+
+ if (false != neighbor_roam_info->FTRoamInfo.preauthRspPending) {
+ /* This must not be true here */
+ CDF_ASSERT(neighbor_roam_info->FTRoamInfo.preauthRspPending ==
+ false);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ /*
+ * Issue Preauth request to PE here.
+ * Need to issue the preauth request with the BSSID that is in the
+ * head of the roamable AP list. Parameters that should be passed are
+ * BSSID, Channel number and the neighborScanPeriod(probably). If
+ * roamableAPList gets empty, should transition to REPORT_SCAN state
+ */
+ neighbor_bss_node = csr_neighbor_roam_next_roamable_ap(mac_ctx,
+ &neighbor_roam_info->roamableAPList, NULL);
+
+ if (NULL == neighbor_bss_node) {
+ sms_log(mac_ctx, LOGW, FL("Roamable AP list is empty.. "));
+ return CDF_STATUS_E_FAILURE;
+ } else {
+ csr_neighbor_roam_send_lfr_metric_event(mac_ctx, session_id,
+ neighbor_bss_node->pBssDescription->bssId,
+ eCSR_ROAM_PREAUTH_INIT_NOTIFY);
+ status = csr_roam_enqueue_preauth(mac_ctx, session_id,
+ neighbor_bss_node->pBssDescription,
+ eCsrPerformPreauth, true);
+
+ sms_log(mac_ctx, LOG1,
+ FL("Before Pre-Auth: BSSID " MAC_ADDRESS_STR ", Ch:%d"),
+ MAC_ADDR_ARRAY(
+ neighbor_bss_node->pBssDescription->bssId),
+ (int)neighbor_bss_node->pBssDescription->channelId);
+
+ if (CDF_STATUS_SUCCESS != status) {
+ sms_log(mac_ctx, LOGE,
+ FL("Return failed preauth request status %d"),
+ status);
+ return status;
+ }
+ }
+
+ neighbor_roam_info->FTRoamInfo.preauthRspPending = true;
+
+ /* Increment the preauth retry count */
+ neighbor_roam_info->FTRoamInfo.numPreAuthRetries++;
+
+ /* Transition the state to preauthenticating */
+ CSR_NEIGHBOR_ROAM_STATE_TRANSITION
+ (mac_ctx, eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING,
+ session_id)
+
+ return status;
+}
+
+/**
+ * csr_neighbor_roam_preauth_rsp_handler() - handle preauth response
+ * @mac_ctx: The handle returned by mac_open.
+ * @session_id: SME session
+ * @lim_status: eSIR_SUCCESS/eSIR_FAILURE/eSIR_LIM_MAX_STA_REACHED_ERROR/
+ * eSIT_LIM_AUTH_RSP_TIMEOUT status from PE
+ *
+ * This function handle the Preauth response from PE
+ * Every preauth is allowed max 3 tries if it fails. If a bssid failed
+ * for more than MAX_TRIES, we will remove it from the list and try
+ * with the next node in the roamable AP list and add the BSSID to
+ * pre-auth failed list. If no more entries present in roamable AP list,
+ * transition to REPORT_SCAN state.
+ *
+ * Return: CDF_STATUS_SUCCESS on success (i.e. pre-auth processed),
+ * CDF_STATUS_E_FAILURE otherwise
+ */
+CDF_STATUS csr_neighbor_roam_preauth_rsp_handler(tpAniSirGlobal mac_ctx,
+ uint8_t session_id,
+ tSirRetStatus lim_status)
+{
+ tpCsrNeighborRoamControlInfo neighbor_roam_info =
+ &mac_ctx->roam.neighborRoamInfo[session_id];
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ CDF_STATUS preauth_processed = CDF_STATUS_SUCCESS;
+ tpCsrNeighborRoamBSSInfo preauth_rsp_node = NULL;
+
+ if (false == neighbor_roam_info->FTRoamInfo.preauthRspPending) {
+ /*
+ * This can happen when we disconnect immediately
+ * after sending a pre-auth request. During processing
+ * of the disconnect command, we would have reset
+ * preauthRspPending and transitioned to INIT state.
+ */
+ NEIGHBOR_ROAM_DEBUG(mac_ctx, LOGW,
+ FL("Unexpected pre-auth response in state %d"),
+ neighbor_roam_info->neighborRoamState);
+ preauth_processed = CDF_STATUS_E_FAILURE;
+ goto DEQ_PREAUTH;
+ }
+ /* We can receive it in these 2 states. */
+ if ((neighbor_roam_info->neighborRoamState !=
+ eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING)) {
+ NEIGHBOR_ROAM_DEBUG(mac_ctx, LOGW,
+ FL("Preauth response received in state %s"),
+ mac_trace_get_neighbour_roam_state
+ (neighbor_roam_info->neighborRoamState));
+ preauth_processed = CDF_STATUS_E_FAILURE;
+ goto DEQ_PREAUTH;
+ }
+
+ neighbor_roam_info->FTRoamInfo.preauthRspPending = false;
+
+ if (eSIR_SUCCESS == lim_status)
+ preauth_rsp_node =
+ csr_neighbor_roam_next_roamable_ap(
+ mac_ctx,
+ &neighbor_roam_info->roamableAPList,
+ NULL);
+ if ((eSIR_SUCCESS == lim_status) && (NULL != preauth_rsp_node)) {
+ NEIGHBOR_ROAM_DEBUG(mac_ctx, LOG1,
+ FL("Preauth completed successfully after %d tries"),
+ neighbor_roam_info->FTRoamInfo.numPreAuthRetries);
+ sms_log(mac_ctx, LOG1,
+ FL("After Pre-Auth: BSSID " MAC_ADDRESS_STR ", Ch:%d"),
+ MAC_ADDR_ARRAY(
+ preauth_rsp_node->pBssDescription->bssId),
+ (int)preauth_rsp_node->pBssDescription->channelId);
+
+ csr_neighbor_roam_send_lfr_metric_event(mac_ctx, session_id,
+ preauth_rsp_node->pBssDescription->bssId,
+ eCSR_ROAM_PREAUTH_STATUS_SUCCESS);
+ /*
+ * Preauth completed successfully. Insert the preauthenticated
+ * node to tail of preAuthDoneList.
+ */
+ csr_neighbor_roam_remove_roamable_ap_list_entry(mac_ctx,
+ &neighbor_roam_info->roamableAPList,
+ preauth_rsp_node);
+ csr_ll_insert_tail(
+ &neighbor_roam_info->FTRoamInfo.preAuthDoneList,
+ &preauth_rsp_node->List, LL_ACCESS_LOCK);
+
+ /* Pre-auth successful. Transition to PREAUTH Done state */
+ CSR_NEIGHBOR_ROAM_STATE_TRANSITION
+ (mac_ctx, eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE,
+ session_id)
+ neighbor_roam_info->FTRoamInfo.numPreAuthRetries = 0;
+
+ /*
+ * The caller of this function would start a timer and by
+ * the time it expires, supplicant should have provided
+ * the updated FTIEs to SME. So, when it expires, handoff
+ * will be triggered then.
+ */
+ } else {
+ tpCsrNeighborRoamBSSInfo neighbor_bss_node = NULL;
+ tListElem *entry;
+
+ sms_log(mac_ctx, LOGE,
+ FL("Preauth failed retry number %d, status = 0x%x"),
+ neighbor_roam_info->FTRoamInfo.numPreAuthRetries,
+ lim_status);
+
+ /*
+ * Preauth failed. Add the bssId to the preAuth failed list
+ * of MAC Address. Also remove the AP from roamable AP list.
+ */
+ if ((neighbor_roam_info->FTRoamInfo.numPreAuthRetries >=
+ CSR_NEIGHBOR_ROAM_MAX_NUM_PREAUTH_RETRIES) ||
+ (eSIR_LIM_MAX_STA_REACHED_ERROR == lim_status)) {
+ /*
+ * We are going to remove the node as it fails for
+ * more than MAX tries. Reset this count to 0
+ */
+ neighbor_roam_info->FTRoamInfo.numPreAuthRetries = 0;
+
+ /*
+ * The one in the head of the list should be one with
+ * which we issued pre-auth and failed
+ */
+ entry = csr_ll_remove_head(
+ &neighbor_roam_info->roamableAPList,
+ LL_ACCESS_LOCK);
+ if (!entry) {
+ sms_log(mac_ctx, LOGE,
+ FL("Preauth list is empty"));
+ goto NEXT_PREAUTH;
+ }
+ neighbor_bss_node = GET_BASE_ADDR(entry,
+ tCsrNeighborRoamBSSInfo,
+ List);
+ /*
+ * Add the BSSID to pre-auth fail list if
+ * it is not requested by HDD
+ */
+ if (!neighbor_roam_info->uOsRequestedHandoff)
+ status =
+ csr_neighbor_roam_add_preauth_fail(
+ mac_ctx, session_id,
+ neighbor_bss_node->
+ pBssDescription->bssId);
+ csr_neighbor_roam_send_lfr_metric_event(mac_ctx,
+ session_id,
+ neighbor_bss_node->pBssDescription->bssId,
+ eCSR_ROAM_PREAUTH_STATUS_FAILURE);
+ /* Now we can free this node */
+ csr_neighbor_roam_free_neighbor_roam_bss_node(
+ mac_ctx, neighbor_bss_node);
+ }
+NEXT_PREAUTH:
+ /* Issue preauth request for the same/next entry */
+ if (CDF_STATUS_SUCCESS == csr_neighbor_roam_issue_preauth_req(
+ mac_ctx, session_id))
+ goto DEQ_PREAUTH;
+
+ if (csr_roam_is_roam_offload_scan_enabled(mac_ctx)) {
+ if (neighbor_roam_info->uOsRequestedHandoff) {
+ neighbor_roam_info->uOsRequestedHandoff = 0;
+ csr_roam_offload_scan(mac_ctx, 0,
+ ROAM_SCAN_OFFLOAD_START,
+ REASON_PREAUTH_FAILED_FOR_ALL);
+ } else {
+ csr_roam_offload_scan(mac_ctx, 0,
+ ROAM_SCAN_OFFLOAD_RESTART,
+ REASON_PREAUTH_FAILED_FOR_ALL);
+ }
+ CSR_NEIGHBOR_ROAM_STATE_TRANSITION
+ (mac_ctx, eCSR_NEIGHBOR_ROAM_STATE_CONNECTED,
+ session_id);
+ }
+ }
+
+DEQ_PREAUTH:
+ csr_dequeue_roam_command(mac_ctx, eCsrPerformPreauth);
+ return preauth_processed;
+}
+#endif /* WLAN_FEATURE_NEIGHBOR_ROAMING */
+
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+/**
+ * csr_neighbor_roam_offload_update_preauth_list()
+ *
+ * @mac_ctx: Pointer to Global MAC structure
+ * @session_id: Session ID
+ * @roam_sync_ind_ptr: Roam offload sync Ind Info
+ *
+ * This function handles the RoamOffloadSynch and adds the
+ * roamed AP to the preauth done list
+ *
+ * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_FAILURE otherwise
+ */
+CDF_STATUS
+csr_neighbor_roam_offload_update_preauth_list(tpAniSirGlobal pMac,
+ roam_offload_synch_ind *roam_sync_ind_ptr, uint8_t session_id)
+{
+ tpCsrNeighborRoamControlInfo neighbor_roam_info_ptr =
+ &pMac->roam.neighborRoamInfo[session_id];
+ tpCsrNeighborRoamBSSInfo bss_info_ptr;
+ uint16_t bss_desc_len;
+
+ if (neighbor_roam_info_ptr->neighborRoamState !=
+ eCSR_NEIGHBOR_ROAM_STATE_CONNECTED) {
+ NEIGHBOR_ROAM_DEBUG(pMac, LOGW,
+ FL("LFR3:Roam Offload Synch Ind received in state %d"),
+ neighbor_roam_info_ptr->neighborRoamState);
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ bss_info_ptr = cdf_mem_malloc(sizeof(tCsrNeighborRoamBSSInfo));
+ if (NULL == bss_info_ptr) {
+ sms_log(pMac, LOGE,
+ FL("LFR3:Memory allocation for Neighbor Roam BSS Info failed"));
+ return CDF_STATUS_E_NOMEM;
+ }
+ bss_desc_len = roam_sync_ind_ptr->bss_desc_ptr->length +
+ sizeof(roam_sync_ind_ptr->bss_desc_ptr->length);
+ bss_info_ptr->pBssDescription = cdf_mem_malloc(bss_desc_len);
+ if (bss_info_ptr->pBssDescription != NULL) {
+ cdf_mem_copy(bss_info_ptr->pBssDescription,
+ roam_sync_ind_ptr->bss_desc_ptr,
+ bss_desc_len);
+ } else {
+ sms_log(pMac, LOGE,
+ FL("LFR3:Mem alloc for Neighbor Roam BSS Descriptor failed"));
+ cdf_mem_free(bss_info_ptr);
+ return CDF_STATUS_E_NOMEM;
+
+ }
+ csr_ll_insert_tail(&neighbor_roam_info_ptr->FTRoamInfo.preAuthDoneList,
+ &bss_info_ptr->List, LL_ACCESS_LOCK);
+
+ CSR_NEIGHBOR_ROAM_STATE_TRANSITION
+ (pMac, eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE, session_id)
+ neighbor_roam_info_ptr->FTRoamInfo.numPreAuthRetries = 0;
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ "LFR3:Entry added to Auth Done List");
+
+ return CDF_STATUS_SUCCESS;
+}
+#endif
+/**
+ * csr_neighbor_roam_prepare_scan_profile_filter()
+ *
+ * @mac_ctx: Pointer to Global MAC structure
+ * @session_id: Session ID
+ * @scan_filter: Populated scan filter based on the connected profile
+ *
+ * This function creates a scan filter based on the currently
+ * connected profile. Based on this filter, scan results are obtained
+ *
+ * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_FAILURE otherwise
+ */
+CDF_STATUS
+csr_neighbor_roam_prepare_scan_profile_filter(tpAniSirGlobal pMac,
+ tCsrScanResultFilter *pScanFilter,
+ uint8_t sessionId)
+{
+ tpCsrNeighborRoamControlInfo nbr_roam_info =
+ &pMac->roam.neighborRoamInfo[sessionId];
+ tCsrRoamConnectedProfile *pCurProfile =
+ &pMac->roam.roamSession[sessionId].connectedProfile;
+ uint8_t i = 0;
+ struct roam_ext_params *roam_params;
+ uint8_t num_ch = 0;
+
+ CDF_ASSERT(pScanFilter != NULL);
+ if (pScanFilter == NULL)
+ return CDF_STATUS_E_FAILURE;
+
+ cdf_mem_zero(pScanFilter, sizeof(tCsrScanResultFilter));
+ roam_params = &pMac->roam.configParam.roam_params;
+ /* We dont want to set BSSID based Filter */
+ pScanFilter->BSSIDs.numOfBSSIDs = 0;
+ pScanFilter->scan_filter_for_roam = 1;
+ /* only for HDD requested handoff fill in the BSSID in the filter */
+ if (nbr_roam_info->uOsRequestedHandoff) {
+ pScanFilter->BSSIDs.numOfBSSIDs = 1;
+ pScanFilter->BSSIDs.bssid =
+ cdf_mem_malloc(sizeof(tSirMacAddr) *
+ pScanFilter->BSSIDs.numOfBSSIDs);
+ if (NULL == pScanFilter->BSSIDs.bssid) {
+ sms_log(pMac, LOGE,
+ FL("Scan Filter BSSID mem alloc failed"));
+ return CDF_STATUS_E_NOMEM;
+ }
+
+ cdf_mem_zero(pScanFilter->BSSIDs.bssid,
+ sizeof(tSirMacAddr) *
+ pScanFilter->BSSIDs.numOfBSSIDs);
+
+ /* Populate the BSSID from handoff info received from HDD */
+ for (i = 0; i < pScanFilter->BSSIDs.numOfBSSIDs; i++) {
+ cdf_copy_macaddr(&pScanFilter->BSSIDs.bssid[i],
+ &nbr_roam_info->handoffReqInfo.bssid);
+ }
+ }
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ FL("No of Allowed SSID List:%d"),
+ roam_params->num_ssid_allowed_list);
+ if (roam_params->num_ssid_allowed_list) {
+ pScanFilter->SSIDs.numOfSSIDs =
+ roam_params->num_ssid_allowed_list;
+ pScanFilter->SSIDs.SSIDList =
+ cdf_mem_malloc(sizeof(tCsrSSIDInfo) *
+ pScanFilter->SSIDs.numOfSSIDs);
+ if (NULL == pScanFilter->SSIDs.SSIDList) {
+ sms_log(pMac, LOGE,
+ FL("Scan Filter SSID mem alloc failed"));
+ return CDF_STATUS_E_NOMEM;
+ }
+ for (i = 0; i < roam_params->num_ssid_allowed_list; i++) {
+ pScanFilter->SSIDs.SSIDList[i].handoffPermitted = 1;
+ pScanFilter->SSIDs.SSIDList[i].ssidHidden = 0;
+ cdf_mem_copy((void *)
+ pScanFilter->SSIDs.SSIDList[i].SSID.ssId,
+ roam_params->ssid_allowed_list[i].ssId,
+ roam_params->ssid_allowed_list[i].length);
+ pScanFilter->SSIDs.SSIDList[i].SSID.length =
+ roam_params->ssid_allowed_list[i].length;
+ }
+ } else {
+ /* Populate all the information from the connected profile */
+ pScanFilter->SSIDs.numOfSSIDs = 1;
+ pScanFilter->SSIDs.SSIDList =
+ cdf_mem_malloc(sizeof(tCsrSSIDInfo));
+ if (NULL == pScanFilter->SSIDs.SSIDList) {
+ sms_log(pMac, LOGE,
+ FL("Scan Filter SSID mem alloc failed"));
+ return CDF_STATUS_E_NOMEM;
+ }
+ pScanFilter->SSIDs.SSIDList->handoffPermitted = 1;
+ pScanFilter->SSIDs.SSIDList->ssidHidden = 0;
+ pScanFilter->SSIDs.SSIDList->SSID.length =
+ pCurProfile->SSID.length;
+ cdf_mem_copy((void *)pScanFilter->SSIDs.SSIDList->SSID.ssId,
+ (void *)pCurProfile->SSID.ssId,
+ pCurProfile->SSID.length);
+
+ NEIGHBOR_ROAM_DEBUG(pMac, LOG1,
+ FL("Filtering for SSID %.*s,length of SSID = %u"),
+ pScanFilter->SSIDs.SSIDList->SSID.length,
+ pScanFilter->SSIDs.SSIDList->SSID.ssId,
+ pScanFilter->SSIDs.SSIDList->SSID.length);
+ }
+ pScanFilter->authType.numEntries = 1;
+ pScanFilter->authType.authType[0] = pCurProfile->AuthType;
+
+ pScanFilter->EncryptionType.numEntries = 1; /* This must be 1 */
+ pScanFilter->EncryptionType.encryptionType[0] =
+ pCurProfile->EncryptionType;
+
+ pScanFilter->mcEncryptionType.numEntries = 1;
+ pScanFilter->mcEncryptionType.encryptionType[0] =
+ pCurProfile->mcEncryptionType;
+
+ pScanFilter->BSSType = pCurProfile->BSSType;
+
+ num_ch =
+ nbr_roam_info->roamChannelInfo.currentChannelListInfo.numOfChannels;
+ if (num_ch) {
+ /*
+ * We are intrested only in the scan results on channels we
+ * scanned
+ */
+ pScanFilter->ChannelInfo.numOfChannels = num_ch;
+ pScanFilter->ChannelInfo.ChannelList =
+ cdf_mem_malloc(num_ch * sizeof(uint8_t));
+ if (NULL == pScanFilter->ChannelInfo.ChannelList) {
+ sms_log(pMac, LOGE,
+ FL("Scan Filter Ch list mem alloc failed"));
+ cdf_mem_free(pScanFilter->SSIDs.SSIDList);
+ pScanFilter->SSIDs.SSIDList = NULL;
+ return CDF_STATUS_E_NOMEM;
+ }
+ for (i = 0; i < pScanFilter->ChannelInfo.numOfChannels; i++) {
+ pScanFilter->ChannelInfo.ChannelList[i] =
+ nbr_roam_info->roamChannelInfo.currentChannelListInfo.
+ ChannelList[i];
+ }
+ } else {
+ pScanFilter->ChannelInfo.numOfChannels = 0;
+ pScanFilter->ChannelInfo.ChannelList = NULL;
+ }
+
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ if (nbr_roam_info->is11rAssoc) {
+ /*
+ * MDIE should be added as a part of profile. This should be
+ * added as a part of filter as well
+ */
+ pScanFilter->MDID.mdiePresent = pCurProfile->MDID.mdiePresent;
+ pScanFilter->MDID.mobilityDomain =
+ pCurProfile->MDID.mobilityDomain;
+ }
+#endif
+
+#ifdef WLAN_FEATURE_11W
+ pScanFilter->MFPEnabled = pCurProfile->MFPEnabled;
+ pScanFilter->MFPRequired = pCurProfile->MFPRequired;
+ pScanFilter->MFPCapable = pCurProfile->MFPCapable;
+#endif
+ return CDF_STATUS_SUCCESS;
+}
+
+uint32_t csr_get_current_ap_rssi(tpAniSirGlobal pMac,
+ tScanResultHandle *pScanResultList,
+ uint8_t sessionId)
+{
+ tCsrScanResultInfo *pScanResult;
+ tpCsrNeighborRoamControlInfo nbr_roam_info =
+ &pMac->roam.neighborRoamInfo[sessionId];
+ /* We are setting this as default value to make sure we return this value,
+ when we do not see this AP in the scan result for some reason.However,it is
+ less likely that we are associated to an AP and do not see it in the scan list */
+ uint32_t CurrAPRssi = -125;
+
+ while (NULL !=
+ (pScanResult = csr_scan_result_get_next(pMac, *pScanResultList))) {
+ if (true ==
+ cdf_mem_compare(pScanResult->BssDescriptor.bssId,
+ nbr_roam_info->currAPbssid.bytes,
+ sizeof(tSirMacAddr))) {
+ /* We got a match with the currently associated AP.
+ * Capture the RSSI value and complete the while loop.
+ * The while loop is completed in order to make the current entry go back to NULL,
+ * and in the next while loop, it properly starts searching from the head of the list.
+ * TODO: Can also try setting the current entry directly to NULL as soon as we find the new AP*/
+
+ CurrAPRssi =
+ (int)pScanResult->BssDescriptor.rssi * (-1);
+
+ } else {
+ continue;
+ }
+ }
+
+ return CurrAPRssi;
+
+}
+
+/**
+ * csr_neighbor_roam_process_scan_results() - build roaming candidate list
+ *
+ * @mac_ctx: The handle returned by mac_open.
+ * @sessionid: Session information
+ * @scan_results_list: List obtained from csr_scan_get_result()
+ *
+ * This function applies various candidate checks like LFR, 11r, preauth, ESE
+ * and builds a roamable AP list. It applies age limit only if no suitable
+ * recent candidates are found.
+ *
+ * Output list is built in mac_ctx->roam.neighborRoamInfo[sessionid].
+ *
+ * Return: void
+ */
+
+static void
+csr_neighbor_roam_process_scan_results(tpAniSirGlobal mac_ctx,
+ uint8_t sessionid,
+ tScanResultHandle *scan_results_list)
+{
+ tCsrScanResultInfo *scan_result;
+ tpCsrNeighborRoamControlInfo n_roam_info =
+ &mac_ctx->roam.neighborRoamInfo[sessionid];
+ tpCsrNeighborRoamBSSInfo bss_info;
+ uint32_t cur_ap_rssi;
+ uint32_t age_ticks = 0;
+ uint32_t limit_ticks =
+ cdf_system_msecs_to_ticks(ROAM_AP_AGE_LIMIT_MS);
+ uint8_t num_candidates = 0;
+ uint8_t num_dropped = 0;
+ /*
+ * first iteration of scan list should consider
+ * age constraint for candidates
+ */
+ bool age_constraint = true;
+#ifdef FEATURE_WLAN_ESE
+ uint16_t qpresent;
+ uint16_t qavail;
+ bool voadmitted;
+#endif
+ /*
+ * Find out the Current AP RSSI and keep it handy to check if
+ * it is better than the RSSI of the AP which we are
+ * going to roam.If so, we are going to continue with the
+ * current AP.
+ */
+ cur_ap_rssi = csr_get_current_ap_rssi(mac_ctx, scan_results_list,
+ sessionid);
+
+ /*
+ * Expecting the scan result already to be in the sorted order based on
+ * RSSI. Based on the previous state we need to check whether the list
+ * should be sorted again taking neighbor score into consideration. If
+ * previous state is CFG_CHAN_LIST_SCAN, there should not be a neighbor
+ * score associated with any of the BSS. If the previous state is
+ * REPORT_QUERY, then there will be neighbor score for each of the APs.
+ * For now, let us take top of the list provided as it is by CSR Scan
+ * result API. Hence it is assumed that neighbor score and rssi score
+ * are in the same order. This will be taken care later.
+ */
+
+ do {
+ while (true) {
+ tSirBssDescription *descr;
+
+ scan_result = csr_scan_result_get_next(
+ mac_ctx, *scan_results_list);
+ if (NULL == scan_result)
+ break;
+ descr = &scan_result->BssDescriptor;
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ FL("Scan result: BSSID " MAC_ADDRESS_STR
+ " (Rssi %ld, Ch:%d)"),
+ MAC_ADDR_ARRAY(descr->bssId),
+ abs(descr->rssi), descr->channelId);
+
+ if (true == cdf_mem_compare(descr->bssId,
+ n_roam_info->currAPbssid.bytes,
+ sizeof(tSirMacAddr))) {
+ /*
+ * currently associated AP. Do not have this
+ * in the roamable AP list
+ */
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_INFO,
+ "SKIP-currently associated AP");
+ continue;
+ }
+#ifdef FEATURE_WLAN_LFR
+ /*
+ * In case of reassoc requested by upper layer, look
+ * for exact match of bssid & channel. csr cache might
+ * have duplicates
+ */
+ if ((n_roam_info->uOsRequestedHandoff) &&
+ ((false == cdf_mem_compare(descr->bssId,
+ n_roam_info->handoffReqInfo.bssid.bytes,
+ sizeof(tSirMacAddr)))
+ || (descr->channelId !=
+ n_roam_info->handoffReqInfo.channel))) {
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_INFO,
+ "SKIP-not a candidate AP for OS requested roam");
+ continue;
+ }
+#endif
+
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ if ((n_roam_info->is11rAssoc) &&
+ (!csr_neighbor_roam_is_preauth_candidate(mac_ctx,
+ sessionid, descr->bssId))) {
+ sms_log(mac_ctx, LOGE,
+ FL("BSSID present in pre-auth fail list.. Ignoring"));
+ continue;
+ }
+#endif /* WLAN_FEATURE_VOWIFI_11R */
+
+#ifdef FEATURE_WLAN_ESE
+ if (!csr_roam_is_roam_offload_scan_enabled(mac_ctx) &&
+ (n_roam_info->isESEAssoc) &&
+ !csr_neighbor_roam_is_preauth_candidate(mac_ctx,
+ sessionid, descr->bssId)) {
+ sms_log(mac_ctx, LOGE,
+ FL("BSSID present in pre-auth fail list.. Ignoring"));
+ continue;
+ }
+
+ qpresent = descr->QBSSLoad_present;
+ qavail = descr->QBSSLoad_avail;
+ voadmitted = n_roam_info->isVOAdmitted;
+ if (voadmitted)
+ sms_log(mac_ctx, LOG1,
+ FL("New AP QBSS present = %s, BW available = 0x%x, required = 0x%x"),
+ ((qpresent) ? "yes" : "no"), qavail,
+ n_roam_info->MinQBssLoadRequired);
+ if (voadmitted && qpresent &&
+ (qavail < n_roam_info->MinQBssLoadRequired)) {
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_INFO,
+ "BSSID : " MAC_ADDRESS_STR " has no bandwidth, ignoring",
+ MAC_ADDR_ARRAY(descr->bssId));
+ continue;
+ }
+ if (voadmitted && !qpresent) {
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_INFO,
+ "BSSID : " MAC_ADDRESS_STR " has no QBSS LOAD IE, ignoring",
+ MAC_ADDR_ARRAY(descr->bssId));
+ continue;
+ }
+#endif /* FEATURE_WLAN_ESE */
+
+#ifdef FEATURE_WLAN_LFR
+ /*
+ * If we are supporting legacy roaming, and
+ * if the candidate is on the "pre-auth failed" list,
+ * ignore it.
+ */
+ if (csr_roam_is_fast_roam_enabled(mac_ctx, sessionid) &&
+ !csr_neighbor_roam_is_preauth_candidate(mac_ctx,
+ sessionid, descr->bssId)) {
+ sms_log(mac_ctx, LOGE,
+ FL("BSSID present in pre-auth fail list.. Ignoring"));
+ continue;
+ }
+#endif /* FEATURE_WLAN_LFR */
+
+ /* check the age of the AP */
+ age_ticks = (uint32_t) cdf_mc_timer_get_system_ticks() -
+ descr->nReceivedTime;
+ if (age_constraint == true && age_ticks > limit_ticks) {
+ num_dropped++;
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_WARN,
+ FL("Old AP (probe rsp/beacon) skipped.")
+ );
+ continue;
+ }
+
+ /* Finished all checks, now add it to candidate list */
+ bss_info =
+ cdf_mem_malloc(sizeof(tCsrNeighborRoamBSSInfo));
+ if (NULL == bss_info) {
+ sms_log(mac_ctx, LOGE,
+ FL("Memory allocation failed. Ignored candidate."));
+ continue;
+ }
+ bss_info->pBssDescription =
+ cdf_mem_malloc(descr->length +
+ sizeof(descr->length));
+ if (bss_info->pBssDescription != NULL) {
+ cdf_mem_copy(bss_info->pBssDescription, descr,
+ descr->length + sizeof(descr->length));
+ } else {
+ sms_log(mac_ctx, LOGE,
+ FL("Memory allocation failed. Ignored candidate."));
+ cdf_mem_free(bss_info);
+ continue;
+ }
+ /*
+ * Assign some preference value for now. Need to
+ * calculate theactual score based on RSSI and neighbor
+ * AP score
+ */
+ bss_info->apPreferenceVal = 10;
+ num_candidates++;
+ csr_ll_insert_tail(&n_roam_info->roamableAPList,
+ &bss_info->List, LL_ACCESS_LOCK);
+ } /* end of while (csr_scan_result_get_next) */
+
+ /* if some candidates were found, then no need to repeat */
+ if (num_candidates)
+ break;
+ /*
+ * if age_constraint is already false, we have done two
+ * iterations and no candidate were found
+ */
+ if (age_constraint == false) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ "%s: No roam able candidates found",
+ __func__);
+ break;
+ }
+ /*
+ * if all candidates were dropped rescan the scan
+ * list but this time without age constraint.
+ */
+ age_constraint = false;
+ /* if no candidates were dropped no need to repeat */
+ } while (num_dropped);
+
+ /*
+ * Now we have all the scan results in our local list. Good time to free
+ * up the the list we got as a part of csrGetScanResult
+ */
+ csr_scan_result_purge(mac_ctx, *scan_results_list);
+}
+
+static CDF_STATUS csr_neighbor_roam_process_scan_complete(tpAniSirGlobal pMac,
+ uint8_t sessionId)
+{
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+ tCsrScanResultFilter scanFilter;
+ tScanResultHandle scanResult;
+ uint32_t tempVal = 0;
+ CDF_STATUS hstatus;
+
+ hstatus = csr_neighbor_roam_prepare_scan_profile_filter(pMac,
+ &scanFilter,
+ sessionId);
+ NEIGHBOR_ROAM_DEBUG(pMac, LOGW,
+ FL
+ ("11R/ESE/Other Association: Prepare scan to find neighbor AP filter status = %d"),
+ hstatus);
+ if (CDF_STATUS_SUCCESS != hstatus) {
+ sms_log(pMac, LOGE,
+ FL
+ ("Scan Filter preparation failed for Assoc type %d.. Bailing out.."),
+ tempVal);
+ return CDF_STATUS_E_FAILURE;
+ }
+ hstatus = csr_scan_get_result(pMac, &scanFilter, &scanResult);
+ if (hstatus != CDF_STATUS_SUCCESS) {
+ NEIGHBOR_ROAM_DEBUG(pMac, LOGE,
+ FL("Get Scan Result status code %d"),
+ hstatus);
+ }
+ /* Process the scan results and update roamable AP list */
+ csr_neighbor_roam_process_scan_results(pMac, sessionId, &scanResult);
+
+ /* Free the scan filter */
+ csr_free_scan_filter(pMac, &scanFilter);
+
+ tempVal = csr_ll_count(&pNeighborRoamInfo->roamableAPList);
+
+ if (tempVal) {
+ csr_neighbor_roam_trigger_handoff(pMac, sessionId);
+ return CDF_STATUS_SUCCESS;
+ }
+
+ if (csr_roam_is_roam_offload_scan_enabled(pMac)) {
+ if (pNeighborRoamInfo->uOsRequestedHandoff) {
+ csr_roam_offload_scan(pMac, sessionId,
+ ROAM_SCAN_OFFLOAD_START,
+ REASON_NO_CAND_FOUND_OR_NOT_ROAMING_NOW);
+ pNeighborRoamInfo->uOsRequestedHandoff = 0;
+ } else {
+ /* There is no candidate or We are not roaming Now.
+ * Inform the FW to restart Roam Offload Scan */
+ csr_roam_offload_scan(pMac, sessionId,
+ ROAM_SCAN_OFFLOAD_RESTART,
+ REASON_NO_CAND_FOUND_OR_NOT_ROAMING_NOW);
+ }
+ CSR_NEIGHBOR_ROAM_STATE_TRANSITION
+ (pMac, eCSR_NEIGHBOR_ROAM_STATE_CONNECTED, sessionId);
+ }
+ return CDF_STATUS_SUCCESS;
+
+}
+
+
+#if defined WLAN_FEATURE_VOWIFI_11R && defined WLAN_FEATURE_VOWIFI
+/**
+ * csr_neighbor_roam_channels_filter_by_current_band()
+ *
+ * @mac_ctx: Pointer to Global MAC structure
+ * @session_id: Session ID
+ * @input_ch_list: The input channel list
+ * @input_num_of_ch: The number of channels in input channel list
+ * @output_ch_list: The output channel list
+ * @output_num_of_ch: The number of channels in output channel list
+ * @merged_output_num_of_ch: The final number of channels in the
+ * output channel list.
+ *
+ * This function is used to filter out the channels based on the
+ * currently associated AP channel
+ *
+ * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_FAILURE otherwise
+ */
+CDF_STATUS csr_neighbor_roam_channels_filter_by_current_band(tpAniSirGlobal pMac,
+ uint8_t sessionId,
+ uint8_t *
+ pInputChannelList,
+ uint8_t
+ inputNumOfChannels,
+ uint8_t *
+ pOutputChannelList,
+ uint8_t *
+ pMergedOutputNumOfChannels)
+{
+ uint8_t i = 0;
+ uint8_t numChannels = 0;
+ uint8_t currAPoperationChannel =
+ pMac->roam.neighborRoamInfo[sessionId].currAPoperationChannel;
+ /* Check for NULL pointer */
+ if (!pInputChannelList)
+ return CDF_STATUS_E_INVAL;
+
+ /* Check for NULL pointer */
+ if (!pOutputChannelList)
+ return CDF_STATUS_E_INVAL;
+
+ if (inputNumOfChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ "%s: Wrong Number of Input Channels %d",
+ __func__, inputNumOfChannels);
+ return CDF_STATUS_E_INVAL;
+ }
+ for (i = 0; i < inputNumOfChannels; i++) {
+ if (get_rf_band(currAPoperationChannel) ==
+ get_rf_band(pInputChannelList[i])) {
+ pOutputChannelList[numChannels] = pInputChannelList[i];
+ numChannels++;
+ }
+ }
+
+ /* Return final number of channels */
+ *pMergedOutputNumOfChannels = numChannels;
+
+ return CDF_STATUS_SUCCESS;
+}
+
+/**
+ * csr_neighbor_roam_channels_filter_by_current_band()
+ *
+ * @mac_ctx: Pointer to Global MAC structure
+ * @session_id: Session ID
+ * @input_ch_list: The additional channels to merge in to the
+ * "merged" channels list.
+ * @input_num_of_ch: The number of additional channels.
+ * @output_ch_list: The place to put the "merged" channel list.
+ * @output_num_of_ch: The original number of channels in the
+ * "merged" channels list.
+ * @merged_output_num_of_ch: The final number of channels in the
+ * "merged" channel list.
+ *
+ * This function is used to merge two channel list.
+ * NB: If called with outputNumOfChannels == 0, this routines simply
+ * copies the input channel list to the output channel list. if number
+ * of merged channels are more than 100, num of channels set to 100
+ *
+ * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_FAILURE otherwise
+ */
+CDF_STATUS csr_neighbor_roam_merge_channel_lists(tpAniSirGlobal pMac,
+ uint8_t *pInputChannelList,
+ uint8_t inputNumOfChannels,
+ uint8_t *pOutputChannelList,
+ uint8_t outputNumOfChannels,
+ uint8_t *
+ pMergedOutputNumOfChannels)
+{
+ uint8_t i = 0;
+ uint8_t j = 0;
+ uint8_t numChannels = outputNumOfChannels;
+
+ /* Check for NULL pointer */
+ if (!pInputChannelList)
+ return CDF_STATUS_E_INVAL;
+
+ /* Check for NULL pointer */
+ if (!pOutputChannelList)
+ return CDF_STATUS_E_INVAL;
+
+ if (inputNumOfChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ "%s: Wrong Number of Input Channels %d",
+ __func__, inputNumOfChannels);
+ return CDF_STATUS_E_INVAL;
+ }
+ if (outputNumOfChannels >= WNI_CFG_VALID_CHANNEL_LIST_LEN) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ "%s: Wrong Number of Output Channels %d",
+ __func__, outputNumOfChannels);
+ return CDF_STATUS_E_INVAL;
+ }
+ /* Add the "new" channels in the input list to the end of the output list. */
+ for (i = 0; i < inputNumOfChannels; i++) {
+ for (j = 0; j < outputNumOfChannels; j++) {
+ if (pInputChannelList[i] == pOutputChannelList[j])
+ break;
+ }
+ if (j == outputNumOfChannels) {
+ if (pInputChannelList[i]) {
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_INFO,
+ "%s: [INFOLOG] Adding extra %d to Neighbor channel list",
+ __func__, pInputChannelList[i]);
+ pOutputChannelList[numChannels] =
+ pInputChannelList[i];
+ numChannels++;
+ }
+ }
+ if (numChannels >= WNI_CFG_VALID_CHANNEL_LIST_LEN) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ "%s: Merge Neighbor channel list reached Max "
+ "limit %d", __func__, numChannels);
+ break;
+ }
+ }
+
+ /* Return final number of channels */
+ *pMergedOutputNumOfChannels = numChannels;
+
+ return CDF_STATUS_SUCCESS;
+}
+
+/**
+ * csr_neighbor_roam_create_chan_list_from_neighbor_report()
+ *
+ * @mac_ctx: Pointer to Global MAC structure
+ * @session_id: Session ID
+ *
+ * This function is invoked when neighbor report is received for the
+ * neighbor request. Based on the channels present in the neighbor report,
+ * it generates channel list which will be used in REPORT_SCAN state to
+ * scan for these neighbor APs
+ *
+ * Return: CDF_STATUS_SUCCESS on success, CDF_STATUS_E_FAILURE otherwise
+ */
+CDF_STATUS csr_neighbor_roam_create_chan_list_from_neighbor_report(tpAniSirGlobal pMac,
+ uint8_t sessionId)
+{
+ tpRrmNeighborReportDesc pNeighborBssDesc;
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+ uint8_t numChannels = 0;
+ uint8_t i = 0;
+ uint8_t channelList[MAX_BSS_IN_NEIGHBOR_RPT];
+ uint8_t mergedOutputNumOfChannels = 0;
+
+ /* This should always start from 0 whenever we create a channel list out of neighbor AP list */
+ pNeighborRoamInfo->FTRoamInfo.numBssFromNeighborReport = 0;
+
+ pNeighborBssDesc = sme_rrm_get_first_bss_entry_from_neighbor_cache(pMac);
+
+ while (pNeighborBssDesc) {
+ if (pNeighborRoamInfo->FTRoamInfo.numBssFromNeighborReport >=
+ MAX_BSS_IN_NEIGHBOR_RPT)
+ break;
+
+ /* Update the neighbor BSS Info in the 11r FT Roam Info */
+ pNeighborRoamInfo->FTRoamInfo.
+ neighboReportBssInfo[pNeighborRoamInfo->FTRoamInfo.
+ numBssFromNeighborReport].channelNum =
+ pNeighborBssDesc->pNeighborBssDescription->channel;
+ pNeighborRoamInfo->FTRoamInfo.
+ neighboReportBssInfo[pNeighborRoamInfo->FTRoamInfo.
+ numBssFromNeighborReport].
+ neighborScore = (uint8_t) pNeighborBssDesc->roamScore;
+ cdf_mem_copy(pNeighborRoamInfo->FTRoamInfo.
+ neighboReportBssInfo[pNeighborRoamInfo->FTRoamInfo.
+ numBssFromNeighborReport].
+ neighborBssId,
+ pNeighborBssDesc->pNeighborBssDescription->bssId,
+ sizeof(tSirMacAddr));
+ pNeighborRoamInfo->FTRoamInfo.numBssFromNeighborReport++;
+
+ /* Saving the channel list non-redundantly */
+ for (i = 0; (i < numChannels && i < MAX_BSS_IN_NEIGHBOR_RPT);
+ i++) {
+ if (pNeighborBssDesc->pNeighborBssDescription->
+ channel == channelList[i])
+ break;
+ }
+
+ if (i == numChannels) {
+ if (pNeighborBssDesc->pNeighborBssDescription->channel) {
+ if (CSR_IS_ROAM_INTRA_BAND_ENABLED(pMac)) {
+ /* Make sure to add only if its the same band */
+ if (get_rf_band
+ (pNeighborRoamInfo->
+ currAPoperationChannel) ==
+ get_rf_band(pNeighborBssDesc->
+ pNeighborBssDescription->
+ channel)) {
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_INFO,
+ "%s: [INFOLOG] Adding %d to Neighbor channel list (Same band)\n",
+ __func__,
+ pNeighborBssDesc->
+ pNeighborBssDescription->
+ channel);
+ channelList[numChannels] =
+ pNeighborBssDesc->
+ pNeighborBssDescription->
+ channel;
+ numChannels++;
+ }
+ } else {
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_INFO,
+ "%s: [INFOLOG] Adding %d to Neighbor channel list\n",
+ __func__,
+ pNeighborBssDesc->
+ pNeighborBssDescription->
+ channel);
+ channelList[numChannels] =
+ pNeighborBssDesc->
+ pNeighborBssDescription->channel;
+ numChannels++;
+ }
+ }
+ }
+
+ pNeighborBssDesc =
+ sme_rrm_get_next_bss_entry_from_neighbor_cache(pMac,
+ pNeighborBssDesc);
+ }
+
+ if (pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.
+ ChannelList) {
+ cdf_mem_free(pNeighborRoamInfo->roamChannelInfo.
+ currentChannelListInfo.ChannelList);
+ }
+
+ pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList =
+ NULL;
+ pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.
+ numOfChannels = 0;
+ /* Store the obtained channel list to the Neighbor Control data structure */
+ if (numChannels)
+ pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.
+ ChannelList =
+ cdf_mem_malloc((numChannels) * sizeof(uint8_t));
+ if (NULL ==
+ pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.
+ ChannelList) {
+ sms_log(pMac, LOGE,
+ FL
+ ("Memory allocation for Channel list failed.. TL event ignored"));
+ return CDF_STATUS_E_NOMEM;
+ }
+
+ cdf_mem_copy(pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.
+ ChannelList, channelList, (numChannels) * sizeof(uint8_t));
+ pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.
+ numOfChannels = numChannels;
+ /*
+ * Create a Union of occupied channel list learnt by the DUT along with the Neighbor
+ * report Channels. This increases the chances of the DUT to get a candidate AP while
+ * roaming even if the Neighbor Report is not able to provide sufficient information.
+ * */
+ if (pMac->scan.occupiedChannels[sessionId].numChannels) {
+ csr_neighbor_roam_merge_channel_lists(pMac,
+ &pMac->scan.
+ occupiedChannels[sessionId].
+ channelList[0],
+ pMac->scan.
+ occupiedChannels[sessionId].
+ numChannels,
+ &pNeighborRoamInfo->
+ roamChannelInfo.
+ currentChannelListInfo.
+ ChannelList[0],
+ pNeighborRoamInfo->
+ roamChannelInfo.
+ currentChannelListInfo.
+ numOfChannels,
+ &mergedOutputNumOfChannels);
+ pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.
+ numOfChannels = mergedOutputNumOfChannels;
+
+ }
+ /*Indicate the firmware about the update only if any new channels are added.
+ * Otherwise, the firmware would already be knowing the non-IAPPneighborlist
+ * channels. There is no need to update.*/
+ if (numChannels) {
+ sms_log(pMac, LOG1,
+ FL("IAPP Neighbor list callback received as expected"
+ "in state %s."),
+ mac_trace_get_neighbour_roam_state(pNeighborRoamInfo->
+ neighborRoamState));
+ pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived =
+ true;
+ if (csr_roam_is_roam_offload_scan_enabled(pMac)) {
+ csr_roam_offload_scan(pMac, sessionId,
+ ROAM_SCAN_OFFLOAD_UPDATE_CFG,
+ REASON_CHANNEL_LIST_CHANGED);
+ }
+ }
+ pNeighborRoamInfo->roamChannelInfo.currentChanIndex = 0;
+
+ return CDF_STATUS_SUCCESS;
+}
+#endif /* WLAN_FEATURE_VOWIFI_11R */
+
+#ifdef FEATURE_WLAN_LFR
+/**
+ * csr_neighbor_roam_is_ssid_and_security_match() - to match ssid/security
+ * @pMac: Pointer to mac context
+ * @pCurProfile: pointer to current roam profile
+ * @pBssDesc: pointer to bss description
+ * @pIes: pointer to local ies
+ *
+ * This routine will be called to see if SSID and security parameters
+ * are matching.
+ *
+ * Return: bool
+ */
+bool csr_neighbor_roam_is_ssid_and_security_match(tpAniSirGlobal pMac,
+ tCsrRoamConnectedProfile *pCurProfile,
+ tSirBssDescription *pBssDesc, tDot11fBeaconIEs *pIes)
+{
+ tCsrAuthList authType;
+ tCsrEncryptionList uCEncryptionType;
+ tCsrEncryptionList mCEncryptionType;
+ bool fMatch = false;
+
+ authType.numEntries = 1;
+ authType.authType[0] = pCurProfile->AuthType;
+ uCEncryptionType.numEntries = 1;
+ uCEncryptionType.encryptionType[0] = pCurProfile->EncryptionType;
+ mCEncryptionType.numEntries = 1;
+ mCEncryptionType.encryptionType[0] = pCurProfile->mcEncryptionType;
+
+ /* Again, treat missing pIes as a non-match. */
+ if (!pIes)
+ return false;
+
+ /* Treat a missing SSID as a non-match. */
+ if (!pIes->SSID.present)
+ return false;
+
+ fMatch = csr_is_ssid_match(pMac,
+ (void *)pCurProfile->SSID.ssId,
+ pCurProfile->SSID.length,
+ pIes->SSID.ssid,
+ pIes->SSID.num_ssid, true);
+ if (true == fMatch) {
+ /*
+ * for now we are sending NULL for all PMF related filter
+ * parameters during roam to the neighbor AP because
+ * so far 80211W spec doesn't specify anything about
+ * roaming scenario.
+ *
+ * Once roaming scenario is defined, we should re-visit
+ * this section and remove this comment.
+ */
+ fMatch = csr_is_security_match(pMac, &authType,
+ &uCEncryptionType,
+ &mCEncryptionType, NULL,
+ NULL, NULL, pBssDesc,
+ pIes, NULL, NULL, NULL);
+ return fMatch;
+ } else {
+ return fMatch;
+ }
+
+}
+
+bool csr_neighbor_roam_is_new_connected_profile(tpAniSirGlobal pMac,
+ uint8_t sessionId)
+{
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+ tCsrRoamConnectedProfile *pCurrProfile = NULL;
+ tCsrRoamConnectedProfile *pPrevProfile = NULL;
+ tDot11fBeaconIEs *pIes = NULL;
+ tSirBssDescription *pBssDesc = NULL;
+ bool fNew = true;
+
+ if (!(pMac->roam.roamSession && CSR_IS_SESSION_VALID(pMac, sessionId))) {
+ return fNew;
+ }
+
+ pCurrProfile = &pMac->roam.roamSession[sessionId].connectedProfile;
+ if (!pCurrProfile) {
+ return fNew;
+ }
+
+ pPrevProfile = &pNeighborRoamInfo->prevConnProfile;
+ if (!pPrevProfile) {
+ return fNew;
+ }
+
+ pBssDesc = pPrevProfile->pBssDesc;
+ if (pBssDesc) {
+ if (CDF_IS_STATUS_SUCCESS(
+ csr_get_parsed_bss_description_ies(pMac, pBssDesc, &pIes))
+ && csr_neighbor_roam_is_ssid_and_security_match(pMac,
+ pCurrProfile, pBssDesc, pIes)) {
+ fNew = false;
+ }
+ if (pIes) {
+ cdf_mem_free(pIes);
+ }
+ }
+
+ if (fNew) {
+ sms_log(pMac, LOG1,
+ FL("Prev roam profile did not match current"));
+ } else {
+ sms_log(pMac, LOG1, FL("Prev roam profile matches current"));
+ }
+
+ return fNew;
+}
+
+bool csr_neighbor_roam_connected_profile_match(tpAniSirGlobal pMac,
+ uint8_t sessionId,
+ tCsrScanResult *pResult,
+ tDot11fBeaconIEs *pIes)
+{
+ tCsrRoamConnectedProfile *pCurProfile = NULL;
+ tSirBssDescription *pBssDesc = &pResult->Result.BssDescriptor;
+
+ if (!(pMac->roam.roamSession && CSR_IS_SESSION_VALID(pMac, sessionId))) {
+ return false;
+ }
+
+ pCurProfile = &pMac->roam.roamSession[sessionId].connectedProfile;
+
+ if (!pCurProfile) {
+ return false;
+ }
+
+ return csr_neighbor_roam_is_ssid_and_security_match(pMac, pCurProfile,
+ pBssDesc, pIes);
+}
+
+/**
+ * csr_neighbor_roam_prepare_non_occupied_channel_list() - prepare non-occup CL
+ * @pMac: The handle returned by mac_open
+ * @pInputChannelList: The default channels list
+ * @numOfChannels: The number of channels in the default channels list
+ * @pOutputChannelList: The place to put the non-occupied channel list
+ * @pOutputNumOfChannels: Number of channels in the non-occupied channel list
+ *
+ * This function is used to prepare a channel list that is derived from
+ * the list of valid channels and does not include those in the occupied list
+ *
+ * Return CDF_STATUS
+ */
+CDF_STATUS
+csr_neighbor_roam_prepare_non_occupied_channel_list(tpAniSirGlobal pMac,
+ uint8_t sessionId, uint8_t *pInputChannelList,
+ uint8_t numOfChannels, uint8_t *pOutputChannelList,
+ uint8_t *pOutputNumOfChannels)
+{
+ uint8_t i = 0;
+ uint8_t outputNumOfChannels = 0;
+ uint8_t numOccupiedChannels =
+ pMac->scan.occupiedChannels[sessionId].numChannels;
+ uint8_t *pOccupiedChannelList =
+ pMac->scan.occupiedChannels[sessionId].channelList;
+
+ for (i = 0; i < numOfChannels; i++) {
+ if (csr_is_channel_present_in_list
+ (pOccupiedChannelList, numOccupiedChannels,
+ pInputChannelList[i]))
+ continue;
+ /*
+ * DFS channel will be added in the list only when the
+ * DFS Roaming scan flag is enabled
+ */
+ if (CDS_IS_DFS_CH(pInputChannelList[i])) {
+ if (CSR_ROAMING_DFS_CHANNEL_DISABLED !=
+ pMac->roam.configParam.allowDFSChannelRoam) {
+ pOutputChannelList[outputNumOfChannels++] =
+ pInputChannelList[i];
+ }
+ } else {
+ pOutputChannelList[outputNumOfChannels++] =
+ pInputChannelList[i];
+ }
+ }
+
+ sms_log(pMac, LOG2,
+ FL("Number of channels in the valid channel list=%d; "
+ "Number of channels in the non-occupied list list=%d"),
+ numOfChannels, outputNumOfChannels);
+
+ /* Return the number of channels */
+ *pOutputNumOfChannels = outputNumOfChannels;
+ return CDF_STATUS_SUCCESS;
+}
+#endif /* FEATURE_WLAN_LFR */
+
+/**
+ * csr_roam_reset_roam_params - API to reset the roaming parameters
+ * @mac_ctx: Pointer to the global MAC structure
+ *
+ * The BSSID blacklist should not be cleared since it has to
+ * be used across connections. These parameters will be cleared
+ * and sent to firmware with with the roaming STOP command.
+ *
+ * Return: VOID
+ */
+void csr_roam_reset_roam_params(tpAniSirGlobal mac_ctx)
+{
+ struct roam_ext_params *roam_params = NULL;
+
+ /*
+ * clear all the whitelist parameters and remaining
+ * needs to be retained across connections.
+ */
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ FL("Roaming parameters are reset"));
+ roam_params = &mac_ctx->roam.configParam.roam_params;
+ roam_params->num_ssid_allowed_list = 0;
+ cdf_mem_set(&roam_params->ssid_allowed_list, 0,
+ sizeof(tSirMacSSid) * MAX_SSID_ALLOWED_LIST);
+}
+
+/**
+ * csr_neighbor_roam_indicate_disconnect() - To indicate disconnect
+ * @pMac: The handle returned by mac_open
+ * @sessionId: CSR session id that got disconnected
+ *
+ * This function is called by CSR as soon as the station disconnects
+ * from the AP. This function does the necessary cleanup of neighbor roam
+ * data structures. Neighbor roam state transitions to INIT state whenever
+ * this function is called except if the current state is REASSOCIATING
+ *
+ * Return: CDF_STATUS
+ */
+CDF_STATUS csr_neighbor_roam_indicate_disconnect(tpAniSirGlobal pMac,
+ uint8_t sessionId)
+{
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+#ifdef FEATURE_WLAN_LFR
+ tCsrRoamConnectedProfile *pPrevProfile =
+ &pNeighborRoamInfo->prevConnProfile;
+#endif
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+ tCsrRoamSession *roam_session = NULL;
+
+ if (NULL == pSession) {
+ sms_log(pMac, LOGE, FL("pSession is NULL"));
+ return CDF_STATUS_E_FAILURE;
+ }
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ FL("Disconn ind on session %d in state %d from bss :"
+ MAC_ADDRESS_STR), sessionId,
+ pNeighborRoamInfo->neighborRoamState,
+ MAC_ADDR_ARRAY(pSession->connectedProfile.bssid.bytes));
+#ifdef FEATURE_WLAN_LFR
+ /*
+ * Free the current previous profile and move
+ * the current profile to prev profile.
+ */
+ csr_roam_free_connect_profile(pMac, pPrevProfile);
+ csr_roam_copy_connect_profile(pMac, sessionId, pPrevProfile);
+#endif
+ /*
+ * clear the roaming parameters that are per connection.
+ * For a new connection, they have to be programmed again.
+ */
+ if (!csr_neighbor_middle_of_roaming((tHalHandle)pMac, sessionId))
+ csr_roam_reset_roam_params(pMac);
+ if (NULL != pSession) {
+ roam_session = &pMac->roam.roamSession[sessionId];
+ if (NULL != pSession->pCurRoamProfile && (CDF_STA_MODE !=
+ roam_session->pCurRoamProfile->csrPersona)) {
+ sms_log(pMac, LOGE,
+ FL("Ignore disconn ind rcvd from nonSTA persona"
+ "sessionId: %d, csrPersonna %d"),
+ sessionId,
+ (int)roam_session->pCurRoamProfile->csrPersona);
+ return CDF_STATUS_SUCCESS;
+ }
+#ifdef FEATURE_WLAN_ESE
+ if (pSession->connectedProfile.isESEAssoc) {
+ cdf_mem_copy(&pSession->prevApSSID,
+ &pSession->connectedProfile.SSID,
+ sizeof(tSirMacSSid));
+ cdf_copy_macaddr(&pSession->prevApBssid,
+ &pSession->connectedProfile.bssid);
+ pSession->prevOpChannel =
+ pSession->connectedProfile.operationChannel;
+ pSession->isPrevApInfoValid = true;
+ pSession->roamTS1 = cdf_mc_timer_get_system_time();
+ }
+#endif
+ }
+
+ switch (pNeighborRoamInfo->neighborRoamState) {
+ case eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING:
+ /*
+ * Stop scan and neighbor refresh timers.
+ * These are indeed not required when we'r in reassoc state.
+ */
+ if (!CSR_IS_ROAM_SUBSTATE_DISASSOC_HO(pMac, sessionId)) {
+ /*
+ * Disconnect indication during Disassoc Handoff
+ * sub-state is received when we are trying to
+ * disconnect with the old AP during roam.
+ * BUT, if receive a disconnect indication outside of
+ * Disassoc Handoff sub-state, then it means that
+ * this is a genuine disconnect and we need to clean up.
+ * Otherwise, we will be stuck in reassoc state which'll
+ * in-turn block scans.
+ */
+ CSR_NEIGHBOR_ROAM_STATE_TRANSITION
+ (pMac, eCSR_NEIGHBOR_ROAM_STATE_INIT,
+ sessionId);
+ pNeighborRoamInfo->roamChannelInfo.
+ IAPPNeighborListReceived = false;
+ }
+ break;
+
+ case eCSR_NEIGHBOR_ROAM_STATE_INIT:
+ csr_neighbor_roam_reset_init_state_control_info(pMac,
+ sessionId);
+ break;
+
+ case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED:
+ CSR_NEIGHBOR_ROAM_STATE_TRANSITION(
+ pMac, eCSR_NEIGHBOR_ROAM_STATE_INIT, sessionId)
+ pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived =
+ false;
+ csr_neighbor_roam_reset_connected_state_control_info(pMac,
+ sessionId);
+ break;
+
+ case eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE:
+ /* Stop pre-auth to reassoc interval timer */
+ cdf_mc_timer_stop(&pSession->ftSmeContext.
+ preAuthReassocIntvlTimer);
+ case eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING:
+ CSR_NEIGHBOR_ROAM_STATE_TRANSITION(
+ pMac, eCSR_NEIGHBOR_ROAM_STATE_INIT, sessionId)
+ pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived =
+ false;
+ csr_neighbor_roam_reset_preauth_control_info(pMac, sessionId);
+ csr_neighbor_roam_reset_report_scan_state_control_info(pMac,
+ sessionId);
+ break;
+ default:
+ NEIGHBOR_ROAM_DEBUG(pMac, LOGW, FL("Received disconnect event"
+ "in state %s "),
+ mac_trace_get_neighbour_roam_state(
+ pNeighborRoamInfo->neighborRoamState));
+ NEIGHBOR_ROAM_DEBUG(pMac, LOGW, FL("Transit to INIT state"));
+ CSR_NEIGHBOR_ROAM_STATE_TRANSITION
+ (pMac, eCSR_NEIGHBOR_ROAM_STATE_INIT, sessionId)
+ pNeighborRoamInfo->roamChannelInfo.
+ IAPPNeighborListReceived = false;
+ break;
+ }
+ /*Inform the Firmware to STOP Scanning as the host has a disconnect. */
+ if (csr_roam_is_sta_mode(pMac, sessionId)) {
+ csr_roam_offload_scan(pMac, sessionId, ROAM_SCAN_OFFLOAD_STOP,
+ REASON_DISCONNECTED);
+ }
+
+ return CDF_STATUS_SUCCESS;
+}
+
+/**
+ * csr_neighbor_roam_info_ctx_init() - Initialize neighbor roam struct
+ * @pMac: mac context
+ * @session_id: Session Id
+ *
+ * This initializes all the necessary data structures related to the
+ * associated AP.
+ *
+ * Return: CDF status
+ */
+static void csr_neighbor_roam_info_ctx_init(
+ tpAniSirGlobal pMac,
+ uint8_t session_id)
+{
+ tpCsrNeighborRoamControlInfo ngbr_roam_info =
+ &pMac->roam.neighborRoamInfo[session_id];
+ tCsrRoamSession *session = &pMac->roam.roamSession[session_id];
+
+#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR)
+ int init_ft_flag = false;
+#endif
+
+#ifdef FEATURE_WLAN_LFR
+ /*
+ * Initialize the occupied list ONLY if we are
+ * transitioning from INIT state to CONNECTED state.
+ */
+ if (eCSR_NEIGHBOR_ROAM_STATE_INIT ==
+ ngbr_roam_info->neighborRoamState)
+ csr_init_occupied_channels_list(pMac, session_id);
+#endif
+ CSR_NEIGHBOR_ROAM_STATE_TRANSITION
+ (pMac, eCSR_NEIGHBOR_ROAM_STATE_CONNECTED, session_id);
+
+ cdf_copy_macaddr(&ngbr_roam_info->currAPbssid,
+ &session->connectedProfile.bssid);
+ ngbr_roam_info->currAPoperationChannel =
+ session->connectedProfile.operationChannel;
+ ngbr_roam_info->currentNeighborLookupThreshold =
+ ngbr_roam_info->cfgParams.neighborLookupThreshold;
+ ngbr_roam_info->currentOpportunisticThresholdDiff =
+ ngbr_roam_info->cfgParams.nOpportunisticThresholdDiff;
+ ngbr_roam_info->currentRoamRescanRssiDiff =
+ ngbr_roam_info->cfgParams.nRoamRescanRssiDiff;
+ ngbr_roam_info->currentRoamBmissFirstBcnt =
+ ngbr_roam_info->cfgParams.nRoamBmissFirstBcnt;
+ ngbr_roam_info->currentRoamBmissFinalBcnt =
+ ngbr_roam_info->cfgParams.nRoamBmissFinalBcnt;
+ ngbr_roam_info->currentRoamBeaconRssiWeight =
+ ngbr_roam_info->cfgParams.nRoamBeaconRssiWeight;
+
+#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR)
+ /**
+ * Now we can clear the preauthDone that
+ * was saved as we are connected afresh */
+ csr_neighbor_roam_free_roamable_bss_list(pMac,
+ &ngbr_roam_info->FTRoamInfo.preAuthDoneList);
+#endif
+
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ /* Based on the auth scheme tell if we are 11r */
+ if (csr_is_auth_type11r
+ (session->connectedProfile.AuthType,
+ session->connectedProfile.MDID.mdiePresent)) {
+ if (pMac->roam.configParam.isFastTransitionEnabled)
+ init_ft_flag = true;
+ ngbr_roam_info->is11rAssoc = true;
+ } else
+ ngbr_roam_info->is11rAssoc = false;
+ NEIGHBOR_ROAM_DEBUG(pMac, LOG2, FL("11rAssoc is = %d"),
+ ngbr_roam_info->is11rAssoc);
+#endif
+
+#ifdef FEATURE_WLAN_ESE
+ /* Based on the auth scheme tell if we are 11r */
+ if (session->connectedProfile.isESEAssoc) {
+ if (pMac->roam.configParam.isFastTransitionEnabled)
+ init_ft_flag = true;
+ ngbr_roam_info->isESEAssoc = true;
+ } else
+ ngbr_roam_info->isESEAssoc = false;
+ NEIGHBOR_ROAM_DEBUG(pMac, LOG2,
+ FL("isESEAssoc is = %d ft = %d"),
+ ngbr_roam_info->isESEAssoc, init_ft_flag);
+#endif
+#ifdef FEATURE_WLAN_LFR
+ /* If "Legacy Fast Roaming" is enabled */
+ if (csr_roam_is_fast_roam_enabled(pMac, session_id))
+ init_ft_flag = true;
+#endif
+#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR)
+ if (init_ft_flag == false)
+ return;
+ /* Initialize all the data structures needed for the 11r FT Preauth */
+ ngbr_roam_info->FTRoamInfo.currentNeighborRptRetryNum = 0;
+ csr_neighbor_roam_purge_preauth_failed_list(pMac);
+ if (!cds_is_multiple_active_sta_sessions() &&
+ csr_roam_is_roam_offload_scan_enabled(pMac)) {
+ /*
+ * If this is not a INFRA type BSS, then do not send the command
+ * down to firmware.Do not send the START command for
+ * other session connections.*/
+ if (!csr_roam_is_sta_mode(pMac, session_id)) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ "Wrong Mode %d",
+ session->connectedProfile.BSSType);
+ return;
+ }
+ ngbr_roam_info->uOsRequestedHandoff = 0;
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+ if (session->roamOffloadSynchParams.bRoamSynchInProgress) {
+ if (pMac->roam.pReassocResp != NULL) {
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_DEBUG,
+ "Free Reassoc Rsp");
+ cdf_mem_free(pMac->roam.pReassocResp);
+ pMac->roam.pReassocResp = NULL;
+ }
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ "LFR3:Send SynchCnf auth, authenticated");
+ csr_roam_offload_send_synch_cnf(pMac, session_id);
+ } else
+#endif
+ csr_roam_offload_scan(pMac, session_id,
+ ROAM_SCAN_OFFLOAD_START,
+ REASON_CONNECT);
+ }
+#endif
+}
+
+/**
+ * csr_neighbor_roam_indicate_connect()
+ * @pMac: mac context
+ * @session_id: Session Id
+ * @cdf_status: CDF status
+ *
+ * This function is called by CSR as soon as the station connects to an AP.
+ * This initializes all the necessary data structures related to the
+ * associated AP and transitions the state to CONNECTED state
+ *
+ * Return: CDF status
+ */
+CDF_STATUS csr_neighbor_roam_indicate_connect(
+ tpAniSirGlobal pMac, uint8_t session_id,
+ CDF_STATUS cdf_status)
+{
+ tpCsrNeighborRoamControlInfo ngbr_roam_info =
+ &pMac->roam.neighborRoamInfo[session_id];
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+ tCsrRoamInfo roamInfo;
+ tCsrRoamSession *session = &pMac->roam.roamSession[session_id];
+ tpSirSetActiveModeSetBncFilterReq msg;
+#endif
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+
+ /* if session id invalid then we need return failure */
+ if (NULL == ngbr_roam_info || !CSR_IS_SESSION_VALID(pMac, session_id)
+ || (NULL == pMac->roam.roamSession[session_id].pCurRoamProfile)) {
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ sms_log(pMac, LOG2,
+ FL("Connect ind. received with session id %d in state %s"),
+ session_id, mac_trace_get_neighbour_roam_state(
+ ngbr_roam_info->neighborRoamState));
+
+ /* Bail out if this is NOT a STA persona */
+ if (pMac->roam.roamSession[session_id].pCurRoamProfile->csrPersona !=
+ CDF_STA_MODE) {
+ sms_log(pMac, LOGE,
+ FL("Ignoring Connect ind received from a non STA."
+ "session_id: %d, csrPersonna %d"), session_id,
+ (int)session->pCurRoamProfile->csrPersona);
+ return CDF_STATUS_SUCCESS;
+ }
+ /* if a concurrent session is running */
+ if ((false ==
+ CSR_IS_FASTROAM_IN_CONCURRENCY_INI_FEATURE_ENABLED(pMac)) &&
+ (csr_is_concurrent_session_running(pMac))) {
+ sms_log(pMac, LOGE,
+ FL("Ignoring Connect ind. received in multisession %d"),
+ csr_is_concurrent_session_running(pMac));
+ return CDF_STATUS_SUCCESS;
+ }
+#ifdef WLAN_FEATURE_ROAM_OFFLOAD
+ if (session->roamOffloadSynchParams.bRoamSynchInProgress &&
+ (eSIR_ROAM_AUTH_STATUS_AUTHENTICATED ==
+ session->roamOffloadSynchParams.authStatus)) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ "LFR3:csr_neighbor_roam_indicate_connect");
+ msg = cdf_mem_malloc(sizeof(tSirSetActiveModeSetBncFilterReq));
+ if (msg == NULL) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ "LFR3:Mem Alloc failed for beacon Filter Req");
+ return CDF_STATUS_E_NOMEM;
+ }
+ msg->messageType = eWNI_SME_SET_BCN_FILTER_REQ;
+ msg->length = sizeof(uint8_t);
+ msg->seesionId = session_id;
+ status = cds_send_mb_message_to_mac(msg);
+ cdf_copy_macaddr(&roamInfo.peerMac,
+ &session->connectedProfile.bssid);
+ roamInfo.roamSynchInProgress =
+ session->roamOffloadSynchParams.bRoamSynchInProgress;
+ csr_roam_call_callback(pMac, session_id, &roamInfo, 0,
+ eCSR_ROAM_SET_KEY_COMPLETE,
+ eCSR_ROAM_RESULT_AUTHENTICATED);
+ }
+#endif
+
+ switch (ngbr_roam_info->neighborRoamState) {
+ case eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING:
+ if (CDF_STATUS_SUCCESS != cdf_status) {
+ /**
+ * Just transition the state to INIT state.Rest of the
+ * clean up happens when we get next connect indication
+ */
+ CSR_NEIGHBOR_ROAM_STATE_TRANSITION(
+ pMac, eCSR_NEIGHBOR_ROAM_STATE_INIT,
+ session_id)
+ ngbr_roam_info->roamChannelInfo.IAPPNeighborListReceived =
+ false;
+ break;
+ }
+ /* Fall through if the status is SUCCESS */
+ case eCSR_NEIGHBOR_ROAM_STATE_INIT:
+ /* Reset all the data structures here */
+ csr_neighbor_roam_reset_init_state_control_info(pMac,
+ session_id);
+ csr_neighbor_roam_info_ctx_init(pMac, session_id);
+ break;
+ default:
+ sms_log(pMac, LOGE,
+ FL("Connect evt received in invalid state %s Ignoring"),
+ mac_trace_get_neighbour_roam_state(
+ ngbr_roam_info->neighborRoamState));
+ break;
+ }
+ return status;
+}
+
+#ifdef WLAN_FEATURE_VOWIFI_11R
+/* ---------------------------------------------------------------------------
+
+ \fn csr_neighbor_roam_purge_preauth_failed_list
+
+ \brief This function purges all the MAC addresses in the pre-auth fail list
+
+ \param pMac - The handle returned by mac_open.
+
+ \return VOID
+
+ ---------------------------------------------------------------------------*/
+void csr_neighbor_roam_purge_preauth_failed_list(tpAniSirGlobal pMac)
+{
+ uint8_t i, j;
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL;
+
+ for (j = 0; j < CSR_ROAM_SESSION_MAX; j++) {
+ pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[j];
+ for (i = 0;
+ i <
+ pNeighborRoamInfo->FTRoamInfo.preAuthFailList.
+ numMACAddress; i++) {
+ cdf_mem_zero(pNeighborRoamInfo->FTRoamInfo.
+ preAuthFailList.macAddress[i],
+ sizeof(tSirMacAddr));
+ }
+ pNeighborRoamInfo->FTRoamInfo.preAuthFailList.numMACAddress = 0;
+ }
+}
+
+/* ---------------------------------------------------------------------------
+
+ \fn csr_neighbor_roam_init11r_assoc_info
+
+ \brief This function initializes 11r related neighbor roam data structures
+
+ \param pMac - The handle returned by mac_open.
+
+ \return CDF_STATUS_SUCCESS on success, corresponding error code otherwise
+
+ ---------------------------------------------------------------------------*/
+CDF_STATUS csr_neighbor_roam_init11r_assoc_info(tpAniSirGlobal pMac)
+{
+ CDF_STATUS status;
+ uint8_t i;
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL;
+ tpCsr11rAssocNeighborInfo pFTRoamInfo = NULL;
+
+ for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
+ pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[i];
+ pFTRoamInfo = &pNeighborRoamInfo->FTRoamInfo;
+
+ pNeighborRoamInfo->is11rAssoc = false;
+ pNeighborRoamInfo->cfgParams.maxNeighborRetries =
+ pMac->roam.configParam.neighborRoamConfig.
+ nMaxNeighborRetries;
+
+ pFTRoamInfo->neighborReportTimeout =
+ CSR_NEIGHBOR_ROAM_REPORT_QUERY_TIMEOUT;
+ pFTRoamInfo->PEPreauthRespTimeout =
+ CSR_NEIGHBOR_ROAM_PREAUTH_RSP_WAIT_MULTIPLIER *
+ pNeighborRoamInfo->cfgParams.neighborScanPeriod;
+ pFTRoamInfo->neighborRptPending = false;
+ pFTRoamInfo->preauthRspPending = false;
+
+ pFTRoamInfo->currentNeighborRptRetryNum = 0;
+ pFTRoamInfo->numBssFromNeighborReport = 0;
+
+ cdf_mem_zero(pFTRoamInfo->neighboReportBssInfo,
+ sizeof(tCsrNeighborReportBssInfo) *
+ MAX_BSS_IN_NEIGHBOR_RPT);
+
+ status = csr_ll_open(pMac->hHdd, &pFTRoamInfo->preAuthDoneList);
+ if (CDF_STATUS_SUCCESS != status) {
+ sms_log(pMac, LOGE,
+ FL("LL Open of preauth done AP List failed"));
+ return CDF_STATUS_E_RESOURCES;
+ }
+ }
+ return status;
+}
+#endif /* WLAN_FEATURE_VOWIFI_11R */
+
+/* ---------------------------------------------------------------------------
+
+ \fn csr_neighbor_roam_init
+
+ \brief This function initializes neighbor roam data structures
+
+ \param pMac - The handle returned by mac_open.
+
+ \return CDF_STATUS_SUCCESS on success, corresponding error code otherwise
+
+ ---------------------------------------------------------------------------*/
+CDF_STATUS csr_neighbor_roam_init(tpAniSirGlobal pMac, uint8_t sessionId)
+{
+ CDF_STATUS status;
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+
+ pNeighborRoamInfo->neighborRoamState = eCSR_NEIGHBOR_ROAM_STATE_CLOSED;
+ pNeighborRoamInfo->prevNeighborRoamState =
+ eCSR_NEIGHBOR_ROAM_STATE_CLOSED;
+ pNeighborRoamInfo->cfgParams.maxChannelScanTime =
+ pMac->roam.configParam.neighborRoamConfig.nNeighborScanMaxChanTime;
+ pNeighborRoamInfo->cfgParams.minChannelScanTime =
+ pMac->roam.configParam.neighborRoamConfig.nNeighborScanMinChanTime;
+ pNeighborRoamInfo->cfgParams.maxNeighborRetries = 0;
+ pNeighborRoamInfo->cfgParams.neighborLookupThreshold =
+ pMac->roam.configParam.neighborRoamConfig.
+ nNeighborLookupRssiThreshold;
+ pNeighborRoamInfo->cfgParams.delay_before_vdev_stop =
+ pMac->roam.configParam.neighborRoamConfig.
+ delay_before_vdev_stop;
+ pNeighborRoamInfo->cfgParams.nOpportunisticThresholdDiff =
+ pMac->roam.configParam.neighborRoamConfig.
+ nOpportunisticThresholdDiff;
+ pNeighborRoamInfo->cfgParams.nRoamRescanRssiDiff =
+ pMac->roam.configParam.neighborRoamConfig.nRoamRescanRssiDiff;
+ pNeighborRoamInfo->cfgParams.nRoamBmissFirstBcnt =
+ pMac->roam.configParam.neighborRoamConfig.nRoamBmissFirstBcnt;
+ pNeighborRoamInfo->cfgParams.nRoamBmissFinalBcnt =
+ pMac->roam.configParam.neighborRoamConfig.nRoamBmissFinalBcnt;
+ pNeighborRoamInfo->cfgParams.nRoamBeaconRssiWeight =
+ pMac->roam.configParam.neighborRoamConfig.nRoamBeaconRssiWeight;
+ pNeighborRoamInfo->cfgParams.neighborScanPeriod =
+ pMac->roam.configParam.neighborRoamConfig.nNeighborScanTimerPeriod;
+ pNeighborRoamInfo->cfgParams.neighborResultsRefreshPeriod =
+ pMac->roam.configParam.neighborRoamConfig.
+ nNeighborResultsRefreshPeriod;
+ pNeighborRoamInfo->cfgParams.emptyScanRefreshPeriod =
+ pMac->roam.configParam.neighborRoamConfig.nEmptyScanRefreshPeriod;
+
+ pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels =
+ pMac->roam.configParam.neighborRoamConfig.neighborScanChanList.
+ numChannels;
+
+ pNeighborRoamInfo->cfgParams.channelInfo.ChannelList =
+ cdf_mem_malloc(pMac->roam.configParam.neighborRoamConfig.
+ neighborScanChanList.numChannels);
+
+ if (NULL == pNeighborRoamInfo->cfgParams.channelInfo.ChannelList) {
+ sms_log(pMac, LOGE,
+ FL("Memory Allocation for CFG Channel List failed"));
+ return CDF_STATUS_E_NOMEM;
+ }
+
+ /* Update the roam global structure from CFG */
+ cdf_mem_copy(pNeighborRoamInfo->cfgParams.channelInfo.ChannelList,
+ pMac->roam.configParam.neighborRoamConfig.
+ neighborScanChanList.channelList,
+ pMac->roam.configParam.neighborRoamConfig.
+ neighborScanChanList.numChannels);
+ pNeighborRoamInfo->cfgParams.hi_rssi_scan_max_count =
+ pMac->roam.configParam.neighborRoamConfig.
+ nhi_rssi_scan_max_count;
+ pNeighborRoamInfo->cfgParams.hi_rssi_scan_rssi_delta =
+ pMac->roam.configParam.neighborRoamConfig.
+ nhi_rssi_scan_rssi_delta;
+ pNeighborRoamInfo->cfgParams.hi_rssi_scan_delay =
+ pMac->roam.configParam.neighborRoamConfig.
+ nhi_rssi_scan_delay;
+ pNeighborRoamInfo->cfgParams.hi_rssi_scan_rssi_ub =
+ pMac->roam.configParam.neighborRoamConfig.
+ nhi_rssi_scan_rssi_ub;
+
+ cdf_zero_macaddr(&pNeighborRoamInfo->currAPbssid);
+ pNeighborRoamInfo->currentNeighborLookupThreshold =
+ pNeighborRoamInfo->cfgParams.neighborLookupThreshold;
+ pNeighborRoamInfo->currentOpportunisticThresholdDiff =
+ pNeighborRoamInfo->cfgParams.nOpportunisticThresholdDiff;
+ pNeighborRoamInfo->currentRoamRescanRssiDiff =
+ pNeighborRoamInfo->cfgParams.nRoamRescanRssiDiff;
+ pNeighborRoamInfo->currentRoamBmissFirstBcnt =
+ pNeighborRoamInfo->cfgParams.nRoamBmissFirstBcnt;
+ pNeighborRoamInfo->currentRoamBmissFinalBcnt =
+ pNeighborRoamInfo->cfgParams.nRoamBmissFinalBcnt;
+ pNeighborRoamInfo->currentRoamBeaconRssiWeight =
+ pNeighborRoamInfo->cfgParams.nRoamBeaconRssiWeight;
+#ifdef FEATURE_WLAN_LFR
+ cdf_mem_set(&pNeighborRoamInfo->prevConnProfile,
+ sizeof(tCsrRoamConnectedProfile), 0);
+#endif
+
+ status = csr_ll_open(pMac->hHdd, &pNeighborRoamInfo->roamableAPList);
+ if (CDF_STATUS_SUCCESS != status) {
+ sms_log(pMac, LOGE, FL("LL Open of roam able AP List failed"));
+ cdf_mem_free(pNeighborRoamInfo->cfgParams.channelInfo.
+ ChannelList);
+ pNeighborRoamInfo->cfgParams.channelInfo.ChannelList = NULL;
+ return CDF_STATUS_E_RESOURCES;
+ }
+
+ pNeighborRoamInfo->roamChannelInfo.currentChanIndex =
+ CSR_NEIGHBOR_ROAM_INVALID_CHANNEL_INDEX;
+ pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.
+ numOfChannels = 0;
+ pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList =
+ NULL;
+ pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived = false;
+
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ status = csr_neighbor_roam_init11r_assoc_info(pMac);
+ if (CDF_STATUS_SUCCESS != status) {
+ sms_log(pMac, LOGE, FL("LL Open of roam able AP List failed"));
+ cdf_mem_free(pNeighborRoamInfo->cfgParams.channelInfo.
+ ChannelList);
+ pNeighborRoamInfo->cfgParams.channelInfo.ChannelList = NULL;
+ csr_ll_close(&pNeighborRoamInfo->roamableAPList);
+ return CDF_STATUS_E_RESOURCES;
+ }
+#endif
+
+ CSR_NEIGHBOR_ROAM_STATE_TRANSITION(pMac, eCSR_NEIGHBOR_ROAM_STATE_INIT,
+ sessionId)
+ pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived = false;
+ /* Set the Last Sent Cmd as RSO_STOP */
+ pNeighborRoamInfo->last_sent_cmd = ROAM_SCAN_OFFLOAD_STOP;
+ return CDF_STATUS_SUCCESS;
+}
+
+/* ---------------------------------------------------------------------------
+
+ \fn csr_neighbor_roam_close
+
+ \brief This function closes/frees all the neighbor roam data structures
+
+ \param pMac - The handle returned by mac_open.
+ \param sessionId - Session identifier
+ \return VOID
+
+ ---------------------------------------------------------------------------*/
+void csr_neighbor_roam_close(tpAniSirGlobal pMac, uint8_t sessionId)
+{
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+
+ if (eCSR_NEIGHBOR_ROAM_STATE_CLOSED ==
+ pNeighborRoamInfo->neighborRoamState) {
+ sms_log(pMac, LOGW,
+ FL("Neighbor Roam Algorithm Already Closed"));
+ return;
+ }
+
+ if (pNeighborRoamInfo->cfgParams.channelInfo.ChannelList)
+ cdf_mem_free(pNeighborRoamInfo->cfgParams.channelInfo.
+ ChannelList);
+
+ pNeighborRoamInfo->cfgParams.channelInfo.ChannelList = NULL;
+
+ /* Should free up the nodes in the list before closing the double Linked list */
+ csr_neighbor_roam_free_roamable_bss_list(pMac,
+ &pNeighborRoamInfo->roamableAPList);
+ csr_ll_close(&pNeighborRoamInfo->roamableAPList);
+
+ if (pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.
+ ChannelList) {
+ cdf_mem_free(pNeighborRoamInfo->roamChannelInfo.
+ currentChannelListInfo.ChannelList);
+ }
+
+ pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList =
+ NULL;
+ pNeighborRoamInfo->roamChannelInfo.currentChanIndex =
+ CSR_NEIGHBOR_ROAM_INVALID_CHANNEL_INDEX;
+ pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.
+ numOfChannels = 0;
+ pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList =
+ NULL;
+ pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived = false;
+
+ /* Free the profile.. */
+ csr_release_profile(pMac, &pNeighborRoamInfo->csrNeighborRoamProfile);
+#ifdef FEATURE_WLAN_LFR
+ csr_roam_free_connect_profile(pMac, &pNeighborRoamInfo->prevConnProfile);
+#endif
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ pNeighborRoamInfo->FTRoamInfo.currentNeighborRptRetryNum = 0;
+ pNeighborRoamInfo->FTRoamInfo.numBssFromNeighborReport = 0;
+ cdf_mem_zero(pNeighborRoamInfo->FTRoamInfo.neighboReportBssInfo,
+ sizeof(tCsrNeighborReportBssInfo) *
+ MAX_BSS_IN_NEIGHBOR_RPT);
+ csr_neighbor_roam_free_roamable_bss_list(pMac,
+ &pNeighborRoamInfo->FTRoamInfo.
+ preAuthDoneList);
+ csr_ll_close(&pNeighborRoamInfo->FTRoamInfo.preAuthDoneList);
+#endif /* WLAN_FEATURE_VOWIFI_11R */
+
+ CSR_NEIGHBOR_ROAM_STATE_TRANSITION(pMac,
+ eCSR_NEIGHBOR_ROAM_STATE_CLOSED, sessionId)
+
+ return;
+}
+
+/**
+ * csr_neighbor_roam_request_handoff() - Handoff to a different AP
+ * @mac_ctx: Pointer to Global MAC structure
+ * @session_id: Session ID
+ *
+ * This function triggers actual switching from one AP to the new AP.
+ * It issues disassociate with reason code as Handoff and CSR as a part of
+ * handling disassoc rsp, issues reassociate to the new AP
+ *
+ * Return: none
+ */
+void csr_neighbor_roam_request_handoff(tpAniSirGlobal mac_ctx,
+ uint8_t session_id)
+{
+ tCsrRoamInfo roam_info;
+ tpCsrNeighborRoamControlInfo neighbor_roam_info =
+ &mac_ctx->roam.neighborRoamInfo[session_id];
+ tCsrNeighborRoamBSSInfo handoff_node;
+ uint32_t roamid = 0;
+ CDF_STATUS status;
+
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG, "%s session_id=%d",
+ __func__, session_id);
+
+ if (neighbor_roam_info->neighborRoamState !=
+ eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE) {
+ sms_log(mac_ctx, LOGE,
+ FL("Roam requested when Neighbor roam is in %s state"),
+ mac_trace_get_neighbour_roam_state(
+ neighbor_roam_info->neighborRoamState));
+ return;
+ }
+
+ if (false == csr_neighbor_roam_get_handoff_ap_info(mac_ctx,
+ &handoff_node, session_id)) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ FL("failed to obtain handoff AP"));
+ return;
+ }
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ FL("HANDOFF CANDIDATE BSSID "MAC_ADDRESS_STR),
+ MAC_ADDR_ARRAY(handoff_node.pBssDescription->bssId));
+
+ cdf_mem_zero(&roam_info, sizeof(tCsrRoamInfo));
+ csr_roam_call_callback(mac_ctx, session_id, &roam_info, roamid,
+ eCSR_ROAM_FT_START, eSIR_SME_SUCCESS);
+
+ cdf_mem_zero(&roam_info, sizeof(tCsrRoamInfo));
+ CSR_NEIGHBOR_ROAM_STATE_TRANSITION
+ (mac_ctx, eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING, session_id)
+
+ csr_neighbor_roam_send_lfr_metric_event(mac_ctx, session_id,
+ handoff_node.pBssDescription->bssId,
+ eCSR_ROAM_HANDOVER_SUCCESS);
+ /* Free the profile.. Just to make sure we dont leak memory here */
+ csr_release_profile(mac_ctx,
+ &neighbor_roam_info->csrNeighborRoamProfile);
+ /*
+ * Create the Handoff AP profile. Copy the currently connected profile
+ * and update only the BSSID and channel number. This should happen
+ * before issuing disconnect
+ */
+ status = csr_roam_copy_connected_profile(mac_ctx, session_id,
+ &neighbor_roam_info->csrNeighborRoamProfile);
+ if (CDF_STATUS_SUCCESS != status) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
+ FL("csr_roam_copy_connected_profile failed %d"),
+ status);
+ return;
+ }
+ cdf_mem_copy(neighbor_roam_info->csrNeighborRoamProfile.BSSIDs.bssid,
+ handoff_node.pBssDescription->bssId, sizeof(tSirMacAddr));
+ neighbor_roam_info->csrNeighborRoamProfile.ChannelInfo.ChannelList[0] =
+ handoff_node.pBssDescription->channelId;
+
+ NEIGHBOR_ROAM_DEBUG(mac_ctx, LOGW,
+ " csr_roamHandoffRequested: disassociating with current AP");
+
+ if (!CDF_IS_STATUS_SUCCESS
+ (csr_roam_issue_disassociate_cmd
+ (mac_ctx, session_id,
+ eCSR_DISCONNECT_REASON_HANDOFF))) {
+ sms_log(mac_ctx, LOGW,
+ "csr_roamHandoffRequested: fail to issue disassociate");
+ return;
+ }
+ /* notify HDD for handoff, providing the BSSID too */
+ roam_info.reasonCode = eCsrRoamReasonBetterAP;
+
+ cdf_mem_copy(roam_info.bssid.bytes,
+ handoff_node.pBssDescription->bssId,
+ sizeof(struct cdf_mac_addr));
+
+ csr_roam_call_callback(mac_ctx, session_id, &roam_info, 0,
+ eCSR_ROAM_ROAMING_START, eCSR_ROAM_RESULT_NONE);
+
+ return;
+}
+
+/**
+ * csr_neighbor_roam_is_handoff_in_progress()
+ *
+ * @mac_ctx: Pointer to Global MAC structure
+ * @session_id: Session ID
+ *
+ * This function returns whether handoff is in progress or not based on
+ * the current neighbor roam state
+ *
+ * Return: true if reassoc in progress, false otherwise
+ */
+bool csr_neighbor_roam_is_handoff_in_progress(tpAniSirGlobal pMac, uint8_t sessionId)
+{
+ if (eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING ==
+ pMac->roam.neighborRoamInfo[sessionId].neighborRoamState)
+ return true;
+
+ return false;
+}
+
+#if defined(WLAN_FEATURE_VOWIFI_11R) || defined(WLAN_FEATURE_NEIGHBOR_ROAMING)
+/* ---------------------------------------------------------------------------
+
+ \fn csr_neighbor_roam_is11r_assoc
+
+ \brief This function returns whether the current association is a 11r assoc or not
+
+ \param pMac - The handle returned by mac_open.
+
+ \return true if current assoc is 11r, false otherwise
+
+ ---------------------------------------------------------------------------*/
+bool csr_neighbor_roam_is11r_assoc(tpAniSirGlobal pMac, uint8_t sessionId)
+{
+ return pMac->roam.neighborRoamInfo[sessionId].is11rAssoc;
+}
+#endif /* WLAN_FEATURE_VOWIFI_11R */
+
+/**
+ * csr_neighbor_roam_get_handoff_ap_info - Identifies the best AP for roaming
+ *
+ * @pMac: mac context
+ * @session_id: Session Id
+ * @hand_off_node: AP node that is the handoff candidate returned
+ *
+ * This function returns the best possible AP for handoff. For 11R case, it
+ * returns the 1st entry from pre-auth done list. For non-11r case, it returns
+ * the 1st entry from roamable AP list
+ *
+ * Return: true if able find handoff AP, false otherwise
+ */
+
+bool csr_neighbor_roam_get_handoff_ap_info(tpAniSirGlobal pMac,
+ tpCsrNeighborRoamBSSInfo hand_off_node,
+ uint8_t session_id)
+{
+ tpCsrNeighborRoamControlInfo ngbr_roam_info =
+ &pMac->roam.neighborRoamInfo[session_id];
+ tpCsrNeighborRoamBSSInfo bss_node = NULL;
+
+ if (NULL == hand_off_node) {
+ CDF_ASSERT(NULL != hand_off_node);
+ return false;
+ }
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ if (ngbr_roam_info->is11rAssoc) {
+ /* Always the BSS info in the head is the handoff candidate */
+ bss_node = csr_neighbor_roam_next_roamable_ap(
+ pMac,
+ &ngbr_roam_info->FTRoamInfo.preAuthDoneList,
+ NULL);
+ NEIGHBOR_ROAM_DEBUG(pMac, LOG1,
+ FL("Number of Handoff candidates = %d"),
+ csr_ll_count(&
+ ngbr_roam_info->FTRoamInfo.preAuthDoneList));
+ } else
+#endif
+#ifdef FEATURE_WLAN_ESE
+ if (ngbr_roam_info->isESEAssoc) {
+ /* Always the BSS info in the head is the handoff candidate */
+ bss_node =
+ csr_neighbor_roam_next_roamable_ap(pMac,
+ &ngbr_roam_info->FTRoamInfo.preAuthDoneList,
+ NULL);
+ NEIGHBOR_ROAM_DEBUG(pMac, LOG1,
+ FL("Number of Handoff candidates = %d"),
+ csr_ll_count(&ngbr_roam_info->FTRoamInfo.
+ preAuthDoneList));
+ } else
+#endif
+#ifdef FEATURE_WLAN_LFR
+ if (csr_roam_is_fast_roam_enabled(pMac, session_id)) {
+ /* Always the BSS info in the head is the handoff candidate */
+ bss_node =
+ csr_neighbor_roam_next_roamable_ap(pMac,
+ &ngbr_roam_info->FTRoamInfo.preAuthDoneList,
+ NULL);
+ NEIGHBOR_ROAM_DEBUG(pMac, LOG1,
+ FL("Number of Handoff candidates = %d"),
+ csr_ll_count(
+ &ngbr_roam_info->FTRoamInfo.preAuthDoneList));
+ } else
+#endif
+ {
+ bss_node =
+ csr_neighbor_roam_next_roamable_ap(pMac,
+ &ngbr_roam_info->roamableAPList,
+ NULL);
+ NEIGHBOR_ROAM_DEBUG(pMac, LOG1,
+ FL("Number of Handoff candidates = %d"),
+ csr_ll_count(&ngbr_roam_info->roamableAPList));
+ }
+ if (NULL == bss_node)
+ return false;
+ cdf_mem_copy(hand_off_node, bss_node, sizeof(tCsrNeighborRoamBSSInfo));
+ return true;
+}
+
+/* ---------------------------------------------------------------------------
+ \brief This function returns true if preauth is completed
+
+ \param pMac - The handle returned by mac_open.
+
+ \return bool
+
+ ---------------------------------------------------------------------------*/
+bool csr_neighbor_roam_state_preauth_done(tpAniSirGlobal pMac, uint8_t sessionId)
+{
+ return pMac->roam.neighborRoamInfo[sessionId].neighborRoamState ==
+ eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE;
+}
+
+/* ---------------------------------------------------------------------------
+ \brief In the event that we are associated with AP1 and we have
+ completed pre auth with AP2. Then we receive a deauth/disassoc from
+ AP1.
+ At this point neighbor roam is in pre auth done state, pre auth timer
+ is running. We now handle this case by stopping timer and clearing
+ the pre-auth state. We basically clear up and just go to disconnected
+ state.
+
+ \param pMac - The handle returned by mac_open.
+
+ \return bool
+ ---------------------------------------------------------------------------*/
+void csr_neighbor_roam_tranistion_preauth_done_to_disconnected(tpAniSirGlobal pMac,
+ uint8_t sessionId)
+{
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+ tCsrRoamSession *session = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!session) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_DEBUG,
+ FL("session is NULL"));
+ return;
+ }
+
+ if (pNeighborRoamInfo->neighborRoamState !=
+ eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE)
+ return;
+
+ /* Stop timer */
+ cdf_mc_timer_stop(&session->ftSmeContext.preAuthReassocIntvlTimer);
+
+ /* Transition to init state */
+ CSR_NEIGHBOR_ROAM_STATE_TRANSITION(pMac, eCSR_NEIGHBOR_ROAM_STATE_INIT,
+ sessionId)
+ pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived = false;
+}
+
+/* ---------------------------------------------------------------------------
+ \brief This function returns true if STA is in the middle of roaming states
+
+ \param halHandle - The handle from HDD context.
+ \param sessionId - Session identifier
+
+ \return bool
+
+ ---------------------------------------------------------------------------*/
+bool csr_neighbor_middle_of_roaming(tpAniSirGlobal pMac, uint8_t sessionId)
+{
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+ bool val = (eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING ==
+ pNeighborRoamInfo->neighborRoamState) ||
+ (eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING ==
+ pNeighborRoamInfo->neighborRoamState) ||
+ (eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE ==
+ pNeighborRoamInfo->neighborRoamState);
+ return val;
+}
+
+/**
+ * csr_neighbor_roam_candidate_found_ind_hdlr()
+ *
+ * @mac_ctx: Pointer to Global MAC structure
+ * @msg_buf: pointer to msg buff
+ *
+ * This function is called by CSR as soon as TL posts the candidate
+ * found indication to SME via MC thread
+ *
+ * Return: CDF_STATUS_SUCCESS on success, corresponding error code otherwise
+ */
+CDF_STATUS csr_neighbor_roam_candidate_found_ind_hdlr(tpAniSirGlobal pMac, void *pMsg)
+{
+ tSirSmeCandidateFoundInd *pSirSmeCandidateFoundInd =
+ (tSirSmeCandidateFoundInd *) pMsg;
+ uint32_t sessionId = pSirSmeCandidateFoundInd->sessionId;
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+
+ sms_log(pMac, LOG1, FL("Received indication from firmware"));
+
+ /* we must be in connected state, if not ignore it */
+ if ((eCSR_NEIGHBOR_ROAM_STATE_CONNECTED !=
+ pNeighborRoamInfo->neighborRoamState)
+ || (pNeighborRoamInfo->uOsRequestedHandoff)) {
+ sms_log(pMac, LOGE,
+ FL
+ ("Received in not CONNECTED state OR uOsRequestedHandoff is set. Ignore it"));
+ status = CDF_STATUS_E_FAILURE;
+ } else {
+ /* Firmware indicated that roaming candidate is found. Beacons
+ * are already in the SME scan results table.
+ * Process the results for choosing best roaming candidate.
+ */
+ csr_save_scan_results(pMac, eCsrScanCandidateFound,
+ sessionId);
+ /* Future enhancements:
+ * If firmware tags candidate beacons, give them preference
+ * for roaming.
+ * Age out older entries so that new candidate beacons
+ * will get preference.
+ */
+ status = csr_neighbor_roam_process_scan_complete(pMac,
+ sessionId);
+ if (CDF_STATUS_SUCCESS != status) {
+ sms_log(pMac, LOGE,
+ FL("Neighbor scan process complete failed with status %d"),
+ status);
+ return CDF_STATUS_E_FAILURE;
+ }
+ }
+
+ return status;
+}
+
+/**
+ * csr_neighbor_roam_process_handoff_req - Processes handoff request
+ *
+ * @mac_ctx Pointer to mac context
+ * @session_id SME session id
+ *
+ * This function is called start with the handoff process. First do a
+ * SSID scan for the BSSID provided.
+ *
+ * Return: status
+ */
+CDF_STATUS csr_neighbor_roam_process_handoff_req(
+ tpAniSirGlobal mac_ctx,
+ uint8_t session_id)
+{
+ tpCsrNeighborRoamControlInfo roam_ctrl_info =
+ &mac_ctx->roam.neighborRoamInfo[session_id];
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ uint32_t roam_id;
+ tCsrRoamProfile *profile = NULL;
+ tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id);
+ uint8_t i = 0;
+
+ if (NULL == session) {
+ sms_log(mac_ctx, LOGE, FL("session is NULL "));
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ roam_id = GET_NEXT_ROAM_ID(&mac_ctx->roam);
+ profile = cdf_mem_malloc(sizeof(tCsrRoamProfile));
+ if (NULL == profile) {
+ sms_log(mac_ctx, LOGE, FL("Memory alloc failed"));
+ return CDF_STATUS_E_NOMEM;
+ }
+ cdf_mem_set(profile, sizeof(tCsrRoamProfile), 0);
+ status =
+ csr_roam_copy_profile(mac_ctx, profile,
+ session->pCurRoamProfile);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(mac_ctx, LOGE, FL("Profile copy failed"));
+ goto end;
+ }
+ /* Add the BSSID & Channel */
+ profile->BSSIDs.numOfBSSIDs = 1;
+ if (NULL == profile->BSSIDs.bssid) {
+ profile->BSSIDs.bssid =
+ cdf_mem_malloc(sizeof(tSirMacAddr) *
+ profile->BSSIDs.numOfBSSIDs);
+ if (NULL == profile->BSSIDs.bssid) {
+ sms_log(mac_ctx, LOGE, FL("mem alloc failed for BSSID"));
+ status = CDF_STATUS_E_NOMEM;
+ goto end;
+ }
+ }
+
+ cdf_mem_zero(profile->BSSIDs.bssid,
+ sizeof(tSirMacAddr) *
+ profile->BSSIDs.numOfBSSIDs);
+
+ /* Populate the BSSID from handoff info received from HDD */
+ for (i = 0; i < profile->BSSIDs.numOfBSSIDs; i++) {
+ cdf_copy_macaddr(&profile->BSSIDs.bssid[i],
+ &roam_ctrl_info->handoffReqInfo.bssid);
+ }
+
+ profile->ChannelInfo.numOfChannels = 1;
+ if (NULL == profile->ChannelInfo.ChannelList) {
+ profile->ChannelInfo.ChannelList =
+ cdf_mem_malloc(sizeof(*profile->
+ ChannelInfo.ChannelList) *
+ profile->ChannelInfo.numOfChannels);
+ if (NULL == profile->ChannelInfo.ChannelList) {
+ sms_log(mac_ctx, LOGE,
+ FL("mem alloc failed for ChannelList"));
+ status = CDF_STATUS_E_NOMEM;
+ goto end;
+ }
+ }
+ profile->ChannelInfo.ChannelList[0] =
+ roam_ctrl_info->handoffReqInfo.channel;
+
+ /* do a SSID scan */
+ status =
+ csr_scan_for_ssid(mac_ctx, session_id, profile, roam_id, false);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(mac_ctx, LOGE, FL("SSID scan failed"));
+ }
+
+end:
+ if (NULL != profile) {
+ csr_release_profile(mac_ctx, profile);
+ cdf_mem_free(profile);
+ }
+
+ return status;
+}
+
+/* ---------------------------------------------------------------------------
+
+ \fn csr_neighbor_roam_sssid_scan_done
+
+ \brief This function is called once SSID scan is done. If SSID scan failed
+ to find our candidate add an entry to csr scan cache ourself before starting
+ the handoff process
+
+ \param pMac - The handle returned by mac_open.
+
+ \return CDF_STATUS_SUCCESS on success, corresponding error code otherwise
+
+ ---------------------------------------------------------------------------*/
+CDF_STATUS csr_neighbor_roam_sssid_scan_done(tpAniSirGlobal pMac,
+ uint8_t sessionId, CDF_STATUS status)
+{
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+ CDF_STATUS hstatus;
+
+ sms_log(pMac, LOGE, FL("called "));
+
+ /* we must be in connected state, if not ignore it */
+ if (eCSR_NEIGHBOR_ROAM_STATE_CONNECTED !=
+ pNeighborRoamInfo->neighborRoamState) {
+ sms_log(pMac, LOGE,
+ FL("Received in not CONNECTED state. Ignore it"));
+ return CDF_STATUS_E_FAILURE;
+ }
+ /* if SSID scan failed to find our candidate add an entry to csr scan cache ourself */
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE, FL("Add an entry to csr scan cache"));
+ hstatus = csr_scan_create_entry_in_scan_cache(pMac, sessionId,
+ pNeighborRoamInfo->
+ handoffReqInfo.bssid,
+ pNeighborRoamInfo->
+ handoffReqInfo.channel);
+ if (CDF_STATUS_SUCCESS != hstatus) {
+ sms_log(pMac, LOGE,
+ FL
+ ("csr_scan_create_entry_in_scan_cache failed with status %d"),
+ hstatus);
+ return CDF_STATUS_E_FAILURE;
+ }
+ }
+
+ /* Now we have completed scanning for the candidate provided by HDD. Let move on to HO */
+ hstatus = csr_neighbor_roam_process_scan_complete(pMac, sessionId);
+
+ if (CDF_STATUS_SUCCESS != hstatus) {
+ sms_log(pMac, LOGE,
+ FL
+ ("Neighbor scan process complete failed with status %d"),
+ hstatus);
+ return CDF_STATUS_E_FAILURE;
+ }
+ return CDF_STATUS_SUCCESS;
+}
+
+
+/**
+ * csr_neighbor_roam_handoff_req_hdlr - Processes handoff request
+ * @mac_ctx Pointer to mac context
+ * @msg message sent to HDD
+ *
+ * This function is called by CSR as soon as it gets a handoff request
+ * to SME via MC thread
+ *
+ * Return: status
+ */
+CDF_STATUS csr_neighbor_roam_handoff_req_hdlr(
+ tpAniSirGlobal mac_ctx, void *msg)
+{
+ tAniHandoffReq *handoff_req = (tAniHandoffReq *) msg;
+ uint32_t session_id = handoff_req->sessionId;
+ tpCsrNeighborRoamControlInfo roam_ctrl_info =
+ &mac_ctx->roam.neighborRoamInfo[session_id];
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+
+ /* we must be in connected state, if not ignore it */
+ if (eCSR_NEIGHBOR_ROAM_STATE_CONNECTED !=
+ roam_ctrl_info->neighborRoamState) {
+ sms_log(mac_ctx, LOGE,
+ FL("Received in not CONNECTED state. Ignore it"));
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ /* save the handoff info came from HDD as part of the reassoc req */
+ handoff_req = (tAniHandoffReq *) msg;
+ if (NULL == handoff_req) {
+ sms_log(mac_ctx, LOGE, FL("Received msg is NULL"));
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ /* sanity check */
+ if (true == cdf_mem_compare(handoff_req->bssid,
+ roam_ctrl_info->currAPbssid.bytes,
+ sizeof(tSirMacAddr))) {
+ sms_log(mac_ctx, LOGE,
+ FL
+ ("Received req has same BSSID as current AP!!"));
+ return CDF_STATUS_E_FAILURE;
+ }
+ roam_ctrl_info->handoffReqInfo.channel =
+ handoff_req->channel;
+ roam_ctrl_info->handoffReqInfo.src =
+ handoff_req->handoff_src;
+ cdf_mem_copy(&roam_ctrl_info->handoffReqInfo.bssid.bytes,
+ &handoff_req->bssid, CDF_MAC_ADDR_SIZE);
+ roam_ctrl_info->uOsRequestedHandoff = 1;
+ status = csr_roam_offload_scan(mac_ctx, session_id,
+ ROAM_SCAN_OFFLOAD_STOP,
+ REASON_OS_REQUESTED_ROAMING_NOW);
+ if (CDF_STATUS_SUCCESS != status) {
+ sms_log(mac_ctx, LOGE,
+ FL("csr_roam_offload_scan failed"));
+ roam_ctrl_info->uOsRequestedHandoff = 0;
+ }
+ return status;
+}
+
+/**
+ * csr_neighbor_roam_proceed_with_handoff_req()
+ *
+ * @mac_ctx: Pointer to Global MAC structure
+ * @session_id: Session ID
+ *
+ * This function is called by CSR as soon as it gets rsp back for
+ * ROAM_SCAN_OFFLOAD_STOP with reason REASON_OS_REQUESTED_ROAMING_NOW
+ *
+ * Return: CDF_STATUS_SUCCESS on success, corresponding error code otherwise
+ */
+CDF_STATUS csr_neighbor_roam_proceed_with_handoff_req(tpAniSirGlobal pMac,
+ uint8_t sessionId)
+{
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ /* we must be in connected state, if not ignore it */
+ if ((eCSR_NEIGHBOR_ROAM_STATE_CONNECTED !=
+ pNeighborRoamInfo->neighborRoamState)
+ || (!pNeighborRoamInfo->uOsRequestedHandoff)) {
+ sms_log(pMac, LOGE,
+ FL
+ ("Received in not CONNECTED state or uOsRequestedHandoff is not set. Ignore it"));
+ status = CDF_STATUS_E_FAILURE;
+ } else {
+ /* Let's go ahead with handoff */
+ status = csr_neighbor_roam_process_handoff_req(pMac, sessionId);
+ }
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ pNeighborRoamInfo->uOsRequestedHandoff = 0;
+ }
+ return status;
+}
+
+/* ---------------------------------------------------------------------------
+
+ \fn csr_neighbor_roam_start_lfr_scan
+
+ \brief This function is called if HDD requested handoff failed for some
+ reason. start the LFR logic at that point.By the time, this function is
+ called, a STOP command has already been issued.
+
+ \param pMac - The handle returned by mac_open.
+
+ \return CDF_STATUS_SUCCESS on success, corresponding error code otherwise
+
+ ---------------------------------------------------------------------------*/
+CDF_STATUS csr_neighbor_roam_start_lfr_scan(tpAniSirGlobal pMac, uint8_t sessionId)
+{
+ tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
+ &pMac->roam.neighborRoamInfo[sessionId];
+ pNeighborRoamInfo->uOsRequestedHandoff = 0;
+ /* There is no candidate or We are not roaming Now.
+ * Inform the FW to restart Roam Offload Scan */
+ csr_roam_offload_scan(pMac, sessionId, ROAM_SCAN_OFFLOAD_START,
+ REASON_NO_CAND_FOUND_OR_NOT_ROAMING_NOW);
+
+ return CDF_STATUS_SUCCESS;
+}
+#endif /* WLAN_FEATURE_NEIGHBOR_ROAMING */
diff --git a/core/sme/src/csr/csr_tdls_process.c b/core/sme/src/csr/csr_tdls_process.c
new file mode 100644
index 0000000..30fadcd
--- /dev/null
+++ b/core/sme/src/csr/csr_tdls_process.c
@@ -0,0 +1,820 @@
+/*
+ * Copyright (c) 2012-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_tdls_process.c
+
+ Implementation for the TDLS interface to PE.
+ ========================================================================== */
+
+#ifdef FEATURE_WLAN_TDLS
+
+#include "ani_global.h" /* for tpAniSirGlobal */
+#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 "csr_internal.h"
+
+/*
+ * common routine to remove TDLS cmd from SME command list..
+ * commands are removed after getting reponse from PE.
+ */
+CDF_STATUS csr_tdls_remove_sme_cmd(tpAniSirGlobal pMac, eSmeCommandType cmdType)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ tListElem *pEntry;
+ tSmeCmd *pCommand;
+
+ pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK);
+ if (pEntry) {
+ pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link);
+ if (cmdType == pCommand->command) {
+ if (csr_ll_remove_entry(&pMac->sme.smeCmdActiveList,
+ pEntry, LL_ACCESS_LOCK)) {
+ cdf_mem_zero(&pCommand->u.tdlsCmd,
+ sizeof(tTdlsCmd));
+ csr_release_command(pMac, pCommand);
+ sme_process_pending_queue(pMac);
+ status = CDF_STATUS_SUCCESS;
+ }
+ }
+ }
+ return status;
+}
+
+/**
+ * csr_tdls_send_mgmt_req() - to send a TDLS frame to PE through SME
+ * @hHal: HAL context
+ * @sessionId: SME session id
+ * @tdlsSendMgmt: tdls mgmt pointer
+ *
+ * TDLS request API, called from HDD to send a TDLS frame in SME/CSR and
+ * send message to PE to trigger TDLS discovery procedure.
+ */
+CDF_STATUS csr_tdls_send_mgmt_req(tHalHandle hHal, uint8_t sessionId,
+ tCsrTdlsSendMgmt *tdlsSendMgmt)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ tSmeCmd *tdlsSendMgmtCmd;
+ tTdlsSendMgmtCmdInfo *tdlsSendMgmtCmdInfo;
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+
+ /* If connected and in Infra. Only then allow this */
+ if (!CSR_IS_SESSION_VALID(pMac, sessionId) ||
+ !csr_is_conn_state_connected_infra(pMac, sessionId) ||
+ (NULL == tdlsSendMgmt))
+ return status;
+ tdlsSendMgmtCmd = csr_get_command_buffer(pMac);
+ if (!tdlsSendMgmtCmd)
+ return status;
+ tdlsSendMgmtCmdInfo = &tdlsSendMgmtCmd->u.tdlsCmd.u.tdlsSendMgmtCmdInfo;
+ tdlsSendMgmtCmd->sessionId = sessionId;
+ tdlsSendMgmtCmdInfo->frameType = tdlsSendMgmt->frameType;
+ tdlsSendMgmtCmdInfo->dialog = tdlsSendMgmt->dialog;
+ tdlsSendMgmtCmdInfo->statusCode = tdlsSendMgmt->statusCode;
+ tdlsSendMgmtCmdInfo->responder = tdlsSendMgmt->responder;
+ tdlsSendMgmtCmdInfo->peerCapability = tdlsSendMgmt->peerCapability;
+ cdf_mem_copy(tdlsSendMgmtCmdInfo->peerMac, tdlsSendMgmt->peerMac,
+ sizeof(tSirMacAddr));
+
+ if ((0 != tdlsSendMgmt->len) && (NULL != tdlsSendMgmt->buf)) {
+ tdlsSendMgmtCmdInfo->buf = cdf_mem_malloc(tdlsSendMgmt->len);
+ if (NULL == tdlsSendMgmtCmdInfo->buf) {
+ status = CDF_STATUS_E_NOMEM;
+ sms_log(pMac, LOGE, FL("Alloc Failed"));
+ CDF_ASSERT(0);
+ return status;
+ }
+ cdf_mem_copy(tdlsSendMgmtCmdInfo->buf, tdlsSendMgmt->buf,
+ tdlsSendMgmt->len);
+ tdlsSendMgmtCmdInfo->len = tdlsSendMgmt->len;
+ } else {
+ tdlsSendMgmtCmdInfo->buf = NULL;
+ tdlsSendMgmtCmdInfo->len = 0;
+ }
+
+ tdlsSendMgmtCmd->command = eSmeCommandTdlsSendMgmt;
+ tdlsSendMgmtCmd->u.tdlsCmd.size = sizeof(tTdlsSendMgmtCmdInfo);
+ sme_push_command(pMac, tdlsSendMgmtCmd, false);
+ status = CDF_STATUS_SUCCESS;
+ return status;
+}
+
+/*
+ * TDLS request API, called from HDD to add a TDLS peer
+ */
+CDF_STATUS csr_tdls_change_peer_sta(tHalHandle hHal, uint8_t sessionId,
+ const tSirMacAddr peerMac,
+ tCsrStaParams *pstaParams)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ tSmeCmd *tdlsAddStaCmd;
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+
+ /* If connected and in Infra. Only then allow this */
+ if (CSR_IS_SESSION_VALID(pMac, sessionId) &&
+ csr_is_conn_state_connected_infra(pMac, sessionId) &&
+ (NULL != peerMac) && (NULL != pstaParams)) {
+
+ tdlsAddStaCmd = csr_get_command_buffer(pMac);
+
+ if (tdlsAddStaCmd) {
+ tTdlsAddStaCmdInfo *tdlsAddStaCmdInfo =
+ &tdlsAddStaCmd->u.tdlsCmd.u.tdlsAddStaCmdInfo;
+
+ tdlsAddStaCmdInfo->tdlsAddOper = TDLS_OPER_UPDATE;
+
+ tdlsAddStaCmd->sessionId = sessionId;
+
+ cdf_mem_copy(tdlsAddStaCmdInfo->peerMac,
+ peerMac, sizeof(tSirMacAddr));
+ tdlsAddStaCmdInfo->capability = pstaParams->capability;
+ tdlsAddStaCmdInfo->uapsdQueues =
+ pstaParams->uapsd_queues;
+ tdlsAddStaCmdInfo->maxSp = pstaParams->max_sp;
+ cdf_mem_copy(tdlsAddStaCmdInfo->extnCapability,
+ pstaParams->extn_capability,
+ sizeof(pstaParams->extn_capability));
+
+ tdlsAddStaCmdInfo->htcap_present =
+ pstaParams->htcap_present;
+ if (pstaParams->htcap_present)
+ cdf_mem_copy(&tdlsAddStaCmdInfo->HTCap,
+ &pstaParams->HTCap,
+ sizeof(pstaParams->HTCap));
+ else
+ cdf_mem_set(&tdlsAddStaCmdInfo->HTCap,
+ sizeof(pstaParams->HTCap), 0);
+
+ tdlsAddStaCmdInfo->vhtcap_present =
+ pstaParams->vhtcap_present;
+ if (pstaParams->vhtcap_present)
+ cdf_mem_copy(&tdlsAddStaCmdInfo->VHTCap,
+ &pstaParams->VHTCap,
+ sizeof(pstaParams->VHTCap));
+ else
+ cdf_mem_set(&tdlsAddStaCmdInfo->VHTCap,
+ sizeof(pstaParams->VHTCap), 0);
+
+ tdlsAddStaCmdInfo->supportedRatesLen =
+ pstaParams->supported_rates_len;
+
+ if (0 != pstaParams->supported_rates_len)
+ cdf_mem_copy(&tdlsAddStaCmdInfo->supportedRates,
+ pstaParams->supported_rates,
+ pstaParams->supported_rates_len);
+
+ tdlsAddStaCmd->command = eSmeCommandTdlsAddPeer;
+ tdlsAddStaCmd->u.tdlsCmd.size =
+ sizeof(tTdlsAddStaCmdInfo);
+ sme_push_command(pMac, tdlsAddStaCmd, false);
+ status = CDF_STATUS_SUCCESS;
+ }
+ }
+
+ return status;
+}
+
+/*
+ * TDLS request API, called from HDD to Send Link Establishment Parameters
+ */
+CDF_STATUS csr_tdls_send_link_establish_params(tHalHandle hHal,
+ uint8_t sessionId,
+ const tSirMacAddr peerMac,
+ tCsrTdlsLinkEstablishParams *
+ tdlsLinkEstablishParams)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ tSmeCmd *tdlsLinkEstablishCmd;
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ /* If connected and in Infra. Only then allow this */
+ if (CSR_IS_SESSION_VALID(pMac, sessionId) &&
+ csr_is_conn_state_connected_infra(pMac, sessionId) &&
+ (NULL != peerMac)) {
+ tdlsLinkEstablishCmd = csr_get_command_buffer(pMac);
+
+ if (tdlsLinkEstablishCmd) {
+ tTdlsLinkEstablishCmdInfo *tdlsLinkEstablishCmdInfo =
+ &tdlsLinkEstablishCmd->u.tdlsCmd.u.
+ tdlsLinkEstablishCmdInfo;
+
+ tdlsLinkEstablishCmd->sessionId = sessionId;
+
+ cdf_mem_copy(tdlsLinkEstablishCmdInfo->peerMac,
+ peerMac, sizeof(tSirMacAddr));
+ tdlsLinkEstablishCmdInfo->isBufSta =
+ tdlsLinkEstablishParams->isBufSta;
+ tdlsLinkEstablishCmdInfo->isResponder =
+ tdlsLinkEstablishParams->isResponder;
+ tdlsLinkEstablishCmdInfo->maxSp =
+ tdlsLinkEstablishParams->maxSp;
+ tdlsLinkEstablishCmdInfo->uapsdQueues =
+ tdlsLinkEstablishParams->uapsdQueues;
+ tdlsLinkEstablishCmdInfo->isOffChannelSupported =
+ tdlsLinkEstablishParams->isOffChannelSupported;
+ cdf_mem_copy(tdlsLinkEstablishCmdInfo->
+ supportedChannels,
+ tdlsLinkEstablishParams->supportedChannels,
+ tdlsLinkEstablishParams->
+ supportedChannelsLen);
+ tdlsLinkEstablishCmdInfo->supportedChannelsLen =
+ tdlsLinkEstablishParams->supportedChannelsLen;
+ cdf_mem_copy(tdlsLinkEstablishCmdInfo->
+ supportedOperClasses,
+ tdlsLinkEstablishParams->
+ supportedOperClasses,
+ tdlsLinkEstablishParams->
+ supportedOperClassesLen);
+ tdlsLinkEstablishCmdInfo->supportedOperClassesLen =
+ tdlsLinkEstablishParams->supportedOperClassesLen;
+ tdlsLinkEstablishCmdInfo->isResponder =
+ tdlsLinkEstablishParams->isResponder;
+ tdlsLinkEstablishCmdInfo->maxSp =
+ tdlsLinkEstablishParams->maxSp;
+ tdlsLinkEstablishCmdInfo->uapsdQueues =
+ tdlsLinkEstablishParams->uapsdQueues;
+ tdlsLinkEstablishCmd->command =
+ eSmeCommandTdlsLinkEstablish;
+ tdlsLinkEstablishCmd->u.tdlsCmd.size =
+ sizeof(tTdlsLinkEstablishCmdInfo);
+ sme_push_command(pMac, tdlsLinkEstablishCmd, false);
+ status = CDF_STATUS_SUCCESS;
+ }
+ }
+
+ return status;
+}
+
+/*
+ * TDLS request API, called from HDD to add a TDLS peer
+ */
+CDF_STATUS csr_tdls_add_peer_sta(tHalHandle hHal, uint8_t sessionId,
+ const tSirMacAddr peerMac)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ tSmeCmd *tdlsAddStaCmd;
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+
+ /* If connected and in Infra. Only then allow this */
+ if (CSR_IS_SESSION_VALID(pMac, sessionId) &&
+ csr_is_conn_state_connected_infra(pMac, sessionId) &&
+ (NULL != peerMac)) {
+ tdlsAddStaCmd = csr_get_command_buffer(pMac);
+
+ if (tdlsAddStaCmd) {
+ tTdlsAddStaCmdInfo *tdlsAddStaCmdInfo =
+ &tdlsAddStaCmd->u.tdlsCmd.u.tdlsAddStaCmdInfo;
+
+ tdlsAddStaCmd->sessionId = sessionId;
+ tdlsAddStaCmdInfo->tdlsAddOper = TDLS_OPER_ADD;
+
+ cdf_mem_copy(tdlsAddStaCmdInfo->peerMac,
+ peerMac, sizeof(tSirMacAddr));
+
+ tdlsAddStaCmd->command = eSmeCommandTdlsAddPeer;
+ tdlsAddStaCmd->u.tdlsCmd.size =
+ sizeof(tTdlsAddStaCmdInfo);
+ sme_push_command(pMac, tdlsAddStaCmd, false);
+ status = CDF_STATUS_SUCCESS;
+ }
+ }
+
+ return status;
+}
+
+/*
+ * TDLS request API, called from HDD to delete a TDLS peer
+ */
+CDF_STATUS csr_tdls_del_peer_sta(tHalHandle hHal, uint8_t sessionId,
+ const tSirMacAddr peerMac)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ tSmeCmd *tdlsDelStaCmd;
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+
+ /* If connected and in Infra. Only then allow this */
+ if (CSR_IS_SESSION_VALID(pMac, sessionId) &&
+ csr_is_conn_state_connected_infra(pMac, sessionId) &&
+ (NULL != peerMac)) {
+ tdlsDelStaCmd = csr_get_command_buffer(pMac);
+
+ if (tdlsDelStaCmd) {
+ tTdlsDelStaCmdInfo *tdlsDelStaCmdInfo =
+ &tdlsDelStaCmd->u.tdlsCmd.u.tdlsDelStaCmdInfo;
+
+ tdlsDelStaCmd->sessionId = sessionId;
+
+ cdf_mem_copy(tdlsDelStaCmdInfo->peerMac,
+ peerMac, sizeof(tSirMacAddr));
+
+ tdlsDelStaCmd->command = eSmeCommandTdlsDelPeer;
+ tdlsDelStaCmd->u.tdlsCmd.size =
+ sizeof(tTdlsDelStaCmdInfo);
+ sme_push_command(pMac, tdlsDelStaCmd, false);
+ status = CDF_STATUS_SUCCESS;
+ }
+ }
+
+ return status;
+}
+
+/*
+ * TDLS messages sent to PE .
+ */
+CDF_STATUS tdls_send_message(tpAniSirGlobal pMac, uint16_t msg_type,
+ void *msg_data, uint32_t msg_size)
+{
+
+ tSirMbMsg *pMsg = (tSirMbMsg *) msg_data;
+ pMsg->type = msg_type;
+ pMsg->msgLen = (uint16_t) (msg_size);
+
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ ("sending msg = %d"), pMsg->type);
+ /* Send message. */
+ if (cds_send_mb_message_to_mac(pMsg) != CDF_STATUS_SUCCESS) {
+ sms_log(pMac, LOGE, FL("Cannot send message"));
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ return CDF_STATUS_SUCCESS;
+}
+
+CDF_STATUS csr_tdls_process_send_mgmt(tpAniSirGlobal pMac, tSmeCmd *cmd)
+{
+ tTdlsSendMgmtCmdInfo *tdlsSendMgmtCmdInfo =
+ &cmd->u.tdlsCmd.u.tdlsSendMgmtCmdInfo;
+ tSirTdlsSendMgmtReq *tdlsSendMgmtReq = NULL;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, cmd->sessionId);
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+
+ if (NULL == pSession) {
+ sms_log(pMac, LOGE, FL("pSession is NULL"));
+ return CDF_STATUS_E_FAILURE;
+ }
+ if (NULL == pSession->pConnectBssDesc) {
+ sms_log(pMac, LOGE, FL("BSS Description is not present"));
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ tdlsSendMgmtReq =
+ cdf_mem_malloc(sizeof(tSirTdlsSendMgmtReq) +
+ tdlsSendMgmtCmdInfo->len);
+ if (NULL == tdlsSendMgmtReq)
+ status = CDF_STATUS_E_NOMEM;
+ else
+ status = CDF_STATUS_SUCCESS;
+
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE, FL("alloc failed"));
+ CDF_ASSERT(0);
+ return status;
+ }
+ tdlsSendMgmtReq->sessionId = cmd->sessionId;
+ /* Using dialog as transactionId. This can be used to match response with request */
+ tdlsSendMgmtReq->transactionId = tdlsSendMgmtCmdInfo->dialog;
+ tdlsSendMgmtReq->reqType = tdlsSendMgmtCmdInfo->frameType;
+ tdlsSendMgmtReq->dialog = tdlsSendMgmtCmdInfo->dialog;
+ tdlsSendMgmtReq->statusCode = tdlsSendMgmtCmdInfo->statusCode;
+ tdlsSendMgmtReq->responder = tdlsSendMgmtCmdInfo->responder;
+ tdlsSendMgmtReq->peerCapability = tdlsSendMgmtCmdInfo->peerCapability;
+
+ cdf_mem_copy(tdlsSendMgmtReq->bssid,
+ pSession->pConnectBssDesc->bssId, sizeof(tSirMacAddr));
+
+ cdf_mem_copy(tdlsSendMgmtReq->peerMac,
+ tdlsSendMgmtCmdInfo->peerMac, sizeof(tSirMacAddr));
+
+ if (tdlsSendMgmtCmdInfo->len && tdlsSendMgmtCmdInfo->buf) {
+ cdf_mem_copy(tdlsSendMgmtReq->addIe, tdlsSendMgmtCmdInfo->buf,
+ tdlsSendMgmtCmdInfo->len);
+
+ }
+ /* Send the request to PE. */
+ sms_log(pMac, LOG1, "sending TDLS Mgmt Frame req to PE ");
+ status = tdls_send_message(pMac, eWNI_SME_TDLS_SEND_MGMT_REQ,
+ (void *)tdlsSendMgmtReq,
+ sizeof(tSirTdlsSendMgmtReq) +
+ tdlsSendMgmtCmdInfo->len);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE, FL("Failed to send request to MAC"));
+ }
+ if (tdlsSendMgmtCmdInfo->len && tdlsSendMgmtCmdInfo->buf) {
+ /* Done with the buf. Free it. */
+ cdf_mem_free(tdlsSendMgmtCmdInfo->buf);
+ tdlsSendMgmtCmdInfo->buf = NULL;
+ tdlsSendMgmtCmdInfo->len = 0;
+ }
+
+ return status;
+}
+
+CDF_STATUS csr_tdls_process_add_sta(tpAniSirGlobal pMac, tSmeCmd *cmd)
+{
+ tTdlsAddStaCmdInfo *tdlsAddStaCmdInfo =
+ &cmd->u.tdlsCmd.u.tdlsAddStaCmdInfo;
+ tSirTdlsAddStaReq *tdlsAddStaReq = NULL;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, cmd->sessionId);
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+
+ if (NULL == pSession) {
+ sms_log(pMac, LOGE, FL("pSession is NULL"));
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ if (NULL == pSession->pConnectBssDesc) {
+ sms_log(pMac, LOGE, FL("BSS description is not present"));
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ tdlsAddStaReq = cdf_mem_malloc(sizeof(tSirTdlsAddStaReq));
+ if (NULL == tdlsAddStaReq)
+ status = CDF_STATUS_E_NOMEM;
+ else
+ status = CDF_STATUS_SUCCESS;
+
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE, FL("alloc failed"));
+ CDF_ASSERT(0);
+ return status;
+ }
+ tdlsAddStaReq->sessionId = cmd->sessionId;
+ tdlsAddStaReq->tdlsAddOper = tdlsAddStaCmdInfo->tdlsAddOper;
+ /* Using dialog as transactionId. This can be used to match response with request */
+ tdlsAddStaReq->transactionId = 0;
+
+ cdf_mem_copy(tdlsAddStaReq->bssid,
+ pSession->pConnectBssDesc->bssId, sizeof(tSirMacAddr));
+
+ cdf_mem_copy(tdlsAddStaReq->peerMac,
+ tdlsAddStaCmdInfo->peerMac, sizeof(tSirMacAddr));
+
+ tdlsAddStaReq->capability = tdlsAddStaCmdInfo->capability;
+ tdlsAddStaReq->uapsd_queues = tdlsAddStaCmdInfo->uapsdQueues;
+ tdlsAddStaReq->max_sp = tdlsAddStaCmdInfo->maxSp;
+
+ cdf_mem_copy(tdlsAddStaReq->extn_capability,
+ tdlsAddStaCmdInfo->extnCapability, SIR_MAC_MAX_EXTN_CAP);
+ tdlsAddStaReq->htcap_present = tdlsAddStaCmdInfo->htcap_present;
+ cdf_mem_copy(&tdlsAddStaReq->htCap,
+ &tdlsAddStaCmdInfo->HTCap,
+ sizeof(tdlsAddStaCmdInfo->HTCap));
+ tdlsAddStaReq->vhtcap_present = tdlsAddStaCmdInfo->vhtcap_present;
+ cdf_mem_copy(&tdlsAddStaReq->vhtCap,
+ &tdlsAddStaCmdInfo->VHTCap,
+ sizeof(tdlsAddStaCmdInfo->VHTCap));
+ tdlsAddStaReq->supported_rates_length =
+ tdlsAddStaCmdInfo->supportedRatesLen;
+ cdf_mem_copy(&tdlsAddStaReq->supported_rates,
+ tdlsAddStaCmdInfo->supportedRates,
+ tdlsAddStaCmdInfo->supportedRatesLen);
+
+ /* Send the request to PE. */
+ sms_log(pMac, LOGE, "sending TDLS Add Sta req to PE ");
+ status = tdls_send_message(pMac, eWNI_SME_TDLS_ADD_STA_REQ,
+ (void *)tdlsAddStaReq,
+ sizeof(tSirTdlsAddStaReq));
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE, FL("Failed to send request to MAC"));
+ }
+ return status;
+}
+
+CDF_STATUS csr_tdls_process_del_sta(tpAniSirGlobal pMac, tSmeCmd *cmd)
+{
+ tTdlsDelStaCmdInfo *tdlsDelStaCmdInfo =
+ &cmd->u.tdlsCmd.u.tdlsDelStaCmdInfo;
+ tSirTdlsDelStaReq *tdlsDelStaReq = NULL;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, cmd->sessionId);
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+
+ if (NULL == pSession) {
+ sms_log(pMac, LOGE, FL("pSession is NULL"));
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ if (NULL == pSession->pConnectBssDesc) {
+ sms_log(pMac, LOGE, FL("BSS description is not present"));
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ tdlsDelStaReq = cdf_mem_malloc(sizeof(tSirTdlsDelStaReq));
+ if (NULL == tdlsDelStaReq)
+ status = CDF_STATUS_E_NOMEM;
+ else
+ status = CDF_STATUS_SUCCESS;
+
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE, FL("alloc failed"));
+ CDF_ASSERT(0);
+ return status;
+ }
+ tdlsDelStaReq->sessionId = cmd->sessionId;
+ /* Using dialog as transactionId. This can be used to match response with request */
+ tdlsDelStaReq->transactionId = 0;
+
+ cdf_mem_copy(tdlsDelStaReq->bssid,
+ pSession->pConnectBssDesc->bssId, sizeof(tSirMacAddr));
+
+ cdf_mem_copy(tdlsDelStaReq->peerMac,
+ tdlsDelStaCmdInfo->peerMac, sizeof(tSirMacAddr));
+
+ /* Send the request to PE. */
+ sms_log(pMac, LOG1,
+ "sending TDLS Del Sta " MAC_ADDRESS_STR " req to PE",
+ MAC_ADDR_ARRAY(tdlsDelStaCmdInfo->peerMac));
+ status = tdls_send_message(pMac, eWNI_SME_TDLS_DEL_STA_REQ,
+ (void *)tdlsDelStaReq,
+ sizeof(tSirTdlsDelStaReq));
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE, FL("Failed to send request to MAC"));
+ }
+ return status;
+}
+
+/*
+ * commands received from CSR
+ */
+CDF_STATUS csr_tdls_process_cmd(tpAniSirGlobal pMac, tSmeCmd *cmd)
+{
+ eSmeCommandType cmdType = cmd->command;
+ bool status = true;
+ switch (cmdType) {
+ case eSmeCommandTdlsSendMgmt:
+ {
+ status = csr_tdls_process_send_mgmt(pMac, cmd);
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ status = false;
+ }
+ }
+ break;
+ case eSmeCommandTdlsAddPeer:
+ {
+ status = csr_tdls_process_add_sta(pMac, cmd);
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ status = false;
+ }
+ }
+ break;
+ case eSmeCommandTdlsDelPeer:
+ {
+ status = csr_tdls_process_del_sta(pMac, cmd);
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ status = false;
+ }
+ }
+ break;
+ case eSmeCommandTdlsLinkEstablish:
+ {
+ status = csr_tdls_process_link_establish(pMac, cmd);
+ if (CDF_IS_STATUS_SUCCESS(status)) {
+ status = false;
+ }
+ }
+ break;
+ default:
+ {
+ /* TODO: Add defualt handling */
+ break;
+ }
+
+ }
+ return status;
+}
+
+CDF_STATUS csr_tdls_process_link_establish(tpAniSirGlobal pMac, tSmeCmd *cmd)
+{
+ tTdlsLinkEstablishCmdInfo *tdlsLinkEstablishCmdInfo =
+ &cmd->u.tdlsCmd.u.tdlsLinkEstablishCmdInfo;
+ tSirTdlsLinkEstablishReq *tdlsLinkEstablishReq = NULL;
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, cmd->sessionId);
+
+ if (NULL == pSession) {
+ sms_log(pMac, LOGE, FL("pSession is NULL"));
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ tdlsLinkEstablishReq = cdf_mem_malloc(sizeof(tSirTdlsLinkEstablishReq));
+
+ if (tdlsLinkEstablishReq == NULL) {
+ sms_log(pMac, LOGE, FL("alloc failed"));
+ CDF_ASSERT(0);
+ return CDF_STATUS_E_NOMEM;
+ }
+ tdlsLinkEstablishReq->sessionId = cmd->sessionId;
+ /* Using dialog as transactionId. This can be used to match response with request */
+ tdlsLinkEstablishReq->transactionId = 0;
+ cdf_mem_copy(tdlsLinkEstablishReq->peerMac,
+ tdlsLinkEstablishCmdInfo->peerMac, sizeof(tSirMacAddr));
+ cdf_mem_copy(tdlsLinkEstablishReq->bssid,
+ pSession->pConnectBssDesc->bssId, sizeof(tSirMacAddr));
+ cdf_mem_copy(tdlsLinkEstablishReq->supportedChannels,
+ tdlsLinkEstablishCmdInfo->supportedChannels,
+ tdlsLinkEstablishCmdInfo->supportedChannelsLen);
+ tdlsLinkEstablishReq->supportedChannelsLen =
+ tdlsLinkEstablishCmdInfo->supportedChannelsLen;
+ cdf_mem_copy(tdlsLinkEstablishReq->supportedOperClasses,
+ tdlsLinkEstablishCmdInfo->supportedOperClasses,
+ tdlsLinkEstablishCmdInfo->supportedOperClassesLen);
+ tdlsLinkEstablishReq->supportedOperClassesLen =
+ tdlsLinkEstablishCmdInfo->supportedOperClassesLen;
+ tdlsLinkEstablishReq->isBufSta = tdlsLinkEstablishCmdInfo->isBufSta;
+ tdlsLinkEstablishReq->isResponder =
+ tdlsLinkEstablishCmdInfo->isResponder;
+ tdlsLinkEstablishReq->uapsdQueues =
+ tdlsLinkEstablishCmdInfo->uapsdQueues;
+ tdlsLinkEstablishReq->maxSp = tdlsLinkEstablishCmdInfo->maxSp;
+
+ /* Send the request to PE. */
+ sms_log(pMac, LOGE, "sending TDLS Link Establish Request to PE \n");
+ status = tdls_send_message(pMac, eWNI_SME_TDLS_LINK_ESTABLISH_REQ,
+ (void *)tdlsLinkEstablishReq,
+ sizeof(tSirTdlsLinkEstablishReq));
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ sms_log(pMac, LOGE, FL("Failed to send request to MAC\n"));
+ }
+ return status;
+}
+
+/*
+ * TDLS Message processor, will be called after TDLS message recieved from
+ * PE
+ */
+CDF_STATUS tdls_msg_processor(tpAniSirGlobal pMac, uint16_t msgType,
+ void *pMsgBuf)
+{
+ tCsrRoamInfo roamInfo = { 0 };
+ eCsrRoamResult roamResult;
+ tSirTdlsAddStaRsp *addStaRsp = (tSirTdlsAddStaRsp *) pMsgBuf;
+ tSirTdlsDelStaRsp *delStaRsp = (tSirTdlsDelStaRsp *) pMsgBuf;
+ tpSirTdlsDelStaInd pSirTdlsDelStaInd = (tpSirTdlsDelStaInd) pMsgBuf;
+ tpSirTdlsDelAllPeerInd pSirTdlsDelAllPeerInd =
+ (tpSirTdlsDelAllPeerInd) pMsgBuf;
+ tpSirMgmtTxCompletionInd tdls_tx_comp_ind =
+ (tpSirMgmtTxCompletionInd) pMsgBuf;
+ tSirTdlsLinkEstablishReqRsp *linkEstablishReqRsp =
+ (tSirTdlsLinkEstablishReqRsp *) pMsgBuf;
+ tSirTdlsEventnotify *tevent = (tSirTdlsEventnotify *) pMsgBuf;
+
+ switch (msgType) {
+ case eWNI_SME_TDLS_SEND_MGMT_RSP:
+ /* remove pending eSmeCommandTdlsDiscovery command */
+ csr_tdls_remove_sme_cmd(pMac, eSmeCommandTdlsSendMgmt);
+ break;
+ case eWNI_SME_TDLS_ADD_STA_RSP:
+ cdf_mem_copy(&roamInfo.peerMac, addStaRsp->peerMac,
+ sizeof(tSirMacAddr));
+ roamInfo.staId = addStaRsp->staId;
+ roamInfo.ucastSig = addStaRsp->ucastSig;
+ roamInfo.bcastSig = addStaRsp->bcastSig;
+ roamInfo.statusCode = addStaRsp->statusCode;
+ /*
+ * register peer with TL, we have to go through HDD as
+ * this is the only way to register any STA with TL.
+ */
+ if (addStaRsp->tdlsAddOper == TDLS_OPER_ADD)
+ roamResult = eCSR_ROAM_RESULT_ADD_TDLS_PEER;
+ else /* addStaRsp->tdlsAddOper must be TDLS_OPER_UPDATE */
+ roamResult = eCSR_ROAM_RESULT_UPDATE_TDLS_PEER;
+ csr_roam_call_callback(pMac, addStaRsp->sessionId,
+ &roamInfo, 0, eCSR_ROAM_TDLS_STATUS_UPDATE,
+ roamResult);
+
+ /* remove pending eSmeCommandTdlsDiscovery command */
+ csr_tdls_remove_sme_cmd(pMac, eSmeCommandTdlsAddPeer);
+ break;
+ case eWNI_SME_TDLS_DEL_STA_RSP:
+ cdf_mem_copy(&roamInfo.peerMac, delStaRsp->peerMac,
+ sizeof(tSirMacAddr));
+ roamInfo.staId = delStaRsp->staId;
+ roamInfo.statusCode = delStaRsp->statusCode;
+ /*
+ * register peer with TL, we have to go through HDD as
+ * this is the only way to register any STA with TL.
+ */
+ csr_roam_call_callback(pMac, delStaRsp->sessionId,
+ &roamInfo, 0,
+ eCSR_ROAM_TDLS_STATUS_UPDATE,
+ eCSR_ROAM_RESULT_DELETE_TDLS_PEER);
+
+ csr_tdls_remove_sme_cmd(pMac, eSmeCommandTdlsDelPeer);
+ break;
+ case eWNI_SME_TDLS_DEL_STA_IND:
+ cdf_mem_copy(&roamInfo.peerMac,
+ pSirTdlsDelStaInd->peerMac,
+ sizeof(tSirMacAddr));
+ roamInfo.staId = pSirTdlsDelStaInd->staId;
+ roamInfo.reasonCode = pSirTdlsDelStaInd->reasonCode;
+
+ /* Sending the TEARDOWN indication to HDD. */
+ csr_roam_call_callback(pMac,
+ pSirTdlsDelStaInd->sessionId, &roamInfo,
+ 0, eCSR_ROAM_TDLS_STATUS_UPDATE,
+ eCSR_ROAM_RESULT_TEARDOWN_TDLS_PEER_IND);
+ break;
+ case eWNI_SME_TDLS_DEL_ALL_PEER_IND:
+ /* Sending the TEARDOWN indication to HDD. */
+ csr_roam_call_callback(pMac,
+ pSirTdlsDelAllPeerInd->sessionId,
+ &roamInfo, 0,
+ eCSR_ROAM_TDLS_STATUS_UPDATE,
+ eCSR_ROAM_RESULT_DELETE_ALL_TDLS_PEER_IND);
+ break;
+ case eWNI_SME_MGMT_FRM_TX_COMPLETION_IND:
+ roamInfo.reasonCode =
+ tdls_tx_comp_ind->txCompleteStatus;
+
+ csr_roam_call_callback(pMac,
+ tdls_tx_comp_ind->sessionId,
+ &roamInfo, 0,
+ eCSR_ROAM_RESULT_MGMT_TX_COMPLETE_IND,
+ 0);
+ break;
+ case eWNI_SME_TDLS_LINK_ESTABLISH_RSP:
+ csr_roam_call_callback(pMac,
+ linkEstablishReqRsp->sessionId,
+ &roamInfo, 0,
+ eCSR_ROAM_TDLS_STATUS_UPDATE,
+ eCSR_ROAM_RESULT_LINK_ESTABLISH_REQ_RSP);
+ /* remove pending eSmeCommandTdlsLinkEstablish command */
+ csr_tdls_remove_sme_cmd(pMac, eSmeCommandTdlsLinkEstablish);
+ break;
+ case eWNI_SME_TDLS_SHOULD_DISCOVER:
+ cdf_mem_copy(&roamInfo.peerMac, tevent->peerMac,
+ sizeof(tSirMacAddr));
+ roamInfo.reasonCode = tevent->peer_reason;
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ "%s: eWNI_SME_TDLS_SHOULD_DISCOVER for peer mac: "
+ MAC_ADDRESS_STR " peer_reason: %d",
+ __func__, MAC_ADDR_ARRAY(tevent->peerMac),
+ tevent->peer_reason);
+ csr_roam_call_callback(pMac, tevent->sessionId, &roamInfo,
+ 0, eCSR_ROAM_TDLS_STATUS_UPDATE,
+ eCSR_ROAM_RESULT_TDLS_SHOULD_DISCOVER);
+ break;
+ case eWNI_SME_TDLS_SHOULD_TEARDOWN:
+ cdf_mem_copy(&roamInfo.peerMac, tevent->peerMac,
+ sizeof(tSirMacAddr));
+ roamInfo.reasonCode = tevent->peer_reason;
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ "%s: eWNI_SME_TDLS_SHOULD_TEARDOWN for peer mac: "
+ MAC_ADDRESS_STR " peer_reason: %d",
+ __func__, MAC_ADDR_ARRAY(tevent->peerMac),
+ tevent->peer_reason);
+ csr_roam_call_callback(pMac, tevent->sessionId, &roamInfo,
+ 0, eCSR_ROAM_TDLS_STATUS_UPDATE,
+ eCSR_ROAM_RESULT_TDLS_SHOULD_TEARDOWN);
+ break;
+ case eWNI_SME_TDLS_PEER_DISCONNECTED:
+ cdf_mem_copy(&roamInfo.peerMac, tevent->peerMac,
+ sizeof(tSirMacAddr));
+ roamInfo.reasonCode = tevent->peer_reason;
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ "%s: eWNI_SME_TDLS_PEER_DISCONNECTED for peer mac: "
+ MAC_ADDRESS_STR " peer_reason: %d",
+ __func__, MAC_ADDR_ARRAY(tevent->peerMac),
+ tevent->peer_reason);
+ csr_roam_call_callback(pMac, tevent->sessionId, &roamInfo,
+ 0, eCSR_ROAM_TDLS_STATUS_UPDATE,
+ eCSR_ROAM_RESULT_TDLS_SHOULD_PEER_DISCONNECTED);
+ break;
+ default:
+ break;
+ }
+
+ return CDF_STATUS_SUCCESS;
+}
+#endif
diff --git a/core/sme/src/csr/csr_util.c b/core/sme/src/csr/csr_util.c
new file mode 100644
index 0000000..eea8cbd
--- /dev/null
+++ b/core/sme/src/csr/csr_util.c
@@ -0,0 +1,5626 @@
+/*
+ * 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_util.c
+
+ Implementation supporting routines for CSR.
+ ========================================================================== */
+
+#include "ani_global.h"
+
+#include "csr_support.h"
+#include "csr_inside_api.h"
+#include "sms_debug.h"
+#include "sme_qos_internal.h"
+#include "wma_types.h"
+#include "cds_utils.h"
+
+
+uint8_t csr_wpa_oui[][CSR_WPA_OUI_SIZE] = {
+ {0x00, 0x50, 0xf2, 0x00}
+ ,
+ {0x00, 0x50, 0xf2, 0x01}
+ ,
+ {0x00, 0x50, 0xf2, 0x02}
+ ,
+ {0x00, 0x50, 0xf2, 0x03}
+ ,
+ {0x00, 0x50, 0xf2, 0x04}
+ ,
+ {0x00, 0x50, 0xf2, 0x05}
+ ,
+#ifdef FEATURE_WLAN_ESE
+ {0x00, 0x40, 0x96, 0x00}
+ , /* CCKM */
+#endif /* FEATURE_WLAN_ESE */
+};
+
+uint8_t csr_rsn_oui[][CSR_RSN_OUI_SIZE] = {
+ {0x00, 0x0F, 0xAC, 0x00}
+ , /* group cipher */
+ {0x00, 0x0F, 0xAC, 0x01}
+ , /* WEP-40 or RSN */
+ {0x00, 0x0F, 0xAC, 0x02}
+ , /* TKIP or RSN-PSK */
+ {0x00, 0x0F, 0xAC, 0x03}
+ , /* Reserved */
+ {0x00, 0x0F, 0xAC, 0x04}
+ , /* AES-CCMP */
+ {0x00, 0x0F, 0xAC, 0x05}
+ , /* WEP-104 */
+ {0x00, 0x40, 0x96, 0x00}
+ , /* CCKM */
+ {0x00, 0x0F, 0xAC, 0x06}
+ , /* BIP (encryption type) or
+ RSN-PSK-SHA256 (authentication type) */
+ /* RSN-8021X-SHA256 (authentication type) */
+ {0x00, 0x0F, 0xAC, 0x05}
+};
+
+#ifdef FEATURE_WLAN_WAPI
+uint8_t csr_wapi_oui[][CSR_WAPI_OUI_SIZE] = {
+ {0x00, 0x14, 0x72, 0x00}
+ , /* Reserved */
+ {0x00, 0x14, 0x72, 0x01}
+ , /* WAI certificate or SMS4 */
+ {0x00, 0x14, 0x72, 0x02} /* WAI PSK */
+};
+#endif /* FEATURE_WLAN_WAPI */
+uint8_t csr_wme_info_oui[CSR_WME_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x02 };
+uint8_t csr_wme_parm_oui[CSR_WME_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x02 };
+
+
+/* ////////////////////////////////////////////////////////////////////// */
+
+/**
+ * \var g_phy_rates_suppt
+ *
+ * \brief Rate support lookup table
+ *
+ *
+ * This is a lookup table indexing rates & configuration parameters to
+ * support. Given a rate (in unites of 0.5Mpbs) & three bools (MIMO
+ * Enabled, Channel Bonding Enabled, & Concatenation Enabled), one can
+ * determine whether the given rate is supported by computing two
+ * indices. The first maps the rate to table row as indicated below
+ * (i.e. eHddSuppRate_6Mbps maps to row zero, eHddSuppRate_9Mbps to row
+ * 1, and so on). Index two can be computed like so:
+ *
+ * \code
+ * idx2 = ( fEsf ? 0x4 : 0x0 ) |
+ * ( fCb ? 0x2 : 0x0 ) |
+ * ( fMimo ? 0x1 : 0x0 );
+ * \endcode
+ *
+ *
+ * Given that:
+ *
+ * \code
+ * fSupported = g_phy_rates_suppt[idx1][idx2];
+ * \endcode
+ *
+ *
+ * This table is based on the document "PHY Supported Rates.doc". This
+ * table is permissive in that a rate is reflected as being supported
+ * even when turning off an enabled feature would be required. For
+ * instance, "PHY Supported Rates" lists 42Mpbs as unsupported when CB,
+ * ESF, & MIMO are all on. However, if we turn off either of CB or
+ * MIMO, it then becomes supported. Therefore, we mark it as supported
+ * even in index 7 of this table.
+ *
+ *
+ */
+
+static const bool g_phy_rates_suppt[24][8] = {
+
+ /* SSF SSF SSF SSF ESF ESF ESF ESF */
+ /* SIMO MIMO SIMO MIMO SIMO MIMO SIMO MIMO */
+ /* No CB No CB CB CB No CB No CB CB CB */
+ {true, true, true, true, true, true, true, true}, /* 6Mbps */
+ {true, true, true, true, true, true, true, true}, /* 9Mbps */
+ {true, true, true, true, true, true, true, true}, /* 12Mbps */
+ {true, true, true, true, true, true, true, true}, /* 18Mbps */
+ {false, false, true, true, false, false, true, true}, /* 20Mbps */
+ {true, true, true, true, true, true, true, true}, /* 24Mbps */
+ {true, true, true, true, true, true, true, true}, /* 36Mbps */
+ {false, false, true, true, false, true, true, true}, /* 40Mbps */
+ {false, false, true, true, false, true, true, true}, /* 42Mbps */
+ {true, true, true, true, true, true, true, true}, /* 48Mbps */
+ {true, true, true, true, true, true, true, true}, /* 54Mbps */
+ {false, true, true, true, false, true, true, true}, /* 72Mbps */
+ {false, false, true, true, false, true, true, true}, /* 80Mbps */
+ {false, false, true, true, false, true, true, true}, /* 84Mbps */
+ {false, true, true, true, false, true, true, true}, /* 96Mbps */
+ {false, true, true, true, false, true, true, true}, /* 108Mbps */
+ {false, false, true, true, false, true, true, true}, /* 120Mbps */
+ {false, false, true, true, false, true, true, true}, /* 126Mbps */
+ {false, false, false, true, false, false, false, true}, /* 144Mbps */
+ {false, false, false, true, false, false, false, true}, /* 160Mbps */
+ {false, false, false, true, false, false, false, true}, /* 168Mbps */
+ {false, false, false, true, false, false, false, true}, /* 192Mbps */
+ {false, false, false, true, false, false, false, true}, /* 216Mbps */
+ {false, false, false, true, false, false, false, true}, /* 240Mbps */
+
+};
+
+#define CASE_RETURN_STR(n) {\
+ case (n): return (# n);\
+}
+
+const char *get_e_roam_cmd_status_str(eRoamCmdStatus val)
+{
+ switch (val) {
+ CASE_RETURN_STR(eCSR_ROAM_CANCELLED);
+ CASE_RETURN_STR(eCSR_ROAM_ROAMING_START);
+ CASE_RETURN_STR(eCSR_ROAM_ROAMING_COMPLETION);
+ CASE_RETURN_STR(eCSR_ROAM_ASSOCIATION_START);
+ CASE_RETURN_STR(eCSR_ROAM_ASSOCIATION_COMPLETION);
+ CASE_RETURN_STR(eCSR_ROAM_DISASSOCIATED);
+ CASE_RETURN_STR(eCSR_ROAM_SHOULD_ROAM);
+ CASE_RETURN_STR(eCSR_ROAM_SCAN_FOUND_NEW_BSS);
+ CASE_RETURN_STR(eCSR_ROAM_LOSTLINK);
+ default:
+ return "unknown";
+ }
+}
+
+const char *get_e_csr_roam_result_str(eCsrRoamResult val)
+{
+ switch (val) {
+ CASE_RETURN_STR(eCSR_ROAM_RESULT_NONE);
+ CASE_RETURN_STR(eCSR_ROAM_RESULT_FAILURE);
+ CASE_RETURN_STR(eCSR_ROAM_RESULT_ASSOCIATED);
+ CASE_RETURN_STR(eCSR_ROAM_RESULT_NOT_ASSOCIATED);
+ CASE_RETURN_STR(eCSR_ROAM_RESULT_MIC_FAILURE);
+ CASE_RETURN_STR(eCSR_ROAM_RESULT_FORCED);
+ CASE_RETURN_STR(eCSR_ROAM_RESULT_DISASSOC_IND);
+ CASE_RETURN_STR(eCSR_ROAM_RESULT_DEAUTH_IND);
+ CASE_RETURN_STR(eCSR_ROAM_RESULT_CAP_CHANGED);
+ CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_CONNECT);
+ CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_INACTIVE);
+ CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_NEW_PEER);
+ CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_COALESCED);
+ default:
+ return "unknown";
+ }
+}
+
+bool csr_get_bss_id_bss_desc(tHalHandle hHal, tSirBssDescription *pSirBssDesc,
+ struct cdf_mac_addr *pBssId)
+{
+ cdf_mem_copy(pBssId, &pSirBssDesc->bssId[0],
+ sizeof(struct cdf_mac_addr));
+ return true;
+}
+
+bool csr_is_bss_id_equal(tHalHandle hHal, tSirBssDescription *pSirBssDesc1,
+ tSirBssDescription *pSirBssDesc2)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ bool fEqual = false;
+ struct cdf_mac_addr bssId1;
+ struct cdf_mac_addr bssId2;
+
+ do {
+ if (!pSirBssDesc1)
+ break;
+ if (!pSirBssDesc2)
+ break;
+
+ if (!csr_get_bss_id_bss_desc(pMac, pSirBssDesc1, &bssId1))
+ break;
+ if (!csr_get_bss_id_bss_desc(pMac, pSirBssDesc2, &bssId2))
+ break;
+
+ fEqual = cdf_is_macaddr_equal(&bssId1, &bssId2);
+ } while (0);
+
+ return fEqual;
+}
+
+bool csr_is_conn_state_connected_ibss(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ return eCSR_ASSOC_STATE_TYPE_IBSS_CONNECTED ==
+ pMac->roam.roamSession[sessionId].connectState;
+}
+
+bool csr_is_conn_state_disconnected_ibss(tpAniSirGlobal pMac,
+ uint32_t sessionId)
+{
+ return eCSR_ASSOC_STATE_TYPE_IBSS_DISCONNECTED ==
+ pMac->roam.roamSession[sessionId].connectState;
+}
+
+bool csr_is_conn_state_connected_infra(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ return eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED ==
+ pMac->roam.roamSession[sessionId].connectState;
+}
+
+bool csr_is_conn_state_connected(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ if (csr_is_conn_state_connected_ibss(pMac, sessionId)
+ || csr_is_conn_state_connected_infra(pMac, sessionId)
+ || csr_is_conn_state_connected_wds(pMac, sessionId))
+ return true;
+ else
+ return false;
+}
+
+bool csr_is_conn_state_infra(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ return csr_is_conn_state_connected_infra(pMac, sessionId);
+}
+
+bool csr_is_conn_state_ibss(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ return csr_is_conn_state_connected_ibss(pMac, sessionId) ||
+ csr_is_conn_state_disconnected_ibss(pMac, sessionId);
+}
+
+bool csr_is_conn_state_connected_wds(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ return eCSR_ASSOC_STATE_TYPE_WDS_CONNECTED ==
+ pMac->roam.roamSession[sessionId].connectState;
+}
+
+bool csr_is_conn_state_connected_infra_ap(tpAniSirGlobal pMac,
+ uint32_t sessionId)
+{
+ return (eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED ==
+ pMac->roam.roamSession[sessionId].connectState) ||
+ (eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTED ==
+ pMac->roam.roamSession[sessionId].connectState);
+}
+
+bool csr_is_conn_state_disconnected_wds(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ return eCSR_ASSOC_STATE_TYPE_WDS_DISCONNECTED ==
+ pMac->roam.roamSession[sessionId].connectState;
+}
+
+bool csr_is_conn_state_wds(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ return csr_is_conn_state_connected_wds(pMac, sessionId) ||
+ csr_is_conn_state_disconnected_wds(pMac, sessionId);
+}
+
+bool csr_is_conn_state_ap(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ tCsrRoamSession *pSession;
+ pSession = CSR_GET_SESSION(pMac, sessionId);
+ if (!pSession)
+ return false;
+ if (CSR_IS_INFRA_AP(&pSession->connectedProfile))
+ return true;
+ return false;
+}
+
+bool csr_is_any_session_in_connect_state(tpAniSirGlobal pMac)
+{
+ uint32_t i;
+ bool fRc = false;
+
+ for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
+ if (CSR_IS_SESSION_VALID(pMac, i) &&
+ (csr_is_conn_state_infra(pMac, i)
+ || csr_is_conn_state_ibss(pMac, i)
+ || csr_is_conn_state_ap(pMac, i))) {
+ fRc = true;
+ break;
+ }
+ }
+
+ return fRc;
+}
+
+int8_t csr_get_infra_session_id(tpAniSirGlobal pMac)
+{
+ uint8_t i;
+ int8_t sessionid = -1;
+
+ for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
+ if (CSR_IS_SESSION_VALID(pMac, i)
+ && csr_is_conn_state_infra(pMac, i)) {
+ sessionid = i;
+ break;
+ }
+ }
+
+ return sessionid;
+}
+
+uint8_t csr_get_infra_operation_channel(tpAniSirGlobal pMac, uint8_t sessionId)
+{
+ uint8_t channel;
+
+ if (CSR_IS_SESSION_VALID(pMac, sessionId)) {
+ channel =
+ pMac->roam.roamSession[sessionId].connectedProfile.
+ operationChannel;
+ } else {
+ channel = 0;
+ }
+ return channel;
+}
+
+bool csr_is_session_client_and_connected(tpAniSirGlobal pMac, uint8_t sessionId)
+{
+ tCsrRoamSession *pSession = NULL;
+ if (CSR_IS_SESSION_VALID(pMac, sessionId)
+ && csr_is_conn_state_infra(pMac, sessionId)) {
+ pSession = CSR_GET_SESSION(pMac, sessionId);
+ if (NULL != pSession->pCurRoamProfile) {
+ if ((pSession->pCurRoamProfile->csrPersona ==
+ CDF_STA_MODE)
+ || (pSession->pCurRoamProfile->csrPersona ==
+ CDF_P2P_CLIENT_MODE))
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * csr_get_concurrent_operation_channel() - To get concurrent operating channel
+ * @mac_ctx: Pointer to mac context
+ *
+ * This routine will return operating channel on FIRST BSS that is
+ * active/operating to be used for concurrency mode.
+ * If other BSS is not up or not connected it will return 0
+ *
+ * Return: uint8_t
+ */
+uint8_t csr_get_concurrent_operation_channel(tpAniSirGlobal mac_ctx)
+{
+ tCsrRoamSession *session = NULL;
+ uint8_t i = 0;
+ tCDF_CON_MODE persona;
+
+ for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
+ if (!CSR_IS_SESSION_VALID(mac_ctx, i))
+ continue;
+ session = CSR_GET_SESSION(mac_ctx, i);
+ if (NULL == session->pCurRoamProfile)
+ continue;
+ persona = session->pCurRoamProfile->csrPersona;
+ if ((((persona == CDF_STA_MODE) ||
+ (persona == CDF_P2P_CLIENT_MODE)) &&
+ (session->connectState ==
+ eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED)) ||
+ (((persona == CDF_P2P_GO_MODE) ||
+ (persona == CDF_SAP_MODE))
+ && (session->connectState !=
+ eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED)))
+ return session->connectedProfile.operationChannel;
+
+ }
+ return 0;
+}
+
+#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH
+
+#define HALF_BW_OF(eCSR_bw_val) ((eCSR_bw_val)/2)
+
+/* calculation of center channel based on V/HT BW and WIFI channel bw=5MHz) */
+
+#define CSR_GET_HT40_PLUS_CCH(och) ((och)+2)
+#define CSR_GET_HT40_MINUS_CCH(och) ((och)-2)
+
+#define CSR_GET_HT80_PLUS_LL_CCH(och) ((och)+6)
+#define CSR_GET_HT80_PLUS_HL_CCH(och) ((och)+2)
+#define CSR_GET_HT80_MINUS_LH_CCH(och) ((och)-2)
+#define CSR_GET_HT80_MINUS_HH_CCH(och) ((och)-6)
+
+/**
+ * csr_get_ch_from_ht_profile() - to get channel from HT profile
+ * @pMac: pointer to Mac context
+ * @htp: pointer to HT profile
+ * @och: operating channel
+ * @cfreq: channel frequency
+ * @hbw: half bandwidth
+ *
+ * This function will fill half bandwidth and channel frequency based
+ * on the HT profile
+ *
+ * Return: none
+ */
+void csr_get_ch_from_ht_profile(tpAniSirGlobal pMac, tCsrRoamHTProfile *htp,
+ uint16_t och, uint16_t *cfreq, uint16_t *hbw)
+{
+ uint16_t cch, ch_bond;
+
+ if (och > 14)
+ ch_bond = pMac->roam.configParam.channelBondingMode5GHz;
+ else
+ ch_bond = pMac->roam.configParam.channelBondingMode24GHz;
+
+ cch = och;
+ *hbw = HALF_BW_OF(eCSR_BW_20MHz_VAL);
+
+ if (!ch_bond)
+ goto ret;
+
+ sms_log(pMac, LOG1, FL("##HTC: %d scbw: %d rcbw: %d sco: %d"
+#ifdef WLAN_FEATURE_11AC
+ "VHTC: %d apc: %d apbw: %d"
+#endif
+ ),
+ htp->htCapability, htp->htSupportedChannelWidthSet,
+ htp->htRecommendedTxWidthSet,
+ htp->htSecondaryChannelOffset,
+#ifdef WLAN_FEATURE_11AC
+ htp->vhtCapability, htp->apCenterChan, htp->apChanWidth
+#endif
+ );
+
+#ifdef WLAN_FEATURE_11AC
+ if (htp->vhtCapability) {
+ cch = htp->apCenterChan;
+ if (htp->apChanWidth == WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ)
+ *hbw = HALF_BW_OF(eCSR_BW_80MHz_VAL);
+ else if (htp->apChanWidth == WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ)
+ *hbw = HALF_BW_OF(eCSR_BW_160MHz_VAL);
+
+ if (!*hbw && htp->htCapability) {
+ if (htp->htSupportedChannelWidthSet ==
+ eHT_CHANNEL_WIDTH_40MHZ)
+ *hbw = HALF_BW_OF(eCSR_BW_40MHz_VAL);
+ else
+ *hbw = HALF_BW_OF(eCSR_BW_20MHz_VAL);
+ }
+ } else
+#endif
+ if (htp->htCapability) {
+ if (htp->htSupportedChannelWidthSet ==
+ eHT_CHANNEL_WIDTH_40MHZ) {
+ *hbw = HALF_BW_OF(eCSR_BW_40MHz_VAL);
+ if (htp->htSecondaryChannelOffset ==
+ PHY_DOUBLE_CHANNEL_LOW_PRIMARY)
+ cch = CSR_GET_HT40_PLUS_CCH(och);
+ else if (htp->htSecondaryChannelOffset ==
+ PHY_DOUBLE_CHANNEL_HIGH_PRIMARY)
+ cch = CSR_GET_HT40_MINUS_CCH(och);
+ } else {
+ cch = och;
+ *hbw = HALF_BW_OF(eCSR_BW_20MHz_VAL);
+ }
+ }
+
+ret:
+ *cfreq = cds_chan_to_freq(cch);
+ return;
+}
+
+/**
+ * csr_calc_chb_for_sap_phymode() - to calc channel bandwidth for sap phymode
+ * @mac_ctx: pointer to mac context
+ * @sap_ch: SAP operating channel
+ * @sap_phymode: SAP physical mode
+ * @sap_cch: concurrency channel
+ * @sap_hbw: SAP half bw
+ * @chb: channel bandwidth
+ *
+ * This routine is called to calculate channel bandwidth
+ *
+ * Return: none
+ */
+static void csr_calc_chb_for_sap_phymode(tpAniSirGlobal mac_ctx,
+ uint16_t *sap_ch, eCsrPhyMode *sap_phymode,
+ uint16_t *sap_cch, uint16_t *sap_hbw, uint8_t *chb)
+{
+ if (*sap_phymode == eCSR_DOT11_MODE_11n ||
+ *sap_phymode == eCSR_DOT11_MODE_11n_ONLY) {
+
+ *sap_hbw = HALF_BW_OF(eCSR_BW_40MHz_VAL);
+ if (*chb == PHY_DOUBLE_CHANNEL_LOW_PRIMARY)
+ *sap_cch = CSR_GET_HT40_PLUS_CCH(*sap_ch);
+ else if (*chb == PHY_DOUBLE_CHANNEL_HIGH_PRIMARY)
+ *sap_cch = CSR_GET_HT40_MINUS_CCH(*sap_ch);
+
+ }
+#ifdef WLAN_FEATURE_11AC
+ else if (*sap_phymode == eCSR_DOT11_MODE_11ac ||
+ *sap_phymode == eCSR_DOT11_MODE_11ac_ONLY) {
+ /*11AC only 80/40/20 Mhz supported in Rome */
+ if (mac_ctx->roam.configParam.nVhtChannelWidth ==
+ (WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ + 1)) {
+ *sap_hbw = HALF_BW_OF(eCSR_BW_80MHz_VAL);
+ if (*chb ==
+ (PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW - 1))
+ *sap_cch = CSR_GET_HT80_PLUS_LL_CCH(*sap_ch);
+ else if (*chb ==
+ (PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW
+ - 1))
+ *sap_cch = CSR_GET_HT80_PLUS_HL_CCH(*sap_ch);
+ else if (*chb ==
+ (PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH
+ - 1))
+ *sap_cch = CSR_GET_HT80_MINUS_LH_CCH(*sap_ch);
+ else if (*chb ==
+ (PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH
+ - 1))
+ *sap_cch = CSR_GET_HT80_MINUS_HH_CCH(*sap_ch);
+ } else {
+ *sap_hbw = HALF_BW_OF(eCSR_BW_40MHz_VAL);
+ if (*chb == (PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW
+ - 1))
+ *sap_cch = CSR_GET_HT40_PLUS_CCH(*sap_ch);
+ else if (*chb ==
+ (PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW
+ - 1))
+ *sap_cch = CSR_GET_HT40_MINUS_CCH(*sap_ch);
+ else if (*chb ==
+ (PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH
+ - 1))
+ *sap_cch = CSR_GET_HT40_PLUS_CCH(*sap_ch);
+ else if (*chb ==
+ (PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH
+ - 1))
+ *sap_cch = CSR_GET_HT40_MINUS_CCH(*sap_ch);
+ }
+ }
+#endif
+}
+
+/**
+ * csr_handle_conc_chnl_overlap_for_sap_go - To handle overlap for AP+AP
+ * @mac_ctx: pointer to mac context
+ * @session: Current session
+ * @sap_ch: SAP/GO operating channel
+ * @sap_hbw: SAP/GO half bw
+ * @sap_cfreq: SAP/GO channel frequency
+ * @intf_ch: concurrent SAP/GO operating channel
+ * @intf_hbw: concurrent SAP/GO half bw
+ * @intf_cfreq: concurrent SAP/GO channel frequency
+ *
+ * This routine is called to check if one SAP/GO channel is overlapping with
+ * other SAP/GO channel
+ *
+ * Return: none
+ */
+static void csr_handle_conc_chnl_overlap_for_sap_go(tpAniSirGlobal mac_ctx,
+ tCsrRoamSession *session,
+ uint16_t *sap_ch, uint16_t *sap_hbw, uint16_t *sap_cfreq,
+ uint16_t *intf_ch, uint16_t *intf_hbw, uint16_t *intf_cfreq)
+{
+ /*
+ * if conc_custom_rule1 is defined then we don't
+ * want p2pgo to follow SAP's channel or SAP to
+ * follow P2PGO's channel.
+ */
+ if (0 == mac_ctx->roam.configParam.conc_custom_rule1 &&
+ 0 == mac_ctx->roam.configParam.conc_custom_rule2) {
+ if (*sap_ch == 0) {
+ *sap_ch = session->connectedProfile.operationChannel;
+ csr_get_ch_from_ht_profile(mac_ctx,
+ &session->connectedProfile.HTProfile,
+ *sap_ch, sap_cfreq, sap_hbw);
+ } else if (*sap_ch !=
+ session->connectedProfile.operationChannel) {
+ *intf_ch = session->connectedProfile.operationChannel;
+ csr_get_ch_from_ht_profile(mac_ctx,
+ &session->connectedProfile.HTProfile,
+ *intf_ch, intf_cfreq, intf_hbw);
+ }
+ } else if (*sap_ch == 0 &&
+ (session->pCurRoamProfile->csrPersona ==
+ CDF_SAP_MODE)) {
+ *sap_ch = session->connectedProfile.operationChannel;
+ csr_get_ch_from_ht_profile(mac_ctx,
+ &session->connectedProfile.HTProfile,
+ *sap_ch, sap_cfreq, sap_hbw);
+ }
+}
+
+
+/**
+ * csr_check_concurrent_channel_overlap() - To check concurrent overlap chnls
+ * @mac_ctx: Pointer to mac context
+ * @sap_ch: SAP channel
+ * @sap_phymode: SAP phy mode
+ * @cc_switch_mode: concurrent switch mode
+ *
+ * This routine will be called to check concurrent overlap channels
+ *
+ * Return: uint16_t
+ */
+uint16_t csr_check_concurrent_channel_overlap(tpAniSirGlobal mac_ctx,
+ uint16_t sap_ch, eCsrPhyMode sap_phymode,
+ uint8_t cc_switch_mode)
+{
+ tCsrRoamSession *session = NULL;
+ uint8_t i = 0, chb = PHY_SINGLE_CHANNEL_CENTERED;
+ uint16_t intf_ch = 0, sap_hbw = 0, intf_hbw = 0, intf_cfreq = 0;
+ uint16_t sap_cfreq = 0;
+ uint16_t sap_lfreq, sap_hfreq, intf_lfreq, intf_hfreq, sap_cch;
+
+ if (mac_ctx->roam.configParam.cc_switch_mode ==
+ CDF_MCC_TO_SCC_SWITCH_DISABLE)
+ return 0;
+
+ if (sap_ch != 0) {
+ sap_cch = sap_ch;
+ sap_hbw = HALF_BW_OF(eCSR_BW_20MHz_VAL);
+
+ if (sap_ch > 14)
+ chb = mac_ctx->roam.configParam.channelBondingMode5GHz;
+ else
+ chb = mac_ctx->roam.configParam.channelBondingMode24GHz;
+
+ if (chb)
+ csr_calc_chb_for_sap_phymode(mac_ctx, &sap_ch,
+ &sap_phymode, &sap_cch, &sap_hbw, &chb);
+ sap_cfreq = cds_chan_to_freq(sap_cch);
+ }
+
+ for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
+ if (!CSR_IS_SESSION_VALID(mac_ctx, i))
+ continue;
+
+ session = CSR_GET_SESSION(mac_ctx, i);
+ if (NULL == session->pCurRoamProfile)
+ continue;
+ if (((session->pCurRoamProfile->csrPersona == CDF_STA_MODE) ||
+ (session->pCurRoamProfile->csrPersona ==
+ CDF_P2P_CLIENT_MODE)) &&
+ (session->connectState ==
+ eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED)) {
+ intf_ch = session->connectedProfile.operationChannel;
+ csr_get_ch_from_ht_profile(mac_ctx,
+ &session->connectedProfile.HTProfile,
+ intf_ch, &intf_cfreq, &intf_hbw);
+ } else if (((session->pCurRoamProfile->csrPersona ==
+ CDF_P2P_GO_MODE) ||
+ (session->pCurRoamProfile->csrPersona ==
+ CDF_SAP_MODE)) &&
+ (session->connectState !=
+ eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED)) {
+ csr_handle_conc_chnl_overlap_for_sap_go(mac_ctx,
+ session, &sap_ch, &sap_hbw, &sap_cfreq,
+ &intf_ch, &intf_hbw, &intf_cfreq);
+ }
+ }
+
+ if (intf_ch && sap_ch != intf_ch &&
+ cc_switch_mode != CDF_MCC_TO_SCC_SWITCH_FORCE) {
+ sap_lfreq = sap_cfreq - sap_hbw;
+ sap_hfreq = sap_cfreq + sap_hbw;
+ intf_lfreq = intf_cfreq - intf_hbw;
+ intf_hfreq = intf_cfreq + intf_hbw;
+
+ sms_log(mac_ctx, LOGE,
+ FL("\nSAP: OCH: %03d OCF: %d CCH: %03d CF: %d BW: %d LF: %d HF: %d\n"
+ "INTF: OCH: %03d OCF: %d CCH: %03d CF: %d BW: %d LF: %d HF: %d"),
+ sap_ch, cds_chan_to_freq(sap_ch),
+ cds_freq_to_chan(sap_cfreq), sap_cfreq, sap_hbw * 2,
+ sap_lfreq, sap_hfreq, intf_ch,
+ cds_chan_to_freq(intf_ch), cds_freq_to_chan(intf_cfreq),
+ intf_cfreq, intf_hbw * 2, intf_lfreq, intf_hfreq);
+
+ if (!(((sap_lfreq > intf_lfreq && sap_lfreq < intf_hfreq) ||
+ (sap_hfreq > intf_lfreq && sap_hfreq < intf_hfreq)) ||
+ ((intf_lfreq > sap_lfreq && intf_lfreq < sap_hfreq) ||
+ (intf_hfreq > sap_lfreq && intf_hfreq < sap_hfreq))))
+ intf_ch = 0;
+ } else if (intf_ch && sap_ch != intf_ch &&
+ cc_switch_mode == CDF_MCC_TO_SCC_SWITCH_FORCE) {
+ if (!((intf_ch < 14 && sap_ch < 14) ||
+ (intf_ch > 14 && sap_ch > 14)))
+ intf_ch = 0;
+ } else if (intf_ch == sap_ch) {
+ intf_ch = 0;
+ }
+
+ sms_log(mac_ctx, LOGE, FL("##Concurrent Channels %s Interfering"),
+ intf_ch == 0 ? "Not" : "Are");
+ return intf_ch;
+}
+#endif
+
+bool csr_is_all_session_disconnected(tpAniSirGlobal pMac)
+{
+ uint32_t i;
+ bool fRc = true;
+
+ for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
+ if (CSR_IS_SESSION_VALID(pMac, i)
+ && !csr_is_conn_state_disconnected(pMac, i)) {
+ fRc = false;
+ break;
+ }
+ }
+
+ return fRc;
+}
+
+/**
+ * csr_is_sta_session_connected() - to find if concurrent sta is active
+ * @mac_ctx: pointer to mac context
+ *
+ * This function will iterate through each session and check if sta
+ * session exist and active
+ *
+ * Return: true or false
+ */
+bool csr_is_sta_session_connected(tpAniSirGlobal mac_ctx)
+{
+ uint32_t i;
+ tCsrRoamSession *pSession = NULL;
+
+ for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
+ if (CSR_IS_SESSION_VALID(mac_ctx, i) &&
+ !csr_is_conn_state_disconnected(mac_ctx, i)) {
+ pSession = CSR_GET_SESSION(mac_ctx, i);
+
+ if ((NULL != pSession->pCurRoamProfile) &&
+ (CDF_STA_MODE ==
+ pSession->pCurRoamProfile->csrPersona))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * csr_is_p2p_session_connected() - to find if any p2p session is active
+ * @mac_ctx: pointer to mac context
+ *
+ * This function will iterate through each session and check if any p2p
+ * session exist and active
+ *
+ * Return: true or false
+ */
+bool csr_is_p2p_session_connected(tpAniSirGlobal pMac)
+{
+ uint32_t i;
+ tCsrRoamSession *pSession = NULL;
+ tCDF_CON_MODE persona;
+
+ for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
+ if (CSR_IS_SESSION_VALID(pMac, i)
+ && !csr_is_conn_state_disconnected(pMac, i)) {
+ pSession = CSR_GET_SESSION(pMac, i);
+ persona = pSession->pCurRoamProfile->csrPersona;
+ if ((NULL != pSession->pCurRoamProfile) &&
+ ((CDF_P2P_CLIENT_MODE == persona) ||
+ (CDF_P2P_GO_MODE == persona))) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool csr_is_any_session_connected(tpAniSirGlobal pMac)
+{
+ uint32_t i, count;
+ bool fRc = false;
+
+ count = 0;
+ for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
+ if (CSR_IS_SESSION_VALID(pMac, i)
+ && !csr_is_conn_state_disconnected(pMac, i))
+ count++;
+ }
+
+ if (count > 0)
+ fRc = true;
+ return fRc;
+}
+
+bool csr_is_infra_connected(tpAniSirGlobal pMac)
+{
+ uint32_t i;
+ bool fRc = false;
+
+ for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
+ if (CSR_IS_SESSION_VALID(pMac, i)
+ && csr_is_conn_state_connected_infra(pMac, i)) {
+ fRc = true;
+ break;
+ }
+ }
+
+ return fRc;
+}
+
+bool csr_is_concurrent_infra_connected(tpAniSirGlobal pMac)
+{
+ uint32_t i, noOfConnectedInfra = 0;
+
+ bool fRc = false;
+
+ for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
+ if (CSR_IS_SESSION_VALID(pMac, i)
+ && csr_is_conn_state_connected_infra(pMac, i)) {
+ ++noOfConnectedInfra;
+ }
+ }
+
+ /* More than one Infra Sta Connected */
+ if (noOfConnectedInfra > 1)
+ fRc = true;
+ return fRc;
+}
+
+bool csr_is_ibss_started(tpAniSirGlobal pMac)
+{
+ uint32_t i;
+ bool fRc = false;
+
+ for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
+ if (CSR_IS_SESSION_VALID(pMac, i)
+ && csr_is_conn_state_ibss(pMac, i)) {
+ fRc = true;
+ break;
+ }
+ }
+
+ return fRc;
+}
+
+bool csr_is_btamp_started(tpAniSirGlobal pMac)
+{
+ uint32_t i;
+ bool fRc = false;
+
+ for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
+ if (CSR_IS_SESSION_VALID(pMac, i)
+ && csr_is_conn_state_connected_wds(pMac, i)) {
+ fRc = true;
+ break;
+ }
+ }
+
+ return fRc;
+}
+
+bool csr_is_concurrent_session_running(tpAniSirGlobal pMac)
+{
+ uint32_t sessionId, noOfCocurrentSession = 0;
+ eCsrConnectState connectState;
+
+ bool fRc = false;
+
+ for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) {
+ if (CSR_IS_SESSION_VALID(pMac, sessionId)) {
+ connectState =
+ pMac->roam.roamSession[sessionId].connectState;
+ if ((eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED ==
+ connectState)
+ || (eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED ==
+ connectState)
+ || (eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTED ==
+ connectState)) {
+ ++noOfCocurrentSession;
+ }
+ }
+ }
+
+ /* More than one session is Up and Running */
+ if (noOfCocurrentSession > 1)
+ fRc = true;
+ return fRc;
+}
+
+bool csr_is_infra_ap_started(tpAniSirGlobal pMac)
+{
+ uint32_t sessionId;
+ bool fRc = false;
+
+ for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) {
+ if (CSR_IS_SESSION_VALID(pMac, sessionId)
+ && (csr_is_conn_state_connected_infra_ap(pMac, sessionId))) {
+ fRc = true;
+ break;
+ }
+ }
+
+ return fRc;
+
+}
+
+bool csr_is_btamp(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ return csr_is_conn_state_connected_wds(pMac, sessionId);
+}
+
+bool csr_is_conn_state_disconnected(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ return eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED ==
+ pMac->roam.roamSession[sessionId].connectState;
+}
+
+/**
+ * csr_is_valid_mc_concurrent_session() - To check concurren session is valid
+ * @mac_ctx: pointer to mac context
+ * @session_id: session id
+ * @bss_descr: bss description
+ *
+ * This function validates the concurrent session
+ *
+ * Return: true or false
+ */
+bool csr_is_valid_mc_concurrent_session(tpAniSirGlobal mac_ctx,
+ uint32_t session_id,
+ tSirBssDescription *bss_descr)
+{
+ tCsrRoamSession *pSession = NULL;
+
+ /* Check for MCC support */
+ if (!mac_ctx->roam.configParam.fenableMCCMode)
+ return false;
+ if (!CSR_IS_SESSION_VALID(mac_ctx, session_id))
+ return false;
+ /* Validate BeaconInterval */
+ pSession = CSR_GET_SESSION(mac_ctx, session_id);
+ if (NULL == pSession->pCurRoamProfile)
+ return false;
+ if (CDF_STATUS_SUCCESS ==
+ csr_isconcurrentsession_valid(mac_ctx, session_id,
+ pSession->pCurRoamProfile->csrPersona)) {
+ if (CDF_STATUS_SUCCESS ==
+ csr_validate_mcc_beacon_interval(mac_ctx,
+ bss_descr->channelId,
+ &bss_descr->beaconInterval, session_id,
+ pSession->pCurRoamProfile->csrPersona))
+ return true;
+ }
+ return false;
+}
+
+static tSirMacCapabilityInfo csr_get_bss_capabilities(tSirBssDescription *
+ pSirBssDesc)
+{
+ tSirMacCapabilityInfo dot11Caps;
+
+ /* tSirMacCapabilityInfo is 16-bit */
+ cdf_get_u16((uint8_t *) &pSirBssDesc->capabilityInfo,
+ (uint16_t *) &dot11Caps);
+
+ return dot11Caps;
+}
+
+bool csr_is_infra_bss_desc(tSirBssDescription *pSirBssDesc)
+{
+ tSirMacCapabilityInfo dot11Caps = csr_get_bss_capabilities(pSirBssDesc);
+
+ return (bool) dot11Caps.ess;
+}
+
+bool csr_is_ibss_bss_desc(tSirBssDescription *pSirBssDesc)
+{
+ tSirMacCapabilityInfo dot11Caps = csr_get_bss_capabilities(pSirBssDesc);
+
+ return (bool) dot11Caps.ibss;
+}
+
+bool csr_is_qo_s_bss_desc(tSirBssDescription *pSirBssDesc)
+{
+ tSirMacCapabilityInfo dot11Caps = csr_get_bss_capabilities(pSirBssDesc);
+
+ return (bool) dot11Caps.qos;
+}
+
+bool csr_is_privacy(tSirBssDescription *pSirBssDesc)
+{
+ tSirMacCapabilityInfo dot11Caps = csr_get_bss_capabilities(pSirBssDesc);
+
+ return (bool) dot11Caps.privacy;
+}
+
+bool csr_is11d_supported(tpAniSirGlobal pMac)
+{
+ return pMac->roam.configParam.Is11dSupportEnabled;
+}
+
+bool csr_is11h_supported(tpAniSirGlobal pMac)
+{
+ return pMac->roam.configParam.Is11hSupportEnabled;
+}
+
+bool csr_is11e_supported(tpAniSirGlobal pMac)
+{
+ return pMac->roam.configParam.Is11eSupportEnabled;
+}
+
+bool csr_is_mcc_supported(tpAniSirGlobal pMac)
+{
+ return pMac->roam.configParam.fenableMCCMode;
+
+}
+
+bool csr_is_wmm_supported(tpAniSirGlobal pMac)
+{
+ if (eCsrRoamWmmNoQos == pMac->roam.configParam.WMMSupportMode)
+ return false;
+ else
+ return true;
+}
+
+/* pIes is the IEs for pSirBssDesc2 */
+bool csr_is_ssid_equal(tHalHandle hHal, tSirBssDescription *pSirBssDesc1,
+ tSirBssDescription *pSirBssDesc2, tDot11fBeaconIEs *pIes2)
+{
+ bool fEqual = false;
+ tSirMacSSid Ssid1, Ssid2;
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ tDot11fBeaconIEs *pIes1 = NULL;
+ tDot11fBeaconIEs *pIesLocal = pIes2;
+
+ do {
+ if ((NULL == pSirBssDesc1) || (NULL == pSirBssDesc2))
+ break;
+ if (!pIesLocal
+ &&
+ !CDF_IS_STATUS_SUCCESS(csr_get_parsed_bss_description_ies
+ (pMac, pSirBssDesc2,
+ &pIesLocal))) {
+ sms_log(pMac, LOGE, FL(" fail to parse IEs"));
+ break;
+ }
+ if (!CDF_IS_STATUS_SUCCESS
+ (csr_get_parsed_bss_description_ies(pMac,
+ pSirBssDesc1, &pIes1))) {
+ break;
+ }
+ if ((!pIes1->SSID.present) || (!pIesLocal->SSID.present))
+ break;
+ if (pIes1->SSID.num_ssid != pIesLocal->SSID.num_ssid)
+ break;
+ cdf_mem_copy(Ssid1.ssId, pIes1->SSID.ssid,
+ pIes1->SSID.num_ssid);
+ cdf_mem_copy(Ssid2.ssId, pIesLocal->SSID.ssid,
+ pIesLocal->SSID.num_ssid);
+
+ fEqual =
+ cdf_mem_compare(Ssid1.ssId, Ssid2.ssId,
+ pIesLocal->SSID.num_ssid);
+
+ } while (0);
+ if (pIes1)
+ cdf_mem_free(pIes1);
+ if (pIesLocal && !pIes2)
+ cdf_mem_free(pIesLocal);
+
+ return fEqual;
+}
+
+/* pIes can be passed in as NULL if the caller doesn't have one prepared */
+bool csr_is_bss_description_wme(tHalHandle hHal, tSirBssDescription *pSirBssDesc,
+ tDot11fBeaconIEs *pIes)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ /* Assume that WME is found... */
+ bool fWme = true;
+ tDot11fBeaconIEs *pIesTemp = pIes;
+
+ do {
+ if (pIesTemp == NULL) {
+ if (!CDF_IS_STATUS_SUCCESS
+ (csr_get_parsed_bss_description_ies
+ (pMac, pSirBssDesc, &pIesTemp))) {
+ fWme = false;
+ break;
+ }
+ }
+ /* if the Wme Info IE is found, then WME is supported... */
+ if (CSR_IS_QOS_BSS(pIesTemp))
+ break;
+ /* if none of these are found, then WME is NOT supported... */
+ fWme = false;
+ } while (0);
+ if (!csr_is_wmm_supported(pMac) && fWme) {
+ if (!pIesTemp->HTCaps.present) {
+ fWme = false;
+ }
+ }
+ if ((pIes == NULL) && (NULL != pIesTemp)) {
+ /* we allocate memory here so free it before returning */
+ cdf_mem_free(pIesTemp);
+ }
+
+ return fWme;
+}
+
+eCsrMediaAccessType csr_get_qo_s_from_bss_desc(tHalHandle hHal,
+ tSirBssDescription *pSirBssDesc,
+ tDot11fBeaconIEs *pIes)
+{
+ eCsrMediaAccessType qosType = eCSR_MEDIUM_ACCESS_DCF;
+
+ if (NULL == pIes) {
+ CDF_ASSERT(pIes != NULL);
+ return qosType;
+ }
+
+ do {
+ /* if we find WMM in the Bss Description, then we let this */
+ /* override and use WMM. */
+ if (csr_is_bss_description_wme(hHal, pSirBssDesc, pIes)) {
+ qosType = eCSR_MEDIUM_ACCESS_WMM_eDCF_DSCP;
+ } else {
+ /* if the QoS bit is on, then the AP is advertising 11E QoS... */
+ if (csr_is_qo_s_bss_desc(pSirBssDesc)) {
+ qosType = eCSR_MEDIUM_ACCESS_11e_eDCF;
+ } else {
+ qosType = eCSR_MEDIUM_ACCESS_DCF;
+ }
+ /* scale back based on the types turned on for the adapter... */
+ if (eCSR_MEDIUM_ACCESS_11e_eDCF == qosType
+ && !csr_is11e_supported(hHal)) {
+ qosType = eCSR_MEDIUM_ACCESS_DCF;
+ }
+ }
+
+ } while (0);
+
+ return qosType;
+}
+
+/* Caller allocates memory for pIEStruct */
+CDF_STATUS csr_parse_bss_description_ies(tHalHandle hHal,
+ tSirBssDescription *pBssDesc,
+ tDot11fBeaconIEs *pIEStruct)
+{
+ CDF_STATUS status = CDF_STATUS_E_FAILURE;
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ int ieLen =
+ (int)(pBssDesc->length + sizeof(pBssDesc->length) -
+ GET_FIELD_OFFSET(tSirBssDescription, ieFields));
+
+ if (ieLen > 0 && pIEStruct) {
+ if (!DOT11F_FAILED
+ (dot11f_unpack_beacon_i_es
+ (pMac, (uint8_t *) pBssDesc->ieFields, ieLen,
+ pIEStruct))) {
+ status = CDF_STATUS_SUCCESS;
+ }
+ }
+
+ return status;
+}
+
+/* This function will allocate memory for the parsed IEs to the caller. Caller must free the memory */
+/* after it is done with the data only if this function succeeds */
+CDF_STATUS csr_get_parsed_bss_description_ies(tHalHandle hHal,
+ tSirBssDescription *pBssDesc,
+ tDot11fBeaconIEs **ppIEStruct)
+{
+ CDF_STATUS status = CDF_STATUS_E_INVAL;
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+
+ if (pBssDesc && ppIEStruct) {
+ *ppIEStruct = cdf_mem_malloc(sizeof(tDot11fBeaconIEs));
+ if ((*ppIEStruct) != NULL) {
+ cdf_mem_set((void *)*ppIEStruct,
+ sizeof(tDot11fBeaconIEs), 0);
+ status =
+ csr_parse_bss_description_ies(hHal, pBssDesc,
+ *ppIEStruct);
+ if (!CDF_IS_STATUS_SUCCESS(status)) {
+ cdf_mem_free(*ppIEStruct);
+ *ppIEStruct = NULL;
+ }
+ } else {
+ sms_log(pMac, LOGE, FL(" failed to allocate memory"));
+ CDF_ASSERT(0);
+ return CDF_STATUS_E_NOMEM;
+ }
+ }
+
+ return status;
+}
+
+bool csr_is_nullssid(uint8_t *pBssSsid, uint8_t len)
+{
+ bool fNullSsid = false;
+
+ uint32_t SsidLength;
+ uint8_t *pSsidStr;
+
+ do {
+ if (0 == len) {
+ fNullSsid = true;
+ break;
+ }
+ /* Consider 0 or space for hidden SSID */
+ if (0 == pBssSsid[0]) {
+ fNullSsid = true;
+ break;
+ }
+
+ SsidLength = len;
+ pSsidStr = pBssSsid;
+
+ while (SsidLength) {
+ if (*pSsidStr)
+ break;
+
+ pSsidStr++;
+ SsidLength--;
+ }
+
+ if (0 == SsidLength) {
+ fNullSsid = true;
+ break;
+ }
+ } while (0);
+
+ return fNullSsid;
+}
+
+uint32_t csr_get_frag_thresh(tHalHandle hHal)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+
+ return pMac->roam.configParam.FragmentationThreshold;
+}
+
+uint32_t csr_get_rts_thresh(tHalHandle hHal)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+
+ return pMac->roam.configParam.RTSThreshold;
+}
+
+eCsrPhyMode csr_translate_to_phy_mode_from_bss_desc(tSirBssDescription *pSirBssDesc)
+{
+ eCsrPhyMode phyMode;
+
+ switch (pSirBssDesc->nwType) {
+ case eSIR_11A_NW_TYPE:
+ phyMode = eCSR_DOT11_MODE_11a;
+ break;
+
+ case eSIR_11B_NW_TYPE:
+ phyMode = eCSR_DOT11_MODE_11b;
+ break;
+
+ case eSIR_11G_NW_TYPE:
+ phyMode = eCSR_DOT11_MODE_11g;
+ break;
+
+ case eSIR_11N_NW_TYPE:
+ phyMode = eCSR_DOT11_MODE_11n;
+ break;
+#ifdef WLAN_FEATURE_11AC
+ case eSIR_11AC_NW_TYPE:
+ default:
+ phyMode = eCSR_DOT11_MODE_11ac;
+#else
+ default:
+ phyMode = eCSR_DOT11_MODE_11n;
+#endif
+ break;
+ }
+ return phyMode;
+}
+
+uint32_t csr_translate_to_wni_cfg_dot11_mode(tpAniSirGlobal pMac,
+ eCsrCfgDot11Mode csrDot11Mode)
+{
+ uint32_t ret;
+
+ switch (csrDot11Mode) {
+ case eCSR_CFG_DOT11_MODE_AUTO:
+ sms_log(pMac, LOGW,
+ FL(" Warning: sees eCSR_CFG_DOT11_MODE_AUTO "));
+ if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC))
+ ret = WNI_CFG_DOT11_MODE_11AC;
+ else
+ ret = WNI_CFG_DOT11_MODE_11N;
+ break;
+ case eCSR_CFG_DOT11_MODE_11A:
+ ret = WNI_CFG_DOT11_MODE_11A;
+ break;
+ case eCSR_CFG_DOT11_MODE_11B:
+ ret = WNI_CFG_DOT11_MODE_11B;
+ break;
+ case eCSR_CFG_DOT11_MODE_11G:
+ ret = WNI_CFG_DOT11_MODE_11G;
+ break;
+ case eCSR_CFG_DOT11_MODE_11N:
+ ret = WNI_CFG_DOT11_MODE_11N;
+ break;
+ case eCSR_CFG_DOT11_MODE_11G_ONLY:
+ ret = WNI_CFG_DOT11_MODE_11G_ONLY;
+ break;
+ case eCSR_CFG_DOT11_MODE_11N_ONLY:
+ ret = WNI_CFG_DOT11_MODE_11N_ONLY;
+ break;
+ case eCSR_CFG_DOT11_MODE_11AC_ONLY:
+ if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC))
+ ret = WNI_CFG_DOT11_MODE_11AC_ONLY;
+ else
+ ret = WNI_CFG_DOT11_MODE_11N;
+ break;
+ case eCSR_CFG_DOT11_MODE_11AC:
+ if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC))
+ ret = WNI_CFG_DOT11_MODE_11AC;
+ else
+ ret = WNI_CFG_DOT11_MODE_11N;
+ break;
+ default:
+ sms_log(pMac, LOGW, FL("doesn't expect %d as csrDo11Mode"),
+ csrDot11Mode);
+ if (eCSR_BAND_24 == pMac->roam.configParam.eBand) {
+ ret = WNI_CFG_DOT11_MODE_11G;
+ } else {
+ ret = WNI_CFG_DOT11_MODE_11A;
+ }
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * csr_get_phy_mode_from_bss() - Get Phy Mode
+ * @pMac: Global MAC context
+ * @pBSSDescription: BSS Descriptor
+ * @pPhyMode: Physical Mode
+ * @pIes: Pointer to the IE fields
+ *
+ * This function should only return the super set of supported modes
+ * 11n implies 11b/g/a/n.
+ *
+ * Return: success
+ **/
+CDF_STATUS csr_get_phy_mode_from_bss(tpAniSirGlobal pMac,
+ tSirBssDescription *pBSSDescription,
+ eCsrPhyMode *pPhyMode, tDot11fBeaconIEs *pIes)
+{
+ CDF_STATUS status = CDF_STATUS_SUCCESS;
+ eCsrPhyMode phyMode =
+ csr_translate_to_phy_mode_from_bss_desc(pBSSDescription);
+
+ if (pIes) {
+ if (pIes->HTCaps.present) {
+ phyMode = eCSR_DOT11_MODE_11n;
+#ifdef WLAN_FEATURE_11AC
+ if (IS_BSS_VHT_CAPABLE(pIes->VHTCaps) ||
+ IS_BSS_VHT_CAPABLE(pIes->vendor2_ie.VHTCaps))
+ phyMode = eCSR_DOT11_MODE_11ac;
+#endif
+ }
+ *pPhyMode = phyMode;
+ }
+
+ return status;
+}
+
+/**
+ * csr_get_phy_mode_in_use() - to get phymode
+ * @phyModeIn: physical mode
+ * @bssPhyMode: physical mode in bss
+ * @f5GhzBand: 5Ghz band
+ * @pCfgDot11ModeToUse: dot11 mode in use
+ *
+ * This function returns the correct eCSR_CFG_DOT11_MODE is the two phyModes
+ * matches. bssPhyMode is the mode derived from the BSS description
+ * f5GhzBand is derived from the channel id of BSS description
+ *
+ * Return: true or false
+ */
+bool csr_get_phy_mode_in_use(eCsrPhyMode phyModeIn, eCsrPhyMode bssPhyMode,
+ bool f5GhzBand, eCsrCfgDot11Mode *pCfgDot11ModeToUse)
+{
+ bool fMatch = false;
+ eCsrCfgDot11Mode cfgDot11Mode;
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N;
+
+ switch (phyModeIn) {
+ /* 11a or 11b or 11g */
+ case eCSR_DOT11_MODE_abg:
+ fMatch = true;
+ if (f5GhzBand)
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A;
+ else if (eCSR_DOT11_MODE_11b == bssPhyMode)
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B;
+ else
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G;
+ break;
+
+ case eCSR_DOT11_MODE_11a:
+ if (f5GhzBand) {
+ fMatch = true;
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A;
+ }
+ break;
+
+ case eCSR_DOT11_MODE_11g:
+ if (!f5GhzBand) {
+ fMatch = true;
+ if (eCSR_DOT11_MODE_11b == bssPhyMode)
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B;
+ else
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G;
+ }
+ break;
+
+ case eCSR_DOT11_MODE_11g_ONLY:
+ if (eCSR_DOT11_MODE_11g == bssPhyMode) {
+ fMatch = true;
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G;
+ }
+ break;
+
+ case eCSR_DOT11_MODE_11b:
+ if (!f5GhzBand) {
+ fMatch = true;
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B;
+ }
+ break;
+
+ case eCSR_DOT11_MODE_11b_ONLY:
+ if (eCSR_DOT11_MODE_11b == bssPhyMode) {
+ fMatch = true;
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B;
+ }
+ break;
+
+ case eCSR_DOT11_MODE_11n:
+ fMatch = true;
+ switch (bssPhyMode) {
+ case eCSR_DOT11_MODE_11g:
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G;
+ break;
+ case eCSR_DOT11_MODE_11b:
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B;
+ break;
+ case eCSR_DOT11_MODE_11a:
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A;
+ break;
+ case eCSR_DOT11_MODE_11n:
+#ifdef WLAN_FEATURE_11AC
+ case eCSR_DOT11_MODE_11ac:
+#endif
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N;
+ break;
+
+ default:
+#ifdef WLAN_FEATURE_11AC
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC;
+#else
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N;
+#endif
+ break;
+ }
+ break;
+
+ case eCSR_DOT11_MODE_11n_ONLY:
+ if ((eCSR_DOT11_MODE_11n == bssPhyMode)) {
+ fMatch = true;
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N;
+
+ }
+
+ break;
+#ifdef WLAN_FEATURE_11AC
+ case eCSR_DOT11_MODE_11ac:
+ fMatch = true;
+ switch (bssPhyMode) {
+ case eCSR_DOT11_MODE_11g:
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G;
+ break;
+ case eCSR_DOT11_MODE_11b:
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B;
+ break;
+ case eCSR_DOT11_MODE_11a:
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A;
+ break;
+ case eCSR_DOT11_MODE_11n:
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N;
+ break;
+ case eCSR_DOT11_MODE_11ac:
+ default:
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC;
+ break;
+ }
+ break;
+
+ case eCSR_DOT11_MODE_11ac_ONLY:
+ if ((eCSR_DOT11_MODE_11ac == bssPhyMode)) {
+ fMatch = true;
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC;
+ }
+ break;
+#endif
+
+ default:
+ fMatch = true;
+ switch (bssPhyMode) {
+ case eCSR_DOT11_MODE_11g:
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G;
+ break;
+ case eCSR_DOT11_MODE_11b:
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B;
+ break;
+ case eCSR_DOT11_MODE_11a:
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A;
+ break;
+ case eCSR_DOT11_MODE_11n:
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N;
+ break;
+#ifdef WLAN_FEATURE_11AC
+ case eCSR_DOT11_MODE_11ac:
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC;
+ break;
+#endif
+ default:
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_AUTO;
+ break;
+ }
+ break;
+ }
+
+ if (fMatch && pCfgDot11ModeToUse) {
+#ifdef WLAN_FEATURE_11AC
+ if (cfgDot11Mode == eCSR_CFG_DOT11_MODE_11AC
+ && (!IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)))
+ *pCfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11N;
+ else
+#endif
+ *pCfgDot11ModeToUse = cfgDot11Mode;
+ }
+ return fMatch;
+}
+
+/**
+ * csr_is_phy_mode_match() - to find if phy mode matches
+ * @pMac: pointer to mac context
+ * @phyMode: physical mode
+ * @pSirBssDesc: bss description
+ * @pProfile: pointer to roam profile
+ * @pReturnCfgDot11Mode: dot1 mode to return
+ * @pIes: pointer to IEs
+ *
+ * This function decides whether the one of the bit of phyMode is matching the
+ * mode in the BSS and allowed by the user setting
+ *
+ * Return: true or false based on mode that fits the criteria
+ */
+bool csr_is_phy_mode_match(tpAniSirGlobal pMac, uint32_t phyMode,
+ tSirBssDescription *pSirBssDesc,
+ tCsrRoamProfile *pProfile,
+ eCsrCfgDot11Mode *pReturnCfgDot11Mode,
+ tDot11fBeaconIEs *pIes)
+{
+ bool fMatch = false;
+ eCsrPhyMode phyModeInBssDesc = eCSR_DOT11_MODE_AUTO, phyMode2;
+ eCsrCfgDot11Mode cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_AUTO;
+ uint32_t bitMask, loopCount;
+
+ if (!CDF_IS_STATUS_SUCCESS(csr_get_phy_mode_from_bss(pMac, pSirBssDesc,
+ &phyModeInBssDesc, pIes)))
+ return fMatch;
+
+ if ((0 == phyMode) || (eCSR_DOT11_MODE_AUTO & phyMode)) {
+ if (eCSR_CFG_DOT11_MODE_ABG ==
+ pMac->roam.configParam.uCfgDot11Mode)
+ phyMode = eCSR_DOT11_MODE_abg;
+ else if (eCSR_CFG_DOT11_MODE_AUTO ==
+ pMac->roam.configParam.uCfgDot11Mode)
+#ifdef WLAN_FEATURE_11AC
+ phyMode = eCSR_DOT11_MODE_11ac;
+#else
+ phyMode = eCSR_DOT11_MODE_11n;
+#endif
+
+ else
+ /* user's pick */
+ phyMode = pMac->roam.configParam.phyMode;
+ }
+
+ if ((0 == phyMode) || (eCSR_DOT11_MODE_AUTO & phyMode)) {
+ if (0 != phyMode) {
+ if (eCSR_DOT11_MODE_AUTO & phyMode) {
+ phyMode2 =
+ eCSR_DOT11_MODE_AUTO & phyMode;
+ }
+ } else {
+ phyMode2 = phyMode;
+ }
+ fMatch = csr_get_phy_mode_in_use(phyMode2, phyModeInBssDesc,
+ CDS_IS_CHANNEL_5GHZ(pSirBssDesc->channelId),
+ &cfgDot11ModeToUse);
+ } else {
+ bitMask = 1;
+ loopCount = 0;
+ while (loopCount < eCSR_NUM_PHY_MODE) {
+ phyMode2 = (phyMode & (bitMask << loopCount++));
+ if (0 != phyMode2 && csr_get_phy_mode_in_use(phyMode2,
+ phyModeInBssDesc,
+ CDS_IS_CHANNEL_5GHZ
+ (pSirBssDesc->channelId),
+ &cfgDot11ModeToUse)) {
+ fMatch = true;
+ break;
+ }
+ }
+ }
+ if (fMatch && pReturnCfgDot11Mode) {
+ if (pProfile) {
+ /*
+ * IEEE 11n spec (8.4.3): HT STA shall
+ * eliminate TKIP as a choice for the pairwise
+ * cipher suite if CCMP is advertised by the AP
+ * or if the AP included an HT capabilities
+ * element in its Beacons and Probe Response.
+ */
+ if ((!CSR_IS_11n_ALLOWED(
+ pProfile->negotiatedUCEncryptionType))
+ && ((eCSR_CFG_DOT11_MODE_11N ==
+ cfgDot11ModeToUse) ||
+#ifdef WLAN_FEATURE_11AC
+ (eCSR_CFG_DOT11_MODE_11AC ==
+ cfgDot11ModeToUse)
+#endif
+ )) {
+ /* We cannot do 11n here */
+ if (!CDS_IS_CHANNEL_5GHZ
+ (pSirBssDesc->channelId)) {
+ cfgDot11ModeToUse =
+ eCSR_CFG_DOT11_MODE_11G;
+ } else {
+ cfgDot11ModeToUse =
+ eCSR_CFG_DOT11_MODE_11A;
+ }
+ }
+ }
+ *pReturnCfgDot11Mode = cfgDot11ModeToUse;
+ }
+
+ return fMatch;
+}
+
+eCsrCfgDot11Mode csr_find_best_phy_mode(tpAniSirGlobal pMac, uint32_t phyMode)
+{
+ eCsrCfgDot11Mode cfgDot11ModeToUse;
+ eCsrBand eBand = pMac->roam.configParam.eBand;
+
+ if ((0 == phyMode) ||
+#ifdef WLAN_FEATURE_11AC
+ (eCSR_DOT11_MODE_11ac & phyMode) ||
+#endif
+ (eCSR_DOT11_MODE_AUTO & phyMode)) {
+#ifdef WLAN_FEATURE_11AC
+ if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) {
+ cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11AC;
+ } else
+#endif
+ {
+ /* Default to 11N mode if user has configured 11ac mode
+ * and FW doesn't supports 11ac mode .
+ */
+ cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11N;
+ }
+ } else {
+ if ((eCSR_DOT11_MODE_11n | eCSR_DOT11_MODE_11n_ONLY) & phyMode) {
+ cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11N;
+ } else if (eCSR_DOT11_MODE_abg & phyMode) {
+ if (eCSR_BAND_24 != eBand) {
+ cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11A;
+ } else {
+ cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11G;
+ }
+ } else if (eCSR_DOT11_MODE_11a & phyMode) {
+ cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11A;
+ } else if ((eCSR_DOT11_MODE_11g | eCSR_DOT11_MODE_11g_ONLY) &
+ phyMode) {
+ cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11G;
+ } else {
+ cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11B;
+ }
+ }
+
+ return cfgDot11ModeToUse;
+}
+
+uint32_t csr_get11h_power_constraint(tHalHandle hHal,
+ tDot11fIEPowerConstraints *pPowerConstraint)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ uint32_t localPowerConstraint = 0;
+
+ /* check if .11h support is enabled, if not, the power constraint is 0. */
+ if (pMac->roam.configParam.Is11hSupportEnabled
+ && pPowerConstraint->present) {
+ localPowerConstraint = pPowerConstraint->localPowerConstraints;
+ }
+
+ return localPowerConstraint;
+}
+
+bool csr_is_profile_wpa(tCsrRoamProfile *pProfile)
+{
+ bool fWpaProfile = false;
+
+ switch (pProfile->negotiatedAuthType) {
+ case eCSR_AUTH_TYPE_WPA:
+ case eCSR_AUTH_TYPE_WPA_PSK:
+ case eCSR_AUTH_TYPE_WPA_NONE:
+#ifdef FEATURE_WLAN_ESE
+ case eCSR_AUTH_TYPE_CCKM_WPA:
+#endif
+ fWpaProfile = true;
+ break;
+
+ default:
+ fWpaProfile = false;
+ break;
+ }
+
+ if (fWpaProfile) {
+ switch (pProfile->negotiatedUCEncryptionType) {
+ case eCSR_ENCRYPT_TYPE_WEP40:
+ case eCSR_ENCRYPT_TYPE_WEP104:
+ case eCSR_ENCRYPT_TYPE_TKIP:
+ case eCSR_ENCRYPT_TYPE_AES:
+ fWpaProfile = true;
+ break;
+
+ default:
+ fWpaProfile = false;
+ break;
+ }
+ }
+ return fWpaProfile;
+}
+
+bool csr_is_profile_rsn(tCsrRoamProfile *pProfile)
+{
+ bool fRSNProfile = false;
+
+ switch (pProfile->negotiatedAuthType) {
+ case eCSR_AUTH_TYPE_RSN:
+ case eCSR_AUTH_TYPE_RSN_PSK:
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ case eCSR_AUTH_TYPE_FT_RSN:
+ case eCSR_AUTH_TYPE_FT_RSN_PSK:
+#endif
+#ifdef FEATURE_WLAN_ESE
+ case eCSR_AUTH_TYPE_CCKM_RSN:
+#endif
+#ifdef WLAN_FEATURE_11W
+ case eCSR_AUTH_TYPE_RSN_PSK_SHA256:
+ case eCSR_AUTH_TYPE_RSN_8021X_SHA256:
+#endif
+ fRSNProfile = true;
+ break;
+
+ default:
+ fRSNProfile = false;
+ break;
+ }
+
+ if (fRSNProfile) {
+ switch (pProfile->negotiatedUCEncryptionType) {
+ /* !!REVIEW - For WPA2, use of RSN IE mandates */
+ /* use of AES as encryption. Here, we qualify */
+ /* even if encryption type is WEP or TKIP */
+ case eCSR_ENCRYPT_TYPE_WEP40:
+ case eCSR_ENCRYPT_TYPE_WEP104:
+ case eCSR_ENCRYPT_TYPE_TKIP:
+ case eCSR_ENCRYPT_TYPE_AES:
+ fRSNProfile = true;
+ break;
+
+ default:
+ fRSNProfile = false;
+ break;
+ }
+ }
+ return fRSNProfile;
+}
+
+/**
+ * csr_isconcurrentsession_valid() - check if concurrent session is valid
+ * @mac_ctx: pointer to mac context
+ * @cur_sessionid: current session id
+ * @cur_bss_persona: current BSS persona
+ *
+ * This function will check if concurrent session is valid
+ *
+ * Return: CDF_STATUS
+ */
+CDF_STATUS
+csr_isconcurrentsession_valid(tpAniSirGlobal mac_ctx, uint32_t cur_sessionid,
+ tCDF_CON_MODE cur_bss_persona)
+{
+ uint32_t sessionid = 0;
+ tCDF_CON_MODE bss_persona;
+ eCsrConnectState connect_state, temp;
+ tCsrRoamSession *roam_session;
+
+ for (sessionid = 0; sessionid < CSR_ROAM_SESSION_MAX; sessionid++) {
+ if (cur_sessionid == sessionid)
+ continue;
+ if (!CSR_IS_SESSION_VALID(mac_ctx, sessionid))
+ continue;
+ roam_session = &mac_ctx->roam.roamSession[sessionid];
+ bss_persona = roam_session->bssParams.bssPersona;
+ connect_state = roam_session->connectState;
+
+ switch (cur_bss_persona) {
+ case CDF_STA_MODE:
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_INFO,
+ FL("** STA session **"));
+ return CDF_STATUS_SUCCESS;
+
+ case CDF_SAP_MODE:
+ temp = eCSR_ASSOC_STATE_TYPE_IBSS_DISCONNECTED;
+#ifndef WLAN_FEATURE_MBSSID
+ if ((bss_persona == CDF_SAP_MODE) &&
+ (connect_state !=
+ eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED)) {
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_ERROR,
+ FL("sap mode already exist"));
+ return CDF_STATUS_E_FAILURE;
+ } else
+#endif
+ if ((bss_persona == CDF_IBSS_MODE)
+ && (connect_state != temp)) {
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_ERROR,
+ FL("Can't start GO"));
+ return CDF_STATUS_E_FAILURE;
+ }
+ break;
+
+ case CDF_P2P_GO_MODE:
+ temp = eCSR_ASSOC_STATE_TYPE_IBSS_DISCONNECTED;
+ if ((bss_persona == CDF_P2P_GO_MODE) &&
+ (connect_state !=
+ eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED)) {
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_ERROR,
+ FL("GO mode already exists"));
+ return CDF_STATUS_E_FAILURE;
+ } else if ((bss_persona == CDF_IBSS_MODE)
+ && (connect_state != temp)) {
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_ERROR,
+ FL("Can't start SAP"));
+ return CDF_STATUS_E_FAILURE;
+ }
+ break;
+ case CDF_IBSS_MODE:
+ if ((bss_persona == CDF_IBSS_MODE) && (connect_state !=
+ eCSR_ASSOC_STATE_TYPE_IBSS_CONNECTED)) {
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_ERROR,
+ FL("IBSS mode already exist"));
+ return CDF_STATUS_E_FAILURE;
+ } else if (((bss_persona == CDF_P2P_GO_MODE) ||
+ (bss_persona == CDF_SAP_MODE)) &&
+ (connect_state !=
+ eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED)) {
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_ERROR,
+ FL("Can't start GO"));
+ return CDF_STATUS_E_FAILURE;
+ }
+ break;
+ case CDF_P2P_CLIENT_MODE:
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_INFO,
+ FL("**P2P-Client session**"));
+ return CDF_STATUS_SUCCESS;
+ default:
+ CDF_TRACE(CDF_MODULE_ID_SME,
+ CDF_TRACE_LEVEL_ERROR,
+ FL("Persona not handled = %d"),
+ cur_bss_persona);
+ break;
+ }
+ }
+ return CDF_STATUS_SUCCESS;
+
+}
+
+/**
+ * csr_update_mcc_p2p_beacon_interval() - update p2p beacon interval
+ * @mac_ctx: pointer to mac context
+ *
+ * This function is to update the mcc p2p beacon interval
+ *
+ * Return: CDF_STATUS
+ */
+CDF_STATUS csr_update_mcc_p2p_beacon_interval(tpAniSirGlobal mac_ctx)
+{
+ uint32_t session_id = 0;
+ tCsrRoamSession *roam_session;
+
+ /* If MCC is not supported just break and return SUCCESS */
+ if (!mac_ctx->roam.configParam.fenableMCCMode)
+ return CDF_STATUS_E_FAILURE;
+
+ for (session_id = 0; session_id < CSR_ROAM_SESSION_MAX; session_id++) {
+ /*
+ * If GO in MCC support different beacon interval,
+ * change the BI of the P2P-GO
+ */
+ roam_session = &mac_ctx->roam.roamSession[session_id];
+ if (roam_session->bssParams.bssPersona != CDF_P2P_GO_MODE)
+ continue;
+ /*
+ * Handle different BI scneario based on the
+ * configuration set.If Config is set to 0x02 then
+ * Disconnect all the P2P clients associated. If config
+ * is set to 0x04 then update the BI without
+ * disconnecting all the clients
+ */
+ if ((mac_ctx->roam.configParam.fAllowMCCGODiffBI == 0x04)
+ && (roam_session->bssParams.
+ updatebeaconInterval)) {
+ return csr_send_chng_mcc_beacon_interval(mac_ctx,
+ session_id);
+ } else if (roam_session->bssParams.updatebeaconInterval) {
+ /*
+ * If the configuration of fAllowMCCGODiffBI is set to
+ * other than 0x04
+ */
+ return csr_roam_call_callback(mac_ctx,
+ session_id,
+ NULL, 0,
+ eCSR_ROAM_DISCONNECT_ALL_P2P_CLIENTS,
+ eCSR_ROAM_RESULT_NONE);
+ }
+ }
+ return CDF_STATUS_E_FAILURE;
+}
+
+uint16_t csr_calculate_mcc_beacon_interval(tpAniSirGlobal pMac, uint16_t sta_bi,
+ uint16_t go_gbi)
+{
+ uint8_t num_beacons = 0;
+ uint8_t is_multiple = 0;
+ uint16_t go_cbi = 0;
+ uint16_t go_fbi = 0;
+ uint16_t sta_cbi = 0;
+
+ /* If GO's given beacon Interval is less than 100 */
+ if (go_gbi < 100)
+ go_cbi = 100;
+ /* if GO's given beacon Interval is greater than or equal to 100 */
+ else
+ go_cbi = 100 + (go_gbi % 100);
+
+ if (sta_bi == 0) {
+ /* There is possibility to receive zero as value.
+ Which will cause divide by zero. Hence initialise with 100
+ */
+ sta_bi = 100;
+ sms_log(pMac, LOGW,
+ FL("sta_bi 2nd parameter is zero, initialize to %d"),
+ sta_bi);
+ }
+ /* check, if either one is multiple of another */
+ if (sta_bi > go_cbi) {
+ is_multiple = !(sta_bi % go_cbi);
+ } else {
+ is_multiple = !(go_cbi % sta_bi);
+ }
+ /* if it is multiple, then accept GO's beacon interval range [100,199] as it is */
+ if (is_multiple) {
+ return go_cbi;
+ }
+ /* else , if it is not multiple, then then check for number of beacons to be */
+ /* inserted based on sta BI */
+ num_beacons = sta_bi / 100;
+ if (num_beacons) {
+ /* GO's final beacon interval will be aligned to sta beacon interval, but */
+ /* in the range of [100, 199]. */
+ sta_cbi = sta_bi / num_beacons;
+ go_fbi = sta_cbi;
+ } else {
+ /* if STA beacon interval is less than 100, use GO's change bacon interval */
+ /* instead of updating to STA's beacon interval. */
+ go_fbi = go_cbi;
+ }
+ return go_fbi;
+}
+
+CDF_STATUS csr_validate_mcc_beacon_interval(tpAniSirGlobal pMac, uint8_t channelId,
+ uint16_t *beaconInterval,
+ uint32_t cursessionId,
+ tCDF_CON_MODE currBssPersona)
+{
+ uint32_t sessionId = 0;
+ uint16_t new_beaconInterval = 0;
+
+ /* If MCC is not supported just break */
+ if (!pMac->roam.configParam.fenableMCCMode) {
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) {
+ if (cursessionId != sessionId) {
+ if (!CSR_IS_SESSION_VALID(pMac, sessionId)) {
+ continue;
+ }
+
+ switch (currBssPersona) {
+ case CDF_STA_MODE:
+ if (pMac->roam.roamSession[sessionId].
+ pCurRoamProfile &&
+ (pMac->roam.roamSession[sessionId].
+ pCurRoamProfile->csrPersona ==
+ CDF_P2P_CLIENT_MODE)) {
+ /* check for P2P client mode */
+ sms_log(pMac, LOG1,
+ FL
+ (" Beacon Interval Validation not required for STA/CLIENT"));
+ }
+ /*
+ * IF SAP has started and STA wants to connect
+ * on different channel MCC should
+ * MCC should not be enabled so making it
+ * false to enforce on same channel
+ */
+ else if (pMac->roam.roamSession[sessionId].
+ bssParams.bssPersona ==
+ CDF_SAP_MODE) {
+ if (pMac->roam.roamSession[sessionId].
+ bssParams.operationChn !=
+ channelId) {
+ sms_log(pMac, LOGE,
+ FL
+ ("*** MCC with SAP+STA sessions ****"));
+ return CDF_STATUS_SUCCESS;
+ }
+ } else if (pMac->roam.roamSession[sessionId].
+ bssParams.bssPersona ==
+ CDF_P2P_GO_MODE) {
+ /*
+ * Check for P2P go scenario
+ * if GO in MCC support different
+ * beacon interval,
+ * change the BI of the P2P-GO
+ */
+ if ((pMac->roam.roamSession[sessionId].
+ bssParams.operationChn !=
+ channelId)
+ && (pMac->roam.
+ roamSession[sessionId].
+ bssParams.beaconInterval !=
+ *beaconInterval)) {
+ /* if GO in MCC support different beacon interval, return success */
+ if (pMac->roam.configParam.
+ fAllowMCCGODiffBI == 0x01) {
+ return
+ CDF_STATUS_SUCCESS;
+ }
+ /* Send only Broadcast disassoc and update beaconInterval */
+ /* If configuration is set to 0x04 then dont */
+ /* disconnect all the station */
+ else if ((pMac->roam.
+ configParam.
+ fAllowMCCGODiffBI ==
+ 0x02)
+ || (pMac->roam.
+ configParam.
+ fAllowMCCGODiffBI
+ == 0x04)) {
+ /* Check to pass the right beacon Interval */
+ if (pMac->roam.configParam.conc_custom_rule1 ||
+ pMac->roam.configParam.conc_custom_rule2) {
+ new_beaconInterval = CSR_CUSTOM_CONC_GO_BI;
+ } else {
+ new_beaconInterval =
+ csr_calculate_mcc_beacon_interval(pMac,
+ *beaconInterval,
+ pMac->roam.
+ roamSession
+ [sessionId].
+ bssParams.
+ beaconInterval);
+ }
+ sms_log(pMac, LOG1,
+ FL
+ (" Peer AP BI : %d, new Beacon Interval: %d"),
+ *beaconInterval,
+ new_beaconInterval);
+ /* Update the becon Interval */
+ if (new_beaconInterval
+ !=
+ pMac->roam.
+ roamSession
+ [sessionId].
+ bssParams.
+ beaconInterval) {
+ /* Update the beaconInterval now */
+ sms_log(pMac,
+ LOGE,
+ FL
+ (" Beacon Interval got changed config used: %d\n"),
+ pMac->
+ roam.
+ configParam.
+ fAllowMCCGODiffBI);
+
+ pMac->roam.
+ roamSession
+ [sessionId].
+ bssParams.
+ beaconInterval
+ =
+ new_beaconInterval;
+ pMac->roam.
+ roamSession
+ [sessionId].
+ bssParams.
+ updatebeaconInterval
+ = true;
+ return
+ csr_update_mcc_p2p_beacon_interval
+ (pMac);
+ }
+ return
+ CDF_STATUS_SUCCESS;
+ }
+ /* Disconnect the P2P session */
+ else if (pMac->roam.configParam.
+ fAllowMCCGODiffBI ==
+ 0x03) {
+ pMac->roam.roamSession[sessionId].bssParams.updatebeaconInterval = false;
+ return
+ csr_roam_call_callback
+ (pMac, sessionId,
+ NULL, 0,
+ eCSR_ROAM_SEND_P2P_STOP_BSS,
+ eCSR_ROAM_RESULT_NONE);
+ } else {
+ sms_log(pMac, LOGE,
+ FL
+ ("BeaconInterval is different cannot connect to preferred AP..."));
+ return
+ CDF_STATUS_E_FAILURE;
+ }
+ }
+ }
+ break;
+
+ case CDF_P2P_CLIENT_MODE:
+ if (pMac->roam.roamSession[sessionId].
+ pCurRoamProfile &&
+ (pMac->roam.roamSession[sessionId].
+ pCurRoamProfile->csrPersona ==
+ CDF_STA_MODE)) {
+ /* check for P2P client mode */
+ sms_log(pMac, LOG1,
+ FL
+ (" Ignore Beacon Interval Validation..."));
+ } else if (pMac->roam.roamSession[sessionId].
+ bssParams.bssPersona ==
+ CDF_P2P_GO_MODE) {
+ /* Check for P2P go scenario */
+ if ((pMac->roam.roamSession[sessionId].
+ bssParams.operationChn !=
+ channelId)
+ && (pMac->roam.
+ roamSession[sessionId].
+ bssParams.beaconInterval !=
+ *beaconInterval)) {
+ sms_log(pMac, LOGE,
+ FL
+ ("BeaconInterval is different cannot connect to P2P_GO network ..."));
+ return CDF_STATUS_E_FAILURE;
+ }
+ }
+ break;
+
+ case CDF_SAP_MODE:
+ break;
+
+ case CDF_P2P_GO_MODE:
+ {
+ if (pMac->roam.roamSession[sessionId].
+ pCurRoamProfile &&
+ ((pMac->roam.roamSession[sessionId].
+ pCurRoamProfile->csrPersona ==
+ CDF_P2P_CLIENT_MODE) ||
+ (pMac->roam.roamSession[sessionId].
+ pCurRoamProfile->csrPersona ==
+ CDF_STA_MODE))) {
+ /* check for P2P_client scenario */
+ if ((pMac->roam.
+ roamSession[sessionId].
+ connectedProfile.
+ operationChannel == 0)
+ && (pMac->roam.
+ roamSession[sessionId].
+ connectedProfile.
+ beaconInterval == 0)) {
+ continue;
+ }
+
+ if (csr_is_conn_state_connected_infra
+ (pMac, sessionId)
+ && (pMac->roam.
+ roamSession[sessionId].
+ connectedProfile.
+ operationChannel !=
+ channelId)
+ && (pMac->roam.
+ roamSession[sessionId].
+ connectedProfile.
+ beaconInterval !=
+ *beaconInterval)) {
+ /*
+ * Updated beaconInterval should be used only when we are starting a new BSS
+ * not incase of client or STA case
+ */
+ /* Calculate beacon Interval for P2P-GO incase of MCC */
+ if (pMac->roam.configParam.conc_custom_rule1 ||
+ pMac->roam.configParam.conc_custom_rule2) {
+ new_beaconInterval = CSR_CUSTOM_CONC_GO_BI;
+ } else {
+ new_beaconInterval =
+ csr_calculate_mcc_beacon_interval
+ (pMac,
+ pMac->roam.
+ roamSession
+ [sessionId].
+ connectedProfile.
+ beaconInterval,
+ *beaconInterval);
+ }
+ if (*beaconInterval !=
+ new_beaconInterval)
+ *beaconInterval
+ =
+ new_beaconInterval;
+ return
+ CDF_STATUS_SUCCESS;
+ }
+ }
+ }
+ break;
+
+ default:
+ sms_log(pMac, LOGE,
+ FL(" Persona not supported : %d"),
+ currBssPersona);
+ return CDF_STATUS_E_FAILURE;
+ }
+ }
+ }
+
+ return CDF_STATUS_SUCCESS;
+}
+
+#ifdef WLAN_FEATURE_VOWIFI_11R
+/* Function to return true if the authtype is 11r */
+bool csr_is_auth_type11r(eCsrAuthType AuthType, uint8_t mdiePresent)
+{
+ switch (AuthType) {
+ case eCSR_AUTH_TYPE_OPEN_SYSTEM:
+ if (mdiePresent)
+ return true;
+ break;
+ case eCSR_AUTH_TYPE_FT_RSN_PSK:
+ case eCSR_AUTH_TYPE_FT_RSN:
+ return true;
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+/* Function to return true if the profile is 11r */
+bool csr_is_profile11r(tCsrRoamProfile *pProfile)
+{
+ return csr_is_auth_type11r(pProfile->negotiatedAuthType,
+ pProfile->MDID.mdiePresent);
+}
+
+#endif
+
+#ifdef FEATURE_WLAN_ESE
+
+/* Function to return true if the authtype is ESE */
+bool csr_is_auth_type_ese(eCsrAuthType AuthType)
+{
+ switch (AuthType) {
+ case eCSR_AUTH_TYPE_CCKM_WPA:
+ case eCSR_AUTH_TYPE_CCKM_RSN:
+ return true;
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+/* Function to return true if the profile is ESE */
+bool csr_is_profile_ese(tCsrRoamProfile *pProfile)
+{
+ return csr_is_auth_type_ese(pProfile->negotiatedAuthType);
+}
+
+#endif
+
+#ifdef FEATURE_WLAN_WAPI
+bool csr_is_profile_wapi(tCsrRoamProfile *pProfile)
+{
+ bool fWapiProfile = false;
+
+ switch (pProfile->negotiatedAuthType) {
+ case eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE:
+ case eCSR_AUTH_TYPE_WAPI_WAI_PSK:
+ fWapiProfile = true;
+ break;
+
+ default:
+ fWapiProfile = false;
+ break;
+ }
+
+ if (fWapiProfile) {
+ switch (pProfile->negotiatedUCEncryptionType) {
+ case eCSR_ENCRYPT_TYPE_WPI:
+ fWapiProfile = true;
+ break;
+
+ default:
+ fWapiProfile = false;
+ break;
+ }
+ }
+ return fWapiProfile;
+}
+
+static bool csr_is_wapi_oui_equal(tpAniSirGlobal pMac, uint8_t *Oui1,
+ uint8_t *Oui2)
+{
+ return cdf_mem_compare(Oui1, Oui2, CSR_WAPI_OUI_SIZE);
+}
+
+static bool csr_is_wapi_oui_match(tpAniSirGlobal pMac,
+ uint8_t AllCyphers[][CSR_WAPI_OUI_SIZE],
+ uint8_t cAllCyphers, uint8_t Cypher[],
+ uint8_t Oui[])
+{
+ bool fYes = false;
+ uint8_t idx;
+
+ for (idx = 0; idx < cAllCyphers; idx++) {
+ if (csr_is_wapi_oui_equal(pMac, AllCyphers[idx], Cypher)) {
+ fYes = true;
+ break;
+ }
+ }
+
+ if (fYes && Oui) {
+ cdf_mem_copy(Oui, AllCyphers[idx], CSR_WAPI_OUI_SIZE);
+ }
+
+ return fYes;
+}
+#endif /* FEATURE_WLAN_WAPI */
+
+static bool csr_is_wpa_oui_equal(tpAniSirGlobal pMac, uint8_t *Oui1,
+ uint8_t *Oui2)
+{
+ return cdf_mem_compare(Oui1, Oui2, CSR_WPA_OUI_SIZE);
+}
+
+static bool csr_is_oui_match(tpAniSirGlobal pMac,
+ uint8_t AllCyphers[][CSR_WPA_OUI_SIZE],
+ uint8_t cAllCyphers, uint8_t Cypher[], uint8_t Oui[])
+{
+ bool fYes = false;
+ uint8_t idx;
+
+ for (idx = 0; idx < cAllCyphers; idx++) {
+ if (csr_is_wpa_oui_equal(pMac, AllCyphers[idx], Cypher)) {
+ fYes = true;
+ break;
+ }
+ }
+
+ if (fYes && Oui) {
+ cdf_mem_copy(Oui, AllCyphers[idx], CSR_WPA_OUI_SIZE);
+ }
+
+ return fYes;
+}
+
+static bool csr_match_rsnoui_index(tpAniSirGlobal pMac,
+ uint8_t AllCyphers[][CSR_RSN_OUI_SIZE],
+ uint8_t cAllCyphers, uint8_t ouiIndex,
+ uint8_t Oui[])
+{
+ return csr_is_oui_match
+ (pMac, AllCyphers, cAllCyphers, csr_rsn_oui[ouiIndex], Oui);
+
+}
+
+#ifdef FEATURE_WLAN_WAPI
+static bool csr_match_wapi_oui_index(tpAniSirGlobal pMac,
+ uint8_t AllCyphers[][CSR_WAPI_OUI_SIZE],
+ uint8_t cAllCyphers, uint8_t ouiIndex,
+ uint8_t Oui[])
+{
+ return csr_is_wapi_oui_match
+ (pMac, AllCyphers, cAllCyphers, csr_wapi_oui[ouiIndex], Oui);
+
+}
+#endif /* FEATURE_WLAN_WAPI */
+
+static bool csr_match_wpaoui_index(tpAniSirGlobal pMac,
+ uint8_t AllCyphers[][CSR_RSN_OUI_SIZE],
+ uint8_t cAllCyphers, uint8_t ouiIndex,
+ uint8_t Oui[])
+{
+ return csr_is_oui_match
+ (pMac, AllCyphers, cAllCyphers, csr_wpa_oui[ouiIndex], Oui);
+
+}
+
+#ifdef FEATURE_WLAN_WAPI
+static bool csr_is_auth_wapi_cert(tpAniSirGlobal pMac,
+ uint8_t AllSuites[][CSR_WAPI_OUI_SIZE],
+ uint8_t cAllSuites, uint8_t Oui[])
+{
+ return csr_is_wapi_oui_match
+ (pMac, AllSuites, cAllSuites, csr_wapi_oui[1], Oui);
+}
+
+static bool csr_is_auth_wapi_psk(tpAniSirGlobal pMac,
+ uint8_t AllSuites[][CSR_WAPI_OUI_SIZE],
+ uint8_t cAllSuites, uint8_t Oui[])
+{
+ return csr_is_wapi_oui_match
+ (pMac, AllSuites, cAllSuites, csr_wapi_oui[2], Oui);
+}
+#endif /* FEATURE_WLAN_WAPI */
+
+#ifdef WLAN_FEATURE_VOWIFI_11R
+
+/*
+ * Function for 11R FT Authentication. We match the FT Authentication Cipher
+ * suite here. This matches for FT Auth with the 802.1X exchange.
+ */
+static bool csr_is_ft_auth_rsn(tpAniSirGlobal pMac,
+ uint8_t AllSuites[][CSR_RSN_OUI_SIZE],
+ uint8_t cAllSuites, uint8_t Oui[])
+{
+ return csr_is_oui_match
+ (pMac, AllSuites, cAllSuites, csr_rsn_oui[03], Oui);
+}
+
+/*
+ * Function for 11R FT Authentication. We match the FT Authentication Cipher
+ * suite here. This matches for FT Auth with the PSK.
+ */
+static bool csr_is_ft_auth_rsn_psk(tpAniSirGlobal pMac,
+ uint8_t AllSuites[][CSR_RSN_OUI_SIZE],
+ uint8_t cAllSuites, uint8_t Oui[])
+{
+ return csr_is_oui_match
+ (pMac, AllSuites, cAllSuites, csr_rsn_oui[04], Oui);
+}
+
+#endif
+
+#ifdef FEATURE_WLAN_ESE
+
+/*
+ * Function for ESE CCKM AKM Authentication. We match the CCKM AKM
+ * Authentication Key Management suite here. This matches for CCKM AKM Auth
+ * with the 802.1X exchange.
+ */
+static bool csr_is_ese_cckm_auth_rsn(tpAniSirGlobal pMac,
+ uint8_t AllSuites[][CSR_RSN_OUI_SIZE],
+ uint8_t cAllSuites, uint8_t Oui[])
+{
+ return csr_is_oui_match
+ (pMac, AllSuites, cAllSuites, csr_rsn_oui[06], Oui);
+}
+
+static bool csr_is_ese_cckm_auth_wpa(tpAniSirGlobal pMac,
+ uint8_t AllSuites[][CSR_WPA_OUI_SIZE],
+ uint8_t cAllSuites, uint8_t Oui[])
+{
+ return csr_is_oui_match
+ (pMac, AllSuites, cAllSuites, csr_wpa_oui[06], Oui);
+}
+
+#endif
+
+static bool csr_is_auth_rsn(tpAniSirGlobal pMac,
+ uint8_t AllSuites[][CSR_RSN_OUI_SIZE],
+ uint8_t cAllSuites, uint8_t Oui[])
+{
+ return csr_is_oui_match
+ (pMac, AllSuites, cAllSuites, csr_rsn_oui[01], Oui);
+}
+
+static bool csr_is_auth_rsn_psk(tpAniSirGlobal pMac,
+ uint8_t AllSuites[][CSR_RSN_OUI_SIZE],
+ uint8_t cAllSuites, uint8_t Oui[])
+{
+ return csr_is_oui_match
+ (pMac, AllSuites, cAllSuites, csr_rsn_oui[02], Oui);
+}
+
+#ifdef WLAN_FEATURE_11W
+static bool csr_is_auth_rsn_psk_sha256(tpAniSirGlobal pMac,
+ uint8_t AllSuites[][CSR_RSN_OUI_SIZE],
+ uint8_t cAllSuites, uint8_t Oui[])
+{
+ return csr_is_oui_match
+ (pMac, AllSuites, cAllSuites, csr_rsn_oui[07], Oui);
+}
+static bool csr_is_auth_rsn8021x_sha256(tpAniSirGlobal pMac,
+ uint8_t AllSuites[][CSR_RSN_OUI_SIZE],
+ uint8_t cAllSuites, uint8_t Oui[])
+{
+ return csr_is_oui_match
+ (pMac, AllSuites, cAllSuites, csr_rsn_oui[8], Oui);
+}
+#endif
+
+static bool csr_is_auth_wpa(tpAniSirGlobal pMac,
+ uint8_t AllSuites[][CSR_WPA_OUI_SIZE],
+ uint8_t cAllSuites, uint8_t Oui[])
+{
+ return csr_is_oui_match
+ (pMac, AllSuites, cAllSuites, csr_wpa_oui[01], Oui);
+}
+
+static bool csr_is_auth_wpa_psk(tpAniSirGlobal pMac,
+ uint8_t AllSuites[][CSR_WPA_OUI_SIZE],
+ uint8_t cAllSuites, uint8_t Oui[])
+{
+ return csr_is_oui_match
+ (pMac, AllSuites, cAllSuites, csr_wpa_oui[02], Oui);
+}
+
+uint8_t csr_get_oui_index_from_cipher(eCsrEncryptionType enType)
+{
+ uint8_t OUIIndex;
+
+ switch (enType) {
+ case eCSR_ENCRYPT_TYPE_WEP40:
+ case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY:
+ OUIIndex = CSR_OUI_WEP40_OR_1X_INDEX;
+ break;
+ case eCSR_ENCRYPT_TYPE_WEP104:
+ case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY:
+ OUIIndex = CSR_OUI_WEP104_INDEX;
+ break;
+ case eCSR_ENCRYPT_TYPE_TKIP:
+ OUIIndex = CSR_OUI_TKIP_OR_PSK_INDEX;
+ break;
+ case eCSR_ENCRYPT_TYPE_AES:
+ OUIIndex = CSR_OUI_AES_INDEX;
+ break;
+ case eCSR_ENCRYPT_TYPE_NONE:
+ OUIIndex = CSR_OUI_USE_GROUP_CIPHER_INDEX;
+ break;
+#ifdef FEATURE_WLAN_WAPI
+ case eCSR_ENCRYPT_TYPE_WPI:
+ OUIIndex = CSR_OUI_WAPI_WAI_CERT_OR_SMS4_INDEX;
+ break;
+#endif /* FEATURE_WLAN_WAPI */
+ default: /* HOWTO handle this? */
+ OUIIndex = CSR_OUI_RESERVED_INDEX;
+ break;
+ } /* switch */
+
+ return OUIIndex;
+}
+/**
+ * csr_get_rsn_information() - to get RSN infomation
+ * @hal: pointer to HAL
+ * @auth_type: auth type
+ * @encr_type: encryption type
+ * @mc_encryption: multicast encryption type
+ * @rsn_ie: pointer to RSN IE
+ * @ucast_cipher: Unicast cipher
+ * @mcast_cipher: Multicast cipher
+ * @auth_suite: Authentication suite
+ * @capabilities: RSN capabilities
+ * @negotiated_authtype: Negotiated auth type
+ * @negotiated_mccipher: negotiated multicast cipher
+ *
+ * This routine will get all RSN information
+ *
+ * Return: bool
+ */
+bool csr_get_rsn_information(tHalHandle hal, tCsrAuthList *auth_type,
+ eCsrEncryptionType encr_type,
+ tCsrEncryptionList *mc_encryption,
+ tDot11fIERSN *rsn_ie, uint8_t *ucast_cipher,
+ uint8_t *mcast_cipher, uint8_t *auth_suite,
+ tCsrRSNCapabilities *capabilities,
+ eCsrAuthType *negotiated_authtype,
+ eCsrEncryptionType *negotiated_mccipher)
+{
+ tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal);
+ bool acceptable_cipher = false;
+ uint8_t c_ucast_cipher = 0;
+ uint8_t c_mcast_cipher = 0;
+ uint8_t c_auth_suites = 0, i;
+ uint8_t unicast[CSR_RSN_OUI_SIZE];
+ uint8_t multicast[CSR_RSN_OUI_SIZE];
+ uint8_t authsuites[CSR_RSN_MAX_AUTH_SUITES][CSR_RSN_OUI_SIZE];
+ uint8_t authentication[CSR_RSN_OUI_SIZE];
+ uint8_t mccipher_arr[CSR_RSN_MAX_MULTICAST_CYPHERS][CSR_RSN_OUI_SIZE];
+ eCsrAuthType neg_authtype = eCSR_AUTH_TYPE_UNKNOWN;
+
+ if (!rsn_ie->present)
+ goto end;
+ c_mcast_cipher++;
+ cdf_mem_copy(mccipher_arr, rsn_ie->gp_cipher_suite,
+ CSR_RSN_OUI_SIZE);
+ c_ucast_cipher =
+ (uint8_t) (rsn_ie->pwise_cipher_suite_count);
+ c_auth_suites = (uint8_t) (rsn_ie->akm_suite_count);
+ for (i = 0; i < c_auth_suites && i < CSR_RSN_MAX_AUTH_SUITES; i++) {
+ cdf_mem_copy((void *)&authsuites[i],
+ (void *)&rsn_ie->akm_suites[i], CSR_RSN_OUI_SIZE);
+ }
+
+ /* Check - Is requested unicast Cipher supported by the BSS. */
+ acceptable_cipher = csr_match_rsnoui_index(mac_ctx,
+ rsn_ie->pwise_cipher_suites, c_ucast_cipher,
+ csr_get_oui_index_from_cipher(encr_type),
+ unicast);
+
+ if (!acceptable_cipher)
+ goto end;
+
+ /* unicast is supported. Pick the first matching Group cipher, if any */
+ for (i = 0; i < mc_encryption->numEntries; i++) {
+ acceptable_cipher = csr_match_rsnoui_index(mac_ctx,
+ mccipher_arr, c_mcast_cipher,
+ csr_get_oui_index_from_cipher(
+ mc_encryption->encryptionType[i]),
+ multicast);
+ if (acceptable_cipher)
+ break;
+ }
+ if (!acceptable_cipher)
+ goto end;
+
+ if (negotiated_mccipher)
+ *negotiated_mccipher = mc_encryption->encryptionType[i];
+
+ /* Initializing with false as it has true value already */
+ acceptable_cipher = false;
+ for (i = 0; i < auth_type->numEntries; i++) {
+ /*
+ * Ciphers are supported, Match authentication algorithm and
+ * pick first matching authtype.
+ */
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ /* Changed the AKM suites according to order of preference */
+ if (csr_is_ft_auth_rsn(mac_ctx, authsuites,
+ c_auth_suites, authentication)) {
+ if (eCSR_AUTH_TYPE_FT_RSN == auth_type->authType[i])
+ neg_authtype = eCSR_AUTH_TYPE_FT_RSN;
+ }
+ if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN)
+ && csr_is_ft_auth_rsn_psk(mac_ctx, authsuites,
+ c_auth_suites, authentication)) {
+ if (eCSR_AUTH_TYPE_FT_RSN_PSK ==
+ auth_type->authType[i])
+ neg_authtype = eCSR_AUTH_TYPE_FT_RSN_PSK;
+ }
+#endif
+#ifdef FEATURE_WLAN_ESE
+ /* ESE only supports 802.1X. No PSK. */
+ if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) &&
+ csr_is_ese_cckm_auth_rsn(mac_ctx, authsuites,
+ c_auth_suites, authentication)) {
+ if (eCSR_AUTH_TYPE_CCKM_RSN == auth_type->authType[i])
+ neg_authtype = eCSR_AUTH_TYPE_CCKM_RSN;
+ }
+#endif
+ if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN)
+ && csr_is_auth_rsn(mac_ctx, authsuites,
+ c_auth_suites, authentication)) {
+ if (eCSR_AUTH_TYPE_RSN == auth_type->authType[i])
+ neg_authtype = eCSR_AUTH_TYPE_RSN;
+ }
+ if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN)
+ && csr_is_auth_rsn_psk(mac_ctx, authsuites,
+ c_auth_suites, authentication)) {
+ if (eCSR_AUTH_TYPE_RSN_PSK == auth_type->authType[i])
+ neg_authtype = eCSR_AUTH_TYPE_RSN_PSK;
+ }
+#ifdef WLAN_FEATURE_11W
+ if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN)
+ && csr_is_auth_rsn_psk_sha256(mac_ctx, authsuites,
+ c_auth_suites, authentication)) {
+ if (eCSR_AUTH_TYPE_RSN_PSK_SHA256 ==
+ auth_type->authType[i])
+ neg_authtype = eCSR_AUTH_TYPE_RSN_PSK_SHA256;
+ }
+ if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) &&
+ csr_is_auth_rsn8021x_sha256(mac_ctx, authsuites,
+ c_auth_suites, authentication)) {
+ if (eCSR_AUTH_TYPE_RSN_8021X_SHA256 ==
+ auth_type->authType[i])
+ neg_authtype = eCSR_AUTH_TYPE_RSN_8021X_SHA256;
+ }
+#endif
+
+ /*
+ * The 1st auth type in the APs RSN IE, to match stations
+ * connecting profiles auth type will cause us to exit this
+ * loop. This is added as some APs advertise multiple akms in
+ * the RSN IE
+ */
+ if (eCSR_AUTH_TYPE_UNKNOWN != neg_authtype) {
+ acceptable_cipher = true;
+ break;
+ }
+ } /* for */
+end:
+ if (acceptable_cipher) {
+ if (mcast_cipher)
+ cdf_mem_copy(mcast_cipher, multicast,
+ CSR_RSN_OUI_SIZE);
+
+ if (ucast_cipher)
+ cdf_mem_copy(ucast_cipher, unicast, CSR_RSN_OUI_SIZE);
+
+ if (auth_suite)
+ cdf_mem_copy(auth_suite, authentication,
+ CSR_RSN_OUI_SIZE);
+
+ if (negotiated_authtype)
+ *negotiated_authtype = neg_authtype;
+
+ if (capabilities) {
+ /* Bit 0 Preauthentication */
+ capabilities->PreAuthSupported =
+ (rsn_ie->RSN_Cap[0] >> 0) & 0x1;
+ /* Bit 1 No Pairwise */
+ capabilities->NoPairwise =
+ (rsn_ie->RSN_Cap[0] >> 1) & 0x1;
+ /* Bit 2, 3 PTKSA Replay Counter */
+ capabilities->PTKSAReplayCounter =
+ (rsn_ie->RSN_Cap[0] >> 2) & 0x3;
+ /* Bit 4, 5 GTKSA Replay Counter */
+ capabilities->GTKSAReplayCounter =
+ (rsn_ie->RSN_Cap[0] >> 4) & 0x3;
+#ifdef WLAN_FEATURE_11W
+ /* Bit 6 MFPR */
+ capabilities->MFPRequired =
+ (rsn_ie->RSN_Cap[0] >> 6) & 0x1;
+ /* Bit 7 MFPC */
+ capabilities->MFPCapable =
+ (rsn_ie->RSN_Cap[0] >> 7) & 0x1;
+#else
+ /* Bit 6 MFPR */
+ capabilities->MFPRequired = 0;
+ /* Bit 7 MFPC */
+ capabilities->MFPCapable = 0;
+#endif
+ /* remaining reserved */
+ capabilities->Reserved = rsn_ie->RSN_Cap[1] & 0xff;
+ }
+ }
+ return acceptable_cipher;
+}
+
+#ifdef WLAN_FEATURE_11W
+/**
+ * csr_is_pmf_capabilities_in_rsn_match() - check for PMF capability
+ * @hHal: Global HAL handle
+ * @pFilterMFPEnabled: given by supplicant to us to specify what kind
+ * of connection supplicant is expecting to make
+ * if it is enabled then make PMF connection.
+ * if it is disabled then make normal connection.
+ * @pFilterMFPRequired: given by supplicant based on our configuration
+ * if it is 1 then we will require mandatory
+ * PMF connection and if it is 0 then we PMF
+ * connection is optional.
+ * @pFilterMFPCapable: given by supplicant based on our configuration
+ * if it 1 then we are PMF capable and if it 0
+ * then we are not PMF capable.
+ * @pRSNIe: RSNIe from Beacon/probe response of
+ * neighbor AP against which we will compare
+ * our capabilities.
+ *
+ * This function is to match our current capabilities with the AP
+ * to which we are expecting make the connection.
+ *
+ * Return: if our PMF capabilities matches with AP then we
+ * will return true to indicate that we are good
+ * to make connection with it. Else we will return false
+ **/
+static bool
+csr_is_pmf_capabilities_in_rsn_match(tHalHandle hHal,
+ bool *pFilterMFPEnabled,
+ uint8_t *pFilterMFPRequired,
+ uint8_t *pFilterMFPCapable,
+ tDot11fIERSN *pRSNIe)
+{
+ uint8_t apProfileMFPCapable = 0;
+ uint8_t apProfileMFPRequired = 0;
+ if (pRSNIe && pFilterMFPEnabled && pFilterMFPCapable
+ && pFilterMFPRequired) {
+ /* Extracting MFPCapable bit from RSN Ie */
+ apProfileMFPCapable = (pRSNIe->RSN_Cap[0] >> 7) & 0x1;
+ apProfileMFPRequired = (pRSNIe->RSN_Cap[0] >> 6) & 0x1;
+ if (*pFilterMFPEnabled && *pFilterMFPCapable
+ && *pFilterMFPRequired && (apProfileMFPCapable == 0)) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ "AP is not capable to make PMF connection");
+ return false;
+ } else if (*pFilterMFPEnabled && *pFilterMFPCapable &&
+ !(*pFilterMFPRequired) &&
+ (apProfileMFPCapable == 0)) {
+ /*
+ * This is tricky, because supplicant asked us to
+ * make mandatory PMF connection eventhough PMF
+ * connection is optional here.
+ * so if AP is not capable of PMF then drop it.
+ * Don't try to connect with it.
+ */
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ "we need PMF connection & AP isn't capable to make PMF connection");
+ return false;
+ } else if (!(*pFilterMFPCapable) &&
+ apProfileMFPCapable && apProfileMFPRequired) {
+
+ /*
+ * In this case, AP with whom we trying to connect
+ * requires mandatory PMF connections and we are not
+ * capable so this AP is not good choice to connect
+ */
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ "AP needs PMF connection and we are not capable of pmf connection");
+ return false;
+ } else if (!(*pFilterMFPEnabled) && *pFilterMFPCapable &&
+ (apProfileMFPCapable == 1)) {
+ CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_INFO,
+ "we don't need PMF connection even though both parties are capable");
+ return false;
+ }
+ }
+ return true;
+}
+#endif
+
+bool csr_is_rsn_match(tHalHandle hHal, tCsrAuthList *pAuthType,
+ eCsrEncryptionType enType,
+ tCsrEncryptionList *pEnMcType,
+ bool *pMFPEnabled, uint8_t *pMFPRequired,
+ uint8_t *pMFPCapable,
+ tDot11fBeaconIEs *pIes,
+ eCsrAuthType *pNegotiatedAuthType,
+ eCsrEncryptionType *pNegotiatedMCCipher)
+{
+ bool fRSNMatch = false;
+
+ /* See if the cyphers in the Bss description match with the settings in the profile. */
+ fRSNMatch =
+ csr_get_rsn_information(hHal, pAuthType, enType, pEnMcType, &pIes->RSN,
+ NULL, NULL, NULL, NULL, pNegotiatedAuthType,
+ pNegotiatedMCCipher);
+#ifdef WLAN_FEATURE_11W
+ /* If all the filter matches then finally checks for PMF capabilities */
+ if (fRSNMatch) {
+ fRSNMatch = csr_is_pmf_capabilities_in_rsn_match(hHal, pMFPEnabled,
+ pMFPRequired,
+ pMFPCapable,
+ &pIes->RSN);
+ }
+#endif
+ return fRSNMatch;
+}
+
+bool csr_lookup_pmkid(tpAniSirGlobal pMac, uint32_t sessionId, uint8_t *pBSSId,
+ uint8_t *pPMKId)
+{
+ bool fRC = false, fMatchFound = false;
+ uint32_t Index;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return false;
+ }
+
+ do {
+ for (Index = 0; Index < CSR_MAX_PMKID_ALLOWED; Index++) {
+ sms_log(pMac, LOG1,
+ "match PMKID " MAC_ADDRESS_STR " to ",
+ MAC_ADDR_ARRAY(pBSSId));
+ if (cdf_mem_compare
+ (pBSSId, pSession->PmkidCacheInfo[Index].BSSID.bytes,
+ sizeof(struct cdf_mac_addr))) {
+ /* match found */
+ fMatchFound = true;
+ break;
+ }
+ }
+
+ if (!fMatchFound)
+ break;
+
+ cdf_mem_copy(pPMKId, pSession->PmkidCacheInfo[Index].PMKID,
+ CSR_RSN_PMKID_SIZE);
+
+ fRC = true;
+ } while (0);
+ sms_log(pMac, LOGW,
+ "csr_lookup_pmkid called return match = %d pMac->roam.NumPmkidCache = %d",
+ fRC, pSession->NumPmkidCache);
+
+ return fRC;
+}
+
+uint8_t csr_construct_rsn_ie(tHalHandle hHal, uint32_t sessionId,
+ tCsrRoamProfile *pProfile,
+ tSirBssDescription *pSirBssDesc,
+ tDot11fBeaconIEs *pIes, tCsrRSNIe *pRSNIe)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ bool fRSNMatch;
+ uint8_t cbRSNIe = 0;
+ uint8_t UnicastCypher[CSR_RSN_OUI_SIZE];
+ uint8_t MulticastCypher[CSR_RSN_OUI_SIZE];
+ uint8_t AuthSuite[CSR_RSN_OUI_SIZE];
+ tCsrRSNAuthIe *pAuthSuite;
+ tCsrRSNCapabilities RSNCapabilities;
+ tCsrRSNPMKIe *pPMK;
+ uint8_t PMKId[CSR_RSN_PMKID_SIZE];
+#ifdef WLAN_FEATURE_11W
+ uint8_t *pGroupMgmtCipherSuite;
+#endif
+ tDot11fBeaconIEs *pIesLocal = pIes;
+ eCsrAuthType negAuthType = eCSR_AUTH_TYPE_UNKNOWN;
+
+ sms_log(pMac, LOGW, "%s called...", __func__);
+
+ do {
+ if (!csr_is_profile_rsn(pProfile))
+ break;
+
+ if (!pIesLocal
+ &&
+ (!CDF_IS_STATUS_SUCCESS
+ (csr_get_parsed_bss_description_ies
+ (pMac, pSirBssDesc, &pIesLocal)))) {
+ break;
+ }
+ /* See if the cyphers in the Bss description match with the settings in the profile. */
+ fRSNMatch =
+ csr_get_rsn_information(hHal, &pProfile->AuthType,
+ pProfile->negotiatedUCEncryptionType,
+ &pProfile->mcEncryptionType,
+ &pIesLocal->RSN, UnicastCypher,
+ MulticastCypher, AuthSuite,
+ &RSNCapabilities, &negAuthType, NULL);
+ if (!fRSNMatch)
+ break;
+
+ pRSNIe->IeHeader.ElementID = SIR_MAC_RSN_EID;
+
+ pRSNIe->Version = CSR_RSN_VERSION_SUPPORTED;
+
+ cdf_mem_copy(pRSNIe->MulticastOui, MulticastCypher,
+ sizeof(MulticastCypher));
+
+ pRSNIe->cUnicastCyphers = 1;
+
+ cdf_mem_copy(&pRSNIe->UnicastOui[0], UnicastCypher,
+ sizeof(UnicastCypher));
+
+ pAuthSuite =
+ (tCsrRSNAuthIe *) (&pRSNIe->
+ UnicastOui[pRSNIe->cUnicastCyphers]);
+
+ pAuthSuite->cAuthenticationSuites = 1;
+ cdf_mem_copy(&pAuthSuite->AuthOui[0], AuthSuite,
+ sizeof(AuthSuite));
+
+ /* RSN capabilities follows the Auth Suite (two octects) */
+ /* !!REVIEW - What should STA put in RSN capabilities, currently */
+ /* just putting back APs capabilities */
+ /* For one, we shouldn't EVER be sending out "pre-auth supported". It is an AP only capability */
+ /* For another, we should use the Management Frame Protection values given by the supplicant */
+ RSNCapabilities.PreAuthSupported = 0;
+#ifdef WLAN_FEATURE_11W
+ if (RSNCapabilities.MFPCapable && pProfile->MFPCapable) {
+ RSNCapabilities.MFPCapable = pProfile->MFPCapable;
+ RSNCapabilities.MFPRequired = pProfile->MFPRequired;
+ } else {
+ RSNCapabilities.MFPCapable = 0;
+ RSNCapabilities.MFPRequired = 0;
+ }
+#endif
+ *(uint16_t *) (&pAuthSuite->AuthOui[1]) =
+ *((uint16_t *) (&RSNCapabilities));
+
+ pPMK =
+ (tCsrRSNPMKIe *) (((uint8_t *) (&pAuthSuite->AuthOui[1])) +
+ sizeof(uint16_t));
+
+ /* Don't include the PMK SA IDs for CCKM associations. */
+ if (
+#ifdef FEATURE_WLAN_ESE
+ (eCSR_AUTH_TYPE_CCKM_RSN != negAuthType) &&
+#endif
+ csr_lookup_pmkid(pMac, sessionId, pSirBssDesc->bssId,
+ &(PMKId[0]))) {
+ pPMK->cPMKIDs = 1;
+
+ cdf_mem_copy(pPMK->PMKIDList[0].PMKID, PMKId,
+ CSR_RSN_PMKID_SIZE);
+ } else {
+ pPMK->cPMKIDs = 0;
+ }
+
+#ifdef WLAN_FEATURE_11W
+ if (pProfile->MFPEnabled) {
+ pGroupMgmtCipherSuite =
+ (uint8_t *) pPMK + sizeof(uint16_t) +
+ (pPMK->cPMKIDs * CSR_RSN_PMKID_SIZE);
+ cdf_mem_copy(pGroupMgmtCipherSuite, csr_rsn_oui[07],
+ CSR_WPA_OUI_SIZE);
+ }
+#endif
+
+ /* Add in the fixed fields plus 1 Unicast cypher, less the IE Header length */
+ /* Add in the size of the Auth suite (count plus a single OUI) */
+ /* Add in the RSN caps field. */
+ /* Add PMKID count and PMKID (if any) */
+ /* Add group management cipher suite */
+ pRSNIe->IeHeader.Length =
+ (uint8_t) (sizeof(*pRSNIe) - sizeof(pRSNIe->IeHeader) +
+ sizeof(*pAuthSuite) +
+ sizeof(tCsrRSNCapabilities));
+ if (pPMK->cPMKIDs) {
+ pRSNIe->IeHeader.Length += (uint8_t) (sizeof(uint16_t) +
+ (pPMK->cPMKIDs *
+ CSR_RSN_PMKID_SIZE));
+ }
+#ifdef WLAN_FEATURE_11W
+ if (pProfile->MFPEnabled) {
+ if (0 == pPMK->cPMKIDs)
+ pRSNIe->IeHeader.Length += sizeof(uint16_t);
+ pRSNIe->IeHeader.Length += CSR_WPA_OUI_SIZE;
+ }
+#endif
+
+ /* return the size of the IE header (total) constructed... */
+ cbRSNIe = pRSNIe->IeHeader.Length + sizeof(pRSNIe->IeHeader);
+
+ } while (0);
+
+ if (!pIes && pIesLocal) {
+ /* locally allocated */
+ cdf_mem_free(pIesLocal);
+ }
+
+ return cbRSNIe;
+}
+
+#ifdef FEATURE_WLAN_WAPI
+/**
+ * csr_get_wapi_information() - to get WAPI infomation
+ * @hal: pointer to HAL
+ * @auth_type: auth type
+ * @encr_type: encryption type
+ * @mc_encryption: multicast encryption type
+ * @wapi_ie: pointer to WAPI IE
+ * @ucast_cipher: Unicast cipher
+ * @mcast_cipher: Multicast cipher
+ * @auth_suite: Authentication suite
+ * @negotiated_authtype: Negotiated auth type
+ * @negotiated_mccipher: negotiated multicast cipher
+ *
+ * This routine will get all WAPI information
+ *
+ * Return: bool
+ */
+bool csr_get_wapi_information(tHalHandle hal, tCsrAuthList *auth_type,
+ eCsrEncryptionType encr_type,
+ tCsrEncryptionList *mc_encryption,
+ tDot11fIEWAPI *wapi_ie, uint8_t *ucast_cipher,
+ uint8_t *mcast_cipher, uint8_t *auth_suite,
+ eCsrAuthType *negotiated_authtype,
+ eCsrEncryptionType *negotiated_mccipher)
+{
+ tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal);
+ bool acceptable_cipher = false;
+ uint8_t c_ucast_cipher = 0;
+ uint8_t c_mcast_cipher = 0;
+ uint8_t c_auth_suites = 0, i;
+ uint8_t unicast[CSR_WAPI_OUI_SIZE];
+ uint8_t multicast[CSR_WAPI_OUI_SIZE];
+ uint8_t authsuites[CSR_WAPI_MAX_AUTH_SUITES][CSR_WAPI_OUI_SIZE];
+ uint8_t authentication[CSR_WAPI_OUI_SIZE];
+ uint8_t mccipher_arr[CSR_WAPI_MAX_MULTICAST_CYPHERS][CSR_WAPI_OUI_SIZE];
+ eCsrAuthType neg_authtype = eCSR_AUTH_TYPE_UNKNOWN;
+ uint8_t wapioui_idx = 0;
+
+ if (!wapi_ie->present)
+ goto end;
+
+ c_mcast_cipher++;
+ cdf_mem_copy(mccipher_arr, wapi_ie->multicast_cipher_suite,
+ CSR_WAPI_OUI_SIZE);
+ c_ucast_cipher = (uint8_t) (wapi_ie->unicast_cipher_suite_count);
+ c_auth_suites = (uint8_t) (wapi_ie->akm_suite_count);
+ for (i = 0; i < c_auth_suites && i < CSR_WAPI_MAX_AUTH_SUITES; i++)
+ cdf_mem_copy((void *)&authsuites[i],
+ (void *)&wapi_ie->akm_suites[i], CSR_WAPI_OUI_SIZE);
+
+ wapioui_idx = csr_get_oui_index_from_cipher(encr_type);
+ if (wapioui_idx >= CSR_OUI_WAPI_WAI_MAX_INDEX) {
+ sms_log(mac_ctx, LOGE,
+ FL("Wapi OUI index = %d out of limit"),
+ wapioui_idx);
+ acceptable_cipher = false;
+ goto end;
+ }
+ /* Check - Is requested unicast Cipher supported by the BSS. */
+ acceptable_cipher = csr_match_wapi_oui_index(mac_ctx,
+ wapi_ie->unicast_cipher_suites,
+ c_ucast_cipher, wapioui_idx, unicast);
+ if (!acceptable_cipher)
+ goto end;
+
+ /* unicast is supported. Pick the first matching Group cipher, if any */
+ for (i = 0; i < mc_encryption->numEntries; i++) {
+ wapioui_idx = csr_get_oui_index_from_cipher(
+ mc_encryption->encryptionType[i]);
+ if (wapioui_idx >= CSR_OUI_WAPI_WAI_MAX_INDEX) {
+ sms_log(mac_ctx, LOGE,
+ FL("Wapi OUI index = %d out of limit"),
+ wapioui_idx);
+ acceptable_cipher = false;
+ break;
+ }
+ acceptable_cipher = csr_match_wapi_oui_index(mac_ctx,
+ mccipher_arr, c_mcast_cipher,
+ wapioui_idx, multicast);
+ if (acceptable_cipher)
+ break;
+ }
+ if (!acceptable_cipher)
+ goto end;
+
+ if (negotiated_mccipher)
+ *negotiated_mccipher =
+ mc_encryption->encryptionType[i];
+
+ /*
+ * Ciphers are supported, Match authentication algorithm and
+ * pick first matching authtype
+ */
+ if (csr_is_auth_wapi_cert
+ (mac_ctx, authsuites, c_auth_suites, authentication)) {
+ neg_authtype =
+ eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE;
+ } else if (csr_is_auth_wapi_psk(mac_ctx, authsuites,
+ c_auth_suites, authentication)) {
+ neg_authtype = eCSR_AUTH_TYPE_WAPI_WAI_PSK;
+ } else {
+ acceptable_cipher = false;
+ neg_authtype = eCSR_AUTH_TYPE_UNKNOWN;
+ }
+
+ /* Caller doesn't care about auth type, or BSS doesn't match */
+ if ((0 == auth_type->numEntries) || (false == acceptable_cipher))
+ goto end;
+
+ acceptable_cipher = false;
+ for (i = 0; i < auth_type->numEntries; i++) {
+ if (auth_type->authType[i] == neg_authtype) {
+ acceptable_cipher = true;
+ break;
+ }
+ }
+
+end:
+ if (acceptable_cipher) {
+ if (mcast_cipher)
+ cdf_mem_copy(mcast_cipher, multicast,
+ CSR_WAPI_OUI_SIZE);
+ if (ucast_cipher)
+ cdf_mem_copy(ucast_cipher, unicast, CSR_WAPI_OUI_SIZE);
+ if (auth_suite)
+ cdf_mem_copy(auth_suite, authentication,
+ CSR_WAPI_OUI_SIZE);
+ if (negotiated_authtype)
+ *negotiated_authtype = neg_authtype;
+ }
+ return acceptable_cipher;
+}
+
+bool csr_is_wapi_match(tHalHandle hHal, tCsrAuthList *pAuthType,
+ eCsrEncryptionType enType, tCsrEncryptionList *pEnMcType,
+ tDot11fBeaconIEs *pIes, eCsrAuthType *pNegotiatedAuthType,
+ eCsrEncryptionType *pNegotiatedMCCipher)
+{
+ bool fWapiMatch = false;
+
+ /* See if the cyphers in the Bss description match with the settings in the profile. */
+ fWapiMatch =
+ csr_get_wapi_information(hHal, pAuthType, enType, pEnMcType,
+ &pIes->WAPI, NULL, NULL, NULL,
+ pNegotiatedAuthType, pNegotiatedMCCipher);
+
+ return fWapiMatch;
+}
+
+bool csr_lookup_bkid(tpAniSirGlobal pMac, uint32_t sessionId, uint8_t *pBSSId,
+ uint8_t *pBKId)
+{
+ bool fRC = false, fMatchFound = false;
+ uint32_t Index;
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ if (!pSession) {
+ sms_log(pMac, LOGE, FL(" session %d not found "), sessionId);
+ return false;
+ }
+
+ do {
+ for (Index = 0; Index < pSession->NumBkidCache; Index++) {
+ sms_log(pMac, LOGW, "match BKID " MAC_ADDRESS_STR " to ",
+ MAC_ADDR_ARRAY(pBSSId));
+ if (cdf_mem_compare
+ (pBSSId, pSession->BkidCacheInfo[Index].BSSID.bytes,
+ sizeof(struct cdf_mac_addr))) {
+ /* match found */
+ fMatchFound = true;
+ break;
+ }
+ }
+
+ if (!fMatchFound)
+ break;
+
+ cdf_mem_copy(pBKId, pSession->BkidCacheInfo[Index].BKID,
+ CSR_WAPI_BKID_SIZE);
+
+ fRC = true;
+ } while (0);
+ sms_log(pMac, LOGW,
+ "csr_lookup_bkid called return match = %d pMac->roam.NumBkidCache = %d",
+ fRC, pSession->NumBkidCache);
+
+ return fRC;
+}
+
+uint8_t csr_construct_wapi_ie(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamProfile *pProfile,
+ tSirBssDescription *pSirBssDesc,
+ tDot11fBeaconIEs *pIes, tCsrWapiIe *pWapiIe)
+{
+ bool fWapiMatch = false;
+ uint8_t cbWapiIe = 0;
+ uint8_t UnicastCypher[CSR_WAPI_OUI_SIZE];
+ uint8_t MulticastCypher[CSR_WAPI_OUI_SIZE];
+ uint8_t AuthSuite[CSR_WAPI_OUI_SIZE];
+ uint8_t BKId[CSR_WAPI_BKID_SIZE];
+ uint8_t *pWapi = NULL;
+ bool fBKIDFound = false;
+ tDot11fBeaconIEs *pIesLocal = pIes;
+
+ do {
+ if (!csr_is_profile_wapi(pProfile))
+ break;
+
+ if (!pIesLocal
+ &&
+ (!CDF_IS_STATUS_SUCCESS
+ (csr_get_parsed_bss_description_ies
+ (pMac, pSirBssDesc, &pIesLocal)))) {
+ break;
+ }
+ /* See if the cyphers in the Bss description match with the settings in the profile. */
+ fWapiMatch =
+ csr_get_wapi_information(pMac, &pProfile->AuthType,
+ pProfile->negotiatedUCEncryptionType,
+ &pProfile->mcEncryptionType,
+ &pIesLocal->WAPI, UnicastCypher,
+ MulticastCypher, AuthSuite, NULL,
+ NULL);
+ if (!fWapiMatch)
+ break;
+
+ cdf_mem_set(pWapiIe, sizeof(tCsrWapiIe), 0);
+
+ pWapiIe->IeHeader.ElementID = DOT11F_EID_WAPI;
+
+ pWapiIe->Version = CSR_WAPI_VERSION_SUPPORTED;
+
+ pWapiIe->cAuthenticationSuites = 1;
+ cdf_mem_copy(&pWapiIe->AuthOui[0], AuthSuite,
+ sizeof(AuthSuite));
+
+ pWapi = (uint8_t *) (&pWapiIe->AuthOui[1]);
+
+ *pWapi = (uint16_t) 1; /* cUnicastCyphers */
+ pWapi += 2;
+ cdf_mem_copy(pWapi, UnicastCypher, sizeof(UnicastCypher));
+ pWapi += sizeof(UnicastCypher);
+
+ cdf_mem_copy(pWapi, MulticastCypher, sizeof(MulticastCypher));
+ pWapi += sizeof(MulticastCypher);
+
+ /* WAPI capabilities follows the Auth Suite (two octects) */
+ /* we shouldn't EVER be sending out "pre-auth supported". It is an AP only capability */
+ /* & since we already did a memset pWapiIe to 0, skip these fields */
+ pWapi += 2;
+
+ fBKIDFound =
+ csr_lookup_bkid(pMac, sessionId, pSirBssDesc->bssId,
+ &(BKId[0]));
+
+ if (fBKIDFound) {
+ /* Do we need to change the endianness here */
+ *pWapi = (uint16_t) 1; /* cBKIDs */
+ pWapi += 2;
+ cdf_mem_copy(pWapi, BKId, CSR_WAPI_BKID_SIZE);
+ } else {
+ *pWapi = 0;
+ pWapi += 1;
+ *pWapi = 0;
+ pWapi += 1;
+ }
+
+ /* Add in the IE fields except the IE header */
+ /* Add BKID count and BKID (if any) */
+ pWapiIe->IeHeader.Length =
+ (uint8_t) (sizeof(*pWapiIe) - sizeof(pWapiIe->IeHeader));
+
+ /*2 bytes for BKID Count field */
+ pWapiIe->IeHeader.Length += sizeof(uint16_t);
+
+ if (fBKIDFound) {
+ pWapiIe->IeHeader.Length += CSR_WAPI_BKID_SIZE;
+ }
+ /* return the size of the IE header (total) constructed... */
+ cbWapiIe = pWapiIe->IeHeader.Length + sizeof(pWapiIe->IeHeader);
+
+ } while (0);
+
+ if (!pIes && pIesLocal) {
+ /* locally allocated */
+ cdf_mem_free(pIesLocal);
+ }
+
+ return cbWapiIe;
+}
+#endif /* FEATURE_WLAN_WAPI */
+
+/**
+ * csr_get_wpa_cyphers() - to get WPA cipher info
+ * @mac_ctx: pointer to mac context
+ * @auth_type: auth type
+ * @encr_type: encryption type
+ * @mc_encryption: multicast encryption type
+ * @wpa_ie: pointer to WPA IE
+ * @ucast_cipher: Unicast cipher
+ * @mcast_cipher: Multicast cipher
+ * @auth_suite: Authentication suite
+ * @negotiated_authtype: Negotiated auth type
+ * @negotiated_mccipher: negotiated multicast cipher
+ *
+ * This routine will get all WPA information
+ *
+ * Return: bool
+ */
+bool csr_get_wpa_cyphers(tpAniSirGlobal mac_ctx, tCsrAuthList *auth_type,
+ eCsrEncryptionType encr_type, tCsrEncryptionList *mc_encryption,
+ tDot11fIEWPA *wpa_ie, uint8_t *ucast_cipher,
+ uint8_t *mcast_cipher, uint8_t *auth_suite,
+ eCsrAuthType *negotiated_authtype,
+ eCsrEncryptionType *negotiated_mccipher)
+{
+ bool acceptable_cipher = false;
+ uint8_t c_ucast_cipher = 0;
+ uint8_t c_mcast_cipher = 0;
+ uint8_t c_auth_suites = 0;
+ uint8_t unicast[CSR_WPA_OUI_SIZE];
+ uint8_t multicast[CSR_WPA_OUI_SIZE];
+ uint8_t authentication[CSR_WPA_OUI_SIZE];
+ uint8_t mccipher_arr[1][CSR_WPA_OUI_SIZE];
+ uint8_t i;
+ eCsrAuthType neg_authtype = eCSR_AUTH_TYPE_UNKNOWN;
+
+ if (!wpa_ie->present)
+ goto end;
+ c_mcast_cipher = 1;
+ cdf_mem_copy(mccipher_arr, wpa_ie->multicast_cipher, CSR_WPA_OUI_SIZE);
+ c_ucast_cipher = (uint8_t) (wpa_ie->unicast_cipher_count);
+ c_auth_suites = (uint8_t) (wpa_ie->auth_suite_count);
+
+ /* Check - Is requested unicast Cipher supported by the BSS. */
+ acceptable_cipher = csr_match_wpaoui_index(mac_ctx,
+ wpa_ie->unicast_ciphers, c_ucast_cipher,
+ csr_get_oui_index_from_cipher(encr_type),
+ unicast);
+ if (!acceptable_cipher)
+ goto end;
+ /* unicast is supported. Pick the first matching Group cipher, if any */
+ for (i = 0; i < mc_encryption->numEntries; i++) {
+ acceptable_cipher = csr_match_wpaoui_index(mac_ctx,
+ mccipher_arr, c_mcast_cipher,
+ csr_get_oui_index_from_cipher(
+ mc_encryption->encryptionType[i]),
+ multicast);
+ if (acceptable_cipher)
+ break;
+ }
+ if (!acceptable_cipher)
+ goto end;
+
+ if (negotiated_mccipher)
+ *negotiated_mccipher = mc_encryption->encryptionType[i];
+
+ /* Initializing with false as it has true value already */
+ acceptable_cipher = false;
+ for (i = 0; i < auth_type->numEntries; i++) {
+ /*
+ * Ciphers are supported, Match authentication algorithm and
+ * pick first matching authtype
+ */
+ if (csr_is_auth_wpa(mac_ctx, wpa_ie->auth_suites, c_auth_suites,
+ authentication)) {
+ if (eCSR_AUTH_TYPE_WPA == auth_type->authType[i])
+ neg_authtype = eCSR_AUTH_TYPE_WPA;
+ }
+ if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) &&
+ csr_is_auth_wpa_psk(mac_ctx,
+ wpa_ie->auth_suites, c_auth_suites,
+ authentication)) {
+ if (eCSR_AUTH_TYPE_WPA_PSK == auth_type->authType[i])
+ neg_authtype = eCSR_AUTH_TYPE_WPA_PSK;
+ }
+#ifdef FEATURE_WLAN_ESE
+ if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN)
+ && csr_is_ese_cckm_auth_wpa(mac_ctx,
+ wpa_ie->auth_suites, c_auth_suites,
+ authentication)) {
+ if (eCSR_AUTH_TYPE_CCKM_WPA == auth_type->authType[i])
+ neg_authtype = eCSR_AUTH_TYPE_CCKM_WPA;
+ }
+#endif /* FEATURE_WLAN_ESE */
+
+ /*
+ * The 1st auth type in the APs WPA IE, to match stations
+ * connecting profiles auth type will cause us to exit this
+ * loop. This is added as some APs advertise multiple akms in
+ * the WPA IE
+ */
+ if (eCSR_AUTH_TYPE_UNKNOWN != neg_authtype) {
+ acceptable_cipher = true;
+ break;
+ }
+ }
+
+end:
+ if (acceptable_cipher) {
+ if (mcast_cipher)
+ cdf_mem_copy((uint8_t **) mcast_cipher, multicast,
+ CSR_WPA_OUI_SIZE);
+
+ if (ucast_cipher)
+ cdf_mem_copy((uint8_t **) ucast_cipher, unicast,
+ CSR_WPA_OUI_SIZE);
+
+ if (auth_suite)
+ cdf_mem_copy((uint8_t **) auth_suite, authentication,
+ CSR_WPA_OUI_SIZE);
+
+ if (negotiated_authtype)
+ *negotiated_authtype = neg_authtype;
+ }
+
+ return acceptable_cipher;
+}
+
+bool csr_is_wpa_encryption_match(tpAniSirGlobal pMac, tCsrAuthList *pAuthType,
+ eCsrEncryptionType enType,
+ tCsrEncryptionList *pEnMcType,
+ tDot11fBeaconIEs *pIes,
+ eCsrAuthType *pNegotiatedAuthtype,
+ eCsrEncryptionType *pNegotiatedMCCipher)
+{
+ bool fWpaMatch = false;
+
+ /* See if the cyphers in the Bss description match with the settings in the profile. */
+ fWpaMatch =
+ csr_get_wpa_cyphers(pMac, pAuthType, enType, pEnMcType, &pIes->WPA,
+ NULL, NULL, NULL, pNegotiatedAuthtype,
+ pNegotiatedMCCipher);
+
+ return fWpaMatch;
+}
+
+uint8_t csr_construct_wpa_ie(tHalHandle hHal, tCsrRoamProfile *pProfile,
+ tSirBssDescription *pSirBssDesc,
+ tDot11fBeaconIEs *pIes, tCsrWpaIe *pWpaIe)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ bool fWpaMatch;
+ uint8_t cbWpaIe = 0;
+ uint8_t UnicastCypher[CSR_WPA_OUI_SIZE];
+ uint8_t MulticastCypher[CSR_WPA_OUI_SIZE];
+ uint8_t AuthSuite[CSR_WPA_OUI_SIZE];
+ tCsrWpaAuthIe *pAuthSuite;
+ tDot11fBeaconIEs *pIesLocal = pIes;
+
+ do {
+ if (!csr_is_profile_wpa(pProfile))
+ break;
+
+ if (!pIesLocal
+ &&
+ (!CDF_IS_STATUS_SUCCESS
+ (csr_get_parsed_bss_description_ies
+ (pMac, pSirBssDesc, &pIesLocal)))) {
+ break;
+ }
+ /* See if the cyphers in the Bss description match with the settings in the profile. */
+ fWpaMatch =
+ csr_get_wpa_cyphers(hHal, &pProfile->AuthType,
+ pProfile->negotiatedUCEncryptionType,
+ &pProfile->mcEncryptionType,
+ &pIesLocal->WPA, UnicastCypher,
+ MulticastCypher, AuthSuite, NULL, NULL);
+ if (!fWpaMatch)
+ break;
+
+ pWpaIe->IeHeader.ElementID = SIR_MAC_WPA_EID;
+
+ cdf_mem_copy(pWpaIe->Oui, csr_wpa_oui[01], sizeof(pWpaIe->Oui));
+
+ pWpaIe->Version = CSR_WPA_VERSION_SUPPORTED;
+
+ cdf_mem_copy(pWpaIe->MulticastOui, MulticastCypher,
+ sizeof(MulticastCypher));
+
+ pWpaIe->cUnicastCyphers = 1;
+
+ cdf_mem_copy(&pWpaIe->UnicastOui[0], UnicastCypher,
+ sizeof(UnicastCypher));
+
+ pAuthSuite =
+ (tCsrWpaAuthIe *) (&pWpaIe->
+ UnicastOui[pWpaIe->cUnicastCyphers]);
+
+ pAuthSuite->cAuthenticationSuites = 1;
+ cdf_mem_copy(&pAuthSuite->AuthOui[0], AuthSuite,
+ sizeof(AuthSuite));
+
+ /* The WPA capabilities follows the Auth Suite (two octects)-- */
+ /* this field is optional, and we always "send" zero, so just */
+ /* remove it. This is consistent with our assumptions in the */
+ /* frames compiler; c.f. bug 15234: */
+ /* http://gold.woodsidenet.com/bugzilla/show_bug.cgi?id=15234 */
+
+ /* Add in the fixed fields plus 1 Unicast cypher, less the IE Header length */
+ /* Add in the size of the Auth suite (count plus a single OUI) */
+ pWpaIe->IeHeader.Length =
+ sizeof(*pWpaIe) - sizeof(pWpaIe->IeHeader) +
+ sizeof(*pAuthSuite);
+
+ /* return the size of the IE header (total) constructed... */
+ cbWpaIe = pWpaIe->IeHeader.Length + sizeof(pWpaIe->IeHeader);
+
+ } while (0);
+
+ if (!pIes && pIesLocal) {
+ /* locally allocated */
+ cdf_mem_free(pIesLocal);
+ }
+
+ return cbWpaIe;
+}
+
+/* If a WPAIE exists in the profile, just use it. Or else construct one from the BSS */
+/* Caller allocated memory for pWpaIe and guarrantee it can contain a max length WPA IE */
+uint8_t csr_retrieve_wpa_ie(tHalHandle hHal, tCsrRoamProfile *pProfile,
+ tSirBssDescription *pSirBssDesc,
+ tDot11fBeaconIEs *pIes, tCsrWpaIe *pWpaIe)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ uint8_t cbWpaIe = 0;
+
+ do {
+ if (!csr_is_profile_wpa(pProfile))
+ break;
+ if (pProfile->nWPAReqIELength && pProfile->pWPAReqIE) {
+ if (SIR_MAC_WPA_IE_MAX_LENGTH >=
+ pProfile->nWPAReqIELength) {
+ cbWpaIe = (uint8_t) pProfile->nWPAReqIELength;
+ cdf_mem_copy(pWpaIe, pProfile->pWPAReqIE,
+ cbWpaIe);
+ } else {
+ sms_log(pMac, LOGW,
+ " csr_retrieve_wpa_ie detect invalid WPA IE length (%d) ",
+ pProfile->nWPAReqIELength);
+ }
+ } else {
+ cbWpaIe =
+ csr_construct_wpa_ie(pMac, pProfile, pSirBssDesc, pIes,
+ pWpaIe);
+ }
+ } while (0);
+
+ return cbWpaIe;
+}
+
+/* If a RSNIE exists in the profile, just use it. Or else construct one from the BSS */
+/* Caller allocated memory for pWpaIe and guarrantee it can contain a max length WPA IE */
+uint8_t csr_retrieve_rsn_ie(tHalHandle hHal, uint32_t sessionId,
+ tCsrRoamProfile *pProfile,
+ tSirBssDescription *pSirBssDesc,
+ tDot11fBeaconIEs *pIes, tCsrRSNIe *pRsnIe)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ uint8_t cbRsnIe = 0;
+
+ do {
+ if (!csr_is_profile_rsn(pProfile))
+ break;
+#ifdef FEATURE_WLAN_LFR
+ if (csr_roam_is_fast_roam_enabled(pMac, sessionId)) {
+ /* If "Legacy Fast Roaming" is enabled ALWAYS rebuild the RSN IE from */
+ /* scratch. So it contains the current PMK-IDs */
+ cbRsnIe =
+ csr_construct_rsn_ie(pMac, sessionId, pProfile,
+ pSirBssDesc, pIes, pRsnIe);
+ } else
+#endif
+ if (pProfile->nRSNReqIELength && pProfile->pRSNReqIE) {
+ /* If you have one started away, re-use it. */
+ if (SIR_MAC_WPA_IE_MAX_LENGTH >=
+ pProfile->nRSNReqIELength) {
+ cbRsnIe = (uint8_t) pProfile->nRSNReqIELength;
+ cdf_mem_copy(pRsnIe, pProfile->pRSNReqIE,
+ cbRsnIe);
+ } else {
+ sms_log(pMac, LOGW,
+ " csr_retrieve_rsn_ie detect invalid RSN IE length (%d) ",
+ pProfile->nRSNReqIELength);
+ }
+ } else {
+ cbRsnIe =
+ csr_construct_rsn_ie(pMac, sessionId, pProfile,
+ pSirBssDesc, pIes, pRsnIe);
+ }
+ } while (0);
+
+ return cbRsnIe;
+}
+
+#ifdef FEATURE_WLAN_WAPI
+/* If a WAPI IE exists in the profile, just use it. Or else construct one from the BSS */
+/* Caller allocated memory for pWapiIe and guarrantee it can contain a max length WAPI IE */
+uint8_t csr_retrieve_wapi_ie(tHalHandle hHal, uint32_t sessionId,
+ tCsrRoamProfile *pProfile,
+ tSirBssDescription *pSirBssDesc,
+ tDot11fBeaconIEs *pIes, tCsrWapiIe *pWapiIe)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ uint8_t cbWapiIe = 0;
+
+ do {
+ if (!csr_is_profile_wapi(pProfile))
+ break;
+ if (pProfile->nWAPIReqIELength && pProfile->pWAPIReqIE) {
+ if (DOT11F_IE_WAPI_MAX_LEN >=
+ pProfile->nWAPIReqIELength) {
+ cbWapiIe = (uint8_t) pProfile->nWAPIReqIELength;
+ cdf_mem_copy(pWapiIe, pProfile->pWAPIReqIE,
+ cbWapiIe);
+ } else {
+ sms_log(pMac, LOGW,
+ " csr_retrieve_wapi_ie detect invalid WAPI IE length (%d) ",
+ pProfile->nWAPIReqIELength);
+ }
+ } else {
+ cbWapiIe =
+ csr_construct_wapi_ie(pMac, sessionId, pProfile,
+ pSirBssDesc, pIes, pWapiIe);
+ }
+ } while (0);
+
+ return cbWapiIe;
+}
+#endif /* FEATURE_WLAN_WAPI */
+
+bool csr_rates_is_dot11_rate11b_supported_rate(uint8_t dot11Rate)
+{
+ bool fSupported = false;
+ uint16_t nonBasicRate =
+ (uint16_t) (BITS_OFF(dot11Rate, CSR_DOT11_BASIC_RATE_MASK));
+
+ switch (nonBasicRate) {
+ case eCsrSuppRate_1Mbps:
+ case eCsrSuppRate_2Mbps:
+ case eCsrSuppRate_5_5Mbps:
+ case eCsrSuppRate_11Mbps:
+ fSupported = true;
+ break;
+
+ default:
+ break;
+ }
+
+ return fSupported;
+}
+
+bool csr_rates_is_dot11_rate11a_supported_rate(uint8_t dot11Rate)
+{
+ bool fSupported = false;
+ uint16_t nonBasicRate =
+ (uint16_t) (BITS_OFF(dot11Rate, CSR_DOT11_BASIC_RATE_MASK));
+
+ switch (nonBasicRate) {
+ case eCsrSuppRate_6Mbps:
+ case eCsrSuppRate_9Mbps:
+ case eCsrSuppRate_12Mbps:
+ case eCsrSuppRate_18Mbps:
+ case eCsrSuppRate_24Mbps:
+ case eCsrSuppRate_36Mbps:
+ case eCsrSuppRate_48Mbps:
+ case eCsrSuppRate_54Mbps:
+ fSupported = true;
+ break;
+
+ default:
+ break;
+ }
+
+ return fSupported;
+}
+
+tAniEdType csr_translate_encrypt_type_to_ed_type(eCsrEncryptionType EncryptType)
+{
+ tAniEdType edType;
+
+ switch (EncryptType) {
+ default:
+ case eCSR_ENCRYPT_TYPE_NONE:
+ edType = eSIR_ED_NONE;
+ break;
+
+ case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY:
+ case eCSR_ENCRYPT_TYPE_WEP40:
+ edType = eSIR_ED_WEP40;
+ break;
+
+ case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY:
+ case eCSR_ENCRYPT_TYPE_WEP104:
+ edType = eSIR_ED_WEP104;
+ break;
+
+ case eCSR_ENCRYPT_TYPE_TKIP:
+ edType = eSIR_ED_TKIP;
+ break;
+
+ case eCSR_ENCRYPT_TYPE_AES:
+ edType = eSIR_ED_CCMP;
+ break;
+#ifdef FEATURE_WLAN_WAPI
+ case eCSR_ENCRYPT_TYPE_WPI:
+ edType = eSIR_ED_WPI;
+ break;
+#endif
+#ifdef WLAN_FEATURE_11W
+ /* 11w BIP */
+ case eCSR_ENCRYPT_TYPE_AES_CMAC:
+ edType = eSIR_ED_AES_128_CMAC;
+ break;
+#endif
+ }
+
+ return edType;
+}
+
+/**
+ * csr_validate_wep() - to validate wep
+ * @uc_encry_type: unicast encryption type
+ * @auth_list: Auth list
+ * @mc_encryption_list: multicast encryption type
+ * @negotiated_authtype: negotiated auth type
+ * @negotiated_mc_encry: negotiated mc encry type
+ * @bss_descr: BSS description
+ * @ie_ptr: IE pointer
+ *
+ * This function just checks whether HDD is giving correct values for
+ * Multicast cipher and Auth
+ *
+ * Return: bool
+ */
+bool csr_validate_wep(tpAniSirGlobal mac_ctx, eCsrEncryptionType uc_encry_type,
+ tCsrAuthList *auth_list,
+ tCsrEncryptionList *mc_encryption_list,
+ eCsrAuthType *negotiated_authtype,
+ eCsrEncryptionType *negotiated_mc_encry,
+ tSirBssDescription *bss_descr, tDot11fBeaconIEs *ie_ptr)
+{
+ uint32_t idx;
+ bool match = false;
+ eCsrAuthType negotiated_auth = eCSR_AUTH_TYPE_OPEN_SYSTEM;
+ eCsrEncryptionType negotiated_mccipher = eCSR_ENCRYPT_TYPE_UNKNOWN;
+
+ /* If privacy bit is not set, consider no match */
+ if (!csr_is_privacy(bss_descr))
+ goto end;
+
+ for (idx = 0; idx < mc_encryption_list->numEntries; idx++) {
+ switch (mc_encryption_list->encryptionType[idx]) {
+ case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY:
+ case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY:
+ case eCSR_ENCRYPT_TYPE_WEP40:
+ case eCSR_ENCRYPT_TYPE_WEP104:
+ /*
+ * Multicast list may contain WEP40/WEP104.
+ * Check whether it matches UC.
+ */
+ if (uc_encry_type ==
+ mc_encryption_list->encryptionType[idx]) {
+ match = true;
+ negotiated_mccipher =
+ mc_encryption_list->encryptionType[idx];
+ }
+ break;
+ default:
+ match = false;
+ break;
+ }
+ if (match)
+ break;
+ }
+
+ if (!match)
+ goto end;
+
+ for (idx = 0; idx < auth_list->numEntries; idx++) {
+ switch (auth_list->authType[idx]) {
+ case eCSR_AUTH_TYPE_OPEN_SYSTEM:
+ case eCSR_AUTH_TYPE_SHARED_KEY:
+ case eCSR_AUTH_TYPE_AUTOSWITCH:
+ match = true;
+ negotiated_auth = auth_list->authType[idx];
+ break;
+ default:
+ match = false;
+ }
+ if (match)
+ break;
+ }
+
+ if (!match)
+ goto end;
+
+ if (!ie_ptr)
+ goto end;
+
+ /*
+ * In case of WPA / WPA2, check whether it supports WEP as well.
+ * Prepare the encryption type for WPA/WPA2 functions
+ */
+ if (eCSR_ENCRYPT_TYPE_WEP40_STATICKEY == uc_encry_type)
+ uc_encry_type = eCSR_ENCRYPT_TYPE_WEP40;
+ else if (eCSR_ENCRYPT_TYPE_WEP104 == uc_encry_type)
+ uc_encry_type = eCSR_ENCRYPT_TYPE_WEP104;
+
+ /* else we can use the encryption type directly */
+ if (ie_ptr->WPA.present) {
+ match = cdf_mem_compare(ie_ptr->WPA.multicast_cipher,
+ csr_wpa_oui[csr_get_oui_index_from_cipher(
+ uc_encry_type)],
+ CSR_WPA_OUI_SIZE);
+ if (match)
+ goto end;
+ }
+ if (ie_ptr->RSN.present) {
+ match = cdf_mem_compare(ie_ptr->RSN.gp_cipher_suite,
+ csr_rsn_oui[csr_get_oui_index_from_cipher(
+ uc_encry_type)],
+ CSR_RSN_OUI_SIZE);
+ }
+
+
+end:
+ if (match) {
+ if (negotiated_authtype)
+ *negotiated_authtype = negotiated_auth;
+ if (negotiated_mc_encry)
+ *negotiated_mc_encry = negotiated_mccipher;
+ }
+ return match;
+}
+
+/**
+ * csr_validate_open_none() - Check if the security is matching
+ * @bss_desc: BSS Descriptor on which the check is done
+ * @mc_enc_type: Multicast encryption type
+ * @mc_cipher: Multicast Cipher
+ * @auth_type: Authentication type
+ * @neg_auth_type: Negotiated Auth type with the AP
+ *
+ * Return: Boolean value to tell if matched or not.
+ */
+static bool csr_validate_open_none(tSirBssDescription *bss_desc,
+ tCsrEncryptionList *mc_enc_type, eCsrEncryptionType *mc_cipher,
+ tCsrAuthList *auth_type, eCsrAuthType *neg_auth_type)
+{
+ bool match;
+ uint8_t idx;
+
+ /*
+ * for NO encryption, if the Bss description has the
+ * Privacy bit turned on, then encryption is required
+ * so we have to reject this Bss.
+ */
+ if (csr_is_privacy(bss_desc))
+ match = false;
+ else
+ match = true;
+ if (match) {
+ match = false;
+ /* Check MC cipher and Auth type requested. */
+ for (idx = 0; idx < mc_enc_type->numEntries; idx++) {
+ if (eCSR_ENCRYPT_TYPE_NONE ==
+ mc_enc_type->encryptionType[idx]) {
+ match = true;
+ *mc_cipher = mc_enc_type->encryptionType[idx];
+ break;
+ }
+ }
+ if (!match)
+ return match;
+
+ match = false;
+ /* Check Auth list. It should contain AuthOpen. */
+ for (idx = 0; idx < auth_type->numEntries; idx++) {
+ if ((eCSR_AUTH_TYPE_OPEN_SYSTEM ==
+ auth_type->authType[idx]) ||
+ (eCSR_AUTH_TYPE_AUTOSWITCH ==
+ auth_type->authType[idx])) {
+ match = true;
+ *neg_auth_type =
+ eCSR_AUTH_TYPE_OPEN_SYSTEM;
+ break;
+ }
+ }
+ if (!match)
+ return match;
+
+ }
+ return match;
+}
+
+/**
+ * csr_validate_any_default() - Check if the security is matching
+ * @hal: Global HAL handle
+ * @auth_type: Authentication type
+ * @mc_enc_type: Multicast encryption type
+ * @mfp_enabled: Management frame protection feature
+ * @mfp_required: Mangement frame protection mandatory
+ * @mfp_capable: Device capable of MFP
+ * @ies_ptr: Pointer to the IE fields
+ * @neg_auth_type: Negotiated Auth type with the AP
+ * @bss_desc: BSS Descriptor
+ * @neg_uc_cipher: Negotiated unicast cipher suite
+ * @neg_mc_cipher: Negotiated multicast cipher
+ *
+ * Return: Boolean value to tell if matched or not.
+ */
+static bool csr_validate_any_default(tHalHandle hal, tCsrAuthList *auth_type,
+ tCsrEncryptionList *mc_enc_type, bool *mfp_enabled,
+ uint8_t *mfp_required, uint8_t *mfp_capable,
+ tDot11fBeaconIEs *ies_ptr, eCsrAuthType *neg_auth_type,
+ tSirBssDescription *bss_desc, eCsrEncryptionType *uc_cipher,
+ eCsrEncryptionType *mc_cipher)
+{
+ bool match_any = false;
+ bool match = true;
+ tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal);
+ /* It is allowed to match anything. Try the more secured ones first. */
+ if (ies_ptr) {
+ /* Check AES first */
+ *uc_cipher = eCSR_ENCRYPT_TYPE_AES;
+ match_any = csr_is_rsn_match(hal, auth_type,
+ *uc_cipher, mc_enc_type, mfp_enabled,
+ mfp_required, mfp_capable, ies_ptr,
+ neg_auth_type, mc_cipher);
+ if (!match_any) {
+ /* Check TKIP */
+ *uc_cipher = eCSR_ENCRYPT_TYPE_TKIP;
+ match_any = csr_is_rsn_match(hal, auth_type, *uc_cipher,
+ mc_enc_type, mfp_enabled, mfp_required,
+ mfp_capable, ies_ptr, neg_auth_type,
+ mc_cipher);
+ }
+#ifdef FEATURE_WLAN_WAPI
+ if (!match_any) {
+ /* Check WAPI */
+ *uc_cipher = eCSR_ENCRYPT_TYPE_WPI;
+ match_any = csr_is_wapi_match(hal, auth_type,
+ *uc_cipher, mc_enc_type, ies_ptr,
+ neg_auth_type, mc_cipher);
+ }
+#endif
+ }
+ if (match_any)
+ return match;
+ *uc_cipher = eCSR_ENCRYPT_TYPE_WEP104;
+ if (csr_validate_wep(mac_ctx, *uc_cipher, auth_type, mc_enc_type,
+ neg_auth_type, mc_cipher, bss_desc, ies_ptr))
+ return match;
+ *uc_cipher = eCSR_ENCRYPT_TYPE_WEP40;
+ if (csr_validate_wep(mac_ctx, *uc_cipher, auth_type, mc_enc_type,
+ neg_auth_type, mc_cipher, bss_desc, ies_ptr))
+ return match;
+ *uc_cipher = eCSR_ENCRYPT_TYPE_WEP104_STATICKEY;
+ if (csr_validate_wep(mac_ctx, *uc_cipher, auth_type, mc_enc_type,
+ neg_auth_type, mc_cipher, bss_desc, ies_ptr))
+ return match;
+ *uc_cipher = eCSR_ENCRYPT_TYPE_WEP40_STATICKEY;
+ if (csr_validate_wep(mac_ctx, *uc_cipher, auth_type, mc_enc_type,
+ neg_auth_type, mc_cipher, bss_desc, ies_ptr))
+ return match;
+ /* It must be open and no enc */
+ if (csr_is_privacy(bss_desc)) {
+ match = false;
+ return match;
+ }
+
+ *neg_auth_type = eCSR_AUTH_TYPE_OPEN_SYSTEM;
+ *mc_cipher = eCSR_ENCRYPT_TYPE_NONE;
+ *uc_cipher = eCSR_ENCRYPT_TYPE_NONE;
+ return match;
+
+}
+
+/**
+ * csr_is_security_match() - Check if the security is matching
+ * @hal: Global HAL handle
+ * @auth_type: Authentication type
+ * @uc_enc_type: Unicast Encryption type
+ * @mc_enc_type: Multicast encryption type
+ * @mfp_enabled: Management frame protection feature
+ * @mfp_required: Mangement frame protection mandatory
+ * @mfp_capable: Device capable of MFP
+ * @bss_desc: BSS Descriptor
+ * @ies_ptr: Pointer to the IE fields
+ * @neg_auth_type: Negotiated Auth type with the AP
+ * @neg_uc_cipher: Negotiated unicast cipher suite
+ * @neg_mc_cipher: Negotiated multicast cipher
+ *
+ * Return: Boolean value to tell if matched or not.
+ */
+bool csr_is_security_match(tHalHandle hal, tCsrAuthList *auth_type,
+ tCsrEncryptionList *uc_enc_type,
+ tCsrEncryptionList *mc_enc_type, bool *mfp_enabled,
+ uint8_t *mfp_required, uint8_t *mfp_capable,
+ tSirBssDescription *bss_desc, tDot11fBeaconIEs *ies_ptr,
+ eCsrAuthType *neg_auth_type,
+ eCsrEncryptionType *neg_uc_cipher,
+ eCsrEncryptionType *neg_mc_cipher)
+{
+ tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal);
+ bool match = false;
+ uint8_t i;
+ eCsrEncryptionType mc_cipher = eCSR_ENCRYPT_TYPE_UNKNOWN;
+ eCsrEncryptionType uc_cipher = eCSR_ENCRYPT_TYPE_UNKNOWN;
+ eCsrAuthType local_neg_auth_type = eCSR_AUTH_TYPE_UNKNOWN;
+
+ for (i = 0; ((i < uc_enc_type->numEntries) && (!match)); i++) {
+ uc_cipher = uc_enc_type->encryptionType[i];
+ /*
+ * If the Bss description shows the Privacy bit is on, then we
+ * must have some sort of encryption configured for the profile
+ * to work. Don't attempt to join networks with Privacy bit
+ * set when profiles say NONE for encryption type.
+ */
+ switch (uc_cipher) {
+ case eCSR_ENCRYPT_TYPE_NONE:
+ match = csr_validate_open_none(bss_desc, mc_enc_type,
+ &mc_cipher, auth_type,
+ &local_neg_auth_type);
+ break;
+
+ case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY:
+ case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY:
+ /*
+ * !! might want to check for WEP keys set in the
+ * Profile.... ? !! don't need to have the privacy bit
+ * in the Bss description. Many AP policies make
+ * legacy encryption 'optional' so we don't know if we
+ * can associate or not. The AP will reject if
+ * encryption is not allowed without the Privacy bit
+ * turned on.
+ */
+ match = csr_validate_wep(mac_ctx, uc_cipher, auth_type,
+ mc_enc_type, &local_neg_auth_type,
+ &mc_cipher, bss_desc, ies_ptr);
+
+ break;
+ /* these are all of the WPA encryption types... */
+ case eCSR_ENCRYPT_TYPE_WEP40:
+ case eCSR_ENCRYPT_TYPE_WEP104:
+ match = csr_validate_wep(mac_ctx, uc_cipher, auth_type,
+ mc_enc_type, &local_neg_auth_type,
+ &mc_cipher, bss_desc, ies_ptr);
+ break;
+
+ case eCSR_ENCRYPT_TYPE_TKIP:
+ case eCSR_ENCRYPT_TYPE_AES:
+ if (!ies_ptr) {
+ match = false;
+ break;
+ }
+ /* First check if there is a RSN match */
+ match = csr_is_rsn_match(mac_ctx, auth_type,
+ uc_cipher, mc_enc_type,
+ mfp_enabled, mfp_required,
+ mfp_capable, ies_ptr,
+ &local_neg_auth_type,
+ &mc_cipher);
+ /* If not RSN, then check WPA match */
+ if (!match)
+ match = csr_is_wpa_encryption_match(
+ mac_ctx, auth_type,
+ uc_cipher, mc_enc_type,
+ ies_ptr,
+ &local_neg_auth_type,
+ &mc_cipher);
+ break;
+#ifdef FEATURE_WLAN_WAPI
+ case eCSR_ENCRYPT_TYPE_WPI: /* WAPI */
+ if (ies_ptr)
+ match = csr_is_wapi_match(hal, auth_type,
+ uc_cipher, mc_enc_type, ies_ptr,
+ &local_neg_auth_type,
+ &mc_cipher);
+ else
+ match = false;
+ break;
+#endif /* FEATURE_WLAN_WAPI */
+ case eCSR_ENCRYPT_TYPE_ANY:
+ default:
+ match = csr_validate_any_default(hal, auth_type,
+ mc_enc_type, mfp_enabled, mfp_required,
+ mfp_capable, ies_ptr,
+ &local_neg_auth_type, bss_desc,
+ &uc_cipher, &mc_cipher);
+ break;
+ }
+
+ }
+
+ if (match) {
+ if (neg_uc_cipher)
+ *neg_uc_cipher = uc_cipher;
+ if (neg_mc_cipher)
+ *neg_mc_cipher = mc_cipher;
+ if (neg_auth_type)
+ *neg_auth_type = local_neg_auth_type;
+ }
+ return match;
+}
+
+bool csr_is_ssid_match(tpAniSirGlobal pMac, uint8_t *ssid1, uint8_t ssid1Len,
+ uint8_t *bssSsid, uint8_t bssSsidLen, bool fSsidRequired)
+{
+ bool fMatch = false;
+
+ do {
+ /*
+ * Check for the specification of the Broadcast SSID at the
+ * beginning of the list. If specified, then all SSIDs are
+ * matches (broadcast SSID means accept all SSIDs).
+ */
+ if (ssid1Len == 0) {
+ fMatch = true;
+ break;
+ }
+
+ /* There are a few special cases. If the Bss description has a Broadcast SSID, */
+ /* then our Profile must have a single SSID without Wildcards so we can program */
+ /* the SSID. */
+ /* SSID could be suppressed in beacons. In that case SSID IE has valid length */
+ /* but the SSID value is all NULL characters. That condition is trated same */
+ /* as NULL SSID */
+ if (csr_is_nullssid(bssSsid, bssSsidLen)) {
+ if (false == fSsidRequired) {
+ fMatch = true;
+ break;
+ }
+ }
+
+ if (ssid1Len != bssSsidLen)
+ break;
+ if (cdf_mem_compare(bssSsid, ssid1, bssSsidLen)) {
+ fMatch = true;
+ break;
+ }
+
+ } while (0);
+
+ return fMatch;
+}
+
+/* Null ssid means match */
+bool csr_is_ssid_in_list(tHalHandle hHal, tSirMacSSid *pSsid,
+ tCsrSSIDs *pSsidList)
+{
+ bool fMatch = false;
+ uint32_t i;
+
+ if (pSsidList && pSsid) {
+ for (i = 0; i < pSsidList->numOfSSIDs; i++) {
+ if (csr_is_nullssid
+ (pSsidList->SSIDList[i].SSID.ssId,
+ pSsidList->SSIDList[i].SSID.length)
+ ||
+ ((pSsidList->SSIDList[i].SSID.length ==
+ pSsid->length)
+ && cdf_mem_compare(pSsid->ssId,
+ pSsidList->SSIDList[i].SSID.
+ ssId, pSsid->length))) {
+ fMatch = true;
+ break;
+ }
+ }
+ }
+
+ return fMatch;
+}
+
+bool csr_is_bssid_match(tHalHandle hHal, struct cdf_mac_addr *pProfBssid,
+ struct cdf_mac_addr *BssBssid)
+{
+ bool fMatch = false;
+ struct cdf_mac_addr ProfileBssid;
+
+ /* for efficiency of the MAC_ADDRESS functions, move the */
+ /* Bssid's into MAC_ADDRESS structs. */
+ cdf_mem_copy(&ProfileBssid, pProfBssid, sizeof(struct cdf_mac_addr));
+
+ do {
+
+ /* Give the profile the benefit of the doubt... accept either all 0 or */
+ /* the real broadcast Bssid (all 0xff) as broadcast Bssids (meaning to */
+ /* match any Bssids). */
+ if (cdf_is_macaddr_zero(&ProfileBssid) ||
+ cdf_is_macaddr_broadcast(&ProfileBssid)) {
+ fMatch = true;
+ break;
+ }
+
+ if (cdf_is_macaddr_equal(BssBssid, &ProfileBssid)) {
+ fMatch = true;
+ break;
+ }
+
+ } while (0);
+
+ return fMatch;
+}
+
+bool csr_is_bss_type_match(eCsrRoamBssType bssType1, eCsrRoamBssType bssType2)
+{
+ if ((eCSR_BSS_TYPE_ANY != bssType1 && eCSR_BSS_TYPE_ANY != bssType2)
+ && (bssType1 != bssType2))
+ return false;
+ else
+ return true;
+}
+
+bool csr_is_bss_type_ibss(eCsrRoamBssType bssType)
+{
+ return (bool)
+ (eCSR_BSS_TYPE_START_IBSS == bssType
+ || eCSR_BSS_TYPE_IBSS == bssType);
+}
+
+bool csr_is_bss_type_wds(eCsrRoamBssType bssType)
+{
+ return (bool)
+ (eCSR_BSS_TYPE_WDS_STA == bssType
+ || eCSR_BSS_TYPE_WDS_AP == bssType);
+}
+
+bool csr_is_bss_type_caps_match(eCsrRoamBssType bssType,
+ tSirBssDescription *pSirBssDesc)
+{
+ bool fMatch = true;
+
+ do {
+ switch (bssType) {
+ case eCSR_BSS_TYPE_ANY:
+ break;
+
+ case eCSR_BSS_TYPE_INFRASTRUCTURE:
+ case eCSR_BSS_TYPE_WDS_STA:
+ if (!csr_is_infra_bss_desc(pSirBssDesc))
+ fMatch = false;
+
+ break;
+
+ case eCSR_BSS_TYPE_IBSS:
+ case eCSR_BSS_TYPE_START_IBSS:
+ if (!csr_is_ibss_bss_desc(pSirBssDesc))
+ fMatch = false;
+
+ break;
+
+ case eCSR_BSS_TYPE_WDS_AP: /* For WDS AP, no need to match anything */
+ default:
+ fMatch = false;
+ break;
+ }
+ } while (0);
+
+ return fMatch;
+}
+
+static bool csr_is_capabilities_match(tpAniSirGlobal pMac, eCsrRoamBssType bssType,
+ tSirBssDescription *pSirBssDesc)
+{
+ return csr_is_bss_type_caps_match(bssType, pSirBssDesc);
+}
+
+static bool csr_is_specific_channel_match(tpAniSirGlobal pMac,
+ tSirBssDescription *pSirBssDesc,
+ uint8_t Channel)
+{
+ bool fMatch = true;
+
+ do {
+ /* if the channel is ANY, then always match... */
+ if (eCSR_OPERATING_CHANNEL_ANY == Channel)
+ break;
+ if (Channel == pSirBssDesc->channelId)
+ break;
+
+ /* didn't match anything.. so return NO match */
+ fMatch = false;
+
+ } while (0);
+
+ return fMatch;
+}
+
+bool csr_is_channel_band_match(tpAniSirGlobal pMac, uint8_t channelId,
+ tSirBssDescription *pSirBssDesc)
+{
+ bool fMatch = true;
+
+ do {
+ /* if the profile says Any channel AND the global settings says ANY channel, then we */
+ /* always match... */
+ if (eCSR_OPERATING_CHANNEL_ANY == channelId)
+ break;
+
+ if (eCSR_OPERATING_CHANNEL_ANY != channelId) {
+ fMatch =
+ csr_is_specific_channel_match(pMac, pSirBssDesc,
+ channelId);
+ }
+
+ } while (0);
+
+ return fMatch;
+}
+
+/**
+ * csr_is_aggregate_rate_supported() - to check if aggregate rate is supported
+ * @mac_ctx: pointer to mac context
+ * @rate: A rate in units of 500kbps
+ *
+ *
+ * The rate encoding is just as in 802.11 Information Elements, except
+ * that the high bit is \em not interpreted as indicating a Basic Rate,
+ * and proprietary rates are allowed, too.
+ *
+ * Note that if the adapter's dot11Mode is g, we don't restrict the
+ * rates. According to hwReadEepromParameters, this will happen when:
+ * ... the card is configured for ALL bands through the property
+ * page. If this occurs, and the card is not an ABG card ,then this
+ * code is setting the dot11Mode to assume the mode that the
+ * hardware can support. For example, if the card is an 11BG card
+ * and we are configured to support ALL bands, then we change the
+ * dot11Mode to 11g because ALL in this case is only what the
+ * hardware can support.
+ *
+ * Return: true if the adapter is currently capable of supporting this rate
+ */
+
+static bool csr_is_aggregate_rate_supported(tpAniSirGlobal mac_ctx,
+ uint16_t rate)
+{
+ bool supported = false;
+ uint16_t idx, new_rate;
+
+ /* In case basic rate flag is set */
+ new_rate = BITS_OFF(rate, CSR_DOT11_BASIC_RATE_MASK);
+ if (eCSR_CFG_DOT11_MODE_11A ==
+ mac_ctx->roam.configParam.uCfgDot11Mode) {
+ switch (new_rate) {
+ case eCsrSuppRate_6Mbps:
+ case eCsrSuppRate_9Mbps:
+ case eCsrSuppRate_12Mbps:
+ case eCsrSuppRate_18Mbps:
+ case eCsrSuppRate_24Mbps:
+ case eCsrSuppRate_36Mbps:
+ case eCsrSuppRate_48Mbps:
+ case eCsrSuppRate_54Mbps:
+ supported = true;
+ break;
+ default:
+ supported = false;
+ break;
+ }
+
+ } else if (eCSR_CFG_DOT11_MODE_11B ==
+ mac_ctx->roam.configParam.uCfgDot11Mode) {
+ switch (new_rate) {
+ case eCsrSuppRate_1Mbps:
+ case eCsrSuppRate_2Mbps:
+ case eCsrSuppRate_5_5Mbps:
+ case eCsrSuppRate_11Mbps:
+ supported = true;
+ break;
+ default:
+ supported = false;
+ break;
+ }
+ } else if (!mac_ctx->roam.configParam.ProprietaryRatesEnabled) {
+
+ switch (new_rate) {
+ case eCsrSuppRate_1Mbps:
+ case eCsrSuppRate_2Mbps:
+ case eCsrSuppRate_5_5Mbps:
+ case eCsrSuppRate_6Mbps:
+ case eCsrSuppRate_9Mbps:
+ case eCsrSuppRate_11Mbps:
+ case eCsrSuppRate_12Mbps:
+ case eCsrSuppRate_18Mbps:
+ case eCsrSuppRate_24Mbps:
+ case eCsrSuppRate_36Mbps:
+ case eCsrSuppRate_48Mbps:
+ case eCsrSuppRate_54Mbps:
+ supported = true;
+ break;
+ default:
+ supported = false;
+ break;
+ }
+ } else if (eCsrSuppRate_1Mbps == new_rate ||
+ eCsrSuppRate_2Mbps == new_rate ||
+ eCsrSuppRate_5_5Mbps == new_rate ||
+ eCsrSuppRate_11Mbps == new_rate) {
+ supported = true;
+ } else {
+ idx = 0x1;
+
+ switch (new_rate) {
+ case eCsrSuppRate_6Mbps:
+ supported = g_phy_rates_suppt[0][idx];
+ break;
+ case eCsrSuppRate_9Mbps:
+ supported = g_phy_rates_suppt[1][idx];
+ break;
+ case eCsrSuppRate_12Mbps:
+ supported = g_phy_rates_suppt[2][idx];
+ break;
+ case eCsrSuppRate_18Mbps:
+ supported = g_phy_rates_suppt[3][idx];
+ break;
+ case eCsrSuppRate_20Mbps:
+ supported = g_phy_rates_suppt[4][idx];
+ break;
+ case eCsrSuppRate_24Mbps:
+ supported = g_phy_rates_suppt[5][idx];
+ break;
+ case eCsrSuppRate_36Mbps:
+ supported = g_phy_rates_suppt[6][idx];
+ break;
+ case eCsrSuppRate_40Mbps:
+ supported = g_phy_rates_suppt[7][idx];
+ break;
+ case eCsrSuppRate_42Mbps:
+ supported = g_phy_rates_suppt[8][idx];
+ break;
+ case eCsrSuppRate_48Mbps:
+ supported = g_phy_rates_suppt[9][idx];
+ break;
+ case eCsrSuppRate_54Mbps:
+ supported = g_phy_rates_suppt[10][idx];
+ break;
+ case eCsrSuppRate_72Mbps:
+ supported = g_phy_rates_suppt[11][idx];
+ break;
+ case eCsrSuppRate_80Mbps:
+ supported = g_phy_rates_suppt[12][idx];
+ break;
+ case eCsrSuppRate_84Mbps:
+ supported = g_phy_rates_suppt[13][idx];
+ break;
+ case eCsrSuppRate_96Mbps:
+ supported = g_phy_rates_suppt[14][idx];
+ break;
+ case eCsrSuppRate_108Mbps:
+ supported = g_phy_rates_suppt[15][idx];
+ break;
+ case eCsrSuppRate_120Mbps:
+ supported = g_phy_rates_suppt[16][idx];
+ break;
+ case eCsrSuppRate_126Mbps:
+ supported = g_phy_rates_suppt[17][idx];
+ break;
+ case eCsrSuppRate_144Mbps:
+ supported = g_phy_rates_suppt[18][idx];
+ break;
+ case eCsrSuppRate_160Mbps:
+ supported = g_phy_rates_suppt[19][idx];
+ break;
+ case eCsrSuppRate_168Mbps:
+ supported = g_phy_rates_suppt[20][idx];
+ break;
+ case eCsrSuppRate_192Mbps:
+ supported = g_phy_rates_suppt[21][idx];
+ break;
+ case eCsrSuppRate_216Mbps:
+ supported = g_phy_rates_suppt[22][idx];
+ break;
+ case eCsrSuppRate_240Mbps:
+ supported = g_phy_rates_suppt[23][idx];
+ break;
+ default:
+ supported = false;
+ break;
+ }
+ }
+ return supported;
+}
+
+/**
+ * csr_is_rate_set_match() - to check if rate set is matching
+ * @mac_ctx: pointer to mac context
+ * @bss_supported_rates: supported rates of BSS
+ * @bss_ext_supp_rates: extended rates of bss
+ *
+ * This routine is to checke if rate set is matched or no
+ *
+ * Return: bool
+ */
+static bool csr_is_rate_set_match(tpAniSirGlobal mac_ctx,
+ tDot11fIESuppRates *bss_supported_rates,
+ tDot11fIEExtSuppRates *bss_ext_supp_rates)
+{
+ bool match = true;
+ uint32_t i;
+
+ /*
+ * Validate that all of the Basic rates advertised in the Bss
+ * description are supported
+ */
+ if (bss_supported_rates) {
+ for (i = 0; i < bss_supported_rates->num_rates; i++) {
+ if (!CSR_IS_BASIC_RATE(bss_supported_rates->rates[i]))
+ continue;
+ if (!csr_is_aggregate_rate_supported(mac_ctx,
+ bss_supported_rates->rates[i])) {
+ match = false;
+ break;
+ }
+ }
+ }
+ if (match && bss_ext_supp_rates) {
+ for (i = 0; i < bss_ext_supp_rates->num_rates; i++) {
+ if (!CSR_IS_BASIC_RATE(bss_ext_supp_rates->rates[i]))
+ continue;
+ if (!csr_is_aggregate_rate_supported(mac_ctx,
+ bss_ext_supp_rates->rates[i])) {
+ match = false;
+ break;
+ }
+ }
+ }
+ return match;
+}
+
+/**
+ * csr_match_bss() - to compare the bss
+ * @hal: pointer to hal context
+ * @bss_descr: pointer bss description
+ * @filter: scan filter
+ * @neg_auth: negotiated auth
+ * @neg_uc: negotiated for unicast
+ * @neg_mc: negotiated for multicast
+ * @ie_dblptr: double pointer to IE
+ *
+ * This routine will be called to match the bss
+ * If caller want to get the *ie_dblptr allocated by this function,
+ * pass in *ie_dblptr = NULL
+ *
+ * Return: bool
+ */
+bool csr_match_bss(tHalHandle hal, tSirBssDescription *bss_descr,
+ tCsrScanResultFilter *filter, eCsrAuthType *neg_auth,
+ eCsrEncryptionType *neg_uc, eCsrEncryptionType *neg_mc,
+ tDot11fBeaconIEs **ie_dblptr)
+{
+ tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal);
+ bool rc = false, check, blacklist_check;
+ uint32_t i;
+ tDot11fBeaconIEs *ie_ptr = NULL;
+ uint8_t *pb;
+ struct roam_ext_params *roam_params;
+ uint8_t *p2p_macaddr = NULL;
+
+ roam_params = &mac_ctx->roam.configParam.roam_params;
+ if ((NULL == ie_dblptr) || (*ie_dblptr) == NULL) {
+ /* If no IEs passed in, get our own. */
+ if (!CDF_IS_STATUS_SUCCESS(
+ csr_get_parsed_bss_description_ies(mac_ctx,
+ bss_descr, &ie_ptr))) {
+ goto end;
+ }
+ } else {
+ /* Save the one pass in for local use */
+ ie_ptr = *ie_dblptr;
+ }
+
+ /* Check if caller wants P2P */
+ check = (!filter->p2pResult || ie_ptr->P2PBeaconProbeRes.present);
+ if (!check)
+ goto end;
+
+ /* Check for Blacklist BSSID's and avoid connections */
+ blacklist_check = false;
+ for (i = 0; i < roam_params->num_bssid_avoid_list; i++) {
+ if (cdf_is_macaddr_equal((struct cdf_mac_addr *)
+ &roam_params->bssid_avoid_list[i],
+ (struct cdf_mac_addr *)bss_descr->bssId)) {
+ blacklist_check = true;
+ break;
+ }
+ }
+ if (blacklist_check) {
+ sms_log(mac_ctx, LOGE,
+ FL("Don't Attempt connect to blacklist bssid"));
+ goto end;
+ }
+
+ if (ie_ptr->SSID.present) {
+ for (i = 0; i < filter->SSIDs.numOfSSIDs; i++) {
+ check = csr_is_ssid_match(mac_ctx,
+ filter->SSIDs.SSIDList[i].SSID.ssId,
+ filter->SSIDs.SSIDList[i].SSID.length,
+ ie_ptr->SSID.ssid,
+ ie_ptr->SSID.num_ssid, true);
+ if (check)
+ break;
+ }
+ if (!check)
+ goto end;
+ }
+ check = true;
+ p2p_macaddr = ie_ptr->P2PBeaconProbeRes.P2PDeviceInfo.P2PDeviceAddress;
+ for (i = 0; i < filter->BSSIDs.numOfBSSIDs; i++) {
+ check = csr_is_bssid_match(mac_ctx,
+ (struct cdf_mac_addr *)&filter->BSSIDs.bssid[i],
+ (struct cdf_mac_addr *)bss_descr->bssId);
+ if (check)
+ break;
+
+ if (filter->p2pResult && ie_ptr->P2PBeaconProbeRes.present) {
+ check = csr_is_bssid_match(mac_ctx,
+ (struct cdf_mac_addr *)
+ &filter->BSSIDs.bssid[i],
+ (struct cdf_mac_addr *)p2p_macaddr);
+ if (check)
+ break;
+ }
+ }
+ if (!check)
+ goto end;
+
+ check = true;
+ for (i = 0; i < filter->ChannelInfo.numOfChannels; i++) {
+ check = csr_is_channel_band_match(mac_ctx,
+ filter->ChannelInfo.ChannelList[i], bss_descr);
+ if (check)
+ break;
+ }
+ if (!check)
+ goto end;
+#if defined WLAN_FEATURE_VOWIFI
+ /* If this is for measurement filtering */
+ if (filter->fMeasurement) {
+ rc = true;
+ goto end;
+ }
+#endif
+ if (!csr_is_phy_mode_match(mac_ctx, filter->phyMode, bss_descr,
+ NULL, NULL, ie_ptr))
+ goto end;
+
+#ifdef WLAN_FEATURE_11W
+ if ((!filter->bWPSAssociation) && (!filter->bOSENAssociation) &&
+ !csr_is_security_match(mac_ctx, &filter->authType,
+ &filter->EncryptionType,
+ &filter->mcEncryptionType,
+ &filter->MFPEnabled,
+ &filter->MFPRequired,
+ &filter->MFPCapable,
+ bss_descr, ie_ptr, neg_auth,
+ neg_uc, neg_mc))
+#else
+ if ((!filter->bWPSAssociation) && (!filter->bOSENAssociation) &&
+ !csr_is_security_match(mac_ctx, &filter->authType,
+ &filter->EncryptionType,
+ &filter->mcEncryptionType,
+ NULL, NULL, NULL,
+ bss_descr, ie_ptr, neg_auth,
+ neg_uc, neg_mc))
+#endif
+ goto end;
+ if (!csr_is_capabilities_match(mac_ctx, filter->BSSType, bss_descr))
+ goto end;
+ if (!csr_is_rate_set_match(mac_ctx, &ie_ptr->SuppRates,
+ &ie_ptr->ExtSuppRates))
+ goto end;
+ if ((eCsrRoamWmmQbssOnly == mac_ctx->roam.configParam.WMMSupportMode)
+ && !CSR_IS_QOS_BSS(ie_ptr))
+ goto end;
+ /*
+ * Check country. check even when pb is NULL because we may
+ * want to make sure
+ */
+ pb = (filter->countryCode[0]) ? (filter->countryCode) : NULL;
+ check = csr_match_country_code(mac_ctx, pb, ie_ptr);
+ if (!check)
+ goto end;
+
+#ifdef WLAN_FEATURE_VOWIFI_11R
+ if (filter->MDID.mdiePresent && csr_roam_is11r_assoc(mac_ctx,
+ mac_ctx->roam.roamSession->sessionId)) {
+ if (bss_descr->mdiePresent) {
+ if (filter->MDID.mobilityDomain !=
+ (bss_descr->mdie[1] << 8 |
+ bss_descr->mdie[0]))
+ goto end;
+ } else {
+ goto end;
+ }
+ }
+#endif
+ rc = true;
+
+end:
+ if (ie_dblptr)
+ *ie_dblptr = ie_ptr;
+ else if (ie_ptr)
+ cdf_mem_free(ie_ptr);
+ return rc;
+}
+
+bool csr_match_connected_bss_security(tpAniSirGlobal pMac,
+ tCsrRoamConnectedProfile *pProfile,
+ tSirBssDescription *pBssDesc,
+ tDot11fBeaconIEs *pIes)
+{
+ tCsrEncryptionList ucEncryptionList, mcEncryptionList;
+ tCsrAuthList authList;
+
+ ucEncryptionList.numEntries = 1;
+ ucEncryptionList.encryptionType[0] = pProfile->EncryptionType;
+
+ mcEncryptionList.numEntries = 1;
+ mcEncryptionList.encryptionType[0] = pProfile->mcEncryptionType;
+
+ authList.numEntries = 1;
+ authList.authType[0] = pProfile->AuthType;
+
+ return csr_is_security_match(pMac, &authList, &ucEncryptionList,
+ &mcEncryptionList, NULL, NULL, NULL,
+ pBssDesc, pIes, NULL, NULL, NULL);
+
+}
+
+bool csr_match_bss_to_connect_profile(tHalHandle hHal,
+ tCsrRoamConnectedProfile *pProfile,
+ tSirBssDescription *pBssDesc,
+ tDot11fBeaconIEs *pIes)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ bool fRC = false, fCheck;
+ tDot11fBeaconIEs *pIesLocal = pIes;
+
+ do {
+ if (!pIes) {
+ if (!CDF_IS_STATUS_SUCCESS
+ (csr_get_parsed_bss_description_ies
+ (pMac, pBssDesc, &pIesLocal))) {
+ break;
+ }
+ }
+ fCheck = true;
+ if (pIesLocal->SSID.present) {
+ bool fCheckSsid = false;
+ if (pProfile->SSID.length) {
+ fCheckSsid = true;
+ }
+ fCheck =
+ csr_is_ssid_match(pMac, pProfile->SSID.ssId,
+ pProfile->SSID.length,
+ pIesLocal->SSID.ssid,
+ pIesLocal->SSID.num_ssid,
+ fCheckSsid);
+ if (!fCheck)
+ break;
+ }
+ if (!csr_match_connected_bss_security
+ (pMac, pProfile, pBssDesc, pIesLocal))
+ break;
+ if (!csr_is_capabilities_match(pMac, pProfile->BSSType, pBssDesc))
+ break;
+ if (!csr_is_rate_set_match
+ (pMac, &pIesLocal->SuppRates, &pIesLocal->ExtSuppRates))
+ break;
+ fCheck =
+ csr_is_channel_band_match(pMac, pProfile->operationChannel,
+ pBssDesc);
+ if (!fCheck)
+ break;
+
+ fRC = true;
+
+ } while (0);
+
+ if (!pIes && pIesLocal) {
+ /* locally allocated */
+ cdf_mem_free(pIesLocal);
+ }
+
+ return fRC;
+}
+
+void csr_add_rate_bitmap(uint8_t rate, uint16_t *pRateBitmap)
+{
+ uint16_t rateBitmap;
+ uint16_t n = BITS_OFF(rate, CSR_DOT11_BASIC_RATE_MASK);
+ rateBitmap = *pRateBitmap;
+ switch (n) {
+ case SIR_MAC_RATE_1:
+ rateBitmap |= SIR_MAC_RATE_1_BITMAP;
+ break;
+ case SIR_MAC_RATE_2:
+ rateBitmap |= SIR_MAC_RATE_2_BITMAP;
+ break;
+ case SIR_MAC_RATE_5_5:
+ rateBitmap |= SIR_MAC_RATE_5_5_BITMAP;
+ break;
+ case SIR_MAC_RATE_11:
+ rateBitmap |= SIR_MAC_RATE_11_BITMAP;
+ break;
+ case SIR_MAC_RATE_6:
+ rateBitmap |= SIR_MAC_RATE_6_BITMAP;
+ break;
+ case SIR_MAC_RATE_9:
+ rateBitmap |= SIR_MAC_RATE_9_BITMAP;
+ break;
+ case SIR_MAC_RATE_12:
+ rateBitmap |= SIR_MAC_RATE_12_BITMAP;
+ break;
+ case SIR_MAC_RATE_18:
+ rateBitmap |= SIR_MAC_RATE_18_BITMAP;
+ break;
+ case SIR_MAC_RATE_24:
+ rateBitmap |= SIR_MAC_RATE_24_BITMAP;
+ break;
+ case SIR_MAC_RATE_36:
+ rateBitmap |= SIR_MAC_RATE_36_BITMAP;
+ break;
+ case SIR_MAC_RATE_48:
+ rateBitmap |= SIR_MAC_RATE_48_BITMAP;
+ break;
+ case SIR_MAC_RATE_54:
+ rateBitmap |= SIR_MAC_RATE_54_BITMAP;
+ break;
+ }
+ *pRateBitmap = rateBitmap;
+}
+
+bool csr_check_rate_bitmap(uint8_t rate, uint16_t rateBitmap)
+{
+ uint16_t n = BITS_OFF(rate, CSR_DOT11_BASIC_RATE_MASK);
+
+ switch (n) {
+ case SIR_MAC_RATE_1:
+ rateBitmap &= SIR_MAC_RATE_1_BITMAP;
+ break;
+ case SIR_MAC_RATE_2:
+ rateBitmap &= SIR_MAC_RATE_2_BITMAP;
+ break;
+ case SIR_MAC_RATE_5_5:
+ rateBitmap &= SIR_MAC_RATE_5_5_BITMAP;
+ break;
+ case SIR_MAC_RATE_11:
+ rateBitmap &= SIR_MAC_RATE_11_BITMAP;
+ break;
+ case SIR_MAC_RATE_6:
+ rateBitmap &= SIR_MAC_RATE_6_BITMAP;
+ break;
+ case SIR_MAC_RATE_9:
+ rateBitmap &= SIR_MAC_RATE_9_BITMAP;
+ break;
+ case SIR_MAC_RATE_12:
+ rateBitmap &= SIR_MAC_RATE_12_BITMAP;
+ break;
+ case SIR_MAC_RATE_18:
+ rateBitmap &= SIR_MAC_RATE_18_BITMAP;
+ break;
+ case SIR_MAC_RATE_24:
+ rateBitmap &= SIR_MAC_RATE_24_BITMAP;
+ break;
+ case SIR_MAC_RATE_36:
+ rateBitmap &= SIR_MAC_RATE_36_BITMAP;
+ break;
+ case SIR_MAC_RATE_48:
+ rateBitmap &= SIR_MAC_RATE_48_BITMAP;
+ break;
+ case SIR_MAC_RATE_54:
+ rateBitmap &= SIR_MAC_RATE_54_BITMAP;
+ break;
+ }
+ return !!rateBitmap;
+}
+
+bool csr_rates_is_dot11_rate_supported(tHalHandle hHal, uint8_t rate)
+{
+ tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+ uint16_t n = BITS_OFF(rate, CSR_DOT11_BASIC_RATE_MASK);
+
+ return csr_is_aggregate_rate_supported(pMac, n);
+}
+
+uint16_t csr_rates_mac_prop_to_dot11(uint16_t Rate)
+{
+ uint16_t ConvertedRate = Rate;
+
+ switch (Rate) {
+ case SIR_MAC_RATE_1:
+ ConvertedRate = 2;
+ break;
+ case SIR_MAC_RATE_2:
+ ConvertedRate = 4;
+ break;
+ case SIR_MAC_RATE_5_5:
+ ConvertedRate = 11;
+ break;
+ case SIR_MAC_RATE_11:
+ ConvertedRate = 22;
+ break;
+
+ case SIR_MAC_RATE_6:
+ ConvertedRate = 12;
+ break;
+ case SIR_MAC_RATE_9:
+ ConvertedRate = 18;
+ break;
+ case SIR_MAC_RATE_12:
+ ConvertedRate = 24;
+ break;
+ case SIR_MAC_RATE_18:
+ ConvertedRate = 36;
+ break;
+ case SIR_MAC_RATE_24:
+ ConvertedRate = 48;
+ break;
+ case SIR_MAC_RATE_36:
+ ConvertedRate = 72;
+ break;
+ case SIR_MAC_RATE_42:
+ ConvertedRate = 84;
+ break;
+ case SIR_MAC_RATE_48:
+ ConvertedRate = 96;
+ break;
+ case SIR_MAC_RATE_54:
+ ConvertedRate = 108;
+ break;
+
+ case SIR_MAC_RATE_72:
+ ConvertedRate = 144;
+ break;
+ case SIR_MAC_RATE_84:
+ ConvertedRate = 168;
+ break;
+ case SIR_MAC_RATE_96:
+ ConvertedRate = 192;
+ break;
+ case SIR_MAC_RATE_108:
+ ConvertedRate = 216;
+ break;
+ case SIR_MAC_RATE_126:
+ ConvertedRate = 252;
+ break;
+ case SIR_MAC_RATE_144:
+ ConvertedRate = 288;
+ break;
+ case SIR_MAC_RATE_168:
+ ConvertedRate = 336;
+ break;
+ case SIR_MAC_RATE_192:
+ ConvertedRate = 384;
+ break;
+ case SIR_MAC_RATE_216:
+ ConvertedRate = 432;
+ break;
+ case SIR_MAC_RATE_240:
+ ConvertedRate = 480;
+ break;
+
+ case 0xff:
+ ConvertedRate = 0;
+ break;
+ }
+
+ return ConvertedRate;
+}
+
+uint16_t csr_rates_find_best_rate(tSirMacRateSet *pSuppRates,
+ tSirMacRateSet *pExtRates,
+ tSirMacPropRateSet *pPropRates)
+{
+ uint8_t i;
+ uint16_t nBest;
+
+ nBest = pSuppRates->rate[0] & (~CSR_DOT11_BASIC_RATE_MASK);
+
+ if (pSuppRates->numRates > SIR_MAC_RATESET_EID_MAX) {
+ pSuppRates->numRates = SIR_MAC_RATESET_EID_MAX;
+ }
+
+ for (i = 1U; i < pSuppRates->numRates; ++i) {
+ nBest =
+ (uint16_t) CSR_MAX(nBest,
+ pSuppRates->
+ rate[i] & (~CSR_DOT11_BASIC_RATE_MASK));
+ }
+
+ if (NULL != pExtRates) {
+ for (i = 0U; i < pExtRates->numRates; ++i) {
+ nBest =
+ (uint16_t) CSR_MAX(nBest,
+ pExtRates->
+ rate[i] &
+ (~CSR_DOT11_BASIC_RATE_MASK));
+ }
+ }
+
+ if (NULL != pPropRates) {
+ for (i = 0U; i < pPropRates->numPropRates; ++i) {
+ nBest =
+ (uint16_t) CSR_MAX(nBest,
+ csr_rates_mac_prop_to_dot11
+ (pPropRates->propRate[i]));
+ }
+ }
+
+ return nBest;
+}
+
+void csr_release_profile(tpAniSirGlobal pMac, tCsrRoamProfile *pProfile)
+{
+ if (pProfile) {
+ if (pProfile->BSSIDs.bssid) {
+ cdf_mem_free(pProfile->BSSIDs.bssid);
+ pProfile->BSSIDs.bssid = NULL;
+ }
+ if (pProfile->SSIDs.SSIDList) {
+ cdf_mem_free(pProfile->SSIDs.SSIDList);
+ pProfile->SSIDs.SSIDList = NULL;
+ }
+ if (pProfile->pWPAReqIE) {
+ cdf_mem_free(pProfile->pWPAReqIE);
+ pProfile->pWPAReqIE = NULL;
+ }
+ if (pProfile->pRSNReqIE) {
+ cdf_mem_free(pProfile->pRSNReqIE);
+ pProfile->pRSNReqIE = NULL;
+ }
+#ifdef FEATURE_WLAN_WAPI
+ if (pProfile->pWAPIReqIE) {
+ cdf_mem_free(pProfile->pWAPIReqIE);
+ pProfile->pWAPIReqIE = NULL;
+ }
+#endif /* FEATURE_WLAN_WAPI */
+
+ if (pProfile->pAddIEScan) {
+ cdf_mem_free(pProfile->pAddIEScan);
+ pProfile->pAddIEScan = NULL;
+ }
+
+ if (pProfile->pAddIEAssoc) {
+ cdf_mem_free(pProfile->pAddIEAssoc);
+ pProfile->pAddIEAssoc = NULL;
+ }
+ if (pProfile->ChannelInfo.ChannelList) {
+ cdf_mem_free(pProfile->ChannelInfo.ChannelList);
+ pProfile->ChannelInfo.ChannelList = NULL;
+ }
+ cdf_mem_set(pProfile, sizeof(tCsrRoamProfile), 0);
+ }
+}
+
+void csr_free_scan_filter(tpAniSirGlobal pMac, tCsrScanResultFilter *pScanFilter)
+{
+ if (pScanFilter->BSSIDs.bssid) {
+ cdf_mem_free(pScanFilter->BSSIDs.bssid);
+ pScanFilter->BSSIDs.bssid = NULL;
+ }
+ if (pScanFilter->ChannelInfo.ChannelList) {
+ cdf_mem_free(pScanFilter->ChannelInfo.ChannelList);
+ pScanFilter->ChannelInfo.ChannelList = NULL;
+ }
+ if (pScanFilter->SSIDs.SSIDList) {
+ cdf_mem_free(pScanFilter->SSIDs.SSIDList);
+ pScanFilter->SSIDs.SSIDList = NULL;
+ }
+}
+
+void csr_free_roam_profile(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ tCsrRoamSession *pSession = &pMac->roam.roamSession[sessionId];
+
+ if (pSession->pCurRoamProfile) {
+ csr_release_profile(pMac, pSession->pCurRoamProfile);
+ cdf_mem_free(pSession->pCurRoamProfile);
+ pSession->pCurRoamProfile = NULL;
+ }
+}
+
+void csr_free_connect_bss_desc(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ tCsrRoamSession *pSession = &pMac->roam.roamSession[sessionId];
+
+ if (pSession->pConnectBssDesc) {
+ cdf_mem_free(pSession->pConnectBssDesc);
+ pSession->pConnectBssDesc = NULL;
+ }
+}
+
+tSirResultCodes csr_get_disassoc_rsp_status_code(tSirSmeDisassocRsp *
+ pSmeDisassocRsp)
+{
+ uint8_t *pBuffer = (uint8_t *) pSmeDisassocRsp;
+ uint32_t ret;
+
+ pBuffer += (sizeof(uint16_t) + sizeof(uint16_t) + sizeof(tSirMacAddr));
+ /* tSirResultCodes is an enum, assuming is 32bit */
+ /* If we cannot make this assumption, use copymemory */
+ cdf_get_u32(pBuffer, &ret);
+
+ return (tSirResultCodes) ret;
+}
+
+tSirResultCodes csr_get_de_auth_rsp_status_code(tSirSmeDeauthRsp *pSmeRsp)
+{
+ uint8_t *pBuffer = (uint8_t *) pSmeRsp;
+ uint32_t ret;
+
+ pBuffer +=
+ (sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint8_t) +
+ sizeof(uint16_t));
+ /* tSirResultCodes is an enum, assuming is 32bit */
+ /* If we cannot make this assumption, use copymemory */
+ cdf_get_u32(pBuffer, &ret);
+
+ return (tSirResultCodes) ret;
+}
+
+tSirScanType csr_get_scan_type(tpAniSirGlobal pMac, uint8_t chnId)
+{
+ tSirScanType scanType = eSIR_PASSIVE_SCAN;
+ CHANNEL_STATE channelEnabledType;
+
+ channelEnabledType = cds_get_channel_state(chnId);
+ if (CHANNEL_STATE_ENABLE == channelEnabledType) {
+ scanType = eSIR_ACTIVE_SCAN;
+ }
+ return scanType;
+}
+
+uint8_t csr_to_upper(uint8_t ch)
+{
+ uint8_t chOut;
+
+ if (ch >= 'a' && ch <= 'z') {
+ chOut = ch - 'a' + 'A';
+ } else {
+ chOut = ch;
+ }
+ return chOut;
+}
+
+tSirBssType csr_translate_bsstype_to_mac_type(eCsrRoamBssType csrtype)
+{
+ tSirBssType ret;
+
+ switch (csrtype) {
+ case eCSR_BSS_TYPE_INFRASTRUCTURE:
+ ret = eSIR_INFRASTRUCTURE_MODE;
+ break;
+ case eCSR_BSS_TYPE_IBSS:
+ case eCSR_BSS_TYPE_START_IBSS:
+ ret = eSIR_IBSS_MODE;
+ break;
+ case eCSR_BSS_TYPE_WDS_AP:
+ ret = eSIR_BTAMP_AP_MODE;
+ break;
+ case eCSR_BSS_TYPE_WDS_STA:
+ ret = eSIR_BTAMP_STA_MODE;
+ break;
+ case eCSR_BSS_TYPE_INFRA_AP:
+ ret = eSIR_INFRA_AP_MODE;
+ break;
+ case eCSR_BSS_TYPE_ANY:
+ default:
+ ret = eSIR_AUTO_MODE;
+ break;
+ }
+
+ return ret;
+}
+
+/* This function use the parameters to decide the CFG value. */
+/* CSR never sets WNI_CFG_DOT11_MODE_ALL to the CFG */
+/* So PE should not see WNI_CFG_DOT11_MODE_ALL when it gets the CFG value */
+eCsrCfgDot11Mode csr_get_cfg_dot11_mode_from_csr_phy_mode(tCsrRoamProfile *pProfile,
+ eCsrPhyMode phyMode,
+ bool fProprietary)
+{
+ uint32_t cfgDot11Mode = eCSR_CFG_DOT11_MODE_ABG;
+
+ switch (phyMode) {
+ case eCSR_DOT11_MODE_11a:
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A;
+ break;
+ case eCSR_DOT11_MODE_11b:
+ case eCSR_DOT11_MODE_11b_ONLY:
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B;
+ break;
+ case eCSR_DOT11_MODE_11g:
+ case eCSR_DOT11_MODE_11g_ONLY:
+ if (pProfile && (CSR_IS_INFRA_AP(pProfile))
+ && (phyMode == eCSR_DOT11_MODE_11g_ONLY))
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G_ONLY;
+ else
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G;
+ break;
+ case eCSR_DOT11_MODE_11n:
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N;
+ break;
+ case eCSR_DOT11_MODE_11n_ONLY:
+ if (pProfile && CSR_IS_INFRA_AP(pProfile))
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N_ONLY;
+ else
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N;
+ break;
+ case eCSR_DOT11_MODE_abg:
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_ABG;
+ break;
+ case eCSR_DOT11_MODE_AUTO:
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_AUTO;
+ break;
+
+#ifdef WLAN_FEATURE_11AC
+ case eCSR_DOT11_MODE_11ac:
+ if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) {
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC;
+ } else {
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N;
+ }
+ break;
+ case eCSR_DOT11_MODE_11ac_ONLY:
+ if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) {
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC_ONLY;
+ } else {
+ cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N;
+ }
+ break;
+#endif
+ default:
+ /* No need to assign anything here */
+ break;
+ }
+
+ return cfgDot11Mode;
+}
+
+CDF_STATUS csr_get_regulatory_domain_for_country
+ (tpAniSirGlobal pMac,
+ uint8_t *pCountry,
+ v_REGDOMAIN_t *pDomainId, v_CountryInfoSource_t source) {
+ CDF_STATUS status = CDF_STATUS_E_INVAL;
+ CDF_STATUS cdf_status;
+ country_code_t countryCode;
+ v_REGDOMAIN_t domainId;
+
+ if (pCountry) {
+ countryCode[0] = pCountry[0];
+ countryCode[1] = pCountry[1];
+ cdf_status = cds_get_reg_domain_from_country_code(&domainId,
+ countryCode,
+ source);
+
+ if (CDF_IS_STATUS_SUCCESS(cdf_status)) {
+ if (pDomainId) {
+ *pDomainId = domainId;
+ }
+ status = CDF_STATUS_SUCCESS;
+ } else {
+ sms_log(pMac, LOGW,
+ FL
+ (" Couldn't find domain for country code %c%c"),
+ pCountry[0], pCountry[1]);
+ status = CDF_STATUS_E_INVAL;
+ }
+ }
+
+ return status;
+}
+
+/* To check whether a country code matches the one in the IE */
+/* Only check the first two characters, ignoring in/outdoor */
+/* pCountry -- caller allocated buffer contain the country code that is checking against */
+/* the one in pIes. It can be NULL. */
+/* caller must provide pIes, it cannot be NULL */
+/* This function always return true if 11d support is not turned on. */
+bool csr_match_country_code(tpAniSirGlobal pMac, uint8_t *pCountry,
+ tDot11fBeaconIEs *pIes)
+{
+ bool fRet = true;
+
+ do {
+ if (!csr_is11d_supported(pMac)) {
+ break;
+ }
+ if (!pIes) {
+ sms_log(pMac, LOGE, FL(" No IEs"));
+ break;
+ }
+
+ if (pCountry) {
+ uint32_t i;
+
+ if (!pIes->Country.present) {
+ fRet = false;
+ break;
+ }
+ /* Convert the CountryCode characters to upper */
+ for (i = 0; i < WNI_CFG_COUNTRY_CODE_LEN - 1; i++) {
+ pCountry[i] = csr_to_upper(pCountry[i]);
+ }
+ if (!cdf_mem_compare(pIes->Country.country, pCountry,
+ WNI_CFG_COUNTRY_CODE_LEN - 1)) {
+ fRet = false;
+ break;
+ }
+ }
+ } while (0);
+
+ return fRet;
+}
+
+CDF_STATUS csr_get_modify_profile_fields(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamModifyProfileFields *
+ pModifyProfileFields)
+{
+
+ if (!pModifyProfileFields) {
+ return CDF_STATUS_E_FAILURE;
+ }
+
+ cdf_mem_copy(pModifyProfileFields,
+ &pMac->roam.roamSession[sessionId].connectedProfile.
+ modifyProfileFields, sizeof(tCsrRoamModifyProfileFields));
+
+ return CDF_STATUS_SUCCESS;
+}
+
+CDF_STATUS csr_set_modify_profile_fields(tpAniSirGlobal pMac, uint32_t sessionId,
+ tCsrRoamModifyProfileFields *
+ pModifyProfileFields)
+{
+ tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ cdf_mem_copy(&pSession->connectedProfile.modifyProfileFields,
+ pModifyProfileFields, sizeof(tCsrRoamModifyProfileFields));
+
+ return CDF_STATUS_SUCCESS;
+}
+
+
+bool csr_is_set_key_allowed(tpAniSirGlobal pMac, uint32_t sessionId)
+{
+ bool fRet = true;
+ tCsrRoamSession *pSession;
+
+ pSession = CSR_GET_SESSION(pMac, sessionId);
+
+ /*
+ * This condition is not working for infra state. When infra is in
+ * not-connected state the pSession->pCurRoamProfile is NULL, this
+ * function returns true, that is incorrect.
+ * Since SAP requires to set key without any BSS started, it needs
+ * this condition to be met. In other words, this function is useless.
+ * The current work-around is to process setcontext_rsp no matter
+ * what the state is.
+ */
+ sms_log(pMac, LOG2,
+ FL(" is not what it intends to. Must be revisit or removed"));
+ if ((NULL == pSession)
+ || (csr_is_conn_state_disconnected(pMac, sessionId)
+ && (pSession->pCurRoamProfile != NULL)
+ && (!(CSR_IS_INFRA_AP(pSession->pCurRoamProfile))))
+ ) {
+ fRet = false;
+ }
+
+ return fRet;
+}
+
+/* no need to acquire lock for this basic function */
+uint16_t sme_chn_to_freq(uint8_t chanNum)
+{
+ int i;
+
+ for (i = 0; i < NUM_RF_CHANNELS; i++) {
+ if (rf_channels[i].channelNum == chanNum) {
+ return rf_channels[i].targetFreq;
+ }
+ }
+
+ return 0;
+}
+
+/* Disconnect all active sessions by sending disassoc. This is mainly used to disconnect the remaining session when we
+ * transition from concurrent sessions to a single session. The use case is Infra STA and wifi direct multiple sessions are up and
+ * P2P session is removed. The Infra STA session remains and should resume BMPS if BMPS is enabled by default. However, there
+ * are some issues seen with BMPS resume during this transition and this is a workaround which will allow the Infra STA session to
+ * disconnect and auto connect back and enter BMPS this giving the same effect as resuming BMPS
+ */
+
+/* Remove this code once SLM_Sessionization is supported */
+/* BMPS_WORKAROUND_NOT_NEEDED */
+void csr_disconnect_all_active_sessions(tpAniSirGlobal pMac)
+{
+ uint8_t i;
+
+ /* Disconnect all the active sessions */
+ for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
+ if (CSR_IS_SESSION_VALID(pMac, i)
+ && !csr_is_conn_state_disconnected(pMac, i)) {
+ csr_roam_disconnect_internal(pMac, i,
+ eCSR_DISCONNECT_REASON_UNSPECIFIED);
+ }
+ }
+}
+
+#ifdef FEATURE_WLAN_LFR
+bool csr_is_channel_present_in_list(uint8_t *pChannelList,
+ int numChannels, uint8_t channel)
+{
+ int i = 0;
+
+ /* Check for NULL pointer */
+ if (!pChannelList || (numChannels == 0)) {
+ return false;
+ }
+ /* Look for the channel in the list */
+ for (i = 0; (i < numChannels) &&
+ (i < WNI_CFG_VALID_CHANNEL_LIST_LEN); i++) {
+ if (pChannelList[i] == channel)
+ return true;
+ }
+
+ return false;
+}
+
+CDF_STATUS csr_add_to_channel_list_front(uint8_t *pChannelList,
+ int numChannels, uint8_t channel)
+{
+ int i = 0;
+
+ /* Check for NULL pointer */
+ if (!pChannelList)
+ return CDF_STATUS_E_NULL_VALUE;
+
+ /* Make room for the addition. (Start moving from the back.) */
+ for (i = numChannels; i > 0; i--) {
+ pChannelList[i] = pChannelList[i - 1];
+ }
+
+ /* Now add the NEW channel...at the front */
+ pChannelList[0] = channel;
+
+ return CDF_STATUS_SUCCESS;
+}
+#endif
+#ifdef FEATURE_WLAN_DIAG_SUPPORT
+/**
+ * csr_diag_event_report() - send PE diag event
+ * @pmac: pointer to global MAC context.
+ * @event_typev: sub event type for DIAG event.
+ * @status: status of the event
+ * @reasoncode: reasoncode for the given status
+ *
+ * This function is called to send diag event
+ *
+ * Return: NA
+ */
+void csr_diag_event_report(tpAniSirGlobal pmac, uint16_t event_type,
+ uint16_t status, uint16_t reasoncode)
+{
+ WLAN_HOST_DIAG_EVENT_DEF(diag_event, host_event_wlan_pe_payload_type);
+
+ cdf_mem_zero(&diag_event, sizeof(host_event_wlan_pe_payload_type));
+
+ /* diag_event.bssid is already all zeroes */
+ diag_event.sme_state = sme_get_lim_sme_state(pmac);
+ diag_event.mlm_state = sme_get_lim_mlm_state(pmac);
+ diag_event.event_type = event_type;
+ diag_event.status = status;
+ diag_event.reason_code = reasoncode;
+
+ WLAN_HOST_DIAG_EVENT_REPORT(&diag_event, EVENT_WLAN_PE);
+ return;
+}
+#endif