wlan: Cache deleted station's information in case of SAP

qcacld-3.0 to prima propagation

During disconnection process, cache disconnecting STA information
so that the same information is updated to upper-layer on receiving
GET_STATION vendor command, after disconnection.

Change-Id: I2e5a0be42d81b86e6f4490de1bdf9d7e0797506d
CRs-Fixed: 2159220
diff --git a/CORE/HDD/inc/wlan_hdd_assoc.h b/CORE/HDD/inc/wlan_hdd_assoc.h
index 0162034..ab86a03 100644
--- a/CORE/HDD/inc/wlan_hdd_assoc.h
+++ b/CORE/HDD/inc/wlan_hdd_assoc.h
@@ -245,4 +245,9 @@
 
 void iw_full_power_cbfn (void *pContext, eHalStatus status);
 
+void hdd_copy_ht_caps(struct ieee80211_ht_cap *hdd_ht_cap,
+                      tDot11fIEHTCaps *roam_ht_cap);
+void hdd_copy_vht_caps(struct ieee80211_vht_cap *hdd_vht_cap,
+                       tDot11fIEVHTCaps *roam_vht_cap);
+
 #endif
diff --git a/CORE/HDD/inc/wlan_hdd_cfg80211.h b/CORE/HDD/inc/wlan_hdd_cfg80211.h
index 7faca82..ae4d9f1 100644
--- a/CORE/HDD/inc/wlan_hdd_cfg80211.h
+++ b/CORE/HDD/inc/wlan_hdd_cfg80211.h
@@ -240,22 +240,23 @@
 
 /**
  * enum qca_wlan_802_11_mode - dot11 mode
- * @QCA_WLAN_802_11_MODE_INVALID: Invalid dot11 mode
- * @QCA_WLAN_802_11_MODE_11A: mode A
  * @QCA_WLAN_802_11_MODE_11B: mode B
  * @QCA_WLAN_802_11_MODE_11G: mode G
  * @QCA_WLAN_802_11_MODE_11N: mode N
+ * @QCA_WLAN_802_11_MODE_11A: mode A
  * @QCA_WLAN_802_11_MODE_11AC: mode AC
+ * @QCA_WLAN_802_11_MODE_INVALID: Invalid dot11 mode
  */
 enum qca_wlan_802_11_mode {
-	QCA_WLAN_802_11_MODE_INVALID,
-	QCA_WLAN_802_11_MODE_11A,
 	QCA_WLAN_802_11_MODE_11B,
 	QCA_WLAN_802_11_MODE_11G,
 	QCA_WLAN_802_11_MODE_11N,
+	QCA_WLAN_802_11_MODE_11A,
 	QCA_WLAN_802_11_MODE_11AC,
+	QCA_WLAN_802_11_MODE_INVALID,
 };
 
+
 /**
  * enum qca_wlan_auth_type - Authentication key management type
  * @QCA_WLAN_AUTH_TYPE_INVALID: Invalid key management type
@@ -1667,4 +1668,5 @@
 
 int wlan_hdd_cfg80211_update_apies(hdd_adapter_t *pHostapdAdapter);
 int wlan_hdd_try_disconnect(hdd_adapter_t *pAdapter);
+void wlan_hdd_sap_get_sta_rssi(hdd_adapter_t *adapter, uint8_t staid, s8 *rssi);
 #endif
diff --git a/CORE/HDD/src/wlan_hdd_assoc.c b/CORE/HDD/src/wlan_hdd_assoc.c
index 5cb9f38..a07f460 100644
--- a/CORE/HDD/src/wlan_hdd_assoc.c
+++ b/CORE/HDD/src/wlan_hdd_assoc.c
@@ -270,18 +270,15 @@
 }
 
 /**
- * hdd_copy_vht_caps()- copy vht caps info from roam info to
- *  hdd station context.
- * @hdd_sta_ctx: pointer to hdd station context
- * @roam_info: pointer to roam info
+ * hdd_copy_ht_caps()- Populate kernel HT caps structure object
+ * @hdd_ht_cap: HT capabilities of kernel type
+ * @roam_ht_cap: HT capabilities maintained locally within driver
  *
  * Return: None
  */
-static void hdd_copy_ht_caps(hdd_station_ctx_t *hdd_sta_ctx,
-                             tCsrRoamInfo *roam_info)
+void hdd_copy_ht_caps(struct ieee80211_ht_cap *hdd_ht_cap,
+                      tDot11fIEHTCaps *roam_ht_cap)
 {
-    tDot11fIEHTCaps *roam_ht_cap = &roam_info->ht_caps;
-    struct ieee80211_ht_cap *hdd_ht_cap = &hdd_sta_ctx->conn_info.ht_caps;
     uint32_t i, temp_ht_cap;
 
     vos_mem_zero(hdd_ht_cap, sizeof(struct ieee80211_ht_cap));
@@ -321,7 +318,6 @@
     if (roam_ht_cap->lsigTXOPProtection)
         hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_LSIG_TXOP_PROT;
 
-
     /* 802.11n HT capability AMPDU settings (for ampdu_params_info) */
     if (roam_ht_cap->maxRxAMPDUFactor)
         hdd_ht_cap->ampdu_params_info |=
@@ -443,11 +439,13 @@
     for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; ++i)
         hdd_ht_cap->mcs.rx_mask[i] =
             roam_ht_cap->supportedMCSSet[i];
+
         hdd_ht_cap->mcs.rx_highest =
             ((short) (roam_ht_cap->supportedMCSSet[11]) << 8) |
             ((short) (roam_ht_cap->supportedMCSSet[10]));
         hdd_ht_cap->mcs.tx_params =
             roam_ht_cap->supportedMCSSet[12];
+
 }
 
 
@@ -466,19 +464,15 @@
 #define VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB_SHIFT	26
 
 /**
- * hdd_copy_ht_caps()- copy ht caps info from roam info to
- *  hdd station context.
- * @hdd_sta_ctx: pointer to hdd station context
- * @roam_info: pointer to roam info
+ * hdd_copy_vht_caps()- Populate kernel VHT caps structure object
+ * @hdd_ht_cap: VHT capabilities of kernel type
+ * @roam_ht_cap: VHT capabilities maintained locally within driver
  *
  * Return: None
  */
-static void hdd_copy_vht_caps(hdd_station_ctx_t *hdd_sta_ctx,
-                              tCsrRoamInfo *roam_info)
+void hdd_copy_vht_caps(struct ieee80211_vht_cap *hdd_vht_cap,
+			      tDot11fIEVHTCaps *roam_vht_cap)
 {
-    tDot11fIEVHTCaps *roam_vht_cap = &roam_info->vht_caps;
-    struct ieee80211_vht_cap *hdd_vht_cap =
-                    &hdd_sta_ctx->conn_info.vht_caps;
     uint32_t temp_vht_cap;
 
     vos_mem_zero(hdd_vht_cap, sizeof(struct ieee80211_vht_cap));
@@ -716,13 +710,14 @@
         hdd_sta_ctx->conn_info.operationChannel);
     if (roam_info->vht_caps.present) {
         hdd_sta_ctx->conn_info.conn_flag.vht_present = true;
-        hdd_copy_vht_caps(hdd_sta_ctx, roam_info);
+        hdd_copy_vht_caps(&hdd_sta_ctx->conn_info.vht_caps,
+                          &roam_info->vht_caps);
     } else {
         hdd_sta_ctx->conn_info.conn_flag.vht_present = false;
     }
     if (roam_info->ht_caps.present) {
         hdd_sta_ctx->conn_info.conn_flag.ht_present = true;
-        hdd_copy_ht_caps(hdd_sta_ctx, roam_info);
+        hdd_copy_ht_caps(&hdd_sta_ctx->conn_info.ht_caps, &roam_info->ht_caps);
     } else {
         hdd_sta_ctx->conn_info.conn_flag.ht_present = false;
     }
diff --git a/CORE/HDD/src/wlan_hdd_cfg80211.c b/CORE/HDD/src/wlan_hdd_cfg80211.c
index 5127abc..23e0705 100644
--- a/CORE/HDD/src/wlan_hdd_cfg80211.c
+++ b/CORE/HDD/src/wlan_hdd_cfg80211.c
@@ -16809,7 +16809,7 @@
  *
  * Return: None
  */
-static void
+void
 wlan_hdd_sap_get_sta_rssi(hdd_adapter_t *adapter, uint8_t staid, s8 *rssi)
 {
 	v_CONTEXT_t pVosContext =  (WLAN_HDD_GET_CTX(adapter))->pvosContext;
diff --git a/CORE/HDD/src/wlan_hdd_hostapd.c b/CORE/HDD/src/wlan_hdd_hostapd.c
index 40b3aa9..db9d5ba 100644
--- a/CORE/HDD/src/wlan_hdd_hostapd.c
+++ b/CORE/HDD/src/wlan_hdd_hostapd.c
@@ -1006,7 +1006,109 @@
    return VOS_STATUS_SUCCESS;
 }
 
+/**
+ * hdd_convert_dot11mode_from_phymode() - get dot11mode to phymode
+ * @phymode: phy mode
+ *
+ * This function is used to get dot11mode to phymode
+ *
+ * Return: dot11mode
+ */
+static int hdd_convert_dot11mode_from_phymode(int phymode)
+{
+	switch (phymode) {
 
+	case VOS_MODE_11A:
+		return QCA_WLAN_802_11_MODE_11A;
+
+	case VOS_MODE_11B:
+		return QCA_WLAN_802_11_MODE_11B;
+
+	case VOS_MODE_11G:
+	case VOS_MODE_11GONLY:
+		return QCA_WLAN_802_11_MODE_11G;
+
+	case VOS_MODE_11NA_HT20:
+	case VOS_MODE_11NG_HT20:
+	case VOS_MODE_11NA_HT40:
+	case VOS_MODE_11NG_HT40:
+		return QCA_WLAN_802_11_MODE_11N;
+
+	case VOS_MODE_11AC_VHT20:
+	case VOS_MODE_11AC_VHT40:
+	case VOS_MODE_11AC_VHT80:
+	case VOS_MODE_11AC_VHT20_2G:
+	case VOS_MODE_11AC_VHT40_2G:
+	case VOS_MODE_11AC_VHT80_2G:
+#ifdef CONFIG_160MHZ_SUPPORT
+	case VOS_MODE_11AC_VHT80_80:
+	case VOS_MODE_11AC_VHT160:
+#endif
+		return QCA_WLAN_802_11_MODE_11AC;
+
+	default:
+		return QCA_WLAN_802_11_MODE_INVALID;
+	}
+
+}
+
+/**
+ * hdd_fill_station_info() - fill station information
+ * @sap_ctx: sap context
+ * @event: assoc event
+ * This function updates sta information from assoc event
+ *
+ * Return: none
+ */
+static void hdd_fill_station_info(ptSapContext sap_ctx,
+				  tSap_StationAssocReassocCompleteEvent *event)
+{
+	struct hdd_cache_sta_info *sta_info = sap_ctx->cache_sta_info;
+	int i=0;
+
+	/* check if there is any dup entry */
+	while (i < WLAN_MAX_STA_COUNT) {
+		if (vos_mem_compare(sta_info[i].macAddrSTA.bytes,
+				    event->staMac.bytes,
+				    VOS_MAC_ADDR_SIZE)) {
+			vos_mem_zero(&sta_info[i], sizeof(*sta_info));
+			break;
+		}
+		i++;
+	}
+	if (i >= WLAN_MAX_STA_COUNT) {
+		i = 0;
+		while (i < WLAN_MAX_STA_COUNT) {
+			if (sta_info[i].isUsed != TRUE)
+				break;
+			i++;
+		}
+	}
+
+	if (i < WLAN_MAX_STA_COUNT) {
+		sta_info[i].isUsed = TRUE;
+		sta_info[i].ucSTAId = event->staId;
+		vos_mem_copy(sta_info[i].macAddrSTA.bytes,
+			     event->staMac.bytes,
+			      VOS_MAC_ADDR_SIZE);
+		sta_info[i].freq = vos_chan_to_freq(event->chan_info.chan_id);
+		sta_info[i].ch_width = event->ch_width;
+		sta_info[i].nss = 1;
+		sta_info[i].dot11_mode = hdd_convert_dot11mode_from_phymode(
+							event->chan_info.info);
+		if (event->HTCaps.present) {
+			sta_info[i].ht_present = TRUE;
+			hdd_copy_ht_caps(&sta_info[i].ht_caps, &event->HTCaps);
+		}
+		if (event->VHTCaps.present) {
+			sta_info[i].vht_present = TRUE;
+			hdd_copy_vht_caps(&sta_info[i].vht_caps,
+					  &event->VHTCaps);
+		}
+	}
+	else
+		VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "reached max staid, stainfo can't be cached");
+}
 
 VOS_STATUS hdd_hostapd_SAPEventCB( tpSap_Event pSapEvent, v_PVOID_t usrDataForCallback)
 {
@@ -1261,6 +1363,9 @@
                     hddLog(LOGW, FL("Failed to register STA %d "MAC_ADDRESS_STR""),
                                      vos_status, MAC_ADDR_ARRAY(wrqu.addr.sa_data));
             }
+            if (VOS_IS_STATUS_SUCCESS(vos_status))
+                hdd_fill_station_info(pSapCtx,
+                        &pSapEvent->sapevt.sapStationAssocReassocCompleteEvent);
 
             staId =
                 pSapEvent->sapevt.sapStationAssocReassocCompleteEvent.staId;
@@ -1484,6 +1589,28 @@
 
             return hdd_chan_change_notify(pHostapdAdapter, dev,
                            pSapEvent->sapevt.sap_chan_selected.new_chan);
+    case eSAP_STA_LOSTLINK_DETECTED:
+        {
+            tSap_StationDisassocCompleteEvent *disassoc_comp =
+                    &pSapEvent->sapevt.sapStationDisassocCompleteEvent;
+
+            struct hdd_cache_sta_info *sta_info = hdd_get_cache_stainfo(
+                                              pSapCtx->cache_sta_info,
+                                              disassoc_comp->staMac.bytes);
+           if (!sta_info) {
+               hddLog(LOGE, FL("invalid cache sta info"));
+               return VOS_STATUS_E_FAILURE;
+           }
+
+            WLANTL_GetSAPStaRSSi(pVosContext, disassoc_comp->staId,
+                        &sta_info->rssi);
+            sta_info->rx_rate =
+                    wlan_tl_get_sta_rx_rate(pVosContext, disassoc_comp->staId);
+            if (disassoc_comp->reason != eSAP_USR_INITATED_DISASSOC)
+                sta_info->reason_code = disassoc_comp->reason;
+            return VOS_STATUS_SUCCESS;
+        }
+
         default:
             hddLog(LOG1,"SAP message is not handled");
             goto stopbss;
@@ -5584,3 +5711,32 @@
   }
   return;
 }
+
+/**
+ * hdd_get_cache_stainfo() - get stainfo for the specified peer
+ * @stainfo: array of station info
+ * @mac_addr: mac address of requested peer
+ *
+ * This function find the stainfo for the peer with mac_addr
+ *
+ * Return: stainfo if found, NULL if not found
+ */
+struct hdd_cache_sta_info *hdd_get_cache_stainfo(
+				struct hdd_cache_sta_info *astainfo,
+				u8 *mac_addr)
+{
+	struct hdd_cache_sta_info *stainfo = NULL;
+	int i;
+
+	for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
+		if (vos_mem_compare(&astainfo[i].macAddrSTA,
+		    mac_addr,
+		    HDD_MAC_ADDR_LEN)) {
+			stainfo = &astainfo[i];
+			break;
+		}
+	}
+
+	return stainfo;
+}
+
diff --git a/CORE/HDD/src/wlan_hdd_main.c b/CORE/HDD/src/wlan_hdd_main.c
index 0021b51..b5b4bd6 100644
--- a/CORE/HDD/src/wlan_hdd_main.c
+++ b/CORE/HDD/src/wlan_hdd_main.c
@@ -13569,12 +13569,29 @@
 {
     v_CONTEXT_t pVosContext = (WLAN_HDD_GET_CTX(pAdapter))->pvosContext;
     VOS_STATUS vosStatus = VOS_STATUS_E_FAULT;
+    struct hdd_cache_sta_info *cache_sta_info;
+    ptSapContext pSapCtx = VOS_GET_SAP_CB(pVosContext);
 
     ENTER();
 
     hddLog(LOG1, "hdd_softap_sta_deauth:(%pK, false)",
            (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
 
+    if (!pSapCtx) {
+        hddLog(LOGE, "sap context is NULL");
+        return vosStatus;
+    }
+
+    cache_sta_info = hdd_get_cache_stainfo(pSapCtx->cache_sta_info,
+                                           pDelStaParams->peerMacAddr);
+    if (cache_sta_info) {
+        cache_sta_info->reason_code = pDelStaParams->reason_code;
+        cache_sta_info->rx_rate =
+                wlan_tl_get_sta_rx_rate(pVosContext, cache_sta_info->ucSTAId);
+        WLANTL_GetSAPStaRSSi(pVosContext, cache_sta_info->ucSTAId,
+                             &cache_sta_info->rssi);
+    }
+
     //Ignore request to deauth bcmc station
     if (pDelStaParams->peerMacAddr[0] & 0x1)
        return vosStatus;
@@ -13656,16 +13673,33 @@
 
 void hdd_softap_sta_disassoc(hdd_adapter_t *pAdapter,v_U8_t *pDestMacAddress)
 {
-        v_CONTEXT_t pVosContext = (WLAN_HDD_GET_CTX(pAdapter))->pvosContext;
+    v_CONTEXT_t pVosContext = (WLAN_HDD_GET_CTX(pAdapter))->pvosContext;
+    struct hdd_cache_sta_info *cache_sta_info;
+    ptSapContext  pSapCtx = VOS_GET_SAP_CB(pVosContext);
 
     ENTER();
 
     hddLog( LOGE, "hdd_softap_sta_disassoc:(%pK, false)", (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
 
+    if (!pSapCtx) {
+        hddLog(LOGE, "sap context is NULL");
+        return ;
+    }
+
     //Ignore request to disassoc bcmc station
     if( pDestMacAddress[0] & 0x1 )
        return;
 
+    cache_sta_info = hdd_get_cache_stainfo(pSapCtx->cache_sta_info,
+                                           pDestMacAddress);
+    if (cache_sta_info) {
+        cache_sta_info->reason_code = eSIR_MAC_DEAUTH_LEAVING_BSS_REASON;
+        cache_sta_info->rx_rate =
+                wlan_tl_get_sta_rx_rate(pVosContext, cache_sta_info->ucSTAId);
+        WLANTL_GetSAPStaRSSi(pVosContext, cache_sta_info->ucSTAId,
+                             &cache_sta_info->rssi);
+    }
+
     WLANSAP_DisassocSta(pVosContext,pDestMacAddress);
 }
 
diff --git a/CORE/MAC/inc/sirApi.h b/CORE/MAC/inc/sirApi.h
index 20eec7c..4b054bf 100644
--- a/CORE/MAC/inc/sirApi.h
+++ b/CORE/MAC/inc/sirApi.h
@@ -1202,6 +1202,15 @@
     tANI_U16           devicePasswdId;
 } tSirSmeProbeReq, *tpSirSmeProbeReq;
 
+typedef struct sSirSmeChanInfo
+{
+    /* channel id */
+    tANI_U8 chan_id;
+    /* channel info described below */
+    tANI_U32 info;
+}tSirSmeChanInfo, *tpSirSmeChanInfo;
+
+
 /// Definition for Association indication from peer
 /// MAC --->
 typedef struct sSirSmeAssocInd
@@ -1236,6 +1245,10 @@
     tANI_U32             assocReqLength;
     tANI_U8*             assocReqPtr;
     uint32_t             rate_flags;
+    tSirSmeChanInfo      chan_info;
+    tSirMacHTChannelWidth ch_width;
+    tDot11fIEHTCaps HTCaps;
+    tDot11fIEVHTCaps VHTCaps;
 } tSirSmeAssocInd, *tpSirSmeAssocInd;
 
 
diff --git a/CORE/MAC/src/pe/lim/limProcessAssocReqFrame.c b/CORE/MAC/src/pe/lim/limProcessAssocReqFrame.c
index e1b7978..7b6666c 100644
--- a/CORE/MAC/src/pe/lim/limProcessAssocReqFrame.c
+++ b/CORE/MAC/src/pe/lim/limProcessAssocReqFrame.c
@@ -1663,6 +1663,52 @@
         pMlmAssocInd->beaconPtr = psessionEntry->beacon;
         pMlmAssocInd->beaconLength = psessionEntry->bcnLen;
 
+        pMlmAssocInd->chan_info.chan_id = psessionEntry->currentOperChannel;
+
+        if (psessionEntry->limRFBand == SIR_BAND_2_4_GHZ) {
+            if (psessionEntry->vhtCapability && pAssocReq->VHTCaps.present) {
+                pMlmAssocInd->chan_info.info = MODE_11AC_VHT20_2G;
+                pMlmAssocInd->VHTCaps = pAssocReq->VHTCaps;
+            } else if (psessionEntry->htCapability &&
+                                                 pAssocReq->HTCaps.present) {
+                pMlmAssocInd->chan_info.info = MODE_11NG_HT20;
+                pMlmAssocInd->HTCaps = pAssocReq->HTCaps;
+            } else if (pStaDs->supportedRates.llaRates[0]) {
+                pMlmAssocInd->chan_info.info = MODE_11G;
+            } else {
+                pMlmAssocInd->chan_info.info = MODE_11B;
+            }
+        } else {
+            if (psessionEntry->vhtCapability && pAssocReq->VHTCaps.present) {
+                if ((psessionEntry->vhtTxChannelWidthSet ==
+                                                eHT_CHANNEL_WIDTH_80MHZ) &&
+                                 pAssocReq->HTCaps.supportedChannelWidthSet) {
+                    pMlmAssocInd->chan_info.info = MODE_11AC_VHT80;
+                } else if ((psessionEntry->vhtTxChannelWidthSet ==
+                                                eHT_CHANNEL_WIDTH_40MHZ) &&
+                                  pAssocReq->HTCaps.supportedChannelWidthSet) {
+                    pMlmAssocInd->chan_info.info = MODE_11AC_VHT40;
+                } else
+                    pMlmAssocInd->chan_info.info = MODE_11AC_VHT20;
+                    pMlmAssocInd->VHTCaps = pAssocReq->VHTCaps;
+            } else if (psessionEntry->htCapability &&
+                                pAssocReq->HTCaps.present) {
+                if ((psessionEntry->vhtTxChannelWidthSet ==
+                                                eHT_CHANNEL_WIDTH_40MHZ) &&
+                                  pAssocReq->HTCaps.supportedChannelWidthSet) {
+                    pMlmAssocInd->chan_info.info = MODE_11NA_HT40;
+                } else
+                    pMlmAssocInd->chan_info.info = MODE_11NA_HT20;
+                pMlmAssocInd->HTCaps = pAssocReq->HTCaps;
+            } else
+                pMlmAssocInd->chan_info.info = MODE_11A;
+        }
+
+        pMlmAssocInd->ch_width = eHT_CHANNEL_WIDTH_20MHZ;
+        if (pStaDs->mlmStaContext.htCapability)
+            pMlmAssocInd->ch_width = pStaDs->htSupportedChannelWidthSet ?
+                            eHT_CHANNEL_WIDTH_40MHZ : eHT_CHANNEL_WIDTH_20MHZ;
+
         pMlmAssocInd->rate_flags =
             limGetMaxRateFlags(pStaDs, psessionEntry);
 
diff --git a/CORE/MAC/src/pe/lim/limProcessMlmRspMessages.c b/CORE/MAC/src/pe/lim/limProcessMlmRspMessages.c
index 42988be..29083df 100644
--- a/CORE/MAC/src/pe/lim/limProcessMlmRspMessages.c
+++ b/CORE/MAC/src/pe/lim/limProcessMlmRspMessages.c
@@ -1233,6 +1233,13 @@
 #endif
     // Fill in rate flags
     pSirSmeAssocInd->rate_flags = pAssocInd->rate_flags;
+
+    pSirSmeAssocInd->ch_width = pAssocInd->ch_width;
+    pSirSmeAssocInd->chan_info = pAssocInd->chan_info;
+    if (pAssocInd->HTCaps.present)
+        pSirSmeAssocInd->HTCaps = pAssocInd->HTCaps;
+    if (pAssocInd->VHTCaps.present)
+        pSirSmeAssocInd->VHTCaps = pAssocInd->VHTCaps;
 } /*** end limAssocIndSerDes() ***/
 
 
@@ -1283,6 +1290,7 @@
                FL("call to AllocateMemory failed for eWNI_SME_ASSOC_IND"));
         return;
     }
+    vos_mem_zero(pSirSmeAssocInd, len);
 
     pSirSmeAssocInd->messageType = eWNI_SME_ASSOC_IND;
     limFillAssocIndParams(pMac, (tpLimMlmAssocInd) pMsgBuf, pSirSmeAssocInd, psessionEntry);
diff --git a/CORE/MAC/src/pe/lim/limTypes.h b/CORE/MAC/src/pe/lim/limTypes.h
index b346ee5..485fd7b 100644
--- a/CORE/MAC/src/pe/lim/limTypes.h
+++ b/CORE/MAC/src/pe/lim/limTypes.h
@@ -274,6 +274,10 @@
     tANI_U32             assocReqLength;
     tANI_U8*             assocReqPtr;
     uint32_t             rate_flags;
+    tSirSmeChanInfo      chan_info;
+    tSirMacHTChannelWidth ch_width;
+    tDot11fIEHTCaps HTCaps;
+    tDot11fIEVHTCaps VHTCaps;
 } tLimMlmAssocInd, *tpLimMlmAssocInd;
 
 typedef struct sLimMlmReassocReq
diff --git a/CORE/SAP/inc/sapApi.h b/CORE/SAP/inc/sapApi.h
index ca1e3fa..0b1956e 100644
--- a/CORE/SAP/inc/sapApi.h
+++ b/CORE/SAP/inc/sapApi.h
@@ -194,6 +194,7 @@
     eSAP_UNKNOWN_STA_JOIN, /* Event send when a STA in neither white list or black list tries to associate in softap mode */
     eSAP_MAX_ASSOC_EXCEEDED, /* Event send when a new STA is rejected association since softAP max assoc limit has reached */
     eSAP_CHANNEL_CHANGED_EVENT,
+    eSAP_STA_LOSTLINK_DETECTED
 } eSapHddEvent;
 
 typedef enum {
@@ -288,6 +289,10 @@
     tANI_U32     assocRespLength;
     tANI_U8*     assocRespPtr;
     uint32_t rate_flags;
+    tSirSmeChanInfo chan_info;
+    tSirMacHTChannelWidth ch_width;
+    tDot11fIEVHTCaps VHTCaps;
+    tDot11fIEHTCaps HTCaps;
 } tSap_StationAssocReassocCompleteEvent;
 
 typedef struct sap_StationDisassocCompleteEvent_s {
diff --git a/CORE/SAP/src/sapApiLinkCntl.c b/CORE/SAP/src/sapApiLinkCntl.c
index 33bd851..146d4e3 100644
--- a/CORE/SAP/src/sapApiLinkCntl.c
+++ b/CORE/SAP/src/sapApiLinkCntl.c
@@ -1451,6 +1451,14 @@
             if (!VOS_IS_STATUS_SUCCESS(vosStatus))
                 halStatus = eHAL_STATUS_FAILURE;
             break;
+        case eCSR_ROAM_LOSTLINK_DETECTED:
+            if (pCsrRoamInfo) {
+                sapSignalHDDevent(sapContext, pCsrRoamInfo,
+                                  eSAP_STA_LOSTLINK_DETECTED,
+                                  (v_PVOID_t)eSAP_STATUS_SUCCESS);
+                return eHAL_STATUS_SUCCESS;
+           }
+
         default:
             VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR,
                          FL("CSR roamStatus not handled roamStatus = %s (%d)"),
diff --git a/CORE/SAP/src/sapFsm.c b/CORE/SAP/src/sapFsm.c
index c613d9c..98907ed 100644
--- a/CORE/SAP/src/sapFsm.c
+++ b/CORE/SAP/src/sapFsm.c
@@ -803,38 +803,45 @@
 
         case eSAP_STA_ASSOC_EVENT:
         {
+            tSap_StationAssocReassocCompleteEvent *event =
+                     &sapApAppEvent.sapevt.sapStationAssocReassocCompleteEvent;
             VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_INFO_HIGH,
                        FL("SAP event callback event = %s"),
                           "eSAP_STA_ASSOC_EVENT");
+            vos_mem_zero(event, sizeof(event));
             if (pCsrRoamInfo->fReassocReq)
                 sapApAppEvent.sapHddEventCode = eSAP_STA_REASSOC_EVENT;
             else
                 sapApAppEvent.sapHddEventCode = eSAP_STA_ASSOC_EVENT;
 
             //TODO: Need to fill the SET KEY information and pass to HDD
-            vos_mem_copy( &sapApAppEvent.sapevt.sapStationAssocReassocCompleteEvent.staMac,
+            vos_mem_copy( &event->staMac,
                          pCsrRoamInfo->peerMac,sizeof(tSirMacAddr));
-            sapApAppEvent.sapevt.sapStationAssocReassocCompleteEvent.staId = pCsrRoamInfo->staId ;
-            sapApAppEvent.sapevt.sapStationAssocReassocCompleteEvent.statusCode = pCsrRoamInfo->statusCode;
-            sapApAppEvent.sapevt.sapStationAssocReassocCompleteEvent.iesLen = pCsrRoamInfo->rsnIELen;
-            vos_mem_copy(sapApAppEvent.sapevt.sapStationAssocReassocCompleteEvent.ies, pCsrRoamInfo->prsnIE,
+            event->staId = pCsrRoamInfo->staId ;
+            event->statusCode = pCsrRoamInfo->statusCode;
+            event->iesLen = pCsrRoamInfo->rsnIELen;
+            vos_mem_copy(event->ies, pCsrRoamInfo->prsnIE,
                         pCsrRoamInfo->rsnIELen);
 
             if(pCsrRoamInfo->addIELen)
             {
-                v_U8_t  len = sapApAppEvent.sapevt.sapStationAssocReassocCompleteEvent.iesLen;
-                sapApAppEvent.sapevt.sapStationAssocReassocCompleteEvent.iesLen
-                                                        += pCsrRoamInfo->addIELen;
-                vos_mem_copy(&sapApAppEvent.sapevt.sapStationAssocReassocCompleteEvent.ies[len], pCsrRoamInfo->paddIE,
+                v_U8_t  len = event->iesLen;
+                event->iesLen += pCsrRoamInfo->addIELen;
+                vos_mem_copy(&event->ies[len], pCsrRoamInfo->paddIE,
                             pCsrRoamInfo->addIELen);
             }
 
-            sapApAppEvent.sapevt.sapStationAssocReassocCompleteEvent.rate_flags = pCsrRoamInfo->maxRateFlags;
+            event->rate_flags = pCsrRoamInfo->maxRateFlags;
 
-            sapApAppEvent.sapevt.sapStationAssocReassocCompleteEvent.wmmEnabled = pCsrRoamInfo->wmmEnabledSta;
-            sapApAppEvent.sapevt.sapStationAssocReassocCompleteEvent.status = (eSapStatus )context;
+            event->wmmEnabled = pCsrRoamInfo->wmmEnabledSta;
+            event->status = (eSapStatus )context;
+            event->ch_width = pCsrRoamInfo->ch_width;
+            event->chan_info = pCsrRoamInfo->chan_info;
+            event->HTCaps = pCsrRoamInfo->ht_caps;
+            event->VHTCaps = pCsrRoamInfo->vht_caps;
+
             //TODO: Need to fill sapAuthType
-            //sapApAppEvent.sapevt.sapStationAssocReassocCompleteEvent.SapAuthType = pCsrRoamInfo->pProfile->negotiatedAuthType;
+            //event->SapAuthType = pCsrRoamInfo->pProfile->negotiatedAuthType;
             break;
         }
 
@@ -970,7 +977,23 @@
             sapApAppEvent.sapevt.sap_chan_selected.new_chan =
                                                 sapContext->channel;
             break;
+    case eSAP_STA_LOSTLINK_DETECTED:
+        {
+            tSap_StationDisassocCompleteEvent* disassoc_comp;
 
+            VOS_TRACE(VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_INFO,
+                    "In %s SAP event callback event = %s",
+                    __func__, "eSAP_STA_LOSTLINK_DETECTED");
+
+            sapApAppEvent.sapHddEventCode = eSAP_STA_LOSTLINK_DETECTED;
+            disassoc_comp =
+                &sapApAppEvent.sapevt.sapStationDisassocCompleteEvent;
+            disassoc_comp->reason = pCsrRoamInfo->reasonCode;
+            disassoc_comp->staId = pCsrRoamInfo->staId;
+            vos_mem_copy(disassoc_comp->staMac.bytes,
+                         pCsrRoamInfo->peerMac, VOS_MAC_ADDR_SIZE);
+            break;
+        }
         default:
             VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR,
                        FL("SAP Unknown callback event = %d"),
diff --git a/CORE/SAP/src/sapInternal.h b/CORE/SAP/src/sapInternal.h
index ed7cd1e..d679580 100644
--- a/CORE/SAP/src/sapInternal.h
+++ b/CORE/SAP/src/sapInternal.h
@@ -189,6 +189,23 @@
 
 } hdd_station_info_t;
 
+struct hdd_cache_sta_info{
+    v_BOOL_t isUsed;
+    v_U8_t ucSTAId;
+    v_U32_t freq;
+    v_MACADDR_t macAddrSTA;
+    v_S7_t rssi;
+    v_U8_t nss;
+    v_U8_t dot11_mode;
+    v_U32_t reason_code;
+    v_U32_t rx_rate;
+    tSirMacHTChannelWidth ch_width;
+    v_BOOL_t ht_present;
+    struct ieee80211_ht_cap ht_caps;
+    v_BOOL_t vht_present;
+    struct ieee80211_vht_cap vht_caps;
+};
+
 /**
  * struct ecsa_info - structure to store ecsa info
  * @new_channel: new channel to which switch is requested
@@ -276,6 +293,7 @@
     tSapAcsChannelInfo acsBestChannelInfo;
     spinlock_t staInfo_lock; //To protect access to station Info
     hdd_station_info_t aStaInfo[WLAN_MAX_STA_COUNT];
+    struct hdd_cache_sta_info cache_sta_info[WLAN_MAX_STA_COUNT];
 #ifdef WLAN_FEATURE_AP_HT40_24G
     v_U8_t            affected_start;
     v_U8_t            affected_end;
@@ -923,6 +941,10 @@
 eHalStatus sapCheckHT40SecondaryIsNotAllowed(ptSapContext psapCtx);
 #endif
 
+struct hdd_cache_sta_info *hdd_get_cache_stainfo(
+                                          struct hdd_cache_sta_info *astainfo,
+                                          u8 *mac_addr);
+
 #ifdef __cplusplus
 }
 #endif 
diff --git a/CORE/SME/inc/csrApi.h b/CORE/SME/inc/csrApi.h
index 1f0f8fd..a0a6b5c 100644
--- a/CORE/SME/inc/csrApi.h
+++ b/CORE/SME/inc/csrApi.h
@@ -1345,6 +1345,8 @@
     tDot11fIEHTInfo ht_operation;
     bool reassoc;
     struct sir_channel_chanege_rsp *ap_chan_change_rsp;
+    tSirSmeChanInfo chan_info;
+    tSirMacHTChannelWidth ch_width;
 }tCsrRoamInfo;
 
 typedef struct tagCsrFreqScanInfo
@@ -1374,6 +1376,10 @@
     tANI_U8              HT40MHzIntoEnabledSta; //set to true if 40 MHz Intolerant enabled STA
 #endif
     uint32_t             rate_flags;
+    tSirSmeChanInfo      chan_info;
+    tSirMacHTChannelWidth ch_width;
+    tDot11fIEHTCaps HTCaps;
+    tDot11fIEVHTCaps VHTCaps;
 } tSirSmeAssocIndToUpperLayerCnf, *tpSirSmeAssocIndToUpperLayerCnf;
 
 typedef struct tagCsrSummaryStatsInfo
diff --git a/CORE/SME/src/csr/csrApiRoam.c b/CORE/SME/src/csr/csrApiRoam.c
index 178f9fa..31e038e 100644
--- a/CORE/SME/src/csr/csrApiRoam.c
+++ b/CORE/SME/src/csr/csrApiRoam.c
@@ -2846,6 +2846,10 @@
         pSession->connectedProfile.operationChannel =
                pRoamInfo->ap_chan_change_rsp->new_channel;
 
+    if (eCSR_ROAM_RESULT_LOSTLINK == u2 ||
+        eCSR_ROAM_LOSTLINK_DETECTED == u1)
+        smsLog(pMac, LOG1, "eCSR_ROAM_RESULT_LOSTLINK ");
+
     if(NULL != pSession->callback)
     {
         if( pRoamInfo )
@@ -9052,6 +9056,13 @@
                                     pRoamInfo->HT40MHzIntoEnabledSta);
 #endif
             pRoamInfo->maxRateFlags = pUpperLayerAssocCnf->rate_flags;
+            pRoamInfo->ch_width = pUpperLayerAssocCnf->ch_width;
+            pRoamInfo->chan_info = pUpperLayerAssocCnf->chan_info;
+            if (pUpperLayerAssocCnf->HTCaps.present)
+                pRoamInfo->ht_caps = pUpperLayerAssocCnf->HTCaps;
+            if (pUpperLayerAssocCnf->VHTCaps.present)
+               pRoamInfo->vht_caps = pUpperLayerAssocCnf->VHTCaps;
+
             if(CSR_IS_INFRA_AP(pRoamInfo->u.pConnectedProfile) )
             {
                 pMac->roam.roamSession[sessionId].connectState = eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED;
@@ -11348,7 +11359,6 @@
     tSirSmeDeauthInd *pDeauthIndMsg = NULL;
     tSirSmeDisassocInd *pDisassocIndMsg = NULL;
     eCsrRoamResult result = eCSR_ROAM_RESULT_LOSTLINK;
-    tCsrRoamInfo *pRoamInfo = NULL;
     tCsrRoamInfo roamInfo;
     tANI_BOOLEAN fToRoam;
     tCsrRoamSession *pSession = CSR_GET_SESSION( pMac, sessionId );
@@ -11361,12 +11371,16 @@
     //Only need to roam for infra station. In this case P2P client will roam as well
     fToRoam = CSR_IS_INFRASTRUCTURE(&pSession->connectedProfile);
     pSession->fCancelRoaming = eANI_BOOLEAN_FALSE;
+    vos_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0);
     if ( eWNI_SME_DISASSOC_IND == type )
     {
         result = eCSR_ROAM_RESULT_DISASSOC_IND;
         pDisassocIndMsg = (tSirSmeDisassocInd *)pSirMsg;
         pSession->roamingStatusCode = pDisassocIndMsg->statusCode;
         pSession->joinFailStatusCode.reasonCode = pDisassocIndMsg->reasonCode;
+        vos_mem_copy(roamInfo.peerMac, pDisassocIndMsg->peerMacAddr,
+                     sizeof(tSirMacAddr));
+        roamInfo.staId = (tANI_U8)pDisassocIndMsg->staId;
     }
     else if ( eWNI_SME_DEAUTH_IND == type )
     {
@@ -11374,6 +11388,9 @@
         pDeauthIndMsg = (tSirSmeDeauthInd *)pSirMsg;
         pSession->roamingStatusCode = pDeauthIndMsg->statusCode;
         pSession->joinFailStatusCode.reasonCode = pDeauthIndMsg->reasonCode;
+        vos_mem_copy(roamInfo.peerMac, pDeauthIndMsg->peerMacAddr,
+                     sizeof(tSirMacAddr));
+        roamInfo.staId = (tANI_U8)pDeauthIndMsg->staId;
     }
     else
     {
@@ -11381,11 +11398,16 @@
         result = eCSR_ROAM_RESULT_NONE;
         pSession->joinFailStatusCode.reasonCode = 1;
     }
-    
-    // call profile lost link routine here
-    if(!CSR_IS_INFRA_AP(&pSession->connectedProfile))
-    {
-        csrRoamCallCallback(pMac, sessionId, NULL, 0, eCSR_ROAM_LOSTLINK_DETECTED, result);
+    roamInfo.statusCode = (tSirResultCodes)pSession->roamingStatusCode;
+    roamInfo.reasonCode = pSession->joinFailStatusCode.reasonCode;
+    smsLog(pMac, LOGW, FL("roamInfo.staId (%d)"), roamInfo.staId);
+
+    if (type == eWNI_SME_DEAUTH_IND || type == eWNI_SME_DISASSOC_IND) {
+        csrRoamCallCallback(pMac, sessionId, &roamInfo, 0,
+                            eCSR_ROAM_LOSTLINK_DETECTED, result);
+    } else if(!CSR_IS_INFRA_AP(&pSession->connectedProfile)) {
+        csrRoamCallCallback(pMac, sessionId, NULL, 0,
+                            eCSR_ROAM_LOSTLINK_DETECTED, result);
     }
     
     if ( eWNI_SME_DISASSOC_IND == type )
@@ -11402,25 +11424,6 @@
         fToRoam = eANI_BOOLEAN_FALSE;
     }
 
-    //prepare to tell HDD to disconnect
-    vos_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0);
-    roamInfo.statusCode = (tSirResultCodes)pSession->roamingStatusCode;
-    roamInfo.reasonCode = pSession->joinFailStatusCode.reasonCode;
-    if( eWNI_SME_DISASSOC_IND == type)
-    {
-        //staMacAddr
-        vos_mem_copy(roamInfo.peerMac, pDisassocIndMsg->peerMacAddr,
-                     sizeof(tSirMacAddr));
-        roamInfo.staId = (tANI_U8)pDisassocIndMsg->staId;
-    }
-    else if( eWNI_SME_DEAUTH_IND == type )
-    {
-        //staMacAddr
-        vos_mem_copy(roamInfo.peerMac, pDeauthIndMsg->peerMacAddr,
-                     sizeof(tSirMacAddr));
-        roamInfo.staId = (tANI_U8)pDeauthIndMsg->staId;
-    }
-    smsLog(pMac, LOGW, FL("roamInfo.staId (%d)"), roamInfo.staId);
 
     /* See if we can possibly roam.  If so, start the roaming process and notify HDD
        that we are roaming.  But if we cannot possibly roam, or if we are unable to
@@ -11448,11 +11451,10 @@
                 {
                    roamInfo.reasonCode = eCsrRoamReasonSmeIssuedForLostLink;
                 }
-                    pRoamInfo = &roamInfo;
                 pSession->roamingReason = ( eWNI_SME_DEAUTH_IND == type ) ? 
                         eCsrLostlinkRoamingDeauth : eCsrLostlinkRoamingDisassoc;
                 pSession->roamingStartTime = (tANI_TIMESTAMP)palGetTickCount(pMac->hHdd);
-                csrRoamCallCallback(pMac, sessionId, pRoamInfo, 0, eCSR_ROAM_ROAMING_START, eCSR_ROAM_RESULT_LOSTLINK);
+                csrRoamCallCallback(pMac, sessionId, &roamInfo, 0, eCSR_ROAM_ROAMING_START, eCSR_ROAM_RESULT_LOSTLINK);
             }
             else
             {
@@ -15373,6 +15375,24 @@
 #endif
         *pBuf = pAssocInd->rate_flags;
         pBuf += sizeof (uint32_t);
+
+        pBuf = (tANI_U8 *)&pMsg->chan_info;
+        vos_mem_copy((void *)pBuf, &pAssocInd->chan_info,
+                     sizeof(tSirSmeChanInfo));
+
+        pBuf = (tANI_U8 *)&pMsg->ch_width;
+        *pBuf = pAssocInd->ch_width;
+
+        if (pAssocInd->HTCaps.present) {
+            pBuf = (tANI_U8 *)&pMsg->HTCaps;
+            vos_mem_copy(pBuf, &pAssocInd->HTCaps, sizeof(pMsg->HTCaps));
+        }
+
+    if (pAssocInd->VHTCaps.present) {
+        pBuf = (tANI_U8 *)&pMsg->VHTCaps;
+        vos_mem_copy(pBuf, &pAssocInd->VHTCaps, sizeof(pMsg->VHTCaps));
+    }
+
         msgQ.type = eWNI_SME_UPPER_LAYER_ASSOC_CNF;
         msgQ.bodyptr = pMsg;
         msgQ.bodyval = 0;
diff --git a/CORE/TL/inc/wlan_qct_tl.h b/CORE/TL/inc/wlan_qct_tl.h
index 146d658..5a0db01 100644
--- a/CORE/TL/inc/wlan_qct_tl.h
+++ b/CORE/TL/inc/wlan_qct_tl.h
@@ -3439,6 +3439,15 @@
 void WLANTL_GetSAPStaRSSi(void * pvosGCtx, uint8_t ucSTAId, s8 *rssi);
 
 /**
+ * wlan_tl_get_sta_rx_rate() - get rx rate for the SAP client
+ * @pvosGCtx: global vos context
+ * @ucSTAId: station id to get rssi for
+ *
+ * Return: rx tate
+ */
+v_U16_t wlan_tl_get_sta_rx_rate(void* pvosGCtx, uint8_t ucSTAId);
+
+/**
  * WLANTL_SetKeySeqCounter() - set sequence key counter
  * @pvosGCtx: global vos context
  * @counter: key sequence counter
diff --git a/CORE/TL/src/wlan_qct_tl.c b/CORE/TL/src/wlan_qct_tl.c
index 07ff758..5596cad 100644
--- a/CORE/TL/src/wlan_qct_tl.c
+++ b/CORE/TL/src/wlan_qct_tl.c
@@ -9491,6 +9491,7 @@
   rxRate        = (v_U8_t)WDA_GET_RX_MAC_RATE_IDX(aucBDHeader);
   type          = (v_U8_t)WDA_GET_RX_TYPE(aucBDHeader);
 #endif
+  pClientSTA->rate_idx = (v_U8_t)WDA_GET_RX_MAC_RATE_IDX(aucBDHeader);
 
   /* Fix for a hardware bug. 
    * H/W does not update the tid field in BD header for BAR frames.
@@ -14430,6 +14431,25 @@
 
 }
 
+v_U16_t wlan_tl_get_sta_rx_rate(void *pvosGCtx, uint8_t ucSTAId)
+{
+	WLANTL_CbType*  pTLCb = NULL;
+	v_U16_t rate = 0;
+
+	pTLCb = VOS_GET_TL_CB(pvosGCtx);
+	if (NULL == pTLCb) {
+		TLLOGE(VOS_TRACE(VOS_MODULE_ID_TL, VOS_TRACE_LEVEL_ERROR,
+			"%s: Invalid TL pointer from pvosGCtx", __func__));
+		return rate;
+	}
+
+	if (pTLCb->atlSTAClients[ucSTAId]->ucExists)
+	    rate = vos_get_rate_from_rateidx(
+		pTLCb->atlSTAClients[ucSTAId]->rate_idx);
+
+	return rate;
+}
+
 void WLANTL_GetSAPStaRSSi(void *pvosGCtx, uint8_t ucSTAId, s8 *rssi)
 {
    WLANTL_CbType*  pTLCb = NULL;
diff --git a/CORE/TL/src/wlan_qct_tli.h b/CORE/TL/src/wlan_qct_tli.h
index 7780655..4314c37 100644
--- a/CORE/TL/src/wlan_qct_tli.h
+++ b/CORE/TL/src/wlan_qct_tli.h
@@ -754,6 +754,7 @@
   s16 rssi_sample_sum;
   uint8_t rssi_sample_cnt;
   uint8_t rssi_stale_idx;
+  uint16_t rate_idx;
 }WLANTL_STAClientType;
 
 /*---------------------------------------------------------------------------
diff --git a/CORE/VOSS/inc/vos_api.h b/CORE/VOSS/inc/vos_api.h
index 5c7fd8c..43c9bfd 100644
--- a/CORE/VOSS/inc/vos_api.h
+++ b/CORE/VOSS/inc/vos_api.h
@@ -534,4 +534,5 @@
 bool vos_check_arp_target_ip(vos_pkt_t *pPacket);
 void vos_update_arp_fw_tx_delivered(void);
 void vos_update_arp_rx_drop_reorder(void);
+v_U16_t vos_get_rate_from_rateidx(uint32 rateindex);
 #endif // if !defined __VOS_NVITEM_H
diff --git a/CORE/VOSS/inc/vos_types.h b/CORE/VOSS/inc/vos_types.h
index 7038749..6f9a8e9 100755
--- a/CORE/VOSS/inc/vos_types.h
+++ b/CORE/VOSS/inc/vos_types.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014, 2017 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -201,6 +201,25 @@
     
 } v_MACADDR_t;
 
+typedef enum {
+    VOS_MODE_11A        = 0,   /* 11a Mode */
+    VOS_MODE_11G        = 1,   /* 11b/g Mode */
+    VOS_MODE_11B        = 2,   /* 11b Mode */
+    VOS_MODE_11GONLY    = 3,   /* 11g only Mode */
+    VOS_MODE_11NA_HT20   = 4,  /* 11a HT20 mode */
+    VOS_MODE_11NG_HT20   = 5,  /* 11g HT20 mode */
+    VOS_MODE_11NA_HT40   = 6,  /* 11a HT40 mode */
+    VOS_MODE_11NG_HT40   = 7,  /* 11g HT40 mode */
+    VOS_MODE_11AC_VHT20 = 8,
+    VOS_MODE_11AC_VHT40 = 9,
+    VOS_MODE_11AC_VHT80 = 10,
+//    VOS_MODE_11AC_VHT160 = 11,
+    VOS_MODE_11AC_VHT20_2G = 11,
+    VOS_MODE_11AC_VHT40_2G = 12,
+    VOS_MODE_11AC_VHT80_2G = 13,
+    VOS_MODE_UNKNOWN    = 14,
+    VOS_MODE_MAX        = 14
+} VOS_WLAN_PHY_MODE;
 
 /// This macro is used to initialize a vOSS MacAddress to the 
 /// broadcast MacAddress.  It is used like this...
diff --git a/CORE/VOSS/src/vos_api.c b/CORE/VOSS/src/vos_api.c
index 8e048ba..c868ff7 100644
--- a/CORE/VOSS/src/vos_api.c
+++ b/CORE/VOSS/src/vos_api.c
@@ -3616,6 +3616,16 @@
     stats->MCS.short_gi = ratetbl->short_gi;
 }
 
+v_U16_t vos_get_rate_from_rateidx(uint32 rateindex)
+{
+	v_U16_t rate = 0;
+
+	if (rateindex < STATS_MAX_RATE_INDEX)
+		rate = rateidx_to_rate_bw_preamble_sgi_table[rateindex].rate;
+
+	return rate;
+}
+
 bool vos_isPktStatsEnabled(void)
 {
     bool value;