blob: 1091e74dd565d87991d66e7648432e6d9bc7a088 [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;
30using std::vector;
31
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 << ")";
68 map<string, string>::iterator find_it = pending_devices_.find(link_name);
69 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 Petkovd1cd7972012-05-22 15:26:15 +020090WiMaxServiceRefPtr WiMaxProvider::GetService(const KeyValueStore &args,
91 Error *error) {
92 SLOG(WiMax, 2) << __func__;
93 CHECK_EQ(args.GetString(flimflam::kTypeProperty), flimflam::kTypeWimax);
Darin Petkovd1cd7972012-05-22 15:26:15 +020094 WiMaxNetworkId id = args.LookupString(WiMaxService::kNetworkIdProperty, "");
95 if (id.empty()) {
96 Error::PopulateAndLog(
97 error, Error::kInvalidArguments, "Missing WiMAX network id.");
98 return NULL;
99 }
100 string name = args.LookupString(flimflam::kNameProperty, "");
101 if (name.empty()) {
102 Error::PopulateAndLog(
103 error, Error::kInvalidArguments, "Missing WiMAX service name.");
104 return NULL;
105 }
Darin Petkovc63dcf02012-05-24 11:51:43 +0200106 WiMaxServiceRefPtr service = GetUniqueService(id, name);
Darin Petkovd1cd7972012-05-22 15:26:15 +0200107 CHECK(service);
108 // Configure the service using the the rest of the passed-in arguments.
109 service->Configure(args, error);
110 // Start the service if there's a matching live network.
Darin Petkovc63dcf02012-05-24 11:51:43 +0200111 StartLiveServices();
Darin Petkovd1cd7972012-05-22 15:26:15 +0200112 return service;
113}
114
Darin Petkovc63dcf02012-05-24 11:51:43 +0200115void WiMaxProvider::CreateServicesFromProfile(const ProfileRefPtr &profile) {
116 SLOG(WiMax, 2) << __func__;
117 bool created = false;
118 const StoreInterface *storage = profile->GetConstStorage();
119 set<string> groups = storage->GetGroupsWithKey(Service::kStorageType);
120 for (set<string>::iterator it = groups.begin(); it != groups.end(); ++it) {
121 const string &storage_id = *it;
122 string type;
123 if (!storage->GetString(storage_id, Service::kStorageType, &type) ||
124 type != Technology::NameFromIdentifier(Technology::kWiMax)) {
125 continue;
126 }
127 if (FindService(storage_id)) {
128 continue;
129 }
130 WiMaxNetworkId id;
131 if (!storage->GetString(storage_id, WiMaxService::kStorageNetworkId, &id) ||
132 id.empty()) {
133 LOG(ERROR) << "Unable to load network id: " << storage_id;
134 continue;
135 }
136 string name;
137 if (!storage->GetString(storage_id, Service::kStorageName, &name) ||
138 name.empty()) {
139 LOG(ERROR) << "Unable to load service name: " << storage_id;
140 continue;
141 }
142 WiMaxServiceRefPtr service = GetUniqueService(id, name);
143 CHECK(service);
144 if (!profile->ConfigureService(service)) {
145 LOG(ERROR) << "Could not configure service: " << storage_id;
146 }
147 created = true;
148 }
149 if (created) {
150 StartLiveServices();
151 }
152}
153
154WiMaxRefPtr WiMaxProvider::SelectCarrier(const WiMaxServiceRefPtr &service) {
155 SLOG(WiMax, 2) << __func__ << "(" << service->GetStorageIdentifier() << ")";
156 if (devices_.empty()) {
157 LOG(ERROR) << "No WiMAX devices available.";
158 return NULL;
159 }
160 // TODO(petkov): For now, just return the first available device. We need to
161 // be smarter here and select a device that sees |service|'s network.
162 return devices_.begin()->second;
163}
164
165void WiMaxProvider::OnDevicesChanged(const RpcIdentifiers &devices) {
166 SLOG(WiMax, 2) << __func__;
167 DestroyDeadDevices(devices);
168 for (RpcIdentifiers::const_iterator it = devices.begin();
169 it != devices.end(); ++it) {
170 const RpcIdentifier &path = *it;
171 string link_name = GetLinkName(path);
172 if (!link_name.empty()) {
173 CreateDevice(link_name, path);
174 }
175 }
176}
177
Darin Petkove4b27022012-05-16 13:28:50 +0200178void WiMaxProvider::CreateDevice(const string &link_name,
179 const RpcIdentifier &path) {
180 SLOG(WiMax, 2) << __func__ << "(" << link_name << ", " << path << ")";
Darin Petkov0fcd3462012-05-17 11:25:11 +0200181 if (ContainsKey(devices_, link_name)) {
182 SLOG(WiMax, 2) << "Device already exists.";
183 CHECK_EQ(path, devices_[link_name]->path());
184 return;
185 }
Darin Petkove4b27022012-05-16 13:28:50 +0200186 pending_devices_.erase(link_name);
187 DeviceInfo *device_info = manager_->device_info();
188 if (device_info->IsDeviceBlackListed(link_name)) {
Darin Petkovc63dcf02012-05-24 11:51:43 +0200189 LOG(INFO) << "WiMAX device not created, interface blacklisted: "
Darin Petkove4b27022012-05-16 13:28:50 +0200190 << link_name;
191 return;
192 }
193 int index = device_info->GetIndex(link_name);
194 if (index < 0) {
195 SLOG(WiMax, 2) << link_name << " pending device info.";
196 // Adds the link to the pending device map, waiting for a notification from
197 // DeviceInfo that it's received information about the device from RTNL.
198 pending_devices_[link_name] = path;
199 return;
200 }
201 ByteString address_bytes;
202 if (!device_info->GetMACAddress(index, &address_bytes)) {
Darin Petkovc63dcf02012-05-24 11:51:43 +0200203 LOG(ERROR) << "Unable to create a WiMAX device with no MAC address: "
Darin Petkove4b27022012-05-16 13:28:50 +0200204 << link_name;
205 return;
206 }
207 string address = address_bytes.HexEncode();
208 WiMaxRefPtr device(new WiMax(control_, dispatcher_, metrics_, manager_,
209 link_name, address, index, path));
Darin Petkov0fcd3462012-05-17 11:25:11 +0200210 devices_[link_name] = device;
Darin Petkove4b27022012-05-16 13:28:50 +0200211 device_info->RegisterDevice(device);
Darin Petkovc63dcf02012-05-24 11:51:43 +0200212 LOG(INFO) << "Created WiMAX device: " << link_name << " @ " << path;
Darin Petkove4b27022012-05-16 13:28:50 +0200213}
214
215void WiMaxProvider::DestroyDeadDevices(const RpcIdentifiers &live_devices) {
216 SLOG(WiMax, 2) << __func__ << "(" << live_devices.size() << ")";
217 for (map<string, string>::iterator it = pending_devices_.begin();
218 it != pending_devices_.end(); ) {
219 if (find(live_devices.begin(), live_devices.end(), it->second) ==
220 live_devices.end()) {
Darin Petkovc63dcf02012-05-24 11:51:43 +0200221 LOG(INFO) << "Forgetting pending device: " << it->second;
Darin Petkove4b27022012-05-16 13:28:50 +0200222 pending_devices_.erase(it++);
223 } else {
224 ++it;
225 }
226 }
Darin Petkov0fcd3462012-05-17 11:25:11 +0200227 for (map<string, WiMaxRefPtr>::iterator it = devices_.begin();
Darin Petkove4b27022012-05-16 13:28:50 +0200228 it != devices_.end(); ) {
Darin Petkov0fcd3462012-05-17 11:25:11 +0200229 if (find(live_devices.begin(), live_devices.end(), it->second->path()) ==
Darin Petkove4b27022012-05-16 13:28:50 +0200230 live_devices.end()) {
Darin Petkovc63dcf02012-05-24 11:51:43 +0200231 LOG(INFO) << "Destroying device: " << it->first;
Darin Petkov0fcd3462012-05-17 11:25:11 +0200232 manager_->device_info()->DeregisterDevice(it->second);
233 devices_.erase(it++);
Darin Petkove4b27022012-05-16 13:28:50 +0200234 } else {
235 ++it;
236 }
237 }
238}
239
240string WiMaxProvider::GetLinkName(const RpcIdentifier &path) {
Darin Petkov9893d9c2012-05-17 15:27:31 -0700241 if (StartsWithASCII(path, wimax_manager::kDeviceObjectPathPrefix, true)) {
242 return path.substr(strlen(wimax_manager::kDeviceObjectPathPrefix));
Darin Petkove4b27022012-05-16 13:28:50 +0200243 }
244 LOG(ERROR) << "Unable to determine link name from RPC path: " << path;
245 return string();
Darin Petkovb72b62e2012-05-15 16:55:36 +0200246}
247
Darin Petkovc63dcf02012-05-24 11:51:43 +0200248WiMaxServiceRefPtr WiMaxProvider::FindService(const string &storage_id) {
249 SLOG(WiMax, 2) << __func__ << "(" << storage_id << ")";
250 for (vector<WiMaxServiceRefPtr>::const_iterator it = services_.begin();
251 it != services_.end(); ++it) {
252 if ((*it)->GetStorageIdentifier() == storage_id) {
253 return *it;
254 }
255 }
256 return NULL;
257}
258
259WiMaxServiceRefPtr WiMaxProvider::GetUniqueService(const WiMaxNetworkId &id,
260 const string &name) {
261 SLOG(WiMax, 2) << __func__ << "(" << id << ", " << name << ")";
262 string storage_id = WiMaxService::CreateStorageIdentifier(id, name);
263 WiMaxServiceRefPtr service = FindService(storage_id);
264 if (service) {
265 SLOG(WiMax, 2) << "Service already exists.";
266 return service;
267 }
268 service = new WiMaxService(control_, dispatcher_, metrics_, manager_);
269 service->set_network_id(id);
270 service->set_friendly_name(name);
271 service->InitStorageIdentifier();
272 services_.push_back(service);
273 manager_->RegisterService(service);
274 LOG(INFO) << "Registered WiMAX service: " << service->GetStorageIdentifier();
275 return service;
276}
277
278WiMaxServiceRefPtr WiMaxProvider::GetDefaultService(
279 const RpcIdentifier &network) {
280 SLOG(WiMax, 2) << __func__ << "(" << network << ")";
281 scoped_ptr<WiMaxNetworkProxyInterface> proxy(
282 proxy_factory_->CreateWiMaxNetworkProxy(network));
283 Error error;
284 uint32 identifier = proxy->Identifier(&error);
285 if (error.IsFailure()) {
286 return NULL;
287 }
288 string name = proxy->Name(&error);
289 if (error.IsFailure()) {
290 return NULL;
291 }
292 return GetUniqueService(
293 WiMaxService::ConvertIdentifierToNetworkId(identifier), name);
294}
295
296void WiMaxProvider::StartLiveServices() {
297 for (set<RpcIdentifier>::const_iterator it = networks_.begin();
298 it != networks_.end(); ++it) {
299 StartLiveServicesForNetwork(*it);
300 }
301}
302
303void WiMaxProvider::StartLiveServicesForNetwork(const RpcIdentifier &network) {
304 SLOG(WiMax, 2) << __func__ << "(" << network << ")";
305 WiMaxServiceRefPtr default_service = GetDefaultService(network);
306 if (!default_service) {
307 return;
308 }
309 // Start services for this live network identifier.
310 for (vector<WiMaxServiceRefPtr>::iterator it = services_.begin();
311 it != services_.end(); ++it) {
312 const WiMaxServiceRefPtr &service = *it;
313 if (service->network_id() != default_service->network_id() ||
314 service->IsStarted()) {
315 continue;
316 }
317 if (!service->Start(proxy_factory_->CreateWiMaxNetworkProxy(network))) {
318 LOG(ERROR) << "Unable to start service: "
319 << service->GetStorageIdentifier();
320 }
321 }
322}
323
324void WiMaxProvider::StopDeadServices() {
325 SLOG(WiMax, 2) << __func__ << "(" << networks_.size() << ")";
326 for (vector<WiMaxServiceRefPtr>::iterator it = services_.begin();
327 it != services_.end(); ++it) {
328 const WiMaxServiceRefPtr &service = *it;
329 if (!service->IsStarted() ||
330 ContainsKey(networks_, service->GetNetworkObjectPath())) {
331 continue;
332 }
333 service->Stop();
334 }
335}
336
337void WiMaxProvider::DestroyAllServices() {
338 SLOG(WiMax, 2) << __func__;
339 while (!services_.empty()) {
340 const WiMaxServiceRefPtr &service = services_.back();
341 // Stop the service so that it can notify its carrier device, if any.
342 service->Stop();
343 manager_->DeregisterService(service);
344 LOG(INFO) << "Deregistered WiMAX service: "
345 << service->GetStorageIdentifier();
346 services_.pop_back();
347 }
348}
349
Darin Petkovb72b62e2012-05-15 16:55:36 +0200350} // namespace shill