/*
 * currBss.c
 *
 * Copyright(c) 1998 - 2010 Texas Instruments. All rights reserved.      
 * All rights reserved.                                                  
 *                                                                       
 * Redistribution and use in source and binary forms, with or without    
 * modification, are permitted provided that the following conditions    
 * are met:                                                              
 *                                                                       
 *  * Redistributions of source code must retain the above copyright     
 *    notice, this list of conditions and the following disclaimer.      
 *  * Redistributions in binary form must reproduce the above copyright  
 *    notice, this list of conditions and the following disclaimer in    
 *    the documentation and/or other materials provided with the         
 *    distribution.                                                      
 *  * Neither the name Texas Instruments nor the names of its            
 *    contributors may be used to endorse or promote products derived    
 *    from this software without specific prior written permission.      
 *                                                                       
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT      
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT   
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/** \file currBss.c
 *  \brief Current BSS info
 *
 *  \see currBss.h
 */

/****************************************************************************
 *                                                                          *
 *   MODULE:  Current BSS                                                   *
 *   PURPOSE:                                                               *
 *   Roaming ability of eSTA is implemented by Roaming Manager Component and 
 *   described in "Roaming Manager module LLD" document, and by 
 *   AP Connection module. AP Connection module implemented as two sub-modules.
 *   The major one is AP Connection, that is responsible for: 
 *   - providing Roaming Manager with access to other parts of WLAN Driver, 
 *   - implementing low levels of roaming mechanism.
 *   Current BSS sub-module takes care of:
 *   - maintaining database of current AP info,
 *   - providing access to database of current AP info.
 *   The Current BSS represents the BSS we are currently connected to. 
 *   Among other parameters, it holds the capabilities of the current AP, 
 *   its ID and its quality.
 *   When FW indicates 'Out of Sync' event, Current BSS module is responsible
 *   for awaking the device, sending unicast Probe request, waiting for
 *   response and - in case FW comes to the conclusion that there was 
 *   no response - for triggering "Beacon missed" to AP Connection module. 
 *   In eSTA5.0 FW updates and checks the quality of the connection with
 *   current AP. Current BSS module is responsible to handle event of type
 *   'Low RSSI' from FW. Third type of roaming event reported by FW is
 *   'Consecutive no ack on TX", and it is handled as well by Current
 *   BSS module.Upon reception of any roaming event from FW, Current BSS
 *   module is transferring this event to the AP Connection module in case
 *   of BSS connection, or to SME module in case of IBSS connection.
 *   When WLAN driver is working in IBSS mode, Current BSS module is holding
 *   the parameters of BSS (channel, band, SSID etc.).
 *                                                                          *
 ****************************************************************************/

#define __FILE_ID__  FILE_ID_65
#include "currBss.h"
#include "currBssApi.h"
#include "osApi.h"
#include "report.h"
#include "802_11Defs.h"
#include "DataCtrl_Api.h"
#include "qosMngr_API.h"
#include "regulatoryDomainApi.h"
#include "apConn.h"
#include "scanMngrApi.h" 
#include "MacServices_api.h"
#include "smeApi.h"
#include "sme.h"
#include "TWDriver.h"
#include "EvHandler.h"
#include "DrvMainModules.h"
#include "siteMgrApi.h"
#include "connApi.h"
#include "roamingMngrTypes.h"

/* Constants */
#define TRIGGER_LOW_RSSI_PACING 1000
#define TRIGGER_LOW_SNR_PACING 1000
#define TRIGGER_BG_SCAN_PACING 10
#define TRIGGER_BG_SCAN_HYSTERESIS 3
static const TI_UINT32 KEEP_ALIVE_NULL_DATA_INDEX = 3;

/* Enumerations */


/* Typedefs */

typedef TI_UINT8 (*currBSS_beaconRxCallb_t) (TI_HANDLE hModule, TI_UINT64 staTSF, TI_UINT8 dtimCount);


/* Structures */

 
/* Internal functions prototypes */

static void currBSS_lowRssiThrCrossed(currBSS_t *hCurrBSS, TI_UINT8 *data, TI_UINT8 dataLength);
static void currBSS_lowSnrThrCrossed(currBSS_t *hCurrBSS, TI_UINT8 *data, TI_UINT8 dataLength);
static void currBSS_BackgroundScanQuality(TI_HANDLE hCurrBSS, TI_UINT8 *data, TI_UINT8 dataLength);
static void currBSS_consecTxErrors(currBSS_t *hCurrBSS, TI_UINT8 *data, TI_UINT8 dataLength);
static void currBSS_BssLost (currBSS_t *hCurrBSS, TI_UINT8 *data, TI_UINT8 dataLength);
static void currBSS_reportRoamingEvent(currBSS_t *hCurrBSS, apConn_roamingTrigger_e roamingEventType, roamingEventData_u *pRoamingEventData);
static void currBSS_updateBSSLoss(currBSS_t *pCurrBSS);

static TI_STATUS currBss_HandleTriggerEvent(TI_HANDLE hCurrBSS, TI_UINT8 *data, TI_UINT8 dataLength, TI_UINT8 eventID);
static triggerDesc_t* currBss_findEmptyUserTrigger(TI_HANDLE hCurrBSS, TI_UINT16 clientID, TI_UINT8* triggerIdx);
static void currBSS_RssiSnrTrigger0 (TI_HANDLE hCurrBSS, TI_UINT8 *data, TI_UINT8 dataLength);
static void currBSS_RssiSnrTrigger1 (TI_HANDLE hCurrBSS, TI_UINT8 *data, TI_UINT8 dataLength);
static void currBSS_RssiSnrTrigger2 (TI_HANDLE hCurrBSS, TI_UINT8 *data, TI_UINT8 dataLength);
static void currBSS_RssiSnrTrigger3 (TI_HANDLE hCurrBSS, TI_UINT8 *data, TI_UINT8 dataLength);
static void currBSS_RssiSnrTrigger4 (TI_HANDLE hCurrBSS, TI_UINT8 *data, TI_UINT8 dataLength);
static void currBSS_RssiSnrTrigger5 (TI_HANDLE hCurrBSS, TI_UINT8 *data, TI_UINT8 dataLength);
static void currBSS_RssiSnrTrigger6 (TI_HANDLE hCurrBSS, TI_UINT8 *data, TI_UINT8 dataLength);
static void currBSS_RssiSnrTrigger7 (TI_HANDLE hCurrBSS, TI_UINT8 *data, TI_UINT8 dataLength);

/* Public functions implementation */



/**
*
* currBSS_create
*
* \b Description: 
*
* Create the Current BSS context: allocate memory for internal variables
*
* \b ARGS:
*
*  I   - hOS - the handle to the OS object
*  
* \b RETURNS:
*
*  TI_OK on success, TI_NOK on failure.
*
* \sa 
*/
TI_HANDLE currBSS_create(TI_HANDLE hOs)
{
    currBSS_t   *pCurrBss;

    if ((pCurrBss = os_memoryAlloc(hOs, sizeof(currBSS_t))) != NULL)
    {
        pCurrBss->hOs = hOs;
    
        return pCurrBss;
    }
    else /* Failed to allocate control block */
    {
        WLAN_OS_REPORT(("FATAL ERROR: currBSS_create(): Error allocating cb - aborting\n"));
        return NULL;
    }
}


/**
*
* currBSS_unload
*
* \b Description: 
*
* Finish Current BSS module work.
*
* \b ARGS:
*
*  
* \b RETURNS:
*
*  TI_OK on success, TI_NOK on failure.
*
* \sa 
*/
TI_STATUS currBSS_unload(TI_HANDLE hCurrBSS)
{
    currBSS_t   *pCurrBSS;
    
    if (hCurrBSS != NULL)
    {
        pCurrBSS = (currBSS_t *)hCurrBSS;

        /* Free pre-allocated control block */
        os_memoryFree(pCurrBSS->hOs, pCurrBSS, sizeof(currBSS_t));
    }
    return TI_OK;
}


/**
*
* currBSS_init
*
* \b Description: 
*
* Get other modules handles.
*
* \b ARGS:
*
*  I   pStadHandles - The driver modules handles
*  
* \b RETURNS:
*
*  void
*
* \sa 
*/
void currBSS_init (TStadHandlesList *pStadHandles)
{
    currBSS_t *pCurrBSS = (currBSS_t *)(pStadHandles->hCurrBss);
    int i=0;

    pCurrBSS->hAPConn       = pStadHandles->hAPConnection;
    pCurrBSS->hTWD          = pStadHandles->hTWD;
    pCurrBSS->hMlme         = pStadHandles->hMlmeSm;
    pCurrBSS->hPowerMngr    = pStadHandles->hPowerMgr;
    pCurrBSS->hSme          = pStadHandles->hSme;
    pCurrBSS->hSiteMgr      = pStadHandles->hSiteMgr;
	pCurrBSS->hConn         = pStadHandles->hConn;
    pCurrBSS->hReport       = pStadHandles->hReport;
    pCurrBSS->hScanMngr     = pStadHandles->hScanMngr;
    pCurrBSS->hEvHandler    = pStadHandles->hEvHandler;
    pCurrBSS->hTxCtrl       = pStadHandles->hTxCtrl;

    for (i=0; i< MAX_NUM_OF_RSSI_SNR_TRIGGERS ; i++)
    {
        pCurrBSS->aTriggersDesc[i].clientID = 0;
        pCurrBSS->aTriggersDesc[i].fCB = NULL;
		pCurrBSS->aTriggersDesc[i].hCB = NULL;
        pCurrBSS->aTriggersDesc[i].WasRegisteredByApp = TI_FALSE;

    }
}


/**
*
* currBSS_SetDefaults
*
* \b Description: 
*
* Prepare Current BSS module to work
*
* \b ARGS:
*
*  I   - hCurrBSS - Current BSS handle \n
*  
* \b RETURNS:
*
*  TI_OK on success, TI_NOK on failure.
*
* \sa 
*/
TI_STATUS currBSS_SetDefaults (TI_HANDLE hCurrBSS, TCurrBssInitParams *pInitParams)
{
    currBSS_t *pCurrBSS = (currBSS_t *)hCurrBSS;
    TRroamingTriggerParams params;
    RssiSnrTriggerCfg_t tTriggerCfg;
    
    /* save the roaming operational mode */
    pCurrBSS->RoamingOperationalMode = pInitParams->RoamingOperationalMode;

    /* Registration succeeded, continue with init procedure */
    pCurrBSS->band = RADIO_BAND_2_4_GHZ;
    pCurrBSS->channel = 0;
    pCurrBSS->isConnected = TI_FALSE;
    pCurrBSS->type = BSS_ANY;
    pCurrBSS->currAPInfo.RSSI = 0;
    pCurrBSS->bUseSGParams = TI_FALSE;
    pCurrBSS->uDefaultKeepAlivePeriod = pInitParams->uNullDataKeepAlivePeriod; 


    /* register the static callbacks */
    TWD_RegisterEvent(pCurrBSS->hTWD,TWD_OWN_EVENT_RSSI_SNR_TRIGGER_0,(void*) currBSS_RssiSnrTrigger0, pCurrBSS);
    TWD_RegisterEvent(pCurrBSS->hTWD,TWD_OWN_EVENT_RSSI_SNR_TRIGGER_1,(void*) currBSS_RssiSnrTrigger1, pCurrBSS);
    TWD_RegisterEvent(pCurrBSS->hTWD,TWD_OWN_EVENT_RSSI_SNR_TRIGGER_2,(void*) currBSS_RssiSnrTrigger2, pCurrBSS);
    TWD_RegisterEvent(pCurrBSS->hTWD,TWD_OWN_EVENT_RSSI_SNR_TRIGGER_3,(void*) currBSS_RssiSnrTrigger3, pCurrBSS);
    TWD_RegisterEvent(pCurrBSS->hTWD,TWD_OWN_EVENT_RSSI_SNR_TRIGGER_4,(void*) currBSS_RssiSnrTrigger4, pCurrBSS);
    TWD_RegisterEvent(pCurrBSS->hTWD,TWD_OWN_EVENT_RSSI_SNR_TRIGGER_5,(void*) currBSS_RssiSnrTrigger5, pCurrBSS);
    TWD_RegisterEvent(pCurrBSS->hTWD,TWD_OWN_EVENT_RSSI_SNR_TRIGGER_6,(void*) currBSS_RssiSnrTrigger6, pCurrBSS);
    TWD_RegisterEvent(pCurrBSS->hTWD,TWD_OWN_EVENT_RSSI_SNR_TRIGGER_7,(void*) currBSS_RssiSnrTrigger7, pCurrBSS);

    if (ROAMING_OPERATIONAL_MODE_AUTO == pCurrBSS->RoamingOperationalMode)
    {
        /* Configure and enable the Low RSSI, the Low SNR and the Missed beacon events */
        currBSS_RegisterTriggerEvent(hCurrBSS, TWD_OWN_EVENT_RSSI_SNR_TRIGGER_0, 0, (void*)currBSS_lowRssiThrCrossed, hCurrBSS);
        currBSS_RegisterTriggerEvent(hCurrBSS, TWD_OWN_EVENT_RSSI_SNR_TRIGGER_1, 0, (void*)currBSS_lowSnrThrCrossed, hCurrBSS);
        currBSS_RegisterTriggerEvent(hCurrBSS, TWD_OWN_EVENT_RSSI_SNR_TRIGGER_4, 0, (void*)currBSS_BackgroundScanQuality, hCurrBSS);

        pCurrBSS->lowRssiThreshold = RSSI_DEFAULT_THRESHOLD;
        tTriggerCfg.index     = TRIGGER_EVENT_LOW_RSSI;
        tTriggerCfg.threshold = pCurrBSS->lowRssiThreshold;
        tTriggerCfg.pacing    = TRIGGER_LOW_RSSI_PACING;
        tTriggerCfg.metric    = METRIC_EVENT_RSSI_BEACON;
        tTriggerCfg.type      = RX_QUALITY_EVENT_LEVEL;
        tTriggerCfg.direction = RSSI_EVENT_DIR_LOW;
        tTriggerCfg.hystersis = 0;
        tTriggerCfg.enable    = TI_TRUE;
        TWD_CfgRssiSnrTrigger (pCurrBSS->hTWD, &tTriggerCfg);
    
        pCurrBSS->lowSnrThreshold = SNR_DEFAULT_THRESHOLD;
        tTriggerCfg.index     = TRIGGER_EVENT_LOW_SNR;
        tTriggerCfg.threshold = pCurrBSS->lowSnrThreshold;
        tTriggerCfg.pacing    = TRIGGER_LOW_SNR_PACING;
        tTriggerCfg.metric    = METRIC_EVENT_SNR_BEACON;
        tTriggerCfg.type      = RX_QUALITY_EVENT_LEVEL;
        tTriggerCfg.direction = RSSI_EVENT_DIR_LOW;
        tTriggerCfg.hystersis = 0;
        tTriggerCfg.enable    = TI_TRUE;
        TWD_CfgRssiSnrTrigger (pCurrBSS->hTWD, &tTriggerCfg);

        pCurrBSS->highQualityForBkgrdScan = RSSI_DEFAULT_THRESHOLD;
        pCurrBSS->lowQualityForBkgrdScan = RSSI_DEFAULT_THRESHOLD;
        tTriggerCfg.index     = TRIGGER_EVENT_BG_SCAN;
        tTriggerCfg.threshold = pCurrBSS->lowQualityForBkgrdScan;
        tTriggerCfg.pacing    = TRIGGER_BG_SCAN_PACING;
        tTriggerCfg.metric    = METRIC_EVENT_RSSI_DATA;
        tTriggerCfg.type      = RX_QUALITY_EVENT_EDGE;
        tTriggerCfg.direction = RSSI_EVENT_DIR_BIDIR;
        tTriggerCfg.hystersis = TRIGGER_BG_SCAN_HYSTERESIS;
        tTriggerCfg.enable    = TI_TRUE;
        TWD_CfgRssiSnrTrigger (pCurrBSS->hTWD, &tTriggerCfg);

         /* Register for 'BSS-Loss' event */
        TWD_RegisterEvent (pCurrBSS->hTWD, TWD_OWN_EVENT_BSS_LOSE, (void *)currBSS_BssLost, pCurrBSS);
        TWD_EnableEvent (pCurrBSS->hTWD, TWD_OWN_EVENT_BSS_LOSE);

        /* save last configured value for handling Soft Gemini changes */ 
        pCurrBSS->numExpectedTbttForBSSLoss = OUT_OF_SYNC_DEFAULT_THRESHOLD;
        params.TsfMissThreshold = OUT_OF_SYNC_DEFAULT_THRESHOLD;
        params.BssLossTimeout = NO_BEACON_DEFAULT_TIMEOUT;
        TWD_CfgConnMonitParams (pCurrBSS->hTWD, &params);

         /* Register for 'Consec. Tx error' */
        TWD_RegisterEvent (pCurrBSS->hTWD, TWD_OWN_EVENT_MAX_TX_RETRY, (void *)currBSS_consecTxErrors, pCurrBSS);
        TWD_EnableEvent (pCurrBSS->hTWD, TWD_OWN_EVENT_MAX_TX_RETRY);

        pCurrBSS->maxTxRetryThreshold = NO_ACK_DEFAULT_THRESHOLD;
        params.maxTxRetry = NO_ACK_DEFAULT_THRESHOLD;
        TWD_CfgMaxTxRetry (pCurrBSS->hTWD, &params);
    }

    return TI_OK;
}


/**
*
* currBSS_updateRoamingTriggers
*
* \b Description: 
*
* Configure parameter of Current BSS
*
* \b ARGS:
*
*  I   - hCurrBSS - Current BSS handle \n
*  I   - params - pointer to datablock of roaming threshols \n
*  
* \b RETURNS:
*
*  TI_OK on success, TI_NOK on failure.
*
* \sa 
*/
TI_STATUS currBSS_updateRoamingTriggers (TI_HANDLE hCurrBSS, roamingMngrThresholdsConfig_t *params)
{
    currBSS_t   *pCurrBSS = (currBSS_t *)hCurrBSS;
    TRroamingTriggerParams roamingTriggersParams;
    RssiSnrTriggerCfg_t tTriggerCfg;

    if (pCurrBSS->lowRssiThreshold != params->lowRssiThreshold) 
    {
        pCurrBSS->lowRssiThreshold = params->lowRssiThreshold;

        tTriggerCfg.index     = TRIGGER_EVENT_LOW_RSSI;
        tTriggerCfg.threshold = pCurrBSS->lowRssiThreshold;
        tTriggerCfg.pacing    = TRIGGER_LOW_RSSI_PACING;
        tTriggerCfg.metric    = METRIC_EVENT_RSSI_BEACON;
        tTriggerCfg.type      = RX_QUALITY_EVENT_LEVEL;
        tTriggerCfg.direction = RSSI_EVENT_DIR_LOW;
        tTriggerCfg.hystersis = 0;
        tTriggerCfg.enable    = TI_TRUE;

        TWD_CfgRssiSnrTrigger (pCurrBSS->hTWD, &tTriggerCfg);
    }

    if (pCurrBSS->lowSnrThreshold != params->lowSnrThreshold) 
    {
        pCurrBSS->lowSnrThreshold = params->lowSnrThreshold;

        tTriggerCfg.index     = TRIGGER_EVENT_LOW_SNR;
        tTriggerCfg.threshold = pCurrBSS->lowSnrThreshold;
        tTriggerCfg.pacing    = TRIGGER_LOW_SNR_PACING;
        tTriggerCfg.metric    = METRIC_EVENT_SNR_BEACON;
        tTriggerCfg.type      = RX_QUALITY_EVENT_LEVEL;
        tTriggerCfg.direction = RSSI_EVENT_DIR_LOW;
        tTriggerCfg.hystersis = 0;
        tTriggerCfg.enable    = TI_TRUE;
    
        TWD_CfgRssiSnrTrigger (pCurrBSS->hTWD, &tTriggerCfg);
    }

    if (pCurrBSS->lowQualityForBkgrdScan != params->lowQualityForBackgroungScanCondition) 
    {
        pCurrBSS->lowQualityForBkgrdScan = params->lowQualityForBackgroungScanCondition;
        tTriggerCfg.index     = TRIGGER_EVENT_BG_SCAN;
        tTriggerCfg.threshold = pCurrBSS->lowQualityForBkgrdScan;
        tTriggerCfg.pacing    = TRIGGER_BG_SCAN_PACING;
        tTriggerCfg.metric    = METRIC_EVENT_RSSI_DATA;
        tTriggerCfg.type      = RX_QUALITY_EVENT_EDGE;
        tTriggerCfg.direction = RSSI_EVENT_DIR_BIDIR;
        tTriggerCfg.hystersis = TRIGGER_BG_SCAN_HYSTERESIS;
        tTriggerCfg.enable    = TI_TRUE;

        TWD_CfgRssiSnrTrigger (pCurrBSS->hTWD, &tTriggerCfg);
    }

    if (pCurrBSS->numExpectedTbttForBSSLoss != params->numExpectedTbttForBSSLoss) 
    {
        /* save last configured value for handling Soft Gemini changes */ 
        pCurrBSS->numExpectedTbttForBSSLoss = params->numExpectedTbttForBSSLoss;
        /* Configure TWD with 'No BSS' thresholds (Same as the other parameters but in a special
            function for the Soft Gemini module consideration) */
        currBSS_updateBSSLoss(pCurrBSS);
    }
    
    /* Configure TWD with 'Consecutive NACK' thresholds */
    if (pCurrBSS->maxTxRetryThreshold != params->dataRetryThreshold) 
    {
        pCurrBSS->maxTxRetryThreshold = params->dataRetryThreshold;
        roamingTriggersParams.maxTxRetry = pCurrBSS->maxTxRetryThreshold;
        TWD_CfgMaxTxRetry (pCurrBSS->hTWD, &roamingTriggersParams);
    }

    pCurrBSS->highQualityForBkgrdScan = params->normalQualityForBackgroungScanCondition;
    
    return TI_OK;
}

/**
*
* currBSS_getRoamingParams
*
* \b Description: 
*
* Retrieves the roaming triggers stored in the CurrBSS module.
*
* \b ARGS:
*
*  I   - hCurrBSS - Current BSS handle \n
*  O   - aNumExpectedTbttForBSSLoss - Current BSS handle \n
*  O   - aLowQualityForBackgroungScanCondition - Current BSS handle \n
*  O   - aNormalQualityForBackgroungScanCondition - Current BSS handle \n
*  
* \b RETURNS:
*
*  TI_OK on success, TI_NOK on failure.
*
* \sa 
*/
TI_STATUS currBSS_getRoamingParams(TI_HANDLE hCurrBSS,
                                   TI_UINT8 * aNumExpectedTbttForBSSLoss,
                                   TI_INT8 * aLowQualityForBackgroungScanCondition,
                                   TI_INT8 * aNormalQualityForBackgroungScanCondition)
{
    currBSS_t * pCurrBSS = (currBSS_t *) hCurrBSS;

    *aNumExpectedTbttForBSSLoss = pCurrBSS->numExpectedTbttForBSSLoss;
    *aLowQualityForBackgroungScanCondition = pCurrBSS->lowQualityForBkgrdScan;
    *aNormalQualityForBackgroungScanCondition = pCurrBSS->highQualityForBkgrdScan;
    
    return TI_OK;
}

/**
*
* currBSS_SGconfigureBSSLoss
*
* \b Description: 
*
*   This function is called by the Soft Gemini module in order to enable/disable the use of
*   the compensation value for the BSSLoss count , and the percent of increasing that value
*   It also set the new parameter to the FW (with another generic function)
*   The compensation is needed since BT activity might over-run recieved beacons
*    
*
* \b ARGS:
*
*  I   - hCurrBSS - Current BSS handle \n
*        SGcompensationPercent - percent of increasing the BSSLoss value to the FW \n
*        bUseSGParams - whether to use the SG compensation
*
* \b RETURNS:
*
*  -
*
* \sa 
*/

void currBSS_SGconfigureBSSLoss(TI_HANDLE hCurrBSS,
                                        TI_UINT32 SGcompensationPercent , TI_BOOL bUseSGParams)
{
    currBSS_t   *pCurrBSS = (currBSS_t *)hCurrBSS;
    
    pCurrBSS->bUseSGParams = bUseSGParams;
    pCurrBSS->SGcompensationPercent = SGcompensationPercent;

TRACE1(pCurrBSS->hReport, REPORT_SEVERITY_INFORMATION, "CurrBSS_SGConf: SG =%d\n", pCurrBSS->bUseSGParams);

    /* update the change of BSSLoss in the FW */
    currBSS_updateBSSLoss(pCurrBSS);
}

/**
*
* currBSS_updateBSSLoss
*
* \b Description: 
*
*   This function updates only BSS Loss parameter , we need it to be able to consider the
*   Soft Gemini status , and change the parameter according to it 
*
* \b ARGS:
*
*  I   - pCurrBSS - Current BSS handle \n
*  
* \b RETURNS:
*
*  -
*
* \sa 
*/
void currBSS_updateBSSLoss(currBSS_t   *pCurrBSS)
{
    TRroamingTriggerParams roamingTriggersParams;
	TI_UINT16 desiredBeaconInterval = 0;
	TI_UINT32 connSelfTimeout = 0;
	paramInfo_t *pParam;

	pParam = (paramInfo_t *)os_memoryAlloc(pCurrBSS->hOs, sizeof(paramInfo_t));
    if (pParam)
    {
		pParam->paramType = SITE_MGR_DESIRED_BEACON_INTERVAL_PARAM;
		siteMgr_getParam(pCurrBSS->hSiteMgr, pParam);
		desiredBeaconInterval = pParam->content.siteMgrDesiredBeaconInterval;

		pParam->paramType = CONN_SELF_TIMEOUT_PARAM;
		conn_getParam(pCurrBSS->hConn, pParam);
		connSelfTimeout = pParam->content.connSelfTimeout;

		os_memoryFree(pCurrBSS->hOs, pParam, sizeof(paramInfo_t));
	}
	else
	{
		TRACE0(pCurrBSS->hReport, REPORT_SEVERITY_ERROR, "currBSS_updateBSSLoss: Error allocating paramInfo_t\n");
	}

    if (pCurrBSS->type == BSS_INDEPENDENT)
    {
       if (desiredBeaconInterval > 0)
       {
		   /* Calculate the number of beacons for miss timeout */
           roamingTriggersParams.TsfMissThreshold = connSelfTimeout / desiredBeaconInterval;
       }
	   else
	   {
		   /* Use default parameter */
		   roamingTriggersParams.TsfMissThreshold = OUT_OF_SYNC_IBSS_THRESHOLD; 
	   }
    }
    else /* In Infra we use the saved parameter */
    {
        roamingTriggersParams.TsfMissThreshold = pCurrBSS->numExpectedTbttForBSSLoss;
    }
    
    roamingTriggersParams.BssLossTimeout = NO_BEACON_DEFAULT_TIMEOUT;
    
    TRACE2(pCurrBSS->hReport, REPORT_SEVERITY_INFORMATION, ": SG=%d, Band=%d\n", pCurrBSS->bUseSGParams, pCurrBSS->currAPInfo.band);

    /* if Soft Gemini is enabled - increase the BSSLoss value (because BT activity might over-run beacons) */
    if ((pCurrBSS->bUseSGParams) && (pCurrBSS->currAPInfo.band == RADIO_BAND_2_4_GHZ))
    {
        roamingTriggersParams.TsfMissThreshold = (roamingTriggersParams.TsfMissThreshold * 
            (100 + pCurrBSS->SGcompensationPercent)) / 100;

        TRACE2(pCurrBSS->hReport, REPORT_SEVERITY_INFORMATION, ": old value = %d, new value (for SG compensation) = %d\n", pCurrBSS->numExpectedTbttForBSSLoss,roamingTriggersParams.TsfMissThreshold);
    }

    TWD_CfgConnMonitParams (pCurrBSS->hTWD, &roamingTriggersParams);
}

/**
*
* currBSS_swChFinished
*
* \b Description: 
*
* Called when switch channel process is complete in order to reset RSSI calculations
*
* \b ARGS:
*
*  I   - hCurrBSS - Current BSS handle \n
*  
* \b RETURNS:
*
*  -
*
* \sa 
*/
void currBSS_restartRssiCounting(TI_HANDLE hCurrBSS)
{
    currBSS_t   *pCurrBSS = (currBSS_t *)hCurrBSS;

    pCurrBSS->currAPInfo.RSSI = 0;
}

/**
*
* currBSS_getBssInfo
*
* \b Description: 
*
* Get parameter of Current BSS
*
* \b ARGS:
*
*  I   - hCurrBSS - Current BSS handle \n
*  
* \b RETURNS:
*
*  pointer to current BSS info block.
*
* \sa 
*/
bssEntry_t *currBSS_getBssInfo(TI_HANDLE hCurrBSS)
{
    currBSS_t   *pCurrBSS = (currBSS_t *)hCurrBSS;

    /* Return pointer to current AP info */
    return &(pCurrBSS->currAPInfo);
}


/**
*
* currBSS_probRespReceivedCallb
*
* \b Description: 
*
* Callback function, provided to MLME module. Called each time Probe response received.
* This function verifies that the Probe response was sent by current AP, and then
* updates current AP database.
*
* \b ARGS:
*
*  I   - hCurrBSS - Current BSS handle \n
*  
* \b RETURNS:
*
*  TI_OK on success, TI_NOK on failure.
*
* \sa 
*/
TI_STATUS currBSS_probRespReceivedCallb(TI_HANDLE hCurrBSS,
                                        TRxAttr *pRxAttr,
                                        TMacAddr *bssid,
                                        mlmeFrameInfo_t *pFrameInfo,
										TI_UINT8 *dataBuffer,
                                        TI_UINT16 bufLength)
{
    currBSS_t   *pCurrBSS = (currBSS_t *)hCurrBSS;
    paramInfo_t *pParam;

    pParam = (paramInfo_t *)os_memoryAlloc(pCurrBSS->hOs, sizeof(paramInfo_t));
    if (!pParam)
    {
        return TI_NOK;
    }
    pParam->paramType = SITE_MGR_CURRENT_BSSID_PARAM;
    siteMgr_getParam(pCurrBSS->hSiteMgr, pParam);    

    if (pCurrBSS->isConnected && MAC_EQUAL (pParam->content.siteMgrDesiredBSSID, *bssid))
    {
        siteMgr_updateSite(pCurrBSS->hSiteMgr, bssid, pFrameInfo, pRxAttr->channel, (ERadioBand)pRxAttr->band, TI_FALSE);
        /* Save the IE part of the Probe Response buffer in the site table */
        siteMgr_saveProbeRespBuffer(pCurrBSS->hSiteMgr, bssid, (TI_UINT8 *)dataBuffer, bufLength);
    }
    os_memoryFree(pCurrBSS->hOs, pParam, sizeof(paramInfo_t));
    return TI_OK;
}



/**
*
* currBSS_beaconReceivedCallb
*
* \b Description: 
*
* Callback function, provided to MLME module. Called each time Beacon received.
* This function verifies that the Probe response was sent by current AP, and then
* updates current AP database.
*
* \b ARGS:
*
*  I   - hCurrBSS - Current BSS handle \n
*  
* \b RETURNS:
*
*  TI_OK on success, TI_NOK on failure.
*
* \sa 
*/
TI_STATUS currBSS_beaconReceivedCallb(TI_HANDLE hCurrBSS,
                                      TRxAttr *pRxAttr,
                                      TMacAddr *bssid,
                                      mlmeFrameInfo_t *pFrameInfo,
                                      TI_UINT8 *dataBuffer,
                                      TI_UINT16 bufLength)
{
    currBSS_t           *pCurrBSS = (currBSS_t *)hCurrBSS;
    paramInfo_t         *pParam;
    ScanBssType_e       eFrameBssType, eCurrentBSSType;
	TMacAddr            desiredBSSID;

    pParam = (paramInfo_t *)os_memoryAlloc(pCurrBSS->hOs, sizeof(paramInfo_t));
    if (!pParam)
    {
        return TI_NOK;
    }

    eFrameBssType = ((pFrameInfo->content.iePacket.capabilities >> CAP_ESS_SHIFT) & CAP_ESS_MASK) ? BSS_INFRASTRUCTURE : BSS_INDEPENDENT;

    /* Get current BSS type */
    pParam->paramType = SITE_MGR_CURRENT_BSS_TYPE_PARAM;
    siteMgr_getParam (pCurrBSS->hSiteMgr, pParam);
    eCurrentBSSType = pParam->content.siteMgrCurrentBSSType; /* Save parameter because the next line overrides it */

    /* Get current BSSID */
    pParam->paramType = SITE_MGR_CURRENT_BSSID_PARAM;
    siteMgr_getParam(pCurrBSS->hSiteMgr, pParam);   
	TRACE12(pCurrBSS->hReport, REPORT_SEVERITY_INFORMATION,
			"currBSS_beaconReceivedCallb: bssid = %02x.%02x.%02x.%02x.%02x.%02x, siteMgrDesiredBSSID = %02x.%02x.%02x.%02x.%02x.%02x\n",
			(*bssid)[0], (*bssid)[1], (*bssid)[2], (*bssid)[3], (*bssid)[4], (*bssid)[5],
			pParam->content.siteMgrDesiredBSSID[0],
			pParam->content.siteMgrDesiredBSSID[1],
			pParam->content.siteMgrDesiredBSSID[2],
			pParam->content.siteMgrDesiredBSSID[3],
			pParam->content.siteMgrDesiredBSSID[4],
			pParam->content.siteMgrDesiredBSSID[5]);
	MAC_COPY(desiredBSSID, pParam->content.siteMgrDesiredBSSID);

    if (pCurrBSS->isConnected && (eCurrentBSSType == eFrameBssType))
    {
		TI_BOOL bFramePrivacy = 0, bCurrentSitePrivacy = 0;
        /* if the bss type is ibss save set the current site privacy (the beacons transimted by STA)
		   and set the privacy from the received frame, so that if the privacy is different there will
		   be no connection */
		if (eFrameBssType == BSS_INDEPENDENT)
		{
			pParam->paramType = SITE_MGR_SITE_CAPABILITY_PARAM;
			siteMgr_getParam(pCurrBSS->hSiteMgr, pParam);

			bCurrentSitePrivacy = ((pParam->content.siteMgrSiteCapability >> CAP_PRIVACY_SHIFT) & CAP_PRIVACY_MASK) ? TI_TRUE : TI_FALSE;
			bFramePrivacy       = ((pFrameInfo->content.iePacket.capabilities >> CAP_PRIVACY_SHIFT) & CAP_PRIVACY_MASK) ? TI_TRUE : TI_FALSE;
		}

        if (MAC_EQUAL(desiredBSSID, *bssid))
        {
            if ((eFrameBssType == BSS_INFRASTRUCTURE) || 
			    ((eFrameBssType == BSS_INDEPENDENT) && (bCurrentSitePrivacy == bFramePrivacy)) )
			{
				siteMgr_updateSite(pCurrBSS->hSiteMgr, bssid, pFrameInfo, pRxAttr->channel, (ERadioBand)pRxAttr->band, TI_FALSE);
				/* Save the IE part of the beacon buffer in the site table */
				siteMgr_saveBeaconBuffer(pCurrBSS->hSiteMgr, bssid, (TI_UINT8 *)dataBuffer, bufLength);
			}
        }
    	else if (eFrameBssType == BSS_INDEPENDENT)
        {
           /* Check if the Station sending the beacon uses privacy for the ibss and
			   compare it to the self site. If privacy usage mathces, merge ibss
			   and if not continue using self site */
			if (bCurrentSitePrivacy == bFramePrivacy) 
			{
				siteMgr_IbssMerge(pCurrBSS->hSiteMgr, desiredBSSID, *bssid,
								  pFrameInfo, pRxAttr->channel, (ERadioBand)pRxAttr->band);
				siteMgr_updateSite(pCurrBSS->hSiteMgr, bssid, pFrameInfo, pRxAttr->channel, (ERadioBand)pRxAttr->band, TI_FALSE);
				siteMgr_saveBeaconBuffer(pCurrBSS->hSiteMgr, bssid, (TI_UINT8 *)dataBuffer, bufLength);
			}
    	}
    }

    os_memoryFree(pCurrBSS->hOs, pParam, sizeof(paramInfo_t));
    return TI_OK;
}


/**
*
* currBSS_updateConnectedState
*
* \b Description: 
*
* This function is called when FW recovery performed.
*
* \b ARGS:
*
*  I   - hCurrBSS - Current BSS handle \n
*  I   - isConnected - TI_TRUE or TI_FALSE \n
*  I   - type - IBSS or EBSS \n
*  
* \b RETURNS:
*
*  -
*
* \sa 
*/
void currBSS_updateConnectedState(TI_HANDLE hCurrBSS, TI_BOOL isConnected, ScanBssType_e type)
{
    currBSS_t   *pCurrBSS = (currBSS_t *)hCurrBSS;

    pCurrBSS->type = type;
    pCurrBSS->isConnected = isConnected;

    if (isConnected) 
    {
        /*** Store the info of current AP ***/
        paramInfo_t  *pParam;

        pParam = (paramInfo_t *)os_memoryAlloc(pCurrBSS->hOs, sizeof(paramInfo_t));
        if (!pParam)
        {
            return;
        }

        /* BSSID */
        pParam->paramType = SITE_MGR_CURRENT_BSSID_PARAM;
        siteMgr_getParam(pCurrBSS->hSiteMgr, pParam);    
        MAC_COPY (pCurrBSS->currAPInfo.BSSID, pParam->content.siteMgrDesiredBSSID);

        /* Rx rate */
        pParam->paramType = SITE_MGR_LAST_RX_RATE_PARAM;
        siteMgr_getParam(pCurrBSS->hSiteMgr, pParam);               
        pCurrBSS->currAPInfo.rxRate = pParam->content.ctrlDataCurrentBasicRate;

        /* Band */
        pParam->paramType = SITE_MGR_RADIO_BAND_PARAM;
        siteMgr_getParam(pCurrBSS->hSiteMgr, pParam);               
        pCurrBSS->currAPInfo.band = pParam->content.siteMgrRadioBand;

        /* Channel */
        pParam->paramType = SITE_MGR_CURRENT_CHANNEL_PARAM;
        siteMgr_getParam(pCurrBSS->hSiteMgr, pParam);               
        pCurrBSS->currAPInfo.channel = pParam->content.siteMgrCurrentChannel;

        /* Last Rx Tsf */
        pParam->paramType = SITE_MGR_CURRENT_TSF_TIME_STAMP;
        siteMgr_getParam(pCurrBSS->hSiteMgr, pParam);               
        os_memoryCopy(pCurrBSS->hOs, &pCurrBSS->currAPInfo.lastRxTSF, 
                      pParam->content.siteMgrCurrentTsfTimeStamp, sizeof(pCurrBSS->currAPInfo.lastRxTSF));

        /* Beacon interval */
        pParam->paramType = SITE_MGR_BEACON_INTERVAL_PARAM;
        siteMgr_getParam(pCurrBSS->hSiteMgr, pParam);               
        pCurrBSS->currAPInfo.beaconInterval = pParam->content.beaconInterval;

        /* Capability */
        pParam->paramType = SITE_MGR_SITE_CAPABILITY_PARAM;
        siteMgr_getParam(pCurrBSS->hSiteMgr,pParam);
        pCurrBSS->currAPInfo.capabilities = pParam->content.siteMgrSiteCapability;
        pParam->paramType = SITE_MGR_CURRENT_TSF_TIME_STAMP;
        siteMgr_getParam(pCurrBSS->hSiteMgr, pParam);    

        /* pCurrBSS->currAPInfo.lastRxHostTimestamp = *((TI_UINT64 *)(pIEs->TimeStamp));*/ /* TBD*/
        os_memoryCopy(pCurrBSS->hOs, &pCurrBSS->currAPInfo.lastRxHostTimestamp, pParam->content.siteMgrCurrentTsfTimeStamp, sizeof(TI_UINT32));

        pParam->paramType = SITE_MGR_LAST_BEACON_BUF_PARAM;
        siteMgr_getParam(pCurrBSS->hSiteMgr, pParam);               
        pCurrBSS->currAPInfo.pBuffer = pParam->content.siteMgrLastBeacon.buffer;
        pCurrBSS->currAPInfo.bufferLength = pParam->content.siteMgrLastBeacon.bufLength;
        pCurrBSS->currAPInfo.resultType = (pParam->content.siteMgrLastBeacon.isBeacon) ? SCAN_RFT_BEACON : SCAN_RFT_PROBE_RESPONSE;

        /* Set BSS Loss to Fw - note that it depends on the Connection type - (Infa/IBSS) */
        currBSS_updateBSSLoss(pCurrBSS);

        if(type == BSS_INFRASTRUCTURE)
        {
            TI_UINT32           uKeepAlivePreiod = pCurrBSS->uDefaultKeepAlivePeriod * 1000; /* convert to ms */
            TSetTemplate        tKeepAliveTemplate;
            TKeepAliveParams    tKeepAliveParams;

            /*
             * only configure the null-data keepa-live message if the interval is valid
             * (either the default interval or the one from teh XCC IE)
             */
            if (0 != uKeepAlivePreiod)
            {
                TRACE0(pCurrBSS->hReport, REPORT_SEVERITY_INFORMATION , "currBSS_updateConnectedState: Configuring null-data keep-alive");
    
                /* build null-data template */
                tKeepAliveTemplate.ptr = &(pCurrBSS->keepAliveBuffer[ 0 ]);
                if ( TI_OK != txCtrlServ_buildNullFrame (pCurrBSS->hTxCtrl, 
                                                         tKeepAliveTemplate.ptr, &(tKeepAliveTemplate.len)))
                {
                    TRACE0(pCurrBSS->hReport, REPORT_SEVERITY_ERROR , "currBSS_updateConnectedState: error building null data frame\n");
    
                }
    
                /* configure null-data template */
                tKeepAliveTemplate.type = KEEP_ALIVE_TEMPLATE;
                tKeepAliveTemplate.index = KEEP_ALIVE_NULL_DATA_INDEX;
                tKeepAliveTemplate.uRateMask = RATE_MASK_UNSPECIFIED;
                TWD_CmdTemplate (pCurrBSS->hTWD, &tKeepAliveTemplate, NULL, NULL);
    
                /* configure paramters */
                tKeepAliveParams.index = KEEP_ALIVE_NULL_DATA_INDEX;
                tKeepAliveParams.enaDisFlag = TI_TRUE; /* enabled */
                tKeepAliveParams.trigType = KEEP_ALIVE_TRIG_TYPE_NO_TX;
                tKeepAliveParams.interval = uKeepAlivePreiod;
                TWD_CfgKeepAlive (pCurrBSS->hTWD, &tKeepAliveParams);
            }
        }        
        os_memoryFree(pCurrBSS->hOs, pParam, sizeof(paramInfo_t));
    }
    else
    {
        if(type == BSS_INFRASTRUCTURE)
        {
            TKeepAliveParams    tKeepAliveParams;

            /* disable NULL-data keep-palive template */
            tKeepAliveParams.index = KEEP_ALIVE_NULL_DATA_INDEX;
            tKeepAliveParams.enaDisFlag = TI_FALSE; /* disabled */
            tKeepAliveParams.interval = 1000; /* minimum accepted by the FW */
            tKeepAliveParams.trigType = KEEP_ALIVE_TRIG_TYPE_NO_TX;
            TWD_CfgKeepAlive (pCurrBSS->hTWD, &tKeepAliveParams);

        }        
    }
}


/**
*
* currBSS_BssLost
*
* \b Description: 
*
* Callback function, called upon BSS-Loss event from FW.
*
* \b ARGS:
*
*  I   - hCurrBSS - Current BSS handle \n
*  
* \b RETURNS:
*
*  void
*
* \sa 
*/
static void currBSS_BssLost (currBSS_t *hCurrBSS,
                             TI_UINT8  *data,
                             TI_UINT8   dataLength)
{
    currBSS_reportRoamingEvent(hCurrBSS, ROAMING_TRIGGER_BSS_LOSS, NULL);
}


/**
*
* currBSS_consecTxErrors
*
* \b Description: 
*
* Callback function, provided to HAL module.
*
* \b ARGS:
*
*  I   - pCurrBSS - Current BSS handle \n
*  
* \b RETURNS:
*
*  TI_OK on success, TI_NOK on failure.
*
* \sa 
*/
static void currBSS_consecTxErrors(currBSS_t *hCurrBSS,
                                   TI_UINT8     *data,
                                   TI_UINT8     dataLength)
{
    currBSS_reportRoamingEvent(hCurrBSS, ROAMING_TRIGGER_MAX_TX_RETRIES, NULL);
}


/**
*
* currBSS_lowRssiThrCrossed
*
* \b Description: 
*
* Callback function, provided to HAL module.
*
* \b ARGS:
*
*  I   - pCurrBSS - Current BSS handle \n
*  
* \b RETURNS:
*
*  TI_OK on success, TI_NOK on failure.
*
* \sa 
*/
static void currBSS_lowRssiThrCrossed(currBSS_t *hCurrBSS,
                                      TI_UINT8     *data,
                                      TI_UINT8     dataLength)
{
    currBSS_reportRoamingEvent(hCurrBSS, ROAMING_TRIGGER_LOW_QUALITY, NULL);
}


/**
*
* currBSS_lowSnrThrCrossed
*
* \b Description: 
*
* Callback function, provided to HAL module.
*
* \b ARGS:
*
*  I   - pCurrBSS - Current BSS handle \n
*  
* \b RETURNS:
*
*  TI_OK on success, TI_NOK on failure.
*
* \sa 
*/
static void currBSS_lowSnrThrCrossed(currBSS_t *hCurrBSS,
                                      TI_UINT8     *data,
                                      TI_UINT8     dataLength)
{
    currBSS_reportRoamingEvent(hCurrBSS, ROAMING_TRIGGER_LOW_SNR, NULL);
}

/**
*
* currBSS_reportRoamingEvent
*
* \b Description: 
*
* This function checks the mode of Current BSS module. 
* If connected to EBSS, it reports roaming event to AP Connection.
*
* \b ARGS:
*
*  I   - pCurrBSS - Current BSS handle \n
*  I   - roamingEventType - Roaming trigger to report \n
*  
* \b RETURNS:
*
*  TI_OK on success, TI_NOK on failure.
*
* \sa 
*/
static void currBSS_reportRoamingEvent(currBSS_t *pCurrBSS, 
                                       apConn_roamingTrigger_e roamingEventType,
                                       roamingEventData_u *pRoamingEventData)
{
    TRACE1(pCurrBSS->hReport, REPORT_SEVERITY_INFORMATION, "currBSS_reportRoamingEvent: trigger %d\n", roamingEventType);

    if (pCurrBSS->isConnected)
    {
        if (pCurrBSS->type == BSS_INFRASTRUCTURE) 
        {
            apConn_reportRoamingEvent(pCurrBSS->hAPConn, roamingEventType, pRoamingEventData);
        }
        else /* IBSS */
        { 
            if( roamingEventType == ROAMING_TRIGGER_BSS_LOSS )
            {
                /* If in IBSS call the SME restart function, this logic issues a DISCONNECT 
                 * event and tries to connect to other STA or establish self connection.
                 */
                sme_Restart (pCurrBSS->hSme);
            }
        }
    }
}


/**
*
* currBSS_GetDefaultKeepAlivePeriod
*
* \b Description: 
*
* Get DefaultKeepAlivePeriod parameter value.
*
* \b ARGS:
*
*  I   - hCurrBSS           - Current BSS handle \n
*  I   - uDefaultKeepAlivePeriod - The  value \n
*  
* \b RETURNS:
*
*  None.
*
* \sa 
*/
void currBSS_GetDefaultKeepAlivePeriod (TI_HANDLE hCurrBSS, TI_UINT8* uKeepAlivePeriod)
{ 
    currBSS_t *pCurrBSS = (currBSS_t *)hCurrBSS;

    *uKeepAlivePeriod = pCurrBSS->uDefaultKeepAlivePeriod;
}


/**
*
* currBSS_BackgroundScanQuality
*
* \b Description: 
*
* Called be EventMBox upon Background Scan Quality Trigger.
*
* \b ARGS:
*
*  I   - hCurrBSS - Current BSS handle \n
*  
* \b RETURNS:
*
*  None.
*
* \sa 
*/
static void currBSS_BackgroundScanQuality(TI_HANDLE hCurrBSS,
                                      TI_UINT8     *data,
                                      TI_UINT8     dataLength)
{
    currBSS_t *pCurrBSS = (currBSS_t *)hCurrBSS;
    TI_UINT8 averageRssi = *data;
    paramInfo_t *pParam;

    TRACE1(pCurrBSS->hReport, REPORT_SEVERITY_INFORMATION, "BackgroundScanQuality Event: RSSI = %d\n", averageRssi );

    /* Report to AP Connection about reaching RSSI low or normal (high) threshold */
    if (averageRssi < pCurrBSS->lowQualityForBkgrdScan)
    {
        apConn_reportRoamingEvent(pCurrBSS->hAPConn, ROAMING_TRIGGER_LOW_QUALITY_FOR_BG_SCAN, NULL);
    }
    else
    {
        apConn_reportRoamingEvent(pCurrBSS->hAPConn, ROAMING_TRIGGER_NORMAL_QUALITY_FOR_BG_SCAN, NULL); 
    }

    /* Update RSSI: */
    pCurrBSS->currAPInfo.RSSI = averageRssi;

    /* Update Site Table in order to represent the RSSI of current AP correctly in the utility */
    pParam = (paramInfo_t *)os_memoryAlloc(pCurrBSS->hOs, sizeof(paramInfo_t));
    if (!pParam)
    {
        return;
    }
    pParam->paramType = SITE_MGR_CURRENT_SIGNAL_PARAM;
    pParam->content.siteMgrCurrentSignal.rssi = averageRssi;
    siteMgr_setParam(pCurrBSS->hSiteMgr, pParam);
    os_memoryFree(pCurrBSS->hOs, pParam, sizeof(paramInfo_t));
}


/**
*
* currBss_findEmptyUserTrigger
*
* \b Description:
*
* Called be EventMBox upon Background Scan Quality Trigger.
*
* \b ARGS:
*
*  I   - hCurrBSS - Current BSS handle \n
*
* \b RETURNS:
*
*  None.
*
* \sa
*/
static triggerDesc_t* currBss_findEmptyUserTrigger(TI_HANDLE hCurrBSS, TI_UINT16 clientID, TI_UINT8* triggerIdx)
{
    currBSS_t       *pCurrBSS = (currBSS_t *)hCurrBSS;
	TI_UINT8        i=0;

    for (i=0; i< MAX_NUM_OF_RSSI_SNR_TRIGGERS ; i++)
    {
        if (clientID == pCurrBSS->aTriggersDesc[i].clientID || /* if the same client ID found, overwrite this trigger*/
            (pCurrBSS->aTriggersDesc[i].WasRegisteredByApp == TI_FALSE && pCurrBSS->aTriggersDesc[i].fCB == NULL))
        {
            *triggerIdx = i;
            return &pCurrBSS->aTriggersDesc[i];
        }
    }

    return NULL;
}


/** 
 * \fn     currBSS_RegisterTriggerEvent
 * \brief  register the event in the currBss static table.
 *
 * \Args:
 * \param  hCurrBSS   - Current BSS handle
 * \param  triggerID  - The RSSI/SNR trigger ID as defined in the TWD. this arg is the table index.
 * \param  clientID - The client ID, '0' value means internal driver module client
 * \param  fCB - the trigger event handler. NULL value will be set for external app registration.
 * \return >= 0 if the empty Trigger event ID (index table) has been found and occupied
    else -1 to signal an error
* \sa
*/
TI_INT8 currBSS_RegisterTriggerEvent (TI_HANDLE hCurrBSS, TI_UINT8 triggerID,TI_UINT16 clientID, void* fCB, TI_HANDLE hCB)
{
    currBSS_t       *pCurrBSS = (currBSS_t *)hCurrBSS;
	triggerDesc_t   *pEmptyTrigger;
    TI_UINT8        emptyTriggerIdx = 0;

    if (triggerID >= MAX_NUM_OF_RSSI_SNR_TRIGGERS)
    {
        TRACE1(pCurrBSS->hReport, REPORT_SEVERITY_ERROR , "currBSS_RegisterTriggerEvent: triggerID=%d is not in legal range \n", triggerID);
        return -1;
    }

    TRACE3(pCurrBSS->hReport, REPORT_SEVERITY_INFORMATION, "currBSS_RegisterTriggerEvent: triggerID=%d, clientID=%d , fCB=%d. \n",triggerID, clientID ,fCB);

    if(clientID > 0) /* this event is registered by application */
    {
        pEmptyTrigger = currBss_findEmptyUserTrigger(hCurrBSS, clientID, &emptyTriggerIdx);
        if (pEmptyTrigger != NULL)
        {
            pEmptyTrigger->clientID = clientID;
            pEmptyTrigger->fCB = NULL;
			pEmptyTrigger->hCB = NULL;
            pEmptyTrigger->WasRegisteredByApp = TI_TRUE;
        }
        else
        {
            TRACE0(pCurrBSS->hReport, REPORT_SEVERITY_ERROR , "currBSS_RegisterTriggerEvent: Table is full!. no Empty trigger is available! \n");
            return -1;
        }
    }
    else
    {
        pCurrBSS->aTriggersDesc[triggerID].clientID = 0;
        pCurrBSS->aTriggersDesc[triggerID].fCB = fCB;
		pCurrBSS->aTriggersDesc[triggerID].hCB = hCB;
        pCurrBSS->aTriggersDesc[triggerID].WasRegisteredByApp = TI_FALSE;
    }

    TWD_EnableEvent (pCurrBSS->hTWD, triggerID);
    return emptyTriggerIdx;
}




/**
 * \fn     currBss_HandleTriggerEvent
 * \brief  called by the user trigger event callbcack.
 *
 * \Args:
 * \param  hCurrBSS   - Current BSS handle
 * \param  data       - The event data
 * \param  dataLength - The event data length
 * \param  eventID -    The event ID
 * \return TI_STATUS
* \sa
*/
static TI_STATUS currBss_HandleTriggerEvent(TI_HANDLE hCurrBSS, TI_UINT8 *data, TI_UINT8 dataLength, TI_UINT8 eventID)
{
    triggerDesc_t *pTrigger;
    triggerDataEx_t triggerInfo;
    currBSS_t *pCurrBSS = (currBSS_t *)hCurrBSS;

    TRACE1(pCurrBSS->hReport ,REPORT_SEVERITY_INFORMATION,  "currBss_HandleTriggerEvent(). eventID =%d \n",eventID);

    if (eventID < MAX_NUM_OF_RSSI_SNR_TRIGGERS)
    {
        pTrigger = &pCurrBSS->aTriggersDesc[eventID];
    }
    else
    {
       return TI_NOK;
    }

    if (TI_FALSE == pTrigger->WasRegisteredByApp)
    {
        ((TCurrBssDataCb)pTrigger->fCB)(pTrigger->hCB, data, dataLength);
    }
    else
    {
        triggerInfo.data =  *data; /* RSSI_SNR Triggers - holds one byte only */
        triggerInfo.clientID = pTrigger->clientID;
        EvHandlerSendEvent(pCurrBSS->hEvHandler, IPC_EVENT_RSSI_SNR_TRIGGER, (TI_UINT8*)&triggerInfo, sizeof(triggerInfo));
    }

    return TI_OK;
}

/**
 * \fn     currBSS_RssiSnrTrigger0-7
 * \brief  User Defined Trigger 0-7 callbacks
 * 
 * Called by EventMBox upon User Defined Trigger 0 - 7.
 * 
 * \note    
 * \param  hCurrBSS   - Current BSS handle
 * \param  data       - The event data
 * \param  dataLength - The event data length
 * \return void  
* \sa 
*/

static void currBSS_RssiSnrTrigger0 (TI_HANDLE hCurrBSS, TI_UINT8 *data, TI_UINT8 dataLength)
{
	TI_UINT8 eventID = TWD_OWN_EVENT_RSSI_SNR_TRIGGER_0;
	currBss_HandleTriggerEvent (hCurrBSS, data, dataLength,  eventID);
}
static void currBSS_RssiSnrTrigger1 (TI_HANDLE hCurrBSS, TI_UINT8 *data, TI_UINT8 dataLength)
{
	TI_UINT8 eventID = TWD_OWN_EVENT_RSSI_SNR_TRIGGER_1;
	currBss_HandleTriggerEvent (hCurrBSS, data, dataLength,  eventID);
}
static void currBSS_RssiSnrTrigger2 (TI_HANDLE hCurrBSS, TI_UINT8 *data, TI_UINT8 dataLength)
{
	TI_UINT8 eventID = TWD_OWN_EVENT_RSSI_SNR_TRIGGER_2;
	currBss_HandleTriggerEvent (hCurrBSS, data, dataLength,  eventID);
}
static void currBSS_RssiSnrTrigger3 (TI_HANDLE hCurrBSS, TI_UINT8 *data, TI_UINT8 dataLength)
{
	TI_UINT8 eventID = TWD_OWN_EVENT_RSSI_SNR_TRIGGER_3;
	currBss_HandleTriggerEvent (hCurrBSS, data, dataLength,  eventID);
}
static void currBSS_RssiSnrTrigger4 (TI_HANDLE hCurrBSS, TI_UINT8 *data, TI_UINT8 dataLength)
{
	TI_UINT8 eventID = TWD_OWN_EVENT_RSSI_SNR_TRIGGER_4;
	currBss_HandleTriggerEvent (hCurrBSS, data, dataLength,  eventID);
}
static void currBSS_RssiSnrTrigger5 (TI_HANDLE hCurrBSS, TI_UINT8 *data, TI_UINT8 dataLength)
{
	TI_UINT8 eventID = TWD_OWN_EVENT_RSSI_SNR_TRIGGER_5;
	currBss_HandleTriggerEvent (hCurrBSS, data, dataLength,  eventID);
}
static void currBSS_RssiSnrTrigger6 (TI_HANDLE hCurrBSS, TI_UINT8 *data, TI_UINT8 dataLength)
{
	TI_UINT8 eventID = TWD_OWN_EVENT_RSSI_SNR_TRIGGER_6;
	currBss_HandleTriggerEvent (hCurrBSS, data, dataLength,  eventID);
}
static void currBSS_RssiSnrTrigger7 (TI_HANDLE hCurrBSS, TI_UINT8 *data, TI_UINT8 dataLength)
{
	TI_UINT8 eventID = TWD_OWN_EVENT_RSSI_SNR_TRIGGER_7;
	currBss_HandleTriggerEvent (hCurrBSS, data, dataLength,  eventID);
}


static TI_STATUS currBSS_BssLossThresholdCrossed(TI_HANDLE hCurrBSS, TI_UINT8 *data, TI_UINT8 dataLength)
{
	currBSS_t *pCurrBSS = (currBSS_t *)hCurrBSS;

	EvHandlerSendEvent(pCurrBSS->hEvHandler, IPC_EVENT_BSS_LOSS, data, dataLength);

    currBSS_reportRoamingEvent(hCurrBSS, ROAMING_TRIGGER_BSS_LOSS, NULL);
    return TI_OK;
}

static TI_STATUS currBSS_MaxTxRetryThresholdCrossed(TI_HANDLE hCurrBSS, TI_UINT8 *data, TI_UINT8 dataLength)
{
	currBSS_t *pCurrBSS = (currBSS_t *)hCurrBSS;

	EvHandlerSendEvent(pCurrBSS->hEvHandler, IPC_EVENT_TX_RETRY_FALIURE, data, dataLength);

    currBSS_reportRoamingEvent(hCurrBSS, ROAMING_TRIGGER_BSS_LOSS, NULL);
    return TI_OK;
}



TI_STATUS currBss_registerBssLossEvent(TI_HANDLE hCurrBSS,TI_UINT32  uNumOfBeacons, TI_UINT16 uClientID)
{
    TRroamingTriggerParams params;
    currBSS_t *pCurrBSS = (currBSS_t *)hCurrBSS;

    TRACE2(pCurrBSS->hReport,REPORT_SEVERITY_INFORMATION , "currBss_registerBssLossEvent() uNumOfBeacons=%d,uClientID =%d \n", uNumOfBeacons,uClientID );

    /* Register for 'BSS-Loss' event */
    TWD_RegisterEvent (pCurrBSS->hTWD, TWD_OWN_EVENT_BSS_LOSE, (void *)currBSS_BssLossThresholdCrossed, pCurrBSS);
    TWD_EnableEvent (pCurrBSS->hTWD, TWD_OWN_EVENT_BSS_LOSE);

    pCurrBSS->numExpectedTbttForBSSLoss = uNumOfBeacons;
    params.TsfMissThreshold = uNumOfBeacons; /* number of missing beacon allowed before out-of-sync event is issued*/
    params.BssLossTimeout = NO_BEACON_DEFAULT_TIMEOUT;
    TWD_CfgConnMonitParams (pCurrBSS->hTWD, &params);

    return TI_OK;
}

TI_STATUS currBss_registerTxRetryEvent(TI_HANDLE hCurrBSS,TI_UINT8 uMaxTxRetryThreshold, TI_UINT16 uClientID)
{
    TRroamingTriggerParams params;
    currBSS_t *pCurrBSS = (currBSS_t *)hCurrBSS;

    TRACE2(pCurrBSS->hReport,REPORT_SEVERITY_INFORMATION , "currBss_registerTxRetryEvent() uMaxTxRetryThreshold=%d,uClientID =%d \n", uMaxTxRetryThreshold,uClientID );
   /* Register for 'Consec. Tx error' */
    TWD_RegisterEvent (pCurrBSS->hTWD, TWD_OWN_EVENT_MAX_TX_RETRY, (void *)currBSS_MaxTxRetryThresholdCrossed, pCurrBSS);
    TWD_EnableEvent (pCurrBSS->hTWD, TWD_OWN_EVENT_MAX_TX_RETRY);

    pCurrBSS->maxTxRetryThreshold = uMaxTxRetryThreshold;
    params.maxTxRetry = uMaxTxRetryThreshold;
    TWD_CfgMaxTxRetry (pCurrBSS->hTWD, &params);

    return TI_OK;
}





TI_STATUS currBSS_setParam(TI_HANDLE hCurrBSS, paramInfo_t *pParam)
{
    currBSS_t *pCurrBSS = (currBSS_t *)hCurrBSS;
    TI_STATUS status = TI_OK;

    if (pParam == NULL)
    {
        TRACE0(pCurrBSS->hReport, REPORT_SEVERITY_ERROR , " currBSS_setParam(): pParam is NULL!\n");
        return TI_NOK;
    }

    TRACE1(pCurrBSS->hReport,REPORT_SEVERITY_INFORMATION , "currBSS_setParam() %X \n", pParam->paramType);

    switch (pParam->paramType)
    {
	    case CURR_BSS_REGISTER_LINK_QUALITY_EVENT_PARAM:
            {
                TUserDefinedQualityTrigger *pUserTrigger = &pParam->content.rssiSnrTrigger;
                RssiSnrTriggerCfg_t         tTriggerCfg;
                TI_INT8                     triggerID = 0;

                TRACE8(pCurrBSS->hReport, REPORT_SEVERITY_INFORMATION , "currBSS_setParam - USER_DEFINED_TRIGGER: \n index = %d, \n	 threshold = %d, \n pacing = %d, \n metric = %d, \n type = %d, \n direction = %d, \n hystersis = %d, \n enable = %d \n",pUserTrigger->uIndex,pUserTrigger->iThreshold,pUserTrigger->uPacing,pUserTrigger->uMetric,pUserTrigger->uType,pUserTrigger->uDirection,pUserTrigger->uHystersis,pUserTrigger->uEnable);
                /* Copy from user structure to driver structure */
                tTriggerCfg.index     = pUserTrigger->uIndex;
                tTriggerCfg.threshold = pUserTrigger->iThreshold;
                tTriggerCfg.pacing    = pUserTrigger->uPacing;
                tTriggerCfg.metric    = pUserTrigger->uMetric;
                tTriggerCfg.type      = pUserTrigger->uType;
                tTriggerCfg.direction = pUserTrigger->uDirection;
                tTriggerCfg.hystersis = pUserTrigger->uHystersis;
                tTriggerCfg.enable    = pUserTrigger->uEnable;

                /* the registration request is not from EMP (clientID must be greater than 0)
                   so it is probably external user mode application like the CLI that sends always '0' as client ID*/
                if (pUserTrigger->uClientID == 0) 
                {
                    pUserTrigger->uClientID = pUserTrigger->uIndex + 1; /* use the index (starting from '0') as positive client ID*/
                }
                /* Register the event and enable it before configuration.  */
                triggerID = currBSS_RegisterTriggerEvent(hCurrBSS, (TI_UINT8)0, pUserTrigger->uClientID, (void*)0, hCurrBSS);

                if (triggerID < 0)
                {
                    TRACE0(pCurrBSS->hReport, REPORT_SEVERITY_ERROR , "currBSS_setParam: RSSI/SNR user trigger registration FAILED!! \n");
                    return TI_NOK;
                }
                else
                {
                    tTriggerCfg.index = (uint8)triggerID; /* the index is used for the eventMBox triggerID mapping*/
                }
                /* Send user defined trigger to FW (the related FW events are handled by the currBSS) */
                status = TWD_CfgRssiSnrTrigger (pCurrBSS->hTWD, &tTriggerCfg);

            }
            break;

        default:
            TRACE1(pCurrBSS->hReport, REPORT_SEVERITY_ERROR, "currBSS_setParam bad param=  %X\n", pParam->paramType);
            break;
    }

    return status;
}


TI_STATUS currBSS_getParam(TI_HANDLE hCurrBSS, paramInfo_t *pParam)
{
    return TI_NOK;
}

void currBss_DbgPrintTriggersTable(TI_HANDLE hCurrBSS)
{
#ifdef REPORT_LOG
    int i=0;
    currBSS_t *pCurrBSS = (currBSS_t *)hCurrBSS;

    WLAN_OS_REPORT(("\n -------------------  Triggers Table -------------------------- \n"));

    for (i=0; i< MAX_NUM_OF_RSSI_SNR_TRIGGERS ; i++)
    {
        WLAN_OS_REPORT(("\n TriggerIdx[%d]: clientID=%d , fCB=%d, WasRegisteredByApp=%d. \n",
                        i,
                        pCurrBSS->aTriggersDesc[i].clientID,
                        pCurrBSS->aTriggersDesc[i].fCB,
                        pCurrBSS->aTriggersDesc[i].WasRegisteredByApp));
    }
    WLAN_OS_REPORT(("\n --------------------------------------------------------------- \n"));
#endif
}