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*)&paramSize, 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