1 #include "file_io.hpp"
2 
3 #include "file_io_by_type.hpp"
4 #include "file_table.hpp"
5 #include "utils.hpp"
6 #include "xyz/openbmc_project/Common/error.hpp"
7 
8 #include <fcntl.h>
9 #include <libpldm/base.h>
10 #include <sys/mman.h>
11 #include <sys/stat.h>
12 #include <sys/types.h>
13 #include <unistd.h>
14 
15 #include <phosphor-logging/lg2.hpp>
16 
17 #include <cstring>
18 #include <fstream>
19 #include <memory>
20 
21 PHOSPHOR_LOG2_USING;
22 
23 namespace pldm
24 {
25 using namespace pldm::responder::utils;
26 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
27 
28 namespace responder
29 {
30 namespace fs = std::filesystem;
31 
32 namespace dma
33 {
34 /** @struct AspeedXdmaOp
35  *
36  * Structure representing XDMA operation
37  */
38 struct AspeedXdmaOp
39 {
40     uint64_t hostAddr; //!< the DMA address on the host side, configured by
41                        //!< PCI subsystem.
42     uint32_t len;      //!< the size of the transfer in bytes, it should be a
43                        //!< multiple of 16 bytes
44     uint32_t upstream; //!< boolean indicating the direction of the DMA
45                        //!< operation, true means a transfer from BMC to host.
46 };
47 
48 constexpr auto xdmaDev = "/dev/aspeed-xdma";
49 
transferHostDataToSocket(int fd,uint32_t length,uint64_t address)50 int DMA::transferHostDataToSocket(int fd, uint32_t length, uint64_t address)
51 {
52     static const size_t pageSize = getpagesize();
53     uint32_t numPages = length / pageSize;
54     uint32_t pageAlignedLength = numPages * pageSize;
55 
56     if (length > pageAlignedLength)
57     {
58         pageAlignedLength += pageSize;
59     }
60 
61     auto mmapCleanup = [pageAlignedLength](void* vgaMem) {
62         munmap(vgaMem, pageAlignedLength);
63     };
64 
65     int dmaFd = -1;
66     int rc = 0;
67     dmaFd = open(xdmaDev, O_RDWR);
68     if (dmaFd < 0)
69     {
70         rc = -errno;
71         error(
72             "Failed to open the XDMA device for transferring remote terminus data to socket with response code '{RC}'",
73             "RC", rc);
74         return rc;
75     }
76 
77     pldm::utils::CustomFD xdmaFd(dmaFd);
78 
79     void* vgaMem;
80     vgaMem = mmap(nullptr, pageAlignedLength, PROT_READ, MAP_SHARED, xdmaFd(),
81                   0);
82     if (MAP_FAILED == vgaMem)
83     {
84         rc = -errno;
85         error(
86             "Failed to mmap the XDMA device for transferring remote terminus data to socket with response code '{RC}'",
87             "RC", rc);
88         return rc;
89     }
90 
91     std::unique_ptr<void, decltype(mmapCleanup)> vgaMemPtr(vgaMem, mmapCleanup);
92 
93     AspeedXdmaOp xdmaOp;
94     xdmaOp.upstream = 0;
95     xdmaOp.hostAddr = address;
96     xdmaOp.len = length;
97 
98     rc = write(xdmaFd(), &xdmaOp, sizeof(xdmaOp));
99     if (rc < 0)
100     {
101         rc = -errno;
102         error(
103             "Failed to execute the DMA operation for transferring remote terminus data to socket at address '{ADDRESS}' and length '{LENGTH}' with response code '{RC}'",
104             "RC", rc, "ADDRESS", address, "LENGTH", length);
105         return rc;
106     }
107 
108     rc = writeToUnixSocket(fd, static_cast<const char*>(vgaMemPtr.get()),
109                            length);
110     if (rc < 0)
111     {
112         rc = -errno;
113         close(fd);
114         error(
115             "Failed to write to Unix socket, closing socket for transferring remote terminus data to socket with response code '{RC}'",
116             "RC", rc);
117         return rc;
118     }
119     return 0;
120 }
121 
transferDataHost(int fd,uint32_t offset,uint32_t length,uint64_t address,bool upstream)122 int DMA::transferDataHost(int fd, uint32_t offset, uint32_t length,
123                           uint64_t address, bool upstream)
124 {
125     static const size_t pageSize = getpagesize();
126     uint32_t numPages = length / pageSize;
127     uint32_t pageAlignedLength = numPages * pageSize;
128 
129     if (length > pageAlignedLength)
130     {
131         pageAlignedLength += pageSize;
132     }
133 
134     int rc = 0;
135     auto mmapCleanup = [pageAlignedLength, &rc](void* vgaMem) {
136         if (rc != -EINTR)
137         {
138             munmap(vgaMem, pageAlignedLength);
139         }
140         else
141         {
142             error(
143                 "Received interrupt during DMA transfer for data between BMC and remote terminus. Skipping Unmap.");
144         }
145     };
146 
147     int dmaFd = -1;
148     dmaFd = open(xdmaDev, O_RDWR);
149     if (dmaFd < 0)
150     {
151         rc = -errno;
152         error(
153             "Failed to open the XDMA device for data transfer between BMC and remote terminus with response code '{RC}'",
154             "RC", rc);
155         return rc;
156     }
157 
158     pldm::utils::CustomFD xdmaFd(dmaFd);
159 
160     void* vgaMem;
161     vgaMem = mmap(nullptr, pageAlignedLength, upstream ? PROT_WRITE : PROT_READ,
162                   MAP_SHARED, xdmaFd(), 0);
163     if (MAP_FAILED == vgaMem)
164     {
165         rc = -errno;
166         error(
167             "Failed to mmap the XDMA device for data transfer between BMC and remote terminus with response code '{RC}'",
168             "RC", rc);
169         return rc;
170     }
171 
172     std::unique_ptr<void, decltype(mmapCleanup)> vgaMemPtr(vgaMem, mmapCleanup);
173 
174     if (upstream)
175     {
176         rc = lseek(fd, offset, SEEK_SET);
177         if (rc == -1)
178         {
179             error(
180                 "Failed to transfer data between BMC and remote terminus due to lseek failure with upstream '{UPSTREAM}' at offset '{OFFSET}', error number - {ERROR_NUM}",
181                 "ERROR_NUM", errno, "UPSTREAM", upstream, "OFFSET", offset);
182             return rc;
183         }
184 
185         // Writing to the VGA memory should be aligned at page boundary,
186         // otherwise write data into a buffer aligned at page boundary and
187         // then write to the VGA memory.
188         std::vector<char> buffer{};
189         buffer.resize(pageAlignedLength);
190         rc = read(fd, buffer.data(), length);
191         if (rc == -1)
192         {
193             error(
194                 "Failed to transfer data between BMC and remote terminus with file read on upstream '{UPSTREAM}' of length '{LENGTH}' at offset '{OFFSET}' failed, error number - {ERROR_NUM}",
195                 "ERROR_NUM", errno, "UPSTREAM", upstream, "LENGTH", length,
196                 "OFFSET", offset);
197             return rc;
198         }
199         if (rc != static_cast<int>(length))
200         {
201             error(
202                 "Failed to transfer data between BMC and remote terminus mismatched for number of characters to read on upstream '{UPSTREAM}' and the length '{LENGTH}' read  and count '{RC}'",
203                 "UPSTREAM", upstream, "LENGTH", length, "RC", rc);
204             return -1;
205         }
206         memcpy(static_cast<char*>(vgaMemPtr.get()), buffer.data(),
207                pageAlignedLength);
208     }
209 
210     AspeedXdmaOp xdmaOp;
211     xdmaOp.upstream = upstream ? 1 : 0;
212     xdmaOp.hostAddr = address;
213     xdmaOp.len = length;
214 
215     rc = write(xdmaFd(), &xdmaOp, sizeof(xdmaOp));
216     if (rc < 0)
217     {
218         rc = -errno;
219         error(
220             "Failed to execute the DMA operation on data between BMC and remote terminus for upstream '{UPSTREAM}' of length '{LENGTH}' at address '{ADDRESS}', response code '{RC}'",
221             "RC", rc, "UPSTREAM", upstream, "ADDRESS", address, "LENGTH",
222             length);
223         return rc;
224     }
225 
226     if (!upstream)
227     {
228         rc = lseek(fd, offset, SEEK_SET);
229         if (rc == -1)
230         {
231             error(
232                 "Failed to transfer data between BMC and remote terminus due to lseek failure '{UPSTREAM}' at offset '{OFFSET}' failed, error number - {ERROR_NUM}",
233                 "ERROR_NUM", errno, "UPSTREAM", upstream, "OFFSET", offset);
234             return rc;
235         }
236         rc = write(fd, static_cast<const char*>(vgaMemPtr.get()), length);
237         if (rc == -1)
238         {
239             error(
240                 "Failed to transfer data between BMC and remote terminus where file write upstream '{UPSTREAM}' of length '{LENGTH}' at offset '{OFFSET}' failed, error number - {ERROR_NUM}",
241                 "ERROR_NUM", errno, "UPSTREAM", upstream, "LENGTH", length,
242                 "OFFSET", offset);
243             return rc;
244         }
245     }
246 
247     return 0;
248 }
249 
250 } // namespace dma
251 
252 namespace oem_ibm
253 {
encodeRWResponseHandler(uint8_t instance_id,uint8_t command,uint8_t completion_code,uint32_t length,struct pldm_msg * msg)254 void encodeRWResponseHandler(uint8_t instance_id, uint8_t command,
255                              uint8_t completion_code, uint32_t length,
256                              struct pldm_msg* msg)
257 {
258     int rc = encode_rw_file_memory_resp(instance_id, command, completion_code,
259                                         length, msg);
260     if (rc != PLDM_SUCCESS)
261     {
262         error(
263             "Failed to encode response for command {COMMAND}, response code '{RC}'",
264             "COMMAND", command, "RC", rc);
265     }
266 }
267 
encodeReadResponseHandler(uint8_t instance_id,uint8_t completion_code,uint32_t length,struct pldm_msg * msg)268 void encodeReadResponseHandler(uint8_t instance_id, uint8_t completion_code,
269                                uint32_t length, struct pldm_msg* msg)
270 {
271     int rc = encode_read_file_resp(instance_id, completion_code, length, msg);
272     if (rc != PLDM_SUCCESS)
273     {
274         error("Failed to encode read file response, response code '{RC}'", "RC",
275               rc);
276     }
277 }
278 
encodeWriteResponseHandler(uint8_t instance_id,uint8_t completion_code,uint32_t length,struct pldm_msg * msg)279 void encodeWriteResponseHandler(uint8_t instance_id, uint8_t completion_code,
280                                 uint32_t length, struct pldm_msg* msg)
281 {
282     int rc = encode_write_file_resp(instance_id, completion_code, length, msg);
283     if (rc != PLDM_SUCCESS)
284     {
285         error("Failed to encode write file response, response code '{RC}'",
286               "RC", rc);
287     }
288 }
289 
encodeGetFileResponseHandler(uint8_t instance_id,uint8_t completion_code,uint32_t next_transfer_handle,uint8_t transfer_flag,const uint8_t * table_data,size_t table_size,struct pldm_msg * msg)290 void encodeGetFileResponseHandler(uint8_t instance_id, uint8_t completion_code,
291                                   uint32_t next_transfer_handle,
292                                   uint8_t transfer_flag,
293                                   const uint8_t* table_data, size_t table_size,
294                                   struct pldm_msg* msg)
295 {
296     int rc = encode_get_file_table_resp(instance_id, completion_code,
297                                         next_transfer_handle, transfer_flag,
298                                         table_data, table_size, msg);
299     if (rc != PLDM_SUCCESS)
300     {
301         error("Failed to encode get file table response, response code '{RC}'",
302               "RC", rc);
303     }
304 }
305 
encodeRWTypeMemoryResponseHandler(uint8_t instance_id,uint8_t command,uint8_t completion_code,uint32_t length,struct pldm_msg * msg)306 void encodeRWTypeMemoryResponseHandler(uint8_t instance_id, uint8_t command,
307                                        uint8_t completion_code, uint32_t length,
308                                        struct pldm_msg* msg)
309 {
310     int rc = encode_rw_file_by_type_memory_resp(instance_id, command,
311                                                 completion_code, length, msg);
312     if (rc != PLDM_SUCCESS)
313     {
314         error(
315             "Failed to encode read/write file by type memory response, response code '{RC}'",
316             "RC", rc);
317     }
318 }
319 
encodeRWTypeResponseHandler(uint8_t instance_id,uint8_t command,uint8_t completion_code,uint32_t length,struct pldm_msg * msg)320 void encodeRWTypeResponseHandler(uint8_t instance_id, uint8_t command,
321                                  uint8_t completion_code, uint32_t length,
322                                  struct pldm_msg* msg)
323 {
324     int rc = encode_rw_file_by_type_resp(instance_id, command, completion_code,
325                                          length, msg);
326     if (rc != PLDM_SUCCESS)
327     {
328         error(
329             "Failed to encode response for command {COMMAND}, response code '{RC}'",
330             "COMMAND", command, "RC", rc);
331     }
332 }
333 
encodeFileAckResponseHandler(uint8_t instance_id,uint8_t completion_code,struct pldm_msg * msg)334 void encodeFileAckResponseHandler(uint8_t instance_id, uint8_t completion_code,
335                                   struct pldm_msg* msg)
336 {
337     int rc = encode_file_ack_resp(instance_id, completion_code, msg);
338     if (rc != PLDM_SUCCESS)
339     {
340         error("Failed to encode file ack response, response code '{RC}'", "RC",
341               rc);
342     }
343 }
344 
readFileIntoMemory(const pldm_msg * request,size_t payloadLength)345 Response Handler::readFileIntoMemory(const pldm_msg* request,
346                                      size_t payloadLength)
347 {
348     uint32_t fileHandle = 0;
349     uint32_t offset = 0;
350     uint32_t length = 0;
351     uint64_t address = 0;
352 
353     Response response((sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES), 0);
354     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
355     if (payloadLength != PLDM_RW_FILE_MEM_REQ_BYTES)
356     {
357         error(
358             "Failed to read file into memory as payload length '{LENGTH}' not equal to '{REQ_LENGTH}'",
359             "LENGTH", payloadLength, "REQ_LENGTH", PLDM_RW_FILE_MEM_REQ_BYTES);
360         encodeRWResponseHandler(request->hdr.instance_id,
361                                 PLDM_READ_FILE_INTO_MEMORY,
362                                 PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
363         return response;
364     }
365 
366     int responseCode = decode_rw_file_memory_req(
367         request, payloadLength, &fileHandle, &offset, &length, &address);
368     if (responseCode != PLDM_SUCCESS)
369     {
370         error(
371             "Failed to decode read file into memory request, response code '{RC}'",
372             "RC", responseCode);
373     }
374 
375     using namespace pldm::filetable;
376     auto& table = buildFileTable(FILE_TABLE_JSON);
377     FileEntry value{};
378 
379     try
380     {
381         value = table.at(fileHandle);
382     }
383     catch (const std::exception& e)
384     {
385         error(
386             "File handle '{HANDLE}' does not exist in the file table, error - {ERROR}",
387             "HANDLE", fileHandle, "ERROR", e);
388         encodeRWResponseHandler(request->hdr.instance_id,
389                                 PLDM_READ_FILE_INTO_MEMORY,
390                                 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
391         return response;
392     }
393 
394     if (!fs::exists(value.fsPath))
395     {
396         error("File '{PATH}' and handle '{FILE_HANDLE}' with does not exist",
397               "PATH", value.fsPath, "FILE_HANDLE", fileHandle);
398         encodeRWResponseHandler(request->hdr.instance_id,
399                                 PLDM_READ_FILE_INTO_MEMORY,
400                                 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
401         return response;
402     }
403 
404     auto fileSize = fs::file_size(value.fsPath);
405     if (!fileSize)
406     {
407         error(
408             "Failed to PLDM_READ_FILE_INTO_MEMORY from file {PATH} with size '{SIZE}'",
409             "PATH", value.fsPath, "SIZE", fileSize);
410         encodeRWResponseHandler(request->hdr.instance_id,
411                                 PLDM_READ_FILE_INTO_MEMORY,
412                                 PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
413         return response;
414     }
415     if (offset >= fileSize)
416     {
417         error(
418             "Offset '{OFFSET}' exceeds file size '{SIZE}' and file handle '{FILE_HANDLE}'",
419             "OFFSET", offset, "SIZE", fileSize, "FILE_HANDLE", fileHandle);
420         encodeRWResponseHandler(request->hdr.instance_id,
421                                 PLDM_READ_FILE_INTO_MEMORY,
422                                 PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
423         return response;
424     }
425 
426     if (offset + length > fileSize)
427     {
428         length = fileSize - offset;
429     }
430 
431     if (!length || length % dma::minSize)
432     {
433         error("Packet length '{LENGTH}' is non multiple of minimum DMA size",
434               "LENGTH", length);
435         encodeRWResponseHandler(request->hdr.instance_id,
436                                 PLDM_READ_FILE_INTO_MEMORY,
437                                 PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
438         return response;
439     }
440 
441     using namespace dma;
442     DMA intf;
443     return transferAll<DMA>(&intf, PLDM_READ_FILE_INTO_MEMORY, value.fsPath,
444                             offset, length, address, true,
445                             request->hdr.instance_id);
446 }
447 
writeFileFromMemory(const pldm_msg * request,size_t payloadLength)448 Response Handler::writeFileFromMemory(const pldm_msg* request,
449                                       size_t payloadLength)
450 {
451     uint32_t fileHandle = 0;
452     uint32_t offset = 0;
453     uint32_t length = 0;
454     uint64_t address = 0;
455 
456     Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES, 0);
457     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
458 
459     if (payloadLength != PLDM_RW_FILE_MEM_REQ_BYTES)
460     {
461         error(
462             "Failed to write file from memory as payload length '{LENGTH}' not equal to '{REQ_LENGTH}'",
463             "LENGTH", payloadLength, "REQ_LENGTH", PLDM_RW_FILE_MEM_REQ_BYTES);
464         encodeRWResponseHandler(request->hdr.instance_id,
465                                 PLDM_WRITE_FILE_FROM_MEMORY,
466                                 PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
467         return response;
468     }
469 
470     int responseCode = decode_rw_file_memory_req(
471         request, payloadLength, &fileHandle, &offset, &length, &address);
472     if (responseCode != PLDM_SUCCESS)
473     {
474         error(
475             "Failed to decode write file from memory request, response code '{RC}'",
476             "RC", responseCode);
477     }
478 
479     if (!length || length % dma::minSize)
480     {
481         error("Packet length '{LENGTH}' is non multiple of minimum DMA size",
482               "LENGTH", length);
483         encodeRWResponseHandler(request->hdr.instance_id,
484                                 PLDM_WRITE_FILE_FROM_MEMORY,
485                                 PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
486         return response;
487     }
488 
489     using namespace pldm::filetable;
490     auto& table = buildFileTable(FILE_TABLE_JSON);
491     FileEntry value{};
492 
493     try
494     {
495         value = table.at(fileHandle);
496     }
497     catch (const std::exception& e)
498     {
499         error(
500             "File handle '{HANDLE}' does not exist in the file table, error - {ERROR}",
501             "HANDLE", fileHandle, "ERROR", e);
502         encodeRWResponseHandler(request->hdr.instance_id,
503                                 PLDM_WRITE_FILE_FROM_MEMORY,
504                                 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
505         return response;
506     }
507 
508     if (!fs::exists(value.fsPath))
509     {
510         error("File '{PATH}' does not exist for file handle '{FILE_HANDLE}'",
511               "PATH", value.fsPath, "FILE_HANDLE", fileHandle);
512         encodeRWResponseHandler(request->hdr.instance_id,
513                                 PLDM_WRITE_FILE_FROM_MEMORY,
514                                 PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
515         return response;
516     }
517 
518     auto fileSize = fs::file_size(value.fsPath);
519     if (!fileSize)
520     {
521         info(
522             "File '{PATH}' has size '{SIZE}' for command PLDM_WRITE_FILE_FROM_MEMORY",
523             "PATH", value.fsPath, "SIZE", fileSize);
524     }
525     if (offset >= fileSize)
526     {
527         error(
528             "Offset '{OFFSET}' exceeds file size {SIZE} for file '{PATH} and handle {FILE_HANDLE}",
529             "OFFSET", offset, "SIZE", fileSize, "PATH", value.fsPath,
530             "FILE_HANDLE", fileHandle);
531         encodeRWResponseHandler(request->hdr.instance_id,
532                                 PLDM_WRITE_FILE_FROM_MEMORY,
533                                 PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
534         return response;
535     }
536 
537     using namespace dma;
538     DMA intf;
539     return transferAll<DMA>(&intf, PLDM_WRITE_FILE_FROM_MEMORY, value.fsPath,
540                             offset, length, address, false,
541                             request->hdr.instance_id);
542 }
543 
getFileTable(const pldm_msg * request,size_t payloadLength)544 Response Handler::getFileTable(const pldm_msg* request, size_t payloadLength)
545 {
546     uint32_t transferHandle = 0;
547     uint8_t transferFlag = 0;
548     uint8_t tableType = 0;
549 
550     Response response(sizeof(pldm_msg_hdr) +
551                       PLDM_GET_FILE_TABLE_MIN_RESP_BYTES);
552     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
553 
554     if (payloadLength != PLDM_GET_FILE_TABLE_REQ_BYTES)
555     {
556         error(
557             "Failed to get file table as payload length '{LENGTH}' not equal to required length '{REQ_LENGTH}'",
558             "LENGTH", payloadLength, "REQ_LENGTH",
559             PLDM_GET_FILE_TABLE_REQ_BYTES);
560         encodeGetFileResponseHandler(request->hdr.instance_id,
561                                      PLDM_ERROR_INVALID_LENGTH, 0, 0, nullptr,
562                                      0, responsePtr);
563         return response;
564     }
565 
566     auto rc = decode_get_file_table_req(request, payloadLength, &transferHandle,
567                                         &transferFlag, &tableType);
568     if (rc)
569     {
570         error("Failed to decode get file table request, response code '{RC}'",
571               "RC", rc);
572         encodeGetFileResponseHandler(request->hdr.instance_id, rc, 0, 0,
573                                      nullptr, 0, responsePtr);
574         return response;
575     }
576 
577     if (tableType != PLDM_FILE_ATTRIBUTE_TABLE)
578     {
579         error(
580             "Failed to match table type '{TYPE}' with expected table type '{REQ_TYPE}'",
581             "TYPE", tableType, "REQ_TYPE", PLDM_FILE_ATTRIBUTE_TABLE);
582         encodeGetFileResponseHandler(request->hdr.instance_id,
583                                      PLDM_INVALID_FILE_TABLE_TYPE, 0, 0,
584                                      nullptr, 0, responsePtr);
585         return response;
586     }
587 
588     using namespace pldm::filetable;
589     auto table = buildFileTable(FILE_TABLE_JSON);
590     auto attrTable = table();
591     response.resize(response.size() + attrTable.size());
592     responsePtr = reinterpret_cast<pldm_msg*>(response.data());
593 
594     if (attrTable.empty())
595     {
596         error("PLDM file attribute table is empty");
597         encodeGetFileResponseHandler(request->hdr.instance_id,
598                                      PLDM_FILE_TABLE_UNAVAILABLE, 0, 0, nullptr,
599                                      0, responsePtr);
600         return response;
601     }
602 
603     encodeGetFileResponseHandler(request->hdr.instance_id, PLDM_SUCCESS, 0,
604                                  PLDM_START_AND_END, attrTable.data(),
605                                  attrTable.size(), responsePtr);
606     return response;
607 }
608 
readFile(const pldm_msg * request,size_t payloadLength)609 Response Handler::readFile(const pldm_msg* request, size_t payloadLength)
610 {
611     uint32_t fileHandle = 0;
612     uint32_t offset = 0;
613     uint32_t length = 0;
614 
615     Response response(sizeof(pldm_msg_hdr) + PLDM_READ_FILE_RESP_BYTES);
616     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
617 
618     if (payloadLength != PLDM_READ_FILE_REQ_BYTES)
619     {
620         error(
621             "Failed to read file as payload length '{LENGTH}' not equal to '{REQ_LENGTH}'",
622             "LENGTH", payloadLength, "REQ_LENGTH", PLDM_READ_FILE_REQ_BYTES);
623         encodeReadResponseHandler(request->hdr.instance_id,
624                                   PLDM_ERROR_INVALID_LENGTH, length,
625                                   responsePtr);
626         return response;
627     }
628 
629     auto rc = decode_read_file_req(request, payloadLength, &fileHandle, &offset,
630                                    &length);
631 
632     if (rc)
633     {
634         error("Failed to decode read file request, response code '{RC}'", "RC",
635               rc);
636         encodeReadResponseHandler(request->hdr.instance_id, rc, 0, responsePtr);
637         return response;
638     }
639 
640     using namespace pldm::filetable;
641     auto& table = buildFileTable(FILE_TABLE_JSON);
642     FileEntry value{};
643 
644     try
645     {
646         value = table.at(fileHandle);
647     }
648     catch (const std::exception& e)
649     {
650         error(
651             "File handle '{HANDLE}' does not exist in the file table, error - {ERROR}",
652             "HANDLE", fileHandle, "ERROR", e);
653 
654         encodeReadResponseHandler(request->hdr.instance_id,
655                                   PLDM_INVALID_FILE_HANDLE, length,
656                                   responsePtr);
657         return response;
658     }
659 
660     if (!fs::exists(value.fsPath))
661     {
662         error("File '{PATH}' and handle {FILE_HANDLE} does not exist", "PATH",
663               value.fsPath, "FILE_HANDLE", fileHandle);
664         encodeReadResponseHandler(request->hdr.instance_id,
665                                   PLDM_INVALID_FILE_HANDLE, length,
666                                   responsePtr);
667         return response;
668     }
669 
670     auto fileSize = fs::file_size(value.fsPath);
671     if (!fileSize)
672     {
673         error("Failed to read file {PATH} with size '{SIZE}'", "PATH",
674               value.fsPath, "SIZE", fileSize);
675         encodeRWResponseHandler(request->hdr.instance_id,
676                                 PLDM_READ_FILE_INTO_MEMORY,
677                                 PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
678         return response;
679     }
680 
681     if (offset >= fileSize)
682     {
683         error(
684             "Offset '{OFFSET}' exceeds file size '{SIZE}' for file '{PATH}' and file handle '{HANDLE}'",
685             "OFFSET", offset, "SIZE", fileSize, "PATH", value.fsPath, "HANDLE",
686             fileHandle);
687         encodeReadResponseHandler(request->hdr.instance_id,
688                                   PLDM_DATA_OUT_OF_RANGE, length, responsePtr);
689         return response;
690     }
691 
692     if (offset + length > fileSize)
693     {
694         length = fileSize - offset;
695     }
696 
697     response.resize(response.size() + length);
698     responsePtr = reinterpret_cast<pldm_msg*>(response.data());
699     auto fileDataPos = reinterpret_cast<char*>(responsePtr);
700     fileDataPos += sizeof(pldm_msg_hdr) + sizeof(uint8_t) + sizeof(length);
701 
702     std::ifstream stream(value.fsPath, std::ios::in | std::ios::binary);
703     stream.seekg(offset);
704     stream.read(fileDataPos, length);
705 
706     encodeReadResponseHandler(request->hdr.instance_id, PLDM_SUCCESS, length,
707                               responsePtr);
708 
709     return response;
710 }
711 
writeFile(const pldm_msg * request,size_t payloadLength)712 Response Handler::writeFile(const pldm_msg* request, size_t payloadLength)
713 {
714     uint32_t fileHandle = 0;
715     uint32_t offset = 0;
716     uint32_t length = 0;
717     size_t fileDataOffset = 0;
718 
719     Response response(sizeof(pldm_msg_hdr) + PLDM_WRITE_FILE_RESP_BYTES);
720     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
721 
722     if (payloadLength < PLDM_WRITE_FILE_REQ_BYTES)
723     {
724         error(
725             "Failed to write file as payload length '{LENGTH}' less than '{REQ_LENGTH}'",
726             "LENGTH", payloadLength, "REQ_LENGTH", PLDM_WRITE_FILE_REQ_BYTES);
727         encodeWriteResponseHandler(request->hdr.instance_id,
728                                    PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
729         return response;
730     }
731 
732     auto rc = decode_write_file_req(request, payloadLength, &fileHandle,
733                                     &offset, &length, &fileDataOffset);
734 
735     if (rc)
736     {
737         error("Failed to decode write file request, response code '{RC}'", "RC",
738               rc);
739         encodeWriteResponseHandler(request->hdr.instance_id, rc, 0,
740                                    responsePtr);
741         return response;
742     }
743 
744     using namespace pldm::filetable;
745     auto& table = buildFileTable(FILE_TABLE_JSON);
746     FileEntry value{};
747 
748     try
749     {
750         value = table.at(fileHandle);
751     }
752     catch (const std::exception& e)
753     {
754         error(
755             "File handle '{HANDLE}' does not exist in the file table, error - {ERROR}",
756             "HANDLE", fileHandle, "ERROR", e);
757         encodeWriteResponseHandler(request->hdr.instance_id,
758                                    PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
759         return response;
760     }
761 
762     if (!fs::exists(value.fsPath))
763     {
764         error("File '{PATH}' and handle {FILE_HANDLE} does not exist", "PATH",
765               value.fsPath, "FILE_HANDLE", fileHandle);
766         encodeWriteResponseHandler(request->hdr.instance_id,
767                                    PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
768         return response;
769     }
770 
771     auto fileSize = fs::file_size(value.fsPath);
772 
773     if (!fileSize)
774     {
775         info("File {PATH} has size '{SIZE}' for write file command", "PATH",
776              value.fsPath, "SIZE", fileSize);
777     }
778 
779     if (offset >= fileSize)
780     {
781         error(
782             "Offset '{OFFSET}' exceeds file size '{SIZE}' for file '{PATH}' and handle {FILE_HANDLE}",
783             "OFFSET", offset, "SIZE", fileSize, "PATH", value.fsPath,
784             "FILE_HANDLE", fileHandle);
785         encodeWriteResponseHandler(request->hdr.instance_id,
786                                    PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
787         return response;
788     }
789 
790     auto fileDataPos = reinterpret_cast<const char*>(request->payload) +
791                        fileDataOffset;
792 
793     std::ofstream stream(value.fsPath,
794                          std::ios::in | std::ios::out | std::ios::binary);
795     stream.seekp(offset);
796     stream.write(fileDataPos, length);
797 
798     encodeWriteResponseHandler(request->hdr.instance_id, PLDM_SUCCESS, length,
799                                responsePtr);
800 
801     return response;
802 }
803 
rwFileByTypeIntoMemory(uint8_t cmd,const pldm_msg * request,size_t payloadLength,oem_platform::Handler * oemPlatformHandler)804 Response rwFileByTypeIntoMemory(uint8_t cmd, const pldm_msg* request,
805                                 size_t payloadLength,
806                                 oem_platform::Handler* oemPlatformHandler)
807 {
808     Response response(
809         sizeof(pldm_msg_hdr) + PLDM_RW_FILE_BY_TYPE_MEM_RESP_BYTES, 0);
810     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
811 
812     if (payloadLength != PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES)
813     {
814         error(
815             "Failed to read file into memory as payload length '{LENGTH}' not equal to '{REQ_LENGTH}'",
816             "LENGTH", payloadLength, "REQ_LENGTH",
817             PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES);
818         encodeRWTypeMemoryResponseHandler(request->hdr.instance_id, cmd,
819                                           PLDM_ERROR_INVALID_LENGTH, 0,
820                                           responsePtr);
821         return response;
822     }
823 
824     uint16_t fileType{};
825     uint32_t fileHandle{};
826     uint32_t offset{};
827     uint32_t length{};
828     uint64_t address{};
829     auto rc = decode_rw_file_by_type_memory_req(request, payloadLength,
830                                                 &fileType, &fileHandle, &offset,
831                                                 &length, &address);
832     if (rc != PLDM_SUCCESS)
833     {
834         error(
835             "Failed to decode read/write file by type memory request, response code '{RC}'",
836             "RC", rc);
837         encodeRWTypeMemoryResponseHandler(request->hdr.instance_id, cmd, rc, 0,
838                                           responsePtr);
839         return response;
840     }
841     if (!length || length % dma::minSize)
842     {
843         error(
844             "Packet length '{LENGTH}' is non multiple of minimum DMA size for command {CMD}",
845             "LENGTH", length, "CMD", cmd);
846         encodeRWTypeMemoryResponseHandler(request->hdr.instance_id, cmd,
847                                           PLDM_ERROR_INVALID_LENGTH, 0,
848                                           responsePtr);
849         return response;
850     }
851 
852     std::unique_ptr<FileHandler> handler{};
853     try
854     {
855         handler = getHandlerByType(fileType, fileHandle);
856     }
857     catch (const InternalFailure& e)
858     {
859         error("Unknown file type '{TYPE}', error - {ERROR} ", "TYPE", fileType,
860               "ERROR", e);
861         encodeRWTypeMemoryResponseHandler(request->hdr.instance_id, cmd,
862                                           PLDM_INVALID_FILE_TYPE, 0,
863                                           responsePtr);
864         return response;
865     }
866 
867     rc = cmd == PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY
868              ? handler->writeFromMemory(offset, length, address,
869                                         oemPlatformHandler)
870              : handler->readIntoMemory(offset, length, address,
871                                        oemPlatformHandler);
872     encodeRWTypeMemoryResponseHandler(request->hdr.instance_id, cmd, rc, length,
873                                       responsePtr);
874     return response;
875 }
876 
writeFileByTypeFromMemory(const pldm_msg * request,size_t payloadLength)877 Response Handler::writeFileByTypeFromMemory(const pldm_msg* request,
878                                             size_t payloadLength)
879 {
880     return rwFileByTypeIntoMemory(PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY, request,
881                                   payloadLength, oemPlatformHandler);
882 }
883 
readFileByTypeIntoMemory(const pldm_msg * request,size_t payloadLength)884 Response Handler::readFileByTypeIntoMemory(const pldm_msg* request,
885                                            size_t payloadLength)
886 {
887     return rwFileByTypeIntoMemory(PLDM_READ_FILE_BY_TYPE_INTO_MEMORY, request,
888                                   payloadLength, oemPlatformHandler);
889 }
890 
writeFileByType(const pldm_msg * request,size_t payloadLength)891 Response Handler::writeFileByType(const pldm_msg* request, size_t payloadLength)
892 {
893     Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_BY_TYPE_RESP_BYTES);
894     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
895 
896     if (payloadLength < PLDM_RW_FILE_BY_TYPE_REQ_BYTES)
897     {
898         error(
899             "Failed to write file by type as payload length '{LENGTH}' less than '{REQ_LENGTH}'",
900             "LENGTH", payloadLength, "REQ_LENGTH",
901             PLDM_RW_FILE_BY_TYPE_REQ_BYTES);
902         encodeRWTypeResponseHandler(request->hdr.instance_id,
903                                     PLDM_WRITE_FILE_BY_TYPE,
904                                     PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
905         return response;
906     }
907     uint16_t fileType{};
908     uint32_t fileHandle{};
909     uint32_t offset{};
910     uint32_t length{};
911 
912     auto rc = decode_rw_file_by_type_req(request, payloadLength, &fileType,
913                                          &fileHandle, &offset, &length);
914     if (rc != PLDM_SUCCESS)
915     {
916         error("Failed decoded write file by type request, response code '{RC}'",
917               "RC", rc);
918         encodeRWTypeResponseHandler(request->hdr.instance_id,
919                                     PLDM_WRITE_FILE_BY_TYPE, rc, 0,
920                                     responsePtr);
921         return response;
922     }
923 
924     std::unique_ptr<FileHandler> handler{};
925     try
926     {
927         handler = getHandlerByType(fileType, fileHandle);
928     }
929     catch (const InternalFailure& e)
930     {
931         error("Unknown file type '{TYPE}', error - {ERROR}", "TYPE", fileType,
932               "ERROR", e);
933         encodeRWTypeResponseHandler(request->hdr.instance_id,
934                                     PLDM_WRITE_FILE_BY_TYPE,
935                                     PLDM_INVALID_FILE_TYPE, 0, responsePtr);
936         return response;
937     }
938 
939     rc = handler->write(reinterpret_cast<const char*>(
940                             request->payload + PLDM_RW_FILE_BY_TYPE_REQ_BYTES),
941                         offset, length, oemPlatformHandler);
942     encodeRWTypeResponseHandler(request->hdr.instance_id,
943                                 PLDM_WRITE_FILE_BY_TYPE, rc, length,
944                                 responsePtr);
945     return response;
946 }
947 
readFileByType(const pldm_msg * request,size_t payloadLength)948 Response Handler::readFileByType(const pldm_msg* request, size_t payloadLength)
949 {
950     Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_BY_TYPE_RESP_BYTES);
951     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
952 
953     if (payloadLength != PLDM_RW_FILE_BY_TYPE_REQ_BYTES)
954     {
955         error(
956             "Failed to read file by type as payload length '{LENGTH}' less than '{REQ_LENGTH}'",
957             "LENGTH", payloadLength, "REQ_LENGTH",
958             PLDM_RW_FILE_BY_TYPE_REQ_BYTES);
959         encodeRWTypeResponseHandler(request->hdr.instance_id,
960                                     PLDM_READ_FILE_BY_TYPE,
961                                     PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
962         return response;
963     }
964     uint16_t fileType{};
965     uint32_t fileHandle{};
966     uint32_t offset{};
967     uint32_t length{};
968 
969     auto rc = decode_rw_file_by_type_req(request, payloadLength, &fileType,
970                                          &fileHandle, &offset, &length);
971     if (rc != PLDM_SUCCESS)
972     {
973         error(
974             "Failed to decode read file by type request, response code '{RC}'",
975             "RC", rc);
976         encodeRWTypeResponseHandler(request->hdr.instance_id,
977                                     PLDM_READ_FILE_BY_TYPE, rc, 0, responsePtr);
978         return response;
979     }
980 
981     std::unique_ptr<FileHandler> handler{};
982     try
983     {
984         handler = getHandlerByType(fileType, fileHandle);
985     }
986     catch (const InternalFailure& e)
987     {
988         error("Unknown file type '{TYPE}', error - {ERROR}", "TYPE", fileType,
989               "ERROR", e);
990         encodeRWTypeResponseHandler(request->hdr.instance_id,
991                                     PLDM_READ_FILE_BY_TYPE,
992                                     PLDM_INVALID_FILE_TYPE, 0, responsePtr);
993         return response;
994     }
995 
996     rc = handler->read(offset, length, response, oemPlatformHandler);
997     responsePtr = reinterpret_cast<pldm_msg*>(response.data());
998     encodeRWTypeResponseHandler(request->hdr.instance_id,
999                                 PLDM_READ_FILE_BY_TYPE, rc, length,
1000                                 responsePtr);
1001     return response;
1002 }
1003 
fileAck(const pldm_msg * request,size_t payloadLength)1004 Response Handler::fileAck(const pldm_msg* request, size_t payloadLength)
1005 {
1006     Response response(sizeof(pldm_msg_hdr) + PLDM_FILE_ACK_RESP_BYTES);
1007     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
1008 
1009     if (payloadLength != PLDM_FILE_ACK_REQ_BYTES)
1010     {
1011         error(
1012             "Failed to do file ack as payload length '{LENGTH}' is less than '{REQ_LENGTH}'",
1013             "LENGTH", payloadLength, "REQ_LENGTH", PLDM_FILE_ACK_REQ_BYTES);
1014         encodeFileAckResponseHandler(request->hdr.instance_id,
1015                                      PLDM_ERROR_INVALID_LENGTH, responsePtr);
1016         return response;
1017     }
1018     uint16_t fileType{};
1019     uint32_t fileHandle{};
1020     uint8_t fileStatus{};
1021 
1022     auto rc = decode_file_ack_req(request, payloadLength, &fileType,
1023                                   &fileHandle, &fileStatus);
1024     if (rc != PLDM_SUCCESS)
1025     {
1026         encodeFileAckResponseHandler(request->hdr.instance_id, rc, responsePtr);
1027         return response;
1028     }
1029 
1030     std::unique_ptr<FileHandler> handler{};
1031     try
1032     {
1033         handler = getHandlerByType(fileType, fileHandle);
1034     }
1035 
1036     catch (const InternalFailure& e)
1037     {
1038         error("Unknown file type '{TYPE}', error - {ERROR}", "TYPE", fileType,
1039               "ERROR", e);
1040         encodeFileAckResponseHandler(request->hdr.instance_id,
1041                                      PLDM_INVALID_FILE_TYPE, responsePtr);
1042         return response;
1043     }
1044 
1045     rc = handler->fileAck(fileStatus);
1046     encodeFileAckResponseHandler(request->hdr.instance_id, rc, responsePtr);
1047     return response;
1048 }
1049 
getAlertStatus(const pldm_msg * request,size_t payloadLength)1050 Response Handler::getAlertStatus(const pldm_msg* request, size_t payloadLength)
1051 {
1052     Response response(sizeof(pldm_msg_hdr) + PLDM_GET_ALERT_STATUS_RESP_BYTES);
1053     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
1054     if (payloadLength != PLDM_GET_ALERT_STATUS_REQ_BYTES)
1055     {
1056         error(
1057             "Failed to get alert status as payload length '{LENGTH}' is less than '{REQ_LENGTH}'",
1058             "LENGTH", payloadLength, "REQ_LENGTH",
1059             PLDM_GET_ALERT_STATUS_REQ_BYTES);
1060         return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
1061     }
1062 
1063     uint8_t versionId{};
1064 
1065     auto rc = decode_get_alert_status_req(request, payloadLength, &versionId);
1066     if (rc != PLDM_SUCCESS)
1067     {
1068         error("Failed to decode get alert status request, response code '{RC}'",
1069               "RC", rc);
1070         return CmdHandler::ccOnlyResponse(request, rc);
1071     }
1072 
1073     if (versionId != 0)
1074     {
1075         error(
1076             "Failed to get alert status due to unsupported version ID '{VERSION}'",
1077             "VERSION", versionId);
1078         return CmdHandler::ccOnlyResponse(request,
1079                                           PLDM_HOST_UNSUPPORTED_FORMAT_VERSION);
1080     }
1081 
1082     constexpr uint32_t rackEntry = 0xFF000030;
1083     constexpr uint32_t priCecNode = 0x00008030;
1084     rc = encode_get_alert_status_resp(request->hdr.instance_id, PLDM_SUCCESS,
1085                                       rackEntry, priCecNode, responsePtr,
1086                                       PLDM_GET_ALERT_STATUS_RESP_BYTES);
1087     if (rc != PLDM_SUCCESS)
1088     {
1089         error(
1090             "Failed to encode get alert status response, response code '{RC}'",
1091             "RC", rc);
1092         return CmdHandler::ccOnlyResponse(request, rc);
1093     }
1094 
1095     return response;
1096 }
1097 
newFileAvailable(const pldm_msg * request,size_t payloadLength)1098 Response Handler::newFileAvailable(const pldm_msg* request,
1099                                    size_t payloadLength)
1100 {
1101     Response response(sizeof(pldm_msg_hdr) + PLDM_NEW_FILE_RESP_BYTES);
1102 
1103     if (payloadLength != PLDM_NEW_FILE_REQ_BYTES)
1104     {
1105         error(
1106             "Failed new file available as payload length '{LENGTH}' is less than '{REQ_LENGTH}'",
1107             "LENGTH", payloadLength, "REQ_LENGTH", PLDM_NEW_FILE_REQ_BYTES);
1108         return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
1109     }
1110     uint16_t fileType{};
1111     uint32_t fileHandle{};
1112     uint64_t length{};
1113 
1114     auto rc = decode_new_file_req(request, payloadLength, &fileType,
1115                                   &fileHandle, &length);
1116 
1117     if (rc != PLDM_SUCCESS)
1118     {
1119         error("Failed to decode new file request, response code '{RC}'", "RC",
1120               rc);
1121         return CmdHandler::ccOnlyResponse(request, rc);
1122     }
1123 
1124     std::unique_ptr<FileHandler> handler{};
1125     try
1126     {
1127         handler = getHandlerByType(fileType, fileHandle);
1128     }
1129     catch (const InternalFailure& e)
1130     {
1131         error("Unknown file type '{TYPE}', error - {ERROR}", "TYPE", fileType,
1132               "ERROR", e);
1133         return CmdHandler::ccOnlyResponse(request, PLDM_INVALID_FILE_TYPE);
1134     }
1135 
1136     rc = handler->newFileAvailable(length);
1137     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
1138     int responseCode = encode_new_file_resp(request->hdr.instance_id, rc,
1139                                             responsePtr);
1140     if (responseCode != PLDM_SUCCESS)
1141     {
1142         error(
1143             "Failed to encode new file available response, response code '{RC}'",
1144             "RC", responseCode);
1145     }
1146     return response;
1147 }
1148 
1149 } // namespace oem_ibm
1150 } // namespace responder
1151 } // namespace pldm
1152