1 //
2 // Copyright (C) 2012 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include "shill/wimax/wimax_service.h"
18
19 #include <algorithm>
20
21 #include <base/strings/string_number_conversions.h>
22 #include <base/strings/string_util.h>
23 #include <base/strings/stringprintf.h>
24 #if defined(__ANDROID__)
25 #include <dbus/service_constants.h>
26 #else
27 #include <chromeos/dbus/service_constants.h>
28 #endif // __ANDROID__
29
30 #include "shill/control_interface.h"
31 #include "shill/eap_credentials.h"
32 #include "shill/key_value_store.h"
33 #include "shill/logging.h"
34 #include "shill/manager.h"
35 #include "shill/store_interface.h"
36 #include "shill/technology.h"
37 #include "shill/wimax/wimax.h"
38
39 using std::replace_if;
40 using std::string;
41
42 namespace shill {
43
44 namespace Logging {
45 static auto kModuleLogScope = ScopeLogger::kWiMax;
ObjectID(WiMaxService * w)46 static string ObjectID(WiMaxService* w) { return w->GetRpcIdentifier(); }
47 }
48
49 const char WiMaxService::kStorageNetworkId[] = "NetworkId";
50 const char WiMaxService::kNetworkIdProperty[] = "NetworkId";
51
WiMaxService(ControlInterface * control,EventDispatcher * dispatcher,Metrics * metrics,Manager * manager)52 WiMaxService::WiMaxService(ControlInterface* control,
53 EventDispatcher* dispatcher,
54 Metrics* metrics,
55 Manager* manager)
56 : Service(control, dispatcher, metrics, manager, Technology::kWiMax),
57 need_passphrase_(true),
58 is_default_(false) {
59 PropertyStore* store = this->mutable_store();
60 // TODO(benchan): Support networks that require no user credentials or
61 // implicitly defined credentials.
62 store->RegisterBool(kPassphraseRequiredProperty, &need_passphrase_);
63 store->RegisterConstString(kNetworkIdProperty, &network_id_);
64
65 SetEapCredentials(new EapCredentials());
66
67 IgnoreParameterForConfigure(kNetworkIdProperty);
68
69 // Initialize a default storage identifier based on the service's unique
70 // name. The identifier most likely needs to be reinitialized by the caller
71 // when its components have been set.
72 InitStorageIdentifier();
73
74 // Now that |this| is a fully constructed WiMaxService, synchronize observers
75 // with our current state, and emit the appropriate change notifications.
76 // (Initial observer state may have been set in our base class.)
77 NotifyPropertyChanges();
78 }
79
~WiMaxService()80 WiMaxService::~WiMaxService() {}
81
GetConnectParameters(KeyValueStore * parameters) const82 void WiMaxService::GetConnectParameters(KeyValueStore* parameters) const {
83 CHECK(parameters);
84 eap()->PopulateWiMaxProperties(parameters);
85 }
86
GetNetworkObjectPath() const87 RpcIdentifier WiMaxService::GetNetworkObjectPath() const {
88 CHECK(proxy_.get());
89 return proxy_->path();
90 }
91
Stop()92 void WiMaxService::Stop() {
93 if (!IsStarted()) {
94 return;
95 }
96 LOG(INFO) << "Stopping WiMAX service: " << GetStorageIdentifier();
97 proxy_.reset();
98 SetStrength(0);
99 if (device_) {
100 device_->OnServiceStopped(this);
101 SetDevice(nullptr);
102 }
103 UpdateConnectable();
104 NotifyPropertyChanges();
105 }
106
Start(WiMaxNetworkProxyInterface * proxy)107 bool WiMaxService::Start(WiMaxNetworkProxyInterface* proxy) {
108 SLOG(this, 2) << __func__;
109 CHECK(proxy);
110 std::unique_ptr<WiMaxNetworkProxyInterface> local_proxy(proxy);
111 if (IsStarted()) {
112 return true;
113 }
114 if (friendly_name().empty()) {
115 LOG(ERROR) << "Empty service name.";
116 return false;
117 }
118 Error error;
119 network_name_ = proxy->Name(&error);
120 if (error.IsFailure()) {
121 return false;
122 }
123 uint32_t identifier = proxy->Identifier(&error);
124 if (error.IsFailure()) {
125 return false;
126 }
127 WiMaxNetworkId id = ConvertIdentifierToNetworkId(identifier);
128 if (id != network_id_) {
129 LOG(ERROR) << "Network identifiers don't match: "
130 << id << " != " << network_id_;
131 return false;
132 }
133 int signal_strength = proxy->SignalStrength(&error);
134 if (error.IsFailure()) {
135 return false;
136 }
137 SetStrength(signal_strength);
138 proxy->set_signal_strength_changed_callback(
139 Bind(&WiMaxService::OnSignalStrengthChanged, Unretained(this)));
140 proxy_.reset(local_proxy.release());
141 UpdateConnectable();
142 NotifyPropertyChanges();
143 LOG(INFO) << "WiMAX service started: " << GetStorageIdentifier();
144 return true;
145 }
146
IsStarted() const147 bool WiMaxService::IsStarted() const {
148 return proxy_.get();
149 }
150
Connect(Error * error,const char * reason)151 void WiMaxService::Connect(Error* error, const char* reason) {
152 SLOG(this, 2) << __func__;
153 if (device_) {
154 // TODO(benchan): Populate error again after changing the way that
155 // Chrome handles Error::kAlreadyConnected situation.
156 LOG(WARNING) << "Service " << GetStorageIdentifier()
157 << " is already being connected or already connected.";
158 return;
159 }
160 if (!connectable()) {
161 LOG(ERROR) << "Can't connect. Service " << GetStorageIdentifier()
162 << " is not connectable.";
163 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed,
164 Error::GetDefaultMessage(Error::kOperationFailed));
165 return;
166 }
167 WiMaxRefPtr carrier = manager()->wimax_provider()->SelectCarrier(this);
168 if (!carrier) {
169 Error::PopulateAndLog(
170 FROM_HERE, error, Error::kNoCarrier,
171 "No suitable WiMAX device available.");
172 return;
173 }
174 Service::Connect(error, reason);
175 carrier->ConnectTo(this, error);
176 if (error->IsSuccess()) {
177 // Associate with the carrier device if the connection process has been
178 // initiated successfully.
179 SetDevice(carrier);
180 }
181 }
182
Disconnect(Error * error,const char * reason)183 void WiMaxService::Disconnect(Error* error, const char* reason) {
184 SLOG(this, 2) << __func__;
185 if (!device_) {
186 Error::PopulateAndLog(
187 FROM_HERE, error, Error::kNotConnected, "Not connected.");
188 return;
189 }
190 Service::Disconnect(error, reason);
191 device_->DisconnectFrom(this, error);
192 SetDevice(nullptr);
193 }
194
GetStorageIdentifier() const195 string WiMaxService::GetStorageIdentifier() const {
196 return storage_id_;
197 }
198
GetDeviceRpcId(Error * error) const199 string WiMaxService::GetDeviceRpcId(Error* error) const {
200 if (!device_) {
201 error->Populate(Error::kNotFound, "Not associated with a device");
202 return control_interface()->NullRPCIdentifier();
203 }
204 return device_->GetRpcIdentifier();
205 }
206
IsAutoConnectable(const char ** reason) const207 bool WiMaxService::IsAutoConnectable(const char** reason) const {
208 if (!Service::IsAutoConnectable(reason)) {
209 return false;
210 }
211 WiMaxRefPtr device = manager()->wimax_provider()->SelectCarrier(this);
212 DCHECK(device);
213 if (!device->IsIdle()) {
214 *reason = kAutoConnBusy;
215 return false;
216 }
217 return true;
218 }
219
Is8021x() const220 bool WiMaxService::Is8021x() const {
221 return true;
222 }
223
IsVisible() const224 bool WiMaxService::IsVisible() const {
225 // WiMAX services should be displayed only if they are in range (i.e.
226 // a corresponding network is exposed by WiMAX manager).
227 return IsStarted();
228 }
229
OnEapCredentialsChanged(Service::UpdateCredentialsReason reason)230 void WiMaxService::OnEapCredentialsChanged(
231 Service::UpdateCredentialsReason reason) {
232 need_passphrase_ = !eap()->IsConnectableUsingPassphrase();
233 if (reason == Service::kReasonPropertyUpdate)
234 SetHasEverConnected(false);
235 UpdateConnectable();
236 }
237
UpdateConnectable()238 void WiMaxService::UpdateConnectable() {
239 SLOG(this, 2) << __func__ << "(started: " << IsStarted()
240 << ", need passphrase: " << need_passphrase_ << ")";
241 SetConnectableFull(IsStarted() && !need_passphrase_);
242 }
243
OnSignalStrengthChanged(int strength)244 void WiMaxService::OnSignalStrengthChanged(int strength) {
245 SLOG(this, 2) << __func__ << "(" << strength << ")";
246 SetStrength(strength);
247 }
248
SetDevice(WiMaxRefPtr new_device)249 void WiMaxService::SetDevice(WiMaxRefPtr new_device) {
250 if (device_ == new_device)
251 return;
252 if (new_device) {
253 adaptor()->EmitRpcIdentifierChanged(kDeviceProperty,
254 new_device->GetRpcIdentifier());
255 } else {
256 adaptor()->EmitRpcIdentifierChanged(
257 kDeviceProperty, control_interface()->NullRPCIdentifier());
258 }
259 device_ = new_device;
260 }
261
Save(StoreInterface * storage)262 bool WiMaxService::Save(StoreInterface* storage) {
263 SLOG(this, 2) << __func__;
264 if (!Service::Save(storage)) {
265 return false;
266 }
267 const string id = GetStorageIdentifier();
268 storage->SetString(id, kStorageNetworkId, network_id_);
269
270 return true;
271 }
272
Unload()273 bool WiMaxService::Unload() {
274 SLOG(this, 2) << __func__;
275 // The base method also disconnects the service.
276 Service::Unload();
277 ClearPassphrase();
278 // Notify the WiMAX provider that this service has been unloaded. If the
279 // provider releases ownership of this service, it needs to be deregistered.
280 return manager()->wimax_provider()->OnServiceUnloaded(this);
281 }
282
SetState(ConnectState state)283 void WiMaxService::SetState(ConnectState state) {
284 Service::SetState(state);
285 if (!IsConnecting() && !IsConnected()) {
286 // Disassociate from any carrier device if it's not connected anymore.
287 SetDevice(nullptr);
288 }
289 }
290
291 // static
ConvertIdentifierToNetworkId(uint32_t identifier)292 WiMaxNetworkId WiMaxService::ConvertIdentifierToNetworkId(uint32_t identifier) {
293 return base::StringPrintf("%08x", identifier);
294 }
295
InitStorageIdentifier()296 void WiMaxService::InitStorageIdentifier() {
297 storage_id_ = CreateStorageIdentifier(network_id_, friendly_name());
298 }
299
300 // static
CreateStorageIdentifier(const WiMaxNetworkId & id,const string & name)301 string WiMaxService::CreateStorageIdentifier(const WiMaxNetworkId& id,
302 const string& name) {
303 string storage_id = base::ToLowerASCII(
304 base::StringPrintf("%s_%s_%s",
305 kTypeWimax, name.c_str(), id.c_str()));
306 replace_if(storage_id.begin(), storage_id.end(), &Service::IllegalChar, '_');
307 return storage_id;
308 }
309
ClearPassphrase()310 void WiMaxService::ClearPassphrase() {
311 SLOG(this, 2) << __func__;
312 mutable_eap()->set_password("");
313 OnEapCredentialsChanged(Service::kReasonPropertyUpdate);
314 }
315
316 } // namespace shill
317