blob: 09bb7eedefeaab4142a5d2be1748ab41725bf5a1 [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"
15#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
167void WiMax::OnServiceStopped(const WiMaxServiceRefPtr &service) {
Darin Petkovb96a4512012-06-04 11:02:49 +0200168 SLOG(WiMax, 2) << __func__;
Darin Petkovc63dcf02012-05-24 11:51:43 +0200169 if (service == selected_service()) {
170 DropConnection();
171 }
Darin Petkovc1e52732012-05-25 15:23:45 +0200172 if (service == pending_service_) {
Darin Petkovc63dcf02012-05-24 11:51:43 +0200173 pending_service_ = NULL;
Darin Petkov9893d9c2012-05-17 15:27:31 -0700174 }
175}
176
Darin Petkovb96a4512012-06-04 11:02:49 +0200177void WiMax::OnDeviceVanished() {
178 LOG(INFO) << "WiMAX device vanished: " << link_name();
179 proxy_.reset();
180 DropService(Service::kStateIdle);
181 // Disable the device. This will also clear any relevant properties such as
182 // the live network set.
183 SetEnabled(false);
184}
185
Darin Petkov9893d9c2012-05-17 15:27:31 -0700186void WiMax::OnScanNetworksComplete(const Error &/*error*/) {
187 SLOG(WiMax, 2) << __func__;
188 scanning_ = false;
189 // The networks are updated when the NetworksChanged signal is received.
Darin Petkov912f0de2012-05-16 14:12:14 +0200190}
191
192void WiMax::OnConnectComplete(const Error &error) {
193 SLOG(WiMax, 2) << __func__;
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200194 if (error.IsSuccess()) {
195 // Nothing to do -- the connection process is resumed on the StatusChanged
196 // signal.
Darin Petkov9893d9c2012-05-17 15:27:31 -0700197 return;
198 }
Darin Petkovb96a4512012-06-04 11:02:49 +0200199 DropService(Service::kStateFailure);
Darin Petkov912f0de2012-05-16 14:12:14 +0200200}
201
Darin Petkov9893d9c2012-05-17 15:27:31 -0700202void WiMax::OnDisconnectComplete(const Error &/*error*/) {
Darin Petkov912f0de2012-05-16 14:12:14 +0200203 SLOG(WiMax, 2) << __func__;
Darin Petkov912f0de2012-05-16 14:12:14 +0200204}
205
206void WiMax::OnEnableComplete(const EnabledStateChangedCallback &callback,
207 const Error &error) {
208 SLOG(WiMax, 2) << __func__;
209 if (error.IsFailure()) {
210 proxy_.reset();
211 } else {
Darin Petkov59f2d692012-06-07 15:57:46 +0200212 LOG(INFO) << "WiMAX device " << link_name() << " enabled.";
213 // Updates the live networks based on the current WiMaxManager.Device
214 // networks. The RPC device will signal when the network set changes.
Darin Petkov9893d9c2012-05-17 15:27:31 -0700215 Error e;
Darin Petkov59f2d692012-06-07 15:57:46 +0200216 OnNetworksChanged(proxy_->Networks(&e));
Darin Petkov912f0de2012-05-16 14:12:14 +0200217 }
218 callback.Run(error);
Darin Petkov912f0de2012-05-16 14:12:14 +0200219}
220
221void WiMax::OnDisableComplete(const EnabledStateChangedCallback &callback,
222 const Error &error) {
Darin Petkovb96a4512012-06-04 11:02:49 +0200223 LOG(INFO) << "WiMAX device " << link_name() << " disabled.";
Darin Petkov9893d9c2012-05-17 15:27:31 -0700224 proxy_.reset();
Darin Petkov912f0de2012-05-16 14:12:14 +0200225 callback.Run(error);
Ben Chan99c8a4d2012-05-01 08:11:53 -0700226}
227
Darin Petkov9893d9c2012-05-17 15:27:31 -0700228void WiMax::OnNetworksChanged(const RpcIdentifiers &networks) {
229 SLOG(WiMax, 2) << __func__;
Darin Petkovc63dcf02012-05-24 11:51:43 +0200230 networks_.clear();
231 networks_.insert(networks.begin(), networks.end());
232 manager()->wimax_provider()->OnNetworksChanged();
Darin Petkovd1cd7972012-05-22 15:26:15 +0200233}
234
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200235void WiMax::OnStatusChanged(wimax_manager::DeviceStatus status) {
Darin Petkov3a4100c2012-06-14 11:36:59 +0200236 SLOG(WiMax, 2) << "WiMAX device " << link_name() << " status: " << status;
237 wimax_manager::DeviceStatus old_status = status_;
238 status_ = status;
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200239 switch (status) {
240 case wimax_manager::kDeviceStatusConnected:
241 if (!pending_service_) {
242 LOG(WARNING) << "Unexpected status change; ignored.";
243 return;
244 }
Darin Petkov3a4100c2012-06-14 11:36:59 +0200245 // Stops the connect timeout -- the DHCP provider has a separate timeout.
246 StopConnectTimeout();
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200247 if (AcquireIPConfig()) {
Darin Petkovb96a4512012-06-04 11:02:49 +0200248 LOG(INFO) << "WiMAX device " << link_name() << " connected to "
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200249 << pending_service_->GetStorageIdentifier();
250 SelectService(pending_service_);
Darin Petkovb96a4512012-06-04 11:02:49 +0200251 pending_service_ = NULL;
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200252 SetServiceState(Service::kStateConfiguring);
253 } else {
Darin Petkovb96a4512012-06-04 11:02:49 +0200254 DropService(Service::kStateFailure);
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200255 }
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200256 break;
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200257 case wimax_manager::kDeviceStatusConnecting:
Darin Petkov3a4100c2012-06-14 11:36:59 +0200258 LOG(INFO) << "WiMAX device " << link_name() << " connecting...";
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200259 // Nothing to do.
260 break;
261 default:
Darin Petkov3a4100c2012-06-14 11:36:59 +0200262 // We may receive a queued up status update (e.g., to Scanning) before
263 // receiving the status update to Connecting, so be careful to fail the
264 // service only on the right status transition.
265 if (old_status == wimax_manager::kDeviceStatusConnecting ||
266 old_status == wimax_manager::kDeviceStatusConnected) {
267 LOG(INFO) << "WiMAX device " << link_name()
268 << " status: " << old_status << " -> " << status;
269 if (pending_service_) {
270 // For now, assume that failing to connect to a live network indicates
271 // bad user credentials. Reset the password to trigger the
272 // user/password dialog in the UI.
273 pending_service_->ClearPassphrase();
274 }
275 DropService(Service::kStateFailure);
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200276 }
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200277 break;
278 }
279}
280
Darin Petkovb96a4512012-06-04 11:02:49 +0200281void WiMax::DropService(Service::ConnectState state) {
282 SLOG(WiMax, 2) << __func__
283 << "(" << Service::ConnectStateToString(state) << ")";
Darin Petkov3a4100c2012-06-14 11:36:59 +0200284 StopConnectTimeout();
Darin Petkovb96a4512012-06-04 11:02:49 +0200285 if (pending_service_) {
286 LOG(WARNING) << "Unable to initiate connection to: "
287 << pending_service_->GetStorageIdentifier();
288 pending_service_->SetState(state);
289 pending_service_ = NULL;
290 }
291 if (selected_service()) {
292 LOG(WARNING) << "Service disconnected: "
293 << selected_service()->GetStorageIdentifier();
294 selected_service()->SetState(state);
295 DropConnection();
296 }
297}
298
Darin Petkovc63dcf02012-05-24 11:51:43 +0200299void WiMax::DropConnection() {
Darin Petkovb96a4512012-06-04 11:02:49 +0200300 SLOG(WiMax, 2) << __func__;
Darin Petkovc63dcf02012-05-24 11:51:43 +0200301 DestroyIPConfig();
302 SelectService(NULL);
Darin Petkovd1cd7972012-05-22 15:26:15 +0200303}
304
Darin Petkov3a4100c2012-06-14 11:36:59 +0200305void WiMax::StartConnectTimeout() {
306 SLOG(WiMax, 2) << __func__;
307 if (IsConnectTimeoutStarted()) {
308 return;
309 }
310 connect_timeout_callback_.Reset(
311 Bind(&WiMax::OnConnectTimeout, weak_ptr_factory_.GetWeakPtr()));
312 dispatcher()->PostDelayedTask(
313 connect_timeout_callback_.callback(), connect_timeout_seconds_ * 1000);
314}
315
316void WiMax::StopConnectTimeout() {
317 SLOG(WiMax, 2) << __func__;
318 connect_timeout_callback_.Cancel();
319}
320
321bool WiMax::IsConnectTimeoutStarted() const {
322 return !connect_timeout_callback_.IsCancelled();
323}
324
325void WiMax::OnConnectTimeout() {
326 LOG(ERROR) << "WiMAX device " << link_name() << ": connect timeout.";
327 StopConnectTimeout();
328 DropService(Service::kStateFailure);
329}
330
Ben Chan99c8a4d2012-05-01 08:11:53 -0700331} // namespace shill