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