blob: 88168bf5afc683527b59a5ce87cd068b62ffc4f8 [file] [log] [blame]
/*
* Copyright (c) 2011-2015 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/**=========================================================================
\file sme_Rrm.c
\brief implementation for SME RRM APIs
========================================================================*/
/* $Header$ */
#if defined WLAN_FEATURE_VOWIFI
/*--------------------------------------------------------------------------
Include Files
------------------------------------------------------------------------*/
#include "ani_global.h"
#include "sme_inside.h"
#include "sme_api.h"
#include "sms_debug.h"
#include "cfg_api.h"
#ifdef FEATURE_WLAN_DIAG_SUPPORT
#include "host_diag_core_event.h"
#include "host_diag_core_log.h"
#endif /* FEATURE_WLAN_DIAG_SUPPORT */
#include "csr_inside_api.h"
#include "rrm_global.h"
/* Roam score for a neighbor AP will be calculated based on the below definitions.
The calculated roam score will be used to select the roamable 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;
/**
* rrm_ll_purge_neighbor_cache() -Purges all the entries in the neighbor cache
*
* @pMac: Pointer to the Hal Handle.
* @pList: Pointer the List that should be purged.
*
* This function purges all the entries in the neighbor cache and frees up all
* the internal nodes
*
* Return: void
*/
static void rrm_ll_purge_neighbor_cache(tpAniSirGlobal pMac,
tDblLinkList *pList)
{
tListElem *pEntry;
tRrmNeighborReportDesc *pNeighborReportDesc;
csr_ll_lock(pList);
while ((pEntry = csr_ll_remove_head(pList, LL_ACCESS_NOLOCK)) != NULL) {
pNeighborReportDesc =
GET_BASE_ADDR(pEntry, tRrmNeighborReportDesc, List);
cdf_mem_free(pNeighborReportDesc->pNeighborBssDescription);
cdf_mem_free(pNeighborReportDesc);
}
csr_ll_unlock(pList);
return;
}
/**
* rrm_indicate_neighbor_report_result() -calls the callback registered for
* neighbor report
* @pMac: Pointer to the Hal Handle.
* @cdf_status - CDF_STATUS_SUCCESS/CDF_STATUS_FAILURE based on whether a valid
* report is received or neighbor timer expired
*
* 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.
*
* Return: void
*/
void rrm_indicate_neighbor_report_result(tpAniSirGlobal pMac, CDF_STATUS cdf_status)
{
NeighborReportRspCallback callback;
void *callbackContext;
/* Reset the neighbor response pending status */
pMac->rrm.rrmSmeContext.neighborReqControlInfo.isNeighborRspPending =
false;
/* Stop the timer if it is already running. The timer should be running only in the SUCCESS case. */
if (CDF_TIMER_STATE_RUNNING ==
cdf_mc_timer_get_current_state(&pMac->rrm.rrmSmeContext.
neighborReqControlInfo.
neighborRspWaitTimer)) {
sms_log(pMac, LOG1, FL("No entry in neighbor report cache"));
cdf_mc_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, cdf_status);
return;
}
/**
* sme_RrmBeaconReportXmitInd () - Send beacon report
* @mac_ctx Pointer to mac context
* @result_arr scan results
* @msrmnt_status flag to indicate that the measurement is done.
* @bss_count bss count
*
* Create and send the beacon report Xmit ind message to PE.
*
* Return: status
*/
static CDF_STATUS
sme_rrm_send_beacon_report_xmit_ind(tpAniSirGlobal mac_ctx,
tCsrScanResultInfo **result_arr, uint8_t msrmnt_status,
uint8_t bss_count)
{
tpSirBssDescription bss_desc = NULL;
tpSirBeaconReportXmitInd beacon_rep;
uint16_t length, ie_len;
uint8_t i = 0, j = 0;
tCsrScanResultInfo *cur_result = NULL;
CDF_STATUS status = CDF_STATUS_E_FAILURE;
tpRrmSMEContext rrm_ctx = &mac_ctx->rrm.rrmSmeContext;
#if defined WLAN_VOWIFI_DEBUG
sms_log(mac_ctx, LOGE, "Beacon report xmit Ind to PE");
#endif
if (NULL == result_arr && !msrmnt_status) {
sms_log(mac_ctx, LOGE, "Beacon report xmit Ind to PE Failed");
return CDF_STATUS_E_FAILURE;
}
if (result_arr)
cur_result = result_arr[j];
do {
length = sizeof(tSirBeaconReportXmitInd);
beacon_rep = cdf_mem_malloc(length);
if (NULL == beacon_rep) {
sms_log(mac_ctx, LOGP,
"Unable to allocate memory for beacon report");
return CDF_STATUS_E_NOMEM;
}
cdf_mem_zero(beacon_rep, length);
#if defined WLAN_VOWIFI_DEBUG
sms_log(mac_ctx, LOGE, FL("Allocated memory for beacon_rep"));
#endif
beacon_rep->messageType = eWNI_SME_BEACON_REPORT_RESP_XMIT_IND;
beacon_rep->length = length;
beacon_rep->uDialogToken = rrm_ctx->token;
beacon_rep->duration = rrm_ctx->duration[0];
beacon_rep->regClass = rrm_ctx->regClass;
cdf_mem_copy(beacon_rep->bssId, rrm_ctx->sessionBssId.bytes,
CDF_MAC_ADDR_SIZE);
i = 0;
while (cur_result) {
bss_desc = &cur_result->BssDescriptor;
if (bss_desc == NULL)
break;
ie_len = GET_IE_LEN_IN_BSS(bss_desc->length);
beacon_rep->pBssDescription[i] =
cdf_mem_malloc(ie_len +
sizeof(tSirBssDescription));
if (NULL ==
beacon_rep->pBssDescription[i])
break;
cdf_mem_copy(beacon_rep->pBssDescription[i],
bss_desc, sizeof(tSirBssDescription));
cdf_mem_copy(
&beacon_rep->pBssDescription[i]->ieFields[0],
bss_desc->ieFields, ie_len);
sms_log(mac_ctx, LOG1,
".RRM Result Bssid = " MAC_ADDRESS_STR
" chan= %d, rssi = -%d",
MAC_ADDR_ARRAY(
beacon_rep->pBssDescription[i]->bssId),
beacon_rep->pBssDescription[i]->channelId,
beacon_rep->pBssDescription[i]->rssi * (-1));
beacon_rep->numBssDesc++;
if (++i >= SIR_BCN_REPORT_MAX_BSS_DESC)
break;
cur_result =
result_arr[j + i];
}
j += i;
if (!result_arr || (cur_result == NULL)
|| (j >= bss_count)) {
cur_result = NULL;
sms_log(mac_ctx, LOG1,
"Reached to max/last BSS in cur_result list");
} else {
cur_result = result_arr[j];
sms_log(mac_ctx, LOG1,
"Move to the next BSS set in cur_result list");
}
beacon_rep->fMeasureDone =
(cur_result) ? false : msrmnt_status;
sms_log(mac_ctx, LOG1,
"SME Sending BcnRepXmit to PE numBss %d i %d j %d",
beacon_rep->numBssDesc, i, j);
status = cds_send_mb_message_to_mac(beacon_rep);
} while (cur_result);
return status;
}
#if defined(FEATURE_WLAN_ESE_UPLOAD)
/**
* sme_ese_send_beacon_req_scan_results () - Send beacon report
* @mac_ctx Pointer to mac context
* @session_id - session id
* @result_arr scan results
* @msrmnt_status flag to indicate that the measurement is done.
* @bss_count number of bss found
*
* 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;
*
* Return: status
*/
static CDF_STATUS sme_ese_send_beacon_req_scan_results(
tpAniSirGlobal mac_ctx, uint32_t session_id,
uint8_t channel, tCsrScanResultInfo **result_arr,
uint8_t msrmnt_status, uint8_t bss_count)
{
CDF_STATUS status = CDF_STATUS_E_FAILURE;
tSirRetStatus fill_ie_status;
tpSirBssDescription bss_desc = NULL;
uint32_t ie_len = 0;
uint32_t out_ie_len = 0;
uint8_t bss_counter = 0;
tCsrScanResultInfo *cur_result = NULL;
tpRrmSMEContext rrm_ctx = &mac_ctx->rrm.rrmSmeContext;
tCsrRoamInfo roam_info;
tSirEseBcnReportRsp bcn_rpt_rsp;
tpSirEseBcnReportRsp bcn_report = &bcn_rpt_rsp;
tpCsrEseBeaconReqParams cur_meas_req = NULL;
uint8_t i = 0, j = 0;
tBcnReportFields *bcn_rpt_fields;
if (NULL == rrm_ctx) {
sms_log(mac_ctx, LOGE, "rrm_ctx is NULL");
return CDF_STATUS_E_FAILURE;
}
if (NULL == result_arr && !msrmnt_status) {
sms_log(mac_ctx, LOGE, "Beacon report xmit Ind to HDD Failed");
return CDF_STATUS_E_FAILURE;
}
if (result_arr)
cur_result = result_arr[bss_counter];
cdf_mem_zero(&bcn_rpt_rsp, sizeof(tSirEseBcnReportRsp));
do {
cur_meas_req = NULL;
for (i = 0; i < rrm_ctx->eseBcnReqInfo.numBcnReqIe; i++) {
if (rrm_ctx->eseBcnReqInfo.bcnReq[i].channel ==
channel) {
cur_meas_req =
&rrm_ctx->eseBcnReqInfo.bcnReq[i];
break;
}
}
if (NULL != cur_meas_req)
bcn_report->measurementToken =
cur_meas_req->measurementToken;
sms_log(mac_ctx, LOG1, "Channel(%d) MeasToken(%d)", channel,
bcn_report->measurementToken);
j = 0;
while (cur_result) {
bss_desc = &cur_result->BssDescriptor;
if (NULL == bss_desc) {
cur_result = NULL;
break;
}
ie_len = GET_IE_LEN_IN_BSS(bss_desc->length);
bcn_rpt_fields =
&bcn_report->bcnRepBssInfo[j].bcnReportFields;
bcn_rpt_fields->ChanNum =
bss_desc->channelId;
bcn_report->bcnRepBssInfo[j].bcnReportFields.Spare = 0;
if (NULL != cur_meas_req)
bcn_rpt_fields->MeasDuration =
cur_meas_req->measurementDuration;
bcn_rpt_fields->PhyType = bss_desc->nwType;
bcn_rpt_fields->RecvSigPower = bss_desc->rssi;
bcn_rpt_fields->ParentTsf = bss_desc->parentTSF;
bcn_rpt_fields->TargetTsf[0] = bss_desc->timeStamp[0];
bcn_rpt_fields->TargetTsf[1] = bss_desc->timeStamp[1];
bcn_rpt_fields->BcnInterval = bss_desc->beaconInterval;
bcn_rpt_fields->CapabilityInfo =
bss_desc->capabilityInfo;
cdf_mem_copy(bcn_rpt_fields->Bssid,
bss_desc->bssId, sizeof(tSirMacAddr));
fill_ie_status =
sir_beacon_ie_ese_bcn_report(mac_ctx,
(uint8_t *) bss_desc->ieFields,
ie_len,
&(bcn_report->bcnRepBssInfo[j].pBuf),
&out_ie_len);
if (eSIR_FAILURE == fill_ie_status)
continue;
bcn_report->bcnRepBssInfo[j].ieLen = out_ie_len;
sms_log(mac_ctx, LOG1, "Bssid(" MAC_ADDRESS_STR")"
"Channel=%d Rssi=%d",
MAC_ADDR_ARRAY(bss_desc->bssId),
bss_desc->channelId, (-1) * bss_desc->rssi);
bcn_report->numBss++;
if (++j >= SIR_BCN_REPORT_MAX_BSS_DESC)
break;
cur_result = result_arr[j];
}
bss_counter += j;
if (!result_arr || !cur_result
|| (bss_counter >= SIR_BCN_REPORT_MAX_BSS_DESC)) {
cur_result = NULL;
sms_log(mac_ctx, LOGE,
"Reached to the max/last BSS in cur_result list");
} else {
cur_result = result_arr[bss_counter];
sms_log(mac_ctx, LOGE,
"Move to the next BSS set in cur_result list");
}
bcn_report->flag =
(msrmnt_status << 1) | ((cur_result) ? true : false);
sms_log(mac_ctx, LOG1, "SME Sending BcnRep to HDD numBss(%d)"
" j(%d) bss_counter(%d) flag(%d)",
bcn_report->numBss, j, bss_counter,
bcn_report->flag);
roam_info.pEseBcnReportRsp = bcn_report;
status = csr_roam_call_callback(mac_ctx, session_id, &roam_info,
0, eCSR_ROAM_ESE_BCN_REPORT_IND, 0);
/* Free the memory allocated to IE */
for (i = 0; i < j; i++)
if (bcn_report->bcnRepBssInfo[i].pBuf)
cdf_mem_free(bcn_report->bcnRepBssInfo[i].pBuf);
} while (cur_result);
return status;
}
#endif /* FEATURE_WLAN_ESE_UPLOAD */
/**
* sme_rrm_send_scan_result() - to get scan result and send the beacon report
* @mac_ctx: pointer to mac context
* @num_chan: number of channels
* @chan_list: list of channels to fetch the result from
* @measurementdone: Flag to indicate measurement done or no
*
* This function is called to get the scan result from CSR and send the beacon
* report xmit ind message to PE
*
* Return: CDF_STATUS
*/
static CDF_STATUS sme_rrm_send_scan_result(tpAniSirGlobal mac_ctx,
uint8_t num_chan,
uint8_t *chan_list,
uint8_t measurementdone)
{
tCsrScanResultFilter filter;
tScanResultHandle result_handle;
tCsrScanResultInfo *scan_results, *next_result;
tCsrScanResultInfo *scanresults_arr[SIR_BCN_REPORT_MAX_BSS_DESC];
CDF_STATUS status;
uint8_t counter = 0;
tpRrmSMEContext rrm_ctx = &mac_ctx->rrm.rrmSmeContext;
uint32_t session_id;
#if defined WLAN_VOWIFI_DEBUG
sms_log(mac_ctx, LOGE, FL("Send scan result to PE "));
#endif
cdf_mem_zero(&filter, sizeof(filter));
cdf_mem_zero(scanresults_arr,
sizeof(next_result) * SIR_BCN_REPORT_MAX_BSS_DESC);
filter.BSSIDs.numOfBSSIDs = 1;
filter.BSSIDs.bssid = (struct cdf_mac_addr *)&rrm_ctx->bssId;
if (rrm_ctx->ssId.length) {
filter.SSIDs.SSIDList =
(tCsrSSIDInfo *) cdf_mem_malloc(sizeof(tCsrSSIDInfo));
if (filter.SSIDs.SSIDList == NULL) {
sms_log(mac_ctx, LOGP, FL("cdf_mem_malloc failed"));
return CDF_STATUS_E_NOMEM;
}
#if defined WLAN_VOWIFI_DEBUG
sms_log(mac_ctx, LOGE, FL("Allocated memory for SSIDList"));
#endif
cdf_mem_zero(filter.SSIDs.SSIDList, sizeof(tCsrSSIDInfo));
filter.SSIDs.SSIDList->SSID.length =
rrm_ctx->ssId.length;
cdf_mem_copy(filter.SSIDs.SSIDList->SSID.ssId,
rrm_ctx->ssId.ssId, rrm_ctx->ssId.length);
filter.SSIDs.numOfSSIDs = 1;
} else {
filter.SSIDs.numOfSSIDs = 0;
}
filter.ChannelInfo.numOfChannels = num_chan;
filter.ChannelInfo.ChannelList = chan_list;
filter.fMeasurement = true;
/*
* In case this is beacon report request from last AP (before roaming)
* following call to csr_roam_get_session_id_from_bssid will fail,
* hence use current session ID instead of one stored in SME rrm context
*/
if (CDF_STATUS_E_FAILURE == csr_roam_get_session_id_from_bssid(mac_ctx,
&rrm_ctx->sessionBssId, &session_id)) {
sms_log(mac_ctx, LOG1,
FL("BSSID mismatch, using current session_id"));
session_id = mac_ctx->roam.roamSession->sessionId;
}
status = sme_scan_get_result(mac_ctx, (uint8_t) session_id,
&filter, &result_handle);
if (filter.SSIDs.SSIDList) {
/* Free the memory allocated for SSIDList */
cdf_mem_free(filter.SSIDs.SSIDList);
#if defined WLAN_VOWIFI_DEBUG
sms_log(mac_ctx, LOGE, FL("Free memory for SSIDList"));
#endif
}
if (NULL == result_handle) {
/*
* 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 respose 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)
return status;
#if defined(FEATURE_WLAN_ESE_UPLOAD)
if (eRRM_MSG_SOURCE_ESE_UPLOAD == rrm_ctx->msgSource)
status = sme_ese_send_beacon_req_scan_results(mac_ctx,
session_id, chan_list[0],
NULL, measurementdone, 0);
else
#endif /*FEATURE_WLAN_ESE_UPLOAD */
status = sme_rrm_send_beacon_report_xmit_ind(mac_ctx,
NULL, measurementdone, 0);
return status;
}
scan_results = sme_scan_result_get_first(mac_ctx, result_handle);
if (NULL == scan_results && measurementdone) {
#if defined(FEATURE_WLAN_ESE_UPLOAD)
if (eRRM_MSG_SOURCE_ESE_UPLOAD == rrm_ctx->msgSource) {
status = sme_ese_send_beacon_req_scan_results(mac_ctx,
session_id,
chan_list[0],
NULL,
measurementdone,
0);
} else
#endif /*FEATURE_WLAN_ESE_UPLOAD */
status = sme_rrm_send_beacon_report_xmit_ind(mac_ctx,
NULL, measurementdone, 0);
}
counter = 0;
while (scan_results) {
next_result = sme_scan_result_get_next(mac_ctx, result_handle);
if (scan_results->timer >= rrm_scan_timer)
scanresults_arr[counter++] = scan_results;
scan_results = next_result;
if (counter >= SIR_BCN_REPORT_MAX_BSS_DESC)
break;
}
if (counter) {
sms_log(mac_ctx, LOG1,
FL(" Number of BSS Desc with RRM Scan %d "),
counter);
#if defined(FEATURE_WLAN_ESE_UPLOAD)
if (eRRM_MSG_SOURCE_ESE_UPLOAD == rrm_ctx->msgSource)
status = sme_ese_send_beacon_req_scan_results(mac_ctx,
session_id, chan_list[0],
scanresults_arr, measurementdone,
counter);
else
#endif /*FEATURE_WLAN_ESE_UPLOAD */
status = sme_rrm_send_beacon_report_xmit_ind(mac_ctx,
scanresults_arr, measurementdone,
counter);
}
sme_scan_result_purge(mac_ctx, result_handle);
return status;
}
/**
* sme_rrm_scan_request_callback() -Sends the beacon report xmit to PE
* @halHandle - Pointer to the Hal Handle.
* @pContext - Pointer to the data context.
* @scanId - Scan ID.
* @status - CSR Status.
*
* 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.
*
* Return : 0 for success, non zero for failure
*/
static CDF_STATUS sme_rrm_scan_request_callback(tHalHandle halHandle,
void *pContext,
uint8_t sessionId,
uint32_t scanId,
eCsrScanStatus status)
{
uint16_t interval;
tpAniSirGlobal pMac = (tpAniSirGlobal) halHandle;
tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext;
uint32_t time_tick;
#if defined WLAN_VOWIFI_DEBUG
sms_log(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_rrm_send_scan_result(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 randmization interval. */
time_tick = cdf_mc_timer_get_system_ticks();
interval =
time_tick % (pSmeRrmContext->randnIntvl - 10 + 1) + 10;
#if defined WLAN_VOWIFI_DEBUG
sms_log(pMac, LOGE, "Set timer for interval %d ", interval);
#endif
cdf_mc_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_rrm_send_scan_result(pMac, 1,
&pSmeRrmContext->channelList.
ChannelList[pSmeRrmContext->currentIndex],
true);
cdf_mem_free(pSmeRrmContext->channelList.ChannelList);
#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD)
pSmeRrmContext->eseBcnReqInProgress = false;
#endif
#if defined WLAN_VOWIFI_DEBUG
sms_log(pMac, LOGE, FL("Free memory for ChannelList"));
#endif
}
return CDF_STATUS_SUCCESS;
}
/**
* sme_rrm_issue_scan_req() - To issue rrm scan request
* @mac_ctx: pointer to mac context
*
* This routine is called to issue rrm scan request
*
* Return: CDF_STATUS
*/
CDF_STATUS sme_rrm_issue_scan_req(tpAniSirGlobal mac_ctx)
{
/* Issue scan request. */
tCsrScanRequest scan_req;
CDF_STATUS status = CDF_STATUS_SUCCESS;
tpRrmSMEContext sme_rrm_ctx = &mac_ctx->rrm.rrmSmeContext;
uint32_t session_id;
tSirScanType scan_type;
status = csr_roam_get_session_id_from_bssid(mac_ctx,
&sme_rrm_ctx->sessionBssId, &session_id);
if (status != CDF_STATUS_SUCCESS) {
sms_log(mac_ctx, LOGE, FL("Invalid sme Session ID"));
return CDF_STATUS_E_FAILURE;
}
if ((sme_rrm_ctx->currentIndex) >=
sme_rrm_ctx->channelList.numOfChannels)
return status;
if (eRRM_MSG_SOURCE_ESE_UPLOAD == sme_rrm_ctx->msgSource ||
eRRM_MSG_SOURCE_LEGACY_ESE == sme_rrm_ctx->msgSource)
scan_type = sme_rrm_ctx->measMode[sme_rrm_ctx->currentIndex];
else
scan_type = sme_rrm_ctx->measMode[0];
if ((eSIR_ACTIVE_SCAN == scan_type) ||
(eSIR_PASSIVE_SCAN == scan_type)) {
#if defined WLAN_VOWIFI_DEBUG
sms_log(mac_ctx, LOGE, FL("Issue scan request"));
#endif
cdf_mem_zero(&scan_req, sizeof(scan_req));
/* set scan_type, active or passive */
scan_req.bcnRptReqScan = true;
scan_req.scanType = scan_type;
cdf_mem_copy(&scan_req.bssid.bytes, sme_rrm_ctx->bssId,
CDF_MAC_ADDR_SIZE);
if (sme_rrm_ctx->ssId.length) {
scan_req.SSIDs.numOfSSIDs = 1;
scan_req.SSIDs.SSIDList =
(tCsrSSIDInfo *)cdf_mem_malloc(
sizeof(tCsrSSIDInfo));
if (NULL == scan_req.SSIDs.SSIDList) {
sms_log(mac_ctx, LOGP,
FL("cdf_mem_malloc failed"));
return CDF_STATUS_E_NOMEM;
}
#if defined WLAN_VOWIFI_DEBUG
sms_log(mac_ctx, LOGE,
FL("Allocated memory for pSSIDList"));
#endif
cdf_mem_zero(scan_req.SSIDs.SSIDList,
sizeof(tCsrSSIDInfo));
scan_req.SSIDs.SSIDList->SSID.length =
sme_rrm_ctx->ssId.length;
cdf_mem_copy(scan_req.SSIDs.SSIDList->SSID.ssId,
sme_rrm_ctx->ssId.ssId,
sme_rrm_ctx->ssId.length);
}
/*
* set min and max channel time
* sme_rrm_ctx->duration; Dont use min timeout.
*/
scan_req.minChnTime = 0;
if (eRRM_MSG_SOURCE_ESE_UPLOAD == sme_rrm_ctx->msgSource ||
eRRM_MSG_SOURCE_LEGACY_ESE == sme_rrm_ctx->msgSource)
scan_req.maxChnTime = sme_rrm_ctx->duration[
sme_rrm_ctx->currentIndex];
else
scan_req.maxChnTime = sme_rrm_ctx->duration[0];
sms_log(mac_ctx, LOG1, FL("Scan Type(%d) Max Dwell Time(%d)"),
scan_req.scanType, scan_req.maxChnTime);
rrm_scan_timer = cdf_mc_timer_get_system_time();
#if defined WLAN_VOWIFI_DEBUG
sms_log(mac_ctx, LOGE, FL("For Duration %d "),
scan_req.maxChnTime);
#endif
/* set BSSType to default type */
scan_req.BSSType = eCSR_BSS_TYPE_ANY;
/*Scan all the channels */
scan_req.ChannelInfo.numOfChannels = 1;
scan_req.ChannelInfo.ChannelList =
&sme_rrm_ctx->channelList.ChannelList[
sme_rrm_ctx->currentIndex];
#if defined WLAN_VOWIFI_DEBUG
sms_log(mac_ctx, LOGE, FL("On channel %d "),
sme_rrm_ctx->channelList.ChannelList[
sme_rrm_ctx->currentIndex]);
#endif
/* set requestType to full scan */
scan_req.requestType = eCSR_SCAN_REQUEST_FULL_SCAN;
status = sme_scan_request(mac_ctx, (uint8_t) session_id,
&scan_req,
&sme_rrm_scan_request_callback, NULL);
if (sme_rrm_ctx->ssId.length) {
cdf_mem_free(scan_req.SSIDs.SSIDList);
#if defined WLAN_VOWIFI_DEBUG
sms_log(mac_ctx, LOGE, FL("Free memory for SSIDList"));
#endif
}
} else if (eSIR_BEACON_TABLE == scan_type) {
/*
* 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 ((sme_rrm_ctx->currentIndex + 1) <
sme_rrm_ctx->channelList.numOfChannels) {
sme_rrm_send_scan_result(mac_ctx, 1,
&sme_rrm_ctx->channelList.ChannelList[
sme_rrm_ctx->currentIndex], false);
/* Advance the current index. */
sme_rrm_ctx->currentIndex++;
sme_rrm_issue_scan_req(mac_ctx);
#if defined(FEATURE_WLAN_ESE) && defined(FEATURE_WLAN_ESE_UPLOAD)
sme_rrm_ctx->eseBcnReqInProgress = false;
#endif
} else {
/*
* Done with the measurement. Clean up all context and
* send a message to PE with measurement done flag set.
*/
sme_rrm_send_scan_result(mac_ctx, 1,
&sme_rrm_ctx->channelList.ChannelList[
sme_rrm_ctx->currentIndex], true);
cdf_mem_free(sme_rrm_ctx->channelList.ChannelList);
}
} else {
sms_log(mac_ctx, LOGE, FL("Unknown beacon report req mode(%d)"),
scan_type);
/*
* 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_rrm_send_beacon_report_xmit_ind(mac_ctx, NULL, true, 0);
}
return status;
}
/**
* sme_rrm_process_beacon_report_req_ind() -Process beacon report request
* @pMac:- Global Mac structure
* @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.
*
* This is called to process the Beacon
* report request from peer AP forwarded through PE .
*
* Return : CDF_STATUS_SUCCESS - Validation is successful.
*/
CDF_STATUS sme_rrm_process_beacon_report_req_ind(tpAniSirGlobal pMac, void *pMsgBuf)
{
tpSirBeaconReportReqInd pBeaconReq = (tpSirBeaconReportReqInd) pMsgBuf;
tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext;
uint32_t len = 0, i = 0;
CDF_STATUS status = CDF_STATUS_SUCCESS;
#if defined WLAN_VOWIFI_DEBUG
sms_log(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_cfg_get_str_len(pMac, WNI_CFG_VALID_CHANNEL_LIST, &len);
pSmeRrmContext->channelList.ChannelList = cdf_mem_malloc(len);
if (pSmeRrmContext->channelList.ChannelList == NULL) {
sms_log(pMac, LOGP, FL("cdf_mem_malloc failed"));
return CDF_STATUS_E_NOMEM;
}
#if defined WLAN_VOWIFI_DEBUG
sms_log(pMac, LOGE, FL("Allocated memory for ChannelList"));
#endif
csr_get_cfg_valid_channels(pMac,
pSmeRrmContext->channelList.ChannelList,
&len);
pSmeRrmContext->channelList.numOfChannels = (uint8_t) len;
#if defined WLAN_VOWIFI_DEBUG
sms_log(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
sms_log(pMac, LOGE, "channel == 255");
#endif
len += pBeaconReq->channelList.numChannels;
pSmeRrmContext->channelList.ChannelList = cdf_mem_malloc(len);
if (pSmeRrmContext->channelList.ChannelList == NULL) {
sms_log(pMac, LOGP, FL("cdf_mem_malloc failed"));
return CDF_STATUS_E_NOMEM;
}
#if defined WLAN_VOWIFI_DEBUG
sms_log(pMac, LOGE, FL("Allocated memory for ChannelList"));
#endif
if (pBeaconReq->channelInfo.channelNum != 255) {
#if defined WLAN_VOWIFI_DEBUG
sms_log(pMac, LOGE, "channel == %d ",
pBeaconReq->channelInfo.channelNum);
#endif
if (csr_roam_is_channel_valid
(pMac, pBeaconReq->channelInfo.channelNum))
pSmeRrmContext->channelList.
ChannelList[pSmeRrmContext->channelList.
numOfChannels++] =
pBeaconReq->channelInfo.channelNum;
#if defined WLAN_VOWIFI_DEBUG
else
sms_log(pMac, LOGE,
"is Invalid channel, Ignoring this channel");
#endif
}
for (i = 0; i < pBeaconReq->channelList.numChannels; i++) {
if (csr_roam_is_channel_valid
(pMac, pBeaconReq->channelList.channelNumber[i])) {
pSmeRrmContext->channelList.
ChannelList[pSmeRrmContext->channelList.
numOfChannels] =
pBeaconReq->channelList.channelNumber[i];
pSmeRrmContext->channelList.numOfChannels++;
}
}
}
/* Copy session bssid */
cdf_mem_copy(pSmeRrmContext->sessionBssId.bytes, pBeaconReq->bssId,
sizeof(tSirMacAddr));
/* copy measurement bssid */
cdf_mem_copy(pSmeRrmContext->bssId, pBeaconReq->macaddrBssid,
sizeof(tSirMacAddr));
/* Copy ssid */
cdf_mem_copy(&pSmeRrmContext->ssId, &pBeaconReq->ssId,
sizeof(tAniSSID));
pSmeRrmContext->token = pBeaconReq->uDialogToken;
pSmeRrmContext->regClass = pBeaconReq->channelInfo.regulatoryClass;
pSmeRrmContext->randnIntvl =
CDF_MAX(pBeaconReq->randomizationInterval,
pSmeRrmContext->rrmConfig.max_randn_interval);
pSmeRrmContext->currentIndex = 0;
pSmeRrmContext->msgSource = pBeaconReq->msgSource;
cdf_mem_copy((uint8_t *) &pSmeRrmContext->measMode,
(uint8_t *) &pBeaconReq->fMeasurementtype,
SIR_ESE_MAX_MEAS_IE_REQS);
cdf_mem_copy((uint8_t *) &pSmeRrmContext->duration,
(uint8_t *) &pBeaconReq->measurementDuration,
SIR_ESE_MAX_MEAS_IE_REQS);
status = sme_rrm_issue_scan_req(pMac);
return status;
}
/**
* sme_rrm_neighbor_report_request() - This is API can be used to trigger a
* Neighbor report from the peer.
* @sessionId: session identifier on which the request should be made.
* @pNeighborReq: a pointer to a neighbor report request.
*
* This is API can be used to trigger a Neighbor report from the peer.
*
* Return: CDF_STATUS_SUCCESS - Validation is successful.
*/
CDF_STATUS sme_rrm_neighbor_report_request(tpAniSirGlobal pMac, uint8_t sessionId,
tpRrmNeighborReq pNeighborReq,
tpRrmNeighborRspCallbackInfo
callbackInfo)
{
CDF_STATUS status = CDF_STATUS_SUCCESS;
tpSirNeighborReportReqInd pMsg;
tCsrRoamSession *pSession;
#if defined WLAN_VOWIFI_DEBUG
sms_log(pMac, LOGE,
FL("Request to send Neighbor report request received "));
#endif
if (!CSR_IS_SESSION_VALID(pMac, sessionId)) {
sms_log(pMac, LOGE, FL("Invalid session %d"), sessionId);
return CDF_STATUS_E_INVAL;
}
pSession = CSR_GET_SESSION(pMac, sessionId);
/* If already a report is pending, return failure */
if (true ==
pMac->rrm.rrmSmeContext.neighborReqControlInfo.
isNeighborRspPending) {
sms_log(pMac, LOGE,
FL("Neighbor request already pending.. Not allowed"));
return CDF_STATUS_E_AGAIN;
}
pMsg = cdf_mem_malloc(sizeof(tSirNeighborReportReqInd));
if (NULL == pMsg) {
sms_log(pMac, LOGE,
"Unable to allocate memory for Neighbor request");
return CDF_STATUS_E_NOMEM;
}
cdf_mem_zero(pMsg, sizeof(tSirNeighborReportReqInd));
#if defined WLAN_VOWIFI_DEBUG
sms_log(pMac, LOGE, FL(" Allocated memory for Neighbor request"));
#endif
rrm_ll_purge_neighbor_cache(pMac,
&pMac->rrm.rrmSmeContext.neighborReportCache);
#if defined WLAN_VOWIFI_DEBUG
sms_log(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);
cdf_mem_copy(&pMsg->bssId, &pSession->connectedProfile.bssid,
sizeof(tSirMacAddr));
pMsg->noSSID = pNeighborReq->no_ssid;
cdf_mem_copy(&pMsg->ucSSID, &pNeighborReq->ssid, sizeof(tSirMacSSid));
status = cds_send_mb_message_to_mac(pMsg);
if (status != CDF_STATUS_SUCCESS)
return CDF_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 =
true;
/* Start neighbor response wait timer now */
cdf_mc_timer_start(&pMac->rrm.rrmSmeContext.neighborReqControlInfo.
neighborRspWaitTimer, callbackInfo->timeout);
return CDF_STATUS_SUCCESS;
}
/**
* rrm_calculate_neighbor_ap_roam_score() - caclulates roam score
* @mac_ctx: mac global context
* @pNeighborReportDesc: Neighbor BSS Descriptor node for which roam score
* should be calculated
*
* 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.
*
* Return: void
*/
static void
rrm_calculate_neighbor_ap_roam_score(tpAniSirGlobal mac_ctx,
tpRrmNeighborReportDesc nbr_report_desc)
{
tpSirNeighborBssDescripton nbr_bss_desc;
uint32_t roam_score = 0;
#ifdef FEATURE_WLAN_ESE
uint8_t session_id;
#endif
if (NULL == nbr_report_desc) {
CDF_ASSERT(0);
return;
}
if (NULL == nbr_report_desc->pNeighborBssDescription) {
CDF_ASSERT(0);
return;
}
nbr_bss_desc = nbr_report_desc->pNeighborBssDescription;
if (!nbr_bss_desc->bssidInfo.rrmInfo.fMobilityDomain)
goto check_11r_assoc;
roam_score += RRM_ROAM_SCORE_NEIGHBOR_REPORT_MOBILITY_DOMAIN;
if (!nbr_bss_desc->bssidInfo.rrmInfo.fSameSecurityMode)
goto check_11r_assoc;
roam_score += RRM_ROAM_SCORE_NEIGHBOR_REPORT_SECURITY;
if (!nbr_bss_desc->bssidInfo.rrmInfo.fSameAuthenticator)
goto check_11r_assoc;
roam_score += RRM_ROAM_SCORE_NEIGHBOR_REPORT_KEY_SCOPE;
if (!nbr_bss_desc->bssidInfo.rrmInfo.fCapRadioMeasurement)
goto check_11r_assoc;
roam_score += RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_RRM;
if (nbr_bss_desc->bssidInfo.rrmInfo.fCapSpectrumMeasurement)
roam_score +=
RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_SPECTRUM_MGMT;
if (nbr_bss_desc->bssidInfo.rrmInfo.fCapQos)
roam_score += RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_QOS;
if (nbr_bss_desc->bssidInfo.rrmInfo.fCapApsd)
roam_score += RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_APSD;
if (nbr_bss_desc->bssidInfo.rrmInfo.fCapDelayedBlockAck)
roam_score +=
RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_DELAYED_BA;
if (nbr_bss_desc->bssidInfo.rrmInfo.fCapImmediateBlockAck)
roam_score +=
RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_IMMEDIATE_BA;
if (nbr_bss_desc->bssidInfo.rrmInfo.fApPreauthReachable)
roam_score += RRM_ROAM_SCORE_NEIGHBOR_REPORT_REACHABILITY;
check_11r_assoc:
#ifdef FEATURE_WLAN_ESE
session_id = nbr_report_desc->sessionId;
/* It has come in the report so its the best score */
if (csr_neighbor_roam_is11r_assoc(mac_ctx, session_id) == 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.
*/
roam_score += RRM_ROAM_SCORE_NEIGHBOR_IAPP_LIST;
}
#endif
nbr_report_desc->roamScore = roam_score;
}
/**
* rrm_store_neighbor_rpt_by_roam_score()-store Neighbor BSS descriptor
* @pNeighborReportDesc - Neighbor BSS Descriptor node to be stored in cache
*
* 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
*
* Return: void.
*/
void rrm_store_neighbor_rpt_by_roam_score(tpAniSirGlobal pMac,
tpRrmNeighborReportDesc pNeighborReportDesc)
{
tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext;
tListElem *pEntry;
tRrmNeighborReportDesc *pTempNeighborReportDesc;
if (NULL == pNeighborReportDesc) {
CDF_ASSERT(0);
return;
}
if (NULL == pNeighborReportDesc->pNeighborBssDescription) {
CDF_ASSERT(0);
return;
}
if (csr_ll_is_list_empty
(&pSmeRrmContext->neighborReportCache, LL_ACCESS_LOCK)) {
sms_log(pMac, LOGE,
FL
("Neighbor report cache is empty.. Adding a entry now"));
/* Neighbor list cache is empty. Insert this entry in the tail */
csr_ll_insert_tail(&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 =
csr_ll_peek_head(&pSmeRrmContext->neighborReportCache,
LL_ACCESS_LOCK);
while (pEntry != NULL) {
pTempNeighborReportDesc =
GET_BASE_ADDR(pEntry, tRrmNeighborReportDesc, List);
if (pTempNeighborReportDesc->roamScore <
pNeighborReportDesc->roamScore)
break;
pEntry =
csr_ll_next(&pSmeRrmContext->neighborReportCache,
pEntry, LL_ACCESS_LOCK);
}
if (pEntry)
/* This BSS roamscore is better than something in the list. Insert this before that one */
csr_ll_insert_entry(&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 */
csr_ll_insert_tail(&pSmeRrmContext->neighborReportCache,
&pNeighborReportDesc->List,
LL_ACCESS_LOCK);
}
return;
}
/**
* sme_rrm_process_neighbor_report() -Process the Neighbor report received
* from PE
* @pMac - Global MAC structure
* @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.
* This is called to process the Neighbor report received from PE.
*
* Return: CDF_STATUS_SUCCESS - Validation is successful
*/
CDF_STATUS sme_rrm_process_neighbor_report(tpAniSirGlobal pMac, void *pMsgBuf)
{
CDF_STATUS status = CDF_STATUS_SUCCESS;
tpSirNeighborReportInd pNeighborRpt = (tpSirNeighborReportInd) pMsgBuf;
tpRrmNeighborReportDesc pNeighborReportDesc;
uint8_t i = 0;
CDF_STATUS cdf_status = CDF_STATUS_SUCCESS;
uint8_t sessionId;
/* Get the session id */
status =
csr_roam_get_session_id_from_bssid(pMac,
(struct cdf_mac_addr *) pNeighborRpt->bssId,
(uint32_t *) &sessionId);
if (CDF_IS_STATUS_SUCCESS(status)) {
#ifdef FEATURE_WLAN_ESE
/* Clear the cache for ESE. */
if (csr_neighbor_roam_is_ese_assoc(pMac, sessionId)) {
rrm_ll_purge_neighbor_cache(pMac,
&pMac->rrm.rrmSmeContext.
neighborReportCache);
}
#endif
}
for (i = 0; i < pNeighborRpt->numNeighborReports; i++) {
pNeighborReportDesc =
cdf_mem_malloc(sizeof(tRrmNeighborReportDesc));
if (NULL == pNeighborReportDesc) {
sms_log(pMac, LOGE,
"Failed to allocate memory for RRM Neighbor report desc");
status = CDF_STATUS_E_NOMEM;
goto end;
}
cdf_mem_zero(pNeighborReportDesc,
sizeof(tRrmNeighborReportDesc));
pNeighborReportDesc->pNeighborBssDescription =
cdf_mem_malloc(sizeof(tSirNeighborBssDescription));
if (NULL == pNeighborReportDesc->pNeighborBssDescription) {
sms_log(pMac, LOGE,
"Failed to allocate memory for RRM Neighbor report BSS Description");
cdf_mem_free(pNeighborReportDesc);
status = CDF_STATUS_E_NOMEM;
goto end;
}
cdf_mem_zero(pNeighborReportDesc->pNeighborBssDescription,
sizeof(tSirNeighborBssDescription));
cdf_mem_copy(pNeighborReportDesc->pNeighborBssDescription,
&pNeighborRpt->sNeighborBssDescription[i],
sizeof(tSirNeighborBssDescription));
#if defined WLAN_VOWIFI_DEBUG
sms_log(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 */
rrm_calculate_neighbor_ap_roam_score(pMac, pNeighborReportDesc);
/* Store the Neighbor report Desc in the cache based on the roam score */
if (pNeighborReportDesc->roamScore > 0) {
rrm_store_neighbor_rpt_by_roam_score(pMac,
pNeighborReportDesc);
} else {
sms_log(pMac, LOGE,
FL("Roam score of BSSID " MAC_ADDRESS_STR
" is 0, Ignoring.."),
MAC_ADDR_ARRAY(pNeighborRpt->
sNeighborBssDescription[i].
bssId));
cdf_mem_free(pNeighborReportDesc->
pNeighborBssDescription);
cdf_mem_free(pNeighborReportDesc);
}
}
end:
if (!csr_ll_count(&pMac->rrm.rrmSmeContext.neighborReportCache))
cdf_status = CDF_STATUS_E_FAILURE;
/* Received a report from AP. Indicate SUCCESS to the caller if there are some valid reports */
rrm_indicate_neighbor_report_result(pMac, cdf_status);
return status;
}
/**
* sme_rrm_msg_processor()-Process RRM message
* @pMac - Pointer to the global MAC parameter structure.
* @msg_type - the type of msg passed by PE as defined in wni_api.h
* @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.
* sme_process_msg() calls this function for the
* messages that are handled by SME RRM module.
*
* Return: CDF_STATUS_SUCCESS - Validation is successful.
*/
CDF_STATUS sme_rrm_msg_processor(tpAniSirGlobal pMac, uint16_t msg_type,
void *pMsgBuf)
{
CDF_TRACE(CDF_MODULE_ID_SME, CDF_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_rrm_process_neighbor_report(pMac, pMsgBuf);
break;
case eWNI_SME_BEACON_REPORT_REQ_IND:
sme_rrm_process_beacon_report_req_ind(pMac, pMsgBuf);
break;
default:
/* err msg */
CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
FL("sme_rrm_msg_processor:unknown msg type = %d"),
msg_type);
break;
}
return CDF_STATUS_SUCCESS;
}
/**
* rrm_iter_meas_timer_handle() - Timer handler to handlet the timeout
* @ pMac - The handle returned by mac_open.
*
* Timer handler to handlet the timeout condition when a specific BT
* stop event does not come back, in which case to restore back the
* heartbeat timer.
*
* Return: NULL
*/
void rrm_iter_meas_timer_handle(void *userData)
{
tpAniSirGlobal pMac = (tpAniSirGlobal) userData;
#if defined WLAN_VOWIFI_DEBUG
sms_log(pMac, LOGE,
"Randomization timer expired...send on next channel ");
#endif
/* Issue a scan req for next channel. */
sme_rrm_issue_scan_req(pMac);
}
/**
* rrm_neighbor_rsp_timeout_handler() - Timer handler to handlet the timeout
* @pMac - The handle returned by mac_open.
*
* Timer handler to handle the timeout condition when a neighbor request is sent
* and no neighbor response is received from the AP
*
* Return: NULL
*/
void rrm_neighbor_rsp_timeout_handler(void *userData)
{
tpAniSirGlobal pMac = (tpAniSirGlobal) userData;
#if defined WLAN_VOWIFI_DEBUG
sms_log(pMac, LOGE, "Neighbor Response timed out ");
#endif
rrm_indicate_neighbor_report_result(pMac, CDF_STATUS_E_FAILURE);
return;
}
/**
* rrm_open() - Initialze all RRM module
* @ pMac: The handle returned by mac_open.
*
* Initialze all RRM module.
*
* Return: CDF_STATUS
*/
CDF_STATUS rrm_open(tpAniSirGlobal pMac)
{
CDF_STATUS cdf_status;
tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext;
CDF_STATUS cdf_ret_status = CDF_STATUS_SUCCESS;
pSmeRrmContext->rrmConfig.max_randn_interval = 50; /* ms */
cdf_status = cdf_mc_timer_init(&pSmeRrmContext->IterMeasTimer,
CDF_TIMER_TYPE_SW,
rrm_iter_meas_timer_handle, (void *)pMac);
if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
"rrm_open: Fail to init timer");
return CDF_STATUS_E_FAILURE;
}
cdf_status =
cdf_mc_timer_init(&pSmeRrmContext->neighborReqControlInfo.
neighborRspWaitTimer, CDF_TIMER_TYPE_SW,
rrm_neighbor_rsp_timeout_handler, (void *)pMac);
if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
"rrm_open: Fail to init timer");
return CDF_STATUS_E_FAILURE;
}
pSmeRrmContext->neighborReqControlInfo.isNeighborRspPending = false;
cdf_ret_status =
csr_ll_open(pMac->hHdd, &pSmeRrmContext->neighborReportCache);
if (CDF_STATUS_SUCCESS != cdf_ret_status) {
CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
"rrm_open: Fail to open neighbor cache result");
return CDF_STATUS_E_FAILURE;
}
return CDF_STATUS_SUCCESS;
}
/**
* rrm_close() - Release all RRM modules and their resources.
* @pMac - The handle returned by mac_open.
*
* Release all RRM modules and their resources.
*
* Return: CDF_STATUS
* CDF_STATUS_E_FAILURE success
* CDF_STATUS_SUCCESS failure
*/
CDF_STATUS rrm_close(tpAniSirGlobal pMac)
{
CDF_STATUS cdf_status = CDF_STATUS_SUCCESS;
tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext;
if (CDF_TIMER_STATE_RUNNING ==
cdf_mc_timer_get_current_state(&pSmeRrmContext->IterMeasTimer)) {
cdf_status = cdf_mc_timer_stop(&pSmeRrmContext->IterMeasTimer);
if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
FL("Timer stop fail"));
}
}
cdf_status = cdf_mc_timer_destroy(&pSmeRrmContext->IterMeasTimer);
if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_ERROR,
FL("Fail to destroy timer"));
}
if (CDF_TIMER_STATE_RUNNING ==
cdf_mc_timer_get_current_state(&pSmeRrmContext->
neighborReqControlInfo.
neighborRspWaitTimer)) {
cdf_status =
cdf_mc_timer_stop(&pSmeRrmContext->neighborReqControlInfo.
neighborRspWaitTimer);
if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL,
FL("Timer stop fail"));
}
}
cdf_status =
cdf_mc_timer_destroy(&pSmeRrmContext->neighborReqControlInfo.
neighborRspWaitTimer);
if (!CDF_IS_STATUS_SUCCESS(cdf_status)) {
CDF_TRACE(CDF_MODULE_ID_SME, CDF_TRACE_LEVEL_FATAL,
FL("Fail to destroy timer"));
}
rrm_ll_purge_neighbor_cache(pMac, &pSmeRrmContext->neighborReportCache);
csr_ll_close(&pSmeRrmContext->neighborReportCache);
return cdf_status;
}
/* ---------------------------------------------------------------------------
\fn rrm_ready
\brief fn
\param pMac - The handle returned by mac_open.
\return CDF_STATUS
---------------------------------------------------------------------------*/
CDF_STATUS rrm_ready(tpAniSirGlobal pMac)
{
return CDF_STATUS_SUCCESS;
}
/* ---------------------------------------------------------------------------
\fn rrm_change_default_config_param
\brief fn
\param pMac - The handle returned by mac_open.
\param pRrmConfig - pointer to new rrm configs.
\return CDF_STATUS
---------------------------------------------------------------------------*/
CDF_STATUS rrm_change_default_config_param(tpAniSirGlobal pMac,
struct rrm_config_param *rrm_config)
{
cdf_mem_copy(&pMac->rrm.rrmSmeContext.rrmConfig, rrm_config,
sizeof(struct rrm_config_param));
return CDF_STATUS_SUCCESS;
}
/* ---------------------------------------------------------------------------
\fn sme_rrm_get_first_bss_entry_from_neighbor_cache()
\brief This function returns the first entry from the neighbor cache to the caller
\param pMac - The handle returned by mac_open.
\return VOID
---------------------------------------------------------------------------*/
tRrmNeighborReportDesc *sme_rrm_get_first_bss_entry_from_neighbor_cache(tpAniSirGlobal
pMac)
{
tListElem *pEntry;
tRrmNeighborReportDesc *pTempBssEntry = NULL;
tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext;
pEntry =
csr_ll_peek_head(&pSmeRrmContext->neighborReportCache, LL_ACCESS_LOCK);
if (!pEntry || !csr_ll_count(&pSmeRrmContext->neighborReportCache)) {
/* list empty */
sms_log(pMac, LOGW, FL("List empty"));
return NULL;
}
pTempBssEntry = GET_BASE_ADDR(pEntry, tRrmNeighborReportDesc, List);
return pTempBssEntry;
}
/**
* sme_rrm_get_next_bss_entry_from_neighbor_cache() - returns the entry next to
* the given entry
* @ pMac - The handle returned by mac_open.
* @pBssEntry- BSS entry
*
* This function returns the entry next to the given entry from the
* neighbor cache to the caller
*
* Return: NULL
*/
tRrmNeighborReportDesc *sme_rrm_get_next_bss_entry_from_neighbor_cache(
tpAniSirGlobal pMac, tpRrmNeighborReportDesc pBssEntry)
{
tListElem *pEntry;
tRrmNeighborReportDesc *pTempBssEntry = NULL;
pEntry =
csr_ll_next(&pMac->rrm.rrmSmeContext.neighborReportCache,
&pBssEntry->List, LL_ACCESS_LOCK);
if (!pEntry) {
/* list empty */
sms_log(pMac, LOGW, FL("List empty"));
return NULL;
}
pTempBssEntry = GET_BASE_ADDR(pEntry, tRrmNeighborReportDesc, List);
return pTempBssEntry;
}
#endif