summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKai Shi <kaishi@google.com>2020-02-11 22:13:36 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2020-02-11 22:13:36 +0000
commit83baec8531a4d5b7870190b71d2cceaad61d538b (patch)
tree0e39930ccec985b91c0e1ae97e579672cd67f144
parent413d7e3aaf017a055f79f9066f8cc4a85cf4f1f6 (diff)
parent731bd94be0770dd9f6e84f3e573486c6e40e020d (diff)
downloadwificond-83baec8531a4d5b7870190b71d2cceaad61d538b.tar.gz
Merge "Parse nl80211 PHY attributes"
-rw-r--r--net/netlink_utils.cpp162
-rw-r--r--net/netlink_utils.h25
-rw-r--r--tests/netlink_utils_unittest.cpp71
3 files changed, 255 insertions, 3 deletions
diff --git a/net/netlink_utils.cpp b/net/netlink_utils.cpp
index 41bb34e..b7d5ebb 100644
--- a/net/netlink_utils.cpp
+++ b/net/netlink_utils.cpp
@@ -37,6 +37,7 @@ using std::make_pair;
using std::make_unique;
using std::map;
using std::move;
+using std::pair;
using std::string;
using std::unique_ptr;
using std::vector;
@@ -57,6 +58,16 @@ uint32_t k5GHzFrequencyUpperBound = 5850;
uint32_t k6GHzFrequencyLowerBound = 5925;
uint32_t k6GHzFrequencyUpperBound = 7125;
+constexpr uint8_t kHtMcsSetNumByte = 16;
+constexpr uint8_t kVhtMcsSetNumByte = 8;
+constexpr uint8_t kHeMcsSetNumByteMin = 4;
+constexpr uint8_t kMaxStreams = 8;
+constexpr uint8_t kVht160MhzBitMask = 0x4;
+constexpr uint8_t kVht80p80MhzBitMask = 0x8;
+constexpr uint8_t kHeCapPhyNumByte = 11;
+constexpr uint8_t kHe160MhzBitMask = 0x8;
+constexpr uint8_t kHe80p80MhzBitMask = 0x10;
+
bool IsExtFeatureFlagSet(
const std::vector<uint8_t>& ext_feature_flags_bytes,
enum nl80211_ext_feature_index ext_feature_flag) {
@@ -421,7 +432,6 @@ bool NetlinkUtils::ParseBandInfo(const NL80211Packet* const packet,
}
*out_band_info = BandInfo();
- //TODO: b/144576344: Need to get also channel width, and #streams
for (auto& band : bands) {
NL80211NestedAttr freqs_attr(0);
if (band.GetAttribute(NL80211_BAND_ATTR_FREQS, &freqs_attr)) {
@@ -441,6 +451,7 @@ bool NetlinkUtils::ParseBandInfo(const NL80211Packet* const packet,
out_band_info->is_80211ax_supported = true;
}
}
+ ParsePhyCapabilities(band, out_band_info);
}
return true;
@@ -498,6 +509,155 @@ void NetlinkUtils::handleBandFreqAttributes(const NL80211NestedAttr& freqs_attr,
}
}
+void NetlinkUtils::ParsePhyCapabilities(const NL80211NestedAttr& band,
+ BandInfo* out_band_info) {
+ ParseHtMcsSetAttribute(band, out_band_info);
+ ParseVhtMcsSetAttribute(band, out_band_info);
+ ParseHeMcsSetAttribute(band, out_band_info);
+ ParseVhtCapAttribute(band, out_band_info);
+ ParseHeCapAttribute(band, out_band_info);
+}
+
+void NetlinkUtils::ParseHtMcsSetAttribute(const NL80211NestedAttr& band,
+ BandInfo* out_band_info) {
+ vector<uint8_t> ht_mcs_set;
+ if (!band.GetAttributeValue(NL80211_BAND_ATTR_HT_MCS_SET, &ht_mcs_set)) {
+ return;
+ }
+ if (ht_mcs_set.size() < kHtMcsSetNumByte) {
+ LOG(ERROR) << "HT MCS set size is incorrect";
+ return;
+ }
+ pair<uint32_t, uint32_t> max_streams_ht = ParseHtMcsSet(ht_mcs_set);
+ out_band_info->max_tx_streams = std::max(out_band_info->max_tx_streams,
+ max_streams_ht.first);
+ out_band_info->max_rx_streams = std::max(out_band_info->max_rx_streams,
+ max_streams_ht.second);
+}
+
+pair<uint32_t, uint32_t> NetlinkUtils::ParseHtMcsSet(
+ const vector<uint8_t>& ht_mcs_set) {
+ uint32_t max_rx_streams = 1;
+ for (int i = 4; i >= 1; i--) {
+ if (ht_mcs_set[i - 1] > 0) {
+ max_rx_streams = i;
+ break;
+ }
+ }
+
+ uint32_t max_tx_streams = max_rx_streams;
+ uint8_t supported_tx_mcs_set = ht_mcs_set[12];
+ uint8_t tx_mcs_set_defined = supported_tx_mcs_set & 0x1;
+ uint8_t tx_rx_mcs_set_not_equal = (supported_tx_mcs_set >> 1) & 0x1;
+ if (tx_mcs_set_defined && tx_rx_mcs_set_not_equal) {
+ uint8_t max_nss_tx_field_value = (supported_tx_mcs_set >> 2) & 0x3;
+ // The maximum number of Tx streams is 1 more than the field value.
+ max_tx_streams = max_nss_tx_field_value + 1;
+ }
+
+ return std::make_pair(max_tx_streams, max_rx_streams);
+}
+
+void NetlinkUtils::ParseVhtMcsSetAttribute(const NL80211NestedAttr& band,
+ BandInfo* out_band_info) {
+ vector<uint8_t> vht_mcs_set;
+ if (!band.GetAttributeValue(NL80211_BAND_ATTR_VHT_MCS_SET, &vht_mcs_set)) {
+ return;
+ }
+ if (vht_mcs_set.size() < kVhtMcsSetNumByte) {
+ LOG(ERROR) << "VHT MCS set size is incorrect";
+ return;
+ }
+ uint16_t vht_mcs_set_rx = (vht_mcs_set[1] << 8) | vht_mcs_set[0];
+ uint32_t max_rx_streams_vht = ParseMcsMap(vht_mcs_set_rx);
+ uint16_t vht_mcs_set_tx = (vht_mcs_set[5] << 8) | vht_mcs_set[4];
+ uint32_t max_tx_streams_vht = ParseMcsMap(vht_mcs_set_tx);
+ out_band_info->max_tx_streams = std::max(out_band_info->max_tx_streams,
+ max_tx_streams_vht);
+ out_band_info->max_rx_streams = std::max(out_band_info->max_rx_streams,
+ max_rx_streams_vht);
+}
+
+void NetlinkUtils::ParseHeMcsSetAttribute(const NL80211NestedAttr& band,
+ BandInfo* out_band_info) {
+ NL80211NestedAttr iftype_data_attr(0);
+ if (!band.GetAttribute(NL80211_BAND_ATTR_IFTYPE_DATA, &iftype_data_attr)) {
+ return;
+ }
+ vector<uint8_t> he_mcs_set;
+ if (!iftype_data_attr.GetAttributeValue(
+ NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET,
+ &he_mcs_set)) {
+ return;
+ }
+ if (he_mcs_set.size() < kHeMcsSetNumByteMin) {
+ LOG(ERROR) << "HE MCS set size is incorrect";
+ return;
+ }
+ uint16_t he_mcs_map_rx = (he_mcs_set[1] << 8) | he_mcs_set[0];
+ uint32_t max_rx_streams_he = ParseMcsMap(he_mcs_map_rx);
+ uint16_t he_mcs_map_tx = (he_mcs_set[3] << 8) | he_mcs_set[2];
+ uint32_t max_tx_streams_he = ParseMcsMap(he_mcs_map_tx);
+ out_band_info->max_tx_streams = std::max(out_band_info->max_tx_streams,
+ max_tx_streams_he);
+ out_band_info->max_rx_streams = std::max(out_band_info->max_rx_streams,
+ max_rx_streams_he);
+}
+
+uint32_t NetlinkUtils::ParseMcsMap(uint16_t mcs_map)
+{
+ uint32_t max_nss = 1;
+ for (int i = kMaxStreams; i >= 1; i--) {
+ uint16_t stream_map = (mcs_map >> ((i - 1) * 2)) & 0x3;
+ // 0x3 means unsupported
+ if (stream_map != 0x3) {
+ max_nss = i;
+ break;
+ }
+ }
+ return max_nss;
+}
+
+void NetlinkUtils::ParseVhtCapAttribute(const NL80211NestedAttr& band,
+ BandInfo* out_band_info) {
+ uint32_t vht_cap;
+ if (!band.GetAttributeValue(NL80211_BAND_ATTR_VHT_CAPA, &vht_cap)) {
+ return;
+ }
+
+ if (vht_cap & kVht160MhzBitMask) {
+ out_band_info->is_160_mhz_supported = true;
+ }
+ if (vht_cap & kVht80p80MhzBitMask) {
+ out_band_info->is_80p80_mhz_supported = true;
+ }
+}
+
+void NetlinkUtils::ParseHeCapAttribute(const NL80211NestedAttr& band,
+ BandInfo* out_band_info) {
+ NL80211NestedAttr iftype_data_attr(0);
+ if (!band.GetAttribute(NL80211_BAND_ATTR_IFTYPE_DATA, &iftype_data_attr)) {
+ return;
+ }
+ vector<uint8_t> he_cap_phy;
+ if (!iftype_data_attr.GetAttributeValue(
+ NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY,
+ &he_cap_phy)) {
+ return;
+ }
+
+ if (he_cap_phy.size() < kHeCapPhyNumByte) {
+ LOG(ERROR) << "HE Cap PHY size is incorrect";
+ return;
+ }
+ if (he_cap_phy[0] & kHe160MhzBitMask) {
+ out_band_info->is_160_mhz_supported = true;
+ }
+ if (he_cap_phy[0] & kHe80p80MhzBitMask) {
+ out_band_info->is_80p80_mhz_supported = true;
+ }
+}
+
bool NetlinkUtils::GetStationInfo(uint32_t interface_index,
const array<uint8_t, ETH_ALEN>& mac_address,
StationInfo* out_station_info) {
diff --git a/net/netlink_utils.h b/net/netlink_utils.h
index 938ed28..d214f94 100644
--- a/net/netlink_utils.h
+++ b/net/netlink_utils.h
@@ -50,7 +50,14 @@ struct InterfaceInfo {
};
struct BandInfo {
- BandInfo() = default;
+ BandInfo():
+ is_80211n_supported(false),
+ is_80211ac_supported(false),
+ is_80211ax_supported(false),
+ is_160_mhz_supported(false),
+ is_80p80_mhz_supported(false),
+ max_tx_streams(1),
+ max_rx_streams(1) {};
// Frequencies for 2.4 GHz band.
std::vector<uint32_t> band_2g;
// Frequencies for 5 GHz band without DFS.
@@ -290,6 +297,22 @@ class NetlinkUtils {
WiphyFeatures* out_wiphy_features);
bool ParseBandInfo(const NL80211Packet* const packet,
BandInfo* out_band_info);
+ void ParsePhyCapabilities(const NL80211NestedAttr& band,
+ BandInfo* out_band_info);
+ void ParseHtMcsSetAttribute(const NL80211NestedAttr& band,
+ BandInfo* out_band_info);
+ void ParseVhtMcsSetAttribute(const NL80211NestedAttr& band,
+ BandInfo* out_band_info);
+ void ParseHeMcsSetAttribute(const NL80211NestedAttr& band,
+ BandInfo* out_band_info);
+ std::pair<uint32_t, uint32_t> ParseHtMcsSet(
+ const std::vector<uint8_t>& ht_mcs_set);
+ uint32_t ParseMcsMap(uint16_t mcs_map);
+ void ParseVhtCapAttribute(const NL80211NestedAttr& band,
+ BandInfo* out_band_info);
+ void ParseHeCapAttribute(const NL80211NestedAttr& band,
+ BandInfo* out_band_info);
+
bool ParseScanCapabilities(const NL80211Packet* const packet,
ScanCapabilities* out_scan_capabilities);
diff --git a/tests/netlink_utils_unittest.cpp b/tests/netlink_utils_unittest.cpp
index 34f5c21..316eea4 100644
--- a/tests/netlink_utils_unittest.cpp
+++ b/tests/netlink_utils_unittest.cpp
@@ -75,7 +75,19 @@ const uint8_t kFakeExtFeaturesForLowPowerScan[] = {0x0, 0x0, 0x80};
const uint8_t kFakeExtFeaturesForHighAccuracy[] = {0x0, 0x0, 0x0, 0x1};
const uint8_t kFakeExtFeaturesForAllScanType[] = {0x0, 0x0, 0xC0, 0x1};
const uint8_t kFakeFrame[] = {0x00, 0x01, 0x02, 0x03};
-
+constexpr bool k11nSupported = true;
+constexpr bool k11acSupported = true;
+constexpr bool k11axSupported = true;
+constexpr uint8_t kMaxTxStreams = 4;
+constexpr uint8_t kMaxRxStreams = 5;
+constexpr bool k160MHzSupported = true;
+constexpr bool k80p80MHzSupported = false;
+const uint8_t kHtMcsSet[] = {0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0xf, 0x0, 0x0, 0x0};
+const uint8_t kVhtMcsSet[] = {0xaa, 0xfe, 0xff, 0xff, 0xaa, 0xff, 0xff, 0xff};
+const uint8_t kHeMcsSet[] = {0xaa, 0xfe, 0xaa, 0xff};
+const uint8_t kVhtCap[] = {0x4, 0x0, 0x0, 0x0};
+const uint8_t kHeCapPhy[] = {0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
// Currently, control messages are only created by the kernel and sent to us.
// Therefore NL80211Packet doesn't have corresponding constructor.
@@ -121,6 +133,53 @@ void AppendScanCapabilitiesAttributes(NL80211Packet* packet,
}
}
+
+NL80211Attr<std::vector<uint8_t>> GenerateBandsAttributeForHtCapa() {
+ std::vector<uint8_t> ht_cap(2, 0);
+ return NL80211Attr<std::vector<uint8_t>>(NL80211_BAND_ATTR_HT_CAPA,
+ ht_cap);
+}
+
+
+NL80211Attr<std::vector<uint8_t>> GenerateBandsAttributeForVhtCapa() {
+ std::vector<uint8_t> vht_cap(kVhtCap, kVhtCap + sizeof(kVhtCap));
+ return NL80211Attr<std::vector<uint8_t>>(NL80211_BAND_ATTR_VHT_CAPA,
+ vht_cap);
+}
+
+NL80211Attr<std::vector<uint8_t>> GenerateBandsAttributeForHtMcsSet() {
+ std::vector<uint8_t> ht_mcs_set(kHtMcsSet, kHtMcsSet + sizeof(kHtMcsSet));
+ return NL80211Attr<std::vector<uint8_t>>(NL80211_BAND_ATTR_HT_MCS_SET,
+ ht_mcs_set);
+}
+
+NL80211Attr<std::vector<uint8_t>> GenerateBandsAttributeForVhtMcsSet() {
+ std::vector<uint8_t> vht_mcs_set(kVhtMcsSet, kVhtMcsSet + sizeof(kVhtMcsSet));
+ return NL80211Attr<std::vector<uint8_t>>(NL80211_BAND_ATTR_VHT_MCS_SET,
+ vht_mcs_set);
+}
+
+NL80211NestedAttr GenerateBandsAttributeForIfTypeData() {
+ NL80211NestedAttr if_type_data(NL80211_BAND_ATTR_IFTYPE_DATA);
+ std::vector<uint8_t> he_cap_phy(kHeCapPhy, kHeCapPhy + sizeof(kHeCapPhy));
+ std::vector<uint8_t> he_mcs_set(kHeMcsSet, kHeMcsSet + sizeof(kHeMcsSet));
+
+ if_type_data.AddAttribute(NL80211Attr<std::vector<uint8_t>>(
+ NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY, he_cap_phy));
+ if_type_data.AddAttribute(NL80211Attr<std::vector<uint8_t>>(
+ NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET, he_mcs_set));
+ return if_type_data;
+}
+
+void AppendBandPhyAttributes(NL80211NestedAttr* band_attr) {
+ band_attr->AddAttribute(GenerateBandsAttributeForHtCapa());
+ band_attr->AddAttribute(GenerateBandsAttributeForHtMcsSet());
+ band_attr->AddAttribute(GenerateBandsAttributeForVhtCapa());
+ band_attr->AddAttribute(GenerateBandsAttributeForVhtMcsSet());
+
+ band_attr->AddAttribute(GenerateBandsAttributeForIfTypeData());
+}
+
NL80211NestedAttr GenerateBandsAttributeFor2g() {
NL80211NestedAttr freq_2g_1(1);
NL80211NestedAttr freq_2g_2(2);
@@ -139,6 +198,7 @@ NL80211NestedAttr GenerateBandsAttributeFor2g() {
NL80211NestedAttr band_2g_attr(1);
band_2g_attr.AddAttribute(band_2g_freqs);
+ AppendBandPhyAttributes(&band_2g_attr);
NL80211NestedAttr band_attr(NL80211_ATTR_WIPHY_BANDS);
band_attr.AddAttribute(band_2g_attr);
@@ -177,6 +237,7 @@ NL80211NestedAttr GenerateBandsAttributeFor5gAndDfs() {
NL80211NestedAttr band_5g_attr(1);
band_5g_attr.AddAttribute(band_5g_freqs);
+ AppendBandPhyAttributes(&band_5g_attr);
NL80211NestedAttr band_attr(NL80211_ATTR_WIPHY_BANDS);
band_attr.AddAttribute(band_5g_attr);
@@ -187,6 +248,7 @@ void AppendBandInfoAttributes(NL80211Packet* packet) {
NL80211NestedAttr attr_2g = GenerateBandsAttributeFor2g();
NL80211NestedAttr attr_5g_and_dfs = GenerateBandsAttributeFor5gAndDfs();
attr_2g.Merge(attr_5g_and_dfs);
+
packet->AddAttribute(attr_2g);
}
@@ -267,6 +329,13 @@ void VerifyBandInfo(const BandInfo& band_info) {
EXPECT_EQ(band_info.band_2g, band_2g_expected);
EXPECT_EQ(band_info.band_5g, band_5g_expected);
EXPECT_EQ(band_info.band_dfs, band_dfs_expected);
+ EXPECT_EQ(band_info.is_80211n_supported, k11nSupported);
+ EXPECT_EQ(band_info.is_80211ac_supported, k11acSupported);
+ EXPECT_EQ(band_info.is_80211ax_supported, k11axSupported);
+ EXPECT_EQ(band_info.is_160_mhz_supported, k160MHzSupported);
+ EXPECT_EQ(band_info.is_80p80_mhz_supported, k80p80MHzSupported);
+ EXPECT_EQ(band_info.max_tx_streams, kMaxTxStreams);
+ EXPECT_EQ(band_info.max_rx_streams, kMaxRxStreams);
}
void VerifyWiphyFeatures(const WiphyFeatures& wiphy_features) {