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