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
ScanUtils(NetlinkManager * netlink_manager)42 ScanUtils::ScanUtils(NetlinkManager* netlink_manager)
43 : netlink_manager_(netlink_manager) {
44 if (!netlink_manager_->IsStarted()) {
45 netlink_manager_->Start();
46 }
47 }
48
~ScanUtils()49 ScanUtils::~ScanUtils() {}
50
SubscribeScanResultNotification(uint32_t interface_index,OnScanResultsReadyHandler handler)51 void ScanUtils::SubscribeScanResultNotification(
52 uint32_t interface_index,
53 OnScanResultsReadyHandler handler) {
54 netlink_manager_->SubscribeScanResultNotification(interface_index, handler);
55 }
56
UnsubscribeScanResultNotification(uint32_t interface_index)57 void ScanUtils::UnsubscribeScanResultNotification(uint32_t interface_index) {
58 netlink_manager_->UnsubscribeScanResultNotification(interface_index);
59 }
60
SubscribeSchedScanResultNotification(uint32_t interface_index,OnSchedScanResultsReadyHandler handler)61 void ScanUtils::SubscribeSchedScanResultNotification(
62 uint32_t interface_index,
63 OnSchedScanResultsReadyHandler handler) {
64 netlink_manager_->SubscribeSchedScanResultNotification(interface_index,
65 handler);
66 }
67
UnsubscribeSchedScanResultNotification(uint32_t interface_index)68 void ScanUtils::UnsubscribeSchedScanResultNotification(
69 uint32_t interface_index) {
70 netlink_manager_->UnsubscribeSchedScanResultNotification(interface_index);
71 }
72
GetScanResult(uint32_t interface_index,vector<NativeScanResult> * out_scan_results)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
ParseScanResult(unique_ptr<const NL80211Packet> packet,NativeScanResult * scan_result)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
GetSSIDFromInfoElement(const vector<uint8_t> & ie,vector<uint8_t> * ssid)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
Scan(uint32_t interface_index,bool request_random_mac,const vector<vector<uint8_t>> & ssids,const vector<uint32_t> & freqs)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
StopScheduledScan(uint32_t interface_index)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
AbortScan(uint32_t interface_index)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
StartScheduledScan(uint32_t interface_index,uint32_t interval_ms,int32_t rssi_threshold,bool request_random_mac,const std::vector<std::vector<uint8_t>> & scan_ssids,const std::vector<std::vector<uint8_t>> & match_ssids,const std::vector<uint32_t> & freqs)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