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