OSDN Git Service

Cleanup p2p0 interface upon tearDownInterfaces(). am: 075145ad1d
[android-x86/system-connectivity-wificond.git] / scanning / scan_utils.cpp
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       // It might be from a hidden network. Framework doesn't need it.
152       return false;
153     }
154     if (ssid.empty() ||
155         std::all_of(ssid.begin(), ssid.end(), [](uint8_t c) {return c == 0;})) {
156       // Skip BSS with empty or all-zero SSID.
157       // It might be from a hidden network. Framework doesn't need it.
158       return false;
159     }
160     uint64_t tsf;
161     if (!bss.GetAttributeValue(NL80211_BSS_TSF, &tsf)) {
162       LOG(ERROR) << "Failed to get TSF from scan result packet";
163       return false;
164     }
165     uint64_t beacon_tsf;
166     if (bss.GetAttributeValue(NL80211_BSS_BEACON_TSF, &beacon_tsf)) {
167       if (beacon_tsf > tsf) {
168         tsf = beacon_tsf;
169       }
170     }
171     int32_t signal;
172     if (!bss.GetAttributeValue(NL80211_BSS_SIGNAL_MBM, &signal)) {
173       LOG(ERROR) << "Failed to get Signal Strength from scan result packet";
174       return false;
175     }
176     uint16_t capability;
177     if (!bss.GetAttributeValue(NL80211_BSS_CAPABILITY, &capability)) {
178       LOG(ERROR) << "Failed to get capability field from scan result packet";
179       return false;
180     }
181     bool associated = false;
182     uint32_t bss_status;
183     if (bss.GetAttributeValue(NL80211_BSS_STATUS, &bss_status) &&
184             (bss_status == NL80211_BSS_STATUS_AUTHENTICATED ||
185                 bss_status == NL80211_BSS_STATUS_ASSOCIATED)) {
186       associated = true;
187     }
188
189     *scan_result =
190         NativeScanResult(ssid, bssid, ie, freq, signal, tsf, capability, associated);
191   }
192   return true;
193 }
194
195 bool ScanUtils::GetSSIDFromInfoElement(const vector<uint8_t>& ie,
196                                        vector<uint8_t>* ssid) {
197   // Information elements are stored in 'TLV' format.
198   // Field:  |   Type     |          Length           |      Value      |
199   // Length: |     1      |             1             |     variable    |
200   // Content:| Element ID | Length of the Value field | Element payload |
201   const uint8_t* end = ie.data() + ie.size();
202   const uint8_t* ptr = ie.data();
203   // +1 means we must have space for the length field.
204   while (ptr + 1  < end) {
205     uint8_t type = *ptr;
206     uint8_t length = *(ptr + 1);
207     // Length field is invalid.
208     if (ptr + 1 + length >= end) {
209       return false;
210     }
211     // SSID element is found.
212     if (type == kElemIdSsid) {
213       // SSID is an empty string.
214       if (length == 0) {
215         *ssid = vector<uint8_t>();
216       } else {
217         *ssid = vector<uint8_t>(ptr + 2, ptr + length + 2);
218       }
219       return true;
220     }
221     ptr += 2 + length;
222   }
223   return false;
224 }
225
226 bool ScanUtils::Scan(uint32_t interface_index,
227                      bool request_random_mac,
228                      const vector<vector<uint8_t>>& ssids,
229                      const vector<uint32_t>& freqs) {
230   NL80211Packet trigger_scan(
231       netlink_manager_->GetFamilyId(),
232       NL80211_CMD_TRIGGER_SCAN,
233       netlink_manager_->GetSequenceNumber(),
234       getpid());
235   // If we do not use NLM_F_ACK, we only receive a unicast repsonse
236   // when there is an error. If everything is good, scan results notification
237   // will only be sent through multicast.
238   // If NLM_F_ACK is set, there will always be an unicast repsonse, either an
239   // ERROR or an ACK message. The handler will always be called and removed by
240   // NetlinkManager.
241   trigger_scan.AddFlag(NLM_F_ACK);
242   NL80211Attr<uint32_t> if_index_attr(NL80211_ATTR_IFINDEX, interface_index);
243
244   NL80211NestedAttr ssids_attr(NL80211_ATTR_SCAN_SSIDS);
245   for (size_t i = 0; i < ssids.size(); i++) {
246     ssids_attr.AddAttribute(NL80211Attr<vector<uint8_t>>(i, ssids[i]));
247   }
248   NL80211NestedAttr freqs_attr(NL80211_ATTR_SCAN_FREQUENCIES);
249   for (size_t i = 0; i < freqs.size(); i++) {
250     freqs_attr.AddAttribute(NL80211Attr<uint32_t>(i, freqs[i]));
251   }
252
253   trigger_scan.AddAttribute(if_index_attr);
254   trigger_scan.AddAttribute(ssids_attr);
255   // An absence of NL80211_ATTR_SCAN_FREQUENCIES attribue informs kernel to
256   // scan all supported frequencies.
257   if (!freqs.empty()) {
258     trigger_scan.AddAttribute(freqs_attr);
259   }
260
261   if (request_random_mac) {
262     trigger_scan.AddAttribute(
263         NL80211Attr<uint32_t>(NL80211_ATTR_SCAN_FLAGS,
264                               NL80211_SCAN_FLAG_RANDOM_ADDR));
265   }
266   // We are receiving an ERROR/ACK message instead of the actual
267   // scan results here, so it is OK to expect a timely response because
268   // kernel is supposed to send the ERROR/ACK back before the scan starts.
269   vector<unique_ptr<const NL80211Packet>> response;
270   if (!netlink_manager_->SendMessageAndGetAck(trigger_scan)) {
271     LOG(ERROR) << "NL80211_CMD_TRIGGER_SCAN failed";
272     return false;
273   }
274   return true;
275 }
276
277 bool ScanUtils::StopScheduledScan(uint32_t interface_index) {
278   NL80211Packet stop_sched_scan(
279       netlink_manager_->GetFamilyId(),
280       NL80211_CMD_STOP_SCHED_SCAN,
281       netlink_manager_->GetSequenceNumber(),
282       getpid());
283   // Force an ACK response upon success.
284   stop_sched_scan.AddFlag(NLM_F_ACK);
285   stop_sched_scan.AddAttribute(
286       NL80211Attr<uint32_t>(NL80211_ATTR_IFINDEX, interface_index));
287   vector<unique_ptr<const NL80211Packet>> response;
288   int error_code;
289   if (!netlink_manager_->SendMessageAndGetAckOrError(stop_sched_scan,
290                                                      &error_code))  {
291     LOG(ERROR) << "NL80211_CMD_STOP_SCHED_SCAN failed";
292     return false;
293   }
294   if (error_code == ENOENT) {
295     LOG(WARNING) << "Scheduled scan is not running!";
296     return false;
297   } else if (error_code != 0) {
298     LOG(ERROR) << "Receive ERROR message in response to"
299                << " 'stop scheduled scan' request: "
300                << strerror(error_code);
301     return false;
302   }
303   return true;
304 }
305
306 bool ScanUtils::StartScheduledScan(
307     uint32_t interface_index,
308     uint32_t interval_ms,
309     int32_t rssi_threshold,
310     bool request_random_mac,
311     const std::vector<std::vector<uint8_t>>& scan_ssids,
312     const std::vector<std::vector<uint8_t>>& match_ssids,
313     const std::vector<uint32_t>& freqs) {
314   NL80211Packet start_sched_scan(
315       netlink_manager_->GetFamilyId(),
316       NL80211_CMD_START_SCHED_SCAN,
317       netlink_manager_->GetSequenceNumber(),
318       getpid());
319   // Force an ACK response upon success.
320   start_sched_scan.AddFlag(NLM_F_ACK);
321
322   NL80211NestedAttr scan_ssids_attr(NL80211_ATTR_SCAN_SSIDS);
323   for (size_t i = 0; i < scan_ssids.size(); i++) {
324     scan_ssids_attr.AddAttribute(NL80211Attr<vector<uint8_t>>(i, scan_ssids[i]));
325   }
326   NL80211NestedAttr freqs_attr(NL80211_ATTR_SCAN_FREQUENCIES);
327   for (size_t i = 0; i < freqs.size(); i++) {
328     freqs_attr.AddAttribute(NL80211Attr<uint32_t>(i, freqs[i]));
329   }
330
331   //   Structure of attributes of scheduled scan filters:
332   // |                                Nested Attribute: id: NL80211_ATTR_SCHED_SCAN_MATCH                           |
333   // |     Nested Attributed: id: 0       |    Nested Attributed: id: 1         |      Nested Attr: id: 2     | ... |
334   // | MATCH_SSID  | MATCH_RSSI(optional) | MATCH_SSID  | MACTCH_RSSI(optional) | MATCH_RSSI(optinal, global) | ... |
335   NL80211NestedAttr scan_match_attr(NL80211_ATTR_SCHED_SCAN_MATCH);
336   for (size_t i = 0; i < match_ssids.size(); i++) {
337     NL80211NestedAttr match_group(i);
338     match_group.AddAttribute(
339         NL80211Attr<vector<uint8_t>>(NL80211_SCHED_SCAN_MATCH_ATTR_SSID, match_ssids[i]));
340     match_group.AddAttribute(
341         NL80211Attr<int32_t>(NL80211_SCHED_SCAN_MATCH_ATTR_RSSI, rssi_threshold));
342     scan_match_attr.AddAttribute(match_group);
343   }
344
345   // Append all attributes to the NL80211_CMD_START_SCHED_SCAN packet.
346   start_sched_scan.AddAttribute(
347       NL80211Attr<uint32_t>(NL80211_ATTR_IFINDEX, interface_index));
348   start_sched_scan.AddAttribute(scan_ssids_attr);
349   // An absence of NL80211_ATTR_SCAN_FREQUENCIES attribue informs kernel to
350   // scan all supported frequencies.
351   if (!freqs.empty()) {
352     start_sched_scan.AddAttribute(freqs_attr);
353   }
354   start_sched_scan.AddAttribute(
355       NL80211Attr<uint32_t>(NL80211_ATTR_SCHED_SCAN_INTERVAL, interval_ms));
356   start_sched_scan.AddAttribute(scan_match_attr);
357   if (request_random_mac) {
358     start_sched_scan.AddAttribute(
359         NL80211Attr<uint32_t>(NL80211_ATTR_SCAN_FLAGS,
360                               NL80211_SCAN_FLAG_RANDOM_ADDR));
361   }
362
363   vector<unique_ptr<const NL80211Packet>> response;
364   if (!netlink_manager_->SendMessageAndGetAck(start_sched_scan)) {
365     LOG(ERROR) << "NL80211_CMD_START_SCHED_SCAN failed";
366     return false;
367   }
368
369   return true;
370 }
371
372 }  // namespace wificond
373 }  // namespace android