| // Copyright 2019 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "shill/ethernet/ethernet_provider.h" |
| |
| #include <string> |
| |
| #include "shill/ethernet/ethernet_service.h" |
| #include "shill/ethernet/ethernet_temporary_service.h" |
| #include "shill/logging.h" |
| #include "shill/manager.h" |
| #include "shill/store_interface.h" |
| |
| using std::string; |
| |
| namespace shill { |
| |
| namespace Logging { |
| static auto kModuleLogScope = ScopeLogger::kEthernet; |
| static string ObjectID(const EthernetProvider* e) { |
| return "(ethernet_provider)"; |
| } |
| } // namespace Logging |
| |
| EthernetProvider::EthernetProvider(Manager* manager) : manager_(manager) {} |
| |
| EthernetProvider::~EthernetProvider() = default; |
| |
| void EthernetProvider::CreateServicesFromProfile(const ProfileRefPtr& profile) { |
| SLOG(this, 2) << __func__; |
| // Since the EthernetProvider's service is created during Start(), |
| // there is no need to do anything in this method. |
| } |
| |
| ServiceRefPtr EthernetProvider::FindSimilarService(const KeyValueStore& args, |
| Error* error) const { |
| CHECK_EQ(kTypeEthernet, args.Lookup<string>(kTypeProperty, "")) |
| << "Service type must be Ethernet!"; |
| ServiceRefPtr service = manager_->GetFirstEthernetService(); |
| if (service) { |
| return service; |
| } |
| return service_; |
| } |
| |
| ServiceRefPtr EthernetProvider::GetService(const KeyValueStore& args, |
| Error* error) { |
| SLOG(this, 2) << __func__; |
| return FindSimilarService(args, error); |
| } |
| |
| ServiceRefPtr EthernetProvider::CreateTemporaryService( |
| const KeyValueStore& args, Error* error) { |
| SLOG(this, 2) << __func__; |
| return new EthernetTemporaryService( |
| manager_, EthernetService::kDefaultEthernetDeviceIdentifier); |
| } |
| |
| ServiceRefPtr EthernetProvider::CreateTemporaryServiceFromProfile( |
| const ProfileRefPtr& profile, const std::string& entry_name, Error* error) { |
| SLOG(this, 2) << __func__; |
| return new EthernetTemporaryService(manager_, entry_name); |
| } |
| |
| EthernetServiceRefPtr EthernetProvider::CreateService( |
| base::WeakPtr<Ethernet> ethernet) { |
| SLOG(this, 2) << __func__; |
| if (!service_->HasEthernet()) { |
| service_->SetEthernet(ethernet); |
| return service_; |
| } |
| return new EthernetService(manager_, EthernetService::Properties(ethernet)); |
| } |
| |
| void EthernetProvider::RegisterService(EthernetServiceRefPtr service) { |
| SLOG(this, 2) << __func__; |
| CHECK(service); |
| // Add the service to the services_ list and register it with the Manager. |
| // A service is registered with the Manager if and only if it is also |
| // registered with the EthernetProvider. |
| if (base::Contains(services_, service)) { |
| LOG(INFO) << "Reusing existing Ethernet service."; |
| return; |
| } |
| services_.push_back(service); |
| manager_->RegisterService(service); |
| } |
| |
| void EthernetProvider::DeregisterService(EthernetServiceRefPtr service) { |
| SLOG(this, 2) << __func__; |
| CHECK(service); |
| // Remove the service from the services_ list if it is not the only remaining |
| // service. Otherwise, turn it into the ethernet_any service. A service is |
| // deregistered with the Manager if and only if it is also deregistered with |
| // the EthernetProvider. |
| CHECK(base::Contains(services_, service)) |
| << "De-registering an unregistered service"; |
| if (services_.size() == 1 && service->HasEthernet()) { |
| service->ResetEthernet(); |
| return; |
| } |
| base::Erase(services_, service); |
| manager_->DeregisterService(service); |
| } |
| |
| EthernetServiceRefPtr EthernetProvider::FindEthernetServiceForService( |
| ServiceRefPtr service) const { |
| CHECK(service); |
| for (const auto& s : services_) { |
| if (s->serial_number() == service->serial_number()) { |
| return s; |
| } |
| } |
| return nullptr; |
| } |
| |
| bool EthernetProvider::LoadGenericEthernetService() { |
| SLOG(this, 2) << __func__; |
| return manager_->ActiveProfile()->LoadService(service_); |
| } |
| |
| void EthernetProvider::RefreshGenericEthernetService() { |
| // Make sure that the first Ethernet service is the generic Ethernet service. |
| // This is to ensure that the preferred/default Ethernet service is the one |
| // being configured. |
| ServiceRefPtr first_ethernet_service = manager_->GetFirstEthernetService(); |
| CHECK(first_ethernet_service); |
| if (first_ethernet_service == service_) { |
| return; |
| } |
| |
| // The first Ethernet service has changed. Remove the ethernet_any storage ID |
| // from the old ethernet_any service and configure it according to its new |
| // storage ID (MAC address of the associated device). If it has no associated |
| // Device, release the service as there should no longer be any other |
| // references to it. |
| service_->ResetStorageIdentifier(); |
| if (base::Contains(services_, service_)) { |
| if (service_->HasEthernet()) { |
| manager_->MatchProfileWithService(service_); |
| } else { |
| // There's no associated Device and it's no longer the ethernet_any |
| // service. Get rid of this service completely. |
| DeregisterService(service_); |
| } |
| } |
| |
| // Set the storage ID of the new first Ethernet service to be ethernet_any and |
| // configure it accordingly. |
| service_ = FindEthernetServiceForService(first_ethernet_service); |
| service_->SetStorageIdentifier( |
| EthernetService::kDefaultEthernetDeviceIdentifier); |
| manager_->MatchProfileWithService(service_); |
| } |
| |
| void EthernetProvider::Start() { |
| SLOG(this, 2) << __func__; |
| // Create a generic Ethernet service with storage ID "ethernet_any". This will |
| // be used to store configurations if any are pushed down from Chrome before |
| // any Ethernet devices are initialized. This will also be used to persist |
| // static IP configurations across Ethernet services. |
| if (!service_) { |
| service_ = new EthernetService( |
| manager_, EthernetService::Properties( |
| EthernetService::kDefaultEthernetDeviceIdentifier)); |
| } |
| RegisterService(service_); |
| } |
| |
| void EthernetProvider::Stop() { |
| SLOG(this, 2) << __func__; |
| while (!services_.empty()) { |
| EthernetServiceRefPtr service = services_.back(); |
| DeregisterService(service); |
| } |
| // Do not destroy the service, since devices may or may not have been |
| // removed as the provider is stopped, and we'd like them to continue |
| // to refer to the same service on restart. |
| } |
| |
| } // namespace shill |