blob: 475cf48937d8c1b7fb5dd1620bacb82e8b3926d4 [file] [log] [blame]
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "shill/cellular_capability_universal.h"
6
7#include <base/bind.h>
8#include <base/logging.h>
9#include <base/stl_util.h>
Jason Glasgow82f9ab32012-04-04 14:27:19 -040010#include <base/stringprintf.h>
11#include <chromeos/dbus/service_constants.h>
12#include <mobile_provider.h>
13#include <mm/ModemManager-names.h>
14
15#include <string>
16#include <vector>
17
18#include "shill/adaptor_interfaces.h"
19#include "shill/cellular_service.h"
Jason Glasgowaf583282012-04-18 15:18:22 -040020#include "shill/dbus_properties_proxy_interface.h"
Jason Glasgow82f9ab32012-04-04 14:27:19 -040021#include "shill/error.h"
22#include "shill/property_accessor.h"
23#include "shill/proxy_factory.h"
Ben Chanfad4a0b2012-04-18 15:49:59 -070024#include "shill/scope_logger.h"
Jason Glasgow82f9ab32012-04-04 14:27:19 -040025
26#ifdef MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN
27#error "Do not include mm-modem.h"
28#endif
29
Jason Glasgow82f9ab32012-04-04 14:27:19 -040030using base::Bind;
Jason Glasgowef965562012-04-10 16:12:35 -040031using base::Closure;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040032using std::string;
33using std::vector;
34
35namespace shill {
36
37// static
Jason Glasgow14521872012-05-07 19:12:15 -040038const char CellularCapabilityUniversal::kConnectPin[] = "pin";
39const char CellularCapabilityUniversal::kConnectOperatorId[] = "operator-id";
40const char CellularCapabilityUniversal::kConnectBands[] = "bands";
41const char CellularCapabilityUniversal::kConnectAllowedModes[] =
42 "allowed-modes";
43const char CellularCapabilityUniversal::kConnectPreferredMode[] =
44 "preferred-mode";
45const char CellularCapabilityUniversal::kConnectApn[] = "apn";
46const char CellularCapabilityUniversal::kConnectIPType[] = "ip-type";
47const char CellularCapabilityUniversal::kConnectUser[] = "user";
48const char CellularCapabilityUniversal::kConnectPassword[] = "password";
49const char CellularCapabilityUniversal::kConnectNumber[] = "number";
50const char CellularCapabilityUniversal::kConnectAllowRoaming[] =
51 "allow-roaming";
52const char CellularCapabilityUniversal::kConnectRMProtocol[] = "rm-protocol";
Jason Glasgowcd0349c2012-05-03 23:32:15 -040053const char CellularCapabilityUniversal::kStatusProperty[] = "status";
54const char CellularCapabilityUniversal::kOperatorLongProperty[] =
55 "operator-long";
56const char CellularCapabilityUniversal::kOperatorShortProperty[] =
57 "operator-short";
58const char CellularCapabilityUniversal::kOperatorCodeProperty[] =
59 "operator-code";
60const char CellularCapabilityUniversal::kOperatorAccessTechnologyProperty[] =
61 "access-technology";
Jason Glasgow14521872012-05-07 19:12:15 -040062const char CellularCapabilityUniversal::kE362ModelId[] = "E362 WWAN";
63unsigned int CellularCapabilityUniversal::friendly_service_name_id_ = 0;
64
Jason Glasgow82f9ab32012-04-04 14:27:19 -040065
66static const char kPhoneNumber[] = "*99#";
67
68static string AccessTechnologyToString(uint32 access_technologies) {
69 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_LTE)
70 return flimflam::kNetworkTechnologyLte;
71 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
72 MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
73 MM_MODEM_ACCESS_TECHNOLOGY_EVDOB))
74 return flimflam::kNetworkTechnologyEvdo;
75 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_1XRTT)
76 return flimflam::kNetworkTechnology1Xrtt;
77 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS)
78 return flimflam::kNetworkTechnologyHspaPlus;
79 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
80 MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
81 MM_MODEM_ACCESS_TECHNOLOGY_HSDPA))
82 return flimflam::kNetworkTechnologyHspa;
83 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_UMTS)
84 return flimflam::kNetworkTechnologyUmts;
85 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_EDGE)
86 return flimflam::kNetworkTechnologyEdge;
87 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_GPRS)
88 return flimflam::kNetworkTechnologyGprs;
89 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
90 MM_MODEM_ACCESS_TECHNOLOGY_GSM))
91 return flimflam::kNetworkTechnologyGsm;
92 return "";
93}
94
Jason Glasgow9f09aef2012-05-08 16:26:55 -040095static string AccessTechnologyToTechnologyFamily(uint32 access_technologies) {
96 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_LTE |
97 MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS |
98 MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
99 MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
100 MM_MODEM_ACCESS_TECHNOLOGY_HSDPA |
101 MM_MODEM_ACCESS_TECHNOLOGY_UMTS |
102 MM_MODEM_ACCESS_TECHNOLOGY_EDGE |
103 MM_MODEM_ACCESS_TECHNOLOGY_GPRS |
104 MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
105 MM_MODEM_ACCESS_TECHNOLOGY_GSM))
106 return flimflam::kTechnologyFamilyGsm;
107 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
108 MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
109 MM_MODEM_ACCESS_TECHNOLOGY_EVDOB |
110 MM_MODEM_ACCESS_TECHNOLOGY_1XRTT))
111 return flimflam::kTechnologyFamilyCdma;
112 return "";
113}
114
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400115CellularCapabilityUniversal::CellularCapabilityUniversal(
116 Cellular *cellular,
117 ProxyFactory *proxy_factory)
118 : CellularCapability(cellular, proxy_factory),
119 weak_ptr_factory_(this),
120 registration_state_(MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN),
121 cdma_registration_state_(MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN),
122 access_technologies_(MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN),
Jason Glasgowaf583282012-04-18 15:18:22 -0400123 supported_modes_(MM_MODEM_MODE_NONE),
124 allowed_modes_(MM_MODEM_MODE_NONE),
125 preferred_mode_(MM_MODEM_MODE_NONE),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400126 home_provider_(NULL),
127 scanning_supported_(true),
128 scanning_(false),
129 scan_interval_(0) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700130 SLOG(Cellular, 2) << "Cellular capability constructed: Universal";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400131 PropertyStore *store = cellular->mutable_store();
132
133 store->RegisterConstString(flimflam::kCarrierProperty, &carrier_);
134 store->RegisterConstBool(flimflam::kSupportNetworkScanProperty,
135 &scanning_supported_);
136 store->RegisterConstString(flimflam::kEsnProperty, &esn_);
137 store->RegisterConstString(flimflam::kFirmwareRevisionProperty,
138 &firmware_revision_);
139 store->RegisterConstString(flimflam::kHardwareRevisionProperty,
140 &hardware_revision_);
141 store->RegisterConstString(flimflam::kImeiProperty, &imei_);
142 store->RegisterConstString(flimflam::kImsiProperty, &imsi_);
143 store->RegisterConstString(flimflam::kManufacturerProperty, &manufacturer_);
144 store->RegisterConstString(flimflam::kMdnProperty, &mdn_);
145 store->RegisterConstString(flimflam::kMeidProperty, &meid_);
146 store->RegisterConstString(flimflam::kMinProperty, &min_);
147 store->RegisterConstString(flimflam::kModelIDProperty, &model_id_);
148 store->RegisterConstString(flimflam::kSelectedNetworkProperty,
149 &selected_network_);
150 store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
151 &found_networks_);
152 store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
153 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
154 HelpRegisterDerivedKeyValueStore(
155 flimflam::kSIMLockStatusProperty,
156 &CellularCapabilityUniversal::SimLockStatusToProperty,
157 NULL);
158 store->RegisterConstStringmaps(flimflam::kCellularApnListProperty,
159 &apn_list_);
160}
161
162KeyValueStore CellularCapabilityUniversal::SimLockStatusToProperty(
163 Error */*error*/) {
164 KeyValueStore status;
165 status.SetBool(flimflam::kSIMLockEnabledProperty, sim_lock_status_.enabled);
166 status.SetString(flimflam::kSIMLockTypeProperty, sim_lock_status_.lock_type);
167 status.SetUint(flimflam::kSIMLockRetriesLeftProperty,
168 sim_lock_status_.retries_left);
169 return status;
170}
171
172void CellularCapabilityUniversal::HelpRegisterDerivedKeyValueStore(
173 const string &name,
174 KeyValueStore(CellularCapabilityUniversal::*get)(Error *error),
175 void(CellularCapabilityUniversal::*set)(
176 const KeyValueStore &value, Error *error)) {
177 cellular()->mutable_store()->RegisterDerivedKeyValueStore(
178 name,
179 KeyValueStoreAccessor(
180 new CustomAccessor<CellularCapabilityUniversal, KeyValueStore>(
181 this, get, set)));
182}
183
184void CellularCapabilityUniversal::InitProxies() {
185 modem_3gpp_proxy_.reset(
186 proxy_factory()->CreateMM1ModemModem3gppProxy(cellular()->dbus_path(),
187 cellular()->dbus_owner()));
188 modem_cdma_proxy_.reset(
189 proxy_factory()->CreateMM1ModemModemCdmaProxy(cellular()->dbus_path(),
190 cellular()->dbus_owner()));
191 modem_proxy_.reset(
192 proxy_factory()->CreateMM1ModemProxy(cellular()->dbus_path(),
193 cellular()->dbus_owner()));
194 modem_simple_proxy_.reset(
195 proxy_factory()->CreateMM1ModemSimpleProxy(cellular()->dbus_path(),
196 cellular()->dbus_owner()));
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400197 modem_proxy_->set_state_changed_callback(
198 Bind(&CellularCapabilityUniversal::OnModemStateChangedSignal,
199 weak_ptr_factory_.GetWeakPtr()));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400200 // Do not create a SIM proxy until the device is enabled because we
201 // do not yet know the object path of the sim object.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400202 // TODO(jglasgow): register callbacks
203}
204
205void CellularCapabilityUniversal::StartModem(Error *error,
Jason Glasgowef965562012-04-10 16:12:35 -0400206 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700207 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400208
209 InitProxies();
210
211 // Start by trying to enable the modem
212 CHECK(!callback.is_null());
213 modem_proxy_->Enable(
214 true,
215 error,
216 Bind(&CellularCapabilityUniversal::Start_EnableModemCompleted,
217 weak_ptr_factory_.GetWeakPtr(), callback),
218 kTimeoutEnable);
219 if (error->IsFailure())
220 callback.Run(*error);
221}
222
223void CellularCapabilityUniversal::Start_EnableModemCompleted(
224 const ResultCallback &callback, const Error &error) {
Eric Shienbrood9b1bd7b2012-04-20 16:42:26 -0400225 SLOG(Cellular, 2) << __func__ << ": " << error;
Jason Glasgowef965562012-04-10 16:12:35 -0400226 if (error.IsFailure()) {
227 callback.Run(error);
228 return;
229 }
230
231 // After modem is enabled, it should be possible to get properties
232 // TODO(jglasgow): handle errors from GetProperties
233 GetProperties();
Jason Glasgow4380f0d2012-05-03 18:05:04 -0400234 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400235}
236
237void CellularCapabilityUniversal::StopModem(Error *error,
Jason Glasgow02401cc2012-05-16 10:35:37 -0400238 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700239 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400240 CHECK(!callback.is_null());
241 CHECK(error);
Jason Glasgow02401cc2012-05-16 10:35:37 -0400242 Cellular::State state = cellular()->state();
243 bool connected = (state == Cellular::kStateConnected ||
244 state == Cellular::kStateLinked);
Jason Glasgowef965562012-04-10 16:12:35 -0400245
246 if (connected) {
Jason Glasgow02401cc2012-05-16 10:35:37 -0400247 string all_bearers("/"); // "/" means all bearers. See Modemanager docs.
Jason Glasgowef965562012-04-10 16:12:35 -0400248 modem_simple_proxy_->Disconnect(
249 all_bearers,
250 error,
251 Bind(&CellularCapabilityUniversal::Stop_DisconnectCompleted,
252 weak_ptr_factory_.GetWeakPtr(), callback),
253 kTimeoutDefault);
254 if (error->IsFailure())
255 callback.Run(*error);
256 } else {
Jason Glasgowef965562012-04-10 16:12:35 -0400257 Closure task = Bind(&CellularCapabilityUniversal::Stop_Disable,
258 weak_ptr_factory_.GetWeakPtr(),
259 callback);
260 cellular()->dispatcher()->PostTask(task);
261 }
262}
263
264void CellularCapabilityUniversal::Stop_DisconnectCompleted(
265 const ResultCallback &callback, const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700266 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400267
268 LOG_IF(ERROR, error.IsFailure()) << "Disconnect failed. Ignoring.";
269 Stop_Disable(callback);
270}
271
272void CellularCapabilityUniversal::Stop_Disable(const ResultCallback &callback) {
273 Error error;
274 modem_proxy_->Enable(
275 false, &error,
276 Bind(&CellularCapabilityUniversal::Stop_DisableCompleted,
277 weak_ptr_factory_.GetWeakPtr(), callback),
Jason Glasgow02401cc2012-05-16 10:35:37 -0400278 kTimeoutEnable);
Jason Glasgowef965562012-04-10 16:12:35 -0400279 if (error.IsFailure())
280 callback.Run(error);
281}
282
283void CellularCapabilityUniversal::Stop_DisableCompleted(
284 const ResultCallback &callback, const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700285 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400286
287 if (error.IsSuccess())
288 ReleaseProxies();
289 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400290}
291
292void CellularCapabilityUniversal::Connect(const DBusPropertiesMap &properties,
293 Error *error,
294 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700295 SLOG(Cellular, 2) << __func__;
Nathan Williamsb54974f2012-04-19 11:16:30 -0400296 DBusPathCallback cb = Bind(&CellularCapabilityUniversal::OnConnectReply,
297 weak_ptr_factory_.GetWeakPtr(),
298 callback);
299 modem_simple_proxy_->Connect(properties, error, cb, kTimeoutConnect);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400300}
301
302void CellularCapabilityUniversal::Disconnect(Error *error,
303 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700304 SLOG(Cellular, 2) << __func__;
Nathan Williamsb54974f2012-04-19 11:16:30 -0400305 modem_simple_proxy_->Disconnect(bearer_path_,
306 error,
307 callback,
308 kTimeoutDefault);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400309}
310
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400311void CellularCapabilityUniversal::Activate(const string &carrier,
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400312 Error *error,
313 const ResultCallback &callback) {
314 OnUnsupportedOperation(__func__, error);
315}
316
317void CellularCapabilityUniversal::ReleaseProxies() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700318 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400319 modem_3gpp_proxy_.reset();
320 modem_cdma_proxy_.reset();
321 modem_proxy_.reset();
322 modem_simple_proxy_.reset();
323 sim_proxy_.reset();
324}
325
326void CellularCapabilityUniversal::OnServiceCreated() {
327 // If IMSI is available, base the service's storage identifier on it.
328 if (!imsi_.empty()) {
329 cellular()->service()->SetStorageIdentifier(
330 string(flimflam::kTypeCellular) + "_" +
331 cellular()->address() + "_" + imsi_);
332 }
333 cellular()->service()->SetActivationState(
334 flimflam::kActivationStateActivated);
335 UpdateServingOperator();
336}
337
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400338// Create the list of APNs to try, in the following order:
339// - last APN that resulted in a successful connection attempt on the
340// current network (if any)
341// - the APN, if any, that was set by the user
342// - the list of APNs found in the mobile broadband provider DB for the
343// home provider associated with the current SIM
344// - as a last resort, attempt to connect with no APN
345void CellularCapabilityUniversal::SetupApnTryList() {
346 apn_try_list_.clear();
347
348 DCHECK(cellular()->service().get());
349 const Stringmap *apn_info = cellular()->service()->GetLastGoodApn();
350 if (apn_info)
351 apn_try_list_.push_back(*apn_info);
352
353 apn_info = cellular()->service()->GetUserSpecifiedApn();
354 if (apn_info)
355 apn_try_list_.push_back(*apn_info);
356
357 apn_try_list_.insert(apn_try_list_.end(), apn_list_.begin(), apn_list_.end());
358}
359
360void CellularCapabilityUniversal::SetupConnectProperties(
361 DBusPropertiesMap *properties) {
362 SetupApnTryList();
363 FillConnectPropertyMap(properties);
364}
365
366void CellularCapabilityUniversal::FillConnectPropertyMap(
367 DBusPropertiesMap *properties) {
368
369 // TODO(jglasgow): Is this really needed anymore?
Jason Glasgow14521872012-05-07 19:12:15 -0400370 (*properties)[kConnectNumber].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400371 kPhoneNumber);
372
Jason Glasgow14521872012-05-07 19:12:15 -0400373 (*properties)[kConnectAllowRoaming].writer().append_bool(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400374 AllowRoaming());
375
376 if (!apn_try_list_.empty()) {
377 // Leave the APN at the front of the list, so that it can be recorded
378 // if the connect attempt succeeds.
379 Stringmap apn_info = apn_try_list_.front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700380 SLOG(Cellular, 2) << __func__ << ": Using APN "
381 << apn_info[flimflam::kApnProperty];
Jason Glasgow14521872012-05-07 19:12:15 -0400382 (*properties)[kConnectApn].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400383 apn_info[flimflam::kApnProperty].c_str());
384 if (ContainsKey(apn_info, flimflam::kApnUsernameProperty))
Jason Glasgow14521872012-05-07 19:12:15 -0400385 (*properties)[kConnectUser].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400386 apn_info[flimflam::kApnUsernameProperty].c_str());
387 if (ContainsKey(apn_info, flimflam::kApnPasswordProperty))
Jason Glasgow14521872012-05-07 19:12:15 -0400388 (*properties)[kConnectPassword].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400389 apn_info[flimflam::kApnPasswordProperty].c_str());
390 }
391}
392
393void CellularCapabilityUniversal::OnConnectReply(const ResultCallback &callback,
Nathan Williamsb54974f2012-04-19 11:16:30 -0400394 const DBus::Path &path,
395 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700396 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Nathan Williamsb54974f2012-04-19 11:16:30 -0400397
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400398 if (error.IsFailure()) {
399 cellular()->service()->ClearLastGoodApn();
400 // The APN that was just tried (and failed) is still at the
401 // front of the list, about to be removed. If the list is empty
402 // after that, try one last time without an APN. This may succeed
403 // with some modems in some cases.
Jason Glasgow14521872012-05-07 19:12:15 -0400404 if (RetriableConnectError(error) && !apn_try_list_.empty()) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400405 apn_try_list_.pop_front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700406 SLOG(Cellular, 2) << "Connect failed with invalid APN, "
407 << apn_try_list_.size() << " remaining APNs to try";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400408 DBusPropertiesMap props;
409 FillConnectPropertyMap(&props);
410 Error error;
411 Connect(props, &error, callback);
412 return;
413 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400414 } else {
415 if (!apn_try_list_.empty()) {
416 cellular()->service()->SetLastGoodApn(apn_try_list_.front());
417 apn_try_list_.clear();
418 }
Nathan Williamsb54974f2012-04-19 11:16:30 -0400419 bearer_path_ = path;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400420 }
421
422 if (!callback.is_null())
423 callback.Run(error);
424}
425
426bool CellularCapabilityUniversal::AllowRoaming() {
427 bool requires_roaming =
428 home_provider_ ? home_provider_->requires_roaming : false;
429 return requires_roaming || allow_roaming_property();
430}
431
Jason Glasgowef965562012-04-10 16:12:35 -0400432void CellularCapabilityUniversal::GetProperties() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700433 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400434
Jason Glasgowaf583282012-04-18 15:18:22 -0400435 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
436 proxy_factory()->CreateDBusPropertiesProxy(cellular()->dbus_path(),
437 cellular()->dbus_owner()));
438 DBusPropertiesMap properties(
439 properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM));
440 OnModemPropertiesChanged(properties, vector<string>());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400441
Jason Glasgowaf583282012-04-18 15:18:22 -0400442 properties = properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM_MODEM3GPP);
443 OnModem3GPPPropertiesChanged(properties, vector<string>());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400444}
445
446string CellularCapabilityUniversal::CreateFriendlyServiceName() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700447 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400448 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME &&
449 !cellular()->home_provider().GetName().empty()) {
450 return cellular()->home_provider().GetName();
451 }
452 if (!serving_operator_.GetName().empty()) {
453 return serving_operator_.GetName();
454 }
455 if (!carrier_.empty()) {
456 return carrier_;
457 }
458 if (!serving_operator_.GetCode().empty()) {
459 return "cellular_" + serving_operator_.GetCode();
460 }
461 return base::StringPrintf("GSMNetwork%u", friendly_service_name_id_++);
462}
463
464void CellularCapabilityUniversal::SetHomeProvider() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700465 SLOG(Cellular, 2) << __func__ << "(IMSI: " << imsi_
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400466 << " SPN: " << spn_ << ")";
467 // TODO(petkov): The test for NULL provider_db should be done by
468 // mobile_provider_lookup_best_match.
469 if (imsi_.empty() || !cellular()->provider_db()) {
470 return;
471 }
472 mobile_provider *provider =
473 mobile_provider_lookup_best_match(
474 cellular()->provider_db(), spn_.c_str(), imsi_.c_str());
475 if (!provider) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700476 SLOG(Cellular, 2) << "GSM provider not found.";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400477 return;
478 }
Jason Glasgow4380f0d2012-05-03 18:05:04 -0400479
480 // Even if provider is the same as home_provider_, it is possible
481 // that the spn_ has changed. Run all the code below.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400482 home_provider_ = provider;
Jason Glasgow4380f0d2012-05-03 18:05:04 -0400483
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400484 Cellular::Operator oper;
485 if (provider->networks) {
486 oper.SetCode(provider->networks[0]);
487 }
488 if (provider->country) {
489 oper.SetCountry(provider->country);
490 }
491 if (spn_.empty()) {
492 const char *name = mobile_provider_get_name(provider);
493 if (name) {
494 oper.SetName(name);
495 }
496 } else {
497 oper.SetName(spn_);
498 }
499 cellular()->set_home_provider(oper);
500 InitAPNList();
501}
502
503void CellularCapabilityUniversal::UpdateOperatorInfo() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700504 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400505 const string &network_id = serving_operator_.GetCode();
506 if (!network_id.empty()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700507 SLOG(Cellular, 2) << "Looking up network id: " << network_id;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400508 mobile_provider *provider =
509 mobile_provider_lookup_by_network(cellular()->provider_db(),
510 network_id.c_str());
511 if (provider) {
512 const char *provider_name = mobile_provider_get_name(provider);
513 if (provider_name && *provider_name) {
514 serving_operator_.SetName(provider_name);
515 if (provider->country) {
516 serving_operator_.SetCountry(provider->country);
517 }
Ben Chanfad4a0b2012-04-18 15:49:59 -0700518 SLOG(Cellular, 2) << "Operator name: " << serving_operator_.GetName()
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400519 << ", country: " << serving_operator_.GetCountry();
520 }
521 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700522 SLOG(Cellular, 2) << "GSM provider not found.";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400523 }
524 }
525 UpdateServingOperator();
526}
527
528void CellularCapabilityUniversal::UpdateServingOperator() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700529 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400530 if (cellular()->service().get()) {
531 cellular()->service()->SetServingOperator(serving_operator_);
532 }
533}
534
535void CellularCapabilityUniversal::InitAPNList() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700536 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400537 if (!home_provider_) {
538 return;
539 }
540 apn_list_.clear();
541 for (int i = 0; i < home_provider_->num_apns; ++i) {
542 Stringmap props;
543 mobile_apn *apn = home_provider_->apns[i];
544 if (apn->value) {
545 props[flimflam::kApnProperty] = apn->value;
546 }
547 if (apn->username) {
548 props[flimflam::kApnUsernameProperty] = apn->username;
549 }
550 if (apn->password) {
551 props[flimflam::kApnPasswordProperty] = apn->password;
552 }
553 // Find the first localized and non-localized name, if any.
554 const localized_name *lname = NULL;
555 const localized_name *name = NULL;
556 for (int j = 0; j < apn->num_names; ++j) {
557 if (apn->names[j]->lang) {
558 if (!lname) {
559 lname = apn->names[j];
560 }
561 } else if (!name) {
562 name = apn->names[j];
563 }
564 }
565 if (name) {
566 props[flimflam::kApnNameProperty] = name->name;
567 }
568 if (lname) {
569 props[flimflam::kApnLocalizedNameProperty] = lname->name;
570 props[flimflam::kApnLanguageProperty] = lname->lang;
571 }
572 apn_list_.push_back(props);
573 }
574 cellular()->adaptor()->EmitStringmapsChanged(
575 flimflam::kCellularApnListProperty, apn_list_);
576}
577
578// always called from an async context
579void CellularCapabilityUniversal::Register(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700580 SLOG(Cellular, 2) << __func__ << " \"" << selected_network_ << "\"";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400581 CHECK(!callback.is_null());
582 Error error;
583 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
584 weak_ptr_factory_.GetWeakPtr(), callback);
585 modem_3gpp_proxy_->Register(selected_network_, &error, cb, kTimeoutRegister);
586 if (error.IsFailure())
587 callback.Run(error);
588}
589
590void CellularCapabilityUniversal::RegisterOnNetwork(
591 const string &network_id,
592 Error *error,
593 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700594 SLOG(Cellular, 2) << __func__ << "(" << network_id << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400595 CHECK(error);
596 desired_network_ = network_id;
597 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
598 weak_ptr_factory_.GetWeakPtr(), callback);
599 modem_3gpp_proxy_->Register(network_id, error, cb, kTimeoutRegister);
600}
601
602void CellularCapabilityUniversal::OnRegisterReply(
603 const ResultCallback &callback,
604 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700605 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400606
607 if (error.IsSuccess()) {
608 selected_network_ = desired_network_;
609 desired_network_.clear();
610 callback.Run(error);
611 return;
612 }
613 // If registration on the desired network failed,
614 // try to register on the home network.
615 if (!desired_network_.empty()) {
616 desired_network_.clear();
617 selected_network_.clear();
618 LOG(INFO) << "Couldn't register on selected network, trying home network";
619 Register(callback);
620 return;
621 }
622 callback.Run(error);
623}
624
625bool CellularCapabilityUniversal::IsRegistered() {
626 return (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
627 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING);
628}
629
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400630void CellularCapabilityUniversal::SetUnregistered(bool searching) {
631 // If we're already in some non-registered state, don't override that
632 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
633 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) {
634 registration_state_ =
635 (searching ? MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING :
636 MM_MODEM_3GPP_REGISTRATION_STATE_IDLE);
637 }
638}
639
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400640void CellularCapabilityUniversal::RequirePIN(
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400641 const string &pin, bool require,
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400642 Error *error, const ResultCallback &callback) {
643 CHECK(error);
644 sim_proxy_->EnablePin(pin, require, error, callback, kTimeoutDefault);
645}
646
647void CellularCapabilityUniversal::EnterPIN(const string &pin,
648 Error *error,
649 const ResultCallback &callback) {
650 CHECK(error);
651 sim_proxy_->SendPin(pin, error, callback, kTimeoutDefault);
652}
653
654void CellularCapabilityUniversal::UnblockPIN(const string &unblock_code,
655 const string &pin,
656 Error *error,
657 const ResultCallback &callback) {
658 CHECK(error);
659 sim_proxy_->SendPuk(unblock_code, pin, error, callback, kTimeoutDefault);
660}
661
662void CellularCapabilityUniversal::ChangePIN(
663 const string &old_pin, const string &new_pin,
664 Error *error, const ResultCallback &callback) {
665 CHECK(error);
666 sim_proxy_->ChangePin(old_pin, new_pin, error, callback, kTimeoutDefault);
667}
668
669void CellularCapabilityUniversal::Scan(Error *error,
670 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700671 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400672 CHECK(error);
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400673 if (scanning_) {
674 Error::PopulateAndLog(error, Error::kInProgress, "Already scanning");
675 return;
676 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400677 DBusPropertyMapsCallback cb = Bind(&CellularCapabilityUniversal::OnScanReply,
678 weak_ptr_factory_.GetWeakPtr(), callback);
679 modem_3gpp_proxy_->Scan(error, cb, kTimeoutScan);
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400680 if (!error->IsFailure()) {
681 scanning_ = true;
682 cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty,
683 scanning_);
684 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400685}
686
687void CellularCapabilityUniversal::OnScanReply(const ResultCallback &callback,
688 const ScanResults &results,
689 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700690 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400691
692 // Error handling is weak. The current expectation is that on any
693 // error, found_networks_ should be cleared and a property change
694 // notification sent out.
695 //
696 // TODO(jglasgow): fix error handling
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400697 scanning_ = false;
698 cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty,
699 scanning_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400700 found_networks_.clear();
701 if (!error.IsFailure()) {
702 for (ScanResults::const_iterator it = results.begin();
703 it != results.end(); ++it) {
704 found_networks_.push_back(ParseScanResult(*it));
705 }
706 }
707 cellular()->adaptor()->EmitStringmapsChanged(flimflam::kFoundNetworksProperty,
708 found_networks_);
Gary Morainceba6aa2012-05-03 10:28:26 -0700709
710 // TODO(gmorain): This check for is_null() is a work-around because
711 // Cellular::Scan() passes a null callback. Instead: 1. Have Cellular::Scan()
712 // pass in a callback. 2. Have Cellular "own" the found_networks_ property
713 // 3. Have Cellular EmitStingMapsChanged() 4. Share the code between GSM and
714 // Universal.
715 if (!callback.is_null())
716 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400717}
718
719Stringmap CellularCapabilityUniversal::ParseScanResult(
720 const ScanResult &result) {
721
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400722 /* ScanResults contain the following keys:
723
724 "status"
725 A MMModem3gppNetworkAvailability value representing network
726 availability status, given as an unsigned integer (signature "u").
727 This key will always be present.
728
729 "operator-long"
730 Long-format name of operator, given as a string value (signature
731 "s"). If the name is unknown, this field should not be present.
732
733 "operator-short"
734 Short-format name of operator, given as a string value
735 (signature "s"). If the name is unknown, this field should not
736 be present.
737
738 "operator-code"
739 Mobile code of the operator, given as a string value (signature
740 "s"). Returned in the format "MCCMNC", where MCC is the
741 three-digit ITU E.212 Mobile Country Code and MNC is the two- or
742 three-digit GSM Mobile Network Code. e.g. "31026" or "310260".
743
744 "access-technology"
745 A MMModemAccessTechnology value representing the generic access
746 technology used by this mobile network, given as an unsigned
747 integer (signature "u").
748 */
749 Stringmap parsed;
750
751 uint32 status;
752 if (DBusProperties::GetUint32(result, kStatusProperty, &status)) {
753 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
754 static const char * const kStatusString[] = {
755 "unknown", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_UNKNOWN
756 "available", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_AVAILABLE
757 "current", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_CURRENT
758 "forbidden", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_FORBIDDEN
759 };
760 parsed[flimflam::kStatusProperty] = kStatusString[status];
761 }
762
763 uint32 tech; // MMModemAccessTechnology
764 if (DBusProperties::GetUint32(result, kOperatorAccessTechnologyProperty,
765 &tech)) {
766 parsed[flimflam::kTechnologyProperty] = AccessTechnologyToString(tech);
767 }
768
769 string operator_long, operator_short, operator_code;
770 if (DBusProperties::GetString(result, kOperatorLongProperty, &operator_long))
771 parsed[flimflam::kLongNameProperty] = operator_long;
772 if (DBusProperties::GetString(result, kOperatorShortProperty,
773 &operator_short))
774 parsed[flimflam::kShortNameProperty] = operator_short;
775 if (DBusProperties::GetString(result, kOperatorCodeProperty, &operator_code))
776 parsed[flimflam::kNetworkIdProperty] = operator_code;
777
778 // If the long name is not available but the network ID is, look up the long
779 // name in the mobile provider database.
780 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
781 parsed[flimflam::kLongNameProperty].empty()) &&
782 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
783 mobile_provider *provider =
784 mobile_provider_lookup_by_network(
785 cellular()->provider_db(),
786 parsed[flimflam::kNetworkIdProperty].c_str());
787 if (provider) {
788 const char *long_name = mobile_provider_get_name(provider);
789 if (long_name && *long_name) {
790 parsed[flimflam::kLongNameProperty] = long_name;
791 }
792 }
793 }
794 return parsed;
795}
796
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400797string CellularCapabilityUniversal::GetNetworkTechnologyString() const {
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400798 // Order is important. Return the highest speed technology
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400799 // TODO(jglasgow): change shill interfaces to a capability model
800
801 return AccessTechnologyToString(access_technologies_);
802}
803
804string CellularCapabilityUniversal::GetRoamingStateString() const {
805 switch (registration_state_) {
806 case MM_MODEM_3GPP_REGISTRATION_STATE_HOME:
807 return flimflam::kRoamingStateHome;
808 case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING:
809 return flimflam::kRoamingStateRoaming;
810 default:
811 break;
812 }
813 return flimflam::kRoamingStateUnknown;
814}
815
816void CellularCapabilityUniversal::GetSignalQuality() {
Nathan Williams218cbcd2012-04-17 16:48:44 -0400817 // TODO(njw): Switch to asynchronous calls (crosbug.com/17583).
818 const DBus::Struct<unsigned int, bool> quality =
819 modem_proxy_->SignalQuality();
820 OnSignalQualityChanged(quality._1);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400821}
822
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400823string CellularCapabilityUniversal::GetTypeString() const {
824 return AccessTechnologyToTechnologyFamily(access_technologies_);
825}
826
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400827void CellularCapabilityUniversal::OnModemPropertiesChanged(
828 const DBusPropertiesMap &properties,
829 const vector<string> &/* invalidated_properties */) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400830 // This solves a bootstrapping problem: If the modem is not yet
831 // enabled, there are no proxy objects associated with the capability
832 // object, so modem signals like StateChanged aren't seen. By monitoring
833 // changes to the State property via the ModemManager, we're able to
834 // get the initialization process started, which will result in the
835 // creation of the proxy objects.
836 //
837 // The first time we see the change to State (when the modem state
838 // is Unknown), we simply update the state, and rely on the Manager to
839 // enable the device when it is registered with the Manager. On subsequent
840 // changes to State, we need to explicitly enable the device ourselves.
841 int32 istate;
Jason Glasgowaf583282012-04-18 15:18:22 -0400842 if (DBusProperties::GetInt32(properties, MM_MODEM_PROPERTY_STATE, &istate)) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400843 Cellular::ModemState state = static_cast<Cellular::ModemState>(istate);
Jason Glasgowaf583282012-04-18 15:18:22 -0400844 OnModemStateChanged(state);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400845 }
Jason Glasgowaf583282012-04-18 15:18:22 -0400846 string string_value;
Nathan Williamse9840802012-04-18 18:47:40 -0400847 if (DBusProperties::GetObjectPath(properties,
Jason Glasgowaf583282012-04-18 15:18:22 -0400848 MM_MODEM_PROPERTY_SIM, &string_value))
849 OnSimPathChanged(string_value);
850 uint32 uint_value;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400851 if (DBusProperties::GetUint32(properties,
Jason Glasgowaf583282012-04-18 15:18:22 -0400852 MM_MODEM_PROPERTY_MODEMCAPABILITIES,
853 &uint_value))
854 OnModemCapabilitesChanged(uint_value);
855 if (DBusProperties::GetUint32(properties,
856 MM_MODEM_PROPERTY_CURRENTCAPABILITIES,
857 &uint_value))
858 OnModemCurrentCapabilitiesChanged(uint_value);
859 // not needed: MM_MODEM_PROPERTY_MAXBEARERS
860 // not needed: MM_MODEM_PROPERTY_MAXACTIVEBEARERS
861 if (DBusProperties::GetString(properties,
862 MM_MODEM_PROPERTY_MANUFACTURER,
863 &string_value))
864 OnModemManufacturerChanged(string_value);
865 if (DBusProperties::GetString(properties,
866 MM_MODEM_PROPERTY_MODEL,
867 &string_value))
868 OnModemModelChanged(string_value);
869 if (DBusProperties::GetString(properties,
870 MM_MODEM_PROPERTY_REVISION,
871 &string_value))
872 OnModemRevisionChanged(string_value);
873 // not needed: MM_MODEM_PROPERTY_DEVICEIDENTIFIER
874 // not needed: MM_MODEM_PROPERTY_DEVICE
875 // not needed: MM_MODEM_PROPERTY_DRIVER
876 // not needed: MM_MODEM_PROPERTY_PLUGIN
877 // not needed: MM_MODEM_PROPERTY_EQUIPMENTIDENTIFIER
Nathan Williams218cbcd2012-04-17 16:48:44 -0400878
Jason Glasgowaf583282012-04-18 15:18:22 -0400879 // Unlock required and SimLock
880 bool locks_changed = false;
881 uint32_t unlock_required; // This is really of type MMModemLock
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400882 if (DBusProperties::GetUint32(properties,
883 MM_MODEM_PROPERTY_UNLOCKREQUIRED,
Jason Glasgowaf583282012-04-18 15:18:22 -0400884 &unlock_required)) {
885 locks_changed = true;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400886 }
Jason Glasgowaf583282012-04-18 15:18:22 -0400887 LockRetryData lock_retries;
888 DBusPropertiesMap::const_iterator it =
889 properties.find(MM_MODEM_PROPERTY_UNLOCKRETRIES);
890 if (it != properties.end()) {
891 lock_retries = it->second;
892 locks_changed = true;
893 }
894 if (locks_changed)
895 OnLockRetriesChanged(static_cast<MMModemLock>(unlock_required),
896 lock_retries);
897 if (DBusProperties::GetUint32(properties,
898 MM_MODEM_PROPERTY_ACCESSTECHNOLOGIES,
899 &uint_value))
900 OnAccessTechnologiesChanged(uint_value);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400901
Jason Glasgowaf583282012-04-18 15:18:22 -0400902 it = properties.find(MM_MODEM_PROPERTY_SIGNALQUALITY);
903 if (it != properties.end()) {
904 DBus::Struct<unsigned int, bool> quality = it->second;
905 OnSignalQualityChanged(quality._1);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400906 }
Jason Glasgowaf583282012-04-18 15:18:22 -0400907 vector<string> numbers;
908 if (DBusProperties::GetStrings(properties, MM_MODEM_PROPERTY_OWNNUMBERS,
909 &numbers)) {
910 string mdn;
911 if (numbers.size() > 0)
912 mdn = numbers[0];
913 OnMdnChanged(mdn);
914 }
915 if (DBusProperties::GetUint32(properties, MM_MODEM_PROPERTY_SUPPORTEDMODES,
916 &uint_value))
917 OnSupportedModesChanged(uint_value);
918 if (DBusProperties::GetUint32(properties, MM_MODEM_PROPERTY_ALLOWEDMODES,
919 &uint_value))
920 OnAllowedModesChanged(uint_value);
921 if (DBusProperties::GetUint32(properties, MM_MODEM_PROPERTY_PREFERREDMODE,
922 &uint_value))
923 OnPreferredModeChanged(static_cast<MMModemMode>(uint_value));
924 // au: MM_MODEM_PROPERTY_SUPPORTEDBANDS,
925 // au: MM_MODEM_PROPERTY_BANDS
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400926}
927
928void CellularCapabilityUniversal::OnDBusPropertiesChanged(
929 const string &interface,
930 const DBusPropertiesMap &changed_properties,
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400931 const vector<string> &invalidated_properties) {
Jason Glasgowef965562012-04-10 16:12:35 -0400932 if (interface == MM_DBUS_INTERFACE_MODEM) {
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400933 OnModemPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgowef965562012-04-10 16:12:35 -0400934 }
Jason Glasgowaf583282012-04-18 15:18:22 -0400935 if (interface == MM_DBUS_INTERFACE_MODEM_MODEM3GPP) {
936 OnModem3GPPPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400937 }
Jason Glasgowaf583282012-04-18 15:18:22 -0400938 if (interface == MM_DBUS_INTERFACE_SIM) {
939 OnSimPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400940 }
941}
942
Jason Glasgow14521872012-05-07 19:12:15 -0400943bool CellularCapabilityUniversal::RetriableConnectError(
944 const Error &error) const {
945 if (error.type() == Error::kInvalidApn)
946 return true;
947
948 // modemmanager does not ever return kInvalidApn for E362 modems
949 // with 1.41 firmware. It remains to be seem if this will change
950 // with 3.x firmware.
951 if ((model_id_ == kE362ModelId) && (error.type() == Error::kOperationFailed))
952 return true;
953
954 return false;
955}
956
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400957void CellularCapabilityUniversal::OnNetworkModeSignal(uint32 /*mode*/) {
958 // TODO(petkov): Implement this.
959 NOTIMPLEMENTED();
960}
961
Jason Glasgowaf583282012-04-18 15:18:22 -0400962void CellularCapabilityUniversal::OnSimPathChanged(
963 const string &sim_path) {
964 if (sim_path == sim_path_)
965 return;
966
967 mm1::SimProxyInterface *proxy = NULL;
968 if (!sim_path.empty())
969 proxy = proxy_factory()->CreateSimProxy(sim_path,
970 cellular()->dbus_owner());
971 sim_path_ = sim_path;
972 sim_proxy_.reset(proxy);
973
974 if (sim_path.empty()) {
975 // Clear all data about the sim
Jason Glasgow4380f0d2012-05-03 18:05:04 -0400976 imsi_ = "";
977 spn_ = "";
Jason Glasgowaf583282012-04-18 15:18:22 -0400978 OnSimIdentifierChanged("");
979 OnOperatorIdChanged("");
Jason Glasgowaf583282012-04-18 15:18:22 -0400980 } else {
981 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
982 proxy_factory()->CreateDBusPropertiesProxy(sim_path,
983 cellular()->dbus_owner()));
984 // TODO(jglasgow): convert to async interface
985 DBusPropertiesMap properties(
986 properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
987 OnSimPropertiesChanged(properties, vector<string>());
988 }
989}
990
991void CellularCapabilityUniversal::OnModemCapabilitesChanged(
992 uint32 capabilities) {
993 capabilities_ = capabilities;
994}
995
996void CellularCapabilityUniversal::OnModemCurrentCapabilitiesChanged(
997 uint32 current_capabilities) {
998 current_capabilities_ = current_capabilities;
999}
1000
1001void CellularCapabilityUniversal::OnMdnChanged(
1002 const string &mdn) {
1003 mdn_ = mdn;
1004}
1005
1006void CellularCapabilityUniversal::OnModemManufacturerChanged(
1007 const string &manufacturer) {
1008 manufacturer_ = manufacturer;
1009}
1010
1011void CellularCapabilityUniversal::OnModemModelChanged(
1012 const string &model) {
1013 model_id_ = model;
1014}
1015
1016void CellularCapabilityUniversal::OnModemRevisionChanged(
1017 const string &revision) {
1018 firmware_revision_ = revision;
1019}
1020
1021void CellularCapabilityUniversal::OnModemStateChanged(
1022 Cellular::ModemState state) {
1023 Cellular::ModemState prev_modem_state = cellular()->modem_state();
1024 bool was_enabled = cellular()->IsUnderlyingDeviceEnabled();
1025 if (Cellular::IsEnabledModemState(state))
1026 cellular()->set_modem_state(state);
1027 if (prev_modem_state != Cellular::kModemStateUnknown &&
1028 prev_modem_state != Cellular::kModemStateEnabling &&
1029 !was_enabled &&
1030 cellular()->state() == Cellular::kStateDisabled &&
1031 cellular()->IsUnderlyingDeviceEnabled()) {
1032 cellular()->SetEnabled(true);
1033 }
1034}
1035
1036void CellularCapabilityUniversal::OnAccessTechnologiesChanged(
1037 uint32 access_technologies) {
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001038 if (access_technologies_ != access_technologies) {
Jason Glasgowbad114b2012-05-21 15:24:16 -04001039 const string old_type_string(GetTypeString());
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001040 access_technologies_ = access_technologies;
Jason Glasgowbad114b2012-05-21 15:24:16 -04001041 const string new_type_string(GetTypeString());
1042 if (new_type_string != old_type_string) {
1043 // TODO(jglasgow): address layering violation of emitting change
1044 // signal here for a property owned by Cellular.
1045 cellular()->adaptor()->EmitStringChanged(
1046 flimflam::kTechnologyFamilyProperty, new_type_string);
1047 }
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001048 if (cellular()->service().get()) {
1049 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
1050 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001051 }
1052}
1053
1054void CellularCapabilityUniversal::OnSupportedModesChanged(
1055 uint32 supported_modes) {
1056 supported_modes_ = supported_modes;
1057}
1058
1059void CellularCapabilityUniversal::OnAllowedModesChanged(
1060 uint32 allowed_modes) {
1061 allowed_modes_ = allowed_modes;
1062}
1063
1064void CellularCapabilityUniversal::OnPreferredModeChanged(
1065 MMModemMode preferred_mode) {
1066 preferred_mode_ = preferred_mode;
1067}
1068
1069void CellularCapabilityUniversal::OnLockRetriesChanged(
1070 MMModemLock unlock_required,
1071 const LockRetryData &lock_retries) {
Jason Glasgowd4af81d2012-05-03 22:25:05 -04001072 switch (unlock_required) {
Jason Glasgowaf583282012-04-18 15:18:22 -04001073 case MM_MODEM_LOCK_SIM_PIN:
1074 sim_lock_status_.lock_type = "sim-pin";
1075 break;
1076 case MM_MODEM_LOCK_SIM_PUK:
1077 sim_lock_status_.lock_type = "sim-puk";
1078 break;
1079 default:
1080 sim_lock_status_.lock_type = "";
1081 break;
1082 }
1083 LockRetryData::const_iterator it = lock_retries.find(unlock_required);
1084 if (it != lock_retries.end()) {
1085 sim_lock_status_.retries_left = it->second;
1086 } else {
1087 // Unknown, use 999
1088 sim_lock_status_.retries_left = 999;
1089 }
1090 OnSimLockStatusChanged();
1091}
1092
1093void CellularCapabilityUniversal::OnSimLockStatusChanged() {
1094 cellular()->adaptor()->EmitKeyValueStoreChanged(
1095 flimflam::kSIMLockStatusProperty, SimLockStatusToProperty(NULL));
1096}
1097
1098void CellularCapabilityUniversal::OnModem3GPPPropertiesChanged(
1099 const DBusPropertiesMap &properties,
1100 const vector<string> &/* invalidated_properties */) {
1101 VLOG(2) << __func__;
1102 string imei;
1103 if (DBusProperties::GetString(properties,
1104 MM_MODEM_MODEM3GPP_PROPERTY_IMEI,
1105 &imei))
1106 OnImeiChanged(imei);
1107
1108 // Handle registration state changes as a single change
1109 string operator_code = serving_operator_.GetCode();
1110 string operator_name = serving_operator_.GetName();
1111 MMModem3gppRegistrationState state = registration_state_;
1112 bool registration_changed = false;
1113 uint32 uint_value;
1114 if (DBusProperties::GetUint32(properties,
1115 MM_MODEM_MODEM3GPP_PROPERTY_REGISTRATIONSTATE,
1116 &uint_value)) {
1117 state = static_cast<MMModem3gppRegistrationState>(uint_value);
1118 registration_changed = true;
1119 }
1120 if (DBusProperties::GetString(properties,
1121 MM_MODEM_MODEM3GPP_PROPERTY_OPERATORCODE,
1122 &operator_code))
1123 registration_changed = true;
1124 if (DBusProperties::GetString(properties,
1125 MM_MODEM_MODEM3GPP_PROPERTY_OPERATORNAME,
1126 &operator_name))
1127 registration_changed = true;
1128 if (registration_changed)
1129 On3GPPRegistrationChanged(state, operator_code, operator_name);
1130
1131 uint32 locks = 0;
1132 if (DBusProperties::GetUint32(
1133 properties, MM_MODEM_MODEM3GPP_PROPERTY_ENABLEDFACILITYLOCKS,
1134 &locks))
1135 OnFacilityLocksChanged(locks);
1136}
1137
1138void CellularCapabilityUniversal::OnImeiChanged(const string &imei) {
1139 imei_ = imei;
1140}
1141
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001142void CellularCapabilityUniversal::On3GPPRegistrationChanged(
1143 MMModem3gppRegistrationState state,
1144 const string &operator_code,
1145 const string &operator_name) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001146 SLOG(Cellular, 2) << __func__ << ": regstate=" << state
1147 << ", opercode=" << operator_code
1148 << ", opername=" << operator_name;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001149 registration_state_ = state;
1150 serving_operator_.SetCode(operator_code);
1151 serving_operator_.SetName(operator_name);
1152 UpdateOperatorInfo();
1153 cellular()->HandleNewRegistrationState();
1154}
1155
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001156void CellularCapabilityUniversal::OnModemStateChangedSignal(
1157 int32 old_state, int32 new_state, uint32 reason) {
Eric Shienbrood9b1bd7b2012-04-20 16:42:26 -04001158 SLOG(Cellular, 2) << __func__ << "(" << old_state << ", " << new_state << ", "
1159 << reason << ")";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001160 cellular()->OnModemStateChanged(static_cast<Cellular::ModemState>(old_state),
1161 static_cast<Cellular::ModemState>(new_state),
1162 reason);
1163}
1164
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001165void CellularCapabilityUniversal::OnSignalQualityChanged(uint32 quality) {
1166 cellular()->HandleNewSignalQuality(quality);
1167}
1168
Jason Glasgowaf583282012-04-18 15:18:22 -04001169void CellularCapabilityUniversal::OnFacilityLocksChanged(uint32 locks) {
1170 if (sim_lock_status_.enabled != (locks & MM_MODEM_3GPP_FACILITY_SIM)) {
1171 sim_lock_status_.enabled = locks & MM_MODEM_3GPP_FACILITY_SIM;
1172 OnSimLockStatusChanged();
1173 }
1174}
Jason Glasgowef965562012-04-10 16:12:35 -04001175
Jason Glasgowaf583282012-04-18 15:18:22 -04001176void CellularCapabilityUniversal::OnSimPropertiesChanged(
1177 const DBusPropertiesMap &props,
1178 const vector<string> &/* invalidated_properties */) {
1179 VLOG(2) << __func__;
1180 string value;
Jason Glasgow4380f0d2012-05-03 18:05:04 -04001181 bool must_update_home_provider = false;
Jason Glasgowaf583282012-04-18 15:18:22 -04001182 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_SIMIDENTIFIER, &value))
1183 OnSimIdentifierChanged(value);
1184 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORIDENTIFIER,
1185 &value))
1186 OnOperatorIdChanged(value);
Jason Glasgow4380f0d2012-05-03 18:05:04 -04001187 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORNAME, &value)) {
1188 spn_ = value;
1189 must_update_home_provider = true;
1190 }
1191 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_IMSI, &value)) {
1192 imsi_ = value;
1193 must_update_home_provider = true;
1194 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001195 // TODO(jglasgow): May eventually want to get SPDI, etc
Jason Glasgowaf583282012-04-18 15:18:22 -04001196
Jason Glasgow4380f0d2012-05-03 18:05:04 -04001197 if (must_update_home_provider)
1198 SetHomeProvider();
Jason Glasgowaf583282012-04-18 15:18:22 -04001199}
1200
1201void CellularCapabilityUniversal::OnSimIdentifierChanged(const string &id) {
1202 sim_identifier_ = id;
1203}
1204
1205void CellularCapabilityUniversal::OnOperatorIdChanged(
1206 const string &operator_id) {
1207 operator_id_ = operator_id;
1208}
1209
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001210} // namespace shill