blob: 742bf712bb55e0c9eb94dae0aa19891bc4f675d7 [file] [log] [blame]
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001// Copyright (c) 2012 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_capability_universal.h"
6
7#include <base/bind.h>
Jason Glasgow82f9ab32012-04-04 14:27:19 -04008#include <base/stl_util.h>
Jason Glasgow82f9ab32012-04-04 14:27:19 -04009#include <base/stringprintf.h>
Ben Chan6d0d1e72012-11-06 21:19:28 -080010#include <base/string_util.h>
Jason Glasgow82f9ab32012-04-04 14:27:19 -040011#include <chromeos/dbus/service_constants.h>
12#include <mobile_provider.h>
Ben Chan5c853ef2012-10-05 00:05:37 -070013#include <ModemManager/ModemManager.h>
Jason Glasgow82f9ab32012-04-04 14:27:19 -040014
15#include <string>
16#include <vector>
17
18#include "shill/adaptor_interfaces.h"
Ben Chan15786032012-11-04 21:28:02 -080019#include "shill/cellular_operator_info.h"
Jason Glasgow82f9ab32012-04-04 14:27:19 -040020#include "shill/cellular_service.h"
Jason Glasgowaf583282012-04-18 15:18:22 -040021#include "shill/dbus_properties_proxy_interface.h"
Jason Glasgow82f9ab32012-04-04 14:27:19 -040022#include "shill/error.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070023#include "shill/logging.h"
Jason Glasgow82f9ab32012-04-04 14:27:19 -040024#include "shill/property_accessor.h"
25#include "shill/proxy_factory.h"
26
27#ifdef MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN
28#error "Do not include mm-modem.h"
29#endif
30
Jason Glasgow82f9ab32012-04-04 14:27:19 -040031using base::Bind;
Jason Glasgowef965562012-04-10 16:12:35 -040032using base::Closure;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040033using std::string;
34using std::vector;
35
36namespace shill {
37
38// static
Jason Glasgow14521872012-05-07 19:12:15 -040039const char CellularCapabilityUniversal::kConnectPin[] = "pin";
40const char CellularCapabilityUniversal::kConnectOperatorId[] = "operator-id";
41const char CellularCapabilityUniversal::kConnectBands[] = "bands";
42const char CellularCapabilityUniversal::kConnectAllowedModes[] =
43 "allowed-modes";
44const char CellularCapabilityUniversal::kConnectPreferredMode[] =
45 "preferred-mode";
46const char CellularCapabilityUniversal::kConnectApn[] = "apn";
47const char CellularCapabilityUniversal::kConnectIPType[] = "ip-type";
48const char CellularCapabilityUniversal::kConnectUser[] = "user";
49const char CellularCapabilityUniversal::kConnectPassword[] = "password";
50const char CellularCapabilityUniversal::kConnectNumber[] = "number";
51const char CellularCapabilityUniversal::kConnectAllowRoaming[] =
52 "allow-roaming";
53const char CellularCapabilityUniversal::kConnectRMProtocol[] = "rm-protocol";
Jason Glasgowcd0349c2012-05-03 23:32:15 -040054const char CellularCapabilityUniversal::kStatusProperty[] = "status";
55const char CellularCapabilityUniversal::kOperatorLongProperty[] =
56 "operator-long";
57const char CellularCapabilityUniversal::kOperatorShortProperty[] =
58 "operator-short";
59const char CellularCapabilityUniversal::kOperatorCodeProperty[] =
60 "operator-code";
61const char CellularCapabilityUniversal::kOperatorAccessTechnologyProperty[] =
62 "access-technology";
Jason Glasgow14521872012-05-07 19:12:15 -040063const char CellularCapabilityUniversal::kE362ModelId[] = "E362 WWAN";
64unsigned int CellularCapabilityUniversal::friendly_service_name_id_ = 0;
65
Jason Glasgow82f9ab32012-04-04 14:27:19 -040066
67static const char kPhoneNumber[] = "*99#";
68
69static string AccessTechnologyToString(uint32 access_technologies) {
70 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_LTE)
71 return flimflam::kNetworkTechnologyLte;
72 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
73 MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
74 MM_MODEM_ACCESS_TECHNOLOGY_EVDOB))
75 return flimflam::kNetworkTechnologyEvdo;
76 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_1XRTT)
77 return flimflam::kNetworkTechnology1Xrtt;
78 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS)
79 return flimflam::kNetworkTechnologyHspaPlus;
80 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
81 MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
82 MM_MODEM_ACCESS_TECHNOLOGY_HSDPA))
83 return flimflam::kNetworkTechnologyHspa;
84 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_UMTS)
85 return flimflam::kNetworkTechnologyUmts;
86 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_EDGE)
87 return flimflam::kNetworkTechnologyEdge;
88 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_GPRS)
89 return flimflam::kNetworkTechnologyGprs;
90 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
91 MM_MODEM_ACCESS_TECHNOLOGY_GSM))
92 return flimflam::kNetworkTechnologyGsm;
93 return "";
94}
95
Jason Glasgow9f09aef2012-05-08 16:26:55 -040096static string AccessTechnologyToTechnologyFamily(uint32 access_technologies) {
97 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_LTE |
98 MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS |
99 MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
100 MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
101 MM_MODEM_ACCESS_TECHNOLOGY_HSDPA |
102 MM_MODEM_ACCESS_TECHNOLOGY_UMTS |
103 MM_MODEM_ACCESS_TECHNOLOGY_EDGE |
104 MM_MODEM_ACCESS_TECHNOLOGY_GPRS |
105 MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
106 MM_MODEM_ACCESS_TECHNOLOGY_GSM))
107 return flimflam::kTechnologyFamilyGsm;
108 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
Ben Chan6d0d1e72012-11-06 21:19:28 -0800109 MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
110 MM_MODEM_ACCESS_TECHNOLOGY_EVDOB |
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400111 MM_MODEM_ACCESS_TECHNOLOGY_1XRTT))
112 return flimflam::kTechnologyFamilyCdma;
113 return "";
114}
115
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400116CellularCapabilityUniversal::CellularCapabilityUniversal(
117 Cellular *cellular,
118 ProxyFactory *proxy_factory)
119 : CellularCapability(cellular, proxy_factory),
120 weak_ptr_factory_(this),
121 registration_state_(MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN),
122 cdma_registration_state_(MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN),
Darin Petkove636c692012-05-31 10:22:17 +0200123 capabilities_(MM_MODEM_CAPABILITY_NONE),
124 current_capabilities_(MM_MODEM_CAPABILITY_NONE),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400125 access_technologies_(MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN),
Jason Glasgowaf583282012-04-18 15:18:22 -0400126 supported_modes_(MM_MODEM_MODE_NONE),
127 allowed_modes_(MM_MODEM_MODE_NONE),
128 preferred_mode_(MM_MODEM_MODE_NONE),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400129 home_provider_(NULL),
Darin Petkovf508c822012-09-21 13:43:17 +0200130 provider_requires_roaming_(false),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400131 scanning_supported_(true),
132 scanning_(false),
Ben Chanbd3aee82012-10-16 23:52:04 -0700133 scan_interval_(0),
134 sim_present_(false) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700135 SLOG(Cellular, 2) << "Cellular capability constructed: Universal";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400136 PropertyStore *store = cellular->mutable_store();
137
138 store->RegisterConstString(flimflam::kCarrierProperty, &carrier_);
139 store->RegisterConstBool(flimflam::kSupportNetworkScanProperty,
140 &scanning_supported_);
141 store->RegisterConstString(flimflam::kEsnProperty, &esn_);
142 store->RegisterConstString(flimflam::kFirmwareRevisionProperty,
143 &firmware_revision_);
144 store->RegisterConstString(flimflam::kHardwareRevisionProperty,
145 &hardware_revision_);
146 store->RegisterConstString(flimflam::kImeiProperty, &imei_);
147 store->RegisterConstString(flimflam::kImsiProperty, &imsi_);
Ben Chana5e27082012-07-31 14:30:28 -0700148 store->RegisterConstString(flimflam::kIccidProperty, &sim_identifier_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400149 store->RegisterConstString(flimflam::kManufacturerProperty, &manufacturer_);
150 store->RegisterConstString(flimflam::kMdnProperty, &mdn_);
151 store->RegisterConstString(flimflam::kMeidProperty, &meid_);
152 store->RegisterConstString(flimflam::kMinProperty, &min_);
153 store->RegisterConstString(flimflam::kModelIDProperty, &model_id_);
154 store->RegisterConstString(flimflam::kSelectedNetworkProperty,
155 &selected_network_);
156 store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
157 &found_networks_);
Darin Petkovf508c822012-09-21 13:43:17 +0200158 store->RegisterConstBool(shill::kProviderRequiresRoamingProperty,
159 &provider_requires_roaming_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400160 store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
161 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
162 HelpRegisterDerivedKeyValueStore(
163 flimflam::kSIMLockStatusProperty,
164 &CellularCapabilityUniversal::SimLockStatusToProperty,
165 NULL);
Ben Chanbd3aee82012-10-16 23:52:04 -0700166 store->RegisterConstBool(shill::kSIMPresentProperty, &sim_present_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400167 store->RegisterConstStringmaps(flimflam::kCellularApnListProperty,
168 &apn_list_);
169}
170
171KeyValueStore CellularCapabilityUniversal::SimLockStatusToProperty(
172 Error */*error*/) {
173 KeyValueStore status;
174 status.SetBool(flimflam::kSIMLockEnabledProperty, sim_lock_status_.enabled);
175 status.SetString(flimflam::kSIMLockTypeProperty, sim_lock_status_.lock_type);
176 status.SetUint(flimflam::kSIMLockRetriesLeftProperty,
177 sim_lock_status_.retries_left);
178 return status;
179}
180
181void CellularCapabilityUniversal::HelpRegisterDerivedKeyValueStore(
182 const string &name,
183 KeyValueStore(CellularCapabilityUniversal::*get)(Error *error),
184 void(CellularCapabilityUniversal::*set)(
185 const KeyValueStore &value, Error *error)) {
186 cellular()->mutable_store()->RegisterDerivedKeyValueStore(
187 name,
188 KeyValueStoreAccessor(
189 new CustomAccessor<CellularCapabilityUniversal, KeyValueStore>(
190 this, get, set)));
191}
192
193void CellularCapabilityUniversal::InitProxies() {
194 modem_3gpp_proxy_.reset(
195 proxy_factory()->CreateMM1ModemModem3gppProxy(cellular()->dbus_path(),
196 cellular()->dbus_owner()));
197 modem_cdma_proxy_.reset(
198 proxy_factory()->CreateMM1ModemModemCdmaProxy(cellular()->dbus_path(),
199 cellular()->dbus_owner()));
200 modem_proxy_.reset(
201 proxy_factory()->CreateMM1ModemProxy(cellular()->dbus_path(),
202 cellular()->dbus_owner()));
203 modem_simple_proxy_.reset(
204 proxy_factory()->CreateMM1ModemSimpleProxy(cellular()->dbus_path(),
205 cellular()->dbus_owner()));
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400206 modem_proxy_->set_state_changed_callback(
207 Bind(&CellularCapabilityUniversal::OnModemStateChangedSignal,
208 weak_ptr_factory_.GetWeakPtr()));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400209 // Do not create a SIM proxy until the device is enabled because we
210 // do not yet know the object path of the sim object.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400211 // TODO(jglasgow): register callbacks
212}
213
214void CellularCapabilityUniversal::StartModem(Error *error,
Jason Glasgowef965562012-04-10 16:12:35 -0400215 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700216 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400217 InitProxies();
218
Gary Moraine285a842012-08-15 08:23:57 -0700219 // ModemManager must be in the disabled state to accept the Enable command.
220 Cellular::ModemState state =
221 static_cast<Cellular::ModemState>(modem_proxy_->State());
222 if (state == Cellular::kModemStateDisabled) {
223 EnableModem(error, callback);
224 } else if (!cellular()->IsUnderlyingDeviceEnabled()) {
225 SLOG(Cellular, 2) << "Enabling of modem deferred because state is "
226 << state;
227 deferred_enable_modem_callback_ =
228 Bind(&CellularCapabilityUniversal::EnableModem,
229 weak_ptr_factory_.GetWeakPtr(), static_cast<Error *>(NULL),
230 callback);
231 } else {
Arman Uguray403fad42012-09-25 17:08:39 -0700232 // Call GetProperties() here to sync up with the modem state
233 GetProperties();
Gary Moraine285a842012-08-15 08:23:57 -0700234 callback.Run(*error);
235 }
236}
237
238void CellularCapabilityUniversal::EnableModem(Error *error,
239 const ResultCallback &callback) {
240 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400241 CHECK(!callback.is_null());
Thieu Lee3b36592012-08-30 17:50:26 -0700242 Error local_error(Error::kOperationInitiated);
Jason Glasgowef965562012-04-10 16:12:35 -0400243 modem_proxy_->Enable(
244 true,
Gary Moraine285a842012-08-15 08:23:57 -0700245 &local_error,
Jason Glasgowef965562012-04-10 16:12:35 -0400246 Bind(&CellularCapabilityUniversal::Start_EnableModemCompleted,
247 weak_ptr_factory_.GetWeakPtr(), callback),
248 kTimeoutEnable);
Gary Moraine285a842012-08-15 08:23:57 -0700249 if (local_error.IsFailure()) {
250 SLOG(Cellular, 2) << __func__ << "Call to modem_proxy_->Enable() failed";
251 callback.Run(local_error);
252 }
253 if (error) {
254 error->CopyFrom(local_error);
255 }
Jason Glasgowef965562012-04-10 16:12:35 -0400256}
257
258void CellularCapabilityUniversal::Start_EnableModemCompleted(
259 const ResultCallback &callback, const Error &error) {
Eric Shienbrood9b1bd7b2012-04-20 16:42:26 -0400260 SLOG(Cellular, 2) << __func__ << ": " << error;
Jason Glasgowef965562012-04-10 16:12:35 -0400261 if (error.IsFailure()) {
262 callback.Run(error);
263 return;
264 }
265
266 // After modem is enabled, it should be possible to get properties
267 // TODO(jglasgow): handle errors from GetProperties
268 GetProperties();
Jason Glasgow4380f0d2012-05-03 18:05:04 -0400269 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400270}
271
272void CellularCapabilityUniversal::StopModem(Error *error,
Jason Glasgow02401cc2012-05-16 10:35:37 -0400273 const ResultCallback &callback) {
Jason Glasgowef965562012-04-10 16:12:35 -0400274 CHECK(!callback.is_null());
275 CHECK(error);
Thieu Led0012052012-07-25 16:09:09 -0700276 Cellular::ModemState state = cellular()->modem_state();
277 SLOG(Cellular, 2) << __func__ << "(" << state << ")";
Jason Glasgowef965562012-04-10 16:12:35 -0400278
Thieu Led0012052012-07-25 16:09:09 -0700279 if (cellular()->IsModemRegistered()) {
Jason Glasgow02401cc2012-05-16 10:35:37 -0400280 string all_bearers("/"); // "/" means all bearers. See Modemanager docs.
Jason Glasgowef965562012-04-10 16:12:35 -0400281 modem_simple_proxy_->Disconnect(
282 all_bearers,
283 error,
284 Bind(&CellularCapabilityUniversal::Stop_DisconnectCompleted,
285 weak_ptr_factory_.GetWeakPtr(), callback),
286 kTimeoutDefault);
287 if (error->IsFailure())
288 callback.Run(*error);
289 } else {
Jason Glasgowef965562012-04-10 16:12:35 -0400290 Closure task = Bind(&CellularCapabilityUniversal::Stop_Disable,
291 weak_ptr_factory_.GetWeakPtr(),
292 callback);
293 cellular()->dispatcher()->PostTask(task);
294 }
Gary Moraine285a842012-08-15 08:23:57 -0700295 deferred_enable_modem_callback_.Reset();
Jason Glasgowef965562012-04-10 16:12:35 -0400296}
297
298void CellularCapabilityUniversal::Stop_DisconnectCompleted(
299 const ResultCallback &callback, const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700300 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400301
302 LOG_IF(ERROR, error.IsFailure()) << "Disconnect failed. Ignoring.";
303 Stop_Disable(callback);
304}
305
306void CellularCapabilityUniversal::Stop_Disable(const ResultCallback &callback) {
307 Error error;
308 modem_proxy_->Enable(
309 false, &error,
310 Bind(&CellularCapabilityUniversal::Stop_DisableCompleted,
311 weak_ptr_factory_.GetWeakPtr(), callback),
Jason Glasgow02401cc2012-05-16 10:35:37 -0400312 kTimeoutEnable);
Jason Glasgowef965562012-04-10 16:12:35 -0400313 if (error.IsFailure())
314 callback.Run(error);
315}
316
317void CellularCapabilityUniversal::Stop_DisableCompleted(
318 const ResultCallback &callback, const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700319 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400320
321 if (error.IsSuccess())
322 ReleaseProxies();
323 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400324}
325
326void CellularCapabilityUniversal::Connect(const DBusPropertiesMap &properties,
327 Error *error,
328 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700329 SLOG(Cellular, 2) << __func__;
Nathan Williamsb54974f2012-04-19 11:16:30 -0400330 DBusPathCallback cb = Bind(&CellularCapabilityUniversal::OnConnectReply,
331 weak_ptr_factory_.GetWeakPtr(),
332 callback);
333 modem_simple_proxy_->Connect(properties, error, cb, kTimeoutConnect);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400334}
335
336void CellularCapabilityUniversal::Disconnect(Error *error,
337 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700338 SLOG(Cellular, 2) << __func__;
Thieu Le5d6864a2012-07-20 11:43:51 -0700339 if (bearer_path_.empty()) {
340 LOG(WARNING) << "In " << __func__ << "(): "
341 << "Ignoring attempt to disconnect without bearer";
Thieu Le3d275392012-07-20 15:32:58 -0700342 } else if (modem_simple_proxy_.get()) {
Thieu Le5d6864a2012-07-20 11:43:51 -0700343 modem_simple_proxy_->Disconnect(bearer_path_,
344 error,
345 callback,
346 kTimeoutDefault);
347 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400348}
349
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400350void CellularCapabilityUniversal::Activate(const string &carrier,
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400351 Error *error,
352 const ResultCallback &callback) {
353 OnUnsupportedOperation(__func__, error);
354}
355
356void CellularCapabilityUniversal::ReleaseProxies() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700357 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400358 modem_3gpp_proxy_.reset();
359 modem_cdma_proxy_.reset();
360 modem_proxy_.reset();
361 modem_simple_proxy_.reset();
362 sim_proxy_.reset();
363}
364
365void CellularCapabilityUniversal::OnServiceCreated() {
366 // If IMSI is available, base the service's storage identifier on it.
367 if (!imsi_.empty()) {
368 cellular()->service()->SetStorageIdentifier(
369 string(flimflam::kTypeCellular) + "_" +
370 cellular()->address() + "_" + imsi_);
371 }
372 cellular()->service()->SetActivationState(
Ben Chan15786032012-11-04 21:28:02 -0800373 IsServiceActivationRequired() ?
374 flimflam::kActivationStateNotActivated :
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400375 flimflam::kActivationStateActivated);
376 UpdateServingOperator();
Ben Chan6d0d1e72012-11-06 21:19:28 -0800377 UpdateOLP();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400378}
379
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400380// Create the list of APNs to try, in the following order:
381// - last APN that resulted in a successful connection attempt on the
382// current network (if any)
383// - the APN, if any, that was set by the user
384// - the list of APNs found in the mobile broadband provider DB for the
385// home provider associated with the current SIM
386// - as a last resort, attempt to connect with no APN
387void CellularCapabilityUniversal::SetupApnTryList() {
388 apn_try_list_.clear();
389
390 DCHECK(cellular()->service().get());
391 const Stringmap *apn_info = cellular()->service()->GetLastGoodApn();
392 if (apn_info)
393 apn_try_list_.push_back(*apn_info);
394
395 apn_info = cellular()->service()->GetUserSpecifiedApn();
396 if (apn_info)
397 apn_try_list_.push_back(*apn_info);
398
399 apn_try_list_.insert(apn_try_list_.end(), apn_list_.begin(), apn_list_.end());
400}
401
402void CellularCapabilityUniversal::SetupConnectProperties(
403 DBusPropertiesMap *properties) {
404 SetupApnTryList();
405 FillConnectPropertyMap(properties);
406}
407
408void CellularCapabilityUniversal::FillConnectPropertyMap(
409 DBusPropertiesMap *properties) {
410
411 // TODO(jglasgow): Is this really needed anymore?
Jason Glasgow14521872012-05-07 19:12:15 -0400412 (*properties)[kConnectNumber].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400413 kPhoneNumber);
414
Jason Glasgow14521872012-05-07 19:12:15 -0400415 (*properties)[kConnectAllowRoaming].writer().append_bool(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400416 AllowRoaming());
417
418 if (!apn_try_list_.empty()) {
419 // Leave the APN at the front of the list, so that it can be recorded
420 // if the connect attempt succeeds.
421 Stringmap apn_info = apn_try_list_.front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700422 SLOG(Cellular, 2) << __func__ << ": Using APN "
423 << apn_info[flimflam::kApnProperty];
Jason Glasgow14521872012-05-07 19:12:15 -0400424 (*properties)[kConnectApn].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400425 apn_info[flimflam::kApnProperty].c_str());
426 if (ContainsKey(apn_info, flimflam::kApnUsernameProperty))
Jason Glasgow14521872012-05-07 19:12:15 -0400427 (*properties)[kConnectUser].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400428 apn_info[flimflam::kApnUsernameProperty].c_str());
429 if (ContainsKey(apn_info, flimflam::kApnPasswordProperty))
Jason Glasgow14521872012-05-07 19:12:15 -0400430 (*properties)[kConnectPassword].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400431 apn_info[flimflam::kApnPasswordProperty].c_str());
432 }
433}
434
435void CellularCapabilityUniversal::OnConnectReply(const ResultCallback &callback,
Nathan Williamsb54974f2012-04-19 11:16:30 -0400436 const DBus::Path &path,
437 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700438 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Nathan Williamsb54974f2012-04-19 11:16:30 -0400439
Jason Glasgow7234ec32012-05-23 16:01:21 -0400440 CellularServiceRefPtr service = cellular()->service();
441 if (!service) {
442 // The service could have been deleted before our Connect() request
443 // completes if the modem was enabled and then quickly disabled.
444 apn_try_list_.clear();
445 } else if (error.IsFailure()) {
446 service->ClearLastGoodApn();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400447 // The APN that was just tried (and failed) is still at the
448 // front of the list, about to be removed. If the list is empty
449 // after that, try one last time without an APN. This may succeed
450 // with some modems in some cases.
Jason Glasgow14521872012-05-07 19:12:15 -0400451 if (RetriableConnectError(error) && !apn_try_list_.empty()) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400452 apn_try_list_.pop_front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700453 SLOG(Cellular, 2) << "Connect failed with invalid APN, "
454 << apn_try_list_.size() << " remaining APNs to try";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400455 DBusPropertiesMap props;
456 FillConnectPropertyMap(&props);
457 Error error;
458 Connect(props, &error, callback);
459 return;
460 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400461 } else {
462 if (!apn_try_list_.empty()) {
Jason Glasgow7234ec32012-05-23 16:01:21 -0400463 service->SetLastGoodApn(apn_try_list_.front());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400464 apn_try_list_.clear();
465 }
Nathan Williamsb54974f2012-04-19 11:16:30 -0400466 bearer_path_ = path;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400467 }
468
469 if (!callback.is_null())
470 callback.Run(error);
471}
472
473bool CellularCapabilityUniversal::AllowRoaming() {
Darin Petkovf508c822012-09-21 13:43:17 +0200474 return provider_requires_roaming_ || allow_roaming_property();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400475}
476
Jason Glasgowef965562012-04-10 16:12:35 -0400477void CellularCapabilityUniversal::GetProperties() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700478 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400479
Jason Glasgowaf583282012-04-18 15:18:22 -0400480 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
481 proxy_factory()->CreateDBusPropertiesProxy(cellular()->dbus_path(),
482 cellular()->dbus_owner()));
483 DBusPropertiesMap properties(
484 properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM));
485 OnModemPropertiesChanged(properties, vector<string>());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400486
Jason Glasgowaf583282012-04-18 15:18:22 -0400487 properties = properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM_MODEM3GPP);
488 OnModem3GPPPropertiesChanged(properties, vector<string>());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400489}
490
491string CellularCapabilityUniversal::CreateFriendlyServiceName() {
Darin Petkova4ca3c32012-08-17 16:05:24 +0200492 SLOG(Cellular, 2) << __func__ << ": " << GetRoamingStateString();
493 string name = serving_operator_.GetName();
494 string home_provider_name = cellular()->home_provider().GetName();
495 if (!name.empty()) {
496 // If roaming, try to show "<home-provider> | <serving-operator>", per 3GPP
497 // rules (TS 31.102 and annex A of 122.101).
498 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING &&
499 !home_provider_name.empty()) {
500 return home_provider_name + " | " + name;
501 }
502 return name;
503 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400504 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME &&
Darin Petkova4ca3c32012-08-17 16:05:24 +0200505 !home_provider_name.empty()) {
506 return home_provider_name;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400507 }
Darin Petkova4ca3c32012-08-17 16:05:24 +0200508 string serving_operator_code = serving_operator_.GetCode();
509 if (!serving_operator_code.empty()) {
510 return "cellular_" + serving_operator_code;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400511 }
512 return base::StringPrintf("GSMNetwork%u", friendly_service_name_id_++);
513}
514
515void CellularCapabilityUniversal::SetHomeProvider() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700516 SLOG(Cellular, 2) << __func__ << "(IMSI: " << imsi_
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400517 << " SPN: " << spn_ << ")";
518 // TODO(petkov): The test for NULL provider_db should be done by
519 // mobile_provider_lookup_best_match.
520 if (imsi_.empty() || !cellular()->provider_db()) {
521 return;
522 }
523 mobile_provider *provider =
524 mobile_provider_lookup_best_match(
525 cellular()->provider_db(), spn_.c_str(), imsi_.c_str());
526 if (!provider) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700527 SLOG(Cellular, 2) << "GSM provider not found.";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400528 return;
529 }
Jason Glasgow4380f0d2012-05-03 18:05:04 -0400530
531 // Even if provider is the same as home_provider_, it is possible
532 // that the spn_ has changed. Run all the code below.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400533 home_provider_ = provider;
Darin Petkovf508c822012-09-21 13:43:17 +0200534 provider_requires_roaming_ = home_provider_->requires_roaming;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400535 Cellular::Operator oper;
Darin Petkovb4fccd22012-08-10 11:59:26 +0200536 if (provider->networks && provider->networks[0]) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400537 oper.SetCode(provider->networks[0]);
538 }
539 if (provider->country) {
540 oper.SetCountry(provider->country);
541 }
542 if (spn_.empty()) {
543 const char *name = mobile_provider_get_name(provider);
544 if (name) {
545 oper.SetName(name);
546 }
547 } else {
548 oper.SetName(spn_);
549 }
550 cellular()->set_home_provider(oper);
Darin Petkova4ca3c32012-08-17 16:05:24 +0200551 SLOG(Cellular, 2) << "Home provider: " << oper.GetCode() << ", "
Darin Petkovf508c822012-09-21 13:43:17 +0200552 << oper.GetName() << ", " << oper.GetCountry()
553 << (provider_requires_roaming_ ? ", roaming required" : "");
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400554 InitAPNList();
555}
556
Ben Chan6d0d1e72012-11-06 21:19:28 -0800557void CellularCapabilityUniversal::UpdateOLP() {
558 if (!cellular()->cellular_operator_info())
559 return;
560
561 CellularService::OLP olp;
562 if (!cellular()->cellular_operator_info()->GetOLP(operator_id_, &olp))
563 return;
564
565 string post_data = olp.GetPostData();
566 ReplaceSubstringsAfterOffset(&post_data, 0, "${esn}", esn_);
567 ReplaceSubstringsAfterOffset(&post_data, 0, "${iccid}", sim_identifier_);
568 ReplaceSubstringsAfterOffset(&post_data, 0, "${imei}", imei_);
569 ReplaceSubstringsAfterOffset(&post_data, 0, "${imsi}", imsi_);
570 ReplaceSubstringsAfterOffset(&post_data, 0, "${mdn}", mdn_);
571 ReplaceSubstringsAfterOffset(&post_data, 0, "${meid}", meid_);
572 ReplaceSubstringsAfterOffset(&post_data, 0, "${min}", min_);
573 olp.SetPostData(post_data);
574 cellular()->service()->SetOLP(olp);
575}
576
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400577void CellularCapabilityUniversal::UpdateOperatorInfo() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700578 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400579 const string &network_id = serving_operator_.GetCode();
580 if (!network_id.empty()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700581 SLOG(Cellular, 2) << "Looking up network id: " << network_id;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400582 mobile_provider *provider =
583 mobile_provider_lookup_by_network(cellular()->provider_db(),
584 network_id.c_str());
585 if (provider) {
Darin Petkova4ca3c32012-08-17 16:05:24 +0200586 if (serving_operator_.GetName().empty()) {
587 const char *provider_name = mobile_provider_get_name(provider);
588 if (provider_name && *provider_name) {
589 serving_operator_.SetName(provider_name);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400590 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400591 }
Darin Petkova4ca3c32012-08-17 16:05:24 +0200592 if (provider->country && *provider->country) {
593 serving_operator_.SetCountry(provider->country);
594 }
595 SLOG(Cellular, 2) << "Operator name: " << serving_operator_.GetName()
596 << ", country: " << serving_operator_.GetCountry();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400597 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700598 SLOG(Cellular, 2) << "GSM provider not found.";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400599 }
600 }
601 UpdateServingOperator();
602}
603
604void CellularCapabilityUniversal::UpdateServingOperator() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700605 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400606 if (cellular()->service().get()) {
607 cellular()->service()->SetServingOperator(serving_operator_);
608 }
609}
610
611void CellularCapabilityUniversal::InitAPNList() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700612 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400613 if (!home_provider_) {
614 return;
615 }
616 apn_list_.clear();
617 for (int i = 0; i < home_provider_->num_apns; ++i) {
618 Stringmap props;
619 mobile_apn *apn = home_provider_->apns[i];
620 if (apn->value) {
621 props[flimflam::kApnProperty] = apn->value;
622 }
623 if (apn->username) {
624 props[flimflam::kApnUsernameProperty] = apn->username;
625 }
626 if (apn->password) {
627 props[flimflam::kApnPasswordProperty] = apn->password;
628 }
629 // Find the first localized and non-localized name, if any.
630 const localized_name *lname = NULL;
631 const localized_name *name = NULL;
632 for (int j = 0; j < apn->num_names; ++j) {
633 if (apn->names[j]->lang) {
634 if (!lname) {
635 lname = apn->names[j];
636 }
637 } else if (!name) {
638 name = apn->names[j];
639 }
640 }
641 if (name) {
642 props[flimflam::kApnNameProperty] = name->name;
643 }
644 if (lname) {
645 props[flimflam::kApnLocalizedNameProperty] = lname->name;
646 props[flimflam::kApnLanguageProperty] = lname->lang;
647 }
648 apn_list_.push_back(props);
649 }
Darin Petkovdb6083f2012-08-16 12:50:23 +0200650 if (cellular()->adaptor()) {
651 cellular()->adaptor()->EmitStringmapsChanged(
652 flimflam::kCellularApnListProperty, apn_list_);
653 } else {
654 LOG(ERROR) << "Null RPC service adaptor.";
655 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400656}
657
Ben Chan15786032012-11-04 21:28:02 -0800658bool CellularCapabilityUniversal::IsServiceActivationRequired() const {
659 // If there is no online payment portal information, it's safer to assume
660 // the service does not require activation.
661 if (!cellular()->cellular_operator_info())
662 return false;
663
664 CellularService::OLP olp;
665 if (!cellular()->cellular_operator_info()->GetOLP(operator_id_, &olp))
666 return false;
667
668 // To avoid false positives, it's safer to assume the service does not
669 // require activation if MDN is not set.
670 if (mdn_.empty())
671 return false;
672
673 // If MDN contains only zeros ('+' and '-' characters are ignored),
674 // the service requires activation.
675 for (size_t i = 0; i < mdn_.size(); ++i) {
676 if (mdn_[i] != '0' && mdn_[i] != '-' && mdn_[i] != '+')
677 return false;
678 }
679 return true;
680}
681
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400682// always called from an async context
683void CellularCapabilityUniversal::Register(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700684 SLOG(Cellular, 2) << __func__ << " \"" << selected_network_ << "\"";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400685 CHECK(!callback.is_null());
686 Error error;
687 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
688 weak_ptr_factory_.GetWeakPtr(), callback);
689 modem_3gpp_proxy_->Register(selected_network_, &error, cb, kTimeoutRegister);
690 if (error.IsFailure())
691 callback.Run(error);
692}
693
694void CellularCapabilityUniversal::RegisterOnNetwork(
695 const string &network_id,
696 Error *error,
697 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700698 SLOG(Cellular, 2) << __func__ << "(" << network_id << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400699 CHECK(error);
700 desired_network_ = network_id;
701 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
702 weak_ptr_factory_.GetWeakPtr(), callback);
703 modem_3gpp_proxy_->Register(network_id, error, cb, kTimeoutRegister);
704}
705
706void CellularCapabilityUniversal::OnRegisterReply(
707 const ResultCallback &callback,
708 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700709 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400710
711 if (error.IsSuccess()) {
712 selected_network_ = desired_network_;
713 desired_network_.clear();
714 callback.Run(error);
715 return;
716 }
717 // If registration on the desired network failed,
718 // try to register on the home network.
719 if (!desired_network_.empty()) {
720 desired_network_.clear();
721 selected_network_.clear();
722 LOG(INFO) << "Couldn't register on selected network, trying home network";
723 Register(callback);
724 return;
725 }
726 callback.Run(error);
727}
728
729bool CellularCapabilityUniversal::IsRegistered() {
730 return (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
731 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING);
732}
733
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400734void CellularCapabilityUniversal::SetUnregistered(bool searching) {
735 // If we're already in some non-registered state, don't override that
736 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
737 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) {
738 registration_state_ =
739 (searching ? MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING :
740 MM_MODEM_3GPP_REGISTRATION_STATE_IDLE);
741 }
742}
743
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400744void CellularCapabilityUniversal::RequirePIN(
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400745 const string &pin, bool require,
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400746 Error *error, const ResultCallback &callback) {
747 CHECK(error);
748 sim_proxy_->EnablePin(pin, require, error, callback, kTimeoutDefault);
749}
750
751void CellularCapabilityUniversal::EnterPIN(const string &pin,
752 Error *error,
753 const ResultCallback &callback) {
754 CHECK(error);
755 sim_proxy_->SendPin(pin, error, callback, kTimeoutDefault);
756}
757
758void CellularCapabilityUniversal::UnblockPIN(const string &unblock_code,
759 const string &pin,
760 Error *error,
761 const ResultCallback &callback) {
762 CHECK(error);
763 sim_proxy_->SendPuk(unblock_code, pin, error, callback, kTimeoutDefault);
764}
765
766void CellularCapabilityUniversal::ChangePIN(
767 const string &old_pin, const string &new_pin,
768 Error *error, const ResultCallback &callback) {
769 CHECK(error);
770 sim_proxy_->ChangePin(old_pin, new_pin, error, callback, kTimeoutDefault);
771}
772
773void CellularCapabilityUniversal::Scan(Error *error,
774 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700775 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400776 CHECK(error);
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400777 if (scanning_) {
778 Error::PopulateAndLog(error, Error::kInProgress, "Already scanning");
779 return;
780 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400781 DBusPropertyMapsCallback cb = Bind(&CellularCapabilityUniversal::OnScanReply,
782 weak_ptr_factory_.GetWeakPtr(), callback);
783 modem_3gpp_proxy_->Scan(error, cb, kTimeoutScan);
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400784 if (!error->IsFailure()) {
785 scanning_ = true;
786 cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty,
787 scanning_);
788 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400789}
790
791void CellularCapabilityUniversal::OnScanReply(const ResultCallback &callback,
792 const ScanResults &results,
793 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700794 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400795
796 // Error handling is weak. The current expectation is that on any
797 // error, found_networks_ should be cleared and a property change
798 // notification sent out.
799 //
800 // TODO(jglasgow): fix error handling
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400801 scanning_ = false;
802 cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty,
803 scanning_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400804 found_networks_.clear();
805 if (!error.IsFailure()) {
806 for (ScanResults::const_iterator it = results.begin();
807 it != results.end(); ++it) {
808 found_networks_.push_back(ParseScanResult(*it));
809 }
810 }
811 cellular()->adaptor()->EmitStringmapsChanged(flimflam::kFoundNetworksProperty,
812 found_networks_);
Gary Morainceba6aa2012-05-03 10:28:26 -0700813
814 // TODO(gmorain): This check for is_null() is a work-around because
815 // Cellular::Scan() passes a null callback. Instead: 1. Have Cellular::Scan()
816 // pass in a callback. 2. Have Cellular "own" the found_networks_ property
817 // 3. Have Cellular EmitStingMapsChanged() 4. Share the code between GSM and
818 // Universal.
819 if (!callback.is_null())
820 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400821}
822
823Stringmap CellularCapabilityUniversal::ParseScanResult(
824 const ScanResult &result) {
825
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400826 /* ScanResults contain the following keys:
827
828 "status"
829 A MMModem3gppNetworkAvailability value representing network
830 availability status, given as an unsigned integer (signature "u").
831 This key will always be present.
832
833 "operator-long"
834 Long-format name of operator, given as a string value (signature
835 "s"). If the name is unknown, this field should not be present.
836
837 "operator-short"
838 Short-format name of operator, given as a string value
839 (signature "s"). If the name is unknown, this field should not
840 be present.
841
842 "operator-code"
843 Mobile code of the operator, given as a string value (signature
844 "s"). Returned in the format "MCCMNC", where MCC is the
845 three-digit ITU E.212 Mobile Country Code and MNC is the two- or
846 three-digit GSM Mobile Network Code. e.g. "31026" or "310260".
847
848 "access-technology"
849 A MMModemAccessTechnology value representing the generic access
850 technology used by this mobile network, given as an unsigned
851 integer (signature "u").
852 */
853 Stringmap parsed;
854
855 uint32 status;
856 if (DBusProperties::GetUint32(result, kStatusProperty, &status)) {
857 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
858 static const char * const kStatusString[] = {
859 "unknown", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_UNKNOWN
860 "available", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_AVAILABLE
861 "current", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_CURRENT
862 "forbidden", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_FORBIDDEN
863 };
864 parsed[flimflam::kStatusProperty] = kStatusString[status];
865 }
866
867 uint32 tech; // MMModemAccessTechnology
868 if (DBusProperties::GetUint32(result, kOperatorAccessTechnologyProperty,
869 &tech)) {
870 parsed[flimflam::kTechnologyProperty] = AccessTechnologyToString(tech);
871 }
872
873 string operator_long, operator_short, operator_code;
874 if (DBusProperties::GetString(result, kOperatorLongProperty, &operator_long))
875 parsed[flimflam::kLongNameProperty] = operator_long;
876 if (DBusProperties::GetString(result, kOperatorShortProperty,
877 &operator_short))
878 parsed[flimflam::kShortNameProperty] = operator_short;
879 if (DBusProperties::GetString(result, kOperatorCodeProperty, &operator_code))
880 parsed[flimflam::kNetworkIdProperty] = operator_code;
881
882 // If the long name is not available but the network ID is, look up the long
883 // name in the mobile provider database.
884 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
885 parsed[flimflam::kLongNameProperty].empty()) &&
886 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
887 mobile_provider *provider =
888 mobile_provider_lookup_by_network(
889 cellular()->provider_db(),
890 parsed[flimflam::kNetworkIdProperty].c_str());
891 if (provider) {
892 const char *long_name = mobile_provider_get_name(provider);
893 if (long_name && *long_name) {
894 parsed[flimflam::kLongNameProperty] = long_name;
895 }
896 }
897 }
898 return parsed;
899}
900
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400901string CellularCapabilityUniversal::GetNetworkTechnologyString() const {
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400902 // Order is important. Return the highest speed technology
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400903 // TODO(jglasgow): change shill interfaces to a capability model
904
905 return AccessTechnologyToString(access_technologies_);
906}
907
908string CellularCapabilityUniversal::GetRoamingStateString() const {
909 switch (registration_state_) {
910 case MM_MODEM_3GPP_REGISTRATION_STATE_HOME:
911 return flimflam::kRoamingStateHome;
912 case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING:
913 return flimflam::kRoamingStateRoaming;
914 default:
915 break;
916 }
917 return flimflam::kRoamingStateUnknown;
918}
919
920void CellularCapabilityUniversal::GetSignalQuality() {
Nathan Williams218cbcd2012-04-17 16:48:44 -0400921 // TODO(njw): Switch to asynchronous calls (crosbug.com/17583).
922 const DBus::Struct<unsigned int, bool> quality =
923 modem_proxy_->SignalQuality();
924 OnSignalQualityChanged(quality._1);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400925}
926
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400927string CellularCapabilityUniversal::GetTypeString() const {
928 return AccessTechnologyToTechnologyFamily(access_technologies_);
929}
930
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400931void CellularCapabilityUniversal::OnModemPropertiesChanged(
932 const DBusPropertiesMap &properties,
933 const vector<string> &/* invalidated_properties */) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400934 // This solves a bootstrapping problem: If the modem is not yet
935 // enabled, there are no proxy objects associated with the capability
936 // object, so modem signals like StateChanged aren't seen. By monitoring
937 // changes to the State property via the ModemManager, we're able to
938 // get the initialization process started, which will result in the
939 // creation of the proxy objects.
940 //
941 // The first time we see the change to State (when the modem state
942 // is Unknown), we simply update the state, and rely on the Manager to
943 // enable the device when it is registered with the Manager. On subsequent
944 // changes to State, we need to explicitly enable the device ourselves.
945 int32 istate;
Jason Glasgowaf583282012-04-18 15:18:22 -0400946 if (DBusProperties::GetInt32(properties, MM_MODEM_PROPERTY_STATE, &istate)) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400947 Cellular::ModemState state = static_cast<Cellular::ModemState>(istate);
Jason Glasgowaf583282012-04-18 15:18:22 -0400948 OnModemStateChanged(state);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400949 }
Jason Glasgowaf583282012-04-18 15:18:22 -0400950 string string_value;
Nathan Williamse9840802012-04-18 18:47:40 -0400951 if (DBusProperties::GetObjectPath(properties,
Jason Glasgowaf583282012-04-18 15:18:22 -0400952 MM_MODEM_PROPERTY_SIM, &string_value))
953 OnSimPathChanged(string_value);
954 uint32 uint_value;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400955 if (DBusProperties::GetUint32(properties,
Jason Glasgowaf583282012-04-18 15:18:22 -0400956 MM_MODEM_PROPERTY_MODEMCAPABILITIES,
957 &uint_value))
958 OnModemCapabilitesChanged(uint_value);
959 if (DBusProperties::GetUint32(properties,
960 MM_MODEM_PROPERTY_CURRENTCAPABILITIES,
961 &uint_value))
962 OnModemCurrentCapabilitiesChanged(uint_value);
963 // not needed: MM_MODEM_PROPERTY_MAXBEARERS
964 // not needed: MM_MODEM_PROPERTY_MAXACTIVEBEARERS
965 if (DBusProperties::GetString(properties,
966 MM_MODEM_PROPERTY_MANUFACTURER,
967 &string_value))
968 OnModemManufacturerChanged(string_value);
969 if (DBusProperties::GetString(properties,
970 MM_MODEM_PROPERTY_MODEL,
971 &string_value))
972 OnModemModelChanged(string_value);
973 if (DBusProperties::GetString(properties,
974 MM_MODEM_PROPERTY_REVISION,
975 &string_value))
976 OnModemRevisionChanged(string_value);
977 // not needed: MM_MODEM_PROPERTY_DEVICEIDENTIFIER
978 // not needed: MM_MODEM_PROPERTY_DEVICE
979 // not needed: MM_MODEM_PROPERTY_DRIVER
980 // not needed: MM_MODEM_PROPERTY_PLUGIN
981 // not needed: MM_MODEM_PROPERTY_EQUIPMENTIDENTIFIER
Nathan Williams218cbcd2012-04-17 16:48:44 -0400982
Jason Glasgowaf583282012-04-18 15:18:22 -0400983 // Unlock required and SimLock
984 bool locks_changed = false;
985 uint32_t unlock_required; // This is really of type MMModemLock
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400986 if (DBusProperties::GetUint32(properties,
987 MM_MODEM_PROPERTY_UNLOCKREQUIRED,
Jason Glasgowaf583282012-04-18 15:18:22 -0400988 &unlock_required)) {
989 locks_changed = true;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400990 }
Jason Glasgowaf583282012-04-18 15:18:22 -0400991 LockRetryData lock_retries;
992 DBusPropertiesMap::const_iterator it =
993 properties.find(MM_MODEM_PROPERTY_UNLOCKRETRIES);
994 if (it != properties.end()) {
995 lock_retries = it->second;
996 locks_changed = true;
997 }
998 if (locks_changed)
999 OnLockRetriesChanged(static_cast<MMModemLock>(unlock_required),
1000 lock_retries);
1001 if (DBusProperties::GetUint32(properties,
1002 MM_MODEM_PROPERTY_ACCESSTECHNOLOGIES,
1003 &uint_value))
1004 OnAccessTechnologiesChanged(uint_value);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001005
Jason Glasgowaf583282012-04-18 15:18:22 -04001006 it = properties.find(MM_MODEM_PROPERTY_SIGNALQUALITY);
1007 if (it != properties.end()) {
1008 DBus::Struct<unsigned int, bool> quality = it->second;
1009 OnSignalQualityChanged(quality._1);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001010 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001011 vector<string> numbers;
1012 if (DBusProperties::GetStrings(properties, MM_MODEM_PROPERTY_OWNNUMBERS,
1013 &numbers)) {
1014 string mdn;
1015 if (numbers.size() > 0)
1016 mdn = numbers[0];
1017 OnMdnChanged(mdn);
1018 }
1019 if (DBusProperties::GetUint32(properties, MM_MODEM_PROPERTY_SUPPORTEDMODES,
1020 &uint_value))
1021 OnSupportedModesChanged(uint_value);
1022 if (DBusProperties::GetUint32(properties, MM_MODEM_PROPERTY_ALLOWEDMODES,
1023 &uint_value))
1024 OnAllowedModesChanged(uint_value);
1025 if (DBusProperties::GetUint32(properties, MM_MODEM_PROPERTY_PREFERREDMODE,
1026 &uint_value))
1027 OnPreferredModeChanged(static_cast<MMModemMode>(uint_value));
1028 // au: MM_MODEM_PROPERTY_SUPPORTEDBANDS,
1029 // au: MM_MODEM_PROPERTY_BANDS
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001030}
1031
1032void CellularCapabilityUniversal::OnDBusPropertiesChanged(
1033 const string &interface,
1034 const DBusPropertiesMap &changed_properties,
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001035 const vector<string> &invalidated_properties) {
Jason Glasgow7234ec32012-05-23 16:01:21 -04001036 SLOG(Cellular, 2) << __func__ << "(" << interface << ")";
Jason Glasgowef965562012-04-10 16:12:35 -04001037 if (interface == MM_DBUS_INTERFACE_MODEM) {
Jason Glasgow4c0724a2012-04-17 15:47:40 -04001038 OnModemPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgowef965562012-04-10 16:12:35 -04001039 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001040 if (interface == MM_DBUS_INTERFACE_MODEM_MODEM3GPP) {
1041 OnModem3GPPPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001042 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001043 if (interface == MM_DBUS_INTERFACE_SIM) {
1044 OnSimPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001045 }
1046}
1047
Jason Glasgow14521872012-05-07 19:12:15 -04001048bool CellularCapabilityUniversal::RetriableConnectError(
1049 const Error &error) const {
1050 if (error.type() == Error::kInvalidApn)
1051 return true;
1052
1053 // modemmanager does not ever return kInvalidApn for E362 modems
1054 // with 1.41 firmware. It remains to be seem if this will change
1055 // with 3.x firmware.
1056 if ((model_id_ == kE362ModelId) && (error.type() == Error::kOperationFailed))
1057 return true;
1058
1059 return false;
1060}
1061
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001062void CellularCapabilityUniversal::OnNetworkModeSignal(uint32 /*mode*/) {
1063 // TODO(petkov): Implement this.
1064 NOTIMPLEMENTED();
1065}
1066
Jason Glasgowaf583282012-04-18 15:18:22 -04001067void CellularCapabilityUniversal::OnSimPathChanged(
1068 const string &sim_path) {
1069 if (sim_path == sim_path_)
1070 return;
1071
1072 mm1::SimProxyInterface *proxy = NULL;
1073 if (!sim_path.empty())
1074 proxy = proxy_factory()->CreateSimProxy(sim_path,
1075 cellular()->dbus_owner());
1076 sim_path_ = sim_path;
1077 sim_proxy_.reset(proxy);
1078
1079 if (sim_path.empty()) {
1080 // Clear all data about the sim
Jason Glasgow4380f0d2012-05-03 18:05:04 -04001081 imsi_ = "";
1082 spn_ = "";
Ben Chanbd3aee82012-10-16 23:52:04 -07001083 sim_present_ = false;
Jason Glasgowaf583282012-04-18 15:18:22 -04001084 OnSimIdentifierChanged("");
1085 OnOperatorIdChanged("");
Jason Glasgowaf583282012-04-18 15:18:22 -04001086 } else {
Ben Chanbd3aee82012-10-16 23:52:04 -07001087 sim_present_ = true;
Jason Glasgowaf583282012-04-18 15:18:22 -04001088 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
1089 proxy_factory()->CreateDBusPropertiesProxy(sim_path,
1090 cellular()->dbus_owner()));
1091 // TODO(jglasgow): convert to async interface
1092 DBusPropertiesMap properties(
1093 properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
1094 OnSimPropertiesChanged(properties, vector<string>());
1095 }
1096}
1097
1098void CellularCapabilityUniversal::OnModemCapabilitesChanged(
1099 uint32 capabilities) {
1100 capabilities_ = capabilities;
1101}
1102
1103void CellularCapabilityUniversal::OnModemCurrentCapabilitiesChanged(
1104 uint32 current_capabilities) {
1105 current_capabilities_ = current_capabilities;
1106}
1107
1108void CellularCapabilityUniversal::OnMdnChanged(
1109 const string &mdn) {
1110 mdn_ = mdn;
1111}
1112
1113void CellularCapabilityUniversal::OnModemManufacturerChanged(
1114 const string &manufacturer) {
1115 manufacturer_ = manufacturer;
1116}
1117
1118void CellularCapabilityUniversal::OnModemModelChanged(
1119 const string &model) {
1120 model_id_ = model;
1121}
1122
1123void CellularCapabilityUniversal::OnModemRevisionChanged(
1124 const string &revision) {
1125 firmware_revision_ = revision;
1126}
1127
1128void CellularCapabilityUniversal::OnModemStateChanged(
1129 Cellular::ModemState state) {
1130 Cellular::ModemState prev_modem_state = cellular()->modem_state();
1131 bool was_enabled = cellular()->IsUnderlyingDeviceEnabled();
1132 if (Cellular::IsEnabledModemState(state))
1133 cellular()->set_modem_state(state);
Gary Moraine285a842012-08-15 08:23:57 -07001134 SLOG(Cellular, 2) << __func__ << ": prev_modem_state: " << prev_modem_state
1135 << " was_enabled: " << was_enabled
1136 << " cellular state: "
1137 << cellular()->GetStateString(cellular()->state());
Jason Glasgowaf583282012-04-18 15:18:22 -04001138 if (prev_modem_state != Cellular::kModemStateUnknown &&
1139 prev_modem_state != Cellular::kModemStateEnabling &&
1140 !was_enabled &&
1141 cellular()->state() == Cellular::kStateDisabled &&
1142 cellular()->IsUnderlyingDeviceEnabled()) {
1143 cellular()->SetEnabled(true);
1144 }
1145}
1146
1147void CellularCapabilityUniversal::OnAccessTechnologiesChanged(
1148 uint32 access_technologies) {
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001149 if (access_technologies_ != access_technologies) {
Jason Glasgowbad114b2012-05-21 15:24:16 -04001150 const string old_type_string(GetTypeString());
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001151 access_technologies_ = access_technologies;
Jason Glasgowbad114b2012-05-21 15:24:16 -04001152 const string new_type_string(GetTypeString());
1153 if (new_type_string != old_type_string) {
1154 // TODO(jglasgow): address layering violation of emitting change
1155 // signal here for a property owned by Cellular.
1156 cellular()->adaptor()->EmitStringChanged(
1157 flimflam::kTechnologyFamilyProperty, new_type_string);
1158 }
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001159 if (cellular()->service().get()) {
1160 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
1161 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001162 }
1163}
1164
1165void CellularCapabilityUniversal::OnSupportedModesChanged(
1166 uint32 supported_modes) {
1167 supported_modes_ = supported_modes;
1168}
1169
1170void CellularCapabilityUniversal::OnAllowedModesChanged(
1171 uint32 allowed_modes) {
1172 allowed_modes_ = allowed_modes;
1173}
1174
1175void CellularCapabilityUniversal::OnPreferredModeChanged(
1176 MMModemMode preferred_mode) {
1177 preferred_mode_ = preferred_mode;
1178}
1179
1180void CellularCapabilityUniversal::OnLockRetriesChanged(
1181 MMModemLock unlock_required,
1182 const LockRetryData &lock_retries) {
Jason Glasgowd4af81d2012-05-03 22:25:05 -04001183 switch (unlock_required) {
Jason Glasgowaf583282012-04-18 15:18:22 -04001184 case MM_MODEM_LOCK_SIM_PIN:
1185 sim_lock_status_.lock_type = "sim-pin";
1186 break;
1187 case MM_MODEM_LOCK_SIM_PUK:
1188 sim_lock_status_.lock_type = "sim-puk";
1189 break;
1190 default:
1191 sim_lock_status_.lock_type = "";
1192 break;
1193 }
1194 LockRetryData::const_iterator it = lock_retries.find(unlock_required);
1195 if (it != lock_retries.end()) {
1196 sim_lock_status_.retries_left = it->second;
1197 } else {
1198 // Unknown, use 999
1199 sim_lock_status_.retries_left = 999;
1200 }
1201 OnSimLockStatusChanged();
1202}
1203
1204void CellularCapabilityUniversal::OnSimLockStatusChanged() {
1205 cellular()->adaptor()->EmitKeyValueStoreChanged(
1206 flimflam::kSIMLockStatusProperty, SimLockStatusToProperty(NULL));
1207}
1208
1209void CellularCapabilityUniversal::OnModem3GPPPropertiesChanged(
1210 const DBusPropertiesMap &properties,
1211 const vector<string> &/* invalidated_properties */) {
Ben Chan6d0d1e72012-11-06 21:19:28 -08001212 SLOG(Cellular, 2) << __func__;
Jason Glasgowaf583282012-04-18 15:18:22 -04001213 string imei;
1214 if (DBusProperties::GetString(properties,
1215 MM_MODEM_MODEM3GPP_PROPERTY_IMEI,
1216 &imei))
1217 OnImeiChanged(imei);
1218
1219 // Handle registration state changes as a single change
1220 string operator_code = serving_operator_.GetCode();
1221 string operator_name = serving_operator_.GetName();
1222 MMModem3gppRegistrationState state = registration_state_;
1223 bool registration_changed = false;
1224 uint32 uint_value;
1225 if (DBusProperties::GetUint32(properties,
1226 MM_MODEM_MODEM3GPP_PROPERTY_REGISTRATIONSTATE,
1227 &uint_value)) {
1228 state = static_cast<MMModem3gppRegistrationState>(uint_value);
1229 registration_changed = true;
1230 }
1231 if (DBusProperties::GetString(properties,
1232 MM_MODEM_MODEM3GPP_PROPERTY_OPERATORCODE,
1233 &operator_code))
1234 registration_changed = true;
1235 if (DBusProperties::GetString(properties,
1236 MM_MODEM_MODEM3GPP_PROPERTY_OPERATORNAME,
1237 &operator_name))
1238 registration_changed = true;
1239 if (registration_changed)
1240 On3GPPRegistrationChanged(state, operator_code, operator_name);
1241
1242 uint32 locks = 0;
1243 if (DBusProperties::GetUint32(
1244 properties, MM_MODEM_MODEM3GPP_PROPERTY_ENABLEDFACILITYLOCKS,
1245 &locks))
1246 OnFacilityLocksChanged(locks);
1247}
1248
1249void CellularCapabilityUniversal::OnImeiChanged(const string &imei) {
1250 imei_ = imei;
1251}
1252
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001253void CellularCapabilityUniversal::On3GPPRegistrationChanged(
1254 MMModem3gppRegistrationState state,
1255 const string &operator_code,
1256 const string &operator_name) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001257 SLOG(Cellular, 2) << __func__ << ": regstate=" << state
1258 << ", opercode=" << operator_code
1259 << ", opername=" << operator_name;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001260 registration_state_ = state;
1261 serving_operator_.SetCode(operator_code);
1262 serving_operator_.SetName(operator_name);
1263 UpdateOperatorInfo();
1264 cellular()->HandleNewRegistrationState();
1265}
1266
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001267void CellularCapabilityUniversal::OnModemStateChangedSignal(
1268 int32 old_state, int32 new_state, uint32 reason) {
Eric Shienbrood9b1bd7b2012-04-20 16:42:26 -04001269 SLOG(Cellular, 2) << __func__ << "(" << old_state << ", " << new_state << ", "
1270 << reason << ")";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001271 cellular()->OnModemStateChanged(static_cast<Cellular::ModemState>(old_state),
1272 static_cast<Cellular::ModemState>(new_state),
1273 reason);
Gary Moraine285a842012-08-15 08:23:57 -07001274 if (!deferred_enable_modem_callback_.is_null() &&
1275 (new_state == Cellular::kModemStateDisabled)) {
1276 SLOG(Cellular, 2) << "Enabling modem after deferring";
1277 deferred_enable_modem_callback_.Run();
1278 deferred_enable_modem_callback_.Reset();
1279 }
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001280}
1281
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001282void CellularCapabilityUniversal::OnSignalQualityChanged(uint32 quality) {
1283 cellular()->HandleNewSignalQuality(quality);
1284}
1285
Jason Glasgowaf583282012-04-18 15:18:22 -04001286void CellularCapabilityUniversal::OnFacilityLocksChanged(uint32 locks) {
1287 if (sim_lock_status_.enabled != (locks & MM_MODEM_3GPP_FACILITY_SIM)) {
1288 sim_lock_status_.enabled = locks & MM_MODEM_3GPP_FACILITY_SIM;
1289 OnSimLockStatusChanged();
1290 }
1291}
Jason Glasgowef965562012-04-10 16:12:35 -04001292
Jason Glasgowaf583282012-04-18 15:18:22 -04001293void CellularCapabilityUniversal::OnSimPropertiesChanged(
1294 const DBusPropertiesMap &props,
1295 const vector<string> &/* invalidated_properties */) {
Ben Chan6d0d1e72012-11-06 21:19:28 -08001296 SLOG(Cellular, 2) << __func__;
Jason Glasgowaf583282012-04-18 15:18:22 -04001297 string value;
Jason Glasgow4380f0d2012-05-03 18:05:04 -04001298 bool must_update_home_provider = false;
Jason Glasgowaf583282012-04-18 15:18:22 -04001299 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_SIMIDENTIFIER, &value))
1300 OnSimIdentifierChanged(value);
1301 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORIDENTIFIER,
1302 &value))
1303 OnOperatorIdChanged(value);
Jason Glasgow4380f0d2012-05-03 18:05:04 -04001304 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORNAME, &value)) {
1305 spn_ = value;
1306 must_update_home_provider = true;
1307 }
1308 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_IMSI, &value)) {
1309 imsi_ = value;
1310 must_update_home_provider = true;
1311 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001312 // TODO(jglasgow): May eventually want to get SPDI, etc
Jason Glasgowaf583282012-04-18 15:18:22 -04001313
Jason Glasgow4380f0d2012-05-03 18:05:04 -04001314 if (must_update_home_provider)
1315 SetHomeProvider();
Jason Glasgowaf583282012-04-18 15:18:22 -04001316}
1317
1318void CellularCapabilityUniversal::OnSimIdentifierChanged(const string &id) {
1319 sim_identifier_ = id;
1320}
1321
1322void CellularCapabilityUniversal::OnOperatorIdChanged(
1323 const string &operator_id) {
Ben Chan6d0d1e72012-11-06 21:19:28 -08001324 SLOG(Cellular, 2) << "Operator ID = '" << operator_id << "'";
Jason Glasgowaf583282012-04-18 15:18:22 -04001325 operator_id_ = operator_id;
1326}
1327
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001328} // namespace shill