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