blob: e256bc8d9354d6d3451dca20129811a751544086 [file] [log] [blame]
#include "dbus_to_file_handler.hpp"
#include "libpldm/requester/pldm.h"
#include "oem/ibm/libpldm/file_io.h"
#include "common/utils.hpp"
namespace pldm
{
namespace requester
{
namespace oem_ibm
{
using namespace pldm::utils;
using namespace sdbusplus::bus::match::rules;
static constexpr auto resDumpObjPath =
"/xyz/openbmc_project/dump/resource/entry";
static constexpr auto resDumpEntry = "com.ibm.Dump.Entry.Resource";
static constexpr auto resDumpProgressIntf =
"xyz.openbmc_project.Common.Progress";
static constexpr auto resDumpStatus =
"xyz.openbmc_project.Common.Progress.OperationStatus.Failed";
DbusToFileHandler::DbusToFileHandler(
int mctp_fd, uint8_t mctp_eid, dbus_api::Requester* requester,
sdbusplus::message::object_path resDumpCurrentObjPath) :
mctp_fd(mctp_fd),
mctp_eid(mctp_eid), requester(requester),
resDumpCurrentObjPath(resDumpCurrentObjPath)
{}
void DbusToFileHandler::sendNewFileAvailableCmd(uint64_t fileSize)
{
if (requester == NULL)
{
std::cerr << "Failed to send resource dump parameters as requester is "
"not set";
pldm::utils::reportError(
"xyz.openbmc_project.bmc.pldm.InternalFailure");
return;
}
auto instanceId = requester->getInstanceId(mctp_eid);
std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
PLDM_NEW_FILE_REQ_BYTES + fileSize);
auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
// Need to revisit this logic at the time of multiple resource dump support
uint32_t fileHandle = 1;
auto rc =
encode_new_file_req(instanceId, PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS,
fileHandle, fileSize, request);
if (rc != PLDM_SUCCESS)
{
requester->markFree(mctp_eid, instanceId);
std::cerr << "Failed to encode_new_file_req, rc = " << rc << std::endl;
return;
}
uint8_t* responseMsg = nullptr;
size_t responseMsgSize{};
auto requesterRc =
pldm_send_recv(mctp_eid, mctp_fd, requestMsg.data(), requestMsg.size(),
&responseMsg, &responseMsgSize);
std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{responseMsg,
std::free};
requester->markFree(mctp_eid, instanceId);
bool isDecodeNewFileRespFailed = false;
if (requesterRc != PLDM_REQUESTER_SUCCESS)
{
std::cerr << "Failed to send resource dump parameters, rc = "
<< requesterRc << std::endl;
}
else
{
uint8_t completionCode{};
auto responsePtr =
reinterpret_cast<struct pldm_msg*>(responseMsgPtr.get());
rc = decode_new_file_resp(responsePtr, PLDM_NEW_FILE_RESP_BYTES,
&completionCode);
if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
{
std::cerr << "Failed to decode_new_file_resp: "
<< "rc=" << rc
<< ", cc=" << static_cast<unsigned>(completionCode)
<< std::endl;
isDecodeNewFileRespFailed = true;
}
}
if ((requesterRc != PLDM_REQUESTER_SUCCESS) || (isDecodeNewFileRespFailed))
{
pldm::utils::reportError(
"xyz.openbmc_project.bmc.pldm.InternalFailure");
PropertyValue value{resDumpStatus};
DBusMapping dbusMapping{resDumpCurrentObjPath, resDumpProgressIntf,
"Status", "string"};
try
{
pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
}
catch (const std::exception& e)
{
std::cerr << "failed to set resource dump operation status, "
"ERROR="
<< e.what() << "\n";
}
}
}
void DbusToFileHandler::processNewResourceDump(
const std::string& vspString, const std::string& resDumpReqPass)
{
// This needs special handling in later point of time. Resource dump without
// the vsp string is supposed to be a non-disruptive system dump.
if (vspString.empty())
{
std::cerr << "Empty vsp string"
<< "\n";
PropertyValue value{resDumpStatus};
DBusMapping dbusMapping{resDumpCurrentObjPath, resDumpProgressIntf,
"Status", "string"};
try
{
pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
}
catch (const std::exception& e)
{
std::cerr << "failed to set resource dump operation status, "
"ERROR="
<< e.what() << "\n";
}
return;
}
namespace fs = std::filesystem;
const fs::path resDumpDirPath = "/var/lib/pldm/resourcedump";
if (!fs::exists(resDumpDirPath))
{
fs::create_directories(resDumpDirPath);
}
// Need to reconsider this logic to set the value as "1" when we have the
// support to handle multiple resource dumps
fs::path resDumpFilePath = resDumpDirPath / "1";
std::ofstream fileHandle;
fileHandle.open(resDumpFilePath, std::ios::out | std::ofstream::binary);
if (!fileHandle)
{
std::cerr << "resource dump file open error: " << resDumpFilePath
<< "\n";
PropertyValue value{resDumpStatus};
DBusMapping dbusMapping{resDumpCurrentObjPath, resDumpProgressIntf,
"Status", "string"};
try
{
pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
}
catch (const std::exception& e)
{
std::cerr << "failed to set resource dump operation status, "
"ERROR="
<< e.what() << "\n";
}
return;
}
// Fill up the file with resource dump parameters and respective sizes
auto fileFunc = [&fileHandle](auto& paramBuf) {
uint32_t paramSize = paramBuf.size();
fileHandle.write((char*)&paramSize, sizeof(paramSize));
fileHandle << paramBuf;
};
fileFunc(vspString);
fileFunc(resDumpReqPass);
fileHandle.close();
size_t fileSize = fs::file_size(resDumpFilePath);
sendNewFileAvailableCmd(fileSize);
}
void DbusToFileHandler::newCsrFileAvailable(const std::string& csr,
const std::string fileHandle)
{
namespace fs = std::filesystem;
std::string dirPath = "/var/lib/ibm/bmcweb";
const fs::path certDirPath = dirPath;
if (!fs::exists(certDirPath))
{
fs::create_directories(certDirPath);
fs::permissions(certDirPath,
fs::perms::others_read | fs::perms::owner_write);
}
fs::path certFilePath = certDirPath / ("CSR_" + fileHandle);
std::ofstream certFile;
certFile.open(certFilePath, std::ios::out | std::ofstream::binary);
if (!certFile)
{
std::cerr << "cert file open error: " << certFilePath << "\n";
return;
}
// Add csr to file
certFile << csr << std::endl;
certFile.close();
uint32_t fileSize = fs::file_size(certFilePath);
newFileAvailableSendToHost(fileSize, (uint32_t)stoi(fileHandle),
PLDM_FILE_TYPE_CERT_SIGNING_REQUEST);
}
void DbusToFileHandler::newFileAvailableSendToHost(const uint32_t fileSize,
const uint32_t fileHandle,
const uint16_t type)
{
if (requester == NULL)
{
std::cerr << "Failed to send csr to host.";
pldm::utils::reportError(
"xyz.openbmc_project.bmc.pldm.InternalFailure");
return;
}
auto instanceId = requester->getInstanceId(mctp_eid);
std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
PLDM_NEW_FILE_REQ_BYTES);
auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
auto rc =
encode_new_file_req(instanceId, type, fileHandle, fileSize, request);
if (rc != PLDM_SUCCESS)
{
requester->markFree(mctp_eid, instanceId);
std::cerr << "Failed to encode_new_file_req, rc = " << rc << std::endl;
return;
}
uint8_t* responseMsg = nullptr;
size_t responseMsgSize{};
auto requesterRc =
pldm_send_recv(mctp_eid, mctp_fd, requestMsg.data(), requestMsg.size(),
&responseMsg, &responseMsgSize);
std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{responseMsg,
std::free};
requester->markFree(mctp_eid, instanceId);
bool isDecodeNewFileRespFailed = false;
if (requesterRc != PLDM_REQUESTER_SUCCESS)
{
std::cerr << "Failed to send file to host, rc = " << requesterRc
<< std::endl;
}
else
{
uint8_t completionCode{};
auto responsePtr =
reinterpret_cast<struct pldm_msg*>(responseMsgPtr.get());
rc = decode_new_file_resp(responsePtr, PLDM_NEW_FILE_RESP_BYTES,
&completionCode);
std::vector<uint8_t> responseMsgVec;
responseMsgVec.resize(responseMsgSize);
memcpy(responseMsgVec.data(), responseMsg, responseMsgVec.size());
if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
{
std::cerr << "Failed to decode_new_file_resp: "
<< "rc=" << rc
<< ", cc=" << static_cast<unsigned>(completionCode)
<< std::endl;
isDecodeNewFileRespFailed = true;
}
}
if ((requesterRc != PLDM_REQUESTER_SUCCESS) || (isDecodeNewFileRespFailed))
{
pldm::utils::reportError(
"xyz.openbmc_project.bmc.pldm.InternalFailure");
}
}
} // namespace oem_ibm
} // namespace requester
} // namespace pldm