blob: 51f80f3b0bfbc3516d3047ba8bab0dbd6fd26e8a [file] [log] [blame]
Darin Petkovc64fe5e2012-01-11 12:46:13 +01001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Darin Petkovdaf43862011-10-27 11:37:28 +02002// 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_gsm.h"
6
Eric Shienbrood3e20a232012-02-16 11:35:56 -05007#include <base/bind.h>
Darin Petkovdaf43862011-10-27 11:37:28 +02008#include <base/logging.h>
Eric Shienbrood3e20a232012-02-16 11:35:56 -05009#include <base/stl_util.h>
Darin Petkov1272a432011-11-10 15:53:37 +010010#include <base/string_number_conversions.h>
Darin Petkovac635a82012-01-10 16:51:58 +010011#include <base/stringprintf.h>
Darin Petkov20c13ec2011-11-09 15:07:15 +010012#include <chromeos/dbus/service_constants.h>
13#include <mm/mm-modem.h>
Darin Petkov1272a432011-11-10 15:53:37 +010014#include <mobile_provider.h>
Darin Petkovdaf43862011-10-27 11:37:28 +020015
Darin Petkov3cfbf212011-11-21 16:02:09 +010016#include "shill/adaptor_interfaces.h"
Darin Petkovae0c64e2011-11-15 15:50:27 +010017#include "shill/cellular_service.h"
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050018#include "shill/error.h"
Darin Petkov721ac932011-11-16 15:43:09 +010019#include "shill/property_accessor.h"
Darin Petkovdaf43862011-10-27 11:37:28 +020020#include "shill/proxy_factory.h"
21
Eric Shienbrood3e20a232012-02-16 11:35:56 -050022using base::Bind;
Darin Petkovb05315f2011-11-07 10:14:25 +010023using std::string;
24
Darin Petkovdaf43862011-10-27 11:37:28 +020025namespace shill {
26
Darin Petkovac635a82012-01-10 16:51:58 +010027// static
28unsigned int CellularCapabilityGSM::friendly_service_name_id_ = 0;
29
Darin Petkov1272a432011-11-10 15:53:37 +010030const char CellularCapabilityGSM::kNetworkPropertyAccessTechnology[] =
31 "access-tech";
32const char CellularCapabilityGSM::kNetworkPropertyID[] = "operator-num";
33const char CellularCapabilityGSM::kNetworkPropertyLongName[] = "operator-long";
34const char CellularCapabilityGSM::kNetworkPropertyShortName[] =
35 "operator-short";
36const char CellularCapabilityGSM::kNetworkPropertyStatus[] = "status";
Darin Petkovae0c64e2011-11-15 15:50:27 +010037const char CellularCapabilityGSM::kPhoneNumber[] = "*99#";
38const char CellularCapabilityGSM::kPropertyAccessTechnology[] =
39 "AccessTechnology";
Darin Petkov63138a92012-02-06 14:09:15 +010040const char CellularCapabilityGSM::kPropertyEnabledFacilityLocks[] =
41 "EnabledFacilityLocks";
Darin Petkov721ac932011-11-16 15:43:09 +010042const char CellularCapabilityGSM::kPropertyUnlockRequired[] = "UnlockRequired";
43const char CellularCapabilityGSM::kPropertyUnlockRetries[] = "UnlockRetries";
Darin Petkov1272a432011-11-10 15:53:37 +010044
Eric Shienbrood5de44ab2011-12-05 10:46:27 -050045CellularCapabilityGSM::CellularCapabilityGSM(Cellular *cellular,
46 ProxyFactory *proxy_factory)
47 : CellularCapability(cellular, proxy_factory),
Eric Shienbrood3e20a232012-02-16 11:35:56 -050048 weak_ptr_factory_(this),
Darin Petkov184c54e2011-11-15 12:44:39 +010049 registration_state_(MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN),
Darin Petkovae0c64e2011-11-15 15:50:27 +010050 access_technology_(MM_MODEM_GSM_ACCESS_TECH_UNKNOWN),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +010051 home_provider_(NULL),
Darin Petkov1272a432011-11-10 15:53:37 +010052 scanning_(false),
53 scan_interval_(0) {
Darin Petkov5f316f62011-11-18 12:10:26 +010054 VLOG(2) << "Cellular capability constructed: GSM";
Darin Petkov1272a432011-11-10 15:53:37 +010055 PropertyStore *store = cellular->mutable_store();
Darin Petkov184c54e2011-11-15 12:44:39 +010056 store->RegisterConstString(flimflam::kSelectedNetworkProperty,
57 &selected_network_);
Darin Petkov1272a432011-11-10 15:53:37 +010058 store->RegisterConstStringmaps(flimflam::kFoundNetworksProperty,
59 &found_networks_);
60 store->RegisterConstBool(flimflam::kScanningProperty, &scanning_);
61 store->RegisterUint16(flimflam::kScanIntervalProperty, &scan_interval_);
Darin Petkov63138a92012-02-06 14:09:15 +010062 HelpRegisterDerivedKeyValueStore(
63 flimflam::kSIMLockStatusProperty,
64 &CellularCapabilityGSM::SimLockStatusToProperty,
65 NULL);
Darin Petkov3cfbf212011-11-21 16:02:09 +010066 store->RegisterConstStringmaps(flimflam::kCellularApnListProperty,
67 &apn_list_);
Darin Petkov0d06f7d2012-02-03 13:08:19 +010068 scanning_supported_ = true;
Darin Petkov1272a432011-11-10 15:53:37 +010069}
Darin Petkovdaf43862011-10-27 11:37:28 +020070
Darin Petkov63138a92012-02-06 14:09:15 +010071KeyValueStore CellularCapabilityGSM::SimLockStatusToProperty(Error */*error*/) {
72 KeyValueStore status;
73 status.SetBool(flimflam::kSIMLockEnabledProperty, sim_lock_status_.enabled);
74 status.SetString(flimflam::kSIMLockTypeProperty, sim_lock_status_.lock_type);
75 status.SetUint(flimflam::kSIMLockRetriesLeftProperty,
76 sim_lock_status_.retries_left);
77 return status;
Darin Petkov721ac932011-11-16 15:43:09 +010078}
79
Darin Petkov63138a92012-02-06 14:09:15 +010080void CellularCapabilityGSM::HelpRegisterDerivedKeyValueStore(
Darin Petkov721ac932011-11-16 15:43:09 +010081 const string &name,
Darin Petkov63138a92012-02-06 14:09:15 +010082 KeyValueStore(CellularCapabilityGSM::*get)(Error *error),
83 void(CellularCapabilityGSM::*set)(
84 const KeyValueStore &value, Error *error)) {
85 cellular()->mutable_store()->RegisterDerivedKeyValueStore(
Darin Petkov721ac932011-11-16 15:43:09 +010086 name,
Darin Petkov63138a92012-02-06 14:09:15 +010087 KeyValueStoreAccessor(
88 new CustomAccessor<CellularCapabilityGSM, KeyValueStore>(
Darin Petkov721ac932011-11-16 15:43:09 +010089 this, get, set)));
90}
91
Eric Shienbrood9a245532012-03-07 14:20:39 -050092void CellularCapabilityGSM::InitProxies() {
93 CellularCapability::InitProxies();
Darin Petkovcb547732011-11-09 13:55:26 +010094 card_proxy_.reset(
Eric Shienbrood9a245532012-03-07 14:20:39 -050095 proxy_factory()->CreateModemGSMCardProxy(cellular()->dbus_path(),
Darin Petkovdaf43862011-10-27 11:37:28 +020096 cellular()->dbus_owner()));
Darin Petkov184c54e2011-11-15 12:44:39 +010097 network_proxy_.reset(
Eric Shienbrood9a245532012-03-07 14:20:39 -050098 proxy_factory()->CreateModemGSMNetworkProxy(cellular()->dbus_path(),
Darin Petkovdaf43862011-10-27 11:37:28 +020099 cellular()->dbus_owner()));
Eric Shienbrood9a245532012-03-07 14:20:39 -0500100 network_proxy_->set_signal_quality_callback(
101 Bind(&CellularCapabilityGSM::OnSignalQualitySignal,
102 weak_ptr_factory_.GetWeakPtr()));
103 network_proxy_->set_network_mode_callback(
104 Bind(&CellularCapabilityGSM::OnNetworkModeSignal,
105 weak_ptr_factory_.GetWeakPtr()));
106 network_proxy_->set_registration_info_callback(
107 Bind(&CellularCapabilityGSM::OnRegistrationInfoSignal,
108 weak_ptr_factory_.GetWeakPtr()));
Darin Petkovdaf43862011-10-27 11:37:28 +0200109}
110
Eric Shienbrood9a245532012-03-07 14:20:39 -0500111void CellularCapabilityGSM::StartModem(Error *error,
112 const ResultCallback &callback) {
113 InitProxies();
114
115 CellularTaskList *tasks = new CellularTaskList();
116 ResultCallback cb =
117 Bind(&CellularCapabilityGSM::StepCompletedCallback,
118 weak_ptr_factory_.GetWeakPtr(), callback, tasks);
119 tasks->push_back(Bind(&CellularCapabilityGSM::EnableModem,
120 weak_ptr_factory_.GetWeakPtr(), cb));
121 tasks->push_back(Bind(&CellularCapabilityGSM::Register,
122 weak_ptr_factory_.GetWeakPtr(), cb));
123 tasks->push_back(Bind(&CellularCapabilityGSM::GetModemStatus,
124 weak_ptr_factory_.GetWeakPtr(), cb));
125 tasks->push_back(Bind(&CellularCapabilityGSM::GetIMEI,
126 weak_ptr_factory_.GetWeakPtr(), cb));
127 tasks->push_back(Bind(&CellularCapabilityGSM::GetIMSI,
128 weak_ptr_factory_.GetWeakPtr(), cb));
129 tasks->push_back(Bind(&CellularCapabilityGSM::GetSPN,
130 weak_ptr_factory_.GetWeakPtr(), cb));
131 tasks->push_back(Bind(&CellularCapabilityGSM::GetMSISDN,
132 weak_ptr_factory_.GetWeakPtr(), cb));
133 tasks->push_back(Bind(&CellularCapabilityGSM::GetProperties,
134 weak_ptr_factory_.GetWeakPtr(), cb));
135 tasks->push_back(Bind(&CellularCapabilityGSM::GetModemInfo,
136 weak_ptr_factory_.GetWeakPtr(), cb));
137 tasks->push_back(Bind(&CellularCapabilityGSM::FinishEnable,
138 weak_ptr_factory_.GetWeakPtr(), cb));
139
140 RunNextStep(tasks);
141}
142
143void CellularCapabilityGSM::StopModem(Error *error,
144 const ResultCallback &callback) {
Darin Petkov721ac932011-11-16 15:43:09 +0100145 VLOG(2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500146
147 CellularTaskList *tasks = new CellularTaskList();
148 ResultCallback cb =
149 Bind(&CellularCapabilityGSM::StepCompletedCallback,
150 weak_ptr_factory_.GetWeakPtr(), callback, tasks);
151 tasks->push_back(Bind(&CellularCapabilityGSM::Disconnect,
152 weak_ptr_factory_.GetWeakPtr(),
153 static_cast<Error *>(NULL), cb));
154 tasks->push_back(Bind(&CellularCapabilityGSM::DisableModem,
155 weak_ptr_factory_.GetWeakPtr(), cb));
156 tasks->push_back(Bind(&CellularCapabilityGSM::FinishDisable,
157 weak_ptr_factory_.GetWeakPtr(), cb));
158
159 RunNextStep(tasks);
160}
161
162void CellularCapabilityGSM::ReleaseProxies() {
163 VLOG(2) << __func__;
164 CellularCapability::ReleaseProxies();
Darin Petkov721ac932011-11-16 15:43:09 +0100165 card_proxy_.reset();
166 network_proxy_.reset();
167}
168
Darin Petkov5f316f62011-11-18 12:10:26 +0100169void CellularCapabilityGSM::OnServiceCreated() {
Darin Petkov31332412012-01-28 01:50:02 +0100170 // If IMSI is available, base the service's storage identifier on it.
171 if (!imsi_.empty()) {
172 cellular()->service()->SetStorageIdentifier(
Darin Petkovdd3e8662012-02-03 13:16:20 +0100173 string(flimflam::kTypeCellular) + "_" +
174 cellular()->address() + "_" + imsi_);
Darin Petkov31332412012-01-28 01:50:02 +0100175 }
Darin Petkovb9c99332012-01-12 13:13:00 +0100176 cellular()->service()->SetActivationState(
Darin Petkov5f316f62011-11-18 12:10:26 +0100177 flimflam::kActivationStateActivated);
178 UpdateServingOperator();
179}
180
Darin Petkovae0c64e2011-11-15 15:50:27 +0100181void CellularCapabilityGSM::UpdateStatus(const DBusPropertiesMap &properties) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500182 if (ContainsKey(properties, kPropertyIMSI)) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100183 SetHomeProvider();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100184 }
185}
186
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400187// Create the list of APNs to try, in the following order:
188// - last APN that resulted in a successful connection attempt on the
189// current network (if any)
190// - the APN, if any, that was set by the user
191// - the list of APNs found in the mobile broadband provider DB for the
192// home provider associated with the current SIM
193// - as a last resort, attempt to connect with no APN
194void CellularCapabilityGSM::SetupApnTryList() {
195 apn_try_list_.clear();
196
197 DCHECK(cellular()->service().get());
198 const Stringmap *apn_info = cellular()->service()->GetLastGoodApn();
199 if (apn_info)
200 apn_try_list_.push_back(*apn_info);
201
202 apn_info = cellular()->service()->GetUserSpecifiedApn();
203 if (apn_info)
204 apn_try_list_.push_back(*apn_info);
205
206 apn_try_list_.insert(apn_try_list_.end(), apn_list_.begin(), apn_list_.end());
207}
208
Darin Petkovae0c64e2011-11-15 15:50:27 +0100209void CellularCapabilityGSM::SetupConnectProperties(
210 DBusPropertiesMap *properties) {
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400211 SetupApnTryList();
212 FillConnectPropertyMap(properties);
213}
214
215void CellularCapabilityGSM::FillConnectPropertyMap(
216 DBusPropertiesMap *properties) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500217 (*properties)[kConnectPropertyPhoneNumber].writer().append_string(
Darin Petkovae0c64e2011-11-15 15:50:27 +0100218 kPhoneNumber);
Eric Shienbrood30bc0ec2012-03-21 18:19:46 -0400219
220 if (!allow_roaming_)
221 (*properties)[kConnectPropertyHomeOnly].writer().append_bool(true);
222
223 if (!apn_try_list_.empty()) {
224 // Leave the APN at the front of the list, so that it can be recorded
225 // if the connect attempt succeeds.
226 Stringmap apn_info = apn_try_list_.front();
227 VLOG(2) << __func__ << ": Using APN " << apn_info[flimflam::kApnProperty];
228 (*properties)[kConnectPropertyApn].writer().append_string(
229 apn_info[flimflam::kApnProperty].c_str());
230 if (ContainsKey(apn_info, flimflam::kApnUsernameProperty))
231 (*properties)[kConnectPropertyApnUsername].writer().append_string(
232 apn_info[flimflam::kApnUsernameProperty].c_str());
233 if (ContainsKey(apn_info, flimflam::kApnPasswordProperty))
234 (*properties)[kConnectPropertyApnPassword].writer().append_string(
235 apn_info[flimflam::kApnPasswordProperty].c_str());
236 }
237}
238
239void CellularCapabilityGSM::OnConnectReply(const ResultCallback &callback,
240 const Error &error) {
241 if (error.IsFailure()) {
242 cellular()->service()->ClearLastGoodApn();
243 // The APN that was just tried (and failed) is still at the
244 // front of the list, about to be removed. If the list is empty
245 // after that, try one last time without an APN. This may succeed
246 // with some modems in some cases.
247 if (error.type() == Error::kInvalidApn && !apn_try_list_.empty()) {
248 apn_try_list_.pop_front();
249 VLOG(2) << "Connect failed with invalid APN, " << apn_try_list_.size()
250 << " remaining APNs to try";
251 DBusPropertiesMap props;
252 FillConnectPropertyMap(&props);
253 Error error;
254 Connect(props, &error, callback);
255 return;
256 }
257 } else if (!apn_try_list_.empty()) {
258 cellular()->service()->SetLastGoodApn(apn_try_list_.front());
259 apn_try_list_.clear();
260 }
261 CellularCapability::OnConnectReply(callback, error);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100262}
263
Eric Shienbrood9a245532012-03-07 14:20:39 -0500264// always called from an async context
265void CellularCapabilityGSM::GetIMEI(const ResultCallback &callback) {
Darin Petkovcb547732011-11-09 13:55:26 +0100266 VLOG(2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500267 CHECK(!callback.is_null());
268 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500269 if (imei_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500270 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetIMEIReply,
271 weak_ptr_factory_.GetWeakPtr(), callback);
272 card_proxy_->GetIMEI(&error, cb, kTimeoutDefault);
273 if (error.IsFailure())
274 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500275 } else {
276 VLOG(2) << "Already have IMEI " << imei_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500277 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100278 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500279}
280
Eric Shienbrood9a245532012-03-07 14:20:39 -0500281// always called from an async context
282void CellularCapabilityGSM::GetIMSI(const ResultCallback &callback) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500283 VLOG(2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500284 CHECK(!callback.is_null());
285 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500286 if (imsi_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500287 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetIMSIReply,
288 weak_ptr_factory_.GetWeakPtr(),
289 callback);
290 card_proxy_->GetIMSI(&error, cb, kTimeoutDefault);
291 if (error.IsFailure())
292 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500293 } else {
294 VLOG(2) << "Already have IMSI " << imsi_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500295 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100296 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500297}
298
Eric Shienbrood9a245532012-03-07 14:20:39 -0500299// always called from an async context
300void CellularCapabilityGSM::GetSPN(const ResultCallback &callback) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500301 VLOG(2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500302 CHECK(!callback.is_null());
303 Error error;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100304 if (spn_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500305 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetSPNReply,
306 weak_ptr_factory_.GetWeakPtr(),
307 callback);
308 card_proxy_->GetSPN(&error, cb, kTimeoutDefault);
309 if (error.IsFailure())
310 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500311 } else {
312 VLOG(2) << "Already have SPN " << spn_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500313 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100314 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500315}
316
Eric Shienbrood9a245532012-03-07 14:20:39 -0500317// always called from an async context
318void CellularCapabilityGSM::GetMSISDN(const ResultCallback &callback) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500319 VLOG(2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500320 CHECK(!callback.is_null());
321 Error error;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500322 if (mdn_.empty()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500323 GSMIdentifierCallback cb = Bind(&CellularCapabilityGSM::OnGetMSISDNReply,
324 weak_ptr_factory_.GetWeakPtr(),
325 callback);
326 card_proxy_->GetMSISDN(&error, cb, kTimeoutDefault);
327 if (error.IsFailure())
328 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500329 } else {
330 VLOG(2) << "Already have MSISDN " << mdn_;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500331 callback.Run(error);
Darin Petkovcb547732011-11-09 13:55:26 +0100332 }
333}
334
Darin Petkov3e509242011-11-10 14:46:44 +0100335void CellularCapabilityGSM::GetSignalQuality() {
336 VLOG(2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500337 SignalQualityCallback callback =
338 Bind(&CellularCapabilityGSM::OnGetSignalQualityReply,
339 weak_ptr_factory_.GetWeakPtr());
340 network_proxy_->GetSignalQuality(NULL, callback, kTimeoutDefault);
Darin Petkov3e509242011-11-10 14:46:44 +0100341}
342
Eric Shienbrood9a245532012-03-07 14:20:39 -0500343void CellularCapabilityGSM::GetRegistrationState() {
Darin Petkov184c54e2011-11-15 12:44:39 +0100344 VLOG(2) << __func__;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500345 RegistrationInfoCallback callback =
346 Bind(&CellularCapabilityGSM::OnGetRegistrationInfoReply,
347 weak_ptr_factory_.GetWeakPtr());
348 network_proxy_->GetRegistrationInfo(NULL, callback, kTimeoutDefault);
Darin Petkov184c54e2011-11-15 12:44:39 +0100349}
350
Eric Shienbrood9a245532012-03-07 14:20:39 -0500351void CellularCapabilityGSM::GetProperties(const ResultCallback &callback) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100352 VLOG(2) << __func__;
Darin Petkov63138a92012-02-06 14:09:15 +0100353
Darin Petkov184c54e2011-11-15 12:44:39 +0100354 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
355 uint32 tech = network_proxy_->AccessTechnology();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100356 SetAccessTechnology(tech);
Darin Petkov184c54e2011-11-15 12:44:39 +0100357 VLOG(2) << "GSM AccessTechnology: " << tech;
Darin Petkov63138a92012-02-06 14:09:15 +0100358
359 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
360 uint32 locks = card_proxy_->EnabledFacilityLocks();
361 sim_lock_status_.enabled = locks & MM_MODEM_GSM_FACILITY_SIM;
362 VLOG(2) << "GSM EnabledFacilityLocks: " << locks;
363
Eric Shienbrood9a245532012-03-07 14:20:39 -0500364 callback.Run(Error());
Darin Petkov184c54e2011-11-15 12:44:39 +0100365}
366
Darin Petkovac635a82012-01-10 16:51:58 +0100367string CellularCapabilityGSM::CreateFriendlyServiceName() {
368 VLOG(2) << __func__;
369 if (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME &&
370 !cellular()->home_provider().GetName().empty()) {
371 return cellular()->home_provider().GetName();
372 }
373 if (!serving_operator_.GetName().empty()) {
374 return serving_operator_.GetName();
375 }
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500376 if (!carrier_.empty()) {
377 return carrier_;
Darin Petkovac635a82012-01-10 16:51:58 +0100378 }
379 if (!serving_operator_.GetCode().empty()) {
380 return "cellular_" + serving_operator_.GetCode();
381 }
382 return base::StringPrintf("GSMNetwork%u", friendly_service_name_id_++);
383}
384
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100385void CellularCapabilityGSM::SetHomeProvider() {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500386 VLOG(2) << __func__ << "(IMSI: " << imsi_
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100387 << " SPN: " << spn_ << ")";
388 // TODO(petkov): The test for NULL provider_db should be done by
389 // mobile_provider_lookup_best_match.
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500390 if (imsi_.empty() || !cellular()->provider_db()) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100391 return;
392 }
393 mobile_provider *provider =
394 mobile_provider_lookup_best_match(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500395 cellular()->provider_db(), spn_.c_str(), imsi_.c_str());
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100396 if (!provider) {
397 VLOG(2) << "GSM provider not found.";
398 return;
399 }
400 home_provider_ = provider;
401 Cellular::Operator oper;
402 if (provider->networks) {
403 oper.SetCode(provider->networks[0]);
404 }
405 if (provider->country) {
406 oper.SetCountry(provider->country);
407 }
408 if (spn_.empty()) {
409 const char *name = mobile_provider_get_name(provider);
410 if (name) {
411 oper.SetName(name);
412 }
413 } else {
414 oper.SetName(spn_);
415 }
416 cellular()->set_home_provider(oper);
Darin Petkov3cfbf212011-11-21 16:02:09 +0100417 InitAPNList();
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100418}
419
Darin Petkovae0c64e2011-11-15 15:50:27 +0100420void CellularCapabilityGSM::UpdateOperatorInfo() {
421 VLOG(2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100422 const string &network_id = serving_operator_.GetCode();
423 if (!network_id.empty()) {
424 VLOG(2) << "Looking up network id: " << network_id;
Darin Petkovae0c64e2011-11-15 15:50:27 +0100425 mobile_provider *provider =
426 mobile_provider_lookup_by_network(cellular()->provider_db(),
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100427 network_id.c_str());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100428 if (provider) {
429 const char *provider_name = mobile_provider_get_name(provider);
430 if (provider_name && *provider_name) {
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100431 serving_operator_.SetName(provider_name);
432 if (provider->country) {
433 serving_operator_.SetCountry(provider->country);
434 }
435 VLOG(2) << "Operator name: " << serving_operator_.GetName()
436 << ", country: " << serving_operator_.GetCountry();
Darin Petkovae0c64e2011-11-15 15:50:27 +0100437 }
438 } else {
439 VLOG(2) << "GSM provider not found.";
440 }
441 }
442 UpdateServingOperator();
443}
444
445void CellularCapabilityGSM::UpdateServingOperator() {
446 VLOG(2) << __func__;
Darin Petkov0a4dfeb2011-11-18 19:36:13 +0100447 if (cellular()->service().get()) {
Darin Petkov9cb02682012-01-28 00:17:38 +0100448 cellular()->service()->SetServingOperator(serving_operator_);
Darin Petkovae0c64e2011-11-15 15:50:27 +0100449 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100450}
451
Darin Petkov3cfbf212011-11-21 16:02:09 +0100452void CellularCapabilityGSM::InitAPNList() {
453 VLOG(2) << __func__;
454 if (!home_provider_) {
455 return;
456 }
457 apn_list_.clear();
458 for (int i = 0; i < home_provider_->num_apns; ++i) {
459 Stringmap props;
460 mobile_apn *apn = home_provider_->apns[i];
461 if (apn->value) {
462 props[flimflam::kApnProperty] = apn->value;
463 }
464 if (apn->username) {
465 props[flimflam::kApnUsernameProperty] = apn->username;
466 }
467 if (apn->password) {
468 props[flimflam::kApnPasswordProperty] = apn->password;
469 }
470 // Find the first localized and non-localized name, if any.
471 const localized_name *lname = NULL;
472 const localized_name *name = NULL;
473 for (int j = 0; j < apn->num_names; ++j) {
474 if (apn->names[j]->lang) {
475 if (!lname) {
476 lname = apn->names[j];
477 }
478 } else if (!name) {
479 name = apn->names[j];
480 }
481 }
482 if (name) {
483 props[flimflam::kApnNameProperty] = name->name;
484 }
485 if (lname) {
486 props[flimflam::kApnLocalizedNameProperty] = lname->name;
487 props[flimflam::kApnLanguageProperty] = lname->lang;
488 }
489 apn_list_.push_back(props);
490 }
491 cellular()->adaptor()->EmitStringmapsChanged(
492 flimflam::kCellularApnListProperty, apn_list_);
493}
494
Eric Shienbrood9a245532012-03-07 14:20:39 -0500495// always called from an async context
496void CellularCapabilityGSM::Register(const ResultCallback &callback) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500497 VLOG(2) << __func__ << " \"" << selected_network_ << "\"";
Eric Shienbrood9a245532012-03-07 14:20:39 -0500498 CHECK(!callback.is_null());
499 Error error;
500 ResultCallback cb = Bind(&CellularCapabilityGSM::OnRegisterReply,
501 weak_ptr_factory_.GetWeakPtr(), callback);
502 network_proxy_->Register(selected_network_, &error, cb, kTimeoutRegister);
503 if (error.IsFailure())
504 callback.Run(error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100505}
506
507void CellularCapabilityGSM::RegisterOnNetwork(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500508 const string &network_id,
509 Error *error,
510 const ResultCallback &callback) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500511 VLOG(2) << __func__ << "(" << network_id << ")";
Eric Shienbrood9a245532012-03-07 14:20:39 -0500512 CHECK(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500513 desired_network_ = network_id;
Eric Shienbrood9a245532012-03-07 14:20:39 -0500514 ResultCallback cb = Bind(&CellularCapabilityGSM::OnRegisterReply,
515 weak_ptr_factory_.GetWeakPtr(), callback);
516 network_proxy_->Register(network_id, error, cb, kTimeoutRegister);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500517}
518
Eric Shienbrood9a245532012-03-07 14:20:39 -0500519void CellularCapabilityGSM::OnRegisterReply(const ResultCallback &callback,
520 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500521 VLOG(2) << __func__ << "(" << error << ")";
522
523 if (error.IsSuccess()) {
524 selected_network_ = desired_network_;
525 desired_network_.clear();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500526 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500527 return;
528 }
529 // If registration on the desired network failed,
530 // try to register on the home network.
531 if (!desired_network_.empty()) {
532 desired_network_.clear();
533 selected_network_.clear();
Eric Shienbrood9a245532012-03-07 14:20:39 -0500534 LOG(INFO) << "Couldn't register on selected network, trying home network";
535 Register(callback);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500536 return;
537 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500538 callback.Run(error);
Darin Petkov184c54e2011-11-15 12:44:39 +0100539}
540
Darin Petkovb72cf402011-11-22 14:51:39 +0100541bool CellularCapabilityGSM::IsRegistered() {
542 return (registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_HOME ||
543 registration_state_ == MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING);
544}
545
Darin Petkovb05315f2011-11-07 10:14:25 +0100546void CellularCapabilityGSM::RequirePIN(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500547 const std::string &pin, bool require,
548 Error *error, const ResultCallback &callback) {
549 CHECK(error);
550 card_proxy_->EnablePIN(pin, require, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100551}
552
Darin Petkove5bc2cb2011-12-07 14:47:32 +0100553void CellularCapabilityGSM::EnterPIN(const string &pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500554 Error *error,
555 const ResultCallback &callback) {
556 CHECK(error);
557 card_proxy_->SendPIN(pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100558}
559
Darin Petkovc64fe5e2012-01-11 12:46:13 +0100560void CellularCapabilityGSM::UnblockPIN(const string &unblock_code,
561 const string &pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500562 Error *error,
563 const ResultCallback &callback) {
564 CHECK(error);
565 card_proxy_->SendPUK(unblock_code, pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100566}
567
568void CellularCapabilityGSM::ChangePIN(
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500569 const string &old_pin, const string &new_pin,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500570 Error *error, const ResultCallback &callback) {
571 CHECK(error);
572 card_proxy_->ChangePIN(old_pin, new_pin, error, callback, kTimeoutDefault);
Darin Petkovb05315f2011-11-07 10:14:25 +0100573}
574
Eric Shienbrood9a245532012-03-07 14:20:39 -0500575void CellularCapabilityGSM::Scan(Error *error, const ResultCallback &callback) {
Darin Petkov1272a432011-11-10 15:53:37 +0100576 VLOG(2) << __func__;
577 // TODO(petkov): Defer scan requests if a scan is in progress already.
Eric Shienbrood9a245532012-03-07 14:20:39 -0500578 CHECK(error);
579 ScanResultsCallback cb = Bind(&CellularCapabilityGSM::OnScanReply,
580 weak_ptr_factory_.GetWeakPtr(), callback);
581 network_proxy_->Scan(error, cb, kTimeoutScan);
Darin Petkov1272a432011-11-10 15:53:37 +0100582}
583
Eric Shienbrood9a245532012-03-07 14:20:39 -0500584void CellularCapabilityGSM::OnScanReply(const ResultCallback &callback,
585 const GSMScanResults &results,
586 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500587 VLOG(2) << __func__;
588 if (error.IsFailure()) {
Eric Shienbrood9a245532012-03-07 14:20:39 -0500589 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500590 return;
591 }
592 found_networks_.clear();
593 for (GSMScanResults::const_iterator it = results.begin();
594 it != results.end(); ++it) {
595 found_networks_.push_back(ParseScanResult(*it));
596 }
Darin Petkovb7828b02012-02-03 12:34:30 +0100597 cellular()->adaptor()->EmitStringmapsChanged(flimflam::kFoundNetworksProperty,
598 found_networks_);
Eric Shienbrood9a245532012-03-07 14:20:39 -0500599 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500600}
601
602Stringmap CellularCapabilityGSM::ParseScanResult(const GSMScanResult &result) {
Darin Petkov1272a432011-11-10 15:53:37 +0100603 Stringmap parsed;
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500604 for (GSMScanResult::const_iterator it = result.begin();
605 it != result.end(); ++it) {
Darin Petkov1272a432011-11-10 15:53:37 +0100606 // TODO(petkov): Define these in system_api/service_constants.h. The
607 // numerical values are taken from 3GPP TS 27.007 Section 7.3.
608 static const char * const kStatusString[] = {
609 "unknown",
610 "available",
611 "current",
612 "forbidden",
613 };
614 static const char * const kTechnologyString[] = {
615 flimflam::kNetworkTechnologyGsm,
616 "GSM Compact",
617 flimflam::kNetworkTechnologyUmts,
618 flimflam::kNetworkTechnologyEdge,
619 "HSDPA",
620 "HSUPA",
621 flimflam::kNetworkTechnologyHspa,
622 };
623 VLOG(2) << "Network property: " << it->first << " = " << it->second;
624 if (it->first == kNetworkPropertyStatus) {
625 int status = 0;
626 if (base::StringToInt(it->second, &status) &&
627 status >= 0 &&
628 status < static_cast<int>(arraysize(kStatusString))) {
629 parsed[flimflam::kStatusProperty] = kStatusString[status];
630 } else {
631 LOG(ERROR) << "Unexpected status value: " << it->second;
632 }
633 } else if (it->first == kNetworkPropertyID) {
634 parsed[flimflam::kNetworkIdProperty] = it->second;
635 } else if (it->first == kNetworkPropertyLongName) {
636 parsed[flimflam::kLongNameProperty] = it->second;
637 } else if (it->first == kNetworkPropertyShortName) {
638 parsed[flimflam::kShortNameProperty] = it->second;
639 } else if (it->first == kNetworkPropertyAccessTechnology) {
640 int tech = 0;
641 if (base::StringToInt(it->second, &tech) &&
642 tech >= 0 &&
643 tech < static_cast<int>(arraysize(kTechnologyString))) {
644 parsed[flimflam::kTechnologyProperty] = kTechnologyString[tech];
645 } else {
646 LOG(ERROR) << "Unexpected technology value: " << it->second;
647 }
648 } else {
649 LOG(WARNING) << "Unknown network property ignored: " << it->first;
650 }
651 }
652 // If the long name is not available but the network ID is, look up the long
653 // name in the mobile provider database.
654 if ((!ContainsKey(parsed, flimflam::kLongNameProperty) ||
655 parsed[flimflam::kLongNameProperty].empty()) &&
656 ContainsKey(parsed, flimflam::kNetworkIdProperty)) {
657 mobile_provider *provider =
658 mobile_provider_lookup_by_network(
659 cellular()->provider_db(),
660 parsed[flimflam::kNetworkIdProperty].c_str());
661 if (provider) {
662 const char *long_name = mobile_provider_get_name(provider);
663 if (long_name && *long_name) {
664 parsed[flimflam::kLongNameProperty] = long_name;
665 }
666 }
667 }
668 return parsed;
669}
670
Darin Petkovae0c64e2011-11-15 15:50:27 +0100671void CellularCapabilityGSM::SetAccessTechnology(uint32 access_technology) {
672 access_technology_ = access_technology;
673 if (cellular()->service().get()) {
Darin Petkovb72cf402011-11-22 14:51:39 +0100674 cellular()->service()->SetNetworkTechnology(GetNetworkTechnologyString());
Darin Petkovae0c64e2011-11-15 15:50:27 +0100675 }
676}
677
Darin Petkov20c13ec2011-11-09 15:07:15 +0100678string CellularCapabilityGSM::GetNetworkTechnologyString() const {
Darin Petkovb72cf402011-11-22 14:51:39 +0100679 switch (access_technology_) {
680 case MM_MODEM_GSM_ACCESS_TECH_GSM:
681 case MM_MODEM_GSM_ACCESS_TECH_GSM_COMPACT:
682 return flimflam::kNetworkTechnologyGsm;
683 case MM_MODEM_GSM_ACCESS_TECH_GPRS:
684 return flimflam::kNetworkTechnologyGprs;
685 case MM_MODEM_GSM_ACCESS_TECH_EDGE:
686 return flimflam::kNetworkTechnologyEdge;
687 case MM_MODEM_GSM_ACCESS_TECH_UMTS:
688 return flimflam::kNetworkTechnologyUmts;
689 case MM_MODEM_GSM_ACCESS_TECH_HSDPA:
690 case MM_MODEM_GSM_ACCESS_TECH_HSUPA:
691 case MM_MODEM_GSM_ACCESS_TECH_HSPA:
692 return flimflam::kNetworkTechnologyHspa;
693 case MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS:
694 return flimflam::kNetworkTechnologyHspaPlus;
695 default:
696 break;
Darin Petkov20c13ec2011-11-09 15:07:15 +0100697 }
698 return "";
699}
700
701string CellularCapabilityGSM::GetRoamingStateString() const {
Darin Petkov184c54e2011-11-15 12:44:39 +0100702 switch (registration_state_) {
Darin Petkov20c13ec2011-11-09 15:07:15 +0100703 case MM_MODEM_GSM_NETWORK_REG_STATUS_HOME:
704 return flimflam::kRoamingStateHome;
705 case MM_MODEM_GSM_NETWORK_REG_STATUS_ROAMING:
706 return flimflam::kRoamingStateRoaming;
707 default:
708 break;
709 }
710 return flimflam::kRoamingStateUnknown;
711}
712
Darin Petkovae0c64e2011-11-15 15:50:27 +0100713void CellularCapabilityGSM::OnModemManagerPropertiesChanged(
714 const DBusPropertiesMap &properties) {
715 uint32 access_technology = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
716 if (DBusProperties::GetUint32(properties,
717 kPropertyAccessTechnology,
718 &access_technology)) {
719 SetAccessTechnology(access_technology);
720 }
Darin Petkov63138a92012-02-06 14:09:15 +0100721 bool emit = false;
722 uint32 locks = 0;
723 if (DBusProperties::GetUint32(
724 properties, kPropertyEnabledFacilityLocks, &locks)) {
725 sim_lock_status_.enabled = locks & MM_MODEM_GSM_FACILITY_SIM;
726 emit = true;
727 }
728 if (DBusProperties::GetString(
729 properties, kPropertyUnlockRequired, &sim_lock_status_.lock_type)) {
730 emit = true;
731 }
732 if (DBusProperties::GetUint32(
733 properties, kPropertyUnlockRetries, &sim_lock_status_.retries_left)) {
734 emit = true;
735 }
736 if (emit) {
737 cellular()->adaptor()->EmitKeyValueStoreChanged(
738 flimflam::kSIMLockStatusProperty, SimLockStatusToProperty(NULL));
739 }
Darin Petkovae0c64e2011-11-15 15:50:27 +0100740}
741
Eric Shienbrood9a245532012-03-07 14:20:39 -0500742void CellularCapabilityGSM::OnNetworkModeSignal(uint32 /*mode*/) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100743 // TODO(petkov): Implement this.
744 NOTIMPLEMENTED();
745}
746
Eric Shienbrood9a245532012-03-07 14:20:39 -0500747void CellularCapabilityGSM::OnRegistrationInfoSignal(
748 uint32 status, const string &operator_code, const string &operator_name) {
749 VLOG(2) << __func__ << ": regstate=" << status
750 << ", opercode=" << operator_code
751 << ", opername=" << operator_name;
752 registration_state_ = status;
753 serving_operator_.SetCode(operator_code);
754 serving_operator_.SetName(operator_name);
755 UpdateOperatorInfo();
756 cellular()->HandleNewRegistrationState();
Darin Petkov184c54e2011-11-15 12:44:39 +0100757}
758
Eric Shienbrood9a245532012-03-07 14:20:39 -0500759void CellularCapabilityGSM::OnSignalQualitySignal(uint32 quality) {
Darin Petkov184c54e2011-11-15 12:44:39 +0100760 cellular()->HandleNewSignalQuality(quality);
761}
762
Eric Shienbrood9a245532012-03-07 14:20:39 -0500763void CellularCapabilityGSM::OnGetRegistrationInfoReply(
764 uint32 status, const string &operator_code, const string &operator_name,
765 const Error &error) {
766 if (error.IsSuccess())
767 OnRegistrationInfoSignal(status, operator_code, operator_name);
768}
769
770void CellularCapabilityGSM::OnGetSignalQualityReply(uint32 quality,
771 const Error &error) {
772 if (error.IsSuccess())
773 OnSignalQualitySignal(quality);
774}
775
776void CellularCapabilityGSM::OnGetIMEIReply(const ResultCallback &callback,
777 const string &imei,
778 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500779 if (error.IsSuccess()) {
780 VLOG(2) << "IMEI: " << imei;
781 imei_ = imei;
782 } else {
783 VLOG(2) << "GetIMEI failed - " << error;
784 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500785 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500786}
787
Eric Shienbrood9a245532012-03-07 14:20:39 -0500788void CellularCapabilityGSM::OnGetIMSIReply(const ResultCallback &callback,
789 const string &imsi,
790 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500791 if (error.IsSuccess()) {
792 VLOG(2) << "IMSI: " << imsi;
793 imsi_ = imsi;
794 SetHomeProvider();
795 } else {
796 VLOG(2) << "GetIMSI failed - " << error;
797 }
Eric Shienbrood9a245532012-03-07 14:20:39 -0500798 callback.Run(error);
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500799}
800
Eric Shienbrood9a245532012-03-07 14:20:39 -0500801void CellularCapabilityGSM::OnGetSPNReply(const ResultCallback &callback,
802 const string &spn,
803 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500804 if (error.IsSuccess()) {
805 VLOG(2) << "SPN: " << spn;
806 spn_ = spn;
807 SetHomeProvider();
808 } else {
809 VLOG(2) << "GetSPN failed - " << error;
810 }
811 // Ignore the error - it's not fatal.
Eric Shienbrood9a245532012-03-07 14:20:39 -0500812 callback.Run(Error());
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500813}
814
Eric Shienbrood9a245532012-03-07 14:20:39 -0500815void CellularCapabilityGSM::OnGetMSISDNReply(const ResultCallback &callback,
816 const string &msisdn,
817 const Error &error) {
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500818 if (error.IsSuccess()) {
819 VLOG(2) << "MSISDN: " << msisdn;
820 mdn_ = msisdn;
821 } else {
822 VLOG(2) << "GetMSISDN failed - " << error;
823 }
824 // Ignore the error - it's not fatal.
Eric Shienbrood9a245532012-03-07 14:20:39 -0500825 callback.Run(Error());
Eric Shienbrood5de44ab2011-12-05 10:46:27 -0500826}
827
Darin Petkovdaf43862011-10-27 11:37:28 +0200828} // namespace shill