blob: 2e35cedd7bb66ec8606c38b36193b2e489560618 [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>
mukesh agrawalab87ea42011-05-18 11:44:49 -070013#include <map>
Paul Stewartb50f0b92011-05-16 16:31:42 -070014#include <string>
mukesh agrawalab87ea42011-05-18 11:44:49 -070015#include <vector>
Paul Stewartb50f0b92011-05-16 16:31:42 -070016
Eric Shienbrood3e20a232012-02-16 11:35:56 -050017#include <base/bind.h>
mukesh agrawal15908392011-11-16 18:29:25 +000018#include <base/stringprintf.h>
mukesh agrawal7a4e4002011-09-06 11:26:05 -070019#include <base/string_util.h>
Chris Masoneb925cc82011-06-22 15:39:57 -070020#include <chromeos/dbus/service_constants.h>
mukesh agrawal16bc1b82012-02-09 18:38:26 -080021#include <glib.h>
Paul Stewartb50f0b92011-05-16 16:31:42 -070022
23#include "shill/control_interface.h"
Paul Stewartced6a0b2011-11-08 15:32:04 -080024#include "shill/dbus_adaptor.h"
Paul Stewartb50f0b92011-05-16 16:31:42 -070025#include "shill/device.h"
mukesh agrawal7a4e4002011-09-06 11:26:05 -070026#include "shill/error.h"
Gaurav Shah6d2c72d2012-10-16 16:30:44 -070027#include "shill/geolocation_info.h"
mukesh agrawal7a4e4002011-09-06 11:26:05 -070028#include "shill/ieee80211.h"
Paul Stewart3c508e12012-08-09 11:40:06 -070029#include "shill/link_monitor.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070030#include "shill/logging.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070031#include "shill/manager.h"
Thieu Le67370f62012-02-14 23:01:42 +000032#include "shill/metrics.h"
Wade Guthriebb9fca22013-04-10 17:21:42 -070033#include "shill/netlink_manager.h"
Wade Guthriebee87c22013-03-06 11:00:46 -080034#include "shill/nl80211_message.h"
mukesh agrawal4d0401c2012-01-06 16:05:31 -080035#include "shill/property_accessor.h"
Darin Petkovd1967262011-07-18 14:55:18 -070036#include "shill/proxy_factory.h"
Eric Shienbrood9a245532012-03-07 14:20:39 -050037#include "shill/rtnl_handler.h"
Paul Stewart5581d072012-12-17 17:30:20 -080038#include "shill/scope_logger.h"
mukesh agrawal5c05b292012-03-07 10:12:52 -080039#include "shill/shill_time.h"
Paul Stewart735eab52013-03-29 09:19:23 -070040#include "shill/supplicant_eap_state_handler.h"
mukesh agrawalaf571952011-07-14 14:31:12 -070041#include "shill/supplicant_interface_proxy_interface.h"
Paul Stewart835934a2012-12-06 19:27:09 -080042#include "shill/supplicant_network_proxy_interface.h"
mukesh agrawalaf571952011-07-14 14:31:12 -070043#include "shill/supplicant_process_proxy_interface.h"
Gaurav Shah435de2c2011-11-17 19:01:07 -080044#include "shill/technology.h"
mukesh agrawalb54601c2011-06-07 17:39:22 -070045#include "shill/wifi_endpoint.h"
Paul Stewart3c504012013-01-17 17:49:58 -080046#include "shill/wifi_provider.h"
mukesh agrawalb54601c2011-06-07 17:39:22 -070047#include "shill/wifi_service.h"
mukesh agrawal6e277772011-09-29 15:04:23 -070048#include "shill/wpa_supplicant.h"
Paul Stewartb50f0b92011-05-16 16:31:42 -070049
Eric Shienbrood3e20a232012-02-16 11:35:56 -050050using base::Bind;
mukesh agrawal15908392011-11-16 18:29:25 +000051using base::StringPrintf;
mukesh agrawal7a4e4002011-09-06 11:26:05 -070052using std::map;
mukesh agrawalab87ea42011-05-18 11:44:49 -070053using std::string;
mukesh agrawal7a4e4002011-09-06 11:26:05 -070054using std::vector;
mukesh agrawalab87ea42011-05-18 11:44:49 -070055
Paul Stewartb50f0b92011-05-16 16:31:42 -070056namespace shill {
mukesh agrawal7a4e4002011-09-06 11:26:05 -070057
58// statics
mukesh agrawal4d0401c2012-01-06 16:05:31 -080059const char *WiFi::kDefaultBgscanMethod =
Paul Stewart0654ece2013-03-26 15:21:26 -070060 WPASupplicant::kNetworkBgscanMethodSimple;
mukesh agrawal4d0401c2012-01-06 16:05:31 -080061const uint16 WiFi::kDefaultBgscanShortIntervalSeconds = 30;
62const int32 WiFi::kDefaultBgscanSignalThresholdDbm = -50;
63const uint16 WiFi::kDefaultScanIntervalSeconds = 180;
Darin Petkov4a66cc52012-06-15 10:08:29 +020064// Scan interval while connected.
65const uint16 WiFi::kBackgroundScanIntervalSeconds = 3601;
mukesh agrawal5c05b292012-03-07 10:12:52 -080066// Age (in seconds) beyond which a BSS cache entry will not be preserved,
67// across a suspend/resume.
68const time_t WiFi::kMaxBSSResumeAgeSeconds = 10;
mukesh agrawal7ec71312011-11-10 02:08:26 +000069const char WiFi::kInterfaceStateUnknown[] = "shill-unknown";
mukesh agrawalf2028172012-03-13 14:20:22 -070070const time_t WiFi::kRescanIntervalSeconds = 1;
Paul Stewarte369ece2012-05-22 09:11:03 -070071const int WiFi::kNumFastScanAttempts = 3;
72const int WiFi::kFastScanIntervalSeconds = 10;
Paul Stewart2b05e622012-07-13 20:38:44 -070073const int WiFi::kPendingTimeoutSeconds = 15;
Paul Stewart44663922012-07-30 11:03:03 -070074const int WiFi::kReconnectTimeoutSeconds = 10;
mukesh agrawalb54601c2011-06-07 17:39:22 -070075
Paul Stewartb50f0b92011-05-16 16:31:42 -070076WiFi::WiFi(ControlInterface *control_interface,
77 EventDispatcher *dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -080078 Metrics *metrics,
Paul Stewartf1ce5d22011-05-19 13:10:20 -070079 Manager *manager,
Chris Masone3bd3c8c2011-06-13 08:20:26 -070080 const string& link,
Paul Stewarta41e38d2011-11-11 07:47:29 -080081 const string &address,
Paul Stewartb50f0b92011-05-16 16:31:42 -070082 int interface_index)
Chris Masonea82b7112011-05-25 15:16:29 -070083 : Device(control_interface,
84 dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -080085 metrics,
Chris Masonea82b7112011-05-25 15:16:29 -070086 manager,
Chris Masone3bd3c8c2011-06-13 08:20:26 -070087 link,
Chris Masone626719f2011-08-18 16:58:48 -070088 address,
Gaurav Shah435de2c2011-11-17 19:01:07 -080089 interface_index,
90 Technology::kWifi),
Paul Stewart3c504012013-01-17 17:49:58 -080091 provider_(manager->wifi_provider()),
Eric Shienbrood9a245532012-03-07 14:20:39 -050092 weak_ptr_factory_(this),
Darin Petkovab565bb2011-10-06 02:55:51 -070093 proxy_factory_(ProxyFactory::GetInstance()),
mukesh agrawal5c05b292012-03-07 10:12:52 -080094 time_(Time::GetInstance()),
Darin Petkov2b8e44e2012-06-25 15:13:26 +020095 supplicant_present_(false),
mukesh agrawal15908392011-11-16 18:29:25 +000096 supplicant_state_(kInterfaceStateUnknown),
97 supplicant_bss_("(unknown)"),
mukesh agrawal5c05b292012-03-07 10:12:52 -080098 need_bss_flush_(false),
Wade Guthriebb9fca22013-04-10 17:21:42 -070099 resumed_at_((struct timeval) {0}),
Paul Stewarte369ece2012-05-22 09:11:03 -0700100 fast_scans_remaining_(kNumFastScanAttempts),
Christopher Wiley8f81e2a2012-10-17 16:51:32 -0700101 has_already_completed_(false),
Paul Stewarta47c3c62012-12-18 12:14:29 -0800102 is_debugging_connection_(false),
Paul Stewart735eab52013-03-29 09:19:23 -0700103 eap_state_handler_(new SupplicantEAPStateHandler()),
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800104 bgscan_short_interval_seconds_(kDefaultBgscanShortIntervalSeconds),
105 bgscan_signal_threshold_dbm_(kDefaultBgscanSignalThresholdDbm),
Chris Masone853b81b2011-06-24 14:11:41 -0700106 scan_pending_(false),
Wade Guthriebee87c22013-03-06 11:00:46 -0800107 scan_interval_seconds_(kDefaultScanIntervalSeconds),
Wade Guthriebb9fca22013-04-10 17:21:42 -0700108 netlink_manager_(NetlinkManager::GetInstance()) {
mukesh agrawalde29fa82011-09-16 16:16:36 -0700109 PropertyStore *store = this->mutable_store();
Darin Petkov4a66cc52012-06-15 10:08:29 +0200110 store->RegisterDerivedString(
111 flimflam::kBgscanMethodProperty,
112 StringAccessor(
113 // TODO(petkov): CustomMappedAccessor is used for convenience because
114 // it provides a way to define a custom clearer (unlike
115 // CustomAccessor). We need to implement a fully custom accessor with
116 // no extra argument.
117 new CustomMappedAccessor<WiFi, string, int>(this,
118 &WiFi::ClearBgscanMethod,
119 &WiFi::GetBgscanMethod,
120 &WiFi::SetBgscanMethod,
121 0))); // Unused.
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800122 HelpRegisterDerivedUint16(store,
123 flimflam::kBgscanShortIntervalProperty,
124 &WiFi::GetBgscanShortInterval,
125 &WiFi::SetBgscanShortInterval);
126 HelpRegisterDerivedInt32(store,
127 flimflam::kBgscanSignalThresholdProperty,
128 &WiFi::GetBgscanSignalThreshold,
129 &WiFi::SetBgscanSignalThreshold);
Chris Masone853b81b2011-06-24 14:11:41 -0700130
Chris Masoneb925cc82011-06-22 15:39:57 -0700131 // TODO(quiche): Decide if scan_pending_ is close enough to
132 // "currently scanning" that we don't care, or if we want to track
133 // scan pending/currently scanning/no scan scheduled as a tri-state
134 // kind of thing.
Paul Stewartac4ac002011-08-26 12:04:26 -0700135 store->RegisterConstBool(flimflam::kScanningProperty, &scan_pending_);
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800136 HelpRegisterDerivedUint16(store,
137 flimflam::kScanIntervalProperty,
138 &WiFi::GetScanInterval,
139 &WiFi::SetScanInterval);
Paul Stewart5581d072012-12-17 17:30:20 -0800140 ScopeLogger::GetInstance()->RegisterScopeEnableChangedCallback(
141 ScopeLogger::kWiFi,
142 Bind(&WiFi::OnWiFiDebugScopeChanged, weak_ptr_factory_.GetWeakPtr()));
Wade Guthriebb9fca22013-04-10 17:21:42 -0700143 CHECK(netlink_manager_);
Ben Chanfad4a0b2012-04-18 15:49:59 -0700144 SLOG(WiFi, 2) << "WiFi device " << link_name() << " initialized.";
Paul Stewartb50f0b92011-05-16 16:31:42 -0700145}
146
mukesh agrawalaf571952011-07-14 14:31:12 -0700147WiFi::~WiFi() {}
Paul Stewartb50f0b92011-05-16 16:31:42 -0700148
Eric Shienbrood9a245532012-03-07 14:20:39 -0500149void WiFi::Start(Error *error, const EnabledStateChangedCallback &callback) {
Darin Petkov2b8e44e2012-06-25 15:13:26 +0200150 SLOG(WiFi, 2) << "WiFi " << link_name() << " starting.";
151 if (enabled()) {
152 return;
mukesh agrawalc7426a42011-06-03 13:04:28 -0700153 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500154 OnEnabledStateChanged(EnabledStateChangedCallback(), Error());
Darin Petkov2b8e44e2012-06-25 15:13:26 +0200155 if (error) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500156 error->Reset(); // indicate immediate completion
Darin Petkov2b8e44e2012-06-25 15:13:26 +0200157 }
158 if (on_supplicant_appear_.IsCancelled()) {
159 // Registers the WPA supplicant appear/vanish callbacks only once per WiFi
160 // device instance.
161 on_supplicant_appear_.Reset(
162 Bind(&WiFi::OnSupplicantAppear, Unretained(this)));
163 on_supplicant_vanish_.Reset(
164 Bind(&WiFi::OnSupplicantVanish, Unretained(this)));
Paul Stewart0654ece2013-03-26 15:21:26 -0700165 manager()->dbus_manager()->WatchName(WPASupplicant::kDBusAddr,
Darin Petkov2b8e44e2012-06-25 15:13:26 +0200166 on_supplicant_appear_.callback(),
167 on_supplicant_vanish_.callback());
168 }
169 // Connect to WPA supplicant if it's already present. If not, we'll connect to
170 // it when it appears.
171 ConnectToSupplicant();
Wade Guthriebee87c22013-03-06 11:00:46 -0800172 // Subscribe to multicast events.
Wade Guthriebb9fca22013-04-10 17:21:42 -0700173 netlink_manager_->SubscribeToEvents(Nl80211Message::kMessageTypeString,
174 NetlinkManager::kEventTypeConfig);
175 netlink_manager_->SubscribeToEvents(Nl80211Message::kMessageTypeString,
176 NetlinkManager::kEventTypeScan);
177 netlink_manager_->SubscribeToEvents(Nl80211Message::kMessageTypeString,
178 NetlinkManager::kEventTypeRegulatory);
179 netlink_manager_->SubscribeToEvents(Nl80211Message::kMessageTypeString,
180 NetlinkManager::kEventTypeMlme);
Wade Guthrie92d06362013-04-25 15:41:30 -0700181 ConfigureScanFrequencies();
mukesh agrawalab87ea42011-05-18 11:44:49 -0700182}
183
Eric Shienbrood9a245532012-03-07 14:20:39 -0500184void WiFi::Stop(Error *error, const EnabledStateChangedCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700185 SLOG(WiFi, 2) << "WiFi " << link_name() << " stopping.";
Darin Petkov2b8e44e2012-06-25 15:13:26 +0200186 DropConnection();
mukesh agrawalb66c6462012-05-07 11:45:25 -0700187 StopScanTimer();
Paul Stewart3c504012013-01-17 17:49:58 -0800188 for (EndpointMap::iterator it = endpoint_by_rpcid_.begin();
189 it != endpoint_by_rpcid_.end(); ++it) {
190 provider_->OnEndpointRemoved(it->second);
191 }
mukesh agrawal15908392011-11-16 18:29:25 +0000192 endpoint_by_rpcid_.clear();
Paul Stewart3c504012013-01-17 17:49:58 -0800193 for (ReverseServiceMap::const_iterator it = rpcid_by_service_.begin();
194 it != rpcid_by_service_.end(); ++it) {
195 RemoveNetwork(it->second);
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -0700196 }
Paul Stewart549d44c2012-07-03 12:40:25 -0700197 rpcid_by_service_.clear();
Paul Stewart549d44c2012-07-03 12:40:25 -0700198 supplicant_interface_proxy_.reset(); // breaks a reference cycle
199 // TODO(quiche): Remove interface from supplicant.
200 supplicant_process_proxy_.reset();
mukesh agrawalb20776f2012-02-10 16:00:36 -0800201 current_service_ = NULL; // breaks a reference cycle
mukesh agrawal7ec71312011-11-10 02:08:26 +0000202 pending_service_ = NULL; // breaks a reference cycle
Paul Stewarta47c3c62012-12-18 12:14:29 -0800203 is_debugging_connection_ = false;
Paul Stewartd2db2b12013-01-17 13:11:07 -0800204 SetScanPending(false);
Paul Stewart2b05e622012-07-13 20:38:44 -0700205 StopPendingTimer();
Paul Stewart44663922012-07-30 11:03:03 -0700206 StopReconnectTimer();
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -0700207
Eric Shienbrood9a245532012-03-07 14:20:39 -0500208 OnEnabledStateChanged(EnabledStateChangedCallback(), Error());
209 if (error)
210 error->Reset(); // indicate immediate completion
mukesh agrawalc4f368f2012-06-04 19:45:52 -0700211 weak_ptr_factory_.InvalidateWeakPtrs();
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -0700212
Ben Chanfad4a0b2012-04-18 15:49:59 -0700213 SLOG(WiFi, 3) << "WiFi " << link_name() << " supplicant_process_proxy_ "
214 << (supplicant_process_proxy_.get() ?
215 "is set." : "is not set.");
216 SLOG(WiFi, 3) << "WiFi " << link_name() << " supplicant_interface_proxy_ "
217 << (supplicant_interface_proxy_.get() ?
218 "is set." : "is not set.");
219 SLOG(WiFi, 3) << "WiFi " << link_name() << " pending_service_ "
220 << (pending_service_.get() ? "is set." : "is not set.");
221 SLOG(WiFi, 3) << "WiFi " << link_name() << " has "
222 << endpoint_by_rpcid_.size() << " EndpointMap entries.";
Paul Stewarta41e38d2011-11-11 07:47:29 -0800223}
224
Wade Guthrie68d41092013-04-02 12:56:02 -0700225void WiFi::Scan(ScanType scan_type, Error */*error*/) {
mukesh agrawal32399322011-09-01 10:53:43 -0700226 LOG(INFO) << __func__;
227
Wade Guthrie68d41092013-04-02 12:56:02 -0700228 if (scan_type == kProgressiveScan)
229 metrics()->NotifyDeviceScanStarted(interface_index());
230
mukesh agrawal7ec71312011-11-10 02:08:26 +0000231 // Needs to send a D-Bus message, but may be called from D-Bus
232 // signal handler context (via Manager::RequestScan). So defer work
mukesh agrawal32399322011-09-01 10:53:43 -0700233 // to event loop.
Eric Shienbrood9a245532012-03-07 14:20:39 -0500234 dispatcher()->PostTask(Bind(&WiFi::ScanTask, weak_ptr_factory_.GetWeakPtr()));
mukesh agrawal32399322011-09-01 10:53:43 -0700235}
236
mukesh agrawalb4bc57d2011-12-07 01:07:47 +0000237void WiFi::BSSAdded(const ::DBus::Path &path,
238 const map<string, ::DBus::Variant> &properties) {
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500239 // Called from a D-Bus signal handler, and may need to send a D-Bus
mukesh agrawalb4bc57d2011-12-07 01:07:47 +0000240 // message. So defer work to event loop.
Eric Shienbrood9a245532012-03-07 14:20:39 -0500241 dispatcher()->PostTask(Bind(&WiFi::BSSAddedTask,
242 weak_ptr_factory_.GetWeakPtr(),
243 path, properties));
mukesh agrawal261daca2011-12-02 18:56:56 +0000244}
245
246void WiFi::BSSRemoved(const ::DBus::Path &path) {
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500247 // Called from a D-Bus signal handler, and may need to send a D-Bus
mukesh agrawalb4bc57d2011-12-07 01:07:47 +0000248 // message. So defer work to event loop.
Eric Shienbrood9a245532012-03-07 14:20:39 -0500249 dispatcher()->PostTask(Bind(&WiFi::BSSRemovedTask,
250 weak_ptr_factory_.GetWeakPtr(), path));
mukesh agrawalb54601c2011-06-07 17:39:22 -0700251}
252
Paul Stewartbc6e7392012-05-24 07:07:48 -0700253void WiFi::Certification(const map<string, ::DBus::Variant> &properties) {
254 dispatcher()->PostTask(Bind(&WiFi::CertificationTask,
255 weak_ptr_factory_.GetWeakPtr(), properties));
256}
257
Paul Stewartdb0f9172012-11-30 16:48:09 -0800258void WiFi::EAPEvent(const string &status, const string &parameter) {
259 dispatcher()->PostTask(Bind(&WiFi::EAPEventTask,
260 weak_ptr_factory_.GetWeakPtr(),
261 status,
262 parameter));
263}
264
mukesh agrawal7ec71312011-11-10 02:08:26 +0000265void WiFi::PropertiesChanged(const map<string, ::DBus::Variant> &properties) {
Darin Petkov9cd7ca12012-07-03 11:06:40 +0200266 SLOG(WiFi, 2) << __func__;
mukesh agrawal15908392011-11-16 18:29:25 +0000267 // Called from D-Bus signal handler, but may need to send a D-Bus
268 // message. So defer work to event loop.
Eric Shienbrood9a245532012-03-07 14:20:39 -0500269 dispatcher()->PostTask(Bind(&WiFi::PropertiesChangedTask,
270 weak_ptr_factory_.GetWeakPtr(), properties));
mukesh agrawal7ec71312011-11-10 02:08:26 +0000271}
272
mukesh agrawalb54601c2011-06-07 17:39:22 -0700273void WiFi::ScanDone() {
274 LOG(INFO) << __func__;
275
mukesh agrawal7ec71312011-11-10 02:08:26 +0000276 // Defer handling of scan result processing, because that processing
277 // may require the the registration of new D-Bus objects. And such
mukesh agrawalb54601c2011-06-07 17:39:22 -0700278 // registration can't be done in the context of a D-Bus signal
279 // handler.
Wade Guthrie68d41092013-04-02 12:56:02 -0700280 metrics()->NotifyDeviceScanFinished(interface_index());
Eric Shienbrood9a245532012-03-07 14:20:39 -0500281 dispatcher()->PostTask(Bind(&WiFi::ScanDoneTask,
282 weak_ptr_factory_.GetWeakPtr()));
mukesh agrawalb54601c2011-06-07 17:39:22 -0700283}
284
mukesh agrawal6e277772011-09-29 15:04:23 -0700285void WiFi::ConnectTo(WiFiService *service,
mukesh agrawal64896322011-12-01 01:13:10 +0000286 map<string, DBus::Variant> service_params) {
mukesh agrawale9adda12012-02-09 18:33:48 -0800287 CHECK(service) << "Can't connect to NULL service.";
mukesh agrawal445e72c2011-06-22 11:13:50 -0700288 DBus::Path network_path;
mukesh agrawalb54601c2011-06-07 17:39:22 -0700289
mukesh agrawal7ec71312011-11-10 02:08:26 +0000290 // TODO(quiche): Handle cases where already connected.
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000291 if (pending_service_ && pending_service_ == service) {
292 // TODO(quiche): Return an error to the caller. crosbug.com/23832
Darin Petkov457728b2013-01-09 09:49:08 +0100293 LOG(INFO) << "WiFi " << link_name() << " ignoring ConnectTo service "
294 << service->unique_name()
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000295 << ", which is already pending.";
296 return;
297 }
298
299 if (pending_service_ && pending_service_ != service) {
300 DisconnectFrom(pending_service_);
301 }
mukesh agrawal32399322011-09-01 10:53:43 -0700302
Paul Stewart835934a2012-12-06 19:27:09 -0800303 Error unused_error;
304 network_path = FindNetworkRpcidForService(service, &unused_error);
305 if (network_path.empty()) {
306 try {
307 const uint32_t scan_ssid = 1; // "True": Use directed probe.
Paul Stewart0654ece2013-03-26 15:21:26 -0700308 service_params[WPASupplicant::kNetworkPropertyScanSSID].writer().
Paul Stewart835934a2012-12-06 19:27:09 -0800309 append_uint32(scan_ssid);
310 AppendBgscan(service, &service_params);
311 network_path = supplicant_interface_proxy_->AddNetwork(service_params);
312 CHECK(!network_path.empty()); // No DBus path should be empty.
313 rpcid_by_service_[service] = network_path;
314 } catch (const DBus::Error &e) { // NOLINT
315 LOG(ERROR) << "exception while adding network: " << e.what();
316 return;
317 }
mukesh agrawal6e277772011-09-29 15:04:23 -0700318 }
mukesh agrawal445e72c2011-06-22 11:13:50 -0700319
Paul Stewarta47c3c62012-12-18 12:14:29 -0800320 if (service->HasRecentConnectionIssues()) {
321 SetConnectionDebugging(true);
322 }
mukesh agrawal445e72c2011-06-22 11:13:50 -0700323 supplicant_interface_proxy_->SelectNetwork(network_path);
Paul Stewart2b05e622012-07-13 20:38:44 -0700324 SetPendingService(service);
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000325 CHECK(current_service_.get() != pending_service_.get());
326
mukesh agrawalf2f68a52011-09-01 12:15:48 -0700327 // SelectService here (instead of in LinkEvent, like Ethernet), so
328 // that, if we fail to bring up L2, we can attribute failure correctly.
329 //
mukesh agrawal7ec71312011-11-10 02:08:26 +0000330 // TODO(quiche): When we add code for dealing with connection failures,
mukesh agrawalf2f68a52011-09-01 12:15:48 -0700331 // reconsider if this is the right place to change the selected service.
332 // see discussion in crosbug.com/20191.
333 SelectService(service);
mukesh agrawal15908392011-11-16 18:29:25 +0000334}
335
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000336void WiFi::DisconnectFrom(WiFiService *service) {
337 if (service != current_service_ && service != pending_service_) {
338 // TODO(quiche): Once we have asynchronous reply support, we should
339 // generate a D-Bus error here. (crosbug.com/23832)
340 LOG(WARNING) << "In " << __func__ << "(): "
341 << " ignoring request to disconnect from service "
Darin Petkov457728b2013-01-09 09:49:08 +0100342 << service->unique_name()
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000343 << " which is neither current nor pending";
344 return;
345 }
346
347 if (pending_service_ && service != pending_service_) {
348 // TODO(quiche): Once we have asynchronous reply support, we should
349 // generate a D-Bus error here. (crosbug.com/23832)
350 LOG(WARNING) << "In " << __func__ << "(): "
351 << " ignoring request to disconnect from service "
Darin Petkov457728b2013-01-09 09:49:08 +0100352 << service->unique_name()
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000353 << " which is not the pending service.";
354 return;
355 }
356
357 if (!pending_service_ && service != current_service_) {
358 // TODO(quiche): Once we have asynchronous reply support, we should
359 // generate a D-Bus error here. (crosbug.com/23832)
360 LOG(WARNING) << "In " << __func__ << "(): "
361 << " ignoring request to disconnect from service "
Darin Petkov457728b2013-01-09 09:49:08 +0100362 << service->unique_name()
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000363 << " which is not the current service.";
364 return;
365 }
366
Paul Stewartff96a842012-08-13 15:59:10 -0700367 if (pending_service_) {
368 // Since wpa_supplicant has not yet set CurrentBSS, we can't depend
369 // on this to drive the service state back to idle. Do that here.
370 pending_service_->SetState(Service::kStateIdle);
371 }
372
Paul Stewart2b05e622012-07-13 20:38:44 -0700373 SetPendingService(NULL);
Paul Stewart44663922012-07-30 11:03:03 -0700374 StopReconnectTimer();
Paul Stewart549d44c2012-07-03 12:40:25 -0700375
376 if (!supplicant_present_) {
Christopher Wileyc6184482012-10-24 15:31:56 -0700377 LOG(ERROR) << "In " << __func__ << "(): "
378 << "wpa_supplicant is not present; silently resetting "
379 << "current_service_.";
380 if (current_service_ == selected_service()) {
381 DropConnection();
382 }
Paul Stewart549d44c2012-07-03 12:40:25 -0700383 current_service_ = NULL;
384 return;
385 }
386
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000387 try {
388 supplicant_interface_proxy_->Disconnect();
389 // We'll call RemoveNetwork and reset |current_service_| after
390 // supplicant notifies us that the CurrentBSS has changed.
Ben Chan80326f32012-05-04 17:51:32 -0700391 } catch (const DBus::Error &e) { // NOLINT
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000392 // Can't depend on getting a notification of CurrentBSS change.
Christopher Wileyc6184482012-10-24 15:31:56 -0700393 // So effect changes immediately. For instance, this can happen when
394 // a disconnect is triggered by a BSS going away.
Paul Stewart835934a2012-12-06 19:27:09 -0800395 Error unused_error;
396 RemoveNetworkForService(service, &unused_error);
Christopher Wileyc6184482012-10-24 15:31:56 -0700397 if (service == selected_service()) {
398 DropConnection();
399 }
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000400 current_service_ = NULL;
401 }
402
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800403 CHECK(current_service_ == NULL ||
404 current_service_.get() != pending_service_.get());
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000405}
406
Paul Stewart835934a2012-12-06 19:27:09 -0800407bool WiFi::DisableNetwork(const ::DBus::Path &network) {
408 scoped_ptr<SupplicantNetworkProxyInterface> supplicant_network_proxy(
409 proxy_factory_->CreateSupplicantNetworkProxy(
Paul Stewart0654ece2013-03-26 15:21:26 -0700410 network, WPASupplicant::kDBusAddr));
Paul Stewart835934a2012-12-06 19:27:09 -0800411 try {
412 supplicant_network_proxy->SetEnabled(false);
413 } catch (const DBus::Error &e) { // NOLINT
414 LOG(ERROR) << "DisableNetwork for " << network << " failed.";
415 return false;
416 }
417 return true;
418}
419
Paul Stewart71f6ecd2012-09-13 14:52:18 -0700420bool WiFi::RemoveNetwork(const ::DBus::Path &network) {
421 try {
422 supplicant_interface_proxy_->RemoveNetwork(network);
423 } catch (const DBus::Error &e) { // NOLINT
Ben Chan381fdcc2012-10-14 21:10:36 -0700424 // RemoveNetwork can fail with three different errors.
425 //
426 // If RemoveNetwork fails with a NetworkUnknown error, supplicant has
427 // already removed the network object, so return true as if
428 // RemoveNetwork removes the network object successfully.
429 //
430 // As shill always passes a valid network object path, RemoveNetwork
431 // should not fail with an InvalidArgs error. Return false in such case
432 // as something weird may have happened. Similarly, return false in case
433 // of an UnknownError.
Paul Stewart0654ece2013-03-26 15:21:26 -0700434 if (strcmp(e.name(), WPASupplicant::kErrorNetworkUnknown) != 0) {
Ben Chan381fdcc2012-10-14 21:10:36 -0700435 return false;
436 }
Paul Stewart71f6ecd2012-09-13 14:52:18 -0700437 }
438 return true;
439}
440
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000441bool WiFi::IsIdle() const {
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800442 return !current_service_ && !pending_service_;
443}
444
Paul Stewart835934a2012-12-06 19:27:09 -0800445void WiFi::ClearCachedCredentials(const WiFiService *service) {
446 Error unused_error;
447 RemoveNetworkForService(service, &unused_error);
Paul Stewart66c86002012-01-30 18:00:52 -0800448}
449
Paul Stewart3c504012013-01-17 17:49:58 -0800450void WiFi::NotifyEndpointChanged(const WiFiEndpointConstRefPtr &endpoint) {
Paul Stewart0427cc12013-03-25 13:50:39 -0700451 provider_->OnEndpointUpdated(endpoint);
mukesh agrawalb20776f2012-02-10 16:00:36 -0800452}
453
Darin Petkov4a66cc52012-06-15 10:08:29 +0200454void WiFi::AppendBgscan(WiFiService *service,
455 map<string, DBus::Variant> *service_params) const {
456 int scan_interval = kBackgroundScanIntervalSeconds;
457 string method = bgscan_method_;
458 if (method.empty()) {
459 // If multiple APs are detected for this SSID, configure the default method.
460 // Otherwise, disable background scanning completely.
461 if (service->GetEndpointCount() > 1) {
462 method = kDefaultBgscanMethod;
463 } else {
464 LOG(INFO) << "Background scan disabled -- single Endpoint for Service.";
465 return;
466 }
Paul Stewart0654ece2013-03-26 15:21:26 -0700467 } else if (method.compare(WPASupplicant::kNetworkBgscanMethodNone) == 0) {
Christopher Wileya998df22012-07-11 15:14:55 -0700468 LOG(INFO) << "Background scan disabled -- chose None method.";
469 return;
Darin Petkov4a66cc52012-06-15 10:08:29 +0200470 } else {
471 // If the background scan method was explicitly specified, honor the
472 // configured background scan interval.
473 scan_interval = scan_interval_seconds_;
474 }
475 DCHECK(!method.empty());
476 string config_string = StringPrintf("%s:%d:%d:%d",
477 method.c_str(),
478 bgscan_short_interval_seconds_,
479 bgscan_signal_threshold_dbm_,
480 scan_interval);
481 LOG(INFO) << "Background scan: " << config_string;
Paul Stewart0654ece2013-03-26 15:21:26 -0700482 (*service_params)[WPASupplicant::kNetworkPropertyBgscan].writer()
Darin Petkov4a66cc52012-06-15 10:08:29 +0200483 .append_string(config_string.c_str());
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800484}
485
Darin Petkov4a66cc52012-06-15 10:08:29 +0200486string WiFi::GetBgscanMethod(const int &/*argument*/, Error */* error */) {
487 return bgscan_method_.empty() ? kDefaultBgscanMethod : bgscan_method_;
488}
489
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700490bool WiFi::SetBgscanMethod(
Darin Petkov4a66cc52012-06-15 10:08:29 +0200491 const int &/*argument*/, const string &method, Error *error) {
Paul Stewart0654ece2013-03-26 15:21:26 -0700492 if (method != WPASupplicant::kNetworkBgscanMethodSimple &&
493 method != WPASupplicant::kNetworkBgscanMethodLearn &&
494 method != WPASupplicant::kNetworkBgscanMethodNone) {
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800495 const string error_message =
496 StringPrintf("Unrecognized bgscan method %s", method.c_str());
497 LOG(WARNING) << error_message;
498 error->Populate(Error::kInvalidArguments, error_message);
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700499 return false;
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800500 }
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700501 if (bgscan_method_ == method) {
502 return false;
503 }
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800504 bgscan_method_ = method;
505 // We do not update kNetworkPropertyBgscan for |pending_service_| or
506 // |current_service_|, because supplicant does not allow for
507 // reconfiguration without disconnect and reconnect.
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700508 return true;
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800509}
510
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700511bool WiFi::SetBgscanShortInterval(const uint16 &seconds, Error */*error*/) {
512 if (bgscan_short_interval_seconds_ == seconds) {
513 return false;
514 }
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800515 bgscan_short_interval_seconds_ = seconds;
516 // We do not update kNetworkPropertyBgscan for |pending_service_| or
517 // |current_service_|, because supplicant does not allow for
518 // reconfiguration without disconnect and reconnect.
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700519 return true;
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800520}
521
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700522bool WiFi::SetBgscanSignalThreshold(const int32 &dbm, Error */*error*/) {
523 if (bgscan_signal_threshold_dbm_ == dbm) {
524 return false;
525 }
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800526 bgscan_signal_threshold_dbm_ = dbm;
527 // We do not update kNetworkPropertyBgscan for |pending_service_| or
528 // |current_service_|, because supplicant does not allow for
529 // reconfiguration without disconnect and reconnect.
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700530 return true;
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800531}
532
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700533bool WiFi::SetScanInterval(const uint16 &seconds, Error */*error*/) {
534 if (scan_interval_seconds_ == seconds) {
535 return false;
536 }
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800537 scan_interval_seconds_ = seconds;
mukesh agrawalb66c6462012-05-07 11:45:25 -0700538 if (running()) {
539 StartScanTimer();
540 }
541 // The scan interval affects both foreground scans (handled by
542 // |scan_timer_callback_|), and background scans (handled by
543 // supplicant). However, we do not update |pending_service_| or
544 // |current_service_|, because supplicant does not allow for
545 // reconfiguration without disconnect and reconnect.
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700546 return true;
mukesh agrawal4d0401c2012-01-06 16:05:31 -0800547}
548
Darin Petkov4a66cc52012-06-15 10:08:29 +0200549void WiFi::ClearBgscanMethod(const int &/*argument*/, Error */*error*/) {
550 bgscan_method_.clear();
551}
552
mukesh agrawal15908392011-11-16 18:29:25 +0000553void WiFi::CurrentBSSChanged(const ::DBus::Path &new_bss) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700554 SLOG(WiFi, 3) << "WiFi " << link_name() << " CurrentBSS "
555 << supplicant_bss_ << " -> " << new_bss;
mukesh agrawal15908392011-11-16 18:29:25 +0000556 supplicant_bss_ = new_bss;
Christopher Wiley8f81e2a2012-10-17 16:51:32 -0700557 has_already_completed_ = false;
Paul Stewart44663922012-07-30 11:03:03 -0700558
559 // Any change in CurrentBSS means supplicant is actively changing our
560 // connectivity. We no longer need to track any previously pending
561 // reconnect.
562 StopReconnectTimer();
563
Paul Stewart0654ece2013-03-26 15:21:26 -0700564 if (new_bss == WPASupplicant::kCurrentBSSNull) {
mukesh agrawal15908392011-11-16 18:29:25 +0000565 HandleDisconnect();
Paul Stewart3c504012013-01-17 17:49:58 -0800566 if (!provider_->GetHiddenSSIDList().empty()) {
mukesh agrawalb66c6462012-05-07 11:45:25 -0700567 // Before disconnecting, wpa_supplicant probably scanned for
568 // APs. So, in the normal case, we defer to the timer for the next scan.
569 //
570 // However, in the case of hidden SSIDs, supplicant knows about
571 // at most one of them. (That would be the hidden SSID we were
572 // connected to, if applicable.)
573 //
574 // So, in this case, we initiate an immediate scan. This scan
575 // will include the hidden SSIDs we know about (up to the limit of
576 // kScanMAxSSIDsPerScan).
577 //
578 // We may want to reconsider this immediate scan, if/when shill
579 // takes greater responsibility for scanning (vs. letting
580 // supplicant handle most of it).
Wade Guthrie68d41092013-04-02 12:56:02 -0700581 Scan(kProgressiveScan, NULL);
mukesh agrawalb66c6462012-05-07 11:45:25 -0700582 }
mukesh agrawal15908392011-11-16 18:29:25 +0000583 } else {
584 HandleRoam(new_bss);
585 }
586
Paul Stewart735eab52013-03-29 09:19:23 -0700587 // Reset the EAP handler only after calling HandleDisconnect() above
588 // so our EAP state could be used to detect a failed authentication.
589 eap_state_handler_->Reset();
Paul Stewart1369c2b2013-01-11 05:41:26 -0800590
Paul Stewart2b05e622012-07-13 20:38:44 -0700591 // If we are selecting a new service, or if we're clearing selection
592 // of a something other than the pending service, call SelectService.
593 // Otherwise skip SelectService, since this will cause the pending
594 // service to be marked as Idle.
595 if (current_service_ || selected_service() != pending_service_) {
596 SelectService(current_service_);
597 }
598
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000599 // Invariant check: a Service can either be current, or pending, but
600 // not both.
mukesh agrawal15908392011-11-16 18:29:25 +0000601 CHECK(current_service_.get() != pending_service_.get() ||
602 current_service_.get() == NULL);
Paul Stewarta47c3c62012-12-18 12:14:29 -0800603
604 // If we are no longer debugging a problematic WiFi connection, return
605 // to the debugging level indicated by the WiFi debugging scope.
606 if ((!current_service_ || !current_service_->HasRecentConnectionIssues()) &&
607 (!pending_service_ || !pending_service_->HasRecentConnectionIssues())) {
608 SetConnectionDebugging(false);
609 }
mukesh agrawal15908392011-11-16 18:29:25 +0000610}
611
612void WiFi::HandleDisconnect() {
613 // Identify the affected service. We expect to get a disconnect
614 // event when we fall off a Service that we were connected
615 // to. However, we also allow for the case where we get a disconnect
616 // event while attempting to connect from a disconnected state.
617 WiFiService *affected_service =
618 current_service_.get() ? current_service_.get() : pending_service_.get();
619
620 current_service_ = NULL;
621 if (!affected_service) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700622 SLOG(WiFi, 2) << "WiFi " << link_name()
623 << " disconnected while not connected or connecting";
mukesh agrawal15908392011-11-16 18:29:25 +0000624 return;
Christopher Wileyc6184482012-10-24 15:31:56 -0700625 }
626 if (affected_service == selected_service()) {
Paul Stewart20b0a092012-05-22 20:39:57 -0700627 // If our selected service has disconnected, destroy IP configuration state.
Christopher Wileyc6184482012-10-24 15:31:56 -0700628 DropConnection();
mukesh agrawal15908392011-11-16 18:29:25 +0000629 }
630
Paul Stewart835934a2012-12-06 19:27:09 -0800631 Error error;
632 if (!DisableNetworkForService(affected_service, &error)) {
633 if (error.type() == Error::kNotFound) {
634 SLOG(WiFi, 2) << "WiFi " << link_name() << " disconnected from "
Darin Petkov457728b2013-01-09 09:49:08 +0100635 << " (or failed to connect to) service "
636 << affected_service->unique_name() << ", "
Paul Stewart835934a2012-12-06 19:27:09 -0800637 << "but could not find supplicant network to disable.";
638 } else {
639 LOG(FATAL) << "DisableNetwork failed.";
Paul Stewart71f6ecd2012-09-13 14:52:18 -0700640 }
mukesh agrawal15908392011-11-16 18:29:25 +0000641 }
642
Ben Chanfad4a0b2012-04-18 15:49:59 -0700643 SLOG(WiFi, 2) << "WiFi " << link_name() << " disconnected from "
Darin Petkov457728b2013-01-09 09:49:08 +0100644 << " (or failed to connect to) service "
645 << affected_service->unique_name();
Paul Stewart1369c2b2013-01-11 05:41:26 -0800646 Service::ConnectFailure failure;
647 if (SuspectCredentials(*affected_service, &failure)) {
mukesh agrawalcf24a242012-05-21 16:46:11 -0700648 // If we suspect bad credentials, set failure, to trigger an error
mukesh agrawal56e32202012-07-26 16:32:11 -0700649 // mole in Chrome.
Paul Stewart1369c2b2013-01-11 05:41:26 -0800650 affected_service->SetFailure(failure);
651 LOG(ERROR) << "Connection failure is due to suspect credentials: returning "
652 << Service::ConnectFailureToString(failure);
Paul Stewartf2d60912012-07-15 08:37:30 -0700653 } else {
654 affected_service->SetFailureSilent(Service::kFailureUnknown);
mukesh agrawalcf24a242012-05-21 16:46:11 -0700655 }
mukesh agrawale1d90e92012-02-15 17:36:08 -0800656 affected_service->NotifyCurrentEndpoint(NULL);
Thieu Le67370f62012-02-14 23:01:42 +0000657 metrics()->NotifyServiceDisconnect(affected_service);
mukesh agrawal15908392011-11-16 18:29:25 +0000658
659 if (affected_service == pending_service_.get()) {
660 // The attempt to connect to |pending_service_| failed. Clear
661 // |pending_service_|, to indicate we're no longer in the middle
662 // of a connect request.
Paul Stewart2b05e622012-07-13 20:38:44 -0700663 SetPendingService(NULL);
mukesh agrawal15908392011-11-16 18:29:25 +0000664 } else if (pending_service_.get()) {
665 // We've attributed the disconnection to what was the
666 // |current_service_|, rather than the |pending_service_|.
667 //
668 // If we're wrong about that (i.e. supplicant reported this
669 // CurrentBSS change after attempting to connect to
670 // |pending_service_|), we're depending on supplicant to retry
671 // connecting to |pending_service_|, and delivering another
672 // CurrentBSS change signal in the future.
673 //
674 // Log this fact, to help us debug (in case our assumptions are
675 // wrong).
Darin Petkov457728b2013-01-09 09:49:08 +0100676 SLOG(WiFi, 2) << "WiFi " << link_name() << " pending connection to service "
677 << pending_service_->unique_name()
Ben Chanfad4a0b2012-04-18 15:49:59 -0700678 << " after disconnect";
mukesh agrawal15908392011-11-16 18:29:25 +0000679 }
Paul Stewarte369ece2012-05-22 09:11:03 -0700680
681 // If we disconnect, initially scan at a faster frequency, to make sure
682 // we've found all available APs.
683 RestartFastScanAttempts();
mukesh agrawal15908392011-11-16 18:29:25 +0000684}
685
686// We use the term "Roam" loosely. In particular, we include the case
687// where we "Roam" to a BSS from the disconnected state.
688void WiFi::HandleRoam(const ::DBus::Path &new_bss) {
689 EndpointMap::iterator endpoint_it = endpoint_by_rpcid_.find(new_bss);
690 if (endpoint_it == endpoint_by_rpcid_.end()) {
691 LOG(WARNING) << "WiFi " << link_name() << " connected to unknown BSS "
692 << new_bss;
693 return;
694 }
695
Paul Stewart3c504012013-01-17 17:49:58 -0800696 const WiFiEndpointConstRefPtr endpoint(endpoint_it->second);
697 WiFiServiceRefPtr service = provider_->FindServiceForEndpoint(endpoint);
mukesh agrawal15908392011-11-16 18:29:25 +0000698 if (!service.get()) {
699 LOG(WARNING) << "WiFi " << link_name()
700 << " could not find Service for Endpoint "
Paul Stewart3c504012013-01-17 17:49:58 -0800701 << endpoint->bssid_string()
mukesh agrawal15908392011-11-16 18:29:25 +0000702 << " (service will be unchanged)";
703 return;
704 }
705
Ben Chanfad4a0b2012-04-18 15:49:59 -0700706 SLOG(WiFi, 2) << "WiFi " << link_name()
Paul Stewart3c504012013-01-17 17:49:58 -0800707 << " roamed to Endpoint " << endpoint->bssid_string()
708 << " " << LogSSID(endpoint->ssid_string());
mukesh agrawal15908392011-11-16 18:29:25 +0000709
Paul Stewart3c504012013-01-17 17:49:58 -0800710 service->NotifyCurrentEndpoint(endpoint);
Wade Guthrie60a37062013-04-02 11:39:09 -0700711 provider_->IncrementConnectCount(endpoint->frequency());
Thieu Lee41a72d2012-02-06 20:46:51 +0000712
mukesh agrawal15908392011-11-16 18:29:25 +0000713 if (pending_service_.get() &&
714 service.get() != pending_service_.get()) {
715 // The Service we've roamed on to is not the one we asked for.
716 // We assume that this is transient, and that wpa_supplicant
717 // is trying / will try to connect to |pending_service_|.
718 //
719 // If it succeeds, we'll end up back here, but with |service|
720 // pointing at the same service as |pending_service_|.
721 //
722 // If it fails, we'll process things in HandleDisconnect.
723 //
724 // So we leave |pending_service_| untouched.
Ben Chanfad4a0b2012-04-18 15:49:59 -0700725 SLOG(WiFi, 2) << "WiFi " << link_name()
726 << " new current Endpoint "
Paul Stewart3c504012013-01-17 17:49:58 -0800727 << endpoint->bssid_string()
Ben Chanfad4a0b2012-04-18 15:49:59 -0700728 << " is not part of pending service "
Darin Petkov457728b2013-01-09 09:49:08 +0100729 << pending_service_->unique_name();
mukesh agrawal15908392011-11-16 18:29:25 +0000730
731 // Sanity check: if we didn't roam onto |pending_service_|, we
732 // should still be on |current_service_|.
733 if (service.get() != current_service_.get()) {
734 LOG(WARNING) << "WiFi " << link_name()
735 << " new current Endpoint "
Paul Stewart3c504012013-01-17 17:49:58 -0800736 << endpoint->bssid_string()
mukesh agrawal15908392011-11-16 18:29:25 +0000737 << " is neither part of pending service "
Darin Petkov457728b2013-01-09 09:49:08 +0100738 << pending_service_->unique_name()
mukesh agrawal15908392011-11-16 18:29:25 +0000739 << " nor part of current service "
Darin Petkov457728b2013-01-09 09:49:08 +0100740 << (current_service_ ?
741 current_service_->unique_name() :
mukesh agrawal15908392011-11-16 18:29:25 +0000742 "(NULL)");
743 // Although we didn't expect to get here, we should keep
744 // |current_service_| in sync with what supplicant has done.
745 current_service_ = service;
746 }
747 return;
748 }
749
750 if (pending_service_.get()) {
751 // We assume service.get() == pending_service_.get() here, because
752 // of the return in the previous if clause.
753 //
754 // Boring case: we've connected to the service we asked
755 // for. Simply update |current_service_| and |pending_service_|.
756 current_service_ = service;
Paul Stewart2b05e622012-07-13 20:38:44 -0700757 SetPendingService(NULL);
mukesh agrawal15908392011-11-16 18:29:25 +0000758 return;
759 }
760
761 // |pending_service_| was NULL, so we weren't attempting to connect
762 // to a new Service. Sanity check that we're still on
763 // |current_service_|.
764 if (service.get() != current_service_.get()) {
765 LOG(WARNING)
766 << "WiFi " << link_name()
767 << " new current Endpoint "
Paul Stewart3c504012013-01-17 17:49:58 -0800768 << endpoint->bssid_string()
mukesh agrawal15908392011-11-16 18:29:25 +0000769 << (current_service_.get() ?
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000770 StringPrintf(" is not part of current service %s",
Darin Petkov457728b2013-01-09 09:49:08 +0100771 current_service_->unique_name().c_str()) :
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000772 " with no current service");
mukesh agrawal15908392011-11-16 18:29:25 +0000773 // We didn't expect to be here, but let's cope as well as we
774 // can. Update |current_service_| to keep it in sync with
775 // supplicant.
776 current_service_ = service;
Paul Stewartabbe2792012-07-15 07:50:35 -0700777
778 // If this service isn't already marked as actively connecting (likely,
779 // since this service is a bit of a surprise) set the service as
780 // associating.
781 if (!current_service_->IsConnecting()) {
782 current_service_->SetState(Service::kStateAssociating);
783 }
784
mukesh agrawal15908392011-11-16 18:29:25 +0000785 return;
786 }
787
788 // At this point, we know that |pending_service_| was NULL, and that
789 // we're still on |current_service_|. This is the most boring case
790 // of all, because there's no state to update here.
791 return;
mukesh agrawalb54601c2011-06-07 17:39:22 -0700792}
793
Paul Stewart835934a2012-12-06 19:27:09 -0800794string WiFi::FindNetworkRpcidForService(
795 const WiFiService *service, Error *error) {
796 ReverseServiceMap::const_iterator rpcid_it =
797 rpcid_by_service_.find(service);
798 if (rpcid_it == rpcid_by_service_.end()) {
799 const string error_message =
Darin Petkov457728b2013-01-09 09:49:08 +0100800 StringPrintf(
801 "WiFi %s cannot find supplicant network rpcid for service %s",
802 link_name().c_str(), service->unique_name().c_str());
Paul Stewart835934a2012-12-06 19:27:09 -0800803 // There are contexts where this is not an error, such as when a service
804 // is clearing whatever cached credentials may not exist.
805 SLOG(WiFi, 2) << error_message;
806 if (error) {
807 error->Populate(Error::kNotFound, error_message);
808 }
809 return "";
810 }
811
812 return rpcid_it->second;
813}
814
815bool WiFi::DisableNetworkForService(const WiFiService *service, Error *error) {
816 string rpcid = FindNetworkRpcidForService(service, error);
817 if (rpcid.empty()) {
818 // Error is already populated.
819 return false;
820 }
821
822 if (!DisableNetwork(rpcid)) {
823 const string error_message =
Darin Petkov457728b2013-01-09 09:49:08 +0100824 StringPrintf("WiFi %s cannot disable network for service %s: "
Paul Stewart835934a2012-12-06 19:27:09 -0800825 "DBus operation failed for rpcid %s.",
Darin Petkov457728b2013-01-09 09:49:08 +0100826 link_name().c_str(), service->unique_name().c_str(),
Paul Stewart835934a2012-12-06 19:27:09 -0800827 rpcid.c_str());
828 Error::PopulateAndLog(error, Error::kOperationFailed, error_message);
829
830 // Make sure that such errored networks are removed, so problems do not
831 // propogate to future connection attempts.
832 RemoveNetwork(rpcid);
833 rpcid_by_service_.erase(service);
834
835 return false;
836 }
837
838 return true;
839}
840
841bool WiFi::RemoveNetworkForService(const WiFiService *service, Error *error) {
842 string rpcid = FindNetworkRpcidForService(service, error);
843 if (rpcid.empty()) {
844 // Error is already populated.
845 return false;
846 }
847
848 // Erase the rpcid from our tables regardless of failure below, since even
849 // if in failure, we never want to use this network again.
850 rpcid_by_service_.erase(service);
851
852 // TODO(quiche): Reconsider giving up immediately. Maybe give
853 // wpa_supplicant some time to retry, first.
854 if (!RemoveNetwork(rpcid)) {
855 const string error_message =
Darin Petkov457728b2013-01-09 09:49:08 +0100856 StringPrintf("WiFi %s cannot remove network for service %s: "
Paul Stewart835934a2012-12-06 19:27:09 -0800857 "DBus operation failed for rpcid %s.",
Darin Petkov457728b2013-01-09 09:49:08 +0100858 link_name().c_str(), service->unique_name().c_str(),
Paul Stewart835934a2012-12-06 19:27:09 -0800859 rpcid.c_str());
860 Error::PopulateAndLog(error, Error::kOperationFailed, error_message);
861 return false;
862 }
863
864 return true;
865}
866
mukesh agrawalb4bc57d2011-12-07 01:07:47 +0000867void WiFi::BSSAddedTask(
868 const ::DBus::Path &path,
869 const map<string, ::DBus::Variant> &properties) {
mukesh agrawalb4bc57d2011-12-07 01:07:47 +0000870 // Note: we assume that BSSIDs are unique across endpoints. This
871 // means that if an AP reuses the same BSSID for multiple SSIDs, we
872 // lose.
mukesh agrawalb20776f2012-02-10 16:00:36 -0800873 WiFiEndpointRefPtr endpoint(
874 new WiFiEndpoint(proxy_factory_, this, path, properties));
Wade Guthrie592ecd52012-11-12 13:12:30 -0800875 SLOG(WiFi, 1) << "Found endpoint. "
876 << "RPC path: " << path << ", "
Darin Petkov50cb78a2013-02-06 16:17:49 +0100877 << LogSSID(endpoint->ssid_string()) << ", "
Wade Guthrie592ecd52012-11-12 13:12:30 -0800878 << "bssid: " << endpoint->bssid_string() << ", "
879 << "signal: " << endpoint->signal_strength() << ", "
880 << "security: " << endpoint->security_mode() << ", "
881 << "frequency: " << endpoint->frequency();
mukesh agrawalb4bc57d2011-12-07 01:07:47 +0000882
883 if (endpoint->ssid_string().empty()) {
884 // Don't bother trying to find or create a Service for an Endpoint
885 // without an SSID. We wouldn't be able to connect to it anyway.
886 return;
887 }
888
mukesh agrawalb3857612012-01-18 16:23:29 -0800889 if (endpoint->ssid()[0] == 0) {
890 // Assume that an SSID starting with NULL is bogus/misconfigured,
891 // and filter it out.
892 return;
893 }
894
Paul Stewart3c504012013-01-17 17:49:58 -0800895 provider_->OnEndpointAdded(endpoint);
mukesh agrawalb4bc57d2011-12-07 01:07:47 +0000896
mukesh agrawale9adda12012-02-09 18:33:48 -0800897 // Do this last, to maintain the invariant that any Endpoint we
898 // know about has a corresponding Service.
mukesh agrawalb20776f2012-02-10 16:00:36 -0800899 //
900 // TODO(quiche): Write test to verify correct behavior in the case
901 // where we get multiple BSSAdded events for a single endpoint.
902 // (Old Endpoint's refcount should fall to zero, and old Endpoint
903 // should be destroyed.)
mukesh agrawale9adda12012-02-09 18:33:48 -0800904 endpoint_by_rpcid_[path] = endpoint;
mukesh agrawalb20776f2012-02-10 16:00:36 -0800905 endpoint->Start();
mukesh agrawalb4bc57d2011-12-07 01:07:47 +0000906}
907
908void WiFi::BSSRemovedTask(const ::DBus::Path &path) {
909 EndpointMap::iterator i = endpoint_by_rpcid_.find(path);
910 if (i == endpoint_by_rpcid_.end()) {
911 LOG(WARNING) << "WiFi " << link_name()
912 << " could not find BSS " << path
913 << " to remove.";
914 return;
915 }
916
917 WiFiEndpointRefPtr endpoint = i->second;
918 CHECK(endpoint);
919 endpoint_by_rpcid_.erase(i);
920
Paul Stewart3c504012013-01-17 17:49:58 -0800921 WiFiServiceRefPtr service = provider_->OnEndpointRemoved(endpoint);
922 if (!service) {
923 return;
924 }
925 Error unused_error;
926 RemoveNetworkForService(service, &unused_error);
mukesh agrawalb4bc57d2011-12-07 01:07:47 +0000927
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000928 bool disconnect_service = !service->HasEndpoints() &&
929 (service->IsConnecting() || service->IsConnected());
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000930
931 if (disconnect_service) {
mukesh agrawaldc7b8442012-09-27 13:48:14 -0700932 LOG(INFO) << "Disconnecting from service " << service->unique_name()
933 << ": BSSRemoved";
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000934 DisconnectFrom(service);
935 }
mukesh agrawalb4bc57d2011-12-07 01:07:47 +0000936}
937
Paul Stewartbc6e7392012-05-24 07:07:48 -0700938void WiFi::CertificationTask(
939 const map<string, ::DBus::Variant> &properties) {
940 if (!current_service_) {
941 LOG(ERROR) << "WiFi " << link_name() << " " << __func__
942 << " with no current service.";
943 return;
944 }
945
Paul Stewart735eab52013-03-29 09:19:23 -0700946 string subject;
947 uint32 depth;
948 if (WPASupplicant::ExtractRemoteCertification(properties, &subject, &depth)) {
949 current_service_->AddEAPCertification(subject, depth);
Paul Stewartbc6e7392012-05-24 07:07:48 -0700950 }
Paul Stewartbc6e7392012-05-24 07:07:48 -0700951}
952
Paul Stewartdb0f9172012-11-30 16:48:09 -0800953void WiFi::EAPEventTask(const string &status, const string &parameter) {
Paul Stewartdb0f9172012-11-30 16:48:09 -0800954 if (!current_service_) {
955 LOG(ERROR) << "WiFi " << link_name() << " " << __func__
956 << " with no current service.";
957 return;
958 }
Paul Stewart735eab52013-03-29 09:19:23 -0700959 Service::ConnectFailure failure = Service::kFailureUnknown;
960 eap_state_handler_->ParseStatus(status, parameter, &failure);
Paul Stewartdb0f9172012-11-30 16:48:09 -0800961 if (failure != Service::kFailureUnknown) {
Paul Stewart735eab52013-03-29 09:19:23 -0700962 // Avoid a reporting failure twice by resetting EAP state handler early.
963 eap_state_handler_->Reset();
mukesh agrawald4dc0832013-03-25 14:38:26 -0700964 Error unused_error;
mukesh agrawald4dc0832013-03-25 14:38:26 -0700965 current_service_->DisconnectWithFailure(failure, &unused_error);
Paul Stewartdb0f9172012-11-30 16:48:09 -0800966 }
967}
968
mukesh agrawal15908392011-11-16 18:29:25 +0000969void WiFi::PropertiesChangedTask(
970 const map<string, ::DBus::Variant> &properties) {
971 // TODO(quiche): Handle changes in other properties (e.g. signal
972 // strength).
973
974 // Note that order matters here. In particular, we want to process
975 // changes in the current BSS before changes in state. This is so
976 // that we update the state of the correct Endpoint/Service.
977
978 map<string, ::DBus::Variant>::const_iterator properties_it =
Paul Stewart0654ece2013-03-26 15:21:26 -0700979 properties.find(WPASupplicant::kInterfacePropertyCurrentBSS);
mukesh agrawal15908392011-11-16 18:29:25 +0000980 if (properties_it != properties.end()) {
981 CurrentBSSChanged(properties_it->second.reader().get_path());
982 }
983
Paul Stewart0654ece2013-03-26 15:21:26 -0700984 properties_it = properties.find(WPASupplicant::kInterfacePropertyState);
mukesh agrawal15908392011-11-16 18:29:25 +0000985 if (properties_it != properties.end()) {
986 StateChanged(properties_it->second.reader().get_string());
987 }
988}
989
mukesh agrawaldc42bb32011-07-28 10:40:26 -0700990void WiFi::ScanDoneTask() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700991 SLOG(WiFi, 2) << __func__ << " need_bss_flush_ " << need_bss_flush_;
mukesh agrawal5c05b292012-03-07 10:12:52 -0800992 if (need_bss_flush_) {
993 CHECK(supplicant_interface_proxy_ != NULL);
994 // Compute |max_age| relative to |resumed_at_|, to account for the
995 // time taken to scan.
996 struct timeval now;
997 uint32_t max_age;
998 time_->GetTimeMonotonic(&now);
999 max_age = kMaxBSSResumeAgeSeconds + (now.tv_sec - resumed_at_.tv_sec);
1000 supplicant_interface_proxy_->FlushBSS(max_age);
1001 need_bss_flush_ = false;
1002 }
Paul Stewartd2db2b12013-01-17 13:11:07 -08001003 SetScanPending(false);
mukesh agrawalb66c6462012-05-07 11:45:25 -07001004 StartScanTimer();
mukesh agrawalb54601c2011-06-07 17:39:22 -07001005}
1006
mukesh agrawal32399322011-09-01 10:53:43 -07001007void WiFi::ScanTask() {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001008 SLOG(WiFi, 2) << "WiFi " << link_name() << " scan requested.";
Paul Stewartfae4dae2012-09-13 07:43:32 -07001009 if (!enabled()) {
1010 SLOG(WiFi, 2) << "Ignoring scan request while device is not enabled.";
1011 return;
1012 }
1013 if (!supplicant_present_ || !supplicant_interface_proxy_.get()) {
1014 SLOG(WiFi, 2) << "Ignoring scan request while supplicant is not present.";
1015 return;
1016 }
Christopher Wileyc68c8672012-11-20 16:52:21 -08001017 if ((pending_service_.get() && pending_service_->IsConnecting()) ||
1018 (current_service_.get() && current_service_->IsConnecting())) {
1019 SLOG(WiFi, 2) << "Ignoring scan request while connecting to an AP.";
1020 return;
1021 }
Paul Stewarta41e38d2011-11-11 07:47:29 -08001022 map<string, DBus::Variant> scan_args;
Paul Stewart0654ece2013-03-26 15:21:26 -07001023 scan_args[WPASupplicant::kPropertyScanType].writer().
1024 append_string(WPASupplicant::kScanTypeActive);
Paul Stewartced6a0b2011-11-08 15:32:04 -08001025
Paul Stewart3c504012013-01-17 17:49:58 -08001026 ByteArrays hidden_ssids = provider_->GetHiddenSSIDList();
Paul Stewartced6a0b2011-11-08 15:32:04 -08001027 if (!hidden_ssids.empty()) {
Paul Stewart3c504012013-01-17 17:49:58 -08001028 // TODO(pstew): Devise a better method for time-sharing with SSIDs that do
1029 // not fit in.
Paul Stewart0654ece2013-03-26 15:21:26 -07001030 if (hidden_ssids.size() >= WPASupplicant::kScanMaxSSIDsPerScan) {
Paul Stewart3c504012013-01-17 17:49:58 -08001031 hidden_ssids.erase(
Paul Stewart0654ece2013-03-26 15:21:26 -07001032 hidden_ssids.begin() + WPASupplicant::kScanMaxSSIDsPerScan - 1,
Paul Stewart3c504012013-01-17 17:49:58 -08001033 hidden_ssids.end());
1034 }
1035 // Add Broadcast SSID, signified by an empty ByteArray. If we specify
1036 // SSIDs to wpa_supplicant, we need to explicitly specify the default
1037 // behavior of doing a broadcast probe.
1038 hidden_ssids.push_back(ByteArray());
1039
Paul Stewart0654ece2013-03-26 15:21:26 -07001040 scan_args[WPASupplicant::kPropertyScanSSIDs] =
Paul Stewartced6a0b2011-11-08 15:32:04 -08001041 DBusAdaptor::ByteArraysToVariant(hidden_ssids);
1042 }
1043
Gaurav Shah10109f22011-11-11 20:16:22 -08001044 try {
1045 supplicant_interface_proxy_->Scan(scan_args);
Paul Stewartd2db2b12013-01-17 13:11:07 -08001046 SetScanPending(true);
Ben Chan80326f32012-05-04 17:51:32 -07001047 } catch (const DBus::Error &e) { // NOLINT
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001048 // A scan may fail if, for example, the wpa_supplicant vanishing
1049 // notification is posted after this task has already started running.
1050 LOG(WARNING) << "Scan failed: " << e.what();
Gaurav Shah10109f22011-11-11 20:16:22 -08001051 }
mukesh agrawal32399322011-09-01 10:53:43 -07001052}
1053
Paul Stewartd2db2b12013-01-17 13:11:07 -08001054void WiFi::SetScanPending(bool pending) {
1055 if (scan_pending_ != pending) {
1056 scan_pending_ = pending;
1057 adaptor()->EmitBoolChanged(flimflam::kScanningProperty, pending);
1058 }
1059}
1060
Albert Chaulk0e1cdea2013-02-27 15:32:55 -08001061string WiFi::GetServiceLeaseName(const WiFiService &service) {
1062 return service.GetStorageIdentifier();
1063}
1064
1065void WiFi::DestroyServiceLease(const WiFiService &service) {
1066 DestroyIPConfigLease(GetServiceLeaseName(service));
1067}
1068
mukesh agrawal15908392011-11-16 18:29:25 +00001069void WiFi::StateChanged(const string &new_state) {
1070 const string old_state = supplicant_state_;
mukesh agrawal7ec71312011-11-10 02:08:26 +00001071 supplicant_state_ = new_state;
mukesh agrawal15908392011-11-16 18:29:25 +00001072 LOG(INFO) << "WiFi " << link_name() << " " << __func__ << " "
1073 << old_state << " -> " << new_state;
1074
1075 WiFiService *affected_service;
1076 // Identify the service to which the state change applies. If
1077 // |pending_service_| is non-NULL, then the state change applies to
1078 // |pending_service_|. Otherwise, it applies to |current_service_|.
1079 //
1080 // This policy is driven by the fact that the |pending_service_|
1081 // doesn't become the |current_service_| until wpa_supplicant
1082 // reports a CurrentBSS change to the |pending_service_|. And the
mukesh agrawalc01f3982012-01-24 13:48:39 -08001083 // CurrentBSS change won't be reported until the |pending_service_|
Paul Stewart0654ece2013-03-26 15:21:26 -07001084 // reaches the WPASupplicant::kInterfaceStateCompleted state.
mukesh agrawal15908392011-11-16 18:29:25 +00001085 affected_service =
1086 pending_service_.get() ? pending_service_.get() : current_service_.get();
1087 if (!affected_service) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001088 SLOG(WiFi, 2) << "WiFi " << link_name() << " " << __func__
1089 << " with no service";
mukesh agrawal15908392011-11-16 18:29:25 +00001090 return;
1091 }
1092
Paul Stewart0654ece2013-03-26 15:21:26 -07001093 if (new_state == WPASupplicant::kInterfaceStateCompleted) {
Paul Stewart44663922012-07-30 11:03:03 -07001094 if (affected_service->IsConnected()) {
1095 StopReconnectTimer();
Christopher Wiley5519e9e2013-01-08 16:55:56 -08001096 EnableHighBitrates();
Christopher Wiley8f81e2a2012-10-17 16:51:32 -07001097 } else if (has_already_completed_) {
1098 LOG(INFO) << link_name() << " L3 configuration already started.";
Paul Stewart44663922012-07-30 11:03:03 -07001099 } else if (AcquireIPConfigWithLeaseName(
Albert Chaulk0e1cdea2013-02-27 15:32:55 -08001100 GetServiceLeaseName(*affected_service))) {
Paul Stewartd408fdf2012-05-07 17:15:57 -07001101 LOG(INFO) << link_name() << " is up; started L3 configuration.";
mukesh agrawalc01f3982012-01-24 13:48:39 -08001102 affected_service->SetState(Service::kStateConfiguring);
1103 } else {
1104 LOG(ERROR) << "Unable to acquire DHCP config.";
1105 }
Christopher Wiley8f81e2a2012-10-17 16:51:32 -07001106 has_already_completed_ = true;
Paul Stewart0654ece2013-03-26 15:21:26 -07001107 } else if (new_state == WPASupplicant::kInterfaceStateAssociated) {
mukesh agrawal15908392011-11-16 18:29:25 +00001108 affected_service->SetState(Service::kStateAssociating);
Paul Stewart0654ece2013-03-26 15:21:26 -07001109 } else if (new_state == WPASupplicant::kInterfaceStateAuthenticating ||
1110 new_state == WPASupplicant::kInterfaceStateAssociating ||
1111 new_state == WPASupplicant::kInterfaceState4WayHandshake ||
1112 new_state == WPASupplicant::kInterfaceStateGroupHandshake) {
mukesh agrawal15908392011-11-16 18:29:25 +00001113 // Ignore transitions into these states from Completed, to avoid
1114 // bothering the user when roaming, or re-keying.
Paul Stewart0654ece2013-03-26 15:21:26 -07001115 if (old_state != WPASupplicant::kInterfaceStateCompleted)
mukesh agrawal15908392011-11-16 18:29:25 +00001116 affected_service->SetState(Service::kStateAssociating);
1117 // TOOD(quiche): On backwards transitions, we should probably set
1118 // a timeout for getting back into the completed state. At present,
1119 // we depend on wpa_supplicant eventually reporting that CurrentBSS
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001120 // has changed. But there may be cases where that signal is not sent.
mukesh agrawal15908392011-11-16 18:29:25 +00001121 // (crosbug.com/23207)
Paul Stewart0654ece2013-03-26 15:21:26 -07001122 } else if (new_state == WPASupplicant::kInterfaceStateDisconnected &&
Paul Stewart44663922012-07-30 11:03:03 -07001123 affected_service == current_service_ &&
1124 affected_service->IsConnected()) {
1125 // This means that wpa_supplicant failed in a re-connect attempt, but
1126 // may still be reconnecting. Give wpa_supplicant a limited amount of
1127 // time to transition out this condition by either connecting or changing
1128 // CurrentBSS.
1129 StartReconnectTimer();
mukesh agrawal15908392011-11-16 18:29:25 +00001130 } else {
1131 // Other transitions do not affect Service state.
1132 //
1133 // Note in particular that we ignore a State change into
1134 // kInterfaceStateDisconnected, in favor of observing the corresponding
1135 // change in CurrentBSS.
1136 }
mukesh agrawal7ec71312011-11-10 02:08:26 +00001137}
1138
Paul Stewart1369c2b2013-01-11 05:41:26 -08001139bool WiFi::SuspectCredentials(
1140 const WiFiService &service, Service::ConnectFailure *failure) const {
Paul Stewart1369c2b2013-01-11 05:41:26 -08001141 if (service.IsSecurityMatch(flimflam::kSecurityPsk)) {
Paul Stewart0654ece2013-03-26 15:21:26 -07001142 if (supplicant_state_ == WPASupplicant::kInterfaceState4WayHandshake &&
Paul Stewart1369c2b2013-01-11 05:41:26 -08001143 !service.has_ever_connected()) {
1144 if (failure) {
1145 *failure = Service::kFailureBadPassphrase;
1146 }
1147 return true;
1148 }
1149 } else if (service.IsSecurityMatch(flimflam::kSecurity8021x)) {
Paul Stewart735eab52013-03-29 09:19:23 -07001150 if (eap_state_handler_->is_eap_in_progress() &&
1151 !service.has_ever_connected()) {
Paul Stewart1369c2b2013-01-11 05:41:26 -08001152 if (failure) {
1153 *failure = Service::kFailureEAPAuthentication;
1154 }
1155 return true;
1156 }
mukesh agrawalcf24a242012-05-21 16:46:11 -07001157 }
1158
Paul Stewart1369c2b2013-01-11 05:41:26 -08001159 return false;
mukesh agrawalcf24a242012-05-21 16:46:11 -07001160}
1161
mukesh agrawal16bc1b82012-02-09 18:38:26 -08001162// static
1163bool WiFi::SanitizeSSID(string *ssid) {
1164 CHECK(ssid);
1165
1166 size_t ssid_len = ssid->length();
1167 size_t i;
1168 bool changed = false;
1169
Gary Morainac1bdb42012-02-16 17:42:29 -08001170 for (i = 0; i < ssid_len; ++i) {
mukesh agrawal16bc1b82012-02-09 18:38:26 -08001171 if (!g_ascii_isprint((*ssid)[i])) {
1172 (*ssid)[i] = '?';
1173 changed = true;
1174 }
1175 }
1176
1177 return changed;
1178}
1179
Darin Petkov50cb78a2013-02-06 16:17:49 +01001180// static
1181string WiFi::LogSSID(const string &ssid) {
1182 string out;
1183 for (string::const_iterator it = ssid.begin(); it != ssid.end(); ++it) {
1184 // Replace '[' and ']' (in addition to non-printable characters) so that
1185 // it's easy to match the right substring through a non-greedy regex.
1186 if (*it == '[' || *it == ']' || !g_ascii_isprint(*it)) {
1187 base::StringAppendF(&out, "\\x%02x", *it);
1188 } else {
1189 out += *it;
1190 }
1191 }
1192 return StringPrintf("[SSID=%s]", out.c_str());
1193}
1194
Paul Stewart3c508e12012-08-09 11:40:06 -07001195void WiFi::OnLinkMonitorFailure() {
1196 // If we have never found the gateway, let's be conservative and not
1197 // do anything, in case this network topology does not have a gateway.
1198 if (!link_monitor()->IsGatewayFound()) {
1199 LOG(INFO) << "In " << __func__ << "(): "
1200 << "Skipping reassociate since gateway was never found.";
1201 return;
1202 }
1203
1204 if (!supplicant_present_) {
1205 LOG(ERROR) << "In " << __func__ << "(): "
1206 << "wpa_supplicant is not present. Cannot reassociate.";
1207 return;
1208 }
1209
1210 try {
Christopher Wileye0b2a012012-10-31 13:11:27 -07001211 // This will force a transition out of connected, if we are actually
1212 // connected.
Paul Stewart3c508e12012-08-09 11:40:06 -07001213 supplicant_interface_proxy_->Reassociate();
Christopher Wileye0b2a012012-10-31 13:11:27 -07001214 // If we don't eventually get a transition back into a connected state,
1215 // there is something wrong.
1216 StartReconnectTimer();
Paul Stewart3c508e12012-08-09 11:40:06 -07001217 LOG(INFO) << "In " << __func__ << "(): Called Reassociate().";
1218 } catch (const DBus::Error &e) { // NOLINT
1219 LOG(ERROR) << "In " << __func__ << "(): failed to call Reassociate().";
1220 return;
1221 }
1222}
1223
Arman Ugurayed8e6102012-11-29 14:47:20 -08001224bool WiFi::ShouldUseArpGateway() const {
1225 return true;
1226}
1227
Paul Stewart3c504012013-01-17 17:49:58 -08001228void WiFi::DisassociateFromService(const WiFiServiceRefPtr &service) {
1229 DisconnectFrom(service);
1230 if (service == selected_service()) {
1231 DropConnection();
1232 }
1233 Error unused_error;
1234 RemoveNetworkForService(service, &unused_error);
1235}
1236
Gaurav Shah6d2c72d2012-10-16 16:30:44 -07001237vector<GeolocationInfo> WiFi::GetGeolocationObjects() const {
1238 vector<GeolocationInfo> objects;
1239 for (EndpointMap::const_iterator it = endpoint_by_rpcid_.begin();
1240 it != endpoint_by_rpcid_.end();
1241 ++it) {
1242 GeolocationInfo geoinfo;
1243 WiFiEndpointRefPtr endpoint = it->second;
1244 geoinfo.AddField(kGeoMacAddressProperty, endpoint->bssid_string());
1245 geoinfo.AddField(kGeoSignalStrengthProperty,
1246 StringPrintf("%d", endpoint->signal_strength()));
1247 geoinfo.AddField(
1248 kGeoChannelProperty,
1249 StringPrintf("%d",
1250 Metrics::WiFiFrequencyToChannel(endpoint->frequency())));
1251 // TODO(gauravsh): Include age field. crosbug.com/35445
1252 objects.push_back(geoinfo);
1253 }
1254 return objects;
1255}
1256
mukesh agrawal4d0401c2012-01-06 16:05:31 -08001257void WiFi::HelpRegisterDerivedInt32(
1258 PropertyStore *store,
1259 const string &name,
1260 int32(WiFi::*get)(Error *error),
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001261 bool(WiFi::*set)(const int32 &value, Error *error)) {
mukesh agrawal4d0401c2012-01-06 16:05:31 -08001262 store->RegisterDerivedInt32(
1263 name,
1264 Int32Accessor(new CustomAccessor<WiFi, int32>(this, get, set)));
1265}
1266
mukesh agrawal4d0401c2012-01-06 16:05:31 -08001267void WiFi::HelpRegisterDerivedUint16(
1268 PropertyStore *store,
1269 const string &name,
1270 uint16(WiFi::*get)(Error *error),
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001271 bool(WiFi::*set)(const uint16 &value, Error *error)) {
mukesh agrawal4d0401c2012-01-06 16:05:31 -08001272 store->RegisterDerivedUint16(
1273 name,
1274 Uint16Accessor(new CustomAccessor<WiFi, uint16>(this, get, set)));
1275}
1276
mukesh agrawal2f9df4e2012-08-08 12:29:20 -07001277void WiFi::OnAfterResume() {
mukesh agrawal5c05b292012-03-07 10:12:52 -08001278 LOG(INFO) << __func__;
mukesh agrawal2f9df4e2012-08-08 12:29:20 -07001279 Device::OnAfterResume(); // May refresh ipconfig_
mukesh agrawal5c05b292012-03-07 10:12:52 -08001280
mukesh agrawal2f9df4e2012-08-08 12:29:20 -07001281 // We want to flush the BSS cache, but we don't want to conflict
1282 // with a running scan or an active connection attempt. So record
1283 // the need to flush, and take care of flushing when the next scan
1284 // completes.
1285 //
1286 // Note that supplicant will automatically expire old cache
1287 // entries (after, e.g., a BSS is not found in two consecutive
1288 // scans). However, our explicit flush accelerates re-association
1289 // in cases where a BSS disappeared while we were asleep. (See,
1290 // e.g. WiFiRoaming.005SuspendRoam.)
1291 time_->GetTimeMonotonic(&resumed_at_);
1292 need_bss_flush_ = true;
1293
1294 if (!scan_pending_ && IsIdle()) {
1295 // Not scanning/connecting/connected, so let's get things rolling.
Wade Guthrie68d41092013-04-02 12:56:02 -07001296 Scan(kProgressiveScan, NULL);
mukesh agrawal2f9df4e2012-08-08 12:29:20 -07001297 } else {
1298 SLOG(WiFi, 1) << __func__
1299 << " skipping scan, already scanning or connected.";
Gary Morainac1bdb42012-02-16 17:42:29 -08001300 }
1301}
1302
Christopher Wiley5519e9e2013-01-08 16:55:56 -08001303void WiFi::OnConnected() {
1304 Device::OnConnected();
1305 EnableHighBitrates();
1306}
1307
Paul Stewarte369ece2012-05-22 09:11:03 -07001308void WiFi::RestartFastScanAttempts() {
1309 fast_scans_remaining_ = kNumFastScanAttempts;
1310 StartScanTimer();
1311}
1312
mukesh agrawalb66c6462012-05-07 11:45:25 -07001313void WiFi::StartScanTimer() {
1314 if (scan_interval_seconds_ == 0) {
1315 StopScanTimer();
1316 return;
1317 }
1318 scan_timer_callback_.Reset(
1319 Bind(&WiFi::ScanTimerHandler, weak_ptr_factory_.GetWeakPtr()));
Paul Stewarte369ece2012-05-22 09:11:03 -07001320 // Repeat the first few scans after disconnect relatively quickly so we
1321 // have reasonable trust that no APs we are looking for are present.
1322 dispatcher()->PostDelayedTask(scan_timer_callback_.callback(),
1323 fast_scans_remaining_ > 0 ?
1324 kFastScanIntervalSeconds * 1000 : scan_interval_seconds_ * 1000);
mukesh agrawalb66c6462012-05-07 11:45:25 -07001325}
1326
1327void WiFi::StopScanTimer() {
1328 scan_timer_callback_.Cancel();
1329}
1330
1331void WiFi::ScanTimerHandler() {
1332 SLOG(WiFi, 2) << "WiFi Device " << link_name() << ": " << __func__;
1333 if (IsIdle() && !scan_pending_) {
Wade Guthrie68d41092013-04-02 12:56:02 -07001334 Scan(kProgressiveScan, NULL);
Paul Stewarte369ece2012-05-22 09:11:03 -07001335 if (fast_scans_remaining_ > 0) {
1336 --fast_scans_remaining_;
1337 }
mukesh agrawalb66c6462012-05-07 11:45:25 -07001338 }
1339 StartScanTimer();
1340}
1341
Paul Stewart2b05e622012-07-13 20:38:44 -07001342void WiFi::StartPendingTimer() {
1343 pending_timeout_callback_.Reset(
1344 Bind(&WiFi::PendingTimeoutHandler, weak_ptr_factory_.GetWeakPtr()));
1345 dispatcher()->PostDelayedTask(pending_timeout_callback_.callback(),
1346 kPendingTimeoutSeconds * 1000);
1347}
1348
1349void WiFi::StopPendingTimer() {
1350 pending_timeout_callback_.Cancel();
1351}
1352
1353void WiFi::SetPendingService(const WiFiServiceRefPtr &service) {
Paul Stewartff96a842012-08-13 15:59:10 -07001354 SLOG(WiFi, 2) << "WiFi " << link_name() << " setting pending service to "
Darin Petkov457728b2013-01-09 09:49:08 +01001355 << (service ? service->unique_name(): "NULL");
Paul Stewart2b05e622012-07-13 20:38:44 -07001356 if (service) {
1357 service->SetState(Service::kStateAssociating);
1358 StartPendingTimer();
1359 } else if (pending_service_) {
1360 StopPendingTimer();
1361 }
1362 pending_service_ = service;
1363}
1364
1365void WiFi::PendingTimeoutHandler() {
mukesh agrawald4dc0832013-03-25 14:38:26 -07001366 Error unused_error;
Paul Stewart2b05e622012-07-13 20:38:44 -07001367 LOG(INFO) << "WiFi Device " << link_name() << ": " << __func__;
1368 CHECK(pending_service_);
mukesh agrawald4dc0832013-03-25 14:38:26 -07001369 pending_service_->DisconnectWithFailure(
1370 Service::kFailureOutOfRange, &unused_error);
Paul Stewart17d90652013-04-04 15:09:11 -07001371
1372 // A hidden service may have no endpoints, since wpa_supplicant
1373 // failed to attain a CurrentBSS. If so, the service has no
1374 // reference to |this| device and cannot call WiFi::DisconnectFrom()
1375 // to reset pending_service_. In this case, we must perform the
1376 // disconnect here ourselves.
1377 if (pending_service_) {
1378 CHECK(!pending_service_->HasEndpoints());
1379 LOG(INFO) << "Hidden service was not found.";
1380 DisconnectFrom(pending_service_);
1381 }
Paul Stewart2b05e622012-07-13 20:38:44 -07001382}
1383
Paul Stewart44663922012-07-30 11:03:03 -07001384void WiFi::StartReconnectTimer() {
Paul Stewart1aff7302012-08-04 20:04:47 -07001385 if (!reconnect_timeout_callback_.IsCancelled()) {
1386 LOG(INFO) << "WiFi Device " << link_name() << ": " << __func__
1387 << ": reconnect timer already running.";
1388 return;
1389 }
Paul Stewart44663922012-07-30 11:03:03 -07001390 LOG(INFO) << "WiFi Device " << link_name() << ": " << __func__;
1391 reconnect_timeout_callback_.Reset(
1392 Bind(&WiFi::ReconnectTimeoutHandler, weak_ptr_factory_.GetWeakPtr()));
1393 dispatcher()->PostDelayedTask(reconnect_timeout_callback_.callback(),
1394 kReconnectTimeoutSeconds * 1000);
1395}
1396
1397void WiFi::StopReconnectTimer() {
1398 SLOG(WiFi, 2) << "WiFi Device " << link_name() << ": " << __func__;
1399 reconnect_timeout_callback_.Cancel();
1400}
1401
1402void WiFi::ReconnectTimeoutHandler() {
1403 LOG(INFO) << "WiFi Device " << link_name() << ": " << __func__;
Paul Stewart1aff7302012-08-04 20:04:47 -07001404 reconnect_timeout_callback_.Cancel();
Paul Stewart44663922012-07-30 11:03:03 -07001405 CHECK(current_service_);
1406 current_service_->SetFailureSilent(Service::kFailureConnect);
1407 DisconnectFrom(current_service_);
1408}
1409
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001410void WiFi::OnSupplicantAppear(const string &/*owner*/) {
1411 LOG(INFO) << "WPA supplicant appeared.";
1412 if (supplicant_present_) {
Darin Petkov9cd7ca12012-07-03 11:06:40 +02001413 // Restart the WiFi device if it's started already. This will reset the
1414 // state and connect the device to the new WPA supplicant instance.
1415 if (enabled()) {
1416 Restart();
1417 }
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001418 return;
1419 }
1420 supplicant_present_ = true;
1421 ConnectToSupplicant();
1422}
1423
1424void WiFi::OnSupplicantVanish() {
1425 LOG(INFO) << "WPA supplicant vanished.";
1426 if (!supplicant_present_) {
1427 return;
1428 }
1429 supplicant_present_ = false;
1430 // Restart the WiFi device if it's started already. This will effectively
1431 // suspend the device until the WPA supplicant reappears.
1432 if (enabled()) {
1433 Restart();
1434 }
1435}
1436
Paul Stewart5581d072012-12-17 17:30:20 -08001437void WiFi::OnWiFiDebugScopeChanged(bool enabled) {
1438 SLOG(WiFi, 2) << "WiFi debug scope changed; enable is now " << enabled;
1439 if (!supplicant_process_proxy_.get()) {
1440 SLOG(WiFi, 2) << "Suplicant process proxy not present.";
1441 return;
1442 }
1443 string current_level;
1444 try {
1445 current_level = supplicant_process_proxy_->GetDebugLevel();
1446 } catch (const DBus::Error &e) { // NOLINT
1447 LOG(ERROR) << __func__ << ": Failed to get wpa_supplicant debug level.";
1448 return;
1449 }
1450
Paul Stewart0654ece2013-03-26 15:21:26 -07001451 if (current_level != WPASupplicant::kDebugLevelInfo &&
1452 current_level != WPASupplicant::kDebugLevelDebug) {
Paul Stewart5581d072012-12-17 17:30:20 -08001453 SLOG(WiFi, 2) << "WiFi debug level is currently "
1454 << current_level
1455 << "; assuming that it is being controlled elsewhere.";
1456 return;
1457 }
Paul Stewart0654ece2013-03-26 15:21:26 -07001458 string new_level = enabled ? WPASupplicant::kDebugLevelDebug :
1459 WPASupplicant::kDebugLevelInfo;
Paul Stewart5581d072012-12-17 17:30:20 -08001460
1461 if (new_level == current_level) {
1462 SLOG(WiFi, 2) << "WiFi debug level is already the desired level "
1463 << current_level;
1464 return;
1465 }
1466
1467 try {
1468 supplicant_process_proxy_->SetDebugLevel(new_level);
1469 } catch (const DBus::Error &e) { // NOLINT
1470 LOG(ERROR) << __func__ << ": Failed to set wpa_supplicant debug level.";
1471 }
1472}
1473
Paul Stewarta47c3c62012-12-18 12:14:29 -08001474void WiFi::SetConnectionDebugging(bool enabled) {
1475 if (is_debugging_connection_ == enabled) {
1476 return;
1477 }
1478 OnWiFiDebugScopeChanged(
1479 enabled ||
1480 ScopeLogger::GetInstance()->IsScopeEnabled(ScopeLogger::kWiFi));
1481 is_debugging_connection_ = enabled;
1482}
1483
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001484void WiFi::ConnectToSupplicant() {
1485 LOG(INFO) << link_name() << ": " << (enabled() ? "enabled" : "disabled")
1486 << " supplicant: "
1487 << (supplicant_present_ ? "present" : "absent")
1488 << " proxy: "
1489 << (supplicant_process_proxy_.get() ? "non-null" : "null");
1490 if (!enabled() || !supplicant_present_ || supplicant_process_proxy_.get()) {
1491 return;
1492 }
1493 supplicant_process_proxy_.reset(
1494 proxy_factory_->CreateSupplicantProcessProxy(
Paul Stewart0654ece2013-03-26 15:21:26 -07001495 WPASupplicant::kDBusPath, WPASupplicant::kDBusAddr));
Paul Stewart5581d072012-12-17 17:30:20 -08001496 OnWiFiDebugScopeChanged(
1497 ScopeLogger::GetInstance()->IsScopeEnabled(ScopeLogger::kWiFi));
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001498 ::DBus::Path interface_path;
1499 try {
1500 map<string, DBus::Variant> create_interface_args;
Paul Stewart0654ece2013-03-26 15:21:26 -07001501 create_interface_args[WPASupplicant::kInterfacePropertyName].writer().
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001502 append_string(link_name().c_str());
Paul Stewart0654ece2013-03-26 15:21:26 -07001503 create_interface_args[WPASupplicant::kInterfacePropertyDriver].writer().
1504 append_string(WPASupplicant::kDriverNL80211);
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001505 create_interface_args[
Paul Stewart0654ece2013-03-26 15:21:26 -07001506 WPASupplicant::kInterfacePropertyConfigFile].writer().
Paul Stewart196f50f2013-03-27 18:02:11 -07001507 append_string(WPASupplicant::kSupplicantConfPath);
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001508 interface_path =
1509 supplicant_process_proxy_->CreateInterface(create_interface_args);
1510 } catch (const DBus::Error &e) { // NOLINT
Paul Stewart0654ece2013-03-26 15:21:26 -07001511 if (!strcmp(e.name(), WPASupplicant::kErrorInterfaceExists)) {
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001512 interface_path =
1513 supplicant_process_proxy_->GetInterface(link_name());
1514 // TODO(quiche): Is it okay to crash here, if device is missing?
1515 } else {
Paul Stewartb80c81c2012-06-28 13:05:45 -07001516 LOG(ERROR) << __func__ << ": Failed to create interface with supplicant.";
1517 return;
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001518 }
1519 }
1520
1521 supplicant_interface_proxy_.reset(
1522 proxy_factory_->CreateSupplicantInterfaceProxy(
Paul Stewart0654ece2013-03-26 15:21:26 -07001523 this, interface_path, WPASupplicant::kDBusAddr));
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001524
1525 RTNLHandler::GetInstance()->SetInterfaceFlags(interface_index(), IFF_UP,
1526 IFF_UP);
1527 // TODO(quiche) Set ApScan=1 and BSSExpireAge=190, like flimflam does?
1528
1529 // Clear out any networks that might previously have been configured
1530 // for this interface.
1531 supplicant_interface_proxy_->RemoveAllNetworks();
1532
1533 // Flush interface's BSS cache, so that we get BSSAdded signals for
1534 // all BSSes (not just new ones since the last scan).
1535 supplicant_interface_proxy_->FlushBSS(0);
1536
1537 try {
1538 // TODO(pstew): Disable fast_reauth until supplicant can properly deal
1539 // with RADIUS servers that respond strangely to such requests.
1540 // crosbug.com/25630
1541 supplicant_interface_proxy_->SetFastReauth(false);
1542 } catch (const DBus::Error &e) { // NOLINT
Christopher Wiley5519e9e2013-01-08 16:55:56 -08001543 LOG(ERROR) << "Failed to disable fast_reauth. "
1544 << "May be running an older version of wpa_supplicant.";
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001545 }
1546
1547 try {
1548 // Helps with passing WiFiRomaing.001SSIDSwitchBack.
1549 supplicant_interface_proxy_->SetScanInterval(kRescanIntervalSeconds);
1550 } catch (const DBus::Error &e) { // NOLINT
Christopher Wiley5519e9e2013-01-08 16:55:56 -08001551 LOG(ERROR) << "Failed to set scan_interval. "
1552 << "May be running an older version of wpa_supplicant.";
1553 }
1554
1555 try {
1556 supplicant_interface_proxy_->SetDisableHighBitrates(true);
1557 } catch (const DBus::Error &e) { // NOLINT
1558 LOG(ERROR) << "Failed to disable high bitrates. "
1559 << "May be running an older version of wpa_supplicant.";
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001560 }
1561
Wade Guthrie68d41092013-04-02 12:56:02 -07001562 Scan(kProgressiveScan, NULL);
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001563 StartScanTimer();
1564}
1565
Christopher Wiley5519e9e2013-01-08 16:55:56 -08001566void WiFi::EnableHighBitrates() {
1567 LOG(INFO) << "Enabling high bitrates.";
1568 try {
1569 supplicant_interface_proxy_->EnableHighBitrates();
1570 } catch (const DBus::Error &e) { // NOLINT
1571 LOG(ERROR) << "exception while enabling high rates: " << e.what();
1572 }
1573}
1574
Darin Petkov2b8e44e2012-06-25 15:13:26 +02001575void WiFi::Restart() {
1576 LOG(INFO) << link_name() << " restarting.";
1577 WiFiRefPtr me = this; // Make sure we don't get destructed.
1578 // Go through the manager rather than starting and stopping the device
1579 // directly so that the device can be configured with the profile.
1580 manager()->DeregisterDevice(me);
1581 manager()->RegisterDevice(me);
1582}
1583
Wade Guthrie92d06362013-04-25 15:41:30 -07001584void WiFi::ConfigureScanFrequencies() {
1585 GetWiphyMessage get_wiphy;
1586 get_wiphy.attributes()->SetU32AttributeValue(NL80211_ATTR_IFINDEX,
1587 interface_index());
1588 netlink_manager_->SendMessage(&get_wiphy,
1589 Bind(&WiFi::OnNewWiphy,
1590 weak_ptr_factory_.GetWeakPtr()));
1591}
1592
1593void WiFi::OnNewWiphy(const NetlinkMessage &netlink_message) {
1594 // Note that we don't fail fatally from this routine because, while it
1595 // provides frequencies for a progressive scan, a failed progressive scan is
1596 // followed by a full scan (which doesn't use the frequency list provided by
1597 // this call).
1598 if (netlink_message.message_type() == ErrorAckMessage::kMessageType) {
1599 const ErrorAckMessage *error_ack_message =
1600 reinterpret_cast<const ErrorAckMessage *>(&netlink_message);
1601 if (error_ack_message->error()) {
1602 LOG(ERROR) << __func__ << ": Message (seq: "
1603 << netlink_message.sequence_number() << ") failed: "
1604 << error_ack_message->ToString();
1605 } else {
1606 SLOG(WiFi, 6) << __func__ << ": Message (seq: "
1607 << netlink_message.sequence_number() << ") ACKed";
1608 }
1609 return;
1610 }
1611
1612 // We only handle a special set of messages, all of which are nl80211
1613 // messages.
1614 if (netlink_message.message_type() != Nl80211Message::GetMessageType()) {
1615 LOG(ERROR) << "Received unexpected message type: "
1616 << netlink_message.message_type();
1617 return;
1618 }
1619
1620 const Nl80211Message *nl80211_message =
1621 dynamic_cast<const Nl80211Message *>(&netlink_message);
1622 // Verify NL80211_CMD_NEW_WIPHY
1623 if (nl80211_message->command() != NewWiphyMessage::kCommand) {
1624 LOG(ERROR) << "Received unexpected command:"
1625 << nl80211_message->command();
1626 return;
1627 }
1628
1629 // The attributes, for this message, are complicated.
1630 // NL80211_ATTR_BANDS contains an array of bands...
1631 AttributeListConstRefPtr wiphy_bands;
1632 if (!nl80211_message->const_attributes()->ConstGetNestedAttributeList(
1633 NL80211_ATTR_WIPHY_BANDS, &wiphy_bands)) {
1634 LOG(ERROR) << "NL80211_CMD_NEW_WIPHY had no NL80211_ATTR_WIPHY_BANDS";
1635 return;
1636 }
1637
1638 AttributeIdIterator band_iter(*wiphy_bands);
1639 for (; !band_iter.AtEnd(); band_iter.Advance()) {
1640 AttributeListConstRefPtr wiphy_band;
1641 if (!wiphy_bands->ConstGetNestedAttributeList(band_iter.GetId(),
1642 &wiphy_band)) {
1643 LOG(WARNING) << "WiFi band " << band_iter.GetId() << " not found";
1644 continue;
1645 }
1646
1647 // ...Each band has a FREQS attribute...
1648 AttributeListConstRefPtr frequencies;
1649 if (!wiphy_band->ConstGetNestedAttributeList(NL80211_BAND_ATTR_FREQS,
1650 &frequencies)) {
1651 LOG(ERROR) << "BAND " << band_iter.GetId()
1652 << " had no 'frequencies' attribute";
1653 continue;
1654 }
1655
1656 // ...And each FREQS attribute contains an array of information about the
1657 // frequency...
1658 AttributeIdIterator freq_iter(*frequencies);
1659 for (; !freq_iter.AtEnd(); freq_iter.Advance()) {
1660 AttributeListConstRefPtr frequency;
1661 if (frequencies->ConstGetNestedAttributeList(freq_iter.GetId(),
1662 &frequency)) {
1663 // ...Including the frequency, itself (the part we want).
1664 uint32_t frequency_value = 0;
1665 if (frequency->GetU32AttributeValue(NL80211_FREQUENCY_ATTR_FREQ,
1666 &frequency_value)) {
1667 SLOG(WiFi, 5) << "Found frequency[" << freq_iter.GetId()
1668 << "] = " << frequency_value;
1669 all_scan_frequencies_.insert(frequency_value);
1670 }
1671 }
1672 }
1673 }
1674}
1675
Paul Stewartb50f0b92011-05-16 16:31:42 -07001676} // namespace shill