blob: 461b3bf2e84d1af866e71c345e0fefc90789a800 [file] [log] [blame]
Darin Petkovc64fe5e2012-01-11 12:46:13 +01001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Darin Petkovdaf43862011-10-27 11:37:28 +02002// 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_gsm.h"
6
Eric Shienbrood3e20a232012-02-16 11:35:56 -05007#include <base/bind.h>
Darin Petkovdaf43862011-10-27 11:37:28 +02008#include <base/logging.h>
Eric Shienbrood3e20a232012-02-16 11:35:56 -05009#include <base/stl_util.h>
Darin Petkov1272a432011-11-10 15:53:37 +010010#include <base/string_number_conversions.h>
Darin Petkovac635a82012-01-10 16:51:58 +010011#include <base/stringprintf.h>
Darin Petkov20c13ec2011-11-09 15:07:15 +010012#include <chromeos/dbus/service_constants.h>
13#include <mm/mm-modem.h>
Darin Petkov1272a432011-11-10 15:53:37 +010014#include <mobile_provider.h>
Darin Petkovdaf43862011-10-27 11:37:28 +020015
Darin Petkov3cfbf212011-11-21 16:02:09 +010016#include "shill/adaptor_interfaces.h"
Darin Petkovae0c64e2011-11-15 15:50:27 +010017#include "shill/cellular_service.h"
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050018#include "shill/error.h"
Darin Petkov721ac932011-11-16 15:43:09 +010019#include "shill/property_accessor.h"
Darin Petkovdaf43862011-10-27 11:37:28 +020020#include "shill/proxy_factory.h"
21
Eric Shienbrood3e20a232012-02-16 11:35:56 -050022using base::Bind;
Darin Petkovb05315f2011-11-07 10:14:25 +010023using std::string;
24
Darin Petkovdaf43862011-10-27 11:37:28 +020025namespace shill {
26
Darin Petkovac635a82012-01-10 16:51:58 +010027// static
28unsigned int CellularCapabilityGSM::friendly_service_name_id_ = 0;
29
Darin Petkov1272a432011-11-10 15:53:37 +010030const char CellularCapabilityGSM::kNetworkPropertyAccessTechnology[] =
31 "access-tech";
32const char CellularCapabilityGSM::kNetworkPropertyID[] = "operator-num";
33const char CellularCapabilityGSM::kNetworkPropertyLongName[] = "operator-long";
34const char CellularCapabilityGSM::kNetworkPropertyShortName[] =
35 "operator-short";
36const char CellularCapabilityGSM::kNetworkPropertyStatus[] = "status";
Darin Petkovae0c64e2011-11-15 15:50:27 +010037const char CellularCapabilityGSM::kPhoneNumber[] = "*99#";
38const char CellularCapabilityGSM::kPropertyAccessTechnology[] =
39 "AccessTechnology";
Darin Petkov63138a92012-02-06 14:09:15 +010040const char CellularCapabilityGSM::kPropertyEnabledFacilityLocks[] =
41 "EnabledFacilityLocks";
Darin Petkov721ac932011-11-16 15:43:09 +010042const char CellularCapabilityGSM::kPropertyUnlockRequired[] = "UnlockRequired";
43const char CellularCapabilityGSM::kPropertyUnlockRetries[] = "UnlockRetries";
Darin Petkov1272a432011-11-10 15:53:37 +010044
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050045CellularCapabilityGSM::CellularCapabilityGSM(Cellular *cellular,
46 ProxyFactory *proxy_factory)
Jason Glasgow82f9ab32012-04-04 14:27:19 -040047 : CellularCapabilityClassic(cellular, proxy_factory),
Eric Shienbrood3e20a232012-02-16 11:35:56 -050048 weak_ptr_factory_(this),
Darin Petkov184c54e2011-11-15 12:44:39 +010049 registration_state_(MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN),
Darin Petkovae0c64e2011-11-15 15:50:27 +010050 access_technology_(MM_MODEM_GSM_ACCESS_TECH_UNKNOWN),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +010051 home_provider_(NULL),
Darin Petkov1272a432011-11-10 15:53:37 +010052 scanning_(false),
53 scan_interval_(0) {
Darin Petkov5f316f62011-11-18 12:10:26 +010054 VLOG(2) << "Cellular capability constructed: GSM";
Darin Petkov1272a432011-11-10 15:53:37 +010055 PropertyStore *store = cellular->mutable_store();
Darin Petkov184c54e2011-11-15 12:44:39 +010056 store->RegisterConstString(flimflam::kSelectedNetworkProperty,
57 &selected_network_);
Darin Petkov1272a432011-11-10 15:53:37 +010058 store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
59 &found_networks_);
60 store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
61 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
Darin Petkov63138a92012-02-06 14:09:15 +010062 HelpRegisterDerivedKeyValueStore(
63 flimflam::kSIMLockStatusProperty,
64 &CellularCapabilityGSM::SimLockStatusToProperty,
65 NULL);
Darin Petkov3cfbf212011-11-21 16:02:09 +010066 store->RegisterConstStringmaps(flimflam::kCellularApnListProperty,
67 &apn_list_);
Darin Petkov0d06f7d2012-02-03 13:08:19 +010068 scanning_supported_ = true;
Darin Petkov1272a432011-11-10 15:53:37 +010069}
Darin Petkovdaf43862011-10-27 11:37:28 +020070
Darin Petkov63138a92012-02-06 14:09:15 +010071KeyValueStore CellularCapabilityGSM::SimLockStatusToProperty(Error */*error*/) {
72 KeyValueStore status;
73 status.SetBool(flimflam::kSIMLockEnabledProperty, sim_lock_status_.enabled);
74 status.SetString(flimflam::kSIMLockTypeProperty, sim_lock_status_.lock_type);
75 status.SetUint(flimflam::kSIMLockRetriesLeftProperty,
76 sim_lock_status_.retries_left);
77 return status;
Darin Petkov721ac932011-11-16 15:43:09 +010078}
79
Darin Petkov63138a92012-02-06 14:09:15 +010080void CellularCapabilityGSM::HelpRegisterDerivedKeyValueStore(
Darin Petkov721ac932011-11-16 15:43:09 +010081 const string &name,
Darin Petkov63138a92012-02-06 14:09:15 +010082 KeyValueStore(CellularCapabilityGSM::*get)(Error *error),
83 void(CellularCapabilityGSM::*set)(
84 const KeyValueStore &value, Error *error)) {
85 cellular()->mutable_store()->RegisterDerivedKeyValueStore(
Darin Petkov721ac932011-11-16 15:43:09 +010086 name,
Darin Petkov63138a92012-02-06 14:09:15 +010087 KeyValueStoreAccessor(
88 new CustomAccessor<CellularCapabilityGSM, KeyValueStore>(
Darin Petkov721ac932011-11-16 15:43:09 +010089 this, get, set)));
90}
91
Eric Shienbrood9a245532012-03-07 14:20:39 -050092void CellularCapabilityGSM::InitProxies() {
Jason Glasgow82f9ab32012-04-04 14:27:19 -040093 CellularCapabilityClassic::InitProxies();
Darin Petkovcb547732011-11-09 13:55:26 +010094 card_proxy_.reset(
Eric Shienbrood9a245532012-03-07 14:20:39 -050095 proxy_factory()->CreateModemGSMCardProxy(cellular()->dbus_path(),
Darin Petkovdaf43862011-10-27 11:37:28 +020096 cellular()->dbus_owner()));
Darin Petkov184c54e2011-11-15 12:44:39 +010097 network_proxy_.reset(
Eric Shienbrood9a245532012-03-07 14:20:39 -050098 proxy_factory()->CreateModemGSMNetworkProxy(cellular()->dbus_path(),
Darin Petkovdaf43862011-10-27 11:37:28 +020099 cellular()->dbus_owner()));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500100 network_proxy_->set_signal_quality_callback(
101 Bind(&CellularCapabilityGSM::OnSignalQualitySignal,
102 weak_ptr_factory_.GetWeakPtr()));
103 network_proxy_->set_network_mode_callback(
104 Bind(&CellularCapabilityGSM::OnNetworkModeSignal,
105 weak_ptr_factory_.GetWeakPtr()));
106 network_proxy_->set_registration_info_callback(
107 Bind(&CellularCapabilityGSM::OnRegistrationInfoSignal,
108 weak_ptr_factory_.GetWeakPtr()));
Darin Petkovdaf43862011-10-27 11:37:28 +0200109}
110
Eric Shienbrood9a245532012-03-07 14:20:39 -0500111void CellularCapabilityGSM::StartModem(Error *error,
112 const ResultCallback &callback) {
113 InitProxies();
114
115 CellularTaskList *tasks = new CellularTaskList();
116 ResultCallback cb =
117 Bind(&CellularCapabilityGSM::StepCompletedCallback,
Thieu Le923006b2012-04-05 16:32:58 -0700118 weak_ptr_factory_.GetWeakPtr(), callback, false, tasks);
119 ResultCallback cb_ignore_error =
120 Bind(&CellularCapabilityGSM::StepCompletedCallback,
121 weak_ptr_factory_.GetWeakPtr(), callback, true, tasks);
Eric Shienbrood9a245532012-03-07 14:20:39 -0500122 tasks->push_back(Bind(&CellularCapabilityGSM::EnableModem,
123 weak_ptr_factory_.GetWeakPtr(), cb));
124 tasks->push_back(Bind(&CellularCapabilityGSM::Register,
125 weak_ptr_factory_.GetWeakPtr(), cb));
126 tasks->push_back(Bind(&CellularCapabilityGSM::GetModemStatus,
127 weak_ptr_factory_.GetWeakPtr(), cb));
128 tasks->push_back(Bind(&CellularCapabilityGSM::GetIMEI,
129 weak_ptr_factory_.GetWeakPtr(), cb));
130 tasks->push_back(Bind(&CellularCapabilityGSM::GetIMSI,
131 weak_ptr_factory_.GetWeakPtr(), cb));
132 tasks->push_back(Bind(&CellularCapabilityGSM::GetSPN,
Thieu Le923006b2012-04-05 16:32:58 -0700133 weak_ptr_factory_.GetWeakPtr(), cb_ignore_error));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500134 tasks->push_back(Bind(&CellularCapabilityGSM::GetMSISDN,
Thieu Le923006b2012-04-05 16:32:58 -0700135 weak_ptr_factory_.GetWeakPtr(), cb_ignore_error));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500136 tasks->push_back(Bind(&CellularCapabilityGSM::GetProperties,
137 weak_ptr_factory_.GetWeakPtr(), cb));
138 tasks->push_back(Bind(&CellularCapabilityGSM::GetModemInfo,
139 weak_ptr_factory_.GetWeakPtr(), cb));
140 tasks->push_back(Bind(&CellularCapabilityGSM::FinishEnable,
141 weak_ptr_factory_.GetWeakPtr(), cb));
142
143 RunNextStep(tasks);
144}
145
Eric Shienbrood9a245532012-03-07 14:20:39 -0500146void CellularCapabilityGSM::ReleaseProxies() {
147 VLOG(2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400148 CellularCapabilityClassic::ReleaseProxies();
Darin Petkov721ac932011-11-16 15:43:09 +0100149 card_proxy_.reset();
150 network_proxy_.reset();
151}
152
Darin Petkov5f316f62011-11-18 12:10:26 +0100153void CellularCapabilityGSM::OnServiceCreated() {
Darin Petkov31332412012-01-28 01:50:02 +0100154 // If IMSI is available, base the service's storage identifier on it.
155 if (!imsi_.empty()) {
156 cellular()->service()->SetStorageIdentifier(
Darin Petkovdd3e8662012-02-03 13:16:20 +0100157 string(flimflam::kTypeCellular) + "_" +
158 cellular()->address() + "_" + imsi_);
Darin Petkov31332412012-01-28 01:50:02 +0100159 }
Darin Petkovb9c99332012-01-12 13:13:00 +0100160 cellular()->service()->SetActivationState(
Darin Petkov5f316f62011-11-18 12:10:26 +0100161 flimflam::kActivationStateActivated);
162 UpdateServingOperator();
163}
164
Darin Petkovae0c64e2011-11-15 15:50:27 +0100165void CellularCapabilityGSM::UpdateStatus(const DBusPropertiesMap &properties) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500166 if (ContainsKey(properties, kPropertyIMSI)) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100167 SetHomeProvider();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100168 }
169}
170
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400171// Create the list of APNs to try, in the following order:
172// - last APN that resulted in a successful connection attempt on the
173// current network (if any)
174// - the APN, if any, that was set by the user
175// - the list of APNs found in the mobile broadband provider DB for the
176// home provider associated with the current SIM
177// - as a last resort, attempt to connect with no APN
178void CellularCapabilityGSM::SetupApnTryList() {
179 apn_try_list_.clear();
180
181 DCHECK(cellular()->service().get());
182 const Stringmap *apn_info = cellular()->service()->GetLastGoodApn();
183 if (apn_info)
184 apn_try_list_.push_back(*apn_info);
185
186 apn_info = cellular()->service()->GetUserSpecifiedApn();
187 if (apn_info)
188 apn_try_list_.push_back(*apn_info);
189
190 apn_try_list_.insert(apn_try_list_.end(), apn_list_.begin(), apn_list_.end());
191}
192
Darin Petkovae0c64e2011-11-15 15:50:27 +0100193void CellularCapabilityGSM::SetupConnectProperties(
194 DBusPropertiesMap *properties) {
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400195 SetupApnTryList();
196 FillConnectPropertyMap(properties);
197}
198
199void CellularCapabilityGSM::FillConnectPropertyMap(
200 DBusPropertiesMap *properties) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500201 (*properties)[kConnectPropertyPhoneNumber].writer().append_string(
Darin Petkovae0c64e2011-11-15 15:50:27 +0100202 kPhoneNumber);
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400203
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400204 if (!AllowRoaming())
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400205 (*properties)[kConnectPropertyHomeOnly].writer().append_bool(true);
206
207 if (!apn_try_list_.empty()) {
208 // Leave the APN at the front of the list, so that it can be recorded
209 // if the connect attempt succeeds.
210 Stringmap apn_info = apn_try_list_.front();
211 VLOG(2) << __func__ << ": Using APN " << apn_info[flimflam::kApnProperty];
212 (*properties)[kConnectPropertyApn].writer().append_string(
213 apn_info[flimflam::kApnProperty].c_str());
214 if (ContainsKey(apn_info, flimflam::kApnUsernameProperty))
215 (*properties)[kConnectPropertyApnUsername].writer().append_string(
216 apn_info[flimflam::kApnUsernameProperty].c_str());
217 if (ContainsKey(apn_info, flimflam::kApnPasswordProperty))
218 (*properties)[kConnectPropertyApnPassword].writer().append_string(
219 apn_info[flimflam::kApnPasswordProperty].c_str());
220 }
221}
222
223void CellularCapabilityGSM::OnConnectReply(const ResultCallback &callback,
224 const Error &error) {
225 if (error.IsFailure()) {
226 cellular()->service()->ClearLastGoodApn();
227 // The APN that was just tried (and failed) is still at the
228 // front of the list, about to be removed. If the list is empty
229 // after that, try one last time without an APN. This may succeed
230 // with some modems in some cases.
231 if (error.type() == Error::kInvalidApn && !apn_try_list_.empty()) {
232 apn_try_list_.pop_front();
233 VLOG(2) << "Connect failed with invalid APN, " << apn_try_list_.size()
234 << " remaining APNs to try";
235 DBusPropertiesMap props;
236 FillConnectPropertyMap(&props);
237 Error error;
238 Connect(props, &error, callback);
239 return;
240 }
241 } else if (!apn_try_list_.empty()) {
242 cellular()->service()->SetLastGoodApn(apn_try_list_.front());
243 apn_try_list_.clear();
244 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400245 CellularCapabilityClassic::OnConnectReply(callback, error);
246}
247
248bool CellularCapabilityGSM::AllowRoaming() {
249 bool requires_roaming =
250 home_provider_ ? home_provider_->requires_roaming : false;
251 return requires_roaming || allow_roaming_property();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100252}
253
Eric Shienbrood9a245532012-03-07 14:20:39 -0500254// always called from an async context
255void CellularCapabilityGSM::GetIMEI(const ResultCallback &callback) {
Darin Petkovcb547732011-11-09 13:55:26 +0100256 VLOG(2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500257 CHECK(!callback.is_null());
258 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500259 if (imei_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500260 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetIMEIReply,
261 weak_ptr_factory_.GetWeakPtr(), callback);
262 card_proxy_->GetIMEI(&error, cb, kTimeoutDefault);
263 if (error.IsFailure())
264 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500265 } else {
266 VLOG(2) << "Already have IMEI " << imei_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500267 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100268 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500269}
270
Eric Shienbrood9a245532012-03-07 14:20:39 -0500271// always called from an async context
272void CellularCapabilityGSM::GetIMSI(const ResultCallback &callback) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500273 VLOG(2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500274 CHECK(!callback.is_null());
275 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500276 if (imsi_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500277 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetIMSIReply,
278 weak_ptr_factory_.GetWeakPtr(),
279 callback);
280 card_proxy_->GetIMSI(&error, cb, kTimeoutDefault);
281 if (error.IsFailure())
282 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500283 } else {
284 VLOG(2) << "Already have IMSI " << imsi_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500285 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100286 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500287}
288
Eric Shienbrood9a245532012-03-07 14:20:39 -0500289// always called from an async context
290void CellularCapabilityGSM::GetSPN(const ResultCallback &callback) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500291 VLOG(2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500292 CHECK(!callback.is_null());
293 Error error;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100294 if (spn_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500295 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetSPNReply,
296 weak_ptr_factory_.GetWeakPtr(),
297 callback);
298 card_proxy_->GetSPN(&error, cb, kTimeoutDefault);
299 if (error.IsFailure())
300 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500301 } else {
302 VLOG(2) << "Already have SPN " << spn_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500303 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100304 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500305}
306
Eric Shienbrood9a245532012-03-07 14:20:39 -0500307// always called from an async context
308void CellularCapabilityGSM::GetMSISDN(const ResultCallback &callback) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500309 VLOG(2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500310 CHECK(!callback.is_null());
311 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500312 if (mdn_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500313 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetMSISDNReply,
314 weak_ptr_factory_.GetWeakPtr(),
315 callback);
316 card_proxy_->GetMSISDN(&error, cb, kTimeoutDefault);
317 if (error.IsFailure())
318 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500319 } else {
320 VLOG(2) << "Already have MSISDN " << mdn_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500321 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100322 }
323}
324
Darin Petkov3e509242011-11-10 14:46:44 +0100325void CellularCapabilityGSM::GetSignalQuality() {
326 VLOG(2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500327 SignalQualityCallback callback =
328 Bind(&CellularCapabilityGSM::OnGetSignalQualityReply,
329 weak_ptr_factory_.GetWeakPtr());
330 network_proxy_->GetSignalQuality(NULL, callback, kTimeoutDefault);
Darin Petkov3e509242011-11-10 14:46:44 +0100331}
332
Eric Shienbrood9a245532012-03-07 14:20:39 -0500333void CellularCapabilityGSM::GetRegistrationState() {
Darin Petkov184c54e2011-11-15 12:44:39 +0100334 VLOG(2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500335 RegistrationInfoCallback callback =
336 Bind(&CellularCapabilityGSM::OnGetRegistrationInfoReply,
337 weak_ptr_factory_.GetWeakPtr());
338 network_proxy_->GetRegistrationInfo(NULL, callback, kTimeoutDefault);
Darin Petkov184c54e2011-11-15 12:44:39 +0100339}
340
Eric Shienbrood9a245532012-03-07 14:20:39 -0500341void CellularCapabilityGSM::GetProperties(const ResultCallback &callback) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100342 VLOG(2) << __func__;
Darin Petkov63138a92012-02-06 14:09:15 +0100343
Darin Petkov184c54e2011-11-15 12:44:39 +0100344 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
345 uint32 tech = network_proxy_->AccessTechnology();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100346 SetAccessTechnology(tech);
Darin Petkov184c54e2011-11-15 12:44:39 +0100347 VLOG(2) << "GSM AccessTechnology: " << tech;
Darin Petkov63138a92012-02-06 14:09:15 +0100348
349 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
350 uint32 locks = card_proxy_->EnabledFacilityLocks();
351 sim_lock_status_.enabled = locks & MM_MODEM_GSM_FACILITY_SIM;
352 VLOG(2) << "GSM EnabledFacilityLocks: " << locks;
353
Eric Shienbrood9a245532012-03-07 14:20:39 -0500354 callback.Run(Error());
Darin Petkov184c54e2011-11-15 12:44:39 +0100355}
356
Darin Petkovac635a82012-01-10 16:51:58 +0100357string CellularCapabilityGSM::CreateFriendlyServiceName() {
358 VLOG(2) << __func__;
359 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME &&
360 !cellular()->home_provider().GetName().empty()) {
361 return cellular()->home_provider().GetName();
362 }
363 if (!serving_operator_.GetName().empty()) {
364 return serving_operator_.GetName();
365 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500366 if (!carrier_.empty()) {
367 return carrier_;
Darin Petkovac635a82012-01-10 16:51:58 +0100368 }
369 if (!serving_operator_.GetCode().empty()) {
370 return "cellular_" + serving_operator_.GetCode();
371 }
372 return base::StringPrintf("GSMNetwork%u", friendly_service_name_id_++);
373}
374
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100375void CellularCapabilityGSM::SetHomeProvider() {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500376 VLOG(2) << __func__ << "(IMSI: " << imsi_
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100377 << " SPN: " << spn_ << ")";
378 // TODO(petkov): The test for NULL provider_db should be done by
379 // mobile_provider_lookup_best_match.
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500380 if (imsi_.empty() || !cellular()->provider_db()) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100381 return;
382 }
383 mobile_provider *provider =
384 mobile_provider_lookup_best_match(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500385 cellular()->provider_db(), spn_.c_str(), imsi_.c_str());
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100386 if (!provider) {
387 VLOG(2) << "GSM provider not found.";
388 return;
389 }
390 home_provider_ = provider;
391 Cellular::Operator oper;
392 if (provider->networks) {
393 oper.SetCode(provider->networks[0]);
394 }
395 if (provider->country) {
396 oper.SetCountry(provider->country);
397 }
398 if (spn_.empty()) {
399 const char *name = mobile_provider_get_name(provider);
400 if (name) {
401 oper.SetName(name);
402 }
403 } else {
404 oper.SetName(spn_);
405 }
406 cellular()->set_home_provider(oper);
Darin Petkov3cfbf212011-11-21 16:02:09 +0100407 InitAPNList();
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100408}
409
Darin Petkovae0c64e2011-11-15 15:50:27 +0100410void CellularCapabilityGSM::UpdateOperatorInfo() {
411 VLOG(2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100412 const string &network_id = serving_operator_.GetCode();
413 if (!network_id.empty()) {
414 VLOG(2) << "Looking up network id: " << network_id;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100415 mobile_provider *provider =
416 mobile_provider_lookup_by_network(cellular()->provider_db(),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100417 network_id.c_str());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100418 if (provider) {
419 const char *provider_name = mobile_provider_get_name(provider);
420 if (provider_name && *provider_name) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100421 serving_operator_.SetName(provider_name);
422 if (provider->country) {
423 serving_operator_.SetCountry(provider->country);
424 }
425 VLOG(2) << "Operator name: " << serving_operator_.GetName()
426 << ", country: " << serving_operator_.GetCountry();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100427 }
428 } else {
429 VLOG(2) << "GSM provider not found.";
430 }
431 }
432 UpdateServingOperator();
433}
434
435void CellularCapabilityGSM::UpdateServingOperator() {
436 VLOG(2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100437 if (cellular()->service().get()) {
Darin Petkov9cb02682012-01-28 00:17:38 +0100438 cellular()->service()->SetServingOperator(serving_operator_);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100439 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100440}
441
Darin Petkov3cfbf212011-11-21 16:02:09 +0100442void CellularCapabilityGSM::InitAPNList() {
443 VLOG(2) << __func__;
444 if (!home_provider_) {
445 return;
446 }
447 apn_list_.clear();
448 for (int i = 0; i < home_provider_->num_apns; ++i) {
449 Stringmap props;
450 mobile_apn *apn = home_provider_->apns[i];
451 if (apn->value) {
452 props[flimflam::kApnProperty] = apn->value;
453 }
454 if (apn->username) {
455 props[flimflam::kApnUsernameProperty] = apn->username;
456 }
457 if (apn->password) {
458 props[flimflam::kApnPasswordProperty] = apn->password;
459 }
460 // Find the first localized and non-localized name, if any.
461 const localized_name *lname = NULL;
462 const localized_name *name = NULL;
463 for (int j = 0; j < apn->num_names; ++j) {
464 if (apn->names[j]->lang) {
465 if (!lname) {
466 lname = apn->names[j];
467 }
468 } else if (!name) {
469 name = apn->names[j];
470 }
471 }
472 if (name) {
473 props[flimflam::kApnNameProperty] = name->name;
474 }
475 if (lname) {
476 props[flimflam::kApnLocalizedNameProperty] = lname->name;
477 props[flimflam::kApnLanguageProperty] = lname->lang;
478 }
479 apn_list_.push_back(props);
480 }
481 cellular()->adaptor()->EmitStringmapsChanged(
482 flimflam::kCellularApnListProperty, apn_list_);
483}
484
Eric Shienbrood9a245532012-03-07 14:20:39 -0500485// always called from an async context
486void CellularCapabilityGSM::Register(const ResultCallback &callback) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500487 VLOG(2) << __func__ << " \"" << selected_network_ << "\"";
Eric Shienbrood9a245532012-03-07 14:20:39 -0500488 CHECK(!callback.is_null());
489 Error error;
490 ResultCallback cb = Bind(&CellularCapabilityGSM::OnRegisterReply,
491 weak_ptr_factory_.GetWeakPtr(), callback);
492 network_proxy_->Register(selected_network_, &error, cb, kTimeoutRegister);
493 if (error.IsFailure())
494 callback.Run(error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100495}
496
497void CellularCapabilityGSM::RegisterOnNetwork(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500498 const string &network_id,
499 Error *error,
500 const ResultCallback &callback) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500501 VLOG(2) << __func__ << "(" << network_id << ")";
Eric Shienbrood9a245532012-03-07 14:20:39 -0500502 CHECK(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500503 desired_network_ = network_id;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500504 ResultCallback cb = Bind(&CellularCapabilityGSM::OnRegisterReply,
505 weak_ptr_factory_.GetWeakPtr(), callback);
506 network_proxy_->Register(network_id, error, cb, kTimeoutRegister);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500507}
508
Eric Shienbrood9a245532012-03-07 14:20:39 -0500509void CellularCapabilityGSM::OnRegisterReply(const ResultCallback &callback,
510 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500511 VLOG(2) << __func__ << "(" << error << ")";
512
513 if (error.IsSuccess()) {
514 selected_network_ = desired_network_;
515 desired_network_.clear();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500516 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500517 return;
518 }
519 // If registration on the desired network failed,
520 // try to register on the home network.
521 if (!desired_network_.empty()) {
522 desired_network_.clear();
523 selected_network_.clear();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500524 LOG(INFO) << "Couldn't register on selected network, trying home network";
525 Register(callback);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500526 return;
527 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500528 callback.Run(error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100529}
530
Darin Petkovb72cf402011-11-22 14:51:39 +0100531bool CellularCapabilityGSM::IsRegistered() {
532 return (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
533 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING);
534}
535
Darin Petkovb05315f2011-11-07 10:14:25 +0100536void CellularCapabilityGSM::RequirePIN(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500537 const std::string &pin, bool require,
538 Error *error, const ResultCallback &callback) {
539 CHECK(error);
540 card_proxy_->EnablePIN(pin, require, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100541}
542
Darin Petkove5bc2cb2011-12-07 14:47:32 +0100543void CellularCapabilityGSM::EnterPIN(const string &pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500544 Error *error,
545 const ResultCallback &callback) {
546 CHECK(error);
547 card_proxy_->SendPIN(pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100548}
549
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100550void CellularCapabilityGSM::UnblockPIN(const string &unblock_code,
551 const string &pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500552 Error *error,
553 const ResultCallback &callback) {
554 CHECK(error);
555 card_proxy_->SendPUK(unblock_code, pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100556}
557
558void CellularCapabilityGSM::ChangePIN(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500559 const string &old_pin, const string &new_pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500560 Error *error, const ResultCallback &callback) {
561 CHECK(error);
562 card_proxy_->ChangePIN(old_pin, new_pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100563}
564
Eric Shienbrood9a245532012-03-07 14:20:39 -0500565void CellularCapabilityGSM::Scan(Error *error, const ResultCallback &callback) {
Darin Petkov1272a432011-11-10 15:53:37 +0100566 VLOG(2) << __func__;
567 // TODO(petkov): Defer scan requests if a scan is in progress already.
Eric Shienbrood9a245532012-03-07 14:20:39 -0500568 CHECK(error);
569 ScanResultsCallback cb = Bind(&CellularCapabilityGSM::OnScanReply,
570 weak_ptr_factory_.GetWeakPtr(), callback);
571 network_proxy_->Scan(error, cb, kTimeoutScan);
Darin Petkov1272a432011-11-10 15:53:37 +0100572}
573
Eric Shienbrood9a245532012-03-07 14:20:39 -0500574void CellularCapabilityGSM::OnScanReply(const ResultCallback &callback,
575 const GSMScanResults &results,
576 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500577 VLOG(2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400578
579 // Error handling is weak. The current expectation is that on any
580 // error, found_networks_ should be cleared and a property change
581 // notification sent out.
582 //
583 // TODO(jglasgow): fix error handling
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500584 found_networks_.clear();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400585 if (!error.IsFailure()) {
586 for (GSMScanResults::const_iterator it = results.begin();
587 it != results.end(); ++it) {
588 found_networks_.push_back(ParseScanResult(*it));
589 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500590 }
Darin Petkovb7828b02012-02-03 12:34:30 +0100591 cellular()->adaptor()->EmitStringmapsChanged(flimflam::kFoundNetworksProperty,
592 found_networks_);
Eric Shienbrood9a245532012-03-07 14:20:39 -0500593 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500594}
595
596Stringmap CellularCapabilityGSM::ParseScanResult(const GSMScanResult &result) {
Darin Petkov1272a432011-11-10 15:53:37 +0100597 Stringmap parsed;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500598 for (GSMScanResult::const_iterator it = result.begin();
599 it != result.end(); ++it) {
Darin Petkov1272a432011-11-10 15:53:37 +0100600 // TODO(petkov): Define these in system_api/service_constants.h. The
601 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
602 static const char * const kStatusString[] = {
603 "unknown",
604 "available",
605 "current",
606 "forbidden",
607 };
608 static const char * const kTechnologyString[] = {
609 flimflam::kNetworkTechnologyGsm,
610 "GSM Compact",
611 flimflam::kNetworkTechnologyUmts,
612 flimflam::kNetworkTechnologyEdge,
613 "HSDPA",
614 "HSUPA",
615 flimflam::kNetworkTechnologyHspa,
616 };
617 VLOG(2) << "Network property: " << it->first << " = " << it->second;
618 if (it->first == kNetworkPropertyStatus) {
619 int status = 0;
620 if (base::StringToInt(it->second, &status) &&
621 status >= 0 &&
622 status < static_cast<int>(arraysize(kStatusString))) {
623 parsed[flimflam::kStatusProperty] = kStatusString[status];
624 } else {
625 LOG(ERROR) << "Unexpected status value: " << it->second;
626 }
627 } else if (it->first == kNetworkPropertyID) {
628 parsed[flimflam::kNetworkIdProperty] = it->second;
629 } else if (it->first == kNetworkPropertyLongName) {
630 parsed[flimflam::kLongNameProperty] = it->second;
631 } else if (it->first == kNetworkPropertyShortName) {
632 parsed[flimflam::kShortNameProperty] = it->second;
633 } else if (it->first == kNetworkPropertyAccessTechnology) {
634 int tech = 0;
635 if (base::StringToInt(it->second, &tech) &&
636 tech >= 0 &&
637 tech < static_cast<int>(arraysize(kTechnologyString))) {
638 parsed[flimflam::kTechnologyProperty] = kTechnologyString[tech];
639 } else {
640 LOG(ERROR) << "Unexpected technology value: " << it->second;
641 }
642 } else {
643 LOG(WARNING) << "Unknown network property ignored: " << it->first;
644 }
645 }
646 // If the long name is not available but the network ID is, look up the long
647 // name in the mobile provider database.
648 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
649 parsed[flimflam::kLongNameProperty].empty()) &&
650 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
651 mobile_provider *provider =
652 mobile_provider_lookup_by_network(
653 cellular()->provider_db(),
654 parsed[flimflam::kNetworkIdProperty].c_str());
655 if (provider) {
656 const char *long_name = mobile_provider_get_name(provider);
657 if (long_name && *long_name) {
658 parsed[flimflam::kLongNameProperty] = long_name;
659 }
660 }
661 }
662 return parsed;
663}
664
Darin Petkovae0c64e2011-11-15 15:50:27 +0100665void CellularCapabilityGSM::SetAccessTechnology(uint32 access_technology) {
666 access_technology_ = access_technology;
667 if (cellular()->service().get()) {
Darin Petkovb72cf402011-11-22 14:51:39 +0100668 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100669 }
670}
671
Darin Petkov20c13ec2011-11-09 15:07:15 +0100672string CellularCapabilityGSM::GetNetworkTechnologyString() const {
Darin Petkovb72cf402011-11-22 14:51:39 +0100673 switch (access_technology_) {
674 case MM_MODEM_GSM_ACCESS_TECH_GSM:
675 case MM_MODEM_GSM_ACCESS_TECH_GSM_COMPACT:
676 return flimflam::kNetworkTechnologyGsm;
677 case MM_MODEM_GSM_ACCESS_TECH_GPRS:
678 return flimflam::kNetworkTechnologyGprs;
679 case MM_MODEM_GSM_ACCESS_TECH_EDGE:
680 return flimflam::kNetworkTechnologyEdge;
681 case MM_MODEM_GSM_ACCESS_TECH_UMTS:
682 return flimflam::kNetworkTechnologyUmts;
683 case MM_MODEM_GSM_ACCESS_TECH_HSDPA:
684 case MM_MODEM_GSM_ACCESS_TECH_HSUPA:
685 case MM_MODEM_GSM_ACCESS_TECH_HSPA:
686 return flimflam::kNetworkTechnologyHspa;
687 case MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS:
688 return flimflam::kNetworkTechnologyHspaPlus;
689 default:
690 break;
Darin Petkov20c13ec2011-11-09 15:07:15 +0100691 }
692 return "";
693}
694
695string CellularCapabilityGSM::GetRoamingStateString() const {
Darin Petkov184c54e2011-11-15 12:44:39 +0100696 switch (registration_state_) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100697 case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME:
698 return flimflam::kRoamingStateHome;
699 case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING:
700 return flimflam::kRoamingStateRoaming;
701 default:
702 break;
703 }
704 return flimflam::kRoamingStateUnknown;
705}
706
Darin Petkovae0c64e2011-11-15 15:50:27 +0100707void CellularCapabilityGSM::OnModemManagerPropertiesChanged(
708 const DBusPropertiesMap &properties) {
709 uint32 access_technology = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
710 if (DBusProperties::GetUint32(properties,
711 kPropertyAccessTechnology,
712 &access_technology)) {
713 SetAccessTechnology(access_technology);
714 }
Darin Petkov63138a92012-02-06 14:09:15 +0100715 bool emit = false;
716 uint32 locks = 0;
717 if (DBusProperties::GetUint32(
718 properties, kPropertyEnabledFacilityLocks, &locks)) {
719 sim_lock_status_.enabled = locks & MM_MODEM_GSM_FACILITY_SIM;
720 emit = true;
721 }
722 if (DBusProperties::GetString(
723 properties, kPropertyUnlockRequired, &sim_lock_status_.lock_type)) {
724 emit = true;
725 }
726 if (DBusProperties::GetUint32(
727 properties, kPropertyUnlockRetries, &sim_lock_status_.retries_left)) {
728 emit = true;
729 }
730 if (emit) {
731 cellular()->adaptor()->EmitKeyValueStoreChanged(
732 flimflam::kSIMLockStatusProperty, SimLockStatusToProperty(NULL));
733 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100734}
735
Eric Shienbrood9a245532012-03-07 14:20:39 -0500736void CellularCapabilityGSM::OnNetworkModeSignal(uint32 /*mode*/) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100737 // TODO(petkov): Implement this.
738 NOTIMPLEMENTED();
739}
740
Eric Shienbrood9a245532012-03-07 14:20:39 -0500741void CellularCapabilityGSM::OnRegistrationInfoSignal(
742 uint32 status, const string &operator_code, const string &operator_name) {
743 VLOG(2) << __func__ << ": regstate=" << status
744 << ", opercode=" << operator_code
745 << ", opername=" << operator_name;
746 registration_state_ = status;
747 serving_operator_.SetCode(operator_code);
748 serving_operator_.SetName(operator_name);
749 UpdateOperatorInfo();
750 cellular()->HandleNewRegistrationState();
Darin Petkov184c54e2011-11-15 12:44:39 +0100751}
752
Eric Shienbrood9a245532012-03-07 14:20:39 -0500753void CellularCapabilityGSM::OnSignalQualitySignal(uint32 quality) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100754 cellular()->HandleNewSignalQuality(quality);
755}
756
Eric Shienbrood9a245532012-03-07 14:20:39 -0500757void CellularCapabilityGSM::OnGetRegistrationInfoReply(
758 uint32 status, const string &operator_code, const string &operator_name,
759 const Error &error) {
760 if (error.IsSuccess())
761 OnRegistrationInfoSignal(status, operator_code, operator_name);
762}
763
764void CellularCapabilityGSM::OnGetSignalQualityReply(uint32 quality,
765 const Error &error) {
766 if (error.IsSuccess())
767 OnSignalQualitySignal(quality);
768}
769
770void CellularCapabilityGSM::OnGetIMEIReply(const ResultCallback &callback,
771 const string &imei,
772 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500773 if (error.IsSuccess()) {
774 VLOG(2) << "IMEI: " << imei;
775 imei_ = imei;
776 } else {
777 VLOG(2) << "GetIMEI failed - " << error;
778 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500779 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500780}
781
Eric Shienbrood9a245532012-03-07 14:20:39 -0500782void CellularCapabilityGSM::OnGetIMSIReply(const ResultCallback &callback,
783 const string &imsi,
784 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500785 if (error.IsSuccess()) {
786 VLOG(2) << "IMSI: " << imsi;
787 imsi_ = imsi;
788 SetHomeProvider();
789 } else {
790 VLOG(2) << "GetIMSI failed - " << error;
791 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500792 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500793}
794
Eric Shienbrood9a245532012-03-07 14:20:39 -0500795void CellularCapabilityGSM::OnGetSPNReply(const ResultCallback &callback,
796 const string &spn,
797 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500798 if (error.IsSuccess()) {
799 VLOG(2) << "SPN: " << spn;
800 spn_ = spn;
801 SetHomeProvider();
802 } else {
803 VLOG(2) << "GetSPN failed - " << error;
804 }
Thieu Le923006b2012-04-05 16:32:58 -0700805 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500806}
807
Eric Shienbrood9a245532012-03-07 14:20:39 -0500808void CellularCapabilityGSM::OnGetMSISDNReply(const ResultCallback &callback,
809 const string &msisdn,
810 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500811 if (error.IsSuccess()) {
812 VLOG(2) << "MSISDN: " << msisdn;
813 mdn_ = msisdn;
814 } else {
815 VLOG(2) << "GetMSISDN failed - " << error;
816 }
Thieu Le923006b2012-04-05 16:32:58 -0700817 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500818}
819
Darin Petkovdaf43862011-10-27 11:37:28 +0200820} // namespace shill