libpldm: Reorganize source and test files

Primarily this is about moving specification-specific files into
'dsp/' (in the "DMTF Standard Publication" sense[1]) subdirectories of
both src/ and tests/.

[1]: https://www.dmtf.org/sites/default/files/standards/documents/DSP4014_2.14.0.pdf

libpldm is a concrete C implementation of the PLDM family of
specifications. This invokes some accidental complexity[2] such as the
msgbuf APIs and other concerns.

[2]: https://en.wikipedia.org/wiki/No_Silver_Bullet

Separate the essential complexity (everything under the dsp/
subdirectories) from the accidental complexity (almost everything else).

While doing so, I took the opportunity to drop the 'libpldm_' prefix
and '_test' suffix from a variety of tests. The 'libpldm_' prefix is a
hangover from the days when libpldm was a subproject of OpenBMC's pldm
repo. The '_test' suffix feels redundant given the parent directory
path.

Note that we maintain separation of the src/ and tests/. The test suite
is implemented in C++ while libpldm's APIs are declared and defined in
C. The ability to chop all the tests and C++ out of the implementation
by ignoring a subtree seems like a desirable property when vendoring the
library into other projects.

Finally, update the x86_64 GCC ABI dump, as rearranging the source
causes a lot of churn in its definitions.

Change-Id: Icffcc6cf48b3101ecd38168827c0a81cffb8f083
Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
diff --git a/src/dsp/base.c b/src/dsp/base.c
new file mode 100644
index 0000000..eec7626
--- /dev/null
+++ b/src/dsp/base.c
@@ -0,0 +1,550 @@
+/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
+#include <libpldm/base.h>
+#include <libpldm/pldm_types.h>
+
+#include <endian.h>
+#include <stdint.h>
+#include <string.h>
+
+LIBPLDM_ABI_STABLE
+uint8_t pack_pldm_header(const struct pldm_header_info *hdr,
+			 struct pldm_msg_hdr *msg)
+{
+	if (msg == NULL || hdr == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (hdr->msg_type != PLDM_RESPONSE && hdr->msg_type != PLDM_REQUEST &&
+	    hdr->msg_type != PLDM_ASYNC_REQUEST_NOTIFY) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (hdr->instance > PLDM_INSTANCE_MAX) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (hdr->pldm_type > (PLDM_MAX_TYPES - 1)) {
+		return PLDM_ERROR_INVALID_PLDM_TYPE;
+	}
+
+	uint8_t datagram = (hdr->msg_type == PLDM_ASYNC_REQUEST_NOTIFY) ? 1 : 0;
+
+	if (hdr->msg_type == PLDM_RESPONSE) {
+		msg->request = PLDM_RESPONSE;
+	} else if (hdr->msg_type == PLDM_REQUEST ||
+		   hdr->msg_type == PLDM_ASYNC_REQUEST_NOTIFY) {
+		msg->request = PLDM_REQUEST;
+	}
+	msg->datagram = datagram;
+	msg->reserved = 0;
+	msg->instance_id = hdr->instance;
+	msg->header_ver = PLDM_CURRENT_VERSION;
+	msg->type = hdr->pldm_type;
+	msg->command = hdr->command;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+uint8_t unpack_pldm_header(const struct pldm_msg_hdr *msg,
+			   struct pldm_header_info *hdr)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (msg->request == PLDM_RESPONSE) {
+		hdr->msg_type = PLDM_RESPONSE;
+	} else {
+		hdr->msg_type = msg->datagram ? PLDM_ASYNC_REQUEST_NOTIFY :
+						PLDM_REQUEST;
+	}
+
+	hdr->instance = msg->instance_id;
+	hdr->pldm_type = msg->type;
+	hdr->command = msg->command;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+bool pldm_msg_hdr_correlate_response(const struct pldm_msg_hdr *req,
+				     const struct pldm_msg_hdr *resp)
+{
+	return req->instance_id == resp->instance_id && req->request &&
+	       !resp->request && req->type == resp->type &&
+	       req->command == resp->command;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_types_req(uint8_t instance_id, struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_REQUEST;
+	header.command = PLDM_GET_PLDM_TYPES;
+
+	return pack_pldm_header(&header, &(msg->hdr));
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_commands_req(uint8_t instance_id, uint8_t type, ver32_t version,
+			    struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_REQUEST;
+	header.command = PLDM_GET_PLDM_COMMANDS;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_get_commands_req *request =
+		(struct pldm_get_commands_req *)msg->payload;
+
+	request->type = type;
+	request->version = version;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_types_resp(uint8_t instance_id, uint8_t completion_code,
+			  const bitfield8_t *types, struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_RESPONSE;
+	header.command = PLDM_GET_PLDM_TYPES;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_get_types_resp *response =
+		(struct pldm_get_types_resp *)msg->payload;
+	response->completion_code = completion_code;
+	if (response->completion_code == PLDM_SUCCESS) {
+		if (types == NULL) {
+			return PLDM_ERROR_INVALID_DATA;
+		}
+		memcpy(response->types, &(types->byte), PLDM_MAX_TYPES / 8);
+	}
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_commands_req(const struct pldm_msg *msg, size_t payload_length,
+			    uint8_t *type, ver32_t *version)
+{
+	if (msg == NULL || type == NULL || version == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != PLDM_GET_COMMANDS_REQ_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_get_commands_req *request =
+		(struct pldm_get_commands_req *)msg->payload;
+	*type = request->type;
+	*version = request->version;
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_commands_resp(uint8_t instance_id, uint8_t completion_code,
+			     const bitfield8_t *commands, struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_RESPONSE;
+	header.command = PLDM_GET_PLDM_COMMANDS;
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_get_commands_resp *response =
+		(struct pldm_get_commands_resp *)msg->payload;
+	response->completion_code = completion_code;
+	if (response->completion_code == PLDM_SUCCESS) {
+		if (commands == NULL) {
+			return PLDM_ERROR_INVALID_DATA;
+		}
+		memcpy(response->commands, &(commands->byte),
+		       PLDM_MAX_CMDS_PER_TYPE / 8);
+	}
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_types_resp(const struct pldm_msg *msg, size_t payload_length,
+			  uint8_t *completion_code, bitfield8_t *types)
+{
+	if (msg == NULL || types == NULL || completion_code == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*completion_code = msg->payload[0];
+	if (PLDM_SUCCESS != *completion_code) {
+		return PLDM_SUCCESS;
+	}
+
+	if (payload_length != PLDM_GET_TYPES_RESP_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_get_types_resp *response =
+		(struct pldm_get_types_resp *)msg->payload;
+
+	memcpy(&(types->byte), response->types, PLDM_MAX_TYPES / 8);
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_commands_resp(const struct pldm_msg *msg, size_t payload_length,
+			     uint8_t *completion_code, bitfield8_t *commands)
+{
+	if (msg == NULL || commands == NULL || completion_code == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*completion_code = msg->payload[0];
+	if (PLDM_SUCCESS != *completion_code) {
+		return PLDM_SUCCESS;
+	}
+
+	if (payload_length != PLDM_GET_COMMANDS_RESP_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_get_commands_resp *response =
+		(struct pldm_get_commands_resp *)msg->payload;
+
+	memcpy(&(commands->byte), response->commands,
+	       PLDM_MAX_CMDS_PER_TYPE / 8);
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_version_req(uint8_t instance_id, uint32_t transfer_handle,
+			   uint8_t transfer_opflag, uint8_t type,
+			   struct pldm_msg *msg)
+{
+	if (NULL == msg) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.msg_type = PLDM_REQUEST;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_BASE;
+	header.command = PLDM_GET_PLDM_VERSION;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_get_version_req *request =
+		(struct pldm_get_version_req *)msg->payload;
+	transfer_handle = htole32(transfer_handle);
+	request->transfer_handle = transfer_handle;
+	request->transfer_opflag = transfer_opflag;
+	request->type = type;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_version_resp(uint8_t instance_id, uint8_t completion_code,
+			    uint32_t next_transfer_handle,
+			    uint8_t transfer_flag, const ver32_t *version_data,
+			    size_t version_size, struct pldm_msg *msg)
+{
+	if (NULL == msg) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.msg_type = PLDM_RESPONSE;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_BASE;
+	header.command = PLDM_GET_PLDM_VERSION;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_get_version_resp *response =
+		(struct pldm_get_version_resp *)msg->payload;
+	response->completion_code = completion_code;
+	if (response->completion_code == PLDM_SUCCESS) {
+		response->next_transfer_handle = htole32(next_transfer_handle);
+		response->transfer_flag = transfer_flag;
+		memcpy(response->version_data, (uint8_t *)version_data,
+		       version_size);
+	}
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_version_req(const struct pldm_msg *msg, size_t payload_length,
+			   uint32_t *transfer_handle, uint8_t *transfer_opflag,
+			   uint8_t *type)
+{
+	if (payload_length != PLDM_GET_VERSION_REQ_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_get_version_req *request =
+		(struct pldm_get_version_req *)msg->payload;
+	*transfer_handle = le32toh(request->transfer_handle);
+	*transfer_opflag = request->transfer_opflag;
+	*type = request->type;
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_version_resp(const struct pldm_msg *msg, size_t payload_length,
+			    uint8_t *completion_code,
+			    uint32_t *next_transfer_handle,
+			    uint8_t *transfer_flag, ver32_t *version)
+{
+	if (msg == NULL || next_transfer_handle == NULL ||
+	    transfer_flag == NULL || completion_code == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*completion_code = msg->payload[0];
+	if (PLDM_SUCCESS != *completion_code) {
+		return PLDM_SUCCESS;
+	}
+
+	if (payload_length < PLDM_GET_VERSION_RESP_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_get_version_resp *response =
+		(struct pldm_get_version_resp *)msg->payload;
+
+	*next_transfer_handle = le32toh(response->next_transfer_handle);
+	*transfer_flag = response->transfer_flag;
+	memcpy(version, (uint8_t *)response->version_data, sizeof(ver32_t));
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_tid_req(uint8_t instance_id, struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_REQUEST;
+	header.command = PLDM_GET_TID;
+
+	return pack_pldm_header(&header, &(msg->hdr));
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_tid_resp(uint8_t instance_id, uint8_t completion_code,
+			uint8_t tid, struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_RESPONSE;
+	header.command = PLDM_GET_TID;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_get_tid_resp *response =
+		(struct pldm_get_tid_resp *)msg->payload;
+	response->completion_code = completion_code;
+	response->tid = tid;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_tid_resp(const struct pldm_msg *msg, size_t payload_length,
+			uint8_t *completion_code, uint8_t *tid)
+{
+	if (msg == NULL || tid == NULL || completion_code == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*completion_code = msg->payload[0];
+	if (PLDM_SUCCESS != *completion_code) {
+		return PLDM_SUCCESS;
+	}
+
+	if (payload_length != PLDM_GET_TID_RESP_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_get_tid_resp *response =
+		(struct pldm_get_tid_resp *)msg->payload;
+
+	*tid = response->tid;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_set_tid_req(uint8_t instance_id, uint8_t tid, struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (tid == 0x0 || tid == 0xff) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_REQUEST;
+	header.command = PLDM_SET_TID;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_set_tid_req *request =
+		(struct pldm_set_tid_req *)msg->payload;
+	request->tid = tid;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_multipart_receive_req(const struct pldm_msg *msg,
+				 size_t payload_length, uint8_t *pldm_type,
+				 uint8_t *transfer_opflag,
+				 uint32_t *transfer_ctx,
+				 uint32_t *transfer_handle,
+				 uint32_t *section_offset,
+				 uint32_t *section_length)
+{
+	if (msg == NULL || pldm_type == NULL || transfer_opflag == NULL ||
+	    transfer_ctx == NULL || transfer_handle == NULL ||
+	    section_offset == NULL || section_length == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != PLDM_MULTIPART_RECEIVE_REQ_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_multipart_receive_req *request =
+		(struct pldm_multipart_receive_req *)msg->payload;
+
+	if (request->pldm_type != PLDM_BASE) {
+		return PLDM_ERROR_INVALID_PLDM_TYPE;
+	}
+
+	// Any enum value above PLDM_XFER_CURRENT_PART is invalid.
+	if (request->transfer_opflag > PLDM_XFER_CURRENT_PART) {
+		return PLDM_INVALID_TRANSFER_OPERATION_FLAG;
+	}
+
+	// A section offset of 0 is only valid on FIRST_PART or COMPLETE Xfers.
+	uint32_t sec_offset = le32toh(request->section_offset);
+	if (sec_offset == 0 &&
+	    (request->transfer_opflag != PLDM_XFER_FIRST_PART &&
+	     request->transfer_opflag != PLDM_XFER_COMPLETE)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	uint32_t handle = le32toh(request->transfer_handle);
+	if (handle == 0 && request->transfer_opflag != PLDM_XFER_COMPLETE) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*pldm_type = request->pldm_type;
+	*transfer_opflag = request->transfer_opflag;
+	*transfer_ctx = request->transfer_ctx;
+	*transfer_handle = handle;
+	*section_offset = sec_offset;
+	*section_length = le32toh(request->section_length);
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_cc_only_resp(uint8_t instance_id, uint8_t type, uint8_t command,
+			uint8_t cc, struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_RESPONSE;
+	header.pldm_type = type;
+	header.command = command;
+
+	uint8_t rc = pack_pldm_header(&header, &msg->hdr);
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	msg->payload[0] = cc;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_pldm_header_only(uint8_t msg_type, uint8_t instance_id,
+			    uint8_t pldm_type, uint8_t command,
+			    struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.msg_type = msg_type;
+	header.instance = instance_id;
+	header.pldm_type = pldm_type;
+	header.command = command;
+	return pack_pldm_header(&header, &(msg->hdr));
+}
diff --git a/src/dsp/bios.c b/src/dsp/bios.c
new file mode 100644
index 0000000..00abf7f
--- /dev/null
+++ b/src/dsp/bios.c
@@ -0,0 +1,697 @@
+/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
+#include <libpldm/base.h>
+#include <libpldm/bios.h>
+#include <libpldm/utils.h>
+
+#include <endian.h>
+#include <string.h>
+
+LIBPLDM_ABI_STABLE
+int encode_get_date_time_req(uint8_t instance_id, struct pldm_msg *msg)
+{
+	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_BIOS;
+	header.command = PLDM_GET_DATE_TIME;
+	return pack_pldm_header(&header, &(msg->hdr));
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_date_time_resp(uint8_t instance_id, uint8_t completion_code,
+			      uint8_t seconds, uint8_t minutes, uint8_t hours,
+			      uint8_t day, uint8_t month, uint16_t year,
+			      struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.msg_type = PLDM_RESPONSE;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_BIOS;
+	header.command = PLDM_GET_DATE_TIME;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_get_date_time_resp *response =
+		(struct pldm_get_date_time_resp *)msg->payload;
+	response->completion_code = completion_code;
+	if (response->completion_code == PLDM_SUCCESS) {
+		response->completion_code = completion_code;
+		response->seconds = seconds;
+		response->minutes = minutes;
+		response->hours = hours;
+		response->day = day;
+		response->month = month;
+		response->year = htole16(year);
+	}
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_date_time_resp(const struct pldm_msg *msg, size_t payload_length,
+			      uint8_t *completion_code, uint8_t *seconds,
+			      uint8_t *minutes, uint8_t *hours, uint8_t *day,
+			      uint8_t *month, uint16_t *year)
+{
+	if (msg == NULL || seconds == NULL || minutes == NULL ||
+	    hours == NULL || day == NULL || month == NULL || year == NULL ||
+	    completion_code == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*completion_code = msg->payload[0];
+	if (PLDM_SUCCESS != *completion_code) {
+		return PLDM_SUCCESS;
+	}
+
+	if (payload_length != PLDM_GET_DATE_TIME_RESP_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_get_date_time_resp *response =
+		(struct pldm_get_date_time_resp *)msg->payload;
+
+	*seconds = response->seconds;
+	*minutes = response->minutes;
+	*hours = response->hours;
+	*day = response->day;
+	*month = response->month;
+	*year = le16toh(response->year);
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_set_date_time_req(uint8_t instance_id, uint8_t seconds,
+			     uint8_t minutes, uint8_t hours, uint8_t day,
+			     uint8_t month, uint16_t year, struct pldm_msg *msg,
+			     size_t payload_length)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (payload_length != sizeof(struct pldm_set_date_time_req)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	if (!is_time_legal(seconds, minutes, hours, day, month, year)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_REQUEST;
+	header.pldm_type = PLDM_BIOS;
+	header.command = PLDM_SET_DATE_TIME;
+
+	uint8_t rc = pack_pldm_header(&header, &msg->hdr);
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_set_date_time_req *request =
+		(struct pldm_set_date_time_req *)msg->payload;
+	request->seconds = dec2bcd8(seconds);
+	request->minutes = dec2bcd8(minutes);
+	request->hours = dec2bcd8(hours);
+	request->day = dec2bcd8(day);
+	request->month = dec2bcd8(month);
+	request->year = htole16(dec2bcd16(year));
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_set_date_time_req(const struct pldm_msg *msg, size_t payload_length,
+			     uint8_t *seconds, uint8_t *minutes, uint8_t *hours,
+			     uint8_t *day, uint8_t *month, uint16_t *year)
+{
+	if (msg == NULL || seconds == NULL || minutes == NULL ||
+	    hours == NULL || day == NULL || month == NULL || year == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (payload_length != sizeof(struct pldm_set_date_time_req)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	const struct pldm_set_date_time_req *request =
+		(struct pldm_set_date_time_req *)msg->payload;
+
+	*seconds = bcd2dec8(request->seconds);
+	*minutes = bcd2dec8(request->minutes);
+	*hours = bcd2dec8(request->hours);
+	*day = bcd2dec8(request->day);
+	*month = bcd2dec8(request->month);
+	*year = bcd2dec16(le16toh(request->year));
+
+	if (!is_time_legal(*seconds, *minutes, *hours, *day, *month, *year)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_set_date_time_resp(uint8_t instance_id, uint8_t completion_code,
+			      struct pldm_msg *msg, size_t payload_length)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (payload_length != sizeof(struct pldm_only_cc_resp)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_RESPONSE;
+	header.pldm_type = PLDM_BIOS;
+	header.command = PLDM_SET_DATE_TIME;
+
+	uint8_t rc = pack_pldm_header(&header, &msg->hdr);
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_only_cc_resp *response =
+		(struct pldm_only_cc_resp *)msg->payload;
+	response->completion_code = completion_code;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_set_date_time_resp(const struct pldm_msg *msg, size_t payload_length,
+			      uint8_t *completion_code)
+{
+	if (msg == NULL || completion_code == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*completion_code = msg->payload[0];
+	if (PLDM_SUCCESS != *completion_code) {
+		return PLDM_SUCCESS;
+	}
+
+	if (payload_length != sizeof(struct pldm_only_cc_resp)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_bios_table_resp(uint8_t instance_id, uint8_t completion_code,
+			       uint32_t next_transfer_handle,
+			       uint8_t transfer_flag, uint8_t *table_data,
+			       size_t payload_length, struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.msg_type = PLDM_RESPONSE;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_BIOS;
+	header.command = PLDM_GET_BIOS_TABLE;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_get_bios_table_resp *response =
+		(struct pldm_get_bios_table_resp *)msg->payload;
+	response->completion_code = completion_code;
+	if (response->completion_code == PLDM_SUCCESS) {
+		response->next_transfer_handle = htole32(next_transfer_handle);
+		response->transfer_flag = transfer_flag;
+		if (table_data != NULL &&
+		    payload_length > (sizeof(struct pldm_msg_hdr) +
+				      PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES)) {
+			memcpy(response->table_data, table_data,
+			       payload_length -
+				       (sizeof(struct pldm_msg_hdr) +
+					PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES));
+		}
+	}
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_bios_table_req(uint8_t instance_id, uint32_t transfer_handle,
+			      uint8_t transfer_op_flag, uint8_t table_type,
+			      struct pldm_msg *msg)
+{
+	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_BIOS;
+	header.command = PLDM_GET_BIOS_TABLE;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_get_bios_table_req *request =
+		(struct pldm_get_bios_table_req *)msg->payload;
+
+	request->transfer_handle = htole32(transfer_handle);
+	request->transfer_op_flag = transfer_op_flag;
+	request->table_type = table_type;
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_bios_table_req(const struct pldm_msg *msg, size_t payload_length,
+			      uint32_t *transfer_handle,
+			      uint8_t *transfer_op_flag, uint8_t *table_type)
+{
+	if (msg == NULL || transfer_op_flag == NULL || table_type == NULL ||
+	    transfer_handle == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != PLDM_GET_BIOS_TABLE_REQ_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_get_bios_table_req *request =
+		(struct pldm_get_bios_table_req *)msg->payload;
+	*transfer_handle = le32toh(request->transfer_handle);
+	*transfer_op_flag = request->transfer_op_flag;
+	*table_type = request->table_type;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_bios_table_resp(const struct pldm_msg *msg,
+			       size_t payload_length, uint8_t *completion_code,
+			       uint32_t *next_transfer_handle,
+			       uint8_t *transfer_flag,
+			       size_t *bios_table_offset)
+
+{
+	if (msg == NULL || transfer_flag == NULL ||
+	    next_transfer_handle == NULL || completion_code == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (payload_length <= PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_get_bios_table_resp *response =
+		(struct pldm_get_bios_table_resp *)msg->payload;
+
+	*completion_code = response->completion_code;
+
+	if (PLDM_SUCCESS != *completion_code) {
+		return PLDM_SUCCESS;
+	}
+
+	*next_transfer_handle = le32toh(response->next_transfer_handle);
+	*transfer_flag = response->transfer_flag;
+
+	*bios_table_offset = sizeof(*completion_code) +
+			     sizeof(*next_transfer_handle) +
+			     sizeof(*transfer_flag);
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_bios_attribute_current_value_by_handle_req(
+	uint8_t instance_id, uint32_t transfer_handle, uint8_t transfer_op_flag,
+	uint16_t attribute_handle, struct pldm_msg *msg)
+{
+	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_BIOS;
+	header.command = PLDM_GET_BIOS_ATTRIBUTE_CURRENT_VALUE_BY_HANDLE;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_get_bios_attribute_current_value_by_handle_req *request =
+		(struct pldm_get_bios_attribute_current_value_by_handle_req *)
+			msg->payload;
+
+	request->transfer_handle = htole32(transfer_handle);
+	request->transfer_op_flag = transfer_op_flag;
+	request->attribute_handle = htole16(attribute_handle);
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_bios_attribute_current_value_by_handle_resp(
+	const struct pldm_msg *msg, size_t payload_length,
+	uint8_t *completion_code, uint32_t *next_transfer_handle,
+	uint8_t *transfer_flag, struct variable_field *attribute_data)
+{
+	if (msg == NULL || transfer_flag == NULL ||
+	    next_transfer_handle == NULL || completion_code == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_get_bios_attribute_current_value_by_handle_resp *response =
+		(struct pldm_get_bios_attribute_current_value_by_handle_resp *)
+			msg->payload;
+
+	*completion_code = response->completion_code;
+
+	if (PLDM_SUCCESS != *completion_code) {
+		return PLDM_SUCCESS;
+	}
+
+	if (payload_length <=
+	    PLDM_GET_BIOS_ATTR_CURR_VAL_BY_HANDLE_MIN_RESP_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	*next_transfer_handle = le32toh(response->next_transfer_handle);
+	*transfer_flag = response->transfer_flag;
+
+	attribute_data->ptr = response->attribute_data;
+	attribute_data->length = payload_length - sizeof(*response) + 1;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_bios_attribute_current_value_by_handle_req(
+	const struct pldm_msg *msg, size_t payload_length,
+	uint32_t *transfer_handle, uint8_t *transfer_op_flag,
+	uint16_t *attribute_handle)
+{
+	if (msg == NULL || transfer_handle == NULL ||
+	    transfer_op_flag == NULL || attribute_handle == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != PLDM_GET_BIOS_ATTR_CURR_VAL_BY_HANDLE_REQ_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_get_bios_attribute_current_value_by_handle_req *request =
+		(struct pldm_get_bios_attribute_current_value_by_handle_req *)
+			msg->payload;
+	*transfer_handle = le32toh(request->transfer_handle);
+	*transfer_op_flag = request->transfer_op_flag;
+	*attribute_handle = le16toh(request->attribute_handle);
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_bios_current_value_by_handle_resp(uint8_t instance_id,
+						 uint8_t completion_code,
+						 uint32_t next_transfer_handle,
+						 uint8_t transfer_flag,
+						 const uint8_t *attribute_data,
+						 size_t attribute_length,
+						 struct pldm_msg *msg)
+{
+	if (msg == NULL || attribute_data == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.msg_type = PLDM_RESPONSE;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_BIOS;
+	header.command = PLDM_GET_BIOS_ATTRIBUTE_CURRENT_VALUE_BY_HANDLE;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_get_bios_attribute_current_value_by_handle_resp *response =
+		(struct pldm_get_bios_attribute_current_value_by_handle_resp *)
+			msg->payload;
+	response->completion_code = completion_code;
+	if (response->completion_code == PLDM_SUCCESS) {
+		response->next_transfer_handle = htole32(next_transfer_handle);
+		response->transfer_flag = transfer_flag;
+		if (attribute_data != NULL) {
+			memcpy(response->attribute_data, attribute_data,
+			       attribute_length);
+		}
+	}
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_set_bios_attribute_current_value_req(
+	uint8_t instance_id, uint32_t transfer_handle, uint8_t transfer_flag,
+	const uint8_t *attribute_data, size_t attribute_length,
+	struct pldm_msg *msg, size_t payload_length)
+{
+	if (msg == NULL || attribute_data == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (PLDM_SET_BIOS_ATTR_CURR_VAL_MIN_REQ_BYTES + attribute_length !=
+	    payload_length) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_REQUEST;
+	header.pldm_type = PLDM_BIOS;
+	header.command = PLDM_SET_BIOS_ATTRIBUTE_CURRENT_VALUE;
+
+	uint8_t rc = pack_pldm_header(&header, &msg->hdr);
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_set_bios_attribute_current_value_req *request =
+		(struct pldm_set_bios_attribute_current_value_req *)msg->payload;
+	request->transfer_handle = htole32(transfer_handle);
+	request->transfer_flag = transfer_flag;
+	memcpy(request->attribute_data, attribute_data, attribute_length);
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_set_bios_attribute_current_value_resp(const struct pldm_msg *msg,
+						 size_t payload_length,
+						 uint8_t *completion_code,
+						 uint32_t *next_transfer_handle)
+{
+	if (msg == NULL || completion_code == NULL ||
+	    next_transfer_handle == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*completion_code = msg->payload[0];
+	if (PLDM_SUCCESS != *completion_code) {
+		return PLDM_SUCCESS;
+	}
+
+	if (payload_length != PLDM_SET_BIOS_ATTR_CURR_VAL_RESP_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_set_bios_attribute_current_value_resp *response =
+		(struct pldm_set_bios_attribute_current_value_resp *)
+			msg->payload;
+
+	*next_transfer_handle = le32toh(response->next_transfer_handle);
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_set_bios_attribute_current_value_req(
+	const struct pldm_msg *msg, size_t payload_length,
+	uint32_t *transfer_handle, uint8_t *transfer_flag,
+	struct variable_field *attribute)
+{
+	if (msg == NULL || transfer_handle == NULL || transfer_flag == NULL ||
+	    attribute == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (payload_length < PLDM_SET_BIOS_ATTR_CURR_VAL_MIN_REQ_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_set_bios_attribute_current_value_req *request =
+		(struct pldm_set_bios_attribute_current_value_req *)msg->payload;
+	*transfer_handle = le32toh(request->transfer_handle);
+	*transfer_flag = request->transfer_flag;
+	attribute->length =
+		payload_length - PLDM_SET_BIOS_ATTR_CURR_VAL_MIN_REQ_BYTES;
+	attribute->ptr = request->attribute_data;
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_set_bios_attribute_current_value_resp(uint8_t instance_id,
+						 uint8_t completion_code,
+						 uint32_t next_transfer_handle,
+						 struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_RESPONSE;
+	header.pldm_type = PLDM_BIOS;
+	header.command = PLDM_SET_BIOS_ATTRIBUTE_CURRENT_VALUE;
+
+	uint8_t rc = pack_pldm_header(&header, &msg->hdr);
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_set_bios_attribute_current_value_resp *response =
+		(struct pldm_set_bios_attribute_current_value_resp *)
+			msg->payload;
+	response->completion_code = completion_code;
+	response->next_transfer_handle = htole32(next_transfer_handle);
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_set_bios_table_req(uint8_t instance_id, uint32_t transfer_handle,
+			      uint8_t transfer_flag, uint8_t table_type,
+			      const uint8_t *table_data, size_t table_length,
+			      struct pldm_msg *msg, size_t payload_length)
+{
+	if (msg == NULL || table_data == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (PLDM_SET_BIOS_TABLE_MIN_REQ_BYTES + table_length !=
+	    payload_length) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_REQUEST;
+	header.pldm_type = PLDM_BIOS;
+	header.command = PLDM_SET_BIOS_TABLE;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_set_bios_table_req *request =
+		(struct pldm_set_bios_table_req *)msg->payload;
+	request->transfer_handle = htole32(transfer_handle);
+	request->transfer_flag = transfer_flag;
+	request->table_type = table_type;
+	memcpy(request->table_data, table_data, table_length);
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_set_bios_table_resp(const struct pldm_msg *msg,
+			       size_t payload_length, uint8_t *completion_code,
+			       uint32_t *next_transfer_handle)
+{
+	if (msg == NULL || completion_code == NULL ||
+	    next_transfer_handle == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*completion_code = msg->payload[0];
+	if (PLDM_SUCCESS != *completion_code) {
+		return PLDM_SUCCESS;
+	}
+
+	if (payload_length != PLDM_SET_BIOS_TABLE_RESP_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_set_bios_table_resp *response =
+		(struct pldm_set_bios_table_resp *)msg->payload;
+
+	*next_transfer_handle = le32toh(response->next_transfer_handle);
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_set_bios_table_resp(uint8_t instance_id, uint8_t completion_code,
+			       uint32_t next_transfer_handle,
+			       struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_RESPONSE;
+	header.pldm_type = PLDM_BIOS;
+	header.command = PLDM_SET_BIOS_TABLE;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_set_bios_table_resp *response =
+		(struct pldm_set_bios_table_resp *)msg->payload;
+	response->completion_code = completion_code;
+	response->next_transfer_handle = htole32(next_transfer_handle);
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_set_bios_table_req(const struct pldm_msg *msg, size_t payload_length,
+			      uint32_t *transfer_handle, uint8_t *transfer_flag,
+			      uint8_t *table_type, struct variable_field *table)
+{
+	if (msg == NULL || transfer_handle == NULL || transfer_flag == NULL ||
+	    table_type == NULL || table == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length < PLDM_SET_BIOS_TABLE_MIN_REQ_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_set_bios_table_req *request =
+		(struct pldm_set_bios_table_req *)msg->payload;
+	*transfer_handle = le32toh(request->transfer_handle);
+	*transfer_flag = request->transfer_flag;
+	*table_type = request->table_type;
+	table->length = payload_length - PLDM_SET_BIOS_TABLE_MIN_REQ_BYTES;
+	table->ptr = request->table_data;
+
+	return PLDM_SUCCESS;
+}
diff --git a/src/dsp/bios_table.c b/src/dsp/bios_table.c
new file mode 100644
index 0000000..10b2495
--- /dev/null
+++ b/src/dsp/bios_table.c
@@ -0,0 +1,1222 @@
+/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
+#include "array.h"
+
+#include <libpldm/base.h>
+#include <libpldm/bios.h>
+#include <libpldm/bios_table.h>
+#include <libpldm/utils.h>
+
+#include <assert.h>
+#include <endian.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define POINTER_CHECK(pointer)                                                 \
+	do {                                                                   \
+		if ((pointer) == NULL)                                         \
+			return PLDM_ERROR_INVALID_DATA;                        \
+	} while (0)
+
+#define ATTR_TYPE_EXPECT(type, expected)                                       \
+	do {                                                                   \
+		if ((type) != (expected) && (type) != ((expected) | 0x80))     \
+			return PLDM_ERROR_INVALID_DATA;                        \
+	} while (0)
+
+#define BUFFER_SIZE_EXPECT(current_size, expected_size)                        \
+	do {                                                                   \
+		if ((current_size) < (expected_size))                          \
+			return PLDM_ERROR_INVALID_LENGTH;                      \
+	} while (0)
+
+#define MEMBER_SIZE(type, member) sizeof(((struct type *)0)->member)
+
+static void set_errmsg(const char **errmsg, const char *msg)
+{
+	if (errmsg != NULL) {
+		*errmsg = msg;
+	}
+}
+
+static int get_bios_string_handle(uint16_t *val)
+{
+	static uint16_t handle = 0;
+	assert(handle != UINT16_MAX);
+	if (handle == UINT16_MAX) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*val = handle++;
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+size_t pldm_bios_table_string_entry_encode_length(uint16_t string_length)
+{
+	return sizeof(struct pldm_bios_string_table_entry) -
+	       MEMBER_SIZE(pldm_bios_string_table_entry, name) + string_length;
+}
+
+LIBPLDM_ABI_STABLE
+int pldm_bios_table_string_entry_encode_check(void *entry, size_t entry_length,
+					      const char *str,
+					      uint16_t str_length)
+{
+	if (str_length == 0) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	POINTER_CHECK(entry);
+	POINTER_CHECK(str);
+	size_t length = pldm_bios_table_string_entry_encode_length(str_length);
+	BUFFER_SIZE_EXPECT(entry_length, length);
+	struct pldm_bios_string_table_entry *string_entry = entry;
+	uint16_t handle;
+	int rc = get_bios_string_handle(&handle);
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+	string_entry->string_handle = htole16(handle);
+	string_entry->string_length = htole16(str_length);
+	memcpy(string_entry->name, str, str_length);
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+uint16_t pldm_bios_table_string_entry_decode_handle(
+	const struct pldm_bios_string_table_entry *entry)
+{
+	return le16toh(entry->string_handle);
+}
+
+LIBPLDM_ABI_STABLE
+uint16_t pldm_bios_table_string_entry_decode_string_length(
+	const struct pldm_bios_string_table_entry *entry)
+{
+	return le16toh(entry->string_length);
+}
+
+LIBPLDM_ABI_STABLE
+int pldm_bios_table_string_entry_decode_string_check(
+	const struct pldm_bios_string_table_entry *entry, char *buffer,
+	size_t size)
+{
+	POINTER_CHECK(entry);
+	POINTER_CHECK(buffer);
+	if (size == 0) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+	size_t length =
+		pldm_bios_table_string_entry_decode_string_length(entry);
+	length = length < (size - 1) ? length : (size - 1);
+	memcpy(buffer, entry->name, length);
+	buffer[length] = 0;
+	return PLDM_SUCCESS;
+}
+
+static ssize_t string_table_entry_length(const void *table_entry)
+{
+	const struct pldm_bios_string_table_entry *entry = table_entry;
+	size_t len = sizeof(*entry) - sizeof(entry->name) +
+		     pldm_bios_table_string_entry_decode_string_length(entry);
+	if (len > SSIZE_MAX) {
+		return -1;
+	}
+	return (ssize_t)len;
+}
+
+static int get_bios_attr_handle(uint16_t *val)
+{
+	static uint16_t handle = 0;
+	assert(handle != UINT16_MAX);
+	if (handle == UINT16_MAX) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*val = handle++;
+	return PLDM_SUCCESS;
+}
+
+static int attr_table_entry_encode_header(void *entry, size_t length,
+					  uint8_t attr_type,
+					  uint16_t string_handle)
+{
+	struct pldm_bios_attr_table_entry *attr_entry = entry;
+
+	assert(sizeof(*attr_entry) <= length);
+	if (sizeof(*attr_entry) > length) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	uint16_t handle;
+	int rc = get_bios_attr_handle(&handle);
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	attr_entry->attr_handle = htole16(handle);
+	attr_entry->attr_type = attr_type;
+	attr_entry->string_handle = htole16(string_handle);
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+uint16_t pldm_bios_table_attr_entry_decode_attribute_handle(
+	const struct pldm_bios_attr_table_entry *entry)
+{
+	return le16toh(entry->attr_handle);
+}
+
+LIBPLDM_ABI_STABLE
+uint8_t pldm_bios_table_attr_entry_decode_attribute_type(
+	const struct pldm_bios_attr_table_entry *entry)
+{
+	return entry->attr_type;
+}
+
+LIBPLDM_ABI_STABLE
+uint16_t pldm_bios_table_attr_entry_decode_string_handle(
+	const struct pldm_bios_attr_table_entry *entry)
+{
+	return le16toh(entry->string_handle);
+}
+
+LIBPLDM_ABI_STABLE
+size_t pldm_bios_table_attr_entry_enum_encode_length(uint8_t pv_num,
+						     uint8_t def_num)
+{
+	return sizeof(struct pldm_bios_attr_table_entry) -
+	       MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
+	       sizeof(pv_num) + pv_num * sizeof(uint16_t) + sizeof(def_num) +
+	       def_num;
+}
+
+LIBPLDM_ABI_STABLE
+int pldm_bios_table_attr_entry_enum_encode_check(
+	void *entry, size_t entry_length,
+	const struct pldm_bios_table_attr_entry_enum_info *info)
+{
+	POINTER_CHECK(entry);
+	POINTER_CHECK(info);
+	size_t length = pldm_bios_table_attr_entry_enum_encode_length(
+		info->pv_num, info->def_num);
+	BUFFER_SIZE_EXPECT(entry_length, length);
+	uint8_t attr_type = info->read_only ? PLDM_BIOS_ENUMERATION_READ_ONLY :
+					      PLDM_BIOS_ENUMERATION;
+	int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
+						info->name_handle);
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+	struct pldm_bios_attr_table_entry *attr_entry = entry;
+	attr_entry->metadata[0] = info->pv_num;
+	uint16_t *pv_hdls =
+		(uint16_t *)(attr_entry->metadata + 1 /* sizeof(pv num) */);
+	size_t i;
+	for (i = 0; i < info->pv_num; i++) {
+		pv_hdls[i] = htole16(info->pv_handle[i]);
+	}
+	attr_entry->metadata[1 + info->pv_num * sizeof(uint16_t)] =
+		info->def_num;
+	memcpy(attr_entry->metadata + 1 /* sizeof(pv num) */ +
+		       info->pv_num * sizeof(uint16_t) + 1 /* sizeof(def num)*/,
+	       info->def_index, info->def_num);
+	return PLDM_SUCCESS;
+}
+
+#define ATTR_TYPE_EXPECT(type, expected)                                       \
+	do {                                                                   \
+		if ((type) != (expected) && (type) != ((expected) | 0x80))     \
+			return PLDM_ERROR_INVALID_DATA;                        \
+	} while (0)
+
+LIBPLDM_ABI_STABLE
+int pldm_bios_table_attr_entry_enum_decode_pv_num_check(
+	const struct pldm_bios_attr_table_entry *entry, uint8_t *pv_num)
+{
+	POINTER_CHECK(entry);
+	POINTER_CHECK(pv_num);
+	ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
+	*pv_num = entry->metadata[0];
+	return PLDM_SUCCESS;
+}
+
+static uint8_t pldm_bios_table_attr_entry_enum_decode_def_num(
+	const struct pldm_bios_attr_table_entry *entry)
+{
+	uint8_t pv_num = entry->metadata[0];
+	return entry->metadata[sizeof(uint8_t) /* pv_num */ +
+			       sizeof(uint16_t) * pv_num];
+}
+
+LIBPLDM_ABI_STABLE
+int pldm_bios_table_attr_entry_enum_decode_def_num_check(
+	const struct pldm_bios_attr_table_entry *entry, uint8_t *def_num)
+{
+	POINTER_CHECK(entry);
+	POINTER_CHECK(def_num);
+	ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
+	*def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int pldm_bios_table_attr_entry_enum_decode_pv_hdls_check(
+	const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
+	uint8_t pv_num)
+{
+	POINTER_CHECK(entry);
+	POINTER_CHECK(pv_hdls);
+	ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
+	uint8_t num = entry->metadata[0];
+	num = num < pv_num ? num : pv_num;
+	size_t i;
+	for (i = 0; i < num; i++) {
+		uint16_t *hdl = (uint16_t *)(entry->metadata + sizeof(uint8_t) +
+					     i * sizeof(uint16_t));
+		pv_hdls[i] = le16toh(*hdl);
+	}
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+uint8_t pldm_bios_table_attr_entry_enum_decode_def_indices(
+	const struct pldm_bios_attr_table_entry *entry, uint8_t *def_indices,
+	uint8_t def_num)
+{
+	uint8_t num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
+	num = num < def_num ? num : def_num;
+	uint8_t pv_num = entry->metadata[0];
+	const uint8_t *p = entry->metadata +
+			   sizeof(uint8_t) /* number of possible values*/
+			   + pv_num * sizeof(uint16_t) /* possible values */
+			   + sizeof(uint8_t); /* number of default values */
+	memcpy(def_indices, p, num);
+	return num;
+}
+
+/** @brief Get length of an enum attribute entry
+ */
+static ssize_t attr_table_entry_length_enum(const void *arg)
+{
+	const struct pldm_bios_attr_table_entry *entry = arg;
+	uint8_t pv_num = entry->metadata[0];
+	uint8_t def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
+	size_t len =
+		pldm_bios_table_attr_entry_enum_encode_length(pv_num, def_num);
+	if (len > SSIZE_MAX) {
+		return -1;
+	}
+	return (ssize_t)len;
+}
+
+struct attr_table_string_entry_fields {
+	uint8_t string_type;
+	uint16_t min_length;
+	uint16_t max_length;
+	uint16_t def_length;
+	uint8_t def_string[1];
+} __attribute__((packed));
+
+LIBPLDM_ABI_STABLE
+size_t pldm_bios_table_attr_entry_string_encode_length(uint16_t def_str_len)
+{
+	return sizeof(struct pldm_bios_attr_table_entry) -
+	       MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
+	       sizeof(struct attr_table_string_entry_fields) -
+	       MEMBER_SIZE(attr_table_string_entry_fields, def_string) +
+	       def_str_len;
+}
+
+#define PLDM_STRING_TYPE_MAX	5
+#define PLDM_STRING_TYPE_VENDOR 0xff
+
+LIBPLDM_ABI_STABLE
+int pldm_bios_table_attr_entry_string_info_check(
+	const struct pldm_bios_table_attr_entry_string_info *info,
+	const char **errmsg)
+{
+	if (info->min_length > info->max_length) {
+		set_errmsg(errmsg, "MinimumStingLength should not be greater "
+				   "than MaximumStringLength");
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (info->min_length == info->max_length &&
+	    info->def_length != info->min_length) {
+		set_errmsg(errmsg, "Wrong DefaultStringLength");
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (info->def_length > info->max_length ||
+	    info->def_length < info->min_length) {
+		set_errmsg(errmsg, "Wrong DefaultStringLength");
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (info->string_type > PLDM_STRING_TYPE_MAX &&
+	    info->string_type != PLDM_STRING_TYPE_VENDOR) {
+		set_errmsg(errmsg, "Wrong StringType");
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (info->def_string && info->def_length != strlen(info->def_string)) {
+		set_errmsg(errmsg, "Length of DefaultString should be equal to "
+				   "DefaultStringLength");
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int pldm_bios_table_attr_entry_string_encode_check(
+	void *entry, size_t entry_length,
+	const struct pldm_bios_table_attr_entry_string_info *info)
+{
+	POINTER_CHECK(entry);
+	POINTER_CHECK(info);
+	size_t length = pldm_bios_table_attr_entry_string_encode_length(
+		info->def_length);
+	BUFFER_SIZE_EXPECT(entry_length, length);
+	if (pldm_bios_table_attr_entry_string_info_check(info, NULL) !=
+	    PLDM_SUCCESS) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	uint8_t attr_type = info->read_only ? PLDM_BIOS_STRING_READ_ONLY :
+					      PLDM_BIOS_STRING;
+	int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
+						info->name_handle);
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+	struct pldm_bios_attr_table_entry *attr_entry = entry;
+	struct attr_table_string_entry_fields *attr_fields =
+		(struct attr_table_string_entry_fields *)attr_entry->metadata;
+	attr_fields->string_type = info->string_type;
+	attr_fields->min_length = htole16(info->min_length);
+	attr_fields->max_length = htole16(info->max_length);
+	attr_fields->def_length = htole16(info->def_length);
+	if (info->def_length != 0 && info->def_string != NULL) {
+		memcpy(attr_fields->def_string, info->def_string,
+		       info->def_length);
+	}
+	return PLDM_SUCCESS;
+}
+
+static uint16_t pldm_bios_table_attr_entry_string_decode_def_string_length(
+	const struct pldm_bios_attr_table_entry *entry)
+{
+	struct attr_table_string_entry_fields *fields =
+		(struct attr_table_string_entry_fields *)entry->metadata;
+	return le16toh(fields->def_length);
+}
+
+LIBPLDM_ABI_STABLE
+int pldm_bios_table_attr_entry_string_decode_def_string_length_check(
+	const struct pldm_bios_attr_table_entry *entry,
+	uint16_t *def_string_length)
+{
+	POINTER_CHECK(entry);
+	POINTER_CHECK(def_string_length);
+	ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_STRING);
+	*def_string_length =
+		pldm_bios_table_attr_entry_string_decode_def_string_length(
+			entry);
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+uint8_t pldm_bios_table_attr_entry_string_decode_string_type(
+	const struct pldm_bios_attr_table_entry *entry)
+{
+	struct attr_table_string_entry_fields *fields =
+		(struct attr_table_string_entry_fields *)entry->metadata;
+	return fields->string_type;
+}
+
+LIBPLDM_ABI_STABLE
+uint16_t pldm_bios_table_attr_entry_string_decode_max_length(
+	const struct pldm_bios_attr_table_entry *entry)
+{
+	struct attr_table_string_entry_fields *fields =
+		(struct attr_table_string_entry_fields *)entry->metadata;
+	return le16toh(fields->max_length);
+}
+
+LIBPLDM_ABI_STABLE
+uint16_t pldm_bios_table_attr_entry_string_decode_min_length(
+	const struct pldm_bios_attr_table_entry *entry)
+{
+	struct attr_table_string_entry_fields *fields =
+		(struct attr_table_string_entry_fields *)entry->metadata;
+	return le16toh(fields->min_length);
+}
+
+LIBPLDM_ABI_STABLE
+uint16_t pldm_bios_table_attr_entry_string_decode_def_string(
+	const struct pldm_bios_attr_table_entry *entry, char *buffer,
+	size_t size)
+{
+	uint16_t length =
+		pldm_bios_table_attr_entry_string_decode_def_string_length(
+			entry);
+	length = length < (size - 1) ? length : (size - 1);
+	struct attr_table_string_entry_fields *fields =
+		(struct attr_table_string_entry_fields *)entry->metadata;
+	memcpy(buffer, fields->def_string, length);
+	buffer[length] = 0;
+	return length;
+}
+
+/** @brief Get length of a string attribute entry
+ */
+static ssize_t attr_table_entry_length_string(const void *entry)
+{
+	uint16_t def_str_len =
+		pldm_bios_table_attr_entry_string_decode_def_string_length(
+			entry);
+	size_t len =
+		pldm_bios_table_attr_entry_string_encode_length(def_str_len);
+	if (len > SSIZE_MAX) {
+		return -1;
+	}
+	return (ssize_t)len;
+}
+
+struct attr_table_integer_entry_fields {
+	uint64_t lower_bound;
+	uint64_t upper_bound;
+	uint32_t scalar_increment;
+	uint64_t default_value;
+} __attribute__((packed));
+
+LIBPLDM_ABI_STABLE
+size_t pldm_bios_table_attr_entry_integer_encode_length(void)
+{
+	return sizeof(struct pldm_bios_attr_table_entry) - 1 +
+	       sizeof(struct attr_table_integer_entry_fields);
+}
+
+LIBPLDM_ABI_STABLE
+int pldm_bios_table_attr_entry_integer_info_check(
+	const struct pldm_bios_table_attr_entry_integer_info *info,
+	const char **errmsg)
+{
+	if (info->lower_bound == info->upper_bound) {
+		if (info->default_value != info->lower_bound) {
+			set_errmsg(errmsg, "Wrong DefaultValue");
+			return PLDM_ERROR_INVALID_DATA;
+		}
+		if (info->scalar_increment != 0) {
+			set_errmsg(errmsg, "Wrong ScalarIncrement");
+			return PLDM_ERROR_INVALID_DATA;
+		}
+		return PLDM_SUCCESS;
+	}
+	if (info->lower_bound > info->upper_bound) {
+		set_errmsg(errmsg,
+			   "LowerBound should not be greater than UpperBound");
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (info->default_value > info->upper_bound ||
+	    info->default_value < info->lower_bound) {
+		set_errmsg(errmsg, "Wrong DefaultValue");
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (info->scalar_increment == 0) {
+		set_errmsg(errmsg, "ScalarIncrement should not be zero when "
+				   "lower_bound != upper_bound");
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if ((info->default_value - info->lower_bound) %
+		    info->scalar_increment !=
+	    0) {
+		set_errmsg(errmsg, "Wrong DefaultValue or ScalarIncrement");
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int pldm_bios_table_attr_entry_integer_encode_check(
+	void *entry, size_t entry_length,
+	const struct pldm_bios_table_attr_entry_integer_info *info)
+{
+	POINTER_CHECK(entry);
+	POINTER_CHECK(info);
+	size_t length = pldm_bios_table_attr_entry_integer_encode_length();
+	BUFFER_SIZE_EXPECT(entry_length, length);
+	if (pldm_bios_table_attr_entry_integer_info_check(info, NULL) !=
+	    PLDM_SUCCESS) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	uint8_t attr_type = info->read_only ? PLDM_BIOS_INTEGER_READ_ONLY :
+					      PLDM_BIOS_INTEGER;
+	int rc = attr_table_entry_encode_header(entry, entry_length, attr_type,
+						info->name_handle);
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+	struct pldm_bios_attr_table_entry *attr_entry = entry;
+	struct attr_table_integer_entry_fields *attr_fields =
+		(struct attr_table_integer_entry_fields *)attr_entry->metadata;
+	attr_fields->lower_bound = htole64(info->lower_bound);
+	attr_fields->upper_bound = htole64(info->upper_bound);
+	attr_fields->scalar_increment = htole32(info->scalar_increment);
+	attr_fields->default_value = htole64(info->default_value);
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+void pldm_bios_table_attr_entry_integer_decode(
+	const struct pldm_bios_attr_table_entry *entry, uint64_t *lower,
+	uint64_t *upper, uint32_t *scalar, uint64_t *def)
+{
+	struct attr_table_integer_entry_fields *fields =
+		(struct attr_table_integer_entry_fields *)entry->metadata;
+	*lower = le64toh(fields->lower_bound);
+	*upper = le64toh(fields->upper_bound);
+	*scalar = le32toh(fields->scalar_increment);
+	*def = le64toh(fields->default_value);
+}
+
+static ssize_t attr_table_entry_length_integer(const void *entry)
+{
+	(void)entry;
+	size_t len = pldm_bios_table_attr_entry_integer_encode_length();
+	if (len > SSIZE_MAX) {
+		return -1;
+	}
+	return (ssize_t)len;
+}
+
+struct table_entry_length {
+	uint8_t attr_type;
+	ssize_t (*entry_length_handler)(const void *);
+};
+
+static const struct table_entry_length *
+find_table_entry_length_by_type(uint8_t attr_type,
+				const struct table_entry_length *handlers,
+				size_t count)
+{
+	size_t i;
+	for (i = 0; i < count; i++) {
+		if (attr_type == handlers[i].attr_type) {
+			return &handlers[i];
+		}
+	}
+	return NULL;
+}
+
+static const struct table_entry_length attr_table_entries[] = {
+	{ .attr_type = PLDM_BIOS_ENUMERATION,
+	  .entry_length_handler = attr_table_entry_length_enum },
+	{ .attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
+	  .entry_length_handler = attr_table_entry_length_enum },
+	{ .attr_type = PLDM_BIOS_STRING,
+	  .entry_length_handler = attr_table_entry_length_string },
+	{ .attr_type = PLDM_BIOS_STRING_READ_ONLY,
+	  .entry_length_handler = attr_table_entry_length_string },
+	{ .attr_type = PLDM_BIOS_INTEGER,
+	  .entry_length_handler = attr_table_entry_length_integer },
+	{ .attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
+	  .entry_length_handler = attr_table_entry_length_integer },
+};
+
+static ssize_t attr_table_entry_length(const void *table_entry)
+{
+	const struct pldm_bios_attr_table_entry *entry = table_entry;
+	const struct table_entry_length *attr_table_entry =
+		find_table_entry_length_by_type(entry->attr_type,
+						attr_table_entries,
+						ARRAY_SIZE(attr_table_entries));
+	assert(attr_table_entry != NULL);
+	if (!attr_table_entry) {
+		return -1;
+	}
+	assert(attr_table_entry->entry_length_handler != NULL);
+	if (!attr_table_entry->entry_length_handler) {
+		return -1;
+	}
+
+	return attr_table_entry->entry_length_handler(entry);
+}
+
+LIBPLDM_ABI_STABLE
+uint16_t pldm_bios_table_attr_value_entry_decode_attribute_handle(
+	const struct pldm_bios_attr_val_table_entry *entry)
+{
+	return le16toh(entry->attr_handle);
+}
+
+LIBPLDM_ABI_STABLE
+uint8_t pldm_bios_table_attr_value_entry_decode_attribute_type(
+	const struct pldm_bios_attr_val_table_entry *entry)
+{
+	return entry->attr_type;
+}
+
+LIBPLDM_ABI_STABLE
+size_t pldm_bios_table_attr_value_entry_encode_enum_length(uint8_t count)
+{
+	return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
+	       sizeof(count) + count;
+}
+
+LIBPLDM_ABI_STABLE
+uint8_t pldm_bios_table_attr_value_entry_enum_decode_number(
+	const struct pldm_bios_attr_val_table_entry *entry)
+{
+	return entry->value[0];
+}
+
+LIBPLDM_ABI_STABLE
+uint8_t pldm_bios_table_attr_value_entry_enum_decode_handles(
+	const struct pldm_bios_attr_val_table_entry *entry, uint8_t *handles,
+	uint8_t number)
+{
+	uint8_t curr_num =
+		pldm_bios_table_attr_value_entry_enum_decode_number(entry);
+	curr_num = number < curr_num ? number : curr_num;
+	memcpy(handles, &entry->value[1], curr_num);
+
+	return curr_num;
+}
+
+LIBPLDM_ABI_STABLE
+int pldm_bios_table_attr_value_entry_encode_enum_check(
+	void *entry, size_t entry_length, uint16_t attr_handle,
+	uint8_t attr_type, uint8_t count, const uint8_t *handles)
+{
+	POINTER_CHECK(entry);
+	POINTER_CHECK(handles);
+	if (count != 0 && handles == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_ENUMERATION);
+	size_t length =
+		pldm_bios_table_attr_value_entry_encode_enum_length(count);
+	BUFFER_SIZE_EXPECT(entry_length, length);
+	struct pldm_bios_attr_val_table_entry *table_entry = entry;
+	table_entry->attr_handle = htole16(attr_handle);
+	table_entry->attr_type = attr_type;
+	table_entry->value[0] = count;
+	if (count != 0) {
+		memcpy(&table_entry->value[1], handles, count);
+	}
+	return PLDM_SUCCESS;
+}
+
+static ssize_t attr_value_table_entry_length_enum(const void *entry)
+{
+	uint8_t number =
+		pldm_bios_table_attr_value_entry_enum_decode_number(entry);
+	size_t len =
+		pldm_bios_table_attr_value_entry_encode_enum_length(number);
+	if (len > SSIZE_MAX) {
+		return -1;
+	}
+	return (ssize_t)len;
+}
+
+LIBPLDM_ABI_STABLE
+size_t
+pldm_bios_table_attr_value_entry_encode_string_length(uint16_t string_length)
+{
+	return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
+	       sizeof(string_length) + string_length;
+}
+
+LIBPLDM_ABI_STABLE
+uint16_t pldm_bios_table_attr_value_entry_string_decode_length(
+	const struct pldm_bios_attr_val_table_entry *entry)
+{
+	uint16_t str_length = 0;
+	memcpy(&str_length, entry->value, sizeof(str_length));
+	return le16toh(str_length);
+}
+
+LIBPLDM_ABI_STABLE
+void pldm_bios_table_attr_value_entry_string_decode_string(
+	const struct pldm_bios_attr_val_table_entry *entry,
+	struct variable_field *current_string)
+{
+	current_string->length =
+		pldm_bios_table_attr_value_entry_string_decode_length(entry);
+	current_string->ptr =
+		entry->value + sizeof(uint16_t); // sizeof(CurrentStringLength)
+}
+
+LIBPLDM_ABI_STABLE
+int pldm_bios_table_attr_value_entry_encode_string_check(
+	void *entry, size_t entry_length, uint16_t attr_handle,
+	uint8_t attr_type, uint16_t str_length, const char *str)
+{
+	POINTER_CHECK(entry);
+	if (str_length != 0 && str == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_STRING);
+	size_t length = pldm_bios_table_attr_value_entry_encode_string_length(
+		str_length);
+	BUFFER_SIZE_EXPECT(entry_length, length);
+	struct pldm_bios_attr_val_table_entry *table_entry = entry;
+	table_entry->attr_handle = htole16(attr_handle);
+	table_entry->attr_type = attr_type;
+	if (str_length != 0) {
+		memcpy(table_entry->value + sizeof(str_length), str,
+		       str_length);
+	}
+	str_length = htole16(str_length);
+	memcpy(table_entry->value, &str_length, sizeof(str_length));
+	return PLDM_SUCCESS;
+}
+
+static ssize_t attr_value_table_entry_length_string(const void *entry)
+{
+	uint16_t str_length =
+		pldm_bios_table_attr_value_entry_string_decode_length(entry);
+	size_t len = pldm_bios_table_attr_value_entry_encode_string_length(
+		str_length);
+	if (len > SSIZE_MAX) {
+		return -1;
+	}
+	return (ssize_t)len;
+}
+
+LIBPLDM_ABI_STABLE
+size_t pldm_bios_table_attr_value_entry_encode_integer_length(void)
+{
+	return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
+	       sizeof(uint64_t);
+}
+
+LIBPLDM_ABI_STABLE
+int pldm_bios_table_attr_value_entry_encode_integer_check(void *entry,
+							  size_t entry_length,
+							  uint16_t attr_handle,
+							  uint8_t attr_type,
+							  uint64_t cv)
+{
+	POINTER_CHECK(entry);
+	size_t length =
+		pldm_bios_table_attr_value_entry_encode_integer_length();
+	ATTR_TYPE_EXPECT(attr_type, PLDM_BIOS_INTEGER);
+	BUFFER_SIZE_EXPECT(entry_length, length);
+	struct pldm_bios_attr_val_table_entry *table_entry = entry;
+	table_entry->attr_handle = htole16(attr_handle);
+	table_entry->attr_type = attr_type;
+	cv = htole64(cv);
+	memcpy(table_entry->value, &cv, sizeof(uint64_t));
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+uint64_t pldm_bios_table_attr_value_entry_integer_decode_cv(
+	const struct pldm_bios_attr_val_table_entry *entry)
+{
+	uint64_t cv = 0;
+	memcpy(&cv, entry->value, sizeof(cv));
+	cv = le64toh(cv);
+	return cv;
+}
+
+static ssize_t attr_value_table_entry_length_integer(const void *entry)
+{
+	(void)entry;
+	size_t len = pldm_bios_table_attr_value_entry_encode_integer_length();
+	if (len > SSIZE_MAX) {
+		return -1;
+	}
+	return (ssize_t)len;
+}
+
+static const struct table_entry_length attr_value_table_entries[] = {
+	{ .attr_type = PLDM_BIOS_ENUMERATION,
+	  .entry_length_handler = attr_value_table_entry_length_enum },
+	{ .attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
+	  .entry_length_handler = attr_value_table_entry_length_enum },
+	{ .attr_type = PLDM_BIOS_STRING,
+	  .entry_length_handler = attr_value_table_entry_length_string },
+	{ .attr_type = PLDM_BIOS_STRING_READ_ONLY,
+	  .entry_length_handler = attr_value_table_entry_length_string },
+	{ .attr_type = PLDM_BIOS_INTEGER,
+	  .entry_length_handler = attr_value_table_entry_length_integer },
+	{ .attr_type = PLDM_BIOS_INTEGER_READ_ONLY,
+	  .entry_length_handler = attr_value_table_entry_length_integer },
+};
+
+static ssize_t attr_value_table_entry_length(const void *table_entry)
+{
+	const struct pldm_bios_attr_val_table_entry *entry = table_entry;
+	const struct table_entry_length *entry_length =
+		find_table_entry_length_by_type(
+			entry->attr_type, attr_value_table_entries,
+			ARRAY_SIZE(attr_value_table_entries));
+	assert(entry_length != NULL);
+	if (!entry_length) {
+		return -1;
+	}
+	assert(entry_length->entry_length_handler != NULL);
+	if (!entry_length->entry_length_handler) {
+		return -1;
+	}
+
+	return entry_length->entry_length_handler(entry);
+}
+
+LIBPLDM_ABI_STABLE
+size_t pldm_bios_table_attr_value_entry_length(
+	const struct pldm_bios_attr_val_table_entry *entry)
+{
+	return attr_value_table_entry_length(entry);
+}
+
+LIBPLDM_ABI_STABLE
+uint16_t pldm_bios_table_attr_value_entry_decode_handle(
+	const struct pldm_bios_attr_val_table_entry *entry)
+{
+	return le16toh(entry->attr_handle);
+}
+
+static size_t pad_size_get(size_t size_without_pad)
+{
+	return ((size_without_pad % 4) ? (4 - size_without_pad % 4) : 0);
+}
+
+static uint8_t *pad_append(uint8_t *table_end, size_t pad_size)
+{
+	while (pad_size--) {
+		*table_end++ = 0;
+	}
+
+	return table_end;
+}
+
+static uint8_t *checksum_append(uint8_t *table_end, uint32_t checksum)
+{
+	checksum = htole32(checksum);
+	memcpy(table_end, &checksum, sizeof(checksum));
+
+	return table_end + sizeof(checksum);
+}
+
+LIBPLDM_ABI_STABLE
+size_t pldm_bios_table_pad_checksum_size(size_t size_without_pad)
+{
+	size_t size = pad_size_get(size_without_pad) +
+		      sizeof(uint32_t) /*sizeof(checksum)*/;
+	return size;
+}
+
+LIBPLDM_ABI_STABLE
+int pldm_bios_table_append_pad_checksum_check(void *table, size_t capacity,
+					      size_t *size)
+{
+	if (!table || !size) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	size_t pad_checksum_size = pldm_bios_table_pad_checksum_size(*size);
+	size_t total_length = *size + pad_checksum_size;
+	if (capacity < total_length) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	uint8_t *table_end = (uint8_t *)table + *size;
+	size_t pad_size = pad_size_get(*size);
+	table_end = pad_append(table_end, pad_size);
+
+	uint32_t checksum = crc32(table, *size + pad_size);
+	checksum_append(table_end, checksum);
+	*size = total_length;
+
+	return PLDM_SUCCESS;
+}
+
+struct pldm_bios_table_iter {
+	const uint8_t *table_data;
+	size_t table_len;
+	size_t current_pos;
+	ssize_t (*entry_length_handler)(const void *table_entry);
+};
+
+LIBPLDM_ABI_STABLE
+struct pldm_bios_table_iter *
+pldm_bios_table_iter_create(const void *table, size_t length,
+			    enum pldm_bios_table_types type)
+{
+	struct pldm_bios_table_iter *iter = malloc(sizeof(*iter));
+	assert(iter != NULL);
+	if (!iter) {
+		return NULL;
+	}
+	iter->table_data = table;
+	iter->table_len = length;
+	iter->current_pos = 0;
+	iter->entry_length_handler = NULL;
+	switch (type) {
+	case PLDM_BIOS_STRING_TABLE:
+		iter->entry_length_handler = string_table_entry_length;
+		break;
+	case PLDM_BIOS_ATTR_TABLE:
+		iter->entry_length_handler = attr_table_entry_length;
+		break;
+	case PLDM_BIOS_ATTR_VAL_TABLE:
+		iter->entry_length_handler = attr_value_table_entry_length;
+		break;
+	}
+
+	return iter;
+}
+
+LIBPLDM_ABI_STABLE
+void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter)
+{
+	free(iter);
+}
+
+#define pad_and_check_max 7
+LIBPLDM_ABI_STABLE
+bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter)
+{
+	ssize_t len;
+
+	if (iter->table_len - iter->current_pos <= pad_and_check_max) {
+		return true;
+	}
+
+	len = iter->entry_length_handler(iter->table_data + iter->current_pos);
+
+	return len < 0;
+}
+
+LIBPLDM_ABI_STABLE
+void pldm_bios_table_iter_next(struct pldm_bios_table_iter *iter)
+{
+	if (pldm_bios_table_iter_is_end(iter)) {
+		return;
+	}
+	const void *entry = iter->table_data + iter->current_pos;
+	ssize_t rc = iter->entry_length_handler(entry);
+	/* Prevent bad behaviour by acting as if we've hit the end of the iterator */
+	if (rc < 0) {
+		return;
+	}
+	iter->current_pos += rc;
+}
+
+LIBPLDM_ABI_STABLE
+const void *pldm_bios_table_iter_value(struct pldm_bios_table_iter *iter)
+{
+	return iter->table_data + iter->current_pos;
+}
+
+typedef bool (*equal_handler)(const void *entry, const void *key);
+
+static const void *
+pldm_bios_table_entry_find_by_iter(struct pldm_bios_table_iter *iter,
+				   const void *key, equal_handler equal)
+{
+	const void *entry;
+	while (!pldm_bios_table_iter_is_end(iter)) {
+		entry = pldm_bios_table_iter_value(iter);
+		if (equal(entry, key)) {
+			return entry;
+		}
+		pldm_bios_table_iter_next(iter);
+	}
+	return NULL;
+}
+
+static const void *
+pldm_bios_table_entry_find_from_table(const void *table, size_t length,
+				      enum pldm_bios_table_types type,
+				      equal_handler equal, const void *key)
+{
+	struct pldm_bios_table_iter *iter =
+		pldm_bios_table_iter_create(table, length, type);
+	const void *entry =
+		pldm_bios_table_entry_find_by_iter(iter, key, equal);
+	pldm_bios_table_iter_free(iter);
+	return entry;
+}
+
+static bool string_table_handle_equal(const void *entry, const void *key)
+{
+	const struct pldm_bios_string_table_entry *string_entry = entry;
+	uint16_t handle = *(uint16_t *)key;
+	if (pldm_bios_table_string_entry_decode_handle(string_entry) ==
+	    handle) {
+		return true;
+	}
+	return false;
+}
+
+LIBPLDM_ABI_STABLE
+const struct pldm_bios_string_table_entry *
+pldm_bios_table_string_find_by_handle(const void *table, size_t length,
+				      uint16_t handle)
+{
+	return pldm_bios_table_entry_find_from_table(table, length,
+						     PLDM_BIOS_STRING_TABLE,
+						     string_table_handle_equal,
+						     &handle);
+}
+
+struct string_equal_arg {
+	uint16_t str_length;
+	const char *str;
+};
+
+static bool string_table_string_equal(const void *entry, const void *key)
+{
+	const struct pldm_bios_string_table_entry *string_entry = entry;
+	const struct string_equal_arg *arg = key;
+	if (arg->str_length !=
+	    pldm_bios_table_string_entry_decode_string_length(string_entry)) {
+		return false;
+	}
+	if (memcmp(string_entry->name, arg->str, arg->str_length) != 0) {
+		return false;
+	}
+	return true;
+}
+
+LIBPLDM_ABI_STABLE
+const struct pldm_bios_string_table_entry *
+pldm_bios_table_string_find_by_string(const void *table, size_t length,
+				      const char *str)
+{
+	uint16_t str_length = strlen(str);
+	struct string_equal_arg arg = { str_length, str };
+	return pldm_bios_table_entry_find_from_table(table, length,
+						     PLDM_BIOS_STRING_TABLE,
+						     string_table_string_equal,
+						     &arg);
+}
+
+static bool attr_table_handle_equal(const void *entry, const void *key)
+{
+	uint16_t handle = *(uint16_t *)key;
+	return pldm_bios_table_attr_entry_decode_attribute_handle(entry) ==
+	       handle;
+}
+
+LIBPLDM_ABI_STABLE
+const struct pldm_bios_attr_table_entry *
+pldm_bios_table_attr_find_by_handle(const void *table, size_t length,
+				    uint16_t handle)
+{
+	return pldm_bios_table_entry_find_from_table(table, length,
+						     PLDM_BIOS_ATTR_TABLE,
+						     attr_table_handle_equal,
+						     &handle);
+}
+
+static bool attr_table_string_handle_equal(const void *entry, const void *key)
+{
+	uint16_t handle = *(uint16_t *)key;
+	return pldm_bios_table_attr_entry_decode_string_handle(entry) == handle;
+}
+
+LIBPLDM_ABI_STABLE
+const struct pldm_bios_attr_table_entry *
+pldm_bios_table_attr_find_by_string_handle(const void *table, size_t length,
+					   uint16_t handle)
+{
+	return pldm_bios_table_entry_find_from_table(
+		table, length, PLDM_BIOS_ATTR_TABLE,
+		attr_table_string_handle_equal, &handle);
+}
+
+static bool attr_value_table_handle_equal(const void *entry, const void *key)
+{
+	uint16_t handle = *(uint16_t *)key;
+	return pldm_bios_table_attr_value_entry_decode_handle(entry) == handle;
+}
+
+LIBPLDM_ABI_STABLE
+const struct pldm_bios_attr_val_table_entry *
+pldm_bios_table_attr_value_find_by_handle(const void *table, size_t length,
+					  uint16_t handle)
+{
+	return pldm_bios_table_entry_find_from_table(
+		table, length, PLDM_BIOS_ATTR_VAL_TABLE,
+		attr_value_table_handle_equal, &handle);
+}
+
+LIBPLDM_ABI_STABLE
+int pldm_bios_table_attr_value_copy_and_update(
+	const void *src_table, size_t src_length, void *dest_table,
+	size_t *dest_length, const void *entry, size_t entry_length)
+{
+	struct pldm_bios_table_iter *iter = pldm_bios_table_iter_create(
+		src_table, src_length, PLDM_BIOS_ATTR_VAL_TABLE);
+
+	int rc = PLDM_SUCCESS;
+	const struct pldm_bios_attr_val_table_entry *tmp;
+	const struct pldm_bios_attr_val_table_entry *to_update = entry;
+	size_t buffer_length = *dest_length;
+	size_t copied_length = 0;
+	size_t length = 0;
+	while (!pldm_bios_table_iter_is_end(iter)) {
+		tmp = pldm_bios_table_iter_attr_value_entry_value(iter);
+		length = attr_value_table_entry_length(tmp);
+
+		/* we need the tmp's entry_length here, iter_next will calculate
+		 * it too, use current_pos directly to avoid calculating it
+		 * twice */
+		iter->current_pos += length;
+		if (tmp->attr_handle == to_update->attr_handle) {
+			if (tmp->attr_type != to_update->attr_type) {
+				rc = PLDM_ERROR_INVALID_DATA;
+				goto out;
+			}
+			length = entry_length;
+			tmp = entry;
+		}
+		if (copied_length + length > buffer_length) {
+			rc = PLDM_ERROR_INVALID_LENGTH;
+			goto out;
+		}
+		memcpy((uint8_t *)dest_table + copied_length, tmp, length);
+		copied_length += length;
+	}
+
+	size_t pad_checksum_size =
+		pldm_bios_table_pad_checksum_size(copied_length);
+	if ((pad_checksum_size + copied_length) > buffer_length) {
+		rc = PLDM_ERROR_INVALID_LENGTH;
+		goto out;
+	}
+
+	rc = pldm_bios_table_append_pad_checksum_check(
+		dest_table, buffer_length, &copied_length);
+	if (rc == PLDM_SUCCESS) {
+		*dest_length = copied_length;
+	}
+out:
+	pldm_bios_table_iter_free(iter);
+	return rc;
+}
+
+LIBPLDM_ABI_STABLE
+bool pldm_bios_table_checksum(const uint8_t *table, size_t size)
+{
+	if (table == NULL) {
+		return false;
+	}
+
+	// 12: BIOSStringHandle(uint16) + BIOSStringLength(uint16) +
+	//     Variable(4) + checksum(uint32)
+	if (size < 12) {
+		return false;
+	}
+
+	uint32_t src_crc = le32toh(*(uint32_t *)(table + size - 4));
+	uint32_t dst_crc = crc32(table, size - 4);
+
+	return src_crc == dst_crc;
+}
diff --git a/src/dsp/firmware_update.c b/src/dsp/firmware_update.c
new file mode 100644
index 0000000..9ebb970
--- /dev/null
+++ b/src/dsp/firmware_update.c
@@ -0,0 +1,1786 @@
+/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
+#include "msgbuf.h"
+#include <libpldm/firmware_update.h>
+#include <libpldm/utils.h>
+
+#include <endian.h>
+#include <stdbool.h>
+#include <string.h>
+
+/** @brief Check whether string type value is valid
+ *
+ *  @return true if string type value is valid, false if not
+ */
+static bool is_string_type_valid(uint8_t string_type)
+{
+	switch (string_type) {
+	case PLDM_STR_TYPE_UNKNOWN:
+		return false;
+	case PLDM_STR_TYPE_ASCII:
+	case PLDM_STR_TYPE_UTF_8:
+	case PLDM_STR_TYPE_UTF_16:
+	case PLDM_STR_TYPE_UTF_16LE:
+	case PLDM_STR_TYPE_UTF_16BE:
+		return true;
+	default:
+		return false;
+	}
+}
+
+/** @brief Return the length of the descriptor type described in firmware update
+ *         specification
+ *
+ *  @return length of the descriptor type if descriptor type is valid else
+ *          return 0
+ */
+static uint16_t get_descriptor_type_length(uint16_t descriptor_type)
+{
+	switch (descriptor_type) {
+	case PLDM_FWUP_PCI_VENDOR_ID:
+		return PLDM_FWUP_PCI_VENDOR_ID_LENGTH;
+	case PLDM_FWUP_IANA_ENTERPRISE_ID:
+		return PLDM_FWUP_IANA_ENTERPRISE_ID_LENGTH;
+	case PLDM_FWUP_UUID:
+		return PLDM_FWUP_UUID_LENGTH;
+	case PLDM_FWUP_PNP_VENDOR_ID:
+		return PLDM_FWUP_PNP_VENDOR_ID_LENGTH;
+	case PLDM_FWUP_ACPI_VENDOR_ID:
+		return PLDM_FWUP_ACPI_VENDOR_ID_LENGTH;
+	case PLDM_FWUP_IEEE_ASSIGNED_COMPANY_ID:
+		return PLDM_FWUP_IEEE_ASSIGNED_COMPANY_ID_LENGTH;
+	case PLDM_FWUP_SCSI_VENDOR_ID:
+		return PLDM_FWUP_SCSI_VENDOR_ID_LENGTH;
+	case PLDM_FWUP_PCI_DEVICE_ID:
+		return PLDM_FWUP_PCI_DEVICE_ID_LENGTH;
+	case PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID:
+		return PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID_LENGTH;
+	case PLDM_FWUP_PCI_SUBSYSTEM_ID:
+		return PLDM_FWUP_PCI_SUBSYSTEM_ID_LENGTH;
+	case PLDM_FWUP_PCI_REVISION_ID:
+		return PLDM_FWUP_PCI_REVISION_ID_LENGTH;
+	case PLDM_FWUP_PNP_PRODUCT_IDENTIFIER:
+		return PLDM_FWUP_PNP_PRODUCT_IDENTIFIER_LENGTH;
+	case PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER:
+		return PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER_LENGTH;
+	case PLDM_FWUP_ASCII_MODEL_NUMBER_LONG_STRING:
+		return PLDM_FWUP_ASCII_MODEL_NUMBER_LONG_STRING_LENGTH;
+	case PLDM_FWUP_ASCII_MODEL_NUMBER_SHORT_STRING:
+		return PLDM_FWUP_ASCII_MODEL_NUMBER_SHORT_STRING_LENGTH;
+	case PLDM_FWUP_SCSI_PRODUCT_ID:
+		return PLDM_FWUP_SCSI_PRODUCT_ID_LENGTH;
+	case PLDM_FWUP_UBM_CONTROLLER_DEVICE_CODE:
+		return PLDM_FWUP_UBM_CONTROLLER_DEVICE_CODE_LENGTH;
+	default:
+		return 0;
+	}
+}
+
+static bool is_downstream_device_update_support_valid(uint8_t resp)
+{
+	switch (resp) {
+	case PLDM_FWUP_DOWNSTREAM_DEVICE_UPDATE_NOT_SUPPORTED:
+	case PLDM_FWUP_DOWNSTREAM_DEVICE_UPDATE_SUPPORTED:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static bool
+is_transfer_operation_flag_valid(enum transfer_op_flag transfer_op_flag)
+{
+	switch (transfer_op_flag) {
+	case PLDM_GET_NEXTPART:
+	case PLDM_GET_FIRSTPART:
+		return true;
+	default:
+		return false;
+	}
+}
+
+/** @brief Check whether ComponentResponse is valid
+ *
+ *  @return true if ComponentResponse is valid, false if not
+ */
+static bool is_comp_resp_valid(uint8_t comp_resp)
+{
+	switch (comp_resp) {
+	case PLDM_CR_COMP_CAN_BE_UPDATED:
+	case PLDM_CR_COMP_MAY_BE_UPDATEABLE:
+		return true;
+
+	default:
+		return false;
+	}
+}
+
+/** @brief Check whether ComponentResponseCode is valid
+ *
+ *  @return true if ComponentResponseCode is valid, false if not
+ */
+static bool is_comp_resp_code_valid(uint8_t comp_resp_code)
+{
+	switch (comp_resp_code) {
+	case PLDM_CRC_COMP_CAN_BE_UPDATED:
+	case PLDM_CRC_COMP_COMPARISON_STAMP_IDENTICAL:
+	case PLDM_CRC_COMP_COMPARISON_STAMP_LOWER:
+	case PLDM_CRC_INVALID_COMP_COMPARISON_STAMP:
+	case PLDM_CRC_COMP_CONFLICT:
+	case PLDM_CRC_COMP_PREREQUISITES_NOT_MET:
+	case PLDM_CRC_COMP_NOT_SUPPORTED:
+	case PLDM_CRC_COMP_SECURITY_RESTRICTIONS:
+	case PLDM_CRC_INCOMPLETE_COMP_IMAGE_SET:
+	case PLDM_CRC_ACTIVE_IMAGE_NOT_UPDATEABLE_SUBSEQUENTLY:
+	case PLDM_CRC_COMP_VER_STR_IDENTICAL:
+	case PLDM_CRC_COMP_VER_STR_LOWER:
+		return true;
+
+	default:
+		if (comp_resp_code >=
+			    PLDM_CRC_VENDOR_COMP_RESP_CODE_RANGE_MIN &&
+		    comp_resp_code <=
+			    PLDM_CRC_VENDOR_COMP_RESP_CODE_RANGE_MAX) {
+			return true;
+		}
+		return false;
+	}
+}
+
+/** @brief Check whether ComponentCompatibilityResponse is valid
+ *
+ *  @return true if ComponentCompatibilityResponse is valid, false if not
+ */
+static bool is_comp_compatibility_resp_valid(uint8_t comp_compatibility_resp)
+{
+	switch (comp_compatibility_resp) {
+	case PLDM_CCR_COMP_CAN_BE_UPDATED:
+	case PLDM_CCR_COMP_CANNOT_BE_UPDATED:
+		return true;
+
+	default:
+		return false;
+	}
+}
+
+/** @brief Check whether ComponentCompatibilityResponse Code is valid
+ *
+ *  @return true if ComponentCompatibilityResponse Code is valid, false if not
+ */
+static bool
+is_comp_compatibility_resp_code_valid(uint8_t comp_compatibility_resp_code)
+{
+	switch (comp_compatibility_resp_code) {
+	case PLDM_CCRC_NO_RESPONSE_CODE:
+	case PLDM_CCRC_COMP_COMPARISON_STAMP_IDENTICAL:
+	case PLDM_CCRC_COMP_COMPARISON_STAMP_LOWER:
+	case PLDM_CCRC_INVALID_COMP_COMPARISON_STAMP:
+	case PLDM_CCRC_COMP_CONFLICT:
+	case PLDM_CCRC_COMP_PREREQUISITES_NOT_MET:
+	case PLDM_CCRC_COMP_NOT_SUPPORTED:
+	case PLDM_CCRC_COMP_SECURITY_RESTRICTIONS:
+	case PLDM_CRC_INCOMPLETE_COMP_IMAGE_SET:
+	case PLDM_CCRC_COMP_INFO_NO_MATCH:
+	case PLDM_CCRC_COMP_VER_STR_IDENTICAL:
+	case PLDM_CCRC_COMP_VER_STR_LOWER:
+		return true;
+
+	default:
+		if (comp_compatibility_resp_code >=
+			    PLDM_CCRC_VENDOR_COMP_RESP_CODE_RANGE_MIN &&
+		    comp_compatibility_resp_code <=
+			    PLDM_CCRC_VENDOR_COMP_RESP_CODE_RANGE_MAX) {
+			return true;
+		}
+		return false;
+	}
+}
+
+/** @brief Check whether SelfContainedActivationRequest is valid
+ *
+ *  @return true if SelfContainedActivationRequest is valid, false if not
+ */
+static bool
+is_self_contained_activation_req_valid(bool8_t self_contained_activation_req)
+{
+	switch (self_contained_activation_req) {
+	case PLDM_NOT_ACTIVATE_SELF_CONTAINED_COMPONENTS:
+	case PLDM_ACTIVATE_SELF_CONTAINED_COMPONENTS:
+		return true;
+
+	default:
+		return false;
+	}
+}
+
+/** @brief Check if current or previous status in GetStatus command response is
+ *         valid
+ *
+ *	@param[in] state - current or previous different state machine state of
+ *                     the FD
+ *	@return true if state is valid, false if not
+ */
+static bool is_state_valid(uint8_t state)
+{
+	switch (state) {
+	case PLDM_FD_STATE_IDLE:
+	case PLDM_FD_STATE_LEARN_COMPONENTS:
+	case PLDM_FD_STATE_READY_XFER:
+	case PLDM_FD_STATE_DOWNLOAD:
+	case PLDM_FD_STATE_VERIFY:
+	case PLDM_FD_STATE_APPLY:
+	case PLDM_FD_STATE_ACTIVATE:
+		return true;
+
+	default:
+		return false;
+	}
+}
+
+/** @brief Check if aux state in GetStatus command response is valid
+ *
+ *  @param[in] aux_state - provides additional information to the UA to describe
+ *                         the current operation state of the FD/FDP
+ *
+ *	@return true if aux state is valid, false if not
+ */
+static bool is_aux_state_valid(uint8_t aux_state)
+{
+	switch (aux_state) {
+	case PLDM_FD_OPERATION_IN_PROGRESS:
+	case PLDM_FD_OPERATION_SUCCESSFUL:
+	case PLDM_FD_OPERATION_FAILED:
+	case PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER:
+		return true;
+
+	default:
+		return false;
+	}
+}
+
+/** @brief Check if aux state status in GetStatus command response is valid
+ *
+ *	@param[in] aux_state_status - aux state status
+ *
+ *	@return true if aux state status is valid, false if not
+ */
+static bool is_aux_state_status_valid(uint8_t aux_state_status)
+{
+	if (aux_state_status == PLDM_FD_AUX_STATE_IN_PROGRESS_OR_SUCCESS ||
+	    aux_state_status == PLDM_FD_TIMEOUT ||
+	    aux_state_status == PLDM_FD_GENERIC_ERROR ||
+	    (aux_state_status >= PLDM_FD_VENDOR_DEFINED_STATUS_CODE_START &&
+	     aux_state_status <= PLDM_FD_VENDOR_DEFINED_STATUS_CODE_END)) {
+		return true;
+	}
+
+	return false;
+}
+
+/** @brief Check if reason code in GetStatus command response is valid
+ *
+ *	@param[in] reason_code - provides the reason for why the current state
+ *                           entered the IDLE state
+ *
+ *	@return true if reason code is valid, false if not
+ */
+static bool is_reason_code_valid(uint8_t reason_code)
+{
+	switch (reason_code) {
+	case PLDM_FD_INITIALIZATION:
+	case PLDM_FD_ACTIVATE_FW:
+	case PLDM_FD_CANCEL_UPDATE:
+	case PLDM_FD_TIMEOUT_LEARN_COMPONENT:
+	case PLDM_FD_TIMEOUT_READY_XFER:
+	case PLDM_FD_TIMEOUT_DOWNLOAD:
+	case PLDM_FD_TIMEOUT_VERIFY:
+	case PLDM_FD_TIMEOUT_APPLY:
+		return true;
+
+	default:
+		if (reason_code >= PLDM_FD_STATUS_VENDOR_DEFINED_MIN) {
+			return true;
+		}
+		return false;
+	}
+}
+
+/** @brief Check if non functioning component indication in CancelUpdate
+ *         response is valid
+ *
+ *  @return true if non functioning component indication is valid, false if not
+ */
+static bool is_non_functioning_component_indication_valid(
+	bool8_t non_functioning_component_indication)
+{
+	switch (non_functioning_component_indication) {
+	case PLDM_FWUP_COMPONENTS_FUNCTIONING:
+	case PLDM_FWUP_COMPONENTS_NOT_FUNCTIONING:
+		return true;
+
+	default:
+		return false;
+	}
+}
+
+LIBPLDM_ABI_STABLE
+int decode_pldm_package_header_info(
+	const uint8_t *data, size_t length,
+	struct pldm_package_header_information *package_header_info,
+	struct variable_field *package_version_str)
+{
+	if (data == NULL || package_header_info == NULL ||
+	    package_version_str == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (length < sizeof(struct pldm_package_header_information)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_package_header_information *data_header =
+		(struct pldm_package_header_information *)(data);
+
+	if (!is_string_type_valid(data_header->package_version_string_type) ||
+	    (data_header->package_version_string_length == 0)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (length < sizeof(struct pldm_package_header_information) +
+			     data_header->package_version_string_length) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	if ((data_header->component_bitmap_bit_length %
+	     PLDM_FWUP_COMPONENT_BITMAP_MULTIPLE) != 0) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	memcpy(package_header_info->uuid, data_header->uuid,
+	       sizeof(data_header->uuid));
+	package_header_info->package_header_format_version =
+		data_header->package_header_format_version;
+	package_header_info->package_header_size =
+		le16toh(data_header->package_header_size);
+	memcpy(package_header_info->package_release_date_time,
+	       data_header->package_release_date_time,
+	       sizeof(data_header->package_release_date_time));
+	package_header_info->component_bitmap_bit_length =
+		le16toh(data_header->component_bitmap_bit_length);
+	package_header_info->package_version_string_type =
+		data_header->package_version_string_type;
+	package_header_info->package_version_string_length =
+		data_header->package_version_string_length;
+	package_version_str->ptr =
+		data + sizeof(struct pldm_package_header_information);
+	package_version_str->length =
+		package_header_info->package_version_string_length;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_firmware_device_id_record(
+	const uint8_t *data, size_t length,
+	uint16_t component_bitmap_bit_length,
+	struct pldm_firmware_device_id_record *fw_device_id_record,
+	struct variable_field *applicable_components,
+	struct variable_field *comp_image_set_version_str,
+	struct variable_field *record_descriptors,
+	struct variable_field *fw_device_pkg_data)
+{
+	if (data == NULL || fw_device_id_record == NULL ||
+	    applicable_components == NULL ||
+	    comp_image_set_version_str == NULL || record_descriptors == NULL ||
+	    fw_device_pkg_data == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (length < sizeof(struct pldm_firmware_device_id_record)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	if ((component_bitmap_bit_length %
+	     PLDM_FWUP_COMPONENT_BITMAP_MULTIPLE) != 0) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_firmware_device_id_record *data_record =
+		(struct pldm_firmware_device_id_record *)(data);
+
+	if (!is_string_type_valid(
+		    data_record->comp_image_set_version_string_type) ||
+	    (data_record->comp_image_set_version_string_length == 0)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	fw_device_id_record->record_length =
+		le16toh(data_record->record_length);
+	fw_device_id_record->descriptor_count = data_record->descriptor_count;
+	fw_device_id_record->device_update_option_flags.value =
+		le32toh(data_record->device_update_option_flags.value);
+	fw_device_id_record->comp_image_set_version_string_type =
+		data_record->comp_image_set_version_string_type;
+	fw_device_id_record->comp_image_set_version_string_length =
+		data_record->comp_image_set_version_string_length;
+	fw_device_id_record->fw_device_pkg_data_length =
+		le16toh(data_record->fw_device_pkg_data_length);
+
+	if (length < fw_device_id_record->record_length) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	uint16_t applicable_components_length =
+		component_bitmap_bit_length /
+		PLDM_FWUP_COMPONENT_BITMAP_MULTIPLE;
+	uint16_t calc_min_record_length =
+		sizeof(struct pldm_firmware_device_id_record) +
+		applicable_components_length +
+		data_record->comp_image_set_version_string_length +
+		PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN +
+		fw_device_id_record->fw_device_pkg_data_length;
+
+	if (fw_device_id_record->record_length < calc_min_record_length) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	applicable_components->ptr =
+		data + sizeof(struct pldm_firmware_device_id_record);
+	applicable_components->length = applicable_components_length;
+
+	comp_image_set_version_str->ptr =
+		applicable_components->ptr + applicable_components->length;
+	comp_image_set_version_str->length =
+		fw_device_id_record->comp_image_set_version_string_length;
+
+	record_descriptors->ptr = comp_image_set_version_str->ptr +
+				  comp_image_set_version_str->length;
+	record_descriptors->length =
+		fw_device_id_record->record_length -
+		sizeof(struct pldm_firmware_device_id_record) -
+		applicable_components_length -
+		fw_device_id_record->comp_image_set_version_string_length -
+		fw_device_id_record->fw_device_pkg_data_length;
+
+	if (fw_device_id_record->fw_device_pkg_data_length) {
+		fw_device_pkg_data->ptr =
+			record_descriptors->ptr + record_descriptors->length;
+		fw_device_pkg_data->length =
+			fw_device_id_record->fw_device_pkg_data_length;
+	}
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_descriptor_type_length_value(const uint8_t *data, size_t length,
+					uint16_t *descriptor_type,
+					struct variable_field *descriptor_data)
+{
+	uint16_t descriptor_length = 0;
+
+	if (data == NULL || descriptor_type == NULL ||
+	    descriptor_data == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (length < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_descriptor_tlv *entry =
+		(struct pldm_descriptor_tlv *)(data);
+
+	*descriptor_type = le16toh(entry->descriptor_type);
+	descriptor_length = le16toh(entry->descriptor_length);
+	if (*descriptor_type != PLDM_FWUP_VENDOR_DEFINED) {
+		if (descriptor_length !=
+		    get_descriptor_type_length(*descriptor_type)) {
+			return PLDM_ERROR_INVALID_LENGTH;
+		}
+	}
+
+	if (length < (sizeof(*descriptor_type) + sizeof(descriptor_length) +
+		      descriptor_length)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	descriptor_data->ptr = entry->descriptor_data;
+	descriptor_data->length = descriptor_length;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_vendor_defined_descriptor_value(
+	const uint8_t *data, size_t length, uint8_t *descriptor_title_str_type,
+	struct variable_field *descriptor_title_str,
+	struct variable_field *descriptor_data)
+{
+	if (data == NULL || descriptor_title_str_type == NULL ||
+	    descriptor_title_str == NULL || descriptor_data == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (length < sizeof(struct pldm_vendor_defined_descriptor_title_data)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_vendor_defined_descriptor_title_data *entry =
+		(struct pldm_vendor_defined_descriptor_title_data *)(data);
+	if (!is_string_type_valid(
+		    entry->vendor_defined_descriptor_title_str_type) ||
+	    (entry->vendor_defined_descriptor_title_str_len == 0)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	// Assuming atleast 1 byte of VendorDefinedDescriptorData
+	if (length < (sizeof(struct pldm_vendor_defined_descriptor_title_data) +
+		      entry->vendor_defined_descriptor_title_str_len)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	*descriptor_title_str_type =
+		entry->vendor_defined_descriptor_title_str_type;
+	descriptor_title_str->ptr = entry->vendor_defined_descriptor_title_str;
+	descriptor_title_str->length =
+		entry->vendor_defined_descriptor_title_str_len;
+
+	descriptor_data->ptr =
+		descriptor_title_str->ptr + descriptor_title_str->length;
+	descriptor_data->length =
+		length -
+		sizeof(entry->vendor_defined_descriptor_title_str_type) -
+		sizeof(entry->vendor_defined_descriptor_title_str_len) -
+		descriptor_title_str->length;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_pldm_comp_image_info(
+	const uint8_t *data, size_t length,
+	struct pldm_component_image_information *pldm_comp_image_info,
+	struct variable_field *comp_version_str)
+{
+	if (data == NULL || pldm_comp_image_info == NULL ||
+	    comp_version_str == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (length < sizeof(struct pldm_component_image_information)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_component_image_information *data_header =
+		(struct pldm_component_image_information *)(data);
+
+	if (!is_string_type_valid(data_header->comp_version_string_type) ||
+	    (data_header->comp_version_string_length == 0)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (length < sizeof(struct pldm_component_image_information) +
+			     data_header->comp_version_string_length) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	pldm_comp_image_info->comp_classification =
+		le16toh(data_header->comp_classification);
+	pldm_comp_image_info->comp_identifier =
+		le16toh(data_header->comp_identifier);
+	pldm_comp_image_info->comp_comparison_stamp =
+		le32toh(data_header->comp_comparison_stamp);
+	pldm_comp_image_info->comp_options.value =
+		le16toh(data_header->comp_options.value);
+	pldm_comp_image_info->requested_comp_activation_method.value =
+		le16toh(data_header->requested_comp_activation_method.value);
+	pldm_comp_image_info->comp_location_offset =
+		le32toh(data_header->comp_location_offset);
+	pldm_comp_image_info->comp_size = le32toh(data_header->comp_size);
+	pldm_comp_image_info->comp_version_string_type =
+		data_header->comp_version_string_type;
+	pldm_comp_image_info->comp_version_string_length =
+		data_header->comp_version_string_length;
+
+	if ((pldm_comp_image_info->comp_options.bits.bit1 == false &&
+	     pldm_comp_image_info->comp_comparison_stamp !=
+		     PLDM_FWUP_INVALID_COMPONENT_COMPARISON_TIMESTAMP)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (pldm_comp_image_info->comp_location_offset == 0 ||
+	    pldm_comp_image_info->comp_size == 0) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	comp_version_str->ptr =
+		data + sizeof(struct pldm_component_image_information);
+	comp_version_str->length =
+		pldm_comp_image_info->comp_version_string_length;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_query_device_identifiers_req(uint8_t instance_id,
+					size_t payload_length,
+					struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
+				       PLDM_QUERY_DEVICE_IDENTIFIERS, msg);
+}
+
+LIBPLDM_ABI_STABLE
+int decode_query_device_identifiers_resp(const struct pldm_msg *msg,
+					 size_t payload_length,
+					 uint8_t *completion_code,
+					 uint32_t *device_identifiers_len,
+					 uint8_t *descriptor_count,
+					 uint8_t **descriptor_data)
+{
+	if (msg == NULL || completion_code == NULL ||
+	    device_identifiers_len == NULL || descriptor_count == NULL ||
+	    descriptor_data == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*completion_code = msg->payload[0];
+	if (PLDM_SUCCESS != *completion_code) {
+		return PLDM_SUCCESS;
+	}
+
+	if (payload_length <
+	    sizeof(struct pldm_query_device_identifiers_resp)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_query_device_identifiers_resp *response =
+		(struct pldm_query_device_identifiers_resp *)msg->payload;
+	*device_identifiers_len = le32toh(response->device_identifiers_len);
+
+	if (*device_identifiers_len < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	if (payload_length !=
+	    sizeof(struct pldm_query_device_identifiers_resp) +
+		    *device_identifiers_len) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+	*descriptor_count = response->descriptor_count;
+
+	if (*descriptor_count == 0) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	*descriptor_data =
+		(uint8_t *)(msg->payload +
+			    sizeof(struct pldm_query_device_identifiers_resp));
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_firmware_parameters_req(uint8_t instance_id,
+				       size_t payload_length,
+				       struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
+				       PLDM_GET_FIRMWARE_PARAMETERS, msg);
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_firmware_parameters_resp(
+	const struct pldm_msg *msg, size_t payload_length,
+	struct pldm_get_firmware_parameters_resp *resp_data,
+	struct variable_field *active_comp_image_set_ver_str,
+	struct variable_field *pending_comp_image_set_ver_str,
+	struct variable_field *comp_parameter_table)
+{
+	if (msg == NULL || resp_data == NULL ||
+	    active_comp_image_set_ver_str == NULL ||
+	    pending_comp_image_set_ver_str == NULL ||
+	    comp_parameter_table == NULL || !payload_length) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	resp_data->completion_code = msg->payload[0];
+	if (PLDM_SUCCESS != resp_data->completion_code) {
+		return PLDM_SUCCESS;
+	}
+
+	if (payload_length < sizeof(struct pldm_get_firmware_parameters_resp)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_get_firmware_parameters_resp *response =
+		(struct pldm_get_firmware_parameters_resp *)msg->payload;
+
+	if (!is_string_type_valid(
+		    response->active_comp_image_set_ver_str_type) ||
+	    (response->active_comp_image_set_ver_str_len == 0)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (response->pending_comp_image_set_ver_str_len == 0) {
+		if (response->pending_comp_image_set_ver_str_type !=
+		    PLDM_STR_TYPE_UNKNOWN) {
+			return PLDM_ERROR_INVALID_DATA;
+		}
+	} else {
+		if (!is_string_type_valid(
+			    response->pending_comp_image_set_ver_str_type)) {
+			return PLDM_ERROR_INVALID_DATA;
+		}
+	}
+
+	size_t partial_response_length =
+		sizeof(struct pldm_get_firmware_parameters_resp) +
+		response->active_comp_image_set_ver_str_len +
+		response->pending_comp_image_set_ver_str_len;
+
+	if (payload_length < partial_response_length) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	resp_data->capabilities_during_update.value =
+		le32toh(response->capabilities_during_update.value);
+	resp_data->comp_count = le16toh(response->comp_count);
+	resp_data->active_comp_image_set_ver_str_type =
+		response->active_comp_image_set_ver_str_type;
+	resp_data->active_comp_image_set_ver_str_len =
+		response->active_comp_image_set_ver_str_len;
+	resp_data->pending_comp_image_set_ver_str_type =
+		response->pending_comp_image_set_ver_str_type;
+	resp_data->pending_comp_image_set_ver_str_len =
+		response->pending_comp_image_set_ver_str_len;
+
+	active_comp_image_set_ver_str->ptr =
+		msg->payload + sizeof(struct pldm_get_firmware_parameters_resp);
+	active_comp_image_set_ver_str->length =
+		resp_data->active_comp_image_set_ver_str_len;
+
+	if (resp_data->pending_comp_image_set_ver_str_len != 0) {
+		pending_comp_image_set_ver_str->ptr =
+			msg->payload +
+			sizeof(struct pldm_get_firmware_parameters_resp) +
+			resp_data->active_comp_image_set_ver_str_len;
+		pending_comp_image_set_ver_str->length =
+			resp_data->pending_comp_image_set_ver_str_len;
+	} else {
+		pending_comp_image_set_ver_str->ptr = NULL;
+		pending_comp_image_set_ver_str->length = 0;
+	}
+
+	if (payload_length > partial_response_length && resp_data->comp_count) {
+		comp_parameter_table->ptr =
+			msg->payload +
+			sizeof(struct pldm_get_firmware_parameters_resp) +
+			resp_data->active_comp_image_set_ver_str_len +
+			resp_data->pending_comp_image_set_ver_str_len;
+		comp_parameter_table->length =
+			payload_length - partial_response_length;
+	} else {
+		comp_parameter_table->ptr = NULL;
+		comp_parameter_table->length = 0;
+	}
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_firmware_parameters_resp_comp_entry(
+	const uint8_t *data, size_t length,
+	struct pldm_component_parameter_entry *component_data,
+	struct variable_field *active_comp_ver_str,
+	struct variable_field *pending_comp_ver_str)
+{
+	if (data == NULL || component_data == NULL ||
+	    active_comp_ver_str == NULL || pending_comp_ver_str == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (length < sizeof(struct pldm_component_parameter_entry)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_component_parameter_entry *entry =
+		(struct pldm_component_parameter_entry *)(data);
+
+	size_t entry_length = sizeof(struct pldm_component_parameter_entry) +
+			      entry->active_comp_ver_str_len +
+			      entry->pending_comp_ver_str_len;
+
+	if (length < entry_length) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	component_data->comp_classification =
+		le16toh(entry->comp_classification);
+	component_data->comp_identifier = le16toh(entry->comp_identifier);
+	component_data->comp_classification_index =
+		entry->comp_classification_index;
+	component_data->active_comp_comparison_stamp =
+		le32toh(entry->active_comp_comparison_stamp);
+	component_data->active_comp_ver_str_type =
+		entry->active_comp_ver_str_type;
+	component_data->active_comp_ver_str_len =
+		entry->active_comp_ver_str_len;
+	memcpy(component_data->active_comp_release_date,
+	       entry->active_comp_release_date,
+	       sizeof(entry->active_comp_release_date));
+	component_data->pending_comp_comparison_stamp =
+		le32toh(entry->pending_comp_comparison_stamp);
+	component_data->pending_comp_ver_str_type =
+		entry->pending_comp_ver_str_type;
+	component_data->pending_comp_ver_str_len =
+		entry->pending_comp_ver_str_len;
+	memcpy(component_data->pending_comp_release_date,
+	       entry->pending_comp_release_date,
+	       sizeof(entry->pending_comp_release_date));
+	component_data->comp_activation_methods.value =
+		le16toh(entry->comp_activation_methods.value);
+	component_data->capabilities_during_update.value =
+		le32toh(entry->capabilities_during_update.value);
+
+	if (entry->active_comp_ver_str_len != 0) {
+		active_comp_ver_str->ptr =
+			data + sizeof(struct pldm_component_parameter_entry);
+		active_comp_ver_str->length = entry->active_comp_ver_str_len;
+	} else {
+		active_comp_ver_str->ptr = NULL;
+		active_comp_ver_str->length = 0;
+	}
+
+	if (entry->pending_comp_ver_str_len != 0) {
+		pending_comp_ver_str->ptr =
+			data + sizeof(struct pldm_component_parameter_entry) +
+			entry->active_comp_ver_str_len;
+		pending_comp_ver_str->length = entry->pending_comp_ver_str_len;
+	} else {
+		pending_comp_ver_str->ptr = NULL;
+		pending_comp_ver_str->length = 0;
+	}
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_TESTING
+int encode_query_downstream_devices_req(uint8_t instance_id,
+					struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
+				       PLDM_QUERY_DOWNSTREAM_DEVICES, msg);
+}
+
+LIBPLDM_ABI_TESTING
+int decode_query_downstream_devices_resp(
+	const struct pldm_msg *msg, size_t payload_length,
+	struct pldm_query_downstream_devices_resp *resp_data)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	if (msg == NULL || resp_data == NULL || !payload_length) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
+				 msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
+	if (rc) {
+		return rc;
+	}
+	if (PLDM_SUCCESS != resp_data->completion_code) {
+		// Return the CC directly without decoding the rest of the payload
+		return PLDM_SUCCESS;
+	}
+
+	if (payload_length < PLDM_QUERY_DOWNSTREAM_DEVICES_RESP_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	rc = pldm_msgbuf_extract(buf,
+				 resp_data->downstream_device_update_supported);
+	if (rc) {
+		return rc;
+	}
+
+	if (!is_downstream_device_update_support_valid(
+		    resp_data->downstream_device_update_supported)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	pldm_msgbuf_extract(buf, resp_data->number_of_downstream_devices);
+	pldm_msgbuf_extract(buf, resp_data->max_number_of_downstream_devices);
+	pldm_msgbuf_extract(buf, resp_data->capabilities.value);
+
+	return pldm_msgbuf_destroy_consumed(buf);
+}
+
+LIBPLDM_ABI_TESTING
+int encode_query_downstream_identifiers_req(
+	uint8_t instance_id, uint32_t data_transfer_handle,
+	enum transfer_op_flag transfer_operation_flag, 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;
+	}
+
+	if (!is_transfer_operation_flag_valid(transfer_operation_flag)) {
+		return PLDM_INVALID_TRANSFER_OPERATION_FLAG;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_REQUEST;
+	header.pldm_type = PLDM_FWUP;
+	header.command = PLDM_QUERY_DOWNSTREAM_IDENTIFIERS;
+	rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc) {
+		return rc;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf,
+				 PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_REQ_BYTES,
+				 msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_insert(buf, data_transfer_handle);
+	// Data correctness has been verified, cast it to 1-byte data directly.
+	pldm_msgbuf_insert(buf, (uint8_t)transfer_operation_flag);
+
+	return pldm_msgbuf_destroy(buf);
+}
+
+LIBPLDM_ABI_TESTING
+int decode_query_downstream_identifiers_resp(
+	const struct pldm_msg *msg, size_t payload_length,
+	struct pldm_query_downstream_identifiers_resp *resp_data,
+	struct variable_field *downstream_devices)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc = PLDM_ERROR;
+
+	if (msg == NULL || resp_data == NULL || downstream_devices == NULL ||
+	    !payload_length) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
+				 msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
+	if (rc) {
+		return rc;
+	}
+	if (PLDM_SUCCESS != resp_data->completion_code) {
+		return PLDM_SUCCESS;
+	}
+
+	if (payload_length < PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_RESP_MIN_LEN) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	pldm_msgbuf_extract(buf, resp_data->next_data_transfer_handle);
+	pldm_msgbuf_extract(buf, resp_data->transfer_flag);
+
+	rc = pldm_msgbuf_extract(buf, resp_data->downstream_devices_length);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_extract(buf, resp_data->number_of_downstream_devices);
+	rc = pldm_msgbuf_span_required(buf,
+				       resp_data->downstream_devices_length,
+				       (void **)&downstream_devices->ptr);
+	if (rc) {
+		return rc;
+	}
+	downstream_devices->length = resp_data->downstream_devices_length;
+
+	return pldm_msgbuf_destroy(buf);
+}
+
+LIBPLDM_ABI_STABLE
+int encode_request_update_req(uint8_t instance_id, uint32_t max_transfer_size,
+			      uint16_t num_of_comp,
+			      uint8_t max_outstanding_transfer_req,
+			      uint16_t pkg_data_len,
+			      uint8_t comp_image_set_ver_str_type,
+			      uint8_t comp_image_set_ver_str_len,
+			      const struct variable_field *comp_img_set_ver_str,
+			      struct pldm_msg *msg, size_t payload_length)
+{
+	if (comp_img_set_ver_str == NULL || comp_img_set_ver_str->ptr == NULL ||
+	    msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != sizeof(struct pldm_request_update_req) +
+				      comp_img_set_ver_str->length) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	if ((comp_image_set_ver_str_len == 0) ||
+	    (comp_image_set_ver_str_len != comp_img_set_ver_str->length)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if ((max_transfer_size < PLDM_FWUP_BASELINE_TRANSFER_SIZE) ||
+	    (max_outstanding_transfer_req < PLDM_FWUP_MIN_OUTSTANDING_REQ)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (!is_string_type_valid(comp_image_set_ver_str_type)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_REQUEST;
+	header.pldm_type = PLDM_FWUP;
+	header.command = PLDM_REQUEST_UPDATE;
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc) {
+		return rc;
+	}
+
+	struct pldm_request_update_req *request =
+		(struct pldm_request_update_req *)msg->payload;
+
+	request->max_transfer_size = htole32(max_transfer_size);
+	request->num_of_comp = htole16(num_of_comp);
+	request->max_outstanding_transfer_req = max_outstanding_transfer_req;
+	request->pkg_data_len = htole16(pkg_data_len);
+	request->comp_image_set_ver_str_type = comp_image_set_ver_str_type;
+	request->comp_image_set_ver_str_len = comp_image_set_ver_str_len;
+
+	memcpy(msg->payload + sizeof(struct pldm_request_update_req),
+	       comp_img_set_ver_str->ptr, comp_img_set_ver_str->length);
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_request_update_resp(const struct pldm_msg *msg,
+			       size_t payload_length, uint8_t *completion_code,
+			       uint16_t *fd_meta_data_len,
+			       uint8_t *fd_will_send_pkg_data)
+{
+	if (msg == NULL || completion_code == NULL ||
+	    fd_meta_data_len == NULL || fd_will_send_pkg_data == NULL ||
+	    !payload_length) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*completion_code = msg->payload[0];
+	if (*completion_code != PLDM_SUCCESS) {
+		return PLDM_SUCCESS;
+	}
+
+	if (payload_length != sizeof(struct pldm_request_update_resp)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_request_update_resp *response =
+		(struct pldm_request_update_resp *)msg->payload;
+
+	*fd_meta_data_len = le16toh(response->fd_meta_data_len);
+	*fd_will_send_pkg_data = response->fd_will_send_pkg_data;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_pass_component_table_req(uint8_t instance_id, uint8_t transfer_flag,
+				    uint16_t comp_classification,
+				    uint16_t comp_identifier,
+				    uint8_t comp_classification_index,
+				    uint32_t comp_comparison_stamp,
+				    uint8_t comp_ver_str_type,
+				    uint8_t comp_ver_str_len,
+				    const struct variable_field *comp_ver_str,
+				    struct pldm_msg *msg, size_t payload_length)
+{
+	if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != sizeof(struct pldm_pass_component_table_req) +
+				      comp_ver_str->length) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	if ((comp_ver_str_len == 0) ||
+	    (comp_ver_str_len != comp_ver_str->length)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (!is_transfer_flag_valid(transfer_flag)) {
+		return PLDM_INVALID_TRANSFER_OPERATION_FLAG;
+	}
+
+	if (!is_string_type_valid(comp_ver_str_type)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_REQUEST;
+	header.pldm_type = PLDM_FWUP;
+	header.command = PLDM_PASS_COMPONENT_TABLE;
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc) {
+		return rc;
+	}
+
+	struct pldm_pass_component_table_req *request =
+		(struct pldm_pass_component_table_req *)msg->payload;
+
+	request->transfer_flag = transfer_flag;
+	request->comp_classification = htole16(comp_classification);
+	request->comp_identifier = htole16(comp_identifier);
+	request->comp_classification_index = comp_classification_index;
+	request->comp_comparison_stamp = htole32(comp_comparison_stamp);
+	request->comp_ver_str_type = comp_ver_str_type;
+	request->comp_ver_str_len = comp_ver_str_len;
+
+	memcpy(msg->payload + sizeof(struct pldm_pass_component_table_req),
+	       comp_ver_str->ptr, comp_ver_str->length);
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_pass_component_table_resp(const struct pldm_msg *msg,
+				     const size_t payload_length,
+				     uint8_t *completion_code,
+				     uint8_t *comp_resp,
+				     uint8_t *comp_resp_code)
+{
+	if (msg == NULL || completion_code == NULL || comp_resp == NULL ||
+	    comp_resp_code == NULL || !payload_length) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*completion_code = msg->payload[0];
+	if (*completion_code != PLDM_SUCCESS) {
+		return PLDM_SUCCESS;
+	}
+
+	if (payload_length != sizeof(struct pldm_pass_component_table_resp)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_pass_component_table_resp *response =
+		(struct pldm_pass_component_table_resp *)msg->payload;
+
+	if (!is_comp_resp_valid(response->comp_resp)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (!is_comp_resp_code_valid(response->comp_resp_code)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*comp_resp = response->comp_resp;
+	*comp_resp_code = response->comp_resp_code;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_update_component_req(
+	uint8_t instance_id, uint16_t comp_classification,
+	uint16_t comp_identifier, uint8_t comp_classification_index,
+	uint32_t comp_comparison_stamp, uint32_t comp_image_size,
+	bitfield32_t update_option_flags, uint8_t comp_ver_str_type,
+	uint8_t comp_ver_str_len, const struct variable_field *comp_ver_str,
+	struct pldm_msg *msg, size_t payload_length)
+{
+	if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length !=
+	    sizeof(struct pldm_update_component_req) + comp_ver_str->length) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	if (!comp_image_size) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if ((comp_ver_str_len == 0) ||
+	    (comp_ver_str_len != comp_ver_str->length)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (!is_string_type_valid(comp_ver_str_type)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_REQUEST;
+	header.pldm_type = PLDM_FWUP;
+	header.command = PLDM_UPDATE_COMPONENT;
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc) {
+		return rc;
+	}
+
+	struct pldm_update_component_req *request =
+		(struct pldm_update_component_req *)msg->payload;
+
+	request->comp_classification = htole16(comp_classification);
+	request->comp_identifier = htole16(comp_identifier);
+	request->comp_classification_index = comp_classification_index;
+	request->comp_comparison_stamp = htole32(comp_comparison_stamp);
+	request->comp_image_size = htole32(comp_image_size);
+	request->update_option_flags.value = htole32(update_option_flags.value);
+	request->comp_ver_str_type = comp_ver_str_type;
+	request->comp_ver_str_len = comp_ver_str_len;
+
+	memcpy(msg->payload + sizeof(struct pldm_update_component_req),
+	       comp_ver_str->ptr, comp_ver_str->length);
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_update_component_resp(const struct pldm_msg *msg,
+				 size_t payload_length,
+				 uint8_t *completion_code,
+				 uint8_t *comp_compatibility_resp,
+				 uint8_t *comp_compatibility_resp_code,
+				 bitfield32_t *update_option_flags_enabled,
+				 uint16_t *time_before_req_fw_data)
+{
+	if (msg == NULL || completion_code == NULL ||
+	    comp_compatibility_resp == NULL ||
+	    comp_compatibility_resp_code == NULL ||
+	    update_option_flags_enabled == NULL ||
+	    time_before_req_fw_data == NULL || !payload_length) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*completion_code = msg->payload[0];
+	if (*completion_code != PLDM_SUCCESS) {
+		return PLDM_SUCCESS;
+	}
+
+	if (payload_length != sizeof(struct pldm_update_component_resp)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_update_component_resp *response =
+		(struct pldm_update_component_resp *)msg->payload;
+
+	if (!is_comp_compatibility_resp_valid(
+		    response->comp_compatibility_resp)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (!is_comp_compatibility_resp_code_valid(
+		    response->comp_compatibility_resp_code)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*comp_compatibility_resp = response->comp_compatibility_resp;
+	*comp_compatibility_resp_code = response->comp_compatibility_resp_code;
+	update_option_flags_enabled->value =
+		le32toh(response->update_option_flags_enabled.value);
+	*time_before_req_fw_data = le16toh(response->time_before_req_fw_data);
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_request_firmware_data_req(const struct pldm_msg *msg,
+				     size_t payload_length, uint32_t *offset,
+				     uint32_t *length)
+{
+	if (msg == NULL || offset == NULL || length == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (payload_length != sizeof(struct pldm_request_firmware_data_req)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+	struct pldm_request_firmware_data_req *request =
+		(struct pldm_request_firmware_data_req *)msg->payload;
+	*offset = le32toh(request->offset);
+	*length = le32toh(request->length);
+
+	if (*length < PLDM_FWUP_BASELINE_TRANSFER_SIZE) {
+		return PLDM_FWUP_INVALID_TRANSFER_LENGTH;
+	}
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_request_firmware_data_resp(uint8_t instance_id,
+				      uint8_t completion_code,
+				      struct pldm_msg *msg,
+				      size_t payload_length)
+{
+	if (msg == NULL || !payload_length) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_RESPONSE;
+	header.pldm_type = PLDM_FWUP;
+	header.command = PLDM_REQUEST_FIRMWARE_DATA;
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc) {
+		return rc;
+	}
+
+	msg->payload[0] = completion_code;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_transfer_complete_req(const struct pldm_msg *msg,
+				 size_t payload_length,
+				 uint8_t *transfer_result)
+{
+	if (msg == NULL || transfer_result == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != sizeof(*transfer_result)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	*transfer_result = msg->payload[0];
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_transfer_complete_resp(uint8_t instance_id, uint8_t completion_code,
+				  struct pldm_msg *msg, size_t payload_length)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != sizeof(completion_code)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_RESPONSE;
+	header.pldm_type = PLDM_FWUP;
+	header.command = PLDM_TRANSFER_COMPLETE;
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc) {
+		return rc;
+	}
+
+	msg->payload[0] = completion_code;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_verify_complete_req(const struct pldm_msg *msg,
+			       size_t payload_length, uint8_t *verify_result)
+{
+	if (msg == NULL || verify_result == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != sizeof(*verify_result)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	*verify_result = msg->payload[0];
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_verify_complete_resp(uint8_t instance_id, uint8_t completion_code,
+				struct pldm_msg *msg, size_t payload_length)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != sizeof(completion_code)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_RESPONSE;
+	header.pldm_type = PLDM_FWUP;
+	header.command = PLDM_VERIFY_COMPLETE;
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc) {
+		return rc;
+	}
+
+	msg->payload[0] = completion_code;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_apply_complete_req(const struct pldm_msg *msg, size_t payload_length,
+			      uint8_t *apply_result,
+			      bitfield16_t *comp_activation_methods_modification)
+{
+	if (msg == NULL || apply_result == NULL ||
+	    comp_activation_methods_modification == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != sizeof(struct pldm_apply_complete_req)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_apply_complete_req *request =
+		(struct pldm_apply_complete_req *)msg->payload;
+
+	*apply_result = request->apply_result;
+	comp_activation_methods_modification->value =
+		le16toh(request->comp_activation_methods_modification.value);
+
+	if ((*apply_result != PLDM_FWUP_APPLY_SUCCESS_WITH_ACTIVATION_METHOD) &&
+	    comp_activation_methods_modification->value) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_apply_complete_resp(uint8_t instance_id, uint8_t completion_code,
+			       struct pldm_msg *msg, size_t payload_length)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != sizeof(completion_code)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_RESPONSE;
+	header.pldm_type = PLDM_FWUP;
+	header.command = PLDM_APPLY_COMPLETE;
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc) {
+		return rc;
+	}
+
+	msg->payload[0] = completion_code;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_activate_firmware_req(uint8_t instance_id,
+				 bool8_t self_contained_activation_req,
+				 struct pldm_msg *msg, size_t payload_length)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != sizeof(struct pldm_activate_firmware_req)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	if (!is_self_contained_activation_req_valid(
+		    self_contained_activation_req)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_REQUEST;
+	header.pldm_type = PLDM_FWUP;
+	header.command = PLDM_ACTIVATE_FIRMWARE;
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc) {
+		return rc;
+	}
+
+	struct pldm_activate_firmware_req *request =
+		(struct pldm_activate_firmware_req *)msg->payload;
+
+	request->self_contained_activation_req = self_contained_activation_req;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_activate_firmware_resp(const struct pldm_msg *msg,
+				  size_t payload_length,
+				  uint8_t *completion_code,
+				  uint16_t *estimated_time_activation)
+{
+	if (msg == NULL || completion_code == NULL ||
+	    estimated_time_activation == NULL || !payload_length) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*completion_code = msg->payload[0];
+	if (*completion_code != PLDM_SUCCESS) {
+		return PLDM_SUCCESS;
+	}
+
+	if (payload_length != sizeof(struct pldm_activate_firmware_resp)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_activate_firmware_resp *response =
+		(struct pldm_activate_firmware_resp *)msg->payload;
+
+	*estimated_time_activation =
+		le16toh(response->estimated_time_activation);
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_status_req(uint8_t instance_id, struct pldm_msg *msg,
+			  size_t payload_length)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != PLDM_GET_STATUS_REQ_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_REQUEST;
+	header.pldm_type = PLDM_FWUP;
+	header.command = PLDM_GET_STATUS;
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc) {
+		return rc;
+	}
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_status_resp(const struct pldm_msg *msg, size_t payload_length,
+			   uint8_t *completion_code, uint8_t *current_state,
+			   uint8_t *previous_state, uint8_t *aux_state,
+			   uint8_t *aux_state_status, uint8_t *progress_percent,
+			   uint8_t *reason_code,
+			   bitfield32_t *update_option_flags_enabled)
+{
+	if (msg == NULL || completion_code == NULL || current_state == NULL ||
+	    previous_state == NULL || aux_state == NULL ||
+	    aux_state_status == NULL || progress_percent == NULL ||
+	    reason_code == NULL || update_option_flags_enabled == NULL ||
+	    !payload_length) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*completion_code = msg->payload[0];
+	if (*completion_code != PLDM_SUCCESS) {
+		return PLDM_SUCCESS;
+	}
+
+	if (payload_length != sizeof(struct pldm_get_status_resp)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+	struct pldm_get_status_resp *response =
+		(struct pldm_get_status_resp *)msg->payload;
+
+	if (!is_state_valid(response->current_state)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (!is_state_valid(response->previous_state)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (!is_aux_state_valid(response->aux_state)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (!is_aux_state_status_valid(response->aux_state_status)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (response->progress_percent > PLDM_FWUP_MAX_PROGRESS_PERCENT) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (!is_reason_code_valid(response->reason_code)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if ((response->current_state == PLDM_FD_STATE_IDLE) ||
+	    (response->current_state == PLDM_FD_STATE_LEARN_COMPONENTS) ||
+	    (response->current_state == PLDM_FD_STATE_READY_XFER)) {
+		if (response->aux_state !=
+		    PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER) {
+			return PLDM_ERROR_INVALID_DATA;
+		}
+	}
+
+	*current_state = response->current_state;
+	*previous_state = response->previous_state;
+	*aux_state = response->aux_state;
+	*aux_state_status = response->aux_state_status;
+	*progress_percent = response->progress_percent;
+	*reason_code = response->reason_code;
+	update_option_flags_enabled->value =
+		le32toh(response->update_option_flags_enabled.value);
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_cancel_update_component_req(uint8_t instance_id,
+				       struct pldm_msg *msg,
+				       size_t payload_length)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != PLDM_CANCEL_UPDATE_COMPONENT_REQ_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_REQUEST;
+	header.pldm_type = PLDM_FWUP;
+	header.command = PLDM_CANCEL_UPDATE_COMPONENT;
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc) {
+		return rc;
+	}
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_cancel_update_component_resp(const struct pldm_msg *msg,
+					size_t payload_length,
+					uint8_t *completion_code)
+{
+	if (msg == NULL || completion_code == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != sizeof(*completion_code)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	*completion_code = msg->payload[0];
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_cancel_update_req(uint8_t instance_id, struct pldm_msg *msg,
+			     size_t payload_length)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != PLDM_CANCEL_UPDATE_REQ_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_REQUEST;
+	header.pldm_type = PLDM_FWUP;
+	header.command = PLDM_CANCEL_UPDATE;
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc) {
+		return rc;
+	}
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_cancel_update_resp(const struct pldm_msg *msg, size_t payload_length,
+			      uint8_t *completion_code,
+			      bool8_t *non_functioning_component_indication,
+			      bitfield64_t *non_functioning_component_bitmap)
+{
+	if (msg == NULL || completion_code == NULL ||
+	    non_functioning_component_indication == NULL ||
+	    non_functioning_component_bitmap == NULL || !payload_length) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*completion_code = msg->payload[0];
+	if (*completion_code != PLDM_SUCCESS) {
+		return PLDM_SUCCESS;
+	}
+
+	if (payload_length != sizeof(struct pldm_cancel_update_resp)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+	struct pldm_cancel_update_resp *response =
+		(struct pldm_cancel_update_resp *)msg->payload;
+
+	if (!is_non_functioning_component_indication_valid(
+		    response->non_functioning_component_indication)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*non_functioning_component_indication =
+		response->non_functioning_component_indication;
+
+	if (*non_functioning_component_indication) {
+		non_functioning_component_bitmap->value =
+			le64toh(response->non_functioning_component_bitmap);
+	}
+
+	return PLDM_SUCCESS;
+}
diff --git a/src/dsp/fru.c b/src/dsp/fru.c
new file mode 100644
index 0000000..fd6120e
--- /dev/null
+++ b/src/dsp/fru.c
@@ -0,0 +1,576 @@
+/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
+#include <libpldm/base.h>
+#include <libpldm/fru.h>
+#include <libpldm/utils.h>
+
+#include <assert.h>
+#include <endian.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+LIBPLDM_ABI_STABLE
+int encode_get_fru_record_table_metadata_req(uint8_t instance_id,
+					     struct pldm_msg *msg,
+					     size_t payload_length)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != PLDM_GET_FRU_RECORD_TABLE_METADATA_REQ_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_REQUEST;
+	header.pldm_type = PLDM_FRU;
+	header.command = PLDM_GET_FRU_RECORD_TABLE_METADATA;
+
+	return pack_pldm_header(&header, &(msg->hdr));
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_fru_record_table_metadata_resp(
+	const struct pldm_msg *msg, size_t payload_length,
+	uint8_t *completion_code, uint8_t *fru_data_major_version,
+	uint8_t *fru_data_minor_version, uint32_t *fru_table_maximum_size,
+	uint32_t *fru_table_length, uint16_t *total_record_set_identifiers,
+	uint16_t *total_table_records, uint32_t *checksum)
+{
+	if (msg == NULL || completion_code == NULL ||
+	    fru_data_major_version == NULL || fru_data_minor_version == NULL ||
+	    fru_table_maximum_size == NULL || fru_table_length == NULL ||
+	    total_record_set_identifiers == NULL ||
+	    total_table_records == NULL || checksum == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*completion_code = msg->payload[0];
+	if (PLDM_SUCCESS != *completion_code) {
+		return PLDM_SUCCESS;
+	}
+
+	if (payload_length != PLDM_GET_FRU_RECORD_TABLE_METADATA_RESP_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_get_fru_record_table_metadata_resp *response =
+		(struct pldm_get_fru_record_table_metadata_resp *)msg->payload;
+
+	*fru_data_major_version = response->fru_data_major_version;
+	*fru_data_minor_version = response->fru_data_minor_version;
+	*fru_table_maximum_size = le32toh(response->fru_table_maximum_size);
+	*fru_table_length = le32toh(response->fru_table_length);
+	*total_record_set_identifiers =
+		le16toh(response->total_record_set_identifiers);
+	*total_table_records = le16toh(response->total_table_records);
+	*checksum = le32toh(response->checksum);
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_fru_record_table_metadata_resp(
+	uint8_t instance_id, uint8_t completion_code,
+	uint8_t fru_data_major_version, uint8_t fru_data_minor_version,
+	uint32_t fru_table_maximum_size, uint32_t fru_table_length,
+	uint16_t total_record_set_identifiers, uint16_t total_table_records,
+	uint32_t checksum, struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.msg_type = PLDM_RESPONSE;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_FRU;
+	header.command = PLDM_GET_FRU_RECORD_TABLE_METADATA;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (PLDM_SUCCESS != rc) {
+		return rc;
+	}
+
+	struct pldm_get_fru_record_table_metadata_resp *response =
+		(struct pldm_get_fru_record_table_metadata_resp *)msg->payload;
+	response->completion_code = completion_code;
+	if (response->completion_code == PLDM_SUCCESS) {
+		response->fru_data_major_version = fru_data_major_version;
+		response->fru_data_minor_version = fru_data_minor_version;
+		response->fru_table_maximum_size =
+			htole32(fru_table_maximum_size);
+		response->fru_table_length = htole32(fru_table_length);
+		response->total_record_set_identifiers =
+			htole16(total_record_set_identifiers);
+		response->total_table_records = htole16(total_table_records);
+		response->checksum = htole32(checksum);
+	}
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_fru_record_table_req(const struct pldm_msg *msg,
+				    size_t payload_length,
+				    uint32_t *data_transfer_handle,
+				    uint8_t *transfer_operation_flag)
+{
+	if (msg == NULL || data_transfer_handle == NULL ||
+	    transfer_operation_flag == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != PLDM_GET_FRU_RECORD_TABLE_REQ_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_get_fru_record_table_req *req =
+		(struct pldm_get_fru_record_table_req *)msg->payload;
+
+	*data_transfer_handle = le32toh(req->data_transfer_handle);
+	*transfer_operation_flag = req->transfer_operation_flag;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_fru_record_table_resp(uint8_t instance_id,
+				     uint8_t completion_code,
+				     uint32_t next_data_transfer_handle,
+				     uint8_t transfer_flag,
+				     struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.msg_type = PLDM_RESPONSE;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_FRU;
+	header.command = PLDM_GET_FRU_RECORD_TABLE;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc > PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_get_fru_record_table_resp *resp =
+		(struct pldm_get_fru_record_table_resp *)msg->payload;
+
+	resp->completion_code = completion_code;
+
+	if (resp->completion_code == PLDM_SUCCESS) {
+		resp->next_data_transfer_handle =
+			htole32(next_data_transfer_handle);
+		resp->transfer_flag = transfer_flag;
+	}
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_fru_record(uint8_t *fru_table, size_t total_size, size_t *curr_size,
+		      uint16_t record_set_id, uint8_t record_type,
+		      uint8_t num_frus, uint8_t encoding, uint8_t *tlvs,
+		      size_t tlvs_size)
+{
+	size_t record_hdr_size = sizeof(struct pldm_fru_record_data_format) -
+				 sizeof(struct pldm_fru_record_tlv);
+
+	if (fru_table == NULL || curr_size == NULL || !tlvs_size) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if ((*curr_size + record_hdr_size + tlvs_size) != total_size) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_fru_record_data_format *record =
+		(struct pldm_fru_record_data_format *)(fru_table + *curr_size);
+	record->record_set_id = htole16(record_set_id);
+	record->record_type = record_type;
+	record->num_fru_fields = num_frus;
+	record->encoding_type = encoding;
+	*curr_size += record_hdr_size;
+
+	if (tlvs) {
+		memcpy(fru_table + *curr_size, tlvs, tlvs_size);
+		*curr_size += tlvs_size;
+	}
+
+	return PLDM_SUCCESS;
+}
+
+static bool is_table_end(const struct pldm_fru_record_data_format *p,
+			 const void *table, size_t table_size)
+{
+	return p >=
+	       (const struct pldm_fru_record_data_format *)((uint8_t *)table +
+							    table_size);
+}
+
+LIBPLDM_ABI_STABLE
+int get_fru_record_by_option_check(const uint8_t *table, size_t table_size,
+				   uint8_t *record_table, size_t *record_size,
+				   uint16_t rsi, uint8_t rt, uint8_t ft)
+{
+	const struct pldm_fru_record_data_format *record_data_src =
+		(const struct pldm_fru_record_data_format *)table;
+	struct pldm_fru_record_data_format *record_data_dest;
+	int count = 0;
+
+	const struct pldm_fru_record_tlv *tlv;
+	size_t len;
+	uint8_t *pos = record_table;
+
+	while (!is_table_end(record_data_src, table, table_size)) {
+		if ((record_data_src->record_set_id != htole16(rsi) &&
+		     rsi != 0) ||
+		    (record_data_src->record_type != rt && rt != 0)) {
+			tlv = record_data_src->tlvs;
+			for (int i = 0; i < record_data_src->num_fru_fields;
+			     i++) {
+				len = sizeof(*tlv) - 1 + tlv->length;
+				tlv = (const struct pldm_fru_record_tlv
+					       *)((char *)tlv + len);
+			}
+			record_data_src =
+				(const struct pldm_fru_record_data_format
+					 *)(tlv);
+			continue;
+		}
+
+		len = sizeof(struct pldm_fru_record_data_format) -
+		      sizeof(struct pldm_fru_record_tlv);
+
+		if (pos - record_table + len >= *record_size) {
+			return PLDM_ERROR_INVALID_LENGTH;
+		}
+		memcpy(pos, record_data_src, len);
+
+		record_data_dest = (struct pldm_fru_record_data_format *)pos;
+		pos += len;
+
+		tlv = record_data_src->tlvs;
+		count = 0;
+		for (int i = 0; i < record_data_src->num_fru_fields; i++) {
+			len = sizeof(*tlv) - 1 + tlv->length;
+			if (tlv->type == ft || ft == 0) {
+				if (pos - record_table + len >= *record_size) {
+					return PLDM_ERROR_INVALID_LENGTH;
+				}
+				memcpy(pos, tlv, len);
+				pos += len;
+				count++;
+			}
+			tlv = (const struct pldm_fru_record_tlv *)((char *)tlv +
+								   len);
+		}
+		record_data_dest->num_fru_fields = count;
+		record_data_src =
+			(const struct pldm_fru_record_data_format *)(tlv);
+	}
+
+	*record_size = pos - record_table;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_fru_record_by_option_req(
+	uint8_t instance_id, uint32_t data_transfer_handle,
+	uint16_t fru_table_handle, uint16_t record_set_identifier,
+	uint8_t record_type, uint8_t field_type, uint8_t transfer_op_flag,
+	struct pldm_msg *msg, size_t payload_length)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length !=
+	    sizeof(struct pldm_get_fru_record_by_option_req)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_REQUEST;
+	header.pldm_type = PLDM_FRU;
+	header.command = PLDM_GET_FRU_RECORD_BY_OPTION;
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_get_fru_record_by_option_req *req =
+		(struct pldm_get_fru_record_by_option_req *)msg->payload;
+
+	req->data_transfer_handle = htole32(data_transfer_handle);
+	req->fru_table_handle = htole16(fru_table_handle);
+	req->record_set_identifier = htole16(record_set_identifier);
+	req->record_type = record_type;
+	req->field_type = field_type;
+	req->transfer_op_flag = transfer_op_flag;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_fru_record_by_option_req(
+	const struct pldm_msg *msg, size_t payload_length,
+	uint32_t *data_transfer_handle, uint16_t *fru_table_handle,
+	uint16_t *record_set_identifier, uint8_t *record_type,
+	uint8_t *field_type, uint8_t *transfer_op_flag)
+{
+	if (msg == NULL || data_transfer_handle == NULL ||
+	    fru_table_handle == NULL || record_set_identifier == NULL ||
+	    record_type == NULL || field_type == NULL ||
+	    transfer_op_flag == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length !=
+	    sizeof(struct pldm_get_fru_record_by_option_req)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_get_fru_record_by_option_req *req =
+		(struct pldm_get_fru_record_by_option_req *)msg->payload;
+
+	*data_transfer_handle = le32toh(req->data_transfer_handle);
+	*fru_table_handle = le16toh(req->fru_table_handle);
+	*record_set_identifier = le16toh(req->record_set_identifier);
+	*record_type = req->record_type;
+	*field_type = req->field_type;
+	*transfer_op_flag = req->transfer_op_flag;
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_fru_record_by_option_resp(uint8_t instance_id,
+					 uint8_t completion_code,
+					 uint32_t next_data_transfer_handle,
+					 uint8_t transfer_flag,
+					 const void *fru_structure_data,
+					 size_t data_size, struct pldm_msg *msg,
+					 size_t payload_length)
+{
+	if (msg == NULL || fru_structure_data == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length !=
+	    PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES + data_size) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_RESPONSE;
+	header.pldm_type = PLDM_FRU;
+	header.command = PLDM_GET_FRU_RECORD_BY_OPTION;
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_get_fru_record_by_option_resp *resp =
+		(struct pldm_get_fru_record_by_option_resp *)msg->payload;
+
+	resp->completion_code = completion_code;
+	resp->next_data_transfer_handle = htole32(next_data_transfer_handle);
+	resp->transfer_flag = transfer_flag;
+
+	if (completion_code == PLDM_SUCCESS) {
+		memcpy(resp->fru_structure_data, fru_structure_data, data_size);
+	}
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_fru_record_by_option_resp(
+	const struct pldm_msg *msg, size_t payload_length,
+	uint8_t *completion_code, uint32_t *next_transfer_handle,
+	uint8_t *transfer_flag, struct variable_field *fru_structure_data)
+{
+	if (msg == NULL || completion_code == NULL ||
+	    next_transfer_handle == NULL || transfer_flag == NULL ||
+	    fru_structure_data == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*completion_code = msg->payload[0];
+	if (PLDM_SUCCESS != *completion_code) {
+		return PLDM_SUCCESS;
+	}
+
+	if (payload_length < PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_get_fru_record_by_option_resp *resp =
+		(struct pldm_get_fru_record_by_option_resp *)msg->payload;
+
+	*next_transfer_handle = le32toh(resp->next_data_transfer_handle);
+	*transfer_flag = resp->transfer_flag;
+	fru_structure_data->ptr = resp->fru_structure_data;
+	fru_structure_data->length =
+		payload_length - PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_fru_record_table_req(uint8_t instance_id,
+				    uint32_t data_transfer_handle,
+				    uint8_t transfer_operation_flag,
+				    struct pldm_msg *msg, size_t payload_length)
+
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (payload_length != sizeof(struct pldm_get_fru_record_table_req)) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.msg_type = PLDM_REQUEST;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_FRU;
+	header.command = PLDM_GET_FRU_RECORD_TABLE;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_get_fru_record_table_req *req =
+		(struct pldm_get_fru_record_table_req *)msg->payload;
+	req->data_transfer_handle = htole32(data_transfer_handle);
+	req->transfer_operation_flag = transfer_operation_flag;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_fru_record_table_resp_safe(
+	const struct pldm_msg *msg, size_t payload_length,
+	uint8_t *completion_code, uint32_t *next_data_transfer_handle,
+	uint8_t *transfer_flag, uint8_t *fru_record_table_data,
+	size_t *fru_record_table_length, size_t max_fru_record_table_length)
+{
+	if (msg == NULL || completion_code == NULL ||
+	    next_data_transfer_handle == NULL || transfer_flag == NULL ||
+	    fru_record_table_data == NULL || fru_record_table_length == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*completion_code = msg->payload[0];
+	if (PLDM_SUCCESS != *completion_code) {
+		return PLDM_SUCCESS;
+	}
+	if (payload_length <= PLDM_GET_FRU_RECORD_TABLE_MIN_RESP_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_get_fru_record_table_resp *resp =
+		(struct pldm_get_fru_record_table_resp *)msg->payload;
+
+	*next_data_transfer_handle = le32toh(resp->next_data_transfer_handle);
+	*transfer_flag = resp->transfer_flag;
+
+	*fru_record_table_length =
+		payload_length - PLDM_GET_FRU_RECORD_TABLE_MIN_RESP_BYTES;
+
+	if (*fru_record_table_length > max_fru_record_table_length) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	memcpy(fru_record_table_data, resp->fru_record_table_data,
+	       *fru_record_table_length);
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_fru_record_table_resp(const struct pldm_msg *msg,
+				     size_t payload_length,
+				     uint8_t *completion_code,
+				     uint32_t *next_data_transfer_handle,
+				     uint8_t *transfer_flag,
+				     uint8_t *fru_record_table_data,
+				     size_t *fru_record_table_length)
+{
+	return decode_get_fru_record_table_resp_safe(
+		msg, payload_length, completion_code, next_data_transfer_handle,
+		transfer_flag, fru_record_table_data, fru_record_table_length,
+		(size_t)-1);
+}
+
+LIBPLDM_ABI_STABLE
+int decode_set_fru_record_table_req(const struct pldm_msg *msg,
+				    size_t payload_length,
+				    uint32_t *data_transfer_handle,
+				    uint8_t *transfer_flag,
+				    struct variable_field *fru_table_data)
+
+{
+	if (msg == NULL || data_transfer_handle == NULL ||
+	    transfer_flag == NULL || fru_table_data == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length <= PLDM_SET_FRU_RECORD_TABLE_MIN_REQ_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_set_fru_record_table_req *req =
+		(struct pldm_set_fru_record_table_req *)msg->payload;
+
+	*data_transfer_handle = le32toh(req->data_transfer_handle);
+	*transfer_flag = req->transfer_flag;
+	fru_table_data->length =
+		payload_length - PLDM_SET_FRU_RECORD_TABLE_MIN_REQ_BYTES;
+	fru_table_data->ptr = req->fru_record_table_data;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_set_fru_record_table_resp(uint8_t instance_id,
+				     uint8_t completion_code,
+				     uint32_t next_data_transfer_handle,
+				     size_t payload_length,
+				     struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (payload_length != PLDM_SET_FRU_RECORD_TABLE_RESP_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_RESPONSE;
+	header.pldm_type = PLDM_FRU;
+	header.command = PLDM_SET_FRU_RECORD_TABLE;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (PLDM_SUCCESS != rc) {
+		return rc;
+	}
+
+	struct pldm_set_fru_record_table_resp *response =
+		(struct pldm_set_fru_record_table_resp *)msg->payload;
+	response->completion_code = completion_code;
+	response->next_data_transfer_handle =
+		htole32(next_data_transfer_handle);
+
+	return PLDM_SUCCESS;
+}
diff --git a/src/dsp/meson.build b/src/dsp/meson.build
new file mode 100644
index 0000000..39f4db8
--- /dev/null
+++ b/src/dsp/meson.build
@@ -0,0 +1,9 @@
+libpldm_sources += files(
+  'base.c',
+  'bios.c',
+  'bios_table.c',
+  'firmware_update.c',
+  'fru.c',
+  'pdr.c',
+  'platform.c',
+)
diff --git a/src/dsp/pdr.c b/src/dsp/pdr.c
new file mode 100644
index 0000000..09e87be
--- /dev/null
+++ b/src/dsp/pdr.c
@@ -0,0 +1,1662 @@
+/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
+#include "msgbuf.h"
+#include <libpldm/pdr.h>
+#include <libpldm/platform.h>
+
+#include <assert.h>
+#include <endian.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#define PDR_ENTITY_ASSOCIATION_MIN_SIZE                                        \
+	(sizeof(struct pldm_pdr_hdr) +                                         \
+	 sizeof(struct pldm_pdr_entity_association))
+
+typedef struct pldm_pdr_record {
+	uint32_t record_handle;
+	uint32_t size;
+	uint8_t *data;
+	struct pldm_pdr_record *next;
+	bool is_remote;
+	uint16_t terminus_handle;
+} pldm_pdr_record;
+
+typedef struct pldm_pdr {
+	uint32_t record_count;
+	uint32_t size;
+	pldm_pdr_record *first;
+	pldm_pdr_record *last;
+} pldm_pdr;
+
+static inline uint32_t get_next_record_handle(const pldm_pdr *repo,
+					      const pldm_pdr_record *record)
+{
+	assert(repo != NULL);
+	assert(record != NULL);
+
+	if (record == repo->last) {
+		return 0;
+	}
+	return record->next->record_handle;
+}
+
+LIBPLDM_ABI_STABLE
+int pldm_pdr_add_check(pldm_pdr *repo, const uint8_t *data, uint32_t size,
+		       bool is_remote, uint16_t terminus_handle,
+		       uint32_t *record_handle)
+{
+	uint32_t curr;
+
+	if (!repo || !data || !size) {
+		return -EINVAL;
+	}
+
+	if (record_handle && *record_handle) {
+		curr = *record_handle;
+	} else if (repo->last) {
+		curr = repo->last->record_handle;
+		if (curr == UINT32_MAX) {
+			return -EOVERFLOW;
+		}
+		curr += 1;
+	} else {
+		curr = 1;
+	}
+
+	pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
+	if (!record) {
+		return -ENOMEM;
+	}
+
+	if (data) {
+		record->data = malloc(size);
+		if (!record->data) {
+			free(record);
+			return -ENOMEM;
+		}
+		memcpy(record->data, data, size);
+	}
+
+	record->size = size;
+	record->is_remote = is_remote;
+	record->terminus_handle = terminus_handle;
+	record->record_handle = curr;
+
+	if (record_handle && !*record_handle && data) {
+		/* If record handle is 0, that is an indication for this API to
+		 * compute a new handle. For that reason, the computed handle
+		 * needs to be populated in the PDR header. For a case where the
+		 * caller supplied the record handle, it would exist in the
+		 * header already.
+		 */
+		struct pldm_pdr_hdr *hdr = (void *)record->data;
+		hdr->record_handle = htole32(record->record_handle);
+	}
+
+	record->next = NULL;
+
+	assert(!repo->first == !repo->last);
+	if (repo->first == NULL) {
+		repo->first = record;
+		repo->last = record;
+	} else {
+		repo->last->next = record;
+		repo->last = record;
+	}
+
+	repo->size += record->size;
+	++repo->record_count;
+
+	if (record_handle) {
+		*record_handle = record->record_handle;
+	}
+
+	return 0;
+}
+
+LIBPLDM_ABI_STABLE
+pldm_pdr *pldm_pdr_init(void)
+{
+	pldm_pdr *repo = malloc(sizeof(pldm_pdr));
+	if (!repo) {
+		return NULL;
+	}
+	repo->record_count = 0;
+	repo->size = 0;
+	repo->first = NULL;
+	repo->last = NULL;
+
+	return repo;
+}
+
+LIBPLDM_ABI_STABLE
+void pldm_pdr_destroy(pldm_pdr *repo)
+{
+	if (!repo) {
+		return;
+	}
+
+	pldm_pdr_record *record = repo->first;
+	while (record != NULL) {
+		pldm_pdr_record *next = record->next;
+		if (record->data) {
+			free(record->data);
+			record->data = NULL;
+		}
+		free(record);
+		record = next;
+	}
+	free(repo);
+}
+
+LIBPLDM_ABI_STABLE
+const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
+					    uint32_t record_handle,
+					    uint8_t **data, uint32_t *size,
+					    uint32_t *next_record_handle)
+{
+	if (!repo || !data || !size || !next_record_handle) {
+		return NULL;
+	}
+
+	if (!record_handle && (repo->first != NULL)) {
+		record_handle = repo->first->record_handle;
+	}
+
+	pldm_pdr_record *record = repo->first;
+	while (record != NULL) {
+		if (record->record_handle == record_handle) {
+			*size = record->size;
+			*data = record->data;
+			*next_record_handle =
+				get_next_record_handle(repo, record);
+			return record;
+		}
+		record = record->next;
+	}
+
+	*size = 0;
+	*next_record_handle = 0;
+	return NULL;
+}
+
+LIBPLDM_ABI_STABLE
+const pldm_pdr_record *
+pldm_pdr_get_next_record(const pldm_pdr *repo,
+			 const pldm_pdr_record *curr_record, uint8_t **data,
+			 uint32_t *size, uint32_t *next_record_handle)
+{
+	if (!repo || !curr_record || !data || !size || !next_record_handle) {
+		return NULL;
+	}
+
+	if (curr_record == repo->last) {
+		*data = NULL;
+		*size = 0;
+		*next_record_handle = get_next_record_handle(repo, curr_record);
+		return NULL;
+	}
+
+	*next_record_handle = get_next_record_handle(repo, curr_record->next);
+	*data = curr_record->next->data;
+	*size = curr_record->next->size;
+	return curr_record->next;
+}
+
+LIBPLDM_ABI_STABLE
+const pldm_pdr_record *
+pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
+			     const pldm_pdr_record *curr_record, uint8_t **data,
+			     uint32_t *size)
+{
+	if (!repo) {
+		return NULL;
+	}
+
+	pldm_pdr_record *record = repo->first;
+	if (curr_record != NULL) {
+		record = curr_record->next;
+	}
+	while (record != NULL) {
+		struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
+		if (hdr->type == pdr_type) {
+			if (data && size) {
+				*size = record->size;
+				*data = record->data;
+			}
+			return record;
+		}
+		record = record->next;
+	}
+
+	if (size) {
+		*size = 0;
+	}
+	return NULL;
+}
+
+LIBPLDM_ABI_STABLE
+uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
+{
+	assert(repo != NULL);
+
+	return repo->record_count;
+}
+
+LIBPLDM_ABI_STABLE
+uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
+{
+	assert(repo != NULL);
+
+	return repo->size;
+}
+
+LIBPLDM_ABI_STABLE
+uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo
+				    __attribute__((unused)),
+				    const pldm_pdr_record *record)
+{
+	assert(repo != NULL);
+	assert(record != NULL);
+
+	return record->record_handle;
+}
+
+LIBPLDM_ABI_STABLE
+bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
+{
+	assert(record != NULL);
+
+	return record->is_remote;
+}
+
+LIBPLDM_ABI_STABLE
+int pldm_pdr_add_fru_record_set_check(pldm_pdr *repo, uint16_t terminus_handle,
+				      uint16_t fru_rsi, uint16_t entity_type,
+				      uint16_t entity_instance_num,
+				      uint16_t container_id,
+				      uint32_t *bmc_record_handle)
+{
+	if (!repo || !bmc_record_handle) {
+		return -EINVAL;
+	}
+
+	uint32_t size = sizeof(struct pldm_pdr_hdr) +
+			sizeof(struct pldm_pdr_fru_record_set);
+	uint8_t data[size];
+
+	struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
+	hdr->version = 1;
+	hdr->record_handle = *bmc_record_handle;
+	hdr->type = PLDM_PDR_FRU_RECORD_SET;
+	hdr->record_change_num = 0;
+	hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
+	struct pldm_pdr_fru_record_set *fru =
+		(struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
+						   sizeof(struct pldm_pdr_hdr));
+	fru->terminus_handle = htole16(terminus_handle);
+	fru->fru_rsi = htole16(fru_rsi);
+	fru->entity_type = htole16(entity_type);
+	fru->entity_instance_num = htole16(entity_instance_num);
+	fru->container_id = htole16(container_id);
+
+	return pldm_pdr_add_check(repo, data, size, false, terminus_handle,
+				  bmc_record_handle);
+}
+
+LIBPLDM_ABI_STABLE
+const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
+	const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
+	uint16_t *entity_type, uint16_t *entity_instance_num,
+	uint16_t *container_id)
+{
+	if (!repo || !terminus_handle || !entity_type || !entity_instance_num ||
+	    !container_id) {
+		return NULL;
+	}
+
+	uint8_t *data = NULL;
+	uint32_t size = 0;
+	const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
+		repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
+	while (curr_record != NULL) {
+		struct pldm_pdr_fru_record_set *fru =
+			(struct pldm_pdr_fru_record_set
+				 *)(data + sizeof(struct pldm_pdr_hdr));
+		if (fru->fru_rsi == htole16(fru_rsi)) {
+			*terminus_handle = le16toh(fru->terminus_handle);
+			*entity_type = le16toh(fru->entity_type);
+			*entity_instance_num =
+				le16toh(fru->entity_instance_num);
+			*container_id = le16toh(fru->container_id);
+			return curr_record;
+		}
+		data = NULL;
+		curr_record = pldm_pdr_find_record_by_type(
+			repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
+			&size);
+	}
+
+	*terminus_handle = 0;
+	*entity_type = 0;
+	*entity_instance_num = 0;
+	*container_id = 0;
+
+	return NULL;
+}
+
+LIBPLDM_ABI_STABLE
+/* NOLINTNEXTLINE(readability-identifier-naming) */
+void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
+			    uint8_t tid, uint8_t tl_eid, bool valid_bit)
+{
+	uint8_t *out_data = NULL;
+	uint32_t size = 0;
+	const pldm_pdr_record *record;
+	record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
+					      NULL, &out_data, &size);
+
+	do {
+		if (record != NULL) {
+			struct pldm_terminus_locator_pdr *pdr =
+				(struct pldm_terminus_locator_pdr *)out_data;
+			struct pldm_terminus_locator_type_mctp_eid *value =
+				(struct pldm_terminus_locator_type_mctp_eid *)
+					pdr->terminus_locator_value;
+			if (pdr->terminus_handle == terminus_handle &&
+			    pdr->tid == tid && value->eid == tl_eid) {
+				pdr->validity = valid_bit;
+				break;
+			}
+		}
+		record = pldm_pdr_find_record_by_type(repo,
+						      PLDM_TERMINUS_LOCATOR_PDR,
+						      record, &out_data, &size);
+	} while (record);
+}
+
+static bool pldm_record_handle_in_range(uint32_t record_handle,
+					uint32_t first_record_handle,
+					uint32_t last_record_handle)
+{
+	return record_handle >= first_record_handle &&
+	       record_handle <= last_record_handle;
+}
+
+LIBPLDM_ABI_TESTING
+int pldm_pdr_find_child_container_id_index_range_exclude(
+	const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
+	uint8_t child_index, uint32_t range_exclude_start_handle,
+	uint32_t range_exclude_end_handle, uint16_t *container_id)
+{
+	pldm_pdr_record *record;
+	if (!repo) {
+		return -EINVAL;
+	}
+
+	for (record = repo->first; record; record = record->next) {
+		bool is_container_entity_instance_number;
+		struct pldm_pdr_entity_association *pdr;
+		bool is_container_entity_type;
+		struct pldm_entity *child;
+		struct pldm_pdr_hdr *hdr;
+		bool in_range;
+
+		// pldm_pdr_add() takes only uint8_t* data as an argument.
+		// The expectation here is the pldm_pdr_hdr is the first field of the record data
+		hdr = (struct pldm_pdr_hdr *)record->data;
+		if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
+			continue;
+		}
+		in_range = pldm_record_handle_in_range(
+			record->record_handle, range_exclude_start_handle,
+			range_exclude_end_handle);
+		if (in_range) {
+			continue;
+		}
+
+		// this cast is valid with respect to alignment because
+		// struct pldm_pdr_hdr is declared with __attribute__((packed))
+		pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
+		if (child_index >= pdr->num_children) {
+			continue;
+		}
+
+		child = (&pdr->children[child_index]);
+		is_container_entity_type = pdr->container.entity_type ==
+					   entity_type;
+		is_container_entity_instance_number =
+			pdr->container.entity_instance_num == entity_instance;
+		if (is_container_entity_type &&
+		    is_container_entity_instance_number) {
+			*container_id = le16toh(child->entity_container_id);
+			return 0;
+		}
+	}
+	return -ENOKEY;
+}
+
+typedef struct pldm_entity_association_tree {
+	pldm_entity_node *root;
+	uint16_t last_used_container_id;
+} pldm_entity_association_tree;
+
+typedef struct pldm_entity_node {
+	pldm_entity entity;
+	pldm_entity parent;
+	uint16_t remote_container_id;
+	pldm_entity_node *first_child;
+	pldm_entity_node *next_sibling;
+	uint8_t association_type;
+} pldm_entity_node;
+
+static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
+{
+	assert(tree != NULL);
+	assert(tree->last_used_container_id != UINT16_MAX);
+
+	return ++tree->last_used_container_id;
+}
+
+LIBPLDM_ABI_STABLE
+pldm_entity pldm_entity_extract(pldm_entity_node *node)
+{
+	assert(node != NULL);
+
+	return node->entity;
+}
+
+LIBPLDM_ABI_STABLE
+uint16_t
+pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity)
+{
+	assert(entity != NULL);
+
+	return entity->remote_container_id;
+}
+
+LIBPLDM_ABI_STABLE
+pldm_entity_association_tree *pldm_entity_association_tree_init(void)
+{
+	pldm_entity_association_tree *tree =
+		malloc(sizeof(pldm_entity_association_tree));
+	if (!tree) {
+		return NULL;
+	}
+	tree->root = NULL;
+	tree->last_used_container_id = 0;
+
+	return tree;
+}
+
+static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
+					   uint16_t entity_type)
+{
+	assert(start != NULL);
+
+	/* Insert after the the last node that matches the input entity type, or
+	 * at the end if no such match occurrs
+	 */
+	while (start->next_sibling != NULL) {
+		uint16_t this_type = start->entity.entity_type;
+		pldm_entity_node *next = start->next_sibling;
+		if (this_type == entity_type &&
+		    (this_type != next->entity.entity_type)) {
+			break;
+		}
+		start = start->next_sibling;
+	}
+
+	return start;
+}
+
+LIBPLDM_ABI_STABLE
+pldm_entity_node *pldm_entity_association_tree_add(
+	pldm_entity_association_tree *tree, pldm_entity *entity,
+	uint16_t entity_instance_number, pldm_entity_node *parent,
+	uint8_t association_type)
+{
+	return pldm_entity_association_tree_add_entity(tree, entity,
+						       entity_instance_number,
+						       parent, association_type,
+						       false, true, 0xffff);
+}
+
+LIBPLDM_ABI_STABLE
+pldm_entity_node *pldm_entity_association_tree_add_entity(
+	pldm_entity_association_tree *tree, pldm_entity *entity,
+	uint16_t entity_instance_number, pldm_entity_node *parent,
+	uint8_t association_type, bool is_remote, bool is_update_container_id,
+	uint16_t container_id)
+{
+	if ((!tree) || (!entity)) {
+		return NULL;
+	}
+
+	if (entity_instance_number != 0xffff && parent != NULL) {
+		pldm_entity node;
+		node.entity_type = entity->entity_type;
+		node.entity_instance_num = entity_instance_number;
+		if (pldm_is_current_parent_child(parent, &node)) {
+			return NULL;
+		}
+	}
+	if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
+	    association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
+		return NULL;
+	}
+	pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
+	if (!node) {
+		return NULL;
+	}
+	node->first_child = NULL;
+	node->next_sibling = NULL;
+	node->parent.entity_type = 0;
+	node->parent.entity_instance_num = 0;
+	node->parent.entity_container_id = 0;
+	node->entity.entity_type = entity->entity_type;
+	node->entity.entity_instance_num =
+		entity_instance_number != 0xffff ? entity_instance_number : 1;
+	node->association_type = association_type;
+	node->remote_container_id = 0;
+	if (tree->root == NULL) {
+		if (parent != NULL) {
+			free(node);
+			return NULL;
+		}
+		tree->root = node;
+		/* container_id 0 here indicates this is the top-most entry */
+		node->entity.entity_container_id = 0;
+		node->remote_container_id = node->entity.entity_container_id;
+	} else if (parent != NULL && parent->first_child == NULL) {
+		/* Ensure next_container_id() will yield a valid ID */
+		if (tree->last_used_container_id == UINT16_MAX) {
+			free(node);
+			return NULL;
+		}
+
+		parent->first_child = node;
+		node->parent = parent->entity;
+
+		if (is_remote) {
+			node->remote_container_id = entity->entity_container_id;
+		}
+		if (is_update_container_id) {
+			if (container_id != 0xffff) {
+				node->entity.entity_container_id = container_id;
+			} else {
+				node->entity.entity_container_id =
+					next_container_id(tree);
+			}
+		} else {
+			node->entity.entity_container_id =
+				entity->entity_container_id;
+		}
+
+		if (!is_remote) {
+			node->remote_container_id =
+				node->entity.entity_container_id;
+		}
+	} else {
+		pldm_entity_node *start = parent == NULL ? tree->root :
+							   parent->first_child;
+		pldm_entity_node *prev =
+			find_insertion_at(start, entity->entity_type);
+		if (!prev) {
+			free(node);
+			return NULL;
+		}
+		pldm_entity_node *next = prev->next_sibling;
+		if (prev->entity.entity_type == entity->entity_type) {
+			if (prev->entity.entity_instance_num == UINT16_MAX) {
+				free(node);
+				return NULL;
+			}
+			node->entity.entity_instance_num =
+				entity_instance_number != 0xffff ?
+					entity_instance_number :
+					prev->entity.entity_instance_num + 1;
+		}
+		prev->next_sibling = node;
+		node->parent = prev->parent;
+		node->next_sibling = next;
+		node->entity.entity_container_id =
+			prev->entity.entity_container_id;
+		node->remote_container_id = entity->entity_container_id;
+	}
+	entity->entity_instance_num = node->entity.entity_instance_num;
+	if (is_update_container_id) {
+		entity->entity_container_id = node->entity.entity_container_id;
+	}
+	return node;
+}
+
+static void get_num_nodes(pldm_entity_node *node, size_t *num)
+{
+	if (node == NULL) {
+		return;
+	}
+
+	++(*num);
+	get_num_nodes(node->next_sibling, num);
+	get_num_nodes(node->first_child, num);
+}
+
+static void entity_association_tree_visit(pldm_entity_node *node,
+					  pldm_entity *entities, size_t *index)
+{
+	if (node == NULL) {
+		return;
+	}
+
+	pldm_entity *entity = &entities[*index];
+	++(*index);
+	entity->entity_type = node->entity.entity_type;
+	entity->entity_instance_num = node->entity.entity_instance_num;
+	entity->entity_container_id = node->entity.entity_container_id;
+
+	entity_association_tree_visit(node->next_sibling, entities, index);
+	entity_association_tree_visit(node->first_child, entities, index);
+}
+
+LIBPLDM_ABI_STABLE
+void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
+					pldm_entity **entities, size_t *size)
+{
+	if (!tree || !entities || !size) {
+		return;
+	}
+
+	*size = 0;
+	if (tree->root == NULL) {
+		return;
+	}
+
+	get_num_nodes(tree->root, size);
+	*entities = malloc(*size * sizeof(pldm_entity));
+	if (!entities) {
+		return;
+	}
+	size_t index = 0;
+	entity_association_tree_visit(tree->root, *entities, &index);
+}
+
+static void entity_association_tree_destroy(pldm_entity_node *node)
+{
+	if (node == NULL) {
+		return;
+	}
+
+	entity_association_tree_destroy(node->next_sibling);
+	entity_association_tree_destroy(node->first_child);
+	free(node);
+}
+
+LIBPLDM_ABI_STABLE
+void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
+{
+	if (!tree) {
+		return;
+	}
+
+	entity_association_tree_destroy(tree->root);
+	free(tree);
+}
+
+LIBPLDM_ABI_STABLE
+bool pldm_entity_is_node_parent(pldm_entity_node *node)
+{
+	assert(node != NULL);
+
+	return node->first_child != NULL;
+}
+
+LIBPLDM_ABI_STABLE
+pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
+{
+	assert(node != NULL);
+
+	return node->parent;
+}
+
+LIBPLDM_ABI_STABLE
+bool pldm_entity_is_exist_parent(pldm_entity_node *node)
+{
+	assert(node != NULL);
+
+	if (node->parent.entity_type == 0 &&
+	    node->parent.entity_instance_num == 0 &&
+	    node->parent.entity_container_id == 0) {
+		return false;
+	}
+
+	return true;
+}
+
+LIBPLDM_ABI_STABLE
+uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
+				     uint8_t association_type)
+{
+	if (!node) {
+		return 0;
+	}
+
+	if (!(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
+	      association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL)) {
+		return 0;
+	}
+
+	size_t count = 0;
+	pldm_entity_node *curr = node->first_child;
+	while (curr != NULL) {
+		if (curr->association_type == association_type) {
+			++count;
+		}
+		curr = curr->next_sibling;
+	}
+
+	assert(count < UINT8_MAX);
+	return count < UINT8_MAX ? count : 0;
+}
+
+LIBPLDM_ABI_STABLE
+bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
+{
+	if (!parent || !node) {
+		return false;
+	}
+
+	pldm_entity_node *curr = parent->first_child;
+	while (curr != NULL) {
+		if (node->entity_type == curr->entity.entity_type &&
+		    node->entity_instance_num ==
+			    curr->entity.entity_instance_num) {
+			return true;
+		}
+		curr = curr->next_sibling;
+	}
+
+	return false;
+}
+
+static int entity_association_pdr_add_children(
+	pldm_entity_node *curr, pldm_pdr *repo, uint16_t size,
+	uint8_t contained_count, uint8_t association_type, bool is_remote,
+	uint16_t terminus_handle, uint32_t record_handle)
+{
+	uint8_t pdr[size];
+	uint8_t *start = pdr;
+
+	struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
+	hdr->version = 1;
+	hdr->record_handle = record_handle;
+	hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
+	hdr->record_change_num = 0;
+	hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
+	start += sizeof(struct pldm_pdr_hdr);
+
+	uint16_t *container_id = (uint16_t *)start;
+	*container_id = htole16(curr->first_child->entity.entity_container_id);
+	start += sizeof(uint16_t);
+	*start = association_type;
+	start += sizeof(uint8_t);
+
+	pldm_entity *entity = (pldm_entity *)start;
+	entity->entity_type = htole16(curr->entity.entity_type);
+	entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
+	entity->entity_container_id = htole16(curr->entity.entity_container_id);
+	start += sizeof(pldm_entity);
+
+	*start = contained_count;
+	start += sizeof(uint8_t);
+
+	pldm_entity_node *node = curr->first_child;
+	while (node != NULL) {
+		if (node->association_type == association_type) {
+			pldm_entity *entity = (pldm_entity *)start;
+			entity->entity_type = htole16(node->entity.entity_type);
+			entity->entity_instance_num =
+				htole16(node->entity.entity_instance_num);
+			entity->entity_container_id =
+				htole16(node->entity.entity_container_id);
+			start += sizeof(pldm_entity);
+		}
+		node = node->next_sibling;
+	}
+
+	return pldm_pdr_add_check(repo, pdr, size, is_remote, terminus_handle,
+				  &record_handle);
+}
+
+static int entity_association_pdr_add_entry(pldm_entity_node *curr,
+					    pldm_pdr *repo, bool is_remote,
+					    uint16_t terminus_handle,
+					    uint32_t record_handle)
+{
+	uint8_t num_logical_children = pldm_entity_get_num_children(
+		curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
+	uint8_t num_physical_children = pldm_entity_get_num_children(
+		curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
+	int rc;
+
+	if (num_logical_children) {
+		uint16_t logical_pdr_size =
+			sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
+			sizeof(uint8_t) + sizeof(pldm_entity) +
+			sizeof(uint8_t) +
+			(num_logical_children * sizeof(pldm_entity));
+		rc = entity_association_pdr_add_children(
+			curr, repo, logical_pdr_size, num_logical_children,
+			PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
+			terminus_handle, record_handle);
+		if (rc < 0) {
+			return rc;
+		}
+	}
+
+	if (num_physical_children) {
+		uint16_t physical_pdr_size =
+			sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
+			sizeof(uint8_t) + sizeof(pldm_entity) +
+			sizeof(uint8_t) +
+			(num_physical_children * sizeof(pldm_entity));
+		rc = entity_association_pdr_add_children(
+			curr, repo, physical_pdr_size, num_physical_children,
+			PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
+			terminus_handle, record_handle);
+		if (rc < 0) {
+			return rc;
+		}
+	}
+
+	return 0;
+}
+
+static bool is_present(pldm_entity entity, pldm_entity **entities,
+		       size_t num_entities)
+{
+	if (entities == NULL || num_entities == 0) {
+		return true;
+	}
+	size_t i = 0;
+	while (i < num_entities) {
+		if ((*entities + i)->entity_type == entity.entity_type) {
+			return true;
+		}
+		i++;
+	}
+	return false;
+}
+
+static int entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
+				      pldm_entity **entities,
+				      size_t num_entities, bool is_remote,
+				      uint16_t terminus_handle,
+				      uint32_t record_handle)
+{
+	int rc;
+
+	if (curr == NULL) {
+		return 0;
+	}
+
+	if (is_present(curr->entity, entities, num_entities)) {
+		rc = entity_association_pdr_add_entry(
+			curr, repo, is_remote, terminus_handle, record_handle);
+		if (rc) {
+			return rc;
+		}
+	}
+
+	rc = entity_association_pdr_add(curr->next_sibling, repo, entities,
+					num_entities, is_remote,
+					terminus_handle, record_handle);
+	if (rc) {
+		return rc;
+	}
+
+	return entity_association_pdr_add(curr->first_child, repo, entities,
+					  num_entities, is_remote,
+					  terminus_handle, record_handle);
+}
+
+LIBPLDM_ABI_STABLE
+int pldm_entity_association_pdr_add_check(pldm_entity_association_tree *tree,
+					  pldm_pdr *repo, bool is_remote,
+					  uint16_t terminus_handle)
+{
+	if (!tree || !repo) {
+		return 0;
+	}
+
+	return entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
+					  terminus_handle, 0);
+}
+
+LIBPLDM_ABI_STABLE
+int pldm_entity_association_pdr_add_from_node_check(
+	pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
+	size_t num_entities, bool is_remote, uint16_t terminus_handle)
+{
+	return pldm_entity_association_pdr_add_from_node_with_record_handle(
+		node, repo, entities, num_entities, is_remote, terminus_handle,
+		0);
+}
+
+LIBPLDM_ABI_STABLE
+int pldm_entity_association_pdr_add_from_node_with_record_handle(
+	pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
+	size_t num_entities, bool is_remote, uint16_t terminus_handle,
+	uint32_t record_handle)
+{
+	if (!node || !repo || !entities) {
+		return -EINVAL;
+	}
+
+	entity_association_pdr_add(node, repo, entities, num_entities,
+				   is_remote, terminus_handle, record_handle);
+
+	return 0;
+}
+
+static void find_entity_ref_in_tree(pldm_entity_node *tree_node,
+				    pldm_entity entity, pldm_entity_node **node)
+{
+	bool is_entity_container_id;
+	bool is_entity_instance_num;
+	bool is_type;
+
+	if (tree_node == NULL) {
+		return;
+	}
+
+	is_type = tree_node->entity.entity_type == entity.entity_type;
+	is_entity_instance_num = tree_node->entity.entity_instance_num ==
+				 entity.entity_instance_num;
+	is_entity_container_id = tree_node->entity.entity_container_id ==
+				 entity.entity_container_id;
+
+	if (is_type && is_entity_instance_num && is_entity_container_id) {
+		*node = tree_node;
+		return;
+	}
+
+	find_entity_ref_in_tree(tree_node->first_child, entity, node);
+	find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
+}
+
+LIBPLDM_ABI_STABLE
+void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
+				  pldm_entity entity, pldm_entity_node **node)
+{
+	if (!tree || !node) {
+		return;
+	}
+
+	find_entity_ref_in_tree(tree->root, entity, node);
+}
+
+LIBPLDM_ABI_STABLE
+void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
+					     uint16_t terminus_handle)
+{
+	if (!repo) {
+		return;
+	}
+
+	bool removed = false;
+
+	pldm_pdr_record *record = repo->first;
+	pldm_pdr_record *prev = NULL;
+	while (record != NULL) {
+		pldm_pdr_record *next = record->next;
+		if (record->terminus_handle == terminus_handle) {
+			if (repo->first == record) {
+				repo->first = next;
+			} else {
+				prev->next = next;
+			}
+			if (repo->last == record) {
+				repo->last = prev;
+			}
+			if (record->data) {
+				free(record->data);
+			}
+			--repo->record_count;
+			repo->size -= record->size;
+			free(record);
+			removed = true;
+		} else {
+			prev = record;
+		}
+		record = next;
+	}
+
+	if (removed == true) {
+		record = repo->first;
+		uint32_t record_handle = 0;
+		while (record != NULL) {
+			record->record_handle = ++record_handle;
+			if (record->data != NULL) {
+				struct pldm_pdr_hdr *hdr =
+					(struct pldm_pdr_hdr *)(record->data);
+				hdr->record_handle =
+					htole32(record->record_handle);
+			}
+			record = record->next;
+		}
+	}
+}
+
+LIBPLDM_ABI_STABLE
+void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
+{
+	if (!repo) {
+		return;
+	}
+
+	bool removed = false;
+
+	pldm_pdr_record *record = repo->first;
+	pldm_pdr_record *prev = NULL;
+	while (record != NULL) {
+		pldm_pdr_record *next = record->next;
+		if (record->is_remote == true) {
+			if (repo->first == record) {
+				repo->first = next;
+			} else {
+				prev->next = next;
+			}
+			if (repo->last == record) {
+				repo->last = prev;
+			}
+			if (record->data) {
+				free(record->data);
+			}
+			--repo->record_count;
+			repo->size -= record->size;
+			free(record);
+			removed = true;
+		} else {
+			prev = record;
+		}
+		record = next;
+	}
+
+	if (removed == true) {
+		record = repo->first;
+		uint32_t record_handle = 0;
+		while (record != NULL) {
+			record->record_handle = ++record_handle;
+			if (record->data != NULL) {
+				struct pldm_pdr_hdr *hdr =
+					(struct pldm_pdr_hdr *)(record->data);
+				hdr->record_handle =
+					htole32(record->record_handle);
+			}
+			record = record->next;
+		}
+	}
+}
+
+LIBPLDM_ABI_STABLE
+pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
+					     uint32_t first, uint32_t last)
+{
+	pldm_pdr_record *record = NULL;
+	pldm_pdr_record *curr;
+
+	if (!repo) {
+		return NULL;
+	}
+	for (curr = repo->first; curr; curr = curr->next) {
+		if (first > curr->record_handle || last < curr->record_handle) {
+			continue;
+		}
+		if (!record || curr->record_handle > record->record_handle) {
+			record = curr;
+		}
+	}
+
+	return record;
+}
+
+static void entity_association_tree_find_if_remote(pldm_entity_node *node,
+						   pldm_entity *entity,
+						   pldm_entity_node **out,
+						   bool is_remote)
+{
+	if (node == NULL) {
+		return;
+	}
+	bool is_entity_type;
+	bool is_entity_instance_num;
+
+	is_entity_type = node->entity.entity_type == entity->entity_type;
+	is_entity_instance_num = node->entity.entity_instance_num ==
+				 entity->entity_instance_num;
+
+	if (!is_remote ||
+	    node->remote_container_id == entity->entity_container_id) {
+		if (is_entity_type && is_entity_instance_num) {
+			entity->entity_container_id =
+				node->entity.entity_container_id;
+			*out = node;
+			return;
+		}
+	}
+	entity_association_tree_find_if_remote(node->next_sibling, entity, out,
+					       is_remote);
+	entity_association_tree_find_if_remote(node->first_child, entity, out,
+					       is_remote);
+}
+
+LIBPLDM_ABI_STABLE
+pldm_entity_node *pldm_entity_association_tree_find_with_locality(
+	pldm_entity_association_tree *tree, pldm_entity *entity, bool is_remote)
+{
+	if (!tree || !entity) {
+		return NULL;
+	}
+	pldm_entity_node *node = NULL;
+	entity_association_tree_find_if_remote(tree->root, entity, &node,
+					       is_remote);
+	return node;
+}
+
+static void entity_association_tree_find(pldm_entity_node *node,
+					 pldm_entity *entity,
+					 pldm_entity_node **out)
+{
+	if (node == NULL) {
+		return;
+	}
+
+	if (node->entity.entity_type == entity->entity_type &&
+	    node->entity.entity_instance_num == entity->entity_instance_num) {
+		entity->entity_container_id = node->entity.entity_container_id;
+		*out = node;
+		return;
+	}
+	entity_association_tree_find(node->next_sibling, entity, out);
+	entity_association_tree_find(node->first_child, entity, out);
+}
+
+LIBPLDM_ABI_STABLE
+pldm_entity_node *
+pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
+				  pldm_entity *entity)
+{
+	if (!tree || !entity) {
+		return NULL;
+	}
+
+	pldm_entity_node *node = NULL;
+	entity_association_tree_find(tree->root, entity, &node);
+	return node;
+}
+
+static void entity_association_tree_copy(pldm_entity_node *org_node,
+					 pldm_entity_node **new_node)
+{
+	if (org_node == NULL) {
+		return;
+	}
+	*new_node = malloc(sizeof(pldm_entity_node));
+	(*new_node)->parent = org_node->parent;
+	(*new_node)->entity = org_node->entity;
+	(*new_node)->association_type = org_node->association_type;
+	(*new_node)->remote_container_id = org_node->remote_container_id;
+	(*new_node)->first_child = NULL;
+	(*new_node)->next_sibling = NULL;
+	entity_association_tree_copy(org_node->first_child,
+				     &((*new_node)->first_child));
+	entity_association_tree_copy(org_node->next_sibling,
+				     &((*new_node)->next_sibling));
+}
+
+LIBPLDM_ABI_STABLE
+void pldm_entity_association_tree_copy_root(
+	pldm_entity_association_tree *org_tree,
+	pldm_entity_association_tree *new_tree)
+{
+	assert(org_tree != NULL);
+	assert(new_tree != NULL);
+
+	new_tree->last_used_container_id = org_tree->last_used_container_id;
+	entity_association_tree_copy(org_tree->root, &(new_tree->root));
+}
+
+LIBPLDM_ABI_STABLE
+void pldm_entity_association_tree_destroy_root(
+	pldm_entity_association_tree *tree)
+{
+	if (!tree) {
+		return;
+	}
+
+	entity_association_tree_destroy(tree->root);
+	tree->last_used_container_id = 0;
+	tree->root = NULL;
+}
+
+LIBPLDM_ABI_STABLE
+bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
+{
+	return ((tree->root == NULL) ? true : false);
+}
+
+LIBPLDM_ABI_STABLE
+void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
+					 size_t *num_entities,
+					 pldm_entity **entities)
+{
+	if (!pdr || !num_entities || !entities) {
+		return;
+	}
+	if (pdr_len < PDR_ENTITY_ASSOCIATION_MIN_SIZE) {
+		return;
+	}
+
+	struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
+	if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
+		return;
+	}
+
+	const uint8_t *start = (uint8_t *)pdr;
+	const uint8_t *end __attribute__((unused)) =
+		start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
+	start += sizeof(struct pldm_pdr_hdr);
+	struct pldm_pdr_entity_association *entity_association_pdr =
+		(struct pldm_pdr_entity_association *)start;
+	size_t l_num_entities = entity_association_pdr->num_children + 1;
+	if (l_num_entities < 2) {
+		return;
+	}
+	if (start + sizeof(struct pldm_pdr_entity_association) +
+		    sizeof(pldm_entity) * (l_num_entities - 2) !=
+	    end) {
+		return;
+	}
+	pldm_entity *l_entities = malloc(sizeof(pldm_entity) * l_num_entities);
+	if (!l_entities) {
+		return;
+	}
+	l_entities[0].entity_type =
+		le16toh(entity_association_pdr->container.entity_type);
+	l_entities[0].entity_instance_num =
+		le16toh(entity_association_pdr->container.entity_instance_num);
+	l_entities[0].entity_container_id =
+		le16toh(entity_association_pdr->container.entity_container_id);
+	pldm_entity *curr_entity = entity_association_pdr->children;
+	for (size_t i = 1; i < l_num_entities; i++, curr_entity++) {
+		l_entities[i].entity_type = le16toh(curr_entity->entity_type);
+		l_entities[i].entity_instance_num =
+			le16toh(curr_entity->entity_instance_num);
+		l_entities[i].entity_container_id =
+			le16toh(curr_entity->entity_container_id);
+	}
+
+	*num_entities = l_num_entities;
+	*entities = l_entities;
+}
+
+/* Find the postion of record in pldm_pdr repo and place new_record in
+ * the same position.
+ */
+static int pldm_pdr_replace_record(pldm_pdr *repo, pldm_pdr_record *record,
+				   pldm_pdr_record *prev,
+				   pldm_pdr_record *new_record)
+{
+	assert(repo);
+	assert(record);
+	assert(prev);
+	assert(new_record);
+
+	if (repo->size < record->size) {
+		return -EOVERFLOW;
+	}
+
+	if (repo->size + new_record->size < new_record->size) {
+		return -EOVERFLOW;
+	}
+
+	if (repo->first == record) {
+		repo->first = new_record;
+	} else {
+		prev->next = new_record;
+	}
+	new_record->next = record->next;
+
+	if (repo->last == record) {
+		repo->last = new_record;
+	}
+
+	repo->size = (repo->size - record->size) + new_record->size;
+	return 0;
+}
+
+/* Insert a new record to pldm_pdr repo to a position that comes after
+ * pldm_pdr_record record.
+ */
+static int pldm_pdr_insert_record(pldm_pdr *repo, pldm_pdr_record *record,
+				  pldm_pdr_record *new_record)
+{
+	assert(repo);
+	assert(record);
+	assert(new_record);
+
+	if (repo->size + new_record->size < new_record->size) {
+		return -EOVERFLOW;
+	}
+
+	if (repo->record_count == UINT32_MAX) {
+		return -EOVERFLOW;
+	}
+
+	new_record->next = record->next;
+	record->next = new_record;
+
+	if (repo->last == record) {
+		repo->last = new_record;
+	}
+
+	repo->size = repo->size + new_record->size;
+	++repo->record_count;
+	return 0;
+}
+
+/* Find the position of PDR when its record handle is known
+ */
+static bool pldm_pdr_find_record_by_handle(pldm_pdr_record **record,
+					   pldm_pdr_record **prev,
+					   uint32_t record_handle)
+{
+	assert(record);
+	assert(prev);
+
+	while (*record != NULL) {
+		if ((*record)->record_handle == record_handle) {
+			return true;
+		}
+		*prev = *record;
+		*record = (*record)->next;
+	}
+	return false;
+}
+
+LIBPLDM_ABI_TESTING
+int pldm_entity_association_pdr_add_contained_entity_to_remote_pdr(
+	pldm_pdr *repo, pldm_entity *entity, uint32_t pdr_record_handle)
+{
+	if (!repo || !entity) {
+		return -EINVAL;
+	}
+
+	pldm_pdr_record *record = repo->first;
+	pldm_pdr_record *prev = repo->first;
+	int rc = 0;
+	uint16_t header_length = 0;
+	uint8_t num_children = 0;
+	struct pldm_msgbuf _src;
+	struct pldm_msgbuf *src = &_src;
+	struct pldm_msgbuf _dst;
+	struct pldm_msgbuf *dst = &_dst;
+
+	pldm_pdr_find_record_by_handle(&record, &prev, pdr_record_handle);
+
+	if (!record) {
+		return -EINVAL;
+	}
+	// Initialize msg buffer for record and record->data
+	rc = pldm_msgbuf_init_errno(src, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
+				    record->data, record->size);
+	if (rc) {
+		return rc;
+	}
+
+	// check if adding another entity to record causes overflow before
+	// allocating memory for new_record.
+	if (record->size + sizeof(pldm_entity) < sizeof(pldm_entity)) {
+		return -EOVERFLOW;
+	}
+	pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
+	if (!new_record) {
+		return -ENOMEM;
+	}
+
+	new_record->data = malloc(record->size + sizeof(pldm_entity));
+	if (!new_record->data) {
+		rc = -ENOMEM;
+		goto cleanup_new_record;
+	}
+
+	new_record->record_handle = record->record_handle;
+	new_record->size = record->size + sizeof(struct pldm_entity);
+	new_record->is_remote = record->is_remote;
+
+	// Initialize new PDR record with data from original PDR record.
+	// Start with adding the header of original PDR
+	rc = pldm_msgbuf_init_errno(dst, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
+				    new_record->data, new_record->size);
+	if (rc) {
+		goto cleanup_new_record_data;
+	}
+
+	pldm_msgbuf_copy(dst, src, uint32_t, hdr_record_handle);
+	pldm_msgbuf_copy(dst, src, uint8_t, hdr_version);
+	pldm_msgbuf_copy(dst, src, uint8_t, hdr_type);
+	pldm_msgbuf_copy(dst, src, uint16_t, hdr_record_change_num);
+	// extract the header length from record and increment size with
+	// size of pldm_entity before inserting the value into new_record.
+	rc = pldm_msgbuf_extract(src, header_length);
+	if (rc) {
+		goto cleanup_new_record_data;
+	}
+	static_assert(UINT16_MAX < (SIZE_MAX - sizeof(pldm_entity)),
+		      "Fix the following bounds check.");
+	if (header_length + sizeof(pldm_entity) > UINT16_MAX) {
+		rc = -EOVERFLOW;
+		goto cleanup_new_record_data;
+	}
+	header_length += sizeof(pldm_entity);
+	pldm_msgbuf_insert(dst, header_length);
+	pldm_msgbuf_copy(dst, src, uint16_t, container_id);
+	pldm_msgbuf_copy(dst, src, uint8_t, association_type);
+	pldm_msgbuf_copy(dst, src, uint16_t, entity_type);
+	pldm_msgbuf_copy(dst, src, uint16_t, entity_instance_num);
+	pldm_msgbuf_copy(dst, src, uint16_t, entity_container_id);
+	// extract value of number of children from record and increment it
+	// by 1 before insert the value to new record.
+	rc = pldm_msgbuf_extract(src, num_children);
+	if (rc) {
+		goto cleanup_new_record_data;
+	}
+	if (num_children == UINT8_MAX) {
+		rc = -EOVERFLOW;
+		goto cleanup_new_record_data;
+	}
+	num_children += 1;
+	pldm_msgbuf_insert(dst, num_children);
+	//Add all children of original PDR to new PDR
+	for (int i = 0; i < num_children - 1; i++) {
+		pldm_msgbuf_copy(dst, src, uint16_t, child_entity_type);
+		pldm_msgbuf_copy(dst, src, uint16_t, child_entity_instance_num);
+		pldm_msgbuf_copy(dst, src, uint16_t, child_entity_container_id);
+	}
+
+	// Add new contained entity as a child of new PDR
+	rc = pldm_msgbuf_destroy(src);
+	if (rc) {
+		goto cleanup_new_record_data;
+	}
+	rc = pldm_msgbuf_init_errno(src, sizeof(struct pldm_entity), entity,
+				    sizeof(struct pldm_entity));
+	if (rc) {
+		goto cleanup_new_record_data;
+	}
+	pldm_msgbuf_copy(dst, src, uint16_t, child_entity_type);
+	pldm_msgbuf_copy(dst, src, uint16_t, child_entity_instance_num);
+	pldm_msgbuf_copy(dst, src, uint16_t, child_entity_container_id);
+
+	rc = pldm_msgbuf_destroy(src);
+	if (rc) {
+		goto cleanup_new_record_data;
+	}
+	rc = pldm_msgbuf_destroy(dst);
+	if (rc) {
+		goto cleanup_new_record_data;
+	}
+
+	rc = pldm_pdr_replace_record(repo, record, prev, new_record);
+	if (rc) {
+		goto cleanup_new_record_data;
+	}
+
+	free(record->data);
+	free(record);
+	return rc;
+cleanup_new_record_data:
+	free(new_record->data);
+cleanup_new_record:
+	free(new_record);
+	return rc;
+}
+
+LIBPLDM_ABI_TESTING
+int pldm_entity_association_pdr_create_new(pldm_pdr *repo,
+					   uint32_t pdr_record_handle,
+					   pldm_entity *parent,
+					   pldm_entity *entity,
+					   uint32_t *entity_record_handle)
+{
+	if (!repo || !parent || !entity || !entity_record_handle) {
+		return -EINVAL;
+	}
+
+	if (pdr_record_handle == UINT32_MAX) {
+		return -EOVERFLOW;
+	}
+
+	bool pdr_added = false;
+	uint16_t new_pdr_size;
+	uint16_t container_id = 0;
+	uint8_t *container_id_addr = NULL;
+	struct pldm_msgbuf _dst;
+	struct pldm_msgbuf *dst = &_dst;
+	struct pldm_msgbuf _src_p;
+	struct pldm_msgbuf *src_p = &_src_p;
+	struct pldm_msgbuf _src_c;
+	struct pldm_msgbuf *src_c = &_src_c;
+	int rc = 0;
+
+	pldm_pdr_record *prev = repo->first;
+	pldm_pdr_record *record = repo->first;
+	pdr_added = pldm_pdr_find_record_by_handle(&record, &prev,
+						   pdr_record_handle);
+	if (!pdr_added) {
+		return -ENOENT;
+	}
+
+	static_assert(PDR_ENTITY_ASSOCIATION_MIN_SIZE < UINT16_MAX,
+		      "Truncation ahead");
+	new_pdr_size = PDR_ENTITY_ASSOCIATION_MIN_SIZE;
+	pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
+	if (!new_record) {
+		return -ENOMEM;
+	}
+
+	new_record->data = malloc(new_pdr_size);
+	if (!new_record->data) {
+		rc = -ENOMEM;
+		goto cleanup_new_record;
+	}
+
+	// Initialise new PDR to be added with the header, size and handle.
+	// Set the position of new PDR
+	*entity_record_handle = pdr_record_handle + 1;
+	new_record->record_handle = *entity_record_handle;
+	new_record->size = new_pdr_size;
+	new_record->is_remote = false;
+
+	rc = pldm_msgbuf_init_errno(dst, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
+				    new_record->data, new_record->size);
+	if (rc) {
+		goto cleanup_new_record_data;
+	}
+
+	// header record handle
+	pldm_msgbuf_insert(dst, *entity_record_handle);
+	// header version
+	pldm_msgbuf_insert_uint8(dst, 1);
+	// header type
+	pldm_msgbuf_insert_uint8(dst, PLDM_PDR_ENTITY_ASSOCIATION);
+	// header change number
+	pldm_msgbuf_insert_uint16(dst, 0);
+	// header length
+	pldm_msgbuf_insert_uint16(dst,
+				  (new_pdr_size - sizeof(struct pldm_pdr_hdr)));
+
+	// Data for new PDR is obtained from parent PDR and new contained entity
+	// is added as the child
+	rc = pldm_msgbuf_init_errno(src_p, sizeof(struct pldm_entity), parent,
+				    sizeof(*parent));
+	if (rc) {
+		goto cleanup_new_record_data;
+	}
+
+	rc = pldm_msgbuf_init_errno(src_c, sizeof(struct pldm_entity), entity,
+				    sizeof(*entity));
+	if (rc) {
+		goto cleanup_new_record_data;
+	}
+
+	// extract pointer for container ID and save the address
+	rc = pldm_msgbuf_span_required(dst, sizeof(container_id),
+				       (void **)&container_id_addr);
+	if (rc) {
+		goto cleanup_new_record_data;
+	}
+	pldm_msgbuf_insert_uint8(dst, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
+	pldm_msgbuf_copy(dst, src_p, uint16_t, entity_type);
+	pldm_msgbuf_copy(dst, src_p, uint16_t, entity_instance_num);
+	pldm_msgbuf_copy(dst, src_p, uint16_t, entity_container_id);
+	// number of children
+	pldm_msgbuf_insert_uint8(dst, 1);
+
+	// Add new entity as child
+	pldm_msgbuf_copy(dst, src_c, uint16_t, child_entity_type);
+	pldm_msgbuf_copy(dst, src_c, uint16_t, child_entity_instance_num);
+	// Extract and insert child entity container ID and add same value to
+	// container ID of entity
+	pldm_msgbuf_extract(src_c, container_id);
+	pldm_msgbuf_insert(dst, container_id);
+	container_id = htole16(container_id);
+	memcpy(container_id_addr, &container_id, sizeof(uint16_t));
+
+	rc = pldm_msgbuf_destroy(dst);
+	if (rc) {
+		goto cleanup_new_record_data;
+	}
+	rc = pldm_msgbuf_destroy(src_p);
+	if (rc) {
+		goto cleanup_new_record_data;
+	}
+	rc = pldm_msgbuf_destroy(src_c);
+	if (rc) {
+		goto cleanup_new_record_data;
+	}
+
+	rc = pldm_pdr_insert_record(repo, record, new_record);
+	if (rc) {
+		goto cleanup_new_record_data;
+	}
+
+	return rc;
+cleanup_new_record_data:
+	free(new_record->data);
+cleanup_new_record:
+	free(new_record);
+	return rc;
+}
diff --git a/src/dsp/platform.c b/src/dsp/platform.c
new file mode 100644
index 0000000..79f7c1e
--- /dev/null
+++ b/src/dsp/platform.c
@@ -0,0 +1,2691 @@
+/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
+#include "msgbuf.h"
+#include "msgbuf/platform.h"
+
+#include <libpldm/base.h>
+#include <libpldm/platform.h>
+#include <libpldm/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,
+					  size_t lower, size_t upper)
+{
+	if (ctx->length + sizeof(*ctx) < lower) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	if (ctx->length > upper) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_state_effecter_pdr(
+	struct pldm_state_effecter_pdr *const effecter,
+	const size_t allocation_size,
+	const struct state_effecter_possible_states *const possible_states,
+	const size_t possible_states_size, size_t *const actual_size)
+{
+	// Encode possible states
+
+	size_t calculated_possible_states_size = 0;
+
+	{
+		char *states_ptr = (char *)possible_states;
+		char *const begin_states_ptr = states_ptr;
+
+		for (int i = 0; i < effecter->composite_effecter_count; ++i) {
+			struct state_effecter_possible_states *states =
+				(struct state_effecter_possible_states *)
+					states_ptr;
+
+			HTOLE16(states->state_set_id);
+
+			states_ptr +=
+				(sizeof(*states) - sizeof(states->states) +
+				 states->possible_states_size);
+		}
+
+		calculated_possible_states_size = states_ptr - begin_states_ptr;
+	}
+
+	// Check lengths
+
+	if (possible_states_size != calculated_possible_states_size) {
+		*actual_size = 0;
+		return PLDM_ERROR;
+	}
+
+	*actual_size =
+		(sizeof(struct pldm_state_effecter_pdr) + possible_states_size -
+		 sizeof(effecter->possible_states));
+
+	if (allocation_size < *actual_size) {
+		*actual_size = 0;
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	// Encode rest of PDR
+
+	effecter->hdr.version = 1;
+	effecter->hdr.type = PLDM_STATE_EFFECTER_PDR;
+	effecter->hdr.length = *actual_size - sizeof(struct pldm_pdr_hdr);
+
+	memcpy(effecter->possible_states, possible_states,
+	       possible_states_size);
+
+	// Convert effecter PDR body
+	HTOLE16(effecter->terminus_handle);
+	HTOLE16(effecter->effecter_id);
+	HTOLE16(effecter->entity_type);
+	HTOLE16(effecter->entity_instance);
+	HTOLE16(effecter->container_id);
+	HTOLE16(effecter->effecter_semantic_id);
+
+	// Convert header
+	HTOLE32(effecter->hdr.record_handle);
+	HTOLE16(effecter->hdr.record_change_num);
+	HTOLE16(effecter->hdr.length);
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_state_sensor_pdr(
+	struct pldm_state_sensor_pdr *const sensor,
+	const size_t allocation_size,
+	const struct state_sensor_possible_states *const possible_states,
+	const size_t possible_states_size, size_t *const actual_size)
+{
+	// Encode possible states
+
+	size_t calculated_possible_states_size = 0;
+
+	{
+		char *states_ptr = (char *)possible_states;
+		char *const begin_states_ptr = states_ptr;
+
+		for (int i = 0; i < sensor->composite_sensor_count; ++i) {
+			struct state_sensor_possible_states *states =
+				(struct state_sensor_possible_states *)
+					states_ptr;
+
+			HTOLE16(states->state_set_id);
+
+			states_ptr +=
+				(sizeof(*states) - sizeof(states->states) +
+				 states->possible_states_size);
+		}
+
+		calculated_possible_states_size = states_ptr - begin_states_ptr;
+	}
+
+	// Check lengths
+
+	if (possible_states_size != calculated_possible_states_size) {
+		*actual_size = 0;
+		return PLDM_ERROR;
+	}
+
+	*actual_size = (sizeof(struct pldm_state_sensor_pdr) +
+			possible_states_size - sizeof(sensor->possible_states));
+
+	if (allocation_size < *actual_size) {
+		*actual_size = 0;
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	// Encode rest of PDR
+
+	sensor->hdr.version = 1;
+	sensor->hdr.type = PLDM_STATE_SENSOR_PDR;
+	sensor->hdr.length = *actual_size - sizeof(struct pldm_pdr_hdr);
+
+	memcpy(sensor->possible_states, possible_states, possible_states_size);
+
+	// Convert sensor PDR body
+	HTOLE16(sensor->terminus_handle);
+	HTOLE16(sensor->sensor_id);
+	HTOLE16(sensor->entity_type);
+	HTOLE16(sensor->entity_instance);
+	HTOLE16(sensor->container_id);
+
+	// Convert header
+	HTOLE32(sensor->hdr.record_handle);
+	HTOLE16(sensor->hdr.record_change_num);
+	HTOLE16(sensor->hdr.length);
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_set_state_effecter_states_resp(uint8_t instance_id,
+					  uint8_t completion_code,
+					  struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.msg_type = PLDM_RESPONSE;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_PLATFORM;
+	header.command = PLDM_SET_STATE_EFFECTER_STATES;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	msg->payload[0] = completion_code;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_set_state_effecter_states_req(uint8_t instance_id,
+					 uint16_t effecter_id,
+					 uint8_t comp_effecter_count,
+					 set_effecter_state_field *field,
+					 struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (comp_effecter_count < 0x1 || comp_effecter_count > 0x8 ||
+	    field == 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_SET_STATE_EFFECTER_STATES;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_set_state_effecter_states_req *request =
+		(struct pldm_set_state_effecter_states_req *)msg->payload;
+	effecter_id = htole16(effecter_id);
+	request->effecter_id = effecter_id;
+	request->comp_effecter_count = comp_effecter_count;
+	memcpy(request->field, field,
+	       (sizeof(set_effecter_state_field) * comp_effecter_count));
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_set_state_effecter_states_resp(const struct pldm_msg *msg,
+					  size_t payload_length,
+					  uint8_t *completion_code)
+{
+	if (msg == NULL || completion_code == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*completion_code = msg->payload[0];
+	if (PLDM_SUCCESS != *completion_code) {
+		return PLDM_SUCCESS;
+	}
+
+	if (payload_length > PLDM_SET_STATE_EFFECTER_STATES_RESP_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	return PLDM_SUCCESS;
+}
+
+#define PLDM_SET_STATE_EFFECTER_STATES_MIN_SIZE 3
+LIBPLDM_ABI_STABLE
+int decode_set_state_effecter_states_req(const struct pldm_msg *msg,
+					 size_t payload_length,
+					 uint16_t *effecter_id,
+					 uint8_t *comp_effecter_count,
+					 set_effecter_state_field *field)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+	int i;
+
+	if (msg == NULL || effecter_id == NULL || comp_effecter_count == NULL ||
+	    field == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length > PLDM_SET_STATE_EFFECTER_STATES_REQ_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf, PLDM_SET_STATE_EFFECTER_STATES_MIN_SIZE,
+				 msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_extract_p(buf, effecter_id);
+	pldm_msgbuf_extract_p(buf, comp_effecter_count);
+
+	if (*comp_effecter_count > 8) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	for (i = 0; i < *comp_effecter_count; i++) {
+		pldm_msgbuf_extract(buf, field[i].set_request);
+		pldm_msgbuf_extract(buf, field[i].effecter_state);
+	}
+
+	return pldm_msgbuf_destroy(buf);
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_pdr_req(const struct pldm_msg *msg, size_t payload_length,
+		       uint32_t *record_hndl, uint32_t *data_transfer_hndl,
+		       uint8_t *transfer_op_flag, uint16_t *request_cnt,
+		       uint16_t *record_chg_num)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	if (msg == NULL || record_hndl == NULL || data_transfer_hndl == NULL ||
+	    transfer_op_flag == NULL || request_cnt == NULL ||
+	    record_chg_num == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != PLDM_GET_PDR_REQ_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf, PLDM_GET_PDR_REQ_BYTES, msg->payload,
+				 payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_extract_p(buf, record_hndl);
+	pldm_msgbuf_extract_p(buf, data_transfer_hndl);
+	pldm_msgbuf_extract_p(buf, transfer_op_flag);
+	pldm_msgbuf_extract_p(buf, request_cnt);
+	pldm_msgbuf_extract_p(buf, record_chg_num);
+
+	return pldm_msgbuf_destroy(buf);
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_pdr_resp(uint8_t instance_id, uint8_t completion_code,
+			uint32_t next_record_hndl,
+			uint32_t next_data_transfer_hndl, uint8_t transfer_flag,
+			uint16_t resp_cnt, const uint8_t *record_data,
+			uint8_t transfer_crc, struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.msg_type = PLDM_RESPONSE;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_PLATFORM;
+	header.command = PLDM_GET_PDR;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_get_pdr_resp *response =
+		(struct pldm_get_pdr_resp *)msg->payload;
+	response->completion_code = completion_code;
+
+	if (response->completion_code == PLDM_SUCCESS) {
+		response->next_record_handle = htole32(next_record_hndl);
+		response->next_data_transfer_handle =
+			htole32(next_data_transfer_hndl);
+		response->transfer_flag = transfer_flag;
+		response->response_count = htole16(resp_cnt);
+		if (record_data != NULL && resp_cnt > 0) {
+			memcpy(response->record_data, record_data, resp_cnt);
+		}
+		if (transfer_flag == PLDM_END) {
+			uint8_t *dst = msg->payload;
+			dst += (sizeof(struct pldm_get_pdr_resp) - 1) +
+			       resp_cnt;
+			*dst = transfer_crc;
+		}
+	}
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_pdr_repository_info_resp(
+	uint8_t instance_id, uint8_t completion_code, uint8_t repository_state,
+	const uint8_t *update_time, const uint8_t *oem_update_time,
+	uint32_t record_count, uint32_t repository_size,
+	uint32_t largest_record_size, uint8_t data_transfer_handle_timeout,
+	struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.msg_type = PLDM_RESPONSE;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_PLATFORM;
+	header.command = PLDM_GET_PDR_REPOSITORY_INFO;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_pdr_repository_info_resp *response =
+		(struct pldm_pdr_repository_info_resp *)msg->payload;
+	response->completion_code = completion_code;
+
+	if (response->completion_code == PLDM_SUCCESS) {
+		response->repository_state = repository_state;
+		if (update_time != NULL) {
+			memcpy(response->update_time, update_time,
+			       PLDM_TIMESTAMP104_SIZE);
+		}
+		if (oem_update_time != NULL) {
+			memcpy(response->oem_update_time, oem_update_time,
+			       PLDM_TIMESTAMP104_SIZE);
+		}
+		response->record_count = htole32(record_count);
+		response->repository_size = htole32(repository_size);
+		response->largest_record_size = htole32(largest_record_size);
+		response->data_transfer_handle_timeout =
+			data_transfer_handle_timeout;
+	}
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_pdr_repository_info_resp(
+	const struct pldm_msg *msg, size_t payload_length,
+	uint8_t *completion_code, uint8_t *repository_state,
+	uint8_t *update_time, uint8_t *oem_update_time, uint32_t *record_count,
+	uint32_t *repository_size, uint32_t *largest_record_size,
+	uint8_t *data_transfer_handle_timeout)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	if (msg == NULL || completion_code == NULL ||
+	    repository_state == NULL || update_time == NULL ||
+	    oem_update_time == NULL || record_count == NULL ||
+	    repository_size == NULL || largest_record_size == NULL ||
+	    data_transfer_handle_timeout == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf, PLDM_GET_PDR_REPOSITORY_INFO_RESP_BYTES,
+				 msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_extract_p(buf, completion_code);
+	if (PLDM_SUCCESS != *completion_code) {
+		return PLDM_SUCCESS;
+	}
+
+	pldm_msgbuf_extract_p(buf, repository_state);
+	if (*repository_state > PLDM_FAILED) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	pldm_msgbuf_extract_array(buf, update_time, PLDM_TIMESTAMP104_SIZE);
+	pldm_msgbuf_extract_array(buf, oem_update_time, PLDM_TIMESTAMP104_SIZE);
+	pldm_msgbuf_extract_p(buf, record_count);
+	pldm_msgbuf_extract_p(buf, repository_size);
+	pldm_msgbuf_extract_p(buf, largest_record_size);
+	pldm_msgbuf_extract_p(buf, data_transfer_handle_timeout);
+
+	return pldm_msgbuf_destroy(buf);
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_pdr_req(uint8_t instance_id, uint32_t record_hndl,
+		       uint32_t data_transfer_hndl, uint8_t transfer_op_flag,
+		       uint16_t request_cnt, uint16_t record_chg_num,
+		       struct pldm_msg *msg, size_t payload_length)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != PLDM_GET_PDR_REQ_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.msg_type = PLDM_REQUEST;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_PLATFORM;
+	header.command = PLDM_GET_PDR;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_get_pdr_req *request =
+		(struct pldm_get_pdr_req *)msg->payload;
+	request->record_handle = htole32(record_hndl);
+	request->data_transfer_handle = htole32(data_transfer_hndl);
+	request->transfer_op_flag = transfer_op_flag;
+	request->request_count = htole16(request_cnt);
+	request->record_change_number = htole16(record_chg_num);
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_pdr_resp(const struct pldm_msg *msg, size_t payload_length,
+			uint8_t *completion_code, uint32_t *next_record_hndl,
+			uint32_t *next_data_transfer_hndl,
+			uint8_t *transfer_flag, uint16_t *resp_cnt,
+			uint8_t *record_data, size_t record_data_length,
+			uint8_t *transfer_crc)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	if (msg == NULL || completion_code == NULL ||
+	    next_record_hndl == NULL || next_data_transfer_hndl == NULL ||
+	    transfer_flag == NULL || resp_cnt == NULL || transfer_crc == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf, PLDM_GET_PDR_MIN_RESP_BYTES, msg->payload,
+				 payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_extract_p(buf, completion_code);
+	if (PLDM_SUCCESS != *completion_code) {
+		return PLDM_SUCCESS;
+	}
+
+	pldm_msgbuf_extract_p(buf, next_record_hndl);
+	pldm_msgbuf_extract_p(buf, next_data_transfer_hndl);
+	pldm_msgbuf_extract_p(buf, transfer_flag);
+	rc = pldm_msgbuf_extract_p(buf, resp_cnt);
+	if (rc) {
+		return rc;
+	}
+
+	if (*resp_cnt > 0 && record_data != NULL) {
+		if (record_data_length < *resp_cnt) {
+			return PLDM_ERROR_INVALID_LENGTH;
+		}
+		pldm_msgbuf_extract_array(buf, record_data, *resp_cnt);
+	}
+
+	if (*transfer_flag == PLDM_END) {
+		pldm_msgbuf_extract_p(buf, transfer_crc);
+	}
+
+	return pldm_msgbuf_destroy(buf);
+}
+
+LIBPLDM_ABI_STABLE
+int decode_set_numeric_effecter_value_req(const struct pldm_msg *msg,
+					  size_t payload_length,
+					  uint16_t *effecter_id,
+					  uint8_t *effecter_data_size,
+					  uint8_t effecter_value[4])
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	if (msg == NULL || effecter_id == NULL || effecter_data_size == NULL ||
+	    effecter_value == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf,
+				 PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES,
+				 msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_extract_p(buf, effecter_id);
+	rc = pldm_msgbuf_extract_p(buf, effecter_data_size);
+	if (rc) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (*effecter_data_size > PLDM_EFFECTER_DATA_SIZE_SINT32) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	pldm_msgbuf_extract_effecter_value(buf, *effecter_data_size,
+					   effecter_value);
+
+	return pldm_msgbuf_destroy(buf);
+}
+
+LIBPLDM_ABI_STABLE
+int encode_set_numeric_effecter_value_resp(uint8_t instance_id,
+					   uint8_t completion_code,
+					   struct pldm_msg *msg,
+					   size_t payload_length)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != PLDM_SET_NUMERIC_EFFECTER_VALUE_RESP_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.msg_type = PLDM_RESPONSE;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_PLATFORM;
+	header.command = PLDM_SET_NUMERIC_EFFECTER_VALUE;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	msg->payload[0] = completion_code;
+
+	return rc;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_set_numeric_effecter_value_req(uint8_t instance_id,
+					  uint16_t effecter_id,
+					  uint8_t effecter_data_size,
+					  const uint8_t *effecter_value,
+					  struct pldm_msg *msg,
+					  size_t payload_length)
+{
+	if (msg == NULL || effecter_value == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (effecter_data_size > PLDM_EFFECTER_DATA_SIZE_SINT32) {
+		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_SET_NUMERIC_EFFECTER_VALUE;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_set_numeric_effecter_value_req *request =
+		(struct pldm_set_numeric_effecter_value_req *)msg->payload;
+	if (effecter_data_size == PLDM_EFFECTER_DATA_SIZE_UINT8 ||
+	    effecter_data_size == PLDM_EFFECTER_DATA_SIZE_SINT8) {
+		if (payload_length !=
+		    PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES) {
+			return PLDM_ERROR_INVALID_LENGTH;
+		}
+		request->effecter_value[0] = *effecter_value;
+	} else if (effecter_data_size == PLDM_EFFECTER_DATA_SIZE_UINT16 ||
+		   effecter_data_size == PLDM_EFFECTER_DATA_SIZE_SINT16) {
+		if (payload_length !=
+		    PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES + 1) {
+			return PLDM_ERROR_INVALID_LENGTH;
+		}
+
+		uint16_t val = *(uint16_t *)(effecter_value);
+		val = htole16(val);
+		memcpy(request->effecter_value, &val, sizeof(uint16_t));
+
+	} else if (effecter_data_size == PLDM_EFFECTER_DATA_SIZE_UINT32 ||
+		   effecter_data_size == PLDM_EFFECTER_DATA_SIZE_SINT32) {
+		if (payload_length !=
+		    PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES + 3) {
+			return PLDM_ERROR_INVALID_LENGTH;
+		}
+
+		uint32_t val = *(uint32_t *)(effecter_value);
+		val = htole32(val);
+		memcpy(request->effecter_value, &val, sizeof(uint32_t));
+	}
+
+	request->effecter_id = htole16(effecter_id);
+	request->effecter_data_size = effecter_data_size;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_set_numeric_effecter_value_resp(const struct pldm_msg *msg,
+					   size_t payload_length,
+					   uint8_t *completion_code)
+{
+	if (msg == NULL || completion_code == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length != PLDM_SET_NUMERIC_EFFECTER_VALUE_RESP_BYTES) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	*completion_code = msg->payload[0];
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_state_sensor_readings_resp(uint8_t instance_id,
+					  uint8_t completion_code,
+					  uint8_t comp_sensor_count,
+					  get_sensor_state_field *field,
+					  struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (comp_sensor_count < 0x1 || comp_sensor_count > 0x8) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.msg_type = PLDM_RESPONSE;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_PLATFORM;
+	header.command = PLDM_GET_STATE_SENSOR_READINGS;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_get_state_sensor_readings_resp *response =
+		(struct pldm_get_state_sensor_readings_resp *)msg->payload;
+
+	response->completion_code = completion_code;
+	response->comp_sensor_count = comp_sensor_count;
+	memcpy(response->field, field,
+	       (sizeof(get_sensor_state_field) * comp_sensor_count));
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_state_sensor_readings_req(uint8_t instance_id,
+					 uint16_t sensor_id,
+					 bitfield8_t sensor_rearm,
+					 uint8_t reserved, struct pldm_msg *msg)
+{
+	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_GET_STATE_SENSOR_READINGS;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_get_state_sensor_readings_req *request =
+		(struct pldm_get_state_sensor_readings_req *)msg->payload;
+
+	request->sensor_id = htole16(sensor_id);
+	request->reserved = reserved;
+	request->sensor_rearm = sensor_rearm;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_state_sensor_readings_resp(const struct pldm_msg *msg,
+					  size_t payload_length,
+					  uint8_t *completion_code,
+					  uint8_t *comp_sensor_count,
+					  get_sensor_state_field *field)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	uint8_t i;
+	int rc;
+
+	if (msg == NULL || completion_code == NULL ||
+	    comp_sensor_count == NULL || field == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf,
+				 PLDM_GET_STATE_SENSOR_READINGS_MIN_RESP_BYTES,
+				 msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	rc = pldm_msgbuf_extract_p(buf, completion_code);
+	if (rc) {
+		return rc;
+	}
+
+	if (PLDM_SUCCESS != *completion_code) {
+		return PLDM_SUCCESS;
+	}
+
+	rc = pldm_msgbuf_extract_p(buf, comp_sensor_count);
+	if (rc) {
+		return rc;
+	}
+
+	if (*comp_sensor_count < 0x1 || *comp_sensor_count > 0x8) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	for (i = 0; i < *comp_sensor_count; i++) {
+		pldm_msgbuf_extract(buf, field[i].sensor_op_state);
+		pldm_msgbuf_extract(buf, field[i].present_state);
+		pldm_msgbuf_extract(buf, field[i].previous_state);
+		pldm_msgbuf_extract(buf, field[i].event_state);
+	}
+
+	return pldm_msgbuf_destroy_consumed(buf);
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_state_sensor_readings_req(const struct pldm_msg *msg,
+					 size_t payload_length,
+					 uint16_t *sensor_id,
+					 bitfield8_t *sensor_rearm,
+					 uint8_t *reserved)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	if (msg == NULL || sensor_id == NULL || sensor_rearm == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf, PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES,
+				 msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_extract_p(buf, sensor_id);
+	pldm_msgbuf_extract(buf, sensor_rearm->byte);
+	pldm_msgbuf_extract_p(buf, reserved);
+
+	return pldm_msgbuf_destroy(buf);
+}
+
+LIBPLDM_ABI_STABLE
+int encode_sensor_event_data(
+	struct pldm_sensor_event_data *const event_data,
+	const size_t event_data_size, const uint16_t sensor_id,
+	const enum sensor_event_class_states sensor_event_class,
+	const uint8_t sensor_offset, const uint8_t event_state,
+	const uint8_t previous_event_state,
+	size_t *const actual_event_data_size)
+{
+	*actual_event_data_size =
+		(sizeof(*event_data) - sizeof(event_data->event_class) +
+		 sizeof(struct pldm_sensor_event_state_sensor_state));
+
+	if (!event_data) {
+		return PLDM_SUCCESS;
+	}
+
+	if (event_data_size < *actual_event_data_size) {
+		*actual_event_data_size = 0;
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	event_data->sensor_id = htole16(sensor_id);
+	event_data->sensor_event_class_type = sensor_event_class;
+
+	struct pldm_sensor_event_state_sensor_state *const state_data =
+		(struct pldm_sensor_event_state_sensor_state *)
+			event_data->event_class;
+
+	state_data->sensor_offset = sensor_offset;
+	state_data->event_state = event_state;
+	state_data->previous_event_state = previous_event_state;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_platform_event_message_req(const struct pldm_msg *msg,
+				      size_t payload_length,
+				      uint8_t *format_version, uint8_t *tid,
+				      uint8_t *event_class,
+				      size_t *event_data_offset)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	if (msg == NULL || format_version == NULL || tid == NULL ||
+	    event_class == NULL || event_data_offset == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf, PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES,
+				 msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_extract_p(buf, format_version);
+	pldm_msgbuf_extract_p(buf, tid);
+	pldm_msgbuf_extract_p(buf, event_class);
+	*event_data_offset =
+		sizeof(*format_version) + sizeof(*tid) + sizeof(*event_class);
+
+	return pldm_msgbuf_destroy(buf);
+}
+
+LIBPLDM_ABI_STABLE
+int decode_poll_for_platform_event_message_req(
+	const struct pldm_msg *msg, size_t payload_length,
+	uint8_t *format_version, uint8_t *transfer_operation_flag,
+	uint32_t *data_transfer_handle, uint16_t *event_id_to_acknowledge)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf,
+				 PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_REQ_BYTES,
+				 msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_extract_p(buf, format_version);
+	rc = pldm_msgbuf_extract_p(buf, transfer_operation_flag);
+	if (rc) {
+		return rc;
+	}
+	if (*transfer_operation_flag > PLDM_ACKNOWLEDGEMENT_ONLY) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	pldm_msgbuf_extract_p(buf, data_transfer_handle);
+	rc = pldm_msgbuf_extract_p(buf, event_id_to_acknowledge);
+	if (rc) {
+		return rc;
+	}
+
+	if (!(((*transfer_operation_flag == PLDM_GET_NEXTPART) &&
+	       (*event_id_to_acknowledge == 0xffff)) ||
+	      ((*transfer_operation_flag == PLDM_GET_FIRSTPART) &&
+	       (*event_id_to_acknowledge == 0x000)) ||
+	      (*transfer_operation_flag == PLDM_ACKNOWLEDGEMENT_ONLY))) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	return pldm_msgbuf_destroy(buf);
+}
+
+LIBPLDM_ABI_STABLE
+int encode_platform_event_message_resp(uint8_t instance_id,
+				       uint8_t completion_code,
+				       uint8_t platform_event_status,
+				       struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (platform_event_status > PLDM_EVENT_LOGGING_REJECTED) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.msg_type = PLDM_RESPONSE;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_PLATFORM;
+	header.command = PLDM_PLATFORM_EVENT_MESSAGE;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_platform_event_message_resp *response =
+		(struct pldm_platform_event_message_resp *)msg->payload;
+	response->completion_code = completion_code;
+	response->platform_event_status = platform_event_status;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_poll_for_platform_event_message_resp(
+	uint8_t instance_id, 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,
+	uint8_t *event_data, uint32_t checksum, struct pldm_msg *msg,
+	size_t payload_length)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	if (!msg) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.msg_type = PLDM_RESPONSE;
+	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_cc(
+		buf, PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_MIN_RESP_BYTES,
+		msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_insert(buf, completion_code);
+	pldm_msgbuf_insert(buf, tid);
+	pldm_msgbuf_insert(buf, event_id);
+
+	if (event_id == 0xffff || event_id == 0x0000) {
+		if (PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_MIN_RESP_BYTES !=
+		    payload_length) {
+			return PLDM_ERROR_INVALID_LENGTH;
+		}
+		return pldm_msgbuf_destroy(buf);
+	}
+
+	if ((event_data == NULL) && (event_data_size > 0)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	pldm_msgbuf_insert(buf, next_data_transfer_handle);
+	pldm_msgbuf_insert(buf, transfer_flag);
+	pldm_msgbuf_insert(buf, event_class);
+	pldm_msgbuf_insert(buf, event_data_size);
+
+	if ((event_data_size > 0) && event_data) {
+		pldm_msgbuf_insert_array(buf, event_data, event_data_size);
+	}
+
+	if (transfer_flag == PLDM_END || transfer_flag == PLDM_START_AND_END) {
+		pldm_msgbuf_insert(buf, checksum);
+	}
+
+	return pldm_msgbuf_destroy(buf);
+}
+
+LIBPLDM_ABI_STABLE
+int encode_platform_event_message_req(
+	uint8_t instance_id, uint8_t format_version, uint8_t tid,
+	uint8_t event_class, const uint8_t *event_data,
+	size_t event_data_length, struct pldm_msg *msg, size_t payload_length)
+
+{
+	if (format_version != 1) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (msg == NULL || event_data == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (event_data_length == 0) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (payload_length !=
+	    PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES + event_data_length) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	if (event_class > PLDM_HEARTBEAT_TIMER_ELAPSED_EVENT &&
+	    !(event_class >= 0xf0 && event_class <= 0xfe)) {
+		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_PLATFORM_EVENT_MESSAGE;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_platform_event_message_req *request =
+		(struct pldm_platform_event_message_req *)msg->payload;
+	request->format_version = format_version;
+	request->tid = tid;
+	request->event_class = event_class;
+	memcpy(request->event_data, event_data, event_data_length);
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_platform_event_message_resp(const struct pldm_msg *msg,
+				       size_t payload_length,
+				       uint8_t *completion_code,
+				       uint8_t *platform_event_status)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	if (msg == NULL || completion_code == NULL ||
+	    platform_event_status == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf, PLDM_PLATFORM_EVENT_MESSAGE_RESP_BYTES,
+				 msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	rc = pldm_msgbuf_extract_p(buf, completion_code);
+	if (rc) {
+		return rc;
+	}
+
+	if (PLDM_SUCCESS != *completion_code) {
+		return PLDM_SUCCESS;
+	}
+
+	rc = pldm_msgbuf_extract_p(buf, platform_event_status);
+	if (rc) {
+		return rc;
+	}
+
+	if (*platform_event_status > PLDM_EVENT_LOGGING_REJECTED) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	return pldm_msgbuf_destroy(buf);
+}
+
+LIBPLDM_ABI_STABLE
+int encode_event_message_buffer_size_req(uint8_t instance_id,
+					 uint16_t event_receiver_max_buffer_size,
+					 struct pldm_msg *msg)
+{
+	struct pldm_header_info header = { 0 };
+	header.msg_type = PLDM_REQUEST;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_PLATFORM;
+	header.command = PLDM_EVENT_MESSAGE_BUFFER_SIZE;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_event_message_buffer_size_req *request =
+		(struct pldm_event_message_buffer_size_req *)msg->payload;
+	request->event_receiver_max_buffer_size =
+		event_receiver_max_buffer_size;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_event_message_buffer_size_resp(const struct pldm_msg *msg,
+					  size_t payload_length,
+					  uint8_t *completion_code,
+					  uint16_t *terminus_max_buffer_size)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	if (msg == NULL || completion_code == NULL ||
+	    terminus_max_buffer_size == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf, PLDM_EVENT_MESSAGE_BUFFER_SIZE_RESP_BYTES,
+				 msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	rc = pldm_msgbuf_extract_p(buf, completion_code);
+	if (rc) {
+		return rc;
+	}
+
+	if (PLDM_SUCCESS != *completion_code) {
+		return PLDM_SUCCESS;
+	}
+
+	pldm_msgbuf_extract_p(buf, terminus_max_buffer_size);
+
+	return pldm_msgbuf_destroy_consumed(buf);
+}
+
+LIBPLDM_ABI_STABLE
+int encode_event_message_supported_req(uint8_t instance_id,
+				       uint8_t format_version,
+				       struct pldm_msg *msg)
+{
+	if (format_version != 1) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	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_EVENT_MESSAGE_SUPPORTED;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_event_message_supported_req *request =
+		(struct pldm_event_message_supported_req *)msg->payload;
+	request->format_version = format_version;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_event_message_supported_resp(const struct pldm_msg *msg,
+					size_t payload_length,
+					uint8_t *completion_code,
+					uint8_t *synchrony_config,
+					bitfield8_t *synchrony_config_support,
+					uint8_t *number_event_class_returned,
+					uint8_t *event_class,
+					uint8_t event_class_count)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int i;
+	int rc;
+
+	if (msg == NULL || completion_code == NULL ||
+	    synchrony_config == NULL || synchrony_config_support == NULL ||
+	    number_event_class_returned == NULL || event_class == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf,
+				 PLDM_EVENT_MESSAGE_SUPPORTED_MIN_RESP_BYTES,
+				 msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	rc = pldm_msgbuf_extract_p(buf, completion_code);
+	if (rc) {
+		return rc;
+	}
+
+	if (PLDM_SUCCESS != *completion_code) {
+		return PLDM_SUCCESS;
+	}
+
+	rc = pldm_msgbuf_extract_p(buf, synchrony_config);
+	if (rc) {
+		return rc;
+	}
+
+	if (*synchrony_config > PLDM_MESSAGE_TYPE_ASYNCHRONOUS_WITH_HEARTBEAT) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	pldm_msgbuf_extract_p(buf, &synchrony_config_support->byte);
+
+	rc = pldm_msgbuf_extract_p(buf, number_event_class_returned);
+	if (rc) {
+		return rc;
+	}
+
+	if (*number_event_class_returned == 0) {
+		return pldm_msgbuf_destroy(buf);
+	}
+
+	if (event_class_count < *number_event_class_returned) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	for (i = 0; i < *number_event_class_returned; i++) {
+		pldm_msgbuf_extract(buf, event_class[i]);
+	}
+
+	return pldm_msgbuf_destroy_consumed(buf);
+}
+
+LIBPLDM_ABI_STABLE
+int decode_sensor_event_data(const uint8_t *event_data,
+			     size_t event_data_length, uint16_t *sensor_id,
+			     uint8_t *sensor_event_class_type,
+			     size_t *event_class_data_offset)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	rc = pldm_msgbuf_init_cc(buf, PLDM_SENSOR_EVENT_DATA_MIN_LENGTH,
+				 event_data, event_data_length);
+	if (rc) {
+		return rc;
+	}
+
+	size_t event_class_data_length =
+		event_data_length - PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES;
+
+	pldm_msgbuf_extract_p(buf, sensor_id);
+	rc = pldm_msgbuf_extract_p(buf, sensor_event_class_type);
+	if (rc) {
+		return rc;
+	}
+
+	if (*sensor_event_class_type == PLDM_SENSOR_OP_STATE) {
+		if (event_class_data_length !=
+		    PLDM_SENSOR_EVENT_SENSOR_OP_STATE_DATA_LENGTH) {
+			return PLDM_ERROR_INVALID_LENGTH;
+		}
+	} else if (*sensor_event_class_type == PLDM_STATE_SENSOR_STATE) {
+		if (event_class_data_length !=
+		    PLDM_SENSOR_EVENT_STATE_SENSOR_STATE_DATA_LENGTH) {
+			return PLDM_ERROR_INVALID_LENGTH;
+		}
+	} else if (*sensor_event_class_type == PLDM_NUMERIC_SENSOR_STATE) {
+		if (event_class_data_length <
+			    PLDM_SENSOR_EVENT_NUMERIC_SENSOR_STATE_MIN_DATA_LENGTH ||
+		    event_class_data_length >
+			    PLDM_SENSOR_EVENT_NUMERIC_SENSOR_STATE_MAX_DATA_LENGTH) {
+			return PLDM_ERROR_INVALID_LENGTH;
+		}
+	} else {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	*event_class_data_offset =
+		sizeof(*sensor_id) + sizeof(*sensor_event_class_type);
+
+	return pldm_msgbuf_destroy(buf);
+}
+
+LIBPLDM_ABI_STABLE
+int decode_sensor_op_data(const uint8_t *sensor_data, size_t sensor_data_length,
+			  uint8_t *present_op_state, uint8_t *previous_op_state)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	if (present_op_state == NULL || previous_op_state == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf,
+				 PLDM_SENSOR_EVENT_SENSOR_OP_STATE_DATA_LENGTH,
+				 sensor_data, sensor_data_length);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_extract_p(buf, present_op_state);
+	pldm_msgbuf_extract_p(buf, previous_op_state);
+
+	return pldm_msgbuf_destroy_consumed(buf);
+}
+
+LIBPLDM_ABI_STABLE
+int decode_state_sensor_data(const uint8_t *sensor_data,
+			     size_t sensor_data_length, uint8_t *sensor_offset,
+			     uint8_t *event_state,
+			     uint8_t *previous_event_state)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	if (sensor_offset == NULL || event_state == NULL ||
+	    previous_event_state == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_init_cc(
+		buf, PLDM_SENSOR_EVENT_STATE_SENSOR_STATE_DATA_LENGTH,
+		sensor_data, sensor_data_length);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_extract_p(buf, sensor_offset);
+	pldm_msgbuf_extract_p(buf, event_state);
+	pldm_msgbuf_extract_p(buf, previous_event_state);
+
+	return pldm_msgbuf_destroy_consumed(buf);
+}
+
+LIBPLDM_ABI_STABLE
+int decode_numeric_sensor_data(const uint8_t *sensor_data,
+			       size_t sensor_data_length, uint8_t *event_state,
+			       uint8_t *previous_event_state,
+			       uint8_t *sensor_data_size,
+			       uint32_t *present_reading)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	if (sensor_data_size == NULL || event_state == NULL ||
+	    previous_event_state == NULL || present_reading == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (sensor_data_length >
+	    PLDM_SENSOR_EVENT_NUMERIC_SENSOR_STATE_MAX_DATA_LENGTH) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	rc = pldm_msgbuf_init_cc(
+		buf, PLDM_SENSOR_EVENT_NUMERIC_SENSOR_STATE_MIN_DATA_LENGTH,
+		sensor_data, sensor_data_length);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_extract_p(buf, event_state);
+	pldm_msgbuf_extract_p(buf, previous_event_state);
+	rc = pldm_msgbuf_extract_p(buf, sensor_data_size);
+	if (rc) {
+		return rc;
+	}
+
+	/*
+	 * The implementation below is bonkers, but it's because the function
+	 * prototype is bonkers. The `present_reading` argument should have been
+	 * a tagged union.
+	 */
+	switch (*sensor_data_size) {
+	case PLDM_SENSOR_DATA_SIZE_UINT8: {
+		uint8_t val;
+		if (!pldm_msgbuf_extract(buf, val)) {
+			*present_reading = (uint32_t)val;
+		}
+		break;
+	}
+	case PLDM_SENSOR_DATA_SIZE_SINT8: {
+		int8_t val;
+		if (!pldm_msgbuf_extract(buf, val)) {
+			*present_reading = (uint32_t)(int32_t)val;
+		}
+		break;
+	}
+	case PLDM_SENSOR_DATA_SIZE_UINT16: {
+		uint16_t val;
+		if (!pldm_msgbuf_extract(buf, val)) {
+			*present_reading = (uint32_t)val;
+		}
+		break;
+	}
+	case PLDM_SENSOR_DATA_SIZE_SINT16: {
+		int16_t val;
+		if (!pldm_msgbuf_extract(buf, val)) {
+			*present_reading = (uint32_t)(int32_t)val;
+		}
+		break;
+	}
+	case PLDM_SENSOR_DATA_SIZE_UINT32: {
+		uint32_t val;
+		if (!pldm_msgbuf_extract(buf, val)) {
+			*present_reading = (uint32_t)val;
+		}
+		break;
+	}
+	case PLDM_SENSOR_DATA_SIZE_SINT32: {
+		int32_t val;
+		if (!pldm_msgbuf_extract(buf, val)) {
+			*present_reading = (uint32_t)val;
+		}
+		break;
+	}
+	default:
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	return pldm_msgbuf_destroy_consumed(buf);
+}
+
+LIBPLDM_ABI_STABLE
+int decode_numeric_sensor_pdr_data(
+	const void *pdr_data, size_t pdr_data_length,
+	struct pldm_numeric_sensor_value_pdr *pdr_value)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	rc = pldm_msgbuf_init_cc(buf, PLDM_PDR_NUMERIC_SENSOR_PDR_MIN_LENGTH,
+				 pdr_data, pdr_data_length);
+	if (rc) {
+		return rc;
+	}
+
+	rc = pldm_msgbuf_extract_value_pdr_hdr(buf, &pdr_value->hdr);
+	if (rc) {
+		return rc;
+	}
+
+	rc = pldm_platform_pdr_hdr_validate(
+		&pdr_value->hdr, PLDM_PDR_NUMERIC_SENSOR_PDR_MIN_LENGTH,
+		pdr_data_length);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_extract(buf, pdr_value->terminus_handle);
+	pldm_msgbuf_extract(buf, pdr_value->sensor_id);
+	pldm_msgbuf_extract(buf, pdr_value->entity_type);
+	pldm_msgbuf_extract(buf, pdr_value->entity_instance_num);
+	pldm_msgbuf_extract(buf, pdr_value->container_id);
+	pldm_msgbuf_extract(buf, pdr_value->sensor_init);
+	pldm_msgbuf_extract(buf, pdr_value->sensor_auxiliary_names_pdr);
+	pldm_msgbuf_extract(buf, pdr_value->base_unit);
+	pldm_msgbuf_extract(buf, pdr_value->unit_modifier);
+	pldm_msgbuf_extract(buf, pdr_value->rate_unit);
+	pldm_msgbuf_extract(buf, pdr_value->base_oem_unit_handle);
+	pldm_msgbuf_extract(buf, pdr_value->aux_unit);
+	pldm_msgbuf_extract(buf, pdr_value->aux_unit_modifier);
+	pldm_msgbuf_extract(buf, pdr_value->aux_rate_unit);
+	pldm_msgbuf_extract(buf, pdr_value->rel);
+	pldm_msgbuf_extract(buf, pdr_value->aux_oem_unit_handle);
+	pldm_msgbuf_extract(buf, pdr_value->is_linear);
+
+	rc = pldm_msgbuf_extract(buf, pdr_value->sensor_data_size);
+	if (rc) {
+		return rc;
+	}
+	if (pdr_value->sensor_data_size > PLDM_SENSOR_DATA_SIZE_MAX) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	pldm_msgbuf_extract(buf, pdr_value->resolution);
+	pldm_msgbuf_extract(buf, pdr_value->offset);
+	pldm_msgbuf_extract(buf, pdr_value->accuracy);
+	pldm_msgbuf_extract(buf, pdr_value->plus_tolerance);
+	pldm_msgbuf_extract(buf, pdr_value->minus_tolerance);
+	pldm_msgbuf_extract_sensor_data(buf, pdr_value->sensor_data_size,
+					&pdr_value->hysteresis);
+	pldm_msgbuf_extract(buf, pdr_value->supported_thresholds.byte);
+	pldm_msgbuf_extract(
+		buf, pdr_value->threshold_and_hysteresis_volatility.byte);
+	pldm_msgbuf_extract(buf, pdr_value->state_transition_interval);
+	pldm_msgbuf_extract(buf, pdr_value->update_interval);
+	pldm_msgbuf_extract_sensor_data(buf, pdr_value->sensor_data_size,
+					&pdr_value->max_readable);
+	pldm_msgbuf_extract_sensor_data(buf, pdr_value->sensor_data_size,
+					&pdr_value->min_readable);
+
+	rc = pldm_msgbuf_extract(buf, pdr_value->range_field_format);
+	if (rc) {
+		return rc;
+	}
+	if (pdr_value->range_field_format > PLDM_RANGE_FIELD_FORMAT_MAX) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	pldm_msgbuf_extract(buf, pdr_value->range_field_support.byte);
+	pldm_msgbuf_extract_range_field_format(
+		buf, pdr_value->range_field_format, pdr_value->nominal_value);
+	pldm_msgbuf_extract_range_field_format(
+		buf, pdr_value->range_field_format, pdr_value->normal_max);
+	pldm_msgbuf_extract_range_field_format(
+		buf, pdr_value->range_field_format, pdr_value->normal_min);
+	pldm_msgbuf_extract_range_field_format(
+		buf, pdr_value->range_field_format, pdr_value->warning_high);
+	pldm_msgbuf_extract_range_field_format(
+		buf, pdr_value->range_field_format, pdr_value->warning_low);
+	pldm_msgbuf_extract_range_field_format(
+		buf, pdr_value->range_field_format, pdr_value->critical_high);
+	pldm_msgbuf_extract_range_field_format(
+		buf, pdr_value->range_field_format, pdr_value->critical_low);
+	pldm_msgbuf_extract_range_field_format(
+		buf, pdr_value->range_field_format, pdr_value->fatal_high);
+	pldm_msgbuf_extract_range_field_format(
+		buf, pdr_value->range_field_format, pdr_value->fatal_low);
+
+	return pldm_msgbuf_destroy(buf);
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_numeric_effecter_value_req(uint8_t instance_id,
+					  uint16_t effecter_id,
+					  struct pldm_msg *msg)
+{
+	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_GET_NUMERIC_EFFECTER_VALUE;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_get_numeric_effecter_value_req *request =
+		(struct pldm_get_numeric_effecter_value_req *)msg->payload;
+	request->effecter_id = htole16(effecter_id);
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_numeric_effecter_value_resp(
+	uint8_t instance_id, uint8_t completion_code,
+	uint8_t effecter_data_size, uint8_t effecter_oper_state,
+	const uint8_t *pending_value, const uint8_t *present_value,
+	struct pldm_msg *msg, size_t payload_length)
+{
+	if (msg == NULL || pending_value == NULL || present_value == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (effecter_data_size > PLDM_EFFECTER_DATA_SIZE_SINT32) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (effecter_oper_state > EFFECTER_OPER_STATE_INTEST) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.msg_type = PLDM_RESPONSE;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_PLATFORM;
+	header.command = PLDM_GET_NUMERIC_EFFECTER_VALUE;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_get_numeric_effecter_value_resp *response =
+		(struct pldm_get_numeric_effecter_value_resp *)msg->payload;
+
+	response->completion_code = completion_code;
+	response->effecter_data_size = effecter_data_size;
+	response->effecter_oper_state = effecter_oper_state;
+
+	if (effecter_data_size == PLDM_EFFECTER_DATA_SIZE_UINT8 ||
+	    effecter_data_size == PLDM_EFFECTER_DATA_SIZE_SINT8) {
+		if (payload_length !=
+		    PLDM_GET_NUMERIC_EFFECTER_VALUE_MIN_RESP_BYTES) {
+			return PLDM_ERROR_INVALID_LENGTH;
+		}
+		response->pending_and_present_values[0] = *pending_value;
+		response->pending_and_present_values[1] = *present_value;
+
+	} else if (effecter_data_size == PLDM_EFFECTER_DATA_SIZE_UINT16 ||
+		   effecter_data_size == PLDM_EFFECTER_DATA_SIZE_SINT16) {
+		if (payload_length !=
+		    PLDM_GET_NUMERIC_EFFECTER_VALUE_MIN_RESP_BYTES + 2) {
+			return PLDM_ERROR_INVALID_LENGTH;
+		}
+		uint16_t val_pending = *(uint16_t *)pending_value;
+		val_pending = htole16(val_pending);
+		memcpy(response->pending_and_present_values, &val_pending,
+		       sizeof(uint16_t));
+		uint16_t val_present = *(uint16_t *)present_value;
+		val_present = htole16(val_present);
+		memcpy((response->pending_and_present_values +
+			sizeof(uint16_t)),
+		       &val_present, sizeof(uint16_t));
+
+	} else if (effecter_data_size == PLDM_EFFECTER_DATA_SIZE_UINT32 ||
+		   effecter_data_size == PLDM_EFFECTER_DATA_SIZE_SINT32) {
+		if (payload_length !=
+		    PLDM_GET_NUMERIC_EFFECTER_VALUE_MIN_RESP_BYTES + 6) {
+			return PLDM_ERROR_INVALID_LENGTH;
+		}
+		uint32_t val_pending = *(uint32_t *)pending_value;
+		val_pending = htole32(val_pending);
+		memcpy(response->pending_and_present_values, &val_pending,
+		       sizeof(uint32_t));
+		uint32_t val_present = *(uint32_t *)present_value;
+		val_present = htole32(val_present);
+		memcpy((response->pending_and_present_values +
+			sizeof(uint32_t)),
+		       &val_present, sizeof(uint32_t));
+	}
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_numeric_effecter_value_req(const struct pldm_msg *msg,
+					  size_t payload_length,
+					  uint16_t *effecter_id)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	if (msg == NULL || effecter_id == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf, PLDM_GET_NUMERIC_EFFECTER_VALUE_REQ_BYTES,
+				 msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_extract_p(buf, effecter_id);
+
+	return pldm_msgbuf_destroy_consumed(buf);
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_numeric_effecter_value_resp(const struct pldm_msg *msg,
+					   size_t payload_length,
+					   uint8_t *completion_code,
+					   uint8_t *effecter_data_size,
+					   uint8_t *effecter_oper_state,
+					   uint8_t *pending_value,
+					   uint8_t *present_value)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	if (msg == NULL || effecter_data_size == NULL ||
+	    effecter_oper_state == NULL || pending_value == NULL ||
+	    present_value == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf,
+				 PLDM_GET_NUMERIC_EFFECTER_VALUE_MIN_RESP_BYTES,
+				 msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	rc = pldm_msgbuf_extract_p(buf, completion_code);
+	if (rc) {
+		return rc;
+	}
+
+	if (PLDM_SUCCESS != *completion_code) {
+		return PLDM_SUCCESS;
+	}
+
+	rc = pldm_msgbuf_extract_p(buf, effecter_data_size);
+	if (rc) {
+		return rc;
+	}
+
+	if (*effecter_data_size > PLDM_EFFECTER_DATA_SIZE_SINT32) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_extract_p(buf, effecter_oper_state);
+	if (rc) {
+		return rc;
+	}
+
+	if (*effecter_oper_state > EFFECTER_OPER_STATE_INTEST) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	pldm_msgbuf_extract_effecter_value(buf, *effecter_data_size,
+					   pending_value);
+	pldm_msgbuf_extract_effecter_value(buf, *effecter_data_size,
+					   present_value);
+
+	return pldm_msgbuf_destroy_consumed(buf);
+}
+
+LIBPLDM_ABI_STABLE
+int encode_pldm_pdr_repository_chg_event_data(
+	uint8_t event_data_format, uint8_t number_of_change_records,
+	const uint8_t *event_data_operations,
+	const uint8_t *numbers_of_change_entries,
+	const uint32_t *const *change_entries,
+	struct pldm_pdr_repository_chg_event_data *event_data,
+	size_t *actual_change_records_size, size_t max_change_records_size)
+{
+	if (event_data_operations == NULL ||
+	    numbers_of_change_entries == NULL || change_entries == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	size_t expected_size =
+		sizeof(event_data_format) + sizeof(number_of_change_records);
+
+	expected_size +=
+		sizeof(*event_data_operations) * number_of_change_records;
+	expected_size +=
+		sizeof(*numbers_of_change_entries) * number_of_change_records;
+
+	for (uint8_t i = 0; i < number_of_change_records; ++i) {
+		expected_size += sizeof(*change_entries[0]) *
+				 numbers_of_change_entries[i];
+	}
+
+	*actual_change_records_size = expected_size;
+
+	if (event_data == NULL) {
+		return PLDM_SUCCESS;
+	}
+
+	if (max_change_records_size < expected_size) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	event_data->event_data_format = event_data_format;
+	event_data->number_of_change_records = number_of_change_records;
+
+	struct pldm_pdr_repository_change_record_data *record_data =
+		(struct pldm_pdr_repository_change_record_data *)
+			event_data->change_records;
+
+	for (uint8_t i = 0; i < number_of_change_records; ++i) {
+		record_data->event_data_operation = event_data_operations[i];
+		record_data->number_of_change_entries =
+			numbers_of_change_entries[i];
+
+		for (uint8_t j = 0; j < record_data->number_of_change_entries;
+		     ++j) {
+			record_data->change_entry[j] =
+				htole32(change_entries[i][j]);
+		}
+
+		record_data =
+			(struct pldm_pdr_repository_change_record_data
+				 *)(record_data->change_entry +
+				    record_data->number_of_change_entries);
+	}
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_pldm_pdr_repository_chg_event_data(const uint8_t *event_data,
+					      size_t event_data_size,
+					      uint8_t *event_data_format,
+					      uint8_t *number_of_change_records,
+					      size_t *change_record_data_offset)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	if (event_data_format == NULL || number_of_change_records == NULL ||
+	    change_record_data_offset == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf, PLDM_PDR_REPOSITORY_CHG_EVENT_MIN_LENGTH,
+				 event_data, event_data_size);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_extract_p(buf, event_data_format);
+	pldm_msgbuf_extract_p(buf, number_of_change_records);
+
+	*change_record_data_offset =
+		sizeof(*event_data_format) + sizeof(*number_of_change_records);
+
+	return pldm_msgbuf_destroy(buf);
+}
+
+LIBPLDM_ABI_TESTING
+int decode_pldm_message_poll_event_data(const uint8_t *event_data,
+					size_t event_data_length,
+					uint8_t *format_version,
+					uint16_t *event_id,
+					uint32_t *data_transfer_handle)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	if (event_data == NULL || format_version == NULL || event_id == NULL ||
+	    data_transfer_handle == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf, PLDM_MSG_POLL_EVENT_LENGTH, event_data,
+				 event_data_length);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_extract_p(buf, format_version);
+	rc = pldm_msgbuf_extract_p(buf, event_id);
+	if (rc) {
+		return rc;
+	}
+
+	if (*event_id == 0x0000 || *event_id == 0xffff) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	pldm_msgbuf_extract_p(buf, data_transfer_handle);
+
+	return pldm_msgbuf_destroy_consumed(buf);
+}
+
+LIBPLDM_ABI_TESTING
+int encode_pldm_message_poll_event_data(uint8_t format_version,
+					uint16_t event_id,
+					uint32_t data_transfer_handle,
+					uint8_t *event_data,
+					size_t event_data_length)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	if (event_data == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (event_id == 0x0000 || event_id == 0xffff) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf, PLDM_MSG_POLL_EVENT_LENGTH, event_data,
+				 event_data_length);
+	if (rc) {
+		return rc;
+	}
+	pldm_msgbuf_insert(buf, format_version);
+	pldm_msgbuf_insert(buf, event_id);
+	pldm_msgbuf_insert(buf, data_transfer_handle);
+
+	return pldm_msgbuf_destroy(buf);
+}
+
+LIBPLDM_ABI_STABLE
+int decode_pldm_pdr_repository_change_record_data(
+	const uint8_t *change_record_data, size_t change_record_data_size,
+	uint8_t *event_data_operation, uint8_t *number_of_change_entries,
+	size_t *change_entry_data_offset)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	if (event_data_operation == NULL || number_of_change_entries == NULL ||
+	    change_entry_data_offset == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf,
+				 PLDM_PDR_REPOSITORY_CHANGE_RECORD_MIN_LENGTH,
+				 change_record_data, change_record_data_size);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_extract_p(buf, event_data_operation);
+	pldm_msgbuf_extract_p(buf, number_of_change_entries);
+
+	*change_entry_data_offset = sizeof(*event_data_operation) +
+				    sizeof(*number_of_change_entries);
+
+	return pldm_msgbuf_destroy(buf);
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_sensor_reading_req(uint8_t instance_id, uint16_t sensor_id,
+				  uint8_t rearm_event_state,
+				  struct pldm_msg *msg)
+{
+	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_GET_SENSOR_READING;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_get_sensor_reading_req *request =
+		(struct pldm_get_sensor_reading_req *)msg->payload;
+
+	request->sensor_id = htole16(sensor_id);
+	request->rearm_event_state = rearm_event_state;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_sensor_reading_resp(
+	const struct pldm_msg *msg, size_t payload_length,
+	uint8_t *completion_code, uint8_t *sensor_data_size,
+	uint8_t *sensor_operational_state, uint8_t *sensor_event_message_enable,
+	uint8_t *present_state, uint8_t *previous_state, uint8_t *event_state,
+	uint8_t *present_reading)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	if (msg == NULL || completion_code == NULL ||
+	    sensor_data_size == NULL || sensor_operational_state == NULL ||
+	    sensor_event_message_enable == NULL || present_state == NULL ||
+	    previous_state == NULL || event_state == NULL ||
+	    present_reading == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf, PLDM_GET_SENSOR_READING_MIN_RESP_BYTES,
+				 msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	rc = pldm_msgbuf_extract_p(buf, completion_code);
+	if (rc) {
+		return rc;
+	}
+
+	if (PLDM_SUCCESS != *completion_code) {
+		return PLDM_SUCCESS;
+	}
+
+	rc = pldm_msgbuf_extract_p(buf, sensor_data_size);
+	if (rc) {
+		return rc;
+	}
+
+	if (*sensor_data_size > PLDM_SENSOR_DATA_SIZE_SINT32) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	pldm_msgbuf_extract_p(buf, sensor_operational_state);
+	pldm_msgbuf_extract_p(buf, sensor_event_message_enable);
+	pldm_msgbuf_extract_p(buf, present_state);
+	pldm_msgbuf_extract_p(buf, previous_state);
+	pldm_msgbuf_extract_p(buf, event_state);
+
+	pldm_msgbuf_extract_sensor_value(buf, *sensor_data_size,
+					 present_reading);
+
+	return pldm_msgbuf_destroy_consumed(buf);
+}
+
+LIBPLDM_ABI_STABLE
+int encode_get_sensor_reading_resp(uint8_t instance_id, uint8_t completion_code,
+				   uint8_t sensor_data_size,
+				   uint8_t sensor_operational_state,
+				   uint8_t sensor_event_message_enable,
+				   uint8_t present_state,
+				   uint8_t previous_state, uint8_t event_state,
+				   const uint8_t *present_reading,
+				   struct pldm_msg *msg, size_t payload_length)
+{
+	if (msg == NULL || present_reading == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (sensor_data_size > PLDM_EFFECTER_DATA_SIZE_SINT32) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.msg_type = PLDM_RESPONSE;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_PLATFORM;
+	header.command = PLDM_GET_SENSOR_READING;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_get_sensor_reading_resp *response =
+		(struct pldm_get_sensor_reading_resp *)msg->payload;
+
+	response->completion_code = completion_code;
+	response->sensor_data_size = sensor_data_size;
+	response->sensor_operational_state = sensor_operational_state;
+	response->sensor_event_message_enable = sensor_event_message_enable;
+	response->present_state = present_state;
+	response->previous_state = previous_state;
+	response->event_state = event_state;
+
+	if (sensor_data_size == PLDM_EFFECTER_DATA_SIZE_UINT8 ||
+	    sensor_data_size == PLDM_EFFECTER_DATA_SIZE_SINT8) {
+		if (payload_length != PLDM_GET_SENSOR_READING_MIN_RESP_BYTES) {
+			return PLDM_ERROR_INVALID_LENGTH;
+		}
+		response->present_reading[0] = *present_reading;
+
+	} else if (sensor_data_size == PLDM_EFFECTER_DATA_SIZE_UINT16 ||
+		   sensor_data_size == PLDM_EFFECTER_DATA_SIZE_SINT16) {
+		if (payload_length !=
+		    PLDM_GET_SENSOR_READING_MIN_RESP_BYTES + 1) {
+			return PLDM_ERROR_INVALID_LENGTH;
+		}
+		uint16_t val = *(uint16_t *)present_reading;
+		val = htole16(val);
+		memcpy(response->present_reading, &val, 2);
+
+	} else if (sensor_data_size == PLDM_EFFECTER_DATA_SIZE_UINT32 ||
+		   sensor_data_size == PLDM_EFFECTER_DATA_SIZE_SINT32) {
+		if (payload_length !=
+		    PLDM_GET_SENSOR_READING_MIN_RESP_BYTES + 3) {
+			return PLDM_ERROR_INVALID_LENGTH;
+		}
+		uint32_t val = *(uint32_t *)present_reading;
+		val = htole32(val);
+		memcpy(response->present_reading, &val, 4);
+	}
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_get_sensor_reading_req(const struct pldm_msg *msg,
+				  size_t payload_length, uint16_t *sensor_id,
+				  uint8_t *rearm_event_state)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	if (msg == NULL || sensor_id == NULL || rearm_event_state == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf, PLDM_GET_SENSOR_READING_REQ_BYTES,
+				 msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_extract_p(buf, sensor_id);
+	pldm_msgbuf_extract_p(buf, rearm_event_state);
+
+	return pldm_msgbuf_destroy(buf);
+}
+
+LIBPLDM_ABI_STABLE
+int encode_set_event_receiver_req(uint8_t instance_id,
+				  uint8_t event_message_global_enable,
+				  uint8_t transport_protocol_type,
+				  uint8_t event_receiver_address_info,
+				  uint16_t heartbeat_timer,
+				  struct pldm_msg *msg)
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	if (transport_protocol_type != PLDM_TRANSPORT_PROTOCOL_TYPE_MCTP) {
+		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_SET_EVENT_RECEIVER;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	struct pldm_set_event_receiver_req *request =
+		(struct pldm_set_event_receiver_req *)msg->payload;
+	request->event_message_global_enable = event_message_global_enable;
+
+	request->transport_protocol_type = transport_protocol_type;
+	request->event_receiver_address_info = event_receiver_address_info;
+
+	if (event_message_global_enable ==
+	    PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE) {
+		if (heartbeat_timer == 0) {
+			return PLDM_ERROR_INVALID_DATA;
+		}
+		request->heartbeat_timer = htole16(heartbeat_timer);
+	}
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int decode_set_event_receiver_resp(const struct pldm_msg *msg,
+				   size_t payload_length,
+				   uint8_t *completion_code)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	if (msg == NULL || completion_code == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf, PLDM_SET_EVENT_RECEIVER_RESP_BYTES,
+				 msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_extract_p(buf, completion_code);
+
+	return pldm_msgbuf_destroy(buf);
+}
+
+LIBPLDM_ABI_STABLE
+int decode_set_event_receiver_req(const struct pldm_msg *msg,
+				  size_t payload_length,
+				  uint8_t *event_message_global_enable,
+				  uint8_t *transport_protocol_type,
+				  uint8_t *event_receiver_address_info,
+				  uint16_t *heartbeat_timer)
+
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	if (msg == NULL || event_message_global_enable == NULL ||
+	    transport_protocol_type == NULL ||
+	    event_receiver_address_info == NULL || heartbeat_timer == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf, PLDM_SET_EVENT_RECEIVER_REQ_BYTES,
+				 msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_extract_p(buf, event_message_global_enable);
+	pldm_msgbuf_extract_p(buf, transport_protocol_type);
+	pldm_msgbuf_extract_p(buf, event_receiver_address_info);
+	pldm_msgbuf_extract_p(buf, heartbeat_timer);
+
+	rc = pldm_msgbuf_destroy(buf);
+	if (rc) {
+		return rc;
+	}
+
+	if ((*event_message_global_enable ==
+	     PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE) &&
+	    (*heartbeat_timer == 0)) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+int encode_set_event_receiver_resp(uint8_t instance_id, uint8_t completion_code,
+				   struct pldm_msg *msg)
+
+{
+	if (msg == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.instance = instance_id;
+	header.msg_type = PLDM_RESPONSE;
+	header.pldm_type = PLDM_PLATFORM;
+	header.command = PLDM_SET_EVENT_RECEIVER;
+
+	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	msg->payload[0] = completion_code;
+
+	return PLDM_SUCCESS;
+}
+
+LIBPLDM_ABI_STABLE
+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_cc(
+		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);
+}
+
+LIBPLDM_ABI_STABLE
+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_cc(
+		buf, PLDM_POLL_FOR_PLATFORM_EVENT_MESSAGE_MIN_RESP_BYTES,
+		msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	rc = pldm_msgbuf_extract_p(buf, completion_code);
+	if (rc) {
+		return rc;
+	}
+	if (PLDM_SUCCESS != *completion_code) {
+		return *completion_code;
+	}
+
+	pldm_msgbuf_extract_p(buf, tid);
+	rc = pldm_msgbuf_extract_p(buf, event_id);
+	if (rc) {
+		return rc;
+	}
+	if ((*event_id == 0) || (*event_id == 0xffff)) {
+		return PLDM_SUCCESS;
+	}
+
+	pldm_msgbuf_extract_p(buf, next_data_transfer_handle);
+	rc = pldm_msgbuf_extract_p(buf, transfer_flag);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_extract_p(buf, event_class);
+	rc = pldm_msgbuf_extract_p(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_p(buf, event_data_integrity_checksum);
+	}
+
+	return pldm_msgbuf_destroy_consumed(buf);
+}
+
+LIBPLDM_ABI_TESTING
+int decode_numeric_effecter_pdr_data(
+	const void *pdr_data, size_t pdr_data_length,
+	struct pldm_numeric_effecter_value_pdr *pdr_value)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	struct pldm_value_pdr_hdr hdr;
+	int rc;
+
+	rc = pldm_msgbuf_init_cc(buf, PLDM_PDR_NUMERIC_EFFECTER_PDR_MIN_LENGTH,
+				 pdr_data, pdr_data_length);
+	if (rc) {
+		return rc;
+	}
+
+	rc = pldm_msgbuf_extract_value_pdr_hdr(buf, &hdr);
+	if (rc) {
+		return rc;
+	}
+
+	rc = pldm_platform_pdr_hdr_validate(
+		&hdr, PLDM_PDR_NUMERIC_EFFECTER_PDR_MIN_LENGTH,
+		pdr_data_length);
+	if (rc) {
+		return rc;
+	}
+
+	memcpy(&pdr_value->hdr, &hdr, sizeof(hdr));
+
+	pldm_msgbuf_extract(buf, pdr_value->terminus_handle);
+	pldm_msgbuf_extract(buf, pdr_value->effecter_id);
+	pldm_msgbuf_extract(buf, pdr_value->entity_type);
+	pldm_msgbuf_extract(buf, pdr_value->entity_instance);
+	pldm_msgbuf_extract(buf, pdr_value->container_id);
+	pldm_msgbuf_extract(buf, pdr_value->effecter_semantic_id);
+	pldm_msgbuf_extract(buf, pdr_value->effecter_init);
+	pldm_msgbuf_extract(buf, pdr_value->effecter_auxiliary_names);
+	pldm_msgbuf_extract(buf, pdr_value->base_unit);
+	pldm_msgbuf_extract(buf, pdr_value->unit_modifier);
+	pldm_msgbuf_extract(buf, pdr_value->rate_unit);
+	pldm_msgbuf_extract(buf, pdr_value->base_oem_unit_handle);
+	pldm_msgbuf_extract(buf, pdr_value->aux_unit);
+	pldm_msgbuf_extract(buf, pdr_value->aux_unit_modifier);
+	pldm_msgbuf_extract(buf, pdr_value->aux_rate_unit);
+	pldm_msgbuf_extract(buf, pdr_value->aux_oem_unit_handle);
+	pldm_msgbuf_extract(buf, pdr_value->is_linear);
+
+	rc = pldm_msgbuf_extract(buf, pdr_value->effecter_data_size);
+	if (rc) {
+		return rc;
+	}
+	if (pdr_value->effecter_data_size > PLDM_SENSOR_DATA_SIZE_MAX) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	pldm_msgbuf_extract(buf, pdr_value->resolution);
+	pldm_msgbuf_extract(buf, pdr_value->offset);
+	pldm_msgbuf_extract(buf, pdr_value->accuracy);
+	pldm_msgbuf_extract(buf, pdr_value->plus_tolerance);
+	pldm_msgbuf_extract(buf, pdr_value->minus_tolerance);
+	pldm_msgbuf_extract(buf, pdr_value->state_transition_interval);
+	pldm_msgbuf_extract(buf, pdr_value->transition_interval);
+	pldm_msgbuf_extract_effecter_data(buf, pdr_value->effecter_data_size,
+					  pdr_value->max_settable);
+	pldm_msgbuf_extract_effecter_data(buf, pdr_value->effecter_data_size,
+					  pdr_value->min_settable);
+
+	rc = pldm_msgbuf_extract(buf, pdr_value->range_field_format);
+	if (rc) {
+		return rc;
+	}
+	if (pdr_value->range_field_format > PLDM_RANGE_FIELD_FORMAT_MAX) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	pldm_msgbuf_extract(buf, pdr_value->range_field_support.byte);
+	pldm_msgbuf_extract_range_field_format(
+		buf, pdr_value->range_field_format, pdr_value->nominal_value);
+	pldm_msgbuf_extract_range_field_format(
+		buf, pdr_value->range_field_format, pdr_value->normal_max);
+	pldm_msgbuf_extract_range_field_format(
+		buf, pdr_value->range_field_format, pdr_value->normal_min);
+	pldm_msgbuf_extract_range_field_format(
+		buf, pdr_value->range_field_format, pdr_value->rated_max);
+	pldm_msgbuf_extract_range_field_format(
+		buf, pdr_value->range_field_format, pdr_value->rated_min);
+
+	return pldm_msgbuf_destroy_consumed(buf);
+}
+
+LIBPLDM_ABI_TESTING
+int encode_get_state_effecter_states_req(uint8_t instance_id,
+					 uint16_t effecter_id,
+					 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_GET_STATE_EFFECTER_STATES;
+
+	rc = pack_pldm_header(&header, &msg->hdr);
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf, PLDM_GET_STATE_EFFECTER_STATES_REQ_BYTES,
+				 msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_insert(buf, effecter_id);
+
+	return pldm_msgbuf_destroy_consumed(buf);
+}
+
+LIBPLDM_ABI_TESTING
+int decode_get_state_effecter_states_req(const struct pldm_msg *msg,
+					 size_t payload_length,
+					 uint16_t *effecter_id)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	int rc;
+
+	if (msg == NULL || effecter_id == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf,
+				 PLDM_GET_STATE_EFFECTER_STATES_MIN_RESP_BYTES,
+				 msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_extract_p(buf, effecter_id);
+
+	return pldm_msgbuf_destroy_consumed(buf);
+}
+
+LIBPLDM_ABI_TESTING
+int decode_get_state_effecter_states_resp(
+	const struct pldm_msg *msg, size_t payload_length,
+	struct pldm_get_state_effecter_states_resp *resp)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	get_effecter_state_field *field;
+	int rc;
+	int i;
+
+	if (msg == NULL || resp == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf,
+				 PLDM_GET_STATE_EFFECTER_STATES_MIN_RESP_BYTES,
+				 msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	rc = pldm_msgbuf_extract(buf, resp->completion_code);
+	if (rc) {
+		return rc;
+	}
+
+	if (PLDM_SUCCESS != resp->completion_code) {
+		return PLDM_SUCCESS;
+	}
+
+	rc = pldm_msgbuf_extract(buf, resp->comp_effecter_count);
+	if (rc) {
+		return rc;
+	}
+
+	uint8_t comp_effecter_count = resp->comp_effecter_count;
+
+	if (comp_effecter_count < PLDM_GET_EFFECTER_STATE_FIELD_COUNT_MIN ||
+	    comp_effecter_count > PLDM_GET_EFFECTER_STATE_FIELD_COUNT_MAX) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	for (i = 0, field = resp->field; i < comp_effecter_count;
+	     i++, field++) {
+		pldm_msgbuf_extract(buf, field->effecter_op_state);
+		pldm_msgbuf_extract(buf, field->pending_state);
+		pldm_msgbuf_extract(buf, field->present_state);
+	}
+
+	return pldm_msgbuf_destroy_consumed(buf);
+}
+
+LIBPLDM_ABI_TESTING
+int encode_get_state_effecter_states_resp(
+	uint8_t instance_id, struct pldm_get_state_effecter_states_resp *resp,
+	struct pldm_msg *msg, size_t payload_length)
+{
+	struct pldm_msgbuf _buf;
+	struct pldm_msgbuf *buf = &_buf;
+	get_effecter_state_field *field;
+	int rc;
+	int i;
+
+	if (msg == NULL || resp == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	uint8_t comp_effecter_count = resp->comp_effecter_count;
+
+	if (comp_effecter_count < PLDM_GET_EFFECTER_STATE_FIELD_COUNT_MIN ||
+	    comp_effecter_count > PLDM_GET_EFFECTER_STATE_FIELD_COUNT_MAX) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+
+	struct pldm_header_info header = { 0 };
+	header.msg_type = PLDM_RESPONSE;
+	header.instance = instance_id;
+	header.pldm_type = PLDM_PLATFORM;
+	header.command = PLDM_GET_STATE_EFFECTER_STATES;
+
+	rc = pack_pldm_header(&header, &msg->hdr);
+	if (rc != PLDM_SUCCESS) {
+		return rc;
+	}
+
+	rc = pldm_msgbuf_init_cc(buf,
+				 PLDM_GET_STATE_EFFECTER_STATES_MIN_RESP_BYTES,
+				 msg->payload, payload_length);
+	if (rc) {
+		return rc;
+	}
+
+	pldm_msgbuf_insert(buf, resp->completion_code);
+	pldm_msgbuf_insert(buf, comp_effecter_count);
+
+	for (i = 0, field = resp->field; i < comp_effecter_count;
+	     i++, field++) {
+		pldm_msgbuf_insert(buf, field->effecter_op_state);
+		pldm_msgbuf_insert(buf, field->pending_state);
+		pldm_msgbuf_insert(buf, field->present_state);
+	}
+
+	return pldm_msgbuf_destroy_consumed(buf);
+}