blob: 7a1825a26630767388295a4380de64a8362756a0 [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>
8#include <linux/if.h>
9
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 Petkove9d12e02011-07-27 15:09:37 -070015#include <base/stringprintf.h>
Chris Masoneb925cc82011-06-22 15:39:57 -070016#include <chromeos/dbus/service_constants.h>
Darin Petkovbec79a22011-08-01 14:47:17 -070017#include <mm/mm-modem.h>
Chris Masone3bd3c8c2011-06-13 08:20:26 -070018
19#include "shill/cellular_service.h"
20#include "shill/control_interface.h"
21#include "shill/device.h"
22#include "shill/device_info.h"
Darin Petkov4d6d9412011-08-24 13:19:54 -070023#include "shill/error.h"
Chris Masone3bd3c8c2011-06-13 08:20:26 -070024#include "shill/manager.h"
Darin Petkove604f702011-07-28 15:51:17 -070025#include "shill/modem_simple_proxy_interface.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070026#include "shill/profile.h"
Chris Masone889666b2011-07-03 12:58:50 -070027#include "shill/property_accessor.h"
Darin Petkove9d12e02011-07-27 15:09:37 -070028#include "shill/proxy_factory.h"
Darin Petkov0828f5f2011-08-11 10:18:52 -070029#include "shill/rtnl_handler.h"
Chris Masone3bd3c8c2011-06-13 08:20:26 -070030#include "shill/shill_event.h"
31
Chris Masone889666b2011-07-03 12:58:50 -070032using std::make_pair;
Chris Masone3bd3c8c2011-06-13 08:20:26 -070033using std::string;
Chris Masone889666b2011-07-03 12:58:50 -070034using std::vector;
Chris Masone3bd3c8c2011-06-13 08:20:26 -070035
36namespace shill {
37
Darin Petkovc5f56562011-08-06 16:40:05 -070038const char Cellular::kConnectPropertyPhoneNumber[] = "number";
39const char Cellular::kPhoneNumberCDMA[] = "#777";
40const char Cellular::kPhoneNumberGSM[] = "*99#";
41
Darin Petkov3335b372011-08-22 11:05:32 -070042Cellular::Operator::Operator() {
43 SetName("");
44 SetCode("");
45 SetCountry("");
46}
47
48Cellular::Operator::~Operator() {}
49
50void Cellular::Operator::CopyFrom(const Operator &oper) {
51 dict_ = oper.dict_;
52}
53
54const string &Cellular::Operator::GetName() const {
55 return dict_.find(flimflam::kOperatorNameKey)->second;
56}
57
58void Cellular::Operator::SetName(const string &name) {
59 dict_[flimflam::kOperatorNameKey] = name;
60}
61
62const string &Cellular::Operator::GetCode() const {
63 return dict_.find(flimflam::kOperatorCodeKey)->second;
64}
65
66void Cellular::Operator::SetCode(const string &code) {
67 dict_[flimflam::kOperatorCodeKey] = code;
68}
69
70const string &Cellular::Operator::GetCountry() const {
71 return dict_.find(flimflam::kOperatorCountryKey)->second;
72}
73
74void Cellular::Operator::SetCountry(const string &country) {
75 dict_[flimflam::kOperatorCountryKey] = country;
76}
77
78const Stringmap &Cellular::Operator::ToDict() const {
79 return dict_;
80}
81
Chris Masone889666b2011-07-03 12:58:50 -070082Cellular::Network::Network() {
83 dict_[flimflam::kStatusProperty] = "";
84 dict_[flimflam::kNetworkIdProperty] = "";
85 dict_[flimflam::kShortNameProperty] = "";
86 dict_[flimflam::kLongNameProperty] = "";
87 dict_[flimflam::kTechnologyProperty] = "";
88}
89
90Cellular::Network::~Network() {}
91
Darin Petkov3335b372011-08-22 11:05:32 -070092const string &Cellular::Network::GetStatus() const {
Chris Masone889666b2011-07-03 12:58:50 -070093 return dict_.find(flimflam::kStatusProperty)->second;
94}
95
Darin Petkov3335b372011-08-22 11:05:32 -070096void Cellular::Network::SetStatus(const string &status) {
Chris Masone889666b2011-07-03 12:58:50 -070097 dict_[flimflam::kStatusProperty] = status;
98}
99
Darin Petkov3335b372011-08-22 11:05:32 -0700100const string &Cellular::Network::GetId() const {
Chris Masone889666b2011-07-03 12:58:50 -0700101 return dict_.find(flimflam::kNetworkIdProperty)->second;
102}
103
Darin Petkov3335b372011-08-22 11:05:32 -0700104void Cellular::Network::SetId(const string &id) {
Chris Masone889666b2011-07-03 12:58:50 -0700105 dict_[flimflam::kNetworkIdProperty] = id;
106}
107
Darin Petkov3335b372011-08-22 11:05:32 -0700108const string &Cellular::Network::GetShortName() const {
Chris Masone889666b2011-07-03 12:58:50 -0700109 return dict_.find(flimflam::kShortNameProperty)->second;
110}
111
Darin Petkov3335b372011-08-22 11:05:32 -0700112void Cellular::Network::SetShortName(const string &name) {
Chris Masone889666b2011-07-03 12:58:50 -0700113 dict_[flimflam::kShortNameProperty] = name;
114}
115
Darin Petkov3335b372011-08-22 11:05:32 -0700116const string &Cellular::Network::GetLongName() const {
Chris Masone889666b2011-07-03 12:58:50 -0700117 return dict_.find(flimflam::kLongNameProperty)->second;
118}
119
Darin Petkov3335b372011-08-22 11:05:32 -0700120void Cellular::Network::SetLongName(const string &name) {
Chris Masone889666b2011-07-03 12:58:50 -0700121 dict_[flimflam::kLongNameProperty] = name;
122}
123
Darin Petkov3335b372011-08-22 11:05:32 -0700124const string &Cellular::Network::GetTechnology() const {
Chris Masone889666b2011-07-03 12:58:50 -0700125 return dict_.find(flimflam::kTechnologyProperty)->second;
126}
127
Darin Petkov3335b372011-08-22 11:05:32 -0700128void Cellular::Network::SetTechnology(const string &technology) {
Chris Masone889666b2011-07-03 12:58:50 -0700129 dict_[flimflam::kTechnologyProperty] = technology;
130}
131
132const Stringmap &Cellular::Network::ToDict() const {
133 return dict_;
134}
135
Darin Petkovbec79a22011-08-01 14:47:17 -0700136Cellular::CDMA::CDMA()
137 : registration_state_evdo(MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN),
138 registration_state_1x(MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN),
Darin Petkovcc044422011-08-17 13:30:06 -0700139 activation_state(MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED),
140 prl_version(0) {}
Darin Petkovbec79a22011-08-01 14:47:17 -0700141
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700142Cellular::Cellular(ControlInterface *control_interface,
143 EventDispatcher *dispatcher,
144 Manager *manager,
Darin Petkove9d12e02011-07-27 15:09:37 -0700145 const string &link_name,
Darin Petkov3335b372011-08-22 11:05:32 -0700146 const string &address,
Darin Petkove9d12e02011-07-27 15:09:37 -0700147 int interface_index,
148 Type type,
149 const string &owner,
150 const string &path)
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700151 : Device(control_interface,
152 dispatcher,
153 manager,
Darin Petkove9d12e02011-07-27 15:09:37 -0700154 link_name,
Chris Masone626719f2011-08-18 16:58:48 -0700155 address,
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700156 interface_index),
Darin Petkove9d12e02011-07-27 15:09:37 -0700157 type_(type),
158 state_(kStateDisabled),
Darin Petkovbac96002011-08-09 13:22:00 -0700159 modem_state_(kModemStateUnknown),
Darin Petkove9d12e02011-07-27 15:09:37 -0700160 dbus_owner_(owner),
161 dbus_path_(path),
Darin Petkovc5f56562011-08-06 16:40:05 -0700162 task_factory_(this),
Darin Petkove9d12e02011-07-27 15:09:37 -0700163 allow_roaming_(false),
Darin Petkove9d12e02011-07-27 15:09:37 -0700164 scanning_(false),
165 scan_interval_(0) {
Darin Petkova1e0a1c2011-08-25 15:08:33 -0700166 store_.RegisterConstString(flimflam::kCarrierProperty, &carrier_);
Darin Petkove9d12e02011-07-27 15:09:37 -0700167 store_.RegisterConstString(flimflam::kDBusConnectionProperty, &dbus_owner_);
168 store_.RegisterConstString(flimflam::kDBusObjectProperty, &dbus_path_);
Chris Masone4d42df82011-07-02 17:09:39 -0700169 store_.RegisterBool(flimflam::kCellularAllowRoamingProperty, &allow_roaming_);
Chris Masone27c4aa52011-07-02 13:10:14 -0700170 store_.RegisterConstString(flimflam::kEsnProperty, &esn_);
Chris Masone27c4aa52011-07-02 13:10:14 -0700171 store_.RegisterConstString(flimflam::kFirmwareRevisionProperty,
172 &firmware_revision_);
173 store_.RegisterConstString(flimflam::kHardwareRevisionProperty,
174 &hardware_revision_);
Darin Petkov3335b372011-08-22 11:05:32 -0700175 store_.RegisterConstStringmap(flimflam::kHomeProviderProperty,
176 &home_provider_.ToDict());
Chris Masone4d42df82011-07-02 17:09:39 -0700177 store_.RegisterConstString(flimflam::kImeiProperty, &imei_);
178 store_.RegisterConstString(flimflam::kImsiProperty, &imsi_);
179 store_.RegisterConstString(flimflam::kManufacturerProperty, &manufacturer_);
180 store_.RegisterConstString(flimflam::kMdnProperty, &mdn_);
181 store_.RegisterConstString(flimflam::kMeidProperty, &meid_);
182 store_.RegisterConstString(flimflam::kMinProperty, &min_);
183 store_.RegisterConstString(flimflam::kModelIDProperty, &model_id_);
Darin Petkovcc044422011-08-17 13:30:06 -0700184 store_.RegisterConstUint16(flimflam::kPRLVersionProperty, &cdma_.prl_version);
Darin Petkova1e0a1c2011-08-25 15:08:33 -0700185 store_.RegisterConstString(flimflam::kSelectedNetworkProperty,
186 &selected_network_);
Chris Masoneb925cc82011-06-22 15:39:57 -0700187
Chris Masone889666b2011-07-03 12:58:50 -0700188 HelpRegisterDerivedStrIntPair(flimflam::kSIMLockStatusProperty,
189 &Cellular::SimLockStatusToProperty,
190 NULL);
191 HelpRegisterDerivedStringmaps(flimflam::kFoundNetworksProperty,
192 &Cellular::EnumerateNetworks,
193 NULL);
Chris Masoneb925cc82011-06-22 15:39:57 -0700194
Chris Masone4d42df82011-07-02 17:09:39 -0700195 store_.RegisterConstBool(flimflam::kScanningProperty, &scanning_);
196 store_.RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
197
Darin Petkove9d12e02011-07-27 15:09:37 -0700198 VLOG(2) << "Cellular device " << link_name_ << " initialized: "
199 << GetTypeString();
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700200}
201
Darin Petkove9d12e02011-07-27 15:09:37 -0700202Cellular::~Cellular() {}
203
Darin Petkovcc044422011-08-17 13:30:06 -0700204string Cellular::GetTypeString() const {
Darin Petkove9d12e02011-07-27 15:09:37 -0700205 switch (type_) {
206 case kTypeGSM: return "CellularTypeGSM";
207 case kTypeCDMA: return "CellularTypeCDMA";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700208 default: NOTREACHED();
Darin Petkove9d12e02011-07-27 15:09:37 -0700209 }
Darin Petkov0828f5f2011-08-11 10:18:52 -0700210 return StringPrintf("CellularTypeUnknown-%d", type_);
Darin Petkove9d12e02011-07-27 15:09:37 -0700211}
212
Darin Petkovcc044422011-08-17 13:30:06 -0700213// static
214string Cellular::GetStateString(State state) {
215 switch (state) {
Darin Petkove9d12e02011-07-27 15:09:37 -0700216 case kStateDisabled: return "CellularStateDisabled";
217 case kStateEnabled: return "CellularStateEnabled";
218 case kStateRegistered: return "CellularStateRegistered";
219 case kStateConnected: return "CellularStateConnected";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700220 case kStateLinked: return "CellularStateLinked";
221 default: NOTREACHED();
Darin Petkove9d12e02011-07-27 15:09:37 -0700222 }
Darin Petkovcc044422011-08-17 13:30:06 -0700223 return StringPrintf("CellularStateUnknown-%d", state);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700224}
225
Darin Petkovd2045802011-08-23 11:09:25 -0700226string Cellular::GetNetworkTechnologyString() const {
227 switch (type_) {
228 case kTypeGSM:
229 // TODO(petkov): Implement this.
230 NOTIMPLEMENTED();
231 break;
232 case kTypeCDMA:
233 if (cdma_.registration_state_evdo !=
234 MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN) {
235 return flimflam::kNetworkTechnologyEvdo;
236 }
237 if (cdma_.registration_state_1x !=
238 MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN) {
239 return flimflam::kNetworkTechnology1Xrtt;
240 }
241 break;
242 default:
243 NOTREACHED();
244 }
245 return "";
246}
247
248string Cellular::GetRoamingStateString() const {
249 switch (type_) {
250 case kTypeGSM:
251 // TODO(petkov): Implement this.
252 NOTIMPLEMENTED();
253 break;
254 case kTypeCDMA: {
255 uint32 state = cdma_.registration_state_evdo;
256 if (state == MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN) {
257 state = cdma_.registration_state_1x;
258 }
259 switch (state) {
260 case MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN:
261 case MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED:
262 break;
263 case MM_MODEM_CDMA_REGISTRATION_STATE_HOME:
264 return flimflam::kRoamingStateHome;
265 case MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING:
266 return flimflam::kRoamingStateRoaming;
267 default:
268 NOTREACHED();
269 }
270 break;
271 }
272 default:
273 NOTREACHED();
274 }
275 return flimflam::kRoamingStateUnknown;
276}
277
Darin Petkovc408e692011-08-17 13:47:15 -0700278// static
279string Cellular::GetCDMAActivationStateString(uint32 state) {
280 switch (state) {
281 case MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED:
Darin Petkov51489002011-08-18 13:13:20 -0700282 return flimflam::kActivationStateActivated;
Darin Petkovc408e692011-08-17 13:47:15 -0700283 case MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING:
Darin Petkov51489002011-08-18 13:13:20 -0700284 return flimflam::kActivationStateActivating;
Darin Petkovc408e692011-08-17 13:47:15 -0700285 case MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED:
Darin Petkov51489002011-08-18 13:13:20 -0700286 return flimflam::kActivationStateNotActivated;
Darin Petkovc408e692011-08-17 13:47:15 -0700287 case MM_MODEM_CDMA_ACTIVATION_STATE_PARTIALLY_ACTIVATED:
Darin Petkov51489002011-08-18 13:13:20 -0700288 return flimflam::kActivationStatePartiallyActivated;
Darin Petkovc408e692011-08-17 13:47:15 -0700289 default:
Darin Petkov51489002011-08-18 13:13:20 -0700290 return flimflam::kActivationStateUnknown;
291 }
292}
293
294// static
295string Cellular::GetCDMAActivationErrorString(uint32 error) {
296 switch (error) {
297 case MM_MODEM_CDMA_ACTIVATION_ERROR_WRONG_RADIO_INTERFACE:
298 return flimflam::kErrorNeedEvdo;
299 case MM_MODEM_CDMA_ACTIVATION_ERROR_ROAMING:
300 return flimflam::kErrorNeedHomeNetwork;
301 case MM_MODEM_CDMA_ACTIVATION_ERROR_COULD_NOT_CONNECT:
302 case MM_MODEM_CDMA_ACTIVATION_ERROR_SECURITY_AUTHENTICATION_FAILED:
303 case MM_MODEM_CDMA_ACTIVATION_ERROR_PROVISIONING_FAILED:
304 return flimflam::kErrorOtaspFailed;
305 case MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR:
306 return "";
307 case MM_MODEM_CDMA_ACTIVATION_ERROR_NO_SIGNAL:
308 default:
309 return flimflam::kErrorActivationFailed;
Darin Petkovc408e692011-08-17 13:47:15 -0700310 }
311}
312
Darin Petkov0828f5f2011-08-11 10:18:52 -0700313void Cellular::SetState(State state) {
Darin Petkovcc044422011-08-17 13:30:06 -0700314 VLOG(2) << GetStateString(state_) << " -> " << GetStateString(state);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700315 state_ = state;
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700316}
317
318void Cellular::Start() {
Darin Petkovcc044422011-08-17 13:30:06 -0700319 LOG(INFO) << __func__ << ": " << GetStateString(state_);
Darin Petkov3335b372011-08-22 11:05:32 -0700320 Device::Start();
Darin Petkovbec79a22011-08-01 14:47:17 -0700321 InitProxies();
Darin Petkovf5f61e02011-07-29 11:35:40 -0700322 EnableModem();
Darin Petkovceb68172011-07-29 14:47:48 -0700323 if (type_ == kTypeGSM) {
324 RegisterGSMModem();
325 }
Darin Petkovf5f61e02011-07-29 11:35:40 -0700326 GetModemStatus();
Darin Petkovceb68172011-07-29 14:47:48 -0700327 GetModemIdentifiers();
328 if (type_ == kTypeGSM) {
329 GetGSMProperties();
330 }
331 GetModemInfo();
332 GetModemRegistrationState();
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700333}
334
335void Cellular::Stop() {
Darin Petkove9d12e02011-07-27 15:09:37 -0700336 proxy_.reset();
Darin Petkove604f702011-07-28 15:51:17 -0700337 simple_proxy_.reset();
Darin Petkovbec79a22011-08-01 14:47:17 -0700338 cdma_proxy_.reset();
Chris Masone2b105542011-06-22 10:58:09 -0700339 manager_->DeregisterService(service_);
Darin Petkove9d12e02011-07-27 15:09:37 -0700340 service_ = NULL; // Breaks a reference cycle.
Darin Petkov60b8c3b2011-08-25 11:03:20 -0700341 SelectService(NULL);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700342 SetState(kStateDisabled);
343 RTNLHandler::GetInstance()->SetInterfaceFlags(interface_index_, 0, IFF_UP);
Darin Petkov3335b372011-08-22 11:05:32 -0700344 Device::Stop();
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700345}
346
Darin Petkovbec79a22011-08-01 14:47:17 -0700347void Cellular::InitProxies() {
Darin Petkovcc044422011-08-17 13:30:06 -0700348 VLOG(2) << __func__;
Darin Petkovbec79a22011-08-01 14:47:17 -0700349 proxy_.reset(
Darin Petkovc5f56562011-08-06 16:40:05 -0700350 ProxyFactory::factory()->CreateModemProxy(this, dbus_path_, dbus_owner_));
Darin Petkovbec79a22011-08-01 14:47:17 -0700351 simple_proxy_.reset(
352 ProxyFactory::factory()->CreateModemSimpleProxy(
353 dbus_path_, dbus_owner_));
354 switch (type_) {
355 case kTypeGSM:
Darin Petkova1e0a1c2011-08-25 15:08:33 -0700356 gsm_network_proxy_.reset(
357 ProxyFactory::factory()->CreateModemGSMNetworkProxy(
358 this, dbus_path_, dbus_owner_));
Darin Petkovbec79a22011-08-01 14:47:17 -0700359 break;
360 case kTypeCDMA:
361 cdma_proxy_.reset(
362 ProxyFactory::factory()->CreateModemCDMAProxy(
Darin Petkovd9661952011-08-03 16:25:42 -0700363 this, dbus_path_, dbus_owner_));
Darin Petkovbec79a22011-08-01 14:47:17 -0700364 break;
365 default: NOTREACHED();
366 }
367}
368
Darin Petkovf5f61e02011-07-29 11:35:40 -0700369void Cellular::EnableModem() {
370 CHECK_EQ(kStateDisabled, state_);
371 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
372 proxy_->Enable(true);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700373 SetState(kStateEnabled);
Darin Petkovf5f61e02011-07-29 11:35:40 -0700374}
375
376void Cellular::GetModemStatus() {
Darin Petkovceb68172011-07-29 14:47:48 -0700377 CHECK_EQ(kStateEnabled, state_);
Darin Petkovf5f61e02011-07-29 11:35:40 -0700378 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
379 DBusPropertiesMap properties = simple_proxy_->GetStatus();
Darin Petkovceb68172011-07-29 14:47:48 -0700380 if (DBusProperties::GetString(properties, "carrier", &carrier_) &&
381 type_ == kTypeCDMA) {
Darin Petkov3335b372011-08-22 11:05:32 -0700382 home_provider_.SetName(carrier_);
383 home_provider_.SetCode("");
384 home_provider_.SetCountry("us");
Darin Petkovf5f61e02011-07-29 11:35:40 -0700385 }
Darin Petkovceb68172011-07-29 14:47:48 -0700386 DBusProperties::GetString(properties, "meid", &meid_);
387 DBusProperties::GetString(properties, "imei", &imei_);
388 if (DBusProperties::GetString(properties, "imsi", &imsi_) &&
389 type_ == kTypeGSM) {
390 // TODO(petkov): Set GSM provider.
391 }
392 DBusProperties::GetString(properties, "esn", &esn_);
393 DBusProperties::GetString(properties, "mdn", &mdn_);
394 DBusProperties::GetString(properties, "min", &min_);
Darin Petkovceb68172011-07-29 14:47:48 -0700395 DBusProperties::GetString(
396 properties, "firmware_revision", &firmware_revision_);
Darin Petkovb27e5442011-08-16 14:36:45 -0700397
Darin Petkovd2045802011-08-23 11:09:25 -0700398 uint32 state = 0;
399 if (DBusProperties::GetUint32(properties, "state", &state)) {
400 modem_state_ = static_cast<ModemState>(state);
401 }
Darin Petkovb27e5442011-08-16 14:36:45 -0700402
Darin Petkovceb68172011-07-29 14:47:48 -0700403 if (type_ == kTypeCDMA) {
Darin Petkovc408e692011-08-17 13:47:15 -0700404 DBusProperties::GetUint32(
405 properties, "activation_state", &cdma_.activation_state);
Darin Petkovcc044422011-08-17 13:30:06 -0700406 DBusProperties::GetUint16(properties, "prl_version", &cdma_.prl_version);
Darin Petkovcc044422011-08-17 13:30:06 -0700407 // TODO(petkov): For now, get the payment and usage URLs from ModemManager
408 // to match flimflam. In the future, provide a plugin API to get these
409 // directly from the modem driver.
410 DBusProperties::GetString(properties, "payment_url", &cdma_.payment_url);
411 DBusProperties::GetString(properties, "usage_url", &cdma_.usage_url);
Darin Petkovceb68172011-07-29 14:47:48 -0700412 }
413}
414
415void Cellular::GetModemIdentifiers() {
416 // TODO(petkov): Implement this.
417 NOTIMPLEMENTED();
418}
419
420void Cellular::GetGSMProperties() {
421 // TODO(petkov): Implement this.
422 NOTIMPLEMENTED();
423}
424
425void Cellular::RegisterGSMModem() {
Darin Petkova1e0a1c2011-08-25 15:08:33 -0700426 LOG(INFO) << "Registering on: "
427 << (selected_network_.empty() ? "home network" : selected_network_);
428 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
429 gsm_network_proxy_->Register(selected_network_);
Darin Petkovceb68172011-07-29 14:47:48 -0700430}
431
432void Cellular::GetModemInfo() {
Darin Petkovd2045802011-08-23 11:09:25 -0700433 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovceb68172011-07-29 14:47:48 -0700434 ModemProxyInterface::Info info = proxy_->GetInfo();
435 manufacturer_ = info._1;
436 model_id_ = info._2;
437 hardware_revision_ = info._3;
438 VLOG(2) << "ModemInfo: " << manufacturer_ << ", " << model_id_ << ", "
439 << hardware_revision_;
440}
441
442void Cellular::GetModemRegistrationState() {
Darin Petkovbec79a22011-08-01 14:47:17 -0700443 switch (type_) {
444 case kTypeGSM:
445 GetGSMRegistrationState();
446 break;
447 case kTypeCDMA:
448 GetCDMARegistrationState();
449 break;
450 default: NOTREACHED();
451 }
Darin Petkovd9661952011-08-03 16:25:42 -0700452 HandleNewRegistrationState();
Darin Petkovbec79a22011-08-01 14:47:17 -0700453}
454
455void Cellular::GetCDMARegistrationState() {
456 CHECK_EQ(kTypeCDMA, type_);
Darin Petkovd2045802011-08-23 11:09:25 -0700457 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovbec79a22011-08-01 14:47:17 -0700458 cdma_proxy_->GetRegistrationState(&cdma_.registration_state_1x,
459 &cdma_.registration_state_evdo);
460 VLOG(2) << "CDMA Registration: 1x(" << cdma_.registration_state_1x
461 << ") EVDO(" << cdma_.registration_state_evdo << ")";
Darin Petkovbec79a22011-08-01 14:47:17 -0700462}
463
464void Cellular::GetGSMRegistrationState() {
Darin Petkovceb68172011-07-29 14:47:48 -0700465 // TODO(petkov): Implement this.
466 NOTIMPLEMENTED();
467}
468
Darin Petkovd9661952011-08-03 16:25:42 -0700469void Cellular::HandleNewRegistrationState() {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700470 dispatcher_->PostTask(
471 task_factory_.NewRunnableMethod(
472 &Cellular::HandleNewRegistrationStateTask));
473}
474
475void Cellular::HandleNewRegistrationStateTask() {
Darin Petkovd9661952011-08-03 16:25:42 -0700476 VLOG(2) << __func__;
Darin Petkovd2045802011-08-23 11:09:25 -0700477 const string network_tech = GetNetworkTechnologyString();
478 if (network_tech.empty()) {
Darin Petkovc408e692011-08-17 13:47:15 -0700479 if (state_ == kStateLinked) {
480 manager_->DeregisterService(service_);
481 }
Darin Petkovd9661952011-08-03 16:25:42 -0700482 service_ = NULL;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700483 if (state_ == kStateLinked ||
484 state_ == kStateConnected ||
485 state_ == kStateRegistered) {
486 SetState(kStateEnabled);
Darin Petkovd9661952011-08-03 16:25:42 -0700487 }
488 return;
489 }
Darin Petkovd9661952011-08-03 16:25:42 -0700490 if (state_ == kStateEnabled) {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700491 SetState(kStateRegistered);
Darin Petkovd9661952011-08-03 16:25:42 -0700492 }
493 if (!service_.get()) {
494 // For now, no endpoint is created. Revisit if necessary.
495 CreateService();
496 }
497 GetModemSignalQuality();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700498 if (state_ == kStateRegistered && modem_state_ == kModemStateConnected) {
499 SetState(kStateConnected);
500 EstablishLink();
501 }
Darin Petkovd2045802011-08-23 11:09:25 -0700502 service_->set_network_tech(network_tech);
503 service_->set_roaming_state(GetRoamingStateString());
Darin Petkovd9661952011-08-03 16:25:42 -0700504}
505
506void Cellular::GetModemSignalQuality() {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700507 VLOG(2) << __func__;
Darin Petkovd9661952011-08-03 16:25:42 -0700508 uint32 strength = 0;
509 switch (type_) {
510 case kTypeGSM:
511 strength = GetGSMSignalQuality();
512 break;
513 case kTypeCDMA:
514 strength = GetCDMASignalQuality();
515 break;
516 default: NOTREACHED();
517 }
518 HandleNewSignalQuality(strength);
519}
520
521uint32 Cellular::GetCDMASignalQuality() {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700522 VLOG(2) << __func__;
Darin Petkovd9661952011-08-03 16:25:42 -0700523 CHECK_EQ(kTypeCDMA, type_);
524 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
525 return cdma_proxy_->GetSignalQuality();
526}
527
528uint32 Cellular::GetGSMSignalQuality() {
Darin Petkovceb68172011-07-29 14:47:48 -0700529 // TODO(petkov): Implement this.
530 NOTIMPLEMENTED();
Darin Petkovd9661952011-08-03 16:25:42 -0700531 return 0;
532}
533
534void Cellular::HandleNewSignalQuality(uint32 strength) {
535 VLOG(2) << "Signal strength: " << strength;
536 if (service_.get()) {
537 service_->set_strength(strength);
538 }
539}
540
541void Cellular::CreateService() {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700542 VLOG(2) << __func__;
Darin Petkovd9661952011-08-03 16:25:42 -0700543 CHECK(!service_.get());
544 service_ =
545 new CellularService(control_interface_, dispatcher_, manager_, this);
Darin Petkovc408e692011-08-17 13:47:15 -0700546 switch (type_) {
547 case kTypeGSM:
Darin Petkov51489002011-08-18 13:13:20 -0700548 service_->set_activation_state(flimflam::kActivationStateActivated);
Darin Petkov3335b372011-08-22 11:05:32 -0700549 // TODO(petkov): Set serving operator.
Darin Petkovc408e692011-08-17 13:47:15 -0700550 break;
551 case kTypeCDMA:
552 service_->set_payment_url(cdma_.payment_url);
553 service_->set_usage_url(cdma_.usage_url);
Darin Petkov3335b372011-08-22 11:05:32 -0700554 service_->set_serving_operator(home_provider_);
Darin Petkovc408e692011-08-17 13:47:15 -0700555 HandleNewCDMAActivationState(MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR);
556 break;
557 default:
558 NOTREACHED();
Darin Petkovcc044422011-08-17 13:30:06 -0700559 }
Darin Petkovf5f61e02011-07-29 11:35:40 -0700560}
561
Darin Petkov6f9eaa32011-08-09 15:26:44 -0700562bool Cellular::TechnologyIs(const Device::Technology type) const {
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700563 return type == Device::kCellular;
564}
565
Darin Petkov4d6d9412011-08-24 13:19:54 -0700566void Cellular::Connect(Error *error) {
Darin Petkovc5f56562011-08-06 16:40:05 -0700567 VLOG(2) << __func__;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700568 if (state_ == kStateConnected ||
569 state_ == kStateLinked) {
Darin Petkov4d6d9412011-08-24 13:19:54 -0700570 LOG(ERROR) << "Already connected; connection request ignored.";
571 CHECK(error);
572 error->Populate(Error::kAlreadyConnected);
Darin Petkovc5f56562011-08-06 16:40:05 -0700573 return;
574 }
575 CHECK_EQ(kStateRegistered, state_);
Darin Petkovd2045802011-08-23 11:09:25 -0700576
577 if (!allow_roaming_ &&
578 service_->roaming_state() == flimflam::kRoamingStateRoaming) {
579 LOG(ERROR) << "Roaming disallowed; connection request ignored.";
Darin Petkov4d6d9412011-08-24 13:19:54 -0700580 CHECK(error);
581 error->Populate(Error::kNotOnHomeNetwork);
Darin Petkovd2045802011-08-23 11:09:25 -0700582 return;
583 }
584
Darin Petkovc5f56562011-08-06 16:40:05 -0700585 DBusPropertiesMap properties;
586 const char *phone_number = NULL;
587 switch (type_) {
588 case kTypeGSM:
589 phone_number = kPhoneNumberGSM;
590 break;
591 case kTypeCDMA:
592 phone_number = kPhoneNumberCDMA;
593 break;
594 default: NOTREACHED();
595 }
596 properties[kConnectPropertyPhoneNumber].writer().append_string(phone_number);
597 // TODO(petkov): Setup apn and "home_only".
598
599 // Defer connect because we may be in a dbus-c++ callback.
600 dispatcher_->PostTask(
601 task_factory_.NewRunnableMethod(&Cellular::ConnectTask, properties));
602}
603
604void Cellular::ConnectTask(const DBusPropertiesMap &properties) {
605 VLOG(2) << __func__;
Darin Petkovbac96002011-08-09 13:22:00 -0700606 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovc5f56562011-08-06 16:40:05 -0700607 simple_proxy_->Connect(properties);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700608 SetState(kStateConnected);
Darin Petkovbac96002011-08-09 13:22:00 -0700609 EstablishLink();
610}
611
612void Cellular::EstablishLink() {
613 VLOG(2) << __func__;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700614 CHECK_EQ(kStateConnected, state_);
615 unsigned int flags = 0;
616 if (manager_->device_info()->GetFlags(interface_index_, &flags) &&
617 (flags & IFF_UP) != 0) {
618 LinkEvent(flags, IFF_UP);
619 return;
620 }
621 // TODO(petkov): Provide a timeout for a failed link-up request.
622 RTNLHandler::GetInstance()->SetInterfaceFlags(
623 interface_index_, IFF_UP, IFF_UP);
624}
625
626void Cellular::LinkEvent(unsigned int flags, unsigned int change) {
627 Device::LinkEvent(flags, change);
628 if ((flags & IFF_UP) != 0 && state_ == kStateConnected) {
629 LOG(INFO) << link_name_ << " is up.";
630 SetState(kStateLinked);
631 manager_->RegisterService(service_);
632 // TODO(petkov): For GSM, remember the APN.
Darin Petkov60b8c3b2011-08-25 11:03:20 -0700633 if (AcquireDHCPConfig()) {
634 SelectService(service_);
635 SetServiceState(Service::kStateConfiguring);
636 } else {
637 LOG(ERROR) << "Unable to acquire DHCP config.";
638 }
Darin Petkov0828f5f2011-08-11 10:18:52 -0700639 } else if ((flags & IFF_UP) == 0 && state_ == kStateLinked) {
640 SetState(kStateConnected);
641 manager_->DeregisterService(service_);
Darin Petkov60b8c3b2011-08-25 11:03:20 -0700642 SelectService(NULL);
Darin Petkov77cb6812011-08-15 16:19:41 -0700643 DestroyIPConfig();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700644 }
Darin Petkovc5f56562011-08-06 16:40:05 -0700645}
646
Darin Petkovb100ae72011-08-24 16:19:45 -0700647void Cellular::Activate(const string &carrier, Error *error) {
648 if (type_ != kTypeCDMA) {
649 const string kMessage = "Unable to activate non-CDMA modem.";
650 LOG(ERROR) << kMessage;
651 CHECK(error);
652 error->Populate(Error::kInvalidArguments, kMessage);
653 return;
654 }
655 if (state_ != kStateEnabled &&
656 state_ != kStateRegistered) {
657 const string kMessage = "Unable to activate in " + GetStateString(state_);
658 LOG(ERROR) << kMessage;
659 CHECK(error);
660 error->Populate(Error::kInvalidArguments, kMessage);
661 return;
662 }
Darin Petkovc408e692011-08-17 13:47:15 -0700663 // Defer connect because we may be in a dbus-c++ callback.
664 dispatcher_->PostTask(
665 task_factory_.NewRunnableMethod(&Cellular::ActivateTask, carrier));
666}
667
668void Cellular::ActivateTask(const string &carrier) {
669 VLOG(2) << __func__ << "(" << carrier << ")";
Darin Petkovb100ae72011-08-24 16:19:45 -0700670 if (state_ != kStateEnabled &&
671 state_ != kStateRegistered) {
Darin Petkovc408e692011-08-17 13:47:15 -0700672 LOG(ERROR) << "Unable to activate in " << GetStateString(state_);
673 return;
674 }
675 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
676 uint32 status = cdma_proxy_->Activate(carrier);
677 if (status == MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR) {
678 cdma_.activation_state = MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING;
679 }
680 HandleNewCDMAActivationState(status);
681}
682
683void Cellular::HandleNewCDMAActivationState(uint32 error) {
684 if (!service_.get()) {
685 return;
686 }
687 service_->set_activation_state(
688 GetCDMAActivationStateString(cdma_.activation_state));
Darin Petkov51489002011-08-18 13:13:20 -0700689 service_->set_error(GetCDMAActivationErrorString(error));
Darin Petkovc408e692011-08-17 13:47:15 -0700690}
691
Darin Petkovb27e5442011-08-16 14:36:45 -0700692void Cellular::OnCDMAActivationStateChanged(
693 uint32 activation_state,
694 uint32 activation_error,
695 const DBusPropertiesMap &status_changes) {
696 CHECK_EQ(kTypeCDMA, type_);
697 DBusProperties::GetString(status_changes, "mdn", &mdn_);
698 DBusProperties::GetString(status_changes, "min", &min_);
Darin Petkovcc044422011-08-17 13:30:06 -0700699 if (DBusProperties::GetString(
700 status_changes, "payment_url", &cdma_.payment_url) &&
Darin Petkovb27e5442011-08-16 14:36:45 -0700701 service_.get()) {
Darin Petkovcc044422011-08-17 13:30:06 -0700702 service_->set_payment_url(cdma_.payment_url);
Darin Petkovb27e5442011-08-16 14:36:45 -0700703 }
Darin Petkovc408e692011-08-17 13:47:15 -0700704 cdma_.activation_state = activation_state;
705 HandleNewCDMAActivationState(activation_error);
Darin Petkovb27e5442011-08-16 14:36:45 -0700706}
707
Darin Petkovd9661952011-08-03 16:25:42 -0700708void Cellular::OnCDMARegistrationStateChanged(uint32 state_1x,
709 uint32 state_evdo) {
710 CHECK_EQ(kTypeCDMA, type_);
711 cdma_.registration_state_1x = state_1x;
712 cdma_.registration_state_evdo = state_evdo;
713 HandleNewRegistrationState();
714}
715
716void Cellular::OnCDMASignalQualityChanged(uint32 strength) {
717 CHECK_EQ(kTypeCDMA, type_);
718 HandleNewSignalQuality(strength);
719}
720
Darin Petkova1e0a1c2011-08-25 15:08:33 -0700721void Cellular::OnGSMNetworkModeChanged(uint32 mode) {
722 // TODO(petkov): Implement this.
723 NOTIMPLEMENTED();
724}
725
726void Cellular::OnGSMRegistrationInfoChanged(uint32 status,
727 const string &operator_code,
728 const string &operator_name) {
729 // TODO(petkov): Implement this.
730 NOTIMPLEMENTED();
731}
732
733void Cellular::OnGSMSignalQualityChanged(uint32 quality) {
734 // TODO(petkov): Implement this.
735 NOTIMPLEMENTED();
736}
737
Darin Petkovc5f56562011-08-06 16:40:05 -0700738void Cellular::OnModemStateChanged(uint32 old_state,
739 uint32 new_state,
740 uint32 reason) {
741 // TODO(petkov): Implement this.
742 NOTIMPLEMENTED();
743}
744
Chris Masone889666b2011-07-03 12:58:50 -0700745Stringmaps Cellular::EnumerateNetworks() {
746 Stringmaps to_return;
747 for (vector<Network>::const_iterator it = found_networks_.begin();
748 it != found_networks_.end();
749 ++it) {
750 to_return.push_back(it->ToDict());
751 }
752 return to_return;
753}
754
755StrIntPair Cellular::SimLockStatusToProperty() {
756 return StrIntPair(make_pair(flimflam::kSIMLockTypeProperty,
757 sim_lock_status_.lock_type),
758 make_pair(flimflam::kSIMLockRetriesLeftProperty,
759 sim_lock_status_.retries_left));
760}
761
762void Cellular::HelpRegisterDerivedStringmaps(
763 const string &name,
764 Stringmaps(Cellular::*get)(void),
765 bool(Cellular::*set)(const Stringmaps&)) {
766 store_.RegisterDerivedStringmaps(
767 name,
768 StringmapsAccessor(
769 new CustomAccessor<Cellular, Stringmaps>(this, get, set)));
770}
771
772void Cellular::HelpRegisterDerivedStrIntPair(
773 const string &name,
774 StrIntPair(Cellular::*get)(void),
775 bool(Cellular::*set)(const StrIntPair&)) {
776 store_.RegisterDerivedStrIntPair(
777 name,
778 StrIntPairAccessor(
779 new CustomAccessor<Cellular, StrIntPair>(this, get, set)));
780}
781
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700782} // namespace shill