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 "android/net/wifi/IWifiScannerImpl.h" 18 #include "wificond/scanning/scan_utils.h" 19 20 #include <vector> 21 22 #include <linux/netlink.h> 23 24 #include <android-base/logging.h> 25 26 #include "wificond/net/kernel-header-latest/nl80211.h" 27 #include "wificond/net/netlink_manager.h" 28 #include "wificond/net/nl80211_packet.h" 29 #include "wificond/scanning/scan_result.h" 30 31 using android::net::wifi::IWifiScannerImpl; 32 using com::android::server::wifi::wificond::NativeScanResult; 33 using com::android::server::wifi::wificond::RadioChainInfo; 34 using std::unique_ptr; 35 using std::vector; 36 37 namespace android { 38 namespace wificond { 39 namespace { 40 41 constexpr uint8_t kElemIdSsid = 0; 42 constexpr unsigned int kMsecPerSec = 1000; 43 44 } // namespace 45 46 ScanUtils::ScanUtils(NetlinkManager* netlink_manager) 47 : netlink_manager_(netlink_manager) { 48 if (!netlink_manager_->IsStarted()) { 49 netlink_manager_->Start(); 50 } 51 } 52 53 ScanUtils::~ScanUtils() {} 54 55 void ScanUtils::SubscribeScanResultNotification( 56 uint32_t interface_index, 57 OnScanResultsReadyHandler handler) { 58 netlink_manager_->SubscribeScanResultNotification(interface_index, handler); 59 } 60 61 void ScanUtils::UnsubscribeScanResultNotification(uint32_t interface_index) { 62 netlink_manager_->UnsubscribeScanResultNotification(interface_index); 63 } 64 65 void ScanUtils::SubscribeSchedScanResultNotification( 66 uint32_t interface_index, 67 OnSchedScanResultsReadyHandler handler) { 68 netlink_manager_->SubscribeSchedScanResultNotification(interface_index, 69 handler); 70 } 71 72 void ScanUtils::UnsubscribeSchedScanResultNotification( 73 uint32_t interface_index) { 74 netlink_manager_->UnsubscribeSchedScanResultNotification(interface_index); 75 } 76 77 bool ScanUtils::GetScanResult(uint32_t interface_index, 78 vector<NativeScanResult>* out_scan_results) { 79 NL80211Packet get_scan( 80 netlink_manager_->GetFamilyId(), 81 NL80211_CMD_GET_SCAN, 82 netlink_manager_->GetSequenceNumber(), 83 getpid()); 84 get_scan.AddFlag(NLM_F_DUMP); 85 NL80211Attr<uint32_t> ifindex(NL80211_ATTR_IFINDEX, interface_index); 86 get_scan.AddAttribute(ifindex); 87 88 vector<unique_ptr<const NL80211Packet>> response; 89 if (!netlink_manager_->SendMessageAndGetResponses(get_scan, &response)) { 90 LOG(ERROR) << "NL80211_CMD_GET_SCAN dump failed"; 91 return false; 92 } 93 if (response.empty()) { 94 LOG(INFO) << "Unexpected empty scan result!"; 95 return true; 96 } 97 98 for (auto& packet : response) { 99 if (packet->GetMessageType() == NLMSG_ERROR) { 100 LOG(ERROR) << "Receive ERROR message: " 101 << strerror(packet->GetErrorCode()); 102 continue; 103 } 104 if (packet->GetMessageType() != netlink_manager_->GetFamilyId()) { 105 LOG(ERROR) << "Wrong message type: " 106 << packet->GetMessageType(); 107 continue; 108 } 109 uint32_t if_index; 110 if (!packet->GetAttributeValue(NL80211_ATTR_IFINDEX, &if_index)) { 111 LOG(ERROR) << "No interface index in scan result."; 112 continue; 113 } 114 if (if_index != interface_index) { 115 LOG(WARNING) << "Uninteresting scan result for interface: " << if_index; 116 continue; 117 } 118 119 NativeScanResult scan_result; 120 if (!ParseScanResult(std::move(packet), &scan_result)) { 121 LOG(DEBUG) << "Ignore invalid scan result"; 122 continue; 123 } 124 out_scan_results->push_back(std::move(scan_result)); 125 } 126 return true; 127 } 128 129 bool ScanUtils::ParseScanResult(unique_ptr<const NL80211Packet> packet, 130 NativeScanResult* scan_result) { 131 if (packet->GetCommand() != NL80211_CMD_NEW_SCAN_RESULTS) { 132 LOG(ERROR) << "Wrong command command for new scan result message"; 133 return false; 134 } 135 NL80211NestedAttr bss(0); 136 if (packet->GetAttribute(NL80211_ATTR_BSS, &bss)) { 137 vector<uint8_t> bssid; 138 if (!bss.GetAttributeValue(NL80211_BSS_BSSID, &bssid)) { 139 LOG(ERROR) << "Failed to get BSSID from scan result packet"; 140 return false; 141 } 142 uint32_t freq; 143 if (!bss.GetAttributeValue(NL80211_BSS_FREQUENCY, &freq)) { 144 LOG(ERROR) << "Failed to get Frequency from scan result packet"; 145 return false; 146 } 147 vector<uint8_t> ie; 148 if (!bss.GetAttributeValue(NL80211_BSS_INFORMATION_ELEMENTS, &ie)) { 149 LOG(ERROR) << "Failed to get Information Element from scan result packet"; 150 return false; 151 } 152 vector<uint8_t> ssid; 153 if (!GetSSIDFromInfoElement(ie, &ssid)) { 154 // Skip BSS without SSID IE. 155 // These scan results are considered as malformed. 156 return false; 157 } 158 uint64_t last_seen_since_boot_microseconds; 159 if (!GetBssTimestamp(bss, &last_seen_since_boot_microseconds)) { 160 // Logging is done inside |GetBssTimestamp|. 161 return false; 162 } 163 int32_t signal; 164 if (!bss.GetAttributeValue(NL80211_BSS_SIGNAL_MBM, &signal)) { 165 LOG(ERROR) << "Failed to get Signal Strength from scan result packet"; 166 return false; 167 } 168 uint16_t capability; 169 if (!bss.GetAttributeValue(NL80211_BSS_CAPABILITY, &capability)) { 170 LOG(ERROR) << "Failed to get capability field from scan result packet"; 171 return false; 172 } 173 bool associated = false; 174 uint32_t bss_status; 175 if (bss.GetAttributeValue(NL80211_BSS_STATUS, &bss_status) && 176 (bss_status == NL80211_BSS_STATUS_AUTHENTICATED || 177 bss_status == NL80211_BSS_STATUS_ASSOCIATED)) { 178 associated = true; 179 } 180 std::vector<RadioChainInfo> radio_chain_infos; 181 ParseRadioChainInfos(bss, &radio_chain_infos); 182 183 *scan_result = 184 NativeScanResult(ssid, bssid, ie, freq, signal, 185 last_seen_since_boot_microseconds, 186 capability, associated, radio_chain_infos); 187 } 188 return true; 189 } 190 191 bool ScanUtils::GetBssTimestampForTesting( 192 const NL80211NestedAttr& bss, 193 uint64_t* last_seen_since_boot_microseconds){ 194 return GetBssTimestamp(bss, last_seen_since_boot_microseconds); 195 } 196 197 bool ScanUtils::GetBssTimestamp(const NL80211NestedAttr& bss, 198 uint64_t* last_seen_since_boot_microseconds){ 199 uint64_t last_seen_since_boot_nanoseconds; 200 if (bss.GetAttributeValue(NL80211_BSS_LAST_SEEN_BOOTTIME, 201 &last_seen_since_boot_nanoseconds)) { 202 *last_seen_since_boot_microseconds = last_seen_since_boot_nanoseconds / 1000; 203 } else { 204 // Fall back to use TSF if we can't find NL80211_BSS_LAST_SEEN_BOOTTIME 205 // attribute. 206 if (!bss.GetAttributeValue(NL80211_BSS_TSF, last_seen_since_boot_microseconds)) { 207 LOG(ERROR) << "Failed to get TSF from scan result packet"; 208 return false; 209 } 210 uint64_t beacon_tsf_microseconds; 211 if (bss.GetAttributeValue(NL80211_BSS_BEACON_TSF, &beacon_tsf_microseconds)) { 212 *last_seen_since_boot_microseconds = std::max(*last_seen_since_boot_microseconds, 213 beacon_tsf_microseconds); 214 } 215 } 216 return true; 217 } 218 219 bool ScanUtils::ParseRadioChainInfos( 220 const NL80211NestedAttr& bss, 221 std::vector<RadioChainInfo> *radio_chain_infos) { 222 *radio_chain_infos = {}; 223 // Contains a nested array of signal strength attributes: (ChainId, Rssi in dBm) 224 NL80211NestedAttr radio_chain_infos_attr(0); 225 if (!bss.GetAttribute(NL80211_BSS_CHAIN_SIGNAL, &radio_chain_infos_attr)) { 226 return false; 227 } 228 std::vector<NL80211Attr<int8_t>> radio_chain_infos_attrs; 229 if (!radio_chain_infos_attr.GetListOfAttributes( 230 &radio_chain_infos_attrs)) { 231 LOG(ERROR) << "Failed to get radio chain info attrs within " 232 << "NL80211_BSS_CHAIN_SIGNAL"; 233 return false; 234 } 235 for (const auto& attr : radio_chain_infos_attrs) { 236 RadioChainInfo radio_chain_info; 237 radio_chain_info.chain_id = attr.GetAttributeId(); 238 radio_chain_info.level = attr.GetValue(); 239 radio_chain_infos->push_back(radio_chain_info); 240 } 241 return true; 242 } 243 244 bool ScanUtils::GetSSIDFromInfoElement(const vector<uint8_t>& ie, 245 vector<uint8_t>* ssid) { 246 // Information elements are stored in 'TLV' format. 247 // Field: | Type | Length | Value | 248 // Length: | 1 | 1 | variable | 249 // Content:| Element ID | Length of the Value field | Element payload | 250 const uint8_t* end = ie.data() + ie.size(); 251 const uint8_t* ptr = ie.data(); 252 // +1 means we must have space for the length field. 253 while (ptr + 1 < end) { 254 uint8_t type = *ptr; 255 uint8_t length = *(ptr + 1); 256 // Length field is invalid. 257 if (ptr + 1 + length >= end) { 258 return false; 259 } 260 // SSID element is found. 261 if (type == kElemIdSsid) { 262 // SSID is an empty string. 263 if (length == 0) { 264 *ssid = vector<uint8_t>(); 265 } else { 266 *ssid = vector<uint8_t>(ptr + 2, ptr + length + 2); 267 } 268 return true; 269 } 270 ptr += 2 + length; 271 } 272 return false; 273 } 274 275 bool ScanUtils::Scan(uint32_t interface_index, 276 bool request_random_mac, 277 int scan_type, 278 const vector<vector<uint8_t>>& ssids, 279 const vector<uint32_t>& freqs, 280 int* error_code) { 281 NL80211Packet trigger_scan( 282 netlink_manager_->GetFamilyId(), 283 NL80211_CMD_TRIGGER_SCAN, 284 netlink_manager_->GetSequenceNumber(), 285 getpid()); 286 // If we do not use NLM_F_ACK, we only receive a unicast repsonse 287 // when there is an error. If everything is good, scan results notification 288 // will only be sent through multicast. 289 // If NLM_F_ACK is set, there will always be an unicast repsonse, either an 290 // ERROR or an ACK message. The handler will always be called and removed by 291 // NetlinkManager. 292 trigger_scan.AddFlag(NLM_F_ACK); 293 NL80211Attr<uint32_t> if_index_attr(NL80211_ATTR_IFINDEX, interface_index); 294 295 NL80211NestedAttr ssids_attr(NL80211_ATTR_SCAN_SSIDS); 296 for (size_t i = 0; i < ssids.size(); i++) { 297 ssids_attr.AddAttribute(NL80211Attr<vector<uint8_t>>(i, ssids[i])); 298 } 299 NL80211NestedAttr freqs_attr(NL80211_ATTR_SCAN_FREQUENCIES); 300 for (size_t i = 0; i < freqs.size(); i++) { 301 freqs_attr.AddAttribute(NL80211Attr<uint32_t>(i, freqs[i])); 302 } 303 304 trigger_scan.AddAttribute(if_index_attr); 305 trigger_scan.AddAttribute(ssids_attr); 306 // An absence of NL80211_ATTR_SCAN_FREQUENCIES attribue informs kernel to 307 // scan all supported frequencies. 308 if (!freqs.empty()) { 309 trigger_scan.AddAttribute(freqs_attr); 310 } 311 312 uint32_t scan_flags = 0; 313 if (request_random_mac) { 314 scan_flags |= NL80211_SCAN_FLAG_RANDOM_ADDR; 315 } 316 switch (scan_type) { 317 case IWifiScannerImpl::SCAN_TYPE_LOW_SPAN: 318 scan_flags |= NL80211_SCAN_FLAG_LOW_SPAN; 319 break; 320 case IWifiScannerImpl::SCAN_TYPE_LOW_POWER: 321 scan_flags |= NL80211_SCAN_FLAG_LOW_POWER; 322 break; 323 case IWifiScannerImpl::SCAN_TYPE_HIGH_ACCURACY: 324 scan_flags |= NL80211_SCAN_FLAG_HIGH_ACCURACY; 325 break; 326 case IWifiScannerImpl::SCAN_TYPE_DEFAULT: 327 break; 328 default: 329 CHECK(0) << "Invalid scan type received: " << scan_type; 330 } 331 if (scan_flags) { 332 trigger_scan.AddAttribute( 333 NL80211Attr<uint32_t>(NL80211_ATTR_SCAN_FLAGS, 334 scan_flags)); 335 } 336 // We are receiving an ERROR/ACK message instead of the actual 337 // scan results here, so it is OK to expect a timely response because 338 // kernel is supposed to send the ERROR/ACK back before the scan starts. 339 vector<unique_ptr<const NL80211Packet>> response; 340 if (!netlink_manager_->SendMessageAndGetAckOrError(trigger_scan, 341 error_code)) { 342 // Logging is done inside |SendMessageAndGetAckOrError|. 343 return false; 344 } 345 if (*error_code != 0) { 346 LOG(ERROR) << "NL80211_CMD_TRIGGER_SCAN failed: " << strerror(*error_code); 347 return false; 348 } 349 return true; 350 } 351 352 bool ScanUtils::StopScheduledScan(uint32_t interface_index) { 353 NL80211Packet stop_sched_scan( 354 netlink_manager_->GetFamilyId(), 355 NL80211_CMD_STOP_SCHED_SCAN, 356 netlink_manager_->GetSequenceNumber(), 357 getpid()); 358 // Force an ACK response upon success. 359 stop_sched_scan.AddFlag(NLM_F_ACK); 360 stop_sched_scan.AddAttribute( 361 NL80211Attr<uint32_t>(NL80211_ATTR_IFINDEX, interface_index)); 362 vector<unique_ptr<const NL80211Packet>> response; 363 int error_code; 364 if (!netlink_manager_->SendMessageAndGetAckOrError(stop_sched_scan, 365 &error_code)) { 366 LOG(ERROR) << "NL80211_CMD_STOP_SCHED_SCAN failed"; 367 return false; 368 } 369 if (error_code == ENOENT) { 370 LOG(WARNING) << "Scheduled scan is not running!"; 371 return false; 372 } else if (error_code != 0) { 373 LOG(ERROR) << "Receive ERROR message in response to" 374 << " 'stop scheduled scan' request: " 375 << strerror(error_code); 376 return false; 377 } 378 return true; 379 } 380 381 bool ScanUtils::AbortScan(uint32_t interface_index) { 382 NL80211Packet abort_scan( 383 netlink_manager_->GetFamilyId(), 384 NL80211_CMD_ABORT_SCAN, 385 netlink_manager_->GetSequenceNumber(), 386 getpid()); 387 388 // Force an ACK response upon success. 389 abort_scan.AddFlag(NLM_F_ACK); 390 abort_scan.AddAttribute( 391 NL80211Attr<uint32_t>(NL80211_ATTR_IFINDEX, interface_index)); 392 393 if (!netlink_manager_->SendMessageAndGetAck(abort_scan)) { 394 LOG(ERROR) << "NL80211_CMD_ABORT_SCAN failed"; 395 return false; 396 } 397 return true; 398 } 399 400 bool ScanUtils::StartScheduledScan( 401 uint32_t interface_index, 402 const SchedScanIntervalSetting& interval_setting, 403 int32_t rssi_threshold_2g, 404 int32_t rssi_threshold_5g, 405 bool request_random_mac, 406 bool request_low_power, 407 const std::vector<std::vector<uint8_t>>& scan_ssids, 408 const std::vector<std::vector<uint8_t>>& match_ssids, 409 const std::vector<uint32_t>& freqs, 410 int* error_code) { 411 NL80211Packet start_sched_scan( 412 netlink_manager_->GetFamilyId(), 413 NL80211_CMD_START_SCHED_SCAN, 414 netlink_manager_->GetSequenceNumber(), 415 getpid()); 416 // Force an ACK response upon success. 417 start_sched_scan.AddFlag(NLM_F_ACK); 418 419 NL80211NestedAttr scan_ssids_attr(NL80211_ATTR_SCAN_SSIDS); 420 for (size_t i = 0; i < scan_ssids.size(); i++) { 421 scan_ssids_attr.AddAttribute(NL80211Attr<vector<uint8_t>>(i, scan_ssids[i])); 422 } 423 NL80211NestedAttr freqs_attr(NL80211_ATTR_SCAN_FREQUENCIES); 424 for (size_t i = 0; i < freqs.size(); i++) { 425 freqs_attr.AddAttribute(NL80211Attr<uint32_t>(i, freqs[i])); 426 } 427 428 // Structure of attributes of scheduled scan filters: 429 // | Nested Attribute: id: NL80211_ATTR_SCHED_SCAN_MATCH | 430 // | Nested Attributed: id: 0 | Nested Attributed: id: 1 | Nested Attr: id: 2 | ... | 431 // | MATCH_SSID | MATCH_RSSI(optional) | MATCH_SSID | MACTCH_RSSI(optional) | MATCH_RSSI(optinal, global) | ... | 432 NL80211NestedAttr scan_match_attr(NL80211_ATTR_SCHED_SCAN_MATCH); 433 for (size_t i = 0; i < match_ssids.size(); i++) { 434 NL80211NestedAttr match_group(i); 435 match_group.AddAttribute( 436 NL80211Attr<vector<uint8_t>>(NL80211_SCHED_SCAN_MATCH_ATTR_SSID, match_ssids[i])); 437 match_group.AddAttribute( 438 NL80211Attr<int32_t>(NL80211_SCHED_SCAN_MATCH_ATTR_RSSI, rssi_threshold_5g)); 439 scan_match_attr.AddAttribute(match_group); 440 } 441 start_sched_scan.AddAttribute(scan_match_attr); 442 443 // We set 5g threshold for default and ajust threshold for 2g band. 444 struct nl80211_bss_select_rssi_adjust rssi_adjust; 445 rssi_adjust.band = NL80211_BAND_2GHZ; 446 rssi_adjust.delta = static_cast<int8_t>(rssi_threshold_2g - rssi_threshold_5g); 447 NL80211Attr<vector<uint8_t>> rssi_adjust_attr( 448 NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST, 449 vector<uint8_t>( 450 reinterpret_cast<uint8_t*>(&rssi_adjust), 451 reinterpret_cast<uint8_t*>(&rssi_adjust) + sizeof(rssi_adjust))); 452 start_sched_scan.AddAttribute(rssi_adjust_attr); 453 454 // Append all attributes to the NL80211_CMD_START_SCHED_SCAN packet. 455 start_sched_scan.AddAttribute( 456 NL80211Attr<uint32_t>(NL80211_ATTR_IFINDEX, interface_index)); 457 start_sched_scan.AddAttribute(scan_ssids_attr); 458 // An absence of NL80211_ATTR_SCAN_FREQUENCIES attribue informs kernel to 459 // scan all supported frequencies. 460 if (!freqs.empty()) { 461 start_sched_scan.AddAttribute(freqs_attr); 462 } 463 464 if (!interval_setting.plans.empty()) { 465 NL80211NestedAttr scan_plans(NL80211_ATTR_SCHED_SCAN_PLANS); 466 for (unsigned int i = 0; i < interval_setting.plans.size(); i++) { 467 NL80211NestedAttr scan_plan(i + 1); 468 scan_plan.AddAttribute( 469 NL80211Attr<uint32_t>(NL80211_SCHED_SCAN_PLAN_INTERVAL, 470 interval_setting.plans[i].interval_ms / kMsecPerSec)); 471 scan_plan.AddAttribute( 472 NL80211Attr<uint32_t>(NL80211_SCHED_SCAN_PLAN_ITERATIONS, 473 interval_setting.plans[i].n_iterations)); 474 scan_plans.AddAttribute(scan_plan); 475 } 476 NL80211NestedAttr last_scan_plan(interval_setting.plans.size() + 1); 477 last_scan_plan.AddAttribute( 478 NL80211Attr<uint32_t>(NL80211_SCHED_SCAN_PLAN_INTERVAL, 479 interval_setting.final_interval_ms / kMsecPerSec)); 480 scan_plans.AddAttribute(last_scan_plan); 481 start_sched_scan.AddAttribute(scan_plans); 482 } else { 483 start_sched_scan.AddAttribute( 484 NL80211Attr<uint32_t>(NL80211_ATTR_SCHED_SCAN_INTERVAL, 485 interval_setting.final_interval_ms)); 486 } 487 uint32_t scan_flags = 0; 488 if (request_random_mac) { 489 scan_flags |= NL80211_SCAN_FLAG_RANDOM_ADDR; 490 } 491 if (request_low_power) { 492 scan_flags |= NL80211_SCAN_FLAG_LOW_POWER; 493 } 494 if (scan_flags) { 495 start_sched_scan.AddAttribute( 496 NL80211Attr<uint32_t>(NL80211_ATTR_SCAN_FLAGS, 497 scan_flags)); 498 } 499 500 vector<unique_ptr<const NL80211Packet>> response; 501 if (!netlink_manager_->SendMessageAndGetAckOrError(start_sched_scan, 502 error_code)) { 503 // Logging is done inside |SendMessageAndGetAckOrError|. 504 return false; 505 } 506 if (*error_code != 0) { 507 LOG(ERROR) << "NL80211_CMD_START_SCHED_SCAN failed: " << strerror(*error_code); 508 return false; 509 } 510 511 return true; 512 } 513 514 } // namespace wificond 515 } // namespace android 516