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