1 #include "dbus_to_file_handler.hpp" 2 3 #include "common/utils.hpp" 4 5 #include <libpldm/file_io.h> 6 #include <libpldm/pldm.h> 7 8 #include <phosphor-logging/lg2.hpp> 9 10 PHOSPHOR_LOG2_USING; 11 12 namespace pldm 13 { 14 namespace requester 15 { 16 namespace oem_ibm 17 { 18 using namespace pldm::utils; 19 using namespace sdbusplus::bus::match::rules; 20 21 static constexpr auto resDumpObjPath = 22 "/xyz/openbmc_project/dump/resource/entry"; 23 static constexpr auto resDumpEntry = "com.ibm.Dump.Entry.Resource"; 24 static constexpr auto resDumpProgressIntf = 25 "xyz.openbmc_project.Common.Progress"; 26 static constexpr auto resDumpStatus = 27 "xyz.openbmc_project.Common.Progress.OperationStatus.Failed"; 28 29 DbusToFileHandler::DbusToFileHandler( 30 int mctp_fd, uint8_t mctp_eid, dbus_api::Requester* requester, 31 sdbusplus::message::object_path resDumpCurrentObjPath, 32 pldm::requester::Handler<pldm::requester::Request>* handler) : 33 mctp_fd(mctp_fd), 34 mctp_eid(mctp_eid), requester(requester), 35 resDumpCurrentObjPath(resDumpCurrentObjPath), handler(handler) 36 {} 37 38 void DbusToFileHandler::sendNewFileAvailableCmd(uint64_t fileSize) 39 { 40 if (requester == NULL) 41 { 42 error( 43 "Failed to send resource dump parameters as requester is not set"); 44 pldm::utils::reportError( 45 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 46 return; 47 } 48 auto instanceId = requester->getInstanceId(mctp_eid); 49 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 50 PLDM_NEW_FILE_REQ_BYTES); 51 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 52 // Need to revisit this logic at the time of multiple resource dump support 53 uint32_t fileHandle = 1; 54 55 auto rc = encode_new_file_req(instanceId, 56 PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS, 57 fileHandle, fileSize, request); 58 if (rc != PLDM_SUCCESS) 59 { 60 requester->markFree(mctp_eid, instanceId); 61 error("Failed to encode_new_file_req, rc = {RC}", "RC", rc); 62 return; 63 } 64 65 auto newFileAvailableRespHandler = [this](mctp_eid_t /*eid*/, 66 const pldm_msg* response, 67 size_t respMsgLen) { 68 if (response == nullptr || !respMsgLen) 69 { 70 error("Failed to receive response for NewFileAvailable command"); 71 return; 72 } 73 uint8_t completionCode{}; 74 auto rc = decode_new_file_resp(response, respMsgLen, &completionCode); 75 if (rc || completionCode) 76 { 77 error( 78 "Failed to decode_new_file_resp or Host returned error for new_file_available rc={RC}, cc = {CC}", 79 "RC", rc, "CC", static_cast<unsigned>(completionCode)); 80 reportResourceDumpFailure(); 81 } 82 }; 83 rc = handler->registerRequest( 84 mctp_eid, instanceId, PLDM_OEM, PLDM_NEW_FILE_AVAILABLE, 85 std::move(requestMsg), std::move(newFileAvailableRespHandler)); 86 if (rc) 87 { 88 error("Failed to send NewFileAvailable Request to Host"); 89 reportResourceDumpFailure(); 90 } 91 } 92 93 void DbusToFileHandler::reportResourceDumpFailure() 94 { 95 pldm::utils::reportError("xyz.openbmc_project.bmc.pldm.InternalFailure"); 96 97 PropertyValue value{resDumpStatus}; 98 DBusMapping dbusMapping{resDumpCurrentObjPath, resDumpProgressIntf, 99 "Status", "string"}; 100 try 101 { 102 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value); 103 } 104 catch (const std::exception& e) 105 { 106 error("failed to set resource dump operation status, ERROR={ERR_EXCEP}", 107 "ERR_EXCEP", e.what()); 108 } 109 } 110 111 void DbusToFileHandler::processNewResourceDump( 112 const std::string& vspString, const std::string& resDumpReqPass) 113 { 114 try 115 { 116 std::string objPath = resDumpCurrentObjPath; 117 auto propVal = pldm::utils::DBusHandler().getDbusPropertyVariant( 118 objPath.c_str(), "Status", resDumpProgressIntf); 119 const auto& curResDumpStatus = std::get<ResDumpStatus>(propVal); 120 121 if (curResDumpStatus != 122 "xyz.openbmc_project.Common.Progress.OperationStatus.InProgress") 123 { 124 return; 125 } 126 } 127 catch (const sdbusplus::exception_t& e) 128 { 129 error( 130 "Error {ERR_EXCEP} found in getting current resource dump status while initiating a new resource dump with objPath={DUMP_OBJ_PATH} and intf={DUMP_PROG_INTF}", 131 "ERR_EXCEP", e.what(), "DUMP_OBJ_PATH", 132 resDumpCurrentObjPath.str.c_str(), "DUMP_PROG_INTF", 133 resDumpProgressIntf); 134 } 135 136 namespace fs = std::filesystem; 137 const fs::path resDumpDirPath = "/var/lib/pldm/resourcedump"; 138 139 if (!fs::exists(resDumpDirPath)) 140 { 141 fs::create_directories(resDumpDirPath); 142 } 143 144 // Need to reconsider this logic to set the value as "1" when we have the 145 // support to handle multiple resource dumps 146 fs::path resDumpFilePath = resDumpDirPath / "1"; 147 148 std::ofstream fileHandle; 149 fileHandle.open(resDumpFilePath, std::ios::out | std::ofstream::binary); 150 151 if (!fileHandle) 152 { 153 error("resource dump file open error:{RES_DUMP_PATH}", "RES_DUMP_PATH", 154 resDumpFilePath); 155 PropertyValue value{resDumpStatus}; 156 DBusMapping dbusMapping{resDumpCurrentObjPath, resDumpProgressIntf, 157 "Status", "string"}; 158 try 159 { 160 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value); 161 } 162 catch (const std::exception& e) 163 { 164 error( 165 "failed to set resource dump operation status, ERROR={ERR_EXCEP}", 166 "ERR_EXCEP", e.what()); 167 } 168 return; 169 } 170 171 // Fill up the file with resource dump parameters and respective sizes 172 auto fileFunc = [&fileHandle](auto& paramBuf) { 173 uint32_t paramSize = paramBuf.size(); 174 fileHandle.write((char*)¶mSize, sizeof(paramSize)); 175 fileHandle << paramBuf; 176 }; 177 fileFunc(vspString); 178 fileFunc(resDumpReqPass); 179 180 std::string str; 181 if (!resDumpReqPass.empty()) 182 { 183 str = getAcfFileContent(); 184 } 185 186 fileFunc(str); 187 188 fileHandle.close(); 189 size_t fileSize = fs::file_size(resDumpFilePath); 190 191 sendNewFileAvailableCmd(fileSize); 192 } 193 194 std::string DbusToFileHandler::getAcfFileContent() 195 { 196 std::string str; 197 static constexpr auto acfDirPath = "/etc/acf/service.acf"; 198 if (fs::exists(acfDirPath)) 199 { 200 std::ifstream file; 201 file.open(acfDirPath); 202 std::stringstream acfBuf; 203 acfBuf << file.rdbuf(); 204 str = acfBuf.str(); 205 file.close(); 206 } 207 return str; 208 } 209 210 void DbusToFileHandler::newCsrFileAvailable(const std::string& csr, 211 const std::string fileHandle) 212 { 213 namespace fs = std::filesystem; 214 std::string dirPath = "/var/lib/ibm/bmcweb"; 215 const fs::path certDirPath = dirPath; 216 217 if (!fs::exists(certDirPath)) 218 { 219 fs::create_directories(certDirPath); 220 fs::permissions(certDirPath, 221 fs::perms::others_read | fs::perms::owner_write); 222 } 223 224 fs::path certFilePath = certDirPath / ("CSR_" + fileHandle); 225 std::ofstream certFile; 226 227 certFile.open(certFilePath, std::ios::out | std::ofstream::binary); 228 229 if (!certFile) 230 { 231 error("cert file open error: {CERT_PATH}", "CERT_PATH", 232 certFilePath.c_str()); 233 return; 234 } 235 236 // Add csr to file 237 certFile << csr << std::endl; 238 239 certFile.close(); 240 uint32_t fileSize = fs::file_size(certFilePath); 241 242 newFileAvailableSendToHost(fileSize, (uint32_t)stoi(fileHandle), 243 PLDM_FILE_TYPE_CERT_SIGNING_REQUEST); 244 } 245 246 void DbusToFileHandler::newFileAvailableSendToHost(const uint32_t fileSize, 247 const uint32_t fileHandle, 248 const uint16_t type) 249 { 250 if (requester == NULL) 251 { 252 error("Failed to send csr to host."); 253 pldm::utils::reportError( 254 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 255 return; 256 } 257 auto instanceId = requester->getInstanceId(mctp_eid); 258 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 259 PLDM_NEW_FILE_REQ_BYTES); 260 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 261 262 auto rc = encode_new_file_req(instanceId, type, fileHandle, fileSize, 263 request); 264 if (rc != PLDM_SUCCESS) 265 { 266 requester->markFree(mctp_eid, instanceId); 267 error("Failed to encode_new_file_req, rc = {RC}", "RC", rc); 268 return; 269 } 270 auto newFileAvailableRespHandler = 271 [](mctp_eid_t /*eid*/, const pldm_msg* response, size_t respMsgLen) { 272 if (response == nullptr || !respMsgLen) 273 { 274 error( 275 "Failed to receive response for NewFileAvailable command for vmi"); 276 return; 277 } 278 uint8_t completionCode{}; 279 auto rc = decode_new_file_resp(response, respMsgLen, &completionCode); 280 if (rc || completionCode) 281 { 282 error( 283 "Failed to decode_new_file_resp for vmi, or Host returned error for new_file_available rc = {RC}, cc = {CC}", 284 "RC", rc, "CC", static_cast<unsigned>(completionCode)); 285 pldm::utils::reportError( 286 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 287 } 288 }; 289 rc = handler->registerRequest( 290 mctp_eid, instanceId, PLDM_OEM, PLDM_NEW_FILE_AVAILABLE, 291 std::move(requestMsg), std::move(newFileAvailableRespHandler)); 292 if (rc) 293 { 294 error("Failed to send NewFileAvailable Request to Host for vmi"); 295 pldm::utils::reportError( 296 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 297 } 298 } 299 300 } // namespace oem_ibm 301 } // namespace requester 302 } // namespace pldm 303