瀏覽代碼

qcacld-3.0: Add support to get pmf bcn protect stats

Host sets WMI_REQUEST_PMF_BCN_PROTECT_STAT bit in stats_id param of
WMI_REQUEST_STATS_CMDID command. Firmware supporting pmf beacon
protection stats responds host with stats in wmi_update_stats_id
event. Host extracts PMF beacon protection stats from wmi_update_stats_id
event. Host adds PMF beacon protection stats in the response of vendor
command QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO for STA mode.

Change-Id: Ib3cb06e03dbccdb9fa1782d414ed734bd97aa309
CRs-Fixed: 2705236
Abhishek Ambure 4 年之前
父節點
當前提交
8c579f5a5b

+ 20 - 0
components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_defs.h

@@ -270,18 +270,36 @@ struct summary_stats {
 	uint32_t rx_error_cnt;
 };
 
+/**
+ * struct pmf_bcn_protect_stats - pmf bcn protect stats param
+ * @pmf_bcn_stats_valid: bcn protect stats received from fw are valid or not
+ * @igtk_mic_fail_cnt: MIC failure count of management packets using IGTK
+ * @igtk_replay_cnt: Replay detection count of management packets using IGTK
+ * @bcn_mic_fail_cnt: MIC failure count of beacon packets using BIGTK
+ * @bcn_replay_cnt: Replay detection count of beacon packets using BIGTK
+ */
+struct pmf_bcn_protect_stats {
+	bool pmf_bcn_stats_valid;
+	uint32_t igtk_mic_fail_cnt;
+	uint32_t igtk_replay_cnt;
+	uint32_t bcn_mic_fail_cnt;
+	uint32_t bcn_replay_cnt;
+};
+
 /**
  * struct vdev_mc_cp_stats - vdev specific stats
  * @cca: cca stats
  * @tx_rate_flags: tx rate flags (enum tx_rate_info)
  * @chain_rssi: chain rssi
  * @vdev_summary_stats: vdev's summary stats
+ * @pmf_bcn_stats: pmf beacon protect stats
  */
 struct vdev_mc_cp_stats {
 	struct cca_stats cca;
 	uint32_t tx_rate_flags;
 	int8_t chain_rssi[MAX_NUM_CHAINS];
 	struct summary_stats vdev_summary_stats;
+	struct pmf_bcn_protect_stats pmf_bcn_stats;
 };
 
 /**
@@ -560,6 +578,7 @@ struct peer_stats_info_ext_event {
  *              MSB indicates if this feature is supported by FW or not.
  * @num_peer_stats_info_ext: number of peer extended stats info
  * @peer_stats_info_ext: peer extended stats info
+ * @pmf_bcn_protect_stats: pmf bcn protect stats
  */
 struct stats_event {
 	uint32_t num_pdev_stats;
@@ -585,6 +604,7 @@ struct stats_event {
 	uint32_t last_event;
 	uint32_t num_peer_stats_info_ext;
 	struct peer_stats_info_ext_event *peer_stats_info_ext;
+	struct pmf_bcn_protect_stats bcn_protect_stats;
 };
 
 /**

+ 46 - 0
components/cp_stats/dispatcher/src/wlan_cp_stats_mc_tgt_api.c

@@ -648,6 +648,48 @@ end:
 	wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID);
 }
 
+static void
+tgt_mc_cp_stats_extract_pmf_bcn_stats(struct wlan_objmgr_psoc *psoc,
+				      struct stats_event *ev)
+{
+	QDF_STATUS status;
+	struct request_info last_req = {0};
+	struct wlan_objmgr_vdev *vdev;
+	struct vdev_mc_cp_stats *vdev_mc_stats;
+	struct vdev_cp_stats *vdev_cp_stats_priv;
+
+	status = ucfg_mc_cp_stats_get_pending_req(psoc,
+						  TYPE_STATION_STATS,
+						  &last_req);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed");
+		return;
+	}
+
+	vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, last_req.vdev_id,
+						    WLAN_CP_STATS_ID);
+	if (!vdev) {
+		cp_stats_err("vdev is null");
+		return;
+	}
+
+	vdev_cp_stats_priv = wlan_cp_stats_get_vdev_stats_obj(vdev);
+	if (!vdev_cp_stats_priv) {
+		cp_stats_err("vdev cp stats object is null");
+		wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID);
+		return;
+	}
+
+	wlan_cp_stats_vdev_obj_lock(vdev_cp_stats_priv);
+	vdev_mc_stats = vdev_cp_stats_priv->vdev_stats;
+
+	if (ev->bcn_protect_stats.pmf_bcn_stats_valid)
+		vdev_mc_stats->pmf_bcn_stats = ev->bcn_protect_stats;
+
+	wlan_cp_stats_vdev_obj_unlock(vdev_cp_stats_priv);
+	wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID);
+}
+
 static void tgt_mc_cp_stats_extract_vdev_summary_stats(
 					struct wlan_objmgr_psoc *psoc,
 					struct stats_event *ev)
@@ -701,6 +743,7 @@ static void tgt_mc_cp_stats_extract_vdev_summary_stats(
 	qdf_mem_copy(&vdev_mc_stats->vdev_summary_stats,
 		     &ev->vdev_summary_stats[i].stats,
 		     sizeof(vdev_mc_stats->vdev_summary_stats));
+
 	wlan_cp_stats_vdev_obj_unlock(vdev_cp_stats_priv);
 
 	peer = wlan_objmgr_get_peer(psoc, last_req.pdev_id,
@@ -851,6 +894,8 @@ tgt_mc_cp_stats_prepare_n_send_raw_station_stats(struct wlan_objmgr_psoc *psoc,
 		     vdev_mc_stats->chain_rssi,
 		     sizeof(vdev_mc_stats->chain_rssi));
 	info.tx_rate_flags = vdev_mc_stats->tx_rate_flags;
+
+	info.bcn_protect_stats = vdev_mc_stats->pmf_bcn_stats;
 	wlan_cp_stats_vdev_obj_unlock(vdev_cp_stats_priv);
 
 	info.peer_adv_stats = qdf_mem_malloc(sizeof(*info.peer_adv_stats));
@@ -907,6 +952,7 @@ static void tgt_mc_cp_stats_extract_station_stats(
 	tgt_mc_cp_stats_extract_peer_stats(psoc, ev, true);
 	tgt_mc_cp_stats_extract_vdev_summary_stats(psoc, ev);
 	tgt_mc_cp_stats_extract_vdev_chain_rssi_stats(psoc, ev);
+	tgt_mc_cp_stats_extract_pmf_bcn_stats(psoc, ev);
 
 	/*
 	 * PEER stats are the last stats sent for get_station statistics.

+ 43 - 4
components/target_if/cp_stats/src/target_if_mc_cp_stats.c

@@ -375,6 +375,38 @@ static QDF_STATUS target_if_cp_stats_extract_pdev_stats(
 	return QDF_STATUS_SUCCESS;
 }
 
+static QDF_STATUS target_if_cp_stats_extract_pmf_bcn_protect_stats(
+					struct wmi_unified *wmi_hdl,
+					wmi_host_stats_event *stats_param,
+					struct stats_event *ev, uint8_t *data)
+{
+	QDF_STATUS status;
+	wmi_host_pmf_bcn_protect_stats pmf_bcn_stats = {0};
+
+	if (!(stats_param->stats_id & WMI_HOST_REQUEST_PMF_BCN_PROTECT_STAT))
+		return QDF_STATUS_SUCCESS;
+
+	qdf_mem_zero(&ev->bcn_protect_stats, sizeof(ev->bcn_protect_stats));
+	status = wmi_extract_pmf_bcn_protect_stats(wmi_hdl, data,
+						   &pmf_bcn_stats);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		cp_stats_err("wmi_extract_pmf_bcn_protect_stats failed");
+		return status;
+	}
+
+	ev->bcn_protect_stats.pmf_bcn_stats_valid = true;
+	ev->bcn_protect_stats.igtk_mic_fail_cnt =
+			pmf_bcn_stats.igtk_mic_fail_cnt;
+	ev->bcn_protect_stats.igtk_replay_cnt =
+			pmf_bcn_stats.igtk_replay_cnt;
+	ev->bcn_protect_stats.bcn_mic_fail_cnt =
+			pmf_bcn_stats.bcn_mic_fail_cnt;
+	ev->bcn_protect_stats.bcn_replay_cnt =
+			pmf_bcn_stats.bcn_replay_cnt;
+
+	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,
@@ -709,7 +741,7 @@ static QDF_STATUS target_if_cp_stats_extract_event(struct wmi_unified *wmi_hdl,
 	cp_stats_nofl_debug("num: pdev: %d, pdev_extd: %d, vdev: %d, peer: %d,"
 			    "peer_extd: %d rssi: %d, mib %d, mib_extd %d, "
 			    "bcnflt: %d, channel: %d, bcn: %d, peer_extd2: %d,"
-			    "last_event: %x",
+			    "last_event: %x, stats id: %d",
 			    stats_param.num_pdev_stats,
 			    stats_param.num_pdev_ext_stats,
 			    stats_param.num_vdev_stats,
@@ -721,7 +753,9 @@ static QDF_STATUS target_if_cp_stats_extract_event(struct wmi_unified *wmi_hdl,
 			    stats_param.num_bcnflt_stats,
 			    stats_param.num_chan_stats,
 			    stats_param.num_bcn_stats,
-			    stats_param.num_peer_adv_stats, stats_param.last_event);
+			    stats_param.num_peer_adv_stats,
+			    stats_param.last_event,
+			    stats_param.stats_id);
 
 	ev->last_event = stats_param.last_event;
 	status = target_if_cp_stats_extract_pdev_stats(wmi_hdl, &stats_param,
@@ -757,7 +791,11 @@ static QDF_STATUS target_if_cp_stats_extract_event(struct wmi_unified *wmi_hdl,
 	if (QDF_IS_STATUS_ERROR(status))
 		return status;
 
-	return QDF_STATUS_SUCCESS;
+	status = target_if_cp_stats_extract_pmf_bcn_protect_stats(wmi_hdl,
+								  &stats_param,
+								  ev, data);
+
+	return status;
 }
 
 /**
@@ -1090,7 +1128,8 @@ static uint32_t get_stats_id(enum stats_req_type type)
 			WMI_REQUEST_VDEV_STAT |
 			WMI_REQUEST_PDEV_STAT |
 			WMI_REQUEST_PEER_EXTD2_STAT |
-			WMI_REQUEST_RSSI_PER_CHAIN_STAT);
+			WMI_REQUEST_RSSI_PER_CHAIN_STAT |
+			WMI_REQUEST_PMF_BCN_PROTECT_STAT);
 	case TYPE_MIB_STATS:
 		return (WMI_REQUEST_MIB_STAT | WMI_REQUEST_MIB_EXTD_STAT);
 	}

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

@@ -700,6 +700,7 @@ struct hdd_stats {
 #endif
 	struct hdd_eapol_stats_s hdd_eapol_stats;
 	struct hdd_dhcp_stats_s hdd_dhcp_stats;
+	struct pmf_bcn_protect_stats bcn_protect_stats;
 };
 
 /**

+ 106 - 1
core/hdd/src/wlan_hdd_station_info.c

@@ -58,6 +58,19 @@
 #define STATION_MAX \
 	QCA_WLAN_VENDOR_ATTR_GET_STATION_MAX
 
+#define STA_INFO_INVALID \
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_INVALID
+#define STA_INFO_BIP_MIC_ERROR_COUNT \
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BIP_MIC_ERROR_COUNT
+#define STA_INFO_BIP_REPLAY_COUNT \
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BIP_REPLAY_COUNT
+#define STA_INFO_BEACON_MIC_ERROR_COUNT \
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_MIC_ERROR_COUNT
+#define STA_INFO_BEACON_REPLAY_COUNT \
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_REPLAY_COUNT
+#define STA_INFO_MAX \
+	QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX
+
 /* define short names for get station info attributes */
 #define LINK_INFO_STANDARD_NL80211_ATTR \
 	QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_LINK_STANDARD_NL80211_ATTR
@@ -127,7 +140,6 @@
  */
 #define HDD_STATION_INFO_RX_MC_BC_COUNT (1 << 31)
 
-
 const struct nla_policy
 hdd_get_station_policy[STATION_MAX + 1] = {
 	[STATION_INFO] = {.type = NLA_FLAG},
@@ -1593,6 +1605,55 @@ hdd_add_peer_stats_get_len(struct hdd_station_info *stainfo)
 		nla_attr_size(sizeof(stainfo->tx_retry_exhaust_fw)));
 }
 
+/**
+ * hdd_get_pmf_bcn_protect_stats_len() - get pmf bcn protect counters len
+ * @adapter: adapter holding valid bcn protect counters
+ *
+ * This function calculates the data length for valid pmf bcn counters.
+ *
+ * Return: total data length used in hdd_add_peer_stats()
+ */
+static uint32_t
+hdd_get_pmf_bcn_protect_stats_len(struct hdd_adapter *adapter)
+{
+	if (!adapter->hdd_stats.bcn_protect_stats.pmf_bcn_stats_valid)
+		return 0;
+
+	/* 4 pmf becon protect counters each of 32 bit */
+	return nla_attr_size(sizeof(uint32_t) * 4);
+}
+
+/**
+ * hdd_add_pmf_bcn_protect_stats() - add pmf bcn protect counters in resp
+ * @skb: pointer to response skb buffer
+ * @adapter: adapter holding valid bcn protect counters
+ *
+ * This function adds the pmf bcn stats in response.
+ *
+ * Return: 0 on success
+ */
+static int hdd_add_pmf_bcn_protect_stats(struct sk_buff *skb,
+					 struct hdd_adapter *adapter)
+{
+	if (!adapter->hdd_stats.bcn_protect_stats.pmf_bcn_stats_valid)
+		return 0;
+
+	adapter->hdd_stats.bcn_protect_stats.pmf_bcn_stats_valid = 0;
+	if (nla_put_u32(skb, STA_INFO_BIP_MIC_ERROR_COUNT,
+			adapter->hdd_stats.bcn_protect_stats.igtk_mic_fail_cnt) ||
+	    nla_put_u32(skb, STA_INFO_BIP_REPLAY_COUNT,
+			adapter->hdd_stats.bcn_protect_stats.igtk_replay_cnt) ||
+	    nla_put_u32(skb, STA_INFO_BEACON_MIC_ERROR_COUNT,
+			adapter->hdd_stats.bcn_protect_stats.bcn_mic_fail_cnt) ||
+	    nla_put_u32(skb, STA_INFO_BEACON_REPLAY_COUNT,
+			adapter->hdd_stats.bcn_protect_stats.bcn_replay_cnt)) {
+		hdd_err("put fail");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 /**
  * hdd_add_peer_stats - add peer statistics information
  * @skb: pointer to response skb buffer
@@ -1807,6 +1868,49 @@ static int hdd_get_station_remote_ex(struct hdd_context *hdd_ctx,
 	return hdd_get_connected_station_info_ex(hdd_ctx, adapter, stainfo);
 }
 
+/**
+ * hdd_get_station_info_ex() - send STA info to userspace, for STA mode only
+ * @hdd_ctx: pointer to hdd context
+ * @adapter: pointer to adapter
+ *
+ * Return: 0 if success else error status
+ */
+static int hdd_get_station_info_ex(struct hdd_context *hdd_ctx,
+				   struct hdd_adapter *adapter)
+{
+	struct sk_buff *skb;
+	uint32_t nl_buf_len;
+	struct hdd_station_ctx *hdd_sta_ctx;
+
+	hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
+
+	if (wlan_hdd_get_station_stats(adapter)) {
+		hdd_err_rl("wlan_hdd_get_station_stats fail");
+		return -EINVAL;
+	}
+
+	nl_buf_len = hdd_get_pmf_bcn_protect_stats_len(adapter);
+	if (!nl_buf_len) {
+		hdd_err_rl("Failed to get bcn pmf stats");
+		return -EINVAL;
+	}
+	nl_buf_len += NLMSG_HDRLEN;
+
+	skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len);
+	if (!skb) {
+		hdd_err_rl("cfg80211_vendor_cmd_alloc_reply_skb failed");
+		return -ENOMEM;
+	}
+
+	if (hdd_add_pmf_bcn_protect_stats(skb, adapter)) {
+		hdd_err_rl("hdd_add_pmf_bcn_protect_stats fail");
+		kfree_skb(skb);
+		return -EINVAL;
+	}
+
+	return cfg80211_vendor_cmd_reply(skb);
+}
+
 /**
  * __hdd_cfg80211_get_sta_info_cmd() - Handle get sta info vendor cmd
  * @wiphy: pointer to wireless phy
@@ -1857,6 +1961,7 @@ __hdd_cfg80211_get_sta_info_cmd(struct wiphy *wiphy,
 	switch (adapter->device_mode) {
 	case QDF_STA_MODE:
 	case QDF_P2P_CLIENT_MODE:
+		status = hdd_get_station_info_ex(hdd_ctx, adapter);
 		break;
 	case QDF_SAP_MODE:
 	case QDF_P2P_GO_MODE:

+ 4 - 4
core/hdd/src/wlan_hdd_station_info.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2018,2020 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2018, 2020 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -30,7 +30,7 @@ extern const struct nla_policy hdd_get_station_policy[
 			QCA_WLAN_VENDOR_ATTR_GET_STATION_MAX + 1];
 
 /**
- * wlan_hdd_cfg80211_get_station_cmd() - Handle get station vendor cmd
+ * hdd_cfg80211_get_station_cmd() - Handle get station vendor cmd
  * @wiphy: corestack handler
  * @wdev: wireless device
  * @data: data
@@ -50,14 +50,14 @@ extern const struct nla_policy hdd_get_sta_policy[
 			QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX + 1];
 
 /**
- * wlan_hdd_cfg80211_get_sta_info_cmd() - Handle get sta info vendor cmd
+ * hdd_cfg80211_get_sta_info_cmd() - Handle get sta info vendor cmd
  * @wiphy: corestack handler
  * @wdev: wireless device
  * @data: data
  * @data_len: data length
  *
  * Handles QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO.
- * Validate cmd attributes and send the station info to upper layers.
+ * Validate cmd attributes and send the sta info to upper layers.
  *
  * Return: Success(0) or reason code for failure
  */

+ 1 - 3
core/hdd/src/wlan_hdd_stats.c

@@ -4866,15 +4866,12 @@ void hdd_wlan_fill_per_chain_rssi_stats(struct station_info *sinfo,
 		sinfo->filled |= HDD_INFO_SIGNAL_AVG;
 	}
 }
-
 #else
-
 static inline
 void hdd_wlan_fill_per_chain_rssi_stats(struct station_info *sinfo,
 					struct hdd_adapter *adapter)
 {
 }
-
 #endif
 
 #if defined(CFG80211_RX_FCS_ERROR_REPORTING_SUPPORT)
@@ -6229,6 +6226,7 @@ int wlan_hdd_get_station_stats(struct hdd_adapter *adapter)
 	qdf_mem_copy(adapter->hdd_stats.per_chain_rssi_stats.rssi,
 		     stats->vdev_chain_rssi[0].chain_rssi,
 		     sizeof(stats->vdev_chain_rssi[0].chain_rssi));
+	adapter->hdd_stats.bcn_protect_stats = stats->bcn_protect_stats;
 	wlan_cfg80211_mc_cp_stats_free_stats_event(stats);
 
 out:

+ 2 - 0
os_if/cp_stats/src/wlan_cfg80211_mc_cp_stats.c

@@ -495,6 +495,7 @@ static void get_station_stats_cb(struct stats_event *ev, void *cookie)
 	qdf_mem_copy(priv->vdev_chain_rssi, ev->vdev_chain_rssi, rssi_size);
 	qdf_mem_copy(priv->vdev_summary_stats, ev->vdev_summary_stats,
 		     summary_size);
+	priv->bcn_protect_stats = ev->bcn_protect_stats;
 
 station_stats_cb_fail:
 	osif_request_complete(request);
@@ -585,6 +586,7 @@ wlan_cfg80211_mc_cp_stats_get_station_stats(struct wlan_objmgr_vdev *vdev,
 	if (priv->peer_adv_stats)
 		out->peer_adv_stats = priv->peer_adv_stats;
 	priv->peer_adv_stats = NULL;
+	out->bcn_protect_stats = priv->bcn_protect_stats;
 	osif_request_put(request);
 
 	osif_debug("Exit");