blob: 2bb13595ffc7046028c5f4f4bba1861d3a3e4aac [file] [log] [blame]
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Paul Stewartb50f0b92011-05-16 16:31:42 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Chris Masone2b105542011-06-22 10:58:09 -07005#include "shill/wifi.h"
6
Wade Guthrie92d06362013-04-25 15:41:30 -07007#include <linux/if.h> // Needs definitions from netinet/ether.h
8#include <netinet/ether.h>
Paul Stewartb50f0b92011-05-16 16:31:42 -07009#include <stdio.h>
mukesh agrawalc7426a42011-06-03 13:04:28 -070010#include <string.h>
Paul Stewartb50f0b92011-05-16 16:31:42 -070011
mukesh agrawal8a3188d2011-12-01 20:56:44 +000012#include <algorithm>
Wade Guthrie5a4e2ef2013-04-30 12:51:39 -070013#include <limits>
mukesh agrawalab87ea42011-05-18 11:44:49 -070014#include <map>
Paul Stewartb50f0b92011-05-16 16:31:42 -070015#include <string>
mukesh agrawalab87ea42011-05-18 11:44:49 -070016#include <vector>
Paul Stewartb50f0b92011-05-16 16:31:42 -070017
Eric Shienbrood3e20a232012-02-16 11:35:56 -050018#include <base/bind.h>
Wade Guthrie5a4e2ef2013-04-30 12:51:39 -070019#include <base/file_path.h>
20#include <base/file_util.h>
mukesh agrawal7a4e4002011-09-06 11:26:05 -070021#include <base/string_util.h>
Wade Guthrie5a4e2ef2013-04-30 12:51:39 -070022#include <base/stringprintf.h>
Chris Masoneb925cc82011-06-22 15:39:57 -070023#include <chromeos/dbus/service_constants.h>
mukesh agrawal16bc1b82012-02-09 18:38:26 -080024#include <glib.h>
Paul Stewartb50f0b92011-05-16 16:31:42 -070025
26#include "shill/control_interface.h"
Paul Stewartced6a0b2011-11-08 15:32:04 -080027#include "shill/dbus_adaptor.h"
Paul Stewartb50f0b92011-05-16 16:31:42 -070028#include "shill/device.h"
mukesh agrawal7a4e4002011-09-06 11:26:05 -070029#include "shill/error.h"
Gaurav Shah6d2c72d2012-10-16 16:30:44 -070030#include "shill/geolocation_info.h"
mukesh agrawal7a4e4002011-09-06 11:26:05 -070031#include "shill/ieee80211.h"
Paul Stewart3c508e12012-08-09 11:40:06 -070032#include "shill/link_monitor.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070033#include "shill/logging.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070034#include "shill/manager.h"
Thieu Le67370f62012-02-14 23:01:42 +000035#include "shill/metrics.h"
Wade Guthriebb9fca22013-04-10 17:21:42 -070036#include "shill/netlink_manager.h"
Wade Guthrie7347bf22013-04-30 11:21:51 -070037#include "shill/netlink_message.h"
Wade Guthriebee87c22013-03-06 11:00:46 -080038#include "shill/nl80211_message.h"
mukesh agrawal4d0401c2012-01-06 16:05:31 -080039#include "shill/property_accessor.h"
Darin Petkovd1967262011-07-18 14:55:18 -070040#include "shill/proxy_factory.h"
Eric Shienbrood9a245532012-03-07 14:20:39 -050041#include "shill/rtnl_handler.h"
Wade Guthrie5a4e2ef2013-04-30 12:51:39 -070042#include "shill/scan_session.h"
Paul Stewart5581d072012-12-17 17:30:20 -080043#include "shill/scope_logger.h"
mukesh agrawal5c05b292012-03-07 10:12:52 -080044#include "shill/shill_time.h"
Paul Stewart735eab52013-03-29 09:19:23 -070045#include "shill/supplicant_eap_state_handler.h"
mukesh agrawalaf571952011-07-14 14:31:12 -070046#include "shill/supplicant_interface_proxy_interface.h"
Paul Stewart835934a2012-12-06 19:27:09 -080047#include "shill/supplicant_network_proxy_interface.h"
mukesh agrawalaf571952011-07-14 14:31:12 -070048#include "shill/supplicant_process_proxy_interface.h"
Gaurav Shah435de2c2011-11-17 19:01:07 -080049#include "shill/technology.h"
mukesh agrawalb54601c2011-06-07 17:39:22 -070050#include "shill/wifi_endpoint.h"
Paul Stewart3c504012013-01-17 17:49:58 -080051#include "shill/wifi_provider.h"
mukesh agrawalb54601c2011-06-07 17:39:22 -070052#include "shill/wifi_service.h"
mukesh agrawal6e277772011-09-29 15:04:23 -070053#include "shill/wpa_supplicant.h"
Paul Stewartb50f0b92011-05-16 16:31:42 -070054
Eric Shienbrood3e20a232012-02-16 11:35:56 -050055using base::Bind;
mukesh agrawal15908392011-11-16 18:29:25 +000056using base::StringPrintf;
Wade Guthrie5a4e2ef2013-04-30 12:51:39 -070057using file_util::PathExists;
mukesh agrawal7a4e4002011-09-06 11:26:05 -070058using std::map;
mukesh agrawalab87ea42011-05-18 11:44:49 -070059using std::string;
mukesh agrawal7a4e4002011-09-06 11:26:05 -070060using std::vector;
mukesh agrawalab87ea42011-05-18 11:44:49 -070061
Paul Stewartb50f0b92011-05-16 16:31:42 -070062namespace shill {
mukesh agrawal7a4e4002011-09-06 11:26:05 -070063
64// statics
mukesh agrawal4d0401c2012-01-06 16:05:31 -080065const char *WiFi::kDefaultBgscanMethod =
Paul Stewart0654ece2013-03-26 15:21:26 -070066 WPASupplicant::kNetworkBgscanMethodSimple;
mukesh agrawal4d0401c2012-01-06 16:05:31 -080067const uint16 WiFi::kDefaultBgscanShortIntervalSeconds = 30;
68const int32 WiFi::kDefaultBgscanSignalThresholdDbm = -50;
69const uint16 WiFi::kDefaultScanIntervalSeconds = 180;
Darin Petkov4a66cc52012-06-15 10:08:29 +020070// Scan interval while connected.
71const uint16 WiFi::kBackgroundScanIntervalSeconds = 3601;
mukesh agrawal5c05b292012-03-07 10:12:52 -080072// Age (in seconds) beyond which a BSS cache entry will not be preserved,
73// across a suspend/resume.
74const time_t WiFi::kMaxBSSResumeAgeSeconds = 10;
mukesh agrawal7ec71312011-11-10 02:08:26 +000075const char WiFi::kInterfaceStateUnknown[] = "shill-unknown";
mukesh agrawalf2028172012-03-13 14:20:22 -070076const time_t WiFi::kRescanIntervalSeconds = 1;
Paul Stewarte369ece2012-05-22 09:11:03 -070077const int WiFi::kNumFastScanAttempts = 3;
78const int WiFi::kFastScanIntervalSeconds = 10;
Paul Stewart2b05e622012-07-13 20:38:44 -070079const int WiFi::kPendingTimeoutSeconds = 15;
Paul Stewart44663922012-07-30 11:03:03 -070080const int WiFi::kReconnectTimeoutSeconds = 10;
Wade Guthrie5a4e2ef2013-04-30 12:51:39 -070081const size_t WiFi::kMinumumFrequenciesToScan = 4; // Arbitrary but > 0.
82const char WiFi::kProgressiveScanFlagFile[] = "/home/chronos/.progressive_scan";
mukesh agrawalb54601c2011-06-07 17:39:22 -070083
Paul Stewartb50f0b92011-05-16 16:31:42 -070084WiFi::WiFi(ControlInterface *control_interface,
85 EventDispatcher *dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -080086 Metrics *metrics,
Paul Stewartf1ce5d22011-05-19 13:10:20 -070087 Manager *manager,
Chris Masone3bd3c8c2011-06-13 08:20:26 -070088 const string& link,
Paul Stewarta41e38d2011-11-11 07:47:29 -080089 const string &address,
Paul Stewartb50f0b92011-05-16 16:31:42 -070090 int interface_index)
Chris Masonea82b7112011-05-25 15:16:29 -070091 : Device(control_interface,
92 dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -080093 metrics,
Chris Masonea82b7112011-05-25 15:16:29 -070094 manager,
Chris Masone3bd3c8c2011-06-13 08:20:26 -070095 link,
Chris Masone626719f2011-08-18 16:58:48 -070096 address,
Gaurav Shah435de2c2011-11-17 19:01:07 -080097 interface_index,
98 Technology::kWifi),
Paul Stewart3c504012013-01-17 17:49:58 -080099 provider_(manager->wifi_provider()),
Eric Shienbrood9a245532012-03-07 14:20:39 -0500100 weak_ptr_factory_(this),
Darin Petkovab565bb2011-10-06 02:55:51 -0700101 proxy_factory_(ProxyFactory::GetInstance()),
mukesh agrawal5c05b292012-03-07 10:12:52 -0800102 time_(Time::GetInstance()),
Darin Petkov2b8e44e2012-06-25 15:13:26 +0200103 supplicant_present_(false),
mukesh agrawal15908392011-11-16 18:29:25 +0000104 supplicant_state_(kInterfaceStateUnknown),
105 supplicant_bss_("(unknown)"),
mukesh agrawal5c05b292012-03-07 10:12:52 -0800106 need_bss_flush_(false),
Wade Guthriebb9fca22013-04-10 17:21:42 -0700107 resumed_at_((struct timeval) {0}),
Paul Stewarte369ece2012-05-22 09:11:03 -0700108 fast_scans_remaining_(kNumFastScanAttempts),
Christopher Wiley8f81e2a2012-10-17 16:51:32 -0700109 has_already_completed_(false),
Paul Stewarta47c3c62012-12-18 12:14:29 -0800110 is_debugging_connection_(false),
Paul Stewart735eab52013-03-29 09:19:23 -0700111 eap_state_handler_(new SupplicantEAPStateHandler()),
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800112 bgscan_short_interval_seconds_(kDefaultBgscanShortIntervalSeconds),
113 bgscan_signal_threshold_dbm_(kDefaultBgscanSignalThresholdDbm),
Chris Masone853b81b2011-06-24 14:11:41 -0700114 scan_pending_(false),
Wade Guthriebee87c22013-03-06 11:00:46 -0800115 scan_interval_seconds_(kDefaultScanIntervalSeconds),
Wade Guthrie5a4e2ef2013-04-30 12:51:39 -0700116 progressive_scan_enabled_(false),
117 netlink_manager_(NetlinkManager::GetInstance()),
118 min_frequencies_to_scan_(kMinumumFrequenciesToScan),
119 max_frequencies_to_scan_(std::numeric_limits<int>::max()) {
mukesh agrawalde29fa82011-09-16 16:16:36 -0700120 PropertyStore *store = this->mutable_store();
Darin Petkov4a66cc52012-06-15 10:08:29 +0200121 store->RegisterDerivedString(
122 flimflam::kBgscanMethodProperty,
123 StringAccessor(
124 // TODO(petkov): CustomMappedAccessor is used for convenience because
125 // it provides a way to define a custom clearer (unlike
126 // CustomAccessor). We need to implement a fully custom accessor with
127 // no extra argument.
128 new CustomMappedAccessor<WiFi, string, int>(this,
129 &WiFi::ClearBgscanMethod,
130 &WiFi::GetBgscanMethod,
131 &WiFi::SetBgscanMethod,
132 0))); // Unused.
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800133 HelpRegisterDerivedUint16(store,
134 flimflam::kBgscanShortIntervalProperty,
135 &WiFi::GetBgscanShortInterval,
136 &WiFi::SetBgscanShortInterval);
137 HelpRegisterDerivedInt32(store,
138 flimflam::kBgscanSignalThresholdProperty,
139 &WiFi::GetBgscanSignalThreshold,
140 &WiFi::SetBgscanSignalThreshold);
Chris Masone853b81b2011-06-24 14:11:41 -0700141
Chris Masoneb925cc82011-06-22 15:39:57 -0700142 // TODO(quiche): Decide if scan_pending_ is close enough to
143 // "currently scanning" that we don't care, or if we want to track
144 // scan pending/currently scanning/no scan scheduled as a tri-state
145 // kind of thing.
Paul Stewartac4ac002011-08-26 12:04:26 -0700146 store->RegisterConstBool(flimflam::kScanningProperty, &scan_pending_);
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800147 HelpRegisterDerivedUint16(store,
148 flimflam::kScanIntervalProperty,
149 &WiFi::GetScanInterval,
150 &WiFi::SetScanInterval);
Paul Stewart5581d072012-12-17 17:30:20 -0800151 ScopeLogger::GetInstance()->RegisterScopeEnableChangedCallback(
152 ScopeLogger::kWiFi,
153 Bind(&WiFi::OnWiFiDebugScopeChanged, weak_ptr_factory_.GetWeakPtr()));
Wade Guthriebb9fca22013-04-10 17:21:42 -0700154 CHECK(netlink_manager_);
Wade Guthrie5a4e2ef2013-04-30 12:51:39 -0700155 progressive_scan_enabled_ = PathExists(FilePath(kProgressiveScanFlagFile));
Ben Chanfad4a0b2012-04-18 15:49:59 -0700156 SLOG(WiFi, 2) << "WiFi device " << link_name() << " initialized.";
Paul Stewartb50f0b92011-05-16 16:31:42 -0700157}
158
mukesh agrawalaf571952011-07-14 14:31:12 -0700159WiFi::~WiFi() {}
Paul Stewartb50f0b92011-05-16 16:31:42 -0700160
Eric Shienbrood9a245532012-03-07 14:20:39 -0500161void WiFi::Start(Error *error, const EnabledStateChangedCallback &callback) {
Darin Petkov2b8e44e2012-06-25 15:13:26 +0200162 SLOG(WiFi, 2) << "WiFi " << link_name() << " starting.";
163 if (enabled()) {
164 return;
mukesh agrawalc7426a42011-06-03 13:04:28 -0700165 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500166 OnEnabledStateChanged(EnabledStateChangedCallback(), Error());
Darin Petkov2b8e44e2012-06-25 15:13:26 +0200167 if (error) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500168 error->Reset(); // indicate immediate completion
Darin Petkov2b8e44e2012-06-25 15:13:26 +0200169 }
170 if (on_supplicant_appear_.IsCancelled()) {
171 // Registers the WPA supplicant appear/vanish callbacks only once per WiFi
172 // device instance.
173 on_supplicant_appear_.Reset(
174 Bind(&WiFi::OnSupplicantAppear, Unretained(this)));
175 on_supplicant_vanish_.Reset(
176 Bind(&WiFi::OnSupplicantVanish, Unretained(this)));
Paul Stewart0654ece2013-03-26 15:21:26 -0700177 manager()->dbus_manager()->WatchName(WPASupplicant::kDBusAddr,
Darin Petkov2b8e44e2012-06-25 15:13:26 +0200178 on_supplicant_appear_.callback(),
179 on_supplicant_vanish_.callback());
180 }
181 // Connect to WPA supplicant if it's already present. If not, we'll connect to
182 // it when it appears.
183 ConnectToSupplicant();
Wade Guthriebee87c22013-03-06 11:00:46 -0800184 // Subscribe to multicast events.
Wade Guthriebb9fca22013-04-10 17:21:42 -0700185 netlink_manager_->SubscribeToEvents(Nl80211Message::kMessageTypeString,
186 NetlinkManager::kEventTypeConfig);
187 netlink_manager_->SubscribeToEvents(Nl80211Message::kMessageTypeString,
188 NetlinkManager::kEventTypeScan);
189 netlink_manager_->SubscribeToEvents(Nl80211Message::kMessageTypeString,
190 NetlinkManager::kEventTypeRegulatory);
191 netlink_manager_->SubscribeToEvents(Nl80211Message::kMessageTypeString,
192 NetlinkManager::kEventTypeMlme);
Wade Guthrie92d06362013-04-25 15:41:30 -0700193 ConfigureScanFrequencies();
mukesh agrawalab87ea42011-05-18 11:44:49 -0700194}
195
Eric Shienbrood9a245532012-03-07 14:20:39 -0500196void WiFi::Stop(Error *error, const EnabledStateChangedCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700197 SLOG(WiFi, 2) << "WiFi " << link_name() << " stopping.";
Darin Petkov2b8e44e2012-06-25 15:13:26 +0200198 DropConnection();
mukesh agrawalb66c6462012-05-07 11:45:25 -0700199 StopScanTimer();
Paul Stewart3c504012013-01-17 17:49:58 -0800200 for (EndpointMap::iterator it = endpoint_by_rpcid_.begin();
201 it != endpoint_by_rpcid_.end(); ++it) {
202 provider_->OnEndpointRemoved(it->second);
203 }
mukesh agrawal15908392011-11-16 18:29:25 +0000204 endpoint_by_rpcid_.clear();
Paul Stewart3c504012013-01-17 17:49:58 -0800205 for (ReverseServiceMap::const_iterator it = rpcid_by_service_.begin();
206 it != rpcid_by_service_.end(); ++it) {
207 RemoveNetwork(it->second);
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -0700208 }
Paul Stewart549d44c2012-07-03 12:40:25 -0700209 rpcid_by_service_.clear();
Paul Stewart549d44c2012-07-03 12:40:25 -0700210 supplicant_interface_proxy_.reset(); // breaks a reference cycle
211 // TODO(quiche): Remove interface from supplicant.
212 supplicant_process_proxy_.reset();
mukesh agrawalb20776f2012-02-10 16:00:36 -0800213 current_service_ = NULL; // breaks a reference cycle
mukesh agrawal7ec71312011-11-10 02:08:26 +0000214 pending_service_ = NULL; // breaks a reference cycle
Paul Stewarta47c3c62012-12-18 12:14:29 -0800215 is_debugging_connection_ = false;
Paul Stewartd2db2b12013-01-17 13:11:07 -0800216 SetScanPending(false);
Paul Stewart2b05e622012-07-13 20:38:44 -0700217 StopPendingTimer();
Paul Stewart44663922012-07-30 11:03:03 -0700218 StopReconnectTimer();
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -0700219
Eric Shienbrood9a245532012-03-07 14:20:39 -0500220 OnEnabledStateChanged(EnabledStateChangedCallback(), Error());
221 if (error)
222 error->Reset(); // indicate immediate completion
mukesh agrawalc4f368f2012-06-04 19:45:52 -0700223 weak_ptr_factory_.InvalidateWeakPtrs();
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -0700224
Ben Chanfad4a0b2012-04-18 15:49:59 -0700225 SLOG(WiFi, 3) << "WiFi " << link_name() << " supplicant_process_proxy_ "
226 << (supplicant_process_proxy_.get() ?
227 "is set." : "is not set.");
228 SLOG(WiFi, 3) << "WiFi " << link_name() << " supplicant_interface_proxy_ "
229 << (supplicant_interface_proxy_.get() ?
230 "is set." : "is not set.");
231 SLOG(WiFi, 3) << "WiFi " << link_name() << " pending_service_ "
232 << (pending_service_.get() ? "is set." : "is not set.");
233 SLOG(WiFi, 3) << "WiFi " << link_name() << " has "
234 << endpoint_by_rpcid_.size() << " EndpointMap entries.";
Paul Stewarta41e38d2011-11-11 07:47:29 -0800235}
236
Wade Guthrie68d41092013-04-02 12:56:02 -0700237void WiFi::Scan(ScanType scan_type, Error */*error*/) {
mukesh agrawal32399322011-09-01 10:53:43 -0700238 LOG(INFO) << __func__;
Wade Guthrie5a4e2ef2013-04-30 12:51:39 -0700239 // Measure scans that are supposed to be "progressive" regardless of whether
240 // we are actually doing a progressive scan.
241 if (scan_type == kProgressiveScan) {
Wade Guthrie68d41092013-04-02 12:56:02 -0700242 metrics()->NotifyDeviceScanStarted(interface_index());
Wade Guthrie5a4e2ef2013-04-30 12:51:39 -0700243 }
Wade Guthrie68d41092013-04-02 12:56:02 -0700244
Wade Guthrie5a4e2ef2013-04-30 12:51:39 -0700245 if (progressive_scan_enabled_ && scan_type == kProgressiveScan) {
246 SLOG(WiFi, 4) << "Doing progressive scan on " << link_name();
247 if (!scan_session_) {
248 // TODO(wdg): Perform in-depth testing to determine the best values for
249 // the different scans. chromium:235293
250 ScanSession::FractionList scan_fractions;
251 scan_fractions.push_back(.33); // First scan gets 33 percentile.
252 scan_fractions.push_back(.33); // Second scan gets 66th percentile.
253 scan_fractions.push_back(ScanSession::kAllFrequencies);
254 scan_session_.reset(
255 new ScanSession(netlink_manager_,
256 dispatcher(),
257 provider_->GetScanFrequencies(),
258 all_scan_frequencies_,
259 interface_index(),
260 scan_fractions,
261 min_frequencies_to_scan_,
262 max_frequencies_to_scan_,
263 Bind(&WiFi::OnFailedProgressiveScan,
264 weak_ptr_factory_.GetWeakPtr())));
265 for (const auto &ssid : provider_->GetHiddenSSIDList()) {
266 scan_session_->AddSsid(ByteString(&ssid.front(), ssid.size()));
267 }
268 }
269 dispatcher()->PostTask(
270 Bind(&WiFi::ProgressiveScanTask, weak_ptr_factory_.GetWeakPtr()));
271 } else {
272 SLOG(WiFi, 4) << "Doing full scan - progressive scan "
273 << (progressive_scan_enabled_ ? "ENABLED" : "DISABLED");
274 // Needs to send a D-Bus message, but may be called from D-Bus
275 // signal handler context (via Manager::RequestScan). So defer work
276 // to event loop.
277 dispatcher()->PostTask(
278 Bind(&WiFi::ScanTask, weak_ptr_factory_.GetWeakPtr()));
279 }
mukesh agrawal32399322011-09-01 10:53:43 -0700280}
281
mukesh agrawalb4bc57d2011-12-07 01:07:47 +0000282void WiFi::BSSAdded(const ::DBus::Path &path,
283 const map<string, ::DBus::Variant> &properties) {
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500284 // Called from a D-Bus signal handler, and may need to send a D-Bus
mukesh agrawalb4bc57d2011-12-07 01:07:47 +0000285 // message. So defer work to event loop.
Eric Shienbrood9a245532012-03-07 14:20:39 -0500286 dispatcher()->PostTask(Bind(&WiFi::BSSAddedTask,
287 weak_ptr_factory_.GetWeakPtr(),
288 path, properties));
mukesh agrawal261daca2011-12-02 18:56:56 +0000289}
290
291void WiFi::BSSRemoved(const ::DBus::Path &path) {
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500292 // Called from a D-Bus signal handler, and may need to send a D-Bus
mukesh agrawalb4bc57d2011-12-07 01:07:47 +0000293 // message. So defer work to event loop.
Eric Shienbrood9a245532012-03-07 14:20:39 -0500294 dispatcher()->PostTask(Bind(&WiFi::BSSRemovedTask,
295 weak_ptr_factory_.GetWeakPtr(), path));
mukesh agrawalb54601c2011-06-07 17:39:22 -0700296}
297
Paul Stewartbc6e7392012-05-24 07:07:48 -0700298void WiFi::Certification(const map<string, ::DBus::Variant> &properties) {
299 dispatcher()->PostTask(Bind(&WiFi::CertificationTask,
300 weak_ptr_factory_.GetWeakPtr(), properties));
301}
302
Paul Stewartdb0f9172012-11-30 16:48:09 -0800303void WiFi::EAPEvent(const string &status, const string &parameter) {
304 dispatcher()->PostTask(Bind(&WiFi::EAPEventTask,
305 weak_ptr_factory_.GetWeakPtr(),
306 status,
307 parameter));
308}
309
mukesh agrawal7ec71312011-11-10 02:08:26 +0000310void WiFi::PropertiesChanged(const map<string, ::DBus::Variant> &properties) {
Darin Petkov9cd7ca12012-07-03 11:06:40 +0200311 SLOG(WiFi, 2) << __func__;
mukesh agrawal15908392011-11-16 18:29:25 +0000312 // Called from D-Bus signal handler, but may need to send a D-Bus
313 // message. So defer work to event loop.
Eric Shienbrood9a245532012-03-07 14:20:39 -0500314 dispatcher()->PostTask(Bind(&WiFi::PropertiesChangedTask,
315 weak_ptr_factory_.GetWeakPtr(), properties));
mukesh agrawal7ec71312011-11-10 02:08:26 +0000316}
317
mukesh agrawalb54601c2011-06-07 17:39:22 -0700318void WiFi::ScanDone() {
319 LOG(INFO) << __func__;
320
mukesh agrawal7ec71312011-11-10 02:08:26 +0000321 // Defer handling of scan result processing, because that processing
322 // may require the the registration of new D-Bus objects. And such
mukesh agrawalb54601c2011-06-07 17:39:22 -0700323 // registration can't be done in the context of a D-Bus signal
324 // handler.
Eric Shienbrood9a245532012-03-07 14:20:39 -0500325 dispatcher()->PostTask(Bind(&WiFi::ScanDoneTask,
326 weak_ptr_factory_.GetWeakPtr()));
mukesh agrawalb54601c2011-06-07 17:39:22 -0700327}
328
mukesh agrawal6e277772011-09-29 15:04:23 -0700329void WiFi::ConnectTo(WiFiService *service,
mukesh agrawal64896322011-12-01 01:13:10 +0000330 map<string, DBus::Variant> service_params) {
mukesh agrawale9adda12012-02-09 18:33:48 -0800331 CHECK(service) << "Can't connect to NULL service.";
mukesh agrawal445e72c2011-06-22 11:13:50 -0700332 DBus::Path network_path;
mukesh agrawalb54601c2011-06-07 17:39:22 -0700333
mukesh agrawal7ec71312011-11-10 02:08:26 +0000334 // TODO(quiche): Handle cases where already connected.
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000335 if (pending_service_ && pending_service_ == service) {
336 // TODO(quiche): Return an error to the caller. crosbug.com/23832
Darin Petkov457728b2013-01-09 09:49:08 +0100337 LOG(INFO) << "WiFi " << link_name() << " ignoring ConnectTo service "
338 << service->unique_name()
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000339 << ", which is already pending.";
340 return;
341 }
342
343 if (pending_service_ && pending_service_ != service) {
344 DisconnectFrom(pending_service_);
345 }
mukesh agrawal32399322011-09-01 10:53:43 -0700346
Paul Stewart835934a2012-12-06 19:27:09 -0800347 Error unused_error;
348 network_path = FindNetworkRpcidForService(service, &unused_error);
349 if (network_path.empty()) {
350 try {
351 const uint32_t scan_ssid = 1; // "True": Use directed probe.
Paul Stewart0654ece2013-03-26 15:21:26 -0700352 service_params[WPASupplicant::kNetworkPropertyScanSSID].writer().
Paul Stewart835934a2012-12-06 19:27:09 -0800353 append_uint32(scan_ssid);
354 AppendBgscan(service, &service_params);
355 network_path = supplicant_interface_proxy_->AddNetwork(service_params);
356 CHECK(!network_path.empty()); // No DBus path should be empty.
357 rpcid_by_service_[service] = network_path;
358 } catch (const DBus::Error &e) { // NOLINT
359 LOG(ERROR) << "exception while adding network: " << e.what();
360 return;
361 }
mukesh agrawal6e277772011-09-29 15:04:23 -0700362 }
mukesh agrawal445e72c2011-06-22 11:13:50 -0700363
Paul Stewarta47c3c62012-12-18 12:14:29 -0800364 if (service->HasRecentConnectionIssues()) {
365 SetConnectionDebugging(true);
366 }
mukesh agrawal445e72c2011-06-22 11:13:50 -0700367 supplicant_interface_proxy_->SelectNetwork(network_path);
Paul Stewart2b05e622012-07-13 20:38:44 -0700368 SetPendingService(service);
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000369 CHECK(current_service_.get() != pending_service_.get());
370
mukesh agrawalf2f68a52011-09-01 12:15:48 -0700371 // SelectService here (instead of in LinkEvent, like Ethernet), so
372 // that, if we fail to bring up L2, we can attribute failure correctly.
373 //
mukesh agrawal7ec71312011-11-10 02:08:26 +0000374 // TODO(quiche): When we add code for dealing with connection failures,
mukesh agrawalf2f68a52011-09-01 12:15:48 -0700375 // reconsider if this is the right place to change the selected service.
376 // see discussion in crosbug.com/20191.
377 SelectService(service);
mukesh agrawal15908392011-11-16 18:29:25 +0000378}
379
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000380void WiFi::DisconnectFrom(WiFiService *service) {
381 if (service != current_service_ && service != pending_service_) {
382 // TODO(quiche): Once we have asynchronous reply support, we should
383 // generate a D-Bus error here. (crosbug.com/23832)
384 LOG(WARNING) << "In " << __func__ << "(): "
385 << " ignoring request to disconnect from service "
Darin Petkov457728b2013-01-09 09:49:08 +0100386 << service->unique_name()
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000387 << " which is neither current nor pending";
388 return;
389 }
390
391 if (pending_service_ && service != pending_service_) {
392 // TODO(quiche): Once we have asynchronous reply support, we should
393 // generate a D-Bus error here. (crosbug.com/23832)
394 LOG(WARNING) << "In " << __func__ << "(): "
395 << " ignoring request to disconnect from service "
Darin Petkov457728b2013-01-09 09:49:08 +0100396 << service->unique_name()
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000397 << " which is not the pending service.";
398 return;
399 }
400
401 if (!pending_service_ && service != current_service_) {
402 // TODO(quiche): Once we have asynchronous reply support, we should
403 // generate a D-Bus error here. (crosbug.com/23832)
404 LOG(WARNING) << "In " << __func__ << "(): "
405 << " ignoring request to disconnect from service "
Darin Petkov457728b2013-01-09 09:49:08 +0100406 << service->unique_name()
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000407 << " which is not the current service.";
408 return;
409 }
410
Paul Stewartff96a842012-08-13 15:59:10 -0700411 if (pending_service_) {
412 // Since wpa_supplicant has not yet set CurrentBSS, we can't depend
413 // on this to drive the service state back to idle. Do that here.
414 pending_service_->SetState(Service::kStateIdle);
415 }
416
Paul Stewart2b05e622012-07-13 20:38:44 -0700417 SetPendingService(NULL);
Paul Stewart44663922012-07-30 11:03:03 -0700418 StopReconnectTimer();
Paul Stewart549d44c2012-07-03 12:40:25 -0700419
420 if (!supplicant_present_) {
Christopher Wileyc6184482012-10-24 15:31:56 -0700421 LOG(ERROR) << "In " << __func__ << "(): "
422 << "wpa_supplicant is not present; silently resetting "
423 << "current_service_.";
424 if (current_service_ == selected_service()) {
425 DropConnection();
426 }
Paul Stewart549d44c2012-07-03 12:40:25 -0700427 current_service_ = NULL;
428 return;
429 }
430
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000431 try {
432 supplicant_interface_proxy_->Disconnect();
433 // We'll call RemoveNetwork and reset |current_service_| after
434 // supplicant notifies us that the CurrentBSS has changed.
Ben Chan80326f32012-05-04 17:51:32 -0700435 } catch (const DBus::Error &e) { // NOLINT
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000436 // Can't depend on getting a notification of CurrentBSS change.
Christopher Wileyc6184482012-10-24 15:31:56 -0700437 // So effect changes immediately. For instance, this can happen when
438 // a disconnect is triggered by a BSS going away.
Paul Stewart835934a2012-12-06 19:27:09 -0800439 Error unused_error;
440 RemoveNetworkForService(service, &unused_error);
Christopher Wileyc6184482012-10-24 15:31:56 -0700441 if (service == selected_service()) {
442 DropConnection();
443 }
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000444 current_service_ = NULL;
445 }
446
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800447 CHECK(current_service_ == NULL ||
448 current_service_.get() != pending_service_.get());
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000449}
450
Paul Stewart835934a2012-12-06 19:27:09 -0800451bool WiFi::DisableNetwork(const ::DBus::Path &network) {
452 scoped_ptr<SupplicantNetworkProxyInterface> supplicant_network_proxy(
453 proxy_factory_->CreateSupplicantNetworkProxy(
Paul Stewart0654ece2013-03-26 15:21:26 -0700454 network, WPASupplicant::kDBusAddr));
Paul Stewart835934a2012-12-06 19:27:09 -0800455 try {
456 supplicant_network_proxy->SetEnabled(false);
457 } catch (const DBus::Error &e) { // NOLINT
458 LOG(ERROR) << "DisableNetwork for " << network << " failed.";
459 return false;
460 }
461 return true;
462}
463
Paul Stewart71f6ecd2012-09-13 14:52:18 -0700464bool WiFi::RemoveNetwork(const ::DBus::Path &network) {
465 try {
466 supplicant_interface_proxy_->RemoveNetwork(network);
467 } catch (const DBus::Error &e) { // NOLINT
Ben Chan381fdcc2012-10-14 21:10:36 -0700468 // RemoveNetwork can fail with three different errors.
469 //
470 // If RemoveNetwork fails with a NetworkUnknown error, supplicant has
471 // already removed the network object, so return true as if
472 // RemoveNetwork removes the network object successfully.
473 //
474 // As shill always passes a valid network object path, RemoveNetwork
475 // should not fail with an InvalidArgs error. Return false in such case
476 // as something weird may have happened. Similarly, return false in case
477 // of an UnknownError.
Paul Stewart0654ece2013-03-26 15:21:26 -0700478 if (strcmp(e.name(), WPASupplicant::kErrorNetworkUnknown) != 0) {
Ben Chan381fdcc2012-10-14 21:10:36 -0700479 return false;
480 }
Paul Stewart71f6ecd2012-09-13 14:52:18 -0700481 }
482 return true;
483}
484
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000485bool WiFi::IsIdle() const {
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800486 return !current_service_ && !pending_service_;
487}
488
Paul Stewart835934a2012-12-06 19:27:09 -0800489void WiFi::ClearCachedCredentials(const WiFiService *service) {
490 Error unused_error;
491 RemoveNetworkForService(service, &unused_error);
Paul Stewart66c86002012-01-30 18:00:52 -0800492}
493
Paul Stewart3c504012013-01-17 17:49:58 -0800494void WiFi::NotifyEndpointChanged(const WiFiEndpointConstRefPtr &endpoint) {
Paul Stewart0427cc12013-03-25 13:50:39 -0700495 provider_->OnEndpointUpdated(endpoint);
mukesh agrawalb20776f2012-02-10 16:00:36 -0800496}
497
Darin Petkov4a66cc52012-06-15 10:08:29 +0200498void WiFi::AppendBgscan(WiFiService *service,
499 map<string, DBus::Variant> *service_params) const {
500 int scan_interval = kBackgroundScanIntervalSeconds;
501 string method = bgscan_method_;
502 if (method.empty()) {
503 // If multiple APs are detected for this SSID, configure the default method.
504 // Otherwise, disable background scanning completely.
505 if (service->GetEndpointCount() > 1) {
506 method = kDefaultBgscanMethod;
507 } else {
508 LOG(INFO) << "Background scan disabled -- single Endpoint for Service.";
509 return;
510 }
Paul Stewart0654ece2013-03-26 15:21:26 -0700511 } else if (method.compare(WPASupplicant::kNetworkBgscanMethodNone) == 0) {
Christopher Wileya998df22012-07-11 15:14:55 -0700512 LOG(INFO) << "Background scan disabled -- chose None method.";
513 return;
Darin Petkov4a66cc52012-06-15 10:08:29 +0200514 } else {
515 // If the background scan method was explicitly specified, honor the
516 // configured background scan interval.
517 scan_interval = scan_interval_seconds_;
518 }
519 DCHECK(!method.empty());
520 string config_string = StringPrintf("%s:%d:%d:%d",
521 method.c_str(),
522 bgscan_short_interval_seconds_,
523 bgscan_signal_threshold_dbm_,
524 scan_interval);
525 LOG(INFO) << "Background scan: " << config_string;
Paul Stewart0654ece2013-03-26 15:21:26 -0700526 (*service_params)[WPASupplicant::kNetworkPropertyBgscan].writer()
Darin Petkov4a66cc52012-06-15 10:08:29 +0200527 .append_string(config_string.c_str());
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800528}
529
Darin Petkov4a66cc52012-06-15 10:08:29 +0200530string WiFi::GetBgscanMethod(const int &/*argument*/, Error */* error */) {
531 return bgscan_method_.empty() ? kDefaultBgscanMethod : bgscan_method_;
532}
533
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700534bool WiFi::SetBgscanMethod(
Darin Petkov4a66cc52012-06-15 10:08:29 +0200535 const int &/*argument*/, const string &method, Error *error) {
Paul Stewart0654ece2013-03-26 15:21:26 -0700536 if (method != WPASupplicant::kNetworkBgscanMethodSimple &&
537 method != WPASupplicant::kNetworkBgscanMethodLearn &&
538 method != WPASupplicant::kNetworkBgscanMethodNone) {
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800539 const string error_message =
540 StringPrintf("Unrecognized bgscan method %s", method.c_str());
541 LOG(WARNING) << error_message;
542 error->Populate(Error::kInvalidArguments, error_message);
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700543 return false;
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800544 }
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700545 if (bgscan_method_ == method) {
546 return false;
547 }
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800548 bgscan_method_ = method;
549 // We do not update kNetworkPropertyBgscan for |pending_service_| or
550 // |current_service_|, because supplicant does not allow for
551 // reconfiguration without disconnect and reconnect.
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700552 return true;
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800553}
554
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700555bool WiFi::SetBgscanShortInterval(const uint16 &seconds, Error */*error*/) {
556 if (bgscan_short_interval_seconds_ == seconds) {
557 return false;
558 }
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800559 bgscan_short_interval_seconds_ = seconds;
560 // We do not update kNetworkPropertyBgscan for |pending_service_| or
561 // |current_service_|, because supplicant does not allow for
562 // reconfiguration without disconnect and reconnect.
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700563 return true;
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800564}
565
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700566bool WiFi::SetBgscanSignalThreshold(const int32 &dbm, Error */*error*/) {
567 if (bgscan_signal_threshold_dbm_ == dbm) {
568 return false;
569 }
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800570 bgscan_signal_threshold_dbm_ = dbm;
571 // We do not update kNetworkPropertyBgscan for |pending_service_| or
572 // |current_service_|, because supplicant does not allow for
573 // reconfiguration without disconnect and reconnect.
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700574 return true;
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800575}
576
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700577bool WiFi::SetScanInterval(const uint16 &seconds, Error */*error*/) {
578 if (scan_interval_seconds_ == seconds) {
579 return false;
580 }
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800581 scan_interval_seconds_ = seconds;
mukesh agrawalb66c6462012-05-07 11:45:25 -0700582 if (running()) {
583 StartScanTimer();
584 }
585 // The scan interval affects both foreground scans (handled by
586 // |scan_timer_callback_|), and background scans (handled by
587 // supplicant). However, we do not update |pending_service_| or
588 // |current_service_|, because supplicant does not allow for
589 // reconfiguration without disconnect and reconnect.
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700590 return true;
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800591}
592
Darin Petkov4a66cc52012-06-15 10:08:29 +0200593void WiFi::ClearBgscanMethod(const int &/*argument*/, Error */*error*/) {
594 bgscan_method_.clear();
595}
596
mukesh agrawal15908392011-11-16 18:29:25 +0000597void WiFi::CurrentBSSChanged(const ::DBus::Path &new_bss) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700598 SLOG(WiFi, 3) << "WiFi " << link_name() << " CurrentBSS "
599 << supplicant_bss_ << " -> " << new_bss;
mukesh agrawal15908392011-11-16 18:29:25 +0000600 supplicant_bss_ = new_bss;
Christopher Wiley8f81e2a2012-10-17 16:51:32 -0700601 has_already_completed_ = false;
Paul Stewart44663922012-07-30 11:03:03 -0700602
603 // Any change in CurrentBSS means supplicant is actively changing our
604 // connectivity. We no longer need to track any previously pending
605 // reconnect.
606 StopReconnectTimer();
607
Paul Stewart0654ece2013-03-26 15:21:26 -0700608 if (new_bss == WPASupplicant::kCurrentBSSNull) {
mukesh agrawal15908392011-11-16 18:29:25 +0000609 HandleDisconnect();
Paul Stewart3c504012013-01-17 17:49:58 -0800610 if (!provider_->GetHiddenSSIDList().empty()) {
mukesh agrawalb66c6462012-05-07 11:45:25 -0700611 // Before disconnecting, wpa_supplicant probably scanned for
612 // APs. So, in the normal case, we defer to the timer for the next scan.
613 //
614 // However, in the case of hidden SSIDs, supplicant knows about
615 // at most one of them. (That would be the hidden SSID we were
616 // connected to, if applicable.)
617 //
618 // So, in this case, we initiate an immediate scan. This scan
619 // will include the hidden SSIDs we know about (up to the limit of
620 // kScanMAxSSIDsPerScan).
621 //
622 // We may want to reconsider this immediate scan, if/when shill
623 // takes greater responsibility for scanning (vs. letting
624 // supplicant handle most of it).
Wade Guthrie68d41092013-04-02 12:56:02 -0700625 Scan(kProgressiveScan, NULL);
mukesh agrawalb66c6462012-05-07 11:45:25 -0700626 }
mukesh agrawal15908392011-11-16 18:29:25 +0000627 } else {
628 HandleRoam(new_bss);
629 }
630
Paul Stewart735eab52013-03-29 09:19:23 -0700631 // Reset the EAP handler only after calling HandleDisconnect() above
632 // so our EAP state could be used to detect a failed authentication.
633 eap_state_handler_->Reset();
Paul Stewart1369c2b2013-01-11 05:41:26 -0800634
Paul Stewart2b05e622012-07-13 20:38:44 -0700635 // If we are selecting a new service, or if we're clearing selection
636 // of a something other than the pending service, call SelectService.
637 // Otherwise skip SelectService, since this will cause the pending
638 // service to be marked as Idle.
639 if (current_service_ || selected_service() != pending_service_) {
640 SelectService(current_service_);
641 }
642
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000643 // Invariant check: a Service can either be current, or pending, but
644 // not both.
mukesh agrawal15908392011-11-16 18:29:25 +0000645 CHECK(current_service_.get() != pending_service_.get() ||
646 current_service_.get() == NULL);
Paul Stewarta47c3c62012-12-18 12:14:29 -0800647
648 // If we are no longer debugging a problematic WiFi connection, return
649 // to the debugging level indicated by the WiFi debugging scope.
650 if ((!current_service_ || !current_service_->HasRecentConnectionIssues()) &&
651 (!pending_service_ || !pending_service_->HasRecentConnectionIssues())) {
652 SetConnectionDebugging(false);
653 }
mukesh agrawal15908392011-11-16 18:29:25 +0000654}
655
656void WiFi::HandleDisconnect() {
657 // Identify the affected service. We expect to get a disconnect
658 // event when we fall off a Service that we were connected
659 // to. However, we also allow for the case where we get a disconnect
660 // event while attempting to connect from a disconnected state.
661 WiFiService *affected_service =
662 current_service_.get() ? current_service_.get() : pending_service_.get();
663
664 current_service_ = NULL;
665 if (!affected_service) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700666 SLOG(WiFi, 2) << "WiFi " << link_name()
667 << " disconnected while not connected or connecting";
mukesh agrawal15908392011-11-16 18:29:25 +0000668 return;
Christopher Wileyc6184482012-10-24 15:31:56 -0700669 }
670 if (affected_service == selected_service()) {
Paul Stewart20b0a092012-05-22 20:39:57 -0700671 // If our selected service has disconnected, destroy IP configuration state.
Christopher Wileyc6184482012-10-24 15:31:56 -0700672 DropConnection();
mukesh agrawal15908392011-11-16 18:29:25 +0000673 }
674
Paul Stewart835934a2012-12-06 19:27:09 -0800675 Error error;
676 if (!DisableNetworkForService(affected_service, &error)) {
677 if (error.type() == Error::kNotFound) {
678 SLOG(WiFi, 2) << "WiFi " << link_name() << " disconnected from "
Darin Petkov457728b2013-01-09 09:49:08 +0100679 << " (or failed to connect to) service "
680 << affected_service->unique_name() << ", "
Paul Stewart835934a2012-12-06 19:27:09 -0800681 << "but could not find supplicant network to disable.";
682 } else {
683 LOG(FATAL) << "DisableNetwork failed.";
Paul Stewart71f6ecd2012-09-13 14:52:18 -0700684 }
mukesh agrawal15908392011-11-16 18:29:25 +0000685 }
686
Ben Chanfad4a0b2012-04-18 15:49:59 -0700687 SLOG(WiFi, 2) << "WiFi " << link_name() << " disconnected from "
Darin Petkov457728b2013-01-09 09:49:08 +0100688 << " (or failed to connect to) service "
689 << affected_service->unique_name();
Paul Stewart1369c2b2013-01-11 05:41:26 -0800690 Service::ConnectFailure failure;
691 if (SuspectCredentials(*affected_service, &failure)) {
mukesh agrawalcf24a242012-05-21 16:46:11 -0700692 // If we suspect bad credentials, set failure, to trigger an error
mukesh agrawal56e32202012-07-26 16:32:11 -0700693 // mole in Chrome.
Paul Stewart1369c2b2013-01-11 05:41:26 -0800694 affected_service->SetFailure(failure);
695 LOG(ERROR) << "Connection failure is due to suspect credentials: returning "
696 << Service::ConnectFailureToString(failure);
Paul Stewartf2d60912012-07-15 08:37:30 -0700697 } else {
698 affected_service->SetFailureSilent(Service::kFailureUnknown);
mukesh agrawalcf24a242012-05-21 16:46:11 -0700699 }
mukesh agrawale1d90e92012-02-15 17:36:08 -0800700 affected_service->NotifyCurrentEndpoint(NULL);
Thieu Le67370f62012-02-14 23:01:42 +0000701 metrics()->NotifyServiceDisconnect(affected_service);
mukesh agrawal15908392011-11-16 18:29:25 +0000702
703 if (affected_service == pending_service_.get()) {
704 // The attempt to connect to |pending_service_| failed. Clear
705 // |pending_service_|, to indicate we're no longer in the middle
706 // of a connect request.
Paul Stewart2b05e622012-07-13 20:38:44 -0700707 SetPendingService(NULL);
mukesh agrawal15908392011-11-16 18:29:25 +0000708 } else if (pending_service_.get()) {
709 // We've attributed the disconnection to what was the
710 // |current_service_|, rather than the |pending_service_|.
711 //
712 // If we're wrong about that (i.e. supplicant reported this
713 // CurrentBSS change after attempting to connect to
714 // |pending_service_|), we're depending on supplicant to retry
715 // connecting to |pending_service_|, and delivering another
716 // CurrentBSS change signal in the future.
717 //
718 // Log this fact, to help us debug (in case our assumptions are
719 // wrong).
Darin Petkov457728b2013-01-09 09:49:08 +0100720 SLOG(WiFi, 2) << "WiFi " << link_name() << " pending connection to service "
721 << pending_service_->unique_name()
Ben Chanfad4a0b2012-04-18 15:49:59 -0700722 << " after disconnect";
mukesh agrawal15908392011-11-16 18:29:25 +0000723 }
Paul Stewarte369ece2012-05-22 09:11:03 -0700724
725 // If we disconnect, initially scan at a faster frequency, to make sure
726 // we've found all available APs.
727 RestartFastScanAttempts();
mukesh agrawal15908392011-11-16 18:29:25 +0000728}
729
730// We use the term "Roam" loosely. In particular, we include the case
731// where we "Roam" to a BSS from the disconnected state.
732void WiFi::HandleRoam(const ::DBus::Path &new_bss) {
733 EndpointMap::iterator endpoint_it = endpoint_by_rpcid_.find(new_bss);
734 if (endpoint_it == endpoint_by_rpcid_.end()) {
735 LOG(WARNING) << "WiFi " << link_name() << " connected to unknown BSS "
736 << new_bss;
737 return;
738 }
739
Paul Stewart3c504012013-01-17 17:49:58 -0800740 const WiFiEndpointConstRefPtr endpoint(endpoint_it->second);
741 WiFiServiceRefPtr service = provider_->FindServiceForEndpoint(endpoint);
mukesh agrawal15908392011-11-16 18:29:25 +0000742 if (!service.get()) {
743 LOG(WARNING) << "WiFi " << link_name()
744 << " could not find Service for Endpoint "
Paul Stewart3c504012013-01-17 17:49:58 -0800745 << endpoint->bssid_string()
mukesh agrawal15908392011-11-16 18:29:25 +0000746 << " (service will be unchanged)";
747 return;
748 }
749
Ben Chanfad4a0b2012-04-18 15:49:59 -0700750 SLOG(WiFi, 2) << "WiFi " << link_name()
Paul Stewart3c504012013-01-17 17:49:58 -0800751 << " roamed to Endpoint " << endpoint->bssid_string()
752 << " " << LogSSID(endpoint->ssid_string());
mukesh agrawal15908392011-11-16 18:29:25 +0000753
Paul Stewart3c504012013-01-17 17:49:58 -0800754 service->NotifyCurrentEndpoint(endpoint);
Wade Guthrie60a37062013-04-02 11:39:09 -0700755 provider_->IncrementConnectCount(endpoint->frequency());
Thieu Lee41a72d2012-02-06 20:46:51 +0000756
mukesh agrawal15908392011-11-16 18:29:25 +0000757 if (pending_service_.get() &&
758 service.get() != pending_service_.get()) {
759 // The Service we've roamed on to is not the one we asked for.
760 // We assume that this is transient, and that wpa_supplicant
761 // is trying / will try to connect to |pending_service_|.
762 //
763 // If it succeeds, we'll end up back here, but with |service|
764 // pointing at the same service as |pending_service_|.
765 //
766 // If it fails, we'll process things in HandleDisconnect.
767 //
768 // So we leave |pending_service_| untouched.
Ben Chanfad4a0b2012-04-18 15:49:59 -0700769 SLOG(WiFi, 2) << "WiFi " << link_name()
770 << " new current Endpoint "
Paul Stewart3c504012013-01-17 17:49:58 -0800771 << endpoint->bssid_string()
Ben Chanfad4a0b2012-04-18 15:49:59 -0700772 << " is not part of pending service "
Darin Petkov457728b2013-01-09 09:49:08 +0100773 << pending_service_->unique_name();
mukesh agrawal15908392011-11-16 18:29:25 +0000774
775 // Sanity check: if we didn't roam onto |pending_service_|, we
776 // should still be on |current_service_|.
777 if (service.get() != current_service_.get()) {
778 LOG(WARNING) << "WiFi " << link_name()
779 << " new current Endpoint "
Paul Stewart3c504012013-01-17 17:49:58 -0800780 << endpoint->bssid_string()
mukesh agrawal15908392011-11-16 18:29:25 +0000781 << " is neither part of pending service "
Darin Petkov457728b2013-01-09 09:49:08 +0100782 << pending_service_->unique_name()
mukesh agrawal15908392011-11-16 18:29:25 +0000783 << " nor part of current service "
Darin Petkov457728b2013-01-09 09:49:08 +0100784 << (current_service_ ?
785 current_service_->unique_name() :
mukesh agrawal15908392011-11-16 18:29:25 +0000786 "(NULL)");
787 // Although we didn't expect to get here, we should keep
788 // |current_service_| in sync with what supplicant has done.
789 current_service_ = service;
790 }
791 return;
792 }
793
794 if (pending_service_.get()) {
795 // We assume service.get() == pending_service_.get() here, because
796 // of the return in the previous if clause.
797 //
798 // Boring case: we've connected to the service we asked
799 // for. Simply update |current_service_| and |pending_service_|.
800 current_service_ = service;
Paul Stewart2b05e622012-07-13 20:38:44 -0700801 SetPendingService(NULL);
mukesh agrawal15908392011-11-16 18:29:25 +0000802 return;
803 }
804
805 // |pending_service_| was NULL, so we weren't attempting to connect
806 // to a new Service. Sanity check that we're still on
807 // |current_service_|.
808 if (service.get() != current_service_.get()) {
809 LOG(WARNING)
810 << "WiFi " << link_name()
811 << " new current Endpoint "
Paul Stewart3c504012013-01-17 17:49:58 -0800812 << endpoint->bssid_string()
mukesh agrawal15908392011-11-16 18:29:25 +0000813 << (current_service_.get() ?
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000814 StringPrintf(" is not part of current service %s",
Darin Petkov457728b2013-01-09 09:49:08 +0100815 current_service_->unique_name().c_str()) :
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000816 " with no current service");
mukesh agrawal15908392011-11-16 18:29:25 +0000817 // We didn't expect to be here, but let's cope as well as we
818 // can. Update |current_service_| to keep it in sync with
819 // supplicant.
820 current_service_ = service;
Paul Stewartabbe2792012-07-15 07:50:35 -0700821
822 // If this service isn't already marked as actively connecting (likely,
823 // since this service is a bit of a surprise) set the service as
824 // associating.
825 if (!current_service_->IsConnecting()) {
826 current_service_->SetState(Service::kStateAssociating);
827 }
828
mukesh agrawal15908392011-11-16 18:29:25 +0000829 return;
830 }
831
832 // At this point, we know that |pending_service_| was NULL, and that
833 // we're still on |current_service_|. This is the most boring case
834 // of all, because there's no state to update here.
835 return;
mukesh agrawalb54601c2011-06-07 17:39:22 -0700836}
837
Paul Stewart835934a2012-12-06 19:27:09 -0800838string WiFi::FindNetworkRpcidForService(
839 const WiFiService *service, Error *error) {
840 ReverseServiceMap::const_iterator rpcid_it =
841 rpcid_by_service_.find(service);
842 if (rpcid_it == rpcid_by_service_.end()) {
843 const string error_message =
Darin Petkov457728b2013-01-09 09:49:08 +0100844 StringPrintf(
845 "WiFi %s cannot find supplicant network rpcid for service %s",
846 link_name().c_str(), service->unique_name().c_str());
Paul Stewart835934a2012-12-06 19:27:09 -0800847 // There are contexts where this is not an error, such as when a service
848 // is clearing whatever cached credentials may not exist.
849 SLOG(WiFi, 2) << error_message;
850 if (error) {
851 error->Populate(Error::kNotFound, error_message);
852 }
853 return "";
854 }
855
856 return rpcid_it->second;
857}
858
859bool WiFi::DisableNetworkForService(const WiFiService *service, Error *error) {
860 string rpcid = FindNetworkRpcidForService(service, error);
861 if (rpcid.empty()) {
862 // Error is already populated.
863 return false;
864 }
865
866 if (!DisableNetwork(rpcid)) {
867 const string error_message =
Darin Petkov457728b2013-01-09 09:49:08 +0100868 StringPrintf("WiFi %s cannot disable network for service %s: "
Paul Stewart835934a2012-12-06 19:27:09 -0800869 "DBus operation failed for rpcid %s.",
Darin Petkov457728b2013-01-09 09:49:08 +0100870 link_name().c_str(), service->unique_name().c_str(),
Paul Stewart835934a2012-12-06 19:27:09 -0800871 rpcid.c_str());
872 Error::PopulateAndLog(error, Error::kOperationFailed, error_message);
873
874 // Make sure that such errored networks are removed, so problems do not
875 // propogate to future connection attempts.
876 RemoveNetwork(rpcid);
877 rpcid_by_service_.erase(service);
878
879 return false;
880 }
881
882 return true;
883}
884
885bool WiFi::RemoveNetworkForService(const WiFiService *service, Error *error) {
886 string rpcid = FindNetworkRpcidForService(service, error);
887 if (rpcid.empty()) {
888 // Error is already populated.
889 return false;
890 }
891
892 // Erase the rpcid from our tables regardless of failure below, since even
893 // if in failure, we never want to use this network again.
894 rpcid_by_service_.erase(service);
895
896 // TODO(quiche): Reconsider giving up immediately. Maybe give
897 // wpa_supplicant some time to retry, first.
898 if (!RemoveNetwork(rpcid)) {
899 const string error_message =
Darin Petkov457728b2013-01-09 09:49:08 +0100900 StringPrintf("WiFi %s cannot remove network for service %s: "
Paul Stewart835934a2012-12-06 19:27:09 -0800901 "DBus operation failed for rpcid %s.",
Darin Petkov457728b2013-01-09 09:49:08 +0100902 link_name().c_str(), service->unique_name().c_str(),
Paul Stewart835934a2012-12-06 19:27:09 -0800903 rpcid.c_str());
904 Error::PopulateAndLog(error, Error::kOperationFailed, error_message);
905 return false;
906 }
907
908 return true;
909}
910
mukesh agrawalb4bc57d2011-12-07 01:07:47 +0000911void WiFi::BSSAddedTask(
912 const ::DBus::Path &path,
913 const map<string, ::DBus::Variant> &properties) {
mukesh agrawalb4bc57d2011-12-07 01:07:47 +0000914 // Note: we assume that BSSIDs are unique across endpoints. This
915 // means that if an AP reuses the same BSSID for multiple SSIDs, we
916 // lose.
mukesh agrawalb20776f2012-02-10 16:00:36 -0800917 WiFiEndpointRefPtr endpoint(
918 new WiFiEndpoint(proxy_factory_, this, path, properties));
Wade Guthrie592ecd52012-11-12 13:12:30 -0800919 SLOG(WiFi, 1) << "Found endpoint. "
920 << "RPC path: " << path << ", "
Darin Petkov50cb78a2013-02-06 16:17:49 +0100921 << LogSSID(endpoint->ssid_string()) << ", "
Wade Guthrie592ecd52012-11-12 13:12:30 -0800922 << "bssid: " << endpoint->bssid_string() << ", "
923 << "signal: " << endpoint->signal_strength() << ", "
924 << "security: " << endpoint->security_mode() << ", "
925 << "frequency: " << endpoint->frequency();
mukesh agrawalb4bc57d2011-12-07 01:07:47 +0000926
927 if (endpoint->ssid_string().empty()) {
928 // Don't bother trying to find or create a Service for an Endpoint
929 // without an SSID. We wouldn't be able to connect to it anyway.
930 return;
931 }
932
mukesh agrawalb3857612012-01-18 16:23:29 -0800933 if (endpoint->ssid()[0] == 0) {
934 // Assume that an SSID starting with NULL is bogus/misconfigured,
935 // and filter it out.
936 return;
937 }
938
Paul Stewart3c504012013-01-17 17:49:58 -0800939 provider_->OnEndpointAdded(endpoint);
mukesh agrawalb4bc57d2011-12-07 01:07:47 +0000940
mukesh agrawale9adda12012-02-09 18:33:48 -0800941 // Do this last, to maintain the invariant that any Endpoint we
942 // know about has a corresponding Service.
mukesh agrawalb20776f2012-02-10 16:00:36 -0800943 //
944 // TODO(quiche): Write test to verify correct behavior in the case
945 // where we get multiple BSSAdded events for a single endpoint.
946 // (Old Endpoint's refcount should fall to zero, and old Endpoint
947 // should be destroyed.)
mukesh agrawale9adda12012-02-09 18:33:48 -0800948 endpoint_by_rpcid_[path] = endpoint;
mukesh agrawalb20776f2012-02-10 16:00:36 -0800949 endpoint->Start();
mukesh agrawalb4bc57d2011-12-07 01:07:47 +0000950}
951
952void WiFi::BSSRemovedTask(const ::DBus::Path &path) {
953 EndpointMap::iterator i = endpoint_by_rpcid_.find(path);
954 if (i == endpoint_by_rpcid_.end()) {
955 LOG(WARNING) << "WiFi " << link_name()
956 << " could not find BSS " << path
957 << " to remove.";
958 return;
959 }
960
961 WiFiEndpointRefPtr endpoint = i->second;
962 CHECK(endpoint);
963 endpoint_by_rpcid_.erase(i);
964
Paul Stewart3c504012013-01-17 17:49:58 -0800965 WiFiServiceRefPtr service = provider_->OnEndpointRemoved(endpoint);
966 if (!service) {
967 return;
968 }
969 Error unused_error;
970 RemoveNetworkForService(service, &unused_error);
mukesh agrawalb4bc57d2011-12-07 01:07:47 +0000971
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000972 bool disconnect_service = !service->HasEndpoints() &&
973 (service->IsConnecting() || service->IsConnected());
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000974
975 if (disconnect_service) {
mukesh agrawaldc7b8442012-09-27 13:48:14 -0700976 LOG(INFO) << "Disconnecting from service " << service->unique_name()
977 << ": BSSRemoved";
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000978 DisconnectFrom(service);
979 }
mukesh agrawalb4bc57d2011-12-07 01:07:47 +0000980}
981
Paul Stewartbc6e7392012-05-24 07:07:48 -0700982void WiFi::CertificationTask(
983 const map<string, ::DBus::Variant> &properties) {
984 if (!current_service_) {
985 LOG(ERROR) << "WiFi " << link_name() << " " << __func__
986 << " with no current service.";
987 return;
988 }
989
Paul Stewart735eab52013-03-29 09:19:23 -0700990 string subject;
991 uint32 depth;
992 if (WPASupplicant::ExtractRemoteCertification(properties, &subject, &depth)) {
993 current_service_->AddEAPCertification(subject, depth);
Paul Stewartbc6e7392012-05-24 07:07:48 -0700994 }
Paul Stewartbc6e7392012-05-24 07:07:48 -0700995}
996
Paul Stewartdb0f9172012-11-30 16:48:09 -0800997void WiFi::EAPEventTask(const string &status, const string &parameter) {
Paul Stewartdb0f9172012-11-30 16:48:09 -0800998 if (!current_service_) {
999 LOG(ERROR) << "WiFi " << link_name() << " " << __func__
1000 << " with no current service.";
1001 return;
1002 }
Paul Stewart735eab52013-03-29 09:19:23 -07001003 Service::ConnectFailure failure = Service::kFailureUnknown;
1004 eap_state_handler_->ParseStatus(status, parameter, &failure);
Paul Stewartdb0f9172012-11-30 16:48:09 -08001005 if (failure != Service::kFailureUnknown) {
Paul Stewart735eab52013-03-29 09:19:23 -07001006 // Avoid a reporting failure twice by resetting EAP state handler early.
1007 eap_state_handler_->Reset();
mukesh agrawald4dc0832013-03-25 14:38:26 -07001008 Error unused_error;
mukesh agrawald4dc0832013-03-25 14:38:26 -07001009 current_service_->DisconnectWithFailure(failure, &unused_error);
Paul Stewartdb0f9172012-11-30 16:48:09 -08001010 }
1011}
1012
mukesh agrawal15908392011-11-16 18:29:25 +00001013void WiFi::PropertiesChangedTask(
1014 const map<string, ::DBus::Variant> &properties) {
1015 // TODO(quiche): Handle changes in other properties (e.g. signal
1016 // strength).
1017
1018 // Note that order matters here. In particular, we want to process
1019 // changes in the current BSS before changes in state. This is so
1020 // that we update the state of the correct Endpoint/Service.
1021
1022 map<string, ::DBus::Variant>::const_iterator properties_it =
Paul Stewart0654ece2013-03-26 15:21:26 -07001023 properties.find(WPASupplicant::kInterfacePropertyCurrentBSS);
mukesh agrawal15908392011-11-16 18:29:25 +00001024 if (properties_it != properties.end()) {
1025 CurrentBSSChanged(properties_it->second.reader().get_path());
1026 }
1027
Paul Stewart0654ece2013-03-26 15:21:26 -07001028 properties_it = properties.find(WPASupplicant::kInterfacePropertyState);
mukesh agrawal15908392011-11-16 18:29:25 +00001029 if (properties_it != properties.end()) {
1030 StateChanged(properties_it->second.reader().get_string());
1031 }
1032}
1033
mukesh agrawaldc42bb32011-07-28 10:40:26 -07001034void WiFi::ScanDoneTask() {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001035 SLOG(WiFi, 2) << __func__ << " need_bss_flush_ " << need_bss_flush_;
Wade Guthrie5a4e2ef2013-04-30 12:51:39 -07001036
1037 if (scan_session_) {
1038 // Post |ProgressiveScanTask| so it runs after any |BSSAddedTask|s that have
1039 // been posted. This allows connections on new BSSes to be started before
1040 // we decide whether to abort the progressive scan or continue scanning.
1041 dispatcher()->PostTask(
1042 Bind(&WiFi::ProgressiveScanTask, weak_ptr_factory_.GetWeakPtr()));
1043 } else {
1044 metrics()->NotifyDeviceScanFinished(interface_index());
1045 }
mukesh agrawal5c05b292012-03-07 10:12:52 -08001046 if (need_bss_flush_) {
1047 CHECK(supplicant_interface_proxy_ != NULL);
1048 // Compute |max_age| relative to |resumed_at_|, to account for the
1049 // time taken to scan.
1050 struct timeval now;
1051 uint32_t max_age;
1052 time_->GetTimeMonotonic(&now);
1053 max_age = kMaxBSSResumeAgeSeconds + (now.tv_sec - resumed_at_.tv_sec);
1054 supplicant_interface_proxy_->FlushBSS(max_age);
1055 need_bss_flush_ = false;
1056 }
Paul Stewartd2db2b12013-01-17 13:11:07 -08001057 SetScanPending(false);
mukesh agrawalb66c6462012-05-07 11:45:25 -07001058 StartScanTimer();
mukesh agrawalb54601c2011-06-07 17:39:22 -07001059}
1060
mukesh agrawal32399322011-09-01 10:53:43 -07001061void WiFi::ScanTask() {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001062 SLOG(WiFi, 2) << "WiFi " << link_name() << " scan requested.";
Paul Stewartfae4dae2012-09-13 07:43:32 -07001063 if (!enabled()) {
1064 SLOG(WiFi, 2) << "Ignoring scan request while device is not enabled.";
1065 return;
1066 }
1067 if (!supplicant_present_ || !supplicant_interface_proxy_.get()) {
1068 SLOG(WiFi, 2) << "Ignoring scan request while supplicant is not present.";
1069 return;
1070 }
Christopher Wileyc68c8672012-11-20 16:52:21 -08001071 if ((pending_service_.get() && pending_service_->IsConnecting()) ||
1072 (current_service_.get() && current_service_->IsConnecting())) {
1073 SLOG(WiFi, 2) << "Ignoring scan request while connecting to an AP.";
1074 return;
1075 }
Paul Stewarta41e38d2011-11-11 07:47:29 -08001076 map<string, DBus::Variant> scan_args;
Paul Stewart0654ece2013-03-26 15:21:26 -07001077 scan_args[WPASupplicant::kPropertyScanType].writer().
1078 append_string(WPASupplicant::kScanTypeActive);
Paul Stewartced6a0b2011-11-08 15:32:04 -08001079
Paul Stewart3c504012013-01-17 17:49:58 -08001080 ByteArrays hidden_ssids = provider_->GetHiddenSSIDList();
Paul Stewartced6a0b2011-11-08 15:32:04 -08001081 if (!hidden_ssids.empty()) {
Paul Stewart3c504012013-01-17 17:49:58 -08001082 // TODO(pstew): Devise a better method for time-sharing with SSIDs that do
1083 // not fit in.
Paul Stewart0654ece2013-03-26 15:21:26 -07001084 if (hidden_ssids.size() >= WPASupplicant::kScanMaxSSIDsPerScan) {
Paul Stewart3c504012013-01-17 17:49:58 -08001085 hidden_ssids.erase(
Paul Stewart0654ece2013-03-26 15:21:26 -07001086 hidden_ssids.begin() + WPASupplicant::kScanMaxSSIDsPerScan - 1,
Paul Stewart3c504012013-01-17 17:49:58 -08001087 hidden_ssids.end());
1088 }
1089 // Add Broadcast SSID, signified by an empty ByteArray. If we specify
1090 // SSIDs to wpa_supplicant, we need to explicitly specify the default
1091 // behavior of doing a broadcast probe.
1092 hidden_ssids.push_back(ByteArray());
1093
Paul Stewart0654ece2013-03-26 15:21:26 -07001094 scan_args[WPASupplicant::kPropertyScanSSIDs] =
Paul Stewartced6a0b2011-11-08 15:32:04 -08001095 DBusAdaptor::ByteArraysToVariant(hidden_ssids);
1096 }
1097
Gaurav Shah10109f22011-11-11 20:16:22 -08001098 try {
1099 supplicant_interface_proxy_->Scan(scan_args);
Paul Stewartd2db2b12013-01-17 13:11:07 -08001100 SetScanPending(true);
Ben Chan80326f32012-05-04 17:51:32 -07001101 } catch (const DBus::Error &e) { // NOLINT
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001102 // A scan may fail if, for example, the wpa_supplicant vanishing
1103 // notification is posted after this task has already started running.
1104 LOG(WARNING) << "Scan failed: " << e.what();
Gaurav Shah10109f22011-11-11 20:16:22 -08001105 }
mukesh agrawal32399322011-09-01 10:53:43 -07001106}
1107
Wade Guthrie5a4e2ef2013-04-30 12:51:39 -07001108void WiFi::ProgressiveScanTask() {
1109 SLOG(WiFi, 2) << __func__ << " - scan requested for " << link_name();
1110 if (!enabled()) {
1111 LOG(INFO) << "Ignoring scan request while device is not enabled.";
1112 metrics()->NotifyDeviceScanFinished(interface_index());
1113 return;
1114 }
1115 if (!scan_session_) {
1116 SLOG(WiFi, 2) << "No scan session -- returning";
1117 metrics()->NotifyDeviceScanFinished(interface_index());
1118 return;
1119 }
1120 if (!IsIdle()) {
1121 SLOG(WiFi, 2) << "Ignoring scan request while connecting to an AP.";
1122 scan_session_.reset();
1123 metrics()->NotifyDeviceScanFinished(interface_index());
1124 return;
1125 }
1126 if (scan_session_->HasMoreFrequencies()) {
1127 SLOG(WiFi, 2) << "Initiating a scan -- returning";
1128 SetScanPending(true);
1129 // After us initiating a scan, supplicant will gather the scan results and
1130 // send us zero or more |BSSAdded| events followed by a |ScanDone|.
1131 scan_session_->InitiateScan();
1132 return;
1133 }
1134 LOG(ERROR) << "A complete progressive scan turned-up nothing -- "
1135 << "do a regular scan";
1136 scan_session_.reset();
1137 Scan(kFullScan, NULL);
1138}
1139
1140void WiFi::OnFailedProgressiveScan() {
1141 LOG(ERROR) << "Couldn't issue a scan on " << link_name()
1142 << " -- doing a regular scan";
1143 scan_session_.reset();
1144 Scan(kFullScan, NULL);
1145}
1146
Paul Stewartd2db2b12013-01-17 13:11:07 -08001147void WiFi::SetScanPending(bool pending) {
1148 if (scan_pending_ != pending) {
1149 scan_pending_ = pending;
1150 adaptor()->EmitBoolChanged(flimflam::kScanningProperty, pending);
1151 }
1152}
1153
Albert Chaulk0e1cdea2013-02-27 15:32:55 -08001154string WiFi::GetServiceLeaseName(const WiFiService &service) {
1155 return service.GetStorageIdentifier();
1156}
1157
1158void WiFi::DestroyServiceLease(const WiFiService &service) {
1159 DestroyIPConfigLease(GetServiceLeaseName(service));
1160}
1161
mukesh agrawal15908392011-11-16 18:29:25 +00001162void WiFi::StateChanged(const string &new_state) {
1163 const string old_state = supplicant_state_;
mukesh agrawal7ec71312011-11-10 02:08:26 +00001164 supplicant_state_ = new_state;
mukesh agrawal15908392011-11-16 18:29:25 +00001165 LOG(INFO) << "WiFi " << link_name() << " " << __func__ << " "
1166 << old_state << " -> " << new_state;
1167
1168 WiFiService *affected_service;
1169 // Identify the service to which the state change applies. If
1170 // |pending_service_| is non-NULL, then the state change applies to
1171 // |pending_service_|. Otherwise, it applies to |current_service_|.
1172 //
1173 // This policy is driven by the fact that the |pending_service_|
1174 // doesn't become the |current_service_| until wpa_supplicant
1175 // reports a CurrentBSS change to the |pending_service_|. And the
mukesh agrawalc01f3982012-01-24 13:48:39 -08001176 // CurrentBSS change won't be reported until the |pending_service_|
Paul Stewart0654ece2013-03-26 15:21:26 -07001177 // reaches the WPASupplicant::kInterfaceStateCompleted state.
mukesh agrawal15908392011-11-16 18:29:25 +00001178 affected_service =
1179 pending_service_.get() ? pending_service_.get() : current_service_.get();
1180 if (!affected_service) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001181 SLOG(WiFi, 2) << "WiFi " << link_name() << " " << __func__
1182 << " with no service";
mukesh agrawal15908392011-11-16 18:29:25 +00001183 return;
1184 }
1185
Paul Stewart0654ece2013-03-26 15:21:26 -07001186 if (new_state == WPASupplicant::kInterfaceStateCompleted) {
Paul Stewart44663922012-07-30 11:03:03 -07001187 if (affected_service->IsConnected()) {
1188 StopReconnectTimer();
Christopher Wiley5519e9e2013-01-08 16:55:56 -08001189 EnableHighBitrates();
Christopher Wiley8f81e2a2012-10-17 16:51:32 -07001190 } else if (has_already_completed_) {
1191 LOG(INFO) << link_name() << " L3 configuration already started.";
Paul Stewart44663922012-07-30 11:03:03 -07001192 } else if (AcquireIPConfigWithLeaseName(
Albert Chaulk0e1cdea2013-02-27 15:32:55 -08001193 GetServiceLeaseName(*affected_service))) {
Paul Stewartd408fdf2012-05-07 17:15:57 -07001194 LOG(INFO) << link_name() << " is up; started L3 configuration.";
mukesh agrawalc01f3982012-01-24 13:48:39 -08001195 affected_service->SetState(Service::kStateConfiguring);
1196 } else {
1197 LOG(ERROR) << "Unable to acquire DHCP config.";
1198 }
Christopher Wiley8f81e2a2012-10-17 16:51:32 -07001199 has_already_completed_ = true;
Paul Stewart0654ece2013-03-26 15:21:26 -07001200 } else if (new_state == WPASupplicant::kInterfaceStateAssociated) {
mukesh agrawal15908392011-11-16 18:29:25 +00001201 affected_service->SetState(Service::kStateAssociating);
Paul Stewart0654ece2013-03-26 15:21:26 -07001202 } else if (new_state == WPASupplicant::kInterfaceStateAuthenticating ||
1203 new_state == WPASupplicant::kInterfaceStateAssociating ||
1204 new_state == WPASupplicant::kInterfaceState4WayHandshake ||
1205 new_state == WPASupplicant::kInterfaceStateGroupHandshake) {
mukesh agrawal15908392011-11-16 18:29:25 +00001206 // Ignore transitions into these states from Completed, to avoid
1207 // bothering the user when roaming, or re-keying.
Paul Stewart0654ece2013-03-26 15:21:26 -07001208 if (old_state != WPASupplicant::kInterfaceStateCompleted)
mukesh agrawal15908392011-11-16 18:29:25 +00001209 affected_service->SetState(Service::kStateAssociating);
1210 // TOOD(quiche): On backwards transitions, we should probably set
1211 // a timeout for getting back into the completed state. At present,
1212 // we depend on wpa_supplicant eventually reporting that CurrentBSS
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001213 // has changed. But there may be cases where that signal is not sent.
mukesh agrawal15908392011-11-16 18:29:25 +00001214 // (crosbug.com/23207)
Paul Stewart0654ece2013-03-26 15:21:26 -07001215 } else if (new_state == WPASupplicant::kInterfaceStateDisconnected &&
Paul Stewart44663922012-07-30 11:03:03 -07001216 affected_service == current_service_ &&
1217 affected_service->IsConnected()) {
1218 // This means that wpa_supplicant failed in a re-connect attempt, but
1219 // may still be reconnecting. Give wpa_supplicant a limited amount of
1220 // time to transition out this condition by either connecting or changing
1221 // CurrentBSS.
1222 StartReconnectTimer();
mukesh agrawal15908392011-11-16 18:29:25 +00001223 } else {
1224 // Other transitions do not affect Service state.
1225 //
1226 // Note in particular that we ignore a State change into
1227 // kInterfaceStateDisconnected, in favor of observing the corresponding
1228 // change in CurrentBSS.
1229 }
mukesh agrawal7ec71312011-11-10 02:08:26 +00001230}
1231
Paul Stewart1369c2b2013-01-11 05:41:26 -08001232bool WiFi::SuspectCredentials(
1233 const WiFiService &service, Service::ConnectFailure *failure) const {
Paul Stewart1369c2b2013-01-11 05:41:26 -08001234 if (service.IsSecurityMatch(flimflam::kSecurityPsk)) {
Paul Stewart0654ece2013-03-26 15:21:26 -07001235 if (supplicant_state_ == WPASupplicant::kInterfaceState4WayHandshake &&
Paul Stewart1369c2b2013-01-11 05:41:26 -08001236 !service.has_ever_connected()) {
1237 if (failure) {
1238 *failure = Service::kFailureBadPassphrase;
1239 }
1240 return true;
1241 }
1242 } else if (service.IsSecurityMatch(flimflam::kSecurity8021x)) {
Paul Stewart735eab52013-03-29 09:19:23 -07001243 if (eap_state_handler_->is_eap_in_progress() &&
1244 !service.has_ever_connected()) {
Paul Stewart1369c2b2013-01-11 05:41:26 -08001245 if (failure) {
1246 *failure = Service::kFailureEAPAuthentication;
1247 }
1248 return true;
1249 }
mukesh agrawalcf24a242012-05-21 16:46:11 -07001250 }
1251
Paul Stewart1369c2b2013-01-11 05:41:26 -08001252 return false;
mukesh agrawalcf24a242012-05-21 16:46:11 -07001253}
1254
mukesh agrawal16bc1b82012-02-09 18:38:26 -08001255// static
1256bool WiFi::SanitizeSSID(string *ssid) {
1257 CHECK(ssid);
1258
1259 size_t ssid_len = ssid->length();
1260 size_t i;
1261 bool changed = false;
1262
Gary Morainac1bdb42012-02-16 17:42:29 -08001263 for (i = 0; i < ssid_len; ++i) {
mukesh agrawal16bc1b82012-02-09 18:38:26 -08001264 if (!g_ascii_isprint((*ssid)[i])) {
1265 (*ssid)[i] = '?';
1266 changed = true;
1267 }
1268 }
1269
1270 return changed;
1271}
1272
Darin Petkov50cb78a2013-02-06 16:17:49 +01001273// static
1274string WiFi::LogSSID(const string &ssid) {
1275 string out;
1276 for (string::const_iterator it = ssid.begin(); it != ssid.end(); ++it) {
1277 // Replace '[' and ']' (in addition to non-printable characters) so that
1278 // it's easy to match the right substring through a non-greedy regex.
1279 if (*it == '[' || *it == ']' || !g_ascii_isprint(*it)) {
1280 base::StringAppendF(&out, "\\x%02x", *it);
1281 } else {
1282 out += *it;
1283 }
1284 }
1285 return StringPrintf("[SSID=%s]", out.c_str());
1286}
1287
Paul Stewart3c508e12012-08-09 11:40:06 -07001288void WiFi::OnLinkMonitorFailure() {
1289 // If we have never found the gateway, let's be conservative and not
1290 // do anything, in case this network topology does not have a gateway.
1291 if (!link_monitor()->IsGatewayFound()) {
1292 LOG(INFO) << "In " << __func__ << "(): "
1293 << "Skipping reassociate since gateway was never found.";
1294 return;
1295 }
1296
1297 if (!supplicant_present_) {
1298 LOG(ERROR) << "In " << __func__ << "(): "
1299 << "wpa_supplicant is not present. Cannot reassociate.";
1300 return;
1301 }
1302
1303 try {
Christopher Wileye0b2a012012-10-31 13:11:27 -07001304 // This will force a transition out of connected, if we are actually
1305 // connected.
Paul Stewart3c508e12012-08-09 11:40:06 -07001306 supplicant_interface_proxy_->Reassociate();
Christopher Wileye0b2a012012-10-31 13:11:27 -07001307 // If we don't eventually get a transition back into a connected state,
1308 // there is something wrong.
1309 StartReconnectTimer();
Paul Stewart3c508e12012-08-09 11:40:06 -07001310 LOG(INFO) << "In " << __func__ << "(): Called Reassociate().";
1311 } catch (const DBus::Error &e) { // NOLINT
1312 LOG(ERROR) << "In " << __func__ << "(): failed to call Reassociate().";
1313 return;
1314 }
1315}
1316
Arman Ugurayed8e6102012-11-29 14:47:20 -08001317bool WiFi::ShouldUseArpGateway() const {
1318 return true;
1319}
1320
Paul Stewart3c504012013-01-17 17:49:58 -08001321void WiFi::DisassociateFromService(const WiFiServiceRefPtr &service) {
1322 DisconnectFrom(service);
1323 if (service == selected_service()) {
1324 DropConnection();
1325 }
1326 Error unused_error;
1327 RemoveNetworkForService(service, &unused_error);
1328}
1329
Gaurav Shah6d2c72d2012-10-16 16:30:44 -07001330vector<GeolocationInfo> WiFi::GetGeolocationObjects() const {
1331 vector<GeolocationInfo> objects;
1332 for (EndpointMap::const_iterator it = endpoint_by_rpcid_.begin();
1333 it != endpoint_by_rpcid_.end();
1334 ++it) {
1335 GeolocationInfo geoinfo;
1336 WiFiEndpointRefPtr endpoint = it->second;
1337 geoinfo.AddField(kGeoMacAddressProperty, endpoint->bssid_string());
1338 geoinfo.AddField(kGeoSignalStrengthProperty,
1339 StringPrintf("%d", endpoint->signal_strength()));
1340 geoinfo.AddField(
1341 kGeoChannelProperty,
1342 StringPrintf("%d",
1343 Metrics::WiFiFrequencyToChannel(endpoint->frequency())));
1344 // TODO(gauravsh): Include age field. crosbug.com/35445
1345 objects.push_back(geoinfo);
1346 }
1347 return objects;
1348}
1349
mukesh agrawal4d0401c2012-01-06 16:05:31 -08001350void WiFi::HelpRegisterDerivedInt32(
1351 PropertyStore *store,
1352 const string &name,
1353 int32(WiFi::*get)(Error *error),
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001354 bool(WiFi::*set)(const int32 &value, Error *error)) {
mukesh agrawal4d0401c2012-01-06 16:05:31 -08001355 store->RegisterDerivedInt32(
1356 name,
1357 Int32Accessor(new CustomAccessor<WiFi, int32>(this, get, set)));
1358}
1359
mukesh agrawal4d0401c2012-01-06 16:05:31 -08001360void WiFi::HelpRegisterDerivedUint16(
1361 PropertyStore *store,
1362 const string &name,
1363 uint16(WiFi::*get)(Error *error),
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001364 bool(WiFi::*set)(const uint16 &value, Error *error)) {
mukesh agrawal4d0401c2012-01-06 16:05:31 -08001365 store->RegisterDerivedUint16(
1366 name,
1367 Uint16Accessor(new CustomAccessor<WiFi, uint16>(this, get, set)));
1368}
1369
mukesh agrawal2f9df4e2012-08-08 12:29:20 -07001370void WiFi::OnAfterResume() {
mukesh agrawal5c05b292012-03-07 10:12:52 -08001371 LOG(INFO) << __func__;
mukesh agrawal2f9df4e2012-08-08 12:29:20 -07001372 Device::OnAfterResume(); // May refresh ipconfig_
mukesh agrawal5c05b292012-03-07 10:12:52 -08001373
mukesh agrawal2f9df4e2012-08-08 12:29:20 -07001374 // We want to flush the BSS cache, but we don't want to conflict
1375 // with a running scan or an active connection attempt. So record
1376 // the need to flush, and take care of flushing when the next scan
1377 // completes.
1378 //
1379 // Note that supplicant will automatically expire old cache
1380 // entries (after, e.g., a BSS is not found in two consecutive
1381 // scans). However, our explicit flush accelerates re-association
1382 // in cases where a BSS disappeared while we were asleep. (See,
1383 // e.g. WiFiRoaming.005SuspendRoam.)
1384 time_->GetTimeMonotonic(&resumed_at_);
1385 need_bss_flush_ = true;
1386
1387 if (!scan_pending_ && IsIdle()) {
1388 // Not scanning/connecting/connected, so let's get things rolling.
Wade Guthrie68d41092013-04-02 12:56:02 -07001389 Scan(kProgressiveScan, NULL);
mukesh agrawal2f9df4e2012-08-08 12:29:20 -07001390 } else {
1391 SLOG(WiFi, 1) << __func__
1392 << " skipping scan, already scanning or connected.";
Gary Morainac1bdb42012-02-16 17:42:29 -08001393 }
1394}
1395
Christopher Wiley5519e9e2013-01-08 16:55:56 -08001396void WiFi::OnConnected() {
1397 Device::OnConnected();
1398 EnableHighBitrates();
1399}
1400
Paul Stewarte369ece2012-05-22 09:11:03 -07001401void WiFi::RestartFastScanAttempts() {
1402 fast_scans_remaining_ = kNumFastScanAttempts;
1403 StartScanTimer();
1404}
1405
mukesh agrawalb66c6462012-05-07 11:45:25 -07001406void WiFi::StartScanTimer() {
1407 if (scan_interval_seconds_ == 0) {
1408 StopScanTimer();
1409 return;
1410 }
1411 scan_timer_callback_.Reset(
1412 Bind(&WiFi::ScanTimerHandler, weak_ptr_factory_.GetWeakPtr()));
Paul Stewarte369ece2012-05-22 09:11:03 -07001413 // Repeat the first few scans after disconnect relatively quickly so we
1414 // have reasonable trust that no APs we are looking for are present.
1415 dispatcher()->PostDelayedTask(scan_timer_callback_.callback(),
1416 fast_scans_remaining_ > 0 ?
1417 kFastScanIntervalSeconds * 1000 : scan_interval_seconds_ * 1000);
mukesh agrawalb66c6462012-05-07 11:45:25 -07001418}
1419
1420void WiFi::StopScanTimer() {
1421 scan_timer_callback_.Cancel();
1422}
1423
1424void WiFi::ScanTimerHandler() {
1425 SLOG(WiFi, 2) << "WiFi Device " << link_name() << ": " << __func__;
1426 if (IsIdle() && !scan_pending_) {
Wade Guthrie68d41092013-04-02 12:56:02 -07001427 Scan(kProgressiveScan, NULL);
Paul Stewarte369ece2012-05-22 09:11:03 -07001428 if (fast_scans_remaining_ > 0) {
1429 --fast_scans_remaining_;
1430 }
mukesh agrawalb66c6462012-05-07 11:45:25 -07001431 }
1432 StartScanTimer();
1433}
1434
Paul Stewart2b05e622012-07-13 20:38:44 -07001435void WiFi::StartPendingTimer() {
1436 pending_timeout_callback_.Reset(
1437 Bind(&WiFi::PendingTimeoutHandler, weak_ptr_factory_.GetWeakPtr()));
1438 dispatcher()->PostDelayedTask(pending_timeout_callback_.callback(),
1439 kPendingTimeoutSeconds * 1000);
1440}
1441
1442void WiFi::StopPendingTimer() {
1443 pending_timeout_callback_.Cancel();
1444}
1445
1446void WiFi::SetPendingService(const WiFiServiceRefPtr &service) {
Paul Stewartff96a842012-08-13 15:59:10 -07001447 SLOG(WiFi, 2) << "WiFi " << link_name() << " setting pending service to "
Darin Petkov457728b2013-01-09 09:49:08 +01001448 << (service ? service->unique_name(): "NULL");
Paul Stewart2b05e622012-07-13 20:38:44 -07001449 if (service) {
1450 service->SetState(Service::kStateAssociating);
1451 StartPendingTimer();
1452 } else if (pending_service_) {
1453 StopPendingTimer();
1454 }
1455 pending_service_ = service;
1456}
1457
1458void WiFi::PendingTimeoutHandler() {
mukesh agrawald4dc0832013-03-25 14:38:26 -07001459 Error unused_error;
Paul Stewart2b05e622012-07-13 20:38:44 -07001460 LOG(INFO) << "WiFi Device " << link_name() << ": " << __func__;
1461 CHECK(pending_service_);
mukesh agrawald4dc0832013-03-25 14:38:26 -07001462 pending_service_->DisconnectWithFailure(
1463 Service::kFailureOutOfRange, &unused_error);
Paul Stewart17d90652013-04-04 15:09:11 -07001464
1465 // A hidden service may have no endpoints, since wpa_supplicant
1466 // failed to attain a CurrentBSS. If so, the service has no
1467 // reference to |this| device and cannot call WiFi::DisconnectFrom()
1468 // to reset pending_service_. In this case, we must perform the
1469 // disconnect here ourselves.
1470 if (pending_service_) {
1471 CHECK(!pending_service_->HasEndpoints());
1472 LOG(INFO) << "Hidden service was not found.";
1473 DisconnectFrom(pending_service_);
1474 }
Paul Stewart2b05e622012-07-13 20:38:44 -07001475}
1476
Paul Stewart44663922012-07-30 11:03:03 -07001477void WiFi::StartReconnectTimer() {
Paul Stewart1aff7302012-08-04 20:04:47 -07001478 if (!reconnect_timeout_callback_.IsCancelled()) {
1479 LOG(INFO) << "WiFi Device " << link_name() << ": " << __func__
1480 << ": reconnect timer already running.";
1481 return;
1482 }
Paul Stewart44663922012-07-30 11:03:03 -07001483 LOG(INFO) << "WiFi Device " << link_name() << ": " << __func__;
1484 reconnect_timeout_callback_.Reset(
1485 Bind(&WiFi::ReconnectTimeoutHandler, weak_ptr_factory_.GetWeakPtr()));
1486 dispatcher()->PostDelayedTask(reconnect_timeout_callback_.callback(),
1487 kReconnectTimeoutSeconds * 1000);
1488}
1489
1490void WiFi::StopReconnectTimer() {
1491 SLOG(WiFi, 2) << "WiFi Device " << link_name() << ": " << __func__;
1492 reconnect_timeout_callback_.Cancel();
1493}
1494
1495void WiFi::ReconnectTimeoutHandler() {
1496 LOG(INFO) << "WiFi Device " << link_name() << ": " << __func__;
Paul Stewart1aff7302012-08-04 20:04:47 -07001497 reconnect_timeout_callback_.Cancel();
Paul Stewart44663922012-07-30 11:03:03 -07001498 CHECK(current_service_);
1499 current_service_->SetFailureSilent(Service::kFailureConnect);
1500 DisconnectFrom(current_service_);
1501}
1502
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001503void WiFi::OnSupplicantAppear(const string &/*owner*/) {
1504 LOG(INFO) << "WPA supplicant appeared.";
1505 if (supplicant_present_) {
Darin Petkov9cd7ca12012-07-03 11:06:40 +02001506 // Restart the WiFi device if it's started already. This will reset the
1507 // state and connect the device to the new WPA supplicant instance.
1508 if (enabled()) {
1509 Restart();
1510 }
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001511 return;
1512 }
1513 supplicant_present_ = true;
1514 ConnectToSupplicant();
1515}
1516
1517void WiFi::OnSupplicantVanish() {
1518 LOG(INFO) << "WPA supplicant vanished.";
1519 if (!supplicant_present_) {
1520 return;
1521 }
1522 supplicant_present_ = false;
1523 // Restart the WiFi device if it's started already. This will effectively
1524 // suspend the device until the WPA supplicant reappears.
1525 if (enabled()) {
1526 Restart();
1527 }
1528}
1529
Paul Stewart5581d072012-12-17 17:30:20 -08001530void WiFi::OnWiFiDebugScopeChanged(bool enabled) {
1531 SLOG(WiFi, 2) << "WiFi debug scope changed; enable is now " << enabled;
1532 if (!supplicant_process_proxy_.get()) {
1533 SLOG(WiFi, 2) << "Suplicant process proxy not present.";
1534 return;
1535 }
1536 string current_level;
1537 try {
1538 current_level = supplicant_process_proxy_->GetDebugLevel();
1539 } catch (const DBus::Error &e) { // NOLINT
1540 LOG(ERROR) << __func__ << ": Failed to get wpa_supplicant debug level.";
1541 return;
1542 }
1543
Paul Stewart0654ece2013-03-26 15:21:26 -07001544 if (current_level != WPASupplicant::kDebugLevelInfo &&
1545 current_level != WPASupplicant::kDebugLevelDebug) {
Paul Stewart5581d072012-12-17 17:30:20 -08001546 SLOG(WiFi, 2) << "WiFi debug level is currently "
1547 << current_level
1548 << "; assuming that it is being controlled elsewhere.";
1549 return;
1550 }
Paul Stewart0654ece2013-03-26 15:21:26 -07001551 string new_level = enabled ? WPASupplicant::kDebugLevelDebug :
1552 WPASupplicant::kDebugLevelInfo;
Paul Stewart5581d072012-12-17 17:30:20 -08001553
1554 if (new_level == current_level) {
1555 SLOG(WiFi, 2) << "WiFi debug level is already the desired level "
1556 << current_level;
1557 return;
1558 }
1559
1560 try {
1561 supplicant_process_proxy_->SetDebugLevel(new_level);
1562 } catch (const DBus::Error &e) { // NOLINT
1563 LOG(ERROR) << __func__ << ": Failed to set wpa_supplicant debug level.";
1564 }
1565}
1566
Paul Stewarta47c3c62012-12-18 12:14:29 -08001567void WiFi::SetConnectionDebugging(bool enabled) {
1568 if (is_debugging_connection_ == enabled) {
1569 return;
1570 }
1571 OnWiFiDebugScopeChanged(
1572 enabled ||
1573 ScopeLogger::GetInstance()->IsScopeEnabled(ScopeLogger::kWiFi));
1574 is_debugging_connection_ = enabled;
1575}
1576
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001577void WiFi::ConnectToSupplicant() {
1578 LOG(INFO) << link_name() << ": " << (enabled() ? "enabled" : "disabled")
1579 << " supplicant: "
1580 << (supplicant_present_ ? "present" : "absent")
1581 << " proxy: "
1582 << (supplicant_process_proxy_.get() ? "non-null" : "null");
1583 if (!enabled() || !supplicant_present_ || supplicant_process_proxy_.get()) {
1584 return;
1585 }
1586 supplicant_process_proxy_.reset(
1587 proxy_factory_->CreateSupplicantProcessProxy(
Paul Stewart0654ece2013-03-26 15:21:26 -07001588 WPASupplicant::kDBusPath, WPASupplicant::kDBusAddr));
Paul Stewart5581d072012-12-17 17:30:20 -08001589 OnWiFiDebugScopeChanged(
1590 ScopeLogger::GetInstance()->IsScopeEnabled(ScopeLogger::kWiFi));
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001591 ::DBus::Path interface_path;
1592 try {
1593 map<string, DBus::Variant> create_interface_args;
Paul Stewart0654ece2013-03-26 15:21:26 -07001594 create_interface_args[WPASupplicant::kInterfacePropertyName].writer().
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001595 append_string(link_name().c_str());
Paul Stewart0654ece2013-03-26 15:21:26 -07001596 create_interface_args[WPASupplicant::kInterfacePropertyDriver].writer().
1597 append_string(WPASupplicant::kDriverNL80211);
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001598 create_interface_args[
Paul Stewart0654ece2013-03-26 15:21:26 -07001599 WPASupplicant::kInterfacePropertyConfigFile].writer().
Paul Stewart196f50f2013-03-27 18:02:11 -07001600 append_string(WPASupplicant::kSupplicantConfPath);
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001601 interface_path =
1602 supplicant_process_proxy_->CreateInterface(create_interface_args);
1603 } catch (const DBus::Error &e) { // NOLINT
Paul Stewart0654ece2013-03-26 15:21:26 -07001604 if (!strcmp(e.name(), WPASupplicant::kErrorInterfaceExists)) {
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001605 interface_path =
1606 supplicant_process_proxy_->GetInterface(link_name());
1607 // TODO(quiche): Is it okay to crash here, if device is missing?
1608 } else {
Paul Stewartb80c81c2012-06-28 13:05:45 -07001609 LOG(ERROR) << __func__ << ": Failed to create interface with supplicant.";
1610 return;
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001611 }
1612 }
1613
1614 supplicant_interface_proxy_.reset(
1615 proxy_factory_->CreateSupplicantInterfaceProxy(
Paul Stewart0654ece2013-03-26 15:21:26 -07001616 this, interface_path, WPASupplicant::kDBusAddr));
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001617
1618 RTNLHandler::GetInstance()->SetInterfaceFlags(interface_index(), IFF_UP,
1619 IFF_UP);
1620 // TODO(quiche) Set ApScan=1 and BSSExpireAge=190, like flimflam does?
1621
1622 // Clear out any networks that might previously have been configured
1623 // for this interface.
1624 supplicant_interface_proxy_->RemoveAllNetworks();
1625
1626 // Flush interface's BSS cache, so that we get BSSAdded signals for
1627 // all BSSes (not just new ones since the last scan).
1628 supplicant_interface_proxy_->FlushBSS(0);
1629
1630 try {
1631 // TODO(pstew): Disable fast_reauth until supplicant can properly deal
1632 // with RADIUS servers that respond strangely to such requests.
1633 // crosbug.com/25630
1634 supplicant_interface_proxy_->SetFastReauth(false);
1635 } catch (const DBus::Error &e) { // NOLINT
Christopher Wiley5519e9e2013-01-08 16:55:56 -08001636 LOG(ERROR) << "Failed to disable fast_reauth. "
1637 << "May be running an older version of wpa_supplicant.";
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001638 }
1639
1640 try {
1641 // Helps with passing WiFiRomaing.001SSIDSwitchBack.
1642 supplicant_interface_proxy_->SetScanInterval(kRescanIntervalSeconds);
1643 } catch (const DBus::Error &e) { // NOLINT
Christopher Wiley5519e9e2013-01-08 16:55:56 -08001644 LOG(ERROR) << "Failed to set scan_interval. "
1645 << "May be running an older version of wpa_supplicant.";
1646 }
1647
1648 try {
1649 supplicant_interface_proxy_->SetDisableHighBitrates(true);
1650 } catch (const DBus::Error &e) { // NOLINT
1651 LOG(ERROR) << "Failed to disable high bitrates. "
1652 << "May be running an older version of wpa_supplicant.";
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001653 }
1654
Wade Guthrie68d41092013-04-02 12:56:02 -07001655 Scan(kProgressiveScan, NULL);
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001656 StartScanTimer();
1657}
1658
Christopher Wiley5519e9e2013-01-08 16:55:56 -08001659void WiFi::EnableHighBitrates() {
1660 LOG(INFO) << "Enabling high bitrates.";
1661 try {
1662 supplicant_interface_proxy_->EnableHighBitrates();
1663 } catch (const DBus::Error &e) { // NOLINT
1664 LOG(ERROR) << "exception while enabling high rates: " << e.what();
1665 }
1666}
1667
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001668void WiFi::Restart() {
1669 LOG(INFO) << link_name() << " restarting.";
1670 WiFiRefPtr me = this; // Make sure we don't get destructed.
1671 // Go through the manager rather than starting and stopping the device
1672 // directly so that the device can be configured with the profile.
1673 manager()->DeregisterDevice(me);
1674 manager()->RegisterDevice(me);
1675}
1676
Wade Guthrie92d06362013-04-25 15:41:30 -07001677void WiFi::ConfigureScanFrequencies() {
1678 GetWiphyMessage get_wiphy;
1679 get_wiphy.attributes()->SetU32AttributeValue(NL80211_ATTR_IFINDEX,
1680 interface_index());
Wade Guthrie7347bf22013-04-30 11:21:51 -07001681 netlink_manager_->SendNl80211Message(
1682 &get_wiphy,
1683 Bind(&WiFi::OnNewWiphy, weak_ptr_factory_.GetWeakPtr()),
1684 Bind(&NetlinkManager::OnNetlinkMessageError));
Wade Guthrie92d06362013-04-25 15:41:30 -07001685}
1686
Wade Guthrie7347bf22013-04-30 11:21:51 -07001687void WiFi::OnNewWiphy(const Nl80211Message &nl80211_message) {
Wade Guthrie92d06362013-04-25 15:41:30 -07001688 // Verify NL80211_CMD_NEW_WIPHY
Wade Guthrie7347bf22013-04-30 11:21:51 -07001689 if (nl80211_message.command() != NewWiphyMessage::kCommand) {
Wade Guthrie92d06362013-04-25 15:41:30 -07001690 LOG(ERROR) << "Received unexpected command:"
Wade Guthrie7347bf22013-04-30 11:21:51 -07001691 << nl80211_message.command();
Wade Guthrie92d06362013-04-25 15:41:30 -07001692 return;
1693 }
1694
1695 // The attributes, for this message, are complicated.
1696 // NL80211_ATTR_BANDS contains an array of bands...
1697 AttributeListConstRefPtr wiphy_bands;
Wade Guthrie7347bf22013-04-30 11:21:51 -07001698 if (!nl80211_message.const_attributes()->ConstGetNestedAttributeList(
Wade Guthrie92d06362013-04-25 15:41:30 -07001699 NL80211_ATTR_WIPHY_BANDS, &wiphy_bands)) {
1700 LOG(ERROR) << "NL80211_CMD_NEW_WIPHY had no NL80211_ATTR_WIPHY_BANDS";
1701 return;
1702 }
1703
1704 AttributeIdIterator band_iter(*wiphy_bands);
1705 for (; !band_iter.AtEnd(); band_iter.Advance()) {
1706 AttributeListConstRefPtr wiphy_band;
1707 if (!wiphy_bands->ConstGetNestedAttributeList(band_iter.GetId(),
1708 &wiphy_band)) {
1709 LOG(WARNING) << "WiFi band " << band_iter.GetId() << " not found";
1710 continue;
1711 }
1712
1713 // ...Each band has a FREQS attribute...
1714 AttributeListConstRefPtr frequencies;
1715 if (!wiphy_band->ConstGetNestedAttributeList(NL80211_BAND_ATTR_FREQS,
1716 &frequencies)) {
1717 LOG(ERROR) << "BAND " << band_iter.GetId()
1718 << " had no 'frequencies' attribute";
1719 continue;
1720 }
1721
1722 // ...And each FREQS attribute contains an array of information about the
1723 // frequency...
1724 AttributeIdIterator freq_iter(*frequencies);
1725 for (; !freq_iter.AtEnd(); freq_iter.Advance()) {
1726 AttributeListConstRefPtr frequency;
1727 if (frequencies->ConstGetNestedAttributeList(freq_iter.GetId(),
1728 &frequency)) {
1729 // ...Including the frequency, itself (the part we want).
1730 uint32_t frequency_value = 0;
1731 if (frequency->GetU32AttributeValue(NL80211_FREQUENCY_ATTR_FREQ,
1732 &frequency_value)) {
1733 SLOG(WiFi, 5) << "Found frequency[" << freq_iter.GetId()
1734 << "] = " << frequency_value;
1735 all_scan_frequencies_.insert(frequency_value);
1736 }
1737 }
1738 }
1739 }
1740}
1741
Paul Stewartb50f0b92011-05-16 16:31:42 -07001742} // namespace shill