blob: ff13300ce2820da4dec204ffe2ea060c5d2eb755 [file] [log] [blame]
Chris Masone3bd3c8c2011-06-13 08:20:26 -07001// 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.h"
6
Darin Petkov0828f5f2011-08-11 10:18:52 -07007#include <netinet/in.h>
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -07008#include <linux/if.h> // Needs definitions from netinet/in.h
Darin Petkov0828f5f2011-08-11 10:18:52 -07009
Chris Masone3bd3c8c2011-06-13 08:20:26 -070010#include <string>
Chris Masone889666b2011-07-03 12:58:50 -070011#include <utility>
12#include <vector>
Chris Masone3bd3c8c2011-06-13 08:20:26 -070013
14#include <base/logging.h>
Darin Petkovc0865312011-09-16 15:31:20 -070015#include <base/string_number_conversions.h>
Darin Petkove9d12e02011-07-27 15:09:37 -070016#include <base/stringprintf.h>
Chris Masoneb925cc82011-06-22 15:39:57 -070017#include <chromeos/dbus/service_constants.h>
Darin Petkovbec79a22011-08-01 14:47:17 -070018#include <mm/mm-modem.h>
Chris Masone3bd3c8c2011-06-13 08:20:26 -070019
20#include "shill/cellular_service.h"
21#include "shill/control_interface.h"
22#include "shill/device.h"
23#include "shill/device_info.h"
Darin Petkov4d6d9412011-08-24 13:19:54 -070024#include "shill/error.h"
Chris Masone3bd3c8c2011-06-13 08:20:26 -070025#include "shill/manager.h"
Darin Petkove604f702011-07-28 15:51:17 -070026#include "shill/modem_simple_proxy_interface.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070027#include "shill/profile.h"
Chris Masone889666b2011-07-03 12:58:50 -070028#include "shill/property_accessor.h"
Darin Petkove9d12e02011-07-27 15:09:37 -070029#include "shill/proxy_factory.h"
Darin Petkov0828f5f2011-08-11 10:18:52 -070030#include "shill/rtnl_handler.h"
Chris Masone3bd3c8c2011-06-13 08:20:26 -070031#include "shill/shill_event.h"
32
Chris Masone889666b2011-07-03 12:58:50 -070033using std::make_pair;
Darin Petkovc0865312011-09-16 15:31:20 -070034using std::map;
Chris Masone3bd3c8c2011-06-13 08:20:26 -070035using std::string;
Chris Masone889666b2011-07-03 12:58:50 -070036using std::vector;
Chris Masone3bd3c8c2011-06-13 08:20:26 -070037
38namespace shill {
39
Darin Petkovc5f56562011-08-06 16:40:05 -070040const char Cellular::kConnectPropertyPhoneNumber[] = "number";
Darin Petkovc0865312011-09-16 15:31:20 -070041const char Cellular::kNetworkPropertyAccessTechnology[] = "access-tech";
42const char Cellular::kNetworkPropertyID[] = "operator-num";
43const char Cellular::kNetworkPropertyLongName[] = "operator-long";
44const char Cellular::kNetworkPropertyShortName[] = "operator-short";
45const char Cellular::kNetworkPropertyStatus[] = "status";
Darin Petkovc5f56562011-08-06 16:40:05 -070046const char Cellular::kPhoneNumberCDMA[] = "#777";
47const char Cellular::kPhoneNumberGSM[] = "*99#";
48
Darin Petkov3335b372011-08-22 11:05:32 -070049Cellular::Operator::Operator() {
50 SetName("");
51 SetCode("");
52 SetCountry("");
53}
54
55Cellular::Operator::~Operator() {}
56
57void Cellular::Operator::CopyFrom(const Operator &oper) {
58 dict_ = oper.dict_;
59}
60
61const string &Cellular::Operator::GetName() const {
62 return dict_.find(flimflam::kOperatorNameKey)->second;
63}
64
65void Cellular::Operator::SetName(const string &name) {
66 dict_[flimflam::kOperatorNameKey] = name;
67}
68
69const string &Cellular::Operator::GetCode() const {
70 return dict_.find(flimflam::kOperatorCodeKey)->second;
71}
72
73void Cellular::Operator::SetCode(const string &code) {
74 dict_[flimflam::kOperatorCodeKey] = code;
75}
76
77const string &Cellular::Operator::GetCountry() const {
78 return dict_.find(flimflam::kOperatorCountryKey)->second;
79}
80
81void Cellular::Operator::SetCountry(const string &country) {
82 dict_[flimflam::kOperatorCountryKey] = country;
83}
84
85const Stringmap &Cellular::Operator::ToDict() const {
86 return dict_;
87}
88
Darin Petkovbec79a22011-08-01 14:47:17 -070089Cellular::CDMA::CDMA()
90 : registration_state_evdo(MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN),
91 registration_state_1x(MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN),
Darin Petkovcc044422011-08-17 13:30:06 -070092 activation_state(MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED),
93 prl_version(0) {}
Darin Petkovbec79a22011-08-01 14:47:17 -070094
Darin Petkov9bac6fe2011-08-26 12:49:05 -070095Cellular::GSM::GSM()
96 : registration_state(MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN),
97 access_technology(MM_MODEM_GSM_ACCESS_TECH_UNKNOWN) {}
98
Chris Masone3bd3c8c2011-06-13 08:20:26 -070099Cellular::Cellular(ControlInterface *control_interface,
100 EventDispatcher *dispatcher,
101 Manager *manager,
Darin Petkove9d12e02011-07-27 15:09:37 -0700102 const string &link_name,
Darin Petkov3335b372011-08-22 11:05:32 -0700103 const string &address,
Darin Petkove9d12e02011-07-27 15:09:37 -0700104 int interface_index,
105 Type type,
106 const string &owner,
107 const string &path)
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700108 : Device(control_interface,
109 dispatcher,
110 manager,
Darin Petkove9d12e02011-07-27 15:09:37 -0700111 link_name,
Chris Masone626719f2011-08-18 16:58:48 -0700112 address,
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700113 interface_index),
Darin Petkovab565bb2011-10-06 02:55:51 -0700114 proxy_factory_(ProxyFactory::GetInstance()),
Darin Petkove9d12e02011-07-27 15:09:37 -0700115 type_(type),
116 state_(kStateDisabled),
Darin Petkovbac96002011-08-09 13:22:00 -0700117 modem_state_(kModemStateUnknown),
Darin Petkove9d12e02011-07-27 15:09:37 -0700118 dbus_owner_(owner),
119 dbus_path_(path),
Darin Petkovc5f56562011-08-06 16:40:05 -0700120 task_factory_(this),
Darin Petkove9d12e02011-07-27 15:09:37 -0700121 allow_roaming_(false),
Darin Petkove9d12e02011-07-27 15:09:37 -0700122 scanning_(false),
123 scan_interval_(0) {
mukesh agrawalde29fa82011-09-16 16:16:36 -0700124 PropertyStore *store = this->mutable_store();
Paul Stewartac4ac002011-08-26 12:04:26 -0700125 store->RegisterConstString(flimflam::kCarrierProperty, &carrier_);
126 store->RegisterConstString(flimflam::kDBusConnectionProperty, &dbus_owner_);
127 store->RegisterConstString(flimflam::kDBusObjectProperty, &dbus_path_);
128 store->RegisterBool(flimflam::kCellularAllowRoamingProperty, &allow_roaming_);
129 store->RegisterConstString(flimflam::kEsnProperty, &esn_);
130 store->RegisterConstString(flimflam::kFirmwareRevisionProperty,
Chris Masone27c4aa52011-07-02 13:10:14 -0700131 &firmware_revision_);
Darin Petkovc0865312011-09-16 15:31:20 -0700132 store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
133 &found_networks_);
Paul Stewartac4ac002011-08-26 12:04:26 -0700134 store->RegisterConstString(flimflam::kHardwareRevisionProperty,
Chris Masone27c4aa52011-07-02 13:10:14 -0700135 &hardware_revision_);
Paul Stewartac4ac002011-08-26 12:04:26 -0700136 store->RegisterConstStringmap(flimflam::kHomeProviderProperty,
Darin Petkov3335b372011-08-22 11:05:32 -0700137 &home_provider_.ToDict());
Paul Stewartac4ac002011-08-26 12:04:26 -0700138 store->RegisterConstString(flimflam::kImeiProperty, &imei_);
139 store->RegisterConstString(flimflam::kImsiProperty, &imsi_);
140 store->RegisterConstString(flimflam::kManufacturerProperty, &manufacturer_);
141 store->RegisterConstString(flimflam::kMdnProperty, &mdn_);
142 store->RegisterConstString(flimflam::kMeidProperty, &meid_);
143 store->RegisterConstString(flimflam::kMinProperty, &min_);
144 store->RegisterConstString(flimflam::kModelIDProperty, &model_id_);
145 store->RegisterConstUint16(flimflam::kPRLVersionProperty, &cdma_.prl_version);
146 store->RegisterConstString(flimflam::kSelectedNetworkProperty,
Darin Petkova1e0a1c2011-08-25 15:08:33 -0700147 &selected_network_);
Chris Masoneb925cc82011-06-22 15:39:57 -0700148
Chris Masone889666b2011-07-03 12:58:50 -0700149 HelpRegisterDerivedStrIntPair(flimflam::kSIMLockStatusProperty,
150 &Cellular::SimLockStatusToProperty,
151 NULL);
Chris Masoneb925cc82011-06-22 15:39:57 -0700152
Paul Stewartac4ac002011-08-26 12:04:26 -0700153 store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
154 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
Chris Masone4d42df82011-07-02 17:09:39 -0700155
Paul Stewartac4ac002011-08-26 12:04:26 -0700156 VLOG(2) << "Cellular device " << this->link_name() << " initialized: "
Darin Petkove9d12e02011-07-27 15:09:37 -0700157 << GetTypeString();
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700158}
159
Darin Petkove9d12e02011-07-27 15:09:37 -0700160Cellular::~Cellular() {}
161
Darin Petkovcc044422011-08-17 13:30:06 -0700162string Cellular::GetTypeString() const {
Darin Petkove9d12e02011-07-27 15:09:37 -0700163 switch (type_) {
164 case kTypeGSM: return "CellularTypeGSM";
165 case kTypeCDMA: return "CellularTypeCDMA";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700166 default: NOTREACHED();
Darin Petkove9d12e02011-07-27 15:09:37 -0700167 }
Darin Petkov0828f5f2011-08-11 10:18:52 -0700168 return StringPrintf("CellularTypeUnknown-%d", type_);
Darin Petkove9d12e02011-07-27 15:09:37 -0700169}
170
Darin Petkovcc044422011-08-17 13:30:06 -0700171// static
172string Cellular::GetStateString(State state) {
173 switch (state) {
Darin Petkove9d12e02011-07-27 15:09:37 -0700174 case kStateDisabled: return "CellularStateDisabled";
175 case kStateEnabled: return "CellularStateEnabled";
176 case kStateRegistered: return "CellularStateRegistered";
177 case kStateConnected: return "CellularStateConnected";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700178 case kStateLinked: return "CellularStateLinked";
179 default: NOTREACHED();
Darin Petkove9d12e02011-07-27 15:09:37 -0700180 }
Darin Petkovcc044422011-08-17 13:30:06 -0700181 return StringPrintf("CellularStateUnknown-%d", state);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700182}
183
Darin Petkovd2045802011-08-23 11:09:25 -0700184string Cellular::GetNetworkTechnologyString() const {
185 switch (type_) {
186 case kTypeGSM:
Darin Petkov9bac6fe2011-08-26 12:49:05 -0700187 if (gsm_.registration_state == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
188 gsm_.registration_state == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING) {
189 switch (gsm_.access_technology) {
190 case MM_MODEM_GSM_ACCESS_TECH_GSM:
191 case MM_MODEM_GSM_ACCESS_TECH_GSM_COMPACT:
Darin Petkove1a3e242011-08-29 12:44:30 -0700192 return flimflam::kNetworkTechnologyGsm;
Darin Petkov9bac6fe2011-08-26 12:49:05 -0700193 case MM_MODEM_GSM_ACCESS_TECH_GPRS:
194 return flimflam::kNetworkTechnologyGprs;
195 case MM_MODEM_GSM_ACCESS_TECH_EDGE:
196 return flimflam::kNetworkTechnologyEdge;
197 case MM_MODEM_GSM_ACCESS_TECH_UMTS:
198 return flimflam::kNetworkTechnologyUmts;
199 case MM_MODEM_GSM_ACCESS_TECH_HSDPA:
200 case MM_MODEM_GSM_ACCESS_TECH_HSUPA:
201 case MM_MODEM_GSM_ACCESS_TECH_HSPA:
202 return flimflam::kNetworkTechnologyHspa;
203 case MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS:
204 return flimflam::kNetworkTechnologyHspaPlus;
205 default:
206 NOTREACHED();
207 }
208 }
Darin Petkovd2045802011-08-23 11:09:25 -0700209 break;
210 case kTypeCDMA:
211 if (cdma_.registration_state_evdo !=
212 MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN) {
213 return flimflam::kNetworkTechnologyEvdo;
214 }
215 if (cdma_.registration_state_1x !=
216 MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN) {
217 return flimflam::kNetworkTechnology1Xrtt;
218 }
219 break;
220 default:
221 NOTREACHED();
222 }
223 return "";
224}
225
226string Cellular::GetRoamingStateString() const {
227 switch (type_) {
228 case kTypeGSM:
Darin Petkov9bac6fe2011-08-26 12:49:05 -0700229 switch (gsm_.registration_state) {
230 case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME:
231 return flimflam::kRoamingStateHome;
232 case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING:
233 return flimflam::kRoamingStateRoaming;
234 default:
235 break;
236 }
Darin Petkovd2045802011-08-23 11:09:25 -0700237 break;
238 case kTypeCDMA: {
239 uint32 state = cdma_.registration_state_evdo;
240 if (state == MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN) {
241 state = cdma_.registration_state_1x;
242 }
243 switch (state) {
244 case MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN:
245 case MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED:
246 break;
247 case MM_MODEM_CDMA_REGISTRATION_STATE_HOME:
248 return flimflam::kRoamingStateHome;
249 case MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING:
250 return flimflam::kRoamingStateRoaming;
251 default:
252 NOTREACHED();
253 }
254 break;
255 }
256 default:
257 NOTREACHED();
258 }
259 return flimflam::kRoamingStateUnknown;
260}
261
Darin Petkovc408e692011-08-17 13:47:15 -0700262// static
263string Cellular::GetCDMAActivationStateString(uint32 state) {
264 switch (state) {
265 case MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED:
Darin Petkov51489002011-08-18 13:13:20 -0700266 return flimflam::kActivationStateActivated;
Darin Petkovc408e692011-08-17 13:47:15 -0700267 case MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING:
Darin Petkov51489002011-08-18 13:13:20 -0700268 return flimflam::kActivationStateActivating;
Darin Petkovc408e692011-08-17 13:47:15 -0700269 case MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED:
Darin Petkov51489002011-08-18 13:13:20 -0700270 return flimflam::kActivationStateNotActivated;
Darin Petkovc408e692011-08-17 13:47:15 -0700271 case MM_MODEM_CDMA_ACTIVATION_STATE_PARTIALLY_ACTIVATED:
Darin Petkov51489002011-08-18 13:13:20 -0700272 return flimflam::kActivationStatePartiallyActivated;
Darin Petkovc408e692011-08-17 13:47:15 -0700273 default:
Darin Petkov51489002011-08-18 13:13:20 -0700274 return flimflam::kActivationStateUnknown;
275 }
276}
277
278// static
279string Cellular::GetCDMAActivationErrorString(uint32 error) {
280 switch (error) {
281 case MM_MODEM_CDMA_ACTIVATION_ERROR_WRONG_RADIO_INTERFACE:
282 return flimflam::kErrorNeedEvdo;
283 case MM_MODEM_CDMA_ACTIVATION_ERROR_ROAMING:
284 return flimflam::kErrorNeedHomeNetwork;
285 case MM_MODEM_CDMA_ACTIVATION_ERROR_COULD_NOT_CONNECT:
286 case MM_MODEM_CDMA_ACTIVATION_ERROR_SECURITY_AUTHENTICATION_FAILED:
287 case MM_MODEM_CDMA_ACTIVATION_ERROR_PROVISIONING_FAILED:
288 return flimflam::kErrorOtaspFailed;
289 case MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR:
290 return "";
291 case MM_MODEM_CDMA_ACTIVATION_ERROR_NO_SIGNAL:
292 default:
293 return flimflam::kErrorActivationFailed;
Darin Petkovc408e692011-08-17 13:47:15 -0700294 }
295}
296
Darin Petkov0828f5f2011-08-11 10:18:52 -0700297void Cellular::SetState(State state) {
Darin Petkovcc044422011-08-17 13:30:06 -0700298 VLOG(2) << GetStateString(state_) << " -> " << GetStateString(state);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700299 state_ = state;
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700300}
301
302void Cellular::Start() {
Darin Petkovcc044422011-08-17 13:30:06 -0700303 LOG(INFO) << __func__ << ": " << GetStateString(state_);
Darin Petkov3335b372011-08-22 11:05:32 -0700304 Device::Start();
Darin Petkovbec79a22011-08-01 14:47:17 -0700305 InitProxies();
Darin Petkovf5f61e02011-07-29 11:35:40 -0700306 EnableModem();
Darin Petkovceb68172011-07-29 14:47:48 -0700307 if (type_ == kTypeGSM) {
308 RegisterGSMModem();
309 }
Darin Petkovf5f61e02011-07-29 11:35:40 -0700310 GetModemStatus();
Darin Petkovceb68172011-07-29 14:47:48 -0700311 GetModemIdentifiers();
312 if (type_ == kTypeGSM) {
313 GetGSMProperties();
314 }
315 GetModemInfo();
316 GetModemRegistrationState();
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700317}
318
319void Cellular::Stop() {
Darin Petkove9d12e02011-07-27 15:09:37 -0700320 proxy_.reset();
Darin Petkove604f702011-07-28 15:51:17 -0700321 simple_proxy_.reset();
Darin Petkovbec79a22011-08-01 14:47:17 -0700322 cdma_proxy_.reset();
Darin Petkove42e1012011-08-31 12:35:04 -0700323 gsm_card_proxy_.reset();
324 gsm_network_proxy_.reset();
Paul Stewartac4ac002011-08-26 12:04:26 -0700325 manager()->DeregisterService(service_);
Darin Petkove9d12e02011-07-27 15:09:37 -0700326 service_ = NULL; // Breaks a reference cycle.
Darin Petkov0828f5f2011-08-11 10:18:52 -0700327 SetState(kStateDisabled);
Darin Petkov3335b372011-08-22 11:05:32 -0700328 Device::Stop();
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700329}
330
Darin Petkovbec79a22011-08-01 14:47:17 -0700331void Cellular::InitProxies() {
Darin Petkovcc044422011-08-17 13:30:06 -0700332 VLOG(2) << __func__;
Darin Petkovab565bb2011-10-06 02:55:51 -0700333 proxy_.reset(proxy_factory_->CreateModemProxy(this, dbus_path_, dbus_owner_));
Darin Petkovbec79a22011-08-01 14:47:17 -0700334 simple_proxy_.reset(
Darin Petkovab565bb2011-10-06 02:55:51 -0700335 proxy_factory_->CreateModemSimpleProxy(dbus_path_, dbus_owner_));
Darin Petkovbec79a22011-08-01 14:47:17 -0700336 switch (type_) {
337 case kTypeGSM:
Darin Petkov975b5e72011-08-30 11:48:08 -0700338 gsm_card_proxy_.reset(
Darin Petkovab565bb2011-10-06 02:55:51 -0700339 proxy_factory_->CreateModemGSMCardProxy(
Darin Petkov975b5e72011-08-30 11:48:08 -0700340 this, dbus_path_, dbus_owner_));
Darin Petkova1e0a1c2011-08-25 15:08:33 -0700341 gsm_network_proxy_.reset(
Darin Petkovab565bb2011-10-06 02:55:51 -0700342 proxy_factory_->CreateModemGSMNetworkProxy(
Darin Petkova1e0a1c2011-08-25 15:08:33 -0700343 this, dbus_path_, dbus_owner_));
Darin Petkovbec79a22011-08-01 14:47:17 -0700344 break;
345 case kTypeCDMA:
346 cdma_proxy_.reset(
Darin Petkovab565bb2011-10-06 02:55:51 -0700347 proxy_factory_->CreateModemCDMAProxy(this, dbus_path_, dbus_owner_));
Darin Petkovbec79a22011-08-01 14:47:17 -0700348 break;
349 default: NOTREACHED();
350 }
351}
352
Darin Petkovf5f61e02011-07-29 11:35:40 -0700353void Cellular::EnableModem() {
354 CHECK_EQ(kStateDisabled, state_);
355 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
356 proxy_->Enable(true);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700357 SetState(kStateEnabled);
Darin Petkovf5f61e02011-07-29 11:35:40 -0700358}
359
360void Cellular::GetModemStatus() {
Darin Petkovceb68172011-07-29 14:47:48 -0700361 CHECK_EQ(kStateEnabled, state_);
Darin Petkovf5f61e02011-07-29 11:35:40 -0700362 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
363 DBusPropertiesMap properties = simple_proxy_->GetStatus();
Darin Petkovceb68172011-07-29 14:47:48 -0700364 if (DBusProperties::GetString(properties, "carrier", &carrier_) &&
365 type_ == kTypeCDMA) {
Darin Petkov3335b372011-08-22 11:05:32 -0700366 home_provider_.SetName(carrier_);
367 home_provider_.SetCode("");
368 home_provider_.SetCountry("us");
Darin Petkovf5f61e02011-07-29 11:35:40 -0700369 }
Darin Petkovceb68172011-07-29 14:47:48 -0700370 DBusProperties::GetString(properties, "meid", &meid_);
371 DBusProperties::GetString(properties, "imei", &imei_);
372 if (DBusProperties::GetString(properties, "imsi", &imsi_) &&
373 type_ == kTypeGSM) {
374 // TODO(petkov): Set GSM provider.
375 }
376 DBusProperties::GetString(properties, "esn", &esn_);
377 DBusProperties::GetString(properties, "mdn", &mdn_);
378 DBusProperties::GetString(properties, "min", &min_);
Darin Petkovceb68172011-07-29 14:47:48 -0700379 DBusProperties::GetString(
380 properties, "firmware_revision", &firmware_revision_);
Darin Petkovb27e5442011-08-16 14:36:45 -0700381
Darin Petkovd2045802011-08-23 11:09:25 -0700382 uint32 state = 0;
383 if (DBusProperties::GetUint32(properties, "state", &state)) {
384 modem_state_ = static_cast<ModemState>(state);
385 }
Darin Petkovb27e5442011-08-16 14:36:45 -0700386
Darin Petkovceb68172011-07-29 14:47:48 -0700387 if (type_ == kTypeCDMA) {
Darin Petkovc408e692011-08-17 13:47:15 -0700388 DBusProperties::GetUint32(
389 properties, "activation_state", &cdma_.activation_state);
Darin Petkovcc044422011-08-17 13:30:06 -0700390 DBusProperties::GetUint16(properties, "prl_version", &cdma_.prl_version);
Darin Petkovcc044422011-08-17 13:30:06 -0700391 // TODO(petkov): For now, get the payment and usage URLs from ModemManager
392 // to match flimflam. In the future, provide a plugin API to get these
393 // directly from the modem driver.
394 DBusProperties::GetString(properties, "payment_url", &cdma_.payment_url);
395 DBusProperties::GetString(properties, "usage_url", &cdma_.usage_url);
Darin Petkovceb68172011-07-29 14:47:48 -0700396 }
397}
398
399void Cellular::GetModemIdentifiers() {
Darin Petkov975b5e72011-08-30 11:48:08 -0700400 VLOG(2) << __func__;
401 switch (type_) {
402 case kTypeGSM:
403 GetGSMIdentifiers();
404 break;
405 case kTypeCDMA:
406 GetCDMAIdentifiers();
407 break;
408 default: NOTREACHED();
409 }
410}
411
412void Cellular::GetCDMAIdentifiers() {
413 CHECK_EQ(kTypeCDMA, type_);
414 if (meid_.empty()) {
415 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
416 meid_ = cdma_proxy_->MEID();
417 VLOG(2) << "MEID: " << imei_;
418 }
419}
420
421void Cellular::GetGSMIdentifiers() {
422 CHECK_EQ(kTypeGSM, type_);
423 if (imei_.empty()) {
424 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
425 imei_ = gsm_card_proxy_->GetIMEI();
426 VLOG(2) << "IMEI: " << imei_;
427 }
428 if (imsi_.empty()) {
429 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
430 imsi_ = gsm_card_proxy_->GetIMSI();
431 VLOG(2) << "IMSI: " << imsi_;
432 }
433 if (gsm_.spn.empty()) {
434 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
435 try {
436 gsm_.spn = gsm_card_proxy_->GetSPN();
437 VLOG(2) << "SPN: " << gsm_.spn;
438 } catch (const DBus::Error e) {
439 // Some modems don't support this call so catch the exception explicitly.
440 LOG(WARNING) << "Unable to obtain SPN: " << e.what();
441 }
442 }
443 if (mdn_.empty()) {
444 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
445 mdn_ = gsm_card_proxy_->GetMSISDN();
446 VLOG(2) << "MSISDN/MDN: " << mdn_;
447 }
Darin Petkovceb68172011-07-29 14:47:48 -0700448}
449
450void Cellular::GetGSMProperties() {
Darin Petkov975b5e72011-08-30 11:48:08 -0700451 CHECK_EQ(kTypeGSM, type_);
Darin Petkov9bac6fe2011-08-26 12:49:05 -0700452 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
453 gsm_.access_technology = gsm_network_proxy_->AccessTechnology();
454 VLOG(2) << "GSM AccessTechnology: " << gsm_.access_technology;
Darin Petkovceb68172011-07-29 14:47:48 -0700455}
456
457void Cellular::RegisterGSMModem() {
Darin Petkov975b5e72011-08-30 11:48:08 -0700458 CHECK_EQ(kTypeGSM, type_);
Darin Petkov9ae310f2011-08-30 15:41:13 -0700459 LOG(INFO) << "Registering on \"" << selected_network_ << "\"";
Darin Petkova1e0a1c2011-08-25 15:08:33 -0700460 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
461 gsm_network_proxy_->Register(selected_network_);
Darin Petkov9ae310f2011-08-30 15:41:13 -0700462 // TODO(petkov): Handle registration failure including trying the home network
463 // when selected_network_ is not empty.
464}
465
466void Cellular::RegisterOnNetwork(const string &network_id, Error *error) {
467 LOG(INFO) << __func__ << "(" << network_id << ")";
468 if (type_ != kTypeGSM) {
469 const string kMessage = "Network registration supported only for GSM.";
470 LOG(ERROR) << kMessage;
471 CHECK(error);
472 error->Populate(Error::kNotSupported, kMessage);
473 return;
474 }
475 // Defer registration because we may be in a dbus-c++ callback.
476 dispatcher()->PostTask(
477 task_factory_.NewRunnableMethod(&Cellular::RegisterOnNetworkTask,
478 network_id));
479}
480
481void Cellular::RegisterOnNetworkTask(const string &network_id) {
482 LOG(INFO) << __func__ << "(" << network_id << ")";
Darin Petkove42e1012011-08-31 12:35:04 -0700483 CHECK_EQ(kTypeGSM, type_);
Darin Petkov9ae310f2011-08-30 15:41:13 -0700484 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
485 gsm_network_proxy_->Register(network_id);
486 // TODO(petkov): Handle registration failure.
487 selected_network_ = network_id;
Darin Petkovceb68172011-07-29 14:47:48 -0700488}
489
Darin Petkove42e1012011-08-31 12:35:04 -0700490void Cellular::RequirePIN(const string &pin, bool require, Error *error) {
491 VLOG(2) << __func__ << "(" << pin << ", " << require << ")";
492 if (type_ != kTypeGSM) {
493 const string kMessage = "RequirePIN supported only for GSM.";
494 LOG(ERROR) << kMessage;
495 CHECK(error);
496 error->Populate(Error::kNotSupported, kMessage);
497 return;
498 }
499 // Defer registration because we may be in a dbus-c++ callback.
500 dispatcher()->PostTask(
501 task_factory_.NewRunnableMethod(&Cellular::RequirePINTask, pin, require));
502}
503
504void Cellular::RequirePINTask(const string &pin, bool require) {
505 VLOG(2) << __func__ << "(" << pin << ", " << require << ")";
506 CHECK_EQ(kTypeGSM, type_);
507 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
508 gsm_card_proxy_->EnablePIN(pin, require);
509}
510
511void Cellular::EnterPIN(const string &pin, Error *error) {
512 VLOG(2) << __func__ << "(" << pin << ")";
513 if (type_ != kTypeGSM) {
514 const string kMessage = "EnterPIN supported only for GSM.";
515 LOG(ERROR) << kMessage;
516 CHECK(error);
517 error->Populate(Error::kNotSupported, kMessage);
518 return;
519 }
520 // Defer registration because we may be in a dbus-c++ callback.
521 dispatcher()->PostTask(
522 task_factory_.NewRunnableMethod(&Cellular::EnterPINTask, pin));
523}
524
525void Cellular::EnterPINTask(const string &pin) {
526 VLOG(2) << __func__ << "(" << pin << ")";
527 CHECK_EQ(kTypeGSM, type_);
528 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
529 gsm_card_proxy_->SendPIN(pin);
530}
531
532void Cellular::UnblockPIN(const string &unblock_code,
533 const string &pin,
534 Error *error) {
535 VLOG(2) << __func__ << "(" << unblock_code << ", " << pin << ")";
536 if (type_ != kTypeGSM) {
537 const string kMessage = "UnblockPIN supported only for GSM.";
538 LOG(ERROR) << kMessage;
539 CHECK(error);
540 error->Populate(Error::kNotSupported, kMessage);
541 return;
542 }
543 // Defer registration because we may be in a dbus-c++ callback.
544 dispatcher()->PostTask(
545 task_factory_.NewRunnableMethod(
546 &Cellular::UnblockPINTask, unblock_code, pin));
547}
548
549void Cellular::UnblockPINTask(const string &unblock_code, const string &pin) {
550 VLOG(2) << __func__ << "(" << unblock_code << ", " << pin << ")";
551 CHECK_EQ(kTypeGSM, type_);
552 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
553 gsm_card_proxy_->SendPUK(unblock_code, pin);
554}
555
556void Cellular::ChangePIN(const string &old_pin,
557 const string &new_pin,
558 Error *error) {
559 VLOG(2) << __func__ << "(" << old_pin << ", " << new_pin << ")";
560 if (type_ != kTypeGSM) {
561 const string kMessage = "ChangePIN supported only for GSM.";
562 LOG(ERROR) << kMessage;
563 CHECK(error);
564 error->Populate(Error::kNotSupported, kMessage);
565 return;
566 }
567 // Defer registration because we may be in a dbus-c++ callback.
568 dispatcher()->PostTask(
569 task_factory_.NewRunnableMethod(
570 &Cellular::ChangePINTask, old_pin, new_pin));
571}
572
573void Cellular::ChangePINTask(const string &old_pin, const string &new_pin) {
574 VLOG(2) << __func__ << "(" << old_pin << ", " << new_pin << ")";
575 CHECK_EQ(kTypeGSM, type_);
576 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
577 gsm_card_proxy_->ChangePIN(old_pin, new_pin);
578}
579
Darin Petkovceb68172011-07-29 14:47:48 -0700580void Cellular::GetModemInfo() {
Darin Petkovd2045802011-08-23 11:09:25 -0700581 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovceb68172011-07-29 14:47:48 -0700582 ModemProxyInterface::Info info = proxy_->GetInfo();
583 manufacturer_ = info._1;
584 model_id_ = info._2;
585 hardware_revision_ = info._3;
586 VLOG(2) << "ModemInfo: " << manufacturer_ << ", " << model_id_ << ", "
587 << hardware_revision_;
588}
589
590void Cellular::GetModemRegistrationState() {
Darin Petkovbec79a22011-08-01 14:47:17 -0700591 switch (type_) {
592 case kTypeGSM:
593 GetGSMRegistrationState();
594 break;
595 case kTypeCDMA:
596 GetCDMARegistrationState();
597 break;
598 default: NOTREACHED();
599 }
Darin Petkovd9661952011-08-03 16:25:42 -0700600 HandleNewRegistrationState();
Darin Petkovbec79a22011-08-01 14:47:17 -0700601}
602
603void Cellular::GetCDMARegistrationState() {
604 CHECK_EQ(kTypeCDMA, type_);
Darin Petkovd2045802011-08-23 11:09:25 -0700605 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovbec79a22011-08-01 14:47:17 -0700606 cdma_proxy_->GetRegistrationState(&cdma_.registration_state_1x,
607 &cdma_.registration_state_evdo);
608 VLOG(2) << "CDMA Registration: 1x(" << cdma_.registration_state_1x
609 << ") EVDO(" << cdma_.registration_state_evdo << ")";
Darin Petkovbec79a22011-08-01 14:47:17 -0700610}
611
612void Cellular::GetGSMRegistrationState() {
Darin Petkov9bac6fe2011-08-26 12:49:05 -0700613 CHECK_EQ(kTypeGSM, type_);
614 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
615 ModemGSMNetworkProxyInterface::RegistrationInfo info =
616 gsm_network_proxy_->GetRegistrationInfo();
617 gsm_.registration_state = info._1;
618 gsm_.network_id = info._2;
619 gsm_.operator_name = info._3;
620 VLOG(2) << "GSM Registration: " << gsm_.registration_state << ", "
621 << gsm_.network_id << ", " << gsm_.operator_name;
Darin Petkovceb68172011-07-29 14:47:48 -0700622}
623
Darin Petkovd9661952011-08-03 16:25:42 -0700624void Cellular::HandleNewRegistrationState() {
Paul Stewartac4ac002011-08-26 12:04:26 -0700625 dispatcher()->PostTask(
Darin Petkov0828f5f2011-08-11 10:18:52 -0700626 task_factory_.NewRunnableMethod(
627 &Cellular::HandleNewRegistrationStateTask));
628}
629
630void Cellular::HandleNewRegistrationStateTask() {
Darin Petkovd9661952011-08-03 16:25:42 -0700631 VLOG(2) << __func__;
Darin Petkovd2045802011-08-23 11:09:25 -0700632 const string network_tech = GetNetworkTechnologyString();
633 if (network_tech.empty()) {
Darin Petkovc408e692011-08-17 13:47:15 -0700634 if (state_ == kStateLinked) {
Paul Stewartac4ac002011-08-26 12:04:26 -0700635 manager()->DeregisterService(service_);
Darin Petkovc408e692011-08-17 13:47:15 -0700636 }
Darin Petkovd9661952011-08-03 16:25:42 -0700637 service_ = NULL;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700638 if (state_ == kStateLinked ||
639 state_ == kStateConnected ||
640 state_ == kStateRegistered) {
641 SetState(kStateEnabled);
Darin Petkovd9661952011-08-03 16:25:42 -0700642 }
643 return;
644 }
Darin Petkovd9661952011-08-03 16:25:42 -0700645 if (state_ == kStateEnabled) {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700646 SetState(kStateRegistered);
Darin Petkovd9661952011-08-03 16:25:42 -0700647 }
648 if (!service_.get()) {
649 // For now, no endpoint is created. Revisit if necessary.
650 CreateService();
651 }
652 GetModemSignalQuality();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700653 if (state_ == kStateRegistered && modem_state_ == kModemStateConnected) {
654 SetState(kStateConnected);
655 EstablishLink();
656 }
Darin Petkovd2045802011-08-23 11:09:25 -0700657 service_->set_network_tech(network_tech);
658 service_->set_roaming_state(GetRoamingStateString());
Darin Petkov9bac6fe2011-08-26 12:49:05 -0700659 // TODO(petkov): For GSM, update the serving operator based on the network id
660 // and the mobile provider database.
Darin Petkovd9661952011-08-03 16:25:42 -0700661}
662
663void Cellular::GetModemSignalQuality() {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700664 VLOG(2) << __func__;
Darin Petkovd9661952011-08-03 16:25:42 -0700665 uint32 strength = 0;
666 switch (type_) {
667 case kTypeGSM:
668 strength = GetGSMSignalQuality();
669 break;
670 case kTypeCDMA:
671 strength = GetCDMASignalQuality();
672 break;
673 default: NOTREACHED();
674 }
675 HandleNewSignalQuality(strength);
676}
677
678uint32 Cellular::GetCDMASignalQuality() {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700679 VLOG(2) << __func__;
Darin Petkovd9661952011-08-03 16:25:42 -0700680 CHECK_EQ(kTypeCDMA, type_);
681 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
682 return cdma_proxy_->GetSignalQuality();
683}
684
685uint32 Cellular::GetGSMSignalQuality() {
Darin Petkov22b72bf2011-08-29 14:01:20 -0700686 VLOG(2) << __func__;
687 CHECK_EQ(kTypeGSM, type_);
688 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
689 return gsm_network_proxy_->GetSignalQuality();
Darin Petkovd9661952011-08-03 16:25:42 -0700690}
691
692void Cellular::HandleNewSignalQuality(uint32 strength) {
693 VLOG(2) << "Signal strength: " << strength;
694 if (service_.get()) {
695 service_->set_strength(strength);
696 }
697}
698
699void Cellular::CreateService() {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700700 VLOG(2) << __func__;
Darin Petkovd9661952011-08-03 16:25:42 -0700701 CHECK(!service_.get());
702 service_ =
Paul Stewartac4ac002011-08-26 12:04:26 -0700703 new CellularService(control_interface(), dispatcher(), manager(), this);
Darin Petkovc408e692011-08-17 13:47:15 -0700704 switch (type_) {
705 case kTypeGSM:
Darin Petkov51489002011-08-18 13:13:20 -0700706 service_->set_activation_state(flimflam::kActivationStateActivated);
Darin Petkov3335b372011-08-22 11:05:32 -0700707 // TODO(petkov): Set serving operator.
Darin Petkovc408e692011-08-17 13:47:15 -0700708 break;
709 case kTypeCDMA:
710 service_->set_payment_url(cdma_.payment_url);
711 service_->set_usage_url(cdma_.usage_url);
Darin Petkov3335b372011-08-22 11:05:32 -0700712 service_->set_serving_operator(home_provider_);
Darin Petkovc408e692011-08-17 13:47:15 -0700713 HandleNewCDMAActivationState(MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR);
714 break;
715 default:
716 NOTREACHED();
Darin Petkovcc044422011-08-17 13:30:06 -0700717 }
Darin Petkovf5f61e02011-07-29 11:35:40 -0700718}
719
Paul Stewartfdd16072011-09-16 12:41:35 -0700720bool Cellular::TechnologyIs(const Technology::Identifier type) const {
721 return type == Technology::kCellular;
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700722}
723
Darin Petkov4d6d9412011-08-24 13:19:54 -0700724void Cellular::Connect(Error *error) {
Darin Petkovc5f56562011-08-06 16:40:05 -0700725 VLOG(2) << __func__;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700726 if (state_ == kStateConnected ||
727 state_ == kStateLinked) {
Darin Petkov4d6d9412011-08-24 13:19:54 -0700728 LOG(ERROR) << "Already connected; connection request ignored.";
729 CHECK(error);
730 error->Populate(Error::kAlreadyConnected);
Darin Petkovc5f56562011-08-06 16:40:05 -0700731 return;
732 }
733 CHECK_EQ(kStateRegistered, state_);
Darin Petkovd2045802011-08-23 11:09:25 -0700734
735 if (!allow_roaming_ &&
736 service_->roaming_state() == flimflam::kRoamingStateRoaming) {
737 LOG(ERROR) << "Roaming disallowed; connection request ignored.";
Darin Petkov4d6d9412011-08-24 13:19:54 -0700738 CHECK(error);
739 error->Populate(Error::kNotOnHomeNetwork);
Darin Petkovd2045802011-08-23 11:09:25 -0700740 return;
741 }
742
Darin Petkovc5f56562011-08-06 16:40:05 -0700743 DBusPropertiesMap properties;
744 const char *phone_number = NULL;
745 switch (type_) {
746 case kTypeGSM:
747 phone_number = kPhoneNumberGSM;
748 break;
749 case kTypeCDMA:
750 phone_number = kPhoneNumberCDMA;
751 break;
752 default: NOTREACHED();
753 }
754 properties[kConnectPropertyPhoneNumber].writer().append_string(phone_number);
755 // TODO(petkov): Setup apn and "home_only".
756
757 // Defer connect because we may be in a dbus-c++ callback.
Paul Stewartac4ac002011-08-26 12:04:26 -0700758 dispatcher()->PostTask(
Darin Petkovc5f56562011-08-06 16:40:05 -0700759 task_factory_.NewRunnableMethod(&Cellular::ConnectTask, properties));
760}
761
762void Cellular::ConnectTask(const DBusPropertiesMap &properties) {
763 VLOG(2) << __func__;
Darin Petkovbac96002011-08-09 13:22:00 -0700764 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovc5f56562011-08-06 16:40:05 -0700765 simple_proxy_->Connect(properties);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700766 SetState(kStateConnected);
Darin Petkovbac96002011-08-09 13:22:00 -0700767 EstablishLink();
768}
769
770void Cellular::EstablishLink() {
771 VLOG(2) << __func__;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700772 CHECK_EQ(kStateConnected, state_);
773 unsigned int flags = 0;
Paul Stewartac4ac002011-08-26 12:04:26 -0700774 if (manager()->device_info()->GetFlags(interface_index(), &flags) &&
Darin Petkov0828f5f2011-08-11 10:18:52 -0700775 (flags & IFF_UP) != 0) {
776 LinkEvent(flags, IFF_UP);
777 return;
778 }
779 // TODO(petkov): Provide a timeout for a failed link-up request.
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -0700780 rtnl_handler()->SetInterfaceFlags(interface_index(), IFF_UP, IFF_UP);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700781}
782
783void Cellular::LinkEvent(unsigned int flags, unsigned int change) {
784 Device::LinkEvent(flags, change);
785 if ((flags & IFF_UP) != 0 && state_ == kStateConnected) {
Paul Stewartac4ac002011-08-26 12:04:26 -0700786 LOG(INFO) << link_name() << " is up.";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700787 SetState(kStateLinked);
Paul Stewartac4ac002011-08-26 12:04:26 -0700788 manager()->RegisterService(service_);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700789 // TODO(petkov): For GSM, remember the APN.
Darin Petkov60b8c3b2011-08-25 11:03:20 -0700790 if (AcquireDHCPConfig()) {
791 SelectService(service_);
792 SetServiceState(Service::kStateConfiguring);
793 } else {
794 LOG(ERROR) << "Unable to acquire DHCP config.";
795 }
Darin Petkov0828f5f2011-08-11 10:18:52 -0700796 } else if ((flags & IFF_UP) == 0 && state_ == kStateLinked) {
797 SetState(kStateConnected);
Paul Stewartac4ac002011-08-26 12:04:26 -0700798 manager()->DeregisterService(service_);
Darin Petkov60b8c3b2011-08-25 11:03:20 -0700799 SelectService(NULL);
Darin Petkov77cb6812011-08-15 16:19:41 -0700800 DestroyIPConfig();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700801 }
Darin Petkovc5f56562011-08-06 16:40:05 -0700802}
803
Darin Petkovc0865312011-09-16 15:31:20 -0700804void Cellular::Scan(Error *error) {
805 VLOG(2) << __func__;
806 if (type_ != kTypeGSM) {
807 const string kMessage = "Network scanning support for GSM only.";
808 LOG(ERROR) << kMessage;
809 CHECK(error);
810 error->Populate(Error::kNotSupported, kMessage);
811 return;
812 }
813 // Defer scan because we may be in a dbus-c++ callback.
814 dispatcher()->PostTask(
815 task_factory_.NewRunnableMethod(&Cellular::ScanTask));
816}
817
818void Cellular::ScanTask() {
819 VLOG(2) << __func__;
820 // TODO(petkov): Defer scan requests if a scan is in progress already.
821 CHECK_EQ(kTypeGSM, type_);
822 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583). This is a
823 // must for this call which is basically a stub at this point.
824 ModemGSMNetworkProxyInterface::ScanResults results =
825 gsm_network_proxy_->Scan();
826 found_networks_.clear();
827 for (ModemGSMNetworkProxyInterface::ScanResults::const_iterator it =
828 results.begin(); it != results.end(); ++it) {
829 found_networks_.push_back(ParseScanResult(*it));
830 }
831}
832
833Stringmap Cellular::ParseScanResult(
834 const ModemGSMNetworkProxyInterface::ScanResult &result) {
835 Stringmap parsed;
836 for (ModemGSMNetworkProxyInterface::ScanResult::const_iterator it =
837 result.begin(); it != result.end(); ++it) {
838 // TODO(petkov): Define these in system_api/service_constants.h. The
839 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
840 static const char * const kStatusString[] = {
841 "unknown",
842 "available",
843 "current",
844 "forbidden",
845 };
846 // TODO(petkov): Do we need the finer level of granularity here or can we
847 // use the same granularity as GetNetworkTechnologyString (e.g.,
848 // HSDPA->"HSPA").
849 static const char * const kTechnologyString[] = {
850 flimflam::kNetworkTechnologyGsm,
851 "GSM Compact",
852 flimflam::kNetworkTechnologyUmts,
853 flimflam::kNetworkTechnologyEdge,
854 "HSDPA",
855 "HSUPA",
856 flimflam::kNetworkTechnologyHspa,
857 };
858 VLOG(2) << "Network property: " << it->first << " = " << it->second;
859 if (it->first == kNetworkPropertyStatus) {
860 int status = 0;
861 if (base::StringToInt(it->second, &status) &&
862 status >= 0 &&
863 status < static_cast<int>(arraysize(kStatusString))) {
864 parsed[flimflam::kStatusProperty] = kStatusString[status];
865 } else {
866 LOG(ERROR) << "Unexpected status value: " << it->second;
867 }
868 } else if (it->first == kNetworkPropertyID) {
869 parsed[flimflam::kNetworkIdProperty] = it->second;
870 } else if (it->first == kNetworkPropertyLongName) {
871 parsed[flimflam::kLongNameProperty] = it->second;
872 } else if (it->first == kNetworkPropertyShortName) {
873 parsed[flimflam::kShortNameProperty] = it->second;
874 } else if (it->first == kNetworkPropertyAccessTechnology) {
875 int tech = 0;
876 if (base::StringToInt(it->second, &tech) &&
877 tech >= 0 &&
878 tech < static_cast<int>(arraysize(kTechnologyString))) {
879 parsed[flimflam::kTechnologyProperty] = kTechnologyString[tech];
880 } else {
881 LOG(ERROR) << "Unexpected technology value: " << it->second;
882 }
883 } else {
884 LOG(WARNING) << "Unknown network property ignored: " << it->first;
885 }
886 }
887 // TODO(petkov): If long name is not set and there's a network ID, do a mobile
888 // database lookup (crosbug.com/19699).
889 return parsed;
890}
891
Darin Petkovb100ae72011-08-24 16:19:45 -0700892void Cellular::Activate(const string &carrier, Error *error) {
Darin Petkovc0865312011-09-16 15:31:20 -0700893 VLOG(2) << __func__ << "(" << carrier << ")";
Darin Petkovb100ae72011-08-24 16:19:45 -0700894 if (type_ != kTypeCDMA) {
895 const string kMessage = "Unable to activate non-CDMA modem.";
896 LOG(ERROR) << kMessage;
897 CHECK(error);
898 error->Populate(Error::kInvalidArguments, kMessage);
899 return;
900 }
901 if (state_ != kStateEnabled &&
902 state_ != kStateRegistered) {
903 const string kMessage = "Unable to activate in " + GetStateString(state_);
904 LOG(ERROR) << kMessage;
905 CHECK(error);
906 error->Populate(Error::kInvalidArguments, kMessage);
907 return;
908 }
Darin Petkovc408e692011-08-17 13:47:15 -0700909 // Defer connect because we may be in a dbus-c++ callback.
Paul Stewartac4ac002011-08-26 12:04:26 -0700910 dispatcher()->PostTask(
Darin Petkovc408e692011-08-17 13:47:15 -0700911 task_factory_.NewRunnableMethod(&Cellular::ActivateTask, carrier));
912}
913
914void Cellular::ActivateTask(const string &carrier) {
915 VLOG(2) << __func__ << "(" << carrier << ")";
Darin Petkovc0865312011-09-16 15:31:20 -0700916 CHECK_EQ(kTypeCDMA, type_);
Darin Petkovb100ae72011-08-24 16:19:45 -0700917 if (state_ != kStateEnabled &&
918 state_ != kStateRegistered) {
Darin Petkovc408e692011-08-17 13:47:15 -0700919 LOG(ERROR) << "Unable to activate in " << GetStateString(state_);
920 return;
921 }
922 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
923 uint32 status = cdma_proxy_->Activate(carrier);
924 if (status == MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR) {
925 cdma_.activation_state = MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING;
926 }
927 HandleNewCDMAActivationState(status);
928}
929
930void Cellular::HandleNewCDMAActivationState(uint32 error) {
931 if (!service_.get()) {
932 return;
933 }
934 service_->set_activation_state(
935 GetCDMAActivationStateString(cdma_.activation_state));
Darin Petkov51489002011-08-18 13:13:20 -0700936 service_->set_error(GetCDMAActivationErrorString(error));
Darin Petkovc408e692011-08-17 13:47:15 -0700937}
938
Darin Petkovb27e5442011-08-16 14:36:45 -0700939void Cellular::OnCDMAActivationStateChanged(
940 uint32 activation_state,
941 uint32 activation_error,
942 const DBusPropertiesMap &status_changes) {
943 CHECK_EQ(kTypeCDMA, type_);
944 DBusProperties::GetString(status_changes, "mdn", &mdn_);
945 DBusProperties::GetString(status_changes, "min", &min_);
Darin Petkovcc044422011-08-17 13:30:06 -0700946 if (DBusProperties::GetString(
947 status_changes, "payment_url", &cdma_.payment_url) &&
Darin Petkovb27e5442011-08-16 14:36:45 -0700948 service_.get()) {
Darin Petkovcc044422011-08-17 13:30:06 -0700949 service_->set_payment_url(cdma_.payment_url);
Darin Petkovb27e5442011-08-16 14:36:45 -0700950 }
Darin Petkovc408e692011-08-17 13:47:15 -0700951 cdma_.activation_state = activation_state;
952 HandleNewCDMAActivationState(activation_error);
Darin Petkovb27e5442011-08-16 14:36:45 -0700953}
954
Darin Petkovd9661952011-08-03 16:25:42 -0700955void Cellular::OnCDMARegistrationStateChanged(uint32 state_1x,
956 uint32 state_evdo) {
957 CHECK_EQ(kTypeCDMA, type_);
958 cdma_.registration_state_1x = state_1x;
959 cdma_.registration_state_evdo = state_evdo;
960 HandleNewRegistrationState();
961}
962
963void Cellular::OnCDMASignalQualityChanged(uint32 strength) {
964 CHECK_EQ(kTypeCDMA, type_);
965 HandleNewSignalQuality(strength);
966}
967
mukesh agrawal1830fa12011-09-26 14:31:40 -0700968void Cellular::OnGSMNetworkModeChanged(uint32 /*mode*/) {
Darin Petkova1e0a1c2011-08-25 15:08:33 -0700969 // TODO(petkov): Implement this.
970 NOTIMPLEMENTED();
971}
972
973void Cellular::OnGSMRegistrationInfoChanged(uint32 status,
974 const string &operator_code,
975 const string &operator_name) {
Darin Petkov9bac6fe2011-08-26 12:49:05 -0700976 CHECK_EQ(kTypeGSM, type_);
977 gsm_.registration_state = status;
978 gsm_.network_id = operator_code;
979 gsm_.operator_name = operator_name;
980 HandleNewRegistrationState();
Darin Petkova1e0a1c2011-08-25 15:08:33 -0700981}
982
983void Cellular::OnGSMSignalQualityChanged(uint32 quality) {
Darin Petkov22b72bf2011-08-29 14:01:20 -0700984 CHECK_EQ(kTypeGSM, type_);
985 HandleNewSignalQuality(quality);
Darin Petkova1e0a1c2011-08-25 15:08:33 -0700986}
987
mukesh agrawal1830fa12011-09-26 14:31:40 -0700988void Cellular::OnModemStateChanged(uint32 /*old_state*/,
989 uint32 /*new_state*/,
990 uint32 /*reason*/) {
Darin Petkovc5f56562011-08-06 16:40:05 -0700991 // TODO(petkov): Implement this.
992 NOTIMPLEMENTED();
993}
994
Darin Petkov48a511a2011-09-15 10:33:37 -0700995void Cellular::SetGSMAccessTechnology(uint32 access_technology) {
996 CHECK_EQ(kTypeGSM, type_);
997 gsm_.access_technology = access_technology;
998 if (service_.get()) {
999 service_->set_network_tech(GetNetworkTechnologyString());
1000 }
1001}
1002
Chris Masone889666b2011-07-03 12:58:50 -07001003StrIntPair Cellular::SimLockStatusToProperty() {
1004 return StrIntPair(make_pair(flimflam::kSIMLockTypeProperty,
1005 sim_lock_status_.lock_type),
1006 make_pair(flimflam::kSIMLockRetriesLeftProperty,
1007 sim_lock_status_.retries_left));
1008}
1009
Chris Masone889666b2011-07-03 12:58:50 -07001010void Cellular::HelpRegisterDerivedStrIntPair(
1011 const string &name,
1012 StrIntPair(Cellular::*get)(void),
mukesh agrawalffa3d042011-10-06 15:26:10 -07001013 void(Cellular::*set)(const StrIntPair&, Error *)) {
mukesh agrawalde29fa82011-09-16 16:16:36 -07001014 mutable_store()->RegisterDerivedStrIntPair(
Chris Masone889666b2011-07-03 12:58:50 -07001015 name,
1016 StrIntPairAccessor(
1017 new CustomAccessor<Cellular, StrIntPair>(this, get, set)));
1018}
1019
Chris Masone3bd3c8c2011-06-13 08:20:26 -07001020} // namespace shill