cellular_capability_universal.cc revision 34f424e672439bdf237a755f85245ebd7b66e8e2
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/dbus_properties_proxy_interface.h"
22#include "shill/error.h"
23#include "shill/logging.h"
24#include "shill/pending_activation_store.h"
25#include "shill/property_accessor.h"
26#include "shill/proxy_factory.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    ProxyFactory *proxy_factory,
136    ModemInfo *modem_info)
137    : CellularCapability(cellular, proxy_factory, 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      proxy_factory()->CreateMM1ModemModem3gppProxy(cellular()->dbus_path(),
192                                                    cellular()->dbus_owner()));
193  modem_proxy_.reset(
194      proxy_factory()->CreateMM1ModemProxy(cellular()->dbus_path(),
195                                           cellular()->dbus_owner()));
196  modem_simple_proxy_.reset(
197      proxy_factory()->CreateMM1ModemSimpleProxy(cellular()->dbus_path(),
198                                                 cellular()->dbus_owner()));
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 DBusPropertiesMap &properties,
410                                          Error *error,
411                                          const ResultCallback &callback) {
412  SLOG(this, 3) << __func__;
413  DBusPathCallback 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(DBus::Path(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    DBusPropertiesMap *properties) {
660  SetupApnTryList();
661  FillConnectPropertyMap(properties);
662}
663
664void CellularCapabilityUniversal::FillConnectPropertyMap(
665    DBusPropertiesMap *properties) {
666
667  // TODO(jglasgow): Is this really needed anymore?
668  (*properties)[kConnectNumber].writer().append_string(
669      kPhoneNumber);
670
671  (*properties)[kConnectAllowRoaming].writer().append_bool(
672      AllowRoaming());
673
674  if (!apn_try_list_.empty()) {
675    // Leave the APN at the front of the list, so that it can be recorded
676    // if the connect attempt succeeds.
677    Stringmap apn_info = apn_try_list_.front();
678    SLOG(this, 2) << __func__ << ": Using APN " << apn_info[kApnProperty];
679    (*properties)[kConnectApn].writer().append_string(
680        apn_info[kApnProperty].c_str());
681    if (ContainsKey(apn_info, kApnUsernameProperty))
682      (*properties)[kConnectUser].writer().append_string(
683          apn_info[kApnUsernameProperty].c_str());
684    if (ContainsKey(apn_info, kApnPasswordProperty))
685      (*properties)[kConnectPassword].writer().append_string(
686          apn_info[kApnPasswordProperty].c_str());
687  }
688}
689
690void CellularCapabilityUniversal::OnConnectReply(const ResultCallback &callback,
691                                                 const DBus::Path &path,
692                                                 const Error &error) {
693  SLOG(this, 3) << __func__ << "(" << error << ")";
694
695  CellularServiceRefPtr service = cellular()->service();
696  if (!service) {
697    // The service could have been deleted before our Connect() request
698    // completes if the modem was enabled and then quickly disabled.
699    apn_try_list_.clear();
700  } else if (error.IsFailure()) {
701    service->ClearLastGoodApn();
702    // The APN that was just tried (and failed) is still at the
703    // front of the list, about to be removed. If the list is empty
704    // after that, try one last time without an APN. This may succeed
705    // with some modems in some cases.
706    if (RetriableConnectError(error) && !apn_try_list_.empty()) {
707      apn_try_list_.pop_front();
708      SLOG(this, 2) << "Connect failed with invalid APN, "
709                    << apn_try_list_.size() << " remaining APNs to try";
710      DBusPropertiesMap props;
711      FillConnectPropertyMap(&props);
712      Error error;
713      Connect(props, &error, callback);
714      return;
715    }
716  } else {
717    if (!apn_try_list_.empty()) {
718      service->SetLastGoodApn(apn_try_list_.front());
719      apn_try_list_.clear();
720    }
721    SLOG(this, 2) << "Connected bearer " << path;
722  }
723
724  if (!callback.is_null())
725    callback.Run(error);
726
727  UpdatePendingActivationState();
728}
729
730bool CellularCapabilityUniversal::AllowRoaming() {
731  return cellular()->provider_requires_roaming() || allow_roaming_property();
732}
733
734void CellularCapabilityUniversal::GetProperties() {
735  SLOG(this, 3) << __func__;
736
737  std::unique_ptr<DBusPropertiesProxyInterface> properties_proxy(
738      proxy_factory()->CreateDBusPropertiesProxy(cellular()->dbus_path(),
739                                                 cellular()->dbus_owner()));
740  DBusPropertiesMap properties(
741      properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM));
742  OnModemPropertiesChanged(properties, vector<string>());
743
744  properties = properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM_MODEM3GPP);
745  OnModem3GPPPropertiesChanged(properties, vector<string>());
746}
747
748void CellularCapabilityUniversal::UpdateServiceOLP() {
749  SLOG(this, 3) << __func__;
750
751  // OLP is based off of the Home Provider.
752  if (!cellular()->home_provider_info()->IsMobileNetworkOperatorKnown()) {
753    return;
754  }
755
756  const vector<MobileOperatorInfo::OnlinePortal> &olp_list =
757      cellular()->home_provider_info()->olp_list();
758  if (olp_list.empty()) {
759    return;
760  }
761
762  if (olp_list.size() > 1) {
763    SLOG(this, 1) << "Found multiple online portals. Choosing the first.";
764  }
765  string post_data = olp_list[0].post_data;
766  ReplaceSubstringsAfterOffset(&post_data, 0, "${iccid}",
767                               cellular()->sim_identifier());
768  ReplaceSubstringsAfterOffset(&post_data, 0, "${imei}", cellular()->imei());
769  ReplaceSubstringsAfterOffset(&post_data, 0, "${imsi}", cellular()->imsi());
770  ReplaceSubstringsAfterOffset(&post_data, 0, "${mdn}",
771                               GetMdnForOLP(cellular()->home_provider_info()));
772  ReplaceSubstringsAfterOffset(&post_data, 0, "${min}", cellular()->min());
773  cellular()->service()->SetOLP(olp_list[0].url, olp_list[0].method, post_data);
774}
775
776void CellularCapabilityUniversal::UpdateActiveBearer() {
777  SLOG(this, 3) << __func__;
778
779  // Look for the first active bearer and use its path as the connected
780  // one. Right now, we don't allow more than one active bearer.
781  active_bearer_.reset();
782  for (const auto &path : bearer_paths_) {
783    std::unique_ptr<CellularBearer> bearer(
784        new CellularBearer(proxy_factory(), path, cellular()->dbus_service()));
785    // The bearer object may have vanished before ModemManager updates the
786    // 'Bearers' property.
787    if (!bearer->Init())
788      continue;
789
790    if (!bearer->connected())
791      continue;
792
793    SLOG(this, 2) << "Found active bearer \"" << path << "\".";
794    CHECK(!active_bearer_) << "Found more than one active bearer.";
795    active_bearer_ = std::move(bearer);
796  }
797
798  if (!active_bearer_)
799    SLOG(this, 2) << "No active bearer found.";
800}
801
802bool CellularCapabilityUniversal::IsServiceActivationRequired() const {
803  const string &sim_identifier = cellular()->sim_identifier();
804  // subscription_state_ is the definitive answer. If that does not work,
805  // fallback on MDN based logic.
806  if (subscription_state_ == kSubscriptionStateProvisioned ||
807      subscription_state_ == kSubscriptionStateOutOfData)
808    return false;
809
810  // We are in the process of activating, ignore all other clues from the
811  // network and use our own knowledge about the activation state.
812  if (!sim_identifier.empty() &&
813      modem_info()->pending_activation_store()->GetActivationState(
814          PendingActivationStore::kIdentifierICCID,
815          sim_identifier) != PendingActivationStore::kStateUnknown)
816    return false;
817
818  // Network notification that the service needs to be activated.
819  if (subscription_state_ == kSubscriptionStateUnprovisioned)
820    return true;
821
822  // If there is no online payment portal information, it's safer to assume
823  // the service does not require activation.
824  if (!cellular()->home_provider_info()->IsMobileNetworkOperatorKnown() ||
825      cellular()->home_provider_info()->olp_list().empty()) {
826    return false;
827  }
828
829  // If the MDN is invalid (i.e. empty or contains only zeros), the service
830  // requires activation.
831  return !IsMdnValid();
832}
833
834bool CellularCapabilityUniversal::IsMdnValid() const {
835  const string &mdn = cellular()->mdn();
836  // Note that |mdn| is normalized to contain only digits in OnMdnChanged().
837  for (size_t i = 0; i < mdn.size(); ++i) {
838    if (mdn[i] != '0')
839      return true;
840  }
841  return false;
842}
843
844// always called from an async context
845void CellularCapabilityUniversal::Register(const ResultCallback &callback) {
846  SLOG(this, 3) << __func__ << " \"" << cellular()->selected_network()
847                            << "\"";
848  CHECK(!callback.is_null());
849  Error error;
850  ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
851                                weak_ptr_factory_.GetWeakPtr(), callback);
852  modem_3gpp_proxy_->Register(cellular()->selected_network(), &error, cb,
853                              kTimeoutRegister);
854  if (error.IsFailure())
855    callback.Run(error);
856}
857
858void CellularCapabilityUniversal::RegisterOnNetwork(
859    const string &network_id,
860    Error *error,
861    const ResultCallback &callback) {
862  SLOG(this, 3) << __func__ << "(" << network_id << ")";
863  CHECK(error);
864  desired_network_ = network_id;
865  ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
866                                weak_ptr_factory_.GetWeakPtr(), callback);
867  modem_3gpp_proxy_->Register(network_id, error, cb, kTimeoutRegister);
868}
869
870void CellularCapabilityUniversal::OnRegisterReply(
871    const ResultCallback &callback,
872    const Error &error) {
873  SLOG(this, 3) << __func__ << "(" << error << ")";
874
875  if (error.IsSuccess()) {
876    cellular()->set_selected_network(desired_network_);
877    desired_network_.clear();
878    callback.Run(error);
879    return;
880  }
881  // If registration on the desired network failed,
882  // try to register on the home network.
883  if (!desired_network_.empty()) {
884    desired_network_.clear();
885    cellular()->set_selected_network("");
886    LOG(INFO) << "Couldn't register on selected network, trying home network";
887    Register(callback);
888    return;
889  }
890  callback.Run(error);
891}
892
893bool CellularCapabilityUniversal::IsRegistered() const {
894  return IsRegisteredState(registration_state_);
895}
896
897bool CellularCapabilityUniversal::IsRegisteredState(
898    MMModem3gppRegistrationState state) {
899  return (state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
900          state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING);
901}
902
903void CellularCapabilityUniversal::SetUnregistered(bool searching) {
904  // If we're already in some non-registered state, don't override that
905  if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
906          registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) {
907    registration_state_ =
908        (searching ? MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING :
909                     MM_MODEM_3GPP_REGISTRATION_STATE_IDLE);
910  }
911}
912
913void CellularCapabilityUniversal::RequirePIN(
914    const string &pin, bool require,
915    Error *error, const ResultCallback &callback) {
916  CHECK(error);
917  sim_proxy_->EnablePin(pin, require, error, callback, kTimeoutDefault);
918}
919
920void CellularCapabilityUniversal::EnterPIN(const string &pin,
921                                           Error *error,
922                                           const ResultCallback &callback) {
923  CHECK(error);
924  SLOG(this, 3) << __func__;
925  sim_proxy_->SendPin(pin, error, callback, kEnterPinTimeoutMilliseconds);
926}
927
928void CellularCapabilityUniversal::UnblockPIN(const string &unblock_code,
929                                             const string &pin,
930                                             Error *error,
931                                             const ResultCallback &callback) {
932  CHECK(error);
933  sim_proxy_->SendPuk(unblock_code, pin, error, callback, kTimeoutDefault);
934}
935
936void CellularCapabilityUniversal::ChangePIN(
937    const string &old_pin, const string &new_pin,
938    Error *error, const ResultCallback &callback) {
939  CHECK(error);
940  sim_proxy_->ChangePin(old_pin, new_pin, error, callback, kTimeoutDefault);
941}
942
943void CellularCapabilityUniversal::Reset(Error *error,
944                                        const ResultCallback &callback) {
945  SLOG(this, 3) << __func__;
946  CHECK(error);
947  if (resetting_) {
948    Error::PopulateAndLog(FROM_HERE, error, Error::kInProgress,
949                          "Already resetting");
950    return;
951  }
952  ResultCallback cb = Bind(&CellularCapabilityUniversal::OnResetReply,
953                           weak_ptr_factory_.GetWeakPtr(), callback);
954  modem_proxy_->Reset(error, cb, kTimeoutReset);
955  if (!error->IsFailure()) {
956    resetting_ = true;
957  }
958}
959
960void CellularCapabilityUniversal::OnResetReply(const ResultCallback &callback,
961                                               const Error &error) {
962  SLOG(this, 3) << __func__;
963  resetting_ = false;
964  if (!callback.is_null())
965    callback.Run(error);
966}
967
968void CellularCapabilityUniversal::Scan(
969    Error *error,
970    const ResultStringmapsCallback &callback) {
971  DBusPropertyMapsCallback cb = Bind(&CellularCapabilityUniversal::OnScanReply,
972                                     weak_ptr_factory_.GetWeakPtr(), callback);
973  modem_3gpp_proxy_->Scan(error, cb, kTimeoutScan);
974}
975
976void CellularCapabilityUniversal::OnScanReply(
977    const ResultStringmapsCallback &callback,
978    const ScanResults &results,
979    const Error &error) {
980  Stringmaps found_networks;
981  for (const auto &result : results)
982    found_networks.push_back(ParseScanResult(result));
983  callback.Run(found_networks, error);
984}
985
986Stringmap CellularCapabilityUniversal::ParseScanResult(
987    const ScanResult &result) {
988
989  /* ScanResults contain the following keys:
990
991     "status"
992     A MMModem3gppNetworkAvailability value representing network
993     availability status, given as an unsigned integer (signature "u").
994     This key will always be present.
995
996     "operator-long"
997     Long-format name of operator, given as a string value (signature
998     "s"). If the name is unknown, this field should not be present.
999
1000     "operator-short"
1001     Short-format name of operator, given as a string value
1002     (signature "s"). If the name is unknown, this field should not
1003     be present.
1004
1005     "operator-code"
1006     Mobile code of the operator, given as a string value (signature
1007     "s"). Returned in the format "MCCMNC", where MCC is the
1008     three-digit ITU E.212 Mobile Country Code and MNC is the two- or
1009     three-digit GSM Mobile Network Code. e.g. "31026" or "310260".
1010
1011     "access-technology"
1012     A MMModemAccessTechnology value representing the generic access
1013     technology used by this mobile network, given as an unsigned
1014     integer (signature "u").
1015  */
1016  Stringmap parsed;
1017
1018  uint32_t status;
1019  if (DBusProperties::GetUint32(result, kStatusProperty, &status)) {
1020    // numerical values are taken from 3GPP TS 27.007 Section 7.3.
1021    static const char * const kStatusString[] = {
1022      "unknown",    // MM_MODEM_3GPP_NETWORK_AVAILABILITY_UNKNOWN
1023      "available",  // MM_MODEM_3GPP_NETWORK_AVAILABILITY_AVAILABLE
1024      "current",    // MM_MODEM_3GPP_NETWORK_AVAILABILITY_CURRENT
1025      "forbidden",  // MM_MODEM_3GPP_NETWORK_AVAILABILITY_FORBIDDEN
1026    };
1027    parsed[kStatusProperty] = kStatusString[status];
1028  }
1029
1030  uint32_t tech;  // MMModemAccessTechnology
1031  if (DBusProperties::GetUint32(result, kOperatorAccessTechnologyProperty,
1032                                &tech)) {
1033    parsed[kTechnologyProperty] = AccessTechnologyToString(tech);
1034  }
1035
1036  string operator_long, operator_short, operator_code;
1037  if (DBusProperties::GetString(result, kOperatorLongProperty, &operator_long))
1038    parsed[kLongNameProperty] = operator_long;
1039  if (DBusProperties::GetString(result, kOperatorShortProperty,
1040                                &operator_short))
1041    parsed[kShortNameProperty] = operator_short;
1042  if (DBusProperties::GetString(result, kOperatorCodeProperty, &operator_code))
1043    parsed[kNetworkIdProperty] = operator_code;
1044
1045  // If the long name is not available but the network ID is, look up the long
1046  // name in the mobile provider database.
1047  if ((!ContainsKey(parsed, kLongNameProperty) ||
1048       parsed[kLongNameProperty].empty()) &&
1049      ContainsKey(parsed, kNetworkIdProperty)) {
1050    mobile_operator_info_->Reset();
1051    mobile_operator_info_->UpdateMCCMNC(parsed[kNetworkIdProperty]);
1052    if (mobile_operator_info_->IsMobileNetworkOperatorKnown() &&
1053        !mobile_operator_info_->operator_name().empty()) {
1054      parsed[kLongNameProperty] = mobile_operator_info_->operator_name();
1055    }
1056  }
1057  return parsed;
1058}
1059
1060CellularBearer *CellularCapabilityUniversal::GetActiveBearer() const {
1061  return active_bearer_.get();
1062}
1063
1064string CellularCapabilityUniversal::GetNetworkTechnologyString() const {
1065  // If we know that the modem is an E362 modem supported by the Novatel LTE
1066  // plugin, return LTE here to make sure that Chrome sees LTE as the network
1067  // technology even if the actual technology is unknown.
1068  //
1069  // This hack will cause the UI to display LTE even if the modem doesn't
1070  // support it at a given time. This might be problematic if we ever want to
1071  // support switching between access technologies (e.g. falling back to 3G
1072  // when LTE is not available).
1073  if (cellular()->mm_plugin() == kNovatelLTEMMPlugin)
1074    return kNetworkTechnologyLte;
1075
1076  // Order is important.  Return the highest speed technology
1077  // TODO(jglasgow): change shill interfaces to a capability model
1078  return AccessTechnologyToString(access_technologies_);
1079}
1080
1081string CellularCapabilityUniversal::GetRoamingStateString() const {
1082  switch (registration_state_) {
1083    case MM_MODEM_3GPP_REGISTRATION_STATE_HOME:
1084      return kRoamingStateHome;
1085    case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING:
1086      return kRoamingStateRoaming;
1087    default:
1088      break;
1089  }
1090  return kRoamingStateUnknown;
1091}
1092
1093// TODO(armansito): Remove this method once cromo is deprecated.
1094void CellularCapabilityUniversal::GetSignalQuality() {
1095  // ModemManager always returns the cached value, so there is no need to
1096  // trigger an update here. The true value is updated through a property
1097  // change signal.
1098}
1099
1100string CellularCapabilityUniversal::GetTypeString() const {
1101  return AccessTechnologyToTechnologyFamily(access_technologies_);
1102}
1103
1104void CellularCapabilityUniversal::OnModemPropertiesChanged(
1105    const DBusPropertiesMap &properties,
1106    const vector<string> &/* invalidated_properties */) {
1107
1108  // Update the bearers property before the modem state property as
1109  // OnModemStateChanged may call UpdateActiveBearer, which reads the bearers
1110  // property.
1111  RpcIdentifiers bearers;
1112  if (DBusProperties::GetRpcIdentifiers(properties, MM_MODEM_PROPERTY_BEARERS,
1113                                        &bearers)) {
1114    OnBearersChanged(bearers);
1115  }
1116
1117  // This solves a bootstrapping problem: If the modem is not yet
1118  // enabled, there are no proxy objects associated with the capability
1119  // object, so modem signals like StateChanged aren't seen. By monitoring
1120  // changes to the State property via the ModemManager, we're able to
1121  // get the initialization process started, which will result in the
1122  // creation of the proxy objects.
1123  //
1124  // The first time we see the change to State (when the modem state
1125  // is Unknown), we simply update the state, and rely on the Manager to
1126  // enable the device when it is registered with the Manager. On subsequent
1127  // changes to State, we need to explicitly enable the device ourselves.
1128  int32_t istate;
1129  if (DBusProperties::GetInt32(properties, MM_MODEM_PROPERTY_STATE, &istate)) {
1130    Cellular::ModemState state = static_cast<Cellular::ModemState>(istate);
1131    OnModemStateChanged(state);
1132  }
1133  DBus::Path object_path_value;
1134  if (DBusProperties::GetObjectPath(properties,
1135                                    MM_MODEM_PROPERTY_SIM, &object_path_value))
1136    OnSimPathChanged(object_path_value);
1137
1138  DBusPropertiesMap::const_iterator it =
1139      properties.find(MM_MODEM_PROPERTY_SUPPORTEDCAPABILITIES);
1140  if (it != properties.end()) {
1141    const vector<uint32_t> &supported_capabilities = it->second;
1142    OnSupportedCapabilitesChanged(supported_capabilities);
1143  }
1144
1145  uint32_t uint_value;
1146  if (DBusProperties::GetUint32(properties,
1147                                MM_MODEM_PROPERTY_CURRENTCAPABILITIES,
1148                                &uint_value))
1149    OnModemCurrentCapabilitiesChanged(uint_value);
1150  // not needed: MM_MODEM_PROPERTY_MAXBEARERS
1151  // not needed: MM_MODEM_PROPERTY_MAXACTIVEBEARERS
1152  string string_value;
1153  if (DBusProperties::GetString(properties,
1154                                MM_MODEM_PROPERTY_MANUFACTURER,
1155                                &string_value))
1156    cellular()->set_manufacturer(string_value);
1157  if (DBusProperties::GetString(properties,
1158                                MM_MODEM_PROPERTY_MODEL,
1159                                &string_value))
1160    cellular()->set_model_id(string_value);
1161  if (DBusProperties::GetString(properties,
1162                                MM_MODEM_PROPERTY_PLUGIN,
1163                                &string_value))
1164    cellular()->set_mm_plugin(string_value);
1165  if (DBusProperties::GetString(properties,
1166                               MM_MODEM_PROPERTY_REVISION,
1167                               &string_value))
1168    OnModemRevisionChanged(string_value);
1169  // not needed: MM_MODEM_PROPERTY_DEVICEIDENTIFIER
1170  // not needed: MM_MODEM_PROPERTY_DEVICE
1171  // not needed: MM_MODEM_PROPERTY_DRIVER
1172  // not needed: MM_MODEM_PROPERTY_PLUGIN
1173  // not needed: MM_MODEM_PROPERTY_EQUIPMENTIDENTIFIER
1174
1175  // Unlock required and SimLock
1176  uint32_t unlock_required;  // This is really of type MMModemLock
1177  bool lock_status_changed = false;
1178  if (DBusProperties::GetUint32(properties,
1179                                MM_MODEM_PROPERTY_UNLOCKREQUIRED,
1180                                &unlock_required)) {
1181    OnLockTypeChanged(static_cast<MMModemLock>(unlock_required));
1182    lock_status_changed = true;
1183  }
1184
1185  // Unlock retries
1186  it = properties.find(MM_MODEM_PROPERTY_UNLOCKRETRIES);
1187  if (it != properties.end()) {
1188    LockRetryData lock_retries = it->second.operator LockRetryData();
1189    OnLockRetriesChanged(lock_retries);
1190    lock_status_changed = true;
1191  }
1192
1193  if (lock_status_changed)
1194    OnSimLockStatusChanged();
1195
1196  if (DBusProperties::GetUint32(properties,
1197                                MM_MODEM_PROPERTY_ACCESSTECHNOLOGIES,
1198                                &uint_value))
1199    OnAccessTechnologiesChanged(uint_value);
1200
1201  it = properties.find(MM_MODEM_PROPERTY_SIGNALQUALITY);
1202  if (it != properties.end()) {
1203    DBus::Struct<unsigned int, bool> quality = it->second;
1204    OnSignalQualityChanged(quality._1);
1205  }
1206  vector<string> numbers;
1207  if (DBusProperties::GetStrings(properties, MM_MODEM_PROPERTY_OWNNUMBERS,
1208                                 &numbers)) {
1209    string mdn;
1210    if (numbers.size() > 0)
1211      mdn = numbers[0];
1212    OnMdnChanged(mdn);
1213  }
1214
1215  it = properties.find(MM_MODEM_PROPERTY_SUPPORTEDMODES);
1216  if (it != properties.end()) {
1217    const vector<DBus::Struct<uint32_t, uint32_t>> &mm_supported_modes =
1218        it->second;
1219    vector<ModemModes> supported_modes;
1220    for (const auto &modes : mm_supported_modes) {
1221      supported_modes.push_back(
1222          ModemModes(modes._1, static_cast<MMModemMode>(modes._2)));
1223    }
1224    OnSupportedModesChanged(supported_modes);
1225  }
1226
1227  it = properties.find(MM_MODEM_PROPERTY_CURRENTMODES);
1228  if (it != properties.end()) {
1229    const DBus::Struct<uint32_t, uint32_t> &current_modes = it->second;
1230    OnCurrentModesChanged(ModemModes(
1231        current_modes._1, static_cast<MMModemMode>(current_modes._2)));
1232  }
1233
1234  // au: MM_MODEM_PROPERTY_SUPPORTEDBANDS,
1235  // au: MM_MODEM_PROPERTY_BANDS
1236}
1237
1238void CellularCapabilityUniversal::OnDBusPropertiesChanged(
1239    const string &interface,
1240    const DBusPropertiesMap &changed_properties,
1241    const vector<string> &invalidated_properties) {
1242  SLOG(this, 3) << __func__ << "(" << interface << ")";
1243  if (interface == MM_DBUS_INTERFACE_MODEM) {
1244    OnModemPropertiesChanged(changed_properties, invalidated_properties);
1245  }
1246  if (interface == MM_DBUS_INTERFACE_MODEM_MODEM3GPP) {
1247    OnModem3GPPPropertiesChanged(changed_properties, invalidated_properties);
1248  }
1249  if (interface == MM_DBUS_INTERFACE_SIM) {
1250    OnSimPropertiesChanged(changed_properties, invalidated_properties);
1251  }
1252}
1253
1254bool CellularCapabilityUniversal::RetriableConnectError(
1255    const Error &error) const {
1256  if (error.type() == Error::kInvalidApn)
1257    return true;
1258
1259  // ModemManager does not ever return kInvalidApn for an E362 modem (with
1260  // firmware version 1.41) supported by the Novatel LTE plugin.
1261  if ((cellular()->mm_plugin() == kNovatelLTEMMPlugin) &&
1262      (error.type() == Error::kOperationFailed)) {
1263    return true;
1264  }
1265  return false;
1266}
1267
1268void CellularCapabilityUniversal::OnNetworkModeSignal(uint32_t /*mode*/) {
1269  // TODO(petkov): Implement this.
1270  NOTIMPLEMENTED();
1271}
1272
1273bool CellularCapabilityUniversal::IsValidSimPath(const string &sim_path) const {
1274  return !sim_path.empty() && sim_path != kRootPath;
1275}
1276
1277string CellularCapabilityUniversal::NormalizeMdn(const string &mdn) const {
1278  string normalized_mdn;
1279  for (size_t i = 0; i < mdn.size(); ++i) {
1280    if (IsAsciiDigit(mdn[i]))
1281      normalized_mdn += mdn[i];
1282  }
1283  return normalized_mdn;
1284}
1285
1286void CellularCapabilityUniversal::OnSimPathChanged(
1287    const string &sim_path) {
1288  if (sim_path == sim_path_)
1289    return;
1290
1291  mm1::SimProxyInterface *proxy = nullptr;
1292  if (IsValidSimPath(sim_path))
1293    proxy = proxy_factory()->CreateSimProxy(sim_path,
1294                                            cellular()->dbus_owner());
1295  sim_path_ = sim_path;
1296  sim_proxy_.reset(proxy);
1297
1298  if (!IsValidSimPath(sim_path)) {
1299    // Clear all data about the sim
1300    cellular()->set_imsi("");
1301    spn_ = "";
1302    cellular()->set_sim_present(false);
1303    OnSimIdentifierChanged("");
1304    OnOperatorIdChanged("");
1305    cellular()->home_provider_info()->Reset();
1306  } else {
1307    cellular()->set_sim_present(true);
1308    std::unique_ptr<DBusPropertiesProxyInterface> properties_proxy(
1309        proxy_factory()->CreateDBusPropertiesProxy(sim_path,
1310                                                   cellular()->dbus_owner()));
1311    // TODO(jglasgow): convert to async interface
1312    DBusPropertiesMap properties(
1313        properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
1314    OnSimPropertiesChanged(properties, vector<string>());
1315  }
1316}
1317
1318void CellularCapabilityUniversal::OnSupportedCapabilitesChanged(
1319    const vector<uint32_t> &supported_capabilities) {
1320  supported_capabilities_ = supported_capabilities;
1321}
1322
1323void CellularCapabilityUniversal::OnModemCurrentCapabilitiesChanged(
1324    uint32_t current_capabilities) {
1325  current_capabilities_ = current_capabilities;
1326
1327  // Only allow network scan when the modem's current capabilities support
1328  // GSM/UMTS.
1329  //
1330  // TODO(benchan): We should consider having the modem plugins in ModemManager
1331  // reporting whether network scan is supported.
1332  cellular()->set_scanning_supported(
1333      (current_capabilities & MM_MODEM_CAPABILITY_GSM_UMTS) != 0);
1334}
1335
1336void CellularCapabilityUniversal::OnMdnChanged(
1337    const string &mdn) {
1338  cellular()->set_mdn(NormalizeMdn(mdn));
1339  UpdatePendingActivationState();
1340}
1341
1342void CellularCapabilityUniversal::OnModemRevisionChanged(
1343    const string &revision) {
1344  cellular()->set_firmware_revision(revision);
1345}
1346
1347void CellularCapabilityUniversal::OnModemStateChanged(
1348    Cellular::ModemState state) {
1349  SLOG(this, 3) << __func__ << ": " << Cellular::GetModemStateString(state);
1350
1351  if (state == Cellular::kModemStateConnected) {
1352    // This assumes that ModemManager updates the Bearers list and the Bearer
1353    // properties before changing Modem state to Connected.
1354    SLOG(this, 2) << "Update active bearer.";
1355    UpdateActiveBearer();
1356  }
1357
1358  cellular()->OnModemStateChanged(state);
1359  // TODO(armansito): Move the deferred enable logic to Cellular
1360  // (See crbug.com/279499).
1361  if (!deferred_enable_modem_callback_.is_null() &&
1362      state == Cellular::kModemStateDisabled) {
1363    SLOG(this, 2) << "Enabling modem after deferring.";
1364    deferred_enable_modem_callback_.Run();
1365    deferred_enable_modem_callback_.Reset();
1366  }
1367}
1368
1369void CellularCapabilityUniversal::OnAccessTechnologiesChanged(
1370    uint32_t access_technologies) {
1371  if (access_technologies_ != access_technologies) {
1372    const string old_type_string(GetTypeString());
1373    access_technologies_ = access_technologies;
1374    const string new_type_string(GetTypeString());
1375    if (new_type_string != old_type_string) {
1376      // TODO(jglasgow): address layering violation of emitting change
1377      // signal here for a property owned by Cellular.
1378      cellular()->adaptor()->EmitStringChanged(
1379          kTechnologyFamilyProperty, new_type_string);
1380    }
1381    if (cellular()->service().get()) {
1382      cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
1383    }
1384  }
1385}
1386
1387void CellularCapabilityUniversal::OnSupportedModesChanged(
1388    const vector<ModemModes> &supported_modes) {
1389  supported_modes_ = supported_modes;
1390}
1391
1392void CellularCapabilityUniversal::OnCurrentModesChanged(
1393    const ModemModes &current_modes) {
1394  current_modes_ = current_modes;
1395}
1396
1397void CellularCapabilityUniversal::OnBearersChanged(
1398    const RpcIdentifiers &bearers) {
1399  bearer_paths_ = bearers;
1400}
1401
1402void CellularCapabilityUniversal::OnLockRetriesChanged(
1403    const LockRetryData &lock_retries) {
1404  SLOG(this, 3) << __func__;
1405
1406  // Look for the retries left for the current lock. Try the obtain the count
1407  // that matches the current count. If no count for the current lock is
1408  // available, report the first one in the dictionary.
1409  LockRetryData::const_iterator it =
1410      lock_retries.find(sim_lock_status_.lock_type);
1411  if (it == lock_retries.end())
1412      it = lock_retries.begin();
1413  if (it != lock_retries.end())
1414    sim_lock_status_.retries_left = it->second;
1415  else
1416    // Unknown, use 999
1417    sim_lock_status_.retries_left = 999;
1418}
1419
1420void CellularCapabilityUniversal::OnLockTypeChanged(
1421    MMModemLock lock_type) {
1422  SLOG(this, 3) << __func__ << ": " << lock_type;
1423  sim_lock_status_.lock_type = lock_type;
1424
1425  // If the SIM is in a locked state |sim_lock_status_.enabled| might be false.
1426  // This is because the corresponding property 'EnabledFacilityLocks' is on
1427  // the 3GPP interface and the 3GPP interface is not available while the Modem
1428  // is in the 'LOCKED' state.
1429  if (lock_type != MM_MODEM_LOCK_NONE &&
1430      lock_type != MM_MODEM_LOCK_UNKNOWN &&
1431      !sim_lock_status_.enabled)
1432    sim_lock_status_.enabled = true;
1433}
1434
1435void CellularCapabilityUniversal::OnSimLockStatusChanged() {
1436  SLOG(this, 3) << __func__;
1437  cellular()->adaptor()->EmitKeyValueStoreChanged(
1438      kSIMLockStatusProperty, SimLockStatusToProperty(nullptr));
1439
1440  // If the SIM is currently unlocked, assume that we need to refresh
1441  // carrier information, since a locked SIM prevents shill from obtaining
1442  // the necessary data to establish a connection later (e.g. IMSI).
1443  if (IsValidSimPath(sim_path_) &&
1444      (sim_lock_status_.lock_type == MM_MODEM_LOCK_NONE ||
1445       sim_lock_status_.lock_type == MM_MODEM_LOCK_UNKNOWN)) {
1446    std::unique_ptr<DBusPropertiesProxyInterface> properties_proxy(
1447        proxy_factory()->CreateDBusPropertiesProxy(sim_path_,
1448                                                   cellular()->dbus_owner()));
1449    DBusPropertiesMap properties(
1450        properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
1451    OnSimPropertiesChanged(properties, vector<string>());
1452  }
1453}
1454
1455void CellularCapabilityUniversal::OnModem3GPPPropertiesChanged(
1456    const DBusPropertiesMap &properties,
1457    const vector<string> &/* invalidated_properties */) {
1458  SLOG(this, 3) << __func__;
1459  uint32_t uint_value;
1460  string imei;
1461  if (DBusProperties::GetString(properties,
1462                                MM_MODEM_MODEM3GPP_PROPERTY_IMEI,
1463                                &imei))
1464    cellular()->set_imei(imei);
1465
1466  // Handle registration state changes as a single change
1467  Stringmap::const_iterator it;
1468  string operator_code;
1469  string operator_name;
1470  it = serving_operator_.find(kOperatorCodeKey);
1471  if (it != serving_operator_.end())
1472    operator_code = it->second;
1473  it = serving_operator_.find(kOperatorNameKey);
1474  if (it != serving_operator_.end())
1475    operator_name = it->second;
1476
1477  MMModem3gppRegistrationState state = registration_state_;
1478  bool registration_changed = false;
1479  if (DBusProperties::GetUint32(properties,
1480                                MM_MODEM_MODEM3GPP_PROPERTY_REGISTRATIONSTATE,
1481                                &uint_value)) {
1482    state = static_cast<MMModem3gppRegistrationState>(uint_value);
1483    registration_changed = true;
1484  }
1485  if (DBusProperties::GetString(properties,
1486                                MM_MODEM_MODEM3GPP_PROPERTY_OPERATORCODE,
1487                                &operator_code))
1488    registration_changed = true;
1489  if (DBusProperties::GetString(properties,
1490                                MM_MODEM_MODEM3GPP_PROPERTY_OPERATORNAME,
1491                                &operator_name))
1492    registration_changed = true;
1493  if (registration_changed)
1494    On3GPPRegistrationChanged(state, operator_code, operator_name);
1495  if (DBusProperties::GetUint32(properties,
1496                                MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE,
1497                                &uint_value))
1498    On3GPPSubscriptionStateChanged(
1499        static_cast<MMModem3gppSubscriptionState>(uint_value));
1500
1501  uint32_t subscription_state;
1502  CellularServiceRefPtr service = cellular()->service();
1503  if (service.get() &&
1504      DBusProperties::GetUint32(properties,
1505                                MM_MODEM_MODEM3GPP_PROPERTY_SUBSCRIPTIONSTATE,
1506                                &subscription_state)) {
1507    SLOG(this, 3) << __func__ << ": Subscription state = "
1508                              << subscription_state;
1509    service->out_of_credits_detector()->NotifySubscriptionStateChanged(
1510        subscription_state);
1511  }
1512
1513  uint32_t locks = 0;
1514  if (DBusProperties::GetUint32(
1515          properties, MM_MODEM_MODEM3GPP_PROPERTY_ENABLEDFACILITYLOCKS,
1516          &locks))
1517    OnFacilityLocksChanged(locks);
1518}
1519
1520void CellularCapabilityUniversal::On3GPPRegistrationChanged(
1521    MMModem3gppRegistrationState state,
1522    const string &operator_code,
1523    const string &operator_name) {
1524  SLOG(this, 3) << __func__ << ": regstate=" << state
1525                            << ", opercode=" << operator_code
1526                            << ", opername=" << operator_name;
1527
1528  // While the modem is connected, if the state changed from a registered state
1529  // to a non registered state, defer the state change by 15 seconds.
1530  if (cellular()->modem_state() == Cellular::kModemStateConnected &&
1531      IsRegistered() && !IsRegisteredState(state)) {
1532    if (!registration_dropped_update_callback_.IsCancelled()) {
1533      LOG(WARNING) << "Modem reported consecutive 3GPP registration drops. "
1534                   << "Ignoring earlier notifications.";
1535      registration_dropped_update_callback_.Cancel();
1536    } else {
1537      // This is not a repeated post. So, count this instance of delayed drop
1538      // posted.
1539      modem_info()->metrics()->Notify3GPPRegistrationDelayedDropPosted();
1540    }
1541    SLOG(this, 2) << "Posted deferred registration state update";
1542    registration_dropped_update_callback_.Reset(
1543        Bind(&CellularCapabilityUniversal::Handle3GPPRegistrationChange,
1544             weak_ptr_factory_.GetWeakPtr(),
1545             state,
1546             operator_code,
1547             operator_name));
1548    cellular()->dispatcher()->PostDelayedTask(
1549        registration_dropped_update_callback_.callback(),
1550        registration_dropped_update_timeout_milliseconds_);
1551  } else {
1552    if (!registration_dropped_update_callback_.IsCancelled()) {
1553      SLOG(this, 2) << "Cancelled a deferred registration state update";
1554      registration_dropped_update_callback_.Cancel();
1555      // If we cancelled the callback here, it means we had flaky network for a
1556      // small duration.
1557      modem_info()->metrics()->Notify3GPPRegistrationDelayedDropCanceled();
1558    }
1559    Handle3GPPRegistrationChange(state, operator_code, operator_name);
1560  }
1561}
1562
1563void CellularCapabilityUniversal::Handle3GPPRegistrationChange(
1564    MMModem3gppRegistrationState updated_state,
1565    string updated_operator_code,
1566    string updated_operator_name) {
1567  // A finished callback does not qualify as a canceled callback.
1568  // We test for a canceled callback to check for outstanding callbacks.
1569  // So, explicitly cancel the callback here.
1570  registration_dropped_update_callback_.Cancel();
1571
1572  SLOG(this, 3) << __func__ << ": regstate=" << updated_state
1573                            << ", opercode=" << updated_operator_code
1574                            << ", opername=" << updated_operator_name;
1575
1576  registration_state_ = updated_state;
1577  serving_operator_[kOperatorCodeKey] = updated_operator_code;
1578  serving_operator_[kOperatorNameKey] = updated_operator_name;
1579  cellular()->serving_operator_info()->UpdateMCCMNC(updated_operator_code);
1580  cellular()->serving_operator_info()->UpdateOperatorName(
1581      updated_operator_name);
1582
1583  cellular()->HandleNewRegistrationState();
1584
1585  // If the modem registered with the network and the current ICCID is pending
1586  // activation, then reset the modem.
1587  UpdatePendingActivationState();
1588}
1589
1590void CellularCapabilityUniversal::On3GPPSubscriptionStateChanged(
1591    MMModem3gppSubscriptionState updated_state) {
1592  SLOG(this, 3) << __func__ << ": Updated subscription state = "
1593                            << updated_state;
1594
1595  // A one-to-one enum mapping.
1596  SubscriptionState new_subscription_state;
1597  switch (updated_state) {
1598    case MM_MODEM_3GPP_SUBSCRIPTION_STATE_UNKNOWN:
1599      new_subscription_state = kSubscriptionStateUnknown;
1600      break;
1601    case MM_MODEM_3GPP_SUBSCRIPTION_STATE_PROVISIONED:
1602      new_subscription_state = kSubscriptionStateProvisioned;
1603      break;
1604    case MM_MODEM_3GPP_SUBSCRIPTION_STATE_UNPROVISIONED:
1605      new_subscription_state = kSubscriptionStateUnprovisioned;
1606      break;
1607    case MM_MODEM_3GPP_SUBSCRIPTION_STATE_OUT_OF_DATA:
1608      new_subscription_state = kSubscriptionStateOutOfData;
1609      break;
1610    default:
1611      LOG(ERROR) << "Unrecognized MMModem3gppSubscriptionState: "
1612                 << updated_state;
1613      new_subscription_state = kSubscriptionStateUnknown;
1614      return;
1615  }
1616  if (new_subscription_state == subscription_state_)
1617    return;
1618
1619  subscription_state_ = new_subscription_state;
1620
1621  UpdateServiceActivationState();
1622  UpdatePendingActivationState();
1623}
1624
1625void CellularCapabilityUniversal::OnModemStateChangedSignal(
1626    int32_t old_state, int32_t new_state, uint32_t reason) {
1627  Cellular::ModemState old_modem_state =
1628      static_cast<Cellular::ModemState>(old_state);
1629  Cellular::ModemState new_modem_state =
1630      static_cast<Cellular::ModemState>(new_state);
1631  SLOG(this, 3) << __func__ << "("
1632                            << Cellular::GetModemStateString(old_modem_state)
1633                            << ", "
1634                            << Cellular::GetModemStateString(new_modem_state)
1635                            << ", "
1636                            << reason << ")";
1637}
1638
1639void CellularCapabilityUniversal::OnSignalQualityChanged(uint32_t quality) {
1640  cellular()->HandleNewSignalQuality(quality);
1641}
1642
1643void CellularCapabilityUniversal::OnFacilityLocksChanged(uint32_t locks) {
1644  bool sim_enabled = !!(locks & MM_MODEM_3GPP_FACILITY_SIM);
1645  if (sim_lock_status_.enabled != sim_enabled) {
1646    sim_lock_status_.enabled = sim_enabled;
1647    OnSimLockStatusChanged();
1648  }
1649}
1650
1651void CellularCapabilityUniversal::OnSimPropertiesChanged(
1652    const DBusPropertiesMap &props,
1653    const vector<string> &/* invalidated_properties */) {
1654  SLOG(this, 3) << __func__;
1655  string value;
1656  if (DBusProperties::GetString(props, MM_SIM_PROPERTY_SIMIDENTIFIER, &value))
1657    OnSimIdentifierChanged(value);
1658  if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORIDENTIFIER,
1659                                &value))
1660    OnOperatorIdChanged(value);
1661  if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORNAME, &value))
1662    OnSpnChanged(value);
1663  if (DBusProperties::GetString(props, MM_SIM_PROPERTY_IMSI, &value)) {
1664    cellular()->set_imsi(value);
1665    cellular()->home_provider_info()->UpdateIMSI(value);
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(value);
1669  }
1670}
1671
1672void CellularCapabilityUniversal::OnSpnChanged(const std::string &spn) {
1673  spn_ = spn;
1674  cellular()->home_provider_info()->UpdateOperatorName(spn);
1675}
1676
1677void 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
1685void 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
1691OutOfCreditsDetector::OOCType
1692CellularCapabilityUniversal::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