1 //
2 // Copyright (C) 2013 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 #include "shill/cellular/cellular_capability_universal.h"
18 
19 #include <base/bind.h>
20 #include <base/stl_util.h>
21 #include <base/strings/string_util.h>
22 #include <base/strings/stringprintf.h>
23 #if defined(__ANDROID__)
24 #include <dbus/service_constants.h>
25 #else
26 #include <chromeos/dbus/service_constants.h>
27 #endif  // __ANDROID__
28 #include <ModemManager/ModemManager.h>
29 
30 #include <string>
31 #include <vector>
32 
33 #include "shill/adaptor_interfaces.h"
34 #include "shill/cellular/cellular_bearer.h"
35 #include "shill/cellular/cellular_service.h"
36 #include "shill/cellular/mobile_operator_info.h"
37 #include "shill/control_interface.h"
38 #include "shill/dbus_properties_proxy_interface.h"
39 #include "shill/error.h"
40 #include "shill/logging.h"
41 #include "shill/pending_activation_store.h"
42 #include "shill/property_accessor.h"
43 
44 #ifdef MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN
45 #error "Do not include mm-modem.h"
46 #endif
47 
48 using base::Bind;
49 using base::Closure;
50 using std::string;
51 using std::vector;
52 
53 namespace shill {
54 
55 namespace Logging {
56 static auto kModuleLogScope = ScopeLogger::kCellular;
ObjectID(CellularCapabilityUniversal * c)57 static string ObjectID(CellularCapabilityUniversal* c) {
58   return c->cellular()->GetRpcIdentifier();
59 }
60 }
61 
62 // static
63 const char CellularCapabilityUniversal::kConnectPin[] = "pin";
64 const char CellularCapabilityUniversal::kConnectOperatorId[] = "operator-id";
65 const char CellularCapabilityUniversal::kConnectApn[] = "apn";
66 const char CellularCapabilityUniversal::kConnectIPType[] = "ip-type";
67 const char CellularCapabilityUniversal::kConnectUser[] = "user";
68 const char CellularCapabilityUniversal::kConnectPassword[] = "password";
69 const char CellularCapabilityUniversal::kConnectNumber[] = "number";
70 const char CellularCapabilityUniversal::kConnectAllowRoaming[] =
71     "allow-roaming";
72 const char CellularCapabilityUniversal::kConnectRMProtocol[] = "rm-protocol";
73 const int64_t CellularCapabilityUniversal::kEnterPinTimeoutMilliseconds = 20000;
74 const int64_t
75 CellularCapabilityUniversal::kRegistrationDroppedUpdateTimeoutMilliseconds =
76     15000;
77 const char CellularCapabilityUniversal::kRootPath[] = "/";
78 const char CellularCapabilityUniversal::kStatusProperty[] = "status";
79 const char CellularCapabilityUniversal::kOperatorLongProperty[] =
80     "operator-long";
81 const char CellularCapabilityUniversal::kOperatorShortProperty[] =
82     "operator-short";
83 const char CellularCapabilityUniversal::kOperatorCodeProperty[] =
84     "operator-code";
85 const char CellularCapabilityUniversal::kOperatorAccessTechnologyProperty[] =
86     "access-technology";
87 const char CellularCapabilityUniversal::kAltairLTEMMPlugin[] = "Altair LTE";
88 const char CellularCapabilityUniversal::kNovatelLTEMMPlugin[] = "Novatel LTE";
89 const int CellularCapabilityUniversal::kSetPowerStateTimeoutMilliseconds =
90     20000;
91 
92 namespace {
93 
94 const char kPhoneNumber[] = "*99#";
95 
96 // This identifier is specified in the serviceproviders.prototxt file.
97 const char kVzwIdentifier[] = "c83d6597-dc91-4d48-a3a7-d86b80123751";
98 const size_t kVzwMdnLength = 10;
99 
AccessTechnologyToString(uint32_t access_technologies)100 string AccessTechnologyToString(uint32_t access_technologies) {
101   if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_LTE)
102     return kNetworkTechnologyLte;
103   if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
104                               MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
105                               MM_MODEM_ACCESS_TECHNOLOGY_EVDOB))
106     return kNetworkTechnologyEvdo;
107   if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_1XRTT)
108     return kNetworkTechnology1Xrtt;
109   if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS)
110     return kNetworkTechnologyHspaPlus;
111   if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
112                               MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
113                               MM_MODEM_ACCESS_TECHNOLOGY_HSDPA))
114     return kNetworkTechnologyHspa;
115   if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_UMTS)
116     return kNetworkTechnologyUmts;
117   if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_EDGE)
118     return kNetworkTechnologyEdge;
119   if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_GPRS)
120     return kNetworkTechnologyGprs;
121   if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
122                               MM_MODEM_ACCESS_TECHNOLOGY_GSM))
123       return kNetworkTechnologyGsm;
124   return "";
125 }
126 
AccessTechnologyToTechnologyFamily(uint32_t access_technologies)127 string AccessTechnologyToTechnologyFamily(uint32_t access_technologies) {
128   if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_LTE |
129                              MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS |
130                              MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
131                              MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
132                              MM_MODEM_ACCESS_TECHNOLOGY_HSDPA |
133                              MM_MODEM_ACCESS_TECHNOLOGY_UMTS |
134                              MM_MODEM_ACCESS_TECHNOLOGY_EDGE |
135                              MM_MODEM_ACCESS_TECHNOLOGY_GPRS |
136                              MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
137                              MM_MODEM_ACCESS_TECHNOLOGY_GSM))
138     return kTechnologyFamilyGsm;
139   if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
140                              MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
141                              MM_MODEM_ACCESS_TECHNOLOGY_EVDOB |
142                              MM_MODEM_ACCESS_TECHNOLOGY_1XRTT))
143     return kTechnologyFamilyCdma;
144   return "";
145 }
146 
147 }  // namespace
148 
CellularCapabilityUniversal(Cellular * cellular,ControlInterface * control_interface,ModemInfo * modem_info)149 CellularCapabilityUniversal::CellularCapabilityUniversal(
150     Cellular* cellular,
151     ControlInterface* control_interface,
152     ModemInfo* modem_info)
153     : CellularCapability(cellular, control_interface, modem_info),
154       mobile_operator_info_(new MobileOperatorInfo(cellular->dispatcher(),
155                                                    "ParseScanResult")),
156       weak_ptr_factory_(this),
157       registration_state_(MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN),
158       current_capabilities_(MM_MODEM_CAPABILITY_NONE),
159       access_technologies_(MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN),
160       resetting_(false),
161       subscription_state_(kSubscriptionStateUnknown),
162       reset_done_(false),
163       registration_dropped_update_timeout_milliseconds_(
164           kRegistrationDroppedUpdateTimeoutMilliseconds) {
165   SLOG(this, 2) << "Cellular capability constructed: Universal";
166   mobile_operator_info_->Init();
167   HelpRegisterConstDerivedKeyValueStore(
168       kSIMLockStatusProperty,
169       &CellularCapabilityUniversal::SimLockStatusToProperty);
170 }
171 
~CellularCapabilityUniversal()172 CellularCapabilityUniversal::~CellularCapabilityUniversal() {}
173 
SimLockStatusToProperty(Error *)174 KeyValueStore CellularCapabilityUniversal::SimLockStatusToProperty(
175     Error* /*error*/) {
176   KeyValueStore status;
177   string lock_type;
178   switch (sim_lock_status_.lock_type) {
179     case MM_MODEM_LOCK_SIM_PIN:
180       lock_type = "sim-pin";
181       break;
182     case MM_MODEM_LOCK_SIM_PUK:
183       lock_type = "sim-puk";
184       break;
185     default:
186       lock_type = "";
187       break;
188   }
189   status.SetBool(kSIMLockEnabledProperty, sim_lock_status_.enabled);
190   status.SetString(kSIMLockTypeProperty, lock_type);
191   status.SetUint(kSIMLockRetriesLeftProperty, sim_lock_status_.retries_left);
192   return status;
193 }
194 
HelpRegisterConstDerivedKeyValueStore(const string & name,KeyValueStore (CellularCapabilityUniversal::* get)(Error * error))195 void CellularCapabilityUniversal::HelpRegisterConstDerivedKeyValueStore(
196     const string& name,
197     KeyValueStore(CellularCapabilityUniversal::*get)(Error* error)) {
198   cellular()->mutable_store()->RegisterDerivedKeyValueStore(
199       name,
200       KeyValueStoreAccessor(
201           new CustomAccessor<CellularCapabilityUniversal, KeyValueStore>(
202               this, get, nullptr)));
203 }
204 
InitProxies()205 void CellularCapabilityUniversal::InitProxies() {
206   modem_3gpp_proxy_.reset(
207       control_interface()->CreateMM1ModemModem3gppProxy(
208           cellular()->dbus_path(), cellular()->dbus_service()));
209   modem_proxy_.reset(
210       control_interface()->CreateMM1ModemProxy(cellular()->dbus_path(),
211                                                cellular()->dbus_service()));
212   modem_simple_proxy_.reset(
213       control_interface()->CreateMM1ModemSimpleProxy(
214           cellular()->dbus_path(), cellular()->dbus_service()));
215 
216   modem_proxy_->set_state_changed_callback(
217       Bind(&CellularCapabilityUniversal::OnModemStateChangedSignal,
218            weak_ptr_factory_.GetWeakPtr()));
219   // Do not create a SIM proxy until the device is enabled because we
220   // do not yet know the object path of the sim object.
221   // TODO(jglasgow): register callbacks
222 }
223 
StartModem(Error * error,const ResultCallback & callback)224 void CellularCapabilityUniversal::StartModem(Error* error,
225                                              const ResultCallback& callback) {
226   SLOG(this, 3) << __func__;
227   InitProxies();
228   deferred_enable_modem_callback_.Reset();
229   EnableModem(true, error, callback);
230 }
231 
EnableModem(bool deferrable,Error * error,const ResultCallback & callback)232 void CellularCapabilityUniversal::EnableModem(bool deferrable,
233                                               Error* error,
234                                               const ResultCallback& callback) {
235   SLOG(this, 3) << __func__ << "(deferrable=" << deferrable << ")";
236   CHECK(!callback.is_null());
237   Error local_error(Error::kOperationInitiated);
238   modem_info()->metrics()->NotifyDeviceEnableStarted(
239       cellular()->interface_index());
240   modem_proxy_->Enable(
241       true,
242       &local_error,
243       Bind(&CellularCapabilityUniversal::EnableModemCompleted,
244            weak_ptr_factory_.GetWeakPtr(), deferrable, callback),
245       kTimeoutEnable);
246   if (local_error.IsFailure()) {
247     SLOG(this, 2) << __func__ << "Call to modem_proxy_->Enable() failed";
248   }
249   if (error) {
250     error->CopyFrom(local_error);
251   }
252 }
253 
EnableModemCompleted(bool deferrable,const ResultCallback & callback,const Error & error)254 void CellularCapabilityUniversal::EnableModemCompleted(
255     bool deferrable, const ResultCallback& callback, const Error& error) {
256   SLOG(this, 3) << __func__ << "(deferrable=" << deferrable
257                             << ", error=" << error << ")";
258 
259   // If the enable operation failed with Error::kWrongState, the modem is not
260   // in the expected state (i.e. disabled). If |deferrable| indicates that the
261   // enable operation can be deferred, we defer the operation until the modem
262   // goes into the expected state (see OnModemStateChangedSignal).
263   //
264   // Note that when the SIM is locked, the enable operation also fails with
265   // Error::kWrongState. The enable operation is deferred until the modem goes
266   // into the disabled state after the SIM is unlocked. We may choose not to
267   // defer the enable operation when the SIM is locked, but the UI needs to
268   // trigger the enable operation after the SIM is unlocked, which is currently
269   // not the case.
270   if (error.IsFailure()) {
271     if (!deferrable || error.type() != Error::kWrongState) {
272       callback.Run(error);
273       return;
274     }
275 
276     if (deferred_enable_modem_callback_.is_null()) {
277       SLOG(this, 2) << "Defer enable operation.";
278       // The Enable operation to be deferred should not be further deferrable.
279       deferred_enable_modem_callback_ =
280           Bind(&CellularCapabilityUniversal::EnableModem,
281                weak_ptr_factory_.GetWeakPtr(),
282                false,  // non-deferrable
283                nullptr,
284                callback);
285     }
286     return;
287   }
288 
289   // After modem is enabled, it should be possible to get properties
290   // TODO(jglasgow): handle errors from GetProperties
291   GetProperties();
292   // We expect the modem to start scanning after it has been enabled.
293   // Change this if this behavior is no longer the case in the future.
294   modem_info()->metrics()->NotifyDeviceEnableFinished(
295       cellular()->interface_index());
296   modem_info()->metrics()->NotifyDeviceScanStarted(
297       cellular()->interface_index());
298   callback.Run(error);
299 }
300 
StopModem(Error * error,const ResultCallback & callback)301 void CellularCapabilityUniversal::StopModem(Error* error,
302                                             const ResultCallback& callback) {
303   CHECK(!callback.is_null());
304   CHECK(error);
305   // If there is an outstanding registration change, simply ignore it since
306   // the service will be destroyed anyway.
307   if (!registration_dropped_update_callback_.IsCancelled()) {
308     registration_dropped_update_callback_.Cancel();
309     SLOG(this, 2) << __func__ << " Cancelled delayed deregister.";
310   }
311 
312   // Some modems will implicitly disconnect the bearer when transitioning to
313   // low power state. For such modems, it's faster to let the modem disconnect
314   // the bearer. To do that, we just remove the bearer from the list so
315   // ModemManager doesn't try to disconnect it during disable.
316   Closure task;
317   if (cellular()->mm_plugin() == kAltairLTEMMPlugin) {
318     task = Bind(&CellularCapabilityUniversal::Stop_DeleteActiveBearer,
319                 weak_ptr_factory_.GetWeakPtr(),
320                 callback);
321   } else {
322     task = Bind(&CellularCapabilityUniversal::Stop_Disable,
323                 weak_ptr_factory_.GetWeakPtr(),
324                 callback);
325   }
326   cellular()->dispatcher()->PostTask(task);
327   deferred_enable_modem_callback_.Reset();
328 }
329 
Stop_DeleteActiveBearer(const ResultCallback & callback)330 void CellularCapabilityUniversal::Stop_DeleteActiveBearer(
331     const ResultCallback& callback) {
332   SLOG(this, 3) << __func__;
333 
334   if (!active_bearer_) {
335     Stop_Disable(callback);
336     return;
337   }
338 
339   Error error;
340   modem_proxy_->DeleteBearer(
341       active_bearer_->dbus_path(), &error,
342       Bind(&CellularCapabilityUniversal::Stop_DeleteActiveBearerCompleted,
343            weak_ptr_factory_.GetWeakPtr(), callback),
344       kTimeoutDefault);
345   if (error.IsFailure())
346     callback.Run(error);
347 }
348 
Stop_DeleteActiveBearerCompleted(const ResultCallback & callback,const Error & error)349 void CellularCapabilityUniversal::Stop_DeleteActiveBearerCompleted(
350     const ResultCallback& callback, const Error& error) {
351   SLOG(this, 3) << __func__;
352   // Disregard the error from the bearer deletion since the disable will clean
353   // up any remaining bearers.
354   Stop_Disable(callback);
355 }
356 
Stop_Disable(const ResultCallback & callback)357 void CellularCapabilityUniversal::Stop_Disable(const ResultCallback& callback) {
358   SLOG(this, 3) << __func__;
359   Error error;
360   modem_info()->metrics()->NotifyDeviceDisableStarted(
361       cellular()->interface_index());
362   modem_proxy_->Enable(
363       false, &error,
364       Bind(&CellularCapabilityUniversal::Stop_DisableCompleted,
365            weak_ptr_factory_.GetWeakPtr(), callback),
366       kTimeoutEnable);
367   if (error.IsFailure())
368     callback.Run(error);
369 }
370 
Stop_DisableCompleted(const ResultCallback & callback,const Error & error)371 void CellularCapabilityUniversal::Stop_DisableCompleted(
372     const ResultCallback& callback, const Error& error) {
373   SLOG(this, 3) << __func__;
374 
375   if (error.IsSuccess()) {
376     // The modem has been successfully disabled, but we still need to power it
377     // down.
378     Stop_PowerDown(callback);
379   } else {
380     // An error occurred; terminate the disable sequence.
381     callback.Run(error);
382   }
383 }
384 
Stop_PowerDown(const ResultCallback & callback)385 void CellularCapabilityUniversal::Stop_PowerDown(
386     const ResultCallback& callback) {
387   SLOG(this, 3) << __func__;
388   Error error;
389   modem_proxy_->SetPowerState(
390       MM_MODEM_POWER_STATE_LOW,
391       &error,
392       Bind(&CellularCapabilityUniversal::Stop_PowerDownCompleted,
393            weak_ptr_factory_.GetWeakPtr(), callback),
394       kSetPowerStateTimeoutMilliseconds);
395 
396   if (error.IsFailure())
397     // This really shouldn't happen, but if it does, report success,
398     // because a stop initiated power down is only called if the
399     // modem was successfully disabled, but the failure of this
400     // operation should still be propagated up as a successful disable.
401     Stop_PowerDownCompleted(callback, error);
402 }
403 
404 // Note: if we were in the middle of powering down the modem when the
405 // system suspended, we might not get this event from
406 // ModemManager. And we might not even get a timeout from dbus-c++,
407 // because StartModem re-initializes proxies.
Stop_PowerDownCompleted(const ResultCallback & callback,const Error & error)408 void CellularCapabilityUniversal::Stop_PowerDownCompleted(
409     const ResultCallback& callback,
410     const Error& error) {
411   SLOG(this, 3) << __func__;
412 
413   if (error.IsFailure())
414     SLOG(this, 2) << "Ignoring error returned by SetPowerState: " << error;
415 
416   // Since the disable succeeded, if power down fails, we currently fail
417   // silently, i.e. we need to report the disable operation as having
418   // succeeded.
419   modem_info()->metrics()->NotifyDeviceDisableFinished(
420       cellular()->interface_index());
421   ReleaseProxies();
422   callback.Run(Error());
423 }
424 
Connect(const KeyValueStore & properties,Error * error,const ResultCallback & callback)425 void CellularCapabilityUniversal::Connect(const KeyValueStore& properties,
426                                           Error* error,
427                                           const ResultCallback& callback) {
428   SLOG(this, 3) << __func__;
429   RpcIdentifierCallback cb = Bind(&CellularCapabilityUniversal::OnConnectReply,
430                                   weak_ptr_factory_.GetWeakPtr(),
431                                   callback);
432   modem_simple_proxy_->Connect(properties, error, cb, kTimeoutConnect);
433 }
434 
Disconnect(Error * error,const ResultCallback & callback)435 void CellularCapabilityUniversal::Disconnect(Error* error,
436                                              const ResultCallback& callback) {
437   SLOG(this, 3) << __func__;
438   if (modem_simple_proxy_.get()) {
439     SLOG(this, 2) << "Disconnect all bearers.";
440     // If "/" is passed as the bearer path, ModemManager will disconnect all
441     // bearers.
442     modem_simple_proxy_->Disconnect(kRootPath,
443                                     error,
444                                     callback,
445                                     kTimeoutDisconnect);
446   }
447 }
448 
CompleteActivation(Error * error)449 void CellularCapabilityUniversal::CompleteActivation(Error* error) {
450   SLOG(this, 3) << __func__;
451 
452   // Persist the ICCID as "Pending Activation".
453   // We're assuming that when this function gets called,
454   // |cellular()->sim_identifier()| will be non-empty. We still check here that
455   // is non-empty, though something is wrong if it is empty.
456   const string& sim_identifier = cellular()->sim_identifier();
457   if (sim_identifier.empty()) {
458     SLOG(this, 2) << "SIM identifier not available. Nothing to do.";
459     return;
460   }
461 
462   modem_info()->pending_activation_store()->SetActivationState(
463       PendingActivationStore::kIdentifierICCID,
464       sim_identifier,
465       PendingActivationStore::kStatePending);
466   UpdatePendingActivationState();
467 
468   SLOG(this, 2) << "Resetting modem for activation.";
469   ResetAfterActivation();
470 }
471 
ResetAfterActivation()472 void CellularCapabilityUniversal::ResetAfterActivation() {
473   SLOG(this, 3) << __func__;
474 
475   // Here the initial call to Reset might fail in rare cases. Simply ignore.
476   Error error;
477   ResultCallback callback = Bind(
478       &CellularCapabilityUniversal::OnResetAfterActivationReply,
479       weak_ptr_factory_.GetWeakPtr());
480   Reset(&error, callback);
481   if (error.IsFailure())
482     SLOG(this, 2) << "Failed to reset after activation.";
483 }
484 
OnResetAfterActivationReply(const Error & error)485 void CellularCapabilityUniversal::OnResetAfterActivationReply(
486     const Error& error) {
487   SLOG(this, 3) << __func__;
488   if (error.IsFailure()) {
489     SLOG(this, 2) << "Failed to reset after activation. Try again later.";
490     // TODO(armansito): Maybe post a delayed reset task?
491     return;
492   }
493   reset_done_ = true;
494   UpdatePendingActivationState();
495 }
496 
UpdatePendingActivationState()497 void CellularCapabilityUniversal::UpdatePendingActivationState() {
498   SLOG(this, 3) << __func__;
499 
500   const string& sim_identifier = cellular()->sim_identifier();
501   bool registered =
502       registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME;
503 
504   // We know a service is activated if |subscription_state_| is
505   // kSubscriptionStateProvisioned / kSubscriptionStateOutOfData
506   // In the case that |subscription_state_| is kSubscriptionStateUnknown, we
507   // fallback on checking for a valid MDN.
508   bool activated =
509     ((subscription_state_ == kSubscriptionStateProvisioned) ||
510      (subscription_state_ == kSubscriptionStateOutOfData)) ||
511     ((subscription_state_ == kSubscriptionStateUnknown) && IsMdnValid());
512 
513   if (activated && !sim_identifier.empty())
514       modem_info()->pending_activation_store()->RemoveEntry(
515           PendingActivationStore::kIdentifierICCID,
516           sim_identifier);
517 
518   CellularServiceRefPtr service = cellular()->service();
519 
520   if (!service.get())
521     return;
522 
523   if (service->activation_state() == kActivationStateActivated)
524       // Either no service or already activated. Nothing to do.
525       return;
526 
527   // If the ICCID is not available, the following logic can be delayed until it
528   // becomes available.
529   if (sim_identifier.empty())
530     return;
531 
532   PendingActivationStore::State state =
533       modem_info()->pending_activation_store()->GetActivationState(
534           PendingActivationStore::kIdentifierICCID,
535           sim_identifier);
536   switch (state) {
537     case PendingActivationStore::kStatePending:
538       // Always mark the service as activating here, as the ICCID could have
539       // been unavailable earlier.
540       service->SetActivationState(kActivationStateActivating);
541       if (reset_done_) {
542         SLOG(this, 2) << "Post-payment activation reset complete.";
543         modem_info()->pending_activation_store()->SetActivationState(
544             PendingActivationStore::kIdentifierICCID,
545             sim_identifier,
546             PendingActivationStore::kStateActivated);
547       }
548       break;
549     case PendingActivationStore::kStateActivated:
550       if (registered) {
551         // Trigger auto connect here.
552         SLOG(this, 2) << "Modem has been reset at least once, try to "
553                       << "autoconnect to force MDN to update.";
554         service->AutoConnect();
555       }
556       break;
557     case PendingActivationStore::kStateUnknown:
558       // No entry exists for this ICCID. Nothing to do.
559       break;
560     default:
561       NOTREACHED();
562   }
563 }
564 
GetMdnForOLP(const MobileOperatorInfo * operator_info) const565 string CellularCapabilityUniversal::GetMdnForOLP(
566     const MobileOperatorInfo* operator_info) const {
567   // TODO(benchan): This is ugly. Remove carrier specific code once we move
568   // mobile activation logic to carrier-specifc extensions (crbug.com/260073).
569   const string& mdn = cellular()->mdn();
570   if (!operator_info->IsMobileNetworkOperatorKnown()) {
571     // Can't make any carrier specific modifications.
572     return mdn;
573   }
574 
575   if (operator_info->uuid() == kVzwIdentifier) {
576     // subscription_state_ is the definitive indicator of whether we need
577     // activation. The OLP expects an all zero MDN in that case.
578     if (subscription_state_ == kSubscriptionStateUnprovisioned || mdn.empty()) {
579       return string(kVzwMdnLength, '0');
580     }
581     if (mdn.length() > kVzwMdnLength) {
582       return mdn.substr(mdn.length() - kVzwMdnLength);
583     }
584   }
585   return mdn;
586 }
587 
ReleaseProxies()588 void CellularCapabilityUniversal::ReleaseProxies() {
589   SLOG(this, 3) << __func__;
590   modem_3gpp_proxy_.reset();
591   modem_proxy_.reset();
592   modem_simple_proxy_.reset();
593   sim_proxy_.reset();
594 }
595 
AreProxiesInitialized() const596 bool CellularCapabilityUniversal::AreProxiesInitialized() const {
597   return (modem_3gpp_proxy_.get() && modem_proxy_.get() &&
598           modem_simple_proxy_.get() && sim_proxy_.get());
599 }
600 
UpdateServiceActivationState()601 void CellularCapabilityUniversal::UpdateServiceActivationState() {
602   if (!cellular()->service().get())
603     return;
604 
605   const string& sim_identifier = cellular()->sim_identifier();
606   string activation_state;
607   PendingActivationStore::State state =
608       modem_info()->pending_activation_store()->GetActivationState(
609           PendingActivationStore::kIdentifierICCID,
610           sim_identifier);
611   if ((subscription_state_ == kSubscriptionStateUnknown ||
612        subscription_state_ == kSubscriptionStateUnprovisioned) &&
613       !sim_identifier.empty() &&
614       state == PendingActivationStore::kStatePending) {
615     activation_state = kActivationStateActivating;
616   } else if (IsServiceActivationRequired()) {
617     activation_state = kActivationStateNotActivated;
618   } else {
619     activation_state = kActivationStateActivated;
620 
621     // Mark an activated service for auto-connect by default. Since data from
622     // the user profile will be loaded after the call to OnServiceCreated, this
623     // property will be corrected based on the user data at that time.
624     // NOTE: This function can be called outside the service initialization
625     // path so make sure we don't overwrite the auto-connect setting.
626     if (cellular()->service()->activation_state() != activation_state)
627       cellular()->service()->SetAutoConnect(true);
628   }
629   cellular()->service()->SetActivationState(activation_state);
630 }
631 
OnServiceCreated()632 void CellularCapabilityUniversal::OnServiceCreated() {
633   cellular()->service()->SetActivationType(CellularService::kActivationTypeOTA);
634   UpdateServiceActivationState();
635 
636   // WORKAROUND:
637   // E362 modems on Verizon network does not properly redirect when a SIM
638   // runs out of credits, we need to enforce out-of-credits detection.
639   //
640   // The out-of-credits detection is also needed on ALT3100 modems until the PCO
641   // support is ready (crosbug.com/p/20461).
642   cellular()->service()->InitOutOfCreditsDetection(
643       GetOutOfCreditsDetectionType());
644 
645   // Make sure that the network technology is set when the service gets
646   // created, just in case.
647   cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
648 }
649 
650 // Create the list of APNs to try, in the following order:
651 // - last APN that resulted in a successful connection attempt on the
652 //   current network (if any)
653 // - the APN, if any, that was set by the user
654 // - the list of APNs found in the mobile broadband provider DB for the
655 //   home provider associated with the current SIM
656 // - as a last resort, attempt to connect with no APN
SetupApnTryList()657 void CellularCapabilityUniversal::SetupApnTryList() {
658   apn_try_list_.clear();
659 
660   DCHECK(cellular()->service().get());
661   const Stringmap* apn_info = cellular()->service()->GetLastGoodApn();
662   if (apn_info)
663     apn_try_list_.push_back(*apn_info);
664 
665   apn_info = cellular()->service()->GetUserSpecifiedApn();
666   if (apn_info)
667     apn_try_list_.push_back(*apn_info);
668 
669   apn_try_list_.insert(apn_try_list_.end(),
670                        cellular()->apn_list().begin(),
671                        cellular()->apn_list().end());
672 }
673 
SetupConnectProperties(KeyValueStore * properties)674 void CellularCapabilityUniversal::SetupConnectProperties(
675     KeyValueStore* properties) {
676   SetupApnTryList();
677   FillConnectPropertyMap(properties);
678 }
679 
FillConnectPropertyMap(KeyValueStore * properties)680 void CellularCapabilityUniversal::FillConnectPropertyMap(
681     KeyValueStore* properties) {
682 
683   // TODO(jglasgow): Is this really needed anymore?
684   properties->SetString(kConnectNumber, kPhoneNumber);
685 
686   properties->SetBool(kConnectAllowRoaming, AllowRoaming());
687 
688   if (!apn_try_list_.empty()) {
689     // Leave the APN at the front of the list, so that it can be recorded
690     // if the connect attempt succeeds.
691     Stringmap apn_info = apn_try_list_.front();
692     SLOG(this, 2) << __func__ << ": Using APN " << apn_info[kApnProperty];
693     properties->SetString(kConnectApn, apn_info[kApnProperty]);
694     if (ContainsKey(apn_info, kApnUsernameProperty))
695       properties->SetString(kConnectUser, apn_info[kApnUsernameProperty]);
696     if (ContainsKey(apn_info, kApnPasswordProperty))
697       properties->SetString(kConnectPassword, apn_info[kApnPasswordProperty]);
698   }
699 }
700 
OnConnectReply(const ResultCallback & callback,const string & path,const Error & error)701 void CellularCapabilityUniversal::OnConnectReply(const ResultCallback& callback,
702                                                  const string& path,
703                                                  const Error& error) {
704   SLOG(this, 3) << __func__ << "(" << error << ")";
705 
706   CellularServiceRefPtr service = cellular()->service();
707   if (!service) {
708     // The service could have been deleted before our Connect() request
709     // completes if the modem was enabled and then quickly disabled.
710     apn_try_list_.clear();
711   } else if (error.IsFailure()) {
712     service->ClearLastGoodApn();
713     // The APN that was just tried (and failed) is still at the
714     // front of the list, about to be removed. If the list is empty
715     // after that, try one last time without an APN. This may succeed
716     // with some modems in some cases.
717     if (RetriableConnectError(error) && !apn_try_list_.empty()) {
718       apn_try_list_.pop_front();
719       SLOG(this, 2) << "Connect failed with invalid APN, "
720                     << apn_try_list_.size() << " remaining APNs to try";
721       KeyValueStore props;
722       FillConnectPropertyMap(&props);
723       Error error;
724       Connect(props, &error, callback);
725       return;
726     }
727   } else {
728     if (!apn_try_list_.empty()) {
729       service->SetLastGoodApn(apn_try_list_.front());
730       apn_try_list_.clear();
731     }
732     SLOG(this, 2) << "Connected bearer " << path;
733   }
734 
735   if (!callback.is_null())
736     callback.Run(error);
737 
738   UpdatePendingActivationState();
739 }
740 
AllowRoaming()741 bool CellularCapabilityUniversal::AllowRoaming() {
742   return cellular()->provider_requires_roaming() || allow_roaming_property();
743 }
744 
GetProperties()745 void CellularCapabilityUniversal::GetProperties() {
746   SLOG(this, 3) << __func__;
747 
748   std::unique_ptr<DBusPropertiesProxyInterface> properties_proxy(
749       control_interface()->CreateDBusPropertiesProxy(
750           cellular()->dbus_path(), cellular()->dbus_service()));
751 
752   KeyValueStore properties(
753       properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM));
754   OnModemPropertiesChanged(properties, vector<string>());
755 
756   properties = properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM_MODEM3GPP);
757   OnModem3GPPPropertiesChanged(properties, vector<string>());
758 }
759 
UpdateServiceOLP()760 void CellularCapabilityUniversal::UpdateServiceOLP() {
761   SLOG(this, 3) << __func__;
762 
763   // OLP is based off of the Home Provider.
764   if (!cellular()->home_provider_info()->IsMobileNetworkOperatorKnown()) {
765     return;
766   }
767 
768   const vector<MobileOperatorInfo::OnlinePortal>& olp_list =
769       cellular()->home_provider_info()->olp_list();
770   if (olp_list.empty()) {
771     return;
772   }
773 
774   if (olp_list.size() > 1) {
775     SLOG(this, 1) << "Found multiple online portals. Choosing the first.";
776   }
777   string post_data = olp_list[0].post_data;
778   base::ReplaceSubstringsAfterOffset(
779       &post_data, 0, "${iccid}", cellular()->sim_identifier());
780   base::ReplaceSubstringsAfterOffset(
781       &post_data, 0, "${imei}", cellular()->imei());
782   base::ReplaceSubstringsAfterOffset(
783       &post_data, 0, "${imsi}", cellular()->imsi());
784   base::ReplaceSubstringsAfterOffset(
785       &post_data, 0, "${mdn}", GetMdnForOLP(cellular()->home_provider_info()));
786   base::ReplaceSubstringsAfterOffset(
787       &post_data, 0, "${min}", cellular()->min());
788   cellular()->service()->SetOLP(olp_list[0].url, olp_list[0].method, post_data);
789 }
790 
UpdateActiveBearer()791 void CellularCapabilityUniversal::UpdateActiveBearer() {
792   SLOG(this, 3) << __func__;
793 
794   // Look for the first active bearer and use its path as the connected
795   // one. Right now, we don't allow more than one active bearer.
796   active_bearer_.reset();
797   for (const auto& path : bearer_paths_) {
798     std::unique_ptr<CellularBearer> bearer(
799         new CellularBearer(control_interface(),
800                            path,
801                            cellular()->dbus_service()));
802     // The bearer object may have vanished before ModemManager updates the
803     // 'Bearers' property.
804     if (!bearer->Init())
805       continue;
806 
807     if (!bearer->connected())
808       continue;
809 
810     SLOG(this, 2) << "Found active bearer \"" << path << "\".";
811     CHECK(!active_bearer_) << "Found more than one active bearer.";
812     active_bearer_ = std::move(bearer);
813   }
814 
815   if (!active_bearer_)
816     SLOG(this, 2) << "No active bearer found.";
817 }
818 
IsServiceActivationRequired() const819 bool CellularCapabilityUniversal::IsServiceActivationRequired() const {
820   const string& sim_identifier = cellular()->sim_identifier();
821   // subscription_state_ is the definitive answer. If that does not work,
822   // fallback on MDN based logic.
823   if (subscription_state_ == kSubscriptionStateProvisioned ||
824       subscription_state_ == kSubscriptionStateOutOfData)
825     return false;
826 
827   // We are in the process of activating, ignore all other clues from the
828   // network and use our own knowledge about the activation state.
829   if (!sim_identifier.empty() &&
830       modem_info()->pending_activation_store()->GetActivationState(
831           PendingActivationStore::kIdentifierICCID,
832           sim_identifier) != PendingActivationStore::kStateUnknown)
833     return false;
834 
835   // Network notification that the service needs to be activated.
836   if (subscription_state_ == kSubscriptionStateUnprovisioned)
837     return true;
838 
839   // If there is no online payment portal information, it's safer to assume
840   // the service does not require activation.
841   if (!cellular()->home_provider_info()->IsMobileNetworkOperatorKnown() ||
842       cellular()->home_provider_info()->olp_list().empty()) {
843     return false;
844   }
845 
846   // If the MDN is invalid (i.e. empty or contains only zeros), the service
847   // requires activation.
848   return !IsMdnValid();
849 }
850 
IsMdnValid() const851 bool CellularCapabilityUniversal::IsMdnValid() const {
852   const string& mdn = cellular()->mdn();
853   // Note that |mdn| is normalized to contain only digits in OnMdnChanged().
854   for (size_t i = 0; i < mdn.size(); ++i) {
855     if (mdn[i] != '0')
856       return true;
857   }
858   return false;
859 }
860 
861 // always called from an async context
Register(const ResultCallback & callback)862 void CellularCapabilityUniversal::Register(const ResultCallback& callback) {
863   SLOG(this, 3) << __func__ << " \"" << cellular()->selected_network()
864                             << "\"";
865   CHECK(!callback.is_null());
866   Error error;
867   ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
868                                 weak_ptr_factory_.GetWeakPtr(), callback);
869   modem_3gpp_proxy_->Register(cellular()->selected_network(), &error, cb,
870                               kTimeoutRegister);
871   if (error.IsFailure())
872     callback.Run(error);
873 }
874 
RegisterOnNetwork(const string & network_id,Error * error,const ResultCallback & callback)875 void CellularCapabilityUniversal::RegisterOnNetwork(
876     const string& network_id,
877     Error* error,
878     const ResultCallback& callback) {
879   SLOG(this, 3) << __func__ << "(" << network_id << ")";
880   CHECK(error);
881   desired_network_ = network_id;
882   ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
883                                 weak_ptr_factory_.GetWeakPtr(), callback);
884   modem_3gpp_proxy_->Register(network_id, error, cb, kTimeoutRegister);
885 }
886 
OnRegisterReply(const ResultCallback & callback,const Error & error)887 void CellularCapabilityUniversal::OnRegisterReply(
888     const ResultCallback& callback,
889     const Error& error) {
890   SLOG(this, 3) << __func__ << "(" << error << ")";
891 
892   if (error.IsSuccess()) {
893     cellular()->set_selected_network(desired_network_);
894     desired_network_.clear();
895     callback.Run(error);
896     return;
897   }
898   // If registration on the desired network failed,
899   // try to register on the home network.
900   if (!desired_network_.empty()) {
901     desired_network_.clear();
902     cellular()->set_selected_network("");
903     LOG(INFO) << "Couldn't register on selected network, trying home network";
904     Register(callback);
905     return;
906   }
907   callback.Run(error);
908 }
909 
IsRegistered() const910 bool CellularCapabilityUniversal::IsRegistered() const {
911   return IsRegisteredState(registration_state_);
912 }
913 
IsRegisteredState(MMModem3gppRegistrationState state)914 bool CellularCapabilityUniversal::IsRegisteredState(
915     MMModem3gppRegistrationState state) {
916   return (state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
917           state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING);
918 }
919 
SetUnregistered(bool searching)920 void CellularCapabilityUniversal::SetUnregistered(bool searching) {
921   // If we're already in some non-registered state, don't override that
922   if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
923           registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) {
924     registration_state_ =
925         (searching ? MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING :
926                      MM_MODEM_3GPP_REGISTRATION_STATE_IDLE);
927   }
928 }
929 
RequirePIN(const string & pin,bool require,Error * error,const ResultCallback & callback)930 void CellularCapabilityUniversal::RequirePIN(
931     const string& pin, bool require,
932     Error* error, const ResultCallback& callback) {
933   CHECK(error);
934   sim_proxy_->EnablePin(pin, require, error, callback, kTimeoutDefault);
935 }
936 
EnterPIN(const string & pin,Error * error,const ResultCallback & callback)937 void CellularCapabilityUniversal::EnterPIN(const string& pin,
938                                            Error* error,
939                                            const ResultCallback& callback) {
940   CHECK(error);
941   SLOG(this, 3) << __func__;
942   sim_proxy_->SendPin(pin, error, callback, kEnterPinTimeoutMilliseconds);
943 }
944 
UnblockPIN(const string & unblock_code,const string & pin,Error * error,const ResultCallback & callback)945 void CellularCapabilityUniversal::UnblockPIN(const string& unblock_code,
946                                              const string& pin,
947                                              Error* error,
948                                              const ResultCallback& callback) {
949   CHECK(error);
950   sim_proxy_->SendPuk(unblock_code, pin, error, callback, kTimeoutDefault);
951 }
952 
ChangePIN(const string & old_pin,const string & new_pin,Error * error,const ResultCallback & callback)953 void CellularCapabilityUniversal::ChangePIN(
954     const string& old_pin, const string& new_pin,
955     Error* error, const ResultCallback& callback) {
956   CHECK(error);
957   sim_proxy_->ChangePin(old_pin, new_pin, error, callback, kTimeoutDefault);
958 }
959 
Reset(Error * error,const ResultCallback & callback)960 void CellularCapabilityUniversal::Reset(Error* error,
961                                         const ResultCallback& callback) {
962   SLOG(this, 3) << __func__;
963   CHECK(error);
964   if (resetting_) {
965     Error::PopulateAndLog(FROM_HERE, error, Error::kInProgress,
966                           "Already resetting");
967     return;
968   }
969   ResultCallback cb = Bind(&CellularCapabilityUniversal::OnResetReply,
970                            weak_ptr_factory_.GetWeakPtr(), callback);
971   modem_proxy_->Reset(error, cb, kTimeoutReset);
972   if (!error->IsFailure()) {
973     resetting_ = true;
974   }
975 }
976 
OnResetReply(const ResultCallback & callback,const Error & error)977 void CellularCapabilityUniversal::OnResetReply(const ResultCallback& callback,
978                                                const Error& error) {
979   SLOG(this, 3) << __func__;
980   resetting_ = false;
981   if (!callback.is_null())
982     callback.Run(error);
983 }
984 
Scan(Error * error,const ResultStringmapsCallback & callback)985 void CellularCapabilityUniversal::Scan(
986     Error* error,
987     const ResultStringmapsCallback& callback) {
988   KeyValueStoresCallback cb = Bind(&CellularCapabilityUniversal::OnScanReply,
989                                    weak_ptr_factory_.GetWeakPtr(), callback);
990   modem_3gpp_proxy_->Scan(error, cb, kTimeoutScan);
991 }
992 
OnScanReply(const ResultStringmapsCallback & callback,const ScanResults & results,const Error & error)993 void CellularCapabilityUniversal::OnScanReply(
994     const ResultStringmapsCallback& callback,
995     const ScanResults& results,
996     const Error& error) {
997   Stringmaps found_networks;
998   for (const auto& result : results)
999     found_networks.push_back(ParseScanResult(result));
1000   callback.Run(found_networks, error);
1001 }
1002 
ParseScanResult(const ScanResult & result)1003 Stringmap CellularCapabilityUniversal::ParseScanResult(
1004     const ScanResult& result) {
1005 
1006   /* ScanResults contain the following keys:
1007 
1008      "status"
1009      A MMModem3gppNetworkAvailability value representing network
1010      availability status, given as an unsigned integer (signature "u").
1011      This key will always be present.
1012 
1013      "operator-long"
1014      Long-format name of operator, given as a string value (signature
1015      "s"). If the name is unknown, this field should not be present.
1016 
1017      "operator-short"
1018      Short-format name of operator, given as a string value
1019      (signature "s"). If the name is unknown, this field should not
1020      be present.
1021 
1022      "operator-code"
1023      Mobile code of the operator, given as a string value (signature
1024      "s"). Returned in the format "MCCMNC", where MCC is the
1025      three-digit ITU E.212 Mobile Country Code and MNC is the two- or
1026      three-digit GSM Mobile Network Code. e.g. "31026" or "310260".
1027 
1028      "access-technology"
1029      A MMModemAccessTechnology value representing the generic access
1030      technology used by this mobile network, given as an unsigned
1031      integer (signature "u").
1032   */
1033   Stringmap parsed;
1034 
1035   if (result.ContainsUint(kStatusProperty)) {
1036     uint32_t status = result.GetUint(kStatusProperty);
1037     // numerical values are taken from 3GPP TS 27.007 Section 7.3.
1038     static const char* const kStatusString[] = {
1039       "unknown",    // MM_MODEM_3GPP_NETWORK_AVAILABILITY_UNKNOWN
1040       "available",  // MM_MODEM_3GPP_NETWORK_AVAILABILITY_AVAILABLE
1041       "current",    // MM_MODEM_3GPP_NETWORK_AVAILABILITY_CURRENT
1042       "forbidden",  // MM_MODEM_3GPP_NETWORK_AVAILABILITY_FORBIDDEN
1043     };
1044     parsed[kStatusProperty] = kStatusString[status];
1045   }
1046 
1047   // MMModemAccessTechnology
1048   if (result.ContainsUint(kOperatorAccessTechnologyProperty)) {
1049     parsed[kTechnologyProperty] =
1050         AccessTechnologyToString(
1051             result.GetUint(kOperatorAccessTechnologyProperty));
1052   }
1053 
1054   string operator_long, operator_short, operator_code;
1055   if (result.ContainsString(kOperatorLongProperty))
1056     parsed[kLongNameProperty] = result.GetString(kOperatorLongProperty);
1057   if (result.ContainsString(kOperatorShortProperty))
1058     parsed[kShortNameProperty] = result.GetString(kOperatorShortProperty);
1059   if (result.ContainsString(kOperatorCodeProperty))
1060     parsed[kNetworkIdProperty] = result.GetString(kOperatorCodeProperty);
1061 
1062   // If the long name is not available but the network ID is, look up the long
1063   // name in the mobile provider database.
1064   if ((!ContainsKey(parsed, kLongNameProperty) ||
1065        parsed[kLongNameProperty].empty()) &&
1066       ContainsKey(parsed, kNetworkIdProperty)) {
1067     mobile_operator_info_->Reset();
1068     mobile_operator_info_->UpdateMCCMNC(parsed[kNetworkIdProperty]);
1069     if (mobile_operator_info_->IsMobileNetworkOperatorKnown() &&
1070         !mobile_operator_info_->operator_name().empty()) {
1071       parsed[kLongNameProperty] = mobile_operator_info_->operator_name();
1072     }
1073   }
1074   return parsed;
1075 }
1076 
GetActiveBearer() const1077 CellularBearer* CellularCapabilityUniversal::GetActiveBearer() const {
1078   return active_bearer_.get();
1079 }
1080 
GetNetworkTechnologyString() const1081 string CellularCapabilityUniversal::GetNetworkTechnologyString() const {
1082   // If we know that the modem is an E362 modem supported by the Novatel LTE
1083   // plugin, return LTE here to make sure that Chrome sees LTE as the network
1084   // technology even if the actual technology is unknown.
1085   //
1086   // This hack will cause the UI to display LTE even if the modem doesn't
1087   // support it at a given time. This might be problematic if we ever want to
1088   // support switching between access technologies (e.g. falling back to 3G
1089   // when LTE is not available).
1090   if (cellular()->mm_plugin() == kNovatelLTEMMPlugin)
1091     return kNetworkTechnologyLte;
1092 
1093   // Order is important.  Return the highest speed technology
1094   // TODO(jglasgow): change shill interfaces to a capability model
1095   return AccessTechnologyToString(access_technologies_);
1096 }
1097 
GetRoamingStateString() const1098 string CellularCapabilityUniversal::GetRoamingStateString() const {
1099   switch (registration_state_) {
1100     case MM_MODEM_3GPP_REGISTRATION_STATE_HOME:
1101       return kRoamingStateHome;
1102     case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING:
1103       return kRoamingStateRoaming;
1104     default:
1105       break;
1106   }
1107   return kRoamingStateUnknown;
1108 }
1109 
1110 // TODO(armansito): Remove this method once cromo is deprecated.
GetSignalQuality()1111 void CellularCapabilityUniversal::GetSignalQuality() {
1112   // ModemManager always returns the cached value, so there is no need to
1113   // trigger an update here. The true value is updated through a property
1114   // change signal.
1115 }
1116 
GetTypeString() const1117 string CellularCapabilityUniversal::GetTypeString() const {
1118   return AccessTechnologyToTechnologyFamily(access_technologies_);
1119 }
1120 
OnModemPropertiesChanged(const KeyValueStore & properties,const vector<string> &)1121 void CellularCapabilityUniversal::OnModemPropertiesChanged(
1122     const KeyValueStore& properties,
1123     const vector<string>& /* invalidated_properties */) {
1124 
1125   // Update the bearers property before the modem state property as
1126   // OnModemStateChanged may call UpdateActiveBearer, which reads the bearers
1127   // property.
1128   if (properties.ContainsRpcIdentifiers(MM_MODEM_PROPERTY_BEARERS)) {
1129     RpcIdentifiers bearers =
1130         properties.GetRpcIdentifiers(MM_MODEM_PROPERTY_BEARERS);
1131     OnBearersChanged(bearers);
1132   }
1133 
1134   // This solves a bootstrapping problem: If the modem is not yet
1135   // enabled, there are no proxy objects associated with the capability
1136   // object, so modem signals like StateChanged aren't seen. By monitoring
1137   // changes to the State property via the ModemManager, we're able to
1138   // get the initialization process started, which will result in the
1139   // creation of the proxy objects.
1140   //
1141   // The first time we see the change to State (when the modem state
1142   // is Unknown), we simply update the state, and rely on the Manager to
1143   // enable the device when it is registered with the Manager. On subsequent
1144   // changes to State, we need to explicitly enable the device ourselves.
1145   if (properties.ContainsInt(MM_MODEM_PROPERTY_STATE)) {
1146     int32_t istate = properties.GetInt(MM_MODEM_PROPERTY_STATE);
1147     Cellular::ModemState state = static_cast<Cellular::ModemState>(istate);
1148     OnModemStateChanged(state);
1149   }
1150   if (properties.ContainsRpcIdentifier(MM_MODEM_PROPERTY_SIM))
1151     OnSimPathChanged(properties.GetRpcIdentifier(MM_MODEM_PROPERTY_SIM));
1152 
1153   if (properties.ContainsUint32s(MM_MODEM_PROPERTY_SUPPORTEDCAPABILITIES)) {
1154     OnSupportedCapabilitesChanged(
1155         properties.GetUint32s(MM_MODEM_PROPERTY_SUPPORTEDCAPABILITIES));
1156   }
1157 
1158   if (properties.ContainsUint(MM_MODEM_PROPERTY_CURRENTCAPABILITIES)) {
1159     OnModemCurrentCapabilitiesChanged(
1160         properties.GetUint(MM_MODEM_PROPERTY_CURRENTCAPABILITIES));
1161   }
1162   // not needed: MM_MODEM_PROPERTY_MAXBEARERS
1163   // not needed: MM_MODEM_PROPERTY_MAXACTIVEBEARERS
1164   if (properties.ContainsString(MM_MODEM_PROPERTY_MANUFACTURER)) {
1165     cellular()->set_manufacturer(
1166         properties.GetString(MM_MODEM_PROPERTY_MANUFACTURER));
1167   }
1168   if (properties.ContainsString(MM_MODEM_PROPERTY_MODEL)) {
1169     cellular()->set_model_id(properties.GetString(MM_MODEM_PROPERTY_MODEL));
1170   }
1171   if (properties.ContainsString(MM_MODEM_PROPERTY_PLUGIN)) {
1172     cellular()->set_mm_plugin(properties.GetString(MM_MODEM_PROPERTY_PLUGIN));
1173   }
1174   if (properties.ContainsString(MM_MODEM_PROPERTY_REVISION)) {
1175     OnModemRevisionChanged(properties.GetString(MM_MODEM_PROPERTY_REVISION));
1176   }
1177   // not needed: MM_MODEM_PROPERTY_DEVICEIDENTIFIER
1178   // not needed: MM_MODEM_PROPERTY_DEVICE
1179   // not needed: MM_MODEM_PROPERTY_DRIVER
1180   // not needed: MM_MODEM_PROPERTY_PLUGIN
1181   // not needed: MM_MODEM_PROPERTY_EQUIPMENTIDENTIFIER
1182 
1183   // Unlock required and SimLock
1184   bool lock_status_changed = false;
1185   if (properties.ContainsUint(MM_MODEM_PROPERTY_UNLOCKREQUIRED)) {
1186     uint32_t unlock_required =
1187         properties.GetUint(MM_MODEM_PROPERTY_UNLOCKREQUIRED);
1188     OnLockTypeChanged(static_cast<MMModemLock>(unlock_required));
1189     lock_status_changed = true;
1190   }
1191 
1192   // Unlock retries
1193   if (properties.Contains(MM_MODEM_PROPERTY_UNLOCKRETRIES)) {
1194     OnLockRetriesChanged(
1195         properties.Get(MM_MODEM_PROPERTY_UNLOCKRETRIES).Get<LockRetryData>());
1196     lock_status_changed = true;
1197   }
1198 
1199   if (lock_status_changed)
1200     OnSimLockStatusChanged();
1201 
1202   if (properties.ContainsUint(MM_MODEM_PROPERTY_ACCESSTECHNOLOGIES)) {
1203     OnAccessTechnologiesChanged(
1204         properties.GetUint(MM_MODEM_PROPERTY_ACCESSTECHNOLOGIES));
1205   }
1206 
1207   if (properties.Contains(MM_MODEM_PROPERTY_SIGNALQUALITY)) {
1208     SignalQuality quality =
1209         properties.Get(MM_MODEM_PROPERTY_SIGNALQUALITY).Get<SignalQuality>();
1210     OnSignalQualityChanged(std::get<0>(quality));
1211   }
1212 
1213   if (properties.ContainsStrings(MM_MODEM_PROPERTY_OWNNUMBERS)) {
1214     vector<string> numbers =
1215         properties.GetStrings(MM_MODEM_PROPERTY_OWNNUMBERS);
1216     string mdn;
1217     if (numbers.size() > 0)
1218       mdn = numbers[0];
1219     OnMdnChanged(mdn);
1220   }
1221 
1222   if (properties.Contains(MM_MODEM_PROPERTY_SUPPORTEDMODES)) {
1223     SupportedModes mm_supported_modes =
1224         properties.Get(MM_MODEM_PROPERTY_SUPPORTEDMODES).Get<SupportedModes>();
1225     vector<ModemModes> supported_modes;
1226     for (const auto& modes : mm_supported_modes) {
1227       supported_modes.push_back(
1228           ModemModes(std::get<0>(modes),
1229                      static_cast<MMModemMode>(std::get<1>(modes))));
1230     }
1231     OnSupportedModesChanged(supported_modes);
1232   }
1233 
1234   if (properties.Contains(MM_MODEM_PROPERTY_CURRENTMODES)) {
1235     ModesData current_modes =
1236         properties.Get(MM_MODEM_PROPERTY_CURRENTMODES).Get<ModesData>();
1237     OnCurrentModesChanged(
1238         ModemModes(std::get<0>(current_modes),
1239                    static_cast<MMModemMode>(std::get<1>(current_modes))));
1240   }
1241 
1242   // au: MM_MODEM_PROPERTY_SUPPORTEDBANDS,
1243   // au: MM_MODEM_PROPERTY_BANDS
1244 }
1245 
OnPropertiesChanged(const string & interface,const KeyValueStore & changed_properties,const vector<string> & invalidated_properties)1246 void CellularCapabilityUniversal::OnPropertiesChanged(
1247     const string& interface,
1248     const KeyValueStore& changed_properties,
1249     const vector<string>& invalidated_properties) {
1250   SLOG(this, 3) << __func__ << "(" << interface << ")";
1251   if (interface == MM_DBUS_INTERFACE_MODEM) {
1252     OnModemPropertiesChanged(changed_properties, invalidated_properties);
1253   }
1254   if (interface == MM_DBUS_INTERFACE_MODEM_MODEM3GPP) {
1255     OnModem3GPPPropertiesChanged(changed_properties, invalidated_properties);
1256   }
1257   if (interface == MM_DBUS_INTERFACE_SIM) {
1258     OnSimPropertiesChanged(changed_properties, invalidated_properties);
1259   }
1260 }
1261 
RetriableConnectError(const Error & error) const1262 bool CellularCapabilityUniversal::RetriableConnectError(
1263     const Error& error) const {
1264   if (error.type() == Error::kInvalidApn)
1265     return true;
1266 
1267   // ModemManager does not ever return kInvalidApn for an E362 modem (with
1268   // firmware version 1.41) supported by the Novatel LTE plugin.
1269   if ((cellular()->mm_plugin() == kNovatelLTEMMPlugin) &&
1270       (error.type() == Error::kOperationFailed)) {
1271     return true;
1272   }
1273   return false;
1274 }
1275 
OnNetworkModeSignal(uint32_t)1276 void CellularCapabilityUniversal::OnNetworkModeSignal(uint32_t /*mode*/) {
1277   // TODO(petkov): Implement this.
1278   NOTIMPLEMENTED();
1279 }
1280 
IsValidSimPath(const string & sim_path) const1281 bool CellularCapabilityUniversal::IsValidSimPath(const string& sim_path) const {
1282   return !sim_path.empty() && sim_path != kRootPath;
1283 }
1284 
NormalizeMdn(const string & mdn) const1285 string CellularCapabilityUniversal::NormalizeMdn(const string& mdn) const {
1286   string normalized_mdn;
1287   for (size_t i = 0; i < mdn.size(); ++i) {
1288     if (base::IsAsciiDigit(mdn[i]))
1289       normalized_mdn += mdn[i];
1290   }
1291   return normalized_mdn;
1292 }
1293 
OnSimPathChanged(const string & sim_path)1294 void CellularCapabilityUniversal::OnSimPathChanged(
1295     const string& sim_path) {
1296   if (sim_path == sim_path_)
1297     return;
1298 
1299   mm1::SimProxyInterface* proxy = nullptr;
1300   if (IsValidSimPath(sim_path))
1301     proxy = control_interface()->CreateSimProxy(sim_path,
1302                                                 cellular()->dbus_service());
1303   sim_path_ = sim_path;
1304   sim_proxy_.reset(proxy);
1305 
1306   if (!IsValidSimPath(sim_path)) {
1307     // Clear all data about the sim
1308     cellular()->set_imsi("");
1309     spn_ = "";
1310     cellular()->set_sim_present(false);
1311     OnSimIdentifierChanged("");
1312     OnOperatorIdChanged("");
1313     cellular()->home_provider_info()->Reset();
1314   } else {
1315     cellular()->set_sim_present(true);
1316     std::unique_ptr<DBusPropertiesProxyInterface> properties_proxy(
1317         control_interface()->CreateDBusPropertiesProxy(
1318             sim_path, cellular()->dbus_service()));
1319     // TODO(jglasgow): convert to async interface
1320     KeyValueStore properties(properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
1321     OnSimPropertiesChanged(properties, vector<string>());
1322   }
1323 }
1324 
OnSupportedCapabilitesChanged(const vector<uint32_t> & supported_capabilities)1325 void CellularCapabilityUniversal::OnSupportedCapabilitesChanged(
1326     const vector<uint32_t>& supported_capabilities) {
1327   supported_capabilities_ = supported_capabilities;
1328 }
1329 
OnModemCurrentCapabilitiesChanged(uint32_t current_capabilities)1330 void CellularCapabilityUniversal::OnModemCurrentCapabilitiesChanged(
1331     uint32_t current_capabilities) {
1332   current_capabilities_ = current_capabilities;
1333 
1334   // Only allow network scan when the modem's current capabilities support
1335   // GSM/UMTS.
1336   //
1337   // TODO(benchan): We should consider having the modem plugins in ModemManager
1338   // reporting whether network scan is supported.
1339   cellular()->set_scanning_supported(
1340       (current_capabilities & MM_MODEM_CAPABILITY_GSM_UMTS) != 0);
1341 }
1342 
OnMdnChanged(const string & mdn)1343 void CellularCapabilityUniversal::OnMdnChanged(
1344     const string& mdn) {
1345   cellular()->set_mdn(NormalizeMdn(mdn));
1346   UpdatePendingActivationState();
1347 }
1348 
OnModemRevisionChanged(const string & revision)1349 void CellularCapabilityUniversal::OnModemRevisionChanged(
1350     const string& revision) {
1351   cellular()->set_firmware_revision(revision);
1352 }
1353 
OnModemStateChanged(Cellular::ModemState state)1354 void CellularCapabilityUniversal::OnModemStateChanged(
1355     Cellular::ModemState state) {
1356   SLOG(this, 3) << __func__ << ": " << Cellular::GetModemStateString(state);
1357 
1358   if (state == Cellular::kModemStateConnected) {
1359     // This assumes that ModemManager updates the Bearers list and the Bearer
1360     // properties before changing Modem state to Connected.
1361     SLOG(this, 2) << "Update active bearer.";
1362     UpdateActiveBearer();
1363   }
1364 
1365   cellular()->OnModemStateChanged(state);
1366   // TODO(armansito): Move the deferred enable logic to Cellular
1367   // (See crbug.com/279499).
1368   if (!deferred_enable_modem_callback_.is_null() &&
1369       state == Cellular::kModemStateDisabled) {
1370     SLOG(this, 2) << "Enabling modem after deferring.";
1371     deferred_enable_modem_callback_.Run();
1372     deferred_enable_modem_callback_.Reset();
1373   }
1374 }
1375 
OnAccessTechnologiesChanged(uint32_t access_technologies)1376 void CellularCapabilityUniversal::OnAccessTechnologiesChanged(
1377     uint32_t access_technologies) {
1378   if (access_technologies_ != access_technologies) {
1379     const string old_type_string(GetTypeString());
1380     access_technologies_ = access_technologies;
1381     const string new_type_string(GetTypeString());
1382     if (new_type_string != old_type_string) {
1383       // TODO(jglasgow): address layering violation of emitting change
1384       // signal here for a property owned by Cellular.
1385       cellular()->adaptor()->EmitStringChanged(
1386           kTechnologyFamilyProperty, new_type_string);
1387     }
1388     if (cellular()->service().get()) {
1389       cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
1390     }
1391   }
1392 }
1393 
OnSupportedModesChanged(const vector<ModemModes> & supported_modes)1394 void CellularCapabilityUniversal::OnSupportedModesChanged(
1395     const vector<ModemModes>& supported_modes) {
1396   supported_modes_ = supported_modes;
1397 }
1398 
OnCurrentModesChanged(const ModemModes & current_modes)1399 void CellularCapabilityUniversal::OnCurrentModesChanged(
1400     const ModemModes& current_modes) {
1401   current_modes_ = current_modes;
1402 }
1403 
OnBearersChanged(const RpcIdentifiers & bearers)1404 void CellularCapabilityUniversal::OnBearersChanged(
1405     const RpcIdentifiers& bearers) {
1406   bearer_paths_ = bearers;
1407 }
1408 
OnLockRetriesChanged(const LockRetryData & lock_retries)1409 void CellularCapabilityUniversal::OnLockRetriesChanged(
1410     const LockRetryData& lock_retries) {
1411   SLOG(this, 3) << __func__;
1412 
1413   // Look for the retries left for the current lock. Try the obtain the count
1414   // that matches the current count. If no count for the current lock is
1415   // available, report the first one in the dictionary.
1416   LockRetryData::const_iterator it =
1417       lock_retries.find(sim_lock_status_.lock_type);
1418   if (it == lock_retries.end())
1419       it = lock_retries.begin();
1420   if (it != lock_retries.end())
1421     sim_lock_status_.retries_left = it->second;
1422   else
1423     // Unknown, use 999
1424     sim_lock_status_.retries_left = 999;
1425 }
1426 
OnLockTypeChanged(MMModemLock lock_type)1427 void CellularCapabilityUniversal::OnLockTypeChanged(
1428     MMModemLock lock_type) {
1429   SLOG(this, 3) << __func__ << ": " << lock_type;
1430   sim_lock_status_.lock_type = lock_type;
1431 
1432   // If the SIM is in a locked state |sim_lock_status_.enabled| might be false.
1433   // This is because the corresponding property 'EnabledFacilityLocks' is on
1434   // the 3GPP interface and the 3GPP interface is not available while the Modem
1435   // is in the 'LOCKED' state.
1436   if (lock_type != MM_MODEM_LOCK_NONE &&
1437       lock_type != MM_MODEM_LOCK_UNKNOWN &&
1438       !sim_lock_status_.enabled)
1439     sim_lock_status_.enabled = true;
1440 }
1441 
OnSimLockStatusChanged()1442 void CellularCapabilityUniversal::OnSimLockStatusChanged() {
1443   SLOG(this, 3) << __func__;
1444   cellular()->adaptor()->EmitKeyValueStoreChanged(
1445       kSIMLockStatusProperty, SimLockStatusToProperty(nullptr));
1446 
1447   // If the SIM is currently unlocked, assume that we need to refresh
1448   // carrier information, since a locked SIM prevents shill from obtaining
1449   // the necessary data to establish a connection later (e.g. IMSI).
1450   if (IsValidSimPath(sim_path_) &&
1451       (sim_lock_status_.lock_type == MM_MODEM_LOCK_NONE ||
1452        sim_lock_status_.lock_type == MM_MODEM_LOCK_UNKNOWN)) {
1453     std::unique_ptr<DBusPropertiesProxyInterface> properties_proxy(
1454         control_interface()->CreateDBusPropertiesProxy(
1455             sim_path_, cellular()->dbus_service()));
1456     KeyValueStore properties(
1457         properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
1458     OnSimPropertiesChanged(properties, vector<string>());
1459   }
1460 }
1461 
OnModem3GPPPropertiesChanged(const KeyValueStore & properties,const vector<string> &)1462 void CellularCapabilityUniversal::OnModem3GPPPropertiesChanged(
1463     const KeyValueStore& properties,
1464     const vector<string>& /* invalidated_properties */) {
1465   SLOG(this, 3) << __func__;
1466   if (properties.ContainsString(MM_MODEM_MODEM3GPP_PROPERTY_IMEI))
1467     cellular()->set_imei(
1468         properties.GetString(MM_MODEM_MODEM3GPP_PROPERTY_IMEI));
1469 
1470   // Handle registration state changes as a single change
1471   Stringmap::const_iterator it;
1472   string operator_code;
1473   string operator_name;
1474   it = serving_operator_.find(kOperatorCodeKey);
1475   if (it != serving_operator_.end())
1476     operator_code = it->second;
1477   it = serving_operator_.find(kOperatorNameKey);
1478   if (it != serving_operator_.end())
1479     operator_name = it->second;
1480 
1481   MMModem3gppRegistrationState state = registration_state_;
1482   bool registration_changed = false;
1483   if (properties.ContainsUint(MM_MODEM_MODEM3GPP_PROPERTY_REGISTRATIONSTATE)) {
1484     state = static_cast<MMModem3gppRegistrationState>(
1485         properties.GetUint(MM_MODEM_MODEM3GPP_PROPERTY_REGISTRATIONSTATE));
1486     registration_changed = true;
1487   }
1488   if (properties.ContainsString(MM_MODEM_MODEM3GPP_PROPERTY_OPERATORCODE)) {
1489     operator_code =
1490         properties.GetString(MM_MODEM_MODEM3GPP_PROPERTY_OPERATORCODE);
1491     registration_changed = true;
1492   }
1493   if (properties.ContainsString(MM_MODEM_MODEM3GPP_PROPERTY_OPERATORNAME)) {
1494     operator_name =
1495         properties.GetString(MM_MODEM_MODEM3GPP_PROPERTY_OPERATORNAME);
1496     registration_changed = true;
1497   }
1498   if (registration_changed)
1499     On3GPPRegistrationChanged(state, operator_code, operator_name);
1500   if (properties.ContainsUint(MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE))
1501     On3GPPSubscriptionStateChanged(
1502         static_cast<MMModem3gppSubscriptionState>(
1503             properties.GetUint(MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE)));
1504 
1505   CellularServiceRefPtr service = cellular()->service();
1506   if (service.get() &&
1507       properties.ContainsUint(MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE)) {
1508     uint32_t subscription_state =
1509         properties.GetUint(MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE);
1510     SLOG(this, 3) << __func__ << ": Subscription state = "
1511                               << subscription_state;
1512     service->out_of_credits_detector()->NotifySubscriptionStateChanged(
1513         subscription_state);
1514   }
1515 
1516   if (properties.ContainsUint(MM_MODEM_MODEM3GPP_PROPERTY_ENABLEDFACILITYLOCKS))
1517     OnFacilityLocksChanged(
1518         properties.GetUint(MM_MODEM_MODEM3GPP_PROPERTY_ENABLEDFACILITYLOCKS));
1519 }
1520 
On3GPPRegistrationChanged(MMModem3gppRegistrationState state,const string & operator_code,const string & operator_name)1521 void CellularCapabilityUniversal::On3GPPRegistrationChanged(
1522     MMModem3gppRegistrationState state,
1523     const string& operator_code,
1524     const string& operator_name) {
1525   SLOG(this, 3) << __func__ << ": regstate=" << state
1526                             << ", opercode=" << operator_code
1527                             << ", opername=" << operator_name;
1528 
1529   // While the modem is connected, if the state changed from a registered state
1530   // to a non registered state, defer the state change by 15 seconds.
1531   if (cellular()->modem_state() == Cellular::kModemStateConnected &&
1532       IsRegistered() && !IsRegisteredState(state)) {
1533     if (!registration_dropped_update_callback_.IsCancelled()) {
1534       LOG(WARNING) << "Modem reported consecutive 3GPP registration drops. "
1535                    << "Ignoring earlier notifications.";
1536       registration_dropped_update_callback_.Cancel();
1537     } else {
1538       // This is not a repeated post. So, count this instance of delayed drop
1539       // posted.
1540       modem_info()->metrics()->Notify3GPPRegistrationDelayedDropPosted();
1541     }
1542     SLOG(this, 2) << "Posted deferred registration state update";
1543     registration_dropped_update_callback_.Reset(
1544         Bind(&CellularCapabilityUniversal::Handle3GPPRegistrationChange,
1545              weak_ptr_factory_.GetWeakPtr(),
1546              state,
1547              operator_code,
1548              operator_name));
1549     cellular()->dispatcher()->PostDelayedTask(
1550         registration_dropped_update_callback_.callback(),
1551         registration_dropped_update_timeout_milliseconds_);
1552   } else {
1553     if (!registration_dropped_update_callback_.IsCancelled()) {
1554       SLOG(this, 2) << "Cancelled a deferred registration state update";
1555       registration_dropped_update_callback_.Cancel();
1556       // If we cancelled the callback here, it means we had flaky network for a
1557       // small duration.
1558       modem_info()->metrics()->Notify3GPPRegistrationDelayedDropCanceled();
1559     }
1560     Handle3GPPRegistrationChange(state, operator_code, operator_name);
1561   }
1562 }
1563 
Handle3GPPRegistrationChange(MMModem3gppRegistrationState updated_state,string updated_operator_code,string updated_operator_name)1564 void CellularCapabilityUniversal::Handle3GPPRegistrationChange(
1565     MMModem3gppRegistrationState updated_state,
1566     string updated_operator_code,
1567     string updated_operator_name) {
1568   // A finished callback does not qualify as a canceled callback.
1569   // We test for a canceled callback to check for outstanding callbacks.
1570   // So, explicitly cancel the callback here.
1571   registration_dropped_update_callback_.Cancel();
1572 
1573   SLOG(this, 3) << __func__ << ": regstate=" << updated_state
1574                             << ", opercode=" << updated_operator_code
1575                             << ", opername=" << updated_operator_name;
1576 
1577   registration_state_ = updated_state;
1578   serving_operator_[kOperatorCodeKey] = updated_operator_code;
1579   serving_operator_[kOperatorNameKey] = updated_operator_name;
1580   cellular()->serving_operator_info()->UpdateMCCMNC(updated_operator_code);
1581   cellular()->serving_operator_info()->UpdateOperatorName(
1582       updated_operator_name);
1583 
1584   cellular()->HandleNewRegistrationState();
1585 
1586   // If the modem registered with the network and the current ICCID is pending
1587   // activation, then reset the modem.
1588   UpdatePendingActivationState();
1589 }
1590 
On3GPPSubscriptionStateChanged(MMModem3gppSubscriptionState updated_state)1591 void CellularCapabilityUniversal::On3GPPSubscriptionStateChanged(
1592     MMModem3gppSubscriptionState updated_state) {
1593   SLOG(this, 3) << __func__ << ": Updated subscription state = "
1594                             << updated_state;
1595 
1596   // A one-to-one enum mapping.
1597   SubscriptionState new_subscription_state;
1598   switch (updated_state) {
1599     case MM_MODEM_3GPP_SUBSCRIPTION_STATE_UNKNOWN:
1600       new_subscription_state = kSubscriptionStateUnknown;
1601       break;
1602     case MM_MODEM_3GPP_SUBSCRIPTION_STATE_PROVISIONED:
1603       new_subscription_state = kSubscriptionStateProvisioned;
1604       break;
1605     case MM_MODEM_3GPP_SUBSCRIPTION_STATE_UNPROVISIONED:
1606       new_subscription_state = kSubscriptionStateUnprovisioned;
1607       break;
1608     case MM_MODEM_3GPP_SUBSCRIPTION_STATE_OUT_OF_DATA:
1609       new_subscription_state = kSubscriptionStateOutOfData;
1610       break;
1611     default:
1612       LOG(ERROR) << "Unrecognized MMModem3gppSubscriptionState: "
1613                  << updated_state;
1614       new_subscription_state = kSubscriptionStateUnknown;
1615       return;
1616   }
1617   if (new_subscription_state == subscription_state_)
1618     return;
1619 
1620   subscription_state_ = new_subscription_state;
1621 
1622   UpdateServiceActivationState();
1623   UpdatePendingActivationState();
1624 }
1625 
OnModemStateChangedSignal(int32_t old_state,int32_t new_state,uint32_t reason)1626 void CellularCapabilityUniversal::OnModemStateChangedSignal(
1627     int32_t old_state, int32_t new_state, uint32_t reason) {
1628   Cellular::ModemState old_modem_state =
1629       static_cast<Cellular::ModemState>(old_state);
1630   Cellular::ModemState new_modem_state =
1631       static_cast<Cellular::ModemState>(new_state);
1632   SLOG(this, 3) << __func__ << "("
1633                             << Cellular::GetModemStateString(old_modem_state)
1634                             << ", "
1635                             << Cellular::GetModemStateString(new_modem_state)
1636                             << ", "
1637                             << reason << ")";
1638 }
1639 
OnSignalQualityChanged(uint32_t quality)1640 void CellularCapabilityUniversal::OnSignalQualityChanged(uint32_t quality) {
1641   cellular()->HandleNewSignalQuality(quality);
1642 }
1643 
OnFacilityLocksChanged(uint32_t locks)1644 void CellularCapabilityUniversal::OnFacilityLocksChanged(uint32_t locks) {
1645   bool sim_enabled = !!(locks & MM_MODEM_3GPP_FACILITY_SIM);
1646   if (sim_lock_status_.enabled != sim_enabled) {
1647     sim_lock_status_.enabled = sim_enabled;
1648     OnSimLockStatusChanged();
1649   }
1650 }
1651 
OnSimPropertiesChanged(const KeyValueStore & props,const vector<string> &)1652 void CellularCapabilityUniversal::OnSimPropertiesChanged(
1653     const KeyValueStore& props,
1654     const vector<string>& /* invalidated_properties */) {
1655   SLOG(this, 3) << __func__;
1656   if (props.ContainsString(MM_SIM_PROPERTY_SIMIDENTIFIER))
1657     OnSimIdentifierChanged(props.GetString(MM_SIM_PROPERTY_SIMIDENTIFIER));
1658   if (props.ContainsString(MM_SIM_PROPERTY_OPERATORIDENTIFIER))
1659     OnOperatorIdChanged(props.GetString(MM_SIM_PROPERTY_OPERATORIDENTIFIER));
1660   if (props.ContainsString(MM_SIM_PROPERTY_OPERATORNAME))
1661     OnSpnChanged(props.GetString(MM_SIM_PROPERTY_OPERATORNAME));
1662   if (props.ContainsString(MM_SIM_PROPERTY_IMSI)) {
1663     string imsi = props.GetString(MM_SIM_PROPERTY_IMSI);
1664     cellular()->set_imsi(imsi);
1665     cellular()->home_provider_info()->UpdateIMSI(imsi);
1666     // We do not obtain IMSI OTA right now. Provide the value from the SIM to
1667     // serving operator as well, to aid in MVNO identification.
1668     cellular()->serving_operator_info()->UpdateIMSI(imsi);
1669   }
1670 }
1671 
OnSpnChanged(const std::string & spn)1672 void CellularCapabilityUniversal::OnSpnChanged(const std::string& spn) {
1673   spn_ = spn;
1674   cellular()->home_provider_info()->UpdateOperatorName(spn);
1675 }
1676 
OnSimIdentifierChanged(const string & id)1677 void CellularCapabilityUniversal::OnSimIdentifierChanged(const string& id) {
1678   cellular()->set_sim_identifier(id);
1679   cellular()->home_provider_info()->UpdateICCID(id);
1680   // Provide ICCID to serving operator as well to aid in MVNO identification.
1681   cellular()->serving_operator_info()->UpdateICCID(id);
1682   UpdatePendingActivationState();
1683 }
1684 
OnOperatorIdChanged(const string & operator_id)1685 void CellularCapabilityUniversal::OnOperatorIdChanged(
1686     const string& operator_id) {
1687   SLOG(this, 2) << "Operator ID = '" << operator_id << "'";
1688   cellular()->home_provider_info()->UpdateMCCMNC(operator_id);
1689 }
1690 
1691 OutOfCreditsDetector::OOCType
GetOutOfCreditsDetectionType() const1692 CellularCapabilityUniversal::GetOutOfCreditsDetectionType() const {
1693   if (cellular()->mm_plugin() == kAltairLTEMMPlugin) {
1694     return OutOfCreditsDetector::OOCTypeSubscriptionState;
1695   } else {
1696     return OutOfCreditsDetector::OOCTypeNone;
1697   }
1698 }
1699 
1700 }  // namespace shill
1701