blob: 99953541a3bee07628395b9c1bf49f178da1fab4 [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 Petkove9d12e02011-07-27 15:09:37 -0700114 type_(type),
115 state_(kStateDisabled),
Darin Petkovbac96002011-08-09 13:22:00 -0700116 modem_state_(kModemStateUnknown),
Darin Petkove9d12e02011-07-27 15:09:37 -0700117 dbus_owner_(owner),
118 dbus_path_(path),
Darin Petkovc5f56562011-08-06 16:40:05 -0700119 task_factory_(this),
Darin Petkove9d12e02011-07-27 15:09:37 -0700120 allow_roaming_(false),
Darin Petkove9d12e02011-07-27 15:09:37 -0700121 scanning_(false),
122 scan_interval_(0) {
mukesh agrawalde29fa82011-09-16 16:16:36 -0700123 PropertyStore *store = this->mutable_store();
Paul Stewartac4ac002011-08-26 12:04:26 -0700124 store->RegisterConstString(flimflam::kCarrierProperty, &carrier_);
125 store->RegisterConstString(flimflam::kDBusConnectionProperty, &dbus_owner_);
126 store->RegisterConstString(flimflam::kDBusObjectProperty, &dbus_path_);
127 store->RegisterBool(flimflam::kCellularAllowRoamingProperty, &allow_roaming_);
128 store->RegisterConstString(flimflam::kEsnProperty, &esn_);
129 store->RegisterConstString(flimflam::kFirmwareRevisionProperty,
Chris Masone27c4aa52011-07-02 13:10:14 -0700130 &firmware_revision_);
Darin Petkovc0865312011-09-16 15:31:20 -0700131 store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
132 &found_networks_);
Paul Stewartac4ac002011-08-26 12:04:26 -0700133 store->RegisterConstString(flimflam::kHardwareRevisionProperty,
Chris Masone27c4aa52011-07-02 13:10:14 -0700134 &hardware_revision_);
Paul Stewartac4ac002011-08-26 12:04:26 -0700135 store->RegisterConstStringmap(flimflam::kHomeProviderProperty,
Darin Petkov3335b372011-08-22 11:05:32 -0700136 &home_provider_.ToDict());
Paul Stewartac4ac002011-08-26 12:04:26 -0700137 store->RegisterConstString(flimflam::kImeiProperty, &imei_);
138 store->RegisterConstString(flimflam::kImsiProperty, &imsi_);
139 store->RegisterConstString(flimflam::kManufacturerProperty, &manufacturer_);
140 store->RegisterConstString(flimflam::kMdnProperty, &mdn_);
141 store->RegisterConstString(flimflam::kMeidProperty, &meid_);
142 store->RegisterConstString(flimflam::kMinProperty, &min_);
143 store->RegisterConstString(flimflam::kModelIDProperty, &model_id_);
144 store->RegisterConstUint16(flimflam::kPRLVersionProperty, &cdma_.prl_version);
145 store->RegisterConstString(flimflam::kSelectedNetworkProperty,
Darin Petkova1e0a1c2011-08-25 15:08:33 -0700146 &selected_network_);
Chris Masoneb925cc82011-06-22 15:39:57 -0700147
Chris Masone889666b2011-07-03 12:58:50 -0700148 HelpRegisterDerivedStrIntPair(flimflam::kSIMLockStatusProperty,
149 &Cellular::SimLockStatusToProperty,
150 NULL);
Chris Masoneb925cc82011-06-22 15:39:57 -0700151
Paul Stewartac4ac002011-08-26 12:04:26 -0700152 store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
153 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
Chris Masone4d42df82011-07-02 17:09:39 -0700154
Paul Stewartac4ac002011-08-26 12:04:26 -0700155 VLOG(2) << "Cellular device " << this->link_name() << " initialized: "
Darin Petkove9d12e02011-07-27 15:09:37 -0700156 << GetTypeString();
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700157}
158
Darin Petkove9d12e02011-07-27 15:09:37 -0700159Cellular::~Cellular() {}
160
Darin Petkovcc044422011-08-17 13:30:06 -0700161string Cellular::GetTypeString() const {
Darin Petkove9d12e02011-07-27 15:09:37 -0700162 switch (type_) {
163 case kTypeGSM: return "CellularTypeGSM";
164 case kTypeCDMA: return "CellularTypeCDMA";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700165 default: NOTREACHED();
Darin Petkove9d12e02011-07-27 15:09:37 -0700166 }
Darin Petkov0828f5f2011-08-11 10:18:52 -0700167 return StringPrintf("CellularTypeUnknown-%d", type_);
Darin Petkove9d12e02011-07-27 15:09:37 -0700168}
169
Darin Petkovcc044422011-08-17 13:30:06 -0700170// static
171string Cellular::GetStateString(State state) {
172 switch (state) {
Darin Petkove9d12e02011-07-27 15:09:37 -0700173 case kStateDisabled: return "CellularStateDisabled";
174 case kStateEnabled: return "CellularStateEnabled";
175 case kStateRegistered: return "CellularStateRegistered";
176 case kStateConnected: return "CellularStateConnected";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700177 case kStateLinked: return "CellularStateLinked";
178 default: NOTREACHED();
Darin Petkove9d12e02011-07-27 15:09:37 -0700179 }
Darin Petkovcc044422011-08-17 13:30:06 -0700180 return StringPrintf("CellularStateUnknown-%d", state);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700181}
182
Darin Petkovd2045802011-08-23 11:09:25 -0700183string Cellular::GetNetworkTechnologyString() const {
184 switch (type_) {
185 case kTypeGSM:
Darin Petkov9bac6fe2011-08-26 12:49:05 -0700186 if (gsm_.registration_state == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
187 gsm_.registration_state == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING) {
188 switch (gsm_.access_technology) {
189 case MM_MODEM_GSM_ACCESS_TECH_GSM:
190 case MM_MODEM_GSM_ACCESS_TECH_GSM_COMPACT:
Darin Petkove1a3e242011-08-29 12:44:30 -0700191 return flimflam::kNetworkTechnologyGsm;
Darin Petkov9bac6fe2011-08-26 12:49:05 -0700192 case MM_MODEM_GSM_ACCESS_TECH_GPRS:
193 return flimflam::kNetworkTechnologyGprs;
194 case MM_MODEM_GSM_ACCESS_TECH_EDGE:
195 return flimflam::kNetworkTechnologyEdge;
196 case MM_MODEM_GSM_ACCESS_TECH_UMTS:
197 return flimflam::kNetworkTechnologyUmts;
198 case MM_MODEM_GSM_ACCESS_TECH_HSDPA:
199 case MM_MODEM_GSM_ACCESS_TECH_HSUPA:
200 case MM_MODEM_GSM_ACCESS_TECH_HSPA:
201 return flimflam::kNetworkTechnologyHspa;
202 case MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS:
203 return flimflam::kNetworkTechnologyHspaPlus;
204 default:
205 NOTREACHED();
206 }
207 }
Darin Petkovd2045802011-08-23 11:09:25 -0700208 break;
209 case kTypeCDMA:
210 if (cdma_.registration_state_evdo !=
211 MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN) {
212 return flimflam::kNetworkTechnologyEvdo;
213 }
214 if (cdma_.registration_state_1x !=
215 MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN) {
216 return flimflam::kNetworkTechnology1Xrtt;
217 }
218 break;
219 default:
220 NOTREACHED();
221 }
222 return "";
223}
224
225string Cellular::GetRoamingStateString() const {
226 switch (type_) {
227 case kTypeGSM:
Darin Petkov9bac6fe2011-08-26 12:49:05 -0700228 switch (gsm_.registration_state) {
229 case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME:
230 return flimflam::kRoamingStateHome;
231 case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING:
232 return flimflam::kRoamingStateRoaming;
233 default:
234 break;
235 }
Darin Petkovd2045802011-08-23 11:09:25 -0700236 break;
237 case kTypeCDMA: {
238 uint32 state = cdma_.registration_state_evdo;
239 if (state == MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN) {
240 state = cdma_.registration_state_1x;
241 }
242 switch (state) {
243 case MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN:
244 case MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED:
245 break;
246 case MM_MODEM_CDMA_REGISTRATION_STATE_HOME:
247 return flimflam::kRoamingStateHome;
248 case MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING:
249 return flimflam::kRoamingStateRoaming;
250 default:
251 NOTREACHED();
252 }
253 break;
254 }
255 default:
256 NOTREACHED();
257 }
258 return flimflam::kRoamingStateUnknown;
259}
260
Darin Petkovc408e692011-08-17 13:47:15 -0700261// static
262string Cellular::GetCDMAActivationStateString(uint32 state) {
263 switch (state) {
264 case MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED:
Darin Petkov51489002011-08-18 13:13:20 -0700265 return flimflam::kActivationStateActivated;
Darin Petkovc408e692011-08-17 13:47:15 -0700266 case MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING:
Darin Petkov51489002011-08-18 13:13:20 -0700267 return flimflam::kActivationStateActivating;
Darin Petkovc408e692011-08-17 13:47:15 -0700268 case MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED:
Darin Petkov51489002011-08-18 13:13:20 -0700269 return flimflam::kActivationStateNotActivated;
Darin Petkovc408e692011-08-17 13:47:15 -0700270 case MM_MODEM_CDMA_ACTIVATION_STATE_PARTIALLY_ACTIVATED:
Darin Petkov51489002011-08-18 13:13:20 -0700271 return flimflam::kActivationStatePartiallyActivated;
Darin Petkovc408e692011-08-17 13:47:15 -0700272 default:
Darin Petkov51489002011-08-18 13:13:20 -0700273 return flimflam::kActivationStateUnknown;
274 }
275}
276
277// static
278string Cellular::GetCDMAActivationErrorString(uint32 error) {
279 switch (error) {
280 case MM_MODEM_CDMA_ACTIVATION_ERROR_WRONG_RADIO_INTERFACE:
281 return flimflam::kErrorNeedEvdo;
282 case MM_MODEM_CDMA_ACTIVATION_ERROR_ROAMING:
283 return flimflam::kErrorNeedHomeNetwork;
284 case MM_MODEM_CDMA_ACTIVATION_ERROR_COULD_NOT_CONNECT:
285 case MM_MODEM_CDMA_ACTIVATION_ERROR_SECURITY_AUTHENTICATION_FAILED:
286 case MM_MODEM_CDMA_ACTIVATION_ERROR_PROVISIONING_FAILED:
287 return flimflam::kErrorOtaspFailed;
288 case MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR:
289 return "";
290 case MM_MODEM_CDMA_ACTIVATION_ERROR_NO_SIGNAL:
291 default:
292 return flimflam::kErrorActivationFailed;
Darin Petkovc408e692011-08-17 13:47:15 -0700293 }
294}
295
Darin Petkov0828f5f2011-08-11 10:18:52 -0700296void Cellular::SetState(State state) {
Darin Petkovcc044422011-08-17 13:30:06 -0700297 VLOG(2) << GetStateString(state_) << " -> " << GetStateString(state);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700298 state_ = state;
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700299}
300
301void Cellular::Start() {
Darin Petkovcc044422011-08-17 13:30:06 -0700302 LOG(INFO) << __func__ << ": " << GetStateString(state_);
Darin Petkov3335b372011-08-22 11:05:32 -0700303 Device::Start();
Darin Petkovbec79a22011-08-01 14:47:17 -0700304 InitProxies();
Darin Petkovf5f61e02011-07-29 11:35:40 -0700305 EnableModem();
Darin Petkovceb68172011-07-29 14:47:48 -0700306 if (type_ == kTypeGSM) {
307 RegisterGSMModem();
308 }
Darin Petkovf5f61e02011-07-29 11:35:40 -0700309 GetModemStatus();
Darin Petkovceb68172011-07-29 14:47:48 -0700310 GetModemIdentifiers();
311 if (type_ == kTypeGSM) {
312 GetGSMProperties();
313 }
314 GetModemInfo();
315 GetModemRegistrationState();
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700316}
317
318void Cellular::Stop() {
Darin Petkove9d12e02011-07-27 15:09:37 -0700319 proxy_.reset();
Darin Petkove604f702011-07-28 15:51:17 -0700320 simple_proxy_.reset();
Darin Petkovbec79a22011-08-01 14:47:17 -0700321 cdma_proxy_.reset();
Darin Petkove42e1012011-08-31 12:35:04 -0700322 gsm_card_proxy_.reset();
323 gsm_network_proxy_.reset();
Paul Stewartac4ac002011-08-26 12:04:26 -0700324 manager()->DeregisterService(service_);
Darin Petkove9d12e02011-07-27 15:09:37 -0700325 service_ = NULL; // Breaks a reference cycle.
Darin Petkov0828f5f2011-08-11 10:18:52 -0700326 SetState(kStateDisabled);
Darin Petkov3335b372011-08-22 11:05:32 -0700327 Device::Stop();
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700328}
329
Darin Petkovbec79a22011-08-01 14:47:17 -0700330void Cellular::InitProxies() {
Darin Petkovcc044422011-08-17 13:30:06 -0700331 VLOG(2) << __func__;
Darin Petkovbec79a22011-08-01 14:47:17 -0700332 proxy_.reset(
Darin Petkovc5f56562011-08-06 16:40:05 -0700333 ProxyFactory::factory()->CreateModemProxy(this, dbus_path_, dbus_owner_));
Darin Petkovbec79a22011-08-01 14:47:17 -0700334 simple_proxy_.reset(
335 ProxyFactory::factory()->CreateModemSimpleProxy(
336 dbus_path_, dbus_owner_));
337 switch (type_) {
338 case kTypeGSM:
Darin Petkov975b5e72011-08-30 11:48:08 -0700339 gsm_card_proxy_.reset(
340 ProxyFactory::factory()->CreateModemGSMCardProxy(
341 this, dbus_path_, dbus_owner_));
Darin Petkova1e0a1c2011-08-25 15:08:33 -0700342 gsm_network_proxy_.reset(
343 ProxyFactory::factory()->CreateModemGSMNetworkProxy(
344 this, dbus_path_, dbus_owner_));
Darin Petkovbec79a22011-08-01 14:47:17 -0700345 break;
346 case kTypeCDMA:
347 cdma_proxy_.reset(
348 ProxyFactory::factory()->CreateModemCDMAProxy(
Darin Petkovd9661952011-08-03 16:25:42 -0700349 this, dbus_path_, dbus_owner_));
Darin Petkovbec79a22011-08-01 14:47:17 -0700350 break;
351 default: NOTREACHED();
352 }
353}
354
Darin Petkovf5f61e02011-07-29 11:35:40 -0700355void Cellular::EnableModem() {
356 CHECK_EQ(kStateDisabled, state_);
357 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
358 proxy_->Enable(true);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700359 SetState(kStateEnabled);
Darin Petkovf5f61e02011-07-29 11:35:40 -0700360}
361
362void Cellular::GetModemStatus() {
Darin Petkovceb68172011-07-29 14:47:48 -0700363 CHECK_EQ(kStateEnabled, state_);
Darin Petkovf5f61e02011-07-29 11:35:40 -0700364 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
365 DBusPropertiesMap properties = simple_proxy_->GetStatus();
Darin Petkovceb68172011-07-29 14:47:48 -0700366 if (DBusProperties::GetString(properties, "carrier", &carrier_) &&
367 type_ == kTypeCDMA) {
Darin Petkov3335b372011-08-22 11:05:32 -0700368 home_provider_.SetName(carrier_);
369 home_provider_.SetCode("");
370 home_provider_.SetCountry("us");
Darin Petkovf5f61e02011-07-29 11:35:40 -0700371 }
Darin Petkovceb68172011-07-29 14:47:48 -0700372 DBusProperties::GetString(properties, "meid", &meid_);
373 DBusProperties::GetString(properties, "imei", &imei_);
374 if (DBusProperties::GetString(properties, "imsi", &imsi_) &&
375 type_ == kTypeGSM) {
376 // TODO(petkov): Set GSM provider.
377 }
378 DBusProperties::GetString(properties, "esn", &esn_);
379 DBusProperties::GetString(properties, "mdn", &mdn_);
380 DBusProperties::GetString(properties, "min", &min_);
Darin Petkovceb68172011-07-29 14:47:48 -0700381 DBusProperties::GetString(
382 properties, "firmware_revision", &firmware_revision_);
Darin Petkovb27e5442011-08-16 14:36:45 -0700383
Darin Petkovd2045802011-08-23 11:09:25 -0700384 uint32 state = 0;
385 if (DBusProperties::GetUint32(properties, "state", &state)) {
386 modem_state_ = static_cast<ModemState>(state);
387 }
Darin Petkovb27e5442011-08-16 14:36:45 -0700388
Darin Petkovceb68172011-07-29 14:47:48 -0700389 if (type_ == kTypeCDMA) {
Darin Petkovc408e692011-08-17 13:47:15 -0700390 DBusProperties::GetUint32(
391 properties, "activation_state", &cdma_.activation_state);
Darin Petkovcc044422011-08-17 13:30:06 -0700392 DBusProperties::GetUint16(properties, "prl_version", &cdma_.prl_version);
Darin Petkovcc044422011-08-17 13:30:06 -0700393 // TODO(petkov): For now, get the payment and usage URLs from ModemManager
394 // to match flimflam. In the future, provide a plugin API to get these
395 // directly from the modem driver.
396 DBusProperties::GetString(properties, "payment_url", &cdma_.payment_url);
397 DBusProperties::GetString(properties, "usage_url", &cdma_.usage_url);
Darin Petkovceb68172011-07-29 14:47:48 -0700398 }
399}
400
401void Cellular::GetModemIdentifiers() {
Darin Petkov975b5e72011-08-30 11:48:08 -0700402 VLOG(2) << __func__;
403 switch (type_) {
404 case kTypeGSM:
405 GetGSMIdentifiers();
406 break;
407 case kTypeCDMA:
408 GetCDMAIdentifiers();
409 break;
410 default: NOTREACHED();
411 }
412}
413
414void Cellular::GetCDMAIdentifiers() {
415 CHECK_EQ(kTypeCDMA, type_);
416 if (meid_.empty()) {
417 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
418 meid_ = cdma_proxy_->MEID();
419 VLOG(2) << "MEID: " << imei_;
420 }
421}
422
423void Cellular::GetGSMIdentifiers() {
424 CHECK_EQ(kTypeGSM, type_);
425 if (imei_.empty()) {
426 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
427 imei_ = gsm_card_proxy_->GetIMEI();
428 VLOG(2) << "IMEI: " << imei_;
429 }
430 if (imsi_.empty()) {
431 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
432 imsi_ = gsm_card_proxy_->GetIMSI();
433 VLOG(2) << "IMSI: " << imsi_;
434 }
435 if (gsm_.spn.empty()) {
436 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
437 try {
438 gsm_.spn = gsm_card_proxy_->GetSPN();
439 VLOG(2) << "SPN: " << gsm_.spn;
440 } catch (const DBus::Error e) {
441 // Some modems don't support this call so catch the exception explicitly.
442 LOG(WARNING) << "Unable to obtain SPN: " << e.what();
443 }
444 }
445 if (mdn_.empty()) {
446 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
447 mdn_ = gsm_card_proxy_->GetMSISDN();
448 VLOG(2) << "MSISDN/MDN: " << mdn_;
449 }
Darin Petkovceb68172011-07-29 14:47:48 -0700450}
451
452void Cellular::GetGSMProperties() {
Darin Petkov975b5e72011-08-30 11:48:08 -0700453 CHECK_EQ(kTypeGSM, type_);
Darin Petkov9bac6fe2011-08-26 12:49:05 -0700454 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
455 gsm_.access_technology = gsm_network_proxy_->AccessTechnology();
456 VLOG(2) << "GSM AccessTechnology: " << gsm_.access_technology;
Darin Petkovceb68172011-07-29 14:47:48 -0700457}
458
459void Cellular::RegisterGSMModem() {
Darin Petkov975b5e72011-08-30 11:48:08 -0700460 CHECK_EQ(kTypeGSM, type_);
Darin Petkov9ae310f2011-08-30 15:41:13 -0700461 LOG(INFO) << "Registering on \"" << selected_network_ << "\"";
Darin Petkova1e0a1c2011-08-25 15:08:33 -0700462 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
463 gsm_network_proxy_->Register(selected_network_);
Darin Petkov9ae310f2011-08-30 15:41:13 -0700464 // TODO(petkov): Handle registration failure including trying the home network
465 // when selected_network_ is not empty.
466}
467
468void Cellular::RegisterOnNetwork(const string &network_id, Error *error) {
469 LOG(INFO) << __func__ << "(" << network_id << ")";
470 if (type_ != kTypeGSM) {
471 const string kMessage = "Network registration supported only for GSM.";
472 LOG(ERROR) << kMessage;
473 CHECK(error);
474 error->Populate(Error::kNotSupported, kMessage);
475 return;
476 }
477 // Defer registration because we may be in a dbus-c++ callback.
478 dispatcher()->PostTask(
479 task_factory_.NewRunnableMethod(&Cellular::RegisterOnNetworkTask,
480 network_id));
481}
482
483void Cellular::RegisterOnNetworkTask(const string &network_id) {
484 LOG(INFO) << __func__ << "(" << network_id << ")";
Darin Petkove42e1012011-08-31 12:35:04 -0700485 CHECK_EQ(kTypeGSM, type_);
Darin Petkov9ae310f2011-08-30 15:41:13 -0700486 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
487 gsm_network_proxy_->Register(network_id);
488 // TODO(petkov): Handle registration failure.
489 selected_network_ = network_id;
Darin Petkovceb68172011-07-29 14:47:48 -0700490}
491
Darin Petkove42e1012011-08-31 12:35:04 -0700492void Cellular::RequirePIN(const string &pin, bool require, Error *error) {
493 VLOG(2) << __func__ << "(" << pin << ", " << require << ")";
494 if (type_ != kTypeGSM) {
495 const string kMessage = "RequirePIN supported only for GSM.";
496 LOG(ERROR) << kMessage;
497 CHECK(error);
498 error->Populate(Error::kNotSupported, kMessage);
499 return;
500 }
501 // Defer registration because we may be in a dbus-c++ callback.
502 dispatcher()->PostTask(
503 task_factory_.NewRunnableMethod(&Cellular::RequirePINTask, pin, require));
504}
505
506void Cellular::RequirePINTask(const string &pin, bool require) {
507 VLOG(2) << __func__ << "(" << pin << ", " << require << ")";
508 CHECK_EQ(kTypeGSM, type_);
509 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
510 gsm_card_proxy_->EnablePIN(pin, require);
511}
512
513void Cellular::EnterPIN(const string &pin, Error *error) {
514 VLOG(2) << __func__ << "(" << pin << ")";
515 if (type_ != kTypeGSM) {
516 const string kMessage = "EnterPIN supported only for GSM.";
517 LOG(ERROR) << kMessage;
518 CHECK(error);
519 error->Populate(Error::kNotSupported, kMessage);
520 return;
521 }
522 // Defer registration because we may be in a dbus-c++ callback.
523 dispatcher()->PostTask(
524 task_factory_.NewRunnableMethod(&Cellular::EnterPINTask, pin));
525}
526
527void Cellular::EnterPINTask(const string &pin) {
528 VLOG(2) << __func__ << "(" << pin << ")";
529 CHECK_EQ(kTypeGSM, type_);
530 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
531 gsm_card_proxy_->SendPIN(pin);
532}
533
534void Cellular::UnblockPIN(const string &unblock_code,
535 const string &pin,
536 Error *error) {
537 VLOG(2) << __func__ << "(" << unblock_code << ", " << pin << ")";
538 if (type_ != kTypeGSM) {
539 const string kMessage = "UnblockPIN supported only for GSM.";
540 LOG(ERROR) << kMessage;
541 CHECK(error);
542 error->Populate(Error::kNotSupported, kMessage);
543 return;
544 }
545 // Defer registration because we may be in a dbus-c++ callback.
546 dispatcher()->PostTask(
547 task_factory_.NewRunnableMethod(
548 &Cellular::UnblockPINTask, unblock_code, pin));
549}
550
551void Cellular::UnblockPINTask(const string &unblock_code, const string &pin) {
552 VLOG(2) << __func__ << "(" << unblock_code << ", " << pin << ")";
553 CHECK_EQ(kTypeGSM, type_);
554 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
555 gsm_card_proxy_->SendPUK(unblock_code, pin);
556}
557
558void Cellular::ChangePIN(const string &old_pin,
559 const string &new_pin,
560 Error *error) {
561 VLOG(2) << __func__ << "(" << old_pin << ", " << new_pin << ")";
562 if (type_ != kTypeGSM) {
563 const string kMessage = "ChangePIN supported only for GSM.";
564 LOG(ERROR) << kMessage;
565 CHECK(error);
566 error->Populate(Error::kNotSupported, kMessage);
567 return;
568 }
569 // Defer registration because we may be in a dbus-c++ callback.
570 dispatcher()->PostTask(
571 task_factory_.NewRunnableMethod(
572 &Cellular::ChangePINTask, old_pin, new_pin));
573}
574
575void Cellular::ChangePINTask(const string &old_pin, const string &new_pin) {
576 VLOG(2) << __func__ << "(" << old_pin << ", " << new_pin << ")";
577 CHECK_EQ(kTypeGSM, type_);
578 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
579 gsm_card_proxy_->ChangePIN(old_pin, new_pin);
580}
581
Darin Petkovceb68172011-07-29 14:47:48 -0700582void Cellular::GetModemInfo() {
Darin Petkovd2045802011-08-23 11:09:25 -0700583 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovceb68172011-07-29 14:47:48 -0700584 ModemProxyInterface::Info info = proxy_->GetInfo();
585 manufacturer_ = info._1;
586 model_id_ = info._2;
587 hardware_revision_ = info._3;
588 VLOG(2) << "ModemInfo: " << manufacturer_ << ", " << model_id_ << ", "
589 << hardware_revision_;
590}
591
592void Cellular::GetModemRegistrationState() {
Darin Petkovbec79a22011-08-01 14:47:17 -0700593 switch (type_) {
594 case kTypeGSM:
595 GetGSMRegistrationState();
596 break;
597 case kTypeCDMA:
598 GetCDMARegistrationState();
599 break;
600 default: NOTREACHED();
601 }
Darin Petkovd9661952011-08-03 16:25:42 -0700602 HandleNewRegistrationState();
Darin Petkovbec79a22011-08-01 14:47:17 -0700603}
604
605void Cellular::GetCDMARegistrationState() {
606 CHECK_EQ(kTypeCDMA, type_);
Darin Petkovd2045802011-08-23 11:09:25 -0700607 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovbec79a22011-08-01 14:47:17 -0700608 cdma_proxy_->GetRegistrationState(&cdma_.registration_state_1x,
609 &cdma_.registration_state_evdo);
610 VLOG(2) << "CDMA Registration: 1x(" << cdma_.registration_state_1x
611 << ") EVDO(" << cdma_.registration_state_evdo << ")";
Darin Petkovbec79a22011-08-01 14:47:17 -0700612}
613
614void Cellular::GetGSMRegistrationState() {
Darin Petkov9bac6fe2011-08-26 12:49:05 -0700615 CHECK_EQ(kTypeGSM, type_);
616 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
617 ModemGSMNetworkProxyInterface::RegistrationInfo info =
618 gsm_network_proxy_->GetRegistrationInfo();
619 gsm_.registration_state = info._1;
620 gsm_.network_id = info._2;
621 gsm_.operator_name = info._3;
622 VLOG(2) << "GSM Registration: " << gsm_.registration_state << ", "
623 << gsm_.network_id << ", " << gsm_.operator_name;
Darin Petkovceb68172011-07-29 14:47:48 -0700624}
625
Darin Petkovd9661952011-08-03 16:25:42 -0700626void Cellular::HandleNewRegistrationState() {
Paul Stewartac4ac002011-08-26 12:04:26 -0700627 dispatcher()->PostTask(
Darin Petkov0828f5f2011-08-11 10:18:52 -0700628 task_factory_.NewRunnableMethod(
629 &Cellular::HandleNewRegistrationStateTask));
630}
631
632void Cellular::HandleNewRegistrationStateTask() {
Darin Petkovd9661952011-08-03 16:25:42 -0700633 VLOG(2) << __func__;
Darin Petkovd2045802011-08-23 11:09:25 -0700634 const string network_tech = GetNetworkTechnologyString();
635 if (network_tech.empty()) {
Darin Petkovc408e692011-08-17 13:47:15 -0700636 if (state_ == kStateLinked) {
Paul Stewartac4ac002011-08-26 12:04:26 -0700637 manager()->DeregisterService(service_);
Darin Petkovc408e692011-08-17 13:47:15 -0700638 }
Darin Petkovd9661952011-08-03 16:25:42 -0700639 service_ = NULL;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700640 if (state_ == kStateLinked ||
641 state_ == kStateConnected ||
642 state_ == kStateRegistered) {
643 SetState(kStateEnabled);
Darin Petkovd9661952011-08-03 16:25:42 -0700644 }
645 return;
646 }
Darin Petkovd9661952011-08-03 16:25:42 -0700647 if (state_ == kStateEnabled) {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700648 SetState(kStateRegistered);
Darin Petkovd9661952011-08-03 16:25:42 -0700649 }
650 if (!service_.get()) {
651 // For now, no endpoint is created. Revisit if necessary.
652 CreateService();
653 }
654 GetModemSignalQuality();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700655 if (state_ == kStateRegistered && modem_state_ == kModemStateConnected) {
656 SetState(kStateConnected);
657 EstablishLink();
658 }
Darin Petkovd2045802011-08-23 11:09:25 -0700659 service_->set_network_tech(network_tech);
660 service_->set_roaming_state(GetRoamingStateString());
Darin Petkov9bac6fe2011-08-26 12:49:05 -0700661 // TODO(petkov): For GSM, update the serving operator based on the network id
662 // and the mobile provider database.
Darin Petkovd9661952011-08-03 16:25:42 -0700663}
664
665void Cellular::GetModemSignalQuality() {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700666 VLOG(2) << __func__;
Darin Petkovd9661952011-08-03 16:25:42 -0700667 uint32 strength = 0;
668 switch (type_) {
669 case kTypeGSM:
670 strength = GetGSMSignalQuality();
671 break;
672 case kTypeCDMA:
673 strength = GetCDMASignalQuality();
674 break;
675 default: NOTREACHED();
676 }
677 HandleNewSignalQuality(strength);
678}
679
680uint32 Cellular::GetCDMASignalQuality() {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700681 VLOG(2) << __func__;
Darin Petkovd9661952011-08-03 16:25:42 -0700682 CHECK_EQ(kTypeCDMA, type_);
683 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
684 return cdma_proxy_->GetSignalQuality();
685}
686
687uint32 Cellular::GetGSMSignalQuality() {
Darin Petkov22b72bf2011-08-29 14:01:20 -0700688 VLOG(2) << __func__;
689 CHECK_EQ(kTypeGSM, type_);
690 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
691 return gsm_network_proxy_->GetSignalQuality();
Darin Petkovd9661952011-08-03 16:25:42 -0700692}
693
694void Cellular::HandleNewSignalQuality(uint32 strength) {
695 VLOG(2) << "Signal strength: " << strength;
696 if (service_.get()) {
697 service_->set_strength(strength);
698 }
699}
700
701void Cellular::CreateService() {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700702 VLOG(2) << __func__;
Darin Petkovd9661952011-08-03 16:25:42 -0700703 CHECK(!service_.get());
704 service_ =
Paul Stewartac4ac002011-08-26 12:04:26 -0700705 new CellularService(control_interface(), dispatcher(), manager(), this);
Darin Petkovc408e692011-08-17 13:47:15 -0700706 switch (type_) {
707 case kTypeGSM:
Darin Petkov51489002011-08-18 13:13:20 -0700708 service_->set_activation_state(flimflam::kActivationStateActivated);
Darin Petkov3335b372011-08-22 11:05:32 -0700709 // TODO(petkov): Set serving operator.
Darin Petkovc408e692011-08-17 13:47:15 -0700710 break;
711 case kTypeCDMA:
712 service_->set_payment_url(cdma_.payment_url);
713 service_->set_usage_url(cdma_.usage_url);
Darin Petkov3335b372011-08-22 11:05:32 -0700714 service_->set_serving_operator(home_provider_);
Darin Petkovc408e692011-08-17 13:47:15 -0700715 HandleNewCDMAActivationState(MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR);
716 break;
717 default:
718 NOTREACHED();
Darin Petkovcc044422011-08-17 13:30:06 -0700719 }
Darin Petkovf5f61e02011-07-29 11:35:40 -0700720}
721
Darin Petkov6f9eaa32011-08-09 15:26:44 -0700722bool Cellular::TechnologyIs(const Device::Technology type) const {
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700723 return type == Device::kCellular;
724}
725
Darin Petkov4d6d9412011-08-24 13:19:54 -0700726void Cellular::Connect(Error *error) {
Darin Petkovc5f56562011-08-06 16:40:05 -0700727 VLOG(2) << __func__;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700728 if (state_ == kStateConnected ||
729 state_ == kStateLinked) {
Darin Petkov4d6d9412011-08-24 13:19:54 -0700730 LOG(ERROR) << "Already connected; connection request ignored.";
731 CHECK(error);
732 error->Populate(Error::kAlreadyConnected);
Darin Petkovc5f56562011-08-06 16:40:05 -0700733 return;
734 }
735 CHECK_EQ(kStateRegistered, state_);
Darin Petkovd2045802011-08-23 11:09:25 -0700736
737 if (!allow_roaming_ &&
738 service_->roaming_state() == flimflam::kRoamingStateRoaming) {
739 LOG(ERROR) << "Roaming disallowed; connection request ignored.";
Darin Petkov4d6d9412011-08-24 13:19:54 -0700740 CHECK(error);
741 error->Populate(Error::kNotOnHomeNetwork);
Darin Petkovd2045802011-08-23 11:09:25 -0700742 return;
743 }
744
Darin Petkovc5f56562011-08-06 16:40:05 -0700745 DBusPropertiesMap properties;
746 const char *phone_number = NULL;
747 switch (type_) {
748 case kTypeGSM:
749 phone_number = kPhoneNumberGSM;
750 break;
751 case kTypeCDMA:
752 phone_number = kPhoneNumberCDMA;
753 break;
754 default: NOTREACHED();
755 }
756 properties[kConnectPropertyPhoneNumber].writer().append_string(phone_number);
757 // TODO(petkov): Setup apn and "home_only".
758
759 // Defer connect because we may be in a dbus-c++ callback.
Paul Stewartac4ac002011-08-26 12:04:26 -0700760 dispatcher()->PostTask(
Darin Petkovc5f56562011-08-06 16:40:05 -0700761 task_factory_.NewRunnableMethod(&Cellular::ConnectTask, properties));
762}
763
764void Cellular::ConnectTask(const DBusPropertiesMap &properties) {
765 VLOG(2) << __func__;
Darin Petkovbac96002011-08-09 13:22:00 -0700766 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovc5f56562011-08-06 16:40:05 -0700767 simple_proxy_->Connect(properties);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700768 SetState(kStateConnected);
Darin Petkovbac96002011-08-09 13:22:00 -0700769 EstablishLink();
770}
771
772void Cellular::EstablishLink() {
773 VLOG(2) << __func__;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700774 CHECK_EQ(kStateConnected, state_);
775 unsigned int flags = 0;
Paul Stewartac4ac002011-08-26 12:04:26 -0700776 if (manager()->device_info()->GetFlags(interface_index(), &flags) &&
Darin Petkov0828f5f2011-08-11 10:18:52 -0700777 (flags & IFF_UP) != 0) {
778 LinkEvent(flags, IFF_UP);
779 return;
780 }
781 // TODO(petkov): Provide a timeout for a failed link-up request.
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -0700782 rtnl_handler()->SetInterfaceFlags(interface_index(), IFF_UP, IFF_UP);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700783}
784
785void Cellular::LinkEvent(unsigned int flags, unsigned int change) {
786 Device::LinkEvent(flags, change);
787 if ((flags & IFF_UP) != 0 && state_ == kStateConnected) {
Paul Stewartac4ac002011-08-26 12:04:26 -0700788 LOG(INFO) << link_name() << " is up.";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700789 SetState(kStateLinked);
Paul Stewartac4ac002011-08-26 12:04:26 -0700790 manager()->RegisterService(service_);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700791 // TODO(petkov): For GSM, remember the APN.
Darin Petkov60b8c3b2011-08-25 11:03:20 -0700792 if (AcquireDHCPConfig()) {
793 SelectService(service_);
794 SetServiceState(Service::kStateConfiguring);
795 } else {
796 LOG(ERROR) << "Unable to acquire DHCP config.";
797 }
Darin Petkov0828f5f2011-08-11 10:18:52 -0700798 } else if ((flags & IFF_UP) == 0 && state_ == kStateLinked) {
799 SetState(kStateConnected);
Paul Stewartac4ac002011-08-26 12:04:26 -0700800 manager()->DeregisterService(service_);
Darin Petkov60b8c3b2011-08-25 11:03:20 -0700801 SelectService(NULL);
Darin Petkov77cb6812011-08-15 16:19:41 -0700802 DestroyIPConfig();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700803 }
Darin Petkovc5f56562011-08-06 16:40:05 -0700804}
805
Darin Petkovc0865312011-09-16 15:31:20 -0700806void Cellular::Scan(Error *error) {
807 VLOG(2) << __func__;
808 if (type_ != kTypeGSM) {
809 const string kMessage = "Network scanning support for GSM only.";
810 LOG(ERROR) << kMessage;
811 CHECK(error);
812 error->Populate(Error::kNotSupported, kMessage);
813 return;
814 }
815 // Defer scan because we may be in a dbus-c++ callback.
816 dispatcher()->PostTask(
817 task_factory_.NewRunnableMethod(&Cellular::ScanTask));
818}
819
820void Cellular::ScanTask() {
821 VLOG(2) << __func__;
822 // TODO(petkov): Defer scan requests if a scan is in progress already.
823 CHECK_EQ(kTypeGSM, type_);
824 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583). This is a
825 // must for this call which is basically a stub at this point.
826 ModemGSMNetworkProxyInterface::ScanResults results =
827 gsm_network_proxy_->Scan();
828 found_networks_.clear();
829 for (ModemGSMNetworkProxyInterface::ScanResults::const_iterator it =
830 results.begin(); it != results.end(); ++it) {
831 found_networks_.push_back(ParseScanResult(*it));
832 }
833}
834
835Stringmap Cellular::ParseScanResult(
836 const ModemGSMNetworkProxyInterface::ScanResult &result) {
837 Stringmap parsed;
838 for (ModemGSMNetworkProxyInterface::ScanResult::const_iterator it =
839 result.begin(); it != result.end(); ++it) {
840 // TODO(petkov): Define these in system_api/service_constants.h. The
841 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
842 static const char * const kStatusString[] = {
843 "unknown",
844 "available",
845 "current",
846 "forbidden",
847 };
848 // TODO(petkov): Do we need the finer level of granularity here or can we
849 // use the same granularity as GetNetworkTechnologyString (e.g.,
850 // HSDPA->"HSPA").
851 static const char * const kTechnologyString[] = {
852 flimflam::kNetworkTechnologyGsm,
853 "GSM Compact",
854 flimflam::kNetworkTechnologyUmts,
855 flimflam::kNetworkTechnologyEdge,
856 "HSDPA",
857 "HSUPA",
858 flimflam::kNetworkTechnologyHspa,
859 };
860 VLOG(2) << "Network property: " << it->first << " = " << it->second;
861 if (it->first == kNetworkPropertyStatus) {
862 int status = 0;
863 if (base::StringToInt(it->second, &status) &&
864 status >= 0 &&
865 status < static_cast<int>(arraysize(kStatusString))) {
866 parsed[flimflam::kStatusProperty] = kStatusString[status];
867 } else {
868 LOG(ERROR) << "Unexpected status value: " << it->second;
869 }
870 } else if (it->first == kNetworkPropertyID) {
871 parsed[flimflam::kNetworkIdProperty] = it->second;
872 } else if (it->first == kNetworkPropertyLongName) {
873 parsed[flimflam::kLongNameProperty] = it->second;
874 } else if (it->first == kNetworkPropertyShortName) {
875 parsed[flimflam::kShortNameProperty] = it->second;
876 } else if (it->first == kNetworkPropertyAccessTechnology) {
877 int tech = 0;
878 if (base::StringToInt(it->second, &tech) &&
879 tech >= 0 &&
880 tech < static_cast<int>(arraysize(kTechnologyString))) {
881 parsed[flimflam::kTechnologyProperty] = kTechnologyString[tech];
882 } else {
883 LOG(ERROR) << "Unexpected technology value: " << it->second;
884 }
885 } else {
886 LOG(WARNING) << "Unknown network property ignored: " << it->first;
887 }
888 }
889 // TODO(petkov): If long name is not set and there's a network ID, do a mobile
890 // database lookup (crosbug.com/19699).
891 return parsed;
892}
893
Darin Petkovb100ae72011-08-24 16:19:45 -0700894void Cellular::Activate(const string &carrier, Error *error) {
Darin Petkovc0865312011-09-16 15:31:20 -0700895 VLOG(2) << __func__ << "(" << carrier << ")";
Darin Petkovb100ae72011-08-24 16:19:45 -0700896 if (type_ != kTypeCDMA) {
897 const string kMessage = "Unable to activate non-CDMA modem.";
898 LOG(ERROR) << kMessage;
899 CHECK(error);
900 error->Populate(Error::kInvalidArguments, kMessage);
901 return;
902 }
903 if (state_ != kStateEnabled &&
904 state_ != kStateRegistered) {
905 const string kMessage = "Unable to activate in " + GetStateString(state_);
906 LOG(ERROR) << kMessage;
907 CHECK(error);
908 error->Populate(Error::kInvalidArguments, kMessage);
909 return;
910 }
Darin Petkovc408e692011-08-17 13:47:15 -0700911 // Defer connect because we may be in a dbus-c++ callback.
Paul Stewartac4ac002011-08-26 12:04:26 -0700912 dispatcher()->PostTask(
Darin Petkovc408e692011-08-17 13:47:15 -0700913 task_factory_.NewRunnableMethod(&Cellular::ActivateTask, carrier));
914}
915
916void Cellular::ActivateTask(const string &carrier) {
917 VLOG(2) << __func__ << "(" << carrier << ")";
Darin Petkovc0865312011-09-16 15:31:20 -0700918 CHECK_EQ(kTypeCDMA, type_);
Darin Petkovb100ae72011-08-24 16:19:45 -0700919 if (state_ != kStateEnabled &&
920 state_ != kStateRegistered) {
Darin Petkovc408e692011-08-17 13:47:15 -0700921 LOG(ERROR) << "Unable to activate in " << GetStateString(state_);
922 return;
923 }
924 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
925 uint32 status = cdma_proxy_->Activate(carrier);
926 if (status == MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR) {
927 cdma_.activation_state = MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING;
928 }
929 HandleNewCDMAActivationState(status);
930}
931
932void Cellular::HandleNewCDMAActivationState(uint32 error) {
933 if (!service_.get()) {
934 return;
935 }
936 service_->set_activation_state(
937 GetCDMAActivationStateString(cdma_.activation_state));
Darin Petkov51489002011-08-18 13:13:20 -0700938 service_->set_error(GetCDMAActivationErrorString(error));
Darin Petkovc408e692011-08-17 13:47:15 -0700939}
940
Darin Petkovb27e5442011-08-16 14:36:45 -0700941void Cellular::OnCDMAActivationStateChanged(
942 uint32 activation_state,
943 uint32 activation_error,
944 const DBusPropertiesMap &status_changes) {
945 CHECK_EQ(kTypeCDMA, type_);
946 DBusProperties::GetString(status_changes, "mdn", &mdn_);
947 DBusProperties::GetString(status_changes, "min", &min_);
Darin Petkovcc044422011-08-17 13:30:06 -0700948 if (DBusProperties::GetString(
949 status_changes, "payment_url", &cdma_.payment_url) &&
Darin Petkovb27e5442011-08-16 14:36:45 -0700950 service_.get()) {
Darin Petkovcc044422011-08-17 13:30:06 -0700951 service_->set_payment_url(cdma_.payment_url);
Darin Petkovb27e5442011-08-16 14:36:45 -0700952 }
Darin Petkovc408e692011-08-17 13:47:15 -0700953 cdma_.activation_state = activation_state;
954 HandleNewCDMAActivationState(activation_error);
Darin Petkovb27e5442011-08-16 14:36:45 -0700955}
956
Darin Petkovd9661952011-08-03 16:25:42 -0700957void Cellular::OnCDMARegistrationStateChanged(uint32 state_1x,
958 uint32 state_evdo) {
959 CHECK_EQ(kTypeCDMA, type_);
960 cdma_.registration_state_1x = state_1x;
961 cdma_.registration_state_evdo = state_evdo;
962 HandleNewRegistrationState();
963}
964
965void Cellular::OnCDMASignalQualityChanged(uint32 strength) {
966 CHECK_EQ(kTypeCDMA, type_);
967 HandleNewSignalQuality(strength);
968}
969
Darin Petkova1e0a1c2011-08-25 15:08:33 -0700970void Cellular::OnGSMNetworkModeChanged(uint32 mode) {
971 // TODO(petkov): Implement this.
972 NOTIMPLEMENTED();
973}
974
975void Cellular::OnGSMRegistrationInfoChanged(uint32 status,
976 const string &operator_code,
977 const string &operator_name) {
Darin Petkov9bac6fe2011-08-26 12:49:05 -0700978 CHECK_EQ(kTypeGSM, type_);
979 gsm_.registration_state = status;
980 gsm_.network_id = operator_code;
981 gsm_.operator_name = operator_name;
982 HandleNewRegistrationState();
Darin Petkova1e0a1c2011-08-25 15:08:33 -0700983}
984
985void Cellular::OnGSMSignalQualityChanged(uint32 quality) {
Darin Petkov22b72bf2011-08-29 14:01:20 -0700986 CHECK_EQ(kTypeGSM, type_);
987 HandleNewSignalQuality(quality);
Darin Petkova1e0a1c2011-08-25 15:08:33 -0700988}
989
Darin Petkovc5f56562011-08-06 16:40:05 -0700990void Cellular::OnModemStateChanged(uint32 old_state,
991 uint32 new_state,
992 uint32 reason) {
993 // TODO(petkov): Implement this.
994 NOTIMPLEMENTED();
995}
996
Darin Petkov48a511a2011-09-15 10:33:37 -0700997void Cellular::SetGSMAccessTechnology(uint32 access_technology) {
998 CHECK_EQ(kTypeGSM, type_);
999 gsm_.access_technology = access_technology;
1000 if (service_.get()) {
1001 service_->set_network_tech(GetNetworkTechnologyString());
1002 }
1003}
1004
Chris Masone889666b2011-07-03 12:58:50 -07001005StrIntPair Cellular::SimLockStatusToProperty() {
1006 return StrIntPair(make_pair(flimflam::kSIMLockTypeProperty,
1007 sim_lock_status_.lock_type),
1008 make_pair(flimflam::kSIMLockRetriesLeftProperty,
1009 sim_lock_status_.retries_left));
1010}
1011
Chris Masone889666b2011-07-03 12:58:50 -07001012void Cellular::HelpRegisterDerivedStrIntPair(
1013 const string &name,
1014 StrIntPair(Cellular::*get)(void),
1015 bool(Cellular::*set)(const StrIntPair&)) {
mukesh agrawalde29fa82011-09-16 16:16:36 -07001016 mutable_store()->RegisterDerivedStrIntPair(
Chris Masone889666b2011-07-03 12:58:50 -07001017 name,
1018 StrIntPairAccessor(
1019 new CustomAccessor<Cellular, StrIntPair>(this, get, set)));
1020}
1021
Chris Masone3bd3c8c2011-06-13 08:20:26 -07001022} // namespace shill