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