blob: ac8c1a93c45e8045a81e84e1b662769c9e82cb53 [file] [log] [blame]
Darin Petkovdaf43862011-10-27 11:37:28 +02001// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2// 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 Petkov20c13ec2011-11-09 15:07:15 +010010#include <chromeos/dbus/service_constants.h>
11#include <mm/mm-modem.h>
Darin Petkov1272a432011-11-10 15:53:37 +010012#include <mobile_provider.h>
Darin Petkovdaf43862011-10-27 11:37:28 +020013
Darin Petkov3cfbf212011-11-21 16:02:09 +010014#include "shill/adaptor_interfaces.h"
Darin Petkovae0c64e2011-11-15 15:50:27 +010015#include "shill/cellular_service.h"
Darin Petkov721ac932011-11-16 15:43:09 +010016#include "shill/property_accessor.h"
Darin Petkovdaf43862011-10-27 11:37:28 +020017#include "shill/proxy_factory.h"
18
Darin Petkov721ac932011-11-16 15:43:09 +010019using std::make_pair;
Darin Petkovb05315f2011-11-07 10:14:25 +010020using std::string;
21
Darin Petkovdaf43862011-10-27 11:37:28 +020022namespace shill {
23
Darin Petkov1272a432011-11-10 15:53:37 +010024const char CellularCapabilityGSM::kNetworkPropertyAccessTechnology[] =
25 "access-tech";
26const char CellularCapabilityGSM::kNetworkPropertyID[] = "operator-num";
27const char CellularCapabilityGSM::kNetworkPropertyLongName[] = "operator-long";
28const char CellularCapabilityGSM::kNetworkPropertyShortName[] =
29 "operator-short";
30const char CellularCapabilityGSM::kNetworkPropertyStatus[] = "status";
Darin Petkovae0c64e2011-11-15 15:50:27 +010031const char CellularCapabilityGSM::kPhoneNumber[] = "*99#";
32const char CellularCapabilityGSM::kPropertyAccessTechnology[] =
33 "AccessTechnology";
Darin Petkov721ac932011-11-16 15:43:09 +010034const char CellularCapabilityGSM::kPropertyUnlockRequired[] = "UnlockRequired";
35const char CellularCapabilityGSM::kPropertyUnlockRetries[] = "UnlockRetries";
Darin Petkov1272a432011-11-10 15:53:37 +010036
Darin Petkovdaf43862011-10-27 11:37:28 +020037CellularCapabilityGSM::CellularCapabilityGSM(Cellular *cellular)
Darin Petkovb05315f2011-11-07 10:14:25 +010038 : CellularCapability(cellular),
Darin Petkov1272a432011-11-10 15:53:37 +010039 task_factory_(this),
Darin Petkov184c54e2011-11-15 12:44:39 +010040 registration_state_(MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN),
Darin Petkovae0c64e2011-11-15 15:50:27 +010041 access_technology_(MM_MODEM_GSM_ACCESS_TECH_UNKNOWN),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +010042 home_provider_(NULL),
Darin Petkov1272a432011-11-10 15:53:37 +010043 scanning_(false),
44 scan_interval_(0) {
Darin Petkov5f316f62011-11-18 12:10:26 +010045 VLOG(2) << "Cellular capability constructed: GSM";
Darin Petkov1272a432011-11-10 15:53:37 +010046 PropertyStore *store = cellular->mutable_store();
Darin Petkov184c54e2011-11-15 12:44:39 +010047 store->RegisterConstString(flimflam::kSelectedNetworkProperty,
48 &selected_network_);
Darin Petkov1272a432011-11-10 15:53:37 +010049 store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
50 &found_networks_);
51 store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
52 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
Darin Petkov721ac932011-11-16 15:43:09 +010053 HelpRegisterDerivedStrIntPair(flimflam::kSIMLockStatusProperty,
54 &CellularCapabilityGSM::SimLockStatusToProperty,
55 NULL);
Darin Petkov3cfbf212011-11-21 16:02:09 +010056 store->RegisterConstStringmaps(flimflam::kCellularApnListProperty,
57 &apn_list_);
Darin Petkov1272a432011-11-10 15:53:37 +010058}
Darin Petkovdaf43862011-10-27 11:37:28 +020059
Darin Petkov721ac932011-11-16 15:43:09 +010060StrIntPair CellularCapabilityGSM::SimLockStatusToProperty(Error */*error*/) {
61 return StrIntPair(make_pair(flimflam::kSIMLockTypeProperty,
62 sim_lock_status_.lock_type),
63 make_pair(flimflam::kSIMLockRetriesLeftProperty,
64 sim_lock_status_.retries_left));
65}
66
67void CellularCapabilityGSM::HelpRegisterDerivedStrIntPair(
68 const string &name,
69 StrIntPair(CellularCapabilityGSM::*get)(Error *),
70 void(CellularCapabilityGSM::*set)(const StrIntPair &, Error *)) {
71 cellular()->mutable_store()->RegisterDerivedStrIntPair(
72 name,
73 StrIntPairAccessor(
74 new CustomAccessor<CellularCapabilityGSM, StrIntPair>(
75 this, get, set)));
76}
77
Darin Petkov5f316f62011-11-18 12:10:26 +010078void CellularCapabilityGSM::OnDeviceStarted() {
Darin Petkovdaf43862011-10-27 11:37:28 +020079 VLOG(2) << __func__;
Darin Petkovcb547732011-11-09 13:55:26 +010080 card_proxy_.reset(
81 proxy_factory()->CreateModemGSMCardProxy(this,
Darin Petkovdaf43862011-10-27 11:37:28 +020082 cellular()->dbus_path(),
83 cellular()->dbus_owner()));
Darin Petkov184c54e2011-11-15 12:44:39 +010084 network_proxy_.reset(
85 proxy_factory()->CreateModemGSMNetworkProxy(this,
Darin Petkovdaf43862011-10-27 11:37:28 +020086 cellular()->dbus_path(),
87 cellular()->dbus_owner()));
88}
89
Darin Petkov5f316f62011-11-18 12:10:26 +010090void CellularCapabilityGSM::OnDeviceStopped() {
Darin Petkov721ac932011-11-16 15:43:09 +010091 VLOG(2) << __func__;
92 card_proxy_.reset();
93 network_proxy_.reset();
94}
95
Darin Petkov5f316f62011-11-18 12:10:26 +010096void CellularCapabilityGSM::OnServiceCreated() {
97 cellular()->service()->set_activation_state(
98 flimflam::kActivationStateActivated);
99 UpdateServingOperator();
100}
101
Darin Petkovae0c64e2011-11-15 15:50:27 +0100102void CellularCapabilityGSM::UpdateStatus(const DBusPropertiesMap &properties) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100103 if (ContainsKey(properties, Cellular::kPropertyIMSI)) {
104 SetHomeProvider();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100105 }
106}
107
108void CellularCapabilityGSM::SetupConnectProperties(
109 DBusPropertiesMap *properties) {
110 (*properties)[Cellular::kConnectPropertyPhoneNumber].writer().append_string(
111 kPhoneNumber);
112 // TODO(petkov): Setup apn and "home_only".
113}
114
Darin Petkovcb547732011-11-09 13:55:26 +0100115void CellularCapabilityGSM::GetIdentifiers() {
116 VLOG(2) << __func__;
117 if (cellular()->imei().empty()) {
118 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
119 cellular()->set_imei(card_proxy_->GetIMEI());
120 VLOG(2) << "IMEI: " << cellular()->imei();
121 }
122 if (cellular()->imsi().empty()) {
123 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
124 cellular()->set_imsi(card_proxy_->GetIMSI());
125 VLOG(2) << "IMSI: " << cellular()->imsi();
126 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100127 if (spn_.empty()) {
Darin Petkovcb547732011-11-09 13:55:26 +0100128 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
129 try {
Darin Petkovae0c64e2011-11-15 15:50:27 +0100130 spn_ = card_proxy_->GetSPN();
131 VLOG(2) << "SPN: " << spn_;
Darin Petkovcb547732011-11-09 13:55:26 +0100132 } catch (const DBus::Error e) {
133 // Some modems don't support this call so catch the exception explicitly.
134 LOG(WARNING) << "Unable to obtain SPN: " << e.what();
135 }
136 }
137 if (cellular()->mdn().empty()) {
Darin Petkovb72cf402011-11-22 14:51:39 +0100138 try {
139 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
140 cellular()->set_mdn(card_proxy_->GetMSISDN());
141 VLOG(2) << "MSISDN/MDN: " << cellular()->mdn();
142 } catch (const DBus::Error e) {
143 LOG(WARNING) << "Unable to obtain MSISDN/MDN: " << e.what();
144 }
Darin Petkovcb547732011-11-09 13:55:26 +0100145 }
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100146 SetHomeProvider();
Darin Petkovcb547732011-11-09 13:55:26 +0100147}
148
Darin Petkov3e509242011-11-10 14:46:44 +0100149void CellularCapabilityGSM::GetSignalQuality() {
150 VLOG(2) << __func__;
151 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkov184c54e2011-11-15 12:44:39 +0100152 uint32 strength = network_proxy_->GetSignalQuality();
Darin Petkov3e509242011-11-10 14:46:44 +0100153 cellular()->HandleNewSignalQuality(strength);
154}
155
Darin Petkov184c54e2011-11-15 12:44:39 +0100156void CellularCapabilityGSM::GetRegistrationState() {
157 VLOG(2) << __func__;
158 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
159 ModemGSMNetworkProxyInterface::RegistrationInfo info =
160 network_proxy_->GetRegistrationInfo();
161 registration_state_ = info._1;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100162 serving_operator_.SetCode(info._2);
163 serving_operator_.SetName(info._3);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100164 VLOG(2) << "GSM Registration: " << registration_state_ << ", "
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100165 << serving_operator_.GetCode() << ", "
166 << serving_operator_.GetName();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100167 UpdateOperatorInfo();
Darin Petkov184c54e2011-11-15 12:44:39 +0100168 cellular()->HandleNewRegistrationState();
169}
170
171void CellularCapabilityGSM::GetProperties() {
172 VLOG(2) << __func__;
173 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
174 uint32 tech = network_proxy_->AccessTechnology();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100175 SetAccessTechnology(tech);
Darin Petkov184c54e2011-11-15 12:44:39 +0100176 VLOG(2) << "GSM AccessTechnology: " << tech;
177}
178
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100179void CellularCapabilityGSM::SetHomeProvider() {
180 VLOG(2) << __func__ << "(IMSI: " << cellular()->imsi()
181 << " SPN: " << spn_ << ")";
182 // TODO(petkov): The test for NULL provider_db should be done by
183 // mobile_provider_lookup_best_match.
184 if (cellular()->imsi().empty() || !cellular()->provider_db()) {
185 return;
186 }
187 mobile_provider *provider =
188 mobile_provider_lookup_best_match(
189 cellular()->provider_db(), spn_.c_str(), cellular()->imsi().c_str());
190 if (!provider) {
191 VLOG(2) << "GSM provider not found.";
192 return;
193 }
194 home_provider_ = provider;
195 Cellular::Operator oper;
196 if (provider->networks) {
197 oper.SetCode(provider->networks[0]);
198 }
199 if (provider->country) {
200 oper.SetCountry(provider->country);
201 }
202 if (spn_.empty()) {
203 const char *name = mobile_provider_get_name(provider);
204 if (name) {
205 oper.SetName(name);
206 }
207 } else {
208 oper.SetName(spn_);
209 }
210 cellular()->set_home_provider(oper);
Darin Petkov3cfbf212011-11-21 16:02:09 +0100211 InitAPNList();
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100212}
213
Darin Petkovae0c64e2011-11-15 15:50:27 +0100214void CellularCapabilityGSM::UpdateOperatorInfo() {
215 VLOG(2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100216 const string &network_id = serving_operator_.GetCode();
217 if (!network_id.empty()) {
218 VLOG(2) << "Looking up network id: " << network_id;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100219 mobile_provider *provider =
220 mobile_provider_lookup_by_network(cellular()->provider_db(),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100221 network_id.c_str());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100222 if (provider) {
223 const char *provider_name = mobile_provider_get_name(provider);
224 if (provider_name && *provider_name) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100225 serving_operator_.SetName(provider_name);
226 if (provider->country) {
227 serving_operator_.SetCountry(provider->country);
228 }
229 VLOG(2) << "Operator name: " << serving_operator_.GetName()
230 << ", country: " << serving_operator_.GetCountry();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100231 }
232 } else {
233 VLOG(2) << "GSM provider not found.";
234 }
235 }
236 UpdateServingOperator();
237}
238
239void CellularCapabilityGSM::UpdateServingOperator() {
240 VLOG(2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100241 if (cellular()->service().get()) {
242 cellular()->service()->set_serving_operator(serving_operator_);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100243 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100244}
245
Darin Petkov3cfbf212011-11-21 16:02:09 +0100246void CellularCapabilityGSM::InitAPNList() {
247 VLOG(2) << __func__;
248 if (!home_provider_) {
249 return;
250 }
251 apn_list_.clear();
252 for (int i = 0; i < home_provider_->num_apns; ++i) {
253 Stringmap props;
254 mobile_apn *apn = home_provider_->apns[i];
255 if (apn->value) {
256 props[flimflam::kApnProperty] = apn->value;
257 }
258 if (apn->username) {
259 props[flimflam::kApnUsernameProperty] = apn->username;
260 }
261 if (apn->password) {
262 props[flimflam::kApnPasswordProperty] = apn->password;
263 }
264 // Find the first localized and non-localized name, if any.
265 const localized_name *lname = NULL;
266 const localized_name *name = NULL;
267 for (int j = 0; j < apn->num_names; ++j) {
268 if (apn->names[j]->lang) {
269 if (!lname) {
270 lname = apn->names[j];
271 }
272 } else if (!name) {
273 name = apn->names[j];
274 }
275 }
276 if (name) {
277 props[flimflam::kApnNameProperty] = name->name;
278 }
279 if (lname) {
280 props[flimflam::kApnLocalizedNameProperty] = lname->name;
281 props[flimflam::kApnLanguageProperty] = lname->lang;
282 }
283 apn_list_.push_back(props);
284 }
285 cellular()->adaptor()->EmitStringmapsChanged(
286 flimflam::kCellularApnListProperty, apn_list_);
287}
288
Darin Petkov184c54e2011-11-15 12:44:39 +0100289void CellularCapabilityGSM::Register() {
290 LOG(INFO) << __func__ << " \"" << selected_network_ << "\"";
291 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
292 network_proxy_->Register(selected_network_);
293 // TODO(petkov): Handle registration failure including trying the home network
294 // when selected_network_ is not empty.
295}
296
297void CellularCapabilityGSM::RegisterOnNetwork(
298 const string &network_id, Error */*error*/) {
299 LOG(INFO) << __func__ << "(" << network_id << ")";
300 // Defer because we may be in a dbus-c++ callback.
301 dispatcher()->PostTask(
302 task_factory_.NewRunnableMethod(
303 &CellularCapabilityGSM::RegisterOnNetworkTask,
304 network_id));
305}
306
Darin Petkovb72cf402011-11-22 14:51:39 +0100307bool CellularCapabilityGSM::IsRegistered() {
308 return (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
309 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING);
310}
311
Darin Petkov184c54e2011-11-15 12:44:39 +0100312void CellularCapabilityGSM::RegisterOnNetworkTask(const string &network_id) {
313 LOG(INFO) << __func__ << "(" << network_id << ")";
314 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
315 network_proxy_->Register(network_id);
316 // TODO(petkov): Handle registration failure.
317 selected_network_ = network_id;
318}
319
Darin Petkovb05315f2011-11-07 10:14:25 +0100320void CellularCapabilityGSM::RequirePIN(
321 const string &pin, bool require, Error */*error*/) {
322 VLOG(2) << __func__ << "(" << pin << ", " << require << ")";
323 // Defer because we may be in a dbus-c++ callback.
324 dispatcher()->PostTask(
325 task_factory_.NewRunnableMethod(
326 &CellularCapabilityGSM::RequirePINTask, pin, require));
327}
328
329void CellularCapabilityGSM::RequirePINTask(const string &pin, bool require) {
330 VLOG(2) << __func__ << "(" << pin << ", " << require << ")";
331 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovcb547732011-11-09 13:55:26 +0100332 card_proxy_->EnablePIN(pin, require);
Darin Petkovb05315f2011-11-07 10:14:25 +0100333}
334
335void CellularCapabilityGSM::EnterPIN(const string &pin, Error */*error*/) {
336 VLOG(2) << __func__ << "(" << pin << ")";
337 // Defer because we may be in a dbus-c++ callback.
338 dispatcher()->PostTask(
339 task_factory_.NewRunnableMethod(
340 &CellularCapabilityGSM::EnterPINTask, pin));
341}
342
343void CellularCapabilityGSM::EnterPINTask(const string &pin) {
344 VLOG(2) << __func__ << "(" << pin << ")";
345 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovcb547732011-11-09 13:55:26 +0100346 card_proxy_->SendPIN(pin);
Darin Petkovb05315f2011-11-07 10:14:25 +0100347}
348
349void CellularCapabilityGSM::UnblockPIN(
350 const string &unblock_code, const string &pin, Error */*error*/) {
351 VLOG(2) << __func__ << "(" << unblock_code << ", " << pin << ")";
352 // Defer because we may be in a dbus-c++ callback.
353 dispatcher()->PostTask(
354 task_factory_.NewRunnableMethod(
355 &CellularCapabilityGSM::UnblockPINTask, unblock_code, pin));
356}
357
358void CellularCapabilityGSM::UnblockPINTask(
359 const string &unblock_code, const string &pin) {
360 VLOG(2) << __func__ << "(" << unblock_code << ", " << pin << ")";
361 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovcb547732011-11-09 13:55:26 +0100362 card_proxy_->SendPUK(unblock_code, pin);
Darin Petkovb05315f2011-11-07 10:14:25 +0100363}
364
365void CellularCapabilityGSM::ChangePIN(
366 const string &old_pin, const string &new_pin, Error */*error*/) {
367 VLOG(2) << __func__ << "(" << old_pin << ", " << new_pin << ")";
368 // Defer because we may be in a dbus-c++ callback.
369 dispatcher()->PostTask(
370 task_factory_.NewRunnableMethod(
371 &CellularCapabilityGSM::ChangePINTask, old_pin, new_pin));
372}
373
374void CellularCapabilityGSM::ChangePINTask(
375 const string &old_pin, const string &new_pin) {
376 VLOG(2) << __func__ << "(" << old_pin << ", " << new_pin << ")";
377 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovcb547732011-11-09 13:55:26 +0100378 card_proxy_->ChangePIN(old_pin, new_pin);
Darin Petkovb05315f2011-11-07 10:14:25 +0100379}
380
Darin Petkov1272a432011-11-10 15:53:37 +0100381void CellularCapabilityGSM::Scan(Error */*error*/) {
382 VLOG(2) << __func__;
383 // Defer because we may be in a dbus-c++ callback.
384 dispatcher()->PostTask(
385 task_factory_.NewRunnableMethod(&CellularCapabilityGSM::ScanTask));
386}
387
388void CellularCapabilityGSM::ScanTask() {
389 VLOG(2) << __func__;
390 // TODO(petkov): Defer scan requests if a scan is in progress already.
391 //
392 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583). This is a
393 // must for this call which is basically a stub at this point.
Darin Petkov184c54e2011-11-15 12:44:39 +0100394 ModemGSMNetworkProxyInterface::ScanResults results = network_proxy_->Scan();
Darin Petkov1272a432011-11-10 15:53:37 +0100395 found_networks_.clear();
396 for (ModemGSMNetworkProxyInterface::ScanResults::const_iterator it =
397 results.begin(); it != results.end(); ++it) {
398 found_networks_.push_back(ParseScanResult(*it));
399 }
400}
401
402Stringmap CellularCapabilityGSM::ParseScanResult(
403 const ModemGSMNetworkProxyInterface::ScanResult &result) {
404 Stringmap parsed;
405 for (ModemGSMNetworkProxyInterface::ScanResult::const_iterator it =
406 result.begin(); it != result.end(); ++it) {
407 // TODO(petkov): Define these in system_api/service_constants.h. The
408 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
409 static const char * const kStatusString[] = {
410 "unknown",
411 "available",
412 "current",
413 "forbidden",
414 };
415 static const char * const kTechnologyString[] = {
416 flimflam::kNetworkTechnologyGsm,
417 "GSM Compact",
418 flimflam::kNetworkTechnologyUmts,
419 flimflam::kNetworkTechnologyEdge,
420 "HSDPA",
421 "HSUPA",
422 flimflam::kNetworkTechnologyHspa,
423 };
424 VLOG(2) << "Network property: " << it->first << " = " << it->second;
425 if (it->first == kNetworkPropertyStatus) {
426 int status = 0;
427 if (base::StringToInt(it->second, &status) &&
428 status >= 0 &&
429 status < static_cast<int>(arraysize(kStatusString))) {
430 parsed[flimflam::kStatusProperty] = kStatusString[status];
431 } else {
432 LOG(ERROR) << "Unexpected status value: " << it->second;
433 }
434 } else if (it->first == kNetworkPropertyID) {
435 parsed[flimflam::kNetworkIdProperty] = it->second;
436 } else if (it->first == kNetworkPropertyLongName) {
437 parsed[flimflam::kLongNameProperty] = it->second;
438 } else if (it->first == kNetworkPropertyShortName) {
439 parsed[flimflam::kShortNameProperty] = it->second;
440 } else if (it->first == kNetworkPropertyAccessTechnology) {
441 int tech = 0;
442 if (base::StringToInt(it->second, &tech) &&
443 tech >= 0 &&
444 tech < static_cast<int>(arraysize(kTechnologyString))) {
445 parsed[flimflam::kTechnologyProperty] = kTechnologyString[tech];
446 } else {
447 LOG(ERROR) << "Unexpected technology value: " << it->second;
448 }
449 } else {
450 LOG(WARNING) << "Unknown network property ignored: " << it->first;
451 }
452 }
453 // If the long name is not available but the network ID is, look up the long
454 // name in the mobile provider database.
455 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
456 parsed[flimflam::kLongNameProperty].empty()) &&
457 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
458 mobile_provider *provider =
459 mobile_provider_lookup_by_network(
460 cellular()->provider_db(),
461 parsed[flimflam::kNetworkIdProperty].c_str());
462 if (provider) {
463 const char *long_name = mobile_provider_get_name(provider);
464 if (long_name && *long_name) {
465 parsed[flimflam::kLongNameProperty] = long_name;
466 }
467 }
468 }
469 return parsed;
470}
471
Darin Petkovae0c64e2011-11-15 15:50:27 +0100472void CellularCapabilityGSM::SetAccessTechnology(uint32 access_technology) {
473 access_technology_ = access_technology;
474 if (cellular()->service().get()) {
Darin Petkovb72cf402011-11-22 14:51:39 +0100475 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100476 }
477}
478
Darin Petkov20c13ec2011-11-09 15:07:15 +0100479string CellularCapabilityGSM::GetNetworkTechnologyString() const {
Darin Petkovb72cf402011-11-22 14:51:39 +0100480 switch (access_technology_) {
481 case MM_MODEM_GSM_ACCESS_TECH_GSM:
482 case MM_MODEM_GSM_ACCESS_TECH_GSM_COMPACT:
483 return flimflam::kNetworkTechnologyGsm;
484 case MM_MODEM_GSM_ACCESS_TECH_GPRS:
485 return flimflam::kNetworkTechnologyGprs;
486 case MM_MODEM_GSM_ACCESS_TECH_EDGE:
487 return flimflam::kNetworkTechnologyEdge;
488 case MM_MODEM_GSM_ACCESS_TECH_UMTS:
489 return flimflam::kNetworkTechnologyUmts;
490 case MM_MODEM_GSM_ACCESS_TECH_HSDPA:
491 case MM_MODEM_GSM_ACCESS_TECH_HSUPA:
492 case MM_MODEM_GSM_ACCESS_TECH_HSPA:
493 return flimflam::kNetworkTechnologyHspa;
494 case MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS:
495 return flimflam::kNetworkTechnologyHspaPlus;
496 default:
497 break;
Darin Petkov20c13ec2011-11-09 15:07:15 +0100498 }
499 return "";
500}
501
502string CellularCapabilityGSM::GetRoamingStateString() const {
Darin Petkov184c54e2011-11-15 12:44:39 +0100503 switch (registration_state_) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100504 case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME:
505 return flimflam::kRoamingStateHome;
506 case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING:
507 return flimflam::kRoamingStateRoaming;
508 default:
509 break;
510 }
511 return flimflam::kRoamingStateUnknown;
512}
513
Darin Petkovae0c64e2011-11-15 15:50:27 +0100514void CellularCapabilityGSM::OnModemManagerPropertiesChanged(
515 const DBusPropertiesMap &properties) {
516 uint32 access_technology = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
517 if (DBusProperties::GetUint32(properties,
518 kPropertyAccessTechnology,
519 &access_technology)) {
520 SetAccessTechnology(access_technology);
521 }
Darin Petkov721ac932011-11-16 15:43:09 +0100522 DBusProperties::GetString(
523 properties, kPropertyUnlockRequired, &sim_lock_status_.lock_type);
524 DBusProperties::GetUint32(
525 properties, kPropertyUnlockRetries, &sim_lock_status_.retries_left);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100526}
527
Darin Petkov184c54e2011-11-15 12:44:39 +0100528void CellularCapabilityGSM::OnGSMNetworkModeChanged(uint32 /*mode*/) {
529 // TODO(petkov): Implement this.
530 NOTIMPLEMENTED();
531}
532
533void CellularCapabilityGSM::OnGSMRegistrationInfoChanged(
534 uint32 status, const string &operator_code, const string &operator_name) {
535 registration_state_ = status;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100536 serving_operator_.SetCode(operator_code);
537 serving_operator_.SetName(operator_name);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100538 UpdateOperatorInfo();
Darin Petkov184c54e2011-11-15 12:44:39 +0100539 cellular()->HandleNewRegistrationState();
540}
541
542void CellularCapabilityGSM::OnGSMSignalQualityChanged(uint32 quality) {
543 cellular()->HandleNewSignalQuality(quality);
544}
545
Darin Petkovdaf43862011-10-27 11:37:28 +0200546} // namespace shill