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 
PPPoEService(ControlInterface * control_interface,EventDispatcher * dispatcher,Metrics * metrics,Manager * manager,base::WeakPtr<Ethernet> ethernet)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 
~PPPoEService()82 PPPoEService::~PPPoEService() {}
83 
Connect(Error * error,const char * reason)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 
Disconnect(Error * error,const char * reason)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 
Load(StoreInterface * storage)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 
Save(StoreInterface * storage)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 
Unload()182 bool PPPoEService::Unload() {
183   username_.clear();
184   password_.clear();
185   return Service::Unload();
186 }
187 
GetInnerDeviceRpcIdentifier() const188 string PPPoEService::GetInnerDeviceRpcIdentifier() const {
189   return ppp_device_ ? ppp_device_->GetRpcIdentifier() : "";
190 }
191 
GetLogin(string * user,string * password)192 void PPPoEService::GetLogin(string* user, string* password) {
193   CHECK(user && password);
194   *user = username_;
195   *password = password_;
196 }
197 
Notify(const string & reason,const map<string,string> & dict)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 
OnPPPDied(pid_t pid,int exit)213 void PPPoEService::OnPPPDied(pid_t pid, int exit) {
214   OnPPPDisconnected();
215 }
216 
OnPPPAuthenticating()217 void PPPoEService::OnPPPAuthenticating() {
218   authenticating_ = true;
219 }
220 
OnPPPAuthenticated()221 void PPPoEService::OnPPPAuthenticated() {
222   authenticating_ = false;
223 }
224 
OnPPPConnected(const map<string,string> & params)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 
OnPPPDisconnected()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