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