blob: cf4e551d7a725a6aa796e05c9b4516bdf0114cc0 [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
7#include <base/logging.h>
Darin Petkov1272a432011-11-10 15:53:37 +01008#include <base/stl_util-inl.h>
9#include <base/string_number_conversions.h>
Darin Petkovac635a82012-01-10 16:51:58 +010010#include <base/stringprintf.h>
Darin Petkov20c13ec2011-11-09 15:07:15 +010011#include <chromeos/dbus/service_constants.h>
12#include <mm/mm-modem.h>
Darin Petkov1272a432011-11-10 15:53:37 +010013#include <mobile_provider.h>
Darin Petkovdaf43862011-10-27 11:37:28 +020014
Darin Petkov3cfbf212011-11-21 16:02:09 +010015#include "shill/adaptor_interfaces.h"
Darin Petkovae0c64e2011-11-15 15:50:27 +010016#include "shill/cellular_service.h"
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050017#include "shill/error.h"
Darin Petkov721ac932011-11-16 15:43:09 +010018#include "shill/property_accessor.h"
Darin Petkovdaf43862011-10-27 11:37:28 +020019#include "shill/proxy_factory.h"
20
Darin Petkov721ac932011-11-16 15:43:09 +010021using std::make_pair;
Darin Petkovb05315f2011-11-07 10:14:25 +010022using std::string;
23
Darin Petkovdaf43862011-10-27 11:37:28 +020024namespace shill {
25
Darin Petkovac635a82012-01-10 16:51:58 +010026// static
27unsigned int CellularCapabilityGSM::friendly_service_name_id_ = 0;
28
Darin Petkov1272a432011-11-10 15:53:37 +010029const char CellularCapabilityGSM::kNetworkPropertyAccessTechnology[] =
30 "access-tech";
31const char CellularCapabilityGSM::kNetworkPropertyID[] = "operator-num";
32const char CellularCapabilityGSM::kNetworkPropertyLongName[] = "operator-long";
33const char CellularCapabilityGSM::kNetworkPropertyShortName[] =
34 "operator-short";
35const char CellularCapabilityGSM::kNetworkPropertyStatus[] = "status";
Darin Petkovae0c64e2011-11-15 15:50:27 +010036const char CellularCapabilityGSM::kPhoneNumber[] = "*99#";
37const char CellularCapabilityGSM::kPropertyAccessTechnology[] =
38 "AccessTechnology";
Darin Petkov721ac932011-11-16 15:43:09 +010039const char CellularCapabilityGSM::kPropertyUnlockRequired[] = "UnlockRequired";
40const char CellularCapabilityGSM::kPropertyUnlockRetries[] = "UnlockRetries";
Darin Petkov1272a432011-11-10 15:53:37 +010041
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050042CellularCapabilityGSM::CellularCapabilityGSM(Cellular *cellular,
43 ProxyFactory *proxy_factory)
44 : CellularCapability(cellular, proxy_factory),
Darin Petkov1272a432011-11-10 15:53:37 +010045 task_factory_(this),
Darin Petkov184c54e2011-11-15 12:44:39 +010046 registration_state_(MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN),
Darin Petkovae0c64e2011-11-15 15:50:27 +010047 access_technology_(MM_MODEM_GSM_ACCESS_TECH_UNKNOWN),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +010048 home_provider_(NULL),
Darin Petkov1272a432011-11-10 15:53:37 +010049 scanning_(false),
50 scan_interval_(0) {
Darin Petkov5f316f62011-11-18 12:10:26 +010051 VLOG(2) << "Cellular capability constructed: GSM";
Darin Petkov1272a432011-11-10 15:53:37 +010052 PropertyStore *store = cellular->mutable_store();
Darin Petkov184c54e2011-11-15 12:44:39 +010053 store->RegisterConstString(flimflam::kSelectedNetworkProperty,
54 &selected_network_);
Darin Petkov1272a432011-11-10 15:53:37 +010055 store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
56 &found_networks_);
57 store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
58 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
Darin Petkov721ac932011-11-16 15:43:09 +010059 HelpRegisterDerivedStrIntPair(flimflam::kSIMLockStatusProperty,
60 &CellularCapabilityGSM::SimLockStatusToProperty,
61 NULL);
Darin Petkov3cfbf212011-11-21 16:02:09 +010062 store->RegisterConstStringmaps(flimflam::kCellularApnListProperty,
63 &apn_list_);
Darin Petkov0d06f7d2012-02-03 13:08:19 +010064 scanning_supported_ = true;
Darin Petkov1272a432011-11-10 15:53:37 +010065}
Darin Petkovdaf43862011-10-27 11:37:28 +020066
Darin Petkov721ac932011-11-16 15:43:09 +010067StrIntPair CellularCapabilityGSM::SimLockStatusToProperty(Error */*error*/) {
68 return StrIntPair(make_pair(flimflam::kSIMLockTypeProperty,
69 sim_lock_status_.lock_type),
70 make_pair(flimflam::kSIMLockRetriesLeftProperty,
71 sim_lock_status_.retries_left));
72}
73
74void CellularCapabilityGSM::HelpRegisterDerivedStrIntPair(
75 const string &name,
76 StrIntPair(CellularCapabilityGSM::*get)(Error *),
77 void(CellularCapabilityGSM::*set)(const StrIntPair &, Error *)) {
78 cellular()->mutable_store()->RegisterDerivedStrIntPair(
79 name,
80 StrIntPairAccessor(
81 new CustomAccessor<CellularCapabilityGSM, StrIntPair>(
82 this, get, set)));
83}
84
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050085void CellularCapabilityGSM::StartModem()
86{
87 CellularCapability::StartModem();
Darin Petkovcb547732011-11-09 13:55:26 +010088 card_proxy_.reset(
89 proxy_factory()->CreateModemGSMCardProxy(this,
Darin Petkovdaf43862011-10-27 11:37:28 +020090 cellular()->dbus_path(),
91 cellular()->dbus_owner()));
Darin Petkov184c54e2011-11-15 12:44:39 +010092 network_proxy_.reset(
93 proxy_factory()->CreateModemGSMNetworkProxy(this,
Darin Petkovdaf43862011-10-27 11:37:28 +020094 cellular()->dbus_path(),
95 cellular()->dbus_owner()));
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050096 MultiStepAsyncCallHandler *call_handler =
97 new MultiStepAsyncCallHandler(cellular()->dispatcher());
98 call_handler->AddTask(task_factory_.NewRunnableMethod(
99 &CellularCapabilityGSM::EnableModem, call_handler));
100
101 call_handler->AddTask(task_factory_.NewRunnableMethod(
102 &CellularCapabilityGSM::Register, call_handler));
103
104 call_handler->AddTask(task_factory_.NewRunnableMethod(
105 &CellularCapabilityGSM::GetModemStatus, call_handler));
106
107 call_handler->AddTask(task_factory_.NewRunnableMethod(
108 &CellularCapabilityGSM::GetIMEI, call_handler));
109
110 call_handler->AddTask(task_factory_.NewRunnableMethod(
111 &CellularCapabilityGSM::GetIMSI, call_handler));
112
113 call_handler->AddTask(task_factory_.NewRunnableMethod(
114 &CellularCapabilityGSM::GetSPN, call_handler));
115
116 call_handler->AddTask(task_factory_.NewRunnableMethod(
117 &CellularCapabilityGSM::GetMSISDN, call_handler));
118
119 call_handler->AddTask(task_factory_.NewRunnableMethod(
120 &CellularCapabilityGSM::GetProperties, call_handler));
121
122 call_handler->AddTask(task_factory_.NewRunnableMethod(
123 &CellularCapabilityGSM::GetModemInfo, call_handler));
124
125 call_handler->AddTask(task_factory_.NewRunnableMethod(
126 &CellularCapabilityGSM::GetRegistrationState,
127 call_handler));
128 call_handler->PostNextTask();
Darin Petkovdaf43862011-10-27 11:37:28 +0200129}
130
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500131void CellularCapabilityGSM::StopModem() {
Darin Petkov721ac932011-11-16 15:43:09 +0100132 VLOG(2) << __func__;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500133 CellularCapability::StopModem();
Darin Petkov721ac932011-11-16 15:43:09 +0100134 card_proxy_.reset();
135 network_proxy_.reset();
136}
137
Darin Petkov5f316f62011-11-18 12:10:26 +0100138void CellularCapabilityGSM::OnServiceCreated() {
Darin Petkov31332412012-01-28 01:50:02 +0100139 // If IMSI is available, base the service's storage identifier on it.
140 if (!imsi_.empty()) {
141 cellular()->service()->SetStorageIdentifier(
142 "cellular_" + cellular()->address() + "_" + imsi_);
143 }
Darin Petkovb9c99332012-01-12 13:13:00 +0100144 cellular()->service()->SetActivationState(
Darin Petkov5f316f62011-11-18 12:10:26 +0100145 flimflam::kActivationStateActivated);
146 UpdateServingOperator();
147}
148
Darin Petkovae0c64e2011-11-15 15:50:27 +0100149void CellularCapabilityGSM::UpdateStatus(const DBusPropertiesMap &properties) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500150 if (ContainsKey(properties, kPropertyIMSI)) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100151 SetHomeProvider();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100152 }
153}
154
155void CellularCapabilityGSM::SetupConnectProperties(
156 DBusPropertiesMap *properties) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500157 (*properties)[kConnectPropertyPhoneNumber].writer().append_string(
Darin Petkovae0c64e2011-11-15 15:50:27 +0100158 kPhoneNumber);
159 // TODO(petkov): Setup apn and "home_only".
160}
161
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500162void CellularCapabilityGSM::GetIMEI(AsyncCallHandler *call_handler){
Darin Petkovcb547732011-11-09 13:55:26 +0100163 VLOG(2) << __func__;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500164 if (imei_.empty()) {
165 card_proxy_->GetIMEI(call_handler, kTimeoutDefault);
166 } else {
167 VLOG(2) << "Already have IMEI " << imei_;
168 CompleteOperation(call_handler);
Darin Petkovcb547732011-11-09 13:55:26 +0100169 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500170}
171
172void CellularCapabilityGSM::GetIMSI(AsyncCallHandler *call_handler){
173 VLOG(2) << __func__;
174 if (imsi_.empty()) {
175 card_proxy_->GetIMSI(call_handler, kTimeoutDefault);
176 } else {
177 VLOG(2) << "Already have IMSI " << imsi_;
178 CompleteOperation(call_handler);
Darin Petkovcb547732011-11-09 13:55:26 +0100179 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500180}
181
182void CellularCapabilityGSM::GetSPN(AsyncCallHandler *call_handler){
183 VLOG(2) << __func__;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100184 if (spn_.empty()) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500185 card_proxy_->GetSPN(call_handler, kTimeoutDefault);
186 } else {
187 VLOG(2) << "Already have SPN " << spn_;
188 CompleteOperation(call_handler);
Darin Petkovcb547732011-11-09 13:55:26 +0100189 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500190}
191
192void CellularCapabilityGSM::GetMSISDN(AsyncCallHandler *call_handler){
193 VLOG(2) << __func__;
194 if (mdn_.empty()) {
195 card_proxy_->GetMSISDN(call_handler, kTimeoutDefault);
196 } else {
197 VLOG(2) << "Already have MSISDN " << mdn_;
198 CompleteOperation(call_handler);
Darin Petkovcb547732011-11-09 13:55:26 +0100199 }
200}
201
Darin Petkov3e509242011-11-10 14:46:44 +0100202void CellularCapabilityGSM::GetSignalQuality() {
203 VLOG(2) << __func__;
204 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkov184c54e2011-11-15 12:44:39 +0100205 uint32 strength = network_proxy_->GetSignalQuality();
Darin Petkov3e509242011-11-10 14:46:44 +0100206 cellular()->HandleNewSignalQuality(strength);
207}
208
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500209void CellularCapabilityGSM::GetRegistrationState(
210 AsyncCallHandler *call_handler) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100211 VLOG(2) << __func__;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500212 network_proxy_->GetRegistrationInfo(call_handler, kTimeoutDefault);
Darin Petkov184c54e2011-11-15 12:44:39 +0100213}
214
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500215void CellularCapabilityGSM::GetProperties(AsyncCallHandler *call_handler) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100216 VLOG(2) << __func__;
217 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
218 uint32 tech = network_proxy_->AccessTechnology();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100219 SetAccessTechnology(tech);
Darin Petkov184c54e2011-11-15 12:44:39 +0100220 VLOG(2) << "GSM AccessTechnology: " << tech;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500221 CompleteOperation(call_handler);
Darin Petkov184c54e2011-11-15 12:44:39 +0100222}
223
Darin Petkovac635a82012-01-10 16:51:58 +0100224string CellularCapabilityGSM::CreateFriendlyServiceName() {
225 VLOG(2) << __func__;
226 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME &&
227 !cellular()->home_provider().GetName().empty()) {
228 return cellular()->home_provider().GetName();
229 }
230 if (!serving_operator_.GetName().empty()) {
231 return serving_operator_.GetName();
232 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500233 if (!carrier_.empty()) {
234 return carrier_;
Darin Petkovac635a82012-01-10 16:51:58 +0100235 }
236 if (!serving_operator_.GetCode().empty()) {
237 return "cellular_" + serving_operator_.GetCode();
238 }
239 return base::StringPrintf("GSMNetwork%u", friendly_service_name_id_++);
240}
241
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100242void CellularCapabilityGSM::SetHomeProvider() {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500243 VLOG(2) << __func__ << "(IMSI: " << imsi_
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100244 << " SPN: " << spn_ << ")";
245 // TODO(petkov): The test for NULL provider_db should be done by
246 // mobile_provider_lookup_best_match.
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500247 if (imsi_.empty() || !cellular()->provider_db()) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100248 return;
249 }
250 mobile_provider *provider =
251 mobile_provider_lookup_best_match(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500252 cellular()->provider_db(), spn_.c_str(), imsi_.c_str());
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100253 if (!provider) {
254 VLOG(2) << "GSM provider not found.";
255 return;
256 }
257 home_provider_ = provider;
258 Cellular::Operator oper;
259 if (provider->networks) {
260 oper.SetCode(provider->networks[0]);
261 }
262 if (provider->country) {
263 oper.SetCountry(provider->country);
264 }
265 if (spn_.empty()) {
266 const char *name = mobile_provider_get_name(provider);
267 if (name) {
268 oper.SetName(name);
269 }
270 } else {
271 oper.SetName(spn_);
272 }
273 cellular()->set_home_provider(oper);
Darin Petkov3cfbf212011-11-21 16:02:09 +0100274 InitAPNList();
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100275}
276
Darin Petkovae0c64e2011-11-15 15:50:27 +0100277void CellularCapabilityGSM::UpdateOperatorInfo() {
278 VLOG(2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100279 const string &network_id = serving_operator_.GetCode();
280 if (!network_id.empty()) {
281 VLOG(2) << "Looking up network id: " << network_id;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100282 mobile_provider *provider =
283 mobile_provider_lookup_by_network(cellular()->provider_db(),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100284 network_id.c_str());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100285 if (provider) {
286 const char *provider_name = mobile_provider_get_name(provider);
287 if (provider_name && *provider_name) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100288 serving_operator_.SetName(provider_name);
289 if (provider->country) {
290 serving_operator_.SetCountry(provider->country);
291 }
292 VLOG(2) << "Operator name: " << serving_operator_.GetName()
293 << ", country: " << serving_operator_.GetCountry();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100294 }
295 } else {
296 VLOG(2) << "GSM provider not found.";
297 }
298 }
299 UpdateServingOperator();
300}
301
302void CellularCapabilityGSM::UpdateServingOperator() {
303 VLOG(2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100304 if (cellular()->service().get()) {
Darin Petkov9cb02682012-01-28 00:17:38 +0100305 cellular()->service()->SetServingOperator(serving_operator_);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100306 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100307}
308
Darin Petkov3cfbf212011-11-21 16:02:09 +0100309void CellularCapabilityGSM::InitAPNList() {
310 VLOG(2) << __func__;
311 if (!home_provider_) {
312 return;
313 }
314 apn_list_.clear();
315 for (int i = 0; i < home_provider_->num_apns; ++i) {
316 Stringmap props;
317 mobile_apn *apn = home_provider_->apns[i];
318 if (apn->value) {
319 props[flimflam::kApnProperty] = apn->value;
320 }
321 if (apn->username) {
322 props[flimflam::kApnUsernameProperty] = apn->username;
323 }
324 if (apn->password) {
325 props[flimflam::kApnPasswordProperty] = apn->password;
326 }
327 // Find the first localized and non-localized name, if any.
328 const localized_name *lname = NULL;
329 const localized_name *name = NULL;
330 for (int j = 0; j < apn->num_names; ++j) {
331 if (apn->names[j]->lang) {
332 if (!lname) {
333 lname = apn->names[j];
334 }
335 } else if (!name) {
336 name = apn->names[j];
337 }
338 }
339 if (name) {
340 props[flimflam::kApnNameProperty] = name->name;
341 }
342 if (lname) {
343 props[flimflam::kApnLocalizedNameProperty] = lname->name;
344 props[flimflam::kApnLanguageProperty] = lname->lang;
345 }
346 apn_list_.push_back(props);
347 }
348 cellular()->adaptor()->EmitStringmapsChanged(
349 flimflam::kCellularApnListProperty, apn_list_);
350}
351
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500352void CellularCapabilityGSM::Register(AsyncCallHandler *call_handler) {
353 VLOG(2) << __func__ << " \"" << selected_network_ << "\"";
354 network_proxy_->Register(selected_network_, call_handler,
355 kTimeoutRegister);
Darin Petkov184c54e2011-11-15 12:44:39 +0100356}
357
358void CellularCapabilityGSM::RegisterOnNetwork(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500359 const string &network_id, AsyncCallHandler *call_handler) {
360 VLOG(2) << __func__ << "(" << network_id << ")";
361 desired_network_ = network_id;
362 network_proxy_->Register(network_id, call_handler,
363 kTimeoutRegister);
364}
365
366void CellularCapabilityGSM::OnRegisterCallback(const Error &error,
367 AsyncCallHandler *call_handler) {
368 VLOG(2) << __func__ << "(" << error << ")";
369
370 if (error.IsSuccess()) {
371 selected_network_ = desired_network_;
372 desired_network_.clear();
373 CompleteOperation(call_handler);
374 return;
375 }
376 // If registration on the desired network failed,
377 // try to register on the home network.
378 if (!desired_network_.empty()) {
379 desired_network_.clear();
380 selected_network_.clear();
381 Register(call_handler);
382 return;
383 }
384 CompleteOperation(call_handler, error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100385}
386
Darin Petkovb72cf402011-11-22 14:51:39 +0100387bool CellularCapabilityGSM::IsRegistered() {
388 return (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
389 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING);
390}
391
Darin Petkovb05315f2011-11-07 10:14:25 +0100392void CellularCapabilityGSM::RequirePIN(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500393 const string &pin, bool require, AsyncCallHandler *call_handler) {
394 VLOG(2) << __func__ << "(" << call_handler << ")";
395 card_proxy_->EnablePIN(pin, require, call_handler, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100396}
397
Darin Petkove5bc2cb2011-12-07 14:47:32 +0100398void CellularCapabilityGSM::EnterPIN(const string &pin,
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500399 AsyncCallHandler *call_handler) {
400 VLOG(2) << __func__ << "(" << call_handler << ")";
401 card_proxy_->SendPIN(pin, call_handler, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100402}
403
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100404void CellularCapabilityGSM::UnblockPIN(const string &unblock_code,
405 const string &pin,
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500406 AsyncCallHandler *call_handler) {
407 VLOG(2) << __func__ << "(" << call_handler << ")";
408 card_proxy_->SendPUK(unblock_code, pin, call_handler,
409 kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100410}
411
412void CellularCapabilityGSM::ChangePIN(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500413 const string &old_pin, const string &new_pin,
414 AsyncCallHandler *call_handler) {
415 VLOG(2) << __func__ << "(" << call_handler << ")";
416 card_proxy_->ChangePIN(old_pin, new_pin, call_handler,
417 kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100418}
419
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500420void CellularCapabilityGSM::Scan(AsyncCallHandler *call_handler) {
Darin Petkov1272a432011-11-10 15:53:37 +0100421 VLOG(2) << __func__;
422 // TODO(petkov): Defer scan requests if a scan is in progress already.
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500423 network_proxy_->Scan(call_handler, kTimeoutScan);
Darin Petkov1272a432011-11-10 15:53:37 +0100424}
425
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500426void CellularCapabilityGSM::OnScanCallback(const GSMScanResults &results,
427 const Error &error,
428 AsyncCallHandler *call_handler) {
429 VLOG(2) << __func__;
430 if (error.IsFailure()) {
431 CompleteOperation(call_handler, error);
432 return;
433 }
434 found_networks_.clear();
435 for (GSMScanResults::const_iterator it = results.begin();
436 it != results.end(); ++it) {
437 found_networks_.push_back(ParseScanResult(*it));
438 }
Darin Petkovb7828b02012-02-03 12:34:30 +0100439 cellular()->adaptor()->EmitStringmapsChanged(flimflam::kFoundNetworksProperty,
440 found_networks_);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500441 CompleteOperation(call_handler);
442}
443
444Stringmap CellularCapabilityGSM::ParseScanResult(const GSMScanResult &result) {
Darin Petkov1272a432011-11-10 15:53:37 +0100445 Stringmap parsed;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500446 for (GSMScanResult::const_iterator it = result.begin();
447 it != result.end(); ++it) {
Darin Petkov1272a432011-11-10 15:53:37 +0100448 // TODO(petkov): Define these in system_api/service_constants.h. The
449 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
450 static const char * const kStatusString[] = {
451 "unknown",
452 "available",
453 "current",
454 "forbidden",
455 };
456 static const char * const kTechnologyString[] = {
457 flimflam::kNetworkTechnologyGsm,
458 "GSM Compact",
459 flimflam::kNetworkTechnologyUmts,
460 flimflam::kNetworkTechnologyEdge,
461 "HSDPA",
462 "HSUPA",
463 flimflam::kNetworkTechnologyHspa,
464 };
465 VLOG(2) << "Network property: " << it->first << " = " << it->second;
466 if (it->first == kNetworkPropertyStatus) {
467 int status = 0;
468 if (base::StringToInt(it->second, &status) &&
469 status >= 0 &&
470 status < static_cast<int>(arraysize(kStatusString))) {
471 parsed[flimflam::kStatusProperty] = kStatusString[status];
472 } else {
473 LOG(ERROR) << "Unexpected status value: " << it->second;
474 }
475 } else if (it->first == kNetworkPropertyID) {
476 parsed[flimflam::kNetworkIdProperty] = it->second;
477 } else if (it->first == kNetworkPropertyLongName) {
478 parsed[flimflam::kLongNameProperty] = it->second;
479 } else if (it->first == kNetworkPropertyShortName) {
480 parsed[flimflam::kShortNameProperty] = it->second;
481 } else if (it->first == kNetworkPropertyAccessTechnology) {
482 int tech = 0;
483 if (base::StringToInt(it->second, &tech) &&
484 tech >= 0 &&
485 tech < static_cast<int>(arraysize(kTechnologyString))) {
486 parsed[flimflam::kTechnologyProperty] = kTechnologyString[tech];
487 } else {
488 LOG(ERROR) << "Unexpected technology value: " << it->second;
489 }
490 } else {
491 LOG(WARNING) << "Unknown network property ignored: " << it->first;
492 }
493 }
494 // If the long name is not available but the network ID is, look up the long
495 // name in the mobile provider database.
496 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
497 parsed[flimflam::kLongNameProperty].empty()) &&
498 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
499 mobile_provider *provider =
500 mobile_provider_lookup_by_network(
501 cellular()->provider_db(),
502 parsed[flimflam::kNetworkIdProperty].c_str());
503 if (provider) {
504 const char *long_name = mobile_provider_get_name(provider);
505 if (long_name && *long_name) {
506 parsed[flimflam::kLongNameProperty] = long_name;
507 }
508 }
509 }
510 return parsed;
511}
512
Darin Petkovae0c64e2011-11-15 15:50:27 +0100513void CellularCapabilityGSM::SetAccessTechnology(uint32 access_technology) {
514 access_technology_ = access_technology;
515 if (cellular()->service().get()) {
Darin Petkovb72cf402011-11-22 14:51:39 +0100516 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100517 }
518}
519
Darin Petkov20c13ec2011-11-09 15:07:15 +0100520string CellularCapabilityGSM::GetNetworkTechnologyString() const {
Darin Petkovb72cf402011-11-22 14:51:39 +0100521 switch (access_technology_) {
522 case MM_MODEM_GSM_ACCESS_TECH_GSM:
523 case MM_MODEM_GSM_ACCESS_TECH_GSM_COMPACT:
524 return flimflam::kNetworkTechnologyGsm;
525 case MM_MODEM_GSM_ACCESS_TECH_GPRS:
526 return flimflam::kNetworkTechnologyGprs;
527 case MM_MODEM_GSM_ACCESS_TECH_EDGE:
528 return flimflam::kNetworkTechnologyEdge;
529 case MM_MODEM_GSM_ACCESS_TECH_UMTS:
530 return flimflam::kNetworkTechnologyUmts;
531 case MM_MODEM_GSM_ACCESS_TECH_HSDPA:
532 case MM_MODEM_GSM_ACCESS_TECH_HSUPA:
533 case MM_MODEM_GSM_ACCESS_TECH_HSPA:
534 return flimflam::kNetworkTechnologyHspa;
535 case MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS:
536 return flimflam::kNetworkTechnologyHspaPlus;
537 default:
538 break;
Darin Petkov20c13ec2011-11-09 15:07:15 +0100539 }
540 return "";
541}
542
543string CellularCapabilityGSM::GetRoamingStateString() const {
Darin Petkov184c54e2011-11-15 12:44:39 +0100544 switch (registration_state_) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100545 case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME:
546 return flimflam::kRoamingStateHome;
547 case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING:
548 return flimflam::kRoamingStateRoaming;
549 default:
550 break;
551 }
552 return flimflam::kRoamingStateUnknown;
553}
554
Darin Petkovae0c64e2011-11-15 15:50:27 +0100555void CellularCapabilityGSM::OnModemManagerPropertiesChanged(
556 const DBusPropertiesMap &properties) {
557 uint32 access_technology = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
558 if (DBusProperties::GetUint32(properties,
559 kPropertyAccessTechnology,
560 &access_technology)) {
561 SetAccessTechnology(access_technology);
562 }
Darin Petkov721ac932011-11-16 15:43:09 +0100563 DBusProperties::GetString(
564 properties, kPropertyUnlockRequired, &sim_lock_status_.lock_type);
565 DBusProperties::GetUint32(
566 properties, kPropertyUnlockRetries, &sim_lock_status_.retries_left);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100567}
568
Darin Petkov184c54e2011-11-15 12:44:39 +0100569void CellularCapabilityGSM::OnGSMNetworkModeChanged(uint32 /*mode*/) {
570 // TODO(petkov): Implement this.
571 NOTIMPLEMENTED();
572}
573
574void CellularCapabilityGSM::OnGSMRegistrationInfoChanged(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500575 uint32 status, const string &operator_code, const string &operator_name,
576 const Error &error, AsyncCallHandler *call_handler) {
577 if (error.IsSuccess()) {
578 VLOG(2) << __func__ << ": regstate=" << status
579 << ", opercode=" << operator_code
580 << ", opername=" << operator_name;
581 registration_state_ = status;
582 serving_operator_.SetCode(operator_code);
583 serving_operator_.SetName(operator_name);
584 UpdateOperatorInfo();
585 cellular()->HandleNewRegistrationState();
586 }
587 CompleteOperation(call_handler, error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100588}
589
590void CellularCapabilityGSM::OnGSMSignalQualityChanged(uint32 quality) {
591 cellular()->HandleNewSignalQuality(quality);
592}
593
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500594void CellularCapabilityGSM::OnGetIMEICallback(const string &imei,
595 const Error &error,
596 AsyncCallHandler *call_handler) {
597 if (error.IsSuccess()) {
598 VLOG(2) << "IMEI: " << imei;
599 imei_ = imei;
600 } else {
601 VLOG(2) << "GetIMEI failed - " << error;
602 }
603 CompleteOperation(call_handler, error);
604}
605
606void CellularCapabilityGSM::OnGetIMSICallback(const string &imsi,
607 const Error &error,
608 AsyncCallHandler *call_handler) {
609 if (error.IsSuccess()) {
610 VLOG(2) << "IMSI: " << imsi;
611 imsi_ = imsi;
612 SetHomeProvider();
613 } else {
614 VLOG(2) << "GetIMSI failed - " << error;
615 }
616 CompleteOperation(call_handler, error);
617}
618
619void CellularCapabilityGSM::OnGetSPNCallback(const string &spn,
620 const Error &error,
621 AsyncCallHandler *call_handler) {
622 if (error.IsSuccess()) {
623 VLOG(2) << "SPN: " << spn;
624 spn_ = spn;
625 SetHomeProvider();
626 } else {
627 VLOG(2) << "GetSPN failed - " << error;
628 }
629 // Ignore the error - it's not fatal.
630 CompleteOperation(call_handler);
631}
632
633void CellularCapabilityGSM::OnGetMSISDNCallback(
634 const string &msisdn, const Error &error, AsyncCallHandler *call_handler) {
635 if (error.IsSuccess()) {
636 VLOG(2) << "MSISDN: " << msisdn;
637 mdn_ = msisdn;
638 } else {
639 VLOG(2) << "GetMSISDN failed - " << error;
640 }
641 // Ignore the error - it's not fatal.
642 CompleteOperation(call_handler);
643}
644
645void CellularCapabilityGSM::OnPINOperationCallback(
646 const Error &error, AsyncCallHandler *call_handler) {
647 if (error.IsFailure())
648 VLOG(2) << "PIN operation failed - " << error;
649 else
650 VLOG(2) << "PIN operation complete";
651 CompleteOperation(call_handler, error);
652}
653
Darin Petkovdaf43862011-10-27 11:37:28 +0200654} // namespace shill