wlan: Link Layer Stats, implementation of interface Tx/Rx statistics

LLstats Implementation for Tx/Rx statistics

Change-Id: Id31c228b7e524b05a5509584b5e047c59c02303c
diff --git a/CORE/HDD/inc/wlan_hdd_main.h b/CORE/HDD/inc/wlan_hdd_main.h
index 1b9b5ad..8295885 100644
--- a/CORE/HDD/inc/wlan_hdd_main.h
+++ b/CORE/HDD/inc/wlan_hdd_main.h
@@ -325,6 +325,9 @@
    __u32    rxRefused;
    __u32    pkt_tx_count; //TX pkt Counter used for dynamic splitscan
    __u32    pkt_rx_count; //RX pkt Counter used for dynamic splitscan
+#ifdef WLAN_FEATURE_LINK_LAYER_STATS
+   __u32    txMcast[WIFI_AC_MAX];
+#endif
    // tx timeout stats
    __u32    txTimeoutCount;
    __u32    continuousTxTimeoutCount;
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index 0ddc72f..ac89e87 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -823,11 +823,15 @@
     return TRUE;
 }
 
-static v_BOOL_t put_wifi_iface_stats(tpSirWifiIfaceStat pWifiIfaceStat,
+static v_BOOL_t put_wifi_iface_stats(hdd_adapter_t *pAdapter,
+                            tpSirWifiIfaceStat pWifiIfaceStat,
                                  struct sk_buff *vendor_event)
 {
     int i = 0;
     struct nlattr *wmmInfo;
+    hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
+    WLANTL_InterfaceStatsType *pWifiIfaceStatTL = NULL;
+
     if (FALSE == put_wifi_interface_info(
                                 &pWifiIfaceStat->info,
                                 vendor_event))
@@ -837,6 +841,80 @@
         return FALSE;
 
     }
+    pWifiIfaceStatTL = (WLANTL_InterfaceStatsType *)
+                             vos_mem_malloc(sizeof(WLANTL_InterfaceStatsType));
+    if (NULL == pWifiIfaceStatTL)
+    {
+        hddLog(VOS_TRACE_LEVEL_ERROR, FL("vos_mem_malloc failed"));
+        return FALSE;
+    }
+
+
+    if ( pWifiIfaceStat->info.state == WIFI_ASSOCIATED)
+    {
+        if (VOS_STATUS_SUCCESS ==
+         WLANTL_CollectInterfaceStats((WLAN_HDD_GET_CTX(pAdapter))->pvosContext,
+                    pHddStaCtx->conn_info.staId[0], pWifiIfaceStatTL))
+        {
+            /* mgmtRx, MgmtActionRx, rxMcast, rxMpdu, rxAmpdu, rssiData are
+             * obtained from TL structure
+             */
+
+            pWifiIfaceStat->mgmtRx = pWifiIfaceStat->beaconRx +
+                pWifiIfaceStatTL->mgmtRx;
+            pWifiIfaceStat->mgmtActionRx = pWifiIfaceStatTL->mgmtActionRx;
+            pWifiIfaceStat->mgmtActionTx = pWifiIfaceStatTL->mgmtActionTx;
+            pWifiIfaceStat->rssiData = pWifiIfaceStatTL->rssiData;
+
+            vos_mem_copy(
+                  (void *) &pWifiIfaceStat->AccessclassStats[WIFI_AC_VO],
+                  (void *) &pWifiIfaceStatTL->accessCategoryStats[WLANTL_AC_VO],
+                  sizeof(WLANTL_AccessCategoryStatsType));
+
+            vos_mem_copy(
+                  (void *) &pWifiIfaceStat->AccessclassStats[WIFI_AC_VI],
+                  (void *) &pWifiIfaceStatTL->accessCategoryStats[WLANTL_AC_VI],
+                  sizeof(WLANTL_AccessCategoryStatsType));
+
+            vos_mem_copy(
+                  (void *) &pWifiIfaceStat->AccessclassStats[WIFI_AC_BE],
+                  (void *) &pWifiIfaceStatTL->accessCategoryStats[WLANTL_AC_BE],
+                  sizeof(WLANTL_AccessCategoryStatsType));
+
+            vos_mem_copy(
+                  (void *) &pWifiIfaceStat->AccessclassStats[WIFI_AC_BK],
+                  (void *) &pWifiIfaceStatTL->accessCategoryStats[WLANTL_AC_BK],
+                  sizeof(WLANTL_AccessCategoryStatsType));
+        }
+        else
+        {
+            hddLog(VOS_TRACE_LEVEL_ERROR, FL("Error in getting stats from TL"));
+        }
+
+        pWifiIfaceStat->AccessclassStats[WIFI_AC_VO].txMpdu =
+            pAdapter->hdd_stats.hddTxRxStats.txFetchedAC[WLANTL_AC_VO];
+        pWifiIfaceStat->AccessclassStats[WIFI_AC_VI].txMpdu =
+            pAdapter->hdd_stats.hddTxRxStats.txFetchedAC[WLANTL_AC_VI];
+        pWifiIfaceStat->AccessclassStats[WIFI_AC_BE].txMpdu =
+            pAdapter->hdd_stats.hddTxRxStats.txFetchedAC[WLANTL_AC_BE];
+        pWifiIfaceStat->AccessclassStats[WIFI_AC_BK].txMpdu =
+            pAdapter->hdd_stats.hddTxRxStats.txFetchedAC[WLANTL_AC_BK];
+
+        pWifiIfaceStat->AccessclassStats[WIFI_AC_VO].txMcast =
+            pAdapter->hdd_stats.hddTxRxStats.txMcast[WLANTL_AC_VO];
+        pWifiIfaceStat->AccessclassStats[WIFI_AC_VI].txMcast =
+            pAdapter->hdd_stats.hddTxRxStats.txMcast[WLANTL_AC_VI];
+        pWifiIfaceStat->AccessclassStats[WIFI_AC_BE].txMcast =
+            pAdapter->hdd_stats.hddTxRxStats.txMcast[WLANTL_AC_BE];
+        pWifiIfaceStat->AccessclassStats[WIFI_AC_BK].txMcast =
+            pAdapter->hdd_stats.hddTxRxStats.txMcast[WLANTL_AC_BK];
+    }
+    else
+    {
+        hddLog(VOS_TRACE_LEVEL_INFO, FL("Interface not Associated"));
+    }
+
+
 
     if (nla_put_u32(vendor_event,
                     QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX,
@@ -850,18 +928,19 @@
         nla_put_u32(vendor_event,
                     QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX,
                     pWifiIfaceStat->mgmtActionTx) ||
-        nla_put_u32(vendor_event,
+        nla_put_s32(vendor_event,
                     QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT,
                     pWifiIfaceStat->rssiMgmt) ||
-        nla_put_u32(vendor_event,
+        nla_put_s32(vendor_event,
                     QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA,
                     pWifiIfaceStat->rssiData) ||
-        nla_put_u32(vendor_event,
+        nla_put_s32(vendor_event,
                     QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK,
                     pWifiIfaceStat->rssiAck))
     {
         hddLog(VOS_TRACE_LEVEL_ERROR,
                 FL("QCA_WLAN_VENDOR_ATTR put fail"));
+        vos_mem_free(pWifiIfaceStatTL);
         return FALSE;
     }
 
@@ -877,12 +956,14 @@
         {
             hddLog(VOS_TRACE_LEVEL_ERROR,
                     FL("QCA_WLAN_VENDOR_ATTR put Fail"));
+            vos_mem_free(pWifiIfaceStatTL);
             return FALSE;
         }
 
         nla_nest_end(vendor_event, wmmStats);
     }
     nla_nest_end(vendor_event, wmmInfo);
+    vos_mem_free(pWifiIfaceStatTL);
     return TRUE;
 }
 
@@ -1153,6 +1234,25 @@
 
     pWifiIfaceStat = (tpSirWifiIfaceStat) pData;
 
+
+    if (FALSE == hdd_get_interface_info( pAdapter,
+                                        &pWifiIfaceStat->info))
+    {
+        hddLog(VOS_TRACE_LEVEL_ERROR,
+               FL("hdd_get_interface_info get fail") );
+        kfree_skb(vendor_event);
+        return;
+    }
+
+    if (FALSE == put_wifi_iface_stats( pAdapter, pWifiIfaceStat,
+                                       vendor_event))
+    {
+        hddLog(VOS_TRACE_LEVEL_ERROR,
+               FL("put_wifi_iface_stats fail") );
+        kfree_skb(vendor_event);
+        return;
+    }
+
     hddLog(VOS_TRACE_LEVEL_INFO,
            "WMI_LINK_STATS_IFACE Data");
 
@@ -1191,9 +1291,9 @@
            " mgmtRx %u "
            " mgmtActionRx  %u "
            " mgmtActionTx %u "
-           " rssiMgmt %u "
-           " rssiData %u "
-           " rssiAck  %u",
+           " rssiMgmt %d "
+           " rssiData %d "
+           " rssiAck  %d",
            pWifiIfaceStat->beaconRx,
            pWifiIfaceStat->mgmtRx,
            pWifiIfaceStat->mgmtActionRx,
@@ -1243,23 +1343,6 @@
         }
     }
 
-    if (FALSE == hdd_get_interface_info( pAdapter,
-                                        &pWifiIfaceStat->info))
-    {
-        hddLog(VOS_TRACE_LEVEL_ERROR,
-               FL("hdd_get_interface_info get fail") );
-        kfree_skb(vendor_event);
-        return;
-    }
-
-    if (FALSE == put_wifi_iface_stats( pWifiIfaceStat,
-                                       vendor_event))
-    {
-        hddLog(VOS_TRACE_LEVEL_ERROR,
-               FL("put_wifi_iface_stats fail") );
-        kfree_skb(vendor_event);
-        return;
-    }
     cfg80211_vendor_event(vendor_event, GFP_KERNEL);
 }
 
diff --git a/CORE/HDD/src/wlan_hdd_tx_rx.c b/CORE/HDD/src/wlan_hdd_tx_rx.c
index a658447..b3a3ad2 100644
--- a/CORE/HDD/src/wlan_hdd_tx_rx.c
+++ b/CORE/HDD/src/wlan_hdd_tx_rx.c
@@ -1530,6 +1530,20 @@
       return VOS_STATUS_E_FAILURE;
    }
 
+#ifdef WLAN_FEATURE_LINK_LAYER_STATS
+   {
+       v_MACADDR_t *pDestMacAddress = (v_MACADDR_t*)skb->data;
+       /* vos_is_macaddr_group expects data in v_MACADDR_t format
+        */
+       if (vos_is_macaddr_group(pDestMacAddress))
+       {
+            pAdapter->hdd_stats.hddTxRxStats.txMcast[ac]++;
+       }
+
+   }
+
+#endif
+
 #ifdef FEATURE_WLAN_TDLS
     if (eTDLS_SUPPORT_ENABLED == pHddCtx->tdls_mode)
     {
diff --git a/CORE/MAC/inc/sirApi.h b/CORE/MAC/inc/sirApi.h
index 0e0ee1a..2187b75 100644
--- a/CORE/MAC/inc/sirApi.h
+++ b/CORE/MAC/inc/sirApi.h
@@ -5103,11 +5103,11 @@
     // action frames transmit count
     tANI_U32            mgmtActionTx;
     // access Point Beacon and Management frames RSSI (averaged)
-    tANI_U32            rssiMgmt;
+    tANI_S32            rssiMgmt;
     // access Point Data Frames RSSI (averaged) from connected AP
-    tANI_U32            rssiData;
+    tANI_S32            rssiData;
     // access Point ACK RSSI (averaged) from connected AP
-    tANI_U32            rssiAck;
+    tANI_S32            rssiAck;
     // per ac data packet statistics
     tSirWifiWmmAcStat    AccessclassStats[WIFI_AC_MAX];
 } tSirWifiIfaceStat, *tpSirWifiIfaceStat;
diff --git a/CORE/TL/inc/wlan_qct_tl.h b/CORE/TL/inc/wlan_qct_tl.h
index 5aedc81..8b268da 100644
--- a/CORE/TL/inc/wlan_qct_tl.h
+++ b/CORE/TL/inc/wlan_qct_tl.h
@@ -429,6 +429,91 @@
  #endif
 }WLANTL_RxMetaInfoType;
 
+#ifdef WLAN_FEATURE_LINK_LAYER_STATS
+/* per interface per access category statistics */
+typedef PACKED_PRE struct PACKED_POST
+{
+  /* access category (VI, VO, BE, BK) */
+  v_U8_t            ac;
+
+  /*Number of successfully transmitted unicast data pkts (ACK rcvd) */
+  v_U32_t           txMpdu;
+
+  /* number of received unicast mpdu */
+  v_U32_t           rxMpdu;
+
+ /* umber of succesfully transmitted multicast data packets
+  * STA case: implies ACK received from AP for the unicast packet in which mcast
+  * pkt was sent
+  */
+  v_U32_t           txMcast;
+
+  /* number of received multicast data packets */
+  v_U32_t           rxMcast;
+
+  /* number of received unicast a-mpdu */
+  v_U32_t           rxAmpdu;
+
+  /* number of transmitted unicast a-mpdus */
+  v_U32_t           txAmpdu;
+
+  /* number of data pkt losses (no ACK) */
+  v_U32_t           mpduLost;
+
+  /* total number of data pkt retries */
+  v_U32_t           retries;
+
+  /* number of short data pkt retries */
+  v_U32_t           retriesShort;
+
+  /* number of long data pkt retries */
+  v_U32_t           retriesLong;
+
+  /* data pkt min contention time (usecs) */
+  v_U32_t           contentionTimeMin;
+
+  /* data pkt max contention time (usecs) */
+  v_U32_t           contentionTimeMax;
+
+  /* data pkt avg contention time (usecs) */
+  v_U32_t           contentionTimeAvg;
+
+  /* num of data pkts used for contention statistics */
+  v_U32_t           contentionNumSamples;
+}WLANTL_AccessCategoryStatsType;
+
+/* per interface statistics */
+typedef PACKED_PRE struct PACKED_POST
+{
+  /* access point beacon received count from connected AP */
+  v_U32_t               beaconRx;
+
+  /* access point mgmt frames received count from connected AP (including
+   * Beacon)
+   */
+  v_U32_t               mgmtRx;
+
+  /* action frames received count */
+  v_U32_t               mgmtActionRx;
+
+  /* action frames transmit count */
+  v_U32_t               mgmtActionTx;
+
+  /* access Point Beacon and Management frames RSSI (averaged) */
+  v_U32_t               rssiMgmt;
+
+  /* access Point Data Frames RSSI (averaged) from connected AP */
+  v_U32_t               rssiData;
+
+  /* access Point ACK RSSI (averaged) from connected AP */
+  v_U32_t               rssiAck;
+
+  WLANTL_AccessCategoryStatsType    accessCategoryStats[WLANTL_MAX_AC];
+
+}WLANTL_InterfaceStatsType;
+
+
+#endif
 
 /*---------------------------------------------------------------------------
   Handoff support and statistics defines and enum types
@@ -1086,6 +1171,44 @@
   v_U8_t           ucSTAId 
 );
 
+#ifdef WLAN_FEATURE_LINK_LAYER_STATS
+/*==========================================================================
+
+  FUNCTION    WLANTL_CollectStats
+
+  DESCRIPTION
+    Utility function used by TL to send the statitics
+
+  DEPENDENCIES
+
+
+  PARAMETERS
+
+    IN
+
+    ucSTAId:    station for which the statistics need to collected
+
+    vosDataBuff: it will contain the pointer to the corresponding
+                structure
+
+  RETURN VALUE
+    The result code associated with performing the operation
+
+    VOS_STATUS_E_INVAL:   Input parameters are invalid
+    VOS_STATUS_SUCCESS:   Everything is good :)
+
+  SIDE EFFECTS
+
+============================================================================*/
+VOS_STATUS
+WLANTL_CollectInterfaceStats
+(
+  v_PVOID_t       pvosGCtx,
+  v_U8_t          ucSTAId,
+  WLANTL_InterfaceStatsType  *vosDataBuff
+);
+#endif
+
 /*===========================================================================
 
   FUNCTION    WLANTL_ChangeSTAState
diff --git a/CORE/TL/src/wlan_qct_tl.c b/CORE/TL/src/wlan_qct_tl.c
index a8e8d4f..165416c 100644
--- a/CORE/TL/src/wlan_qct_tl.c
+++ b/CORE/TL/src/wlan_qct_tl.c
@@ -170,6 +170,11 @@
 /*BT-AMP packet LLC OUI value*/
 const v_U8_t WLANTL_BT_AMP_OUI[] =  {0x00, 0x19, 0x58 };
 
+#ifdef WLAN_FEATURE_LINK_LAYER_STATS
+extern const v_U8_t  WLANTL_TID_2_AC[WLAN_MAX_TID];
+
+#endif
+
 #define WLANTL_MAX_SNR_DATA_SAMPLES 20
 
 #ifdef VOLANS_PERF
@@ -194,6 +199,11 @@
 #define WLANTL_IS_MGMT_FRAME(_type_sub)                                     \
                      ( WLANTL_MGMT_FRAME_TYPE == ( (_type_sub) & 0x30 ))
 
+#define WLANTL_IS_MGMT_ACTION_FRAME(_type_sub)                                \
+    (( WLANTL_MGMT_FRAME_TYPE == ( (_type_sub) & 0x30 )) &&    \
+     ( ( WLANTL_80211_MGMT_ACTION_SUBTYPE == ( (_type_sub) & 0xF )) || \
+       ( WLANTL_80211_MGMT_ACTION_NO_ACK_SUBTYPE == ( (_type_sub) & 0xF ))))
+
 #define WLANTL_IS_CTRL_FRAME(_type_sub)                                     \
                      ( WLANTL_CTRL_FRAME_TYPE == ( (_type_sub) & 0x30 ))
 
@@ -1387,6 +1397,13 @@
 #else
     pClientSTA->rssiAlpha = WLANTL_HO_DEFAULT_ALPHA;
 #endif /* FEATURE_WLAN_TDLS */
+#ifdef WLAN_FEATURE_LINK_LAYER_STATS
+  pClientSTA->rssiDataAlpha = WLANTL_HO_DEFAULT_ALPHA;
+  pClientSTA->interfaceStats.accessCategoryStats[0].ac = WLANTL_AC_BK;
+  pClientSTA->interfaceStats.accessCategoryStats[1].ac = WLANTL_AC_BE;
+  pClientSTA->interfaceStats.accessCategoryStats[2].ac = WLANTL_AC_VI;
+  pClientSTA->interfaceStats.accessCategoryStats[3].ac = WLANTL_AC_VO;
+#endif
 
   /*Tx not suspended and station fully registered*/
   vos_atomic_set_U8(
@@ -5552,6 +5569,11 @@
   v_U16_t             usEtherType = 0;
 #endif
   v_BOOL_t            bForwardIAPPwithLLC = VOS_FALSE;
+#ifdef WLAN_FEATURE_LINK_LAYER_STATS
+  v_S7_t              currentAvgRSSI = 0;
+  v_U8_t              ac;
+
+#endif
 
   /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
 
@@ -5716,6 +5738,18 @@
           TLLOGW(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_WARN,
                             FL("Failed to Read SNR")));
         }
+#ifdef WLAN_FEATURE_LINK_LAYER_STATS
+        pClientSTA = pTLCb->atlSTAClients[ucSTAId];
+        if ( NULL != pClientSTA)
+        {
+            pClientSTA->interfaceStats.mgmtRx++;
+            if (WLANTL_IS_MGMT_ACTION_FRAME(ucFrmType))
+            {
+                pClientSTA->interfaceStats.mgmtActionRx++;
+
+            }
+        }
+#endif
       }
 
       pTLCb->tlMgmtFrmClient.pfnTlMgmtFrmRx( pvosGCtx, vosTempBuff); 
@@ -5724,6 +5758,9 @@
     {
       ucSTAId = (v_U8_t)WDA_GET_RX_STAID( pvBDHeader );
       ucTid   = (v_U8_t)WDA_GET_RX_TID( pvBDHeader );
+#ifdef WLAN_FEATURE_LINK_LAYER_STATS
+      ac = WLANTL_TID_2_AC[ucTid];
+#endif
 
       TLLOG2(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_HIGH,
                  "WLAN TL:Data packet received for STA %d", ucSTAId));
@@ -5737,7 +5774,6 @@
         TLLOG2(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_INFO_HIGH,
         "WLAN TL:TL rx Bcast frame - sending to last registered station"));
         broadcast = VOS_TRUE;
-        
         /*-------------------------------------------------------------------
           If Addr1 is b/mcast, but Addr3 is our own self MAC, it is a b/mcast
           pkt we sent  looping back to us. To be dropped if we are non BTAMP  
@@ -5958,6 +5994,29 @@
            * continue;
            */
         }
+#ifdef WLAN_FEATURE_LINK_LAYER_STATS
+        pClientSTA = pTLCb->atlSTAClients[ucSTAId];
+        if ( NULL != pClientSTA)
+        {
+            tpSirMacMgmtHdr pMacHeader = WDA_GET_RX_MAC_HEADER( pvBDHeader );
+            if( !WDA_IS_RX_BCAST(pvBDHeader) && ( pMacHeader->da[0] & 0x1))
+            {
+                pClientSTA->interfaceStats.accessCategoryStats[ac].rxMcast++;
+            }
+
+            WLANTL_HSGetDataRSSI(pvosGCtx, pvBDHeader, ucSTAId,
+                    &currentAvgRSSI);
+            pClientSTA->interfaceStats.rssiData = currentAvgRSSI;
+
+            pClientSTA->interfaceStats.accessCategoryStats[ac].rxMpdu++;
+            if (WDA_IS_RX_AN_AMPDU (pvBDHeader))
+            {
+                pClientSTA->interfaceStats.accessCategoryStats[ac].rxAmpdu++;
+            }
+        }
+
+
+#endif
         vosStatus = WLANTL_ReadSNR(pvosGCtx, pvBDHeader, ucSTAId);
 
         if (!VOS_IS_STATUS_SUCCESS(vosStatus))
@@ -5986,6 +6045,76 @@
   return VOS_STATUS_SUCCESS;
 }/* WLANTL_RxFrames */
 
+#ifdef WLAN_FEATURE_LINK_LAYER_STATS
+/*==========================================================================
+
+  FUNCTION    WLANTL_CollectInterfaceStats
+
+  DESCRIPTION
+    Utility function used by TL to send the statitics
+
+  DEPENDENCIES
+
+
+  PARAMETERS
+
+    IN
+
+    ucSTAId:    station for which the statistics need to collected
+
+    vosDataBuff: it will contain the pointer to the corresponding
+                structure
+
+  RETURN VALUE
+    The result code associated with performing the operation
+
+    VOS_STATUS_E_INVAL:   Input parameters are invalid
+    VOS_STATUS_SUCCESS:   Everything is good :)
+
+  SIDE EFFECTS
+
+============================================================================*/
+VOS_STATUS
+WLANTL_CollectInterfaceStats
+(
+  v_PVOID_t       pvosGCtx,
+  v_U8_t          ucSTAId,
+  WLANTL_InterfaceStatsType    *vosDataBuff
+)
+{
+  WLANTL_CbType*  pTLCb = NULL;
+  /*------------------------------------------------------------------------
+    Sanity check
+   ------------------------------------------------------------------------*/
+  if ( WLANTL_STA_ID_INVALID( ucSTAId ) )
+  {
+    TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+           "WLAN TL:Invalid station id requested on WLANTL_CollectStats"));
+    return VOS_STATUS_E_FAULT;
+  }
+  /*------------------------------------------------------------------------
+    Extract TL control block
+   ------------------------------------------------------------------------*/
+  pTLCb = VOS_GET_TL_CB(pvosGCtx);
+  if ( NULL == pTLCb )
+  {
+    TLLOGE(VOS_TRACE( VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+       "WLAN TL:Invalid TL pointer from pvosGCtx on WLANTL_CollectStats"));
+    return VOS_STATUS_E_FAULT;
+  }
+
+  if ( NULL == pTLCb->atlSTAClients[ucSTAId] )
+  {
+      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;
+  }
+  vos_mem_copy(vosDataBuff, &pTLCb->atlSTAClients[ucSTAId]->interfaceStats,
+          sizeof(WLANTL_InterfaceStatsType));
+  return VOS_STATUS_SUCCESS;
+}
+
+#endif /* WLAN_FEATURE_LINK_LAYER_STATS */
 
 /*==========================================================================
 
diff --git a/CORE/TL/src/wlan_qct_tl_hosupport.c b/CORE/TL/src/wlan_qct_tl_hosupport.c
index 1b46d77..03f213b 100644
--- a/CORE/TL/src/wlan_qct_tl_hosupport.c
+++ b/CORE/TL/src/wlan_qct_tl_hosupport.c
@@ -882,13 +882,99 @@
    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 
+   DESCRIPTION
+
+   PARAMETERS
 
    RETURN VALUE
 
diff --git a/CORE/TL/src/wlan_qct_tl_hosupport.h b/CORE/TL/src/wlan_qct_tl_hosupport.h
index 1d27e97..fcffea7 100644
--- a/CORE/TL/src/wlan_qct_tl_hosupport.h
+++ b/CORE/TL/src/wlan_qct_tl_hosupport.h
@@ -68,6 +68,27 @@
 ===========================================================================*/
 #include "wlan_qct_tl.h" 
 
+#ifdef WLAN_FEATURE_LINK_LAYER_STATS
+/*==========================================================================
+
+   FUNCTION
+
+   DESCRIPTION
+
+   PARAMETERS
+
+   RETURN VALUE
+
+============================================================================*/
+VOS_STATUS WLANTL_HSGetDataRSSI
+(
+   v_PVOID_t        pAdapter,
+   v_PVOID_t        pBDHeader,
+   v_U8_t           STAid,
+   v_S7_t          *currentAvgRSSI
+);
+#endif
+
 #if defined WLAN_FEATURE_NEIGHBOR_ROAMING
 /*----------------------------------------------------------------------------
  * Include Files
diff --git a/CORE/TL/src/wlan_qct_tli.h b/CORE/TL/src/wlan_qct_tli.h
index 7c22514..1215177 100644
--- a/CORE/TL/src/wlan_qct_tli.h
+++ b/CORE/TL/src/wlan_qct_tli.h
@@ -172,12 +172,15 @@
 #define WLANTL_80211_DATA_TYPE         0x02
 #define WLANTL_80211_DATA_QOS_SUBTYPE  0x08
 #define WLANTL_80211_NULL_QOS_SUBTYPE  0x0C
+#define WLANTL_80211_MGMT_ACTION_SUBTYPE  0x0D
+#define WLANTL_80211_MGMT_ACTION_NO_ACK_SUBTYPE  0x0E
 
 /*Defines for internal utility functions */
 #define WLANTL_FRAME_TYPE_BCAST 0xff
 #define WLANTL_FRAME_TYPE_MCAST 0x01
 #define WLANTL_FRAME_TYPE_UCAST 0x00
 
+#define WLANTL_FRAME_TYPESUBTYPE_MASK 0x3F
 
 /*-------------------------------------------------------------------------
   BT-AMP related definition - !!! should probably be moved to BT-AMP header
@@ -492,6 +495,7 @@
   v_TIME_t              cacheClearTime;
 }WLANTL_CacheInfoType;
 
+
 /*---------------------------------------------------------------------------
   STA Client type
 ---------------------------------------------------------------------------*/
@@ -673,6 +677,20 @@
   v_U8_t ptkInstalled;
 
   v_U32_t       linkCapacity;
+
+#ifdef WLAN_FEATURE_LINK_LAYER_STATS
+
+  /* Value of the averaged Data RSSI for this station */
+  v_S7_t                        rssiDataAvg;
+
+  /* Value of the averaged Data RSSI for this station in BMPS */
+  v_S7_t                        rssiDataAvgBmps;
+
+  /* Value of the Alpha to calculate Data RSSI average */
+  v_S7_t                        rssiDataAlpha;
+
+  WLANTL_InterfaceStatsType         interfaceStats;
+#endif
 }WLANTL_STAClientType;
 
 /*---------------------------------------------------------------------------