blob: d5e25f5e85b876937536354e49591a74cde74f26 [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"
Darin Petkov721ac932011-11-16 15:43:09 +010017#include "shill/property_accessor.h"
Darin Petkovdaf43862011-10-27 11:37:28 +020018#include "shill/proxy_factory.h"
19
Darin Petkov721ac932011-11-16 15:43:09 +010020using std::make_pair;
Darin Petkovb05315f2011-11-07 10:14:25 +010021using std::string;
22
Darin Petkovdaf43862011-10-27 11:37:28 +020023namespace shill {
24
Darin Petkovac635a82012-01-10 16:51:58 +010025// static
26unsigned int CellularCapabilityGSM::friendly_service_name_id_ = 0;
27
Darin Petkov1272a432011-11-10 15:53:37 +010028const char CellularCapabilityGSM::kNetworkPropertyAccessTechnology[] =
29 "access-tech";
30const char CellularCapabilityGSM::kNetworkPropertyID[] = "operator-num";
31const char CellularCapabilityGSM::kNetworkPropertyLongName[] = "operator-long";
32const char CellularCapabilityGSM::kNetworkPropertyShortName[] =
33 "operator-short";
34const char CellularCapabilityGSM::kNetworkPropertyStatus[] = "status";
Darin Petkovae0c64e2011-11-15 15:50:27 +010035const char CellularCapabilityGSM::kPhoneNumber[] = "*99#";
36const char CellularCapabilityGSM::kPropertyAccessTechnology[] =
37 "AccessTechnology";
Darin Petkov721ac932011-11-16 15:43:09 +010038const char CellularCapabilityGSM::kPropertyUnlockRequired[] = "UnlockRequired";
39const char CellularCapabilityGSM::kPropertyUnlockRetries[] = "UnlockRetries";
Darin Petkov1272a432011-11-10 15:53:37 +010040
Darin Petkovdaf43862011-10-27 11:37:28 +020041CellularCapabilityGSM::CellularCapabilityGSM(Cellular *cellular)
Darin Petkovb05315f2011-11-07 10:14:25 +010042 : CellularCapability(cellular),
Darin Petkov1272a432011-11-10 15:53:37 +010043 task_factory_(this),
Darin Petkov184c54e2011-11-15 12:44:39 +010044 registration_state_(MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN),
Darin Petkovae0c64e2011-11-15 15:50:27 +010045 access_technology_(MM_MODEM_GSM_ACCESS_TECH_UNKNOWN),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +010046 home_provider_(NULL),
Darin Petkov1272a432011-11-10 15:53:37 +010047 scanning_(false),
48 scan_interval_(0) {
Darin Petkov5f316f62011-11-18 12:10:26 +010049 VLOG(2) << "Cellular capability constructed: GSM";
Darin Petkov1272a432011-11-10 15:53:37 +010050 PropertyStore *store = cellular->mutable_store();
Darin Petkov184c54e2011-11-15 12:44:39 +010051 store->RegisterConstString(flimflam::kSelectedNetworkProperty,
52 &selected_network_);
Darin Petkov1272a432011-11-10 15:53:37 +010053 store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
54 &found_networks_);
55 store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
56 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
Darin Petkov721ac932011-11-16 15:43:09 +010057 HelpRegisterDerivedStrIntPair(flimflam::kSIMLockStatusProperty,
58 &CellularCapabilityGSM::SimLockStatusToProperty,
59 NULL);
Darin Petkov3cfbf212011-11-21 16:02:09 +010060 store->RegisterConstStringmaps(flimflam::kCellularApnListProperty,
61 &apn_list_);
Darin Petkov1272a432011-11-10 15:53:37 +010062}
Darin Petkovdaf43862011-10-27 11:37:28 +020063
Darin Petkov721ac932011-11-16 15:43:09 +010064StrIntPair CellularCapabilityGSM::SimLockStatusToProperty(Error */*error*/) {
65 return StrIntPair(make_pair(flimflam::kSIMLockTypeProperty,
66 sim_lock_status_.lock_type),
67 make_pair(flimflam::kSIMLockRetriesLeftProperty,
68 sim_lock_status_.retries_left));
69}
70
71void CellularCapabilityGSM::HelpRegisterDerivedStrIntPair(
72 const string &name,
73 StrIntPair(CellularCapabilityGSM::*get)(Error *),
74 void(CellularCapabilityGSM::*set)(const StrIntPair &, Error *)) {
75 cellular()->mutable_store()->RegisterDerivedStrIntPair(
76 name,
77 StrIntPairAccessor(
78 new CustomAccessor<CellularCapabilityGSM, StrIntPair>(
79 this, get, set)));
80}
81
Darin Petkov5f316f62011-11-18 12:10:26 +010082void CellularCapabilityGSM::OnDeviceStarted() {
Darin Petkovdaf43862011-10-27 11:37:28 +020083 VLOG(2) << __func__;
Darin Petkovcb547732011-11-09 13:55:26 +010084 card_proxy_.reset(
85 proxy_factory()->CreateModemGSMCardProxy(this,
Darin Petkovdaf43862011-10-27 11:37:28 +020086 cellular()->dbus_path(),
87 cellular()->dbus_owner()));
Darin Petkov184c54e2011-11-15 12:44:39 +010088 network_proxy_.reset(
89 proxy_factory()->CreateModemGSMNetworkProxy(this,
Darin Petkovdaf43862011-10-27 11:37:28 +020090 cellular()->dbus_path(),
91 cellular()->dbus_owner()));
92}
93
Darin Petkov5f316f62011-11-18 12:10:26 +010094void CellularCapabilityGSM::OnDeviceStopped() {
Darin Petkov721ac932011-11-16 15:43:09 +010095 VLOG(2) << __func__;
96 card_proxy_.reset();
97 network_proxy_.reset();
98}
99
Darin Petkov5f316f62011-11-18 12:10:26 +0100100void CellularCapabilityGSM::OnServiceCreated() {
Darin Petkovb9c99332012-01-12 13:13:00 +0100101 cellular()->service()->SetActivationState(
Darin Petkov5f316f62011-11-18 12:10:26 +0100102 flimflam::kActivationStateActivated);
103 UpdateServingOperator();
104}
105
Darin Petkovae0c64e2011-11-15 15:50:27 +0100106void CellularCapabilityGSM::UpdateStatus(const DBusPropertiesMap &properties) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100107 if (ContainsKey(properties, Cellular::kPropertyIMSI)) {
108 SetHomeProvider();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100109 }
110}
111
112void CellularCapabilityGSM::SetupConnectProperties(
113 DBusPropertiesMap *properties) {
114 (*properties)[Cellular::kConnectPropertyPhoneNumber].writer().append_string(
115 kPhoneNumber);
116 // TODO(petkov): Setup apn and "home_only".
117}
118
Darin Petkovcb547732011-11-09 13:55:26 +0100119void CellularCapabilityGSM::GetIdentifiers() {
120 VLOG(2) << __func__;
121 if (cellular()->imei().empty()) {
122 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
123 cellular()->set_imei(card_proxy_->GetIMEI());
Darin Petkovcb547732011-11-09 13:55:26 +0100124 }
125 if (cellular()->imsi().empty()) {
126 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkove5bc2cb2011-12-07 14:47:32 +0100127 try {
128 cellular()->set_imsi(card_proxy_->GetIMSI());
129 VLOG(2) << "IMSI: " << cellular()->imsi();
130 } catch (const DBus::Error e) {
131 LOG(WARNING) << "Unable to obtain IMSI: " << e.what();
132 }
Darin Petkovcb547732011-11-09 13:55:26 +0100133 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100134 if (spn_.empty()) {
Darin Petkovcb547732011-11-09 13:55:26 +0100135 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
136 try {
Darin Petkovae0c64e2011-11-15 15:50:27 +0100137 spn_ = card_proxy_->GetSPN();
138 VLOG(2) << "SPN: " << spn_;
Darin Petkovcb547732011-11-09 13:55:26 +0100139 } catch (const DBus::Error e) {
140 // Some modems don't support this call so catch the exception explicitly.
141 LOG(WARNING) << "Unable to obtain SPN: " << e.what();
142 }
143 }
144 if (cellular()->mdn().empty()) {
Darin Petkovb72cf402011-11-22 14:51:39 +0100145 try {
146 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
147 cellular()->set_mdn(card_proxy_->GetMSISDN());
148 VLOG(2) << "MSISDN/MDN: " << cellular()->mdn();
149 } catch (const DBus::Error e) {
150 LOG(WARNING) << "Unable to obtain MSISDN/MDN: " << e.what();
151 }
Darin Petkovcb547732011-11-09 13:55:26 +0100152 }
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100153 SetHomeProvider();
Darin Petkovcb547732011-11-09 13:55:26 +0100154}
155
Darin Petkov3e509242011-11-10 14:46:44 +0100156void CellularCapabilityGSM::GetSignalQuality() {
157 VLOG(2) << __func__;
158 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkov184c54e2011-11-15 12:44:39 +0100159 uint32 strength = network_proxy_->GetSignalQuality();
Darin Petkov3e509242011-11-10 14:46:44 +0100160 cellular()->HandleNewSignalQuality(strength);
161}
162
Darin Petkov184c54e2011-11-15 12:44:39 +0100163void CellularCapabilityGSM::GetRegistrationState() {
164 VLOG(2) << __func__;
165 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
166 ModemGSMNetworkProxyInterface::RegistrationInfo info =
167 network_proxy_->GetRegistrationInfo();
168 registration_state_ = info._1;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100169 serving_operator_.SetCode(info._2);
170 serving_operator_.SetName(info._3);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100171 VLOG(2) << "GSM Registration: " << registration_state_ << ", "
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100172 << serving_operator_.GetCode() << ", "
173 << serving_operator_.GetName();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100174 UpdateOperatorInfo();
Darin Petkov184c54e2011-11-15 12:44:39 +0100175 cellular()->HandleNewRegistrationState();
176}
177
178void CellularCapabilityGSM::GetProperties() {
179 VLOG(2) << __func__;
180 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
181 uint32 tech = network_proxy_->AccessTechnology();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100182 SetAccessTechnology(tech);
Darin Petkov184c54e2011-11-15 12:44:39 +0100183 VLOG(2) << "GSM AccessTechnology: " << tech;
184}
185
Darin Petkovac635a82012-01-10 16:51:58 +0100186string CellularCapabilityGSM::CreateFriendlyServiceName() {
187 VLOG(2) << __func__;
188 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME &&
189 !cellular()->home_provider().GetName().empty()) {
190 return cellular()->home_provider().GetName();
191 }
192 if (!serving_operator_.GetName().empty()) {
193 return serving_operator_.GetName();
194 }
195 if (!cellular()->carrier().empty()) {
196 return cellular()->carrier();
197 }
198 if (!serving_operator_.GetCode().empty()) {
199 return "cellular_" + serving_operator_.GetCode();
200 }
201 return base::StringPrintf("GSMNetwork%u", friendly_service_name_id_++);
202}
203
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100204void CellularCapabilityGSM::SetHomeProvider() {
205 VLOG(2) << __func__ << "(IMSI: " << cellular()->imsi()
206 << " SPN: " << spn_ << ")";
207 // TODO(petkov): The test for NULL provider_db should be done by
208 // mobile_provider_lookup_best_match.
209 if (cellular()->imsi().empty() || !cellular()->provider_db()) {
210 return;
211 }
212 mobile_provider *provider =
213 mobile_provider_lookup_best_match(
214 cellular()->provider_db(), spn_.c_str(), cellular()->imsi().c_str());
215 if (!provider) {
216 VLOG(2) << "GSM provider not found.";
217 return;
218 }
219 home_provider_ = provider;
220 Cellular::Operator oper;
221 if (provider->networks) {
222 oper.SetCode(provider->networks[0]);
223 }
224 if (provider->country) {
225 oper.SetCountry(provider->country);
226 }
227 if (spn_.empty()) {
228 const char *name = mobile_provider_get_name(provider);
229 if (name) {
230 oper.SetName(name);
231 }
232 } else {
233 oper.SetName(spn_);
234 }
235 cellular()->set_home_provider(oper);
Darin Petkov3cfbf212011-11-21 16:02:09 +0100236 InitAPNList();
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100237}
238
Darin Petkovae0c64e2011-11-15 15:50:27 +0100239void CellularCapabilityGSM::UpdateOperatorInfo() {
240 VLOG(2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100241 const string &network_id = serving_operator_.GetCode();
242 if (!network_id.empty()) {
243 VLOG(2) << "Looking up network id: " << network_id;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100244 mobile_provider *provider =
245 mobile_provider_lookup_by_network(cellular()->provider_db(),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100246 network_id.c_str());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100247 if (provider) {
248 const char *provider_name = mobile_provider_get_name(provider);
249 if (provider_name && *provider_name) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100250 serving_operator_.SetName(provider_name);
251 if (provider->country) {
252 serving_operator_.SetCountry(provider->country);
253 }
254 VLOG(2) << "Operator name: " << serving_operator_.GetName()
255 << ", country: " << serving_operator_.GetCountry();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100256 }
257 } else {
258 VLOG(2) << "GSM provider not found.";
259 }
260 }
261 UpdateServingOperator();
262}
263
264void CellularCapabilityGSM::UpdateServingOperator() {
265 VLOG(2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100266 if (cellular()->service().get()) {
267 cellular()->service()->set_serving_operator(serving_operator_);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100268 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100269}
270
Darin Petkov3cfbf212011-11-21 16:02:09 +0100271void CellularCapabilityGSM::InitAPNList() {
272 VLOG(2) << __func__;
273 if (!home_provider_) {
274 return;
275 }
276 apn_list_.clear();
277 for (int i = 0; i < home_provider_->num_apns; ++i) {
278 Stringmap props;
279 mobile_apn *apn = home_provider_->apns[i];
280 if (apn->value) {
281 props[flimflam::kApnProperty] = apn->value;
282 }
283 if (apn->username) {
284 props[flimflam::kApnUsernameProperty] = apn->username;
285 }
286 if (apn->password) {
287 props[flimflam::kApnPasswordProperty] = apn->password;
288 }
289 // Find the first localized and non-localized name, if any.
290 const localized_name *lname = NULL;
291 const localized_name *name = NULL;
292 for (int j = 0; j < apn->num_names; ++j) {
293 if (apn->names[j]->lang) {
294 if (!lname) {
295 lname = apn->names[j];
296 }
297 } else if (!name) {
298 name = apn->names[j];
299 }
300 }
301 if (name) {
302 props[flimflam::kApnNameProperty] = name->name;
303 }
304 if (lname) {
305 props[flimflam::kApnLocalizedNameProperty] = lname->name;
306 props[flimflam::kApnLanguageProperty] = lname->lang;
307 }
308 apn_list_.push_back(props);
309 }
310 cellular()->adaptor()->EmitStringmapsChanged(
311 flimflam::kCellularApnListProperty, apn_list_);
312}
313
Darin Petkov184c54e2011-11-15 12:44:39 +0100314void CellularCapabilityGSM::Register() {
315 LOG(INFO) << __func__ << " \"" << selected_network_ << "\"";
316 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
317 network_proxy_->Register(selected_network_);
318 // TODO(petkov): Handle registration failure including trying the home network
319 // when selected_network_ is not empty.
320}
321
322void CellularCapabilityGSM::RegisterOnNetwork(
323 const string &network_id, Error */*error*/) {
324 LOG(INFO) << __func__ << "(" << network_id << ")";
325 // Defer because we may be in a dbus-c++ callback.
326 dispatcher()->PostTask(
327 task_factory_.NewRunnableMethod(
328 &CellularCapabilityGSM::RegisterOnNetworkTask,
329 network_id));
330}
331
Darin Petkovb72cf402011-11-22 14:51:39 +0100332bool CellularCapabilityGSM::IsRegistered() {
333 return (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
334 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING);
335}
336
Darin Petkov184c54e2011-11-15 12:44:39 +0100337void CellularCapabilityGSM::RegisterOnNetworkTask(const string &network_id) {
338 LOG(INFO) << __func__ << "(" << network_id << ")";
339 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
340 network_proxy_->Register(network_id);
341 // TODO(petkov): Handle registration failure.
342 selected_network_ = network_id;
343}
344
Darin Petkovb05315f2011-11-07 10:14:25 +0100345void CellularCapabilityGSM::RequirePIN(
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100346 const string &pin, bool require, ReturnerInterface *returner) {
347 VLOG(2) << __func__ << "(" << returner << ")";
Darin Petkovb05315f2011-11-07 10:14:25 +0100348 // Defer because we may be in a dbus-c++ callback.
349 dispatcher()->PostTask(
350 task_factory_.NewRunnableMethod(
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100351 &CellularCapabilityGSM::RequirePINTask, pin, require, returner));
Darin Petkovb05315f2011-11-07 10:14:25 +0100352}
353
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100354void CellularCapabilityGSM::RequirePINTask(
355 const string &pin, bool require, ReturnerInterface *returner) {
356 VLOG(2) << __func__ << "(" << returner << ")";
Darin Petkovb05315f2011-11-07 10:14:25 +0100357 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100358 try {
359 card_proxy_->EnablePIN(pin, require);
360 } catch (DBus::Error e) {
361 LOG(ERROR) << "EnablePIN failed: " << e.name() << "/" << e.message();
362 returner->ReturnError(Error(Error::kInternalError));
363 return;
364 }
365 returner->Return();
Darin Petkovb05315f2011-11-07 10:14:25 +0100366}
367
Darin Petkove5bc2cb2011-12-07 14:47:32 +0100368void CellularCapabilityGSM::EnterPIN(const string &pin,
369 ReturnerInterface *returner) {
370 VLOG(2) << __func__ << "(" << returner << ")";
Darin Petkovb05315f2011-11-07 10:14:25 +0100371 // Defer because we may be in a dbus-c++ callback.
372 dispatcher()->PostTask(
373 task_factory_.NewRunnableMethod(
Darin Petkove5bc2cb2011-12-07 14:47:32 +0100374 &CellularCapabilityGSM::EnterPINTask, pin, returner));
Darin Petkovb05315f2011-11-07 10:14:25 +0100375}
376
Darin Petkove5bc2cb2011-12-07 14:47:32 +0100377void CellularCapabilityGSM::EnterPINTask(const string &pin,
378 ReturnerInterface *returner) {
379 VLOG(2) << __func__ << "(" << returner << ")";
Darin Petkovb05315f2011-11-07 10:14:25 +0100380 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkove5bc2cb2011-12-07 14:47:32 +0100381 try {
382 card_proxy_->SendPIN(pin);
383 } catch (DBus::Error e) {
384 LOG(ERROR) << "EnterPIN failed: " << e.name() << "/" << e.message();
385 returner->ReturnError(Error(Error::kInternalError));
386 return;
387 }
388 returner->Return();
Darin Petkovb05315f2011-11-07 10:14:25 +0100389}
390
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100391void CellularCapabilityGSM::UnblockPIN(const string &unblock_code,
392 const string &pin,
393 ReturnerInterface *returner) {
394 VLOG(2) << __func__ << "(" << returner << ")";
Darin Petkovb05315f2011-11-07 10:14:25 +0100395 // Defer because we may be in a dbus-c++ callback.
396 dispatcher()->PostTask(
397 task_factory_.NewRunnableMethod(
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100398 &CellularCapabilityGSM::UnblockPINTask, unblock_code, pin, returner));
Darin Petkovb05315f2011-11-07 10:14:25 +0100399}
400
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100401void CellularCapabilityGSM::UnblockPINTask(const string &unblock_code,
402 const string &pin,
403 ReturnerInterface *returner) {
404 VLOG(2) << __func__ << "(" << returner << ")";
Darin Petkovb05315f2011-11-07 10:14:25 +0100405 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100406 try {
407 card_proxy_->SendPUK(unblock_code, pin);
408 } catch (DBus::Error e) {
409 LOG(ERROR) << "SendPUK failed: " << e.name() << "/" << e.message();
410 returner->ReturnError(Error(Error::kInternalError));
411 return;
412 }
413 returner->Return();
Darin Petkovb05315f2011-11-07 10:14:25 +0100414}
415
416void CellularCapabilityGSM::ChangePIN(
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100417 const string &old_pin, const string &new_pin, ReturnerInterface *returner) {
418 VLOG(2) << __func__ << "(" << returner << ")";
Darin Petkovb05315f2011-11-07 10:14:25 +0100419 // Defer because we may be in a dbus-c++ callback.
420 dispatcher()->PostTask(
421 task_factory_.NewRunnableMethod(
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100422 &CellularCapabilityGSM::ChangePINTask, old_pin, new_pin, returner));
Darin Petkovb05315f2011-11-07 10:14:25 +0100423}
424
425void CellularCapabilityGSM::ChangePINTask(
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100426 const string &old_pin, const string &new_pin, ReturnerInterface *returner) {
427 VLOG(2) << __func__ << "(" << returner << ")";
Darin Petkovb05315f2011-11-07 10:14:25 +0100428 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100429 try {
430 card_proxy_->ChangePIN(old_pin, new_pin);
431 } catch (DBus::Error e) {
432 LOG(ERROR) << "ChangePIN failed: " << e.name() << "/" << e.message();
433 returner->ReturnError(Error(Error::kInternalError));
434 return;
435 }
436 returner->Return();
Darin Petkovb05315f2011-11-07 10:14:25 +0100437}
438
Darin Petkov1272a432011-11-10 15:53:37 +0100439void CellularCapabilityGSM::Scan(Error */*error*/) {
440 VLOG(2) << __func__;
441 // Defer because we may be in a dbus-c++ callback.
442 dispatcher()->PostTask(
443 task_factory_.NewRunnableMethod(&CellularCapabilityGSM::ScanTask));
444}
445
446void CellularCapabilityGSM::ScanTask() {
447 VLOG(2) << __func__;
448 // TODO(petkov): Defer scan requests if a scan is in progress already.
449 //
450 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583). This is a
451 // must for this call which is basically a stub at this point.
Darin Petkov184c54e2011-11-15 12:44:39 +0100452 ModemGSMNetworkProxyInterface::ScanResults results = network_proxy_->Scan();
Darin Petkov1272a432011-11-10 15:53:37 +0100453 found_networks_.clear();
454 for (ModemGSMNetworkProxyInterface::ScanResults::const_iterator it =
455 results.begin(); it != results.end(); ++it) {
456 found_networks_.push_back(ParseScanResult(*it));
457 }
458}
459
460Stringmap CellularCapabilityGSM::ParseScanResult(
461 const ModemGSMNetworkProxyInterface::ScanResult &result) {
462 Stringmap parsed;
463 for (ModemGSMNetworkProxyInterface::ScanResult::const_iterator it =
464 result.begin(); it != result.end(); ++it) {
465 // TODO(petkov): Define these in system_api/service_constants.h. The
466 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
467 static const char * const kStatusString[] = {
468 "unknown",
469 "available",
470 "current",
471 "forbidden",
472 };
473 static const char * const kTechnologyString[] = {
474 flimflam::kNetworkTechnologyGsm,
475 "GSM Compact",
476 flimflam::kNetworkTechnologyUmts,
477 flimflam::kNetworkTechnologyEdge,
478 "HSDPA",
479 "HSUPA",
480 flimflam::kNetworkTechnologyHspa,
481 };
482 VLOG(2) << "Network property: " << it->first << " = " << it->second;
483 if (it->first == kNetworkPropertyStatus) {
484 int status = 0;
485 if (base::StringToInt(it->second, &status) &&
486 status >= 0 &&
487 status < static_cast<int>(arraysize(kStatusString))) {
488 parsed[flimflam::kStatusProperty] = kStatusString[status];
489 } else {
490 LOG(ERROR) << "Unexpected status value: " << it->second;
491 }
492 } else if (it->first == kNetworkPropertyID) {
493 parsed[flimflam::kNetworkIdProperty] = it->second;
494 } else if (it->first == kNetworkPropertyLongName) {
495 parsed[flimflam::kLongNameProperty] = it->second;
496 } else if (it->first == kNetworkPropertyShortName) {
497 parsed[flimflam::kShortNameProperty] = it->second;
498 } else if (it->first == kNetworkPropertyAccessTechnology) {
499 int tech = 0;
500 if (base::StringToInt(it->second, &tech) &&
501 tech >= 0 &&
502 tech < static_cast<int>(arraysize(kTechnologyString))) {
503 parsed[flimflam::kTechnologyProperty] = kTechnologyString[tech];
504 } else {
505 LOG(ERROR) << "Unexpected technology value: " << it->second;
506 }
507 } else {
508 LOG(WARNING) << "Unknown network property ignored: " << it->first;
509 }
510 }
511 // If the long name is not available but the network ID is, look up the long
512 // name in the mobile provider database.
513 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
514 parsed[flimflam::kLongNameProperty].empty()) &&
515 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
516 mobile_provider *provider =
517 mobile_provider_lookup_by_network(
518 cellular()->provider_db(),
519 parsed[flimflam::kNetworkIdProperty].c_str());
520 if (provider) {
521 const char *long_name = mobile_provider_get_name(provider);
522 if (long_name && *long_name) {
523 parsed[flimflam::kLongNameProperty] = long_name;
524 }
525 }
526 }
527 return parsed;
528}
529
Darin Petkovae0c64e2011-11-15 15:50:27 +0100530void CellularCapabilityGSM::SetAccessTechnology(uint32 access_technology) {
531 access_technology_ = access_technology;
532 if (cellular()->service().get()) {
Darin Petkovb72cf402011-11-22 14:51:39 +0100533 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100534 }
535}
536
Darin Petkov20c13ec2011-11-09 15:07:15 +0100537string CellularCapabilityGSM::GetNetworkTechnologyString() const {
Darin Petkovb72cf402011-11-22 14:51:39 +0100538 switch (access_technology_) {
539 case MM_MODEM_GSM_ACCESS_TECH_GSM:
540 case MM_MODEM_GSM_ACCESS_TECH_GSM_COMPACT:
541 return flimflam::kNetworkTechnologyGsm;
542 case MM_MODEM_GSM_ACCESS_TECH_GPRS:
543 return flimflam::kNetworkTechnologyGprs;
544 case MM_MODEM_GSM_ACCESS_TECH_EDGE:
545 return flimflam::kNetworkTechnologyEdge;
546 case MM_MODEM_GSM_ACCESS_TECH_UMTS:
547 return flimflam::kNetworkTechnologyUmts;
548 case MM_MODEM_GSM_ACCESS_TECH_HSDPA:
549 case MM_MODEM_GSM_ACCESS_TECH_HSUPA:
550 case MM_MODEM_GSM_ACCESS_TECH_HSPA:
551 return flimflam::kNetworkTechnologyHspa;
552 case MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS:
553 return flimflam::kNetworkTechnologyHspaPlus;
554 default:
555 break;
Darin Petkov20c13ec2011-11-09 15:07:15 +0100556 }
557 return "";
558}
559
560string CellularCapabilityGSM::GetRoamingStateString() const {
Darin Petkov184c54e2011-11-15 12:44:39 +0100561 switch (registration_state_) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100562 case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME:
563 return flimflam::kRoamingStateHome;
564 case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING:
565 return flimflam::kRoamingStateRoaming;
566 default:
567 break;
568 }
569 return flimflam::kRoamingStateUnknown;
570}
571
Darin Petkovae0c64e2011-11-15 15:50:27 +0100572void CellularCapabilityGSM::OnModemManagerPropertiesChanged(
573 const DBusPropertiesMap &properties) {
574 uint32 access_technology = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
575 if (DBusProperties::GetUint32(properties,
576 kPropertyAccessTechnology,
577 &access_technology)) {
578 SetAccessTechnology(access_technology);
579 }
Darin Petkov721ac932011-11-16 15:43:09 +0100580 DBusProperties::GetString(
581 properties, kPropertyUnlockRequired, &sim_lock_status_.lock_type);
582 DBusProperties::GetUint32(
583 properties, kPropertyUnlockRetries, &sim_lock_status_.retries_left);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100584}
585
Darin Petkov184c54e2011-11-15 12:44:39 +0100586void CellularCapabilityGSM::OnGSMNetworkModeChanged(uint32 /*mode*/) {
587 // TODO(petkov): Implement this.
588 NOTIMPLEMENTED();
589}
590
591void CellularCapabilityGSM::OnGSMRegistrationInfoChanged(
592 uint32 status, const string &operator_code, const string &operator_name) {
593 registration_state_ = status;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100594 serving_operator_.SetCode(operator_code);
595 serving_operator_.SetName(operator_name);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100596 UpdateOperatorInfo();
Darin Petkov184c54e2011-11-15 12:44:39 +0100597 cellular()->HandleNewRegistrationState();
598}
599
600void CellularCapabilityGSM::OnGSMSignalQualityChanged(uint32 quality) {
601 cellular()->HandleNewSignalQuality(quality);
602}
603
Darin Petkovdaf43862011-10-27 11:37:28 +0200604} // namespace shill