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
ScanUtils(NetlinkManager * netlink_manager)46 ScanUtils::ScanUtils(NetlinkManager* netlink_manager)
47 : netlink_manager_(netlink_manager) {
48 if (!netlink_manager_->IsStarted()) {
49 netlink_manager_->Start();
50 }
51 }
52
~ScanUtils()53 ScanUtils::~ScanUtils() {}
54
SubscribeScanResultNotification(uint32_t interface_index,OnScanResultsReadyHandler handler)55 void ScanUtils::SubscribeScanResultNotification(
56 uint32_t interface_index,
57 OnScanResultsReadyHandler handler) {
58 netlink_manager_->SubscribeScanResultNotification(interface_index, handler);
59 }
60
UnsubscribeScanResultNotification(uint32_t interface_index)61 void ScanUtils::UnsubscribeScanResultNotification(uint32_t interface_index) {
62 netlink_manager_->UnsubscribeScanResultNotification(interface_index);
63 }
64
SubscribeSchedScanResultNotification(uint32_t interface_index,OnSchedScanResultsReadyHandler handler)65 void ScanUtils::SubscribeSchedScanResultNotification(
66 uint32_t interface_index,
67 OnSchedScanResultsReadyHandler handler) {
68 netlink_manager_->SubscribeSchedScanResultNotification(interface_index,
69 handler);
70 }
71
UnsubscribeSchedScanResultNotification(uint32_t interface_index)72 void ScanUtils::UnsubscribeSchedScanResultNotification(
73 uint32_t interface_index) {
74 netlink_manager_->UnsubscribeSchedScanResultNotification(interface_index);
75 }
76
GetScanResult(uint32_t interface_index,vector<NativeScanResult> * out_scan_results)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
ParseScanResult(unique_ptr<const NL80211Packet> packet,NativeScanResult * scan_result)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
GetBssTimestampForTesting(const NL80211NestedAttr & bss,uint64_t * last_seen_since_boot_microseconds)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
GetBssTimestamp(const NL80211NestedAttr & bss,uint64_t * last_seen_since_boot_microseconds)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
ParseRadioChainInfos(const NL80211NestedAttr & bss,std::vector<RadioChainInfo> * radio_chain_infos)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
GetSSIDFromInfoElement(const vector<uint8_t> & ie,vector<uint8_t> * ssid)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
Scan(uint32_t interface_index,bool request_random_mac,int scan_type,const vector<vector<uint8_t>> & ssids,const vector<uint32_t> & freqs,int * error_code)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
StopScheduledScan(uint32_t interface_index)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
AbortScan(uint32_t interface_index)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
StartScheduledScan(uint32_t interface_index,const SchedScanIntervalSetting & interval_setting,int32_t rssi_threshold_2g,int32_t rssi_threshold_5g,bool request_random_mac,bool request_low_power,const std::vector<std::vector<uint8_t>> & scan_ssids,const std::vector<std::vector<uint8_t>> & match_ssids,const std::vector<uint32_t> & freqs,int * error_code)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