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