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