Kaynağa Gözat

qcacld-3.0: Add peer ps change and TX failure indication

qcacld-2.0 to qcacld-3.0 propagation

This change indicates Peer STA's power state change and TX
failure to NL80211.

Vendor command QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT(127)
is introduced by this change.

Change-Id: Iaa1c14e5cdc5a7d04beebbff1149daf871f9ef5a
CRs-fixed: 1048388
Zhang Qian 8 yıl önce
ebeveyn
işleme
ca38fb13b5

+ 6 - 0
core/hdd/src/wlan_hdd_cfg80211.c

@@ -978,6 +978,12 @@ static const struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] =
 		.subcmd =
 			QCA_NL80211_VENDOR_SUBCMD_LL_STATS_PEERS_RESULTS
 	},
+	[QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT_INDEX] = {
+		.vendor_id =
+			QCA_NL80211_VENDOR_ID,
+		.subcmd =
+			QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT
+	},
 #endif /* WLAN_FEATURE_LINK_LAYER_STATS */
 	[QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE_CHANGE_INDEX] = {
 		.vendor_id =

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

@@ -9344,6 +9344,9 @@ int hdd_register_cb(hdd_context_t *hdd_ctx)
 
 	sme_rso_cmd_status_cb(hdd_ctx->hHal, wlan_hdd_rso_cmd_status_cb);
 
+	sme_set_link_layer_ext_cb(hdd_ctx->hHal,
+			wlan_hdd_cfg80211_link_layer_stats_ext_callback);
+
 	status = sme_set_lost_link_info_cb(hdd_ctx->hHal,
 					   hdd_lost_link_info_cb);
 	/* print error and not block the startup process */

+ 205 - 0
core/hdd/src/wlan_hdd_stats.c

@@ -1583,6 +1583,211 @@ int wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy,
 	return ret;
 }
 
+/**
+ * hdd_populate_per_peer_ps_info() - populate per peer sta's PS info
+ * @wifi_peer_info: peer information
+ * @vendor_event: buffer for vendor event
+ *
+ * Return: 0 success
+ */
+static inline int
+hdd_populate_per_peer_ps_info(tSirWifiPeerInfo *wifi_peer_info,
+			      struct sk_buff *vendor_event)
+{
+	if (!wifi_peer_info) {
+		hdd_err("Invalid pointer to peer info.");
+		return -EINVAL;
+	}
+
+	if (nla_put_u32(vendor_event,
+			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_STATE,
+			wifi_peer_info->power_saving) ||
+	    nla_put(vendor_event,
+		    QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS,
+		    QDF_MAC_ADDR_SIZE, &wifi_peer_info->peerMacAddress)) {
+		hdd_err("QCA_WLAN_VENDOR_ATTR put fail.");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/**
+ * hdd_populate_wifi_peer_ps_info() - populate peer sta's power state
+ * @data: stats for peer STA
+ * @vendor_event: buffer for vendor event
+ *
+ * Return: 0 success
+ */
+static int hdd_populate_wifi_peer_ps_info(tSirWifiPeerStat *data,
+					  struct sk_buff *vendor_event)
+{
+	uint32_t peer_num, i;
+	tSirWifiPeerInfo *wifi_peer_info;
+	struct nlattr *peer_info, *peers;
+
+	if (!data) {
+		hdd_err("Invalid pointer to Wifi peer stat.");
+		return -EINVAL;
+	}
+
+	peer_num = data->numPeers;
+	if (peer_num == 0) {
+		hdd_err("Peer number is zero.");
+		return -EINVAL;
+	}
+
+	if (nla_put_u32(vendor_event,
+			QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM,
+			peer_num)) {
+		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
+		return -EINVAL;
+	}
+
+	peer_info = nla_nest_start(vendor_event,
+			       QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_CHG);
+	if (peer_info == NULL) {
+		hdd_err("nla_nest_start failed");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < peer_num; i++) {
+		wifi_peer_info = &data->peerInfo[i];
+		peers = nla_nest_start(vendor_event, i);
+
+		if (peers == NULL) {
+			hdd_err("nla_nest_start failed");
+			return -EINVAL;
+		}
+
+		if (hdd_populate_per_peer_ps_info(wifi_peer_info, vendor_event))
+			return -EINVAL;
+
+		nla_nest_end(vendor_event, peers);
+	}
+	nla_nest_end(vendor_event, peer_info);
+
+	return 0;
+}
+
+/**
+ * hdd_populate_tx_failure_info() - populate TX failure info
+ * @tx_fail: TX failure info
+ * @skb: buffer for vendor event
+ *
+ * Return: 0 Success
+ */
+static inline int
+hdd_populate_tx_failure_info(struct sir_wifi_iface_tx_fail *tx_fail,
+			     struct sk_buff *skb)
+{
+	int status = 0;
+
+	if (tx_fail == NULL || skb == NULL)
+		return -EINVAL;
+
+	if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TID,
+			tx_fail->tid) ||
+	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NUM_MSDU,
+			tx_fail->msdu_num) ||
+	    nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS,
+			tx_fail->status)) {
+		hdd_err("QCA_WLAN_VENDOR_ATTR put fail");
+		status = -EINVAL;
+	}
+
+	return status;
+}
+
+/**
+ * wlan_hdd_cfg80211_link_layer_stats_ext_callback() - Callback for LL ext
+ * @ctx: HDD context
+ * @rsp: msg from FW
+ *
+ * This function is an extension of
+ * wlan_hdd_cfg80211_link_layer_stats_callback. It converts
+ * monitoring parameters offloaded to NL data and send the same to the
+ * kernel/upper layers.
+ *
+ * Return: None
+ */
+void wlan_hdd_cfg80211_link_layer_stats_ext_callback(tHddHandle ctx,
+						     tSirLLStatsResults *rsp)
+{
+	hdd_context_t *hdd_ctx;
+	struct sk_buff *skb = NULL;
+	uint32_t param_id, index;
+	hdd_adapter_t *adapter = NULL;
+	tSirLLStatsResults *linkLayer_stats_results;
+	tSirWifiPeerStat *peer_stats;
+	uint8_t *results;
+	int status;
+
+	ENTER();
+
+	if (!ctx) {
+		hdd_err("Invalid HDD context.");
+		return;
+	}
+
+	if (!rsp) {
+		hdd_err("Invalid result.");
+		return;
+	}
+
+	hdd_ctx = (hdd_context_t *)ctx;
+	linkLayer_stats_results = rsp;
+
+	status = wlan_hdd_validate_context(hdd_ctx);
+	if (0 != status)
+		return;
+
+	adapter = hdd_get_adapter_by_vdev(hdd_ctx,
+					  linkLayer_stats_results->ifaceId);
+
+	if (NULL == adapter) {
+		hdd_err("vdev_id %d does not exist with host.",
+			linkLayer_stats_results->ifaceId);
+		return;
+	}
+
+	index = QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT_INDEX;
+	skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy,
+			NULL, LL_STATS_EVENT_BUF_SIZE + NLMSG_HDRLEN,
+			index, GFP_KERNEL);
+	if (!skb) {
+		hdd_err("cfg80211_vendor_event_alloc failed.");
+		return;
+	}
+
+	results = linkLayer_stats_results->results;
+	param_id = linkLayer_stats_results->paramId;
+	hdd_info("LL_STATS RESP paramID = 0x%x, ifaceId = %u, result = %p",
+		 linkLayer_stats_results->paramId,
+		 linkLayer_stats_results->ifaceId,
+		 linkLayer_stats_results->results);
+	if (param_id & WMI_LL_STATS_EXT_PS_CHG) {
+		peer_stats = (tSirWifiPeerStat *)results;
+		status = hdd_populate_wifi_peer_ps_info(peer_stats, skb);
+	} else if (param_id & WMI_LL_STATS_EXT_TX_FAIL) {
+		struct sir_wifi_iface_tx_fail *tx_fail;
+
+		tx_fail = (struct sir_wifi_iface_tx_fail *)results;
+		status = hdd_populate_tx_failure_info(tx_fail, skb);
+	} else if (param_id & WMI_LL_STATS_EXT_MAC_COUNTER) {
+		hdd_info("MAC counters stats");
+		status = -EINVAL;
+	} else {
+		hdd_info("Unknown link layer stats");
+		status = -EINVAL;
+	}
+
+	if (status == 0)
+		cfg80211_vendor_event(skb, GFP_KERNEL);
+	else
+		kfree_skb(skb);
+	EXIT();
+}
+
 #endif /* WLAN_FEATURE_LINK_LAYER_STATS */
 
 #ifdef WLAN_FEATURE_STATS_EXT

+ 14 - 0
core/hdd/src/wlan_hdd_stats.h

@@ -220,5 +220,19 @@ void wlan_hdd_cfg80211_stats_ext_callback(void *ctx,
 
 void wlan_hdd_cfg80211_link_layer_stats_callback(void *ctx,
 						 int indType, void *pRsp);
+/**
+ * wlan_hdd_cfg80211_link_layer_stats_ext_callback() - Callback for LL ext
+ * @ctx: HDD context
+ * @rsp: msg from FW
+ *
+ * This function is an extension of
+ * wlan_hdd_cfg80211_link_layer_stats_callback. It converts
+ * monitoring parameters offloaded to NL data and send the same to the
+ * kernel/upper layers.
+ *
+ * Return: None.
+ */
+void wlan_hdd_cfg80211_link_layer_stats_ext_callback(tHddHandle ctx,
+						     tSirLLStatsResults *rsp);
 #endif /* end #if !defined(WLAN_HDD_STATS_H) */