blob: dba8137ed0d3413db8e7ec574fd81ac088d72368 [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>
Paul Stewart75897df2011-04-27 09:05:53 -070011#include <string>
Chris Masone52cd19b2011-06-29 17:23:04 -070012#include <vector>
Paul Stewart75897df2011-04-27 09:05:53 -070013
Paul Stewarte6132022011-08-16 09:11:02 -070014#include <base/file_util.h>
Chris Masoneee929b72011-05-10 10:02:18 -070015#include <base/logging.h>
Chris Masone9be4a9d2011-05-16 15:44:09 -070016#include <base/memory/ref_counted.h>
Paul Stewart22aa71b2011-09-16 12:15:11 -070017#include <base/string_util.h>
Chris Masone3bd3c8c2011-06-13 08:20:26 -070018#include <chromeos/dbus/service_constants.h>
Chris Masoneee929b72011-05-10 10:02:18 -070019
Chris Masoned0ceb8c2011-06-02 10:05:39 -070020#include "shill/adaptor_interfaces.h"
Paul Stewartc1dec4d2011-12-08 15:25:28 -080021#include "shill/connection.h"
Paul Stewart75897df2011-04-27 09:05:53 -070022#include "shill/control_interface.h"
Chris Masoned0ceb8c2011-06-02 10:05:39 -070023#include "shill/dbus_adaptor.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070024#include "shill/default_profile.h"
Chris Masone9be4a9d2011-05-16 15:44:09 -070025#include "shill/device.h"
26#include "shill/device_info.h"
Chris Masone6791a432011-07-12 13:23:19 -070027#include "shill/ephemeral_profile.h"
Chris Masone8fe2c7e2011-06-09 15:51:19 -070028#include "shill/error.h"
Paul Stewart26b327e2011-10-19 11:38:09 -070029#include "shill/event_dispatcher.h"
Chris Masone9d779932011-08-25 16:33:41 -070030#include "shill/key_file_store.h"
Thieu Lea20cbc22012-01-09 22:01:43 +000031#include "shill/metrics.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070032#include "shill/profile.h"
Chris Masoneb925cc82011-06-22 15:39:57 -070033#include "shill/property_accessor.h"
Paul Stewarte6132022011-08-16 09:11:02 -070034#include "shill/resolver.h"
Chris Masone9be4a9d2011-05-16 15:44:09 -070035#include "shill/service.h"
Thieu Lea20cbc22012-01-09 22:01:43 +000036#include "shill/service_sorter.h"
mukesh agrawal7a4e4002011-09-06 11:26:05 -070037#include "shill/wifi.h"
38#include "shill/wifi_service.h"
Paul Stewart75897df2011-04-27 09:05:53 -070039
Gaurav Shah435de2c2011-11-17 19:01:07 -080040using std::set;
Paul Stewart75897df2011-04-27 09:05:53 -070041using std::string;
Chris Masone9be4a9d2011-05-16 15:44:09 -070042using std::vector;
Paul Stewart75897df2011-04-27 09:05:53 -070043
44namespace shill {
Paul Stewarte6132022011-08-16 09:11:02 -070045
Darin Petkovb65c2452012-02-23 15:17:06 +010046// statics
47const char Manager::kErrorNoDevice[] = "no wifi devices available";
48const char Manager::kErrorTypeRequired[] = "must specify service type";
49const char Manager::kErrorUnsupportedServiceType[] =
50 "service type is unsupported";
mukesh agrawal7a4e4002011-09-06 11:26:05 -070051
Paul Stewart75897df2011-04-27 09:05:53 -070052Manager::Manager(ControlInterface *control_interface,
Darin Petkov887f2982011-07-14 16:10:17 -070053 EventDispatcher *dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -080054 Metrics *metrics,
Chris Masone2ae797d2011-08-23 20:41:00 -070055 GLib *glib,
56 const string &run_directory,
57 const string &storage_directory,
58 const string &user_storage_format)
mukesh agrawal8a3188d2011-12-01 20:56:44 +000059 : dispatcher_(dispatcher),
60 task_factory_(this),
61 run_path_(FilePath(run_directory)),
62 storage_path_(FilePath(storage_directory)),
63 user_storage_format_(user_storage_format),
64 adaptor_(control_interface->CreateManagerAdaptor(this)),
Thieu Le3426c8f2012-01-11 17:35:11 -080065 device_info_(control_interface, dispatcher, metrics, this),
66 modem_info_(control_interface, dispatcher, metrics, this, glib),
mukesh agrawal8a3188d2011-12-01 20:56:44 +000067 running_(false),
68 connect_profiles_to_rpc_(true),
69 ephemeral_profile_(new EphemeralProfile(control_interface, this)),
70 control_interface_(control_interface),
Thieu Le3426c8f2012-01-11 17:35:11 -080071 metrics_(metrics),
mukesh agrawal8a3188d2011-12-01 20:56:44 +000072 glib_(glib) {
Chris Masone7aa5f902011-07-11 11:13:35 -070073 HelpRegisterDerivedString(flimflam::kActiveProfileProperty,
Paul Stewart1b253142012-01-26 14:05:52 -080074 &Manager::GetActiveProfileRpcIdentifier,
Chris Masone7aa5f902011-07-11 11:13:35 -070075 NULL);
Chris Masone27c4aa52011-07-02 13:10:14 -070076 HelpRegisterDerivedStrings(flimflam::kAvailableTechnologiesProperty,
77 &Manager::AvailableTechnologies,
78 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -070079 store_.RegisterString(flimflam::kCheckPortalListProperty,
80 &props_.check_portal_list);
Chris Masone27c4aa52011-07-02 13:10:14 -070081 HelpRegisterDerivedStrings(flimflam::kConnectedTechnologiesProperty,
82 &Manager::ConnectedTechnologies,
83 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -070084 store_.RegisterString(flimflam::kCountryProperty, &props_.country);
Chris Masone27c4aa52011-07-02 13:10:14 -070085 HelpRegisterDerivedString(flimflam::kDefaultTechnologyProperty,
86 &Manager::DefaultTechnology,
87 NULL);
Chris Masone27c4aa52011-07-02 13:10:14 -070088 HelpRegisterDerivedStrings(flimflam::kDevicesProperty,
89 &Manager::EnumerateDevices,
90 NULL);
Chris Masone88cbd5f2011-07-03 14:30:04 -070091 HelpRegisterDerivedStrings(flimflam::kEnabledTechnologiesProperty,
92 &Manager::EnabledTechnologies,
93 NULL);
94 store_.RegisterBool(flimflam::kOfflineModeProperty, &props_.offline_mode);
95 store_.RegisterString(flimflam::kPortalURLProperty, &props_.portal_url);
Paul Stewart1b253142012-01-26 14:05:52 -080096 HelpRegisterDerivedStrings(flimflam::kProfilesProperty,
97 &Manager::EnumerateProfiles,
98 NULL);
Paul Stewartd32f4842012-01-11 16:08:13 -080099 store_.RegisterString(shill::kHostNameProperty, &props_.host_name);
Chris Masone88cbd5f2011-07-03 14:30:04 -0700100 HelpRegisterDerivedString(flimflam::kStateProperty,
101 &Manager::CalculateState,
102 NULL);
Chris Masone27c4aa52011-07-02 13:10:14 -0700103 HelpRegisterDerivedStrings(flimflam::kServicesProperty,
104 &Manager::EnumerateAvailableServices,
105 NULL);
106 HelpRegisterDerivedStrings(flimflam::kServiceWatchListProperty,
107 &Manager::EnumerateWatchedServices,
108 NULL);
Chris Masone3c3f6a12011-07-01 10:01:41 -0700109
mukesh agrawal84de5d22012-02-17 19:29:15 -0800110 // Set default technology order "by hand", to avoid invoking side
111 // effects of SetTechnologyOrder.
112 technology_order_.push_back(
113 Technology::IdentifierFromName(flimflam::kTypeEthernet));
114 technology_order_.push_back(
115 Technology::IdentifierFromName(flimflam::kTypeWifi));
116 technology_order_.push_back(
117 Technology::IdentifierFromName(flimflam::kTypeCellular));
118
Chris Masoneb07006b2011-05-14 16:10:04 -0700119 VLOG(2) << "Manager initialized.";
Paul Stewart75897df2011-04-27 09:05:53 -0700120}
121
Chris Masone6791a432011-07-12 13:23:19 -0700122Manager::~Manager() {
Chris Masone9d779932011-08-25 16:33:41 -0700123 profiles_.clear();
Chris Masone6791a432011-07-12 13:23:19 -0700124}
Paul Stewart75897df2011-04-27 09:05:53 -0700125
mukesh agrawal8f317b62011-07-15 11:53:23 -0700126void Manager::AddDeviceToBlackList(const string &device_name) {
127 device_info_.AddDeviceToBlackList(device_name);
128}
129
Paul Stewart75897df2011-04-27 09:05:53 -0700130void Manager::Start() {
Paul Stewart0af98bf2011-05-10 17:38:08 -0700131 LOG(INFO) << "Manager started.";
Paul Stewarte6132022011-08-16 09:11:02 -0700132
Chris Masone2ae797d2011-08-23 20:41:00 -0700133 CHECK(file_util::CreateDirectory(run_path_)) << run_path_.value();
Paul Stewarte6132022011-08-16 09:11:02 -0700134 Resolver::GetInstance()->set_path(run_path_.Append("resolv.conf"));
Chris Masone2ae797d2011-08-23 20:41:00 -0700135
Gaurav Shah71354762011-11-28 19:22:49 -0800136 InitializeProfiles();
Paul Stewart75897df2011-04-27 09:05:53 -0700137 running_ = true;
Chris Masone413a3192011-05-09 17:10:05 -0700138 adaptor_->UpdateRunning();
Paul Stewart0af98bf2011-05-10 17:38:08 -0700139 device_info_.Start();
Darin Petkov887f2982011-07-14 16:10:17 -0700140 modem_info_.Start();
Paul Stewart75897df2011-04-27 09:05:53 -0700141}
142
143void Manager::Stop() {
144 running_ = false;
Chris Masone9d779932011-08-25 16:33:41 -0700145 // Persist profile, device, service information to disk.
146 vector<ProfileRefPtr>::iterator it;
147 for (it = profiles_.begin(); it != profiles_.end(); ++it) {
Chris Masone6515aab2011-10-12 16:19:09 -0700148 (*it)->Save();
Chris Masone9d779932011-08-25 16:33:41 -0700149 }
Chris Masone9d779932011-08-25 16:33:41 -0700150
Thieu Le1271d682011-11-02 22:48:19 +0000151 vector<ServiceRefPtr>::iterator services_it;
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000152 Error e;
Thieu Le1271d682011-11-02 22:48:19 +0000153 for (services_it = services_.begin(); services_it != services_.end();
154 ++services_it) {
mukesh agrawal0ed0f2e2011-12-05 20:36:17 +0000155 (*services_it)->Disconnect(&e);
Thieu Le1271d682011-11-02 22:48:19 +0000156 }
157
Chris Masone413a3192011-05-09 17:10:05 -0700158 adaptor_->UpdateRunning();
Darin Petkov887f2982011-07-14 16:10:17 -0700159 modem_info_.Stop();
160 device_info_.Stop();
Paul Stewart75897df2011-04-27 09:05:53 -0700161}
162
Gaurav Shah71354762011-11-28 19:22:49 -0800163void Manager::InitializeProfiles() {
164 DCHECK(profiles_.empty());
165 // The default profile must go first on the stack.
166 CHECK(file_util::CreateDirectory(storage_path_)) << storage_path_.value();
Paul Stewart870523b2012-01-11 17:00:42 -0800167 scoped_refptr<DefaultProfile>
168 default_profile(new DefaultProfile(control_interface_,
Gaurav Shah71354762011-11-28 19:22:49 -0800169 this,
170 storage_path_,
171 props_));
Paul Stewart870523b2012-01-11 17:00:42 -0800172 CHECK(default_profile->InitStorage(glib_, Profile::kCreateOrOpenExisting,
173 NULL));
174 CHECK(default_profile->LoadManagerProperties(&props_));
175 profiles_.push_back(default_profile.release());
Gaurav Shah71354762011-11-28 19:22:49 -0800176 Error error;
Paul Stewart19c871d2011-12-15 16:10:13 -0800177 string path;
Gaurav Shah71354762011-11-28 19:22:49 -0800178 for (vector<string>::iterator it = startup_profiles_.begin();
179 it != startup_profiles_.end(); ++it)
Paul Stewart19c871d2011-12-15 16:10:13 -0800180 PushProfile(*it, &path, &error);
Gaurav Shah71354762011-11-28 19:22:49 -0800181}
182
Paul Stewart19c871d2011-12-15 16:10:13 -0800183void Manager::CreateProfile(const string &name, string *path, Error *error) {
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700184 Profile::Identifier ident;
185 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700186 Error::PopulateAndLog(error, Error::kInvalidArguments,
187 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700188 return;
189 }
190 ProfileRefPtr profile(new Profile(control_interface_,
191 this,
192 ident,
193 user_storage_format_,
Paul Stewart19c871d2011-12-15 16:10:13 -0800194 connect_profiles_to_rpc_));
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700195 if (!profile->InitStorage(glib_, Profile::kCreateNew, error)) {
Paul Stewart19c871d2011-12-15 16:10:13 -0800196 // |error| will have been populated by InitStorage().
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700197 return;
198 }
199
200 // Save profile data out, and then let the scoped pointer fall out of scope.
201 if (!profile->Save()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700202 Error::PopulateAndLog(error, Error::kInternalError,
203 "Profile name " + name + " could not be saved");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700204 return;
205 }
Paul Stewart19c871d2011-12-15 16:10:13 -0800206
207 *path = profile->GetRpcIdentifier();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700208}
209
Paul Stewart19c871d2011-12-15 16:10:13 -0800210void Manager::PushProfile(const string &name, string *path, Error *error) {
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700211 Profile::Identifier ident;
212 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700213 Error::PopulateAndLog(error, Error::kInvalidArguments,
214 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700215 return;
216 }
217
218 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
219 it != profiles_.end();
220 ++it) {
221 if ((*it)->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700222 Error::PopulateAndLog(error, Error::kAlreadyExists,
223 "Profile name " + name + " is already on stack");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700224 return;
225 }
226 }
227
228 if (ident.user.empty()) {
229 // The manager will have only one machine-wide profile, and this is the
230 // DefaultProfile. This means no other profiles can be loaded that do
231 // not have a user component.
232 // TODO(pstew): This is all well and good, but WiFi autotests try to
233 // creating a default profile (by a name other than "default") in order
234 // to avoid leaving permanent side effects to devices under test. This
235 // whole thing will need to be reworked in order to allow that to happen,
236 // or the autotests (or their expectations) will need to change.
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000237 // crosbug.com/24461
Paul Stewartbe005172011-11-02 18:10:29 -0700238 Error::PopulateAndLog(error, Error::kInvalidArguments,
239 "Cannot load non-default global profile " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700240 return;
241 }
242
243 ProfileRefPtr profile(new Profile(control_interface_,
244 this,
245 ident,
246 user_storage_format_,
247 connect_profiles_to_rpc_));
248 if (!profile->InitStorage(glib_, Profile::kOpenExisting, error)) {
Paul Stewart19c871d2011-12-15 16:10:13 -0800249 // |error| will have been populated by InitStorage().
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700250 return;
251 }
252
Paul Stewarta849a3d2011-11-03 05:54:09 -0700253 profiles_.push_back(profile);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700254
255 // Offer each registered Service the opportunity to join this new Profile.
Paul Stewarta41e38d2011-11-11 07:47:29 -0800256 for (vector<ServiceRefPtr>::iterator it = services_.begin();
257 it != services_.end(); ++it) {
Paul Stewartbba6a5b2011-11-02 18:45:59 -0700258 profile->ConfigureService(*it);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700259 }
260
Paul Stewarta41e38d2011-11-11 07:47:29 -0800261 // Shop the Profile contents around to Devices which can create
262 // non-visible services.
263 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
264 it != devices_.end(); ++it) {
265 profile->ConfigureDevice(*it);
266 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800267
Paul Stewart19c871d2011-12-15 16:10:13 -0800268 *path = profile->GetRpcIdentifier();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800269 SortServices();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700270}
271
272void Manager::PopProfileInternal() {
273 CHECK(!profiles_.empty());
274 ProfileRefPtr active_profile = profiles_.back();
275 profiles_.pop_back();
Paul Stewart75225512012-01-26 22:51:33 -0800276 vector<ServiceRefPtr>::iterator it;
277 for (it = services_.begin(); it != services_.end(); ++it) {
278 if ((*it)->profile().get() == active_profile.get() &&
279 !MatchProfileWithService(*it)) {
280 (*it)->Unload();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700281 }
282 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800283 SortServices();
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700284}
285
Paul Stewarta41e38d2011-11-11 07:47:29 -0800286void Manager::PopProfile(const string &name, Error *error) {
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700287 Profile::Identifier ident;
288 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700289 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700290 return;
291 }
292 ProfileRefPtr active_profile = profiles_.back();
293 if (!Profile::ParseIdentifier(name, &ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700294 Error::PopulateAndLog(error, Error::kInvalidArguments,
295 "Invalid profile name " + name);
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700296 return;
297 }
298 if (!active_profile->MatchesIdentifier(ident)) {
Paul Stewartbe005172011-11-02 18:10:29 -0700299 Error::PopulateAndLog(error, Error::kNotSupported,
300 name + " is not the active profile");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700301 return;
302 }
303 PopProfileInternal();
304}
305
306void Manager::PopAnyProfile(Error *error) {
307 Profile::Identifier ident;
308 if (profiles_.empty()) {
Paul Stewartbe005172011-11-02 18:10:29 -0700309 Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
Paul Stewart5dc40aa2011-10-28 19:43:43 -0700310 return;
311 }
312 PopProfileInternal();
313}
314
Paul Stewart75225512012-01-26 22:51:33 -0800315bool Manager::HandleProfileEntryDeletion(const ProfileRefPtr &profile,
316 const std::string &entry_name) {
317 bool moved_services = false;
318 for (vector<ServiceRefPtr>::iterator it = services_.begin();
319 it != services_.end(); ++it) {
320 if ((*it)->profile().get() == profile.get() &&
321 (*it)->GetStorageIdentifier() == entry_name) {
322 profile->AbandonService(*it);
323 if (!MatchProfileWithService(*it)) {
324 (*it)->Unload();
325 }
326 moved_services = true;
327 }
328 }
329 return moved_services;
330}
331
Paul Stewart0756db92012-01-27 08:34:47 -0800332ServiceRefPtr Manager::GetServiceWithStorageIdentifier(
333 const ProfileRefPtr &profile, const std::string &entry_name, Error *error) {
334 for (vector<ServiceRefPtr>::iterator it = services_.begin();
335 it != services_.end(); ++it) {
336 if ((*it)->profile().get() == profile.get() &&
337 (*it)->GetStorageIdentifier() == entry_name) {
338 return *it;
339 }
340 }
341
342 Error::PopulateAndLog(error, Error::kNotFound,
343 base::StringPrintf("Entry %s is not registered in the manager",
344 entry_name.c_str()));
345 return NULL;
346}
347
Paul Stewart20088d82012-02-16 06:58:55 -0800348bool Manager::IsPortalDetectionEnabled(Technology::Identifier tech) {
349 Error error;
350 vector<Technology::Identifier> portal_technologies;
351 return Technology::GetTechnologyVectorFromString(props_.check_portal_list,
352 &portal_technologies,
353 &error) &&
354 std::find(portal_technologies.begin(), portal_technologies.end(),
355 tech) != portal_technologies.end();
356}
357
Paul Stewart1b253142012-01-26 14:05:52 -0800358const ProfileRefPtr &Manager::ActiveProfile() const {
Chris Masoneb9c00592011-10-06 13:10:39 -0700359 DCHECK_NE(profiles_.size(), 0);
Chris Masone7aa5f902011-07-11 11:13:35 -0700360 return profiles_.back();
361}
362
Paul Stewart1b253142012-01-26 14:05:52 -0800363bool Manager::IsActiveProfile(const ProfileRefPtr &profile) const {
364 return (profiles_.size() > 0 &&
365 ActiveProfile().get() == profile.get());
366}
367
Chris Masone6515aab2011-10-12 16:19:09 -0700368bool Manager::MoveServiceToProfile(const ServiceRefPtr &to_move,
369 const ProfileRefPtr &destination) {
370 const ProfileRefPtr from = to_move->profile();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800371 VLOG(2) << "Moving service "
372 << to_move->UniqueName()
373 << " to profile "
374 << destination->GetFriendlyName()
375 << " from "
376 << from->GetFriendlyName();
Chris Masone6515aab2011-10-12 16:19:09 -0700377 return destination->AdoptService(to_move) &&
378 from->AbandonService(to_move);
Chris Masone6791a432011-07-12 13:23:19 -0700379}
380
Paul Stewart1b1a7f22012-01-06 16:24:06 -0800381void Manager::SetProfileForService(const ServiceRefPtr &to_set,
382 const string &profile_rpcid,
383 Error *error) {
384 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
385 it != profiles_.end();
386 ++it) {
387 if (profile_rpcid == (*it)->GetRpcIdentifier()) {
388 if (to_set->profile().get() == it->get()) {
389 Error::PopulateAndLog(error, Error::kInvalidArguments,
390 "Service is already connected to this profile");
391 } else if (!MoveServiceToProfile(to_set, *it)) {
392 Error::PopulateAndLog(error, Error::kInternalError,
393 "Unable to move service to profile");
394 }
395 return;
396 }
397 }
398 Error::PopulateAndLog(error, Error::kInvalidArguments,
399 "Unknown Profile requested for Service");
400}
401
Chris Masone2b105542011-06-22 10:58:09 -0700402void Manager::RegisterDevice(const DeviceRefPtr &to_manage) {
Chris Masonec1e50412011-06-07 13:04:53 -0700403 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700404 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700405 if (to_manage.get() == it->get())
Chris Masone9be4a9d2011-05-16 15:44:09 -0700406 return;
407 }
Chris Masonec1e50412011-06-07 13:04:53 -0700408 devices_.push_back(to_manage);
Paul Stewartf1ce5d22011-05-19 13:10:20 -0700409
Paul Stewarta41e38d2011-11-11 07:47:29 -0800410 // We are applying device properties from the DefaultProfile, and adding
411 // the union of hidden services in all loaded profiles to the device.
Chris Masone6515aab2011-10-12 16:19:09 -0700412 for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
413 it != profiles_.end();
414 ++it) {
Paul Stewarta41e38d2011-11-11 07:47:29 -0800415 // Load device configuration, if any exists, as well as hidden services.
416 (*it)->ConfigureDevice(to_manage);
417
418 // Currently the only profile for which "Save" is implemented is the
419 // DefaultProfile. It iterates over all Devices and stores their state.
420 // We perform the Save now in case the device we have just registered
421 // is new and needs to be added to the stored DefaultProfile.
Chris Masone6515aab2011-10-12 16:19:09 -0700422 (*it)->Save();
423 }
Paul Stewarta41e38d2011-11-11 07:47:29 -0800424
425 // In normal usage, running_ will always be true when we are here, however
426 // unit tests sometimes do things in otherwise invalid states.
427 if (running_ && to_manage->powered())
428 to_manage->Start();
Gaurav Shah435de2c2011-11-17 19:01:07 -0800429
430 Error error;
431 adaptor_->EmitStringsChanged(flimflam::kAvailableTechnologiesProperty,
432 AvailableTechnologies(&error));
433 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
434 EnabledTechnologies(&error));
Chris Masone9be4a9d2011-05-16 15:44:09 -0700435}
436
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700437void Manager::DeregisterDevice(const DeviceRefPtr &to_forget) {
Chris Masonec1e50412011-06-07 13:04:53 -0700438 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700439 for (it = devices_.begin(); it != devices_.end(); ++it) {
Chris Masonec1e50412011-06-07 13:04:53 -0700440 if (to_forget.get() == it->get()) {
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700441 VLOG(2) << "Deregistered device: " << to_forget->UniqueName();
442 to_forget->Stop();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700443 devices_.erase(it);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800444 Error error;
445 adaptor_->EmitStringsChanged(flimflam::kAvailableTechnologiesProperty,
446 AvailableTechnologies(&error));
447 adaptor_->EmitStringsChanged(flimflam::kEnabledTechnologiesProperty,
448 EnabledTechnologies(&error));
Chris Masone9be4a9d2011-05-16 15:44:09 -0700449 return;
450 }
451 }
mukesh agrawal5029c6c2011-08-25 11:12:40 -0700452 VLOG(2) << __func__ << " unknown device: " << to_forget->UniqueName();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700453}
454
mukesh agrawal4eb4d782011-12-05 17:34:37 +0000455bool Manager::HasService(const ServiceRefPtr &service) {
456 vector<ServiceRefPtr>::iterator it;
457 for (it = services_.begin(); it != services_.end(); ++it) {
458 if ((*it)->UniqueName() == service->UniqueName())
459 return true;
460 }
461 return false;
462}
463
Chris Masone2b105542011-06-22 10:58:09 -0700464void Manager::RegisterService(const ServiceRefPtr &to_manage) {
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800465 VLOG(2) << "In " << __func__ << "(): Registering service "
466 << to_manage->UniqueName();
mukesh agrawald835b202011-10-07 15:26:47 -0700467
Paul Stewart75225512012-01-26 22:51:33 -0800468 MatchProfileWithService(to_manage);
Chris Masone6791a432011-07-12 13:23:19 -0700469
470 // Now add to OUR list.
Chris Masonec1e50412011-06-07 13:04:53 -0700471 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700472 for (it = services_.begin(); it != services_.end(); ++it) {
mukesh agrawald835b202011-10-07 15:26:47 -0700473 CHECK(to_manage->UniqueName() != (*it)->UniqueName());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700474 }
Chris Masonec1e50412011-06-07 13:04:53 -0700475 services_.push_back(to_manage);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700476 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700477}
478
Chris Masone6515aab2011-10-12 16:19:09 -0700479void Manager::DeregisterService(const ServiceRefPtr &to_forget) {
Chris Masonec1e50412011-06-07 13:04:53 -0700480 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700481 for (it = services_.begin(); it != services_.end(); ++it) {
Chris Masone6791a432011-07-12 13:23:19 -0700482 if (to_forget->UniqueName() == (*it)->UniqueName()) {
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800483 DCHECK(!(*it)->connection());
Chris Masone9be4a9d2011-05-16 15:44:09 -0700484 services_.erase(it);
Paul Stewart22aa71b2011-09-16 12:15:11 -0700485 SortServices();
Chris Masone9be4a9d2011-05-16 15:44:09 -0700486 return;
487 }
488 }
489}
490
mukesh agrawal00917ce2011-11-22 23:56:55 +0000491void Manager::UpdateService(const ServiceRefPtr &to_update) {
492 CHECK(to_update);
Paul Stewart03dba0b2011-08-22 16:32:45 -0700493 LOG(INFO) << "Service " << to_update->UniqueName() << " updated;"
Gaurav Shahc6d6c722011-11-17 18:59:39 -0800494 << " state: " << Service::ConnectStateToString(to_update->state())
495 << " failure: "
496 << Service::ConnectFailureToString(to_update->failure());
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000497 VLOG(2) << "IsConnected(): " << to_update->IsConnected();
498 VLOG(2) << "IsConnecting(): " << to_update->IsConnecting();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800499 if (to_update->IsConnected()) {
Thieu Led4e9e552012-02-16 16:26:07 -0800500 bool originally_favorite = to_update->favorite();
mukesh agrawal00917ce2011-11-22 23:56:55 +0000501 to_update->MakeFavorite();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800502 if (to_update->profile().get() == ephemeral_profile_.get()) {
503 if (profiles_.empty()) {
504 LOG(ERROR) << "Cannot assign profile to service: no profiles exist!";
505 } else {
506 MoveServiceToProfile(to_update, profiles_.back());
507 }
Thieu Led4e9e552012-02-16 16:26:07 -0800508 } else if (!originally_favorite) {
509 // Persists the updated favorite setting in the profile.
510 to_update->SaveToCurrentProfile();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800511 }
512 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700513 SortServices();
Paul Stewart03dba0b2011-08-22 16:32:45 -0700514}
515
Paul Stewartfdd16072011-09-16 12:41:35 -0700516void Manager::FilterByTechnology(Technology::Identifier tech,
Chris Masonec1e50412011-06-07 13:04:53 -0700517 vector<DeviceRefPtr> *found) {
Chris Masone9be4a9d2011-05-16 15:44:09 -0700518 CHECK(found);
Chris Masonec1e50412011-06-07 13:04:53 -0700519 vector<DeviceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700520 for (it = devices_.begin(); it != devices_.end(); ++it) {
521 if ((*it)->TechnologyIs(tech))
522 found->push_back(*it);
523 }
524}
525
Paul Stewart22aa71b2011-09-16 12:15:11 -0700526ServiceRefPtr Manager::FindService(const string& name) {
Chris Masonec1e50412011-06-07 13:04:53 -0700527 vector<ServiceRefPtr>::iterator it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700528 for (it = services_.begin(); it != services_.end(); ++it) {
Chris Masone6791a432011-07-12 13:23:19 -0700529 if (name == (*it)->UniqueName())
Chris Masonee0dea762011-06-09 09:06:03 -0700530 return *it;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700531 }
Chris Masonee0dea762011-06-09 09:06:03 -0700532 return NULL;
Chris Masone9be4a9d2011-05-16 15:44:09 -0700533}
534
mukesh agrawalffa3d042011-10-06 15:26:10 -0700535void Manager::HelpRegisterDerivedString(
536 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800537 string(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -0700538 void(Manager::*set)(const string&, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -0700539 store_.RegisterDerivedString(
540 name,
541 StringAccessor(new CustomAccessor<Manager, string>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -0700542}
543
mukesh agrawalffa3d042011-10-06 15:26:10 -0700544void Manager::HelpRegisterDerivedStrings(
545 const string &name,
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800546 Strings(Manager::*get)(Error *),
mukesh agrawalffa3d042011-10-06 15:26:10 -0700547 void(Manager::*set)(const Strings &, Error *)) {
Chris Masone27c4aa52011-07-02 13:10:14 -0700548 store_.RegisterDerivedStrings(
549 name,
550 StringsAccessor(new CustomAccessor<Manager, Strings>(this, get, set)));
Chris Masoneb925cc82011-06-22 15:39:57 -0700551}
552
Paul Stewart22aa71b2011-09-16 12:15:11 -0700553void Manager::SortServices() {
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800554 VLOG(4) << "In " << __func__;
Thieu Lea20cbc22012-01-09 22:01:43 +0000555 ServiceRefPtr default_service;
556
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800557 if (!services_.empty()) {
Thieu Lea20cbc22012-01-09 22:01:43 +0000558 // Keep track of the service that was last considered default.
559 default_service = services_[0];
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800560 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700561 sort(services_.begin(), services_.end(), ServiceSorter(technology_order_));
Paul Stewarta41e38d2011-11-11 07:47:29 -0800562
563 vector<string> service_paths;
564 vector<ServiceRefPtr>::iterator it;
565 for (it = services_.begin(); it != services_.end(); ++it) {
566 if ((*it)->IsVisible()) {
567 service_paths.push_back((*it)->GetRpcIdentifier());
568 }
569 }
570 adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kServicesProperty,
571 service_paths);
Gaurav Shah435de2c2011-11-17 19:01:07 -0800572
573 Error error;
574 adaptor_->EmitStringsChanged(flimflam::kConnectedTechnologiesProperty,
575 ConnectedTechnologies(&error));
576 adaptor_->EmitStringChanged(flimflam::kDefaultTechnologyProperty,
577 DefaultTechnology(&error));
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800578
579 if (!services_.empty()) {
Thieu Lea20cbc22012-01-09 22:01:43 +0000580 ConnectionRefPtr default_connection = default_service->connection();
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800581 if (default_connection.get() &&
582 (services_[0]->connection().get() != default_connection.get())) {
583 default_connection->SetIsDefault(false);
Thieu Lea20cbc22012-01-09 22:01:43 +0000584 default_service = NULL;
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800585 }
586 if (services_[0]->connection().get()) {
587 services_[0]->connection()->SetIsDefault(true);
Thieu Lea20cbc22012-01-09 22:01:43 +0000588 default_service = services_[0];
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800589 }
Thieu Lea20cbc22012-01-09 22:01:43 +0000590 metrics_->NotifyDefaultServiceChanged(default_service);
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800591 }
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800592
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000593 AutoConnect();
594}
595
Paul Stewart75225512012-01-26 22:51:33 -0800596bool Manager::MatchProfileWithService(const ServiceRefPtr &service) {
597 vector<ProfileRefPtr>::reverse_iterator it;
598 for (it = profiles_.rbegin(); it != profiles_.rend(); ++it) {
599 if ((*it)->ConfigureService(service)) {
600 break;
601 }
602 }
603 if (it == profiles_.rend()) {
604 ephemeral_profile_->AdoptService(service);
605 return false;
606 }
607 return true;
608}
609
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000610void Manager::AutoConnect() {
611 // We might be called in the middle of another request (e.g., as a
612 // consequence of Service::SetState calling UpdateService). To avoid
613 // re-entrancy issues in dbus-c++, defer to the event loop.
614 dispatcher_->PostTask(
615 task_factory_.NewRunnableMethod(&Manager::AutoConnectTask));
616 return;
617}
618
619void Manager::AutoConnectTask() {
620 if (services_.empty()) {
621 LOG(INFO) << "No services.";
622 return;
623 }
624
625 if (VLOG_IS_ON(4)) {
mukesh agrawalddc378f2012-02-17 18:26:20 -0800626 VLOG(4) << "Sorted service list: ";
627 for (size_t i = 0; i < services_.size(); ++i) {
628 ServiceRefPtr service = services_[i];
629 const char *compare_reason = NULL;
630 if (i + 1 < services_.size()) {
631 Service::Compare(
632 service, services_[i+1], technology_order_, &compare_reason);
633 } else {
634 compare_reason = "";
635 }
636 VLOG(4) << "Service " << service->friendly_name()
637 << " IsConnected: " << service->IsConnected()
638 << " IsConnecting: " << service->IsConnecting()
639 << " IsFailed: " << service->IsFailed()
640 << " connectable: " << service->connectable()
641 << " auto_connect: " << service->auto_connect()
642 << " favorite: " << service->favorite()
643 << " priority: " << service->priority()
644 << " security_level: " << service->security_level()
645 << " strength: " << service->strength()
646 << " UniqueName: " << service->UniqueName()
647 << " " << compare_reason;
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000648 }
649 }
650
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800651 // Perform auto-connect.
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000652 for (vector<ServiceRefPtr>::iterator it = services_.begin();
653 it != services_.end(); ++it) {
654 if ((*it)->auto_connect()) {
mukesh agrawal592516d2012-01-12 14:01:00 -0800655 LOG(INFO) << "Requesting autoconnect to service "
656 << (*it)->friendly_name() << ".";
mukesh agrawal8a3188d2011-12-01 20:56:44 +0000657 (*it)->AutoConnect();
Paul Stewart3d9bcf52011-12-12 15:02:22 -0800658 }
659 }
Paul Stewart22aa71b2011-09-16 12:15:11 -0700660}
661
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800662string Manager::CalculateState(Error */*error*/) {
Chris Masoneb925cc82011-06-22 15:39:57 -0700663 return flimflam::kStateOffline;
664}
665
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800666vector<string> Manager::AvailableTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -0800667 set<string> unique_technologies;
668 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
669 it != devices_.end(); ++it) {
670 unique_technologies.insert(
671 Technology::NameFromIdentifier((*it)->technology()));
672 }
673 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700674}
675
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800676vector<string> Manager::ConnectedTechnologies(Error */*error*/) {
Gaurav Shah435de2c2011-11-17 19:01:07 -0800677 set<string> unique_technologies;
678 for (vector<DeviceRefPtr>::iterator it = devices_.begin();
679 it != devices_.end(); ++it) {
680 if ((*it)->IsConnected())
681 unique_technologies.insert(
682 Technology::NameFromIdentifier((*it)->technology()));
683 }
684 return vector<string>(unique_technologies.begin(), unique_technologies.end());
Chris Masoneb925cc82011-06-22 15:39:57 -0700685}
686
Gaurav Shah435de2c2011-11-17 19:01:07 -0800687string Manager::DefaultTechnology(Error *error) {
688 return (!services_.empty() && services_[0]->IsConnected()) ?
689 services_[0]->GetTechnologyString(error) : "";
Chris Masoneb925cc82011-06-22 15:39:57 -0700690}
691
Gaurav Shah435de2c2011-11-17 19:01:07 -0800692vector<string> Manager::EnabledTechnologies(Error *error) {
693 // TODO(gauravsh): This must be wired up to the RPC interface to handle
694 // enabled/disabled devices as set by the user. crosbug.com/23319
695 return AvailableTechnologies(error);
Chris Masoneb925cc82011-06-22 15:39:57 -0700696}
697
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800698vector<string> Manager::EnumerateDevices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -0700699 vector<string> device_rpc_ids;
700 for (vector<DeviceRefPtr>::const_iterator it = devices_.begin();
701 it != devices_.end();
702 ++it) {
703 device_rpc_ids.push_back((*it)->GetRpcIdentifier());
704 }
705 return device_rpc_ids;
706}
707
Paul Stewart1b253142012-01-26 14:05:52 -0800708vector<string> Manager::EnumerateProfiles(Error */*error*/) {
709 vector<string> profile_rpc_ids;
710 for (vector<ProfileRefPtr>::const_iterator it = profiles_.begin();
711 it != profiles_.end();
712 ++it) {
713 profile_rpc_ids.push_back((*it)->GetRpcIdentifier());
714 }
715 return profile_rpc_ids;
716}
717
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800718vector<string> Manager::EnumerateAvailableServices(Error */*error*/) {
Chris Masone3c3f6a12011-07-01 10:01:41 -0700719 vector<string> service_rpc_ids;
720 for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
721 it != services_.end();
722 ++it) {
723 service_rpc_ids.push_back((*it)->GetRpcIdentifier());
724 }
725 return service_rpc_ids;
726}
727
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800728vector<string> Manager::EnumerateWatchedServices(Error *error) {
Chris Masone6791a432011-07-12 13:23:19 -0700729 // TODO(cmasone): Filter this list for services in appropriate states.
Gaurav Shah1b7a6162011-11-09 11:41:01 -0800730 return EnumerateAvailableServices(error);
Chris Masone3c3f6a12011-07-01 10:01:41 -0700731}
732
Paul Stewart1b253142012-01-26 14:05:52 -0800733string Manager::GetActiveProfileRpcIdentifier(Error */*error*/) {
734 return ActiveProfile()->GetRpcIdentifier();
Chris Masone7aa5f902011-07-11 11:13:35 -0700735}
736
mukesh agrawal32399322011-09-01 10:53:43 -0700737// called via RPC (e.g., from ManagerDBusAdaptor)
Darin Petkovb65c2452012-02-23 15:17:06 +0100738ServiceRefPtr Manager::GetService(const KeyValueStore &args, Error *error) {
739 if (!args.ContainsString(flimflam::kTypeProperty)) {
740 error->Populate(Error::kInvalidArguments, kErrorTypeRequired);
741 return NULL;
742 }
743
744 string type = args.GetString(flimflam::kTypeProperty);
745 if (type == flimflam::kTypeWifi) {
746 return GetWifiService(args, error);
747 }
748 if (type == flimflam::kTypeVPN) {
749 return GetVPNService(args, error);
750 }
751 error->Populate(Error::kNotSupported, kErrorUnsupportedServiceType);
752 return NULL;
753}
754
mukesh agrawal7a4e4002011-09-06 11:26:05 -0700755WiFiServiceRefPtr Manager::GetWifiService(const KeyValueStore &args,
756 Error *error) {
Paul Stewarta41e38d2011-11-11 07:47:29 -0800757 vector<DeviceRefPtr> wifi_devices;
Paul Stewart22aa71b2011-09-16 12:15:11 -0700758 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal7a4e4002011-09-06 11:26:05 -0700759 if (wifi_devices.empty()) {
Darin Petkovb65c2452012-02-23 15:17:06 +0100760 error->Populate(Error::kInvalidArguments, kErrorNoDevice);
mukesh agrawal7a4e4002011-09-06 11:26:05 -0700761 return NULL;
762 } else {
763 WiFi *wifi = dynamic_cast<WiFi *>(wifi_devices.front().get());
764 CHECK(wifi);
765 return wifi->GetService(args, error);
766 }
767}
768
Darin Petkovb65c2452012-02-23 15:17:06 +0100769ServiceRefPtr Manager::GetVPNService(const KeyValueStore &/*args*/,
770 Error *error) {
771 // TODO(petkov): Implement this.
772 NOTIMPLEMENTED();
773 error->Populate(Error::kNotSupported, kErrorUnsupportedServiceType);
774 return NULL;
775}
776
mukesh agrawal7a4e4002011-09-06 11:26:05 -0700777// called via RPC (e.g., from ManagerDBusAdaptor)
Paul Stewart22aa71b2011-09-16 12:15:11 -0700778void Manager::RequestScan(const string &technology, Error *error) {
mukesh agrawal32399322011-09-01 10:53:43 -0700779 if (technology == flimflam::kTypeWifi || technology == "") {
780 vector<DeviceRefPtr> wifi_devices;
Paul Stewartfdd16072011-09-16 12:41:35 -0700781 FilterByTechnology(Technology::kWifi, &wifi_devices);
mukesh agrawal32399322011-09-01 10:53:43 -0700782
783 for (vector<DeviceRefPtr>::iterator it = wifi_devices.begin();
784 it != wifi_devices.end();
785 ++it) {
Darin Petkovc0865312011-09-16 15:31:20 -0700786 (*it)->Scan(error);
mukesh agrawal32399322011-09-01 10:53:43 -0700787 }
788 } else {
789 // TODO(quiche): support scanning for other technologies?
Paul Stewartbe005172011-11-02 18:10:29 -0700790 Error::PopulateAndLog(error, Error::kInvalidArguments,
791 "Unrecognized technology " + technology);
mukesh agrawal32399322011-09-01 10:53:43 -0700792 }
793}
794
Paul Stewart22aa71b2011-09-16 12:15:11 -0700795string Manager::GetTechnologyOrder() {
796 vector<string> technology_names;
797 for (vector<Technology::Identifier>::iterator it = technology_order_.begin();
798 it != technology_order_.end();
799 ++it) {
800 technology_names.push_back(Technology::NameFromIdentifier(*it));
801 }
802
803 return JoinString(technology_names, ',');
804}
805
806void Manager::SetTechnologyOrder(const string &order, Error *error) {
807 vector<Technology::Identifier> new_order;
mukesh agrawal84de5d22012-02-17 19:29:15 -0800808 VLOG(2) << "Setting technology order to " << order;
Paul Stewart20088d82012-02-16 06:58:55 -0800809 if (!Technology::GetTechnologyVectorFromString(order, &new_order, error)) {
810 return;
Paul Stewart22aa71b2011-09-16 12:15:11 -0700811 }
812
813 technology_order_ = new_order;
814 SortServices();
815}
816
Paul Stewart75897df2011-04-27 09:05:53 -0700817} // namespace shill