blob: bd581c7c1cb036db131c6c0720506fc03ab68503 [file] [log] [blame]
// 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