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; 66 static string ObjectID(Ethernet* e) { return e->GetRpcIdentifier(); } 67 } 68 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 118 Ethernet::~Ethernet() { 119 } 120 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 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 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 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 194 bool Ethernet::Save(StoreInterface* storage) { 195 const string id = GetStorageIdentifier(); 196 storage->SetBool(id, kPPPoEProperty, GetPPPoEMode(nullptr)); 197 return true; 198 } 199 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 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) 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 231 void Ethernet::BSSAdded(const string& path, const KeyValueStore& properties) { 232 NOTREACHED() << __func__ << " is not implemented for Ethernet"; 233 } 234 235 void Ethernet::BSSRemoved(const string& path) { 236 NOTREACHED() << __func__ << " is not implemented for Ethernet"; 237 } 238 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 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 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 266 void Ethernet::ScanDone(const bool& /*success*/) { 267 NOTREACHED() << __func__ << " is not implented for Ethernet"; 268 } 269 270 void Ethernet::TDLSDiscoverResponse(const std::string& peer_address) { 271 NOTREACHED() << __func__ << " is not implented for Ethernet"; 272 } 273 274 EthernetEapProvider* Ethernet::GetEapProvider() { 275 EthernetEapProvider* eap_provider = manager()->ethernet_eap_provider(); 276 CHECK(eap_provider); 277 return eap_provider; 278 } 279 280 ServiceConstRefPtr Ethernet::GetEapService() { 281 ServiceConstRefPtr eap_service = GetEapProvider()->service(); 282 CHECK(eap_service); 283 return eap_service; 284 } 285 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 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 326 bool Ethernet::StartEapAuthentication() { 327 KeyValueStore params; 328 GetEapService()->eap()->PopulateSupplicantProperties( 329 &certificate_file_, ¶ms); 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 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 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 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 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 405 void Ethernet::SupplicantStateChangedTask(const string& state) { 406 LOG(INFO) << "Supplicant state changed to " << state; 407 } 408 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 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 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 503 bool Ethernet::GetPPPoEMode(Error* error) { 504 if (service_ == nullptr) { 505 return false; 506 } 507 return service_->technology() == Technology::kPPPoE; 508 } 509 510 void Ethernet::ClearPPPoEMode(Error* error) { 511 ConfigurePPPoEMode(false, error); 512 } 513 514 EthernetServiceRefPtr Ethernet::CreateEthernetService() { 515 return new EthernetService(control_interface_, 516 dispatcher(), 517 metrics(), 518 manager(), 519 weak_ptr_factory_.GetWeakPtr()); 520 } 521 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