1// 2// Copyright (C) 2012 The Android Open Source Project 3// 4// Licensed under the Apache License, Version 2.0 (the "License"); 5// you may not use this file except in compliance with the License. 6// You may obtain a copy of the License at 7// 8// http://www.apache.org/licenses/LICENSE-2.0 9// 10// Unless required by applicable law or agreed to in writing, software 11// distributed under the License is distributed on an "AS IS" BASIS, 12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13// See the License for the specific language governing permissions and 14// limitations under the License. 15// 16 17#include "shill/cellular/cellular_capability_gsm.h" 18 19#include <string> 20#include <vector> 21 22#include <base/bind.h> 23#include <base/stl_util.h> 24#include <base/strings/string_number_conversions.h> 25#include <base/strings/stringprintf.h> 26#if defined(__ANDROID__) 27#include <dbus/service_constants.h> 28#else 29#include <chromeos/dbus/service_constants.h> 30#endif // __ANDROID__ 31#include <mm/mm-modem.h> 32 33#include "shill/adaptor_interfaces.h" 34#include "shill/cellular/cellular_service.h" 35#include "shill/control_interface.h" 36#include "shill/error.h" 37#include "shill/logging.h" 38#include "shill/property_accessor.h" 39 40using base::Bind; 41using std::string; 42using std::vector; 43 44namespace shill { 45 46namespace Logging { 47static auto kModuleLogScope = ScopeLogger::kCellular; 48static string ObjectID(CellularCapabilityGSM* c) { 49 return c->cellular()->GetRpcIdentifier(); 50} 51} 52 53// static 54const char CellularCapabilityGSM::kNetworkPropertyAccessTechnology[] = 55 "access-tech"; 56const char CellularCapabilityGSM::kNetworkPropertyID[] = "operator-num"; 57const char CellularCapabilityGSM::kNetworkPropertyLongName[] = "operator-long"; 58const char CellularCapabilityGSM::kNetworkPropertyShortName[] = 59 "operator-short"; 60const char CellularCapabilityGSM::kNetworkPropertyStatus[] = "status"; 61const char CellularCapabilityGSM::kPhoneNumber[] = "*99#"; 62const char CellularCapabilityGSM::kPropertyAccessTechnology[] = 63 "AccessTechnology"; 64const char CellularCapabilityGSM::kPropertyEnabledFacilityLocks[] = 65 "EnabledFacilityLocks"; 66const char CellularCapabilityGSM::kPropertyUnlockRequired[] = "UnlockRequired"; 67const char CellularCapabilityGSM::kPropertyUnlockRetries[] = "UnlockRetries"; 68 69const int CellularCapabilityGSM::kGetIMSIRetryLimit = 40; 70const int64_t CellularCapabilityGSM::kGetIMSIRetryDelayMilliseconds = 500; 71 72 73CellularCapabilityGSM::CellularCapabilityGSM( 74 Cellular* cellular, 75 ControlInterface* control_interface, 76 ModemInfo* modem_info) 77 : CellularCapabilityClassic(cellular, control_interface, modem_info), 78 weak_ptr_factory_(this), 79 mobile_operator_info_(new MobileOperatorInfo(cellular->dispatcher(), 80 "ParseScanResult")), 81 registration_state_(MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN), 82 access_technology_(MM_MODEM_GSM_ACCESS_TECH_UNKNOWN), 83 home_provider_info_(nullptr), 84 get_imsi_retries_(0), 85 get_imsi_retry_delay_milliseconds_(kGetIMSIRetryDelayMilliseconds) { 86 SLOG(this, 2) << "Cellular capability constructed: GSM"; 87 mobile_operator_info_->Init(); 88 HelpRegisterConstDerivedKeyValueStore( 89 kSIMLockStatusProperty, &CellularCapabilityGSM::SimLockStatusToProperty); 90 this->cellular()->set_scanning_supported(true); 91 92 // TODO(benchan): This is a hack to initialize the GSM card proxy for GetIMSI 93 // before InitProxies is called. There are side-effects of calling InitProxies 94 // before the device is enabled. It's better to refactor InitProxies such that 95 // proxies can be created when the cellular device/capability is constructed, 96 // but callbacks for DBus signal updates are not set up until the device is 97 // enabled. 98 card_proxy_.reset( 99 control_interface->CreateModemGSMCardProxy(cellular->dbus_path(), 100 cellular->dbus_service())); 101 // TODO(benchan): To allow unit testing using a mock proxy without further 102 // complicating the code, the test proxy factory is set up to return a nullptr 103 // pointer when CellularCapabilityGSM is constructed. Refactor the code to 104 // avoid this hack. 105 if (card_proxy_.get()) 106 InitProperties(); 107} 108 109CellularCapabilityGSM::~CellularCapabilityGSM() {} 110 111string CellularCapabilityGSM::GetTypeString() const { 112 return kTechnologyFamilyGsm; 113} 114 115KeyValueStore CellularCapabilityGSM::SimLockStatusToProperty(Error* /*error*/) { 116 KeyValueStore status; 117 status.SetBool(kSIMLockEnabledProperty, sim_lock_status_.enabled); 118 status.SetString(kSIMLockTypeProperty, sim_lock_status_.lock_type); 119 status.SetUint(kSIMLockRetriesLeftProperty, sim_lock_status_.retries_left); 120 return status; 121} 122 123void CellularCapabilityGSM::HelpRegisterConstDerivedKeyValueStore( 124 const string& name, 125 KeyValueStore(CellularCapabilityGSM::*get)(Error* error)) { 126 cellular()->mutable_store()->RegisterDerivedKeyValueStore( 127 name, 128 KeyValueStoreAccessor( 129 new CustomAccessor<CellularCapabilityGSM, KeyValueStore>( 130 this, get, nullptr))); 131} 132 133void CellularCapabilityGSM::InitProxies() { 134 CellularCapabilityClassic::InitProxies(); 135 // TODO(benchan): Remove this check after refactoring the proxy 136 // initialization. 137 if (!card_proxy_.get()) { 138 card_proxy_.reset( 139 control_interface()->CreateModemGSMCardProxy( 140 cellular()->dbus_path(), cellular()->dbus_service())); 141 } 142 network_proxy_.reset( 143 control_interface()->CreateModemGSMNetworkProxy( 144 cellular()->dbus_path(), cellular()->dbus_service())); 145 network_proxy_->set_signal_quality_callback( 146 Bind(&CellularCapabilityGSM::OnSignalQualitySignal, 147 weak_ptr_factory_.GetWeakPtr())); 148 network_proxy_->set_network_mode_callback( 149 Bind(&CellularCapabilityGSM::OnNetworkModeSignal, 150 weak_ptr_factory_.GetWeakPtr())); 151 network_proxy_->set_registration_info_callback( 152 Bind(&CellularCapabilityGSM::OnRegistrationInfoSignal, 153 weak_ptr_factory_.GetWeakPtr())); 154} 155 156void CellularCapabilityGSM::InitProperties() { 157 CellularTaskList* tasks = new CellularTaskList(); 158 ResultCallback cb_ignore_error = 159 Bind(&CellularCapabilityGSM::StepCompletedCallback, 160 weak_ptr_factory_.GetWeakPtr(), ResultCallback(), true, tasks); 161 // Chrome checks if a SIM is present before allowing the modem to be enabled, 162 // so shill needs to obtain IMSI, as an indicator of SIM presence, even 163 // before the device is enabled. 164 tasks->push_back(Bind(&CellularCapabilityGSM::GetIMSI, 165 weak_ptr_factory_.GetWeakPtr(), cb_ignore_error)); 166 RunNextStep(tasks); 167} 168 169void CellularCapabilityGSM::StartModem(Error* error, 170 const ResultCallback& callback) { 171 InitProxies(); 172 173 CellularTaskList* tasks = new CellularTaskList(); 174 ResultCallback cb = 175 Bind(&CellularCapabilityGSM::StepCompletedCallback, 176 weak_ptr_factory_.GetWeakPtr(), callback, false, tasks); 177 ResultCallback cb_ignore_error = 178 Bind(&CellularCapabilityGSM::StepCompletedCallback, 179 weak_ptr_factory_.GetWeakPtr(), callback, true, tasks); 180 if (!cellular()->IsUnderlyingDeviceEnabled()) 181 tasks->push_back(Bind(&CellularCapabilityGSM::EnableModem, 182 weak_ptr_factory_.GetWeakPtr(), cb)); 183 // If we're within range of the home network, the modem will try to 184 // register once it's enabled, or may be already registered if we 185 // started out enabled. 186 if (!IsUnderlyingDeviceRegistered() && 187 !cellular()->selected_network().empty()) 188 tasks->push_back(Bind(&CellularCapabilityGSM::Register, 189 weak_ptr_factory_.GetWeakPtr(), cb)); 190 tasks->push_back(Bind(&CellularCapabilityGSM::GetIMEI, 191 weak_ptr_factory_.GetWeakPtr(), cb)); 192 get_imsi_retries_ = 0; 193 tasks->push_back(Bind(&CellularCapabilityGSM::GetIMSI, 194 weak_ptr_factory_.GetWeakPtr(), cb)); 195 tasks->push_back(Bind(&CellularCapabilityGSM::GetSPN, 196 weak_ptr_factory_.GetWeakPtr(), cb_ignore_error)); 197 tasks->push_back(Bind(&CellularCapabilityGSM::GetMSISDN, 198 weak_ptr_factory_.GetWeakPtr(), cb_ignore_error)); 199 tasks->push_back(Bind(&CellularCapabilityGSM::GetProperties, 200 weak_ptr_factory_.GetWeakPtr(), cb)); 201 tasks->push_back(Bind(&CellularCapabilityGSM::GetModemInfo, 202 weak_ptr_factory_.GetWeakPtr(), cb_ignore_error)); 203 tasks->push_back(Bind(&CellularCapabilityGSM::FinishEnable, 204 weak_ptr_factory_.GetWeakPtr(), cb)); 205 206 RunNextStep(tasks); 207} 208 209bool CellularCapabilityGSM::IsUnderlyingDeviceRegistered() const { 210 switch (cellular()->modem_state()) { 211 case Cellular::kModemStateFailed: 212 case Cellular::kModemStateUnknown: 213 case Cellular::kModemStateDisabled: 214 case Cellular::kModemStateInitializing: 215 case Cellular::kModemStateLocked: 216 case Cellular::kModemStateDisabling: 217 case Cellular::kModemStateEnabling: 218 case Cellular::kModemStateEnabled: 219 return false; 220 case Cellular::kModemStateSearching: 221 case Cellular::kModemStateRegistered: 222 case Cellular::kModemStateDisconnecting: 223 case Cellular::kModemStateConnecting: 224 case Cellular::kModemStateConnected: 225 return true; 226 } 227 return false; 228} 229 230void CellularCapabilityGSM::ReleaseProxies() { 231 SLOG(this, 2) << __func__; 232 CellularCapabilityClassic::ReleaseProxies(); 233 card_proxy_.reset(); 234 network_proxy_.reset(); 235} 236 237bool CellularCapabilityGSM::AreProxiesInitialized() const { 238 return (CellularCapabilityClassic::AreProxiesInitialized() && 239 card_proxy_.get() && network_proxy_.get()); 240} 241 242void CellularCapabilityGSM::OnServiceCreated() { 243 cellular()->service()->SetActivationState(kActivationStateActivated); 244} 245 246// Create the list of APNs to try, in the following order: 247// - last APN that resulted in a successful connection attempt on the 248// current network (if any) 249// - the APN, if any, that was set by the user 250// - the list of APNs found in the mobile broadband provider DB for the 251// home provider associated with the current SIM 252// - as a last resort, attempt to connect with no APN 253void CellularCapabilityGSM::SetupApnTryList() { 254 apn_try_list_.clear(); 255 256 DCHECK(cellular()->service().get()); 257 const Stringmap* apn_info = cellular()->service()->GetLastGoodApn(); 258 if (apn_info) 259 apn_try_list_.push_back(*apn_info); 260 261 apn_info = cellular()->service()->GetUserSpecifiedApn(); 262 if (apn_info) 263 apn_try_list_.push_back(*apn_info); 264 265 apn_try_list_.insert(apn_try_list_.end(), 266 cellular()->apn_list().begin(), 267 cellular()->apn_list().end()); 268} 269 270void CellularCapabilityGSM::SetupConnectProperties( 271 KeyValueStore* properties) { 272 SetupApnTryList(); 273 FillConnectPropertyMap(properties); 274} 275 276void CellularCapabilityGSM::FillConnectPropertyMap( 277 KeyValueStore* properties) { 278 properties->SetString(kConnectPropertyPhoneNumber, kPhoneNumber); 279 280 if (!AllowRoaming()) 281 properties->SetBool(kConnectPropertyHomeOnly, true); 282 283 if (!apn_try_list_.empty()) { 284 // Leave the APN at the front of the list, so that it can be recorded 285 // if the connect attempt succeeds. 286 Stringmap apn_info = apn_try_list_.front(); 287 SLOG(this, 2) << __func__ << ": Using APN " << apn_info[kApnProperty]; 288 properties->SetString(kConnectPropertyApn, apn_info[kApnProperty]); 289 if (ContainsKey(apn_info, kApnUsernameProperty)) 290 properties->SetString(kConnectPropertyApnUsername, 291 apn_info[kApnUsernameProperty]); 292 if (ContainsKey(apn_info, kApnPasswordProperty)) 293 properties->SetString(kConnectPropertyApnPassword, 294 apn_info[kApnPasswordProperty]); 295 } 296} 297 298void CellularCapabilityGSM::Connect(const KeyValueStore& properties, 299 Error* error, 300 const ResultCallback& callback) { 301 SLOG(this, 2) << __func__; 302 ResultCallback cb = Bind(&CellularCapabilityGSM::OnConnectReply, 303 weak_ptr_factory_.GetWeakPtr(), 304 callback); 305 simple_proxy_->Connect(properties, error, cb, kTimeoutConnect); 306} 307 308void CellularCapabilityGSM::OnConnectReply(const ResultCallback& callback, 309 const Error& error) { 310 CellularServiceRefPtr service = cellular()->service(); 311 if (!service) { 312 // The service could have been deleted before our Connect() request 313 // completes if the modem was enabled and then quickly disabled. 314 apn_try_list_.clear(); 315 } else if (error.IsFailure()) { 316 service->ClearLastGoodApn(); 317 // The APN that was just tried (and failed) is still at the 318 // front of the list, about to be removed. If the list is empty 319 // after that, try one last time without an APN. This may succeed 320 // with some modems in some cases. 321 if (error.type() == Error::kInvalidApn && !apn_try_list_.empty()) { 322 apn_try_list_.pop_front(); 323 SLOG(this, 2) << "Connect failed with invalid APN, " 324 << apn_try_list_.size() << " remaining APNs to try"; 325 KeyValueStore props; 326 FillConnectPropertyMap(&props); 327 Error error; 328 Connect(props, &error, callback); 329 return; 330 } 331 } else if (!apn_try_list_.empty()) { 332 service->SetLastGoodApn(apn_try_list_.front()); 333 apn_try_list_.clear(); 334 } 335 if (!callback.is_null()) 336 callback.Run(error); 337} 338 339bool CellularCapabilityGSM::AllowRoaming() { 340 return cellular()->provider_requires_roaming() || allow_roaming_property(); 341} 342 343// always called from an async context 344void CellularCapabilityGSM::GetIMEI(const ResultCallback& callback) { 345 SLOG(this, 2) << __func__; 346 CHECK(!callback.is_null()); 347 Error error; 348 if (cellular()->imei().empty()) { 349 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetIMEIReply, 350 weak_ptr_factory_.GetWeakPtr(), callback); 351 card_proxy_->GetIMEI(&error, cb, kTimeoutDefault); 352 if (error.IsFailure()) 353 callback.Run(error); 354 } else { 355 SLOG(this, 2) << "Already have IMEI " << cellular()->imei(); 356 callback.Run(error); 357 } 358} 359 360// always called from an async context 361void CellularCapabilityGSM::GetIMSI(const ResultCallback& callback) { 362 SLOG(this, 2) << __func__; 363 CHECK(!callback.is_null()); 364 Error error; 365 if (cellular()->imsi().empty()) { 366 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetIMSIReply, 367 weak_ptr_factory_.GetWeakPtr(), 368 callback); 369 card_proxy_->GetIMSI(&error, cb, kTimeoutDefault); 370 if (error.IsFailure()) { 371 cellular()->home_provider_info()->Reset(); 372 callback.Run(error); 373 } 374 } else { 375 SLOG(this, 2) << "Already have IMSI " << cellular()->imsi(); 376 callback.Run(error); 377 } 378} 379 380// always called from an async context 381void CellularCapabilityGSM::GetSPN(const ResultCallback& callback) { 382 SLOG(this, 2) << __func__; 383 CHECK(!callback.is_null()); 384 Error error; 385 if (spn_.empty()) { 386 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetSPNReply, 387 weak_ptr_factory_.GetWeakPtr(), 388 callback); 389 card_proxy_->GetSPN(&error, cb, kTimeoutDefault); 390 if (error.IsFailure()) 391 callback.Run(error); 392 } else { 393 SLOG(this, 2) << "Already have SPN " << spn_; 394 callback.Run(error); 395 } 396} 397 398// always called from an async context 399void CellularCapabilityGSM::GetMSISDN(const ResultCallback& callback) { 400 SLOG(this, 2) << __func__; 401 CHECK(!callback.is_null()); 402 Error error; 403 string mdn = cellular()->mdn(); 404 if (mdn.empty()) { 405 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetMSISDNReply, 406 weak_ptr_factory_.GetWeakPtr(), 407 callback); 408 card_proxy_->GetMSISDN(&error, cb, kTimeoutDefault); 409 if (error.IsFailure()) 410 callback.Run(error); 411 } else { 412 SLOG(this, 2) << "Already have MSISDN " << mdn; 413 callback.Run(error); 414 } 415} 416 417void CellularCapabilityGSM::GetSignalQuality() { 418 SLOG(this, 2) << __func__; 419 SignalQualityCallback callback = 420 Bind(&CellularCapabilityGSM::OnGetSignalQualityReply, 421 weak_ptr_factory_.GetWeakPtr()); 422 network_proxy_->GetSignalQuality(nullptr, callback, kTimeoutDefault); 423} 424 425void CellularCapabilityGSM::GetRegistrationState() { 426 SLOG(this, 2) << __func__; 427 RegistrationInfoCallback callback = 428 Bind(&CellularCapabilityGSM::OnGetRegistrationInfoReply, 429 weak_ptr_factory_.GetWeakPtr()); 430 network_proxy_->GetRegistrationInfo(nullptr, callback, kTimeoutDefault); 431} 432 433void CellularCapabilityGSM::GetProperties(const ResultCallback& callback) { 434 SLOG(this, 2) << __func__; 435 436 // TODO(petkov): Switch to asynchronous calls (crbug.com/200687). 437 uint32_t tech = network_proxy_->AccessTechnology(); 438 SetAccessTechnology(tech); 439 SLOG(this, 2) << "GSM AccessTechnology: " << tech; 440 441 // TODO(petkov): Switch to asynchronous calls (crbug.com/200687). 442 uint32_t locks = card_proxy_->EnabledFacilityLocks(); 443 sim_lock_status_.enabled = locks & MM_MODEM_GSM_FACILITY_SIM; 444 SLOG(this, 2) << "GSM EnabledFacilityLocks: " << locks; 445 446 callback.Run(Error()); 447} 448 449// always called from an async context 450void CellularCapabilityGSM::Register(const ResultCallback& callback) { 451 SLOG(this, 2) << __func__ << " \"" << cellular()->selected_network() 452 << "\""; 453 CHECK(!callback.is_null()); 454 Error error; 455 ResultCallback cb = Bind(&CellularCapabilityGSM::OnRegisterReply, 456 weak_ptr_factory_.GetWeakPtr(), callback); 457 network_proxy_->Register(cellular()->selected_network(), &error, cb, 458 kTimeoutRegister); 459 if (error.IsFailure()) 460 callback.Run(error); 461} 462 463void CellularCapabilityGSM::RegisterOnNetwork( 464 const string& network_id, 465 Error* error, 466 const ResultCallback& callback) { 467 SLOG(this, 2) << __func__ << "(" << network_id << ")"; 468 CHECK(error); 469 desired_network_ = network_id; 470 ResultCallback cb = Bind(&CellularCapabilityGSM::OnRegisterReply, 471 weak_ptr_factory_.GetWeakPtr(), callback); 472 network_proxy_->Register(network_id, error, cb, kTimeoutRegister); 473} 474 475void CellularCapabilityGSM::OnRegisterReply(const ResultCallback& callback, 476 const Error& error) { 477 SLOG(this, 2) << __func__ << "(" << error << ")"; 478 479 if (error.IsSuccess()) { 480 cellular()->set_selected_network(desired_network_); 481 desired_network_.clear(); 482 callback.Run(error); 483 return; 484 } 485 // If registration on the desired network failed, 486 // try to register on the home network. 487 if (!desired_network_.empty()) { 488 desired_network_.clear(); 489 cellular()->set_selected_network(""); 490 LOG(INFO) << "Couldn't register on selected network, trying home network"; 491 Register(callback); 492 return; 493 } 494 callback.Run(error); 495} 496 497bool CellularCapabilityGSM::IsRegistered() const { 498 return (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME || 499 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING); 500} 501 502void CellularCapabilityGSM::SetUnregistered(bool searching) { 503 // If we're already in some non-registered state, don't override that 504 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME || 505 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING) { 506 registration_state_ = 507 (searching ? MM_MODEM_GSM_NETWORK_REG_STATUS_SEARCHING : 508 MM_MODEM_GSM_NETWORK_REG_STATUS_IDLE); 509 } 510} 511 512void CellularCapabilityGSM::RequirePIN( 513 const std::string& pin, bool require, 514 Error* error, const ResultCallback& callback) { 515 CHECK(error); 516 card_proxy_->EnablePIN(pin, require, error, callback, kTimeoutDefault); 517} 518 519void CellularCapabilityGSM::EnterPIN(const string& pin, 520 Error* error, 521 const ResultCallback& callback) { 522 CHECK(error); 523 card_proxy_->SendPIN(pin, error, callback, kTimeoutDefault); 524} 525 526void CellularCapabilityGSM::UnblockPIN(const string& unblock_code, 527 const string& pin, 528 Error* error, 529 const ResultCallback& callback) { 530 CHECK(error); 531 card_proxy_->SendPUK(unblock_code, pin, error, callback, kTimeoutDefault); 532} 533 534void CellularCapabilityGSM::ChangePIN( 535 const string& old_pin, const string& new_pin, 536 Error* error, const ResultCallback& callback) { 537 CHECK(error); 538 card_proxy_->ChangePIN(old_pin, new_pin, error, callback, kTimeoutDefault); 539} 540 541void CellularCapabilityGSM::Scan(Error* error, 542 const ResultStringmapsCallback& callback) { 543 ScanResultsCallback cb = Bind(&CellularCapabilityGSM::OnScanReply, 544 weak_ptr_factory_.GetWeakPtr(), callback); 545 network_proxy_->Scan(error, cb, kTimeoutScan); 546} 547 548void CellularCapabilityGSM::OnScanReply( 549 const ResultStringmapsCallback& callback, 550 const GSMScanResults& results, 551 const Error& error) { 552 Stringmaps found_networks; 553 for (const auto& result : results) 554 found_networks.push_back(ParseScanResult(result)); 555 callback.Run(found_networks, error); 556} 557 558Stringmap CellularCapabilityGSM::ParseScanResult(const GSMScanResult& result) { 559 Stringmap parsed; 560 for (GSMScanResult::const_iterator it = result.begin(); 561 it != result.end(); ++it) { 562 // TODO(petkov): Define these in system_api/service_constants.h. The 563 // numerical values are taken from 3GPP TS 27.007 Section 7.3. 564 static const char* const kStatusString[] = { 565 "unknown", 566 "available", 567 "current", 568 "forbidden", 569 }; 570 static const char* const kTechnologyString[] = { 571 kNetworkTechnologyGsm, 572 "GSM Compact", 573 kNetworkTechnologyUmts, 574 kNetworkTechnologyEdge, 575 "HSDPA", 576 "HSUPA", 577 kNetworkTechnologyHspa, 578 }; 579 SLOG(this, 2) << "Network property: " << it->first << " = " 580 << it->second; 581 if (it->first == kNetworkPropertyStatus) { 582 int status = 0; 583 if (base::StringToInt(it->second, &status) && 584 status >= 0 && 585 status < static_cast<int>(arraysize(kStatusString))) { 586 parsed[kStatusProperty] = kStatusString[status]; 587 } else { 588 LOG(ERROR) << "Unexpected status value: " << it->second; 589 } 590 } else if (it->first == kNetworkPropertyID) { 591 parsed[kNetworkIdProperty] = it->second; 592 } else if (it->first == kNetworkPropertyLongName) { 593 parsed[kLongNameProperty] = it->second; 594 } else if (it->first == kNetworkPropertyShortName) { 595 parsed[kShortNameProperty] = it->second; 596 } else if (it->first == kNetworkPropertyAccessTechnology) { 597 int tech = 0; 598 if (base::StringToInt(it->second, &tech) && 599 tech >= 0 && 600 tech < static_cast<int>(arraysize(kTechnologyString))) { 601 parsed[kTechnologyProperty] = kTechnologyString[tech]; 602 } else { 603 LOG(ERROR) << "Unexpected technology value: " << it->second; 604 } 605 } else { 606 LOG(WARNING) << "Unknown network property ignored: " << it->first; 607 } 608 } 609 // If the long name is not available but the network ID is, look up the long 610 // name in the mobile provider database. 611 if ((!ContainsKey(parsed, kLongNameProperty) || 612 parsed[kLongNameProperty].empty()) && 613 ContainsKey(parsed, kNetworkIdProperty)) { 614 mobile_operator_info_->Reset(); 615 mobile_operator_info_->UpdateMCCMNC(parsed[kNetworkIdProperty]); 616 if (mobile_operator_info_->IsMobileNetworkOperatorKnown() && 617 !mobile_operator_info_->operator_name().empty()) { 618 parsed[kLongNameProperty] = mobile_operator_info_->operator_name(); 619 } 620 } 621 return parsed; 622} 623 624void CellularCapabilityGSM::SetAccessTechnology(uint32_t access_technology) { 625 access_technology_ = access_technology; 626 if (cellular()->service().get()) { 627 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString()); 628 } 629} 630 631string CellularCapabilityGSM::GetNetworkTechnologyString() const { 632 switch (access_technology_) { 633 case MM_MODEM_GSM_ACCESS_TECH_GSM: 634 case MM_MODEM_GSM_ACCESS_TECH_GSM_COMPACT: 635 return kNetworkTechnologyGsm; 636 case MM_MODEM_GSM_ACCESS_TECH_GPRS: 637 return kNetworkTechnologyGprs; 638 case MM_MODEM_GSM_ACCESS_TECH_EDGE: 639 return kNetworkTechnologyEdge; 640 case MM_MODEM_GSM_ACCESS_TECH_UMTS: 641 return kNetworkTechnologyUmts; 642 case MM_MODEM_GSM_ACCESS_TECH_HSDPA: 643 case MM_MODEM_GSM_ACCESS_TECH_HSUPA: 644 case MM_MODEM_GSM_ACCESS_TECH_HSPA: 645 return kNetworkTechnologyHspa; 646 case MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS: 647 return kNetworkTechnologyHspaPlus; 648 default: 649 break; 650 } 651 return ""; 652} 653 654string CellularCapabilityGSM::GetRoamingStateString() const { 655 switch (registration_state_) { 656 case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME: 657 return kRoamingStateHome; 658 case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING: 659 return kRoamingStateRoaming; 660 default: 661 break; 662 } 663 return kRoamingStateUnknown; 664} 665 666void CellularCapabilityGSM::OnPropertiesChanged( 667 const string& interface, 668 const KeyValueStore& properties, 669 const vector<string>& invalidated_properties) { 670 CellularCapabilityClassic::OnPropertiesChanged(interface, 671 properties, 672 invalidated_properties); 673 if (interface == MM_MODEM_GSM_NETWORK_INTERFACE) { 674 if (properties.ContainsUint(kPropertyAccessTechnology)) { 675 SetAccessTechnology(properties.GetUint(kPropertyAccessTechnology)); 676 } 677 } else { 678 bool emit = false; 679 if (interface == MM_MODEM_GSM_CARD_INTERFACE) { 680 if (properties.ContainsUint(kPropertyEnabledFacilityLocks)) { 681 uint32_t locks = properties.GetUint(kPropertyEnabledFacilityLocks); 682 sim_lock_status_.enabled = locks & MM_MODEM_GSM_FACILITY_SIM; 683 emit = true; 684 } 685 } else if (interface == MM_MODEM_INTERFACE) { 686 if (properties.ContainsString(kPropertyUnlockRequired)) { 687 sim_lock_status_.lock_type = 688 properties.GetString(kPropertyUnlockRequired); 689 emit = true; 690 } 691 if (properties.ContainsUint(kPropertyUnlockRetries)) { 692 sim_lock_status_.retries_left = 693 properties.GetUint(kPropertyUnlockRetries); 694 emit = true; 695 } 696 } 697 // TODO(pprabhu) Rename |emit| to |sim_present| after |sim_lock_status| 698 // moves to cellular. 699 if (emit) { 700 cellular()->set_sim_present(true); 701 cellular()->adaptor()->EmitKeyValueStoreChanged( 702 kSIMLockStatusProperty, SimLockStatusToProperty(nullptr)); 703 } 704 } 705} 706 707void CellularCapabilityGSM::OnNetworkModeSignal(uint32_t /*mode*/) { 708 // TODO(petkov): Implement this. 709 NOTIMPLEMENTED(); 710} 711 712void CellularCapabilityGSM::OnRegistrationInfoSignal( 713 uint32_t status, const string& operator_code, const string& operator_name) { 714 SLOG(this, 2) << __func__ << ": regstate=" << status 715 << ", opercode=" << operator_code 716 << ", opername=" << operator_name; 717 registration_state_ = status; 718 cellular()->serving_operator_info()->UpdateMCCMNC(operator_code); 719 cellular()->serving_operator_info()->UpdateOperatorName(operator_name); 720 cellular()->HandleNewRegistrationState(); 721} 722 723void CellularCapabilityGSM::OnSignalQualitySignal(uint32_t quality) { 724 cellular()->HandleNewSignalQuality(quality); 725} 726 727void CellularCapabilityGSM::OnGetRegistrationInfoReply( 728 uint32_t status, const string& operator_code, const string& operator_name, 729 const Error& error) { 730 if (error.IsSuccess()) 731 OnRegistrationInfoSignal(status, operator_code, operator_name); 732} 733 734void CellularCapabilityGSM::OnGetSignalQualityReply(uint32_t quality, 735 const Error& error) { 736 if (error.IsSuccess()) 737 OnSignalQualitySignal(quality); 738} 739 740void CellularCapabilityGSM::OnGetIMEIReply(const ResultCallback& callback, 741 const string& imei, 742 const Error& error) { 743 if (error.IsSuccess()) { 744 SLOG(this, 2) << "IMEI: " << imei; 745 cellular()->set_imei(imei); 746 } else { 747 SLOG(this, 2) << "GetIMEI failed - " << error; 748 } 749 callback.Run(error); 750} 751 752void CellularCapabilityGSM::OnGetIMSIReply(const ResultCallback& callback, 753 const string& imsi, 754 const Error& error) { 755 if (error.IsSuccess()) { 756 SLOG(this, 2) << "IMSI: " << imsi; 757 cellular()->set_imsi(imsi); 758 cellular()->set_sim_present(true); 759 cellular()->home_provider_info()->UpdateIMSI(imsi); 760 // We do not currently obtain the IMSI OTA at all. Provide the IMSI from the 761 // SIM to the serving operator as well to aid in MVNO identification. 762 cellular()->serving_operator_info()->UpdateIMSI(imsi); 763 callback.Run(error); 764 } else if (!sim_lock_status_.lock_type.empty()) { 765 SLOG(this, 2) << "GetIMSI failed - SIM lock in place."; 766 cellular()->set_sim_present(true); 767 callback.Run(error); 768 } else { 769 cellular()->set_sim_present(false); 770 if (get_imsi_retries_++ < kGetIMSIRetryLimit) { 771 SLOG(this, 2) << "GetIMSI failed - " << error << ". Retrying"; 772 base::Callback<void(void)> retry_get_imsi_cb = 773 Bind(&CellularCapabilityGSM::GetIMSI, 774 weak_ptr_factory_.GetWeakPtr(), callback); 775 cellular()->dispatcher()->PostDelayedTask( 776 retry_get_imsi_cb, 777 get_imsi_retry_delay_milliseconds_); 778 } else { 779 LOG(INFO) << "GetIMSI failed - " << error; 780 cellular()->home_provider_info()->Reset(); 781 callback.Run(error); 782 } 783 } 784} 785 786void CellularCapabilityGSM::OnGetSPNReply(const ResultCallback& callback, 787 const string& spn, 788 const Error& error) { 789 if (error.IsSuccess()) { 790 SLOG(this, 2) << "SPN: " << spn; 791 spn_ = spn; 792 cellular()->home_provider_info()->UpdateOperatorName(spn); 793 } else { 794 SLOG(this, 2) << "GetSPN failed - " << error; 795 } 796 callback.Run(error); 797} 798 799void CellularCapabilityGSM::OnGetMSISDNReply(const ResultCallback& callback, 800 const string& msisdn, 801 const Error& error) { 802 if (error.IsSuccess()) { 803 SLOG(this, 2) << "MSISDN: " << msisdn; 804 cellular()->set_mdn(msisdn); 805 } else { 806 SLOG(this, 2) << "GetMSISDN failed - " << error; 807 } 808 callback.Run(error); 809} 810 811} // namespace shill 812