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(
307             "Offset exceeds file size, OFFSET={OFFSTE} FILE_SIZE={FILE_SIZE} FILE_HANDLE{FILE_HANDLE}",
308             "OFFSET", offset, "FILE_SIZE", fileSize, "FILE_HANDLE", fileHandle);
309         encode_rw_file_memory_resp(request->hdr.instance_id,
310                                    PLDM_READ_FILE_INTO_MEMORY,
311                                    PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
312         return response;
313     }
314 
315     if (offset + length > fileSize)
316     {
317         length = fileSize - offset;
318     }
319 
320     if (length % dma::minSize)
321     {
322         error("Read length is not a multiple of DMA minSize, LENGTH={LEN}",
323               "LEN", length);
324         encode_rw_file_memory_resp(request->hdr.instance_id,
325                                    PLDM_READ_FILE_INTO_MEMORY,
326                                    PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
327         return response;
328     }
329 
330     using namespace dma;
331     DMA intf;
332     return transferAll<DMA>(&intf, PLDM_READ_FILE_INTO_MEMORY, value.fsPath,
333                             offset, length, address, true,
334                             request->hdr.instance_id);
335 }
336 
337 Response Handler::writeFileFromMemory(const pldm_msg* request,
338                                       size_t payloadLength)
339 {
340     uint32_t fileHandle = 0;
341     uint32_t offset = 0;
342     uint32_t length = 0;
343     uint64_t address = 0;
344 
345     Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_RESP_BYTES, 0);
346     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
347 
348     if (payloadLength != PLDM_RW_FILE_MEM_REQ_BYTES)
349     {
350         encode_rw_file_memory_resp(request->hdr.instance_id,
351                                    PLDM_WRITE_FILE_FROM_MEMORY,
352                                    PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
353         return response;
354     }
355 
356     decode_rw_file_memory_req(request, payloadLength, &fileHandle, &offset,
357                               &length, &address);
358 
359     if (length % dma::minSize)
360     {
361         error("Write length is not a multiple of DMA minSize, LENGTH={LEN}",
362               "LEN", length);
363         encode_rw_file_memory_resp(request->hdr.instance_id,
364                                    PLDM_WRITE_FILE_FROM_MEMORY,
365                                    PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
366         return response;
367     }
368 
369     using namespace pldm::filetable;
370     auto& table = buildFileTable(FILE_TABLE_JSON);
371     FileEntry value{};
372 
373     try
374     {
375         value = table.at(fileHandle);
376     }
377     catch (const std::exception& e)
378     {
379         error(
380             "File handle does not exist in the file table, HANDLE={FILE_HANDLE}",
381             "FILE_HANDLE", fileHandle);
382         encode_rw_file_memory_resp(request->hdr.instance_id,
383                                    PLDM_WRITE_FILE_FROM_MEMORY,
384                                    PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
385         return response;
386     }
387 
388     if (!fs::exists(value.fsPath))
389     {
390         error("File does not exist, HANDLE={FILE_HANDLE}", "FILE_HANDLE",
391               fileHandle);
392         encode_rw_file_memory_resp(request->hdr.instance_id,
393                                    PLDM_WRITE_FILE_FROM_MEMORY,
394                                    PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
395         return response;
396     }
397 
398     auto fileSize = fs::file_size(value.fsPath);
399     if (offset >= fileSize)
400     {
401         error(
402             "Offset exceeds file size, OFFSET={OFFSET} FILE_SIZE={FILE_SIZE} FILE_HANDLE{FILE_HANDLE}",
403             "OFFSET", offset, "FILE_SIZE", fileSize, "FILE_HANDLE", fileHandle);
404         encode_rw_file_memory_resp(request->hdr.instance_id,
405                                    PLDM_WRITE_FILE_FROM_MEMORY,
406                                    PLDM_DATA_OUT_OF_RANGE, 0, responsePtr);
407         return response;
408     }
409 
410     using namespace dma;
411     DMA intf;
412     return transferAll<DMA>(&intf, PLDM_WRITE_FILE_FROM_MEMORY, value.fsPath,
413                             offset, length, address, false,
414                             request->hdr.instance_id);
415 }
416 
417 Response Handler::getFileTable(const pldm_msg* request, size_t payloadLength)
418 {
419     uint32_t transferHandle = 0;
420     uint8_t transferFlag = 0;
421     uint8_t tableType = 0;
422 
423     Response response(sizeof(pldm_msg_hdr) +
424                       PLDM_GET_FILE_TABLE_MIN_RESP_BYTES);
425     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
426 
427     if (payloadLength != PLDM_GET_FILE_TABLE_REQ_BYTES)
428     {
429         encode_get_file_table_resp(request->hdr.instance_id,
430                                    PLDM_ERROR_INVALID_LENGTH, 0, 0, nullptr, 0,
431                                    responsePtr);
432         return response;
433     }
434 
435     auto rc = decode_get_file_table_req(request, payloadLength, &transferHandle,
436                                         &transferFlag, &tableType);
437     if (rc)
438     {
439         encode_get_file_table_resp(request->hdr.instance_id, rc, 0, 0, nullptr,
440                                    0, responsePtr);
441         return response;
442     }
443 
444     if (tableType != PLDM_FILE_ATTRIBUTE_TABLE)
445     {
446         encode_get_file_table_resp(request->hdr.instance_id,
447                                    PLDM_INVALID_FILE_TABLE_TYPE, 0, 0, nullptr,
448                                    0, responsePtr);
449         return response;
450     }
451 
452     using namespace pldm::filetable;
453     auto table = buildFileTable(FILE_TABLE_JSON);
454     auto attrTable = table();
455     response.resize(response.size() + attrTable.size());
456     responsePtr = reinterpret_cast<pldm_msg*>(response.data());
457 
458     if (attrTable.empty())
459     {
460         encode_get_file_table_resp(request->hdr.instance_id,
461                                    PLDM_FILE_TABLE_UNAVAILABLE, 0, 0, nullptr,
462                                    0, responsePtr);
463         return response;
464     }
465 
466     encode_get_file_table_resp(request->hdr.instance_id, PLDM_SUCCESS, 0,
467                                PLDM_START_AND_END, attrTable.data(),
468                                attrTable.size(), responsePtr);
469     return response;
470 }
471 
472 Response Handler::readFile(const pldm_msg* request, size_t payloadLength)
473 {
474     uint32_t fileHandle = 0;
475     uint32_t offset = 0;
476     uint32_t length = 0;
477 
478     Response response(sizeof(pldm_msg_hdr) + PLDM_READ_FILE_RESP_BYTES);
479     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
480 
481     if (payloadLength != PLDM_READ_FILE_REQ_BYTES)
482     {
483         encode_read_file_resp(request->hdr.instance_id,
484                               PLDM_ERROR_INVALID_LENGTH, length, responsePtr);
485         return response;
486     }
487 
488     auto rc = decode_read_file_req(request, payloadLength, &fileHandle, &offset,
489                                    &length);
490 
491     if (rc)
492     {
493         encode_read_file_resp(request->hdr.instance_id, rc, 0, responsePtr);
494         return response;
495     }
496 
497     using namespace pldm::filetable;
498     auto& table = buildFileTable(FILE_TABLE_JSON);
499     FileEntry value{};
500 
501     try
502     {
503         value = table.at(fileHandle);
504     }
505     catch (const std::exception& e)
506     {
507         error(
508             "File handle does not exist in the file table, HANDLE={FILE_HANDLE}",
509             "FILE_HANDLE", fileHandle);
510         encode_read_file_resp(request->hdr.instance_id,
511                               PLDM_INVALID_FILE_HANDLE, length, responsePtr);
512         return response;
513     }
514 
515     if (!fs::exists(value.fsPath))
516     {
517         error("File does not exist, HANDLE={FILE_HANDLE}", "FILE_HANDLE",
518               fileHandle);
519         encode_read_file_resp(request->hdr.instance_id,
520                               PLDM_INVALID_FILE_HANDLE, length, responsePtr);
521         return response;
522     }
523 
524     auto fileSize = fs::file_size(value.fsPath);
525     if (offset >= fileSize)
526     {
527         error("Offset exceeds file size, OFFSET={OFFSET} FILE_SIZE={FILE_SIZE}",
528               "OFFSET", offset, "FILE_SIZE", fileSize);
529         encode_read_file_resp(request->hdr.instance_id, PLDM_DATA_OUT_OF_RANGE,
530                               length, responsePtr);
531         return response;
532     }
533 
534     if (offset + length > fileSize)
535     {
536         length = fileSize - offset;
537     }
538 
539     response.resize(response.size() + length);
540     responsePtr = reinterpret_cast<pldm_msg*>(response.data());
541     auto fileDataPos = reinterpret_cast<char*>(responsePtr);
542     fileDataPos += sizeof(pldm_msg_hdr) + sizeof(uint8_t) + sizeof(length);
543 
544     std::ifstream stream(value.fsPath, std::ios::in | std::ios::binary);
545     stream.seekg(offset);
546     stream.read(fileDataPos, length);
547 
548     encode_read_file_resp(request->hdr.instance_id, PLDM_SUCCESS, length,
549                           responsePtr);
550 
551     return response;
552 }
553 
554 Response Handler::writeFile(const pldm_msg* request, size_t payloadLength)
555 {
556     uint32_t fileHandle = 0;
557     uint32_t offset = 0;
558     uint32_t length = 0;
559     size_t fileDataOffset = 0;
560 
561     Response response(sizeof(pldm_msg_hdr) + PLDM_WRITE_FILE_RESP_BYTES);
562     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
563 
564     if (payloadLength < PLDM_WRITE_FILE_REQ_BYTES)
565     {
566         encode_write_file_resp(request->hdr.instance_id,
567                                PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
568         return response;
569     }
570 
571     auto rc = decode_write_file_req(request, payloadLength, &fileHandle,
572                                     &offset, &length, &fileDataOffset);
573 
574     if (rc)
575     {
576         encode_write_file_resp(request->hdr.instance_id, rc, 0, responsePtr);
577         return response;
578     }
579 
580     using namespace pldm::filetable;
581     auto& table = buildFileTable(FILE_TABLE_JSON);
582     FileEntry value{};
583 
584     try
585     {
586         value = table.at(fileHandle);
587     }
588     catch (const std::exception& e)
589     {
590         error(
591             "File handle does not exist in the file table, HANDLE={FILE_HANDLE}",
592             "FILE_HANDLE", fileHandle);
593         encode_write_file_resp(request->hdr.instance_id,
594                                PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
595         return response;
596     }
597 
598     if (!fs::exists(value.fsPath))
599     {
600         error("File does not exist, HANDLE={FILE_HANDLE}", "FILE_HANDLE",
601               fileHandle);
602         encode_write_file_resp(request->hdr.instance_id,
603                                PLDM_INVALID_FILE_HANDLE, 0, responsePtr);
604         return response;
605     }
606 
607     auto fileSize = fs::file_size(value.fsPath);
608     if (offset >= fileSize)
609     {
610         error("Offset exceeds file size, OFFSET={OFFSET} FILE_SIZE={FILE_SIZE}",
611               "OFFSET", offset, "FILE_SIZE", fileSize);
612         encode_write_file_resp(request->hdr.instance_id, PLDM_DATA_OUT_OF_RANGE,
613                                0, responsePtr);
614         return response;
615     }
616 
617     auto fileDataPos = reinterpret_cast<const char*>(request->payload) +
618                        fileDataOffset;
619 
620     std::ofstream stream(value.fsPath,
621                          std::ios::in | std::ios::out | std::ios::binary);
622     stream.seekp(offset);
623     stream.write(fileDataPos, length);
624 
625     encode_write_file_resp(request->hdr.instance_id, PLDM_SUCCESS, length,
626                            responsePtr);
627 
628     return response;
629 }
630 
631 Response rwFileByTypeIntoMemory(uint8_t cmd, const pldm_msg* request,
632                                 size_t payloadLength,
633                                 oem_platform::Handler* oemPlatformHandler)
634 {
635     Response response(
636         sizeof(pldm_msg_hdr) + PLDM_RW_FILE_BY_TYPE_MEM_RESP_BYTES, 0);
637     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
638 
639     if (payloadLength != PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES)
640     {
641         encode_rw_file_by_type_memory_resp(request->hdr.instance_id, cmd,
642                                            PLDM_ERROR_INVALID_LENGTH, 0,
643                                            responsePtr);
644         return response;
645     }
646 
647     uint16_t fileType{};
648     uint32_t fileHandle{};
649     uint32_t offset{};
650     uint32_t length{};
651     uint64_t address{};
652     auto rc = decode_rw_file_by_type_memory_req(request, payloadLength,
653                                                 &fileType, &fileHandle, &offset,
654                                                 &length, &address);
655     if (rc != PLDM_SUCCESS)
656     {
657         encode_rw_file_by_type_memory_resp(request->hdr.instance_id, cmd, rc, 0,
658                                            responsePtr);
659         return response;
660     }
661     if (length % dma::minSize)
662     {
663         error("Length is not a multiple of DMA minSize, LENGTH={LEN}", "LEN",
664               length);
665         encode_rw_file_by_type_memory_resp(request->hdr.instance_id, cmd,
666                                            PLDM_ERROR_INVALID_LENGTH, 0,
667                                            responsePtr);
668         return response;
669     }
670 
671     std::unique_ptr<FileHandler> handler{};
672     try
673     {
674         handler = getHandlerByType(fileType, fileHandle);
675     }
676     catch (const InternalFailure& e)
677     {
678         error("unknown file type, TYPE={FILE_TYPE}", "FILE_TYPE", fileType);
679         encode_rw_file_by_type_memory_resp(request->hdr.instance_id, cmd,
680                                            PLDM_INVALID_FILE_TYPE, 0,
681                                            responsePtr);
682         return response;
683     }
684 
685     rc = cmd == PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY
686              ? handler->writeFromMemory(offset, length, address,
687                                         oemPlatformHandler)
688              : handler->readIntoMemory(offset, length, address,
689                                        oemPlatformHandler);
690     encode_rw_file_by_type_memory_resp(request->hdr.instance_id, cmd, rc,
691                                        length, responsePtr);
692     return response;
693 }
694 
695 Response Handler::writeFileByTypeFromMemory(const pldm_msg* request,
696                                             size_t payloadLength)
697 {
698     return rwFileByTypeIntoMemory(PLDM_WRITE_FILE_BY_TYPE_FROM_MEMORY, request,
699                                   payloadLength, oemPlatformHandler);
700 }
701 
702 Response Handler::readFileByTypeIntoMemory(const pldm_msg* request,
703                                            size_t payloadLength)
704 {
705     return rwFileByTypeIntoMemory(PLDM_READ_FILE_BY_TYPE_INTO_MEMORY, request,
706                                   payloadLength, oemPlatformHandler);
707 }
708 
709 Response Handler::writeFileByType(const pldm_msg* request, size_t payloadLength)
710 {
711     Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_BY_TYPE_RESP_BYTES);
712     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
713 
714     if (payloadLength < PLDM_RW_FILE_BY_TYPE_REQ_BYTES)
715     {
716         encode_rw_file_by_type_resp(request->hdr.instance_id,
717                                     PLDM_WRITE_FILE_BY_TYPE,
718                                     PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
719         return response;
720     }
721     uint16_t fileType{};
722     uint32_t fileHandle{};
723     uint32_t offset{};
724     uint32_t length{};
725 
726     auto rc = decode_rw_file_by_type_req(request, payloadLength, &fileType,
727                                          &fileHandle, &offset, &length);
728     if (rc != PLDM_SUCCESS)
729     {
730         encode_rw_file_by_type_resp(request->hdr.instance_id,
731                                     PLDM_WRITE_FILE_BY_TYPE, rc, 0,
732                                     responsePtr);
733         return response;
734     }
735 
736     std::unique_ptr<FileHandler> handler{};
737     try
738     {
739         handler = getHandlerByType(fileType, fileHandle);
740     }
741     catch (const InternalFailure& e)
742     {
743         error("unknown file type, TYPE={FILE_TYPE}", "FILE_TYPE", fileType);
744         encode_rw_file_by_type_resp(request->hdr.instance_id,
745                                     PLDM_WRITE_FILE_BY_TYPE,
746                                     PLDM_INVALID_FILE_TYPE, 0, responsePtr);
747         return response;
748     }
749 
750     rc = handler->write(reinterpret_cast<const char*>(
751                             request->payload + PLDM_RW_FILE_BY_TYPE_REQ_BYTES),
752                         offset, length, oemPlatformHandler);
753     encode_rw_file_by_type_resp(request->hdr.instance_id,
754                                 PLDM_WRITE_FILE_BY_TYPE, rc, length,
755                                 responsePtr);
756     return response;
757 }
758 
759 Response Handler::readFileByType(const pldm_msg* request, size_t payloadLength)
760 {
761     Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_BY_TYPE_RESP_BYTES);
762     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
763 
764     if (payloadLength != PLDM_RW_FILE_BY_TYPE_REQ_BYTES)
765     {
766         encode_rw_file_by_type_resp(request->hdr.instance_id,
767                                     PLDM_READ_FILE_BY_TYPE,
768                                     PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
769         return response;
770     }
771     uint16_t fileType{};
772     uint32_t fileHandle{};
773     uint32_t offset{};
774     uint32_t length{};
775 
776     auto rc = decode_rw_file_by_type_req(request, payloadLength, &fileType,
777                                          &fileHandle, &offset, &length);
778     if (rc != PLDM_SUCCESS)
779     {
780         encode_rw_file_by_type_resp(request->hdr.instance_id,
781                                     PLDM_READ_FILE_BY_TYPE, rc, 0, responsePtr);
782         return response;
783     }
784 
785     std::unique_ptr<FileHandler> handler{};
786     try
787     {
788         handler = getHandlerByType(fileType, fileHandle);
789     }
790     catch (const InternalFailure& e)
791     {
792         error("unknown file type, TYPE={FILE_TYPE}", "FILE_TYPE", fileType);
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         encode_file_ack_resp(request->hdr.instance_id, PLDM_INVALID_FILE_TYPE,
839                              responsePtr);
840         return response;
841     }
842 
843     rc = handler->fileAck(fileStatus);
844     encode_file_ack_resp(request->hdr.instance_id, rc, responsePtr);
845     return response;
846 }
847 
848 Response Handler::getAlertStatus(const pldm_msg* request, size_t payloadLength)
849 {
850     Response response(sizeof(pldm_msg_hdr) + PLDM_GET_ALERT_STATUS_RESP_BYTES);
851     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
852     if (payloadLength != PLDM_GET_ALERT_STATUS_REQ_BYTES)
853     {
854         return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
855     }
856 
857     uint8_t versionId{};
858 
859     auto rc = decode_get_alert_status_req(request, payloadLength, &versionId);
860     if (rc != PLDM_SUCCESS)
861     {
862         return CmdHandler::ccOnlyResponse(request, rc);
863     }
864 
865     if (versionId != 0)
866     {
867         return CmdHandler::ccOnlyResponse(request,
868                                           PLDM_HOST_UNSUPPORTED_FORMAT_VERSION);
869     }
870 
871     constexpr uint32_t rackEntry = 0xFF000030;
872     constexpr uint32_t priCecNode = 0x00008030;
873     rc = encode_get_alert_status_resp(request->hdr.instance_id, PLDM_SUCCESS,
874                                       rackEntry, priCecNode, responsePtr,
875                                       PLDM_GET_ALERT_STATUS_RESP_BYTES);
876     if (rc != PLDM_SUCCESS)
877     {
878         return CmdHandler::ccOnlyResponse(request, rc);
879     }
880 
881     return response;
882 }
883 
884 Response Handler::newFileAvailable(const pldm_msg* request,
885                                    size_t payloadLength)
886 {
887     Response response(sizeof(pldm_msg_hdr) + PLDM_NEW_FILE_RESP_BYTES);
888 
889     if (payloadLength != PLDM_NEW_FILE_REQ_BYTES)
890     {
891         return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
892     }
893     uint16_t fileType{};
894     uint32_t fileHandle{};
895     uint64_t length{};
896 
897     auto rc = decode_new_file_req(request, payloadLength, &fileType,
898                                   &fileHandle, &length);
899 
900     if (rc != PLDM_SUCCESS)
901     {
902         return CmdHandler::ccOnlyResponse(request, rc);
903     }
904 
905     std::unique_ptr<FileHandler> handler{};
906     try
907     {
908         handler = getHandlerByType(fileType, fileHandle);
909     }
910     catch (const InternalFailure& e)
911     {
912         error("unknown file type, TYPE={FILE_TYPE}", "FILE_TYPE", fileType);
913         return CmdHandler::ccOnlyResponse(request, PLDM_INVALID_FILE_TYPE);
914     }
915 
916     rc = handler->newFileAvailable(length);
917     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
918     encode_new_file_resp(request->hdr.instance_id, rc, responsePtr);
919     return response;
920 }
921 
922 } // namespace oem_ibm
923 } // namespace responder
924 } // namespace pldm
925