cellular_capability_universal.cc revision f6339a4bb6c4db7ea3eb187f652ee48e86c0df58
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/control_interface.h" 22#include "shill/dbus_properties_proxy_interface.h" 23#include "shill/error.h" 24#include "shill/logging.h" 25#include "shill/pending_activation_store.h" 26#include "shill/property_accessor.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 ControlInterface* control_interface, 136 ModemInfo* modem_info) 137 : CellularCapability(cellular, control_interface, 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 control_interface()->CreateMM1ModemModem3gppProxy( 192 cellular()->dbus_path(), cellular()->dbus_service())); 193 modem_proxy_.reset( 194 control_interface()->CreateMM1ModemProxy(cellular()->dbus_path(), 195 cellular()->dbus_service())); 196 modem_simple_proxy_.reset( 197 control_interface()->CreateMM1ModemSimpleProxy( 198 cellular()->dbus_path(), cellular()->dbus_service())); 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 KeyValueStore& properties, 410 Error* error, 411 const ResultCallback& callback) { 412 SLOG(this, 3) << __func__; 413 RpcIdentifierCallback 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(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 KeyValueStore* properties) { 660 SetupApnTryList(); 661 FillConnectPropertyMap(properties); 662} 663 664void CellularCapabilityUniversal::FillConnectPropertyMap( 665 KeyValueStore* properties) { 666 667 // TODO(jglasgow): Is this really needed anymore? 668 properties->SetString(kConnectNumber, kPhoneNumber); 669 670 properties->SetBool(kConnectAllowRoaming, AllowRoaming()); 671 672 if (!apn_try_list_.empty()) { 673 // Leave the APN at the front of the list, so that it can be recorded 674 // if the connect attempt succeeds. 675 Stringmap apn_info = apn_try_list_.front(); 676 SLOG(this, 2) << __func__ << ": Using APN " << apn_info[kApnProperty]; 677 properties->SetString(kConnectApn, apn_info[kApnProperty]); 678 if (ContainsKey(apn_info, kApnUsernameProperty)) 679 properties->SetString(kConnectUser, apn_info[kApnUsernameProperty]); 680 if (ContainsKey(apn_info, kApnPasswordProperty)) 681 properties->SetString(kConnectPassword, apn_info[kApnPasswordProperty]); 682 } 683} 684 685void CellularCapabilityUniversal::OnConnectReply(const ResultCallback& callback, 686 const string& path, 687 const Error& error) { 688 SLOG(this, 3) << __func__ << "(" << error << ")"; 689 690 CellularServiceRefPtr service = cellular()->service(); 691 if (!service) { 692 // The service could have been deleted before our Connect() request 693 // completes if the modem was enabled and then quickly disabled. 694 apn_try_list_.clear(); 695 } else if (error.IsFailure()) { 696 service->ClearLastGoodApn(); 697 // The APN that was just tried (and failed) is still at the 698 // front of the list, about to be removed. If the list is empty 699 // after that, try one last time without an APN. This may succeed 700 // with some modems in some cases. 701 if (RetriableConnectError(error) && !apn_try_list_.empty()) { 702 apn_try_list_.pop_front(); 703 SLOG(this, 2) << "Connect failed with invalid APN, " 704 << apn_try_list_.size() << " remaining APNs to try"; 705 KeyValueStore props; 706 FillConnectPropertyMap(&props); 707 Error error; 708 Connect(props, &error, callback); 709 return; 710 } 711 } else { 712 if (!apn_try_list_.empty()) { 713 service->SetLastGoodApn(apn_try_list_.front()); 714 apn_try_list_.clear(); 715 } 716 SLOG(this, 2) << "Connected bearer " << path; 717 } 718 719 if (!callback.is_null()) 720 callback.Run(error); 721 722 UpdatePendingActivationState(); 723} 724 725bool CellularCapabilityUniversal::AllowRoaming() { 726 return cellular()->provider_requires_roaming() || allow_roaming_property(); 727} 728 729void CellularCapabilityUniversal::GetProperties() { 730 SLOG(this, 3) << __func__; 731 732 std::unique_ptr<DBusPropertiesProxyInterface> properties_proxy( 733 control_interface()->CreateDBusPropertiesProxy( 734 cellular()->dbus_path(), cellular()->dbus_service())); 735 736 KeyValueStore properties( 737 properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM)); 738 OnModemPropertiesChanged(properties, vector<string>()); 739 740 properties = properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM_MODEM3GPP); 741 OnModem3GPPPropertiesChanged(properties, vector<string>()); 742} 743 744void CellularCapabilityUniversal::UpdateServiceOLP() { 745 SLOG(this, 3) << __func__; 746 747 // OLP is based off of the Home Provider. 748 if (!cellular()->home_provider_info()->IsMobileNetworkOperatorKnown()) { 749 return; 750 } 751 752 const vector<MobileOperatorInfo::OnlinePortal>& olp_list = 753 cellular()->home_provider_info()->olp_list(); 754 if (olp_list.empty()) { 755 return; 756 } 757 758 if (olp_list.size() > 1) { 759 SLOG(this, 1) << "Found multiple online portals. Choosing the first."; 760 } 761 string post_data = olp_list[0].post_data; 762 ReplaceSubstringsAfterOffset(&post_data, 0, "${iccid}", 763 cellular()->sim_identifier()); 764 ReplaceSubstringsAfterOffset(&post_data, 0, "${imei}", cellular()->imei()); 765 ReplaceSubstringsAfterOffset(&post_data, 0, "${imsi}", cellular()->imsi()); 766 ReplaceSubstringsAfterOffset(&post_data, 0, "${mdn}", 767 GetMdnForOLP(cellular()->home_provider_info())); 768 ReplaceSubstringsAfterOffset(&post_data, 0, "${min}", cellular()->min()); 769 cellular()->service()->SetOLP(olp_list[0].url, olp_list[0].method, post_data); 770} 771 772void CellularCapabilityUniversal::UpdateActiveBearer() { 773 SLOG(this, 3) << __func__; 774 775 // Look for the first active bearer and use its path as the connected 776 // one. Right now, we don't allow more than one active bearer. 777 active_bearer_.reset(); 778 for (const auto& path : bearer_paths_) { 779 std::unique_ptr<CellularBearer> bearer( 780 new CellularBearer(control_interface(), 781 path, 782 cellular()->dbus_service())); 783 // The bearer object may have vanished before ModemManager updates the 784 // 'Bearers' property. 785 if (!bearer->Init()) 786 continue; 787 788 if (!bearer->connected()) 789 continue; 790 791 SLOG(this, 2) << "Found active bearer \"" << path << "\"."; 792 CHECK(!active_bearer_) << "Found more than one active bearer."; 793 active_bearer_ = std::move(bearer); 794 } 795 796 if (!active_bearer_) 797 SLOG(this, 2) << "No active bearer found."; 798} 799 800bool CellularCapabilityUniversal::IsServiceActivationRequired() const { 801 const string& sim_identifier = cellular()->sim_identifier(); 802 // subscription_state_ is the definitive answer. If that does not work, 803 // fallback on MDN based logic. 804 if (subscription_state_ == kSubscriptionStateProvisioned || 805 subscription_state_ == kSubscriptionStateOutOfData) 806 return false; 807 808 // We are in the process of activating, ignore all other clues from the 809 // network and use our own knowledge about the activation state. 810 if (!sim_identifier.empty() && 811 modem_info()->pending_activation_store()->GetActivationState( 812 PendingActivationStore::kIdentifierICCID, 813 sim_identifier) != PendingActivationStore::kStateUnknown) 814 return false; 815 816 // Network notification that the service needs to be activated. 817 if (subscription_state_ == kSubscriptionStateUnprovisioned) 818 return true; 819 820 // If there is no online payment portal information, it's safer to assume 821 // the service does not require activation. 822 if (!cellular()->home_provider_info()->IsMobileNetworkOperatorKnown() || 823 cellular()->home_provider_info()->olp_list().empty()) { 824 return false; 825 } 826 827 // If the MDN is invalid (i.e. empty or contains only zeros), the service 828 // requires activation. 829 return !IsMdnValid(); 830} 831 832bool CellularCapabilityUniversal::IsMdnValid() const { 833 const string& mdn = cellular()->mdn(); 834 // Note that |mdn| is normalized to contain only digits in OnMdnChanged(). 835 for (size_t i = 0; i < mdn.size(); ++i) { 836 if (mdn[i] != '0') 837 return true; 838 } 839 return false; 840} 841 842// always called from an async context 843void CellularCapabilityUniversal::Register(const ResultCallback& callback) { 844 SLOG(this, 3) << __func__ << " \"" << cellular()->selected_network() 845 << "\""; 846 CHECK(!callback.is_null()); 847 Error error; 848 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply, 849 weak_ptr_factory_.GetWeakPtr(), callback); 850 modem_3gpp_proxy_->Register(cellular()->selected_network(), &error, cb, 851 kTimeoutRegister); 852 if (error.IsFailure()) 853 callback.Run(error); 854} 855 856void CellularCapabilityUniversal::RegisterOnNetwork( 857 const string& network_id, 858 Error* error, 859 const ResultCallback& callback) { 860 SLOG(this, 3) << __func__ << "(" << network_id << ")"; 861 CHECK(error); 862 desired_network_ = network_id; 863 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply, 864 weak_ptr_factory_.GetWeakPtr(), callback); 865 modem_3gpp_proxy_->Register(network_id, error, cb, kTimeoutRegister); 866} 867 868void CellularCapabilityUniversal::OnRegisterReply( 869 const ResultCallback& callback, 870 const Error& error) { 871 SLOG(this, 3) << __func__ << "(" << error << ")"; 872 873 if (error.IsSuccess()) { 874 cellular()->set_selected_network(desired_network_); 875 desired_network_.clear(); 876 callback.Run(error); 877 return; 878 } 879 // If registration on the desired network failed, 880 // try to register on the home network. 881 if (!desired_network_.empty()) { 882 desired_network_.clear(); 883 cellular()->set_selected_network(""); 884 LOG(INFO) << "Couldn't register on selected network, trying home network"; 885 Register(callback); 886 return; 887 } 888 callback.Run(error); 889} 890 891bool CellularCapabilityUniversal::IsRegistered() const { 892 return IsRegisteredState(registration_state_); 893} 894 895bool CellularCapabilityUniversal::IsRegisteredState( 896 MMModem3gppRegistrationState state) { 897 return (state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME || 898 state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING); 899} 900 901void CellularCapabilityUniversal::SetUnregistered(bool searching) { 902 // If we're already in some non-registered state, don't override that 903 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME || 904 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) { 905 registration_state_ = 906 (searching ? MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING : 907 MM_MODEM_3GPP_REGISTRATION_STATE_IDLE); 908 } 909} 910 911void CellularCapabilityUniversal::RequirePIN( 912 const string& pin, bool require, 913 Error* error, const ResultCallback& callback) { 914 CHECK(error); 915 sim_proxy_->EnablePin(pin, require, error, callback, kTimeoutDefault); 916} 917 918void CellularCapabilityUniversal::EnterPIN(const string& pin, 919 Error* error, 920 const ResultCallback& callback) { 921 CHECK(error); 922 SLOG(this, 3) << __func__; 923 sim_proxy_->SendPin(pin, error, callback, kEnterPinTimeoutMilliseconds); 924} 925 926void CellularCapabilityUniversal::UnblockPIN(const string& unblock_code, 927 const string& pin, 928 Error* error, 929 const ResultCallback& callback) { 930 CHECK(error); 931 sim_proxy_->SendPuk(unblock_code, pin, error, callback, kTimeoutDefault); 932} 933 934void CellularCapabilityUniversal::ChangePIN( 935 const string& old_pin, const string& new_pin, 936 Error* error, const ResultCallback& callback) { 937 CHECK(error); 938 sim_proxy_->ChangePin(old_pin, new_pin, error, callback, kTimeoutDefault); 939} 940 941void CellularCapabilityUniversal::Reset(Error* error, 942 const ResultCallback& callback) { 943 SLOG(this, 3) << __func__; 944 CHECK(error); 945 if (resetting_) { 946 Error::PopulateAndLog(FROM_HERE, error, Error::kInProgress, 947 "Already resetting"); 948 return; 949 } 950 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnResetReply, 951 weak_ptr_factory_.GetWeakPtr(), callback); 952 modem_proxy_->Reset(error, cb, kTimeoutReset); 953 if (!error->IsFailure()) { 954 resetting_ = true; 955 } 956} 957 958void CellularCapabilityUniversal::OnResetReply(const ResultCallback& callback, 959 const Error& error) { 960 SLOG(this, 3) << __func__; 961 resetting_ = false; 962 if (!callback.is_null()) 963 callback.Run(error); 964} 965 966void CellularCapabilityUniversal::Scan( 967 Error* error, 968 const ResultStringmapsCallback& callback) { 969 KeyValueStoresCallback cb = Bind(&CellularCapabilityUniversal::OnScanReply, 970 weak_ptr_factory_.GetWeakPtr(), callback); 971 modem_3gpp_proxy_->Scan(error, cb, kTimeoutScan); 972} 973 974void CellularCapabilityUniversal::OnScanReply( 975 const ResultStringmapsCallback& callback, 976 const ScanResults& results, 977 const Error& error) { 978 Stringmaps found_networks; 979 for (const auto& result : results) 980 found_networks.push_back(ParseScanResult(result)); 981 callback.Run(found_networks, error); 982} 983 984Stringmap CellularCapabilityUniversal::ParseScanResult( 985 const ScanResult& result) { 986 987 /* ScanResults contain the following keys: 988 989 "status" 990 A MMModem3gppNetworkAvailability value representing network 991 availability status, given as an unsigned integer (signature "u"). 992 This key will always be present. 993 994 "operator-long" 995 Long-format name of operator, given as a string value (signature 996 "s"). If the name is unknown, this field should not be present. 997 998 "operator-short" 999 Short-format name of operator, given as a string value 1000 (signature "s"). If the name is unknown, this field should not 1001 be present. 1002 1003 "operator-code" 1004 Mobile code of the operator, given as a string value (signature 1005 "s"). Returned in the format "MCCMNC", where MCC is the 1006 three-digit ITU E.212 Mobile Country Code and MNC is the two- or 1007 three-digit GSM Mobile Network Code. e.g. "31026" or "310260". 1008 1009 "access-technology" 1010 A MMModemAccessTechnology value representing the generic access 1011 technology used by this mobile network, given as an unsigned 1012 integer (signature "u"). 1013 */ 1014 Stringmap parsed; 1015 1016 if (result.ContainsUint(kStatusProperty)) { 1017 uint32_t status = result.GetUint(kStatusProperty); 1018 // numerical values are taken from 3GPP TS 27.007 Section 7.3. 1019 static const char* const kStatusString[] = { 1020 "unknown", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_UNKNOWN 1021 "available", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_AVAILABLE 1022 "current", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_CURRENT 1023 "forbidden", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_FORBIDDEN 1024 }; 1025 parsed[kStatusProperty] = kStatusString[status]; 1026 } 1027 1028 // MMModemAccessTechnology 1029 if (result.ContainsUint(kOperatorAccessTechnologyProperty)) { 1030 parsed[kTechnologyProperty] = 1031 AccessTechnologyToString( 1032 result.GetUint(kOperatorAccessTechnologyProperty)); 1033 } 1034 1035 string operator_long, operator_short, operator_code; 1036 if (result.ContainsString(kOperatorLongProperty)) 1037 parsed[kLongNameProperty] = result.GetString(kOperatorLongProperty); 1038 if (result.ContainsString(kOperatorShortProperty)) 1039 parsed[kShortNameProperty] = result.GetString(kOperatorShortProperty); 1040 if (result.ContainsString(kOperatorCodeProperty)) 1041 parsed[kNetworkIdProperty] = result.GetString(kOperatorCodeProperty); 1042 1043 // If the long name is not available but the network ID is, look up the long 1044 // name in the mobile provider database. 1045 if ((!ContainsKey(parsed, kLongNameProperty) || 1046 parsed[kLongNameProperty].empty()) && 1047 ContainsKey(parsed, kNetworkIdProperty)) { 1048 mobile_operator_info_->Reset(); 1049 mobile_operator_info_->UpdateMCCMNC(parsed[kNetworkIdProperty]); 1050 if (mobile_operator_info_->IsMobileNetworkOperatorKnown() && 1051 !mobile_operator_info_->operator_name().empty()) { 1052 parsed[kLongNameProperty] = mobile_operator_info_->operator_name(); 1053 } 1054 } 1055 return parsed; 1056} 1057 1058CellularBearer* CellularCapabilityUniversal::GetActiveBearer() const { 1059 return active_bearer_.get(); 1060} 1061 1062string CellularCapabilityUniversal::GetNetworkTechnologyString() const { 1063 // If we know that the modem is an E362 modem supported by the Novatel LTE 1064 // plugin, return LTE here to make sure that Chrome sees LTE as the network 1065 // technology even if the actual technology is unknown. 1066 // 1067 // This hack will cause the UI to display LTE even if the modem doesn't 1068 // support it at a given time. This might be problematic if we ever want to 1069 // support switching between access technologies (e.g. falling back to 3G 1070 // when LTE is not available). 1071 if (cellular()->mm_plugin() == kNovatelLTEMMPlugin) 1072 return kNetworkTechnologyLte; 1073 1074 // Order is important. Return the highest speed technology 1075 // TODO(jglasgow): change shill interfaces to a capability model 1076 return AccessTechnologyToString(access_technologies_); 1077} 1078 1079string CellularCapabilityUniversal::GetRoamingStateString() const { 1080 switch (registration_state_) { 1081 case MM_MODEM_3GPP_REGISTRATION_STATE_HOME: 1082 return kRoamingStateHome; 1083 case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING: 1084 return kRoamingStateRoaming; 1085 default: 1086 break; 1087 } 1088 return kRoamingStateUnknown; 1089} 1090 1091// TODO(armansito): Remove this method once cromo is deprecated. 1092void CellularCapabilityUniversal::GetSignalQuality() { 1093 // ModemManager always returns the cached value, so there is no need to 1094 // trigger an update here. The true value is updated through a property 1095 // change signal. 1096} 1097 1098string CellularCapabilityUniversal::GetTypeString() const { 1099 return AccessTechnologyToTechnologyFamily(access_technologies_); 1100} 1101 1102void CellularCapabilityUniversal::OnModemPropertiesChanged( 1103 const KeyValueStore& properties, 1104 const vector<string>& /* invalidated_properties */) { 1105 1106 // Update the bearers property before the modem state property as 1107 // OnModemStateChanged may call UpdateActiveBearer, which reads the bearers 1108 // property. 1109 if (properties.ContainsRpcIdentifiers(MM_MODEM_PROPERTY_BEARERS)) { 1110 RpcIdentifiers bearers = 1111 properties.GetRpcIdentifiers(MM_MODEM_PROPERTY_BEARERS); 1112 OnBearersChanged(bearers); 1113 } 1114 1115 // This solves a bootstrapping problem: If the modem is not yet 1116 // enabled, there are no proxy objects associated with the capability 1117 // object, so modem signals like StateChanged aren't seen. By monitoring 1118 // changes to the State property via the ModemManager, we're able to 1119 // get the initialization process started, which will result in the 1120 // creation of the proxy objects. 1121 // 1122 // The first time we see the change to State (when the modem state 1123 // is Unknown), we simply update the state, and rely on the Manager to 1124 // enable the device when it is registered with the Manager. On subsequent 1125 // changes to State, we need to explicitly enable the device ourselves. 1126 if (properties.ContainsInt(MM_MODEM_PROPERTY_STATE)) { 1127 int32_t istate = properties.GetInt(MM_MODEM_PROPERTY_STATE); 1128 Cellular::ModemState state = static_cast<Cellular::ModemState>(istate); 1129 OnModemStateChanged(state); 1130 } 1131 if (properties.ContainsRpcIdentifier(MM_MODEM_PROPERTY_SIM)) 1132 OnSimPathChanged(properties.GetRpcIdentifier(MM_MODEM_PROPERTY_SIM)); 1133 1134 if (properties.ContainsUint32s(MM_MODEM_PROPERTY_SUPPORTEDCAPABILITIES)) { 1135 OnSupportedCapabilitesChanged( 1136 properties.GetUint32s(MM_MODEM_PROPERTY_SUPPORTEDCAPABILITIES)); 1137 } 1138 1139 if (properties.ContainsUint(MM_MODEM_PROPERTY_CURRENTCAPABILITIES)) { 1140 OnModemCurrentCapabilitiesChanged( 1141 properties.GetUint(MM_MODEM_PROPERTY_CURRENTCAPABILITIES)); 1142 } 1143 // not needed: MM_MODEM_PROPERTY_MAXBEARERS 1144 // not needed: MM_MODEM_PROPERTY_MAXACTIVEBEARERS 1145 if (properties.ContainsString(MM_MODEM_PROPERTY_MANUFACTURER)) { 1146 cellular()->set_manufacturer( 1147 properties.GetString(MM_MODEM_PROPERTY_MANUFACTURER)); 1148 } 1149 if (properties.ContainsString(MM_MODEM_PROPERTY_MODEL)) { 1150 cellular()->set_model_id(properties.GetString(MM_MODEM_PROPERTY_MODEL)); 1151 } 1152 if (properties.ContainsString(MM_MODEM_PROPERTY_PLUGIN)) { 1153 cellular()->set_mm_plugin(properties.GetString(MM_MODEM_PROPERTY_PLUGIN)); 1154 } 1155 if (properties.ContainsString(MM_MODEM_PROPERTY_REVISION)) { 1156 OnModemRevisionChanged(properties.GetString(MM_MODEM_PROPERTY_REVISION)); 1157 } 1158 // not needed: MM_MODEM_PROPERTY_DEVICEIDENTIFIER 1159 // not needed: MM_MODEM_PROPERTY_DEVICE 1160 // not needed: MM_MODEM_PROPERTY_DRIVER 1161 // not needed: MM_MODEM_PROPERTY_PLUGIN 1162 // not needed: MM_MODEM_PROPERTY_EQUIPMENTIDENTIFIER 1163 1164 // Unlock required and SimLock 1165 bool lock_status_changed = false; 1166 if (properties.ContainsUint(MM_MODEM_PROPERTY_UNLOCKREQUIRED)) { 1167 uint32_t unlock_required = 1168 properties.GetUint(MM_MODEM_PROPERTY_UNLOCKREQUIRED); 1169 OnLockTypeChanged(static_cast<MMModemLock>(unlock_required)); 1170 lock_status_changed = true; 1171 } 1172 1173 // Unlock retries 1174 if (properties.Contains(MM_MODEM_PROPERTY_UNLOCKRETRIES)) { 1175 OnLockRetriesChanged( 1176 properties.Get(MM_MODEM_PROPERTY_UNLOCKRETRIES).Get<LockRetryData>()); 1177 lock_status_changed = true; 1178 } 1179 1180 if (lock_status_changed) 1181 OnSimLockStatusChanged(); 1182 1183 if (properties.ContainsUint(MM_MODEM_PROPERTY_ACCESSTECHNOLOGIES)) { 1184 OnAccessTechnologiesChanged( 1185 properties.GetUint(MM_MODEM_PROPERTY_ACCESSTECHNOLOGIES)); 1186 } 1187 1188 if (properties.Contains(MM_MODEM_PROPERTY_SIGNALQUALITY)) { 1189 SignalQuality quality = 1190 properties.Get(MM_MODEM_PROPERTY_SIGNALQUALITY).Get<SignalQuality>(); 1191 OnSignalQualityChanged(std::get<0>(quality)); 1192 } 1193 1194 if (properties.ContainsStrings(MM_MODEM_PROPERTY_OWNNUMBERS)) { 1195 vector<string> numbers = 1196 properties.GetStrings(MM_MODEM_PROPERTY_OWNNUMBERS); 1197 string mdn; 1198 if (numbers.size() > 0) 1199 mdn = numbers[0]; 1200 OnMdnChanged(mdn); 1201 } 1202 1203 if (properties.Contains(MM_MODEM_PROPERTY_SUPPORTEDMODES)) { 1204 SupportedModes mm_supported_modes = 1205 properties.Get(MM_MODEM_PROPERTY_SUPPORTEDMODES).Get<SupportedModes>(); 1206 vector<ModemModes> supported_modes; 1207 for (const auto& modes : mm_supported_modes) { 1208 supported_modes.push_back( 1209 ModemModes(std::get<0>(modes), 1210 static_cast<MMModemMode>(std::get<1>(modes)))); 1211 } 1212 OnSupportedModesChanged(supported_modes); 1213 } 1214 1215 if (properties.Contains(MM_MODEM_PROPERTY_CURRENTMODES)) { 1216 ModesData current_modes = 1217 properties.Get(MM_MODEM_PROPERTY_CURRENTMODES).Get<ModesData>(); 1218 OnCurrentModesChanged( 1219 ModemModes(std::get<0>(current_modes), 1220 static_cast<MMModemMode>(std::get<1>(current_modes)))); 1221 } 1222 1223 // au: MM_MODEM_PROPERTY_SUPPORTEDBANDS, 1224 // au: MM_MODEM_PROPERTY_BANDS 1225} 1226 1227void CellularCapabilityUniversal::OnPropertiesChanged( 1228 const string& interface, 1229 const KeyValueStore& changed_properties, 1230 const vector<string>& invalidated_properties) { 1231 SLOG(this, 3) << __func__ << "(" << interface << ")"; 1232 if (interface == MM_DBUS_INTERFACE_MODEM) { 1233 OnModemPropertiesChanged(changed_properties, invalidated_properties); 1234 } 1235 if (interface == MM_DBUS_INTERFACE_MODEM_MODEM3GPP) { 1236 OnModem3GPPPropertiesChanged(changed_properties, invalidated_properties); 1237 } 1238 if (interface == MM_DBUS_INTERFACE_SIM) { 1239 OnSimPropertiesChanged(changed_properties, invalidated_properties); 1240 } 1241} 1242 1243bool CellularCapabilityUniversal::RetriableConnectError( 1244 const Error& error) const { 1245 if (error.type() == Error::kInvalidApn) 1246 return true; 1247 1248 // ModemManager does not ever return kInvalidApn for an E362 modem (with 1249 // firmware version 1.41) supported by the Novatel LTE plugin. 1250 if ((cellular()->mm_plugin() == kNovatelLTEMMPlugin) && 1251 (error.type() == Error::kOperationFailed)) { 1252 return true; 1253 } 1254 return false; 1255} 1256 1257void CellularCapabilityUniversal::OnNetworkModeSignal(uint32_t /*mode*/) { 1258 // TODO(petkov): Implement this. 1259 NOTIMPLEMENTED(); 1260} 1261 1262bool CellularCapabilityUniversal::IsValidSimPath(const string& sim_path) const { 1263 return !sim_path.empty() && sim_path != kRootPath; 1264} 1265 1266string CellularCapabilityUniversal::NormalizeMdn(const string& mdn) const { 1267 string normalized_mdn; 1268 for (size_t i = 0; i < mdn.size(); ++i) { 1269 if (IsAsciiDigit(mdn[i])) 1270 normalized_mdn += mdn[i]; 1271 } 1272 return normalized_mdn; 1273} 1274 1275void CellularCapabilityUniversal::OnSimPathChanged( 1276 const string& sim_path) { 1277 if (sim_path == sim_path_) 1278 return; 1279 1280 mm1::SimProxyInterface* proxy = nullptr; 1281 if (IsValidSimPath(sim_path)) 1282 proxy = control_interface()->CreateSimProxy(sim_path, 1283 cellular()->dbus_service()); 1284 sim_path_ = sim_path; 1285 sim_proxy_.reset(proxy); 1286 1287 if (!IsValidSimPath(sim_path)) { 1288 // Clear all data about the sim 1289 cellular()->set_imsi(""); 1290 spn_ = ""; 1291 cellular()->set_sim_present(false); 1292 OnSimIdentifierChanged(""); 1293 OnOperatorIdChanged(""); 1294 cellular()->home_provider_info()->Reset(); 1295 } else { 1296 cellular()->set_sim_present(true); 1297 std::unique_ptr<DBusPropertiesProxyInterface> properties_proxy( 1298 control_interface()->CreateDBusPropertiesProxy( 1299 sim_path, cellular()->dbus_service())); 1300 // TODO(jglasgow): convert to async interface 1301 KeyValueStore properties(properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM)); 1302 OnSimPropertiesChanged(properties, vector<string>()); 1303 } 1304} 1305 1306void CellularCapabilityUniversal::OnSupportedCapabilitesChanged( 1307 const vector<uint32_t>& supported_capabilities) { 1308 supported_capabilities_ = supported_capabilities; 1309} 1310 1311void CellularCapabilityUniversal::OnModemCurrentCapabilitiesChanged( 1312 uint32_t current_capabilities) { 1313 current_capabilities_ = current_capabilities; 1314 1315 // Only allow network scan when the modem's current capabilities support 1316 // GSM/UMTS. 1317 // 1318 // TODO(benchan): We should consider having the modem plugins in ModemManager 1319 // reporting whether network scan is supported. 1320 cellular()->set_scanning_supported( 1321 (current_capabilities & MM_MODEM_CAPABILITY_GSM_UMTS) != 0); 1322} 1323 1324void CellularCapabilityUniversal::OnMdnChanged( 1325 const string& mdn) { 1326 cellular()->set_mdn(NormalizeMdn(mdn)); 1327 UpdatePendingActivationState(); 1328} 1329 1330void CellularCapabilityUniversal::OnModemRevisionChanged( 1331 const string& revision) { 1332 cellular()->set_firmware_revision(revision); 1333} 1334 1335void CellularCapabilityUniversal::OnModemStateChanged( 1336 Cellular::ModemState state) { 1337 SLOG(this, 3) << __func__ << ": " << Cellular::GetModemStateString(state); 1338 1339 if (state == Cellular::kModemStateConnected) { 1340 // This assumes that ModemManager updates the Bearers list and the Bearer 1341 // properties before changing Modem state to Connected. 1342 SLOG(this, 2) << "Update active bearer."; 1343 UpdateActiveBearer(); 1344 } 1345 1346 cellular()->OnModemStateChanged(state); 1347 // TODO(armansito): Move the deferred enable logic to Cellular 1348 // (See crbug.com/279499). 1349 if (!deferred_enable_modem_callback_.is_null() && 1350 state == Cellular::kModemStateDisabled) { 1351 SLOG(this, 2) << "Enabling modem after deferring."; 1352 deferred_enable_modem_callback_.Run(); 1353 deferred_enable_modem_callback_.Reset(); 1354 } 1355} 1356 1357void CellularCapabilityUniversal::OnAccessTechnologiesChanged( 1358 uint32_t access_technologies) { 1359 if (access_technologies_ != access_technologies) { 1360 const string old_type_string(GetTypeString()); 1361 access_technologies_ = access_technologies; 1362 const string new_type_string(GetTypeString()); 1363 if (new_type_string != old_type_string) { 1364 // TODO(jglasgow): address layering violation of emitting change 1365 // signal here for a property owned by Cellular. 1366 cellular()->adaptor()->EmitStringChanged( 1367 kTechnologyFamilyProperty, new_type_string); 1368 } 1369 if (cellular()->service().get()) { 1370 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString()); 1371 } 1372 } 1373} 1374 1375void CellularCapabilityUniversal::OnSupportedModesChanged( 1376 const vector<ModemModes>& supported_modes) { 1377 supported_modes_ = supported_modes; 1378} 1379 1380void CellularCapabilityUniversal::OnCurrentModesChanged( 1381 const ModemModes& current_modes) { 1382 current_modes_ = current_modes; 1383} 1384 1385void CellularCapabilityUniversal::OnBearersChanged( 1386 const RpcIdentifiers& bearers) { 1387 bearer_paths_ = bearers; 1388} 1389 1390void CellularCapabilityUniversal::OnLockRetriesChanged( 1391 const LockRetryData& lock_retries) { 1392 SLOG(this, 3) << __func__; 1393 1394 // Look for the retries left for the current lock. Try the obtain the count 1395 // that matches the current count. If no count for the current lock is 1396 // available, report the first one in the dictionary. 1397 LockRetryData::const_iterator it = 1398 lock_retries.find(sim_lock_status_.lock_type); 1399 if (it == lock_retries.end()) 1400 it = lock_retries.begin(); 1401 if (it != lock_retries.end()) 1402 sim_lock_status_.retries_left = it->second; 1403 else 1404 // Unknown, use 999 1405 sim_lock_status_.retries_left = 999; 1406} 1407 1408void CellularCapabilityUniversal::OnLockTypeChanged( 1409 MMModemLock lock_type) { 1410 SLOG(this, 3) << __func__ << ": " << lock_type; 1411 sim_lock_status_.lock_type = lock_type; 1412 1413 // If the SIM is in a locked state |sim_lock_status_.enabled| might be false. 1414 // This is because the corresponding property 'EnabledFacilityLocks' is on 1415 // the 3GPP interface and the 3GPP interface is not available while the Modem 1416 // is in the 'LOCKED' state. 1417 if (lock_type != MM_MODEM_LOCK_NONE && 1418 lock_type != MM_MODEM_LOCK_UNKNOWN && 1419 !sim_lock_status_.enabled) 1420 sim_lock_status_.enabled = true; 1421} 1422 1423void CellularCapabilityUniversal::OnSimLockStatusChanged() { 1424 SLOG(this, 3) << __func__; 1425 cellular()->adaptor()->EmitKeyValueStoreChanged( 1426 kSIMLockStatusProperty, SimLockStatusToProperty(nullptr)); 1427 1428 // If the SIM is currently unlocked, assume that we need to refresh 1429 // carrier information, since a locked SIM prevents shill from obtaining 1430 // the necessary data to establish a connection later (e.g. IMSI). 1431 if (IsValidSimPath(sim_path_) && 1432 (sim_lock_status_.lock_type == MM_MODEM_LOCK_NONE || 1433 sim_lock_status_.lock_type == MM_MODEM_LOCK_UNKNOWN)) { 1434 std::unique_ptr<DBusPropertiesProxyInterface> properties_proxy( 1435 control_interface()->CreateDBusPropertiesProxy( 1436 sim_path_, cellular()->dbus_service())); 1437 KeyValueStore properties( 1438 properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM)); 1439 OnSimPropertiesChanged(properties, vector<string>()); 1440 } 1441} 1442 1443void CellularCapabilityUniversal::OnModem3GPPPropertiesChanged( 1444 const KeyValueStore& properties, 1445 const vector<string>& /* invalidated_properties */) { 1446 SLOG(this, 3) << __func__; 1447 if (properties.ContainsString(MM_MODEM_MODEM3GPP_PROPERTY_IMEI)) 1448 cellular()->set_imei( 1449 properties.GetString(MM_MODEM_MODEM3GPP_PROPERTY_IMEI)); 1450 1451 // Handle registration state changes as a single change 1452 Stringmap::const_iterator it; 1453 string operator_code; 1454 string operator_name; 1455 it = serving_operator_.find(kOperatorCodeKey); 1456 if (it != serving_operator_.end()) 1457 operator_code = it->second; 1458 it = serving_operator_.find(kOperatorNameKey); 1459 if (it != serving_operator_.end()) 1460 operator_name = it->second; 1461 1462 MMModem3gppRegistrationState state = registration_state_; 1463 bool registration_changed = false; 1464 if (properties.ContainsUint(MM_MODEM_MODEM3GPP_PROPERTY_REGISTRATIONSTATE)) { 1465 state = static_cast<MMModem3gppRegistrationState>( 1466 properties.GetUint(MM_MODEM_MODEM3GPP_PROPERTY_REGISTRATIONSTATE)); 1467 registration_changed = true; 1468 } 1469 if (properties.ContainsString(MM_MODEM_MODEM3GPP_PROPERTY_OPERATORCODE)) { 1470 operator_code = 1471 properties.GetString(MM_MODEM_MODEM3GPP_PROPERTY_OPERATORCODE); 1472 registration_changed = true; 1473 } 1474 if (properties.ContainsString(MM_MODEM_MODEM3GPP_PROPERTY_OPERATORNAME)) { 1475 operator_name = 1476 properties.GetString(MM_MODEM_MODEM3GPP_PROPERTY_OPERATORNAME); 1477 registration_changed = true; 1478 } 1479 if (registration_changed) 1480 On3GPPRegistrationChanged(state, operator_code, operator_name); 1481 if (properties.ContainsUint(MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE)) 1482 On3GPPSubscriptionStateChanged( 1483 static_cast<MMModem3gppSubscriptionState>( 1484 properties.GetUint(MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE))); 1485 1486 CellularServiceRefPtr service = cellular()->service(); 1487 if (service.get() && 1488 properties.ContainsUint(MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE)) { 1489 uint32_t subscription_state = 1490 properties.GetUint(MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE); 1491 SLOG(this, 3) << __func__ << ": Subscription state = " 1492 << subscription_state; 1493 service->out_of_credits_detector()->NotifySubscriptionStateChanged( 1494 subscription_state); 1495 } 1496 1497 if (properties.ContainsUint(MM_MODEM_MODEM3GPP_PROPERTY_ENABLEDFACILITYLOCKS)) 1498 OnFacilityLocksChanged( 1499 properties.GetUint(MM_MODEM_MODEM3GPP_PROPERTY_ENABLEDFACILITYLOCKS)); 1500} 1501 1502void CellularCapabilityUniversal::On3GPPRegistrationChanged( 1503 MMModem3gppRegistrationState state, 1504 const string& operator_code, 1505 const string& operator_name) { 1506 SLOG(this, 3) << __func__ << ": regstate=" << state 1507 << ", opercode=" << operator_code 1508 << ", opername=" << operator_name; 1509 1510 // While the modem is connected, if the state changed from a registered state 1511 // to a non registered state, defer the state change by 15 seconds. 1512 if (cellular()->modem_state() == Cellular::kModemStateConnected && 1513 IsRegistered() && !IsRegisteredState(state)) { 1514 if (!registration_dropped_update_callback_.IsCancelled()) { 1515 LOG(WARNING) << "Modem reported consecutive 3GPP registration drops. " 1516 << "Ignoring earlier notifications."; 1517 registration_dropped_update_callback_.Cancel(); 1518 } else { 1519 // This is not a repeated post. So, count this instance of delayed drop 1520 // posted. 1521 modem_info()->metrics()->Notify3GPPRegistrationDelayedDropPosted(); 1522 } 1523 SLOG(this, 2) << "Posted deferred registration state update"; 1524 registration_dropped_update_callback_.Reset( 1525 Bind(&CellularCapabilityUniversal::Handle3GPPRegistrationChange, 1526 weak_ptr_factory_.GetWeakPtr(), 1527 state, 1528 operator_code, 1529 operator_name)); 1530 cellular()->dispatcher()->PostDelayedTask( 1531 registration_dropped_update_callback_.callback(), 1532 registration_dropped_update_timeout_milliseconds_); 1533 } else { 1534 if (!registration_dropped_update_callback_.IsCancelled()) { 1535 SLOG(this, 2) << "Cancelled a deferred registration state update"; 1536 registration_dropped_update_callback_.Cancel(); 1537 // If we cancelled the callback here, it means we had flaky network for a 1538 // small duration. 1539 modem_info()->metrics()->Notify3GPPRegistrationDelayedDropCanceled(); 1540 } 1541 Handle3GPPRegistrationChange(state, operator_code, operator_name); 1542 } 1543} 1544 1545void CellularCapabilityUniversal::Handle3GPPRegistrationChange( 1546 MMModem3gppRegistrationState updated_state, 1547 string updated_operator_code, 1548 string updated_operator_name) { 1549 // A finished callback does not qualify as a canceled callback. 1550 // We test for a canceled callback to check for outstanding callbacks. 1551 // So, explicitly cancel the callback here. 1552 registration_dropped_update_callback_.Cancel(); 1553 1554 SLOG(this, 3) << __func__ << ": regstate=" << updated_state 1555 << ", opercode=" << updated_operator_code 1556 << ", opername=" << updated_operator_name; 1557 1558 registration_state_ = updated_state; 1559 serving_operator_[kOperatorCodeKey] = updated_operator_code; 1560 serving_operator_[kOperatorNameKey] = updated_operator_name; 1561 cellular()->serving_operator_info()->UpdateMCCMNC(updated_operator_code); 1562 cellular()->serving_operator_info()->UpdateOperatorName( 1563 updated_operator_name); 1564 1565 cellular()->HandleNewRegistrationState(); 1566 1567 // If the modem registered with the network and the current ICCID is pending 1568 // activation, then reset the modem. 1569 UpdatePendingActivationState(); 1570} 1571 1572void CellularCapabilityUniversal::On3GPPSubscriptionStateChanged( 1573 MMModem3gppSubscriptionState updated_state) { 1574 SLOG(this, 3) << __func__ << ": Updated subscription state = " 1575 << updated_state; 1576 1577 // A one-to-one enum mapping. 1578 SubscriptionState new_subscription_state; 1579 switch (updated_state) { 1580 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_UNKNOWN: 1581 new_subscription_state = kSubscriptionStateUnknown; 1582 break; 1583 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_PROVISIONED: 1584 new_subscription_state = kSubscriptionStateProvisioned; 1585 break; 1586 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_UNPROVISIONED: 1587 new_subscription_state = kSubscriptionStateUnprovisioned; 1588 break; 1589 case MM_MODEM_3GPP_SUBSCRIPTION_STATE_OUT_OF_DATA: 1590 new_subscription_state = kSubscriptionStateOutOfData; 1591 break; 1592 default: 1593 LOG(ERROR) << "Unrecognized MMModem3gppSubscriptionState: " 1594 << updated_state; 1595 new_subscription_state = kSubscriptionStateUnknown; 1596 return; 1597 } 1598 if (new_subscription_state == subscription_state_) 1599 return; 1600 1601 subscription_state_ = new_subscription_state; 1602 1603 UpdateServiceActivationState(); 1604 UpdatePendingActivationState(); 1605} 1606 1607void CellularCapabilityUniversal::OnModemStateChangedSignal( 1608 int32_t old_state, int32_t new_state, uint32_t reason) { 1609 Cellular::ModemState old_modem_state = 1610 static_cast<Cellular::ModemState>(old_state); 1611 Cellular::ModemState new_modem_state = 1612 static_cast<Cellular::ModemState>(new_state); 1613 SLOG(this, 3) << __func__ << "(" 1614 << Cellular::GetModemStateString(old_modem_state) 1615 << ", " 1616 << Cellular::GetModemStateString(new_modem_state) 1617 << ", " 1618 << reason << ")"; 1619} 1620 1621void CellularCapabilityUniversal::OnSignalQualityChanged(uint32_t quality) { 1622 cellular()->HandleNewSignalQuality(quality); 1623} 1624 1625void CellularCapabilityUniversal::OnFacilityLocksChanged(uint32_t locks) { 1626 bool sim_enabled = !!(locks & MM_MODEM_3GPP_FACILITY_SIM); 1627 if (sim_lock_status_.enabled != sim_enabled) { 1628 sim_lock_status_.enabled = sim_enabled; 1629 OnSimLockStatusChanged(); 1630 } 1631} 1632 1633void CellularCapabilityUniversal::OnSimPropertiesChanged( 1634 const KeyValueStore& props, 1635 const vector<string>& /* invalidated_properties */) { 1636 SLOG(this, 3) << __func__; 1637 if (props.ContainsString(MM_SIM_PROPERTY_SIMIDENTIFIER)) 1638 OnSimIdentifierChanged(props.GetString(MM_SIM_PROPERTY_SIMIDENTIFIER)); 1639 if (props.ContainsString(MM_SIM_PROPERTY_OPERATORIDENTIFIER)) 1640 OnOperatorIdChanged(props.GetString(MM_SIM_PROPERTY_OPERATORIDENTIFIER)); 1641 if (props.ContainsString(MM_SIM_PROPERTY_OPERATORNAME)) 1642 OnSpnChanged(props.GetString(MM_SIM_PROPERTY_OPERATORNAME)); 1643 if (props.ContainsString(MM_SIM_PROPERTY_IMSI)) { 1644 string imsi = props.GetString(MM_SIM_PROPERTY_IMSI); 1645 cellular()->set_imsi(imsi); 1646 cellular()->home_provider_info()->UpdateIMSI(imsi); 1647 // We do not obtain IMSI OTA right now. Provide the value from the SIM to 1648 // serving operator as well, to aid in MVNO identification. 1649 cellular()->serving_operator_info()->UpdateIMSI(imsi); 1650 } 1651} 1652 1653void CellularCapabilityUniversal::OnSpnChanged(const std::string& spn) { 1654 spn_ = spn; 1655 cellular()->home_provider_info()->UpdateOperatorName(spn); 1656} 1657 1658void CellularCapabilityUniversal::OnSimIdentifierChanged(const string& id) { 1659 cellular()->set_sim_identifier(id); 1660 cellular()->home_provider_info()->UpdateICCID(id); 1661 // Provide ICCID to serving operator as well to aid in MVNO identification. 1662 cellular()->serving_operator_info()->UpdateICCID(id); 1663 UpdatePendingActivationState(); 1664} 1665 1666void CellularCapabilityUniversal::OnOperatorIdChanged( 1667 const string& operator_id) { 1668 SLOG(this, 2) << "Operator ID = '" << operator_id << "'"; 1669 cellular()->home_provider_info()->UpdateMCCMNC(operator_id); 1670} 1671 1672OutOfCreditsDetector::OOCType 1673CellularCapabilityUniversal::GetOutOfCreditsDetectionType() const { 1674 if (cellular()->mm_plugin() == kAltairLTEMMPlugin) { 1675 return OutOfCreditsDetector::OOCTypeSubscriptionState; 1676 } else { 1677 return OutOfCreditsDetector::OOCTypeNone; 1678 } 1679} 1680 1681} // namespace shill 1682