Home | History | Annotate | Download | only in pppoe
      1 //
      2 // Copyright (C) 2015 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/pppoe/pppoe_service.h"
     18 
     19 #include <algorithm>
     20 #include <map>
     21 #include <memory>
     22 #include <string>
     23 
     24 #include <base/callback.h>
     25 #include <base/logging.h>
     26 #if defined(__ANDROID__)
     27 #include <dbus/service_constants.h>
     28 #else
     29 #include <chromeos/dbus/service_constants.h>
     30 #endif  // __ANDROID__
     31 
     32 #include "shill/control_interface.h"
     33 #include "shill/ethernet/ethernet.h"
     34 #include "shill/event_dispatcher.h"
     35 #include "shill/manager.h"
     36 #include "shill/metrics.h"
     37 #include "shill/ppp_daemon.h"
     38 #include "shill/ppp_device.h"
     39 #include "shill/ppp_device_factory.h"
     40 #include "shill/process_manager.h"
     41 #include "shill/store_interface.h"
     42 
     43 using base::StringPrintf;
     44 using std::map;
     45 using std::string;
     46 using std::unique_ptr;
     47 
     48 namespace shill {
     49 
     50 const int PPPoEService::kDefaultLCPEchoInterval = 30;
     51 const int PPPoEService::kDefaultLCPEchoFailure = 3;
     52 const int PPPoEService::kDefaultMaxAuthFailure = 3;
     53 
     54 PPPoEService::PPPoEService(ControlInterface* control_interface,
     55                            EventDispatcher* dispatcher,
     56                            Metrics* metrics,
     57                            Manager* manager,
     58                            base::WeakPtr<Ethernet> ethernet)
     59     : EthernetService(control_interface, dispatcher, metrics, manager,
     60                       Technology::kPPPoE, ethernet),
     61       control_interface_(control_interface),
     62       ppp_device_factory_(PPPDeviceFactory::GetInstance()),
     63       process_manager_(ProcessManager::GetInstance()),
     64       lcp_echo_interval_(kDefaultLCPEchoInterval),
     65       lcp_echo_failure_(kDefaultLCPEchoFailure),
     66       max_auth_failure_(kDefaultMaxAuthFailure),
     67       authenticating_(false),
     68       weak_ptr_factory_(this) {
     69   PropertyStore* store = this->mutable_store();
     70   store->RegisterString(kPPPoEUsernameProperty, &username_);
     71   store->RegisterString(kPPPoEPasswordProperty, &password_);
     72   store->RegisterInt32(kPPPoELCPEchoIntervalProperty, &lcp_echo_interval_);
     73   store->RegisterInt32(kPPPoELCPEchoFailureProperty, &lcp_echo_failure_);
     74   store->RegisterInt32(kPPPoEMaxAuthFailureProperty, &max_auth_failure_);
     75 
     76   set_friendly_name("PPPoE");
     77   SetConnectable(true);
     78   SetAutoConnect(true);
     79   NotifyPropertyChanges();
     80 }
     81 
     82 PPPoEService::~PPPoEService() {}
     83 
     84 void PPPoEService::Connect(Error* error, const char* reason) {
     85   Service::Connect(error, reason);
     86 
     87   CHECK(ethernet());
     88 
     89   if (!ethernet()->link_up()) {
     90     Error::PopulateAndLog(
     91         FROM_HERE, error, Error::kOperationFailed, StringPrintf(
     92             "PPPoE Service %s does not have Ethernet link.",
     93             unique_name().c_str()));
     94     return;
     95   }
     96 
     97   if (IsConnected()) {
     98     Error::PopulateAndLog(FROM_HERE, error, Error::kAlreadyConnected,
     99                           StringPrintf("PPPoE service %s already connected.",
    100                                        unique_name().c_str()));
    101     return;
    102   }
    103 
    104   if (IsConnecting()) {
    105     Error::PopulateAndLog(FROM_HERE, error, Error::kInProgress,
    106                           StringPrintf("PPPoE service %s already connecting.",
    107                                        unique_name().c_str()));
    108     return;
    109   }
    110 
    111   PPPDaemon::DeathCallback callback(base::Bind(&PPPoEService::OnPPPDied,
    112                                                weak_ptr_factory_.GetWeakPtr()));
    113 
    114   PPPDaemon::Options options;
    115   options.no_detach = true;
    116   options.no_default_route = true;
    117   options.use_peer_dns = true;
    118   options.use_pppoe_plugin = true;
    119   options.lcp_echo_interval = lcp_echo_interval_;
    120   options.lcp_echo_failure = lcp_echo_failure_;
    121   options.max_fail = max_auth_failure_;
    122   options.use_ipv6 = true;
    123 
    124   pppd_ = PPPDaemon::Start(
    125       control_interface_, process_manager_, weak_ptr_factory_.GetWeakPtr(),
    126       options, ethernet()->link_name(), callback, error);
    127   if (pppd_ == nullptr) {
    128     Error::PopulateAndLog(FROM_HERE, error, Error::kInternalError,
    129                           StringPrintf("PPPoE service %s can't start pppd.",
    130                                        unique_name().c_str()));
    131     return;
    132   }
    133 
    134   SetState(Service::kStateAssociating);
    135 }
    136 
    137 void PPPoEService::Disconnect(Error* error, const char* reason) {
    138   EthernetService::Disconnect(error, reason);
    139   if (ppp_device_) {
    140     ppp_device_->DropConnection();
    141   } else {
    142     // If no PPPDevice has been associated with this service then nothing will
    143     // drive this service's transition into the idle state.  This must be forced
    144     // here to ensure that the service is not left in any intermediate state.
    145     SetState(Service::kStateIdle);
    146   }
    147   ppp_device_ = nullptr;
    148   pppd_.reset();
    149   manager()->OnInnerDevicesChanged();
    150 }
    151 
    152 bool PPPoEService::Load(StoreInterface* storage) {
    153   if (!Service::Load(storage)) {
    154     return false;
    155   }
    156 
    157   const string id = GetStorageIdentifier();
    158   storage->GetString(id, kPPPoEUsernameProperty, &username_);
    159   storage->GetString(id, kPPPoEPasswordProperty, &password_);
    160   storage->GetInt(id, kPPPoELCPEchoIntervalProperty, &lcp_echo_interval_);
    161   storage->GetInt(id, kPPPoELCPEchoFailureProperty, &lcp_echo_failure_);
    162   storage->GetInt(id, kPPPoEMaxAuthFailureProperty, &max_auth_failure_);
    163 
    164   return true;
    165 }
    166 
    167 bool PPPoEService::Save(StoreInterface* storage) {
    168   if (!Service::Save(storage)) {
    169     return false;
    170   }
    171 
    172   const string id = GetStorageIdentifier();
    173   storage->SetString(id, kPPPoEUsernameProperty, username_);
    174   storage->SetString(id, kPPPoEPasswordProperty, password_);
    175   storage->SetInt(id, kPPPoELCPEchoIntervalProperty, lcp_echo_interval_);
    176   storage->SetInt(id, kPPPoELCPEchoFailureProperty, lcp_echo_failure_);
    177   storage->SetInt(id, kPPPoEMaxAuthFailureProperty, max_auth_failure_);
    178 
    179   return true;
    180 }
    181 
    182 bool PPPoEService::Unload() {
    183   username_.clear();
    184   password_.clear();
    185   return Service::Unload();
    186 }
    187 
    188 string PPPoEService::GetInnerDeviceRpcIdentifier() const {
    189   return ppp_device_ ? ppp_device_->GetRpcIdentifier() : "";
    190 }
    191 
    192 void PPPoEService::GetLogin(string* user, string* password) {
    193   CHECK(user && password);
    194   *user = username_;
    195   *password = password_;
    196 }
    197 
    198 void PPPoEService::Notify(const string& reason,
    199                           const map<string, string>& dict) {
    200   if (reason == kPPPReasonAuthenticating) {
    201     OnPPPAuthenticating();
    202   } else if (reason == kPPPReasonAuthenticated) {
    203     OnPPPAuthenticated();
    204   } else if (reason == kPPPReasonConnect) {
    205     OnPPPConnected(dict);
    206   } else if (reason == kPPPReasonDisconnect) {
    207     OnPPPDisconnected();
    208   } else {
    209     NOTREACHED();
    210   }
    211 }
    212 
    213 void PPPoEService::OnPPPDied(pid_t pid, int exit) {
    214   OnPPPDisconnected();
    215 }
    216 
    217 void PPPoEService::OnPPPAuthenticating() {
    218   authenticating_ = true;
    219 }
    220 
    221 void PPPoEService::OnPPPAuthenticated() {
    222   authenticating_ = false;
    223 }
    224 
    225 void PPPoEService::OnPPPConnected(const map<string, string>& params) {
    226   const string interface_name = PPPDevice::GetInterfaceName(params);
    227 
    228   DeviceInfo* device_info = manager()->device_info();
    229   const int interface_index = device_info->GetIndex(interface_name);
    230   if (interface_index < 0) {
    231     NOTIMPLEMENTED() << ": No device info for " << interface_name;
    232     return;
    233   }
    234 
    235   if (ppp_device_) {
    236     ppp_device_->SelectService(nullptr);
    237   }
    238 
    239   ppp_device_ = ppp_device_factory_->CreatePPPDevice(
    240       control_interface_, dispatcher(), metrics(), manager(), interface_name,
    241       interface_index);
    242   device_info->RegisterDevice(ppp_device_);
    243   ppp_device_->SetEnabled(true);
    244   ppp_device_->SelectService(this);
    245   ppp_device_->UpdateIPConfigFromPPP(params, false);
    246 #ifndef DISABLE_DHCPV6
    247   // Acquire DHCPv6 configurations through the PPPoE (virtual) interface
    248   // if it is enabled for DHCPv6.
    249   if (manager()->IsDHCPv6EnabledForDevice(ppp_device_->link_name())) {
    250     ppp_device_->AcquireIPv6Config();
    251   }
    252 #endif
    253   manager()->OnInnerDevicesChanged();
    254 }
    255 
    256 void PPPoEService::OnPPPDisconnected() {
    257   pppd_.release()->DestroyLater(dispatcher());
    258 
    259   Error unused_error;
    260   Disconnect(&unused_error, __func__);
    261 
    262   if (authenticating_) {
    263     SetFailure(Service::kFailurePPPAuth);
    264   } else {
    265     SetFailure(Service::kFailureUnknown);
    266   }
    267 }
    268 
    269 }  // namespace shill
    270