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     pldm::utils::reportError("xyz.openbmc_project.bmc.pldm.InternalFailure");
96 
97     PropertyValue value{resDumpStatus};
98     DBusMapping dbusMapping{resDumpCurrentObjPath, resDumpProgressIntf,
99                             "Status", "string"};
100     try
101     {
102         pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
103     }
104     catch (const std::exception& e)
105     {
106         std::cerr << "failed to set resource dump operation status, "
107                      "ERROR="
108                   << e.what() << "\n";
109     }
110 }
111 
112 void DbusToFileHandler::processNewResourceDump(
113     const std::string& vspString, const std::string& resDumpReqPass)
114 {
115     namespace fs = std::filesystem;
116     const fs::path resDumpDirPath = "/var/lib/pldm/resourcedump";
117 
118     if (!fs::exists(resDumpDirPath))
119     {
120         fs::create_directories(resDumpDirPath);
121     }
122 
123     // Need to reconsider this logic to set the value as "1" when we have the
124     // support to handle multiple resource dumps
125     fs::path resDumpFilePath = resDumpDirPath / "1";
126 
127     std::ofstream fileHandle;
128     fileHandle.open(resDumpFilePath, std::ios::out | std::ofstream::binary);
129 
130     if (!fileHandle)
131     {
132         std::cerr << "resource dump file open error: " << resDumpFilePath
133                   << "\n";
134         PropertyValue value{resDumpStatus};
135         DBusMapping dbusMapping{resDumpCurrentObjPath, resDumpProgressIntf,
136                                 "Status", "string"};
137         try
138         {
139             pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
140         }
141         catch (const std::exception& e)
142         {
143             std::cerr << "failed to set resource dump operation status, "
144                          "ERROR="
145                       << e.what() << "\n";
146         }
147         return;
148     }
149 
150     // Fill up the file with resource dump parameters and respective sizes
151     auto fileFunc = [&fileHandle](auto& paramBuf) {
152         uint32_t paramSize = paramBuf.size();
153         fileHandle.write((char*)&paramSize, sizeof(paramSize));
154         fileHandle << paramBuf;
155     };
156     fileFunc(vspString);
157     fileFunc(resDumpReqPass);
158 
159     fileHandle.close();
160     size_t fileSize = fs::file_size(resDumpFilePath);
161 
162     sendNewFileAvailableCmd(fileSize);
163 }
164 
165 void DbusToFileHandler::newCsrFileAvailable(const std::string& csr,
166                                             const std::string fileHandle)
167 {
168     namespace fs = std::filesystem;
169     std::string dirPath = "/var/lib/ibm/bmcweb";
170     const fs::path certDirPath = dirPath;
171 
172     if (!fs::exists(certDirPath))
173     {
174         fs::create_directories(certDirPath);
175         fs::permissions(certDirPath,
176                         fs::perms::others_read | fs::perms::owner_write);
177     }
178 
179     fs::path certFilePath = certDirPath / ("CSR_" + fileHandle);
180     std::ofstream certFile;
181 
182     certFile.open(certFilePath, std::ios::out | std::ofstream::binary);
183 
184     if (!certFile)
185     {
186         std::cerr << "cert file open error: " << certFilePath << "\n";
187         return;
188     }
189 
190     // Add csr to file
191     certFile << csr << std::endl;
192 
193     certFile.close();
194     uint32_t fileSize = fs::file_size(certFilePath);
195 
196     newFileAvailableSendToHost(fileSize, (uint32_t)stoi(fileHandle),
197                                PLDM_FILE_TYPE_CERT_SIGNING_REQUEST);
198 }
199 
200 void DbusToFileHandler::newFileAvailableSendToHost(const uint32_t fileSize,
201                                                    const uint32_t fileHandle,
202                                                    const uint16_t type)
203 {
204     if (requester == NULL)
205     {
206         std::cerr << "Failed to send csr to host.";
207         pldm::utils::reportError(
208             "xyz.openbmc_project.bmc.pldm.InternalFailure");
209         return;
210     }
211     auto instanceId = requester->getInstanceId(mctp_eid);
212     std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
213                                     PLDM_NEW_FILE_REQ_BYTES);
214     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
215 
216     auto rc =
217         encode_new_file_req(instanceId, type, fileHandle, fileSize, request);
218     if (rc != PLDM_SUCCESS)
219     {
220         requester->markFree(mctp_eid, instanceId);
221         std::cerr << "Failed to encode_new_file_req, rc = " << rc << std::endl;
222         return;
223     }
224     auto newFileAvailableRespHandler = [](mctp_eid_t /*eid*/,
225                                           const pldm_msg* response,
226                                           size_t respMsgLen) {
227         if (response == nullptr || !respMsgLen)
228         {
229             std::cerr << "Failed to receive response for NewFileAvailable "
230                          "command for vmi \n";
231             return;
232         }
233         uint8_t completionCode{};
234         auto rc = decode_new_file_resp(response, respMsgLen, &completionCode);
235         if (rc || completionCode)
236         {
237             std::cerr << "Failed to decode_new_file_resp for vmi, or"
238                       << " Host returned error for new_file_available"
239                       << " rc=" << rc
240                       << ", cc=" << static_cast<unsigned>(completionCode)
241                       << "\n";
242             pldm::utils::reportError(
243                 "xyz.openbmc_project.bmc.pldm.InternalFailure");
244         }
245     };
246     rc = handler->registerRequest(
247         mctp_eid, instanceId, PLDM_OEM, PLDM_NEW_FILE_AVAILABLE,
248         std::move(requestMsg), std::move(newFileAvailableRespHandler));
249     if (rc)
250     {
251         std::cerr
252             << "Failed to send NewFileAvailable Request to Host for vmi \n";
253         pldm::utils::reportError(
254             "xyz.openbmc_project.bmc.pldm.InternalFailure");
255     }
256 }
257 
258 } // namespace oem_ibm
259 } // namespace requester
260 } // namespace pldm
261