blob: 1ef2d432d8114db18d414b205bcc4efb4f2719ba [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 Petkov1272a432011-11-10 15:53:37 +010064}
Darin Petkovdaf43862011-10-27 11:37:28 +020065
Darin Petkov721ac932011-11-16 15:43:09 +010066StrIntPair CellularCapabilityGSM::SimLockStatusToProperty(Error */*error*/) {
67 return StrIntPair(make_pair(flimflam::kSIMLockTypeProperty,
68 sim_lock_status_.lock_type),
69 make_pair(flimflam::kSIMLockRetriesLeftProperty,
70 sim_lock_status_.retries_left));
71}
72
73void CellularCapabilityGSM::HelpRegisterDerivedStrIntPair(
74 const string &name,
75 StrIntPair(CellularCapabilityGSM::*get)(Error *),
76 void(CellularCapabilityGSM::*set)(const StrIntPair &, Error *)) {
77 cellular()->mutable_store()->RegisterDerivedStrIntPair(
78 name,
79 StrIntPairAccessor(
80 new CustomAccessor<CellularCapabilityGSM, StrIntPair>(
81 this, get, set)));
82}
83
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050084void CellularCapabilityGSM::StartModem()
85{
86 CellularCapability::StartModem();
Darin Petkovcb547732011-11-09 13:55:26 +010087 card_proxy_.reset(
88 proxy_factory()->CreateModemGSMCardProxy(this,
Darin Petkovdaf43862011-10-27 11:37:28 +020089 cellular()->dbus_path(),
90 cellular()->dbus_owner()));
Darin Petkov184c54e2011-11-15 12:44:39 +010091 network_proxy_.reset(
92 proxy_factory()->CreateModemGSMNetworkProxy(this,
Darin Petkovdaf43862011-10-27 11:37:28 +020093 cellular()->dbus_path(),
94 cellular()->dbus_owner()));
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050095 MultiStepAsyncCallHandler *call_handler =
96 new MultiStepAsyncCallHandler(cellular()->dispatcher());
97 call_handler->AddTask(task_factory_.NewRunnableMethod(
98 &CellularCapabilityGSM::EnableModem, call_handler));
99
100 call_handler->AddTask(task_factory_.NewRunnableMethod(
101 &CellularCapabilityGSM::Register, call_handler));
102
103 call_handler->AddTask(task_factory_.NewRunnableMethod(
104 &CellularCapabilityGSM::GetModemStatus, call_handler));
105
106 call_handler->AddTask(task_factory_.NewRunnableMethod(
107 &CellularCapabilityGSM::GetIMEI, call_handler));
108
109 call_handler->AddTask(task_factory_.NewRunnableMethod(
110 &CellularCapabilityGSM::GetIMSI, call_handler));
111
112 call_handler->AddTask(task_factory_.NewRunnableMethod(
113 &CellularCapabilityGSM::GetSPN, call_handler));
114
115 call_handler->AddTask(task_factory_.NewRunnableMethod(
116 &CellularCapabilityGSM::GetMSISDN, call_handler));
117
118 call_handler->AddTask(task_factory_.NewRunnableMethod(
119 &CellularCapabilityGSM::GetProperties, call_handler));
120
121 call_handler->AddTask(task_factory_.NewRunnableMethod(
122 &CellularCapabilityGSM::GetModemInfo, call_handler));
123
124 call_handler->AddTask(task_factory_.NewRunnableMethod(
125 &CellularCapabilityGSM::GetRegistrationState,
126 call_handler));
127 call_handler->PostNextTask();
Darin Petkovdaf43862011-10-27 11:37:28 +0200128}
129
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500130void CellularCapabilityGSM::StopModem() {
Darin Petkov721ac932011-11-16 15:43:09 +0100131 VLOG(2) << __func__;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500132 CellularCapability::StopModem();
Darin Petkov721ac932011-11-16 15:43:09 +0100133 card_proxy_.reset();
134 network_proxy_.reset();
135}
136
Darin Petkov5f316f62011-11-18 12:10:26 +0100137void CellularCapabilityGSM::OnServiceCreated() {
Darin Petkov31332412012-01-28 01:50:02 +0100138 // If IMSI is available, base the service's storage identifier on it.
139 if (!imsi_.empty()) {
140 cellular()->service()->SetStorageIdentifier(
141 "cellular_" + cellular()->address() + "_" + imsi_);
142 }
Darin Petkovb9c99332012-01-12 13:13:00 +0100143 cellular()->service()->SetActivationState(
Darin Petkov5f316f62011-11-18 12:10:26 +0100144 flimflam::kActivationStateActivated);
145 UpdateServingOperator();
146}
147
Darin Petkovae0c64e2011-11-15 15:50:27 +0100148void CellularCapabilityGSM::UpdateStatus(const DBusPropertiesMap &properties) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500149 if (ContainsKey(properties, kPropertyIMSI)) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100150 SetHomeProvider();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100151 }
152}
153
154void CellularCapabilityGSM::SetupConnectProperties(
155 DBusPropertiesMap *properties) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500156 (*properties)[kConnectPropertyPhoneNumber].writer().append_string(
Darin Petkovae0c64e2011-11-15 15:50:27 +0100157 kPhoneNumber);
158 // TODO(petkov): Setup apn and "home_only".
159}
160
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500161void CellularCapabilityGSM::GetIMEI(AsyncCallHandler *call_handler){
Darin Petkovcb547732011-11-09 13:55:26 +0100162 VLOG(2) << __func__;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500163 if (imei_.empty()) {
164 card_proxy_->GetIMEI(call_handler, kTimeoutDefault);
165 } else {
166 VLOG(2) << "Already have IMEI " << imei_;
167 CompleteOperation(call_handler);
Darin Petkovcb547732011-11-09 13:55:26 +0100168 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500169}
170
171void CellularCapabilityGSM::GetIMSI(AsyncCallHandler *call_handler){
172 VLOG(2) << __func__;
173 if (imsi_.empty()) {
174 card_proxy_->GetIMSI(call_handler, kTimeoutDefault);
175 } else {
176 VLOG(2) << "Already have IMSI " << imsi_;
177 CompleteOperation(call_handler);
Darin Petkovcb547732011-11-09 13:55:26 +0100178 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500179}
180
181void CellularCapabilityGSM::GetSPN(AsyncCallHandler *call_handler){
182 VLOG(2) << __func__;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100183 if (spn_.empty()) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500184 card_proxy_->GetSPN(call_handler, kTimeoutDefault);
185 } else {
186 VLOG(2) << "Already have SPN " << spn_;
187 CompleteOperation(call_handler);
Darin Petkovcb547732011-11-09 13:55:26 +0100188 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500189}
190
191void CellularCapabilityGSM::GetMSISDN(AsyncCallHandler *call_handler){
192 VLOG(2) << __func__;
193 if (mdn_.empty()) {
194 card_proxy_->GetMSISDN(call_handler, kTimeoutDefault);
195 } else {
196 VLOG(2) << "Already have MSISDN " << mdn_;
197 CompleteOperation(call_handler);
Darin Petkovcb547732011-11-09 13:55:26 +0100198 }
199}
200
Darin Petkov3e509242011-11-10 14:46:44 +0100201void CellularCapabilityGSM::GetSignalQuality() {
202 VLOG(2) << __func__;
203 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkov184c54e2011-11-15 12:44:39 +0100204 uint32 strength = network_proxy_->GetSignalQuality();
Darin Petkov3e509242011-11-10 14:46:44 +0100205 cellular()->HandleNewSignalQuality(strength);
206}
207
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500208void CellularCapabilityGSM::GetRegistrationState(
209 AsyncCallHandler *call_handler) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100210 VLOG(2) << __func__;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500211 network_proxy_->GetRegistrationInfo(call_handler, kTimeoutDefault);
Darin Petkov184c54e2011-11-15 12:44:39 +0100212}
213
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500214void CellularCapabilityGSM::GetProperties(AsyncCallHandler *call_handler) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100215 VLOG(2) << __func__;
216 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
217 uint32 tech = network_proxy_->AccessTechnology();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100218 SetAccessTechnology(tech);
Darin Petkov184c54e2011-11-15 12:44:39 +0100219 VLOG(2) << "GSM AccessTechnology: " << tech;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500220 CompleteOperation(call_handler);
Darin Petkov184c54e2011-11-15 12:44:39 +0100221}
222
Darin Petkovac635a82012-01-10 16:51:58 +0100223string CellularCapabilityGSM::CreateFriendlyServiceName() {
224 VLOG(2) << __func__;
225 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME &&
226 !cellular()->home_provider().GetName().empty()) {
227 return cellular()->home_provider().GetName();
228 }
229 if (!serving_operator_.GetName().empty()) {
230 return serving_operator_.GetName();
231 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500232 if (!carrier_.empty()) {
233 return carrier_;
Darin Petkovac635a82012-01-10 16:51:58 +0100234 }
235 if (!serving_operator_.GetCode().empty()) {
236 return "cellular_" + serving_operator_.GetCode();
237 }
238 return base::StringPrintf("GSMNetwork%u", friendly_service_name_id_++);
239}
240
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100241void CellularCapabilityGSM::SetHomeProvider() {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500242 VLOG(2) << __func__ << "(IMSI: " << imsi_
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100243 << " SPN: " << spn_ << ")";
244 // TODO(petkov): The test for NULL provider_db should be done by
245 // mobile_provider_lookup_best_match.
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500246 if (imsi_.empty() || !cellular()->provider_db()) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100247 return;
248 }
249 mobile_provider *provider =
250 mobile_provider_lookup_best_match(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500251 cellular()->provider_db(), spn_.c_str(), imsi_.c_str());
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100252 if (!provider) {
253 VLOG(2) << "GSM provider not found.";
254 return;
255 }
256 home_provider_ = provider;
257 Cellular::Operator oper;
258 if (provider->networks) {
259 oper.SetCode(provider->networks[0]);
260 }
261 if (provider->country) {
262 oper.SetCountry(provider->country);
263 }
264 if (spn_.empty()) {
265 const char *name = mobile_provider_get_name(provider);
266 if (name) {
267 oper.SetName(name);
268 }
269 } else {
270 oper.SetName(spn_);
271 }
272 cellular()->set_home_provider(oper);
Darin Petkov3cfbf212011-11-21 16:02:09 +0100273 InitAPNList();
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100274}
275
Darin Petkovae0c64e2011-11-15 15:50:27 +0100276void CellularCapabilityGSM::UpdateOperatorInfo() {
277 VLOG(2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100278 const string &network_id = serving_operator_.GetCode();
279 if (!network_id.empty()) {
280 VLOG(2) << "Looking up network id: " << network_id;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100281 mobile_provider *provider =
282 mobile_provider_lookup_by_network(cellular()->provider_db(),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100283 network_id.c_str());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100284 if (provider) {
285 const char *provider_name = mobile_provider_get_name(provider);
286 if (provider_name && *provider_name) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100287 serving_operator_.SetName(provider_name);
288 if (provider->country) {
289 serving_operator_.SetCountry(provider->country);
290 }
291 VLOG(2) << "Operator name: " << serving_operator_.GetName()
292 << ", country: " << serving_operator_.GetCountry();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100293 }
294 } else {
295 VLOG(2) << "GSM provider not found.";
296 }
297 }
298 UpdateServingOperator();
299}
300
301void CellularCapabilityGSM::UpdateServingOperator() {
302 VLOG(2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100303 if (cellular()->service().get()) {
Darin Petkov9cb02682012-01-28 00:17:38 +0100304 cellular()->service()->SetServingOperator(serving_operator_);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100305 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100306}
307
Darin Petkov3cfbf212011-11-21 16:02:09 +0100308void CellularCapabilityGSM::InitAPNList() {
309 VLOG(2) << __func__;
310 if (!home_provider_) {
311 return;
312 }
313 apn_list_.clear();
314 for (int i = 0; i < home_provider_->num_apns; ++i) {
315 Stringmap props;
316 mobile_apn *apn = home_provider_->apns[i];
317 if (apn->value) {
318 props[flimflam::kApnProperty] = apn->value;
319 }
320 if (apn->username) {
321 props[flimflam::kApnUsernameProperty] = apn->username;
322 }
323 if (apn->password) {
324 props[flimflam::kApnPasswordProperty] = apn->password;
325 }
326 // Find the first localized and non-localized name, if any.
327 const localized_name *lname = NULL;
328 const localized_name *name = NULL;
329 for (int j = 0; j < apn->num_names; ++j) {
330 if (apn->names[j]->lang) {
331 if (!lname) {
332 lname = apn->names[j];
333 }
334 } else if (!name) {
335 name = apn->names[j];
336 }
337 }
338 if (name) {
339 props[flimflam::kApnNameProperty] = name->name;
340 }
341 if (lname) {
342 props[flimflam::kApnLocalizedNameProperty] = lname->name;
343 props[flimflam::kApnLanguageProperty] = lname->lang;
344 }
345 apn_list_.push_back(props);
346 }
347 cellular()->adaptor()->EmitStringmapsChanged(
348 flimflam::kCellularApnListProperty, apn_list_);
349}
350
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500351void CellularCapabilityGSM::Register(AsyncCallHandler *call_handler) {
352 VLOG(2) << __func__ << " \"" << selected_network_ << "\"";
353 network_proxy_->Register(selected_network_, call_handler,
354 kTimeoutRegister);
Darin Petkov184c54e2011-11-15 12:44:39 +0100355}
356
357void CellularCapabilityGSM::RegisterOnNetwork(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500358 const string &network_id, AsyncCallHandler *call_handler) {
359 VLOG(2) << __func__ << "(" << network_id << ")";
360 desired_network_ = network_id;
361 network_proxy_->Register(network_id, call_handler,
362 kTimeoutRegister);
363}
364
365void CellularCapabilityGSM::OnRegisterCallback(const Error &error,
366 AsyncCallHandler *call_handler) {
367 VLOG(2) << __func__ << "(" << error << ")";
368
369 if (error.IsSuccess()) {
370 selected_network_ = desired_network_;
371 desired_network_.clear();
372 CompleteOperation(call_handler);
373 return;
374 }
375 // If registration on the desired network failed,
376 // try to register on the home network.
377 if (!desired_network_.empty()) {
378 desired_network_.clear();
379 selected_network_.clear();
380 Register(call_handler);
381 return;
382 }
383 CompleteOperation(call_handler, error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100384}
385
Darin Petkovb72cf402011-11-22 14:51:39 +0100386bool CellularCapabilityGSM::IsRegistered() {
387 return (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
388 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING);
389}
390
Darin Petkovb05315f2011-11-07 10:14:25 +0100391void CellularCapabilityGSM::RequirePIN(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500392 const string &pin, bool require, AsyncCallHandler *call_handler) {
393 VLOG(2) << __func__ << "(" << call_handler << ")";
394 card_proxy_->EnablePIN(pin, require, call_handler, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100395}
396
Darin Petkove5bc2cb2011-12-07 14:47:32 +0100397void CellularCapabilityGSM::EnterPIN(const string &pin,
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500398 AsyncCallHandler *call_handler) {
399 VLOG(2) << __func__ << "(" << call_handler << ")";
400 card_proxy_->SendPIN(pin, call_handler, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100401}
402
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100403void CellularCapabilityGSM::UnblockPIN(const string &unblock_code,
404 const string &pin,
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500405 AsyncCallHandler *call_handler) {
406 VLOG(2) << __func__ << "(" << call_handler << ")";
407 card_proxy_->SendPUK(unblock_code, pin, call_handler,
408 kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100409}
410
411void CellularCapabilityGSM::ChangePIN(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500412 const string &old_pin, const string &new_pin,
413 AsyncCallHandler *call_handler) {
414 VLOG(2) << __func__ << "(" << call_handler << ")";
415 card_proxy_->ChangePIN(old_pin, new_pin, call_handler,
416 kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100417}
418
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500419void CellularCapabilityGSM::Scan(AsyncCallHandler *call_handler) {
Darin Petkov1272a432011-11-10 15:53:37 +0100420 VLOG(2) << __func__;
421 // TODO(petkov): Defer scan requests if a scan is in progress already.
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500422 network_proxy_->Scan(call_handler, kTimeoutScan);
Darin Petkov1272a432011-11-10 15:53:37 +0100423}
424
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500425void CellularCapabilityGSM::OnScanCallback(const GSMScanResults &results,
426 const Error &error,
427 AsyncCallHandler *call_handler) {
428 VLOG(2) << __func__;
429 if (error.IsFailure()) {
430 CompleteOperation(call_handler, error);
431 return;
432 }
433 found_networks_.clear();
434 for (GSMScanResults::const_iterator it = results.begin();
435 it != results.end(); ++it) {
436 found_networks_.push_back(ParseScanResult(*it));
437 }
Darin Petkovb7828b02012-02-03 12:34:30 +0100438 cellular()->adaptor()->EmitStringmapsChanged(flimflam::kFoundNetworksProperty,
439 found_networks_);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500440 CompleteOperation(call_handler);
441}
442
443Stringmap CellularCapabilityGSM::ParseScanResult(const GSMScanResult &result) {
Darin Petkov1272a432011-11-10 15:53:37 +0100444 Stringmap parsed;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500445 for (GSMScanResult::const_iterator it = result.begin();
446 it != result.end(); ++it) {
Darin Petkov1272a432011-11-10 15:53:37 +0100447 // TODO(petkov): Define these in system_api/service_constants.h. The
448 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
449 static const char * const kStatusString[] = {
450 "unknown",
451 "available",
452 "current",
453 "forbidden",
454 };
455 static const char * const kTechnologyString[] = {
456 flimflam::kNetworkTechnologyGsm,
457 "GSM Compact",
458 flimflam::kNetworkTechnologyUmts,
459 flimflam::kNetworkTechnologyEdge,
460 "HSDPA",
461 "HSUPA",
462 flimflam::kNetworkTechnologyHspa,
463 };
464 VLOG(2) << "Network property: " << it->first << " = " << it->second;
465 if (it->first == kNetworkPropertyStatus) {
466 int status = 0;
467 if (base::StringToInt(it->second, &status) &&
468 status >= 0 &&
469 status < static_cast<int>(arraysize(kStatusString))) {
470 parsed[flimflam::kStatusProperty] = kStatusString[status];
471 } else {
472 LOG(ERROR) << "Unexpected status value: " << it->second;
473 }
474 } else if (it->first == kNetworkPropertyID) {
475 parsed[flimflam::kNetworkIdProperty] = it->second;
476 } else if (it->first == kNetworkPropertyLongName) {
477 parsed[flimflam::kLongNameProperty] = it->second;
478 } else if (it->first == kNetworkPropertyShortName) {
479 parsed[flimflam::kShortNameProperty] = it->second;
480 } else if (it->first == kNetworkPropertyAccessTechnology) {
481 int tech = 0;
482 if (base::StringToInt(it->second, &tech) &&
483 tech >= 0 &&
484 tech < static_cast<int>(arraysize(kTechnologyString))) {
485 parsed[flimflam::kTechnologyProperty] = kTechnologyString[tech];
486 } else {
487 LOG(ERROR) << "Unexpected technology value: " << it->second;
488 }
489 } else {
490 LOG(WARNING) << "Unknown network property ignored: " << it->first;
491 }
492 }
493 // If the long name is not available but the network ID is, look up the long
494 // name in the mobile provider database.
495 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
496 parsed[flimflam::kLongNameProperty].empty()) &&
497 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
498 mobile_provider *provider =
499 mobile_provider_lookup_by_network(
500 cellular()->provider_db(),
501 parsed[flimflam::kNetworkIdProperty].c_str());
502 if (provider) {
503 const char *long_name = mobile_provider_get_name(provider);
504 if (long_name && *long_name) {
505 parsed[flimflam::kLongNameProperty] = long_name;
506 }
507 }
508 }
509 return parsed;
510}
511
Darin Petkovae0c64e2011-11-15 15:50:27 +0100512void CellularCapabilityGSM::SetAccessTechnology(uint32 access_technology) {
513 access_technology_ = access_technology;
514 if (cellular()->service().get()) {
Darin Petkovb72cf402011-11-22 14:51:39 +0100515 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100516 }
517}
518
Darin Petkov20c13ec2011-11-09 15:07:15 +0100519string CellularCapabilityGSM::GetNetworkTechnologyString() const {
Darin Petkovb72cf402011-11-22 14:51:39 +0100520 switch (access_technology_) {
521 case MM_MODEM_GSM_ACCESS_TECH_GSM:
522 case MM_MODEM_GSM_ACCESS_TECH_GSM_COMPACT:
523 return flimflam::kNetworkTechnologyGsm;
524 case MM_MODEM_GSM_ACCESS_TECH_GPRS:
525 return flimflam::kNetworkTechnologyGprs;
526 case MM_MODEM_GSM_ACCESS_TECH_EDGE:
527 return flimflam::kNetworkTechnologyEdge;
528 case MM_MODEM_GSM_ACCESS_TECH_UMTS:
529 return flimflam::kNetworkTechnologyUmts;
530 case MM_MODEM_GSM_ACCESS_TECH_HSDPA:
531 case MM_MODEM_GSM_ACCESS_TECH_HSUPA:
532 case MM_MODEM_GSM_ACCESS_TECH_HSPA:
533 return flimflam::kNetworkTechnologyHspa;
534 case MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS:
535 return flimflam::kNetworkTechnologyHspaPlus;
536 default:
537 break;
Darin Petkov20c13ec2011-11-09 15:07:15 +0100538 }
539 return "";
540}
541
542string CellularCapabilityGSM::GetRoamingStateString() const {
Darin Petkov184c54e2011-11-15 12:44:39 +0100543 switch (registration_state_) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100544 case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME:
545 return flimflam::kRoamingStateHome;
546 case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING:
547 return flimflam::kRoamingStateRoaming;
548 default:
549 break;
550 }
551 return flimflam::kRoamingStateUnknown;
552}
553
Darin Petkovae0c64e2011-11-15 15:50:27 +0100554void CellularCapabilityGSM::OnModemManagerPropertiesChanged(
555 const DBusPropertiesMap &properties) {
556 uint32 access_technology = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
557 if (DBusProperties::GetUint32(properties,
558 kPropertyAccessTechnology,
559 &access_technology)) {
560 SetAccessTechnology(access_technology);
561 }
Darin Petkov721ac932011-11-16 15:43:09 +0100562 DBusProperties::GetString(
563 properties, kPropertyUnlockRequired, &sim_lock_status_.lock_type);
564 DBusProperties::GetUint32(
565 properties, kPropertyUnlockRetries, &sim_lock_status_.retries_left);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100566}
567
Darin Petkov184c54e2011-11-15 12:44:39 +0100568void CellularCapabilityGSM::OnGSMNetworkModeChanged(uint32 /*mode*/) {
569 // TODO(petkov): Implement this.
570 NOTIMPLEMENTED();
571}
572
573void CellularCapabilityGSM::OnGSMRegistrationInfoChanged(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500574 uint32 status, const string &operator_code, const string &operator_name,
575 const Error &error, AsyncCallHandler *call_handler) {
576 if (error.IsSuccess()) {
577 VLOG(2) << __func__ << ": regstate=" << status
578 << ", opercode=" << operator_code
579 << ", opername=" << operator_name;
580 registration_state_ = status;
581 serving_operator_.SetCode(operator_code);
582 serving_operator_.SetName(operator_name);
583 UpdateOperatorInfo();
584 cellular()->HandleNewRegistrationState();
585 }
586 CompleteOperation(call_handler, error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100587}
588
589void CellularCapabilityGSM::OnGSMSignalQualityChanged(uint32 quality) {
590 cellular()->HandleNewSignalQuality(quality);
591}
592
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500593void CellularCapabilityGSM::OnGetIMEICallback(const string &imei,
594 const Error &error,
595 AsyncCallHandler *call_handler) {
596 if (error.IsSuccess()) {
597 VLOG(2) << "IMEI: " << imei;
598 imei_ = imei;
599 } else {
600 VLOG(2) << "GetIMEI failed - " << error;
601 }
602 CompleteOperation(call_handler, error);
603}
604
605void CellularCapabilityGSM::OnGetIMSICallback(const string &imsi,
606 const Error &error,
607 AsyncCallHandler *call_handler) {
608 if (error.IsSuccess()) {
609 VLOG(2) << "IMSI: " << imsi;
610 imsi_ = imsi;
611 SetHomeProvider();
612 } else {
613 VLOG(2) << "GetIMSI failed - " << error;
614 }
615 CompleteOperation(call_handler, error);
616}
617
618void CellularCapabilityGSM::OnGetSPNCallback(const string &spn,
619 const Error &error,
620 AsyncCallHandler *call_handler) {
621 if (error.IsSuccess()) {
622 VLOG(2) << "SPN: " << spn;
623 spn_ = spn;
624 SetHomeProvider();
625 } else {
626 VLOG(2) << "GetSPN failed - " << error;
627 }
628 // Ignore the error - it's not fatal.
629 CompleteOperation(call_handler);
630}
631
632void CellularCapabilityGSM::OnGetMSISDNCallback(
633 const string &msisdn, const Error &error, AsyncCallHandler *call_handler) {
634 if (error.IsSuccess()) {
635 VLOG(2) << "MSISDN: " << msisdn;
636 mdn_ = msisdn;
637 } else {
638 VLOG(2) << "GetMSISDN failed - " << error;
639 }
640 // Ignore the error - it's not fatal.
641 CompleteOperation(call_handler);
642}
643
644void CellularCapabilityGSM::OnPINOperationCallback(
645 const Error &error, AsyncCallHandler *call_handler) {
646 if (error.IsFailure())
647 VLOG(2) << "PIN operation failed - " << error;
648 else
649 VLOG(2) << "PIN operation complete";
650 CompleteOperation(call_handler, error);
651}
652
Darin Petkovdaf43862011-10-27 11:37:28 +0200653} // namespace shill