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, ¤t_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, ¤t_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