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;
ObjectID(Cellular * c)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
Cellular(ModemInfo * modem_info,const string & link_name,const string & address,int interface_index,Type type,const string & service,const string & path)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
~Cellular()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
Load(StoreInterface * storage)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
Save(StoreInterface * storage)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
GetStateString(State state)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
GetModemStateString(ModemState modem_state)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
GetTechnologyFamily(Error * error)228 string Cellular::GetTechnologyFamily(Error* error) {
229 return capability_->GetTypeString();
230 }
231
SetState(State state)232 void Cellular::SetState(State state) {
233 SLOG(this, 2) << GetStateString(state_) << " -> "
234 << GetStateString(state);
235 state_ = state;
236 }
237
HelpRegisterDerivedBool(const string & name,bool (Cellular::* get)(Error * error),bool (Cellular::* set)(const bool & value,Error * error))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
HelpRegisterConstDerivedString(const string & name,string (Cellular::* get)(Error *))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
Start(Error * error,const EnabledStateChangedCallback & callback)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
Stop(Error * error,const EnabledStateChangedCallback & callback)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
IsUnderlyingDeviceEnabled() const283 bool Cellular::IsUnderlyingDeviceEnabled() const {
284 return IsEnabledModemState(modem_state_);
285 }
286
IsModemRegistered() const287 bool Cellular::IsModemRegistered() const {
288 return (modem_state_ == Cellular::kModemStateRegistered ||
289 modem_state_ == Cellular::kModemStateConnecting ||
290 modem_state_ == Cellular::kModemStateConnected);
291 }
292
293 // static
IsEnabledModemState(ModemState state)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
StartModemCallback(const EnabledStateChangedCallback & callback,const Error & error)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
StopModemCallback(const EnabledStateChangedCallback & callback,const Error & error)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
InitCapability(Type type)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
Activate(const string & carrier,Error * error,const ResultCallback & callback)376 void Cellular::Activate(const string& carrier,
377 Error* error, const ResultCallback& callback) {
378 capability_->Activate(carrier, error, callback);
379 }
380
CompleteActivation(Error * error)381 void Cellular::CompleteActivation(Error* error) {
382 capability_->CompleteActivation(error);
383 }
384
RegisterOnNetwork(const string & network_id,Error * error,const ResultCallback & callback)385 void Cellular::RegisterOnNetwork(const string& network_id,
386 Error* error,
387 const ResultCallback& callback) {
388 capability_->RegisterOnNetwork(network_id, error, callback);
389 }
390
RequirePIN(const string & pin,bool require,Error * error,const ResultCallback & callback)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
EnterPIN(const string & pin,Error * error,const ResultCallback & callback)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
UnblockPIN(const string & unblock_code,const string & pin,Error * error,const ResultCallback & callback)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
ChangePIN(const string & old_pin,const string & new_pin,Error * error,const ResultCallback & callback)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
Reset(Error * error,const ResultCallback & callback)416 void Cellular::Reset(Error* error, const ResultCallback& callback) {
417 SLOG(this, 2) << __func__;
418 capability_->Reset(error, callback);
419 }
420
SetCarrier(const string & carrier,Error * error,const ResultCallback & callback)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
IsIPv6Allowed() const427 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
DropConnection()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
SetServiceState(Service::ConnectState state)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
SetServiceFailure(Service::ConnectFailure failure_state)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
SetServiceFailureSilent(Service::ConnectFailure failure_state)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
OnBeforeSuspend(const ResultCallback & callback)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
OnAfterResume()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
Scan(ScanType,Error * error,const string &)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
OnScanReply(const Stringmaps & found_networks,const Error & error)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
HandleNewRegistrationState()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
HandleNewSignalQuality(uint32_t strength)612 void Cellular::HandleNewSignalQuality(uint32_t strength) {
613 SLOG(this, 2) << "Signal strength: " << strength;
614 if (service_) {
615 service_->SetStrength(strength);
616 }
617 }
618
CreateService()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
DestroyService()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
Connect(Error * error)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.
OnConnectReply(const Error & error)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
OnDisabled()728 void Cellular::OnDisabled() {
729 SetEnabled(false);
730 }
731
OnEnabled()732 void Cellular::OnEnabled() {
733 manager()->AddTerminationAction(FriendlyName(),
734 Bind(&Cellular::StartTermination,
735 weak_ptr_factory_.GetWeakPtr()));
736 SetEnabled(true);
737 }
738
OnConnecting()739 void Cellular::OnConnecting() {
740 if (service_)
741 service_->SetState(Service::kStateAssociating);
742 }
743
OnConnected()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
OnConnectFailed(const Error & error)763 void Cellular::OnConnectFailed(const Error& error) {
764 if (service_)
765 service_->SetFailure(Service::kFailureUnknown);
766 }
767
Disconnect(Error * error,const char * reason)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
OnDisconnectReply(const Error & error)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
OnDisconnected()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
OnDisconnectFailed()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
EstablishLink()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
LinkEvent(unsigned int flags,unsigned int change)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
OnPropertiesChanged(const string & interface,const KeyValueStore & changed_properties,const vector<string> & invalidated_properties)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
CreateDefaultFriendlyServiceName()904 string Cellular::CreateDefaultFriendlyServiceName() {
905 SLOG(this, 2) << __func__;
906 return base::StringPrintf("%s_%u",
907 kGenericServiceNamePrefix,
908 friendly_service_name_id_++);
909 }
910
IsDefaultFriendlyServiceName(const string & service_name) const911 bool Cellular::IsDefaultFriendlyServiceName(const string& service_name) const {
912 return base::StartsWith(service_name, kGenericServiceNamePrefix,
913 base::CompareCase::SENSITIVE);
914 }
915
OnModemStateChanged(ModemState new_state)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
IsActivating() const956 bool Cellular::IsActivating() const {
957 return capability_->IsActivating();
958 }
959
SetAllowRoaming(const bool & value,Error *)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
StartTermination()981 void Cellular::StartTermination() {
982 SLOG(this, 2) << __func__;
983 OnBeforeSuspend(Bind(&Cellular::OnTerminationCompleted,
984 weak_ptr_factory_.GetWeakPtr()));
985 }
986
OnTerminationCompleted(const Error & error)987 void Cellular::OnTerminationCompleted(const Error& error) {
988 LOG(INFO) << __func__ << ": " << error;
989 manager()->TerminationActionComplete(FriendlyName());
990 manager()->RemoveTerminationAction(FriendlyName());
991 }
992
DisconnectCleanup()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
LogRestartModemResult(const Error & error)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
StartPPP(const string & serial_device)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
StopPPP()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_|
GetLogin(string * user,string * password)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_|.
Notify(const string & reason,const map<string,string> & dict)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
OnPPPAuthenticated()1097 void Cellular::OnPPPAuthenticated() {
1098 SLOG(PPP, this, 2) << __func__;
1099 is_ppp_authenticating_ = false;
1100 }
1101
OnPPPAuthenticating()1102 void Cellular::OnPPPAuthenticating() {
1103 SLOG(PPP, this, 2) << __func__;
1104 is_ppp_authenticating_ = true;
1105 }
1106
OnPPPConnected(const map<string,string> & params)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
OnPPPDisconnected()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
OnPPPDied(pid_t pid,int exit)1156 void Cellular::OnPPPDied(pid_t pid, int exit) {
1157 LOG(INFO) << __func__ << " on " << link_name();
1158 OnPPPDisconnected();
1159 }
1160
UpdateScanning()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
RegisterProperties()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
set_home_provider(const Stringmap & home_provider)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
set_carrier(const string & carrier)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
set_scanning_supported(bool scanning_supported)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
set_esn(const string & esn)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
set_firmware_revision(const string & firmware_revision)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
set_hardware_revision(const string & hardware_revision)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.
set_imei(const string & imei)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
set_imsi(const string & imsi)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
set_mdn(const string & mdn)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
set_meid(const string & meid)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
set_min(const string & min)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
set_manufacturer(const string & manufacturer)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
set_model_id(const string & model_id)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
set_mm_plugin(const string & mm_plugin)1344 void Cellular::set_mm_plugin(const string& mm_plugin) {
1345 mm_plugin_ = mm_plugin;
1346 }
1347
set_scanning(bool scanning)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
set_selected_network(const string & selected_network)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
set_found_networks(const Stringmaps & found_networks)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
clear_found_networks()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
set_provider_requires_roaming(bool provider_requires_roaming)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
set_sim_present(bool sim_present)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
set_apn_list(const Stringmaps & apn_list)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
set_sim_identifier(const string & sim_identifier)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
set_supported_carriers(const Strings & supported_carriers)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
set_prl_version(uint16_t prl_version)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
set_home_provider_info(MobileOperatorInfo * home_provider_info)1453 void Cellular::set_home_provider_info(MobileOperatorInfo* home_provider_info) {
1454 home_provider_info_.reset(home_provider_info);
1455 }
1456
set_serving_operator_info(MobileOperatorInfo * serving_operator_info)1457 void Cellular::set_serving_operator_info(
1458 MobileOperatorInfo* serving_operator_info) {
1459 serving_operator_info_.reset(serving_operator_info);
1460 }
1461
UpdateHomeProvider(const MobileOperatorInfo * operator_info)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
UpdateServingOperator(const MobileOperatorInfo * operator_info,const MobileOperatorInfo * home_provider_info)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.
MobileOperatorInfoObserver(Cellular * cellular)1570 Cellular::MobileOperatorInfoObserver::MobileOperatorInfoObserver(
1571 Cellular* cellular)
1572 : cellular_(cellular),
1573 capability_(nullptr) {}
1574
~MobileOperatorInfoObserver()1575 Cellular::MobileOperatorInfoObserver::~MobileOperatorInfoObserver() {}
1576
OnOperatorChanged()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