blob: 63ebbffe4a4e3d13379b59afae5f52085a744e93 [file] [log] [blame]
Darin Petkovc64fe5e2012-01-11 12:46:13 +01001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Darin Petkovdaf43862011-10-27 11:37:28 +02002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "shill/cellular_capability_gsm.h"
6
Eric Shienbrood3e20a232012-02-16 11:35:56 -05007#include <base/bind.h>
Darin Petkovdaf43862011-10-27 11:37:28 +02008#include <base/logging.h>
Eric Shienbrood3e20a232012-02-16 11:35:56 -05009#include <base/stl_util.h>
Darin Petkov1272a432011-11-10 15:53:37 +010010#include <base/string_number_conversions.h>
Darin Petkovac635a82012-01-10 16:51:58 +010011#include <base/stringprintf.h>
Darin Petkov20c13ec2011-11-09 15:07:15 +010012#include <chromeos/dbus/service_constants.h>
13#include <mm/mm-modem.h>
Darin Petkov1272a432011-11-10 15:53:37 +010014#include <mobile_provider.h>
Darin Petkovdaf43862011-10-27 11:37:28 +020015
Darin Petkov3cfbf212011-11-21 16:02:09 +010016#include "shill/adaptor_interfaces.h"
Darin Petkovae0c64e2011-11-15 15:50:27 +010017#include "shill/cellular_service.h"
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050018#include "shill/error.h"
Darin Petkov721ac932011-11-16 15:43:09 +010019#include "shill/property_accessor.h"
Darin Petkovdaf43862011-10-27 11:37:28 +020020#include "shill/proxy_factory.h"
21
Eric Shienbrood3e20a232012-02-16 11:35:56 -050022using base::Bind;
Darin Petkovb05315f2011-11-07 10:14:25 +010023using std::string;
24
Darin Petkovdaf43862011-10-27 11:37:28 +020025namespace shill {
26
Darin Petkovac635a82012-01-10 16:51:58 +010027// static
28unsigned int CellularCapabilityGSM::friendly_service_name_id_ = 0;
29
Darin Petkov1272a432011-11-10 15:53:37 +010030const char CellularCapabilityGSM::kNetworkPropertyAccessTechnology[] =
31 "access-tech";
32const char CellularCapabilityGSM::kNetworkPropertyID[] = "operator-num";
33const char CellularCapabilityGSM::kNetworkPropertyLongName[] = "operator-long";
34const char CellularCapabilityGSM::kNetworkPropertyShortName[] =
35 "operator-short";
36const char CellularCapabilityGSM::kNetworkPropertyStatus[] = "status";
Darin Petkovae0c64e2011-11-15 15:50:27 +010037const char CellularCapabilityGSM::kPhoneNumber[] = "*99#";
38const char CellularCapabilityGSM::kPropertyAccessTechnology[] =
39 "AccessTechnology";
Darin Petkov63138a92012-02-06 14:09:15 +010040const char CellularCapabilityGSM::kPropertyEnabledFacilityLocks[] =
41 "EnabledFacilityLocks";
Darin Petkov721ac932011-11-16 15:43:09 +010042const char CellularCapabilityGSM::kPropertyUnlockRequired[] = "UnlockRequired";
43const char CellularCapabilityGSM::kPropertyUnlockRetries[] = "UnlockRetries";
Darin Petkov1272a432011-11-10 15:53:37 +010044
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050045CellularCapabilityGSM::CellularCapabilityGSM(Cellular *cellular,
46 ProxyFactory *proxy_factory)
47 : CellularCapability(cellular, proxy_factory),
Eric Shienbrood3e20a232012-02-16 11:35:56 -050048 weak_ptr_factory_(this),
Darin Petkov184c54e2011-11-15 12:44:39 +010049 registration_state_(MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN),
Darin Petkovae0c64e2011-11-15 15:50:27 +010050 access_technology_(MM_MODEM_GSM_ACCESS_TECH_UNKNOWN),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +010051 home_provider_(NULL),
Darin Petkov1272a432011-11-10 15:53:37 +010052 scanning_(false),
53 scan_interval_(0) {
Darin Petkov5f316f62011-11-18 12:10:26 +010054 VLOG(2) << "Cellular capability constructed: GSM";
Darin Petkov1272a432011-11-10 15:53:37 +010055 PropertyStore *store = cellular->mutable_store();
Darin Petkov184c54e2011-11-15 12:44:39 +010056 store->RegisterConstString(flimflam::kSelectedNetworkProperty,
57 &selected_network_);
Darin Petkov1272a432011-11-10 15:53:37 +010058 store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
59 &found_networks_);
60 store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
61 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
Darin Petkov63138a92012-02-06 14:09:15 +010062 HelpRegisterDerivedKeyValueStore(
63 flimflam::kSIMLockStatusProperty,
64 &CellularCapabilityGSM::SimLockStatusToProperty,
65 NULL);
Darin Petkov3cfbf212011-11-21 16:02:09 +010066 store->RegisterConstStringmaps(flimflam::kCellularApnListProperty,
67 &apn_list_);
Darin Petkov0d06f7d2012-02-03 13:08:19 +010068 scanning_supported_ = true;
Darin Petkov1272a432011-11-10 15:53:37 +010069}
Darin Petkovdaf43862011-10-27 11:37:28 +020070
Darin Petkov63138a92012-02-06 14:09:15 +010071KeyValueStore CellularCapabilityGSM::SimLockStatusToProperty(Error */*error*/) {
72 KeyValueStore status;
73 status.SetBool(flimflam::kSIMLockEnabledProperty, sim_lock_status_.enabled);
74 status.SetString(flimflam::kSIMLockTypeProperty, sim_lock_status_.lock_type);
75 status.SetUint(flimflam::kSIMLockRetriesLeftProperty,
76 sim_lock_status_.retries_left);
77 return status;
Darin Petkov721ac932011-11-16 15:43:09 +010078}
79
Darin Petkov63138a92012-02-06 14:09:15 +010080void CellularCapabilityGSM::HelpRegisterDerivedKeyValueStore(
Darin Petkov721ac932011-11-16 15:43:09 +010081 const string &name,
Darin Petkov63138a92012-02-06 14:09:15 +010082 KeyValueStore(CellularCapabilityGSM::*get)(Error *error),
83 void(CellularCapabilityGSM::*set)(
84 const KeyValueStore &value, Error *error)) {
85 cellular()->mutable_store()->RegisterDerivedKeyValueStore(
Darin Petkov721ac932011-11-16 15:43:09 +010086 name,
Darin Petkov63138a92012-02-06 14:09:15 +010087 KeyValueStoreAccessor(
88 new CustomAccessor<CellularCapabilityGSM, KeyValueStore>(
Darin Petkov721ac932011-11-16 15:43:09 +010089 this, get, set)));
90}
91
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050092void CellularCapabilityGSM::StartModem()
93{
94 CellularCapability::StartModem();
Darin Petkovcb547732011-11-09 13:55:26 +010095 card_proxy_.reset(
96 proxy_factory()->CreateModemGSMCardProxy(this,
Darin Petkovdaf43862011-10-27 11:37:28 +020097 cellular()->dbus_path(),
98 cellular()->dbus_owner()));
Darin Petkov184c54e2011-11-15 12:44:39 +010099 network_proxy_.reset(
100 proxy_factory()->CreateModemGSMNetworkProxy(this,
Darin Petkovdaf43862011-10-27 11:37:28 +0200101 cellular()->dbus_path(),
102 cellular()->dbus_owner()));
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500103 MultiStepAsyncCallHandler *call_handler =
104 new MultiStepAsyncCallHandler(cellular()->dispatcher());
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500105 call_handler->AddTask(Bind(&CellularCapabilityGSM::EnableModem,
106 weak_ptr_factory_.GetWeakPtr(), call_handler));
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500107
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500108 call_handler->AddTask(Bind(&CellularCapabilityGSM::Register,
109 weak_ptr_factory_.GetWeakPtr(), call_handler));
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500110
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500111 call_handler->AddTask(Bind(&CellularCapabilityGSM::GetModemStatus,
112 weak_ptr_factory_.GetWeakPtr(), call_handler));
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500113
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500114 call_handler->AddTask(Bind(&CellularCapabilityGSM::GetIMEI,
115 weak_ptr_factory_.GetWeakPtr(), call_handler));
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500116
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500117 call_handler->AddTask(Bind(&CellularCapabilityGSM::GetIMSI,
118 weak_ptr_factory_.GetWeakPtr(), call_handler));
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500119
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500120 call_handler->AddTask(Bind(&CellularCapabilityGSM::GetSPN,
121 weak_ptr_factory_.GetWeakPtr(), call_handler));
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500122
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500123 call_handler->AddTask(Bind(&CellularCapabilityGSM::GetMSISDN,
124 weak_ptr_factory_.GetWeakPtr(), call_handler));
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500125
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500126 call_handler->AddTask(Bind(&CellularCapabilityGSM::GetProperties,
127 weak_ptr_factory_.GetWeakPtr(), call_handler));
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500128
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500129 call_handler->AddTask(Bind(&CellularCapabilityGSM::GetModemInfo,
130 weak_ptr_factory_.GetWeakPtr(), call_handler));
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500131
Eric Shienbrood3e20a232012-02-16 11:35:56 -0500132 call_handler->AddTask(Bind(&CellularCapabilityGSM::GetRegistrationState,
133 weak_ptr_factory_.GetWeakPtr(),
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500134 call_handler));
135 call_handler->PostNextTask();
Darin Petkovdaf43862011-10-27 11:37:28 +0200136}
137
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500138void CellularCapabilityGSM::StopModem() {
Darin Petkov721ac932011-11-16 15:43:09 +0100139 VLOG(2) << __func__;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500140 CellularCapability::StopModem();
Darin Petkov721ac932011-11-16 15:43:09 +0100141 card_proxy_.reset();
142 network_proxy_.reset();
143}
144
Darin Petkov5f316f62011-11-18 12:10:26 +0100145void CellularCapabilityGSM::OnServiceCreated() {
Darin Petkov31332412012-01-28 01:50:02 +0100146 // If IMSI is available, base the service's storage identifier on it.
147 if (!imsi_.empty()) {
148 cellular()->service()->SetStorageIdentifier(
Darin Petkovdd3e8662012-02-03 13:16:20 +0100149 string(flimflam::kTypeCellular) + "_" +
150 cellular()->address() + "_" + imsi_);
Darin Petkov31332412012-01-28 01:50:02 +0100151 }
Darin Petkovb9c99332012-01-12 13:13:00 +0100152 cellular()->service()->SetActivationState(
Darin Petkov5f316f62011-11-18 12:10:26 +0100153 flimflam::kActivationStateActivated);
154 UpdateServingOperator();
155}
156
Darin Petkovae0c64e2011-11-15 15:50:27 +0100157void CellularCapabilityGSM::UpdateStatus(const DBusPropertiesMap &properties) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500158 if (ContainsKey(properties, kPropertyIMSI)) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100159 SetHomeProvider();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100160 }
161}
162
163void CellularCapabilityGSM::SetupConnectProperties(
164 DBusPropertiesMap *properties) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500165 (*properties)[kConnectPropertyPhoneNumber].writer().append_string(
Darin Petkovae0c64e2011-11-15 15:50:27 +0100166 kPhoneNumber);
167 // TODO(petkov): Setup apn and "home_only".
168}
169
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500170void CellularCapabilityGSM::GetIMEI(AsyncCallHandler *call_handler){
Darin Petkovcb547732011-11-09 13:55:26 +0100171 VLOG(2) << __func__;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500172 if (imei_.empty()) {
173 card_proxy_->GetIMEI(call_handler, kTimeoutDefault);
174 } else {
175 VLOG(2) << "Already have IMEI " << imei_;
176 CompleteOperation(call_handler);
Darin Petkovcb547732011-11-09 13:55:26 +0100177 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500178}
179
180void CellularCapabilityGSM::GetIMSI(AsyncCallHandler *call_handler){
181 VLOG(2) << __func__;
182 if (imsi_.empty()) {
183 card_proxy_->GetIMSI(call_handler, kTimeoutDefault);
184 } else {
185 VLOG(2) << "Already have IMSI " << imsi_;
186 CompleteOperation(call_handler);
Darin Petkovcb547732011-11-09 13:55:26 +0100187 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500188}
189
190void CellularCapabilityGSM::GetSPN(AsyncCallHandler *call_handler){
191 VLOG(2) << __func__;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100192 if (spn_.empty()) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500193 card_proxy_->GetSPN(call_handler, kTimeoutDefault);
194 } else {
195 VLOG(2) << "Already have SPN " << spn_;
196 CompleteOperation(call_handler);
Darin Petkovcb547732011-11-09 13:55:26 +0100197 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500198}
199
200void CellularCapabilityGSM::GetMSISDN(AsyncCallHandler *call_handler){
201 VLOG(2) << __func__;
202 if (mdn_.empty()) {
203 card_proxy_->GetMSISDN(call_handler, kTimeoutDefault);
204 } else {
205 VLOG(2) << "Already have MSISDN " << mdn_;
206 CompleteOperation(call_handler);
Darin Petkovcb547732011-11-09 13:55:26 +0100207 }
208}
209
Darin Petkov3e509242011-11-10 14:46:44 +0100210void CellularCapabilityGSM::GetSignalQuality() {
211 VLOG(2) << __func__;
212 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkov184c54e2011-11-15 12:44:39 +0100213 uint32 strength = network_proxy_->GetSignalQuality();
Darin Petkov3e509242011-11-10 14:46:44 +0100214 cellular()->HandleNewSignalQuality(strength);
215}
216
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500217void CellularCapabilityGSM::GetRegistrationState(
218 AsyncCallHandler *call_handler) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100219 VLOG(2) << __func__;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500220 network_proxy_->GetRegistrationInfo(call_handler, kTimeoutDefault);
Darin Petkov184c54e2011-11-15 12:44:39 +0100221}
222
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500223void CellularCapabilityGSM::GetProperties(AsyncCallHandler *call_handler) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100224 VLOG(2) << __func__;
Darin Petkov63138a92012-02-06 14:09:15 +0100225
Darin Petkov184c54e2011-11-15 12:44:39 +0100226 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
227 uint32 tech = network_proxy_->AccessTechnology();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100228 SetAccessTechnology(tech);
Darin Petkov184c54e2011-11-15 12:44:39 +0100229 VLOG(2) << "GSM AccessTechnology: " << tech;
Darin Petkov63138a92012-02-06 14:09:15 +0100230
231 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
232 uint32 locks = card_proxy_->EnabledFacilityLocks();
233 sim_lock_status_.enabled = locks & MM_MODEM_GSM_FACILITY_SIM;
234 VLOG(2) << "GSM EnabledFacilityLocks: " << locks;
235
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500236 CompleteOperation(call_handler);
Darin Petkov184c54e2011-11-15 12:44:39 +0100237}
238
Darin Petkovac635a82012-01-10 16:51:58 +0100239string CellularCapabilityGSM::CreateFriendlyServiceName() {
240 VLOG(2) << __func__;
241 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME &&
242 !cellular()->home_provider().GetName().empty()) {
243 return cellular()->home_provider().GetName();
244 }
245 if (!serving_operator_.GetName().empty()) {
246 return serving_operator_.GetName();
247 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500248 if (!carrier_.empty()) {
249 return carrier_;
Darin Petkovac635a82012-01-10 16:51:58 +0100250 }
251 if (!serving_operator_.GetCode().empty()) {
252 return "cellular_" + serving_operator_.GetCode();
253 }
254 return base::StringPrintf("GSMNetwork%u", friendly_service_name_id_++);
255}
256
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100257void CellularCapabilityGSM::SetHomeProvider() {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500258 VLOG(2) << __func__ << "(IMSI: " << imsi_
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100259 << " SPN: " << spn_ << ")";
260 // TODO(petkov): The test for NULL provider_db should be done by
261 // mobile_provider_lookup_best_match.
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500262 if (imsi_.empty() || !cellular()->provider_db()) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100263 return;
264 }
265 mobile_provider *provider =
266 mobile_provider_lookup_best_match(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500267 cellular()->provider_db(), spn_.c_str(), imsi_.c_str());
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100268 if (!provider) {
269 VLOG(2) << "GSM provider not found.";
270 return;
271 }
272 home_provider_ = provider;
273 Cellular::Operator oper;
274 if (provider->networks) {
275 oper.SetCode(provider->networks[0]);
276 }
277 if (provider->country) {
278 oper.SetCountry(provider->country);
279 }
280 if (spn_.empty()) {
281 const char *name = mobile_provider_get_name(provider);
282 if (name) {
283 oper.SetName(name);
284 }
285 } else {
286 oper.SetName(spn_);
287 }
288 cellular()->set_home_provider(oper);
Darin Petkov3cfbf212011-11-21 16:02:09 +0100289 InitAPNList();
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100290}
291
Darin Petkovae0c64e2011-11-15 15:50:27 +0100292void CellularCapabilityGSM::UpdateOperatorInfo() {
293 VLOG(2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100294 const string &network_id = serving_operator_.GetCode();
295 if (!network_id.empty()) {
296 VLOG(2) << "Looking up network id: " << network_id;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100297 mobile_provider *provider =
298 mobile_provider_lookup_by_network(cellular()->provider_db(),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100299 network_id.c_str());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100300 if (provider) {
301 const char *provider_name = mobile_provider_get_name(provider);
302 if (provider_name && *provider_name) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100303 serving_operator_.SetName(provider_name);
304 if (provider->country) {
305 serving_operator_.SetCountry(provider->country);
306 }
307 VLOG(2) << "Operator name: " << serving_operator_.GetName()
308 << ", country: " << serving_operator_.GetCountry();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100309 }
310 } else {
311 VLOG(2) << "GSM provider not found.";
312 }
313 }
314 UpdateServingOperator();
315}
316
317void CellularCapabilityGSM::UpdateServingOperator() {
318 VLOG(2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100319 if (cellular()->service().get()) {
Darin Petkov9cb02682012-01-28 00:17:38 +0100320 cellular()->service()->SetServingOperator(serving_operator_);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100321 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100322}
323
Darin Petkov3cfbf212011-11-21 16:02:09 +0100324void CellularCapabilityGSM::InitAPNList() {
325 VLOG(2) << __func__;
326 if (!home_provider_) {
327 return;
328 }
329 apn_list_.clear();
330 for (int i = 0; i < home_provider_->num_apns; ++i) {
331 Stringmap props;
332 mobile_apn *apn = home_provider_->apns[i];
333 if (apn->value) {
334 props[flimflam::kApnProperty] = apn->value;
335 }
336 if (apn->username) {
337 props[flimflam::kApnUsernameProperty] = apn->username;
338 }
339 if (apn->password) {
340 props[flimflam::kApnPasswordProperty] = apn->password;
341 }
342 // Find the first localized and non-localized name, if any.
343 const localized_name *lname = NULL;
344 const localized_name *name = NULL;
345 for (int j = 0; j < apn->num_names; ++j) {
346 if (apn->names[j]->lang) {
347 if (!lname) {
348 lname = apn->names[j];
349 }
350 } else if (!name) {
351 name = apn->names[j];
352 }
353 }
354 if (name) {
355 props[flimflam::kApnNameProperty] = name->name;
356 }
357 if (lname) {
358 props[flimflam::kApnLocalizedNameProperty] = lname->name;
359 props[flimflam::kApnLanguageProperty] = lname->lang;
360 }
361 apn_list_.push_back(props);
362 }
363 cellular()->adaptor()->EmitStringmapsChanged(
364 flimflam::kCellularApnListProperty, apn_list_);
365}
366
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500367void CellularCapabilityGSM::Register(AsyncCallHandler *call_handler) {
368 VLOG(2) << __func__ << " \"" << selected_network_ << "\"";
369 network_proxy_->Register(selected_network_, call_handler,
370 kTimeoutRegister);
Darin Petkov184c54e2011-11-15 12:44:39 +0100371}
372
373void CellularCapabilityGSM::RegisterOnNetwork(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500374 const string &network_id, AsyncCallHandler *call_handler) {
375 VLOG(2) << __func__ << "(" << network_id << ")";
376 desired_network_ = network_id;
377 network_proxy_->Register(network_id, call_handler,
378 kTimeoutRegister);
379}
380
381void CellularCapabilityGSM::OnRegisterCallback(const Error &error,
382 AsyncCallHandler *call_handler) {
383 VLOG(2) << __func__ << "(" << error << ")";
384
385 if (error.IsSuccess()) {
386 selected_network_ = desired_network_;
387 desired_network_.clear();
388 CompleteOperation(call_handler);
389 return;
390 }
391 // If registration on the desired network failed,
392 // try to register on the home network.
393 if (!desired_network_.empty()) {
394 desired_network_.clear();
395 selected_network_.clear();
396 Register(call_handler);
397 return;
398 }
399 CompleteOperation(call_handler, error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100400}
401
Darin Petkovb72cf402011-11-22 14:51:39 +0100402bool CellularCapabilityGSM::IsRegistered() {
403 return (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
404 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING);
405}
406
Darin Petkovb05315f2011-11-07 10:14:25 +0100407void CellularCapabilityGSM::RequirePIN(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500408 const string &pin, bool require, AsyncCallHandler *call_handler) {
409 VLOG(2) << __func__ << "(" << call_handler << ")";
410 card_proxy_->EnablePIN(pin, require, call_handler, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100411}
412
Darin Petkove5bc2cb2011-12-07 14:47:32 +0100413void CellularCapabilityGSM::EnterPIN(const string &pin,
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500414 AsyncCallHandler *call_handler) {
415 VLOG(2) << __func__ << "(" << call_handler << ")";
416 card_proxy_->SendPIN(pin, call_handler, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100417}
418
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100419void CellularCapabilityGSM::UnblockPIN(const string &unblock_code,
420 const string &pin,
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500421 AsyncCallHandler *call_handler) {
422 VLOG(2) << __func__ << "(" << call_handler << ")";
423 card_proxy_->SendPUK(unblock_code, pin, call_handler,
424 kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100425}
426
427void CellularCapabilityGSM::ChangePIN(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500428 const string &old_pin, const string &new_pin,
429 AsyncCallHandler *call_handler) {
430 VLOG(2) << __func__ << "(" << call_handler << ")";
431 card_proxy_->ChangePIN(old_pin, new_pin, call_handler,
432 kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100433}
434
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500435void CellularCapabilityGSM::Scan(AsyncCallHandler *call_handler) {
Darin Petkov1272a432011-11-10 15:53:37 +0100436 VLOG(2) << __func__;
437 // TODO(petkov): Defer scan requests if a scan is in progress already.
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500438 network_proxy_->Scan(call_handler, kTimeoutScan);
Darin Petkov1272a432011-11-10 15:53:37 +0100439}
440
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500441void CellularCapabilityGSM::OnScanCallback(const GSMScanResults &results,
442 const Error &error,
443 AsyncCallHandler *call_handler) {
444 VLOG(2) << __func__;
445 if (error.IsFailure()) {
446 CompleteOperation(call_handler, error);
447 return;
448 }
449 found_networks_.clear();
450 for (GSMScanResults::const_iterator it = results.begin();
451 it != results.end(); ++it) {
452 found_networks_.push_back(ParseScanResult(*it));
453 }
Darin Petkovb7828b02012-02-03 12:34:30 +0100454 cellular()->adaptor()->EmitStringmapsChanged(flimflam::kFoundNetworksProperty,
455 found_networks_);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500456 CompleteOperation(call_handler);
457}
458
459Stringmap CellularCapabilityGSM::ParseScanResult(const GSMScanResult &result) {
Darin Petkov1272a432011-11-10 15:53:37 +0100460 Stringmap parsed;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500461 for (GSMScanResult::const_iterator it = result.begin();
462 it != result.end(); ++it) {
Darin Petkov1272a432011-11-10 15:53:37 +0100463 // TODO(petkov): Define these in system_api/service_constants.h. The
464 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
465 static const char * const kStatusString[] = {
466 "unknown",
467 "available",
468 "current",
469 "forbidden",
470 };
471 static const char * const kTechnologyString[] = {
472 flimflam::kNetworkTechnologyGsm,
473 "GSM Compact",
474 flimflam::kNetworkTechnologyUmts,
475 flimflam::kNetworkTechnologyEdge,
476 "HSDPA",
477 "HSUPA",
478 flimflam::kNetworkTechnologyHspa,
479 };
480 VLOG(2) << "Network property: " << it->first << " = " << it->second;
481 if (it->first == kNetworkPropertyStatus) {
482 int status = 0;
483 if (base::StringToInt(it->second, &status) &&
484 status >= 0 &&
485 status < static_cast<int>(arraysize(kStatusString))) {
486 parsed[flimflam::kStatusProperty] = kStatusString[status];
487 } else {
488 LOG(ERROR) << "Unexpected status value: " << it->second;
489 }
490 } else if (it->first == kNetworkPropertyID) {
491 parsed[flimflam::kNetworkIdProperty] = it->second;
492 } else if (it->first == kNetworkPropertyLongName) {
493 parsed[flimflam::kLongNameProperty] = it->second;
494 } else if (it->first == kNetworkPropertyShortName) {
495 parsed[flimflam::kShortNameProperty] = it->second;
496 } else if (it->first == kNetworkPropertyAccessTechnology) {
497 int tech = 0;
498 if (base::StringToInt(it->second, &tech) &&
499 tech >= 0 &&
500 tech < static_cast<int>(arraysize(kTechnologyString))) {
501 parsed[flimflam::kTechnologyProperty] = kTechnologyString[tech];
502 } else {
503 LOG(ERROR) << "Unexpected technology value: " << it->second;
504 }
505 } else {
506 LOG(WARNING) << "Unknown network property ignored: " << it->first;
507 }
508 }
509 // If the long name is not available but the network ID is, look up the long
510 // name in the mobile provider database.
511 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
512 parsed[flimflam::kLongNameProperty].empty()) &&
513 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
514 mobile_provider *provider =
515 mobile_provider_lookup_by_network(
516 cellular()->provider_db(),
517 parsed[flimflam::kNetworkIdProperty].c_str());
518 if (provider) {
519 const char *long_name = mobile_provider_get_name(provider);
520 if (long_name && *long_name) {
521 parsed[flimflam::kLongNameProperty] = long_name;
522 }
523 }
524 }
525 return parsed;
526}
527
Darin Petkovae0c64e2011-11-15 15:50:27 +0100528void CellularCapabilityGSM::SetAccessTechnology(uint32 access_technology) {
529 access_technology_ = access_technology;
530 if (cellular()->service().get()) {
Darin Petkovb72cf402011-11-22 14:51:39 +0100531 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100532 }
533}
534
Darin Petkov20c13ec2011-11-09 15:07:15 +0100535string CellularCapabilityGSM::GetNetworkTechnologyString() const {
Darin Petkovb72cf402011-11-22 14:51:39 +0100536 switch (access_technology_) {
537 case MM_MODEM_GSM_ACCESS_TECH_GSM:
538 case MM_MODEM_GSM_ACCESS_TECH_GSM_COMPACT:
539 return flimflam::kNetworkTechnologyGsm;
540 case MM_MODEM_GSM_ACCESS_TECH_GPRS:
541 return flimflam::kNetworkTechnologyGprs;
542 case MM_MODEM_GSM_ACCESS_TECH_EDGE:
543 return flimflam::kNetworkTechnologyEdge;
544 case MM_MODEM_GSM_ACCESS_TECH_UMTS:
545 return flimflam::kNetworkTechnologyUmts;
546 case MM_MODEM_GSM_ACCESS_TECH_HSDPA:
547 case MM_MODEM_GSM_ACCESS_TECH_HSUPA:
548 case MM_MODEM_GSM_ACCESS_TECH_HSPA:
549 return flimflam::kNetworkTechnologyHspa;
550 case MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS:
551 return flimflam::kNetworkTechnologyHspaPlus;
552 default:
553 break;
Darin Petkov20c13ec2011-11-09 15:07:15 +0100554 }
555 return "";
556}
557
558string CellularCapabilityGSM::GetRoamingStateString() const {
Darin Petkov184c54e2011-11-15 12:44:39 +0100559 switch (registration_state_) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100560 case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME:
561 return flimflam::kRoamingStateHome;
562 case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING:
563 return flimflam::kRoamingStateRoaming;
564 default:
565 break;
566 }
567 return flimflam::kRoamingStateUnknown;
568}
569
Darin Petkovae0c64e2011-11-15 15:50:27 +0100570void CellularCapabilityGSM::OnModemManagerPropertiesChanged(
571 const DBusPropertiesMap &properties) {
572 uint32 access_technology = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
573 if (DBusProperties::GetUint32(properties,
574 kPropertyAccessTechnology,
575 &access_technology)) {
576 SetAccessTechnology(access_technology);
577 }
Darin Petkov63138a92012-02-06 14:09:15 +0100578 bool emit = false;
579 uint32 locks = 0;
580 if (DBusProperties::GetUint32(
581 properties, kPropertyEnabledFacilityLocks, &locks)) {
582 sim_lock_status_.enabled = locks & MM_MODEM_GSM_FACILITY_SIM;
583 emit = true;
584 }
585 if (DBusProperties::GetString(
586 properties, kPropertyUnlockRequired, &sim_lock_status_.lock_type)) {
587 emit = true;
588 }
589 if (DBusProperties::GetUint32(
590 properties, kPropertyUnlockRetries, &sim_lock_status_.retries_left)) {
591 emit = true;
592 }
593 if (emit) {
594 cellular()->adaptor()->EmitKeyValueStoreChanged(
595 flimflam::kSIMLockStatusProperty, SimLockStatusToProperty(NULL));
596 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100597}
598
Darin Petkov184c54e2011-11-15 12:44:39 +0100599void CellularCapabilityGSM::OnGSMNetworkModeChanged(uint32 /*mode*/) {
600 // TODO(petkov): Implement this.
601 NOTIMPLEMENTED();
602}
603
604void CellularCapabilityGSM::OnGSMRegistrationInfoChanged(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500605 uint32 status, const string &operator_code, const string &operator_name,
606 const Error &error, AsyncCallHandler *call_handler) {
607 if (error.IsSuccess()) {
608 VLOG(2) << __func__ << ": regstate=" << status
609 << ", opercode=" << operator_code
610 << ", opername=" << operator_name;
611 registration_state_ = status;
612 serving_operator_.SetCode(operator_code);
613 serving_operator_.SetName(operator_name);
614 UpdateOperatorInfo();
615 cellular()->HandleNewRegistrationState();
616 }
617 CompleteOperation(call_handler, error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100618}
619
620void CellularCapabilityGSM::OnGSMSignalQualityChanged(uint32 quality) {
621 cellular()->HandleNewSignalQuality(quality);
622}
623
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500624void CellularCapabilityGSM::OnGetIMEICallback(const string &imei,
625 const Error &error,
626 AsyncCallHandler *call_handler) {
627 if (error.IsSuccess()) {
628 VLOG(2) << "IMEI: " << imei;
629 imei_ = imei;
630 } else {
631 VLOG(2) << "GetIMEI failed - " << error;
632 }
633 CompleteOperation(call_handler, error);
634}
635
636void CellularCapabilityGSM::OnGetIMSICallback(const string &imsi,
637 const Error &error,
638 AsyncCallHandler *call_handler) {
639 if (error.IsSuccess()) {
640 VLOG(2) << "IMSI: " << imsi;
641 imsi_ = imsi;
642 SetHomeProvider();
643 } else {
644 VLOG(2) << "GetIMSI failed - " << error;
645 }
646 CompleteOperation(call_handler, error);
647}
648
649void CellularCapabilityGSM::OnGetSPNCallback(const string &spn,
650 const Error &error,
651 AsyncCallHandler *call_handler) {
652 if (error.IsSuccess()) {
653 VLOG(2) << "SPN: " << spn;
654 spn_ = spn;
655 SetHomeProvider();
656 } else {
657 VLOG(2) << "GetSPN failed - " << error;
658 }
659 // Ignore the error - it's not fatal.
660 CompleteOperation(call_handler);
661}
662
663void CellularCapabilityGSM::OnGetMSISDNCallback(
664 const string &msisdn, const Error &error, AsyncCallHandler *call_handler) {
665 if (error.IsSuccess()) {
666 VLOG(2) << "MSISDN: " << msisdn;
667 mdn_ = msisdn;
668 } else {
669 VLOG(2) << "GetMSISDN failed - " << error;
670 }
671 // Ignore the error - it's not fatal.
672 CompleteOperation(call_handler);
673}
674
675void CellularCapabilityGSM::OnPINOperationCallback(
676 const Error &error, AsyncCallHandler *call_handler) {
677 if (error.IsFailure())
678 VLOG(2) << "PIN operation failed - " << error;
679 else
680 VLOG(2) << "PIN operation complete";
681 CompleteOperation(call_handler, error);
682}
683
Darin Petkovdaf43862011-10-27 11:37:28 +0200684} // namespace shill