1 #include "config.h"
2 
3 #include "file_io.hpp"
4 
5 #include "libpldm/base.h"
6 
7 #include "file_io_by_type.hpp"
8 #include "file_table.hpp"
9 #include "utils.hpp"
10 #include "xyz/openbmc_project/Common/error.hpp"
11 
12 #include <fcntl.h>
13 #include <sys/mman.h>
14 #include <sys/stat.h>
15 #include <sys/types.h>
16 #include <unistd.h>
17 
18 #include <cstring>
19 #include <fstream>
20 #include <iostream>
21 #include <memory>
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 
31 namespace fs = std::filesystem;
32 
33 namespace dma
34 {
35 
36 /** @struct AspeedXdmaOp
37  *
38  * Structure representing XDMA operation
39  */
40 struct AspeedXdmaOp
41 {
42     uint64_t hostAddr; //!< the DMA address on the host side, configured by
43                        //!< PCI subsystem.
44     uint32_t len;      //!< the size of the transfer in bytes, it should be a
45                        //!< multiple of 16 bytes
46     uint32_t upstream; //!< boolean indicating the direction of the DMA
47                        //!< operation, true means a transfer from BMC to host.
48 };
49 
50 constexpr auto xdmaDev = "/dev/aspeed-xdma";
51 
52 int DMA::transferHostDataToSocket(int fd, uint32_t length, uint64_t address)
53 {
54     static const size_t pageSize = getpagesize();
55     uint32_t numPages = length / pageSize;
56     uint32_t pageAlignedLength = numPages * pageSize;
57 
58     if (length > pageAlignedLength)
59     {
60         pageAlignedLength += pageSize;
61     }
62 
63     auto mmapCleanup = [pageAlignedLength](void* vgaMem) {
64         munmap(vgaMem, pageAlignedLength);
65     };
66 
67     int dmaFd = -1;
68     int rc = 0;
69     dmaFd = open(xdmaDev, O_RDWR);
70     if (dmaFd < 0)
71     {
72         rc = -errno;
73         std::cerr << "Failed to open the XDMA device, RC=" << rc << "\n";
74         return rc;
75     }
76 
77     pldm::utils::CustomFD xdmaFd(dmaFd);
78 
79     void* vgaMem;
80     vgaMem =
81         mmap(nullptr, pageAlignedLength, PROT_READ, MAP_SHARED, xdmaFd(), 0);
82     if (MAP_FAILED == vgaMem)
83     {
84         rc = -errno;
85         std::cerr << "Failed to mmap the XDMA device, RC=" << rc << "\n";
86         return rc;
87     }
88 
89     std::unique_ptr<void, decltype(mmapCleanup)> vgaMemPtr(vgaMem, mmapCleanup);
90 
91     AspeedXdmaOp xdmaOp;
92     xdmaOp.upstream = 0;
93     xdmaOp.hostAddr = address;
94     xdmaOp.len = length;
95 
96     rc = write(xdmaFd(), &xdmaOp, sizeof(xdmaOp));
97     if (rc < 0)
98     {
99         rc = -errno;
100         std::cerr << "Failed to execute the DMA operation, RC=" << rc
101                   << " ADDRESS=" << address << " LENGTH=" << length << "\n";
102         return rc;
103     }
104 
105     rc = writeToUnixSocket(fd, static_cast<const char*>(vgaMemPtr.get()),
106                            length);
107     if (rc < 0)
108     {
109         rc = -errno;
110         close(fd);
111         std::cerr << "closing socket" << std::endl;
112         return rc;
113     }
114     return 0;
115 }
116 
117 int DMA::transferDataHost(int fd, uint32_t offset, uint32_t length,
118                           uint64_t address, bool upstream)
119 {
120     static const size_t pageSize = getpagesize();
121     uint32_t numPages = length / pageSize;
122     uint32_t pageAlignedLength = numPages * pageSize;
123 
124     if (length > pageAlignedLength)
125     {
126         pageAlignedLength += pageSize;
127     }
128 
129     auto mmapCleanup = [pageAlignedLength](void* vgaMem) {
130         munmap(vgaMem, pageAlignedLength);
131     };
132 
133     int dmaFd = -1;
134     int rc = 0;
135     dmaFd = open(xdmaDev, O_RDWR);
136     if (dmaFd < 0)
137     {
138         rc = -errno;
139         std::cerr << "Failed to open the XDMA device, RC=" << rc << "\n";
140         return rc;
141     }
142 
143     pldm::utils::CustomFD xdmaFd(dmaFd);
144 
145     void* vgaMem;
146     vgaMem = mmap(nullptr, pageAlignedLength, upstream ? PROT_WRITE : PROT_READ,
147                   MAP_SHARED, xdmaFd(), 0);
148     if (MAP_FAILED == vgaMem)
149     {
150         rc = -errno;
151         std::cerr << "Failed to mmap the XDMA device, RC=" << rc << "\n";
152         return rc;
153     }
154 
155     std::unique_ptr<void, decltype(mmapCleanup)> vgaMemPtr(vgaMem, mmapCleanup);
156 
157     if (upstream)
158     {
159         rc = lseek(fd, offset, SEEK_SET);
160         if (rc == -1)
161         {
162             std::cerr << "lseek failed, ERROR=" << errno
163                       << ", UPSTREAM=" << upstream << ", OFFSET=" << offset
164                       << "\n";
165             return rc;
166         }
167 
168         // Writing to the VGA memory should be aligned at page boundary,
169         // otherwise write data into a buffer aligned at page boundary and
170         // then write to the VGA memory.
171         std::vector<char> buffer{};
172         buffer.resize(pageAlignedLength);
173         rc = read(fd, buffer.data(), length);
174         if (rc == -1)
175         {
176             std::cerr << "file read failed, ERROR=" << errno
177                       << ", UPSTREAM=" << upstream << ", LENGTH=" << length
178                       << ", OFFSET=" << offset << "\n";
179             return rc;
180         }
181         if (rc != static_cast<int>(length))
182         {
183             std::cerr << "mismatch between number of characters to read and "
184                       << "the length read, LENGTH=" << length << " COUNT=" << rc
185                       << "\n";
186             return -1;
187         }
188         memcpy(static_cast<char*>(vgaMemPtr.get()), buffer.data(),
189                pageAlignedLength);
190     }
191 
192     AspeedXdmaOp xdmaOp;
193     xdmaOp.upstream = upstream ? 1 : 0;
194     xdmaOp.hostAddr = address;
195     xdmaOp.len = length;
196 
197     rc = write(xdmaFd(), &xdmaOp, sizeof(xdmaOp));
198     if (rc < 0)
199     {
200         rc = -errno;
201         std::cerr << "Failed to execute the DMA operation, RC=" << rc
202                   << " UPSTREAM=" << upstream << " ADDRESS=" << address
203                   << " LENGTH=" << length << "\n";
204         return rc;
205     }
206 
207     if (!upstream)
208     {
209         rc = lseek(fd, offset, SEEK_SET);
210         if (rc == -1)
211         {
212             std::cerr << "lseek failed, ERROR=" << errno
213                       << ", UPSTREAM=" << upstream << ", OFFSET=" << offset
214                       << "\n";
215             return rc;
216         }
217         rc = write(fd, static_cast<const char*>(vgaMemPtr.get()), length);
218         if (rc == -1)
219         {
220             std::cerr << "file write failed, ERROR=" << errno
221                       << ", UPSTREAM=" << upstream << ", LENGTH=" << length
222                       << ", OFFSET=" << offset << "\n";
223             return rc;
224         }
225     }
226 
227     return 0;
228 }
229 
230 } // namespace dma
231 
232 namespace oem_ibm
233 {
234 
235 Response Handler::readFileIntoMemory(const pldm_msg* request,
236                                      size_t payloadLength)
237 {
238     uint32_t fileHandle = 0;
239     uint32_t offset = 0;
240     uint32_t length = 0;
241     uint64_t address = 0;
242 
243     Response response((sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES), 0);
244     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
245 
246     if (payloadLength != PLDM_RW_FILE_MEM_REQ_BYTES)
247     {
248         encode_rw_file_memory_resp(request->hdr.instance_id,
249                                    PLDM_READ_FILE_INTO_MEMORY,
250                                    PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
251         return response;
252     }
253 
254     decode_rw_file_memory_req(request, payloadLength, &fileHandle, &offset,
255                               &length, &address);
256 
257     using namespace pldm::filetable;
258     auto& table = buildFileTable(FILE_TABLE_JSON);
259     FileEntry value{};
260 
261     try
262     {
263         value = table.at(fileHandle);
264     }
265     catch (const std::exception& e)
266     {
267         std::cerr << "File handle does not exist in the file table, HANDLE="
268                   << fileHandle << "\n";
269         encode_rw_file_memory_resp(request->hdr.instance_id,
270                                    PLDM_READ_FILE_INTO_MEMORY,
271                                    PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
272         return response;
273     }
274 
275     if (!fs::exists(value.fsPath))
276     {
277         std::cerr << "File does not exist, HANDLE=" << fileHandle << "\n";
278         encode_rw_file_memory_resp(request->hdr.instance_id,
279                                    PLDM_READ_FILE_INTO_MEMORY,
280                                    PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
281         return response;
282     }
283 
284     auto fileSize = fs::file_size(value.fsPath);
285     if (offset >= fileSize)
286     {
287         std::cerr << "Offset exceeds file size, OFFSET=" << offset
288                   << " FILE_SIZE=" << fileSize << "\n";
289         encode_rw_file_memory_resp(request->hdr.instance_id,
290                                    PLDM_READ_FILE_INTO_MEMORY,
291                                    PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
292         return response;
293     }
294 
295     if (offset + length > fileSize)
296     {
297         length = fileSize - offset;
298     }
299 
300     if (length % dma::minSize)
301     {
302         std::cerr << "Read length is not a multiple of DMA minSize, LENGTH="
303                   << length << "\n";
304         encode_rw_file_memory_resp(request->hdr.instance_id,
305                                    PLDM_READ_FILE_INTO_MEMORY,
306                                    PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
307         return response;
308     }
309 
310     using namespace dma;
311     DMA intf;
312     return transferAll<DMA>(&intf, PLDM_READ_FILE_INTO_MEMORY, value.fsPath,
313                             offset, length, address, true,
314                             request->hdr.instance_id);
315 }
316 
317 Response Handler::writeFileFromMemory(const pldm_msg* request,
318                                       size_t payloadLength)
319 {
320     uint32_t fileHandle = 0;
321     uint32_t offset = 0;
322     uint32_t length = 0;
323     uint64_t address = 0;
324 
325     Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES, 0);
326     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
327 
328     if (payloadLength != PLDM_RW_FILE_MEM_REQ_BYTES)
329     {
330         encode_rw_file_memory_resp(request->hdr.instance_id,
331                                    PLDM_WRITE_FILE_FROM_MEMORY,
332                                    PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
333         return response;
334     }
335 
336     decode_rw_file_memory_req(request, payloadLength, &fileHandle, &offset,
337                               &length, &address);
338 
339     if (length % dma::minSize)
340     {
341         std::cerr << "Write length is not a multiple of DMA minSize, LENGTH="
342                   << length << "\n";
343         encode_rw_file_memory_resp(request->hdr.instance_id,
344                                    PLDM_WRITE_FILE_FROM_MEMORY,
345                                    PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
346         return response;
347     }
348 
349     using namespace pldm::filetable;
350     auto& table = buildFileTable(FILE_TABLE_JSON);
351     FileEntry value{};
352 
353     try
354     {
355         value = table.at(fileHandle);
356     }
357     catch (const std::exception& e)
358     {
359         std::cerr << "File handle does not exist in the file table, HANDLE="
360                   << fileHandle << "\n";
361         encode_rw_file_memory_resp(request->hdr.instance_id,
362                                    PLDM_WRITE_FILE_FROM_MEMORY,
363                                    PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
364         return response;
365     }
366 
367     if (!fs::exists(value.fsPath))
368     {
369         std::cerr << "File does not exist, HANDLE=" << fileHandle << "\n";
370         encode_rw_file_memory_resp(request->hdr.instance_id,
371                                    PLDM_WRITE_FILE_FROM_MEMORY,
372                                    PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
373         return response;
374     }
375 
376     auto fileSize = fs::file_size(value.fsPath);
377     if (offset >= fileSize)
378     {
379         std::cerr << "Offset exceeds file size, OFFSET=" << offset
380                   << " FILE_SIZE=" << fileSize << "\n";
381         encode_rw_file_memory_resp(request->hdr.instance_id,
382                                    PLDM_WRITE_FILE_FROM_MEMORY,
383                                    PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
384         return response;
385     }
386 
387     using namespace dma;
388     DMA intf;
389     return transferAll<DMA>(&intf, PLDM_WRITE_FILE_FROM_MEMORY, value.fsPath,
390                             offset, length, address, false,
391                             request->hdr.instance_id);
392 }
393 
394 Response Handler::getFileTable(const pldm_msg* request, size_t payloadLength)
395 {
396     uint32_t transferHandle = 0;
397     uint8_t transferFlag = 0;
398     uint8_t tableType = 0;
399 
400     Response response(sizeof(pldm_msg_hdr) +
401                       PLDM_GET_FILE_TABLE_MIN_RESP_BYTES);
402     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
403 
404     if (payloadLength != PLDM_GET_FILE_TABLE_REQ_BYTES)
405     {
406         encode_get_file_table_resp(request->hdr.instance_id,
407                                    PLDM_ERROR_INVALID_LENGTH, 0, 0, nullptr, 0,
408                                    responsePtr);
409         return response;
410     }
411 
412     auto rc = decode_get_file_table_req(request, payloadLength, &transferHandle,
413                                         &transferFlag, &tableType);
414     if (rc)
415     {
416         encode_get_file_table_resp(request->hdr.instance_id, rc, 0, 0, nullptr,
417                                    0, responsePtr);
418         return response;
419     }
420 
421     if (tableType != PLDM_FILE_ATTRIBUTE_TABLE)
422     {
423         encode_get_file_table_resp(request->hdr.instance_id,
424                                    PLDM_INVALID_FILE_TABLE_TYPE, 0, 0, nullptr,
425                                    0, responsePtr);
426         return response;
427     }
428 
429     using namespace pldm::filetable;
430     auto table = buildFileTable(FILE_TABLE_JSON);
431     auto attrTable = table();
432     response.resize(response.size() + attrTable.size());
433     responsePtr = reinterpret_cast<pldm_msg*>(response.data());
434 
435     if (attrTable.empty())
436     {
437         encode_get_file_table_resp(request->hdr.instance_id,
438                                    PLDM_FILE_TABLE_UNAVAILABLE, 0, 0, nullptr,
439                                    0, responsePtr);
440         return response;
441     }
442 
443     encode_get_file_table_resp(request->hdr.instance_id, PLDM_SUCCESS, 0,
444                                PLDM_START_AND_END, attrTable.data(),
445                                attrTable.size(), responsePtr);
446     return response;
447 }
448 
449 Response Handler::readFile(const pldm_msg* request, size_t payloadLength)
450 {
451     uint32_t fileHandle = 0;
452     uint32_t offset = 0;
453     uint32_t length = 0;
454 
455     Response response(sizeof(pldm_msg_hdr) + PLDM_READ_FILE_RESP_BYTES);
456     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
457 
458     if (payloadLength != PLDM_READ_FILE_REQ_BYTES)
459     {
460         encode_read_file_resp(request->hdr.instance_id,
461                               PLDM_ERROR_INVALID_LENGTH, length, responsePtr);
462         return response;
463     }
464 
465     auto rc = decode_read_file_req(request, payloadLength, &fileHandle, &offset,
466                                    &length);
467 
468     if (rc)
469     {
470         encode_read_file_resp(request->hdr.instance_id, rc, 0, responsePtr);
471         return response;
472     }
473 
474     using namespace pldm::filetable;
475     auto& table = buildFileTable(FILE_TABLE_JSON);
476     FileEntry value{};
477 
478     try
479     {
480         value = table.at(fileHandle);
481     }
482     catch (const std::exception& e)
483     {
484         std::cerr << "File handle does not exist in the file table, HANDLE="
485                   << fileHandle << "\n";
486         encode_read_file_resp(request->hdr.instance_id,
487                               PLDM_INVALID_FILE_HANDLE, length, responsePtr);
488         return response;
489     }
490 
491     if (!fs::exists(value.fsPath))
492     {
493         std::cerr << "File does not exist, HANDLE=" << fileHandle << "\n";
494         encode_read_file_resp(request->hdr.instance_id,
495                               PLDM_INVALID_FILE_HANDLE, length, responsePtr);
496         return response;
497     }
498 
499     auto fileSize = fs::file_size(value.fsPath);
500     if (offset >= fileSize)
501     {
502         std::cerr << "Offset exceeds file size, OFFSET=" << offset
503                   << " FILE_SIZE=" << fileSize << "\n";
504         encode_read_file_resp(request->hdr.instance_id, PLDM_DATA_OUT_OF_RANGE,
505                               length, responsePtr);
506         return response;
507     }
508 
509     if (offset + length > fileSize)
510     {
511         length = fileSize - offset;
512     }
513 
514     response.resize(response.size() + length);
515     responsePtr = reinterpret_cast<pldm_msg*>(response.data());
516     auto fileDataPos = reinterpret_cast<char*>(responsePtr);
517     fileDataPos += sizeof(pldm_msg_hdr) + sizeof(uint8_t) + sizeof(length);
518 
519     std::ifstream stream(value.fsPath, std::ios::in | std::ios::binary);
520     stream.seekg(offset);
521     stream.read(fileDataPos, length);
522 
523     encode_read_file_resp(request->hdr.instance_id, PLDM_SUCCESS, length,
524                           responsePtr);
525 
526     return response;
527 }
528 
529 Response Handler::writeFile(const pldm_msg* request, size_t payloadLength)
530 {
531     uint32_t fileHandle = 0;
532     uint32_t offset = 0;
533     uint32_t length = 0;
534     size_t fileDataOffset = 0;
535 
536     Response response(sizeof(pldm_msg_hdr) + PLDM_WRITE_FILE_RESP_BYTES);
537     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
538 
539     if (payloadLength < PLDM_WRITE_FILE_REQ_BYTES)
540     {
541         encode_write_file_resp(request->hdr.instance_id,
542                                PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
543         return response;
544     }
545 
546     auto rc = decode_write_file_req(request, payloadLength, &fileHandle,
547                                     &offset, &length, &fileDataOffset);
548 
549     if (rc)
550     {
551         encode_write_file_resp(request->hdr.instance_id, rc, 0, responsePtr);
552         return response;
553     }
554 
555     using namespace pldm::filetable;
556     auto& table = buildFileTable(FILE_TABLE_JSON);
557     FileEntry value{};
558 
559     try
560     {
561         value = table.at(fileHandle);
562     }
563     catch (const std::exception& e)
564     {
565         std::cerr << "File handle does not exist in the file table, HANDLE="
566                   << fileHandle << "\n";
567         encode_write_file_resp(request->hdr.instance_id,
568                                PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
569         return response;
570     }
571 
572     if (!fs::exists(value.fsPath))
573     {
574         std::cerr << "File does not exist, HANDLE=" << fileHandle << "\n";
575         encode_write_file_resp(request->hdr.instance_id,
576                                PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
577         return response;
578     }
579 
580     auto fileSize = fs::file_size(value.fsPath);
581     if (offset >= fileSize)
582     {
583         std::cerr << "Offset exceeds file size, OFFSET=" << offset
584                   << " FILE_SIZE=" << fileSize << "\n";
585         encode_write_file_resp(request->hdr.instance_id, PLDM_DATA_OUT_OF_RANGE,
586                                0, responsePtr);
587         return response;
588     }
589 
590     auto fileDataPos =
591         reinterpret_cast<const char*>(request->payload) + fileDataOffset;
592 
593     std::ofstream stream(value.fsPath,
594                          std::ios::in | std::ios::out | std::ios::binary);
595     stream.seekp(offset);
596     stream.write(fileDataPos, length);
597 
598     encode_write_file_resp(request->hdr.instance_id, PLDM_SUCCESS, length,
599                            responsePtr);
600 
601     return response;
602 }
603 
604 Response rwFileByTypeIntoMemory(uint8_t cmd, const pldm_msg* request,
605                                 size_t payloadLength,
606                                 oem_platform::Handler* oemPlatformHandler)
607 {
608     Response response(
609         sizeof(pldm_msg_hdr) + PLDM_RW_FILE_BY_TYPE_MEM_RESP_BYTES, 0);
610     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
611 
612     if (payloadLength != PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES)
613     {
614         encode_rw_file_by_type_memory_resp(request->hdr.instance_id, cmd,
615                                            PLDM_ERROR_INVALID_LENGTH, 0,
616                                            responsePtr);
617         return response;
618     }
619 
620     uint16_t fileType{};
621     uint32_t fileHandle{};
622     uint32_t offset{};
623     uint32_t length{};
624     uint64_t address{};
625     auto rc = decode_rw_file_by_type_memory_req(request, payloadLength,
626                                                 &fileType, &fileHandle, &offset,
627                                                 &length, &address);
628     if (rc != PLDM_SUCCESS)
629     {
630         encode_rw_file_by_type_memory_resp(request->hdr.instance_id, cmd, rc, 0,
631                                            responsePtr);
632         return response;
633     }
634     if (length % dma::minSize)
635     {
636         std::cerr << "Length is not a multiple of DMA minSize, LENGTH="
637                   << length << "\n";
638         encode_rw_file_by_type_memory_resp(request->hdr.instance_id, cmd,
639                                            PLDM_ERROR_INVALID_LENGTH, 0,
640                                            responsePtr);
641         return response;
642     }
643 
644     std::unique_ptr<FileHandler> handler{};
645     try
646     {
647         handler = getHandlerByType(fileType, fileHandle);
648     }
649     catch (const InternalFailure& e)
650     {
651         std::cerr << "unknown file type, TYPE=" << fileType << "\n";
652         encode_rw_file_by_type_memory_resp(request->hdr.instance_id, cmd,
653                                            PLDM_INVALID_FILE_TYPE, 0,
654                                            responsePtr);
655         return response;
656     }
657 
658     rc = cmd == PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY
659              ? handler->writeFromMemory(offset, length, address,
660                                         oemPlatformHandler)
661              : handler->readIntoMemory(offset, length, address,
662                                        oemPlatformHandler);
663     encode_rw_file_by_type_memory_resp(request->hdr.instance_id, cmd, rc,
664                                        length, responsePtr);
665     return response;
666 }
667 
668 Response Handler::writeFileByTypeFromMemory(const pldm_msg* request,
669                                             size_t payloadLength)
670 {
671     return rwFileByTypeIntoMemory(PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY, request,
672                                   payloadLength, oemPlatformHandler);
673 }
674 
675 Response Handler::readFileByTypeIntoMemory(const pldm_msg* request,
676                                            size_t payloadLength)
677 {
678     return rwFileByTypeIntoMemory(PLDM_READ_FILE_BY_TYPE_INTO_MEMORY, request,
679                                   payloadLength, oemPlatformHandler);
680 }
681 
682 Response Handler::writeFileByType(const pldm_msg* request, size_t payloadLength)
683 {
684     Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_BY_TYPE_RESP_BYTES);
685     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
686 
687     if (payloadLength < PLDM_RW_FILE_BY_TYPE_REQ_BYTES)
688     {
689         encode_rw_file_by_type_resp(request->hdr.instance_id,
690                                     PLDM_WRITE_FILE_BY_TYPE,
691                                     PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
692         return response;
693     }
694     uint16_t fileType{};
695     uint32_t fileHandle{};
696     uint32_t offset{};
697     uint32_t length{};
698 
699     auto rc = decode_rw_file_by_type_req(request, payloadLength, &fileType,
700                                          &fileHandle, &offset, &length);
701     if (rc != PLDM_SUCCESS)
702     {
703         encode_rw_file_by_type_resp(request->hdr.instance_id,
704                                     PLDM_WRITE_FILE_BY_TYPE, rc, 0,
705                                     responsePtr);
706         return response;
707     }
708 
709     std::unique_ptr<FileHandler> handler{};
710     try
711     {
712         handler = getHandlerByType(fileType, fileHandle);
713     }
714     catch (const InternalFailure& e)
715     {
716         std::cerr << "unknown file type, TYPE=" << fileType << "\n";
717         encode_rw_file_by_type_resp(request->hdr.instance_id,
718                                     PLDM_WRITE_FILE_BY_TYPE,
719                                     PLDM_INVALID_FILE_TYPE, 0, responsePtr);
720         return response;
721     }
722 
723     rc = handler->write(reinterpret_cast<const char*>(
724                             request->payload + PLDM_RW_FILE_BY_TYPE_REQ_BYTES),
725                         offset, length, oemPlatformHandler);
726     encode_rw_file_by_type_resp(request->hdr.instance_id,
727                                 PLDM_WRITE_FILE_BY_TYPE, rc, length,
728                                 responsePtr);
729     return response;
730 }
731 
732 Response Handler::readFileByType(const pldm_msg* request, size_t payloadLength)
733 {
734     Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_BY_TYPE_RESP_BYTES);
735     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
736 
737     if (payloadLength != PLDM_RW_FILE_BY_TYPE_REQ_BYTES)
738     {
739         encode_rw_file_by_type_resp(request->hdr.instance_id,
740                                     PLDM_READ_FILE_BY_TYPE,
741                                     PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
742         return response;
743     }
744     uint16_t fileType{};
745     uint32_t fileHandle{};
746     uint32_t offset{};
747     uint32_t length{};
748 
749     auto rc = decode_rw_file_by_type_req(request, payloadLength, &fileType,
750                                          &fileHandle, &offset, &length);
751     if (rc != PLDM_SUCCESS)
752     {
753         encode_rw_file_by_type_resp(request->hdr.instance_id,
754                                     PLDM_READ_FILE_BY_TYPE, rc, 0, responsePtr);
755         return response;
756     }
757 
758     std::unique_ptr<FileHandler> handler{};
759     try
760     {
761         handler = getHandlerByType(fileType, fileHandle);
762     }
763     catch (const InternalFailure& e)
764     {
765         std::cerr << "unknown file type, TYPE=" << fileType << "\n";
766         encode_rw_file_by_type_resp(request->hdr.instance_id,
767                                     PLDM_READ_FILE_BY_TYPE,
768                                     PLDM_INVALID_FILE_TYPE, 0, responsePtr);
769         return response;
770     }
771 
772     rc = handler->read(offset, length, response, oemPlatformHandler);
773     responsePtr = reinterpret_cast<pldm_msg*>(response.data());
774     encode_rw_file_by_type_resp(request->hdr.instance_id,
775                                 PLDM_READ_FILE_BY_TYPE, rc, length,
776                                 responsePtr);
777     return response;
778 }
779 
780 Response Handler::fileAck(const pldm_msg* request, size_t payloadLength)
781 {
782     Response response(sizeof(pldm_msg_hdr) + PLDM_FILE_ACK_RESP_BYTES);
783     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
784 
785     if (payloadLength != PLDM_FILE_ACK_REQ_BYTES)
786     {
787         encode_file_ack_resp(request->hdr.instance_id,
788                              PLDM_ERROR_INVALID_LENGTH, responsePtr);
789         return response;
790     }
791     uint16_t fileType{};
792     uint32_t fileHandle{};
793     uint8_t fileStatus{};
794 
795     auto rc = decode_file_ack_req(request, payloadLength, &fileType,
796                                   &fileHandle, &fileStatus);
797     if (rc != PLDM_SUCCESS)
798     {
799         encode_file_ack_resp(request->hdr.instance_id, rc, responsePtr);
800         return response;
801     }
802 
803     std::unique_ptr<FileHandler> handler{};
804     try
805     {
806         handler = getHandlerByType(fileType, fileHandle);
807     }
808 
809     catch (const InternalFailure& e)
810     {
811         encode_file_ack_resp(request->hdr.instance_id, PLDM_INVALID_FILE_TYPE,
812                              responsePtr);
813         return response;
814     }
815 
816     rc = handler->fileAck(fileStatus);
817     encode_file_ack_resp(request->hdr.instance_id, rc, responsePtr);
818     return response;
819 }
820 
821 Response Handler::getAlertStatus(const pldm_msg* request, size_t payloadLength)
822 {
823     Response response(sizeof(pldm_msg_hdr) + PLDM_GET_ALERT_STATUS_RESP_BYTES);
824     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
825     if (payloadLength != PLDM_GET_ALERT_STATUS_REQ_BYTES)
826     {
827         return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
828     }
829 
830     uint8_t versionId{};
831 
832     auto rc = decode_get_alert_status_req(request, payloadLength, &versionId);
833     if (rc != PLDM_SUCCESS)
834     {
835         return CmdHandler::ccOnlyResponse(request, rc);
836     }
837 
838     if (versionId != 0)
839     {
840         return CmdHandler::ccOnlyResponse(request,
841                                           PLDM_HOST_UNSUPPORTED_FORMAT_VERSION);
842     }
843 
844     constexpr uint32_t rackEntry = 0xFF000030;
845     constexpr uint32_t priCecNode = 0x00008030;
846     rc = encode_get_alert_status_resp(request->hdr.instance_id, PLDM_SUCCESS,
847                                       rackEntry, priCecNode, responsePtr,
848                                       PLDM_GET_ALERT_STATUS_RESP_BYTES);
849     if (rc != PLDM_SUCCESS)
850     {
851         return CmdHandler::ccOnlyResponse(request, rc);
852     }
853 
854     return response;
855 }
856 
857 Response Handler::newFileAvailable(const pldm_msg* request,
858                                    size_t payloadLength)
859 {
860     Response response(sizeof(pldm_msg_hdr) + PLDM_NEW_FILE_RESP_BYTES);
861 
862     if (payloadLength != PLDM_NEW_FILE_REQ_BYTES)
863     {
864         return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
865     }
866     uint16_t fileType{};
867     uint32_t fileHandle{};
868     uint64_t length{};
869 
870     auto rc = decode_new_file_req(request, payloadLength, &fileType,
871                                   &fileHandle, &length);
872 
873     if (rc != PLDM_SUCCESS)
874     {
875         return CmdHandler::ccOnlyResponse(request, rc);
876     }
877 
878     std::unique_ptr<FileHandler> handler{};
879     try
880     {
881         handler = getHandlerByType(fileType, fileHandle);
882     }
883     catch (const InternalFailure& e)
884     {
885         std::cerr << "unknown file type, TYPE=" << fileType << "\n";
886         return CmdHandler::ccOnlyResponse(request, PLDM_INVALID_FILE_TYPE);
887     }
888 
889     rc = handler->newFileAvailable(length);
890     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
891     encode_new_file_resp(request->hdr.instance_id, rc, responsePtr);
892     return response;
893 }
894 
895 } // namespace oem_ibm
896 } // namespace responder
897 } // namespace pldm
898