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