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