WiFi: Get peer information (BSS load and rate statistics) from link layer stats
Bug: 177069641
Test: atest VtsHalWifiV1_5TargetTest
Signed-off-by: Mingguang Xu <mingguangxu@google.com>
Change-Id: I3373d065a3b04d86f52d5bffe28d5581746cef4a
diff --git a/wifi/1.5/default/hidl_struct_util.cpp b/wifi/1.5/default/hidl_struct_util.cpp
index cd0edbe..baa898e 100644
--- a/wifi/1.5/default/hidl_struct_util.cpp
+++ b/wifi/1.5/default/hidl_struct_util.cpp
@@ -1077,6 +1077,17 @@
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].contention_num_samples;
hidl_stats->iface.timeSliceDutyCycleInPercent =
legacy_stats.iface.info.time_slicing_duty_cycle_percent;
+ // peer info legacy_stats conversion.
+ std::vector<StaPeerInfo> hidl_peers_info_stats;
+ for (const auto& legacy_peer_info_stats : legacy_stats.peers) {
+ StaPeerInfo hidl_peer_info_stats;
+ if (!convertLegacyPeerInfoStatsToHidl(legacy_peer_info_stats,
+ &hidl_peer_info_stats)) {
+ return false;
+ }
+ hidl_peers_info_stats.push_back(hidl_peer_info_stats);
+ }
+ hidl_stats->iface.peers = hidl_peers_info_stats;
// radio legacy_stats conversion.
std::vector<V1_3::StaLinkLayerRadioStats> hidl_radios_stats;
for (const auto& legacy_radio_stats : legacy_stats.radios) {
@@ -1094,6 +1105,35 @@
return true;
}
+bool convertLegacyPeerInfoStatsToHidl(
+ const legacy_hal::WifiPeerInfo& legacy_peer_info_stats,
+ StaPeerInfo* hidl_peer_info_stats) {
+ if (!hidl_peer_info_stats) {
+ return false;
+ }
+ *hidl_peer_info_stats = {};
+ hidl_peer_info_stats->staCount =
+ legacy_peer_info_stats.peer_info.bssload.sta_count;
+ hidl_peer_info_stats->chanUtil =
+ legacy_peer_info_stats.peer_info.bssload.chan_util;
+
+ std::vector<StaRateStat> hidlRateStats;
+ for (const auto& legacy_rate_stats : legacy_peer_info_stats.rate_stats) {
+ StaRateStat rateStat;
+ if (!convertLegacyWifiRateInfoToHidl(legacy_rate_stats.rate,
+ &rateStat.rateInfo)) {
+ return false;
+ }
+ rateStat.txMpdu = legacy_rate_stats.tx_mpdu;
+ rateStat.rxMpdu = legacy_rate_stats.rx_mpdu;
+ rateStat.mpduLost = legacy_rate_stats.mpdu_lost;
+ rateStat.retries = legacy_rate_stats.retries;
+ hidlRateStats.push_back(rateStat);
+ }
+ hidl_peer_info_stats->rateStats = hidlRateStats;
+ return true;
+}
+
bool convertLegacyRoamingCapabilitiesToHidl(
const legacy_hal::wifi_roaming_capabilities& legacy_caps,
StaRoamingCapabilities* hidl_caps) {
diff --git a/wifi/1.5/default/hidl_struct_util.h b/wifi/1.5/default/hidl_struct_util.h
index 8b81033..352f213 100644
--- a/wifi/1.5/default/hidl_struct_util.h
+++ b/wifi/1.5/default/hidl_struct_util.h
@@ -212,6 +212,11 @@
bool convertLegacyWifiUsableChannelsToHidl(
const std::vector<legacy_hal::wifi_usable_channel>& legacy_usable_channels,
std::vector<V1_5::WifiUsableChannel>* hidl_usable_channels);
+bool convertLegacyPeerInfoStatsToHidl(
+ const legacy_hal::WifiPeerInfo& legacy_peer_info_stats,
+ StaPeerInfo* hidl_peer_info_stats);
+bool convertLegacyWifiRateInfoToHidl(const legacy_hal::wifi_rate& legacy_rate,
+ V1_4::WifiRateInfo* hidl_rate);
} // namespace hidl_struct_util
} // namespace implementation
} // namespace V1_5
diff --git a/wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp
index 6391a6a..e70d7ba 100644
--- a/wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp
+++ b/wifi/1.5/default/tests/hidl_struct_util_unit_tests.cpp
@@ -132,6 +132,8 @@
legacy_hal::LinkLayerStats legacy_stats{};
legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
+ legacy_stats.peers.push_back(legacy_hal::WifiPeerInfo{});
+ legacy_stats.peers.push_back(legacy_hal::WifiPeerInfo{});
legacy_stats.iface.beacon_rx = rand();
legacy_stats.iface.rssi_mgmt = rand();
legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu = rand();
@@ -175,6 +177,7 @@
rand();
legacy_stats.iface.info.time_slicing_duty_cycle_percent = rand();
+ legacy_stats.iface.num_peers = 1;
for (auto& radio : legacy_stats.radios) {
radio.stats.on_time = rand();
@@ -204,6 +207,31 @@
radio.channel_stats.push_back(channel_stat2);
}
+ for (auto& peer : legacy_stats.peers) {
+ peer.peer_info.bssload.sta_count = rand();
+ peer.peer_info.bssload.chan_util = rand();
+ wifi_rate_stat rate_stat1 = {
+ .rate = {3, 1, 2, 5, 0, 0},
+ .tx_mpdu = 0,
+ .rx_mpdu = 1,
+ .mpdu_lost = 2,
+ .retries = 3,
+ .retries_short = 4,
+ .retries_long = 5,
+ };
+ wifi_rate_stat rate_stat2 = {
+ .rate = {2, 2, 1, 6, 0, 1},
+ .tx_mpdu = 6,
+ .rx_mpdu = 7,
+ .mpdu_lost = 8,
+ .retries = 9,
+ .retries_short = 10,
+ .retries_long = 11,
+ };
+ peer.rate_stats.push_back(rate_stat1);
+ peer.rate_stats.push_back(rate_stat2);
+ }
+
V1_5::StaLinkLayerStats converted{};
hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats,
&converted);
@@ -330,6 +358,37 @@
converted.radios[i].channelStats[k].onTimeInMs);
}
}
+
+ EXPECT_EQ(legacy_stats.peers.size(), converted.iface.peers.size());
+ for (size_t i = 0; i < legacy_stats.peers.size(); i++) {
+ EXPECT_EQ(legacy_stats.peers[i].peer_info.bssload.sta_count,
+ converted.iface.peers[i].staCount);
+ EXPECT_EQ(legacy_stats.peers[i].peer_info.bssload.chan_util,
+ converted.iface.peers[i].chanUtil);
+ for (size_t j = 0; j < legacy_stats.peers[i].rate_stats.size(); j++) {
+ EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rate.preamble,
+ (uint32_t)converted.iface.peers[i]
+ .rateStats[j]
+ .rateInfo.preamble);
+ EXPECT_EQ(
+ legacy_stats.peers[i].rate_stats[j].rate.nss,
+ (uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.nss);
+ EXPECT_EQ(
+ legacy_stats.peers[i].rate_stats[j].rate.bw,
+ (uint32_t)converted.iface.peers[i].rateStats[j].rateInfo.bw);
+ EXPECT_EQ(
+ legacy_stats.peers[i].rate_stats[j].rate.rateMcsIdx,
+ converted.iface.peers[i].rateStats[j].rateInfo.rateMcsIdx);
+ EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].tx_mpdu,
+ converted.iface.peers[i].rateStats[j].txMpdu);
+ EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].rx_mpdu,
+ converted.iface.peers[i].rateStats[j].rxMpdu);
+ EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].mpdu_lost,
+ converted.iface.peers[i].rateStats[j].mpduLost);
+ EXPECT_EQ(legacy_stats.peers[i].rate_stats[j].retries,
+ converted.iface.peers[i].rateStats[j].retries);
+ }
+ }
}
TEST_F(HidlStructUtilTest, CanConvertLegacyFeaturesToHidl) {
diff --git a/wifi/1.5/default/wifi_legacy_hal.cpp b/wifi/1.5/default/wifi_legacy_hal.cpp
index f5ca753..8c64ebc 100644
--- a/wifi/1.5/default/wifi_legacy_hal.cpp
+++ b/wifi/1.5/default/wifi_legacy_hal.cpp
@@ -715,9 +715,29 @@
wifi_iface_stat* iface_stats_ptr, int num_radios,
wifi_radio_stat* radio_stats_ptr) {
wifi_radio_stat* l_radio_stats_ptr;
+ wifi_peer_info* l_peer_info_stats_ptr;
if (iface_stats_ptr != nullptr) {
link_stats_ptr->iface = *iface_stats_ptr;
+ l_peer_info_stats_ptr = iface_stats_ptr->peer_info;
+ for (uint32_t i = 0; i < iface_stats_ptr->num_peers; i++) {
+ WifiPeerInfo peer;
+ peer.peer_info = *l_peer_info_stats_ptr;
+ if (l_peer_info_stats_ptr->num_rate > 0) {
+ /* Copy the rate stats */
+ peer.rate_stats.assign(
+ l_peer_info_stats_ptr->rate_stats,
+ l_peer_info_stats_ptr->rate_stats +
+ l_peer_info_stats_ptr->num_rate);
+ }
+ peer.peer_info.num_rate = 0;
+ link_stats_ptr->peers.push_back(peer);
+ l_peer_info_stats_ptr =
+ (wifi_peer_info*)((u8*)l_peer_info_stats_ptr +
+ sizeof(wifi_peer_info) +
+ (sizeof(wifi_rate_stat) *
+ l_peer_info_stats_ptr->num_rate));
+ }
link_stats_ptr->iface.num_peers = 0;
} else {
LOG(ERROR) << "Invalid iface stats in link layer stats";
diff --git a/wifi/1.5/default/wifi_legacy_hal.h b/wifi/1.5/default/wifi_legacy_hal.h
index 03ca841..cf2450d 100644
--- a/wifi/1.5/default/wifi_legacy_hal.h
+++ b/wifi/1.5/default/wifi_legacy_hal.h
@@ -340,9 +340,15 @@
std::vector<wifi_channel_stat> channel_stats;
};
+struct WifiPeerInfo {
+ wifi_peer_info peer_info;
+ std::vector<wifi_rate_stat> rate_stats;
+};
+
struct LinkLayerStats {
wifi_iface_stat iface;
std::vector<LinkLayerRadioStats> radios;
+ std::vector<WifiPeerInfo> peers;
};
#pragma GCC diagnostic pop
diff --git a/wifi/1.5/types.hal b/wifi/1.5/types.hal
index e1c0d32..0543004 100644
--- a/wifi/1.5/types.hal
+++ b/wifi/1.5/types.hal
@@ -26,6 +26,7 @@
import @1.3::StaLinkLayerRadioStats;
import @1.0::WifiChannelInMhz;
import @1.0::WifiChannelWidthInMhz;
+import @1.4::WifiRateInfo;
/**
* Wifi bands defined in 80211 spec.
@@ -162,6 +163,54 @@
};
/**
+ * Per rate statistics. The rate is characterized by the combination of preamble, number of spatial
+ * streams, transmission bandwidth, and modulation and coding scheme (MCS).
+ */
+struct StaRateStat{
+ /**
+ * Wifi rate information: preamble, number of spatial streams, bandwidth, MCS, etc.
+ */
+ WifiRateInfo rateInfo;
+ /**
+ * Number of successfully transmitted data packets (ACK received)
+ */
+ uint32_t txMpdu;
+ /**
+ * Number of received data packets
+ */
+ uint32_t rxMpdu;
+ /**
+ * Number of data packet losses (no ACK)
+ */
+ uint32_t mpduLost;
+ /**
+ * Number of data packet retries
+ */
+ uint32_t retries;
+};
+
+/**
+ * Per peer statistics. The types of peer include the Access Point (AP), the Tunneled Direct Link
+ * Setup (TDLS), the Group Owner (GO), the Neighbor Awareness Networking (NAN), etc.
+ */
+struct StaPeerInfo {
+ /**
+ * Station count: The total number of stations currently associated with the peer.
+ */
+ uint16_t staCount;
+ /**
+ * Channel utilization: The percentage of time (normalized to 255, i.e., x% corresponds to
+ * (int) x * 255 / 100) that the medium is sensed as busy measured by either physical or
+ * virtual carrier sense (CS) mechanism.
+ */
+ uint16_t chanUtil;
+ /**
+ * Per rate statistics
+ */
+ vec<StaRateStat> rateStats;
+};
+
+/**
* Iface statistics for the current connection.
*/
struct StaLinkLayerIfaceStats {
@@ -197,6 +246,11 @@
* WME Voice (VO) Access Category (AC) contention time statistics.
*/
StaLinkLayerIfaceContentionTimeStats wmeVoContentionTimeStats;
+
+ /**
+ * Per peer statistics.
+ */
+ vec<StaPeerInfo> peers;
};
/**