blob: dd43b4aa0c856bafbcb4ac3ea568666a8dd8d8c9 [file] [log] [blame]
// Copyright 2021 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 "trunks/csme/mei_client_factory.h"
#include <memory>
#include <string>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <linux/uuid.h>
#include "trunks/csme/mei_client.h"
#include "trunks/csme/mei_client_char_device.h"
#include "trunks/csme/mei_client_socket.h"
namespace trunks {
namespace csme {
namespace {
constexpr uuid_le kCoreGuid = UUID_LE(
0x989e0b6f, 0xda76, 0x45d7, 0x92, 0x99, 0xa4, 0x07, 0x9d, 0x7e, 0x22, 0xb1);
constexpr uuid_le kProvisionGuid = UUID_LE(
0x168dbc9c, 0xf757, 0x4eed, 0xa2, 0xd8, 0x94, 0xa3, 0xb7, 0x0f, 0x26, 0xc2);
constexpr uuid_le kTpmTunnelGuid = UUID_LE(
0xa6103662, 0x23a6, 0x4315, 0xa5, 0x3b, 0x74, 0x9d, 0x91, 0xca, 0xee, 0x17);
constexpr char kDefaultMeiDevicePath[] = "/dev/mei0";
constexpr char kDefaultSocketConfigPath[] = "/run/pinweaver_socket.config";
} // namespace
MeiClientFactory::MeiClientFactory(const std::string& socket_config_path,
const std::string& char_device_path)
: socket_config_path_(socket_config_path),
char_device_path_(char_device_path) {}
MeiClientFactory::MeiClientFactory()
: socket_config_path_(kDefaultSocketConfigPath),
char_device_path_(kDefaultMeiDevicePath) {}
std::unique_ptr<MeiClient> MeiClientFactory::CreateMeiClient(
const std::string path, const uuid_le& guid) {
switch (GetMeiConnectionType()) {
case MeiConnectionType::kUnknown:
LOG(FATAL) << __func__ << ": Unknown connection type.";
break;
case MeiConnectionType::kSocket:
#if !USE_CSME_EMULATOR
LOG(FATAL) << __func__ << ": socket-based connection is not allowed.";
#endif
return std::unique_ptr<MeiClient>(new MeiClientSocket(path, guid));
case MeiConnectionType::kCharacterDevice:
return std::unique_ptr<MeiClient>(new MeiClientCharDevice(path, guid));
}
return nullptr;
}
std::unique_ptr<MeiClient> MeiClientFactory::CreateMeiClientForPinWeaverCore() {
return CreateMeiClient(GetCoreMeiPath(), kCoreGuid);
}
std::unique_ptr<MeiClient>
MeiClientFactory::CreateMeiClientForPinWeaverProvision() {
return CreateMeiClient(GetProvisionMeiPath(), kProvisionGuid);
}
std::unique_ptr<MeiClient>
MeiClientFactory::CreateMeiClientForPinWeaverTpmTunnel() {
return CreateMeiClient(GetTpmTunnelMeiPath(), kTpmTunnelGuid);
}
MeiClientFactory::MeiConnectionType MeiClientFactory::GetMeiConnectionType() {
DetermineMeiConnectionType();
return mei_client_type_;
}
std::string MeiClientFactory::GetMeiPath(
MeiClientFactory::MeiFunctionType function_type) {
switch (GetMeiConnectionType()) {
case MeiConnectionType::kUnknown:
LOG(DFATAL) << __func__ << ": Unknown Mei client type.";
return "";
case MeiConnectionType::kCharacterDevice:
return char_device_path_;
case MeiConnectionType::kSocket:
return socket_paths_[static_cast<int>(function_type)];
}
}
std::string MeiClientFactory::GetCoreMeiPath() {
return GetMeiPath(MeiFunctionType::kCore);
}
std::string MeiClientFactory::GetProvisionMeiPath() {
return GetMeiPath(MeiFunctionType::kProvision);
}
std::string MeiClientFactory::GetTpmTunnelMeiPath() {
return GetMeiPath(MeiFunctionType::kTpmTunnel);
}
void MeiClientFactory::DetermineMeiConnectionType() {
if (mei_client_type_ != MeiConnectionType::kUnknown) {
return;
}
if (ReadSocketConfig()) {
mei_client_type_ = MeiConnectionType::kSocket;
} else {
mei_client_type_ = MeiConnectionType::kCharacterDevice;
}
}
bool MeiClientFactory::ReadSocketConfig() {
const base::FilePath config_path(socket_config_path_);
if (!base::PathExists(config_path)) {
return false;
}
std::string config_str;
if (!base::ReadFileToString(config_path, &config_str)) {
LOG(ERROR) << __func__ << ": Failed to read socket config at "
<< socket_config_path_;
return false;
}
int index = 0;
for (std::string& s : socket_paths_) {
s.clear();
}
while (index < socket_paths_.size()) {
size_t pos = config_str.find('\n');
if (pos == std::string::npos) {
socket_paths_[index] = config_str;
} else {
socket_paths_[index] = config_str.substr(0, pos);
config_str = config_str.substr(pos + 1);
}
index += 1;
}
for (const std::string& s : socket_paths_) {
if (s.empty()) {
LOG(ERROR) << __func__ << ": Empty path.";
return false;
}
}
return true;
}
} // namespace csme
} // namespace trunks