/*
 * Copyright (c) 2012-2013, 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.
 */

/*===========================================================================

                       W L A N _ Q C T _ T L _ HOSUPPORT. C
                                               
  OVERVIEW:
  
  DEPENDENCIES: 

  Are listed for each API below. 
  
  
===========================================================================*/

/*===========================================================================

                      EDIT HISTORY FOR FILE


  This section contains comments describing changes made to the module.
  Notice that changes are listed in reverse chronological order.


   $Header$$DateTime$$Author$


  when        who     what, where, why
----------    ---    --------------------------------------------------------
02/19/09      lti     Vos trace fix
02/06/09      sch     Dereg Bug fix
12/11/08      sch     Initial creation

===========================================================================*/
#include "wlan_qct_tl.h" 
#include "wlan_qct_wda.h"
#if defined WLAN_FEATURE_NEIGHBOR_ROAMING
/*----------------------------------------------------------------------------
 * Include Files
 * -------------------------------------------------------------------------*/
#include "wlan_qct_tl_hosupport.h"
#include "wlan_qct_tli.h"
#include "tlDebug.h"
/*----------------------------------------------------------------------------
 * Preprocessor Definitions and Constants
 * -------------------------------------------------------------------------*/
//#define WLANTL_HO_DEBUG_MSG
//#define WLANTL_HO_UTEST

#define WLANTL_HO_DEFAULT_RSSI      0xFF
#define WLANTL_HO_INVALID_RSSI      -100
/* RSSI sampling period, usec based
 * To reduce performance overhead
 * Current default 500msec */
#define WLANTL_HO_SAMPLING_PERIOD   500000



/* Get and release lock */
#define THSGETLOCK(a, b)                                      \
        do                                                    \
        {                                                     \
           if(!VOS_IS_STATUS_SUCCESS(vos_lock_acquire(b)))    \
           {                                                  \
              TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"%s Get Lock Fail", a));      \
              return VOS_STATUS_E_FAILURE;                    \
           }                                                  \
        }while(0)

#define THSRELEASELOCK(a, b)                                  \
        do                                                    \
        {                                                     \
           if(!VOS_IS_STATUS_SUCCESS(vos_lock_release(b)))    \
           {                                                  \
              TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"%s Release Lock Fail", a));  \
              return VOS_STATUS_E_FAILURE;                    \
           }                                                  \
        }while(0)

const v_U8_t  WLANTL_HO_TID_2_AC[WLAN_MAX_TID] = {WLANTL_AC_BE, 
                                                  WLANTL_AC_BK,
                                                  WLANTL_AC_BK, 
                                                  WLANTL_AC_BE,
                                                  WLANTL_AC_VI, 
                                                  WLANTL_AC_VI,
                                                  WLANTL_AC_VO,
                                                  WLANTL_AC_VO};
/*----------------------------------------------------------------------------
 *  Type Declarations
 * -------------------------------------------------------------------------*/
/* Temporary threshold store place for BMPS */
typedef struct
{
   v_S7_t  rssi;
   v_U8_t  event;
} WLANTL_HSTempPSIndType;

#ifdef RSSI_HACK
/* This is a dummy averaged RSSI value that can be controlled using dump commands 
 * to trigger TL to issue handoff related events. We will be using dump 362 <average RSSI> 
 * value to change its value */
int  dumpCmdRSSI = -48;
#endif

#ifdef WLANTL_HO_UTEST
/*==========================================================================

   FUNCTION

   DESCRIPTION 
    
   PARAMETERS 

   RETURN VALUE

============================================================================*/
static v_S7_t   rssi;
static v_S7_t   direction;
void TLHS_UtestHandleNewRSSI(v_S7_t *newRSSI, v_PVOID_t pAdapter)
{
   if(0 == rssi)
   {
      direction = -1;
   }
   else if(-90 == rssi)
   {
      direction = 1;
   }

   *newRSSI = rssi;
   rssi += direction;

   return;
}
#endif /* WLANTL_HO_UTEST */

#ifdef WLANTL_HO_DEBUG_MSG
/*==========================================================================

   FUNCTION

   DESCRIPTION 
    
   PARAMETERS 

   RETURN VALUE

============================================================================*/
void WLANTL_StatDebugDisplay
(
   v_U8_t                    STAid,
   WLANTL_TRANSFER_STA_TYPE *statistics
)
{
   TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"================================================="));
   TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Statistics for STA %d", STAid));
   TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"RX UC Fcnt %5d, MC Fcnt %5d, BC Fcnt %5d",
                statistics->rxUCFcnt, statistics->rxMCFcnt, statistics->rxBCFcnt));
   TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"RX UC Bcnt %5d, MC Bcnt %5d, BC Bcnt %5d",
                statistics->rxUCBcnt, statistics->rxMCBcnt, statistics->rxBCBcnt));
   TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"TX UC Fcnt %5d, MC Fcnt %5d, BC Fcnt %5d",
                statistics->txUCFcnt, statistics->txMCFcnt, statistics->txBCFcnt));
   TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"TX UC Bcnt %5d, MC Bcnt %5d, BC Bcnt %5d",
                statistics->txUCBcnt, statistics->txMCBcnt, statistics->txBCBcnt));
   TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"TRX Bcnt %5d, CRCOK Bcnt %5d, RXRate %5d",
                statistics->rxBcnt, statistics->rxBcntCRCok, statistics->rxRate));
   TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"================================================="));
   return;
}
#endif /* WLANTL_HO_DEBUG_MSG */

#ifdef WLANTL_DEBUG
void WLANTLPrintPktsRcvdPerRateIdx(v_PVOID_t pAdapter, v_U8_t staId, v_BOOL_t flush)
{
    v_U16_t  ii;
    WLANTL_CbType  *tlCtxt = VOS_GET_TL_CB(pAdapter);

    if(NULL == tlCtxt)
    {
        TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Invalid TL handle"));
        return;
    }

    if(NULL == tlCtxt->atlSTAClients[staId])
    {
        TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
            "WLAN TL:Client Memory was not allocated on %s", __func__));
        return;
    }

    if(0 == tlCtxt->atlSTAClients[staId]->ucExists )
    {
        TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLAN TL: %d STA ID does not exist", staId));
        return;
    }

    if(flush)
    {
        TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
                         "flushed rateIdx counters"));

        for(ii = 0; ii < MAX_RATE_INDEX; ii++)
            tlCtxt->atlSTAClients[staId]->trafficStatistics.pktCounterRateIdx[ii] = 0;

        return;
    }

    TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, "pkts per rate Index"));

    for(ii = 0; ii < MAX_RATE_INDEX; ii++)
    {
        /* printing int the below format
         * " rateIndex = pktCount "*/
        TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
                         "%d = %d", ii+1,
                         tlCtxt->atlSTAClients[staId]->trafficStatistics.pktCounterRateIdx[ii]));
    }

    return;
}

void WLANTLPrintPktsRcvdPerRssi(v_PVOID_t pAdapter, v_U8_t staId, v_BOOL_t flush)
{
    v_U16_t ii,jj;
    v_U32_t count = 0;
    WLANTL_CbType  *tlCtxt = VOS_GET_TL_CB(pAdapter);

    if(NULL == tlCtxt)
    {
        TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Invalid TL handle"));
        return;
    }

    if(NULL == tlCtxt->atlSTAClients[staId])
    {
        TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
            "WLAN TL:Client Memory was not allocated on %s", __func__));
        return;
    }

    if(0 == tlCtxt->atlSTAClients[staId]->ucExists)
    {
        TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLAN TL: %d STA ID does not exist", staId));
        return;
    }

    if(flush)
    {
        TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
                         "flushed rssi counters"));

        for(ii = 0; ii < MAX_NUM_RSSI; ii++)
            tlCtxt->atlSTAClients[staId]->trafficStatistics.pktCounterRssi[ii] = 0;

        return;
    }

    TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, "pkts per RSSI"));

    for(ii = 0; ii < MAX_NUM_RSSI; ii += MAX_RSSI_INTERVAL)
    {
        count = 0;

        for(jj = ii; jj < (ii + MAX_RSSI_INTERVAL); jj++)
            count += tlCtxt->atlSTAClients[staId]->trafficStatistics.pktCounterRssi[jj];

        /* prints are in the below format
         * " fromRSSI - toRSSI = pktCount " */
        TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
                         " %d - %d = %d",
                         ii, ii+(MAX_RSSI_INTERVAL - 1), count));
    }
    return;
}
#endif

/*==========================================================================

   FUNCTION

   DESCRIPTION 
    
   PARAMETERS 

   RETURN VALUE

============================================================================*/
void WLANTL_HSDebugDisplay
(
   v_PVOID_t pAdapter
)
{
   WLANTL_CbType                  *tlCtxt = VOS_GET_TL_CB(pAdapter);
   v_U8_t                          idx, sIdx;
   v_BOOL_t                        regionFound = VOS_FALSE;
   WLANTL_CURRENT_HO_STATE_TYPE   *currentHO;
   WLANTL_HO_SUPPORT_TYPE         *hoSupport;

   if (NULL == tlCtxt)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
                       "%s: Invalid TL Context",
                       __func__));
      return;
   }

   currentHO = &(tlCtxt->hoSupport.currentHOState);
   hoSupport = &(tlCtxt->hoSupport);


   for(idx = 0; idx < currentHO->numThreshold; idx++)
   {
      if(idx == currentHO->regionNumber)
      {
         regionFound = VOS_TRUE;
         if(VOS_TRUE == tlCtxt->isBMPS)
         {
            TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO," ----> CRegion %d, hRSSI:NA, BMPS, Alpha %d",
                         currentHO->regionNumber, currentHO->alpha));
         }
         else
         {
            TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO," ----> CRegion %d, hRSSI %d, Alpha %d",
                         currentHO->regionNumber,
                         currentHO->historyRSSI,
                         currentHO->alpha));
         }
      }
      for(sIdx = 0; sIdx < WLANTL_HS_NUM_CLIENT; sIdx++)
      {
         if(NULL != hoSupport->registeredInd[idx].crossCBFunction[sIdx])
         {
            if(VOS_MODULE_ID_HDD == hoSupport->registeredInd[idx].whoIsClient[sIdx])
            {
               TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Client HDD pCB %pK, triggerEvt %d, RSSI %d",
                   hoSupport->registeredInd[idx].crossCBFunction[sIdx],
                             hoSupport->registeredInd[idx].triggerEvent[sIdx],
                             hoSupport->registeredInd[idx].rssiValue));
            }
            else
            {
               TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Client SME pCB %pK, triggerEvt %d, RSSI %d",
                             hoSupport->registeredInd[idx].crossCBFunction[sIdx],
                             hoSupport->registeredInd[idx].triggerEvent[sIdx],
                             hoSupport->registeredInd[idx].rssiValue));
            }
         }
      }
   }

   if(VOS_FALSE == regionFound)
   {
      if(VOS_TRUE == tlCtxt->isBMPS)
      {
         TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO," ----> CRegion %d, hRSSI:NA, BMPS, Alpha %d",
                      currentHO->regionNumber, currentHO->alpha));
      }
      else
      {
         TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO," ----> CRegion %d, hRSSI %d, Alpha %d",
                      currentHO->regionNumber,
                      currentHO->historyRSSI,
                      currentHO->alpha));
      }
   }

   return;
}

/*==========================================================================

   FUNCTION

   DESCRIPTION 
    
   PARAMETERS 

   RETURN VALUE

============================================================================*/
VOS_STATUS WLANTL_SetFWRSSIThresholds
(
   v_PVOID_t                       pAdapter
)
{
   WLANTL_CbType                  *tlCtxt = VOS_GET_TL_CB(pAdapter);
   VOS_STATUS                      status = VOS_STATUS_SUCCESS;
   WLANTL_HO_SUPPORT_TYPE         *hoSupport;
   WLANTL_CURRENT_HO_STATE_TYPE   *currentHO;
   tSirRSSIThresholds              bmpsThresholds;
   WLANTL_HSTempPSIndType          tempIndSet[WLANTL_SINGLE_CLNT_THRESHOLD];
   v_U8_t                          bmpsLoop;
   v_U8_t                          bmpsInd;
   v_U8_t                          clientLoop;

   if(NULL == tlCtxt)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Invalid TL handle"));
      return VOS_STATUS_E_INVAL;
   }

   WLANTL_HSDebugDisplay(pAdapter);
   currentHO = &(tlCtxt->hoSupport.currentHOState);
   hoSupport = &(tlCtxt->hoSupport);

   memset((v_U8_t *)&tempIndSet[0], 0, WLANTL_SINGLE_CLNT_THRESHOLD * sizeof(WLANTL_HSTempPSIndType));
   memset(&bmpsThresholds, 0, sizeof(tSirRSSIThresholds));

   bmpsInd = 0;
   for(bmpsLoop = 0; bmpsLoop < WLANTL_MAX_AVAIL_THRESHOLD; bmpsLoop++)
   {
      for(clientLoop = 0; clientLoop < WLANTL_HS_NUM_CLIENT; clientLoop++)
      {
         if(0 != hoSupport->registeredInd[bmpsLoop].triggerEvent[clientLoop])
         {
            if(bmpsInd == WLANTL_SINGLE_CLNT_THRESHOLD)
            {
               TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Single Client Threshold should be less than %d", WLANTL_SINGLE_CLNT_THRESHOLD));
               break;
            }
            tempIndSet[bmpsInd].rssi  = hoSupport->registeredInd[bmpsLoop].rssiValue;
            tempIndSet[bmpsInd].event = hoSupport->registeredInd[bmpsLoop].triggerEvent[clientLoop];
            bmpsInd++;
            break;
         }
      }
   }

   bmpsThresholds.ucRssiThreshold1 = tempIndSet[0].rssi;
   if((WLANTL_HO_THRESHOLD_DOWN == tempIndSet[0].event) ||
      (WLANTL_HO_THRESHOLD_CROSS == tempIndSet[0].event))
   {
      bmpsThresholds.bRssiThres1NegNotify = 1;
   }
   if((WLANTL_HO_THRESHOLD_UP == tempIndSet[0].event) ||
      (WLANTL_HO_THRESHOLD_CROSS == tempIndSet[0].event))
   {
      bmpsThresholds.bRssiThres1PosNotify = 1;
   }

   bmpsThresholds.ucRssiThreshold2 = tempIndSet[1].rssi;
   if((WLANTL_HO_THRESHOLD_DOWN == tempIndSet[1].event) ||
      (WLANTL_HO_THRESHOLD_CROSS == tempIndSet[1].event))
   {
      bmpsThresholds.bRssiThres2NegNotify = 1;
   }
   if((WLANTL_HO_THRESHOLD_UP == tempIndSet[1].event) ||
      (WLANTL_HO_THRESHOLD_CROSS == tempIndSet[1].event))
   {
      bmpsThresholds.bRssiThres2PosNotify = 1;
   }

   bmpsThresholds.ucRssiThreshold3 = tempIndSet[2].rssi;
   if((WLANTL_HO_THRESHOLD_DOWN == tempIndSet[2].event) ||
      (WLANTL_HO_THRESHOLD_CROSS == tempIndSet[2].event))
   {
      bmpsThresholds.bRssiThres3NegNotify = 1;
   }
   if((WLANTL_HO_THRESHOLD_UP == tempIndSet[2].event) ||
      (WLANTL_HO_THRESHOLD_CROSS == tempIndSet[2].event))
   {
      bmpsThresholds.bRssiThres3PosNotify = 1;
   }

   WDA_SetRSSIThresholds(hoSupport->macCtxt, &bmpsThresholds);
   return status;
}

/*==========================================================================

   FUNCTION

   DESCRIPTION 
    
   PARAMETERS 

   RETURN VALUE

============================================================================*/
VOS_STATUS WLANTL_StatHandleRXFrame
(
   v_PVOID_t        pAdapter,
   v_PVOID_t        pBDHeader,
   v_U8_t           STAid,
   v_BOOL_t         isBroadcast,
   vos_pkt_t       *dataBuffer   
)
{
   WLANTL_CbType            *tlCtxt = VOS_GET_TL_CB(pAdapter);
   VOS_STATUS                status = VOS_STATUS_SUCCESS;
   WLANTL_TRANSFER_STA_TYPE *statistics;
   v_U16_t                   packetSize;

   if(NULL == tlCtxt)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Invalid TL handle"));
      return VOS_STATUS_E_INVAL;
   }

   if ( NULL == tlCtxt->atlSTAClients[STAid] )
   {
       TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
           "WLAN TL:Client Memory was not allocated on %s", __func__));
       return VOS_STATUS_E_FAILURE;
   }


   if(NULL == dataBuffer)
   {
      TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Management Frame, not need to handle with Stat"));
      return status;
   }

   if(0 == tlCtxt->atlSTAClients[STAid]->ucExists)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLAN TL: %d STA ID is not exist", STAid));
      return VOS_STATUS_E_INVAL;
   }

   statistics = &tlCtxt->atlSTAClients[STAid]->trafficStatistics;
   vos_pkt_get_packet_length(dataBuffer, &packetSize);

   if(isBroadcast)
   {
      /* Above flag is set for both broadcast and multicast frame. So
         find frame type to distinguish between multicast and broadcast.
         Ideally, it would be better if BD header has a field to indicate
         multicast frame and then we would not need to call below function */

      v_U8_t ucFrameCastType;

      status = WLANTL_FindFrameTypeBcMcUc(tlCtxt, STAid, dataBuffer,
                                          &ucFrameCastType);

      if (VOS_STATUS_SUCCESS != status)
      {
         TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLAN TL: failed to distinguish if Rx frame is broadcast or multicast"));
         return status;
      }

      switch (ucFrameCastType)
      {
         case WLANTL_FRAME_TYPE_BCAST:
            TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"This is RX BC frame"));
            statistics->rxBCFcnt++;
            statistics->rxBCBcnt += (packetSize - WLANHAL_RX_BD_HEADER_SIZE);
            break;

         case WLANTL_FRAME_TYPE_MCAST:
            TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"This is RX MC frame"));
            statistics->rxMCFcnt++;
            statistics->rxMCBcnt += (packetSize - WLANHAL_RX_BD_HEADER_SIZE);
            break;

         case WLANTL_FRAME_TYPE_UCAST:
            /* error - for unicast frame we should not reach here */
            TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLAN TL: BD header indicates broadcast but MAC address indicates unicast"));
            return VOS_STATUS_E_INVAL;
            break;

         default:
            TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLAN TL: error in finding bc/mc/uc type of the received frame"));
            return VOS_STATUS_E_INVAL;
            break;
      }
   }
   else
   {
      TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"This is RX UC frame"));
      statistics->rxUCFcnt++;
      statistics->rxUCBcnt += (packetSize - WLANHAL_RX_BD_HEADER_SIZE);
   }

   /* TODO caculation is needed, dimension of 500kbps */
   statistics->rxRate = WDA_GET_RX_MAC_RATE_IDX(pBDHeader);

#ifdef WLANTL_DEBUG
   if( (statistics->rxRate - 1) < MAX_RATE_INDEX)
     tlCtxt->atlSTAClients[STAid]->trafficStatistics.pktCounterRateIdx[statistics->rxRate - 1]++;

   /* Check if the +ve value of RSSI is within the valid range.
    * And increment pkt counter based on RSSI */
   if( (v_U16_t)((WDA_GET_RX_RSSI_DB(pBDHeader)) * (-1)) < MAX_NUM_RSSI)
     tlCtxt->atlSTAClients[STAid]->trafficStatistics.pktCounterRssi[(v_U16_t)((WDA_GET_RX_RSSI_DB(pBDHeader)) * (-1))]++;
#endif
   TLLOG1(VOS_TRACE (VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_MED,
                  "****Received rate Index = %d type=%d subtype=%d****",
                  statistics->rxRate,WDA_GET_RX_TYPE(pBDHeader),WDA_GET_RX_SUBTYPE(pBDHeader)));

   statistics->rxBcnt += (packetSize - WLANHAL_RX_BD_HEADER_SIZE);

#ifdef WLANTL_HO_DEBUG_MSG
   WLANTL_StatDebugDisplay(STAid, statistics);
#endif /* WLANTL_HO_DEBUG_MSG */

   return status;
}

/*==========================================================================

   FUNCTION

   DESCRIPTION 
    
   PARAMETERS 

   RETURN VALUE

============================================================================*/
VOS_STATUS WLANTL_StatHandleTXFrame
(
   v_PVOID_t        pAdapter,
   v_U8_t           STAid,
   vos_pkt_t       *dataBuffer,
   v_PVOID_t        pBDHeader,
   WLANTL_MetaInfoType *txMetaInfo
)
{
   WLANTL_CbType            *tlCtxt = VOS_GET_TL_CB(pAdapter);
   VOS_STATUS                status = VOS_STATUS_SUCCESS;
   WLANTL_TRANSFER_STA_TYPE *statistics;
   v_U16_t                   packetSize;

   if((NULL == tlCtxt) || (NULL == dataBuffer))
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Invalid TL handle"));
      return VOS_STATUS_E_INVAL;
   }

   if ( NULL == tlCtxt->atlSTAClients[STAid] )
   {
       TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
           "WLAN TL:Client Memory was not allocated on %s", __func__));
       return VOS_STATUS_E_FAILURE;
   }

   if(0 == tlCtxt->atlSTAClients[STAid]->ucExists)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLAN TL: %d STA ID is not exist", STAid));
      return VOS_STATUS_E_INVAL;
   }

   /* TODO : BC/MC/UC have to be determined by MAC address */
   statistics = &tlCtxt->atlSTAClients[STAid]->trafficStatistics;
   vos_pkt_get_packet_length(dataBuffer, &packetSize);
   if(txMetaInfo->ucBcast)
   {
      TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"This TX is BC frame"));
      statistics->txBCFcnt++;
      statistics->txBCBcnt += packetSize;
   }
   else if(txMetaInfo->ucMcast)
   {
      TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"This TX is MC frame"));
      statistics->txMCFcnt++;
      statistics->txMCBcnt += packetSize;
   }
   else
   {
      TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"This is TX UC frame"));
      statistics->txUCFcnt++;
      statistics->txUCBcnt += packetSize;
   }

#ifdef WLANTL_HO_DEBUG_MSG
   WLANTL_StatDebugDisplay(STAid, statistics);
#endif /* WLANTL_HO_DEBUG_MSG */

   return status;
}

/*==========================================================================

   FUNCTION  WLANTL_HSTrafficStatusTimerExpired

   DESCRIPTION  If traffic status monitoring timer is expiered,
                Count how may frames have sent and received during 
                measure period and if traffic status is changed
                send notification to Client(SME)
    
   PARAMETERS pAdapter
              Global handle

   RETURN VALUE

============================================================================*/
v_VOID_t WLANTL_HSTrafficStatusTimerExpired
(
   v_PVOID_t pAdapter
)
{
   WLANTL_CbType                        *tlCtxt = VOS_GET_TL_CB(pAdapter);
   WLANTL_HO_TRAFFIC_STATUS_HANDLE_TYPE *trafficHandle = NULL;
   WLANTL_HO_TRAFFIC_STATUS_TYPE         newTraffic;
   v_U32_t                               rtFrameCount;
   v_U32_t                               nrtFrameCount;
   v_BOOL_t                              trafficStatusChanged = VOS_FALSE;

   if(NULL == tlCtxt)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Invalid TL handle"));
      return;
   }

   /* Get rt and nrt frame count sum */
   trafficHandle = &tlCtxt->hoSupport.currentTraffic;
   rtFrameCount  = trafficHandle->rtRXFrameCount + trafficHandle->rtTXFrameCount;
   nrtFrameCount = trafficHandle->nrtRXFrameCount + trafficHandle->nrtTXFrameCount;

   TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Traffic status timer expired RT FC %d, NRT FC %d", rtFrameCount, nrtFrameCount));

   /* Get current traffic status */
   if(rtFrameCount > trafficHandle->idleThreshold)
   {
      newTraffic.rtTrafficStatus = WLANTL_HO_RT_TRAFFIC_STATUS_ON;
   }
   else
   {
      newTraffic.rtTrafficStatus = WLANTL_HO_RT_TRAFFIC_STATUS_OFF;
   }

   if(nrtFrameCount > trafficHandle->idleThreshold)
   {
      newTraffic.nrtTrafficStatus = WLANTL_HO_NRT_TRAFFIC_STATUS_ON;
   }
   else
   {
      newTraffic.nrtTrafficStatus = WLANTL_HO_NRT_TRAFFIC_STATUS_OFF;
   }

   /* Differentiate with old traffic status */
   if(trafficHandle->trafficStatus.rtTrafficStatus != newTraffic.rtTrafficStatus)
   {
      TLLOGW(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_WARN,"RT Traffic status changed from %d to %d",
                   trafficHandle->trafficStatus.rtTrafficStatus,
                   newTraffic.rtTrafficStatus));
      trafficStatusChanged = VOS_TRUE;
   }
   if(trafficHandle->trafficStatus.nrtTrafficStatus != newTraffic.nrtTrafficStatus)
   {
      TLLOGW(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_WARN,"NRT Traffic status changed from %d to %d",
                   trafficHandle->trafficStatus.nrtTrafficStatus,
                   newTraffic.nrtTrafficStatus));
      trafficStatusChanged = VOS_TRUE;
   }

   /* If traffic status is changed send notification to client */
   if((VOS_TRUE == trafficStatusChanged) && (NULL != trafficHandle->trafficCB))
   {
      trafficHandle->trafficCB(pAdapter, newTraffic, trafficHandle->usrCtxt);
      trafficHandle->trafficStatus.rtTrafficStatus = newTraffic.rtTrafficStatus;
      trafficHandle->trafficStatus.nrtTrafficStatus = newTraffic.nrtTrafficStatus;
   }
   else if((VOS_TRUE == trafficStatusChanged) && (NULL == trafficHandle->trafficCB))
   {
      TLLOGW(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_WARN,"Traffic status is changed but not need to report"));
   }

   /* Reset frame counters */
   trafficHandle->rtRXFrameCount = 0;
   trafficHandle->rtTXFrameCount = 0;
   trafficHandle->nrtRXFrameCount = 0;
   trafficHandle->nrtTXFrameCount = 0;

   if(NULL != trafficHandle->trafficCB)
   {
      /* restart timer  only when the callback is not NULL */
      vos_timer_start(&trafficHandle->trafficTimer, trafficHandle->measurePeriod);
   }
   
   return;
}


/*==========================================================================

   FUNCTION

   DESCRIPTION 
    
   PARAMETERS 

   RETURN VALUE

============================================================================*/
VOS_STATUS WLANTL_HSGetRSSI
(
   v_PVOID_t        pAdapter,
   v_PVOID_t        pBDHeader,
   v_U8_t           STAid,
   v_S7_t          *currentAvgRSSI
)
{
   WLANTL_CbType   *tlCtxt = VOS_GET_TL_CB(pAdapter);
   VOS_STATUS       status = VOS_STATUS_SUCCESS;
   v_S7_t           currentRSSI, currentRSSI0, currentRSSI1;
   WLANTL_CURRENT_HO_STATE_TYPE *currentHO = NULL;


   if(NULL == tlCtxt)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Invalid TL handle"));
      return VOS_STATUS_E_INVAL;
   }

   if ( NULL == tlCtxt->atlSTAClients[STAid] )
   {
       TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
           "WLAN TL:Client Memory was not allocated on %s", __func__));
       return VOS_STATUS_E_FAILURE;
   }

   /* 
      Compute RSSI only for the last MPDU of an AMPDU.
      Only last MPDU carries the Phy Stats Values 
   */
    if (WDA_IS_RX_AN_AMPDU (pBDHeader)) {
       if (!WDA_IS_RX_LAST_MPDU(pBDHeader)) {
           return VOS_STATUS_E_FAILURE;
          }
    }

   currentHO = &tlCtxt->hoSupport.currentHOState;

   currentRSSI0 = WLANTL_GETRSSI0(pBDHeader);
   currentRSSI1 = WLANTL_GETRSSI1(pBDHeader);
   currentRSSI  = (currentRSSI0 > currentRSSI1) ? currentRSSI0 : currentRSSI1;

   if (0 == currentRSSI)
      return VOS_STATUS_E_INVAL;

#ifdef WLANTL_HO_UTEST
   TLHS_UtestHandleNewRSSI(&currentRSSI, pAdapter);
#endif /* WLANTL_HO_UTEST */

   if(0 == tlCtxt->atlSTAClients[STAid]->rssiAvg)
   {
      *currentAvgRSSI = currentRSSI;
   }
   else
   {
      *currentAvgRSSI = ((tlCtxt->atlSTAClients[STAid]->rssiAvg  *
                          tlCtxt->atlSTAClients[STAid]->rssiAlpha) +
                         (currentRSSI * (10 - tlCtxt->atlSTAClients[STAid]->rssiAlpha))) / 10;
   }

#ifdef RSSI_HACK
   *currentAvgRSSI = (v_S7_t)dumpCmdRSSI;
#endif

   tlCtxt->atlSTAClients[STAid]->rssiAvg = *currentAvgRSSI;

   TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Current new RSSI is %d, averaged RSSI is %d", currentRSSI, *currentAvgRSSI));
   return status;
}

#ifdef WLAN_FEATURE_LINK_LAYER_STATS

/*==========================================================================

   FUNCTION WLANTL_HSGetDataRSSI

   DESCRIPTION

   PARAMETERS

   RETURN VALUE

============================================================================*/
VOS_STATUS WLANTL_HSGetDataRSSI
(
   v_PVOID_t        pAdapter,
   v_PVOID_t        pBDHeader,
   v_U8_t           STAid,
   v_S7_t          *currentAvgRSSI
)
{
   WLANTL_CbType   *tlCtxt = VOS_GET_TL_CB(pAdapter);
   VOS_STATUS       status = VOS_STATUS_SUCCESS;
   v_S7_t           currentRSSI, currentRSSI0, currentRSSI1;
   WLANTL_CURRENT_HO_STATE_TYPE *currentHO = NULL;


   if(NULL == tlCtxt)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
                  "Invalid TL handle"));
      return VOS_STATUS_E_INVAL;
   }

   if ( NULL == tlCtxt->atlSTAClients[STAid] )
   {
       TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
           "WLAN TL:Client Memory was not allocated on %s", __func__));
       return VOS_STATUS_E_FAILURE;
   }

   /*
    * Compute RSSI only for the last MPDU of an AMPDU.
    * Only last MPDU carries the Phy Stats Values
    */
    if (WDA_IS_RX_AN_AMPDU (pBDHeader)) {
       if (!WDA_IS_RX_LAST_MPDU(pBDHeader)) {
           return VOS_STATUS_E_FAILURE;
          }
    }

   currentHO = &tlCtxt->hoSupport.currentHOState;

   currentRSSI0 = WLANTL_GETRSSI0(pBDHeader);
   currentRSSI1 = WLANTL_GETRSSI0(pBDHeader);
   currentRSSI  = (currentRSSI0 > currentRSSI1) ? currentRSSI0 : currentRSSI1;

   if (0 == currentRSSI)
      return VOS_STATUS_E_INVAL;

#ifdef WLANTL_HO_UTEST
   TLHS_UtestHandleNewRSSI(&currentRSSI, pAdapter);
#endif /* WLANTL_HO_UTEST */

   if(0 == tlCtxt->atlSTAClients[STAid]->rssiDataAvg)
   {
      *currentAvgRSSI = currentRSSI;
   }
   else
   {
      *currentAvgRSSI = ((tlCtxt->atlSTAClients[STAid]->rssiDataAvg  *
                          tlCtxt->atlSTAClients[STAid]->rssiDataAlpha) +
                         (currentRSSI *
                     (10 - tlCtxt->atlSTAClients[STAid]->rssiDataAlpha))) / 10;
   }


   tlCtxt->atlSTAClients[STAid]->rssiDataAvg = *currentAvgRSSI;

   TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,
          "Current new Data RSSI is %d, averaged Data RSSI is %d",
          currentRSSI, *currentAvgRSSI));
   return status;
}
#endif

/*==========================================================================

   FUNCTION

   DESCRIPTION

   PARAMETERS

   RETURN VALUE

============================================================================*/
VOS_STATUS WLANTL_HSBMPSRSSIRegionChangedNotification
(
   v_PVOID_t             pAdapter,
   tpSirRSSINotification pRSSINotification
)
{
   WLANTL_CbType                  *tlCtxt = VOS_GET_TL_CB(pAdapter);
   VOS_STATUS                      status = VOS_STATUS_SUCCESS;
   WLANTL_CURRENT_HO_STATE_TYPE   *currentHO;
   WLANTL_HO_SUPPORT_TYPE         *hoSupport;
   WLANTL_RSSICrossThresholdCBType cbFunction = NULL;
   v_PVOID_t                       usrCtxt = NULL;
   v_U8_t                          evtType = WLANTL_HO_THRESHOLD_NA;
   v_U32_t                         preFWNotification = 0;
   v_U32_t                         curFWNotification = 0;
   v_U8_t                          newRegionNumber = 0;
   v_U8_t                          pRegionNumber = 0, nRegionNumber = 0;
   v_U32_t                         isSet;
   v_U8_t                          idx, sIdx;


   if(NULL == tlCtxt)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Invalid TL handle"));
      return VOS_STATUS_E_INVAL;
   }

   if(NULL == pRSSINotification)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Invalid FW RSSI Notification"));
      VOS_ASSERT(0);
      return VOS_STATUS_E_INVAL;
   }

   THSGETLOCK("WLANTL_HSBMPSRSSIRegionChangedNotification",
                                                   &tlCtxt->hoSupport.hosLock);
   currentHO = &(tlCtxt->hoSupport.currentHOState);
   hoSupport = &(tlCtxt->hoSupport);
   preFWNotification = currentHO->fwNotification;

   isSet = pRSSINotification->bRssiThres1PosCross;
   curFWNotification |= isSet << 5;
   isSet = pRSSINotification->bRssiThres2PosCross;
   curFWNotification |= isSet << 4;
   isSet = pRSSINotification->bRssiThres3PosCross;
   curFWNotification |= isSet << 3;
   isSet = pRSSINotification->bRssiThres1NegCross;
   curFWNotification |= isSet << 2;
   isSet = pRSSINotification->bRssiThres2NegCross;
   curFWNotification |= isSet << 1;
   isSet = pRSSINotification->bRssiThres3NegCross;
   curFWNotification |= isSet;
   TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Current FW Notification is 0x%x", (v_U32_t)curFWNotification ));

   currentHO->fwNotification = curFWNotification;

   if(0 == preFWNotification)
   {
      TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"This is the first time notification from FW Value is 0x%x", curFWNotification));
      preFWNotification = curFWNotification;
   }
   else if(preFWNotification == curFWNotification)
   {
      THSRELEASELOCK("WLANTL_HSBMPSRSSIRegionChangedNotification",
                                                   &tlCtxt->hoSupport.hosLock);
      return status;
   }

   if(1 == pRSSINotification->bRssiThres1PosCross)
   {
      TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"POS Cross to Region 0"));
      pRegionNumber = 0;
   }
   else if(1 == pRSSINotification->bRssiThres2PosCross)
   {
      TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"POS Cross to Region 1"));
      pRegionNumber = 1;
   }
   else if(1 == pRSSINotification->bRssiThres3PosCross)
   {
      TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"POS Cross to Region 2"));
      pRegionNumber = 2;
   }

   if(1 == pRSSINotification->bRssiThres3NegCross)
   {
      TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"NEG Cross to Region 3"));
      nRegionNumber = 3;
   }
   else if(1 == pRSSINotification->bRssiThres2NegCross)
   {
      TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"NEG Cross to Region 2"));
      nRegionNumber = 2;
   }
   else if(1 == pRSSINotification->bRssiThres1NegCross)
   {
      TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"NEG Cross to Region 1"));
      nRegionNumber = 1;
   }

   newRegionNumber = (nRegionNumber > pRegionNumber) ? nRegionNumber : pRegionNumber;
   if((currentHO->regionNumber) && (newRegionNumber == currentHO->regionNumber))
   {
      TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"No Region Change with BMPS mode"));
      preFWNotification = curFWNotification;
      THSRELEASELOCK("WLANTL_HSBMPSRSSIRegionChangedNotification",
                                                   &tlCtxt->hoSupport.hosLock);
      return status;
   }
   else if(newRegionNumber > currentHO->regionNumber)
   {
      TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Region Increase Worse RSSI"));
      for(idx = currentHO->regionNumber; idx < newRegionNumber; idx++)
      {
         for(sIdx = 0; sIdx < WLANTL_HS_NUM_CLIENT; sIdx++)
         {
            if((WLANTL_HO_THRESHOLD_DOWN == hoSupport->registeredInd[idx].triggerEvent[sIdx]) ||
               (WLANTL_HO_THRESHOLD_CROSS == hoSupport->registeredInd[idx].triggerEvent[sIdx]))
            {
               if(NULL != hoSupport->registeredInd[idx].crossCBFunction[sIdx])
               {
                  cbFunction = hoSupport->registeredInd[idx].crossCBFunction[sIdx];
                  usrCtxt = hoSupport->registeredInd[idx].usrCtxt[sIdx];

                  evtType = WLANTL_HO_THRESHOLD_DOWN;
                  TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Trigger Event %d, region index %d", hoSupport->registeredInd[idx].triggerEvent[sIdx], idx));
                  currentHO->regionNumber = newRegionNumber;
                  status = cbFunction(pAdapter, evtType, usrCtxt, pRSSINotification->avgRssi);
               }
            }
         }
      }
   }
   else
   {
      TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Region Decrease Better RSSI"));
      idx = (currentHO->regionNumber)?(currentHO->regionNumber-1):0;
      while (idx >= newRegionNumber)
      {
         for(sIdx = 0; sIdx < WLANTL_HS_NUM_CLIENT; sIdx++)
         {
            if((WLANTL_HO_THRESHOLD_UP & hoSupport->registeredInd[idx].triggerEvent[sIdx]) ||
               (WLANTL_HO_THRESHOLD_CROSS & hoSupport->registeredInd[idx].triggerEvent[sIdx]))
            {
               if(NULL != hoSupport->registeredInd[idx].crossCBFunction[sIdx])
               {
                  cbFunction = hoSupport->registeredInd[idx].crossCBFunction[sIdx];
                  usrCtxt = hoSupport->registeredInd[idx].usrCtxt[sIdx];

                  evtType = WLANTL_HO_THRESHOLD_UP;
                  TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Trigger Event %d, region index %d", hoSupport->registeredInd[idx].triggerEvent[sIdx], idx));
                  currentHO->regionNumber = newRegionNumber;
                  status = cbFunction(pAdapter, evtType, usrCtxt, pRSSINotification->avgRssi);
               }
            }
         }
         if (!idx--)
             break;
      }
   }

   TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"BMPS State, MSG from FW, Trigger Event %d, region index %d",
                 evtType, currentHO->regionNumber));

   THSRELEASELOCK("WLANTL_HSBMPSRSSIRegionChangedNotification",
                                                   &tlCtxt->hoSupport.hosLock);
   return VOS_STATUS_SUCCESS;
}

/*==========================================================================

   FUNCTION

   DESCRIPTION 
    
   PARAMETERS 

   RETURN VALUE

============================================================================*/
VOS_STATUS WLANTL_HSHandleRSSIChange
(
   v_PVOID_t   pAdapter,
   v_S7_t      currentRSSI
)
{
   WLANTL_CbType                  *tlCtxt = VOS_GET_TL_CB(pAdapter);
   VOS_STATUS                      status = VOS_STATUS_SUCCESS;
   v_U8_t                          currentRegion = 0;
   v_U8_t                          idx, sIdx;
   WLANTL_CURRENT_HO_STATE_TYPE   *currentHO;
   WLANTL_HO_SUPPORT_TYPE         *hoSupport;
   WLANTL_RSSICrossThresholdCBType cbFunction = NULL;
   v_PVOID_t                       usrCtxt = NULL;
   v_U8_t                          evtType = WLANTL_HO_THRESHOLD_NA;

   if(NULL == tlCtxt)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Invalid TL handle"));
      return VOS_STATUS_E_INVAL;
   }

   currentHO = &(tlCtxt->hoSupport.currentHOState);
   hoSupport = &(tlCtxt->hoSupport);
   TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"CRegion %d, NThreshold %d, HRSSI %d",
                currentHO->regionNumber,
                currentHO->numThreshold,
                currentHO->historyRSSI));

   /* Find where is current region */
   for(idx = 0; idx < currentHO->numThreshold; idx++)
   {
      if(hoSupport->registeredInd[idx].rssiValue < currentRSSI)
      {
         currentRegion = idx;
         TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Found region %d, not bottom", currentRegion));
         break;
      }
   }

   /* If could not find then new RSSI is belong to bottom region */
   if(idx == currentHO->numThreshold)
   {
      currentRegion = idx;
      TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Current region is bottom %d", idx));
   }

   /* This is a hack. Actual assignment was happening after the below checks. This hack is needed till TL
      posts message and nothing else in the callback indicating UP/DOWN event to the registered module */
   currentHO->historyRSSI = currentRSSI;
   
   if(currentRegion == currentHO->regionNumber)
   {
      currentHO->historyRSSI = currentRSSI;
      return status;
   }
   else if(currentRegion > currentHO->regionNumber)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Region Increase Worse RSSI"));
      for(idx = currentHO->regionNumber; idx < currentRegion; idx++)
      {
         for(sIdx = 0; sIdx < WLANTL_HS_NUM_CLIENT; sIdx++)
         {
            if((WLANTL_HO_THRESHOLD_DOWN == hoSupport->registeredInd[idx].triggerEvent[sIdx]) ||
               (WLANTL_HO_THRESHOLD_CROSS == hoSupport->registeredInd[idx].triggerEvent[sIdx]))
            {
               if(NULL != hoSupport->registeredInd[idx].crossCBFunction[sIdx])
               {
                  cbFunction = hoSupport->registeredInd[idx].crossCBFunction[sIdx];
                  usrCtxt = hoSupport->registeredInd[idx].usrCtxt[sIdx];

                  evtType = WLANTL_HO_THRESHOLD_DOWN;
                  TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Trigger Event %d, region index %d", hoSupport->registeredInd[idx].triggerEvent[sIdx], idx));
                  status = WLANTL_HSSerializeTlIndication(pAdapter, evtType, usrCtxt, cbFunction, currentRSSI);
               }
            }
         }
      }
   }
   else
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Region Decrease Better RSSI"));
      for(idx = currentHO->regionNumber; idx > currentRegion; idx--)
      {
         for(sIdx = 0; sIdx < WLANTL_HS_NUM_CLIENT; sIdx++)
         {
            if((WLANTL_HO_THRESHOLD_UP & hoSupport->registeredInd[idx - 1].triggerEvent[sIdx]) ||
               (WLANTL_HO_THRESHOLD_CROSS & hoSupport->registeredInd[idx - 1].triggerEvent[sIdx]))
            {
               if(NULL != hoSupport->registeredInd[idx - 1].crossCBFunction[sIdx])
               {
                  cbFunction = hoSupport->registeredInd[idx - 1].crossCBFunction[sIdx];
                  usrCtxt = hoSupport->registeredInd[idx - 1].usrCtxt[sIdx];

                  evtType = WLANTL_HO_THRESHOLD_UP;
                  TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Trigger Event %d, region index %d", hoSupport->registeredInd[idx - 1].triggerEvent[sIdx], idx - 1));
                  status = WLANTL_HSSerializeTlIndication(pAdapter, evtType, usrCtxt, cbFunction, currentRSSI);
               }
            }
         }
      }
   }

   currentHO->historyRSSI = currentRSSI;
   currentHO->regionNumber = currentRegion;
   WLANTL_HSDebugDisplay(pAdapter);

   if(!VOS_IS_STATUS_SUCCESS(status))
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Client fail to handle region change in normal mode %d", status));
   }
   return VOS_STATUS_SUCCESS;
}

/*==========================================================================

   FUNCTION

   DESCRIPTION 
    
   PARAMETERS 

   RETURN VALUE

============================================================================*/
VOS_STATUS WLANTL_HSHandleRXFrame
(
   v_PVOID_t        pAdapter,
   v_U8_t           frameType,
   v_PVOID_t        pBDHeader,
   v_U8_t           STAid,
   v_BOOL_t         isBroadcast,
   vos_pkt_t       *dataBuffer
)
{
   WLANTL_CURRENT_HO_STATE_TYPE *currentHO = NULL;
   WLANTL_CbType   *tlCtxt = VOS_GET_TL_CB(pAdapter);
   VOS_STATUS       status = VOS_STATUS_SUCCESS;
   v_S7_t           currentAvgRSSI = 0;
   v_U8_t           ac;
   v_U32_t          currentTimestamp;
   v_U8_t           tid;

   if(NULL == tlCtxt)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Invalid TL handle"));
      return VOS_STATUS_E_INVAL;
   }

   THSGETLOCK("WLANTL_HSHandleRXFrame", &tlCtxt->hoSupport.hosLock);
   WLANTL_StatHandleRXFrame(pAdapter, pBDHeader, STAid, isBroadcast, dataBuffer);

   /* If this frame is not management frame increase frame count */
   if((0 != tlCtxt->hoSupport.currentTraffic.idleThreshold) &&
      (WLANTL_MGMT_FRAME_TYPE != frameType))
   {
      tid = WDA_GET_RX_TID( pBDHeader );

      /* If AP uses TID greater than 8 for EAPOL packet connection will not
         be established. To ensure no connection fail use TID as zero.*/
      if (WLANTL_TID_INVALID(tid)) {
         VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,
             "WLAN TL:Invalid Tid: %d", tid);
         tid = 0;
      }

      ac = WLANTL_HO_TID_2_AC[(v_U8_t)tid];

      /* Only Voice traffic is handled as real time traffic */
      if(WLANTL_AC_VO == ac)
      {
         tlCtxt->hoSupport.currentTraffic.rtRXFrameCount++;
      }
      else
      {
         tlCtxt->hoSupport.currentTraffic.nrtRXFrameCount++;
      }
      TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"RX frame AC %d, RT Frame Count %d, NRT Frame Count %d",
                   ac,
                   tlCtxt->hoSupport.currentTraffic.rtRXFrameCount,
                   tlCtxt->hoSupport.currentTraffic.nrtRXFrameCount));
   }

   currentHO = &tlCtxt->hoSupport.currentHOState;
   if(VOS_TRUE == tlCtxt->isBMPS)
   {
      WLANTL_HSGetRSSI(pAdapter, pBDHeader, STAid, &currentAvgRSSI);
      currentHO->historyRSSI = currentAvgRSSI;
      THSRELEASELOCK("WLANTL_HSHandleRXFrame", &tlCtxt->hoSupport.hosLock);
      return status;
   }

   currentTimestamp = WDA_GET_RX_TIMESTAMP(pBDHeader);
   if((currentTimestamp - currentHO->sampleTime) < WLANTL_HO_SAMPLING_PERIOD)
   {
      THSRELEASELOCK("WLANTL_HSHandleRXFrame", &tlCtxt->hoSupport.hosLock);
      return status;
   }
   currentHO->sampleTime = currentTimestamp;

   /* Get Current RSSI from BD Heaser */
   status = WLANTL_HSGetRSSI(pAdapter, pBDHeader, STAid, &currentAvgRSSI);
   if(!VOS_IS_STATUS_SUCCESS(status))
   {
      TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Get RSSI Fail"));
      THSRELEASELOCK("WLANTL_HSHandleRXFrame", &tlCtxt->hoSupport.hosLock);
      return status;
   }
#ifdef WLAN_ACTIVEMODE_OFFLOAD_FEATURE
   if(!IS_ACTIVEMODE_OFFLOAD_FEATURE_ENABLE)
#endif
   {
      /* If any threshold is not registerd, DO NOTHING! */
      if(0 == tlCtxt->hoSupport.currentHOState.numThreshold)
      {
         TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"There is no thresholds pass"));
      }
      else
      {
         /* Handle current RSSI value, region, notification, etc */
         status = WLANTL_HSHandleRSSIChange(pAdapter, currentAvgRSSI);
         if(!VOS_IS_STATUS_SUCCESS(status))
         {
            TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Handle new RSSI fail"));
            THSRELEASELOCK("WLANTL_HSHandleRXFrame",
                                                  &tlCtxt->hoSupport.hosLock);
            return status;
         }
      }
   }

   THSRELEASELOCK("WLANTL_HSHandleRXFrame", &tlCtxt->hoSupport.hosLock);
   return status;
}

/*==========================================================================

   FUNCTION

   DESCRIPTION 
    
   PARAMETERS 

   RETURN VALUE

============================================================================*/
VOS_STATUS WLANTL_HSHandleTXFrame
(
   v_PVOID_t        pAdapter,
   v_U8_t           ac,
   v_U8_t           STAid,
   vos_pkt_t       *dataBuffer,
   v_PVOID_t        bdHeader
)
{
   WLANTL_CbType                  *tlCtxt = VOS_GET_TL_CB(pAdapter);
   VOS_STATUS                      status = VOS_STATUS_SUCCESS;

   if(NULL == tlCtxt)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Invalid TL handle"));
      return VOS_STATUS_E_INVAL;
   }

   /* Traffic status report is not registered, JUST DO NOTHING */
   if(0 == tlCtxt->hoSupport.currentTraffic.idleThreshold)
   {
      return VOS_STATUS_SUCCESS;
   }


   /* Only Voice traffic is handled as real time traffic */
   if(WLANTL_AC_VO == ac)
   {
      tlCtxt->hoSupport.currentTraffic.rtTXFrameCount++;
   }
   else
   {
      tlCtxt->hoSupport.currentTraffic.nrtTXFrameCount++;
   }
   TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"TX frame AC %d, RT Frame Count %d, NRT Frame Count %d",
                ac,
                tlCtxt->hoSupport.currentTraffic.rtTXFrameCount,
                tlCtxt->hoSupport.currentTraffic.nrtTXFrameCount));

   return status;
}

/*==========================================================================

   FUNCTION

   DESCRIPTION 
    
   PARAMETERS 

   RETURN VALUE

============================================================================*/
VOS_STATUS WLANTL_HSRegRSSIIndicationCB
(
   v_PVOID_t                       pAdapter,
   v_S7_t                          rssiValue,
   v_U8_t                          triggerEvent,
   WLANTL_RSSICrossThresholdCBType crossCBFunction,
   VOS_MODULE_ID                   moduleID,
   v_PVOID_t                       usrCtxt
)
{
   WLANTL_CbType                  *tlCtxt = VOS_GET_TL_CB(pAdapter);
   VOS_STATUS                      status = VOS_STATUS_SUCCESS;
   v_U8_t                          idx, sIdx;
   WLANTL_HO_SUPPORT_TYPE         *hoSupport;
   WLANTL_CURRENT_HO_STATE_TYPE   *currentHO;
   v_U8_t                          clientOrder = 0;

   if(NULL == tlCtxt)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Invalid TL handle"));
      return VOS_STATUS_E_INVAL;
   }

   if((-1 < rssiValue) || (NULL == crossCBFunction))
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Reg Invalid Argument"));
      return VOS_STATUS_E_INVAL;
   }

   THSGETLOCK("WLANTL_HSRegRSSIIndicationCB", &tlCtxt->hoSupport.hosLock);

   currentHO = &(tlCtxt->hoSupport.currentHOState);
   hoSupport = &(tlCtxt->hoSupport);
   TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Make Registration Module %d, Event %d, RSSI %d", moduleID, triggerEvent, rssiValue));

   if((WLANTL_MAX_AVAIL_THRESHOLD < currentHO->numThreshold) ||
      (WLANTL_MAX_AVAIL_THRESHOLD == currentHO->numThreshold))
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"No more available slot, please DEL first %d",
                    currentHO->numThreshold));
      THSRELEASELOCK("WLANTL_HSRegRSSIIndicationCB", &tlCtxt->hoSupport.hosLock);
      return VOS_STATUS_E_RESOURCES;
   }

   if(0 == currentHO->numThreshold)
   {
      TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"First Registration"));
      hoSupport->registeredInd[0].rssiValue    = rssiValue;
      hoSupport->registeredInd[0].triggerEvent[0]    = triggerEvent;
      hoSupport->registeredInd[0].crossCBFunction[0] = crossCBFunction;
      hoSupport->registeredInd[0].usrCtxt[0]         = usrCtxt;
      hoSupport->registeredInd[0].whoIsClient[0]     = moduleID;
      hoSupport->registeredInd[0].numClient++;
   }
   else
   {
      for(idx = 0; idx < currentHO->numThreshold; idx++)
      {
         if(rssiValue == hoSupport->registeredInd[idx].rssiValue)
         {
            for(sIdx = 0; sIdx < WLANTL_HS_NUM_CLIENT; sIdx++)
            {
               TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Reg CB P %pK, registered CB P %pK",
                             crossCBFunction,
                             hoSupport->registeredInd[idx].crossCBFunction[sIdx]));
               if(crossCBFunction == hoSupport->registeredInd[idx].crossCBFunction[sIdx])
               {
                  TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Same RSSI %d, Same CB %pK already registered",
                               rssiValue, crossCBFunction));
                  WLANTL_HSDebugDisplay(pAdapter);
                  THSRELEASELOCK("WLANTL_HSRegRSSIIndicationCB", &tlCtxt->hoSupport.hosLock);
                  return status;
               }
            }

            for(sIdx = 0; sIdx < WLANTL_HS_NUM_CLIENT; sIdx++)
            {
               if(NULL == hoSupport->registeredInd[idx].crossCBFunction[sIdx])
               {
                  clientOrder = sIdx;
                  break;
               }
            }
            hoSupport->registeredInd[idx].triggerEvent[clientOrder]    = triggerEvent;
            hoSupport->registeredInd[idx].crossCBFunction[clientOrder] = crossCBFunction;
            hoSupport->registeredInd[idx].usrCtxt[clientOrder]         = usrCtxt;
            hoSupport->registeredInd[idx].whoIsClient[clientOrder]     = moduleID;
            hoSupport->registeredInd[idx].numClient++;
            WLANTL_HSDebugDisplay(pAdapter);
            THSRELEASELOCK("WLANTL_HSRegRSSIIndicationCB", &tlCtxt->hoSupport.hosLock);
            return status;
         }
      }
      for(idx = 0; idx < currentHO->numThreshold; idx++)
      {
         if(rssiValue > hoSupport->registeredInd[idx].rssiValue)
         {
            for(sIdx = (currentHO->numThreshold - 1); (sIdx > idx) || (sIdx == idx); sIdx--)
            {
               TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO, "Shift %d array to %d", sIdx, sIdx + 1));
               vos_mem_copy(&hoSupport->registeredInd[sIdx + 1], &hoSupport->registeredInd[sIdx], sizeof(WLANTL_HO_RSSI_INDICATION_TYPE));
               memset(&hoSupport->registeredInd[sIdx], 0, sizeof(WLANTL_HO_RSSI_INDICATION_TYPE));
               if(0 == sIdx)
               {
                  break;
               }
            }
            TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Put in Here %d", idx));
            hoSupport->registeredInd[idx].rssiValue    = rssiValue;
            hoSupport->registeredInd[idx].triggerEvent[0]    = triggerEvent;
            hoSupport->registeredInd[idx].crossCBFunction[0] = crossCBFunction;
            hoSupport->registeredInd[idx].usrCtxt[0]         = usrCtxt;
            hoSupport->registeredInd[idx].whoIsClient[0]     = moduleID;
            hoSupport->registeredInd[idx].numClient++;
            break;
         }
      }
      if(currentHO->numThreshold == idx)
      {
         TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO, "New threshold put in bottom"));

         hoSupport->registeredInd[currentHO->numThreshold].rssiValue    = rssiValue;
         hoSupport->registeredInd[currentHO->numThreshold].triggerEvent[0] = triggerEvent;
         hoSupport->registeredInd[currentHO->numThreshold].crossCBFunction[0] = crossCBFunction;
         hoSupport->registeredInd[currentHO->numThreshold].usrCtxt[0] = usrCtxt;
         hoSupport->registeredInd[currentHO->numThreshold].whoIsClient[0]     = moduleID;
         hoSupport->registeredInd[currentHO->numThreshold].numClient++;
      }
   }

   currentHO->numThreshold++;
   if((VOS_FALSE == tlCtxt->isBMPS) && (rssiValue > currentHO->historyRSSI))
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Added Threshold above current RSSI level, old RN %d", currentHO->regionNumber));
      if(4 > currentHO->regionNumber)
      {
         currentHO->regionNumber++;
      }
      else
      {
         TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Current region number is max %d, cannot increase anymore", currentHO->regionNumber));
      }
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"increase region number without notification %d", currentHO->regionNumber));
   }
   else if(VOS_TRUE == tlCtxt->isBMPS)
   {
      if(0 != currentHO->regionNumber)
      {
         if(hoSupport->registeredInd[currentHO->regionNumber].rssiValue < rssiValue)
         {
            currentHO->regionNumber++;
            if((WLANTL_HO_THRESHOLD_DOWN == triggerEvent) || (WLANTL_HO_THRESHOLD_CROSS == triggerEvent))
            {
               TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Registered RSSI value larger than Current RSSI, and DOWN event, Send Notification"));
               WLANTL_HSSerializeTlIndication(pAdapter, WLANTL_HO_THRESHOLD_DOWN, usrCtxt, crossCBFunction,
                                              hoSupport->registeredInd[currentHO->regionNumber].rssiValue);
            }
         }
         else if((currentHO->regionNumber < (currentHO->numThreshold - 1)) &&
                 (hoSupport->registeredInd[currentHO->regionNumber + 1].rssiValue > rssiValue))
         {
            if((WLANTL_HO_THRESHOLD_UP == triggerEvent) || (WLANTL_HO_THRESHOLD_CROSS == triggerEvent))
            {
               TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Registered RSSI value smaller than Current RSSI"));
            }
         }
      }
      else
      {
         if(hoSupport->registeredInd[currentHO->regionNumber].rssiValue > rssiValue)
         {
            if((WLANTL_HO_THRESHOLD_UP == triggerEvent) || (WLANTL_HO_THRESHOLD_CROSS == triggerEvent))
            {
               TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Registered RSSI value smaller than Current RSSI"));
            }
         }
      }
   }

   if((VOS_FALSE == tlCtxt->isBMPS) &&
      (rssiValue >= currentHO->historyRSSI) && (0 != currentHO->historyRSSI) &&
      ((WLANTL_HO_THRESHOLD_DOWN == triggerEvent) || (WLANTL_HO_THRESHOLD_CROSS == triggerEvent)))
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Registered RSSI value larger than Current RSSI, and DOWN event, Send Notification"));
      WLANTL_HSSerializeTlIndication(pAdapter, WLANTL_HO_THRESHOLD_DOWN, usrCtxt, crossCBFunction, currentHO->historyRSSI);
   }
   else if((VOS_FALSE == tlCtxt->isBMPS) &&
           (rssiValue < currentHO->historyRSSI) && (0 != currentHO->historyRSSI) &&
           ((WLANTL_HO_THRESHOLD_UP == triggerEvent) || (WLANTL_HO_THRESHOLD_CROSS == triggerEvent)))
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Registered RSSI value smaller than Current RSSI, and UP event, Send Notification"));
      WLANTL_HSSerializeTlIndication(pAdapter, WLANTL_HO_THRESHOLD_UP, usrCtxt, crossCBFunction, currentHO->historyRSSI);
   }

   if((VOS_TRUE == tlCtxt->isBMPS) || (IS_ACTIVEMODE_OFFLOAD_FEATURE_ENABLE))
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Register into FW, now BMPS"));
      /* this function holds the lock across a downstream WDA function call, this is violates some lock
         ordering checks done on some HLOS see CR323221*/
      THSRELEASELOCK("WLANTL_HSRegRSSIIndicationCB", &tlCtxt->hoSupport.hosLock);
      WLANTL_SetFWRSSIThresholds(pAdapter);
      THSGETLOCK("WLANTL_HSRegRSSIIndicationCB", &tlCtxt->hoSupport.hosLock);
   }

   WLANTL_HSDebugDisplay(pAdapter);
   THSRELEASELOCK("WLANTL_HSRegRSSIIndicationCB", &tlCtxt->hoSupport.hosLock);
   return status;
}

/*==========================================================================

   FUNCTION

   DESCRIPTION 
    
   PARAMETERS 

   RETURN VALUE

============================================================================*/
VOS_STATUS WLANTL_HSDeregRSSIIndicationCB
(
   v_PVOID_t                       pAdapter,
   v_S7_t                          rssiValue,
   v_U8_t                          triggerEvent,
   WLANTL_RSSICrossThresholdCBType crossCBFunction,
   VOS_MODULE_ID                   moduleID
)
{
   WLANTL_CbType                  *tlCtxt = VOS_GET_TL_CB(pAdapter);
   VOS_STATUS                      status = VOS_STATUS_SUCCESS;
   v_U8_t                          idx, sIdx;
   WLANTL_HO_SUPPORT_TYPE         *hoSupport;
   WLANTL_CURRENT_HO_STATE_TYPE   *currentHO;
   v_BOOL_t                        bmpsAbove = VOS_FALSE;

   if(NULL == tlCtxt)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Invalid TL handle"));
      return VOS_STATUS_E_INVAL;
   }

   if(0 == tlCtxt->hoSupport.currentHOState.numThreshold)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Empty list, can not remove"));
      return VOS_STATUS_E_EMPTY;
   }

   THSGETLOCK("WLANTL_HSDeregRSSIIndicationCB", &tlCtxt->hoSupport.hosLock);
   currentHO = &(tlCtxt->hoSupport.currentHOState);
   hoSupport = &(tlCtxt->hoSupport);

   TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"DEL target RSSI %d, event %d", rssiValue, triggerEvent));

   if((VOS_TRUE == tlCtxt->isBMPS) && (0 < currentHO->regionNumber))
   {
      if(rssiValue >= hoSupport->registeredInd[currentHO->regionNumber - 1].rssiValue)
      {
         bmpsAbove = VOS_TRUE;
         TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Remove Threshold larger than current region"));
      }
   }

   for(idx = 0; idx < currentHO->numThreshold; idx++)
   {
      if(rssiValue == hoSupport->registeredInd[idx].rssiValue)
      {
         for(sIdx = 0; sIdx < WLANTL_HS_NUM_CLIENT; sIdx++)
         {
            if(crossCBFunction == tlCtxt->hoSupport.registeredInd[idx].crossCBFunction[sIdx])
            {
               tlCtxt->hoSupport.registeredInd[idx].triggerEvent[sIdx]    = 0;
               tlCtxt->hoSupport.registeredInd[idx].crossCBFunction[sIdx] = NULL;
               tlCtxt->hoSupport.registeredInd[idx].usrCtxt[sIdx]         = NULL;
               tlCtxt->hoSupport.registeredInd[idx].whoIsClient[sIdx]     = 0;
               tlCtxt->hoSupport.registeredInd[idx].numClient--;
            }
         }
         if(0 != tlCtxt->hoSupport.registeredInd[idx].numClient)
         {
            TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Found Multiple idx is %d", idx));
            WLANTL_HSDebugDisplay(pAdapter);
            THSRELEASELOCK("WLANTL_HSDeregRSSIIndicationCB", &tlCtxt->hoSupport.hosLock);
            return status;
         }
         else
         {
            TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Found Single idx is %d", idx));
            break;
         }
      }
   }
   if(idx == currentHO->numThreshold)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Could not find entry, maybe invalid arg"));
      THSRELEASELOCK("WLANTL_HSDeregRSSIIndicationCB", &tlCtxt->hoSupport.hosLock);
      return VOS_STATUS_E_INVAL;
   }

   for(idx = 0; idx < currentHO->numThreshold; idx++)
   {
      if(rssiValue == hoSupport->registeredInd[idx].rssiValue)
      {
         if((currentHO->numThreshold - 1) == idx)
         {
            TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Remove target is last one"));
            /* Does not need move any element, just remove last array entry */
         }
         else
         {
            for(sIdx = idx; sIdx < (currentHO->numThreshold - 1); sIdx++)
            {
               TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Shift up from %d to %d", sIdx + 1, sIdx));
               vos_mem_copy(&hoSupport->registeredInd[sIdx], &hoSupport->registeredInd[sIdx + 1], sizeof(WLANTL_HO_RSSI_INDICATION_TYPE));
            }
         }
         break;
      }
   }
   /* Common remove last array entry */
   tlCtxt->hoSupport.registeredInd[currentHO->numThreshold - 1].rssiValue    = WLANTL_HO_DEFAULT_RSSI;
   for(idx = 0; idx < WLANTL_HS_NUM_CLIENT; idx++)
   {
      tlCtxt->hoSupport.registeredInd[currentHO->numThreshold - 1].triggerEvent[idx]    = WLANTL_HO_THRESHOLD_NA;
      tlCtxt->hoSupport.registeredInd[currentHO->numThreshold - 1].crossCBFunction[idx] = NULL;
      tlCtxt->hoSupport.registeredInd[currentHO->numThreshold - 1].usrCtxt[idx]         = NULL;
      tlCtxt->hoSupport.registeredInd[currentHO->numThreshold - 1].whoIsClient[idx]     = 0;
      tlCtxt->hoSupport.registeredInd[currentHO->numThreshold - 1].numClient            = 0;
   }

   if( ((VOS_FALSE == tlCtxt->isBMPS) && (rssiValue >= currentHO->historyRSSI))
    || ((VOS_TRUE == tlCtxt->isBMPS) && (VOS_TRUE == bmpsAbove)) )
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,
                       "Removed Threshold above current RSSI level, old RN %d",
                                                      currentHO->regionNumber));
      if(0 < currentHO->regionNumber)
      {
         currentHO->regionNumber--;
      }
      else
      {
          TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
                        "Current Region number is 0, cannot decrease anymore"));
      }
      TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,
                       "Decrease region number without notification %d",
                                                      currentHO->regionNumber));
   }

   /* Decrease number of thresholds */
   tlCtxt->hoSupport.currentHOState.numThreshold--;
   /*Reset the FW notification*/
   tlCtxt->hoSupport.currentHOState.fwNotification=0;

   if((VOS_TRUE == tlCtxt->isBMPS) || (IS_ACTIVEMODE_OFFLOAD_FEATURE_ENABLE))
   {
      TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Register into FW, now BMPS"));
       /* this function holds the lock across a downstream WDA function call, this is violates some lock
         ordering checks done on some HLOS see CR323221*/
      THSRELEASELOCK("WLANTL_HSDeregRSSIIndicationCB", &tlCtxt->hoSupport.hosLock);
      WLANTL_SetFWRSSIThresholds(pAdapter); 
      THSGETLOCK("WLANTL_HSDeregRSSIIndicationCB", &tlCtxt->hoSupport.hosLock);
   }

   /* Based on new threshold set recalculated current RSSI status */
   if(0 < tlCtxt->hoSupport.currentHOState.numThreshold)
   {
   }
   else if(0 == tlCtxt->hoSupport.currentHOState.numThreshold)
   {
      currentHO->regionNumber = 0;
      TLLOGW(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_WARN,"No registered Threshold"));
      /* What should do? */
   }

   WLANTL_HSDebugDisplay(pAdapter);
   THSRELEASELOCK("WLANTL_HSDeregRSSIIndicationCB", &tlCtxt->hoSupport.hosLock);
   return status;
}

/*==========================================================================

   FUNCTION

   DESCRIPTION 
    
   PARAMETERS 

   RETURN VALUE

============================================================================*/
VOS_STATUS WLANTL_HSSetAlpha
(
   v_PVOID_t pAdapter,
   int       valueAlpha
)
{
   WLANTL_CbType   *tlCtxt = VOS_GET_TL_CB(pAdapter);
   VOS_STATUS       status = VOS_STATUS_SUCCESS;

   if(NULL == tlCtxt)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Invalid TL handle"));
      return VOS_STATUS_E_INVAL;
   }

   THSGETLOCK("WLANTL_HSSetAlpha", &tlCtxt->hoSupport.hosLock);
   tlCtxt->hoSupport.currentHOState.alpha = (v_U8_t)valueAlpha;
   THSRELEASELOCK("WLANTL_HSSetAlpha", &tlCtxt->hoSupport.hosLock);
   return status;
}

/*==========================================================================

   FUNCTION

   DESCRIPTION 
    
   PARAMETERS 

   RETURN VALUE

============================================================================*/
VOS_STATUS WLANTL_HSRegGetTrafficStatus
(
   v_PVOID_t                          pAdapter,
   v_U32_t                            idleThreshold,
   v_U32_t                            period,
   WLANTL_TrafficStatusChangedCBType  trfficStatusCB,
   v_PVOID_t                          usrCtxt
)
{
   WLANTL_CbType   *tlCtxt = VOS_GET_TL_CB(pAdapter);
   VOS_STATUS       status = VOS_STATUS_SUCCESS;

   if(NULL == tlCtxt)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Invalid TL handle"));
      return VOS_STATUS_E_INVAL;
   }

   if((0 == idleThreshold) || (0 == period) || (NULL == trfficStatusCB))
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Invalid Argument Passed from SME"));
      return VOS_STATUS_E_INVAL;
   }

   tlCtxt->hoSupport.currentTraffic.idleThreshold = idleThreshold;
   tlCtxt->hoSupport.currentTraffic.measurePeriod = period;
   tlCtxt->hoSupport.currentTraffic.trafficCB     = trfficStatusCB;
   tlCtxt->hoSupport.currentTraffic.usrCtxt       = usrCtxt;

   vos_timer_start(&tlCtxt->hoSupport.currentTraffic.trafficTimer,
                   tlCtxt->hoSupport.currentTraffic.measurePeriod);

   return status;
}

/*==========================================================================

   FUNCTION

   DESCRIPTION 
    
   PARAMETERS 

   RETURN VALUE

============================================================================*/
VOS_STATUS WLANTL_HSInit
(
   v_PVOID_t   pAdapter
)
{
   WLANTL_CbType   *tlCtxt = VOS_GET_TL_CB(pAdapter);
   VOS_STATUS       status = VOS_STATUS_SUCCESS;
   v_U8_t           idx, sIdx;

   if(NULL == tlCtxt)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Invalid TL handle"));
      return VOS_STATUS_E_INVAL;
   }
#ifdef WLANTL_HO_UTEST
   rssi = 0;
   direction = -1;
#endif /* WLANTL_HO_UTEST */

   /* set default current HO status */
   tlCtxt->hoSupport.currentHOState.alpha        = WLANTL_HO_DEFAULT_ALPHA;
   tlCtxt->hoSupport.currentHOState.historyRSSI  = 0;
   tlCtxt->hoSupport.currentHOState.numThreshold = 0;
   tlCtxt->hoSupport.currentHOState.regionNumber = 0;
   tlCtxt->hoSupport.currentHOState.sampleTime   = 0;

   /* set default current traffic status */
   tlCtxt->hoSupport.currentTraffic.trafficStatus.rtTrafficStatus
                                                    = WLANTL_HO_RT_TRAFFIC_STATUS_OFF;
   tlCtxt->hoSupport.currentTraffic.trafficStatus.nrtTrafficStatus
                                                    = WLANTL_HO_NRT_TRAFFIC_STATUS_OFF;
   tlCtxt->hoSupport.currentTraffic.idleThreshold   = 0;
   tlCtxt->hoSupport.currentTraffic.measurePeriod   = 0;
   tlCtxt->hoSupport.currentTraffic.rtRXFrameCount  = 0;
   tlCtxt->hoSupport.currentTraffic.rtTXFrameCount  = 0;
   tlCtxt->hoSupport.currentTraffic.nrtRXFrameCount = 0;
   tlCtxt->hoSupport.currentTraffic.nrtTXFrameCount = 0;
   tlCtxt->hoSupport.currentTraffic.trafficCB       = NULL;

   /* Initialize indication array */
   for(idx = 0; idx < WLANTL_MAX_AVAIL_THRESHOLD; idx++)
   {
      for(sIdx = 0; sIdx < WLANTL_HS_NUM_CLIENT; sIdx++)
      {
         tlCtxt->hoSupport.registeredInd[idx].triggerEvent[sIdx]    = WLANTL_HO_THRESHOLD_NA;
         tlCtxt->hoSupport.registeredInd[idx].crossCBFunction[sIdx] = NULL;
         tlCtxt->hoSupport.registeredInd[idx].usrCtxt[sIdx]         = NULL;
         tlCtxt->hoSupport.registeredInd[idx].whoIsClient[sIdx]     = 0;
      }
      tlCtxt->hoSupport.registeredInd[idx].rssiValue          = WLANTL_HO_DEFAULT_RSSI;
      tlCtxt->hoSupport.registeredInd[idx].numClient          = 0;
   }

   vos_timer_init(&tlCtxt->hoSupport.currentTraffic.trafficTimer,
                  VOS_TIMER_TYPE_SW,
                  WLANTL_HSTrafficStatusTimerExpired,
                  pAdapter);


   vos_lock_init(&tlCtxt->hoSupport.hosLock);
   tlCtxt->hoSupport.macCtxt = vos_get_context(VOS_MODULE_ID_SME, pAdapter);

   return status;
}


/*==========================================================================

   FUNCTION    WLANTL_HSDeInit

   DESCRIPTION 
    
   PARAMETERS 

   RETURN VALUE

============================================================================*/

VOS_STATUS WLANTL_HSDeInit
(
   v_PVOID_t   pAdapter
)
{
   WLANTL_CbType   *tlCtxt = VOS_GET_TL_CB(pAdapter);
   VOS_STATUS       status = VOS_STATUS_SUCCESS;

   if(NULL == tlCtxt)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Invalid TL handle"));
      return VOS_STATUS_E_INVAL;
   }

   // Destroy the timer...      
   status = vos_timer_destroy( &tlCtxt->hoSupport.currentTraffic.trafficTimer );
   if ( !VOS_IS_STATUS_SUCCESS( status ) )
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"WLANTL_HSStop: Timer Destroy Fail Status %d", status));
   }
   return status;   
}


/*==========================================================================

   FUNCTION

   DESCRIPTION 
    
   PARAMETERS 

   RETURN VALUE

============================================================================*/
VOS_STATUS WLANTL_HSStop
(
   v_PVOID_t   pAdapter
)
{
   WLANTL_CbType   *tlCtxt = VOS_GET_TL_CB(pAdapter);
   VOS_STATUS       status = VOS_STATUS_SUCCESS;
   VOS_TIMER_STATE  timerState;

   if(NULL == tlCtxt)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Invalid TL handle"));
      return VOS_STATUS_E_INVAL;
   }

   timerState = vos_timer_getCurrentState(&tlCtxt->hoSupport.currentTraffic.trafficTimer);
   if(VOS_TIMER_STATE_RUNNING == timerState)
   {
      TLLOG1(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO,"Stop Traffic status monitoring timer"));
      status = vos_timer_stop(&tlCtxt->hoSupport.currentTraffic.trafficTimer);
   }
   if(VOS_STATUS_SUCCESS != status)
   {
      TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,"Timer Stop Failed, Status %d", status));
   }

   //Deregister the traffic Status
   tlCtxt->hoSupport.currentTraffic.idleThreshold = 0;
   tlCtxt->hoSupport.currentTraffic.measurePeriod = 0;
   tlCtxt->hoSupport.currentTraffic.trafficCB     = NULL;
   tlCtxt->hoSupport.currentTraffic.usrCtxt       = NULL;

   return status;   
}

/*==========================================================================

   FUNCTION

   DESCRIPTION 
    
   PARAMETERS 

   RETURN VALUE

============================================================================*/
VOS_STATUS WLANTL_HSSerializeTlIndication
(
   v_PVOID_t   pAdapter,
   v_U8_t      rssiNotification,
   v_PVOID_t   pUserCtxt,
   WLANTL_RSSICrossThresholdCBType cbFunction,
   v_U8_t      avgRssi
)
{
   VOS_STATUS       status = VOS_STATUS_SUCCESS;
   vos_msg_t        msg;
   WLANTL_TlIndicationReq *pMsg;

   pMsg = vos_mem_malloc(sizeof(WLANTL_TlIndicationReq));
   if ( NULL == pMsg ) 
   {
      VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, "In %s, failed to allocate mem for req", __func__);
      return VOS_STATUS_E_NOMEM;
   }

   pMsg->msgType = pal_cpu_to_be16((tANI_U16)eWNI_SME_RSSI_IND);
   pMsg->msgLen = (tANI_U16)sizeof(WLANTL_TlIndicationReq);
   pMsg->sessionId = 0;//for now just pass 0
   pMsg->pAdapter = pAdapter;
   pMsg->pUserCtxt = pUserCtxt;
   pMsg->rssiNotification = rssiNotification;
   pMsg->avgRssi = avgRssi;
   pMsg->tlCallback = cbFunction;


   msg.type = eWNI_SME_RSSI_IND;
   msg.bodyptr = pMsg;
   msg.reserved = 0;

   if(VOS_STATUS_SUCCESS != vos_mq_post_message(VOS_MQ_ID_SME, &msg))
   {
       VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR, "In %s, failed to post msg to self", __func__);
       vos_mem_free(pMsg);
       status = VOS_STATUS_E_FAILURE;
   }

   return status;   
}

#endif //WLAN_FEATURE_NEIGHBOR_ROAMING
