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