1 //
2 // Copyright (C) 2012 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/ethernet/ethernet.h"
18 
19 #include <linux/ethtool.h>
20 #include <netinet/ether.h>
21 #include <netinet/in.h>
22 #include <linux/if.h>  // NOLINT - Needs definitions from netinet/ether.h
23 #include <linux/sockios.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <time.h>
27 
28 #include <map>
29 #include <string>
30 #include <vector>
31 
32 #include <base/bind.h>
33 
34 #include "shill/adaptor_interfaces.h"
35 #include "shill/control_interface.h"
36 #include "shill/device.h"
37 #include "shill/device_info.h"
38 #include "shill/ethernet/ethernet_service.h"
39 #include "shill/event_dispatcher.h"
40 #include "shill/logging.h"
41 #include "shill/manager.h"
42 #include "shill/net/rtnl_handler.h"
43 #include "shill/pppoe/pppoe_service.h"
44 #include "shill/profile.h"
45 #include "shill/property_accessor.h"
46 #include "shill/refptr_types.h"
47 #include "shill/store_interface.h"
48 
49 #if !defined(DISABLE_WIRED_8021X)
50 #include "shill/eap_credentials.h"
51 #include "shill/eap_listener.h"
52 #include "shill/ethernet/ethernet_eap_provider.h"
53 #include "shill/supplicant/supplicant_interface_proxy_interface.h"
54 #include "shill/supplicant/supplicant_process_proxy_interface.h"
55 #include "shill/supplicant/wpa_supplicant.h"
56 #endif  // DISABLE_WIRED_8021X
57 
58 using std::map;
59 using std::string;
60 using std::vector;
61 
62 namespace shill {
63 
64 namespace Logging {
65 static auto kModuleLogScope = ScopeLogger::kEthernet;
ObjectID(Ethernet * e)66 static string ObjectID(Ethernet* e) { return e->GetRpcIdentifier(); }
67 }
68 
Ethernet(ControlInterface * control_interface,EventDispatcher * dispatcher,Metrics * metrics,Manager * manager,const string & link_name,const string & address,int interface_index)69 Ethernet::Ethernet(ControlInterface* control_interface,
70                    EventDispatcher* dispatcher,
71                    Metrics* metrics,
72                    Manager* manager,
73                    const string& link_name,
74                    const string& address,
75                    int interface_index)
76     : Device(control_interface,
77              dispatcher,
78              metrics,
79              manager,
80              link_name,
81              address,
82              interface_index,
83              Technology::kEthernet),
84       control_interface_(control_interface),
85       link_up_(false),
86 #if !defined(DISABLE_WIRED_8021X)
87       is_eap_authenticated_(false),
88       is_eap_detected_(false),
89       eap_listener_(new EapListener(dispatcher, interface_index)),
90       supplicant_process_proxy_(
91           control_interface_->CreateSupplicantProcessProxy(
92               base::Closure(), base::Closure())),
93 #endif  // DISABLE_WIRED_8021X
94       sockets_(new Sockets()),
95       weak_ptr_factory_(this) {
96   PropertyStore* store = this->mutable_store();
97 #if !defined(DISABLE_WIRED_8021X)
98   store->RegisterConstBool(kEapAuthenticationCompletedProperty,
99                            &is_eap_authenticated_);
100   store->RegisterConstBool(kEapAuthenticatorDetectedProperty,
101                            &is_eap_detected_);
102 #endif  // DISABLE_WIRED_8021X
103   store->RegisterConstBool(kLinkUpProperty, &link_up_);
104   store->RegisterDerivedBool(kPPPoEProperty, BoolAccessor(
105       new CustomAccessor<Ethernet, bool>(this,
106                                          &Ethernet::GetPPPoEMode,
107                                          &Ethernet::ConfigurePPPoEMode,
108                                          &Ethernet::ClearPPPoEMode)));
109 
110 #if !defined(DISABLE_WIRED_8021X)
111   eap_listener_->set_request_received_callback(
112       base::Bind(&Ethernet::OnEapDetected, weak_ptr_factory_.GetWeakPtr()));
113 #endif  // DISABLE_WIRED_8021X
114   service_ = CreateEthernetService();
115   SLOG(this, 2) << "Ethernet device " << link_name << " initialized.";
116 }
117 
~Ethernet()118 Ethernet::~Ethernet() {
119 }
120 
Start(Error * error,const EnabledStateChangedCallback &)121 void Ethernet::Start(Error* error,
122                      const EnabledStateChangedCallback& /*callback*/) {
123   rtnl_handler()->SetInterfaceFlags(interface_index(), IFF_UP, IFF_UP);
124   OnEnabledStateChanged(EnabledStateChangedCallback(), Error());
125   LOG(INFO) << "Registering " << link_name() << " with manager.";
126   if (!manager()->HasService(service_)) {
127     manager()->RegisterService(service_);
128   }
129   if (error)
130     error->Reset();       // indicate immediate completion
131 }
132 
Stop(Error * error,const EnabledStateChangedCallback &)133 void Ethernet::Stop(Error* error,
134                     const EnabledStateChangedCallback& /*callback*/) {
135   manager()->DeregisterService(service_);
136 #if !defined(DISABLE_WIRED_8021X)
137   StopSupplicant();
138 #endif  // DISABLE_WIRED_8021X
139   OnEnabledStateChanged(EnabledStateChangedCallback(), Error());
140   if (error)
141     error->Reset();       // indicate immediate completion
142 }
143 
LinkEvent(unsigned int flags,unsigned int change)144 void Ethernet::LinkEvent(unsigned int flags, unsigned int change) {
145   Device::LinkEvent(flags, change);
146   if ((flags & IFF_LOWER_UP) != 0 && !link_up_) {
147     link_up_ = true;
148     adaptor()->EmitBoolChanged(kLinkUpProperty, link_up_);
149     // We SetupWakeOnLan() here, instead of in Start(), because with
150     // r8139, "ethtool -s eth0 wol g" fails when no cable is plugged
151     // in.
152     manager()->UpdateService(service_);
153     service_->OnVisibilityChanged();
154     SetupWakeOnLan();
155 #if !defined(DISABLE_WIRED_8021X)
156     eap_listener_->Start();
157 #endif  // DISABLE_WIRED_8021X
158   } else if ((flags & IFF_LOWER_UP) == 0 && link_up_) {
159     link_up_ = false;
160     adaptor()->EmitBoolChanged(kLinkUpProperty, link_up_);
161     DestroyIPConfig();
162     SelectService(nullptr);
163     manager()->UpdateService(service_);
164     service_->OnVisibilityChanged();
165 #if !defined(DISABLE_WIRED_8021X)
166     is_eap_detected_ = false;
167     GetEapProvider()->ClearCredentialChangeCallback(this);
168     SetIsEapAuthenticated(false);
169     StopSupplicant();
170     eap_listener_->Stop();
171 #endif  // DISABLE_WIRED_8021X
172   }
173 }
174 
Load(StoreInterface * storage)175 bool Ethernet::Load(StoreInterface* storage) {
176   const string id = GetStorageIdentifier();
177   if (!storage->ContainsGroup(id)) {
178     SLOG(this, 2) << "Device is not available in the persistent store: " << id;
179     return false;
180   }
181 
182   bool pppoe = false;
183   storage->GetBool(id, kPPPoEProperty, &pppoe);
184 
185   Error error;
186   ConfigurePPPoEMode(pppoe, &error);
187   if (!error.IsSuccess()) {
188     LOG(WARNING) << "Error configuring PPPoE mode.  Ignoring!";
189   }
190 
191   return Device::Load(storage);
192 }
193 
Save(StoreInterface * storage)194 bool Ethernet::Save(StoreInterface* storage) {
195   const string id = GetStorageIdentifier();
196   storage->SetBool(id, kPPPoEProperty, GetPPPoEMode(nullptr));
197   return true;
198 }
199 
ConnectTo(EthernetService * service)200 void Ethernet::ConnectTo(EthernetService* service) {
201   CHECK(service == service_.get()) << "Ethernet was asked to connect the "
202                                    << "wrong service?";
203   CHECK(!GetPPPoEMode(nullptr)) << "We should never connect in PPPoE mode!";
204   if (!link_up_) {
205     return;
206   }
207   SelectService(service);
208   if (AcquireIPConfigWithLeaseName(service->GetStorageIdentifier())) {
209     SetServiceState(Service::kStateConfiguring);
210   } else {
211     LOG(ERROR) << "Unable to acquire DHCP config.";
212     SetServiceState(Service::kStateFailure);
213     DestroyIPConfig();
214   }
215 }
216 
DisconnectFrom(EthernetService * service)217 void Ethernet::DisconnectFrom(EthernetService* service) {
218   CHECK(service == service_.get()) << "Ethernet was asked to disconnect the "
219                                    << "wrong service?";
220   DropConnection();
221 }
222 
223 #if !defined(DISABLE_WIRED_8021X)
TryEapAuthentication()224 void Ethernet::TryEapAuthentication() {
225   try_eap_authentication_callback_.Reset(
226       Bind(&Ethernet::TryEapAuthenticationTask,
227            weak_ptr_factory_.GetWeakPtr()));
228   dispatcher()->PostTask(try_eap_authentication_callback_.callback());
229 }
230 
BSSAdded(const string & path,const KeyValueStore & properties)231 void Ethernet::BSSAdded(const string& path, const KeyValueStore& properties) {
232   NOTREACHED() << __func__ << " is not implemented for Ethernet";
233 }
234 
BSSRemoved(const string & path)235 void Ethernet::BSSRemoved(const string& path) {
236   NOTREACHED() << __func__ << " is not implemented for Ethernet";
237 }
238 
Certification(const KeyValueStore & properties)239 void Ethernet::Certification(const KeyValueStore& properties) {
240   string subject;
241   uint32_t depth;
242   if (WPASupplicant::ExtractRemoteCertification(properties, &subject, &depth)) {
243     dispatcher()->PostTask(Bind(&Ethernet::CertificationTask,
244                                 weak_ptr_factory_.GetWeakPtr(),
245                                 subject, depth));
246   }
247 }
248 
EAPEvent(const string & status,const string & parameter)249 void Ethernet::EAPEvent(const string& status, const string& parameter) {
250   dispatcher()->PostTask(Bind(&Ethernet::EAPEventTask,
251                               weak_ptr_factory_.GetWeakPtr(),
252                               status,
253                               parameter));
254 }
255 
PropertiesChanged(const KeyValueStore & properties)256 void Ethernet::PropertiesChanged(const KeyValueStore& properties) {
257   if (!properties.ContainsString(WPASupplicant::kInterfacePropertyState)) {
258     return;
259   }
260   dispatcher()->PostTask(
261       Bind(&Ethernet::SupplicantStateChangedTask,
262            weak_ptr_factory_.GetWeakPtr(),
263            properties.GetString(WPASupplicant::kInterfacePropertyState)));
264 }
265 
ScanDone(const bool &)266 void Ethernet::ScanDone(const bool& /*success*/) {
267   NOTREACHED() << __func__ << " is not implented for Ethernet";
268 }
269 
TDLSDiscoverResponse(const std::string & peer_address)270 void Ethernet::TDLSDiscoverResponse(const std::string& peer_address) {
271   NOTREACHED() << __func__ << " is not implented for Ethernet";
272 }
273 
GetEapProvider()274 EthernetEapProvider* Ethernet::GetEapProvider() {
275   EthernetEapProvider* eap_provider = manager()->ethernet_eap_provider();
276   CHECK(eap_provider);
277   return eap_provider;
278 }
279 
GetEapService()280 ServiceConstRefPtr Ethernet::GetEapService() {
281   ServiceConstRefPtr eap_service = GetEapProvider()->service();
282   CHECK(eap_service);
283   return eap_service;
284 }
285 
OnEapDetected()286 void Ethernet::OnEapDetected() {
287   is_eap_detected_ = true;
288   eap_listener_->Stop();
289   GetEapProvider()->SetCredentialChangeCallback(
290       this,
291       base::Bind(&Ethernet::TryEapAuthentication,
292                  weak_ptr_factory_.GetWeakPtr()));
293   TryEapAuthentication();
294 }
295 
StartSupplicant()296 bool Ethernet::StartSupplicant() {
297   if (supplicant_interface_proxy_.get()) {
298     return true;
299   }
300 
301   string interface_path;
302   KeyValueStore create_interface_args;
303   create_interface_args.SetString(WPASupplicant::kInterfacePropertyName,
304                                   link_name());
305   create_interface_args.SetString(WPASupplicant::kInterfacePropertyDriver,
306                                   WPASupplicant::kDriverWired);
307   create_interface_args.SetString(WPASupplicant::kInterfacePropertyConfigFile,
308                                   WPASupplicant::kSupplicantConfPath);
309   if (!supplicant_process_proxy_->CreateInterface(create_interface_args,
310                                                   &interface_path)) {
311     // Interface might've already been created, try to retrieve it.
312     if (!supplicant_process_proxy_->GetInterface(link_name(),
313                                                  &interface_path)) {
314       LOG(ERROR) << __func__ << ": Failed to create interface with supplicant.";
315       StopSupplicant();
316       return false;
317     }
318   }
319 
320   supplicant_interface_proxy_.reset(
321       control_interface_->CreateSupplicantInterfaceProxy(this, interface_path));
322   supplicant_interface_path_ = interface_path;
323   return true;
324 }
325 
StartEapAuthentication()326 bool Ethernet::StartEapAuthentication() {
327   KeyValueStore params;
328   GetEapService()->eap()->PopulateSupplicantProperties(
329       &certificate_file_, &params);
330   params.SetString(WPASupplicant::kNetworkPropertyEapKeyManagement,
331                    WPASupplicant::kKeyManagementIeee8021X);
332   params.SetUint(WPASupplicant::kNetworkPropertyEapolFlags, 0);
333   params.SetUint(WPASupplicant::kNetworkPropertyScanSSID, 0);
334 
335   service_->ClearEAPCertification();
336   eap_state_handler_.Reset();
337 
338   if (!supplicant_network_path_.empty()) {
339     if (!supplicant_interface_proxy_->RemoveNetwork(supplicant_network_path_)) {
340       LOG(ERROR) << "Failed to remove network: " << supplicant_network_path_;
341       return false;
342     }
343   }
344   if (!supplicant_interface_proxy_->AddNetwork(params,
345                                                &supplicant_network_path_)) {
346     LOG(ERROR) << "Failed to add network";
347     return false;
348   }
349   CHECK(!supplicant_network_path_.empty());
350 
351   supplicant_interface_proxy_->SelectNetwork(supplicant_network_path_);
352   supplicant_interface_proxy_->EAPLogon();
353   return true;
354 }
355 
StopSupplicant()356 void Ethernet::StopSupplicant() {
357   if (supplicant_interface_proxy_.get()) {
358     supplicant_interface_proxy_->EAPLogoff();
359   }
360   supplicant_interface_proxy_.reset();
361   if (!supplicant_interface_path_.empty()) {
362     if (!supplicant_process_proxy_->RemoveInterface(
363         supplicant_interface_path_)) {
364       LOG(ERROR) << __func__ << ": Failed to remove interface from supplicant.";
365     }
366   }
367   supplicant_network_path_ = "";
368   supplicant_interface_path_ = "";
369   SetIsEapAuthenticated(false);
370 }
371 
SetIsEapAuthenticated(bool is_eap_authenticated)372 void Ethernet::SetIsEapAuthenticated(bool is_eap_authenticated) {
373   if (is_eap_authenticated == is_eap_authenticated_) {
374     return;
375   }
376 
377   // If our EAP authentication state changes, we have now joined a different
378   // network.  Restart the DHCP process and any other connection state.
379   DisconnectFrom(service_.get());
380   ConnectTo(service_.get());
381   is_eap_authenticated_ = is_eap_authenticated;
382   adaptor()->EmitBoolChanged(kEapAuthenticationCompletedProperty,
383                              is_eap_authenticated_);
384 }
385 
CertificationTask(const string & subject,uint32_t depth)386 void Ethernet::CertificationTask(const string& subject, uint32_t depth) {
387   CHECK(service_) << "Ethernet " << link_name() << " " << __func__
388                   << " with no service.";
389   service_->AddEAPCertification(subject, depth);
390 }
391 
EAPEventTask(const string & status,const string & parameter)392 void Ethernet::EAPEventTask(const string& status, const string& parameter) {
393   LOG(INFO) << "In " << __func__ << " with status " << status
394             << ", parameter " << parameter;
395   Service::ConnectFailure failure = Service::kFailureUnknown;
396   if (eap_state_handler_.ParseStatus(status, parameter, &failure)) {
397     LOG(INFO) << "EAP authentication succeeded!";
398     SetIsEapAuthenticated(true);
399   } else if (failure != Service::Service::kFailureUnknown) {
400     LOG(INFO) << "EAP authentication failed!";
401     SetIsEapAuthenticated(false);
402   }
403 }
404 
SupplicantStateChangedTask(const string & state)405 void Ethernet::SupplicantStateChangedTask(const string& state) {
406   LOG(INFO) << "Supplicant state changed to " << state;
407 }
408 
TryEapAuthenticationTask()409 void Ethernet::TryEapAuthenticationTask() {
410   if (!GetEapService()->Is8021xConnectable()) {
411     if (is_eap_authenticated_) {
412       LOG(INFO) << "EAP Service lost 802.1X credentials; "
413                 << "terminating EAP authentication.";
414     } else {
415       LOG(INFO) << "EAP Service lacks 802.1X credentials; "
416                 << "not doing EAP authentication.";
417     }
418     StopSupplicant();
419     return;
420   }
421 
422   if (!is_eap_detected_) {
423     LOG(WARNING) << "EAP authenticator not detected; "
424                  << "not doing EAP authentication.";
425     return;
426   }
427   if (!StartSupplicant()) {
428     LOG(ERROR) << "Failed to start supplicant.";
429     return;
430   }
431   StartEapAuthentication();
432 }
433 #endif  // DISABLE_WIRED_8021X
434 
SetupWakeOnLan()435 void Ethernet::SetupWakeOnLan() {
436   int sock;
437   struct ifreq interface_command;
438   struct ethtool_wolinfo wake_on_lan_command;
439 
440   if (link_name().length() >= sizeof(interface_command.ifr_name)) {
441     LOG(WARNING) << "Interface name " << link_name() << " too long: "
442                  << link_name().size() << " >= "
443                  << sizeof(interface_command.ifr_name);
444     return;
445   }
446 
447   sock = sockets_->Socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
448   if (sock < 0) {
449     LOG(WARNING) << "Failed to allocate socket: "
450                  << sockets_->ErrorString() << ".";
451     return;
452   }
453   ScopedSocketCloser socket_closer(sockets_.get(), sock);
454 
455   memset(&interface_command, 0, sizeof(interface_command));
456   memset(&wake_on_lan_command, 0, sizeof(wake_on_lan_command));
457   wake_on_lan_command.cmd = ETHTOOL_SWOL;
458   if (manager()->IsWakeOnLanEnabled()) {
459     wake_on_lan_command.wolopts = WAKE_MAGIC;
460   }
461   interface_command.ifr_data = &wake_on_lan_command;
462   memcpy(interface_command.ifr_name,
463          link_name().data(), link_name().length());
464 
465   int res = sockets_->Ioctl(sock, SIOCETHTOOL, &interface_command);
466   if (res < 0) {
467     LOG(WARNING) << "Failed to enable wake-on-lan: "
468                  << sockets_->ErrorString() << ".";
469     return;
470   }
471 }
472 
ConfigurePPPoEMode(const bool & enable,Error * error)473 bool Ethernet::ConfigurePPPoEMode(const bool& enable, Error* error) {
474 #if defined(DISABLE_PPPOE)
475   if (enable) {
476     LOG(WARNING) << "PPPoE support is not implemented.  Ignoring attempt "
477                  << "to configure " << link_name();
478     error->Populate(Error::kNotSupported);
479   }
480   return false;
481 #else
482   CHECK(service_);
483 
484   EthernetServiceRefPtr service = nullptr;
485   if (enable && service_->technology() != Technology::kPPPoE) {
486     service = CreatePPPoEService();
487   } else if (!enable && service_->technology() == Technology::kPPPoE) {
488     service = CreateEthernetService();
489   } else {
490     return false;
491   }
492 
493   CHECK(service);
494   service_->Disconnect(error, nullptr);
495   manager()->DeregisterService(service_);
496   service_ = service;
497   manager()->RegisterService(service_);
498 
499   return true;
500 #endif  // DISABLE_PPPOE
501 }
502 
GetPPPoEMode(Error * error)503 bool Ethernet::GetPPPoEMode(Error* error) {
504   if (service_ == nullptr) {
505     return false;
506   }
507   return service_->technology() == Technology::kPPPoE;
508 }
509 
ClearPPPoEMode(Error * error)510 void Ethernet::ClearPPPoEMode(Error* error) {
511   ConfigurePPPoEMode(false, error);
512 }
513 
CreateEthernetService()514 EthernetServiceRefPtr Ethernet::CreateEthernetService() {
515   return new EthernetService(control_interface_,
516                              dispatcher(),
517                              metrics(),
518                              manager(),
519                              weak_ptr_factory_.GetWeakPtr());
520 }
521 
CreatePPPoEService()522 EthernetServiceRefPtr Ethernet::CreatePPPoEService() {
523   return new PPPoEService(control_interface_,
524                           dispatcher(),
525                           metrics(),
526                           manager(),
527                           weak_ptr_factory_.GetWeakPtr());
528 }
529 
530 }  // namespace shill
531