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.h" 18 19 #include <netinet/in.h> 20 #include <linux/if.h> // NOLINT - Needs definitions from netinet/in.h 21 22 #include <string> 23 #include <utility> 24 #include <vector> 25 26 #include <base/bind.h> 27 #include <base/callback.h> 28 #include <base/files/file_path.h> 29 #include <base/strings/string_util.h> 30 #include <base/strings/stringprintf.h> 31 #if defined(__ANDROID__) 32 #include <dbus/service_constants.h> 33 #else 34 #include <chromeos/dbus/service_constants.h> 35 #endif // __ANDROID__ 36 37 #include "shill/adaptor_interfaces.h" 38 #include "shill/cellular/cellular_bearer.h" 39 #include "shill/cellular/cellular_capability_cdma.h" 40 #include "shill/cellular/cellular_capability_gsm.h" 41 #include "shill/cellular/cellular_capability_universal.h" 42 #include "shill/cellular/cellular_capability_universal_cdma.h" 43 #include "shill/cellular/cellular_service.h" 44 #include "shill/cellular/mobile_operator_info.h" 45 #include "shill/control_interface.h" 46 #include "shill/device.h" 47 #include "shill/device_info.h" 48 #include "shill/error.h" 49 #include "shill/event_dispatcher.h" 50 #include "shill/external_task.h" 51 #include "shill/logging.h" 52 #include "shill/manager.h" 53 #include "shill/net/rtnl_handler.h" 54 #include "shill/ppp_daemon.h" 55 #include "shill/ppp_device.h" 56 #include "shill/ppp_device_factory.h" 57 #include "shill/process_manager.h" 58 #include "shill/profile.h" 59 #include "shill/property_accessor.h" 60 #include "shill/store_interface.h" 61 #include "shill/technology.h" 62 63 using base::Bind; 64 using base::Closure; 65 using base::FilePath; 66 using base::StringPrintf; 67 using std::map; 68 using std::string; 69 using std::vector; 70 71 namespace shill { 72 73 namespace Logging { 74 static auto kModuleLogScope = ScopeLogger::kCellular; 75 static string ObjectID(Cellular* c) { return c->GetRpcIdentifier(); } 76 } 77 78 // static 79 const char Cellular::kAllowRoaming[] = "AllowRoaming"; 80 const int64_t Cellular::kDefaultScanningTimeoutMilliseconds = 60000; 81 const char Cellular::kGenericServiceNamePrefix[] = "MobileNetwork"; 82 unsigned int Cellular::friendly_service_name_id_ = 1; 83 84 Cellular::Cellular(ModemInfo* modem_info, 85 const string& link_name, 86 const string& address, 87 int interface_index, 88 Type type, 89 const string& service, 90 const string& path) 91 : Device(modem_info->control_interface(), 92 modem_info->dispatcher(), 93 modem_info->metrics(), 94 modem_info->manager(), 95 link_name, 96 address, 97 interface_index, 98 Technology::kCellular), 99 weak_ptr_factory_(this), 100 state_(kStateDisabled), 101 modem_state_(kModemStateUnknown), 102 home_provider_info_( 103 new MobileOperatorInfo(modem_info->dispatcher(), "HomeProvider")), 104 serving_operator_info_( 105 new MobileOperatorInfo(modem_info->dispatcher(), "ServingOperator")), 106 mobile_operator_info_observer_( 107 new Cellular::MobileOperatorInfoObserver(this)), 108 dbus_service_(service), 109 dbus_path_(path), 110 scanning_supported_(false), 111 scanning_(false), 112 provider_requires_roaming_(false), 113 scan_interval_(0), 114 sim_present_(false), 115 prl_version_(0), 116 modem_info_(modem_info), 117 type_(type), 118 ppp_device_factory_(PPPDeviceFactory::GetInstance()), 119 process_manager_(ProcessManager::GetInstance()), 120 allow_roaming_(false), 121 proposed_scan_in_progress_(false), 122 explicit_disconnect_(false), 123 is_ppp_authenticating_(false), 124 scanning_timeout_milliseconds_(kDefaultScanningTimeoutMilliseconds) { 125 RegisterProperties(); 126 InitCapability(type); 127 128 // TODO(pprabhu) Split MobileOperatorInfo into a context that stores the 129 // costly database, and lighter objects that |Cellular| can own. 130 // crbug.com/363874 131 home_provider_info_->Init(); 132 serving_operator_info_->Init(); 133 home_provider_info()->AddObserver(mobile_operator_info_observer_.get()); 134 serving_operator_info()->AddObserver(mobile_operator_info_observer_.get()); 135 136 SLOG(this, 2) << "Cellular device " << this->link_name() 137 << " initialized."; 138 } 139 140 Cellular::~Cellular() { 141 // Under certain conditions, Cellular::StopModem may not be 142 // called before the Cellular device is destroyed. This happens if the dbus 143 // modem exported by the modem-manager daemon disappears soon after the modem 144 // is disabled, not giving shill enough time to complete the disable 145 // operation. 146 // In that case, the termination action associated with this cellular object 147 // may not have been removed. 148 manager()->RemoveTerminationAction(FriendlyName()); 149 150 home_provider_info()->RemoveObserver(mobile_operator_info_observer_.get()); 151 serving_operator_info()->RemoveObserver( 152 mobile_operator_info_observer_.get()); 153 // Explicitly delete the observer to ensure that it is destroyed before the 154 // handle to |capability_| that it holds. 155 mobile_operator_info_observer_.reset(); 156 } 157 158 bool Cellular::Load(StoreInterface* storage) { 159 const string id = GetStorageIdentifier(); 160 if (!storage->ContainsGroup(id)) { 161 LOG(WARNING) << "Device is not available in the persistent store: " << id; 162 return false; 163 } 164 storage->GetBool(id, kAllowRoaming, &allow_roaming_); 165 return Device::Load(storage); 166 } 167 168 bool Cellular::Save(StoreInterface* storage) { 169 const string id = GetStorageIdentifier(); 170 storage->SetBool(id, kAllowRoaming, allow_roaming_); 171 return Device::Save(storage); 172 } 173 174 // static 175 string Cellular::GetStateString(State state) { 176 switch (state) { 177 case kStateDisabled: 178 return "CellularStateDisabled"; 179 case kStateEnabled: 180 return "CellularStateEnabled"; 181 case kStateRegistered: 182 return "CellularStateRegistered"; 183 case kStateConnected: 184 return "CellularStateConnected"; 185 case kStateLinked: 186 return "CellularStateLinked"; 187 default: 188 NOTREACHED(); 189 } 190 return StringPrintf("CellularStateUnknown-%d", state); 191 } 192 193 // static 194 string Cellular::GetModemStateString(ModemState modem_state) { 195 switch (modem_state) { 196 case kModemStateFailed: 197 return "CellularModemStateFailed"; 198 case kModemStateUnknown: 199 return "CellularModemStateUnknown"; 200 case kModemStateInitializing: 201 return "CellularModemStateInitializing"; 202 case kModemStateLocked: 203 return "CellularModemStateLocked"; 204 case kModemStateDisabled: 205 return "CellularModemStateDisabled"; 206 case kModemStateDisabling: 207 return "CellularModemStateDisabling"; 208 case kModemStateEnabling: 209 return "CellularModemStateEnabling"; 210 case kModemStateEnabled: 211 return "CellularModemStateEnabled"; 212 case kModemStateSearching: 213 return "CellularModemStateSearching"; 214 case kModemStateRegistered: 215 return "CellularModemStateRegistered"; 216 case kModemStateDisconnecting: 217 return "CellularModemStateDisconnecting"; 218 case kModemStateConnecting: 219 return "CellularModemStateConnecting"; 220 case kModemStateConnected: 221 return "CellularModemStateConnected"; 222 default: 223 NOTREACHED(); 224 } 225 return StringPrintf("CellularModemStateUnknown-%d", modem_state); 226 } 227 228 string Cellular::GetTechnologyFamily(Error* error) { 229 return capability_->GetTypeString(); 230 } 231 232 void Cellular::SetState(State state) { 233 SLOG(this, 2) << GetStateString(state_) << " -> " 234 << GetStateString(state); 235 state_ = state; 236 } 237 238 void Cellular::HelpRegisterDerivedBool( 239 const string& name, 240 bool(Cellular::*get)(Error* error), 241 bool(Cellular::*set)(const bool& value, Error* error)) { 242 mutable_store()->RegisterDerivedBool( 243 name, 244 BoolAccessor( 245 new CustomAccessor<Cellular, bool>(this, get, set))); 246 } 247 248 void Cellular::HelpRegisterConstDerivedString( 249 const string& name, 250 string(Cellular::*get)(Error*)) { 251 mutable_store()->RegisterDerivedString( 252 name, 253 StringAccessor(new CustomAccessor<Cellular, string>(this, get, nullptr))); 254 } 255 256 void Cellular::Start(Error* error, 257 const EnabledStateChangedCallback& callback) { 258 DCHECK(error); 259 SLOG(this, 2) << __func__ << ": " << GetStateString(state_); 260 // We can only short circuit the start operation if both the cellular state 261 // is not disabled AND the proxies have been initialized. We have seen 262 // crashes due to NULL proxies and the state being not disabled. 263 if (state_ != kStateDisabled && capability_->AreProxiesInitialized()) { 264 return; 265 } 266 267 ResultCallback cb = Bind(&Cellular::StartModemCallback, 268 weak_ptr_factory_.GetWeakPtr(), 269 callback); 270 capability_->StartModem(error, cb); 271 } 272 273 void Cellular::Stop(Error* error, 274 const EnabledStateChangedCallback& callback) { 275 SLOG(this, 2) << __func__ << ": " << GetStateString(state_); 276 explicit_disconnect_ = true; 277 ResultCallback cb = Bind(&Cellular::StopModemCallback, 278 weak_ptr_factory_.GetWeakPtr(), 279 callback); 280 capability_->StopModem(error, cb); 281 } 282 283 bool Cellular::IsUnderlyingDeviceEnabled() const { 284 return IsEnabledModemState(modem_state_); 285 } 286 287 bool Cellular::IsModemRegistered() const { 288 return (modem_state_ == Cellular::kModemStateRegistered || 289 modem_state_ == Cellular::kModemStateConnecting || 290 modem_state_ == Cellular::kModemStateConnected); 291 } 292 293 // static 294 bool Cellular::IsEnabledModemState(ModemState state) { 295 switch (state) { 296 case kModemStateFailed: 297 case kModemStateUnknown: 298 case kModemStateDisabled: 299 case kModemStateInitializing: 300 case kModemStateLocked: 301 case kModemStateDisabling: 302 case kModemStateEnabling: 303 return false; 304 case kModemStateEnabled: 305 case kModemStateSearching: 306 case kModemStateRegistered: 307 case kModemStateDisconnecting: 308 case kModemStateConnecting: 309 case kModemStateConnected: 310 return true; 311 } 312 return false; 313 } 314 315 void Cellular::StartModemCallback(const EnabledStateChangedCallback& callback, 316 const Error& error) { 317 SLOG(this, 2) << __func__ << ": " << GetStateString(state_); 318 if (error.IsSuccess() && (state_ == kStateDisabled)) { 319 SetState(kStateEnabled); 320 // Registration state updates may have been ignored while the 321 // modem was not yet marked enabled. 322 HandleNewRegistrationState(); 323 } 324 callback.Run(error); 325 } 326 327 void Cellular::StopModemCallback(const EnabledStateChangedCallback& callback, 328 const Error& error) { 329 SLOG(this, 2) << __func__ << ": " << GetStateString(state_); 330 explicit_disconnect_ = false; 331 // Destroy the cellular service regardless of any errors that occur during 332 // the stop process since we do not know the state of the modem at this 333 // point. 334 DestroyService(); 335 if (state_ != kStateDisabled) 336 SetState(kStateDisabled); 337 callback.Run(error); 338 // In case no termination action was executed (and TerminationActionComplete 339 // was not invoked) in response to a suspend request, any registered 340 // termination action needs to be removed explicitly. 341 manager()->RemoveTerminationAction(FriendlyName()); 342 } 343 344 void Cellular::InitCapability(Type type) { 345 // TODO(petkov): Consider moving capability construction into a factory that's 346 // external to the Cellular class. 347 SLOG(this, 2) << __func__ << "(" << type << ")"; 348 switch (type) { 349 case kTypeGSM: 350 capability_.reset(new CellularCapabilityGSM(this, 351 control_interface(), 352 modem_info_)); 353 break; 354 case kTypeCDMA: 355 capability_.reset(new CellularCapabilityCDMA(this, 356 control_interface(), 357 modem_info_)); 358 break; 359 case kTypeUniversal: 360 capability_.reset(new CellularCapabilityUniversal( 361 this, 362 control_interface(), 363 modem_info_)); 364 break; 365 case kTypeUniversalCDMA: 366 capability_.reset(new CellularCapabilityUniversalCDMA( 367 this, 368 control_interface(), 369 modem_info_)); 370 break; 371 default: NOTREACHED(); 372 } 373 mobile_operator_info_observer_->set_capability(capability_.get()); 374 } 375 376 void Cellular::Activate(const string& carrier, 377 Error* error, const ResultCallback& callback) { 378 capability_->Activate(carrier, error, callback); 379 } 380 381 void Cellular::CompleteActivation(Error* error) { 382 capability_->CompleteActivation(error); 383 } 384 385 void Cellular::RegisterOnNetwork(const string& network_id, 386 Error* error, 387 const ResultCallback& callback) { 388 capability_->RegisterOnNetwork(network_id, error, callback); 389 } 390 391 void Cellular::RequirePIN(const string& pin, bool require, 392 Error* error, const ResultCallback& callback) { 393 SLOG(this, 2) << __func__ << "(" << require << ")"; 394 capability_->RequirePIN(pin, require, error, callback); 395 } 396 397 void Cellular::EnterPIN(const string& pin, 398 Error* error, const ResultCallback& callback) { 399 SLOG(this, 2) << __func__; 400 capability_->EnterPIN(pin, error, callback); 401 } 402 403 void Cellular::UnblockPIN(const string& unblock_code, 404 const string& pin, 405 Error* error, const ResultCallback& callback) { 406 SLOG(this, 2) << __func__; 407 capability_->UnblockPIN(unblock_code, pin, error, callback); 408 } 409 410 void Cellular::ChangePIN(const string& old_pin, const string& new_pin, 411 Error* error, const ResultCallback& callback) { 412 SLOG(this, 2) << __func__; 413 capability_->ChangePIN(old_pin, new_pin, error, callback); 414 } 415 416 void Cellular::Reset(Error* error, const ResultCallback& callback) { 417 SLOG(this, 2) << __func__; 418 capability_->Reset(error, callback); 419 } 420 421 void Cellular::SetCarrier(const string& carrier, 422 Error* error, const ResultCallback& callback) { 423 SLOG(this, 2) << __func__ << "(" << carrier << ")"; 424 capability_->SetCarrier(carrier, error, callback); 425 } 426 427 bool Cellular::IsIPv6Allowed() const { 428 // A cellular device is disabled before the system goes into suspend mode. 429 // However, outstanding TCP sockets may not be nuked when the associated 430 // network interface goes down. When the system resumes from suspend, the 431 // cellular device is re-enabled and may reconnect to the network, which 432 // acquire a new IPv6 address on the network interface. However, those 433 // outstanding TCP sockets may initiate traffic with the old IPv6 address. 434 // Some network may not like the fact that two IPv6 addresses originated from 435 // the same modem within a connection session and may drop the connection. 436 // Here we disable IPv6 support on cellular devices to work around the issue. 437 // 438 // TODO(benchan): Resolve the IPv6 issue in a different way and then 439 // re-enable IPv6 support on cellular devices. 440 return false; 441 } 442 443 void Cellular::DropConnection() { 444 if (ppp_device_) { 445 // For PPP dongles, IP configuration is handled on the |ppp_device_|, 446 // rather than the netdev plumbed into |this|. 447 ppp_device_->DropConnection(); 448 } else { 449 Device::DropConnection(); 450 } 451 } 452 453 void Cellular::SetServiceState(Service::ConnectState state) { 454 if (ppp_device_) { 455 ppp_device_->SetServiceState(state); 456 } else if (selected_service()) { 457 Device::SetServiceState(state); 458 } else if (service_) { 459 service_->SetState(state); 460 } else { 461 LOG(WARNING) << "State change with no Service."; 462 } 463 } 464 465 void Cellular::SetServiceFailure(Service::ConnectFailure failure_state) { 466 if (ppp_device_) { 467 ppp_device_->SetServiceFailure(failure_state); 468 } else if (selected_service()) { 469 Device::SetServiceFailure(failure_state); 470 } else if (service_) { 471 service_->SetFailure(failure_state); 472 } else { 473 LOG(WARNING) << "State change with no Service."; 474 } 475 } 476 477 void Cellular::SetServiceFailureSilent(Service::ConnectFailure failure_state) { 478 if (ppp_device_) { 479 ppp_device_->SetServiceFailureSilent(failure_state); 480 } else if (selected_service()) { 481 Device::SetServiceFailureSilent(failure_state); 482 } else if (service_) { 483 service_->SetFailureSilent(failure_state); 484 } else { 485 LOG(WARNING) << "State change with no Service."; 486 } 487 } 488 489 void Cellular::OnBeforeSuspend(const ResultCallback& callback) { 490 LOG(INFO) << __func__; 491 Error error; 492 StopPPP(); 493 SetEnabledNonPersistent(false, &error, callback); 494 if (error.IsFailure() && error.type() != Error::kInProgress) { 495 // If we fail to disable the modem right away, proceed instead of wasting 496 // the time to wait for the suspend/termination delay to expire. 497 LOG(WARNING) << "Proceed with suspend/termination even though the modem " 498 << "is not yet disabled: " << error; 499 callback.Run(error); 500 } 501 } 502 503 void Cellular::OnAfterResume() { 504 SLOG(this, 2) << __func__; 505 if (enabled_persistent()) { 506 LOG(INFO) << "Restarting modem after resume."; 507 508 // If we started disabling the modem before suspend, but that 509 // suspend is still in progress, then we are not yet in 510 // kStateDisabled. That's a problem, because Cellular::Start 511 // returns immediately in that case. Hack around that by forcing 512 // |state_| here. 513 // 514 // TODO(quiche): Remove this hack. Maybe 515 // CellularCapabilityUniversal should generate separate 516 // notifications for Stop_Disable, and Stop_PowerDown. Then we'd 517 // update our state to kStateDisabled when Stop_Disable completes. 518 state_ = kStateDisabled; 519 520 Error error; 521 SetEnabledUnchecked(true, &error, Bind(LogRestartModemResult)); 522 if (error.IsSuccess()) { 523 LOG(INFO) << "Modem restart completed immediately."; 524 } else if (error.IsOngoing()) { 525 LOG(INFO) << "Modem restart in progress."; 526 } else { 527 LOG(WARNING) << "Modem restart failed: " << error; 528 } 529 } 530 // TODO(quiche): Consider if this should be conditional. If, e.g., 531 // the device was still disabling when we suspended, will trying to 532 // renew DHCP here cause problems? 533 Device::OnAfterResume(); 534 } 535 536 void Cellular::Scan(ScanType /*scan_type*/, Error* error, 537 const string& /*reason*/) { 538 SLOG(this, 2) << __func__; 539 CHECK(error); 540 if (proposed_scan_in_progress_) { 541 Error::PopulateAndLog(FROM_HERE, error, Error::kInProgress, 542 "Already scanning"); 543 return; 544 } 545 546 // |scan_type| is ignored because Cellular only does a full scan. 547 ResultStringmapsCallback cb = Bind(&Cellular::OnScanReply, 548 weak_ptr_factory_.GetWeakPtr()); 549 capability_->Scan(error, cb); 550 // An immediate failure in |cabapility_->Scan(...)| is indicated through the 551 // |error| argument. 552 if (error->IsFailure()) 553 return; 554 555 proposed_scan_in_progress_ = true; 556 UpdateScanning(); 557 } 558 559 void Cellular::OnScanReply(const Stringmaps& found_networks, 560 const Error& error) { 561 proposed_scan_in_progress_ = false; 562 UpdateScanning(); 563 564 // TODO(jglasgow): fix error handling. 565 // At present, there is no way of notifying user of this asynchronous error. 566 if (error.IsFailure()) { 567 clear_found_networks(); 568 return; 569 } 570 571 set_found_networks(found_networks); 572 } 573 574 void Cellular::HandleNewRegistrationState() { 575 SLOG(this, 2) << __func__ 576 << ": (new state " << GetStateString(state_) << ")"; 577 if (!capability_->IsRegistered()) { 578 if (!explicit_disconnect_ && 579 (state_ == kStateLinked || state_ == kStateConnected) && 580 service_.get()) 581 metrics()->NotifyCellularDeviceDrop( 582 capability_->GetNetworkTechnologyString(), service_->strength()); 583 DestroyService(); 584 if (state_ == kStateLinked || 585 state_ == kStateConnected || 586 state_ == kStateRegistered) { 587 SetState(kStateEnabled); 588 } 589 return; 590 } 591 // In Disabled state, defer creating a service until fully 592 // enabled. UI will ignore the appearance of a new service 593 // on a disabled device. 594 if (state_ == kStateDisabled) { 595 return; 596 } 597 if (state_ == kStateEnabled) { 598 SetState(kStateRegistered); 599 } 600 if (!service_.get()) { 601 metrics()->NotifyDeviceScanFinished(interface_index()); 602 CreateService(); 603 } 604 capability_->GetSignalQuality(); 605 if (state_ == kStateRegistered && modem_state_ == kModemStateConnected) 606 OnConnected(); 607 service_->SetNetworkTechnology(capability_->GetNetworkTechnologyString()); 608 service_->SetRoamingState(capability_->GetRoamingStateString()); 609 manager()->UpdateService(service_); 610 } 611 612 void Cellular::HandleNewSignalQuality(uint32_t strength) { 613 SLOG(this, 2) << "Signal strength: " << strength; 614 if (service_) { 615 service_->SetStrength(strength); 616 } 617 } 618 619 void Cellular::CreateService() { 620 SLOG(this, 2) << __func__; 621 CHECK(!service_.get()); 622 service_ = new CellularService(modem_info_, this); 623 capability_->OnServiceCreated(); 624 625 // Storage identifier must be set only once, and before registering the 626 // service with the manager, since we key off of this identifier to 627 // determine the profile to load. 628 // TODO(pprabhu) Make profile matching more robust (crbug.com/369755) 629 string service_id; 630 if (home_provider_info_->IsMobileNetworkOperatorKnown() && 631 !home_provider_info_->uuid().empty()) { 632 service_id = home_provider_info_->uuid(); 633 } else if (serving_operator_info_->IsMobileNetworkOperatorKnown() && 634 !serving_operator_info_->uuid().empty()) { 635 service_id = serving_operator_info_->uuid(); 636 } else { 637 switch (type_) { 638 case kTypeGSM: 639 case kTypeUniversal: 640 if (!sim_identifier().empty()) { 641 service_id = sim_identifier(); 642 } 643 break; 644 645 case kTypeCDMA: 646 case kTypeUniversalCDMA: 647 if (!meid().empty()) { 648 service_id = meid(); 649 } 650 break; 651 652 default: 653 NOTREACHED(); 654 } 655 } 656 657 if (!service_id.empty()) { 658 string storage_id = base::StringPrintf( 659 "%s_%s_%s", 660 kTypeCellular, address().c_str(), service_id.c_str()); 661 service()->SetStorageIdentifier(storage_id); 662 } 663 664 manager()->RegisterService(service_); 665 666 // We might have missed a property update because the service wasn't created 667 // ealier. 668 UpdateScanning(); 669 mobile_operator_info_observer_->OnOperatorChanged(); 670 } 671 672 void Cellular::DestroyService() { 673 SLOG(this, 2) << __func__; 674 DropConnection(); 675 if (service_) { 676 LOG(INFO) << "Deregistering cellular service " << service_->unique_name() 677 << " for device " << link_name(); 678 manager()->DeregisterService(service_); 679 service_ = nullptr; 680 } 681 } 682 683 void Cellular::Connect(Error* error) { 684 SLOG(this, 2) << __func__; 685 if (state_ == kStateConnected || state_ == kStateLinked) { 686 Error::PopulateAndLog(FROM_HERE, error, Error::kAlreadyConnected, 687 "Already connected; connection request ignored."); 688 return; 689 } else if (state_ != kStateRegistered) { 690 Error::PopulateAndLog(FROM_HERE, error, Error::kNotRegistered, 691 "Modem not registered; connection request ignored."); 692 return; 693 } 694 695 if (!capability_->AllowRoaming() && 696 service_->roaming_state() == kRoamingStateRoaming) { 697 Error::PopulateAndLog(FROM_HERE, error, Error::kNotOnHomeNetwork, 698 "Roaming disallowed; connection request ignored."); 699 return; 700 } 701 702 KeyValueStore properties; 703 capability_->SetupConnectProperties(&properties); 704 ResultCallback cb = Bind(&Cellular::OnConnectReply, 705 weak_ptr_factory_.GetWeakPtr()); 706 OnConnecting(); 707 capability_->Connect(properties, error, cb); 708 if (!error->IsSuccess()) 709 return; 710 711 bool is_auto_connecting = service_.get() && service_->is_auto_connecting(); 712 metrics()->NotifyDeviceConnectStarted(interface_index(), is_auto_connecting); 713 } 714 715 // Note that there's no ResultCallback argument to this, 716 // since Connect() isn't yet passed one. 717 void Cellular::OnConnectReply(const Error& error) { 718 SLOG(this, 2) << __func__ << "(" << error << ")"; 719 if (error.IsSuccess()) { 720 metrics()->NotifyDeviceConnectFinished(interface_index()); 721 OnConnected(); 722 } else { 723 metrics()->NotifyCellularDeviceConnectionFailure(); 724 OnConnectFailed(error); 725 } 726 } 727 728 void Cellular::OnDisabled() { 729 SetEnabled(false); 730 } 731 732 void Cellular::OnEnabled() { 733 manager()->AddTerminationAction(FriendlyName(), 734 Bind(&Cellular::StartTermination, 735 weak_ptr_factory_.GetWeakPtr())); 736 SetEnabled(true); 737 } 738 739 void Cellular::OnConnecting() { 740 if (service_) 741 service_->SetState(Service::kStateAssociating); 742 } 743 744 void Cellular::OnConnected() { 745 SLOG(this, 2) << __func__; 746 if (state_ == kStateConnected || state_ == kStateLinked) { 747 SLOG(this, 2) << "Already connected"; 748 return; 749 } 750 SetState(kStateConnected); 751 if (!service_) { 752 LOG(INFO) << "Disconnecting due to no cellular service."; 753 Disconnect(nullptr, "no celluar service"); 754 } else if (!capability_->AllowRoaming() && 755 service_->roaming_state() == kRoamingStateRoaming) { 756 LOG(INFO) << "Disconnecting due to roaming."; 757 Disconnect(nullptr, "roaming"); 758 } else { 759 EstablishLink(); 760 } 761 } 762 763 void Cellular::OnConnectFailed(const Error& error) { 764 if (service_) 765 service_->SetFailure(Service::kFailureUnknown); 766 } 767 768 void Cellular::Disconnect(Error* error, const char* reason) { 769 SLOG(this, 2) << __func__ << ": " << reason; 770 if (state_ != kStateConnected && state_ != kStateLinked) { 771 Error::PopulateAndLog( 772 FROM_HERE, error, Error::kNotConnected, 773 "Not connected; request ignored."); 774 return; 775 } 776 StopPPP(); 777 explicit_disconnect_ = true; 778 ResultCallback cb = Bind(&Cellular::OnDisconnectReply, 779 weak_ptr_factory_.GetWeakPtr()); 780 capability_->Disconnect(error, cb); 781 } 782 783 void Cellular::OnDisconnectReply(const Error& error) { 784 SLOG(this, 2) << __func__ << "(" << error << ")"; 785 explicit_disconnect_ = false; 786 if (error.IsSuccess()) { 787 OnDisconnected(); 788 } else { 789 metrics()->NotifyCellularDeviceDisconnectionFailure(); 790 OnDisconnectFailed(); 791 } 792 } 793 794 void Cellular::OnDisconnected() { 795 SLOG(this, 2) << __func__; 796 if (!DisconnectCleanup()) { 797 LOG(WARNING) << "Disconnect occurred while in state " 798 << GetStateString(state_); 799 } 800 } 801 802 void Cellular::OnDisconnectFailed() { 803 SLOG(this, 2) << __func__; 804 // If the modem is in the disconnecting state, then 805 // the disconnect should eventually succeed, so do 806 // nothing. 807 if (modem_state_ == kModemStateDisconnecting) { 808 LOG(WARNING) << "Ignoring failed disconnect while modem is disconnecting."; 809 return; 810 } 811 812 // OnDisconnectFailed got called because no bearers 813 // to disconnect were found. Which means that we shouldn't 814 // really remain in the connected/linked state if we 815 // are in one of those. 816 if (!DisconnectCleanup()) { 817 // otherwise, no-op 818 LOG(WARNING) << "Ignoring failed disconnect while in state " 819 << GetStateString(state_); 820 } 821 822 // TODO(armansito): In either case, shill ends up thinking 823 // that it's disconnected, while for some reason the underlying 824 // modem might still actually be connected. In that case the UI 825 // would be reflecting an incorrect state and a further connection 826 // request would fail. We should perhaps tear down the modem and 827 // restart it here. 828 } 829 830 void Cellular::EstablishLink() { 831 SLOG(this, 2) << __func__; 832 CHECK_EQ(kStateConnected, state_); 833 834 CellularBearer* bearer = capability_->GetActiveBearer(); 835 if (bearer && bearer->ipv4_config_method() == IPConfig::kMethodPPP) { 836 LOG(INFO) << "Start PPP connection on " << bearer->data_interface(); 837 StartPPP(bearer->data_interface()); 838 return; 839 } 840 841 unsigned int flags = 0; 842 if (manager()->device_info()->GetFlags(interface_index(), &flags) && 843 (flags & IFF_UP) != 0) { 844 LinkEvent(flags, IFF_UP); 845 return; 846 } 847 // TODO(petkov): Provide a timeout for a failed link-up request. 848 rtnl_handler()->SetInterfaceFlags(interface_index(), IFF_UP, IFF_UP); 849 850 // Set state to associating. 851 OnConnecting(); 852 } 853 854 void Cellular::LinkEvent(unsigned int flags, unsigned int change) { 855 Device::LinkEvent(flags, change); 856 if (ppp_task_) { 857 LOG(INFO) << "Ignoring LinkEvent on device with PPP interface."; 858 return; 859 } 860 861 if ((flags & IFF_UP) != 0 && state_ == kStateConnected) { 862 LOG(INFO) << link_name() << " is up."; 863 SetState(kStateLinked); 864 865 // TODO(benchan): IPv6 support is currently disabled for cellular devices. 866 // Check and obtain IPv6 configuration from the bearer when we later enable 867 // IPv6 support on cellular devices. 868 CellularBearer* bearer = capability_->GetActiveBearer(); 869 if (bearer && bearer->ipv4_config_method() == IPConfig::kMethodStatic) { 870 SLOG(this, 2) << "Assign static IP configuration from bearer."; 871 SelectService(service_); 872 SetServiceState(Service::kStateConfiguring); 873 AssignIPConfig(*bearer->ipv4_config_properties()); 874 return; 875 } 876 877 if (AcquireIPConfig()) { 878 SLOG(this, 2) << "Start DHCP to acquire IP configuration."; 879 SelectService(service_); 880 SetServiceState(Service::kStateConfiguring); 881 return; 882 } 883 884 LOG(ERROR) << "Unable to acquire IP configuration over DHCP."; 885 return; 886 } 887 888 if ((flags & IFF_UP) == 0 && state_ == kStateLinked) { 889 LOG(INFO) << link_name() << " is down."; 890 SetState(kStateConnected); 891 DropConnection(); 892 } 893 } 894 895 void Cellular::OnPropertiesChanged( 896 const string& interface, 897 const KeyValueStore& changed_properties, 898 const vector<string>& invalidated_properties) { 899 capability_->OnPropertiesChanged(interface, 900 changed_properties, 901 invalidated_properties); 902 } 903 904 string Cellular::CreateDefaultFriendlyServiceName() { 905 SLOG(this, 2) << __func__; 906 return base::StringPrintf("%s_%u", 907 kGenericServiceNamePrefix, 908 friendly_service_name_id_++); 909 } 910 911 bool Cellular::IsDefaultFriendlyServiceName(const string& service_name) const { 912 return base::StartsWith(service_name, kGenericServiceNamePrefix, 913 base::CompareCase::SENSITIVE); 914 } 915 916 void Cellular::OnModemStateChanged(ModemState new_state) { 917 ModemState old_state = modem_state_; 918 SLOG(this, 2) << __func__ << ": " << GetModemStateString(old_state) 919 << " -> " << GetModemStateString(new_state); 920 if (old_state == new_state) { 921 SLOG(this, 2) << "The new state matches the old state. Nothing to do."; 922 return; 923 } 924 set_modem_state(new_state); 925 if (old_state >= kModemStateRegistered && 926 new_state < kModemStateRegistered) { 927 capability_->SetUnregistered(new_state == kModemStateSearching); 928 HandleNewRegistrationState(); 929 } 930 if (new_state == kModemStateDisabled) { 931 OnDisabled(); 932 } else if (new_state >= kModemStateEnabled) { 933 if (old_state < kModemStateEnabled) { 934 // Just became enabled, update enabled state. 935 OnEnabled(); 936 } 937 if ((new_state == kModemStateEnabled || 938 new_state == kModemStateSearching || 939 new_state == kModemStateRegistered) && 940 (old_state == kModemStateConnected || 941 old_state == kModemStateConnecting || 942 old_state == kModemStateDisconnecting)) 943 OnDisconnected(); 944 else if (new_state == kModemStateConnecting) 945 OnConnecting(); 946 else if (new_state == kModemStateConnected && 947 old_state == kModemStateConnecting) 948 OnConnected(); 949 } 950 951 // Update the kScanningProperty property after we've handled the current state 952 // update completely. 953 UpdateScanning(); 954 } 955 956 bool Cellular::IsActivating() const { 957 return capability_->IsActivating(); 958 } 959 960 bool Cellular::SetAllowRoaming(const bool& value, Error* /*error*/) { 961 SLOG(this, 2) << __func__ 962 << "(" << allow_roaming_ << "->" << value << ")"; 963 if (allow_roaming_ == value) { 964 return false; 965 } 966 allow_roaming_ = value; 967 manager()->UpdateDevice(this); 968 969 // Use AllowRoaming() instead of allow_roaming_ in order to 970 // incorporate provider preferences when evaluating if a disconnect 971 // is required. 972 if (!capability_->AllowRoaming() && 973 capability_->GetRoamingStateString() == kRoamingStateRoaming) { 974 Error error; 975 Disconnect(&error, __func__); 976 } 977 adaptor()->EmitBoolChanged(kCellularAllowRoamingProperty, value); 978 return true; 979 } 980 981 void Cellular::StartTermination() { 982 SLOG(this, 2) << __func__; 983 OnBeforeSuspend(Bind(&Cellular::OnTerminationCompleted, 984 weak_ptr_factory_.GetWeakPtr())); 985 } 986 987 void Cellular::OnTerminationCompleted(const Error& error) { 988 LOG(INFO) << __func__ << ": " << error; 989 manager()->TerminationActionComplete(FriendlyName()); 990 manager()->RemoveTerminationAction(FriendlyName()); 991 } 992 993 bool Cellular::DisconnectCleanup() { 994 bool succeeded = false; 995 if (state_ == kStateConnected || state_ == kStateLinked) { 996 SetState(kStateRegistered); 997 SetServiceFailureSilent(Service::kFailureUnknown); 998 DestroyIPConfig(); 999 succeeded = true; 1000 } 1001 capability_->DisconnectCleanup(); 1002 return succeeded; 1003 } 1004 1005 // static 1006 void Cellular::LogRestartModemResult(const Error& error) { 1007 if (error.IsSuccess()) { 1008 LOG(INFO) << "Modem restart completed."; 1009 } else { 1010 LOG(WARNING) << "Attempt to restart modem failed: " << error; 1011 } 1012 } 1013 1014 void Cellular::StartPPP(const string& serial_device) { 1015 SLOG(PPP, this, 2) << __func__ << " on " << serial_device; 1016 // Detach any SelectedService from this device. It will be grafted onto 1017 // the PPPDevice after PPP is up (in Cellular::Notify). 1018 // 1019 // This has two important effects: 1) kills dhcpcd if it is running. 1020 // 2) stops Cellular::LinkEvent from driving changes to the 1021 // SelectedService. 1022 if (selected_service()) { 1023 CHECK_EQ(service_.get(), selected_service().get()); 1024 // Save and restore |service_| state, as DropConnection calls 1025 // SelectService, and SelectService will move selected_service() 1026 // to kStateIdle. 1027 Service::ConnectState original_state(service_->state()); 1028 Device::DropConnection(); // Don't redirect to PPPDevice. 1029 service_->SetState(original_state); 1030 } else { 1031 CHECK(!ipconfig()); // Shouldn't have ipconfig without selected_service(). 1032 } 1033 1034 PPPDaemon::DeathCallback death_callback(Bind(&Cellular::OnPPPDied, 1035 weak_ptr_factory_.GetWeakPtr())); 1036 1037 PPPDaemon::Options options; 1038 options.no_detach = true; 1039 options.no_default_route = true; 1040 options.use_peer_dns = true; 1041 1042 is_ppp_authenticating_ = false; 1043 1044 Error error; 1045 std::unique_ptr<ExternalTask> new_ppp_task( 1046 PPPDaemon::Start(modem_info_->control_interface(), 1047 process_manager_, 1048 weak_ptr_factory_.GetWeakPtr(), 1049 options, 1050 serial_device, 1051 death_callback, 1052 &error)); 1053 if (new_ppp_task) { 1054 LOG(INFO) << "Forked pppd process."; 1055 ppp_task_ = std::move(new_ppp_task); 1056 } 1057 } 1058 1059 void Cellular::StopPPP() { 1060 SLOG(PPP, this, 2) << __func__; 1061 DropConnection(); 1062 ppp_task_.reset(); 1063 ppp_device_ = nullptr; 1064 } 1065 1066 // called by |ppp_task_| 1067 void Cellular::GetLogin(string* user, string* password) { 1068 SLOG(PPP, this, 2) << __func__; 1069 if (!service()) { 1070 LOG(ERROR) << __func__ << " with no service "; 1071 return; 1072 } 1073 CHECK(user); 1074 CHECK(password); 1075 *user = service()->ppp_username(); 1076 *password = service()->ppp_password(); 1077 } 1078 1079 // Called by |ppp_task_|. 1080 void Cellular::Notify(const string& reason, 1081 const map<string, string>& dict) { 1082 SLOG(PPP, this, 2) << __func__ << " " << reason << " on " << link_name(); 1083 1084 if (reason == kPPPReasonAuthenticating) { 1085 OnPPPAuthenticating(); 1086 } else if (reason == kPPPReasonAuthenticated) { 1087 OnPPPAuthenticated(); 1088 } else if (reason == kPPPReasonConnect) { 1089 OnPPPConnected(dict); 1090 } else if (reason == kPPPReasonDisconnect) { 1091 OnPPPDisconnected(); 1092 } else { 1093 NOTREACHED(); 1094 } 1095 } 1096 1097 void Cellular::OnPPPAuthenticated() { 1098 SLOG(PPP, this, 2) << __func__; 1099 is_ppp_authenticating_ = false; 1100 } 1101 1102 void Cellular::OnPPPAuthenticating() { 1103 SLOG(PPP, this, 2) << __func__; 1104 is_ppp_authenticating_ = true; 1105 } 1106 1107 void Cellular::OnPPPConnected(const map<string, string>& params) { 1108 SLOG(PPP, this, 2) << __func__; 1109 string interface_name = PPPDevice::GetInterfaceName(params); 1110 DeviceInfo* device_info = modem_info_->manager()->device_info(); 1111 int interface_index = device_info->GetIndex(interface_name); 1112 if (interface_index < 0) { 1113 // TODO(quiche): Consider handling the race when the RTNL notification about 1114 // the new PPP device has not been received yet. crbug.com/246832. 1115 NOTIMPLEMENTED() << ": No device info for " << interface_name << "."; 1116 return; 1117 } 1118 1119 if (!ppp_device_ || ppp_device_->interface_index() != interface_index) { 1120 if (ppp_device_) { 1121 ppp_device_->SelectService(nullptr); // No longer drives |service_|. 1122 } 1123 ppp_device_ = ppp_device_factory_->CreatePPPDevice( 1124 modem_info_->control_interface(), 1125 modem_info_->dispatcher(), 1126 modem_info_->metrics(), 1127 modem_info_->manager(), 1128 interface_name, 1129 interface_index); 1130 device_info->RegisterDevice(ppp_device_); 1131 } 1132 1133 CHECK(service_); 1134 // For PPP, we only SelectService on the |ppp_device_|. 1135 CHECK(!selected_service()); 1136 const bool kBlackholeIPv6 = false; 1137 ppp_device_->SetEnabled(true); 1138 ppp_device_->SelectService(service_); 1139 ppp_device_->UpdateIPConfigFromPPP(params, kBlackholeIPv6); 1140 } 1141 1142 void Cellular::OnPPPDisconnected() { 1143 SLOG(PPP, this, 2) << __func__; 1144 // DestroyLater, rather than while on stack. 1145 ppp_task_.release()->DestroyLater(modem_info_->dispatcher()); 1146 if (is_ppp_authenticating_) { 1147 SetServiceFailure(Service::kFailurePPPAuth); 1148 } else { 1149 // TODO(quiche): Don't set failure if we disconnected intentionally. 1150 SetServiceFailure(Service::kFailureUnknown); 1151 } 1152 Error error; 1153 Disconnect(&error, __func__); 1154 } 1155 1156 void Cellular::OnPPPDied(pid_t pid, int exit) { 1157 LOG(INFO) << __func__ << " on " << link_name(); 1158 OnPPPDisconnected(); 1159 } 1160 1161 void Cellular::UpdateScanning() { 1162 if (proposed_scan_in_progress_) { 1163 set_scanning(true); 1164 return; 1165 } 1166 1167 if (modem_state_ == kModemStateEnabling) { 1168 set_scanning(true); 1169 return; 1170 } 1171 1172 if (service_ && service_->activation_state() != kActivationStateActivated) { 1173 set_scanning(false); 1174 return; 1175 } 1176 1177 if (modem_state_ == kModemStateEnabled || 1178 modem_state_ == kModemStateSearching) { 1179 set_scanning(true); 1180 return; 1181 } 1182 1183 set_scanning(false); 1184 } 1185 1186 void Cellular::RegisterProperties() { 1187 PropertyStore* store = this->mutable_store(); 1188 1189 // These properties do not have setters, and events are not generated when 1190 // they are changed. 1191 store->RegisterConstString(kDBusServiceProperty, &dbus_service_); 1192 store->RegisterConstString(kDBusObjectProperty, &dbus_path_); 1193 1194 store->RegisterUint16(kScanIntervalProperty, &scan_interval_); 1195 1196 // These properties have setters that should be used to change their values. 1197 // Events are generated whenever the values change. 1198 store->RegisterConstStringmap(kHomeProviderProperty, &home_provider_); 1199 store->RegisterConstString(kCarrierProperty, &carrier_); 1200 store->RegisterConstBool(kSupportNetworkScanProperty, &scanning_supported_); 1201 store->RegisterConstString(kEsnProperty, &esn_); 1202 store->RegisterConstString(kFirmwareRevisionProperty, &firmware_revision_); 1203 store->RegisterConstString(kHardwareRevisionProperty, &hardware_revision_); 1204 store->RegisterConstString(kImeiProperty, &imei_); 1205 store->RegisterConstString(kImsiProperty, &imsi_); 1206 store->RegisterConstString(kMdnProperty, &mdn_); 1207 store->RegisterConstString(kMeidProperty, &meid_); 1208 store->RegisterConstString(kMinProperty, &min_); 1209 store->RegisterConstString(kManufacturerProperty, &manufacturer_); 1210 store->RegisterConstString(kModelIDProperty, &model_id_); 1211 store->RegisterConstBool(kScanningProperty, &scanning_); 1212 1213 store->RegisterConstString(kSelectedNetworkProperty, &selected_network_); 1214 store->RegisterConstStringmaps(kFoundNetworksProperty, &found_networks_); 1215 store->RegisterConstBool(kProviderRequiresRoamingProperty, 1216 &provider_requires_roaming_); 1217 store->RegisterConstBool(kSIMPresentProperty, &sim_present_); 1218 store->RegisterConstStringmaps(kCellularApnListProperty, &apn_list_); 1219 store->RegisterConstString(kIccidProperty, &sim_identifier_); 1220 1221 store->RegisterConstStrings(kSupportedCarriersProperty, &supported_carriers_); 1222 store->RegisterConstUint16(kPRLVersionProperty, &prl_version_); 1223 1224 // TODO(pprabhu): Decide whether these need their own custom setters. 1225 HelpRegisterConstDerivedString(kTechnologyFamilyProperty, 1226 &Cellular::GetTechnologyFamily); 1227 HelpRegisterDerivedBool(kCellularAllowRoamingProperty, 1228 &Cellular::GetAllowRoaming, 1229 &Cellular::SetAllowRoaming); 1230 } 1231 1232 void Cellular::set_home_provider(const Stringmap& home_provider) { 1233 if (home_provider_ == home_provider) 1234 return; 1235 1236 home_provider_ = home_provider; 1237 adaptor()->EmitStringmapChanged(kHomeProviderProperty, home_provider_); 1238 } 1239 1240 void Cellular::set_carrier(const string& carrier) { 1241 if (carrier_ == carrier) 1242 return; 1243 1244 carrier_ = carrier; 1245 adaptor()->EmitStringChanged(kCarrierProperty, carrier_); 1246 } 1247 1248 void Cellular::set_scanning_supported(bool scanning_supported) { 1249 if (scanning_supported_ == scanning_supported) 1250 return; 1251 1252 scanning_supported_ = scanning_supported; 1253 if (adaptor()) 1254 adaptor()->EmitBoolChanged(kSupportNetworkScanProperty, 1255 scanning_supported_); 1256 else 1257 SLOG(this, 2) << "Could not emit signal for property |" 1258 << kSupportNetworkScanProperty 1259 << "| change. DBus adaptor is NULL!"; 1260 } 1261 1262 void Cellular::set_esn(const string& esn) { 1263 if (esn_ == esn) 1264 return; 1265 1266 esn_ = esn; 1267 adaptor()->EmitStringChanged(kEsnProperty, esn_); 1268 } 1269 1270 void Cellular::set_firmware_revision(const string& firmware_revision) { 1271 if (firmware_revision_ == firmware_revision) 1272 return; 1273 1274 firmware_revision_ = firmware_revision; 1275 adaptor()->EmitStringChanged(kFirmwareRevisionProperty, firmware_revision_); 1276 } 1277 1278 void Cellular::set_hardware_revision(const string& hardware_revision) { 1279 if (hardware_revision_ == hardware_revision) 1280 return; 1281 1282 hardware_revision_ = hardware_revision; 1283 adaptor()->EmitStringChanged(kHardwareRevisionProperty, hardware_revision_); 1284 } 1285 1286 // TODO(armansito): The following methods should probably log their argument 1287 // values. Need to learn if any of them need to be scrubbed. 1288 void Cellular::set_imei(const string& imei) { 1289 if (imei_ == imei) 1290 return; 1291 1292 imei_ = imei; 1293 adaptor()->EmitStringChanged(kImeiProperty, imei_); 1294 } 1295 1296 void Cellular::set_imsi(const string& imsi) { 1297 if (imsi_ == imsi) 1298 return; 1299 1300 imsi_ = imsi; 1301 adaptor()->EmitStringChanged(kImsiProperty, imsi_); 1302 } 1303 1304 void Cellular::set_mdn(const string& mdn) { 1305 if (mdn_ == mdn) 1306 return; 1307 1308 mdn_ = mdn; 1309 adaptor()->EmitStringChanged(kMdnProperty, mdn_); 1310 } 1311 1312 void Cellular::set_meid(const string& meid) { 1313 if (meid_ == meid) 1314 return; 1315 1316 meid_ = meid; 1317 adaptor()->EmitStringChanged(kMeidProperty, meid_); 1318 } 1319 1320 void Cellular::set_min(const string& min) { 1321 if (min_ == min) 1322 return; 1323 1324 min_ = min; 1325 adaptor()->EmitStringChanged(kMinProperty, min_); 1326 } 1327 1328 void Cellular::set_manufacturer(const string& manufacturer) { 1329 if (manufacturer_ == manufacturer) 1330 return; 1331 1332 manufacturer_ = manufacturer; 1333 adaptor()->EmitStringChanged(kManufacturerProperty, manufacturer_); 1334 } 1335 1336 void Cellular::set_model_id(const string& model_id) { 1337 if (model_id_ == model_id) 1338 return; 1339 1340 model_id_ = model_id; 1341 adaptor()->EmitStringChanged(kModelIDProperty, model_id_); 1342 } 1343 1344 void Cellular::set_mm_plugin(const string& mm_plugin) { 1345 mm_plugin_ = mm_plugin; 1346 } 1347 1348 void Cellular::set_scanning(bool scanning) { 1349 if (scanning_ == scanning) 1350 return; 1351 1352 scanning_ = scanning; 1353 adaptor()->EmitBoolChanged(kScanningProperty, scanning_); 1354 1355 // kScanningProperty is a sticky-false property. 1356 // Every time it is set to |true|, it will remain |true| up to a maximum of 1357 // |kScanningTimeout| time, after which it will be reset to |false|. 1358 if (!scanning_ && !scanning_timeout_callback_.IsCancelled()) { 1359 SLOG(this, 2) << "Scanning set to false. " 1360 << "Cancelling outstanding timeout."; 1361 scanning_timeout_callback_.Cancel(); 1362 } else { 1363 CHECK(scanning_timeout_callback_.IsCancelled()); 1364 SLOG(this, 2) << "Scanning set to true. " 1365 << "Starting timeout to reset to false."; 1366 scanning_timeout_callback_.Reset(Bind(&Cellular::set_scanning, 1367 weak_ptr_factory_.GetWeakPtr(), 1368 false)); 1369 dispatcher()->PostDelayedTask( 1370 scanning_timeout_callback_.callback(), 1371 scanning_timeout_milliseconds_); 1372 } 1373 } 1374 1375 void Cellular::set_selected_network(const string& selected_network) { 1376 if (selected_network_ == selected_network) 1377 return; 1378 1379 selected_network_ = selected_network; 1380 adaptor()->EmitStringChanged(kSelectedNetworkProperty, selected_network_); 1381 } 1382 1383 void Cellular::set_found_networks(const Stringmaps& found_networks) { 1384 // There is no canonical form of a Stringmaps value. 1385 // So don't check for redundant updates. 1386 found_networks_ = found_networks; 1387 adaptor()->EmitStringmapsChanged(kFoundNetworksProperty, found_networks_); 1388 } 1389 1390 void Cellular::clear_found_networks() { 1391 if (found_networks_.empty()) 1392 return; 1393 1394 found_networks_.clear(); 1395 adaptor()->EmitStringmapsChanged(kFoundNetworksProperty, found_networks_); 1396 } 1397 1398 void Cellular::set_provider_requires_roaming(bool provider_requires_roaming) { 1399 if (provider_requires_roaming_ == provider_requires_roaming) 1400 return; 1401 1402 provider_requires_roaming_ = provider_requires_roaming; 1403 adaptor()->EmitBoolChanged(kProviderRequiresRoamingProperty, 1404 provider_requires_roaming_); 1405 } 1406 1407 void Cellular::set_sim_present(bool sim_present) { 1408 if (sim_present_ == sim_present) 1409 return; 1410 1411 sim_present_ = sim_present; 1412 adaptor()->EmitBoolChanged(kSIMPresentProperty, sim_present_); 1413 } 1414 1415 void Cellular::set_apn_list(const Stringmaps& apn_list) { 1416 // There is no canonical form of a Stringmaps value. 1417 // So don't check for redundant updates. 1418 apn_list_ = apn_list; 1419 // See crbug.com/215581: Sometimes adaptor may be nullptr when |set_apn_list| 1420 // is called. 1421 if (adaptor()) 1422 adaptor()->EmitStringmapsChanged(kCellularApnListProperty, apn_list_); 1423 else 1424 SLOG(this, 2) << "Could not emit signal for property |" 1425 << kCellularApnListProperty 1426 << "| change. DBus adaptor is NULL!"; 1427 } 1428 1429 void Cellular::set_sim_identifier(const string& sim_identifier) { 1430 if (sim_identifier_ == sim_identifier) 1431 return; 1432 1433 sim_identifier_ = sim_identifier; 1434 adaptor()->EmitStringChanged(kIccidProperty, sim_identifier_); 1435 } 1436 1437 void Cellular::set_supported_carriers(const Strings& supported_carriers) { 1438 // There is no canonical form of a Strings value. 1439 // So don't check for redundant updates. 1440 supported_carriers_ = supported_carriers; 1441 adaptor()->EmitStringsChanged(kSupportedCarriersProperty, 1442 supported_carriers_); 1443 } 1444 1445 void Cellular::set_prl_version(uint16_t prl_version) { 1446 if (prl_version_ == prl_version) 1447 return; 1448 1449 prl_version_ = prl_version; 1450 adaptor()->EmitUint16Changed(kPRLVersionProperty, prl_version_); 1451 } 1452 1453 void Cellular::set_home_provider_info(MobileOperatorInfo* home_provider_info) { 1454 home_provider_info_.reset(home_provider_info); 1455 } 1456 1457 void Cellular::set_serving_operator_info( 1458 MobileOperatorInfo* serving_operator_info) { 1459 serving_operator_info_.reset(serving_operator_info); 1460 } 1461 1462 void Cellular::UpdateHomeProvider(const MobileOperatorInfo* operator_info) { 1463 SLOG(this, 3) << __func__; 1464 1465 Stringmap home_provider; 1466 if (!operator_info->sid().empty()) { 1467 home_provider[kOperatorCodeKey] = operator_info->sid(); 1468 } 1469 if (!operator_info->nid().empty()) { 1470 home_provider[kOperatorCodeKey] = operator_info->nid(); 1471 } 1472 if (!operator_info->mccmnc().empty()) { 1473 home_provider[kOperatorCodeKey] = operator_info->mccmnc(); 1474 } 1475 if (!operator_info->operator_name().empty()) { 1476 home_provider[kOperatorNameKey] = operator_info->operator_name(); 1477 } 1478 if (!operator_info->country().empty()) { 1479 home_provider[kOperatorCountryKey] = operator_info->country(); 1480 } 1481 set_home_provider(home_provider); 1482 1483 const ScopedVector<MobileOperatorInfo::MobileAPN>& apn_list = 1484 operator_info->apn_list(); 1485 Stringmaps apn_list_dict; 1486 1487 for (const auto& mobile_apn : apn_list) { 1488 Stringmap props; 1489 if (!mobile_apn->apn.empty()) { 1490 props[kApnProperty] = mobile_apn->apn; 1491 } 1492 if (!mobile_apn->username.empty()) { 1493 props[kApnUsernameProperty] = mobile_apn->username; 1494 } 1495 if (!mobile_apn->password.empty()) { 1496 props[kApnPasswordProperty] = mobile_apn->password; 1497 } 1498 1499 // Find the first localized and non-localized name, if any. 1500 if (!mobile_apn->operator_name_list.empty()) { 1501 props[kApnNameProperty] = mobile_apn->operator_name_list[0].name; 1502 } 1503 for (const auto& lname : mobile_apn->operator_name_list) { 1504 if (!lname.language.empty()) { 1505 props[kApnLocalizedNameProperty] = lname.name; 1506 } 1507 } 1508 1509 apn_list_dict.push_back(props); 1510 } 1511 set_apn_list(apn_list_dict); 1512 1513 set_provider_requires_roaming(operator_info->requires_roaming()); 1514 } 1515 1516 void Cellular::UpdateServingOperator( 1517 const MobileOperatorInfo* operator_info, 1518 const MobileOperatorInfo* home_provider_info) { 1519 SLOG(this, 3) << __func__; 1520 if (!service()) { 1521 return; 1522 } 1523 1524 Stringmap serving_operator; 1525 if (!operator_info->sid().empty()) { 1526 serving_operator[kOperatorCodeKey] = operator_info->sid(); 1527 } 1528 if (!operator_info->nid().empty()) { 1529 serving_operator[kOperatorCodeKey] = operator_info->nid(); 1530 } 1531 if (!operator_info->mccmnc().empty()) { 1532 serving_operator[kOperatorCodeKey] = operator_info->mccmnc(); 1533 } 1534 if (!operator_info->operator_name().empty()) { 1535 serving_operator[kOperatorNameKey] = operator_info->operator_name(); 1536 } 1537 if (!operator_info->country().empty()) { 1538 serving_operator[kOperatorCountryKey] = operator_info->country(); 1539 } 1540 service()->set_serving_operator(serving_operator); 1541 1542 // Set friendly name of service. 1543 string service_name; 1544 if (!operator_info->operator_name().empty()) { 1545 // If roaming, try to show "<home-provider> | <serving-operator>", per 3GPP 1546 // rules (TS 31.102 and annex A of 122.101). 1547 if (service()->roaming_state() == kRoamingStateRoaming && 1548 home_provider_info && 1549 !home_provider_info->operator_name().empty()) { 1550 service_name += home_provider_info->operator_name() + " | "; 1551 } 1552 service_name += operator_info->operator_name(); 1553 } else if (!operator_info->mccmnc().empty()) { 1554 // We could not get a name for the operator, just use the code. 1555 service_name = "cellular_" + operator_info->mccmnc(); 1556 } else { 1557 // We do not have any information, so must fallback to default service name. 1558 // Only assign a new default name if the service doesn't already have one, 1559 // because we we generate a new name each time. 1560 service_name = service()->friendly_name(); 1561 if (!IsDefaultFriendlyServiceName(service_name)) { 1562 service_name = CreateDefaultFriendlyServiceName(); 1563 } 1564 } 1565 service()->SetFriendlyName(service_name); 1566 } 1567 1568 // ///////////////////////////////////////////////////////////////////////////// 1569 // MobileOperatorInfoObserver implementation. 1570 Cellular::MobileOperatorInfoObserver::MobileOperatorInfoObserver( 1571 Cellular* cellular) 1572 : cellular_(cellular), 1573 capability_(nullptr) {} 1574 1575 Cellular::MobileOperatorInfoObserver::~MobileOperatorInfoObserver() {} 1576 1577 void Cellular::MobileOperatorInfoObserver::OnOperatorChanged() { 1578 SLOG(cellular_, 3) << __func__; 1579 1580 // Give the capabilities a chance to hook in and update their state. 1581 // Some tests set |capability_| to nullptr avoid having to expect the full 1582 // behaviour caused by this call. 1583 if (capability_) { 1584 capability_->OnOperatorChanged(); 1585 } 1586 1587 const MobileOperatorInfo* home_provider_info = 1588 cellular_->home_provider_info(); 1589 const MobileOperatorInfo* serving_operator_info = 1590 cellular_->serving_operator_info(); 1591 1592 const bool home_provider_known = 1593 home_provider_info->IsMobileNetworkOperatorKnown(); 1594 const bool serving_operator_known = 1595 serving_operator_info->IsMobileNetworkOperatorKnown(); 1596 1597 if (home_provider_known) { 1598 cellular_->UpdateHomeProvider(home_provider_info); 1599 } else if (serving_operator_known) { 1600 SLOG(cellular_, 2) << "Serving provider proxying in for home provider."; 1601 cellular_->UpdateHomeProvider(serving_operator_info); 1602 } 1603 1604 if (serving_operator_known) { 1605 if (home_provider_known) { 1606 cellular_->UpdateServingOperator(serving_operator_info, 1607 home_provider_info); 1608 } else { 1609 cellular_->UpdateServingOperator(serving_operator_info, nullptr); 1610 } 1611 } else if (home_provider_known) { 1612 cellular_->UpdateServingOperator(home_provider_info, home_provider_info); 1613 } 1614 } 1615 1616 } // namespace shill 1617