blob: c33cf14dffa8e0caaadcb9d0eb728858fc1ac4fb [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()) {
138 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
139 cellular()->set_mdn(card_proxy_->GetMSISDN());
140 VLOG(2) << "MSISDN/MDN: " << cellular()->mdn();
141 }
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100142 SetHomeProvider();
Darin Petkovcb547732011-11-09 13:55:26 +0100143}
144
Darin Petkov3e509242011-11-10 14:46:44 +0100145void CellularCapabilityGSM::GetSignalQuality() {
146 VLOG(2) << __func__;
147 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkov184c54e2011-11-15 12:44:39 +0100148 uint32 strength = network_proxy_->GetSignalQuality();
Darin Petkov3e509242011-11-10 14:46:44 +0100149 cellular()->HandleNewSignalQuality(strength);
150}
151
Darin Petkov184c54e2011-11-15 12:44:39 +0100152void CellularCapabilityGSM::GetRegistrationState() {
153 VLOG(2) << __func__;
154 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
155 ModemGSMNetworkProxyInterface::RegistrationInfo info =
156 network_proxy_->GetRegistrationInfo();
157 registration_state_ = info._1;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100158 serving_operator_.SetCode(info._2);
159 serving_operator_.SetName(info._3);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100160 VLOG(2) << "GSM Registration: " << registration_state_ << ", "
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100161 << serving_operator_.GetCode() << ", "
162 << serving_operator_.GetName();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100163 UpdateOperatorInfo();
Darin Petkov184c54e2011-11-15 12:44:39 +0100164 cellular()->HandleNewRegistrationState();
165}
166
167void CellularCapabilityGSM::GetProperties() {
168 VLOG(2) << __func__;
169 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
170 uint32 tech = network_proxy_->AccessTechnology();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100171 SetAccessTechnology(tech);
Darin Petkov184c54e2011-11-15 12:44:39 +0100172 VLOG(2) << "GSM AccessTechnology: " << tech;
173}
174
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100175void CellularCapabilityGSM::SetHomeProvider() {
176 VLOG(2) << __func__ << "(IMSI: " << cellular()->imsi()
177 << " SPN: " << spn_ << ")";
178 // TODO(petkov): The test for NULL provider_db should be done by
179 // mobile_provider_lookup_best_match.
180 if (cellular()->imsi().empty() || !cellular()->provider_db()) {
181 return;
182 }
183 mobile_provider *provider =
184 mobile_provider_lookup_best_match(
185 cellular()->provider_db(), spn_.c_str(), cellular()->imsi().c_str());
186 if (!provider) {
187 VLOG(2) << "GSM provider not found.";
188 return;
189 }
190 home_provider_ = provider;
191 Cellular::Operator oper;
192 if (provider->networks) {
193 oper.SetCode(provider->networks[0]);
194 }
195 if (provider->country) {
196 oper.SetCountry(provider->country);
197 }
198 if (spn_.empty()) {
199 const char *name = mobile_provider_get_name(provider);
200 if (name) {
201 oper.SetName(name);
202 }
203 } else {
204 oper.SetName(spn_);
205 }
206 cellular()->set_home_provider(oper);
Darin Petkov3cfbf212011-11-21 16:02:09 +0100207 InitAPNList();
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100208}
209
Darin Petkovae0c64e2011-11-15 15:50:27 +0100210void CellularCapabilityGSM::UpdateOperatorInfo() {
211 VLOG(2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100212 const string &network_id = serving_operator_.GetCode();
213 if (!network_id.empty()) {
214 VLOG(2) << "Looking up network id: " << network_id;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100215 mobile_provider *provider =
216 mobile_provider_lookup_by_network(cellular()->provider_db(),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100217 network_id.c_str());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100218 if (provider) {
219 const char *provider_name = mobile_provider_get_name(provider);
220 if (provider_name && *provider_name) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100221 serving_operator_.SetName(provider_name);
222 if (provider->country) {
223 serving_operator_.SetCountry(provider->country);
224 }
225 VLOG(2) << "Operator name: " << serving_operator_.GetName()
226 << ", country: " << serving_operator_.GetCountry();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100227 }
228 } else {
229 VLOG(2) << "GSM provider not found.";
230 }
231 }
232 UpdateServingOperator();
233}
234
235void CellularCapabilityGSM::UpdateServingOperator() {
236 VLOG(2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100237 if (cellular()->service().get()) {
238 cellular()->service()->set_serving_operator(serving_operator_);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100239 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100240}
241
Darin Petkov3cfbf212011-11-21 16:02:09 +0100242void CellularCapabilityGSM::InitAPNList() {
243 VLOG(2) << __func__;
244 if (!home_provider_) {
245 return;
246 }
247 apn_list_.clear();
248 for (int i = 0; i < home_provider_->num_apns; ++i) {
249 Stringmap props;
250 mobile_apn *apn = home_provider_->apns[i];
251 if (apn->value) {
252 props[flimflam::kApnProperty] = apn->value;
253 }
254 if (apn->username) {
255 props[flimflam::kApnUsernameProperty] = apn->username;
256 }
257 if (apn->password) {
258 props[flimflam::kApnPasswordProperty] = apn->password;
259 }
260 // Find the first localized and non-localized name, if any.
261 const localized_name *lname = NULL;
262 const localized_name *name = NULL;
263 for (int j = 0; j < apn->num_names; ++j) {
264 if (apn->names[j]->lang) {
265 if (!lname) {
266 lname = apn->names[j];
267 }
268 } else if (!name) {
269 name = apn->names[j];
270 }
271 }
272 if (name) {
273 props[flimflam::kApnNameProperty] = name->name;
274 }
275 if (lname) {
276 props[flimflam::kApnLocalizedNameProperty] = lname->name;
277 props[flimflam::kApnLanguageProperty] = lname->lang;
278 }
279 apn_list_.push_back(props);
280 }
281 cellular()->adaptor()->EmitStringmapsChanged(
282 flimflam::kCellularApnListProperty, apn_list_);
283}
284
Darin Petkov184c54e2011-11-15 12:44:39 +0100285void CellularCapabilityGSM::Register() {
286 LOG(INFO) << __func__ << " \"" << selected_network_ << "\"";
287 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
288 network_proxy_->Register(selected_network_);
289 // TODO(petkov): Handle registration failure including trying the home network
290 // when selected_network_ is not empty.
291}
292
293void CellularCapabilityGSM::RegisterOnNetwork(
294 const string &network_id, Error */*error*/) {
295 LOG(INFO) << __func__ << "(" << network_id << ")";
296 // Defer because we may be in a dbus-c++ callback.
297 dispatcher()->PostTask(
298 task_factory_.NewRunnableMethod(
299 &CellularCapabilityGSM::RegisterOnNetworkTask,
300 network_id));
301}
302
303void CellularCapabilityGSM::RegisterOnNetworkTask(const string &network_id) {
304 LOG(INFO) << __func__ << "(" << network_id << ")";
305 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
306 network_proxy_->Register(network_id);
307 // TODO(petkov): Handle registration failure.
308 selected_network_ = network_id;
309}
310
Darin Petkovb05315f2011-11-07 10:14:25 +0100311void CellularCapabilityGSM::RequirePIN(
312 const string &pin, bool require, Error */*error*/) {
313 VLOG(2) << __func__ << "(" << pin << ", " << require << ")";
314 // Defer because we may be in a dbus-c++ callback.
315 dispatcher()->PostTask(
316 task_factory_.NewRunnableMethod(
317 &CellularCapabilityGSM::RequirePINTask, pin, require));
318}
319
320void CellularCapabilityGSM::RequirePINTask(const string &pin, bool require) {
321 VLOG(2) << __func__ << "(" << pin << ", " << require << ")";
322 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovcb547732011-11-09 13:55:26 +0100323 card_proxy_->EnablePIN(pin, require);
Darin Petkovb05315f2011-11-07 10:14:25 +0100324}
325
326void CellularCapabilityGSM::EnterPIN(const string &pin, Error */*error*/) {
327 VLOG(2) << __func__ << "(" << pin << ")";
328 // Defer because we may be in a dbus-c++ callback.
329 dispatcher()->PostTask(
330 task_factory_.NewRunnableMethod(
331 &CellularCapabilityGSM::EnterPINTask, pin));
332}
333
334void CellularCapabilityGSM::EnterPINTask(const string &pin) {
335 VLOG(2) << __func__ << "(" << pin << ")";
336 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovcb547732011-11-09 13:55:26 +0100337 card_proxy_->SendPIN(pin);
Darin Petkovb05315f2011-11-07 10:14:25 +0100338}
339
340void CellularCapabilityGSM::UnblockPIN(
341 const string &unblock_code, const string &pin, Error */*error*/) {
342 VLOG(2) << __func__ << "(" << unblock_code << ", " << pin << ")";
343 // Defer because we may be in a dbus-c++ callback.
344 dispatcher()->PostTask(
345 task_factory_.NewRunnableMethod(
346 &CellularCapabilityGSM::UnblockPINTask, unblock_code, pin));
347}
348
349void CellularCapabilityGSM::UnblockPINTask(
350 const string &unblock_code, const string &pin) {
351 VLOG(2) << __func__ << "(" << unblock_code << ", " << pin << ")";
352 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovcb547732011-11-09 13:55:26 +0100353 card_proxy_->SendPUK(unblock_code, pin);
Darin Petkovb05315f2011-11-07 10:14:25 +0100354}
355
356void CellularCapabilityGSM::ChangePIN(
357 const string &old_pin, const string &new_pin, Error */*error*/) {
358 VLOG(2) << __func__ << "(" << old_pin << ", " << new_pin << ")";
359 // Defer because we may be in a dbus-c++ callback.
360 dispatcher()->PostTask(
361 task_factory_.NewRunnableMethod(
362 &CellularCapabilityGSM::ChangePINTask, old_pin, new_pin));
363}
364
365void CellularCapabilityGSM::ChangePINTask(
366 const string &old_pin, const string &new_pin) {
367 VLOG(2) << __func__ << "(" << old_pin << ", " << new_pin << ")";
368 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovcb547732011-11-09 13:55:26 +0100369 card_proxy_->ChangePIN(old_pin, new_pin);
Darin Petkovb05315f2011-11-07 10:14:25 +0100370}
371
Darin Petkov1272a432011-11-10 15:53:37 +0100372void CellularCapabilityGSM::Scan(Error */*error*/) {
373 VLOG(2) << __func__;
374 // Defer because we may be in a dbus-c++ callback.
375 dispatcher()->PostTask(
376 task_factory_.NewRunnableMethod(&CellularCapabilityGSM::ScanTask));
377}
378
379void CellularCapabilityGSM::ScanTask() {
380 VLOG(2) << __func__;
381 // TODO(petkov): Defer scan requests if a scan is in progress already.
382 //
383 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583). This is a
384 // must for this call which is basically a stub at this point.
Darin Petkov184c54e2011-11-15 12:44:39 +0100385 ModemGSMNetworkProxyInterface::ScanResults results = network_proxy_->Scan();
Darin Petkov1272a432011-11-10 15:53:37 +0100386 found_networks_.clear();
387 for (ModemGSMNetworkProxyInterface::ScanResults::const_iterator it =
388 results.begin(); it != results.end(); ++it) {
389 found_networks_.push_back(ParseScanResult(*it));
390 }
391}
392
393Stringmap CellularCapabilityGSM::ParseScanResult(
394 const ModemGSMNetworkProxyInterface::ScanResult &result) {
395 Stringmap parsed;
396 for (ModemGSMNetworkProxyInterface::ScanResult::const_iterator it =
397 result.begin(); it != result.end(); ++it) {
398 // TODO(petkov): Define these in system_api/service_constants.h. The
399 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
400 static const char * const kStatusString[] = {
401 "unknown",
402 "available",
403 "current",
404 "forbidden",
405 };
406 static const char * const kTechnologyString[] = {
407 flimflam::kNetworkTechnologyGsm,
408 "GSM Compact",
409 flimflam::kNetworkTechnologyUmts,
410 flimflam::kNetworkTechnologyEdge,
411 "HSDPA",
412 "HSUPA",
413 flimflam::kNetworkTechnologyHspa,
414 };
415 VLOG(2) << "Network property: " << it->first << " = " << it->second;
416 if (it->first == kNetworkPropertyStatus) {
417 int status = 0;
418 if (base::StringToInt(it->second, &status) &&
419 status >= 0 &&
420 status < static_cast<int>(arraysize(kStatusString))) {
421 parsed[flimflam::kStatusProperty] = kStatusString[status];
422 } else {
423 LOG(ERROR) << "Unexpected status value: " << it->second;
424 }
425 } else if (it->first == kNetworkPropertyID) {
426 parsed[flimflam::kNetworkIdProperty] = it->second;
427 } else if (it->first == kNetworkPropertyLongName) {
428 parsed[flimflam::kLongNameProperty] = it->second;
429 } else if (it->first == kNetworkPropertyShortName) {
430 parsed[flimflam::kShortNameProperty] = it->second;
431 } else if (it->first == kNetworkPropertyAccessTechnology) {
432 int tech = 0;
433 if (base::StringToInt(it->second, &tech) &&
434 tech >= 0 &&
435 tech < static_cast<int>(arraysize(kTechnologyString))) {
436 parsed[flimflam::kTechnologyProperty] = kTechnologyString[tech];
437 } else {
438 LOG(ERROR) << "Unexpected technology value: " << it->second;
439 }
440 } else {
441 LOG(WARNING) << "Unknown network property ignored: " << it->first;
442 }
443 }
444 // If the long name is not available but the network ID is, look up the long
445 // name in the mobile provider database.
446 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
447 parsed[flimflam::kLongNameProperty].empty()) &&
448 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
449 mobile_provider *provider =
450 mobile_provider_lookup_by_network(
451 cellular()->provider_db(),
452 parsed[flimflam::kNetworkIdProperty].c_str());
453 if (provider) {
454 const char *long_name = mobile_provider_get_name(provider);
455 if (long_name && *long_name) {
456 parsed[flimflam::kLongNameProperty] = long_name;
457 }
458 }
459 }
460 return parsed;
461}
462
Darin Petkovae0c64e2011-11-15 15:50:27 +0100463void CellularCapabilityGSM::SetAccessTechnology(uint32 access_technology) {
464 access_technology_ = access_technology;
465 if (cellular()->service().get()) {
466 cellular()->service()->set_network_tech(GetNetworkTechnologyString());
467 }
468}
469
Darin Petkov20c13ec2011-11-09 15:07:15 +0100470string CellularCapabilityGSM::GetNetworkTechnologyString() const {
Darin Petkov184c54e2011-11-15 12:44:39 +0100471 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
472 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING) {
Darin Petkovae0c64e2011-11-15 15:50:27 +0100473 switch (access_technology_) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100474 case MM_MODEM_GSM_ACCESS_TECH_GSM:
475 case MM_MODEM_GSM_ACCESS_TECH_GSM_COMPACT:
476 return flimflam::kNetworkTechnologyGsm;
477 case MM_MODEM_GSM_ACCESS_TECH_GPRS:
478 return flimflam::kNetworkTechnologyGprs;
479 case MM_MODEM_GSM_ACCESS_TECH_EDGE:
480 return flimflam::kNetworkTechnologyEdge;
481 case MM_MODEM_GSM_ACCESS_TECH_UMTS:
482 return flimflam::kNetworkTechnologyUmts;
483 case MM_MODEM_GSM_ACCESS_TECH_HSDPA:
484 case MM_MODEM_GSM_ACCESS_TECH_HSUPA:
485 case MM_MODEM_GSM_ACCESS_TECH_HSPA:
486 return flimflam::kNetworkTechnologyHspa;
487 case MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS:
488 return flimflam::kNetworkTechnologyHspaPlus;
489 default:
490 NOTREACHED();
491 }
492 }
493 return "";
494}
495
496string CellularCapabilityGSM::GetRoamingStateString() const {
Darin Petkov184c54e2011-11-15 12:44:39 +0100497 switch (registration_state_) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100498 case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME:
499 return flimflam::kRoamingStateHome;
500 case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING:
501 return flimflam::kRoamingStateRoaming;
502 default:
503 break;
504 }
505 return flimflam::kRoamingStateUnknown;
506}
507
Darin Petkovae0c64e2011-11-15 15:50:27 +0100508void CellularCapabilityGSM::OnModemManagerPropertiesChanged(
509 const DBusPropertiesMap &properties) {
510 uint32 access_technology = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
511 if (DBusProperties::GetUint32(properties,
512 kPropertyAccessTechnology,
513 &access_technology)) {
514 SetAccessTechnology(access_technology);
515 }
Darin Petkov721ac932011-11-16 15:43:09 +0100516 DBusProperties::GetString(
517 properties, kPropertyUnlockRequired, &sim_lock_status_.lock_type);
518 DBusProperties::GetUint32(
519 properties, kPropertyUnlockRetries, &sim_lock_status_.retries_left);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100520}
521
Darin Petkov184c54e2011-11-15 12:44:39 +0100522void CellularCapabilityGSM::OnGSMNetworkModeChanged(uint32 /*mode*/) {
523 // TODO(petkov): Implement this.
524 NOTIMPLEMENTED();
525}
526
527void CellularCapabilityGSM::OnGSMRegistrationInfoChanged(
528 uint32 status, const string &operator_code, const string &operator_name) {
529 registration_state_ = status;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100530 serving_operator_.SetCode(operator_code);
531 serving_operator_.SetName(operator_name);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100532 UpdateOperatorInfo();
Darin Petkov184c54e2011-11-15 12:44:39 +0100533 cellular()->HandleNewRegistrationState();
534}
535
536void CellularCapabilityGSM::OnGSMSignalQualityChanged(uint32 quality) {
537 cellular()->HandleNewSignalQuality(quality);
538}
539
Darin Petkovdaf43862011-10-27 11:37:28 +0200540} // namespace shill