blob: 85097a5d06cf3cdc4194be71939b19305e0eb1e2 [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 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>
Darin Petkov137884a2011-10-26 18:52:47 +020018#include <mobile_provider.h>
Chris Masone3bd3c8c2011-06-13 08:20:26 -070019
Darin Petkovdaf43862011-10-27 11:37:28 +020020#include "shill/cellular_capability_cdma.h"
21#include "shill/cellular_capability_gsm.h"
Chris Masone3bd3c8c2011-06-13 08:20:26 -070022#include "shill/cellular_service.h"
23#include "shill/control_interface.h"
24#include "shill/device.h"
25#include "shill/device_info.h"
Darin Petkov4d6d9412011-08-24 13:19:54 -070026#include "shill/error.h"
Paul Stewart26b327e2011-10-19 11:38:09 -070027#include "shill/event_dispatcher.h"
Chris Masone3bd3c8c2011-06-13 08:20:26 -070028#include "shill/manager.h"
Darin Petkove604f702011-07-28 15:51:17 -070029#include "shill/modem_simple_proxy_interface.h"
Chris Masone7aa5f902011-07-11 11:13:35 -070030#include "shill/profile.h"
Chris Masone889666b2011-07-03 12:58:50 -070031#include "shill/property_accessor.h"
Darin Petkove9d12e02011-07-27 15:09:37 -070032#include "shill/proxy_factory.h"
Darin Petkov0828f5f2011-08-11 10:18:52 -070033#include "shill/rtnl_handler.h"
Chris Masone3bd3c8c2011-06-13 08:20:26 -070034
Chris Masone889666b2011-07-03 12:58:50 -070035using std::make_pair;
Darin Petkovc0865312011-09-16 15:31:20 -070036using std::map;
Chris Masone3bd3c8c2011-06-13 08:20:26 -070037using std::string;
Chris Masone889666b2011-07-03 12:58:50 -070038using std::vector;
Chris Masone3bd3c8c2011-06-13 08:20:26 -070039
40namespace shill {
41
Darin Petkovc5f56562011-08-06 16:40:05 -070042const char Cellular::kConnectPropertyPhoneNumber[] = "number";
43const char Cellular::kPhoneNumberCDMA[] = "#777";
44const char Cellular::kPhoneNumberGSM[] = "*99#";
45
Darin Petkov3335b372011-08-22 11:05:32 -070046Cellular::Operator::Operator() {
47 SetName("");
48 SetCode("");
49 SetCountry("");
50}
51
52Cellular::Operator::~Operator() {}
53
54void Cellular::Operator::CopyFrom(const Operator &oper) {
55 dict_ = oper.dict_;
56}
57
58const string &Cellular::Operator::GetName() const {
59 return dict_.find(flimflam::kOperatorNameKey)->second;
60}
61
62void Cellular::Operator::SetName(const string &name) {
63 dict_[flimflam::kOperatorNameKey] = name;
64}
65
66const string &Cellular::Operator::GetCode() const {
67 return dict_.find(flimflam::kOperatorCodeKey)->second;
68}
69
70void Cellular::Operator::SetCode(const string &code) {
71 dict_[flimflam::kOperatorCodeKey] = code;
72}
73
74const string &Cellular::Operator::GetCountry() const {
75 return dict_.find(flimflam::kOperatorCountryKey)->second;
76}
77
78void Cellular::Operator::SetCountry(const string &country) {
79 dict_[flimflam::kOperatorCountryKey] = country;
80}
81
82const Stringmap &Cellular::Operator::ToDict() const {
83 return dict_;
84}
85
Darin Petkovbec79a22011-08-01 14:47:17 -070086Cellular::CDMA::CDMA()
87 : registration_state_evdo(MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN),
88 registration_state_1x(MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN),
Darin Petkovcc044422011-08-17 13:30:06 -070089 activation_state(MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED),
90 prl_version(0) {}
Darin Petkovbec79a22011-08-01 14:47:17 -070091
Darin Petkov9bac6fe2011-08-26 12:49:05 -070092Cellular::GSM::GSM()
93 : registration_state(MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN),
94 access_technology(MM_MODEM_GSM_ACCESS_TECH_UNKNOWN) {}
95
Chris Masone3bd3c8c2011-06-13 08:20:26 -070096Cellular::Cellular(ControlInterface *control_interface,
97 EventDispatcher *dispatcher,
98 Manager *manager,
Darin Petkove9d12e02011-07-27 15:09:37 -070099 const string &link_name,
Darin Petkov3335b372011-08-22 11:05:32 -0700100 const string &address,
Darin Petkove9d12e02011-07-27 15:09:37 -0700101 int interface_index,
102 Type type,
103 const string &owner,
Darin Petkov137884a2011-10-26 18:52:47 +0200104 const string &path,
105 mobile_provider_db *provider_db)
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700106 : Device(control_interface,
107 dispatcher,
108 manager,
Darin Petkove9d12e02011-07-27 15:09:37 -0700109 link_name,
Chris Masone626719f2011-08-18 16:58:48 -0700110 address,
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700111 interface_index),
Darin Petkovab565bb2011-10-06 02:55:51 -0700112 proxy_factory_(ProxyFactory::GetInstance()),
Darin Petkove9d12e02011-07-27 15:09:37 -0700113 type_(type),
114 state_(kStateDisabled),
Darin Petkovbac96002011-08-09 13:22:00 -0700115 modem_state_(kModemStateUnknown),
Darin Petkove9d12e02011-07-27 15:09:37 -0700116 dbus_owner_(owner),
117 dbus_path_(path),
Darin Petkov137884a2011-10-26 18:52:47 +0200118 provider_db_(provider_db),
Darin Petkovc5f56562011-08-06 16:40:05 -0700119 task_factory_(this),
Darin Petkov1272a432011-11-10 15:53:37 +0100120 allow_roaming_(false) {
mukesh agrawalde29fa82011-09-16 16:16:36 -0700121 PropertyStore *store = this->mutable_store();
Paul Stewartac4ac002011-08-26 12:04:26 -0700122 store->RegisterConstString(flimflam::kCarrierProperty, &carrier_);
123 store->RegisterConstString(flimflam::kDBusConnectionProperty, &dbus_owner_);
124 store->RegisterConstString(flimflam::kDBusObjectProperty, &dbus_path_);
125 store->RegisterBool(flimflam::kCellularAllowRoamingProperty, &allow_roaming_);
126 store->RegisterConstString(flimflam::kEsnProperty, &esn_);
127 store->RegisterConstString(flimflam::kFirmwareRevisionProperty,
Chris Masone27c4aa52011-07-02 13:10:14 -0700128 &firmware_revision_);
Paul Stewartac4ac002011-08-26 12:04:26 -0700129 store->RegisterConstString(flimflam::kHardwareRevisionProperty,
Chris Masone27c4aa52011-07-02 13:10:14 -0700130 &hardware_revision_);
Paul Stewartac4ac002011-08-26 12:04:26 -0700131 store->RegisterConstStringmap(flimflam::kHomeProviderProperty,
Darin Petkov3335b372011-08-22 11:05:32 -0700132 &home_provider_.ToDict());
Paul Stewartac4ac002011-08-26 12:04:26 -0700133 store->RegisterConstString(flimflam::kImeiProperty, &imei_);
134 store->RegisterConstString(flimflam::kImsiProperty, &imsi_);
135 store->RegisterConstString(flimflam::kManufacturerProperty, &manufacturer_);
136 store->RegisterConstString(flimflam::kMdnProperty, &mdn_);
137 store->RegisterConstString(flimflam::kMeidProperty, &meid_);
138 store->RegisterConstString(flimflam::kMinProperty, &min_);
139 store->RegisterConstString(flimflam::kModelIDProperty, &model_id_);
140 store->RegisterConstUint16(flimflam::kPRLVersionProperty, &cdma_.prl_version);
141 store->RegisterConstString(flimflam::kSelectedNetworkProperty,
Darin Petkova1e0a1c2011-08-25 15:08:33 -0700142 &selected_network_);
Chris Masoneb925cc82011-06-22 15:39:57 -0700143
Chris Masone889666b2011-07-03 12:58:50 -0700144 HelpRegisterDerivedStrIntPair(flimflam::kSIMLockStatusProperty,
145 &Cellular::SimLockStatusToProperty,
146 NULL);
Chris Masoneb925cc82011-06-22 15:39:57 -0700147
Paul Stewartac4ac002011-08-26 12:04:26 -0700148 VLOG(2) << "Cellular device " << this->link_name() << " initialized: "
Darin Petkove9d12e02011-07-27 15:09:37 -0700149 << GetTypeString();
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700150}
151
Darin Petkove9d12e02011-07-27 15:09:37 -0700152Cellular::~Cellular() {}
153
Darin Petkovcc044422011-08-17 13:30:06 -0700154string Cellular::GetTypeString() const {
Darin Petkove9d12e02011-07-27 15:09:37 -0700155 switch (type_) {
156 case kTypeGSM: return "CellularTypeGSM";
157 case kTypeCDMA: return "CellularTypeCDMA";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700158 default: NOTREACHED();
Darin Petkove9d12e02011-07-27 15:09:37 -0700159 }
Darin Petkov0828f5f2011-08-11 10:18:52 -0700160 return StringPrintf("CellularTypeUnknown-%d", type_);
Darin Petkove9d12e02011-07-27 15:09:37 -0700161}
162
Darin Petkovcc044422011-08-17 13:30:06 -0700163// static
164string Cellular::GetStateString(State state) {
165 switch (state) {
Darin Petkove9d12e02011-07-27 15:09:37 -0700166 case kStateDisabled: return "CellularStateDisabled";
167 case kStateEnabled: return "CellularStateEnabled";
168 case kStateRegistered: return "CellularStateRegistered";
169 case kStateConnected: return "CellularStateConnected";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700170 case kStateLinked: return "CellularStateLinked";
171 default: NOTREACHED();
Darin Petkove9d12e02011-07-27 15:09:37 -0700172 }
Darin Petkovcc044422011-08-17 13:30:06 -0700173 return StringPrintf("CellularStateUnknown-%d", state);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700174}
175
Darin Petkovc408e692011-08-17 13:47:15 -0700176// static
177string Cellular::GetCDMAActivationStateString(uint32 state) {
178 switch (state) {
179 case MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED:
Darin Petkov51489002011-08-18 13:13:20 -0700180 return flimflam::kActivationStateActivated;
Darin Petkovc408e692011-08-17 13:47:15 -0700181 case MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING:
Darin Petkov51489002011-08-18 13:13:20 -0700182 return flimflam::kActivationStateActivating;
Darin Petkovc408e692011-08-17 13:47:15 -0700183 case MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED:
Darin Petkov51489002011-08-18 13:13:20 -0700184 return flimflam::kActivationStateNotActivated;
Darin Petkovc408e692011-08-17 13:47:15 -0700185 case MM_MODEM_CDMA_ACTIVATION_STATE_PARTIALLY_ACTIVATED:
Darin Petkov51489002011-08-18 13:13:20 -0700186 return flimflam::kActivationStatePartiallyActivated;
Darin Petkovc408e692011-08-17 13:47:15 -0700187 default:
Darin Petkov51489002011-08-18 13:13:20 -0700188 return flimflam::kActivationStateUnknown;
189 }
190}
191
192// static
193string Cellular::GetCDMAActivationErrorString(uint32 error) {
194 switch (error) {
195 case MM_MODEM_CDMA_ACTIVATION_ERROR_WRONG_RADIO_INTERFACE:
196 return flimflam::kErrorNeedEvdo;
197 case MM_MODEM_CDMA_ACTIVATION_ERROR_ROAMING:
198 return flimflam::kErrorNeedHomeNetwork;
199 case MM_MODEM_CDMA_ACTIVATION_ERROR_COULD_NOT_CONNECT:
200 case MM_MODEM_CDMA_ACTIVATION_ERROR_SECURITY_AUTHENTICATION_FAILED:
201 case MM_MODEM_CDMA_ACTIVATION_ERROR_PROVISIONING_FAILED:
202 return flimflam::kErrorOtaspFailed;
203 case MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR:
204 return "";
205 case MM_MODEM_CDMA_ACTIVATION_ERROR_NO_SIGNAL:
206 default:
207 return flimflam::kErrorActivationFailed;
Darin Petkovc408e692011-08-17 13:47:15 -0700208 }
209}
210
Darin Petkov0828f5f2011-08-11 10:18:52 -0700211void Cellular::SetState(State state) {
Darin Petkovcc044422011-08-17 13:30:06 -0700212 VLOG(2) << GetStateString(state_) << " -> " << GetStateString(state);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700213 state_ = state;
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700214}
215
216void Cellular::Start() {
Darin Petkovcc044422011-08-17 13:30:06 -0700217 LOG(INFO) << __func__ << ": " << GetStateString(state_);
Darin Petkov3335b372011-08-22 11:05:32 -0700218 Device::Start();
Darin Petkovdaf43862011-10-27 11:37:28 +0200219 InitCapability(); // For now, only a single capability is supported.
Darin Petkovbec79a22011-08-01 14:47:17 -0700220 InitProxies();
Darin Petkovf5f61e02011-07-29 11:35:40 -0700221 EnableModem();
Darin Petkovceb68172011-07-29 14:47:48 -0700222 if (type_ == kTypeGSM) {
223 RegisterGSMModem();
224 }
Darin Petkovf5f61e02011-07-29 11:35:40 -0700225 GetModemStatus();
Darin Petkovcb547732011-11-09 13:55:26 +0100226 capability_->GetIdentifiers();
Darin Petkovceb68172011-07-29 14:47:48 -0700227 if (type_ == kTypeGSM) {
228 GetGSMProperties();
229 }
230 GetModemInfo();
231 GetModemRegistrationState();
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700232}
233
234void Cellular::Stop() {
Darin Petkovdaf43862011-10-27 11:37:28 +0200235 capability_.reset();
Darin Petkove9d12e02011-07-27 15:09:37 -0700236 proxy_.reset();
Darin Petkove604f702011-07-28 15:51:17 -0700237 simple_proxy_.reset();
Darin Petkovbec79a22011-08-01 14:47:17 -0700238 cdma_proxy_.reset();
Darin Petkove42e1012011-08-31 12:35:04 -0700239 gsm_network_proxy_.reset();
Paul Stewartac4ac002011-08-26 12:04:26 -0700240 manager()->DeregisterService(service_);
Darin Petkove9d12e02011-07-27 15:09:37 -0700241 service_ = NULL; // Breaks a reference cycle.
Darin Petkov0828f5f2011-08-11 10:18:52 -0700242 SetState(kStateDisabled);
Darin Petkov3335b372011-08-22 11:05:32 -0700243 Device::Stop();
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700244}
245
Darin Petkovdaf43862011-10-27 11:37:28 +0200246void Cellular::InitCapability() {
247 VLOG(2) << __func__;
248 switch (type_) {
249 case kTypeGSM:
250 capability_.reset(new CellularCapabilityGSM(this));
251 break;
252 case kTypeCDMA:
253 capability_.reset(new CellularCapabilityCDMA(this));
254 break;
255 default: NOTREACHED();
256 }
257}
258
Darin Petkovbec79a22011-08-01 14:47:17 -0700259void Cellular::InitProxies() {
Darin Petkovcc044422011-08-17 13:30:06 -0700260 VLOG(2) << __func__;
Darin Petkovab565bb2011-10-06 02:55:51 -0700261 proxy_.reset(proxy_factory_->CreateModemProxy(this, dbus_path_, dbus_owner_));
Darin Petkovbec79a22011-08-01 14:47:17 -0700262 simple_proxy_.reset(
Darin Petkovab565bb2011-10-06 02:55:51 -0700263 proxy_factory_->CreateModemSimpleProxy(dbus_path_, dbus_owner_));
Darin Petkovdaf43862011-10-27 11:37:28 +0200264 capability_->InitProxies();
Darin Petkovbec79a22011-08-01 14:47:17 -0700265}
266
Darin Petkovf5f61e02011-07-29 11:35:40 -0700267void Cellular::EnableModem() {
268 CHECK_EQ(kStateDisabled, state_);
269 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
270 proxy_->Enable(true);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700271 SetState(kStateEnabled);
Darin Petkovf5f61e02011-07-29 11:35:40 -0700272}
273
274void Cellular::GetModemStatus() {
Darin Petkovceb68172011-07-29 14:47:48 -0700275 CHECK_EQ(kStateEnabled, state_);
Darin Petkovf5f61e02011-07-29 11:35:40 -0700276 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
277 DBusPropertiesMap properties = simple_proxy_->GetStatus();
Darin Petkovceb68172011-07-29 14:47:48 -0700278 if (DBusProperties::GetString(properties, "carrier", &carrier_) &&
279 type_ == kTypeCDMA) {
Darin Petkov3335b372011-08-22 11:05:32 -0700280 home_provider_.SetName(carrier_);
281 home_provider_.SetCode("");
282 home_provider_.SetCountry("us");
Darin Petkovf5f61e02011-07-29 11:35:40 -0700283 }
Darin Petkovceb68172011-07-29 14:47:48 -0700284 DBusProperties::GetString(properties, "meid", &meid_);
285 DBusProperties::GetString(properties, "imei", &imei_);
286 if (DBusProperties::GetString(properties, "imsi", &imsi_) &&
287 type_ == kTypeGSM) {
Darin Petkov137884a2011-10-26 18:52:47 +0200288 // TODO(petkov): Set GSM provider based on IMSI and SPN.
Darin Petkovceb68172011-07-29 14:47:48 -0700289 }
290 DBusProperties::GetString(properties, "esn", &esn_);
291 DBusProperties::GetString(properties, "mdn", &mdn_);
292 DBusProperties::GetString(properties, "min", &min_);
Darin Petkovceb68172011-07-29 14:47:48 -0700293 DBusProperties::GetString(
294 properties, "firmware_revision", &firmware_revision_);
Darin Petkovb27e5442011-08-16 14:36:45 -0700295
Darin Petkovd2045802011-08-23 11:09:25 -0700296 uint32 state = 0;
297 if (DBusProperties::GetUint32(properties, "state", &state)) {
298 modem_state_ = static_cast<ModemState>(state);
299 }
Darin Petkovb27e5442011-08-16 14:36:45 -0700300
Darin Petkovceb68172011-07-29 14:47:48 -0700301 if (type_ == kTypeCDMA) {
Darin Petkovc408e692011-08-17 13:47:15 -0700302 DBusProperties::GetUint32(
303 properties, "activation_state", &cdma_.activation_state);
Darin Petkovcc044422011-08-17 13:30:06 -0700304 DBusProperties::GetUint16(properties, "prl_version", &cdma_.prl_version);
Darin Petkovcc044422011-08-17 13:30:06 -0700305 // TODO(petkov): For now, get the payment and usage URLs from ModemManager
306 // to match flimflam. In the future, provide a plugin API to get these
307 // directly from the modem driver.
308 DBusProperties::GetString(properties, "payment_url", &cdma_.payment_url);
309 DBusProperties::GetString(properties, "usage_url", &cdma_.usage_url);
Darin Petkovceb68172011-07-29 14:47:48 -0700310 }
311}
312
Darin Petkovceb68172011-07-29 14:47:48 -0700313void Cellular::GetGSMProperties() {
Darin Petkov975b5e72011-08-30 11:48:08 -0700314 CHECK_EQ(kTypeGSM, type_);
Darin Petkov9bac6fe2011-08-26 12:49:05 -0700315 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
316 gsm_.access_technology = gsm_network_proxy_->AccessTechnology();
317 VLOG(2) << "GSM AccessTechnology: " << gsm_.access_technology;
Darin Petkovceb68172011-07-29 14:47:48 -0700318}
319
320void Cellular::RegisterGSMModem() {
Darin Petkov975b5e72011-08-30 11:48:08 -0700321 CHECK_EQ(kTypeGSM, type_);
Darin Petkov9ae310f2011-08-30 15:41:13 -0700322 LOG(INFO) << "Registering on \"" << selected_network_ << "\"";
Darin Petkova1e0a1c2011-08-25 15:08:33 -0700323 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
324 gsm_network_proxy_->Register(selected_network_);
Darin Petkov9ae310f2011-08-30 15:41:13 -0700325 // TODO(petkov): Handle registration failure including trying the home network
326 // when selected_network_ is not empty.
327}
328
329void Cellular::RegisterOnNetwork(const string &network_id, Error *error) {
330 LOG(INFO) << __func__ << "(" << network_id << ")";
331 if (type_ != kTypeGSM) {
Paul Stewartbe005172011-11-02 18:10:29 -0700332 Error::PopulateAndLog(error, Error::kNotSupported,
333 "Network registration supported only for GSM.");
Darin Petkov9ae310f2011-08-30 15:41:13 -0700334 return;
335 }
336 // Defer registration because we may be in a dbus-c++ callback.
337 dispatcher()->PostTask(
338 task_factory_.NewRunnableMethod(&Cellular::RegisterOnNetworkTask,
339 network_id));
340}
341
342void Cellular::RegisterOnNetworkTask(const string &network_id) {
343 LOG(INFO) << __func__ << "(" << network_id << ")";
Darin Petkove42e1012011-08-31 12:35:04 -0700344 CHECK_EQ(kTypeGSM, type_);
Darin Petkov9ae310f2011-08-30 15:41:13 -0700345 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
346 gsm_network_proxy_->Register(network_id);
347 // TODO(petkov): Handle registration failure.
348 selected_network_ = network_id;
Darin Petkovceb68172011-07-29 14:47:48 -0700349}
350
Darin Petkove42e1012011-08-31 12:35:04 -0700351void Cellular::RequirePIN(const string &pin, bool require, Error *error) {
Darin Petkovb05315f2011-11-07 10:14:25 +0100352 capability_->RequirePIN(pin, require, error);
Darin Petkove42e1012011-08-31 12:35:04 -0700353}
354
355void Cellular::EnterPIN(const string &pin, Error *error) {
Darin Petkovb05315f2011-11-07 10:14:25 +0100356 capability_->EnterPIN(pin, error);
Darin Petkove42e1012011-08-31 12:35:04 -0700357}
358
Darin Petkovb05315f2011-11-07 10:14:25 +0100359void Cellular::UnblockPIN(
360 const string &unblock_code, const string &pin, Error *error) {
361 capability_->UnblockPIN(unblock_code, pin, error);
Darin Petkove42e1012011-08-31 12:35:04 -0700362}
363
Darin Petkovb05315f2011-11-07 10:14:25 +0100364void Cellular::ChangePIN(
365 const string &old_pin, const string &new_pin, Error *error) {
366 capability_->ChangePIN(old_pin, new_pin, error);
Darin Petkove42e1012011-08-31 12:35:04 -0700367}
368
Darin Petkov1272a432011-11-10 15:53:37 +0100369void Cellular::Scan(Error *error) {
370 capability_->Scan(error);
371}
372
Darin Petkovceb68172011-07-29 14:47:48 -0700373void Cellular::GetModemInfo() {
Darin Petkovd2045802011-08-23 11:09:25 -0700374 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovceb68172011-07-29 14:47:48 -0700375 ModemProxyInterface::Info info = proxy_->GetInfo();
376 manufacturer_ = info._1;
377 model_id_ = info._2;
378 hardware_revision_ = info._3;
379 VLOG(2) << "ModemInfo: " << manufacturer_ << ", " << model_id_ << ", "
380 << hardware_revision_;
381}
382
383void Cellular::GetModemRegistrationState() {
Darin Petkovbec79a22011-08-01 14:47:17 -0700384 switch (type_) {
385 case kTypeGSM:
386 GetGSMRegistrationState();
387 break;
388 case kTypeCDMA:
389 GetCDMARegistrationState();
390 break;
391 default: NOTREACHED();
392 }
Darin Petkovd9661952011-08-03 16:25:42 -0700393 HandleNewRegistrationState();
Darin Petkovbec79a22011-08-01 14:47:17 -0700394}
395
396void Cellular::GetCDMARegistrationState() {
397 CHECK_EQ(kTypeCDMA, type_);
Darin Petkovd2045802011-08-23 11:09:25 -0700398 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovbec79a22011-08-01 14:47:17 -0700399 cdma_proxy_->GetRegistrationState(&cdma_.registration_state_1x,
400 &cdma_.registration_state_evdo);
401 VLOG(2) << "CDMA Registration: 1x(" << cdma_.registration_state_1x
402 << ") EVDO(" << cdma_.registration_state_evdo << ")";
Darin Petkovbec79a22011-08-01 14:47:17 -0700403}
404
405void Cellular::GetGSMRegistrationState() {
Darin Petkov9bac6fe2011-08-26 12:49:05 -0700406 CHECK_EQ(kTypeGSM, type_);
407 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
408 ModemGSMNetworkProxyInterface::RegistrationInfo info =
409 gsm_network_proxy_->GetRegistrationInfo();
410 gsm_.registration_state = info._1;
411 gsm_.network_id = info._2;
412 gsm_.operator_name = info._3;
413 VLOG(2) << "GSM Registration: " << gsm_.registration_state << ", "
414 << gsm_.network_id << ", " << gsm_.operator_name;
Darin Petkov137884a2011-10-26 18:52:47 +0200415 UpdateGSMOperatorInfo();
Darin Petkovceb68172011-07-29 14:47:48 -0700416}
417
Darin Petkovd9661952011-08-03 16:25:42 -0700418void Cellular::HandleNewRegistrationState() {
Paul Stewartac4ac002011-08-26 12:04:26 -0700419 dispatcher()->PostTask(
Darin Petkov0828f5f2011-08-11 10:18:52 -0700420 task_factory_.NewRunnableMethod(
421 &Cellular::HandleNewRegistrationStateTask));
422}
423
424void Cellular::HandleNewRegistrationStateTask() {
Darin Petkovd9661952011-08-03 16:25:42 -0700425 VLOG(2) << __func__;
Darin Petkov20c13ec2011-11-09 15:07:15 +0100426 const string network_tech = capability_->GetNetworkTechnologyString();
Darin Petkovd2045802011-08-23 11:09:25 -0700427 if (network_tech.empty()) {
Darin Petkovc408e692011-08-17 13:47:15 -0700428 if (state_ == kStateLinked) {
Paul Stewartac4ac002011-08-26 12:04:26 -0700429 manager()->DeregisterService(service_);
Darin Petkovc408e692011-08-17 13:47:15 -0700430 }
Darin Petkovd9661952011-08-03 16:25:42 -0700431 service_ = NULL;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700432 if (state_ == kStateLinked ||
433 state_ == kStateConnected ||
434 state_ == kStateRegistered) {
435 SetState(kStateEnabled);
Darin Petkovd9661952011-08-03 16:25:42 -0700436 }
437 return;
438 }
Darin Petkovd9661952011-08-03 16:25:42 -0700439 if (state_ == kStateEnabled) {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700440 SetState(kStateRegistered);
Darin Petkovd9661952011-08-03 16:25:42 -0700441 }
442 if (!service_.get()) {
443 // For now, no endpoint is created. Revisit if necessary.
444 CreateService();
445 }
Darin Petkov3e509242011-11-10 14:46:44 +0100446 capability_->GetSignalQuality();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700447 if (state_ == kStateRegistered && modem_state_ == kModemStateConnected) {
448 SetState(kStateConnected);
449 EstablishLink();
450 }
Darin Petkovd2045802011-08-23 11:09:25 -0700451 service_->set_network_tech(network_tech);
Darin Petkov20c13ec2011-11-09 15:07:15 +0100452 service_->set_roaming_state(capability_->GetRoamingStateString());
Darin Petkovd9661952011-08-03 16:25:42 -0700453}
454
Darin Petkovd9661952011-08-03 16:25:42 -0700455void Cellular::HandleNewSignalQuality(uint32 strength) {
456 VLOG(2) << "Signal strength: " << strength;
457 if (service_.get()) {
458 service_->set_strength(strength);
459 }
460}
461
462void Cellular::CreateService() {
Darin Petkov0828f5f2011-08-11 10:18:52 -0700463 VLOG(2) << __func__;
Darin Petkovd9661952011-08-03 16:25:42 -0700464 CHECK(!service_.get());
465 service_ =
Paul Stewartac4ac002011-08-26 12:04:26 -0700466 new CellularService(control_interface(), dispatcher(), manager(), this);
Darin Petkovc408e692011-08-17 13:47:15 -0700467 switch (type_) {
468 case kTypeGSM:
Darin Petkov51489002011-08-18 13:13:20 -0700469 service_->set_activation_state(flimflam::kActivationStateActivated);
Darin Petkov137884a2011-10-26 18:52:47 +0200470 UpdateServingOperator();
Darin Petkovc408e692011-08-17 13:47:15 -0700471 break;
472 case kTypeCDMA:
473 service_->set_payment_url(cdma_.payment_url);
474 service_->set_usage_url(cdma_.usage_url);
Darin Petkov137884a2011-10-26 18:52:47 +0200475 UpdateServingOperator();
Darin Petkovc408e692011-08-17 13:47:15 -0700476 HandleNewCDMAActivationState(MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR);
477 break;
478 default:
479 NOTREACHED();
Darin Petkovcc044422011-08-17 13:30:06 -0700480 }
Darin Petkovf5f61e02011-07-29 11:35:40 -0700481}
482
Paul Stewartfdd16072011-09-16 12:41:35 -0700483bool Cellular::TechnologyIs(const Technology::Identifier type) const {
484 return type == Technology::kCellular;
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700485}
486
Darin Petkov4d6d9412011-08-24 13:19:54 -0700487void Cellular::Connect(Error *error) {
Darin Petkovc5f56562011-08-06 16:40:05 -0700488 VLOG(2) << __func__;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700489 if (state_ == kStateConnected ||
490 state_ == kStateLinked) {
Paul Stewartbe005172011-11-02 18:10:29 -0700491 Error::PopulateAndLog(error, Error::kAlreadyConnected,
492 "Already connected; connection request ignored.");
Darin Petkovc5f56562011-08-06 16:40:05 -0700493 return;
494 }
495 CHECK_EQ(kStateRegistered, state_);
Darin Petkovd2045802011-08-23 11:09:25 -0700496
497 if (!allow_roaming_ &&
498 service_->roaming_state() == flimflam::kRoamingStateRoaming) {
Paul Stewartbe005172011-11-02 18:10:29 -0700499 Error::PopulateAndLog(error, Error::kNotOnHomeNetwork,
500 "Roaming disallowed; connection request ignored.");
Darin Petkov4d6d9412011-08-24 13:19:54 -0700501 CHECK(error);
Darin Petkovd2045802011-08-23 11:09:25 -0700502 return;
503 }
504
Darin Petkovc5f56562011-08-06 16:40:05 -0700505 DBusPropertiesMap properties;
506 const char *phone_number = NULL;
507 switch (type_) {
508 case kTypeGSM:
509 phone_number = kPhoneNumberGSM;
510 break;
511 case kTypeCDMA:
512 phone_number = kPhoneNumberCDMA;
513 break;
514 default: NOTREACHED();
515 }
516 properties[kConnectPropertyPhoneNumber].writer().append_string(phone_number);
517 // TODO(petkov): Setup apn and "home_only".
518
519 // Defer connect because we may be in a dbus-c++ callback.
Paul Stewartac4ac002011-08-26 12:04:26 -0700520 dispatcher()->PostTask(
Darin Petkovc5f56562011-08-06 16:40:05 -0700521 task_factory_.NewRunnableMethod(&Cellular::ConnectTask, properties));
522}
523
524void Cellular::ConnectTask(const DBusPropertiesMap &properties) {
525 VLOG(2) << __func__;
Darin Petkovbac96002011-08-09 13:22:00 -0700526 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
Darin Petkovc5f56562011-08-06 16:40:05 -0700527 simple_proxy_->Connect(properties);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700528 SetState(kStateConnected);
Darin Petkovbac96002011-08-09 13:22:00 -0700529 EstablishLink();
530}
531
532void Cellular::EstablishLink() {
533 VLOG(2) << __func__;
Darin Petkov0828f5f2011-08-11 10:18:52 -0700534 CHECK_EQ(kStateConnected, state_);
535 unsigned int flags = 0;
Paul Stewartac4ac002011-08-26 12:04:26 -0700536 if (manager()->device_info()->GetFlags(interface_index(), &flags) &&
Darin Petkov0828f5f2011-08-11 10:18:52 -0700537 (flags & IFF_UP) != 0) {
538 LinkEvent(flags, IFF_UP);
539 return;
540 }
541 // TODO(petkov): Provide a timeout for a failed link-up request.
mukesh agrawal5c4dd0b2011-09-14 13:53:14 -0700542 rtnl_handler()->SetInterfaceFlags(interface_index(), IFF_UP, IFF_UP);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700543}
544
545void Cellular::LinkEvent(unsigned int flags, unsigned int change) {
546 Device::LinkEvent(flags, change);
547 if ((flags & IFF_UP) != 0 && state_ == kStateConnected) {
Paul Stewartac4ac002011-08-26 12:04:26 -0700548 LOG(INFO) << link_name() << " is up.";
Darin Petkov0828f5f2011-08-11 10:18:52 -0700549 SetState(kStateLinked);
Paul Stewartac4ac002011-08-26 12:04:26 -0700550 manager()->RegisterService(service_);
Darin Petkov0828f5f2011-08-11 10:18:52 -0700551 // TODO(petkov): For GSM, remember the APN.
Darin Petkov60b8c3b2011-08-25 11:03:20 -0700552 if (AcquireDHCPConfig()) {
553 SelectService(service_);
554 SetServiceState(Service::kStateConfiguring);
555 } else {
556 LOG(ERROR) << "Unable to acquire DHCP config.";
557 }
Darin Petkov0828f5f2011-08-11 10:18:52 -0700558 } else if ((flags & IFF_UP) == 0 && state_ == kStateLinked) {
559 SetState(kStateConnected);
Paul Stewartac4ac002011-08-26 12:04:26 -0700560 manager()->DeregisterService(service_);
Darin Petkov60b8c3b2011-08-25 11:03:20 -0700561 SelectService(NULL);
Darin Petkov77cb6812011-08-15 16:19:41 -0700562 DestroyIPConfig();
Darin Petkov0828f5f2011-08-11 10:18:52 -0700563 }
Darin Petkovc5f56562011-08-06 16:40:05 -0700564}
565
Darin Petkovb100ae72011-08-24 16:19:45 -0700566void Cellular::Activate(const string &carrier, Error *error) {
Darin Petkovc0865312011-09-16 15:31:20 -0700567 VLOG(2) << __func__ << "(" << carrier << ")";
Darin Petkovb100ae72011-08-24 16:19:45 -0700568 if (type_ != kTypeCDMA) {
Paul Stewartbe005172011-11-02 18:10:29 -0700569 Error::PopulateAndLog(error, Error::kInvalidArguments,
570 "Unable to activate non-CDMA modem.");
Darin Petkovb100ae72011-08-24 16:19:45 -0700571 return;
572 }
573 if (state_ != kStateEnabled &&
574 state_ != kStateRegistered) {
Paul Stewartbe005172011-11-02 18:10:29 -0700575 Error::PopulateAndLog(error, Error::kInvalidArguments,
576 "Unable to activate in " + GetStateString(state_));
Darin Petkovb100ae72011-08-24 16:19:45 -0700577 return;
578 }
Darin Petkovc408e692011-08-17 13:47:15 -0700579 // Defer connect because we may be in a dbus-c++ callback.
Paul Stewartac4ac002011-08-26 12:04:26 -0700580 dispatcher()->PostTask(
Darin Petkovc408e692011-08-17 13:47:15 -0700581 task_factory_.NewRunnableMethod(&Cellular::ActivateTask, carrier));
582}
583
584void Cellular::ActivateTask(const string &carrier) {
585 VLOG(2) << __func__ << "(" << carrier << ")";
Darin Petkovc0865312011-09-16 15:31:20 -0700586 CHECK_EQ(kTypeCDMA, type_);
Darin Petkovb100ae72011-08-24 16:19:45 -0700587 if (state_ != kStateEnabled &&
588 state_ != kStateRegistered) {
Darin Petkovc408e692011-08-17 13:47:15 -0700589 LOG(ERROR) << "Unable to activate in " << GetStateString(state_);
590 return;
591 }
592 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
593 uint32 status = cdma_proxy_->Activate(carrier);
594 if (status == MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR) {
595 cdma_.activation_state = MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING;
596 }
597 HandleNewCDMAActivationState(status);
598}
599
600void Cellular::HandleNewCDMAActivationState(uint32 error) {
601 if (!service_.get()) {
602 return;
603 }
604 service_->set_activation_state(
605 GetCDMAActivationStateString(cdma_.activation_state));
Darin Petkov51489002011-08-18 13:13:20 -0700606 service_->set_error(GetCDMAActivationErrorString(error));
Darin Petkovc408e692011-08-17 13:47:15 -0700607}
608
Darin Petkovb27e5442011-08-16 14:36:45 -0700609void Cellular::OnCDMAActivationStateChanged(
610 uint32 activation_state,
611 uint32 activation_error,
612 const DBusPropertiesMap &status_changes) {
613 CHECK_EQ(kTypeCDMA, type_);
614 DBusProperties::GetString(status_changes, "mdn", &mdn_);
615 DBusProperties::GetString(status_changes, "min", &min_);
Darin Petkovcc044422011-08-17 13:30:06 -0700616 if (DBusProperties::GetString(
617 status_changes, "payment_url", &cdma_.payment_url) &&
Darin Petkovb27e5442011-08-16 14:36:45 -0700618 service_.get()) {
Darin Petkovcc044422011-08-17 13:30:06 -0700619 service_->set_payment_url(cdma_.payment_url);
Darin Petkovb27e5442011-08-16 14:36:45 -0700620 }
Darin Petkovc408e692011-08-17 13:47:15 -0700621 cdma_.activation_state = activation_state;
622 HandleNewCDMAActivationState(activation_error);
Darin Petkovb27e5442011-08-16 14:36:45 -0700623}
624
Darin Petkovd9661952011-08-03 16:25:42 -0700625void Cellular::OnCDMARegistrationStateChanged(uint32 state_1x,
626 uint32 state_evdo) {
627 CHECK_EQ(kTypeCDMA, type_);
628 cdma_.registration_state_1x = state_1x;
629 cdma_.registration_state_evdo = state_evdo;
630 HandleNewRegistrationState();
631}
632
633void Cellular::OnCDMASignalQualityChanged(uint32 strength) {
634 CHECK_EQ(kTypeCDMA, type_);
635 HandleNewSignalQuality(strength);
636}
637
mukesh agrawal1830fa12011-09-26 14:31:40 -0700638void Cellular::OnGSMNetworkModeChanged(uint32 /*mode*/) {
Darin Petkova1e0a1c2011-08-25 15:08:33 -0700639 // TODO(petkov): Implement this.
640 NOTIMPLEMENTED();
641}
642
643void Cellular::OnGSMRegistrationInfoChanged(uint32 status,
644 const string &operator_code,
645 const string &operator_name) {
Darin Petkov9bac6fe2011-08-26 12:49:05 -0700646 CHECK_EQ(kTypeGSM, type_);
647 gsm_.registration_state = status;
648 gsm_.network_id = operator_code;
649 gsm_.operator_name = operator_name;
Darin Petkov137884a2011-10-26 18:52:47 +0200650 UpdateGSMOperatorInfo();
Darin Petkov9bac6fe2011-08-26 12:49:05 -0700651 HandleNewRegistrationState();
Darin Petkova1e0a1c2011-08-25 15:08:33 -0700652}
653
654void Cellular::OnGSMSignalQualityChanged(uint32 quality) {
Darin Petkov22b72bf2011-08-29 14:01:20 -0700655 CHECK_EQ(kTypeGSM, type_);
656 HandleNewSignalQuality(quality);
Darin Petkova1e0a1c2011-08-25 15:08:33 -0700657}
658
mukesh agrawal1830fa12011-09-26 14:31:40 -0700659void Cellular::OnModemStateChanged(uint32 /*old_state*/,
660 uint32 /*new_state*/,
661 uint32 /*reason*/) {
Darin Petkovc5f56562011-08-06 16:40:05 -0700662 // TODO(petkov): Implement this.
663 NOTIMPLEMENTED();
664}
665
Darin Petkov48a511a2011-09-15 10:33:37 -0700666void Cellular::SetGSMAccessTechnology(uint32 access_technology) {
667 CHECK_EQ(kTypeGSM, type_);
668 gsm_.access_technology = access_technology;
669 if (service_.get()) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100670 service_->set_network_tech(capability_->GetNetworkTechnologyString());
Darin Petkov48a511a2011-09-15 10:33:37 -0700671 }
672}
673
Darin Petkov137884a2011-10-26 18:52:47 +0200674void Cellular::UpdateGSMOperatorInfo() {
675 if (!gsm_.network_id.empty()) {
676 VLOG(2) << "Looking up network id: " << gsm_.network_id;
677 mobile_provider *provider =
678 mobile_provider_lookup_by_network(provider_db_,
679 gsm_.network_id.c_str());
680 if (provider) {
681 const char *provider_name = mobile_provider_get_name(provider);
682 if (provider_name && *provider_name) {
683 gsm_.operator_name = provider_name;
684 gsm_.operator_country = provider->country;
685 VLOG(2) << "Operator name: " << gsm_.operator_name
686 << ", country: " << gsm_.operator_country;
687 }
688 } else {
689 VLOG(2) << "GSM provider not found.";
690 }
691 }
692 UpdateServingOperator();
693}
694
695void Cellular::UpdateServingOperator() {
696 if (!service_.get()) {
697 return;
698 }
699 switch (type_) {
700 case kTypeGSM: {
701 Operator oper;
702 oper.SetName(gsm_.operator_name);
703 oper.SetCode(gsm_.network_id);
704 oper.SetCountry(gsm_.operator_country);
705 service_->set_serving_operator(oper);
706 break;
707 }
708 case kTypeCDMA:
709 service_->set_serving_operator(home_provider_);
710 break;
711 default: NOTREACHED();
712 }
713}
714
Chris Masone889666b2011-07-03 12:58:50 -0700715StrIntPair Cellular::SimLockStatusToProperty() {
716 return StrIntPair(make_pair(flimflam::kSIMLockTypeProperty,
717 sim_lock_status_.lock_type),
718 make_pair(flimflam::kSIMLockRetriesLeftProperty,
719 sim_lock_status_.retries_left));
720}
721
Chris Masone889666b2011-07-03 12:58:50 -0700722void Cellular::HelpRegisterDerivedStrIntPair(
723 const string &name,
724 StrIntPair(Cellular::*get)(void),
mukesh agrawalffa3d042011-10-06 15:26:10 -0700725 void(Cellular::*set)(const StrIntPair&, Error *)) {
mukesh agrawalde29fa82011-09-16 16:16:36 -0700726 mutable_store()->RegisterDerivedStrIntPair(
Chris Masone889666b2011-07-03 12:58:50 -0700727 name,
728 StrIntPairAccessor(
729 new CustomAccessor<Cellular, StrIntPair>(this, get, set)));
730}
731
Chris Masone3bd3c8c2011-06-13 08:20:26 -0700732} // namespace shill