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_eid(mctp_eid), instanceIdDb(instanceIdDb), 30 resDumpCurrentObjPath(resDumpCurrentObjPath), handler(handler) 31 {} 32 33 void DbusToFileHandler::sendNewFileAvailableCmd(uint64_t fileSize) 34 { 35 if (instanceIdDb == NULL) 36 { 37 error( 38 "Failed to send resource dump parameters as instance ID DB is not set"); 39 pldm::utils::reportError( 40 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 41 return; 42 } 43 auto instanceId = instanceIdDb->next(mctp_eid); 44 std::vector<uint8_t> requestMsg( 45 sizeof(pldm_msg_hdr) + PLDM_NEW_FILE_REQ_BYTES); 46 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 47 // Need to revisit this logic at the time of multiple resource dump support 48 uint32_t fileHandle = 1; 49 50 auto rc = 51 encode_new_file_req(instanceId, PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS, 52 fileHandle, fileSize, request); 53 if (rc != PLDM_SUCCESS) 54 { 55 instanceIdDb->free(mctp_eid, instanceId); 56 error("Failed to encode new file request with response code '{RC}'", 57 "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 available response or remote terminus returned error, response code '{RC}' and completion code '{CC}'", 75 "RC", rc, "CC", completionCode); 76 reportResourceDumpFailure("DecodeNewFileResp"); 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( 85 "Failed to send NewFileAvailable Request to Host, response code '{RC}'", 86 "RC", rc); 87 reportResourceDumpFailure("NewFileAvailableRequest"); 88 } 89 } 90 91 void DbusToFileHandler::reportResourceDumpFailure(const std::string_view& str) 92 { 93 std::string s = "xyz.openbmc_project.PLDM.Error.ReportResourceDumpFail."; 94 s += str; 95 96 pldm::utils::reportError(s.c_str()); 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 error("Failed to set resource dump operation status, error - {ERROR}", 108 "ERROR", e); 109 } 110 } 111 112 void DbusToFileHandler::processNewResourceDump( 113 const std::string& vspString, const std::string& resDumpReqPass) 114 { 115 try 116 { 117 std::string objPath = resDumpCurrentObjPath; 118 auto propVal = pldm::utils::DBusHandler().getDbusPropertyVariant( 119 objPath.c_str(), "Status", resDumpProgressIntf); 120 const auto& curResDumpStatus = std::get<ResDumpStatus>(propVal); 121 122 if (curResDumpStatus != 123 "xyz.openbmc_project.Common.Progress.OperationStatus.InProgress") 124 { 125 return; 126 } 127 } 128 catch (const sdbusplus::exception_t& e) 129 { 130 error( 131 "Error '{ERROR}' found in getting current resource dump status while initiating a new resource dump with object path '{PATH}' and interface {INTERFACE}", 132 "ERROR", e, "PATH", resDumpCurrentObjPath, "INTERFACE", 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("Failed to open resource dump file '{PATH}'", "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 - {ERROR}", 166 "ERROR", e); 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("Failed to open certificate file '{PATH}'", "PATH", certFilePath); 232 return; 233 } 234 235 // Add csr to file 236 certFile << csr << std::endl; 237 238 certFile.close(); 239 uint32_t fileSize = fs::file_size(certFilePath); 240 241 newFileAvailableSendToHost(fileSize, (uint32_t)stoi(fileHandle), 242 PLDM_FILE_TYPE_CERT_SIGNING_REQUEST); 243 } 244 245 void DbusToFileHandler::newFileAvailableSendToHost( 246 const uint32_t fileSize, const uint32_t fileHandle, const uint16_t type) 247 { 248 if (instanceIdDb == NULL) 249 { 250 error("Failed to send csr to remote terminus."); 251 pldm::utils::reportError( 252 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 253 return; 254 } 255 auto instanceId = instanceIdDb->next(mctp_eid); 256 std::vector<uint8_t> requestMsg( 257 sizeof(pldm_msg_hdr) + PLDM_NEW_FILE_REQ_BYTES); 258 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 259 260 auto rc = 261 encode_new_file_req(instanceId, type, fileHandle, fileSize, request); 262 if (rc != PLDM_SUCCESS) 263 { 264 instanceIdDb->free(mctp_eid, instanceId); 265 error("Failed to encode new file request with response code '{RC}'", 266 "RC", rc); 267 return; 268 } 269 auto newFileAvailableRespHandler = [](mctp_eid_t /*eid*/, 270 const pldm_msg* response, 271 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 available response for vmi or remote terminus returned error, response code '{RC}' and completion code '{CC}'", 284 "RC", rc, "CC", completionCode); 285 pldm::utils::reportError( 286 "xyz.openbmc_project.PLDM.Error.DecodeNewFileResponseFail"); 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( 295 "Failed to send NewFileAvailable Request to Host for vmi, response code '{RC}'", 296 "RC", rc); 297 pldm::utils::reportError( 298 "xyz.openbmc_project.PLDM.Error.NewFileAvailableRequestFail"); 299 } 300 } 301 302 } // namespace oem_ibm 303 } // namespace requester 304 } // namespace pldm 305