pppoe_service.cc revision aab63499fccbd5b94fcfd2fa88e5fda83a8b5da8
1// Copyright 2015 The Chromium OS Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "shill/pppoe/pppoe_service.h" 6 7#include <algorithm> 8#include <map> 9#include <memory> 10#include <string> 11 12#include <base/callback.h> 13#include <base/logging.h> 14#include <chromeos/dbus/service_constants.h> 15 16#include "shill/control_interface.h" 17#include "shill/ethernet/ethernet.h" 18#include "shill/event_dispatcher.h" 19#include "shill/manager.h" 20#include "shill/metrics.h" 21#include "shill/ppp_daemon.h" 22#include "shill/ppp_device.h" 23#include "shill/ppp_device_factory.h" 24#include "shill/store_interface.h" 25 26using base::StringPrintf; 27using std::map; 28using std::string; 29using std::unique_ptr; 30 31namespace shill { 32 33PPPoEService::PPPoEService(ControlInterface *control_interface, 34 EventDispatcher *dispatcher, 35 Metrics *metrics, 36 Manager *manager, 37 base::WeakPtr<Ethernet> ethernet) 38 : EthernetService(control_interface, dispatcher, metrics, manager, 39 Technology::kPPPoE, ethernet), 40 control_interface_(control_interface), 41 authenticating_(false), 42 weak_ptr_factory_(this) { 43 PropertyStore *store = this->mutable_store(); 44 store->RegisterString(kPPPoEUsernameProperty, &username_); 45 store->RegisterString(kPPPoEPasswordProperty, &password_); 46 47 set_friendly_name("PPPoE"); 48 SetConnectable(true); 49 SetAutoConnect(true); 50 NotifyPropertyChanges(); 51} 52 53PPPoEService::~PPPoEService() {} 54 55void PPPoEService::Connect(Error *error, const char *reason) { 56 Service::Connect(error, reason); 57 58 CHECK(ethernet()); 59 60 if (!ethernet()->link_up()) { 61 Error::PopulateAndLog( 62 FROM_HERE, error, Error::kOperationFailed, StringPrintf( 63 "PPPoE Service %s does not have Ethernet link.", 64 unique_name().c_str())); 65 return; 66 } 67 68 if (IsConnected()) { 69 Error::PopulateAndLog(FROM_HERE, error, Error::kAlreadyConnected, 70 StringPrintf("PPPoE service %s already connected.", 71 unique_name().c_str())); 72 return; 73 } 74 75 if (IsConnecting()) { 76 Error::PopulateAndLog(FROM_HERE, error, Error::kInProgress, 77 StringPrintf("PPPoE service %s already connecting.", 78 unique_name().c_str())); 79 return; 80 } 81 82 PPPDaemon::DeathCallback callback(base::Bind(&PPPoEService::OnPPPDied, 83 weak_ptr_factory_.GetWeakPtr())); 84 85 PPPDaemon::Options options; 86 options.no_detach = true; 87 options.no_default_route = true; 88 options.use_peer_dns = true; 89 options.use_pppoe_plugin = true; 90 91 pppd_ = PPPDaemon::Start( 92 control_interface_, manager()->glib(), weak_ptr_factory_.GetWeakPtr(), 93 options, ethernet()->link_name(), callback, error); 94 if (pppd_ == nullptr) { 95 Error::PopulateAndLog(FROM_HERE, error, Error::kInternalError, 96 StringPrintf("PPPoE service %s can't start pppd.", 97 unique_name().c_str())); 98 return; 99 } 100 101 SetState(Service::kStateAssociating); 102} 103 104void PPPoEService::Disconnect(Error *error, const char *reason) { 105 EthernetService::Disconnect(error, reason); 106 if (ppp_device_) { 107 ppp_device_->DropConnection(); 108 } 109 ppp_device_ = nullptr; 110 pppd_.reset(); 111} 112 113bool PPPoEService::Load(StoreInterface *storage) { 114 if (!Service::Load(storage)) { 115 return false; 116 } 117 118 const string id = GetStorageIdentifier(); 119 storage->GetString(id, kPPPoEUsernameProperty, &username_); 120 storage->GetString(id, kPPPoEPasswordProperty, &password_); 121 122 return true; 123} 124 125bool PPPoEService::Save(StoreInterface *storage) { 126 if (!Service::Save(storage)) { 127 return false; 128 } 129 130 const string id = GetStorageIdentifier(); 131 storage->SetString(id, kPPPoEUsernameProperty, username_); 132 storage->SetString(id, kPPPoEPasswordProperty, password_); 133 134 return true; 135} 136 137bool PPPoEService::Unload() { 138 username_.clear(); 139 password_.clear(); 140 return Service::Unload(); 141} 142 143void PPPoEService::GetLogin(string *user, string *password) { 144 CHECK(user && password); 145 *user = username_; 146 *password = password_; 147} 148 149void PPPoEService::Notify(const string &reason, 150 const map<string, string> &dict) { 151 if (reason == kPPPReasonAuthenticating) { 152 OnPPPAuthenticating(); 153 } else if (reason == kPPPReasonAuthenticated) { 154 OnPPPAuthenticated(); 155 } else if (reason == kPPPReasonConnect) { 156 OnPPPConnected(dict); 157 } else if (reason == kPPPReasonDisconnect) { 158 OnPPPDisconnected(); 159 } else { 160 NOTREACHED(); 161 } 162} 163 164void PPPoEService::OnPPPDied(pid_t pid, int exit) { 165 OnPPPDisconnected(); 166} 167 168void PPPoEService::OnPPPAuthenticating() { 169 authenticating_ = true; 170} 171 172void PPPoEService::OnPPPAuthenticated() { 173 authenticating_ = false; 174} 175 176void PPPoEService::OnPPPConnected(const map<string, string> ¶ms) { 177 const string interface_name = PPPDevice::GetInterfaceName(params); 178 179 DeviceInfo *device_info = manager()->device_info(); 180 const int interface_index = device_info->GetIndex(interface_name); 181 if (interface_index < 0) { 182 NOTIMPLEMENTED() << ": No device info for " << interface_name; 183 return; 184 } 185 186 if (ppp_device_) { 187 ppp_device_->SelectService(nullptr); 188 } 189 190 const auto factory = PPPDeviceFactory::GetInstance(); 191 ppp_device_ = factory->CreatePPPDevice( 192 control_interface_, dispatcher(), metrics(), manager(), interface_name, 193 interface_index); 194 device_info->RegisterDevice(ppp_device_); 195 ppp_device_->SetEnabled(true); 196 ppp_device_->SelectService(this); 197 ppp_device_->UpdateIPConfigFromPPP(params, false); 198} 199 200void PPPoEService::OnPPPDisconnected() { 201 pppd_.release()->DestroyLater(dispatcher()); 202 203 if (authenticating_) { 204 SetFailure(Service::kFailurePPPAuth); 205 } else { 206 SetFailure(Service::kFailureUnknown); 207 } 208 209 Error error; 210 Disconnect(&error, __func__); 211} 212 213} // namespace shill 214