Home | History | Annotate | Download | only in net
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "wificond/net/netlink_utils.h"
     18 
     19 #include <bitset>
     20 #include <map>
     21 #include <string>
     22 #include <vector>
     23 
     24 #include <linux/netlink.h>
     25 
     26 #include <android-base/logging.h>
     27 
     28 #include "wificond/net/kernel-header-latest/nl80211.h"
     29 #include "wificond/net/mlme_event_handler.h"
     30 #include "wificond/net/nl80211_packet.h"
     31 
     32 using std::make_pair;
     33 using std::make_unique;
     34 using std::map;
     35 using std::move;
     36 using std::string;
     37 using std::unique_ptr;
     38 using std::vector;
     39 
     40 namespace android {
     41 namespace wificond {
     42 
     43 namespace {
     44 
     45 uint32_t k2GHzFrequencyLowerBound = 2400;
     46 uint32_t k2GHzFrequencyUpperBound = 2500;
     47 
     48 uint32_t k5GHzFrequencyLowerBound = 5000;
     49 // This upper bound will exclude any 5.9Ghz channels which belong to 802.11p
     50 // for "vehicular communication systems".
     51 uint32_t k5GHzFrequencyUpperBound = 5850;
     52 
     53 bool IsExtFeatureFlagSet(
     54     const std::vector<uint8_t>& ext_feature_flags_bytes,
     55     enum nl80211_ext_feature_index ext_feature_flag) {
     56   static_assert(NUM_NL80211_EXT_FEATURES <= SIZE_MAX,
     57                 "Ext feature values doesn't fit in |size_t|");
     58   // TODO:This is an unsafe cast because this assumes that the values
     59   // are always unsigned!
     60   size_t ext_feature_flag_idx = static_cast<size_t>(ext_feature_flag);
     61   size_t ext_feature_flag_byte_pos = ext_feature_flag_idx / 8;
     62   size_t ext_feature_flag_bit_pos = ext_feature_flag_idx % 8;
     63   if (ext_feature_flag_byte_pos >= ext_feature_flags_bytes.size()) {
     64     return false;
     65   }
     66   uint8_t ext_feature_flag_byte =
     67       ext_feature_flags_bytes[ext_feature_flag_byte_pos];
     68   return (ext_feature_flag_byte & (1U << ext_feature_flag_bit_pos));
     69 }
     70 }  // namespace
     71 
     72 WiphyFeatures::WiphyFeatures(uint32_t feature_flags,
     73                              const std::vector<uint8_t>& ext_feature_flags_bytes)
     74     : supports_random_mac_oneshot_scan(
     75             feature_flags & NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR),
     76         supports_random_mac_sched_scan(
     77             feature_flags & NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR) {
     78   supports_low_span_oneshot_scan =
     79       IsExtFeatureFlagSet(ext_feature_flags_bytes,
     80                           NL80211_EXT_FEATURE_LOW_SPAN_SCAN);
     81   supports_low_power_oneshot_scan =
     82       IsExtFeatureFlagSet(ext_feature_flags_bytes,
     83                           NL80211_EXT_FEATURE_LOW_POWER_SCAN);
     84   supports_high_accuracy_oneshot_scan =
     85       IsExtFeatureFlagSet(ext_feature_flags_bytes,
     86                           NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN);
     87 }
     88 
     89 NetlinkUtils::NetlinkUtils(NetlinkManager* netlink_manager)
     90     : netlink_manager_(netlink_manager) {
     91   if (!netlink_manager_->IsStarted()) {
     92     netlink_manager_->Start();
     93   }
     94   uint32_t protocol_features = 0;
     95   supports_split_wiphy_dump_ = GetProtocolFeatures(&protocol_features) &&
     96       (protocol_features & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP);
     97 }
     98 
     99 NetlinkUtils::~NetlinkUtils() {}
    100 
    101 bool NetlinkUtils::GetWiphyIndex(uint32_t* out_wiphy_index) {
    102   NL80211Packet get_wiphy(
    103       netlink_manager_->GetFamilyId(),
    104       NL80211_CMD_GET_WIPHY,
    105       netlink_manager_->GetSequenceNumber(),
    106       getpid());
    107   get_wiphy.AddFlag(NLM_F_DUMP);
    108   vector<unique_ptr<const NL80211Packet>> response;
    109   if (!netlink_manager_->SendMessageAndGetResponses(get_wiphy, &response))  {
    110     LOG(ERROR) << "NL80211_CMD_GET_WIPHY dump failed";
    111     return false;
    112   }
    113   if (response.empty()) {
    114     LOG(DEBUG) << "No wiphy is found";
    115     return false;
    116   }
    117   for (auto& packet : response) {
    118     if (packet->GetMessageType() == NLMSG_ERROR) {
    119       LOG(ERROR) << "Receive ERROR message: "
    120                  << strerror(packet->GetErrorCode());
    121       return false;
    122     }
    123     if (packet->GetMessageType() != netlink_manager_->GetFamilyId()) {
    124       LOG(ERROR) << "Wrong message type for new interface message: "
    125                  << packet->GetMessageType();
    126       return false;
    127     }
    128     if (packet->GetCommand() != NL80211_CMD_NEW_WIPHY) {
    129       LOG(ERROR) << "Wrong command in response to "
    130                  << "a wiphy dump request: "
    131                  << static_cast<int>(packet->GetCommand());
    132       return false;
    133     }
    134     if (!packet->GetAttributeValue(NL80211_ATTR_WIPHY, out_wiphy_index)) {
    135       LOG(ERROR) << "Failed to get wiphy index from reply message";
    136       return false;
    137     }
    138   }
    139   return true;
    140 }
    141 
    142 bool NetlinkUtils::GetInterfaces(uint32_t wiphy_index,
    143                                  vector<InterfaceInfo>* interface_info) {
    144   NL80211Packet get_interfaces(
    145       netlink_manager_->GetFamilyId(),
    146       NL80211_CMD_GET_INTERFACE,
    147       netlink_manager_->GetSequenceNumber(),
    148       getpid());
    149 
    150   get_interfaces.AddFlag(NLM_F_DUMP);
    151   get_interfaces.AddAttribute(
    152       NL80211Attr<uint32_t>(NL80211_ATTR_WIPHY, wiphy_index));
    153   vector<unique_ptr<const NL80211Packet>> response;
    154   if (!netlink_manager_->SendMessageAndGetResponses(get_interfaces, &response)) {
    155     LOG(ERROR) << "NL80211_CMD_GET_INTERFACE dump failed";
    156     return false;
    157   }
    158   if (response.empty()) {
    159     LOG(ERROR) << "No interface is found";
    160     return false;
    161   }
    162   for (auto& packet : response) {
    163     if (packet->GetMessageType() == NLMSG_ERROR) {
    164       LOG(ERROR) << "Receive ERROR message: "
    165                  << strerror(packet->GetErrorCode());
    166       return false;
    167     }
    168     if (packet->GetMessageType() != netlink_manager_->GetFamilyId()) {
    169       LOG(ERROR) << "Wrong message type for new interface message: "
    170                  << packet->GetMessageType();
    171       return false;
    172     }
    173     if (packet->GetCommand() != NL80211_CMD_NEW_INTERFACE) {
    174       LOG(ERROR) << "Wrong command in response to "
    175                  << "an interface dump request: "
    176                  << static_cast<int>(packet->GetCommand());
    177       return false;
    178     }
    179 
    180     // In some situations, it has been observed that the kernel tells us
    181     // about a pseudo interface that does not have a real netdev.  In this
    182     // case, responses will have a NL80211_ATTR_WDEV, and not the expected
    183     // IFNAME/IFINDEX. In this case we just skip these pseudo interfaces.
    184     uint32_t if_index;
    185     if (!packet->GetAttributeValue(NL80211_ATTR_IFINDEX, &if_index)) {
    186       LOG(DEBUG) << "Failed to get interface index";
    187       continue;
    188     }
    189 
    190     // Today we don't check NL80211_ATTR_IFTYPE because at this point of time
    191     // driver always reports that interface is in STATION mode. Even when we
    192     // are asking interfaces infomation on behalf of tethering, it is still so
    193     // because hostapd is supposed to set interface to AP mode later.
    194 
    195     string if_name;
    196     if (!packet->GetAttributeValue(NL80211_ATTR_IFNAME, &if_name)) {
    197       LOG(WARNING) << "Failed to get interface name";
    198       continue;
    199     }
    200 
    201     vector<uint8_t> if_mac_addr;
    202     if (!packet->GetAttributeValue(NL80211_ATTR_MAC, &if_mac_addr)) {
    203       LOG(WARNING) << "Failed to get interface mac address";
    204       continue;
    205     }
    206 
    207     interface_info->emplace_back(if_index, if_name, if_mac_addr);
    208   }
    209 
    210   return true;
    211 }
    212 
    213 bool NetlinkUtils::SetInterfaceMode(uint32_t interface_index,
    214                                     InterfaceMode mode) {
    215   uint32_t set_to_mode = NL80211_IFTYPE_UNSPECIFIED;
    216   if (mode == STATION_MODE) {
    217     set_to_mode = NL80211_IFTYPE_STATION;
    218   } else {
    219     LOG(ERROR) << "Unexpected mode for interface with index: "
    220                << interface_index;
    221     return false;
    222   }
    223   NL80211Packet set_interface_mode(
    224       netlink_manager_->GetFamilyId(),
    225       NL80211_CMD_SET_INTERFACE,
    226       netlink_manager_->GetSequenceNumber(),
    227       getpid());
    228   // Force an ACK response upon success.
    229   set_interface_mode.AddFlag(NLM_F_ACK);
    230 
    231   set_interface_mode.AddAttribute(
    232       NL80211Attr<uint32_t>(NL80211_ATTR_IFINDEX, interface_index));
    233   set_interface_mode.AddAttribute(
    234       NL80211Attr<uint32_t>(NL80211_ATTR_IFTYPE, set_to_mode));
    235 
    236   if (!netlink_manager_->SendMessageAndGetAck(set_interface_mode)) {
    237     LOG(ERROR) << "NL80211_CMD_SET_INTERFACE failed";
    238     return false;
    239   }
    240 
    241   return true;
    242 }
    243 
    244 bool NetlinkUtils::GetProtocolFeatures(uint32_t* features) {
    245   NL80211Packet get_protocol_features(
    246       netlink_manager_->GetFamilyId(),
    247       NL80211_CMD_GET_PROTOCOL_FEATURES,
    248       netlink_manager_->GetSequenceNumber(),
    249       getpid());
    250   unique_ptr<const NL80211Packet> response;
    251   if (!netlink_manager_->SendMessageAndGetSingleResponse(get_protocol_features,
    252                                                          &response)) {
    253     LOG(ERROR) << "NL80211_CMD_GET_PROTOCOL_FEATURES failed";
    254     return false;
    255   }
    256   if (!response->GetAttributeValue(NL80211_ATTR_PROTOCOL_FEATURES, features)) {
    257     LOG(ERROR) << "Failed to get NL80211_ATTR_PROTOCOL_FEATURES";
    258     return false;
    259   }
    260   return true;
    261 }
    262 
    263 bool NetlinkUtils::GetWiphyInfo(
    264     uint32_t wiphy_index,
    265     BandInfo* out_band_info,
    266     ScanCapabilities* out_scan_capabilities,
    267     WiphyFeatures* out_wiphy_features) {
    268   NL80211Packet get_wiphy(
    269       netlink_manager_->GetFamilyId(),
    270       NL80211_CMD_GET_WIPHY,
    271       netlink_manager_->GetSequenceNumber(),
    272       getpid());
    273   get_wiphy.AddAttribute(NL80211Attr<uint32_t>(NL80211_ATTR_WIPHY, wiphy_index));
    274   if (supports_split_wiphy_dump_) {
    275     get_wiphy.AddFlagAttribute(NL80211_ATTR_SPLIT_WIPHY_DUMP);
    276     get_wiphy.AddFlag(NLM_F_DUMP);
    277   }
    278   vector<unique_ptr<const NL80211Packet>> response;
    279   if (!netlink_manager_->SendMessageAndGetResponses(get_wiphy, &response))  {
    280     LOG(ERROR) << "NL80211_CMD_GET_WIPHY dump failed";
    281     return false;
    282   }
    283 
    284   vector<NL80211Packet> packet_per_wiphy;
    285   if (supports_split_wiphy_dump_) {
    286     if (!MergePacketsForSplitWiphyDump(response, &packet_per_wiphy)) {
    287       LOG(WARNING) << "Failed to merge responses from split wiphy dump";
    288     }
    289   } else {
    290     for (auto& packet : response) {
    291       packet_per_wiphy.push_back(move(*(packet.release())));
    292     }
    293   }
    294 
    295   for (const auto& packet : packet_per_wiphy) {
    296     uint32_t current_wiphy_index;
    297     if (!packet.GetAttributeValue(NL80211_ATTR_WIPHY, &current_wiphy_index) ||
    298         // Not the wihpy we requested.
    299         current_wiphy_index != wiphy_index) {
    300       continue;
    301     }
    302     if (ParseWiphyInfoFromPacket(packet, out_band_info,
    303                                  out_scan_capabilities, out_wiphy_features)) {
    304       return true;
    305     }
    306   }
    307 
    308   LOG(ERROR) << "Failed to find expected wiphy info "
    309              << "from NL80211_CMD_GET_WIPHY responses";
    310   return false;
    311 }
    312 
    313 bool NetlinkUtils::ParseWiphyInfoFromPacket(
    314     const NL80211Packet& packet,
    315     BandInfo* out_band_info,
    316     ScanCapabilities* out_scan_capabilities,
    317     WiphyFeatures* out_wiphy_features) {
    318   if (packet.GetCommand() != NL80211_CMD_NEW_WIPHY) {
    319     LOG(ERROR) << "Wrong command in response to a get wiphy request: "
    320                << static_cast<int>(packet.GetCommand());
    321     return false;
    322   }
    323   if (!ParseBandInfo(&packet, out_band_info) ||
    324       !ParseScanCapabilities(&packet, out_scan_capabilities)) {
    325     return false;
    326   }
    327   uint32_t feature_flags;
    328   if (!packet.GetAttributeValue(NL80211_ATTR_FEATURE_FLAGS,
    329                                  &feature_flags)) {
    330     LOG(ERROR) << "Failed to get NL80211_ATTR_FEATURE_FLAGS";
    331     return false;
    332   }
    333   std::vector<uint8_t> ext_feature_flags_bytes;
    334   if (!packet.GetAttributeValue(NL80211_ATTR_EXT_FEATURES,
    335                                 &ext_feature_flags_bytes)) {
    336     LOG(WARNING) << "Failed to get NL80211_ATTR_EXT_FEATURES";
    337   }
    338   *out_wiphy_features = WiphyFeatures(feature_flags,
    339                                       ext_feature_flags_bytes);
    340   return true;
    341 }
    342 
    343 bool NetlinkUtils::ParseScanCapabilities(
    344     const NL80211Packet* const packet,
    345     ScanCapabilities* out_scan_capabilities) {
    346   uint8_t max_num_scan_ssids;
    347   if (!packet->GetAttributeValue(NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
    348                                    &max_num_scan_ssids)) {
    349     LOG(ERROR) << "Failed to get the capacity of maximum number of scan ssids";
    350     return false;
    351   }
    352 
    353   uint8_t max_num_sched_scan_ssids;
    354   if (!packet->GetAttributeValue(NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
    355                                  &max_num_sched_scan_ssids)) {
    356     LOG(ERROR) << "Failed to get the capacity of "
    357                << "maximum number of scheduled scan ssids";
    358     return false;
    359   }
    360 
    361   // Use default value 0 for scan plan capabilities if attributes are missing.
    362   uint32_t max_num_scan_plans = 0;
    363   packet->GetAttributeValue(NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS,
    364                             &max_num_scan_plans);
    365   uint32_t max_scan_plan_interval = 0;
    366   packet->GetAttributeValue(NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL,
    367                             &max_scan_plan_interval);
    368   uint32_t max_scan_plan_iterations = 0;
    369   packet->GetAttributeValue(NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS,
    370                             &max_scan_plan_iterations);
    371 
    372   uint8_t max_match_sets;
    373   if (!packet->GetAttributeValue(NL80211_ATTR_MAX_MATCH_SETS,
    374                                    &max_match_sets)) {
    375     LOG(ERROR) << "Failed to get the capacity of maximum number of match set"
    376                << "of a scheduled scan";
    377     return false;
    378   }
    379   *out_scan_capabilities = ScanCapabilities(max_num_scan_ssids,
    380                                             max_num_sched_scan_ssids,
    381                                             max_match_sets,
    382                                             max_num_scan_plans,
    383                                             max_scan_plan_interval,
    384                                             max_scan_plan_iterations);
    385   return true;
    386 }
    387 
    388 bool NetlinkUtils::ParseBandInfo(const NL80211Packet* const packet,
    389                                  BandInfo* out_band_info) {
    390 
    391   NL80211NestedAttr bands_attr(0);
    392   if (!packet->GetAttribute(NL80211_ATTR_WIPHY_BANDS, &bands_attr)) {
    393     LOG(ERROR) << "Failed to get NL80211_ATTR_WIPHY_BANDS";
    394     return false;
    395   }
    396   vector<NL80211NestedAttr> bands;
    397   if (!bands_attr.GetListOfNestedAttributes(&bands)) {
    398     LOG(ERROR) << "Failed to get bands within NL80211_ATTR_WIPHY_BANDS";
    399     return false;
    400   }
    401   vector<uint32_t> frequencies_2g;
    402   vector<uint32_t> frequencies_5g;
    403   vector<uint32_t> frequencies_dfs;
    404   for (unsigned int band_index = 0; band_index < bands.size(); band_index++) {
    405     NL80211NestedAttr freqs_attr(0);
    406     if (!bands[band_index].GetAttribute(NL80211_BAND_ATTR_FREQS, &freqs_attr)) {
    407       LOG(DEBUG) << "Failed to get NL80211_BAND_ATTR_FREQS";
    408       continue;
    409     }
    410     vector<NL80211NestedAttr> freqs;
    411     if (!freqs_attr.GetListOfNestedAttributes(&freqs)) {
    412       LOG(ERROR) << "Failed to get frequencies within NL80211_BAND_ATTR_FREQS";
    413       continue;
    414     }
    415     for (auto& freq : freqs) {
    416       uint32_t frequency_value;
    417       if (!freq.GetAttributeValue(NL80211_FREQUENCY_ATTR_FREQ,
    418                                   &frequency_value)) {
    419         LOG(DEBUG) << "Failed to get NL80211_FREQUENCY_ATTR_FREQ";
    420         continue;
    421       }
    422       // Channel is disabled in current regulatory domain.
    423       if (freq.HasAttribute(NL80211_FREQUENCY_ATTR_DISABLED)) {
    424         continue;
    425       }
    426       if (frequency_value > k2GHzFrequencyLowerBound &&
    427             frequency_value < k2GHzFrequencyUpperBound) {
    428           frequencies_2g.push_back(frequency_value);
    429       } else if (frequency_value > k5GHzFrequencyLowerBound &&
    430             frequency_value < k5GHzFrequencyUpperBound) {
    431         // If this is an available/usable DFS frequency, we should save it to
    432         // DFS frequencies list.
    433         uint32_t dfs_state;
    434         if (freq.GetAttributeValue(NL80211_FREQUENCY_ATTR_DFS_STATE,
    435                                    &dfs_state) &&
    436             (dfs_state == NL80211_DFS_AVAILABLE ||
    437                  dfs_state == NL80211_DFS_USABLE)) {
    438           frequencies_dfs.push_back(frequency_value);
    439           continue;
    440         }
    441 
    442         // Put non-dfs passive-only channels into the dfs category.
    443         // This aligns with what framework always assumes.
    444         if (freq.HasAttribute(NL80211_FREQUENCY_ATTR_NO_IR)) {
    445           frequencies_dfs.push_back(frequency_value);
    446           continue;
    447         }
    448 
    449         // Otherwise, this is a regular 5g frequency.
    450         frequencies_5g.push_back(frequency_value);
    451       }
    452 
    453     }
    454   }
    455   *out_band_info = BandInfo(frequencies_2g, frequencies_5g, frequencies_dfs);
    456   return true;
    457 }
    458 
    459 bool NetlinkUtils::GetStationInfo(uint32_t interface_index,
    460                                   const vector<uint8_t>& mac_address,
    461                                   StationInfo* out_station_info) {
    462   NL80211Packet get_station(
    463       netlink_manager_->GetFamilyId(),
    464       NL80211_CMD_GET_STATION,
    465       netlink_manager_->GetSequenceNumber(),
    466       getpid());
    467   get_station.AddAttribute(NL80211Attr<uint32_t>(NL80211_ATTR_IFINDEX,
    468                                                  interface_index));
    469   get_station.AddAttribute(NL80211Attr<vector<uint8_t>>(NL80211_ATTR_MAC,
    470                                                         mac_address));
    471 
    472   unique_ptr<const NL80211Packet> response;
    473   if (!netlink_manager_->SendMessageAndGetSingleResponse(get_station,
    474                                                          &response)) {
    475     LOG(ERROR) << "NL80211_CMD_GET_STATION failed";
    476     return false;
    477   }
    478   if (response->GetCommand() != NL80211_CMD_NEW_STATION) {
    479     LOG(ERROR) << "Wrong command in response to a get station request: "
    480                << static_cast<int>(response->GetCommand());
    481     return false;
    482   }
    483   NL80211NestedAttr sta_info(0);
    484   if (!response->GetAttribute(NL80211_ATTR_STA_INFO, &sta_info)) {
    485     LOG(ERROR) << "Failed to get NL80211_ATTR_STA_INFO";
    486     return false;
    487   }
    488   int32_t tx_good, tx_bad;
    489   if (!sta_info.GetAttributeValue(NL80211_STA_INFO_TX_PACKETS, &tx_good)) {
    490     LOG(ERROR) << "Failed to get NL80211_STA_INFO_TX_PACKETS";
    491     return false;
    492   }
    493   if (!sta_info.GetAttributeValue(NL80211_STA_INFO_TX_FAILED, &tx_bad)) {
    494     LOG(ERROR) << "Failed to get NL80211_STA_INFO_TX_FAILED";
    495     return false;
    496   }
    497   int8_t current_rssi;
    498   if (!sta_info.GetAttributeValue(NL80211_STA_INFO_SIGNAL, &current_rssi)) {
    499     LOG(ERROR) << "Failed to get NL80211_STA_INFO_SIGNAL";
    500     return false;
    501   }
    502   NL80211NestedAttr tx_bitrate_attr(0);
    503   if (!sta_info.GetAttribute(NL80211_STA_INFO_TX_BITRATE,
    504                             &tx_bitrate_attr)) {
    505     LOG(ERROR) << "Failed to get NL80211_STA_INFO_TX_BITRATE";
    506     return false;
    507   }
    508   uint32_t tx_bitrate;
    509   if (!tx_bitrate_attr.GetAttributeValue(NL80211_RATE_INFO_BITRATE32,
    510                                          &tx_bitrate)) {
    511     LOG(ERROR) << "Failed to get NL80211_RATE_INFO_BITRATE32";
    512     return false;
    513   }
    514 
    515   *out_station_info = StationInfo(tx_good, tx_bad, tx_bitrate, current_rssi);
    516   return true;
    517 }
    518 
    519 // This is a helper function for merging split NL80211_CMD_NEW_WIPHY packets.
    520 // For example:
    521 // First NL80211_CMD_NEW_WIPHY has attribute A with payload 0x1234.
    522 // Second NL80211_CMD_NEW_WIPHY has attribute A with payload 0x5678.
    523 // The generated NL80211_CMD_NEW_WIPHY will have attribute A with
    524 // payload 0x12345678.
    525 // NL80211_ATTR_WIPHY, NL80211_ATTR_IFINDEX, and NL80211_ATTR_WDEV
    526 // are used for filtering packets so we know which packets should
    527 // be merged together.
    528 bool NetlinkUtils::MergePacketsForSplitWiphyDump(
    529     const vector<unique_ptr<const NL80211Packet>>& split_dump_info,
    530     vector<NL80211Packet>* packet_per_wiphy) {
    531   map<uint32_t, map<int, BaseNL80211Attr>> attr_by_wiphy_and_id;
    532 
    533   // Construct the map using input packets.
    534   for (const auto& packet : split_dump_info) {
    535     uint32_t wiphy_index;
    536     if (!packet->GetAttributeValue(NL80211_ATTR_WIPHY, &wiphy_index)) {
    537       LOG(ERROR) << "Failed to get NL80211_ATTR_WIPHY from wiphy split dump";
    538       return false;
    539     }
    540     vector<BaseNL80211Attr> attributes;
    541     if (!packet->GetAllAttributes(&attributes)) {
    542       return false;
    543     }
    544     for (auto& attr : attributes) {
    545       int attr_id = attr.GetAttributeId();
    546       if (attr_id != NL80211_ATTR_WIPHY &&
    547           attr_id != NL80211_ATTR_IFINDEX &&
    548               attr_id != NL80211_ATTR_WDEV) {
    549           auto attr_id_and_attr =
    550               attr_by_wiphy_and_id[wiphy_index].find(attr_id);
    551           if (attr_id_and_attr == attr_by_wiphy_and_id[wiphy_index].end()) {
    552             attr_by_wiphy_and_id[wiphy_index].
    553                 insert(make_pair(attr_id, move(attr)));
    554           } else {
    555             attr_id_and_attr->second.Merge(attr);
    556           }
    557       }
    558     }
    559   }
    560 
    561   // Generate output packets using the constructed map.
    562   for (const auto& wiphy_and_attributes : attr_by_wiphy_and_id) {
    563     NL80211Packet new_wiphy(0, NL80211_CMD_NEW_WIPHY, 0, 0);
    564     new_wiphy.AddAttribute(
    565         NL80211Attr<uint32_t>(NL80211_ATTR_WIPHY, wiphy_and_attributes.first));
    566     for (const auto& attr : wiphy_and_attributes.second) {
    567       new_wiphy.AddAttribute(attr.second);
    568     }
    569     packet_per_wiphy->emplace_back(move(new_wiphy));
    570   }
    571   return true;
    572 }
    573 
    574 bool NetlinkUtils::GetCountryCode(string* out_country_code) {
    575   NL80211Packet get_country_code(
    576       netlink_manager_->GetFamilyId(),
    577       NL80211_CMD_GET_REG,
    578       netlink_manager_->GetSequenceNumber(),
    579       getpid());
    580   unique_ptr<const NL80211Packet> response;
    581   if (!netlink_manager_->SendMessageAndGetSingleResponse(get_country_code,
    582                                                          &response)) {
    583     LOG(ERROR) << "NL80211_CMD_GET_REG failed";
    584     return false;
    585   }
    586   if (!response->GetAttributeValue(NL80211_ATTR_REG_ALPHA2, out_country_code)) {
    587     LOG(ERROR) << "Get NL80211_ATTR_REG_ALPHA2 failed";
    588     return false;
    589   }
    590   return true;
    591 }
    592 
    593 void NetlinkUtils::SubscribeMlmeEvent(uint32_t interface_index,
    594                                       MlmeEventHandler* handler) {
    595   netlink_manager_->SubscribeMlmeEvent(interface_index, handler);
    596 }
    597 
    598 void NetlinkUtils::UnsubscribeMlmeEvent(uint32_t interface_index) {
    599   netlink_manager_->UnsubscribeMlmeEvent(interface_index);
    600 }
    601 
    602 void NetlinkUtils::SubscribeRegDomainChange(
    603     uint32_t wiphy_index,
    604     OnRegDomainChangedHandler handler) {
    605   netlink_manager_->SubscribeRegDomainChange(wiphy_index, handler);
    606 }
    607 
    608 void NetlinkUtils::UnsubscribeRegDomainChange(uint32_t wiphy_index) {
    609   netlink_manager_->UnsubscribeRegDomainChange(wiphy_index);
    610 }
    611 
    612 void NetlinkUtils::SubscribeStationEvent(uint32_t interface_index,
    613                                          OnStationEventHandler handler) {
    614   netlink_manager_->SubscribeStationEvent(interface_index, handler);
    615 }
    616 
    617 void NetlinkUtils::UnsubscribeStationEvent(uint32_t interface_index) {
    618   netlink_manager_->UnsubscribeStationEvent(interface_index);
    619 }
    620 
    621 void NetlinkUtils::SubscribeChannelSwitchEvent(uint32_t interface_index,
    622                                          OnChannelSwitchEventHandler handler) {
    623   netlink_manager_->SubscribeChannelSwitchEvent(interface_index, handler);
    624 }
    625 
    626 void NetlinkUtils::UnsubscribeChannelSwitchEvent(uint32_t interface_index) {
    627   netlink_manager_->UnsubscribeChannelSwitchEvent(interface_index);
    628 }
    629 
    630 
    631 }  // namespace wificond
    632 }  // namespace android
    633