1 // 2 // Copyright (C) 2012 The Android Open Source Project 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 #include "shill/cellular/cellular_capability_cdma.h" 18 19 #include <string> 20 #include <vector> 21 22 #include <base/bind.h> 23 #include <base/strings/stringprintf.h> 24 #include <base/strings/string_util.h> 25 #if defined(__ANDROID__) 26 #include <dbus/service_constants.h> 27 #else 28 #include <chromeos/dbus/service_constants.h> 29 #endif // __ANDROID__ 30 #include <mm/mm-modem.h> 31 32 #include "shill/cellular/cellular.h" 33 #include "shill/cellular/cellular_service.h" 34 #include "shill/control_interface.h" 35 #include "shill/logging.h" 36 37 using base::Bind; 38 using std::string; 39 using std::vector; 40 41 namespace shill { 42 43 namespace Logging { 44 static auto kModuleLogScope = ScopeLogger::kCellular; 45 static string ObjectID(CellularCapabilityCDMA* c) { 46 return c->cellular()->GetRpcIdentifier(); 47 } 48 } 49 50 // static 51 const char CellularCapabilityCDMA::kPhoneNumber[] = "#777"; 52 53 CellularCapabilityCDMA::CellularCapabilityCDMA( 54 Cellular* cellular, 55 ControlInterface* control_interface, 56 ModemInfo* modem_info) 57 : CellularCapabilityClassic(cellular, control_interface, modem_info), 58 weak_ptr_factory_(this), 59 activation_starting_(false), 60 activation_state_(MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED), 61 registration_state_evdo_(MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN), 62 registration_state_1x_(MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN) { 63 SLOG(this, 2) << "Cellular capability constructed: CDMA"; 64 } 65 66 CellularCapabilityCDMA::~CellularCapabilityCDMA() {} 67 68 void CellularCapabilityCDMA::InitProxies() { 69 CellularCapabilityClassic::InitProxies(); 70 proxy_.reset(control_interface()->CreateModemCDMAProxy( 71 cellular()->dbus_path(), cellular()->dbus_service())); 72 proxy_->set_signal_quality_callback( 73 Bind(&CellularCapabilityCDMA::OnSignalQualitySignal, 74 weak_ptr_factory_.GetWeakPtr())); 75 proxy_->set_activation_state_callback( 76 Bind(&CellularCapabilityCDMA::OnActivationStateChangedSignal, 77 weak_ptr_factory_.GetWeakPtr())); 78 proxy_->set_registration_state_callback( 79 Bind(&CellularCapabilityCDMA::OnRegistrationStateChangedSignal, 80 weak_ptr_factory_.GetWeakPtr())); 81 } 82 83 string CellularCapabilityCDMA::GetTypeString() const { 84 return kTechnologyFamilyCdma; 85 } 86 87 void CellularCapabilityCDMA::StartModem(Error* error, 88 const ResultCallback& callback) { 89 SLOG(this, 2) << __func__; 90 InitProxies(); 91 92 CellularTaskList* tasks = new CellularTaskList(); 93 ResultCallback cb = 94 Bind(&CellularCapabilityCDMA::StepCompletedCallback, 95 weak_ptr_factory_.GetWeakPtr(), callback, false, tasks); 96 if (!cellular()->IsUnderlyingDeviceEnabled()) 97 tasks->push_back(Bind(&CellularCapabilityCDMA::EnableModem, 98 weak_ptr_factory_.GetWeakPtr(), cb)); 99 tasks->push_back(Bind(&CellularCapabilityCDMA::GetModemStatus, 100 weak_ptr_factory_.GetWeakPtr(), cb)); 101 tasks->push_back(Bind(&CellularCapabilityCDMA::GetMEID, 102 weak_ptr_factory_.GetWeakPtr(), cb)); 103 tasks->push_back(Bind(&CellularCapabilityCDMA::GetModemInfo, 104 weak_ptr_factory_.GetWeakPtr(), cb)); 105 tasks->push_back(Bind(&CellularCapabilityCDMA::FinishEnable, 106 weak_ptr_factory_.GetWeakPtr(), cb)); 107 108 RunNextStep(tasks); 109 } 110 111 void CellularCapabilityCDMA::ReleaseProxies() { 112 CellularCapabilityClassic::ReleaseProxies(); 113 proxy_.reset(); 114 } 115 116 bool CellularCapabilityCDMA::AreProxiesInitialized() const { 117 return (CellularCapabilityClassic::AreProxiesInitialized() && proxy_.get()); 118 } 119 120 bool CellularCapabilityCDMA::AllowRoaming() { 121 return allow_roaming_property(); 122 } 123 124 125 void CellularCapabilityCDMA::OnServiceCreated() { 126 SLOG(this, 2) << __func__; 127 cellular()->service()->SetUsageURL(usage_url_); 128 cellular()->service()->SetActivationType( 129 CellularService::kActivationTypeOTASP); 130 HandleNewActivationState(MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR); 131 } 132 133 void CellularCapabilityCDMA::UpdateStatus(const KeyValueStore& properties) { 134 string carrier; 135 if (properties.ContainsUint("activation_state")) { 136 activation_state_ = properties.GetUint("activation_state"); 137 } 138 // TODO(petkov): For now, get the payment and usage URLs from ModemManager to 139 // match flimflam. In the future, get these from an alternative source (e.g., 140 // database, carrier-specific properties, etc.). 141 UpdateOnlinePortal(properties); 142 if (properties.ContainsUint("prl_version")) 143 cellular()->set_prl_version(properties.GetUint("prl_version")); 144 } 145 146 void CellularCapabilityCDMA::UpdateServiceOLP() { 147 SLOG(this, 3) << __func__; 148 // All OLP changes are routed up to the Home Provider. 149 if (!cellular()->home_provider_info()->IsMobileNetworkOperatorKnown()) { 150 return; 151 } 152 153 const vector<MobileOperatorInfo::OnlinePortal>& olp_list = 154 cellular()->home_provider_info()->olp_list(); 155 if (olp_list.empty()) { 156 return; 157 } 158 159 if (olp_list.size() > 1) { 160 SLOG(this, 1) << "Found multiple online portals. Choosing the first."; 161 } 162 cellular()->service()->SetOLP(olp_list[0].url, 163 olp_list[0].method, 164 olp_list[0].post_data); 165 } 166 167 void CellularCapabilityCDMA::SetupConnectProperties( 168 KeyValueStore* properties) { 169 properties->SetString(kConnectPropertyPhoneNumber, kPhoneNumber); 170 } 171 172 void CellularCapabilityCDMA::Activate(const string& carrier, 173 Error* error, 174 const ResultCallback& callback) { 175 SLOG(this, 2) << __func__ << "(" << carrier << ")"; 176 // We're going to trigger something which leads to an activation. 177 activation_starting_ = true; 178 if (cellular()->state() == Cellular::kStateEnabled || 179 cellular()->state() == Cellular::kStateRegistered) { 180 ActivationResultCallback activation_callback = 181 Bind(&CellularCapabilityCDMA::OnActivateReply, 182 weak_ptr_factory_.GetWeakPtr(), 183 callback); 184 proxy_->Activate(carrier, error, activation_callback, kTimeoutActivate); 185 } else if (cellular()->state() == Cellular::kStateConnected || 186 cellular()->state() == Cellular::kStateLinked) { 187 pending_activation_callback_ = callback; 188 pending_activation_carrier_ = carrier; 189 cellular()->Disconnect(error, __func__); 190 } else { 191 Error::PopulateAndLog(FROM_HERE, error, Error::kInvalidArguments, 192 "Unable to activate in " + 193 Cellular::GetStateString(cellular()->state())); 194 activation_starting_ = false; 195 } 196 } 197 198 void CellularCapabilityCDMA::HandleNewActivationState(uint32_t error) { 199 SLOG(this, 2) << __func__ << "(" << error << ")"; 200 if (!cellular()->service().get()) { 201 LOG(ERROR) << "In " << __func__ << "(): service is null."; 202 return; 203 } 204 cellular()->service()->SetActivationState( 205 GetActivationStateString(activation_state_)); 206 cellular()->service()->set_error(GetActivationErrorString(error)); 207 } 208 209 void CellularCapabilityCDMA::DisconnectCleanup() { 210 CellularCapabilityClassic::DisconnectCleanup(); 211 if (pending_activation_callback_.is_null()) { 212 return; 213 } 214 if (cellular()->state() == Cellular::kStateEnabled || 215 cellular()->state() == Cellular::kStateRegistered) { 216 Error ignored_error; 217 Activate(pending_activation_carrier_, 218 &ignored_error, 219 pending_activation_callback_); 220 } else { 221 Error error; 222 Error::PopulateAndLog( 223 FROM_HERE, 224 &error, 225 Error::kOperationFailed, 226 "Tried to disconnect before activating cellular service and failed"); 227 HandleNewActivationState(MM_MODEM_CDMA_ACTIVATION_ERROR_UNKNOWN); 228 activation_starting_ = false; 229 pending_activation_callback_.Run(error); 230 } 231 pending_activation_callback_.Reset(); 232 pending_activation_carrier_.clear(); 233 } 234 235 // static 236 string CellularCapabilityCDMA::GetActivationStateString(uint32_t state) { 237 switch (state) { 238 case MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATED: 239 return kActivationStateActivated; 240 case MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING: 241 return kActivationStateActivating; 242 case MM_MODEM_CDMA_ACTIVATION_STATE_NOT_ACTIVATED: 243 return kActivationStateNotActivated; 244 case MM_MODEM_CDMA_ACTIVATION_STATE_PARTIALLY_ACTIVATED: 245 return kActivationStatePartiallyActivated; 246 default: 247 return kActivationStateUnknown; 248 } 249 } 250 251 // static 252 string CellularCapabilityCDMA::GetActivationErrorString(uint32_t error) { 253 switch (error) { 254 case MM_MODEM_CDMA_ACTIVATION_ERROR_WRONG_RADIO_INTERFACE: 255 return kErrorNeedEvdo; 256 case MM_MODEM_CDMA_ACTIVATION_ERROR_ROAMING: 257 return kErrorNeedHomeNetwork; 258 case MM_MODEM_CDMA_ACTIVATION_ERROR_COULD_NOT_CONNECT: 259 case MM_MODEM_CDMA_ACTIVATION_ERROR_SECURITY_AUTHENTICATION_FAILED: 260 case MM_MODEM_CDMA_ACTIVATION_ERROR_PROVISIONING_FAILED: 261 return kErrorOtaspFailed; 262 case MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR: 263 return ""; 264 case MM_MODEM_CDMA_ACTIVATION_ERROR_NO_SIGNAL: 265 default: 266 return kErrorActivationFailed; 267 } 268 } 269 270 void CellularCapabilityCDMA::GetMEID(const ResultCallback& callback) { 271 SLOG(this, 2) << __func__; 272 if (cellular()->meid().empty()) { 273 // TODO(petkov): Switch to asynchronous calls (crbug.com/200687). 274 cellular()->set_meid(proxy_->MEID()); 275 SLOG(this, 2) << "MEID: " << cellular()->meid(); 276 } 277 callback.Run(Error()); 278 } 279 280 void CellularCapabilityCDMA::GetProperties(const ResultCallback& callback) { 281 SLOG(this, 2) << __func__; 282 // No properties. 283 callback.Run(Error()); 284 } 285 286 bool CellularCapabilityCDMA::IsActivating() const { 287 return activation_starting_ || 288 activation_state_ == MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING; 289 } 290 291 bool CellularCapabilityCDMA::IsRegistered() const { 292 return registration_state_evdo_ != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN || 293 registration_state_1x_ != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN; 294 } 295 296 void CellularCapabilityCDMA::SetUnregistered(bool searching) { 297 registration_state_evdo_ = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN; 298 registration_state_1x_ = MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN; 299 } 300 301 string CellularCapabilityCDMA::GetNetworkTechnologyString() const { 302 if (registration_state_evdo_ != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN) { 303 return kNetworkTechnologyEvdo; 304 } 305 if (registration_state_1x_ != MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN) { 306 return kNetworkTechnology1Xrtt; 307 } 308 return ""; 309 } 310 311 string CellularCapabilityCDMA::GetRoamingStateString() const { 312 uint32_t state = registration_state_evdo_; 313 if (state == MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN) { 314 state = registration_state_1x_; 315 } 316 switch (state) { 317 case MM_MODEM_CDMA_REGISTRATION_STATE_UNKNOWN: 318 case MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED: 319 break; 320 case MM_MODEM_CDMA_REGISTRATION_STATE_HOME: 321 return kRoamingStateHome; 322 case MM_MODEM_CDMA_REGISTRATION_STATE_ROAMING: 323 return kRoamingStateRoaming; 324 default: 325 NOTREACHED(); 326 } 327 return kRoamingStateUnknown; 328 } 329 330 void CellularCapabilityCDMA::GetSignalQuality() { 331 SLOG(this, 2) << __func__; 332 SignalQualityCallback callback = 333 Bind(&CellularCapabilityCDMA::OnGetSignalQualityReply, 334 weak_ptr_factory_.GetWeakPtr()); 335 proxy_->GetSignalQuality(nullptr, callback, kTimeoutDefault); 336 } 337 338 void CellularCapabilityCDMA::GetRegistrationState() { 339 SLOG(this, 2) << __func__; 340 RegistrationStateCallback callback = 341 Bind(&CellularCapabilityCDMA::OnGetRegistrationStateReply, 342 weak_ptr_factory_.GetWeakPtr()); 343 proxy_->GetRegistrationState(nullptr, callback, kTimeoutDefault); 344 } 345 346 void CellularCapabilityCDMA::OnActivateReply( 347 const ResultCallback& callback, uint32_t status, const Error& error) { 348 activation_starting_ = false; 349 if (error.IsSuccess()) { 350 if (status == MM_MODEM_CDMA_ACTIVATION_ERROR_NO_ERROR) { 351 activation_state_ = MM_MODEM_CDMA_ACTIVATION_STATE_ACTIVATING; 352 } else { 353 LOG(WARNING) << "Modem activation failed with status: " 354 << GetActivationErrorString(status) << " (" << status << ")"; 355 } 356 HandleNewActivationState(status); 357 } else { 358 LOG(ERROR) << "Activate() failed with error: " << error; 359 } 360 callback.Run(error); 361 } 362 363 void CellularCapabilityCDMA::OnGetRegistrationStateReply( 364 uint32_t state_1x, uint32_t state_evdo, const Error& error) { 365 SLOG(this, 2) << __func__; 366 if (error.IsSuccess()) 367 OnRegistrationStateChangedSignal(state_1x, state_evdo); 368 } 369 370 void CellularCapabilityCDMA::OnGetSignalQualityReply(uint32_t quality, 371 const Error& error) { 372 if (error.IsSuccess()) 373 OnSignalQualitySignal(quality); 374 } 375 376 void CellularCapabilityCDMA::OnActivationStateChangedSignal( 377 uint32_t activation_state, 378 uint32_t activation_error, 379 const KeyValueStore& status_changes) { 380 SLOG(this, 2) << __func__; 381 382 if (status_changes.ContainsString("mdn")) 383 cellular()->set_mdn(status_changes.GetString("mdn")); 384 if (status_changes.ContainsString("min")) 385 cellular()->set_min(status_changes.GetString("min")); 386 387 UpdateOnlinePortal(status_changes); 388 activation_state_ = activation_state; 389 HandleNewActivationState(activation_error); 390 } 391 392 void CellularCapabilityCDMA::OnRegistrationStateChangedSignal( 393 uint32_t state_1x, uint32_t state_evdo) { 394 SLOG(this, 2) << __func__; 395 registration_state_1x_ = state_1x; 396 registration_state_evdo_ = state_evdo; 397 cellular()->HandleNewRegistrationState(); 398 } 399 400 void CellularCapabilityCDMA::OnSignalQualitySignal(uint32_t strength) { 401 cellular()->HandleNewSignalQuality(strength); 402 } 403 404 void CellularCapabilityCDMA::UpdateOnlinePortal( 405 const KeyValueStore& properties) { 406 // Treat the three updates atomically: Only update the serving operator when 407 // all three are known: 408 if (properties.ContainsString("payment_url") && 409 properties.ContainsString("payment_url_method") && 410 properties.ContainsString("payment_url_postdata")) { 411 cellular()->home_provider_info()->UpdateOnlinePortal( 412 properties.GetString("payment_url"), 413 properties.GetString("payment_url_method"), 414 properties.GetString("payment_url_postdata")); 415 } 416 } 417 418 } // namespace shill 419