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 39 using std::replace_if; 40 using std::string; 41 42 namespace shill { 43 44 namespace Logging { 45 static auto kModuleLogScope = ScopeLogger::kWiMax; 46 static string ObjectID(WiMaxService* w) { return w->GetRpcIdentifier(); } 47 } 48 49 const char WiMaxService::kStorageNetworkId[] = "NetworkId"; 50 const char WiMaxService::kNetworkIdProperty[] = "NetworkId"; 51 52 WiMaxService::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 80 WiMaxService::~WiMaxService() {} 81 82 void WiMaxService::GetConnectParameters(KeyValueStore* parameters) const { 83 CHECK(parameters); 84 eap()->PopulateWiMaxProperties(parameters); 85 } 86 87 RpcIdentifier WiMaxService::GetNetworkObjectPath() const { 88 CHECK(proxy_.get()); 89 return proxy_->path(); 90 } 91 92 void 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 107 bool 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 147 bool WiMaxService::IsStarted() const { 148 return proxy_.get(); 149 } 150 151 void 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 183 void 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 195 string WiMaxService::GetStorageIdentifier() const { 196 return storage_id_; 197 } 198 199 string 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 207 bool 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 220 bool WiMaxService::Is8021x() const { 221 return true; 222 } 223 224 bool 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 230 void WiMaxService::OnEapCredentialsChanged( 231 Service::UpdateCredentialsReason reason) { 232 need_passphrase_ = !eap()->IsConnectableUsingPassphrase(); 233 if (reason == Service::kReasonPropertyUpdate) 234 SetHasEverConnected(false); 235 UpdateConnectable(); 236 } 237 238 void WiMaxService::UpdateConnectable() { 239 SLOG(this, 2) << __func__ << "(started: " << IsStarted() 240 << ", need passphrase: " << need_passphrase_ << ")"; 241 SetConnectableFull(IsStarted() && !need_passphrase_); 242 } 243 244 void WiMaxService::OnSignalStrengthChanged(int strength) { 245 SLOG(this, 2) << __func__ << "(" << strength << ")"; 246 SetStrength(strength); 247 } 248 249 void 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 262 bool 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 273 bool 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 283 void 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 292 WiMaxNetworkId WiMaxService::ConvertIdentifierToNetworkId(uint32_t identifier) { 293 return base::StringPrintf("%08x", identifier); 294 } 295 296 void WiMaxService::InitStorageIdentifier() { 297 storage_id_ = CreateStorageIdentifier(network_id_, friendly_name()); 298 } 299 300 // static 301 string 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 310 void WiMaxService::ClearPassphrase() { 311 SLOG(this, 2) << __func__; 312 mutable_eap()->set_password(""); 313 OnEapCredentialsChanged(Service::kReasonPropertyUpdate); 314 } 315 316 } // namespace shill 317