requester: Add PollForPlatformEventMessage APIs

Added encode/decode APIs for PollForPlatformEventMessage command(0x0B)
which is defined in DSP0248 Version 1.2.1 sec:16.7.

Signed-off-by: Thu Nguyen <thu@os.amperecomputing.com>
Signed-off-by: Dung Cao <dung@os.amperecomputing.com>
Change-Id: I0a707256d0ff6133d48a384dc252bce736b802f7
diff --git a/include/libpldm/platform.h b/include/libpldm/platform.h
index dd4e9b8..514dbe9 100644
--- a/include/libpldm/platform.h
+++ b/include/libpldm/platform.h
@@ -35,6 +35,9 @@
 #define PLDM_EVENT_MESSAGE_SUPPORTED_REQ_BYTES 1
 #define PLDM_EVENT_MESSAGE_SUPPORTED_MIN_RESP_BYTES 4
 
+#define PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_REQ_BYTES 8
+#define PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_MIN_RESP_BYTES 4
+
 /* Minimum response length */
 #define PLDM_GET_PDR_MIN_RESP_BYTES 12
 #define PLDM_GET_NUMERIC_EFFECTER_VALUE_MIN_RESP_BYTES 5
@@ -139,6 +142,7 @@
 enum pldm_platform_commands {
 	PLDM_SET_EVENT_RECEIVER = 0x04,
 	PLDM_PLATFORM_EVENT_MESSAGE = 0x0A,
+	PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE = 0x0B,
 	PLDM_EVENT_MESSAGE_SUPPORTED = 0x0C,
 	PLDM_EVENT_MESSAGE_BUFFER_SIZE = 0x0D,
 	PLDM_GET_SENSOR_READING = 0x11,
@@ -1005,6 +1009,27 @@
 	uint8_t event_data[1];
 } __attribute__((packed));
 
+/** @struct pldm_poll_for_platform_event_message_req
+ *
+ *  structure representing PollForPlatformEventMessage command request data
+ */
+struct pldm_poll_for_platform_event_message_req {
+	uint8_t format_version;
+	uint8_t transfer_operation_flag;
+	uint32_t data_transfer_handle;
+	uint16_t event_id_to_acknowledge;
+};
+
+/** @struct pldm_poll_for_platform_event_message_min_resp
+ *
+ *  structure representing PollForPlatformEventMessage command response data
+ */
+struct pldm_poll_for_platform_event_message_min_resp {
+	uint8_t completion_code;
+	uint8_t tid;
+	uint16_t event_id;
+};
+
 /** @struct pldm_platform_event_message_response
  *
  *  structure representing PlatformEventMessage command response data
@@ -1027,7 +1052,7 @@
 /** @struct pldm_pdr_repository_chg_event_change_record_data
  *
  *  structure representing pldmPDRRepositoryChgEvent class eventData's change
- * record data
+ *  record data
  */
 struct pldm_pdr_repository_change_record_data {
 	uint8_t event_data_operation;
@@ -1608,6 +1633,49 @@
     uint8_t event_class, const uint8_t *event_data, size_t event_data_length,
     struct pldm_msg *msg, size_t payload_length);
 
+/** @brief Encode PollForPlatformEventMessage request data
+ *  @param[in] instance_id - Message's instance id
+ *  @param[in] format_version - Version of the event format
+ *  @param[in] transfer_operation_flag - Tranfer operation
+ *  @param[in] data_transfer_handle - The data transfer handle
+ *  @param[in] event_id_to_acknowledge - the event data to acknowleadge
+ *  @param[out] msg - Request message
+ *  @return pldm_completion_codes
+ *  @note Caller is responsible for memory alloc and dealloc of param
+ *  'msg.payload'
+ */
+int encode_poll_for_platform_event_message_req(uint8_t instance_id,
+					       uint8_t format_version,
+					       uint8_t transfer_operation_flag,
+					       uint32_t data_transfer_handle,
+					       uint16_t event_id_to_acknowledge,
+					       struct pldm_msg *msg,
+					       size_t payload_length);
+
+/** @brief Decode PollForPlatformEventMessage response data
+ *  @param[in] msg - Request message
+ *  @param[in] payload_length - Length of Response message payload
+ *  @param[out] completion_code - the completion code
+ *  @param[out] tid - the tid
+ *  @param[out] event_id - The event id
+ *  @param[out] next_data_transfer_handle - The next data transfer handle
+ *  @param[out] transfer_flag - The transfer flag
+ *  @param[out] event_class - The event class
+ *  @param[out] event_data_size - The event data size
+ *  @param[out] event_data - The event data. The event_data pointer points into
+ *  msg.payload and therefore has the same lifetime as msg.payload.
+ *  @param[out] event_data_integrity_checksum - The checksum
+ *  command
+ *  @return pldm_completion_codes
+ *  @note Caller is responsible for memory alloc and dealloc of param
+ *  'msg.payload'
+ */
+int decode_poll_for_platform_event_message_resp(
+    const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code,
+    uint8_t *tid, uint16_t *event_id, uint32_t *next_data_transfer_handle,
+    uint8_t *transfer_flag, uint8_t *event_class, uint32_t *event_data_size,
+    void **event_data, uint32_t *event_data_integrity_checksum);
+
 /** @brief Decode PlatformEventMessage response data
  * @param[in] msg - Request message
  * @param[in] payload_length - Length of Response message payload
diff --git a/src/platform.c b/src/platform.c
index 35a5a72..eae38c1 100644
--- a/src/platform.c
+++ b/src/platform.c
@@ -5,6 +5,7 @@
 #include "pldm_types.h"
 #include <endian.h>
 #include <stdint.h>
+#include <stdlib.h>
 #include <string.h>
 
 static int pldm_platform_pdr_hdr_validate(struct pldm_value_pdr_hdr *ctx,
@@ -2062,3 +2063,114 @@
 
 	return PLDM_SUCCESS;
 }
+
+int encode_poll_for_platform_event_message_req(uint8_t instance_id,
+					       uint8_t format_version,
+					       uint8_t transfer_operation_flag,
+					       uint32_t data_transfer_handle,
+					       uint16_t event_id_to_acknowledge,
+					       struct pldm_msg *msg,
+					       size_t payload_length)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = {0};
+	header.msg_type = PLDM_REQUEST;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_PLATFORM;
+	header.command = PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE;
+
+	rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	rc = pldm_msgbuf_init(
+	    buf, PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_MIN_RESP_BYTES,
+	    msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_insert(buf, format_version);
+	pldm_msgbuf_insert(buf, transfer_operation_flag);
+	pldm_msgbuf_insert(buf, data_transfer_handle);
+	pldm_msgbuf_insert(buf, event_id_to_acknowledge);
+
+	return pldm_msgbuf_destroy(buf);
+}
+
+int decode_poll_for_platform_event_message_resp(
+    const struct pldm_msg *msg, size_t payload_length, uint8_t *completion_code,
+    uint8_t *tid, uint16_t *event_id, uint32_t *next_data_transfer_handle,
+    uint8_t *transfer_flag, uint8_t *event_class, uint32_t *event_data_size,
+    void **event_data, uint32_t *event_data_integrity_checksum)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	if (msg == NULL || completion_code == NULL || tid == NULL ||
+	    event_id == NULL || next_data_transfer_handle == NULL ||
+	    transfer_flag == NULL || event_class == NULL ||
+	    event_data_size == NULL || event_data == NULL ||
+	    event_data_integrity_checksum == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_init(
+	    buf, PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_MIN_RESP_BYTES,
+	    msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	rc = pldm_msgbuf_extract(buf, completion_code);
+	if (rc) {
+		return rc;
+	}
+	if (PLDM_SUCCESS != *completion_code) {
+		return *completion_code;
+	}
+
+	pldm_msgbuf_extract(buf, tid);
+	rc = pldm_msgbuf_extract(buf, event_id);
+	if (rc) {
+		return rc;
+	}
+	if ((*event_id == 0) || (*event_id == 0xffff)) {
+		return PLDM_SUCCESS;
+	}
+
+	pldm_msgbuf_extract(buf, next_data_transfer_handle);
+	rc = pldm_msgbuf_extract(buf, transfer_flag);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_extract(buf, event_class);
+	rc = pldm_msgbuf_extract(buf, event_data_size);
+	if (rc) {
+		return rc;
+	}
+	if (*event_data_size > payload_length) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (*event_data_size > 0) {
+		pldm_msgbuf_span_required(buf, *event_data_size, event_data);
+	}
+
+	if (*transfer_flag == PLDM_END ||
+	    *transfer_flag == PLDM_START_AND_END) {
+		pldm_msgbuf_extract(buf, event_data_integrity_checksum);
+	}
+
+	return pldm_msgbuf_destroy_consumed(buf);
+}
diff --git a/tests/libpldm_platform_test.cpp b/tests/libpldm_platform_test.cpp
index e7f4253..7746b59 100644
--- a/tests/libpldm_platform_test.cpp
+++ b/tests/libpldm_platform_test.cpp
@@ -8,6 +8,7 @@
 #include "libpldm/base.h"
 #include "libpldm/entity.h"
 #include "libpldm/platform.h"
+#include "msgbuf.h"
 #include "pldm_types.h"
 
 #include <gtest/gtest.h>
@@ -1181,6 +1182,257 @@
     EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
 }
 
+TEST(PollForPlatformEventMessage, testGoodEncodeRequest)
+{
+    uint8_t formatVersion = 0x01;
+    uint8_t transferOperationFlag = 0x1;
+    uint32_t dataTransferHandle = 0xffffffff;
+    uint16_t eventIdToAcknowledge = 0x0;
+
+    std::array<uint8_t,
+               hdrSize + PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_REQ_BYTES>
+        requestMsg{};
+    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+    auto rc = encode_poll_for_platform_event_message_req(
+        0, formatVersion, transferOperationFlag, dataTransferHandle,
+        eventIdToAcknowledge, request,
+        PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_REQ_BYTES);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+
+    struct pldm_msgbuf _buf;
+    struct pldm_msgbuf* buf = &_buf;
+    rc = pldm_msgbuf_init(buf, PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_REQ_BYTES,
+                          request->payload,
+                          PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_REQ_BYTES);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+
+    uint8_t retFormatVersion;
+    uint8_t retTransferOperationFlag;
+    uint32_t retDataTransferHandle;
+    uint16_t retEventIdToAcknowledge;
+
+    pldm_msgbuf_extract_uint8(buf, &retFormatVersion);
+    pldm_msgbuf_extract_uint8(buf, &retTransferOperationFlag);
+    pldm_msgbuf_extract_uint32(buf, &retDataTransferHandle);
+    pldm_msgbuf_extract_uint16(buf, &retEventIdToAcknowledge);
+
+    EXPECT_EQ(retFormatVersion, formatVersion);
+    EXPECT_EQ(retTransferOperationFlag, transferOperationFlag);
+    EXPECT_EQ(retDataTransferHandle, dataTransferHandle);
+    EXPECT_EQ(retEventIdToAcknowledge, eventIdToAcknowledge);
+    EXPECT_EQ(pldm_msgbuf_destroy(buf), PLDM_SUCCESS);
+}
+
+TEST(PollForPlatformEventMessage, testBadEncodeRequest)
+{
+    uint8_t formatVersion = 0x01;
+    uint8_t transferOperationFlag = 0x1;
+    uint32_t dataTransferHandle = 0xffffffff;
+    uint16_t eventIdToAcknowledge = 0x0;
+
+    std::array<uint8_t,
+               hdrSize + PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_REQ_BYTES>
+        requestMsg{};
+    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+    auto rc = encode_poll_for_platform_event_message_req(
+        0, formatVersion, transferOperationFlag, dataTransferHandle,
+        eventIdToAcknowledge, nullptr,
+        PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_REQ_BYTES);
+
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    encode_poll_for_platform_event_message_req(
+        0, formatVersion, transferOperationFlag, dataTransferHandle,
+        eventIdToAcknowledge, request, hdrSize);
+}
+
+TEST(PollForPlatformEventMessage, testGoodDecodeRespond)
+{
+    uint8_t completionCode = PLDM_SUCCESS;
+    uint8_t tId = 0x9;
+    uint16_t eventId = 159;
+    uint32_t nextDataTransferHandle = 0x11223344;
+    uint8_t transferFlag = PLDM_START_AND_END;
+    uint8_t eventClass = 0x5;
+    uint8_t eventData[5] = {0x55, 0x44, 0x33, 0x22, 0x11};
+    constexpr uint32_t eventDataSize = 0x00000005;
+    uint32_t eventDataIntegrityChecksum = 0x66778899;
+
+    std::vector<uint8_t> responseMsg{
+        0x1,
+        0x0,
+        0x0,
+        PLDM_SUCCESS,
+        0x9, // tid
+        159,
+        0x0, // event id
+        0x44,
+        0x33,
+        0x22,
+        0x11,               // next_data_transfer_handle
+        PLDM_START_AND_END, // transfer_flag
+        0x05,               // event class
+        0x05,
+        0x00,
+        0x00,
+        0x00, // event_data_size
+        0x55,
+        0x44,
+        0x33,
+        0x22,
+        0x11, // event_data[5]
+        0x99,
+        0x88,
+        0x77,
+        0x66 // event_data_integrity_checksum
+    };
+    const uint32_t respMsgLen = 23;
+
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+    uint8_t retCompletionCode;
+    uint8_t retTid = 0;
+    uint16_t retEventId = 0;
+    uint32_t retNextDataTransferHandle = 0;
+    uint8_t retTransferFlag = 0;
+    uint8_t retEventClass = 0;
+    uint32_t retEventDataSize = 0;
+    uint8_t* retEventData = nullptr;
+    uint32_t retEventDataIntegrityChecksum = 0;
+
+    auto rc = decode_poll_for_platform_event_message_resp(
+        response, respMsgLen, &retCompletionCode, &retTid, &retEventId,
+        &retNextDataTransferHandle, &retTransferFlag, &retEventClass,
+        &retEventDataSize, (void**)&retEventData,
+        &retEventDataIntegrityChecksum);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(retCompletionCode, completionCode);
+    EXPECT_EQ(retTid, tId);
+    EXPECT_EQ(retEventId, eventId);
+    EXPECT_EQ(retNextDataTransferHandle, nextDataTransferHandle);
+    EXPECT_EQ(retTransferFlag, transferFlag);
+    EXPECT_EQ(retEventClass, eventClass);
+    EXPECT_EQ(retEventDataSize, eventDataSize);
+    EXPECT_EQ(retEventDataIntegrityChecksum, eventDataIntegrityChecksum);
+    EXPECT_EQ(0, memcmp(eventData, retEventData, eventDataSize));
+}
+
+TEST(PollForPlatformEventMessage, testGoodDecodeAckOnlyRespond)
+{
+    uint8_t completionCode = PLDM_SUCCESS;
+    uint8_t tId = 0x9;
+    uint16_t eventId = 0xffff;
+
+    std::vector<uint8_t> responseMsg{
+        0x1,  0x0, 0x0, PLDM_SUCCESS,
+        0x9, // tid
+        0xff,
+        0xff // event id
+    };
+    const uint32_t respMsgLen = 4;
+
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+    uint8_t retCompletionCode;
+    uint8_t retTid = 0;
+    uint16_t retEventId = 0;
+    uint32_t retNextDataTransferHandle = 0;
+    uint8_t retTransferFlag = 0;
+    uint8_t retEventClass = 0;
+    uint32_t retEventDataSize = 0;
+    uint8_t* retEventData = nullptr;
+    uint32_t retEventDataIntegrityChecksum = 0;
+
+    auto rc = decode_poll_for_platform_event_message_resp(
+        response, respMsgLen, &retCompletionCode, &retTid, &retEventId,
+        &retNextDataTransferHandle, &retTransferFlag, &retEventClass,
+        &retEventDataSize, (void**)&retEventData,
+        &retEventDataIntegrityChecksum);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(retCompletionCode, completionCode);
+    EXPECT_EQ(retTid, tId);
+    EXPECT_EQ(retEventId, eventId);
+
+    eventId = 0x0000;
+    responseMsg[5] = 0x00;
+    responseMsg[6] = 0x00;
+    response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+    rc = decode_poll_for_platform_event_message_resp(
+        response, respMsgLen, &retCompletionCode, &retTid, &retEventId,
+        &retNextDataTransferHandle, &retTransferFlag, &retEventClass,
+        &retEventDataSize, (void**)&retEventData,
+        &retEventDataIntegrityChecksum);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(retCompletionCode, completionCode);
+    EXPECT_EQ(retTid, tId);
+    EXPECT_EQ(retEventId, eventId);
+}
+
+TEST(PollForPlatformEventMessage, testBadDecodeRespond)
+{
+    std::vector<uint8_t> responseMsg{
+        0x1,
+        0x0,
+        0x0,
+        PLDM_SUCCESS,
+        0x9, // tid
+        159,
+        0x0, // event id
+        0x44,
+        0x33,
+        0x22,
+        0x11,               // next_data_transfer_handle
+        PLDM_START_AND_END, // transfer_flag
+        0x05,               // event class
+        0x05,
+        0x00,
+        0x00,
+        0x00, // event_data_size
+        0x55,
+        0x44,
+        0x33,
+        0x22,
+        0x11, // event_data[5]
+        0x99,
+        0x88,
+        0x77,
+        0x66 // event_data_integrity_checksum
+    };
+    // const uint32_t respMsgLen = 23;
+
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+    auto rc = decode_poll_for_platform_event_message_resp(
+        nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+        nullptr, nullptr, nullptr);
+
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    uint8_t retCompletionCode;
+    uint8_t retTid = 0;
+    uint16_t retEventId = 0;
+    uint32_t retNextDataTransferHandle = 0;
+    uint8_t retTransferFlag = 0;
+    uint8_t retEventClass = 0;
+    uint32_t retEventDataSize = 0;
+    uint8_t* retEventData = nullptr;
+    uint32_t retEventDataIntegrityChecksum = 0;
+
+    rc = decode_poll_for_platform_event_message_resp(
+        response, PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_MIN_RESP_BYTES - 1,
+        &retCompletionCode, &retTid, &retEventId, &retNextDataTransferHandle,
+        &retTransferFlag, &retEventClass, &retEventDataSize,
+        (void**)&retEventData, &retEventDataIntegrityChecksum);
+
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
+
 TEST(PlatformEventMessage, testGoodStateSensorDecodeRequest)
 {
     std::array<uint8_t,