blob: b2027771c41b1e299981d32a70b4f36f07159876 [file] [log] [blame]
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Paul Stewart75897df2011-04-27 09:05:53 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Chris Masone8fe2c7e2011-06-09 15:51:19 -07005#include "shill/manager.h"
6
Paul Stewart75897df2011-04-27 09:05:53 -07007#include <time.h>
Paul Stewart75897df2011-04-27 09:05:53 -07008#include <stdio.h>
Chris Masoneee929b72011-05-10 10:02:18 -07009
Paul Stewart22aa71b2011-09-16 12:15:11 -070010#include <algorithm>
Jason Glasgowdf7c5532012-05-14 14:41:45 -040011#include <set>
Paul Stewart75897df2011-04-27 09:05:53 -070012#include <string>
Chris Masone52cd19b2011-06-29 17:23:04 -070013#include <vector>
Paul Stewart75897df2011-04-27 09:05:53 -070014
Eric Shienbrood3e20a232012-02-16 11:35:56 -050015#include <base/bind.h>
Paul Stewarte6132022011-08-16 09:11:02 -070016#include <base/file_util.h>
Chris Masone9be4a9d2011-05-16 15:44:09 -070017#include <base/memory/ref_counted.h>
Eric Shienbrood3e20a232012-02-16 11:35:56 -050018#include <base/stringprintf.h>
Paul Stewart4d5efb72012-09-17 12:24:34 -070019#include <base/string_split.h>
Paul Stewart22aa71b2011-09-16 12:15:11 -070020#include <base/string_util.h>
Chris Masone3bd3c8c2011-06-13 08:20:26 -070021#include <chromeos/dbus/service_constants.h>
Chris Masoneee929b72011-05-10 10:02:18 -070022
Chris Masoned0ceb8c2011-06-02 10:05:39 -070023#include "shill/adaptor_interfaces.h"
mukesh agrawal46c27cc2013-07-10 16:39:10 -070024#include "shill/callbacks.h"
Paul Stewartc1dec4d2011-12-08 15:25:28 -080025#include "shill/connection.h"
Paul Stewart75897df2011-04-27 09:05:53 -070026#include "shill/control_interface.h"
Chris Masoned0ceb8c2011-06-02 10:05:39 -070027#include "shill/dbus_adaptor.h"
Darin Petkov002c58e2012-06-19 02:56:05 +020028#include "shill/dbus_manager.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070029#include "shill/default_profile.h"
Chris Masone9be4a9d2011-05-16 15:44:09 -070030#include "shill/device.h"
31#include "shill/device_info.h"
Chris Masone6791a432011-07-12 13:23:19 -070032#include "shill/ephemeral_profile.h"
Chris Masone8fe2c7e2011-06-09 15:51:19 -070033#include "shill/error.h"
Paul Stewart35eff132013-04-12 12:08:40 -070034#include "shill/ethernet_eap_provider.h"
35#include "shill/ethernet_eap_service.h"
Paul Stewart26b327e2011-10-19 11:38:09 -070036#include "shill/event_dispatcher.h"
Gaurav Shahb790aa22012-10-23 12:51:12 -070037#include "shill/geolocation_info.h"
Gary Moraina9fb3252012-05-31 12:05:31 -070038#include "shill/hook_table.h"
Prathmesh Prabhuba99b592013-04-17 15:13:14 -070039#include "shill/ip_address_store.h"
Chris Masone9d779932011-08-25 16:33:41 -070040#include "shill/key_file_store.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070041#include "shill/logging.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070042#include "shill/profile.h"
Chris Masoneb925cc82011-06-22 15:39:57 -070043#include "shill/property_accessor.h"
Gary Morainac1bdb42012-02-16 17:42:29 -080044#include "shill/proxy_factory.h"
Paul Stewarte6132022011-08-16 09:11:02 -070045#include "shill/resolver.h"
mukesh agrawal46c27cc2013-07-10 16:39:10 -070046#include "shill/result_aggregator.h"
Chris Masone9be4a9d2011-05-16 15:44:09 -070047#include "shill/service.h"
Thieu Lea20cbc22012-01-09 22:01:43 +000048#include "shill/service_sorter.h"
Darin Petkovc3505a52013-03-18 15:13:29 +010049#include "shill/vpn_provider.h"
Darin Petkov33af05c2012-02-28 10:10:30 +010050#include "shill/vpn_service.h"
mukesh agrawal7a4e4002011-09-06 11:26:05 -070051#include "shill/wifi.h"
Paul Stewart3c504012013-01-17 17:49:58 -080052#include "shill/wifi_provider.h"
mukesh agrawal7a4e4002011-09-06 11:26:05 -070053#include "shill/wifi_service.h"
Darin Petkovd1cd7972012-05-22 15:26:15 +020054#include "shill/wimax_service.h"
Paul Stewart75897df2011-04-27 09:05:53 -070055
Eric Shienbrood3e20a232012-02-16 11:35:56 -050056using base::Bind;
Albert Chaulk0e1cdea2013-02-27 15:32:55 -080057using base::FilePath;
Eric Shienbrood3e20a232012-02-16 11:35:56 -050058using base::StringPrintf;
59using base::Unretained;
Darin Petkova5e07ef2012-07-09 14:27:57 +020060using std::map;
Gaurav Shah435de2c2011-11-17 19:01:07 -080061using std::set;
Paul Stewart75897df2011-04-27 09:05:53 -070062using std::string;
Chris Masone9be4a9d2011-05-16 15:44:09 -070063using std::vector;
Paul Stewart75897df2011-04-27 09:05:53 -070064
65namespace shill {
Paul Stewarte6132022011-08-16 09:11:02 -070066
Daniel Eratf9753672013-01-24 10:17:02 -080067namespace {
68
69// Human-readable string describing the suspend delay that is registered
70// with the power manager.
71const char kSuspendDelayDescription[] = "shill";
72
73} // namespace
74
Darin Petkovb65c2452012-02-23 15:17:06 +010075// statics
76const char Manager::kErrorNoDevice[] = "no wifi devices available";
77const char Manager::kErrorTypeRequired[] = "must specify service type";
78const char Manager::kErrorUnsupportedServiceType[] =
79 "service type is unsupported";
Arman Ugurayab22c162012-10-08 19:08:38 -070080// This timeout should be less than the upstart job timeout, otherwise
81// stats for termination actions might be lost.
82const int Manager::kTerminationActionsTimeoutMilliseconds = 4500;
Darin Petkov3ec55342012-09-28 14:04:44 +020083const char Manager::kPowerManagerKey[] = "manager";
mukesh agrawal7a4e4002011-09-06 11:26:05 -070084
Paul Stewart75897df2011-04-27 09:05:53 -070085Manager::Manager(ControlInterface *control_interface,
Darin Petkov887f2982011-07-14 16:10:17 -070086 EventDispatcher *dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -080087 Metrics *metrics,
Chris Masone2ae797d2011-08-23 20:41:00 -070088 GLib *glib,
89 const string &run_directory,
90 const string &storage_directory,
91 const string &user_storage_format)
mukesh agrawal8a3188d2011-12-01 20:56:44 +000092 : dispatcher_(dispatcher),
mukesh agrawal8a3188d2011-12-01 20:56:44 +000093 run_path_(FilePath(run_directory)),
94 storage_path_(FilePath(storage_directory)),
95 user_storage_format_(user_storage_format),
mukesh agrawald142fd62013-05-01 16:50:57 -070096 user_profile_list_path_(FilePath(Profile::kUserProfileListPathname)),
mukesh agrawal8a3188d2011-12-01 20:56:44 +000097 adaptor_(control_interface->CreateManagerAdaptor(this)),
Thieu Le3426c8f2012-01-11 17:35:11 -080098 device_info_(control_interface, dispatcher, metrics, this),
99 modem_info_(control_interface, dispatcher, metrics, this, glib),
Paul Stewart35eff132013-04-12 12:08:40 -0700100 ethernet_eap_provider_(
101 new EthernetEapProvider(
102 control_interface, dispatcher, metrics, this)),
Darin Petkovc3505a52013-03-18 15:13:29 +0100103 vpn_provider_(
104 new VPNProvider(control_interface, dispatcher, metrics, this)),
Paul Stewart3c504012013-01-17 17:49:58 -0800105 wifi_provider_(
106 new WiFiProvider(control_interface, dispatcher, metrics, this)),
Darin Petkovb72b62e2012-05-15 16:55:36 +0200107 wimax_provider_(control_interface, dispatcher, metrics, this),
Paul Stewart4d5efb72012-09-17 12:24:34 -0700108 resolver_(Resolver::GetInstance()),
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000109 running_(false),
110 connect_profiles_to_rpc_(true),
Thieu Le5133b712013-02-19 14:47:21 -0800111 ephemeral_profile_(
112 new EphemeralProfile(control_interface, metrics, this)),
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000113 control_interface_(control_interface),
Thieu Le3426c8f2012-01-11 17:35:11 -0800114 metrics_(metrics),
Paul Stewart10e9e4e2012-04-26 19:46:28 -0700115 glib_(glib),
Gary Moraina9fb3252012-05-31 12:05:31 -0700116 use_startup_portal_list_(false),
Darin Petkova5e07ef2012-07-09 14:27:57 +0200117 termination_actions_(dispatcher),
Daniel Erat0818cca2012-12-14 10:16:21 -0800118 suspend_delay_registered_(false),
119 suspend_delay_id_(0),
Christopher Wiley1057cd72013-02-28 15:21:29 -0800120 default_service_callback_tag_(0),
Prathmesh Prabhuba99b592013-04-17 15:13:14 -0700121 crypto_util_proxy_(new CryptoUtilProxy(dispatcher, glib)),
122 health_checker_remote_ips_(new IPAddressStore()) {
Chris Masone7aa5f902011-07-11 11:13:35 -0700123 HelpRegisterDerivedString(flimflam::kActiveProfileProperty,
Paul Stewart1b253142012-01-26 14:05:52 -0800124 &Manager::GetActiveProfileRpcIdentifier,
Chris Masone7aa5f902011-07-11 11:13:35 -0700125 NULL);
Paul Stewartd408fdf2012-05-07 17:15:57 -0700126 store_.RegisterBool(flimflam::kArpGatewayProperty, &props_.arp_gateway);
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700127 HelpRegisterConstDerivedStrings(flimflam::kAvailableTechnologiesProperty,
128 &Manager::AvailableTechnologies);
Paul Stewart10e9e4e2012-04-26 19:46:28 -0700129 HelpRegisterDerivedString(flimflam::kCheckPortalListProperty,
130 &Manager::GetCheckPortalList,
131 &Manager::SetCheckPortalList);
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700132 HelpRegisterConstDerivedStrings(flimflam::kConnectedTechnologiesProperty,
133 &Manager::ConnectedTechnologies);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700134 store_.RegisterString(flimflam::kCountryProperty, &props_.country);
Chris Masone27c4aa52011-07-02 13:10:14 -0700135 HelpRegisterDerivedString(flimflam::kDefaultTechnologyProperty,
136 &Manager::DefaultTechnology,
137 NULL);
Paul Stewart49739c02012-08-08 17:24:03 -0700138 HelpRegisterConstDerivedRpcIdentifier(
139 shill::kDefaultServiceProperty,
140 &Manager::GetDefaultServiceRpcIdentifier);
Paul Stewartcb3eb892012-06-07 14:24:46 -0700141 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kDevicesProperty,
142 &Manager::EnumerateDevices);
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700143 HelpRegisterConstDerivedStrings(flimflam::kEnabledTechnologiesProperty,
144 &Manager::EnabledTechnologies);
Paul Stewart4d5efb72012-09-17 12:24:34 -0700145 HelpRegisterDerivedString(shill::kIgnoredDNSSearchPathsProperty,
146 &Manager::GetIgnoredDNSSearchPaths,
147 &Manager::SetIgnoredDNSSearchPaths);
Paul Stewart036dba02012-08-07 12:34:41 -0700148 store_.RegisterString(shill::kLinkMonitorTechnologiesProperty,
149 &props_.link_monitor_technologies);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700150 store_.RegisterBool(flimflam::kOfflineModeProperty, &props_.offline_mode);
151 store_.RegisterString(flimflam::kPortalURLProperty, &props_.portal_url);
Paul Stewartc681fa02012-03-02 19:40:04 -0800152 store_.RegisterInt32(kPortalCheckIntervalProperty,
153 &props_.portal_check_interval_seconds);
Paul Stewartcb3eb892012-06-07 14:24:46 -0700154 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kProfilesProperty,
155 &Manager::EnumerateProfiles);
Paul Stewartc681fa02012-03-02 19:40:04 -0800156 store_.RegisterString(kHostNameProperty, &props_.host_name);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700157 HelpRegisterDerivedString(flimflam::kStateProperty,
158 &Manager::CalculateState,
159 NULL);
mukesh agrawal2366eed2012-03-20 18:21:50 -0700160 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kServicesProperty,
161 &Manager::EnumerateAvailableServices);
Paul Stewart3c504012013-01-17 17:49:58 -0800162 HelpRegisterConstDerivedRpcIdentifiers(shill::kServiceCompleteListProperty,
163 &Manager::EnumerateCompleteServices);
Paul Stewartcb3eb892012-06-07 14:24:46 -0700164 HelpRegisterConstDerivedRpcIdentifiers(flimflam::kServiceWatchListProperty,
165 &Manager::EnumerateWatchedServices);
mukesh agrawalbebf1b82013-04-23 15:06:33 -0700166 HelpRegisterConstDerivedStrings(kUninitializedTechnologiesProperty,
167 &Manager::UninitializedTechnologies);
Chris Masone3c3f6a12011-07-01 10:01:41 -0700168
mukesh agrawal84de5d22012-02-17 19:29:15 -0800169 // Set default technology order "by hand", to avoid invoking side
170 // effects of SetTechnologyOrder.
171 technology_order_.push_back(
Darin Petkov2f903b32012-04-18 12:56:43 +0200172 Technology::IdentifierFromName(flimflam::kTypeVPN));
173 technology_order_.push_back(
mukesh agrawal84de5d22012-02-17 19:29:15 -0800174 Technology::IdentifierFromName(flimflam::kTypeEthernet));
175 technology_order_.push_back(
176 Technology::IdentifierFromName(flimflam::kTypeWifi));
177 technology_order_.push_back(
Ben Chan3cafe382012-11-13 07:51:10 -0800178 Technology::IdentifierFromName(flimflam::kTypeWimax));
179 technology_order_.push_back(
mukesh agrawal84de5d22012-02-17 19:29:15 -0800180 Technology::IdentifierFromName(flimflam::kTypeCellular));
181
Ben Chanfad4a0b2012-04-18 15:49:59 -0700182 SLOG(Manager, 2) << "Manager initialized.";
Paul Stewart75897df2011-04-27 09:05:53 -0700183}
184
Darin Petkove7c6ad32012-06-29 10:22:09 +0200185Manager::~Manager() {}
Paul Stewart75897df2011-04-27 09:05:53 -0700186
mukesh agrawal8f317b62011-07-15 11:53:23 -0700187void Manager::AddDeviceToBlackList(const string &device_name) {
188 device_info_.AddDeviceToBlackList(device_name);
189}
190
Paul Stewart75897df2011-04-27 09:05:53 -0700191void Manager::Start() {
Paul Stewart0af98bf2011-05-10 17:38:08 -0700192 LOG(INFO) << "Manager started.";
Paul Stewarte6132022011-08-16 09:11:02 -0700193
Darin Petkov002c58e2012-06-19 02:56:05 +0200194 dbus_manager_.reset(new DBusManager());
195 dbus_manager_->Start();
196
Darin Petkov3ec55342012-09-28 14:04:44 +0200197 power_manager_.reset(
198 new PowerManager(dispatcher_, ProxyFactory::GetInstance()));
Darin Petkovca621542012-07-25 14:25:56 +0200199 power_manager_->AddStateChangeCallback(
Darin Petkov3ec55342012-09-28 14:04:44 +0200200 kPowerManagerKey,
Darin Petkovca621542012-07-25 14:25:56 +0200201 Bind(&Manager::OnPowerStateChanged, AsWeakPtr()));
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500202 // TODO(ers): weak ptr for metrics_?
203 PowerManager::PowerStateCallback cb =
204 Bind(&Metrics::NotifyPowerStateChange, Unretained(metrics_));
Thieu Leb84ba342012-03-02 15:15:19 -0800205 power_manager_->AddStateChangeCallback(Metrics::kMetricPowerManagerKey, cb);
206
Chris Masone2ae797d2011-08-23 20:41:00 -0700207 CHECK(file_util::CreateDirectory(run_path_)) << run_path_.value();
Paul Stewart4d5efb72012-09-17 12:24:34 -0700208 resolver_->set_path(run_path_.Append("resolv.conf"));
Chris Masone2ae797d2011-08-23 20:41:00 -0700209
Gaurav Shah71354762011-11-28 19:22:49 -0800210 InitializeProfiles();
Paul Stewart75897df2011-04-27 09:05:53 -0700211 running_ = true;
Chris Masone413a3192011-05-09 17:10:05 -0700212 adaptor_->UpdateRunning();
Paul Stewart0af98bf2011-05-10 17:38:08 -0700213 device_info_.Start();
Darin Petkov887f2982011-07-14 16:10:17 -0700214 modem_info_.Start();
Paul Stewart35eff132013-04-12 12:08:40 -0700215 ethernet_eap_provider_->Start();
Darin Petkovc3505a52013-03-18 15:13:29 +0100216 vpn_provider_->Start();
Paul Stewart3c504012013-01-17 17:49:58 -0800217 wifi_provider_->Start();
Darin Petkov9893d9c2012-05-17 15:27:31 -0700218 wimax_provider_.Start();
Paul Stewart75897df2011-04-27 09:05:53 -0700219}
220
221void Manager::Stop() {
222 running_ = false;
Paul Stewart212d60f2012-07-12 10:59:13 -0700223 // Persist device information to disk;
224 vector<DeviceRefPtr>::iterator devices_it;
225 for (devices_it = devices_.begin(); devices_it != devices_.end();
226 ++devices_it) {
227 UpdateDevice(*devices_it);
228 }
229
Wade Guthrie60a37062013-04-02 11:39:09 -0700230 UpdateWiFiProvider();
231
Paul Stewart212d60f2012-07-12 10:59:13 -0700232 // Persist profile, service information to disk.
233 vector<ProfileRefPtr>::iterator profiles_it;
234 for (profiles_it = profiles_.begin(); profiles_it != profiles_.end();
235 ++profiles_it) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700236 // Since this happens in a loop, the current manager state is stored to
237 // all default profiles in the stack. This is acceptable because the
238 // only time multiple default profiles are loaded are during autotests.
Paul Stewart212d60f2012-07-12 10:59:13 -0700239 (*profiles_it)->Save();
Chris Masone9d779932011-08-25 16:33:41 -0700240 }
Chris Masone9d779932011-08-25 16:33:41 -0700241
Thieu Le1271d682011-11-02 22:48:19 +0000242 vector<ServiceRefPtr>::iterator services_it;
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000243 Error e;
Thieu Le1271d682011-11-02 22:48:19 +0000244 for (services_it = services_.begin(); services_it != services_.end();
245 ++services_it) {
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000246 (*services_it)->Disconnect(&e);
Thieu Le1271d682011-11-02 22:48:19 +0000247 }
248
Chris Masone413a3192011-05-09 17:10:05 -0700249 adaptor_->UpdateRunning();
Darin Petkovb72b62e2012-05-15 16:55:36 +0200250 wimax_provider_.Stop();
Paul Stewart3c504012013-01-17 17:49:58 -0800251 wifi_provider_->Stop();
Darin Petkovc3505a52013-03-18 15:13:29 +0100252 vpn_provider_->Stop();
Paul Stewart35eff132013-04-12 12:08:40 -0700253 ethernet_eap_provider_->Stop();
Darin Petkov887f2982011-07-14 16:10:17 -0700254 modem_info_.Stop();
255 device_info_.Stop();
Paul Stewartdfa46052012-06-26 09:44:14 -0700256 sort_services_task_.Cancel();
Darin Petkovca621542012-07-25 14:25:56 +0200257 power_manager_.reset();
Darin Petkov002c58e2012-06-19 02:56:05 +0200258 dbus_manager_.reset();
Paul Stewart75897df2011-04-27 09:05:53 -0700259}
260
Gaurav Shah71354762011-11-28 19:22:49 -0800261void Manager::InitializeProfiles() {
mukesh agrawald142fd62013-05-01 16:50:57 -0700262 DCHECK(profiles_.empty()); // The default profile must go first on stack.
Gaurav Shah71354762011-11-28 19:22:49 -0800263 CHECK(file_util::CreateDirectory(storage_path_)) << storage_path_.value();
mukesh agrawald142fd62013-05-01 16:50:57 -0700264
265 // Ensure that we have storage for the default profile, and that
266 // the persistent copy of the default profile is not corrupt.
Paul Stewart870523b2012-01-11 17:00:42 -0800267 scoped_refptr<DefaultProfile>
268 default_profile(new DefaultProfile(control_interface_,
Thieu Le5133b712013-02-19 14:47:21 -0800269 metrics_,
Gaurav Shah71354762011-11-28 19:22:49 -0800270 this,
271 storage_path_,
Paul Stewartd0a3b812012-03-28 22:48:22 -0700272 DefaultProfile::kDefaultId,
Gaurav Shah71354762011-11-28 19:22:49 -0800273 props_));
Thieu Le5133b712013-02-19 14:47:21 -0800274 // The default profile may fail to initialize if it's corrupted.
275 // If so, recreate the default profile.
276 if (!default_profile->InitStorage(
277 glib_, Profile::kCreateOrOpenExisting, NULL))
278 CHECK(default_profile->InitStorage(glib_, Profile::kCreateNew,
279 NULL));
mukesh agrawal00752532013-05-03 15:46:55 -0700280 // In case we created a new profile, initialize its default values,
281 // and then save. This is required for properties such as
282 // PortalDetector::kDefaultCheckPortalList to be initialized correctly.
283 LoadProperties(default_profile);
mukesh agrawald142fd62013-05-01 16:50:57 -0700284 default_profile->Save();
285 default_profile = NULL; // PushProfileInternal will re-create.
286
287 // Read list of user profiles. This must be done before pushing the
288 // default profile, because modifying the profile stack updates the
289 // user profile list.
290 vector<Profile::Identifier> identifiers =
291 Profile::LoadUserProfileList(user_profile_list_path_);
292
293 // Push the default profile onto the stack.
Gaurav Shah71354762011-11-28 19:22:49 -0800294 Error error;
Paul Stewart19c871d2011-12-15 16:10:13 -0800295 string path;
mukesh agrawald142fd62013-05-01 16:50:57 -0700296 Profile::Identifier default_profile_id;
297 CHECK(Profile::ParseIdentifier(
298 DefaultProfile::kDefaultId, &default_profile_id));
299 PushProfileInternal(default_profile_id, &path, &error);
300 CHECK(error.IsSuccess()); // Must have a default profile.
301
302 // Push user profiles onto the stack.
303 for (const auto &profile_id : identifiers) {
304 PushProfileInternal(profile_id, &path, &error);
Paul Stewart78af94c2013-04-17 16:02:06 -0700305 }
Gaurav Shah71354762011-11-28 19:22:49 -0800306}
307
Paul Stewart19c871d2011-12-15 16:10:13 -0800308void Manager::CreateProfile(const string &name, string *path, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700309 SLOG(Manager, 2) << __func__ << " " << name;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700310 Profile::Identifier ident;
311 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700312 Error::PopulateAndLog(error, Error::kInvalidArguments,
313 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700314 return;
315 }
Paul Stewartd0a3b812012-03-28 22:48:22 -0700316
Paul Stewartf3eced92013-04-17 12:18:22 -0700317 if (HasProfile(ident)) {
318 Error::PopulateAndLog(error, Error::kAlreadyExists,
319 "Profile name " + name + " is already on stack");
320 return;
Paul Stewartfc9a1da2012-06-27 15:54:52 -0700321 }
322
Paul Stewartd0a3b812012-03-28 22:48:22 -0700323 ProfileRefPtr profile;
324 if (ident.user.empty()) {
325 profile = new DefaultProfile(control_interface_,
Thieu Le5133b712013-02-19 14:47:21 -0800326 metrics_,
Paul Stewartd0a3b812012-03-28 22:48:22 -0700327 this,
328 storage_path_,
329 ident.identifier,
330 props_);
331 } else {
332 profile = new Profile(control_interface_,
Thieu Le5133b712013-02-19 14:47:21 -0800333 metrics_,
Paul Stewartd0a3b812012-03-28 22:48:22 -0700334 this,
335 ident,
336 user_storage_format_,
Gary Morainb672d352012-04-25 09:19:06 -0700337 true);
Paul Stewartd0a3b812012-03-28 22:48:22 -0700338 }
339
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700340 if (!profile->InitStorage(glib_, Profile::kCreateNew, error)) {
Paul Stewart19c871d2011-12-15 16:10:13 -0800341 // |error| will have been populated by InitStorage().
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700342 return;
343 }
344
345 // Save profile data out, and then let the scoped pointer fall out of scope.
346 if (!profile->Save()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700347 Error::PopulateAndLog(error, Error::kInternalError,
348 "Profile name " + name + " could not be saved");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700349 return;
350 }
Paul Stewart19c871d2011-12-15 16:10:13 -0800351
352 *path = profile->GetRpcIdentifier();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700353}
354
Paul Stewartf3eced92013-04-17 12:18:22 -0700355bool Manager::HasProfile(const Profile::Identifier &ident) {
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700356 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
357 it != profiles_.end();
358 ++it) {
359 if ((*it)->MatchesIdentifier(ident)) {
Paul Stewartf3eced92013-04-17 12:18:22 -0700360 return true;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700361 }
362 }
Paul Stewartf3eced92013-04-17 12:18:22 -0700363 return false;
364}
365
366void Manager::PushProfileInternal(
367 const Profile::Identifier &ident, string *path, Error *error) {
368 if (HasProfile(ident)) {
369 Error::PopulateAndLog(error, Error::kAlreadyExists,
370 "Profile name " + Profile::IdentifierToString(ident) +
371 " is already on stack");
372 return;
373 }
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700374
Paul Stewartd0a3b812012-03-28 22:48:22 -0700375 ProfileRefPtr profile;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700376 if (ident.user.empty()) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700377 // Allow a machine-wide-profile to be pushed on the stack only if the
378 // profile stack is empty, or if the topmost profile on the stack is
379 // also a machine-wide (non-user) profile.
380 if (!profiles_.empty() && !profiles_.back()->GetUser().empty()) {
381 Error::PopulateAndLog(error, Error::kInvalidArguments,
Paul Stewartf3eced92013-04-17 12:18:22 -0700382 "Cannot load non-default global profile " +
383 Profile::IdentifierToString(ident) +
Paul Stewartd0a3b812012-03-28 22:48:22 -0700384 " on top of a user profile");
385 return;
386 }
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700387
Paul Stewartd0a3b812012-03-28 22:48:22 -0700388 scoped_refptr<DefaultProfile>
389 default_profile(new DefaultProfile(control_interface_,
Thieu Le5133b712013-02-19 14:47:21 -0800390 metrics_,
Paul Stewartd0a3b812012-03-28 22:48:22 -0700391 this,
392 storage_path_,
393 ident.identifier,
394 props_));
395 if (!default_profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
396 // |error| will have been populated by InitStorage().
397 return;
398 }
399
Paul Stewart4d5efb72012-09-17 12:24:34 -0700400 if (!LoadProperties(default_profile)) {
Paul Stewartd0a3b812012-03-28 22:48:22 -0700401 Error::PopulateAndLog(error, Error::kInvalidArguments,
402 "Could not load Manager properties from profile " +
Paul Stewartf3eced92013-04-17 12:18:22 -0700403 Profile::IdentifierToString(ident));
Paul Stewartd0a3b812012-03-28 22:48:22 -0700404 return;
405 }
406 profile = default_profile;
407 } else {
408 profile = new Profile(control_interface_,
Thieu Le5133b712013-02-19 14:47:21 -0800409 metrics_,
Paul Stewartd0a3b812012-03-28 22:48:22 -0700410 this,
411 ident,
412 user_storage_format_,
413 connect_profiles_to_rpc_);
414 if (!profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
415 // |error| will have been populated by InitStorage().
416 return;
417 }
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700418 }
419
Paul Stewarta849a3d2011-11-03 05:54:09 -0700420 profiles_.push_back(profile);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700421
422 // Offer each registered Service the opportunity to join this new Profile.
Paul Stewarta41e38d2011-11-11 07:47:29 -0800423 for (vector<ServiceRefPtr>::iterator it = services_.begin();
424 it != services_.end(); ++it) {
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700425 profile->ConfigureService(*it);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700426 }
427
Paul Stewart3c504012013-01-17 17:49:58 -0800428 // Shop the Profile contents around to Devices which may have configuration
429 // stored in these profiles.
Paul Stewarta41e38d2011-11-11 07:47:29 -0800430 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
431 it != devices_.end(); ++it) {
432 profile->ConfigureDevice(*it);
433 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800434
Darin Petkovc63dcf02012-05-24 11:51:43 +0200435 // Offer the Profile contents to the service/device providers which will
436 // create new services if necessary.
Darin Petkovc3505a52013-03-18 15:13:29 +0100437 vpn_provider_->CreateServicesFromProfile(profile);
Paul Stewart3c504012013-01-17 17:49:58 -0800438 wifi_provider_->CreateServicesFromProfile(profile);
Darin Petkovc63dcf02012-05-24 11:51:43 +0200439 wimax_provider_.CreateServicesFromProfile(profile);
Paul Stewart66815332012-04-09 18:09:36 -0700440
Paul Stewart19c871d2011-12-15 16:10:13 -0800441 *path = profile->GetRpcIdentifier();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800442 SortServices();
Paul Stewart78af94c2013-04-17 16:02:06 -0700443 OnProfilesChanged();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700444}
445
Paul Stewartf3eced92013-04-17 12:18:22 -0700446void Manager::PushProfile(const string &name, string *path, Error *error) {
447 SLOG(Manager, 2) << __func__ << " " << name;
448 Profile::Identifier ident;
449 if (!Profile::ParseIdentifier(name, &ident)) {
450 Error::PopulateAndLog(error, Error::kInvalidArguments,
451 "Invalid profile name " + name);
452 return;
453 }
454 PushProfileInternal(ident, path, error);
455}
456
457void Manager::InsertUserProfile(const string &name,
458 const string &user_hash,
459 string *path,
460 Error *error) {
461 SLOG(Manager, 2) << __func__ << " " << name;
462 Profile::Identifier ident;
463 if (!Profile::ParseIdentifier(name, &ident) ||
464 ident.user.empty()) {
465 Error::PopulateAndLog(error, Error::kInvalidArguments,
466 "Invalid user profile name " + name);
467 return;
468 }
469 ident.user_hash = user_hash;
470 PushProfileInternal(ident, path, error);
471}
472
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700473void Manager::PopProfileInternal() {
474 CHECK(!profiles_.empty());
475 ProfileRefPtr active_profile = profiles_.back();
476 profiles_.pop_back();
Paul Stewart75225512012-01-26 22:51:33 -0800477 vector<ServiceRefPtr>::iterator it;
Paul Stewart65512e12012-03-26 18:01:08 -0700478 for (it = services_.begin(); it != services_.end();) {
479 if ((*it)->profile().get() != active_profile.get() ||
480 MatchProfileWithService(*it) ||
481 !UnloadService(&it)) {
482 LOG(ERROR) << "Skipping unload of service";
483 ++it;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700484 }
485 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800486 SortServices();
Paul Stewart78af94c2013-04-17 16:02:06 -0700487 OnProfilesChanged();
488}
Philipp Neubeck79173602012-11-13 21:10:09 +0100489
Paul Stewart78af94c2013-04-17 16:02:06 -0700490void Manager::OnProfilesChanged() {
Philipp Neubeck79173602012-11-13 21:10:09 +0100491 Error unused_error;
Paul Stewart78af94c2013-04-17 16:02:06 -0700492
Philipp Neubeck79173602012-11-13 21:10:09 +0100493 adaptor_->EmitStringsChanged(flimflam::kProfilesProperty,
494 EnumerateProfiles(&unused_error));
mukesh agrawald142fd62013-05-01 16:50:57 -0700495 Profile::SaveUserProfileList(user_profile_list_path_, profiles_);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700496}
497
Paul Stewarta41e38d2011-11-11 07:47:29 -0800498void Manager::PopProfile(const string &name, Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700499 SLOG(Manager, 2) << __func__ << " " << name;
Christopher Wiley3e7635e2012-08-15 09:46:17 -0700500 // This signal is sent when a user logs out of a session. Regardless of
501 // whether we find their profile to remove, lets clear the network related
502 // logs.
503 MemoryLog::GetInstance()->Clear();
504 LOG(INFO) << "Cleared the memory log on logout event.";
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700505 Profile::Identifier ident;
506 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700507 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700508 return;
509 }
510 ProfileRefPtr active_profile = profiles_.back();
511 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700512 Error::PopulateAndLog(error, Error::kInvalidArguments,
513 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700514 return;
515 }
516 if (!active_profile->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700517 Error::PopulateAndLog(error, Error::kNotSupported,
518 name + " is not the active profile");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700519 return;
520 }
521 PopProfileInternal();
522}
523
524void Manager::PopAnyProfile(Error *error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700525 SLOG(Manager, 2) << __func__;
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700526 Profile::Identifier ident;
527 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700528 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700529 return;
530 }
531 PopProfileInternal();
532}
533
Paul Stewart307c2502013-03-23 12:32:10 -0700534void Manager::PopAllUserProfiles(Error */*error*/) {
535 SLOG(Manager, 2) << __func__;
536 // This signal is sent when a user logs out of a session. Regardless of
537 // whether we find their profile to remove, lets clear the network related
538 // logs.
539 MemoryLog::GetInstance()->Clear();
540 LOG(INFO) << "Cleared the memory log on logout event.";
541 while (!profiles_.empty() && !profiles_.back()->GetUser().empty()) {
542 PopProfileInternal();
543 }
544}
545
Paul Stewarte73d05c2012-03-29 16:26:05 -0700546void Manager::RemoveProfile(const string &name, Error *error) {
547 Profile::Identifier ident;
548 if (!Profile::ParseIdentifier(name, &ident)) {
549 Error::PopulateAndLog(error, Error::kInvalidArguments,
550 "Invalid profile name " + name);
551 return;
552 }
553
Paul Stewartf3eced92013-04-17 12:18:22 -0700554 if (HasProfile(ident)) {
555 Error::PopulateAndLog(error, Error::kInvalidArguments,
556 "Cannot remove profile name " + name +
557 " since it is on stack");
558 return;
Paul Stewarte73d05c2012-03-29 16:26:05 -0700559 }
560
561 ProfileRefPtr profile;
562 if (ident.user.empty()) {
563 profile = new DefaultProfile(control_interface_,
Thieu Le5133b712013-02-19 14:47:21 -0800564 metrics_,
Paul Stewarte73d05c2012-03-29 16:26:05 -0700565 this,
566 storage_path_,
567 ident.identifier,
568 props_);
569 } else {
570 profile = new Profile(control_interface_,
Thieu Le5133b712013-02-19 14:47:21 -0800571 metrics_,
Paul Stewarte73d05c2012-03-29 16:26:05 -0700572 this,
573 ident,
574 user_storage_format_,
575 false);
576 }
577
578
579 // |error| will have been populated if RemoveStorage fails.
580 profile->RemoveStorage(glib_, error);
581
582 return;
583}
584
Paul Stewart75225512012-01-26 22:51:33 -0800585bool Manager::HandleProfileEntryDeletion(const ProfileRefPtr &profile,
586 const std::string &entry_name) {
587 bool moved_services = false;
588 for (vector<ServiceRefPtr>::iterator it = services_.begin();
Paul Stewart65512e12012-03-26 18:01:08 -0700589 it != services_.end();) {
Paul Stewart75225512012-01-26 22:51:33 -0800590 if ((*it)->profile().get() == profile.get() &&
591 (*it)->GetStorageIdentifier() == entry_name) {
592 profile->AbandonService(*it);
Paul Stewart65512e12012-03-26 18:01:08 -0700593 if (MatchProfileWithService(*it) ||
594 !UnloadService(&it)) {
595 ++it;
Paul Stewart75225512012-01-26 22:51:33 -0800596 }
597 moved_services = true;
Paul Stewart65512e12012-03-26 18:01:08 -0700598 } else {
599 ++it;
Paul Stewart75225512012-01-26 22:51:33 -0800600 }
601 }
602 return moved_services;
603}
604
Paul Stewart967eaeb2013-04-25 19:53:07 -0700605map<string, string> Manager::GetLoadableProfileEntriesForService(
606 const ServiceConstRefPtr &service) {
607 map<string, string> profile_entries;
608 for (const auto &profile : profiles_) {
609 string entry_name = service->GetLoadableStorageIdentifier(
610 *profile->GetConstStorage());
611 if (!entry_name.empty()) {
612 profile_entries[profile->GetRpcIdentifier()] = entry_name;
613 }
614 }
615 return profile_entries;
616}
617
Paul Stewart0756db92012-01-27 08:34:47 -0800618ServiceRefPtr Manager::GetServiceWithStorageIdentifier(
619 const ProfileRefPtr &profile, const std::string &entry_name, Error *error) {
620 for (vector<ServiceRefPtr>::iterator it = services_.begin();
621 it != services_.end(); ++it) {
622 if ((*it)->profile().get() == profile.get() &&
623 (*it)->GetStorageIdentifier() == entry_name) {
624 return *it;
625 }
626 }
627
Paul Stewart76a89cb2012-09-14 06:06:48 -0700628 string error_string(
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500629 StringPrintf("Entry %s is not registered in the manager",
630 entry_name.c_str()));
Paul Stewart76a89cb2012-09-14 06:06:48 -0700631 if (error) {
632 error->Populate(Error::kNotFound, error_string);
633 }
634 SLOG(Manager, 2) << error_string;
Paul Stewart0756db92012-01-27 08:34:47 -0800635 return NULL;
636}
637
Paul Stewart13ed2252012-03-21 12:52:46 -0700638ServiceRefPtr Manager::GetServiceWithGUID(
639 const std::string &guid, Error *error) {
640 for (vector<ServiceRefPtr>::iterator it = services_.begin();
641 it != services_.end(); ++it) {
642 if ((*it)->guid() == guid) {
643 return *it;
644 }
645 }
646
Paul Stewart76a89cb2012-09-14 06:06:48 -0700647 string error_string(
Paul Stewart13ed2252012-03-21 12:52:46 -0700648 StringPrintf("Service wth GUID %s is not registered in the manager",
649 guid.c_str()));
Paul Stewart76a89cb2012-09-14 06:06:48 -0700650 if (error) {
651 error->Populate(Error::kNotFound, error_string);
652 }
653 SLOG(Manager, 2) << error_string;
Paul Stewart13ed2252012-03-21 12:52:46 -0700654 return NULL;
655}
656
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700657ServiceRefPtr Manager::GetDefaultService() const {
Arman Uguray32c76402012-11-27 14:01:13 -0800658 SLOG(Manager, 2) << __func__;
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700659 if (services_.empty() || !services_[0]->connection().get()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700660 SLOG(Manager, 2) << "In " << __func__ << ": No default connection exists.";
Paul Stewarte2bad7c2012-03-14 08:55:33 -0700661 return NULL;
662 }
663 return services_[0];
664}
665
Paul Stewart49739c02012-08-08 17:24:03 -0700666RpcIdentifier Manager::GetDefaultServiceRpcIdentifier(Error */*error*/) {
667 ServiceRefPtr default_service = GetDefaultService();
668 return default_service ? default_service->GetRpcIdentifier() : "/";
669}
670
Paul Stewart036dba02012-08-07 12:34:41 -0700671bool Manager::IsTechnologyInList(const string &technology_list,
672 Technology::Identifier tech) const {
Paul Stewart20088d82012-02-16 06:58:55 -0800673 Error error;
Paul Stewart036dba02012-08-07 12:34:41 -0700674 vector<Technology::Identifier> technologies;
675 return Technology::GetTechnologyVectorFromString(technology_list,
676 &technologies,
Paul Stewart20088d82012-02-16 06:58:55 -0800677 &error) &&
Paul Stewart036dba02012-08-07 12:34:41 -0700678 std::find(technologies.begin(), technologies.end(), tech) !=
679 technologies.end();
680}
681
682bool Manager::IsPortalDetectionEnabled(Technology::Identifier tech) {
683 return IsTechnologyInList(GetCheckPortalList(NULL), tech);
Paul Stewart20088d82012-02-16 06:58:55 -0800684}
685
Paul Stewart10e9e4e2012-04-26 19:46:28 -0700686void Manager::SetStartupPortalList(const string &portal_list) {
687 startup_portal_list_ = portal_list;
688 use_startup_portal_list_ = true;
689}
690
Paul Stewartd2e1c362013-03-03 19:06:07 -0800691bool Manager::IsProfileBefore(const ProfileRefPtr &a,
692 const ProfileRefPtr &b) const {
693 DCHECK(a != b);
694 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
695 it != profiles_.end();
696 ++it) {
697 if (*it == a) {
698 return true;
699 }
700 if (*it == b) {
701 return false;
702 }
703 }
704 NOTREACHED() << "We should have found both profiles in the profiles_ list!";
705 return false;
706}
707
Paul Stewart10ccbb32012-04-26 15:59:30 -0700708bool Manager::IsServiceEphemeral(const ServiceConstRefPtr &service) const {
709 return service->profile() == ephemeral_profile_;
710}
711
Paul Stewart036dba02012-08-07 12:34:41 -0700712bool Manager::IsTechnologyLinkMonitorEnabled(
713 Technology::Identifier technology) const {
714 return IsTechnologyInList(props_.link_monitor_technologies, technology);
Paul Stewartbf667612012-06-29 14:49:54 -0700715}
716
Paul Stewart3c504012013-01-17 17:49:58 -0800717bool Manager::IsDefaultProfile(StoreInterface *storage) {
718 return profiles_.empty() || storage == profiles_.front()->GetConstStorage();
719}
720
721void Manager::OnProfileStorageInitialized(StoreInterface *storage) {
Wade Guthrie60a37062013-04-02 11:39:09 -0700722 wifi_provider_->LoadAndFixupServiceEntries(storage,
723 IsDefaultProfile(storage));
Paul Stewart3c504012013-01-17 17:49:58 -0800724}
725
726DeviceRefPtr Manager::GetEnabledDeviceWithTechnology(
727 Technology::Identifier technology) const {
728 vector<DeviceRefPtr> devices;
729 FilterByTechnology(technology, &devices);
730 for (vector<DeviceRefPtr>::const_iterator it = devices.begin();
731 it != devices.end(); ++it) {
732 if ((*it)->enabled()) {
733 return *it;
734 }
Paul Stewart85aea152013-01-22 09:31:56 -0800735 }
Paul Stewart3c504012013-01-17 17:49:58 -0800736 return NULL;
Paul Stewart85aea152013-01-22 09:31:56 -0800737}
738
Paul Stewart1b253142012-01-26 14:05:52 -0800739const ProfileRefPtr &Manager::ActiveProfile() const {
Eric Shienbroodc74cf9c2012-03-02 15:00:35 -0500740 DCHECK_NE(profiles_.size(), 0U);
Chris Masone7aa5f902011-07-11 11:13:35 -0700741 return profiles_.back();
742}
743
Paul Stewart1b253142012-01-26 14:05:52 -0800744bool Manager::IsActiveProfile(const ProfileRefPtr &profile) const {
745 return (profiles_.size() > 0 &&
746 ActiveProfile().get() == profile.get());
747}
748
Chris Masone6515aab2011-10-12 16:19:09 -0700749bool Manager::MoveServiceToProfile(const ServiceRefPtr &to_move,
750 const ProfileRefPtr &destination) {
751 const ProfileRefPtr from = to_move->profile();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700752 SLOG(Manager, 2) << "Moving service "
Darin Petkov457728b2013-01-09 09:49:08 +0100753 << to_move->unique_name()
Ben Chanfad4a0b2012-04-18 15:49:59 -0700754 << " to profile "
755 << destination->GetFriendlyName()
756 << " from "
757 << from->GetFriendlyName();
Darin Petkov457728b2013-01-09 09:49:08 +0100758 return destination->AdoptService(to_move) && from->AbandonService(to_move);
Chris Masone6791a432011-07-12 13:23:19 -0700759}
760
Paul Stewart7f61e522012-03-22 11:13:45 -0700761ProfileRefPtr Manager::LookupProfileByRpcIdentifier(
762 const string &profile_rpcid) {
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800763 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
764 it != profiles_.end();
765 ++it) {
766 if (profile_rpcid == (*it)->GetRpcIdentifier()) {
Paul Stewart7f61e522012-03-22 11:13:45 -0700767 return *it;
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800768 }
769 }
Paul Stewart7f61e522012-03-22 11:13:45 -0700770 return NULL;
771}
772
773void Manager::SetProfileForService(const ServiceRefPtr &to_set,
774 const string &profile_rpcid,
775 Error *error) {
776 ProfileRefPtr profile = LookupProfileByRpcIdentifier(profile_rpcid);
777 if (!profile) {
778 Error::PopulateAndLog(error, Error::kInvalidArguments,
779 StringPrintf("Unknown Profile %s requested for "
780 "Service", profile_rpcid.c_str()));
781 return;
782 }
783
Paul Stewart649f3a42012-04-24 23:22:16 -0700784 if (!to_set->profile()) {
785 // We are being asked to set the profile property of a service that
786 // has never been registered. Now is a good time to register it.
787 RegisterService(to_set);
788 }
789
Paul Stewart7f61e522012-03-22 11:13:45 -0700790 if (to_set->profile().get() == profile.get()) {
791 Error::PopulateAndLog(error, Error::kInvalidArguments,
792 "Service is already connected to this profile");
793 } else if (!MoveServiceToProfile(to_set, profile)) {
794 Error::PopulateAndLog(error, Error::kInternalError,
795 "Unable to move service to profile");
796 }
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800797}
798
mukesh agrawal46c27cc2013-07-10 16:39:10 -0700799void Manager::SetEnabledStateForTechnology(const std::string &technology_name,
800 bool enabled_state,
801 Error *error,
802 const ResultCallback &callback) {
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400803 CHECK(error != NULL);
804 DCHECK(error->IsOngoing());
Eric Shienbrood9a245532012-03-07 14:20:39 -0500805 Technology::Identifier id = Technology::IdentifierFromName(technology_name);
806 if (id == Technology::kUnknown) {
807 error->Populate(Error::kInvalidArguments, "Unknown technology");
808 return;
809 }
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400810 bool deferred = false;
mukesh agrawalb711ba22013-07-17 10:21:00 -0700811 auto result_aggregator(make_scoped_refptr(new ResultAggregator(callback)));
mukesh agrawal46c27cc2013-07-10 16:39:10 -0700812 for (auto &device : devices_) {
813 if (device->technology() != id || device->enabled() == enabled_state)
814 continue;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500815
mukesh agrawal46c27cc2013-07-10 16:39:10 -0700816 Error device_error(Error::kOperationInitiated);
817 ResultCallback aggregator_callback(
818 Bind(&ResultAggregator::ReportResult, result_aggregator));
819 device->SetEnabledPersistent(
820 enabled_state, &device_error, aggregator_callback);
821 if (device_error.IsOngoing()) {
822 deferred = true;
823 } else if (!error->IsFailure()) { // Report first failure.
824 error->CopyFrom(device_error);
Eric Shienbrood9a245532012-03-07 14:20:39 -0500825 }
826 }
mukesh agrawal46c27cc2013-07-10 16:39:10 -0700827 if (deferred) {
828 // Some device is handling this change asynchronously. Clobber any error
829 // from another device, so that we can indicate the operation is still in
830 // progress.
831 error->Populate(Error::kOperationInitiated);
832 } else if (error->IsOngoing()) {
833 // |error| IsOngoing at entry to this method, but no device
834 // |deferred|. Reset |error|, to indicate we're done.
Jason Glasgowdf7c5532012-05-14 14:41:45 -0400835 error->Reset();
mukesh agrawal46c27cc2013-07-10 16:39:10 -0700836 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500837}
838
839void Manager::UpdateEnabledTechnologies() {
840 Error error;
841 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
842 EnabledTechnologies(&error));
843}
844
Ben Chan5086b972013-01-15 21:51:38 -0800845void Manager::UpdateUninitializedTechnologies() {
846 Error error;
847 adaptor_->EmitStringsChanged(kUninitializedTechnologiesProperty,
848 UninitializedTechnologies(&error));
849}
850
Chris Masone2b105542011-06-22 10:58:09 -0700851void Manager::RegisterDevice(const DeviceRefPtr &to_manage) {
Darin Petkove7c6ad32012-06-29 10:22:09 +0200852 LOG(INFO) << "Device " << to_manage->FriendlyName() << " registered.";
853 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
854 it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700855 if (to_manage.get() == it->get())
Chris Masone9be4a9d2011-05-16 15:44:09 -0700856 return;
857 }
Chris Masonec1e50412011-06-07 13:04:53 -0700858 devices_.push_back(to_manage);
Paul Stewartf1ce5d22011-05-19 13:10:20 -0700859
Paul Stewart87a4ae82012-10-26 15:49:32 -0700860 LoadDeviceFromProfiles(to_manage);
Paul Stewarta41e38d2011-11-11 07:47:29 -0800861
Darin Petkove7c6ad32012-06-29 10:22:09 +0200862 // If |to_manage| is new, it needs to be persisted.
863 UpdateDevice(to_manage);
864
Paul Stewarta41e38d2011-11-11 07:47:29 -0800865 // In normal usage, running_ will always be true when we are here, however
866 // unit tests sometimes do things in otherwise invalid states.
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400867 if (running_ && (to_manage->enabled_persistent() ||
868 to_manage->IsUnderlyingDeviceEnabled()))
Eric Shienbrood9a245532012-03-07 14:20:39 -0500869 to_manage->SetEnabled(true);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800870
Eric Shienbrood8839a892012-03-29 10:33:48 -0400871 EmitDeviceProperties();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700872}
873
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700874void Manager::DeregisterDevice(const DeviceRefPtr &to_forget) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700875 SLOG(Manager, 2) << __func__ << "(" << to_forget->FriendlyName() << ")";
Chris Masonec1e50412011-06-07 13:04:53 -0700876 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700877 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700878 if (to_forget.get() == it->get()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700879 SLOG(Manager, 2) << "Deregistered device: " << to_forget->UniqueName();
Paul Stewart212d60f2012-07-12 10:59:13 -0700880 UpdateDevice(to_forget);
Eric Shienbrood9a245532012-03-07 14:20:39 -0500881 to_forget->SetEnabled(false);
Chris Masone9be4a9d2011-05-16 15:44:09 -0700882 devices_.erase(it);
Eric Shienbrood8839a892012-03-29 10:33:48 -0400883 EmitDeviceProperties();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700884 return;
885 }
886 }
Ben Chanfad4a0b2012-04-18 15:49:59 -0700887 SLOG(Manager, 2) << __func__ << " unknown device: "
888 << to_forget->UniqueName();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700889}
890
Paul Stewart87a4ae82012-10-26 15:49:32 -0700891void Manager::LoadDeviceFromProfiles(const DeviceRefPtr &device) {
892 // We are applying device properties from the DefaultProfile, and adding the
893 // union of hidden services in all loaded profiles to the device.
894 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
895 it != profiles_.end(); ++it) {
896 // Load device configuration, if any exists, as well as hidden services.
897 (*it)->ConfigureDevice(device);
898 }
899}
900
Eric Shienbrood8839a892012-03-29 10:33:48 -0400901void Manager::EmitDeviceProperties() {
902 vector<DeviceRefPtr>::iterator it;
903 vector<string> device_paths;
904 for (it = devices_.begin(); it != devices_.end(); ++it) {
905 device_paths.push_back((*it)->GetRpcIdentifier());
906 }
907 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kDevicesProperty,
908 device_paths);
909 Error error;
910 adaptor_->EmitStringsChanged(flimflam::kAvailableTechnologiesProperty,
911 AvailableTechnologies(&error));
912 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
913 EnabledTechnologies(&error));
Ben Chan5086b972013-01-15 21:51:38 -0800914 adaptor_->EmitStringsChanged(kUninitializedTechnologiesProperty,
915 UninitializedTechnologies(&error));
Eric Shienbrood8839a892012-03-29 10:33:48 -0400916}
917
mukesh agrawal4eb4d782011-12-05 17:34:37 +0000918bool Manager::HasService(const ServiceRefPtr &service) {
919 vector<ServiceRefPtr>::iterator it;
920 for (it = services_.begin(); it != services_.end(); ++it) {
Darin Petkov457728b2013-01-09 09:49:08 +0100921 if ((*it)->unique_name() == service->unique_name())
mukesh agrawal4eb4d782011-12-05 17:34:37 +0000922 return true;
923 }
924 return false;
925}
926
Chris Masone2b105542011-06-22 10:58:09 -0700927void Manager::RegisterService(const ServiceRefPtr &to_manage) {
Darin Petkov457728b2013-01-09 09:49:08 +0100928 SLOG(Manager, 2) << "Registering service " << to_manage->unique_name();
mukesh agrawald835b202011-10-07 15:26:47 -0700929
Paul Stewart75225512012-01-26 22:51:33 -0800930 MatchProfileWithService(to_manage);
Chris Masone6791a432011-07-12 13:23:19 -0700931
932 // Now add to OUR list.
Chris Masonec1e50412011-06-07 13:04:53 -0700933 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700934 for (it = services_.begin(); it != services_.end(); ++it) {
Darin Petkov457728b2013-01-09 09:49:08 +0100935 CHECK(to_manage->unique_name() != (*it)->unique_name());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700936 }
Chris Masonec1e50412011-06-07 13:04:53 -0700937 services_.push_back(to_manage);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700938 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700939}
940
Chris Masone6515aab2011-10-12 16:19:09 -0700941void Manager::DeregisterService(const ServiceRefPtr &to_forget) {
mukesh agrawal6813e762013-07-10 19:05:08 -0700942 for (auto it = services_.begin(); it != services_.end(); ++it) {
Darin Petkov457728b2013-01-09 09:49:08 +0100943 if (to_forget->unique_name() == (*it)->unique_name()) {
mukesh agrawal6813e762013-07-10 19:05:08 -0700944 DLOG_IF(FATAL, (*it)->connection())
945 << "Service " << (*it)->unique_name()
946 << " still has a connection (in call to " << __func__ << ")";
Paul Stewartfc9a1da2012-06-27 15:54:52 -0700947 (*it)->Unload();
Philipp Neubeck79173602012-11-13 21:10:09 +0100948 (*it)->SetProfile(NULL);
Chris Masone9be4a9d2011-05-16 15:44:09 -0700949 services_.erase(it);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700950 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700951 return;
952 }
953 }
954}
955
Paul Stewart65512e12012-03-26 18:01:08 -0700956bool Manager::UnloadService(vector<ServiceRefPtr>::iterator *service_iterator) {
957 if (!(**service_iterator)->Unload()) {
958 return false;
959 }
960
961 DCHECK(!(**service_iterator)->connection());
Philipp Neubeck79173602012-11-13 21:10:09 +0100962 (**service_iterator)->SetProfile(NULL);
Paul Stewart65512e12012-03-26 18:01:08 -0700963 *service_iterator = services_.erase(*service_iterator);
964
965 return true;
966}
967
mukesh agrawal00917ce2011-11-22 23:56:55 +0000968void Manager::UpdateService(const ServiceRefPtr &to_update) {
969 CHECK(to_update);
Darin Petkov457728b2013-01-09 09:49:08 +0100970 LOG(INFO) << "Service " << to_update->unique_name() << " updated;"
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800971 << " state: " << Service::ConnectStateToString(to_update->state())
972 << " failure: "
973 << Service::ConnectFailureToString(to_update->failure());
Ben Chanfad4a0b2012-04-18 15:49:59 -0700974 SLOG(Manager, 2) << "IsConnected(): " << to_update->IsConnected();
975 SLOG(Manager, 2) << "IsConnecting(): " << to_update->IsConnecting();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800976 if (to_update->IsConnected()) {
mukesh agrawal00917ce2011-11-22 23:56:55 +0000977 to_update->MakeFavorite();
Gary Moraind93615e2012-04-27 11:50:03 -0700978 // Persists the updated favorite setting in the profile.
979 SaveServiceToProfile(to_update);
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800980 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700981 SortServices();
Paul Stewart03dba0b2011-08-22 16:32:45 -0700982}
983
Darin Petkove7c6ad32012-06-29 10:22:09 +0200984void Manager::UpdateDevice(const DeviceRefPtr &to_update) {
985 LOG(INFO) << "Device " << to_update->link_name() << " updated: "
986 << (to_update->enabled_persistent() ? "enabled" : "disabled");
Wade Guthrie60a37062013-04-02 11:39:09 -0700987 // Saves the device to the topmost profile that accepts it (ordinary
988 // profiles don't update but default profiles do). Normally, the topmost
989 // updating profile would be the DefaultProfile at the bottom of the stack.
990 // Autotests, differ from the normal scenario, however, in that they push a
991 // second test-only DefaultProfile.
Darin Petkove7c6ad32012-06-29 10:22:09 +0200992 for (vector<ProfileRefPtr>::reverse_iterator rit = profiles_.rbegin();
993 rit != profiles_.rend(); ++rit) {
994 if ((*rit)->UpdateDevice(to_update)) {
995 return;
996 }
997 }
998}
999
Wade Guthrie60a37062013-04-02 11:39:09 -07001000void Manager::UpdateWiFiProvider() {
1001 // Saves |wifi_provider_| to the topmost profile that accepts it (ordinary
1002 // profiles don't update but default profiles do). Normally, the topmost
1003 // updating profile would be the DefaultProfile at the bottom of the stack.
1004 // Autotests, differ from the normal scenario, however, in that they push a
1005 // second test-only DefaultProfile.
1006 for (vector<ProfileRefPtr>::reverse_iterator rit = profiles_.rbegin();
1007 rit != profiles_.rend(); ++rit) {
1008 if ((*rit)->UpdateWiFiProvider(*wifi_provider_)) {
1009 return;
1010 }
1011 }
1012}
1013
Gary Moraind93615e2012-04-27 11:50:03 -07001014void Manager::SaveServiceToProfile(const ServiceRefPtr &to_update) {
1015 if (IsServiceEphemeral(to_update)) {
1016 if (profiles_.empty()) {
1017 LOG(ERROR) << "Cannot assign profile to service: no profiles exist!";
1018 } else {
1019 MoveServiceToProfile(to_update, profiles_.back());
1020 }
1021 } else {
1022 to_update->profile()->UpdateService(to_update);
1023 }
1024}
1025
Paul Stewart4d5efb72012-09-17 12:24:34 -07001026bool Manager::LoadProperties(const scoped_refptr<DefaultProfile> &profile) {
1027 if (!profile->LoadManagerProperties(&props_)) {
1028 return false;
1029 }
1030 SetIgnoredDNSSearchPaths(props_.ignored_dns_search_paths, NULL);
1031 return true;
1032}
1033
Darin Petkov3ec55342012-09-28 14:04:44 +02001034void Manager::AddTerminationAction(const string &name,
Gary Moraina9fb3252012-05-31 12:05:31 -07001035 const base::Closure &start) {
Darin Petkov3ec55342012-09-28 14:04:44 +02001036 if (termination_actions_.IsEmpty() && power_manager_.get()) {
1037 power_manager_->AddSuspendDelayCallback(
1038 kPowerManagerKey,
Daniel Erat0818cca2012-12-14 10:16:21 -08001039 Bind(&Manager::OnSuspendImminent, AsWeakPtr()));
1040 CHECK(!suspend_delay_registered_);
1041 suspend_delay_registered_ = power_manager_->RegisterSuspendDelay(
1042 base::TimeDelta::FromMilliseconds(
1043 kTerminationActionsTimeoutMilliseconds),
Daniel Eratf9753672013-01-24 10:17:02 -08001044 kSuspendDelayDescription,
Daniel Erat0818cca2012-12-14 10:16:21 -08001045 &suspend_delay_id_);
Darin Petkov3ec55342012-09-28 14:04:44 +02001046 }
Gary Moraina9fb3252012-05-31 12:05:31 -07001047 termination_actions_.Add(name, start);
1048}
1049
Darin Petkov3ec55342012-09-28 14:04:44 +02001050void Manager::TerminationActionComplete(const string &name) {
Gary Moraina9fb3252012-05-31 12:05:31 -07001051 termination_actions_.ActionComplete(name);
1052}
1053
Darin Petkov3ec55342012-09-28 14:04:44 +02001054void Manager::RemoveTerminationAction(const string &name) {
1055 if (termination_actions_.IsEmpty()) {
1056 return;
1057 }
Gary Moraina9fb3252012-05-31 12:05:31 -07001058 termination_actions_.Remove(name);
Darin Petkov3ec55342012-09-28 14:04:44 +02001059 if (termination_actions_.IsEmpty() && power_manager_.get()) {
Daniel Erat0818cca2012-12-14 10:16:21 -08001060 if (suspend_delay_registered_) {
1061 power_manager_->UnregisterSuspendDelay(suspend_delay_id_);
1062 suspend_delay_registered_ = false;
1063 suspend_delay_id_ = 0;
1064 }
Darin Petkov3ec55342012-09-28 14:04:44 +02001065 power_manager_->RemoveSuspendDelayCallback(kPowerManagerKey);
1066 }
Gary Moraina9fb3252012-05-31 12:05:31 -07001067}
1068
1069void Manager::RunTerminationActions(
Darin Petkov3ec55342012-09-28 14:04:44 +02001070 const base::Callback<void(const Error &)> &done) {
1071 LOG(INFO) << "Running termination actions.";
1072 termination_actions_.Run(kTerminationActionsTimeoutMilliseconds, done);
Gary Moraina9fb3252012-05-31 12:05:31 -07001073}
1074
Arman Ugurayab22c162012-10-08 19:08:38 -07001075bool Manager::RunTerminationActionsAndNotifyMetrics(
1076 const base::Callback<void(const Error &)> &done,
1077 Metrics::TerminationActionReason reason) {
1078 if (termination_actions_.IsEmpty())
1079 return false;
1080
1081 metrics_->NotifyTerminationActionsStarted(reason);
1082 RunTerminationActions(done);
1083 return true;
1084}
1085
Darin Petkova5e07ef2012-07-09 14:27:57 +02001086int Manager::RegisterDefaultServiceCallback(const ServiceCallback &callback) {
1087 default_service_callbacks_[++default_service_callback_tag_] = callback;
1088 return default_service_callback_tag_;
1089}
1090
1091void Manager::DeregisterDefaultServiceCallback(int tag) {
1092 default_service_callbacks_.erase(tag);
1093}
1094
Christopher Wiley0d9cf0c2013-02-19 19:24:57 -08001095void Manager::VerifyDestination(const string &certificate,
1096 const string &public_key,
1097 const string &nonce,
1098 const string &signed_data,
1099 const string &destination_udn,
Christopher Wileycdde79f2013-05-01 14:26:56 -07001100 const string &hotspot_ssid,
1101 const string &hotspot_bssid,
Christopher Wiley0d9cf0c2013-02-19 19:24:57 -08001102 const ResultBoolCallback &cb,
1103 Error *error) {
Christopher Wileycdde79f2013-05-01 14:26:56 -07001104 if (hotspot_bssid.length() > 32) {
1105 error->Populate(Error::kOperationFailed,
1106 "Invalid SSID given for verification.");
1107 return;
1108 }
Christopher Wiley83889862013-05-02 15:55:09 -07001109 vector<uint8_t> ssid;
1110 string bssid;
Christopher Wileycdde79f2013-05-01 14:26:56 -07001111 if (hotspot_ssid.length() || hotspot_bssid.length()) {
Christopher Wiley83889862013-05-02 15:55:09 -07001112 // If Chrome thinks this destination is already configured, service
1113 // will be an AP that both we and the destination are connected
1114 // to, and not the thing we should verify against.
Christopher Wileycdde79f2013-05-01 14:26:56 -07001115 ssid.assign(hotspot_ssid.begin(), hotspot_ssid.end());
1116 bssid = hotspot_bssid;
Christopher Wiley83889862013-05-02 15:55:09 -07001117 } else {
1118 // For now, we only support a single connected WiFi service. If we change
1119 // that, we'll need to revisit this.
1120 bool found_one = false;
1121 for (const auto &service : services_) {
1122 if (service->technology() == Technology::kWifi &&
1123 service->IsConnected()) {
1124 WiFiService *wifi = reinterpret_cast<WiFiService *>(&(*service));
1125 bssid = wifi->bssid();
1126 ssid = wifi->ssid();
1127 found_one = true;
1128 break;
1129 }
1130 }
1131 if (!found_one) {
1132 error->Populate(Error::kOperationFailed,
1133 "Unable to find connected WiFi service.");
1134 return;
1135
1136 }
Christopher Wileycdde79f2013-05-01 14:26:56 -07001137 }
Christopher Wiley1057cd72013-02-28 15:21:29 -08001138 crypto_util_proxy_->VerifyDestination(certificate, public_key, nonce,
1139 signed_data, destination_udn,
Christopher Wiley83889862013-05-02 15:55:09 -07001140 ssid, bssid, cb, error);
Christopher Wiley1057cd72013-02-28 15:21:29 -08001141}
1142
1143void Manager::VerifyToEncryptLink(string public_key,
1144 string data,
1145 ResultStringCallback cb,
1146 const Error &error,
1147 bool success) {
1148 if (!success || !error.IsSuccess()) {
1149 CHECK(error.IsFailure()) << "Return code from CryptoUtilProxy "
1150 << "inconsistent with error code.";
1151 cb.Run(error, "");
1152 return;
1153 }
1154 Error encrypt_error;
1155 if (!crypto_util_proxy_->EncryptData(public_key, data, cb, &encrypt_error)) {
Christopher Wileyb3e70d22013-04-26 17:28:37 -07001156 CHECK(encrypt_error.IsFailure()) << "CryptoUtilProxy::EncryptData returned "
1157 << "inconsistently.";
1158 cb.Run(encrypt_error, "");
Christopher Wiley1057cd72013-02-28 15:21:29 -08001159 }
Christopher Wiley0d9cf0c2013-02-19 19:24:57 -08001160}
1161
1162void Manager::VerifyAndEncryptData(const string &certificate,
1163 const string &public_key,
1164 const string &nonce,
1165 const string &signed_data,
1166 const string &destination_udn,
Christopher Wileycdde79f2013-05-01 14:26:56 -07001167 const string &hotspot_ssid,
1168 const string &hotspot_bssid,
Christopher Wiley0d9cf0c2013-02-19 19:24:57 -08001169 const string &data,
1170 const ResultStringCallback &cb,
1171 Error *error) {
Christopher Wiley1057cd72013-02-28 15:21:29 -08001172 ResultBoolCallback on_verification_success = Bind(
1173 &Manager::VerifyToEncryptLink, AsWeakPtr(), public_key, data, cb);
1174 VerifyDestination(certificate, public_key, nonce, signed_data,
Christopher Wileycdde79f2013-05-01 14:26:56 -07001175 destination_udn, hotspot_ssid, hotspot_bssid,
1176 on_verification_success, error);
Christopher Wiley0d9cf0c2013-02-19 19:24:57 -08001177}
1178
1179void Manager::VerifyAndEncryptCredentials(const string &certificate,
1180 const string &public_key,
1181 const string &nonce,
1182 const string &signed_data,
1183 const string &destination_udn,
Christopher Wileycdde79f2013-05-01 14:26:56 -07001184 const string &hotspot_ssid,
1185 const string &hotspot_bssid,
Christopher Wiley0d9cf0c2013-02-19 19:24:57 -08001186 const string &network_path,
1187 const ResultStringCallback &cb,
1188 Error *error) {
Christopher Wiley1057cd72013-02-28 15:21:29 -08001189 // This is intentionally left unimplemented until we have a security review.
Christopher Wiley0d9cf0c2013-02-19 19:24:57 -08001190 error->Populate(Error::kNotImplemented, "Not implemented");
1191}
1192
Darin Petkova5e07ef2012-07-09 14:27:57 +02001193void Manager::NotifyDefaultServiceChanged(const ServiceRefPtr &service) {
1194 for (map<int, ServiceCallback>::const_iterator it =
1195 default_service_callbacks_.begin();
1196 it != default_service_callbacks_.end(); ++it) {
1197 it->second.Run(service);
1198 }
1199 metrics_->NotifyDefaultServiceChanged(service);
Paul Stewart49739c02012-08-08 17:24:03 -07001200 EmitDefaultService();
1201}
1202
1203void Manager::EmitDefaultService() {
1204 RpcIdentifier rpc_identifier = GetDefaultServiceRpcIdentifier(NULL);
1205 if (rpc_identifier != default_service_rpc_identifier_) {
1206 adaptor_->EmitRpcIdentifierChanged(shill::kDefaultServiceProperty,
1207 rpc_identifier);
1208 default_service_rpc_identifier_ = rpc_identifier;
1209 }
Darin Petkova5e07ef2012-07-09 14:27:57 +02001210}
1211
Darin Petkovca621542012-07-25 14:25:56 +02001212void Manager::OnPowerStateChanged(
1213 PowerManagerProxyDelegate::SuspendState power_state) {
1214 if (power_state == PowerManagerProxyDelegate::kOn) {
Christopher Wiley0801d192012-09-24 11:57:15 -07001215 vector<ServiceRefPtr>::iterator sit;
1216 for (sit = services_.begin(); sit != services_.end(); ++sit) {
1217 (*sit)->OnAfterResume();
1218 }
Darin Petkovca621542012-07-25 14:25:56 +02001219 SortServices();
mukesh agrawal784566d2012-08-08 18:32:58 -07001220 vector<DeviceRefPtr>::iterator it;
1221 for (it = devices_.begin(); it != devices_.end(); ++it) {
1222 (*it)->OnAfterResume();
1223 }
1224 } else if (power_state == PowerManagerProxyDelegate::kMem) {
1225 vector<DeviceRefPtr>::iterator it;
1226 for (it = devices_.begin(); it != devices_.end(); ++it) {
1227 (*it)->OnBeforeSuspend();
1228 }
Darin Petkovca621542012-07-25 14:25:56 +02001229 }
1230}
1231
Daniel Erat0818cca2012-12-14 10:16:21 -08001232void Manager::OnSuspendImminent(int suspend_id) {
Arman Ugurayab22c162012-10-08 19:08:38 -07001233 if (!RunTerminationActionsAndNotifyMetrics(
Daniel Erat0818cca2012-12-14 10:16:21 -08001234 Bind(&Manager::OnSuspendActionsComplete, AsWeakPtr(), suspend_id),
Arman Ugurayab22c162012-10-08 19:08:38 -07001235 Metrics::kTerminationActionReasonSuspend)) {
1236 LOG(INFO) << "No suspend actions were run.";
Daniel Erat0818cca2012-12-14 10:16:21 -08001237 power_manager_->ReportSuspendReadiness(suspend_delay_id_, suspend_id);
Arman Ugurayab22c162012-10-08 19:08:38 -07001238 }
Darin Petkov3ec55342012-09-28 14:04:44 +02001239}
1240
Daniel Erat0818cca2012-12-14 10:16:21 -08001241void Manager::OnSuspendActionsComplete(int suspend_id, const Error &error) {
Darin Petkov3ec55342012-09-28 14:04:44 +02001242 LOG(INFO) << "Finished suspend actions. Result: " << error;
Arman Ugurayab22c162012-10-08 19:08:38 -07001243 metrics_->NotifyTerminationActionsCompleted(
1244 Metrics::kTerminationActionReasonSuspend, error.IsSuccess());
Daniel Erat0818cca2012-12-14 10:16:21 -08001245 power_manager_->ReportSuspendReadiness(suspend_delay_id_, suspend_id);
Darin Petkov3ec55342012-09-28 14:04:44 +02001246}
1247
Paul Stewartfdd16072011-09-16 12:41:35 -07001248void Manager::FilterByTechnology(Technology::Identifier tech,
Paul Stewart3c504012013-01-17 17:49:58 -08001249 vector<DeviceRefPtr> *found) const {
Chris Masone9be4a9d2011-05-16 15:44:09 -07001250 CHECK(found);
Paul Stewart3c504012013-01-17 17:49:58 -08001251 vector<DeviceRefPtr>::const_iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -07001252 for (it = devices_.begin(); it != devices_.end(); ++it) {
Joshua Krollda798622012-06-05 12:30:48 -07001253 if ((*it)->technology() == tech)
Chris Masone9be4a9d2011-05-16 15:44:09 -07001254 found->push_back(*it);
1255 }
1256}
1257
Darin Petkov457728b2013-01-09 09:49:08 +01001258ServiceRefPtr Manager::FindService(const string &name) {
Chris Masonec1e50412011-06-07 13:04:53 -07001259 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -07001260 for (it = services_.begin(); it != services_.end(); ++it) {
Darin Petkov457728b2013-01-09 09:49:08 +01001261 if (name == (*it)->unique_name())
Chris Masonee0dea762011-06-09 09:06:03 -07001262 return *it;
Chris Masone9be4a9d2011-05-16 15:44:09 -07001263 }
Chris Masonee0dea762011-06-09 09:06:03 -07001264 return NULL;
Chris Masone9be4a9d2011-05-16 15:44:09 -07001265}
1266
Paul Stewart49739c02012-08-08 17:24:03 -07001267void Manager::HelpRegisterConstDerivedRpcIdentifier(
1268 const string &name,
1269 RpcIdentifier(Manager::*get)(Error *error)) {
1270 store_.RegisterDerivedRpcIdentifier(
1271 name,
1272 RpcIdentifierAccessor(
1273 new CustomAccessor<Manager, RpcIdentifier>(this, get, NULL)));
1274}
1275
mukesh agrawal2366eed2012-03-20 18:21:50 -07001276void Manager::HelpRegisterConstDerivedRpcIdentifiers(
1277 const string &name,
Jason Glasgowdf7c5532012-05-14 14:41:45 -04001278 RpcIdentifiers(Manager::*get)(Error *error)) {
mukesh agrawal2366eed2012-03-20 18:21:50 -07001279 store_.RegisterDerivedRpcIdentifiers(
1280 name,
1281 RpcIdentifiersAccessor(
1282 new CustomAccessor<Manager, RpcIdentifiers>(this, get, NULL)));
1283}
1284
mukesh agrawalffa3d042011-10-06 15:26:10 -07001285void Manager::HelpRegisterDerivedString(
1286 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001287 string(Manager::*get)(Error *),
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001288 bool(Manager::*set)(const string&, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -07001289 store_.RegisterDerivedString(
1290 name,
1291 StringAccessor(new CustomAccessor<Manager, string>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -07001292}
1293
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001294void Manager::HelpRegisterConstDerivedStrings(
mukesh agrawalffa3d042011-10-06 15:26:10 -07001295 const string &name,
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001296 Strings(Manager::*get)(Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -07001297 store_.RegisterDerivedStrings(
1298 name,
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001299 StringsAccessor(new CustomAccessor<Manager, Strings>(this, get, NULL)));
Chris Masoneb925cc82011-06-22 15:39:57 -07001300}
1301
Paul Stewart22aa71b2011-09-16 12:15:11 -07001302void Manager::SortServices() {
Paul Stewartdfa46052012-06-26 09:44:14 -07001303 // We might be called in the middle of a series of events that
1304 // may result in multiple calls to Manager::SortServices, or within
1305 // an outer loop that may also be traversing the services_ list.
1306 // Defer this work to the event loop.
1307 if (sort_services_task_.IsCancelled()) {
1308 sort_services_task_.Reset(Bind(&Manager::SortServicesTask, AsWeakPtr()));
1309 dispatcher_->PostTask(sort_services_task_.callback());
1310 }
1311}
1312
1313void Manager::SortServicesTask() {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001314 SLOG(Manager, 4) << "In " << __func__;
Paul Stewartdfa46052012-06-26 09:44:14 -07001315 sort_services_task_.Cancel();
Thieu Lea20cbc22012-01-09 22:01:43 +00001316 ServiceRefPtr default_service;
1317
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001318 if (!services_.empty()) {
Paul Stewarte2bad7c2012-03-14 08:55:33 -07001319 // Keep track of the service that is the candidate for the default
1320 // service. We have not yet tested to see if this service has a
1321 // connection.
Thieu Lea20cbc22012-01-09 22:01:43 +00001322 default_service = services_[0];
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001323 }
Paul Stewart39db5ca2013-03-18 14:15:17 -07001324 const bool kCompareConnectivityState = true;
1325 sort(services_.begin(), services_.end(),
1326 ServiceSorter(kCompareConnectivityState, technology_order_));
Paul Stewarta41e38d2011-11-11 07:47:29 -08001327
Paul Stewarta41e38d2011-11-11 07:47:29 -08001328 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kServicesProperty,
Paul Stewartbfb82552012-10-24 16:48:48 -07001329 EnumerateAvailableServices(NULL));
1330 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kServiceWatchListProperty,
1331 EnumerateWatchedServices(NULL));
Gaurav Shah435de2c2011-11-17 19:01:07 -08001332
1333 Error error;
1334 adaptor_->EmitStringsChanged(flimflam::kConnectedTechnologiesProperty,
1335 ConnectedTechnologies(&error));
1336 adaptor_->EmitStringChanged(flimflam::kDefaultTechnologyProperty,
1337 DefaultTechnology(&error));
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001338
1339 if (!services_.empty()) {
Thieu Lea20cbc22012-01-09 22:01:43 +00001340 ConnectionRefPtr default_connection = default_service->connection();
Darin Petkova5e07ef2012-07-09 14:27:57 +02001341 if (default_connection &&
1342 services_[0]->connection() != default_connection) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001343 default_connection->SetIsDefault(false);
1344 }
Darin Petkova5e07ef2012-07-09 14:27:57 +02001345 if (services_[0]->connection()) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001346 services_[0]->connection()->SetIsDefault(true);
Paul Stewart8596f9f2013-03-14 07:58:26 -07001347 if (default_service != services_[0]) {
1348 default_service = services_[0];
1349 LOG(INFO) << "Default service is now "
1350 << default_service->unique_name();
1351 }
Paul Stewarte2bad7c2012-03-14 08:55:33 -07001352 } else {
1353 default_service = NULL;
Paul Stewartc1dec4d2011-12-08 15:25:28 -08001354 }
1355 }
Darin Petkova5e07ef2012-07-09 14:27:57 +02001356 NotifyDefaultServiceChanged(default_service);
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001357 AutoConnect();
1358}
1359
Paul Stewart75225512012-01-26 22:51:33 -08001360bool Manager::MatchProfileWithService(const ServiceRefPtr &service) {
1361 vector<ProfileRefPtr>::reverse_iterator it;
1362 for (it = profiles_.rbegin(); it != profiles_.rend(); ++it) {
1363 if ((*it)->ConfigureService(service)) {
1364 break;
1365 }
1366 }
1367 if (it == profiles_.rend()) {
1368 ephemeral_profile_->AdoptService(service);
1369 return false;
1370 }
1371 return true;
1372}
1373
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001374void Manager::AutoConnect() {
Paul Stewart63864b62012-11-07 15:10:55 -08001375 if (!running_) {
1376 LOG(INFO) << "Auto-connect suppressed -- not running.";
1377 return;
1378 }
Darin Petkovca621542012-07-25 14:25:56 +02001379 if (power_manager_.get() &&
1380 power_manager_->power_state() != PowerManagerProxyDelegate::kOn &&
1381 power_manager_->power_state() != PowerManagerProxyDelegate::kUnknown) {
1382 LOG(INFO) << "Auto-connect suppressed -- power state is not 'on'.";
1383 return;
1384 }
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001385 if (services_.empty()) {
Darin Petkovca621542012-07-25 14:25:56 +02001386 LOG(INFO) << "Auto-connect suppressed -- no services.";
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001387 return;
1388 }
1389
Ben Chanfad4a0b2012-04-18 15:49:59 -07001390 if (SLOG_IS_ON(Manager, 4)) {
1391 SLOG(Manager, 4) << "Sorted service list: ";
mukesh agrawalddc378f2012-02-17 18:26:20 -08001392 for (size_t i = 0; i < services_.size(); ++i) {
1393 ServiceRefPtr service = services_[i];
1394 const char *compare_reason = NULL;
1395 if (i + 1 < services_.size()) {
Paul Stewart39db5ca2013-03-18 14:15:17 -07001396 const bool kCompareConnectivityState = true;
mukesh agrawalddc378f2012-02-17 18:26:20 -08001397 Service::Compare(
Paul Stewart39db5ca2013-03-18 14:15:17 -07001398 service, services_[i+1], kCompareConnectivityState,
1399 technology_order_, &compare_reason);
mukesh agrawalddc378f2012-02-17 18:26:20 -08001400 } else {
mukesh agrawalbf14e942012-03-02 14:36:34 -08001401 compare_reason = "last";
mukesh agrawalddc378f2012-02-17 18:26:20 -08001402 }
Darin Petkov457728b2013-01-09 09:49:08 +01001403 SLOG(Manager, 4) << "Service " << service->unique_name()
Ben Chanfad4a0b2012-04-18 15:49:59 -07001404 << " IsConnected: " << service->IsConnected()
1405 << " IsConnecting: " << service->IsConnecting()
1406 << " IsFailed: " << service->IsFailed()
1407 << " connectable: " << service->connectable()
1408 << " auto_connect: " << service->auto_connect()
1409 << " favorite: " << service->favorite()
1410 << " priority: " << service->priority()
mukesh agrawal43970a22013-02-15 16:00:07 -08001411 << " crypto_algorithm: " << service->crypto_algorithm()
1412 << " key_rotation: " << service->key_rotation()
1413 << " endpoint_auth: " << service->endpoint_auth()
Ben Chanfad4a0b2012-04-18 15:49:59 -07001414 << " strength: " << service->strength()
Ben Chanfad4a0b2012-04-18 15:49:59 -07001415 << " sorted: " << compare_reason;
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001416 }
1417 }
1418
Paul Stewart3d9bcf52011-12-12 15:02:22 -08001419 // Perform auto-connect.
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001420 for (vector<ServiceRefPtr>::iterator it = services_.begin();
1421 it != services_.end(); ++it) {
1422 if ((*it)->auto_connect()) {
mukesh agrawal8a3188d2011-12-01 20:56:44 +00001423 (*it)->AutoConnect();
Paul Stewart3d9bcf52011-12-12 15:02:22 -08001424 }
1425 }
Paul Stewart22aa71b2011-09-16 12:15:11 -07001426}
1427
Paul Stewart39db5ca2013-03-18 14:15:17 -07001428void Manager::ConnectToBestServices(Error */*error*/) {
1429 dispatcher_->PostTask(Bind(&Manager::ConnectToBestServicesTask, AsWeakPtr()));
1430}
1431
1432void Manager::ConnectToBestServicesTask() {
1433 vector<ServiceRefPtr> services_copy = services_;
1434 const bool kCompareConnectivityState = false;
1435 sort(services_copy.begin(), services_copy.end(),
1436 ServiceSorter(kCompareConnectivityState, technology_order_));
1437 set<Technology::Identifier> connecting_technologies;
1438 for (vector<ServiceRefPtr>::const_iterator it = services_copy.begin();
1439 it != services_copy.end();
1440 ++it) {
1441 if (!(*it)->connectable()) {
1442 // Due to service sort order, it is guaranteed that no services beyond
1443 // this one will be connectable either.
1444 break;
1445 }
Paul Stewartf7d7d3f2013-04-24 14:47:44 -07001446 if (!(*it)->auto_connect() || !(*it)->IsVisible()) {
Paul Stewart39db5ca2013-03-18 14:15:17 -07001447 continue;
1448 }
1449 Technology::Identifier technology = (*it)->technology();
1450 if (!Technology::IsPrimaryConnectivityTechnology(technology) &&
1451 !IsOnline()) {
1452 // Non-primary services need some other service connected first.
1453 continue;
1454 }
1455 if (ContainsKey(connecting_technologies, technology)) {
1456 // We have already started a connection for this technology.
1457 continue;
1458 }
1459 connecting_technologies.insert(technology);
1460 if (!(*it)->IsConnected() && !(*it)->IsConnecting()) {
1461 // At first blush, it may seem that using Service::AutoConnect might
1462 // be the right choice, however Service::IsAutoConnectable and its
1463 // overridden implementations consider a host of conditions which
1464 // prevent it from attempting a connection which we'd like to ignore
1465 // for the purposes of this user-initiated action.
1466 Error error;
mukesh agrawaldc7b8442012-09-27 13:48:14 -07001467 (*it)->Connect(&error, __func__);
Paul Stewart39db5ca2013-03-18 14:15:17 -07001468 if (error.IsFailure()) {
1469 LOG(ERROR) << "Connection failed: " << error.message();
1470 }
1471 }
1472 }
1473}
1474
Darin Petkov4cbff5b2013-01-29 16:29:05 +01001475bool Manager::IsOnline() const {
Gary Morain028545d2012-04-07 14:55:52 -07001476 // |services_| is sorted such that connected services are first.
Darin Petkov4cbff5b2013-01-29 16:29:05 +01001477 return !services_.empty() && services_.front()->IsConnected();
1478}
1479
1480string Manager::CalculateState(Error */*error*/) {
1481 return IsOnline() ? flimflam::kStateOnline : flimflam::kStateOffline;
Chris Masoneb925cc82011-06-22 15:39:57 -07001482}
1483
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001484vector<string> Manager::AvailableTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -08001485 set<string> unique_technologies;
1486 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1487 it != devices_.end(); ++it) {
1488 unique_technologies.insert(
1489 Technology::NameFromIdentifier((*it)->technology()));
1490 }
1491 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -07001492}
1493
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001494vector<string> Manager::ConnectedTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -08001495 set<string> unique_technologies;
1496 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1497 it != devices_.end(); ++it) {
1498 if ((*it)->IsConnected())
1499 unique_technologies.insert(
1500 Technology::NameFromIdentifier((*it)->technology()));
1501 }
1502 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -07001503}
1504
Paul Stewart3c504012013-01-17 17:49:58 -08001505bool Manager::IsTechnologyConnected(Technology::Identifier technology) const {
1506 for (vector<DeviceRefPtr>::const_iterator it = devices_.begin();
1507 it != devices_.end(); ++it) {
1508 if ((*it)->technology() == technology && (*it)->IsConnected())
1509 return true;
1510 }
1511 return false;
1512}
1513
Darin Petkov58f0b6d2012-06-12 12:52:30 +02001514string Manager::DefaultTechnology(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -08001515 return (!services_.empty() && services_[0]->IsConnected()) ?
Darin Petkov58f0b6d2012-06-12 12:52:30 +02001516 services_[0]->GetTechnologyString() : "";
Chris Masoneb925cc82011-06-22 15:39:57 -07001517}
1518
Eric Shienbrood9a245532012-03-07 14:20:39 -05001519vector<string> Manager::EnabledTechnologies(Error */*error*/) {
1520 set<string> unique_technologies;
1521 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1522 it != devices_.end(); ++it) {
1523 if ((*it)->enabled())
1524 unique_technologies.insert(
1525 Technology::NameFromIdentifier((*it)->technology()));
1526 }
1527 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -07001528}
1529
Ben Chan5086b972013-01-15 21:51:38 -08001530vector<string> Manager::UninitializedTechnologies(Error */*error*/) {
1531 return device_info_.GetUninitializedTechnologies();
1532}
1533
Paul Stewartcb3eb892012-06-07 14:24:46 -07001534RpcIdentifiers Manager::EnumerateDevices(Error */*error*/) {
1535 RpcIdentifiers device_rpc_ids;
Chris Masone3c3f6a12011-07-01 10:01:41 -07001536 for (vector<DeviceRefPtr>::const_iterator it = devices_.begin();
1537 it != devices_.end();
1538 ++it) {
1539 device_rpc_ids.push_back((*it)->GetRpcIdentifier());
1540 }
1541 return device_rpc_ids;
1542}
1543
Paul Stewartcb3eb892012-06-07 14:24:46 -07001544RpcIdentifiers Manager::EnumerateProfiles(Error */*error*/) {
1545 RpcIdentifiers profile_rpc_ids;
Paul Stewart1b253142012-01-26 14:05:52 -08001546 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
1547 it != profiles_.end();
1548 ++it) {
1549 profile_rpc_ids.push_back((*it)->GetRpcIdentifier());
1550 }
1551 return profile_rpc_ids;
1552}
1553
Gaurav Shah1b7a6162011-11-09 11:41:01 -08001554vector<string> Manager::EnumerateAvailableServices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -07001555 vector<string> service_rpc_ids;
1556 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
1557 it != services_.end();
1558 ++it) {
Paul Stewartbfb82552012-10-24 16:48:48 -07001559 if ((*it)->IsVisible()) {
1560 service_rpc_ids.push_back((*it)->GetRpcIdentifier());
1561 }
Chris Masone3c3f6a12011-07-01 10:01:41 -07001562 }
1563 return service_rpc_ids;
1564}
1565
Paul Stewart3c504012013-01-17 17:49:58 -08001566RpcIdentifiers Manager::EnumerateCompleteServices(Error */*error*/) {
1567 vector<string> service_rpc_ids;
1568 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
1569 it != services_.end();
1570 ++it) {
1571 service_rpc_ids.push_back((*it)->GetRpcIdentifier());
1572 }
1573 return service_rpc_ids;
1574}
1575
Paul Stewartbfb82552012-10-24 16:48:48 -07001576RpcIdentifiers Manager::EnumerateWatchedServices(Error */*error*/) {
1577 vector<string> service_rpc_ids;
1578 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
1579 it != services_.end();
1580 ++it) {
1581 if ((*it)->IsVisible() && (*it)->IsActive(NULL)) {
1582 service_rpc_ids.push_back((*it)->GetRpcIdentifier());
1583 }
1584 }
1585 return service_rpc_ids;
Chris Masone3c3f6a12011-07-01 10:01:41 -07001586}
1587
Paul Stewart1b253142012-01-26 14:05:52 -08001588string Manager::GetActiveProfileRpcIdentifier(Error */*error*/) {
1589 return ActiveProfile()->GetRpcIdentifier();
Chris Masone7aa5f902011-07-11 11:13:35 -07001590}
1591
Paul Stewart10e9e4e2012-04-26 19:46:28 -07001592string Manager::GetCheckPortalList(Error */*error*/) {
Jason Glasgowdf7c5532012-05-14 14:41:45 -04001593 return use_startup_portal_list_ ? startup_portal_list_ :
1594 props_.check_portal_list;
Paul Stewart10e9e4e2012-04-26 19:46:28 -07001595}
1596
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001597bool Manager::SetCheckPortalList(const string &portal_list, Error *error) {
Paul Stewart10e9e4e2012-04-26 19:46:28 -07001598 use_startup_portal_list_ = false;
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001599 if (props_.check_portal_list == portal_list) {
1600 return false;
1601 }
1602 props_.check_portal_list = portal_list;
1603 return true;
Paul Stewart10e9e4e2012-04-26 19:46:28 -07001604}
1605
Paul Stewart4d5efb72012-09-17 12:24:34 -07001606string Manager::GetIgnoredDNSSearchPaths(Error */*error*/) {
1607 return props_.ignored_dns_search_paths;
1608}
1609
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001610bool Manager::SetIgnoredDNSSearchPaths(const string &ignored_paths,
Paul Stewart4d5efb72012-09-17 12:24:34 -07001611 Error */*error*/) {
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001612 if (props_.ignored_dns_search_paths == ignored_paths) {
1613 return false;
1614 }
Paul Stewart4d5efb72012-09-17 12:24:34 -07001615 vector<string> ignored_path_list;
1616 if (!ignored_paths.empty()) {
1617 base::SplitString(ignored_paths, ',', &ignored_path_list);
1618 }
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001619 props_.ignored_dns_search_paths = ignored_paths;
Paul Stewart4d5efb72012-09-17 12:24:34 -07001620 resolver_->set_ignored_search_list(ignored_path_list);
mukesh agrawalbebf1b82013-04-23 15:06:33 -07001621 return true;
Paul Stewart4d5efb72012-09-17 12:24:34 -07001622}
1623
mukesh agrawal32399322011-09-01 10:53:43 -07001624// called via RPC (e.g., from ManagerDBusAdaptor)
Darin Petkovb65c2452012-02-23 15:17:06 +01001625ServiceRefPtr Manager::GetService(const KeyValueStore &args, Error *error) {
Paul Stewart7f5ad572012-06-04 15:18:54 -07001626 if (args.ContainsString(flimflam::kTypeProperty) &&
1627 args.GetString(flimflam::kTypeProperty) == flimflam::kTypeVPN) {
1628 // GetService on a VPN service should actually perform ConfigureService.
1629 // TODO(pstew): Remove this hack and change Chrome to use ConfigureService
Paul Stewartee6b3d72013-07-12 16:07:51 -07001630 // instead, when we no longer need to support flimflam. crbug.com/213802
Paul Stewart7f5ad572012-06-04 15:18:54 -07001631 return ConfigureService(args, error);
1632 }
Paul Stewart2c575d22012-12-07 12:28:57 -08001633
1634 ServiceRefPtr service = GetServiceInner(args, error);
1635 if (service) {
1636 // Configures the service using the rest of the passed-in arguments.
1637 service->Configure(args, error);
1638 }
1639
1640 return service;
Paul Stewart7f5ad572012-06-04 15:18:54 -07001641}
1642
1643ServiceRefPtr Manager::GetServiceInner(const KeyValueStore &args,
1644 Error *error) {
Paul Stewart13ed2252012-03-21 12:52:46 -07001645 if (args.ContainsString(flimflam::kGuidProperty)) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001646 SLOG(Manager, 2) << __func__ << ": searching by GUID";
Paul Stewart13ed2252012-03-21 12:52:46 -07001647 ServiceRefPtr service =
1648 GetServiceWithGUID(args.GetString(flimflam::kGuidProperty), NULL);
1649 if (service) {
Paul Stewart13ed2252012-03-21 12:52:46 -07001650 return service;
1651 }
1652 }
1653
Darin Petkovb65c2452012-02-23 15:17:06 +01001654 if (!args.ContainsString(flimflam::kTypeProperty)) {
Paul Stewart7f61e522012-03-22 11:13:45 -07001655 Error::PopulateAndLog(error, Error::kInvalidArguments, kErrorTypeRequired);
Darin Petkovb65c2452012-02-23 15:17:06 +01001656 return NULL;
1657 }
1658
1659 string type = args.GetString(flimflam::kTypeProperty);
Paul Stewart35eff132013-04-12 12:08:40 -07001660 if (type == kTypeEthernetEap) {
1661 SLOG(Manager, 2) << __func__ << ": getting Ethernet EAP Service";
1662 return ethernet_eap_provider_->service();
1663 }
Darin Petkovd1cd7972012-05-22 15:26:15 +02001664 if (type == flimflam::kTypeVPN) {
1665 SLOG(Manager, 2) << __func__ << ": getting VPN Service";
Darin Petkovc3505a52013-03-18 15:13:29 +01001666 return vpn_provider_->GetService(args, error);
Darin Petkovd1cd7972012-05-22 15:26:15 +02001667 }
Darin Petkovb65c2452012-02-23 15:17:06 +01001668 if (type == flimflam::kTypeWifi) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001669 SLOG(Manager, 2) << __func__ << ": getting WiFi Service";
Paul Stewart3c504012013-01-17 17:49:58 -08001670 return wifi_provider_->GetService(args, error);
Darin Petkovb65c2452012-02-23 15:17:06 +01001671 }
Darin Petkovd1cd7972012-05-22 15:26:15 +02001672 if (type == flimflam::kTypeWimax) {
1673 SLOG(Manager, 2) << __func__ << ": getting WiMAX Service";
1674 return wimax_provider_.GetService(args, error);
Darin Petkovb65c2452012-02-23 15:17:06 +01001675 }
mukesh agrawal06175d72012-04-23 16:46:01 -07001676 Error::PopulateAndLog(error, Error::kNotSupported,
1677 kErrorUnsupportedServiceType);
Darin Petkovb65c2452012-02-23 15:17:06 +01001678 return NULL;
1679}
1680
Paul Stewart7f61e522012-03-22 11:13:45 -07001681// called via RPC (e.g., from ManagerDBusAdaptor)
Paul Stewart7f5ad572012-06-04 15:18:54 -07001682ServiceRefPtr Manager::ConfigureService(const KeyValueStore &args,
1683 Error *error) {
Paul Stewart7f61e522012-03-22 11:13:45 -07001684 ProfileRefPtr profile = ActiveProfile();
1685 bool profile_specified = args.ContainsString(flimflam::kProfileProperty);
1686 if (profile_specified) {
1687 string profile_rpcid = args.GetString(flimflam::kProfileProperty);
1688 profile = LookupProfileByRpcIdentifier(profile_rpcid);
1689 if (!profile) {
1690 Error::PopulateAndLog(error, Error::kInvalidArguments,
1691 "Invalid profile name " + profile_rpcid);
Paul Stewart7f5ad572012-06-04 15:18:54 -07001692 return NULL;
Paul Stewart7f61e522012-03-22 11:13:45 -07001693 }
1694 }
1695
Paul Stewart7f5ad572012-06-04 15:18:54 -07001696 ServiceRefPtr service = GetServiceInner(args, error);
Paul Stewart7f61e522012-03-22 11:13:45 -07001697 if (error->IsFailure() || !service) {
1698 LOG(ERROR) << "GetService failed; returning upstream error.";
Paul Stewart7f5ad572012-06-04 15:18:54 -07001699 return NULL;
Paul Stewart7f61e522012-03-22 11:13:45 -07001700 }
1701
Paul Stewart2c575d22012-12-07 12:28:57 -08001702 // First pull in any stored configuration associated with the service.
1703 if (service->profile() == profile) {
Darin Petkov457728b2013-01-09 09:49:08 +01001704 SLOG(Manager, 2) << __func__ << ": service " << service->unique_name()
Paul Stewart2c575d22012-12-07 12:28:57 -08001705 << " is already a member of profile "
1706 << profile->GetFriendlyName()
1707 << " so a load is not necessary.";
1708 } else if (profile->LoadService(service)) {
1709 SLOG(Manager, 2) << __func__ << ": applied stored information from profile "
1710 << profile->GetFriendlyName()
1711 << " into service "
Darin Petkov457728b2013-01-09 09:49:08 +01001712 << service->unique_name();
Paul Stewart2c575d22012-12-07 12:28:57 -08001713 } else {
1714 SLOG(Manager, 2) << __func__ << ": no previous information in profile "
1715 << profile->GetFriendlyName()
1716 << " exists for service "
Darin Petkov457728b2013-01-09 09:49:08 +01001717 << service->unique_name();
Paul Stewart2c575d22012-12-07 12:28:57 -08001718 }
1719
1720 // Overlay this with the passed-in configuration parameters.
1721 service->Configure(args, error);
1722
mukesh agrawal06175d72012-04-23 16:46:01 -07001723 // Overwrite the profile data with the resulting configured service.
Paul Stewart7f61e522012-03-22 11:13:45 -07001724 if (!profile->UpdateService(service)) {
1725 Error::PopulateAndLog(error, Error::kInternalError,
1726 "Unable to save service to profile");
Paul Stewart7f5ad572012-06-04 15:18:54 -07001727 return NULL;
Paul Stewart7f61e522012-03-22 11:13:45 -07001728 }
1729
1730 if (HasService(service)) {
1731 // If the service has been registered (it may not be -- as is the case
1732 // with invisible WiFi networks), we can now transfer the service between
1733 // profiles.
Paul Stewart10ccbb32012-04-26 15:59:30 -07001734 if (IsServiceEphemeral(service) ||
Paul Stewart7f61e522012-03-22 11:13:45 -07001735 (profile_specified && service->profile() != profile)) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001736 SLOG(Manager, 2) << "Moving service to profile "
1737 << profile->GetFriendlyName();
Paul Stewart7f61e522012-03-22 11:13:45 -07001738 if (!MoveServiceToProfile(service, profile)) {
1739 Error::PopulateAndLog(error, Error::kInternalError,
1740 "Unable to move service to profile");
1741 }
1742 }
1743 }
Paul Stewart4357f4e2012-04-26 17:39:26 -07001744
1745 // Notify the service that a profile has been configured for it.
1746 service->OnProfileConfigured();
Paul Stewart7f5ad572012-06-04 15:18:54 -07001747
1748 return service;
Paul Stewart7f61e522012-03-22 11:13:45 -07001749}
1750
Paul Stewartd2e1c362013-03-03 19:06:07 -08001751// called via RPC (e.g., from ManagerDBusAdaptor)
1752ServiceRefPtr Manager::ConfigureServiceForProfile(
1753 const string &profile_rpcid, const KeyValueStore &args, Error *error) {
1754 if (args.LookupString(flimflam::kTypeProperty, "") != flimflam::kTypeWifi) {
1755 Error::PopulateAndLog(error, Error::kNotSupported,
1756 "This method only supports WiFi services");
1757 return NULL;
1758 }
1759
1760 ProfileRefPtr profile = LookupProfileByRpcIdentifier(profile_rpcid);
1761 if (!profile) {
1762 Error::PopulateAndLog(error, Error::kNotFound,
1763 "Profile specified was not found");
1764 return NULL;
1765 }
1766 if (args.LookupString(flimflam::kProfileProperty,
1767 profile_rpcid) != profile_rpcid) {
1768 Error::PopulateAndLog(error, Error::kInvalidArguments,
1769 "Profile argument does not match that in "
1770 "the configuration arguments");
1771 return NULL;
1772 }
1773
1774 ServiceRefPtr service;
1775 if (args.ContainsString(flimflam::kGuidProperty)) {
1776 SLOG(Manager, 2) << __func__ << ": searching by GUID";
1777 service = GetServiceWithGUID(args.GetString(flimflam::kGuidProperty), NULL);
1778 if (service && service->technology() != Technology::kWifi) {
1779 Error::PopulateAndLog(error, Error::kNotSupported,
1780 "This GUID matches a non-WiFi service");
1781 return NULL;
1782 }
1783 }
1784
1785 if (!service) {
1786 Error find_error;
1787 service = wifi_provider_->FindSimilarService(args, &find_error);
1788 }
1789
1790 // If no matching service exists, create a new service in the specified
1791 // profile using ConfigureService().
1792 if (!service) {
1793 KeyValueStore configure_args;
1794 configure_args.CopyFrom(args);
1795 configure_args.SetString(flimflam::kProfileProperty, profile_rpcid);
1796 return ConfigureService(configure_args, error);
1797 }
1798
1799 // The service already exists and is set to the desired profile,
1800 // the service is in the ephemeral profile, or the current profile
1801 // for the service appears before the desired profile, we need to
1802 // reassign the service to the new profile if necessary, leaving
1803 // the old profile intact (i.e, not calling Profile::AbandonService()).
1804 // Then, configure the properties on the service as well as its newly
1805 // associated profile.
1806 if (service->profile() == profile ||
1807 IsServiceEphemeral(service) ||
1808 IsProfileBefore(service->profile(), profile)) {
1809 SetupServiceInProfile(service, profile, args, error);
1810 return service;
1811 }
1812
1813 // The current profile for the service appears after the desired
1814 // profile. We must create a temporary service specifically for
1815 // the task of creating configuration data. This service will
1816 // neither inherit properties from the visible service, nor will
1817 // it exist after this function returns.
1818 service = wifi_provider_->CreateTemporaryService(args, error);
1819 if (!service || !error->IsSuccess()) {
1820 // Service::CreateTemporaryService() failed, and has set the error
1821 // appropriately.
1822 return NULL;
1823 }
1824
1825 // The profile may already have configuration for this service.
1826 profile->ConfigureService(service);
1827
1828 SetupServiceInProfile(service, profile, args, error);
1829
1830 // Although we have succeeded, this service will not exist, so its
1831 // path is of no use to the caller.
1832 DCHECK(service->HasOneRef());
1833 return NULL;
1834}
1835
1836void Manager::SetupServiceInProfile(ServiceRefPtr service,
1837 ProfileRefPtr profile,
1838 const KeyValueStore &args,
1839 Error *error) {
1840 service->SetProfile(profile);
1841 service->Configure(args, error);
1842 profile->UpdateService(service);
1843}
1844
Paul Stewart7a20aa42013-01-17 12:21:41 -08001845ServiceRefPtr Manager::FindMatchingService(const KeyValueStore &args,
1846 Error *error) {
1847 for (vector<ServiceRefPtr>::iterator it = services_.begin();
1848 it != services_.end(); ++it) {
1849 if ((*it)->DoPropertiesMatch(args)) {
1850 return *it;
1851 }
1852 }
1853 error->Populate(Error::kNotFound, "Matching service was not found");
1854 return NULL;
1855}
1856
Gaurav Shahb790aa22012-10-23 12:51:12 -07001857map<string, GeolocationInfos> Manager::GetNetworksForGeolocation() {
1858 map<string, GeolocationInfos> networks;
1859 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1860 it != devices_.end(); ++it) {
Wade Guthrie60a37062013-04-02 11:39:09 -07001861 switch ((*it)->technology()) {
Paul Stewartee6b3d72013-07-12 16:07:51 -07001862 // TODO(gauravsh): crbug.com/217833 Need a strategy for combining
Gaurav Shahb790aa22012-10-23 12:51:12 -07001863 // geolocation objects from multiple devices of the same technolgy.
1864 // Currently, we just pick the geolocation objects from the first found
1865 // device of each supported technology type.
1866 case Technology::kWifi:
1867 if (!ContainsKey(networks, kGeoWifiAccessPointsProperty))
1868 networks[kGeoWifiAccessPointsProperty] =
1869 (*it)->GetGeolocationObjects();
1870 break;
1871 case Technology::kCellular:
1872 if (!ContainsKey(networks, kGeoCellTowersProperty))
1873 networks[kGeoCellTowersProperty] = (*it)->GetGeolocationObjects();
1874 break;
1875 default:
1876 // Ignore other technologies.
1877 break;
1878 };
1879 }
1880 return networks;
1881};
1882
Paul Stewartc681fa02012-03-02 19:40:04 -08001883void Manager::RecheckPortal(Error */*error*/) {
1884 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1885 it != devices_.end(); ++it) {
1886 if ((*it)->RequestPortalDetection()) {
1887 // Only start Portal Detection on the device with the default connection.
1888 // We will get a "true" return value when we've found that device, and
1889 // can end our loop early as a result.
1890 break;
1891 }
1892 }
1893}
1894
Paul Stewartd215af62012-04-24 23:25:50 -07001895void Manager::RecheckPortalOnService(const ServiceRefPtr &service) {
1896 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
1897 it != devices_.end(); ++it) {
1898 if ((*it)->IsConnectedToService(service)) {
1899 // As opposed to RecheckPortal() above, we explicitly stop and then
1900 // restart portal detection, since the service to recheck was explicitly
1901 // specified.
1902 (*it)->RestartPortalDetection();
1903 break;
1904 }
1905 }
1906}
1907
Wade Guthrie68d41092013-04-02 12:56:02 -07001908void Manager::RequestScan(Device::ScanType scan_type,
1909 const string &technology, Error *error) {
mukesh agrawal32399322011-09-01 10:53:43 -07001910 if (technology == flimflam::kTypeWifi || technology == "") {
1911 vector<DeviceRefPtr> wifi_devices;
Paul Stewartfdd16072011-09-16 12:41:35 -07001912 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal32399322011-09-01 10:53:43 -07001913 for (vector<DeviceRefPtr>::iterator it = wifi_devices.begin();
1914 it != wifi_devices.end();
1915 ++it) {
Wade Guthrie4823f4f2013-07-25 10:03:03 -07001916 (*it)->Scan(scan_type, error, __func__);
mukesh agrawal32399322011-09-01 10:53:43 -07001917 }
1918 } else {
1919 // TODO(quiche): support scanning for other technologies?
Paul Stewartbe005172011-11-02 18:10:29 -07001920 Error::PopulateAndLog(error, Error::kInvalidArguments,
1921 "Unrecognized technology " + technology);
mukesh agrawal32399322011-09-01 10:53:43 -07001922 }
1923}
1924
Paul Stewart22aa71b2011-09-16 12:15:11 -07001925string Manager::GetTechnologyOrder() {
1926 vector<string> technology_names;
1927 for (vector<Technology::Identifier>::iterator it = technology_order_.begin();
1928 it != technology_order_.end();
1929 ++it) {
1930 technology_names.push_back(Technology::NameFromIdentifier(*it));
1931 }
1932
1933 return JoinString(technology_names, ',');
1934}
1935
1936void Manager::SetTechnologyOrder(const string &order, Error *error) {
1937 vector<Technology::Identifier> new_order;
Ben Chanfad4a0b2012-04-18 15:49:59 -07001938 SLOG(Manager, 2) << "Setting technology order to " << order;
Paul Stewart20088d82012-02-16 06:58:55 -08001939 if (!Technology::GetTechnologyVectorFromString(order, &new_order, error)) {
1940 return;
Paul Stewart22aa71b2011-09-16 12:15:11 -07001941 }
1942
1943 technology_order_ = new_order;
1944 SortServices();
1945}
1946
Paul Stewart75897df2011-04-27 09:05:53 -07001947} // namespace shill