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