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/cellular/cellular_service.h"
18
19 #include <string>
20
21 #include <base/strings/stringprintf.h>
22 #if defined(__ANDROID__)
23 #include <dbus/service_constants.h>
24 #else
25 #include <chromeos/dbus/service_constants.h>
26 #endif // __ANDROID__
27
28 #include "shill/adaptor_interfaces.h"
29 #include "shill/cellular/cellular.h"
30 #include "shill/property_accessor.h"
31 #include "shill/store_interface.h"
32
33 using std::string;
34
35 namespace shill {
36
37 namespace Logging {
38 static auto kModuleLogScope = ScopeLogger::kCellular;
ObjectID(CellularService * c)39 static string ObjectID(CellularService* c) { return c->GetRpcIdentifier(); }
40 }
41
42 // statics
43 const char CellularService::kAutoConnActivating[] = "activating";
44 const char CellularService::kAutoConnBadPPPCredentials[] =
45 "bad PPP credentials";
46 const char CellularService::kAutoConnDeviceDisabled[] = "device disabled";
47 const char CellularService::kAutoConnOutOfCredits[] = "device out of credits";
48 const char CellularService::kAutoConnOutOfCreditsDetectionInProgress[] =
49 "device detecting out-of-credits";
50 const char CellularService::kStoragePPPUsername[] = "Cellular.PPP.Username";
51 const char CellularService::kStoragePPPPassword[] = "Cellular.PPP.Password";
52
53 // TODO(petkov): Add these to system_api/dbus/service_constants.h
54 namespace {
55 const char kCellularPPPUsernameProperty[] = "Cellular.PPP.Username";
56 const char kCellularPPPPasswordProperty[] = "Cellular.PPP.Password";
57 } // namespace
58
59 namespace {
60 const char kStorageAPN[] = "Cellular.APN";
61 const char kStorageLastGoodAPN[] = "Cellular.LastGoodAPN";
62 } // namespace
63
GetNonEmptyField(const Stringmap & stringmap,const string & fieldname,string * value)64 static bool GetNonEmptyField(const Stringmap& stringmap,
65 const string& fieldname,
66 string* value) {
67 Stringmap::const_iterator it = stringmap.find(fieldname);
68 if (it != stringmap.end() && !it->second.empty()) {
69 *value = it->second;
70 return true;
71 }
72 return false;
73 }
74
CellularService(ModemInfo * modem_info,const CellularRefPtr & device)75 CellularService::CellularService(ModemInfo* modem_info,
76 const CellularRefPtr& device)
77 : Service(modem_info->control_interface(), modem_info->dispatcher(),
78 modem_info->metrics(), modem_info->manager(),
79 Technology::kCellular),
80 weak_ptr_factory_(this),
81 activation_type_(kActivationTypeUnknown),
82 cellular_(device),
83 is_auto_connecting_(false) {
84 SetConnectable(true);
85 PropertyStore* store = this->mutable_store();
86 HelpRegisterDerivedString(kActivationTypeProperty,
87 &CellularService::CalculateActivationType,
88 nullptr);
89 store->RegisterConstString(kActivationStateProperty, &activation_state_);
90 HelpRegisterDerivedStringmap(kCellularApnProperty,
91 &CellularService::GetApn,
92 &CellularService::SetApn);
93 store->RegisterConstStringmap(kCellularLastGoodApnProperty,
94 &last_good_apn_info_);
95 store->RegisterConstString(kNetworkTechnologyProperty, &network_technology_);
96 HelpRegisterDerivedBool(kOutOfCreditsProperty,
97 &CellularService::IsOutOfCredits,
98 nullptr);
99 store->RegisterConstStringmap(kPaymentPortalProperty, &olp_);
100 store->RegisterConstString(kRoamingStateProperty, &roaming_state_);
101 store->RegisterConstStringmap(kServingOperatorProperty, &serving_operator_);
102 store->RegisterConstString(kUsageURLProperty, &usage_url_);
103 store->RegisterString(kCellularPPPUsernameProperty, &ppp_username_);
104 store->RegisterWriteOnlyString(kCellularPPPPasswordProperty, &ppp_password_);
105
106 set_friendly_name(cellular_->CreateDefaultFriendlyServiceName());
107 SetStorageIdentifier(string(kTypeCellular) + "_" +
108 cellular_->address() + "_" + friendly_name());
109 // Assume we are not performing any out-of-credits detection.
110 // The capability can reinitialize with the appropriate type later.
111 InitOutOfCreditsDetection(OutOfCreditsDetector::OOCTypeNone);
112 }
113
~CellularService()114 CellularService::~CellularService() { }
115
IsAutoConnectable(const char ** reason) const116 bool CellularService::IsAutoConnectable(const char** reason) const {
117 if (!cellular_->running()) {
118 *reason = kAutoConnDeviceDisabled;
119 return false;
120 }
121 if (cellular_->IsActivating()) {
122 *reason = kAutoConnActivating;
123 return false;
124 }
125 if (failure() == kFailurePPPAuth) {
126 *reason = kAutoConnBadPPPCredentials;
127 return false;
128 }
129 if (out_of_credits_detector_->IsDetecting()) {
130 *reason = kAutoConnOutOfCreditsDetectionInProgress;
131 return false;
132 }
133 if (out_of_credits_detector_->out_of_credits()) {
134 *reason = kAutoConnOutOfCredits;
135 return false;
136 }
137 return Service::IsAutoConnectable(reason);
138 }
139
HelpRegisterDerivedString(const string & name,string (CellularService::* get)(Error * error),bool (CellularService::* set)(const string & value,Error * error))140 void CellularService::HelpRegisterDerivedString(
141 const string& name,
142 string(CellularService::*get)(Error* error),
143 bool(CellularService::*set)(const string& value, Error* error)) {
144 mutable_store()->RegisterDerivedString(
145 name,
146 StringAccessor(
147 new CustomAccessor<CellularService, string>(this, get, set)));
148 }
149
HelpRegisterDerivedStringmap(const string & name,Stringmap (CellularService::* get)(Error * error),bool (CellularService::* set)(const Stringmap & value,Error * error))150 void CellularService::HelpRegisterDerivedStringmap(
151 const string& name,
152 Stringmap(CellularService::*get)(Error* error),
153 bool(CellularService::*set)(
154 const Stringmap& value, Error* error)) {
155 mutable_store()->RegisterDerivedStringmap(
156 name,
157 StringmapAccessor(
158 new CustomAccessor<CellularService, Stringmap>(this, get, set)));
159 }
160
HelpRegisterDerivedBool(const string & name,bool (CellularService::* get)(Error * error),bool (CellularService::* set)(const bool &,Error *))161 void CellularService::HelpRegisterDerivedBool(
162 const string& name,
163 bool(CellularService::*get)(Error* error),
164 bool(CellularService::*set)(const bool&, Error*)) {
165 mutable_store()->RegisterDerivedBool(
166 name,
167 BoolAccessor(new CustomAccessor<CellularService, bool>(this, get, set)));
168 }
169
GetUserSpecifiedApn()170 Stringmap* CellularService::GetUserSpecifiedApn() {
171 Stringmap::iterator it = apn_info_.find(kApnProperty);
172 if (it == apn_info_.end() || it->second.empty())
173 return nullptr;
174 return &apn_info_;
175 }
176
GetLastGoodApn()177 Stringmap* CellularService::GetLastGoodApn() {
178 Stringmap::iterator it = last_good_apn_info_.find(kApnProperty);
179 if (it == last_good_apn_info_.end() || it->second.empty())
180 return nullptr;
181 return &last_good_apn_info_;
182 }
183
CalculateActivationType(Error * error)184 string CellularService::CalculateActivationType(Error* error) {
185 return GetActivationTypeString();
186 }
187
GetApn(Error *)188 Stringmap CellularService::GetApn(Error* /*error*/) {
189 return apn_info_;
190 }
191
SetApn(const Stringmap & value,Error * error)192 bool CellularService::SetApn(const Stringmap& value, Error* error) {
193 // Only copy in the fields we care about, and validate the contents.
194 // If the "apn" field is missing or empty, the APN is cleared.
195 string str;
196 Stringmap new_apn_info;
197 if (GetNonEmptyField(value, kApnProperty, &str)) {
198 new_apn_info[kApnProperty] = str;
199 if (GetNonEmptyField(value, kApnUsernameProperty, &str))
200 new_apn_info[kApnUsernameProperty] = str;
201 if (GetNonEmptyField(value, kApnPasswordProperty, &str))
202 new_apn_info[kApnPasswordProperty] = str;
203 }
204 if (apn_info_ == new_apn_info) {
205 return false;
206 }
207 apn_info_ = new_apn_info;
208 if (ContainsKey(apn_info_, kApnProperty)) {
209 // Clear the last good APN, otherwise the one the user just
210 // set won't be used, since LastGoodApn comes first in the
211 // search order when trying to connect. Only do this if a
212 // non-empty user APN has been supplied. If the user APN is
213 // being cleared, leave LastGoodApn alone.
214 ClearLastGoodApn();
215 }
216 adaptor()->EmitStringmapChanged(kCellularApnProperty, apn_info_);
217 return true;
218 }
219
SetLastGoodApn(const Stringmap & apn_info)220 void CellularService::SetLastGoodApn(const Stringmap& apn_info) {
221 last_good_apn_info_ = apn_info;
222 adaptor()->EmitStringmapChanged(kCellularLastGoodApnProperty,
223 last_good_apn_info_);
224 }
225
ClearLastGoodApn()226 void CellularService::ClearLastGoodApn() {
227 last_good_apn_info_.clear();
228 adaptor()->EmitStringmapChanged(kCellularLastGoodApnProperty,
229 last_good_apn_info_);
230 }
231
OnAfterResume()232 void CellularService::OnAfterResume() {
233 Service::OnAfterResume();
234 resume_start_time_ = base::Time::Now();
235 }
236
InitOutOfCreditsDetection(OutOfCreditsDetector::OOCType ooc_type)237 void CellularService::InitOutOfCreditsDetection(
238 OutOfCreditsDetector::OOCType ooc_type) {
239 out_of_credits_detector_.reset(
240 OutOfCreditsDetector::CreateDetector(ooc_type,
241 dispatcher(),
242 manager(),
243 metrics(),
244 this));
245 }
246
Load(StoreInterface * storage)247 bool CellularService::Load(StoreInterface* storage) {
248 // Load properties common to all Services.
249 if (!Service::Load(storage))
250 return false;
251
252 const string id = GetStorageIdentifier();
253 LoadApn(storage, id, kStorageAPN, &apn_info_);
254 LoadApn(storage, id, kStorageLastGoodAPN, &last_good_apn_info_);
255
256 const string old_username = ppp_username_;
257 const string old_password = ppp_password_;
258 storage->GetString(id, kStoragePPPUsername, &ppp_username_);
259 storage->GetString(id, kStoragePPPPassword, &ppp_password_);
260 if (IsFailed() && failure() == kFailurePPPAuth &&
261 (old_username != ppp_username_ || old_password != ppp_password_)) {
262 SetState(kStateIdle);
263 }
264 return true;
265 }
266
LoadApn(StoreInterface * storage,const string & storage_group,const string & keytag,Stringmap * apn_info)267 void CellularService::LoadApn(StoreInterface* storage,
268 const string& storage_group,
269 const string& keytag,
270 Stringmap* apn_info) {
271 if (!LoadApnField(storage, storage_group, keytag, kApnProperty, apn_info))
272 return;
273 LoadApnField(storage, storage_group, keytag, kApnUsernameProperty, apn_info);
274 LoadApnField(storage, storage_group, keytag, kApnPasswordProperty, apn_info);
275 }
276
LoadApnField(StoreInterface * storage,const string & storage_group,const string & keytag,const string & apntag,Stringmap * apn_info)277 bool CellularService::LoadApnField(StoreInterface* storage,
278 const string& storage_group,
279 const string& keytag,
280 const string& apntag,
281 Stringmap* apn_info) {
282 string value;
283 if (storage->GetString(storage_group, keytag + "." + apntag, &value) &&
284 !value.empty()) {
285 (*apn_info)[apntag] = value;
286 return true;
287 }
288 return false;
289 }
290
Save(StoreInterface * storage)291 bool CellularService::Save(StoreInterface* storage) {
292 // Save properties common to all Services.
293 if (!Service::Save(storage))
294 return false;
295
296 const string id = GetStorageIdentifier();
297 SaveApn(storage, id, GetUserSpecifiedApn(), kStorageAPN);
298 SaveApn(storage, id, GetLastGoodApn(), kStorageLastGoodAPN);
299 SaveString(storage, id, kStoragePPPUsername, ppp_username_, false, true);
300 SaveString(storage, id, kStoragePPPPassword, ppp_password_, false, true);
301 return true;
302 }
303
SaveApn(StoreInterface * storage,const string & storage_group,const Stringmap * apn_info,const string & keytag)304 void CellularService::SaveApn(StoreInterface* storage,
305 const string& storage_group,
306 const Stringmap* apn_info,
307 const string& keytag) {
308 SaveApnField(storage, storage_group, apn_info, keytag, kApnProperty);
309 SaveApnField(storage, storage_group, apn_info, keytag, kApnUsernameProperty);
310 SaveApnField(storage, storage_group, apn_info, keytag, kApnPasswordProperty);
311 }
312
SaveApnField(StoreInterface * storage,const string & storage_group,const Stringmap * apn_info,const string & keytag,const string & apntag)313 void CellularService::SaveApnField(StoreInterface* storage,
314 const string& storage_group,
315 const Stringmap* apn_info,
316 const string& keytag,
317 const string& apntag) {
318 const string key = keytag + "." + apntag;
319 string str;
320 if (apn_info && GetNonEmptyField(*apn_info, apntag, &str))
321 storage->SetString(storage_group, key, str);
322 else
323 storage->DeleteKey(storage_group, key);
324 }
325
IsOutOfCredits(Error *)326 bool CellularService::IsOutOfCredits(Error* /*error*/) {
327 return out_of_credits_detector_->out_of_credits();
328 }
329
set_out_of_credits_detector(OutOfCreditsDetector * detector)330 void CellularService::set_out_of_credits_detector(
331 OutOfCreditsDetector* detector) {
332 out_of_credits_detector_.reset(detector);
333 }
334
SignalOutOfCreditsChanged(bool state) const335 void CellularService::SignalOutOfCreditsChanged(bool state) const {
336 adaptor()->EmitBoolChanged(kOutOfCreditsProperty, state);
337 }
338
AutoConnect()339 void CellularService::AutoConnect() {
340 is_auto_connecting_ = true;
341 Service::AutoConnect();
342 is_auto_connecting_ = false;
343 }
344
Connect(Error * error,const char * reason)345 void CellularService::Connect(Error* error, const char* reason) {
346 Service::Connect(error, reason);
347 cellular_->Connect(error);
348 if (error->IsFailure())
349 out_of_credits_detector_->ResetDetector();
350 }
351
Disconnect(Error * error,const char * reason)352 void CellularService::Disconnect(Error* error, const char* reason) {
353 Service::Disconnect(error, reason);
354 cellular_->Disconnect(error, reason);
355 }
356
ActivateCellularModem(const string & carrier,Error * error,const ResultCallback & callback)357 void CellularService::ActivateCellularModem(const string& carrier,
358 Error* error,
359 const ResultCallback& callback) {
360 cellular_->Activate(carrier, error, callback);
361 }
362
CompleteCellularActivation(Error * error)363 void CellularService::CompleteCellularActivation(Error* error) {
364 cellular_->CompleteActivation(error);
365 }
366
SetState(ConnectState new_state)367 void CellularService::SetState(ConnectState new_state) {
368 out_of_credits_detector_->NotifyServiceStateChanged(state(), new_state);
369 Service::SetState(new_state);
370 }
371
SetStorageIdentifier(const string & identifier)372 void CellularService::SetStorageIdentifier(const string& identifier) {
373 SLOG(this, 3) << __func__ << ": " << identifier;
374 storage_identifier_ = identifier;
375 std::replace_if(storage_identifier_.begin(),
376 storage_identifier_.end(),
377 &Service::IllegalChar, '_');
378 }
379
GetStorageIdentifier() const380 string CellularService::GetStorageIdentifier() const {
381 return storage_identifier_;
382 }
383
GetDeviceRpcId(Error *) const384 string CellularService::GetDeviceRpcId(Error* /*error*/) const {
385 return cellular_->GetRpcIdentifier();
386 }
387
SetActivationType(ActivationType type)388 void CellularService::SetActivationType(ActivationType type) {
389 if (type == activation_type_) {
390 return;
391 }
392 activation_type_ = type;
393 adaptor()->EmitStringChanged(kActivationTypeProperty,
394 GetActivationTypeString());
395 }
396
GetActivationTypeString() const397 string CellularService::GetActivationTypeString() const {
398 switch (activation_type_) {
399 case kActivationTypeNonCellular:
400 return shill::kActivationTypeNonCellular;
401 case kActivationTypeOMADM:
402 return shill::kActivationTypeOMADM;
403 case kActivationTypeOTA:
404 return shill::kActivationTypeOTA;
405 case kActivationTypeOTASP:
406 return shill::kActivationTypeOTASP;
407 case kActivationTypeUnknown:
408 return "";
409 default:
410 NOTREACHED();
411 return ""; // Make compiler happy.
412 }
413 }
414
SetActivationState(const string & state)415 void CellularService::SetActivationState(const string& state) {
416 if (state == activation_state_) {
417 return;
418 }
419 activation_state_ = state;
420 adaptor()->EmitStringChanged(kActivationStateProperty, state);
421 SetConnectableFull(state != kActivationStateNotActivated);
422 }
423
SetOLP(const string & url,const string & method,const string & post_data)424 void CellularService::SetOLP(const string& url,
425 const string& method,
426 const string& post_data) {
427 Stringmap olp;
428 olp[kPaymentPortalURL] = url;
429 olp[kPaymentPortalMethod] = method;
430 olp[kPaymentPortalPostData] = post_data;
431
432 if (olp_ == olp) {
433 return;
434 }
435 olp_ = olp;
436 adaptor()->EmitStringmapChanged(kPaymentPortalProperty, olp);
437 }
438
SetUsageURL(const string & url)439 void CellularService::SetUsageURL(const string& url) {
440 if (url == usage_url_) {
441 return;
442 }
443 usage_url_ = url;
444 adaptor()->EmitStringChanged(kUsageURLProperty, url);
445 }
446
SetNetworkTechnology(const string & technology)447 void CellularService::SetNetworkTechnology(const string& technology) {
448 if (technology == network_technology_) {
449 return;
450 }
451 network_technology_ = technology;
452 adaptor()->EmitStringChanged(kNetworkTechnologyProperty,
453 technology);
454 }
455
SetRoamingState(const string & state)456 void CellularService::SetRoamingState(const string& state) {
457 if (state == roaming_state_) {
458 return;
459 }
460 roaming_state_ = state;
461 adaptor()->EmitStringChanged(kRoamingStateProperty, state);
462 }
463
set_serving_operator(const Stringmap & serving_operator)464 void CellularService::set_serving_operator(const Stringmap& serving_operator) {
465 if (serving_operator_ == serving_operator)
466 return;
467
468 serving_operator_ = serving_operator;
469 adaptor()->EmitStringmapChanged(kServingOperatorProperty, serving_operator_);
470 }
471
472 } // namespace shill
473