Home | History | Annotate | Download | only in wifi
      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;
     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 {
    122 bool IsPrintableAsciiChar(char c) {
    123   return (c >= ' ' && c <= '~');
    124 }
    125 }  // namespace
    126 
    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 
    240 WiFi::~WiFi() {}
    241 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    401 void WiFi::Certification(const KeyValueStore& properties) {
    402   dispatcher()->PostTask(Bind(&WiFi::CertificationTask,
    403                               weak_ptr_factory_.GetWeakPtr(), properties));
    404 }
    405 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    639 bool WiFi::RemoveNetwork(const string& network) {
    640   return supplicant_interface_proxy_->RemoveNetwork(network);
    641 }
    642 
    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 
    662 bool WiFi::IsIdle() const {
    663   return !current_service_ && !pending_service_;
    664 }
    665 
    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 
    682 void WiFi::NotifyEndpointChanged(const WiFiEndpointConstRefPtr& endpoint) {
    683   provider_->OnEndpointUpdated(endpoint);
    684 }
    685 
    686 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 
    718 string WiFi::GetBgscanMethod(const int& /*argument*/, Error* /* error */) {
    719   return bgscan_method_.empty() ? kDefaultBgscanMethod : bgscan_method_;
    720 }
    721 
    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 
    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 
    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 
    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 
    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 
    789 void WiFi::ClearBgscanMethod(const int& /*argument*/, Error* /*error*/) {
    790   bgscan_method_.clear();
    791 }
    792 
    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 
    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 
    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 
    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.
    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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   1428 void WiFi::ScanFailedTask() {
   1429   SLOG(this, 2) << __func__;
   1430   SetScanState(kScanIdle, kScanMethodNone, __func__);
   1431 }
   1432 
   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 
   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 
   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 
   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 
   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 
   1566 string WiFi::GetServiceLeaseName(const WiFiService& service) {
   1567   return service.GetStorageIdentifier();
   1568 }
   1569 
   1570 void WiFi::DestroyServiceLease(const WiFiService& service) {
   1571   DestroyIPConfigLease(GetServiceLeaseName(service));
   1572 }
   1573 
   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 
   1680 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
   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
   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 
   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 
   1775 void WiFi::OnUnreliableLink() {
   1776   Device::OnUnreliableLink();
   1777 
   1778   // Disable HT40 for the current network.
   1779   SetHT40EnableForService(current_service_.get(), false);
   1780 }
   1781 
   1782 bool WiFi::ShouldUseArpGateway() const {
   1783   return !IsUsingStaticIP();
   1784 }
   1785 
   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 
   1797 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 
   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 
   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 
   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 
   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 
   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 
   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 
   1918 void WiFi::AbortScan() {
   1919   if (scan_session_) {
   1920     scan_session_.reset();
   1921   }
   1922   SetScanState(kScanIdle, kScanMethodNone, __func__);
   1923 }
   1924 
   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 
   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 
   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 
   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 
   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 
   2042 void WiFi::AddWakeOnPacketConnection(const string& ip_endpoint, Error* error) {
   2043   wake_on_wifi_->AddWakeOnPacketConnection(ip_endpoint, error);
   2044 }
   2045 
   2046 void WiFi::RemoveWakeOnPacketConnection(const string& ip_endpoint,
   2047                                         Error* error) {
   2048   wake_on_wifi_->RemoveWakeOnPacketConnection(ip_endpoint, error);
   2049 }
   2050 
   2051 void WiFi::RemoveAllWakeOnPacketConnections(Error* error) {
   2052   wake_on_wifi_->RemoveAllWakeOnPacketConnections(error);
   2053 }
   2054 
   2055 void WiFi::RestartFastScanAttempts() {
   2056   fast_scans_remaining_ = kNumFastScanAttempts;
   2057   StartScanTimer();
   2058 }
   2059 
   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 
   2077 void WiFi::StopScanTimer() {
   2078   SLOG(this, 2) << __func__;
   2079   scan_timer_callback_.Cancel();
   2080 }
   2081 
   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 
   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 
   2116 void WiFi::StopPendingTimer() {
   2117   SLOG(this, 2) << "WiFi Device " << link_name() << ": " << __func__;
   2118   pending_timeout_callback_.Cancel();
   2119 }
   2120 
   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 
   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 
   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 
   2192 void WiFi::StopReconnectTimer() {
   2193   SLOG(this, 2) << "WiFi Device " << link_name() << ": " << __func__;
   2194   reconnect_timeout_callback_.Cancel();
   2195 }
   2196 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   2465 KeyValueStore WiFi::GetLinkStatistics(Error* /*error*/) {
   2466   return link_statistics_;
   2467 }
   2468 
   2469 bool WiFi::GetScanPending(Error* /* error */) {
   2470   return scan_state_ == kScanScanning || scan_state_ == kScanBackgroundScanning;
   2471 }
   2472 
   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
   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 
   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 
   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 
   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 
   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 
   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 
   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.
   2908 bool WiFi::IsTrafficMonitorEnabled() const {
   2909   return true;
   2910 }
   2911 
   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 
   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 
   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 
   2953 bool WiFi::IsConnectedToCurrentService() {
   2954   return (current_service_ && current_service_->IsConnected());
   2955 }
   2956 
   2957 void WiFi::ReportConnectedToServiceAfterWake() {
   2958   wake_on_wifi_->ReportConnectedToServiceAfterWake(
   2959       IsConnectedToCurrentService());
   2960 }
   2961 
   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