diff options
| author | Xin Li <delphij@google.com> | 2020-09-08 16:57:18 -0700 |
|---|---|---|
| committer | Xin Li <delphij@google.com> | 2020-09-08 16:57:18 -0700 |
| commit | eaf7c4998d15c61360bdcd716fb02b33acd8b526 (patch) | |
| tree | 7535ac3f76cce213db2f66501107c5e68c4830e3 /net/netlink_utils.cpp | |
| parent | 0bcc0e4488989dad285c7664b4cdaa6eaad666d4 (diff) | |
| parent | 7e90494ad7cd8b2a5f52781a636ae34af1904c97 (diff) | |
| download | platform_system_connectivity_wificond-master.tar.gz platform_system_connectivity_wificond-master.tar.bz2 platform_system_connectivity_wificond-master.zip | |
Bug: 168057903
Merged-In: I3b0a326c6381091e8721811fb5ea352e6af1031f
Change-Id: Id8a690a46c023b26372220ab8878b86b2b881eeb
Diffstat (limited to 'net/netlink_utils.cpp')
| -rw-r--r-- | net/netlink_utils.cpp | 287 |
1 files changed, 242 insertions, 45 deletions
diff --git a/net/netlink_utils.cpp b/net/netlink_utils.cpp index f395d92..c31249d 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; @@ -52,7 +53,22 @@ uint32_t k2GHzFrequencyUpperBound = 2500; uint32_t k5GHzFrequencyLowerBound = 5000; // This upper bound will exclude any 5.9Ghz channels which belong to 802.11p // for "vehicular communication systems". -uint32_t k5GHzFrequencyUpperBound = 5850; +uint32_t k5GHzFrequencyUpperBound = 5865; + +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; +// Some old Linux kernel versions set it to 9. +// 9 is OK because only 1st byte is used +constexpr uint8_t kHeCapPhyNumByte = 9; // Should be 11 +constexpr uint8_t kHe160MhzBitMask = 0x8; +constexpr uint8_t kHe80p80MhzBitMask = 0x10; bool IsExtFeatureFlagSet( const std::vector<uint8_t>& ext_feature_flags_bytes, @@ -416,62 +432,243 @@ bool NetlinkUtils::ParseBandInfo(const NL80211Packet* const packet, LOG(ERROR) << "Failed to get bands within NL80211_ATTR_WIPHY_BANDS"; return false; } - vector<uint32_t> frequencies_2g; - vector<uint32_t> frequencies_5g; - vector<uint32_t> frequencies_dfs; - for (unsigned int band_index = 0; band_index < bands.size(); band_index++) { + + *out_band_info = BandInfo(); + for (auto& band : bands) { NL80211NestedAttr freqs_attr(0); - if (!bands[band_index].GetAttribute(NL80211_BAND_ATTR_FREQS, &freqs_attr)) { - LOG(DEBUG) << "Failed to get NL80211_BAND_ATTR_FREQS"; + if (band.GetAttribute(NL80211_BAND_ATTR_FREQS, &freqs_attr)) { + handleBandFreqAttributes(freqs_attr, out_band_info); + } + if (band.HasAttribute(NL80211_BAND_ATTR_HT_CAPA)) { + out_band_info->is_80211n_supported = true; + } + if (band.HasAttribute(NL80211_BAND_ATTR_VHT_CAPA)) { + out_band_info->is_80211ac_supported = true; + } + + NL80211NestedAttr iftype_data_attr(0); + if (band.GetAttribute(NL80211_BAND_ATTR_IFTYPE_DATA, + &iftype_data_attr)) { + ParseIfTypeDataAttributes(iftype_data_attr, out_band_info); + } + ParseHtVhtPhyCapabilities(band, out_band_info); + } + + return true; +} + +void NetlinkUtils::ParseIfTypeDataAttributes( + const NL80211NestedAttr& iftype_data_attr, + BandInfo* out_band_info) { + vector<NL80211NestedAttr> attrs; + if (!iftype_data_attr.GetListOfNestedAttributes(&attrs) || attrs.empty()) { + LOG(ERROR) << "Failed to get the list of attributes under iftype_data_attr"; + return; + } + NL80211NestedAttr attr = attrs[0]; + if (attr.HasAttribute(NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY)) { + out_band_info->is_80211ax_supported = true; + ParseHeCapPhyAttribute(attr, out_band_info); + } + if (attr.HasAttribute(NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET)) { + ParseHeMcsSetAttribute(attr, out_band_info); + } + return; +} + +void NetlinkUtils::handleBandFreqAttributes(const NL80211NestedAttr& freqs_attr, + BandInfo* out_band_info) { + vector<NL80211NestedAttr> freqs; + if (!freqs_attr.GetListOfNestedAttributes(&freqs)) { + LOG(ERROR) << "Failed to get frequency attributes"; + return; + } + + for (auto& freq : freqs) { + uint32_t frequency_value; + if (!freq.GetAttributeValue(NL80211_FREQUENCY_ATTR_FREQ, + &frequency_value)) { + LOG(DEBUG) << "Failed to get NL80211_FREQUENCY_ATTR_FREQ"; continue; } - vector<NL80211NestedAttr> freqs; - if (!freqs_attr.GetListOfNestedAttributes(&freqs)) { - LOG(ERROR) << "Failed to get frequencies within NL80211_BAND_ATTR_FREQS"; + // Channel is disabled in current regulatory domain. + if (freq.HasAttribute(NL80211_FREQUENCY_ATTR_DISABLED)) { continue; } - for (auto& freq : freqs) { - uint32_t frequency_value; - if (!freq.GetAttributeValue(NL80211_FREQUENCY_ATTR_FREQ, - &frequency_value)) { - LOG(DEBUG) << "Failed to get NL80211_FREQUENCY_ATTR_FREQ"; + + if (frequency_value > k2GHzFrequencyLowerBound && + frequency_value < k2GHzFrequencyUpperBound) { + out_band_info->band_2g.push_back(frequency_value); + } else if (frequency_value > k5GHzFrequencyLowerBound && + frequency_value <= k5GHzFrequencyUpperBound) { + // If this is an available/usable DFS frequency, we should save it to + // DFS frequencies list. + uint32_t dfs_state; + if (freq.GetAttributeValue(NL80211_FREQUENCY_ATTR_DFS_STATE, + &dfs_state) && + (dfs_state == NL80211_DFS_AVAILABLE || + dfs_state == NL80211_DFS_USABLE)) { + out_band_info->band_dfs.push_back(frequency_value); continue; } - // Channel is disabled in current regulatory domain. - if (freq.HasAttribute(NL80211_FREQUENCY_ATTR_DISABLED)) { + + // Put non-dfs passive-only channels into the dfs category. + // This aligns with what framework always assumes. + if (freq.HasAttribute(NL80211_FREQUENCY_ATTR_NO_IR)) { + out_band_info->band_dfs.push_back(frequency_value); continue; } - if (frequency_value > k2GHzFrequencyLowerBound && - frequency_value < k2GHzFrequencyUpperBound) { - frequencies_2g.push_back(frequency_value); - } else if (frequency_value > k5GHzFrequencyLowerBound && - frequency_value < k5GHzFrequencyUpperBound) { - // If this is an available/usable DFS frequency, we should save it to - // DFS frequencies list. - uint32_t dfs_state; - if (freq.GetAttributeValue(NL80211_FREQUENCY_ATTR_DFS_STATE, - &dfs_state) && - (dfs_state == NL80211_DFS_AVAILABLE || - dfs_state == NL80211_DFS_USABLE)) { - frequencies_dfs.push_back(frequency_value); - continue; - } - - // Put non-dfs passive-only channels into the dfs category. - // This aligns with what framework always assumes. - if (freq.HasAttribute(NL80211_FREQUENCY_ATTR_NO_IR)) { - frequencies_dfs.push_back(frequency_value); - continue; - } - - // Otherwise, this is a regular 5g frequency. - frequencies_5g.push_back(frequency_value); - } + // Otherwise, this is a regular 5g frequency. + out_band_info->band_5g.push_back(frequency_value); + } else if (frequency_value > k6GHzFrequencyLowerBound && + frequency_value < k6GHzFrequencyUpperBound) { + out_band_info->band_6g.push_back(frequency_value); } } - *out_band_info = BandInfo(frequencies_2g, frequencies_5g, frequencies_dfs); - return true; +} + +void NetlinkUtils::ParseHtVhtPhyCapabilities(const NL80211NestedAttr& band, + BandInfo* out_band_info) { + ParseHtMcsSetAttribute(band, out_band_info); + ParseVhtMcsSetAttribute(band, out_band_info); + ParseVhtCapAttribute(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& attribute, + BandInfo* out_band_info) { + vector<uint8_t> he_mcs_set; + if (!attribute.GetAttributeValue( + NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET, + &he_mcs_set)) { + LOG(ERROR) << " HE MCS set is not found "; + 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::ParseHeCapPhyAttribute(const NL80211NestedAttr& attribute, + BandInfo* out_band_info) { + + vector<uint8_t> he_cap_phy; + if (!attribute.GetAttributeValue( + NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY, + &he_cap_phy)) { + LOG(ERROR) << " HE CAP PHY is not found"; + 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, |
