blob: ad7b9ee8f812b8dac1b3d56ce034ce02926fff27 [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;
Ben Chan3ecdf822012-08-06 12:29:23 -070080
81 // TODO(benchan): This is a hack to initialize the GSM card proxy for GetIMSI
82 // before InitProxies is called. There are side-effects of calling InitProxies
83 // before the device is enabled. It's better to refactor InitProxies such that
84 // proxies can be created when the cellular device/capability is constructed,
85 // but callbacks for DBus signal updates are not set up until the device is
86 // enabled.
87 card_proxy_.reset(
88 proxy_factory->CreateModemGSMCardProxy(cellular->dbus_path(),
89 cellular->dbus_owner()));
90 // TODO(benchan): To allow unit testing using a mock proxy without further
91 // complicating the code, the test proxy factory is set up to return a NULL
92 // pointer when CellularCapabilityGSM is constructed. Refactor the code to
93 // avoid this hack.
94 if (card_proxy_.get())
95 InitProperties();
Darin Petkov1272a432011-11-10 15:53:37 +010096}
Darin Petkovdaf43862011-10-27 11:37:28 +020097
Darin Petkov63138a92012-02-06 14:09:15 +010098KeyValueStore CellularCapabilityGSM::SimLockStatusToProperty(Error */*error*/) {
99 KeyValueStore status;
100 status.SetBool(flimflam::kSIMLockEnabledProperty, sim_lock_status_.enabled);
101 status.SetString(flimflam::kSIMLockTypeProperty, sim_lock_status_.lock_type);
102 status.SetUint(flimflam::kSIMLockRetriesLeftProperty,
103 sim_lock_status_.retries_left);
104 return status;
Darin Petkov721ac932011-11-16 15:43:09 +0100105}
106
Darin Petkov63138a92012-02-06 14:09:15 +0100107void CellularCapabilityGSM::HelpRegisterDerivedKeyValueStore(
Darin Petkov721ac932011-11-16 15:43:09 +0100108 const string &name,
Darin Petkov63138a92012-02-06 14:09:15 +0100109 KeyValueStore(CellularCapabilityGSM::*get)(Error *error),
110 void(CellularCapabilityGSM::*set)(
111 const KeyValueStore &value, Error *error)) {
112 cellular()->mutable_store()->RegisterDerivedKeyValueStore(
Darin Petkov721ac932011-11-16 15:43:09 +0100113 name,
Darin Petkov63138a92012-02-06 14:09:15 +0100114 KeyValueStoreAccessor(
115 new CustomAccessor<CellularCapabilityGSM, KeyValueStore>(
Darin Petkov721ac932011-11-16 15:43:09 +0100116 this, get, set)));
117}
118
Eric Shienbrood9a245532012-03-07 14:20:39 -0500119void CellularCapabilityGSM::InitProxies() {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400120 CellularCapabilityClassic::InitProxies();
Ben Chan3ecdf822012-08-06 12:29:23 -0700121 // TODO(benchan): Remove this check after refactoring the proxy
122 // initialization.
123 if (!card_proxy_.get()) {
124 card_proxy_.reset(
125 proxy_factory()->CreateModemGSMCardProxy(cellular()->dbus_path(),
126 cellular()->dbus_owner()));
127 }
Darin Petkov184c54e2011-11-15 12:44:39 +0100128 network_proxy_.reset(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500129 proxy_factory()->CreateModemGSMNetworkProxy(cellular()->dbus_path(),
Darin Petkovdaf43862011-10-27 11:37:28 +0200130 cellular()->dbus_owner()));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500131 network_proxy_->set_signal_quality_callback(
132 Bind(&CellularCapabilityGSM::OnSignalQualitySignal,
133 weak_ptr_factory_.GetWeakPtr()));
134 network_proxy_->set_network_mode_callback(
135 Bind(&CellularCapabilityGSM::OnNetworkModeSignal,
136 weak_ptr_factory_.GetWeakPtr()));
137 network_proxy_->set_registration_info_callback(
138 Bind(&CellularCapabilityGSM::OnRegistrationInfoSignal,
139 weak_ptr_factory_.GetWeakPtr()));
Darin Petkovdaf43862011-10-27 11:37:28 +0200140}
141
Ben Chan3ecdf822012-08-06 12:29:23 -0700142void CellularCapabilityGSM::InitProperties() {
143 CellularTaskList *tasks = new CellularTaskList();
144 ResultCallback cb_ignore_error =
145 Bind(&CellularCapabilityGSM::StepCompletedCallback,
146 weak_ptr_factory_.GetWeakPtr(), ResultCallback(), true, tasks);
147 // Chrome uses IMSI to determine if a SIM is present before allowing the
148 // modem to be enabled, so shill needs to obtain IMSI even before the device
149 // is enabled.
150 tasks->push_back(Bind(&CellularCapabilityGSM::GetIMSI,
151 weak_ptr_factory_.GetWeakPtr(), cb_ignore_error));
152 RunNextStep(tasks);
153}
154
Eric Shienbrood9a245532012-03-07 14:20:39 -0500155void CellularCapabilityGSM::StartModem(Error *error,
156 const ResultCallback &callback) {
157 InitProxies();
158
159 CellularTaskList *tasks = new CellularTaskList();
160 ResultCallback cb =
161 Bind(&CellularCapabilityGSM::StepCompletedCallback,
Thieu Le923006b2012-04-05 16:32:58 -0700162 weak_ptr_factory_.GetWeakPtr(), callback, false, tasks);
163 ResultCallback cb_ignore_error =
164 Bind(&CellularCapabilityGSM::StepCompletedCallback,
165 weak_ptr_factory_.GetWeakPtr(), callback, true, tasks);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400166 if (!cellular()->IsUnderlyingDeviceEnabled())
167 tasks->push_back(Bind(&CellularCapabilityGSM::EnableModem,
168 weak_ptr_factory_.GetWeakPtr(), cb));
169 // If we're within range of the home network, the modem will try to
170 // register once it's enabled, or may be already registered if we
171 // started out enabled.
172 if (!IsUnderlyingDeviceRegistered() && !selected_network_.empty())
173 tasks->push_back(Bind(&CellularCapabilityGSM::Register,
174 weak_ptr_factory_.GetWeakPtr(), cb));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500175 tasks->push_back(Bind(&CellularCapabilityGSM::GetIMEI,
176 weak_ptr_factory_.GetWeakPtr(), cb));
Gary Morain82a31a02012-08-02 18:03:32 -0700177 get_imsi_retries_ = 0;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500178 tasks->push_back(Bind(&CellularCapabilityGSM::GetIMSI,
179 weak_ptr_factory_.GetWeakPtr(), cb));
180 tasks->push_back(Bind(&CellularCapabilityGSM::GetSPN,
Thieu Le923006b2012-04-05 16:32:58 -0700181 weak_ptr_factory_.GetWeakPtr(), cb_ignore_error));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500182 tasks->push_back(Bind(&CellularCapabilityGSM::GetMSISDN,
Thieu Le923006b2012-04-05 16:32:58 -0700183 weak_ptr_factory_.GetWeakPtr(), cb_ignore_error));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500184 tasks->push_back(Bind(&CellularCapabilityGSM::GetProperties,
185 weak_ptr_factory_.GetWeakPtr(), cb));
186 tasks->push_back(Bind(&CellularCapabilityGSM::GetModemInfo,
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400187 weak_ptr_factory_.GetWeakPtr(), cb_ignore_error));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500188 tasks->push_back(Bind(&CellularCapabilityGSM::FinishEnable,
189 weak_ptr_factory_.GetWeakPtr(), cb));
190
191 RunNextStep(tasks);
192}
193
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400194bool CellularCapabilityGSM::IsUnderlyingDeviceRegistered() const {
195 switch (cellular()->modem_state()) {
196 case Cellular::kModemStateUnknown:
197 case Cellular::kModemStateDisabled:
198 case Cellular::kModemStateInitializing:
199 case Cellular::kModemStateLocked:
200 case Cellular::kModemStateDisabling:
201 case Cellular::kModemStateEnabling:
202 case Cellular::kModemStateEnabled:
203 return false;
204 case Cellular::kModemStateSearching:
205 case Cellular::kModemStateRegistered:
206 case Cellular::kModemStateDisconnecting:
207 case Cellular::kModemStateConnecting:
208 case Cellular::kModemStateConnected:
209 return true;
210 }
211 return false;
212}
213
Eric Shienbrood9a245532012-03-07 14:20:39 -0500214void CellularCapabilityGSM::ReleaseProxies() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700215 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400216 CellularCapabilityClassic::ReleaseProxies();
Darin Petkov721ac932011-11-16 15:43:09 +0100217 card_proxy_.reset();
218 network_proxy_.reset();
219}
220
Darin Petkov5f316f62011-11-18 12:10:26 +0100221void CellularCapabilityGSM::OnServiceCreated() {
Darin Petkov31332412012-01-28 01:50:02 +0100222 // If IMSI is available, base the service's storage identifier on it.
223 if (!imsi_.empty()) {
224 cellular()->service()->SetStorageIdentifier(
Darin Petkovdd3e8662012-02-03 13:16:20 +0100225 string(flimflam::kTypeCellular) + "_" +
226 cellular()->address() + "_" + imsi_);
Darin Petkov31332412012-01-28 01:50:02 +0100227 }
Darin Petkovb9c99332012-01-12 13:13:00 +0100228 cellular()->service()->SetActivationState(
Darin Petkov5f316f62011-11-18 12:10:26 +0100229 flimflam::kActivationStateActivated);
230 UpdateServingOperator();
231}
232
Darin Petkovae0c64e2011-11-15 15:50:27 +0100233void CellularCapabilityGSM::UpdateStatus(const DBusPropertiesMap &properties) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400234 if (ContainsKey(properties, kModemPropertyIMSI)) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100235 SetHomeProvider();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100236 }
237}
238
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400239// Create the list of APNs to try, in the following order:
240// - last APN that resulted in a successful connection attempt on the
241// current network (if any)
242// - the APN, if any, that was set by the user
243// - the list of APNs found in the mobile broadband provider DB for the
244// home provider associated with the current SIM
245// - as a last resort, attempt to connect with no APN
246void CellularCapabilityGSM::SetupApnTryList() {
247 apn_try_list_.clear();
248
249 DCHECK(cellular()->service().get());
250 const Stringmap *apn_info = cellular()->service()->GetLastGoodApn();
251 if (apn_info)
252 apn_try_list_.push_back(*apn_info);
253
254 apn_info = cellular()->service()->GetUserSpecifiedApn();
255 if (apn_info)
256 apn_try_list_.push_back(*apn_info);
257
258 apn_try_list_.insert(apn_try_list_.end(), apn_list_.begin(), apn_list_.end());
259}
260
Darin Petkovae0c64e2011-11-15 15:50:27 +0100261void CellularCapabilityGSM::SetupConnectProperties(
262 DBusPropertiesMap *properties) {
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400263 SetupApnTryList();
264 FillConnectPropertyMap(properties);
265}
266
267void CellularCapabilityGSM::FillConnectPropertyMap(
268 DBusPropertiesMap *properties) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500269 (*properties)[kConnectPropertyPhoneNumber].writer().append_string(
Darin Petkovae0c64e2011-11-15 15:50:27 +0100270 kPhoneNumber);
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400271
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400272 if (!AllowRoaming())
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400273 (*properties)[kConnectPropertyHomeOnly].writer().append_bool(true);
274
275 if (!apn_try_list_.empty()) {
276 // Leave the APN at the front of the list, so that it can be recorded
277 // if the connect attempt succeeds.
278 Stringmap apn_info = apn_try_list_.front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700279 SLOG(Cellular, 2) << __func__ << ": Using APN "
280 << apn_info[flimflam::kApnProperty];
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400281 (*properties)[kConnectPropertyApn].writer().append_string(
282 apn_info[flimflam::kApnProperty].c_str());
283 if (ContainsKey(apn_info, flimflam::kApnUsernameProperty))
284 (*properties)[kConnectPropertyApnUsername].writer().append_string(
285 apn_info[flimflam::kApnUsernameProperty].c_str());
286 if (ContainsKey(apn_info, flimflam::kApnPasswordProperty))
287 (*properties)[kConnectPropertyApnPassword].writer().append_string(
288 apn_info[flimflam::kApnPasswordProperty].c_str());
289 }
290}
291
Nathan Williamsb54974f2012-04-19 11:16:30 -0400292void CellularCapabilityGSM::Connect(const DBusPropertiesMap &properties,
293 Error *error,
294 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700295 SLOG(Cellular, 2) << __func__;
Nathan Williamsb54974f2012-04-19 11:16:30 -0400296 ResultCallback cb = Bind(&CellularCapabilityGSM::OnConnectReply,
297 weak_ptr_factory_.GetWeakPtr(),
298 callback);
299 simple_proxy_->Connect(properties, error, cb, kTimeoutConnect);
300}
301
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400302void CellularCapabilityGSM::OnConnectReply(const ResultCallback &callback,
303 const Error &error) {
Thieu Leb5954a22012-05-18 10:37:34 -0700304 CellularServiceRefPtr service = cellular()->service();
305 if (!service) {
306 // The service could have been deleted before our Connect() request
307 // completes if the modem was enabled and then quickly disabled.
308 apn_try_list_.clear();
309 } else if (error.IsFailure()) {
310 service->ClearLastGoodApn();
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400311 // The APN that was just tried (and failed) is still at the
312 // front of the list, about to be removed. If the list is empty
313 // after that, try one last time without an APN. This may succeed
314 // with some modems in some cases.
315 if (error.type() == Error::kInvalidApn && !apn_try_list_.empty()) {
316 apn_try_list_.pop_front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700317 SLOG(Cellular, 2) << "Connect failed with invalid APN, "
318 << apn_try_list_.size() << " remaining APNs to try";
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400319 DBusPropertiesMap props;
320 FillConnectPropertyMap(&props);
321 Error error;
322 Connect(props, &error, callback);
323 return;
324 }
325 } else if (!apn_try_list_.empty()) {
Thieu Leb5954a22012-05-18 10:37:34 -0700326 service->SetLastGoodApn(apn_try_list_.front());
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400327 apn_try_list_.clear();
328 }
Nathan Williamsb54974f2012-04-19 11:16:30 -0400329 if (!callback.is_null())
330 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400331}
332
333bool CellularCapabilityGSM::AllowRoaming() {
334 bool requires_roaming =
335 home_provider_ ? home_provider_->requires_roaming : false;
336 return requires_roaming || allow_roaming_property();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100337}
338
Eric Shienbrood9a245532012-03-07 14:20:39 -0500339// always called from an async context
340void CellularCapabilityGSM::GetIMEI(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700341 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500342 CHECK(!callback.is_null());
343 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500344 if (imei_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500345 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetIMEIReply,
346 weak_ptr_factory_.GetWeakPtr(), callback);
347 card_proxy_->GetIMEI(&error, cb, kTimeoutDefault);
348 if (error.IsFailure())
349 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500350 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700351 SLOG(Cellular, 2) << "Already have IMEI " << imei_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500352 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100353 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500354}
355
Eric Shienbrood9a245532012-03-07 14:20:39 -0500356// always called from an async context
357void CellularCapabilityGSM::GetIMSI(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700358 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500359 CHECK(!callback.is_null());
360 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500361 if (imsi_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500362 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetIMSIReply,
363 weak_ptr_factory_.GetWeakPtr(),
364 callback);
365 card_proxy_->GetIMSI(&error, cb, kTimeoutDefault);
366 if (error.IsFailure())
367 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500368 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700369 SLOG(Cellular, 2) << "Already have IMSI " << imsi_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500370 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100371 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500372}
373
Eric Shienbrood9a245532012-03-07 14:20:39 -0500374// always called from an async context
375void CellularCapabilityGSM::GetSPN(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700376 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500377 CHECK(!callback.is_null());
378 Error error;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100379 if (spn_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500380 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetSPNReply,
381 weak_ptr_factory_.GetWeakPtr(),
382 callback);
383 card_proxy_->GetSPN(&error, cb, kTimeoutDefault);
384 if (error.IsFailure())
385 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500386 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700387 SLOG(Cellular, 2) << "Already have SPN " << spn_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500388 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100389 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500390}
391
Eric Shienbrood9a245532012-03-07 14:20:39 -0500392// always called from an async context
393void CellularCapabilityGSM::GetMSISDN(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700394 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500395 CHECK(!callback.is_null());
396 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500397 if (mdn_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500398 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetMSISDNReply,
399 weak_ptr_factory_.GetWeakPtr(),
400 callback);
401 card_proxy_->GetMSISDN(&error, cb, kTimeoutDefault);
402 if (error.IsFailure())
403 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500404 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700405 SLOG(Cellular, 2) << "Already have MSISDN " << mdn_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500406 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100407 }
408}
409
Darin Petkov3e509242011-11-10 14:46:44 +0100410void CellularCapabilityGSM::GetSignalQuality() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700411 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500412 SignalQualityCallback callback =
413 Bind(&CellularCapabilityGSM::OnGetSignalQualityReply,
414 weak_ptr_factory_.GetWeakPtr());
415 network_proxy_->GetSignalQuality(NULL, callback, kTimeoutDefault);
Darin Petkov3e509242011-11-10 14:46:44 +0100416}
417
Eric Shienbrood9a245532012-03-07 14:20:39 -0500418void CellularCapabilityGSM::GetRegistrationState() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700419 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500420 RegistrationInfoCallback callback =
421 Bind(&CellularCapabilityGSM::OnGetRegistrationInfoReply,
422 weak_ptr_factory_.GetWeakPtr());
423 network_proxy_->GetRegistrationInfo(NULL, callback, kTimeoutDefault);
Darin Petkov184c54e2011-11-15 12:44:39 +0100424}
425
Eric Shienbrood9a245532012-03-07 14:20:39 -0500426void CellularCapabilityGSM::GetProperties(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700427 SLOG(Cellular, 2) << __func__;
Darin Petkov63138a92012-02-06 14:09:15 +0100428
Darin Petkov184c54e2011-11-15 12:44:39 +0100429 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
430 uint32 tech = network_proxy_->AccessTechnology();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100431 SetAccessTechnology(tech);
Ben Chanfad4a0b2012-04-18 15:49:59 -0700432 SLOG(Cellular, 2) << "GSM AccessTechnology: " << tech;
Darin Petkov63138a92012-02-06 14:09:15 +0100433
434 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
435 uint32 locks = card_proxy_->EnabledFacilityLocks();
436 sim_lock_status_.enabled = locks & MM_MODEM_GSM_FACILITY_SIM;
Ben Chanfad4a0b2012-04-18 15:49:59 -0700437 SLOG(Cellular, 2) << "GSM EnabledFacilityLocks: " << locks;
Darin Petkov63138a92012-02-06 14:09:15 +0100438
Eric Shienbrood9a245532012-03-07 14:20:39 -0500439 callback.Run(Error());
Darin Petkov184c54e2011-11-15 12:44:39 +0100440}
441
Darin Petkovac635a82012-01-10 16:51:58 +0100442string CellularCapabilityGSM::CreateFriendlyServiceName() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700443 SLOG(Cellular, 2) << __func__;
Darin Petkovac635a82012-01-10 16:51:58 +0100444 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME &&
445 !cellular()->home_provider().GetName().empty()) {
446 return cellular()->home_provider().GetName();
447 }
448 if (!serving_operator_.GetName().empty()) {
449 return serving_operator_.GetName();
450 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500451 if (!carrier_.empty()) {
452 return carrier_;
Darin Petkovac635a82012-01-10 16:51:58 +0100453 }
454 if (!serving_operator_.GetCode().empty()) {
455 return "cellular_" + serving_operator_.GetCode();
456 }
457 return base::StringPrintf("GSMNetwork%u", friendly_service_name_id_++);
458}
459
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100460void CellularCapabilityGSM::SetHomeProvider() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700461 SLOG(Cellular, 2) << __func__ << "(IMSI: " << imsi_
462 << " SPN: " << spn_ << ")";
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100463 // TODO(petkov): The test for NULL provider_db should be done by
464 // mobile_provider_lookup_best_match.
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500465 if (imsi_.empty() || !cellular()->provider_db()) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100466 return;
467 }
468 mobile_provider *provider =
469 mobile_provider_lookup_best_match(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500470 cellular()->provider_db(), spn_.c_str(), imsi_.c_str());
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100471 if (!provider) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700472 SLOG(Cellular, 2) << "GSM provider not found.";
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100473 return;
474 }
475 home_provider_ = provider;
476 Cellular::Operator oper;
477 if (provider->networks) {
478 oper.SetCode(provider->networks[0]);
479 }
480 if (provider->country) {
481 oper.SetCountry(provider->country);
482 }
483 if (spn_.empty()) {
484 const char *name = mobile_provider_get_name(provider);
485 if (name) {
486 oper.SetName(name);
487 }
488 } else {
489 oper.SetName(spn_);
490 }
491 cellular()->set_home_provider(oper);
Darin Petkov3cfbf212011-11-21 16:02:09 +0100492 InitAPNList();
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100493}
494
Darin Petkovae0c64e2011-11-15 15:50:27 +0100495void CellularCapabilityGSM::UpdateOperatorInfo() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700496 SLOG(Cellular, 2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100497 const string &network_id = serving_operator_.GetCode();
498 if (!network_id.empty()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700499 SLOG(Cellular, 2) << "Looking up network id: " << network_id;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100500 mobile_provider *provider =
501 mobile_provider_lookup_by_network(cellular()->provider_db(),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100502 network_id.c_str());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100503 if (provider) {
504 const char *provider_name = mobile_provider_get_name(provider);
505 if (provider_name && *provider_name) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100506 serving_operator_.SetName(provider_name);
507 if (provider->country) {
508 serving_operator_.SetCountry(provider->country);
509 }
Ben Chanfad4a0b2012-04-18 15:49:59 -0700510 SLOG(Cellular, 2) << "Operator name: " << serving_operator_.GetName()
511 << ", country: " << serving_operator_.GetCountry();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100512 }
513 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700514 SLOG(Cellular, 2) << "GSM provider not found.";
Darin Petkovae0c64e2011-11-15 15:50:27 +0100515 }
516 }
517 UpdateServingOperator();
518}
519
520void CellularCapabilityGSM::UpdateServingOperator() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700521 SLOG(Cellular, 2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100522 if (cellular()->service().get()) {
Darin Petkov9cb02682012-01-28 00:17:38 +0100523 cellular()->service()->SetServingOperator(serving_operator_);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100524 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100525}
526
Darin Petkov3cfbf212011-11-21 16:02:09 +0100527void CellularCapabilityGSM::InitAPNList() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700528 SLOG(Cellular, 2) << __func__;
Darin Petkov3cfbf212011-11-21 16:02:09 +0100529 if (!home_provider_) {
530 return;
531 }
532 apn_list_.clear();
533 for (int i = 0; i < home_provider_->num_apns; ++i) {
534 Stringmap props;
535 mobile_apn *apn = home_provider_->apns[i];
536 if (apn->value) {
537 props[flimflam::kApnProperty] = apn->value;
538 }
539 if (apn->username) {
540 props[flimflam::kApnUsernameProperty] = apn->username;
541 }
542 if (apn->password) {
543 props[flimflam::kApnPasswordProperty] = apn->password;
544 }
545 // Find the first localized and non-localized name, if any.
546 const localized_name *lname = NULL;
547 const localized_name *name = NULL;
548 for (int j = 0; j < apn->num_names; ++j) {
549 if (apn->names[j]->lang) {
550 if (!lname) {
551 lname = apn->names[j];
552 }
553 } else if (!name) {
554 name = apn->names[j];
555 }
556 }
557 if (name) {
558 props[flimflam::kApnNameProperty] = name->name;
559 }
560 if (lname) {
561 props[flimflam::kApnLocalizedNameProperty] = lname->name;
562 props[flimflam::kApnLanguageProperty] = lname->lang;
563 }
564 apn_list_.push_back(props);
565 }
566 cellular()->adaptor()->EmitStringmapsChanged(
567 flimflam::kCellularApnListProperty, apn_list_);
568}
569
Eric Shienbrood9a245532012-03-07 14:20:39 -0500570// always called from an async context
571void CellularCapabilityGSM::Register(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700572 SLOG(Cellular, 2) << __func__ << " \"" << selected_network_ << "\"";
Eric Shienbrood9a245532012-03-07 14:20:39 -0500573 CHECK(!callback.is_null());
574 Error error;
575 ResultCallback cb = Bind(&CellularCapabilityGSM::OnRegisterReply,
576 weak_ptr_factory_.GetWeakPtr(), callback);
577 network_proxy_->Register(selected_network_, &error, cb, kTimeoutRegister);
578 if (error.IsFailure())
579 callback.Run(error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100580}
581
582void CellularCapabilityGSM::RegisterOnNetwork(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500583 const string &network_id,
584 Error *error,
585 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700586 SLOG(Cellular, 2) << __func__ << "(" << network_id << ")";
Eric Shienbrood9a245532012-03-07 14:20:39 -0500587 CHECK(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500588 desired_network_ = network_id;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500589 ResultCallback cb = Bind(&CellularCapabilityGSM::OnRegisterReply,
590 weak_ptr_factory_.GetWeakPtr(), callback);
591 network_proxy_->Register(network_id, error, cb, kTimeoutRegister);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500592}
593
Eric Shienbrood9a245532012-03-07 14:20:39 -0500594void CellularCapabilityGSM::OnRegisterReply(const ResultCallback &callback,
595 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700596 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500597
598 if (error.IsSuccess()) {
599 selected_network_ = desired_network_;
600 desired_network_.clear();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500601 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500602 return;
603 }
604 // If registration on the desired network failed,
605 // try to register on the home network.
606 if (!desired_network_.empty()) {
607 desired_network_.clear();
608 selected_network_.clear();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500609 LOG(INFO) << "Couldn't register on selected network, trying home network";
610 Register(callback);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500611 return;
612 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500613 callback.Run(error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100614}
615
Darin Petkovb72cf402011-11-22 14:51:39 +0100616bool CellularCapabilityGSM::IsRegistered() {
617 return (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
618 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING);
619}
620
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400621void CellularCapabilityGSM::SetUnregistered(bool searching) {
622 // If we're already in some non-registered state, don't override that
623 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
624 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING) {
625 registration_state_ =
626 (searching ? MM_MODEM_GSM_NETWORK_REG_STATUS_SEARCHING :
627 MM_MODEM_GSM_NETWORK_REG_STATUS_IDLE);
628 }
629}
630
Darin Petkovb05315f2011-11-07 10:14:25 +0100631void CellularCapabilityGSM::RequirePIN(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500632 const std::string &pin, bool require,
633 Error *error, const ResultCallback &callback) {
634 CHECK(error);
635 card_proxy_->EnablePIN(pin, require, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100636}
637
Darin Petkove5bc2cb2011-12-07 14:47:32 +0100638void CellularCapabilityGSM::EnterPIN(const string &pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500639 Error *error,
640 const ResultCallback &callback) {
641 CHECK(error);
642 card_proxy_->SendPIN(pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100643}
644
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100645void CellularCapabilityGSM::UnblockPIN(const string &unblock_code,
646 const string &pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500647 Error *error,
648 const ResultCallback &callback) {
649 CHECK(error);
650 card_proxy_->SendPUK(unblock_code, pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100651}
652
653void CellularCapabilityGSM::ChangePIN(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500654 const string &old_pin, const string &new_pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500655 Error *error, const ResultCallback &callback) {
656 CHECK(error);
657 card_proxy_->ChangePIN(old_pin, new_pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100658}
659
Eric Shienbrood9a245532012-03-07 14:20:39 -0500660void CellularCapabilityGSM::Scan(Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700661 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500662 CHECK(error);
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400663 if (scanning_) {
664 Error::PopulateAndLog(error, Error::kInProgress, "Already scanning");
665 return;
666 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500667 ScanResultsCallback cb = Bind(&CellularCapabilityGSM::OnScanReply,
668 weak_ptr_factory_.GetWeakPtr(), callback);
669 network_proxy_->Scan(error, cb, kTimeoutScan);
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400670 if (!error->IsFailure()) {
671 scanning_ = true;
672 cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty,
673 scanning_);
674 }
Darin Petkov1272a432011-11-10 15:53:37 +0100675}
676
Eric Shienbrood9a245532012-03-07 14:20:39 -0500677void CellularCapabilityGSM::OnScanReply(const ResultCallback &callback,
678 const GSMScanResults &results,
679 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700680 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400681
682 // Error handling is weak. The current expectation is that on any
683 // error, found_networks_ should be cleared and a property change
684 // notification sent out.
685 //
686 // TODO(jglasgow): fix error handling
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400687 scanning_ = false;
688 cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty,
689 scanning_);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500690 found_networks_.clear();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400691 if (!error.IsFailure()) {
692 for (GSMScanResults::const_iterator it = results.begin();
693 it != results.end(); ++it) {
694 found_networks_.push_back(ParseScanResult(*it));
695 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500696 }
Darin Petkovb7828b02012-02-03 12:34:30 +0100697 cellular()->adaptor()->EmitStringmapsChanged(flimflam::kFoundNetworksProperty,
698 found_networks_);
Gary Moraina49062a2012-04-27 13:48:41 -0700699 if (!callback.is_null())
700 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500701}
702
703Stringmap CellularCapabilityGSM::ParseScanResult(const GSMScanResult &result) {
Darin Petkov1272a432011-11-10 15:53:37 +0100704 Stringmap parsed;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500705 for (GSMScanResult::const_iterator it = result.begin();
706 it != result.end(); ++it) {
Darin Petkov1272a432011-11-10 15:53:37 +0100707 // TODO(petkov): Define these in system_api/service_constants.h. The
708 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
709 static const char * const kStatusString[] = {
710 "unknown",
711 "available",
712 "current",
713 "forbidden",
714 };
715 static const char * const kTechnologyString[] = {
716 flimflam::kNetworkTechnologyGsm,
717 "GSM Compact",
718 flimflam::kNetworkTechnologyUmts,
719 flimflam::kNetworkTechnologyEdge,
720 "HSDPA",
721 "HSUPA",
722 flimflam::kNetworkTechnologyHspa,
723 };
Ben Chanfad4a0b2012-04-18 15:49:59 -0700724 SLOG(Cellular, 2) << "Network property: " << it->first << " = "
725 << it->second;
Darin Petkov1272a432011-11-10 15:53:37 +0100726 if (it->first == kNetworkPropertyStatus) {
727 int status = 0;
728 if (base::StringToInt(it->second, &status) &&
729 status >= 0 &&
730 status < static_cast<int>(arraysize(kStatusString))) {
731 parsed[flimflam::kStatusProperty] = kStatusString[status];
732 } else {
733 LOG(ERROR) << "Unexpected status value: " << it->second;
734 }
735 } else if (it->first == kNetworkPropertyID) {
736 parsed[flimflam::kNetworkIdProperty] = it->second;
737 } else if (it->first == kNetworkPropertyLongName) {
738 parsed[flimflam::kLongNameProperty] = it->second;
739 } else if (it->first == kNetworkPropertyShortName) {
740 parsed[flimflam::kShortNameProperty] = it->second;
741 } else if (it->first == kNetworkPropertyAccessTechnology) {
742 int tech = 0;
743 if (base::StringToInt(it->second, &tech) &&
744 tech >= 0 &&
745 tech < static_cast<int>(arraysize(kTechnologyString))) {
746 parsed[flimflam::kTechnologyProperty] = kTechnologyString[tech];
747 } else {
748 LOG(ERROR) << "Unexpected technology value: " << it->second;
749 }
750 } else {
751 LOG(WARNING) << "Unknown network property ignored: " << it->first;
752 }
753 }
754 // If the long name is not available but the network ID is, look up the long
755 // name in the mobile provider database.
756 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
757 parsed[flimflam::kLongNameProperty].empty()) &&
758 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
759 mobile_provider *provider =
760 mobile_provider_lookup_by_network(
761 cellular()->provider_db(),
762 parsed[flimflam::kNetworkIdProperty].c_str());
763 if (provider) {
764 const char *long_name = mobile_provider_get_name(provider);
765 if (long_name && *long_name) {
766 parsed[flimflam::kLongNameProperty] = long_name;
767 }
768 }
769 }
770 return parsed;
771}
772
Darin Petkovae0c64e2011-11-15 15:50:27 +0100773void CellularCapabilityGSM::SetAccessTechnology(uint32 access_technology) {
774 access_technology_ = access_technology;
775 if (cellular()->service().get()) {
Darin Petkovb72cf402011-11-22 14:51:39 +0100776 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100777 }
778}
779
Darin Petkov20c13ec2011-11-09 15:07:15 +0100780string CellularCapabilityGSM::GetNetworkTechnologyString() const {
Darin Petkovb72cf402011-11-22 14:51:39 +0100781 switch (access_technology_) {
782 case MM_MODEM_GSM_ACCESS_TECH_GSM:
783 case MM_MODEM_GSM_ACCESS_TECH_GSM_COMPACT:
784 return flimflam::kNetworkTechnologyGsm;
785 case MM_MODEM_GSM_ACCESS_TECH_GPRS:
786 return flimflam::kNetworkTechnologyGprs;
787 case MM_MODEM_GSM_ACCESS_TECH_EDGE:
788 return flimflam::kNetworkTechnologyEdge;
789 case MM_MODEM_GSM_ACCESS_TECH_UMTS:
790 return flimflam::kNetworkTechnologyUmts;
791 case MM_MODEM_GSM_ACCESS_TECH_HSDPA:
792 case MM_MODEM_GSM_ACCESS_TECH_HSUPA:
793 case MM_MODEM_GSM_ACCESS_TECH_HSPA:
794 return flimflam::kNetworkTechnologyHspa;
795 case MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS:
796 return flimflam::kNetworkTechnologyHspaPlus;
797 default:
798 break;
Darin Petkov20c13ec2011-11-09 15:07:15 +0100799 }
800 return "";
801}
802
803string CellularCapabilityGSM::GetRoamingStateString() const {
Darin Petkov184c54e2011-11-15 12:44:39 +0100804 switch (registration_state_) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100805 case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME:
806 return flimflam::kRoamingStateHome;
807 case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING:
808 return flimflam::kRoamingStateRoaming;
809 default:
810 break;
811 }
812 return flimflam::kRoamingStateUnknown;
813}
814
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400815void CellularCapabilityGSM::OnDBusPropertiesChanged(
816 const string &interface,
817 const DBusPropertiesMap &properties,
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400818 const vector<string> &invalidated_properties) {
819 CellularCapabilityClassic::OnDBusPropertiesChanged(interface,
820 properties,
821 invalidated_properties);
822 if (interface == MM_MODEM_GSM_NETWORK_INTERFACE) {
823 uint32 access_technology = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
824 if (DBusProperties::GetUint32(properties,
825 kPropertyAccessTechnology,
826 &access_technology)) {
827 SetAccessTechnology(access_technology);
828 }
Gary Morainbaeefdf2012-04-30 14:53:35 -0700829 } else {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400830 bool emit = false;
Gary Morainbaeefdf2012-04-30 14:53:35 -0700831 if (interface == MM_MODEM_GSM_CARD_INTERFACE) {
832 uint32 locks = 0;
833 if (DBusProperties::GetUint32(
834 properties, kPropertyEnabledFacilityLocks, &locks)) {
835 sim_lock_status_.enabled = locks & MM_MODEM_GSM_FACILITY_SIM;
836 emit = true;
837 }
838 } else if (interface == MM_MODEM_INTERFACE) {
839 if (DBusProperties::GetString(properties, kPropertyUnlockRequired,
840 &sim_lock_status_.lock_type)) {
841 emit = true;
842 }
843 if (DBusProperties::GetUint32(properties, kPropertyUnlockRetries,
844 &sim_lock_status_.retries_left)) {
845 emit = true;
846 }
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400847 }
848 if (emit) {
849 cellular()->adaptor()->EmitKeyValueStoreChanged(
850 flimflam::kSIMLockStatusProperty, SimLockStatusToProperty(NULL));
851 }
Darin Petkov63138a92012-02-06 14:09:15 +0100852 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100853}
854
Eric Shienbrood9a245532012-03-07 14:20:39 -0500855void CellularCapabilityGSM::OnNetworkModeSignal(uint32 /*mode*/) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100856 // TODO(petkov): Implement this.
857 NOTIMPLEMENTED();
858}
859
Eric Shienbrood9a245532012-03-07 14:20:39 -0500860void CellularCapabilityGSM::OnRegistrationInfoSignal(
861 uint32 status, const string &operator_code, const string &operator_name) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700862 SLOG(Cellular, 2) << __func__ << ": regstate=" << status
863 << ", opercode=" << operator_code
864 << ", opername=" << operator_name;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500865 registration_state_ = status;
866 serving_operator_.SetCode(operator_code);
867 serving_operator_.SetName(operator_name);
868 UpdateOperatorInfo();
869 cellular()->HandleNewRegistrationState();
Darin Petkov184c54e2011-11-15 12:44:39 +0100870}
871
Eric Shienbrood9a245532012-03-07 14:20:39 -0500872void CellularCapabilityGSM::OnSignalQualitySignal(uint32 quality) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100873 cellular()->HandleNewSignalQuality(quality);
874}
875
Eric Shienbrood9a245532012-03-07 14:20:39 -0500876void CellularCapabilityGSM::OnGetRegistrationInfoReply(
877 uint32 status, const string &operator_code, const string &operator_name,
878 const Error &error) {
879 if (error.IsSuccess())
880 OnRegistrationInfoSignal(status, operator_code, operator_name);
881}
882
883void CellularCapabilityGSM::OnGetSignalQualityReply(uint32 quality,
884 const Error &error) {
885 if (error.IsSuccess())
886 OnSignalQualitySignal(quality);
887}
888
889void CellularCapabilityGSM::OnGetIMEIReply(const ResultCallback &callback,
890 const string &imei,
891 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500892 if (error.IsSuccess()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700893 SLOG(Cellular, 2) << "IMEI: " << imei;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500894 imei_ = imei;
895 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700896 SLOG(Cellular, 2) << "GetIMEI failed - " << error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500897 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500898 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500899}
900
Eric Shienbrood9a245532012-03-07 14:20:39 -0500901void CellularCapabilityGSM::OnGetIMSIReply(const ResultCallback &callback,
902 const string &imsi,
903 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500904 if (error.IsSuccess()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700905 SLOG(Cellular, 2) << "IMSI: " << imsi;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500906 imsi_ = imsi;
907 SetHomeProvider();
Gary Morain82a31a02012-08-02 18:03:32 -0700908 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500909 } else {
Gary Morain82a31a02012-08-02 18:03:32 -0700910 if (get_imsi_retries_++ < kGetIMSIRetryLimit) {
911 SLOG(Cellular, 2) << "GetIMSI failed - " << error << ". Retrying";
912 base::Callback<void(void)> retry_get_imsi_cb =
913 Bind(&CellularCapabilityGSM::GetIMSI,
914 weak_ptr_factory_.GetWeakPtr(), callback);
915 cellular()->dispatcher()->PostDelayedTask(
916 retry_get_imsi_cb,
917 get_imsi_retry_delay_milliseconds_);
918 } else {
919 LOG(INFO) << "GetIMSI failed - " << error;
920 callback.Run(error);
921 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500922 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500923}
924
Eric Shienbrood9a245532012-03-07 14:20:39 -0500925void CellularCapabilityGSM::OnGetSPNReply(const ResultCallback &callback,
926 const string &spn,
927 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500928 if (error.IsSuccess()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700929 SLOG(Cellular, 2) << "SPN: " << spn;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500930 spn_ = spn;
931 SetHomeProvider();
932 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700933 SLOG(Cellular, 2) << "GetSPN failed - " << error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500934 }
Thieu Le923006b2012-04-05 16:32:58 -0700935 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500936}
937
Eric Shienbrood9a245532012-03-07 14:20:39 -0500938void CellularCapabilityGSM::OnGetMSISDNReply(const ResultCallback &callback,
939 const string &msisdn,
940 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500941 if (error.IsSuccess()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700942 SLOG(Cellular, 2) << "MSISDN: " << msisdn;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500943 mdn_ = msisdn;
944 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700945 SLOG(Cellular, 2) << "GetMSISDN failed - " << error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500946 }
Thieu Le923006b2012-04-05 16:32:58 -0700947 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500948}
949
Darin Petkovdaf43862011-10-27 11:37:28 +0200950} // namespace shill