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     mctp_fd(mctp_fd),
30     mctp_eid(mctp_eid), requester(requester),
31     resDumpCurrentObjPath(resDumpCurrentObjPath)
32 {}
33 
34 void DbusToFileHandler::sendNewFileAvailableCmd(uint64_t fileSize)
35 {
36     if (requester == NULL)
37     {
38         std::cerr << "Failed to send resource dump parameters as requester is "
39                      "not set";
40         pldm::utils::reportError(
41             "xyz.openbmc_project.bmc.pldm.InternalFailure");
42         return;
43     }
44     auto instanceId = requester->getInstanceId(mctp_eid);
45     std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
46                                     PLDM_NEW_FILE_REQ_BYTES + fileSize);
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 =
52         encode_new_file_req(instanceId, PLDM_FILE_TYPE_RESOURCE_DUMP_PARMS,
53                             fileHandle, fileSize, request);
54     if (rc != PLDM_SUCCESS)
55     {
56         requester->markFree(mctp_eid, instanceId);
57         std::cerr << "Failed to encode_new_file_req, rc = " << rc << std::endl;
58         return;
59     }
60 
61     uint8_t* responseMsg = nullptr;
62     size_t responseMsgSize{};
63 
64     auto requesterRc =
65         pldm_send_recv(mctp_eid, mctp_fd, requestMsg.data(), requestMsg.size(),
66                        &responseMsg, &responseMsgSize);
67 
68     std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{responseMsg,
69                                                                   std::free};
70 
71     requester->markFree(mctp_eid, instanceId);
72     bool isDecodeNewFileRespFailed = false;
73     if (requesterRc != PLDM_REQUESTER_SUCCESS)
74     {
75         std::cerr << "Failed to send resource dump parameters, rc = "
76                   << requesterRc << std::endl;
77     }
78     else
79     {
80         uint8_t completionCode{};
81         auto responsePtr =
82             reinterpret_cast<struct pldm_msg*>(responseMsgPtr.get());
83 
84         rc = decode_new_file_resp(responsePtr, PLDM_NEW_FILE_RESP_BYTES,
85                                   &completionCode);
86 
87         if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
88         {
89             std::cerr << "Failed to decode_new_file_resp: "
90                       << "rc=" << rc
91                       << ", cc=" << static_cast<unsigned>(completionCode)
92                       << std::endl;
93             isDecodeNewFileRespFailed = true;
94         }
95     }
96 
97     if ((requesterRc != PLDM_REQUESTER_SUCCESS) || (isDecodeNewFileRespFailed))
98     {
99         pldm::utils::reportError(
100             "xyz.openbmc_project.bmc.pldm.InternalFailure");
101 
102         PropertyValue value{resDumpStatus};
103         DBusMapping dbusMapping{resDumpCurrentObjPath, resDumpProgressIntf,
104                                 "Status", "string"};
105         try
106         {
107             pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
108         }
109         catch (const std::exception& e)
110         {
111             std::cerr << "failed to set resource dump operation status, "
112                          "ERROR="
113                       << e.what() << "\n";
114         }
115     }
116 }
117 
118 void DbusToFileHandler::processNewResourceDump(
119     const std::string& vspString, const std::string& resDumpReqPass)
120 {
121     // This needs special handling in later point of time. Resource dump without
122     // the vsp string is supposed to be a non-disruptive system dump.
123     if (vspString.empty())
124     {
125         std::cerr << "Empty vsp string"
126                   << "\n";
127         PropertyValue value{resDumpStatus};
128         DBusMapping dbusMapping{resDumpCurrentObjPath, resDumpProgressIntf,
129                                 "Status", "string"};
130         try
131         {
132             pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
133         }
134         catch (const std::exception& e)
135         {
136             std::cerr << "failed to set resource dump operation status, "
137                          "ERROR="
138                       << e.what() << "\n";
139         }
140         return;
141     }
142 
143     namespace fs = std::filesystem;
144     const fs::path resDumpDirPath = "/var/lib/pldm/resourcedump";
145 
146     if (!fs::exists(resDumpDirPath))
147     {
148         fs::create_directories(resDumpDirPath);
149     }
150 
151     // Need to reconsider this logic to set the value as "1" when we have the
152     // support to handle multiple resource dumps
153     fs::path resDumpFilePath = resDumpDirPath / "1";
154 
155     std::ofstream fileHandle;
156     fileHandle.open(resDumpFilePath, std::ios::out | std::ofstream::binary);
157 
158     if (!fileHandle)
159     {
160         std::cerr << "resource dump file open error: " << resDumpFilePath
161                   << "\n";
162         PropertyValue value{resDumpStatus};
163         DBusMapping dbusMapping{resDumpCurrentObjPath, resDumpProgressIntf,
164                                 "Status", "string"};
165         try
166         {
167             pldm::utils::DBusHandler().setDbusProperty(dbusMapping, value);
168         }
169         catch (const std::exception& e)
170         {
171             std::cerr << "failed to set resource dump operation status, "
172                          "ERROR="
173                       << e.what() << "\n";
174         }
175         return;
176     }
177 
178     // Fill up the file with resource dump parameters and respective sizes
179     auto fileFunc = [&fileHandle](auto& paramBuf) {
180         uint32_t paramSize = paramBuf.size();
181         fileHandle.write((char*)&paramSize, sizeof(paramSize));
182         fileHandle << paramBuf;
183     };
184     fileFunc(vspString);
185     fileFunc(resDumpReqPass);
186 
187     fileHandle.close();
188     size_t fileSize = fs::file_size(resDumpFilePath);
189 
190     sendNewFileAvailableCmd(fileSize);
191 }
192 
193 void DbusToFileHandler::newCsrFileAvailable(const std::string& csr,
194                                             const std::string fileHandle)
195 {
196     namespace fs = std::filesystem;
197     std::string dirPath = "/var/lib/ibm/bmcweb";
198     const fs::path certDirPath = dirPath;
199 
200     if (!fs::exists(certDirPath))
201     {
202         fs::create_directories(certDirPath);
203         fs::permissions(certDirPath,
204                         fs::perms::others_read | fs::perms::owner_write);
205     }
206 
207     fs::path certFilePath = certDirPath / ("CSR_" + fileHandle);
208     std::ofstream certFile;
209 
210     certFile.open(certFilePath, std::ios::out | std::ofstream::binary);
211 
212     if (!certFile)
213     {
214         std::cerr << "cert file open error: " << certFilePath << "\n";
215         return;
216     }
217 
218     // Add csr to file
219     certFile << csr << std::endl;
220 
221     certFile.close();
222     uint32_t fileSize = fs::file_size(certFilePath);
223 
224     newFileAvailableSendToHost(fileSize, (uint32_t)stoi(fileHandle),
225                                PLDM_FILE_TYPE_CERT_SIGNING_REQUEST);
226 }
227 
228 void DbusToFileHandler::newFileAvailableSendToHost(const uint32_t fileSize,
229                                                    const uint32_t fileHandle,
230                                                    const uint16_t type)
231 {
232     if (requester == NULL)
233     {
234         std::cerr << "Failed to send csr to host.";
235         pldm::utils::reportError(
236             "xyz.openbmc_project.bmc.pldm.InternalFailure");
237         return;
238     }
239     auto instanceId = requester->getInstanceId(mctp_eid);
240     std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
241                                     PLDM_NEW_FILE_REQ_BYTES);
242     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
243 
244     auto rc =
245         encode_new_file_req(instanceId, type, fileHandle, fileSize, request);
246     if (rc != PLDM_SUCCESS)
247     {
248         requester->markFree(mctp_eid, instanceId);
249         std::cerr << "Failed to encode_new_file_req, rc = " << rc << std::endl;
250         return;
251     }
252 
253     uint8_t* responseMsg = nullptr;
254     size_t responseMsgSize{};
255 
256     auto requesterRc =
257         pldm_send_recv(mctp_eid, mctp_fd, requestMsg.data(), requestMsg.size(),
258                        &responseMsg, &responseMsgSize);
259 
260     std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{responseMsg,
261                                                                   std::free};
262 
263     requester->markFree(mctp_eid, instanceId);
264     bool isDecodeNewFileRespFailed = false;
265     if (requesterRc != PLDM_REQUESTER_SUCCESS)
266     {
267         std::cerr << "Failed to send file to host, rc = " << requesterRc
268                   << std::endl;
269     }
270     else
271     {
272         uint8_t completionCode{};
273         auto responsePtr =
274             reinterpret_cast<struct pldm_msg*>(responseMsgPtr.get());
275 
276         rc = decode_new_file_resp(responsePtr, PLDM_NEW_FILE_RESP_BYTES,
277                                   &completionCode);
278 
279         std::vector<uint8_t> responseMsgVec;
280         responseMsgVec.resize(responseMsgSize);
281         memcpy(responseMsgVec.data(), responseMsg, responseMsgVec.size());
282 
283         if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
284         {
285             std::cerr << "Failed to decode_new_file_resp: "
286                       << "rc=" << rc
287                       << ", cc=" << static_cast<unsigned>(completionCode)
288                       << std::endl;
289             isDecodeNewFileRespFailed = true;
290         }
291     }
292     if ((requesterRc != PLDM_REQUESTER_SUCCESS) || (isDecodeNewFileRespFailed))
293     {
294         pldm::utils::reportError(
295             "xyz.openbmc_project.bmc.pldm.InternalFailure");
296     }
297 }
298 
299 } // namespace oem_ibm
300 } // namespace requester
301 } // namespace pldm
302