Home | History | Annotate | Download | only in wimax
      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