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