blob: 98db5de7e44c0bddda9017841b16168d98eb2066 [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 Petkov912f0de2012-05-16 14:12:14 +020024const int WiMax::kTimeoutDefault = 30000;
25
Ben Chan99c8a4d2012-05-01 08:11:53 -070026WiMax::WiMax(ControlInterface *control,
27 EventDispatcher *dispatcher,
28 Metrics *metrics,
29 Manager *manager,
30 const string &link_name,
Ben Chan4e64d2d2012-05-16 00:02:25 -070031 const string &address,
Darin Petkovb72b62e2012-05-15 16:55:36 +020032 int interface_index,
33 const RpcIdentifier &path)
Ben Chan4e64d2d2012-05-16 00:02:25 -070034 : Device(control, dispatcher, metrics, manager, link_name, address,
Darin Petkovb72b62e2012-05-15 16:55:36 +020035 interface_index, Technology::kWiMax),
36 path_(path),
Darin Petkov9893d9c2012-05-17 15:27:31 -070037 scanning_(false),
Darin Petkovb72b62e2012-05-15 16:55:36 +020038 proxy_factory_(ProxyFactory::GetInstance()) {
39 SLOG(WiMax, 2) << __func__ << "(" << link_name << ", " << path << ")";
Darin Petkov9893d9c2012-05-17 15:27:31 -070040 PropertyStore *store = mutable_store();
41 store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
Darin Petkovb72b62e2012-05-15 16:55:36 +020042}
Ben Chan99c8a4d2012-05-01 08:11:53 -070043
Darin Petkovb72b62e2012-05-15 16:55:36 +020044WiMax::~WiMax() {
45 SLOG(WiMax, 2) << __func__ << "(" << link_name() << ", " << path_ << ")";
46}
Ben Chan99c8a4d2012-05-01 08:11:53 -070047
48void WiMax::Start(Error *error, const EnabledStateChangedCallback &callback) {
Darin Petkovb72b62e2012-05-15 16:55:36 +020049 SLOG(WiMax, 2) << __func__;
Darin Petkov9893d9c2012-05-17 15:27:31 -070050 scanning_ = false;
Darin Petkovb72b62e2012-05-15 16:55:36 +020051 proxy_.reset(proxy_factory_->CreateWiMaxDeviceProxy(path_));
Darin Petkov9893d9c2012-05-17 15:27:31 -070052 proxy_->set_networks_changed_callback(
53 Bind(&WiMax::OnNetworksChanged, Unretained(this)));
Darin Petkov8ea0eaf2012-05-29 11:21:33 +020054 proxy_->set_status_changed_callback(
55 Bind(&WiMax::OnStatusChanged, 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 Petkovc63dcf02012-05-24 11:51:43 +020062 if (selected_service()) {
63 Error error;
64 DisconnectFrom(selected_service(), &error);
65 }
Darin Petkovd1cd7972012-05-22 15:26:15 +020066 networks_.clear();
Darin Petkovc63dcf02012-05-24 11:51:43 +020067 manager()->wimax_provider()->OnNetworksChanged();
Darin Petkov912f0de2012-05-16 14:12:14 +020068 proxy_->Disable(
69 error, Bind(&WiMax::OnDisableComplete, this, callback), kTimeoutDefault);
Ben Chan99c8a4d2012-05-01 08:11:53 -070070}
71
72bool WiMax::TechnologyIs(const Technology::Identifier type) const {
73 return type == Technology::kWiMax;
74}
75
Darin Petkov9893d9c2012-05-17 15:27:31 -070076void WiMax::Scan(Error *error) {
Darin Petkov912f0de2012-05-16 14:12:14 +020077 SLOG(WiMax, 2) << __func__;
Darin Petkov9893d9c2012-05-17 15:27:31 -070078 if (scanning_) {
79 Error::PopulateAndLog(
80 error, Error::kInProgress, "Scan already in progress.");
81 return;
82 }
83 scanning_ = true;
84 proxy_->ScanNetworks(
85 error, Bind(&WiMax::OnScanNetworksComplete, this), kTimeoutDefault);
86 if (error->IsFailure()) {
87 OnScanNetworksComplete(*error);
88 }
Ben Chan99c8a4d2012-05-01 08:11:53 -070089}
90
Darin Petkov9893d9c2012-05-17 15:27:31 -070091void WiMax::ConnectTo(const WiMaxServiceRefPtr &service, Error *error) {
Darin Petkovc63dcf02012-05-24 11:51:43 +020092 SLOG(WiMax, 2) << __func__ << "(" << service->GetStorageIdentifier() << ")";
Darin Petkov9893d9c2012-05-17 15:27:31 -070093 if (pending_service_) {
94 Error::PopulateAndLog(
95 error, Error::kInProgress,
96 base::StringPrintf(
97 "Pending connect to %s, ignoring connect request to %s.",
98 pending_service_->friendly_name().c_str(),
Darin Petkovc63dcf02012-05-24 11:51:43 +020099 service->GetStorageIdentifier().c_str()));
Darin Petkov9893d9c2012-05-17 15:27:31 -0700100 return;
101 }
102 service->SetState(Service::kStateAssociating);
103 pending_service_ = service;
Ben Chan4e5c1312012-05-18 18:45:38 -0700104
Darin Petkov25665aa2012-05-21 14:08:12 +0200105 KeyValueStore parameters;
Ben Chan4e5c1312012-05-18 18:45:38 -0700106 service->GetConnectParameters(&parameters);
Darin Petkov9893d9c2012-05-17 15:27:31 -0700107 proxy_->Connect(
Ben Chan4e5c1312012-05-18 18:45:38 -0700108 service->GetNetworkObjectPath(), parameters,
Darin Petkov9893d9c2012-05-17 15:27:31 -0700109 error, Bind(&WiMax::OnConnectComplete, this), kTimeoutDefault);
110 if (error->IsFailure()) {
111 OnConnectComplete(*error);
112 }
113}
114
Darin Petkovc63dcf02012-05-24 11:51:43 +0200115void WiMax::DisconnectFrom(const ServiceRefPtr &service, Error *error) {
Darin Petkov912f0de2012-05-16 14:12:14 +0200116 SLOG(WiMax, 2) << __func__;
Darin Petkov9893d9c2012-05-17 15:27:31 -0700117 if (pending_service_) {
118 Error::PopulateAndLog(
119 error, Error::kInProgress,
120 base::StringPrintf(
121 "Pending connect to %s, ignoring disconnect request from %s.",
122 pending_service_->friendly_name().c_str(),
Darin Petkovc63dcf02012-05-24 11:51:43 +0200123 service->GetStorageIdentifier().c_str()));
Darin Petkov9893d9c2012-05-17 15:27:31 -0700124 return;
125 }
126 if (selected_service() && service != selected_service()) {
127 Error::PopulateAndLog(
128 error, Error::kNotConnected,
129 base::StringPrintf(
130 "Curent service is %s, ignoring disconnect request from %s.",
131 selected_service()->friendly_name().c_str(),
Darin Petkovc63dcf02012-05-24 11:51:43 +0200132 service->GetStorageIdentifier().c_str()));
Darin Petkov9893d9c2012-05-17 15:27:31 -0700133 return;
134 }
Darin Petkovc63dcf02012-05-24 11:51:43 +0200135 DropConnection();
Darin Petkov912f0de2012-05-16 14:12:14 +0200136 proxy_->Disconnect(
137 error, Bind(&WiMax::OnDisconnectComplete, this), kTimeoutDefault);
Darin Petkov9893d9c2012-05-17 15:27:31 -0700138 if (error->IsFailure()) {
Darin Petkovc63dcf02012-05-24 11:51:43 +0200139 OnDisconnectComplete(*error);
140 }
141}
142
143void WiMax::OnServiceStopped(const WiMaxServiceRefPtr &service) {
144 if (service == selected_service()) {
145 DropConnection();
146 }
Darin Petkovc1e52732012-05-25 15:23:45 +0200147 if (service == pending_service_) {
Darin Petkovc63dcf02012-05-24 11:51:43 +0200148 pending_service_ = NULL;
Darin Petkov9893d9c2012-05-17 15:27:31 -0700149 }
150}
151
152void WiMax::OnScanNetworksComplete(const Error &/*error*/) {
153 SLOG(WiMax, 2) << __func__;
154 scanning_ = false;
155 // The networks are updated when the NetworksChanged signal is received.
Darin Petkov912f0de2012-05-16 14:12:14 +0200156}
157
158void WiMax::OnConnectComplete(const Error &error) {
159 SLOG(WiMax, 2) << __func__;
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200160 if (error.IsSuccess()) {
161 // Nothing to do -- the connection process is resumed on the StatusChanged
162 // signal.
Darin Petkov9893d9c2012-05-17 15:27:31 -0700163 return;
164 }
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200165 if (pending_service_) {
166 LOG(ERROR) << "Unable to initiate connection to "
167 << pending_service_->GetStorageIdentifier();
Darin Petkov9893d9c2012-05-17 15:27:31 -0700168 pending_service_->SetState(Service::kStateFailure);
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200169 pending_service_ = NULL;
Darin Petkov912f0de2012-05-16 14:12:14 +0200170 }
171}
172
Darin Petkov9893d9c2012-05-17 15:27:31 -0700173void WiMax::OnDisconnectComplete(const Error &/*error*/) {
Darin Petkov912f0de2012-05-16 14:12:14 +0200174 SLOG(WiMax, 2) << __func__;
Darin Petkov912f0de2012-05-16 14:12:14 +0200175}
176
177void WiMax::OnEnableComplete(const EnabledStateChangedCallback &callback,
178 const Error &error) {
179 SLOG(WiMax, 2) << __func__;
180 if (error.IsFailure()) {
181 proxy_.reset();
182 } else {
Darin Petkov9893d9c2012-05-17 15:27:31 -0700183 // Scan for networks to allow service creation when the network list becomes
184 // available.
185 Error e;
186 Scan(&e);
Darin Petkov912f0de2012-05-16 14:12:14 +0200187 }
188 callback.Run(error);
Darin Petkov912f0de2012-05-16 14:12:14 +0200189}
190
191void WiMax::OnDisableComplete(const EnabledStateChangedCallback &callback,
192 const Error &error) {
193 SLOG(WiMax, 2) << __func__;
Darin Petkov9893d9c2012-05-17 15:27:31 -0700194 proxy_.reset();
Darin Petkov912f0de2012-05-16 14:12:14 +0200195 callback.Run(error);
Ben Chan99c8a4d2012-05-01 08:11:53 -0700196}
197
Darin Petkov9893d9c2012-05-17 15:27:31 -0700198void WiMax::OnNetworksChanged(const RpcIdentifiers &networks) {
199 SLOG(WiMax, 2) << __func__;
Darin Petkovc63dcf02012-05-24 11:51:43 +0200200 networks_.clear();
201 networks_.insert(networks.begin(), networks.end());
202 manager()->wimax_provider()->OnNetworksChanged();
Darin Petkovd1cd7972012-05-22 15:26:15 +0200203}
204
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200205void WiMax::OnStatusChanged(wimax_manager::DeviceStatus status) {
206 SLOG(WiMax, 2) << __func__ << "(" << status << ")";
207 switch (status) {
208 case wimax_manager::kDeviceStatusConnected:
209 if (!pending_service_) {
210 LOG(WARNING) << "Unexpected status change; ignored.";
211 return;
212 }
213 if (AcquireIPConfig()) {
214 LOG(INFO) << "Connected to "
215 << pending_service_->GetStorageIdentifier();
216 SelectService(pending_service_);
217 SetServiceState(Service::kStateConfiguring);
218 } else {
219 LOG(ERROR) << "Unable to connect to "
220 << pending_service_->GetStorageIdentifier();
221 pending_service_->SetState(Service::kStateFailure);
222 }
223 pending_service_ = NULL;
224 break;
225 case wimax_manager::kDeviceStatusScanning:
226 case wimax_manager::kDeviceStatusConnecting:
227 // Nothing to do.
228 break;
229 default:
230 if (pending_service_) {
231 pending_service_->SetState(Service::kStateFailure);
232 pending_service_ = NULL;
233 }
234 if (selected_service()) {
235 selected_service()->SetState(Service::kStateFailure);
236 DropConnection();
237 }
238 break;
239 }
240}
241
Darin Petkovc63dcf02012-05-24 11:51:43 +0200242void WiMax::DropConnection() {
243 DestroyIPConfig();
244 SelectService(NULL);
Darin Petkovd1cd7972012-05-22 15:26:15 +0200245}
246
Ben Chan99c8a4d2012-05-01 08:11:53 -0700247} // namespace shill