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(
285             "File handle does not exist in the file table, HANDLE={FILE_HANDLE}",
286             "FILE_HANDLE", fileHandle);
287         encode_rw_file_memory_resp(request->hdr.instance_id,
288                                    PLDM_READ_FILE_INTO_MEMORY,
289                                    PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
290         return response;
291     }
292 
293     if (!fs::exists(value.fsPath))
294     {
295         error("File does not exist, HANDLE={FILE_HANDLE}", "FILE_HANDLE",
296               fileHandle);
297         encode_rw_file_memory_resp(request->hdr.instance_id,
298                                    PLDM_READ_FILE_INTO_MEMORY,
299                                    PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
300         return response;
301     }
302 
303     auto fileSize = fs::file_size(value.fsPath);
304     if (offset >= fileSize)
305     {
306         error("Offset exceeds file size, OFFSET={OFFSTE} FILE_SIZE={FILE_SIZE}",
307               "OFFSET", offset, "FILE_SIZE", fileSize);
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(
379             "File handle does not exist in the file table, HANDLE={FILE_HANDLE}",
380             "FILE_HANDLE", fileHandle);
381         encode_rw_file_memory_resp(request->hdr.instance_id,
382                                    PLDM_WRITE_FILE_FROM_MEMORY,
383                                    PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
384         return response;
385     }
386 
387     if (!fs::exists(value.fsPath))
388     {
389         error("File does not exist, HANDLE={FILE_HANDLE}", "FILE_HANDLE",
390               fileHandle);
391         encode_rw_file_memory_resp(request->hdr.instance_id,
392                                    PLDM_WRITE_FILE_FROM_MEMORY,
393                                    PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
394         return response;
395     }
396 
397     auto fileSize = fs::file_size(value.fsPath);
398     if (offset >= fileSize)
399     {
400         error("Offset exceeds file size, OFFSET={OFFSET} FILE_SIZE={FILE_SIZE}",
401               "OFFSET", offset, "FILE_SIZE", fileSize);
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(
506             "File handle does not exist in the file table, HANDLE={FILE_HANDLE}",
507             "FILE_HANDLE", fileHandle);
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(
589             "File handle does not exist in the file table, HANDLE={FILE_HANDLE}",
590             "FILE_HANDLE", fileHandle);
591         encode_write_file_resp(request->hdr.instance_id,
592                                PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
593         return response;
594     }
595 
596     if (!fs::exists(value.fsPath))
597     {
598         error("File does not exist, HANDLE={FILE_HANDLE}", "FILE_HANDLE",
599               fileHandle);
600         encode_write_file_resp(request->hdr.instance_id,
601                                PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
602         return response;
603     }
604 
605     auto fileSize = fs::file_size(value.fsPath);
606     if (offset >= fileSize)
607     {
608         error("Offset exceeds file size, OFFSET={OFFSET} FILE_SIZE={FILE_SIZE}",
609               "OFFSET", offset, "FILE_SIZE", fileSize);
610         encode_write_file_resp(request->hdr.instance_id, PLDM_DATA_OUT_OF_RANGE,
611                                0, responsePtr);
612         return response;
613     }
614 
615     auto fileDataPos = reinterpret_cast<const char*>(request->payload) +
616                        fileDataOffset;
617 
618     std::ofstream stream(value.fsPath,
619                          std::ios::in | std::ios::out | std::ios::binary);
620     stream.seekp(offset);
621     stream.write(fileDataPos, length);
622 
623     encode_write_file_resp(request->hdr.instance_id, PLDM_SUCCESS, length,
624                            responsePtr);
625 
626     return response;
627 }
628 
629 Response rwFileByTypeIntoMemory(uint8_t cmd, const pldm_msg* request,
630                                 size_t payloadLength,
631                                 oem_platform::Handler* oemPlatformHandler)
632 {
633     Response response(
634         sizeof(pldm_msg_hdr) + PLDM_RW_FILE_BY_TYPE_MEM_RESP_BYTES, 0);
635     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
636 
637     if (payloadLength != PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES)
638     {
639         encode_rw_file_by_type_memory_resp(request->hdr.instance_id, cmd,
640                                            PLDM_ERROR_INVALID_LENGTH, 0,
641                                            responsePtr);
642         return response;
643     }
644 
645     uint16_t fileType{};
646     uint32_t fileHandle{};
647     uint32_t offset{};
648     uint32_t length{};
649     uint64_t address{};
650     auto rc = decode_rw_file_by_type_memory_req(request, payloadLength,
651                                                 &fileType, &fileHandle, &offset,
652                                                 &length, &address);
653     if (rc != PLDM_SUCCESS)
654     {
655         encode_rw_file_by_type_memory_resp(request->hdr.instance_id, cmd, rc, 0,
656                                            responsePtr);
657         return response;
658     }
659     if (length % dma::minSize)
660     {
661         error("Length is not a multiple of DMA minSize, LENGTH={LEN}", "LEN",
662               length);
663         encode_rw_file_by_type_memory_resp(request->hdr.instance_id, cmd,
664                                            PLDM_ERROR_INVALID_LENGTH, 0,
665                                            responsePtr);
666         return response;
667     }
668 
669     std::unique_ptr<FileHandler> handler{};
670     try
671     {
672         handler = getHandlerByType(fileType, fileHandle);
673     }
674     catch (const InternalFailure& e)
675     {
676         error("unknown file type, TYPE={FILE_TYPE}", "FILE_TYPE", fileType);
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, TYPE={FILE_TYPE}", "FILE_TYPE", fileType);
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, TYPE={FILE_TYPE}", "FILE_TYPE", fileType);
791         encode_rw_file_by_type_resp(request->hdr.instance_id,
792                                     PLDM_READ_FILE_BY_TYPE,
793                                     PLDM_INVALID_FILE_TYPE, 0, responsePtr);
794         return response;
795     }
796 
797     rc = handler->read(offset, length, response, oemPlatformHandler);
798     responsePtr = reinterpret_cast<pldm_msg*>(response.data());
799     encode_rw_file_by_type_resp(request->hdr.instance_id,
800                                 PLDM_READ_FILE_BY_TYPE, rc, length,
801                                 responsePtr);
802     return response;
803 }
804 
805 Response Handler::fileAck(const pldm_msg* request, size_t payloadLength)
806 {
807     Response response(sizeof(pldm_msg_hdr) + PLDM_FILE_ACK_RESP_BYTES);
808     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
809 
810     if (payloadLength != PLDM_FILE_ACK_REQ_BYTES)
811     {
812         encode_file_ack_resp(request->hdr.instance_id,
813                              PLDM_ERROR_INVALID_LENGTH, responsePtr);
814         return response;
815     }
816     uint16_t fileType{};
817     uint32_t fileHandle{};
818     uint8_t fileStatus{};
819 
820     auto rc = decode_file_ack_req(request, payloadLength, &fileType,
821                                   &fileHandle, &fileStatus);
822     if (rc != PLDM_SUCCESS)
823     {
824         encode_file_ack_resp(request->hdr.instance_id, rc, responsePtr);
825         return response;
826     }
827 
828     std::unique_ptr<FileHandler> handler{};
829     try
830     {
831         handler = getHandlerByType(fileType, fileHandle);
832     }
833 
834     catch (const InternalFailure& e)
835     {
836         encode_file_ack_resp(request->hdr.instance_id, PLDM_INVALID_FILE_TYPE,
837                              responsePtr);
838         return response;
839     }
840 
841     rc = handler->fileAck(fileStatus);
842     encode_file_ack_resp(request->hdr.instance_id, rc, responsePtr);
843     return response;
844 }
845 
846 Response Handler::getAlertStatus(const pldm_msg* request, size_t payloadLength)
847 {
848     Response response(sizeof(pldm_msg_hdr) + PLDM_GET_ALERT_STATUS_RESP_BYTES);
849     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
850     if (payloadLength != PLDM_GET_ALERT_STATUS_REQ_BYTES)
851     {
852         return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
853     }
854 
855     uint8_t versionId{};
856 
857     auto rc = decode_get_alert_status_req(request, payloadLength, &versionId);
858     if (rc != PLDM_SUCCESS)
859     {
860         return CmdHandler::ccOnlyResponse(request, rc);
861     }
862 
863     if (versionId != 0)
864     {
865         return CmdHandler::ccOnlyResponse(request,
866                                           PLDM_HOST_UNSUPPORTED_FORMAT_VERSION);
867     }
868 
869     constexpr uint32_t rackEntry = 0xFF000030;
870     constexpr uint32_t priCecNode = 0x00008030;
871     rc = encode_get_alert_status_resp(request->hdr.instance_id, PLDM_SUCCESS,
872                                       rackEntry, priCecNode, responsePtr,
873                                       PLDM_GET_ALERT_STATUS_RESP_BYTES);
874     if (rc != PLDM_SUCCESS)
875     {
876         return CmdHandler::ccOnlyResponse(request, rc);
877     }
878 
879     return response;
880 }
881 
882 Response Handler::newFileAvailable(const pldm_msg* request,
883                                    size_t payloadLength)
884 {
885     Response response(sizeof(pldm_msg_hdr) + PLDM_NEW_FILE_RESP_BYTES);
886 
887     if (payloadLength != PLDM_NEW_FILE_REQ_BYTES)
888     {
889         return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
890     }
891     uint16_t fileType{};
892     uint32_t fileHandle{};
893     uint64_t length{};
894 
895     auto rc = decode_new_file_req(request, payloadLength, &fileType,
896                                   &fileHandle, &length);
897 
898     if (rc != PLDM_SUCCESS)
899     {
900         return CmdHandler::ccOnlyResponse(request, rc);
901     }
902 
903     std::unique_ptr<FileHandler> handler{};
904     try
905     {
906         handler = getHandlerByType(fileType, fileHandle);
907     }
908     catch (const InternalFailure& e)
909     {
910         error("unknown file type, TYPE={FILE_TYPE}", "FILE_TYPE", fileType);
911         return CmdHandler::ccOnlyResponse(request, PLDM_INVALID_FILE_TYPE);
912     }
913 
914     rc = handler->newFileAvailable(length);
915     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
916     encode_new_file_resp(request->hdr.instance_id, rc, responsePtr);
917     return response;
918 }
919 
920 } // namespace oem_ibm
921 } // namespace responder
922 } // namespace pldm
923