blob: 202f2054b21760d07b0e7a2f82718f28e99b3d50 [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"
Christopher Wileyb691efd2012-08-09 13:51:51 -070012#include "shill/logging.h"
Darin Petkov912f0de2012-05-16 14:12:14 +020013#include "shill/manager.h"
Darin Petkovb72b62e2012-05-15 16:55:36 +020014#include "shill/proxy_factory.h"
Darin Petkovb72b62e2012-05-15 16:55:36 +020015#include "shill/wimax_device_proxy_interface.h"
Darin Petkov912f0de2012-05-16 14:12:14 +020016#include "shill/wimax_service.h"
Darin Petkovb72b62e2012-05-15 16:55:36 +020017
Darin Petkov912f0de2012-05-16 14:12:14 +020018using base::Bind;
Darin Petkovd1cd7972012-05-22 15:26:15 +020019using std::set;
Ben Chan99c8a4d2012-05-01 08:11:53 -070020using std::string;
21
22namespace shill {
23
Darin Petkov3a4100c2012-06-14 11:36:59 +020024const int WiMax::kDefaultConnectTimeoutSeconds = 60;
25const int WiMax::kDefaultRPCTimeoutSeconds = 30;
Darin Petkov912f0de2012-05-16 14:12:14 +020026
Ben Chan99c8a4d2012-05-01 08:11:53 -070027WiMax::WiMax(ControlInterface *control,
28 EventDispatcher *dispatcher,
29 Metrics *metrics,
30 Manager *manager,
31 const string &link_name,
Ben Chan4e64d2d2012-05-16 00:02:25 -070032 const string &address,
Darin Petkovb72b62e2012-05-15 16:55:36 +020033 int interface_index,
34 const RpcIdentifier &path)
Ben Chan4e64d2d2012-05-16 00:02:25 -070035 : Device(control, dispatcher, metrics, manager, link_name, address,
Darin Petkovb72b62e2012-05-15 16:55:36 +020036 interface_index, Technology::kWiMax),
37 path_(path),
Darin Petkov3a4100c2012-06-14 11:36:59 +020038 weak_ptr_factory_(this),
Darin Petkov9893d9c2012-05-17 15:27:31 -070039 scanning_(false),
Darin Petkov3a4100c2012-06-14 11:36:59 +020040 status_(wimax_manager::kDeviceStatusUninitialized),
41 proxy_factory_(ProxyFactory::GetInstance()),
42 connect_timeout_seconds_(kDefaultConnectTimeoutSeconds) {
Darin Petkovb96a4512012-06-04 11:02:49 +020043 LOG(INFO) << "WiMAX device created: " << link_name << " @ " << path;
Darin Petkov9893d9c2012-05-17 15:27:31 -070044 PropertyStore *store = mutable_store();
45 store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
Darin Petkovb72b62e2012-05-15 16:55:36 +020046}
Ben Chan99c8a4d2012-05-01 08:11:53 -070047
Darin Petkovb72b62e2012-05-15 16:55:36 +020048WiMax::~WiMax() {
Darin Petkovb96a4512012-06-04 11:02:49 +020049 LOG(INFO) << "WiMAX device destroyed: " << link_name();
Darin Petkovb72b62e2012-05-15 16:55:36 +020050}
Ben Chan99c8a4d2012-05-01 08:11:53 -070051
52void WiMax::Start(Error *error, const EnabledStateChangedCallback &callback) {
Darin Petkovb72b62e2012-05-15 16:55:36 +020053 SLOG(WiMax, 2) << __func__;
Darin Petkov9893d9c2012-05-17 15:27:31 -070054 scanning_ = false;
Darin Petkovb72b62e2012-05-15 16:55:36 +020055 proxy_.reset(proxy_factory_->CreateWiMaxDeviceProxy(path_));
Darin Petkov9893d9c2012-05-17 15:27:31 -070056 proxy_->set_networks_changed_callback(
57 Bind(&WiMax::OnNetworksChanged, Unretained(this)));
Darin Petkov8ea0eaf2012-05-29 11:21:33 +020058 proxy_->set_status_changed_callback(
59 Bind(&WiMax::OnStatusChanged, Unretained(this)));
Darin Petkov912f0de2012-05-16 14:12:14 +020060 proxy_->Enable(
Darin Petkov3a4100c2012-06-14 11:36:59 +020061 error, Bind(&WiMax::OnEnableComplete, this, callback),
62 kDefaultRPCTimeoutSeconds * 1000);
Ben Chan99c8a4d2012-05-01 08:11:53 -070063}
64
65void WiMax::Stop(Error *error, const EnabledStateChangedCallback &callback) {
Darin Petkovb72b62e2012-05-15 16:55:36 +020066 SLOG(WiMax, 2) << __func__;
Darin Petkov3a4100c2012-06-14 11:36:59 +020067 StopConnectTimeout();
68 if (pending_service_) {
69 pending_service_->SetState(Service::kStateIdle);
70 pending_service_ = NULL;
71 }
Darin Petkovc63dcf02012-05-24 11:51:43 +020072 if (selected_service()) {
73 Error error;
74 DisconnectFrom(selected_service(), &error);
75 }
Darin Petkovb96a4512012-06-04 11:02:49 +020076 scanning_ = false;
Darin Petkovd1cd7972012-05-22 15:26:15 +020077 networks_.clear();
Darin Petkovc63dcf02012-05-24 11:51:43 +020078 manager()->wimax_provider()->OnNetworksChanged();
Darin Petkovb96a4512012-06-04 11:02:49 +020079 if (proxy_.get()) {
80 proxy_->Disable(
81 error, Bind(&WiMax::OnDisableComplete, this, callback),
Darin Petkov3a4100c2012-06-14 11:36:59 +020082 kDefaultRPCTimeoutSeconds * 1000);
Darin Petkovb96a4512012-06-04 11:02:49 +020083 } else {
84 OnDisableComplete(callback, Error());
85 }
Ben Chan99c8a4d2012-05-01 08:11:53 -070086}
87
Darin Petkov9893d9c2012-05-17 15:27:31 -070088void WiMax::Scan(Error *error) {
Darin Petkov912f0de2012-05-16 14:12:14 +020089 SLOG(WiMax, 2) << __func__;
Darin Petkov9893d9c2012-05-17 15:27:31 -070090 if (scanning_) {
91 Error::PopulateAndLog(
92 error, Error::kInProgress, "Scan already in progress.");
93 return;
94 }
95 scanning_ = true;
96 proxy_->ScanNetworks(
Darin Petkov3a4100c2012-06-14 11:36:59 +020097 error, Bind(&WiMax::OnScanNetworksComplete, this),
98 kDefaultRPCTimeoutSeconds * 1000);
Darin Petkov9893d9c2012-05-17 15:27:31 -070099 if (error->IsFailure()) {
100 OnScanNetworksComplete(*error);
101 }
Ben Chan99c8a4d2012-05-01 08:11:53 -0700102}
103
Darin Petkov9893d9c2012-05-17 15:27:31 -0700104void WiMax::ConnectTo(const WiMaxServiceRefPtr &service, Error *error) {
Darin Petkovc63dcf02012-05-24 11:51:43 +0200105 SLOG(WiMax, 2) << __func__ << "(" << service->GetStorageIdentifier() << ")";
Darin Petkov9893d9c2012-05-17 15:27:31 -0700106 if (pending_service_) {
107 Error::PopulateAndLog(
108 error, Error::kInProgress,
109 base::StringPrintf(
110 "Pending connect to %s, ignoring connect request to %s.",
111 pending_service_->friendly_name().c_str(),
Darin Petkovc63dcf02012-05-24 11:51:43 +0200112 service->GetStorageIdentifier().c_str()));
Darin Petkov9893d9c2012-05-17 15:27:31 -0700113 return;
114 }
115 service->SetState(Service::kStateAssociating);
116 pending_service_ = service;
Ben Chan4e5c1312012-05-18 18:45:38 -0700117
Darin Petkov3a4100c2012-06-14 11:36:59 +0200118 // We use the RPC device status to determine the outcome of the connect
119 // operation by listening for status updates in OnStatusChanged. A transition
120 // to Connected means success. A transition to Connecting and then to a status
121 // different than Connected means failure. Also, schedule a connect timeout to
122 // guard against the RPC device never transitioning to a Connecting or a
123 // Connected state.
124 status_ = wimax_manager::kDeviceStatusUninitialized;
125 StartConnectTimeout();
126
Darin Petkov25665aa2012-05-21 14:08:12 +0200127 KeyValueStore parameters;
Ben Chan4e5c1312012-05-18 18:45:38 -0700128 service->GetConnectParameters(&parameters);
Darin Petkov9893d9c2012-05-17 15:27:31 -0700129 proxy_->Connect(
Ben Chan4e5c1312012-05-18 18:45:38 -0700130 service->GetNetworkObjectPath(), parameters,
Darin Petkov3a4100c2012-06-14 11:36:59 +0200131 error, Bind(&WiMax::OnConnectComplete, this),
132 kDefaultRPCTimeoutSeconds * 1000);
Darin Petkov9893d9c2012-05-17 15:27:31 -0700133 if (error->IsFailure()) {
134 OnConnectComplete(*error);
135 }
136}
137
Darin Petkovc63dcf02012-05-24 11:51:43 +0200138void WiMax::DisconnectFrom(const ServiceRefPtr &service, Error *error) {
Darin Petkov912f0de2012-05-16 14:12:14 +0200139 SLOG(WiMax, 2) << __func__;
Darin Petkov9893d9c2012-05-17 15:27:31 -0700140 if (pending_service_) {
141 Error::PopulateAndLog(
142 error, Error::kInProgress,
143 base::StringPrintf(
144 "Pending connect to %s, ignoring disconnect request from %s.",
145 pending_service_->friendly_name().c_str(),
Darin Petkovc63dcf02012-05-24 11:51:43 +0200146 service->GetStorageIdentifier().c_str()));
Darin Petkov9893d9c2012-05-17 15:27:31 -0700147 return;
148 }
149 if (selected_service() && service != selected_service()) {
150 Error::PopulateAndLog(
151 error, Error::kNotConnected,
152 base::StringPrintf(
153 "Curent service is %s, ignoring disconnect request from %s.",
154 selected_service()->friendly_name().c_str(),
Darin Petkovc63dcf02012-05-24 11:51:43 +0200155 service->GetStorageIdentifier().c_str()));
Darin Petkov9893d9c2012-05-17 15:27:31 -0700156 return;
157 }
Darin Petkovc63dcf02012-05-24 11:51:43 +0200158 DropConnection();
Darin Petkov912f0de2012-05-16 14:12:14 +0200159 proxy_->Disconnect(
Darin Petkov3a4100c2012-06-14 11:36:59 +0200160 error, Bind(&WiMax::OnDisconnectComplete, this),
161 kDefaultRPCTimeoutSeconds * 1000);
Darin Petkov9893d9c2012-05-17 15:27:31 -0700162 if (error->IsFailure()) {
Darin Petkovc63dcf02012-05-24 11:51:43 +0200163 OnDisconnectComplete(*error);
164 }
165}
166
Darin Petkov6b9b2e12012-07-10 15:51:42 +0200167bool WiMax::IsIdle() const {
168 return !pending_service_ && !selected_service();
169}
170
Darin Petkovc63dcf02012-05-24 11:51:43 +0200171void WiMax::OnServiceStopped(const WiMaxServiceRefPtr &service) {
Darin Petkovb96a4512012-06-04 11:02:49 +0200172 SLOG(WiMax, 2) << __func__;
Darin Petkovc63dcf02012-05-24 11:51:43 +0200173 if (service == selected_service()) {
174 DropConnection();
175 }
Darin Petkovc1e52732012-05-25 15:23:45 +0200176 if (service == pending_service_) {
Darin Petkovc63dcf02012-05-24 11:51:43 +0200177 pending_service_ = NULL;
Darin Petkov9893d9c2012-05-17 15:27:31 -0700178 }
179}
180
Darin Petkovb96a4512012-06-04 11:02:49 +0200181void WiMax::OnDeviceVanished() {
182 LOG(INFO) << "WiMAX device vanished: " << link_name();
183 proxy_.reset();
184 DropService(Service::kStateIdle);
185 // Disable the device. This will also clear any relevant properties such as
186 // the live network set.
187 SetEnabled(false);
188}
189
Darin Petkov9893d9c2012-05-17 15:27:31 -0700190void WiMax::OnScanNetworksComplete(const Error &/*error*/) {
191 SLOG(WiMax, 2) << __func__;
192 scanning_ = false;
193 // The networks are updated when the NetworksChanged signal is received.
Darin Petkov912f0de2012-05-16 14:12:14 +0200194}
195
196void WiMax::OnConnectComplete(const Error &error) {
197 SLOG(WiMax, 2) << __func__;
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200198 if (error.IsSuccess()) {
199 // Nothing to do -- the connection process is resumed on the StatusChanged
200 // signal.
Darin Petkov9893d9c2012-05-17 15:27:31 -0700201 return;
202 }
Darin Petkovb96a4512012-06-04 11:02:49 +0200203 DropService(Service::kStateFailure);
Darin Petkov912f0de2012-05-16 14:12:14 +0200204}
205
Darin Petkov9893d9c2012-05-17 15:27:31 -0700206void WiMax::OnDisconnectComplete(const Error &/*error*/) {
Darin Petkov912f0de2012-05-16 14:12:14 +0200207 SLOG(WiMax, 2) << __func__;
Darin Petkov912f0de2012-05-16 14:12:14 +0200208}
209
210void WiMax::OnEnableComplete(const EnabledStateChangedCallback &callback,
211 const Error &error) {
212 SLOG(WiMax, 2) << __func__;
213 if (error.IsFailure()) {
214 proxy_.reset();
215 } else {
Darin Petkov59f2d692012-06-07 15:57:46 +0200216 LOG(INFO) << "WiMAX device " << link_name() << " enabled.";
217 // Updates the live networks based on the current WiMaxManager.Device
218 // networks. The RPC device will signal when the network set changes.
Darin Petkov9893d9c2012-05-17 15:27:31 -0700219 Error e;
Darin Petkov59f2d692012-06-07 15:57:46 +0200220 OnNetworksChanged(proxy_->Networks(&e));
Darin Petkov912f0de2012-05-16 14:12:14 +0200221 }
222 callback.Run(error);
Darin Petkov912f0de2012-05-16 14:12:14 +0200223}
224
225void WiMax::OnDisableComplete(const EnabledStateChangedCallback &callback,
226 const Error &error) {
Darin Petkovb96a4512012-06-04 11:02:49 +0200227 LOG(INFO) << "WiMAX device " << link_name() << " disabled.";
Darin Petkov9893d9c2012-05-17 15:27:31 -0700228 proxy_.reset();
Darin Petkov912f0de2012-05-16 14:12:14 +0200229 callback.Run(error);
Ben Chan99c8a4d2012-05-01 08:11:53 -0700230}
231
Darin Petkov9893d9c2012-05-17 15:27:31 -0700232void WiMax::OnNetworksChanged(const RpcIdentifiers &networks) {
233 SLOG(WiMax, 2) << __func__;
Darin Petkovc63dcf02012-05-24 11:51:43 +0200234 networks_.clear();
235 networks_.insert(networks.begin(), networks.end());
236 manager()->wimax_provider()->OnNetworksChanged();
Darin Petkovd1cd7972012-05-22 15:26:15 +0200237}
238
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200239void WiMax::OnStatusChanged(wimax_manager::DeviceStatus status) {
Darin Petkov3a4100c2012-06-14 11:36:59 +0200240 SLOG(WiMax, 2) << "WiMAX device " << link_name() << " status: " << status;
241 wimax_manager::DeviceStatus old_status = status_;
242 status_ = status;
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200243 switch (status) {
244 case wimax_manager::kDeviceStatusConnected:
245 if (!pending_service_) {
246 LOG(WARNING) << "Unexpected status change; ignored.";
247 return;
248 }
Darin Petkov3a4100c2012-06-14 11:36:59 +0200249 // Stops the connect timeout -- the DHCP provider has a separate timeout.
250 StopConnectTimeout();
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200251 if (AcquireIPConfig()) {
Darin Petkovb96a4512012-06-04 11:02:49 +0200252 LOG(INFO) << "WiMAX device " << link_name() << " connected to "
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200253 << pending_service_->GetStorageIdentifier();
254 SelectService(pending_service_);
Darin Petkovb96a4512012-06-04 11:02:49 +0200255 pending_service_ = NULL;
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200256 SetServiceState(Service::kStateConfiguring);
257 } else {
Darin Petkovb96a4512012-06-04 11:02:49 +0200258 DropService(Service::kStateFailure);
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200259 }
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200260 break;
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200261 case wimax_manager::kDeviceStatusConnecting:
Darin Petkov3a4100c2012-06-14 11:36:59 +0200262 LOG(INFO) << "WiMAX device " << link_name() << " connecting...";
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200263 // Nothing to do.
264 break;
265 default:
Darin Petkov3a4100c2012-06-14 11:36:59 +0200266 // We may receive a queued up status update (e.g., to Scanning) before
267 // receiving the status update to Connecting, so be careful to fail the
268 // service only on the right status transition.
269 if (old_status == wimax_manager::kDeviceStatusConnecting ||
270 old_status == wimax_manager::kDeviceStatusConnected) {
271 LOG(INFO) << "WiMAX device " << link_name()
272 << " status: " << old_status << " -> " << status;
273 if (pending_service_) {
274 // For now, assume that failing to connect to a live network indicates
275 // bad user credentials. Reset the password to trigger the
276 // user/password dialog in the UI.
277 pending_service_->ClearPassphrase();
278 }
279 DropService(Service::kStateFailure);
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200280 }
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200281 break;
282 }
283}
284
Darin Petkovb96a4512012-06-04 11:02:49 +0200285void WiMax::DropService(Service::ConnectState state) {
286 SLOG(WiMax, 2) << __func__
287 << "(" << Service::ConnectStateToString(state) << ")";
Darin Petkov3a4100c2012-06-14 11:36:59 +0200288 StopConnectTimeout();
Darin Petkovb96a4512012-06-04 11:02:49 +0200289 if (pending_service_) {
290 LOG(WARNING) << "Unable to initiate connection to: "
291 << pending_service_->GetStorageIdentifier();
292 pending_service_->SetState(state);
293 pending_service_ = NULL;
294 }
295 if (selected_service()) {
296 LOG(WARNING) << "Service disconnected: "
297 << selected_service()->GetStorageIdentifier();
298 selected_service()->SetState(state);
299 DropConnection();
300 }
301}
302
Darin Petkov3a4100c2012-06-14 11:36:59 +0200303void WiMax::StartConnectTimeout() {
304 SLOG(WiMax, 2) << __func__;
305 if (IsConnectTimeoutStarted()) {
306 return;
307 }
308 connect_timeout_callback_.Reset(
309 Bind(&WiMax::OnConnectTimeout, weak_ptr_factory_.GetWeakPtr()));
310 dispatcher()->PostDelayedTask(
311 connect_timeout_callback_.callback(), connect_timeout_seconds_ * 1000);
312}
313
314void WiMax::StopConnectTimeout() {
315 SLOG(WiMax, 2) << __func__;
316 connect_timeout_callback_.Cancel();
317}
318
319bool WiMax::IsConnectTimeoutStarted() const {
320 return !connect_timeout_callback_.IsCancelled();
321}
322
323void WiMax::OnConnectTimeout() {
324 LOG(ERROR) << "WiMAX device " << link_name() << ": connect timeout.";
325 StopConnectTimeout();
326 DropService(Service::kStateFailure);
327}
328
Ben Chan99c8a4d2012-05-01 08:11:53 -0700329} // namespace shill