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; 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 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 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 114 CellularService::~CellularService() { } 115 116 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 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 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 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 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 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 184 string CellularService::CalculateActivationType(Error* error) { 185 return GetActivationTypeString(); 186 } 187 188 Stringmap CellularService::GetApn(Error* /*error*/) { 189 return apn_info_; 190 } 191 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 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 226 void CellularService::ClearLastGoodApn() { 227 last_good_apn_info_.clear(); 228 adaptor()->EmitStringmapChanged(kCellularLastGoodApnProperty, 229 last_good_apn_info_); 230 } 231 232 void CellularService::OnAfterResume() { 233 Service::OnAfterResume(); 234 resume_start_time_ = base::Time::Now(); 235 } 236 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 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 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 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 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 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 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 326 bool CellularService::IsOutOfCredits(Error* /*error*/) { 327 return out_of_credits_detector_->out_of_credits(); 328 } 329 330 void CellularService::set_out_of_credits_detector( 331 OutOfCreditsDetector* detector) { 332 out_of_credits_detector_.reset(detector); 333 } 334 335 void CellularService::SignalOutOfCreditsChanged(bool state) const { 336 adaptor()->EmitBoolChanged(kOutOfCreditsProperty, state); 337 } 338 339 void CellularService::AutoConnect() { 340 is_auto_connecting_ = true; 341 Service::AutoConnect(); 342 is_auto_connecting_ = false; 343 } 344 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 352 void CellularService::Disconnect(Error* error, const char* reason) { 353 Service::Disconnect(error, reason); 354 cellular_->Disconnect(error, reason); 355 } 356 357 void CellularService::ActivateCellularModem(const string& carrier, 358 Error* error, 359 const ResultCallback& callback) { 360 cellular_->Activate(carrier, error, callback); 361 } 362 363 void CellularService::CompleteCellularActivation(Error* error) { 364 cellular_->CompleteActivation(error); 365 } 366 367 void CellularService::SetState(ConnectState new_state) { 368 out_of_credits_detector_->NotifyServiceStateChanged(state(), new_state); 369 Service::SetState(new_state); 370 } 371 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 380 string CellularService::GetStorageIdentifier() const { 381 return storage_identifier_; 382 } 383 384 string CellularService::GetDeviceRpcId(Error* /*error*/) const { 385 return cellular_->GetRpcIdentifier(); 386 } 387 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 397 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 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 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 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 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 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 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