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