qcacld-3.0: Add new vendor command to get link properties

qcacld-2.0 to qcacld-3.0 propagation

Add support in driver for a new vendor command to get
the link properties nss, rate flags and operating
frequency.

Change-Id: Ie3b8d5b2c3886055d303441c5d8b2f2a0a2719bd
CRs-Fixed: 834199
diff --git a/core/hdd/inc/wlan_hdd_assoc.h b/core/hdd/inc/wlan_hdd_assoc.h
index d9012e5..190e756 100644
--- a/core/hdd/inc/wlan_hdd_assoc.h
+++ b/core/hdd/inc/wlan_hdd_assoc.h
@@ -108,6 +108,8 @@
  * @proxyARPService: proxy arp service
  * @ptk_installed: ptk installed state
  * @gtk_installed: gtk installed state
+ * @nss: number of spatial streams negotiated
+ * @rate_flags: rate flags for current connection
  */
 typedef struct connection_info_s {
 	eConnectionState connState;
@@ -126,6 +128,8 @@
 	uint8_t proxyARPService;
 	bool ptk_installed;
 	bool gtk_installed;
+	uint8_t nss;
+	uint32_t rate_flags;
 } connection_info_t;
 
 /* Forward declarations */
diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h
index e0a8bc1..e069bd2 100644
--- a/core/hdd/inc/wlan_hdd_main.h
+++ b/core/hdd/inc/wlan_hdd_main.h
@@ -704,6 +704,12 @@
 
 	/** The station entry for which Deauth is in progress  */
 	bool isDeauthInProgress;
+
+	/** Number of spatial streams supported */
+	uint8_t   nss;
+
+	/** Rate Flags for this connection */
+	uint32_t  rate_flags;
 } hdd_station_info_t;
 
 struct hdd_ap_ctx_s {
diff --git a/core/hdd/src/wlan_hdd_assoc.c b/core/hdd/src/wlan_hdd_assoc.c
index c534d7e..e65ecd6 100644
--- a/core/hdd/src/wlan_hdd_assoc.c
+++ b/core/hdd/src/wlan_hdd_assoc.c
@@ -388,6 +388,11 @@
 
 			pHddStaCtx->conn_info.proxyARPService =
 				pRoamInfo->u.pConnectedProfile->proxyARPService;
+
+			pHddStaCtx->conn_info.nss = pRoamInfo->chan_info.nss;
+
+			pHddStaCtx->conn_info.rate_flags =
+				pRoamInfo->chan_info.rate_flags;
 		}
 	}
 	/* save the connected BssType */
diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c
index b392482..3ac951b 100644
--- a/core/hdd/src/wlan_hdd_cfg80211.c
+++ b/core/hdd/src/wlan_hdd_cfg80211.c
@@ -4250,6 +4250,197 @@
 	return ret;
 }
 
+static const struct
+nla_policy
+qca_wlan_vendor_attr_policy[QCA_WLAN_VENDOR_ATTR_MAX+1] = {
+	[QCA_WLAN_VENDOR_ATTR_MAC_ADDR] = { .type = NLA_UNSPEC },
+};
+
+/**
+ * __wlan_hdd_cfg80211_get_link_properties() - Get link properties
+ * @wiphy: WIPHY structure pointer
+ * @wdev: Wireless device structure pointer
+ * @data: Pointer to the data received
+ * @data_len: Length of the data received
+ *
+ * This function is used to get link properties like nss, rate flags and
+ * operating frequency for the active connection with the given peer.
+ *
+ * Return: 0 on success and errno on failure
+ */
+static int __wlan_hdd_cfg80211_get_link_properties(struct wiphy *wiphy,
+						   struct wireless_dev *wdev,
+						   const void *data,
+						   int data_len)
+{
+	hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
+	struct net_device *dev = wdev->netdev;
+	hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
+	hdd_station_ctx_t *hdd_sta_ctx;
+	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX+1];
+	uint8_t peer_mac[CDF_MAC_ADDR_SIZE];
+	uint32_t sta_id;
+	struct sk_buff *reply_skb;
+	uint32_t rate_flags = 0;
+	uint8_t nss;
+	uint8_t final_rate_flags = 0;
+	uint32_t freq;
+
+	ENTER();
+
+	if (CDF_FTM_MODE == hdd_get_conparam()) {
+		hdd_err("Command not allowed in FTM mode");
+		return -EPERM;
+	}
+
+	if (0 != wlan_hdd_validate_context(hdd_ctx))
+		return -EINVAL;
+
+	if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MAX, data, data_len,
+		      qca_wlan_vendor_attr_policy)) {
+		hddLog(CDF_TRACE_LEVEL_ERROR, FL("Invalid attribute"));
+		return -EINVAL;
+	}
+
+	if (!tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR]) {
+		hddLog(CDF_TRACE_LEVEL_ERROR,
+		       FL("Attribute peerMac not provided for mode=%d"),
+		       adapter->device_mode);
+		return -EINVAL;
+	}
+
+	cdf_mem_copy(peer_mac, nla_data(tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR]),
+		     CDF_MAC_ADDR_SIZE);
+	hddLog(CDF_TRACE_LEVEL_INFO,
+	       FL("peerMac="MAC_ADDRESS_STR" for device_mode:%d"),
+	       MAC_ADDR_ARRAY(peer_mac), adapter->device_mode);
+
+	if (adapter->device_mode == WLAN_HDD_INFRA_STATION ||
+	    adapter->device_mode == WLAN_HDD_P2P_CLIENT) {
+		hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
+		if ((hdd_sta_ctx->conn_info.connState !=
+			eConnectionState_Associated) ||
+		    !cdf_mem_compare(hdd_sta_ctx->conn_info.bssId.bytes,
+			peer_mac, CDF_MAC_ADDR_SIZE)) {
+			hddLog(CDF_TRACE_LEVEL_ERROR,
+			       FL("Not Associated to mac "MAC_ADDRESS_STR),
+			       MAC_ADDR_ARRAY(peer_mac));
+			return -EINVAL;
+		}
+
+		nss  = hdd_sta_ctx->conn_info.nss;
+		freq = cds_chan_to_freq(
+				hdd_sta_ctx->conn_info.operationChannel);
+		rate_flags = hdd_sta_ctx->conn_info.rate_flags;
+	} else if (adapter->device_mode == WLAN_HDD_P2P_GO ||
+		   adapter->device_mode == WLAN_HDD_SOFTAP) {
+
+		for (sta_id = 0; sta_id < WLAN_MAX_STA_COUNT; sta_id++) {
+			if (adapter->aStaInfo[sta_id].isUsed &&
+			    !cdf_is_macaddr_broadcast(
+				&adapter->aStaInfo[sta_id].macAddrSTA) &&
+			    cdf_mem_compare(
+				&adapter->aStaInfo[sta_id].macAddrSTA.bytes,
+				peer_mac, CDF_MAC_ADDR_SIZE))
+				break;
+		}
+
+		if (WLAN_MAX_STA_COUNT == sta_id) {
+			hddLog(CDF_TRACE_LEVEL_ERROR,
+			       FL("No active peer with mac="MAC_ADDRESS_STR),
+			       MAC_ADDR_ARRAY(peer_mac));
+			return -EINVAL;
+		}
+
+		nss = adapter->aStaInfo[sta_id].nss;
+		freq = cds_chan_to_freq(
+			(WLAN_HDD_GET_AP_CTX_PTR(adapter))->operatingChannel);
+		rate_flags = adapter->aStaInfo[sta_id].rate_flags;
+	} else {
+		hddLog(CDF_TRACE_LEVEL_ERROR,
+		       FL("Not Associated! with mac "MAC_ADDRESS_STR),
+		       MAC_ADDR_ARRAY(peer_mac));
+		return -EINVAL;
+	}
+
+	if (!(rate_flags & eHAL_TX_RATE_LEGACY)) {
+		if (rate_flags & eHAL_TX_RATE_VHT80) {
+			final_rate_flags |= RATE_INFO_FLAGS_VHT_MCS;
+			final_rate_flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
+		} else if (rate_flags & eHAL_TX_RATE_VHT40) {
+			final_rate_flags |= RATE_INFO_FLAGS_VHT_MCS;
+			final_rate_flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+		} else if (rate_flags & eHAL_TX_RATE_VHT20) {
+			final_rate_flags |= RATE_INFO_FLAGS_VHT_MCS;
+		} else if (rate_flags &
+				(eHAL_TX_RATE_HT20 | eHAL_TX_RATE_HT40)) {
+			final_rate_flags |= RATE_INFO_FLAGS_MCS;
+			if (rate_flags & eHAL_TX_RATE_HT40)
+				final_rate_flags |=
+					RATE_INFO_FLAGS_40_MHZ_WIDTH;
+		}
+
+		if (rate_flags & eHAL_TX_RATE_SGI) {
+			if (!(final_rate_flags & RATE_INFO_FLAGS_VHT_MCS))
+				final_rate_flags |= RATE_INFO_FLAGS_MCS;
+			final_rate_flags |= RATE_INFO_FLAGS_SHORT_GI;
+		}
+	}
+
+	reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
+			sizeof(u8) + sizeof(u8) + sizeof(u32) + NLMSG_HDRLEN);
+
+	if (NULL == reply_skb) {
+		hddLog(CDF_TRACE_LEVEL_ERROR,
+		       FL("getLinkProperties: skb alloc failed"));
+		return -EINVAL;
+	}
+
+	if (nla_put_u8(reply_skb,
+		QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_NSS,
+		nss) ||
+	    nla_put_u8(reply_skb,
+		QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_RATE_FLAGS,
+		final_rate_flags) ||
+	    nla_put_u32(reply_skb,
+		QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_FREQ,
+		freq)) {
+		hddLog(CDF_TRACE_LEVEL_ERROR, FL("nla_put failed"));
+		kfree_skb(reply_skb);
+		return -EINVAL;
+	}
+
+	return cfg80211_vendor_cmd_reply(reply_skb);
+}
+
+/**
+ * wlan_hdd_cfg80211_get_link_properties() - Wrapper function to get link
+ * properties.
+ * @wiphy: WIPHY structure pointer
+ * @wdev: Wireless device structure pointer
+ * @data: Pointer to the data received
+ * @data_len: Length of the data received
+ *
+ * This function is used to get link properties like nss, rate flags and
+ * operating frequency for the active connection with the given peer.
+ *
+ * Return: 0 on success and errno on failure
+ */
+static int wlan_hdd_cfg80211_get_link_properties(struct wiphy *wiphy,
+						 struct wireless_dev *wdev,
+						 const void *data,
+						 int data_len)
+{
+	int ret = 0;
+
+	cds_ssr_protect(__func__);
+	ret = __wlan_hdd_cfg80211_get_link_properties(wiphy,
+			wdev, data, data_len);
+	cds_ssr_unprotect(__func__);
+
+	return ret;
+}
+
 const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = {
 	{
 		.info.vendor_id = QCA_NL80211_VENDOR_ID,
@@ -4663,6 +4854,14 @@
 				 WIPHY_VENDOR_CMD_NEED_RUNNING,
 		.doit = wlan_hdd_cfg80211_dcc_update_ndl
 	},
+	{
+		.info.vendor_id = QCA_NL80211_VENDOR_ID,
+		.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES,
+		.flags = WIPHY_VENDOR_CMD_NEED_WDEV |
+			 WIPHY_VENDOR_CMD_NEED_NETDEV |
+			 WIPHY_VENDOR_CMD_NEED_RUNNING,
+		.doit = wlan_hdd_cfg80211_get_link_properties
+	},
 };
 
 /*
diff --git a/core/hdd/src/wlan_hdd_cfg80211.h b/core/hdd/src/wlan_hdd_cfg80211.h
index 28fc309..df5e5aa 100644
--- a/core/hdd/src/wlan_hdd_cfg80211.h
+++ b/core/hdd/src/wlan_hdd_cfg80211.h
@@ -245,6 +245,7 @@
  * @QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION: set wifi config
  * @QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_CONFIGURATION: get wifi config
  * @QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET: get logging features
+ * @QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES: get link properties
  * @QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN: venodr scan command
  * @QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE: vendor scan complete
  */
@@ -346,6 +347,9 @@
 	QCA_NL80211_VENDOR_SUBCMD_DCC_UPDATE_NDL = 99,
 	QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT = 100,
 
+	/* subcommand to get link properties */
+	QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES = 101,
+
 	/* DBS subcommands */
 	QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST = 103,
 	QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL = 104,
@@ -604,6 +608,8 @@
  * @QCA_WLAN_VENDOR_ATTR_STATS_EXT: Ext stats attribute which is used by
  *	QCA_NL80211_VENDOR_SUBCMD_STATS_EXT
  * @QCA_WLAN_VENDOR_ATTR_IFINDEX: After IFINDEX
+ * @QCA_WLAN_VENDOR_ATTR_MAC_ADDR: MAC Address attribute which is used by
+ *	QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES
  * @QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS: Supported Features
  * @QCA_WLAN_VENDOR_ATTR_AFTER_LAST: After last
  * @QCA_WLAN_VENDOR_ATTR_MAX: Max value
@@ -614,6 +620,7 @@
 	QCA_WLAN_VENDOR_ATTR_NAN = 2,
 	QCA_WLAN_VENDOR_ATTR_STATS_EXT = 3,
 	QCA_WLAN_VENDOR_ATTR_IFINDEX = 4,
+	QCA_WLAN_VENDOR_ATTR_MAC_ADDR = 6,
 	QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS = 7,
 	QCA_WLAN_VENDOR_ATTR_CONCURRENCY_CAPA = 9,
 	QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_2_4_BAND = 10,
@@ -1805,6 +1812,31 @@
 };
 
 /**
+ * enum qca_wlan_vendor_attr_link_properties - link properties
+ *
+ * @QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_INVALID: Invalid initial value
+ * @QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_NSS: Unsigned 8-bit value to
+ *	specify the number of spatial streams negotiated
+ * @QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_RATE_FLAGS: Unsigned 8-bit value
+ *	to specify negotiated rate flags i.e. ht, vht and channel width
+ * @QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_FREQ: Unsigned 32bit value to
+ *	specify the operating frequency
+ * @QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_AFTER_LAST: after last
+ * @QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_MAX: max value
+ */
+enum qca_wlan_vendor_attr_link_properties {
+	QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_NSS = 1,
+	QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_RATE_FLAGS = 2,
+	QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_FREQ = 3,
+
+	/* KEEP LAST */
+	QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_MAX =
+		QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_AFTER_LAST - 1,
+};
+
+/**
  * enum qca_wlan_vendor_features - vendor device/driver features
  * @QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD: Device supports key
  * management offload, a mechanism where the station's firmware
diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c
index 2afa2c7..fadaedd 100644
--- a/core/hdd/src/wlan_hdd_hostapd.c
+++ b/core/hdd/src/wlan_hdd_hostapd.c
@@ -1232,6 +1232,19 @@
 				       MAC_ADDR_ARRAY(wrqu.addr.sa_data));
 		}
 
+		staId =
+		   pSapEvent->sapevt.sapStationAssocReassocCompleteEvent.staId;
+		if (CDF_IS_STATUS_SUCCESS(cdf_status)) {
+			pHostapdAdapter->aStaInfo[staId].nss =
+				pSapEvent->sapevt.
+				sapStationAssocReassocCompleteEvent.
+				chan_info.nss;
+			pHostapdAdapter->aStaInfo[staId].rate_flags =
+				pSapEvent->sapevt.
+				sapStationAssocReassocCompleteEvent.
+				chan_info.rate_flags;
+		}
+
 		if (hdd_ipa_is_enabled(pHddCtx)) {
 			status = hdd_ipa_wlan_evt(pHostapdAdapter,
 					pSapEvent->sapevt.
diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h
index 4af7214..bae0b4c 100644
--- a/core/mac/inc/sir_api.h
+++ b/core/mac/inc/sir_api.h
@@ -1034,6 +1034,9 @@
 	bool tdls_prohibited;
 	bool tdls_chan_swit_prohibited;
 #endif
+	uint8_t nss;
+	uint32_t max_rate_flags;
+
 #ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH
 	tSirSmeHTProfile HTProfile;
 #endif
@@ -1057,7 +1060,10 @@
 	uint32_t info;
 	uint32_t reg_info_1;
 	uint32_t reg_info_2;
+	uint8_t nss;
+	uint32_t rate_flags;
 } tSirSmeChanInfo, *tpSirSmeChanInfo;
+
 /* / Definition for Association indication from peer */
 /* / MAC ---> */
 typedef struct sSirSmeAssocInd {
diff --git a/core/mac/src/include/dph_global.h b/core/mac/src/include/dph_global.h
index ae590db..abeacf4 100644
--- a/core/mac/src/include/dph_global.h
+++ b/core/mac/src/include/dph_global.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -238,6 +238,8 @@
 	/* key installed for this STA or not in the firmware */
 	uint8_t is_key_installed;
 	uint8_t is_disassoc_deauth_in_progress;
+
+	uint8_t nss;
 	/*
 	 * When a station with already an existing dph entry tries to
 	 * associate again, the old dph entry will be zeroed out except
diff --git a/core/mac/src/pe/lim/lim_process_assoc_req_frame.c b/core/mac/src/pe/lim/lim_process_assoc_req_frame.c
index 02b0923..8e23a4e 100644
--- a/core/mac/src/pe/lim/lim_process_assoc_req_frame.c
+++ b/core/mac/src/pe/lim/lim_process_assoc_req_frame.c
@@ -1929,6 +1929,9 @@
 			(session_entry->maxTxPower << 16);
 		assoc_ind->chan_info.reg_info_2 =
 			(session_entry->maxTxPower << 8);
+		assoc_ind->chan_info.nss = sta_ds->nss;
+		assoc_ind->chan_info.rate_flags =
+			lim_get_max_rate_flags(mac_ctx, sta_ds);
 		/* updates VHT information in assoc indication */
 		lim_fill_assoc_ind_vht_info(mac_ctx, session_entry, assoc_req,
 			assoc_ind);
diff --git a/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c b/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c
index 24caac9..c11cecc 100644
--- a/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c
+++ b/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c
@@ -61,6 +61,7 @@
  * @mac_ctx: Pointer to Global MAC structure
  * @sta_ds: Station Descriptor in DPH
  * @assoc_rsp: Pointer to Association Response Structure
+ * @session_entry : PE session Entry
  *
  * This function is called to Update the HT capabilities in
  * Station Descriptor (dph) Details from
@@ -69,20 +70,27 @@
  * Return: None
  */
 static void lim_update_stads_htcap(tpAniSirGlobal mac_ctx,
-	tpDphHashNode sta_ds, tpSirAssocRsp assoc_rsp)
+		tpDphHashNode sta_ds, tpSirAssocRsp assoc_rsp,
+		tpPESession session_entry)
 {
 	uint16_t highest_rxrate = 0;
 	tDot11fIEHTCaps *ht_caps;
+	uint32_t shortgi_20mhz_support;
+	uint32_t shortgi_40mhz_support;
 
 	ht_caps = &assoc_rsp->HTCaps;
 	sta_ds->mlmStaContext.htCapability = assoc_rsp->HTCaps.present;
 	if (assoc_rsp->HTCaps.present) {
 		sta_ds->htGreenfield =
 			(uint8_t) ht_caps->greenField;
-		sta_ds->htSupportedChannelWidthSet =
-			(uint8_t) (ht_caps->supportedChannelWidthSet ?
-		assoc_rsp->HTInfo.recommendedTxWidthSet :
-		ht_caps->supportedChannelWidthSet);
+		if (session_entry->htSupportedChannelWidthSet) {
+			sta_ds->htSupportedChannelWidthSet =
+				(uint8_t) (ht_caps->supportedChannelWidthSet ?
+				assoc_rsp->HTInfo.recommendedTxWidthSet :
+				ht_caps->supportedChannelWidthSet);
+		} else
+			sta_ds->htSupportedChannelWidthSet =
+				eHT_CHANNEL_WIDTH_20MHZ;
 		sta_ds->htLsigTXOPProtection =
 			(uint8_t) ht_caps->lsigTXOPProtection;
 		sta_ds->htMIMOPSState =
@@ -92,10 +100,6 @@
 		sta_ds->htAMpduDensity = ht_caps->mpduDensity;
 		sta_ds->htDsssCckRate40MHzSupport =
 			(uint8_t) ht_caps->dsssCckMode40MHz;
-		sta_ds->htShortGI20Mhz =
-			(uint8_t) ht_caps->shortGI20MHz;
-		sta_ds->htShortGI40Mhz =
-			(uint8_t) ht_caps->shortGI40MHz;
 		sta_ds->htMaxRxAMpduFactor =
 			ht_caps->maxRxAMPDUFactor;
 		lim_fill_rx_highest_supported_rate(mac_ctx, &highest_rxrate,
@@ -115,6 +119,39 @@
 		 * For now, it is IMMEDIATE BA only on ALL TID's
 		 */
 		sta_ds->baPolicyFlag = 0xFF;
+
+		/* Check if we have support for gShortGI20Mhz and
+		 * gShortGI40Mhz from ini file
+		 */
+		if (eSIR_SUCCESS == wlan_cfg_get_int(mac_ctx,
+						WNI_CFG_SHORT_GI_20MHZ,
+						&shortgi_20mhz_support)) {
+			if (true == shortgi_20mhz_support)
+				sta_ds->htShortGI20Mhz =
+				      (uint8_t)assoc_rsp->HTCaps.shortGI20MHz;
+			else
+				sta_ds->htShortGI20Mhz = false;
+		} else {
+			lim_log(mac_ctx, LOGE,
+				FL("could not retrieve shortGI 20Mhz CFG, setting value to default"));
+			sta_ds->htShortGI20Mhz =
+				WNI_CFG_SHORT_GI_20MHZ_STADEF;
+		}
+
+		if (eSIR_SUCCESS == wlan_cfg_get_int(mac_ctx,
+						WNI_CFG_SHORT_GI_40MHZ,
+						&shortgi_40mhz_support)) {
+			if (true == shortgi_40mhz_support)
+				sta_ds->htShortGI40Mhz =
+				      (uint8_t)assoc_rsp->HTCaps.shortGI40MHz;
+			else
+				sta_ds->htShortGI40Mhz = false;
+		} else {
+			lim_log(mac_ctx, LOGE,
+				FL("could not retrieve shortGI 40Mhz CFG,setting value to default"));
+			sta_ds->htShortGI40Mhz =
+				WNI_CFG_SHORT_GI_40MHZ_STADEF;
+		}
 	}
 }
 
@@ -150,7 +187,8 @@
 
 	/* Update HT Capabilites only when the self mode supports HT */
 	if (IS_DOT11_MODE_HT(session_entry->dot11mode))
-		lim_update_stads_htcap(mac_ctx, sta_ds, assoc_rsp);
+		lim_update_stads_htcap(mac_ctx, sta_ds, assoc_rsp,
+				       session_entry);
 
 #ifdef WLAN_FEATURE_11AC
 	if (assoc_rsp->VHTCaps.present)
diff --git a/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c b/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c
index 366b79e..41282b7 100644
--- a/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c
+++ b/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c
@@ -1762,9 +1762,11 @@
 		sta_ds =
 			dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER,
 				&session_entry->dph.dphHashTable);
-		if (NULL != sta_ds)
+		if (NULL != sta_ds) {
 			sta_ds->mlmStaContext.mlmState =
 				eLIM_MLM_LINK_ESTABLISHED_STATE;
+			sta_ds->nss = add_sta_params->nss;
+		}
 		else
 			lim_log(mac_ctx, LOGW,
 				FL("Fail to get DPH Hash Entry for AID - %d"),
@@ -2258,6 +2260,7 @@
 	}
 	pStaDs->bssId = pAddStaParams->bssIdx;
 	pStaDs->staIndex = pAddStaParams->staIdx;
+	pStaDs->nss = pAddStaParams->nss;
 	/* if the AssocRsp frame is not acknowledged, then keep alive timer will take care of the state */
 	pStaDs->valid = 1;
 	pStaDs->mlmStaContext.mlmState = eLIM_MLM_WT_ASSOC_CNF_STATE;
diff --git a/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c b/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c
index 10a7032..bde6cba 100644
--- a/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c
+++ b/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c
@@ -168,6 +168,55 @@
 
 
 /**
+ * lim_get_max_rate_flags() - Get rate flags
+ * @mac_ctx: Pointer to global MAC structure
+ * @sta_ds: Pointer to station ds structure
+ *
+ * This function is called to get the rate flags for a connection
+ * from the station ds structure depending on the ht and the vht
+ * channel width supported.
+ *
+ * Return: Returns the populated rate_flags
+ */
+uint32_t lim_get_max_rate_flags(tpAniSirGlobal mac_ctx, tpDphHashNode sta_ds)
+{
+	uint32_t rate_flags = 0;
+
+	if (sta_ds == NULL) {
+		lim_log(mac_ctx, LOGE, FL("sta_ds is NULL"));
+		return rate_flags;
+	}
+
+	if (!sta_ds->mlmStaContext.htCapability &&
+	    !sta_ds->mlmStaContext.vhtCapability) {
+		rate_flags |= eHAL_TX_RATE_LEGACY;
+	} else {
+		if (sta_ds->mlmStaContext.vhtCapability) {
+			if (WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ ==
+				sta_ds->vhtSupportedChannelWidthSet) {
+				rate_flags |= eHAL_TX_RATE_VHT80;
+			} else if (WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ ==
+					sta_ds->vhtSupportedChannelWidthSet) {
+				if (sta_ds->htSupportedChannelWidthSet)
+					rate_flags |= eHAL_TX_RATE_VHT40;
+				else
+					rate_flags |= eHAL_TX_RATE_VHT20;
+			}
+		} else if (sta_ds->mlmStaContext.htCapability) {
+			if (sta_ds->htSupportedChannelWidthSet)
+				rate_flags |= eHAL_TX_RATE_HT40;
+			else
+				rate_flags |= eHAL_TX_RATE_HT20;
+		}
+	}
+
+	if (sta_ds->htShortGI20Mhz || sta_ds->htShortGI40Mhz)
+		rate_flags |= eHAL_TX_RATE_SGI;
+
+	return rate_flags;
+}
+
+/**
  * lim_send_sme_join_reassoc_rsp_after_resume() - Send Response to SME
  * @mac_ctx          Pointer to Global MAC structure
  * @status           Resume link status
@@ -430,6 +479,9 @@
 				sme_join_rsp->tdls_chan_swit_prohibited =
 				   session_entry->tdls_chan_swit_prohibited;
 #endif
+				sme_join_rsp->nss = sta_ds->nss;
+				sme_join_rsp->max_rate_flags =
+					lim_get_max_rate_flags(mac_ctx, sta_ds);
 			}
 		}
 		sme_join_rsp->beaconLength = 0;
diff --git a/core/mac/src/pe/lim/lim_utils.h b/core/mac/src/pe/lim/lim_utils.h
index f551109..cd9d6a1 100644
--- a/core/mac/src/pe/lim/lim_utils.h
+++ b/core/mac/src/pe/lim/lim_utils.h
@@ -444,6 +444,7 @@
 bool lim_is_noa_insert_reqd(tpAniSirGlobal pMac);
 bool lim_isconnected_on_dfs_channel(uint8_t currentChannel);
 uint8_t lim_get_current_operating_channel(tpAniSirGlobal pMac);
+uint32_t lim_get_max_rate_flags(tpAniSirGlobal mac_ctx, tpDphHashNode sta_ds);
 
 #ifdef WLAN_FEATURE_11AC
 bool lim_check_vht_op_mode_change(tpAniSirGlobal pMac,
diff --git a/core/sap/src/sap_fsm.c b/core/sap/src/sap_fsm.c
index 1ca439e..b14deb4 100644
--- a/core/sap/src/sap_fsm.c
+++ b/core/sap/src/sap_fsm.c
@@ -2665,6 +2665,8 @@
 			csr_roaminfo->chan_info.reg_info_1;
 		chaninfo->reg_info_2 =
 			csr_roaminfo->chan_info.reg_info_2;
+		chaninfo->nss = csr_roaminfo->chan_info.nss;
+		chaninfo->rate_flags = csr_roaminfo->chan_info.rate_flags;
 
 		reassoc_complete->wmmEnabled = csr_roaminfo->wmmEnabledSta;
 		reassoc_complete->status = (eSapStatus) context;
diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c
index 72711d2..7c627c0 100644
--- a/core/sme/src/csr/csr_api_roam.c
+++ b/core/sme/src/csr/csr_api_roam.c
@@ -6398,6 +6398,9 @@
 			roam_info.ucastSig = (uint8_t) join_rsp->ucastSig;
 			roam_info.bcastSig = (uint8_t) join_rsp->bcastSig;
 			roam_info.timingMeasCap = join_rsp->timingMeasCap;
+			roam_info.chan_info.nss = join_rsp->nss;
+			roam_info.chan_info.rate_flags =
+				join_rsp->max_rate_flags;
 #ifdef FEATURE_WLAN_TDLS
 			roam_info.tdls_prohibited = join_rsp->tdls_prohibited;
 			roam_info.tdls_chan_swit_prohibited =
diff --git a/core/wma/inc/wma_if.h b/core/wma/inc/wma_if.h
index 6ab2a52..63dd5e3 100644
--- a/core/wma/inc/wma_if.h
+++ b/core/wma/inc/wma_if.h
@@ -224,6 +224,7 @@
  * @maxTxPower: max tx power
  * @atimIePresent: Peer Atim Info
  * @peerAtimWindowLength: peer ATIM Window length
+ * @nss: Return the number of spatial streams supported
  *
  * This structure contains parameter required for
  * add sta request of upper layer.
@@ -320,6 +321,7 @@
 	uint8_t atimIePresent;
 	uint32_t peerAtimWindowLength;
 	uint8_t nonRoamReassoc;
+	uint32_t nss;
 } tAddStaParams, *tpAddStaParams;
 
 /**
diff --git a/core/wma/src/wma_dev_if.c b/core/wma/src/wma_dev_if.c
index c1de651..2fa2461 100644
--- a/core/wma/src/wma_dev_if.c
+++ b/core/wma/src/wma_dev_if.c
@@ -3502,9 +3502,7 @@
 	uint8_t peer_id;
 	CDF_STATUS status;
 	int32_t ret;
-#ifdef WLAN_FEATURE_11W
 	struct wma_txrx_node *iface = NULL;
-#endif /* WLAN_FEATURE_11W */
 	struct wma_target_req *msg;
 	bool peer_assoc_cnf = false;
 
@@ -3535,6 +3533,7 @@
 		goto send_rsp;
 	}
 
+	iface = &wma->interfaces[vdev->vdev_id];
 	peer = ol_txrx_find_peer_by_addr_and_vdev(pdev,
 						  vdev,
 						  add_sta->staMac, &peer_id);
@@ -3633,7 +3632,6 @@
 		 * per STA for SAP case
 		 * We will isolate the ifaces based on vdevid
 		 */
-		iface = &wma->interfaces[vdev->vdev_id];
 		iface->rmfEnabled = add_sta->rmfEnabled;
 		/*
 		 * when 802.11w PMF is enabled for hw encr/decr
@@ -3669,6 +3667,7 @@
 	ol_txrx_peer_state_update(pdev, add_sta->staMac, state);
 
 	add_sta->staIdx = ol_txrx_local_peer_id(peer);
+	add_sta->nss    = iface->nss;
 	add_sta->status = CDF_STATUS_SUCCESS;
 send_rsp:
 	/* Do not send add stat resp when peer assoc cnf is enabled */
@@ -4042,6 +4041,7 @@
 		wma_set_ppsconfig(params->smesessionId,
 				  WMA_VHT_PPS_DELIM_CRC_FAIL, 1);
 	iface->aid = params->assocId;
+	params->nss = iface->nss;
 out:
 	/* Do not send add stat resp when peer assoc cnf is enabled */
 	if (peer_assoc_cnf)