blob: a8aa27a39a1c43d50898f93f11386cf4d0f2dc12 [file] [log] [blame]
/*
* Copyright (c) 2011-2014, 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 sme_Rrm.c
\brief implementation for SME RRM APIs
========================================================================*/
/* $Header$ */
#if defined WLAN_FEATURE_VOWIFI
/*--------------------------------------------------------------------------
Include Files
------------------------------------------------------------------------*/
#include "aniGlobal.h"
#include "smeInside.h"
#include "sme_Api.h"
#include "smsDebug.h"
#include "cfgApi.h"
#ifdef FEATURE_WLAN_DIAG_SUPPORT
#include "vos_diag_core_event.h"
#include "vos_diag_core_log.h"
#endif /* FEATURE_WLAN_DIAG_SUPPORT */
#include "csrInsideApi.h"
#include "rrmGlobal.h"
#if defined(FEATURE_WLAN_ESE) && !defined(FEATURE_WLAN_ESE_UPLOAD)
#include "csrEse.h"
#endif
/* Roam score for a neighbor AP will be calculated based on the below definitions.
The calculated roam score will be used to select the roam able
candidate from neighbor AP list */
#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_REACHABILITY 0 /* When we support 11r over the DS, this should have a non-zero value */
#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_SECURITY 10
#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_KEY_SCOPE 20
#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_SPECTRUM_MGMT 0 /* Not used */
#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_QOS 5
#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_APSD 3
#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_RRM 8
#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_DELAYED_BA 0 /* We dont support delayed BA */
#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_IMMEDIATE_BA 3
#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_MOBILITY_DOMAIN 30
#ifdef FEATURE_WLAN_ESE
#define RRM_ROAM_SCORE_NEIGHBOR_IAPP_LIST 30
#endif
v_TIME_t RRM_scan_timer;
/**---------------------------------------------------------------------------
\brief rrmLLPurgeNeighborCache() -
This function purges all the entries in the neighbor cache and frees up all the internal nodes
\param - pMac - Pointer to the Hal Handle.
- pList - Pointer the List that should be purged.
\return - void
--------------------------------------------------------------------------*/
static void rrmLLPurgeNeighborCache(tpAniSirGlobal pMac, tDblLinkList *pList)
{
tListElem *pEntry;
tRrmNeighborReportDesc *pNeighborReportDesc;
csrLLLock(pList);
while((pEntry = csrLLRemoveHead(pList, LL_ACCESS_NOLOCK)) != NULL)
{
pNeighborReportDesc = GET_BASE_ADDR( pEntry, tRrmNeighborReportDesc, List );
vos_mem_free(pNeighborReportDesc->pNeighborBssDescription);
vos_mem_free(pNeighborReportDesc);
}
csrLLUnlock(pList);
return;
}
/**---------------------------------------------------------------------------
\brief rrmIndicateNeighborReportResult() -
This function calls the callback register by the caller while requesting for
neighbor report. This function gets invoked if a neighbor report is received from an AP
or neighbor response wait timer expires.
\param - pMac - Pointer to the Hal Handle.
- vosStatus - VOS_STATUS_SUCCESS/VOS_STATUS_FAILURE based on whether a valid report is
received or neighbor timer expired
\return - void
--------------------------------------------------------------------------*/
void rrmIndicateNeighborReportResult(tpAniSirGlobal pMac, VOS_STATUS vosStatus)
{
NeighborReportRspCallback callback;
void *callbackContext;
/* Reset the neighbor response pending status */
pMac->rrm.rrmSmeContext.neighborReqControlInfo.isNeighborRspPending = eANI_BOOLEAN_FALSE;
/* Stop the timer if it is already running. The timer should be running only in the SUCCESS case. */
if (VOS_TIMER_STATE_RUNNING == vos_timer_getCurrentState(&pMac->rrm.rrmSmeContext.neighborReqControlInfo.neighborRspWaitTimer))
{
smsLog( pMac, LOG1, FL("No entry in neighbor report cache"));
vos_timer_stop(&pMac->rrm.rrmSmeContext.neighborReqControlInfo.neighborRspWaitTimer);
}
callback = pMac->rrm.rrmSmeContext.neighborReqControlInfo.neighborRspCallbackInfo.neighborRspCallback;
callbackContext = pMac->rrm.rrmSmeContext.neighborReqControlInfo.neighborRspCallbackInfo.neighborRspCallbackContext;
/* Reset the callback and the callback context before calling the callback. It is very likely that there may be a registration in
callback itself. */
pMac->rrm.rrmSmeContext.neighborReqControlInfo.neighborRspCallbackInfo.neighborRspCallback = NULL;
pMac->rrm.rrmSmeContext.neighborReqControlInfo.neighborRspCallbackInfo.neighborRspCallbackContext = NULL;
/* Call the callback with the status received from caller */
if (callback)
callback(callbackContext, vosStatus);
#if defined(FEATURE_WLAN_ESE) && !defined(FEATURE_WLAN_ESE_UPLOAD)
// We came here with IAPP AP List
// Make sure we inform CSR of the neighbor list
// for ESE Associations. First clear the cache.
else
if (csrNeighborRoamIsESEAssoc(pMac))
{
ProcessIAPPNeighborAPList(pMac);
}
#endif
return;
}
/**---------------------------------------------------------------------------
\brief sme_RrmBeaconReportXmitInd() -
Create and send the beacon report Xmit ind message to PE.
\param - pMac - Pointer to the Hal Handle.
- pResult - scan result.
- measurementDone - flag to indicate that the measurement is done.
\return - 0 for success, non zero for failure
--------------------------------------------------------------------------*/
static eHalStatus sme_RrmSendBeaconReportXmitInd( tpAniSirGlobal pMac,
tCsrScanResultInfo **pResultArr,
tANI_U8 measurementDone,
tANI_U8 bss_count )
{
tpSirBssDescription pBssDesc = NULL;
tpSirBeaconReportXmitInd pBeaconRep;
tANI_U16 length, ie_len, tot_len;
tANI_U8 bssCounter=0, msgCounter=0;
tCsrScanResultInfo *pCurResult=NULL;
eHalStatus status = eHAL_STATUS_FAILURE;
tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext;
#if defined WLAN_VOWIFI_DEBUG
smsLog( pMac, LOGE, "Beacon report xmit Ind to PE");
#endif
if( NULL == pResultArr && !measurementDone )
{
smsLog( pMac, LOGE, "Beacon report xmit Ind to PE Failed");
return eHAL_STATUS_FAILURE;
}
if (pResultArr)
pCurResult=pResultArr[bssCounter];
do
{
length = sizeof(tSirBeaconReportXmitInd);
pBeaconRep = vos_mem_malloc ( length );
if ( NULL == pBeaconRep )
{
smsLog( pMac, LOGP, "Unable to allocate memory for beacon report");
return eHAL_STATUS_FAILED_ALLOC;
}
vos_mem_zero( pBeaconRep, length );
#if defined WLAN_VOWIFI_DEBUG
smsLog( pMac, LOGE, FL("Allocated memory for pBeaconRep"));
#endif
pBeaconRep->messageType = eWNI_SME_BEACON_REPORT_RESP_XMIT_IND;
pBeaconRep->length = length;
pBeaconRep->uDialogToken = pSmeRrmContext->token;
pBeaconRep->duration = pSmeRrmContext->duration[0];
pBeaconRep->regClass = pSmeRrmContext->regClass;
vos_mem_copy( pBeaconRep->bssId, pSmeRrmContext->sessionBssId, sizeof(tSirMacAddr) );
msgCounter=0;
while (pCurResult)
{
pBssDesc = &pCurResult->BssDescriptor;
if(pBssDesc != NULL)
{
ie_len = GET_IE_LEN_IN_BSS( pBssDesc->length );
tot_len = ie_len+sizeof(tSirBssDescription);
pBeaconRep->pBssDescription[msgCounter] =
vos_mem_malloc(tot_len);
if (NULL == pBeaconRep->pBssDescription[msgCounter])
break;
vos_mem_zero(pBeaconRep->pBssDescription[msgCounter],
tot_len);
vos_mem_copy( pBeaconRep->pBssDescription[msgCounter],
pBssDesc,
sizeof(tSirBssDescription) );
vos_mem_copy( &pBeaconRep->pBssDescription[msgCounter]->ieFields[0],
pBssDesc->ieFields, ie_len );
smsLog( pMac, LOG1,
"...RRM Result Bssid = "MAC_ADDRESS_STR" chan= %d, rssi = -%d",
MAC_ADDR_ARRAY(pBeaconRep->pBssDescription[msgCounter]->bssId),
pBeaconRep->pBssDescription[msgCounter]->channelId,
pBeaconRep->pBssDescription[msgCounter]->rssi * (-1));
pBeaconRep->numBssDesc++;
if (++msgCounter >= SIR_BCN_REPORT_MAX_BSS_DESC)
break;
pCurResult = pResultArr[bssCounter + msgCounter];
}
else
{
pCurResult = NULL;
break;
}
}
bssCounter+=msgCounter;
if (!pResultArr || (pCurResult == NULL) || (bssCounter >= bss_count))
{
pCurResult = NULL;
smsLog(pMac, LOG1,
"Reached to the max/last BSS in pCurResult list");
}
else
{
pCurResult = pResultArr[bssCounter];
smsLog(pMac, LOG1,
"Move to the next BSS set in pCurResult list");
}
pBeaconRep->fMeasureDone = (pCurResult)?false:measurementDone;
smsLog(pMac, LOG1,
"SME Sending BcnRepXmit to PE numBss %d msgCounter %d bssCounter %d",
pBeaconRep->numBssDesc, msgCounter, bssCounter);
status = palSendMBMessage(pMac->hHdd, pBeaconRep);
} while (pCurResult);
return status;
}
#if defined(FEATURE_WLAN_ESE_UPLOAD)
/**---------------------------------------------------------------------------
\brief sme_EseSendBeaconReqScanResults()
This function sends up the scan results received as a part of
beacon request scanning.
This function is called after receiving the scan results per channel
Due to the limitation on the size of the IWEVCUSTOM buffer, we send 3 BSSIDs of
beacon report information in one custom event;
\param - pMac - Pointer to the Hal Handle.
- sessionId - Session id
- channel - scan results belongs to this channel
- pResultArr - scan result.
- measurementDone - flag to indicate that the measurement is done.
- bss_count - number of bss found
\return - 0 for success, non zero for failure
--------------------------------------------------------------------------*/
static eHalStatus sme_EseSendBeaconReqScanResults(tpAniSirGlobal pMac,
tANI_U32 sessionId,
tANI_U8 channel,
tCsrScanResultInfo **pResultArr,
tANI_U8 measurementDone,
tANI_U8 bss_count)
{
eHalStatus status = eHAL_STATUS_FAILURE;
tSirRetStatus fillIeStatus;
tpSirBssDescription pBssDesc = NULL;
tANI_U32 ie_len = 0;
tANI_U32 outIeLen = 0;
tANI_U8 bssCounter = 0;
tCsrScanResultInfo *pCurResult = NULL;
tANI_U8 msgCounter = 0;
tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext;
tCsrRoamInfo roamInfo;
tSirEseBcnReportRsp bcnReport;
tpSirEseBcnReportRsp pBcnReport = &bcnReport;
tpCsrEseBeaconReqParams pCurMeasReqIe = NULL;
tANI_U8 i = 0;
if (NULL == pSmeRrmContext)
{
smsLog( pMac, LOGE, "pSmeRrmContext is NULL");
return eHAL_STATUS_FAILURE;
}
if (NULL == pResultArr && !measurementDone)
{
smsLog( pMac, LOGE, "Beacon report xmit Ind to HDD Failed");
return eHAL_STATUS_FAILURE;
}
if (pResultArr)
pCurResult=pResultArr[bssCounter];
vos_mem_zero(&bcnReport, sizeof(tSirEseBcnReportRsp));
do
{
pCurMeasReqIe = NULL;
for (i = 0; i < pSmeRrmContext->eseBcnReqInfo.numBcnReqIe; i++)
{
if(pSmeRrmContext->eseBcnReqInfo.bcnReq[i].channel == channel)
{
pCurMeasReqIe = &pSmeRrmContext->eseBcnReqInfo.bcnReq[i];
break;
}
}
if(NULL != pCurMeasReqIe)
pBcnReport->measurementToken = pCurMeasReqIe->measurementToken;
smsLog( pMac, LOG1, "Channel(%d) MeasToken(%d)", channel, pBcnReport->measurementToken);
msgCounter=0;
while (pCurResult)
{
pBssDesc = &pCurResult->BssDescriptor;
if (NULL != pBssDesc)
{
ie_len = GET_IE_LEN_IN_BSS( pBssDesc->length );
pBcnReport->bcnRepBssInfo[msgCounter].bcnReportFields.ChanNum = pBssDesc->channelId;
pBcnReport->bcnRepBssInfo[msgCounter].bcnReportFields.Spare = 0;
if(NULL != pCurMeasReqIe)
pBcnReport->bcnRepBssInfo[msgCounter].bcnReportFields.MeasDuration = pCurMeasReqIe->measurementDuration;
pBcnReport->bcnRepBssInfo[msgCounter].bcnReportFields.PhyType = pBssDesc->nwType;
pBcnReport->bcnRepBssInfo[msgCounter].bcnReportFields.RecvSigPower = pBssDesc->rssi;
pBcnReport->bcnRepBssInfo[msgCounter].bcnReportFields.ParentTsf = pBssDesc->parentTSF;
pBcnReport->bcnRepBssInfo[msgCounter].bcnReportFields.TargetTsf[0] = pBssDesc->timeStamp[0];
pBcnReport->bcnRepBssInfo[msgCounter].bcnReportFields.TargetTsf[1] = pBssDesc->timeStamp[1];
pBcnReport->bcnRepBssInfo[msgCounter].bcnReportFields.BcnInterval = pBssDesc->beaconInterval;
pBcnReport->bcnRepBssInfo[msgCounter].bcnReportFields.CapabilityInfo = pBssDesc->capabilityInfo;
vos_mem_copy(pBcnReport->bcnRepBssInfo[msgCounter].bcnReportFields.Bssid,
pBssDesc->bssId, sizeof(tSirMacAddr));
fillIeStatus = sirFillBeaconMandatoryIEforEseBcnReport(pMac,
(tANI_U8 *)pBssDesc->ieFields,
ie_len,
&(pBcnReport->bcnRepBssInfo[msgCounter].pBuf),
&outIeLen);
if (eSIR_FAILURE == fillIeStatus)
{
continue;
}
pBcnReport->bcnRepBssInfo[msgCounter].ieLen = outIeLen;
smsLog( pMac, LOG1,"Bssid("MAC_ADDRESS_STR") Channel=%d Rssi=%d",
MAC_ADDR_ARRAY(pBssDesc->bssId),
pBssDesc->channelId, (-1) * pBssDesc->rssi);
pBcnReport->numBss++;
if (++msgCounter >= SIR_BCN_REPORT_MAX_BSS_DESC)
break;
pCurResult = pResultArr[msgCounter];
}
else
{
pCurResult = NULL;
break;
}
}
bssCounter += msgCounter;
if (!pResultArr || !pCurResult || (bssCounter >= SIR_BCN_REPORT_MAX_BSS_DESC))
{
pCurResult = NULL;
smsLog(pMac, LOGE,
"Reached to the max/last BSS in pCurResult list");
}
else
{
pCurResult = pResultArr[bssCounter];
smsLog(pMac, LOGE,
"Move to the next BSS set in pCurResult list");
}
pBcnReport->flag = (measurementDone << 1)|((pCurResult)?true:false);
smsLog(pMac, LOG1, "SME Sending BcnRep to HDD numBss(%d)"
" msgCounter(%d) bssCounter(%d) flag(%d)",
pBcnReport->numBss, msgCounter, bssCounter, pBcnReport->flag);
roamInfo.pEseBcnReportRsp = pBcnReport;
status = csrRoamCallCallback(pMac, sessionId, &roamInfo,
0, eCSR_ROAM_ESE_BCN_REPORT_IND, 0);
/* Free the memory allocated to IE */
for (i = 0; i < msgCounter; i++)
{
if (pBcnReport->bcnRepBssInfo[i].pBuf)
vos_mem_free(pBcnReport->bcnRepBssInfo[i].pBuf);
}
} while (pCurResult);
return status;
}
#endif /* FEATURE_WLAN_ESE_UPLOAD */
/**---------------------------------------------------------------------------
\brief sme_RrmSendScanRequest() -
This function is called to get the scan result from CSR and send the beacon report
xmit ind message to PE.
\param - pMac - Pointer to the Hal Handle.
- num_chan - number of channels.
- channel list - list of channels to fetch the result from.
- measurementDone - flag to indicate that the measurement is done.
\return - 0 for success, non zero for failure
--------------------------------------------------------------------------*/
static eHalStatus sme_RrmSendScanResult( tpAniSirGlobal pMac,
tANI_U8 num_chan,
tANI_U8* chanList,
tANI_U8 measurementDone )
{
tCsrScanResultFilter filter;
tScanResultHandle pResult;
tCsrScanResultInfo *pScanResult, *pNextResult;
tCsrScanResultInfo *pScanResultsArr[SIR_BCN_REPORT_MAX_BSS_DESC];
eHalStatus status;
tANI_U8 counter=0;
tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext;
tANI_U32 sessionId;
tCsrRoamInfo *roam_info;
#if defined WLAN_VOWIFI_DEBUG
smsLog( pMac, LOGE, "Send scan result to PE ");
#endif
vos_mem_zero( &filter, sizeof(filter) );
vos_mem_zero( pScanResultsArr, sizeof(pNextResult)*SIR_BCN_REPORT_MAX_BSS_DESC );
filter.BSSIDs.numOfBSSIDs = 1;
filter.BSSIDs.bssid = &pSmeRrmContext->bssId;
if( pSmeRrmContext->ssId.length )
{
filter.SSIDs.SSIDList =( tCsrSSIDInfo *)vos_mem_malloc(sizeof(tCsrSSIDInfo));
if( filter.SSIDs.SSIDList == NULL )
{
smsLog( pMac, LOGP, FL("vos_mem_malloc failed:") );
return eHAL_STATUS_FAILURE;
}
#if defined WLAN_VOWIFI_DEBUG
smsLog( pMac, LOGE, FL("Allocated memory for SSIDList"));
#endif
vos_mem_zero( filter.SSIDs.SSIDList, sizeof(tCsrSSIDInfo) );
filter.SSIDs.SSIDList->SSID.length = pSmeRrmContext->ssId.length;
vos_mem_copy(filter.SSIDs.SSIDList->SSID.ssId, pSmeRrmContext->ssId.ssId, pSmeRrmContext->ssId.length);
filter.SSIDs.numOfSSIDs = 1;
}
else
{
filter.SSIDs.numOfSSIDs = 0;
}
filter.ChannelInfo.numOfChannels = num_chan;
filter.ChannelInfo.ChannelList = chanList;
filter.fMeasurement = TRUE;
/*
* In case this is beacon report request from last AP (before roaming)
* following call to csrRoamGetSessionIdFromBSSID will fail, hence use
* current session ID instead of one stored in SME rrm context
*/
if (eHAL_STATUS_FAILURE ==
csrRoamGetSessionIdFromBSSID(pMac,
(tCsrBssid*)pSmeRrmContext->sessionBssId,
&sessionId )) {
smsLog( pMac, LOG1, FL("BSSID mismatch, using current sessionID"));
sessionId = pMac->roam.roamSession->sessionId;
}
status = sme_ScanGetResult(pMac, (tANI_U8)sessionId, &filter, &pResult);
if( filter.SSIDs.SSIDList )
{
//Free the memory allocated for SSIDList.
vos_mem_free( filter.SSIDs.SSIDList );
#if defined WLAN_VOWIFI_DEBUG
smsLog( pMac, LOGE, FL("Free memory for SSIDList") );
#endif
}
smsLog(pMac, LOG1, FL("RRM Measurement Done %d"), measurementDone);
if (NULL == pResult)
{
/*
* no scan results
*
* Spec. doesnt say anything about such condition.
* Since section 7.4.6.2 (IEEE802.11k-2008) says-rrm report frame should
* contain one or more report IEs. It probably means dont send any
* response if no matching BSS found. Moreover, there is no flag or
* field in measurement report IE(7.3.2.22) OR beacon report
* IE(7.3.2.22.6) that can be set to indicate no BSS found on a
* given channel.
*
* If we finished measurement on all the channels, we still need to
* send a xmit indication with moreToFollow set to MEASURMENT_DONE
* so that PE can clean any context allocated.
*/
if( measurementDone )
{
#if defined(FEATURE_WLAN_ESE_UPLOAD)
if (eRRM_MSG_SOURCE_ESE_UPLOAD == pSmeRrmContext->msgSource)
{
status = sme_EseSendBeaconReqScanResults(pMac,
sessionId,
chanList[0],
NULL,
measurementDone,
0);
}
else
#endif /*FEATURE_WLAN_ESE_UPLOAD*/
status = sme_RrmSendBeaconReportXmitInd( pMac, NULL, measurementDone, 0);
}
return status;
}
pScanResult = sme_ScanResultGetFirst(pMac, pResult);
if( NULL == pScanResult && measurementDone )
{
#if defined(FEATURE_WLAN_ESE_UPLOAD)
if (eRRM_MSG_SOURCE_ESE_UPLOAD == pSmeRrmContext->msgSource)
{
status = sme_EseSendBeaconReqScanResults(pMac,
sessionId,
chanList[0],
NULL,
measurementDone,
0);
}
else
#endif /*FEATURE_WLAN_ESE_UPLOAD*/
status = sme_RrmSendBeaconReportXmitInd( pMac, NULL, measurementDone, 0 );
}
counter=0;
while (pScanResult)
{
pNextResult = sme_ScanResultGetNext(pMac, pResult);
smsLog(pMac, LOG1, "Scan res timer:%lu, rrm scan timer:%lu",
pScanResult->timer, RRM_scan_timer);
if(pScanResult->timer >= RRM_scan_timer)
{
roam_info = vos_mem_malloc(sizeof(*roam_info));
if (NULL == roam_info) {
smsLog( pMac, LOGP, FL("vos_mem_malloc failed:") );
status = eHAL_STATUS_FAILED_ALLOC;
goto rrm_send_scan_results_done;
}
vos_mem_zero(roam_info, sizeof(*roam_info));
roam_info->pBssDesc = &pScanResult->BssDescriptor;
csrRoamCallCallback(pMac, sessionId, roam_info, 0,
eCSR_ROAM_UPDATE_SCAN_RESULT, eCSR_ROAM_RESULT_NONE);
vos_mem_free(roam_info);
pScanResultsArr[counter++] = pScanResult;
}
pScanResult = pNextResult; //sme_ScanResultGetNext(hHal, pResult);
if (counter >= SIR_BCN_REPORT_MAX_BSS_DESC)
break;
}
smsLog(pMac, LOG1, " Number of BSS Desc with RRM Scan %d ", counter);
/*
* The beacon report should be sent whether the counter is zero or non-zero.
* There might be a few scan results in the cache but not actually are a
* result of this scan. During that scenario, the counter will be zero.
* The report should be sent and LIM will further cleanup the RRM to
* accept the further incoming requests
* In case the counter is Zero, the pScanResultsArr will be NULL.
* The next level routine does a check for the measurementDone to determine
* whether to send a report or not.
*/
if (counter || measurementDone) {
#if defined(FEATURE_WLAN_ESE_UPLOAD)
if (eRRM_MSG_SOURCE_ESE_UPLOAD == pSmeRrmContext->msgSource)
status = sme_EseSendBeaconReqScanResults(pMac, sessionId,
chanList[0], pScanResultsArr,
measurementDone, counter);
else
#endif
status = sme_RrmSendBeaconReportXmitInd(pMac,
pScanResultsArr,
measurementDone, counter);
}
rrm_send_scan_results_done:
sme_ScanResultPurge(pMac, pResult);
return status;
}
/**---------------------------------------------------------------------------
\brief sme_RrmScanRequestCallback() -
The sme module calls this callback function once it finish the scan request
and this function send the beacon report xmit to PE and starts a timer of
random interval to issue next request.
\param - halHandle - Pointer to the Hal Handle.
- pContext - Pointer to the data context.
- scanId - Scan ID.
- status - CSR Status.
\return - 0 for success, non zero for failure
--------------------------------------------------------------------------*/
static eHalStatus sme_RrmScanRequestCallback(tHalHandle halHandle,
void *pContext,
tANI_U8 sessionId,
tANI_U32 scanId,
eCsrScanStatus status)
{
tANI_U16 interval;
tpAniSirGlobal pMac = (tpAniSirGlobal) halHandle;
tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext;
tANI_U32 time_tick;
#if defined WLAN_VOWIFI_DEBUG
smsLog( pMac, LOGE, "Scan Request callback ");
#endif
//if any more channels are pending, start a timer of a random value within randomization interval.
//
//
if( (pSmeRrmContext->currentIndex + 1) < pSmeRrmContext->channelList.numOfChannels )
{
sme_RrmSendScanResult( pMac, 1, &pSmeRrmContext->channelList.ChannelList[pSmeRrmContext->currentIndex], false );
pSmeRrmContext->currentIndex++; //Advance the current index.
/* Start the timer to issue next request. From timer tick get a random
number within 10ms and max randomization interval. */
time_tick = vos_timer_get_system_ticks();
interval = time_tick % (pSmeRrmContext->randnIntvl - 10 + 1) + 10;
#if defined WLAN_VOWIFI_DEBUG
smsLog( pMac, LOGE, "Set timer for interval %d ", interval);
#endif
vos_timer_start( &pSmeRrmContext->IterMeasTimer, interval );
}
else
{
//Done with the measurement. Clean up all context and send a message to PE with measurement done flag set.
sme_RrmSendScanResult( pMac, 1, &pSmeRrmContext->channelList.ChannelList[pSmeRrmContext->currentIndex], true );
vos_mem_free( pSmeRrmContext->channelList.ChannelList );
#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD)
pSmeRrmContext->eseBcnReqInProgress = FALSE;
#endif
#if defined WLAN_VOWIFI_DEBUG
smsLog( pMac, LOGE, FL("Free memory for ChannelList") );
#endif
}
return eHAL_STATUS_SUCCESS;
}
/*--------------------------------------------------------------------------
\brief sme_RrmIssueScanReq() - This is called to send a scan request as part
of beacon report request .
\param pMac - pMac global pointer
\return eHAL_STATUS_SUCCESS - Validation is successful.
\sa
--------------------------------------------------------------------------*/
eHalStatus sme_RrmIssueScanReq( tpAniSirGlobal pMac )
{
//Issue scan request.
tCsrScanRequest scanRequest;
v_U32_t scanId = 0;
eHalStatus status = eHAL_STATUS_SUCCESS;
tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext;
tANI_U32 sessionId;
tSirScanType scanType;
v_TIME_t current_time;
status = csrRoamGetSessionIdFromBSSID( pMac, (tCsrBssid*)pSmeRrmContext->sessionBssId, &sessionId );
if( status != eHAL_STATUS_SUCCESS )
{
smsLog( pMac, LOGE, "%s : Invalid sme Session ID", __func__);
return eHAL_STATUS_FAILURE;
}
if ((pSmeRrmContext->currentIndex) >= pSmeRrmContext->channelList.numOfChannels)
return status;
if( eRRM_MSG_SOURCE_ESE_UPLOAD == pSmeRrmContext->msgSource ||
eRRM_MSG_SOURCE_LEGACY_ESE == pSmeRrmContext->msgSource )
scanType = pSmeRrmContext->measMode[pSmeRrmContext->currentIndex];
else
scanType = pSmeRrmContext->measMode[0];
if ((eSIR_ACTIVE_SCAN == scanType) || (eSIR_PASSIVE_SCAN == scanType))
{
#if defined WLAN_VOWIFI_DEBUG
smsLog( pMac, LOGE, "Issue scan request " );
#endif
vos_mem_zero( &scanRequest, sizeof(scanRequest));
/* set scanType, active or passive */
scanRequest.scanType = scanType;
vos_mem_copy(scanRequest.bssid,
pSmeRrmContext->bssId, sizeof(scanRequest.bssid) );
if (pSmeRrmContext->ssId.length)
{
scanRequest.SSIDs.numOfSSIDs = 1;
scanRequest.SSIDs.SSIDList =( tCsrSSIDInfo *)vos_mem_malloc(sizeof(tCsrSSIDInfo));
if (NULL == scanRequest.SSIDs.SSIDList)
{
smsLog( pMac, LOGP, FL("vos_mem_malloc failed:") );
return eHAL_STATUS_FAILURE;
}
#if defined WLAN_VOWIFI_DEBUG
smsLog( pMac, LOGE, FL("Allocated memory for pSSIDList"));
#endif
vos_mem_zero( scanRequest.SSIDs.SSIDList, sizeof(tCsrSSIDInfo) );
scanRequest.SSIDs.SSIDList->SSID.length = pSmeRrmContext->ssId.length;
vos_mem_copy(scanRequest.SSIDs.SSIDList->SSID.ssId, pSmeRrmContext->ssId.ssId, pSmeRrmContext->ssId.length);
}
/* set min and max channel time */
scanRequest.minChnTime = 0; //pSmeRrmContext->duration; Dont use min timeout.
if( eRRM_MSG_SOURCE_ESE_UPLOAD == pSmeRrmContext->msgSource ||
eRRM_MSG_SOURCE_LEGACY_ESE == pSmeRrmContext->msgSource )
scanRequest.maxChnTime = pSmeRrmContext->duration[pSmeRrmContext->currentIndex];
else
scanRequest.maxChnTime = pSmeRrmContext->duration[0];
smsLog( pMac, LOG1, "Scan Type(%d) Max Dwell Time(%d)", scanRequest.scanType,
scanRequest.maxChnTime );
/**
* For RRM scans timing is very important especially when the request
* is for limited channels. There is no need for firmware to rest for
* about 100-200 ms on the home channel. Instead, it can start the
* scan right away which will make the host to respond with the beacon
* report as quickly as possible. Ensure that the scan requests are
* not back to back and hence there is a check to see if the requests
* are atleast 1 second apart.
*/
current_time = vos_timer_get_system_time();
smsLog(pMac, LOG1, "prev scan triggered before %ld ms, totalchannels %d",
current_time - RRM_scan_timer,
pSmeRrmContext->channelList.numOfChannels);
if ((abs(current_time - RRM_scan_timer) > 1000) &&
(pSmeRrmContext->channelList.numOfChannels == 1)) {
scanRequest.restTime = 1;
scanRequest.min_rest_time = 1;
scanRequest.idle_time = 1;
}
RRM_scan_timer = vos_timer_get_system_time();
#if defined WLAN_VOWIFI_DEBUG
smsLog( pMac, LOGE, "For Duration %d ", scanRequest.maxChnTime );
#endif
/* set BSSType to default type */
scanRequest.BSSType = eCSR_BSS_TYPE_ANY;
/*Scan all the channels */
scanRequest.ChannelInfo.numOfChannels = 1;
scanRequest.ChannelInfo.ChannelList = &pSmeRrmContext->channelList.ChannelList[pSmeRrmContext->currentIndex];
#if defined WLAN_VOWIFI_DEBUG
smsLog( pMac, LOGE, "On channel %d ", pSmeRrmContext->channelList.ChannelList[pSmeRrmContext->currentIndex] );
#endif
/* set requestType to full scan */
scanRequest.requestType = eCSR_SCAN_REQUEST_FULL_SCAN;
status = sme_ScanRequest( pMac, (tANI_U8)sessionId, &scanRequest, &scanId, &sme_RrmScanRequestCallback, NULL );
if ( pSmeRrmContext->ssId.length )
{
vos_mem_free(scanRequest.SSIDs.SSIDList);
#if defined WLAN_VOWIFI_DEBUG
smsLog( pMac, LOGE, FL("Free memory for SSIDList"));
#endif
}
}
else if (eSIR_BEACON_TABLE == scanType) /* beacon table */
{
/*In beacon table mode, scan results are taken directly from scan cache
without issuing any scan request. So, it is not proper to update
RRM_scan_timer with latest time and hence made it to zero to satisfy
pScanResult->timer >= RRM_scan_timer */
RRM_scan_timer = 0;
if ((pSmeRrmContext->currentIndex + 1) < pSmeRrmContext->channelList.numOfChannels)
{
sme_RrmSendScanResult( pMac, 1, &pSmeRrmContext->channelList.ChannelList[pSmeRrmContext->currentIndex], false );
pSmeRrmContext->currentIndex++; //Advance the current index.
sme_RrmIssueScanReq(pMac);
#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD)
pSmeRrmContext->eseBcnReqInProgress = FALSE;
#endif
}
else
{
//Done with the measurement. Clean up all context and send a message to PE with measurement done flag set.
sme_RrmSendScanResult( pMac, 1, &pSmeRrmContext->channelList.ChannelList[pSmeRrmContext->currentIndex], true );
vos_mem_free( pSmeRrmContext->channelList.ChannelList );
}
}
else
{
smsLog( pMac, LOGE, "Unknown beacon report request mode(%d)", scanType);
/* Indicate measurement completion to PE */
/* If this is not done, pCurrentReq pointer will not be freed and
PE will not handle subsequent Beacon requests */
sme_RrmSendBeaconReportXmitInd(pMac, NULL, true, 0);
}
return status;
}
/*--------------------------------------------------------------------------
\brief sme_RrmProcessBeaconReportReqInd() - This is called to process the Beacon
report request from peer AP forwarded through PE .
\param pMsgBuf - a pointer to a buffer that maps to various structures base
on the message type.
The beginning of the buffer can always map to tSirSmeRsp.
\return eHAL_STATUS_SUCCESS - Validation is successful.
\sa
--------------------------------------------------------------------------*/
eHalStatus sme_RrmProcessBeaconReportReqInd(tpAniSirGlobal pMac, void *pMsgBuf)
{
tpSirBeaconReportReqInd pBeaconReq = (tpSirBeaconReportReqInd) pMsgBuf;
tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext;
tANI_U32 len = 0, i = 0;
eHalStatus status = eHAL_STATUS_SUCCESS;
#if defined WLAN_VOWIFI_DEBUG
smsLog( pMac, LOGE, "Received Beacon report request ind Channel = %d", pBeaconReq->channelInfo.channelNum );
#endif
//section 11.10.8.1 (IEEE Std 802.11k-2008)
//channel 0 and 255 has special meaning.
if( (pBeaconReq->channelInfo.channelNum == 0) ||
((pBeaconReq->channelInfo.channelNum == 255) && (pBeaconReq->channelList.numChannels == 0) ) )
{
//Add all the channel in the regulatory domain.
wlan_cfgGetStrLen( pMac, WNI_CFG_VALID_CHANNEL_LIST, &len );
pSmeRrmContext->channelList.ChannelList = vos_mem_malloc( len );
if( pSmeRrmContext->channelList.ChannelList == NULL )
{
smsLog( pMac, LOGP, FL("vos_mem_malloc failed:") );
return eHAL_STATUS_FAILURE;
}
#if defined WLAN_VOWIFI_DEBUG
smsLog( pMac, LOGE, FL("Allocated memory for ChannelList") );
#endif
csrGetCfgValidChannels( pMac, pSmeRrmContext->channelList.ChannelList, &len );
pSmeRrmContext->channelList.numOfChannels = (tANI_U8)len;
#if defined WLAN_VOWIFI_DEBUG
smsLog( pMac, LOGE, "channel == 0 performing on all channels");
#endif
}
else
{
len = 0;
pSmeRrmContext->channelList.numOfChannels = 0;
//If valid channel is present. We first Measure on the given channel. and
//if there are additional channels present in APchannelreport, measure on these also.
if ( pBeaconReq->channelInfo.channelNum != 255 )
len = 1;
#if defined WLAN_VOWIFI_DEBUG
else
smsLog( pMac, LOGE, "channel == 255");
#endif
len += pBeaconReq->channelList.numChannels;
pSmeRrmContext->channelList.ChannelList = vos_mem_malloc( len );
if( pSmeRrmContext->channelList.ChannelList == NULL )
{
smsLog( pMac, LOGP, FL("vos_mem_malloc failed") );
return eHAL_STATUS_FAILURE;
}
#if defined WLAN_VOWIFI_DEBUG
smsLog( pMac, LOGE, FL("Allocated memory for ChannelList") );
#endif
if ( pBeaconReq->channelInfo.channelNum != 255 )
{
#if defined WLAN_VOWIFI_DEBUG
smsLog( pMac, LOGE, "channel == %d ", pBeaconReq->channelInfo.channelNum );
#endif
if(csrRoamIsChannelValid( pMac, pBeaconReq->channelInfo.channelNum ))
pSmeRrmContext->channelList.ChannelList[pSmeRrmContext->channelList.numOfChannels++] = pBeaconReq->channelInfo.channelNum;
#if defined WLAN_VOWIFI_DEBUG
else
smsLog( pMac, LOGE, "is Invalid channel, Ignoring this channel" );
#endif
}
for ( i = 0 ; i < pBeaconReq->channelList.numChannels; i++ )
{
if(csrRoamIsChannelValid( pMac, pBeaconReq->channelList.channelNumber[i] ))
{
pSmeRrmContext->channelList.ChannelList[pSmeRrmContext->channelList.numOfChannels] = pBeaconReq->channelList.channelNumber[i];
pSmeRrmContext->channelList.numOfChannels++;
}
}
}
//Copy session bssid
vos_mem_copy( pSmeRrmContext->sessionBssId, pBeaconReq->bssId, sizeof(tSirMacAddr) );
//copy measurement bssid
vos_mem_copy( pSmeRrmContext->bssId, pBeaconReq->macaddrBssid, sizeof(tSirMacAddr) );
//Copy ssid
vos_mem_copy( &pSmeRrmContext->ssId, &pBeaconReq->ssId, sizeof(tAniSSID) );
pSmeRrmContext->token = pBeaconReq->uDialogToken;
pSmeRrmContext->regClass = pBeaconReq->channelInfo.regulatoryClass;
pSmeRrmContext->randnIntvl = VOS_MAX(pBeaconReq->randomizationInterval, pSmeRrmContext->rrmConfig.max_randn_interval);
pSmeRrmContext->currentIndex = 0;
pSmeRrmContext->msgSource = pBeaconReq->msgSource;
vos_mem_copy((tANI_U8*)&pSmeRrmContext->measMode, (tANI_U8*)&pBeaconReq->fMeasurementtype, SIR_ESE_MAX_MEAS_IE_REQS);
vos_mem_copy((tANI_U8*)&pSmeRrmContext->duration, (tANI_U8*)&pBeaconReq->measurementDuration, SIR_ESE_MAX_MEAS_IE_REQS);
status = sme_RrmIssueScanReq( pMac );
return status;
}
/*--------------------------------------------------------------------------
\brief sme_RrmNeighborReportRequest() - This is API can be used to trigger a
Neighbor report from the peer.
\param sessionId - session identifier on which the request should be made.
\param pNeighborReq - a pointer to a neighbor report request.
\return eHAL_STATUS_SUCCESS - Validation is successful.
\sa
--------------------------------------------------------------------------*/
VOS_STATUS sme_RrmNeighborReportRequest(tpAniSirGlobal pMac, tANI_U8 sessionId,
tpRrmNeighborReq pNeighborReq, tpRrmNeighborRspCallbackInfo callbackInfo)
{
eHalStatus status = eHAL_STATUS_SUCCESS;
tpSirNeighborReportReqInd pMsg;
tCsrRoamSession *pSession;
#if defined WLAN_VOWIFI_DEBUG
smsLog( pMac, LOGE, FL("Request to send Neighbor report request received "));
#endif
if( !CSR_IS_SESSION_VALID( pMac, sessionId ) )
{
smsLog( pMac, LOGE, FL("Invalid session %d"), sessionId );
return VOS_STATUS_E_INVAL;
}
pSession = CSR_GET_SESSION( pMac, sessionId );
/* If already a report is pending, return failure */
if (eANI_BOOLEAN_TRUE == pMac->rrm.rrmSmeContext.neighborReqControlInfo.isNeighborRspPending)
{
smsLog( pMac, LOGE, FL("Neighbor request already pending.. Not allowed"));
return VOS_STATUS_E_AGAIN;
}
pMsg = vos_mem_malloc ( sizeof(tSirNeighborReportReqInd) );
if ( NULL == pMsg )
{
smsLog( pMac, LOGE, "Unable to allocate memory for Neighbor request");
return VOS_STATUS_E_NOMEM;
}
vos_mem_zero( pMsg, sizeof(tSirNeighborReportReqInd) );
#if defined WLAN_VOWIFI_DEBUG
smsLog( pMac, LOGE, FL(" Allocated memory for Neighbor request") );
#endif
rrmLLPurgeNeighborCache(pMac, &pMac->rrm.rrmSmeContext.neighborReportCache);
#if defined WLAN_VOWIFI_DEBUG
smsLog( pMac, LOGE, FL("Purged the neighbor cache before sending Neighbor request: Status = %d"), status );
#endif
pMsg->messageType = eWNI_SME_NEIGHBOR_REPORT_REQ_IND;
pMsg->length = sizeof( tSirNeighborReportReqInd );
vos_mem_copy( &pMsg->bssId, &pSession->connectedProfile.bssid, sizeof(tSirMacAddr) );
pMsg->noSSID = pNeighborReq->no_ssid;
vos_mem_copy( &pMsg->ucSSID, &pNeighborReq->ssid, sizeof(tSirMacSSid));
status = palSendMBMessage(pMac->hHdd, pMsg);
if( status != eHAL_STATUS_SUCCESS )
return VOS_STATUS_E_FAILURE;
/* Neighbor report request message sent successfully to PE. Now register the callbacks */
pMac->rrm.rrmSmeContext.neighborReqControlInfo.neighborRspCallbackInfo.neighborRspCallback =
callbackInfo->neighborRspCallback;
pMac->rrm.rrmSmeContext.neighborReqControlInfo.neighborRspCallbackInfo.neighborRspCallbackContext =
callbackInfo->neighborRspCallbackContext;
pMac->rrm.rrmSmeContext.neighborReqControlInfo.isNeighborRspPending = eANI_BOOLEAN_TRUE;
/* Start neighbor response wait timer now */
vos_timer_start(&pMac->rrm.rrmSmeContext.neighborReqControlInfo.neighborRspWaitTimer, callbackInfo->timeout);
return VOS_STATUS_SUCCESS;
}
/*--------------------------------------------------------------------------
\brief rrmCalculateNeighborAPRoamScore() - This API is called while handling
individual neighbor reports from the APs neighbor AP report to
calculate the cumulative roam score before storing it in neighbor
cache.
\param pNeighborReportDesc - Neighbor BSS Descriptor node for which roam score
should be calculated
\return void.
--------------------------------------------------------------------------*/
static void rrmCalculateNeighborAPRoamScore(tpAniSirGlobal pMac, tpRrmNeighborReportDesc pNeighborReportDesc)
{
tpSirNeighborBssDescripton pNeighborBssDesc;
tANI_U32 roamScore = 0;
#ifdef FEATURE_WLAN_ESE
tANI_U8 sessionId;
#endif
if (NULL == pNeighborReportDesc)
{
VOS_ASSERT(0);
return;
}
if (NULL == pNeighborReportDesc->pNeighborBssDescription)
{
VOS_ASSERT(0);
return;
}
pNeighborBssDesc = pNeighborReportDesc->pNeighborBssDescription;
if (pNeighborBssDesc->bssidInfo.rrmInfo.fMobilityDomain)
{
roamScore += RRM_ROAM_SCORE_NEIGHBOR_REPORT_MOBILITY_DOMAIN;
if (pNeighborBssDesc->bssidInfo.rrmInfo.fSameSecurityMode)
{
roamScore += RRM_ROAM_SCORE_NEIGHBOR_REPORT_SECURITY;
if (pNeighborBssDesc->bssidInfo.rrmInfo.fSameAuthenticator)
{
roamScore += RRM_ROAM_SCORE_NEIGHBOR_REPORT_KEY_SCOPE;
if (pNeighborBssDesc->bssidInfo.rrmInfo.fCapRadioMeasurement)
{
roamScore += RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_RRM;
if (pNeighborBssDesc->bssidInfo.rrmInfo.fCapSpectrumMeasurement)
roamScore += RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_SPECTRUM_MGMT;
if (pNeighborBssDesc->bssidInfo.rrmInfo.fCapQos)
roamScore += RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_QOS;
if (pNeighborBssDesc->bssidInfo.rrmInfo.fCapApsd)
roamScore += RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_APSD;
if (pNeighborBssDesc->bssidInfo.rrmInfo.fCapDelayedBlockAck)
roamScore += RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_DELAYED_BA;
if (pNeighborBssDesc->bssidInfo.rrmInfo.fCapImmediateBlockAck)
roamScore += RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_IMMEDIATE_BA;
if (pNeighborBssDesc->bssidInfo.rrmInfo.fApPreauthReachable)
roamScore += RRM_ROAM_SCORE_NEIGHBOR_REPORT_REACHABILITY;
}
}
}
}
#ifdef FEATURE_WLAN_ESE
sessionId = pNeighborReportDesc->sessionId;
/* It has come in the report so its the best score */
if (csrNeighborRoamIs11rAssoc(pMac, sessionId) == FALSE) {
/* IAPP Route so lets make use of this info
* save all AP, as the list does not come all the time
* Save and reuse till the next AP List comes to us.
* Even save our own MAC address. Will be useful next time around.
*/
roamScore += RRM_ROAM_SCORE_NEIGHBOR_IAPP_LIST;
}
#endif
pNeighborReportDesc->roamScore = roamScore;
return;
}
/*--------------------------------------------------------------------------
\brief rrmStoreNeighborRptByRoamScore() - This API is called to store a given
Neighbor BSS descriptor to the neighbor cache. This function
stores the neighbor BSS descriptors in such a way that descriptors
are sorted by roamScore in descending order
\param pNeighborReportDesc - Neighbor BSS Descriptor node to be stored in cache
\return void.
--------------------------------------------------------------------------*/
void rrmStoreNeighborRptByRoamScore(tpAniSirGlobal pMac, tpRrmNeighborReportDesc pNeighborReportDesc)
{
tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext;
tListElem *pEntry;
tRrmNeighborReportDesc *pTempNeighborReportDesc;
if (NULL == pNeighborReportDesc)
{
VOS_ASSERT(0);
return;
}
if (NULL == pNeighborReportDesc->pNeighborBssDescription)
{
VOS_ASSERT(0);
return;
}
if (csrLLIsListEmpty(&pSmeRrmContext->neighborReportCache, LL_ACCESS_LOCK))
{
smsLog(pMac, LOGE, FL("Neighbor report cache is empty.. Adding a entry now"));
/* Neighbor list cache is empty. Insert this entry in the tail */
csrLLInsertTail(&pSmeRrmContext->neighborReportCache, &pNeighborReportDesc->List, LL_ACCESS_LOCK);
return;
}
else
{
/* Should store the neighbor BSS description in the order sorted by roamScore in descending
order. APs with highest roamScore should be the 1st entry in the list */
pEntry = csrLLPeekHead(&pSmeRrmContext->neighborReportCache, LL_ACCESS_LOCK);
while (pEntry != NULL)
{
pTempNeighborReportDesc = GET_BASE_ADDR( pEntry, tRrmNeighborReportDesc, List );
if (pTempNeighborReportDesc->roamScore < pNeighborReportDesc->roamScore)
break;
pEntry = csrLLNext(&pSmeRrmContext->neighborReportCache, pEntry, LL_ACCESS_LOCK);
}
if (pEntry)
/* This BSS roamscore is better than something in the list. Insert this before that one */
csrLLInsertEntry(&pSmeRrmContext->neighborReportCache, pEntry, &pNeighborReportDesc->List, LL_ACCESS_LOCK);
else
/* All the entries in the list has a better roam Score than this one. Insert this at the last */
csrLLInsertTail(&pSmeRrmContext->neighborReportCache, &pNeighborReportDesc->List, LL_ACCESS_LOCK);
}
return;
}
/*--------------------------------------------------------------------------
\brief sme_RrmProcessNeighborReport() - This is called to process the Neighbor
report received from PE.
\param pMsgBuf - a pointer to a buffer that maps to various structures base
on the message type.
The beginning of the buffer can always map to tSirSmeRsp.
\return eHAL_STATUS_SUCCESS - Validation is successful.
\sa
--------------------------------------------------------------------------*/
eHalStatus sme_RrmProcessNeighborReport(tpAniSirGlobal pMac, void *pMsgBuf)
{
eHalStatus status = eHAL_STATUS_SUCCESS;
tpSirNeighborReportInd pNeighborRpt = (tpSirNeighborReportInd) pMsgBuf;
tpRrmNeighborReportDesc pNeighborReportDesc;
tANI_U8 i = 0;
VOS_STATUS vosStatus = VOS_STATUS_SUCCESS;
tANI_U32 sessionId;
/* Get the session id */
status = csrRoamGetSessionIdFromBSSID(pMac, (tCsrBssid *)pNeighborRpt->bssId,
&sessionId);
if (HAL_STATUS_SUCCESS(status)) {
#ifdef FEATURE_WLAN_ESE
/* Clear the cache for ESE. */
if (csrNeighborRoamIsESEAssoc(pMac, sessionId)) {
rrmLLPurgeNeighborCache(pMac,
&pMac->rrm.rrmSmeContext.neighborReportCache);
}
#endif
}
for (i = 0; i < pNeighborRpt->numNeighborReports; i++)
{
pNeighborReportDesc = vos_mem_malloc(sizeof(tRrmNeighborReportDesc));
if (NULL == pNeighborReportDesc)
{
smsLog( pMac, LOGE, "Failed to allocate memory for RRM Neighbor report desc");
status = eHAL_STATUS_FAILED_ALLOC;
goto end;
}
vos_mem_zero(pNeighborReportDesc, sizeof(tRrmNeighborReportDesc));
pNeighborReportDesc->pNeighborBssDescription = vos_mem_malloc(sizeof(tSirNeighborBssDescription));
if (NULL == pNeighborReportDesc->pNeighborBssDescription)
{
smsLog( pMac, LOGE, "Failed to allocate memory for RRM Neighbor report BSS Description");
vos_mem_free(pNeighborReportDesc);
status = eHAL_STATUS_FAILED_ALLOC;
goto end;
}
vos_mem_zero(pNeighborReportDesc->pNeighborBssDescription, sizeof(tSirNeighborBssDescription));
vos_mem_copy(pNeighborReportDesc->pNeighborBssDescription, &pNeighborRpt->sNeighborBssDescription[i],
sizeof(tSirNeighborBssDescription));
#if defined WLAN_VOWIFI_DEBUG
smsLog( pMac, LOGE, "Received neighbor report with Neighbor BSSID: "MAC_ADDRESS_STR,
MAC_ADDR_ARRAY(pNeighborRpt->sNeighborBssDescription[i].bssId));
#endif
/* Calculate the roam score based on the BSS Capability in the BSSID Information and store it in Neighbor report Desc */
rrmCalculateNeighborAPRoamScore(pMac, pNeighborReportDesc);
/* Store the Neighbor report Desc in the cache based on the roam score */
if ( pNeighborReportDesc->roamScore > 0)
{
rrmStoreNeighborRptByRoamScore(pMac, pNeighborReportDesc);
}
else
{
smsLog(pMac, LOGE, FL("Roam score of BSSID "MAC_ADDRESS_STR" is 0, Ignoring.."),
MAC_ADDR_ARRAY(pNeighborRpt->sNeighborBssDescription[i].bssId));
vos_mem_free(pNeighborReportDesc->pNeighborBssDescription);
vos_mem_free(pNeighborReportDesc);
}
}
end:
if (!csrLLCount(&pMac->rrm.rrmSmeContext.neighborReportCache))
vosStatus = VOS_STATUS_E_FAILURE;
/* Received a report from AP. Indicate SUCCESS to the caller if there are some valid reports */
rrmIndicateNeighborReportResult(pMac, vosStatus);
return status;
}
/*--------------------------------------------------------------------------
\brief sme_RrmMsgProcessor() - sme_ProcessMsg() calls this function for the
messages that are handled by SME RRM module.
\param pMac - Pointer to the global MAC parameter structure.
\param msg_type - the type of msg passed by PE as defined in wniApi.h
\param pMsgBuf - a pointer to a buffer that maps to various structures base
on the message type.
The beginning of the buffer can always map to tSirSmeRsp.
\return eHAL_STATUS_SUCCESS - Validation is successful.
\sa
--------------------------------------------------------------------------*/
eHalStatus sme_RrmMsgProcessor( tpAniSirGlobal pMac, v_U16_t msg_type,
void *pMsgBuf)
{
VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_INFO_HIGH,
FL(" Msg = %d for RRM measurement") , msg_type );
//switch on the msg type & make the state transition accordingly
switch(msg_type)
{
case eWNI_SME_NEIGHBOR_REPORT_IND:
sme_RrmProcessNeighborReport( pMac, pMsgBuf );
break;
case eWNI_SME_BEACON_REPORT_REQ_IND:
sme_RrmProcessBeaconReportReqInd( pMac, pMsgBuf );
break;
default:
//err msg
VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
FL("sme_RrmMsgProcessor:unknown msg type = %d"), msg_type);
break;
}
return eHAL_STATUS_SUCCESS;
}
/* ---------------------------------------------------------------------------
\fn rrmIterMeasTimerHandle
\brief Timer handler to handle the timeout condition when a specific BT
stop event does not come back, in which case to restore back the
heartbeat timer.
\param pMac - The handle returned by macOpen.
\return VOID
---------------------------------------------------------------------------*/
void rrmIterMeasTimerHandle( v_PVOID_t userData )
{
tpAniSirGlobal pMac = (tpAniSirGlobal) userData;
#if defined WLAN_VOWIFI_DEBUG
smsLog( pMac, LOGE, "Randomization timer expired...send on next channel ");
#endif
//Issue a scan req for next channel.
sme_RrmIssueScanReq( pMac );
}
/* ---------------------------------------------------------------------------
\fn rrmNeighborRspTimeoutHandler
\brief Timer handler to handle the timeout condition when a neighbor request is sent
and no neighbor response is received from the AP
\param pMac - The handle returned by macOpen.
\return VOID
---------------------------------------------------------------------------*/
void rrmNeighborRspTimeoutHandler
( v_PVOID_t userData )
{
tpAniSirGlobal pMac = (tpAniSirGlobal) userData;
#if defined WLAN_VOWIFI_DEBUG
smsLog( pMac, LOGE, "Neighbor Response timed out ");
#endif
rrmIndicateNeighborReportResult(pMac, VOS_STATUS_E_FAILURE);
return;
}
/* ---------------------------------------------------------------------------
\fn rrmOpen
\brief
\param pMac - The handle returned by macOpen.
\return VOS_STATUS
VOS_STATUS_E_FAILURE success
VOS_STATUS_SUCCESS failure
---------------------------------------------------------------------------*/
VOS_STATUS rrmOpen (tpAniSirGlobal pMac)
{
VOS_STATUS vosStatus;
tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext;
eHalStatus halStatus = eHAL_STATUS_SUCCESS;
pSmeRrmContext->rrmConfig.max_randn_interval = 50; //ms
vosStatus = vos_timer_init( &pSmeRrmContext->IterMeasTimer,
VOS_TIMER_TYPE_SW,
rrmIterMeasTimerHandle,
(void*) pMac);
if (!VOS_IS_STATUS_SUCCESS(vosStatus)) {
VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, "rrmOpen: Fail to init timer");
return VOS_STATUS_E_FAILURE;
}
vosStatus = vos_timer_init( &pSmeRrmContext->neighborReqControlInfo.neighborRspWaitTimer,
VOS_TIMER_TYPE_SW,
rrmNeighborRspTimeoutHandler,
(void*) pMac);
if (!VOS_IS_STATUS_SUCCESS(vosStatus)) {
VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, "rrmOpen: Fail to init timer");
return VOS_STATUS_E_FAILURE;
}
pSmeRrmContext->neighborReqControlInfo.isNeighborRspPending = eANI_BOOLEAN_FALSE;
halStatus = csrLLOpen(pMac->hHdd, &pSmeRrmContext->neighborReportCache);
if (eHAL_STATUS_SUCCESS != halStatus)
{
VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, "rrmOpen: Fail to open neighbor cache result");
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
/* ---------------------------------------------------------------------------
\fn rrmClose
\brief
\param pMac - The handle returned by macOpen.
\return VOS_STATUS
VOS_STATUS_E_FAILURE success
VOS_STATUS_SUCCESS failure
---------------------------------------------------------------------------*/
VOS_STATUS rrmClose (tpAniSirGlobal pMac)
{
VOS_STATUS vosStatus = VOS_STATUS_SUCCESS;
tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext;
if( VOS_TIMER_STATE_RUNNING == vos_timer_getCurrentState( &pSmeRrmContext->IterMeasTimer ) )
{
vosStatus = vos_timer_stop( &pSmeRrmContext->IterMeasTimer );
if(!VOS_IS_STATUS_SUCCESS(vosStatus))
{
VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, FL("Timer stop fail") );
}
}
vosStatus = vos_timer_destroy( &pSmeRrmContext->IterMeasTimer );
if (!VOS_IS_STATUS_SUCCESS(vosStatus))
{
VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR, FL("Fail to destroy timer") );
}
if( VOS_TIMER_STATE_RUNNING ==
vos_timer_getCurrentState( &pSmeRrmContext->neighborReqControlInfo.neighborRspWaitTimer ) )
{
vosStatus = vos_timer_stop( &pSmeRrmContext->neighborReqControlInfo.neighborRspWaitTimer );
if(!VOS_IS_STATUS_SUCCESS(vosStatus))
{
VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL, FL("Timer stop fail") );
}
}
vosStatus = vos_timer_destroy( &pSmeRrmContext->neighborReqControlInfo.neighborRspWaitTimer );
if (!VOS_IS_STATUS_SUCCESS(vosStatus))
{
VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_FATAL, FL("Fail to destroy timer") );
}
rrmLLPurgeNeighborCache(pMac, &pSmeRrmContext->neighborReportCache);
csrLLClose(&pSmeRrmContext->neighborReportCache);
return vosStatus;
}
/* ---------------------------------------------------------------------------
\fn rrmReady
\brief fn
\param pMac - The handle returned by macOpen.
\return VOS_STATUS
---------------------------------------------------------------------------*/
VOS_STATUS rrmReady (tpAniSirGlobal pMac)
{
return VOS_STATUS_SUCCESS;
}
/* ---------------------------------------------------------------------------
\fn rrmChangeDefaultConfigParam
\brief fn
\param pMac - The handle returned by macOpen.
\param pRrmConfig - pointer to new rrm configs.
\return VOS_STATUS
---------------------------------------------------------------------------*/
VOS_STATUS rrmChangeDefaultConfigParam(tpAniSirGlobal pMac,
struct rrm_config_param *pRrmConfig)
{
vos_mem_copy(&pMac->rrm.rrmSmeContext.rrmConfig, pRrmConfig,
sizeof(struct rrm_config_param));
return VOS_STATUS_SUCCESS;
}
/* ---------------------------------------------------------------------------
\fn smeRrmGetFirstBssEntryFromNeighborCache()
\brief This function returns the first entry from the neighbor cache to the caller
\param pMac - The handle returned by macOpen.
\return VOID
---------------------------------------------------------------------------*/
tRrmNeighborReportDesc* smeRrmGetFirstBssEntryFromNeighborCache( tpAniSirGlobal pMac)
{
tListElem *pEntry;
tRrmNeighborReportDesc *pTempBssEntry = NULL;
tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext;
pEntry = csrLLPeekHead( &pSmeRrmContext->neighborReportCache, LL_ACCESS_LOCK );
if(!pEntry || !csrLLCount(&pSmeRrmContext->neighborReportCache))
{
//list empty
smsLog(pMac, LOGW, FL("List empty"));
return NULL;
}
pTempBssEntry = GET_BASE_ADDR( pEntry, tRrmNeighborReportDesc, List );
return pTempBssEntry;
}
/* ---------------------------------------------------------------------------
\fn smeRrmGetNextBssEntryFromNeighborCache()
\brief This function returns the entry next to the given entry from the
neighbor cache to the caller
\param pMac - The handle returned by macOpen.
\return VOID
---------------------------------------------------------------------------*/
tRrmNeighborReportDesc* smeRrmGetNextBssEntryFromNeighborCache( tpAniSirGlobal pMac,
tpRrmNeighborReportDesc pBssEntry)
{
tListElem *pEntry;
tRrmNeighborReportDesc *pTempBssEntry = NULL;
pEntry = csrLLNext(&pMac->rrm.rrmSmeContext.neighborReportCache, &pBssEntry->List, LL_ACCESS_LOCK);
if(!pEntry)
{
//list empty
smsLog(pMac, LOGW, FL("List empty"));
return NULL;
}
pTempBssEntry = GET_BASE_ADDR( pEntry, tRrmNeighborReportDesc, List );
return pTempBssEntry;
}
#if defined(FEATURE_WLAN_ESE) && !defined(FEATURE_WLAN_ESE_UPLOAD)
void csrEseSendAdjacentApRepMsg(tpAniSirGlobal pMac, tCsrRoamSession *pSession)
{
tpSirAdjacentApRepInd pAdjRep;
tANI_U16 length;
tANI_U32 roamTS2;
smsLog( pMac, LOG1, "Adjacent AP Report Msg to PE");
length = sizeof(tSirAdjacentApRepInd );
pAdjRep = vos_mem_malloc ( length );
if ( NULL == pAdjRep )
{
smsLog( pMac, LOGP, "Unable to allocate memory for Adjacent AP report");
return;
}
vos_mem_zero( pAdjRep, length );
pAdjRep->messageType = eWNI_SME_ESE_ADJACENT_AP_REPORT;
pAdjRep->length = length;
pAdjRep->channelNum = pSession->prevOpChannel;
vos_mem_copy( pAdjRep->bssid, &pSession->connectedProfile.bssid, sizeof(tSirMacAddr) );
vos_mem_copy( pAdjRep->prevApMacAddr, &pSession->prevApBssid, sizeof(tSirMacAddr) );
vos_mem_copy( &pAdjRep->prevApSSID, &pSession->prevApSSID, sizeof(tSirMacSSid) );
roamTS2 = vos_timer_get_system_time();
pAdjRep->tsmRoamdelay = roamTS2 - pSession->roamTS1;
pAdjRep->roamReason =SIR_ESE_ASSOC_REASON_UNSPECIFIED;
pAdjRep->clientDissSecs =(pAdjRep->tsmRoamdelay/1000);
palSendMBMessage(pMac->hHdd, pAdjRep);
return;
}
#endif /* FEATURE_WLAN_ESE */
#endif