1 #include "event_manager.hpp"
2 
3 #include "libpldm/platform.h"
4 #include "libpldm/utils.h"
5 
6 #include "terminus_manager.hpp"
7 
8 #include <phosphor-logging/lg2.hpp>
9 #include <xyz/openbmc_project/Logging/Entry/server.hpp>
10 
11 #include <cerrno>
12 #include <memory>
13 
14 PHOSPHOR_LOG2_USING;
15 
16 namespace pldm
17 {
18 namespace platform_mc
19 {
20 namespace fs = std::filesystem;
21 
handlePlatformEvent(pldm_tid_t tid,uint16_t eventId,uint8_t eventClass,const uint8_t * eventData,size_t eventDataSize)22 int EventManager::handlePlatformEvent(
23     pldm_tid_t tid, uint16_t eventId, uint8_t eventClass,
24     const uint8_t* eventData, size_t eventDataSize)
25 {
26     /* Only handle the event of the discovered termini*/
27     if (!termini.contains(tid))
28     {
29         lg2::error("Terminus ID {TID} is not in the managing list.", "TID",
30                    tid);
31         return PLDM_ERROR;
32     }
33 
34     /* EventClass sensorEvent `Table 11 - PLDM Event Types` DSP0248 */
35     if (eventClass == PLDM_SENSOR_EVENT)
36     {
37         uint16_t sensorId = 0;
38         uint8_t sensorEventClassType = 0;
39         size_t eventClassDataOffset = 0;
40         auto rc = decode_sensor_event_data(eventData, eventDataSize, &sensorId,
41                                            &sensorEventClassType,
42                                            &eventClassDataOffset);
43         if (rc)
44         {
45             lg2::error(
46                 "Failed to decode sensor event data from terminus ID {TID}, event class {CLASS}, event ID {EVENTID} with return code {RC}.",
47                 "TID", tid, "CLASS", eventClass, "EVENTID", eventId, "RC", rc);
48             return rc;
49         }
50         switch (sensorEventClassType)
51         {
52             case PLDM_NUMERIC_SENSOR_STATE:
53             {
54                 const uint8_t* sensorData = eventData + eventClassDataOffset;
55                 size_t sensorDataLength = eventDataSize - eventClassDataOffset;
56                 return processNumericSensorEvent(tid, sensorId, sensorData,
57                                                  sensorDataLength);
58             }
59             case PLDM_STATE_SENSOR_STATE:
60             case PLDM_SENSOR_OP_STATE:
61             default:
62                 lg2::info(
63                     "Unsupported class type {CLASSTYPE} for the sensor event from terminus ID {TID} sensorId {SID}",
64                     "CLASSTYPE", sensorEventClassType, "TID", tid, "SID",
65                     sensorId);
66                 return PLDM_ERROR;
67         }
68     }
69 
70     /* EventClass CPEREvent as `Table 11 - PLDM Event Types` DSP0248 V1.3.0 */
71     if (eventClass == PLDM_CPER_EVENT)
72     {
73         return processCperEvent(tid, eventId, eventData, eventDataSize);
74     }
75 
76     /* EventClass pldmMessagePollEvent `Table 11 - PLDM Event Types` DSP0248 */
77     if (eventClass == PLDM_MESSAGE_POLL_EVENT)
78     {
79         lg2::info("Received pldmMessagePollEvent for terminus {TID}", "TID",
80                   tid);
81         pldm_message_poll_event poll_event{};
82         auto rc = decode_pldm_message_poll_event_data(eventData, eventDataSize,
83                                                       &poll_event);
84         if (rc)
85         {
86             lg2::error(
87                 "Failed to decode PldmMessagePollEvent event, error {RC} ",
88                 "RC", rc);
89             return rc;
90         }
91 
92         auto it = termini.find(tid);
93         if (it != termini.end())
94         {
95             auto& terminus = it->second; // Reference for clarity
96             terminus->pollEvent = true;
97             terminus->pollEventId = poll_event.event_id;
98             terminus->pollDataTransferHandle = poll_event.data_transfer_handle;
99         }
100 
101         return PLDM_SUCCESS;
102     }
103 
104     lg2::info("Unsupported class type {CLASSTYPE}", "CLASSTYPE", eventClass);
105 
106     return PLDM_ERROR;
107 }
108 
processNumericSensorEvent(pldm_tid_t tid,uint16_t sensorId,const uint8_t * sensorData,size_t sensorDataLength)109 int EventManager::processNumericSensorEvent(pldm_tid_t tid, uint16_t sensorId,
110                                             const uint8_t* sensorData,
111                                             size_t sensorDataLength)
112 {
113     uint8_t eventState = 0;
114     uint8_t previousEventState = 0;
115     uint8_t sensorDataSize = 0;
116     uint32_t presentReading;
117     auto rc = decode_numeric_sensor_data(
118         sensorData, sensorDataLength, &eventState, &previousEventState,
119         &sensorDataSize, &presentReading);
120     if (rc)
121     {
122         lg2::error(
123             "Failed to decode numericSensorState event for terminus ID {TID}, error {RC} ",
124             "TID", tid, "RC", rc);
125         return rc;
126     }
127 
128     double value = static_cast<double>(presentReading);
129     lg2::error(
130         "processNumericSensorEvent tid {TID}, sensorID {SID} value {VAL} previousState {PSTATE} eventState {ESTATE}",
131         "TID", tid, "SID", sensorId, "VAL", value, "PSTATE", previousEventState,
132         "ESTATE", eventState);
133 
134     if (!termini.contains(tid) || !termini[tid])
135     {
136         lg2::error("Terminus ID {TID} is not in the managing list.", "TID",
137                    tid);
138         return PLDM_ERROR;
139     }
140 
141     auto& terminus = termini[tid];
142 
143     auto sensor = terminus->getSensorObject(sensorId);
144     if (!sensor)
145     {
146         lg2::error(
147             "Terminus ID {TID} has no sensor object with sensor ID {SID}.",
148             "TID", tid, "SID", sensorId);
149         return PLDM_ERROR;
150     }
151 
152     switch (previousEventState)
153     {
154         case PLDM_SENSOR_UNKNOWN:
155         case PLDM_SENSOR_NORMAL:
156         {
157             switch (eventState)
158             {
159                 case PLDM_SENSOR_UPPERFATAL:
160                 case PLDM_SENSOR_UPPERCRITICAL:
161                 {
162                     sensor->triggerThresholdEvent(pldm::utils::Level::WARNING,
163                                                   pldm::utils::Direction::HIGH,
164                                                   value, true, true);
165                     return sensor->triggerThresholdEvent(
166                         pldm::utils::Level::CRITICAL,
167                         pldm::utils::Direction::HIGH, value, true, true);
168                 }
169                 case PLDM_SENSOR_UPPERWARNING:
170                 {
171                     return sensor->triggerThresholdEvent(
172                         pldm::utils::Level::WARNING,
173                         pldm::utils::Direction::HIGH, value, true, true);
174                 }
175                 case PLDM_SENSOR_NORMAL:
176                     break;
177                 case PLDM_SENSOR_LOWERWARNING:
178                 {
179                     return sensor->triggerThresholdEvent(
180                         pldm::utils::Level::WARNING,
181                         pldm::utils::Direction::LOW, value, true, true);
182                 }
183                 case PLDM_SENSOR_LOWERCRITICAL:
184                 case PLDM_SENSOR_LOWERFATAL:
185                 {
186                     sensor->triggerThresholdEvent(pldm::utils::Level::WARNING,
187                                                   pldm::utils::Direction::LOW,
188                                                   value, true, true);
189                     return sensor->triggerThresholdEvent(
190                         pldm::utils::Level::CRITICAL,
191                         pldm::utils::Direction::LOW, value, true, true);
192                 }
193                 default:
194                     break;
195             }
196             break;
197         }
198         case PLDM_SENSOR_LOWERWARNING:
199         {
200             switch (eventState)
201             {
202                 case PLDM_SENSOR_UPPERFATAL:
203                 case PLDM_SENSOR_UPPERCRITICAL:
204                     break;
205                 case PLDM_SENSOR_UPPERWARNING:
206                 {
207                     sensor->triggerThresholdEvent(pldm::utils::Level::WARNING,
208                                                   pldm::utils::Direction::LOW,
209                                                   value, false, false);
210                     return sensor->triggerThresholdEvent(
211                         pldm::utils::Level::WARNING,
212                         pldm::utils::Direction::HIGH, value, true, true);
213                 }
214                 case PLDM_SENSOR_NORMAL:
215                 {
216                     return sensor->triggerThresholdEvent(
217                         pldm::utils::Level::WARNING,
218                         pldm::utils::Direction::LOW, value, false, false);
219                 }
220                 case PLDM_SENSOR_LOWERWARNING:
221                     break;
222                 case PLDM_SENSOR_LOWERCRITICAL:
223                 case PLDM_SENSOR_LOWERFATAL:
224                 {
225                     return sensor->triggerThresholdEvent(
226                         pldm::utils::Level::CRITICAL,
227                         pldm::utils::Direction::LOW, value, true, true);
228                 }
229                 default:
230                     break;
231             }
232             break;
233         }
234         case PLDM_SENSOR_LOWERCRITICAL:
235         case PLDM_SENSOR_LOWERFATAL:
236         {
237             switch (eventState)
238             {
239                 case PLDM_SENSOR_UPPERFATAL:
240                 case PLDM_SENSOR_UPPERCRITICAL:
241                 case PLDM_SENSOR_UPPERWARNING:
242                     break;
243                 case PLDM_SENSOR_NORMAL:
244                 {
245                     sensor->triggerThresholdEvent(pldm::utils::Level::CRITICAL,
246                                                   pldm::utils::Direction::LOW,
247                                                   value, false, false);
248                     sensor->triggerThresholdEvent(pldm::utils::Level::WARNING,
249                                                   pldm::utils::Direction::LOW,
250                                                   value, true, true);
251                     return sensor->triggerThresholdEvent(
252                         pldm::utils::Level::WARNING,
253                         pldm::utils::Direction::LOW, value, false, false);
254                 }
255                 case PLDM_SENSOR_LOWERWARNING:
256                 {
257                     sensor->triggerThresholdEvent(pldm::utils::Level::CRITICAL,
258                                                   pldm::utils::Direction::LOW,
259                                                   value, false, false);
260                     return sensor->triggerThresholdEvent(
261                         pldm::utils::Level::WARNING,
262                         pldm::utils::Direction::LOW, value, true, true);
263                 }
264                 case PLDM_SENSOR_LOWERCRITICAL:
265                 case PLDM_SENSOR_LOWERFATAL:
266                 default:
267                     break;
268             }
269             break;
270         }
271         case PLDM_SENSOR_UPPERFATAL:
272         case PLDM_SENSOR_UPPERCRITICAL:
273         {
274             switch (eventState)
275             {
276                 case PLDM_SENSOR_UPPERFATAL:
277                 case PLDM_SENSOR_UPPERCRITICAL:
278                     break;
279                 case PLDM_SENSOR_UPPERWARNING:
280                 {
281                     sensor->triggerThresholdEvent(pldm::utils::Level::CRITICAL,
282                                                   pldm::utils::Direction::HIGH,
283                                                   value, false, false);
284                     return sensor->triggerThresholdEvent(
285                         pldm::utils::Level::WARNING,
286                         pldm::utils::Direction::HIGH, value, true, true);
287                 }
288                 case PLDM_SENSOR_NORMAL:
289                 {
290                     sensor->triggerThresholdEvent(pldm::utils::Level::CRITICAL,
291                                                   pldm::utils::Direction::HIGH,
292                                                   value, false, false);
293                     sensor->triggerThresholdEvent(pldm::utils::Level::WARNING,
294                                                   pldm::utils::Direction::HIGH,
295                                                   value, true, true);
296                     return sensor->triggerThresholdEvent(
297                         pldm::utils::Level::WARNING,
298                         pldm::utils::Direction::HIGH, value, false, false);
299                 }
300                 case PLDM_SENSOR_LOWERWARNING:
301                 case PLDM_SENSOR_LOWERCRITICAL:
302                 case PLDM_SENSOR_LOWERFATAL:
303                 default:
304                     break;
305             }
306             break;
307         }
308         case PLDM_SENSOR_UPPERWARNING:
309         {
310             switch (eventState)
311             {
312                 case PLDM_SENSOR_UPPERFATAL:
313                 case PLDM_SENSOR_UPPERCRITICAL:
314                 {
315                     return sensor->triggerThresholdEvent(
316                         pldm::utils::Level::CRITICAL,
317                         pldm::utils::Direction::HIGH, value, true, true);
318                 }
319                 case PLDM_SENSOR_UPPERWARNING:
320                     break;
321                 case PLDM_SENSOR_NORMAL:
322                 {
323                     return sensor->triggerThresholdEvent(
324                         pldm::utils::Level::WARNING,
325                         pldm::utils::Direction::HIGH, value, false, false);
326                 }
327                 case PLDM_SENSOR_LOWERWARNING:
328                 {
329                     sensor->triggerThresholdEvent(pldm::utils::Level::WARNING,
330                                                   pldm::utils::Direction::HIGH,
331                                                   value, false, false);
332                     return sensor->triggerThresholdEvent(
333                         pldm::utils::Level::WARNING,
334                         pldm::utils::Direction::LOW, value, true, true);
335                 }
336                 case PLDM_SENSOR_LOWERCRITICAL:
337                 case PLDM_SENSOR_LOWERFATAL:
338                 default:
339                     break;
340             }
341             break;
342         }
343         default:
344             break;
345     }
346 
347     return PLDM_SUCCESS;
348 }
349 
processCperEvent(pldm_tid_t tid,uint16_t eventId,const uint8_t * eventData,const size_t eventDataSize)350 int EventManager::processCperEvent(pldm_tid_t tid, uint16_t eventId,
351                                    const uint8_t* eventData,
352                                    const size_t eventDataSize)
353 {
354     if (eventDataSize < PLDM_PLATFORM_CPER_EVENT_MIN_LENGTH)
355     {
356         lg2::error(
357             "Error : Invalid CPER Event data length for eventId {EVENTID}.",
358             "EVENTID", eventId);
359         return PLDM_ERROR;
360     }
361     const size_t cperEventDataSize =
362         eventDataSize - PLDM_PLATFORM_CPER_EVENT_MIN_LENGTH;
363     const size_t msgDataLen =
364         sizeof(pldm_platform_cper_event) + cperEventDataSize;
365     std::string terminusName = "";
366     auto msgData = std::make_unique<unsigned char[]>(msgDataLen);
367     auto cperEvent = new (msgData.get()) pldm_platform_cper_event;
368 
369     auto rc = decode_pldm_platform_cper_event(eventData, eventDataSize,
370                                               cperEvent, msgDataLen);
371 
372     if (rc)
373     {
374         lg2::error(
375             "Failed to decode CPER event for eventId {EVENTID} of terminus ID {TID} error {RC}.",
376             "EVENTID", eventId, "TID", tid, "RC", rc);
377         return rc;
378     }
379 
380     if (termini.contains(tid) && termini[tid])
381     {
382         auto tmp = termini[tid]->getTerminusName();
383         if (tmp && !tmp.value().empty())
384         {
385             terminusName = static_cast<std::string>(tmp.value());
386         }
387     }
388     else
389     {
390         lg2::error("Terminus ID {TID} is not in the managing list.", "TID",
391                    tid);
392         return PLDM_ERROR;
393     }
394 
395     // Save event data to file
396     std::filesystem::path dirName{"/var/cper"};
397     if (!std::filesystem::exists(dirName))
398     {
399         try
400         {
401             std::filesystem::create_directory(dirName);
402         }
403         catch (const std::filesystem::filesystem_error& e)
404         {
405             lg2::error("Failed to create /var/cper directory: {ERROR}", "ERROR",
406                        e);
407             return PLDM_ERROR;
408         }
409     }
410 
411     std::string fileName{dirName.string() + "/cper-XXXXXX"};
412     auto fd = mkstemp(fileName.data());
413     if (fd < 0)
414     {
415         lg2::error("Failed to generate temp file, error {ERRORNO}", "ERRORNO",
416                    std::strerror(errno));
417         return PLDM_ERROR;
418     }
419     close(fd);
420 
421     std::ofstream ofs;
422     ofs.exceptions(std::ofstream::failbit | std::ofstream::badbit |
423                    std::ofstream::eofbit);
424 
425     try
426     {
427         ofs.open(fileName);
428         ofs.write(reinterpret_cast<const char*>(
429                       pldm_platform_cper_event_event_data(cperEvent)),
430                   cperEvent->event_data_length);
431         if (cperEvent->format_type == PLDM_PLATFORM_CPER_EVENT_WITH_HEADER)
432         {
433             rc = createCperDumpEntry("CPER", fileName, terminusName);
434         }
435         else
436         {
437             rc = createCperDumpEntry("CPERSection", fileName, terminusName);
438         }
439         ofs.close();
440     }
441     catch (const std::ofstream::failure& e)
442     {
443         lg2::error("Failed to save CPER to '{FILENAME}', error - {ERROR}.",
444                    "FILENAME", fileName, "ERROR", e);
445         return PLDM_ERROR;
446     }
447     return rc;
448 }
449 
createCperDumpEntry(const std::string & dataType,const std::string & dataPath,const std::string & typeName)450 int EventManager::createCperDumpEntry(const std::string& dataType,
451                                       const std::string& dataPath,
452                                       const std::string& typeName)
453 {
454     auto createDump =
455         [](std::map<std::string, std::variant<std::string, uint64_t>>&
456                addData) {
457             static constexpr auto dumpObjPath =
458                 "/xyz/openbmc_project/dump/faultlog";
459             static constexpr auto dumpInterface =
460                 "xyz.openbmc_project.Dump.Create";
461             auto& bus = pldm::utils::DBusHandler::getBus();
462 
463             try
464             {
465                 auto service = pldm::utils::DBusHandler().getService(
466                     dumpObjPath, dumpInterface);
467                 auto method = bus.new_method_call(service.c_str(), dumpObjPath,
468                                                   dumpInterface, "CreateDump");
469                 method.append(addData);
470                 bus.call_noreply(method);
471             }
472             catch (const std::exception& e)
473             {
474                 lg2::error(
475                     "Failed to create D-Bus Dump entry, error - {ERROR}.",
476                     "ERROR", e);
477             }
478         };
479 
480     std::map<std::string, std::variant<std::string, uint64_t>> addData;
481     addData["Type"] = dataType;
482     addData["PrimaryLogId"] = dataPath;
483     addData["AdditionalTypeName"] = typeName;
484     createDump(addData);
485     return PLDM_SUCCESS;
486 }
487 
getNextPartParameters(uint16_t eventId,std::vector<uint8_t> eventMessage,uint8_t transferFlag,uint32_t eventDataIntegrityChecksum,uint32_t nextDataTransferHandle,uint8_t * transferOperationFlag,uint32_t * dataTransferHandle,uint32_t * eventIdToAcknowledge)488 int EventManager::getNextPartParameters(
489     uint16_t eventId, std::vector<uint8_t> eventMessage, uint8_t transferFlag,
490     uint32_t eventDataIntegrityChecksum, uint32_t nextDataTransferHandle,
491     uint8_t* transferOperationFlag, uint32_t* dataTransferHandle,
492     uint32_t* eventIdToAcknowledge)
493 {
494     if (transferFlag != PLDM_PLATFORM_TRANSFER_START_AND_END &&
495         transferFlag != PLDM_PLATFORM_TRANSFER_END)
496     {
497         *transferOperationFlag = PLDM_GET_NEXTPART;
498         *dataTransferHandle = nextDataTransferHandle;
499         *eventIdToAcknowledge = PLDM_PLATFORM_EVENT_ID_FRAGMENT;
500         return PLDM_SUCCESS;
501     }
502 
503     if (transferFlag == PLDM_PLATFORM_TRANSFER_END)
504     {
505         if (eventDataIntegrityChecksum !=
506             crc32(eventMessage.data(), eventMessage.size()))
507         {
508             lg2::error("pollForPlatformEventMessage invalid checksum.");
509             return PLDM_ERROR_INVALID_DATA;
510         }
511     }
512 
513     /* End of one event. Set request transfer flag to ACK */
514     *transferOperationFlag = PLDM_ACKNOWLEDGEMENT_ONLY;
515     *dataTransferHandle = 0;
516     *eventIdToAcknowledge = eventId;
517 
518     return PLDM_SUCCESS;
519 }
520 
callPolledEventHandlers(pldm_tid_t tid,uint8_t eventClass,uint16_t eventId,std::vector<uint8_t> & eventMessage)521 void EventManager::callPolledEventHandlers(pldm_tid_t tid, uint8_t eventClass,
522                                            uint16_t eventId,
523                                            std::vector<uint8_t>& eventMessage)
524 {
525     try
526     {
527         const auto& handlers = eventHandlers.at(eventClass);
528         for (const auto& handler : handlers)
529         {
530             auto rc =
531                 handler(tid, eventId, eventMessage.data(), eventMessage.size());
532             if (rc != PLDM_SUCCESS)
533             {
534                 lg2::error(
535                     "Failed to handle platform event msg for terminus {TID}, event {EVENTID} return {RET}",
536                     "TID", tid, "EVENTID", eventId, "RET", rc);
537             }
538         }
539     }
540     catch (const std::out_of_range& e)
541     {
542         lg2::error(
543             "Failed to handle platform event msg for terminus {TID}, event {EVENTID} error - {ERROR}",
544             "TID", tid, "EVENTID", eventId, "ERROR", e);
545     }
546 }
547 
pollForPlatformEventTask(pldm_tid_t tid,uint32_t pollDataTransferHandle)548 exec::task<int> EventManager::pollForPlatformEventTask(
549     pldm_tid_t tid, uint32_t pollDataTransferHandle)
550 {
551     uint8_t rc = 0;
552     // Set once, doesn't need resetting
553     uint8_t transferOperationFlag = PLDM_GET_FIRSTPART;
554     uint32_t dataTransferHandle = pollDataTransferHandle;
555     uint32_t eventIdToAcknowledge = PLDM_PLATFORM_EVENT_ID_NULL;
556     uint8_t formatVersion = 0x1; // Constant, no need to reset
557     uint16_t eventId = PLDM_PLATFORM_EVENT_ID_ACK;
558     uint16_t polledEventId = PLDM_PLATFORM_EVENT_ID_NONE;
559     pldm_tid_t polledEventTid = 0;
560     uint8_t polledEventClass = 0;
561 
562     std::vector<uint8_t> eventMessage{};
563 
564     // Reset and mark terminus as available
565     updateAvailableState(tid, true);
566 
567     while (eventId != PLDM_PLATFORM_EVENT_ID_NONE)
568     {
569         uint8_t completionCode = 0;
570         pldm_tid_t eventTid = PLDM_PLATFORM_EVENT_ID_NONE;
571         eventId = PLDM_PLATFORM_EVENT_ID_NONE;
572         uint32_t nextDataTransferHandle = 0;
573         uint8_t transferFlag = 0;
574         uint8_t eventClass = 0;
575         uint32_t eventDataSize = 0;
576         uint8_t* eventData = nullptr;
577         uint32_t eventDataIntegrityChecksum = 0;
578 
579         /* Stop event polling */
580         if (!getAvailableState(tid))
581         {
582             lg2::info(
583                 "Terminus ID {TID} is not available for PLDM request from {NOW}.",
584                 "TID", tid, "NOW", pldm::utils::getCurrentSystemTime());
585             co_await stdexec::just_stopped();
586         }
587 
588         rc = co_await pollForPlatformEventMessage(
589             tid, formatVersion, transferOperationFlag, dataTransferHandle,
590             eventIdToAcknowledge, completionCode, eventTid, eventId,
591             nextDataTransferHandle, transferFlag, eventClass, eventDataSize,
592             eventData, eventDataIntegrityChecksum);
593         if (rc || completionCode != PLDM_SUCCESS)
594         {
595             lg2::error(
596                 "Failed to pollForPlatformEventMessage for terminus {TID}, event {EVENTID}, error {RC}, complete code {CC}",
597                 "TID", tid, "EVENTID", eventId, "RC", rc, "CC", completionCode);
598             co_return rc;
599         }
600 
601         if (eventDataSize > 0)
602         {
603             eventMessage.insert(eventMessage.end(), eventData,
604                                 eventData + eventDataSize);
605         }
606 
607         if (transferOperationFlag == PLDM_ACKNOWLEDGEMENT_ONLY)
608         {
609             /* Handle the polled event after finish ACK it */
610             if (eventHandlers.contains(polledEventClass))
611             {
612                 callPolledEventHandlers(polledEventTid, polledEventClass,
613                                         polledEventId, eventMessage);
614             }
615             eventMessage.clear();
616 
617             if (eventId == PLDM_PLATFORM_EVENT_ID_ACK)
618             {
619                 transferOperationFlag = PLDM_GET_FIRSTPART;
620                 dataTransferHandle = 0;
621                 eventIdToAcknowledge = PLDM_PLATFORM_EVENT_ID_NULL;
622             }
623         }
624         else
625         {
626             auto ret = getNextPartParameters(
627                 eventId, eventMessage, transferFlag, eventDataIntegrityChecksum,
628                 nextDataTransferHandle, &transferOperationFlag,
629                 &dataTransferHandle, &eventIdToAcknowledge);
630             if (ret)
631             {
632                 lg2::error(
633                     "Failed to process data of pollForPlatformEventMessage for terminus {TID}, event {EVENTID} return {RET}",
634                     "TID", tid, "EVENTID", eventId, "RET", ret);
635                 co_return PLDM_ERROR_INVALID_DATA;
636             }
637 
638             /* Store the polled event INFO to handle after ACK */
639             if ((transferFlag == PLDM_PLATFORM_TRANSFER_START_AND_END) ||
640                 (transferFlag == PLDM_PLATFORM_TRANSFER_END))
641             {
642                 polledEventTid = eventTid;
643                 polledEventId = eventId;
644                 polledEventClass = eventClass;
645             }
646         }
647     }
648 
649     co_return PLDM_SUCCESS;
650 }
651 
pollForPlatformEventMessage(pldm_tid_t tid,uint8_t formatVersion,uint8_t transferOperationFlag,uint32_t dataTransferHandle,uint16_t eventIdToAcknowledge,uint8_t & completionCode,uint8_t & eventTid,uint16_t & eventId,uint32_t & nextDataTransferHandle,uint8_t & transferFlag,uint8_t & eventClass,uint32_t & eventDataSize,uint8_t * & eventData,uint32_t & eventDataIntegrityChecksum)652 exec::task<int> EventManager::pollForPlatformEventMessage(
653     pldm_tid_t tid, uint8_t formatVersion, uint8_t transferOperationFlag,
654     uint32_t dataTransferHandle, uint16_t eventIdToAcknowledge,
655     uint8_t& completionCode, uint8_t& eventTid, uint16_t& eventId,
656     uint32_t& nextDataTransferHandle, uint8_t& transferFlag,
657     uint8_t& eventClass, uint32_t& eventDataSize, uint8_t*& eventData,
658     uint32_t& eventDataIntegrityChecksum)
659 {
660     Request request(
661         sizeof(pldm_msg_hdr) + PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_REQ_BYTES);
662     auto requestMsg = new (request.data()) pldm_msg;
663     auto rc = encode_poll_for_platform_event_message_req(
664         0, formatVersion, transferOperationFlag, dataTransferHandle,
665         eventIdToAcknowledge, requestMsg, request.size());
666     if (rc)
667     {
668         lg2::error(
669             "Failed to encode request PollForPlatformEventMessage for terminus ID {TID}, error {RC} ",
670             "TID", tid, "RC", rc);
671         co_return rc;
672     }
673 
674     /* Stop event polling */
675     if (!getAvailableState(tid))
676     {
677         lg2::info(
678             "Terminus ID {TID} is not available for PLDM request from {NOW}.",
679             "TID", tid, "NOW", pldm::utils::getCurrentSystemTime());
680         co_await stdexec::just_stopped();
681     }
682 
683     const pldm_msg* responseMsg = nullptr;
684     size_t responseLen = 0;
685     rc = co_await terminusManager.sendRecvPldmMsg(tid, request, &responseMsg,
686                                                   &responseLen);
687     if (rc)
688     {
689         lg2::error(
690             "Failed to send PollForPlatformEventMessage message for terminus {TID}, error {RC}",
691             "TID", tid, "RC", rc);
692         co_return rc;
693     }
694 
695     rc = decode_poll_for_platform_event_message_resp(
696         responseMsg, responseLen, &completionCode, &eventTid, &eventId,
697         &nextDataTransferHandle, &transferFlag, &eventClass, &eventDataSize,
698         (void**)&eventData, &eventDataIntegrityChecksum);
699     if (rc)
700     {
701         lg2::error(
702             "Failed to decode response PollForPlatformEventMessage for terminus ID {TID}, error {RC} ",
703             "TID", tid, "RC", rc);
704         co_return rc;
705     }
706     if (completionCode != PLDM_SUCCESS)
707     {
708         lg2::error(
709             "Error : PollForPlatformEventMessage for terminus ID {TID}, complete code {CC}.",
710             "TID", tid, "CC", completionCode);
711         co_return rc;
712     }
713 
714     co_return completionCode;
715 }
716 
717 } // namespace platform_mc
718 } // namespace pldm
719