blob: 5c07c966eeabad4b4cdba2971fbd2f5031808b41 [file] [log] [blame]
Ben Chan99c8a4d2012-05-01 08:11:53 -07001// 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.h"
6
Darin Petkov912f0de2012-05-16 14:12:14 +02007#include <base/bind.h>
Darin Petkovd1cd7972012-05-22 15:26:15 +02008#include <base/string_util.h>
Darin Petkov9893d9c2012-05-17 15:27:31 -07009#include <base/stringprintf.h>
Darin Petkov912f0de2012-05-16 14:12:14 +020010
Darin Petkov25665aa2012-05-21 14:08:12 +020011#include "shill/key_value_store.h"
Darin Petkov912f0de2012-05-16 14:12:14 +020012#include "shill/manager.h"
Darin Petkovb72b62e2012-05-15 16:55:36 +020013#include "shill/proxy_factory.h"
14#include "shill/scope_logger.h"
Darin Petkovd1cd7972012-05-22 15:26:15 +020015#include "shill/store_interface.h"
Darin Petkovb72b62e2012-05-15 16:55:36 +020016#include "shill/wimax_device_proxy_interface.h"
Darin Petkov912f0de2012-05-16 14:12:14 +020017#include "shill/wimax_service.h"
Darin Petkovb72b62e2012-05-15 16:55:36 +020018
Darin Petkov912f0de2012-05-16 14:12:14 +020019using base::Bind;
Darin Petkovd1cd7972012-05-22 15:26:15 +020020using std::set;
Ben Chan99c8a4d2012-05-01 08:11:53 -070021using std::string;
Darin Petkovd1cd7972012-05-22 15:26:15 +020022using std::vector;
Ben Chan99c8a4d2012-05-01 08:11:53 -070023
24namespace shill {
25
Darin Petkov912f0de2012-05-16 14:12:14 +020026const int WiMax::kTimeoutDefault = 30000;
27
Ben Chan99c8a4d2012-05-01 08:11:53 -070028WiMax::WiMax(ControlInterface *control,
29 EventDispatcher *dispatcher,
30 Metrics *metrics,
31 Manager *manager,
32 const string &link_name,
Ben Chan4e64d2d2012-05-16 00:02:25 -070033 const string &address,
Darin Petkovb72b62e2012-05-15 16:55:36 +020034 int interface_index,
35 const RpcIdentifier &path)
Ben Chan4e64d2d2012-05-16 00:02:25 -070036 : Device(control, dispatcher, metrics, manager, link_name, address,
Darin Petkovb72b62e2012-05-15 16:55:36 +020037 interface_index, Technology::kWiMax),
38 path_(path),
Darin Petkov9893d9c2012-05-17 15:27:31 -070039 scanning_(false),
Darin Petkovb72b62e2012-05-15 16:55:36 +020040 proxy_factory_(ProxyFactory::GetInstance()) {
41 SLOG(WiMax, 2) << __func__ << "(" << link_name << ", " << path << ")";
Darin Petkov9893d9c2012-05-17 15:27:31 -070042 PropertyStore *store = mutable_store();
43 store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
Darin Petkovb72b62e2012-05-15 16:55:36 +020044}
Ben Chan99c8a4d2012-05-01 08:11:53 -070045
Darin Petkovb72b62e2012-05-15 16:55:36 +020046WiMax::~WiMax() {
47 SLOG(WiMax, 2) << __func__ << "(" << link_name() << ", " << path_ << ")";
48}
Ben Chan99c8a4d2012-05-01 08:11:53 -070049
50void WiMax::Start(Error *error, const EnabledStateChangedCallback &callback) {
Darin Petkovb72b62e2012-05-15 16:55:36 +020051 SLOG(WiMax, 2) << __func__;
Darin Petkov9893d9c2012-05-17 15:27:31 -070052 scanning_ = false;
Darin Petkovb72b62e2012-05-15 16:55:36 +020053 proxy_.reset(proxy_factory_->CreateWiMaxDeviceProxy(path_));
Darin Petkov9893d9c2012-05-17 15:27:31 -070054 proxy_->set_networks_changed_callback(
55 Bind(&WiMax::OnNetworksChanged, Unretained(this)));
Darin Petkov912f0de2012-05-16 14:12:14 +020056 proxy_->Enable(
57 error, Bind(&WiMax::OnEnableComplete, this, callback), kTimeoutDefault);
Ben Chan99c8a4d2012-05-01 08:11:53 -070058}
59
60void WiMax::Stop(Error *error, const EnabledStateChangedCallback &callback) {
Darin Petkovb72b62e2012-05-15 16:55:36 +020061 SLOG(WiMax, 2) << __func__;
Darin Petkovd1cd7972012-05-22 15:26:15 +020062 networks_.clear();
63 StopDeadServices();
64 DestroyAllServices();
65 services_.clear();
Darin Petkov912f0de2012-05-16 14:12:14 +020066 proxy_->Disable(
67 error, Bind(&WiMax::OnDisableComplete, this, callback), kTimeoutDefault);
Ben Chan99c8a4d2012-05-01 08:11:53 -070068}
69
70bool WiMax::TechnologyIs(const Technology::Identifier type) const {
71 return type == Technology::kWiMax;
72}
73
Darin Petkov9893d9c2012-05-17 15:27:31 -070074void WiMax::Scan(Error *error) {
Darin Petkov912f0de2012-05-16 14:12:14 +020075 SLOG(WiMax, 2) << __func__;
Darin Petkov9893d9c2012-05-17 15:27:31 -070076 if (scanning_) {
77 Error::PopulateAndLog(
78 error, Error::kInProgress, "Scan already in progress.");
79 return;
80 }
81 scanning_ = true;
82 proxy_->ScanNetworks(
83 error, Bind(&WiMax::OnScanNetworksComplete, this), kTimeoutDefault);
84 if (error->IsFailure()) {
85 OnScanNetworksComplete(*error);
86 }
Ben Chan99c8a4d2012-05-01 08:11:53 -070087}
88
Darin Petkov9893d9c2012-05-17 15:27:31 -070089void WiMax::ConnectTo(const WiMaxServiceRefPtr &service, Error *error) {
90 SLOG(WiMax, 2) << __func__ << "(" << service->friendly_name() << ")";
91 if (pending_service_) {
92 Error::PopulateAndLog(
93 error, Error::kInProgress,
94 base::StringPrintf(
95 "Pending connect to %s, ignoring connect request to %s.",
96 pending_service_->friendly_name().c_str(),
97 service->friendly_name().c_str()));
98 return;
99 }
100 service->SetState(Service::kStateAssociating);
101 pending_service_ = service;
Ben Chan4e5c1312012-05-18 18:45:38 -0700102
Darin Petkov25665aa2012-05-21 14:08:12 +0200103 KeyValueStore parameters;
Ben Chan4e5c1312012-05-18 18:45:38 -0700104 service->GetConnectParameters(&parameters);
Darin Petkov9893d9c2012-05-17 15:27:31 -0700105 proxy_->Connect(
Ben Chan4e5c1312012-05-18 18:45:38 -0700106 service->GetNetworkObjectPath(), parameters,
Darin Petkov9893d9c2012-05-17 15:27:31 -0700107 error, Bind(&WiMax::OnConnectComplete, this), kTimeoutDefault);
108 if (error->IsFailure()) {
109 OnConnectComplete(*error);
110 }
111}
112
113void WiMax::DisconnectFrom(const WiMaxServiceRefPtr &service, Error *error) {
Darin Petkov912f0de2012-05-16 14:12:14 +0200114 SLOG(WiMax, 2) << __func__;
Darin Petkov9893d9c2012-05-17 15:27:31 -0700115 if (pending_service_) {
116 Error::PopulateAndLog(
117 error, Error::kInProgress,
118 base::StringPrintf(
119 "Pending connect to %s, ignoring disconnect request from %s.",
120 pending_service_->friendly_name().c_str(),
121 service->friendly_name().c_str()));
122 return;
123 }
124 if (selected_service() && service != selected_service()) {
125 Error::PopulateAndLog(
126 error, Error::kNotConnected,
127 base::StringPrintf(
128 "Curent service is %s, ignoring disconnect request from %s.",
129 selected_service()->friendly_name().c_str(),
130 service->friendly_name().c_str()));
131 return;
132 }
Darin Petkov912f0de2012-05-16 14:12:14 +0200133 proxy_->Disconnect(
134 error, Bind(&WiMax::OnDisconnectComplete, this), kTimeoutDefault);
Darin Petkov9893d9c2012-05-17 15:27:31 -0700135 if (error->IsFailure()) {
136 OnDisconnectComplete(Error());
137 }
138}
139
140void WiMax::OnScanNetworksComplete(const Error &/*error*/) {
141 SLOG(WiMax, 2) << __func__;
142 scanning_ = false;
143 // The networks are updated when the NetworksChanged signal is received.
Darin Petkov912f0de2012-05-16 14:12:14 +0200144}
145
146void WiMax::OnConnectComplete(const Error &error) {
147 SLOG(WiMax, 2) << __func__;
Darin Petkov9893d9c2012-05-17 15:27:31 -0700148 if (!pending_service_) {
149 LOG(ERROR) << "Unexpected OnConnectComplete callback.";
150 return;
151 }
Darin Petkov126d5862012-05-17 14:39:11 +0200152 if (error.IsSuccess() && AcquireIPConfig()) {
Darin Petkov9893d9c2012-05-17 15:27:31 -0700153 LOG(INFO) << "Connected to " << pending_service_->friendly_name();
154 SelectService(pending_service_);
Darin Petkov126d5862012-05-17 14:39:11 +0200155 SetServiceState(Service::kStateConfiguring);
156 } else {
Darin Petkov9893d9c2012-05-17 15:27:31 -0700157 LOG(ERROR) << "Unable to connect to " << pending_service_->friendly_name();
158 pending_service_->SetState(Service::kStateFailure);
Darin Petkov912f0de2012-05-16 14:12:14 +0200159 }
Darin Petkov9893d9c2012-05-17 15:27:31 -0700160 pending_service_ = NULL;
Darin Petkov912f0de2012-05-16 14:12:14 +0200161}
162
Darin Petkov9893d9c2012-05-17 15:27:31 -0700163void WiMax::OnDisconnectComplete(const Error &/*error*/) {
Darin Petkov912f0de2012-05-16 14:12:14 +0200164 SLOG(WiMax, 2) << __func__;
Darin Petkov126d5862012-05-17 14:39:11 +0200165 DestroyIPConfig();
Darin Petkov912f0de2012-05-16 14:12:14 +0200166 SelectService(NULL);
167}
168
169void WiMax::OnEnableComplete(const EnabledStateChangedCallback &callback,
170 const Error &error) {
171 SLOG(WiMax, 2) << __func__;
172 if (error.IsFailure()) {
173 proxy_.reset();
174 } else {
Darin Petkov9893d9c2012-05-17 15:27:31 -0700175 // Scan for networks to allow service creation when the network list becomes
176 // available.
177 Error e;
178 Scan(&e);
Darin Petkov912f0de2012-05-16 14:12:14 +0200179 }
180 callback.Run(error);
Darin Petkov912f0de2012-05-16 14:12:14 +0200181}
182
183void WiMax::OnDisableComplete(const EnabledStateChangedCallback &callback,
184 const Error &error) {
185 SLOG(WiMax, 2) << __func__;
Darin Petkov9893d9c2012-05-17 15:27:31 -0700186 proxy_.reset();
Darin Petkov912f0de2012-05-16 14:12:14 +0200187 callback.Run(error);
Ben Chan99c8a4d2012-05-01 08:11:53 -0700188}
189
Darin Petkov9893d9c2012-05-17 15:27:31 -0700190void WiMax::OnNetworksChanged(const RpcIdentifiers &networks) {
191 SLOG(WiMax, 2) << __func__;
Darin Petkovd1cd7972012-05-22 15:26:15 +0200192 networks_ = networks;
193 StopDeadServices();
194 StartLiveServices();
195}
196
197void WiMax::StartLiveServices() {
198 for (RpcIdentifiers::const_iterator it = networks_.begin();
199 it != networks_.end(); ++it) {
200 StartLiveServicesForNetwork(*it);
Darin Petkov9893d9c2012-05-17 15:27:31 -0700201 }
202}
203
Darin Petkovd1cd7972012-05-22 15:26:15 +0200204void WiMax::StartLiveServicesForNetwork(const RpcIdentifier &network) {
Darin Petkov9893d9c2012-05-17 15:27:31 -0700205 SLOG(WiMax, 2) << __func__ << "(" << network << ")";
Darin Petkovd1cd7972012-05-22 15:26:15 +0200206 WiMaxServiceRefPtr default_service = GetDefaultService(network);
207 if (!default_service) {
Darin Petkov9893d9c2012-05-17 15:27:31 -0700208 return;
209 }
Darin Petkovd1cd7972012-05-22 15:26:15 +0200210 // Start services for this live network identifier.
211 for (vector<WiMaxServiceRefPtr>::iterator it = services_.begin();
212 it != services_.end(); ++it) {
213 WiMaxServiceRefPtr service = *it;
214 if (service->network_id() != default_service->network_id()) {
215 continue;
216 }
217 if (service->IsStarted()) {
218 continue;
219 }
220 if (service->Start(proxy_factory_->CreateWiMaxNetworkProxy(network))) {
221 LOG(INFO) << "WiMAX service started: "
222 << service->GetStorageIdentifier();
223 } else {
224 LOG(ERROR) << "Unable to start service: "
225 << service->GetStorageIdentifier();
226 }
Darin Petkov9893d9c2012-05-17 15:27:31 -0700227 }
228}
229
Darin Petkovd1cd7972012-05-22 15:26:15 +0200230void WiMax::StopDeadServices() {
231 SLOG(WiMax, 2) << __func__ << "(" << networks_.size() << ")";
232 for (vector<WiMaxServiceRefPtr>::iterator it = services_.begin();
233 it != services_.end(); ++it) {
234 WiMaxServiceRefPtr service = *it;
235 if (!service->IsStarted()) {
236 continue;
237 }
238 if (find(networks_.begin(), networks_.end(),
239 service->GetNetworkObjectPath()) == networks_.end()) {
240 LOG(INFO) << "Stopping WiMAX service: "
241 << service->GetStorageIdentifier();
Darin Petkov9893d9c2012-05-17 15:27:31 -0700242 if (service == selected_service()) {
243 DestroyIPConfig();
244 SelectService(NULL);
245 }
246 if (pending_service_ == service) {
247 pending_service_ = NULL;
248 }
Darin Petkovd1cd7972012-05-22 15:26:15 +0200249 service->Stop();
Darin Petkov9893d9c2012-05-17 15:27:31 -0700250 }
251 }
252}
253
Darin Petkovd1cd7972012-05-22 15:26:15 +0200254void WiMax::DestroyAllServices() {
255 SLOG(WiMax, 2) << __func__;
256 while (!services_.empty()) {
257 const WiMaxServiceRefPtr &service = services_.back();
258 manager()->DeregisterService(service);
259 LOG(INFO) << "Deregistered WiMAX service: "
260 << service->GetStorageIdentifier();
261 services_.pop_back();
262 }
263}
264
265WiMaxServiceRefPtr WiMax::GetService(const WiMaxNetworkId &id,
266 const string &name) {
267 SLOG(WiMax, 2) << __func__ << "(" << id << ", " << name << ")";
268 string storage_id = WiMaxService::CreateStorageIdentifier(id, name);
269 WiMaxServiceRefPtr service = FindService(storage_id);
270 if (service) {
271 SLOG(WiMax, 2) << "Service already exists.";
272 return service;
273 }
274 service = new WiMaxService(control_interface(),
275 dispatcher(),
276 metrics(),
277 manager(),
278 this);
279 service->set_network_id(id);
280 service->set_friendly_name(name);
281 service->InitStorageIdentifier();
282 services_.push_back(service);
283 manager()->RegisterService(service);
284 LOG(INFO) << "Registered WiMAX service: " << service->GetStorageIdentifier();
285 return service;
286}
287
288WiMaxServiceRefPtr WiMax::GetDefaultService(const RpcIdentifier &network) {
289 SLOG(WiMax, 2) << __func__ << "(" << network << ")";
290 scoped_ptr<WiMaxNetworkProxyInterface> proxy(
291 proxy_factory_->CreateWiMaxNetworkProxy(network));
292 Error error;
293 uint32 identifier = proxy->Identifier(&error);
294 if (error.IsFailure()) {
295 return NULL;
296 }
297 string name = proxy->Name(&error);
298 if (error.IsFailure()) {
299 return NULL;
300 }
301 return GetService(WiMaxService::ConvertIdentifierToNetworkId(identifier),
302 name);
303}
304
305WiMaxServiceRefPtr WiMax::FindService(const string &storage_id) {
306 SLOG(WiMax, 2) << __func__ << "(" << storage_id << ")";
307 for (vector<WiMaxServiceRefPtr>::const_iterator it = services_.begin();
308 it != services_.end(); ++it) {
309 if ((*it)->GetStorageIdentifier() == storage_id) {
310 return *it;
311 }
312 }
313 return NULL;
314}
315
316bool WiMax::Load(StoreInterface *storage) {
317 bool loaded = Device::Load(storage);
318 if (LoadServices(storage)) {
319 StartLiveServices();
320 }
321 return loaded;
322}
323
324bool WiMax::LoadServices(StoreInterface *storage) {
325 SLOG(WiMax, 2) << __func__;
326 bool loaded = false;
327 set<string> groups = storage->GetGroupsWithKey(Service::kStorageType);
328 for (set<string>::iterator it = groups.begin(); it != groups.end(); ++it) {
329 string type;
330 if (!storage->GetString(*it, Service::kStorageType, &type) ||
331 type != GetTechnologyString(NULL)) {
332 continue;
333 }
334 if (FindService(*it)) {
335 continue;
336 }
337 WiMaxNetworkId id;
338 if (!storage->GetString(*it, WiMaxService::kStorageNetworkId, &id) ||
339 id.empty()) {
340 LOG(ERROR) << "Unable to load network id.";
341 continue;
342 }
343 string name;
344 if (!storage->GetString(*it, Service::kStorageName, &name) ||
345 name.empty()) {
346 LOG(ERROR) << "Unable to load service name.";
347 continue;
348 }
349 GetService(id, name);
350 loaded = true;
351 }
352 return loaded;
353}
354
Ben Chan99c8a4d2012-05-01 08:11:53 -0700355} // namespace shill