Explorar el Código

qcacld-3.0: Cache deleted station's information in case of SAP

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: 2126182
Ashish Kumar Dhanotiya hace 7 años
padre
commit
443d31f5f8

+ 24 - 1
core/hdd/inc/wlan_hdd_assoc.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -378,4 +378,27 @@ static inline void hdd_save_gtk_params(struct hdd_adapter *adapter,
 }
 #endif
 
+/**
+ * hdd_copy_ht_caps()- copy ht caps info from roam ht caps
+ * info to source ht_cap info of type ieee80211_ht_cap.
+ * @hdd_ht_cap: pointer to Source ht_cap info of type ieee80211_ht_cap
+ * @roam_ht_cap: pointer to roam ht_caps info
+ *
+ * Return: None
+ */
+
+void hdd_copy_ht_caps(struct ieee80211_ht_cap *hdd_ht_cap,
+		      tDot11fIEHTCaps *roam_ht_cap);
+
+/**
+ * hdd_copy_vht_caps()- copy vht caps info from roam vht caps
+ * info to source vht_cap info of type ieee80211_vht_cap.
+ * @hdd_vht_cap: pointer to Source vht_cap info of type ieee80211_vht_cap
+ * @roam_vht_cap: pointer to roam vht_caps info
+ *
+ * Return: None
+ */
+void hdd_copy_vht_caps(struct ieee80211_vht_cap *hdd_vht_cap,
+		       tDot11fIEVHTCaps *roam_vht_cap);
+
 #endif

+ 21 - 0
core/hdd/inc/wlan_hdd_main.h

@@ -56,6 +56,7 @@
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <net/cfg80211.h>
+#include <linux/ieee80211.h>
 #include <qdf_list.h>
 #include <qdf_types.h>
 #include "sir_mac_prot_def.h"
@@ -821,6 +822,13 @@ struct hdd_station_info {
 	uint8_t max_mcs_idx;
 	uint8_t rx_mcs_map;
 	uint8_t tx_mcs_map;
+	uint32_t freq;
+	bool ht_present;
+	bool vht_present;
+	struct ieee80211_ht_cap ht_caps;
+	struct ieee80211_vht_cap vht_caps;
+	uint32_t reason_code;
+	int8_t rssi;
 };
 
 /**
@@ -1082,6 +1090,7 @@ struct hdd_adapter {
 	/** Per-station structure */
 	spinlock_t sta_info_lock;        /* To protect access to station Info */
 	struct hdd_station_info sta_info[WLAN_MAX_STA_COUNT];
+	struct hdd_station_info cache_sta_info[WLAN_MAX_STA_COUNT];
 
 
 #ifdef FEATURE_WLAN_WAPI
@@ -2837,6 +2846,18 @@ void hdd_pld_ipa_uc_shutdown_pipes(void);
  * Return: per_index_score within the max limit
  */
 uint32_t hdd_limit_max_per_index_score(uint32_t per_index_score);
+/**
+ * hdd_get_stainfo() - get stainfo for the specified peer
+ * @astainfo: array of the station info in which the sta info
+ * corresponding to mac_addr needs to be searched
+ * @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_station_info *hdd_get_stainfo(struct hdd_station_info *astainfo,
+					 struct qdf_mac_addr mac_addr);
 
 int hdd_driver_memdump_init(void);
 void hdd_driver_memdump_deinit(void);

+ 10 - 28
core/hdd/src/wlan_hdd_assoc.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -349,19 +349,10 @@ static int hdd_add_beacon_filter(struct hdd_adapter *adapter)
 	return 0;
 }
 
-/**
- * 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
- *
- * Return: None
- */
-static void hdd_copy_ht_caps(struct hdd_station_ctx *hdd_sta_ctx,
-				     struct csr_roam_info *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;
 
 	qdf_mem_zero(hdd_ht_cap, sizeof(struct ieee80211_ht_cap));
@@ -543,20 +534,9 @@ static void hdd_copy_ht_caps(struct hdd_station_ctx *hdd_sta_ctx,
 	(0x03800000 >> VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK_SHIFT)
 #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
- *
- * Return: None
- */
-static void hdd_copy_vht_caps(struct hdd_station_ctx *hdd_sta_ctx,
-				     struct csr_roam_info *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;
 
 	qdf_mem_zero(hdd_vht_cap, sizeof(struct ieee80211_vht_cap));
@@ -811,13 +791,15 @@ static void hdd_save_bss_info(struct hdd_adapter *adapter,
 		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;
 	}

+ 12 - 15
core/hdd/src/wlan_hdd_cfg80211.c

@@ -4925,26 +4925,19 @@ fail:
 	return -EINVAL;
 }
 
-/**
- * hdd_get_stainfo() - get stainfo for the specified peer
- * @adapter: hostapd interface
- * @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
- */
-static struct hdd_station_info *hdd_get_stainfo(struct hdd_adapter *adapter,
-					   struct qdf_mac_addr mac_addr)
+struct hdd_station_info *hdd_get_stainfo(struct hdd_station_info *astainfo,
+					 struct qdf_mac_addr mac_addr)
 {
 	struct hdd_station_info *stainfo = NULL;
 	int i;
 
 	for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
-		if (!qdf_mem_cmp(&adapter->sta_info[i].sta_mac,
+		if (!qdf_mem_cmp(&astainfo[i].sta_mac,
 				 &mac_addr,
-				 QDF_MAC_ADDR_SIZE))
-			stainfo = &adapter->sta_info[i];
+				 QDF_MAC_ADDR_SIZE)) {
+			stainfo = &astainfo[i];
+			break;
+		}
 	}
 
 	return stainfo;
@@ -4980,7 +4973,8 @@ static int hdd_get_station_remote(struct hdd_context *hdd_ctx,
 				  struct hdd_adapter *adapter,
 				  struct qdf_mac_addr mac_addr)
 {
-	struct hdd_station_info *stainfo = hdd_get_stainfo(adapter, mac_addr);
+	struct hdd_station_info *stainfo = hdd_get_stainfo(adapter->sta_info,
+						    mac_addr);
 	struct sk_buff *skb = NULL;
 	struct sir_peer_info_ext peer_info;
 	uint32_t nl_buf_len;
@@ -18936,6 +18930,9 @@ int __wlan_hdd_cfg80211_del_station(struct wiphy *wiphy,
 					SME_CMD_TIMEOUT_VALUE);
 			if (!QDF_IS_STATUS_SUCCESS(qdf_status))
 				hdd_warn("Deauth wait time expired");
+
+			adapter->cache_sta_info[staId].reason_code =
+				pDelStaParams->reason_code;
 		}
 	}
 

+ 68 - 10
core/hdd/src/wlan_hdd_hostapd.c

@@ -1405,9 +1405,25 @@ static int calcuate_max_phy_rate(int mode, int nss, int ch_width,
  *
  * Return: None.
  */
-static void hdd_fill_station_info(struct hdd_station_info *stainfo,
+static void hdd_fill_station_info(struct hdd_adapter *adapter,
 				  tSap_StationAssocReassocCompleteEvent *event)
 {
+	struct hdd_station_info *stainfo;
+	uint8_t i = 0;
+
+	if (event->staId >= WLAN_MAX_STA_COUNT) {
+		hdd_err("invalid sta id");
+		return;
+	}
+
+	stainfo = &adapter->sta_info[event->staId];
+
+	if (!stainfo) {
+		hdd_err("invalid stainfo");
+		return;
+	}
+
+	stainfo->freq = cds_chan_to_freq(event->chan_info.chan_id);
 	stainfo->sta_type = event->staType;
 	stainfo->nss = event->chan_info.nss;
 	stainfo->rate_flags = event->chan_info.rate_flags;
@@ -1434,6 +1450,40 @@ static void hdd_fill_station_info(struct hdd_station_info *stainfo,
 				      stainfo->rx_mcs_map);
 	/* expect max_phy_rate report in kbps */
 	stainfo->max_phy_rate *= 100;
+
+	if (event->vht_caps.present) {
+		stainfo->vht_present = true;
+		hdd_copy_vht_caps(&stainfo->vht_caps, &event->vht_caps);
+	}
+	if (event->ht_caps.present) {
+		stainfo->ht_present = true;
+		hdd_copy_ht_caps(&stainfo->ht_caps, &event->ht_caps);
+	}
+
+	while (i < WLAN_MAX_STA_COUNT) {
+		if (!qdf_mem_cmp(adapter->cache_sta_info[i].sta_mac.bytes,
+				 event->staMac.bytes,
+				 QDF_MAC_ADDR_SIZE)) {
+			qdf_mem_zero(&adapter->cache_sta_info[i],
+				     sizeof(*stainfo));
+			break;
+		}
+		i++;
+	}
+	if (i >= WLAN_MAX_STA_COUNT) {
+		i = 0;
+		while (i < WLAN_MAX_STA_COUNT) {
+			if (adapter->cache_sta_info[i].in_use != TRUE)
+				break;
+			i++;
+		}
+	}
+	if (i < WLAN_MAX_STA_COUNT)
+		qdf_mem_copy(&adapter->cache_sta_info[i],
+			     stainfo, sizeof(struct hdd_station_info));
+	else
+		hdd_debug("reached max staid, stainfo can't be cached");
+
 	hdd_debug("cap %d %d %d %d %d %d %d %d %d %x %d",
 		  stainfo->ampdu,
 		  stainfo->sgi_enable,
@@ -1529,6 +1579,8 @@ QDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent,
 	struct ch_params sap_ch_param = {0};
 	eCsrPhyMode phy_mode;
 	bool legacy_phymode;
+	tSap_StationDisassocCompleteEvent *disassoc_comp;
+	struct hdd_station_info *stainfo;
 
 	dev = (struct net_device *)usrDataForCallback;
 	if (!dev) {
@@ -2027,13 +2079,8 @@ QDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent,
 		}
 
 		staId = event->staId;
-		if (QDF_IS_STATUS_SUCCESS(qdf_status)) {
-			hdd_fill_station_info(
-				&adapter->sta_info[staId],
-				event);
-			hdd_debug("hdd_hostapd_sap_event_cb, StaID: %d, Type: %d",
-			      staId, adapter->sta_info[staId].sta_type);
-		}
+		if (QDF_IS_STATUS_SUCCESS(qdf_status))
+			hdd_fill_station_info(adapter, event);
 
 		if (hdd_ipa_is_enabled(hdd_ctx)) {
 			status = hdd_ipa_wlan_evt(adapter,
@@ -2148,12 +2195,22 @@ QDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent,
 		break;
 
 	case eSAP_STA_DISASSOC_EVENT:
+		disassoc_comp =
+			&pSapEvent->sapevt.sapStationDisassocCompleteEvent;
 		memcpy(wrqu.addr.sa_data,
-		       &pSapEvent->sapevt.sapStationDisassocCompleteEvent.
-		       staMac, QDF_MAC_ADDR_SIZE);
+		       &disassoc_comp->staMac, QDF_MAC_ADDR_SIZE);
 		hdd_notice(" disassociated " MAC_ADDRESS_STR,
 		       MAC_ADDR_ARRAY(wrqu.addr.sa_data));
 
+		stainfo = hdd_get_stainfo(adapter->cache_sta_info,
+					  disassoc_comp->staMac);
+		if (stainfo) {
+			stainfo->rssi = disassoc_comp->rssi;
+			stainfo->tx_rate = disassoc_comp->tx_rate;
+			stainfo->rx_rate = disassoc_comp->rx_rate;
+			stainfo->reason_code = disassoc_comp->reason_code;
+		}
+
 		qdf_status = qdf_event_set(&hostapd_state->qdf_sta_disassoc_event);
 		if (!QDF_IS_STATUS_SUCCESS(qdf_status))
 			hdd_err("Station Deauth event Set failed");
@@ -4672,6 +4729,7 @@ static __iw_softap_disassoc_sta(struct net_device *dev,
 			(SIR_MAC_MGMT_DISASSOC >> 4),
 			&del_sta_params);
 	hdd_softap_sta_disassoc(adapter, &del_sta_params);
+
 	EXIT();
 	return 0;
 }

+ 14 - 0
core/hdd/src/wlan_hdd_main.c

@@ -10605,12 +10605,26 @@ QDF_STATUS hdd_softap_sta_deauth(struct hdd_adapter *adapter,
 void hdd_softap_sta_disassoc(struct hdd_adapter *adapter,
 			     struct csr_del_sta_params *pDelStaParams)
 {
+	struct sir_peer_sta_info peer_sta_info;
+	struct hdd_station_info *stainfo;
 	ENTER();
 
 	/* Ignore request to disassoc bcmc station */
 	if (pDelStaParams->peerMacAddr.bytes[0] & 0x1)
 		return;
 
+	wlan_hdd_get_peer_rssi(adapter, &pDelStaParams->peerMacAddr,
+			       &peer_sta_info);
+	stainfo = hdd_get_stainfo(adapter->cache_sta_info,
+				  pDelStaParams->peerMacAddr);
+	if (stainfo) {
+		stainfo->rssi = peer_sta_info.info[0].rssi;
+		stainfo->tx_rate = peer_sta_info.info[0].tx_rate;
+		stainfo->rx_rate = peer_sta_info.info[0].rx_rate;
+	}
+
+	stainfo->reason_code = pDelStaParams->reason_code;
+
 	wlansap_disassoc_sta(WLAN_HDD_GET_SAP_CTX_PTR(adapter),
 			     pDelStaParams);
 }

+ 4 - 4
core/hdd/src/wlan_hdd_wext.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -3857,9 +3857,8 @@ static void hdd_get_peer_rssi_cb(struct sir_peer_info_resp *sta_rssi,
 	struct sir_peer_info *rssi_info;
 	uint8_t peer_num;
 
-	if ((!sta_rssi) || (!context)) {
-		hdd_err("Bad param, sta_rssi [%pK] context [%pK]",
-			sta_rssi, context);
+	if ((!sta_rssi)) {
+		hdd_err("Bad param, sta_rssi [%pK]", sta_rssi);
 		return;
 	}
 
@@ -3887,6 +3886,7 @@ static void hdd_get_peer_rssi_cb(struct sir_peer_info_resp *sta_rssi,
 
 	hdd_request_complete(request);
 	hdd_request_put(request);
+
 }
 
 int wlan_hdd_get_peer_rssi(struct hdd_adapter *adapter,

+ 4 - 1
core/mac/inc/ani_global.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -959,6 +959,9 @@ typedef struct sAniSirGlobal {
 	void (*chan_info_cb)(struct scan_chan_info *chan_info);
 	uint32_t rx_packet_drop_counter;
 	bool ignore_assoc_disallowed;
+	uint32_t peer_rssi;
+	uint32_t peer_txrate;
+	uint32_t peer_rxrate;
 } tAniSirGlobal;
 
 

+ 3 - 1
core/mac/inc/sir_api.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -1410,6 +1410,8 @@ typedef struct sSirSmeAssocInd {
 	uint8_t tx_mcs_map;
 	/* Extended CSA capability of station */
 	uint8_t ecsa_capable;
+	tDot11fIEHTCaps HTCaps;
+	tDot11fIEVHTCaps VHTCaps;
 } tSirSmeAssocInd, *tpSirSmeAssocInd;
 
 /* / Definition for Association confirm */

+ 24 - 5
core/mac/src/pe/lim/lim_process_assoc_req_frame.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -2077,9 +2077,12 @@ static void lim_fill_assoc_ind_wapi_info(tpAniSirGlobal mac_ctx,
 static void lim_fill_assoc_ind_vht_info(tpAniSirGlobal mac_ctx,
 					tpPESession session_entry,
 					tpSirAssocReq assoc_req,
-					tpLimMlmAssocInd assoc_ind)
+					tpLimMlmAssocInd assoc_ind,
+					tpDphHashNode sta_ds)
 {
 	uint8_t chan;
+	uint8_t i;
+	bool nw_type_11b = true;
 
 	if (session_entry->limRFBand == BAND_2G) {
 		if (session_entry->vhtCapability && assoc_req->VHTCaps.present)
@@ -2087,8 +2090,19 @@ static void lim_fill_assoc_ind_vht_info(tpAniSirGlobal mac_ctx,
 		else if (session_entry->htCapability
 			    && assoc_req->HTCaps.present)
 			assoc_ind->chan_info.info = MODE_11NG_HT20;
-		else
-			assoc_ind->chan_info.info = MODE_11G;
+		else {
+			for (i = 0; i < SIR_NUM_11A_RATES; i++) {
+				if (sirIsArate(sta_ds->
+					       supportedRates.llaRates[i]
+					       & 0x7F)) {
+					assoc_ind->chan_info.info = MODE_11G;
+					nw_type_11b = false;
+					break;
+				}
+			}
+			if (nw_type_11b)
+				assoc_ind->chan_info.info = MODE_11B;
+		}
 		return;
 	}
 
@@ -2311,6 +2325,9 @@ void lim_send_mlm_assoc_ind(tpAniSirGlobal mac_ctx,
 		 * processing in hostapd
 		 */
 		if (assoc_req->HTCaps.present) {
+			qdf_mem_copy(&assoc_ind->ht_caps, &assoc_req->HTCaps,
+				     sizeof(tDot11fIEHTCaps));
+
 			rsn_len = assoc_ind->addIE.length;
 			if (assoc_ind->addIE.length + DOT11F_IE_HTCAPS_MIN_LEN
 				+ 2 < SIR_MAC_MAX_IE_LENGTH) {
@@ -2423,8 +2440,10 @@ void lim_send_mlm_assoc_ind(tpAniSirGlobal mac_ctx,
 			ext_chan_switch;
 
 		/* updates VHT information in assoc indication */
+		 qdf_mem_copy(&assoc_ind->vht_caps, &assoc_req->VHTCaps,
+			      sizeof(tDot11fIEVHTCaps));
 		lim_fill_assoc_ind_vht_info(mac_ctx, session_entry, assoc_req,
-			assoc_ind);
+					    assoc_ind, sta_ds);
 		lim_post_sme_message(mac_ctx, LIM_MLM_ASSOC_IND,
 			 (uint32_t *) assoc_ind);
 		qdf_mem_free(assoc_ind);

+ 6 - 1
core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -784,6 +784,11 @@ lim_fill_assoc_ind_params(tpAniSirGlobal mac_ctx,
 	sme_assoc_ind->rx_mcs_map = assoc_ind->rx_mcs_map;
 	sme_assoc_ind->tx_mcs_map = assoc_ind->tx_mcs_map;
 	sme_assoc_ind->ecsa_capable = assoc_ind->ecsa_capable;
+
+	if (assoc_ind->ht_caps.present)
+		sme_assoc_ind->HTCaps = assoc_ind->ht_caps;
+	if (assoc_ind->vht_caps.present)
+		sme_assoc_ind->VHTCaps = assoc_ind->vht_caps;
 }
 
 /**

+ 3 - 0
core/mac/src/pe/lim/lim_types.h

@@ -278,6 +278,9 @@ typedef struct sLimMlmAssocInd {
 	uint8_t rx_mcs_map;
 	uint8_t tx_mcs_map;
 	uint8_t ecsa_capable;
+
+	tDot11fIEHTCaps ht_caps;
+	tDot11fIEVHTCaps vht_caps;
 } tLimMlmAssocInd, *tpLimMlmAssocInd;
 
 typedef struct sLimMlmReassocReq {

+ 6 - 0
core/sap/inc/sap_api.h

@@ -295,6 +295,8 @@ typedef struct sap_StationAssocReassocCompleteEvent_s {
 	uint8_t rx_mcs_map;
 	uint8_t tx_mcs_map;
 	uint8_t ecsa_capable;
+	tDot11fIEHTCaps ht_caps;
+	tDot11fIEVHTCaps vht_caps;
 } tSap_StationAssocReassocCompleteEvent;
 
 typedef struct sap_StationDisassocCompleteEvent_s {
@@ -302,7 +304,11 @@ typedef struct sap_StationDisassocCompleteEvent_s {
 	uint8_t staId;          /* STAID should not be used */
 	uint8_t status;
 	uint32_t statusCode;
+	uint32_t reason_code;
 	eSapDisassocReason reason;
+	int rssi;
+	int tx_rate;
+	int rx_rate;
 } tSap_StationDisassocCompleteEvent;
 
 typedef struct sap_StationSetKeyCompleteEvent_s {

+ 10 - 2
core/sap/src/sap_fsm.c

@@ -2469,10 +2469,14 @@ QDF_STATUS sap_signal_hdd_event(struct sap_context *sap_ctx,
 		reassoc_complete->rx_mcs_map = csr_roaminfo->rx_mcs_map;
 		reassoc_complete->tx_mcs_map = csr_roaminfo->tx_mcs_map;
 		reassoc_complete->ecsa_capable = csr_roaminfo->ecsa_capable;
+		if (csr_roaminfo->ht_caps.present)
+			reassoc_complete->ht_caps = csr_roaminfo->ht_caps;
+		if (csr_roaminfo->vht_caps.present)
+			reassoc_complete->vht_caps = csr_roaminfo->vht_caps;
+
 		break;
 
 	case eSAP_STA_DISASSOC_EVENT:
-
 		if (!csr_roaminfo) {
 			QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR,
 				  FL("Invalid CSR Roam Info"));
@@ -2485,13 +2489,17 @@ QDF_STATUS sap_signal_hdd_event(struct sap_context *sap_ctx,
 		qdf_copy_macaddr(&disassoc_comp->staMac,
 				 &csr_roaminfo->peerMac);
 		disassoc_comp->staId = csr_roaminfo->staId;
-		if (csr_roaminfo->reasonCode == eCSR_ROAM_RESULT_FORCED)
+		if (csr_roaminfo->disassoc_reason == eCSR_ROAM_RESULT_FORCED)
 			disassoc_comp->reason = eSAP_USR_INITATED_DISASSOC;
 		else
 			disassoc_comp->reason = eSAP_MAC_INITATED_DISASSOC;
 
 		disassoc_comp->statusCode = csr_roaminfo->statusCode;
 		disassoc_comp->status = (eSapStatus) context;
+		disassoc_comp->rssi = csr_roaminfo->rssi;
+		disassoc_comp->rx_rate = csr_roaminfo->rx_rate;
+		disassoc_comp->tx_rate = csr_roaminfo->tx_rate;
+		disassoc_comp->reason_code = csr_roaminfo->reasonCode;
 		break;
 
 	case eSAP_STA_SET_KEY_EVENT:

+ 10 - 1
core/sme/inc/csr_api.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -1415,6 +1415,9 @@ struct csr_roam_info {
 	tSirResultCodes statusCode;
 	/* this'd be our own defined or sent from otherBSS(per 802.11spec) */
 	uint32_t reasonCode;
+
+	uint8_t disassoc_reason;
+
 	uint8_t staId;         /* Peer stationId when connected */
 	/*
 	 * The DPU signatures will be sent eventually to TL to help it
@@ -1523,6 +1526,9 @@ struct csr_roam_info {
 	uint16_t fils_seq_num;
 	struct fils_join_rsp_params *fils_join_rsp;
 #endif
+	int rssi;
+	int tx_rate;
+	int rx_rate;
 };
 
 typedef struct tagCsrFreqScanInfo {
@@ -1563,6 +1569,9 @@ typedef struct sSirSmeAssocIndToUpperLayerCnf {
 	uint8_t tx_mcs_map;
 	/* Extended capabilities of STA */
 	uint8_t              ecsa_capable;
+
+	tDot11fIEHTCaps ht_caps;
+	tDot11fIEVHTCaps vht_caps;
 } tSirSmeAssocIndToUpperLayerCnf, *tpSirSmeAssocIndToUpperLayerCnf;
 
 typedef struct tagCsrSummaryStatsInfo {

+ 13 - 1
core/sme/inc/sme_api.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -1737,6 +1737,18 @@ QDF_STATUS sme_set_bt_activity_info_cb(tHalHandle hal,
 
 QDF_STATUS sme_set_smps_cfg(uint32_t vdev_id, uint32_t param_id,
 				uint32_t param_val);
+
+/**
+ * sme_get_peer_stats() - sme api to post peer info request
+ * @mac: mac handle
+ * @req: peer info request struct send to wma
+ *
+ * Return: QDF_STATUS_SUCCESS or non-zero on failure
+ */
+
+QDF_STATUS sme_get_peer_stats(tpAniSirGlobal mac,
+			      struct sir_peer_info_req req);
+
 /**
  * sme_get_peer_info() - sme api to get peer info
  * @hal: hal handle for getting global mac struct

+ 48 - 1
core/sme/src/common/sme_api.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -1954,6 +1954,8 @@ QDF_STATUS sme_process_msg(tHalHandle hHal, struct scheduler_msg *pMsg)
 {
 	QDF_STATUS status = QDF_STATUS_E_FAILURE;
 	tpAniSirGlobal pMac = PMAC_STRUCT(hHal);
+	struct sir_peer_info *peer_stats;
+	struct sir_peer_info_resp *peer_info_rsp;
 
 	if (pMsg == NULL) {
 		sme_err("Empty message for SME");
@@ -2141,6 +2143,17 @@ QDF_STATUS sme_process_msg(tHalHandle hHal, struct scheduler_msg *pMsg)
 		if (pMac->sme.pget_peer_info_ind_cb)
 			pMac->sme.pget_peer_info_ind_cb(pMsg->bodyptr,
 				pMac->sme.pget_peer_info_cb_context);
+		if (pMsg->bodyptr) {
+			peer_info_rsp = (struct sir_peer_info_resp *)
+							(pMsg->bodyptr);
+			peer_stats = (struct sir_peer_info *)
+							(peer_info_rsp->info);
+			if (peer_stats) {
+				pMac->peer_rssi = peer_stats[0].rssi;
+				pMac->peer_txrate = peer_stats[0].tx_rate;
+				pMac->peer_rxrate = peer_stats[0].rx_rate;
+			}
+		}
 		qdf_mem_free(pMsg->bodyptr);
 		break;
 	case eWNI_SME_GET_PEER_INFO_EXT_IND:
@@ -8581,6 +8594,39 @@ QDF_STATUS sme_get_link_speed(tHalHandle hHal, tSirLinkSpeedInfo *lsReq,
 	return status;
 }
 
+QDF_STATUS sme_get_peer_stats(tpAniSirGlobal mac,
+			      struct sir_peer_info_req req)
+{
+	QDF_STATUS qdf_status;
+	struct scheduler_msg message = {0};
+
+	qdf_status = sme_acquire_global_lock(&mac->sme);
+	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
+		sme_debug("Failed to get Lock");
+		return qdf_status;
+	}
+	/* serialize the req through MC thread */
+	message.bodyptr = qdf_mem_malloc(sizeof(req));
+	if (NULL == message.bodyptr) {
+		QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
+			  "%s: Memory allocation failed.", __func__);
+		sme_release_global_lock(&mac->sme);
+		return QDF_STATUS_E_NOMEM;
+	}
+	qdf_mem_copy(message.bodyptr, &req, sizeof(req));
+	message.type = WMA_GET_PEER_INFO;
+	message.reserved = 0;
+	qdf_status = scheduler_post_msg(QDF_MODULE_ID_WMA, &message);
+	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
+		QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,
+			  "%s: Post get peer info msg fail", __func__);
+		qdf_mem_free(message.bodyptr);
+		qdf_status = QDF_STATUS_E_FAILURE;
+	}
+	sme_release_global_lock(&mac->sme);
+	return qdf_status;
+}
+
 QDF_STATUS sme_get_peer_info(tHalHandle hal, struct sir_peer_info_req req,
 			void *context,
 			void (*callbackfn)(struct sir_peer_info_resp *param,
@@ -8615,6 +8661,7 @@ QDF_STATUS sme_get_peer_info(tHalHandle hal, struct sir_peer_info_req req,
 		}
 		qdf_mem_copy(message.bodyptr, &req, sizeof(req));
 		message.type = WMA_GET_PEER_INFO;
+		message.reserved = 0;
 		qdf_status = scheduler_post_msg(QDF_MODULE_ID_WMA, &message);
 		if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
 			QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR,

+ 48 - 6
core/sme/src/csr/csr_api_roam.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -6816,6 +6816,10 @@ static void csr_roam_process_results_default(tpAniSirGlobal mac_ctx,
 		break;
 	case eCsrForcedDisassocSta:
 	case eCsrForcedDeauthSta:
+		roam_info.rssi = mac_ctx->peer_rssi;
+		roam_info.tx_rate = mac_ctx->peer_txrate;
+		roam_info.rx_rate = mac_ctx->peer_rxrate;
+
 		csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_JOINED,
 			session_id);
 		session = CSR_GET_SESSION(mac_ctx, session_id);
@@ -6826,7 +6830,8 @@ static void csr_roam_process_results_default(tpAniSirGlobal mac_ctx,
 			qdf_mem_copy(roam_info.peerMac.bytes,
 					cmd->u.roamCmd.peerMac,
 					sizeof(tSirMacAddr));
-			roam_info.reasonCode = eCSR_ROAM_RESULT_FORCED;
+			roam_info.reasonCode = cmd->u.roamCmd.reason;
+			roam_info.disassoc_reason = eCSR_ROAM_RESULT_FORCED;
 			roam_info.statusCode = eSIR_SME_SUCCESS;
 			status = csr_roam_call_callback(mac_ctx, session_id,
 					&roam_info, cmd->u.roamCmd.roamId,
@@ -10363,6 +10368,10 @@ void csr_roam_joined_state_msg_processor(tpAniSirGlobal pMac, void *pMsgBuf)
 		roam_info->rx_mcs_map = pUpperLayerAssocCnf->rx_mcs_map;
 		roam_info->tx_mcs_map = pUpperLayerAssocCnf->tx_mcs_map;
 		roam_info->ecsa_capable = pUpperLayerAssocCnf->ecsa_capable;
+		if (pUpperLayerAssocCnf->ht_caps.present)
+			roam_info->ht_caps = pUpperLayerAssocCnf->ht_caps;
+		if (pUpperLayerAssocCnf->vht_caps.present)
+			roam_info->vht_caps = pUpperLayerAssocCnf->vht_caps;
 		if (CSR_IS_INFRA_AP(roam_info->u.pConnectedProfile)) {
 			pMac->roam.roamSession[sessionId].connectState =
 				eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED;
@@ -11209,6 +11218,16 @@ csr_roam_chk_lnk_assoc_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr)
 	qdf_mem_copy(&roam_info_ptr->chan_info,
 		     &pAssocInd->chan_info,
 		     sizeof(tSirSmeChanInfo));
+
+	if (pAssocInd->HTCaps.present)
+		qdf_mem_copy(&roam_info_ptr->ht_caps,
+			     &pAssocInd->HTCaps,
+			     sizeof(tDot11fIEHTCaps));
+	if (pAssocInd->VHTCaps.present)
+		qdf_mem_copy(&roam_info_ptr->vht_caps,
+			     &pAssocInd->VHTCaps,
+			     sizeof(tDot11fIEVHTCaps));
+
 	if (CSR_IS_INFRA_AP(roam_info_ptr->u.pConnectedProfile)) {
 		if (session->pCurRoamProfile &&
 		    CSR_IS_ENC_TYPE_STATIC(
@@ -11364,6 +11383,11 @@ csr_roam_send_disconnect_done_indication(tpAniSirGlobal mac_ctx, tSirSmeRsp
 		roam_info.statusCode = eSIR_SME_STA_NOT_ASSOCIATED;
 		qdf_mem_copy(roam_info.peerMac.bytes, discon_ind->peer_mac,
 			     ETH_ALEN);
+
+		roam_info.rssi = mac_ctx->peer_rssi;
+		roam_info.tx_rate = mac_ctx->peer_txrate;
+		roam_info.rx_rate = mac_ctx->peer_rxrate;
+
 		csr_roam_call_callback(mac_ctx, discon_ind->session_id,
 				       &roam_info, 0, eCSR_ROAM_LOSTLINK,
 				       eCSR_ROAM_RESULT_DISASSOC_IND);
@@ -12656,6 +12680,7 @@ QDF_STATUS csr_roam_lost_link(tpAniSirGlobal pMac, uint32_t sessionId,
 		sme_err("session: %d not found", sessionId);
 		return QDF_STATUS_E_FAILURE;
 	}
+	qdf_mem_set(&roamInfo, sizeof(struct csr_roam_info), 0);
 #ifndef NAPIER_SCAN
 	pSession->fCancelRoaming = false;
 #endif
@@ -12665,22 +12690,34 @@ QDF_STATUS csr_roam_lost_link(tpAniSirGlobal pMac, uint32_t sessionId,
 		pSession->roamingStatusCode = pDisassocIndMsg->statusCode;
 		pSession->joinFailStatusCode.reasonCode =
 			pDisassocIndMsg->reasonCode;
+
+		qdf_copy_macaddr(&roamInfo.peerMac,
+				 &pDisassocIndMsg->peer_macaddr);
 	} else if (eWNI_SME_DEAUTH_IND == type) {
 		result = eCSR_ROAM_RESULT_DEAUTH_IND;
 		pDeauthIndMsg = (tSirSmeDeauthInd *) pSirMsg;
 		pSession->roamingStatusCode = pDeauthIndMsg->statusCode;
 		pSession->joinFailStatusCode.reasonCode =
 			pDeauthIndMsg->reasonCode;
+
+		qdf_copy_macaddr(&roamInfo.peerMac,
+				 &pDeauthIndMsg->peer_macaddr);
+
 	} else {
 		sme_warn("gets an unknown type (%d)", type);
 		result = eCSR_ROAM_RESULT_NONE;
 		pSession->joinFailStatusCode.reasonCode = 1;
 	}
 
-	/* call profile lost link routine here */
-	if (!CSR_IS_INFRA_AP(&pSession->connectedProfile))
-		csr_roam_call_callback(pMac, sessionId, NULL, 0,
-				       eCSR_ROAM_LOSTLINK_DETECTED, result);
+	if (type == eWNI_SME_DISASSOC_IND || type == eWNI_SME_DEAUTH_IND) {
+		struct	sir_peer_info_req req;
+
+		req.sessionid = sessionId;
+		req.peer_macaddr = roamInfo.peerMac;
+		sme_get_peer_stats(pMac, req);
+	}
+	csr_roam_call_callback(pMac, sessionId, NULL, 0,
+			       eCSR_ROAM_LOSTLINK_DETECTED, result);
 
 	if (eWNI_SME_DISASSOC_IND == type)
 		status = csr_send_mb_disassoc_cnf_msg(pMac, pDisassocIndMsg);
@@ -15958,6 +15995,11 @@ QDF_STATUS csr_send_assoc_ind_to_upper_layer_cnf_msg(tpAniSirGlobal pMac,
 		pBuf = (uint8_t *)&pMsg->ecsa_capable;
 		*pBuf = pAssocInd->ecsa_capable;
 
+		if (pAssocInd->HTCaps.present)
+			pMsg->ht_caps = pAssocInd->HTCaps;
+		if (pAssocInd->VHTCaps.present)
+			pMsg->vht_caps = pAssocInd->VHTCaps;
+
 		msgQ.type = eWNI_SME_UPPER_LAYER_ASSOC_CNF;
 		msgQ.bodyptr = pMsg;
 		msgQ.bodyval = 0;