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.h" 18 19 #include <base/bind.h> 20 #include <base/stl_util.h> 21 #include <base/strings/string_util.h> 22 #include <base/strings/stringprintf.h> 23 #if defined(__ANDROID__) 24 #include <dbus/service_constants.h> 25 #else 26 #include <chromeos/dbus/service_constants.h> 27 #endif // __ANDROID__ 28 #include <ModemManager/ModemManager.h> 29 30 #include <string> 31 #include <vector> 32 33 #include "shill/adaptor_interfaces.h" 34 #include "shill/cellular/cellular_bearer.h" 35 #include "shill/cellular/cellular_service.h" 36 #include "shill/cellular/mobile_operator_info.h" 37 #include "shill/control_interface.h" 38 #include "shill/dbus_properties_proxy_interface.h" 39 #include "shill/error.h" 40 #include "shill/logging.h" 41 #include "shill/pending_activation_store.h" 42 #include "shill/property_accessor.h" 43 44 #ifdef MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN 45 #error "Do not include mm-modem.h" 46 #endif 47 48 using base::Bind; 49 using base::Closure; 50 using std::string; 51 using std::vector; 52 53 namespace shill { 54 55 namespace Logging { 56 static auto kModuleLogScope = ScopeLogger::kCellular; 57 static string ObjectID(CellularCapabilityUniversal* c) { 58 return c->cellular()->GetRpcIdentifier(); 59 } 60 } 61 62 // static 63 const char CellularCapabilityUniversal::kConnectPin[] = "pin"; 64 const char CellularCapabilityUniversal::kConnectOperatorId[] = "operator-id"; 65 const char CellularCapabilityUniversal::kConnectApn[] = "apn"; 66 const char CellularCapabilityUniversal::kConnectIPType[] = "ip-type"; 67 const char CellularCapabilityUniversal::kConnectUser[] = "user"; 68 const char CellularCapabilityUniversal::kConnectPassword[] = "password"; 69 const char CellularCapabilityUniversal::kConnectNumber[] = "number"; 70 const char CellularCapabilityUniversal::kConnectAllowRoaming[] = 71 "allow-roaming"; 72 const char CellularCapabilityUniversal::kConnectRMProtocol[] = "rm-protocol"; 73 const int64_t CellularCapabilityUniversal::kEnterPinTimeoutMilliseconds = 20000; 74 const int64_t 75 CellularCapabilityUniversal::kRegistrationDroppedUpdateTimeoutMilliseconds = 76 15000; 77 const char CellularCapabilityUniversal::kRootPath[] = "/"; 78 const char CellularCapabilityUniversal::kStatusProperty[] = "status"; 79 const char CellularCapabilityUniversal::kOperatorLongProperty[] = 80 "operator-long"; 81 const char CellularCapabilityUniversal::kOperatorShortProperty[] = 82 "operator-short"; 83 const char CellularCapabilityUniversal::kOperatorCodeProperty[] = 84 "operator-code"; 85 const char CellularCapabilityUniversal::kOperatorAccessTechnologyProperty[] = 86 "access-technology"; 87 const char CellularCapabilityUniversal::kAltairLTEMMPlugin[] = "Altair LTE"; 88 const char CellularCapabilityUniversal::kNovatelLTEMMPlugin[] = "Novatel LTE"; 89 const int CellularCapabilityUniversal::kSetPowerStateTimeoutMilliseconds = 90 20000; 91 92 namespace { 93 94 const char kPhoneNumber[] = "*99#"; 95 96 // This identifier is specified in the serviceproviders.prototxt file. 97 const char kVzwIdentifier[] = "c83d6597-dc91-4d48-a3a7-d86b80123751"; 98 const size_t kVzwMdnLength = 10; 99 100 string AccessTechnologyToString(uint32_t access_technologies) { 101 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_LTE) 102 return kNetworkTechnologyLte; 103 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 | 104 MM_MODEM_ACCESS_TECHNOLOGY_EVDOA | 105 MM_MODEM_ACCESS_TECHNOLOGY_EVDOB)) 106 return kNetworkTechnologyEvdo; 107 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_1XRTT) 108 return kNetworkTechnology1Xrtt; 109 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS) 110 return kNetworkTechnologyHspaPlus; 111 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_HSPA | 112 MM_MODEM_ACCESS_TECHNOLOGY_HSUPA | 113 MM_MODEM_ACCESS_TECHNOLOGY_HSDPA)) 114 return kNetworkTechnologyHspa; 115 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_UMTS) 116 return kNetworkTechnologyUmts; 117 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_EDGE) 118 return kNetworkTechnologyEdge; 119 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_GPRS) 120 return kNetworkTechnologyGprs; 121 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT | 122 MM_MODEM_ACCESS_TECHNOLOGY_GSM)) 123 return kNetworkTechnologyGsm; 124 return ""; 125 } 126 127 string AccessTechnologyToTechnologyFamily(uint32_t access_technologies) { 128 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_LTE | 129 MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS | 130 MM_MODEM_ACCESS_TECHNOLOGY_HSPA | 131 MM_MODEM_ACCESS_TECHNOLOGY_HSUPA | 132 MM_MODEM_ACCESS_TECHNOLOGY_HSDPA | 133 MM_MODEM_ACCESS_TECHNOLOGY_UMTS | 134 MM_MODEM_ACCESS_TECHNOLOGY_EDGE | 135 MM_MODEM_ACCESS_TECHNOLOGY_GPRS | 136 MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT | 137 MM_MODEM_ACCESS_TECHNOLOGY_GSM)) 138 return kTechnologyFamilyGsm; 139 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 | 140 MM_MODEM_ACCESS_TECHNOLOGY_EVDOA | 141 MM_MODEM_ACCESS_TECHNOLOGY_EVDOB | 142 MM_MODEM_ACCESS_TECHNOLOGY_1XRTT)) 143 return kTechnologyFamilyCdma; 144 return ""; 145 } 146 147 } // namespace 148 149 CellularCapabilityUniversal::CellularCapabilityUniversal( 150 Cellular* cellular, 151 ControlInterface* control_interface, 152 ModemInfo* modem_info) 153 : CellularCapability(cellular, control_interface, modem_info), 154 mobile_operator_info_(new MobileOperatorInfo(cellular->dispatcher(), 155 "ParseScanResult")), 156 weak_ptr_factory_(this), 157 registration_state_(MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN), 158 current_capabilities_(MM_MODEM_CAPABILITY_NONE), 159 access_technologies_(MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN), 160 resetting_(false), 161 subscription_state_(kSubscriptionStateUnknown), 162 reset_done_(false), 163 registration_dropped_update_timeout_milliseconds_( 164 kRegistrationDroppedUpdateTimeoutMilliseconds) { 165 SLOG(this, 2) << "Cellular capability constructed: Universal"; 166 mobile_operator_info_->Init(); 167 HelpRegisterConstDerivedKeyValueStore( 168 kSIMLockStatusProperty, 169 &CellularCapabilityUniversal::SimLockStatusToProperty); 170 } 171 172 CellularCapabilityUniversal::~CellularCapabilityUniversal() {} 173 174 KeyValueStore CellularCapabilityUniversal::SimLockStatusToProperty( 175 Error* /*error*/) { 176 KeyValueStore status; 177 string lock_type; 178 switch (sim_lock_status_.lock_type) { 179 case MM_MODEM_LOCK_SIM_PIN: 180 lock_type = "sim-pin"; 181 break; 182 case MM_MODEM_LOCK_SIM_PUK: 183 lock_type = "sim-puk"; 184 break; 185 default: 186 lock_type = ""; 187 break; 188 } 189 status.SetBool(kSIMLockEnabledProperty, sim_lock_status_.enabled); 190 status.SetString(kSIMLockTypeProperty, lock_type); 191 status.SetUint(kSIMLockRetriesLeftProperty, sim_lock_status_.retries_left); 192 return status; 193 } 194 195 void CellularCapabilityUniversal::HelpRegisterConstDerivedKeyValueStore( 196 const string& name, 197 KeyValueStore(CellularCapabilityUniversal::*get)(Error* error)) { 198 cellular()->mutable_store()->RegisterDerivedKeyValueStore( 199 name, 200 KeyValueStoreAccessor( 201 new CustomAccessor<CellularCapabilityUniversal, KeyValueStore>( 202 this, get, nullptr))); 203 } 204 205 void CellularCapabilityUniversal::InitProxies() { 206 modem_3gpp_proxy_.reset( 207 control_interface()->CreateMM1ModemModem3gppProxy( 208 cellular()->dbus_path(), cellular()->dbus_service())); 209 modem_proxy_.reset( 210 control_interface()->CreateMM1ModemProxy(cellular()->dbus_path(), 211 cellular()->dbus_service())); 212 modem_simple_proxy_.reset( 213 control_interface()->CreateMM1ModemSimpleProxy( 214 cellular()->dbus_path(), cellular()->dbus_service())); 215 216 modem_proxy_->set_state_changed_callback( 217 Bind(&CellularCapabilityUniversal::OnModemStateChangedSignal, 218 weak_ptr_factory_.GetWeakPtr())); 219 // Do not create a SIM proxy until the device is enabled because we 220 // do not yet know the object path of the sim object. 221 // TODO(jglasgow): register callbacks 222 } 223 224 void CellularCapabilityUniversal::StartModem(Error* error, 225 const ResultCallback& callback) { 226 SLOG(this, 3) << __func__; 227 InitProxies(); 228 deferred_enable_modem_callback_.Reset(); 229 EnableModem(true, error, callback); 230 } 231 232 void CellularCapabilityUniversal::EnableModem(bool deferrable, 233 Error* error, 234 const ResultCallback& callback) { 235 SLOG(this, 3) << __func__ << "(deferrable=" << deferrable << ")"; 236 CHECK(!callback.is_null()); 237 Error local_error(Error::kOperationInitiated); 238 modem_info()->metrics()->NotifyDeviceEnableStarted( 239 cellular()->interface_index()); 240 modem_proxy_->Enable( 241 true, 242 &local_error, 243 Bind(&CellularCapabilityUniversal::EnableModemCompleted, 244 weak_ptr_factory_.GetWeakPtr(), deferrable, callback), 245 kTimeoutEnable); 246 if (local_error.IsFailure()) { 247 SLOG(this, 2) << __func__ << "Call to modem_proxy_->Enable() failed"; 248 } 249 if (error) { 250 error->CopyFrom(local_error); 251 } 252 } 253 254 void CellularCapabilityUniversal::EnableModemCompleted( 255 bool deferrable, const ResultCallback& callback, const Error& error) { 256 SLOG(this, 3) << __func__ << "(deferrable=" << deferrable 257 << ", error=" << error << ")"; 258 259 // If the enable operation failed with Error::kWrongState, the modem is not 260 // in the expected state (i.e. disabled). If |deferrable| indicates that the 261 // enable operation can be deferred, we defer the operation until the modem 262 // goes into the expected state (see OnModemStateChangedSignal). 263 // 264 // Note that when the SIM is locked, the enable operation also fails with 265 // Error::kWrongState. The enable operation is deferred until the modem goes 266 // into the disabled state after the SIM is unlocked. We may choose not to 267 // defer the enable operation when the SIM is locked, but the UI needs to 268 // trigger the enable operation after the SIM is unlocked, which is currently 269 // not the case. 270 if (error.IsFailure()) { 271 if (!deferrable || error.type() != Error::kWrongState) { 272 callback.Run(error); 273 return; 274 } 275 276 if (deferred_enable_modem_callback_.is_null()) { 277 SLOG(this, 2) << "Defer enable operation."; 278 // The Enable operation to be deferred should not be further deferrable. 279 deferred_enable_modem_callback_ = 280 Bind(&CellularCapabilityUniversal::EnableModem, 281 weak_ptr_factory_.GetWeakPtr(), 282 false, // non-deferrable 283 nullptr, 284 callback); 285 } 286 return; 287 } 288 289 // After modem is enabled, it should be possible to get properties 290 // TODO(jglasgow): handle errors from GetProperties 291 GetProperties(); 292 // We expect the modem to start scanning after it has been enabled. 293 // Change this if this behavior is no longer the case in the future. 294 modem_info()->metrics()->NotifyDeviceEnableFinished( 295 cellular()->interface_index()); 296 modem_info()->metrics()->NotifyDeviceScanStarted( 297 cellular()->interface_index()); 298 callback.Run(error); 299 } 300 301 void CellularCapabilityUniversal::StopModem(Error* error, 302 const ResultCallback& callback) { 303 CHECK(!callback.is_null()); 304 CHECK(error); 305 // If there is an outstanding registration change, simply ignore it since 306 // the service will be destroyed anyway. 307 if (!registration_dropped_update_callback_.IsCancelled()) { 308 registration_dropped_update_callback_.Cancel(); 309 SLOG(this, 2) << __func__ << " Cancelled delayed deregister."; 310 } 311 312 // Some modems will implicitly disconnect the bearer when transitioning to 313 // low power state. For such modems, it's faster to let the modem disconnect 314 // the bearer. To do that, we just remove the bearer from the list so 315 // ModemManager doesn't try to disconnect it during disable. 316 Closure task; 317 if (cellular()->mm_plugin() == kAltairLTEMMPlugin) { 318 task = Bind(&CellularCapabilityUniversal::Stop_DeleteActiveBearer, 319 weak_ptr_factory_.GetWeakPtr(), 320 callback); 321 } else { 322 task = Bind(&CellularCapabilityUniversal::Stop_Disable, 323 weak_ptr_factory_.GetWeakPtr(), 324 callback); 325 } 326 cellular()->dispatcher()->PostTask(task); 327 deferred_enable_modem_callback_.Reset(); 328 } 329 330 void CellularCapabilityUniversal::Stop_DeleteActiveBearer( 331 const ResultCallback& callback) { 332 SLOG(this, 3) << __func__; 333 334 if (!active_bearer_) { 335 Stop_Disable(callback); 336 return; 337 } 338 339 Error error; 340 modem_proxy_->DeleteBearer( 341 active_bearer_->dbus_path(), &error, 342 Bind(&CellularCapabilityUniversal::Stop_DeleteActiveBearerCompleted, 343 weak_ptr_factory_.GetWeakPtr(), callback), 344 kTimeoutDefault); 345 if (error.IsFailure()) 346 callback.Run(error); 347 } 348 349 void CellularCapabilityUniversal::Stop_DeleteActiveBearerCompleted( 350 const ResultCallback& callback, const Error& error) { 351 SLOG(this, 3) << __func__; 352 // Disregard the error from the bearer deletion since the disable will clean 353 // up any remaining bearers. 354 Stop_Disable(callback); 355 } 356 357 void CellularCapabilityUniversal::Stop_Disable(const ResultCallback& callback) { 358 SLOG(this, 3) << __func__; 359 Error error; 360 modem_info()->metrics()->NotifyDeviceDisableStarted( 361 cellular()->interface_index()); 362 modem_proxy_->Enable( 363 false, &error, 364 Bind(&CellularCapabilityUniversal::Stop_DisableCompleted, 365 weak_ptr_factory_.GetWeakPtr(), callback), 366 kTimeoutEnable); 367 if (error.IsFailure()) 368 callback.Run(error); 369 } 370 371 void CellularCapabilityUniversal::Stop_DisableCompleted( 372 const ResultCallback& callback, const Error& error) { 373 SLOG(this, 3) << __func__; 374 375 if (error.IsSuccess()) { 376 // The modem has been successfully disabled, but we still need to power it 377 // down. 378 Stop_PowerDown(callback); 379 } else { 380 // An error occurred; terminate the disable sequence. 381 callback.Run(error); 382 } 383 } 384 385 void CellularCapabilityUniversal::Stop_PowerDown( 386 const ResultCallback& callback) { 387 SLOG(this, 3) << __func__; 388 Error error; 389 modem_proxy_->SetPowerState( 390 MM_MODEM_POWER_STATE_LOW, 391 &error, 392 Bind(&CellularCapabilityUniversal::Stop_PowerDownCompleted, 393 weak_ptr_factory_.GetWeakPtr(), callback), 394 kSetPowerStateTimeoutMilliseconds); 395 396 if (error.IsFailure()) 397 // This really shouldn't happen, but if it does, report success, 398 // because a stop initiated power down is only called if the 399 // modem was successfully disabled, but the failure of this 400 // operation should still be propagated up as a successful disable. 401 Stop_PowerDownCompleted(callback, error); 402 } 403 404 // Note: if we were in the middle of powering down the modem when the 405 // system suspended, we might not get this event from 406 // ModemManager. And we might not even get a timeout from dbus-c++, 407 // because StartModem re-initializes proxies. 408 void CellularCapabilityUniversal::Stop_PowerDownCompleted( 409 const ResultCallback& callback, 410 const Error& error) { 411 SLOG(this, 3) << __func__; 412 413 if (error.IsFailure()) 414 SLOG(this, 2) << "Ignoring error returned by SetPowerState: " << error; 415 416 // Since the disable succeeded, if power down fails, we currently fail 417 // silently, i.e. we need to report the disable operation as having 418 // succeeded. 419 modem_info()->metrics()->NotifyDeviceDisableFinished( 420 cellular()->interface_index()); 421 ReleaseProxies(); 422 callback.Run(Error()); 423 } 424 425 void CellularCapabilityUniversal::Connect(const KeyValueStore& properties, 426 Error* error, 427 const ResultCallback& callback) { 428 SLOG(this, 3) << __func__; 429 RpcIdentifierCallback cb = Bind(&CellularCapabilityUniversal::OnConnectReply, 430 weak_ptr_factory_.GetWeakPtr(), 431 callback); 432 modem_simple_proxy_->Connect(properties, error, cb, kTimeoutConnect); 433 } 434 435 void CellularCapabilityUniversal::Disconnect(Error* error, 436 const ResultCallback& callback) { 437 SLOG(this, 3) << __func__; 438 if (modem_simple_proxy_.get()) { 439 SLOG(this, 2) << "Disconnect all bearers."; 440 // If "/" is passed as the bearer path, ModemManager will disconnect all 441 // bearers. 442 modem_simple_proxy_->Disconnect(kRootPath, 443 error, 444 callback, 445 kTimeoutDisconnect); 446 } 447 } 448 449 void CellularCapabilityUniversal::CompleteActivation(Error* error) { 450 SLOG(this, 3) << __func__; 451 452 // Persist the ICCID as "Pending Activation". 453 // We're assuming that when this function gets called, 454 // |cellular()->sim_identifier()| will be non-empty. We still check here that 455 // is non-empty, though something is wrong if it is empty. 456 const string& sim_identifier = cellular()->sim_identifier(); 457 if (sim_identifier.empty()) { 458 SLOG(this, 2) << "SIM identifier not available. Nothing to do."; 459 return; 460 } 461 462 modem_info()->pending_activation_store()->SetActivationState( 463 PendingActivationStore::kIdentifierICCID, 464 sim_identifier, 465 PendingActivationStore::kStatePending); 466 UpdatePendingActivationState(); 467 468 SLOG(this, 2) << "Resetting modem for activation."; 469 ResetAfterActivation(); 470 } 471 472 void CellularCapabilityUniversal::ResetAfterActivation() { 473 SLOG(this, 3) << __func__; 474 475 // Here the initial call to Reset might fail in rare cases. Simply ignore. 476 Error error; 477 ResultCallback callback = Bind( 478 &CellularCapabilityUniversal::OnResetAfterActivationReply, 479 weak_ptr_factory_.GetWeakPtr()); 480 Reset(&error, callback); 481 if (error.IsFailure()) 482 SLOG(this, 2) << "Failed to reset after activation."; 483 } 484 485 void CellularCapabilityUniversal::OnResetAfterActivationReply( 486 const Error& error) { 487 SLOG(this, 3) << __func__; 488 if (error.IsFailure()) { 489 SLOG(this, 2) << "Failed to reset after activation. Try again later."; 490 // TODO(armansito): Maybe post a delayed reset task? 491 return; 492 } 493 reset_done_ = true; 494 UpdatePendingActivationState(); 495 } 496 497 void CellularCapabilityUniversal::UpdatePendingActivationState() { 498 SLOG(this, 3) << __func__; 499 500 const string& sim_identifier = cellular()->sim_identifier(); 501 bool registered = 502 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME; 503 504 // We know a service is activated if |subscription_state_| is 505 // kSubscriptionStateProvisioned / kSubscriptionStateOutOfData 506 // In the case that |subscription_state_| is kSubscriptionStateUnknown, we 507 // fallback on checking for a valid MDN. 508 bool activated = 509 ((subscription_state_ == kSubscriptionStateProvisioned) || 510 (subscription_state_ == kSubscriptionStateOutOfData)) || 511 ((subscription_state_ == kSubscriptionStateUnknown) && IsMdnValid()); 512 513 if (activated && !sim_identifier.empty()) 514 modem_info()->pending_activation_store()->RemoveEntry( 515 PendingActivationStore::kIdentifierICCID, 516 sim_identifier); 517 518 CellularServiceRefPtr service = cellular()->service(); 519 520 if (!service.get()) 521 return; 522 523 if (service->activation_state() == kActivationStateActivated) 524 // Either no service or already activated. Nothing to do. 525 return; 526 527 // If the ICCID is not available, the following logic can be delayed until it 528 // becomes available. 529 if (sim_identifier.empty()) 530 return; 531 532 PendingActivationStore::State state = 533 modem_info()->pending_activation_store()->GetActivationState( 534 PendingActivationStore::kIdentifierICCID, 535 sim_identifier); 536 switch (state) { 537 case PendingActivationStore::kStatePending: 538 // Always mark the service as activating here, as the ICCID could have 539 // been unavailable earlier. 540 service->SetActivationState(kActivationStateActivating); 541 if (reset_done_) { 542 SLOG(this, 2) << "Post-payment activation reset complete."; 543 modem_info()->pending_activation_store()->SetActivationState( 544 PendingActivationStore::kIdentifierICCID, 545 sim_identifier, 546 PendingActivationStore::kStateActivated); 547 } 548 break; 549 case PendingActivationStore::kStateActivated: 550 if (registered) { 551 // Trigger auto connect here. 552 SLOG(this, 2) << "Modem has been reset at least once, try to " 553 << "autoconnect to force MDN to update."; 554 service->AutoConnect(); 555 } 556 break; 557 case PendingActivationStore::kStateUnknown: 558 // No entry exists for this ICCID. Nothing to do. 559 break; 560 default: 561 NOTREACHED(); 562 } 563 } 564 565 string CellularCapabilityUniversal::GetMdnForOLP( 566 const MobileOperatorInfo* operator_info) const { 567 // TODO(benchan): This is ugly. Remove carrier specific code once we move 568 // mobile activation logic to carrier-specifc extensions (crbug.com/260073). 569 const string& mdn = cellular()->mdn(); 570 if (!operator_info->IsMobileNetworkOperatorKnown()) { 571 // Can't make any carrier specific modifications. 572 return mdn; 573 } 574 575 if (operator_info->uuid() == kVzwIdentifier) { 576 // subscription_state_ is the definitive indicator of whether we need 577 // activation. The OLP expects an all zero MDN in that case. 578 if (subscription_state_ == kSubscriptionStateUnprovisioned || mdn.empty()) { 579 return string(kVzwMdnLength, '0'); 580 } 581 if (mdn.length() > kVzwMdnLength) { 582 return mdn.substr(mdn.length() - kVzwMdnLength); 583 } 584 } 585 return mdn; 586 } 587 588 void CellularCapabilityUniversal::ReleaseProxies() { 589 SLOG(this, 3) << __func__; 590 modem_3gpp_proxy_.reset(); 591 modem_proxy_.reset(); 592 modem_simple_proxy_.reset(); 593 sim_proxy_.reset(); 594 } 595 596 bool CellularCapabilityUniversal::AreProxiesInitialized() const { 597 return (modem_3gpp_proxy_.get() && modem_proxy_.get() && 598 modem_simple_proxy_.get() && sim_proxy_.get()); 599 } 600 601 void CellularCapabilityUniversal::UpdateServiceActivationState() { 602 if (!cellular()->service().get()) 603 return; 604 605 const string& sim_identifier = cellular()->sim_identifier(); 606 string activation_state; 607 PendingActivationStore::State state = 608 modem_info()->pending_activation_store()->GetActivationState( 609 PendingActivationStore::kIdentifierICCID, 610 sim_identifier); 611 if ((subscription_state_ == kSubscriptionStateUnknown || 612 subscription_state_ == kSubscriptionStateUnprovisioned) && 613 !sim_identifier.empty() && 614 state == PendingActivationStore::kStatePending) { 615 activation_state = kActivationStateActivating; 616 } else if (IsServiceActivationRequired()) { 617 activation_state = kActivationStateNotActivated; 618 } else { 619 activation_state = kActivationStateActivated; 620 621 // Mark an activated service for auto-connect by default. Since data from 622 // the user profile will be loaded after the call to OnServiceCreated, this 623 // property will be corrected based on the user data at that time. 624 // NOTE: This function can be called outside the service initialization 625 // path so make sure we don't overwrite the auto-connect setting. 626 if (cellular()->service()->activation_state() != activation_state) 627 cellular()->service()->SetAutoConnect(true); 628 } 629 cellular()->service()->SetActivationState(activation_state); 630 } 631 632 void CellularCapabilityUniversal::OnServiceCreated() { 633 cellular()->service()->SetActivationType(CellularService::kActivationTypeOTA); 634 UpdateServiceActivationState(); 635 636 // WORKAROUND: 637 // E362 modems on Verizon network does not properly redirect when a SIM 638 // runs out of credits, we need to enforce out-of-credits detection. 639 // 640 // The out-of-credits detection is also needed on ALT3100 modems until the PCO 641 // support is ready (crosbug.com/p/20461). 642 cellular()->service()->InitOutOfCreditsDetection( 643 GetOutOfCreditsDetectionType()); 644 645 // Make sure that the network technology is set when the service gets 646 // created, just in case. 647 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString()); 648 } 649 650 // Create the list of APNs to try, in the following order: 651 // - last APN that resulted in a successful connection attempt on the 652 // current network (if any) 653 // - the APN, if any, that was set by the user 654 // - the list of APNs found in the mobile broadband provider DB for the 655 // home provider associated with the current SIM 656 // - as a last resort, attempt to connect with no APN 657 void CellularCapabilityUniversal::SetupApnTryList() { 658 apn_try_list_.clear(); 659 660 DCHECK(cellular()->service().get()); 661 const Stringmap* apn_info = cellular()->service()->GetLastGoodApn(); 662 if (apn_info) 663 apn_try_list_.push_back(*apn_info); 664 665 apn_info = cellular()->service()->GetUserSpecifiedApn(); 666 if (apn_info) 667 apn_try_list_.push_back(*apn_info); 668 669 apn_try_list_.insert(apn_try_list_.end(), 670 cellular()->apn_list().begin(), 671 cellular()->apn_list().end()); 672 } 673 674 void CellularCapabilityUniversal::SetupConnectProperties( 675 KeyValueStore* properties) { 676 SetupApnTryList(); 677 FillConnectPropertyMap(properties); 678 } 679 680 void CellularCapabilityUniversal::FillConnectPropertyMap( 681 KeyValueStore* properties) { 682 683 // TODO(jglasgow): Is this really needed anymore? 684 properties->SetString(kConnectNumber, kPhoneNumber); 685 686 properties->SetBool(kConnectAllowRoaming, AllowRoaming()); 687 688 if (!apn_try_list_.empty()) { 689 // Leave the APN at the front of the list, so that it can be recorded 690 // if the connect attempt succeeds. 691 Stringmap apn_info = apn_try_list_.front(); 692 SLOG(this, 2) << __func__ << ": Using APN " << apn_info[kApnProperty]; 693 properties->SetString(kConnectApn, apn_info[kApnProperty]); 694 if (ContainsKey(apn_info, kApnUsernameProperty)) 695 properties->SetString(kConnectUser, apn_info[kApnUsernameProperty]); 696 if (ContainsKey(apn_info, kApnPasswordProperty)) 697 properties->SetString(kConnectPassword, apn_info[kApnPasswordProperty]); 698 } 699 } 700 701 void CellularCapabilityUniversal::OnConnectReply(const ResultCallback& callback, 702 const string& path, 703 const Error& error) { 704 SLOG(this, 3) << __func__ << "(" << error << ")"; 705 706 CellularServiceRefPtr service = cellular()->service(); 707 if (!service) { 708 // The service could have been deleted before our Connect() request 709 // completes if the modem was enabled and then quickly disabled. 710 apn_try_list_.clear(); 711 } else if (error.IsFailure()) { 712 service->ClearLastGoodApn(); 713 // The APN that was just tried (and failed) is still at the 714 // front of the list, about to be removed. If the list is empty 715 // after that, try one last time without an APN. This may succeed 716 // with some modems in some cases. 717 if (RetriableConnectError(error) && !apn_try_list_.empty()) { 718 apn_try_list_.pop_front(); 719 SLOG(this, 2) << "Connect failed with invalid APN, " 720 << apn_try_list_.size() << " remaining APNs to try"; 721 KeyValueStore props; 722 FillConnectPropertyMap(&props); 723 Error error; 724 Connect(props, &error, callback); 725 return; 726 } 727 } else { 728 if (!apn_try_list_.empty()) { 729 service->SetLastGoodApn(apn_try_list_.front()); 730 apn_try_list_.clear(); 731 } 732 SLOG(this, 2) << "Connected bearer " << path; 733 } 734 735 if (!callback.is_null()) 736 callback.Run(error); 737 738 UpdatePendingActivationState(); 739 } 740 741 bool CellularCapabilityUniversal::AllowRoaming() { 742 return cellular()->provider_requires_roaming() || allow_roaming_property(); 743 } 744 745 void CellularCapabilityUniversal::GetProperties() { 746 SLOG(this, 3) << __func__; 747 748 std::unique_ptr<DBusPropertiesProxyInterface> properties_proxy( 749 control_interface()->CreateDBusPropertiesProxy( 750 cellular()->dbus_path(), cellular()->dbus_service())); 751 752 KeyValueStore properties( 753 properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM)); 754 OnModemPropertiesChanged(properties, vector<string>()); 755 756 properties = properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM_MODEM3GPP); 757 OnModem3GPPPropertiesChanged(properties, vector<string>()); 758 } 759 760 void CellularCapabilityUniversal::UpdateServiceOLP() { 761 SLOG(this, 3) << __func__; 762 763 // OLP is based off of the Home Provider. 764 if (!cellular()->home_provider_info()->IsMobileNetworkOperatorKnown()) { 765 return; 766 } 767 768 const vector<MobileOperatorInfo::OnlinePortal>& olp_list = 769 cellular()->home_provider_info()->olp_list(); 770 if (olp_list.empty()) { 771 return; 772 } 773 774 if (olp_list.size() > 1) { 775 SLOG(this, 1) << "Found multiple online portals. Choosing the first."; 776 } 777 string post_data = olp_list[0].post_data; 778 base::ReplaceSubstringsAfterOffset( 779 &post_data, 0, "${iccid}", cellular()->sim_identifier()); 780 base::ReplaceSubstringsAfterOffset( 781 &post_data, 0, "${imei}", cellular()->imei()); 782 base::ReplaceSubstringsAfterOffset( 783 &post_data, 0, "${imsi}", cellular()->imsi()); 784 base::ReplaceSubstringsAfterOffset( 785 &post_data, 0, "${mdn}", GetMdnForOLP(cellular()->home_provider_info())); 786 base::ReplaceSubstringsAfterOffset( 787 &post_data, 0, "${min}", cellular()->min()); 788 cellular()->service()->SetOLP(olp_list[0].url, olp_list[0].method, post_data); 789 } 790 791 void CellularCapabilityUniversal::UpdateActiveBearer() { 792 SLOG(this, 3) << __func__; 793 794 // Look for the first active bearer and use its path as the connected 795 // one. Right now, we don't allow more than one active bearer. 796 active_bearer_.reset(); 797 for (const auto& path : bearer_paths_) { 798 std::unique_ptr<CellularBearer> bearer( 799 new CellularBearer(control_interface(), 800 path, 801 cellular()->dbus_service())); 802 // The bearer object may have vanished before ModemManager updates the 803 // 'Bearers' property. 804 if (!bearer->Init()) 805 continue; 806 807 if (!bearer->connected()) 808 continue; 809 810 SLOG(this, 2) << "Found active bearer \"" << path << "\"."; 811 CHECK(!active_bearer_) << "Found more than one active bearer."; 812 active_bearer_ = std::move(bearer); 813 } 814 815 if (!active_bearer_) 816 SLOG(this, 2) << "No active bearer found."; 817 } 818 819 bool CellularCapabilityUniversal::IsServiceActivationRequired() const { 820 const string& sim_identifier = cellular()->sim_identifier(); 821 // subscription_state_ is the definitive answer. If that does not work, 822 // fallback on MDN based logic. 823 if (subscription_state_ == kSubscriptionStateProvisioned || 824 subscription_state_ == kSubscriptionStateOutOfData) 825 return false; 826 827 // We are in the process of activating, ignore all other clues from the 828 // network and use our own knowledge about the activation state. 829 if (!sim_identifier.empty() && 830 modem_info()->pending_activation_store()->GetActivationState( 831 PendingActivationStore::kIdentifierICCID, 832 sim_identifier) != PendingActivationStore::kStateUnknown) 833 return false; 834 835 // Network notification that the service needs to be activated. 836 if (subscription_state_ == kSubscriptionStateUnprovisioned) 837 return true; 838 839 // If there is no online payment portal information, it's safer to assume 840 // the service does not require activation. 841 if (!cellular()->home_provider_info()->IsMobileNetworkOperatorKnown() || 842 cellular()->home_provider_info()->olp_list().empty()) { 843 return false; 844 } 845 846 // If the MDN is invalid (i.e. empty or contains only zeros), the service 847 // requires activation. 848 return !IsMdnValid(); 849 } 850 851 bool CellularCapabilityUniversal::IsMdnValid() const { 852 const string& mdn = cellular()->mdn(); 853 // Note that |mdn| is normalized to contain only digits in OnMdnChanged(). 854 for (size_t i = 0; i < mdn.size(); ++i) { 855 if (mdn[i] != '0') 856 return true; 857 } 858 return false; 859 } 860 861 // always called from an async context 862 void CellularCapabilityUniversal::Register(const ResultCallback& callback) { 863 SLOG(this, 3) << __func__ << " \"" << cellular()->selected_network() 864 << "\""; 865 CHECK(!callback.is_null()); 866 Error error; 867 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply, 868 weak_ptr_factory_.GetWeakPtr(), callback); 869 modem_3gpp_proxy_->Register(cellular()->selected_network(), &error, cb, 870 kTimeoutRegister); 871 if (error.IsFailure()) 872 callback.Run(error); 873 } 874 875 void CellularCapabilityUniversal::RegisterOnNetwork( 876 const string& network_id, 877 Error* error, 878 const ResultCallback& callback) { 879 SLOG(this, 3) << __func__ << "(" << network_id << ")"; 880 CHECK(error); 881 desired_network_ = network_id; 882 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply, 883 weak_ptr_factory_.GetWeakPtr(), callback); 884 modem_3gpp_proxy_->Register(network_id, error, cb, kTimeoutRegister); 885 } 886 887 void CellularCapabilityUniversal::OnRegisterReply( 888 const ResultCallback& callback, 889 const Error& error) { 890 SLOG(this, 3) << __func__ << "(" << error << ")"; 891 892 if (error.IsSuccess()) { 893 cellular()->set_selected_network(desired_network_); 894 desired_network_.clear(); 895 callback.Run(error); 896 return; 897 } 898 // If registration on the desired network failed, 899 // try to register on the home network. 900 if (!desired_network_.empty()) { 901 desired_network_.clear(); 902 cellular()->set_selected_network(""); 903 LOG(INFO) << "Couldn't register on selected network, trying home network"; 904 Register(callback); 905 return; 906 } 907 callback.Run(error); 908 } 909 910 bool CellularCapabilityUniversal::IsRegistered() const { 911 return IsRegisteredState(registration_state_); 912 } 913 914 bool CellularCapabilityUniversal::IsRegisteredState( 915 MMModem3gppRegistrationState state) { 916 return (state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME || 917 state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING); 918 } 919 920 void CellularCapabilityUniversal::SetUnregistered(bool searching) { 921 // If we're already in some non-registered state, don't override that 922 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME || 923 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) { 924 registration_state_ = 925 (searching ? MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING : 926 MM_MODEM_3GPP_REGISTRATION_STATE_IDLE); 927 } 928 } 929 930 void CellularCapabilityUniversal::RequirePIN( 931 const string& pin, bool require, 932 Error* error, const ResultCallback& callback) { 933 CHECK(error); 934 sim_proxy_->EnablePin(pin, require, error, callback, kTimeoutDefault); 935 } 936 937 void CellularCapabilityUniversal::EnterPIN(const string& pin, 938 Error* error, 939 const ResultCallback& callback) { 940 CHECK(error); 941 SLOG(this, 3) << __func__; 942 sim_proxy_->SendPin(pin, error, callback, kEnterPinTimeoutMilliseconds); 943 } 944 945 void CellularCapabilityUniversal::UnblockPIN(const string& unblock_code, 946 const string& pin, 947 Error* error, 948 const ResultCallback& callback) { 949 CHECK(error); 950 sim_proxy_->SendPuk(unblock_code, pin, error, callback, kTimeoutDefault); 951 } 952 953 void CellularCapabilityUniversal::ChangePIN( 954 const string& old_pin, const string& new_pin, 955 Error* error, const ResultCallback& callback) { 956 CHECK(error); 957 sim_proxy_->ChangePin(old_pin, new_pin, error, callback, kTimeoutDefault); 958 } 959 960 void CellularCapabilityUniversal::Reset(Error* error, 961 const ResultCallback& callback) { 962 SLOG(this, 3) << __func__; 963 CHECK(error); 964 if (resetting_) { 965 Error::PopulateAndLog(FROM_HERE, error, Error::kInProgress, 966 "Already resetting"); 967 return; 968 } 969 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnResetReply, 970 weak_ptr_factory_.GetWeakPtr(), callback); 971 modem_proxy_->Reset(error, cb, kTimeoutReset); 972 if (!error->IsFailure()) { 973 resetting_ = true; 974 } 975 } 976 977 void CellularCapabilityUniversal::OnResetReply(const ResultCallback& callback, 978 const Error& error) { 979 SLOG(this, 3) << __func__; 980 resetting_ = false; 981 if (!callback.is_null()) 982 callback.Run(error); 983 } 984 985 void CellularCapabilityUniversal::Scan( 986 Error* error, 987 const ResultStringmapsCallback& callback) { 988 KeyValueStoresCallback cb = Bind(&CellularCapabilityUniversal::OnScanReply, 989 weak_ptr_factory_.GetWeakPtr(), callback); 990 modem_3gpp_proxy_->Scan(error, cb, kTimeoutScan); 991 } 992 993 void CellularCapabilityUniversal::OnScanReply( 994 const ResultStringmapsCallback& callback, 995 const ScanResults& results, 996 const Error& error) { 997 Stringmaps found_networks; 998 for (const auto& result : results) 999 found_networks.push_back(ParseScanResult(result)); 1000 callback.Run(found_networks, error); 1001 } 1002 1003 Stringmap CellularCapabilityUniversal::ParseScanResult( 1004 const ScanResult& result) { 1005 1006 /* ScanResults contain the following keys: 1007 1008 "status" 1009 A MMModem3gppNetworkAvailability value representing network 1010 availability status, given as an unsigned integer (signature "u"). 1011 This key will always be present. 1012 1013 "operator-long" 1014 Long-format name of operator, given as a string value (signature 1015 "s"). If the name is unknown, this field should not be present. 1016 1017 "operator-short" 1018 Short-format name of operator, given as a string value 1019 (signature "s"). If the name is unknown, this field should not 1020 be present. 1021 1022 "operator-code" 1023 Mobile code of the operator, given as a string value (signature 1024 "s"). Returned in the format "MCCMNC", where MCC is the 1025 three-digit ITU E.212 Mobile Country Code and MNC is the two- or 1026 three-digit GSM Mobile Network Code. e.g. "31026" or "310260". 1027 1028 "access-technology" 1029 A MMModemAccessTechnology value representing the generic access 1030 technology used by this mobile network, given as an unsigned 1031 integer (signature "u"). 1032 */ 1033 Stringmap parsed; 1034 1035 if (result.ContainsUint(kStatusProperty)) { 1036 uint32_t status = result.GetUint(kStatusProperty); 1037 // numerical values are taken from 3GPP TS 27.007 Section 7.3. 1038 static const char* const kStatusString[] = { 1039 "unknown", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_UNKNOWN 1040 "available", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_AVAILABLE 1041 "current", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_CURRENT 1042 "forbidden", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_FORBIDDEN 1043 }; 1044 parsed[kStatusProperty] = kStatusString[status]; 1045 } 1046 1047 // MMModemAccessTechnology 1048 if (result.ContainsUint(kOperatorAccessTechnologyProperty)) { 1049 parsed[kTechnologyProperty] = 1050 AccessTechnologyToString( 1051 result.GetUint(kOperatorAccessTechnologyProperty)); 1052 } 1053 1054 string operator_long, operator_short, operator_code; 1055 if (result.ContainsString(kOperatorLongProperty)) 1056 parsed[kLongNameProperty] = result.GetString(kOperatorLongProperty); 1057 if (result.ContainsString(kOperatorShortProperty)) 1058 parsed[kShortNameProperty] = result.GetString(kOperatorShortProperty); 1059 if (result.ContainsString(kOperatorCodeProperty)) 1060 parsed[kNetworkIdProperty] = result.GetString(kOperatorCodeProperty); 1061 1062 // If the long name is not available but the network ID is, look up the long 1063 // name in the mobile provider database. 1064 if ((!ContainsKey(parsed, kLongNameProperty) || 1065 parsed[kLongNameProperty].empty()) && 1066 ContainsKey(parsed, kNetworkIdProperty)) { 1067 mobile_operator_info_->Reset(); 1068 mobile_operator_info_->UpdateMCCMNC(parsed[kNetworkIdProperty]); 1069 if (mobile_operator_info_->IsMobileNetworkOperatorKnown() && 1070 !mobile_operator_info_->operator_name().empty()) { 1071 parsed[kLongNameProperty] = mobile_operator_info_->operator_name(); 1072 } 1073 } 1074 return parsed; 1075 } 1076 1077 CellularBearer* CellularCapabilityUniversal::GetActiveBearer() const { 1078 return active_bearer_.get(); 1079 } 1080 1081 string CellularCapabilityUniversal::GetNetworkTechnologyString() const { 1082 // If we know that the modem is an E362 modem supported by the Novatel LTE 1083 // plugin, return LTE here to make sure that Chrome sees LTE as the network 1084 // technology even if the actual technology is unknown. 1085 // 1086 // This hack will cause the UI to display LTE even if the modem doesn't 1087 // support it at a given time. This might be problematic if we ever want to 1088 // support switching between access technologies (e.g. falling back to 3G 1089 // when LTE is not available). 1090 if (cellular()->mm_plugin() == kNovatelLTEMMPlugin) 1091 return kNetworkTechnologyLte; 1092 1093 // Order is important. Return the highest speed technology 1094 // TODO(jglasgow): change shill interfaces to a capability model 1095 return AccessTechnologyToString(access_technologies_); 1096 } 1097 1098 string CellularCapabilityUniversal::GetRoamingStateString() const { 1099 switch (registration_state_) { 1100 case MM_MODEM_3GPP_REGISTRATION_STATE_HOME: 1101 return kRoamingStateHome; 1102 case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING: 1103 return kRoamingStateRoaming; 1104 default: 1105 break; 1106 } 1107 return kRoamingStateUnknown; 1108 } 1109 1110 // TODO(armansito): Remove this method once cromo is deprecated. 1111 void CellularCapabilityUniversal::GetSignalQuality() { 1112 // ModemManager always returns the cached value, so there is no need to 1113 // trigger an update here. The true value is updated through a property 1114 // change signal. 1115 } 1116 1117 string CellularCapabilityUniversal::GetTypeString() const { 1118 return AccessTechnologyToTechnologyFamily(access_technologies_); 1119 } 1120 1121 void CellularCapabilityUniversal::OnModemPropertiesChanged( 1122 const KeyValueStore& properties, 1123 const vector<string>& /* invalidated_properties */) { 1124 1125 // Update the bearers property before the modem state property as 1126 // OnModemStateChanged may call UpdateActiveBearer, which reads the bearers 1127 // property. 1128 if (properties.ContainsRpcIdentifiers(MM_MODEM_PROPERTY_BEARERS)) { 1129 RpcIdentifiers bearers = 1130 properties.GetRpcIdentifiers(MM_MODEM_PROPERTY_BEARERS); 1131 OnBearersChanged(bearers); 1132 } 1133 1134 // This solves a bootstrapping problem: If the modem is not yet 1135 // enabled, there are no proxy objects associated with the capability 1136 // object, so modem signals like StateChanged aren't seen. By monitoring 1137 // changes to the State property via the ModemManager, we're able to 1138 // get the initialization process started, which will result in the 1139 // creation of the proxy objects. 1140 // 1141 // The first time we see the change to State (when the modem state 1142 // is Unknown), we simply update the state, and rely on the Manager to 1143 // enable the device when it is registered with the Manager. On subsequent 1144 // changes to State, we need to explicitly enable the device ourselves. 1145 if (properties.ContainsInt(MM_MODEM_PROPERTY_STATE)) { 1146 int32_t istate = properties.GetInt(MM_MODEM_PROPERTY_STATE); 1147 Cellular::ModemState state = static_cast<Cellular::ModemState>(istate); 1148 OnModemStateChanged(state); 1149 } 1150 if (properties.ContainsRpcIdentifier(MM_MODEM_PROPERTY_SIM)) 1151 OnSimPathChanged(properties.GetRpcIdentifier(MM_MODEM_PROPERTY_SIM)); 1152 1153 if (properties.ContainsUint32s(MM_MODEM_PROPERTY_SUPPORTEDCAPABILITIES)) { 1154 OnSupportedCapabilitesChanged( 1155 properties.GetUint32s(MM_MODEM_PROPERTY_SUPPORTEDCAPABILITIES)); 1156 } 1157 1158 if (properties.ContainsUint(MM_MODEM_PROPERTY_CURRENTCAPABILITIES)) { 1159 OnModemCurrentCapabilitiesChanged( 1160 properties.GetUint(MM_MODEM_PROPERTY_CURRENTCAPABILITIES)); 1161 } 1162 // not needed: MM_MODEM_PROPERTY_MAXBEARERS 1163 // not needed: MM_MODEM_PROPERTY_MAXACTIVEBEARERS 1164 if (properties.ContainsString(MM_MODEM_PROPERTY_MANUFACTURER)) { 1165 cellular()->set_manufacturer( 1166 properties.GetString(MM_MODEM_PROPERTY_MANUFACTURER)); 1167 } 1168 if (properties.ContainsString(MM_MODEM_PROPERTY_MODEL)) { 1169 cellular()->set_model_id(properties.GetString(MM_MODEM_PROPERTY_MODEL)); 1170 } 1171 if (properties.ContainsString(MM_MODEM_PROPERTY_PLUGIN)) { 1172 cellular()->set_mm_plugin(properties.GetString(MM_MODEM_PROPERTY_PLUGIN)); 1173 } 1174 if (properties.ContainsString(MM_MODEM_PROPERTY_REVISION)) { 1175 OnModemRevisionChanged(properties.GetString(MM_MODEM_PROPERTY_REVISION)); 1176 } 1177 // not needed: MM_MODEM_PROPERTY_DEVICEIDENTIFIER 1178 // not needed: MM_MODEM_PROPERTY_DEVICE 1179 // not needed: MM_MODEM_PROPERTY_DRIVER 1180 // not needed: MM_MODEM_PROPERTY_PLUGIN 1181 // not needed: MM_MODEM_PROPERTY_EQUIPMENTIDENTIFIER 1182 1183 // Unlock required and SimLock 1184 bool lock_status_changed = false; 1185 if (properties.ContainsUint(MM_MODEM_PROPERTY_UNLOCKREQUIRED)) { 1186 uint32_t unlock_required = 1187 properties.GetUint(MM_MODEM_PROPERTY_UNLOCKREQUIRED); 1188 OnLockTypeChanged(static_cast<MMModemLock>(unlock_required)); 1189 lock_status_changed = true; 1190 } 1191 1192 // Unlock retries 1193 if (properties.Contains(MM_MODEM_PROPERTY_UNLOCKRETRIES)) { 1194 OnLockRetriesChanged( 1195 properties.Get(MM_MODEM_PROPERTY_UNLOCKRETRIES).Get<LockRetryData>()); 1196 lock_status_changed = true; 1197 } 1198 1199 if (lock_status_changed) 1200 OnSimLockStatusChanged(); 1201 1202 if (properties.ContainsUint(MM_MODEM_PROPERTY_ACCESSTECHNOLOGIES)) { 1203 OnAccessTechnologiesChanged( 1204 properties.GetUint(MM_MODEM_PROPERTY_ACCESSTECHNOLOGIES)); 1205 } 1206 1207 if (properties.Contains(MM_MODEM_PROPERTY_SIGNALQUALITY)) { 1208 SignalQuality quality = 1209 properties.Get(MM_MODEM_PROPERTY_SIGNALQUALITY).Get<SignalQuality>(); 1210 OnSignalQualityChanged(std::get<0>(quality)); 1211 } 1212 1213 if (properties.ContainsStrings(MM_MODEM_PROPERTY_OWNNUMBERS)) { 1214 vector<string> numbers = 1215 properties.GetStrings(MM_MODEM_PROPERTY_OWNNUMBERS); 1216 string mdn; 1217 if (numbers.size() > 0) 1218 mdn = numbers[0]; 1219 OnMdnChanged(mdn); 1220 } 1221 1222 if (properties.Contains(MM_MODEM_PROPERTY_SUPPORTEDMODES)) { 1223 SupportedModes mm_supported_modes = 1224 properties.Get(MM_MODEM_PROPERTY_SUPPORTEDMODES).Get<SupportedModes>(); 1225 vector<ModemModes> supported_modes; 1226 for (const auto& modes : mm_supported_modes) { 1227 supported_modes.push_back( 1228 ModemModes(std::get<0>(modes), 1229 static_cast<MMModemMode>(std::get<1>(modes)))); 1230 } 1231 OnSupportedModesChanged(supported_modes); 1232 } 1233 1234 if (properties.Contains(MM_MODEM_PROPERTY_CURRENTMODES)) { 1235 ModesData current_modes = 1236 properties.Get(MM_MODEM_PROPERTY_CURRENTMODES).Get<ModesData>(); 1237 OnCurrentModesChanged( 1238 ModemModes(std::get<0>(current_modes), 1239 static_cast<MMModemMode>(std::get<1>(current_modes)))); 1240 } 1241 1242 // au: MM_MODEM_PROPERTY_SUPPORTEDBANDS, 1243 // au: MM_MODEM_PROPERTY_BANDS 1244 } 1245 1246 void CellularCapabilityUniversal::OnPropertiesChanged( 1247 const string& interface, 1248 const KeyValueStore& changed_properties, 1249 const vector<string>& invalidated_properties) { 1250 SLOG(this, 3) << __func__ << "(" << interface << ")"; 1251 if (interface == MM_DBUS_INTERFACE_MODEM) { 1252 OnModemPropertiesChanged(changed_properties, invalidated_properties); 1253 } 1254 if (interface == MM_DBUS_INTERFACE_MODEM_MODEM3GPP) { 1255 OnModem3GPPPropertiesChanged(changed_properties, invalidated_properties); 1256 } 1257 if (interface == MM_DBUS_INTERFACE_SIM) { 1258 OnSimPropertiesChanged(changed_properties, invalidated_properties); 1259 } 1260 } 1261 1262 bool CellularCapabilityUniversal::RetriableConnectError( 1263 const Error& error) const { 1264 if (error.type() == Error::kInvalidApn) 1265 return true; 1266 1267 // ModemManager does not ever return kInvalidApn for an E362 modem (with 1268 // firmware version 1.41) supported by the Novatel LTE plugin. 1269 if ((cellular()->mm_plugin() == kNovatelLTEMMPlugin) && 1270 (error.type() == Error::kOperationFailed)) { 1271 return true; 1272 } 1273 return false; 1274 } 1275 1276 void CellularCapabilityUniversal::OnNetworkModeSignal(uint32_t /*mode*/) { 1277 // TODO(petkov): Implement this. 1278 NOTIMPLEMENTED(); 1279 } 1280 1281 bool CellularCapabilityUniversal::IsValidSimPath(const string& sim_path) const { 1282 return !sim_path.empty() && sim_path != kRootPath; 1283 } 1284 1285 string CellularCapabilityUniversal::NormalizeMdn(const string& mdn) const { 1286 string normalized_mdn; 1287 for (size_t i = 0; i < mdn.size(); ++i) { 1288 if (base::IsAsciiDigit(mdn[i])) 1289 normalized_mdn += mdn[i]; 1290 } 1291 return normalized_mdn; 1292 } 1293 1294 void CellularCapabilityUniversal::OnSimPathChanged( 1295 const string& sim_path) { 1296 if (sim_path == sim_path_) 1297 return; 1298 1299 mm1::SimProxyInterface* proxy = nullptr; 1300 if (IsValidSimPath(sim_path)) 1301 proxy = control_interface()->CreateSimProxy(sim_path, 1302 cellular()->dbus_service()); 1303 sim_path_ = sim_path; 1304 sim_proxy_.reset(proxy); 1305 1306 if (!IsValidSimPath(sim_path)) { 1307 // Clear all data about the sim 1308 cellular()->set_imsi(""); 1309 spn_ = ""; 1310 cellular()->set_sim_present(false); 1311 OnSimIdentifierChanged(""); 1312 OnOperatorIdChanged(""); 1313 cellular()->home_provider_info()->Reset(); 1314 } else { 1315 cellular()->set_sim_present(true); 1316 std::unique_ptr<DBusPropertiesProxyInterface> properties_proxy( 1317 control_interface()->CreateDBusPropertiesProxy( 1318 sim_path, cellular()->dbus_service())); 1319 // TODO(jglasgow): convert to async interface 1320 KeyValueStore properties(properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM)); 1321 OnSimPropertiesChanged(properties, vector<string>()); 1322 } 1323 } 1324 1325 void CellularCapabilityUniversal::OnSupportedCapabilitesChanged( 1326 const vector<uint32_t>& supported_capabilities) { 1327 supported_capabilities_ = supported_capabilities; 1328 } 1329 1330 void CellularCapabilityUniversal::OnModemCurrentCapabilitiesChanged( 1331 uint32_t current_capabilities) { 1332 current_capabilities_ = current_capabilities; 1333 1334 // Only allow network scan when the modem's current capabilities support 1335 // GSM/UMTS. 1336 // 1337 // TODO(benchan): We should consider having the modem plugins in ModemManager 1338 // reporting whether network scan is supported. 1339 cellular()->set_scanning_supported( 1340 (current_capabilities & MM_MODEM_CAPABILITY_GSM_UMTS) != 0); 1341 } 1342 1343 void CellularCapabilityUniversal::OnMdnChanged( 1344 const string& mdn) { 1345 cellular()->set_mdn(NormalizeMdn(mdn)); 1346 UpdatePendingActivationState(); 1347 } 1348 1349 void CellularCapabilityUniversal::OnModemRevisionChanged( 1350 const string& revision) { 1351 cellular()->set_firmware_revision(revision); 1352 } 1353 1354 void CellularCapabilityUniversal::OnModemStateChanged( 1355 Cellular::ModemState state) { 1356 SLOG(this, 3) << __func__ << ": " << Cellular::GetModemStateString(state); 1357 1358 if (state == Cellular::kModemStateConnected) { 1359 // This assumes that ModemManager updates the Bearers list and the Bearer 1360 // properties before changing Modem state to Connected. 1361 SLOG(this, 2) << "Update active bearer."; 1362 UpdateActiveBearer(); 1363 } 1364 1365 cellular()->OnModemStateChanged(state); 1366 // TODO(armansito): Move the deferred enable logic to Cellular 1367 // (See crbug.com/279499). 1368 if (!deferred_enable_modem_callback_.is_null() && 1369 state == Cellular::kModemStateDisabled) { 1370 SLOG(this, 2) << "Enabling modem after deferring."; 1371 deferred_enable_modem_callback_.Run(); 1372 deferred_enable_modem_callback_.Reset(); 1373 } 1374 } 1375 1376 void CellularCapabilityUniversal::OnAccessTechnologiesChanged( 1377 uint32_t access_technologies) { 1378 if (access_technologies_ != access_technologies) { 1379 const string old_type_string(GetTypeString()); 1380 access_technologies_ = access_technologies; 1381 const string new_type_string(GetTypeString()); 1382 if (new_type_string != old_type_string) { 1383 // TODO(jglasgow): address layering violation of emitting change 1384 // signal here for a property owned by Cellular. 1385 cellular()->adaptor()->EmitStringChanged( 1386 kTechnologyFamilyProperty, new_type_string); 1387 } 1388 if (cellular()->service().get()) { 1389 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString()); 1390 } 1391 } 1392 } 1393 1394 void CellularCapabilityUniversal::OnSupportedModesChanged( 1395 const vector<ModemModes>& supported_modes) { 1396 supported_modes_ = supported_modes; 1397 } 1398 1399 void CellularCapabilityUniversal::OnCurrentModesChanged( 1400 const ModemModes& current_modes) { 1401 current_modes_ = current_modes; 1402 } 1403 1404 void CellularCapabilityUniversal::OnBearersChanged( 1405 const RpcIdentifiers& bearers) { 1406 bearer_paths_ = bearers; 1407 } 1408 1409 void CellularCapabilityUniversal::OnLockRetriesChanged( 1410 const LockRetryData& lock_retries) { 1411 SLOG(this, 3) << __func__; 1412 1413 // Look for the retries left for the current lock. Try the obtain the count 1414 // that matches the current count. If no count for the current lock is 1415 // available, report the first one in the dictionary. 1416 LockRetryData::const_iterator it = 1417 lock_retries.find(sim_lock_status_.lock_type); 1418 if (it == lock_retries.end()) 1419 it = lock_retries.begin(); 1420 if (it != lock_retries.end()) 1421 sim_lock_status_.retries_left = it->second; 1422 else 1423 // Unknown, use 999 1424 sim_lock_status_.retries_left = 999; 1425 } 1426 1427 void CellularCapabilityUniversal::OnLockTypeChanged( 1428 MMModemLock lock_type) { 1429 SLOG(this, 3) << __func__ << ": " << lock_type; 1430 sim_lock_status_.lock_type = lock_type; 1431 1432 // If the SIM is in a locked state |sim_lock_status_.enabled| might be false. 1433 // This is because the corresponding property 'EnabledFacilityLocks' is on 1434 // the 3GPP interface and the 3GPP interface is not available while the Modem 1435 // is in the 'LOCKED' state. 1436 if (lock_type != MM_MODEM_LOCK_NONE && 1437 lock_type != MM_MODEM_LOCK_UNKNOWN && 1438 !sim_lock_status_.enabled) 1439 sim_lock_status_.enabled = true; 1440 } 1441 1442 void CellularCapabilityUniversal::OnSimLockStatusChanged() { 1443 SLOG(this, 3) << __func__; 1444 cellular()->adaptor()->EmitKeyValueStoreChanged( 1445 kSIMLockStatusProperty, SimLockStatusToProperty(nullptr)); 1446 1447 // If the SIM is currently unlocked, assume that we need to refresh 1448 // carrier information, since a locked SIM prevents shill from obtaining 1449 // the necessary data to establish a connection later (e.g. IMSI). 1450 if (IsValidSimPath(sim_path_) && 1451 (sim_lock_status_.lock_type == MM_MODEM_LOCK_NONE || 1452 sim_lock_status_.lock_type == MM_MODEM_LOCK_UNKNOWN)) { 1453 std::unique_ptr<DBusPropertiesProxyInterface> properties_proxy( 1454 control_interface()->CreateDBusPropertiesProxy( 1455 sim_path_, cellular()->dbus_service())); 1456 KeyValueStore properties( 1457 properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM)); 1458 OnSimPropertiesChanged(properties, vector<string>()); 1459 } 1460 } 1461 1462 void CellularCapabilityUniversal::OnModem3GPPPropertiesChanged( 1463 const KeyValueStore& properties, 1464 const vector<string>& /* invalidated_properties */) { 1465 SLOG(this, 3) << __func__; 1466 if (properties.ContainsString(MM_MODEM_MODEM3GPP_PROPERTY_IMEI)) 1467 cellular()->set_imei( 1468 properties.GetString(MM_MODEM_MODEM3GPP_PROPERTY_IMEI)); 1469 1470 // Handle registration state changes as a single change 1471 Stringmap::const_iterator it; 1472 string operator_code; 1473 string operator_name; 1474 it = serving_operator_.find(kOperatorCodeKey); 1475 if (it != serving_operator_.end()) 1476 operator_code = it->second; 1477 it = serving_operator_.find(kOperatorNameKey); 1478 if (it != serving_operator_.end()) 1479 operator_name = it->second; 1480 1481 MMModem3gppRegistrationState state = registration_state_; 1482 bool registration_changed = false; 1483 if (properties.ContainsUint(MM_MODEM_MODEM3GPP_PROPERTY_REGISTRATIONSTATE)) { 1484 state = static_cast<MMModem3gppRegistrationState>( 1485 properties.GetUint(MM_MODEM_MODEM3GPP_PROPERTY_REGISTRATIONSTATE)); 1486 registration_changed = true; 1487 } 1488 if (properties.ContainsString(MM_MODEM_MODEM3GPP_PROPERTY_OPERATORCODE)) { 1489 operator_code = 1490 properties.GetString(MM_MODEM_MODEM3GPP_PROPERTY_OPERATORCODE); 1491 registration_changed = true; 1492 } 1493 if (properties.ContainsString(MM_MODEM_MODEM3GPP_PROPERTY_OPERATORNAME)) { 1494 operator_name = 1495 properties.GetString(MM_MODEM_MODEM3GPP_PROPERTY_OPERATORNAME); 1496 registration_changed = true; 1497 } 1498 if (registration_changed) 1499 On3GPPRegistrationChanged(state, operator_code, operator_name); 1500 if (properties.ContainsUint(MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE)) 1501 On3GPPSubscriptionStateChanged( 1502 static_cast<MMModem3gppSubscriptionState>( 1503 properties.GetUint(MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE))); 1504 1505 CellularServiceRefPtr service = cellular()->service(); 1506 if (service.get() && 1507 properties.ContainsUint(MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE)) { 1508 uint32_t subscription_state = 1509 properties.GetUint(MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE); 1510 SLOG(this, 3) << __func__ << ": Subscription state = " 1511 << subscription_state; 1512 service->out_of_credits_detector()->NotifySubscriptionStateChanged( 1513 subscription_state); 1514 } 1515 1516 if (properties.ContainsUint(MM_MODEM_MODEM3GPP_PROPERTY_ENABLEDFACILITYLOCKS)) 1517 OnFacilityLocksChanged( 1518 properties.GetUint(MM_MODEM_MODEM3GPP_PROPERTY_ENABLEDFACILITYLOCKS)); 1519 } 1520 1521 void CellularCapabilityUniversal::On3GPPRegistrationChanged( 1522 MMModem3gppRegistrationState state, 1523 const string& operator_code, 1524 const string& operator_name) { 1525 SLOG(this, 3) << __func__ << ": regstate=" << state 1526 << ", opercode=" << operator_code 1527 << ", opername=" << operator_name; 1528 1529 // While the modem is connected, if the state changed from a registered state 1530 // to a non registered state, defer the state change by 15 seconds. 1531 if (cellular()->modem_state() == Cellular::kModemStateConnected && 1532 IsRegistered() && !IsRegisteredState(state)) { 1533 if (!registration_dropped_update_callback_.IsCancelled()) { 1534 LOG(WARNING) << "Modem reported consecutive 3GPP registration drops. " 1535 << "Ignoring earlier notifications."; 1536 registration_dropped_update_callback_.Cancel(); 1537 } else { 1538 // This is not a repeated post. So, count this instance of delayed drop 1539 // posted. 1540 modem_info()->metrics()->Notify3GPPRegistrationDelayedDropPosted(); 1541 } 1542 SLOG(this, 2) << "Posted deferred registration state update"; 1543 registration_dropped_update_callback_.Reset( 1544 Bind(&CellularCapabilityUniversal::Handle3GPPRegistrationChange, 1545 weak_ptr_factory_.GetWeakPtr(), 1546 state, 1547 operator_code, 1548 operator_name)); 1549 cellular()->dispatcher()->PostDelayedTask( 1550 registration_dropped_update_callback_.callback(), 1551 registration_dropped_update_timeout_milliseconds_); 1552 } else { 1553 if (!registration_dropped_update_callback_.IsCancelled()) { 1554 SLOG(this, 2) << "Cancelled a deferred registration state update"; 1555 registration_dropped_update_callback_.Cancel(); 1556 // If we cancelled the callback here, it means we had flaky network for a 1557 // small duration. 1558 modem_info()->metrics()->Notify3GPPRegistrationDelayedDropCanceled(); 1559 } 1560 Handle3GPPRegistrationChange(state, operator_code, operator_name); 1561 } 1562 } 1563 1564 void CellularCapabilityUniversal::Handle3GPPRegistrationChange( 1565 MMModem3gppRegistrationState updated_state, 1566 string updated_operator_code, 1567 string updated_operator_name) { 1568 // A finished callback does not qualify as a canceled callback. 1569 // We test for a canceled callback to check for outstanding callbacks. 1570 // So, explicitly cancel the callback here. 1571 registration_dropped_update_callback_.Cancel(); 1572 1573 SLOG(this, 3) << __func__ << ": regstate=" << updated_state 1574 << ", opercode=" << updated_operator_code 1575 << ", opername=" << updated_operator_name; 1576 1577 registration_state_ = updated_state; 1578 serving_operator_[kOperatorCodeKey] = updated_operator_code; 1579 serving_operator_[kOperatorNameKey] = updated_operator_name; 1580 cellular()->serving_operator_info()->UpdateMCCMNC(updated_operator_code); 1581 cellular()->serving_operator_info()->UpdateOperatorName( 1582 updated_operator_name); 1583 1584 cellular()->HandleNewRegistrationState(); 1585 1586 // If the modem registered with the network and the current ICCID is pending 1587 // activation, then reset the modem. 1588 UpdatePendingActivationState(); 1589 } 1590 1591 void CellularCapabilityUniversal::On3GPPSubscriptionStateChanged( 1592 MMModem3gppSubscriptionState updated_state) { 1593 SLOG(this, 3) << __func__ << ": Updated subscription state = " 1594 << updated_state; 1595 1596 // A one-to-one enum mapping. 1597 SubscriptionState new_subscription_state; 1598 switch (updated_state) { 1599 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_UNKNOWN: 1600 new_subscription_state = kSubscriptionStateUnknown; 1601 break; 1602 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_PROVISIONED: 1603 new_subscription_state = kSubscriptionStateProvisioned; 1604 break; 1605 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_UNPROVISIONED: 1606 new_subscription_state = kSubscriptionStateUnprovisioned; 1607 break; 1608 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_OUT_OF_DATA: 1609 new_subscription_state = kSubscriptionStateOutOfData; 1610 break; 1611 default: 1612 LOG(ERROR) << "Unrecognized MMModem3gppSubscriptionState: " 1613 << updated_state; 1614 new_subscription_state = kSubscriptionStateUnknown; 1615 return; 1616 } 1617 if (new_subscription_state == subscription_state_) 1618 return; 1619 1620 subscription_state_ = new_subscription_state; 1621 1622 UpdateServiceActivationState(); 1623 UpdatePendingActivationState(); 1624 } 1625 1626 void CellularCapabilityUniversal::OnModemStateChangedSignal( 1627 int32_t old_state, int32_t new_state, uint32_t reason) { 1628 Cellular::ModemState old_modem_state = 1629 static_cast<Cellular::ModemState>(old_state); 1630 Cellular::ModemState new_modem_state = 1631 static_cast<Cellular::ModemState>(new_state); 1632 SLOG(this, 3) << __func__ << "(" 1633 << Cellular::GetModemStateString(old_modem_state) 1634 << ", " 1635 << Cellular::GetModemStateString(new_modem_state) 1636 << ", " 1637 << reason << ")"; 1638 } 1639 1640 void CellularCapabilityUniversal::OnSignalQualityChanged(uint32_t quality) { 1641 cellular()->HandleNewSignalQuality(quality); 1642 } 1643 1644 void CellularCapabilityUniversal::OnFacilityLocksChanged(uint32_t locks) { 1645 bool sim_enabled = !!(locks & MM_MODEM_3GPP_FACILITY_SIM); 1646 if (sim_lock_status_.enabled != sim_enabled) { 1647 sim_lock_status_.enabled = sim_enabled; 1648 OnSimLockStatusChanged(); 1649 } 1650 } 1651 1652 void CellularCapabilityUniversal::OnSimPropertiesChanged( 1653 const KeyValueStore& props, 1654 const vector<string>& /* invalidated_properties */) { 1655 SLOG(this, 3) << __func__; 1656 if (props.ContainsString(MM_SIM_PROPERTY_SIMIDENTIFIER)) 1657 OnSimIdentifierChanged(props.GetString(MM_SIM_PROPERTY_SIMIDENTIFIER)); 1658 if (props.ContainsString(MM_SIM_PROPERTY_OPERATORIDENTIFIER)) 1659 OnOperatorIdChanged(props.GetString(MM_SIM_PROPERTY_OPERATORIDENTIFIER)); 1660 if (props.ContainsString(MM_SIM_PROPERTY_OPERATORNAME)) 1661 OnSpnChanged(props.GetString(MM_SIM_PROPERTY_OPERATORNAME)); 1662 if (props.ContainsString(MM_SIM_PROPERTY_IMSI)) { 1663 string imsi = props.GetString(MM_SIM_PROPERTY_IMSI); 1664 cellular()->set_imsi(imsi); 1665 cellular()->home_provider_info()->UpdateIMSI(imsi); 1666 // We do not obtain IMSI OTA right now. Provide the value from the SIM to 1667 // serving operator as well, to aid in MVNO identification. 1668 cellular()->serving_operator_info()->UpdateIMSI(imsi); 1669 } 1670 } 1671 1672 void CellularCapabilityUniversal::OnSpnChanged(const std::string& spn) { 1673 spn_ = spn; 1674 cellular()->home_provider_info()->UpdateOperatorName(spn); 1675 } 1676 1677 void CellularCapabilityUniversal::OnSimIdentifierChanged(const string& id) { 1678 cellular()->set_sim_identifier(id); 1679 cellular()->home_provider_info()->UpdateICCID(id); 1680 // Provide ICCID to serving operator as well to aid in MVNO identification. 1681 cellular()->serving_operator_info()->UpdateICCID(id); 1682 UpdatePendingActivationState(); 1683 } 1684 1685 void CellularCapabilityUniversal::OnOperatorIdChanged( 1686 const string& operator_id) { 1687 SLOG(this, 2) << "Operator ID = '" << operator_id << "'"; 1688 cellular()->home_provider_info()->UpdateMCCMNC(operator_id); 1689 } 1690 1691 OutOfCreditsDetector::OOCType 1692 CellularCapabilityUniversal::GetOutOfCreditsDetectionType() const { 1693 if (cellular()->mm_plugin() == kAltairLTEMMPlugin) { 1694 return OutOfCreditsDetector::OOCTypeSubscriptionState; 1695 } else { 1696 return OutOfCreditsDetector::OOCTypeNone; 1697 } 1698 } 1699 1700 } // namespace shill 1701