blob: 94a98f0039efd3ce8205cb4ca12463a5d18bab81 [file] [log] [blame]
Darin Petkovb72b62e2012-05-15 16:55:36 +02001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "shill/wimax_provider.h"
6
Darin Petkove4b27022012-05-16 13:28:50 +02007#include <algorithm>
8
Darin Petkovb72b62e2012-05-15 16:55:36 +02009#include <base/bind.h>
Darin Petkove4b27022012-05-16 13:28:50 +020010#include <base/string_util.h>
Ben Chanb879d142012-05-15 11:10:32 -070011#include <chromeos/dbus/service_constants.h>
Darin Petkovb72b62e2012-05-15 16:55:36 +020012
Darin Petkovb72b62e2012-05-15 16:55:36 +020013#include "shill/error.h"
Darin Petkovd1cd7972012-05-22 15:26:15 +020014#include "shill/key_value_store.h"
Darin Petkove4b27022012-05-16 13:28:50 +020015#include "shill/manager.h"
Darin Petkovc63dcf02012-05-24 11:51:43 +020016#include "shill/profile.h"
Darin Petkovb72b62e2012-05-15 16:55:36 +020017#include "shill/proxy_factory.h"
18#include "shill/scope_logger.h"
Darin Petkovc63dcf02012-05-24 11:51:43 +020019#include "shill/store_interface.h"
Darin Petkove4b27022012-05-16 13:28:50 +020020#include "shill/wimax.h"
Darin Petkovb72b62e2012-05-15 16:55:36 +020021#include "shill/wimax_manager_proxy_interface.h"
Darin Petkovd1cd7972012-05-22 15:26:15 +020022#include "shill/wimax_service.h"
Darin Petkovb72b62e2012-05-15 16:55:36 +020023
24using base::Bind;
25using base::Unretained;
Darin Petkove4b27022012-05-16 13:28:50 +020026using std::find;
27using std::map;
Darin Petkovc63dcf02012-05-24 11:51:43 +020028using std::set;
Darin Petkovb72b62e2012-05-15 16:55:36 +020029using std::string;
Darin Petkovb72b62e2012-05-15 16:55:36 +020030
31namespace shill {
32
Darin Petkovb72b62e2012-05-15 16:55:36 +020033WiMaxProvider::WiMaxProvider(ControlInterface *control,
34 EventDispatcher *dispatcher,
35 Metrics *metrics,
36 Manager *manager)
37 : control_(control),
38 dispatcher_(dispatcher),
39 metrics_(metrics),
40 manager_(manager),
41 proxy_factory_(ProxyFactory::GetInstance()) {}
42
Darin Petkovc63dcf02012-05-24 11:51:43 +020043WiMaxProvider::~WiMaxProvider() {}
Darin Petkovb72b62e2012-05-15 16:55:36 +020044
45void WiMaxProvider::Start() {
46 SLOG(WiMax, 2) << __func__;
47 if (manager_proxy_.get()) {
48 return;
49 }
Darin Petkovb72b62e2012-05-15 16:55:36 +020050 manager_proxy_.reset(proxy_factory_->CreateWiMaxManagerProxy());
Darin Petkov9893d9c2012-05-17 15:27:31 -070051 manager_proxy_->set_devices_changed_callback(
52 Bind(&WiMaxProvider::OnDevicesChanged, Unretained(this)));
Darin Petkovb72b62e2012-05-15 16:55:36 +020053 Error error;
Darin Petkov9893d9c2012-05-17 15:27:31 -070054 OnDevicesChanged(manager_proxy_->Devices(&error));
Darin Petkovb72b62e2012-05-15 16:55:36 +020055}
56
57void WiMaxProvider::Stop() {
58 SLOG(WiMax, 2) << __func__;
Darin Petkovb72b62e2012-05-15 16:55:36 +020059 manager_proxy_.reset();
Darin Petkove4b27022012-05-16 13:28:50 +020060 DestroyDeadDevices(RpcIdentifiers());
Darin Petkovc63dcf02012-05-24 11:51:43 +020061 networks_.clear();
62 DestroyAllServices();
Darin Petkovb72b62e2012-05-15 16:55:36 +020063}
64
Darin Petkove4b27022012-05-16 13:28:50 +020065void WiMaxProvider::OnDeviceInfoAvailable(const string &link_name) {
66 SLOG(WiMax, 2) << __func__ << "(" << link_name << ")";
Darin Petkovc1e52732012-05-25 15:23:45 +020067 map<string, RpcIdentifier>::iterator find_it =
68 pending_devices_.find(link_name);
Darin Petkove4b27022012-05-16 13:28:50 +020069 if (find_it != pending_devices_.end()) {
70 RpcIdentifier path = find_it->second;
71 CreateDevice(link_name, path);
72 }
73}
74
Darin Petkovc63dcf02012-05-24 11:51:43 +020075void WiMaxProvider::OnNetworksChanged() {
76 SLOG(WiMax, 2) << __func__;
77 // Collects the set if live networks from all devices.
78 networks_.clear();
79 for (map<string, WiMaxRefPtr>::iterator it = devices_.begin();
80 it != devices_.end(); ++it) {
81 const set<RpcIdentifier> &networks = it->second->networks();
82 networks_.insert(networks.begin(), networks.end());
83 }
84 // Stops dead and starts live services based on the collected set of live
85 // networks.
86 StopDeadServices();
87 StartLiveServices();
88}
89
Darin Petkovc1e52732012-05-25 15:23:45 +020090bool WiMaxProvider::OnServiceUnloaded(const WiMaxServiceRefPtr &service) {
91 SLOG(WiMax, 2) << __func__ << "(" << service->GetStorageIdentifier() << ")";
92 if (service->is_default()) {
93 return false;
94 }
95 // Removes the service from the managed service set. The service will be
96 // deregistered from Manager when we release ownership by returning true.
97 services_.erase(service->GetStorageIdentifier());
98 return true;
99}
100
Darin Petkovd1cd7972012-05-22 15:26:15 +0200101WiMaxServiceRefPtr WiMaxProvider::GetService(const KeyValueStore &args,
102 Error *error) {
103 SLOG(WiMax, 2) << __func__;
104 CHECK_EQ(args.GetString(flimflam::kTypeProperty), flimflam::kTypeWimax);
Darin Petkovd1cd7972012-05-22 15:26:15 +0200105 WiMaxNetworkId id = args.LookupString(WiMaxService::kNetworkIdProperty, "");
106 if (id.empty()) {
107 Error::PopulateAndLog(
108 error, Error::kInvalidArguments, "Missing WiMAX network id.");
109 return NULL;
110 }
111 string name = args.LookupString(flimflam::kNameProperty, "");
112 if (name.empty()) {
113 Error::PopulateAndLog(
114 error, Error::kInvalidArguments, "Missing WiMAX service name.");
115 return NULL;
116 }
Darin Petkovc63dcf02012-05-24 11:51:43 +0200117 WiMaxServiceRefPtr service = GetUniqueService(id, name);
Darin Petkovd1cd7972012-05-22 15:26:15 +0200118 CHECK(service);
119 // Configure the service using the the rest of the passed-in arguments.
120 service->Configure(args, error);
121 // Start the service if there's a matching live network.
Darin Petkovc63dcf02012-05-24 11:51:43 +0200122 StartLiveServices();
Darin Petkovd1cd7972012-05-22 15:26:15 +0200123 return service;
124}
125
Darin Petkovc63dcf02012-05-24 11:51:43 +0200126void WiMaxProvider::CreateServicesFromProfile(const ProfileRefPtr &profile) {
127 SLOG(WiMax, 2) << __func__;
128 bool created = false;
129 const StoreInterface *storage = profile->GetConstStorage();
130 set<string> groups = storage->GetGroupsWithKey(Service::kStorageType);
131 for (set<string>::iterator it = groups.begin(); it != groups.end(); ++it) {
132 const string &storage_id = *it;
133 string type;
134 if (!storage->GetString(storage_id, Service::kStorageType, &type) ||
135 type != Technology::NameFromIdentifier(Technology::kWiMax)) {
136 continue;
137 }
138 if (FindService(storage_id)) {
139 continue;
140 }
141 WiMaxNetworkId id;
142 if (!storage->GetString(storage_id, WiMaxService::kStorageNetworkId, &id) ||
143 id.empty()) {
144 LOG(ERROR) << "Unable to load network id: " << storage_id;
145 continue;
146 }
147 string name;
148 if (!storage->GetString(storage_id, Service::kStorageName, &name) ||
149 name.empty()) {
150 LOG(ERROR) << "Unable to load service name: " << storage_id;
151 continue;
152 }
153 WiMaxServiceRefPtr service = GetUniqueService(id, name);
154 CHECK(service);
155 if (!profile->ConfigureService(service)) {
156 LOG(ERROR) << "Could not configure service: " << storage_id;
157 }
158 created = true;
159 }
160 if (created) {
161 StartLiveServices();
162 }
163}
164
165WiMaxRefPtr WiMaxProvider::SelectCarrier(const WiMaxServiceRefPtr &service) {
166 SLOG(WiMax, 2) << __func__ << "(" << service->GetStorageIdentifier() << ")";
167 if (devices_.empty()) {
168 LOG(ERROR) << "No WiMAX devices available.";
169 return NULL;
170 }
171 // TODO(petkov): For now, just return the first available device. We need to
172 // be smarter here and select a device that sees |service|'s network.
173 return devices_.begin()->second;
174}
175
176void WiMaxProvider::OnDevicesChanged(const RpcIdentifiers &devices) {
177 SLOG(WiMax, 2) << __func__;
178 DestroyDeadDevices(devices);
179 for (RpcIdentifiers::const_iterator it = devices.begin();
180 it != devices.end(); ++it) {
181 const RpcIdentifier &path = *it;
182 string link_name = GetLinkName(path);
183 if (!link_name.empty()) {
184 CreateDevice(link_name, path);
185 }
186 }
187}
188
Darin Petkove4b27022012-05-16 13:28:50 +0200189void WiMaxProvider::CreateDevice(const string &link_name,
190 const RpcIdentifier &path) {
191 SLOG(WiMax, 2) << __func__ << "(" << link_name << ", " << path << ")";
Darin Petkov0fcd3462012-05-17 11:25:11 +0200192 if (ContainsKey(devices_, link_name)) {
193 SLOG(WiMax, 2) << "Device already exists.";
194 CHECK_EQ(path, devices_[link_name]->path());
195 return;
196 }
Darin Petkove4b27022012-05-16 13:28:50 +0200197 pending_devices_.erase(link_name);
198 DeviceInfo *device_info = manager_->device_info();
199 if (device_info->IsDeviceBlackListed(link_name)) {
Darin Petkovc63dcf02012-05-24 11:51:43 +0200200 LOG(INFO) << "WiMAX device not created, interface blacklisted: "
Darin Petkove4b27022012-05-16 13:28:50 +0200201 << link_name;
202 return;
203 }
204 int index = device_info->GetIndex(link_name);
205 if (index < 0) {
206 SLOG(WiMax, 2) << link_name << " pending device info.";
207 // Adds the link to the pending device map, waiting for a notification from
208 // DeviceInfo that it's received information about the device from RTNL.
209 pending_devices_[link_name] = path;
210 return;
211 }
212 ByteString address_bytes;
213 if (!device_info->GetMACAddress(index, &address_bytes)) {
Darin Petkovc63dcf02012-05-24 11:51:43 +0200214 LOG(ERROR) << "Unable to create a WiMAX device with no MAC address: "
Darin Petkove4b27022012-05-16 13:28:50 +0200215 << link_name;
216 return;
217 }
218 string address = address_bytes.HexEncode();
219 WiMaxRefPtr device(new WiMax(control_, dispatcher_, metrics_, manager_,
220 link_name, address, index, path));
Darin Petkov0fcd3462012-05-17 11:25:11 +0200221 devices_[link_name] = device;
Darin Petkove4b27022012-05-16 13:28:50 +0200222 device_info->RegisterDevice(device);
Darin Petkovc63dcf02012-05-24 11:51:43 +0200223 LOG(INFO) << "Created WiMAX device: " << link_name << " @ " << path;
Darin Petkove4b27022012-05-16 13:28:50 +0200224}
225
226void WiMaxProvider::DestroyDeadDevices(const RpcIdentifiers &live_devices) {
227 SLOG(WiMax, 2) << __func__ << "(" << live_devices.size() << ")";
Darin Petkovc1e52732012-05-25 15:23:45 +0200228 for (map<string, RpcIdentifier>::iterator it = pending_devices_.begin();
Darin Petkove4b27022012-05-16 13:28:50 +0200229 it != pending_devices_.end(); ) {
230 if (find(live_devices.begin(), live_devices.end(), it->second) ==
231 live_devices.end()) {
Darin Petkovc63dcf02012-05-24 11:51:43 +0200232 LOG(INFO) << "Forgetting pending device: " << it->second;
Darin Petkove4b27022012-05-16 13:28:50 +0200233 pending_devices_.erase(it++);
234 } else {
235 ++it;
236 }
237 }
Darin Petkov0fcd3462012-05-17 11:25:11 +0200238 for (map<string, WiMaxRefPtr>::iterator it = devices_.begin();
Darin Petkove4b27022012-05-16 13:28:50 +0200239 it != devices_.end(); ) {
Darin Petkov0fcd3462012-05-17 11:25:11 +0200240 if (find(live_devices.begin(), live_devices.end(), it->second->path()) ==
Darin Petkove4b27022012-05-16 13:28:50 +0200241 live_devices.end()) {
Darin Petkovc63dcf02012-05-24 11:51:43 +0200242 LOG(INFO) << "Destroying device: " << it->first;
Darin Petkov0fcd3462012-05-17 11:25:11 +0200243 manager_->device_info()->DeregisterDevice(it->second);
244 devices_.erase(it++);
Darin Petkove4b27022012-05-16 13:28:50 +0200245 } else {
246 ++it;
247 }
248 }
249}
250
251string WiMaxProvider::GetLinkName(const RpcIdentifier &path) {
Darin Petkov9893d9c2012-05-17 15:27:31 -0700252 if (StartsWithASCII(path, wimax_manager::kDeviceObjectPathPrefix, true)) {
253 return path.substr(strlen(wimax_manager::kDeviceObjectPathPrefix));
Darin Petkove4b27022012-05-16 13:28:50 +0200254 }
255 LOG(ERROR) << "Unable to determine link name from RPC path: " << path;
256 return string();
Darin Petkovb72b62e2012-05-15 16:55:36 +0200257}
258
Darin Petkovc63dcf02012-05-24 11:51:43 +0200259WiMaxServiceRefPtr WiMaxProvider::FindService(const string &storage_id) {
260 SLOG(WiMax, 2) << __func__ << "(" << storage_id << ")";
Darin Petkovc1e52732012-05-25 15:23:45 +0200261 map<string, WiMaxServiceRefPtr>::const_iterator find_it =
262 services_.find(storage_id);
263 if (find_it == services_.end()) {
264 return NULL;
Darin Petkovc63dcf02012-05-24 11:51:43 +0200265 }
Darin Petkovc1e52732012-05-25 15:23:45 +0200266 const WiMaxServiceRefPtr &service = find_it->second;
267 LOG_IF(ERROR, storage_id != service->GetStorageIdentifier());
268 return service;
Darin Petkovc63dcf02012-05-24 11:51:43 +0200269}
270
271WiMaxServiceRefPtr WiMaxProvider::GetUniqueService(const WiMaxNetworkId &id,
272 const string &name) {
273 SLOG(WiMax, 2) << __func__ << "(" << id << ", " << name << ")";
274 string storage_id = WiMaxService::CreateStorageIdentifier(id, name);
275 WiMaxServiceRefPtr service = FindService(storage_id);
276 if (service) {
277 SLOG(WiMax, 2) << "Service already exists.";
278 return service;
279 }
280 service = new WiMaxService(control_, dispatcher_, metrics_, manager_);
281 service->set_network_id(id);
282 service->set_friendly_name(name);
283 service->InitStorageIdentifier();
Darin Petkovc1e52732012-05-25 15:23:45 +0200284 services_[service->GetStorageIdentifier()] = service;
Darin Petkovc63dcf02012-05-24 11:51:43 +0200285 manager_->RegisterService(service);
286 LOG(INFO) << "Registered WiMAX service: " << service->GetStorageIdentifier();
287 return service;
288}
289
290WiMaxServiceRefPtr WiMaxProvider::GetDefaultService(
291 const RpcIdentifier &network) {
292 SLOG(WiMax, 2) << __func__ << "(" << network << ")";
293 scoped_ptr<WiMaxNetworkProxyInterface> proxy(
294 proxy_factory_->CreateWiMaxNetworkProxy(network));
295 Error error;
296 uint32 identifier = proxy->Identifier(&error);
297 if (error.IsFailure()) {
298 return NULL;
299 }
300 string name = proxy->Name(&error);
301 if (error.IsFailure()) {
302 return NULL;
303 }
Darin Petkovc1e52732012-05-25 15:23:45 +0200304 WiMaxServiceRefPtr service =
305 GetUniqueService(
306 WiMaxService::ConvertIdentifierToNetworkId(identifier), name);
307 CHECK(service);
308 service->set_is_default(true);
309 return service;
Darin Petkovc63dcf02012-05-24 11:51:43 +0200310}
311
312void WiMaxProvider::StartLiveServices() {
313 for (set<RpcIdentifier>::const_iterator it = networks_.begin();
314 it != networks_.end(); ++it) {
315 StartLiveServicesForNetwork(*it);
316 }
317}
318
319void WiMaxProvider::StartLiveServicesForNetwork(const RpcIdentifier &network) {
320 SLOG(WiMax, 2) << __func__ << "(" << network << ")";
321 WiMaxServiceRefPtr default_service = GetDefaultService(network);
322 if (!default_service) {
323 return;
324 }
325 // Start services for this live network identifier.
Darin Petkovc1e52732012-05-25 15:23:45 +0200326 for (map<string, WiMaxServiceRefPtr>::const_iterator it = services_.begin();
Darin Petkovc63dcf02012-05-24 11:51:43 +0200327 it != services_.end(); ++it) {
Darin Petkovc1e52732012-05-25 15:23:45 +0200328 const WiMaxServiceRefPtr &service = it->second;
Darin Petkovc63dcf02012-05-24 11:51:43 +0200329 if (service->network_id() != default_service->network_id() ||
330 service->IsStarted()) {
331 continue;
332 }
333 if (!service->Start(proxy_factory_->CreateWiMaxNetworkProxy(network))) {
334 LOG(ERROR) << "Unable to start service: "
335 << service->GetStorageIdentifier();
336 }
337 }
338}
339
340void WiMaxProvider::StopDeadServices() {
341 SLOG(WiMax, 2) << __func__ << "(" << networks_.size() << ")";
Darin Petkovc1e52732012-05-25 15:23:45 +0200342 for (map<string, WiMaxServiceRefPtr>::iterator it = services_.begin();
343 it != services_.end(); ) {
344 const WiMaxServiceRefPtr &service = it->second;
345 if (service->IsStarted() &&
346 !ContainsKey(networks_, service->GetNetworkObjectPath())) {
347 service->Stop();
348 // Default services are created and registered when a network becomes
349 // live. They need to be deregistered and destroyed when the network
350 // disappears.
351 if (service->is_default()) {
352 manager_->DeregisterService(service);
353 services_.erase(it++);
354 continue;
355 }
Darin Petkovc63dcf02012-05-24 11:51:43 +0200356 }
Darin Petkovc1e52732012-05-25 15:23:45 +0200357 ++it;
Darin Petkovc63dcf02012-05-24 11:51:43 +0200358 }
359}
360
361void WiMaxProvider::DestroyAllServices() {
362 SLOG(WiMax, 2) << __func__;
Darin Petkovc1e52732012-05-25 15:23:45 +0200363 for (map<string, WiMaxServiceRefPtr>::iterator it = services_.begin();
364 it != services_.end(); services_.erase(it++)) {
365 const WiMaxServiceRefPtr &service = it->second;
Darin Petkovc63dcf02012-05-24 11:51:43 +0200366 // Stop the service so that it can notify its carrier device, if any.
367 service->Stop();
368 manager_->DeregisterService(service);
369 LOG(INFO) << "Deregistered WiMAX service: "
370 << service->GetStorageIdentifier();
Darin Petkovc63dcf02012-05-24 11:51:43 +0200371 }
372}
373
Darin Petkovb72b62e2012-05-15 16:55:36 +0200374} // namespace shill