• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (C) 2012 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 "shill/wifi/wifi.h"
18 
19 #include <linux/if.h>  // Needs definitions from netinet/ether.h
20 #include <netinet/ether.h>
21 #include <stdio.h>
22 #include <string.h>
23 
24 #include <limits>
25 #include <map>
26 #include <set>
27 #include <string>
28 #include <vector>
29 
30 #include <base/bind.h>
31 #include <base/files/file_util.h>
32 #include <base/files/file_path.h>
33 #include <base/strings/string_util.h>
34 #include <base/strings/stringprintf.h>
35 #if defined(__ANDROID__)
36 #include <dbus/service_constants.h>
37 #else
38 #include <chromeos/dbus/service_constants.h>
39 #endif  // __ANDROID__
40 
41 #include "shill/control_interface.h"
42 #include "shill/device.h"
43 #include "shill/eap_credentials.h"
44 #include "shill/error.h"
45 #include "shill/file_reader.h"
46 #include "shill/geolocation_info.h"
47 #include "shill/link_monitor.h"
48 #include "shill/logging.h"
49 #include "shill/manager.h"
50 #include "shill/metrics.h"
51 #include "shill/net/ieee80211.h"
52 #include "shill/net/ip_address.h"
53 #include "shill/net/netlink_manager.h"
54 #include "shill/net/netlink_message.h"
55 #include "shill/net/nl80211_message.h"
56 #include "shill/net/rtnl_handler.h"
57 #include "shill/net/shill_time.h"
58 #include "shill/property_accessor.h"
59 #include "shill/scope_logger.h"
60 #include "shill/supplicant/supplicant_eap_state_handler.h"
61 #include "shill/supplicant/supplicant_interface_proxy_interface.h"
62 #include "shill/supplicant/supplicant_network_proxy_interface.h"
63 #include "shill/supplicant/supplicant_process_proxy_interface.h"
64 #include "shill/supplicant/wpa_supplicant.h"
65 #include "shill/technology.h"
66 #include "shill/wifi/mac80211_monitor.h"
67 #include "shill/wifi/scan_session.h"
68 #include "shill/wifi/tdls_manager.h"
69 #include "shill/wifi/wake_on_wifi.h"
70 #include "shill/wifi/wifi_endpoint.h"
71 #include "shill/wifi/wifi_provider.h"
72 #include "shill/wifi/wifi_service.h"
73 
74 using base::Bind;
75 using base::FilePath;
76 using base::StringPrintf;
77 using std::map;
78 using std::set;
79 using std::string;
80 using std::vector;
81 
82 namespace shill {
83 
84 namespace Logging {
85 static auto kModuleLogScope = ScopeLogger::kWiFi;
ObjectID(WiFi * w)86 static string ObjectID(WiFi* w) { return w->GetRpcIdentifier(); }
87 }
88 
89 // statics
90 const char* WiFi::kDefaultBgscanMethod =
91     WPASupplicant::kNetworkBgscanMethodSimple;
92 const uint16_t WiFi::kDefaultBgscanShortIntervalSeconds = 30;
93 const int32_t WiFi::kDefaultBgscanSignalThresholdDbm = -50;
94 const uint16_t WiFi::kDefaultScanIntervalSeconds = 60;
95 const uint16_t WiFi::kDefaultRoamThresholdDb = 18;  // Supplicant's default.
96 
97 // Scan interval while connected.
98 const uint16_t WiFi::kBackgroundScanIntervalSeconds = 3601;
99 // Age (in seconds) beyond which a BSS cache entry will not be preserved,
100 // across a suspend/resume.
101 const time_t WiFi::kMaxBSSResumeAgeSeconds = 10;
102 const char WiFi::kInterfaceStateUnknown[] = "shill-unknown";
103 const time_t WiFi::kRescanIntervalSeconds = 1;
104 const int WiFi::kNumFastScanAttempts = 3;
105 const int WiFi::kFastScanIntervalSeconds = 10;
106 const int WiFi::kPendingTimeoutSeconds = 15;
107 const int WiFi::kReconnectTimeoutSeconds = 10;
108 const int WiFi::kRequestStationInfoPeriodSeconds = 20;
109 const size_t WiFi::kMinumumFrequenciesToScan = 4;  // Arbitrary but > 0.
110 const float WiFi::kDefaultFractionPerScan = 0.34;
111 const size_t WiFi::kStuckQueueLengthThreshold = 40;  // ~1 full-channel scan
112 // 1 second is less than the time it takes to scan and establish a new
113 // connection after waking, but should be enough time for supplicant to update
114 // its state.
115 const int WiFi::kPostWakeConnectivityReportDelayMilliseconds = 1000;
116 const uint32_t WiFi::kDefaultWiphyIndex = UINT32_MAX;
117 const int WiFi::kPostScanFailedDelayMilliseconds = 10000;
118 // Invalid 802.11 disconnect reason code.
119 const int WiFi::kDefaultDisconnectReason = INT32_MAX;
120 
121 namespace {
IsPrintableAsciiChar(char c)122 bool IsPrintableAsciiChar(char c) {
123   return (c >= ' ' && c <= '~');
124 }
125 }  // namespace
126 
WiFi(ControlInterface * control_interface,EventDispatcher * dispatcher,Metrics * metrics,Manager * manager,const string & link,const string & address,int interface_index)127 WiFi::WiFi(ControlInterface* control_interface,
128            EventDispatcher* dispatcher,
129            Metrics* metrics,
130            Manager* manager,
131            const string& link,
132            const string& address,
133            int interface_index)
134     : Device(control_interface,
135              dispatcher,
136              metrics,
137              manager,
138              link,
139              address,
140              interface_index,
141              Technology::kWifi),
142       provider_(manager->wifi_provider()),
143       weak_ptr_factory_(this),
144       time_(Time::GetInstance()),
145       supplicant_present_(false),
146       supplicant_process_proxy_(
147           control_interface->CreateSupplicantProcessProxy(
148               Bind(&WiFi::OnSupplicantAppear, Unretained(this)),
149               Bind(&WiFi::OnSupplicantVanish, Unretained(this)))),
150       supplicant_state_(kInterfaceStateUnknown),
151       supplicant_bss_("(unknown)"),
152       supplicant_disconnect_reason_(kDefaultDisconnectReason),
153       need_bss_flush_(false),
154       resumed_at_((struct timeval){0}),
155       fast_scans_remaining_(kNumFastScanAttempts),
156       has_already_completed_(false),
157       is_roaming_in_progress_(false),
158       is_debugging_connection_(false),
159       eap_state_handler_(new SupplicantEAPStateHandler()),
160       mac80211_monitor_(new Mac80211Monitor(
161           dispatcher,
162           link,
163           kStuckQueueLengthThreshold,
164           base::Bind(&WiFi::RestartFastScanAttempts,
165                      weak_ptr_factory_.GetWeakPtr()),
166           metrics)),
167       bgscan_short_interval_seconds_(kDefaultBgscanShortIntervalSeconds),
168       bgscan_signal_threshold_dbm_(kDefaultBgscanSignalThresholdDbm),
169       roam_threshold_db_(kDefaultRoamThresholdDb),
170       scan_interval_seconds_(kDefaultScanIntervalSeconds),
171       progressive_scan_enabled_(false),
172       scan_configuration_("Full scan"),
173       netlink_manager_(NetlinkManager::GetInstance()),
174       min_frequencies_to_scan_(kMinumumFrequenciesToScan),
175       max_frequencies_to_scan_(std::numeric_limits<int>::max()),
176       scan_all_frequencies_(true),
177       fraction_per_scan_(kDefaultFractionPerScan),
178       scan_state_(kScanIdle),
179       scan_method_(kScanMethodNone),
180       receive_byte_count_at_connect_(0),
181       wiphy_index_(kDefaultWiphyIndex),
182       wake_on_wifi_(new WakeOnWiFi(netlink_manager_,
183                                    dispatcher,
184                                    metrics,
185                                    Bind(&Manager::RecordDarkResumeWakeReason,
186                                         manager->AsWeakPtr()))) {
187   PropertyStore* store = this->mutable_store();
188   store->RegisterDerivedString(
189       kBgscanMethodProperty,
190       StringAccessor(
191           // TODO(petkov): CustomMappedAccessor is used for convenience because
192           // it provides a way to define a custom clearer (unlike
193           // CustomAccessor). We need to implement a fully custom accessor with
194           // no extra argument.
195           new CustomMappedAccessor<WiFi, string, int>(this,
196                                                       &WiFi::ClearBgscanMethod,
197                                                       &WiFi::GetBgscanMethod,
198                                                       &WiFi::SetBgscanMethod,
199                                                       0)));  // Unused.
200   HelpRegisterDerivedUint16(store,
201                             kBgscanShortIntervalProperty,
202                             &WiFi::GetBgscanShortInterval,
203                             &WiFi::SetBgscanShortInterval);
204   HelpRegisterDerivedInt32(store,
205                            kBgscanSignalThresholdProperty,
206                            &WiFi::GetBgscanSignalThreshold,
207                            &WiFi::SetBgscanSignalThreshold);
208 
209   store->RegisterDerivedKeyValueStore(
210       kLinkStatisticsProperty,
211       KeyValueStoreAccessor(
212           new CustomAccessor<WiFi, KeyValueStore>(
213               this, &WiFi::GetLinkStatistics, nullptr)));
214 
215   // TODO(quiche): Decide if scan_pending_ is close enough to
216   // "currently scanning" that we don't care, or if we want to track
217   // scan pending/currently scanning/no scan scheduled as a tri-state
218   // kind of thing.
219   HelpRegisterConstDerivedBool(store,
220                                kScanningProperty,
221                                &WiFi::GetScanPending);
222   HelpRegisterDerivedUint16(store,
223                             kRoamThresholdProperty,
224                             &WiFi::GetRoamThreshold,
225                             &WiFi::SetRoamThreshold);
226   HelpRegisterDerivedUint16(store,
227                             kScanIntervalProperty,
228                             &WiFi::GetScanInterval,
229                             &WiFi::SetScanInterval);
230   wake_on_wifi_->InitPropertyStore(store);
231   ScopeLogger::GetInstance()->RegisterScopeEnableChangedCallback(
232       ScopeLogger::kWiFi,
233       Bind(&WiFi::OnWiFiDebugScopeChanged, weak_ptr_factory_.GetWeakPtr()));
234   CHECK(netlink_manager_);
235   netlink_manager_->AddBroadcastHandler(Bind(
236       &WiFi::OnScanStarted, weak_ptr_factory_.GetWeakPtr()));
237   SLOG(this, 2) << "WiFi device " << link_name() << " initialized.";
238 }
239 
~WiFi()240 WiFi::~WiFi() {}
241 
Start(Error * error,const EnabledStateChangedCallback &)242 void WiFi::Start(Error* error,
243                  const EnabledStateChangedCallback& /*callback*/) {
244   SLOG(this, 2) << "WiFi " << link_name() << " starting.";
245   if (enabled()) {
246     return;
247   }
248   OnEnabledStateChanged(EnabledStateChangedCallback(), Error());
249   if (error) {
250     error->Reset();       // indicate immediate completion
251   }
252 
253   // Subscribe to multicast events.
254   netlink_manager_->SubscribeToEvents(Nl80211Message::kMessageTypeString,
255                                       NetlinkManager::kEventTypeConfig);
256   netlink_manager_->SubscribeToEvents(Nl80211Message::kMessageTypeString,
257                                       NetlinkManager::kEventTypeScan);
258   netlink_manager_->SubscribeToEvents(Nl80211Message::kMessageTypeString,
259                                       NetlinkManager::kEventTypeRegulatory);
260   netlink_manager_->SubscribeToEvents(Nl80211Message::kMessageTypeString,
261                                       NetlinkManager::kEventTypeMlme);
262   GetPhyInfo();
263   // Connect to WPA supplicant if it's already present. If not, we'll connect to
264   // it when it appears.
265   ConnectToSupplicant();
266   wake_on_wifi_->StartMetricsTimer();
267 }
268 
Stop(Error * error,const EnabledStateChangedCallback &)269 void WiFi::Stop(Error* error, const EnabledStateChangedCallback& /*callback*/) {
270   SLOG(this, 2) << "WiFi " << link_name() << " stopping.";
271   // Unlike other devices, we leave the DBus name watcher in place here, because
272   // WiFi callbacks expect notifications even if the device is disabled.
273   DropConnection();
274   StopScanTimer();
275   for (const auto& endpoint : endpoint_by_rpcid_) {
276     provider_->OnEndpointRemoved(endpoint.second);
277   }
278   endpoint_by_rpcid_.clear();
279   for (const auto& map_entry : rpcid_by_service_) {
280     RemoveNetwork(map_entry.second);
281   }
282   rpcid_by_service_.clear();
283   // Remove interface from supplicant.
284   if (supplicant_present_ &&
285       supplicant_interface_proxy_) {
286       supplicant_process_proxy_->RemoveInterface(supplicant_interface_path_);
287   }
288   supplicant_interface_path_ = "";
289   SetSupplicantInterfaceProxy(nullptr);
290   pending_scan_results_.reset();
291   tdls_manager_.reset();
292   current_service_ = nullptr;            // breaks a reference cycle
293   pending_service_ = nullptr;            // breaks a reference cycle
294   is_debugging_connection_ = false;
295   SetScanState(kScanIdle, kScanMethodNone, __func__);
296   StopPendingTimer();
297   StopReconnectTimer();
298   StopRequestingStationInfo();
299   mac80211_monitor_->Stop();
300 
301   OnEnabledStateChanged(EnabledStateChangedCallback(), Error());
302   if (error)
303     error->Reset();       // indicate immediate completion
304   weak_ptr_factory_.InvalidateWeakPtrs();
305 
306   SLOG(this, 3) << "WiFi " << link_name() << " supplicant_process_proxy_ "
307                 << (supplicant_process_proxy_.get() ?
308                     "is set." : "is not set.");
309   SLOG(this, 3) << "WiFi " << link_name() << " supplicant_interface_proxy_ "
310                 << (supplicant_interface_proxy_.get() ?
311                     "is set." : "is not set.");
312   SLOG(this, 3) << "WiFi " << link_name() << " pending_service_ "
313                 << (pending_service_.get() ? "is set." : "is not set.");
314   SLOG(this, 3) << "WiFi " << link_name() << " has "
315                 << endpoint_by_rpcid_.size() << " EndpointMap entries.";
316 }
317 
Scan(ScanType scan_type,Error *,const string & reason)318 void WiFi::Scan(ScanType scan_type, Error* /*error*/, const string& reason) {
319   if ((scan_state_ != kScanIdle) ||
320       (current_service_.get() && current_service_->IsConnecting())) {
321     SLOG(this, 2) << "Ignoring scan request while scanning or connecting.";
322     return;
323   }
324   if (progressive_scan_enabled_ && scan_type == kProgressiveScan) {
325     LOG(INFO) << __func__ << " [progressive] on " << link_name() << " from "
326               << reason;
327     LOG(INFO) << scan_configuration_;
328     if (!scan_session_) {
329       // TODO(wdg): Perform in-depth testing to determine the best values for
330       // the different scans. chromium:235293
331       ScanSession::FractionList scan_fractions;
332       float total_fraction = 0.0;
333       do {
334         total_fraction += fraction_per_scan_;
335         scan_fractions.push_back(fraction_per_scan_);
336       } while (total_fraction < 1.0);
337       scan_session_.reset(
338           new ScanSession(netlink_manager_,
339                           dispatcher(),
340                           provider_->GetScanFrequencies(),
341                           (scan_all_frequencies_ ? all_scan_frequencies_ :
342                            set<uint16_t>()),
343                           interface_index(),
344                           scan_fractions,
345                           min_frequencies_to_scan_,
346                           max_frequencies_to_scan_,
347                           Bind(&WiFi::OnFailedProgressiveScan,
348                                weak_ptr_factory_.GetWeakPtr()),
349                           metrics()));
350       for (const auto& ssid : provider_->GetHiddenSSIDList()) {
351         scan_session_->AddSsid(ByteString(&ssid.front(), ssid.size()));
352       }
353     }
354     dispatcher()->PostTask(
355         Bind(&WiFi::ProgressiveScanTask, weak_ptr_factory_.GetWeakPtr()));
356   } else {
357     LOG(INFO) << __func__ << " [full] on " << link_name()
358               << " (progressive scan "
359               << (progressive_scan_enabled_ ? "ENABLED" : "DISABLED")
360               << ") from " << reason;
361     // Needs to send a D-Bus message, but may be called from D-Bus
362     // signal handler context (via Manager::RequestScan). So defer work
363     // to event loop.
364     dispatcher()->PostTask(
365         Bind(&WiFi::ScanTask, weak_ptr_factory_.GetWeakPtr()));
366   }
367 }
368 
SetSchedScan(bool enable,Error *)369 void WiFi::SetSchedScan(bool enable, Error* /*error*/) {
370   // Needs to send a D-Bus message, but may be called from D-Bus
371   // signal handler context (via Manager::SetSchedScan). So defer work
372   // to event loop.
373   dispatcher()->PostTask(
374       Bind(&WiFi::SetSchedScanTask, weak_ptr_factory_.GetWeakPtr(), enable));
375 }
376 
AddPendingScanResult(const string & path,const KeyValueStore & properties,bool is_removal)377 void WiFi::AddPendingScanResult(const string& path,
378                                 const KeyValueStore& properties,
379                                 bool is_removal) {
380   if (!pending_scan_results_) {
381     pending_scan_results_.reset(new PendingScanResults(
382         Bind(&WiFi::PendingScanResultsHandler,
383              weak_ptr_factory_.GetWeakPtr())));
384     dispatcher()->PostTask(pending_scan_results_->callback.callback());
385   }
386   pending_scan_results_->results.emplace_back(path, properties, is_removal);
387 }
388 
BSSAdded(const string & path,const KeyValueStore & properties)389 void WiFi::BSSAdded(const string& path, const KeyValueStore& properties) {
390   // Called from a D-Bus signal handler, and may need to send a D-Bus
391   // message. So defer work to event loop.
392   AddPendingScanResult(path, properties, false);
393 }
394 
BSSRemoved(const string & path)395 void WiFi::BSSRemoved(const string& path) {
396   // Called from a D-Bus signal handler, and may need to send a D-Bus
397   // message. So defer work to event loop.
398   AddPendingScanResult(path, {}, true);
399 }
400 
Certification(const KeyValueStore & properties)401 void WiFi::Certification(const KeyValueStore& properties) {
402   dispatcher()->PostTask(Bind(&WiFi::CertificationTask,
403                               weak_ptr_factory_.GetWeakPtr(), properties));
404 }
405 
EAPEvent(const string & status,const string & parameter)406 void WiFi::EAPEvent(const string& status, const string& parameter) {
407   dispatcher()->PostTask(Bind(&WiFi::EAPEventTask,
408                               weak_ptr_factory_.GetWeakPtr(),
409                               status,
410                               parameter));
411 }
412 
PropertiesChanged(const KeyValueStore & properties)413 void WiFi::PropertiesChanged(const KeyValueStore& properties) {
414   SLOG(this, 2) << __func__;
415   // Called from D-Bus signal handler, but may need to send a D-Bus
416   // message. So defer work to event loop.
417   dispatcher()->PostTask(Bind(&WiFi::PropertiesChangedTask,
418                               weak_ptr_factory_.GetWeakPtr(), properties));
419 }
420 
ScanDone(const bool & success)421 void WiFi::ScanDone(const bool& success) {
422   LOG(INFO) << __func__;
423 
424   // Defer handling of scan result processing, because that processing
425   // may require the the registration of new D-Bus objects. And such
426   // registration can't be done in the context of a D-Bus signal
427   // handler.
428   if (pending_scan_results_) {
429     pending_scan_results_->is_complete = true;
430     return;
431   }
432   if (success) {
433     scan_failed_callback_.Cancel();
434     dispatcher()->PostTask(
435         Bind(&WiFi::ScanDoneTask, weak_ptr_factory_.GetWeakPtr()));
436   } else {
437     scan_failed_callback_.Reset(
438         Bind(&WiFi::ScanFailedTask, weak_ptr_factory_.GetWeakPtr()));
439     dispatcher()->PostDelayedTask(scan_failed_callback_.callback(),
440                                   kPostScanFailedDelayMilliseconds);
441   }
442 }
443 
ConnectTo(WiFiService * service)444 void WiFi::ConnectTo(WiFiService* service) {
445   CHECK(service) << "Can't connect to NULL service.";
446   string network_path;
447 
448   // Ignore this connection attempt if suppplicant is not present.
449   // This is possible when we try to connect right after WiFi
450   // boostrapping is completed (through weaved). Refer to b/24605760
451   // for more information.
452   // Once supplicant is detected, shill will auto-connect to this
453   // service (if this service is configured for auto-connect) when
454   // it is discovered in the scan.
455   if (!supplicant_present_) {
456     LOG(ERROR) << "Trying to connect before supplicant is present";
457     return;
458   }
459 
460   // TODO(quiche): Handle cases where already connected.
461   if (pending_service_ && pending_service_ == service) {
462     // TODO(quiche): Return an error to the caller. crbug.com/206812
463     LOG(INFO) << "WiFi " << link_name() << " ignoring ConnectTo service "
464               << service->unique_name()
465               << ", which is already pending.";
466     return;
467   }
468 
469   if (pending_service_ && pending_service_ != service) {
470     LOG(INFO) << "Connecting to service. "
471               << LogSSID(service->unique_name()) << ", "
472               << "bssid: " << service->bssid() << ", "
473               << "mode: " << service->mode() << ", "
474               << "key management: " << service->key_management() << ", "
475               << "physical mode: " << service->physical_mode() << ", "
476               << "frequency: " << service->frequency();
477     // This is a signal to SetPendingService(nullptr) to not modify the scan
478     // state since the overall story arc isn't reflected by the disconnect.
479     // It is, instead, described by the transition to either kScanFoundNothing
480     // or kScanConnecting (made by |SetPendingService|, below).
481     if (scan_method_ != kScanMethodNone) {
482       SetScanState(kScanTransitionToConnecting, scan_method_, __func__);
483     }
484     // Explicitly disconnect pending service.
485     pending_service_->set_expecting_disconnect(true);
486     DisconnectFrom(pending_service_.get());
487   }
488 
489   Error unused_error;
490   network_path = FindNetworkRpcidForService(service, &unused_error);
491   if (network_path.empty()) {
492     KeyValueStore service_params =
493         service->GetSupplicantConfigurationParameters();
494     const uint32_t scan_ssid = 1;  // "True": Use directed probe.
495     service_params.SetUint(WPASupplicant::kNetworkPropertyScanSSID, scan_ssid);
496     AppendBgscan(service, &service_params);
497     service_params.SetUint(WPASupplicant::kNetworkPropertyDisableVHT,
498                            provider_->disable_vht());
499     if (!supplicant_interface_proxy_->AddNetwork(service_params,
500                                                  &network_path)) {
501       LOG(ERROR) << "Failed to add network";
502       SetScanState(kScanIdle, scan_method_, __func__);
503       return;
504     }
505     CHECK(!network_path.empty());  // No DBus path should be empty.
506     rpcid_by_service_[service] = network_path;
507   }
508 
509   if (service->HasRecentConnectionIssues()) {
510     SetConnectionDebugging(true);
511   }
512 
513   // Enable HT40 for this network in case if it was disabled previously due to
514   // unreliable link.
515   supplicant_interface_proxy_->SetHT40Enable(network_path, true);
516 
517   supplicant_interface_proxy_->SelectNetwork(network_path);
518   SetPendingService(service);
519   CHECK(current_service_.get() != pending_service_.get());
520 
521   // SelectService here (instead of in LinkEvent, like Ethernet), so
522   // that, if we fail to bring up L2, we can attribute failure correctly.
523   //
524   // TODO(quiche): When we add code for dealing with connection failures,
525   // reconsider if this is the right place to change the selected service.
526   // see discussion in crbug.com/203282.
527   SelectService(service);
528 }
529 
DisconnectFromIfActive(WiFiService * service)530 void WiFi::DisconnectFromIfActive(WiFiService* service) {
531   SLOG(this, 2) << __func__ << " service " << service->unique_name();
532 
533   if (service != current_service_ &&  service != pending_service_) {
534     if (!service->IsActive(nullptr)) {
535       SLOG(this, 2) << "In " << __func__ << "():  service "
536                     << service->unique_name()
537                     << " is not active, no need to initiate disconnect";
538       return;
539     }
540   }
541 
542   DisconnectFrom(service);
543 }
544 
DisconnectFrom(WiFiService * service)545 void WiFi::DisconnectFrom(WiFiService* service) {
546   SLOG(this, 2) << __func__ << " service " << service->unique_name();
547 
548   if (service != current_service_ &&  service != pending_service_) {
549     // TODO(quiche): Once we have asynchronous reply support, we should
550     // generate a D-Bus error here. (crbug.com/206812)
551     LOG(WARNING) << "In " << __func__ << "(): "
552                  << " ignoring request to disconnect from service "
553                  << service->unique_name()
554                  << " which is neither current nor pending";
555     return;
556   }
557 
558   if (pending_service_ && service != pending_service_) {
559     // TODO(quiche): Once we have asynchronous reply support, we should
560     // generate a D-Bus error here. (crbug.com/206812)
561     LOG(WARNING) << "In " << __func__ << "(): "
562                  << " ignoring request to disconnect from service "
563                  << service->unique_name()
564                  << " which is not the pending service.";
565     return;
566   }
567 
568   if (!pending_service_ && service != current_service_) {
569     // TODO(quiche): Once we have asynchronous reply support, we should
570     // generate a D-Bus error here. (crbug.com/206812)
571     LOG(WARNING) << "In " << __func__ << "(): "
572                  << " ignoring request to disconnect from service "
573                  << service->unique_name()
574                  << " which is not the current service.";
575     return;
576   }
577 
578   if (pending_service_) {
579     // Since wpa_supplicant has not yet set CurrentBSS, we can't depend
580     // on this to drive the service state back to idle.  Do that here.
581     // Update service state for pending service.
582     ServiceDisconnected(pending_service_);
583   }
584 
585   SetPendingService(nullptr);
586   StopReconnectTimer();
587   StopRequestingStationInfo();
588 
589   if (!supplicant_present_) {
590     LOG(ERROR) << "In " << __func__ << "(): "
591                << "wpa_supplicant is not present; silently resetting "
592                << "current_service_.";
593     if (current_service_ == selected_service()) {
594       DropConnection();
595     }
596     current_service_ = nullptr;
597     return;
598   }
599 
600   bool disconnect_in_progress = true;
601   // We'll call RemoveNetwork and reset |current_service_| after
602   // supplicant notifies us that the CurrentBSS has changed.
603   if (!supplicant_interface_proxy_->Disconnect()) {
604     disconnect_in_progress = false;
605   }
606 
607   if (supplicant_state_ != WPASupplicant::kInterfaceStateCompleted ||
608       !disconnect_in_progress) {
609     // Can't depend on getting a notification of CurrentBSS change.
610     // So effect changes immediately.  For instance, this can happen when
611     // a disconnect is triggered by a BSS going away.
612     Error unused_error;
613     RemoveNetworkForService(service, &unused_error);
614     if (service == selected_service()) {
615       DropConnection();
616     } else {
617       SLOG(this, 5) << __func__ << " skipping DropConnection, "
618                     << "selected_service is "
619                     << (selected_service() ?
620                         selected_service()->unique_name() : "(null)");
621     }
622     current_service_ = nullptr;
623   }
624 
625   CHECK(current_service_ == nullptr ||
626         current_service_.get() != pending_service_.get());
627 }
628 
DisableNetwork(const string & network)629 bool WiFi::DisableNetwork(const string& network) {
630   std::unique_ptr<SupplicantNetworkProxyInterface> supplicant_network_proxy(
631       control_interface()->CreateSupplicantNetworkProxy(network));
632   if (!supplicant_network_proxy->SetEnabled(false)) {
633     LOG(ERROR) << "DisableNetwork for " << network << " failed.";
634     return false;
635   }
636   return true;
637 }
638 
RemoveNetwork(const string & network)639 bool WiFi::RemoveNetwork(const string& network) {
640   return supplicant_interface_proxy_->RemoveNetwork(network);
641 }
642 
SetHT40EnableForService(const WiFiService * service,bool enable)643 void WiFi::SetHT40EnableForService(const WiFiService* service, bool enable) {
644   if (!supplicant_present_) {
645     LOG(ERROR) << "In " << __func__ << "(): "
646                << "wpa_supplicant is not present.  Cannot SetHT40Enable.";
647     return;
648   }
649 
650   Error error;
651   string rpcid = FindNetworkRpcidForService(service, &error);
652   if (rpcid.empty()) {
653       LOG(ERROR) << "Unable to find supplicant network.";
654       return;
655   }
656 
657   if (!supplicant_interface_proxy_->SetHT40Enable(rpcid, enable)) {
658     LOG(ERROR) << "SetHT40Enable for " << rpcid << " failed.";
659   }
660 }
661 
IsIdle() const662 bool WiFi::IsIdle() const {
663   return !current_service_ && !pending_service_;
664 }
665 
ClearCachedCredentials(const WiFiService * service)666 void WiFi::ClearCachedCredentials(const WiFiService* service) {
667   Error unused_error;
668   RemoveNetworkForService(service, &unused_error);
669 
670   // Give up on the connection attempt for the pending service immediately since
671   // the credential for it had already changed. This will allow the Manager to
672   // start a new connection attempt for the pending service immediately without
673   // waiting for the pending connection timeout.
674   // current_service_ will get disconnect notification from the CurrentBSS
675   // change event, so no need to explicitly disconnect here.
676   if (service == pending_service_) {
677     LOG(INFO) << "Disconnect pending service: credential changed";
678     DisconnectFrom(pending_service_.get());
679   }
680 }
681 
NotifyEndpointChanged(const WiFiEndpointConstRefPtr & endpoint)682 void WiFi::NotifyEndpointChanged(const WiFiEndpointConstRefPtr& endpoint) {
683   provider_->OnEndpointUpdated(endpoint);
684 }
685 
AppendBgscan(WiFiService * service,KeyValueStore * service_params) const686 void WiFi::AppendBgscan(WiFiService* service,
687                         KeyValueStore* service_params) const {
688   int scan_interval = kBackgroundScanIntervalSeconds;
689   string method = bgscan_method_;
690   if (method.empty()) {
691     // If multiple APs are detected for this SSID, configure the default method.
692     // Otherwise, disable background scanning completely.
693     if (service->GetEndpointCount() > 1) {
694       method = kDefaultBgscanMethod;
695     } else {
696       LOG(INFO) << "Background scan disabled -- single Endpoint for Service.";
697       return;
698     }
699   } else if (method.compare(WPASupplicant::kNetworkBgscanMethodNone) == 0) {
700       LOG(INFO) << "Background scan disabled -- chose None method.";
701       return;
702   } else {
703     // If the background scan method was explicitly specified, honor the
704     // configured background scan interval.
705     scan_interval = scan_interval_seconds_;
706   }
707   DCHECK(!method.empty());
708   string config_string = StringPrintf("%s:%d:%d:%d",
709                                       method.c_str(),
710                                       bgscan_short_interval_seconds_,
711                                       bgscan_signal_threshold_dbm_,
712                                       scan_interval);
713   LOG(INFO) << "Background scan: " << config_string;
714   service_params->SetString(WPASupplicant::kNetworkPropertyBgscan,
715                            config_string);
716 }
717 
GetBgscanMethod(const int &,Error *)718 string WiFi::GetBgscanMethod(const int& /*argument*/, Error* /* error */) {
719   return bgscan_method_.empty() ? kDefaultBgscanMethod : bgscan_method_;
720 }
721 
SetBgscanMethod(const int &,const string & method,Error * error)722 bool WiFi::SetBgscanMethod(
723     const int& /*argument*/, const string& method, Error* error) {
724   if (method != WPASupplicant::kNetworkBgscanMethodSimple &&
725       method != WPASupplicant::kNetworkBgscanMethodLearn &&
726       method != WPASupplicant::kNetworkBgscanMethodNone) {
727     const string error_message =
728         StringPrintf("Unrecognized bgscan method %s", method.c_str());
729     LOG(WARNING) << error_message;
730     error->Populate(Error::kInvalidArguments, error_message);
731     return false;
732   }
733   if (bgscan_method_ == method) {
734     return false;
735   }
736   bgscan_method_ = method;
737   // We do not update kNetworkPropertyBgscan for |pending_service_| or
738   // |current_service_|, because supplicant does not allow for
739   // reconfiguration without disconnect and reconnect.
740   return true;
741 }
742 
SetBgscanShortInterval(const uint16_t & seconds,Error *)743 bool WiFi::SetBgscanShortInterval(const uint16_t& seconds, Error* /*error*/) {
744   if (bgscan_short_interval_seconds_ == seconds) {
745     return false;
746   }
747   bgscan_short_interval_seconds_ = seconds;
748   // We do not update kNetworkPropertyBgscan for |pending_service_| or
749   // |current_service_|, because supplicant does not allow for
750   // reconfiguration without disconnect and reconnect.
751   return true;
752 }
753 
SetBgscanSignalThreshold(const int32_t & dbm,Error *)754 bool WiFi::SetBgscanSignalThreshold(const int32_t& dbm, Error* /*error*/) {
755   if (bgscan_signal_threshold_dbm_ == dbm) {
756     return false;
757   }
758   bgscan_signal_threshold_dbm_ = dbm;
759   // We do not update kNetworkPropertyBgscan for |pending_service_| or
760   // |current_service_|, because supplicant does not allow for
761   // reconfiguration without disconnect and reconnect.
762   return true;
763 }
764 
SetRoamThreshold(const uint16_t & threshold,Error *)765 bool WiFi::SetRoamThreshold(const uint16_t& threshold, Error* /*error*/) {
766   roam_threshold_db_ = threshold;
767   if (!current_service_ || !current_service_->roam_threshold_db_set()) {
768     supplicant_interface_proxy_->SetRoamThreshold(threshold);
769   }
770   return true;
771 }
772 
SetScanInterval(const uint16_t & seconds,Error *)773 bool WiFi::SetScanInterval(const uint16_t& seconds, Error* /*error*/) {
774   if (scan_interval_seconds_ == seconds) {
775     return false;
776   }
777   scan_interval_seconds_ = seconds;
778   if (running()) {
779     StartScanTimer();
780   }
781   // The scan interval affects both foreground scans (handled by
782   // |scan_timer_callback_|), and background scans (handled by
783   // supplicant). However, we do not update |pending_service_| or
784   // |current_service_|, because supplicant does not allow for
785   // reconfiguration without disconnect and reconnect.
786   return true;
787 }
788 
ClearBgscanMethod(const int &,Error *)789 void WiFi::ClearBgscanMethod(const int& /*argument*/, Error* /*error*/) {
790   bgscan_method_.clear();
791 }
792 
CurrentBSSChanged(const string & new_bss)793 void WiFi::CurrentBSSChanged(const string& new_bss) {
794   SLOG(this, 3) << "WiFi " << link_name() << " CurrentBSS "
795                 << supplicant_bss_ << " -> " << new_bss;
796   supplicant_bss_ = new_bss;
797   has_already_completed_ = false;
798   is_roaming_in_progress_ = false;
799 
800   // Any change in CurrentBSS means supplicant is actively changing our
801   // connectivity.  We no longer need to track any previously pending
802   // reconnect.
803   StopReconnectTimer();
804   StopRequestingStationInfo();
805 
806   if (new_bss == WPASupplicant::kCurrentBSSNull) {
807     HandleDisconnect();
808     if (!provider_->GetHiddenSSIDList().empty()) {
809       // Before disconnecting, wpa_supplicant probably scanned for
810       // APs. So, in the normal case, we defer to the timer for the next scan.
811       //
812       // However, in the case of hidden SSIDs, supplicant knows about
813       // at most one of them. (That would be the hidden SSID we were
814       // connected to, if applicable.)
815       //
816       // So, in this case, we initiate an immediate scan. This scan
817       // will include the hidden SSIDs we know about (up to the limit of
818       // kScanMAxSSIDsPerScan).
819       //
820       // We may want to reconsider this immediate scan, if/when shill
821       // takes greater responsibility for scanning (vs. letting
822       // supplicant handle most of it).
823       Scan(kProgressiveScan, nullptr, __func__);
824     }
825   } else {
826     HandleRoam(new_bss);
827   }
828 
829   // Reset the EAP handler only after calling HandleDisconnect() above
830   // so our EAP state could be used to detect a failed authentication.
831   eap_state_handler_->Reset();
832 
833   // If we are selecting a new service, or if we're clearing selection
834   // of a something other than the pending service, call SelectService.
835   // Otherwise skip SelectService, since this will cause the pending
836   // service to be marked as Idle.
837   if (current_service_ || selected_service() != pending_service_) {
838     SelectService(current_service_);
839   }
840 
841   // Invariant check: a Service can either be current, or pending, but
842   // not both.
843   CHECK(current_service_.get() != pending_service_.get() ||
844         current_service_.get() == nullptr);
845 
846   // If we are no longer debugging a problematic WiFi connection, return
847   // to the debugging level indicated by the WiFi debugging scope.
848   if ((!current_service_ || !current_service_->HasRecentConnectionIssues()) &&
849       (!pending_service_ || !pending_service_->HasRecentConnectionIssues())) {
850     SetConnectionDebugging(false);
851   }
852 }
853 
DisconnectReasonChanged(const int32_t new_disconnect_reason)854 void WiFi::DisconnectReasonChanged(const int32_t new_disconnect_reason) {
855   if (new_disconnect_reason == kDefaultDisconnectReason) {
856     SLOG(this, 3) << "WiFi clearing DisconnectReason for " << link_name();
857   } else {
858     string update = "";
859     if (supplicant_disconnect_reason_ != kDefaultDisconnectReason) {
860       update = StringPrintf(" (was %d)", supplicant_disconnect_reason_);
861     }
862     LOG(INFO) << "WiFi " << link_name()
863               << " supplicant updated DisconnectReason to "
864               << new_disconnect_reason << update;
865   }
866   supplicant_disconnect_reason_ = new_disconnect_reason;
867 }
868 
HandleDisconnect()869 void WiFi::HandleDisconnect() {
870   // Identify the affected service. We expect to get a disconnect
871   // event when we fall off a Service that we were connected
872   // to. However, we also allow for the case where we get a disconnect
873   // event while attempting to connect from a disconnected state.
874   WiFiService* affected_service =
875       current_service_.get() ? current_service_.get() : pending_service_.get();
876 
877   if (!affected_service) {
878     SLOG(this, 2) << "WiFi " << link_name()
879                   << " disconnected while not connected or connecting";
880     return;
881   }
882 
883   SLOG(this, 2) << "WiFi " << link_name() << " disconnected from "
884                 << " (or failed to connect to) service "
885                 << affected_service->unique_name();
886 
887   if (affected_service == current_service_.get() && pending_service_.get()) {
888     // Current service disconnected intentionally for network switching,
889     // set service state to idle.
890     affected_service->SetState(Service::kStateIdle);
891   } else {
892     // Perform necessary handling for disconnected service.
893     ServiceDisconnected(affected_service);
894   }
895 
896   current_service_ = nullptr;
897 
898   if (affected_service == selected_service()) {
899     // If our selected service has disconnected, destroy IP configuration state.
900     DropConnection();
901   }
902 
903   Error error;
904   if (!DisableNetworkForService(affected_service, &error)) {
905     if (error.type() == Error::kNotFound) {
906       SLOG(this, 2) << "WiFi " << link_name() << " disconnected from "
907                     << " (or failed to connect to) service "
908                     << affected_service->unique_name() << ", "
909                     << "but could not find supplicant network to disable.";
910     } else {
911       LOG(FATAL) << "DisableNetwork failed on " << link_name()
912                  << "for service " << affected_service->unique_name() << ".";
913     }
914   }
915 
916   metrics()->NotifySignalAtDisconnect(*affected_service,
917                                       affected_service->SignalLevel());
918   affected_service->NotifyCurrentEndpoint(nullptr);
919   metrics()->NotifyServiceDisconnect(*affected_service);
920 
921   if (affected_service == pending_service_.get()) {
922     // The attempt to connect to |pending_service_| failed. Clear
923     // |pending_service_|, to indicate we're no longer in the middle
924     // of a connect request.
925     SetPendingService(nullptr);
926   } else if (pending_service_.get()) {
927     // We've attributed the disconnection to what was the
928     // |current_service_|, rather than the |pending_service_|.
929     //
930     // If we're wrong about that (i.e. supplicant reported this
931     // CurrentBSS change after attempting to connect to
932     // |pending_service_|), we're depending on supplicant to retry
933     // connecting to |pending_service_|, and delivering another
934     // CurrentBSS change signal in the future.
935     //
936     // Log this fact, to help us debug (in case our assumptions are
937     // wrong).
938     SLOG(this, 2) << "WiFi " << link_name() << " pending connection to service "
939                   << pending_service_->unique_name()
940                   << " after disconnect";
941   }
942 
943   // If we disconnect, initially scan at a faster frequency, to make sure
944   // we've found all available APs.
945   RestartFastScanAttempts();
946 }
947 
ServiceDisconnected(WiFiServiceRefPtr affected_service)948 void WiFi::ServiceDisconnected(WiFiServiceRefPtr affected_service) {
949   SLOG(this, 2) << __func__ << " service " << affected_service->unique_name();
950 
951   // Check if service was explicitly disconnected due to failure or
952   // is explicitly disconnected by user.
953   if (!affected_service->IsInFailState() &&
954       !affected_service->explicitly_disconnected() &&
955       !affected_service->expecting_disconnect()) {
956     // Determine disconnect failure reason.
957     Service::ConnectFailure failure;
958     if (SuspectCredentials(affected_service, &failure)) {
959       // If we suspect bad credentials, set failure, to trigger an error
960       // mole in Chrome.
961       affected_service->SetFailure(failure);
962       LOG(ERROR) << "Connection failure is due to suspect credentials: "
963                  << "returning "
964                  << Service::ConnectFailureToString(failure);
965     } else {
966       // Disconnected due to inability to connect to service, most likely
967       // due to roaming out of range.
968       LOG(ERROR) << "Disconnected due to inability to connect to the service.";
969       affected_service->SetFailure(Service::kFailureOutOfRange);
970     }
971   }
972 
973   // Set service state back to idle, so this service can be used for
974   // future connections.
975   affected_service->SetState(Service::kStateIdle);
976 }
977 
978 // We use the term "Roam" loosely. In particular, we include the case
979 // where we "Roam" to a BSS from the disconnected state.
HandleRoam(const string & new_bss)980 void WiFi::HandleRoam(const string& new_bss) {
981   EndpointMap::iterator endpoint_it = endpoint_by_rpcid_.find(new_bss);
982   if (endpoint_it == endpoint_by_rpcid_.end()) {
983     LOG(WARNING) << "WiFi " << link_name() << " connected to unknown BSS "
984                  << new_bss;
985     return;
986   }
987 
988   const WiFiEndpointConstRefPtr endpoint(endpoint_it->second);
989   WiFiServiceRefPtr service = provider_->FindServiceForEndpoint(endpoint);
990   if (!service.get()) {
991       LOG(WARNING) << "WiFi " << link_name()
992                    << " could not find Service for Endpoint "
993                    << endpoint->bssid_string()
994                    << " (service will be unchanged)";
995       return;
996   }
997 
998   SLOG(this, 2) << "WiFi " << link_name()
999                 << " roamed to Endpoint " << endpoint->bssid_string()
1000                 << " " << LogSSID(endpoint->ssid_string());
1001 
1002   service->NotifyCurrentEndpoint(endpoint);
1003 
1004   if (pending_service_.get() &&
1005       service.get() != pending_service_.get()) {
1006     // The Service we've roamed on to is not the one we asked for.
1007     // We assume that this is transient, and that wpa_supplicant
1008     // is trying / will try to connect to |pending_service_|.
1009     //
1010     // If it succeeds, we'll end up back here, but with |service|
1011     // pointing at the same service as |pending_service_|.
1012     //
1013     // If it fails, we'll process things in HandleDisconnect.
1014     //
1015     // So we leave |pending_service_| untouched.
1016     SLOG(this, 2) << "WiFi " << link_name()
1017                   << " new current Endpoint "
1018                   << endpoint->bssid_string()
1019                   << " is not part of pending service "
1020                   << pending_service_->unique_name();
1021 
1022     // Sanity check: if we didn't roam onto |pending_service_|, we
1023     // should still be on |current_service_|.
1024     if (service.get() != current_service_.get()) {
1025       LOG(WARNING) << "WiFi " << link_name()
1026                    << " new current Endpoint "
1027                    << endpoint->bssid_string()
1028                    << " is neither part of pending service "
1029                    << pending_service_->unique_name()
1030                    << " nor part of current service "
1031                    << (current_service_ ?
1032                        current_service_->unique_name() :
1033                        "(nullptr)");
1034       // wpa_supplicant has no knowledge of the pending_service_ at this point.
1035       // Disconnect the pending_service_, so that it can be connectable again.
1036       // Otherwise, we'd have to wait for the pending timeout to trigger the
1037       // disconnect. This will speed up the connection attempt process for
1038       // the pending_service_.
1039       DisconnectFrom(pending_service_.get());
1040     }
1041     return;
1042   }
1043 
1044   if (pending_service_.get()) {
1045     // We assume service.get() == pending_service_.get() here, because
1046     // of the return in the previous if clause.
1047     //
1048     // Boring case: we've connected to the service we asked
1049     // for. Simply update |current_service_| and |pending_service_|.
1050     current_service_ = service;
1051     SetScanState(kScanConnected, scan_method_, __func__);
1052     SetPendingService(nullptr);
1053     // Use WiFi service-specific roam threshold if it is set, otherwise use WiFi
1054     // device-wide roam threshold.
1055     if (current_service_->roam_threshold_db_set()) {
1056       supplicant_interface_proxy_->SetRoamThreshold(
1057           current_service_->roam_threshold_db());
1058     } else {
1059       supplicant_interface_proxy_->SetRoamThreshold(roam_threshold_db_);
1060     }
1061     return;
1062   }
1063 
1064   // |pending_service_| was nullptr, so we weren't attempting to connect
1065   // to a new Service. Sanity check that we're still on
1066   // |current_service_|.
1067   if (service.get() != current_service_.get()) {
1068     LOG(WARNING)
1069         << "WiFi " << link_name()
1070         << " new current Endpoint "
1071         << endpoint->bssid_string()
1072         << (current_service_.get() ?
1073             StringPrintf(" is not part of current service %s",
1074                          current_service_->unique_name().c_str()) :
1075             " with no current service");
1076     // We didn't expect to be here, but let's cope as well as we
1077     // can. Update |current_service_| to keep it in sync with
1078     // supplicant.
1079     current_service_ = service;
1080 
1081     // If this service isn't already marked as actively connecting (likely,
1082     // since this service is a bit of a surprise) set the service as
1083     // associating.
1084     if (!current_service_->IsConnecting()) {
1085       current_service_->SetState(Service::kStateAssociating);
1086     }
1087 
1088     return;
1089   }
1090 
1091   // At this point, we know that |pending_service_| was nullptr, and that
1092   // we're still on |current_service_|.  We should track this roaming
1093   // event so we can refresh our IPConfig if it succeeds.
1094   is_roaming_in_progress_ = true;
1095 
1096   return;
1097 }
1098 
FindNetworkRpcidForService(const WiFiService * service,Error * error)1099 string WiFi::FindNetworkRpcidForService(
1100     const WiFiService* service, Error* error) {
1101   ReverseServiceMap::const_iterator rpcid_it = rpcid_by_service_.find(service);
1102   if (rpcid_it == rpcid_by_service_.end()) {
1103     const string error_message =
1104         StringPrintf(
1105             "WiFi %s cannot find supplicant network rpcid for service %s",
1106             link_name().c_str(), service->unique_name().c_str());
1107     // There are contexts where this is not an error, such as when a service
1108     // is clearing whatever cached credentials may not exist.
1109     SLOG(this, 2) << error_message;
1110     if (error) {
1111       error->Populate(Error::kNotFound, error_message);
1112     }
1113     return "";
1114   }
1115 
1116   return rpcid_it->second;
1117 }
1118 
DisableNetworkForService(const WiFiService * service,Error * error)1119 bool WiFi::DisableNetworkForService(const WiFiService* service, Error* error) {
1120   string rpcid = FindNetworkRpcidForService(service, error);
1121   if (rpcid.empty()) {
1122       // Error is already populated.
1123       return false;
1124   }
1125 
1126   if (!DisableNetwork(rpcid)) {
1127     const string error_message =
1128         StringPrintf("WiFi %s cannot disable network for service %s: "
1129                      "DBus operation failed for rpcid %s.",
1130                      link_name().c_str(), service->unique_name().c_str(),
1131                      rpcid.c_str());
1132     Error::PopulateAndLog(
1133         FROM_HERE, error, Error::kOperationFailed, error_message);
1134 
1135     // Make sure that such errored networks are removed, so problems do not
1136     // propagate to future connection attempts.
1137     RemoveNetwork(rpcid);
1138     rpcid_by_service_.erase(service);
1139 
1140     return false;
1141   }
1142 
1143   return true;
1144 }
1145 
RemoveNetworkForService(const WiFiService * service,Error * error)1146 bool WiFi::RemoveNetworkForService(const WiFiService* service, Error* error) {
1147   string rpcid = FindNetworkRpcidForService(service, error);
1148   if (rpcid.empty()) {
1149       // Error is already populated.
1150       return false;
1151   }
1152 
1153   // Erase the rpcid from our tables regardless of failure below, since even
1154   // if in failure, we never want to use this network again.
1155   rpcid_by_service_.erase(service);
1156 
1157   // TODO(quiche): Reconsider giving up immediately. Maybe give
1158   // wpa_supplicant some time to retry, first.
1159   if (!RemoveNetwork(rpcid)) {
1160     const string error_message =
1161         StringPrintf("WiFi %s cannot remove network for service %s: "
1162                      "DBus operation failed for rpcid %s.",
1163                      link_name().c_str(), service->unique_name().c_str(),
1164                      rpcid.c_str());
1165     Error::PopulateAndLog(
1166         FROM_HERE, error, Error::kOperationFailed, error_message);
1167     return false;
1168   }
1169 
1170   return true;
1171 }
1172 
PendingScanResultsHandler()1173 void WiFi::PendingScanResultsHandler() {
1174   CHECK(pending_scan_results_);
1175   SLOG(this, 2) << __func__ << " with " << pending_scan_results_->results.size()
1176                 << " results and is_complete set to "
1177                 << pending_scan_results_->is_complete;
1178   for (const auto result : pending_scan_results_->results) {
1179     if (result.is_removal) {
1180       BSSRemovedTask(result.path);
1181     } else {
1182       BSSAddedTask(result.path, result.properties);
1183     }
1184   }
1185   if (pending_scan_results_->is_complete) {
1186     ScanDoneTask();
1187   }
1188   pending_scan_results_.reset();
1189 }
1190 
ParseWiphyIndex(const Nl80211Message & nl80211_message)1191 bool WiFi::ParseWiphyIndex(const Nl80211Message& nl80211_message) {
1192   // Verify NL80211_CMD_NEW_WIPHY.
1193   if (nl80211_message.command() != NewWiphyMessage::kCommand) {
1194     LOG(ERROR) << "Received unexpected command: " << nl80211_message.command();
1195     return false;
1196   }
1197   if (!nl80211_message.const_attributes()->GetU32AttributeValue(
1198           NL80211_ATTR_WIPHY, &wiphy_index_)) {
1199     LOG(ERROR) << "NL80211_CMD_NEW_WIPHY had no NL80211_ATTR_WIPHY";
1200     return false;
1201   }
1202   return true;
1203 }
1204 
OnScanStarted(const NetlinkMessage & netlink_message)1205 void WiFi::OnScanStarted(const NetlinkMessage& netlink_message) {
1206   // We only handle scan triggers in this handler, which is are nl80211 messages
1207   // with the NL80211_CMD_TRIGGER_SCAN command.
1208   if (netlink_message.message_type() != Nl80211Message::GetMessageType()) {
1209     SLOG(this, 7) << __func__ << ": "
1210                   << "Not a NL80211 Message";
1211     return;
1212   }
1213   const Nl80211Message& scan_trigger_msg =
1214       *reinterpret_cast<const Nl80211Message*>(&netlink_message);
1215   if (scan_trigger_msg.command() != TriggerScanMessage::kCommand) {
1216     SLOG(this, 7) << __func__ << ": "
1217                   << "Not a NL80211_CMD_TRIGGER_SCAN message";
1218     return;
1219   }
1220   uint32_t wiphy_index;
1221   if (!scan_trigger_msg.const_attributes()->GetU32AttributeValue(
1222           NL80211_ATTR_WIPHY, &wiphy_index)) {
1223     LOG(ERROR) << "NL80211_CMD_TRIGGER_SCAN had no NL80211_ATTR_WIPHY";
1224     return;
1225   }
1226   if (wiphy_index != wiphy_index_) {
1227     SLOG(this, 7) << __func__ << ": "
1228                   << "Scan trigger not meant for this interface";
1229     return;
1230   }
1231   bool is_active_scan = false;
1232   AttributeListConstRefPtr ssids;
1233   if (scan_trigger_msg.const_attributes()->ConstGetNestedAttributeList(
1234           NL80211_ATTR_SCAN_SSIDS, &ssids)) {
1235     AttributeIdIterator ssid_iter(*ssids);
1236     // If any SSIDs (even the empty wild card) are reported, an active scan was
1237     // launched. Otherwise, a passive scan was launched.
1238     is_active_scan = !ssid_iter.AtEnd();
1239   }
1240   wake_on_wifi_->OnScanStarted(is_active_scan);
1241 }
1242 
BSSAddedTask(const string & path,const KeyValueStore & properties)1243 void WiFi::BSSAddedTask(const string& path, const KeyValueStore& properties) {
1244   // Note: we assume that BSSIDs are unique across endpoints. This
1245   // means that if an AP reuses the same BSSID for multiple SSIDs, we
1246   // lose.
1247   WiFiEndpointRefPtr endpoint(
1248       new WiFiEndpoint(control_interface(), this, path, properties));
1249   SLOG(this, 5) << "Found endpoint. "
1250                 << "RPC path: " << path << ", "
1251                 << LogSSID(endpoint->ssid_string()) << ", "
1252                 << "bssid: " << endpoint->bssid_string() << ", "
1253                 << "signal: " << endpoint->signal_strength() << ", "
1254                 << "security: " << endpoint->security_mode() << ", "
1255                 << "frequency: " << endpoint->frequency();
1256 
1257   if (endpoint->ssid_string().empty()) {
1258     // Don't bother trying to find or create a Service for an Endpoint
1259     // without an SSID. We wouldn't be able to connect to it anyway.
1260     return;
1261   }
1262 
1263   if (endpoint->ssid()[0] == 0) {
1264     // Assume that an SSID starting with nullptr is bogus/misconfigured,
1265     // and filter it out.
1266     return;
1267   }
1268 
1269   provider_->OnEndpointAdded(endpoint);
1270 
1271   // Do this last, to maintain the invariant that any Endpoint we
1272   // know about has a corresponding Service.
1273   //
1274   // TODO(quiche): Write test to verify correct behavior in the case
1275   // where we get multiple BSSAdded events for a single endpoint.
1276   // (Old Endpoint's refcount should fall to zero, and old Endpoint
1277   // should be destroyed.)
1278   endpoint_by_rpcid_[path] = endpoint;
1279   endpoint->Start();
1280 }
1281 
BSSRemovedTask(const string & path)1282 void WiFi::BSSRemovedTask(const string& path) {
1283   EndpointMap::iterator i = endpoint_by_rpcid_.find(path);
1284   if (i == endpoint_by_rpcid_.end()) {
1285     SLOG(this, 1) << "WiFi " << link_name()
1286                   << " could not find BSS " << path
1287                   << " to remove.";
1288     return;
1289   }
1290 
1291   WiFiEndpointRefPtr endpoint = i->second;
1292   CHECK(endpoint);
1293   endpoint_by_rpcid_.erase(i);
1294 
1295   WiFiServiceRefPtr service = provider_->OnEndpointRemoved(endpoint);
1296   if (!service) {
1297     return;
1298   }
1299   Error unused_error;
1300   RemoveNetworkForService(service.get(), &unused_error);
1301 
1302   bool disconnect_service = !service->HasEndpoints() &&
1303       (service->IsConnecting() || service->IsConnected());
1304 
1305   if (disconnect_service) {
1306     LOG(INFO) << "Disconnecting from service " << service->unique_name()
1307               << ": BSSRemoved";
1308     DisconnectFrom(service.get());
1309   }
1310 }
1311 
CertificationTask(const KeyValueStore & properties)1312 void WiFi::CertificationTask(const KeyValueStore& properties) {
1313   if (!current_service_) {
1314     LOG(ERROR) << "WiFi " << link_name() << " " << __func__
1315                << " with no current service.";
1316     return;
1317   }
1318 
1319   string subject;
1320   uint32_t depth;
1321   if (WPASupplicant::ExtractRemoteCertification(properties, &subject, &depth)) {
1322     current_service_->AddEAPCertification(subject, depth);
1323   }
1324 }
1325 
EAPEventTask(const string & status,const string & parameter)1326 void WiFi::EAPEventTask(const string& status, const string& parameter) {
1327   if (!current_service_) {
1328     LOG(ERROR) << "WiFi " << link_name() << " " << __func__
1329                << " with no current service.";
1330     return;
1331   }
1332   Service::ConnectFailure failure = Service::kFailureUnknown;
1333   eap_state_handler_->ParseStatus(status, parameter, &failure);
1334   if (failure == Service::kFailurePinMissing) {
1335     // wpa_supplicant can sometimes forget the PIN on disconnect from the AP.
1336     const string& pin = current_service_->eap()->pin();
1337     Error unused_error;
1338     string rpcid = FindNetworkRpcidForService(current_service_.get(),
1339                                               &unused_error);
1340     if (!pin.empty() && !rpcid.empty()) {
1341       // We have a PIN configured, so we can provide it back to wpa_supplicant.
1342       LOG(INFO) << "Re-supplying PIN parameter to wpa_supplicant.";
1343       supplicant_interface_proxy_->NetworkReply(
1344           rpcid, WPASupplicant::kEAPRequestedParameterPIN, pin);
1345       failure = Service::kFailureUnknown;
1346     }
1347   }
1348   if (failure != Service::kFailureUnknown) {
1349     // Avoid a reporting failure twice by resetting EAP state handler early.
1350     eap_state_handler_->Reset();
1351     Error unused_error;
1352     current_service_->DisconnectWithFailure(failure, &unused_error, __func__);
1353   }
1354 }
1355 
PropertiesChangedTask(const KeyValueStore & properties)1356 void WiFi::PropertiesChangedTask(
1357     const KeyValueStore& properties) {
1358   // TODO(quiche): Handle changes in other properties (e.g. signal
1359   // strength).
1360 
1361   // Note that order matters here. In particular, we want to process
1362   // changes in the current BSS before changes in state. This is so
1363   // that we update the state of the correct Endpoint/Service.
1364   if (properties.ContainsRpcIdentifier(
1365       WPASupplicant::kInterfacePropertyCurrentBSS)) {
1366     CurrentBSSChanged(
1367         properties.GetRpcIdentifier(
1368             WPASupplicant::kInterfacePropertyCurrentBSS));
1369   }
1370 
1371   if (properties.ContainsString(WPASupplicant::kInterfacePropertyState)) {
1372     StateChanged(properties.GetString(WPASupplicant::kInterfacePropertyState));
1373   }
1374 
1375   if (properties.ContainsInt(
1376       WPASupplicant::kInterfacePropertyDisconnectReason)) {
1377     DisconnectReasonChanged(
1378         properties.GetInt(WPASupplicant::kInterfacePropertyDisconnectReason));
1379   }
1380 }
1381 
ScanDoneTask()1382 void WiFi::ScanDoneTask() {
1383   SLOG(this, 2) << __func__ << " need_bss_flush_ " << need_bss_flush_;
1384   // Unsets this flag if it was set in InitiateScanInDarkResume since that scan
1385   // has completed.
1386   manager()->set_suppress_autoconnect(false);
1387   if (wake_on_wifi_->in_dark_resume()) {
1388     metrics()->NotifyDarkResumeScanResultsReceived();
1389   }
1390   if (scan_session_) {
1391     // Post |ProgressiveScanTask| so it runs after any pending scan results
1392     // have been processed.  This allows connections on new BSSes to be
1393     // started before we decide whether to abort the progressive scan or
1394     // continue scanning.
1395     dispatcher()->PostTask(
1396         Bind(&WiFi::ProgressiveScanTask, weak_ptr_factory_.GetWeakPtr()));
1397   } else {
1398     // Post |UpdateScanStateAfterScanDone| so it runs after any pending scan
1399     // results have been processed.  This allows connections on new BSSes to be
1400     // started before we decide whether the scan was fruitful.
1401     dispatcher()->PostTask(Bind(&WiFi::UpdateScanStateAfterScanDone,
1402                                 weak_ptr_factory_.GetWeakPtr()));
1403     if ((provider_->NumAutoConnectableServices() < 1) && IsIdle()) {
1404       // Ensure we are also idle in case we are in the midst of connecting to
1405       // the only service that was available for auto-connect on the previous
1406       // scan (which will cause it to show up as unavailable for auto-connect
1407       // when we query the WiFiProvider this time).
1408       wake_on_wifi_->OnNoAutoConnectableServicesAfterScan(
1409           provider_->GetSsidsConfiguredForAutoConnect(),
1410           Bind(&WiFi::RemoveSupplicantNetworks, weak_ptr_factory_.GetWeakPtr()),
1411           Bind(&WiFi::TriggerPassiveScan, weak_ptr_factory_.GetWeakPtr()));
1412     }
1413   }
1414   if (need_bss_flush_) {
1415     CHECK(supplicant_interface_proxy_);
1416     // Compute |max_age| relative to |resumed_at_|, to account for the
1417     // time taken to scan.
1418     struct timeval now;
1419     uint32_t max_age;
1420     time_->GetTimeMonotonic(&now);
1421     max_age = kMaxBSSResumeAgeSeconds + (now.tv_sec - resumed_at_.tv_sec);
1422     supplicant_interface_proxy_->FlushBSS(max_age);
1423     need_bss_flush_ = false;
1424   }
1425   StartScanTimer();
1426 }
1427 
ScanFailedTask()1428 void WiFi::ScanFailedTask() {
1429   SLOG(this, 2) << __func__;
1430   SetScanState(kScanIdle, kScanMethodNone, __func__);
1431 }
1432 
UpdateScanStateAfterScanDone()1433 void WiFi::UpdateScanStateAfterScanDone() {
1434   if (scan_method_ == kScanMethodFull) {
1435     // Only notify the Manager on completion of full scans, since the manager
1436     // will replace any cached geolocation info with the BSSes we have right
1437     // now.
1438     manager()->OnDeviceGeolocationInfoUpdated(this);
1439   }
1440   if (scan_state_ == kScanBackgroundScanning) {
1441     // Going directly to kScanIdle (instead of to kScanFoundNothing) inhibits
1442     // some UMA reporting in SetScanState.  That's desired -- we don't want
1443     // to report background scan results to UMA since the drivers may play
1444     // background scans over a longer period in order to not interfere with
1445     // traffic.
1446     SetScanState(kScanIdle, kScanMethodNone, __func__);
1447   } else if (scan_state_ != kScanIdle && IsIdle()) {
1448     SetScanState(kScanFoundNothing, scan_method_, __func__);
1449   }
1450 }
1451 
ScanTask()1452 void WiFi::ScanTask() {
1453   SLOG(this, 2) << "WiFi " << link_name() << " scan requested.";
1454   if (!enabled()) {
1455     SLOG(this, 2) << "Ignoring scan request while device is not enabled.";
1456     SetScanState(kScanIdle, kScanMethodNone, __func__);  // Probably redundant.
1457     return;
1458   }
1459   if (!supplicant_present_ || !supplicant_interface_proxy_.get()) {
1460     SLOG(this, 2) << "Ignoring scan request while supplicant is not present.";
1461     SetScanState(kScanIdle, kScanMethodNone, __func__);
1462     return;
1463   }
1464   if ((pending_service_.get() && pending_service_->IsConnecting()) ||
1465       (current_service_.get() && current_service_->IsConnecting())) {
1466     SLOG(this, 2) << "Ignoring scan request while connecting to an AP.";
1467     return;
1468   }
1469   KeyValueStore scan_args;
1470   scan_args.SetString(WPASupplicant::kPropertyScanType,
1471                       WPASupplicant::kScanTypeActive);
1472 
1473   ByteArrays hidden_ssids = provider_->GetHiddenSSIDList();
1474   if (!hidden_ssids.empty()) {
1475     // TODO(pstew): Devise a better method for time-sharing with SSIDs that do
1476     // not fit in.
1477     if (hidden_ssids.size() >= WPASupplicant::kScanMaxSSIDsPerScan) {
1478       hidden_ssids.erase(
1479           hidden_ssids.begin() + WPASupplicant::kScanMaxSSIDsPerScan - 1,
1480           hidden_ssids.end());
1481     }
1482     // Add Broadcast SSID, signified by an empty ByteArray.  If we specify
1483     // SSIDs to wpa_supplicant, we need to explicitly specify the default
1484     // behavior of doing a broadcast probe.
1485     hidden_ssids.push_back(ByteArray());
1486 
1487     scan_args.SetByteArrays(WPASupplicant::kPropertyScanSSIDs, hidden_ssids);
1488   }
1489 
1490   if (!supplicant_interface_proxy_->Scan(scan_args)) {
1491     // A scan may fail if, for example, the wpa_supplicant vanishing
1492     // notification is posted after this task has already started running.
1493     LOG(WARNING) << "Scan failed";
1494     return;
1495   }
1496 
1497   // Only set the scan state/method if we are starting a full scan from
1498   // scratch.  Keep the existing method if this is a failover from a
1499   // progressive scan.
1500   if (scan_state_ != kScanScanning) {
1501     SetScanState(IsIdle() ? kScanScanning : kScanBackgroundScanning,
1502                  kScanMethodFull, __func__);
1503   }
1504 }
1505 
ProgressiveScanTask()1506 void WiFi::ProgressiveScanTask() {
1507   SLOG(this, 2) << __func__ << " - scan requested for " << link_name();
1508   if (!enabled()) {
1509     LOG(INFO) << "Ignoring scan request while device is not enabled.";
1510     SetScanState(kScanIdle, kScanMethodNone, __func__);  // Probably redundant.
1511     return;
1512   }
1513   if (!scan_session_) {
1514     SLOG(this, 2) << "No scan session -- returning";
1515     SetScanState(kScanIdle, kScanMethodNone, __func__);
1516     return;
1517   }
1518   // TODO(wdg): We don't currently support progressive background scans.  If
1519   // we did, we couldn't bail out, here, if we're connected. Progressive scan
1520   // state will have to be modified to include whether there was a connection
1521   // when the scan started. Then, this code would only bail out if we didn't
1522   // start with a connection but one exists at this point.
1523   if (!IsIdle()) {
1524     SLOG(this, 2) << "Ignoring scan request while connecting to an AP.";
1525     scan_session_.reset();
1526     return;
1527   }
1528   if (scan_session_->HasMoreFrequencies()) {
1529     SLOG(this, 2) << "Initiating a scan -- returning";
1530     SetScanState(kScanScanning, kScanMethodProgressive, __func__);
1531     // After us initiating a scan, supplicant will gather the scan results and
1532     // send us zero or more |BSSAdded| events followed by a |ScanDone|.
1533     scan_session_->InitiateScan();
1534     return;
1535   }
1536   LOG(ERROR) << "A complete progressive scan turned-up nothing -- "
1537              << "do a regular scan";
1538   scan_session_.reset();
1539   SetScanState(kScanScanning, kScanMethodProgressiveFinishedToFull, __func__);
1540   LOG(INFO) << "Scan [full] on " << link_name()
1541             << " (connected to nothing on progressive scan) from " << __func__;
1542   ScanTask();
1543 }
1544 
SetSchedScanTask(bool enable)1545 void WiFi::SetSchedScanTask(bool enable) {
1546   if (!supplicant_present_ || !supplicant_interface_proxy_.get()) {
1547     SLOG(this, 2) << "Ignoring sched scan configure request "
1548                   << "while supplicant is not present.";
1549     return;
1550   }
1551   if (!supplicant_interface_proxy_->SetSchedScan(enable)) {
1552     LOG(WARNING) << "Failed to set SchedScan";
1553   }
1554 }
1555 
OnFailedProgressiveScan()1556 void WiFi::OnFailedProgressiveScan() {
1557   LOG(ERROR) << "Couldn't issue a scan on " << link_name()
1558              << " -- doing a regular scan";
1559   scan_session_.reset();
1560   SetScanState(kScanScanning, kScanMethodProgressiveErrorToFull, __func__);
1561   LOG(INFO) << "Scan [full] on " << link_name()
1562             << " (failover from progressive scan) from " << __func__;
1563   ScanTask();
1564 }
1565 
GetServiceLeaseName(const WiFiService & service)1566 string WiFi::GetServiceLeaseName(const WiFiService& service) {
1567   return service.GetStorageIdentifier();
1568 }
1569 
DestroyServiceLease(const WiFiService & service)1570 void WiFi::DestroyServiceLease(const WiFiService& service) {
1571   DestroyIPConfigLease(GetServiceLeaseName(service));
1572 }
1573 
StateChanged(const string & new_state)1574 void WiFi::StateChanged(const string& new_state) {
1575   const string old_state = supplicant_state_;
1576   supplicant_state_ = new_state;
1577   LOG(INFO) << "WiFi " << link_name() << " " << __func__ << " "
1578             << old_state << " -> " << new_state;
1579 
1580   if (new_state == WPASupplicant::kInterfaceStateCompleted ||
1581       new_state == WPASupplicant::kInterfaceState4WayHandshake) {
1582     mac80211_monitor_->UpdateConnectedState(true);
1583   } else {
1584     mac80211_monitor_->UpdateConnectedState(false);
1585   }
1586 
1587   if (old_state == WPASupplicant::kInterfaceStateDisconnected &&
1588       new_state != WPASupplicant::kInterfaceStateDisconnected) {
1589     // The state has been changed from disconnect to something else, clearing
1590     // out disconnect reason to avoid confusion about future disconnects.
1591     DisconnectReasonChanged(kDefaultDisconnectReason);
1592   }
1593 
1594   // Identify the service to which the state change applies. If
1595   // |pending_service_| is non-NULL, then the state change applies to
1596   // |pending_service_|. Otherwise, it applies to |current_service_|.
1597   //
1598   // This policy is driven by the fact that the |pending_service_|
1599   // doesn't become the |current_service_| until wpa_supplicant
1600   // reports a CurrentBSS change to the |pending_service_|. And the
1601   // CurrentBSS change won't be reported until the |pending_service_|
1602   // reaches the WPASupplicant::kInterfaceStateCompleted state.
1603   WiFiService* affected_service =
1604       pending_service_.get() ? pending_service_.get() : current_service_.get();
1605   if (!affected_service) {
1606     SLOG(this, 2) << "WiFi " << link_name() << " " << __func__
1607                   << " with no service";
1608     return;
1609   }
1610 
1611   if (new_state == WPASupplicant::kInterfaceStateCompleted) {
1612     if (affected_service->IsConnected()) {
1613       StopReconnectTimer();
1614       EnableHighBitrates();
1615       if (is_roaming_in_progress_) {
1616         // This means wpa_supplicant completed a roam without an intervening
1617         // disconnect.  We should renew our DHCP lease just in case the new
1618         // AP is on a different subnet than where we started.
1619         is_roaming_in_progress_ = false;
1620         const IPConfigRefPtr& ip_config = ipconfig();
1621         if (ip_config) {
1622           LOG(INFO) << link_name() << " renewing L3 configuration after roam.";
1623           ip_config->RenewIP();
1624         }
1625       }
1626     } else if (has_already_completed_) {
1627       LOG(INFO) << link_name() << " L3 configuration already started.";
1628     } else {
1629       provider_->IncrementConnectCount(affected_service->frequency());
1630       if (AcquireIPConfigWithLeaseName(
1631               GetServiceLeaseName(*affected_service))) {
1632         LOG(INFO) << link_name() << " is up; started L3 configuration.";
1633         affected_service->SetState(Service::kStateConfiguring);
1634         if (affected_service->IsSecurityMatch(kSecurityWep)) {
1635           // With the overwhelming majority of WEP networks, we cannot assume
1636           // our credentials are correct just because we have successfully
1637           // connected.  It is more useful to track received data as the L3
1638           // configuration proceeds to see if we can decrypt anything.
1639           receive_byte_count_at_connect_ = GetReceiveByteCount();
1640         } else {
1641           affected_service->ResetSuspectedCredentialFailures();
1642         }
1643       } else {
1644         LOG(ERROR) << "Unable to acquire DHCP config.";
1645       }
1646     }
1647     has_already_completed_ = true;
1648   } else if (new_state == WPASupplicant::kInterfaceStateAssociated) {
1649     affected_service->SetState(Service::kStateAssociating);
1650   } else if (new_state == WPASupplicant::kInterfaceStateAuthenticating ||
1651              new_state == WPASupplicant::kInterfaceStateAssociating ||
1652              new_state == WPASupplicant::kInterfaceState4WayHandshake ||
1653              new_state == WPASupplicant::kInterfaceStateGroupHandshake) {
1654     // Ignore transitions into these states from Completed, to avoid
1655     // bothering the user when roaming, or re-keying.
1656     if (old_state != WPASupplicant::kInterfaceStateCompleted)
1657       affected_service->SetState(Service::kStateAssociating);
1658     // TODO(quiche): On backwards transitions, we should probably set
1659     // a timeout for getting back into the completed state. At present,
1660     // we depend on wpa_supplicant eventually reporting that CurrentBSS
1661     // has changed. But there may be cases where that signal is not sent.
1662     // (crbug.com/206208)
1663   } else if (new_state == WPASupplicant::kInterfaceStateDisconnected &&
1664              affected_service == current_service_ &&
1665              affected_service->IsConnected()) {
1666     // This means that wpa_supplicant failed in a re-connect attempt, but
1667     // may still be reconnecting.  Give wpa_supplicant a limited amount of
1668     // time to transition out this condition by either connecting or changing
1669     // CurrentBSS.
1670     StartReconnectTimer();
1671   } else {
1672     // Other transitions do not affect Service state.
1673     //
1674     // Note in particular that we ignore a State change into
1675     // kInterfaceStateDisconnected, in favor of observing the corresponding
1676     // change in CurrentBSS.
1677   }
1678 }
1679 
SuspectCredentials(WiFiServiceRefPtr service,Service::ConnectFailure * failure) const1680 bool WiFi::SuspectCredentials(
1681     WiFiServiceRefPtr service, Service::ConnectFailure* failure) const {
1682   if (service->IsSecurityMatch(kSecurityPsk)) {
1683     if (supplicant_state_ == WPASupplicant::kInterfaceState4WayHandshake &&
1684         service->AddSuspectedCredentialFailure()) {
1685       if (failure) {
1686         *failure = Service::kFailureBadPassphrase;
1687       }
1688       return true;
1689     }
1690   } else if (service->IsSecurityMatch(kSecurity8021x)) {
1691     if (eap_state_handler_->is_eap_in_progress() &&
1692         service->AddSuspectedCredentialFailure()) {
1693       if (failure) {
1694         *failure = Service::kFailureEAPAuthentication;
1695       }
1696       return true;
1697     }
1698   }
1699 
1700   return false;
1701 }
1702 
1703 // static
SanitizeSSID(string * ssid)1704 bool WiFi::SanitizeSSID(string* ssid) {
1705   CHECK(ssid);
1706 
1707   size_t ssid_len = ssid->length();
1708   size_t i;
1709   bool changed = false;
1710 
1711   for (i = 0; i < ssid_len; ++i) {
1712     if (!IsPrintableAsciiChar((*ssid)[i])) {
1713       (*ssid)[i] = '?';
1714       changed = true;
1715     }
1716   }
1717 
1718   return changed;
1719 }
1720 
1721 // static
LogSSID(const string & ssid)1722 string WiFi::LogSSID(const string& ssid) {
1723   string out;
1724   for (const auto& chr : ssid) {
1725     // Replace '[' and ']' (in addition to non-printable characters) so that
1726     // it's easy to match the right substring through a non-greedy regex.
1727     if (chr == '[' || chr == ']' || !IsPrintableAsciiChar(chr)) {
1728       base::StringAppendF(&out, "\\x%02x", chr);
1729     } else {
1730       out += chr;
1731     }
1732   }
1733   return StringPrintf("[SSID=%s]", out.c_str());
1734 }
1735 
OnLinkMonitorFailure()1736 void WiFi::OnLinkMonitorFailure() {
1737   // Invoke base class call first to allow it to determine the reliability of
1738   // the link.
1739   Device::OnLinkMonitorFailure();
1740 
1741   // If we have never found the gateway, let's be conservative and not
1742   // do anything, in case this network topology does not have a gateway.
1743   if (!link_monitor()->IsGatewayFound()) {
1744     LOG(INFO) << "In " << __func__ << "(): "
1745               << "Skipping reassociate since gateway was never found.";
1746     return;
1747   }
1748 
1749   if (!supplicant_present_) {
1750     LOG(ERROR) << "In " << __func__ << "(): "
1751                << "wpa_supplicant is not present.  Cannot reassociate.";
1752     return;
1753   }
1754 
1755   // Skip reassociate attempt if service is not reliable, meaning multiple link
1756   // failures in short period of time.
1757   if (current_service_->unreliable()) {
1758     LOG(INFO) << "Current service is unreliable, skipping reassociate attempt.";
1759     return;
1760   }
1761 
1762   // This will force a transition out of connected, if we are actually
1763   // connected.
1764   if (!supplicant_interface_proxy_->Reattach()) {
1765     LOG(ERROR) << "In " << __func__ << "(): failed to call Reattach().";
1766     return;
1767   }
1768 
1769   // If we don't eventually get a transition back into a connected state,
1770   // there is something wrong.
1771   StartReconnectTimer();
1772   LOG(INFO) << "In " << __func__ << "(): Called Reattach().";
1773 }
1774 
OnUnreliableLink()1775 void WiFi::OnUnreliableLink() {
1776   Device::OnUnreliableLink();
1777 
1778   // Disable HT40 for the current network.
1779   SetHT40EnableForService(current_service_.get(), false);
1780 }
1781 
ShouldUseArpGateway() const1782 bool WiFi::ShouldUseArpGateway() const {
1783   return !IsUsingStaticIP();
1784 }
1785 
DisassociateFromService(const WiFiServiceRefPtr & service)1786 void WiFi::DisassociateFromService(const WiFiServiceRefPtr& service) {
1787   SLOG(this, 2) << "In " << __func__ << " for service: "
1788                 << service->unique_name();
1789   DisconnectFromIfActive(service.get());
1790   if (service == selected_service()) {
1791     DropConnection();
1792   }
1793   Error unused_error;
1794   RemoveNetworkForService(service.get(), &unused_error);
1795 }
1796 
GetGeolocationObjects() const1797 vector<GeolocationInfo> WiFi::GetGeolocationObjects() const {
1798   vector<GeolocationInfo> objects;
1799   for (const auto& endpoint_entry : endpoint_by_rpcid_) {
1800     GeolocationInfo geoinfo;
1801     const WiFiEndpointRefPtr& endpoint = endpoint_entry.second;
1802     geoinfo.AddField(kGeoMacAddressProperty, endpoint->bssid_string());
1803     geoinfo.AddField(kGeoSignalStrengthProperty,
1804                 StringPrintf("%d", endpoint->signal_strength()));
1805     geoinfo.AddField(
1806         kGeoChannelProperty,
1807         StringPrintf("%d",
1808                      Metrics::WiFiFrequencyToChannel(endpoint->frequency())));
1809     // TODO(gauravsh): Include age field. crbug.com/217554
1810     objects.push_back(geoinfo);
1811   }
1812   return objects;
1813 }
1814 
HelpRegisterDerivedInt32(PropertyStore * store,const string & name,int32_t (WiFi::* get)(Error * error),bool (WiFi::* set)(const int32_t & value,Error * error))1815 void WiFi::HelpRegisterDerivedInt32(
1816     PropertyStore* store,
1817     const string& name,
1818     int32_t(WiFi::*get)(Error* error),
1819     bool(WiFi::*set)(const int32_t& value, Error* error)) {
1820   store->RegisterDerivedInt32(
1821       name,
1822       Int32Accessor(new CustomAccessor<WiFi, int32_t>(this, get, set)));
1823 }
1824 
HelpRegisterDerivedUint16(PropertyStore * store,const string & name,uint16_t (WiFi::* get)(Error * error),bool (WiFi::* set)(const uint16_t & value,Error * error))1825 void WiFi::HelpRegisterDerivedUint16(
1826     PropertyStore* store,
1827     const string& name,
1828     uint16_t(WiFi::*get)(Error* error),
1829     bool(WiFi::*set)(const uint16_t& value, Error* error)) {
1830   store->RegisterDerivedUint16(
1831       name,
1832       Uint16Accessor(new CustomAccessor<WiFi, uint16_t>(this, get, set)));
1833 }
1834 
HelpRegisterConstDerivedBool(PropertyStore * store,const string & name,bool (WiFi::* get)(Error * error))1835 void WiFi::HelpRegisterConstDerivedBool(
1836     PropertyStore* store,
1837     const string& name,
1838     bool(WiFi::*get)(Error* error)) {
1839   store->RegisterDerivedBool(
1840       name,
1841       BoolAccessor(new CustomAccessor<WiFi, bool>(this, get, nullptr)));
1842 }
1843 
OnBeforeSuspend(const ResultCallback & callback)1844 void WiFi::OnBeforeSuspend(const ResultCallback& callback) {
1845   if (!enabled()) {
1846     callback.Run(Error(Error::kSuccess));
1847     return;
1848   }
1849   LOG(INFO) << __func__ << ": "
1850             << (IsConnectedToCurrentService() ? "connected" : "not connected");
1851   StopScanTimer();
1852   supplicant_process_proxy_->ExpectDisconnect();
1853   uint32_t time_to_next_lease_renewal;
1854   bool have_dhcp_lease =
1855       TimeToNextDHCPLeaseRenewal(&time_to_next_lease_renewal);
1856   wake_on_wifi_->OnBeforeSuspend(
1857       IsConnectedToCurrentService(),
1858       provider_->GetSsidsConfiguredForAutoConnect(),
1859       callback,
1860       Bind(&Device::RenewDHCPLease, weak_ptr_factory_.GetWeakPtr()),
1861       Bind(&WiFi::RemoveSupplicantNetworks, weak_ptr_factory_.GetWeakPtr()),
1862       have_dhcp_lease,
1863       time_to_next_lease_renewal);
1864 }
1865 
OnDarkResume(const ResultCallback & callback)1866 void WiFi::OnDarkResume(const ResultCallback& callback) {
1867   if (!enabled()) {
1868     callback.Run(Error(Error::kSuccess));
1869     return;
1870   }
1871   LOG(INFO) << __func__ << ": "
1872             << (IsConnectedToCurrentService() ? "connected" : "not connected");
1873   StopScanTimer();
1874   wake_on_wifi_->OnDarkResume(
1875       IsConnectedToCurrentService(),
1876       provider_->GetSsidsConfiguredForAutoConnect(),
1877       callback,
1878       Bind(&Device::RenewDHCPLease, weak_ptr_factory_.GetWeakPtr()),
1879       Bind(&WiFi::InitiateScanInDarkResume, weak_ptr_factory_.GetWeakPtr()),
1880       Bind(&WiFi::RemoveSupplicantNetworks, weak_ptr_factory_.GetWeakPtr()));
1881 }
1882 
OnAfterResume()1883 void WiFi::OnAfterResume() {
1884   LOG(INFO) << __func__ << ": "
1885             << (IsConnectedToCurrentService() ? "connected" : "not connected");
1886   Device::OnAfterResume();  // May refresh ipconfig_
1887   dispatcher()->PostDelayedTask(Bind(&WiFi::ReportConnectedToServiceAfterWake,
1888                                      weak_ptr_factory_.GetWeakPtr()),
1889                                 kPostWakeConnectivityReportDelayMilliseconds);
1890   wake_on_wifi_->OnAfterResume();
1891 
1892   // We want to flush the BSS cache, but we don't want to conflict
1893   // with an active connection attempt. So record the need to flush,
1894   // and take care of flushing when the next scan completes.
1895   //
1896   // Note that supplicant will automatically expire old cache
1897   // entries (after, e.g., a BSS is not found in two consecutive
1898   // scans). However, our explicit flush accelerates re-association
1899   // in cases where a BSS disappeared while we were asleep. (See,
1900   // e.g. WiFiRoaming.005SuspendRoam.)
1901   time_->GetTimeMonotonic(&resumed_at_);
1902   need_bss_flush_ = true;
1903 
1904   if (!IsConnectedToCurrentService()) {
1905     InitiateScan(kProgressiveScan);
1906   }
1907 
1908   // Since we stopped the scan timer before suspending, start it again here.
1909   StartScanTimer();
1910 
1911   // Enable HT40 for current service in case if it was disabled previously due
1912   // to unreliable link.
1913   if (current_service_) {
1914     SetHT40EnableForService(current_service_.get(), true);
1915   }
1916 }
1917 
AbortScan()1918 void WiFi::AbortScan() {
1919   if (scan_session_) {
1920     scan_session_.reset();
1921   }
1922   SetScanState(kScanIdle, kScanMethodNone, __func__);
1923 }
1924 
InitiateScan(ScanType scan_type)1925 void WiFi::InitiateScan(ScanType scan_type) {
1926   LOG(INFO) << __func__;
1927   // Abort any current scan (at the shill-level; let any request that's
1928   // already gone out finish) since we don't know when it started.
1929   AbortScan();
1930 
1931   if (IsIdle()) {
1932     // Not scanning/connecting/connected, so let's get things rolling.
1933     Scan(scan_type, nullptr, __func__);
1934     RestartFastScanAttempts();
1935   } else {
1936     SLOG(this, 1) << __func__
1937                   << " skipping scan, already connecting or connected.";
1938   }
1939 }
1940 
InitiateScanInDarkResume(const FreqSet & freqs)1941 void WiFi::InitiateScanInDarkResume(const FreqSet& freqs) {
1942   LOG(INFO) << __func__;
1943   AbortScan();
1944   if (!IsIdle()) {
1945     SLOG(this, 1) << __func__
1946                   << " skipping scan, already connecting or connected.";
1947     return;
1948   }
1949 
1950   CHECK(supplicant_interface_proxy_);
1951   // Force complete flush of BSS cache since we want WPA supplicant and shill to
1952   // have an accurate view of what endpoints are available in dark resume. This
1953   // prevents either from performing incorrect actions that can prolong dark
1954   // resume (e.g. attempting to auto-connect to a WiFi service whose endpoint
1955   // disappeared before the dark resume).
1956   if (!supplicant_interface_proxy_->FlushBSS(0)) {
1957     LOG(WARNING) << __func__
1958                  << ": Failed to flush wpa_supplicant BSS cache";
1959   }
1960   // Suppress any autoconnect attempts until this scan is done and endpoints
1961   // are updated.
1962   manager()->set_suppress_autoconnect(true);
1963 
1964   TriggerPassiveScan(freqs);
1965 }
1966 
TriggerPassiveScan(const FreqSet & freqs)1967 void WiFi::TriggerPassiveScan(const FreqSet& freqs) {
1968   LOG(INFO) << __func__;
1969   TriggerScanMessage trigger_scan;
1970   trigger_scan.attributes()->SetU32AttributeValue(NL80211_ATTR_IFINDEX,
1971                                                   interface_index());
1972   if (!freqs.empty()) {
1973     SLOG(this, 3) << __func__ << ": " << "Scanning on specific channels";
1974     trigger_scan.attributes()->CreateNl80211Attribute(
1975         NL80211_ATTR_SCAN_FREQUENCIES, NetlinkMessage::MessageContext());
1976 
1977     AttributeListRefPtr frequency_list;
1978     if (!trigger_scan.attributes()->GetNestedAttributeList(
1979             NL80211_ATTR_SCAN_FREQUENCIES, &frequency_list) ||
1980         !frequency_list) {
1981       LOG(ERROR) << __func__ << ": "
1982                  << "Couldn't get NL80211_ATTR_SCAN_FREQUENCIES";
1983     }
1984     trigger_scan.attributes()->SetNestedAttributeHasAValue(
1985         NL80211_ATTR_SCAN_FREQUENCIES);
1986 
1987     string attribute_name;
1988     int i = 0;
1989     for (uint32_t freq : freqs) {
1990       SLOG(this, 7) << __func__ << ": "
1991                     << "Frequency-" << i << ": " << freq;
1992       attribute_name = StringPrintf("Frequency-%d", i);
1993       frequency_list->CreateU32Attribute(i, attribute_name.c_str());
1994       frequency_list->SetU32AttributeValue(i, freq);
1995       ++i;
1996     }
1997   }
1998 
1999   netlink_manager_->SendNl80211Message(
2000       &trigger_scan,
2001       Bind(&WiFi::OnTriggerPassiveScanResponse, weak_ptr_factory_.GetWeakPtr()),
2002       Bind(&NetlinkManager::OnAckDoNothing),
2003       Bind(&NetlinkManager::OnNetlinkMessageError));
2004 }
2005 
OnConnected()2006 void WiFi::OnConnected() {
2007   Device::OnConnected();
2008   EnableHighBitrates();
2009   if (current_service_ &&
2010       current_service_->IsSecurityMatch(kSecurityWep)) {
2011     // With a WEP network, we are now reasonably certain the credentials are
2012     // correct, whereas with other network types we were able to determine
2013     // this earlier when the association process succeeded.
2014     current_service_->ResetSuspectedCredentialFailures();
2015   }
2016   RequestStationInfo();
2017 }
2018 
OnIPConfigFailure()2019 void WiFi::OnIPConfigFailure() {
2020   if (!current_service_) {
2021     LOG(ERROR) << "WiFi " << link_name() << " " << __func__
2022                << " with no current service.";
2023     return;
2024   }
2025   if (current_service_->IsSecurityMatch(kSecurityWep) &&
2026       GetReceiveByteCount() == receive_byte_count_at_connect_ &&
2027       current_service_->AddSuspectedCredentialFailure()) {
2028     // If we've connected to a WEP network and haven't successfully
2029     // decrypted any bytes at all during the configuration process,
2030     // it is fair to suspect that our credentials to this network
2031     // may not be correct.
2032     Error error;
2033     current_service_->DisconnectWithFailure(Service::kFailureBadPassphrase,
2034                                             &error,
2035                                             __func__);
2036     return;
2037   }
2038 
2039   Device::OnIPConfigFailure();
2040 }
2041 
AddWakeOnPacketConnection(const string & ip_endpoint,Error * error)2042 void WiFi::AddWakeOnPacketConnection(const string& ip_endpoint, Error* error) {
2043   wake_on_wifi_->AddWakeOnPacketConnection(ip_endpoint, error);
2044 }
2045 
RemoveWakeOnPacketConnection(const string & ip_endpoint,Error * error)2046 void WiFi::RemoveWakeOnPacketConnection(const string& ip_endpoint,
2047                                         Error* error) {
2048   wake_on_wifi_->RemoveWakeOnPacketConnection(ip_endpoint, error);
2049 }
2050 
RemoveAllWakeOnPacketConnections(Error * error)2051 void WiFi::RemoveAllWakeOnPacketConnections(Error* error) {
2052   wake_on_wifi_->RemoveAllWakeOnPacketConnections(error);
2053 }
2054 
RestartFastScanAttempts()2055 void WiFi::RestartFastScanAttempts() {
2056   fast_scans_remaining_ = kNumFastScanAttempts;
2057   StartScanTimer();
2058 }
2059 
StartScanTimer()2060 void WiFi::StartScanTimer() {
2061   SLOG(this, 2) << __func__;
2062   if (scan_interval_seconds_ == 0) {
2063     StopScanTimer();
2064     return;
2065   }
2066   scan_timer_callback_.Reset(
2067       Bind(&WiFi::ScanTimerHandler, weak_ptr_factory_.GetWeakPtr()));
2068   // Repeat the first few scans after disconnect relatively quickly so we
2069   // have reasonable trust that no APs we are looking for are present.
2070   size_t wait_time_milliseconds = fast_scans_remaining_ > 0 ?
2071       kFastScanIntervalSeconds * 1000 : scan_interval_seconds_ * 1000;
2072   dispatcher()->PostDelayedTask(scan_timer_callback_.callback(),
2073                                 wait_time_milliseconds);
2074   SLOG(this, 5) << "Next scan scheduled for " << wait_time_milliseconds << "ms";
2075 }
2076 
StopScanTimer()2077 void WiFi::StopScanTimer() {
2078   SLOG(this, 2) << __func__;
2079   scan_timer_callback_.Cancel();
2080 }
2081 
ScanTimerHandler()2082 void WiFi::ScanTimerHandler() {
2083   SLOG(this, 2) << "WiFi Device " << link_name() << ": " << __func__;
2084   if (manager()->IsSuspending()) {
2085     SLOG(this, 5) << "Not scanning: still in suspend";
2086     return;
2087   }
2088   if (scan_state_ == kScanIdle && IsIdle()) {
2089     Scan(kProgressiveScan, nullptr, __func__);
2090     if (fast_scans_remaining_ > 0) {
2091       --fast_scans_remaining_;
2092     }
2093   } else {
2094     if (scan_state_ != kScanIdle) {
2095       SLOG(this, 5) << "Skipping scan: scan_state_ is " << scan_state_;
2096     }
2097     if (current_service_) {
2098       SLOG(this, 5) << "Skipping scan: current_service_ is service "
2099                     << current_service_->unique_name();
2100     }
2101     if (pending_service_) {
2102       SLOG(this, 5) << "Skipping scan: pending_service_ is service"
2103                     << pending_service_->unique_name();
2104     }
2105   }
2106   StartScanTimer();
2107 }
2108 
StartPendingTimer()2109 void WiFi::StartPendingTimer() {
2110   pending_timeout_callback_.Reset(
2111       Bind(&WiFi::PendingTimeoutHandler, weak_ptr_factory_.GetWeakPtr()));
2112   dispatcher()->PostDelayedTask(pending_timeout_callback_.callback(),
2113                                 kPendingTimeoutSeconds * 1000);
2114 }
2115 
StopPendingTimer()2116 void WiFi::StopPendingTimer() {
2117   SLOG(this, 2) << "WiFi Device " << link_name() << ": " << __func__;
2118   pending_timeout_callback_.Cancel();
2119 }
2120 
SetPendingService(const WiFiServiceRefPtr & service)2121 void WiFi::SetPendingService(const WiFiServiceRefPtr& service) {
2122   SLOG(this, 2) << "WiFi " << link_name() << " setting pending service to "
2123                 << (service ? service->unique_name(): "NULL");
2124   if (service) {
2125     SetScanState(kScanConnecting, scan_method_, __func__);
2126     service->SetState(Service::kStateAssociating);
2127     StartPendingTimer();
2128   } else {
2129     // SetPendingService(nullptr) is called in the following cases:
2130     //  a) |ConnectTo|->|DisconnectFrom|.  Connecting to a service, disconnect
2131     //     the old service (scan_state_ == kScanTransitionToConnecting).  No
2132     //     state transition is needed here.
2133     //  b) |HandleRoam|.  Connected to a service, it's no longer pending
2134     //     (scan_state_ == kScanIdle).  No state transition is needed here.
2135     //  c) |DisconnectFrom| and |HandleDisconnect|. Disconnected/disconnecting
2136     //     from a service not during a scan (scan_state_ == kScanIdle).  No
2137     //     state transition is needed here.
2138     //  d) |DisconnectFrom| and |HandleDisconnect|. Disconnected/disconnecting
2139     //     from a service during a scan (scan_state_ == kScanScanning or
2140     //     kScanConnecting).  This is an odd case -- let's discard any
2141     //     statistics we're gathering by transitioning directly into kScanIdle.
2142     if (scan_state_ == kScanScanning ||
2143         scan_state_ == kScanBackgroundScanning ||
2144         scan_state_ == kScanConnecting) {
2145       SetScanState(kScanIdle, kScanMethodNone, __func__);
2146     }
2147     if (pending_service_) {
2148       StopPendingTimer();
2149     }
2150   }
2151   pending_service_ = service;
2152 }
2153 
PendingTimeoutHandler()2154 void WiFi::PendingTimeoutHandler() {
2155   Error unused_error;
2156   LOG(INFO) << "WiFi Device " << link_name() << ": " << __func__;
2157   CHECK(pending_service_);
2158   SetScanState(kScanFoundNothing, scan_method_, __func__);
2159   WiFiServiceRefPtr pending_service = pending_service_;
2160   pending_service_->DisconnectWithFailure(
2161       Service::kFailureOutOfRange, &unused_error, __func__);
2162 
2163   // A hidden service may have no endpoints, since wpa_supplicant
2164   // failed to attain a CurrentBSS.  If so, the service has no
2165   // reference to |this| device and cannot call WiFi::DisconnectFrom()
2166   // to reset pending_service_.  In this case, we must perform the
2167   // disconnect here ourselves.
2168   if (pending_service_) {
2169     CHECK(!pending_service_->HasEndpoints());
2170     LOG(INFO) << "Hidden service was not found.";
2171     DisconnectFrom(pending_service_.get());
2172   }
2173 
2174   // DisconnectWithFailure will leave the pending service's state in failure
2175   // state. Reset its state back to idle, to allow it to be connectable again.
2176   pending_service->SetState(Service::kStateIdle);
2177 }
2178 
StartReconnectTimer()2179 void WiFi::StartReconnectTimer() {
2180   if (!reconnect_timeout_callback_.IsCancelled()) {
2181     LOG(INFO) << "WiFi Device " << link_name() << ": " << __func__
2182               << ": reconnect timer already running.";
2183     return;
2184   }
2185   LOG(INFO) << "WiFi Device " << link_name() << ": " << __func__;
2186   reconnect_timeout_callback_.Reset(
2187       Bind(&WiFi::ReconnectTimeoutHandler, weak_ptr_factory_.GetWeakPtr()));
2188   dispatcher()->PostDelayedTask(reconnect_timeout_callback_.callback(),
2189                                 kReconnectTimeoutSeconds * 1000);
2190 }
2191 
StopReconnectTimer()2192 void WiFi::StopReconnectTimer() {
2193   SLOG(this, 2) << "WiFi Device " << link_name() << ": " << __func__;
2194   reconnect_timeout_callback_.Cancel();
2195 }
2196 
ReconnectTimeoutHandler()2197 void WiFi::ReconnectTimeoutHandler() {
2198   LOG(INFO) << "WiFi Device " << link_name() << ": " << __func__;
2199   reconnect_timeout_callback_.Cancel();
2200   CHECK(current_service_);
2201   current_service_->SetFailure(Service::kFailureConnect);
2202   DisconnectFrom(current_service_.get());
2203 }
2204 
OnSupplicantAppear()2205 void WiFi::OnSupplicantAppear() {
2206   LOG(INFO) << "WPA supplicant appeared.";
2207   if (supplicant_present_) {
2208     // Restart the WiFi device if it's started already. This will reset the
2209     // state and connect the device to the new WPA supplicant instance.
2210     if (enabled()) {
2211       Restart();
2212     }
2213     return;
2214   }
2215   supplicant_present_ = true;
2216   ConnectToSupplicant();
2217 }
2218 
OnSupplicantVanish()2219 void WiFi::OnSupplicantVanish() {
2220   LOG(INFO) << "WPA supplicant vanished.";
2221   if (!supplicant_present_) {
2222     return;
2223   }
2224   supplicant_present_ = false;
2225   // Restart the WiFi device if it's started already. This will effectively
2226   // suspend the device until the WPA supplicant reappears.
2227   if (enabled()) {
2228     Restart();
2229   }
2230 }
2231 
OnWiFiDebugScopeChanged(bool enabled)2232 void WiFi::OnWiFiDebugScopeChanged(bool enabled) {
2233   SLOG(this, 2) << "WiFi debug scope changed; enable is now " << enabled;
2234   if (!Device::enabled() || !supplicant_present_) {
2235     SLOG(this, 2) << "Supplicant process proxy not connected.";
2236     return;
2237   }
2238   string current_level;
2239   if (!supplicant_process_proxy_->GetDebugLevel(&current_level)) {
2240     LOG(ERROR) << __func__ << ": Failed to get wpa_supplicant debug level.";
2241     return;
2242   }
2243 
2244   if (current_level != WPASupplicant::kDebugLevelInfo &&
2245       current_level != WPASupplicant::kDebugLevelDebug) {
2246     SLOG(this, 2) << "WiFi debug level is currently "
2247                   << current_level
2248                   << "; assuming that it is being controlled elsewhere.";
2249     return;
2250   }
2251   string new_level = enabled ? WPASupplicant::kDebugLevelDebug :
2252       WPASupplicant::kDebugLevelInfo;
2253 
2254   if (new_level == current_level) {
2255     SLOG(this, 2) << "WiFi debug level is already the desired level "
2256                   << current_level;
2257     return;
2258   }
2259 
2260   if (!supplicant_process_proxy_->SetDebugLevel(new_level)) {
2261     LOG(ERROR) << __func__ << ": Failed to set wpa_supplicant debug level.";
2262   }
2263 }
2264 
SetConnectionDebugging(bool enabled)2265 void WiFi::SetConnectionDebugging(bool enabled) {
2266   if (is_debugging_connection_ == enabled) {
2267     return;
2268   }
2269   OnWiFiDebugScopeChanged(
2270       enabled ||
2271       ScopeLogger::GetInstance()->IsScopeEnabled(ScopeLogger::kWiFi));
2272   is_debugging_connection_ = enabled;
2273 }
2274 
SetSupplicantInterfaceProxy(SupplicantInterfaceProxyInterface * supplicant_interface_proxy)2275 void WiFi::SetSupplicantInterfaceProxy(
2276     SupplicantInterfaceProxyInterface* supplicant_interface_proxy) {
2277   if (supplicant_interface_proxy) {
2278     supplicant_interface_proxy_.reset(supplicant_interface_proxy);
2279     tdls_manager_.reset(new TDLSManager(dispatcher(),
2280                                         supplicant_interface_proxy,
2281                                         link_name()));
2282   } else {
2283     supplicant_interface_proxy_.reset();
2284     tdls_manager_.reset();
2285   }
2286 }
2287 
ConnectToSupplicant()2288 void WiFi::ConnectToSupplicant() {
2289   LOG(INFO) << link_name() << ": " << (enabled() ? "enabled" : "disabled")
2290             << " supplicant: "
2291             << (supplicant_present_ ? "present" : "absent")
2292             << " proxy: "
2293             << (supplicant_interface_proxy_.get() ? "non-null" : "null");
2294   // The check for |supplicant_interface_proxy_| is mainly for testing,
2295   // to avoid recreation of supplicant interface proxy.
2296   if (!enabled() || !supplicant_present_ || supplicant_interface_proxy_) {
2297     return;
2298   }
2299   OnWiFiDebugScopeChanged(
2300       ScopeLogger::GetInstance()->IsScopeEnabled(ScopeLogger::kWiFi));
2301 
2302   KeyValueStore create_interface_args;
2303   create_interface_args.SetString(WPASupplicant::kInterfacePropertyName,
2304                                   link_name());
2305   create_interface_args.SetString(WPASupplicant::kInterfacePropertyDriver,
2306                                   WPASupplicant::kDriverNL80211);
2307   create_interface_args.SetString(WPASupplicant::kInterfacePropertyConfigFile,
2308                                   WPASupplicant::kSupplicantConfPath);
2309   if (!supplicant_process_proxy_->CreateInterface(
2310       create_interface_args, &supplicant_interface_path_)) {
2311     // Interface might've already been created, attempt to retrieve it.
2312     if (!supplicant_process_proxy_->GetInterface(link_name(),
2313                                                  &supplicant_interface_path_)) {
2314       // TODO(quiche): Is it okay to crash here, if device is missing?
2315       LOG(ERROR) << __func__ << ": Failed to create interface with supplicant.";
2316       return;
2317     }
2318   }
2319 
2320   SetSupplicantInterfaceProxy(
2321       control_interface()->CreateSupplicantInterfaceProxy(
2322           this, supplicant_interface_path_));
2323 
2324   RTNLHandler::GetInstance()->SetInterfaceFlags(interface_index(), IFF_UP,
2325                                                 IFF_UP);
2326   // TODO(quiche) Set ApScan=1 and BSSExpireAge=190, like flimflam does?
2327 
2328   // Clear out any networks that might previously have been configured
2329   // for this interface.
2330   supplicant_interface_proxy_->RemoveAllNetworks();
2331 
2332   // Flush interface's BSS cache, so that we get BSSAdded signals for
2333   // all BSSes (not just new ones since the last scan).
2334   supplicant_interface_proxy_->FlushBSS(0);
2335 
2336   // TODO(pstew): Disable fast_reauth until supplicant can properly deal
2337   // with RADIUS servers that respond strangely to such requests.
2338   // crbug.com/208561
2339   if (!supplicant_interface_proxy_->SetFastReauth(false)) {
2340     LOG(ERROR) << "Failed to disable fast_reauth. "
2341                << "May be running an older version of wpa_supplicant.";
2342   }
2343 
2344   if (!supplicant_interface_proxy_->SetRoamThreshold(roam_threshold_db_)) {
2345     LOG(ERROR) << "Failed to set roam_threshold. "
2346                << "May be running an older version of wpa_supplicant.";
2347   }
2348 
2349   // Helps with passing WiFiRoaming.001SSIDSwitchBack.
2350   if (!supplicant_interface_proxy_->SetScanInterval(kRescanIntervalSeconds)) {
2351     LOG(ERROR) << "Failed to set scan_interval. "
2352                << "May be running an older version of wpa_supplicant.";
2353   }
2354 
2355   if (!supplicant_interface_proxy_->SetDisableHighBitrates(true)) {
2356     LOG(ERROR) << "Failed to disable high bitrates. "
2357                << "May be running an older version of wpa_supplicant.";
2358   }
2359 
2360   Scan(kProgressiveScan, nullptr, __func__);
2361   StartScanTimer();
2362 }
2363 
EnableHighBitrates()2364 void WiFi::EnableHighBitrates() {
2365   LOG(INFO) << "Enabling high bitrates.";
2366   if (!supplicant_interface_proxy_->EnableHighBitrates()) {
2367     LOG(ERROR) << "Failed to enable high rates";
2368   }
2369 }
2370 
Restart()2371 void WiFi::Restart() {
2372   LOG(INFO) << link_name() << " restarting.";
2373   WiFiRefPtr me = this;  // Make sure we don't get destructed.
2374   // Go through the manager rather than starting and stopping the device
2375   // directly so that the device can be configured with the profile.
2376   manager()->DeregisterDevice(me);
2377   manager()->RegisterDevice(me);
2378 }
2379 
GetPhyInfo()2380 void WiFi::GetPhyInfo() {
2381   GetWiphyMessage get_wiphy;
2382   get_wiphy.attributes()->SetU32AttributeValue(NL80211_ATTR_IFINDEX,
2383                                                interface_index());
2384   netlink_manager_->SendNl80211Message(
2385       &get_wiphy,
2386       Bind(&WiFi::OnNewWiphy, weak_ptr_factory_.GetWeakPtr()),
2387       Bind(&NetlinkManager::OnAckDoNothing),
2388       Bind(&NetlinkManager::OnNetlinkMessageError));
2389 }
2390 
OnNewWiphy(const Nl80211Message & nl80211_message)2391 void WiFi::OnNewWiphy(const Nl80211Message& nl80211_message) {
2392   // Verify NL80211_CMD_NEW_WIPHY.
2393   if (nl80211_message.command() != NewWiphyMessage::kCommand) {
2394     LOG(ERROR) << "Received unexpected command:"
2395                << nl80211_message.command();
2396     return;
2397   }
2398 
2399   if (!nl80211_message.const_attributes()->GetStringAttributeValue(
2400           NL80211_ATTR_WIPHY_NAME, &phy_name_)) {
2401     LOG(ERROR) << "NL80211_CMD_NEW_WIPHY had no NL80211_ATTR_WIPHY_NAME";
2402     return;
2403   }
2404   mac80211_monitor_->Start(phy_name_);
2405 
2406   wake_on_wifi_->ParseWakeOnWiFiCapabilities(nl80211_message);
2407   if (ParseWiphyIndex(nl80211_message)) {
2408     wake_on_wifi_->OnWiphyIndexReceived(wiphy_index_);
2409   }
2410 
2411   // The attributes, for this message, are complicated.
2412   // NL80211_ATTR_BANDS contains an array of bands...
2413   AttributeListConstRefPtr wiphy_bands;
2414   if (!nl80211_message.const_attributes()->ConstGetNestedAttributeList(
2415       NL80211_ATTR_WIPHY_BANDS, &wiphy_bands)) {
2416     LOG(ERROR) << "NL80211_CMD_NEW_WIPHY had no NL80211_ATTR_WIPHY_BANDS";
2417     return;
2418   }
2419 
2420   AttributeIdIterator band_iter(*wiphy_bands);
2421   for (; !band_iter.AtEnd(); band_iter.Advance()) {
2422     AttributeListConstRefPtr wiphy_band;
2423     if (!wiphy_bands->ConstGetNestedAttributeList(band_iter.GetId(),
2424                                                   &wiphy_band)) {
2425       LOG(WARNING) << "WiFi band " << band_iter.GetId() << " not found";
2426       continue;
2427     }
2428 
2429     // ...Each band has a FREQS attribute...
2430     AttributeListConstRefPtr frequencies;
2431     if (!wiphy_band->ConstGetNestedAttributeList(NL80211_BAND_ATTR_FREQS,
2432                                                  &frequencies)) {
2433       LOG(ERROR) << "BAND " << band_iter.GetId()
2434                  << " had no 'frequencies' attribute";
2435       continue;
2436     }
2437 
2438     // ...And each FREQS attribute contains an array of information about the
2439     // frequency...
2440     AttributeIdIterator freq_iter(*frequencies);
2441     for (; !freq_iter.AtEnd(); freq_iter.Advance()) {
2442       AttributeListConstRefPtr frequency;
2443       if (frequencies->ConstGetNestedAttributeList(freq_iter.GetId(),
2444                                                    &frequency)) {
2445         // ...Including the frequency, itself (the part we want).
2446         uint32_t frequency_value = 0;
2447         if (frequency->GetU32AttributeValue(NL80211_FREQUENCY_ATTR_FREQ,
2448                                             &frequency_value)) {
2449           SLOG(this, 7) << "Found frequency[" << freq_iter.GetId()
2450                         << "] = " << frequency_value;
2451           all_scan_frequencies_.insert(frequency_value);
2452         }
2453       }
2454     }
2455   }
2456 }
2457 
OnTriggerPassiveScanResponse(const Nl80211Message & netlink_message)2458 void WiFi::OnTriggerPassiveScanResponse(const Nl80211Message& netlink_message) {
2459   LOG(WARNING) << "Didn't expect _this_netlink message ("
2460                << netlink_message.command() << " here:";
2461   netlink_message.Print(0, 0);
2462   return;
2463 }
2464 
GetLinkStatistics(Error *)2465 KeyValueStore WiFi::GetLinkStatistics(Error* /*error*/) {
2466   return link_statistics_;
2467 }
2468 
GetScanPending(Error *)2469 bool WiFi::GetScanPending(Error* /* error */) {
2470   return scan_state_ == kScanScanning || scan_state_ == kScanBackgroundScanning;
2471 }
2472 
SetScanState(ScanState new_state,ScanMethod new_method,const char * reason)2473 void WiFi::SetScanState(ScanState new_state,
2474                         ScanMethod new_method,
2475                         const char* reason) {
2476   if (new_state == kScanIdle)
2477     new_method = kScanMethodNone;
2478   if (new_state == kScanConnected) {
2479     // The scan method shouldn't be changed by the connection process, so
2480     // we'll put a CHECK, here, to verify.  NOTE: this assumption is also
2481     // enforced by the parameters to the call to |ReportScanResultToUma|.
2482     CHECK(new_method == scan_method_);
2483   }
2484 
2485   int log_level = 6;
2486   bool state_or_method_changed = true;
2487   bool is_terminal_state = false;
2488   if (new_state == scan_state_ && new_method == scan_method_) {
2489     log_level = 7;
2490     state_or_method_changed = false;
2491   } else if (new_state == kScanConnected || new_state == kScanFoundNothing) {
2492     // These 'terminal' states are slightly more interesting than the
2493     // intermediate states.
2494     // NOTE: Since background scan goes directly to kScanIdle (skipping over
2495     // the states required to set |is_terminal_state|), ReportScanResultToUma,
2496     // below, doesn't get called.  That's intentional.
2497     log_level = 5;
2498     is_terminal_state = true;
2499   }
2500 
2501   base::TimeDelta elapsed_time;
2502   if (new_state == kScanScanning || new_state == kScanBackgroundScanning) {
2503     if (!scan_timer_.Start()) {
2504       LOG(ERROR) << "Scan start unreliable";
2505     }
2506   } else {
2507     if (!scan_timer_.GetElapsedTime(&elapsed_time)) {
2508       LOG(ERROR) << "Scan time unreliable";
2509     }
2510   }
2511   SLOG(this, log_level) << (reason ? reason : "<unknown>")
2512                         << " - " << link_name()
2513                         << ": Scan state: "
2514                         << ScanStateString(scan_state_, scan_method_)
2515                         << " -> " << ScanStateString(new_state, new_method)
2516                         << " @ " << elapsed_time.InMillisecondsF()
2517                         << " ms into scan.";
2518   if (!state_or_method_changed)
2519     return;
2520 
2521   // Actually change the state.
2522   ScanState old_state = scan_state_;
2523   ScanMethod old_method = scan_method_;
2524   bool old_scan_pending = GetScanPending(nullptr);
2525   scan_state_ = new_state;
2526   scan_method_ = new_method;
2527   bool new_scan_pending = GetScanPending(nullptr);
2528   if (old_scan_pending != new_scan_pending) {
2529     adaptor()->EmitBoolChanged(kScanningProperty, new_scan_pending);
2530   }
2531   switch (new_state) {
2532     case kScanIdle:
2533       metrics()->ResetScanTimer(interface_index());
2534       metrics()->ResetConnectTimer(interface_index());
2535       if (scan_session_) {
2536         scan_session_.reset();
2537       }
2538       break;
2539     case kScanScanning:  // FALLTHROUGH
2540     case kScanBackgroundScanning:
2541       if (new_state != old_state) {
2542         metrics()->NotifyDeviceScanStarted(interface_index());
2543       }
2544       break;
2545     case kScanConnecting:
2546       metrics()->NotifyDeviceScanFinished(interface_index());
2547       // TODO(wdg): Provide |is_auto_connecting| to this interface.  For now,
2548       // I'll lie (because I don't care about the auto-connect metrics).
2549       metrics()->NotifyDeviceConnectStarted(interface_index(), false);
2550       break;
2551     case kScanConnected:
2552       metrics()->NotifyDeviceConnectFinished(interface_index());
2553       break;
2554     case kScanFoundNothing:
2555       // Note that finishing a scan that hasn't started (if, for example, we
2556       // get here when we fail to complete a connection) does nothing.
2557       metrics()->NotifyDeviceScanFinished(interface_index());
2558       metrics()->ResetConnectTimer(interface_index());
2559       break;
2560     case kScanTransitionToConnecting:  // FALLTHROUGH
2561     default:
2562       break;
2563   }
2564   if (is_terminal_state) {
2565     ReportScanResultToUma(new_state, old_method);
2566     // Now that we've logged a terminal state, let's call ourselves to
2567     // transition to the idle state.
2568     SetScanState(kScanIdle, kScanMethodNone, reason);
2569   }
2570 }
2571 
2572 // static
ScanStateString(ScanState state,ScanMethod method)2573 string WiFi::ScanStateString(ScanState state, ScanMethod method) {
2574   switch (state) {
2575     case kScanIdle:
2576       return "IDLE";
2577     case kScanScanning:
2578       DCHECK(method != kScanMethodNone) << "Scanning with no scan method.";
2579       switch (method) {
2580         case kScanMethodFull:
2581           return "FULL_START";
2582         case kScanMethodProgressive:
2583           return "PROGRESSIVE_START";
2584         case kScanMethodProgressiveErrorToFull:
2585           return "PROGRESSIVE_ERROR_FULL_START";
2586         case kScanMethodProgressiveFinishedToFull:
2587           return "PROGRESSIVE_FINISHED_FULL_START";
2588         default:
2589           NOTREACHED();
2590       }
2591     case kScanBackgroundScanning:
2592       return "BACKGROUND_START";
2593     case kScanTransitionToConnecting:
2594       return "TRANSITION_TO_CONNECTING";
2595     case kScanConnecting:
2596       switch (method) {
2597         case kScanMethodNone:
2598           return "CONNECTING (not scan related)";
2599         case kScanMethodFull:
2600           return "FULL_CONNECTING";
2601         case kScanMethodProgressive:
2602           return "PROGRESSIVE_CONNECTING";
2603         case kScanMethodProgressiveErrorToFull:
2604           return "PROGRESSIVE_ERROR_FULL_CONNECTING";
2605         case kScanMethodProgressiveFinishedToFull:
2606           return "PROGRESSIVE_FINISHED_FULL_CONNECTING";
2607         default:
2608           NOTREACHED();
2609       }
2610     case kScanConnected:
2611       switch (method) {
2612         case kScanMethodNone:
2613           return "CONNECTED (not scan related; e.g., from a supplicant roam)";
2614         case kScanMethodFull:
2615           return "FULL_CONNECTED";
2616         case kScanMethodProgressive:
2617           return "PROGRESSIVE_CONNECTED";
2618         case kScanMethodProgressiveErrorToFull:
2619           return "PROGRESSIVE_ERROR_FULL_CONNECTED";
2620         case kScanMethodProgressiveFinishedToFull:
2621           return "PROGRESSIVE_FINISHED_FULL_CONNECTED";
2622         default:
2623           NOTREACHED();
2624       }
2625     case kScanFoundNothing:
2626       switch (method) {
2627         case kScanMethodNone:
2628           return "CONNECT FAILED (not scan related)";
2629         case kScanMethodFull:
2630           return "FULL_NOCONNECTION";
2631         case kScanMethodProgressive:
2632           // This is possible if shill started to connect but timed out before
2633           // the connection was completed.
2634           return "PROGRESSIVE_FINISHED_NOCONNECTION";
2635         case kScanMethodProgressiveErrorToFull:
2636           return "PROGRESSIVE_ERROR_FULL_NOCONNECTION";
2637         case kScanMethodProgressiveFinishedToFull:
2638           return "PROGRESSIVE_FINISHED_FULL_NOCONNECTION";
2639         default:
2640           NOTREACHED();
2641       }
2642     default:
2643       NOTREACHED();
2644   }
2645   return "";  // To shut up the compiler (that doesn't understand NOTREACHED).
2646 }
2647 
ReportScanResultToUma(ScanState state,ScanMethod method)2648 void WiFi::ReportScanResultToUma(ScanState state, ScanMethod method) {
2649   Metrics::WiFiScanResult result = Metrics::kScanResultMax;
2650   if (state == kScanConnected) {
2651     switch (method) {
2652       case kScanMethodFull:
2653         result = Metrics::kScanResultFullScanConnected;
2654         break;
2655       case kScanMethodProgressive:
2656         result = Metrics::kScanResultProgressiveConnected;
2657         break;
2658       case kScanMethodProgressiveErrorToFull:
2659         result = Metrics::kScanResultProgressiveErrorButFullConnected;
2660         break;
2661       case kScanMethodProgressiveFinishedToFull:
2662         result = Metrics::kScanResultProgressiveAndFullConnected;
2663         break;
2664       default:
2665         // OK: Connect resulting from something other than scan.
2666         break;
2667     }
2668   } else if (state == kScanFoundNothing) {
2669     switch (method) {
2670       case kScanMethodFull:
2671         result = Metrics::kScanResultFullScanFoundNothing;
2672         break;
2673       case kScanMethodProgressiveErrorToFull:
2674         result = Metrics::kScanResultProgressiveErrorAndFullFoundNothing;
2675         break;
2676       case kScanMethodProgressiveFinishedToFull:
2677         result = Metrics::kScanResultProgressiveAndFullFoundNothing;
2678         break;
2679       default:
2680         // OK: Connect failed, not scan related.
2681         break;
2682     }
2683   }
2684 
2685   if (result != Metrics::kScanResultMax) {
2686     metrics()->SendEnumToUMA(Metrics::kMetricScanResult,
2687                              result,
2688                              Metrics::kScanResultMax);
2689   }
2690 }
2691 
RequestStationInfo()2692 void WiFi::RequestStationInfo() {
2693   if (!IsConnectedToCurrentService()) {
2694     LOG(ERROR) << "Not collecting station info because we are not connected.";
2695     return;
2696   }
2697 
2698   EndpointMap::iterator endpoint_it = endpoint_by_rpcid_.find(supplicant_bss_);
2699   if (endpoint_it == endpoint_by_rpcid_.end()) {
2700     LOG(ERROR) << "Can't get endpoint for current supplicant BSS "
2701                << supplicant_bss_;
2702     return;
2703   }
2704 
2705   GetStationMessage get_station;
2706   if (!get_station.attributes()->SetU32AttributeValue(NL80211_ATTR_IFINDEX,
2707                                                       interface_index())) {
2708     LOG(ERROR) << "Could not add IFINDEX attribute for GetStation message.";
2709     return;
2710   }
2711 
2712   const WiFiEndpointConstRefPtr endpoint(endpoint_it->second);
2713   if (!get_station.attributes()->SetRawAttributeValue(
2714           NL80211_ATTR_MAC,
2715           ByteString::CreateFromHexString(endpoint->bssid_hex()))) {
2716     LOG(ERROR) << "Could not add MAC attribute for GetStation message.";
2717     return;
2718   }
2719 
2720   netlink_manager_->SendNl80211Message(
2721       &get_station,
2722       Bind(&WiFi::OnReceivedStationInfo, weak_ptr_factory_.GetWeakPtr()),
2723       Bind(&NetlinkManager::OnAckDoNothing),
2724       Bind(&NetlinkManager::OnNetlinkMessageError));
2725 
2726   request_station_info_callback_.Reset(
2727       Bind(&WiFi::RequestStationInfo, weak_ptr_factory_.GetWeakPtr()));
2728   dispatcher()->PostDelayedTask(request_station_info_callback_.callback(),
2729                                 kRequestStationInfoPeriodSeconds * 1000);
2730 }
2731 
OnReceivedStationInfo(const Nl80211Message & nl80211_message)2732 void WiFi::OnReceivedStationInfo(const Nl80211Message& nl80211_message) {
2733   // Verify NL80211_CMD_NEW_STATION
2734   if (nl80211_message.command() != NewStationMessage::kCommand) {
2735     LOG(ERROR) << "Received unexpected command:"
2736                << nl80211_message.command();
2737     return;
2738   }
2739 
2740   if (!IsConnectedToCurrentService()) {
2741     LOG(ERROR) << "Not accepting station info because we are not connected.";
2742     return;
2743   }
2744 
2745   EndpointMap::iterator endpoint_it = endpoint_by_rpcid_.find(supplicant_bss_);
2746   if (endpoint_it == endpoint_by_rpcid_.end()) {
2747     LOG(ERROR) << "Can't get endpoint for current supplicant BSS."
2748                << supplicant_bss_;
2749     return;
2750   }
2751 
2752   ByteString station_bssid;
2753   if (!nl80211_message.const_attributes()->GetRawAttributeValue(
2754           NL80211_ATTR_MAC, &station_bssid)) {
2755     LOG(ERROR) << "Unable to get MAC attribute from received station info.";
2756     return;
2757   }
2758 
2759   WiFiEndpointRefPtr endpoint(endpoint_it->second);
2760 
2761   if (!station_bssid.Equals(
2762           ByteString::CreateFromHexString(endpoint->bssid_hex()))) {
2763     LOG(ERROR) << "Received station info for a non-current BSS.";
2764     return;
2765   }
2766 
2767   AttributeListConstRefPtr station_info;
2768   if (!nl80211_message.const_attributes()->ConstGetNestedAttributeList(
2769       NL80211_ATTR_STA_INFO, &station_info)) {
2770     LOG(ERROR) << "Received station info had no NL80211_ATTR_STA_INFO.";
2771     return;
2772   }
2773 
2774   uint8_t signal;
2775   if (!station_info->GetU8AttributeValue(NL80211_STA_INFO_SIGNAL, &signal)) {
2776     LOG(ERROR) << "Received station info had no NL80211_STA_INFO_SIGNAL.";
2777     return;
2778   }
2779 
2780   endpoint->UpdateSignalStrength(static_cast<signed char>(signal));
2781 
2782   link_statistics_.Clear();
2783 
2784   map<int, string> u32_property_map = {
2785       { NL80211_STA_INFO_INACTIVE_TIME, kInactiveTimeMillisecondsProperty },
2786       { NL80211_STA_INFO_RX_PACKETS, kPacketReceiveSuccessesProperty },
2787       { NL80211_STA_INFO_TX_FAILED, kPacketTransmitFailuresProperty },
2788       { NL80211_STA_INFO_TX_PACKETS, kPacketTransmitSuccessesProperty },
2789       { NL80211_STA_INFO_TX_RETRIES, kTransmitRetriesProperty }
2790   };
2791 
2792   for (const auto& kv : u32_property_map) {
2793     uint32_t value;
2794     if (station_info->GetU32AttributeValue(kv.first, &value)) {
2795       link_statistics_.SetUint(kv.second, value);
2796     }
2797   }
2798 
2799   map<int, string> s8_property_map = {
2800       { NL80211_STA_INFO_SIGNAL, kLastReceiveSignalDbmProperty },
2801       { NL80211_STA_INFO_SIGNAL_AVG, kAverageReceiveSignalDbmProperty }
2802   };
2803 
2804   for (const auto& kv : s8_property_map) {
2805     uint8_t value;
2806     if (station_info->GetU8AttributeValue(kv.first, &value)) {
2807       // Despite these values being reported as a U8 by the kernel, these
2808       // should be interpreted as signed char.
2809       link_statistics_.SetInt(kv.second, static_cast<signed char>(value));
2810     }
2811   }
2812 
2813   AttributeListConstRefPtr transmit_info;
2814   if (station_info->ConstGetNestedAttributeList(
2815       NL80211_STA_INFO_TX_BITRATE, &transmit_info)) {
2816     uint32_t rate = 0;  // In 100Kbps.
2817     uint16_t u16_rate = 0;  // In 100Kbps.
2818     uint8_t mcs = 0;
2819     uint8_t nss = 0;
2820     bool band_flag = false;
2821     bool is_short_gi = false;
2822     string mcs_info;
2823     string nss_info;
2824     string band_info;
2825 
2826     if (transmit_info->GetU16AttributeValue(
2827         NL80211_RATE_INFO_BITRATE, &u16_rate)) {
2828       rate = static_cast<uint32_t>(u16_rate);
2829     } else {
2830       transmit_info->GetU32AttributeValue(NL80211_RATE_INFO_BITRATE32, &rate);
2831     }
2832 
2833     if (transmit_info->GetU8AttributeValue(NL80211_RATE_INFO_MCS, &mcs)) {
2834       mcs_info = StringPrintf(" MCS %d", mcs);
2835     } else if (transmit_info->GetU8AttributeValue(
2836         NL80211_RATE_INFO_VHT_MCS, &mcs)) {
2837       mcs_info = StringPrintf(" VHT-MCS %d", mcs);
2838     }
2839 
2840     if (transmit_info->GetU8AttributeValue(NL80211_RATE_INFO_VHT_NSS, &nss)) {
2841       nss_info = StringPrintf(" VHT-NSS %d", nss);
2842     }
2843 
2844     if (transmit_info->GetFlagAttributeValue(NL80211_RATE_INFO_40_MHZ_WIDTH,
2845                                              &band_flag) && band_flag) {
2846       band_info = StringPrintf(" 40MHz");
2847     } else if (transmit_info->GetFlagAttributeValue(
2848         NL80211_RATE_INFO_80_MHZ_WIDTH, &band_flag) && band_flag) {
2849       band_info = StringPrintf(" 80MHz");
2850     } else if (transmit_info->GetFlagAttributeValue(
2851         NL80211_RATE_INFO_80P80_MHZ_WIDTH, &band_flag) && band_flag) {
2852       band_info = StringPrintf(" 80+80MHz");
2853     } else if (transmit_info->GetFlagAttributeValue(
2854         NL80211_RATE_INFO_160_MHZ_WIDTH, &band_flag) && band_flag) {
2855       band_info = StringPrintf(" 160MHz");
2856     }
2857 
2858     transmit_info->GetFlagAttributeValue(NL80211_RATE_INFO_SHORT_GI,
2859                                          &is_short_gi);
2860     if (rate) {
2861       link_statistics_.SetString(kTransmitBitrateProperty,
2862                                  StringPrintf("%d.%d MBit/s%s%s%s%s",
2863                                               rate / 10, rate % 10,
2864                                               mcs_info.c_str(),
2865                                               band_info.c_str(),
2866                                               is_short_gi ? " short GI" : "",
2867                                               nss_info.c_str()));
2868       metrics()->NotifyWifiTxBitrate(rate/10);
2869     }
2870   }
2871 }
2872 
StopRequestingStationInfo()2873 void WiFi::StopRequestingStationInfo() {
2874   SLOG(this, 2) << "WiFi Device " << link_name() << ": " << __func__;
2875   request_station_info_callback_.Cancel();
2876   link_statistics_.Clear();
2877 }
2878 
TDLSDiscoverResponse(const string & peer_address)2879 void WiFi::TDLSDiscoverResponse(const string& peer_address) {
2880   LOG(INFO) << __func__ << " TDLS discover response from " << peer_address;
2881 
2882   if (!tdls_manager_) {
2883     LOG(ERROR) << "TDLS manager not setup - not connected to supplicant";
2884     return;
2885   }
2886   tdls_manager_->OnDiscoverResponseReceived(peer_address);
2887 }
2888 
PerformTDLSOperation(const string & operation,const string & peer,Error * error)2889 string WiFi::PerformTDLSOperation(const string& operation,
2890                                   const string& peer,
2891                                   Error* error) {
2892   SLOG(this, 2) << "TDLS command received: " << operation
2893                 << " for peer " << peer;
2894   if (!tdls_manager_) {
2895     LOG(ERROR) << "TDLS manager not setup - not connected to supplicant";
2896     return "";
2897   }
2898 
2899   string peer_mac_address;
2900   if (!ResolvePeerMacAddress(peer, &peer_mac_address, error)) {
2901     return "";
2902   }
2903 
2904   return tdls_manager_->PerformOperation(peer_mac_address, operation, error);
2905 }
2906 
2907 // Traffic monitor is enabled for wifi.
IsTrafficMonitorEnabled() const2908 bool WiFi::IsTrafficMonitorEnabled() const {
2909   return true;
2910 }
2911 
RemoveSupplicantNetworks()2912 void WiFi::RemoveSupplicantNetworks() {
2913   for (const auto& map_entry : rpcid_by_service_) {
2914     RemoveNetwork(map_entry.second);
2915   }
2916   rpcid_by_service_.clear();
2917 }
2918 
OnIPConfigUpdated(const IPConfigRefPtr & ipconfig,bool new_lease_acquired)2919 void WiFi::OnIPConfigUpdated(const IPConfigRefPtr& ipconfig,
2920                              bool new_lease_acquired) {
2921   Device::OnIPConfigUpdated(ipconfig, new_lease_acquired);
2922   if (new_lease_acquired) {
2923     SLOG(this, 3) << __func__ << ": "
2924                   << "IPv4 DHCP lease obtained";
2925     uint32_t time_to_next_lease_renewal;
2926     bool have_dhcp_lease =
2927         TimeToNextDHCPLeaseRenewal(&time_to_next_lease_renewal);
2928     wake_on_wifi_->OnConnectedAndReachable(have_dhcp_lease,
2929                                            time_to_next_lease_renewal);
2930   } else {
2931     SLOG(this, 3) << __func__ << ": "
2932                   << "Gateway ARP received";
2933     // Do nothing since we are waiting until the DHCP lease is actually
2934     // obtained.
2935     return;
2936   }
2937 }
2938 
OnIPv6ConfigUpdated()2939 void WiFi::OnIPv6ConfigUpdated() {
2940   Device::OnIPv6ConfigUpdated();
2941   if (!IsConnectedToCurrentService()) {
2942     return;
2943   }
2944   SLOG(this, 3) << __func__ << ": "
2945                 << "IPv6 configuration obtained";
2946   uint32_t time_to_next_lease_renewal;
2947   bool have_dhcp_lease =
2948       TimeToNextDHCPLeaseRenewal(&time_to_next_lease_renewal);
2949   wake_on_wifi_->OnConnectedAndReachable(have_dhcp_lease,
2950                                          time_to_next_lease_renewal);
2951 }
2952 
IsConnectedToCurrentService()2953 bool WiFi::IsConnectedToCurrentService() {
2954   return (current_service_ && current_service_->IsConnected());
2955 }
2956 
ReportConnectedToServiceAfterWake()2957 void WiFi::ReportConnectedToServiceAfterWake() {
2958   wake_on_wifi_->ReportConnectedToServiceAfterWake(
2959       IsConnectedToCurrentService());
2960 }
2961 
RequestRoam(const std::string & addr,Error * error)2962 bool WiFi::RequestRoam(const std::string& addr, Error* error) {
2963   if (!supplicant_interface_proxy_->Roam(addr)) {
2964     LOG(WARNING) << "Request roam to " << addr << " failed.";
2965     return false;
2966   }
2967   return true;
2968 }
2969 
2970 }  // namespace shill
2971