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), 30 instanceIdDb(instanceIdDb), resDumpCurrentObjPath(resDumpCurrentObjPath), 31 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 request with response code '{RC}'", 58 "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 available response or remote terminus returned error, response code '{RC}' and completion code '{CC}'", 76 "RC", rc, "CC", 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( 86 "Failed to send NewFileAvailable Request to Host, response code '{RC}'", 87 "RC", rc); 88 reportResourceDumpFailure(); 89 } 90 } 91 92 void DbusToFileHandler::reportResourceDumpFailure() 93 { 94 pldm::utils::reportError("xyz.openbmc_project.bmc.pldm.InternalFailure"); 95 96 PropertyValue value{resDumpStatus}; 97 DBusMapping dbusMapping{resDumpCurrentObjPath, resDumpProgressIntf, 98 "Status", "string"}; 99 try 100 { 101 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value); 102 } 103 catch (const std::exception& e) 104 { 105 error("Failed to set resource dump operation status, error - {ERROR}", 106 "ERROR", e); 107 } 108 } 109 110 void DbusToFileHandler::processNewResourceDump( 111 const std::string& vspString, const std::string& resDumpReqPass) 112 { 113 try 114 { 115 std::string objPath = resDumpCurrentObjPath; 116 auto propVal = pldm::utils::DBusHandler().getDbusPropertyVariant( 117 objPath.c_str(), "Status", resDumpProgressIntf); 118 const auto& curResDumpStatus = std::get<ResDumpStatus>(propVal); 119 120 if (curResDumpStatus != 121 "xyz.openbmc_project.Common.Progress.OperationStatus.InProgress") 122 { 123 return; 124 } 125 } 126 catch (const sdbusplus::exception_t& e) 127 { 128 error( 129 "Error '{ERROR}' found in getting current resource dump status while initiating a new resource dump with object path '{PATH}' and interface {INTERFACE}", 130 "ERROR", e, "PATH", resDumpCurrentObjPath, "INTERFACE", 131 resDumpProgressIntf); 132 } 133 134 namespace fs = std::filesystem; 135 const fs::path resDumpDirPath = "/var/lib/pldm/resourcedump"; 136 137 if (!fs::exists(resDumpDirPath)) 138 { 139 fs::create_directories(resDumpDirPath); 140 } 141 142 // Need to reconsider this logic to set the value as "1" when we have the 143 // support to handle multiple resource dumps 144 fs::path resDumpFilePath = resDumpDirPath / "1"; 145 146 std::ofstream fileHandle; 147 fileHandle.open(resDumpFilePath, std::ios::out | std::ofstream::binary); 148 149 if (!fileHandle) 150 { 151 error("Failed to open resource dump file '{PATH}'", "PATH", 152 resDumpFilePath); 153 PropertyValue value{resDumpStatus}; 154 DBusMapping dbusMapping{resDumpCurrentObjPath, resDumpProgressIntf, 155 "Status", "string"}; 156 try 157 { 158 pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value); 159 } 160 catch (const std::exception& e) 161 { 162 error( 163 "Failed to set resource dump operation status, error - {ERROR}", 164 "ERROR", e); 165 } 166 return; 167 } 168 169 // Fill up the file with resource dump parameters and respective sizes 170 auto fileFunc = [&fileHandle](auto& paramBuf) { 171 uint32_t paramSize = paramBuf.size(); 172 fileHandle.write((char*)¶mSize, sizeof(paramSize)); 173 fileHandle << paramBuf; 174 }; 175 fileFunc(vspString); 176 fileFunc(resDumpReqPass); 177 178 std::string str; 179 if (!resDumpReqPass.empty()) 180 { 181 str = getAcfFileContent(); 182 } 183 184 fileFunc(str); 185 186 fileHandle.close(); 187 size_t fileSize = fs::file_size(resDumpFilePath); 188 189 sendNewFileAvailableCmd(fileSize); 190 } 191 192 std::string DbusToFileHandler::getAcfFileContent() 193 { 194 std::string str; 195 static constexpr auto acfDirPath = "/etc/acf/service.acf"; 196 if (fs::exists(acfDirPath)) 197 { 198 std::ifstream file; 199 file.open(acfDirPath); 200 std::stringstream acfBuf; 201 acfBuf << file.rdbuf(); 202 str = acfBuf.str(); 203 file.close(); 204 } 205 return str; 206 } 207 208 void DbusToFileHandler::newCsrFileAvailable(const std::string& csr, 209 const std::string fileHandle) 210 { 211 namespace fs = std::filesystem; 212 std::string dirPath = "/var/lib/ibm/bmcweb"; 213 const fs::path certDirPath = dirPath; 214 215 if (!fs::exists(certDirPath)) 216 { 217 fs::create_directories(certDirPath); 218 fs::permissions(certDirPath, 219 fs::perms::others_read | fs::perms::owner_write); 220 } 221 222 fs::path certFilePath = certDirPath / ("CSR_" + fileHandle); 223 std::ofstream certFile; 224 225 certFile.open(certFilePath, std::ios::out | std::ofstream::binary); 226 227 if (!certFile) 228 { 229 error("Failed to open certificate file '{PATH}'", "PATH", certFilePath); 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 remote terminus."); 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 request with response code '{RC}'", 265 "RC", rc); 266 return; 267 } 268 auto newFileAvailableRespHandler = 269 [](mctp_eid_t /*eid*/, const pldm_msg* response, size_t respMsgLen) { 270 if (response == nullptr || !respMsgLen) 271 { 272 error( 273 "Failed to receive response for NewFileAvailable command for vmi"); 274 return; 275 } 276 uint8_t completionCode{}; 277 auto rc = decode_new_file_resp(response, respMsgLen, &completionCode); 278 if (rc || completionCode) 279 { 280 error( 281 "Failed to decode new file available response for vmi or remote terminus returned error, response code '{RC}' and completion code '{CC}'", 282 "RC", rc, "CC", completionCode); 283 pldm::utils::reportError( 284 "xyz.openbmc_project.bmc.pldm.InternalFailure"); 285 } 286 }; 287 rc = handler->registerRequest( 288 mctp_eid, instanceId, PLDM_OEM, PLDM_NEW_FILE_AVAILABLE, 289 std::move(requestMsg), std::move(newFileAvailableRespHandler)); 290 if (rc) 291 { 292 error( 293 "Failed to send NewFileAvailable Request to Host for vmi, response code '{RC}'", 294 "RC", rc); 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