blob: 3cbddb36e203e3434db2254cf956a1cefe653218 [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>
Darin Petkovfc00fd42012-05-30 11:30:06 +02008#include <set>
Darin Petkove4b27022012-05-16 13:28:50 +02009
Darin Petkovb72b62e2012-05-15 16:55:36 +020010#include <base/bind.h>
Darin Petkove4b27022012-05-16 13:28:50 +020011#include <base/string_util.h>
Ben Chanb879d142012-05-15 11:10:32 -070012#include <chromeos/dbus/service_constants.h>
Darin Petkovb72b62e2012-05-15 16:55:36 +020013
Darin Petkovb72b62e2012-05-15 16:55:36 +020014#include "shill/error.h"
Darin Petkovd1cd7972012-05-22 15:26:15 +020015#include "shill/key_value_store.h"
Darin Petkove4b27022012-05-16 13:28:50 +020016#include "shill/manager.h"
Darin Petkovc63dcf02012-05-24 11:51:43 +020017#include "shill/profile.h"
Darin Petkovb72b62e2012-05-15 16:55:36 +020018#include "shill/proxy_factory.h"
19#include "shill/scope_logger.h"
Darin Petkovc63dcf02012-05-24 11:51:43 +020020#include "shill/store_interface.h"
Darin Petkove4b27022012-05-16 13:28:50 +020021#include "shill/wimax.h"
Darin Petkovb72b62e2012-05-15 16:55:36 +020022#include "shill/wimax_manager_proxy_interface.h"
Darin Petkovd1cd7972012-05-22 15:26:15 +020023#include "shill/wimax_service.h"
Darin Petkovb72b62e2012-05-15 16:55:36 +020024
25using base::Bind;
26using base::Unretained;
Darin Petkove4b27022012-05-16 13:28:50 +020027using std::find;
28using std::map;
Darin Petkovc63dcf02012-05-24 11:51:43 +020029using std::set;
Darin Petkovb72b62e2012-05-15 16:55:36 +020030using std::string;
Darin Petkovb72b62e2012-05-15 16:55:36 +020031
32namespace shill {
33
Darin Petkovb72b62e2012-05-15 16:55:36 +020034WiMaxProvider::WiMaxProvider(ControlInterface *control,
35 EventDispatcher *dispatcher,
36 Metrics *metrics,
37 Manager *manager)
38 : control_(control),
39 dispatcher_(dispatcher),
40 metrics_(metrics),
41 manager_(manager),
42 proxy_factory_(ProxyFactory::GetInstance()) {}
43
Darin Petkovc63dcf02012-05-24 11:51:43 +020044WiMaxProvider::~WiMaxProvider() {}
Darin Petkovb72b62e2012-05-15 16:55:36 +020045
46void WiMaxProvider::Start() {
47 SLOG(WiMax, 2) << __func__;
48 if (manager_proxy_.get()) {
49 return;
50 }
Darin Petkovb72b62e2012-05-15 16:55:36 +020051 manager_proxy_.reset(proxy_factory_->CreateWiMaxManagerProxy());
Darin Petkov9893d9c2012-05-17 15:27:31 -070052 manager_proxy_->set_devices_changed_callback(
53 Bind(&WiMaxProvider::OnDevicesChanged, Unretained(this)));
Darin Petkovb72b62e2012-05-15 16:55:36 +020054 Error error;
Darin Petkov9893d9c2012-05-17 15:27:31 -070055 OnDevicesChanged(manager_proxy_->Devices(&error));
Darin Petkovb72b62e2012-05-15 16:55:36 +020056}
57
58void WiMaxProvider::Stop() {
59 SLOG(WiMax, 2) << __func__;
Darin Petkovb72b62e2012-05-15 16:55:36 +020060 manager_proxy_.reset();
Darin Petkove4b27022012-05-16 13:28:50 +020061 DestroyDeadDevices(RpcIdentifiers());
Darin Petkovc63dcf02012-05-24 11:51:43 +020062 networks_.clear();
63 DestroyAllServices();
Darin Petkovb72b62e2012-05-15 16:55:36 +020064}
65
Darin Petkove4b27022012-05-16 13:28:50 +020066void WiMaxProvider::OnDeviceInfoAvailable(const string &link_name) {
67 SLOG(WiMax, 2) << __func__ << "(" << link_name << ")";
Darin Petkovfc00fd42012-05-30 11:30:06 +020068 map<string, RpcIdentifier>::const_iterator find_it =
Darin Petkovc1e52732012-05-25 15:23:45 +020069 pending_devices_.find(link_name);
Darin Petkove4b27022012-05-16 13:28:50 +020070 if (find_it != pending_devices_.end()) {
71 RpcIdentifier path = find_it->second;
72 CreateDevice(link_name, path);
73 }
74}
75
Darin Petkovc63dcf02012-05-24 11:51:43 +020076void WiMaxProvider::OnNetworksChanged() {
77 SLOG(WiMax, 2) << __func__;
Darin Petkovfc00fd42012-05-30 11:30:06 +020078 // Collects a set of live networks from all devices.
79 set<RpcIdentifier> live_networks;
80 for (map<string, WiMaxRefPtr>::const_iterator it = devices_.begin();
Darin Petkovc63dcf02012-05-24 11:51:43 +020081 it != devices_.end(); ++it) {
82 const set<RpcIdentifier> &networks = it->second->networks();
Darin Petkovfc00fd42012-05-30 11:30:06 +020083 live_networks.insert(networks.begin(), networks.end());
Darin Petkovc63dcf02012-05-24 11:51:43 +020084 }
Darin Petkovfc00fd42012-05-30 11:30:06 +020085 // Removes dead networks from |networks_|.
86 for (map<RpcIdentifier, NetworkInfo>::iterator it = networks_.begin();
87 it != networks_.end(); ) {
Darin Petkovb96a4512012-06-04 11:02:49 +020088 const RpcIdentifier &path = it->first;
89 if (ContainsKey(live_networks, path)) {
Darin Petkovfc00fd42012-05-30 11:30:06 +020090 ++it;
91 } else {
Darin Petkovb96a4512012-06-04 11:02:49 +020092 LOG(INFO) << "WiMAX network disappeared: " << path;
Darin Petkovfc00fd42012-05-30 11:30:06 +020093 networks_.erase(it++);
94 }
95 }
96 // Retrieves network info into |networks_| for the live networks.
97 for (set<RpcIdentifier>::const_iterator it = live_networks.begin();
98 it != live_networks.end(); ++it) {
99 RetrieveNetworkInfo(*it);
100 }
101 // Stops dead and starts live services based on the current |networks_|.
Darin Petkovc63dcf02012-05-24 11:51:43 +0200102 StopDeadServices();
103 StartLiveServices();
104}
105
Darin Petkovc1e52732012-05-25 15:23:45 +0200106bool WiMaxProvider::OnServiceUnloaded(const WiMaxServiceRefPtr &service) {
107 SLOG(WiMax, 2) << __func__ << "(" << service->GetStorageIdentifier() << ")";
108 if (service->is_default()) {
109 return false;
110 }
111 // Removes the service from the managed service set. The service will be
112 // deregistered from Manager when we release ownership by returning true.
113 services_.erase(service->GetStorageIdentifier());
114 return true;
115}
116
Darin Petkovd1cd7972012-05-22 15:26:15 +0200117WiMaxServiceRefPtr WiMaxProvider::GetService(const KeyValueStore &args,
118 Error *error) {
119 SLOG(WiMax, 2) << __func__;
120 CHECK_EQ(args.GetString(flimflam::kTypeProperty), flimflam::kTypeWimax);
Darin Petkovd1cd7972012-05-22 15:26:15 +0200121 WiMaxNetworkId id = args.LookupString(WiMaxService::kNetworkIdProperty, "");
122 if (id.empty()) {
123 Error::PopulateAndLog(
124 error, Error::kInvalidArguments, "Missing WiMAX network id.");
125 return NULL;
126 }
127 string name = args.LookupString(flimflam::kNameProperty, "");
128 if (name.empty()) {
129 Error::PopulateAndLog(
130 error, Error::kInvalidArguments, "Missing WiMAX service name.");
131 return NULL;
132 }
Darin Petkovc63dcf02012-05-24 11:51:43 +0200133 WiMaxServiceRefPtr service = GetUniqueService(id, name);
Darin Petkovd1cd7972012-05-22 15:26:15 +0200134 CHECK(service);
Darin Petkovfc00fd42012-05-30 11:30:06 +0200135 // Configures the service using the rest of the passed-in arguments.
Darin Petkovd1cd7972012-05-22 15:26:15 +0200136 service->Configure(args, error);
Darin Petkovfc00fd42012-05-30 11:30:06 +0200137 // Starts the service if there's a matching live network.
Darin Petkovc63dcf02012-05-24 11:51:43 +0200138 StartLiveServices();
Darin Petkovd1cd7972012-05-22 15:26:15 +0200139 return service;
140}
141
Darin Petkovc63dcf02012-05-24 11:51:43 +0200142void WiMaxProvider::CreateServicesFromProfile(const ProfileRefPtr &profile) {
143 SLOG(WiMax, 2) << __func__;
144 bool created = false;
145 const StoreInterface *storage = profile->GetConstStorage();
146 set<string> groups = storage->GetGroupsWithKey(Service::kStorageType);
Darin Petkovfc00fd42012-05-30 11:30:06 +0200147 for (set<string>::const_iterator it = groups.begin();
148 it != groups.end(); ++it) {
Darin Petkovc63dcf02012-05-24 11:51:43 +0200149 const string &storage_id = *it;
150 string type;
151 if (!storage->GetString(storage_id, Service::kStorageType, &type) ||
152 type != Technology::NameFromIdentifier(Technology::kWiMax)) {
153 continue;
154 }
155 if (FindService(storage_id)) {
156 continue;
157 }
158 WiMaxNetworkId id;
159 if (!storage->GetString(storage_id, WiMaxService::kStorageNetworkId, &id) ||
160 id.empty()) {
161 LOG(ERROR) << "Unable to load network id: " << storage_id;
162 continue;
163 }
164 string name;
165 if (!storage->GetString(storage_id, Service::kStorageName, &name) ||
166 name.empty()) {
167 LOG(ERROR) << "Unable to load service name: " << storage_id;
168 continue;
169 }
170 WiMaxServiceRefPtr service = GetUniqueService(id, name);
171 CHECK(service);
172 if (!profile->ConfigureService(service)) {
173 LOG(ERROR) << "Could not configure service: " << storage_id;
174 }
175 created = true;
176 }
177 if (created) {
178 StartLiveServices();
179 }
180}
181
182WiMaxRefPtr WiMaxProvider::SelectCarrier(const WiMaxServiceRefPtr &service) {
183 SLOG(WiMax, 2) << __func__ << "(" << service->GetStorageIdentifier() << ")";
184 if (devices_.empty()) {
185 LOG(ERROR) << "No WiMAX devices available.";
186 return NULL;
187 }
188 // TODO(petkov): For now, just return the first available device. We need to
189 // be smarter here and select a device that sees |service|'s network.
190 return devices_.begin()->second;
191}
192
193void WiMaxProvider::OnDevicesChanged(const RpcIdentifiers &devices) {
194 SLOG(WiMax, 2) << __func__;
195 DestroyDeadDevices(devices);
196 for (RpcIdentifiers::const_iterator it = devices.begin();
197 it != devices.end(); ++it) {
198 const RpcIdentifier &path = *it;
199 string link_name = GetLinkName(path);
200 if (!link_name.empty()) {
201 CreateDevice(link_name, path);
202 }
203 }
204}
205
Darin Petkove4b27022012-05-16 13:28:50 +0200206void WiMaxProvider::CreateDevice(const string &link_name,
207 const RpcIdentifier &path) {
208 SLOG(WiMax, 2) << __func__ << "(" << link_name << ", " << path << ")";
Darin Petkov0fcd3462012-05-17 11:25:11 +0200209 if (ContainsKey(devices_, link_name)) {
210 SLOG(WiMax, 2) << "Device already exists.";
211 CHECK_EQ(path, devices_[link_name]->path());
212 return;
213 }
Darin Petkove4b27022012-05-16 13:28:50 +0200214 pending_devices_.erase(link_name);
215 DeviceInfo *device_info = manager_->device_info();
216 if (device_info->IsDeviceBlackListed(link_name)) {
Darin Petkovc63dcf02012-05-24 11:51:43 +0200217 LOG(INFO) << "WiMAX device not created, interface blacklisted: "
Darin Petkove4b27022012-05-16 13:28:50 +0200218 << link_name;
219 return;
220 }
221 int index = device_info->GetIndex(link_name);
222 if (index < 0) {
223 SLOG(WiMax, 2) << link_name << " pending device info.";
224 // Adds the link to the pending device map, waiting for a notification from
225 // DeviceInfo that it's received information about the device from RTNL.
226 pending_devices_[link_name] = path;
227 return;
228 }
229 ByteString address_bytes;
230 if (!device_info->GetMACAddress(index, &address_bytes)) {
Darin Petkovc63dcf02012-05-24 11:51:43 +0200231 LOG(ERROR) << "Unable to create a WiMAX device with no MAC address: "
Darin Petkove4b27022012-05-16 13:28:50 +0200232 << link_name;
233 return;
234 }
235 string address = address_bytes.HexEncode();
236 WiMaxRefPtr device(new WiMax(control_, dispatcher_, metrics_, manager_,
237 link_name, address, index, path));
Darin Petkov0fcd3462012-05-17 11:25:11 +0200238 devices_[link_name] = device;
Darin Petkove4b27022012-05-16 13:28:50 +0200239 device_info->RegisterDevice(device);
Darin Petkovc63dcf02012-05-24 11:51:43 +0200240 LOG(INFO) << "Created WiMAX device: " << link_name << " @ " << path;
Darin Petkove4b27022012-05-16 13:28:50 +0200241}
242
243void WiMaxProvider::DestroyDeadDevices(const RpcIdentifiers &live_devices) {
244 SLOG(WiMax, 2) << __func__ << "(" << live_devices.size() << ")";
Darin Petkovc1e52732012-05-25 15:23:45 +0200245 for (map<string, RpcIdentifier>::iterator it = pending_devices_.begin();
Darin Petkove4b27022012-05-16 13:28:50 +0200246 it != pending_devices_.end(); ) {
247 if (find(live_devices.begin(), live_devices.end(), it->second) ==
248 live_devices.end()) {
Darin Petkovc63dcf02012-05-24 11:51:43 +0200249 LOG(INFO) << "Forgetting pending device: " << it->second;
Darin Petkove4b27022012-05-16 13:28:50 +0200250 pending_devices_.erase(it++);
251 } else {
252 ++it;
253 }
254 }
Darin Petkov0fcd3462012-05-17 11:25:11 +0200255 for (map<string, WiMaxRefPtr>::iterator it = devices_.begin();
Darin Petkove4b27022012-05-16 13:28:50 +0200256 it != devices_.end(); ) {
Darin Petkov0fcd3462012-05-17 11:25:11 +0200257 if (find(live_devices.begin(), live_devices.end(), it->second->path()) ==
Darin Petkove4b27022012-05-16 13:28:50 +0200258 live_devices.end()) {
Darin Petkovc63dcf02012-05-24 11:51:43 +0200259 LOG(INFO) << "Destroying device: " << it->first;
Darin Petkovb96a4512012-06-04 11:02:49 +0200260 const WiMaxRefPtr &device = it->second;
261 device->OnDeviceVanished();
262 manager_->device_info()->DeregisterDevice(device);
Darin Petkov0fcd3462012-05-17 11:25:11 +0200263 devices_.erase(it++);
Darin Petkove4b27022012-05-16 13:28:50 +0200264 } else {
265 ++it;
266 }
267 }
268}
269
270string WiMaxProvider::GetLinkName(const RpcIdentifier &path) {
Darin Petkov9893d9c2012-05-17 15:27:31 -0700271 if (StartsWithASCII(path, wimax_manager::kDeviceObjectPathPrefix, true)) {
272 return path.substr(strlen(wimax_manager::kDeviceObjectPathPrefix));
Darin Petkove4b27022012-05-16 13:28:50 +0200273 }
274 LOG(ERROR) << "Unable to determine link name from RPC path: " << path;
275 return string();
Darin Petkovb72b62e2012-05-15 16:55:36 +0200276}
277
Darin Petkovfc00fd42012-05-30 11:30:06 +0200278void WiMaxProvider::RetrieveNetworkInfo(const RpcIdentifier &path) {
279 if (ContainsKey(networks_, path)) {
280 // Nothing to do, the network info is already available.
281 return;
282 }
Darin Petkovb96a4512012-06-04 11:02:49 +0200283 LOG(INFO) << "WiMAX network appeared: " << path;
Darin Petkovfc00fd42012-05-30 11:30:06 +0200284 scoped_ptr<WiMaxNetworkProxyInterface> proxy(
285 proxy_factory_->CreateWiMaxNetworkProxy(path));
286 Error error;
287 NetworkInfo info;
288 info.name = proxy->Name(&error);
289 if (error.IsFailure()) {
290 return;
291 }
292 uint32 identifier = proxy->Identifier(&error);
293 if (error.IsFailure()) {
294 return;
295 }
296 info.id = WiMaxService::ConvertIdentifierToNetworkId(identifier);
297 networks_[path] = info;
298}
299
Darin Petkovc63dcf02012-05-24 11:51:43 +0200300WiMaxServiceRefPtr WiMaxProvider::FindService(const string &storage_id) {
301 SLOG(WiMax, 2) << __func__ << "(" << storage_id << ")";
Darin Petkovc1e52732012-05-25 15:23:45 +0200302 map<string, WiMaxServiceRefPtr>::const_iterator find_it =
303 services_.find(storage_id);
304 if (find_it == services_.end()) {
305 return NULL;
Darin Petkovc63dcf02012-05-24 11:51:43 +0200306 }
Darin Petkovc1e52732012-05-25 15:23:45 +0200307 const WiMaxServiceRefPtr &service = find_it->second;
308 LOG_IF(ERROR, storage_id != service->GetStorageIdentifier());
309 return service;
Darin Petkovc63dcf02012-05-24 11:51:43 +0200310}
311
312WiMaxServiceRefPtr WiMaxProvider::GetUniqueService(const WiMaxNetworkId &id,
313 const string &name) {
314 SLOG(WiMax, 2) << __func__ << "(" << id << ", " << name << ")";
315 string storage_id = WiMaxService::CreateStorageIdentifier(id, name);
316 WiMaxServiceRefPtr service = FindService(storage_id);
317 if (service) {
318 SLOG(WiMax, 2) << "Service already exists.";
319 return service;
320 }
321 service = new WiMaxService(control_, dispatcher_, metrics_, manager_);
322 service->set_network_id(id);
323 service->set_friendly_name(name);
324 service->InitStorageIdentifier();
Darin Petkovc1e52732012-05-25 15:23:45 +0200325 services_[service->GetStorageIdentifier()] = service;
Darin Petkovc63dcf02012-05-24 11:51:43 +0200326 manager_->RegisterService(service);
327 LOG(INFO) << "Registered WiMAX service: " << service->GetStorageIdentifier();
328 return service;
329}
330
Darin Petkovc63dcf02012-05-24 11:51:43 +0200331void WiMaxProvider::StartLiveServices() {
Darin Petkovfc00fd42012-05-30 11:30:06 +0200332 SLOG(WiMax, 2) << __func__ << "(" << networks_.size() << ")";
333 for (map<RpcIdentifier, NetworkInfo>::const_iterator nit = networks_.begin();
334 nit != networks_.end(); ++nit) {
335 const RpcIdentifier &path = nit->first;
336 const NetworkInfo &info = nit->second;
Darin Petkovc63dcf02012-05-24 11:51:43 +0200337
Darin Petkovfc00fd42012-05-30 11:30:06 +0200338 // Creates the default service for the network, if not already created.
339 GetUniqueService(info.id, info.name)->set_is_default(true);
340
341 // Starts services for this live network.
342 for (map<string, WiMaxServiceRefPtr>::const_iterator it = services_.begin();
343 it != services_.end(); ++it) {
344 const WiMaxServiceRefPtr &service = it->second;
345 if (service->network_id() != info.id || service->IsStarted()) {
346 continue;
347 }
348 if (!service->Start(proxy_factory_->CreateWiMaxNetworkProxy(path))) {
349 LOG(ERROR) << "Unable to start service: "
350 << service->GetStorageIdentifier();
351 }
Darin Petkovc63dcf02012-05-24 11:51:43 +0200352 }
353 }
354}
355
356void WiMaxProvider::StopDeadServices() {
357 SLOG(WiMax, 2) << __func__ << "(" << networks_.size() << ")";
Darin Petkovc1e52732012-05-25 15:23:45 +0200358 for (map<string, WiMaxServiceRefPtr>::iterator it = services_.begin();
359 it != services_.end(); ) {
360 const WiMaxServiceRefPtr &service = it->second;
361 if (service->IsStarted() &&
362 !ContainsKey(networks_, service->GetNetworkObjectPath())) {
363 service->Stop();
364 // Default services are created and registered when a network becomes
365 // live. They need to be deregistered and destroyed when the network
366 // disappears.
367 if (service->is_default()) {
368 manager_->DeregisterService(service);
369 services_.erase(it++);
370 continue;
371 }
Darin Petkovc63dcf02012-05-24 11:51:43 +0200372 }
Darin Petkovc1e52732012-05-25 15:23:45 +0200373 ++it;
Darin Petkovc63dcf02012-05-24 11:51:43 +0200374 }
375}
376
377void WiMaxProvider::DestroyAllServices() {
378 SLOG(WiMax, 2) << __func__;
Darin Petkovc1e52732012-05-25 15:23:45 +0200379 for (map<string, WiMaxServiceRefPtr>::iterator it = services_.begin();
380 it != services_.end(); services_.erase(it++)) {
381 const WiMaxServiceRefPtr &service = it->second;
Darin Petkovc63dcf02012-05-24 11:51:43 +0200382 // Stop the service so that it can notify its carrier device, if any.
383 service->Stop();
384 manager_->DeregisterService(service);
385 LOG(INFO) << "Deregistered WiMAX service: "
386 << service->GetStorageIdentifier();
Darin Petkovc63dcf02012-05-24 11:51:43 +0200387 }
388}
389
Darin Petkovb72b62e2012-05-15 16:55:36 +0200390} // namespace shill