blob: 9074f37cae7c9686a89f5269183d7c4fddd4c472 [file] [log] [blame]
/*
* 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,
&reg_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, &regId,
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, &param);
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,
&param.operationalRateSet, sizeof(pMsg->operational_rateset));
cdf_mem_copy(&pMsg->extended_rateset,
&param.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);
}