blob: bb14966ba1aacb3437c7ae48c45f8c258a0390ab [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
Jason Glasgow4c0724a2012-04-17 15:47:40 -04007#include <string>
8#include <vector>
9
Eric Shienbrood3e20a232012-02-16 11:35:56 -050010#include <base/bind.h>
Darin Petkovdaf43862011-10-27 11:37:28 +020011#include <base/logging.h>
Eric Shienbrood3e20a232012-02-16 11:35:56 -050012#include <base/stl_util.h>
Darin Petkov1272a432011-11-10 15:53:37 +010013#include <base/string_number_conversions.h>
Darin Petkovac635a82012-01-10 16:51:58 +010014#include <base/stringprintf.h>
Darin Petkov20c13ec2011-11-09 15:07:15 +010015#include <chromeos/dbus/service_constants.h>
16#include <mm/mm-modem.h>
Darin Petkov1272a432011-11-10 15:53:37 +010017#include <mobile_provider.h>
Darin Petkovdaf43862011-10-27 11:37:28 +020018
Darin Petkov3cfbf212011-11-21 16:02:09 +010019#include "shill/adaptor_interfaces.h"
Darin Petkovae0c64e2011-11-15 15:50:27 +010020#include "shill/cellular_service.h"
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050021#include "shill/error.h"
Darin Petkov721ac932011-11-16 15:43:09 +010022#include "shill/property_accessor.h"
Darin Petkovdaf43862011-10-27 11:37:28 +020023#include "shill/proxy_factory.h"
Ben Chanfad4a0b2012-04-18 15:49:59 -070024#include "shill/scope_logger.h"
Darin Petkovdaf43862011-10-27 11:37:28 +020025
Eric Shienbrood3e20a232012-02-16 11:35:56 -050026using base::Bind;
Darin Petkovb05315f2011-11-07 10:14:25 +010027using std::string;
Jason Glasgow4c0724a2012-04-17 15:47:40 -040028using std::vector;
Darin Petkovb05315f2011-11-07 10:14:25 +010029
Darin Petkovdaf43862011-10-27 11:37:28 +020030namespace shill {
31
Darin Petkovac635a82012-01-10 16:51:58 +010032// static
33unsigned int CellularCapabilityGSM::friendly_service_name_id_ = 0;
34
Darin Petkov1272a432011-11-10 15:53:37 +010035const char CellularCapabilityGSM::kNetworkPropertyAccessTechnology[] =
36 "access-tech";
37const char CellularCapabilityGSM::kNetworkPropertyID[] = "operator-num";
38const char CellularCapabilityGSM::kNetworkPropertyLongName[] = "operator-long";
39const char CellularCapabilityGSM::kNetworkPropertyShortName[] =
40 "operator-short";
41const char CellularCapabilityGSM::kNetworkPropertyStatus[] = "status";
Darin Petkovae0c64e2011-11-15 15:50:27 +010042const char CellularCapabilityGSM::kPhoneNumber[] = "*99#";
43const char CellularCapabilityGSM::kPropertyAccessTechnology[] =
44 "AccessTechnology";
Darin Petkov63138a92012-02-06 14:09:15 +010045const char CellularCapabilityGSM::kPropertyEnabledFacilityLocks[] =
46 "EnabledFacilityLocks";
Darin Petkov721ac932011-11-16 15:43:09 +010047const char CellularCapabilityGSM::kPropertyUnlockRequired[] = "UnlockRequired";
48const char CellularCapabilityGSM::kPropertyUnlockRetries[] = "UnlockRetries";
Darin Petkov1272a432011-11-10 15:53:37 +010049
Gary Morain82a31a02012-08-02 18:03:32 -070050const int CellularCapabilityGSM::kGetIMSIRetryLimit = 10;
51const int64 CellularCapabilityGSM::kGetIMSIRetryDelayMilliseconds = 200;
52
53
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050054CellularCapabilityGSM::CellularCapabilityGSM(Cellular *cellular,
55 ProxyFactory *proxy_factory)
Jason Glasgow82f9ab32012-04-04 14:27:19 -040056 : CellularCapabilityClassic(cellular, proxy_factory),
Eric Shienbrood3e20a232012-02-16 11:35:56 -050057 weak_ptr_factory_(this),
Darin Petkov184c54e2011-11-15 12:44:39 +010058 registration_state_(MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN),
Darin Petkovae0c64e2011-11-15 15:50:27 +010059 access_technology_(MM_MODEM_GSM_ACCESS_TECH_UNKNOWN),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +010060 home_provider_(NULL),
Gary Morain82a31a02012-08-02 18:03:32 -070061 get_imsi_retries_(0),
62 get_imsi_retry_delay_milliseconds_(kGetIMSIRetryDelayMilliseconds),
Darin Petkov1272a432011-11-10 15:53:37 +010063 scanning_(false),
64 scan_interval_(0) {
Ben Chanfad4a0b2012-04-18 15:49:59 -070065 SLOG(Cellular, 2) << "Cellular capability constructed: GSM";
Darin Petkov1272a432011-11-10 15:53:37 +010066 PropertyStore *store = cellular->mutable_store();
Darin Petkov184c54e2011-11-15 12:44:39 +010067 store->RegisterConstString(flimflam::kSelectedNetworkProperty,
68 &selected_network_);
Darin Petkov1272a432011-11-10 15:53:37 +010069 store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
70 &found_networks_);
71 store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
72 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
Darin Petkov63138a92012-02-06 14:09:15 +010073 HelpRegisterDerivedKeyValueStore(
74 flimflam::kSIMLockStatusProperty,
75 &CellularCapabilityGSM::SimLockStatusToProperty,
76 NULL);
Darin Petkov3cfbf212011-11-21 16:02:09 +010077 store->RegisterConstStringmaps(flimflam::kCellularApnListProperty,
78 &apn_list_);
Darin Petkov0d06f7d2012-02-03 13:08:19 +010079 scanning_supported_ = true;
Darin Petkov1272a432011-11-10 15:53:37 +010080}
Darin Petkovdaf43862011-10-27 11:37:28 +020081
Darin Petkov63138a92012-02-06 14:09:15 +010082KeyValueStore CellularCapabilityGSM::SimLockStatusToProperty(Error */*error*/) {
83 KeyValueStore status;
84 status.SetBool(flimflam::kSIMLockEnabledProperty, sim_lock_status_.enabled);
85 status.SetString(flimflam::kSIMLockTypeProperty, sim_lock_status_.lock_type);
86 status.SetUint(flimflam::kSIMLockRetriesLeftProperty,
87 sim_lock_status_.retries_left);
88 return status;
Darin Petkov721ac932011-11-16 15:43:09 +010089}
90
Darin Petkov63138a92012-02-06 14:09:15 +010091void CellularCapabilityGSM::HelpRegisterDerivedKeyValueStore(
Darin Petkov721ac932011-11-16 15:43:09 +010092 const string &name,
Darin Petkov63138a92012-02-06 14:09:15 +010093 KeyValueStore(CellularCapabilityGSM::*get)(Error *error),
94 void(CellularCapabilityGSM::*set)(
95 const KeyValueStore &value, Error *error)) {
96 cellular()->mutable_store()->RegisterDerivedKeyValueStore(
Darin Petkov721ac932011-11-16 15:43:09 +010097 name,
Darin Petkov63138a92012-02-06 14:09:15 +010098 KeyValueStoreAccessor(
99 new CustomAccessor<CellularCapabilityGSM, KeyValueStore>(
Darin Petkov721ac932011-11-16 15:43:09 +0100100 this, get, set)));
101}
102
Eric Shienbrood9a245532012-03-07 14:20:39 -0500103void CellularCapabilityGSM::InitProxies() {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400104 CellularCapabilityClassic::InitProxies();
Darin Petkovcb547732011-11-09 13:55:26 +0100105 card_proxy_.reset(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500106 proxy_factory()->CreateModemGSMCardProxy(cellular()->dbus_path(),
Darin Petkovdaf43862011-10-27 11:37:28 +0200107 cellular()->dbus_owner()));
Darin Petkov184c54e2011-11-15 12:44:39 +0100108 network_proxy_.reset(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500109 proxy_factory()->CreateModemGSMNetworkProxy(cellular()->dbus_path(),
Darin Petkovdaf43862011-10-27 11:37:28 +0200110 cellular()->dbus_owner()));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500111 network_proxy_->set_signal_quality_callback(
112 Bind(&CellularCapabilityGSM::OnSignalQualitySignal,
113 weak_ptr_factory_.GetWeakPtr()));
114 network_proxy_->set_network_mode_callback(
115 Bind(&CellularCapabilityGSM::OnNetworkModeSignal,
116 weak_ptr_factory_.GetWeakPtr()));
117 network_proxy_->set_registration_info_callback(
118 Bind(&CellularCapabilityGSM::OnRegistrationInfoSignal,
119 weak_ptr_factory_.GetWeakPtr()));
Darin Petkovdaf43862011-10-27 11:37:28 +0200120}
121
Eric Shienbrood9a245532012-03-07 14:20:39 -0500122void CellularCapabilityGSM::StartModem(Error *error,
123 const ResultCallback &callback) {
124 InitProxies();
125
126 CellularTaskList *tasks = new CellularTaskList();
127 ResultCallback cb =
128 Bind(&CellularCapabilityGSM::StepCompletedCallback,
Thieu Le923006b2012-04-05 16:32:58 -0700129 weak_ptr_factory_.GetWeakPtr(), callback, false, tasks);
130 ResultCallback cb_ignore_error =
131 Bind(&CellularCapabilityGSM::StepCompletedCallback,
132 weak_ptr_factory_.GetWeakPtr(), callback, true, tasks);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400133 if (!cellular()->IsUnderlyingDeviceEnabled())
134 tasks->push_back(Bind(&CellularCapabilityGSM::EnableModem,
135 weak_ptr_factory_.GetWeakPtr(), cb));
136 // If we're within range of the home network, the modem will try to
137 // register once it's enabled, or may be already registered if we
138 // started out enabled.
139 if (!IsUnderlyingDeviceRegistered() && !selected_network_.empty())
140 tasks->push_back(Bind(&CellularCapabilityGSM::Register,
141 weak_ptr_factory_.GetWeakPtr(), cb));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500142 tasks->push_back(Bind(&CellularCapabilityGSM::GetIMEI,
143 weak_ptr_factory_.GetWeakPtr(), cb));
Gary Morain82a31a02012-08-02 18:03:32 -0700144 get_imsi_retries_ = 0;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500145 tasks->push_back(Bind(&CellularCapabilityGSM::GetIMSI,
146 weak_ptr_factory_.GetWeakPtr(), cb));
147 tasks->push_back(Bind(&CellularCapabilityGSM::GetSPN,
Thieu Le923006b2012-04-05 16:32:58 -0700148 weak_ptr_factory_.GetWeakPtr(), cb_ignore_error));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500149 tasks->push_back(Bind(&CellularCapabilityGSM::GetMSISDN,
Thieu Le923006b2012-04-05 16:32:58 -0700150 weak_ptr_factory_.GetWeakPtr(), cb_ignore_error));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500151 tasks->push_back(Bind(&CellularCapabilityGSM::GetProperties,
152 weak_ptr_factory_.GetWeakPtr(), cb));
153 tasks->push_back(Bind(&CellularCapabilityGSM::GetModemInfo,
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400154 weak_ptr_factory_.GetWeakPtr(), cb_ignore_error));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500155 tasks->push_back(Bind(&CellularCapabilityGSM::FinishEnable,
156 weak_ptr_factory_.GetWeakPtr(), cb));
157
158 RunNextStep(tasks);
159}
160
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400161bool CellularCapabilityGSM::IsUnderlyingDeviceRegistered() const {
162 switch (cellular()->modem_state()) {
163 case Cellular::kModemStateUnknown:
164 case Cellular::kModemStateDisabled:
165 case Cellular::kModemStateInitializing:
166 case Cellular::kModemStateLocked:
167 case Cellular::kModemStateDisabling:
168 case Cellular::kModemStateEnabling:
169 case Cellular::kModemStateEnabled:
170 return false;
171 case Cellular::kModemStateSearching:
172 case Cellular::kModemStateRegistered:
173 case Cellular::kModemStateDisconnecting:
174 case Cellular::kModemStateConnecting:
175 case Cellular::kModemStateConnected:
176 return true;
177 }
178 return false;
179}
180
Eric Shienbrood9a245532012-03-07 14:20:39 -0500181void CellularCapabilityGSM::ReleaseProxies() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700182 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400183 CellularCapabilityClassic::ReleaseProxies();
Darin Petkov721ac932011-11-16 15:43:09 +0100184 card_proxy_.reset();
185 network_proxy_.reset();
186}
187
Darin Petkov5f316f62011-11-18 12:10:26 +0100188void CellularCapabilityGSM::OnServiceCreated() {
Darin Petkov31332412012-01-28 01:50:02 +0100189 // If IMSI is available, base the service's storage identifier on it.
190 if (!imsi_.empty()) {
191 cellular()->service()->SetStorageIdentifier(
Darin Petkovdd3e8662012-02-03 13:16:20 +0100192 string(flimflam::kTypeCellular) + "_" +
193 cellular()->address() + "_" + imsi_);
Darin Petkov31332412012-01-28 01:50:02 +0100194 }
Darin Petkovb9c99332012-01-12 13:13:00 +0100195 cellular()->service()->SetActivationState(
Darin Petkov5f316f62011-11-18 12:10:26 +0100196 flimflam::kActivationStateActivated);
197 UpdateServingOperator();
198}
199
Darin Petkovae0c64e2011-11-15 15:50:27 +0100200void CellularCapabilityGSM::UpdateStatus(const DBusPropertiesMap &properties) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400201 if (ContainsKey(properties, kModemPropertyIMSI)) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100202 SetHomeProvider();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100203 }
204}
205
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400206// Create the list of APNs to try, in the following order:
207// - last APN that resulted in a successful connection attempt on the
208// current network (if any)
209// - the APN, if any, that was set by the user
210// - the list of APNs found in the mobile broadband provider DB for the
211// home provider associated with the current SIM
212// - as a last resort, attempt to connect with no APN
213void CellularCapabilityGSM::SetupApnTryList() {
214 apn_try_list_.clear();
215
216 DCHECK(cellular()->service().get());
217 const Stringmap *apn_info = cellular()->service()->GetLastGoodApn();
218 if (apn_info)
219 apn_try_list_.push_back(*apn_info);
220
221 apn_info = cellular()->service()->GetUserSpecifiedApn();
222 if (apn_info)
223 apn_try_list_.push_back(*apn_info);
224
225 apn_try_list_.insert(apn_try_list_.end(), apn_list_.begin(), apn_list_.end());
226}
227
Darin Petkovae0c64e2011-11-15 15:50:27 +0100228void CellularCapabilityGSM::SetupConnectProperties(
229 DBusPropertiesMap *properties) {
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400230 SetupApnTryList();
231 FillConnectPropertyMap(properties);
232}
233
234void CellularCapabilityGSM::FillConnectPropertyMap(
235 DBusPropertiesMap *properties) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500236 (*properties)[kConnectPropertyPhoneNumber].writer().append_string(
Darin Petkovae0c64e2011-11-15 15:50:27 +0100237 kPhoneNumber);
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400238
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400239 if (!AllowRoaming())
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400240 (*properties)[kConnectPropertyHomeOnly].writer().append_bool(true);
241
242 if (!apn_try_list_.empty()) {
243 // Leave the APN at the front of the list, so that it can be recorded
244 // if the connect attempt succeeds.
245 Stringmap apn_info = apn_try_list_.front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700246 SLOG(Cellular, 2) << __func__ << ": Using APN "
247 << apn_info[flimflam::kApnProperty];
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400248 (*properties)[kConnectPropertyApn].writer().append_string(
249 apn_info[flimflam::kApnProperty].c_str());
250 if (ContainsKey(apn_info, flimflam::kApnUsernameProperty))
251 (*properties)[kConnectPropertyApnUsername].writer().append_string(
252 apn_info[flimflam::kApnUsernameProperty].c_str());
253 if (ContainsKey(apn_info, flimflam::kApnPasswordProperty))
254 (*properties)[kConnectPropertyApnPassword].writer().append_string(
255 apn_info[flimflam::kApnPasswordProperty].c_str());
256 }
257}
258
Nathan Williamsb54974f2012-04-19 11:16:30 -0400259void CellularCapabilityGSM::Connect(const DBusPropertiesMap &properties,
260 Error *error,
261 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700262 SLOG(Cellular, 2) << __func__;
Nathan Williamsb54974f2012-04-19 11:16:30 -0400263 ResultCallback cb = Bind(&CellularCapabilityGSM::OnConnectReply,
264 weak_ptr_factory_.GetWeakPtr(),
265 callback);
266 simple_proxy_->Connect(properties, error, cb, kTimeoutConnect);
267}
268
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400269void CellularCapabilityGSM::OnConnectReply(const ResultCallback &callback,
270 const Error &error) {
Thieu Leb5954a22012-05-18 10:37:34 -0700271 CellularServiceRefPtr service = cellular()->service();
272 if (!service) {
273 // The service could have been deleted before our Connect() request
274 // completes if the modem was enabled and then quickly disabled.
275 apn_try_list_.clear();
276 } else if (error.IsFailure()) {
277 service->ClearLastGoodApn();
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400278 // The APN that was just tried (and failed) is still at the
279 // front of the list, about to be removed. If the list is empty
280 // after that, try one last time without an APN. This may succeed
281 // with some modems in some cases.
282 if (error.type() == Error::kInvalidApn && !apn_try_list_.empty()) {
283 apn_try_list_.pop_front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700284 SLOG(Cellular, 2) << "Connect failed with invalid APN, "
285 << apn_try_list_.size() << " remaining APNs to try";
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400286 DBusPropertiesMap props;
287 FillConnectPropertyMap(&props);
288 Error error;
289 Connect(props, &error, callback);
290 return;
291 }
292 } else if (!apn_try_list_.empty()) {
Thieu Leb5954a22012-05-18 10:37:34 -0700293 service->SetLastGoodApn(apn_try_list_.front());
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400294 apn_try_list_.clear();
295 }
Nathan Williamsb54974f2012-04-19 11:16:30 -0400296 if (!callback.is_null())
297 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400298}
299
300bool CellularCapabilityGSM::AllowRoaming() {
301 bool requires_roaming =
302 home_provider_ ? home_provider_->requires_roaming : false;
303 return requires_roaming || allow_roaming_property();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100304}
305
Eric Shienbrood9a245532012-03-07 14:20:39 -0500306// always called from an async context
307void CellularCapabilityGSM::GetIMEI(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700308 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500309 CHECK(!callback.is_null());
310 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500311 if (imei_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500312 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetIMEIReply,
313 weak_ptr_factory_.GetWeakPtr(), callback);
314 card_proxy_->GetIMEI(&error, cb, kTimeoutDefault);
315 if (error.IsFailure())
316 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500317 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700318 SLOG(Cellular, 2) << "Already have IMEI " << imei_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500319 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100320 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500321}
322
Eric Shienbrood9a245532012-03-07 14:20:39 -0500323// always called from an async context
324void CellularCapabilityGSM::GetIMSI(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700325 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500326 CHECK(!callback.is_null());
327 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500328 if (imsi_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500329 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetIMSIReply,
330 weak_ptr_factory_.GetWeakPtr(),
331 callback);
332 card_proxy_->GetIMSI(&error, cb, kTimeoutDefault);
333 if (error.IsFailure())
334 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500335 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700336 SLOG(Cellular, 2) << "Already have IMSI " << imsi_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500337 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100338 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500339}
340
Eric Shienbrood9a245532012-03-07 14:20:39 -0500341// always called from an async context
342void CellularCapabilityGSM::GetSPN(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700343 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500344 CHECK(!callback.is_null());
345 Error error;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100346 if (spn_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500347 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetSPNReply,
348 weak_ptr_factory_.GetWeakPtr(),
349 callback);
350 card_proxy_->GetSPN(&error, cb, kTimeoutDefault);
351 if (error.IsFailure())
352 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500353 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700354 SLOG(Cellular, 2) << "Already have SPN " << spn_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500355 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100356 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500357}
358
Eric Shienbrood9a245532012-03-07 14:20:39 -0500359// always called from an async context
360void CellularCapabilityGSM::GetMSISDN(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700361 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500362 CHECK(!callback.is_null());
363 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500364 if (mdn_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500365 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetMSISDNReply,
366 weak_ptr_factory_.GetWeakPtr(),
367 callback);
368 card_proxy_->GetMSISDN(&error, cb, kTimeoutDefault);
369 if (error.IsFailure())
370 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500371 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700372 SLOG(Cellular, 2) << "Already have MSISDN " << mdn_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500373 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100374 }
375}
376
Darin Petkov3e509242011-11-10 14:46:44 +0100377void CellularCapabilityGSM::GetSignalQuality() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700378 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500379 SignalQualityCallback callback =
380 Bind(&CellularCapabilityGSM::OnGetSignalQualityReply,
381 weak_ptr_factory_.GetWeakPtr());
382 network_proxy_->GetSignalQuality(NULL, callback, kTimeoutDefault);
Darin Petkov3e509242011-11-10 14:46:44 +0100383}
384
Eric Shienbrood9a245532012-03-07 14:20:39 -0500385void CellularCapabilityGSM::GetRegistrationState() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700386 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500387 RegistrationInfoCallback callback =
388 Bind(&CellularCapabilityGSM::OnGetRegistrationInfoReply,
389 weak_ptr_factory_.GetWeakPtr());
390 network_proxy_->GetRegistrationInfo(NULL, callback, kTimeoutDefault);
Darin Petkov184c54e2011-11-15 12:44:39 +0100391}
392
Eric Shienbrood9a245532012-03-07 14:20:39 -0500393void CellularCapabilityGSM::GetProperties(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700394 SLOG(Cellular, 2) << __func__;
Darin Petkov63138a92012-02-06 14:09:15 +0100395
Darin Petkov184c54e2011-11-15 12:44:39 +0100396 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
397 uint32 tech = network_proxy_->AccessTechnology();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100398 SetAccessTechnology(tech);
Ben Chanfad4a0b2012-04-18 15:49:59 -0700399 SLOG(Cellular, 2) << "GSM AccessTechnology: " << tech;
Darin Petkov63138a92012-02-06 14:09:15 +0100400
401 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
402 uint32 locks = card_proxy_->EnabledFacilityLocks();
403 sim_lock_status_.enabled = locks & MM_MODEM_GSM_FACILITY_SIM;
Ben Chanfad4a0b2012-04-18 15:49:59 -0700404 SLOG(Cellular, 2) << "GSM EnabledFacilityLocks: " << locks;
Darin Petkov63138a92012-02-06 14:09:15 +0100405
Eric Shienbrood9a245532012-03-07 14:20:39 -0500406 callback.Run(Error());
Darin Petkov184c54e2011-11-15 12:44:39 +0100407}
408
Darin Petkovac635a82012-01-10 16:51:58 +0100409string CellularCapabilityGSM::CreateFriendlyServiceName() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700410 SLOG(Cellular, 2) << __func__;
Darin Petkovac635a82012-01-10 16:51:58 +0100411 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME &&
412 !cellular()->home_provider().GetName().empty()) {
413 return cellular()->home_provider().GetName();
414 }
415 if (!serving_operator_.GetName().empty()) {
416 return serving_operator_.GetName();
417 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500418 if (!carrier_.empty()) {
419 return carrier_;
Darin Petkovac635a82012-01-10 16:51:58 +0100420 }
421 if (!serving_operator_.GetCode().empty()) {
422 return "cellular_" + serving_operator_.GetCode();
423 }
424 return base::StringPrintf("GSMNetwork%u", friendly_service_name_id_++);
425}
426
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100427void CellularCapabilityGSM::SetHomeProvider() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700428 SLOG(Cellular, 2) << __func__ << "(IMSI: " << imsi_
429 << " SPN: " << spn_ << ")";
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100430 // TODO(petkov): The test for NULL provider_db should be done by
431 // mobile_provider_lookup_best_match.
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500432 if (imsi_.empty() || !cellular()->provider_db()) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100433 return;
434 }
435 mobile_provider *provider =
436 mobile_provider_lookup_best_match(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500437 cellular()->provider_db(), spn_.c_str(), imsi_.c_str());
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100438 if (!provider) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700439 SLOG(Cellular, 2) << "GSM provider not found.";
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100440 return;
441 }
442 home_provider_ = provider;
443 Cellular::Operator oper;
444 if (provider->networks) {
445 oper.SetCode(provider->networks[0]);
446 }
447 if (provider->country) {
448 oper.SetCountry(provider->country);
449 }
450 if (spn_.empty()) {
451 const char *name = mobile_provider_get_name(provider);
452 if (name) {
453 oper.SetName(name);
454 }
455 } else {
456 oper.SetName(spn_);
457 }
458 cellular()->set_home_provider(oper);
Darin Petkov3cfbf212011-11-21 16:02:09 +0100459 InitAPNList();
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100460}
461
Darin Petkovae0c64e2011-11-15 15:50:27 +0100462void CellularCapabilityGSM::UpdateOperatorInfo() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700463 SLOG(Cellular, 2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100464 const string &network_id = serving_operator_.GetCode();
465 if (!network_id.empty()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700466 SLOG(Cellular, 2) << "Looking up network id: " << network_id;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100467 mobile_provider *provider =
468 mobile_provider_lookup_by_network(cellular()->provider_db(),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100469 network_id.c_str());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100470 if (provider) {
471 const char *provider_name = mobile_provider_get_name(provider);
472 if (provider_name && *provider_name) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100473 serving_operator_.SetName(provider_name);
474 if (provider->country) {
475 serving_operator_.SetCountry(provider->country);
476 }
Ben Chanfad4a0b2012-04-18 15:49:59 -0700477 SLOG(Cellular, 2) << "Operator name: " << serving_operator_.GetName()
478 << ", country: " << serving_operator_.GetCountry();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100479 }
480 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700481 SLOG(Cellular, 2) << "GSM provider not found.";
Darin Petkovae0c64e2011-11-15 15:50:27 +0100482 }
483 }
484 UpdateServingOperator();
485}
486
487void CellularCapabilityGSM::UpdateServingOperator() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700488 SLOG(Cellular, 2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100489 if (cellular()->service().get()) {
Darin Petkov9cb02682012-01-28 00:17:38 +0100490 cellular()->service()->SetServingOperator(serving_operator_);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100491 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100492}
493
Darin Petkov3cfbf212011-11-21 16:02:09 +0100494void CellularCapabilityGSM::InitAPNList() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700495 SLOG(Cellular, 2) << __func__;
Darin Petkov3cfbf212011-11-21 16:02:09 +0100496 if (!home_provider_) {
497 return;
498 }
499 apn_list_.clear();
500 for (int i = 0; i < home_provider_->num_apns; ++i) {
501 Stringmap props;
502 mobile_apn *apn = home_provider_->apns[i];
503 if (apn->value) {
504 props[flimflam::kApnProperty] = apn->value;
505 }
506 if (apn->username) {
507 props[flimflam::kApnUsernameProperty] = apn->username;
508 }
509 if (apn->password) {
510 props[flimflam::kApnPasswordProperty] = apn->password;
511 }
512 // Find the first localized and non-localized name, if any.
513 const localized_name *lname = NULL;
514 const localized_name *name = NULL;
515 for (int j = 0; j < apn->num_names; ++j) {
516 if (apn->names[j]->lang) {
517 if (!lname) {
518 lname = apn->names[j];
519 }
520 } else if (!name) {
521 name = apn->names[j];
522 }
523 }
524 if (name) {
525 props[flimflam::kApnNameProperty] = name->name;
526 }
527 if (lname) {
528 props[flimflam::kApnLocalizedNameProperty] = lname->name;
529 props[flimflam::kApnLanguageProperty] = lname->lang;
530 }
531 apn_list_.push_back(props);
532 }
533 cellular()->adaptor()->EmitStringmapsChanged(
534 flimflam::kCellularApnListProperty, apn_list_);
535}
536
Eric Shienbrood9a245532012-03-07 14:20:39 -0500537// always called from an async context
538void CellularCapabilityGSM::Register(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700539 SLOG(Cellular, 2) << __func__ << " \"" << selected_network_ << "\"";
Eric Shienbrood9a245532012-03-07 14:20:39 -0500540 CHECK(!callback.is_null());
541 Error error;
542 ResultCallback cb = Bind(&CellularCapabilityGSM::OnRegisterReply,
543 weak_ptr_factory_.GetWeakPtr(), callback);
544 network_proxy_->Register(selected_network_, &error, cb, kTimeoutRegister);
545 if (error.IsFailure())
546 callback.Run(error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100547}
548
549void CellularCapabilityGSM::RegisterOnNetwork(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500550 const string &network_id,
551 Error *error,
552 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700553 SLOG(Cellular, 2) << __func__ << "(" << network_id << ")";
Eric Shienbrood9a245532012-03-07 14:20:39 -0500554 CHECK(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500555 desired_network_ = network_id;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500556 ResultCallback cb = Bind(&CellularCapabilityGSM::OnRegisterReply,
557 weak_ptr_factory_.GetWeakPtr(), callback);
558 network_proxy_->Register(network_id, error, cb, kTimeoutRegister);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500559}
560
Eric Shienbrood9a245532012-03-07 14:20:39 -0500561void CellularCapabilityGSM::OnRegisterReply(const ResultCallback &callback,
562 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700563 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500564
565 if (error.IsSuccess()) {
566 selected_network_ = desired_network_;
567 desired_network_.clear();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500568 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500569 return;
570 }
571 // If registration on the desired network failed,
572 // try to register on the home network.
573 if (!desired_network_.empty()) {
574 desired_network_.clear();
575 selected_network_.clear();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500576 LOG(INFO) << "Couldn't register on selected network, trying home network";
577 Register(callback);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500578 return;
579 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500580 callback.Run(error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100581}
582
Darin Petkovb72cf402011-11-22 14:51:39 +0100583bool CellularCapabilityGSM::IsRegistered() {
584 return (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
585 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING);
586}
587
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400588void CellularCapabilityGSM::SetUnregistered(bool searching) {
589 // If we're already in some non-registered state, don't override that
590 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
591 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING) {
592 registration_state_ =
593 (searching ? MM_MODEM_GSM_NETWORK_REG_STATUS_SEARCHING :
594 MM_MODEM_GSM_NETWORK_REG_STATUS_IDLE);
595 }
596}
597
Darin Petkovb05315f2011-11-07 10:14:25 +0100598void CellularCapabilityGSM::RequirePIN(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500599 const std::string &pin, bool require,
600 Error *error, const ResultCallback &callback) {
601 CHECK(error);
602 card_proxy_->EnablePIN(pin, require, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100603}
604
Darin Petkove5bc2cb2011-12-07 14:47:32 +0100605void CellularCapabilityGSM::EnterPIN(const string &pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500606 Error *error,
607 const ResultCallback &callback) {
608 CHECK(error);
609 card_proxy_->SendPIN(pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100610}
611
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100612void CellularCapabilityGSM::UnblockPIN(const string &unblock_code,
613 const string &pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500614 Error *error,
615 const ResultCallback &callback) {
616 CHECK(error);
617 card_proxy_->SendPUK(unblock_code, pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100618}
619
620void CellularCapabilityGSM::ChangePIN(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500621 const string &old_pin, const string &new_pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500622 Error *error, const ResultCallback &callback) {
623 CHECK(error);
624 card_proxy_->ChangePIN(old_pin, new_pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100625}
626
Eric Shienbrood9a245532012-03-07 14:20:39 -0500627void CellularCapabilityGSM::Scan(Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700628 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500629 CHECK(error);
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400630 if (scanning_) {
631 Error::PopulateAndLog(error, Error::kInProgress, "Already scanning");
632 return;
633 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500634 ScanResultsCallback cb = Bind(&CellularCapabilityGSM::OnScanReply,
635 weak_ptr_factory_.GetWeakPtr(), callback);
636 network_proxy_->Scan(error, cb, kTimeoutScan);
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400637 if (!error->IsFailure()) {
638 scanning_ = true;
639 cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty,
640 scanning_);
641 }
Darin Petkov1272a432011-11-10 15:53:37 +0100642}
643
Eric Shienbrood9a245532012-03-07 14:20:39 -0500644void CellularCapabilityGSM::OnScanReply(const ResultCallback &callback,
645 const GSMScanResults &results,
646 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700647 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400648
649 // Error handling is weak. The current expectation is that on any
650 // error, found_networks_ should be cleared and a property change
651 // notification sent out.
652 //
653 // TODO(jglasgow): fix error handling
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400654 scanning_ = false;
655 cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty,
656 scanning_);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500657 found_networks_.clear();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400658 if (!error.IsFailure()) {
659 for (GSMScanResults::const_iterator it = results.begin();
660 it != results.end(); ++it) {
661 found_networks_.push_back(ParseScanResult(*it));
662 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500663 }
Darin Petkovb7828b02012-02-03 12:34:30 +0100664 cellular()->adaptor()->EmitStringmapsChanged(flimflam::kFoundNetworksProperty,
665 found_networks_);
Gary Moraina49062a2012-04-27 13:48:41 -0700666 if (!callback.is_null())
667 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500668}
669
670Stringmap CellularCapabilityGSM::ParseScanResult(const GSMScanResult &result) {
Darin Petkov1272a432011-11-10 15:53:37 +0100671 Stringmap parsed;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500672 for (GSMScanResult::const_iterator it = result.begin();
673 it != result.end(); ++it) {
Darin Petkov1272a432011-11-10 15:53:37 +0100674 // TODO(petkov): Define these in system_api/service_constants.h. The
675 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
676 static const char * const kStatusString[] = {
677 "unknown",
678 "available",
679 "current",
680 "forbidden",
681 };
682 static const char * const kTechnologyString[] = {
683 flimflam::kNetworkTechnologyGsm,
684 "GSM Compact",
685 flimflam::kNetworkTechnologyUmts,
686 flimflam::kNetworkTechnologyEdge,
687 "HSDPA",
688 "HSUPA",
689 flimflam::kNetworkTechnologyHspa,
690 };
Ben Chanfad4a0b2012-04-18 15:49:59 -0700691 SLOG(Cellular, 2) << "Network property: " << it->first << " = "
692 << it->second;
Darin Petkov1272a432011-11-10 15:53:37 +0100693 if (it->first == kNetworkPropertyStatus) {
694 int status = 0;
695 if (base::StringToInt(it->second, &status) &&
696 status >= 0 &&
697 status < static_cast<int>(arraysize(kStatusString))) {
698 parsed[flimflam::kStatusProperty] = kStatusString[status];
699 } else {
700 LOG(ERROR) << "Unexpected status value: " << it->second;
701 }
702 } else if (it->first == kNetworkPropertyID) {
703 parsed[flimflam::kNetworkIdProperty] = it->second;
704 } else if (it->first == kNetworkPropertyLongName) {
705 parsed[flimflam::kLongNameProperty] = it->second;
706 } else if (it->first == kNetworkPropertyShortName) {
707 parsed[flimflam::kShortNameProperty] = it->second;
708 } else if (it->first == kNetworkPropertyAccessTechnology) {
709 int tech = 0;
710 if (base::StringToInt(it->second, &tech) &&
711 tech >= 0 &&
712 tech < static_cast<int>(arraysize(kTechnologyString))) {
713 parsed[flimflam::kTechnologyProperty] = kTechnologyString[tech];
714 } else {
715 LOG(ERROR) << "Unexpected technology value: " << it->second;
716 }
717 } else {
718 LOG(WARNING) << "Unknown network property ignored: " << it->first;
719 }
720 }
721 // If the long name is not available but the network ID is, look up the long
722 // name in the mobile provider database.
723 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
724 parsed[flimflam::kLongNameProperty].empty()) &&
725 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
726 mobile_provider *provider =
727 mobile_provider_lookup_by_network(
728 cellular()->provider_db(),
729 parsed[flimflam::kNetworkIdProperty].c_str());
730 if (provider) {
731 const char *long_name = mobile_provider_get_name(provider);
732 if (long_name && *long_name) {
733 parsed[flimflam::kLongNameProperty] = long_name;
734 }
735 }
736 }
737 return parsed;
738}
739
Darin Petkovae0c64e2011-11-15 15:50:27 +0100740void CellularCapabilityGSM::SetAccessTechnology(uint32 access_technology) {
741 access_technology_ = access_technology;
742 if (cellular()->service().get()) {
Darin Petkovb72cf402011-11-22 14:51:39 +0100743 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100744 }
745}
746
Darin Petkov20c13ec2011-11-09 15:07:15 +0100747string CellularCapabilityGSM::GetNetworkTechnologyString() const {
Darin Petkovb72cf402011-11-22 14:51:39 +0100748 switch (access_technology_) {
749 case MM_MODEM_GSM_ACCESS_TECH_GSM:
750 case MM_MODEM_GSM_ACCESS_TECH_GSM_COMPACT:
751 return flimflam::kNetworkTechnologyGsm;
752 case MM_MODEM_GSM_ACCESS_TECH_GPRS:
753 return flimflam::kNetworkTechnologyGprs;
754 case MM_MODEM_GSM_ACCESS_TECH_EDGE:
755 return flimflam::kNetworkTechnologyEdge;
756 case MM_MODEM_GSM_ACCESS_TECH_UMTS:
757 return flimflam::kNetworkTechnologyUmts;
758 case MM_MODEM_GSM_ACCESS_TECH_HSDPA:
759 case MM_MODEM_GSM_ACCESS_TECH_HSUPA:
760 case MM_MODEM_GSM_ACCESS_TECH_HSPA:
761 return flimflam::kNetworkTechnologyHspa;
762 case MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS:
763 return flimflam::kNetworkTechnologyHspaPlus;
764 default:
765 break;
Darin Petkov20c13ec2011-11-09 15:07:15 +0100766 }
767 return "";
768}
769
770string CellularCapabilityGSM::GetRoamingStateString() const {
Darin Petkov184c54e2011-11-15 12:44:39 +0100771 switch (registration_state_) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100772 case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME:
773 return flimflam::kRoamingStateHome;
774 case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING:
775 return flimflam::kRoamingStateRoaming;
776 default:
777 break;
778 }
779 return flimflam::kRoamingStateUnknown;
780}
781
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400782void CellularCapabilityGSM::OnDBusPropertiesChanged(
783 const string &interface,
784 const DBusPropertiesMap &properties,
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400785 const vector<string> &invalidated_properties) {
786 CellularCapabilityClassic::OnDBusPropertiesChanged(interface,
787 properties,
788 invalidated_properties);
789 if (interface == MM_MODEM_GSM_NETWORK_INTERFACE) {
790 uint32 access_technology = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
791 if (DBusProperties::GetUint32(properties,
792 kPropertyAccessTechnology,
793 &access_technology)) {
794 SetAccessTechnology(access_technology);
795 }
Gary Morainbaeefdf2012-04-30 14:53:35 -0700796 } else {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400797 bool emit = false;
Gary Morainbaeefdf2012-04-30 14:53:35 -0700798 if (interface == MM_MODEM_GSM_CARD_INTERFACE) {
799 uint32 locks = 0;
800 if (DBusProperties::GetUint32(
801 properties, kPropertyEnabledFacilityLocks, &locks)) {
802 sim_lock_status_.enabled = locks & MM_MODEM_GSM_FACILITY_SIM;
803 emit = true;
804 }
805 } else if (interface == MM_MODEM_INTERFACE) {
806 if (DBusProperties::GetString(properties, kPropertyUnlockRequired,
807 &sim_lock_status_.lock_type)) {
808 emit = true;
809 }
810 if (DBusProperties::GetUint32(properties, kPropertyUnlockRetries,
811 &sim_lock_status_.retries_left)) {
812 emit = true;
813 }
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400814 }
815 if (emit) {
816 cellular()->adaptor()->EmitKeyValueStoreChanged(
817 flimflam::kSIMLockStatusProperty, SimLockStatusToProperty(NULL));
818 }
Darin Petkov63138a92012-02-06 14:09:15 +0100819 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100820}
821
Eric Shienbrood9a245532012-03-07 14:20:39 -0500822void CellularCapabilityGSM::OnNetworkModeSignal(uint32 /*mode*/) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100823 // TODO(petkov): Implement this.
824 NOTIMPLEMENTED();
825}
826
Eric Shienbrood9a245532012-03-07 14:20:39 -0500827void CellularCapabilityGSM::OnRegistrationInfoSignal(
828 uint32 status, const string &operator_code, const string &operator_name) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700829 SLOG(Cellular, 2) << __func__ << ": regstate=" << status
830 << ", opercode=" << operator_code
831 << ", opername=" << operator_name;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500832 registration_state_ = status;
833 serving_operator_.SetCode(operator_code);
834 serving_operator_.SetName(operator_name);
835 UpdateOperatorInfo();
836 cellular()->HandleNewRegistrationState();
Darin Petkov184c54e2011-11-15 12:44:39 +0100837}
838
Eric Shienbrood9a245532012-03-07 14:20:39 -0500839void CellularCapabilityGSM::OnSignalQualitySignal(uint32 quality) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100840 cellular()->HandleNewSignalQuality(quality);
841}
842
Eric Shienbrood9a245532012-03-07 14:20:39 -0500843void CellularCapabilityGSM::OnGetRegistrationInfoReply(
844 uint32 status, const string &operator_code, const string &operator_name,
845 const Error &error) {
846 if (error.IsSuccess())
847 OnRegistrationInfoSignal(status, operator_code, operator_name);
848}
849
850void CellularCapabilityGSM::OnGetSignalQualityReply(uint32 quality,
851 const Error &error) {
852 if (error.IsSuccess())
853 OnSignalQualitySignal(quality);
854}
855
856void CellularCapabilityGSM::OnGetIMEIReply(const ResultCallback &callback,
857 const string &imei,
858 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500859 if (error.IsSuccess()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700860 SLOG(Cellular, 2) << "IMEI: " << imei;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500861 imei_ = imei;
862 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700863 SLOG(Cellular, 2) << "GetIMEI failed - " << error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500864 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500865 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500866}
867
Eric Shienbrood9a245532012-03-07 14:20:39 -0500868void CellularCapabilityGSM::OnGetIMSIReply(const ResultCallback &callback,
869 const string &imsi,
870 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500871 if (error.IsSuccess()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700872 SLOG(Cellular, 2) << "IMSI: " << imsi;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500873 imsi_ = imsi;
874 SetHomeProvider();
Gary Morain82a31a02012-08-02 18:03:32 -0700875 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500876 } else {
Gary Morain82a31a02012-08-02 18:03:32 -0700877 if (get_imsi_retries_++ < kGetIMSIRetryLimit) {
878 SLOG(Cellular, 2) << "GetIMSI failed - " << error << ". Retrying";
879 base::Callback<void(void)> retry_get_imsi_cb =
880 Bind(&CellularCapabilityGSM::GetIMSI,
881 weak_ptr_factory_.GetWeakPtr(), callback);
882 cellular()->dispatcher()->PostDelayedTask(
883 retry_get_imsi_cb,
884 get_imsi_retry_delay_milliseconds_);
885 } else {
886 LOG(INFO) << "GetIMSI failed - " << error;
887 callback.Run(error);
888 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500889 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500890}
891
Eric Shienbrood9a245532012-03-07 14:20:39 -0500892void CellularCapabilityGSM::OnGetSPNReply(const ResultCallback &callback,
893 const string &spn,
894 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500895 if (error.IsSuccess()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700896 SLOG(Cellular, 2) << "SPN: " << spn;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500897 spn_ = spn;
898 SetHomeProvider();
899 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700900 SLOG(Cellular, 2) << "GetSPN failed - " << error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500901 }
Thieu Le923006b2012-04-05 16:32:58 -0700902 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500903}
904
Eric Shienbrood9a245532012-03-07 14:20:39 -0500905void CellularCapabilityGSM::OnGetMSISDNReply(const ResultCallback &callback,
906 const string &msisdn,
907 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500908 if (error.IsSuccess()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700909 SLOG(Cellular, 2) << "MSISDN: " << msisdn;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500910 mdn_ = msisdn;
911 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700912 SLOG(Cellular, 2) << "GetMSISDN failed - " << error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500913 }
Thieu Le923006b2012-04-05 16:32:58 -0700914 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500915}
916
Darin Petkovdaf43862011-10-27 11:37:28 +0200917} // namespace shill