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/wimax/wimax_service.h" 18 19#include <algorithm> 20 21#include <base/strings/string_number_conversions.h> 22#include <base/strings/string_util.h> 23#include <base/strings/stringprintf.h> 24#if defined(__ANDROID__) 25#include <dbus/service_constants.h> 26#else 27#include <chromeos/dbus/service_constants.h> 28#endif // __ANDROID__ 29 30#include "shill/control_interface.h" 31#include "shill/eap_credentials.h" 32#include "shill/key_value_store.h" 33#include "shill/logging.h" 34#include "shill/manager.h" 35#include "shill/store_interface.h" 36#include "shill/technology.h" 37#include "shill/wimax/wimax.h" 38 39using std::replace_if; 40using std::string; 41 42namespace shill { 43 44namespace Logging { 45static auto kModuleLogScope = ScopeLogger::kWiMax; 46static string ObjectID(WiMaxService* w) { return w->GetRpcIdentifier(); } 47} 48 49const char WiMaxService::kStorageNetworkId[] = "NetworkId"; 50const char WiMaxService::kNetworkIdProperty[] = "NetworkId"; 51 52WiMaxService::WiMaxService(ControlInterface* control, 53 EventDispatcher* dispatcher, 54 Metrics* metrics, 55 Manager* manager) 56 : Service(control, dispatcher, metrics, manager, Technology::kWiMax), 57 need_passphrase_(true), 58 is_default_(false) { 59 PropertyStore* store = this->mutable_store(); 60 // TODO(benchan): Support networks that require no user credentials or 61 // implicitly defined credentials. 62 store->RegisterBool(kPassphraseRequiredProperty, &need_passphrase_); 63 store->RegisterConstString(kNetworkIdProperty, &network_id_); 64 65 SetEapCredentials(new EapCredentials()); 66 67 IgnoreParameterForConfigure(kNetworkIdProperty); 68 69 // Initialize a default storage identifier based on the service's unique 70 // name. The identifier most likely needs to be reinitialized by the caller 71 // when its components have been set. 72 InitStorageIdentifier(); 73 74 // Now that |this| is a fully constructed WiMaxService, synchronize observers 75 // with our current state, and emit the appropriate change notifications. 76 // (Initial observer state may have been set in our base class.) 77 NotifyPropertyChanges(); 78} 79 80WiMaxService::~WiMaxService() {} 81 82void WiMaxService::GetConnectParameters(KeyValueStore* parameters) const { 83 CHECK(parameters); 84 eap()->PopulateWiMaxProperties(parameters); 85} 86 87RpcIdentifier WiMaxService::GetNetworkObjectPath() const { 88 CHECK(proxy_.get()); 89 return proxy_->path(); 90} 91 92void WiMaxService::Stop() { 93 if (!IsStarted()) { 94 return; 95 } 96 LOG(INFO) << "Stopping WiMAX service: " << GetStorageIdentifier(); 97 proxy_.reset(); 98 SetStrength(0); 99 if (device_) { 100 device_->OnServiceStopped(this); 101 SetDevice(nullptr); 102 } 103 UpdateConnectable(); 104 NotifyPropertyChanges(); 105} 106 107bool WiMaxService::Start(WiMaxNetworkProxyInterface* proxy) { 108 SLOG(this, 2) << __func__; 109 CHECK(proxy); 110 std::unique_ptr<WiMaxNetworkProxyInterface> local_proxy(proxy); 111 if (IsStarted()) { 112 return true; 113 } 114 if (friendly_name().empty()) { 115 LOG(ERROR) << "Empty service name."; 116 return false; 117 } 118 Error error; 119 network_name_ = proxy->Name(&error); 120 if (error.IsFailure()) { 121 return false; 122 } 123 uint32_t identifier = proxy->Identifier(&error); 124 if (error.IsFailure()) { 125 return false; 126 } 127 WiMaxNetworkId id = ConvertIdentifierToNetworkId(identifier); 128 if (id != network_id_) { 129 LOG(ERROR) << "Network identifiers don't match: " 130 << id << " != " << network_id_; 131 return false; 132 } 133 int signal_strength = proxy->SignalStrength(&error); 134 if (error.IsFailure()) { 135 return false; 136 } 137 SetStrength(signal_strength); 138 proxy->set_signal_strength_changed_callback( 139 Bind(&WiMaxService::OnSignalStrengthChanged, Unretained(this))); 140 proxy_.reset(local_proxy.release()); 141 UpdateConnectable(); 142 NotifyPropertyChanges(); 143 LOG(INFO) << "WiMAX service started: " << GetStorageIdentifier(); 144 return true; 145} 146 147bool WiMaxService::IsStarted() const { 148 return proxy_.get(); 149} 150 151void WiMaxService::Connect(Error* error, const char* reason) { 152 SLOG(this, 2) << __func__; 153 if (device_) { 154 // TODO(benchan): Populate error again after changing the way that 155 // Chrome handles Error::kAlreadyConnected situation. 156 LOG(WARNING) << "Service " << GetStorageIdentifier() 157 << " is already being connected or already connected."; 158 return; 159 } 160 if (!connectable()) { 161 LOG(ERROR) << "Can't connect. Service " << GetStorageIdentifier() 162 << " is not connectable."; 163 Error::PopulateAndLog(FROM_HERE, error, Error::kOperationFailed, 164 Error::GetDefaultMessage(Error::kOperationFailed)); 165 return; 166 } 167 WiMaxRefPtr carrier = manager()->wimax_provider()->SelectCarrier(this); 168 if (!carrier) { 169 Error::PopulateAndLog( 170 FROM_HERE, error, Error::kNoCarrier, 171 "No suitable WiMAX device available."); 172 return; 173 } 174 Service::Connect(error, reason); 175 carrier->ConnectTo(this, error); 176 if (error->IsSuccess()) { 177 // Associate with the carrier device if the connection process has been 178 // initiated successfully. 179 SetDevice(carrier); 180 } 181} 182 183void WiMaxService::Disconnect(Error* error, const char* reason) { 184 SLOG(this, 2) << __func__; 185 if (!device_) { 186 Error::PopulateAndLog( 187 FROM_HERE, error, Error::kNotConnected, "Not connected."); 188 return; 189 } 190 Service::Disconnect(error, reason); 191 device_->DisconnectFrom(this, error); 192 SetDevice(nullptr); 193} 194 195string WiMaxService::GetStorageIdentifier() const { 196 return storage_id_; 197} 198 199string WiMaxService::GetDeviceRpcId(Error* error) const { 200 if (!device_) { 201 error->Populate(Error::kNotFound, "Not associated with a device"); 202 return control_interface()->NullRPCIdentifier(); 203 } 204 return device_->GetRpcIdentifier(); 205} 206 207bool WiMaxService::IsAutoConnectable(const char** reason) const { 208 if (!Service::IsAutoConnectable(reason)) { 209 return false; 210 } 211 WiMaxRefPtr device = manager()->wimax_provider()->SelectCarrier(this); 212 DCHECK(device); 213 if (!device->IsIdle()) { 214 *reason = kAutoConnBusy; 215 return false; 216 } 217 return true; 218} 219 220bool WiMaxService::Is8021x() const { 221 return true; 222} 223 224bool WiMaxService::IsVisible() const { 225 // WiMAX services should be displayed only if they are in range (i.e. 226 // a corresponding network is exposed by WiMAX manager). 227 return IsStarted(); 228} 229 230void WiMaxService::OnEapCredentialsChanged( 231 Service::UpdateCredentialsReason reason) { 232 need_passphrase_ = !eap()->IsConnectableUsingPassphrase(); 233 if (reason == Service::kReasonPropertyUpdate) 234 SetHasEverConnected(false); 235 UpdateConnectable(); 236} 237 238void WiMaxService::UpdateConnectable() { 239 SLOG(this, 2) << __func__ << "(started: " << IsStarted() 240 << ", need passphrase: " << need_passphrase_ << ")"; 241 SetConnectableFull(IsStarted() && !need_passphrase_); 242} 243 244void WiMaxService::OnSignalStrengthChanged(int strength) { 245 SLOG(this, 2) << __func__ << "(" << strength << ")"; 246 SetStrength(strength); 247} 248 249void WiMaxService::SetDevice(WiMaxRefPtr new_device) { 250 if (device_ == new_device) 251 return; 252 if (new_device) { 253 adaptor()->EmitRpcIdentifierChanged(kDeviceProperty, 254 new_device->GetRpcIdentifier()); 255 } else { 256 adaptor()->EmitRpcIdentifierChanged( 257 kDeviceProperty, control_interface()->NullRPCIdentifier()); 258 } 259 device_ = new_device; 260} 261 262bool WiMaxService::Save(StoreInterface* storage) { 263 SLOG(this, 2) << __func__; 264 if (!Service::Save(storage)) { 265 return false; 266 } 267 const string id = GetStorageIdentifier(); 268 storage->SetString(id, kStorageNetworkId, network_id_); 269 270 return true; 271} 272 273bool WiMaxService::Unload() { 274 SLOG(this, 2) << __func__; 275 // The base method also disconnects the service. 276 Service::Unload(); 277 ClearPassphrase(); 278 // Notify the WiMAX provider that this service has been unloaded. If the 279 // provider releases ownership of this service, it needs to be deregistered. 280 return manager()->wimax_provider()->OnServiceUnloaded(this); 281} 282 283void WiMaxService::SetState(ConnectState state) { 284 Service::SetState(state); 285 if (!IsConnecting() && !IsConnected()) { 286 // Disassociate from any carrier device if it's not connected anymore. 287 SetDevice(nullptr); 288 } 289} 290 291// static 292WiMaxNetworkId WiMaxService::ConvertIdentifierToNetworkId(uint32_t identifier) { 293 return base::StringPrintf("%08x", identifier); 294} 295 296void WiMaxService::InitStorageIdentifier() { 297 storage_id_ = CreateStorageIdentifier(network_id_, friendly_name()); 298} 299 300// static 301string WiMaxService::CreateStorageIdentifier(const WiMaxNetworkId& id, 302 const string& name) { 303 string storage_id = base::ToLowerASCII( 304 base::StringPrintf("%s_%s_%s", 305 kTypeWimax, name.c_str(), id.c_str())); 306 replace_if(storage_id.begin(), storage_id.end(), &Service::IllegalChar, '_'); 307 return storage_id; 308} 309 310void WiMaxService::ClearPassphrase() { 311 SLOG(this, 2) << __func__; 312 mutable_eap()->set_password(""); 313 OnEapCredentialsChanged(Service::kReasonPropertyUpdate); 314} 315 316} // namespace shill 317