blob: 0a26228496d512a516275f7d76950be992166214 [file] [log] [blame]
/*
* Copyright (c) 2011-2016 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/** ------------------------------------------------------------------------- *
------------------------------------------------------------------------- *
\file csr_neighbor_roam.c
Implementation for the simple roaming algorithm for 802.11r Fast
transitions and Legacy roaming for Android platform.
========================================================================== */
#include "wma_types.h"
#include "cds_mq.h"
#include "csr_inside_api.h"
#include "sms_debug.h"
#include "sme_qos_internal.h"
#include "sme_inside.h"
#include "host_diag_core_event.h"
#include "host_diag_core_log.h"
#include "csr_api.h"
#include "sme_api.h"
#include "csr_neighbor_roam.h"
#include "mac_trace.h"
#include "cds_concurrency.h"
#define NEIGHBOR_ROAM_DEBUG sms_log
static void csr_neighbor_roam_reset_channel_info(tpCsrNeighborRoamChannelInfo
rChInfo);
QDF_STATUS csr_roam_copy_connected_profile(tpAniSirGlobal pMac, uint32_t sessionId,
tCsrRoamProfile *pDstProfile);
void csr_neighbor_roam_state_transition(tpAniSirGlobal mac_ctx,
uint8_t newstate, uint8_t session)
{
mac_ctx->roam.neighborRoamInfo[session].prevNeighborRoamState =
mac_ctx->roam.neighborRoamInfo[session].neighborRoamState;
mac_ctx->roam.neighborRoamInfo[session].neighborRoamState = newstate;
QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG,
FL("Sessionid (%d) NeighborRoam transition from %s to %s"),
session, csr_neighbor_roam_state_to_string(
mac_ctx->roam.neighborRoamInfo[session].prevNeighborRoamState),
csr_neighbor_roam_state_to_string(newstate));
}
uint8_t *csr_neighbor_roam_state_to_string(uint8_t state)
{
switch (state) {
CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_CLOSED);
CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_INIT);
CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_CONNECTED);
CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING);
CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING);
CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE);
default:
return "eCSR_NEIGHBOR_ROAM_STATE_UNKNOWN";
}
}
#ifdef FEATURE_WLAN_LFR_METRICS
/**
* csr_neighbor_roam_send_lfr_metric_event() - Send event of LFR metric
* @mac_ctx: Handle returned by mac_open.
* @session_id: Session information
* @bssid: BSSID of attempted AP
* @status: Result of LFR operation
*
* LFR metrics - pre-auth completion metric
* Send the event to supplicant indicating pre-auth result
*
* Return: void
*/
void csr_neighbor_roam_send_lfr_metric_event(
tpAniSirGlobal mac_ctx,
uint8_t session_id,
tSirMacAddr bssid,
eRoamCmdStatus status)
{
tCsrRoamInfo *roam_info;
roam_info = qdf_mem_malloc(sizeof(tCsrRoamInfo));
if (NULL == roam_info) {
sms_log(mac_ctx, LOG1, FL("Memory allocation failed!"));
} else {
qdf_mem_copy((void *)roam_info->bssid,
(void *)bssid, sizeof(*roam_info));
csr_roam_call_callback(mac_ctx, session_id, roam_info, 0,
status, 0);
qdf_mem_free(roam_info);
}
}
#endif
QDF_STATUS
csr_neighbor_roam_update_fast_roaming_enabled(tpAniSirGlobal pMac,
uint8_t sessionId,
const bool fastRoamEnabled)
{
QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
&pMac->roam.neighborRoamInfo[sessionId];
/* set fast roam enable/disable flag */
pMac->roam.configParam.isFastRoamIniFeatureEnabled = fastRoamEnabled;
switch (pNeighborRoamInfo->neighborRoamState) {
case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED:
if (true == fastRoamEnabled) {
csr_roam_offload_scan(pMac, sessionId,
ROAM_SCAN_OFFLOAD_START,
REASON_CONNECT);
} else {
csr_roam_offload_scan(pMac, sessionId,
ROAM_SCAN_OFFLOAD_STOP,
REASON_DISCONNECTED);
}
break;
case eCSR_NEIGHBOR_ROAM_STATE_INIT:
NEIGHBOR_ROAM_DEBUG(pMac, LOG2,
FL
("Currently in INIT state, Nothing to do"));
break;
default:
NEIGHBOR_ROAM_DEBUG(pMac, LOGE,
FL
("Unexpected state %s, returning failure"),
mac_trace_get_neighbour_roam_state
(pNeighborRoamInfo->neighborRoamState));
qdf_status = QDF_STATUS_E_FAILURE;
break;
}
return qdf_status;
}
#ifdef FEATURE_WLAN_ESE
QDF_STATUS csr_neighbor_roam_update_ese_mode_enabled(tpAniSirGlobal pMac,
uint8_t sessionId,
const bool eseMode)
{
QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
&pMac->roam.neighborRoamInfo[sessionId];
switch (pNeighborRoamInfo->neighborRoamState) {
case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED:
if (true == eseMode) {
csr_roam_offload_scan(pMac, sessionId,
ROAM_SCAN_OFFLOAD_START,
REASON_CONNECT);
} else if (false == eseMode) {
csr_roam_offload_scan(pMac, sessionId,
ROAM_SCAN_OFFLOAD_STOP,
REASON_DISCONNECTED);
}
break;
case eCSR_NEIGHBOR_ROAM_STATE_INIT:
NEIGHBOR_ROAM_DEBUG(pMac,
LOG2,
FL
("Currently in INIT state, Nothing to do"));
break;
default:
NEIGHBOR_ROAM_DEBUG(pMac, LOGE,
FL
("Unexpected state %d, returning failure"),
pNeighborRoamInfo->neighborRoamState);
break;
}
return qdf_status;
}
#endif
QDF_STATUS csr_neighbor_roam_set_lookup_rssi_threshold(tpAniSirGlobal pMac,
uint8_t sessionId,
uint8_t
neighborLookupRssiThreshold)
{
tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
&pMac->roam.neighborRoamInfo[sessionId];
QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
switch (pNeighborRoamInfo->neighborRoamState) {
case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED:
NEIGHBOR_ROAM_DEBUG(pMac, LOG2,
FL("Currently in CONNECTED state, "
"sending ROAM_SCAN_OFFLOAD_UPDATE_CFG."));
pNeighborRoamInfo->cfgParams.neighborLookupThreshold =
neighborLookupRssiThreshold;
pNeighborRoamInfo->currentNeighborLookupThreshold =
pNeighborRoamInfo->cfgParams.neighborLookupThreshold;
csr_roam_offload_scan(pMac, sessionId,
ROAM_SCAN_OFFLOAD_UPDATE_CFG,
REASON_LOOKUP_THRESH_CHANGED);
break;
case eCSR_NEIGHBOR_ROAM_STATE_INIT:
NEIGHBOR_ROAM_DEBUG(pMac, LOG2,
FL("Currently in INIT state, "
"just set lookupRssi threshold."));
pNeighborRoamInfo->cfgParams.neighborLookupThreshold =
neighborLookupRssiThreshold;
pNeighborRoamInfo->currentNeighborLookupThreshold =
pNeighborRoamInfo->cfgParams.neighborLookupThreshold;
break;
default:
NEIGHBOR_ROAM_DEBUG(pMac, LOGE,
FL
("Unexpected state %s, returning failure"),
mac_trace_get_neighbour_roam_state
(pNeighborRoamInfo->neighborRoamState));
qdf_status = QDF_STATUS_E_FAILURE;
break;
}
return qdf_status;
}
QDF_STATUS
csr_neighbor_roam_set_opportunistic_scan_threshold_diff(tpAniSirGlobal pMac,
uint8_t sessionId,
uint8_t
nOpportunisticThresholdDiff)
{
QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
&pMac->roam.neighborRoamInfo[sessionId];
switch (pNeighborRoamInfo->neighborRoamState) {
case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED:
NEIGHBOR_ROAM_DEBUG(pMac, LOG2,
FL("Currently in CONNECTED state, "
"sending ROAM_SCAN_OFFLOAD_UPDATE_CFG"));
pNeighborRoamInfo->cfgParams.nOpportunisticThresholdDiff =
nOpportunisticThresholdDiff;
pNeighborRoamInfo->currentOpportunisticThresholdDiff =
nOpportunisticThresholdDiff;
csr_roam_offload_scan(pMac,
sessionId,
ROAM_SCAN_OFFLOAD_UPDATE_CFG,
REASON_OPPORTUNISTIC_THRESH_DIFF_CHANGED);
break;
case eCSR_NEIGHBOR_ROAM_STATE_INIT:
NEIGHBOR_ROAM_DEBUG(pMac, LOG2,
FL("Currently in INIT state, "
"just set opportunistic threshold diff"));
pNeighborRoamInfo->cfgParams.nOpportunisticThresholdDiff =
nOpportunisticThresholdDiff;
pNeighborRoamInfo->currentOpportunisticThresholdDiff =
nOpportunisticThresholdDiff;
break;
default:
NEIGHBOR_ROAM_DEBUG(pMac, LOGE,
FL("Unexpected state %d returning failure"),
pNeighborRoamInfo->neighborRoamState);
qdf_status = QDF_STATUS_E_FAILURE;
break;
}
return qdf_status;
}
QDF_STATUS
csr_neighbor_roam_set_roam_rescan_rssi_diff(tpAniSirGlobal pMac,
uint8_t sessionId,
uint8_t nRoamRescanRssiDiff)
{
QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
&pMac->roam.neighborRoamInfo[sessionId];
switch (pNeighborRoamInfo->neighborRoamState) {
case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED:
NEIGHBOR_ROAM_DEBUG(pMac, LOG2,
FL("Currently in CONNECTED state, "
"sending ROAM_SCAN_OFFLOAD_UPDATE_CFG."));
pNeighborRoamInfo->cfgParams.nRoamRescanRssiDiff =
nRoamRescanRssiDiff;
pNeighborRoamInfo->currentRoamRescanRssiDiff =
nRoamRescanRssiDiff;
csr_roam_offload_scan(pMac, sessionId,
ROAM_SCAN_OFFLOAD_UPDATE_CFG,
REASON_ROAM_RESCAN_RSSI_DIFF_CHANGED);
break;
case eCSR_NEIGHBOR_ROAM_STATE_INIT:
NEIGHBOR_ROAM_DEBUG(pMac, LOG2,
FL("Currently in INIT state, "
"just set rescan rssi diff"));
pNeighborRoamInfo->cfgParams.nRoamRescanRssiDiff =
nRoamRescanRssiDiff;
pNeighborRoamInfo->currentRoamRescanRssiDiff =
nRoamRescanRssiDiff;
break;
default:
NEIGHBOR_ROAM_DEBUG(pMac, LOGE,
FL("Unexpected state %d returning failure"),
pNeighborRoamInfo->neighborRoamState);
qdf_status = QDF_STATUS_E_FAILURE;
break;
}
return qdf_status;
}
QDF_STATUS
csr_neighbor_roam_set_roam_bmiss_first_bcnt(tpAniSirGlobal pMac,
uint8_t sessionId,
uint8_t nRoamBmissFirstBcnt)
{
QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
&pMac->roam.neighborRoamInfo[sessionId];
switch (pNeighborRoamInfo->neighborRoamState) {
case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED:
NEIGHBOR_ROAM_DEBUG(pMac, LOG2,
FL("Currently in CONNECTED state, "
"sending ROAM_SCAN_OFFLOAD_UPDATE_CFG."));
pNeighborRoamInfo->cfgParams.nRoamBmissFirstBcnt =
nRoamBmissFirstBcnt;
pNeighborRoamInfo->currentRoamBmissFirstBcnt =
nRoamBmissFirstBcnt;
csr_roam_offload_scan(pMac,
sessionId,
ROAM_SCAN_OFFLOAD_UPDATE_CFG,
REASON_ROAM_BMISS_FIRST_BCNT_CHANGED);
break;
case eCSR_NEIGHBOR_ROAM_STATE_INIT:
NEIGHBOR_ROAM_DEBUG(pMac,
LOG2, FL
("Currently in INIT state, safe to set roam rescan rssi diff"));
pNeighborRoamInfo->cfgParams.nRoamBmissFirstBcnt =
nRoamBmissFirstBcnt;
pNeighborRoamInfo->currentRoamBmissFirstBcnt =
nRoamBmissFirstBcnt;
break;
default:
NEIGHBOR_ROAM_DEBUG(pMac,
LOGE,
FL("Unexpected state %d returning failure"),
pNeighborRoamInfo->neighborRoamState);
qdf_status = QDF_STATUS_E_FAILURE;
break;
}
return qdf_status;
}
QDF_STATUS
csr_neighbor_roam_set_roam_bmiss_final_bcnt(tpAniSirGlobal pMac,
uint8_t sessionId,
uint8_t nRoamBmissFinalBcnt)
{
QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
&pMac->roam.neighborRoamInfo[sessionId];
switch (pNeighborRoamInfo->neighborRoamState) {
case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED:
NEIGHBOR_ROAM_DEBUG(pMac, LOG2,
FL("Currently in CONNECTED state, "
"sending ROAM_SCAN_OFFLOAD_UPDATE_CFG."));
pNeighborRoamInfo->cfgParams.nRoamBmissFinalBcnt =
nRoamBmissFinalBcnt;
pNeighborRoamInfo->currentRoamBmissFinalBcnt =
nRoamBmissFinalBcnt;
csr_roam_offload_scan(pMac, sessionId,
ROAM_SCAN_OFFLOAD_UPDATE_CFG,
REASON_ROAM_BMISS_FINAL_BCNT_CHANGED);
break;
case eCSR_NEIGHBOR_ROAM_STATE_INIT:
NEIGHBOR_ROAM_DEBUG(pMac, LOG2,
FL("Currently in INIT state, "
"just set roam fianl bmiss count"));
pNeighborRoamInfo->cfgParams.nRoamBmissFinalBcnt =
nRoamBmissFinalBcnt;
pNeighborRoamInfo->currentRoamBmissFinalBcnt =
nRoamBmissFinalBcnt;
break;
default:
NEIGHBOR_ROAM_DEBUG(pMac,
LOGE,
FL("Unexpected state %d returning failure"),
pNeighborRoamInfo->neighborRoamState);
qdf_status = QDF_STATUS_E_FAILURE;
break;
}
return qdf_status;
}
QDF_STATUS
csr_neighbor_roam_set_roam_beacon_rssi_weight(tpAniSirGlobal pMac,
uint8_t sessionId,
uint8_t nRoamBeaconRssiWeight)
{
QDF_STATUS qdf_status = QDF_STATUS_SUCCESS;
tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
&pMac->roam.neighborRoamInfo[sessionId];
switch (pNeighborRoamInfo->neighborRoamState) {
case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED:
NEIGHBOR_ROAM_DEBUG(pMac, LOG2,
FL("Currently in CONNECTED state, "
"sending ROAM_SCAN_OFFLOAD_UPDATE_CFG."));
pNeighborRoamInfo->cfgParams.nRoamBeaconRssiWeight =
nRoamBeaconRssiWeight;
pNeighborRoamInfo->currentRoamBeaconRssiWeight =
nRoamBeaconRssiWeight;
csr_roam_offload_scan(pMac, sessionId,
ROAM_SCAN_OFFLOAD_UPDATE_CFG,
REASON_ROAM_BEACON_RSSI_WEIGHT_CHANGED);
break;
case eCSR_NEIGHBOR_ROAM_STATE_INIT:
NEIGHBOR_ROAM_DEBUG(pMac, LOG2,
FL("Currently in INIT state, "
"just set roam beacon rssi weight"));
pNeighborRoamInfo->cfgParams.nRoamBeaconRssiWeight =
nRoamBeaconRssiWeight;
pNeighborRoamInfo->currentRoamBeaconRssiWeight =
nRoamBeaconRssiWeight;
break;
default:
NEIGHBOR_ROAM_DEBUG(pMac,
LOGE,
FL("Unexpected state %d returning failure"),
pNeighborRoamInfo->neighborRoamState);
qdf_status = QDF_STATUS_E_FAILURE;
break;
}
return qdf_status;
}
/*CleanUP Routines*/
static void csr_neighbor_roam_reset_channel_info(tpCsrNeighborRoamChannelInfo
rChInfo)
{
if ((rChInfo->IAPPNeighborListReceived == false) &&
(rChInfo->currentChannelListInfo.numOfChannels)) {
rChInfo->currentChanIndex =
CSR_NEIGHBOR_ROAM_INVALID_CHANNEL_INDEX;
rChInfo->currentChannelListInfo.numOfChannels = 0;
if (rChInfo->currentChannelListInfo.ChannelList)
qdf_mem_free(rChInfo->currentChannelListInfo.
ChannelList);
rChInfo->currentChannelListInfo.ChannelList = NULL;
} else {
rChInfo->currentChanIndex = 0;
}
}
/**
* csr_neighbor_roam_reset_connected_state_control_info()
*
* @mac_ctx: Pointer to Global MAC structure
* @sessionId : session id
*
* This function will reset the neighbor roam control info data structures.
* This function should be invoked whenever we move to CONNECTED state from
* any state other than INIT state
*
* Return: None
*/
void csr_neighbor_roam_reset_connected_state_control_info(tpAniSirGlobal pMac,
uint8_t sessionId)
{
tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
&pMac->roam.neighborRoamInfo[sessionId];
csr_neighbor_roam_reset_channel_info(&pNeighborRoamInfo->roamChannelInfo);
csr_neighbor_roam_free_roamable_bss_list(pMac,
&pNeighborRoamInfo->roamableAPList);
/* Do not free up the preauth done list here */
pNeighborRoamInfo->FTRoamInfo.currentNeighborRptRetryNum = 0;
pNeighborRoamInfo->FTRoamInfo.neighborRptPending = false;
pNeighborRoamInfo->FTRoamInfo.numPreAuthRetries = 0;
pNeighborRoamInfo->FTRoamInfo.numBssFromNeighborReport = 0;
pNeighborRoamInfo->FTRoamInfo.preauthRspPending = 0;
qdf_mem_zero(pNeighborRoamInfo->FTRoamInfo.neighboReportBssInfo,
sizeof(tCsrNeighborReportBssInfo) *
MAX_BSS_IN_NEIGHBOR_RPT);
pNeighborRoamInfo->uOsRequestedHandoff = 0;
qdf_mem_zero(&pNeighborRoamInfo->handoffReqInfo,
sizeof(tCsrHandoffRequest));
}
void csr_neighbor_roam_reset_report_scan_state_control_info(tpAniSirGlobal pMac,
uint8_t sessionId)
{
tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
&pMac->roam.neighborRoamInfo[sessionId];
qdf_zero_macaddr(&pNeighborRoamInfo->currAPbssid);
#ifdef FEATURE_WLAN_ESE
pNeighborRoamInfo->isESEAssoc = false;
pNeighborRoamInfo->isVOAdmitted = false;
pNeighborRoamInfo->MinQBssLoadRequired = 0;
#endif
/* Purge roamable AP list */
csr_neighbor_roam_free_roamable_bss_list(pMac,
&pNeighborRoamInfo->roamableAPList);
return;
}
/**
* csr_neighbor_roam_reset_init_state_control_info()
*
* @mac_ctx: Pointer to Global MAC structure
* @sessionId : session id
*
* This function will reset the neighbor roam control info data structures.
* This function should be invoked whenever we move to CONNECTED state from
* INIT state
*
* Return: None
*/
void csr_neighbor_roam_reset_init_state_control_info(tpAniSirGlobal pMac,
uint8_t sessionId)
{
csr_neighbor_roam_reset_connected_state_control_info(pMac, sessionId);
/* In addition to the above resets,
we should clear off the curAPBssId/Session ID in the timers */
csr_neighbor_roam_reset_report_scan_state_control_info(pMac, sessionId);
}
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
/**
* csr_neighbor_roam_offload_update_preauth_list()
*
* @mac_ctx: Pointer to Global MAC structure
* @session_id: Session ID
* @roam_sync_ind_ptr: Roam offload sync Ind Info
*
* This function handles the RoamOffloadSynch and adds the
* roamed AP to the preauth done list
*
* Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE otherwise
*/
QDF_STATUS
csr_neighbor_roam_offload_update_preauth_list(tpAniSirGlobal pMac,
roam_offload_synch_ind *roam_sync_ind_ptr, uint8_t session_id)
{
tpCsrNeighborRoamControlInfo neighbor_roam_info_ptr =
&pMac->roam.neighborRoamInfo[session_id];
tpCsrNeighborRoamBSSInfo bss_info_ptr;
uint16_t bss_desc_len;
if (neighbor_roam_info_ptr->neighborRoamState !=
eCSR_NEIGHBOR_ROAM_STATE_CONNECTED) {
NEIGHBOR_ROAM_DEBUG(pMac, LOGW,
FL("LFR3:Roam Offload Synch Ind received in state %d"),
neighbor_roam_info_ptr->neighborRoamState);
return QDF_STATUS_E_FAILURE;
}
bss_info_ptr = qdf_mem_malloc(sizeof(tCsrNeighborRoamBSSInfo));
if (NULL == bss_info_ptr) {
sms_log(pMac, LOGE,
FL("LFR3:Memory allocation for Neighbor Roam BSS Info failed"));
return QDF_STATUS_E_NOMEM;
}
bss_desc_len = roam_sync_ind_ptr->bss_desc_ptr->length +
sizeof(roam_sync_ind_ptr->bss_desc_ptr->length);
bss_info_ptr->pBssDescription = qdf_mem_malloc(bss_desc_len);
if (bss_info_ptr->pBssDescription != NULL) {
qdf_mem_copy(bss_info_ptr->pBssDescription,
roam_sync_ind_ptr->bss_desc_ptr,
bss_desc_len);
} else {
sms_log(pMac, LOGE,
FL("LFR3:Mem alloc for Neighbor Roam BSS Descriptor failed"));
qdf_mem_free(bss_info_ptr);
return QDF_STATUS_E_NOMEM;
}
csr_ll_insert_tail(&neighbor_roam_info_ptr->FTRoamInfo.preAuthDoneList,
&bss_info_ptr->List, LL_ACCESS_LOCK);
csr_neighbor_roam_state_transition(pMac,
eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE, session_id);
neighbor_roam_info_ptr->FTRoamInfo.numPreAuthRetries = 0;
QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG,
"LFR3:Entry added to Auth Done List");
return QDF_STATUS_SUCCESS;
}
#endif
/**
* csr_neighbor_roam_prepare_scan_profile_filter()
*
* @mac_ctx: Pointer to Global MAC structure
* @session_id: Session ID
* @scan_filter: Populated scan filter based on the connected profile
*
* This function creates a scan filter based on the currently
* connected profile. Based on this filter, scan results are obtained
*
* Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE otherwise
*/
QDF_STATUS
csr_neighbor_roam_prepare_scan_profile_filter(tpAniSirGlobal pMac,
tCsrScanResultFilter *pScanFilter,
uint8_t sessionId)
{
tpCsrNeighborRoamControlInfo nbr_roam_info =
&pMac->roam.neighborRoamInfo[sessionId];
tCsrRoamConnectedProfile *pCurProfile =
&pMac->roam.roamSession[sessionId].connectedProfile;
uint8_t i = 0;
struct roam_ext_params *roam_params;
uint8_t num_ch = 0;
QDF_ASSERT(pScanFilter != NULL);
if (pScanFilter == NULL)
return QDF_STATUS_E_FAILURE;
qdf_mem_zero(pScanFilter, sizeof(tCsrScanResultFilter));
roam_params = &pMac->roam.configParam.roam_params;
/* We dont want to set BSSID based Filter */
pScanFilter->BSSIDs.numOfBSSIDs = 0;
pScanFilter->scan_filter_for_roam = 1;
/* only for HDD requested handoff fill in the BSSID in the filter */
if (nbr_roam_info->uOsRequestedHandoff) {
pScanFilter->BSSIDs.numOfBSSIDs = 1;
pScanFilter->BSSIDs.bssid =
qdf_mem_malloc(sizeof(tSirMacAddr) *
pScanFilter->BSSIDs.numOfBSSIDs);
if (NULL == pScanFilter->BSSIDs.bssid) {
sms_log(pMac, LOGE,
FL("Scan Filter BSSID mem alloc failed"));
return QDF_STATUS_E_NOMEM;
}
qdf_mem_zero(pScanFilter->BSSIDs.bssid,
sizeof(tSirMacAddr) *
pScanFilter->BSSIDs.numOfBSSIDs);
/* Populate the BSSID from handoff info received from HDD */
for (i = 0; i < pScanFilter->BSSIDs.numOfBSSIDs; i++) {
qdf_copy_macaddr(&pScanFilter->BSSIDs.bssid[i],
&nbr_roam_info->handoffReqInfo.bssid);
}
}
QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG,
FL("No of Allowed SSID List:%d"),
roam_params->num_ssid_allowed_list);
if (roam_params->num_ssid_allowed_list) {
pScanFilter->SSIDs.numOfSSIDs =
roam_params->num_ssid_allowed_list;
pScanFilter->SSIDs.SSIDList =
qdf_mem_malloc(sizeof(tCsrSSIDInfo) *
pScanFilter->SSIDs.numOfSSIDs);
if (NULL == pScanFilter->SSIDs.SSIDList) {
sms_log(pMac, LOGE,
FL("Scan Filter SSID mem alloc failed"));
return QDF_STATUS_E_NOMEM;
}
for (i = 0; i < roam_params->num_ssid_allowed_list; i++) {
pScanFilter->SSIDs.SSIDList[i].handoffPermitted = 1;
pScanFilter->SSIDs.SSIDList[i].ssidHidden = 0;
qdf_mem_copy((void *)
pScanFilter->SSIDs.SSIDList[i].SSID.ssId,
roam_params->ssid_allowed_list[i].ssId,
roam_params->ssid_allowed_list[i].length);
pScanFilter->SSIDs.SSIDList[i].SSID.length =
roam_params->ssid_allowed_list[i].length;
}
} else {
/* Populate all the information from the connected profile */
pScanFilter->SSIDs.numOfSSIDs = 1;
pScanFilter->SSIDs.SSIDList =
qdf_mem_malloc(sizeof(tCsrSSIDInfo));
if (NULL == pScanFilter->SSIDs.SSIDList) {
sms_log(pMac, LOGE,
FL("Scan Filter SSID mem alloc failed"));
return QDF_STATUS_E_NOMEM;
}
pScanFilter->SSIDs.SSIDList->handoffPermitted = 1;
pScanFilter->SSIDs.SSIDList->ssidHidden = 0;
pScanFilter->SSIDs.SSIDList->SSID.length =
pCurProfile->SSID.length;
qdf_mem_copy((void *)pScanFilter->SSIDs.SSIDList->SSID.ssId,
(void *)pCurProfile->SSID.ssId,
pCurProfile->SSID.length);
NEIGHBOR_ROAM_DEBUG(pMac, LOG1,
FL("Filtering for SSID %.*s,length of SSID = %u"),
pScanFilter->SSIDs.SSIDList->SSID.length,
pScanFilter->SSIDs.SSIDList->SSID.ssId,
pScanFilter->SSIDs.SSIDList->SSID.length);
}
pScanFilter->authType.numEntries = 1;
pScanFilter->authType.authType[0] = pCurProfile->AuthType;
pScanFilter->EncryptionType.numEntries = 1; /* This must be 1 */
pScanFilter->EncryptionType.encryptionType[0] =
pCurProfile->EncryptionType;
pScanFilter->mcEncryptionType.numEntries = 1;
pScanFilter->mcEncryptionType.encryptionType[0] =
pCurProfile->mcEncryptionType;
pScanFilter->BSSType = pCurProfile->BSSType;
num_ch =
nbr_roam_info->roamChannelInfo.currentChannelListInfo.numOfChannels;
if (num_ch) {
/*
* We are intrested only in the scan results on channels we
* scanned
*/
pScanFilter->ChannelInfo.numOfChannels = num_ch;
pScanFilter->ChannelInfo.ChannelList =
qdf_mem_malloc(num_ch * sizeof(uint8_t));
if (NULL == pScanFilter->ChannelInfo.ChannelList) {
sms_log(pMac, LOGE,
FL("Scan Filter Ch list mem alloc failed"));
qdf_mem_free(pScanFilter->SSIDs.SSIDList);
pScanFilter->SSIDs.SSIDList = NULL;
return QDF_STATUS_E_NOMEM;
}
for (i = 0; i < pScanFilter->ChannelInfo.numOfChannels; i++) {
pScanFilter->ChannelInfo.ChannelList[i] =
nbr_roam_info->roamChannelInfo.currentChannelListInfo.
ChannelList[i];
}
} else {
pScanFilter->ChannelInfo.numOfChannels = 0;
pScanFilter->ChannelInfo.ChannelList = NULL;
}
if (nbr_roam_info->is11rAssoc) {
/*
* MDIE should be added as a part of profile. This should be
* added as a part of filter as well
*/
pScanFilter->MDID.mdiePresent = pCurProfile->MDID.mdiePresent;
pScanFilter->MDID.mobilityDomain =
pCurProfile->MDID.mobilityDomain;
}
#ifdef WLAN_FEATURE_11W
pScanFilter->MFPEnabled = pCurProfile->MFPEnabled;
pScanFilter->MFPRequired = pCurProfile->MFPRequired;
pScanFilter->MFPCapable = pCurProfile->MFPCapable;
#endif
return QDF_STATUS_SUCCESS;
}
uint32_t csr_get_current_ap_rssi(tpAniSirGlobal pMac,
tScanResultHandle *pScanResultList,
uint8_t sessionId)
{
tCsrScanResultInfo *pScanResult;
tpCsrNeighborRoamControlInfo nbr_roam_info =
&pMac->roam.neighborRoamInfo[sessionId];
/* We are setting this as default value to make sure we return this value,
when we do not see this AP in the scan result for some reason.However,it is
less likely that we are associated to an AP and do not see it in the scan list */
uint32_t CurrAPRssi = -125;
while (NULL !=
(pScanResult = csr_scan_result_get_next(pMac, *pScanResultList))) {
if (true !=
qdf_mem_cmp(pScanResult->BssDescriptor.bssId,
nbr_roam_info->currAPbssid.bytes,
sizeof(tSirMacAddr))) {
/* We got a match with the currently associated AP.
* Capture the RSSI value and complete the while loop.
* The while loop is completed in order to make the current entry go back to NULL,
* and in the next while loop, it properly starts searching from the head of the list.
* TODO: Can also try setting the current entry directly to NULL as soon as we find the new AP*/
CurrAPRssi =
(int)pScanResult->BssDescriptor.rssi * (-1);
} else {
continue;
}
}
return CurrAPRssi;
}
/**
* csr_neighbor_roam_channels_filter_by_current_band()
*
* @mac_ctx: Pointer to Global MAC structure
* @session_id: Session ID
* @input_ch_list: The input channel list
* @input_num_of_ch: The number of channels in input channel list
* @output_ch_list: The output channel list
* @output_num_of_ch: The number of channels in output channel list
* @merged_output_num_of_ch: The final number of channels in the
* output channel list.
*
* This function is used to filter out the channels based on the
* currently associated AP channel
*
* Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE otherwise
*/
QDF_STATUS csr_neighbor_roam_channels_filter_by_current_band(tpAniSirGlobal pMac,
uint8_t sessionId,
uint8_t *
pInputChannelList,
uint8_t
inputNumOfChannels,
uint8_t *
pOutputChannelList,
uint8_t *
pMergedOutputNumOfChannels)
{
uint8_t i = 0;
uint8_t numChannels = 0;
uint8_t currAPoperationChannel =
pMac->roam.neighborRoamInfo[sessionId].currAPoperationChannel;
/* Check for NULL pointer */
if (!pInputChannelList)
return QDF_STATUS_E_INVAL;
/* Check for NULL pointer */
if (!pOutputChannelList)
return QDF_STATUS_E_INVAL;
if (inputNumOfChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
"%s: Wrong Number of Input Channels %d",
__func__, inputNumOfChannels);
return QDF_STATUS_E_INVAL;
}
for (i = 0; i < inputNumOfChannels; i++) {
if (get_rf_band(currAPoperationChannel) ==
get_rf_band(pInputChannelList[i])) {
pOutputChannelList[numChannels] = pInputChannelList[i];
numChannels++;
}
}
/* Return final number of channels */
*pMergedOutputNumOfChannels = numChannels;
return QDF_STATUS_SUCCESS;
}
/**
* csr_neighbor_roam_channels_filter_by_current_band()
*
* @mac_ctx: Pointer to Global MAC structure
* @session_id: Session ID
* @input_ch_list: The additional channels to merge in to the
* "merged" channels list.
* @input_num_of_ch: The number of additional channels.
* @output_ch_list: The place to put the "merged" channel list.
* @output_num_of_ch: The original number of channels in the
* "merged" channels list.
* @merged_output_num_of_ch: The final number of channels in the
* "merged" channel list.
*
* This function is used to merge two channel list.
* NB: If called with outputNumOfChannels == 0, this routines simply
* copies the input channel list to the output channel list. if number
* of merged channels are more than 100, num of channels set to 100
*
* Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE otherwise
*/
QDF_STATUS csr_neighbor_roam_merge_channel_lists(tpAniSirGlobal pMac,
uint8_t *pInputChannelList,
uint8_t inputNumOfChannels,
uint8_t *pOutputChannelList,
uint8_t outputNumOfChannels,
uint8_t *
pMergedOutputNumOfChannels)
{
uint8_t i = 0;
uint8_t j = 0;
uint8_t numChannels = outputNumOfChannels;
/* Check for NULL pointer */
if (!pInputChannelList)
return QDF_STATUS_E_INVAL;
/* Check for NULL pointer */
if (!pOutputChannelList)
return QDF_STATUS_E_INVAL;
if (inputNumOfChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
"%s: Wrong Number of Input Channels %d",
__func__, inputNumOfChannels);
return QDF_STATUS_E_INVAL;
}
if (outputNumOfChannels >= WNI_CFG_VALID_CHANNEL_LIST_LEN) {
QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
"%s: Wrong Number of Output Channels %d",
__func__, outputNumOfChannels);
return QDF_STATUS_E_INVAL;
}
/* Add the "new" channels in the input list to the end of the output list. */
for (i = 0; i < inputNumOfChannels; i++) {
for (j = 0; j < outputNumOfChannels; j++) {
if (pInputChannelList[i] == pOutputChannelList[j])
break;
}
if (j == outputNumOfChannels) {
if (pInputChannelList[i]) {
QDF_TRACE(QDF_MODULE_ID_SME,
QDF_TRACE_LEVEL_INFO,
"%s: [INFOLOG] Adding extra %d to Neighbor channel list",
__func__, pInputChannelList[i]);
pOutputChannelList[numChannels] =
pInputChannelList[i];
numChannels++;
}
}
if (numChannels >= WNI_CFG_VALID_CHANNEL_LIST_LEN) {
QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO,
"%s: Merge Neighbor channel list reached Max "
"limit %d", __func__, numChannels);
break;
}
}
/* Return final number of channels */
*pMergedOutputNumOfChannels = numChannels;
return QDF_STATUS_SUCCESS;
}
/**
* csr_neighbor_roam_create_chan_list_from_neighbor_report()
*
* @mac_ctx: Pointer to Global MAC structure
* @session_id: Session ID
*
* This function is invoked when neighbor report is received for the
* neighbor request. Based on the channels present in the neighbor report,
* it generates channel list which will be used in REPORT_SCAN state to
* scan for these neighbor APs
*
* Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE otherwise
*/
QDF_STATUS csr_neighbor_roam_create_chan_list_from_neighbor_report(tpAniSirGlobal pMac,
uint8_t sessionId)
{
tpRrmNeighborReportDesc pNeighborBssDesc;
tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
&pMac->roam.neighborRoamInfo[sessionId];
uint8_t numChannels = 0;
uint8_t i = 0;
uint8_t channelList[MAX_BSS_IN_NEIGHBOR_RPT];
uint8_t mergedOutputNumOfChannels = 0;
/* This should always start from 0 whenever we create a channel list out of neighbor AP list */
pNeighborRoamInfo->FTRoamInfo.numBssFromNeighborReport = 0;
pNeighborBssDesc = sme_rrm_get_first_bss_entry_from_neighbor_cache(pMac);
while (pNeighborBssDesc) {
if (pNeighborRoamInfo->FTRoamInfo.numBssFromNeighborReport >=
MAX_BSS_IN_NEIGHBOR_RPT)
break;
/* Update the neighbor BSS Info in the 11r FT Roam Info */
pNeighborRoamInfo->FTRoamInfo.
neighboReportBssInfo[pNeighborRoamInfo->FTRoamInfo.
numBssFromNeighborReport].channelNum =
pNeighborBssDesc->pNeighborBssDescription->channel;
pNeighborRoamInfo->FTRoamInfo.
neighboReportBssInfo[pNeighborRoamInfo->FTRoamInfo.
numBssFromNeighborReport].
neighborScore = (uint8_t) pNeighborBssDesc->roamScore;
qdf_mem_copy(pNeighborRoamInfo->FTRoamInfo.
neighboReportBssInfo[pNeighborRoamInfo->FTRoamInfo.
numBssFromNeighborReport].
neighborBssId,
pNeighborBssDesc->pNeighborBssDescription->bssId,
sizeof(tSirMacAddr));
pNeighborRoamInfo->FTRoamInfo.numBssFromNeighborReport++;
/* Saving the channel list non-redundantly */
for (i = 0; (i < numChannels && i < MAX_BSS_IN_NEIGHBOR_RPT);
i++) {
if (pNeighborBssDesc->pNeighborBssDescription->
channel == channelList[i])
break;
}
if (i == numChannels) {
if (pNeighborBssDesc->pNeighborBssDescription->channel) {
if (CSR_IS_ROAM_INTRA_BAND_ENABLED(pMac)) {
/* Make sure to add only if its the same band */
if (get_rf_band
(pNeighborRoamInfo->
currAPoperationChannel) ==
get_rf_band(pNeighborBssDesc->
pNeighborBssDescription->
channel)) {
QDF_TRACE(QDF_MODULE_ID_SME,
QDF_TRACE_LEVEL_INFO,
"%s: [INFOLOG] Adding %d to Neighbor channel list (Same band)\n",
__func__,
pNeighborBssDesc->
pNeighborBssDescription->
channel);
channelList[numChannels] =
pNeighborBssDesc->
pNeighborBssDescription->
channel;
numChannels++;
}
} else {
QDF_TRACE(QDF_MODULE_ID_SME,
QDF_TRACE_LEVEL_INFO,
"%s: [INFOLOG] Adding %d to Neighbor channel list\n",
__func__,
pNeighborBssDesc->
pNeighborBssDescription->
channel);
channelList[numChannels] =
pNeighborBssDesc->
pNeighborBssDescription->channel;
numChannels++;
}
}
}
pNeighborBssDesc =
sme_rrm_get_next_bss_entry_from_neighbor_cache(pMac,
pNeighborBssDesc);
}
if (pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.
ChannelList) {
qdf_mem_free(pNeighborRoamInfo->roamChannelInfo.
currentChannelListInfo.ChannelList);
}
pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList =
NULL;
pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.
numOfChannels = 0;
/* Store the obtained channel list to the Neighbor Control data structure */
if (numChannels)
pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.
ChannelList =
qdf_mem_malloc((numChannels) * sizeof(uint8_t));
if (NULL ==
pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.
ChannelList) {
sms_log(pMac, LOGE,
FL
("Memory allocation for Channel list failed.. TL event ignored"));
return QDF_STATUS_E_NOMEM;
}
qdf_mem_copy(pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.
ChannelList, channelList, (numChannels) * sizeof(uint8_t));
pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.
numOfChannels = numChannels;
/*
* Create a Union of occupied channel list learnt by the DUT along with the Neighbor
* report Channels. This increases the chances of the DUT to get a candidate AP while
* roaming even if the Neighbor Report is not able to provide sufficient information.
* */
if (pMac->scan.occupiedChannels[sessionId].numChannels) {
csr_neighbor_roam_merge_channel_lists(pMac,
&pMac->scan.
occupiedChannels[sessionId].
channelList[0],
pMac->scan.
occupiedChannels[sessionId].
numChannels,
&pNeighborRoamInfo->
roamChannelInfo.
currentChannelListInfo.
ChannelList[0],
pNeighborRoamInfo->
roamChannelInfo.
currentChannelListInfo.
numOfChannels,
&mergedOutputNumOfChannels);
pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.
numOfChannels = mergedOutputNumOfChannels;
}
/*Indicate the firmware about the update only if any new channels are added.
* Otherwise, the firmware would already be knowing the non-IAPPneighborlist
* channels. There is no need to update.*/
if (numChannels) {
sms_log(pMac, LOG1,
FL("IAPP Neighbor list callback received as expected"
"in state %s."),
mac_trace_get_neighbour_roam_state(pNeighborRoamInfo->
neighborRoamState));
pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived =
true;
if (csr_roam_is_roam_offload_scan_enabled(pMac)) {
csr_roam_offload_scan(pMac, sessionId,
ROAM_SCAN_OFFLOAD_UPDATE_CFG,
REASON_CHANNEL_LIST_CHANGED);
}
}
pNeighborRoamInfo->roamChannelInfo.currentChanIndex = 0;
return QDF_STATUS_SUCCESS;
}
/**
* csr_neighbor_roam_is_ssid_and_security_match() - to match ssid/security
* @pMac: Pointer to mac context
* @pCurProfile: pointer to current roam profile
* @pBssDesc: pointer to bss description
* @pIes: pointer to local ies
*
* This routine will be called to see if SSID and security parameters
* are matching.
*
* Return: bool
*/
bool csr_neighbor_roam_is_ssid_and_security_match(tpAniSirGlobal pMac,
tCsrRoamConnectedProfile *pCurProfile,
tSirBssDescription *pBssDesc, tDot11fBeaconIEs *pIes)
{
tCsrAuthList authType;
tCsrEncryptionList uCEncryptionType;
tCsrEncryptionList mCEncryptionType;
bool fMatch = false;
authType.numEntries = 1;
authType.authType[0] = pCurProfile->AuthType;
uCEncryptionType.numEntries = 1;
uCEncryptionType.encryptionType[0] = pCurProfile->EncryptionType;
mCEncryptionType.numEntries = 1;
mCEncryptionType.encryptionType[0] = pCurProfile->mcEncryptionType;
/* Again, treat missing pIes as a non-match. */
if (!pIes)
return false;
/* Treat a missing SSID as a non-match. */
if (!pIes->SSID.present)
return false;
fMatch = csr_is_ssid_match(pMac,
(void *)pCurProfile->SSID.ssId,
pCurProfile->SSID.length,
pIes->SSID.ssid,
pIes->SSID.num_ssid, true);
if (true == fMatch) {
#ifdef WLAN_FEATURE_11W
/*
* We are sending current connected APs profile setting
* if other AP doesn't have the same PMF setting as currently
* connected AP then we will have some issues in roaming.
*
* Make sure all the APs have same PMF settings to avoid
* any corner cases.
*/
fMatch = csr_is_security_match(pMac, &authType,
&uCEncryptionType, &mCEncryptionType,
&pCurProfile->MFPEnabled,
&pCurProfile->MFPRequired,
&pCurProfile->MFPCapable,
pBssDesc, pIes, NULL, NULL, NULL);
#else
fMatch = csr_is_security_match(pMac, &authType,
&uCEncryptionType,
&mCEncryptionType, NULL,
NULL, NULL, pBssDesc,
pIes, NULL, NULL, NULL);
#endif
return fMatch;
} else {
return fMatch;
}
}
bool csr_neighbor_roam_is_new_connected_profile(tpAniSirGlobal pMac,
uint8_t sessionId)
{
tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
&pMac->roam.neighborRoamInfo[sessionId];
tCsrRoamConnectedProfile *pCurrProfile = NULL;
tCsrRoamConnectedProfile *pPrevProfile = NULL;
tDot11fBeaconIEs *pIes = NULL;
tSirBssDescription *pBssDesc = NULL;
bool fNew = true;
if (!(pMac->roam.roamSession && CSR_IS_SESSION_VALID(pMac, sessionId))) {
return fNew;
}
pCurrProfile = &pMac->roam.roamSession[sessionId].connectedProfile;
if (!pCurrProfile) {
return fNew;
}
pPrevProfile = &pNeighborRoamInfo->prevConnProfile;
if (!pPrevProfile) {
return fNew;
}
pBssDesc = pPrevProfile->pBssDesc;
if (pBssDesc) {
if (QDF_IS_STATUS_SUCCESS(
csr_get_parsed_bss_description_ies(pMac, pBssDesc, &pIes))
&& csr_neighbor_roam_is_ssid_and_security_match(pMac,
pCurrProfile, pBssDesc, pIes)) {
fNew = false;
}
if (pIes) {
qdf_mem_free(pIes);
}
}
if (fNew) {
sms_log(pMac, LOG1,
FL("Prev roam profile did not match current"));
} else {
sms_log(pMac, LOG1, FL("Prev roam profile matches current"));
}
return fNew;
}
bool csr_neighbor_roam_connected_profile_match(tpAniSirGlobal pMac,
uint8_t sessionId,
tCsrScanResult *pResult,
tDot11fBeaconIEs *pIes)
{
tCsrRoamConnectedProfile *pCurProfile = NULL;
tSirBssDescription *pBssDesc = &pResult->Result.BssDescriptor;
if (!(pMac->roam.roamSession && CSR_IS_SESSION_VALID(pMac, sessionId))) {
return false;
}
pCurProfile = &pMac->roam.roamSession[sessionId].connectedProfile;
if (!pCurProfile) {
return false;
}
return csr_neighbor_roam_is_ssid_and_security_match(pMac, pCurProfile,
pBssDesc, pIes);
}
/**
* csr_neighbor_roam_prepare_non_occupied_channel_list() - prepare non-occup CL
* @pMac: The handle returned by mac_open
* @pInputChannelList: The default channels list
* @numOfChannels: The number of channels in the default channels list
* @pOutputChannelList: The place to put the non-occupied channel list
* @pOutputNumOfChannels: Number of channels in the non-occupied channel list
*
* This function is used to prepare a channel list that is derived from
* the list of valid channels and does not include those in the occupied list
*
* Return QDF_STATUS
*/
QDF_STATUS
csr_neighbor_roam_prepare_non_occupied_channel_list(tpAniSirGlobal pMac,
uint8_t sessionId, uint8_t *pInputChannelList,
uint8_t numOfChannels, uint8_t *pOutputChannelList,
uint8_t *pOutputNumOfChannels)
{
uint8_t i = 0;
uint8_t outputNumOfChannels = 0;
uint8_t numOccupiedChannels =
pMac->scan.occupiedChannels[sessionId].numChannels;
uint8_t *pOccupiedChannelList =
pMac->scan.occupiedChannels[sessionId].channelList;
for (i = 0; i < numOfChannels; i++) {
if (csr_is_channel_present_in_list
(pOccupiedChannelList, numOccupiedChannels,
pInputChannelList[i]))
continue;
/*
* DFS channel will be added in the list only when the
* DFS Roaming scan flag is enabled
*/
if (CDS_IS_DFS_CH(pInputChannelList[i])) {
if (CSR_ROAMING_DFS_CHANNEL_DISABLED !=
pMac->roam.configParam.allowDFSChannelRoam) {
pOutputChannelList[outputNumOfChannels++] =
pInputChannelList[i];
}
} else {
pOutputChannelList[outputNumOfChannels++] =
pInputChannelList[i];
}
}
sms_log(pMac, LOG2,
FL("Number of channels in the valid channel list=%d; "
"Number of channels in the non-occupied list list=%d"),
numOfChannels, outputNumOfChannels);
/* Return the number of channels */
*pOutputNumOfChannels = outputNumOfChannels;
return QDF_STATUS_SUCCESS;
}
/**
* csr_roam_reset_roam_params - API to reset the roaming parameters
* @mac_ctx: Pointer to the global MAC structure
*
* The BSSID blacklist should not be cleared since it has to
* be used across connections. These parameters will be cleared
* and sent to firmware with with the roaming STOP command.
*
* Return: VOID
*/
void csr_roam_reset_roam_params(tpAniSirGlobal mac_ctx)
{
struct roam_ext_params *roam_params = NULL;
/*
* clear all the whitelist parameters and remaining
* needs to be retained across connections.
*/
QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG,
FL("Roaming parameters are reset"));
roam_params = &mac_ctx->roam.configParam.roam_params;
roam_params->num_ssid_allowed_list = 0;
qdf_mem_set(&roam_params->ssid_allowed_list, 0,
sizeof(tSirMacSSid) * MAX_SSID_ALLOWED_LIST);
}
/**
* csr_neighbor_roam_indicate_disconnect() - To indicate disconnect
* @pMac: The handle returned by mac_open
* @sessionId: CSR session id that got disconnected
*
* This function is called by CSR as soon as the station disconnects
* from the AP. This function does the necessary cleanup of neighbor roam
* data structures. Neighbor roam state transitions to INIT state whenever
* this function is called except if the current state is REASSOCIATING
*
* Return: QDF_STATUS
*/
QDF_STATUS csr_neighbor_roam_indicate_disconnect(tpAniSirGlobal pMac,
uint8_t sessionId)
{
tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
&pMac->roam.neighborRoamInfo[sessionId];
tCsrRoamConnectedProfile *pPrevProfile =
&pNeighborRoamInfo->prevConnProfile;
tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId);
tCsrRoamSession *roam_session = NULL;
if (NULL == pSession) {
sms_log(pMac, LOGE, FL("pSession is NULL"));
return QDF_STATUS_E_FAILURE;
}
QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO,
FL("Disconn ind on session %d in state %d from bss :"
MAC_ADDRESS_STR), sessionId,
pNeighborRoamInfo->neighborRoamState,
MAC_ADDR_ARRAY(pSession->connectedProfile.bssid.bytes));
/*
* Free the current previous profile and move
* the current profile to prev profile.
*/
csr_roam_free_connect_profile(pPrevProfile);
csr_roam_copy_connect_profile(pMac, sessionId, pPrevProfile);
/*
* clear the roaming parameters that are per connection.
* For a new connection, they have to be programmed again.
*/
if (!csr_neighbor_middle_of_roaming((tHalHandle)pMac, sessionId))
csr_roam_reset_roam_params(pMac);
if (NULL != pSession) {
roam_session = &pMac->roam.roamSession[sessionId];
if (NULL != pSession->pCurRoamProfile && (QDF_STA_MODE !=
roam_session->pCurRoamProfile->csrPersona)) {
sms_log(pMac, LOGE,
FL("Ignore disconn ind rcvd from nonSTA persona"
"sessionId: %d, csrPersonna %d"),
sessionId,
(int)roam_session->pCurRoamProfile->csrPersona);
return QDF_STATUS_SUCCESS;
}
#ifdef FEATURE_WLAN_ESE
if (pSession->connectedProfile.isESEAssoc) {
qdf_mem_copy(&pSession->prevApSSID,
&pSession->connectedProfile.SSID,
sizeof(tSirMacSSid));
qdf_copy_macaddr(&pSession->prevApBssid,
&pSession->connectedProfile.bssid);
pSession->prevOpChannel =
pSession->connectedProfile.operationChannel;
pSession->isPrevApInfoValid = true;
pSession->roamTS1 = qdf_mc_timer_get_system_time();
}
#endif
}
switch (pNeighborRoamInfo->neighborRoamState) {
case eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING:
/*
* Stop scan and neighbor refresh timers.
* These are indeed not required when we'r in reassoc state.
*/
if (!CSR_IS_ROAM_SUBSTATE_DISASSOC_HO(pMac, sessionId)) {
/*
* Disconnect indication during Disassoc Handoff
* sub-state is received when we are trying to
* disconnect with the old AP during roam.
* BUT, if receive a disconnect indication outside of
* Disassoc Handoff sub-state, then it means that
* this is a genuine disconnect and we need to clean up.
* Otherwise, we will be stuck in reassoc state which'll
* in-turn block scans.
*/
csr_neighbor_roam_state_transition(pMac,
eCSR_NEIGHBOR_ROAM_STATE_INIT, sessionId);
pNeighborRoamInfo->roamChannelInfo.
IAPPNeighborListReceived = false;
}
break;
case eCSR_NEIGHBOR_ROAM_STATE_INIT:
csr_neighbor_roam_reset_init_state_control_info(pMac,
sessionId);
break;
case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED:
csr_neighbor_roam_state_transition(pMac,
eCSR_NEIGHBOR_ROAM_STATE_INIT, sessionId);
pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived =
false;
csr_neighbor_roam_reset_connected_state_control_info(pMac,
sessionId);
break;
case eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE:
/* Stop pre-auth to reassoc interval timer */
qdf_mc_timer_stop(&pSession->ftSmeContext.
preAuthReassocIntvlTimer);
case eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING:
csr_neighbor_roam_state_transition(pMac,
eCSR_NEIGHBOR_ROAM_STATE_INIT, sessionId);
pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived =
false;
csr_neighbor_roam_reset_preauth_control_info(pMac, sessionId);
csr_neighbor_roam_reset_report_scan_state_control_info(pMac,
sessionId);
break;
default:
NEIGHBOR_ROAM_DEBUG(pMac, LOGW, FL("Received disconnect event"
"in state %s "),
mac_trace_get_neighbour_roam_state(
pNeighborRoamInfo->neighborRoamState));
NEIGHBOR_ROAM_DEBUG(pMac, LOGW, FL("Transit to INIT state"));
csr_neighbor_roam_state_transition(pMac,
eCSR_NEIGHBOR_ROAM_STATE_INIT, sessionId);
pNeighborRoamInfo->roamChannelInfo.
IAPPNeighborListReceived = false;
break;
}
/*Inform the Firmware to STOP Scanning as the host has a disconnect. */
if (csr_roam_is_sta_mode(pMac, sessionId)) {
csr_roam_offload_scan(pMac, sessionId, ROAM_SCAN_OFFLOAD_STOP,
REASON_DISCONNECTED);
}
return QDF_STATUS_SUCCESS;
}
/**
* csr_neighbor_roam_info_ctx_init() - Initialize neighbor roam struct
* @pMac: mac context
* @session_id: Session Id
*
* This initializes all the necessary data structures related to the
* associated AP.
*
* Return: QDF status
*/
static void csr_neighbor_roam_info_ctx_init(
tpAniSirGlobal pMac,
uint8_t session_id)
{
tpCsrNeighborRoamControlInfo ngbr_roam_info =
&pMac->roam.neighborRoamInfo[session_id];
tCsrRoamSession *session = &pMac->roam.roamSession[session_id];
int init_ft_flag = false;
/*
* Initialize the occupied list ONLY if we are
* transitioning from INIT state to CONNECTED state.
*/
if (eCSR_NEIGHBOR_ROAM_STATE_INIT ==
ngbr_roam_info->neighborRoamState)
csr_init_occupied_channels_list(pMac, session_id);
csr_neighbor_roam_state_transition(pMac,
eCSR_NEIGHBOR_ROAM_STATE_CONNECTED, session_id);
qdf_copy_macaddr(&ngbr_roam_info->currAPbssid,
&session->connectedProfile.bssid);
ngbr_roam_info->currAPoperationChannel =
session->connectedProfile.operationChannel;
ngbr_roam_info->currentNeighborLookupThreshold =
ngbr_roam_info->cfgParams.neighborLookupThreshold;
ngbr_roam_info->currentOpportunisticThresholdDiff =
ngbr_roam_info->cfgParams.nOpportunisticThresholdDiff;
ngbr_roam_info->currentRoamRescanRssiDiff =
ngbr_roam_info->cfgParams.nRoamRescanRssiDiff;
ngbr_roam_info->currentRoamBmissFirstBcnt =
ngbr_roam_info->cfgParams.nRoamBmissFirstBcnt;
ngbr_roam_info->currentRoamBmissFinalBcnt =
ngbr_roam_info->cfgParams.nRoamBmissFinalBcnt;
ngbr_roam_info->currentRoamBeaconRssiWeight =
ngbr_roam_info->cfgParams.nRoamBeaconRssiWeight;
/**
* Now we can clear the preauthDone that
* was saved as we are connected afresh */
csr_neighbor_roam_free_roamable_bss_list(pMac,
&ngbr_roam_info->FTRoamInfo.preAuthDoneList);
/* Based on the auth scheme tell if we are 11r */
if (csr_is_auth_type11r
(session->connectedProfile.AuthType,
session->connectedProfile.MDID.mdiePresent)) {
if (pMac->roam.configParam.isFastTransitionEnabled)
init_ft_flag = true;
ngbr_roam_info->is11rAssoc = true;
} else
ngbr_roam_info->is11rAssoc = false;
NEIGHBOR_ROAM_DEBUG(pMac, LOG2, FL("11rAssoc is = %d"),
ngbr_roam_info->is11rAssoc);
#ifdef FEATURE_WLAN_ESE
/* Based on the auth scheme tell if we are 11r */
if (session->connectedProfile.isESEAssoc) {
if (pMac->roam.configParam.isFastTransitionEnabled)
init_ft_flag = true;
ngbr_roam_info->isESEAssoc = true;
} else
ngbr_roam_info->isESEAssoc = false;
NEIGHBOR_ROAM_DEBUG(pMac, LOG2,
FL("isESEAssoc is = %d ft = %d"),
ngbr_roam_info->isESEAssoc, init_ft_flag);
#endif
/* If "Legacy Fast Roaming" is enabled */
if (csr_roam_is_fast_roam_enabled(pMac, session_id))
init_ft_flag = true;
if (init_ft_flag == false)
return;
/* Initialize all the data structures needed for the 11r FT Preauth */
ngbr_roam_info->FTRoamInfo.currentNeighborRptRetryNum = 0;
csr_neighbor_roam_purge_preauth_failed_list(pMac);
if (!cds_is_multiple_active_sta_sessions() &&
csr_roam_is_roam_offload_scan_enabled(pMac)) {
/*
* If this is not a INFRA type BSS, then do not send the command
* down to firmware.Do not send the START command for
* other session connections.*/
if (!csr_roam_is_sta_mode(pMac, session_id)) {
QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG,
"Wrong Mode %d",
session->connectedProfile.BSSType);
return;
}
ngbr_roam_info->uOsRequestedHandoff = 0;
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
if (session->roam_synch_in_progress) {
if (pMac->roam.pReassocResp != NULL) {
QDF_TRACE(QDF_MODULE_ID_SME,
QDF_TRACE_LEVEL_DEBUG,
"Free Reassoc Rsp");
qdf_mem_free(pMac->roam.pReassocResp);
pMac->roam.pReassocResp = NULL;
}
} else
#endif
csr_roam_offload_scan(pMac, session_id,
ROAM_SCAN_OFFLOAD_START,
REASON_CONNECT);
}
}
/**
* csr_neighbor_roam_indicate_connect()
* @pMac: mac context
* @session_id: Session Id
* @qdf_status: QDF status
*
* This function is called by CSR as soon as the station connects to an AP.
* This initializes all the necessary data structures related to the
* associated AP and transitions the state to CONNECTED state
*
* Return: QDF status
*/
QDF_STATUS csr_neighbor_roam_indicate_connect(
tpAniSirGlobal pMac, uint8_t session_id,
QDF_STATUS qdf_status)
{
tpCsrNeighborRoamControlInfo ngbr_roam_info =
&pMac->roam.neighborRoamInfo[session_id];
tCsrRoamSession *session = &pMac->roam.roamSession[session_id];
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
tCsrRoamInfo roamInfo;
tpSirSetActiveModeSetBncFilterReq msg;
#endif
QDF_STATUS status = QDF_STATUS_SUCCESS;
/* if session id invalid then we need return failure */
if (NULL == ngbr_roam_info || !CSR_IS_SESSION_VALID(pMac, session_id)
|| (NULL == pMac->roam.roamSession[session_id].pCurRoamProfile)) {
return QDF_STATUS_E_FAILURE;
}
sms_log(pMac, LOG2,
FL("Connect ind. received with session id %d in state %s"),
session_id, mac_trace_get_neighbour_roam_state(
ngbr_roam_info->neighborRoamState));
/* Bail out if this is NOT a STA persona */
if (pMac->roam.roamSession[session_id].pCurRoamProfile->csrPersona !=
QDF_STA_MODE) {
sms_log(pMac, LOGE,
FL("Ignoring Connect ind received from a non STA."
"session_id: %d, csrPersonna %d"), session_id,
(int)session->pCurRoamProfile->csrPersona);
return QDF_STATUS_SUCCESS;
}
/* if a concurrent session is running */
if ((false ==
CSR_IS_FASTROAM_IN_CONCURRENCY_INI_FEATURE_ENABLED(pMac)) &&
(csr_is_concurrent_session_running(pMac))) {
sms_log(pMac, LOGE,
FL("Ignoring Connect ind. received in multisession %d"),
csr_is_concurrent_session_running(pMac));
return QDF_STATUS_SUCCESS;
}
#ifdef WLAN_FEATURE_ROAM_OFFLOAD
if (session->roam_synch_in_progress &&
(eSIR_ROAM_AUTH_STATUS_AUTHENTICATED ==
session->roam_synch_data->authStatus)) {
QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG,
"LFR3:csr_neighbor_roam_indicate_connect");
msg = qdf_mem_malloc(sizeof(tSirSetActiveModeSetBncFilterReq));
if (msg == NULL) {
QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
"LFR3:Mem Alloc failed for beacon Filter Req");
return QDF_STATUS_E_NOMEM;
}
msg->messageType = eWNI_SME_SET_BCN_FILTER_REQ;
msg->length = sizeof(uint8_t);
msg->seesionId = session_id;
status = cds_send_mb_message_to_mac(msg);
qdf_copy_macaddr(&roamInfo.peerMac,
&session->connectedProfile.bssid);
roamInfo.roamSynchInProgress =
session->roam_synch_in_progress;
csr_roam_call_callback(pMac, session_id, &roamInfo, 0,
eCSR_ROAM_SET_KEY_COMPLETE,
eCSR_ROAM_RESULT_AUTHENTICATED);
csr_neighbor_roam_reset_init_state_control_info(pMac,
session_id);
csr_neighbor_roam_info_ctx_init(pMac, session_id);
return status;
}
#endif
switch (ngbr_roam_info->neighborRoamState) {
case eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING:
if (QDF_STATUS_SUCCESS != qdf_status) {
/**
* Just transition the state to INIT state.Rest of the
* clean up happens when we get next connect indication
*/
csr_neighbor_roam_state_transition(pMac,
eCSR_NEIGHBOR_ROAM_STATE_INIT, session_id);
ngbr_roam_info->roamChannelInfo.IAPPNeighborListReceived =
false;
break;
}
/* Fall through if the status is SUCCESS */
case eCSR_NEIGHBOR_ROAM_STATE_INIT:
/* Reset all the data structures here */
csr_neighbor_roam_reset_init_state_control_info(pMac,
session_id);
csr_neighbor_roam_info_ctx_init(pMac, session_id);
break;
default:
sms_log(pMac, LOGE,
FL("Connect evt received in invalid state %s Ignoring"),
mac_trace_get_neighbour_roam_state(
ngbr_roam_info->neighborRoamState));
break;
}
return status;
}
/* ---------------------------------------------------------------------------
\fn csr_neighbor_roam_init11r_assoc_info
\brief This function initializes 11r related neighbor roam data structures
\param pMac - The handle returned by mac_open.
\return QDF_STATUS_SUCCESS on success, corresponding error code otherwise
---------------------------------------------------------------------------*/
QDF_STATUS csr_neighbor_roam_init11r_assoc_info(tpAniSirGlobal pMac)
{
QDF_STATUS status;
uint8_t i;
tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL;
tpCsr11rAssocNeighborInfo pFTRoamInfo = NULL;
for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) {
pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[i];
pFTRoamInfo = &pNeighborRoamInfo->FTRoamInfo;
pNeighborRoamInfo->is11rAssoc = false;
pNeighborRoamInfo->cfgParams.maxNeighborRetries =
pMac->roam.configParam.neighborRoamConfig.
nMaxNeighborRetries;
pFTRoamInfo->neighborReportTimeout =
CSR_NEIGHBOR_ROAM_REPORT_QUERY_TIMEOUT;
pFTRoamInfo->PEPreauthRespTimeout =
CSR_NEIGHBOR_ROAM_PREAUTH_RSP_WAIT_MULTIPLIER *
pNeighborRoamInfo->cfgParams.neighborScanPeriod;
pFTRoamInfo->neighborRptPending = false;
pFTRoamInfo->preauthRspPending = false;
pFTRoamInfo->currentNeighborRptRetryNum = 0;
pFTRoamInfo->numBssFromNeighborReport = 0;
qdf_mem_zero(pFTRoamInfo->neighboReportBssInfo,
sizeof(tCsrNeighborReportBssInfo) *
MAX_BSS_IN_NEIGHBOR_RPT);
status = csr_ll_open(pMac->hHdd, &pFTRoamInfo->preAuthDoneList);
if (QDF_STATUS_SUCCESS != status) {
sms_log(pMac, LOGE,
FL("LL Open of preauth done AP List failed"));
return QDF_STATUS_E_RESOURCES;
}
}
return status;
}
/* ---------------------------------------------------------------------------
\fn csr_neighbor_roam_init
\brief This function initializes neighbor roam data structures
\param pMac - The handle returned by mac_open.
\return QDF_STATUS_SUCCESS on success, corresponding error code otherwise
---------------------------------------------------------------------------*/
QDF_STATUS csr_neighbor_roam_init(tpAniSirGlobal pMac, uint8_t sessionId)
{
QDF_STATUS status;
tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
&pMac->roam.neighborRoamInfo[sessionId];
pNeighborRoamInfo->neighborRoamState = eCSR_NEIGHBOR_ROAM_STATE_CLOSED;
pNeighborRoamInfo->prevNeighborRoamState =
eCSR_NEIGHBOR_ROAM_STATE_CLOSED;
pNeighborRoamInfo->cfgParams.maxChannelScanTime =
pMac->roam.configParam.neighborRoamConfig.nNeighborScanMaxChanTime;
pNeighborRoamInfo->cfgParams.minChannelScanTime =
pMac->roam.configParam.neighborRoamConfig.nNeighborScanMinChanTime;
pNeighborRoamInfo->cfgParams.maxNeighborRetries = 0;
pNeighborRoamInfo->cfgParams.neighborLookupThreshold =
pMac->roam.configParam.neighborRoamConfig.
nNeighborLookupRssiThreshold;
pNeighborRoamInfo->cfgParams.delay_before_vdev_stop =
pMac->roam.configParam.neighborRoamConfig.
delay_before_vdev_stop;
pNeighborRoamInfo->cfgParams.nOpportunisticThresholdDiff =
pMac->roam.configParam.neighborRoamConfig.
nOpportunisticThresholdDiff;
pNeighborRoamInfo->cfgParams.nRoamRescanRssiDiff =
pMac->roam.configParam.neighborRoamConfig.nRoamRescanRssiDiff;
pNeighborRoamInfo->cfgParams.nRoamBmissFirstBcnt =
pMac->roam.configParam.neighborRoamConfig.nRoamBmissFirstBcnt;
pNeighborRoamInfo->cfgParams.nRoamBmissFinalBcnt =
pMac->roam.configParam.neighborRoamConfig.nRoamBmissFinalBcnt;
pNeighborRoamInfo->cfgParams.nRoamBeaconRssiWeight =
pMac->roam.configParam.neighborRoamConfig.nRoamBeaconRssiWeight;
pNeighborRoamInfo->cfgParams.neighborScanPeriod =
pMac->roam.configParam.neighborRoamConfig.nNeighborScanTimerPeriod;
pNeighborRoamInfo->cfgParams.neighborResultsRefreshPeriod =
pMac->roam.configParam.neighborRoamConfig.
nNeighborResultsRefreshPeriod;
pNeighborRoamInfo->cfgParams.emptyScanRefreshPeriod =
pMac->roam.configParam.neighborRoamConfig.nEmptyScanRefreshPeriod;
pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels =
pMac->roam.configParam.neighborRoamConfig.neighborScanChanList.
numChannels;
if (pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels != 0) {
pNeighborRoamInfo->cfgParams.channelInfo.ChannelList =
qdf_mem_malloc(pMac->roam.configParam.neighborRoamConfig.
neighborScanChanList.numChannels);
if (NULL ==
pNeighborRoamInfo->cfgParams.channelInfo.ChannelList) {
sms_log(pMac, LOGE,
FL("Memory Allocation for CFG Channel List failed"));
return QDF_STATUS_E_NOMEM;
}
} else {
pNeighborRoamInfo->cfgParams.channelInfo.ChannelList = NULL;
sms_log(pMac, LOGE,
FL("invalid neighbor roam channel list: %u"),
pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels);
}
/* Update the roam global structure from CFG */
qdf_mem_copy(pNeighborRoamInfo->cfgParams.channelInfo.ChannelList,
pMac->roam.configParam.neighborRoamConfig.
neighborScanChanList.channelList,
pMac->roam.configParam.neighborRoamConfig.
neighborScanChanList.numChannels);
pNeighborRoamInfo->cfgParams.hi_rssi_scan_max_count =
pMac->roam.configParam.neighborRoamConfig.
nhi_rssi_scan_max_count;
pNeighborRoamInfo->cfgParams.hi_rssi_scan_rssi_delta =
pMac->roam.configParam.neighborRoamConfig.
nhi_rssi_scan_rssi_delta;
pNeighborRoamInfo->cfgParams.hi_rssi_scan_delay =
pMac->roam.configParam.neighborRoamConfig.
nhi_rssi_scan_delay;
pNeighborRoamInfo->cfgParams.hi_rssi_scan_rssi_ub =
pMac->roam.configParam.neighborRoamConfig.
nhi_rssi_scan_rssi_ub;
qdf_zero_macaddr(&pNeighborRoamInfo->currAPbssid);
pNeighborRoamInfo->currentNeighborLookupThreshold =
pNeighborRoamInfo->cfgParams.neighborLookupThreshold;
pNeighborRoamInfo->currentOpportunisticThresholdDiff =
pNeighborRoamInfo->cfgParams.nOpportunisticThresholdDiff;
pNeighborRoamInfo->currentRoamRescanRssiDiff =
pNeighborRoamInfo->cfgParams.nRoamRescanRssiDiff;
pNeighborRoamInfo->currentRoamBmissFirstBcnt =
pNeighborRoamInfo->cfgParams.nRoamBmissFirstBcnt;
pNeighborRoamInfo->currentRoamBmissFinalBcnt =
pNeighborRoamInfo->cfgParams.nRoamBmissFinalBcnt;
pNeighborRoamInfo->currentRoamBeaconRssiWeight =
pNeighborRoamInfo->cfgParams.nRoamBeaconRssiWeight;
qdf_mem_set(&pNeighborRoamInfo->prevConnProfile,
sizeof(tCsrRoamConnectedProfile), 0);
status = csr_ll_open(pMac->hHdd, &pNeighborRoamInfo->roamableAPList);
if (QDF_STATUS_SUCCESS != status) {
sms_log(pMac, LOGE, FL("LL Open of roam able AP List failed"));
qdf_mem_free(pNeighborRoamInfo->cfgParams.channelInfo.
ChannelList);
pNeighborRoamInfo->cfgParams.channelInfo.ChannelList = NULL;
return QDF_STATUS_E_RESOURCES;
}
pNeighborRoamInfo->roamChannelInfo.currentChanIndex =
CSR_NEIGHBOR_ROAM_INVALID_CHANNEL_INDEX;
pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.
numOfChannels = 0;
pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList =
NULL;
pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived = false;
status = csr_neighbor_roam_init11r_assoc_info(pMac);
if (QDF_STATUS_SUCCESS != status) {
sms_log(pMac, LOGE, FL("LL Open of roam able AP List failed"));
qdf_mem_free(pNeighborRoamInfo->cfgParams.channelInfo.
ChannelList);
pNeighborRoamInfo->cfgParams.channelInfo.ChannelList = NULL;
csr_ll_close(&pNeighborRoamInfo->roamableAPList);
return QDF_STATUS_E_RESOURCES;
}
csr_neighbor_roam_state_transition(pMac,
eCSR_NEIGHBOR_ROAM_STATE_INIT, sessionId);
pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived = false;
/* Set the Last Sent Cmd as RSO_STOP */
pNeighborRoamInfo->last_sent_cmd = ROAM_SCAN_OFFLOAD_STOP;
return QDF_STATUS_SUCCESS;
}
/* ---------------------------------------------------------------------------
\fn csr_neighbor_roam_close
\brief This function closes/frees all the neighbor roam data structures
\param pMac - The handle returned by mac_open.
\param sessionId - Session identifier
\return VOID
---------------------------------------------------------------------------*/
void csr_neighbor_roam_close(tpAniSirGlobal pMac, uint8_t sessionId)
{
tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
&pMac->roam.neighborRoamInfo[sessionId];
if (eCSR_NEIGHBOR_ROAM_STATE_CLOSED ==
pNeighborRoamInfo->neighborRoamState) {
sms_log(pMac, LOGW,
FL("Neighbor Roam Algorithm Already Closed"));
return;
}
if (pNeighborRoamInfo->cfgParams.channelInfo.ChannelList)
qdf_mem_free(pNeighborRoamInfo->cfgParams.channelInfo.
ChannelList);
pNeighborRoamInfo->cfgParams.channelInfo.ChannelList = NULL;
/* Should free up the nodes in the list before closing the double Linked list */
csr_neighbor_roam_free_roamable_bss_list(pMac,
&pNeighborRoamInfo->roamableAPList);
csr_ll_close(&pNeighborRoamInfo->roamableAPList);
if (pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.
ChannelList) {
qdf_mem_free(pNeighborRoamInfo->roamChannelInfo.
currentChannelListInfo.ChannelList);
}
pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList =
NULL;
pNeighborRoamInfo->roamChannelInfo.currentChanIndex =
CSR_NEIGHBOR_ROAM_INVALID_CHANNEL_INDEX;
pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.
numOfChannels = 0;
pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived = false;
/* Free the profile.. */
csr_release_profile(pMac, &pNeighborRoamInfo->csrNeighborRoamProfile);
csr_roam_free_connect_profile(&pNeighborRoamInfo->prevConnProfile);
pNeighborRoamInfo->FTRoamInfo.currentNeighborRptRetryNum = 0;
pNeighborRoamInfo->FTRoamInfo.numBssFromNeighborReport = 0;
qdf_mem_zero(pNeighborRoamInfo->FTRoamInfo.neighboReportBssInfo,
sizeof(tCsrNeighborReportBssInfo) *
MAX_BSS_IN_NEIGHBOR_RPT);
csr_neighbor_roam_free_roamable_bss_list(pMac,
&pNeighborRoamInfo->FTRoamInfo.
preAuthDoneList);
csr_ll_close(&pNeighborRoamInfo->FTRoamInfo.preAuthDoneList);
csr_neighbor_roam_state_transition(pMac,
eCSR_NEIGHBOR_ROAM_STATE_CLOSED, sessionId);
return;
}
/**
* csr_neighbor_roam_is11r_assoc() - Check if association type is 11R
* @mac_ctx: MAC Global context
* @session_id: Session ID
*
* Return: true if 11r Association, false otherwise.
*/
bool csr_neighbor_roam_is11r_assoc(tpAniSirGlobal mac_ctx, uint8_t session_id)
{
return mac_ctx->roam.neighborRoamInfo[session_id].is11rAssoc;
}
/* ---------------------------------------------------------------------------
\brief This function returns true if STA is in the middle of roaming states
\param halHandle - The handle from HDD context.
\param sessionId - Session identifier
\return bool
---------------------------------------------------------------------------*/
bool csr_neighbor_middle_of_roaming(tpAniSirGlobal pMac, uint8_t sessionId)
{
tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
&pMac->roam.neighborRoamInfo[sessionId];
bool val = (eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING ==
pNeighborRoamInfo->neighborRoamState) ||
(eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING ==
pNeighborRoamInfo->neighborRoamState) ||
(eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE ==
pNeighborRoamInfo->neighborRoamState);
return val;
}
/**
* csr_neighbor_roam_process_handoff_req - Processes handoff request
*
* @mac_ctx Pointer to mac context
* @session_id SME session id
*
* This function is called start with the handoff process. First do a
* SSID scan for the BSSID provided.
*
* Return: status
*/
QDF_STATUS csr_neighbor_roam_process_handoff_req(
tpAniSirGlobal mac_ctx,
uint8_t session_id)
{
tpCsrNeighborRoamControlInfo roam_ctrl_info =
&mac_ctx->roam.neighborRoamInfo[session_id];
QDF_STATUS status = QDF_STATUS_SUCCESS;
uint32_t roam_id;
tCsrRoamProfile *profile = NULL;
tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id);
uint8_t i = 0;
if (NULL == session) {
sms_log(mac_ctx, LOGE, FL("session is NULL "));
return QDF_STATUS_E_FAILURE;
}
roam_id = GET_NEXT_ROAM_ID(&mac_ctx->roam);
profile = qdf_mem_malloc(sizeof(tCsrRoamProfile));
if (NULL == profile) {
sms_log(mac_ctx, LOGE, FL("Memory alloc failed"));
return QDF_STATUS_E_NOMEM;
}
qdf_mem_set(profile, sizeof(tCsrRoamProfile), 0);
status =
csr_roam_copy_profile(mac_ctx, profile,
session->pCurRoamProfile);
if (!QDF_IS_STATUS_SUCCESS(status)) {
sms_log(mac_ctx, LOGE, FL("Profile copy failed"));
goto end;
}
/* Add the BSSID & Channel */
profile->BSSIDs.numOfBSSIDs = 1;
if (NULL == profile->BSSIDs.bssid) {
profile->BSSIDs.bssid =
qdf_mem_malloc(sizeof(tSirMacAddr) *
profile->BSSIDs.numOfBSSIDs);
if (NULL == profile->BSSIDs.bssid) {
sms_log(mac_ctx, LOGE, FL("mem alloc failed for BSSID"));
status = QDF_STATUS_E_NOMEM;
goto end;
}
}
qdf_mem_zero(profile->BSSIDs.bssid,
sizeof(tSirMacAddr) *
profile->BSSIDs.numOfBSSIDs);
/* Populate the BSSID from handoff info received from HDD */
for (i = 0; i < profile->BSSIDs.numOfBSSIDs; i++) {
qdf_copy_macaddr(&profile->BSSIDs.bssid[i],
&roam_ctrl_info->handoffReqInfo.bssid);
}
profile->ChannelInfo.numOfChannels = 1;
if (NULL == profile->ChannelInfo.ChannelList) {
profile->ChannelInfo.ChannelList =
qdf_mem_malloc(sizeof(*profile->
ChannelInfo.ChannelList) *
profile->ChannelInfo.numOfChannels);
if (NULL == profile->ChannelInfo.ChannelList) {
sms_log(mac_ctx, LOGE,
FL("mem alloc failed for ChannelList"));
status = QDF_STATUS_E_NOMEM;
goto end;
}
}
profile->ChannelInfo.ChannelList[0] =
roam_ctrl_info->handoffReqInfo.channel;
/* do a SSID scan */
status =
csr_scan_for_ssid(mac_ctx, session_id, profile, roam_id, false);
if (!QDF_IS_STATUS_SUCCESS(status)) {
sms_log(mac_ctx, LOGE, FL("SSID scan failed"));
}
end:
if (NULL != profile) {
csr_release_profile(mac_ctx, profile);
qdf_mem_free(profile);
}
return status;
}
/* ---------------------------------------------------------------------------
\fn csr_neighbor_roam_sssid_scan_done
\brief This function is called once SSID scan is done. If SSID scan failed
to find our candidate add an entry to csr scan cache ourself before starting
the handoff process
\param pMac - The handle returned by mac_open.
\return QDF_STATUS_SUCCESS on success, corresponding error code otherwise
---------------------------------------------------------------------------*/
QDF_STATUS csr_neighbor_roam_sssid_scan_done(tpAniSirGlobal pMac,
uint8_t sessionId, QDF_STATUS status)
{
tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
&pMac->roam.neighborRoamInfo[sessionId];
QDF_STATUS hstatus;
sms_log(pMac, LOGE, FL("called "));
/* we must be in connected state, if not ignore it */
if (eCSR_NEIGHBOR_ROAM_STATE_CONNECTED !=
pNeighborRoamInfo->neighborRoamState) {
sms_log(pMac, LOGE,
FL("Received in not CONNECTED state. Ignore it"));
return QDF_STATUS_E_FAILURE;
}
/* if SSID scan failed to find our candidate add an entry to csr scan cache ourself */
if (!QDF_IS_STATUS_SUCCESS(status)) {
sms_log(pMac, LOGE, FL("Add an entry to csr scan cache"));
hstatus = csr_scan_create_entry_in_scan_cache(pMac, sessionId,
pNeighborRoamInfo->
handoffReqInfo.bssid,
pNeighborRoamInfo->
handoffReqInfo.channel);
if (QDF_STATUS_SUCCESS != hstatus) {
sms_log(pMac, LOGE,
FL
("csr_scan_create_entry_in_scan_cache failed with status %d"),
hstatus);
return QDF_STATUS_E_FAILURE;
}
}
/* Now we have completed scanning for the candidate provided by HDD. Let move on to HO */
hstatus = csr_neighbor_roam_process_scan_complete(pMac, sessionId);
if (QDF_STATUS_SUCCESS != hstatus) {
sms_log(pMac, LOGE,
FL
("Neighbor scan process complete failed with status %d"),
hstatus);
return QDF_STATUS_E_FAILURE;
}
return QDF_STATUS_SUCCESS;
}
/**
* csr_neighbor_roam_handoff_req_hdlr - Processes handoff request
* @mac_ctx Pointer to mac context
* @msg message sent to HDD
*
* This function is called by CSR as soon as it gets a handoff request
* to SME via MC thread
*
* Return: status
*/
QDF_STATUS csr_neighbor_roam_handoff_req_hdlr(
tpAniSirGlobal mac_ctx, void *msg)
{
tAniHandoffReq *handoff_req = (tAniHandoffReq *) msg;
uint32_t session_id = handoff_req->sessionId;
tpCsrNeighborRoamControlInfo roam_ctrl_info =
&mac_ctx->roam.neighborRoamInfo[session_id];
QDF_STATUS status = QDF_STATUS_SUCCESS;
/* we must be in connected state, if not ignore it */
if (eCSR_NEIGHBOR_ROAM_STATE_CONNECTED !=
roam_ctrl_info->neighborRoamState) {
sms_log(mac_ctx, LOGE,
FL("Received in not CONNECTED state. Ignore it"));
return QDF_STATUS_E_FAILURE;
}
/* save the handoff info came from HDD as part of the reassoc req */
handoff_req = (tAniHandoffReq *) msg;
if (NULL == handoff_req) {
sms_log(mac_ctx, LOGE, FL("Received msg is NULL"));
return QDF_STATUS_E_FAILURE;
}
/* sanity check */
if (true != qdf_mem_cmp(handoff_req->bssid,
roam_ctrl_info->currAPbssid.bytes,
sizeof(tSirMacAddr))) {
sms_log(mac_ctx, LOGE,
FL
("Received req has same BSSID as current AP!!"));
return QDF_STATUS_E_FAILURE;
}
roam_ctrl_info->handoffReqInfo.channel =
handoff_req->channel;
roam_ctrl_info->handoffReqInfo.src =
handoff_req->handoff_src;
qdf_mem_copy(&roam_ctrl_info->handoffReqInfo.bssid.bytes,
&handoff_req->bssid, QDF_MAC_ADDR_SIZE);
roam_ctrl_info->uOsRequestedHandoff = 1;
status = csr_roam_offload_scan(mac_ctx, session_id,
ROAM_SCAN_OFFLOAD_STOP,
REASON_OS_REQUESTED_ROAMING_NOW);
if (QDF_STATUS_SUCCESS != status) {
sms_log(mac_ctx, LOGE,
FL("csr_roam_offload_scan failed"));
roam_ctrl_info->uOsRequestedHandoff = 0;
}
return status;
}
/**
* csr_neighbor_roam_proceed_with_handoff_req()
*
* @mac_ctx: Pointer to Global MAC structure
* @session_id: Session ID
*
* This function is called by CSR as soon as it gets rsp back for
* ROAM_SCAN_OFFLOAD_STOP with reason REASON_OS_REQUESTED_ROAMING_NOW
*
* Return: QDF_STATUS_SUCCESS on success, corresponding error code otherwise
*/
QDF_STATUS csr_neighbor_roam_proceed_with_handoff_req(tpAniSirGlobal pMac,
uint8_t sessionId)
{
tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
&pMac->roam.neighborRoamInfo[sessionId];
QDF_STATUS status = QDF_STATUS_SUCCESS;
/* we must be in connected state, if not ignore it */
if ((eCSR_NEIGHBOR_ROAM_STATE_CONNECTED !=
pNeighborRoamInfo->neighborRoamState)
|| (!pNeighborRoamInfo->uOsRequestedHandoff)) {
sms_log(pMac, LOGE,
FL
("Received in not CONNECTED state or uOsRequestedHandoff is not set. Ignore it"));
status = QDF_STATUS_E_FAILURE;
} else {
/* Let's go ahead with handoff */
status = csr_neighbor_roam_process_handoff_req(pMac, sessionId);
}
if (!QDF_IS_STATUS_SUCCESS(status)) {
pNeighborRoamInfo->uOsRequestedHandoff = 0;
}
return status;
}
/* ---------------------------------------------------------------------------
\fn csr_neighbor_roam_start_lfr_scan
\brief This function is called if HDD requested handoff failed for some
reason. start the LFR logic at that point.By the time, this function is
called, a STOP command has already been issued.
\param pMac - The handle returned by mac_open.
\return QDF_STATUS_SUCCESS on success, corresponding error code otherwise
---------------------------------------------------------------------------*/
QDF_STATUS csr_neighbor_roam_start_lfr_scan(tpAniSirGlobal pMac, uint8_t sessionId)
{
tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
&pMac->roam.neighborRoamInfo[sessionId];
pNeighborRoamInfo->uOsRequestedHandoff = 0;
/* There is no candidate or We are not roaming Now.
* Inform the FW to restart Roam Offload Scan */
csr_roam_offload_scan(pMac, sessionId, ROAM_SCAN_OFFLOAD_START,
REASON_NO_CAND_FOUND_OR_NOT_ROAMING_NOW);
return QDF_STATUS_SUCCESS;
}