blob: e76438c35cf9b8c6458a13a8cad3dfe00305b25e [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>
Eric Shienbrood3e20a232012-02-16 11:35:56 -050011#include <base/stl_util.h>
Darin Petkov1272a432011-11-10 15:53:37 +010012#include <base/string_number_conversions.h>
Darin Petkovac635a82012-01-10 16:51:58 +010013#include <base/stringprintf.h>
Darin Petkov20c13ec2011-11-09 15:07:15 +010014#include <chromeos/dbus/service_constants.h>
15#include <mm/mm-modem.h>
Darin Petkov1272a432011-11-10 15:53:37 +010016#include <mobile_provider.h>
Darin Petkovdaf43862011-10-27 11:37:28 +020017
Darin Petkov3cfbf212011-11-21 16:02:09 +010018#include "shill/adaptor_interfaces.h"
Darin Petkovae0c64e2011-11-15 15:50:27 +010019#include "shill/cellular_service.h"
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050020#include "shill/error.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070021#include "shill/logging.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"
24
Eric Shienbrood3e20a232012-02-16 11:35:56 -050025using base::Bind;
Darin Petkovb05315f2011-11-07 10:14:25 +010026using std::string;
Jason Glasgow4c0724a2012-04-17 15:47:40 -040027using std::vector;
Darin Petkovb05315f2011-11-07 10:14:25 +010028
Darin Petkovdaf43862011-10-27 11:37:28 +020029namespace shill {
30
Darin Petkovac635a82012-01-10 16:51:58 +010031// static
32unsigned int CellularCapabilityGSM::friendly_service_name_id_ = 0;
33
Darin Petkov1272a432011-11-10 15:53:37 +010034const char CellularCapabilityGSM::kNetworkPropertyAccessTechnology[] =
35 "access-tech";
36const char CellularCapabilityGSM::kNetworkPropertyID[] = "operator-num";
37const char CellularCapabilityGSM::kNetworkPropertyLongName[] = "operator-long";
38const char CellularCapabilityGSM::kNetworkPropertyShortName[] =
39 "operator-short";
40const char CellularCapabilityGSM::kNetworkPropertyStatus[] = "status";
Darin Petkovae0c64e2011-11-15 15:50:27 +010041const char CellularCapabilityGSM::kPhoneNumber[] = "*99#";
42const char CellularCapabilityGSM::kPropertyAccessTechnology[] =
43 "AccessTechnology";
Darin Petkov63138a92012-02-06 14:09:15 +010044const char CellularCapabilityGSM::kPropertyEnabledFacilityLocks[] =
45 "EnabledFacilityLocks";
Darin Petkov721ac932011-11-16 15:43:09 +010046const char CellularCapabilityGSM::kPropertyUnlockRequired[] = "UnlockRequired";
47const char CellularCapabilityGSM::kPropertyUnlockRetries[] = "UnlockRetries";
Darin Petkov1272a432011-11-10 15:53:37 +010048
Ben Chanc89b9282012-12-12 14:00:29 -080049const int CellularCapabilityGSM::kGetIMSIRetryLimit = 40;
50const int64 CellularCapabilityGSM::kGetIMSIRetryDelayMilliseconds = 500;
Gary Morain82a31a02012-08-02 18:03:32 -070051
52
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050053CellularCapabilityGSM::CellularCapabilityGSM(Cellular *cellular,
54 ProxyFactory *proxy_factory)
Jason Glasgow82f9ab32012-04-04 14:27:19 -040055 : CellularCapabilityClassic(cellular, proxy_factory),
Eric Shienbrood3e20a232012-02-16 11:35:56 -050056 weak_ptr_factory_(this),
Darin Petkov184c54e2011-11-15 12:44:39 +010057 registration_state_(MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN),
Darin Petkovae0c64e2011-11-15 15:50:27 +010058 access_technology_(MM_MODEM_GSM_ACCESS_TECH_UNKNOWN),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +010059 home_provider_(NULL),
Darin Petkovf508c822012-09-21 13:43:17 +020060 provider_requires_roaming_(false),
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),
Ben Chanbd3aee82012-10-16 23:52:04 -070064 scan_interval_(0),
65 sim_present_(false) {
Ben Chanfad4a0b2012-04-18 15:49:59 -070066 SLOG(Cellular, 2) << "Cellular capability constructed: GSM";
Darin Petkov1272a432011-11-10 15:53:37 +010067 PropertyStore *store = cellular->mutable_store();
Darin Petkov184c54e2011-11-15 12:44:39 +010068 store->RegisterConstString(flimflam::kSelectedNetworkProperty,
69 &selected_network_);
Darin Petkov1272a432011-11-10 15:53:37 +010070 store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
71 &found_networks_);
Darin Petkovf508c822012-09-21 13:43:17 +020072 store->RegisterConstBool(shill::kProviderRequiresRoamingProperty,
73 &provider_requires_roaming_);
Darin Petkov1272a432011-11-10 15:53:37 +010074 store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
75 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
Ben Chanbd3aee82012-10-16 23:52:04 -070076 store->RegisterConstBool(shill::kSIMPresentProperty, &sim_present_);
Darin Petkov63138a92012-02-06 14:09:15 +010077 HelpRegisterDerivedKeyValueStore(
78 flimflam::kSIMLockStatusProperty,
79 &CellularCapabilityGSM::SimLockStatusToProperty,
80 NULL);
Darin Petkov3cfbf212011-11-21 16:02:09 +010081 store->RegisterConstStringmaps(flimflam::kCellularApnListProperty,
82 &apn_list_);
Darin Petkov0d06f7d2012-02-03 13:08:19 +010083 scanning_supported_ = true;
Ben Chan3ecdf822012-08-06 12:29:23 -070084
85 // TODO(benchan): This is a hack to initialize the GSM card proxy for GetIMSI
86 // before InitProxies is called. There are side-effects of calling InitProxies
87 // before the device is enabled. It's better to refactor InitProxies such that
88 // proxies can be created when the cellular device/capability is constructed,
89 // but callbacks for DBus signal updates are not set up until the device is
90 // enabled.
91 card_proxy_.reset(
92 proxy_factory->CreateModemGSMCardProxy(cellular->dbus_path(),
93 cellular->dbus_owner()));
94 // TODO(benchan): To allow unit testing using a mock proxy without further
95 // complicating the code, the test proxy factory is set up to return a NULL
96 // pointer when CellularCapabilityGSM is constructed. Refactor the code to
97 // avoid this hack.
98 if (card_proxy_.get())
99 InitProperties();
Darin Petkov1272a432011-11-10 15:53:37 +0100100}
Darin Petkovdaf43862011-10-27 11:37:28 +0200101
Darin Petkov63138a92012-02-06 14:09:15 +0100102KeyValueStore CellularCapabilityGSM::SimLockStatusToProperty(Error */*error*/) {
103 KeyValueStore status;
104 status.SetBool(flimflam::kSIMLockEnabledProperty, sim_lock_status_.enabled);
105 status.SetString(flimflam::kSIMLockTypeProperty, sim_lock_status_.lock_type);
106 status.SetUint(flimflam::kSIMLockRetriesLeftProperty,
107 sim_lock_status_.retries_left);
108 return status;
Darin Petkov721ac932011-11-16 15:43:09 +0100109}
110
Darin Petkov63138a92012-02-06 14:09:15 +0100111void CellularCapabilityGSM::HelpRegisterDerivedKeyValueStore(
Darin Petkov721ac932011-11-16 15:43:09 +0100112 const string &name,
Darin Petkov63138a92012-02-06 14:09:15 +0100113 KeyValueStore(CellularCapabilityGSM::*get)(Error *error),
114 void(CellularCapabilityGSM::*set)(
115 const KeyValueStore &value, Error *error)) {
116 cellular()->mutable_store()->RegisterDerivedKeyValueStore(
Darin Petkov721ac932011-11-16 15:43:09 +0100117 name,
Darin Petkov63138a92012-02-06 14:09:15 +0100118 KeyValueStoreAccessor(
119 new CustomAccessor<CellularCapabilityGSM, KeyValueStore>(
Darin Petkov721ac932011-11-16 15:43:09 +0100120 this, get, set)));
121}
122
Eric Shienbrood9a245532012-03-07 14:20:39 -0500123void CellularCapabilityGSM::InitProxies() {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400124 CellularCapabilityClassic::InitProxies();
Ben Chan3ecdf822012-08-06 12:29:23 -0700125 // TODO(benchan): Remove this check after refactoring the proxy
126 // initialization.
127 if (!card_proxy_.get()) {
128 card_proxy_.reset(
129 proxy_factory()->CreateModemGSMCardProxy(cellular()->dbus_path(),
130 cellular()->dbus_owner()));
131 }
Darin Petkov184c54e2011-11-15 12:44:39 +0100132 network_proxy_.reset(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500133 proxy_factory()->CreateModemGSMNetworkProxy(cellular()->dbus_path(),
Darin Petkovdaf43862011-10-27 11:37:28 +0200134 cellular()->dbus_owner()));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500135 network_proxy_->set_signal_quality_callback(
136 Bind(&CellularCapabilityGSM::OnSignalQualitySignal,
137 weak_ptr_factory_.GetWeakPtr()));
138 network_proxy_->set_network_mode_callback(
139 Bind(&CellularCapabilityGSM::OnNetworkModeSignal,
140 weak_ptr_factory_.GetWeakPtr()));
141 network_proxy_->set_registration_info_callback(
142 Bind(&CellularCapabilityGSM::OnRegistrationInfoSignal,
143 weak_ptr_factory_.GetWeakPtr()));
Darin Petkovdaf43862011-10-27 11:37:28 +0200144}
145
Ben Chan3ecdf822012-08-06 12:29:23 -0700146void CellularCapabilityGSM::InitProperties() {
147 CellularTaskList *tasks = new CellularTaskList();
148 ResultCallback cb_ignore_error =
149 Bind(&CellularCapabilityGSM::StepCompletedCallback,
150 weak_ptr_factory_.GetWeakPtr(), ResultCallback(), true, tasks);
Ben Chanbd3aee82012-10-16 23:52:04 -0700151 // Chrome checks if a SIM is present before allowing the modem to be enabled,
152 // so shill needs to obtain IMSI, as an indicator of SIM presence, even
153 // before the device is enabled.
Ben Chan3ecdf822012-08-06 12:29:23 -0700154 tasks->push_back(Bind(&CellularCapabilityGSM::GetIMSI,
155 weak_ptr_factory_.GetWeakPtr(), cb_ignore_error));
156 RunNextStep(tasks);
157}
158
Eric Shienbrood9a245532012-03-07 14:20:39 -0500159void CellularCapabilityGSM::StartModem(Error *error,
160 const ResultCallback &callback) {
161 InitProxies();
162
163 CellularTaskList *tasks = new CellularTaskList();
164 ResultCallback cb =
165 Bind(&CellularCapabilityGSM::StepCompletedCallback,
Thieu Le923006b2012-04-05 16:32:58 -0700166 weak_ptr_factory_.GetWeakPtr(), callback, false, tasks);
167 ResultCallback cb_ignore_error =
168 Bind(&CellularCapabilityGSM::StepCompletedCallback,
169 weak_ptr_factory_.GetWeakPtr(), callback, true, tasks);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400170 if (!cellular()->IsUnderlyingDeviceEnabled())
171 tasks->push_back(Bind(&CellularCapabilityGSM::EnableModem,
172 weak_ptr_factory_.GetWeakPtr(), cb));
173 // If we're within range of the home network, the modem will try to
174 // register once it's enabled, or may be already registered if we
175 // started out enabled.
176 if (!IsUnderlyingDeviceRegistered() && !selected_network_.empty())
177 tasks->push_back(Bind(&CellularCapabilityGSM::Register,
178 weak_ptr_factory_.GetWeakPtr(), cb));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500179 tasks->push_back(Bind(&CellularCapabilityGSM::GetIMEI,
180 weak_ptr_factory_.GetWeakPtr(), cb));
Gary Morain82a31a02012-08-02 18:03:32 -0700181 get_imsi_retries_ = 0;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500182 tasks->push_back(Bind(&CellularCapabilityGSM::GetIMSI,
183 weak_ptr_factory_.GetWeakPtr(), cb));
184 tasks->push_back(Bind(&CellularCapabilityGSM::GetSPN,
Thieu Le923006b2012-04-05 16:32:58 -0700185 weak_ptr_factory_.GetWeakPtr(), cb_ignore_error));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500186 tasks->push_back(Bind(&CellularCapabilityGSM::GetMSISDN,
Thieu Le923006b2012-04-05 16:32:58 -0700187 weak_ptr_factory_.GetWeakPtr(), cb_ignore_error));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500188 tasks->push_back(Bind(&CellularCapabilityGSM::GetProperties,
189 weak_ptr_factory_.GetWeakPtr(), cb));
190 tasks->push_back(Bind(&CellularCapabilityGSM::GetModemInfo,
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400191 weak_ptr_factory_.GetWeakPtr(), cb_ignore_error));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500192 tasks->push_back(Bind(&CellularCapabilityGSM::FinishEnable,
193 weak_ptr_factory_.GetWeakPtr(), cb));
194
195 RunNextStep(tasks);
196}
197
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400198bool CellularCapabilityGSM::IsUnderlyingDeviceRegistered() const {
199 switch (cellular()->modem_state()) {
200 case Cellular::kModemStateUnknown:
201 case Cellular::kModemStateDisabled:
202 case Cellular::kModemStateInitializing:
203 case Cellular::kModemStateLocked:
204 case Cellular::kModemStateDisabling:
205 case Cellular::kModemStateEnabling:
206 case Cellular::kModemStateEnabled:
207 return false;
208 case Cellular::kModemStateSearching:
209 case Cellular::kModemStateRegistered:
210 case Cellular::kModemStateDisconnecting:
211 case Cellular::kModemStateConnecting:
212 case Cellular::kModemStateConnected:
213 return true;
214 }
215 return false;
216}
217
Eric Shienbrood9a245532012-03-07 14:20:39 -0500218void CellularCapabilityGSM::ReleaseProxies() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700219 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400220 CellularCapabilityClassic::ReleaseProxies();
Darin Petkov721ac932011-11-16 15:43:09 +0100221 card_proxy_.reset();
222 network_proxy_.reset();
223}
224
Darin Petkov5f316f62011-11-18 12:10:26 +0100225void CellularCapabilityGSM::OnServiceCreated() {
Darin Petkov31332412012-01-28 01:50:02 +0100226 // If IMSI is available, base the service's storage identifier on it.
227 if (!imsi_.empty()) {
228 cellular()->service()->SetStorageIdentifier(
Darin Petkovdd3e8662012-02-03 13:16:20 +0100229 string(flimflam::kTypeCellular) + "_" +
230 cellular()->address() + "_" + imsi_);
Darin Petkov31332412012-01-28 01:50:02 +0100231 }
Darin Petkovb9c99332012-01-12 13:13:00 +0100232 cellular()->service()->SetActivationState(
Darin Petkov5f316f62011-11-18 12:10:26 +0100233 flimflam::kActivationStateActivated);
234 UpdateServingOperator();
235}
236
Darin Petkovae0c64e2011-11-15 15:50:27 +0100237void CellularCapabilityGSM::UpdateStatus(const DBusPropertiesMap &properties) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400238 if (ContainsKey(properties, kModemPropertyIMSI)) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100239 SetHomeProvider();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100240 }
241}
242
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400243// Create the list of APNs to try, in the following order:
244// - last APN that resulted in a successful connection attempt on the
245// current network (if any)
246// - the APN, if any, that was set by the user
247// - the list of APNs found in the mobile broadband provider DB for the
248// home provider associated with the current SIM
249// - as a last resort, attempt to connect with no APN
250void CellularCapabilityGSM::SetupApnTryList() {
251 apn_try_list_.clear();
252
253 DCHECK(cellular()->service().get());
254 const Stringmap *apn_info = cellular()->service()->GetLastGoodApn();
255 if (apn_info)
256 apn_try_list_.push_back(*apn_info);
257
258 apn_info = cellular()->service()->GetUserSpecifiedApn();
259 if (apn_info)
260 apn_try_list_.push_back(*apn_info);
261
262 apn_try_list_.insert(apn_try_list_.end(), apn_list_.begin(), apn_list_.end());
263}
264
Darin Petkovae0c64e2011-11-15 15:50:27 +0100265void CellularCapabilityGSM::SetupConnectProperties(
266 DBusPropertiesMap *properties) {
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400267 SetupApnTryList();
268 FillConnectPropertyMap(properties);
269}
270
271void CellularCapabilityGSM::FillConnectPropertyMap(
272 DBusPropertiesMap *properties) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500273 (*properties)[kConnectPropertyPhoneNumber].writer().append_string(
Darin Petkovae0c64e2011-11-15 15:50:27 +0100274 kPhoneNumber);
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400275
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400276 if (!AllowRoaming())
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400277 (*properties)[kConnectPropertyHomeOnly].writer().append_bool(true);
278
279 if (!apn_try_list_.empty()) {
280 // Leave the APN at the front of the list, so that it can be recorded
281 // if the connect attempt succeeds.
282 Stringmap apn_info = apn_try_list_.front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700283 SLOG(Cellular, 2) << __func__ << ": Using APN "
284 << apn_info[flimflam::kApnProperty];
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400285 (*properties)[kConnectPropertyApn].writer().append_string(
286 apn_info[flimflam::kApnProperty].c_str());
287 if (ContainsKey(apn_info, flimflam::kApnUsernameProperty))
288 (*properties)[kConnectPropertyApnUsername].writer().append_string(
289 apn_info[flimflam::kApnUsernameProperty].c_str());
290 if (ContainsKey(apn_info, flimflam::kApnPasswordProperty))
291 (*properties)[kConnectPropertyApnPassword].writer().append_string(
292 apn_info[flimflam::kApnPasswordProperty].c_str());
293 }
294}
295
Nathan Williamsb54974f2012-04-19 11:16:30 -0400296void CellularCapabilityGSM::Connect(const DBusPropertiesMap &properties,
297 Error *error,
298 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700299 SLOG(Cellular, 2) << __func__;
Nathan Williamsb54974f2012-04-19 11:16:30 -0400300 ResultCallback cb = Bind(&CellularCapabilityGSM::OnConnectReply,
301 weak_ptr_factory_.GetWeakPtr(),
302 callback);
303 simple_proxy_->Connect(properties, error, cb, kTimeoutConnect);
304}
305
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400306void CellularCapabilityGSM::OnConnectReply(const ResultCallback &callback,
307 const Error &error) {
Thieu Leb5954a22012-05-18 10:37:34 -0700308 CellularServiceRefPtr service = cellular()->service();
309 if (!service) {
310 // The service could have been deleted before our Connect() request
311 // completes if the modem was enabled and then quickly disabled.
312 apn_try_list_.clear();
313 } else if (error.IsFailure()) {
314 service->ClearLastGoodApn();
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400315 // The APN that was just tried (and failed) is still at the
316 // front of the list, about to be removed. If the list is empty
317 // after that, try one last time without an APN. This may succeed
318 // with some modems in some cases.
319 if (error.type() == Error::kInvalidApn && !apn_try_list_.empty()) {
320 apn_try_list_.pop_front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700321 SLOG(Cellular, 2) << "Connect failed with invalid APN, "
322 << apn_try_list_.size() << " remaining APNs to try";
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400323 DBusPropertiesMap props;
324 FillConnectPropertyMap(&props);
325 Error error;
326 Connect(props, &error, callback);
327 return;
328 }
329 } else if (!apn_try_list_.empty()) {
Thieu Leb5954a22012-05-18 10:37:34 -0700330 service->SetLastGoodApn(apn_try_list_.front());
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400331 apn_try_list_.clear();
332 }
Nathan Williamsb54974f2012-04-19 11:16:30 -0400333 if (!callback.is_null())
334 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400335}
336
337bool CellularCapabilityGSM::AllowRoaming() {
Darin Petkovf508c822012-09-21 13:43:17 +0200338 return provider_requires_roaming_ || allow_roaming_property();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100339}
340
Eric Shienbrood9a245532012-03-07 14:20:39 -0500341// always called from an async context
342void CellularCapabilityGSM::GetIMEI(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;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500346 if (imei_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500347 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetIMEIReply,
348 weak_ptr_factory_.GetWeakPtr(), callback);
349 card_proxy_->GetIMEI(&error, cb, kTimeoutDefault);
350 if (error.IsFailure())
351 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500352 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700353 SLOG(Cellular, 2) << "Already have IMEI " << imei_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500354 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100355 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500356}
357
Eric Shienbrood9a245532012-03-07 14:20:39 -0500358// always called from an async context
359void CellularCapabilityGSM::GetIMSI(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700360 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500361 CHECK(!callback.is_null());
362 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500363 if (imsi_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500364 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetIMSIReply,
365 weak_ptr_factory_.GetWeakPtr(),
366 callback);
367 card_proxy_->GetIMSI(&error, cb, kTimeoutDefault);
368 if (error.IsFailure())
369 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500370 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700371 SLOG(Cellular, 2) << "Already have IMSI " << imsi_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500372 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100373 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500374}
375
Eric Shienbrood9a245532012-03-07 14:20:39 -0500376// always called from an async context
377void CellularCapabilityGSM::GetSPN(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700378 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500379 CHECK(!callback.is_null());
380 Error error;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100381 if (spn_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500382 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetSPNReply,
383 weak_ptr_factory_.GetWeakPtr(),
384 callback);
385 card_proxy_->GetSPN(&error, cb, kTimeoutDefault);
386 if (error.IsFailure())
387 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500388 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700389 SLOG(Cellular, 2) << "Already have SPN " << spn_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500390 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100391 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500392}
393
Eric Shienbrood9a245532012-03-07 14:20:39 -0500394// always called from an async context
395void CellularCapabilityGSM::GetMSISDN(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700396 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500397 CHECK(!callback.is_null());
398 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500399 if (mdn_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500400 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetMSISDNReply,
401 weak_ptr_factory_.GetWeakPtr(),
402 callback);
403 card_proxy_->GetMSISDN(&error, cb, kTimeoutDefault);
404 if (error.IsFailure())
405 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500406 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700407 SLOG(Cellular, 2) << "Already have MSISDN " << mdn_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500408 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100409 }
410}
411
Darin Petkov3e509242011-11-10 14:46:44 +0100412void CellularCapabilityGSM::GetSignalQuality() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700413 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500414 SignalQualityCallback callback =
415 Bind(&CellularCapabilityGSM::OnGetSignalQualityReply,
416 weak_ptr_factory_.GetWeakPtr());
417 network_proxy_->GetSignalQuality(NULL, callback, kTimeoutDefault);
Darin Petkov3e509242011-11-10 14:46:44 +0100418}
419
Eric Shienbrood9a245532012-03-07 14:20:39 -0500420void CellularCapabilityGSM::GetRegistrationState() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700421 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500422 RegistrationInfoCallback callback =
423 Bind(&CellularCapabilityGSM::OnGetRegistrationInfoReply,
424 weak_ptr_factory_.GetWeakPtr());
425 network_proxy_->GetRegistrationInfo(NULL, callback, kTimeoutDefault);
Darin Petkov184c54e2011-11-15 12:44:39 +0100426}
427
Eric Shienbrood9a245532012-03-07 14:20:39 -0500428void CellularCapabilityGSM::GetProperties(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700429 SLOG(Cellular, 2) << __func__;
Darin Petkov63138a92012-02-06 14:09:15 +0100430
Darin Petkov184c54e2011-11-15 12:44:39 +0100431 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
432 uint32 tech = network_proxy_->AccessTechnology();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100433 SetAccessTechnology(tech);
Ben Chanfad4a0b2012-04-18 15:49:59 -0700434 SLOG(Cellular, 2) << "GSM AccessTechnology: " << tech;
Darin Petkov63138a92012-02-06 14:09:15 +0100435
436 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
437 uint32 locks = card_proxy_->EnabledFacilityLocks();
438 sim_lock_status_.enabled = locks & MM_MODEM_GSM_FACILITY_SIM;
Ben Chanfad4a0b2012-04-18 15:49:59 -0700439 SLOG(Cellular, 2) << "GSM EnabledFacilityLocks: " << locks;
Darin Petkov63138a92012-02-06 14:09:15 +0100440
Eric Shienbrood9a245532012-03-07 14:20:39 -0500441 callback.Run(Error());
Darin Petkov184c54e2011-11-15 12:44:39 +0100442}
443
Darin Petkovac635a82012-01-10 16:51:58 +0100444string CellularCapabilityGSM::CreateFriendlyServiceName() {
Darin Petkova4ca3c32012-08-17 16:05:24 +0200445 SLOG(Cellular, 2) << __func__ << ": " << GetRoamingStateString();
446 string name = serving_operator_.GetName();
447 string home_provider_name = cellular()->home_provider().GetName();
448 if (!name.empty()) {
449 // If roaming, try to show "<home-provider> | <serving-operator>", per 3GPP
450 // rules (TS 31.102 and annex A of 122.101).
451 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING &&
452 !home_provider_name.empty()) {
453 return home_provider_name + " | " + name;
454 }
455 return name;
Darin Petkovac635a82012-01-10 16:51:58 +0100456 }
Darin Petkova4ca3c32012-08-17 16:05:24 +0200457 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME &&
458 !home_provider_name.empty()) {
459 return home_provider_name;
Darin Petkovac635a82012-01-10 16:51:58 +0100460 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500461 if (!carrier_.empty()) {
462 return carrier_;
Darin Petkovac635a82012-01-10 16:51:58 +0100463 }
Darin Petkova4ca3c32012-08-17 16:05:24 +0200464 string serving_operator_code = serving_operator_.GetCode();
465 if (!serving_operator_code.empty()) {
466 return "cellular_" + serving_operator_code;
Darin Petkovac635a82012-01-10 16:51:58 +0100467 }
468 return base::StringPrintf("GSMNetwork%u", friendly_service_name_id_++);
469}
470
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100471void CellularCapabilityGSM::SetHomeProvider() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700472 SLOG(Cellular, 2) << __func__ << "(IMSI: " << imsi_
473 << " SPN: " << spn_ << ")";
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100474 // TODO(petkov): The test for NULL provider_db should be done by
475 // mobile_provider_lookup_best_match.
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500476 if (imsi_.empty() || !cellular()->provider_db()) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100477 return;
478 }
479 mobile_provider *provider =
480 mobile_provider_lookup_best_match(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500481 cellular()->provider_db(), spn_.c_str(), imsi_.c_str());
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100482 if (!provider) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700483 SLOG(Cellular, 2) << "GSM provider not found.";
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100484 return;
485 }
486 home_provider_ = provider;
Darin Petkovf508c822012-09-21 13:43:17 +0200487 provider_requires_roaming_ = home_provider_->requires_roaming;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100488 Cellular::Operator oper;
Darin Petkovb4fccd22012-08-10 11:59:26 +0200489 if (provider->networks && provider->networks[0]) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100490 oper.SetCode(provider->networks[0]);
491 }
492 if (provider->country) {
493 oper.SetCountry(provider->country);
494 }
495 if (spn_.empty()) {
496 const char *name = mobile_provider_get_name(provider);
497 if (name) {
498 oper.SetName(name);
499 }
500 } else {
501 oper.SetName(spn_);
502 }
503 cellular()->set_home_provider(oper);
Darin Petkova4ca3c32012-08-17 16:05:24 +0200504 SLOG(Cellular, 2) << "Home provider: " << oper.GetCode() << ", "
Darin Petkovf508c822012-09-21 13:43:17 +0200505 << oper.GetName() << ", " << oper.GetCountry()
506 << (provider_requires_roaming_ ? ", roaming required" : "");
Darin Petkov3cfbf212011-11-21 16:02:09 +0100507 InitAPNList();
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100508}
509
Darin Petkovae0c64e2011-11-15 15:50:27 +0100510void CellularCapabilityGSM::UpdateOperatorInfo() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700511 SLOG(Cellular, 2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100512 const string &network_id = serving_operator_.GetCode();
513 if (!network_id.empty()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700514 SLOG(Cellular, 2) << "Looking up network id: " << network_id;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100515 mobile_provider *provider =
516 mobile_provider_lookup_by_network(cellular()->provider_db(),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100517 network_id.c_str());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100518 if (provider) {
Darin Petkova4ca3c32012-08-17 16:05:24 +0200519 if (serving_operator_.GetName().empty()) {
520 const char *provider_name = mobile_provider_get_name(provider);
521 if (provider_name && *provider_name) {
522 serving_operator_.SetName(provider_name);
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100523 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100524 }
Darin Petkova4ca3c32012-08-17 16:05:24 +0200525 if (provider->country && *provider->country) {
526 serving_operator_.SetCountry(provider->country);
527 }
528 SLOG(Cellular, 2) << "Operator name: " << serving_operator_.GetName()
529 << ", country: " << serving_operator_.GetCountry();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100530 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700531 SLOG(Cellular, 2) << "GSM provider not found.";
Darin Petkovae0c64e2011-11-15 15:50:27 +0100532 }
533 }
534 UpdateServingOperator();
535}
536
537void CellularCapabilityGSM::UpdateServingOperator() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700538 SLOG(Cellular, 2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100539 if (cellular()->service().get()) {
Darin Petkov9cb02682012-01-28 00:17:38 +0100540 cellular()->service()->SetServingOperator(serving_operator_);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100541 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100542}
543
Darin Petkov3cfbf212011-11-21 16:02:09 +0100544void CellularCapabilityGSM::InitAPNList() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700545 SLOG(Cellular, 2) << __func__;
Darin Petkov3cfbf212011-11-21 16:02:09 +0100546 if (!home_provider_) {
547 return;
548 }
549 apn_list_.clear();
550 for (int i = 0; i < home_provider_->num_apns; ++i) {
551 Stringmap props;
552 mobile_apn *apn = home_provider_->apns[i];
553 if (apn->value) {
554 props[flimflam::kApnProperty] = apn->value;
555 }
556 if (apn->username) {
557 props[flimflam::kApnUsernameProperty] = apn->username;
558 }
559 if (apn->password) {
560 props[flimflam::kApnPasswordProperty] = apn->password;
561 }
562 // Find the first localized and non-localized name, if any.
563 const localized_name *lname = NULL;
564 const localized_name *name = NULL;
565 for (int j = 0; j < apn->num_names; ++j) {
566 if (apn->names[j]->lang) {
567 if (!lname) {
568 lname = apn->names[j];
569 }
570 } else if (!name) {
571 name = apn->names[j];
572 }
573 }
574 if (name) {
575 props[flimflam::kApnNameProperty] = name->name;
576 }
577 if (lname) {
578 props[flimflam::kApnLocalizedNameProperty] = lname->name;
579 props[flimflam::kApnLanguageProperty] = lname->lang;
580 }
581 apn_list_.push_back(props);
582 }
Darin Petkovdb6083f2012-08-16 12:50:23 +0200583 if (cellular()->adaptor()) {
584 cellular()->adaptor()->EmitStringmapsChanged(
585 flimflam::kCellularApnListProperty, apn_list_);
586 } else {
587 LOG(ERROR) << "Null RPC service adaptor.";
588 }
Darin Petkov3cfbf212011-11-21 16:02:09 +0100589}
590
Eric Shienbrood9a245532012-03-07 14:20:39 -0500591// always called from an async context
592void CellularCapabilityGSM::Register(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700593 SLOG(Cellular, 2) << __func__ << " \"" << selected_network_ << "\"";
Eric Shienbrood9a245532012-03-07 14:20:39 -0500594 CHECK(!callback.is_null());
595 Error error;
596 ResultCallback cb = Bind(&CellularCapabilityGSM::OnRegisterReply,
597 weak_ptr_factory_.GetWeakPtr(), callback);
598 network_proxy_->Register(selected_network_, &error, cb, kTimeoutRegister);
599 if (error.IsFailure())
600 callback.Run(error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100601}
602
603void CellularCapabilityGSM::RegisterOnNetwork(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500604 const string &network_id,
605 Error *error,
606 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700607 SLOG(Cellular, 2) << __func__ << "(" << network_id << ")";
Eric Shienbrood9a245532012-03-07 14:20:39 -0500608 CHECK(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500609 desired_network_ = network_id;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500610 ResultCallback cb = Bind(&CellularCapabilityGSM::OnRegisterReply,
611 weak_ptr_factory_.GetWeakPtr(), callback);
612 network_proxy_->Register(network_id, error, cb, kTimeoutRegister);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500613}
614
Eric Shienbrood9a245532012-03-07 14:20:39 -0500615void CellularCapabilityGSM::OnRegisterReply(const ResultCallback &callback,
616 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700617 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500618
619 if (error.IsSuccess()) {
620 selected_network_ = desired_network_;
621 desired_network_.clear();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500622 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500623 return;
624 }
625 // If registration on the desired network failed,
626 // try to register on the home network.
627 if (!desired_network_.empty()) {
628 desired_network_.clear();
629 selected_network_.clear();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500630 LOG(INFO) << "Couldn't register on selected network, trying home network";
631 Register(callback);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500632 return;
633 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500634 callback.Run(error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100635}
636
Darin Petkovb72cf402011-11-22 14:51:39 +0100637bool CellularCapabilityGSM::IsRegistered() {
638 return (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
639 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING);
640}
641
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400642void CellularCapabilityGSM::SetUnregistered(bool searching) {
643 // If we're already in some non-registered state, don't override that
644 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
645 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING) {
646 registration_state_ =
647 (searching ? MM_MODEM_GSM_NETWORK_REG_STATUS_SEARCHING :
648 MM_MODEM_GSM_NETWORK_REG_STATUS_IDLE);
649 }
650}
651
Darin Petkovb05315f2011-11-07 10:14:25 +0100652void CellularCapabilityGSM::RequirePIN(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500653 const std::string &pin, bool require,
654 Error *error, const ResultCallback &callback) {
655 CHECK(error);
656 card_proxy_->EnablePIN(pin, require, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100657}
658
Darin Petkove5bc2cb2011-12-07 14:47:32 +0100659void CellularCapabilityGSM::EnterPIN(const string &pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500660 Error *error,
661 const ResultCallback &callback) {
662 CHECK(error);
663 card_proxy_->SendPIN(pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100664}
665
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100666void CellularCapabilityGSM::UnblockPIN(const string &unblock_code,
667 const string &pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500668 Error *error,
669 const ResultCallback &callback) {
670 CHECK(error);
671 card_proxy_->SendPUK(unblock_code, pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100672}
673
674void CellularCapabilityGSM::ChangePIN(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500675 const string &old_pin, const string &new_pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500676 Error *error, const ResultCallback &callback) {
677 CHECK(error);
678 card_proxy_->ChangePIN(old_pin, new_pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100679}
680
Eric Shienbrood9a245532012-03-07 14:20:39 -0500681void CellularCapabilityGSM::Scan(Error *error, const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700682 SLOG(Cellular, 2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500683 CHECK(error);
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400684 if (scanning_) {
685 Error::PopulateAndLog(error, Error::kInProgress, "Already scanning");
686 return;
687 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500688 ScanResultsCallback cb = Bind(&CellularCapabilityGSM::OnScanReply,
689 weak_ptr_factory_.GetWeakPtr(), callback);
690 network_proxy_->Scan(error, cb, kTimeoutScan);
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400691 if (!error->IsFailure()) {
692 scanning_ = true;
693 cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty,
694 scanning_);
695 }
Darin Petkov1272a432011-11-10 15:53:37 +0100696}
697
Eric Shienbrood9a245532012-03-07 14:20:39 -0500698void CellularCapabilityGSM::OnScanReply(const ResultCallback &callback,
699 const GSMScanResults &results,
700 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700701 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400702
703 // Error handling is weak. The current expectation is that on any
704 // error, found_networks_ should be cleared and a property change
705 // notification sent out.
706 //
707 // TODO(jglasgow): fix error handling
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400708 scanning_ = false;
709 cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty,
710 scanning_);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500711 found_networks_.clear();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400712 if (!error.IsFailure()) {
713 for (GSMScanResults::const_iterator it = results.begin();
714 it != results.end(); ++it) {
715 found_networks_.push_back(ParseScanResult(*it));
716 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500717 }
Darin Petkovb7828b02012-02-03 12:34:30 +0100718 cellular()->adaptor()->EmitStringmapsChanged(flimflam::kFoundNetworksProperty,
719 found_networks_);
Gary Moraina49062a2012-04-27 13:48:41 -0700720 if (!callback.is_null())
721 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500722}
723
724Stringmap CellularCapabilityGSM::ParseScanResult(const GSMScanResult &result) {
Darin Petkov1272a432011-11-10 15:53:37 +0100725 Stringmap parsed;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500726 for (GSMScanResult::const_iterator it = result.begin();
727 it != result.end(); ++it) {
Darin Petkov1272a432011-11-10 15:53:37 +0100728 // TODO(petkov): Define these in system_api/service_constants.h. The
729 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
730 static const char * const kStatusString[] = {
731 "unknown",
732 "available",
733 "current",
734 "forbidden",
735 };
736 static const char * const kTechnologyString[] = {
737 flimflam::kNetworkTechnologyGsm,
738 "GSM Compact",
739 flimflam::kNetworkTechnologyUmts,
740 flimflam::kNetworkTechnologyEdge,
741 "HSDPA",
742 "HSUPA",
743 flimflam::kNetworkTechnologyHspa,
744 };
Ben Chanfad4a0b2012-04-18 15:49:59 -0700745 SLOG(Cellular, 2) << "Network property: " << it->first << " = "
746 << it->second;
Darin Petkov1272a432011-11-10 15:53:37 +0100747 if (it->first == kNetworkPropertyStatus) {
748 int status = 0;
749 if (base::StringToInt(it->second, &status) &&
750 status >= 0 &&
751 status < static_cast<int>(arraysize(kStatusString))) {
752 parsed[flimflam::kStatusProperty] = kStatusString[status];
753 } else {
754 LOG(ERROR) << "Unexpected status value: " << it->second;
755 }
756 } else if (it->first == kNetworkPropertyID) {
757 parsed[flimflam::kNetworkIdProperty] = it->second;
758 } else if (it->first == kNetworkPropertyLongName) {
759 parsed[flimflam::kLongNameProperty] = it->second;
760 } else if (it->first == kNetworkPropertyShortName) {
761 parsed[flimflam::kShortNameProperty] = it->second;
762 } else if (it->first == kNetworkPropertyAccessTechnology) {
763 int tech = 0;
764 if (base::StringToInt(it->second, &tech) &&
765 tech >= 0 &&
766 tech < static_cast<int>(arraysize(kTechnologyString))) {
767 parsed[flimflam::kTechnologyProperty] = kTechnologyString[tech];
768 } else {
769 LOG(ERROR) << "Unexpected technology value: " << it->second;
770 }
771 } else {
772 LOG(WARNING) << "Unknown network property ignored: " << it->first;
773 }
774 }
775 // If the long name is not available but the network ID is, look up the long
776 // name in the mobile provider database.
777 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
778 parsed[flimflam::kLongNameProperty].empty()) &&
779 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
780 mobile_provider *provider =
781 mobile_provider_lookup_by_network(
782 cellular()->provider_db(),
783 parsed[flimflam::kNetworkIdProperty].c_str());
784 if (provider) {
785 const char *long_name = mobile_provider_get_name(provider);
786 if (long_name && *long_name) {
787 parsed[flimflam::kLongNameProperty] = long_name;
788 }
789 }
790 }
791 return parsed;
792}
793
Darin Petkovae0c64e2011-11-15 15:50:27 +0100794void CellularCapabilityGSM::SetAccessTechnology(uint32 access_technology) {
795 access_technology_ = access_technology;
796 if (cellular()->service().get()) {
Darin Petkovb72cf402011-11-22 14:51:39 +0100797 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100798 }
799}
800
Darin Petkov20c13ec2011-11-09 15:07:15 +0100801string CellularCapabilityGSM::GetNetworkTechnologyString() const {
Darin Petkovb72cf402011-11-22 14:51:39 +0100802 switch (access_technology_) {
803 case MM_MODEM_GSM_ACCESS_TECH_GSM:
804 case MM_MODEM_GSM_ACCESS_TECH_GSM_COMPACT:
805 return flimflam::kNetworkTechnologyGsm;
806 case MM_MODEM_GSM_ACCESS_TECH_GPRS:
807 return flimflam::kNetworkTechnologyGprs;
808 case MM_MODEM_GSM_ACCESS_TECH_EDGE:
809 return flimflam::kNetworkTechnologyEdge;
810 case MM_MODEM_GSM_ACCESS_TECH_UMTS:
811 return flimflam::kNetworkTechnologyUmts;
812 case MM_MODEM_GSM_ACCESS_TECH_HSDPA:
813 case MM_MODEM_GSM_ACCESS_TECH_HSUPA:
814 case MM_MODEM_GSM_ACCESS_TECH_HSPA:
815 return flimflam::kNetworkTechnologyHspa;
816 case MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS:
817 return flimflam::kNetworkTechnologyHspaPlus;
818 default:
819 break;
Darin Petkov20c13ec2011-11-09 15:07:15 +0100820 }
821 return "";
822}
823
824string CellularCapabilityGSM::GetRoamingStateString() const {
Darin Petkov184c54e2011-11-15 12:44:39 +0100825 switch (registration_state_) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100826 case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME:
827 return flimflam::kRoamingStateHome;
828 case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING:
829 return flimflam::kRoamingStateRoaming;
830 default:
831 break;
832 }
833 return flimflam::kRoamingStateUnknown;
834}
835
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400836void CellularCapabilityGSM::OnDBusPropertiesChanged(
837 const string &interface,
838 const DBusPropertiesMap &properties,
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400839 const vector<string> &invalidated_properties) {
840 CellularCapabilityClassic::OnDBusPropertiesChanged(interface,
841 properties,
842 invalidated_properties);
843 if (interface == MM_MODEM_GSM_NETWORK_INTERFACE) {
844 uint32 access_technology = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
845 if (DBusProperties::GetUint32(properties,
846 kPropertyAccessTechnology,
847 &access_technology)) {
848 SetAccessTechnology(access_technology);
849 }
Gary Morainbaeefdf2012-04-30 14:53:35 -0700850 } else {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400851 bool emit = false;
Gary Morainbaeefdf2012-04-30 14:53:35 -0700852 if (interface == MM_MODEM_GSM_CARD_INTERFACE) {
853 uint32 locks = 0;
854 if (DBusProperties::GetUint32(
855 properties, kPropertyEnabledFacilityLocks, &locks)) {
856 sim_lock_status_.enabled = locks & MM_MODEM_GSM_FACILITY_SIM;
857 emit = true;
858 }
859 } else if (interface == MM_MODEM_INTERFACE) {
860 if (DBusProperties::GetString(properties, kPropertyUnlockRequired,
861 &sim_lock_status_.lock_type)) {
862 emit = true;
863 }
864 if (DBusProperties::GetUint32(properties, kPropertyUnlockRetries,
865 &sim_lock_status_.retries_left)) {
866 emit = true;
867 }
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400868 }
869 if (emit) {
870 cellular()->adaptor()->EmitKeyValueStoreChanged(
871 flimflam::kSIMLockStatusProperty, SimLockStatusToProperty(NULL));
872 }
Darin Petkov63138a92012-02-06 14:09:15 +0100873 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100874}
875
Eric Shienbrood9a245532012-03-07 14:20:39 -0500876void CellularCapabilityGSM::OnNetworkModeSignal(uint32 /*mode*/) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100877 // TODO(petkov): Implement this.
878 NOTIMPLEMENTED();
879}
880
Eric Shienbrood9a245532012-03-07 14:20:39 -0500881void CellularCapabilityGSM::OnRegistrationInfoSignal(
882 uint32 status, const string &operator_code, const string &operator_name) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700883 SLOG(Cellular, 2) << __func__ << ": regstate=" << status
884 << ", opercode=" << operator_code
885 << ", opername=" << operator_name;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500886 registration_state_ = status;
887 serving_operator_.SetCode(operator_code);
888 serving_operator_.SetName(operator_name);
889 UpdateOperatorInfo();
890 cellular()->HandleNewRegistrationState();
Darin Petkov184c54e2011-11-15 12:44:39 +0100891}
892
Eric Shienbrood9a245532012-03-07 14:20:39 -0500893void CellularCapabilityGSM::OnSignalQualitySignal(uint32 quality) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100894 cellular()->HandleNewSignalQuality(quality);
895}
896
Eric Shienbrood9a245532012-03-07 14:20:39 -0500897void CellularCapabilityGSM::OnGetRegistrationInfoReply(
898 uint32 status, const string &operator_code, const string &operator_name,
899 const Error &error) {
900 if (error.IsSuccess())
901 OnRegistrationInfoSignal(status, operator_code, operator_name);
902}
903
904void CellularCapabilityGSM::OnGetSignalQualityReply(uint32 quality,
905 const Error &error) {
906 if (error.IsSuccess())
907 OnSignalQualitySignal(quality);
908}
909
910void CellularCapabilityGSM::OnGetIMEIReply(const ResultCallback &callback,
911 const string &imei,
912 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500913 if (error.IsSuccess()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700914 SLOG(Cellular, 2) << "IMEI: " << imei;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500915 imei_ = imei;
916 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700917 SLOG(Cellular, 2) << "GetIMEI failed - " << error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500918 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500919 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500920}
921
Eric Shienbrood9a245532012-03-07 14:20:39 -0500922void CellularCapabilityGSM::OnGetIMSIReply(const ResultCallback &callback,
923 const string &imsi,
924 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500925 if (error.IsSuccess()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700926 SLOG(Cellular, 2) << "IMSI: " << imsi;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500927 imsi_ = imsi;
Ben Chanbd3aee82012-10-16 23:52:04 -0700928 sim_present_ = true;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500929 SetHomeProvider();
Gary Morain82a31a02012-08-02 18:03:32 -0700930 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500931 } else {
Ben Chanbd3aee82012-10-16 23:52:04 -0700932 sim_present_ = false;
Gary Morain82a31a02012-08-02 18:03:32 -0700933 if (get_imsi_retries_++ < kGetIMSIRetryLimit) {
934 SLOG(Cellular, 2) << "GetIMSI failed - " << error << ". Retrying";
935 base::Callback<void(void)> retry_get_imsi_cb =
936 Bind(&CellularCapabilityGSM::GetIMSI,
937 weak_ptr_factory_.GetWeakPtr(), callback);
938 cellular()->dispatcher()->PostDelayedTask(
939 retry_get_imsi_cb,
940 get_imsi_retry_delay_milliseconds_);
941 } else {
942 LOG(INFO) << "GetIMSI failed - " << error;
943 callback.Run(error);
944 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500945 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500946}
947
Eric Shienbrood9a245532012-03-07 14:20:39 -0500948void CellularCapabilityGSM::OnGetSPNReply(const ResultCallback &callback,
949 const string &spn,
950 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500951 if (error.IsSuccess()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700952 SLOG(Cellular, 2) << "SPN: " << spn;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500953 spn_ = spn;
954 SetHomeProvider();
955 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700956 SLOG(Cellular, 2) << "GetSPN failed - " << error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500957 }
Thieu Le923006b2012-04-05 16:32:58 -0700958 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500959}
960
Eric Shienbrood9a245532012-03-07 14:20:39 -0500961void CellularCapabilityGSM::OnGetMSISDNReply(const ResultCallback &callback,
962 const string &msisdn,
963 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500964 if (error.IsSuccess()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700965 SLOG(Cellular, 2) << "MSISDN: " << msisdn;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500966 mdn_ = msisdn;
967 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700968 SLOG(Cellular, 2) << "GetMSISDN failed - " << error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500969 }
Thieu Le923006b2012-04-05 16:32:58 -0700970 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500971}
972
Darin Petkovdaf43862011-10-27 11:37:28 +0200973} // namespace shill