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