#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 requestMsg(sizeof(pldm_msg_hdr) + PLDM_NEW_FILE_REQ_BYTES + fileSize); auto request = reinterpret_cast(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 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(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(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*)¶mSize, 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 requestMsg(sizeof(pldm_msg_hdr) + PLDM_NEW_FILE_REQ_BYTES); auto request = reinterpret_cast(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 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(responseMsgPtr.get()); rc = decode_new_file_resp(responsePtr, PLDM_NEW_FILE_RESP_BYTES, &completionCode); std::vector 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(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