blob: 7296bf9069dd51225da489b840915cb9e1551312 [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
14#include "shill/cellular.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 Petkov1272a432011-11-10 15:53:37 +010042 scanning_(false),
43 scan_interval_(0) {
44 PropertyStore *store = cellular->mutable_store();
Darin Petkov184c54e2011-11-15 12:44:39 +010045 store->RegisterConstString(flimflam::kSelectedNetworkProperty,
46 &selected_network_);
Darin Petkov1272a432011-11-10 15:53:37 +010047 store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
48 &found_networks_);
49 store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
50 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
Darin Petkov721ac932011-11-16 15:43:09 +010051 HelpRegisterDerivedStrIntPair(flimflam::kSIMLockStatusProperty,
52 &CellularCapabilityGSM::SimLockStatusToProperty,
53 NULL);
Darin Petkov1272a432011-11-10 15:53:37 +010054}
Darin Petkovdaf43862011-10-27 11:37:28 +020055
Darin Petkov721ac932011-11-16 15:43:09 +010056StrIntPair CellularCapabilityGSM::SimLockStatusToProperty(Error */*error*/) {
57 return StrIntPair(make_pair(flimflam::kSIMLockTypeProperty,
58 sim_lock_status_.lock_type),
59 make_pair(flimflam::kSIMLockRetriesLeftProperty,
60 sim_lock_status_.retries_left));
61}
62
63void CellularCapabilityGSM::HelpRegisterDerivedStrIntPair(
64 const string &name,
65 StrIntPair(CellularCapabilityGSM::*get)(Error *),
66 void(CellularCapabilityGSM::*set)(const StrIntPair &, Error *)) {
67 cellular()->mutable_store()->RegisterDerivedStrIntPair(
68 name,
69 StrIntPairAccessor(
70 new CustomAccessor<CellularCapabilityGSM, StrIntPair>(
71 this, get, set)));
72}
73
74void CellularCapabilityGSM::OnStart() {
Darin Petkovdaf43862011-10-27 11:37:28 +020075 VLOG(2) << __func__;
Darin Petkovcb547732011-11-09 13:55:26 +010076 card_proxy_.reset(
77 proxy_factory()->CreateModemGSMCardProxy(this,
Darin Petkovdaf43862011-10-27 11:37:28 +020078 cellular()->dbus_path(),
79 cellular()->dbus_owner()));
Darin Petkov184c54e2011-11-15 12:44:39 +010080 network_proxy_.reset(
81 proxy_factory()->CreateModemGSMNetworkProxy(this,
Darin Petkovdaf43862011-10-27 11:37:28 +020082 cellular()->dbus_path(),
83 cellular()->dbus_owner()));
84}
85
Darin Petkov721ac932011-11-16 15:43:09 +010086void CellularCapabilityGSM::OnStop() {
87 VLOG(2) << __func__;
88 card_proxy_.reset();
89 network_proxy_.reset();
90}
91
Darin Petkovae0c64e2011-11-15 15:50:27 +010092void CellularCapabilityGSM::UpdateStatus(const DBusPropertiesMap &properties) {
93 string imsi;
94 if (DBusProperties::GetString(properties, "imsi", &imsi)) {
95 // TODO(petkov): Set GSM provider based on IMSI and SPN.
96 }
97}
98
99void CellularCapabilityGSM::SetupConnectProperties(
100 DBusPropertiesMap *properties) {
101 (*properties)[Cellular::kConnectPropertyPhoneNumber].writer().append_string(
102 kPhoneNumber);
103 // TODO(petkov): Setup apn and "home_only".
104}
105
Darin Petkovcb547732011-11-09 13:55:26 +0100106void CellularCapabilityGSM::GetIdentifiers() {
107 VLOG(2) << __func__;
108 if (cellular()->imei().empty()) {
109 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
110 cellular()->set_imei(card_proxy_->GetIMEI());
111 VLOG(2) << "IMEI: " << cellular()->imei();
112 }
113 if (cellular()->imsi().empty()) {
114 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
115 cellular()->set_imsi(card_proxy_->GetIMSI());
116 VLOG(2) << "IMSI: " << cellular()->imsi();
117 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100118 if (spn_.empty()) {
Darin Petkovcb547732011-11-09 13:55:26 +0100119 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
120 try {
Darin Petkovae0c64e2011-11-15 15:50:27 +0100121 spn_ = card_proxy_->GetSPN();
122 VLOG(2) << "SPN: " << spn_;
Darin Petkovcb547732011-11-09 13:55:26 +0100123 } catch (const DBus::Error e) {
124 // Some modems don't support this call so catch the exception explicitly.
125 LOG(WARNING) << "Unable to obtain SPN: " << e.what();
126 }
127 }
128 if (cellular()->mdn().empty()) {
129 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
130 cellular()->set_mdn(card_proxy_->GetMSISDN());
131 VLOG(2) << "MSISDN/MDN: " << cellular()->mdn();
132 }
133}
134
Darin Petkov3e509242011-11-10 14:46:44 +0100135void CellularCapabilityGSM::GetSignalQuality() {
136 VLOG(2) << __func__;
137 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkov184c54e2011-11-15 12:44:39 +0100138 uint32 strength = network_proxy_->GetSignalQuality();
Darin Petkov3e509242011-11-10 14:46:44 +0100139 cellular()->HandleNewSignalQuality(strength);
140}
141
Darin Petkov184c54e2011-11-15 12:44:39 +0100142void CellularCapabilityGSM::GetRegistrationState() {
143 VLOG(2) << __func__;
144 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
145 ModemGSMNetworkProxyInterface::RegistrationInfo info =
146 network_proxy_->GetRegistrationInfo();
147 registration_state_ = info._1;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100148 network_id_ = info._2;
149 operator_name_ = info._3;
150 VLOG(2) << "GSM Registration: " << registration_state_ << ", "
151 << network_id_ << ", " << operator_name_;
152 UpdateOperatorInfo();
Darin Petkov184c54e2011-11-15 12:44:39 +0100153 cellular()->HandleNewRegistrationState();
154}
155
156void CellularCapabilityGSM::GetProperties() {
157 VLOG(2) << __func__;
158 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
159 uint32 tech = network_proxy_->AccessTechnology();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100160 SetAccessTechnology(tech);
Darin Petkov184c54e2011-11-15 12:44:39 +0100161 VLOG(2) << "GSM AccessTechnology: " << tech;
162}
163
Darin Petkovae0c64e2011-11-15 15:50:27 +0100164void CellularCapabilityGSM::UpdateOperatorInfo() {
165 VLOG(2) << __func__;
166 if (!network_id_.empty()) {
167 VLOG(2) << "Looking up network id: " << network_id_;
168 mobile_provider *provider =
169 mobile_provider_lookup_by_network(cellular()->provider_db(),
170 network_id_.c_str());
171 if (provider) {
172 const char *provider_name = mobile_provider_get_name(provider);
173 if (provider_name && *provider_name) {
174 operator_name_ = provider_name;
175 operator_country_ = provider->country;
176 VLOG(2) << "Operator name: " << operator_name_
177 << ", country: " << operator_country_;
178 }
179 } else {
180 VLOG(2) << "GSM provider not found.";
181 }
182 }
183 UpdateServingOperator();
184}
185
186void CellularCapabilityGSM::UpdateServingOperator() {
187 VLOG(2) << __func__;
188 if (!cellular()->service().get()) {
189 return;
190 }
191 Cellular::Operator oper;
192 oper.SetName(operator_name_);
193 oper.SetCode(network_id_);
194 oper.SetCountry(operator_country_);
195 cellular()->service()->set_serving_operator(oper);
196}
197
Darin Petkov184c54e2011-11-15 12:44:39 +0100198void CellularCapabilityGSM::Register() {
199 LOG(INFO) << __func__ << " \"" << selected_network_ << "\"";
200 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
201 network_proxy_->Register(selected_network_);
202 // TODO(petkov): Handle registration failure including trying the home network
203 // when selected_network_ is not empty.
204}
205
206void CellularCapabilityGSM::RegisterOnNetwork(
207 const string &network_id, Error */*error*/) {
208 LOG(INFO) << __func__ << "(" << network_id << ")";
209 // Defer because we may be in a dbus-c++ callback.
210 dispatcher()->PostTask(
211 task_factory_.NewRunnableMethod(
212 &CellularCapabilityGSM::RegisterOnNetworkTask,
213 network_id));
214}
215
216void CellularCapabilityGSM::RegisterOnNetworkTask(const string &network_id) {
217 LOG(INFO) << __func__ << "(" << network_id << ")";
218 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
219 network_proxy_->Register(network_id);
220 // TODO(petkov): Handle registration failure.
221 selected_network_ = network_id;
222}
223
Darin Petkovb05315f2011-11-07 10:14:25 +0100224void CellularCapabilityGSM::RequirePIN(
225 const string &pin, bool require, Error */*error*/) {
226 VLOG(2) << __func__ << "(" << pin << ", " << require << ")";
227 // Defer because we may be in a dbus-c++ callback.
228 dispatcher()->PostTask(
229 task_factory_.NewRunnableMethod(
230 &CellularCapabilityGSM::RequirePINTask, pin, require));
231}
232
233void CellularCapabilityGSM::RequirePINTask(const string &pin, bool require) {
234 VLOG(2) << __func__ << "(" << pin << ", " << require << ")";
235 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovcb547732011-11-09 13:55:26 +0100236 card_proxy_->EnablePIN(pin, require);
Darin Petkovb05315f2011-11-07 10:14:25 +0100237}
238
239void CellularCapabilityGSM::EnterPIN(const string &pin, Error */*error*/) {
240 VLOG(2) << __func__ << "(" << pin << ")";
241 // Defer because we may be in a dbus-c++ callback.
242 dispatcher()->PostTask(
243 task_factory_.NewRunnableMethod(
244 &CellularCapabilityGSM::EnterPINTask, pin));
245}
246
247void CellularCapabilityGSM::EnterPINTask(const string &pin) {
248 VLOG(2) << __func__ << "(" << pin << ")";
249 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovcb547732011-11-09 13:55:26 +0100250 card_proxy_->SendPIN(pin);
Darin Petkovb05315f2011-11-07 10:14:25 +0100251}
252
253void CellularCapabilityGSM::UnblockPIN(
254 const string &unblock_code, const string &pin, Error */*error*/) {
255 VLOG(2) << __func__ << "(" << unblock_code << ", " << pin << ")";
256 // Defer because we may be in a dbus-c++ callback.
257 dispatcher()->PostTask(
258 task_factory_.NewRunnableMethod(
259 &CellularCapabilityGSM::UnblockPINTask, unblock_code, pin));
260}
261
262void CellularCapabilityGSM::UnblockPINTask(
263 const string &unblock_code, const string &pin) {
264 VLOG(2) << __func__ << "(" << unblock_code << ", " << pin << ")";
265 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovcb547732011-11-09 13:55:26 +0100266 card_proxy_->SendPUK(unblock_code, pin);
Darin Petkovb05315f2011-11-07 10:14:25 +0100267}
268
269void CellularCapabilityGSM::ChangePIN(
270 const string &old_pin, const string &new_pin, Error */*error*/) {
271 VLOG(2) << __func__ << "(" << old_pin << ", " << new_pin << ")";
272 // Defer because we may be in a dbus-c++ callback.
273 dispatcher()->PostTask(
274 task_factory_.NewRunnableMethod(
275 &CellularCapabilityGSM::ChangePINTask, old_pin, new_pin));
276}
277
278void CellularCapabilityGSM::ChangePINTask(
279 const string &old_pin, const string &new_pin) {
280 VLOG(2) << __func__ << "(" << old_pin << ", " << new_pin << ")";
281 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovcb547732011-11-09 13:55:26 +0100282 card_proxy_->ChangePIN(old_pin, new_pin);
Darin Petkovb05315f2011-11-07 10:14:25 +0100283}
284
Darin Petkov1272a432011-11-10 15:53:37 +0100285void CellularCapabilityGSM::Scan(Error */*error*/) {
286 VLOG(2) << __func__;
287 // Defer because we may be in a dbus-c++ callback.
288 dispatcher()->PostTask(
289 task_factory_.NewRunnableMethod(&CellularCapabilityGSM::ScanTask));
290}
291
292void CellularCapabilityGSM::ScanTask() {
293 VLOG(2) << __func__;
294 // TODO(petkov): Defer scan requests if a scan is in progress already.
295 //
296 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583). This is a
297 // must for this call which is basically a stub at this point.
Darin Petkov184c54e2011-11-15 12:44:39 +0100298 ModemGSMNetworkProxyInterface::ScanResults results = network_proxy_->Scan();
Darin Petkov1272a432011-11-10 15:53:37 +0100299 found_networks_.clear();
300 for (ModemGSMNetworkProxyInterface::ScanResults::const_iterator it =
301 results.begin(); it != results.end(); ++it) {
302 found_networks_.push_back(ParseScanResult(*it));
303 }
304}
305
306Stringmap CellularCapabilityGSM::ParseScanResult(
307 const ModemGSMNetworkProxyInterface::ScanResult &result) {
308 Stringmap parsed;
309 for (ModemGSMNetworkProxyInterface::ScanResult::const_iterator it =
310 result.begin(); it != result.end(); ++it) {
311 // TODO(petkov): Define these in system_api/service_constants.h. The
312 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
313 static const char * const kStatusString[] = {
314 "unknown",
315 "available",
316 "current",
317 "forbidden",
318 };
319 static const char * const kTechnologyString[] = {
320 flimflam::kNetworkTechnologyGsm,
321 "GSM Compact",
322 flimflam::kNetworkTechnologyUmts,
323 flimflam::kNetworkTechnologyEdge,
324 "HSDPA",
325 "HSUPA",
326 flimflam::kNetworkTechnologyHspa,
327 };
328 VLOG(2) << "Network property: " << it->first << " = " << it->second;
329 if (it->first == kNetworkPropertyStatus) {
330 int status = 0;
331 if (base::StringToInt(it->second, &status) &&
332 status >= 0 &&
333 status < static_cast<int>(arraysize(kStatusString))) {
334 parsed[flimflam::kStatusProperty] = kStatusString[status];
335 } else {
336 LOG(ERROR) << "Unexpected status value: " << it->second;
337 }
338 } else if (it->first == kNetworkPropertyID) {
339 parsed[flimflam::kNetworkIdProperty] = it->second;
340 } else if (it->first == kNetworkPropertyLongName) {
341 parsed[flimflam::kLongNameProperty] = it->second;
342 } else if (it->first == kNetworkPropertyShortName) {
343 parsed[flimflam::kShortNameProperty] = it->second;
344 } else if (it->first == kNetworkPropertyAccessTechnology) {
345 int tech = 0;
346 if (base::StringToInt(it->second, &tech) &&
347 tech >= 0 &&
348 tech < static_cast<int>(arraysize(kTechnologyString))) {
349 parsed[flimflam::kTechnologyProperty] = kTechnologyString[tech];
350 } else {
351 LOG(ERROR) << "Unexpected technology value: " << it->second;
352 }
353 } else {
354 LOG(WARNING) << "Unknown network property ignored: " << it->first;
355 }
356 }
357 // If the long name is not available but the network ID is, look up the long
358 // name in the mobile provider database.
359 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
360 parsed[flimflam::kLongNameProperty].empty()) &&
361 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
362 mobile_provider *provider =
363 mobile_provider_lookup_by_network(
364 cellular()->provider_db(),
365 parsed[flimflam::kNetworkIdProperty].c_str());
366 if (provider) {
367 const char *long_name = mobile_provider_get_name(provider);
368 if (long_name && *long_name) {
369 parsed[flimflam::kLongNameProperty] = long_name;
370 }
371 }
372 }
373 return parsed;
374}
375
Darin Petkovae0c64e2011-11-15 15:50:27 +0100376void CellularCapabilityGSM::SetAccessTechnology(uint32 access_technology) {
377 access_technology_ = access_technology;
378 if (cellular()->service().get()) {
379 cellular()->service()->set_network_tech(GetNetworkTechnologyString());
380 }
381}
382
Darin Petkov20c13ec2011-11-09 15:07:15 +0100383string CellularCapabilityGSM::GetNetworkTechnologyString() const {
Darin Petkov184c54e2011-11-15 12:44:39 +0100384 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
385 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING) {
Darin Petkovae0c64e2011-11-15 15:50:27 +0100386 switch (access_technology_) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100387 case MM_MODEM_GSM_ACCESS_TECH_GSM:
388 case MM_MODEM_GSM_ACCESS_TECH_GSM_COMPACT:
389 return flimflam::kNetworkTechnologyGsm;
390 case MM_MODEM_GSM_ACCESS_TECH_GPRS:
391 return flimflam::kNetworkTechnologyGprs;
392 case MM_MODEM_GSM_ACCESS_TECH_EDGE:
393 return flimflam::kNetworkTechnologyEdge;
394 case MM_MODEM_GSM_ACCESS_TECH_UMTS:
395 return flimflam::kNetworkTechnologyUmts;
396 case MM_MODEM_GSM_ACCESS_TECH_HSDPA:
397 case MM_MODEM_GSM_ACCESS_TECH_HSUPA:
398 case MM_MODEM_GSM_ACCESS_TECH_HSPA:
399 return flimflam::kNetworkTechnologyHspa;
400 case MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS:
401 return flimflam::kNetworkTechnologyHspaPlus;
402 default:
403 NOTREACHED();
404 }
405 }
406 return "";
407}
408
409string CellularCapabilityGSM::GetRoamingStateString() const {
Darin Petkov184c54e2011-11-15 12:44:39 +0100410 switch (registration_state_) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100411 case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME:
412 return flimflam::kRoamingStateHome;
413 case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING:
414 return flimflam::kRoamingStateRoaming;
415 default:
416 break;
417 }
418 return flimflam::kRoamingStateUnknown;
419}
420
Darin Petkovae0c64e2011-11-15 15:50:27 +0100421void CellularCapabilityGSM::OnModemManagerPropertiesChanged(
422 const DBusPropertiesMap &properties) {
423 uint32 access_technology = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
424 if (DBusProperties::GetUint32(properties,
425 kPropertyAccessTechnology,
426 &access_technology)) {
427 SetAccessTechnology(access_technology);
428 }
Darin Petkov721ac932011-11-16 15:43:09 +0100429 DBusProperties::GetString(
430 properties, kPropertyUnlockRequired, &sim_lock_status_.lock_type);
431 DBusProperties::GetUint32(
432 properties, kPropertyUnlockRetries, &sim_lock_status_.retries_left);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100433}
434
435void CellularCapabilityGSM::OnServiceCreated() {
436 cellular()->service()->set_activation_state(
437 flimflam::kActivationStateActivated);
438 UpdateServingOperator();
439}
440
Darin Petkov184c54e2011-11-15 12:44:39 +0100441void CellularCapabilityGSM::OnGSMNetworkModeChanged(uint32 /*mode*/) {
442 // TODO(petkov): Implement this.
443 NOTIMPLEMENTED();
444}
445
446void CellularCapabilityGSM::OnGSMRegistrationInfoChanged(
447 uint32 status, const string &operator_code, const string &operator_name) {
448 registration_state_ = status;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100449 network_id_ = operator_code;
450 operator_name_ = operator_name;
451 UpdateOperatorInfo();
Darin Petkov184c54e2011-11-15 12:44:39 +0100452 cellular()->HandleNewRegistrationState();
453}
454
455void CellularCapabilityGSM::OnGSMSignalQualityChanged(uint32 quality) {
456 cellular()->HandleNewSignalQuality(quality);
457}
458
Darin Petkovdaf43862011-10-27 11:37:28 +0200459} // namespace shill