1 // 2 // Copyright (C) 2013 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_capability_universal_cdma.h" 18 19 #include <base/strings/string_number_conversions.h> 20 #include <base/strings/string_util.h> 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/cellular/cellular_bearer.h" 29 #include "shill/cellular/cellular_service.h" 30 #include "shill/control_interface.h" 31 #include "shill/dbus_properties_proxy_interface.h" 32 #include "shill/error.h" 33 #include "shill/logging.h" 34 #include "shill/pending_activation_store.h" 35 36 #ifdef MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN 37 #error "Do not include mm-modem.h" 38 #endif 39 40 using base::UintToString; 41 42 using std::string; 43 using std::vector; 44 45 namespace shill { 46 47 namespace Logging { 48 static auto kModuleLogScope = ScopeLogger::kCellular; 49 static string ObjectID(CellularCapabilityUniversalCDMA* c) { 50 return c->cellular()->GetRpcIdentifier(); 51 } 52 } 53 54 namespace { 55 56 const char kPhoneNumber[] = "#777"; 57 const char kPropertyConnectNumber[] = "number"; 58 59 } // namespace 60 61 CellularCapabilityUniversalCDMA::CellularCapabilityUniversalCDMA( 62 Cellular* cellular, 63 ControlInterface* control_interface, 64 ModemInfo* modem_info) 65 : CellularCapabilityUniversal(cellular, control_interface, modem_info), 66 weak_cdma_ptr_factory_(this), 67 activation_state_(MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED), 68 cdma_1x_registration_state_(MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN), 69 cdma_evdo_registration_state_(MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN), 70 nid_(0), 71 sid_(0) { 72 SLOG(this, 2) << "Cellular capability constructed: Universal CDMA"; 73 // TODO(armansito): Update PRL for activation over cellular. 74 // See crbug.com/197330. 75 } 76 77 CellularCapabilityUniversalCDMA::~CellularCapabilityUniversalCDMA() {} 78 79 void CellularCapabilityUniversalCDMA::InitProxies() { 80 SLOG(this, 2) << __func__; 81 modem_cdma_proxy_.reset( 82 control_interface()->CreateMM1ModemModemCdmaProxy( 83 cellular()->dbus_path(), cellular()->dbus_service())); 84 modem_cdma_proxy_->set_activation_state_callback( 85 Bind(&CellularCapabilityUniversalCDMA::OnActivationStateChangedSignal, 86 weak_cdma_ptr_factory_.GetWeakPtr())); 87 CellularCapabilityUniversal::InitProxies(); 88 } 89 90 void CellularCapabilityUniversalCDMA::ReleaseProxies() { 91 SLOG(this, 2) << __func__; 92 modem_cdma_proxy_.reset(); 93 CellularCapabilityUniversal::ReleaseProxies(); 94 } 95 96 void CellularCapabilityUniversalCDMA::Activate(const string& carrier, 97 Error* error, 98 const ResultCallback& callback) { 99 // Currently activation over the cellular network is not supported using 100 // ModemManager-next. Service activation is currently carried through over 101 // non-cellular networks and only the final step of the OTA activation 102 // procedure ("automatic activation") is performed by this class. 103 OnUnsupportedOperation(__func__, error); 104 } 105 106 void CellularCapabilityUniversalCDMA::CompleteActivation(Error* error) { 107 SLOG(this, 2) << __func__; 108 if (cellular()->state() < Cellular::kStateEnabled) { 109 Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments, 110 "Unable to activate in state " + 111 Cellular::GetStateString(cellular()->state())); 112 return; 113 } 114 ActivateAutomatic(); 115 } 116 117 void CellularCapabilityUniversalCDMA::ActivateAutomatic() { 118 if (!cellular()->serving_operator_info()->IsMobileNetworkOperatorKnown() || 119 cellular()->serving_operator_info()->activation_code().empty()) { 120 SLOG(this, 2) << "OTA activation cannot be run in the presence of no " 121 << "activation code."; 122 return; 123 } 124 125 PendingActivationStore::State state = 126 modem_info()->pending_activation_store()->GetActivationState( 127 PendingActivationStore::kIdentifierMEID, cellular()->meid()); 128 if (state == PendingActivationStore::kStatePending) { 129 SLOG(this, 2) << "There's already a pending activation. Ignoring."; 130 return; 131 } 132 if (state == PendingActivationStore::kStateActivated) { 133 SLOG(this, 2) << "A call to OTA activation has already completed " 134 << "successfully. Ignoring."; 135 return; 136 } 137 138 // Mark as pending activation, so that shill can recover if anything fails 139 // during OTA activation. 140 modem_info()->pending_activation_store()->SetActivationState( 141 PendingActivationStore::kIdentifierMEID, 142 cellular()->meid(), 143 PendingActivationStore::kStatePending); 144 145 // Initiate OTA activation. 146 ResultCallback activation_callback = 147 Bind(&CellularCapabilityUniversalCDMA::OnActivateReply, 148 weak_cdma_ptr_factory_.GetWeakPtr(), 149 ResultCallback()); 150 151 Error error; 152 modem_cdma_proxy_->Activate( 153 cellular()->serving_operator_info()->activation_code(), 154 &error, 155 activation_callback, 156 kTimeoutActivate); 157 } 158 159 void CellularCapabilityUniversalCDMA::UpdatePendingActivationState() { 160 SLOG(this, 2) << __func__; 161 if (IsActivated()) { 162 SLOG(this, 3) << "CDMA service activated. Clear store."; 163 modem_info()->pending_activation_store()->RemoveEntry( 164 PendingActivationStore::kIdentifierMEID, cellular()->meid()); 165 return; 166 } 167 PendingActivationStore::State state = 168 modem_info()->pending_activation_store()->GetActivationState( 169 PendingActivationStore::kIdentifierMEID, cellular()->meid()); 170 if (IsActivating() && state != PendingActivationStore::kStateFailureRetry) { 171 SLOG(this, 3) << "OTA activation in progress. Nothing to do."; 172 return; 173 } 174 switch (state) { 175 case PendingActivationStore::kStateFailureRetry: 176 SLOG(this, 3) << "OTA activation failed. Scheduling a retry."; 177 cellular()->dispatcher()->PostTask( 178 Bind(&CellularCapabilityUniversalCDMA::ActivateAutomatic, 179 weak_cdma_ptr_factory_.GetWeakPtr())); 180 break; 181 case PendingActivationStore::kStateActivated: 182 SLOG(this, 3) << "OTA Activation has completed successfully. " 183 << "Waiting for activation state update to finalize."; 184 break; 185 default: 186 break; 187 } 188 } 189 190 bool CellularCapabilityUniversalCDMA::IsServiceActivationRequired() const { 191 // If there is no online payment portal information, it's safer to assume 192 // the service does not require activation. 193 if (!cellular()->serving_operator_info()->IsMobileNetworkOperatorKnown() || 194 cellular()->serving_operator_info()->olp_list().empty()) { 195 return false; 196 } 197 198 // We could also use the MDN to determine whether or not the service is 199 // activated, however, the CDMA ActivatonState property is a more absolute 200 // and fine-grained indicator of activation status. 201 return (activation_state_ == MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED); 202 } 203 204 bool CellularCapabilityUniversalCDMA::IsActivated() const { 205 return (activation_state_ == MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED); 206 } 207 208 void CellularCapabilityUniversalCDMA::OnServiceCreated() { 209 SLOG(this, 2) << __func__; 210 cellular()->service()->SetActivationType( 211 CellularService::kActivationTypeOTASP); 212 UpdateServiceActivationStateProperty(); 213 HandleNewActivationStatus(MM_CDMA_ACTIVATION_ERROR_NONE); 214 UpdatePendingActivationState(); 215 } 216 217 void CellularCapabilityUniversalCDMA::UpdateServiceActivationStateProperty() { 218 string activation_state; 219 if (IsActivating()) 220 activation_state = kActivationStateActivating; 221 else if (IsServiceActivationRequired()) 222 activation_state = kActivationStateNotActivated; 223 else 224 activation_state = kActivationStateActivated; 225 cellular()->service()->SetActivationState(activation_state); 226 } 227 228 void CellularCapabilityUniversalCDMA::UpdateServiceOLP() { 229 SLOG(this, 2) << __func__; 230 231 // In this case, the Home Provider is trivial. All information comes from the 232 // Serving Operator. 233 if (!cellular()->serving_operator_info()->IsMobileNetworkOperatorKnown()) { 234 return; 235 } 236 237 const vector<MobileOperatorInfo::OnlinePortal>& olp_list = 238 cellular()->serving_operator_info()->olp_list(); 239 if (olp_list.empty()) { 240 return; 241 } 242 243 if (olp_list.size() > 1) { 244 SLOG(this, 1) << "Found multiple online portals. Choosing the first."; 245 } 246 string post_data = olp_list[0].post_data; 247 base::ReplaceSubstringsAfterOffset(&post_data, 0, "${esn}", 248 cellular()->esn()); 249 base::ReplaceSubstringsAfterOffset( 250 &post_data, 0, "${mdn}", 251 GetMdnForOLP(cellular()->serving_operator_info())); 252 base::ReplaceSubstringsAfterOffset(&post_data, 0, 253 "${meid}", cellular()->meid()); 254 base::ReplaceSubstringsAfterOffset(&post_data, 0, "${oem}", "GOG2"); 255 cellular()->service()->SetOLP(olp_list[0].url, olp_list[0].method, post_data); 256 } 257 258 void CellularCapabilityUniversalCDMA::GetProperties() { 259 SLOG(this, 2) << __func__; 260 CellularCapabilityUniversal::GetProperties(); 261 262 std::unique_ptr<DBusPropertiesProxyInterface> properties_proxy( 263 control_interface()->CreateDBusPropertiesProxy( 264 cellular()->dbus_path(), cellular()->dbus_service())); 265 266 KeyValueStore properties( 267 properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM_MODEMCDMA)); 268 OnModemCDMAPropertiesChanged(properties, vector<string>()); 269 } 270 271 void CellularCapabilityUniversalCDMA::OnActivationStateChangedSignal( 272 uint32_t activation_state, 273 uint32_t activation_error, 274 const KeyValueStore& status_changes) { 275 SLOG(this, 2) << __func__; 276 277 activation_state_ = 278 static_cast<MMModemCdmaActivationState>(activation_state); 279 280 string value; 281 if (status_changes.ContainsString("mdn")) 282 cellular()->set_mdn(status_changes.GetString("mdn")); 283 if (status_changes.ContainsString("min")) 284 cellular()->set_min(status_changes.GetString("min")); 285 SLOG(this, 2) << "Activation state: " 286 << GetActivationStateString(activation_state_); 287 288 HandleNewActivationStatus(activation_error); 289 UpdatePendingActivationState(); 290 } 291 292 void CellularCapabilityUniversalCDMA::OnActivateReply( 293 const ResultCallback& callback, 294 const Error& error) { 295 SLOG(this, 2) << __func__; 296 if (error.IsSuccess()) { 297 LOG(INFO) << "Activation completed successfully."; 298 modem_info()->pending_activation_store()->SetActivationState( 299 PendingActivationStore::kIdentifierMEID, 300 cellular()->meid(), 301 PendingActivationStore::kStateActivated); 302 } else { 303 LOG(ERROR) << "Activation failed with error: " << error; 304 modem_info()->pending_activation_store()->SetActivationState( 305 PendingActivationStore::kIdentifierMEID, 306 cellular()->meid(), 307 PendingActivationStore::kStateFailureRetry); 308 } 309 UpdatePendingActivationState(); 310 311 // CellularCapabilityUniversalCDMA::ActivateAutomatic passes a dummy 312 // ResultCallback when it calls Activate on the proxy object, in which case 313 // |callback.is_null()| will return true. 314 if (!callback.is_null()) 315 callback.Run(error); 316 } 317 318 void CellularCapabilityUniversalCDMA::HandleNewActivationStatus( 319 uint32_t error) { 320 SLOG(this, 2) << __func__ << "(" << error << ")"; 321 if (!cellular()->service().get()) { 322 LOG(ERROR) << "In " << __func__ << "(): service is null."; 323 return; 324 } 325 SLOG(this, 2) << "Activation State: " << activation_state_; 326 cellular()->service()->SetActivationState( 327 GetActivationStateString(activation_state_)); 328 cellular()->service()->set_error(GetActivationErrorString(error)); 329 UpdateServiceOLP(); 330 } 331 332 // static 333 string CellularCapabilityUniversalCDMA::GetActivationStateString( 334 uint32_t state) { 335 switch (state) { 336 case MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED: 337 return kActivationStateActivated; 338 case MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING: 339 return kActivationStateActivating; 340 case MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED: 341 return kActivationStateNotActivated; 342 case MM_MODEM_CDMA_ACTIVATION_STATE_PARTIALLY_ACTIVATED: 343 return kActivationStatePartiallyActivated; 344 default: 345 return kActivationStateUnknown; 346 } 347 } 348 349 // static 350 string CellularCapabilityUniversalCDMA::GetActivationErrorString( 351 uint32_t error) { 352 switch (error) { 353 case MM_CDMA_ACTIVATION_ERROR_WRONG_RADIO_INTERFACE: 354 return kErrorNeedEvdo; 355 case MM_CDMA_ACTIVATION_ERROR_ROAMING: 356 return kErrorNeedHomeNetwork; 357 case MM_CDMA_ACTIVATION_ERROR_COULD_NOT_CONNECT: 358 case MM_CDMA_ACTIVATION_ERROR_SECURITY_AUTHENTICATION_FAILED: 359 case MM_CDMA_ACTIVATION_ERROR_PROVISIONING_FAILED: 360 return kErrorOtaspFailed; 361 case MM_CDMA_ACTIVATION_ERROR_NONE: 362 return ""; 363 case MM_CDMA_ACTIVATION_ERROR_NO_SIGNAL: 364 default: 365 return kErrorActivationFailed; 366 } 367 } 368 369 void CellularCapabilityUniversalCDMA::Register(const ResultCallback& callback) { 370 // TODO(armansito): Remove once 3GPP is implemented in its own class. 371 } 372 373 void CellularCapabilityUniversalCDMA::RegisterOnNetwork( 374 const string& network_id, 375 Error* error, 376 const ResultCallback& callback) { 377 // TODO(armansito): Remove once 3GPP is implemented in its own class. 378 } 379 380 bool CellularCapabilityUniversalCDMA::IsActivating() const { 381 PendingActivationStore::State state = 382 modem_info()->pending_activation_store()->GetActivationState( 383 PendingActivationStore::kIdentifierMEID, cellular()->meid()); 384 return (state == PendingActivationStore::kStatePending) || 385 (state == PendingActivationStore::kStateFailureRetry) || 386 (activation_state_ == MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING); 387 } 388 389 bool CellularCapabilityUniversalCDMA::IsRegistered() const { 390 return (cdma_1x_registration_state_ != 391 MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN || 392 cdma_evdo_registration_state_ != 393 MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN); 394 } 395 396 void CellularCapabilityUniversalCDMA::SetUnregistered(bool /*searching*/) { 397 cdma_1x_registration_state_ = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN; 398 cdma_evdo_registration_state_ = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN; 399 } 400 401 void CellularCapabilityUniversalCDMA::SetupConnectProperties( 402 KeyValueStore* properties) { 403 properties->SetString(kPropertyConnectNumber, kPhoneNumber); 404 } 405 406 void CellularCapabilityUniversalCDMA::RequirePIN( 407 const string& pin, bool require, 408 Error* error, const ResultCallback& callback) { 409 // TODO(armansito): Remove once 3GPP is implemented in its own class. 410 } 411 412 void CellularCapabilityUniversalCDMA::EnterPIN( 413 const string& pin, 414 Error* error, 415 const ResultCallback& callback) { 416 // TODO(armansito): Remove once 3GPP is implemented in its own class. 417 } 418 419 void CellularCapabilityUniversalCDMA::UnblockPIN( 420 const string& unblock_code, 421 const string& pin, 422 Error* error, 423 const ResultCallback& callback) { 424 // TODO(armansito): Remove once 3GPP is implemented in its own class. 425 } 426 427 void CellularCapabilityUniversalCDMA::ChangePIN( 428 const string& old_pin, const string& new_pin, 429 Error* error, const ResultCallback& callback) { 430 // TODO(armansito): Remove once 3GPP is implemented in its own class. 431 } 432 433 void CellularCapabilityUniversalCDMA::Scan( 434 Error* error, 435 const ResultStringmapsCallback& callback) { 436 // TODO(armansito): Remove once 3GPP is implemented in its own class. 437 OnUnsupportedOperation(__func__, error); 438 } 439 440 void CellularCapabilityUniversalCDMA::OnSimPathChanged( 441 const string& sim_path) { 442 // TODO(armansito): Remove once 3GPP is implemented in its own class. 443 } 444 445 string CellularCapabilityUniversalCDMA::GetRoamingStateString() const { 446 uint32_t state = cdma_evdo_registration_state_; 447 if (state == MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN) { 448 state = cdma_1x_registration_state_; 449 } 450 switch (state) { 451 case MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN: 452 case MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED: 453 break; 454 case MM_MODEM_CDMA_REGISTRATION_STATE_HOME: 455 return kRoamingStateHome; 456 case MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING: 457 return kRoamingStateRoaming; 458 default: 459 NOTREACHED(); 460 } 461 return kRoamingStateUnknown; 462 } 463 464 void CellularCapabilityUniversalCDMA::OnPropertiesChanged( 465 const string& interface, 466 const KeyValueStore& changed_properties, 467 const vector<string>& invalidated_properties) { 468 SLOG(this, 2) << __func__ << "(" << interface << ")"; 469 if (interface == MM_DBUS_INTERFACE_MODEM_MODEMCDMA) { 470 OnModemCDMAPropertiesChanged(changed_properties, invalidated_properties); 471 } else { 472 CellularCapabilityUniversal::OnPropertiesChanged( 473 interface, changed_properties, invalidated_properties); 474 } 475 } 476 477 void CellularCapabilityUniversalCDMA::OnModemCDMAPropertiesChanged( 478 const KeyValueStore& properties, 479 const std::vector<std::string>& /*invalidated_properties*/) { 480 SLOG(this, 2) << __func__; 481 string str_value; 482 if (properties.ContainsString(MM_MODEM_MODEMCDMA_PROPERTY_MEID)) { 483 cellular()->set_meid( 484 properties.GetString(MM_MODEM_MODEMCDMA_PROPERTY_MEID)); 485 } 486 if (properties.ContainsString(MM_MODEM_MODEMCDMA_PROPERTY_ESN)) { 487 cellular()->set_esn(properties.GetString(MM_MODEM_MODEMCDMA_PROPERTY_ESN)); 488 } 489 490 uint32_t sid = sid_; 491 uint32_t nid = nid_; 492 MMModemCdmaRegistrationState state_1x = cdma_1x_registration_state_; 493 MMModemCdmaRegistrationState state_evdo = cdma_evdo_registration_state_; 494 bool registration_changed = false; 495 if (properties.ContainsUint( 496 MM_MODEM_MODEMCDMA_PROPERTY_CDMA1XREGISTRATIONSTATE)) { 497 state_1x = static_cast<MMModemCdmaRegistrationState>( 498 properties.GetUint( 499 MM_MODEM_MODEMCDMA_PROPERTY_CDMA1XREGISTRATIONSTATE)); 500 registration_changed = true; 501 } 502 if (properties.ContainsUint( 503 MM_MODEM_MODEMCDMA_PROPERTY_EVDOREGISTRATIONSTATE)) { 504 state_evdo = static_cast<MMModemCdmaRegistrationState>( 505 properties.GetUint(MM_MODEM_MODEMCDMA_PROPERTY_EVDOREGISTRATIONSTATE)); 506 registration_changed = true; 507 } 508 if (properties.ContainsUint(MM_MODEM_MODEMCDMA_PROPERTY_SID)) { 509 sid = properties.GetUint(MM_MODEM_MODEMCDMA_PROPERTY_SID); 510 registration_changed = true; 511 } 512 if (properties.ContainsUint(MM_MODEM_MODEMCDMA_PROPERTY_NID)) { 513 nid = properties.GetUint(MM_MODEM_MODEMCDMA_PROPERTY_NID); 514 registration_changed = true; 515 } 516 if (properties.ContainsUint(MM_MODEM_MODEMCDMA_PROPERTY_ACTIVATIONSTATE)) { 517 activation_state_ = static_cast<MMModemCdmaActivationState>( 518 properties.GetUint(MM_MODEM_MODEMCDMA_PROPERTY_ACTIVATIONSTATE)); 519 HandleNewActivationStatus(MM_CDMA_ACTIVATION_ERROR_NONE); 520 } 521 if (registration_changed) 522 OnCDMARegistrationChanged(state_1x, state_evdo, sid, nid); 523 } 524 525 void CellularCapabilityUniversalCDMA::OnCDMARegistrationChanged( 526 MMModemCdmaRegistrationState state_1x, 527 MMModemCdmaRegistrationState state_evdo, 528 uint32_t sid, uint32_t nid) { 529 SLOG(this, 2) << __func__ << ": state_1x=" << state_1x 530 << ", state_evdo=" << state_evdo; 531 cdma_1x_registration_state_ = state_1x; 532 cdma_evdo_registration_state_ = state_evdo; 533 sid_ = sid; 534 nid_ = nid; 535 cellular()->serving_operator_info()->UpdateSID(UintToString(sid)); 536 cellular()->serving_operator_info()->UpdateNID(UintToString(nid)); 537 cellular()->HandleNewRegistrationState(); 538 } 539 540 } // namespace shill 541