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