blob: 5c4cb86e8d86ffa9aeebc85d0f6bce74cb578749 [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>
Jason Glasgow82f9ab32012-04-04 14:27:19 -04008#include <base/stl_util.h>
Jason Glasgow82f9ab32012-04-04 14:27:19 -04009#include <base/stringprintf.h>
10#include <chromeos/dbus/service_constants.h>
11#include <mobile_provider.h>
Ben Chanf6120e92012-06-28 18:56:17 -070012#include <ModemManager/ModemManager-names.h>
Jason Glasgow82f9ab32012-04-04 14:27:19 -040013
14#include <string>
15#include <vector>
16
17#include "shill/adaptor_interfaces.h"
18#include "shill/cellular_service.h"
Jason Glasgowaf583282012-04-18 15:18:22 -040019#include "shill/dbus_properties_proxy_interface.h"
Jason Glasgow82f9ab32012-04-04 14:27:19 -040020#include "shill/error.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070021#include "shill/logging.h"
Jason Glasgow82f9ab32012-04-04 14:27:19 -040022#include "shill/property_accessor.h"
23#include "shill/proxy_factory.h"
24
25#ifdef MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN
26#error "Do not include mm-modem.h"
27#endif
28
Jason Glasgow82f9ab32012-04-04 14:27:19 -040029using base::Bind;
Jason Glasgowef965562012-04-10 16:12:35 -040030using base::Closure;
Jason Glasgow82f9ab32012-04-04 14:27:19 -040031using std::string;
32using std::vector;
33
34namespace shill {
35
36// static
Jason Glasgow14521872012-05-07 19:12:15 -040037const char CellularCapabilityUniversal::kConnectPin[] = "pin";
38const char CellularCapabilityUniversal::kConnectOperatorId[] = "operator-id";
39const char CellularCapabilityUniversal::kConnectBands[] = "bands";
40const char CellularCapabilityUniversal::kConnectAllowedModes[] =
41 "allowed-modes";
42const char CellularCapabilityUniversal::kConnectPreferredMode[] =
43 "preferred-mode";
44const char CellularCapabilityUniversal::kConnectApn[] = "apn";
45const char CellularCapabilityUniversal::kConnectIPType[] = "ip-type";
46const char CellularCapabilityUniversal::kConnectUser[] = "user";
47const char CellularCapabilityUniversal::kConnectPassword[] = "password";
48const char CellularCapabilityUniversal::kConnectNumber[] = "number";
49const char CellularCapabilityUniversal::kConnectAllowRoaming[] =
50 "allow-roaming";
51const char CellularCapabilityUniversal::kConnectRMProtocol[] = "rm-protocol";
Jason Glasgowcd0349c2012-05-03 23:32:15 -040052const char CellularCapabilityUniversal::kStatusProperty[] = "status";
53const char CellularCapabilityUniversal::kOperatorLongProperty[] =
54 "operator-long";
55const char CellularCapabilityUniversal::kOperatorShortProperty[] =
56 "operator-short";
57const char CellularCapabilityUniversal::kOperatorCodeProperty[] =
58 "operator-code";
59const char CellularCapabilityUniversal::kOperatorAccessTechnologyProperty[] =
60 "access-technology";
Jason Glasgow14521872012-05-07 19:12:15 -040061const char CellularCapabilityUniversal::kE362ModelId[] = "E362 WWAN";
62unsigned int CellularCapabilityUniversal::friendly_service_name_id_ = 0;
63
Jason Glasgow82f9ab32012-04-04 14:27:19 -040064
65static const char kPhoneNumber[] = "*99#";
66
67static string AccessTechnologyToString(uint32 access_technologies) {
68 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_LTE)
69 return flimflam::kNetworkTechnologyLte;
70 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
71 MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
72 MM_MODEM_ACCESS_TECHNOLOGY_EVDOB))
73 return flimflam::kNetworkTechnologyEvdo;
74 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_1XRTT)
75 return flimflam::kNetworkTechnology1Xrtt;
76 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS)
77 return flimflam::kNetworkTechnologyHspaPlus;
78 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
79 MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
80 MM_MODEM_ACCESS_TECHNOLOGY_HSDPA))
81 return flimflam::kNetworkTechnologyHspa;
82 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_UMTS)
83 return flimflam::kNetworkTechnologyUmts;
84 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_EDGE)
85 return flimflam::kNetworkTechnologyEdge;
86 if (access_technologies & MM_MODEM_ACCESS_TECHNOLOGY_GPRS)
87 return flimflam::kNetworkTechnologyGprs;
88 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
89 MM_MODEM_ACCESS_TECHNOLOGY_GSM))
90 return flimflam::kNetworkTechnologyGsm;
91 return "";
92}
93
Jason Glasgow9f09aef2012-05-08 16:26:55 -040094static string AccessTechnologyToTechnologyFamily(uint32 access_technologies) {
95 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_LTE |
96 MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS |
97 MM_MODEM_ACCESS_TECHNOLOGY_HSPA |
98 MM_MODEM_ACCESS_TECHNOLOGY_HSUPA |
99 MM_MODEM_ACCESS_TECHNOLOGY_HSDPA |
100 MM_MODEM_ACCESS_TECHNOLOGY_UMTS |
101 MM_MODEM_ACCESS_TECHNOLOGY_EDGE |
102 MM_MODEM_ACCESS_TECHNOLOGY_GPRS |
103 MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT |
104 MM_MODEM_ACCESS_TECHNOLOGY_GSM))
105 return flimflam::kTechnologyFamilyGsm;
106 if (access_technologies & (MM_MODEM_ACCESS_TECHNOLOGY_EVDO0 |
107 MM_MODEM_ACCESS_TECHNOLOGY_EVDOA |
108 MM_MODEM_ACCESS_TECHNOLOGY_EVDOB |
109 MM_MODEM_ACCESS_TECHNOLOGY_1XRTT))
110 return flimflam::kTechnologyFamilyCdma;
111 return "";
112}
113
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400114CellularCapabilityUniversal::CellularCapabilityUniversal(
115 Cellular *cellular,
116 ProxyFactory *proxy_factory)
117 : CellularCapability(cellular, proxy_factory),
118 weak_ptr_factory_(this),
119 registration_state_(MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN),
120 cdma_registration_state_(MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN),
Darin Petkove636c692012-05-31 10:22:17 +0200121 capabilities_(MM_MODEM_CAPABILITY_NONE),
122 current_capabilities_(MM_MODEM_CAPABILITY_NONE),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400123 access_technologies_(MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN),
Jason Glasgowaf583282012-04-18 15:18:22 -0400124 supported_modes_(MM_MODEM_MODE_NONE),
125 allowed_modes_(MM_MODEM_MODE_NONE),
126 preferred_mode_(MM_MODEM_MODE_NONE),
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400127 home_provider_(NULL),
128 scanning_supported_(true),
129 scanning_(false),
130 scan_interval_(0) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700131 SLOG(Cellular, 2) << "Cellular capability constructed: Universal";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400132 PropertyStore *store = cellular->mutable_store();
133
134 store->RegisterConstString(flimflam::kCarrierProperty, &carrier_);
135 store->RegisterConstBool(flimflam::kSupportNetworkScanProperty,
136 &scanning_supported_);
137 store->RegisterConstString(flimflam::kEsnProperty, &esn_);
138 store->RegisterConstString(flimflam::kFirmwareRevisionProperty,
139 &firmware_revision_);
140 store->RegisterConstString(flimflam::kHardwareRevisionProperty,
141 &hardware_revision_);
142 store->RegisterConstString(flimflam::kImeiProperty, &imei_);
143 store->RegisterConstString(flimflam::kImsiProperty, &imsi_);
Ben Chana5e27082012-07-31 14:30:28 -0700144 store->RegisterConstString(flimflam::kIccidProperty, &sim_identifier_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400145 store->RegisterConstString(flimflam::kManufacturerProperty, &manufacturer_);
146 store->RegisterConstString(flimflam::kMdnProperty, &mdn_);
147 store->RegisterConstString(flimflam::kMeidProperty, &meid_);
148 store->RegisterConstString(flimflam::kMinProperty, &min_);
149 store->RegisterConstString(flimflam::kModelIDProperty, &model_id_);
150 store->RegisterConstString(flimflam::kSelectedNetworkProperty,
151 &selected_network_);
152 store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
153 &found_networks_);
154 store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
155 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
156 HelpRegisterDerivedKeyValueStore(
157 flimflam::kSIMLockStatusProperty,
158 &CellularCapabilityUniversal::SimLockStatusToProperty,
159 NULL);
160 store->RegisterConstStringmaps(flimflam::kCellularApnListProperty,
161 &apn_list_);
162}
163
164KeyValueStore CellularCapabilityUniversal::SimLockStatusToProperty(
165 Error */*error*/) {
166 KeyValueStore status;
167 status.SetBool(flimflam::kSIMLockEnabledProperty, sim_lock_status_.enabled);
168 status.SetString(flimflam::kSIMLockTypeProperty, sim_lock_status_.lock_type);
169 status.SetUint(flimflam::kSIMLockRetriesLeftProperty,
170 sim_lock_status_.retries_left);
171 return status;
172}
173
174void CellularCapabilityUniversal::HelpRegisterDerivedKeyValueStore(
175 const string &name,
176 KeyValueStore(CellularCapabilityUniversal::*get)(Error *error),
177 void(CellularCapabilityUniversal::*set)(
178 const KeyValueStore &value, Error *error)) {
179 cellular()->mutable_store()->RegisterDerivedKeyValueStore(
180 name,
181 KeyValueStoreAccessor(
182 new CustomAccessor<CellularCapabilityUniversal, KeyValueStore>(
183 this, get, set)));
184}
185
186void CellularCapabilityUniversal::InitProxies() {
187 modem_3gpp_proxy_.reset(
188 proxy_factory()->CreateMM1ModemModem3gppProxy(cellular()->dbus_path(),
189 cellular()->dbus_owner()));
190 modem_cdma_proxy_.reset(
191 proxy_factory()->CreateMM1ModemModemCdmaProxy(cellular()->dbus_path(),
192 cellular()->dbus_owner()));
193 modem_proxy_.reset(
194 proxy_factory()->CreateMM1ModemProxy(cellular()->dbus_path(),
195 cellular()->dbus_owner()));
196 modem_simple_proxy_.reset(
197 proxy_factory()->CreateMM1ModemSimpleProxy(cellular()->dbus_path(),
198 cellular()->dbus_owner()));
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400199 modem_proxy_->set_state_changed_callback(
200 Bind(&CellularCapabilityUniversal::OnModemStateChangedSignal,
201 weak_ptr_factory_.GetWeakPtr()));
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400202 // Do not create a SIM proxy until the device is enabled because we
203 // do not yet know the object path of the sim object.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400204 // TODO(jglasgow): register callbacks
205}
206
207void CellularCapabilityUniversal::StartModem(Error *error,
Jason Glasgowef965562012-04-10 16:12:35 -0400208 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700209 SLOG(Cellular, 2) << __func__;
Jason Glasgowef965562012-04-10 16:12:35 -0400210
211 InitProxies();
212
213 // Start by trying to enable the modem
214 CHECK(!callback.is_null());
215 modem_proxy_->Enable(
216 true,
217 error,
218 Bind(&CellularCapabilityUniversal::Start_EnableModemCompleted,
219 weak_ptr_factory_.GetWeakPtr(), callback),
220 kTimeoutEnable);
221 if (error->IsFailure())
222 callback.Run(*error);
223}
224
225void CellularCapabilityUniversal::Start_EnableModemCompleted(
226 const ResultCallback &callback, const Error &error) {
Eric Shienbrood9b1bd7b2012-04-20 16:42:26 -0400227 SLOG(Cellular, 2) << __func__ << ": " << error;
Jason Glasgowef965562012-04-10 16:12:35 -0400228 if (error.IsFailure()) {
229 callback.Run(error);
230 return;
231 }
232
233 // After modem is enabled, it should be possible to get properties
234 // TODO(jglasgow): handle errors from GetProperties
235 GetProperties();
Jason Glasgow4380f0d2012-05-03 18:05:04 -0400236 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400237}
238
239void CellularCapabilityUniversal::StopModem(Error *error,
Jason Glasgow02401cc2012-05-16 10:35:37 -0400240 const ResultCallback &callback) {
Jason Glasgowef965562012-04-10 16:12:35 -0400241 CHECK(!callback.is_null());
242 CHECK(error);
Thieu Led0012052012-07-25 16:09:09 -0700243 Cellular::ModemState state = cellular()->modem_state();
244 SLOG(Cellular, 2) << __func__ << "(" << state << ")";
Jason Glasgowef965562012-04-10 16:12:35 -0400245
Thieu Led0012052012-07-25 16:09:09 -0700246 if (cellular()->IsModemRegistered()) {
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__;
Thieu Le5d6864a2012-07-20 11:43:51 -0700305 if (bearer_path_.empty()) {
306 LOG(WARNING) << "In " << __func__ << "(): "
307 << "Ignoring attempt to disconnect without bearer";
Thieu Le3d275392012-07-20 15:32:58 -0700308 } else if (modem_simple_proxy_.get()) {
Thieu Le5d6864a2012-07-20 11:43:51 -0700309 modem_simple_proxy_->Disconnect(bearer_path_,
310 error,
311 callback,
312 kTimeoutDefault);
313 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400314}
315
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400316void CellularCapabilityUniversal::Activate(const string &carrier,
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400317 Error *error,
318 const ResultCallback &callback) {
319 OnUnsupportedOperation(__func__, error);
320}
321
322void CellularCapabilityUniversal::ReleaseProxies() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700323 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400324 modem_3gpp_proxy_.reset();
325 modem_cdma_proxy_.reset();
326 modem_proxy_.reset();
327 modem_simple_proxy_.reset();
328 sim_proxy_.reset();
329}
330
331void CellularCapabilityUniversal::OnServiceCreated() {
332 // If IMSI is available, base the service's storage identifier on it.
333 if (!imsi_.empty()) {
334 cellular()->service()->SetStorageIdentifier(
335 string(flimflam::kTypeCellular) + "_" +
336 cellular()->address() + "_" + imsi_);
337 }
338 cellular()->service()->SetActivationState(
339 flimflam::kActivationStateActivated);
340 UpdateServingOperator();
341}
342
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400343// Create the list of APNs to try, in the following order:
344// - last APN that resulted in a successful connection attempt on the
345// current network (if any)
346// - the APN, if any, that was set by the user
347// - the list of APNs found in the mobile broadband provider DB for the
348// home provider associated with the current SIM
349// - as a last resort, attempt to connect with no APN
350void CellularCapabilityUniversal::SetupApnTryList() {
351 apn_try_list_.clear();
352
353 DCHECK(cellular()->service().get());
354 const Stringmap *apn_info = cellular()->service()->GetLastGoodApn();
355 if (apn_info)
356 apn_try_list_.push_back(*apn_info);
357
358 apn_info = cellular()->service()->GetUserSpecifiedApn();
359 if (apn_info)
360 apn_try_list_.push_back(*apn_info);
361
362 apn_try_list_.insert(apn_try_list_.end(), apn_list_.begin(), apn_list_.end());
363}
364
365void CellularCapabilityUniversal::SetupConnectProperties(
366 DBusPropertiesMap *properties) {
367 SetupApnTryList();
368 FillConnectPropertyMap(properties);
369}
370
371void CellularCapabilityUniversal::FillConnectPropertyMap(
372 DBusPropertiesMap *properties) {
373
374 // TODO(jglasgow): Is this really needed anymore?
Jason Glasgow14521872012-05-07 19:12:15 -0400375 (*properties)[kConnectNumber].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400376 kPhoneNumber);
377
Jason Glasgow14521872012-05-07 19:12:15 -0400378 (*properties)[kConnectAllowRoaming].writer().append_bool(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400379 AllowRoaming());
380
381 if (!apn_try_list_.empty()) {
382 // Leave the APN at the front of the list, so that it can be recorded
383 // if the connect attempt succeeds.
384 Stringmap apn_info = apn_try_list_.front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700385 SLOG(Cellular, 2) << __func__ << ": Using APN "
386 << apn_info[flimflam::kApnProperty];
Jason Glasgow14521872012-05-07 19:12:15 -0400387 (*properties)[kConnectApn].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400388 apn_info[flimflam::kApnProperty].c_str());
389 if (ContainsKey(apn_info, flimflam::kApnUsernameProperty))
Jason Glasgow14521872012-05-07 19:12:15 -0400390 (*properties)[kConnectUser].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400391 apn_info[flimflam::kApnUsernameProperty].c_str());
392 if (ContainsKey(apn_info, flimflam::kApnPasswordProperty))
Jason Glasgow14521872012-05-07 19:12:15 -0400393 (*properties)[kConnectPassword].writer().append_string(
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400394 apn_info[flimflam::kApnPasswordProperty].c_str());
395 }
396}
397
398void CellularCapabilityUniversal::OnConnectReply(const ResultCallback &callback,
Nathan Williamsb54974f2012-04-19 11:16:30 -0400399 const DBus::Path &path,
400 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700401 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Nathan Williamsb54974f2012-04-19 11:16:30 -0400402
Jason Glasgow7234ec32012-05-23 16:01:21 -0400403 CellularServiceRefPtr service = cellular()->service();
404 if (!service) {
405 // The service could have been deleted before our Connect() request
406 // completes if the modem was enabled and then quickly disabled.
407 apn_try_list_.clear();
408 } else if (error.IsFailure()) {
409 service->ClearLastGoodApn();
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400410 // The APN that was just tried (and failed) is still at the
411 // front of the list, about to be removed. If the list is empty
412 // after that, try one last time without an APN. This may succeed
413 // with some modems in some cases.
Jason Glasgow14521872012-05-07 19:12:15 -0400414 if (RetriableConnectError(error) && !apn_try_list_.empty()) {
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400415 apn_try_list_.pop_front();
Ben Chanfad4a0b2012-04-18 15:49:59 -0700416 SLOG(Cellular, 2) << "Connect failed with invalid APN, "
417 << apn_try_list_.size() << " remaining APNs to try";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400418 DBusPropertiesMap props;
419 FillConnectPropertyMap(&props);
420 Error error;
421 Connect(props, &error, callback);
422 return;
423 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400424 } else {
425 if (!apn_try_list_.empty()) {
Jason Glasgow7234ec32012-05-23 16:01:21 -0400426 service->SetLastGoodApn(apn_try_list_.front());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400427 apn_try_list_.clear();
428 }
Nathan Williamsb54974f2012-04-19 11:16:30 -0400429 bearer_path_ = path;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400430 }
431
432 if (!callback.is_null())
433 callback.Run(error);
434}
435
436bool CellularCapabilityUniversal::AllowRoaming() {
437 bool requires_roaming =
438 home_provider_ ? home_provider_->requires_roaming : false;
439 return requires_roaming || allow_roaming_property();
440}
441
Jason Glasgowef965562012-04-10 16:12:35 -0400442void CellularCapabilityUniversal::GetProperties() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700443 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400444
Jason Glasgowaf583282012-04-18 15:18:22 -0400445 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
446 proxy_factory()->CreateDBusPropertiesProxy(cellular()->dbus_path(),
447 cellular()->dbus_owner()));
448 DBusPropertiesMap properties(
449 properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM));
450 OnModemPropertiesChanged(properties, vector<string>());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400451
Jason Glasgowaf583282012-04-18 15:18:22 -0400452 properties = properties_proxy->GetAll(MM_DBUS_INTERFACE_MODEM_MODEM3GPP);
453 OnModem3GPPPropertiesChanged(properties, vector<string>());
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400454}
455
456string CellularCapabilityUniversal::CreateFriendlyServiceName() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700457 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400458 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME &&
459 !cellular()->home_provider().GetName().empty()) {
460 return cellular()->home_provider().GetName();
461 }
462 if (!serving_operator_.GetName().empty()) {
463 return serving_operator_.GetName();
464 }
465 if (!carrier_.empty()) {
466 return carrier_;
467 }
468 if (!serving_operator_.GetCode().empty()) {
469 return "cellular_" + serving_operator_.GetCode();
470 }
471 return base::StringPrintf("GSMNetwork%u", friendly_service_name_id_++);
472}
473
474void CellularCapabilityUniversal::SetHomeProvider() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700475 SLOG(Cellular, 2) << __func__ << "(IMSI: " << imsi_
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400476 << " SPN: " << spn_ << ")";
477 // TODO(petkov): The test for NULL provider_db should be done by
478 // mobile_provider_lookup_best_match.
479 if (imsi_.empty() || !cellular()->provider_db()) {
480 return;
481 }
482 mobile_provider *provider =
483 mobile_provider_lookup_best_match(
484 cellular()->provider_db(), spn_.c_str(), imsi_.c_str());
485 if (!provider) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700486 SLOG(Cellular, 2) << "GSM provider not found.";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400487 return;
488 }
Jason Glasgow4380f0d2012-05-03 18:05:04 -0400489
490 // Even if provider is the same as home_provider_, it is possible
491 // that the spn_ has changed. Run all the code below.
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400492 home_provider_ = provider;
Jason Glasgow4380f0d2012-05-03 18:05:04 -0400493
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400494 Cellular::Operator oper;
495 if (provider->networks) {
496 oper.SetCode(provider->networks[0]);
497 }
498 if (provider->country) {
499 oper.SetCountry(provider->country);
500 }
501 if (spn_.empty()) {
502 const char *name = mobile_provider_get_name(provider);
503 if (name) {
504 oper.SetName(name);
505 }
506 } else {
507 oper.SetName(spn_);
508 }
509 cellular()->set_home_provider(oper);
510 InitAPNList();
511}
512
513void CellularCapabilityUniversal::UpdateOperatorInfo() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700514 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400515 const string &network_id = serving_operator_.GetCode();
516 if (!network_id.empty()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700517 SLOG(Cellular, 2) << "Looking up network id: " << network_id;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400518 mobile_provider *provider =
519 mobile_provider_lookup_by_network(cellular()->provider_db(),
520 network_id.c_str());
521 if (provider) {
522 const char *provider_name = mobile_provider_get_name(provider);
523 if (provider_name && *provider_name) {
524 serving_operator_.SetName(provider_name);
525 if (provider->country) {
526 serving_operator_.SetCountry(provider->country);
527 }
Ben Chanfad4a0b2012-04-18 15:49:59 -0700528 SLOG(Cellular, 2) << "Operator name: " << serving_operator_.GetName()
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400529 << ", country: " << serving_operator_.GetCountry();
530 }
531 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700532 SLOG(Cellular, 2) << "GSM provider not found.";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400533 }
534 }
535 UpdateServingOperator();
536}
537
538void CellularCapabilityUniversal::UpdateServingOperator() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700539 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400540 if (cellular()->service().get()) {
541 cellular()->service()->SetServingOperator(serving_operator_);
542 }
543}
544
545void CellularCapabilityUniversal::InitAPNList() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700546 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400547 if (!home_provider_) {
548 return;
549 }
550 apn_list_.clear();
551 for (int i = 0; i < home_provider_->num_apns; ++i) {
552 Stringmap props;
553 mobile_apn *apn = home_provider_->apns[i];
554 if (apn->value) {
555 props[flimflam::kApnProperty] = apn->value;
556 }
557 if (apn->username) {
558 props[flimflam::kApnUsernameProperty] = apn->username;
559 }
560 if (apn->password) {
561 props[flimflam::kApnPasswordProperty] = apn->password;
562 }
563 // Find the first localized and non-localized name, if any.
564 const localized_name *lname = NULL;
565 const localized_name *name = NULL;
566 for (int j = 0; j < apn->num_names; ++j) {
567 if (apn->names[j]->lang) {
568 if (!lname) {
569 lname = apn->names[j];
570 }
571 } else if (!name) {
572 name = apn->names[j];
573 }
574 }
575 if (name) {
576 props[flimflam::kApnNameProperty] = name->name;
577 }
578 if (lname) {
579 props[flimflam::kApnLocalizedNameProperty] = lname->name;
580 props[flimflam::kApnLanguageProperty] = lname->lang;
581 }
582 apn_list_.push_back(props);
583 }
584 cellular()->adaptor()->EmitStringmapsChanged(
585 flimflam::kCellularApnListProperty, apn_list_);
586}
587
588// always called from an async context
589void CellularCapabilityUniversal::Register(const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700590 SLOG(Cellular, 2) << __func__ << " \"" << selected_network_ << "\"";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400591 CHECK(!callback.is_null());
592 Error error;
593 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
594 weak_ptr_factory_.GetWeakPtr(), callback);
595 modem_3gpp_proxy_->Register(selected_network_, &error, cb, kTimeoutRegister);
596 if (error.IsFailure())
597 callback.Run(error);
598}
599
600void CellularCapabilityUniversal::RegisterOnNetwork(
601 const string &network_id,
602 Error *error,
603 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700604 SLOG(Cellular, 2) << __func__ << "(" << network_id << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400605 CHECK(error);
606 desired_network_ = network_id;
607 ResultCallback cb = Bind(&CellularCapabilityUniversal::OnRegisterReply,
608 weak_ptr_factory_.GetWeakPtr(), callback);
609 modem_3gpp_proxy_->Register(network_id, error, cb, kTimeoutRegister);
610}
611
612void CellularCapabilityUniversal::OnRegisterReply(
613 const ResultCallback &callback,
614 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700615 SLOG(Cellular, 2) << __func__ << "(" << error << ")";
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400616
617 if (error.IsSuccess()) {
618 selected_network_ = desired_network_;
619 desired_network_.clear();
620 callback.Run(error);
621 return;
622 }
623 // If registration on the desired network failed,
624 // try to register on the home network.
625 if (!desired_network_.empty()) {
626 desired_network_.clear();
627 selected_network_.clear();
628 LOG(INFO) << "Couldn't register on selected network, trying home network";
629 Register(callback);
630 return;
631 }
632 callback.Run(error);
633}
634
635bool CellularCapabilityUniversal::IsRegistered() {
636 return (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
637 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING);
638}
639
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400640void CellularCapabilityUniversal::SetUnregistered(bool searching) {
641 // If we're already in some non-registered state, don't override that
642 if (registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_HOME ||
643 registration_state_ == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) {
644 registration_state_ =
645 (searching ? MM_MODEM_3GPP_REGISTRATION_STATE_SEARCHING :
646 MM_MODEM_3GPP_REGISTRATION_STATE_IDLE);
647 }
648}
649
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400650void CellularCapabilityUniversal::RequirePIN(
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400651 const string &pin, bool require,
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400652 Error *error, const ResultCallback &callback) {
653 CHECK(error);
654 sim_proxy_->EnablePin(pin, require, error, callback, kTimeoutDefault);
655}
656
657void CellularCapabilityUniversal::EnterPIN(const string &pin,
658 Error *error,
659 const ResultCallback &callback) {
660 CHECK(error);
661 sim_proxy_->SendPin(pin, error, callback, kTimeoutDefault);
662}
663
664void CellularCapabilityUniversal::UnblockPIN(const string &unblock_code,
665 const string &pin,
666 Error *error,
667 const ResultCallback &callback) {
668 CHECK(error);
669 sim_proxy_->SendPuk(unblock_code, pin, error, callback, kTimeoutDefault);
670}
671
672void CellularCapabilityUniversal::ChangePIN(
673 const string &old_pin, const string &new_pin,
674 Error *error, const ResultCallback &callback) {
675 CHECK(error);
676 sim_proxy_->ChangePin(old_pin, new_pin, error, callback, kTimeoutDefault);
677}
678
679void CellularCapabilityUniversal::Scan(Error *error,
680 const ResultCallback &callback) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700681 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400682 CHECK(error);
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400683 if (scanning_) {
684 Error::PopulateAndLog(error, Error::kInProgress, "Already scanning");
685 return;
686 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400687 DBusPropertyMapsCallback cb = Bind(&CellularCapabilityUniversal::OnScanReply,
688 weak_ptr_factory_.GetWeakPtr(), callback);
689 modem_3gpp_proxy_->Scan(error, cb, kTimeoutScan);
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400690 if (!error->IsFailure()) {
691 scanning_ = true;
692 cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty,
693 scanning_);
694 }
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400695}
696
697void CellularCapabilityUniversal::OnScanReply(const ResultCallback &callback,
698 const ScanResults &results,
699 const Error &error) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700700 SLOG(Cellular, 2) << __func__;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400701
702 // Error handling is weak. The current expectation is that on any
703 // error, found_networks_ should be cleared and a property change
704 // notification sent out.
705 //
706 // TODO(jglasgow): fix error handling
Jason Glasgowcd0349c2012-05-03 23:32:15 -0400707 scanning_ = false;
708 cellular()->adaptor()->EmitBoolChanged(flimflam::kScanningProperty,
709 scanning_);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400710 found_networks_.clear();
711 if (!error.IsFailure()) {
712 for (ScanResults::const_iterator it = results.begin();
713 it != results.end(); ++it) {
714 found_networks_.push_back(ParseScanResult(*it));
715 }
716 }
717 cellular()->adaptor()->EmitStringmapsChanged(flimflam::kFoundNetworksProperty,
718 found_networks_);
Gary Morainceba6aa2012-05-03 10:28:26 -0700719
720 // TODO(gmorain): This check for is_null() is a work-around because
721 // Cellular::Scan() passes a null callback. Instead: 1. Have Cellular::Scan()
722 // pass in a callback. 2. Have Cellular "own" the found_networks_ property
723 // 3. Have Cellular EmitStingMapsChanged() 4. Share the code between GSM and
724 // Universal.
725 if (!callback.is_null())
726 callback.Run(error);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400727}
728
729Stringmap CellularCapabilityUniversal::ParseScanResult(
730 const ScanResult &result) {
731
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400732 /* ScanResults contain the following keys:
733
734 "status"
735 A MMModem3gppNetworkAvailability value representing network
736 availability status, given as an unsigned integer (signature "u").
737 This key will always be present.
738
739 "operator-long"
740 Long-format name of operator, given as a string value (signature
741 "s"). If the name is unknown, this field should not be present.
742
743 "operator-short"
744 Short-format name of operator, given as a string value
745 (signature "s"). If the name is unknown, this field should not
746 be present.
747
748 "operator-code"
749 Mobile code of the operator, given as a string value (signature
750 "s"). Returned in the format "MCCMNC", where MCC is the
751 three-digit ITU E.212 Mobile Country Code and MNC is the two- or
752 three-digit GSM Mobile Network Code. e.g. "31026" or "310260".
753
754 "access-technology"
755 A MMModemAccessTechnology value representing the generic access
756 technology used by this mobile network, given as an unsigned
757 integer (signature "u").
758 */
759 Stringmap parsed;
760
761 uint32 status;
762 if (DBusProperties::GetUint32(result, kStatusProperty, &status)) {
763 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
764 static const char * const kStatusString[] = {
765 "unknown", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_UNKNOWN
766 "available", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_AVAILABLE
767 "current", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_CURRENT
768 "forbidden", // MM_MODEM_3GPP_NETWORK_AVAILABILITY_FORBIDDEN
769 };
770 parsed[flimflam::kStatusProperty] = kStatusString[status];
771 }
772
773 uint32 tech; // MMModemAccessTechnology
774 if (DBusProperties::GetUint32(result, kOperatorAccessTechnologyProperty,
775 &tech)) {
776 parsed[flimflam::kTechnologyProperty] = AccessTechnologyToString(tech);
777 }
778
779 string operator_long, operator_short, operator_code;
780 if (DBusProperties::GetString(result, kOperatorLongProperty, &operator_long))
781 parsed[flimflam::kLongNameProperty] = operator_long;
782 if (DBusProperties::GetString(result, kOperatorShortProperty,
783 &operator_short))
784 parsed[flimflam::kShortNameProperty] = operator_short;
785 if (DBusProperties::GetString(result, kOperatorCodeProperty, &operator_code))
786 parsed[flimflam::kNetworkIdProperty] = operator_code;
787
788 // If the long name is not available but the network ID is, look up the long
789 // name in the mobile provider database.
790 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
791 parsed[flimflam::kLongNameProperty].empty()) &&
792 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
793 mobile_provider *provider =
794 mobile_provider_lookup_by_network(
795 cellular()->provider_db(),
796 parsed[flimflam::kNetworkIdProperty].c_str());
797 if (provider) {
798 const char *long_name = mobile_provider_get_name(provider);
799 if (long_name && *long_name) {
800 parsed[flimflam::kLongNameProperty] = long_name;
801 }
802 }
803 }
804 return parsed;
805}
806
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400807string CellularCapabilityUniversal::GetNetworkTechnologyString() const {
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400808 // Order is important. Return the highest speed technology
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400809 // TODO(jglasgow): change shill interfaces to a capability model
810
811 return AccessTechnologyToString(access_technologies_);
812}
813
814string CellularCapabilityUniversal::GetRoamingStateString() const {
815 switch (registration_state_) {
816 case MM_MODEM_3GPP_REGISTRATION_STATE_HOME:
817 return flimflam::kRoamingStateHome;
818 case MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING:
819 return flimflam::kRoamingStateRoaming;
820 default:
821 break;
822 }
823 return flimflam::kRoamingStateUnknown;
824}
825
826void CellularCapabilityUniversal::GetSignalQuality() {
Nathan Williams218cbcd2012-04-17 16:48:44 -0400827 // TODO(njw): Switch to asynchronous calls (crosbug.com/17583).
828 const DBus::Struct<unsigned int, bool> quality =
829 modem_proxy_->SignalQuality();
830 OnSignalQualityChanged(quality._1);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400831}
832
Jason Glasgow9f09aef2012-05-08 16:26:55 -0400833string CellularCapabilityUniversal::GetTypeString() const {
834 return AccessTechnologyToTechnologyFamily(access_technologies_);
835}
836
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400837void CellularCapabilityUniversal::OnModemPropertiesChanged(
838 const DBusPropertiesMap &properties,
839 const vector<string> &/* invalidated_properties */) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400840 // This solves a bootstrapping problem: If the modem is not yet
841 // enabled, there are no proxy objects associated with the capability
842 // object, so modem signals like StateChanged aren't seen. By monitoring
843 // changes to the State property via the ModemManager, we're able to
844 // get the initialization process started, which will result in the
845 // creation of the proxy objects.
846 //
847 // The first time we see the change to State (when the modem state
848 // is Unknown), we simply update the state, and rely on the Manager to
849 // enable the device when it is registered with the Manager. On subsequent
850 // changes to State, we need to explicitly enable the device ourselves.
851 int32 istate;
Jason Glasgowaf583282012-04-18 15:18:22 -0400852 if (DBusProperties::GetInt32(properties, MM_MODEM_PROPERTY_STATE, &istate)) {
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400853 Cellular::ModemState state = static_cast<Cellular::ModemState>(istate);
Jason Glasgowaf583282012-04-18 15:18:22 -0400854 OnModemStateChanged(state);
Eric Shienbrood7fce52c2012-04-13 19:11:02 -0400855 }
Jason Glasgowaf583282012-04-18 15:18:22 -0400856 string string_value;
Nathan Williamse9840802012-04-18 18:47:40 -0400857 if (DBusProperties::GetObjectPath(properties,
Jason Glasgowaf583282012-04-18 15:18:22 -0400858 MM_MODEM_PROPERTY_SIM, &string_value))
859 OnSimPathChanged(string_value);
860 uint32 uint_value;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400861 if (DBusProperties::GetUint32(properties,
Jason Glasgowaf583282012-04-18 15:18:22 -0400862 MM_MODEM_PROPERTY_MODEMCAPABILITIES,
863 &uint_value))
864 OnModemCapabilitesChanged(uint_value);
865 if (DBusProperties::GetUint32(properties,
866 MM_MODEM_PROPERTY_CURRENTCAPABILITIES,
867 &uint_value))
868 OnModemCurrentCapabilitiesChanged(uint_value);
869 // not needed: MM_MODEM_PROPERTY_MAXBEARERS
870 // not needed: MM_MODEM_PROPERTY_MAXACTIVEBEARERS
871 if (DBusProperties::GetString(properties,
872 MM_MODEM_PROPERTY_MANUFACTURER,
873 &string_value))
874 OnModemManufacturerChanged(string_value);
875 if (DBusProperties::GetString(properties,
876 MM_MODEM_PROPERTY_MODEL,
877 &string_value))
878 OnModemModelChanged(string_value);
879 if (DBusProperties::GetString(properties,
880 MM_MODEM_PROPERTY_REVISION,
881 &string_value))
882 OnModemRevisionChanged(string_value);
883 // not needed: MM_MODEM_PROPERTY_DEVICEIDENTIFIER
884 // not needed: MM_MODEM_PROPERTY_DEVICE
885 // not needed: MM_MODEM_PROPERTY_DRIVER
886 // not needed: MM_MODEM_PROPERTY_PLUGIN
887 // not needed: MM_MODEM_PROPERTY_EQUIPMENTIDENTIFIER
Nathan Williams218cbcd2012-04-17 16:48:44 -0400888
Jason Glasgowaf583282012-04-18 15:18:22 -0400889 // Unlock required and SimLock
890 bool locks_changed = false;
891 uint32_t unlock_required; // This is really of type MMModemLock
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400892 if (DBusProperties::GetUint32(properties,
893 MM_MODEM_PROPERTY_UNLOCKREQUIRED,
Jason Glasgowaf583282012-04-18 15:18:22 -0400894 &unlock_required)) {
895 locks_changed = true;
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400896 }
Jason Glasgowaf583282012-04-18 15:18:22 -0400897 LockRetryData lock_retries;
898 DBusPropertiesMap::const_iterator it =
899 properties.find(MM_MODEM_PROPERTY_UNLOCKRETRIES);
900 if (it != properties.end()) {
901 lock_retries = it->second;
902 locks_changed = true;
903 }
904 if (locks_changed)
905 OnLockRetriesChanged(static_cast<MMModemLock>(unlock_required),
906 lock_retries);
907 if (DBusProperties::GetUint32(properties,
908 MM_MODEM_PROPERTY_ACCESSTECHNOLOGIES,
909 &uint_value))
910 OnAccessTechnologiesChanged(uint_value);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400911
Jason Glasgowaf583282012-04-18 15:18:22 -0400912 it = properties.find(MM_MODEM_PROPERTY_SIGNALQUALITY);
913 if (it != properties.end()) {
914 DBus::Struct<unsigned int, bool> quality = it->second;
915 OnSignalQualityChanged(quality._1);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400916 }
Jason Glasgowaf583282012-04-18 15:18:22 -0400917 vector<string> numbers;
918 if (DBusProperties::GetStrings(properties, MM_MODEM_PROPERTY_OWNNUMBERS,
919 &numbers)) {
920 string mdn;
921 if (numbers.size() > 0)
922 mdn = numbers[0];
923 OnMdnChanged(mdn);
924 }
925 if (DBusProperties::GetUint32(properties, MM_MODEM_PROPERTY_SUPPORTEDMODES,
926 &uint_value))
927 OnSupportedModesChanged(uint_value);
928 if (DBusProperties::GetUint32(properties, MM_MODEM_PROPERTY_ALLOWEDMODES,
929 &uint_value))
930 OnAllowedModesChanged(uint_value);
931 if (DBusProperties::GetUint32(properties, MM_MODEM_PROPERTY_PREFERREDMODE,
932 &uint_value))
933 OnPreferredModeChanged(static_cast<MMModemMode>(uint_value));
934 // au: MM_MODEM_PROPERTY_SUPPORTEDBANDS,
935 // au: MM_MODEM_PROPERTY_BANDS
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400936}
937
938void CellularCapabilityUniversal::OnDBusPropertiesChanged(
939 const string &interface,
940 const DBusPropertiesMap &changed_properties,
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400941 const vector<string> &invalidated_properties) {
Jason Glasgow7234ec32012-05-23 16:01:21 -0400942 SLOG(Cellular, 2) << __func__ << "(" << interface << ")";
Jason Glasgowef965562012-04-10 16:12:35 -0400943 if (interface == MM_DBUS_INTERFACE_MODEM) {
Jason Glasgow4c0724a2012-04-17 15:47:40 -0400944 OnModemPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgowef965562012-04-10 16:12:35 -0400945 }
Jason Glasgowaf583282012-04-18 15:18:22 -0400946 if (interface == MM_DBUS_INTERFACE_MODEM_MODEM3GPP) {
947 OnModem3GPPPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400948 }
Jason Glasgowaf583282012-04-18 15:18:22 -0400949 if (interface == MM_DBUS_INTERFACE_SIM) {
950 OnSimPropertiesChanged(changed_properties, invalidated_properties);
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400951 }
952}
953
Jason Glasgow14521872012-05-07 19:12:15 -0400954bool CellularCapabilityUniversal::RetriableConnectError(
955 const Error &error) const {
956 if (error.type() == Error::kInvalidApn)
957 return true;
958
959 // modemmanager does not ever return kInvalidApn for E362 modems
960 // with 1.41 firmware. It remains to be seem if this will change
961 // with 3.x firmware.
962 if ((model_id_ == kE362ModelId) && (error.type() == Error::kOperationFailed))
963 return true;
964
965 return false;
966}
967
Jason Glasgow82f9ab32012-04-04 14:27:19 -0400968void CellularCapabilityUniversal::OnNetworkModeSignal(uint32 /*mode*/) {
969 // TODO(petkov): Implement this.
970 NOTIMPLEMENTED();
971}
972
Jason Glasgowaf583282012-04-18 15:18:22 -0400973void CellularCapabilityUniversal::OnSimPathChanged(
974 const string &sim_path) {
975 if (sim_path == sim_path_)
976 return;
977
978 mm1::SimProxyInterface *proxy = NULL;
979 if (!sim_path.empty())
980 proxy = proxy_factory()->CreateSimProxy(sim_path,
981 cellular()->dbus_owner());
982 sim_path_ = sim_path;
983 sim_proxy_.reset(proxy);
984
985 if (sim_path.empty()) {
986 // Clear all data about the sim
Jason Glasgow4380f0d2012-05-03 18:05:04 -0400987 imsi_ = "";
988 spn_ = "";
Jason Glasgowaf583282012-04-18 15:18:22 -0400989 OnSimIdentifierChanged("");
990 OnOperatorIdChanged("");
Jason Glasgowaf583282012-04-18 15:18:22 -0400991 } else {
992 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
993 proxy_factory()->CreateDBusPropertiesProxy(sim_path,
994 cellular()->dbus_owner()));
995 // TODO(jglasgow): convert to async interface
996 DBusPropertiesMap properties(
997 properties_proxy->GetAll(MM_DBUS_INTERFACE_SIM));
998 OnSimPropertiesChanged(properties, vector<string>());
999 }
1000}
1001
1002void CellularCapabilityUniversal::OnModemCapabilitesChanged(
1003 uint32 capabilities) {
1004 capabilities_ = capabilities;
1005}
1006
1007void CellularCapabilityUniversal::OnModemCurrentCapabilitiesChanged(
1008 uint32 current_capabilities) {
1009 current_capabilities_ = current_capabilities;
1010}
1011
1012void CellularCapabilityUniversal::OnMdnChanged(
1013 const string &mdn) {
1014 mdn_ = mdn;
1015}
1016
1017void CellularCapabilityUniversal::OnModemManufacturerChanged(
1018 const string &manufacturer) {
1019 manufacturer_ = manufacturer;
1020}
1021
1022void CellularCapabilityUniversal::OnModemModelChanged(
1023 const string &model) {
1024 model_id_ = model;
1025}
1026
1027void CellularCapabilityUniversal::OnModemRevisionChanged(
1028 const string &revision) {
1029 firmware_revision_ = revision;
1030}
1031
1032void CellularCapabilityUniversal::OnModemStateChanged(
1033 Cellular::ModemState state) {
1034 Cellular::ModemState prev_modem_state = cellular()->modem_state();
1035 bool was_enabled = cellular()->IsUnderlyingDeviceEnabled();
1036 if (Cellular::IsEnabledModemState(state))
1037 cellular()->set_modem_state(state);
1038 if (prev_modem_state != Cellular::kModemStateUnknown &&
1039 prev_modem_state != Cellular::kModemStateEnabling &&
1040 !was_enabled &&
1041 cellular()->state() == Cellular::kStateDisabled &&
1042 cellular()->IsUnderlyingDeviceEnabled()) {
1043 cellular()->SetEnabled(true);
1044 }
1045}
1046
1047void CellularCapabilityUniversal::OnAccessTechnologiesChanged(
1048 uint32 access_technologies) {
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001049 if (access_technologies_ != access_technologies) {
Jason Glasgowbad114b2012-05-21 15:24:16 -04001050 const string old_type_string(GetTypeString());
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001051 access_technologies_ = access_technologies;
Jason Glasgowbad114b2012-05-21 15:24:16 -04001052 const string new_type_string(GetTypeString());
1053 if (new_type_string != old_type_string) {
1054 // TODO(jglasgow): address layering violation of emitting change
1055 // signal here for a property owned by Cellular.
1056 cellular()->adaptor()->EmitStringChanged(
1057 flimflam::kTechnologyFamilyProperty, new_type_string);
1058 }
Jason Glasgow9f09aef2012-05-08 16:26:55 -04001059 if (cellular()->service().get()) {
1060 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
1061 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001062 }
1063}
1064
1065void CellularCapabilityUniversal::OnSupportedModesChanged(
1066 uint32 supported_modes) {
1067 supported_modes_ = supported_modes;
1068}
1069
1070void CellularCapabilityUniversal::OnAllowedModesChanged(
1071 uint32 allowed_modes) {
1072 allowed_modes_ = allowed_modes;
1073}
1074
1075void CellularCapabilityUniversal::OnPreferredModeChanged(
1076 MMModemMode preferred_mode) {
1077 preferred_mode_ = preferred_mode;
1078}
1079
1080void CellularCapabilityUniversal::OnLockRetriesChanged(
1081 MMModemLock unlock_required,
1082 const LockRetryData &lock_retries) {
Jason Glasgowd4af81d2012-05-03 22:25:05 -04001083 switch (unlock_required) {
Jason Glasgowaf583282012-04-18 15:18:22 -04001084 case MM_MODEM_LOCK_SIM_PIN:
1085 sim_lock_status_.lock_type = "sim-pin";
1086 break;
1087 case MM_MODEM_LOCK_SIM_PUK:
1088 sim_lock_status_.lock_type = "sim-puk";
1089 break;
1090 default:
1091 sim_lock_status_.lock_type = "";
1092 break;
1093 }
1094 LockRetryData::const_iterator it = lock_retries.find(unlock_required);
1095 if (it != lock_retries.end()) {
1096 sim_lock_status_.retries_left = it->second;
1097 } else {
1098 // Unknown, use 999
1099 sim_lock_status_.retries_left = 999;
1100 }
1101 OnSimLockStatusChanged();
1102}
1103
1104void CellularCapabilityUniversal::OnSimLockStatusChanged() {
1105 cellular()->adaptor()->EmitKeyValueStoreChanged(
1106 flimflam::kSIMLockStatusProperty, SimLockStatusToProperty(NULL));
1107}
1108
1109void CellularCapabilityUniversal::OnModem3GPPPropertiesChanged(
1110 const DBusPropertiesMap &properties,
1111 const vector<string> &/* invalidated_properties */) {
1112 VLOG(2) << __func__;
1113 string imei;
1114 if (DBusProperties::GetString(properties,
1115 MM_MODEM_MODEM3GPP_PROPERTY_IMEI,
1116 &imei))
1117 OnImeiChanged(imei);
1118
1119 // Handle registration state changes as a single change
1120 string operator_code = serving_operator_.GetCode();
1121 string operator_name = serving_operator_.GetName();
1122 MMModem3gppRegistrationState state = registration_state_;
1123 bool registration_changed = false;
1124 uint32 uint_value;
1125 if (DBusProperties::GetUint32(properties,
1126 MM_MODEM_MODEM3GPP_PROPERTY_REGISTRATIONSTATE,
1127 &uint_value)) {
1128 state = static_cast<MMModem3gppRegistrationState>(uint_value);
1129 registration_changed = true;
1130 }
1131 if (DBusProperties::GetString(properties,
1132 MM_MODEM_MODEM3GPP_PROPERTY_OPERATORCODE,
1133 &operator_code))
1134 registration_changed = true;
1135 if (DBusProperties::GetString(properties,
1136 MM_MODEM_MODEM3GPP_PROPERTY_OPERATORNAME,
1137 &operator_name))
1138 registration_changed = true;
1139 if (registration_changed)
1140 On3GPPRegistrationChanged(state, operator_code, operator_name);
1141
1142 uint32 locks = 0;
1143 if (DBusProperties::GetUint32(
1144 properties, MM_MODEM_MODEM3GPP_PROPERTY_ENABLEDFACILITYLOCKS,
1145 &locks))
1146 OnFacilityLocksChanged(locks);
1147}
1148
1149void CellularCapabilityUniversal::OnImeiChanged(const string &imei) {
1150 imei_ = imei;
1151}
1152
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001153void CellularCapabilityUniversal::On3GPPRegistrationChanged(
1154 MMModem3gppRegistrationState state,
1155 const string &operator_code,
1156 const string &operator_name) {
Ben Chanfad4a0b2012-04-18 15:49:59 -07001157 SLOG(Cellular, 2) << __func__ << ": regstate=" << state
1158 << ", opercode=" << operator_code
1159 << ", opername=" << operator_name;
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001160 registration_state_ = state;
1161 serving_operator_.SetCode(operator_code);
1162 serving_operator_.SetName(operator_name);
1163 UpdateOperatorInfo();
1164 cellular()->HandleNewRegistrationState();
1165}
1166
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001167void CellularCapabilityUniversal::OnModemStateChangedSignal(
1168 int32 old_state, int32 new_state, uint32 reason) {
Eric Shienbrood9b1bd7b2012-04-20 16:42:26 -04001169 SLOG(Cellular, 2) << __func__ << "(" << old_state << ", " << new_state << ", "
1170 << reason << ")";
Eric Shienbrood7fce52c2012-04-13 19:11:02 -04001171 cellular()->OnModemStateChanged(static_cast<Cellular::ModemState>(old_state),
1172 static_cast<Cellular::ModemState>(new_state),
1173 reason);
1174}
1175
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001176void CellularCapabilityUniversal::OnSignalQualityChanged(uint32 quality) {
1177 cellular()->HandleNewSignalQuality(quality);
1178}
1179
Jason Glasgowaf583282012-04-18 15:18:22 -04001180void CellularCapabilityUniversal::OnFacilityLocksChanged(uint32 locks) {
1181 if (sim_lock_status_.enabled != (locks & MM_MODEM_3GPP_FACILITY_SIM)) {
1182 sim_lock_status_.enabled = locks & MM_MODEM_3GPP_FACILITY_SIM;
1183 OnSimLockStatusChanged();
1184 }
1185}
Jason Glasgowef965562012-04-10 16:12:35 -04001186
Jason Glasgowaf583282012-04-18 15:18:22 -04001187void CellularCapabilityUniversal::OnSimPropertiesChanged(
1188 const DBusPropertiesMap &props,
1189 const vector<string> &/* invalidated_properties */) {
1190 VLOG(2) << __func__;
1191 string value;
Jason Glasgow4380f0d2012-05-03 18:05:04 -04001192 bool must_update_home_provider = false;
Jason Glasgowaf583282012-04-18 15:18:22 -04001193 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_SIMIDENTIFIER, &value))
1194 OnSimIdentifierChanged(value);
1195 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORIDENTIFIER,
1196 &value))
1197 OnOperatorIdChanged(value);
Jason Glasgow4380f0d2012-05-03 18:05:04 -04001198 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_OPERATORNAME, &value)) {
1199 spn_ = value;
1200 must_update_home_provider = true;
1201 }
1202 if (DBusProperties::GetString(props, MM_SIM_PROPERTY_IMSI, &value)) {
1203 imsi_ = value;
1204 must_update_home_provider = true;
1205 }
Jason Glasgowaf583282012-04-18 15:18:22 -04001206 // TODO(jglasgow): May eventually want to get SPDI, etc
Jason Glasgowaf583282012-04-18 15:18:22 -04001207
Jason Glasgow4380f0d2012-05-03 18:05:04 -04001208 if (must_update_home_provider)
1209 SetHomeProvider();
Jason Glasgowaf583282012-04-18 15:18:22 -04001210}
1211
1212void CellularCapabilityUniversal::OnSimIdentifierChanged(const string &id) {
1213 sim_identifier_ = id;
1214}
1215
1216void CellularCapabilityUniversal::OnOperatorIdChanged(
1217 const string &operator_id) {
1218 operator_id_ = operator_id;
1219}
1220
Jason Glasgow82f9ab32012-04-04 14:27:19 -04001221} // namespace shill