blob: 8df864fc35b1d34a2247fb4013cb3cb9246c6921 [file] [log] [blame]
/*
* Copyright (c) 2011-2017 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 csrApiScan.c
Implementation for the Common Scan interfaces.
========================================================================== */
#include "aniGlobal.h"
#include "palApi.h"
#include "csrInsideApi.h"
#include "smeInside.h"
#include "smsDebug.h"
#include "csrSupport.h"
#include "wlan_qct_tl.h"
#include "vos_diag_core_log.h"
#include "vos_diag_core_event.h"
#include "vos_nvitem.h"
#include "vos_memory.h"
#include "wlan_qct_wda.h"
#include "vos_utils.h"
#define MIN_CHN_TIME_TO_FIND_GO 100
#define MAX_CHN_TIME_TO_FIND_GO 100
#define DIRECT_SSID_LEN 7
/*
* Purpose of HIDDEN_TIMER
* When we remove hidden ssid from the profile i.e., forget the SSID via GUI
* that SSID shouldn't see in the profile for above requirement we used timer
* limit, logic is explained below timer value is initialized to current time
* when it receives corresponding probe response of hidden SSID
* (The probe request is received regularly till SSID in the profile.
* Once it is removed from profile probe request is not sent.) when we receive
* probe response for broadcast probe request, during update SSID with saved
* SSID we will diff current time with saved SSID time if it is greater than
* 1 min then we are not updating with old one.
*/
#define HIDDEN_TIMER (1*60*1000)
/* Must be less than 100, represent the percentage of new RSSI */
#define CSR_SCAN_RESULT_RSSI_WEIGHT 80
#define CSR_PURGE_RSSI_THRESHOLD -70
#define MAX_ACTIVE_SCAN_FOR_ONE_CHANNEL 140
#define MIN_ACTIVE_SCAN_FOR_ONE_CHANNEL 120
#define MAX_ACTIVE_SCAN_FOR_ONE_CHANNEL_FASTREASSOC 30
#define MIN_ACTIVE_SCAN_FOR_ONE_CHANNEL_FASTREASSOC 20
#define CSR_SCAN_IS_OVER_BSS_LIMIT(pMac) \
( (pMac)->scan.nBssLimit <= (csrLLCount(&(pMac)->scan.scanResultList)) )
//*** This is temporary work around. It need to call CCM api to get to CFG later
/// Get string parameter value
extern tSirRetStatus wlan_cfgGetStr(tpAniSirGlobal, tANI_U16, tANI_U8*, tANI_U32*);
void csrScanGetResultTimerHandler(void *);
static void csrPurgeScanResultByAge(void *pv);
void csrScanIdleScanTimerHandler(void *);
static void csrSetDefaultScanTiming( tpAniSirGlobal pMac, tSirScanType scanType, tCsrScanRequest *pScanRequest);
tANI_BOOLEAN csrIsSupportedChannel(tpAniSirGlobal pMac, tANI_U8 channelId);
eHalStatus csrScanChannels( tpAniSirGlobal pMac, tSmeCmd *pCommand );
void csrSetCfgValidChannelList( tpAniSirGlobal pMac, tANI_U8 *pChannelList, tANI_U8 NumChannels );
void csrSaveTxPowerToCfg( tpAniSirGlobal pMac, tDblLinkList *pList, tANI_U32 cfgId );
void csrSetCfgCountryCode( tpAniSirGlobal pMac, tANI_U8 *countryCode );
void csrPurgeChannelPower( tpAniSirGlobal pMac, tDblLinkList *pChannelList );
//if bgPeriod is 0, background scan is disabled. It is in millisecond units
eHalStatus csrSetCfgBackgroundScanPeriod(tpAniSirGlobal pMac, tANI_U32 bgPeriod);
eHalStatus csrProcessSetBGScanParam(tpAniSirGlobal pMac, tSmeCmd *pCommand);
void csrReleaseScanCommand(tpAniSirGlobal pMac, tSmeCmd *pCommand, eCsrScanStatus scanStatus);
static tANI_BOOLEAN csrScanValidateScanResult( tpAniSirGlobal pMac, tANI_U8 *pChannels,
tANI_U8 numChn, tSirBssDescription *pBssDesc,
tDot11fBeaconIEs **ppIes );
eHalStatus csrSetBGScanChannelList( tpAniSirGlobal pMac, tANI_U8 *pAdjustChannels, tANI_U8 NumAdjustChannels);
void csrReleaseCmdSingle(tpAniSirGlobal pMac, tSmeCmd *pCommand);
tANI_BOOLEAN csrRoamIsValidChannel( tpAniSirGlobal pMac, tANI_U8 channel );
void csrPruneChannelListForMode( tpAniSirGlobal pMac, tCsrChannel *pChannelList );
void csr_purge_scan_result(tpAniSirGlobal mac_ctx);
#define CSR_IS_SOCIAL_CHANNEL(channel) (((channel) == 1) || ((channel) == 6) || ((channel) == 11) )
static void csrReleaseScanCmdPendingList(tpAniSirGlobal pMac)
{
tListElem *pEntry;
tSmeCmd *pCommand;
while((pEntry = csrLLRemoveHead( &pMac->scan.scanCmdPendingList, LL_ACCESS_LOCK)) != NULL)
{
pCommand = GET_BASE_ADDR( pEntry, tSmeCmd, Link );
if ( eSmeCsrCommandMask & pCommand->command )
{
csrAbortCommand( pMac, pCommand, eANI_BOOLEAN_TRUE );
}
else
{
smsLog(pMac, LOGE, FL("Error: Received command : %d"),pCommand->command);
}
}
}
//pResult is invalid calling this function.
void csrFreeScanResultEntry( tpAniSirGlobal pMac, tCsrScanResult *pResult )
{
if( NULL != pResult->Result.pvIes )
{
vos_mem_free(pResult->Result.pvIes);
}
vos_mem_free(pResult);
}
static eHalStatus csrLLScanPurgeResult(tpAniSirGlobal pMac, tDblLinkList *pList)
{
eHalStatus status = eHAL_STATUS_SUCCESS;
tListElem *pEntry;
tCsrScanResult *pBssDesc;
csrLLLock(pList);
while((pEntry = csrLLRemoveHead(pList, LL_ACCESS_NOLOCK)) != NULL)
{
pBssDesc = GET_BASE_ADDR( pEntry, tCsrScanResult, Link );
csrFreeScanResultEntry( pMac, pBssDesc );
}
csrLLUnlock(pList);
return (status);
}
eHalStatus csrScanOpen( tpAniSirGlobal pMac )
{
eHalStatus status;
do
{
csrLLOpen(pMac->hHdd, &pMac->scan.scanResultList);
csrLLOpen(pMac->hHdd, &pMac->scan.tempScanResults);
csrLLOpen(pMac->hHdd, &pMac->scan.channelPowerInfoList24);
csrLLOpen(pMac->hHdd, &pMac->scan.channelPowerInfoList5G);
#ifdef WLAN_AP_STA_CONCURRENCY
csrLLOpen(pMac->hHdd, &pMac->scan.scanCmdPendingList);
#endif
pMac->scan.fFullScanIssued = eANI_BOOLEAN_FALSE;
pMac->scan.nBssLimit = CSR_MAX_BSS_SUPPORT;
status = vos_timer_init(&pMac->scan.hTimerGetResult, VOS_TIMER_TYPE_SW, csrScanGetResultTimerHandler, pMac);
if (!HAL_STATUS_SUCCESS(status))
{
smsLog(pMac, LOGE, FL("cannot allocate memory for getResult timer"));
break;
}
status = vos_timer_init(&pMac->scan.hTimerIdleScan, VOS_TIMER_TYPE_SW, csrScanIdleScanTimerHandler, pMac);
if (!HAL_STATUS_SUCCESS(status))
{
smsLog(pMac, LOGE, FL("cannot allocate memory for idleScan timer"));
break;
}
}while(0);
return (status);
}
eHalStatus csrScanClose( tpAniSirGlobal pMac )
{
csrLLScanPurgeResult(pMac, &pMac->scan.tempScanResults);
csrLLScanPurgeResult(pMac, &pMac->scan.scanResultList);
#ifdef WLAN_AP_STA_CONCURRENCY
csrReleaseScanCmdPendingList(pMac);
#endif
csrLLClose(&pMac->scan.scanResultList);
csrLLClose(&pMac->scan.tempScanResults);
#ifdef WLAN_AP_STA_CONCURRENCY
csrLLClose(&pMac->scan.scanCmdPendingList);
#endif
csrPurgeChannelPower(pMac, &pMac->scan.channelPowerInfoList24);
csrPurgeChannelPower(pMac, &pMac->scan.channelPowerInfoList5G);
csrLLClose(&pMac->scan.channelPowerInfoList24);
csrLLClose(&pMac->scan.channelPowerInfoList5G);
csrScanDisable(pMac);
vos_timer_destroy(&pMac->scan.hTimerGetResult);
vos_timer_destroy(&pMac->scan.hTimerIdleScan);
return eHAL_STATUS_SUCCESS;
}
eHalStatus csrScanEnable( tpAniSirGlobal pMac )
{
pMac->scan.fScanEnable = eANI_BOOLEAN_TRUE;
pMac->scan.fRestartIdleScan = eANI_BOOLEAN_TRUE;
return eHAL_STATUS_SUCCESS;
}
eHalStatus csrScanDisable( tpAniSirGlobal pMac )
{
csrScanStopTimers(pMac);
pMac->scan.fScanEnable = eANI_BOOLEAN_FALSE;
return eHAL_STATUS_SUCCESS;
}
//Set scan timing parameters according to state of other driver sessions
//No validation of the parameters is performed.
static void csrSetDefaultScanTiming( tpAniSirGlobal pMac, tSirScanType scanType, tCsrScanRequest *pScanRequest)
{
#ifdef WLAN_AP_STA_CONCURRENCY
if(csrIsAnySessionConnected(pMac))
{
/* Reset passive scan time as per ini parameter. */
ccmCfgSetInt(pMac, WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME,
pMac->roam.configParam.nPassiveMaxChnTimeConc,
NULL, false);
//If multi-session, use the appropriate default scan times
if(scanType == eSIR_ACTIVE_SCAN)
{
pScanRequest->maxChnTime = pMac->roam.configParam.nActiveMaxChnTimeConc;
pScanRequest->minChnTime = pMac->roam.configParam.nActiveMinChnTimeConc;
}
else
{
pScanRequest->maxChnTime = pMac->roam.configParam.nPassiveMaxChnTimeConc;
pScanRequest->minChnTime = pMac->roam.configParam.nPassiveMinChnTimeConc;
}
pScanRequest->restTime = pMac->roam.configParam.nRestTimeConc;
pScanRequest->min_rest_time = pMac->roam.configParam.min_rest_time_conc;
pScanRequest->idle_time = pMac->roam.configParam.idle_time_conc;
//Return so that fields set above will not be overwritten.
return;
}
#endif
//This portion of the code executed if multi-session not supported
//(WLAN_AP_STA_CONCURRENCY not defined) or no multi-session.
//Use the "regular" (non-concurrency) default scan timing.
ccmCfgSetInt(pMac, WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME,
pMac->roam.configParam.nPassiveMaxChnTime,
NULL,eANI_BOOLEAN_FALSE);
if(pScanRequest->scanType == eSIR_ACTIVE_SCAN)
{
pScanRequest->maxChnTime = pMac->roam.configParam.nActiveMaxChnTime;
pScanRequest->minChnTime = pMac->roam.configParam.nActiveMinChnTime;
}
else
{
pScanRequest->maxChnTime = pMac->roam.configParam.nPassiveMaxChnTime;
pScanRequest->minChnTime = pMac->roam.configParam.nPassiveMinChnTime;
}
#ifdef WLAN_AP_STA_CONCURRENCY
/* No rest time/Idle time if no sessions are connected. */
pScanRequest->restTime = 0;
pScanRequest->min_rest_time = 0;
pScanRequest->idle_time = 0;
#endif
}
#ifdef WLAN_AP_STA_CONCURRENCY
//Return SUCCESS is the command is queued, else returns eHAL_STATUS_FAILURE
eHalStatus csrQueueScanRequest(tpAniSirGlobal pMac, tANI_U8 sessionId,
tSmeCmd *pScanCmd)
{
eHalStatus status = eHAL_STATUS_SUCCESS;
tANI_BOOLEAN fNoCmdPending;
tSmeCmd *pQueueScanCmd=NULL;
tSmeCmd *pSendScanCmd=NULL;
if (NULL == pScanCmd)
{
smsLog (pMac, LOGE, FL("Scan Req cmd is NULL"));
return eHAL_STATUS_FAILURE;
}
if ( (csrIsStaSessionConnected(pMac) &&
#ifdef FEATURE_WLAN_LFR
(csrIsConcurrentInfraConnected(pMac) ||
((pScanCmd->u.scanCmd.reason != eCsrScanBgScan) &&
(pMac->roam.neighborRoamInfo[sessionId].neighborRoamState !=
eCSR_NEIGHBOR_ROAM_STATE_CFG_CHAN_LIST_SCAN))) &&
#endif
(pScanCmd->u.scanCmd.u.scanRequest.p2pSearch != 1)) ||
(csrIsP2pOrSapSessionConnected(pMac)))
{
tANI_U8 numChn = pScanCmd->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels;
tANI_BOOLEAN bMemAlloc = eANI_BOOLEAN_FALSE;
if (numChn == 0)
{
numChn = pMac->scan.baseChannels.numChannels;
pScanCmd->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList = vos_mem_malloc(numChn);
if ( NULL == pScanCmd->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList )
{
smsLog( pMac, LOGE, FL(" Failed to get memory for channel list ") );
return eHAL_STATUS_FAILURE;
}
bMemAlloc = eANI_BOOLEAN_TRUE;
vos_mem_copy(pScanCmd->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList,
pMac->scan.baseChannels.channelList, numChn);
status = eHAL_STATUS_SUCCESS;
if( !HAL_STATUS_SUCCESS( status ) )
{
vos_mem_free(pScanCmd->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList);
pScanCmd->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList = NULL;
smsLog( pMac, LOGE, FL(" Failed to copy memory to channel list ") );
return eHAL_STATUS_FAILURE;
}
pScanCmd->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels = numChn;
}
pSendScanCmd = pScanCmd;
pSendScanCmd->u.scanCmd.u.scanRequest.BSSType = eCSR_BSS_TYPE_ANY;
//Use concurrency values for min/maxChnTime.
//We know csrIsAnySessionConnected(pMac) returns TRUE here
csrSetDefaultScanTiming(pMac, pSendScanCmd->u.scanCmd.u.scanRequest.scanType, &pSendScanCmd->u.scanCmd.u.scanRequest);
fNoCmdPending = csrLLIsListEmpty( &pMac->scan.scanCmdPendingList, LL_ACCESS_LOCK );
//Logic Below is as follows
// If the scanCmdPendingList is empty then we directly send that command
// to smeCommandQueue else we buffer it in our scanCmdPendingList Queue
if( fNoCmdPending )
{
if (pQueueScanCmd != NULL)
{
csrLLInsertTail( &pMac->scan.scanCmdPendingList, &pQueueScanCmd->Link, LL_ACCESS_LOCK );
}
if (pSendScanCmd != NULL)
{
return csrQueueSmeCommand(pMac, pSendScanCmd, eANI_BOOLEAN_FALSE);
}
}
else
{
if (pSendScanCmd != NULL)
{
csrLLInsertTail( &pMac->scan.scanCmdPendingList, &pSendScanCmd->Link, LL_ACCESS_LOCK );
}
if (pQueueScanCmd != NULL)
{
csrLLInsertTail( &pMac->scan.scanCmdPendingList, &pQueueScanCmd->Link, LL_ACCESS_LOCK );
}
}
}
else
{ //No concurrency case
smsLog( pMac, LOG2, FL("Queuing scan command (reason=%d, roamState=%d"
" numOfChannels=%d)"),
pScanCmd->u.scanCmd.reason,
pMac->roam.neighborRoamInfo[sessionId].neighborRoamState,
pScanCmd->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels);
return csrQueueSmeCommand(pMac, pScanCmd, eANI_BOOLEAN_FALSE);
}
return ( status );
}
#endif
/**
* csrScan2GOnyRequest() - This function will update the scan request with
* only 2.4GHz valid channel list.
* @mac_ctx: Pointer to Global MAC structure
* @scan_cmd scan cmd
* @scan_req scan req
*
* This function will update the scan request with only 2.4GHz valid channel
* list.
*
* @Return: status of operation
*/
static eHalStatus csrScan2GOnyRequest(tpAniSirGlobal mac_ctx,
tSmeCmd *scan_cmd,
tCsrScanRequest *scan_req)
{
uint8_t idx, lst_sz = 0;
VOS_ASSERT(scan_cmd && scan_req);
/* To silence the KW tool null check is added */
if ((scan_cmd == NULL) || (scan_req == NULL)) {
smsLog(mac_ctx, LOGE, FL(" Scan Cmd or Scan Request is NULL "));
return eHAL_STATUS_INVALID_PARAMETER;
}
if (eCSR_SCAN_REQUEST_FULL_SCAN != scan_req->requestType)
return eHAL_STATUS_SUCCESS;
smsLog(mac_ctx, LOG1,
FL("Scanning only 2G Channels during first scan"));
/* Contsruct valid Supported 2.4 GHz Channel List */
if (NULL == scan_req->ChannelInfo.ChannelList) {
scan_req->ChannelInfo.ChannelList =
vos_mem_malloc(NUM_2_4GHZ_CHANNELS);
if (NULL == scan_req->ChannelInfo.ChannelList) {
smsLog(mac_ctx, LOGE, FL("Memory allocation failed."));
return eHAL_STATUS_FAILED_ALLOC;
}
for (idx = 1; idx <= NUM_2_4GHZ_CHANNELS; idx++) {
if (csrIsSupportedChannel(mac_ctx, idx)) {
scan_req->ChannelInfo.ChannelList[lst_sz] = idx;
lst_sz++;
}
}
}
else {
for (idx = 0; idx < scan_req->ChannelInfo.numOfChannels; idx++) {
if (scan_req->ChannelInfo.ChannelList[idx] <= VOS_24_GHZ_CHANNEL_14
&& csrIsSupportedChannel(mac_ctx,
scan_req->ChannelInfo.ChannelList[idx])) {
scan_req->ChannelInfo.ChannelList[lst_sz] =
scan_req->ChannelInfo.ChannelList[idx];
lst_sz++;
}
}
}
scan_req->ChannelInfo.numOfChannels = lst_sz;
return eHAL_STATUS_SUCCESS;
}
eHalStatus csrScanRequest(tpAniSirGlobal pMac, tANI_U16 sessionId,
tCsrScanRequest *pScanRequest, tANI_U32 *pScanRequestID,
csrScanCompleteCallback callback, void *pContext)
{
eHalStatus status = eHAL_STATUS_FAILURE;
tSmeCmd *pScanCmd = NULL;
if(pScanRequest == NULL)
{
smsLog( pMac, LOGE, FL(" pScanRequest is NULL"));
VOS_ASSERT(0);
return status;
}
/* During group formation, the P2P client scans for GO with the specific SSID.
* There will be chances of GO switching to other channels because of scan or
* to STA channel in case of STA+GO MCC scenario. So to increase the possibility
* of client to find the GO, the dwell time of scan is increased to 100ms.
*/
if(pScanRequest->p2pSearch)
{
if ((pScanRequest->SSIDs.numOfSSIDs) && (NULL != pScanRequest->SSIDs.SSIDList))
{
//If the scan request is for specific SSId the length of SSID will be
//greater than 7 as SSID for p2p search contains "DIRECT-")
if(pScanRequest->SSIDs.SSIDList->SSID.length > DIRECT_SSID_LEN)
{
smsLog( pMac, LOG1, FL("P2P: Increasing the min and max Dwell"
" time to %d for specific SSID scan %.*s"),
MAX_CHN_TIME_TO_FIND_GO,
pScanRequest->SSIDs.SSIDList->SSID.length,
pScanRequest->SSIDs.SSIDList->SSID.ssId);
pScanRequest->maxChnTime = MAX_CHN_TIME_TO_FIND_GO;
pScanRequest->minChnTime = MIN_CHN_TIME_TO_FIND_GO;
}
}
}
do
{
if(pMac->scan.fScanEnable)
{
pScanCmd = csrGetCommandBuffer(pMac);
if(pScanCmd)
{
vos_mem_set(&pScanCmd->u.scanCmd, sizeof(tScanCmd), 0);
pScanCmd->command = eSmeCommandScan;
pScanCmd->sessionId = sessionId;
if (pScanCmd->sessionId >= CSR_ROAM_SESSION_MAX)
smsLog( pMac, LOGE, FL("Invalid Sme Session ID = %d"), sessionId);
pScanCmd->u.scanCmd.callback = callback;
pScanCmd->u.scanCmd.pContext = pContext;
if(eCSR_SCAN_REQUEST_11D_SCAN == pScanRequest->requestType)
{
pScanCmd->u.scanCmd.reason = eCsrScan11d1;
}
else if((eCSR_SCAN_REQUEST_FULL_SCAN == pScanRequest->requestType) ||
(eCSR_SCAN_P2P_DISCOVERY == pScanRequest->requestType)
#ifdef SOFTAP_CHANNEL_RANGE
||(eCSR_SCAN_SOFTAP_CHANNEL_RANGE == pScanRequest->requestType)
#endif
)
{
pScanCmd->u.scanCmd.reason = eCsrScanUserRequest;
}
else if(eCSR_SCAN_HO_BG_SCAN == pScanRequest->requestType)
{
pScanCmd->u.scanCmd.reason = eCsrScanBgScan;
}
else if(eCSR_SCAN_HO_PROBE_SCAN == pScanRequest->requestType)
{
pScanCmd->u.scanCmd.reason = eCsrScanProbeBss;
}
else if(eCSR_SCAN_P2P_FIND_PEER == pScanRequest->requestType)
{
pScanCmd->u.scanCmd.reason = eCsrScanP2PFindPeer;
}
else
{
pScanCmd->u.scanCmd.reason = eCsrScanIdleScan;
}
if(pScanRequest->minChnTime == 0 && pScanRequest->maxChnTime == 0)
{
//The caller doesn't set the time correctly. Set it here
csrSetDefaultScanTiming(pMac, pScanRequest->scanType,
pScanRequest);
smsLog(pMac, LOG1, FL("Setting default min %d and max %d"
" ChnTime"), pScanRequest->minChnTime,
pScanRequest->maxChnTime);
}
#ifdef WLAN_AP_STA_CONCURRENCY
if(pScanRequest->restTime == 0)
{
/* Need to set restTime/min_Ret_time/idle_time only
* if at least one session is connected
*/
if(csrIsAnySessionConnected(pMac))
{
pScanRequest->restTime = pMac->roam.configParam.nRestTimeConc;
pScanRequest->min_rest_time = pMac->roam.configParam.min_rest_time_conc;
pScanRequest->idle_time = pMac->roam.configParam.idle_time_conc;
if(pScanRequest->scanType == eSIR_ACTIVE_SCAN)
{
pScanRequest->maxChnTime = pMac->roam.configParam.nActiveMaxChnTimeConc;
pScanRequest->minChnTime = pMac->roam.configParam.nActiveMinChnTimeConc;
}
else
{
pScanRequest->maxChnTime = pMac->roam.configParam.nPassiveMaxChnTimeConc;
pScanRequest->minChnTime = pMac->roam.configParam.nPassiveMinChnTimeConc;
}
}
}
#endif
/* Increase dwell time in case P2P Search and Miracast is not present*/
if(pScanRequest->p2pSearch &&
pScanRequest->ChannelInfo.numOfChannels == P2P_SOCIAL_CHANNELS
&& (!(pMac->sme.miracast_value))) {
pScanRequest->maxChnTime += P2P_SEARCH_DWELL_TIME_INCREASE;
}
//Need to make the following atomic
pScanCmd->u.scanCmd.scanID = pMac->scan.nextScanID++; //let it wrap around
if(pScanRequestID)
{
*pScanRequestID = pScanCmd->u.scanCmd.scanID;
}
// If it is the first scan request from HDD, CSR checks if it is for 11d.
// If it is not, CSR will save the scan request in the pending cmd queue
// & issue an 11d scan request to PE.
if (((false == pMac->first_scan_done)
&& (eCSR_SCAN_REQUEST_11D_SCAN != pScanRequest->requestType))
#ifdef SOFTAP_CHANNEL_RANGE
&& (eCSR_SCAN_SOFTAP_CHANNEL_RANGE != pScanRequest->requestType)
#endif
&& (eANI_BOOLEAN_FALSE == pMac->scan.fEnableBypass11d)
)
{
tSmeCmd *p11dScanCmd;
tCsrScanRequest scanReq;
tCsrChannelInfo *pChnInfo = &scanReq.ChannelInfo;
vos_mem_set(&scanReq, sizeof(tCsrScanRequest), 0);
p11dScanCmd = csrGetCommandBuffer(pMac);
if (p11dScanCmd)
{
tANI_U32 numChn = pMac->scan.baseChannels.numChannels;
if (numChn > WNI_CFG_VALID_CHANNEL_LIST_LEN) {
smsLog(pMac, LOGE,
FL("Invalid number of channels: %d"), numChn);
status = eHAL_STATUS_FAILURE;
break;
}
vos_mem_set(&p11dScanCmd->u.scanCmd, sizeof(tScanCmd), 0);
pChnInfo->ChannelList = vos_mem_malloc(numChn);
if ( NULL == pChnInfo->ChannelList )
{
smsLog(pMac, LOGE, FL("Failed to allocate memory"));
status = eHAL_STATUS_FAILURE;
break;
}
vos_mem_copy(pChnInfo->ChannelList,
pMac->scan.baseChannels.channelList,
numChn);
pChnInfo->numOfChannels = (tANI_U8)numChn;
p11dScanCmd->command = eSmeCommandScan;
p11dScanCmd->u.scanCmd.callback = pMac->scan.callback11dScanDone;
p11dScanCmd->u.scanCmd.pContext = NULL;
p11dScanCmd->u.scanCmd.scanID = pMac->scan.nextScanID++;
scanReq.BSSType = eCSR_BSS_TYPE_ANY;
if ( csrIs11dSupported(pMac) )
{
scanReq.scanType = eSIR_PASSIVE_SCAN;
scanReq.requestType = eCSR_SCAN_REQUEST_11D_SCAN;
p11dScanCmd->u.scanCmd.reason = eCsrScan11d1;
scanReq.maxChnTime = pMac->roam.configParam.nPassiveMaxChnTime;
scanReq.minChnTime = pMac->roam.configParam.nPassiveMinChnTime;
}
else
{
scanReq.scanType = pScanRequest->scanType;
scanReq.requestType = eCSR_SCAN_IDLE_MODE_SCAN;
p11dScanCmd->u.scanCmd.reason = eCsrScanIdleScan;
scanReq.maxChnTime = pMac->roam.configParam.nActiveMaxChnTime;
scanReq.minChnTime = pMac->roam.configParam.nActiveMinChnTime;
}
if (pMac->roam.configParam.nInitialDwellTime)
{
scanReq.maxChnTime =
pMac->roam.configParam.nInitialDwellTime;
smsLog(pMac, LOG1, FL("11d scan, updating"
"dwell time for first scan %u"),
scanReq.maxChnTime);
}
status = csrScanCopyRequest(pMac, &p11dScanCmd->u.scanCmd.u.scanRequest, &scanReq);
//Free the channel list
vos_mem_free(pChnInfo->ChannelList);
pChnInfo->ChannelList = NULL;
if (HAL_STATUS_SUCCESS(status))
{
pMac->scan.scanProfile.numOfChannels =
p11dScanCmd->u.scanCmd.u.scanRequest.
ChannelInfo.numOfChannels;
//Start process the command
#ifdef WLAN_AP_STA_CONCURRENCY
if (!pMac->fScanOffload)
status = csrQueueScanRequest(pMac, sessionId,
p11dScanCmd);
else
status = csrQueueSmeCommand(pMac, p11dScanCmd,
eANI_BOOLEAN_FALSE);
#else
status = csrQueueSmeCommand(pMac, p11dScanCmd, eANI_BOOLEAN_FALSE);
#endif
if( !HAL_STATUS_SUCCESS( status ) )
{
smsLog( pMac, LOGE, FL(" Failed to send message"
" status = %d"), status);
break;
}
}
else
{
smsLog(pMac, LOGE, FL("csrScanCopyRequest failed"));
break;
}
}
else
{
//error
smsLog( pMac, LOGE, FL("p11dScanCmd failed") );
break;
}
}
//Scan only 2G Channels if set in ini file
//This is mainly to reduce the First Scan duration
//Once we turn on Wifi
if(pMac->scan.fFirstScanOnly2GChnl
&& false == pMac->first_scan_done) {
status = csrScan2GOnyRequest(pMac, pScanCmd, pScanRequest);
if (!HAL_STATUS_SUCCESS(status)) {
smsLog(pMac, LOGE, FL("csrScan2GOnyRequest failed."));
break;
}
}
pMac->first_scan_done = true;
if (pMac->roam.configParam.nInitialDwellTime)
{
pScanRequest->maxChnTime =
pMac->roam.configParam.nInitialDwellTime;
pMac->roam.configParam.nInitialDwellTime = 0;
smsLog(pMac, LOG1,
FL("updating dwell time for first scan %u"),
pScanRequest->maxChnTime);
}
status = csrScanCopyRequest(pMac, &pScanCmd->u.scanCmd.u.scanRequest, pScanRequest);
/*
* Reset the variable after the first scan is queued after
* loading the driver. The purpose of this parameter is that
* DFS channels are skipped during the first scan after loading
* the driver. The above API builds the target scan request in
* which this variable is used.
*/
pMac->roam.configParam.initial_scan_no_dfs_chnl = 0;
if(HAL_STATUS_SUCCESS(status))
{
tCsrScanRequest *pTempScanReq =
&pScanCmd->u.scanCmd.u.scanRequest;
pMac->scan.scanProfile.numOfChannels =
pTempScanReq->ChannelInfo.numOfChannels;
smsLog(pMac, LOG1, FL(" SId=%d scanId=%d"
" Scan reason=%u numSSIDs=%d"
" numChan=%d P2P search=%d minCT=%d maxCT=%d"
" minCBtc=%d maxCBtx=%d uIEFieldLen=%d"),
sessionId, pScanCmd->u.scanCmd.scanID,
pScanCmd->u.scanCmd.reason,
pTempScanReq->SSIDs.numOfSSIDs,
pTempScanReq->ChannelInfo.numOfChannels,
pTempScanReq->p2pSearch,
pTempScanReq->minChnTime,
pTempScanReq->maxChnTime,
pTempScanReq->minChnTimeBtc,
pTempScanReq->maxChnTimeBtc,
pTempScanReq->uIEFieldLen);
//Start process the command
#ifdef WLAN_AP_STA_CONCURRENCY
if (!pMac->fScanOffload)
status = csrQueueScanRequest(pMac, sessionId, pScanCmd);
else
status = csrQueueSmeCommand(pMac, pScanCmd,
eANI_BOOLEAN_FALSE);
#else
status = csrQueueSmeCommand(pMac, pScanCmd, eANI_BOOLEAN_FALSE);
#endif
if( !HAL_STATUS_SUCCESS( status ) )
{
smsLog( pMac, LOGE, FL(" fail to send message status = %d"), status );
break;
}
}
else
{
smsLog( pMac, LOGE, FL(" fail to copy request status = %d"), status );
break;
}
}
else
{
smsLog( pMac, LOGE, FL(" pScanCmd is NULL"));
break;
}
}
else
{
smsLog( pMac, LOGE, FL("SId: %d Scanning not enabled"
" Scan type=%u, numOfSSIDs=%d P2P search=%d"),
sessionId, pScanRequest->requestType,
pScanRequest->SSIDs.numOfSSIDs,
pScanRequest->p2pSearch );
}
} while(0);
if(!HAL_STATUS_SUCCESS(status) && pScanCmd)
{
if( eCsrScanIdleScan == pScanCmd->u.scanCmd.reason )
{
//Set the flag back for restarting idle scan
pMac->scan.fRestartIdleScan = eANI_BOOLEAN_TRUE;
}
smsLog( pMac, LOGE, FL(" SId: %d Failed with status=%d"
" Scan reason=%u numOfSSIDs=%d"
" P2P search=%d scanId=%d"),
sessionId, status, pScanCmd->u.scanCmd.reason,
pScanRequest->SSIDs.numOfSSIDs, pScanRequest->p2pSearch,
pScanCmd->u.scanCmd.scanID );
csrReleaseCommandScan(pMac, pScanCmd);
}
return (status);
}
eHalStatus csrScanRequestResult(tpAniSirGlobal pMac)
{
eHalStatus status = eHAL_STATUS_SUCCESS;
tSmeCmd *pScanCmd;
if(pMac->scan.fScanEnable)
{
pScanCmd = csrGetCommandBuffer(pMac);
if(pScanCmd)
{
pScanCmd->command = eSmeCommandScan;
vos_mem_set(&pScanCmd->u.scanCmd, sizeof(tScanCmd), 0);
pScanCmd->u.scanCmd.callback = NULL;
pScanCmd->u.scanCmd.pContext = NULL;
pScanCmd->u.scanCmd.reason = eCsrScanGetResult;
//Need to make the following atomic
pScanCmd->u.scanCmd.scanID = pMac->scan.nextScanID; //let it wrap around
status = csrQueueSmeCommand(pMac, pScanCmd, eANI_BOOLEAN_FALSE);
if( !HAL_STATUS_SUCCESS( status ) )
{
smsLog( pMac, LOGE, FL(" fail to send message status = %d"), status );
csrReleaseCommandScan(pMac, pScanCmd);
}
}
else
{
//log error
smsLog(pMac, LOGE, FL("can not obtain a common buffer"));
status = eHAL_STATUS_RESOURCES;
}
}
return (status);
}
#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD
eHalStatus csrScanRequestLfrResult(tpAniSirGlobal pMac, tANI_U32 sessionId,
csrScanCompleteCallback callback, void *pContext)
{
eHalStatus status = eHAL_STATUS_SUCCESS;
tSmeCmd *pScanCmd;
if (pMac->scan.fScanEnable)
{
pScanCmd = csrGetCommandBuffer(pMac);
if (pScanCmd)
{
pScanCmd->command = eSmeCommandScan;
pScanCmd->sessionId = sessionId;
vos_mem_set(&pScanCmd->u.scanCmd, sizeof(tScanCmd), 0);
pScanCmd->u.scanCmd.callback = callback;
pScanCmd->u.scanCmd.pContext = pContext;
pScanCmd->u.scanCmd.reason = eCsrScanGetLfrResult;
//Need to make the following atomic
pScanCmd->u.scanCmd.scanID = pMac->scan.nextScanID; //let it wrap around
status = csrQueueSmeCommand(pMac, pScanCmd, eANI_BOOLEAN_TRUE);
if ( !HAL_STATUS_SUCCESS( status ) )
{
smsLog( pMac, LOGE, FL(" fail to send message status = %d\n"), status );
csrReleaseCommandScan(pMac, pScanCmd);
}
}
else
{
//log error
smsLog(pMac, LOGE, FL("can not obtain a common buffer\n"));
status = eHAL_STATUS_RESOURCES;
}
}
return (status);
}
#endif //WLAN_FEATURE_ROAM_SCAN_OFFLOAD
eHalStatus csrScanAllChannels(tpAniSirGlobal pMac, eCsrRequestType reqType)
{
eHalStatus status = eHAL_STATUS_SUCCESS;
tANI_U32 scanId;
tCsrScanRequest scanReq;
vos_mem_set(&scanReq, sizeof(tCsrScanRequest), 0);
scanReq.BSSType = eCSR_BSS_TYPE_ANY;
scanReq.scanType = eSIR_ACTIVE_SCAN;
scanReq.requestType = reqType;
scanReq.maxChnTime = pMac->roam.configParam.nActiveMaxChnTime;
scanReq.minChnTime = pMac->roam.configParam.nActiveMinChnTime;
//Scan with invalid sessionId.
//This results in SME using the first available session to scan.
status = csrScanRequest(pMac, CSR_SESSION_ID_INVALID, &scanReq,
&scanId, NULL, NULL);
return (status);
}
eHalStatus csrIssueRoamAfterLostlinkScan(tpAniSirGlobal pMac, tANI_U32 sessionId, eCsrRoamReason reason)
{
eHalStatus status = eHAL_STATUS_FAILURE;
tScanResultHandle hBSSList = NULL;
tCsrScanResultFilter *pScanFilter = NULL;
tANI_U32 roamId = 0;
tCsrRoamProfile *pProfile = NULL;
tCsrRoamSession *pSession = CSR_GET_SESSION( pMac, sessionId );
if(!pSession)
{
smsLog(pMac, LOGE, FL(" session %d not found "), sessionId);
return eHAL_STATUS_FAILURE;
}
do
{
smsLog(pMac, LOG1, " csrIssueRoamAfterLostlinkScan called");
if(pSession->fCancelRoaming)
{
smsLog(pMac, LOGW, " lost link roaming is canceled");
csrScanStartIdleScan(pMac);
status = eHAL_STATUS_SUCCESS;
break;
}
//Here is the profile we need to connect to
pScanFilter = vos_mem_malloc(sizeof(tCsrScanResultFilter));
if ( NULL == pScanFilter)
status = eHAL_STATUS_FAILURE;
else
status = eHAL_STATUS_SUCCESS;
if (!HAL_STATUS_SUCCESS(status))
break;
vos_mem_set(pScanFilter, sizeof(tCsrScanResultFilter), 0);
if(NULL == pSession->pCurRoamProfile)
{
pScanFilter->EncryptionType.numEntries = 1;
pScanFilter->EncryptionType.encryptionType[0] = eCSR_ENCRYPT_TYPE_NONE;
}
else
{
//We have to make a copy of pCurRoamProfile because it will be free inside csrRoamIssueConnect
pProfile = vos_mem_malloc(sizeof(tCsrRoamProfile));
if ( NULL == pProfile )
status = eHAL_STATUS_FAILURE;
else
status = eHAL_STATUS_SUCCESS;
if (!HAL_STATUS_SUCCESS(status))
break;
vos_mem_set(pProfile, sizeof(tCsrRoamProfile), 0);
status = csrRoamCopyProfile(pMac, pProfile, pSession->pCurRoamProfile);
if(!HAL_STATUS_SUCCESS(status))
break;
status = csrRoamPrepareFilterFromProfile(pMac, pProfile, pScanFilter);
}//We have a profile
roamId = GET_NEXT_ROAM_ID(&pMac->roam);
if(HAL_STATUS_SUCCESS(status))
{
status = csrScanGetResult(pMac, pScanFilter, &hBSSList);
if(HAL_STATUS_SUCCESS(status))
{
if(eCsrLostLink1 == reason)
{
//we want to put the last connected BSS to the very beginning, if possible
csrMoveBssToHeadFromBSSID(pMac, &pSession->connectedProfile.bssid, hBSSList);
}
status = csrRoamIssueConnect(pMac, sessionId, pProfile, hBSSList, reason,
roamId, eANI_BOOLEAN_TRUE, eANI_BOOLEAN_TRUE);
if(!HAL_STATUS_SUCCESS(status))
{
csrScanResultPurge(pMac, hBSSList);
}
}//Have scan result
}
}while(0);
if(pScanFilter)
{
//we need to free memory for filter if profile exists
csrFreeScanFilter(pMac, pScanFilter);
vos_mem_free(pScanFilter);
}
if(NULL != pProfile)
{
csrReleaseProfile(pMac, pProfile);
vos_mem_free(pProfile);
}
return (status);
}
eHalStatus csrScanGetScanChnInfo(tpAniSirGlobal pMac, tSmeCmd *pCommand)
{
eHalStatus status = eHAL_STATUS_SUCCESS;
tSmeCmd *pScanCmd;
if(pMac->scan.fScanEnable)
{
pScanCmd = csrGetCommandBuffer(pMac);
if(pScanCmd)
{
pScanCmd->command = eSmeCommandScan;
vos_mem_set(&pScanCmd->u.scanCmd, sizeof(tScanCmd), 0);
pScanCmd->u.scanCmd.reason = eCsrScanGetScanChnInfo;
/* Need to make the following atomic */
pScanCmd->u.scanCmd.scanID =
pMac->scan.nextScanID++; /* let it wrap around */
pScanCmd->sessionId = pCommand->sessionId;
if (eCsrScanUserRequest == pCommand->u.scanCmd.reason)
{
pScanCmd->u.scanCmd.callback = NULL;
pScanCmd->u.scanCmd.pContext = NULL;
} else {
pScanCmd->u.scanCmd.callback = pCommand->u.scanCmd.callback;
pScanCmd->u.scanCmd.pContext = pCommand->u.scanCmd.pContext;
pScanCmd->u.scanCmd.abort_scan_indication =
pCommand->u.scanCmd.abort_scan_indication;
}
status = csrQueueSmeCommand(pMac, pScanCmd, eANI_BOOLEAN_FALSE);
if( !HAL_STATUS_SUCCESS( status ) )
{
smsLog( pMac, LOGE, FL(" fail to send message status = %d"), status );
csrReleaseCommandScan(pMac, pScanCmd);
}
}
else
{
//log error
smsLog(pMac, LOGE, FL("can not obtain a common buffer"));
status = eHAL_STATUS_RESOURCES;
}
}
return (status);
}
eHalStatus csrScanHandleFailedLostlink1(tpAniSirGlobal pMac, tANI_U32 sessionId)
{
eHalStatus status = eHAL_STATUS_FAILURE;
tCsrRoamSession *pSession = CSR_GET_SESSION( pMac, sessionId );
if(!pSession)
{
smsLog(pMac, LOGE, FL(" session %d not found "), sessionId);
return eHAL_STATUS_FAILURE;
}
smsLog(pMac, LOGW, "Lost link scan 1 failed");
if(pSession->fCancelRoaming)
{
csrScanStartIdleScan(pMac);
}
else if(pSession->pCurRoamProfile)
{
//We fail lostlink1 but there may be other BSS in the cached result fit the profile. Give it a try first
if(pSession->pCurRoamProfile->SSIDs.numOfSSIDs == 0 ||
pSession->pCurRoamProfile->SSIDs.numOfSSIDs > 1)
{
/* Try lost link scan2 */
status = csrScanRequestLostLink2(pMac, sessionId);
}
else if(!pSession->pCurRoamProfile->ChannelInfo.ChannelList ||
pSession->pCurRoamProfile->ChannelInfo.ChannelList[0] == 0)
{
/* Go straight to lost link scan3 */
status = csrScanRequestLostLink3(pMac, sessionId);
}
else
{
/* We are done with lost link */
if(csrRoamCompleteRoaming(pMac, sessionId, eANI_BOOLEAN_FALSE, eCSR_ROAM_RESULT_FAILURE))
{
csrScanStartIdleScan(pMac);
}
status = eHAL_STATUS_SUCCESS;
}
}
else
{
status = csrScanRequestLostLink3(pMac, sessionId);
}
return (status);
}
eHalStatus csrScanHandleFailedLostlink2(tpAniSirGlobal pMac, tANI_U32 sessionId)
{
eHalStatus status = eHAL_STATUS_FAILURE;
tCsrRoamSession *pSession = CSR_GET_SESSION( pMac, sessionId );
if(!pSession)
{
smsLog(pMac, LOGE, FL(" session %d not found "), sessionId);
return eHAL_STATUS_FAILURE;
}
smsLog(pMac, LOGW, "Lost link scan 2 failed");
if(pSession->fCancelRoaming)
{
csrScanStartIdleScan(pMac);
}
else if(!pSession->pCurRoamProfile || !pSession->pCurRoamProfile->ChannelInfo.ChannelList ||
pSession->pCurRoamProfile->ChannelInfo.ChannelList[0] == 0)
{
/* Try lost link scan3 */
status = csrScanRequestLostLink3(pMac, sessionId);
}
else
{
/* We are done with lost link */
if(csrRoamCompleteRoaming(pMac, sessionId, eANI_BOOLEAN_FALSE, eCSR_ROAM_RESULT_FAILURE))
{
csrScanStartIdleScan(pMac);
}
}
return (status);
}
eHalStatus csrScanHandleFailedLostlink3(tpAniSirGlobal pMac, tANI_U32 sessionId)
{
eHalStatus status = eHAL_STATUS_SUCCESS;
smsLog(pMac, LOGW, "Lost link scan 3 failed");
if(eANI_BOOLEAN_TRUE == csrRoamCompleteRoaming(pMac, sessionId, eANI_BOOLEAN_FALSE, eCSR_ROAM_RESULT_FAILURE))
{
/* We are done with lost link */
csrScanStartIdleScan(pMac);
}
return (status);
}
//Lostlink1 scan is to actively scan the last connected profile's SSID on all matched BSS channels.
//If no roam profile (it should not), it is like lostlinkscan3
eHalStatus csrScanRequestLostLink1( tpAniSirGlobal pMac, tANI_U32 sessionId )
{
eHalStatus status = eHAL_STATUS_SUCCESS;
tSmeCmd *pCommand = NULL;
tANI_U8 bAddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
tCsrScanResultFilter *pScanFilter = NULL;
tScanResultHandle hBSSList = NULL;
tCsrScanResultInfo *pScanResult = NULL;
tCsrRoamSession *pSession = CSR_GET_SESSION( pMac, sessionId );
if(!pSession)
{
smsLog(pMac, LOGE, FL(" session %d not found "), sessionId);
return eHAL_STATUS_FAILURE;
}
smsLog(pMac, LOGW, FL(" called"));
do
{
pCommand = csrGetCommandBuffer(pMac);
if(!pCommand)
{
status = eHAL_STATUS_RESOURCES;
break;
}
vos_mem_set(&pCommand->u.scanCmd, sizeof(tScanCmd), 0);
pCommand->command = eSmeCommandScan;
pCommand->sessionId = (tANI_U8)sessionId;
pCommand->u.scanCmd.reason = eCsrScanLostLink1;
pCommand->u.scanCmd.callback = NULL;
pCommand->u.scanCmd.pContext = NULL;
pCommand->u.scanCmd.u.scanRequest.maxChnTime = pMac->roam.configParam.nActiveMaxChnTime;
pCommand->u.scanCmd.u.scanRequest.minChnTime = pMac->roam.configParam.nActiveMinChnTime;
pCommand->u.scanCmd.u.scanRequest.scanType = eSIR_ACTIVE_SCAN;
if(pSession->connectedProfile.SSID.length)
{
pCommand->u.scanCmd.u.scanRequest.SSIDs.SSIDList = vos_mem_malloc(sizeof(tCsrSSIDInfo));
if ( NULL == pCommand->u.scanCmd.u.scanRequest.SSIDs.SSIDList )
status = eHAL_STATUS_FAILURE;
else
status = eHAL_STATUS_SUCCESS;
if(!HAL_STATUS_SUCCESS(status))
{
break;
}
pCommand->u.scanCmd.u.scanRequest.SSIDs.numOfSSIDs = 1;
vos_mem_copy(&pCommand->u.scanCmd.u.scanRequest.SSIDs.SSIDList[0].SSID,
&pSession->connectedProfile.SSID, sizeof(tSirMacSSid));
}
else
{
pCommand->u.scanCmd.u.scanRequest.SSIDs.numOfSSIDs = 0;
}
if(pSession->pCurRoamProfile)
{
pScanFilter = vos_mem_malloc(sizeof(tCsrScanResultFilter));
if ( NULL == pScanFilter )
status = eHAL_STATUS_FAILURE;
else
status = eHAL_STATUS_SUCCESS;
if(!HAL_STATUS_SUCCESS(status))
{
break;
}
vos_mem_set(pScanFilter, sizeof(tCsrScanResultFilter), 0);
status = csrRoamPrepareFilterFromProfile(pMac, pSession->pCurRoamProfile, pScanFilter);
if(!HAL_STATUS_SUCCESS(status))
{
break;
}
//Don't change variable status here because whether we can get result or not, the command goes to PE.
//The status is also used to indicate whether the command is queued. Not success meaning not queue
if(HAL_STATUS_SUCCESS((csrScanGetResult(pMac, pScanFilter, &hBSSList))) && hBSSList)
{
tANI_U8 i, nChn = 0;
pCommand->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList =
vos_mem_malloc(WNI_CFG_VALID_CHANNEL_LIST_LEN);
if ( NULL == pCommand->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList )
status = eHAL_STATUS_FAILURE;
else
status = eHAL_STATUS_SUCCESS;
if(!HAL_STATUS_SUCCESS(status))
{
break;
}
while(((pScanResult = csrScanResultGetNext(pMac, hBSSList)) != NULL) &&
nChn < WNI_CFG_VALID_CHANNEL_LIST_LEN)
{
for(i = 0; i < nChn; i++)
{
if(pCommand->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList[i] ==
pScanResult->BssDescriptor.channelId)
{
break;
}
}
if(i == nChn)
{
pCommand->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList[nChn++] = pScanResult->BssDescriptor.channelId;
}
}
//Include the last connected BSS' channel
if(csrRoamIsChannelValid(pMac, pSession->connectedProfile.operationChannel))
{
for(i = 0; i < nChn; i++)
{
if(pCommand->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList[i] ==
pSession->connectedProfile.operationChannel)
{
break;
}
}
if(i == nChn)
{
pCommand->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList[nChn++] = pSession->connectedProfile.operationChannel;
}
}
pCommand->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels = nChn;
}
else
{
if(csrRoamIsChannelValid(pMac, pSession->connectedProfile.operationChannel))
{
pCommand->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList = vos_mem_malloc(1);
if ( NULL == pCommand->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList )
status = eHAL_STATUS_FAILURE;
else
status = eHAL_STATUS_SUCCESS;
//just try the last connected channel
if(HAL_STATUS_SUCCESS(status))
{
pCommand->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList[0] = pSession->connectedProfile.operationChannel;
pCommand->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels = 1;
}
else
{
break;
}
}
}
}
vos_mem_copy(&pCommand->u.scanCmd.u.scanRequest.bssid, bAddr, sizeof(tCsrBssid));
status = csrQueueSmeCommand(pMac, pCommand, eANI_BOOLEAN_FALSE);
if( !HAL_STATUS_SUCCESS( status ) )
{
smsLog( pMac, LOGE, FL(" fail to send message status = %d"), status );
break;
}
} while( 0 );
if(!HAL_STATUS_SUCCESS(status))
{
smsLog(pMac, LOGW, " csrScanRequestLostLink1 failed with status %d", status);
if(pCommand)
{
csrReleaseCommandScan(pMac, pCommand);
}
status = csrScanHandleFailedLostlink1( pMac, sessionId );
}
if(pScanFilter)
{
csrFreeScanFilter(pMac, pScanFilter);
vos_mem_free(pScanFilter);
}
if(hBSSList)
{
csrScanResultPurge(pMac, hBSSList);
}
return( status );
}
//Lostlink2 scan is to actively scan the all SSIDs of the last roaming profile's on all matched BSS channels.
//Since MAC doesn't support multiple SSID, we scan all SSIDs and filter them afterwards
eHalStatus csrScanRequestLostLink2( tpAniSirGlobal pMac, tANI_U32 sessionId )
{
eHalStatus status = eHAL_STATUS_SUCCESS;
tANI_U8 bAddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
tCsrScanResultFilter *pScanFilter = NULL;
tScanResultHandle hBSSList = NULL;
tCsrScanResultInfo *pScanResult = NULL;
tSmeCmd *pCommand = NULL;
tCsrRoamSession *pSession = CSR_GET_SESSION( pMac, sessionId );
if(!pSession)
{
smsLog(pMac, LOGE, FL(" session %d not found "), sessionId);
return eHAL_STATUS_FAILURE;
}
smsLog(pMac, LOGW, FL(" called"));
do
{
pCommand = csrGetCommandBuffer(pMac);
if(!pCommand)
{
status = eHAL_STATUS_RESOURCES;
break;
}
vos_mem_set(&pCommand->u.scanCmd, sizeof(tScanCmd), 0);
pCommand->command = eSmeCommandScan;
pCommand->sessionId = (tANI_U8)sessionId;
pCommand->u.scanCmd.reason = eCsrScanLostLink2;
pCommand->u.scanCmd.callback = NULL;
pCommand->u.scanCmd.pContext = NULL;
pCommand->u.scanCmd.u.scanRequest.maxChnTime = pMac->roam.configParam.nActiveMaxChnTime;
pCommand->u.scanCmd.u.scanRequest.minChnTime = pMac->roam.configParam.nActiveMinChnTime;
pCommand->u.scanCmd.u.scanRequest.scanType = eSIR_ACTIVE_SCAN;
if(pSession->pCurRoamProfile)
{
pScanFilter = vos_mem_malloc(sizeof(tCsrScanResultFilter));
if ( NULL == pScanFilter )
status = eHAL_STATUS_FAILURE;
else
status = eHAL_STATUS_SUCCESS;
if (!HAL_STATUS_SUCCESS(status))
{
break;
}
vos_mem_set(pScanFilter, sizeof(tCsrScanResultFilter), 0);
status = csrRoamPrepareFilterFromProfile(pMac, pSession->pCurRoamProfile, pScanFilter);
if(!HAL_STATUS_SUCCESS(status))
{
break;
}
status = csrScanGetResult(pMac, pScanFilter, &hBSSList);
if(!HAL_STATUS_SUCCESS(status))
{
break;
}
if(hBSSList)
{
tANI_U8 i, nChn = 0;
pCommand->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList =
vos_mem_malloc(WNI_CFG_VALID_CHANNEL_LIST_LEN);
if ( NULL == pCommand->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList )
status = eHAL_STATUS_FAILURE;
else
status = eHAL_STATUS_SUCCESS;
if (!HAL_STATUS_SUCCESS(status))
{
break;
}
while(((pScanResult = csrScanResultGetNext(pMac, hBSSList)) != NULL) &&
nChn < WNI_CFG_VALID_CHANNEL_LIST_LEN)
{
for(i = 0; i < nChn; i++)
{
if(pCommand->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList[i] ==
pScanResult->BssDescriptor.channelId)
{
break;
}
}
if(i == nChn)
{
pCommand->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList[nChn++] = pScanResult->BssDescriptor.channelId;
}
}
pCommand->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels = nChn;
}
}
vos_mem_copy(&pCommand->u.scanCmd.u.scanRequest.bssid, bAddr, sizeof(tCsrBssid));
//Put to the head in pending queue
status = csrQueueSmeCommand(pMac, pCommand, eANI_BOOLEAN_TRUE);
if( !HAL_STATUS_SUCCESS( status ) )
{
smsLog( pMac, LOGE, FL(" fail to send message status = %d"), status );
break;
}
} while( 0 );
if(!HAL_STATUS_SUCCESS(status))
{
smsLog(pMac, LOGW, " csrScanRequestLostLink2 failed with status %d", status);
if(pCommand)
{
csrReleaseCommandScan(pMac, pCommand);
}
status = csrScanHandleFailedLostlink2( pMac, sessionId );
}
if(pScanFilter)
{
csrFreeScanFilter(pMac, pScanFilter);
vos_mem_free(pScanFilter);
}
if(hBSSList)
{
csrScanResultPurge(pMac, hBSSList);
}
return( status );
}
//To actively scan all valid channels
eHalStatus csrScanRequestLostLink3( tpAniSirGlobal pMac, tANI_U32 sessionId )
{
eHalStatus status = eHAL_STATUS_SUCCESS;
tSmeCmd *pCommand;
tANI_U8 bAddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
smsLog(pMac, LOGW, FL(" called"));
do
{
pCommand = csrGetCommandBuffer(pMac);
if(!pCommand)
{
status = eHAL_STATUS_RESOURCES;
break;
}
vos_mem_set(&pCommand->u.scanCmd, sizeof(tScanCmd), 0);
pCommand->command = eSmeCommandScan;
pCommand->sessionId = (tANI_U8)sessionId;
pCommand->u.scanCmd.reason = eCsrScanLostLink3;
pCommand->u.scanCmd.callback = NULL;
pCommand->u.scanCmd.pContext = NULL;
pCommand->u.scanCmd.u.scanRequest.maxChnTime = pMac->roam.configParam.nActiveMaxChnTime;
pCommand->u.scanCmd.u.scanRequest.minChnTime = pMac->roam.configParam.nActiveMinChnTime;
pCommand->u.scanCmd.u.scanRequest.scanType = eSIR_ACTIVE_SCAN;
vos_mem_copy(&pCommand->u.scanCmd.u.scanRequest.bssid, bAddr, sizeof(tCsrBssid));
//Put to the head of pending queue
status = csrQueueSmeCommand(pMac, pCommand, eANI_BOOLEAN_TRUE);
if( !HAL_STATUS_SUCCESS( status ) )
{
smsLog( pMac, LOGE, FL(" fail to send message status = %d"), status );
break;
}
} while( 0 );
if(!HAL_STATUS_SUCCESS(status))
{
smsLog(pMac, LOGW, " csrScanRequestLostLink3 failed with status %d", status);
if(csrRoamCompleteRoaming(pMac, sessionId, eANI_BOOLEAN_FALSE, eCSR_ROAM_RESULT_FAILURE))
{
csrScanStartIdleScan(pMac);
}
if(pCommand)
{
csrReleaseCommandScan(pMac, pCommand);
}
}
return( status );
}
eHalStatus csrScanHandleSearchForSSID(tpAniSirGlobal pMac, tSmeCmd *pCommand)
{
eHalStatus status = eHAL_STATUS_FAILURE;
tScanResultHandle hBSSList = CSR_INVALID_SCANRESULT_HANDLE;
tCsrScanResultFilter *pScanFilter = NULL;
tCsrRoamProfile *pProfile = pCommand->u.scanCmd.pToRoamProfile;
tANI_U32 sessionId = pCommand->sessionId;
do
{
#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD
/* If this scan is for LFR */
if (pMac->roam.neighborRoamInfo[sessionId].uOsRequestedHandoff) {
/* Notify LFR state m/c */
if (eHAL_STATUS_SUCCESS != csrNeighborRoamSssidScanDone(pMac,
sessionId,
eHAL_STATUS_SUCCESS)) {
csrNeighborRoamStartLfrScan(pMac, sessionId);
}
status = eHAL_STATUS_SUCCESS;
break;
}
#endif
//If there is roam command waiting, ignore this roam because the newer roam command is the one to execute
if(csrIsRoamCommandWaitingForSession(pMac, sessionId))
{
smsLog(pMac, LOGW, FL(" aborts because roam command waiting"));
break;
}
if(pProfile == NULL)
break;
pScanFilter = vos_mem_malloc(sizeof(tCsrScanResultFilter));
if ( NULL == pScanFilter )
status = eHAL_STATUS_FAILURE;
else
status = eHAL_STATUS_SUCCESS;
if (!HAL_STATUS_SUCCESS(status))
break;
vos_mem_set(pScanFilter, sizeof(tCsrScanResultFilter), 0);
status = csrRoamPrepareFilterFromProfile(pMac, pProfile, pScanFilter);
if(!HAL_STATUS_SUCCESS(status))
break;
status = csrScanGetResult(pMac, pScanFilter, &hBSSList);
if(!HAL_STATUS_SUCCESS(status))
break;
if (pMac->roam.roamSession[sessionId].connectState ==
eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTING) {
smsLog(pMac, LOGE, FL("upper layer issued disconnetion"));
status = eHAL_STATUS_FAILURE;
break;
}
status = csrRoamIssueConnect(pMac, sessionId, pProfile, hBSSList, eCsrHddIssued,
pCommand->u.scanCmd.roamId, eANI_BOOLEAN_TRUE, eANI_BOOLEAN_TRUE);
if(!HAL_STATUS_SUCCESS(status))
{
break;
}
}while(0);
if(!HAL_STATUS_SUCCESS(status))
{
if(CSR_INVALID_SCANRESULT_HANDLE != hBSSList)
{
csrScanResultPurge(pMac, hBSSList);
}
//We haven't done anything to this profile
csrRoamCallCallback(pMac, sessionId, NULL,
pCommand->u.scanCmd.roamId,
eCSR_ROAM_ASSOCIATION_FAILURE,
eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE);
//In case we have nothing else to do, restart idle scan
if(csrIsConnStateDisconnected(pMac, sessionId) && !csrIsRoamCommandWaiting(pMac))
{
status = csrScanStartIdleScan(pMac);
}
}
if (pScanFilter)
{
csrFreeScanFilter(pMac, pScanFilter);
vos_mem_free(pScanFilter);
}
return (status);
}
eHalStatus csrScanHandleSearchForSSIDFailure(tpAniSirGlobal pMac, tSmeCmd *pCommand)
{
eHalStatus status = eHAL_STATUS_SUCCESS;
tANI_U32 sessionId = pCommand->sessionId;
tCsrRoamProfile *pProfile = pCommand->u.scanCmd.pToRoamProfile;
tCsrRoamSession *pSession = CSR_GET_SESSION( pMac, sessionId );
if (!pSession) {
smsLog(pMac, LOGE, FL("Session %d not found"), sessionId);
return eHAL_STATUS_FAILURE;
}
#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD
/* If this scan is for LFR */
if (pMac->roam.neighborRoamInfo[sessionId].uOsRequestedHandoff) {
/* Notify LFR state m/c */
if (eHAL_STATUS_SUCCESS != csrNeighborRoamSssidScanDone(pMac,
sessionId,
eHAL_STATUS_FAILURE)) {
csrNeighborRoamStartLfrScan(pMac, sessionId);
}
return eHAL_STATUS_SUCCESS;
}
#endif
#if defined(WLAN_DEBUG)
if(pCommand->u.scanCmd.u.scanRequest.SSIDs.numOfSSIDs == 1)
{
char str[36];
vos_mem_copy(str,
pCommand->u.scanCmd.u.scanRequest.SSIDs.SSIDList[0].SSID.ssId,
pCommand->u.scanCmd.u.scanRequest.SSIDs.SSIDList[0].SSID.length);
str[pCommand->u.scanCmd.u.scanRequest.SSIDs.SSIDList[0].SSID.length] = 0;
smsLog(pMac, LOGW, FL(" SSID = %s"), str);
}
#endif
//Check whether it is for start ibss. No need to do anything if it is a JOIN request
if(pProfile && CSR_IS_START_IBSS(pProfile))
{
status = csrRoamIssueConnect(pMac, sessionId, pProfile, NULL, eCsrHddIssued,
pCommand->u.scanCmd.roamId, eANI_BOOLEAN_TRUE, eANI_BOOLEAN_TRUE);
if(!HAL_STATUS_SUCCESS(status))
{
smsLog(pMac, LOGE, FL("failed to issue startIBSS command with status = 0x%08X"), status);
csrRoamCallCallback(pMac, sessionId, NULL, pCommand->u.scanCmd.roamId, eCSR_ROAM_FAILED, eCSR_ROAM_RESULT_FAILURE);
}
}
else
{
eCsrRoamResult roamResult = eCSR_ROAM_RESULT_FAILURE;
if(csrIsConnStateDisconnected(pMac, sessionId) &&
!csrIsRoamCommandWaitingForSession(pMac, sessionId))
{
status = csrScanStartIdleScan(pMac);
}
if((NULL == pProfile) || !csrIsBssTypeIBSS(pProfile->BSSType))
{
//Only indicate assoc_completion if we indicate assoc_start.
if(pSession->bRefAssocStartCnt > 0)
{
tCsrRoamInfo *pRoamInfo = NULL, roamInfo;
vos_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0);
pRoamInfo = &roamInfo;
if(pCommand->u.roamCmd.pRoamBssEntry)
{
tCsrScanResult *pScanResult =
GET_BASE_ADDR(pCommand->u.roamCmd.pRoamBssEntry,
tCsrScanResult, Link);
roamInfo.pBssDesc = &pScanResult->Result.BssDescriptor;
}
roamInfo.statusCode = pSession->joinFailStatusCode.statusCode;
roamInfo.reasonCode = pSession->joinFailStatusCode.reasonCode;
pSession->bRefAssocStartCnt--;
csrRoamCallCallback(pMac, sessionId, pRoamInfo,
pCommand->u.scanCmd.roamId,
eCSR_ROAM_ASSOCIATION_COMPLETION,
eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE);
}
else
{
csrRoamCallCallback(pMac, sessionId, NULL,
pCommand->u.scanCmd.roamId,
eCSR_ROAM_ASSOCIATION_FAILURE,
eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE);
}
}
else
{
roamResult = eCSR_ROAM_RESULT_IBSS_START_FAILED;
}
csrRoamCompletion(pMac, sessionId, NULL, pCommand, roamResult, eANI_BOOLEAN_FALSE);
}
return (status);
}
//After scan for cap changes, issue a roaming command to either reconnect to the AP or pick another one to connect
eHalStatus csrScanHandleCapChangeScanComplete(tpAniSirGlobal pMac, tANI_U32 sessionId)
{
eHalStatus status = eHAL_STATUS_FAILURE;
tScanResultHandle hBSSList = NULL;
tCsrScanResultFilter *pScanFilter = NULL;
tANI_U32 roamId = 0;
tCsrRoamProfile *pProfile = NULL;
tCsrRoamSession *pSession = CSR_GET_SESSION( pMac, sessionId );
do
{
//Here is the profile we need to connect to
pScanFilter = vos_mem_malloc(sizeof(tCsrScanResultFilter));
if ( NULL == pScanFilter )
status = eHAL_STATUS_FAILURE;
else
status = eHAL_STATUS_SUCCESS;
if (!HAL_STATUS_SUCCESS(status))
break;
vos_mem_set(pScanFilter, sizeof(tCsrScanResultFilter), 0);
if (NULL == pSession) break;
if (NULL == pSession->pCurRoamProfile)
{
pScanFilter->EncryptionType.numEntries = 1;
pScanFilter->EncryptionType.encryptionType[0] = eCSR_ENCRYPT_TYPE_NONE;
}
else
{
//We have to make a copy of pCurRoamProfile because it will be free inside csrRoamIssueConnect
pProfile = vos_mem_malloc(sizeof(tCsrRoamProfile));
if ( NULL == pProfile )
status = eHAL_STATUS_FAILURE;
else
status = eHAL_STATUS_SUCCESS;
if(!HAL_STATUS_SUCCESS(status))
break;
status = csrRoamCopyProfile(pMac, pProfile, pSession->pCurRoamProfile);
if(!HAL_STATUS_SUCCESS(status))
break;
status = csrRoamPrepareFilterFromProfile(pMac, pProfile, pScanFilter);
}//We have a profile
roamId = GET_NEXT_ROAM_ID(&pMac->roam);
if(HAL_STATUS_SUCCESS(status))
{
status = csrScanGetResult(pMac, pScanFilter, &hBSSList);
if(HAL_STATUS_SUCCESS(status))
{
//we want to put the last connected BSS to the very beginning, if possible
csrMoveBssToHeadFromBSSID(pMac, &pSession->connectedProfile.bssid, hBSSList);
status = csrRoamIssueConnect(pMac, sessionId, pProfile, hBSSList,
eCsrCapsChange, 0, eANI_BOOLEAN_TRUE, eANI_BOOLEAN_TRUE);
if(!HAL_STATUS_SUCCESS(status))
{
csrScanResultPurge(pMac, hBSSList);
}
}//Have scan result
else
{
smsLog(pMac, LOGW, FL("cannot find matching BSS of "
MAC_ADDRESS_STR),
MAC_ADDR_ARRAY(pSession->connectedProfile.bssid));
//Disconnect
csrRoamDisconnectInternal(pMac, sessionId, eCSR_DISCONNECT_REASON_UNSPECIFIED);
}
}
}while(0);
if(pScanFilter)
{
csrFreeScanFilter(pMac, pScanFilter);
vos_mem_free(pScanFilter);
}
if(NULL != pProfile)
{
csrReleaseProfile(pMac, pProfile);
vos_mem_free(pProfile);
}
return (status);
}
eHalStatus csrScanResultPurge(tpAniSirGlobal pMac, tScanResultHandle hScanList)
{
eHalStatus status = eHAL_STATUS_INVALID_PARAMETER;
tScanResultList *pScanList = (tScanResultList *)hScanList;
if(pScanList)
{
status = csrLLScanPurgeResult(pMac, &pScanList->List);
csrLLClose(&pScanList->List);
vos_mem_free(pScanList);
}
return (status);
}
/**
* csr_get_altered_rssi() - Artificially increase/decrease RSSI
* @mac_ctx: Global MAC Context pointer.
* @rssi: Actual RSSI of the AP.
* @channel_id: Channel on which the AP is parked.
* @bssid: BSSID of the AP to connect to.
*
* This routine will apply the boost and penalty parameters
* if the channel_id is of 5G band and it will also apply
* the preferred bssid score if there is a match between
* the bssid and the global preferred bssid list.
*
* Return: The modified RSSI Value
*/
static int csr_get_altered_rssi(tpAniSirGlobal mac_ctx, int rssi,
uint8_t channel_id, tCsrBssid *bssid)
{
int modified_rssi;
int boost_factor;
int penalty_factor;
int i;
struct roam_ext_params *roam_params;
tCsrBssid local_bssid;
modified_rssi = rssi;
vos_mem_set(&local_bssid, 0, VOS_MAC_ADDR_SIZE);
if (bssid)
vos_mem_copy(&local_bssid, bssid, VOS_MAC_ADDR_SIZE);
roam_params = &mac_ctx->roam.configParam.roam_params;
/*
* If the 5G pref feature is enabled, apply the roaming
* parameters to boost or penalize the rssi.
* Boost Factor = boost_factor * (Actual RSSI - boost Threshold)
* Penalty Factor = penalty factor * (penalty threshold - Actual RSSI)
*/
if (CSR_IS_SELECT_5G_PREFERRED(mac_ctx) &&
CSR_IS_CHANNEL_5GHZ(channel_id)) {
if (rssi > roam_params->raise_rssi_thresh_5g) {
/* Check and boost the threshold*/
boost_factor = roam_params->raise_factor_5g *
(rssi - roam_params->raise_rssi_thresh_5g);
/* Check and penalize the threshold */
modified_rssi += CSR_MIN(roam_params->max_raise_rssi_5g,
boost_factor);
} else if(rssi < roam_params->drop_rssi_thresh_5g) {
penalty_factor = roam_params->drop_factor_5g *
(roam_params->drop_rssi_thresh_5g - rssi);
modified_rssi -= CSR_MAX(roam_params->max_drop_rssi_5g,
penalty_factor);
}
VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_DEBUG,
FL("5G BSSID("MAC_ADDRESS_STR") AR:%d, MR:%d, ch=%d"),
MAC_ADDR_ARRAY(local_bssid), rssi,
modified_rssi, channel_id);
}
/*
* Check if there are preferred bssid and then apply the
* preferred score
*/
if (roam_params->num_bssid_favored) {
for (i=0; i<roam_params->num_bssid_favored; i++) {
if (!csrIsMacAddressEqual(mac_ctx,
&roam_params->bssid_favored[i], bssid))
continue;
modified_rssi += roam_params->bssid_favored_factor[i];
VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_DEBUG,
FL("Pref: ("MAC_ADDRESS_STR") AR:%d, MR:%d, ch=%d"),
MAC_ADDR_ARRAY(local_bssid), rssi, modified_rssi,
channel_id);
}
}
return modified_rssi;
}
/**
* csrGetBssPreferValue() - Get BSS Preference Value
* @pMac: Global MAC Context pointer.
* @rssi: Actual RSSI of the AP.
* @bssid: BSSID of the AP to connect to.
* @channel_id: Channel on which the AP is parked.
*
*
* This routine helps in determining the preference value
* of a particular BSS in the scan result which is further
* used in the sorting logic of the final candidate AP's.
*
* Return: The preference Value for a BSS.
*/
static tANI_U32 csrGetBssPreferValue(tpAniSirGlobal pMac, int rssi,
tCsrBssid *bssid, int channel_id)
{
tANI_U32 ret = 0;
int i, modified_rssi;
/*
* The RSSI does not get modified in case the 5G
* preference or preferred BSSID is not applicable
*/
modified_rssi = csr_get_altered_rssi(pMac, rssi, channel_id, bssid);
i = CSR_NUM_RSSI_CAT - 1;
while(i >= 0) {
if(modified_rssi >= pMac->roam.configParam.RSSICat[i]) {
ret = pMac->roam.configParam.BssPreferValue[i];
break;
}
i--;
};
return (ret);
}
//Return a CapValue base on the capabilities of a BSS
static tANI_U32 csrGetBssCapValue(tpAniSirGlobal pMac, tSirBssDescription *pBssDesc, tDot11fBeaconIEs *pIes)
{
tANI_U32 ret = CSR_BSS_CAP_VALUE_NONE;
#if defined (WLAN_FEATURE_VOWIFI_11R) || defined (FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_LFR)
if(CSR_IS_ROAM_PREFER_5GHZ(pMac) || CSR_IS_SELECT_5G_PREFERRED(pMac))
{
if((pBssDesc) && CSR_IS_CHANNEL_5GHZ(pBssDesc->channelId))
{
ret += CSR_BSS_CAP_VALUE_5GHZ;
}
}
#endif
/* if strict select 5GHz is non-zero then ignore the capability checking */
if (pIes && !CSR_IS_SELECT_5GHZ_MARGIN(pMac))
{
//We only care about 11N capability
if (pIes->VHTCaps.present)
ret += CSR_BSS_CAP_VALUE_VHT;
else if (pIes->HTCaps.present)
ret += CSR_BSS_CAP_VALUE_HT;
if(CSR_IS_QOS_BSS(pIes))
{
ret += CSR_BSS_CAP_VALUE_WMM;
//Give advantage to UAPSD
if(CSR_IS_UAPSD_BSS(pIes))
{
ret += CSR_BSS_CAP_VALUE_UAPSD;
}
}
}
return (ret);
}
/**
* csr_is_better_rssi() - Is bss1 better than bss2
* @mac_ctx: Global MAC Context pointer.
* @bss1: Pointer to the first BSS.
* @bss2: Pointer to the second BSS.
*
*
* This routine helps in determining the preference value
* of a particular BSS in the scan result which is further
* used in the sorting logic of the final candidate AP's.
*
* Return: true, if bss1 is better than bss2
* false, if bss2 is better than bss1.
*/
static bool csr_is_better_rssi(tpAniSirGlobal mac_ctx,
tCsrScanResult *bss1, tCsrScanResult *bss2)
{
bool ret;
int rssi1, rssi2;
rssi1 = bss1->Result.BssDescriptor.rssi;
rssi2 = bss2->Result.BssDescriptor.rssi;
/*
* Apply the boost and penlty logic and check
* which is the best RSSI
*/
rssi1 = csr_get_altered_rssi(mac_ctx, rssi1,
bss1->Result.BssDescriptor.channelId,
&bss1->Result.BssDescriptor.bssId);
rssi2 = csr_get_altered_rssi(mac_ctx, rssi2,
bss2->Result.BssDescriptor.channelId,
&bss2->Result.BssDescriptor.bssId);
if (CSR_IS_BETTER_RSSI(rssi1, rssi2))
ret = true;
else
ret = false;
return ret;
}
/* To check whether pBss1 is better than pBss2 */
static tANI_BOOLEAN csrIsBetterBss(tpAniSirGlobal mac_ctx,
tCsrScanResult *pBss1, tCsrScanResult *pBss2)
{
tANI_BOOLEAN ret;
if(CSR_IS_BETTER_PREFER_VALUE(pBss1->preferValue, pBss2->preferValue))
ret = eANI_BOOLEAN_TRUE;
else if(CSR_IS_EQUAL_PREFER_VALUE
(pBss1->preferValue, pBss2->preferValue)) {
if(CSR_IS_BETTER_CAP_VALUE(pBss1->capValue, pBss2->capValue))
ret = eANI_BOOLEAN_TRUE;
else if (CSR_IS_EQUAL_CAP_VALUE
(pBss1->capValue, pBss2->capValue)) {
if (csr_is_better_rssi(mac_ctx, pBss1, pBss2))
ret = eANI_BOOLEAN_TRUE;
else
ret = eANI_BOOLEAN_FALSE;
}
else
ret = eANI_BOOLEAN_FALSE;
}
else
ret = eANI_BOOLEAN_FALSE;
return (ret);
}
#ifdef FEATURE_WLAN_LFR
//Add the channel to the occupiedChannels array
static void csrScanAddToOccupiedChannels(
tpAniSirGlobal pMac,
tCsrScanResult *pResult,
tANI_U8 sessionId,
tCsrChannel *pOccupiedChannels,
tDot11fBeaconIEs *pIes)
{
eHalStatus status;
tANI_U8 channel;
tANI_U8 numOccupiedChannels = pOccupiedChannels->numChannels;
tANI_U8 *pOccupiedChannelList = pOccupiedChannels->channelList;
channel = pResult->Result.BssDescriptor.channelId;
if (!csrIsChannelPresentInList(pOccupiedChannelList, numOccupiedChannels, channel)
&& csrNeighborRoamConnectedProfileMatch(pMac, sessionId, pResult, pIes))
{
status = csrAddToChannelListFront(pOccupiedChannelList, numOccupiedChannels, channel);
if(HAL_STATUS_SUCCESS(status))
{
pOccupiedChannels->numChannels++;
smsLog(pMac, LOG2, FL("Added channel %d to the list (count=%d)"),
channel, pOccupiedChannels->numChannels);
if (pOccupiedChannels->numChannels > CSR_BG_SCAN_OCCUPIED_CHANNEL_LIST_LEN)
pOccupiedChannels->numChannels = CSR_BG_SCAN_OCCUPIED_CHANNEL_LIST_LEN;
}
}
}
#endif
//Put the BSS into the scan result list
//pIes can not be NULL
static void csrScanAddResult(tpAniSirGlobal pMac, tCsrScanResult *pResult,
tDot11fBeaconIEs *pIes, tANI_U32 sessionId)
{
#ifdef FEATURE_WLAN_LFR
tpCsrNeighborRoamControlInfo pNeighborRoamInfo =
&pMac->roam.neighborRoamInfo[sessionId];
#endif
tCsrBssid *bssid = &pResult->Result.BssDescriptor.bssId;
uint8_t channel_id = pResult->Result.BssDescriptor.channelId;
pResult->preferValue = csrGetBssPreferValue(pMac,
(int)pResult->Result.BssDescriptor.rssi, bssid, channel_id);
pResult->capValue =
csrGetBssCapValue(pMac, &pResult->Result.BssDescriptor, pIes);
csrLLInsertTail( &pMac->scan.scanResultList, &pResult->Link, LL_ACCESS_LOCK );
#ifdef FEATURE_WLAN_LFR
if(0 == pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels)
{
/* Build the occupied channel list, only if "gNeighborScanChannelList" is
NOT set in the cfg.ini file */
csrScanAddToOccupiedChannels(pMac, pResult, sessionId,
&pMac->scan.occupiedChannels[sessionId],
pIes);
}
#endif
}
eHalStatus csrScanGetResult(tpAniSirGlobal pMac, tCsrScanResultFilter *pFilter, tScanResultHandle *phResult)
{
eHalStatus status;
tScanResultList *pRetList;
tCsrScanResult *pResult, *pBssDesc;
tANI_U32 count = 0;
tListElem *pEntry;
tANI_U32 bssLen, allocLen;
eCsrEncryptionType uc = eCSR_ENCRYPT_TYPE_NONE, mc = eCSR_ENCRYPT_TYPE_NONE;
eCsrAuthType auth = eCSR_AUTH_TYPE_OPEN_SYSTEM;
tDot11fBeaconIEs *pIes, *pNewIes;
tANI_BOOLEAN fMatch;
tANI_U16 i = 0;
struct roam_ext_params *roam_params = NULL;
if(phResult)
{
*phResult = CSR_INVALID_SCANRESULT_HANDLE;
}
if (pMac->roam.configParam.nSelect5GHzMargin ||
CSR_IS_SELECT_5G_PREFERRED(pMac))
{
pMac->scan.inScanResultBestAPRssi = -128;
roam_params = &pMac->roam.configParam.roam_params;
#ifdef WLAN_DEBUG_ROAM_OFFLOAD
VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_ERROR,
FL("nSelect5GHzMargin"));
#endif
csrLLLock(&pMac->scan.scanResultList);
/* For 5G preference feature, there is no
* need to check the filter match and also re-program the
* RSSI bucket categories, since we use the RSSI values
* while setting the preference value for the BSS.
* There is no need to check the match for roaming since
* it is already done.*/
if(!CSR_IS_SELECT_5G_PREFERRED(pMac)) {
/* Find out the best AP Rssi going thru the scan results */
pEntry = csrLLPeekHead(&pMac->scan.scanResultList, LL_ACCESS_NOLOCK);
while ( NULL != pEntry)
{
pBssDesc = GET_BASE_ADDR( pEntry, tCsrScanResult, Link );
fMatch = FALSE;
if (pFilter)
for(i = 0; i < pFilter->SSIDs.numOfSSIDs; i++)
{
fMatch = csrIsSsidMatch( pMac, pFilter->SSIDs.SSIDList[i].SSID.ssId, pFilter->SSIDs.SSIDList[i].SSID.length,
pBssDesc->Result.ssId.ssId,
pBssDesc->Result.ssId.length, eANI_BOOLEAN_TRUE );
if (fMatch)
{
pIes = (tDot11fBeaconIEs *)( pBssDesc->Result.pvIes );
//At this time, pBssDescription->Result.pvIes may be NULL
if( !pIes && (!HAL_STATUS_SUCCESS(csrGetParsedBssDescriptionIEs(pMac,
&pBssDesc->Result.BssDescriptor, &pIes))) )
{
continue;
}
smsLog(pMac, LOG1, FL("SSID Matched"));
if ( pFilter->bOSENAssociation )
{
fMatch = TRUE;
}
else
{
#ifdef WLAN_FEATURE_11W
fMatch = csrIsSecurityMatch(pMac, &pFilter->authType,
&pFilter->EncryptionType,
&pFilter->mcEncryptionType,
&pFilter->MFPEnabled,
&pFilter->MFPRequired,
&pFilter->MFPCapable,
&pBssDesc->Result.BssDescriptor,
pIes, NULL, NULL, NULL );
#else
fMatch = csrIsSecurityMatch(pMac, &pFilter->authType,
&pFilter->EncryptionType,
&pFilter->mcEncryptionType,
NULL, NULL, NULL,
&pBssDesc->Result.BssDescriptor,
pIes, NULL, NULL, NULL );
#endif
}
if ((pBssDesc->Result.pvIes == NULL) && pIes)
vos_mem_free(pIes);
if (fMatch)
smsLog(pMac, LOG1, FL(" Security Matched"));
}
}
if (fMatch && (pBssDesc->Result.BssDescriptor.rssi > pMac->scan.inScanResultBestAPRssi))
{
smsLog(pMac, LOG1, FL("Best AP Rssi changed from %d to %d"),
pMac->scan.inScanResultBestAPRssi,
pBssDesc->Result.BssDescriptor.rssi);
pMac->scan.inScanResultBestAPRssi = pBssDesc->Result.BssDescriptor.rssi;
}
pEntry = csrLLNext(&pMac->scan.scanResultList, pEntry, LL_ACCESS_NOLOCK);
}
}
if ((-128 != pMac->scan.inScanResultBestAPRssi) ||
CSR_IS_SELECT_5G_PREFERRED(pMac))
{
smsLog(pMac, LOG1, FL("Best AP Rssi is %d"), pMac->scan.inScanResultBestAPRssi);
/* Modify Rssi category based on best AP Rssi */
if (-128 != pMac->scan.inScanResultBestAPRssi)
csrAssignRssiForCategory(pMac, pMac->scan.inScanResultBestAPRssi, pMac->roam.configParam.bCatRssiOffset);
pEntry = csrLLPeekHead(&pMac->scan.scanResultList, LL_ACCESS_NOLOCK);
while ( NULL != pEntry)
{
pBssDesc = GET_BASE_ADDR( pEntry, tCsrScanResult, Link );
/* re-assign preference value based on (modified rssi bucket (or)
* prefer 5G feature.*/
pBssDesc->preferValue = csrGetBssPreferValue(pMac,
(int)pBssDesc->Result.BssDescriptor.rssi,
&pBssDesc->Result.BssDescriptor.bssId,
pBssDesc->Result.BssDescriptor.channelId);
smsLog(pMac, LOG2, FL("BSSID("MAC_ADDRESS_STR
") Rssi(%d) Chnl(%d) PrefVal(%u) SSID=%.*s"),
MAC_ADDR_ARRAY(pBssDesc->Result.BssDescriptor.bssId),
pBssDesc->Result.BssDescriptor.rssi,
pBssDesc->Result.BssDescriptor.channelId,
pBssDesc->preferValue,
pBssDesc->Result.ssId.length, pBssDesc->Result.ssId.ssId);
pEntry = csrLLNext(&pMac->scan.scanResultList, pEntry, LL_ACCESS_NOLOCK);
}
}
csrLLUnlock(&pMac->scan.scanResultList);
}
pRetList = vos_mem_malloc(sizeof(tScanResultList));
if ( NULL == pRetList )
status = eHAL_STATUS_FAILURE;
else
{
status = eHAL_STATUS_SUCCESS;
vos_mem_set(pRetList, sizeof(tScanResultList), 0);
csrLLOpen(pMac->hHdd, &pRetList->List);
pRetList->pCurEntry = NULL;
csrLLLock(&pMac->scan.scanResultList);
pEntry = csrLLPeekHead( &pMac->scan.scanResultList, LL_ACCESS_NOLOCK );
while( pEntry )
{
pBssDesc = GET_BASE_ADDR( pEntry, tCsrScanResult, Link );
pIes = (tDot11fBeaconIEs *)( pBssDesc->Result.pvIes );
/*
* If pBssDesc->Result.pvIes is NULL, we need to free any memory
* allocated by csrMatchBSS for any error condition, otherwise,
* it will be freed later.
*/
fMatch = eANI_BOOLEAN_FALSE;
pNewIes = NULL;
if(pFilter)
{
fMatch = csrMatchBSS(pMac, &pBssDesc->Result.BssDescriptor, pFilter, &auth, &uc, &mc, &pIes);
#ifdef WLAN_DEBUG_ROAM_OFFLOAD
VOS_TRACE(VOS_MODULE_ID_SME, VOS_TRACE_LEVEL_DEBUG,
FL("csrMatchBSS fmatch %d"), fMatch);
#endif
if( NULL != pIes )
{
//Only save it when matching
if(fMatch)
{
if( !pBssDesc->Result.pvIes )
{
//csrMatchBSS allocates the memory. Simply pass it and it is freed later
pNewIes = pIes;
}
else
{
//The pIes is allocated by someone else. make a copy
//Only to save parsed IEs if caller provides a filter. Most likely the caller
//is using to for association, hence save the parsed IEs
pNewIes = vos_mem_malloc(sizeof(tDot11fBeaconIEs));
if ( NULL == pNewIes )
status = eHAL_STATUS_FAILURE;
else
status = eHAL_STATUS_SUCCESS;
if ( HAL_STATUS_SUCCESS( status ) )
{
vos_mem_copy(pNewIes, pIes, sizeof( tDot11fBeaconIEs ));
}
else
{
smsLog(pMac, LOGE, FL(" fail to allocate memory for IEs"));
//Need to free memory allocated by csrMatchBSS
if( !pBssDesc->Result.pvIes )
{
vos_mem_free(pIes);
}
break;
}
}
}//fMatch
else if( !pBssDesc->Result.pvIes )
{
vos_mem_free(pIes);
}
}
}
if(NULL == pFilter || fMatch)
{
bssLen = pBssDesc->Result.BssDescriptor.length + sizeof(pBssDesc->Result.BssDescriptor.length);
allocLen = sizeof( tCsrScanResult ) + bssLen;
pResult = vos_mem_malloc(allocLen);
if ( NULL == pResult )
status = eHAL_STATUS_FAILURE;
else
status = eHAL_STATUS_SUCCESS;
if(!HAL_STATUS_SUCCESS(status))
{
smsLog(pMac, LOGE, FL(" fail to allocate memory for scan result, len=%d"), allocLen);
if(pNewIes)
{
vos_mem_free(pNewIes);
}
break;
}
vos_mem_set(pResult, allocLen, 0);
pResult->capValue = pBssDesc->capValue;
pResult->preferValue = pBssDesc->preferValue;
pResult->ucEncryptionType = uc;
pResult->mcEncryptionType = mc;
pResult->authType = auth;
pResult->Result.ssId = pBssDesc->Result.ssId;
pResult->Result.timer = pBssDesc->Result.timer;
//save the pIes for later use
pResult->Result.pvIes = pNewIes;
//save bss description
vos_mem_copy(&pResult->Result.BssDescriptor,
&pBssDesc->Result.BssDescriptor, bssLen);
//No need to lock pRetList because it is locally allocated and no outside can access it at this time
if(csrLLIsListEmpty(&pRetList->List, LL_ACCESS_NOLOCK))
{
csrLLInsertTail(&pRetList->List, &pResult->Link, LL_ACCESS_NOLOCK);
} else if(pFilter &&
vos_mem_compare(pResult->Result.BssDescriptor.bssId,
pFilter->bssid_hint, VOS_MAC_ADDR_SIZE)) {
/* bssid hint AP should be on head */
csrLLInsertHead(&pRetList->List,
&pResult->Link, LL_ACCESS_NOLOCK);
}
else
{
//To sort the list
tListElem *pTmpEntry;
tCsrScanResult *pTmpResult;
pTmpEntry = csrLLPeekHead(&pRetList->List, LL_ACCESS_NOLOCK);
while(pTmpEntry)
{
pTmpResult = GET_BASE_ADDR( pTmpEntry, tCsrScanResult, Link );
/* Skip the bssid hint AP, as it should be on head */
if (pFilter &&
vos_mem_compare(
pTmpResult->Result.BssDescriptor.bssId,
pFilter->bssid_hint, VOS_MAC_ADDR_SIZE)) {
pTmpEntry = csrLLNext(&pRetList->List,
pTmpEntry, LL_ACCESS_NOLOCK);
continue;
}
if (csrIsBetterBss(pMac, pResult, pTmpResult))
{
csrLLInsertEntry(&pRetList->List, pTmpEntry, &pResult->Link, LL_ACCESS_NOLOCK);
//To indicate we are done
pResult = NULL;
break;
}
pTmpEntry = csrLLNext(&pRetList->List, pTmpEntry, LL_ACCESS_NOLOCK);
}
if(pResult != NULL)
{
/* This one is'nt better than anyone or the first one */
csrLLInsertTail(&pRetList->List, &pResult->Link, LL_ACCESS_NOLOCK);
}
}
count++;
}
pEntry = csrLLNext( &pMac->scan.scanResultList, pEntry, LL_ACCESS_NOLOCK );
}//while
csrLLUnlock(&pMac->scan.scanResultList);
smsLog(pMac, LOG2, FL("return %d BSS"), csrLLCount(&pRetList->List));
if( !HAL_STATUS_SUCCESS(status) || (phResult == NULL) )
{
//Fail or No one wants the result.
csrScanResultPurge(pMac, (tScanResultHandle)pRetList);
}
else
{
if(0 == count)
{
//We are here meaning the there is no match
csrLLClose(&pRetList->List);
vos_mem_free(pRetList);
status = eHAL_STATUS_E_NULL_VALUE;
}
else if(phResult)
{
*phResult = pRetList;
}
}
}//Allocated pRetList
return (status);
}
/*
* NOTE: This routine is being added to make
* sure that scan results are not being flushed
* while roaming. If the scan results are flushed,
* we are unable to recover from
* csrRoamRoamingStateDisassocRspProcessor.
* If it is needed to remove this routine,
* first ensure that we recover gracefully from
* csrRoamRoamingStateDisassocRspProcessor if
* csrScanGetResult returns with a failure because
* of not being able to find the roaming BSS.
*/
tANI_U8 csrScanFlushDenied(tpAniSirGlobal pMac, tANI_U8 sessionId)
{
switch(pMac->roam.neighborRoamInfo[sessionId].neighborRoamState) {
case eCSR_NEIGHBOR_ROAM_STATE_REPORT_SCAN:
case eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING:
case eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE:
case eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING:
return (pMac->roam.neighborRoamInfo[sessionId].neighborRoamState);
default:
return 0;
}
}
eHalStatus csrScanFlushResult(tpAniSirGlobal pMac, tANI_U8 sessionId)
{
tANI_U8 isFlushDenied = csrScanFlushDenied(pMac, sessionId);
eHalStatus status = eHAL_STATUS_SUCCESS;
tSirMbMsg *pMsg;
tANI_U16 msgLen;
if (isFlushDenied) {
smsLog(pMac, LOGW, "%s: scan flush denied in roam state %d",
__func__, isFlushDenied);
return eHAL_STATUS_FAILURE;
}
/* prepare and send clear cached scan results msg to lim */
msgLen = (tANI_U16)(sizeof( tSirMbMsg ));
pMsg = vos_mem_malloc(msgLen);
if ( NULL != pMsg ) {
vos_mem_set((void *)pMsg, msgLen, 0);
pMsg->type = pal_cpu_to_be16((tANI_U16)eWNI_SME_CLEAR_LIM_SCAN_CACHE);
pMsg->msgLen = pal_cpu_to_be16(msgLen);
palSendMBMessage(pMac->hHdd, pMsg);
} else {
status = eHAL_STATUS_FAILED_ALLOC;
}
csrLLScanPurgeResult( pMac, &pMac->scan.tempScanResults );
csrLLScanPurgeResult( pMac, &pMac->scan.scanResultList );
return( status );
}
eHalStatus csrScanFlushSelectiveResult(tpAniSirGlobal pMac, v_BOOL_t flushP2P)
{
eHalStatus status = eHAL_STATUS_SUCCESS;
tListElem *pEntry,*pFreeElem;
tCsrScanResult *pBssDesc;
tDblLinkList *pList = &pMac->scan.scanResultList;
csrLLLock(pList);
pEntry = csrLLPeekHead( pList, LL_ACCESS_NOLOCK );
while( pEntry != NULL)
{
pBssDesc = GET_BASE_ADDR( pEntry, tCsrScanResult, Link );
if( flushP2P == vos_mem_compare( pBssDesc->Result.ssId.ssId,
"DIRECT-", 7) )
{
pFreeElem = pEntry;
pEntry = csrLLNext(pList, pEntry, LL_ACCESS_NOLOCK);
csrLLRemoveEntry(pList, pFreeElem, LL_ACCESS_NOLOCK);
csrFreeScanResultEntry( pMac, pBssDesc );
continue;
}
pEntry = csrLLNext(pList, pEntry, LL_ACCESS_NOLOCK);
}
csrLLUnlock(pList);
return (status);
}
void csrScanFlushBssEntry(tpAniSirGlobal pMac,
tpSmeCsaOffloadInd pCsaOffloadInd)
{
tListElem *pEntry,*pFreeElem;
tCsrScanResult *pBssDesc;
tDblLinkList *pList = &pMac->scan.scanResultList;
csrLLLock(pList);
pEntry = csrLLPeekHead( pList, LL_ACCESS_NOLOCK );
while( pEntry != NULL)
{
pBssDesc = GET_BASE_ADDR( pEntry, tCsrScanResult, Link );
if( vos_mem_compare(pBssDesc->Result.BssDescriptor.bssId,
pCsaOffloadInd->bssId, sizeof(tSirMacAddr)) )
{
pFreeElem = pEntry;
pEntry = csrLLNext(pList, pEntry, LL_ACCESS_NOLOCK);
csrLLRemoveEntry(pList, pFreeElem, LL_ACCESS_NOLOCK);
csrFreeScanResultEntry( pMac, pBssDesc );
smsLog( pMac, LOG1, FL("Removed BSS entry:%pM"),
pCsaOffloadInd->bssId);
continue;
}
pEntry = csrLLNext(pList, pEntry, LL_ACCESS_NOLOCK);
}
csrLLUnlock(pList);
}
/**
* csrCheck11dChannel
*
*FUNCTION:
* This function is called from csrScanFilterResults function and
* compare channel number with given channel list.
*
*LOGIC:
* Check Scan result channel number with CFG channel list
*
*ASSUMPTIONS:
*
*
*NOTE:
*
* @param channelId channel number
* @param pChannelList Pointer to channel list
* @param numChannels Number of channel in channel list
*
* @return Status
*/
eHalStatus csrCheck11dChannel(tANI_U8 channelId, tANI_U8 *pChannelList, tANI_U32 numChannels)
{
eHalStatus status = eHAL_STATUS_FAILURE;
tANI_U8 i = 0;
for (i = 0; i < numChannels; i++)
{
if(pChannelList[ i ] == channelId)
{
status = eHAL_STATUS_SUCCESS;
break;
}
}
return status;
}
/**
* csrScanFilterResults
*
*FUNCTION:
* This function is called from csrApplyCountryInformation function and
* filter scan result based on valid channel list number.
*
*LOGIC:
* Get scan result from scan list and Check Scan result channel number
* with 11d channel list if channel number is found in 11d channel list
* then do not remove scan result entry from scan list
*
*ASSUMPTIONS:
*
*
*NOTE:
*
* @param pMac Pointer to Global MAC structure
*
* @return Status
*/
eHalStatus csrScanFilterResults(tpAniSirGlobal pMac)
{
eHalStatus status = eHAL_STATUS_SUCCESS;
tListElem *pEntry,*pTempEntry;
tCsrScanResult *pBssDesc;
tANI_U32 len = sizeof(pMac->roam.validChannelList);
/* Get valid channels list from CFG */
if (!HAL_STATUS_SUCCESS(csrGetCfgValidChannels(pMac,
pMac->roam.validChannelList, &len)))
{
smsLog( pMac, LOGE, "Failed to get Channel list from CFG");
}
csrLLLock(&pMac->scan.scanResultList);
pEntry = csrLLPeekHead(&pMac->scan.scanResultList, LL_ACCESS_NOLOCK);
while( pEntry )
{
pBssDesc = GET_BASE_ADDR( pEntry, tCsrScanResult, Link );
pTempEntry = csrLLNext(&pMac->scan.scanResultList, pEntry,
LL_ACCESS_NOLOCK);
if(csrCheck11dChannel(pBssDesc->Result.BssDescriptor.channelId,
pMac->roam.validChannelList, len))
{
/* Remove Scan result which does not have 11d channel */
if( csrLLRemoveEntry(&pMac->scan.scanResultList, pEntry,
LL_ACCESS_NOLOCK))
{
csrFreeScanResultEntry( pMac, pBssDesc );
}
}
pEntry = pTempEntry;
}
csrLLUnlock(&pMac->scan.scanResultList);
csrLLLock(&pMac->scan.tempScanResults);
pEntry = csrLLPeekHead(&pMac->scan.tempScanResults, LL_ACCESS_NOLOCK);
while( pEntry )
{
pBssDesc = GET_BASE_ADDR( pEntry, tCsrScanResult, Link );
pTempEntry = csrLLNext(&pMac->scan.tempScanResults, pEntry,
LL_ACCESS_NOLOCK);
if(csrCheck11dChannel(pBssDesc->Result.BssDescriptor.channelId,
pMac->roam.validChannelList, len))
{
/* Remove Scan result which does not have 11d channel */
if(csrLLRemoveEntry(&pMac->scan.tempScanResults, pEntry,
LL_ACCESS_NOLOCK))
{
csrFreeScanResultEntry( pMac, pBssDesc );
}
}
else
{
smsLog( pMac, LOG1, FL("%d is a Valid channel"),
pBssDesc->Result.BssDescriptor.channelId);
}
pEntry = pTempEntry;
}
csrLLUnlock(&pMac->scan.tempScanResults);
return status;
}
eHalStatus csrScanCopyResultList(tpAniSirGlobal pMac, tScanResultHandle hIn, tScanResultHandle *phResult)
{
eHalStatus status = eHAL_STATUS_SUCCESS;
tScanResultList *pRetList, *pInList = (tScanResultList *)hIn;
tCsrScanResult *pResult, *pScanResult;
tANI_U32 count = 0;
tListElem *pEntry;
tANI_U32 bssLen, allocLen;
if(phResult)
{
*phResult = CSR_INVALID_SCANRESULT_HANDLE;
}
pRetList = vos_mem_malloc(sizeof(tScanResultList));
if ( NULL == pRetList )
status = eHAL_STATUS_FAILURE;
else
{
vos_mem_set(pRetList, sizeof(tScanResultList), 0);
csrLLOpen(pMac->hHdd, &pRetList->List);
pRetList->pCurEntry = NULL;
csrLLLock(&pMac->scan.scanResultList);
csrLLLock(&pInList->List);
pEntry = csrLLPeekHead( &pInList->List, LL_ACCESS_NOLOCK );
while( pEntry )
{
pScanResult = GET_BASE_ADDR( pEntry, tCsrScanResult, Link );
bssLen = pScanResult->Result.BssDescriptor.length + sizeof(pScanResult->Result.BssDescriptor.length);
allocLen = sizeof( tCsrScanResult ) + bssLen;
pResult = vos_mem_malloc(allocLen);
if ( NULL == pResult )
status = eHAL_STATUS_FAILURE;
else
status = eHAL_STATUS_SUCCESS;
if (!HAL_STATUS_SUCCESS(status))
{
csrScanResultPurge(pMac, (tScanResultHandle *)pRetList);
count = 0;
break;
}
vos_mem_set(pResult, allocLen , 0);
vos_mem_copy(&pResult->Result.BssDescriptor, &pScanResult->Result.BssDescriptor, bssLen);
if( pScanResult->Result.pvIes )
{
pResult->Result.pvIes = vos_mem_malloc(sizeof( tDot11fBeaconIEs ));
if ( NULL == pResult->Result.pvIes )
status = eHAL_STATUS_FAILURE;
else
status = eHAL_STATUS_SUCCESS;
if (!HAL_STATUS_SUCCESS(status))
{
//Free the memory we allocate above first
vos_mem_free(pResult);
csrScanResultPurge(pMac, (tScanResultHandle *)pRetList);
count = 0;
break;
}
vos_mem_copy(pResult->Result.pvIes, pScanResult->Result.pvIes,
sizeof( tDot11fBeaconIEs ));
}
csrLLInsertTail(&pRetList->List, &pResult->Link, LL_ACCESS_LOCK);
count++;
pEntry = csrLLNext( &pInList->List, pEntry, LL_ACCESS_NOLOCK );
}//while
csrLLUnlock(&pInList->List);
csrLLUnlock(&pMac->scan.scanResultList);
if(HAL_STATUS_SUCCESS(status))
{
if(0 == count)
{
csrLLClose(&pRetList->List);
vos_mem_free(pRetList);
status = eHAL_STATUS_E_NULL_VALUE;
}
else if(phResult)
{
*phResult = pRetList;
}
}
}//Allocated pRetList
return (status);
}
eHalStatus csrScanningStateMsgProcessor( tpAniSirGlobal pMac, void *pMsgBuf )
{
eHalStatus status = eHAL_STATUS_SUCCESS;
tSirMbMsg *pMsg = (tSirMbMsg *)pMsgBuf;
tSirSmeDisConDoneInd *pDisConDoneInd;
tCsrRoamInfo roamInfo = {0};
tCsrRoamSession *pSession;
if ((eWNI_SME_SCAN_RSP == pMsg->type) ||
(eWNI_SME_GET_SCANNED_CHANNEL_RSP == pMsg->type)) {
status = csrScanSmeScanResponse( pMac, pMsgBuf );
} else {
switch (pMsg->type) {
case eWNI_SME_UPPER_LAYER_ASSOC_CNF:
{
tSirSmeAssocIndToUpperLayerCnf *pUpperLayerAssocCnf;
tCsrRoamInfo *pRoamInfo = NULL;
tANI_U32 sessionId;
eHalStatus status;
smsLog(pMac, LOG1,
FL("Scanning : ASSOCIATION confirmation can be given to upper layer "));
pRoamInfo = &roamInfo;
pUpperLayerAssocCnf =
(tSirSmeAssocIndToUpperLayerCnf *)pMsgBuf;
status = csrRoamGetSessionIdFromBSSID( pMac,
(tCsrBssid *)pUpperLayerAssocCnf->bssId,
&sessionId );
pSession = CSR_GET_SESSION(pMac, sessionId);
if(!pSession) {
smsLog(pMac, LOGE,
FL(" session %d not found "),
sessionId);
return eHAL_STATUS_FAILURE;
}
//send the status code as Success
pRoamInfo->statusCode = eSIR_SME_SUCCESS;
pRoamInfo->u.pConnectedProfile =
&pSession->connectedProfile;
pRoamInfo->staId = (tANI_U8)pUpperLayerAssocCnf->aid;
pRoamInfo->rsnIELen =
(tANI_U8)pUpperLayerAssocCnf->rsnIE.length;
pRoamInfo->prsnIE =
pUpperLayerAssocCnf->rsnIE.rsnIEdata;
pRoamInfo->addIELen =
(tANI_U8)pUpperLayerAssocCnf->addIE.length;
pRoamInfo->paddIE =
pUpperLayerAssocCnf->addIE.addIEdata;
vos_mem_copy(pRoamInfo->peerMac,
pUpperLayerAssocCnf->peerMacAddr,
sizeof(tSirMacAddr));
vos_mem_copy(&pRoamInfo->bssid,
pUpperLayerAssocCnf->bssId,
sizeof(tCsrBssid));
pRoamInfo->wmmEnabledSta =
pUpperLayerAssocCnf->wmmEnabledSta;
if (CSR_IS_INFRA_AP(pRoamInfo->u.pConnectedProfile)) {
pMac->roam.roamSession[sessionId].connectState =
eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED;
pRoamInfo->fReassocReq =
pUpperLayerAssocCnf->reassocReq;
status = csrRoamCallCallback(pMac, sessionId,
pRoamInfo, 0,
eCSR_ROAM_INFRA_IND,
eCSR_ROAM_RESULT_INFRA_ASSOCIATION_CNF);
}
if(CSR_IS_WDS_AP( pRoamInfo->u.pConnectedProfile)) {
vos_sleep( 100 );
pMac->roam.roamSession[sessionId].connectState =
//Sta
eCSR_ASSOC_STATE_TYPE_WDS_CONNECTED;
status = csrRoamCallCallback(pMac,
sessionId, pRoamInfo, 0,
eCSR_ROAM_WDS_IND,
//Sta
eCSR_ROAM_RESULT_WDS_ASSOCIATION_IND);
}
break;
}
case eWNI_SME_DISCONNECT_DONE_IND:
pDisConDoneInd = (tSirSmeDisConDoneInd *)(pMsg);
smsLog( pMac, LOG1,
FL("eWNI_SME_DISCONNECT_DONE_IND RC:%d"),
pDisConDoneInd->reasonCode);
pSession = CSR_GET_SESSION(pMac,
pDisConDoneInd->sessionId);
if (!pSession) {
smsLog(pMac, LOGE, FL("Invalid session"));
return eHAL_STATUS_FAILURE;
}
if (CSR_IS_SESSION_VALID(pMac,
pDisConDoneInd->sessionId))
{
roamInfo.reasonCode =
pDisConDoneInd->reasonCode;
roamInfo.statusCode =
eSIR_SME_STA_DISASSOCIATED;
vos_mem_copy(roamInfo.peerMac,
pDisConDoneInd->peerMacAddr,
sizeof(tSirMacAddr));
status = csrRoamCallCallback(pMac,
pDisConDoneInd->sessionId,
&roamInfo, 0,
eCSR_ROAM_LOSTLINK,
eCSR_ROAM_RESULT_DISASSOC_IND);
/*
* Update the previous state if
* previous to eCSR_ROAMING_STATE_IDLE
* as we are disconnected and
* currunt state is scanning
*/
if (!CSR_IS_INFRA_AP(
&pSession->connectedProfile))
pMac->roam.prev_state[
pDisConDoneInd->sessionId] =
eCSR_ROAMING_STATE_IDLE;
}
else
{
smsLog(pMac, LOGE, FL("Inactive session %d"),
pDisConDoneInd->sessionId);
status = eHAL_STATUS_FAILURE;
}
break;
default :
if (csrIsAnySessionInConnectState(pMac)) {
/* In case of we are connected, we need to check
* whether connect status changes because scan
* may also run while connected.
*/
csrRoamCheckForLinkStatusChange( pMac,
(tSirSmeRsp *)pMsgBuf );
} else {
smsLog( pMac, LOGW,
"Message [0x%04x] received in state, when expecting Scan Response",
pMsg->type );
}
}
}
return (status);
}
void csrCheckNSaveWscIe(tpAniSirGlobal pMac, tSirBssDescription *pNewBssDescr, tSirBssDescription *pOldBssDescr)
{
int idx, len;
tANI_U8 *pbIe;
//If failed to remove, assuming someone else got it.
if((pNewBssDescr->fProbeRsp != pOldBssDescr->fProbeRsp) &&
(0 == pNewBssDescr->WscIeLen))
{
idx = 0;
len = GET_IE_LEN_IN_BSS(pOldBssDescr->length) - DOT11F_IE_WSCPROBERES_MIN_LEN - 2;
pbIe = (tANI_U8 *)pOldBssDescr->ieFields;
//Save WPS IE if it exists
pNewBssDescr->WscIeLen = 0;
while(idx < len)
{
if((DOT11F_EID_WSCPROBERES == pbIe[0]) &&
(0x00 == pbIe[2]) && (0x50 == pbIe[3]) && (0xf2 == pbIe[4]) && (0x04 == pbIe[5]))
{
/* Found it */
if((DOT11F_IE_WSCPROBERES_MAX_LEN - 2) >= pbIe[1])
{
vos_mem_copy(pNewBssDescr->WscIeProbeRsp, pbIe, pbIe[1] + 2);
pNewBssDescr->WscIeLen = pbIe[1] + 2;
}
break;
}
idx += pbIe[1] + 2;
pbIe += pbIe[1] + 2;
}
}
}
//pIes may be NULL
tANI_BOOLEAN csrRemoveDupBssDescription( tpAniSirGlobal pMac, tSirBssDescription *pSirBssDescr,
tDot11fBeaconIEs *pIes, tAniSSID *pSsid, v_TIME_t *timer, tANI_BOOLEAN fForced )
{
tListElem *pEntry;
tCsrScanResult *pBssDesc;
tANI_BOOLEAN fRC = FALSE;
// Walk through all the chained BssDescriptions. If we find a chained BssDescription that
// matches the BssID of the BssDescription passed in, then these must be duplicate scan
// results for this Bss. In that case, remove the 'old' Bss description from the linked list.
csrLLLock(&pMac->scan.scanResultList);
pEntry = csrLLPeekHead(&pMac->scan.scanResultList, LL_ACCESS_NOLOCK);
while( pEntry )
{
pBssDesc = GET_BASE_ADDR( pEntry, tCsrScanResult, Link );
// we have a duplicate scan results only when BSSID, SSID, Channel and NetworkType
// matches
if ( csrIsDuplicateBssDescription( pMac, &pBssDesc->Result.BssDescriptor,
pSirBssDescr, pIes, fForced ) )
{
int32_t rssi_new, rssi_old;
rssi_new = (int32_t) pSirBssDescr->rssi;
rssi_old = (int32_t) pBssDesc->Result.BssDescriptor.rssi;
rssi_new = ((rssi_new * CSR_SCAN_RESULT_RSSI_WEIGHT) +
rssi_old * (100 - CSR_SCAN_RESULT_RSSI_WEIGHT)) / 100;
pSirBssDescr->rssi = (tANI_S8) rssi_new;
rssi_new = (int32_t) pSirBssDescr->rssi_raw;
rssi_old = (int32_t) pBssDesc->Result.BssDescriptor.rssi_raw;
rssi_new = ((rssi_new * CSR_SCAN_RESULT_RSSI_WEIGHT) +
rssi_old * (100 - CSR_SCAN_RESULT_RSSI_WEIGHT)) / 100;
pSirBssDescr->rssi_raw = (tANI_S8) rssi_new;
// Remove the 'old' entry from the list....
if(csrLLRemoveEntry(&pMac->scan.scanResultList, pEntry,
LL_ACCESS_NOLOCK))
{
// !we need to free the memory associated with this node
//If failed to remove, assuming someone else got it.
*pSsid = pBssDesc->Result.ssId;
*timer = pBssDesc->Result.timer;
csrCheckNSaveWscIe(pMac, pSirBssDescr, &pBssDesc->Result.BssDescriptor);
csrFreeScanResultEntry( pMac, pBssDesc );
}
else
{
smsLog( pMac, LOGW, FL( " fail to remove entry" ) );
}
fRC = TRUE;
// If we found a match, we can stop looking through the list.
break;
}
pEntry = csrLLNext(&pMac->scan.scanResultList, pEntry,
LL_ACCESS_NOLOCK);
}
csrLLUnlock(&pMac->scan.scanResultList);
return fRC;
}
eHalStatus csrAddPMKIDCandidateList( tpAniSirGlobal pMac, tANI_U32 sessionId,
tSirBssDescription *pBssDesc, tDot11fBeaconIEs *pIes )
{