Kaynağa Gözat

Merge "qcacmn: Add support to cache peer capability info"

Linux Build Service Account 6 yıl önce
ebeveyn
işleme
b8a649b3a0

+ 3 - 2
os_if/linux/qca_vendor.h

@@ -770,9 +770,10 @@ enum qca_wlan_vendor_attr_get_station_info {
 	QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_RX_STBC,
 	QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_CH_WIDTH,
 	QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_SGI_ENABLE,
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0))
 	QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_PAD,
-#endif
+	QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_RX_RETRY_COUNT,
+	QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_RX_BC_MC_COUNT,
+
 	/* keep last */
 	QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_AFTER_LAST,
 	QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_MAX =

+ 46 - 4
target_if/cp_stats/src/target_if_mc_cp_stats.c

@@ -43,6 +43,8 @@ static void target_if_cp_stats_free_stats_event(struct stats_event *ev)
 	ev->peer_stats = NULL;
 	qdf_mem_free(ev->peer_adv_stats);
 	ev->peer_adv_stats = NULL;
+	qdf_mem_free(ev->peer_extended_stats);
+	ev->peer_extended_stats = NULL;
 	qdf_mem_free(ev->cca_stats);
 	ev->cca_stats = NULL;
 	qdf_mem_free(ev->vdev_summary_stats);
@@ -86,6 +88,43 @@ static QDF_STATUS target_if_cp_stats_extract_pdev_stats(
 	return QDF_STATUS_SUCCESS;
 }
 
+static void target_if_cp_stats_extract_peer_extd_stats(
+	struct wmi_unified *wmi_hdl,
+	wmi_host_stats_event *stats_param,
+	struct stats_event *ev,
+	uint8_t *data)
+
+{
+	QDF_STATUS status;
+	uint32_t i;
+	wmi_host_peer_extd_stats peer_extd_stats;
+
+	if (!stats_param->num_peer_extd_stats)
+		return;
+
+	ev->peer_extended_stats =
+			qdf_mem_malloc(sizeof(*ev->peer_extended_stats) *
+				       stats_param->num_peer_extd_stats);
+	if (!ev->peer_extended_stats)
+		return;
+
+	ev->num_peer_extd_stats = stats_param->num_peer_extd_stats;
+
+	for (i = 0; i < ev->num_peer_extd_stats; i++) {
+		status = wmi_extract_peer_extd_stats(wmi_hdl, data, i,
+						     &peer_extd_stats);
+		if (QDF_IS_STATUS_ERROR(status)) {
+			cp_stats_err("wmi_extract_peer_extd_stats failed");
+			continue;
+		}
+		WMI_MAC_ADDR_TO_CHAR_ARRAY(
+			     &peer_extd_stats.peer_macaddr,
+			ev->peer_extended_stats[i].peer_macaddr);
+		ev->peer_extended_stats[i].rx_mc_bc_cnt =
+						peer_extd_stats.rx_mc_bc_cnt;
+	}
+}
+
 static QDF_STATUS target_if_cp_stats_extract_peer_stats(
 					struct wmi_unified *wmi_hdl,
 					wmi_host_stats_event *stats_param,
@@ -99,14 +138,14 @@ static QDF_STATUS target_if_cp_stats_extract_peer_stats(
 	struct wmi_host_peer_adv_stats *peer_adv_stats;
 
 	/* Extract peer_stats */
-	ev->num_peer_stats = stats_param->num_peer_stats;
-	if (!ev->num_peer_stats)
+	if (!stats_param->num_peer_stats)
 		return QDF_STATUS_SUCCESS;
 
 	ev->peer_stats = qdf_mem_malloc(sizeof(*ev->peer_stats) *
-						ev->num_peer_stats);
+						stats_param->num_peer_stats);
 	if (!ev->peer_stats)
 		return QDF_STATUS_E_NOMEM;
+	ev->num_peer_stats = stats_param->num_peer_stats;
 
 	db2dbm_enabled = wmi_service_enabled(wmi_hdl,
 					     wmi_service_hw_db2dbm_support);
@@ -127,6 +166,9 @@ static QDF_STATUS target_if_cp_stats_extract_peer_stats(
 							TGT_NOISE_FLOOR_DBM;
 	}
 
+	target_if_cp_stats_extract_peer_extd_stats(wmi_hdl, stats_param, ev,
+						   data);
+
 	/* Extract peer_adv_stats */
 	ev->num_peer_adv_stats = stats_param->num_peer_adv_stats;
 	if (!ev->num_peer_adv_stats)
@@ -540,7 +582,7 @@ static uint32_t get_stats_id(enum stats_req_type type)
 	case TYPE_CONNECTION_TX_POWER:
 		return WMI_REQUEST_PDEV_STAT;
 	case TYPE_PEER_STATS:
-		return WMI_REQUEST_PEER_STAT;
+		return WMI_REQUEST_PEER_STAT | WMI_REQUEST_PEER_EXTD_STAT;
 	case TYPE_STATION_STATS:
 		return (WMI_REQUEST_AP_STAT   |
 			WMI_REQUEST_PEER_STAT |

+ 10 - 0
umac/cmn_services/crypto/inc/wlan_crypto_global_api.h

@@ -222,6 +222,16 @@ QDF_STATUS wlan_crypto_demic(struct wlan_objmgr_vdev *vdev,
  */
 bool wlan_crypto_vdev_is_pmf_enabled(struct wlan_objmgr_vdev *vdev);
 
+/**
+ * wlan_crypto_vdev_is_pmf_required - called to check is pmf required in vdev
+ * @vdev: vdev
+ *
+ * This function gets called to check is pmf required or not in vdev.
+ *
+ * Return: true or false
+ */
+bool wlan_crypto_vdev_is_pmf_required(struct wlan_objmgr_vdev *vdev);
+
 /**
  * wlan_crypto_is_pmf_enabled - called by mgmt txrx to check is pmf enabled
  * @vdev: vdev

+ 35 - 2
umac/cmn_services/crypto/src/wlan_crypto_global_api.c

@@ -394,8 +394,11 @@ QDF_STATUS wlan_crypto_set_del_pmksa(struct wlan_objmgr_vdev *vdev,
 	QDF_STATUS status = QDF_STATUS_E_INVAL;
 	struct wlan_crypto_comp_priv *crypto_priv;
 	struct wlan_crypto_params *crypto_params;
+	enum QDF_OPMODE op_mode;
 
-	if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE)
+	op_mode = wlan_vdev_mlme_get_opmode(vdev);
+
+	if (op_mode != QDF_STA_MODE && op_mode != QDF_SAP_MODE)
 		return QDF_STATUS_E_NOSUPPORT;
 
 	if (!pmksa && set) {
@@ -1642,6 +1645,36 @@ bool wlan_crypto_vdev_is_pmf_enabled(struct wlan_objmgr_vdev *vdev)
 
 	return false;
 }
+
+/**
+ * wlan_crypto_vdev_is_pmf_required - called to check is pmf required in vdev
+ * @vdev: vdev
+ *
+ * This function gets called to check is pmf required or not in vdev.
+ *
+ * Return: true or false
+ */
+bool wlan_crypto_vdev_is_pmf_required(struct wlan_objmgr_vdev *vdev)
+{
+	struct wlan_crypto_comp_priv *crypto_priv;
+	struct wlan_crypto_params *vdev_crypto_params;
+
+	if (!vdev)
+		return false;
+
+	vdev_crypto_params = wlan_crypto_vdev_get_comp_params(vdev,
+							      &crypto_priv);
+	if (!crypto_priv) {
+		crypto_err("crypto_priv NULL");
+		return QDF_STATUS_E_INVAL;
+	}
+
+	if (vdev_crypto_params->rsn_caps & WLAN_CRYPTO_RSN_CAP_MFP_REQUIRED)
+		return true;
+
+	return false;
+}
+
 /**
  * wlan_crypto_is_pmf_enabled - called by mgmt txrx to check is pmf enabled
  * @vdev: vdev
@@ -2805,7 +2838,7 @@ bool wlan_crypto_rsn_info(struct wlan_objmgr_vdev *vdev,
 		crypto_debug("Key mgmt match failed");
 		return false;
 	}
-	if (wlan_crypto_vdev_is_pmf_enabled(vdev) &&
+	if (wlan_crypto_vdev_is_pmf_required(vdev) &&
 	    !(crypto_params->rsn_caps & WLAN_CRYPTO_RSN_CAP_MFP_ENABLED)) {
 		crypto_debug("Peer is not PMF capable");
 		return false;

+ 2 - 0
umac/cp_stats/core/src/wlan_cp_stats_defs.h

@@ -88,6 +88,7 @@ struct vdev_cp_stats {
  * @peer_obj: pointer to peer
  * @peer_stats: pointer to ic/mc specific stats
  * @peer_adv_stats: pointer to peer adv stats
+ * @peer_extd_stats: Pointer to peer extended stats
  * @peer_comp_priv_obj[]: component's private object pointers
  * @peer_cp_stats_lock:	lock to protect object
  */
@@ -95,6 +96,7 @@ struct peer_cp_stats {
 	struct wlan_objmgr_peer  *peer_obj;
 	void                     *peer_stats;
 	void                     *peer_adv_stats;
+	void                     *peer_extd_stats;
 	void *peer_comp_priv_obj[WLAN_CP_STATS_MAX_COMPONENTS];
 	qdf_spinlock_t peer_cp_stats_lock;
 };

+ 26 - 0
umac/cp_stats/dispatcher/inc/wlan_cp_stats_mc_defs.h

@@ -237,6 +237,28 @@ struct vdev_mc_cp_stats {
 	struct summary_stats vdev_summary_stats;
 };
 
+/**
+ * struct peer_extd_stats - Peer extension statistics
+ * @peer_macaddr: peer MAC address
+ * @rx_duration: lower 32 bits of rx duration in microseconds
+ * @peer_tx_bytes: Total TX bytes (including dot11 header) sent to peer
+ * @peer_rx_bytes: Total RX bytes (including dot11 header) received from peer
+ * @last_tx_rate_code: last TX ratecode
+ * @last_tx_power: TX power used by peer - units are 0.5 dBm
+ * @rx_mc_bc_cnt: Total number of received multicast & broadcast data frames
+ * corresponding to this peer, 1 in the MSB of rx_mc_bc_cnt represents a
+ * valid data
+ */
+struct peer_extd_stats {
+	uint8_t peer_macaddr[QDF_MAC_ADDR_SIZE];
+	uint32_t rx_duration;
+	uint32_t peer_tx_bytes;
+	uint32_t peer_rx_bytes;
+	uint32_t last_tx_rate_code;
+	int32_t last_tx_power;
+	uint32_t rx_mc_bc_cnt;
+};
+
 /**
  * struct peer_mc_cp_stats - peer specific stats
  * @tx_rate: tx rate
@@ -303,6 +325,8 @@ struct chain_rssi_event {
  * @peer_stats: if populated array indicating peer stats
  * @peer_adv_stats: if populated, indicates peer adv (extd2) stats
  * @num_peer_adv_stats: number of peer adv (extd2) stats
+ * @num_peer_extd_stats: Num peer extended stats
+ * @peer_extended_stats: Peer extended stats
  * @cca_stats: if populated indicates congestion stats
  * @num_summary_stats: number of summary stats
  * @vdev_summary_stats: if populated indicates array of summary stats per vdev
@@ -320,6 +344,8 @@ struct stats_event {
 	struct peer_mc_cp_stats *peer_stats;
 	uint32_t num_peer_adv_stats;
 	struct peer_adv_mc_cp_stats *peer_adv_stats;
+	uint32_t num_peer_extd_stats;
+	struct peer_extd_stats *peer_extended_stats;
 	struct congestion_stats_event *cca_stats;
 	uint32_t num_summary_stats;
 	struct summary_stats_event *vdev_summary_stats;

+ 122 - 2
umac/cp_stats/dispatcher/src/wlan_cp_stats_mc_tgt_api.c

@@ -115,6 +115,7 @@ static void peer_rssi_iterator(struct wlan_objmgr_pdev *pdev,
 	struct stats_event *ev;
 	struct peer_mc_cp_stats *peer_mc_stats;
 	struct peer_cp_stats *peer_cp_stats_priv;
+	struct peer_extd_stats *peer_extd_mc_stats;
 
 	if (WLAN_PEER_SELF == wlan_peer_get_peer_type(peer)) {
 		cp_stats_err("ignore self peer: %pM",
@@ -133,6 +134,10 @@ static void peer_rssi_iterator(struct wlan_objmgr_pdev *pdev,
 	ev = arg;
 	ev->peer_stats[ev->num_peer_stats] = *peer_mc_stats;
 	ev->num_peer_stats++;
+
+	peer_extd_mc_stats = peer_cp_stats_priv->peer_extd_stats;
+	ev->peer_extended_stats[ev->num_peer_extd_stats] = *peer_extd_mc_stats;
+	ev->num_peer_extd_stats++;
 	wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv);
 }
 
@@ -147,6 +152,7 @@ tgt_mc_cp_stats_prepare_raw_peer_rssi(struct wlan_objmgr_psoc *psoc,
 	struct wlan_objmgr_vdev *vdev;
 	struct wlan_objmgr_peer *peer = NULL;
 	struct peer_mc_cp_stats *peer_mc_stats;
+	struct peer_extd_stats *peer_mc_extd_stats;
 	struct peer_cp_stats *peer_cp_stats_priv;
 	void (*get_peer_rssi_cb)(struct stats_event *ev, void *cookie);
 
@@ -172,6 +178,12 @@ tgt_mc_cp_stats_prepare_raw_peer_rssi(struct wlan_objmgr_psoc *psoc,
 		if (!ev.peer_stats)
 			goto end;
 
+		ev.peer_extended_stats =
+			qdf_mem_malloc(sizeof(*ev.peer_extended_stats) *
+				       peer_count);
+		if (!ev.peer_extended_stats)
+			goto end;
+
 		wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_PEER_OP,
 						  peer_rssi_iterator, &ev,
 						  true, WLAN_CP_STATS_ID);
@@ -194,9 +206,20 @@ tgt_mc_cp_stats_prepare_raw_peer_rssi(struct wlan_objmgr_psoc *psoc,
 			goto end;
 
 		ev.num_peer_stats = 1;
+
+		ev.peer_extended_stats =
+			qdf_mem_malloc(sizeof(*ev.peer_extended_stats));
+		if (!ev.peer_extended_stats)
+			goto end;
+
+		ev.num_peer_extd_stats = 1;
+
 		wlan_cp_stats_peer_obj_lock(peer_cp_stats_priv);
 		peer_mc_stats = peer_cp_stats_priv->peer_stats;
 		*ev.peer_stats = *peer_mc_stats;
+
+		peer_mc_extd_stats = peer_cp_stats_priv->peer_extd_stats;
+		*ev.peer_extended_stats = *peer_mc_extd_stats;
 		wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv);
 	}
 
@@ -299,8 +322,7 @@ tgt_mc_cp_stats_update_peer_stats(struct wlan_objmgr_psoc *psoc,
 		peer_mc_stats->rx_rate = peer_stats->rx_rate;
 	if (peer_stats->peer_rssi)
 		peer_mc_stats->peer_rssi = peer_stats->peer_rssi;
-
-	cp_stats_debug("peer_mac=%pM, tx_rate=%u, rx_rate=%u, peer_rssi=%u",
+	cp_stats_debug("peer_mac=%pM, tx_rate=%u, rx_rate=%u, peer_rssi=%d",
 		       peer_mc_stats->peer_macaddr, peer_mc_stats->tx_rate,
 		       peer_mc_stats->rx_rate, peer_mc_stats->peer_rssi);
 	wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv);
@@ -312,6 +334,103 @@ end:
 	return status;
 }
 
+static QDF_STATUS
+tgt_mc_cp_stats_update_peer_extd_stats(
+				struct wlan_objmgr_psoc *psoc,
+				struct peer_extd_stats *peer_extended_stats)
+{
+	uint8_t *peer_mac_addr;
+	struct wlan_objmgr_peer *peer;
+	struct peer_extd_stats *peer_extd_mc_stats;
+	QDF_STATUS status = QDF_STATUS_SUCCESS;
+	struct peer_cp_stats *peer_cp_stats_priv;
+
+	if (!peer_extended_stats)
+		return QDF_STATUS_E_INVAL;
+
+	peer_mac_addr = peer_extended_stats->peer_macaddr;
+	peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac_addr,
+					   WLAN_CP_STATS_ID);
+	if (!peer) {
+		cp_stats_err("peer is null");
+		return QDF_STATUS_E_EXISTS;
+	}
+
+	peer_cp_stats_priv = wlan_cp_stats_get_peer_stats_obj(peer);
+	if (!peer_cp_stats_priv) {
+		cp_stats_err("peer_cp_stats_priv is null");
+		status = QDF_STATUS_E_EXISTS;
+		goto end;
+	}
+
+	wlan_cp_stats_peer_obj_lock(peer_cp_stats_priv);
+	peer_extd_mc_stats = peer_cp_stats_priv->peer_extd_stats;
+	if (!peer_extd_mc_stats) {
+		wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv);
+		cp_stats_err("No peer_extd_mc_stats");
+		status = QDF_STATUS_E_INVAL;
+		goto end;
+	}
+	qdf_mem_copy(peer_extd_mc_stats->peer_macaddr,
+		     peer_extended_stats->peer_macaddr,
+		     QDF_MAC_ADDR_SIZE);
+	if (peer_extended_stats->rx_mc_bc_cnt)
+		peer_extd_mc_stats->rx_mc_bc_cnt =
+					peer_extended_stats->rx_mc_bc_cnt;
+	wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv);
+
+	cp_stats_debug("peer_mac=%pM, rx_mc_bc_cnt=%u",
+		       peer_extended_stats->peer_macaddr,
+		       peer_extended_stats->rx_mc_bc_cnt);
+
+end:
+		wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID);
+
+	return status;
+}
+
+static void tgt_mc_cp_stats_extract_peer_extd_stats(
+						struct wlan_objmgr_psoc *psoc,
+						struct stats_event *ev)
+{
+	uint32_t i, selected;
+	QDF_STATUS status;
+	struct request_info last_req = {0};
+
+	status = ucfg_mc_cp_stats_get_pending_req(psoc,
+						  TYPE_PEER_STATS,
+						  &last_req);
+
+	if (QDF_IS_STATUS_ERROR(status)) {
+		cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed");
+		return;
+	}
+
+	selected = ev->num_peer_extd_stats;
+	for (i = 0; i < ev->num_peer_extd_stats; i++) {
+		status = tgt_mc_cp_stats_update_peer_extd_stats(
+						psoc,
+						&ev->peer_extended_stats[i]);
+		if (!QDF_IS_ADDR_BROADCAST(last_req.peer_mac_addr) &&
+		    !qdf_mem_cmp(ev->peer_stats[i].peer_macaddr,
+				 last_req.peer_mac_addr,
+				 QDF_MAC_ADDR_SIZE)) {
+			/* mac is specified, but failed to update the peer */
+			if (QDF_IS_STATUS_ERROR(status))
+				return;
+
+			selected = i;
+		}
+	}
+
+	/* no matched peer */
+	if (!QDF_IS_ADDR_BROADCAST(last_req.peer_mac_addr) &&
+	    selected == ev->num_peer_extd_stats) {
+		cp_stats_err("peer not found stats");
+		return;
+	}
+}
+
 static void tgt_mc_cp_stats_extract_peer_stats(struct wlan_objmgr_psoc *psoc,
 					       struct stats_event *ev,
 					       bool is_station_stats)
@@ -397,6 +516,7 @@ complete:
 	if (is_station_stats)
 		return;
 
+	tgt_mc_cp_stats_extract_peer_extd_stats(psoc, ev);
 	tgt_mc_cp_stats_prepare_raw_peer_rssi(psoc, &last_req);
 	ucfg_mc_cp_stats_reset_pending_req(psoc, TYPE_PEER_STATS);
 }

+ 14 - 1
umac/cp_stats/dispatcher/src/wlan_cp_stats_mc_ucfg_api.c

@@ -88,10 +88,19 @@ QDF_STATUS wlan_cp_stats_peer_cs_init(struct peer_cp_stats *peer_cs)
 	peer_cs->peer_adv_stats = qdf_mem_malloc(sizeof
 						 (struct peer_adv_mc_cp_stats));
 	if (!peer_cs->peer_adv_stats) {
-		cp_stats_err("malloc failed");
 		qdf_mem_free(peer_cs->peer_stats);
 		return QDF_STATUS_E_NOMEM;
 	}
+
+	peer_cs->peer_extd_stats =
+			qdf_mem_malloc(sizeof(struct peer_extd_stats));
+	if (!peer_cs->peer_extd_stats) {
+		qdf_mem_free(peer_cs->peer_stats);
+		peer_cs->peer_stats = NULL;
+		qdf_mem_free(peer_cs->peer_adv_stats);
+		peer_cs->peer_adv_stats = NULL;
+		return QDF_STATUS_E_NOMEM;
+	}
 	return QDF_STATUS_SUCCESS;
 }
 
@@ -99,8 +108,11 @@ QDF_STATUS wlan_cp_stats_peer_cs_deinit(struct peer_cp_stats *peer_cs)
 {
 	qdf_mem_free(peer_cs->peer_adv_stats);
 	peer_cs->peer_adv_stats = NULL;
+	qdf_mem_free(peer_cs->peer_extd_stats);
+	peer_cs->peer_extd_stats = NULL;
 	qdf_mem_free(peer_cs->peer_stats);
 	peer_cs->peer_stats = NULL;
+
 	return QDF_STATUS_SUCCESS;
 }
 
@@ -568,6 +580,7 @@ void ucfg_mc_cp_stats_free_stats_resources(struct stats_event *ev)
 	qdf_mem_free(ev->cca_stats);
 	qdf_mem_free(ev->vdev_summary_stats);
 	qdf_mem_free(ev->vdev_chain_rssi);
+	qdf_mem_free(ev->peer_extended_stats);
 	qdf_mem_zero(ev, sizeof(*ev));
 }
 

+ 9 - 2
wmi/inc/wmi_unified_param.h

@@ -4083,6 +4083,8 @@ struct rx_reorder_queue_remove_params {
  * @num_pdev_ext_stats: number of pdev ext stats event structures
  * @num_vdev_stats: number of vdev stats
  * @num_peer_stats: number of peer stats event structures 0 or max peers
+ * @num_peer_extd_stats: number of peer extended stats event structures 0
+ * or max peers
  * @num_bcnflt_stats: number of beacon filter stats
  * @num_chan_stats: number of channel stats
  * @pdev_id: device id for the radio
@@ -4097,6 +4099,7 @@ typedef struct {
 	uint32_t num_pdev_ext_stats;
 	uint32_t num_vdev_stats;
 	uint32_t num_peer_stats;
+	uint32_t num_peer_extd_stats;
 	uint32_t num_bcnflt_stats;
 	uint32_t num_chan_stats;
 	uint32_t pdev_id;
@@ -4119,7 +4122,10 @@ typedef struct {
  * @atf_tokens_utilized: atf tokens utilized
  * @num_mu_tx_blacklisted: Blacklisted MU Tx count
  * @sgi_count: sgi count of the peer
- * @reserved: for future use
+ * @rx_mc_bc_cnt: Total number of received multicast & broadcast data frames
+ * corresponding to this peer, 1 in the MSB of rx_mc_bc_cnt represents a
+ * valid data
+ * @rx_retry_cnt: Number of rx retries received from current station
  */
 typedef struct {
 	wmi_host_mac_addr peer_macaddr;
@@ -4133,7 +4139,8 @@ typedef struct {
 	uint32_t atf_tokens_utilized;
 	uint32_t num_mu_tx_blacklisted;
 	uint32_t sgi_count;
-	uint32_t reserved[2];
+	uint32_t rx_mc_bc_cnt;
+	uint32_t rx_retry_cnt;
 } wmi_host_peer_extd_stats;
 
 /**

+ 34 - 0
wmi/src/wmi_unified_tlv.c

@@ -8341,6 +8341,9 @@ static QDF_STATUS extract_all_stats_counts_tlv(wmi_unified_t wmi_handle,
 	case WMI_REQUEST_BCN_STAT:
 		stats_param->stats_id |= WMI_HOST_REQUEST_BCN_STAT;
 		break;
+	case WMI_REQUEST_PEER_EXTD_STAT:
+		stats_param->stats_id |= WMI_REQUEST_PEER_EXTD_STAT;
+		break;
 
 	case WMI_REQUEST_PEER_EXTD2_STAT:
 		stats_param->stats_id |= WMI_HOST_REQUEST_PEER_ADV_STATS;
@@ -8377,6 +8380,7 @@ static QDF_STATUS extract_all_stats_counts_tlv(wmi_unified_t wmi_handle,
 	stats_param->num_pdev_ext_stats = 0;
 	stats_param->num_vdev_stats = ev->num_vdev_stats;
 	stats_param->num_peer_stats = ev->num_peer_stats;
+	stats_param->num_peer_extd_stats = ev->num_peer_extd_stats;
 	stats_param->num_bcnflt_stats = ev->num_bcnflt_stats;
 	stats_param->num_chan_stats = ev->num_chan_stats;
 	stats_param->num_bcn_stats = ev->num_bcn_stats;
@@ -8821,7 +8825,37 @@ static QDF_STATUS extract_peer_extd_stats_tlv(wmi_unified_t wmi_handle,
 		void *evt_buf, uint32_t index,
 		wmi_host_peer_extd_stats *peer_extd_stats)
 {
+	WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf;
+	wmi_stats_event_fixed_param *ev_param;
+	uint8_t *data;
+
+	param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *)evt_buf;
+	ev_param = (wmi_stats_event_fixed_param *)param_buf->fixed_param;
+	data = (uint8_t *)param_buf->data;
+	if (!data)
+		return QDF_STATUS_E_FAILURE;
+
+	if (index < ev_param->num_peer_extd_stats) {
+		wmi_peer_extd_stats *ev = (wmi_peer_extd_stats *) (data +
+			(ev_param->num_pdev_stats * sizeof(wmi_pdev_stats)) +
+			(ev_param->num_vdev_stats * sizeof(wmi_vdev_stats)) +
+			(ev_param->num_peer_stats * sizeof(wmi_peer_stats)) +
+			(ev_param->num_bcnflt_stats *
+			sizeof(wmi_bcnfilter_stats_t)) +
+			(ev_param->num_chan_stats * sizeof(wmi_chan_stats)) +
+			(ev_param->num_mib_stats * sizeof(wmi_mib_stats)) +
+			(ev_param->num_bcn_stats * sizeof(wmi_bcn_stats)) +
+			(index * sizeof(wmi_peer_extd_stats)));
+
+		qdf_mem_zero(peer_extd_stats, sizeof(wmi_host_peer_extd_stats));
+		qdf_mem_copy(&peer_extd_stats->peer_macaddr, &ev->peer_macaddr,
+			     sizeof(wmi_mac_addr));
+
+		peer_extd_stats->rx_mc_bc_cnt = ev->rx_mc_bc_cnt;
+	}
+
 	return QDF_STATUS_SUCCESS;
+
 }
 
 /**