blob: b5f76afb3718a120426588c72fcc432054a2e1c7 [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_service.h"
6
Darin Petkov9893d9c2012-05-17 15:27:31 -07007#include <algorithm>
8
Darin Petkovd1cd7972012-05-22 15:26:15 +02009#include <base/string_number_conversions.h>
Darin Petkove4b27022012-05-16 13:28:50 +020010#include <base/string_util.h>
Darin Petkov9893d9c2012-05-17 15:27:31 -070011#include <base/stringprintf.h>
Darin Petkove4b27022012-05-16 13:28:50 +020012#include <chromeos/dbus/service_constants.h>
13
Darin Petkov25665aa2012-05-21 14:08:12 +020014#include "shill/key_value_store.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070015#include "shill/logging.h"
Darin Petkovc63dcf02012-05-24 11:51:43 +020016#include "shill/manager.h"
Darin Petkovd1cd7972012-05-22 15:26:15 +020017#include "shill/store_interface.h"
Ben Chan99c8a4d2012-05-01 08:11:53 -070018#include "shill/technology.h"
19#include "shill/wimax.h"
20
Darin Petkov9893d9c2012-05-17 15:27:31 -070021using std::replace_if;
Ben Chanc07362b2012-05-12 10:54:11 -070022using std::string;
23
Ben Chan99c8a4d2012-05-01 08:11:53 -070024namespace shill {
25
Darin Petkovd1cd7972012-05-22 15:26:15 +020026const char WiMaxService::kStorageNetworkId[] = "NetworkId";
27const char WiMaxService::kNetworkIdProperty[] = "NetworkId";
Darin Petkov6b9b2e12012-07-10 15:51:42 +020028const char WiMaxService::kAutoConnBusy[] = "busy";
29
Darin Petkovd1cd7972012-05-22 15:26:15 +020030
Ben Chan99c8a4d2012-05-01 08:11:53 -070031WiMaxService::WiMaxService(ControlInterface *control,
32 EventDispatcher *dispatcher,
33 Metrics *metrics,
Darin Petkovc63dcf02012-05-24 11:51:43 +020034 Manager *manager)
Ben Chan99c8a4d2012-05-01 08:11:53 -070035 : Service(control, dispatcher, metrics, manager, Technology::kWiMax),
Darin Petkovc1e52732012-05-25 15:23:45 +020036 need_passphrase_(true),
37 is_default_(false) {
Ben Chan4e5c1312012-05-18 18:45:38 -070038 PropertyStore *store = this->mutable_store();
39 // TODO(benchan): Support networks that require no user credentials or
40 // implicitly defined credentials.
41 store->RegisterBool(flimflam::kPassphraseRequiredProperty, &need_passphrase_);
Darin Petkovd1cd7972012-05-22 15:26:15 +020042 store->RegisterConstString(kNetworkIdProperty, &network_id_);
43
44 IgnoreParameterForConfigure(kNetworkIdProperty);
Darin Petkovc1e52732012-05-25 15:23:45 +020045
46 // Initialize a default storage identifier based on the service's unique
47 // name. The identifier most likely needs to be reinitialized by the caller
48 // when its components have been set.
49 InitStorageIdentifier();
Ben Chan4e5c1312012-05-18 18:45:38 -070050}
Ben Chan99c8a4d2012-05-01 08:11:53 -070051
52WiMaxService::~WiMaxService() {}
53
Darin Petkov25665aa2012-05-21 14:08:12 +020054void WiMaxService::GetConnectParameters(KeyValueStore *parameters) const {
Ben Chan4e5c1312012-05-18 18:45:38 -070055 CHECK(parameters);
Darin Petkov25665aa2012-05-21 14:08:12 +020056 if (!eap().anonymous_identity.empty()) {
57 parameters->SetString(wimax_manager::kEAPAnonymousIdentity,
58 eap().anonymous_identity);
59 }
60 if (!eap().identity.empty()) {
61 parameters->SetString(wimax_manager::kEAPUserIdentity, eap().identity);
62 }
63 if (!eap().password.empty()) {
64 parameters->SetString(wimax_manager::kEAPUserPassword, eap().password);
65 }
Ben Chan4e5c1312012-05-18 18:45:38 -070066}
67
Darin Petkov1e52a1b2012-05-21 10:35:56 +020068RpcIdentifier WiMaxService::GetNetworkObjectPath() const {
Ben Chan4e5c1312012-05-18 18:45:38 -070069 CHECK(proxy_.get());
Darin Petkov1e52a1b2012-05-21 10:35:56 +020070 return proxy_->path();
Ben Chan4e5c1312012-05-18 18:45:38 -070071}
72
Darin Petkovd1cd7972012-05-22 15:26:15 +020073void WiMaxService::Stop() {
Darin Petkovc63dcf02012-05-24 11:51:43 +020074 if (!IsStarted()) {
75 return;
76 }
77 LOG(INFO) << "Stopping WiMAX service: " << GetStorageIdentifier();
Darin Petkovd1cd7972012-05-22 15:26:15 +020078 proxy_.reset();
79 SetStrength(0);
Darin Petkovc63dcf02012-05-24 11:51:43 +020080 if (device_) {
81 device_->OnServiceStopped(this);
82 device_ = NULL;
83 }
Darin Petkovc1e52732012-05-25 15:23:45 +020084 UpdateConnectable();
Darin Petkovd1cd7972012-05-22 15:26:15 +020085}
86
Darin Petkov9893d9c2012-05-17 15:27:31 -070087bool WiMaxService::Start(WiMaxNetworkProxyInterface *proxy) {
88 SLOG(WiMax, 2) << __func__;
Darin Petkov1e52a1b2012-05-21 10:35:56 +020089 CHECK(proxy);
Darin Petkovd1cd7972012-05-22 15:26:15 +020090 scoped_ptr<WiMaxNetworkProxyInterface> local_proxy(proxy);
91 if (IsStarted()) {
92 return true;
93 }
94 if (friendly_name().empty()) {
95 LOG(ERROR) << "Empty service name.";
96 return false;
97 }
Darin Petkov9893d9c2012-05-17 15:27:31 -070098 Error error;
Darin Petkovd1cd7972012-05-22 15:26:15 +020099 network_name_ = proxy->Name(&error);
100 if (error.IsFailure()) {
Darin Petkov9893d9c2012-05-17 15:27:31 -0700101 return false;
102 }
Darin Petkovd1cd7972012-05-22 15:26:15 +0200103 uint32 identifier = proxy->Identifier(&error);
104 if (error.IsFailure()) {
Darin Petkov9893d9c2012-05-17 15:27:31 -0700105 return false;
106 }
Darin Petkovd1cd7972012-05-22 15:26:15 +0200107 WiMaxNetworkId id = ConvertIdentifierToNetworkId(identifier);
108 if (id != network_id_) {
109 LOG(ERROR) << "Network identifiers don't match: "
110 << id << " != " << network_id_;
111 return false;
112 }
113 int signal_strength = proxy->SignalStrength(&error);
114 if (error.IsFailure()) {
Ben Chanac6e8362012-05-20 00:39:58 -0700115 return false;
116 }
117 SetStrength(signal_strength);
Darin Petkovd1cd7972012-05-22 15:26:15 +0200118 proxy->set_signal_strength_changed_callback(
Darin Petkov1e52a1b2012-05-21 10:35:56 +0200119 Bind(&WiMaxService::OnSignalStrengthChanged, Unretained(this)));
Darin Petkovd1cd7972012-05-22 15:26:15 +0200120 proxy_.reset(local_proxy.release());
Darin Petkova3f9f772012-05-31 12:11:28 +0200121 UpdateConnectable();
Darin Petkovc63dcf02012-05-24 11:51:43 +0200122 LOG(INFO) << "WiMAX service started: " << GetStorageIdentifier();
Darin Petkov9893d9c2012-05-17 15:27:31 -0700123 return true;
124}
125
Darin Petkovd1cd7972012-05-22 15:26:15 +0200126bool WiMaxService::IsStarted() const {
127 return proxy_.get();
128}
129
Ben Chan99c8a4d2012-05-01 08:11:53 -0700130void WiMaxService::Connect(Error *error) {
Darin Petkovc63dcf02012-05-24 11:51:43 +0200131 if (device_) {
Ben Chanb5310a12012-06-15 13:53:29 -0700132 // TODO(benchan): Populate error again after changing the way that
133 // Chrome handles Error::kAlreadyConnected situation.
134 LOG(WARNING) << "Service " << GetStorageIdentifier()
135 << " is already being connected or already connected.";
Darin Petkovc63dcf02012-05-24 11:51:43 +0200136 return;
137 }
Darin Petkova3f9f772012-05-31 12:11:28 +0200138 if (!connectable()) {
139 LOG(ERROR) << "Can't connect. Service " << GetStorageIdentifier()
140 << " is not connectable.";
141 Error::PopulateAndLog(error, Error::kOperationFailed,
142 Error::GetDefaultMessage(Error::kOperationFailed));
143 return;
144 }
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200145 WiMaxRefPtr carrier = manager()->wimax_provider()->SelectCarrier(this);
146 if (!carrier) {
Darin Petkovc63dcf02012-05-24 11:51:43 +0200147 Error::PopulateAndLog(
148 error, Error::kNoCarrier, "No suitable WiMAX device available.");
149 return;
150 }
Ben Chan99c8a4d2012-05-01 08:11:53 -0700151 Service::Connect(error);
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200152 carrier->ConnectTo(this, error);
153 if (error->IsSuccess()) {
154 // Associate with the carrier device if the connection process has been
155 // initiated successfully.
156 device_ = carrier;
157 }
Ben Chan99c8a4d2012-05-01 08:11:53 -0700158}
159
160void WiMaxService::Disconnect(Error *error) {
Darin Petkovc63dcf02012-05-24 11:51:43 +0200161 if (!device_) {
162 Error::PopulateAndLog(
163 error, Error::kNotConnected, "Not connected.");
164 return;
165 }
Ben Chan99c8a4d2012-05-01 08:11:53 -0700166 Service::Disconnect(error);
Darin Petkovc63dcf02012-05-24 11:51:43 +0200167 device_->DisconnectFrom(this, error);
168 device_ = NULL;
Ben Chan1411a042012-06-05 18:56:20 -0700169 // Set |need_passphrase_| to true so that after users explicitly disconnect
170 // from the network, the UI will prompt for credentials when they try to
171 // re-connect to the same network. This works around the fact that there is
172 // currently no mechanism for changing credentials for WiMAX connections.
173 // TODO(benchan,petkov): Find a better way to allow users to change the
174 // EAP credentials.
175 need_passphrase_ = true;
Ben Chancdbfc9f2012-06-06 13:05:11 -0700176 UpdateConnectable();
Ben Chan99c8a4d2012-05-01 08:11:53 -0700177}
178
Ben Chanc07362b2012-05-12 10:54:11 -0700179string WiMaxService::GetStorageIdentifier() const {
Darin Petkove4b27022012-05-16 13:28:50 +0200180 return storage_id_;
Ben Chanc07362b2012-05-12 10:54:11 -0700181}
182
183string WiMaxService::GetDeviceRpcId(Error *error) {
Darin Petkovc63dcf02012-05-24 11:51:43 +0200184 if (device_) {
185 return device_->GetRpcIdentifier();
186 }
187 error->Populate(Error::kNotSupported);
188 return "/";
Ben Chanc07362b2012-05-12 10:54:11 -0700189}
190
Darin Petkov6b9b2e12012-07-10 15:51:42 +0200191bool WiMaxService::IsAutoConnectable(const char **reason) const {
192 if (!Service::IsAutoConnectable(reason)) {
193 return false;
194 }
195 WiMaxRefPtr device = manager()->wimax_provider()->SelectCarrier(this);
196 DCHECK(device);
197 if (!device->IsIdle()) {
198 *reason = kAutoConnBusy;
199 return false;
200 }
201 return true;
202}
203
Darin Petkov8021e7f2012-05-21 12:15:00 +0200204bool WiMaxService::Is8021x() const {
205 return true;
206}
207
208void WiMaxService::set_eap(const EapCredentials &eap) {
209 Service::set_eap(eap);
Darin Petkova3f9f772012-05-31 12:11:28 +0200210 need_passphrase_ = eap.identity.empty() || eap.password.empty();
Darin Petkov8021e7f2012-05-21 12:15:00 +0200211 UpdateConnectable();
212}
213
214void WiMaxService::UpdateConnectable() {
Darin Petkovb2ba39f2012-06-06 10:33:43 +0200215 SetConnectable(IsStarted() && !need_passphrase_);
Darin Petkov8021e7f2012-05-21 12:15:00 +0200216}
217
Darin Petkov1e52a1b2012-05-21 10:35:56 +0200218void WiMaxService::OnSignalStrengthChanged(int strength) {
219 SLOG(WiMax, 2) << __func__ << "(" << strength << ")";
220 SetStrength(strength);
221}
222
Darin Petkovd1cd7972012-05-22 15:26:15 +0200223bool WiMaxService::Save(StoreInterface *storage) {
224 SLOG(WiMax, 2) << __func__;
225 if (!Service::Save(storage)) {
226 return false;
227 }
228 const string id = GetStorageIdentifier();
229 storage->SetString(id, kStorageNetworkId, network_id_);
230 return true;
231}
232
Darin Petkovc1e52732012-05-25 15:23:45 +0200233bool WiMaxService::Unload() {
234 // The base method also disconnects the service.
235 Service::Unload();
Darin Petkova3f9f772012-05-31 12:11:28 +0200236 ClearPassphrase();
Darin Petkovc1e52732012-05-25 15:23:45 +0200237 // Notify the WiMAX provider that this service has been unloaded. If the
238 // provider releases ownership of this service, it needs to be deregistered.
239 return manager()->wimax_provider()->OnServiceUnloaded(this);
240}
241
Darin Petkov8ea0eaf2012-05-29 11:21:33 +0200242void WiMaxService::SetState(ConnectState state) {
243 Service::SetState(state);
244 if (!IsConnecting() && !IsConnected()) {
245 // Disassociate from any carrier device if it's not connected anymore.
246 device_ = NULL;
247 }
248}
249
Darin Petkovd1cd7972012-05-22 15:26:15 +0200250// static
251WiMaxNetworkId WiMaxService::ConvertIdentifierToNetworkId(uint32 identifier) {
252 return base::StringPrintf("%08x", identifier);
253}
254
255void WiMaxService::InitStorageIdentifier() {
256 storage_id_ = CreateStorageIdentifier(network_id_, friendly_name());
257}
258
259// static
260string WiMaxService::CreateStorageIdentifier(const WiMaxNetworkId &id,
261 const string &name) {
262 string storage_id =
263 base::StringPrintf("%s_%s_%s",
264 flimflam::kTypeWimax, name.c_str(), id.c_str());
265 StringToLowerASCII(&storage_id);
266 replace_if(storage_id.begin(), storage_id.end(), &Service::IllegalChar, '_');
267 return storage_id;
268}
269
Darin Petkova3f9f772012-05-31 12:11:28 +0200270void WiMaxService::ClearPassphrase() {
271 EapCredentials creds = eap();
272 creds.password.clear();
273 // Updates the service credentials and connectability status.
274 set_eap(creds);
275}
276
Ben Chan99c8a4d2012-05-01 08:11:53 -0700277} // namespace shill