summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAjay Davanageri <ajay.davanageri@broadcom.corp-partner.google.com>2021-12-23 14:21:31 +0530
committerRoger Wang <wangroger@google.com>2022-01-14 19:35:39 +0800
commit20ccb0a67c3a09a49cdbc84683a2b10cc5d81b1b (patch)
tree47c798f4695ba67108a99ef9f5eb38f33f22d8de
parent2aeb35145870217359b137d17e6d053134d2aee7 (diff)
downloadwlan-20ccb0a67c3a09a49cdbc84683a2b10cc5d81b1b.tar.gz
Extending Radio stats for supported radios.
Bug: 208371177 Test: Verified on pixel6/hikey960 Test: Passed sanity test Signed-off-by: Ajay Davanageri <ajay.davanageri@broadcom.corp-partner.google.com> Change-Id: I06d5ad2667b628f1363a5a1ea7cc393e6097fd36
-rwxr-xr-xbcmdhd/wifi_hal/common.h2
-rw-r--r--bcmdhd/wifi_hal/link_layer_stats.cpp174
2 files changed, 155 insertions, 21 deletions
diff --git a/bcmdhd/wifi_hal/common.h b/bcmdhd/wifi_hal/common.h
index 9065802..ddaf64d 100755
--- a/bcmdhd/wifi_hal/common.h
+++ b/bcmdhd/wifi_hal/common.h
@@ -56,6 +56,8 @@ const uint32_t BRCM_OUI = 0x001018;
#define NAN_MASTER_RANK_LEN 8
#define SAR_CONFIG_SCENARIO_COUNT 100
+#define MAX_NUM_RADIOS 3
+#define MAX_CMD_RESP_BUF_LEN 8192
/*
This enum defines ranges for various commands; commands themselves
diff --git a/bcmdhd/wifi_hal/link_layer_stats.cpp b/bcmdhd/wifi_hal/link_layer_stats.cpp
index a2aabe3..3a922db 100644
--- a/bcmdhd/wifi_hal/link_layer_stats.cpp
+++ b/bcmdhd/wifi_hal/link_layer_stats.cpp
@@ -43,6 +43,13 @@
#include "common.h"
#include "cpp_bindings.h"
+typedef enum {
+ ANDR_WIFI_ATTRIBUTE_INVALID = 0,
+ ANDR_WIFI_ATTRIBUTE_NUM_RADIO = 1,
+ ANDR_WIFI_ATTRIBUTE_STATS_INFO = 2,
+ ANDR_WIFI_ATTRIBUTE_STATS_MAX = 3
+} LINK_STAT_ATTRIBUTE;
+
/* Internal radio statistics structure in the driver */
typedef struct {
wifi_radio radio;
@@ -85,6 +92,12 @@ public:
protected:
virtual int handleResponse(WifiEvent& reply) {
+ void *data = NULL;
+ wifi_radio_stat *radio_stat_ptr = NULL;
+ u8 *iface_stat = NULL;
+ u8 *radioStatsBuf = NULL, *output = NULL, *data_ptr = NULL;
+ uint32_t total_size = 0, per_radio_size = 0, data_len = 0, rem_len = 0;
+ int num_radios = 0, id = 0, subcmd = 0, len = 0;
// ALOGI("In GetLinkStatsCommand::handleResponse");
@@ -93,34 +106,153 @@ protected:
return NL_SKIP;
}
- int id = reply.get_vendor_id();
-
- void *data = reply.get_vendor_data();
- int len = reply.get_vendor_data_len();
- if (!data || !len) {
- ALOGE("Invalid vendor data received");
- return NL_SKIP;
- }
- wifi_radio_stat *radio_stat =
- convertToExternalRadioStatStructure((wifi_radio_stat_internal *)data);
- if (!radio_stat) {
- ALOGE("Invalid stats pointer received");
+ id = reply.get_vendor_id();
+ subcmd = reply.get_vendor_subcmd();
+ nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
+ len = reply.get_vendor_data_len();
+
+ ALOGV("Id = %0x, subcmd = %d, len = %d\n", id, subcmd, len);
+ if (vendor_data == NULL || len == 0) {
+ ALOGE("no vendor data in GetLinkStatCommand response; ignoring it");
return NL_SKIP;
}
- wifi_iface_stat *iface_stat =
- (wifi_iface_stat *)((char *)&((wifi_radio_stat_internal *)data)->channels
- + radio_stat->num_channels * sizeof(wifi_channel_stat));
- (*mHandler.on_link_stats_results)(id, iface_stat, 1, radio_stat);
- free(radio_stat);
+
+ for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
+ if (it.get_type() == ANDR_WIFI_ATTRIBUTE_NUM_RADIO) {
+ num_radios = it.get_u32();
+ } else if (it.get_type() == ANDR_WIFI_ATTRIBUTE_STATS_INFO) {
+ data = it.get_data();
+ data_len = it.get_len();
+ } else {
+ ALOGW("Ignoring invalid attribute type = %d, size = %d\n",
+ it.get_type(), it.get_len());
+ }
+ }
+
+ if (num_radios) {
+ rem_len = MAX_CMD_RESP_BUF_LEN;
+ radioStatsBuf = (u8 *)malloc(MAX_CMD_RESP_BUF_LEN);
+ if (!radioStatsBuf) {
+ ALOGE("No memory\n");
+ return NL_SKIP;
+ }
+ memset(radioStatsBuf, 0, MAX_CMD_RESP_BUF_LEN);
+ output = radioStatsBuf;
+
+ if (!data || !data_len) {
+ ALOGE("%s: null data\n", __func__);
+ return NL_SKIP;
+ }
+
+ data_ptr = (u8*)data;
+ for (int i = 0; i < num_radios; i++) {
+ rem_len -= per_radio_size;
+ if (rem_len < per_radio_size) {
+ ALOGE("No data left for radio %d\n", i);
+ goto exit;
+ }
+ data_ptr = (u8*)data + total_size;
+ if (!data_ptr) {
+ ALOGE("Invalid data for radio index = %d\n", i);
+ goto exit;
+ }
+ radio_stat_ptr =
+ convertToExternalRadioStatStructure((wifi_radio_stat*)data_ptr,
+ &per_radio_size);
+ if (!radio_stat_ptr || !per_radio_size) {
+ ALOGE("No data for radio %d\n", i);
+ continue;
+ }
+ memcpy(output, radio_stat_ptr, per_radio_size);
+ output += per_radio_size;
+ total_size += per_radio_size;
+ }
+
+ iface_stat = ((u8*)data + total_size);
+ if (!iface_stat || data_len < total_size) {
+ ALOGE("No data for iface stats!!, data_len = %d, total_size = %d\n",
+ data_len, total_size);
+ goto exit;
+ }
+ (*mHandler.on_link_stats_results)(id, (wifi_iface_stat *)iface_stat,
+ num_radios, (wifi_radio_stat *)radioStatsBuf);
+ } else {
+ /* To be deprecated, adding it to keep it backward compatible */
+ ALOGD("GetLinkStatCommand: zero radio case\n");
+ data = reply.get_vendor_data();
+ if (!data) {
+ ALOGE("Invalid vendor data received\n");
+ return NL_SKIP;
+ }
+
+ num_radios = 1;
+ data = reply.get_vendor_data();
+ len = reply.get_vendor_data_len();
+ if (!data || !len) {
+ ALOGE("Invalid vendor data received\n");
+ return NL_SKIP;
+ }
+ radio_stat_ptr =
+ convertToExternalRadioStatStructureLegacy((wifi_radio_stat_internal *)data);
+ if (!radio_stat_ptr) {
+ ALOGE("Invalid stats pointer received\n");
+ return NL_SKIP;
+ }
+ wifi_iface_stat *iface_stat =
+ (wifi_iface_stat *)((char *)&((wifi_radio_stat_internal *)data)->channels
+ + radio_stat_ptr->num_channels * sizeof(wifi_channel_stat));
+ (*mHandler.on_link_stats_results)(id, iface_stat, num_radios, radio_stat_ptr);
+ }
+exit:
+ if (radio_stat_ptr) {
+ free(radio_stat_ptr);
+ radio_stat_ptr = NULL;
+ }
+ if (radioStatsBuf) {
+ free(radioStatsBuf);
+ radioStatsBuf = NULL;
+ }
return NL_OK;
}
private:
- wifi_radio_stat *convertToExternalRadioStatStructure(wifi_radio_stat_internal *internal_stat_ptr) {
+ wifi_radio_stat *convertToExternalRadioStatStructure(wifi_radio_stat *internal_stat_ptr,
+ uint32_t *per_radio_size) {
+ wifi_radio_stat *external_stat_ptr = NULL;
+ if (!internal_stat_ptr) {
+ ALOGE("Incoming data is null\n");
+ } else {
+ uint32_t channel_size = internal_stat_ptr->num_channels * sizeof(wifi_channel_stat);
+ *per_radio_size = offsetof(wifi_radio_stat, channels) + channel_size;
+ external_stat_ptr = (wifi_radio_stat *)malloc(*per_radio_size);
+ if (external_stat_ptr) {
+ external_stat_ptr->radio = internal_stat_ptr->radio;
+ external_stat_ptr->on_time = internal_stat_ptr->on_time;
+ external_stat_ptr->tx_time = internal_stat_ptr->tx_time;
+ external_stat_ptr->num_tx_levels = internal_stat_ptr->num_tx_levels;
+ external_stat_ptr->tx_time_per_levels = NULL;
+ external_stat_ptr->rx_time = internal_stat_ptr->rx_time;
+ external_stat_ptr->on_time_scan = internal_stat_ptr->on_time_scan;
+ external_stat_ptr->on_time_nbd = internal_stat_ptr->on_time_nbd;
+ external_stat_ptr->on_time_gscan = internal_stat_ptr->on_time_gscan;
+ external_stat_ptr->on_time_roam_scan = internal_stat_ptr->on_time_roam_scan;
+ external_stat_ptr->on_time_pno_scan = internal_stat_ptr->on_time_pno_scan;
+ external_stat_ptr->on_time_hs20 = internal_stat_ptr->on_time_hs20;
+ external_stat_ptr->num_channels = internal_stat_ptr->num_channels;
+ if (internal_stat_ptr->num_channels) {
+ memcpy(&(external_stat_ptr->channels), &(internal_stat_ptr->channels),
+ channel_size);
+ }
+ }
+ }
+ return external_stat_ptr;
+ }
+
+ wifi_radio_stat *convertToExternalRadioStatStructureLegacy(wifi_radio_stat_internal *internal_stat_ptr) {
wifi_radio_stat *external_stat_ptr = NULL;
- if (!internal_stat_ptr) {
- ALOGE("Sta_ptr is null\n");
- } else {
+ if (!internal_stat_ptr) {
+ ALOGE("Sta_ptr is null\n");
+ } else {
uint32_t channel_size = internal_stat_ptr->num_channels * sizeof(wifi_channel_stat);
uint32_t total_size = sizeof(wifi_radio_stat) + channel_size;
external_stat_ptr = (wifi_radio_stat *)malloc(total_size);