[Skiboot] [PATCH V2 09/10] pldm/libpldm: Import libpldm library handling PLDM protocol
Christophe Lombard
clombard at linux.vnet.ibm.com
Tue Mar 15 23:49:13 AEDT 2022
Platform Level Data Model (PLDM) is a standard application layer
communication protocol defined by the DMTF. PLDM is an effective data and
control source. PLDM defines a method to provide efficient access to
low-level platform inventory, monitoring, control, eventing, and
data/parameters transfer functions such as temperature, fan, voltage,
event logging, and boot control.
PLDM has defined data representations and commands that abstract the
platform management hardware.
The library deals with the encoding and decoding of PLDM messages.
The source is located here:
https://github.com/openbmc/pldm/tree/master/libpldm and use as is, without
any update.
The libpldm code is integrated into the folder ./pldm/libpldm as a set of
sources, compilated if the compiler flag CONFIG_PLDM is set.
Signed-off-by: Christophe Lombard <clombard at linux.vnet.ibm.com>
---
Makefile.main | 3 +-
pldm/libpldm/Makefile.inc | 23 +
pldm/libpldm/README.skiboot | 17 +
pldm/libpldm/base.c | 438 ++++++++
pldm/libpldm/base.h | 505 ++++++++++
pldm/libpldm/bios.c | 668 +++++++++++++
pldm/libpldm/bios.h | 618 ++++++++++++
pldm/libpldm/bios_table.c | 1126 +++++++++++++++++++++
pldm/libpldm/bios_table.h | 728 ++++++++++++++
pldm/libpldm/entity.h | 149 +++
pldm/libpldm/firmware_update.c | 1567 +++++++++++++++++++++++++++++
pldm/libpldm/firmware_update.h | 1132 +++++++++++++++++++++
pldm/libpldm/fru.c | 548 ++++++++++
pldm/libpldm/fru.h | 507 ++++++++++
pldm/libpldm/pdr.c | 914 +++++++++++++++++
pldm/libpldm/pdr.h | 399 ++++++++
pldm/libpldm/platform.c | 1706 ++++++++++++++++++++++++++++++++
pldm/libpldm/platform.h | 1625 ++++++++++++++++++++++++++++++
pldm/libpldm/pldm_types.h | 165 +++
pldm/libpldm/state_set.h | 236 +++++
pldm/libpldm/states.h | 27 +
pldm/libpldm/utils.c | 211 ++++
pldm/libpldm/utils.h | 108 ++
23 files changed, 13419 insertions(+), 1 deletion(-)
create mode 100644 pldm/libpldm/Makefile.inc
create mode 100644 pldm/libpldm/README.skiboot
create mode 100644 pldm/libpldm/base.c
create mode 100644 pldm/libpldm/base.h
create mode 100644 pldm/libpldm/bios.c
create mode 100644 pldm/libpldm/bios.h
create mode 100644 pldm/libpldm/bios_table.c
create mode 100644 pldm/libpldm/bios_table.h
create mode 100644 pldm/libpldm/entity.h
create mode 100644 pldm/libpldm/firmware_update.c
create mode 100644 pldm/libpldm/firmware_update.h
create mode 100644 pldm/libpldm/fru.c
create mode 100644 pldm/libpldm/fru.h
create mode 100644 pldm/libpldm/pdr.c
create mode 100644 pldm/libpldm/pdr.h
create mode 100644 pldm/libpldm/platform.c
create mode 100644 pldm/libpldm/platform.h
create mode 100644 pldm/libpldm/pldm_types.h
create mode 100644 pldm/libpldm/state_set.h
create mode 100644 pldm/libpldm/states.h
create mode 100644 pldm/libpldm/utils.c
create mode 100644 pldm/libpldm/utils.h
diff --git a/Makefile.main b/Makefile.main
index 738e0857..a65220c6 100644
--- a/Makefile.main
+++ b/Makefile.main
@@ -307,6 +307,7 @@ include $(SRC)/$(DEVSRC)/Makefile.inc
include $(SRC)/libstb/Makefile.inc
ifeq ($(CONFIG_PLDM),1)
include $(SRC)/libmctp/Makefile.inc
+include $(SRC)/pldm/libpldm/Makefile.inc
endif
# hack for travis-ci and coverity
@@ -333,7 +334,7 @@ all: $(TARGET).lid.stb $(TARGET).lid.xz.stb
OBJS := $(ASM) $(CORE) $(HW) $(PLATFORMS) $(LIBFDT) $(LIBXZ) $(LIBFLASH) $(LIBSTB)
OBJS += $(LIBC) $(CCAN) $(DEVSRC_OBJ) $(LIBPORE)
ifeq ($(CONFIG_PLDM),1)
-OBJS += $(LIBMCTP)
+OBJS += $(LIBMCTP) $(LIBPLDM)
endif
OBJS_NO_VER = $(OBJS)
ALL_OBJS = $(OBJS) version.o
diff --git a/pldm/libpldm/Makefile.inc b/pldm/libpldm/Makefile.inc
new file mode 100644
index 00000000..22ecc82e
--- /dev/null
+++ b/pldm/libpldm/Makefile.inc
@@ -0,0 +1,23 @@
+# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+# Copyright 2022 IBM Corp.
+
+LIBPLDM_DIR ?= pldm/libpldm
+SUBDIRS += $(LIBPLDM_DIR)
+
+LIBPLDM_OBJS = base.o platform.o bios.o bios_table.o fru.o utils.o
+LIBPLDM_OBJS += pdr.o firmware_update.o
+
+CFLAGS_$(LIBPLDM_DIR)/ = -I$(SRC)/ccan/endian/ \
+ -D__BIG_ENDIAN_BITFIELD \
+ -Wno-error \
+ -Wno-declaration-after-statement \
+ -Wno-suggest-attribute=const \
+ -Wno-jump-misses-init \
+ -Wno-strict-prototypes \
+ -Wno-missing-prototypes \
+ -Wno-stack-usage \
+ -Wno-missing-declarations
+
+LIBPLDM = $(LIBPLDM_DIR)/built-in.a
+
+$(LIBPLDM): $(LIBPLDM_OBJS:%=$(LIBPLDM_DIR)/%)
diff --git a/pldm/libpldm/README.skiboot b/pldm/libpldm/README.skiboot
new file mode 100644
index 00000000..af8a6430
--- /dev/null
+++ b/pldm/libpldm/README.skiboot
@@ -0,0 +1,17 @@
+skiboot/pldm/libpldm/ is a minimally modified version of upstream
+libpldm that is distributed with the openbmc project hosted at
+https://github.com/openbmc/pldm.git
+
+This version is taken from pldm.git commit 2b7c1bfd342a ("Change the
+entity type for system") by copying most of files from the pldm/libpldm/
+directory.
+
+The only modifications from the upstream source are the additions of
+this file, Makefile.inc which has been derived from the original
+Makefile.inc, the rename of the api crc32() which is already
+defined in libmctp/crc32.c and the removal of several unnecessary
+folders and files.
+
+Local libpldm changes should be kept to a minimum, and submitted
+upstream if possible.
+
diff --git a/pldm/libpldm/base.c b/pldm/libpldm/base.c
new file mode 100644
index 00000000..83cd22ae
--- /dev/null
+++ b/pldm/libpldm/base.c
@@ -0,0 +1,438 @@
+#include <endian.h>
+#include <string.h>
+
+#include "base.h"
+
+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;
+}
+
+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;
+}
+
+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));
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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));
+}
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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/pldm/libpldm/base.h b/pldm/libpldm/base.h
new file mode 100644
index 00000000..99fd6afb
--- /dev/null
+++ b/pldm/libpldm/base.h
@@ -0,0 +1,505 @@
+#ifndef BASE_H
+#define BASE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <asm/byteorder.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "pldm_types.h"
+
+/** @brief PLDM Types
+ */
+enum pldm_supported_types {
+ PLDM_BASE = 0x00,
+ PLDM_PLATFORM = 0x02,
+ PLDM_BIOS = 0x03,
+ PLDM_FRU = 0x04,
+ PLDM_FWUP = 0x05,
+ PLDM_OEM = 0x3F,
+};
+
+/** @brief PLDM Commands
+ */
+enum pldm_supported_commands {
+ PLDM_GET_TID = 0x2,
+ PLDM_GET_PLDM_VERSION = 0x3,
+ PLDM_GET_PLDM_TYPES = 0x4,
+ PLDM_GET_PLDM_COMMANDS = 0x5
+};
+
+/** @brief PLDM base codes
+ */
+enum pldm_completion_codes {
+ PLDM_SUCCESS = 0x00,
+ PLDM_ERROR = 0x01,
+ PLDM_ERROR_INVALID_DATA = 0x02,
+ PLDM_ERROR_INVALID_LENGTH = 0x03,
+ PLDM_ERROR_NOT_READY = 0x04,
+ PLDM_ERROR_UNSUPPORTED_PLDM_CMD = 0x05,
+ PLDM_ERROR_INVALID_PLDM_TYPE = 0x20,
+ PLDM_INVALID_TRANSFER_OPERATION_FLAG = 0x21
+};
+
+enum transfer_op_flag {
+ PLDM_GET_NEXTPART = 0,
+ PLDM_GET_FIRSTPART = 1,
+};
+
+enum transfer_resp_flag {
+ PLDM_START = 0x01,
+ PLDM_MIDDLE = 0x02,
+ PLDM_END = 0x04,
+ PLDM_START_AND_END = 0x05,
+};
+
+/** @brief PLDM transport protocol type
+ */
+enum pldm_transport_protocol_type {
+ PLDM_TRANSPORT_PROTOCOL_TYPE_MCTP = 0x00,
+ PLDM_TRANSPORT_PROTOCOL_TYPE_OEM = 0xFF,
+};
+
+/** @enum MessageType
+ *
+ * The different message types supported by the PLDM specification.
+ */
+typedef enum {
+ PLDM_RESPONSE, //!< PLDM response
+ PLDM_REQUEST, //!< PLDM request
+ PLDM_RESERVED, //!< Reserved
+ PLDM_ASYNC_REQUEST_NOTIFY, //!< Unacknowledged PLDM request messages
+} MessageType;
+
+#define PLDM_INSTANCE_MAX 31
+#define PLDM_MAX_TYPES 64
+#define PLDM_MAX_CMDS_PER_TYPE 256
+
+/* Message payload lengths */
+#define PLDM_GET_COMMANDS_REQ_BYTES 5
+#define PLDM_GET_VERSION_REQ_BYTES 6
+
+/* Response lengths are inclusive of completion code */
+#define PLDM_GET_TYPES_RESP_BYTES 9
+#define PLDM_GET_TID_RESP_BYTES 2
+#define PLDM_GET_COMMANDS_RESP_BYTES 33
+/* Response data has only one version and does not contain the checksum */
+#define PLDM_GET_VERSION_RESP_BYTES 10
+
+#define PLDM_VERSION_0 0
+#define PLDM_CURRENT_VERSION PLDM_VERSION_0
+
+#define PLDM_TIMESTAMP104_SIZE 13
+
+/** @struct pldm_msg_hdr
+ *
+ * Structure representing PLDM message header fields
+ */
+struct pldm_msg_hdr {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ uint8_t instance_id : 5; //!< Instance ID
+ uint8_t reserved : 1; //!< Reserved
+ uint8_t datagram : 1; //!< Datagram bit
+ uint8_t request : 1; //!< Request bit
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ uint8_t request : 1; //!< Request bit
+ uint8_t datagram : 1; //!< Datagram bit
+ uint8_t reserved : 1; //!< Reserved
+ uint8_t instance_id : 5; //!< Instance ID
+#endif
+
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ uint8_t type : 6; //!< PLDM type
+ uint8_t header_ver : 2; //!< Header version
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ uint8_t header_ver : 2; //!< Header version
+ uint8_t type : 6; //!< PLDM type
+#endif
+ uint8_t command; //!< PLDM command code
+} __attribute__((packed));
+
+// Macros for byte-swapping variables in-place
+#define HTOLE32(X) (X = htole32(X))
+#define HTOLE16(X) (X = htole16(X))
+#define LE32TOH(X) (X = le32toh(X))
+#define LE16TOH(X) (X = le16toh(X))
+
+/** @struct pldm_msg
+ *
+ * Structure representing PLDM message
+ */
+struct pldm_msg {
+ struct pldm_msg_hdr hdr; //!< PLDM message header
+ uint8_t payload[1]; //!< &payload[0] is the beginning of the payload
+} __attribute__((packed));
+
+/** @struct pldm_header_info
+ *
+ * The information needed to prepare PLDM header and this is passed to the
+ * pack_pldm_header and unpack_pldm_header API.
+ */
+struct pldm_header_info {
+ MessageType msg_type; //!< PLDM message type
+ uint8_t instance; //!< PLDM instance id
+ uint8_t pldm_type; //!< PLDM type
+ uint8_t command; //!< PLDM command code
+ uint8_t completion_code; //!< PLDM completion code, applies for response
+};
+
+/** @struct pldm_get_types_resp
+ *
+ * Structure representing PLDM get types response.
+ */
+struct pldm_get_types_resp {
+ uint8_t completion_code; //!< completion code
+ bitfield8_t types[8]; //!< each bit represents whether a given PLDM Type
+ //!< is supported
+} __attribute__((packed));
+
+/** @struct pldm_get_commands_req
+ *
+ * Structure representing PLDM get commands request.
+ */
+struct pldm_get_commands_req {
+ uint8_t type; //!< PLDM Type for which command support information is
+ //!< being requested
+ ver32_t version; //!< version for the specified PLDM Type
+} __attribute__((packed));
+
+/** @struct pldm_get_commands_resp
+ *
+ * Structure representing PLDM get commands response.
+ */
+struct pldm_get_commands_resp {
+ uint8_t completion_code; //!< completion code
+ bitfield8_t commands[32]; //!< each bit represents whether a given PLDM
+ //!< command is supported
+} __attribute__((packed));
+
+/** @struct pldm_get_version_req
+ *
+ * Structure representing PLDM get version request.
+ */
+struct pldm_get_version_req {
+ uint32_t
+ transfer_handle; //!< handle to identify PLDM version data transfer
+ uint8_t transfer_opflag; //!< PLDM GetVersion operation flag
+ uint8_t type; //!< PLDM Type for which version information is being
+ //!< requested
+} __attribute__((packed));
+
+/** @struct pldm_get_version_resp
+ *
+ * Structure representing PLDM get version response.
+ */
+
+struct pldm_get_version_resp {
+ uint8_t completion_code; //!< completion code
+ uint32_t next_transfer_handle; //!< next portion of PLDM version data
+ //!< transfer
+ uint8_t transfer_flag; //!< PLDM GetVersion transfer flag
+ uint8_t version_data[1]; //!< PLDM GetVersion version field
+} __attribute__((packed));
+
+/** @struct pldm_get_tid_resp
+ *
+ * Structure representing PLDM get tid response.
+ */
+
+struct pldm_get_tid_resp {
+ uint8_t completion_code; //!< completion code
+ uint8_t tid; //!< PLDM GetTID TID field
+} __attribute__((packed));
+
+/**
+ * @brief Populate the PLDM message with the PLDM header.The caller of this API
+ * allocates buffer for the PLDM header when forming the PLDM message.
+ * The buffer is passed to this API to pack the PLDM header.
+ *
+ * @param[in] hdr - Pointer to the PLDM header information
+ * @param[out] msg - Pointer to PLDM message header
+ *
+ * @return 0 on success, otherwise PLDM error codes.
+ * @note Caller is responsible for alloc and dealloc of msg
+ * and hdr params
+ */
+uint8_t pack_pldm_header(const struct pldm_header_info *hdr,
+ struct pldm_msg_hdr *msg);
+
+/**
+ * @brief Unpack the PLDM header from the PLDM message.
+ *
+ * @param[in] msg - Pointer to the PLDM message header
+ * @param[out] hdr - Pointer to the PLDM header information
+ *
+ * @return 0 on success, otherwise PLDM error codes.
+ * @note Caller is responsible for alloc and dealloc of msg
+ * and hdr params
+ */
+uint8_t unpack_pldm_header(const struct pldm_msg_hdr *msg,
+ struct pldm_header_info *hdr);
+
+/* Requester */
+
+/* GetPLDMTypes */
+
+/** @brief Create a PLDM request message for GetPLDMTypes
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in,out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+int encode_get_types_req(uint8_t instance_id, struct pldm_msg *msg);
+
+/** @brief Decode a GetPLDMTypes response message
+ *
+ * Note:
+ * * If the return value is not PLDM_SUCCESS, it represents a
+ * transport layer error.
+ * * If the completion_code value is not PLDM_SUCCESS, it represents a
+ * protocol layer error and all the out-parameters are invalid.
+ *
+ * @param[in] msg - Response message
+ * @param[in] payload_length - Length of response message payload
+ * @param[out] completion_code - Pointer to response msg's PLDM completion code
+ * @param[out] types - pointer to array bitfield8_t[8] containing supported
+ * types (MAX_TYPES/8) = 8), as per DSP0240
+ * @return pldm_completion_codes
+ */
+int decode_get_types_resp(const struct pldm_msg *msg, size_t payload_length,
+ uint8_t *completion_code, bitfield8_t *types);
+
+/* GetPLDMCommands */
+
+/** @brief Create a PLDM request message for GetPLDMCommands
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] type - PLDM Type
+ * @param[in] version - Version for PLDM Type
+ * @param[in,out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+int encode_get_commands_req(uint8_t instance_id, uint8_t type, ver32_t version,
+ struct pldm_msg *msg);
+
+/** @brief Decode a GetPLDMCommands response message
+ *
+ * Note:
+ * * If the return value is not PLDM_SUCCESS, it represents a
+ * transport layer error.
+ * * If the completion_code value is not PLDM_SUCCESS, it represents a
+ * protocol layer error and all the out-parameters are invalid.
+ *
+ * @param[in] msg - Response message
+ * @param[in] payload_length - Length of reponse message payload
+ * @param[out] completion_code - Pointer to response msg's PLDM completion code
+ * @param[in] commands - pointer to array bitfield8_t[32] containing supported
+ * commands (PLDM_MAX_CMDS_PER_TYPE/8) = 32), as per DSP0240
+ * @return pldm_completion_codes
+ */
+int decode_get_commands_resp(const struct pldm_msg *msg, size_t payload_length,
+ uint8_t *completion_code, bitfield8_t *commands);
+
+/* GetPLDMVersion */
+
+/** @brief Create a PLDM request for GetPLDMVersion
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] transfer_handle - Handle to identify PLDM version data transfer.
+ * This handle is ignored by the responder when the
+ * transferop_flag is set to getFirstPart.
+ * @param[in] transfer_opflag - flag to indicate whether it is start of
+ * transfer
+ * @param[in] type - PLDM Type for which version is requested
+ * @param[in,out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+int encode_get_version_req(uint8_t instance_id, uint32_t transfer_handle,
+ uint8_t transfer_opflag, uint8_t type,
+ struct pldm_msg *msg);
+
+/** @brief Decode a GetPLDMVersion response message
+ *
+ * Note:
+ * * If the return value is not PLDM_SUCCESS, it represents a
+ * transport layer error.
+ * * If the completion_code value is not PLDM_SUCCESS, it represents a
+ * protocol layer error and all the out-parameters are invalid.
+ *
+ * @param[in] msg - Response message
+ * @param[in] payload_length - Length of reponse message payload
+ * @param[out] completion_code - Pointer to response msg's PLDM completion code
+ * @param[out] next_transfer_handle - the next handle for the next part of data
+ * @param[out] transfer_flag - flag to indicate the part of data
+ * @return pldm_completion_codes
+ */
+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);
+
+/* GetTID */
+
+/** @brief Decode a GetTID response message
+ *
+ * Note:
+ * * If the return value is not PLDM_SUCCESS, it represents a
+ * transport layer error.
+ * * If the completion_code value is not PLDM_SUCCESS, it represents a
+ * protocol layer error and all the out-parameters are invalid.
+ *
+ * @param[in] msg - Response message
+ * @param[in] payload_length - Length of response message payload
+ * @param[out] completion_code - Pointer to response msg's PLDM completion code
+ * @param[out] tid - Pointer to the terminus id
+ * @return pldm_completion_codes
+ */
+int decode_get_tid_resp(const struct pldm_msg *msg, size_t payload_length,
+ uint8_t *completion_code, uint8_t *tid);
+
+/* Responder */
+
+/* GetPLDMTypes */
+
+/** @brief Create a PLDM response message for GetPLDMTypes
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - PLDM completion code
+ * @param[in] types - pointer to array bitfield8_t[8] containing supported
+ * types (MAX_TYPES/8) = 8), as per DSP0240
+ * @param[in,out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+int encode_get_types_resp(uint8_t instance_id, uint8_t completion_code,
+ const bitfield8_t *types, struct pldm_msg *msg);
+
+/* GetPLDMCommands */
+
+/** @brief Decode GetPLDMCommands' request data
+ *
+ * @param[in] msg - Request message
+ * @param[in] payload_length - Length of request message payload
+ * @param[out] type - PLDM Type
+ * @param[out] version - Version for PLDM Type
+ * @return pldm_completion_codes
+ */
+int decode_get_commands_req(const struct pldm_msg *msg, size_t payload_length,
+ uint8_t *type, ver32_t *version);
+
+/** @brief Create a PLDM response message for GetPLDMCommands
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - PLDM completion code
+ * @param[in] commands - pointer to array bitfield8_t[32] containing supported
+ * commands (PLDM_MAX_CMDS_PER_TYPE/8) = 32), as per DSP0240
+ * @param[in,out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+int encode_get_commands_resp(uint8_t instance_id, uint8_t completion_code,
+ const bitfield8_t *commands, struct pldm_msg *msg);
+
+/* GetPLDMVersion */
+
+/** @brief Create a PLDM response for GetPLDMVersion
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - PLDM completion code
+ * @param[in] next_transfer_handle - Handle to identify next portion of
+ * data transfer
+ * @param[in] transfer_flag - Represents the part of transfer
+ * @param[in] version_data - the version data
+ * @param[in] version_size - size of version data
+ * @param[in,out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+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);
+
+/** @brief Decode a GetPLDMVersion request message
+ *
+ * @param[in] msg - Request message
+ * @param[in] payload_length - length of request message payload
+ * @param[out] transfer_handle - the handle of data
+ * @param[out] transfer_opflag - Transfer Flag
+ * @param[out] type - PLDM type for which version is requested
+ * @return pldm_completion_codes
+ */
+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);
+
+/* Requester */
+
+/* GetTID */
+
+/** @brief Create a PLDM request message for GetTID
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in,out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+int encode_get_tid_req(uint8_t instance_id, struct pldm_msg *msg);
+
+/** @brief Create a PLDM response message for GetTID
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - PLDM completion code
+ * @param[in] tid - Terminus ID
+ * @param[in,out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+int encode_get_tid_resp(uint8_t instance_id, uint8_t completion_code,
+ uint8_t tid, struct pldm_msg *msg);
+
+/** @brief Create a PLDM response message containing only cc
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] type - PLDM Type
+ * @param[in] command - PLDM Command
+ * @param[in] cc - PLDM Completion Code
+ * @param[out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ */
+int encode_cc_only_resp(uint8_t instance_id, uint8_t type, uint8_t command,
+ uint8_t cc, struct pldm_msg *msg);
+
+/** @brief Create a PLDM message only with the header
+ *
+ * @param[in] msg_type - PLDM message type
+ * @param[in] instance_id - Message's instance id
+ * @param[in] pldm_type - PLDM Type
+ * @param[in] command - PLDM Command
+ * @param[out] msg - Message will be written to this
+ *
+ * @return pldm_completion_codes
+ */
+int encode_pldm_header_only(uint8_t msg_type, uint8_t instance_id,
+ uint8_t pldm_type, uint8_t command,
+ struct pldm_msg *msg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BASE_H */
diff --git a/pldm/libpldm/bios.c b/pldm/libpldm/bios.c
new file mode 100644
index 00000000..8d93a6ab
--- /dev/null
+++ b/pldm/libpldm/bios.c
@@ -0,0 +1,668 @@
+#include "bios.h"
+#include "utils.h"
+#include <endian.h>
+#include <stdbool.h>
+#include <string.h>
+
+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));
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+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_lenth)
+{
+ if (msg == NULL || attribute_data == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ if (PLDM_SET_BIOS_ATTR_CURR_VAL_MIN_REQ_BYTES + attribute_length !=
+ payload_lenth) {
+ 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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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/pldm/libpldm/bios.h b/pldm/libpldm/bios.h
new file mode 100644
index 00000000..a23a671b
--- /dev/null
+++ b/pldm/libpldm/bios.h
@@ -0,0 +1,618 @@
+#ifndef BIOS_H
+#define BIOS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <asm/byteorder.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base.h"
+#include "utils.h"
+
+/* Response lengths are inclusive of completion code */
+#define PLDM_GET_DATE_TIME_RESP_BYTES 8
+
+#define PLDM_GET_BIOS_TABLE_REQ_BYTES 6
+#define PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES 6
+#define PLDM_SET_BIOS_TABLE_MIN_REQ_BYTES 6
+#define PLDM_SET_BIOS_TABLE_RESP_BYTES 5
+#define PLDM_SET_BIOS_ATTR_CURR_VAL_MIN_REQ_BYTES 5
+#define PLDM_SET_BIOS_ATTR_CURR_VAL_RESP_BYTES 5
+#define PLDM_GET_BIOS_ATTR_CURR_VAL_BY_HANDLE_REQ_BYTES 7
+#define PLDM_GET_BIOS_ATTR_CURR_VAL_BY_HANDLE_MIN_RESP_BYTES 6
+
+enum pldm_bios_completion_codes {
+ PLDM_BIOS_TABLE_UNAVAILABLE = 0x83,
+ PLDM_INVALID_BIOS_TABLE_DATA_INTEGRITY_CHECK = 0x84,
+ PLDM_INVALID_BIOS_TABLE_TYPE = 0x85,
+ PLDM_INVALID_BIOS_ATTR_HANDLE = 0x88,
+};
+enum pldm_bios_commands {
+ PLDM_GET_BIOS_TABLE = 0x01,
+ PLDM_SET_BIOS_TABLE = 0x02,
+ PLDM_SET_BIOS_ATTRIBUTE_CURRENT_VALUE = 0x07,
+ PLDM_GET_BIOS_ATTRIBUTE_CURRENT_VALUE_BY_HANDLE = 0x08,
+ PLDM_GET_DATE_TIME = 0x0c,
+ PLDM_SET_DATE_TIME = 0x0d,
+};
+
+enum pldm_bios_table_types {
+ PLDM_BIOS_STRING_TABLE,
+ PLDM_BIOS_ATTR_TABLE,
+ PLDM_BIOS_ATTR_VAL_TABLE,
+};
+
+struct pldm_bios_string_table_entry {
+ uint16_t string_handle;
+ uint16_t string_length;
+ char name[1];
+} __attribute__((packed));
+
+struct pldm_bios_attr_table_entry {
+ uint16_t attr_handle;
+ uint8_t attr_type;
+ uint16_t string_handle;
+ uint8_t metadata[1];
+} __attribute__((packed));
+
+struct pldm_bios_enum_attr {
+ uint8_t num_possible_values;
+ uint16_t indices[1];
+} __attribute__((packed));
+
+struct pldm_bios_attr_val_table_entry {
+ uint16_t attr_handle;
+ uint8_t attr_type;
+ uint8_t value[1];
+} __attribute__((packed));
+
+enum pldm_bios_attribute_type {
+ PLDM_BIOS_ENUMERATION = 0x0,
+ PLDM_BIOS_STRING = 0x1,
+ PLDM_BIOS_PASSWORD = 0x2,
+ PLDM_BIOS_INTEGER = 0x3,
+ PLDM_BIOS_ENUMERATION_READ_ONLY = 0x80,
+ PLDM_BIOS_STRING_READ_ONLY = 0x81,
+ PLDM_BIOS_PASSWORD_READ_ONLY = 0x82,
+ PLDM_BIOS_INTEGER_READ_ONLY = 0x83,
+};
+
+/** @struct pldm_get_bios_table_req
+ *
+ * structure representing GetBIOSTable request packet
+ */
+struct pldm_get_bios_table_req {
+ uint32_t transfer_handle;
+ uint8_t transfer_op_flag;
+ uint8_t table_type;
+} __attribute__((packed));
+
+/** @struct pldm_get_bios_table_resp
+ *
+ * structure representing GetBIOSTable response packet
+ */
+struct pldm_get_bios_table_resp {
+ uint8_t completion_code;
+ uint32_t next_transfer_handle;
+ uint8_t transfer_flag;
+ uint8_t table_data[1];
+} __attribute__((packed));
+
+/** @struct pldm_get_date_time_resp
+ *
+ * Structure representing PLDM get date time response
+ */
+struct pldm_get_date_time_resp {
+ uint8_t completion_code; //!< completion code
+ uint8_t seconds; //!< Seconds in BCD format
+ uint8_t minutes; //!< Minutes in BCD format
+ uint8_t hours; //!< Hours in BCD format
+ uint8_t day; //!< Day of the month in BCD format
+ uint8_t month; //!< Month in BCD format
+ uint16_t year; //!< Year in BCD format
+} __attribute__((packed));
+
+/** @struct pldm_set_date_time_req
+ *
+ * structure representing SetDateTime request packet
+ *
+ */
+struct pldm_set_date_time_req {
+ uint8_t seconds; //!< Seconds in BCD format
+ uint8_t minutes; //!< Minutes in BCD format
+ uint8_t hours; //!< Hours in BCD format
+ uint8_t day; //!< Day of the month in BCD format
+ uint8_t month; //!< Month in BCD format
+ uint16_t year; //!< Year in BCD format
+} __attribute__((packed));
+
+/** @struct pldm_only_cc_resp
+ *
+ * Structure representing PLDM responses only have completion code
+ */
+struct pldm_only_cc_resp {
+ uint8_t completion_code;
+} __attribute__((packed));
+
+/** @struct pldm_get_bios_attribute_current_value_by_handle_req
+ *
+ * structure representing GetBIOSAttributeCurrentValueByHandle request packet
+ */
+struct pldm_get_bios_attribute_current_value_by_handle_req {
+ uint32_t transfer_handle;
+ uint8_t transfer_op_flag;
+ uint16_t attribute_handle;
+} __attribute__((packed));
+
+/** @struct pldm_get_bios_attribute_current_value_by_handle_resp
+ *
+ * structure representing GetBIOSAttributeCurrentValueByHandle response
+ */
+struct pldm_get_bios_attribute_current_value_by_handle_resp {
+ uint8_t completion_code;
+ uint32_t next_transfer_handle;
+ uint8_t transfer_flag;
+ uint8_t attribute_data[1];
+} __attribute__((packed));
+
+/** @struct pldm_set_bios_attribute_current_value_req
+ *
+ * structure representing SetBiosAttributeCurrentValue request packet
+ *
+ */
+struct pldm_set_bios_attribute_current_value_req {
+ uint32_t transfer_handle;
+ uint8_t transfer_flag;
+ uint8_t attribute_data[1];
+} __attribute__((packed));
+
+/** @struct pldm_set_bios_attribute_current_value_resp
+ *
+ * structure representing SetBiosCurrentValue response packet
+ *
+ */
+struct pldm_set_bios_attribute_current_value_resp {
+ uint8_t completion_code;
+ uint32_t next_transfer_handle;
+} __attribute__((packed));
+
+/** @struct pldm_set_bios_table_req
+ *
+ * structure representing SetBIOSTable request packet
+ *
+ */
+struct pldm_set_bios_table_req {
+ uint32_t transfer_handle;
+ uint8_t transfer_flag;
+ uint8_t table_type;
+ uint8_t table_data[1];
+} __attribute__((packed));
+
+/** @struct pldm_set_bios_table_resp
+ *
+ * structure representing SetBIOSTable response packet
+ *
+ */
+struct pldm_set_bios_table_resp {
+ uint8_t completion_code;
+ uint32_t next_transfer_handle;
+} __attribute__((packed));
+
+/* Requester */
+
+/* GetDateTime */
+
+/** @brief Create a PLDM request message for GetDateTime
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.body.payload'
+ */
+
+int encode_get_date_time_req(uint8_t instance_id, struct pldm_msg *msg);
+
+/** @brief Decode a GetDateTime response message
+ *
+ * Note:
+ * * If the return value is not PLDM_SUCCESS, it represents a
+ * transport layer error.
+ * * If the completion_code value is not PLDM_SUCCESS, it represents a
+ * protocol layer error and all the out-parameters are invalid.
+ *
+ * @param[in] msg - Response message
+ * @param[in] payload_length - Length of response message payload
+ * @param[out] completion_code - Pointer to response msg's PLDM completion code
+ * @param[out] seconds - Seconds in BCD format
+ * @param[out] minutes - minutes in BCD format
+ * @param[out] hours - hours in BCD format
+ * @param[out] day - day of month in BCD format
+ * @param[out] month - number of month in BCD format
+ * @param[out] year - year in BCD format
+ * @return pldm_completion_codes
+ */
+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);
+
+/* SetBiosAttributeCurrentValue */
+
+/** @brief Create a PLDM request message for SetBiosAttributeCurrentValue
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] transfer_handle - Handle to identify a BIOS table transfer
+ * @param[in] transfer_flag - Flag to indicate what part of the transfer
+ * this request represents
+ * @param[in] attribute_data - Contains current value of attribute
+ * @param[in] attribute_length - Length of attribute
+ * @param[out] msg - Message will be written to this
+ * @param[in] payload_length - Length of message payload
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of params
+ * 'msg.payload'
+ */
+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);
+
+/** @brief Decode a SetBiosAttributeCurrentValue response message
+ *
+ * Note:
+ * * If the return value is not PLDM_SUCCESS, it represents a
+ * transport layer error.
+ * * If the completion_code value is not PLDM_SUCCESS, it represents a
+ * protocol layer error and all the out-parameters are invalid.
+ *
+ * @param[in] msg - Response message
+ * @param[in] payload_length - Length of response message payload
+ * @param[out] completion_code - Pointer to response msg's PLDM completion code
+ * @param[out] next_transfer_handle - Pointer to a handle that identify the
+ * next portion of the transfer
+ * @return pldm_completion_codes
+ */
+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);
+
+/* SetBIOSTable */
+
+/** @brief Create a PLDM request message for SetBIOSTable
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] transfer_handle - Handle to identify a BIOS table transfer
+ * @param[in] transfer_flag - Flag to indicate what part of the transfer
+ * this request represents
+ * @param[in] table_type - Indicates what table is being transferred
+ * {BIOSStringTable=0x0, BIOSAttributeTable=0x1,
+ * BIOSAttributeValueTable=0x2}
+ * @param[in] table_data - Contains data specific to the table type
+ * @param[in] table_length - Length of table data
+ * @param[out] msg - Message will be written to this
+ * @param[in] payload_length - Length of message payload
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of params
+ * 'msg.payload'
+ */
+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);
+
+/** @brief Decode a SetBIOSTable response message
+ *
+ * Note:
+ * * If the return value is not PLDM_SUCCESS, it represents a
+ * transport layer error.
+ * * If the completion_code value is not PLDM_SUCCESS, it represents a
+ * protocol layer error and all the out-parameters are invalid.
+ *
+ * @param[in] msg - Response message
+ * @param[in] payload_length - Length of response message payload
+ * @param[out] completion_code - Pointer to response msg's PLDM completion code
+ * @param[out] next_transfer_handle - Pointer to a handle that identify the
+ * next portion of the transfer
+ * @return pldm_completion_codes
+ */
+int decode_set_bios_table_resp(const struct pldm_msg *msg,
+ size_t payload_length, uint8_t *completion_code,
+ uint32_t *next_transfer_handle);
+
+/* Responder */
+
+/* GetDateTime */
+
+/** @brief Create a PLDM response message for GetDateTime
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - PLDM completion code
+ * @param[in] seconds - seconds in BCD format
+ * @param[in] minutes - minutes in BCD format
+ * @param[in] hours - hours in BCD format
+ * @param[in] day - day of the month in BCD format
+ * @param[in] month - number of month in BCD format
+ * @param[in] year - year in BCD format
+ * @param[out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.body.payload'
+ */
+
+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);
+
+/* GetBIOSTable */
+
+/** @brief Create a PLDM response message for GetBIOSTable
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - PLDM completion code
+ * @param[in] next_transfer_handle - handle to identify the next portion of the
+ * transfer
+ * @param[in] transfer_flag - To indicate what part of the transfer this
+ * response represents
+ * @param[in] table_data - BIOS Table type specific data
+ * @param[in] payload_length - Length of payload message
+ * @param[out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Encode GetBIOSTable request packet
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] transfer_handle - Handle to identify a BIOS table transfer
+ * @param[in] transfer_op_flag - Flag to indicate the start of a multipart
+ * transfer
+ * @param[in] table_type - BIOS table type
+ * @param[out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Decode GetBIOSTable request packet
+ *
+ * @param[in] msg - Request message
+ * @param[in] payload_length - Length of request message payload
+ * @param[out] transfer_handle - Handle to identify a BIOS table transfer
+ * @param[out] transfer_op_flag - Flag to indicate the start of a multipart
+ * transfer
+ * @param[out] table_type - BIOS table type
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Decode GetBIOSTable response packet
+ *
+ * @param[in] msg - Response message
+ * @param[in] payload_length - Length of response message payload
+ * @param[in] completion_code - PLDM completion code
+ * @param[in] next_transfer_handle - handle to identify the next portion of the
+ * transfer
+ * @param[in] transfer_flag - To indicate what part of the transfer this
+ * response represents
+ * @param[out] bios_table_offset - Offset where bios table data should be read
+ * in pldm msg
+ * @return pldm_completion_codes
+ */
+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);
+
+/* GetBIOSAttributeCurrentValueByHandle */
+
+/** @brief Decode GetBIOSAttributeCurrentValueByHandle request packet
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] transfer_handle - Handle to identify a BIOS attribute transfer
+ * @param[in] transfer_op_flag - Flag to indicate the start of a multipart
+ * transfer
+ * @param[in] attribute_handle - Handle to identify the BIOS attribute
+ * @param[out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Decode GetBIOSAttributeCurrentValueByHandle response packet
+ *
+ * @param[in] msg - Response message
+ * @param[in] payload_length - Length of response message payload
+ * @param[out] completion_code - PLDM completion code
+ * @param[out] next_transfer_handle - handle to identify the next portion of
+ * the transfer
+ * @param[out] transfer_flag - To indicate what part of the transfer this
+ * response represents
+ * @param[out] attribute_data - contains current value of attribute
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Decode GetBIOSAttributeCurrentValueByHandle request packet
+ *
+ * @param[in] msg - Request message
+ * @param[in] payload_length - Length of request message payload
+ * @param[out] transfer_handle - Handle to identify a BIOS table transfer
+ * @param[out] transfer_op_flag - Flag to indicate the start of a multipart
+ * transfer
+ * @param[out] attribute_handle - Handle to identify the BIOS attribute
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Create a PLDM response message for
+ * GetBIOSAttributeCurrentValueByHandle
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - PLDM completion code
+ * @param[in] next_transfer_handle - handle to identify the next portion of the
+ * transfer
+ * @param[in] transfer_flag - To indicate what part of the transfer this
+ * response represents
+ * @param[in] attribute_data - contains current value of attribute
+ * @param[in] attribute_length - Length of attribute
+ * @param[out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ */
+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);
+
+/* SetBiosAttributeCurrentValue */
+
+/** @brief Decode SetBIOSAttributeCurrentValue request packet
+ *
+ * @param[in] msg - Request message
+ * @param[in] payload_length - Length of request message payload
+ * @param[out] transfer_handle - Handle to identify a BIOS table transfer
+ * @param[out] transfer_flag - Flag to indicate what part of the transfer
+ * this request represents
+ * @param[out] attribute - Struct variable_field, contains a pointer to the
+ * attribute field in the buffer of \p msg, \p msg must
+ * be valid when \p attribute is used.
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Create a PLDM response message for SetBiosAttributeCurrentValue
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - PLDM completion code
+ * @param[in] next_transfer_handle - handle to identify the next portion of the
+ * @param[out] msg - Message will be written to this
+ */
+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);
+
+/** @brief Create a PLDM request message for SetDateTime
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] seconds - Seconds in decimal format. Value range 0~59
+ * @param[in] minutes - minutes in decimal format. Value range 0~59
+ * @param[in] hours - hours in decimal format. Value range 0~23
+ * @param[in] day - day of month in decimal format. Value range 1~31
+ * @param[in] month - number of month in decimal format. Value range 1~12
+ * @param[in] year - year in decimal format. Value range 1970~
+ * @param[out] msg - Message will be written to this
+ * @param[in] payload_length - Length of request message payload
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.body.payload'
+ */
+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);
+
+/** @brief Decode a SetDateTime request message
+ *
+ * @param[in] msg - Response message
+ * @param[in] payload_length - Length of request message payload
+ * @param[out] seconds - seconds in BCD format
+ * @param[out] minutes - minutes in BCD format
+ * @param[out] hours - hours in BCD format
+ * @param[out] day - day of the month in BCD format
+ * @param[out] month - number of month in BCD format
+ * @param[out] year - year in BCD format
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Create a PLDM response message for SetDateTime
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - PLDM completion code
+ * @param[out] msg - Message will be written to this
+ * @param[in] payload_length - Length of response message payload
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.body.payload'
+ */
+int encode_set_date_time_resp(uint8_t instance_id, uint8_t completion_code,
+ struct pldm_msg *msg, size_t payload_length);
+
+/** @brief Decode a SetDateTime response message
+ *
+ * Note:
+ * * If the return value is not PLDM_SUCCESS, it represents a
+ * transport layer error.
+ * * If the completion_code value is not PLDM_SUCCESS, it represents a
+ * protocol layer error and all the out-parameters are invalid.
+ *
+ * @param[in] msg - Response message
+ * @param[in] payload_length - Length of response message payload
+ * @param[out] completion_code - Pointer to response msg's PLDM completion code
+ * @return pldm_completion_codes
+ */
+int decode_set_date_time_resp(const struct pldm_msg *msg, size_t payload_length,
+ uint8_t *completion_code);
+
+/* SetBIOSTable */
+
+/** @brief Create a PLDM response message for SetBIOSTable
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - PLDM completion code
+ * @param[in] next_transfer_handle - handle to identify the next portion of the
+ * transfer
+ * @param[out] msg - Message will be written to this
+ */
+int encode_set_bios_table_resp(uint8_t instance_id, uint8_t completion_code,
+ uint32_t next_transfer_handle,
+ struct pldm_msg *msg);
+
+/** @brief Decode SetBIOSTable request packet
+ *
+ * @param[in] msg - Request message
+ * @param[in] payload_length - Length of request message payload
+ * @param[out] transfer_handle - Handle to identify a BIOS table transfer
+ * @param[out] transfer_flag - Flag to indicate what part of the transfer
+ * this request represents
+ * @param[out] table_type - Indicates what table is being transferred
+ * {BIOSStringTable=0x0, BIOSAttributeTable=0x1,
+ * BIOSAttributeValueTable=0x2}
+ * @param[out] table - Struct variable_field, contains data specific to the
+ * table type and the length of table data.
+ * @return pldm_completion_codes
+ */
+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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BIOS_H */
diff --git a/pldm/libpldm/bios_table.c b/pldm/libpldm/bios_table.c
new file mode 100644
index 00000000..62c34db5
--- /dev/null
+++ b/pldm/libpldm/bios_table.c
@@ -0,0 +1,1126 @@
+#include <assert.h>
+#include <endian.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bios.h"
+#include "bios_table.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 uint16_t get_bios_string_handle()
+{
+ static uint16_t handle = 0;
+ assert(handle != UINT16_MAX);
+
+ return handle++;
+}
+
+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;
+}
+
+void pldm_bios_table_string_entry_encode(void *entry, size_t entry_length,
+ const char *str, uint16_t str_length)
+{
+ size_t length = pldm_bios_table_string_entry_encode_length(str_length);
+ assert(length <= entry_length);
+ struct pldm_bios_string_table_entry *string_entry = entry;
+ string_entry->string_handle = htole16(get_bios_string_handle());
+ string_entry->string_length = htole16(str_length);
+ memcpy(string_entry->name, str, str_length);
+}
+
+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);
+ pldm_bios_table_string_entry_encode(entry, entry_length, str,
+ str_length);
+ return PLDM_SUCCESS;
+}
+
+uint16_t pldm_bios_table_string_entry_decode_handle(
+ const struct pldm_bios_string_table_entry *entry)
+{
+ return le16toh(entry->string_handle);
+}
+
+uint16_t pldm_bios_table_string_entry_decode_string_length(
+ const struct pldm_bios_string_table_entry *entry)
+{
+ return le16toh(entry->string_length);
+}
+
+uint16_t pldm_bios_table_string_entry_decode_string(
+ const struct pldm_bios_string_table_entry *entry, char *buffer, size_t size)
+{
+ uint16_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 length;
+}
+
+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);
+ size_t length =
+ pldm_bios_table_string_entry_decode_string_length(entry);
+ BUFFER_SIZE_EXPECT(size, length + 1);
+ pldm_bios_table_string_entry_decode_string(entry, buffer, size);
+ return PLDM_SUCCESS;
+}
+
+static size_t string_table_entry_length(const void *table_entry)
+{
+ const struct pldm_bios_string_table_entry *entry = table_entry;
+ return sizeof(*entry) - sizeof(entry->name) +
+ pldm_bios_table_string_entry_decode_string_length(entry);
+}
+
+static uint16_t get_bios_attr_handle()
+{
+ static uint16_t handle = 0;
+ assert(handle != UINT16_MAX);
+
+ return handle++;
+}
+
+static void 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);
+ attr_entry->attr_handle = htole16(get_bios_attr_handle());
+ attr_entry->attr_type = attr_type;
+ attr_entry->string_handle = htole16(string_handle);
+}
+
+uint16_t pldm_bios_table_attr_entry_decode_attribute_handle(
+ const struct pldm_bios_attr_table_entry *entry)
+{
+ return le16toh(entry->attr_handle);
+}
+
+uint8_t pldm_bios_table_attr_entry_decode_attribute_type(
+ const struct pldm_bios_attr_table_entry *entry)
+{
+ return entry->attr_type;
+}
+
+uint16_t pldm_bios_table_attr_entry_decode_string_handle(
+ const struct pldm_bios_attr_table_entry *entry)
+{
+ return le16toh(entry->string_handle);
+}
+
+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;
+}
+
+void pldm_bios_table_attr_entry_enum_encode(
+ void *entry, size_t entry_length,
+ const struct pldm_bios_table_attr_entry_enum_info *info)
+{
+ size_t length = pldm_bios_table_attr_entry_enum_encode_length(
+ info->pv_num, info->def_num);
+ assert(length <= entry_length);
+ uint8_t attr_type = info->read_only ? PLDM_BIOS_ENUMERATION_READ_ONLY
+ : PLDM_BIOS_ENUMERATION;
+ attr_table_entry_encode_header(entry, entry_length, attr_type,
+ info->name_handle);
+ 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);
+}
+
+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);
+ pldm_bios_table_attr_entry_enum_encode(entry, entry_length, info);
+ return PLDM_SUCCESS;
+}
+
+#define ATTR_TYPE_EXPECT(type, expected) \
+ do { \
+ if (type != expected && type != (expected | 0x80)) \
+ return PLDM_ERROR_INVALID_DATA; \
+ } while (0)
+
+uint8_t pldm_bios_table_attr_entry_enum_decode_pv_num(
+ const struct pldm_bios_attr_table_entry *entry)
+{
+ return entry->metadata[0];
+}
+
+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 = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
+ return PLDM_SUCCESS;
+}
+
+uint8_t pldm_bios_table_attr_entry_enum_decode_def_num(
+ const struct pldm_bios_attr_table_entry *entry)
+{
+ uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
+ return entry->metadata[sizeof(uint8_t) /* pv_num */ +
+ sizeof(uint16_t) * pv_num];
+}
+
+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;
+}
+
+uint8_t pldm_bios_table_attr_entry_enum_decode_pv_hdls(
+ const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
+ uint8_t pv_num)
+{
+ uint8_t num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
+ 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 num;
+}
+
+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 = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
+ if (num != pv_num)
+ return PLDM_ERROR_INVALID_DATA;
+ pldm_bios_table_attr_entry_enum_decode_pv_hdls(entry, pv_hdls, pv_num);
+ return PLDM_SUCCESS;
+}
+
+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 = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
+ 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 size_t attr_table_entry_length_enum(const void *entry)
+{
+ uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
+ uint8_t def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
+ return pldm_bios_table_attr_entry_enum_encode_length(pv_num, def_num);
+}
+
+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));
+
+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;
+}
+
+void pldm_bios_table_attr_entry_string_encode(
+ void *entry, size_t entry_length,
+ const struct pldm_bios_table_attr_entry_string_info *info)
+{
+ size_t length =
+ pldm_bios_table_attr_entry_string_encode_length(info->def_length);
+ assert(length <= entry_length);
+ uint8_t attr_type =
+ info->read_only ? PLDM_BIOS_STRING_READ_ONLY : PLDM_BIOS_STRING;
+ attr_table_entry_encode_header(entry, entry_length, attr_type,
+ info->name_handle);
+ 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);
+}
+
+#define PLDM_STRING_TYPE_MAX 5
+#define PLDM_STRING_TYPE_VENDOR 0xff
+
+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_length != strlen(info->def_string)) {
+ set_errmsg(errmsg, "Length of DefaultString should be equal to "
+ "DefaultStringLength");
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ return PLDM_SUCCESS;
+}
+
+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;
+ pldm_bios_table_attr_entry_string_encode(entry, entry_length, info);
+ return PLDM_SUCCESS;
+}
+
+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);
+}
+
+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;
+}
+
+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;
+}
+
+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);
+}
+
+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);
+}
+
+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 size_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);
+ return pldm_bios_table_attr_entry_string_encode_length(def_str_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));
+
+size_t pldm_bios_table_attr_entry_integer_encode_length()
+{
+ return sizeof(struct pldm_bios_attr_table_entry) - 1 +
+ sizeof(struct attr_table_integer_entry_fields);
+}
+
+void pldm_bios_table_attr_entry_integer_encode(
+ void *entry, size_t entry_length,
+ const struct pldm_bios_table_attr_entry_integer_info *info)
+{
+ size_t length = pldm_bios_table_attr_entry_integer_encode_length();
+ assert(length <= entry_length);
+ uint8_t attr_type =
+ info->read_only ? PLDM_BIOS_INTEGER_READ_ONLY : PLDM_BIOS_INTEGER;
+ attr_table_entry_encode_header(entry, entry_length, attr_type,
+ info->name_handle);
+ 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);
+}
+
+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;
+}
+
+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;
+ pldm_bios_table_attr_entry_integer_encode(entry, entry_length, info);
+ return PLDM_SUCCESS;
+}
+
+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 size_t attr_table_entry_length_integer(const void *entry)
+{
+ (void)entry;
+ return pldm_bios_table_attr_entry_integer_encode_length();
+}
+
+struct table_entry_length {
+ uint8_t attr_type;
+ size_t (*entry_length_handler)(const void *);
+};
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+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 size_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);
+ assert(attr_table_entry->entry_length_handler != NULL);
+
+ return attr_table_entry->entry_length_handler(entry);
+}
+
+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);
+}
+
+uint8_t pldm_bios_table_attr_value_entry_decode_attribute_type(
+ const struct pldm_bios_attr_val_table_entry *entry)
+{
+ return entry->attr_type;
+}
+
+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;
+}
+
+void pldm_bios_table_attr_value_entry_encode_enum(
+ void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
+ uint8_t count, const uint8_t *handles)
+{
+ size_t length =
+ pldm_bios_table_attr_value_entry_encode_enum_length(count);
+ assert(length <= entry_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);
+}
+
+uint8_t pldm_bios_table_attr_value_entry_enum_decode_number(
+ const struct pldm_bios_attr_val_table_entry *entry)
+{
+ return entry->value[0];
+}
+
+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);
+ number = number < curr_num ? number : curr_num;
+ memcpy(handles, &entry->value[1], number);
+
+ return number;
+}
+
+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, uint8_t *handles)
+{
+ POINTER_CHECK(entry);
+ 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);
+ pldm_bios_table_attr_value_entry_encode_enum(
+ entry, entry_length, attr_handle, attr_type, count, handles);
+ return PLDM_SUCCESS;
+}
+
+static size_t attr_value_table_entry_length_enum(const void *entry)
+{
+ uint8_t number =
+ pldm_bios_table_attr_value_entry_enum_decode_number(entry);
+ return pldm_bios_table_attr_value_entry_encode_enum_length(number);
+}
+
+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;
+}
+
+void pldm_bios_table_attr_value_entry_encode_string(
+ void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
+ uint16_t str_length, const char *str)
+{
+ size_t length =
+ pldm_bios_table_attr_value_entry_encode_string_length(str_length);
+ assert(length <= entry_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));
+}
+
+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);
+}
+
+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)
+}
+
+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);
+ pldm_bios_table_attr_value_entry_encode_string(
+ entry, entry_length, attr_handle, attr_type, str_length, str);
+ return PLDM_SUCCESS;
+}
+
+static size_t attr_value_table_entry_length_string(const void *entry)
+{
+ uint16_t str_length =
+ pldm_bios_table_attr_value_entry_string_decode_length(entry);
+ return pldm_bios_table_attr_value_entry_encode_string_length(
+ str_length);
+}
+
+size_t pldm_bios_table_attr_value_entry_encode_integer_length()
+{
+ return sizeof(struct pldm_bios_attr_val_table_entry) - 1 +
+ sizeof(uint64_t);
+}
+void pldm_bios_table_attr_value_entry_encode_integer(void *entry,
+ size_t entry_length,
+ uint16_t attr_handle,
+ uint8_t attr_type,
+ uint64_t cv)
+{
+ size_t length =
+ pldm_bios_table_attr_value_entry_encode_integer_length();
+ assert(length <= entry_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));
+}
+
+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);
+ pldm_bios_table_attr_value_entry_encode_integer(
+ entry, entry_length, attr_handle, attr_type, cv);
+ return PLDM_SUCCESS;
+}
+
+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 size_t attr_value_table_entry_length_integer(const void *entry)
+{
+ (void)entry;
+ return pldm_bios_table_attr_value_entry_encode_integer_length();
+}
+
+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 size_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);
+ assert(entry_length->entry_length_handler != NULL);
+
+ return entry_length->entry_length_handler(entry);
+}
+
+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);
+}
+
+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);
+}
+
+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;
+}
+
+size_t pldm_bios_table_append_pad_checksum(void *table, size_t size,
+ size_t size_without_pad)
+{
+
+ size_t pad_checksum_size =
+ pldm_bios_table_pad_checksum_size(size_without_pad);
+ size_t total_length = size_without_pad + pad_checksum_size;
+ assert(size >= total_length);
+
+ uint8_t *table_end = (uint8_t *)table + size_without_pad;
+ size_t pad_size = pad_size_get(size_without_pad);
+ table_end = pad_append(table_end, pad_size);
+
+ uint32_t checksum = pldm_crc32(table, size_without_pad + pad_size);
+ checksum_append(table_end, checksum);
+
+ return total_length;
+}
+
+struct pldm_bios_table_iter {
+ const uint8_t *table_data;
+ size_t table_len;
+ size_t current_pos;
+ size_t (*entry_length_handler)(const void *table_entry);
+};
+
+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);
+ 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;
+}
+
+void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter)
+{
+ free(iter);
+}
+
+#define pad_and_check_max 7
+bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter)
+{
+ if (iter->table_len - iter->current_pos <= pad_and_check_max)
+ return true;
+ return false;
+}
+
+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;
+ iter->current_pos += iter->entry_length_handler(entry);
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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);
+}
+
+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, *to_update = entry;
+ size_t buffer_length = *dest_length, copied_length = 0, 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;
+ }
+
+ *dest_length = pldm_bios_table_append_pad_checksum(
+ dest_table, buffer_length, copied_length);
+out:
+ pldm_bios_table_iter_free(iter);
+ return rc;
+}
+
+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 = pldm_crc32(table, size - 4);
+
+ return src_crc == dst_crc;
+}
diff --git a/pldm/libpldm/bios_table.h b/pldm/libpldm/bios_table.h
new file mode 100644
index 00000000..284efcb8
--- /dev/null
+++ b/pldm/libpldm/bios_table.h
@@ -0,0 +1,728 @@
+#ifndef BIOS_TABLE_H__
+#define BIOS_TABLE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "bios.h"
+#include "utils.h"
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+/** @struct pldm_bios_table_iter
+ * structure representing bios table iterator
+ */
+struct pldm_bios_table_iter;
+
+/** @brief Create a bios table iterator
+ * @param[in] table - Pointer to table data
+ * @param[in] length - Length of table data
+ * @param[in] type - Type of pldm bios table
+ * @return Iterator to the beginning
+ */
+struct pldm_bios_table_iter *
+pldm_bios_table_iter_create(const void *table, size_t length,
+ enum pldm_bios_table_types type);
+
+/** @brief Release a bios table iterator
+ * @param[in] iter - Pointer to bios table iterator
+ */
+void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter);
+
+/** @brief Check if the iterator reaches the end of the bios table
+ * @param[in] iter - Pointer to the bios table iterator
+ * @return true if iterator reaches the end
+ * @note *end* is a position after the last entry.
+ */
+bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter);
+
+/** @brief Get iterator to next entry
+ * @param[in] iter - Pointer the bios table iterator
+ */
+void pldm_bios_table_iter_next(struct pldm_bios_table_iter *iter);
+
+/** @brief Get the bios table entry that the iterator points to
+ * @param[in] iter - Pointer to the bios table iterator
+ * @return Pointer to an entry in bios table
+ */
+const void *pldm_bios_table_iter_value(struct pldm_bios_table_iter *iter);
+
+/** @brief Get the bios attribute table entry that the iterator points to
+ * @param[in] iter - Pointer the bios attribute table iterator
+ * @return Pointer to an entry in bios attribute table
+ */
+static inline const struct pldm_bios_attr_table_entry *
+pldm_bios_table_iter_attr_entry_value(struct pldm_bios_table_iter *iter)
+{
+ return (const struct pldm_bios_attr_table_entry *)
+ pldm_bios_table_iter_value(iter);
+}
+
+/** @brief Get the bios string table entry that the iterator ponit to
+ * @param[in] iter - Pointer the bios string table iterator
+ * @return Pointer to an entry in bios string table
+ */
+static inline const struct pldm_bios_string_table_entry *
+pldm_bios_table_iter_string_entry_value(struct pldm_bios_table_iter *iter)
+{
+ return (const struct pldm_bios_string_table_entry *)
+ pldm_bios_table_iter_value(iter);
+}
+
+/** @brief Get the bios attribute value table entry that the iterator ponit to
+ * @param[in] iter - Pointer the bios attribute value table iterator
+ * @return Pointer to an entry in bios attribute value table
+ */
+static inline const struct pldm_bios_attr_val_table_entry *
+pldm_bios_table_iter_attr_value_entry_value(struct pldm_bios_table_iter *iter)
+{
+ return (const struct pldm_bios_attr_val_table_entry *)
+ pldm_bios_table_iter_value(iter);
+}
+
+/** @brief Get the length of an entry in the BIOS String Table
+ * @param[in] string_length - Length of string
+ * @return Length of an entry in bytes
+ */
+size_t pldm_bios_table_string_entry_encode_length(uint16_t string_length);
+
+/** @brief Create an entry of BIOS String Table
+ * @param[out] entry - Pointer to a buffer to create an entry
+ * @param[in] entry_length - Length of the buffer to create an entry
+ * @param[in] str - String itself
+ * @param[in] str_length - Length of the string
+ */
+void pldm_bios_table_string_entry_encode(void *entry, size_t entry_length,
+ const char *str, uint16_t str_length);
+
+/** @brief Create an entry of BIOS String Table and check the validity of the
+ * parameters
+ * @param[out] entry - Pointer to a buffer to create an entry
+ * @param[in] entry_length - Length of the buffer to create an entry
+ * @param[in] str - String itself
+ * @param[in] str_length - Length of the string
+ * @return pldm_completion_codes
+ */
+int pldm_bios_table_string_entry_encode_check(void *entry, size_t entry_length,
+ const char *str,
+ uint16_t str_length);
+
+/** @brief Get the string handle for the entry
+ * @param[in] entry - Pointer to a bios string table entry
+ * @return Handle to identify a string in the bios string table
+ */
+uint16_t pldm_bios_table_string_entry_decode_handle(
+ const struct pldm_bios_string_table_entry *entry);
+
+/** @brief Get the string length for the entry
+ * @param[in] entry - Pointer to a bios string table entry
+ * @return Length of string in bytes
+ */
+uint16_t pldm_bios_table_string_entry_decode_string_length(
+ const struct pldm_bios_string_table_entry *entry);
+
+/** @brief Get the string(at most one less than *size* characters) from the
+ * entry
+ * @param[in] entry - Pointer to a bios string table entry
+ * @param[out] buffer - Pointer to a buffer to store the string
+ * @param[in] size - Size of the buffer to store the string
+ * @return Length of the string decoded
+ */
+uint16_t pldm_bios_table_string_entry_decode_string(
+ const struct pldm_bios_string_table_entry *entry, char *buffer,
+ size_t size);
+
+/** @brief Get the string from the entry and check the validity of the
+ * parameters
+ * @param[in] entry - Pointer to a bios string table entry
+ * @param[out] buffer - Pointer to a buffer to store the string
+ * @param[in] size - Size of the buffer to store the string
+ * @return pldm_completion_codes
+ */
+int pldm_bios_table_string_entry_decode_string_check(
+ const struct pldm_bios_string_table_entry *entry, char *buffer,
+ size_t size);
+
+/** @brief Find an entry in bios string table by string
+ * @param[in] table - The BIOS String Table
+ * @param[in] length - Length of the BIOS String Table
+ * @param[in] str - String itself
+ * @return Pointer to an entry in the bios string table
+ */
+const struct pldm_bios_string_table_entry *
+pldm_bios_table_string_find_by_string(const void *table, size_t length,
+ const char *str);
+/** @brief Find an entry in bios string table by handle
+ * @param[in] table - The BIOS String Table
+ * @param[in] length - Length of the BIOS String Table
+ * @param[in] handle - Handle to identify a string in the bios string table
+ * @return Pointer to an entry in the bios string table
+ */
+const struct pldm_bios_string_table_entry *
+pldm_bios_table_string_find_by_handle(const void *table, size_t length,
+ uint16_t handle);
+
+/** @brief Get the attribute handle from the attribute table entry
+ * @param[in] entry - Pointer to bios attribute table entry
+ * @return handle to identify the attribute in the attribute table
+ */
+uint16_t pldm_bios_table_attr_entry_decode_attribute_handle(
+ const struct pldm_bios_attr_table_entry *entry);
+
+/** @brief Get the attribute type of the attribute table entry
+ * @param[in] entry - Pointer to bios attribute table entry
+ * @return Type of the attribute table entry
+ */
+uint8_t pldm_bios_table_attr_entry_decode_attribute_type(
+ const struct pldm_bios_attr_table_entry *entry);
+
+/** @brief Get the attribute name handle from the attribute table entry
+ * @param[in] entry - Pointer to bios attribute table entry
+ * @return handle to identify the name of the attribute, this handle points
+ * to a string in the bios string table.
+ */
+uint16_t pldm_bios_table_attr_entry_decode_string_handle(
+ const struct pldm_bios_attr_table_entry *entry);
+
+/** @brief Find an entry in attribute table by handle
+ * @param[in] table - The BIOS Attribute Table
+ * @param[in] length - Length of the BIOS Attribute Table
+ * @param[in] handle - handle to identify the attribute in the attribute table
+ * @return Pointer to the entry
+ */
+const struct pldm_bios_attr_table_entry *
+pldm_bios_table_attr_find_by_handle(const void *table, size_t length,
+ uint16_t handle);
+
+/** @brief Find an entry in attribute table by string handle
+ * @param[in] table - The BIOS Attribute Table
+ * @param[in] length - Length of the BIOS Attribute Table
+ * @param[in] handle - The string handle
+ * @return Pointer to the entry
+ */
+const struct pldm_bios_attr_table_entry *
+pldm_bios_table_attr_find_by_string_handle(const void *table, size_t length,
+ uint16_t handle);
+
+/** @struct pldm_bios_table_attr_entry_enum_info
+ *
+ * An auxiliary structure for passing parameters to @ref
+ * pldm_bios_table_attr_entry_enum_encode
+ *
+ */
+struct pldm_bios_table_attr_entry_enum_info {
+ uint16_t name_handle; //!< attribute name handle
+ bool read_only; //!< indicate whether the attribute is read-only
+ uint8_t pv_num; //!< number of possible values
+ const uint16_t *pv_handle; //!< handles of possible values
+ uint8_t def_num; //!< nnumber of default values
+ const uint8_t *def_index; //!< indices of default values.
+};
+
+/** @brief Get length that an attribute entry(type: enum) will take
+ * @param[in] pv_num - Number of possible values
+ * @param[in] def_num - Number of default values
+ * @return The length that an entry(type: enum) will take
+ */
+size_t pldm_bios_table_attr_entry_enum_encode_length(uint8_t pv_num,
+ uint8_t def_num);
+
+/** @brief Create an entry of BIOS Attribute Table (type: enum)
+ * @param[out] entry - Pointer to a buffer to create an entry
+ * @param[in] entry_length - Length of the buffer to create an entry
+ * @param[in] info - Pointer to an auxiliary structure @ref
+ * pldm_bios_table_attr_entry_enum_info
+ */
+void pldm_bios_table_attr_entry_enum_encode(
+ void *entry, size_t entry_length,
+ const struct pldm_bios_table_attr_entry_enum_info *info);
+
+/** @brief Create an entry of BIOS Attribute Table (type: enum) and check the
+ * validity of the parameters
+ * @param[out] entry - Pointer to a buffer to create an entry
+ * @param[in] entry_length - Length of the buffer to create an entry
+ * @param[in] info - Pointer to an auxiliary structure @ref
+ * pldm_bios_table_attr_entry_enum_info
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Get the total number of possible values for the entry
+ * @param[in] entry - Pointer to bios attribute table entry
+ * @return total number of possible values
+ */
+uint8_t pldm_bios_table_attr_entry_enum_decode_pv_num(
+ const struct pldm_bios_attr_table_entry *entry);
+
+/** @brief Get the total number of possible values for the entry and check the
+ * validity of the parameters
+ * @param[in] entry - Pointer to bios attribute table entry
+ * @param[out] pv_num - Pointer to total number of possible values
+ * @return pldm_completion_codes
+ */
+int pldm_bios_table_attr_entry_enum_decode_pv_num_check(
+ const struct pldm_bios_attr_table_entry *entry, uint8_t *pv_num);
+
+/** @brief Get the total number of default values for the entry
+ * @param[in] entry - Pointer to bios attribute table entry
+ * @return total number of default values
+ */
+uint8_t pldm_bios_table_attr_entry_enum_decode_def_num(
+ const struct pldm_bios_attr_table_entry *entry);
+
+/** @brief Get the total number of default values for the entry and check the
+ * validity of the parameters
+ * @param[in] entry - Pointer to bios attribute table entry
+ * @param[out] def_num - Pointer to total number of default values
+ * @return pldm_completion_codes
+ */
+int pldm_bios_table_attr_entry_enum_decode_def_num_check(
+ const struct pldm_bios_attr_table_entry *entry, uint8_t *def_num);
+
+/** @brief Get possible values string handles
+ * @param[in] entry - Pointer to bios attribute table entry
+ * @param[out] pv_hdls - Pointer to a buffer to stroe
+ * PossibleValuesStringHandles
+ * @param[in] pv_num - Number of PossibleValuesStringHandles expected
+ * @return pldm_completion_codes
+ */
+uint8_t pldm_bios_table_attr_entry_enum_decode_pv_hdls(
+ const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
+ uint8_t pv_num);
+
+/** @brief Get possible values string handles and check the validity of the
+ * parameters
+ * @param[in] entry - Pointer to bios attribute table entry
+ * @param[out] pv_hdls - Pointer to a buffer to stroe
+ * PossibleValuesStringHandles
+ * @param[in] pv_num - Number of PossibleValuesStringHandles the buffer can
+ * stroe
+ * @return Number of PossibleValuesStringHandles decoded
+ */
+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);
+
+/** @brief Get Indices of default values
+ * @param[in] entry - Pointer to bios attribute table entry
+ * @param[out] def_indices - Pointer to a buffer to store
+ * default value indices
+ * @param[in] def_num - Number of DefaultValues the buffer can
+ * store
+ * @return Number of default values decoded
+ */
+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);
+
+/** @struct pldm_bios_table_attr_entry_string_info
+ *
+ * An auxiliary structure for passing parameters to @ref
+ * pldm_bios_table_attr_entry_string_encode
+ *
+ */
+struct pldm_bios_table_attr_entry_string_info {
+ uint16_t name_handle; //!< attribute name handle
+ bool read_only; //!< indicate whether the attribute is read-only
+ uint8_t string_type; //!< The type of the string
+ uint16_t min_length; //!< The minimum length of the string in bytes
+ uint16_t max_length; //!< The maximum length of the string in bytes
+ uint16_t def_length; //!< The length of the defaut string in bytes
+ const char *def_string; //!< The default string itself
+};
+
+/** @brief Check fields in @ref pldm_bios_table_attr_entry_string_info
+ * @param[in] info - Pointer to the pldm_bios_table_attr_entry_string_info
+ * @param[out] errmsg - Pointer to an errmsg stored in the statically allocated
+ * memory
+ * @return pldm_completion_codes
+ */
+int pldm_bios_table_attr_entry_string_info_check(
+ const struct pldm_bios_table_attr_entry_string_info *info,
+ const char **errmsg);
+
+/** @brief Get length that an attribute entry(type: string) will take
+ * @param[in] def_str_len - Length of default string
+ * @return The length that an entry(type: string) will take
+ */
+size_t pldm_bios_table_attr_entry_string_encode_length(uint16_t def_str_len);
+
+/** @brief Create an entry of BIOS Attribute Table (type: string)
+ * @param[out] entry - Pointer to a buffer to create an entry
+ * @param[in] entry_length - Length of the buffer to create an entry
+ * @param[in] info - Pointer to an auxiliary structure @ref
+ * pldm_bios_table_attr_entry_string_info
+ */
+void pldm_bios_table_attr_entry_string_encode(
+ void *entry, size_t entry_length,
+ const struct pldm_bios_table_attr_entry_string_info *info);
+
+/** @brief Create an entry of BIOS Attribute Table (type: string) and check the
+ * validity of the parameters
+ * @param[out] entry - Pointer to a buffer to create an entry
+ * @param[in] entry_length - Length of the buffer to create an entry
+ * @param[in] info - Pointer to an auxiliary structure @ref
+ * pldm_bios_table_attr_entry_string_info
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Get the length of default string in bytes for the entry
+ * @param[in] entry - Pointer to bios attribute table entry
+ * @return length of default string in bytes
+ */
+uint16_t pldm_bios_table_attr_entry_string_decode_def_string_length(
+ const struct pldm_bios_attr_table_entry *entry);
+
+/** @brief Get the length of default string in bytes for the entry and check the
+ * validity of the parameters
+ * @param[in] entry - Pointer to bios attribute table entry
+ * @param[out] def_string_length Pointer to length of default string in bytes
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Get the type of string of bios attribute table entry
+ * @param[in] entry - Pointer to bios attribute table entry
+ * @return Type of the string
+ */
+uint8_t pldm_bios_table_attr_entry_string_decode_string_type(
+ const struct pldm_bios_attr_table_entry *entry);
+
+/** @brief Get maximum length of the string from a bios attribute table entry in
+ * bytes
+ * @param[in] entry - Pointer to a bios attribute table entry
+ * @return Maximum length of the string
+ */
+uint16_t pldm_bios_table_attr_entry_string_decode_max_length(
+ const struct pldm_bios_attr_table_entry *entry);
+
+/** @brief Get minimum length of the string from a bios attribute table entry in
+ * bytes
+ * @param[in] entry - Pointer to a bios attribute table entry
+ * @return Minimum length of the string
+ */
+uint16_t pldm_bios_table_attr_entry_string_decode_min_length(
+ const struct pldm_bios_attr_table_entry *entry);
+
+/** @brief Get the default string from a bios attribute table entry
+ * @param[out] buffer - Pointer to a buffer to store the string
+ * @param[in] size - Size of the buffer to store the string
+ * @return Length of the string decoded
+ */
+uint16_t pldm_bios_table_attr_entry_string_decode_def_string(
+ const struct pldm_bios_attr_table_entry *entry, char *buffer, size_t size);
+
+/** @struct pldm_bios_table_attr_entry_integer_info
+ *
+ * An auxiliary structure for passing parameters to @ref
+ * pldm_bios_table_attr_entry_integer_encode
+ *
+ */
+struct pldm_bios_table_attr_entry_integer_info {
+ uint16_t name_handle; //!< attribute name handle
+ bool read_only; //!< indicate whether the attribute is read-only
+ uint64_t lower_bound; //!< The lower bound on the integer value
+ uint64_t upper_bound; //!< The upper bound on the integer value
+ uint32_t scalar_increment; //!< The scalar value that is used for the
+ //!< increments to this integer
+ uint64_t default_value; //!< The default value of the integer
+};
+
+/** @brief Check fields in @ref pldm_bios_table_attr_entry_integer_info
+ * @param[in] info - Pointer to the pldm_bios_table_attr_entry_integer_info
+ * @param[out] errmsg - Pointer to an errmsg stored in the statically allocated
+ * memory
+ * @return pldm_completion_codes
+ */
+int pldm_bios_table_attr_entry_integer_info_check(
+ const struct pldm_bios_table_attr_entry_integer_info *info,
+ const char **errmsg);
+
+/** @brief Get length that an attribute entry(type: integer) will take
+ * @return The length that an entry(type: integer) will take
+ */
+size_t pldm_bios_table_attr_entry_integer_encode_length();
+
+/** @brief Create an entry of BIOS Attribute Table (type: integer)
+ * @param[out] entry - Pointer to a buffer to create an entry
+ * @param[in] entry_length - Length of the buffer to create an entry
+ * @param[in] info - Pointer to an auxiliary structure @ref
+ * pldm_bios_table_attr_entry_integer_info
+ */
+void pldm_bios_table_attr_entry_integer_encode(
+ void *entry, size_t entry_length,
+ const struct pldm_bios_table_attr_entry_integer_info *info);
+
+/** @brief Create an entry of BIOS Attribute Table (type: integer) and check the
+ * validity of the parameters
+ * @param[out] entry - Pointer to a buffer to create an entry
+ * @param[in] entry_length - Length of the buffer to create an entry
+ * @param[in] info - Pointer to an auxiliary structure @ref
+ * pldm_bios_table_attr_entry_integer_info
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Decode the specific fields(integer) of attribute table entry
+ * @param[in] entry - Pointer to an entry of attribute table
+ * @param[out] lower - The lower bound on the integer value
+ * @param[out] upper - The upper bound on the integer value
+ * @param[out] scalar - The scalar value that is used for the increments to
+ * this integer
+ * @param[out] def - The default value of the integer
+ */
+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);
+
+/** @brief Get the attribute handle from the attribute value table entry
+ * @param[in] entry - Pointer to bios attribute value table entry
+ * @return handle to identify the attribute in the attribute value table
+ */
+uint16_t pldm_bios_table_attr_value_entry_decode_attribute_handle(
+ const struct pldm_bios_attr_val_table_entry *entry);
+
+/** @brief Get the attribute type from the attribute value table entry
+ * @param[in] entry - Pointer to bios attribute value table entry
+ * @return Type of the attribute value entry
+ */
+uint8_t pldm_bios_table_attr_value_entry_decode_attribute_type(
+ const struct pldm_bios_attr_val_table_entry *entry);
+
+/** @brief Get length that an attribute value entry(type: enum) will take
+ * @param[in] count - Total number of current values for this enumeration
+ * @return The length that an entry(type: enum) will take
+ */
+size_t pldm_bios_table_attr_value_entry_encode_enum_length(uint8_t count);
+
+/** @brief Create an attribute value entry(type: enum)
+ * @param[out] entry - Pointer to bios attribute value entry
+ * @param[in] entry_length - Length of attribute value entry
+ * @param[in] attr_handle - This handle points to an attribute in the
+ * BIOS Attribute Vlaue Table.
+ * @param[in] attr_type - Type of this attribute in the BIOS Attribute Value
+ * Table
+ * @param[in] count - Total number of current values for this enum attribute
+ * @param[in] handle_indexes - Index into the array(provided in the BIOS
+ * Attribute Table) of the possible values of string handles for this attribute.
+ */
+void pldm_bios_table_attr_value_entry_encode_enum(
+ void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
+ uint8_t count, const uint8_t *handle_indexes);
+
+/** @brief Get number of current values for the enum entry
+ * @param[in] entry - Pointer to bios attribute value table entry
+ * @return Total number of current values for this enumeration
+ */
+uint8_t pldm_bios_table_attr_value_entry_enum_decode_number(
+ const struct pldm_bios_attr_val_table_entry *entry);
+
+/** @brief Get CurrentValueStringHandleIndex
+ * @param[in] entry - Pointer to bios attribute value table entry
+ * @param[in, out] handles - Pointer to a buffer to store
+ * CurrentValueStringHandleIndex
+ * @param[in] number - Number of PossibleValuesStringHandles expected
+ * @return Number of CurrentValueStringHandleIndex decoded.
+ */
+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);
+
+/** @brief Create an attribute value entry(type: enum) and check the validity of
+ * the parameters
+ * @param[out] entry - Pointer to bios attribute value entry
+ * @param[in] entry_length - Length of attribute value entry
+ * @param[in] attr_handle - This handle points to an attribute in the
+ * BIOS Attribute Vlaue Table.
+ * @param[in] attr_type - Type of this attribute in the BIOS Attribute Value
+ * Table
+ * @param[in] count - Total number of current values for this enum attribute
+ * @param[in] handle_indexes - Index into the array(provided in the BIOS
+ * Attribute Table) of the possible values of string handles for this attribute.
+ * @return pldm_completion_codes
+ */
+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, uint8_t *handle_indexes);
+
+/** @brief Get length that an attribute value entry(type: string) will take
+ * @param[in] string_length - Length of the current string in byte, 0 indicates
+ * that the current string value is not set.
+ * @return The length that an entry(type: string) will take
+ */
+size_t
+pldm_bios_table_attr_value_entry_encode_string_length(uint16_t string_length);
+
+/** @brief Create an attribute value entry(type: string)
+ * @param[out] entry - Pointer to bios attribute value entry
+ * @param[in] entry_length - Length of attribute value entry
+ * @param[in] attr_handle - This handle points to an attribute in the
+ * BIOS Attribute Vlaue Table.
+ * @param[in] attr_type - Type of this attribute in the BIOS Attribute Value
+ * Table
+ * @param[in] string_length - Length of current string in bytes. 0 indicates
+ * that the current string value is not set.
+ * @param[in] string - The current string itsel
+ */
+void pldm_bios_table_attr_value_entry_encode_string(
+ void *entry, size_t entry_length, uint16_t attr_handle, uint8_t attr_type,
+ uint16_t string_length, const char *string);
+
+/** @brief Get length of the current string in bytes
+ * @param [in] entry - Pointer to bios attribute value table entry
+ * @return The length of the current string in bytes
+ */
+uint16_t pldm_bios_table_attr_value_entry_string_decode_length(
+ const struct pldm_bios_attr_val_table_entry *entry);
+
+/** @brief Get Current String Itself
+ * @param[in] entry - Pointer to bios attribute value table entry
+ * @param[in, out] current_string - Struct variable_field, contains a pointer
+ * to the CurrentString field in the buffer of
+ * \p entry, \p entry must be valid
+ * when \p current_string is used.
+ */
+void pldm_bios_table_attr_value_entry_string_decode_string(
+ const struct pldm_bios_attr_val_table_entry *entry,
+ struct variable_field *current_string);
+
+/** @brief Create an attribute value entry(type: string) and check the validity
+ * of the parameters
+ * @param[out] entry - Pointer to bios attribute value entry
+ * @param[in] entry_length - Length of attribute value entry
+ * @param[in] attr_handle - This handle points to an attribute in the
+ * BIOS Attribute Vlaue Table.
+ * @param[in] attr_type - Type of this attribute in the BIOS Attribute Value
+ * Table
+ * @param[in] string_length - Length of current string in bytes. 0 indicates
+ * that the current string value is not set.
+ * @param[in] string - The current string itsel
+ * @return pldm_completion_codes
+ */
+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 string_length, const char *string);
+
+/** @brief Get length that an attribute value entry(type: integer) will take
+ * @return The length that an entry(type: integer) will take
+ */
+size_t pldm_bios_table_attr_value_entry_encode_integer_length();
+
+/** @brief Create an attribute value entry(type: integer)
+ * @param[out] entry - Pointer to bios attribute value entry
+ * @param[in] entry_length - Length of attribute value entry
+ * @param[in] attr_handle - This handle points to an attribute in the
+ * BIOS Attribute Vlaue Table.
+ * @param[in] attr_type - Type of this attribute in the BIOS Attribute Value
+ * Table
+ * @param[in] cv - Current Value
+ */
+void pldm_bios_table_attr_value_entry_encode_integer(void *entry,
+ size_t entry_length,
+ uint16_t attr_handle,
+ uint8_t attr_type,
+ uint64_t cv);
+
+/** @brief Get current values for the integer entry
+ * @param[in] entry - Pointer to bios attribute value table entry
+ * @return Current Value
+ */
+uint64_t pldm_bios_table_attr_value_entry_integer_decode_cv(
+ const struct pldm_bios_attr_val_table_entry *entry);
+
+/** @brief Create an attribute value entry(type: integer) and check the validity
+ * of the parameters
+ * @param[out] entry - Pointer to bios attribute value entry
+ * @param[in] entry_length - Length of attribute value entry
+ * @param[in] attr_handle - This handle points to an attribute in the
+ * BIOS Attribute Vlaue Table.
+ * @param[in] attr_type - Type of this attribute in the BIOS Attribute Value
+ * Table
+ * @param[in] cv - Current Value
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Get the handle from the attribute value entry
+ * @param[in] entry - Pointer to bios attribute value entry
+ * @return handle to identify the attribute in the attribute value table
+ */
+uint16_t pldm_bios_table_attr_value_entry_decode_handle(
+ const struct pldm_bios_attr_val_table_entry *entry);
+
+/** @brief Get the length of the attribute value entry
+ * @param[in] entry - Pointer to bios attribute value entry
+ * @return Length of the entry
+ */
+size_t pldm_bios_table_attr_value_entry_length(
+ const struct pldm_bios_attr_val_table_entry *entry);
+
+/** @brief Find an entry in attribute value table by handle
+ * @param[in] table - The BIOS Attribute Value Table
+ * @param[in] length - Length of the BIOS Attribute Value Table
+ * @param[in] handle - handle to identify the attribute in the attribute value
+ * table
+ * @return Pointer to the entry
+ */
+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);
+
+/** @brief Get the size of pad and checksum
+ * @param[in] size_without_pad - Table size without pad
+ * @return The size of pad and checksum
+ */
+size_t pldm_bios_table_pad_checksum_size(size_t size_without_pad);
+
+/** @brief Append pad and checksum at the end of the table
+ * @param[in,out] table - Pointer to a buffer of a bios table
+ * @param[in] size - Size of the buffer of a bios table
+ * @param[in] size_without_pad - Table size without pad and checksum
+ * @return Total size of the table
+ */
+size_t pldm_bios_table_append_pad_checksum(void *table, size_t size,
+ size_t size_without_pad);
+
+/** @brief Build a new table and update an entry
+ * @param[in] src_table - Pointer to the source table
+ * @param[in] src_length - Size of the source table
+ * @param[out] dest_table - Pointer to the buffer of destination table
+ * @param[in,out] dest_length - Buffer size of the destination table as input
+ * parameter and will be assigned the length of
+ * the new table, if the function returns
+ * PLDM_SUCCESS
+ * @param[in] entry - Pointer to an entry
+ * @param[in] entry_length - Size of the entry
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Verify the crc value of the complete table
+ * @param[in] table - Pointer to a buffer of a bios table
+ * @param[in] size - Size of the buffer of a bios table
+ * @return true: crc value is correct
+ */
+bool pldm_bios_table_checksum(const uint8_t *table, size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/pldm/libpldm/entity.h b/pldm/libpldm/entity.h
new file mode 100644
index 00000000..9e657c11
--- /dev/null
+++ b/pldm/libpldm/entity.h
@@ -0,0 +1,149 @@
+#ifndef ENTITY_H
+#define ENTITY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @brief PLDM Entity ID Codes in DSP0249_1.1.0 specification
+ */
+enum pldm_entity_id_codes {
+ PLDM_ENTITY_UNSPECIFIED = 0,
+ PLDM_ENTITY_OTHER = 1,
+
+ /* Miscellaneous Entities */
+ PLDM_ENTITY_NETWORK = 2,
+ PLDM_ENTITY_GROUP = 3,
+ PLDM_ENTITY_REMOTE_MGMT_COMM_DEVICE = 4,
+ PLDM_ENTITY_EXTERNAL_ENVIRONMENT = 5,
+ PLDM_ENTITY_COMM_CHANNEL = 6,
+ PLDM_ENTITY_TERMINUS = 7,
+ PLDM_ENTITY_PLATFORM_EVENT_LOG = 8,
+
+ /* Human Interface Entities */
+ PLDM_ENTITY_KEYPAD = 15,
+ PLDM_ENTITY_SWITCH = 16,
+ PLDM_ENTITY_PUSHBUTTON = 17,
+ PLDM_ENTITY_DISPLAY = 18,
+ PLDM_ENTITY_INDICATOR = 19,
+
+ /* Software/Firmware Entities */
+ PLDM_ENTITY_SYS_MGMT_SW = 30,
+ PLDM_ENTITY_SYS_FIRMWARE = 31,
+ PLDM_ENTITY_OPERATING_SYS = 32,
+ PLDM_ENTITY_VIRTUAL_MACHINE_MANAGER = 33,
+ PLDM_ENTITY_OS_LOADER = 34,
+ PLDM_ENTITY_DEVICE_DRIVER = 35,
+ PLDM_ENTITY_MGMT_CONTROLLER_FW = 36,
+
+ /* Chassis/Enclosure Entities */
+ PLDM_ENTITY_SYSTEM_CHASSIS = 45,
+ PLDM_ENTITY_SUB_CHASSIS = 46,
+ PLDM_ENTITY_DISK_DRIVE_BAY = 47,
+ PLDM_ENTITY_PERIPHERAL_BAY = 48,
+ PLDM_ENTITY_DEVICE_BAY = 49,
+ PLDM_ENTITY_DOOR = 50,
+ PLDM_ENTITY_ACCESS_PANEL = 51,
+ PLDM_ENTITY_COVER = 52,
+
+ /* Board/Card/Module Entities */
+ PLDM_ENTITY_BOARD = 60,
+ PLDM_ENTITY_CARD = 61,
+ PLDM_ENTITY_MODULE = 62,
+ PLDM_ENTITY_SYS_MGMT_MODULE = 63,
+ PLDM_ENTITY_SYS_BOARD = 64,
+ PLDM_ENTITY_MEMORY_BOARD = 65,
+ PLDM_ENTITY_MEMORY_MODULE = 66,
+ PLDM_ENTITY_PROC_MODULE = 67,
+ PLDM_ENTITY_ADD_IN_CARD = 68,
+ PLDM_ENTITY_CHASSIS_FRONT_PANEL_BOARD = 69,
+ PLDM_ENTITY_BACK_PANEL_BOARD = 70,
+ PLDM_ENTITY_POWER_MGMT = 71,
+ PLDM_ENTITY_POWER_SYS_BOARD = 72,
+ PLDM_ENTITY_DRIVE_BACKPLANE = 73,
+ PLDM_ENTITY_SYS_INTERNAL_EXPANSION_BOARD = 74,
+ PLDM_ENTITY_OTHER_SYS_BOARD = 75,
+ PLDM_ENTITY_CHASSIS_BACK_PANEL_BOARD = 76,
+ PLDM_ENTITY_PROCESSING_BLADE = 77,
+ PLDM_ENTITY_CONNECTIVITY_SWITCH = 78,
+ PLDM_ENTITY_PROC_MEMORY_MODULE = 79,
+ PLDM_ENTITY_IO_MODULE = 80,
+ PLDM_ENTITY_PROC_IO_MODULE = 81,
+
+ /* Cooling Entities */
+ PLDM_ENTITY_COOLING_DEVICE = 90,
+ PLDM_ENTITY_COOLING_SUBSYSTEM = 91,
+ PLDM_ENTITY_COOLING_UNIT = 92,
+ PLDM_ENTITY_FAN = 93,
+ PLDM_ENTITY_PELTIER_COOLING_DEVICE = 94,
+ PLDM_ENTITY_LIQUID_COOLING_DEVICE = 95,
+ PLDM_ENTITY_LIQUID_COOLING_SUBSYSTEM = 96,
+
+ /* Storage Device Entities */
+ PLDM_ENTITY_OTHER_STORAGE_DEVICE = 105,
+ PLDM_ENTITY_FLOPPY_DRIVE = 106,
+ PLDM_ENTITY_FIXED_DISK_HARD_DRIVE = 107,
+ PLDM_ENTITY_CD_DRIVE = 108,
+ PLDM_ENTITY_CD_DVD_DRIVE = 109,
+ PLDM_ENTITY_OTHER_SILICON_STORAGE_DEVICE = 110,
+ PLDM_ENTITY_SOLID_STATE_SRIVE = 111,
+
+ /* Power Entities */
+ PLDM_ENTITY_POWER_SUPPLY = 120,
+ PLDM_ENTITY_BATTERY = 121,
+ PLDM_ENTITY_SUPER_CAPACITOR = 122,
+ PLDM_ENTITY_POWER_CONVERTER = 123,
+ PLDM_ENTITY_DC_DC_CONVERTER = 124,
+ PLDM_ENTITY_AC_MAINS_POWER_SUPPLY = 125,
+ PLDM_ENTITY_DC_MAINS_POWER_SUPPLY = 126,
+
+ /* Chip Entities */
+ PLDM_ENTITY_PROC = 135,
+ PLDM_ENTITY_CHIPSET_COMPONENT = 136,
+ PLDM_ENTITY_MGMT_CONTROLLER = 137,
+ PLDM_ENTITY_PERIPHERAL_CONTROLLER = 138,
+ PLDM_ENTITY_SEEPROM = 139,
+ PLDM_ENTITY_NVRAM_CHIP = 140,
+ PLDM_ENTITY_FLASH_MEMORY_CHIP = 141,
+ PLDM_ENTITY_MEMORY_CHIP = 142,
+ PLDM_ENTITY_MEMORY_CONTROLLER = 143,
+ PLDM_ENTITY_NETWORK_CONTROLLER = 144,
+ PLDM_ENTITY_IO_CONTROLLER = 145,
+ PLDM_ENTITY_SOUTH_BRIDGE = 146,
+ PLDM_ENTITY_REAL_TIME_CLOCK = 147,
+ PLDM_ENTITY_FPGA_CPLD_DEVICE = 148,
+ /* Bus Entities */
+ PLDM_ENTITY_OTHER_BUS = 160,
+ PLDM_ENTITY_SYS_BUS = 161,
+ PLDM_ENTITY_I2C_BUS = 162,
+ PLDM_ENTITY_SMBUS_BUS = 163,
+ PLDM_ENTITY_SPI_BUS = 164,
+ PLDM_ENTITY_PCI_BUS = 165,
+ PLDM_ENTITY_PCI_EXPRESS_BUS = 166,
+ PLDM_ENTITY_PECI_BUS = 167,
+ PLDM_ENTITY_LPC_BUS = 168,
+ PLDM_ENTITY_USB_BUS = 169,
+ PLDM_ENTITY_FIREWIRE_BUS = 170,
+ PLDM_ENTITY_SCSI_BUS = 171,
+ PLDM_ENTITY_SATA_SAS_BUS = 172,
+ PLDM_ENTITY_PROC_FRONT_SIDE_BUS = 173,
+ PLDM_ENTITY_INTER_PROC_BUS = 174,
+
+ /* Connectors/Cables */
+ PLDM_ENTITY_CONNECTOR = 185,
+ PLDM_ENTITY_SLOT = 186,
+ PLDM_ENTITY_CABLE = 187,
+ PLDM_ENTITY_INTERCONNECT = 188,
+ PLDM_ENTITY_PLUG = 189,
+ PLDM_ENTITY_SOCKET = 190,
+
+ /* OEM ranges */
+ PLDM_OEM_ENTITY_TYPE_START = 24576,
+ PLDM_OEM_ENTITY_TYPE_END = 32767,
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ENTITY_H */
diff --git a/pldm/libpldm/firmware_update.c b/pldm/libpldm/firmware_update.c
new file mode 100644
index 00000000..023fc4f6
--- /dev/null
+++ b/pldm/libpldm/firmware_update.c
@@ -0,0 +1,1567 @@
+#include "firmware_update.h"
+#include <endian.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;
+ }
+}
+
+/** @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) {
+ return true;
+ } else if (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;
+ }
+}
+
+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->timestamp104, data_header->timestamp104,
+ sizeof(data_header->timestamp104));
+ 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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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);
+}
+
+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;
+}
+
+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);
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+int decode_update_component_resp(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint8_t *completion_code,
+ uint8_t *comp_compatability_resp,
+ uint8_t *comp_compatability_resp_code,
+ bitfield32_t *update_option_flags_enabled,
+ uint16_t *time_before_req_fw_data)
+{
+ if (msg == NULL || completion_code == NULL ||
+ comp_compatability_resp == NULL ||
+ comp_compatability_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_compatability_resp)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (!is_comp_compatibility_resp_code_valid(
+ response->comp_compatability_resp_code)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ *comp_compatability_resp = response->comp_compatability_resp;
+ *comp_compatability_resp_code = response->comp_compatability_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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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/pldm/libpldm/firmware_update.h b/pldm/libpldm/firmware_update.h
new file mode 100644
index 00000000..a89ebbe7
--- /dev/null
+++ b/pldm/libpldm/firmware_update.h
@@ -0,0 +1,1132 @@
+#ifndef FW_UPDATE_H
+#define FW_UPDATE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include "base.h"
+#include "stdbool.h"
+#include "utils.h"
+
+#define PLDM_FWUP_COMPONENT_BITMAP_MULTIPLE 8
+#define PLDM_FWUP_INVALID_COMPONENT_COMPARISON_TIMESTAMP 0xFFFFFFFF
+#define PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES 0
+/** @brief Minimum length of device descriptor, 2 bytes for descriptor type,
+ * 2 bytes for descriptor length and atleast 1 byte of descriptor data
+ */
+#define PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN 5
+#define PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES 0
+#define PLDM_FWUP_BASELINE_TRANSFER_SIZE 32
+#define PLDM_FWUP_MIN_OUTSTANDING_REQ 1
+#define PLDM_GET_STATUS_REQ_BYTES 0
+/* Maximum progress percentage value*/
+#define PLDM_FWUP_MAX_PROGRESS_PERCENT 0x65
+#define PLDM_CANCEL_UPDATE_COMPONENT_REQ_BYTES 0
+#define PLDM_CANCEL_UPDATE_REQ_BYTES 0
+
+/** @brief PLDM Firmware update commands
+ */
+enum pldm_firmware_update_commands {
+ PLDM_QUERY_DEVICE_IDENTIFIERS = 0x01,
+ PLDM_GET_FIRMWARE_PARAMETERS = 0x02,
+ PLDM_REQUEST_UPDATE = 0x10,
+ PLDM_PASS_COMPONENT_TABLE = 0x13,
+ PLDM_UPDATE_COMPONENT = 0x14,
+ PLDM_REQUEST_FIRMWARE_DATA = 0x15,
+ PLDM_TRANSFER_COMPLETE = 0x16,
+ PLDM_VERIFY_COMPLETE = 0x17,
+ PLDM_APPLY_COMPLETE = 0x18,
+ PLDM_ACTIVATE_FIRMWARE = 0x1A,
+ PLDM_GET_STATUS = 0x1B,
+ PLDM_CANCEL_UPDATE_COMPONENT = 0x1C,
+ PLDM_CANCEL_UPDATE = 0x1D
+};
+
+/** @brief PLDM Firmware update completion codes
+ */
+enum pldm_firmware_update_completion_codes {
+ PLDM_FWUP_NOT_IN_UPDATE_MODE = 0x80,
+ PLDM_FWUP_ALREADY_IN_UPDATE_MODE = 0x81,
+ PLDM_FWUP_DATA_OUT_OF_RANGE = 0x82,
+ PLDM_FWUP_INVALID_TRANSFER_LENGTH = 0x83,
+ PLDM_FWUP_INVALID_STATE_FOR_COMMAND = 0x84,
+ PLDM_FWUP_INCOMPLETE_UPDATE = 0x85,
+ PLDM_FWUP_BUSY_IN_BACKGROUND = 0x86,
+ PLDM_FWUP_CANCEL_PENDING = 0x87,
+ PLDM_FWUP_COMMAND_NOT_EXPECTED = 0x88,
+ PLDM_FWUP_RETRY_REQUEST_FW_DATA = 0x89,
+ PLDM_FWUP_UNABLE_TO_INITIATE_UPDATE = 0x8A,
+ PLDM_FWUP_ACTIVATION_NOT_REQUIRED = 0x8B,
+ PLDM_FWUP_SELF_CONTAINED_ACTIVATION_NOT_PERMITTED = 0x8C,
+ PLDM_FWUP_NO_DEVICE_METADATA = 0x8D,
+ PLDM_FWUP_RETRY_REQUEST_UPDATE = 0x8E,
+ PLDM_FWUP_NO_PACKAGE_DATA = 0x8F,
+ PLDM_FWUP_INVALID_TRANSFER_HANDLE = 0x90,
+ PLDM_FWUP_INVALID_TRANSFER_OPERATION_FLAG = 0x91,
+ PLDM_FWUP_ACTIVATE_PENDING_IMAGE_NOT_PERMITTED = 0x92,
+ PLDM_FWUP_PACKAGE_DATA_ERROR = 0x93
+};
+
+/** @brief String type values defined in the PLDM firmware update specification
+ */
+enum pldm_firmware_update_string_type {
+ PLDM_STR_TYPE_UNKNOWN = 0,
+ PLDM_STR_TYPE_ASCII = 1,
+ PLDM_STR_TYPE_UTF_8 = 2,
+ PLDM_STR_TYPE_UTF_16 = 3,
+ PLDM_STR_TYPE_UTF_16LE = 4,
+ PLDM_STR_TYPE_UTF_16BE = 5
+};
+
+/** @brief Descriptor types defined in PLDM firmware update specification
+ */
+enum pldm_firmware_update_descriptor_types {
+ PLDM_FWUP_PCI_VENDOR_ID = 0x0000,
+ PLDM_FWUP_IANA_ENTERPRISE_ID = 0x0001,
+ PLDM_FWUP_UUID = 0x0002,
+ PLDM_FWUP_PNP_VENDOR_ID = 0x0003,
+ PLDM_FWUP_ACPI_VENDOR_ID = 0x0004,
+ PLDM_FWUP_IEEE_ASSIGNED_COMPANY_ID = 0x0005,
+ PLDM_FWUP_SCSI_VENDOR_ID = 0x0006,
+ PLDM_FWUP_PCI_DEVICE_ID = 0x0100,
+ PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID = 0x0101,
+ PLDM_FWUP_PCI_SUBSYSTEM_ID = 0x0102,
+ PLDM_FWUP_PCI_REVISION_ID = 0x0103,
+ PLDM_FWUP_PNP_PRODUCT_IDENTIFIER = 0x0104,
+ PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER = 0x0105,
+ PLDM_FWUP_ASCII_MODEL_NUMBER_LONG_STRING = 0x0106,
+ PLDM_FWUP_ASCII_MODEL_NUMBER_SHORT_STRING = 0x0107,
+ PLDM_FWUP_SCSI_PRODUCT_ID = 0x0108,
+ PLDM_FWUP_UBM_CONTROLLER_DEVICE_CODE = 0x0109,
+ PLDM_FWUP_VENDOR_DEFINED = 0xFFFF
+};
+
+/** @brief Descriptor types length defined in PLDM firmware update specification
+ */
+enum pldm_firmware_update_descriptor_types_length {
+ PLDM_FWUP_PCI_VENDOR_ID_LENGTH = 2,
+ PLDM_FWUP_IANA_ENTERPRISE_ID_LENGTH = 4,
+ PLDM_FWUP_UUID_LENGTH = 16,
+ PLDM_FWUP_PNP_VENDOR_ID_LENGTH = 3,
+ PLDM_FWUP_ACPI_VENDOR_ID_LENGTH = 4,
+ PLDM_FWUP_IEEE_ASSIGNED_COMPANY_ID_LENGTH = 3,
+ PLDM_FWUP_SCSI_VENDOR_ID_LENGTH = 8,
+ PLDM_FWUP_PCI_DEVICE_ID_LENGTH = 2,
+ PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID_LENGTH = 2,
+ PLDM_FWUP_PCI_SUBSYSTEM_ID_LENGTH = 2,
+ PLDM_FWUP_PCI_REVISION_ID_LENGTH = 1,
+ PLDM_FWUP_PNP_PRODUCT_IDENTIFIER_LENGTH = 4,
+ PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER_LENGTH = 4,
+ PLDM_FWUP_ASCII_MODEL_NUMBER_LONG_STRING_LENGTH = 40,
+ PLDM_FWUP_ASCII_MODEL_NUMBER_SHORT_STRING_LENGTH = 10,
+ PLDM_FWUP_SCSI_PRODUCT_ID_LENGTH = 16,
+ PLDM_FWUP_UBM_CONTROLLER_DEVICE_CODE_LENGTH = 4
+};
+
+/** @brief ComponentClassification values defined in firmware update
+ * specification
+ */
+enum pldm_component_classification_values {
+ PLDM_COMP_UNKNOWN = 0x0000,
+ PLDM_COMP_OTHER = 0x0001,
+ PLDM_COMP_DRIVER = 0x0002,
+ PLDM_COMP_CONFIGURATION_SOFTWARE = 0x0003,
+ PLDM_COMP_APPLICATION_SOFTWARE = 0x0004,
+ PLDM_COMP_INSTRUMENTATION = 0x0005,
+ PLDM_COMP_FIRMWARE_OR_BIOS = 0x0006,
+ PLDM_COMP_DIAGNOSTIC_SOFTWARE = 0x0007,
+ PLDM_COMP_OPERATING_SYSTEM = 0x0008,
+ PLDM_COMP_MIDDLEWARE = 0x0009,
+ PLDM_COMP_FIRMWARE = 0x000A,
+ PLDM_COMP_BIOS_OR_FCODE = 0x000B,
+ PLDM_COMP_SUPPORT_OR_SERVICEPACK = 0x000C,
+ PLDM_COMP_SOFTWARE_BUNDLE = 0x000D,
+ PLDM_COMP_DOWNSTREAM_DEVICE = 0xFFFF
+};
+
+/** @brief ComponentActivationMethods is the bit position in the bitfield that
+ * provides the capability of the FD for firmware activation. Multiple
+ * activation methods can be supported.
+ */
+enum pldm_comp_activation_methods {
+ PLDM_ACTIVATION_AUTOMATIC = 0,
+ PLDM_ACTIVATION_SELF_CONTAINED = 1,
+ PLDM_ACTIVATION_MEDIUM_SPECIFIC_RESET = 2,
+ PLDM_ACTIVATION_SYSTEM_REBOOT = 3,
+ PLDM_ACTIVATION_DC_POWER_CYCLE = 4,
+ PLDM_ACTIVATION_AC_POWER_CYCLE = 5,
+ PLDM_SUPPORTS_ACTIVATE_PENDING_IMAGE = 6,
+ PLDM_SUPPORTS_ACTIVATE_PENDING_IMAGE_SET = 7
+};
+
+/** @brief ComponentResponse values in the response of PassComponentTable
+ */
+enum pldm_component_responses {
+ PLDM_CR_COMP_CAN_BE_UPDATED = 0,
+ PLDM_CR_COMP_MAY_BE_UPDATEABLE = 1
+};
+
+/** @brief ComponentResponseCode values in the response of PassComponentTable
+ */
+enum pldm_component_response_codes {
+ PLDM_CRC_COMP_CAN_BE_UPDATED = 0x00,
+ PLDM_CRC_COMP_COMPARISON_STAMP_IDENTICAL = 0x01,
+ PLDM_CRC_COMP_COMPARISON_STAMP_LOWER = 0x02,
+ PLDM_CRC_INVALID_COMP_COMPARISON_STAMP = 0x03,
+ PLDM_CRC_COMP_CONFLICT = 0x04,
+ PLDM_CRC_COMP_PREREQUISITES_NOT_MET = 0x05,
+ PLDM_CRC_COMP_NOT_SUPPORTED = 0x06,
+ PLDM_CRC_COMP_SECURITY_RESTRICTIONS = 0x07,
+ PLDM_CRC_INCOMPLETE_COMP_IMAGE_SET = 0x08,
+ PLDM_CRC_ACTIVE_IMAGE_NOT_UPDATEABLE_SUBSEQUENTLY = 0x09,
+ PLDM_CRC_COMP_VER_STR_IDENTICAL = 0x0A,
+ PLDM_CRC_COMP_VER_STR_LOWER = 0x0B,
+ PLDM_CRC_VENDOR_COMP_RESP_CODE_RANGE_MIN = 0xD0,
+ PLDM_CRC_VENDOR_COMP_RESP_CODE_RANGE_MAX = 0xEF
+};
+
+/** @brief ComponentCompatibilityResponse values in the response of
+ * UpdateComponent
+ */
+enum pldm_component_compatability_responses {
+ PLDM_CCR_COMP_CAN_BE_UPDATED = 0,
+ PLDM_CCR_COMP_CANNOT_BE_UPDATED = 1
+};
+
+/** @brief ComponentCompatibilityResponse Code values in the response of
+ * UpdateComponent
+ */
+enum pldm_component_compatability_response_codes {
+ PLDM_CCRC_NO_RESPONSE_CODE = 0x00,
+ PLDM_CCRC_COMP_COMPARISON_STAMP_IDENTICAL = 0x01,
+ PLDM_CCRC_COMP_COMPARISON_STAMP_LOWER = 0x02,
+ PLDM_CCRC_INVALID_COMP_COMPARISON_STAMP = 0x03,
+ PLDM_CCRC_COMP_CONFLICT = 0x04,
+ PLDM_CCRC_COMP_PREREQUISITES_NOT_MET = 0x05,
+ PLDM_CCRC_COMP_NOT_SUPPORTED = 0x06,
+ PLDM_CCRC_COMP_SECURITY_RESTRICTIONS = 0x07,
+ PLDM_CCRC_INCOMPLETE_COMP_IMAGE_SET = 0x08,
+ PLDM_CCRC_COMP_INFO_NO_MATCH = 0x09,
+ PLDM_CCRC_COMP_VER_STR_IDENTICAL = 0x0A,
+ PLDM_CCRC_COMP_VER_STR_LOWER = 0x0B,
+ PLDM_CCRC_VENDOR_COMP_RESP_CODE_RANGE_MIN = 0xD0,
+ PLDM_CCRC_VENDOR_COMP_RESP_CODE_RANGE_MAX = 0xEF
+};
+
+/** @brief Common error codes in TransferComplete, VerifyComplete and
+ * ApplyComplete request
+ */
+enum pldm_firmware_update_common_error_codes {
+ PLDM_FWUP_TIME_OUT = 0x09,
+ PLDM_FWUP_GENERIC_ERROR = 0x0A
+};
+
+/** @brief TransferResult values in the request of TransferComplete
+ */
+enum pldm_firmware_update_transfer_result_values {
+ PLDM_FWUP_TRANSFER_SUCCESS = 0x00,
+ PLDM_FWUP_TRANSFER_ERROR_IMAGE_CORRUPT = 0x02,
+ PLDM_FWUP_TRANSFER_ERROR_VERSION_MISMATCH = 0x02,
+ PLDM_FWUP_FD_ABORTED_TRANSFER = 0x03,
+ PLDM_FWUP_FD_ABORTED_TRANSFER_LOW_POWER_STATE = 0x0B,
+ PLDM_FWUP_FD_ABORTED_TRANSFER_RESET_NEEDED = 0x0C,
+ PLDM_FWUP_FD_ABORTED_TRANSFER_STORAGE_ISSUE = 0x0D,
+ PLDM_FWUP_VENDOR_TRANSFER_RESULT_RANGE_MIN = 0x70,
+ PLDM_FWUP_VENDOR_TRANSFER_RESULT_RANGE_MAX = 0x8F
+};
+
+/**@brief VerifyResult values in the request of VerifyComplete
+ */
+enum pldm_firmware_update_verify_result_values {
+ PLDM_FWUP_VERIFY_SUCCESS = 0x00,
+ PLDM_FWUP_VERIFY_ERROR_VERIFICATION_FAILURE = 0x01,
+ PLDM_FWUP_VERIFY_ERROR_VERSION_MISMATCH = 0x02,
+ PLDM_FWUP_VERIFY_FAILED_FD_SECURITY_CHECKS = 0x03,
+ PLDM_FWUP_VERIFY_ERROR_IMAGE_INCOMPLETE = 0x04,
+ PLDM_FWUP_VENDOR_VERIFY_RESULT_RANGE_MIN = 0x90,
+ PLDM_FWUP_VENDOR_VERIFY_RESULT_RANGE_MAX = 0xAF
+};
+
+/**@brief ApplyResult values in the request of ApplyComplete
+ */
+enum pldm_firmware_update_apply_result_values {
+ PLDM_FWUP_APPLY_SUCCESS = 0x00,
+ PLDM_FWUP_APPLY_SUCCESS_WITH_ACTIVATION_METHOD = 0x01,
+ PLDM_FWUP_APPLY_FAILURE_MEMORY_ISSUE = 0x02,
+ PLDM_FWUP_VENDOR_APPLY_RESULT_RANGE_MIN = 0xB0,
+ PLDM_FWUP_VENDOR_APPLY_RESULT_RANGE_MAX = 0xCF
+};
+
+/** @brief SelfContainedActivationRequest in the request of ActivateFirmware
+ */
+enum pldm_self_contained_activation_req {
+ PLDM_NOT_ACTIVATE_SELF_CONTAINED_COMPONENTS = false,
+ PLDM_ACTIVATE_SELF_CONTAINED_COMPONENTS = true
+};
+
+/** @brief Current state/previous state of the FD or FDP returned in GetStatus
+ * response
+ */
+enum pldm_firmware_device_states {
+ PLDM_FD_STATE_IDLE = 0,
+ PLDM_FD_STATE_LEARN_COMPONENTS = 1,
+ PLDM_FD_STATE_READY_XFER = 2,
+ PLDM_FD_STATE_DOWNLOAD = 3,
+ PLDM_FD_STATE_VERIFY = 4,
+ PLDM_FD_STATE_APPLY = 5,
+ PLDM_FD_STATE_ACTIVATE = 6
+};
+
+/** @brief Firmware device aux state in GetStatus response
+ */
+enum pldm_get_status_aux_states {
+ PLDM_FD_OPERATION_IN_PROGRESS = 0,
+ PLDM_FD_OPERATION_SUCCESSFUL = 1,
+ PLDM_FD_OPERATION_FAILED = 2,
+ PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER = 3
+};
+
+/** @brief Firmware device aux state status in GetStatus response
+ */
+enum pldm_get_status_aux_state_status_values {
+ PLDM_FD_AUX_STATE_IN_PROGRESS_OR_SUCCESS = 0x00,
+ PLDM_FD_TIMEOUT = 0x09,
+ PLDM_FD_GENERIC_ERROR = 0x0A,
+ PLDM_FD_VENDOR_DEFINED_STATUS_CODE_START = 0x70,
+ PLDM_FD_VENDOR_DEFINED_STATUS_CODE_END = 0xEF
+};
+
+/** @brief Firmware device reason code in GetStatus response
+ */
+enum pldm_get_status_reason_code_values {
+ PLDM_FD_INITIALIZATION = 0,
+ PLDM_FD_ACTIVATE_FW = 1,
+ PLDM_FD_CANCEL_UPDATE = 2,
+ PLDM_FD_TIMEOUT_LEARN_COMPONENT = 3,
+ PLDM_FD_TIMEOUT_READY_XFER = 4,
+ PLDM_FD_TIMEOUT_DOWNLOAD = 5,
+ PLDM_FD_TIMEOUT_VERIFY = 6,
+ PLDM_FD_TIMEOUT_APPLY = 7,
+ PLDM_FD_STATUS_VENDOR_DEFINED_MIN = 200,
+ PLDM_FD_STATUS_VENDOR_DEFINED_MAX = 255
+};
+
+/** @brief Components functional indicator in CancelUpdate response
+ */
+enum pldm_firmware_update_non_functioning_component_indication {
+ PLDM_FWUP_COMPONENTS_FUNCTIONING = 0,
+ PLDM_FWUP_COMPONENTS_NOT_FUNCTIONING = 1
+};
+
+/** @struct pldm_package_header_information
+ *
+ * Structure representing fixed part of package header information
+ */
+struct pldm_package_header_information {
+ uint8_t uuid[PLDM_FWUP_UUID_LENGTH];
+ uint8_t package_header_format_version;
+ uint16_t package_header_size;
+ uint8_t timestamp104[PLDM_TIMESTAMP104_SIZE];
+ uint16_t component_bitmap_bit_length;
+ uint8_t package_version_string_type;
+ uint8_t package_version_string_length;
+} __attribute__((packed));
+
+/** @struct pldm_firmware_device_id_record
+ *
+ * Structure representing firmware device ID record
+ */
+struct pldm_firmware_device_id_record {
+ uint16_t record_length;
+ uint8_t descriptor_count;
+ bitfield32_t device_update_option_flags;
+ uint8_t comp_image_set_version_string_type;
+ uint8_t comp_image_set_version_string_length;
+ uint16_t fw_device_pkg_data_length;
+} __attribute__((packed));
+
+/** @struct pldm_descriptor_tlv
+ *
+ * Structure representing descriptor type, length and value
+ */
+struct pldm_descriptor_tlv {
+ uint16_t descriptor_type;
+ uint16_t descriptor_length;
+ uint8_t descriptor_data[1];
+} __attribute__((packed));
+
+/** @struct pldm_vendor_defined_descriptor_title_data
+ *
+ * Structure representing vendor defined descriptor title sections
+ */
+struct pldm_vendor_defined_descriptor_title_data {
+ uint8_t vendor_defined_descriptor_title_str_type;
+ uint8_t vendor_defined_descriptor_title_str_len;
+ uint8_t vendor_defined_descriptor_title_str[1];
+} __attribute__((packed));
+
+/** @struct pldm_component_image_information
+ *
+ * Structure representing fixed part of individual component information in
+ * PLDM firmware update package
+ */
+struct pldm_component_image_information {
+ uint16_t comp_classification;
+ uint16_t comp_identifier;
+ uint32_t comp_comparison_stamp;
+ bitfield16_t comp_options;
+ bitfield16_t requested_comp_activation_method;
+ uint32_t comp_location_offset;
+ uint32_t comp_size;
+ uint8_t comp_version_string_type;
+ uint8_t comp_version_string_length;
+} __attribute__((packed));
+
+/** @struct pldm_query_device_identifiers_resp
+ *
+ * Structure representing query device identifiers response.
+ */
+struct pldm_query_device_identifiers_resp {
+ uint8_t completion_code;
+ uint32_t device_identifiers_len;
+ uint8_t descriptor_count;
+} __attribute__((packed));
+
+/** @struct pldm_get_firmware_parameters_resp
+ *
+ * Structure representing the fixed part of GetFirmwareParameters response
+ */
+struct pldm_get_firmware_parameters_resp {
+ uint8_t completion_code;
+ bitfield32_t capabilities_during_update;
+ uint16_t comp_count;
+ uint8_t active_comp_image_set_ver_str_type;
+ uint8_t active_comp_image_set_ver_str_len;
+ uint8_t pending_comp_image_set_ver_str_type;
+ uint8_t pending_comp_image_set_ver_str_len;
+} __attribute__((packed));
+
+/** @struct pldm_component_parameter_entry
+ *
+ * Structure representing component parameter table entry.
+ */
+struct pldm_component_parameter_entry {
+ uint16_t comp_classification;
+ uint16_t comp_identifier;
+ uint8_t comp_classification_index;
+ uint32_t active_comp_comparison_stamp;
+ uint8_t active_comp_ver_str_type;
+ uint8_t active_comp_ver_str_len;
+ uint8_t active_comp_release_date[8];
+ uint32_t pending_comp_comparison_stamp;
+ uint8_t pending_comp_ver_str_type;
+ uint8_t pending_comp_ver_str_len;
+ uint8_t pending_comp_release_date[8];
+ bitfield16_t comp_activation_methods;
+ bitfield32_t capabilities_during_update;
+} __attribute__((packed));
+
+/** @struct pldm_request_update_req
+ *
+ * Structure representing fixed part of Request Update request
+ */
+struct pldm_request_update_req {
+ 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;
+} __attribute__((packed));
+
+/** @struct pldm_request_update_resp
+ *
+ * Structure representing Request Update response
+ */
+struct pldm_request_update_resp {
+ uint8_t completion_code;
+ uint16_t fd_meta_data_len;
+ uint8_t fd_will_send_pkg_data;
+} __attribute__((packed));
+
+/** @struct pldm_pass_component_table_req
+ *
+ * Structure representing PassComponentTable request
+ */
+struct pldm_pass_component_table_req {
+ 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;
+} __attribute__((packed));
+
+/** @struct pldm_pass_component_table_resp
+ *
+ * Structure representing PassComponentTable response
+ */
+struct pldm_pass_component_table_resp {
+ uint8_t completion_code;
+ uint8_t comp_resp;
+ uint8_t comp_resp_code;
+} __attribute__((packed));
+
+/** @struct pldm_update_component_req
+ *
+ * Structure representing UpdateComponent request
+ */
+struct pldm_update_component_req {
+ 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;
+} __attribute__((packed));
+
+/** @struct pldm_update_component_resp
+ *
+ * Structure representing UpdateComponent response
+ */
+struct pldm_update_component_resp {
+ uint8_t completion_code;
+ uint8_t comp_compatability_resp;
+ uint8_t comp_compatability_resp_code;
+ bitfield32_t update_option_flags_enabled;
+ uint16_t time_before_req_fw_data;
+} __attribute__((packed));
+
+/** @struct pldm_request_firmware_data_req
+ *
+ * Structure representing RequestFirmwareData request.
+ */
+struct pldm_request_firmware_data_req {
+ uint32_t offset;
+ uint32_t length;
+} __attribute__((packed));
+
+/** @struct pldm_apply_complete_req
+ *
+ * Structure representing ApplyComplete request.
+ */
+struct pldm_apply_complete_req {
+ uint8_t apply_result;
+ bitfield16_t comp_activation_methods_modification;
+} __attribute__((packed));
+
+/** @struct pldm_activate_firmware_req
+ *
+ * Structure representing ActivateFirmware request
+ */
+struct pldm_activate_firmware_req {
+ bool8_t self_contained_activation_req;
+} __attribute__((packed));
+
+/** @struct activate_firmware_resp
+ *
+ * Structure representing Activate Firmware response
+ */
+struct pldm_activate_firmware_resp {
+ uint8_t completion_code;
+ uint16_t estimated_time_activation;
+} __attribute__((packed));
+
+/** @struct pldm_get_status_resp
+ *
+ * Structure representing GetStatus response.
+ */
+struct pldm_get_status_resp {
+ 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;
+} __attribute__((packed));
+
+/** @struct pldm_cancel_update_resp
+ *
+ * Structure representing CancelUpdate response.
+ */
+struct pldm_cancel_update_resp {
+ uint8_t completion_code;
+ bool8_t non_functioning_component_indication;
+ uint64_t non_functioning_component_bitmap;
+} __attribute__((packed));
+
+/** @brief Decode the PLDM package header information
+ *
+ * @param[in] data - pointer to package header information
+ * @param[in] length - available length in the firmware update package
+ * @param[out] package_header_info - pointer to fixed part of PLDM package
+ * header information
+ * @param[out] package_version_str - pointer to package version string
+ *
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Decode individual firmware device ID record
+ *
+ * @param[in] data - pointer to firmware device ID record
+ * @param[in] length - available length in the firmware update package
+ * @param[in] component_bitmap_bit_length - ComponentBitmapBitLengthfield
+ * parsed from the package header info
+ * @param[out] fw_device_id_record - pointer to fixed part of firmware device
+ * id record
+ * @param[out] applicable_components - pointer to ApplicableComponents
+ * @param[out] comp_image_set_version_str - pointer to
+ * ComponentImageSetVersionString
+ * @param[out] record_descriptors - pointer to RecordDescriptors
+ * @param[out] fw_device_pkg_data - pointer to FirmwareDevicePackageData
+ *
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Decode the record descriptor entries in the firmware update package
+ * and the Descriptors in the QueryDeviceIDentifiers command
+ *
+ * @param[in] data - pointer to descriptor entry
+ * @param[in] length - remaining length of the descriptor data
+ * @param[out] descriptor_type - pointer to descriptor type
+ * @param[out] descriptor_data - pointer to descriptor data
+ *
+ * @return pldm_completion_codes
+ */
+int decode_descriptor_type_length_value(const uint8_t *data, size_t length,
+ uint16_t *descriptor_type,
+ struct variable_field *descriptor_data);
+
+/** @brief Decode the vendor defined descriptor value
+ *
+ * @param[in] data - pointer to vendor defined descriptor value
+ * @param[in] length - length of the vendor defined descriptor value
+ * @param[out] descriptor_title_str_type - pointer to vendor defined descriptor
+ * title string type
+ * @param[out] descriptor_title_str - pointer to vendor defined descriptor
+ * title string
+ * @param[out] descriptor_data - pointer to vendor defined descriptor data
+ *
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Decode individual component image information
+ *
+ * @param[in] data - pointer to component image information
+ * @param[in] length - available length in the firmware update package
+ * @param[out] pldm_comp_image_info - pointer to fixed part of component image
+ * information
+ * @param[out] comp_version_str - pointer to component version string
+ *
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Create a PLDM request message for QueryDeviceIdentifiers
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] payload_length - Length of the request message payload
+ * @param[in,out] msg - Message will be written to this
+ *
+ * @return pldm_completion_codes
+ *
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+int encode_query_device_identifiers_req(uint8_t instance_id,
+ size_t payload_length,
+ struct pldm_msg *msg);
+
+/** @brief Decode QueryDeviceIdentifiers response message
+ *
+ * @param[in] msg - Response message
+ * @param[in] payload_length - Length of response message payload
+ * @param[out] completion_code - Pointer to response msg's PLDM completion code
+ * @param[out] device_identifiers_len - Pointer to device identifiers length
+ * @param[out] descriptor_count - Pointer to descriptor count
+ * @param[out] descriptor_data - Pointer to descriptor data
+ *
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Create a PLDM request message for GetFirmwareParameters
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] payload_length - Length of the request message payload
+ * @param[in,out] msg - Message will be written to this
+ *
+ * @return pldm_completion_codes
+ *
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+int encode_get_firmware_parameters_req(uint8_t instance_id,
+ size_t payload_length,
+ struct pldm_msg *msg);
+
+/** @brief Decode GetFirmwareParameters response
+ *
+ * @param[in] msg - Response message
+ * @param[in] payload_length - Length of response message payload
+ * @param[out] resp_data - Pointer to get firmware parameters response
+ * @param[out] active_comp_image_set_ver_str - Pointer to active component
+ * image set version string
+ * @param[out] pending_comp_image_set_ver_str - Pointer to pending component
+ * image set version string
+ * @param[out] comp_parameter_table - Pointer to component parameter table
+ *
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Decode component entries in the component parameter table which is
+ * part of the response of GetFirmwareParameters command
+ *
+ * @param[in] data - Component entry
+ * @param[in] length - Length of component entry
+ * @param[out] component_data - Pointer to component parameter table
+ * @param[out] active_comp_ver_str - Pointer to active component version string
+ * @param[out] pending_comp_ver_str - Pointer to pending component version
+ * string
+ *
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Create PLDM request message for RequestUpdate
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] max_transfer_size - Maximum size of the variable payload allowed
+ * to be requested via RequestFirmwareData
+ * command
+ * @param[in] num_of_comp - Total number of components that will be passed to
+ * the FD during the update
+ * @param[in] max_outstanding_transfer_req - Total number of outstanding
+ * RequestFirmwareData
+ * commands that can be sent by the FD
+ * @param[in] pkg_data_len - Value of the FirmwareDevicePackageDataLength field
+ * present in firmware package header
+ * @param[in] comp_image_set_ver_str_type - StringType of
+ * ComponentImageSetVersionString
+ * @param[in] comp_image_set_ver_str_len - The length of the
+ * ComponentImageSetVersionString
+ * @param[in] comp_img_set_ver_str - Component Image Set version information
+ * @param[in,out] msg - Message will be written to this
+ * @param[in] payload_length - Length of request message payload
+ *
+ * @return pldm_completion_codes
+ *
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+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);
+
+/** @brief Decode a RequestUpdate response message
+ *
+ * @param[in] msg - Response message
+ * @param[in] payload_length - Length of response message payload
+ * @param[out] completion_code - Pointer to hold the completion code
+ * @param[out] fd_meta_data_len - Pointer to hold the length of FD metadata
+ * @param[out] fd_will_send_pkg_data - Pointer to hold information whether FD
+ * will send GetPackageData command
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Create PLDM request message for PassComponentTable
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] transfer_flag - TransferFlag
+ * @param[in] comp_classification - ComponentClassification
+ * @param[in] comp_identifier - ComponentIdentifier
+ * @param[in] comp_classification_index - ComponentClassificationIndex
+ * @param[in] comp_comparison_stamp - ComponentComparisonStamp
+ * @param[in] comp_ver_str_type - ComponentVersionStringType
+ * @param[in] comp_ver_str_len - ComponentVersionStringLength
+ * @param[in] comp_ver_str - ComponentVersionString
+ * @param[in,out] msg - Message will be written to this
+ * @param[in] payload_length - Length of request message payload
+ * information
+ *
+ * @return pldm_completion_codes
+ *
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+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);
+
+/** @brief Decode PassComponentTable response message
+ *
+ * @param[in] msg - Response message
+ * @param[in] payload_length - Length of response message payload
+ * @param[out] completion_code - Pointer to hold completion code
+ * @param[out] comp_resp - Pointer to hold component response
+ * @param[out] comp_resp_code - Pointer to hold component response code
+ *
+ * @return pldm_completion_codes
+ */
+int decode_pass_component_table_resp(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint8_t *completion_code,
+ uint8_t *comp_resp,
+ uint8_t *comp_resp_code);
+
+/** @brief Create PLDM request message for UpdateComponent
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] comp_classification - ComponentClassification
+ * @param[in] comp_identifier - ComponentIdentifier
+ * @param[in] comp_classification_index - ComponentClassificationIndex
+ * @param[in] comp_comparison_stamp - ComponentComparisonStamp
+ * @param[in] comp_image_size - ComponentImageSize
+ * @param[in] update_option_flags - UpdateOptionFlags
+ * @param[in] comp_ver_str_type - ComponentVersionStringType
+ * @param[in] comp_ver_str_len - ComponentVersionStringLength
+ * @param[in] comp_ver_str - ComponentVersionString
+ * @param[in,out] msg - Message will be written to this
+ * @param[in] payload_length - Length of request message payload
+ * information
+ *
+ * @return pldm_completion_codes
+ *
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+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);
+
+/** @brief Decode UpdateComponent response message
+ *
+ * @param[in] msg - Response message
+ * @param[in] payload_length - Length of response message payload
+ * @param[out] completion_code - Pointer to hold completion code
+ * @param[out] comp_compatability_resp - Pointer to hold component
+ * compatibility response
+ * @param[out] comp_compatability_resp_code - Pointer to hold component
+ * compatibility response code
+ * @param[out] update_option_flags_enabled - Pointer to hold
+ * UpdateOptionsFlagEnabled
+ * @param[out] time_before_req_fw_data - Pointer to hold the estimated time
+ * before sending RequestFirmwareData
+ *
+ * @return pldm_completion_codes
+ */
+int decode_update_component_resp(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint8_t *completion_code,
+ uint8_t *comp_compatability_resp,
+ uint8_t *comp_compatability_resp_code,
+ bitfield32_t *update_option_flags_enabled,
+ uint16_t *time_before_req_fw_data);
+
+/** @brief Decode RequestFirmwareData request message
+ *
+ * @param[in] msg - Request message
+ * @param[in] payload_length - Length of request message payload
+ * @param[out] offset - Pointer to hold offset
+ * @param[out] length - Pointer to hold the size of the component image
+ * segment requested by the FD/FDP
+ *
+ * @return pldm_completion_codes
+ */
+int decode_request_firmware_data_req(const struct pldm_msg *msg,
+ size_t payload_length, uint32_t *offset,
+ uint32_t *length);
+
+/** @brief Create PLDM response message for RequestFirmwareData
+ *
+ * The ComponentImagePortion is not encoded in the PLDM response message
+ * by encode_request_firmware_data_resp to avoid an additional copy. Populating
+ * ComponentImagePortion in the PLDM response message is handled by the user
+ * of this API. The payload_length validation considers only the
+ * CompletionCode.
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - CompletionCode
+ * @param[in,out] msg - Message will be written to this
+ * @param[in] payload_length - Length of response message payload
+ *
+ * @return pldm_completion_codes
+ *
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+int encode_request_firmware_data_resp(uint8_t instance_id,
+ uint8_t completion_code,
+ struct pldm_msg *msg,
+ size_t payload_length);
+
+/** @brief Decode TransferComplete request message
+ *
+ * @param[in] msg - Request message
+ * @param[in] payload_length - Length of request message payload
+ * @param[out] transfer_result - Pointer to hold TransferResult
+ *
+ * @return pldm_completion_codes
+ */
+int decode_transfer_complete_req(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint8_t *transfer_result);
+
+/** @brief Create PLDM response message for TransferComplete
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - CompletionCode
+ * @param[in,out] msg - Message will be written to this
+ * @param[in] payload_length - Length of response message payload
+ *
+ * @return pldm_completion_codes
+ *
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+int encode_transfer_complete_resp(uint8_t instance_id, uint8_t completion_code,
+ struct pldm_msg *msg, size_t payload_length);
+
+/** @brief Decode VerifyComplete request message
+ *
+ * @param[in] msg - Request message
+ * @param[in] payload_length - Length of request message payload
+ * @param[in] verify_result - Pointer to hold VerifyResult
+ *
+ * @return pldm_completion_codes
+ */
+int decode_verify_complete_req(const struct pldm_msg *msg,
+ size_t payload_length, uint8_t *verify_result);
+
+/** @brief Create PLDM response message for VerifyComplete
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - CompletionCode
+ * @param[in,out] msg - Message will be written to this
+ * @param[in] payload_length - Length of response message payload
+ *
+ * @return pldm_completion_codes
+ *
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+int encode_verify_complete_resp(uint8_t instance_id, uint8_t completion_code,
+ struct pldm_msg *msg, size_t payload_length);
+
+/** @brief Decode ApplyComplete request message
+ *
+ * @param[in] msg - Request message
+ * @param[in] payload_length - Length of request message payload
+ * @param[in] apply_result - Pointer to hold ApplyResult
+ * @param[in] comp_activation_methods_modification - Pointer to hold the
+ * ComponentActivationMethodsModification
+ *
+ * @return pldm_completion_codes
+ */
+int decode_apply_complete_req(
+ const struct pldm_msg *msg, size_t payload_length, uint8_t *apply_result,
+ bitfield16_t *comp_activation_methods_modification);
+
+/** @brief Create PLDM response message for ApplyComplete
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - CompletionCode
+ * @param[in,out] msg - Message will be written to this
+ * @param[in] payload_length - Length of response message payload
+ *
+ * @return pldm_completion_codes
+ *
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+int encode_apply_complete_resp(uint8_t instance_id, uint8_t completion_code,
+ struct pldm_msg *msg, size_t payload_length);
+
+/** @brief Create PLDM request message for ActivateFirmware
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] self_contained_activation_req SelfContainedActivationRequest
+ * @param[in,out] msg - Message will be written to this
+ * @param[in] payload_length - Length of request message payload
+ *
+ * @return pldm_completion_codes
+ *
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+int encode_activate_firmware_req(uint8_t instance_id,
+ bool8_t self_contained_activation_req,
+ struct pldm_msg *msg, size_t payload_length);
+
+/** @brief Decode ActivateFirmware response message
+ *
+ * @param[in] msg - Response message
+ * @param[in] payload_length - Length of response message payload
+ * @param[out] completion_code - Pointer to hold CompletionCode
+ * @param[out] estimated_time_activation - Pointer to hold
+ * EstimatedTimeForSelfContainedActivation
+ *
+ * @return pldm_completion_codes
+ */
+int decode_activate_firmware_resp(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint8_t *completion_code,
+ uint16_t *estimated_time_activation);
+
+/** @brief Create PLDM request message for GetStatus
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in,out] msg - Message will be written to this
+ * @param[in] payload_length - Length of request message payload
+ *
+ * @return pldm_completion_codes
+ *
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+int encode_get_status_req(uint8_t instance_id, struct pldm_msg *msg,
+ size_t payload_length);
+
+/** @brief Decode GetStatus response message
+ *
+ * @param[in] msg - Response message
+ * @param[in] payload_length - Length of response message payload
+ * @param[out] completion_code - Pointer to completion code
+ * @param[out] current_state - Pointer to current state machine state
+ * @param[out] previous_state - Pointer to previous different state machine
+ * state
+ * @param[out] aux_state - Pointer to current operation state of FD/FDP
+ * @param[out] aux_state_status - Pointer to aux state status
+ * @param[out] progress_percent - Pointer to progress percentage
+ * @param[out] reason_code - Pointer to reason for entering current state
+ * @param[out] update_option_flags_enabled - Pointer to update option flags
+ * enabled
+ *
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Create PLDM request message for CancelUpdateComponent
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in,out] msg - Message will be written to this
+ * @param[in] payload_length - Length of request message payload
+ *
+ * @return pldm_completion_codes
+ *
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+int encode_cancel_update_component_req(uint8_t instance_id,
+ struct pldm_msg *msg,
+ size_t payload_length);
+
+/** @brief Decode CancelUpdateComponent response message
+ *
+ * @param[in] msg - Response message
+ * @param[in] payload_length - Length of response message payload
+ * @param[out] completion_code - Pointer to the completion code
+ *
+ * @return pldm_completion_codes
+ */
+int decode_cancel_update_component_resp(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint8_t *completion_code);
+
+/** @brief Create PLDM request message for CancelUpdate
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in,out] msg - Message will be written to this
+ * @param[in] payload_length - Length of request message payload
+ *
+ * @return pldm_completion_codes
+ *
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+int encode_cancel_update_req(uint8_t instance_id, struct pldm_msg *msg,
+ size_t payload_length);
+
+/** @brief Decode CancelUpdate response message
+ *
+ * @param[in] msg - Response message
+ * @param[in] payload_length - Length of response message payload
+ * @param[out] completion_code - Pointer to completion code
+ * @param[out] non_functioning_component_indication - Pointer to non
+ functioning
+ * component indication
+ * @param[out] non_functioning_component_bitmap - Pointer to non
+ functioning
+ * component bitmap
+ *
+ * @return pldm_completion_codes
+ */
+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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // End of FW_UPDATE_H
diff --git a/pldm/libpldm/fru.c b/pldm/libpldm/fru.c
new file mode 100644
index 00000000..fa79f2bf
--- /dev/null
+++ b/pldm/libpldm/fru.c
@@ -0,0 +1,548 @@
+#include <assert.h>
+#include <endian.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include "fru.h"
+
+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));
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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);
+}
+
+void get_fru_record_by_option(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);
+
+ assert(pos - record_table + len < *record_size);
+ 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) {
+ assert(pos - record_table + len < *record_size);
+ 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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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);
+}
+
+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;
+}
+
+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/pldm/libpldm/fru.h b/pldm/libpldm/fru.h
new file mode 100644
index 00000000..bb2f5715
--- /dev/null
+++ b/pldm/libpldm/fru.h
@@ -0,0 +1,507 @@
+#ifndef FRU_H
+#define FRU_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <asm/byteorder.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base.h"
+#include "utils.h"
+
+#define PLDM_GET_FRU_RECORD_TABLE_METADATA_REQ_BYTES 0
+#define PLDM_GET_FRU_RECORD_TABLE_METADATA_RESP_BYTES 19
+#define PLDM_GET_FRU_RECORD_TABLE_REQ_BYTES 5
+#define PLDM_GET_FRU_RECORD_TABLE_MIN_RESP_BYTES 6
+#define PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES 6
+#define PLDM_SET_FRU_RECORD_TABLE_MIN_REQ_BYTES 5
+#define PLDM_SET_FRU_RECORD_TABLE_RESP_BYTES 5
+
+#define FRU_TABLE_CHECKSUM_SIZE 4
+
+enum pldm_fru_completion_codes {
+ PLDM_FRU_INVALID_DATA_TRANSFER_HANDLE = 0x80,
+ PLDM_FRU_INVALID_TRANSFER_FLAG = 0x82,
+ PLDM_FRU_DATA_INVALID_DATA_INTEGRITY_CHECK = 0x84,
+ PLDM_FRU_DATA_STRUCTURE_TABLE_UNAVAILABLE = 0x85,
+};
+
+/** @brief PLDM FRU commands
+ */
+enum pldm_fru_commands {
+ PLDM_GET_FRU_RECORD_TABLE_METADATA = 0X01,
+ PLDM_GET_FRU_RECORD_TABLE = 0X02,
+ PLDM_SET_FRU_RECORD_TABLE = 0X03,
+ PLDM_GET_FRU_RECORD_BY_OPTION = 0X04
+};
+
+/** @brief FRU record types
+ */
+enum pldm_fru_record_type {
+ PLDM_FRU_RECORD_TYPE_GENERAL = 0X01,
+ PLDM_FRU_RECORD_TYPE_OEM = 0XFE,
+};
+
+/** @brief Encoding type for FRU fields
+ */
+enum pldm_fru_field_encoding {
+ PLDM_FRU_ENCODING_UNSPECIFIED = 0X00,
+ PLDM_FRU_ENCODING_ASCII = 0X01,
+ PLDM_FRU_ENCODING_UTF8 = 0X02,
+ PLDM_FRU_ENCODING_UTF16 = 0X03,
+ PLDM_FRU_ENCODING_UTF16LE = 0X04,
+ PLDM_FRU_ENCODING_UTF16BE = 0X05,
+};
+
+/** @brief FRU field types
+ */
+enum pldm_fru_field_type {
+ PLDM_FRU_FIELD_TYPE_CHASSIS = 0X01,
+ PLDM_FRU_FIELD_TYPE_MODEL = 0X02,
+ PLDM_FRU_FIELD_TYPE_PN = 0X03,
+ PLDM_FRU_FIELD_TYPE_SN = 0X04,
+ PLDM_FRU_FIELD_TYPE_MANUFAC = 0X05,
+ PLDM_FRU_FIELD_TYPE_MANUFAC_DATE = 0X06,
+ PLDM_FRU_FIELD_TYPE_VENDOR = 0X07,
+ PLDM_FRU_FIELD_TYPE_NAME = 0X08,
+ PLDM_FRU_FIELD_TYPE_SKU = 0X09,
+ PLDM_FRU_FIELD_TYPE_VERSION = 0X0A,
+ PLDM_FRU_FIELD_TYPE_ASSET_TAG = 0X0B,
+ PLDM_FRU_FIELD_TYPE_DESC = 0X0C,
+ PLDM_FRU_FIELD_TYPE_EC_LVL = 0X0D,
+ PLDM_FRU_FIELD_TYPE_OTHER = 0X0E,
+ PLDM_FRU_FIELD_TYPE_IANA = 0X0F,
+};
+
+/** @struct pldm_get_fru_record_table_metadata_resp
+ *
+ * Structure representing PLDM get FRU table metadata response.
+ */
+struct pldm_get_fru_record_table_metadata_resp {
+ uint8_t completion_code; //!< completion code
+ uint8_t fru_data_major_version; //!< The major version of the FRU Record
+ uint8_t fru_data_minor_version; //!< The minor version of the FRU Record
+ uint32_t
+ fru_table_maximum_size; //!< The size of the largest FRU Record data
+ uint32_t fru_table_length; //!< The total length of the FRU Record Table
+ uint16_t total_record_set_identifiers; //!< The total number of FRU
+ //!< Record Data structures
+ uint16_t
+ total_table_records; //!< The total number of records in the table
+ uint32_t
+ checksum; //!< The integrity checksum on the FRU Record Table data
+} __attribute__((packed));
+
+/** @struct pldm_get_fru_record_table_req
+ *
+ * Structure representing PLDM get FRU record table request.
+ */
+struct pldm_get_fru_record_table_req {
+ uint32_t data_transfer_handle;
+ uint8_t transfer_operation_flag;
+} __attribute__((packed));
+
+/** @struct pldm_get_fru_record_table_resp
+ *
+ * Structure representing PLDM get FRU record table response.
+ */
+struct pldm_get_fru_record_table_resp {
+ uint8_t completion_code;
+ uint32_t next_data_transfer_handle;
+ uint8_t transfer_flag;
+ uint8_t fru_record_table_data[1];
+} __attribute__((packed));
+
+struct pldm_get_fru_record_by_option_req {
+ 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;
+} __attribute__((packed));
+
+struct pldm_get_fru_record_by_option_resp {
+ uint8_t completion_code;
+ uint32_t next_data_transfer_handle;
+ uint8_t transfer_flag;
+ uint8_t fru_structure_data[1];
+} __attribute__((packed));
+
+struct pldm_set_fru_record_table_req {
+ uint32_t data_transfer_handle;
+ uint8_t transfer_flag;
+ uint8_t fru_record_table_data[1];
+} __attribute__((packed));
+
+struct pldm_set_fru_record_table_resp {
+ uint8_t completion_code;
+ uint32_t next_data_transfer_handle;
+} __attribute__((packed));
+
+/** @struct pldm_fru_record_tlv
+ *
+ * Structure representing each FRU field entry (type, length, value)
+ */
+struct pldm_fru_record_tlv {
+ uint8_t type;
+ uint8_t length;
+ uint8_t value[1];
+} __attribute__((packed));
+
+/** @struct pldm_fru_record_data_format
+ *
+ * Structure representing the FRU record data format
+ */
+struct pldm_fru_record_data_format {
+ uint16_t record_set_id;
+ uint8_t record_type;
+ uint8_t num_fru_fields;
+ uint8_t encoding_type;
+ struct pldm_fru_record_tlv tlvs[1];
+} __attribute__((packed));
+
+/* Requester */
+
+/* GetFRURecordTableMetadata */
+
+/** @brief Create a PLDM request message for GetFRURecordTableMetadata
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in,out] msg - Message will be written to this
+ * @param[in] payload_length - Length of the request message payload
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+int encode_get_fru_record_table_metadata_req(uint8_t instance_id,
+ struct pldm_msg *msg,
+ size_t payload_length);
+
+/** @brief Decode GetFruRecordTable response data
+ *
+ * Note:
+ * * If the return value is not PLDM_SUCCESS, it represents a
+ * transport layer error.
+ * * If the completion_code value is not PLDM_SUCCESS, it represents a
+ * protocol layer error and all the out-parameters are invalid.
+ *
+ * @param[in] msg - Response message
+ * @param[in] payload_length - Length of response message payload
+ * @param[out] completion_code - Pointer to response msg's PLDM completion code
+ * @param[out] fru_data_major_version - Major version of the FRU Record
+ * @param[out] fru_data_minor_version - Minor version of the FRU Record
+ * @param[out] fru_table_maximum_size - Size of the largest FRU Record data
+ * @param[out] fru_table_length - Total length of the FRU Record Table
+ * @param[out] total_Record_Set_Identifiers - Total number of FRU Record Data
+ * structures
+ * @param[out] total_table_records - Total number of records in the table
+ * @param[out] checksum - integrity checksum on the FRU Record Table data
+ * @return pldm_completion_codes
+ */
+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);
+
+/* Responder */
+
+/* GetFRURecordTableMetadata */
+
+/** @brief Create a PLDM response message for GetFRURecordTableMetadata
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - PLDM completion code
+ * @param[in] fru_data_major_version - Major version of the FRU Record
+ * @param[in] fru_data_minor_version - Minor version of the FRU Record
+ * @param[in] fru_table_maximum_size - Size of the largest FRU Record data
+ * @param[in] fru_table_length - Total length of the FRU Record Table
+ * @param[in] total_Record_Set_Identifiers - Total number of FRU Record Data
+ * structures
+ * @param[in] total_table_records - Total number of records in the table
+ * @param[in] checksum - integrity checksum on the FRU Record Table data
+ * @param[in,out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+
+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);
+
+/* GetFruRecordTable */
+
+/** @brief Decode GetFruRecordTable request data
+ *
+ * @param[in] msg - PLDM request message payload
+ * @param[in] payload_length - Length of request payload
+ * @param[out] data_transfer_handle - A handle, used to identify a FRU Record
+ * Table data transfer
+ * @param[out] transfer_operation_flag - A flag that indicates whether this is
+ * the start of the transfer
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Create a PLDM response message for GetFruRecordTable
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - PLDM completion code
+ * @param[in] next_data_transfer_handle - A handle that is used to identify the
+ * next portion of the transfer
+ * @param[in] transfer_flag - The transfer flag that indicates what part of the
+ * transfer this response represents
+ * @param[in,out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param 'msg',
+ * and for appending the FRU table to the msg.
+ */
+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);
+
+/* GetFRURecordByOption */
+
+/** @brief Decode GetFRURecordByOption request data
+ *
+ * @param[in] msg - PLDM request message payload
+ * @param[in] payload_length - Length of request payload
+ * @param[out] data_transfer_handle - A handle, used to identify a FRU Record
+ * Table data transfer
+ * @param[out] fru_table_handle - A handle, used to identify a FRU DATA
+ * records
+ * @param[out] record_set_identifier - FRU record set identifier
+ * @param[out] record_type - FRU record type
+ * @param[out] field_type - FRU field type
+ * @param[out] transfer_op_flag - A flag that indicates whether this is
+ * the start of the transfer
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Encode GetFRURecordByOption response data
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - PLDM completion code
+ * @param[in] next_data_transfer_handle - A handle that is used to identify the
+ * next portion of the transfer
+ * @param[in] transfer_flag - The transfer flag that indicates what part of the
+ * transfer this response represents
+ * @param[in] fru_structure_data - FRU Structure Data
+ * @param[in] data_size - Size of FRU Structrue Data
+ * @param[in,out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param 'msg',
+ * and for appending the FRU table to the msg.
+ */
+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);
+
+/* Requester */
+
+/* GetFruRecordTable */
+
+/** @brief Create a PLDM request message for GetFruRecordTable
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] data_transfer_handle - A handle, used to identify a FRU Record
+ * Table data transfer
+ * @param[in] transfer_operation_flag - A flag that indicates whether this is
+ * the start of the transfer
+ * @param[in,out] msg - Message will be written to this
+ * @param[in] payload_length - Length of request message payload
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+
+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);
+
+/** @brief Decode GetFruRecordTable response data
+ *
+ * @param[in] msg - Response message
+ * @param[in] payload_length - Length of response message payload
+ * @param[out] completion_code - Pointer to response msg's PLDM completion code
+ * @param[out] next_data_transfer_handle - A handle used to identify the next
+ * portion of the transfer
+ * @param[out] transfer_flag - The transfer flag that indicates what part of
+ * the transfer this response represents
+ * @param[out] fru_record_table_data - This data is a portion of the overall
+ * FRU Record Table
+ * @param[out] fru_record_table_length - Length of the FRU record table data
+ * @return pldm_completion_codes
+ */
+
+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);
+
+/** @brief Decode GetFruRecordTable response data, ensuring that the fru
+ * record table section is small enough to fit in the provided buffer.
+ *
+ * @param[in] msg - Response message
+ * @param[in] payload_length - Length of response message payload
+ * @param[out] completion_code - Pointer to response msg's PLDM completion code
+ * @param[out] next_data_transfer_handle - A handle used to identify the next
+ * portion of the transfer
+ * @param[out] transfer_flag - The transfer flag that indicates what part of
+ * the transfer this response represents
+ * @param[out] fru_record_table_data - This data is a portion of the overall
+ * FRU Record Table
+ * @param[out] fru_record_table_length - Length of the FRU record table data
+ * @param[in] max_fru_record_table_length - Maximum length of the FRU record
+ * table data. If the response contains more data than this,
+ * return PLDM_ERROR_INVALID_LENGTH.
+ * @return pldm_completion_codes
+ */
+
+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);
+
+/** @brief Encode the FRU record in the FRU table
+ *
+ * @param[in/out] fru_table - Pointer to the FRU table
+ * @param[in] total_size - The size of the table,including the size of FRU
+ * record to be added to the table.
+ * @param[in/out] curr_size - The size of the table, excluding the size of FRU
+ * record to be added to the table.
+ * @param[in] record_set_id - FRU record set identifier
+ * @param[in] record_type - FRU record type
+ * @param[in] num_frus - Number of FRU fields
+ * @param[in] encoding - Encoding type for FRU fields
+ * @param[in] tlvs - Pointer to the buffer with all the FRU fields
+ * @param[in] tlvs_size - Size of the buffer with all the FRU fields
+ *
+ * @return pldm_completion_codes
+ */
+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);
+
+/* GetFRURecordByOption */
+
+/** @brief Create a PLDM request message for GetFRURecordByOption
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] data_transfer_handle - A handle, used to identify a FRU Record
+ * Table data transfer
+ * @param[in] fru_table_handle - A handle, used to identify a FRU DATA records
+ * @param[in] record_set_identifier - FRU record set identifier
+ * @param[in] record_type - FRU record type
+ * @param[in] field_type - FRU field type
+ * @param[in] transfer_op_flag - A flag that indicates whether this is
+ * the start of the transfer
+ * @param[in,out] msg - Message will be written to this
+ * @param[in] payload_length - Length of request message payload
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+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);
+
+/** @brief Decode GetFRURecordByOption response data
+ *
+ * @param[in] msg - Response message
+ * @param[in] payload_length - Length of response message payload
+ * @param[out] completion_code - Pointer to response msg's PLDM completion code
+ * @param[out] next_data_transfer_handle - A handle used to identify the next
+ * portion of the transfer
+ * @param[out] transfer_flag - The transfer flag that indicates what part of
+ * the transfer this response represents
+ * @param[out] fru_structure_data - FRU Structure Data
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Get FRU Record Table By Option
+ * @param[in] table - The source fru record table
+ * @param[in] table_size - Size of the source fru record table
+ * @param[out] record_table - Fru table fetched based on the input option
+ * @param[in/out] record_size - Size of the table fetched by fru record option
+ * @param[in] rsi - FRU record set identifier
+ * @param[in] rt - FRU record type
+ * @param[in] ft - FRU field type
+ */
+void get_fru_record_by_option(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);
+/* SetFruRecordTable */
+
+/** @brief Decode SetFruRecordTable request data
+ *
+ * @param[in] msg - PLDM request message payload
+ * @param[in] payload_length - Length of request payload
+ * @param[out] data_transfer_handle - A handle used to identify a FRU Record
+ * table data transfer
+ * @param[out] transfer_flag - Flag to indicate what part of the transfer
+ * this request represents
+ * @param[out] fru_table_data - Struct variable_field, contains data specific
+ * to the fru record table and the length of table
+ * data
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Create a PLDM response message for SetFruRecordTable
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - PLDM completion code
+ * @param[in] next_transfer_handle - handle to identify the next portion of the
+ * transfer
+ * @param[in] payload_length - Length of payload message
+ * @param[out] msg - Argument to capture the Message
+ */
+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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/pldm/libpldm/pdr.c b/pldm/libpldm/pdr.c
new file mode 100644
index 00000000..eeb98054
--- /dev/null
+++ b/pldm/libpldm/pdr.c
@@ -0,0 +1,914 @@
+#include "pdr.h"
+#include "platform.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct pldm_pdr_record {
+ uint32_t record_handle;
+ uint32_t size;
+ uint8_t *data;
+ struct pldm_pdr_record *next;
+ bool is_remote;
+} 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;
+}
+
+static void add_record(pldm_pdr *repo, pldm_pdr_record *record)
+{
+ assert(repo != NULL);
+ assert(record != NULL);
+
+ if (repo->first == NULL) {
+ assert(repo->last == NULL);
+ repo->first = record;
+ repo->last = record;
+ } else {
+ repo->last->next = record;
+ repo->last = record;
+ }
+ repo->size += record->size;
+ ++repo->record_count;
+}
+
+static inline uint32_t get_new_record_handle(const pldm_pdr *repo)
+{
+ assert(repo != NULL);
+ uint32_t last_used_hdl =
+ repo->last != NULL ? repo->last->record_handle : 0;
+ assert(last_used_hdl != UINT32_MAX);
+
+ return last_used_hdl + 1;
+}
+
+static pldm_pdr_record *make_new_record(const pldm_pdr *repo,
+ const uint8_t *data, uint32_t size,
+ uint32_t record_handle, bool is_remote)
+{
+ assert(repo != NULL);
+ assert(size != 0);
+
+ pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
+ assert(record != NULL);
+ record->record_handle =
+ record_handle == 0 ? get_new_record_handle(repo) : record_handle;
+ record->size = size;
+ record->is_remote = is_remote;
+ if (data != NULL) {
+ record->data = malloc(size);
+ assert(record->data != NULL);
+ memcpy(record->data, data, size);
+ /* 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.
+ */
+ if (!record_handle) {
+ struct pldm_pdr_hdr *hdr =
+ (struct pldm_pdr_hdr *)(record->data);
+ hdr->record_handle = htole32(record->record_handle);
+ }
+ }
+ record->next = NULL;
+
+ return record;
+}
+
+uint32_t pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size,
+ uint32_t record_handle, bool is_remote)
+{
+ assert(size != 0);
+ assert(data != NULL);
+
+ pldm_pdr_record *record =
+ make_new_record(repo, data, size, record_handle, is_remote);
+ add_record(repo, record);
+
+ return record->record_handle;
+}
+
+pldm_pdr *pldm_pdr_init()
+{
+ pldm_pdr *repo = malloc(sizeof(pldm_pdr));
+ assert(repo != NULL);
+ repo->record_count = 0;
+ repo->size = 0;
+ repo->first = NULL;
+ repo->last = NULL;
+
+ return repo;
+}
+
+void pldm_pdr_destroy(pldm_pdr *repo)
+{
+ assert(repo != NULL);
+
+ 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);
+}
+
+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)
+{
+ assert(repo != NULL);
+ assert(data != NULL);
+ assert(size != NULL);
+ assert(next_record_handle != 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;
+}
+
+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)
+{
+ assert(repo != NULL);
+ assert(curr_record != NULL);
+ assert(data != NULL);
+ assert(size != NULL);
+ assert(next_record_handle != 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;
+}
+
+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)
+{
+ assert(repo != 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;
+}
+
+uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
+{
+ assert(repo != NULL);
+
+ return repo->record_count;
+}
+
+uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
+{
+ assert(repo != NULL);
+
+ return repo->size;
+}
+
+uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo,
+ const pldm_pdr_record *record)
+{
+ assert(repo != NULL);
+ assert(record != NULL);
+
+ return record->record_handle;
+}
+
+inline bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
+{
+ assert(record != NULL);
+
+ return record->is_remote;
+}
+
+uint32_t pldm_pdr_add_fru_record_set(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)
+{
+ 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(repo, data, size, bmc_record_handle, false);
+}
+
+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)
+{
+ assert(terminus_handle != NULL);
+ assert(entity_type != NULL);
+ assert(entity_instance_num != NULL);
+ assert(container_id != 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;
+}
+
+void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminusHandle,
+ uint8_t tid, uint8_t tlEid, bool validBit)
+{
+ uint8_t *outData = NULL;
+ uint32_t size = 0;
+ const pldm_pdr_record *record;
+ record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
+ NULL, &outData, &size);
+
+ do {
+ if (record != NULL) {
+ struct pldm_terminus_locator_pdr *pdr =
+ (struct pldm_terminus_locator_pdr *)outData;
+ struct pldm_terminus_locator_type_mctp_eid *value =
+ (struct pldm_terminus_locator_type_mctp_eid *)
+ pdr->terminus_locator_value;
+ if (pdr->terminus_handle == terminusHandle &&
+ pdr->tid == tid && value->eid == tlEid) {
+ pdr->validity = validBit;
+ break;
+ }
+ }
+ record = pldm_pdr_find_record_by_type(
+ repo, PLDM_TERMINUS_LOCATOR_PDR, record, &outData, &size);
+ } while (record);
+}
+
+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;
+ 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;
+}
+
+pldm_entity pldm_entity_extract(pldm_entity_node *node)
+{
+ assert(node != NULL);
+
+ return node->entity;
+}
+
+pldm_entity_association_tree *pldm_entity_association_tree_init()
+{
+ pldm_entity_association_tree *tree =
+ malloc(sizeof(pldm_entity_association_tree));
+ assert(tree != 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;
+}
+
+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)
+{
+ assert(tree != NULL);
+ assert(entity != 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;
+ }
+ }
+
+ assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
+ association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
+ pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
+ assert(node != 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;
+
+ if (tree->root == NULL) {
+ assert(parent == NULL);
+ tree->root = node;
+ /* container_id 0 here indicates this is the top-most entry */
+ node->entity.entity_container_id = 0;
+ } else if (parent != NULL && parent->first_child == NULL) {
+ parent->first_child = node;
+ node->parent = parent->entity;
+ node->entity.entity_container_id = next_container_id(tree);
+ } else {
+ pldm_entity_node *start =
+ parent == NULL ? tree->root : parent->first_child;
+ pldm_entity_node *prev =
+ find_insertion_at(start, entity->entity_type);
+ assert(prev != NULL);
+ pldm_entity_node *next = prev->next_sibling;
+ if (prev->entity.entity_type == entity->entity_type) {
+ assert(prev->entity.entity_instance_num != UINT16_MAX);
+ 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;
+ }
+ entity->entity_instance_num = node->entity.entity_instance_num;
+ 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);
+}
+
+void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
+ pldm_entity **entities, size_t *size)
+{
+ assert(tree != NULL);
+
+ *size = 0;
+ if (tree->root == NULL) {
+ return;
+ }
+
+ get_num_nodes(tree->root, size);
+ *entities = malloc(*size * sizeof(pldm_entity));
+ 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);
+}
+
+void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
+{
+ assert(tree != NULL);
+
+ entity_association_tree_destroy(tree->root);
+ free(tree);
+}
+
+inline bool pldm_entity_is_node_parent(pldm_entity_node *node)
+{
+ assert(node != NULL);
+
+ return node->first_child != NULL;
+}
+
+inline pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
+{
+ assert(node != NULL);
+
+ return node->parent;
+}
+
+inline 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;
+}
+
+uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
+ uint8_t association_type)
+{
+ assert(node != NULL);
+ assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
+ association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
+
+ 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;
+}
+
+bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
+{
+ assert(parent != NULL);
+ assert(node != NULL);
+
+ 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 void _entity_association_pdr_add_entry(pldm_entity_node *curr,
+ pldm_pdr *repo, uint16_t size,
+ uint8_t contained_count,
+ uint8_t association_type,
+ bool is_remote)
+{
+ uint8_t pdr[size];
+ uint8_t *start = pdr;
+
+ struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
+ hdr->version = 1;
+ hdr->record_handle = 0;
+ 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;
+ }
+
+ pldm_pdr_add(repo, pdr, size, 0, is_remote);
+}
+
+static void entity_association_pdr_add_entry(pldm_entity_node *curr,
+ pldm_pdr *repo, bool is_remote)
+{
+ 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);
+
+ 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));
+ _entity_association_pdr_add_entry(
+ curr, repo, logical_pdr_size, num_logical_children,
+ PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote);
+ }
+
+ 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));
+ _entity_association_pdr_add_entry(
+ curr, repo, physical_pdr_size, num_physical_children,
+ PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote);
+ }
+}
+
+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 void entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
+ pldm_entity **entities,
+ size_t num_entities, bool is_remote)
+{
+ if (curr == NULL) {
+ return;
+ }
+ bool to_add = true;
+ to_add = is_present(curr->entity, entities, num_entities);
+ if (to_add) {
+ entity_association_pdr_add_entry(curr, repo, is_remote);
+ }
+ entity_association_pdr_add(curr->next_sibling, repo, entities,
+ num_entities, is_remote);
+ entity_association_pdr_add(curr->first_child, repo, entities,
+ num_entities, is_remote);
+}
+
+void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
+ pldm_pdr *repo, bool is_remote)
+{
+ assert(tree != NULL);
+ assert(repo != NULL);
+
+ entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote);
+}
+
+void pldm_entity_association_pdr_add_from_node(pldm_entity_node *node,
+ pldm_pdr *repo,
+ pldm_entity **entities,
+ size_t num_entities,
+ bool is_remote)
+{
+ assert(repo != NULL);
+
+ entity_association_pdr_add(node, repo, entities, num_entities,
+ is_remote);
+}
+
+void find_entity_ref_in_tree(pldm_entity_node *tree_node, pldm_entity entity,
+ pldm_entity_node **node)
+{
+ if (tree_node == NULL) {
+ return;
+ }
+
+ if (tree_node->entity.entity_type == entity.entity_type &&
+ tree_node->entity.entity_instance_num ==
+ entity.entity_instance_num) {
+ *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);
+}
+
+void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
+ pldm_entity entity, pldm_entity_node **node)
+{
+ assert(tree != NULL);
+ find_entity_ref_in_tree(tree->root, entity, node);
+}
+
+void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
+{
+ assert(repo != NULL);
+ 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;
+ }
+ }
+}
+
+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);
+}
+
+pldm_entity_node *
+pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
+ pldm_entity *entity)
+{
+ assert(tree != 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)->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));
+}
+
+void pldm_entity_association_tree_copy_root(
+ pldm_entity_association_tree *org_tree,
+ pldm_entity_association_tree *new_tree)
+{
+ new_tree->last_used_container_id = org_tree->last_used_container_id;
+ entity_association_tree_copy(org_tree->root, &(new_tree->root));
+}
+
+void pldm_entity_association_tree_destroy_root(
+ pldm_entity_association_tree *tree)
+{
+ assert(tree != NULL);
+ entity_association_tree_destroy(tree->root);
+ tree->last_used_container_id = 0;
+ tree->root = NULL;
+}
+
+bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
+{
+ return ((tree->root == NULL) ? true : false);
+}
+
+void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
+ size_t *num_entities,
+ pldm_entity **entities)
+{
+ assert(pdr != NULL);
+ assert(pdr_len >= sizeof(struct pldm_pdr_hdr) +
+ sizeof(struct pldm_pdr_entity_association));
+
+ struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
+ assert(hdr->type == PLDM_PDR_ENTITY_ASSOCIATION);
+
+ const uint8_t *start = (uint8_t *)pdr;
+ const uint8_t *end =
+ 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;
+ *num_entities = entity_association_pdr->num_children + 1;
+ assert(*num_entities >= 2);
+ *entities = malloc(sizeof(pldm_entity) * *num_entities);
+ assert(*entities != NULL);
+ assert(start + sizeof(struct pldm_pdr_entity_association) +
+ sizeof(pldm_entity) * (*num_entities - 2) ==
+ end);
+ (*entities)->entity_type =
+ le16toh(entity_association_pdr->container.entity_type);
+ (*entities)->entity_instance_num =
+ le16toh(entity_association_pdr->container.entity_instance_num);
+ (*entities)->entity_container_id =
+ le16toh(entity_association_pdr->container.entity_container_id);
+ pldm_entity *curr_entity = entity_association_pdr->children;
+ size_t i = 1;
+ while (i < *num_entities) {
+ (*entities + i)->entity_type =
+ le16toh(curr_entity->entity_type);
+ (*entities + i)->entity_instance_num =
+ le16toh(curr_entity->entity_instance_num);
+ (*entities + i)->entity_container_id =
+ le16toh(curr_entity->entity_container_id);
+ ++curr_entity;
+ ++i;
+ }
+}
diff --git a/pldm/libpldm/pdr.h b/pldm/libpldm/pdr.h
new file mode 100644
index 00000000..9e39da30
--- /dev/null
+++ b/pldm/libpldm/pdr.h
@@ -0,0 +1,399 @@
+#ifndef PDR_H
+#define PDR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+/** @struct pldm_pdr
+ * opaque structure that acts as a handle to a PDR repository
+ */
+typedef struct pldm_pdr pldm_pdr;
+
+/** @struct pldm_pdr_record
+ * opaque structure that acts as a handle to a PDR record
+ */
+typedef struct pldm_pdr_record pldm_pdr_record;
+
+/* ====================== */
+/* Common PDR access APIs */
+/* ====================== */
+
+/** @brief Make a new PDR repository
+ *
+ * @return opaque pointer that acts as a handle to the repository; NULL if no
+ * repository could be created
+ *
+ * @note Caller may make multiple repositories (for its own PDRs, as well as
+ * for PDRs received by other entities) and can associate the returned handle
+ * to a PLDM terminus id.
+ */
+pldm_pdr *pldm_pdr_init();
+
+/** @brief Destroy a PDR repository (and free up associated resources)
+ *
+ * @param[in/out] repo - pointer to opaque pointer acting as a PDR repo handle
+ */
+void pldm_pdr_destroy(pldm_pdr *repo);
+
+/** @brief Get number of records in a PDR repository
+ *
+ * @param[in] repo - opaque pointer acting as a PDR repo handle
+ *
+ * @return uint32_t - number of records
+ */
+uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo);
+
+/** @brief Get size of a PDR repository, in bytes
+ *
+ * @param[in] repo - opaque pointer acting as a PDR repo handle
+ *
+ * @return uint32_t - size in bytes
+ */
+uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo);
+
+/** @brief Add a PDR record to a PDR repository
+ *
+ * @param[in/out] repo - opaque pointer acting as a PDR repo handle
+ * @param[in] data - pointer to a PDR record, pointing to a PDR definition as
+ * per DSP0248. This data is memcpy'd.
+ * @param[in] size - size of input PDR record in bytes
+ * @param[in] record_handle - record handle of input PDR record; if this is set
+ * to 0, then a record handle is computed and assigned to this PDR record
+ * @param[in] is_remote - if true, then the PDR is not from this terminus
+ *
+ * @return uint32_t - record handle assigned to PDR record
+ */
+uint32_t pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size,
+ uint32_t record_handle, bool is_remote);
+
+/** @brief Get record handle of a PDR record
+ *
+ * @param[in] repo - opaque pointer acting as a PDR repo handle
+ * @param[in] record - opaque pointer acting as a PDR record handle
+ *
+ * @return uint32_t - record handle assigned to PDR record; 0 if record is not
+ * found
+ */
+uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo,
+ const pldm_pdr_record *record);
+
+/** @brief Find PDR record by record handle
+ *
+ * @param[in] repo - opaque pointer acting as a PDR repo handle
+ * @param[in] record_handle - input record handle
+ * @param[in/out] data - will point to PDR record data (as per DSP0248) on
+ * return
+ * @param[out] size - *size will be size of PDR record
+ * @param[out] next_record_handle - *next_record_handle will be the record
+ * handle of record next to the returned PDR record
+ *
+ * @return opaque pointer acting as PDR record handle, will be NULL if record
+ * was not found
+ */
+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);
+
+/** @brief Get PDR record next to input PDR record
+ *
+ * @param[in] repo - opaque pointer acting as a PDR repo handle
+ * @param[in] curr_record - opaque pointer acting as a PDR record handle
+ * @param[in/out] data - will point to PDR record data (as per DSP0248) on
+ * return
+ * @param[out] size - *size will be size of PDR record
+ * @param[out] next_record_handle - *next_record_handle will be the record
+ * handle of record nect to the returned PDR record
+ *
+ * @return opaque pointer acting as PDR record handle, will be NULL if record
+ * was not found
+ */
+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);
+
+/** @brief Find (first) PDR record by PDR type
+ *
+ * @param[in] repo - opaque pointer acting as a PDR repo handle
+ * @param[in] pdr_type - PDR type number as per DSP0248
+ * @param[in] curr_record - opaque pointer acting as a PDR record handle; if
+ * not NULL, then search will begin from this record's next record
+ * @param[in/out] data - will point to PDR record data (as per DSP0248) on
+ * return, if input is not NULL
+ * @param[out] size - *size will be size of PDR record, if input is not NULL
+ *
+ * @return opaque pointer acting as PDR record handle, will be NULL if record
+ * was not found
+ */
+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);
+
+bool pldm_pdr_record_is_remote(const pldm_pdr_record *record);
+
+/** @brief Remove all PDR records that belong to a remote terminus
+ *
+ * @param[in] repo - opaque pointer acting as a PDR repo handle
+ */
+void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo);
+
+/** @brief Update the validity of TL PDR - the validity is decided based on
+ * whether the valid bit is set or not as per the spec DSP0248
+ *
+ * @param[in] repo - opaque pointer acting as a PDR repo handle
+ * @param[in] terminusHandle - PLDM terminus handle
+ * @param[in] tid - Terminus ID
+ * @param[in] tlEid - MCTP endpoint EID
+ * @param[in] valid - validity bit of TLPDR
+ */
+void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminusHandle,
+ uint8_t tid, uint8_t tlEid, bool valid);
+
+/* ======================= */
+/* FRU Record Set PDR APIs */
+/* ======================= */
+
+/** @brief Add a FRU record set PDR record to a PDR repository
+ *
+ * @param[in/out] repo - opaque pointer acting as a PDR repo handle
+ * @param[in] terminus_handle - PLDM terminus handle of terminus owning the PDR
+ * record
+ * @param[in] fru_rsi - FRU record set identifier
+ * @param[in] entity_type - entity type of FRU
+ * @param[in] entity_instance_num - entity instance number of FRU
+ * @param[in] container_id - container id of FRU
+ * @param[in] bmc_record_handle - handle used to construct the next record
+ *
+ * @return uint32_t - record handle assigned to PDR record
+ */
+uint32_t pldm_pdr_add_fru_record_set(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);
+
+/** @brief Find a FRU record set PDR by FRU record set identifier
+ *
+ * @param[in] repo - opaque pointer acting as a PDR repo handle
+ * @param[in] fru_rsi - FRU record set identifier
+ * @param[in] terminus_handle - *terminus_handle will be FRU terminus handle of
+ * found PDR, or 0 if not found
+ * @param[in] entity_type - *entity_type will be FRU entity type of found PDR,
+ * or 0 if not found
+ * @param[in] entity_instance_num - *entity_instance_num will be FRU entity
+ * instance number of found PDR, or 0 if not found
+ * @param[in] container_id - *cintainer_id will be FRU container id of found
+ * PDR, or 0 if not found
+ *
+ * @return uint32_t - record handle assigned to PDR record
+ */
+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);
+
+/* =========================== */
+/* Entity Association PDR APIs */
+/* =========================== */
+
+typedef struct pldm_entity {
+ uint16_t entity_type;
+ uint16_t entity_instance_num;
+ uint16_t entity_container_id;
+} __attribute__((packed)) pldm_entity;
+
+enum entity_association_containment_type {
+ PLDM_ENTITY_ASSOCIAION_PHYSICAL = 0x0,
+ PLDM_ENTITY_ASSOCIAION_LOGICAL = 0x1,
+};
+
+/** @struct pldm_entity_association_tree
+ * opaque structure that represents the entity association hierarchy
+ */
+typedef struct pldm_entity_association_tree pldm_entity_association_tree;
+
+/** @struct pldm_entity_node
+ * opaque structure that represents a node in the entity association hierarchy
+ */
+typedef struct pldm_entity_node pldm_entity_node;
+
+/** @brief Make a new entity association tree
+ *
+ * @return opaque pointer that acts as a handle to the tree; NULL if no
+ * tree could be created
+ */
+pldm_entity_association_tree *pldm_entity_association_tree_init();
+
+/** @brief Add an entity into the entity association tree
+ *
+ * @param[in/out] tree - opaque pointer acting as a handle to the tree
+ * @param[in/out] entity - pointer to the entity to be added. Input has the
+ * entity type. On output, instance number and the
+ * container id are populated.
+ * @param[in] entity_instance_number - entity instance number, we can use the
+ * entity instance number of the entity by
+ * default if its value is equal 0xFFFF.
+ * @param[in] parent - pointer to the node that should be the parent of input
+ * entity. If this is NULL, then the entity is the root
+ * @param[in] association_type - relation with the parent : logical or physical
+ *
+ * @return pldm_entity_node* - opaque pointer to added entity
+ */
+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);
+
+/** @brief Visit and note each entity in the entity association tree
+ *
+ * @param[in] tree - opaque pointer acting as a handle to the tree
+ * @param[out] entities - pointer to list of pldm_entity's. To be free()'d by
+ * the caller
+ * @param[out] size - number of pldm_entity's
+ */
+void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
+ pldm_entity **entities, size_t *size);
+
+/** @brief Extract pldm entity by the pldm_entity_node
+ *
+ * @param[in] node - opaque pointer to added entity
+ *
+ * @return pldm_entity - pldm entity
+ */
+pldm_entity pldm_entity_extract(pldm_entity_node *node);
+
+/** @brief Destroy entity association tree
+ *
+ * @param[in] tree - opaque pointer acting as a handle to the tree
+ */
+void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree);
+
+/** @brief Check if input enity node is a parent
+ *
+ * @param[in] node - opaque pointer acting as a handle to an entity node
+ *
+ * @return bool true if node is a parent, false otherwise
+ */
+bool pldm_entity_is_node_parent(pldm_entity_node *node);
+
+/** @brief Get parent of entity
+ *
+ * @param[in] node - opaque pointer acting as a handle to an entity node
+ *
+ * @return pldm_entity - pldm entity
+ */
+pldm_entity pldm_entity_get_parent(pldm_entity_node *node);
+
+/** @brief Check the current pldm entity is exist parent
+ *
+ * @param[in] node - opaque pointer acting as a handle to an entity node
+ *
+ * @return bool true if exist parent, false otherwise
+ */
+bool pldm_entity_is_exist_parent(pldm_entity_node *node);
+
+/** @brief Convert entity association tree to PDR
+ *
+ * @param[in] tree - opaque pointer to entity association tree
+ * @param[in] repo - PDR repo where entity association records should be added
+ * @param[in] is_remote - if true, then the PDR is not from this terminus
+ */
+void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
+ pldm_pdr *repo, bool is_remote);
+/** @brief Add entity association pdr from node
+ *
+ * @param[in] node - opaque pointer acting as a handle to an entity node
+ * @param[in] repo - PDR repo where entity association records should be added
+ * @param[in] is_remote - if true, then the PDR is not from this terminus
+ */
+void pldm_entity_association_pdr_add_from_node(pldm_entity_node *node,
+ pldm_pdr *repo,
+ pldm_entity **entities,
+ size_t num_entities,
+ bool is_remote);
+
+/** @brief Find entity reference in tree
+ *
+ * @param[in] tree - opaque pointer to entity association tree
+ * @param[in] entity - PLDM entity
+ * @param[in] node - node to the entity
+ */
+void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
+ pldm_entity entity, pldm_entity_node **node);
+
+/** @brief Get number of children of entity
+ *
+ * @param[in] node - opaque pointer acting as a handle to an entity node
+ * @param[in] association_type - relation type filter : logical or physical
+ *
+ * @return uint8_t number of children
+ */
+uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
+ uint8_t association_type);
+
+/** @brief Verify that the current node is a child of the current parent
+ *
+ * @param[in] parent - opaque pointer acting as a handle to an entity parent
+ * @param[in] node - pointer to the node of the pldm entity
+ */
+bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node);
+
+/** @brief Find an entity in the entity association tree
+ *
+ * @param[in] tree - pointer to entity association tree
+ * @param[in/out] entity - entity type and instance id set on input, container
+ * id set on output
+ *
+ * @return pldm_entity_node* pointer to entity if found, NULL otherwise
+ */
+pldm_entity_node *
+pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
+ pldm_entity *entity);
+
+/** @brief Create a copy of an existing entity association tree
+ *
+ * @param[in] org_tree - pointer to source tree
+ * @param[in/out] new_tree - pointer to destination tree
+ */
+void pldm_entity_association_tree_copy_root(
+ pldm_entity_association_tree *org_tree,
+ pldm_entity_association_tree *new_tree);
+
+/** @brief Destroy all the nodes of the entity association tree
+ *
+ * @param[in] tree - pointer to entity association tree
+ */
+void pldm_entity_association_tree_destroy_root(
+ pldm_entity_association_tree *tree);
+
+/** @brief Check whether the entity association tree is empty
+ *
+ * @param[in] tree - pointer to entity association tree
+ * @return bool, true if tree is empty
+ */
+bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree);
+
+/** @brief Extract entities from entity association PDR
+ *
+ * @param[in] pdr - entity association PDR
+ * @param[in] pdr_len - size of entity association PDR in bytes
+ * @param[out] num_entities - number of entities found, including the container
+ * @param[out] entities - extracted entities, container is *entities[0]. Caller
+ * must free *entities
+ */
+void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
+ size_t *num_entities,
+ pldm_entity **entities);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PDR_H */
diff --git a/pldm/libpldm/platform.c b/pldm/libpldm/platform.c
new file mode 100644
index 00000000..8e332396
--- /dev/null
+++ b/pldm/libpldm/platform.c
@@ -0,0 +1,1706 @@
+#include <endian.h>
+#include <string.h>
+
+#include "platform.h"
+
+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;
+}
+
+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,
+ *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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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)
+{
+ 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;
+ }
+
+ struct pldm_set_state_effecter_states_req *request =
+ (struct pldm_set_state_effecter_states_req *)msg->payload;
+
+ *effecter_id = le16toh(request->effecter_id);
+ *comp_effecter_count = request->comp_effecter_count;
+ memcpy(field, request->field,
+ (sizeof(set_effecter_state_field) * (*comp_effecter_count)));
+
+ return PLDM_SUCCESS;
+}
+
+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)
+{
+ 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;
+ }
+
+ struct pldm_get_pdr_req *request =
+ (struct pldm_get_pdr_req *)msg->payload;
+ *record_hndl = le32toh(request->record_handle);
+ *data_transfer_hndl = le32toh(request->data_transfer_handle);
+ *transfer_op_flag = request->transfer_op_flag;
+ *request_cnt = le16toh(request->request_count);
+ *record_chg_num = le16toh(request->record_change_number);
+
+ return PLDM_SUCCESS;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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)
+{
+ 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;
+ }
+
+ *completion_code = msg->payload[0];
+ if (PLDM_SUCCESS != *completion_code) {
+ return PLDM_SUCCESS;
+ }
+
+ if (payload_length < PLDM_GET_PDR_MIN_RESP_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_get_pdr_resp *response =
+ (struct pldm_get_pdr_resp *)msg->payload;
+
+ *next_record_hndl = le32toh(response->next_record_handle);
+ *next_data_transfer_hndl = le32toh(response->next_data_transfer_handle);
+ *transfer_flag = response->transfer_flag;
+ *resp_cnt = le16toh(response->response_count);
+
+ if (*transfer_flag != PLDM_END &&
+ (int)payload_length != PLDM_GET_PDR_MIN_RESP_BYTES + *resp_cnt) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ if (*transfer_flag == PLDM_END &&
+ (int)payload_length !=
+ PLDM_GET_PDR_MIN_RESP_BYTES + *resp_cnt + 1) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ if (*resp_cnt > 0 && record_data != NULL) {
+ if (record_data_length < *resp_cnt) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+ memcpy(record_data, response->record_data, *resp_cnt);
+ }
+
+ if (*transfer_flag == PLDM_END) {
+ *transfer_crc =
+ msg->payload[PLDM_GET_PDR_MIN_RESP_BYTES + *resp_cnt];
+ }
+
+ return PLDM_SUCCESS;
+}
+
+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)
+{
+ if (msg == NULL || effecter_id == NULL || effecter_data_size == NULL ||
+ effecter_value == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (payload_length < PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_set_numeric_effecter_value_req *request =
+ (struct pldm_set_numeric_effecter_value_req *)msg->payload;
+ *effecter_id = le16toh(request->effecter_id);
+ *effecter_data_size = request->effecter_data_size;
+
+ if (*effecter_data_size > PLDM_EFFECTER_DATA_SIZE_SINT32) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ 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;
+ }
+
+ *effecter_value = request->effecter_value[0];
+ }
+
+ 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;
+ }
+
+ memcpy(effecter_value, request->effecter_value, 2);
+ uint16_t *val = (uint16_t *)(effecter_value);
+ *val = le16toh(*val);
+ }
+
+ 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;
+ }
+
+ memcpy(effecter_value, request->effecter_value, 4);
+ uint32_t *val = (uint32_t *)(effecter_value);
+ *val = le32toh(*val);
+ }
+
+ return PLDM_SUCCESS;
+}
+
+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;
+}
+
+int encode_set_numeric_effecter_value_req(
+ uint8_t instance_id, uint16_t effecter_id, uint8_t effecter_data_size,
+ 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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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)
+{
+ if (msg == NULL || completion_code == NULL ||
+ comp_sensor_count == NULL || field == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ *completion_code = msg->payload[0];
+ if (PLDM_SUCCESS != *completion_code) {
+ return PLDM_SUCCESS;
+ }
+
+ struct pldm_get_state_sensor_readings_resp *response =
+ (struct pldm_get_state_sensor_readings_resp *)msg->payload;
+
+ if (response->comp_sensor_count < 0x1 ||
+ response->comp_sensor_count > 0x8) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (payload_length >
+ PLDM_GET_STATE_SENSOR_READINGS_MIN_RESP_BYTES +
+ sizeof(get_sensor_state_field) * response->comp_sensor_count) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ *comp_sensor_count = response->comp_sensor_count;
+
+ memcpy(field, response->field,
+ (sizeof(get_sensor_state_field) * (*comp_sensor_count)));
+
+ return PLDM_SUCCESS;
+}
+
+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)
+{
+ if (msg == NULL || sensor_id == NULL || sensor_rearm == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (payload_length != PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_get_state_sensor_readings_req *request =
+ (struct pldm_get_state_sensor_readings_req *)msg->payload;
+
+ *sensor_id = le16toh(request->sensor_id);
+ *reserved = request->reserved;
+ memcpy(&(sensor_rearm->byte), &(request->sensor_rearm.byte),
+ sizeof(request->sensor_rearm.byte));
+
+ return PLDM_SUCCESS;
+}
+
+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;
+}
+
+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)
+{
+
+ if (msg == NULL || format_version == NULL || tid == NULL ||
+ event_class == NULL || event_data_offset == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (payload_length <= PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+ struct pldm_platform_event_message_req *response =
+ (struct pldm_platform_event_message_req *)msg->payload;
+
+ *format_version = response->format_version;
+ *tid = response->tid;
+ *event_class = response->event_class;
+ *event_data_offset =
+ sizeof(*format_version) + sizeof(*tid) + sizeof(*event_class);
+
+ return PLDM_SUCCESS;
+}
+
+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;
+}
+
+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;
+}
+
+int decode_platform_event_message_resp(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint8_t *completion_code,
+ uint8_t *platform_event_status)
+{
+ if (msg == NULL || completion_code == NULL ||
+ platform_event_status == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ *completion_code = msg->payload[0];
+ if (PLDM_SUCCESS != *completion_code) {
+ return PLDM_SUCCESS;
+ }
+ if (payload_length != PLDM_PLATFORM_EVENT_MESSAGE_RESP_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_platform_event_message_resp *response =
+ (struct pldm_platform_event_message_resp *)msg->payload;
+ *platform_event_status = response->platform_event_status;
+
+ if (*platform_event_status > PLDM_EVENT_LOGGING_REJECTED) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ return PLDM_SUCCESS;
+}
+
+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)
+{
+ if (event_data == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ if (event_data_length < PLDM_SENSOR_EVENT_DATA_MIN_LENGTH) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ size_t event_class_data_length =
+ event_data_length - PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES;
+
+ struct pldm_sensor_event_data *sensor_event_data =
+ (struct pldm_sensor_event_data *)event_data;
+ *sensor_id = sensor_event_data->sensor_id;
+ *sensor_event_class_type = sensor_event_data->sensor_event_class_type;
+ if (sensor_event_data->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_data->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_data->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_SUCCESS;
+}
+
+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)
+{
+ if (sensor_data == NULL || present_op_state == NULL ||
+ previous_op_state == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ if (sensor_data_length !=
+ PLDM_SENSOR_EVENT_SENSOR_OP_STATE_DATA_LENGTH) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_sensor_event_sensor_op_state *sensor_op_data =
+ (struct pldm_sensor_event_sensor_op_state *)sensor_data;
+ *present_op_state = sensor_op_data->present_op_state;
+ *previous_op_state = sensor_op_data->previous_op_state;
+ return PLDM_SUCCESS;
+}
+
+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)
+{
+ if (sensor_data == NULL || sensor_offset == NULL ||
+ event_state == NULL || previous_event_state == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ if (sensor_data_length !=
+ PLDM_SENSOR_EVENT_STATE_SENSOR_STATE_DATA_LENGTH) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_sensor_event_state_sensor_state *sensor_state_data =
+ (struct pldm_sensor_event_state_sensor_state *)sensor_data;
+ *sensor_offset = sensor_state_data->sensor_offset;
+ *event_state = sensor_state_data->event_state;
+ *previous_event_state = sensor_state_data->previous_event_state;
+ return PLDM_SUCCESS;
+}
+
+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)
+{
+ if (sensor_data == NULL || 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_MIN_DATA_LENGTH ||
+ sensor_data_length >
+ PLDM_SENSOR_EVENT_NUMERIC_SENSOR_STATE_MAX_DATA_LENGTH) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+ struct pldm_sensor_event_numeric_sensor_state *numeric_sensor_data =
+ (struct pldm_sensor_event_numeric_sensor_state *)sensor_data;
+ *event_state = numeric_sensor_data->event_state;
+ *previous_event_state = numeric_sensor_data->previous_event_state;
+ *sensor_data_size = numeric_sensor_data->sensor_data_size;
+ uint8_t *present_reading_ptr = numeric_sensor_data->present_reading;
+
+ switch (*sensor_data_size) {
+ case PLDM_SENSOR_DATA_SIZE_UINT8:
+ case PLDM_SENSOR_DATA_SIZE_SINT8:
+ if (sensor_data_length !=
+ PLDM_SENSOR_EVENT_NUMERIC_SENSOR_STATE_8BIT_DATA_LENGTH) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+ *present_reading = present_reading_ptr[0];
+ break;
+ case PLDM_SENSOR_DATA_SIZE_UINT16:
+ case PLDM_SENSOR_DATA_SIZE_SINT16:
+ if (sensor_data_length !=
+ PLDM_SENSOR_EVENT_NUMERIC_SENSOR_STATE_16BIT_DATA_LENGTH) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+ *present_reading = le16toh(present_reading_ptr[1] |
+ (present_reading_ptr[0] << 8));
+ break;
+ case PLDM_SENSOR_DATA_SIZE_UINT32:
+ case PLDM_SENSOR_DATA_SIZE_SINT32:
+ if (sensor_data_length !=
+ PLDM_SENSOR_EVENT_NUMERIC_SENSOR_STATE_32BIT_DATA_LENGTH) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+ *present_reading = le32toh(present_reading_ptr[3] |
+ (present_reading_ptr[2] << 8) |
+ (present_reading_ptr[1] << 16) |
+ (present_reading_ptr[0] << 24));
+ break;
+ default:
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ return PLDM_SUCCESS;
+}
+
+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;
+}
+
+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, uint8_t *pending_value, 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;
+}
+
+int decode_get_numeric_effecter_value_req(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint16_t *effecter_id)
+{
+ if (msg == NULL || effecter_id == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (payload_length != PLDM_GET_NUMERIC_EFFECTER_VALUE_REQ_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_get_numeric_effecter_value_req *request =
+ (struct pldm_get_numeric_effecter_value_req *)msg->payload;
+
+ *effecter_id = le16toh(request->effecter_id);
+
+ return PLDM_SUCCESS;
+}
+
+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)
+{
+ if (msg == NULL || effecter_data_size == NULL ||
+ effecter_oper_state == NULL || pending_value == NULL ||
+ present_value == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ *completion_code = msg->payload[0];
+ if (PLDM_SUCCESS != *completion_code) {
+ return PLDM_SUCCESS;
+ }
+
+ if (payload_length < PLDM_GET_NUMERIC_EFFECTER_VALUE_MIN_RESP_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_get_numeric_effecter_value_resp *response =
+ (struct pldm_get_numeric_effecter_value_resp *)msg->payload;
+
+ *effecter_data_size = response->effecter_data_size;
+ *effecter_oper_state = response->effecter_oper_state;
+
+ 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;
+ }
+
+ 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;
+ }
+ memcpy(pending_value, response->pending_and_present_values, 1);
+ memcpy(present_value, &response->pending_and_present_values[1],
+ 1);
+
+ } 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;
+ }
+ memcpy(pending_value, response->pending_and_present_values,
+ sizeof(uint16_t));
+ uint16_t *val_pending = (uint16_t *)pending_value;
+ *val_pending = le16toh(*val_pending);
+ memcpy(
+ present_value,
+ (response->pending_and_present_values + sizeof(uint16_t)),
+ sizeof(uint16_t));
+ uint16_t *val_present = (uint16_t *)present_value;
+ *val_present = le16toh(*val_present);
+
+ } 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;
+ }
+ memcpy(pending_value, response->pending_and_present_values,
+ sizeof(uint32_t));
+ uint32_t *val_pending = (uint32_t *)pending_value;
+ *val_pending = le32toh(*val_pending);
+ memcpy(
+ present_value,
+ (response->pending_and_present_values + sizeof(uint32_t)),
+ sizeof(uint32_t));
+ uint32_t *val_present = (uint32_t *)present_value;
+ *val_present = le32toh(*val_present);
+ }
+ return PLDM_SUCCESS;
+}
+
+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;
+}
+
+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)
+{
+ if (event_data == NULL || event_data_format == NULL ||
+ number_of_change_records == NULL ||
+ change_record_data_offset == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ if (event_data_size < PLDM_PDR_REPOSITORY_CHG_EVENT_MIN_LENGTH) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_pdr_repository_chg_event_data
+ *pdr_repository_chg_event_data =
+ (struct pldm_pdr_repository_chg_event_data *)event_data;
+
+ *event_data_format = pdr_repository_chg_event_data->event_data_format;
+ *number_of_change_records =
+ pdr_repository_chg_event_data->number_of_change_records;
+ *change_record_data_offset =
+ sizeof(*event_data_format) + sizeof(*number_of_change_records);
+
+ return PLDM_SUCCESS;
+}
+
+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)
+{
+ if (change_record_data == NULL || event_data_operation == NULL ||
+ number_of_change_entries == NULL ||
+ change_entry_data_offset == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ if (change_record_data_size <
+ PLDM_PDR_REPOSITORY_CHANGE_RECORD_MIN_LENGTH) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_pdr_repository_change_record_data
+ *pdr_repository_change_record_data =
+ (struct pldm_pdr_repository_change_record_data *)
+ change_record_data;
+
+ *event_data_operation =
+ pdr_repository_change_record_data->event_data_operation;
+ *number_of_change_entries =
+ pdr_repository_change_record_data->number_of_change_entries;
+ *change_entry_data_offset =
+ sizeof(*event_data_operation) + sizeof(*number_of_change_entries);
+
+ return PLDM_SUCCESS;
+}
+
+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;
+}
+
+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)
+{
+ 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;
+ }
+
+ *completion_code = msg->payload[0];
+ if (PLDM_SUCCESS != *completion_code) {
+ return PLDM_SUCCESS;
+ }
+
+ if (payload_length < PLDM_GET_SENSOR_READING_MIN_RESP_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_get_sensor_reading_resp *response =
+ (struct pldm_get_sensor_reading_resp *)msg->payload;
+
+ if (response->sensor_data_size > PLDM_SENSOR_DATA_SIZE_SINT32) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ if (response->sensor_data_size > *sensor_data_size) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ *sensor_data_size = response->sensor_data_size;
+ *sensor_operational_state = response->sensor_operational_state;
+ *sensor_event_message_enable = response->sensor_event_message_enable;
+ *present_state = response->present_state;
+ *previous_state = response->previous_state;
+ *event_state = response->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;
+ }
+ *present_reading = response->present_reading[0];
+
+ } 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;
+ }
+ memcpy(present_reading, response->present_reading, 2);
+ uint16_t *val = (uint16_t *)(present_reading);
+ *val = le16toh(*val);
+
+ } 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;
+ }
+ memcpy(present_reading, response->present_reading, 4);
+ uint32_t *val = (uint32_t *)(present_reading);
+ *val = le32toh(*val);
+ }
+
+ return PLDM_SUCCESS;
+}
+
+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,
+ 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;
+}
+
+int decode_get_sensor_reading_req(const struct pldm_msg *msg,
+ size_t payload_length, uint16_t *sensor_id,
+ uint8_t *rearm_event_state)
+{
+ if (msg == NULL || sensor_id == NULL || rearm_event_state == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (payload_length != PLDM_GET_SENSOR_READING_REQ_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_get_sensor_reading_req *request =
+ (struct pldm_get_sensor_reading_req *)msg->payload;
+
+ *sensor_id = le16toh(request->sensor_id);
+ *rearm_event_state = request->rearm_event_state;
+
+ return PLDM_SUCCESS;
+}
+
+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;
+}
+
+int decode_set_event_receiver_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_EVENT_RECEIVER_RESP_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ return PLDM_SUCCESS;
+}
+
+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)
+
+{
+ 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;
+ }
+
+ if (payload_length != PLDM_SET_EVENT_RECEIVER_REQ_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_set_event_receiver_req *request =
+ (struct pldm_set_event_receiver_req *)msg->payload;
+
+ if ((*event_message_global_enable ==
+ PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE) &&
+ (*heartbeat_timer == 0)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ *event_message_global_enable = request->event_message_global_enable,
+ *transport_protocol_type = request->transport_protocol_type,
+ *event_receiver_address_info = request->event_receiver_address_info,
+ *heartbeat_timer = le16toh(request->heartbeat_timer);
+
+ return PLDM_SUCCESS;
+}
+
+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;
+}
diff --git a/pldm/libpldm/platform.h b/pldm/libpldm/platform.h
new file mode 100644
index 00000000..962bad06
--- /dev/null
+++ b/pldm/libpldm/platform.h
@@ -0,0 +1,1625 @@
+#ifndef PLATFORM_H
+#define PLATFORM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base.h"
+#include "pdr.h"
+
+/* Maximum size for request */
+#define PLDM_SET_STATE_EFFECTER_STATES_REQ_BYTES 19
+#define PLDM_GET_STATE_SENSOR_READINGS_REQ_BYTES 4
+#define PLDM_GET_NUMERIC_EFFECTER_VALUE_REQ_BYTES 2
+#define PLDM_GET_SENSOR_READING_REQ_BYTES 4
+#define PLDM_SET_EVENT_RECEIVER_REQ_BYTES 5
+/* Response lengths are inclusive of completion code */
+#define PLDM_SET_STATE_EFFECTER_STATES_RESP_BYTES 1
+
+#define PLDM_SET_NUMERIC_EFFECTER_VALUE_RESP_BYTES 1
+#define PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES 4
+
+#define PLDM_GET_PDR_REQ_BYTES 13
+
+#define PLDM_SET_EVENT_RECEIVER_RESP_BYTES 1
+/* Minimum response length */
+#define PLDM_GET_PDR_MIN_RESP_BYTES 12
+#define PLDM_GET_NUMERIC_EFFECTER_VALUE_MIN_RESP_BYTES 5
+#define PLDM_GET_SENSOR_READING_MIN_RESP_BYTES 8
+#define PLDM_GET_STATE_SENSOR_READINGS_MIN_RESP_BYTES 2
+#define PLDM_GET_PDR_REPOSITORY_INFO_RESP_BYTES 41
+
+/* Minimum length for PLDM PlatformEventMessage request */
+#define PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES 3
+#define PLDM_PLATFORM_EVENT_MESSAGE_STATE_SENSOR_STATE_REQ_BYTES 6
+#define PLDM_PLATFORM_EVENT_MESSAGE_RESP_BYTES 2
+#define PLDM_PLATFORM_EVENT_MESSAGE_FORMAT_VERSION 1
+
+/* Minumum length of senson event data */
+#define PLDM_SENSOR_EVENT_DATA_MIN_LENGTH 5
+#define PLDM_SENSOR_EVENT_SENSOR_OP_STATE_DATA_LENGTH 2
+#define PLDM_SENSOR_EVENT_STATE_SENSOR_STATE_DATA_LENGTH 3
+#define PLDM_SENSOR_EVENT_NUMERIC_SENSOR_STATE_MIN_DATA_LENGTH 4
+#define PLDM_SENSOR_EVENT_NUMERIC_SENSOR_STATE_MAX_DATA_LENGTH 7
+#define PLDM_SENSOR_EVENT_NUMERIC_SENSOR_STATE_8BIT_DATA_LENGTH 4
+#define PLDM_SENSOR_EVENT_NUMERIC_SENSOR_STATE_16BIT_DATA_LENGTH 5
+#define PLDM_SENSOR_EVENT_NUMERIC_SENSOR_STATE_32BIT_DATA_LENGTH 7
+
+/* Minimum length of data for pldmPDRRepositoryChgEvent */
+#define PLDM_PDR_REPOSITORY_CHG_EVENT_MIN_LENGTH 2
+#define PLDM_PDR_REPOSITORY_CHANGE_RECORD_MIN_LENGTH 2
+
+#define PLDM_INVALID_EFFECTER_ID 0xFFFF
+#define PLDM_TID_RESERVED 0xFF
+
+enum pldm_effecter_data_size {
+ PLDM_EFFECTER_DATA_SIZE_UINT8,
+ PLDM_EFFECTER_DATA_SIZE_SINT8,
+ PLDM_EFFECTER_DATA_SIZE_UINT16,
+ PLDM_EFFECTER_DATA_SIZE_SINT16,
+ PLDM_EFFECTER_DATA_SIZE_UINT32,
+ PLDM_EFFECTER_DATA_SIZE_SINT32
+};
+
+enum pldm_range_field_format {
+ PLDM_RANGE_FIELD_FORMAT_UINT8,
+ PLDM_RANGE_FIELD_FORMAT_SINT8,
+ PLDM_RANGE_FIELD_FORMAT_UINT16,
+ PLDM_RANGE_FIELD_FORMAT_SINT16,
+ PLDM_RANGE_FIELD_FORMAT_UINT32,
+ PLDM_RANGE_FIELD_FORMAT_SINT32,
+ PLDM_RANGE_FIELD_FORMAT_REAL32
+};
+
+enum set_request { PLDM_NO_CHANGE = 0x00, PLDM_REQUEST_SET = 0x01 };
+
+enum effecter_state { PLDM_INVALID_VALUE = 0xFF };
+
+enum pldm_sensor_present_state {
+ PLDM_SENSOR_UNKNOWN = 0x0,
+ PLDM_SENSOR_NORMAL = 0x01,
+ PLDM_SENSOR_WARNING = 0x02,
+ PLDM_SENSOR_CRITICAL = 0x03,
+ PLDM_SENSOR_FATAL = 0x04,
+ PLDM_SENSOR_LOWERWARNING = 0x05,
+ PLDM_SENSOR_LOWERCRITICAL = 0x06,
+ PLDM_SENSOR_LOWERFATAL = 0x07,
+ PLDM_SENSOR_UPPERWARNING = 0x08,
+ PLDM_SENSOR_UPPERCRITICAL = 0x09,
+ PLDM_SENSOR_UPPERFATAL = 0x0a
+};
+
+enum pldm_sensor_event_message_enable {
+ PLDM_NO_EVENT_GENERATION,
+ PLDM_EVENTS_DISABLED,
+ PLDM_EVENTS_ENABLED,
+ PLDM_OP_EVENTS_ONLY_ENABLED,
+ PLDM_STATE_EVENTS_ONLY_ENABLED
+};
+
+enum pldm_effecter_oper_state {
+ EFFECTER_OPER_STATE_ENABLED_UPDATEPENDING,
+ EFFECTER_OPER_STATE_ENABLED_NOUPDATEPENDING,
+ EFFECTER_OPER_STATE_DISABLED,
+ EFFECTER_OPER_STATE_UNAVAILABLE,
+ EFFECTER_OPER_STATE_STATUSUNKNOWN,
+ EFFECTER_OPER_STATE_FAILED,
+ EFFECTER_OPER_STATE_INITIALIZING,
+ EFFECTER_OPER_STATE_SHUTTINGDOWN,
+ EFFECTER_OPER_STATE_INTEST
+};
+
+enum pldm_platform_commands {
+ PLDM_SET_EVENT_RECEIVER = 0x04,
+ PLDM_GET_SENSOR_READING = 0x11,
+ PLDM_GET_STATE_SENSOR_READINGS = 0x21,
+ PLDM_SET_NUMERIC_EFFECTER_VALUE = 0x31,
+ PLDM_GET_NUMERIC_EFFECTER_VALUE = 0x32,
+ PLDM_SET_STATE_EFFECTER_STATES = 0x39,
+ PLDM_GET_PDR_REPOSITORY_INFO = 0x50,
+ PLDM_GET_PDR = 0x51,
+ PLDM_PLATFORM_EVENT_MESSAGE = 0x0A
+};
+
+/** @brief PLDM PDR types
+ */
+enum pldm_pdr_types {
+ PLDM_TERMINUS_LOCATOR_PDR = 1,
+ PLDM_NUMERIC_SENSOR_PDR = 2,
+ PLDM_NUMERIC_SENSOR_INITIALIZATION_PDR = 3,
+ PLDM_STATE_SENSOR_PDR = 4,
+ PLDM_STATE_SENSOR_INITIALIZATION_PDR = 5,
+ PLDM_SENSOR_AUXILIARY_NAMES_PDR = 6,
+ PLDM_OEM_UNIT_PDR = 7,
+ PLDM_OEM_STATE_SET_PDR = 8,
+ PLDM_NUMERIC_EFFECTER_PDR = 9,
+ PLDM_NUMERIC_EFFECTER_INITIALIZATION_PDR = 10,
+ PLDM_STATE_EFFECTER_PDR = 11,
+ PLDM_STATE_EFFECTER_INITIALIZATION_PDR = 12,
+ PLDM_EFFECTER_AUXILIARY_NAMES_PDR = 13,
+ PLDM_EFFECTER_OEM_SEMANTIC_PDR = 14,
+ PLDM_PDR_ENTITY_ASSOCIATION = 15,
+ PLDM_ENTITY_AUXILIARY_NAMES_PDR = 16,
+ PLDM_OEM_ENTITY_ID_PDR = 17,
+ PLDM_INTERRUPT_ASSOCIATION_PDR = 18,
+ PLDM_EVENT_LOG_PDR = 19,
+ PLDM_PDR_FRU_RECORD_SET = 20,
+ PLDM_OEM_DEVICE_PDR = 126,
+ PLDM_OEM_PDR = 127,
+};
+
+/** @brief PLDM effecter initialization schemes
+ */
+enum pldm_effecter_init {
+ PLDM_NO_INIT,
+ PLDM_USE_INIT_PDR,
+ PLDM_ENABLE_EFFECTER,
+ PLDM_DISABLE_EFECTER
+};
+
+/** @brief PLDM Platform M&C completion codes
+ */
+enum pldm_platform_completion_codes {
+ PLDM_PLATFORM_INVALID_SENSOR_ID = 0x80,
+ PLDM_PLATFORM_REARM_UNAVAILABLE_IN_PRESENT_STATE = 0x81,
+
+ PLDM_PLATFORM_INVALID_EFFECTER_ID = 0x80,
+ PLDM_PLATFORM_INVALID_STATE_VALUE = 0x81,
+
+ PLDM_PLATFORM_INVALID_DATA_TRANSFER_HANDLE = 0x80,
+ PLDM_PLATFORM_INVALID_TRANSFER_OPERATION_FLAG = 0x81,
+ PLDM_PLATFORM_INVALID_RECORD_HANDLE = 0x82,
+ PLDM_PLATFORM_INVALID_RECORD_CHANGE_NUMBER = 0x83,
+ PLDM_PLATFORM_TRANSFER_TIMEOUT = 0x84,
+
+ PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE = 0x82,
+
+ PLDM_PLATFORM_INVALID_PROTOCOL_TYPE = 0x80,
+ PLDM_PLATFORM_ENABLE_METHOD_NOT_SUPPORTED = 0x81,
+ PLDM_PLATFORM_HEARTBEAT_FREQUENCY_TOO_HIGH = 0x82,
+};
+
+/** @brief PLDM Event types
+ */
+enum pldm_event_types {
+ PLDM_SENSOR_EVENT = 0x00,
+ PLDM_EFFECTER_EVENT = 0x01,
+ PLDM_REDFISH_TASK_EXECUTED_EVENT = 0x02,
+ PLDM_REDFISH_MESSAGE_EVENT = 0x03,
+ PLDM_PDR_REPOSITORY_CHG_EVENT = 0x04,
+ PLDM_MESSAGE_POLL_EVENT = 0x05,
+ PLDM_HEARTBEAT_TIMER_ELAPSED_EVENT = 0x06
+};
+
+/** @brief PLDM sensorEventClass states
+ */
+enum sensor_event_class_states {
+ PLDM_SENSOR_OP_STATE,
+ PLDM_STATE_SENSOR_STATE,
+ PLDM_NUMERIC_SENSOR_STATE
+};
+
+/** @brief PLDM sensor supported states
+ */
+enum pldm_sensor_operational_state {
+ PLDM_SENSOR_ENABLED,
+ PLDM_SENSOR_DISABLED,
+ PLDM_SENSOR_UNAVAILABLE,
+ PLDM_SENSOR_STATUSUNKOWN,
+ PLDM_SENSOR_FAILED,
+ PLDM_SENSOR_INITIALIZING,
+ PLDM_SENSOR_SHUTTINGDOWN,
+ PLDM_SENSOR_INTEST
+};
+
+/** @brief PLDM pldmPDRRepositoryChgEvent class eventData format
+ */
+enum pldm_pdr_repository_chg_event_data_format {
+ REFRESH_ENTIRE_REPOSITORY,
+ FORMAT_IS_PDR_TYPES,
+ FORMAT_IS_PDR_HANDLES
+};
+
+/** @brief PLDM pldmPDRRepositoryChgEvent class changeRecord format
+ * eventDataOperation
+ */
+enum pldm_pdr_repository_chg_event_change_record_event_data_operation {
+ PLDM_REFRESH_ALL_RECORDS,
+ PLDM_RECORDS_DELETED,
+ PLDM_RECORDS_ADDED,
+ PLDM_RECORDS_MODIFIED
+};
+
+/** @brief PLDM NumericSensorStatePresentReading data type
+ */
+enum pldm_sensor_readings_data_type {
+ PLDM_SENSOR_DATA_SIZE_UINT8,
+ PLDM_SENSOR_DATA_SIZE_SINT8,
+ PLDM_SENSOR_DATA_SIZE_UINT16,
+ PLDM_SENSOR_DATA_SIZE_SINT16,
+ PLDM_SENSOR_DATA_SIZE_UINT32,
+ PLDM_SENSOR_DATA_SIZE_SINT32
+};
+
+/** @brief PLDM PlatformEventMessage response status
+ */
+enum pldm_platform_event_status {
+ PLDM_EVENT_NO_LOGGING = 0x00,
+ PLDM_EVENT_LOGGING_DISABLED = 0x01,
+ PLDM_EVENT_LOG_FULL = 0x02,
+ PLDM_EVENT_ACCEPTED_FOR_LOGGING = 0x03,
+ PLDM_EVENT_LOGGED = 0x04,
+ PLDM_EVENT_LOGGING_REJECTED = 0x05
+};
+
+/** @brief PLDM Terminus Locator PDR validity
+ */
+enum pldm_terminus_locator_pdr_validity {
+ PLDM_TL_PDR_NOT_VALID,
+ PLDM_TL_PDR_VALID
+};
+
+/** @brief PLDM Terminus Locator type
+ */
+enum pldm_terminus_locator_type {
+ PLDM_TERMINUS_LOCATOR_TYPE_UID,
+ PLDM_TERMINUS_LOCATOR_TYPE_MCTP_EID,
+ PLDM_TERMINUS_LOCATOR_TYPE_SMBUS_RELATIVE,
+ PLDM_TERMINUS_LOCATOR_TYPE_SYS_SW
+};
+
+/** @brief PLDM event message global enable for
+ * SetEventReceiver command
+ */
+enum pldm_event_message_global_enable {
+ PLDM_EVENT_MESSAGE_GLOBAL_DISABLE,
+ PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC,
+ PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_POLLING,
+ PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE
+};
+
+/** @brief PLDM respository state */
+enum pldm_repository_state {
+ PLDM_AVAILABLE,
+ PLDM_UPDATE_IN_PROGRESS,
+ PLDM_FAILED
+};
+
+/** @brief PLDM respository data transfer handler timeout */
+enum pldm_repository_data_transfer_handler_timeout {
+ PLDM_NO_TIMEOUT,
+ PLDM_DEFALUT_MINIMUM_TIMEOUT
+};
+
+/** @struct pldm_pdr_hdr
+ *
+ * Structure representing PLDM common PDR header
+ */
+struct pldm_pdr_hdr {
+ uint32_t record_handle;
+ uint8_t version;
+ uint8_t type;
+ uint16_t record_change_num;
+ uint16_t length;
+} __attribute__((packed));
+
+/** @struct pldm_terminus_locator_pdr
+ *
+ * Structure representing PLDM terminus locator PDR
+ */
+struct pldm_terminus_locator_pdr {
+ struct pldm_pdr_hdr hdr;
+ uint16_t terminus_handle;
+ uint8_t validity;
+ uint8_t tid;
+ uint16_t container_id;
+ uint8_t terminus_locator_type;
+ uint8_t terminus_locator_value_size;
+ uint8_t terminus_locator_value[1];
+} __attribute__((packed));
+
+/** @struct pldm_terminus_locator_type_mctp_eid
+ *
+ * Structure representing terminus locator value for
+ * terminus locator type MCTP_EID
+ */
+struct pldm_terminus_locator_type_mctp_eid {
+ uint8_t eid;
+} __attribute__((packed));
+
+/** @struct pldm_pdr_entity_association
+ *
+ * Structure representing PLDM Entity Association PDR
+ */
+struct pldm_pdr_entity_association {
+ uint16_t container_id;
+ uint8_t association_type;
+ pldm_entity container;
+ uint8_t num_children;
+ pldm_entity children[1];
+} __attribute__((packed));
+
+/** @struct pldm_pdr_fru_record_set
+ *
+ * Structure representing PLDM FRU record set PDR
+ */
+struct pldm_pdr_fru_record_set {
+ uint16_t terminus_handle;
+ uint16_t fru_rsi;
+ uint16_t entity_type;
+ uint16_t entity_instance_num;
+ uint16_t container_id;
+} __attribute__((packed));
+
+/** @struct pldm_state_sensor_pdr
+ *
+ * Structure representing PLDM state sensor PDR
+ */
+struct pldm_state_sensor_pdr {
+ struct pldm_pdr_hdr hdr;
+ uint16_t terminus_handle;
+ uint16_t sensor_id;
+ uint16_t entity_type;
+ uint16_t entity_instance;
+ uint16_t container_id;
+ uint8_t sensor_init;
+ bool8_t sensor_auxiliary_names_pdr;
+ uint8_t composite_sensor_count;
+ uint8_t possible_states[1];
+} __attribute__((packed));
+
+/** @struct state_sensor_possible_states
+ *
+ * Structure representing state enums for state sensor
+ */
+struct state_sensor_possible_states {
+ uint16_t state_set_id;
+ uint8_t possible_states_size;
+ bitfield8_t states[1];
+} __attribute__((packed));
+
+/** @struct pldm_state_effecter_pdr
+ *
+ * Structure representing PLDM state effecter PDR
+ */
+struct pldm_state_effecter_pdr {
+ struct pldm_pdr_hdr hdr;
+ uint16_t terminus_handle;
+ uint16_t effecter_id;
+ uint16_t entity_type;
+ uint16_t entity_instance;
+ uint16_t container_id;
+ uint16_t effecter_semantic_id;
+ uint8_t effecter_init;
+ bool8_t has_description_pdr;
+ uint8_t composite_effecter_count;
+ uint8_t possible_states[1];
+} __attribute__((packed));
+
+/** @brief Encode PLDM state sensor PDR
+ *
+ * @param[in/out] sensor Structure to encode. All members of
+ * sensor, except those mentioned in the @note below, should be initialized by
+ * the caller.
+ * @param[in] allocation_size Size of sensor allocation in bytes
+ * @param[in] possible_states Possible sensor states
+ * @param[in] possible_states_size Size of possible sensor states in bytes
+ * @param[out] actual_size Size of sensor PDR. Set to 0 on error.
+ * @return int pldm_completion_codes
+ * PLDM_SUCCESS/PLDM_ERROR/PLDM_ERROR_INVALID_LENGTH
+ *
+ * @note The sensor parameter will be encoded in place.
+ * @note Caller is responsible for allocation of the sensor parameter. Caller
+ * must allocate enough space for the base structure and the
+ * sensor->possible_states array, otherwise the function will fail.
+ * @note sensor->hdr.length, .type, and .version will be set appropriately.
+ */
+int encode_state_sensor_pdr(
+ struct pldm_state_sensor_pdr *sensor, size_t allocation_size,
+ const struct state_sensor_possible_states *possible_states,
+ size_t possible_states_size, size_t *actual_size);
+
+/** @union union_effecter_data_size
+ *
+ * The bit width and format of reading and threshold values that the effecter
+ * returns.
+ * Refer to: DSP0248_1.2.0: 28.11 Table 87
+ */
+typedef union {
+ uint8_t value_u8;
+ int8_t value_s8;
+ uint16_t value_u16;
+ int16_t value_s16;
+ uint32_t value_u32;
+ int32_t value_s32;
+} union_effecter_data_size;
+
+/** @union union_range_field_format
+ *
+ * Indicates the format used for the nominalValue, normalMax, and normalMin
+ * fields.
+ * Refer to: DSP0248_1.2.0: 28.11 Table 87
+ */
+typedef union {
+ uint8_t value_u8;
+ int8_t value_s8;
+ uint16_t value_u16;
+ int16_t value_s16;
+ uint32_t value_u32;
+ int32_t value_s32;
+ real32_t value_f32;
+} union_range_field_format;
+
+/** @struct pldm_numeric_effecter_value_pdr
+ *
+ * Structure representing PLDM numeric effecter value PDR
+ */
+struct pldm_numeric_effecter_value_pdr {
+ struct pldm_pdr_hdr hdr;
+ uint16_t terminus_handle;
+ uint16_t effecter_id;
+ uint16_t entity_type;
+ uint16_t entity_instance;
+ uint16_t container_id;
+ uint16_t effecter_semantic_id;
+ uint8_t effecter_init;
+ bool8_t effecter_auxiliary_names;
+ uint8_t base_unit;
+ int8_t unit_modifier;
+ uint8_t rate_unit;
+ uint8_t base_oem_unit_handle;
+ uint8_t aux_unit;
+ int8_t aux_unit_modifier;
+ uint8_t aux_rate_unit;
+ uint8_t aux_oem_unit_handle;
+ bool8_t is_linear;
+ uint8_t effecter_data_size;
+ real32_t resolution;
+ real32_t offset;
+ uint16_t accuracy;
+ uint8_t plus_tolerance;
+ uint8_t minus_tolerance;
+ real32_t state_transition_interval;
+ real32_t transition_interval;
+ union_effecter_data_size max_set_table;
+ union_effecter_data_size min_set_table;
+ uint8_t range_field_format;
+ bitfield8_t range_field_support;
+ union_range_field_format nominal_value;
+ union_range_field_format normal_max;
+ union_range_field_format normal_min;
+ union_range_field_format rated_max;
+ union_range_field_format rated_min;
+} __attribute__((packed));
+
+/** @struct state_effecter_possible_states
+ *
+ * Structure representing state enums for state effecter
+ */
+struct state_effecter_possible_states {
+ uint16_t state_set_id;
+ uint8_t possible_states_size;
+ bitfield8_t states[1];
+} __attribute__((packed));
+
+/** @brief Encode PLDM state effecter PDR
+ *
+ * @param[in/out] effecter Structure to encode. All members of
+ * effecter, except those mentioned in
+ * the @note below, should be initialized
+ * by the caller.
+ * @param[in] allocation_size Size of effecter allocation in bytes
+ * @param[in] possible_states Possible effecter states
+ * @param[in] possible_states_size Size of possible effecter states in
+ * bytes
+ * @param[out] actual_size Size of effecter PDR. Set to 0 on
+ * error.
+ * @return int pldm_completion_codes
+ * PLDM_SUCCESS/PLDM_ERROR/PLDM_ERROR_INVALID_LENGTH
+ *
+ * @note The effecter parameter will be encoded in place.
+ * @note Caller is responsible for allocation of the effecter parameter. Caller
+ * must allocate enough space for the base structure and the
+ * effecter->possible_states array, otherwise the function will fail.
+ * @note effecter->hdr.length, .type, and .version will be set appropriately.
+ */
+int encode_state_effecter_pdr(
+ struct pldm_state_effecter_pdr *effecter, size_t allocation_size,
+ const struct state_effecter_possible_states *possible_states,
+ size_t possible_states_size, size_t *actual_size);
+
+/** @struct set_effecter_state_field
+ *
+ * Structure representing a stateField in SetStateEffecterStates command */
+
+typedef struct state_field_for_state_effecter_set {
+ uint8_t set_request; //!< Whether to change the state
+ uint8_t effecter_state; //!< Expected state of the effecter
+} __attribute__((packed)) set_effecter_state_field;
+
+/** @struct get_sensor_readings_field
+ *
+ * Structure representing a stateField in GetStateSensorReadings command */
+
+typedef struct state_field_for_get_state_sensor_readings {
+ uint8_t sensor_op_state; //!< The state of the sensor itself
+ uint8_t present_state; //!< Return a state value
+ uint8_t previous_state; //!< The state that the presentState was entered
+ //! from. This must be different from the
+ //! present state
+ uint8_t event_state; //!< Return a state value from a PLDM State Set
+ //! that is associated with the sensor
+} __attribute__((packed)) get_sensor_state_field;
+
+/** @struct PLDM_SetStateEffecterStates_Request
+ *
+ * Structure representing PLDM set state effecter states request.
+ */
+struct pldm_set_state_effecter_states_req {
+ uint16_t effecter_id;
+ uint8_t comp_effecter_count;
+ set_effecter_state_field field[8];
+} __attribute__((packed));
+
+/** @struct pldm_get_pdr_repository_info_resp
+ *
+ * Structure representing GetPDRRepositoryInfo response packet
+ */
+struct pldm_pdr_repository_info_resp {
+ uint8_t completion_code;
+ uint8_t repository_state;
+ uint8_t update_time[PLDM_TIMESTAMP104_SIZE];
+ uint8_t oem_update_time[PLDM_TIMESTAMP104_SIZE];
+ uint32_t record_count;
+ uint32_t repository_size;
+ uint32_t largest_record_size;
+ uint8_t data_transfer_handle_timeout;
+} __attribute__((packed));
+
+/** @struct pldm_get_pdr_resp
+ *
+ * structure representing GetPDR response packet
+ * transfer CRC is not part of the structure and will be
+ * added at the end of last packet in multipart transfer
+ */
+struct pldm_get_pdr_resp {
+ uint8_t completion_code;
+ uint32_t next_record_handle;
+ uint32_t next_data_transfer_handle;
+ uint8_t transfer_flag;
+ uint16_t response_count;
+ uint8_t record_data[1];
+} __attribute__((packed));
+
+/** @struct pldm_get_pdr_req
+ *
+ * structure representing GetPDR request packet
+ */
+struct pldm_get_pdr_req {
+ uint32_t record_handle;
+ uint32_t data_transfer_handle;
+ uint8_t transfer_op_flag;
+ uint16_t request_count;
+ uint16_t record_change_number;
+} __attribute__((packed));
+
+/** @struct pldm_set_event_receiver_req
+ *
+ * Structure representing SetEventReceiver command.
+ * This structure applies only for MCTP as a transport type.
+ */
+struct pldm_set_event_receiver_req {
+ uint8_t event_message_global_enable;
+ uint8_t transport_protocol_type;
+ uint8_t event_receiver_address_info;
+ uint16_t heartbeat_timer;
+} __attribute__((packed));
+
+/** @struct pldm_set_numeric_effecter_value_req
+ *
+ * structure representing SetNumericEffecterValue request packet
+ */
+struct pldm_set_numeric_effecter_value_req {
+ uint16_t effecter_id;
+ uint8_t effecter_data_size;
+ uint8_t effecter_value[1];
+} __attribute__((packed));
+
+/** @struct pldm_get_state_sensor_readings_req
+ *
+ * Structure representing PLDM get state sensor readings request.
+ */
+struct pldm_get_state_sensor_readings_req {
+ uint16_t sensor_id;
+ bitfield8_t sensor_rearm;
+ uint8_t reserved;
+} __attribute__((packed));
+
+/** @struct pldm_get_state_sensor_readings_resp
+ *
+ * Structure representing PLDM get state sensor readings response.
+ */
+struct pldm_get_state_sensor_readings_resp {
+ uint8_t completion_code;
+ uint8_t comp_sensor_count;
+ get_sensor_state_field field[1];
+} __attribute__((packed));
+
+/** @struct pldm_sensor_event
+ *
+ * structure representing sensorEventClass
+ */
+struct pldm_sensor_event_data {
+ uint16_t sensor_id;
+ uint8_t sensor_event_class_type;
+ uint8_t event_class[1];
+} __attribute__((packed));
+
+/** @struct pldm_state_sensor_state
+ *
+ * structure representing sensorEventClass for stateSensorState
+ */
+struct pldm_sensor_event_state_sensor_state {
+ uint8_t sensor_offset;
+ uint8_t event_state;
+ uint8_t previous_event_state;
+} __attribute__((packed));
+
+/** @struct pldm_sensor_event_numeric_sensor_state
+ *
+ * structure representing sensorEventClass for stateSensorState
+ */
+struct pldm_sensor_event_numeric_sensor_state {
+ uint8_t event_state;
+ uint8_t previous_event_state;
+ uint8_t sensor_data_size;
+ uint8_t present_reading[1];
+} __attribute__((packed));
+
+/** @struct pldm_sensor_event_sensor_op_state
+ *
+ * structure representing sensorEventClass for SensorOpState
+ */
+struct pldm_sensor_event_sensor_op_state {
+ uint8_t present_op_state;
+ uint8_t previous_op_state;
+} __attribute__((packed));
+
+/** @struct pldm_platform_event_message_req
+ *
+ * structure representing PlatformEventMessage command request data
+ */
+struct pldm_platform_event_message_req {
+ uint8_t format_version;
+ uint8_t tid;
+ uint8_t event_class;
+ uint8_t event_data[1];
+} __attribute__((packed));
+
+/** @struct pldm_platform_event_message_response
+ *
+ * structure representing PlatformEventMessage command response data
+ */
+struct pldm_platform_event_message_resp {
+ uint8_t completion_code;
+ uint8_t platform_event_status;
+} __attribute__((packed));
+
+/** @struct pldm_pdr_repository_chg_event_data
+ *
+ * structure representing pldmPDRRepositoryChgEvent class eventData
+ */
+struct pldm_pdr_repository_chg_event_data {
+ uint8_t event_data_format;
+ uint8_t number_of_change_records;
+ uint8_t change_records[1];
+} __attribute__((packed));
+
+/** @struct pldm_pdr_repository_chg_event_change_record_data
+ *
+ * structure representing pldmPDRRepositoryChgEvent class eventData's change
+ * record data
+ */
+struct pldm_pdr_repository_change_record_data {
+ uint8_t event_data_operation;
+ uint8_t number_of_change_entries;
+ uint32_t change_entry[1];
+} __attribute__((packed));
+
+/** @struct pldm_get_numeric_effecter_value_req
+ *
+ * structure representing GetNumericEffecterValue request packet
+ */
+struct pldm_get_numeric_effecter_value_req {
+ uint16_t effecter_id;
+} __attribute__((packed));
+
+/** @struct pldm_get_numeric_effecter_value_resp
+ *
+ * structure representing GetNumericEffecterValue response packet
+ */
+struct pldm_get_numeric_effecter_value_resp {
+ uint8_t completion_code;
+ uint8_t effecter_data_size;
+ uint8_t effecter_oper_state;
+ uint8_t pending_and_present_values[1];
+} __attribute__((packed));
+
+/** @struct pldm_get_sensor_reading_req
+ *
+ * Structure representing PLDM get sensor reading request
+ */
+struct pldm_get_sensor_reading_req {
+ uint16_t sensor_id;
+ bool8_t rearm_event_state;
+} __attribute__((packed));
+
+/** @struct pldm_get_sensor_reading_resp
+ *
+ * Structure representing PLDM get sensor reading response
+ */
+struct pldm_get_sensor_reading_resp {
+ 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[1];
+} __attribute__((packed));
+
+/* Responder */
+
+/* SetNumericEffecterValue */
+
+/** @brief Decode SetNumericEffecterValue request data
+ *
+ * @param[in] msg - Request message
+ * @param[in] payload_length - Length of request message payload
+ * @param[out] effecter_id - used to identify and access the effecter
+ * @param[out] effecter_data_size - The bit width and format of the setting
+ * value for the effecter.
+ * value:{uint8,sint8,uint16,sint16,uint32,sint32}
+ * @param[out] effecter_value - The setting value of numeric effecter being
+ * requested.
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Create a PLDM response message for SetNumericEffecterValue
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - PLDM completion code
+ * @param[out] msg - Message will be written to this
+ * @param[in] payload_length - Length of request message payload
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.body.payload'
+ */
+int encode_set_numeric_effecter_value_resp(uint8_t instance_id,
+ uint8_t completion_code,
+ struct pldm_msg *msg,
+ size_t payload_length);
+
+/* SetStateEffecterStates */
+
+/** @brief Create a PLDM response message for SetStateEffecterStates
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - PLDM completion code
+ * @param[out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.body.payload'
+ */
+
+int encode_set_state_effecter_states_resp(uint8_t instance_id,
+ uint8_t completion_code,
+ struct pldm_msg *msg);
+
+/** @brief Decode SetStateEffecterStates request data
+ *
+ * @param[in] msg - Request message
+ * @param[in] payload_length - Length of request message payload
+ * @param[out] effecter_id - used to identify and access the effecter
+ * @param[out] comp_effecter_count - number of individual sets of effecter
+ * information. Upto eight sets of state effecter info can be accessed
+ * for a given effecter.
+ * @param[out] field - each unit is an instance of the stateFileld structure
+ * that is used to set the requested state for a particular effecter
+ * within the state effecter. This field holds the starting address of
+ * the stateField values. The user is responsible to allocate the
+ * memory prior to calling this command. Since the state field count is
+ * not known in advance, the user should allocate the maximum size
+ * always, which is 8 in number.
+ * @return pldm_completion_codes
+ */
+
+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);
+
+/* GetPDR */
+
+/** @brief Create a PLDM response message for GetPDR
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - PLDM completion code
+ * @param[in] next_record_hndl - The recordHandle for the PDR that is next in
+ * the PDR Repository
+ * @param[in] next_data_transfer_hndl - A handle that identifies the next
+ * portion of the PDR data to be transferred, if any
+ * @param[in] transfer_flag - Indicates the portion of PDR data being
+ * transferred
+ * @param[in] resp_cnt - The number of recordData bytes returned in this
+ * response
+ * @param[in] record_data - PDR data bytes of length resp_cnt
+ * @param[in] transfer_crc - A CRC-8 for the overall PDR. This is present only
+ * in the last part of a PDR being transferred
+ * @param[out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+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);
+
+/** @brief Decode GetPDR request data
+ *
+ * @param[in] msg - Request message
+ * @param[in] payload_length - Length of request message payload
+ * @param[out] record_hndl - The recordHandle value for the PDR to be retrieved
+ * @param[out] data_transfer_hndl - Handle used to identify a particular
+ * multipart PDR data transfer operation
+ * @param[out] transfer_op_flag - Flag to indicate the first or subsequent
+ * portion of transfer
+ * @param[out] request_cnt - The maximum number of record bytes requested
+ * @param[out] record_chg_num - Used to determine whether the PDR has changed
+ * while PDR transfer is going on
+ * @return pldm_completion_codes
+ */
+
+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);
+
+/* GetStateSensorReadings */
+
+/** @brief Decode GetStateSensorReadings request data
+ *
+ * @param[in] msg - Request message
+ * @param[in] payload_length - Length of request message payload
+ * @param[out] sensor_id - used to identify and access the simple or composite
+ * sensor
+ * @param[out] sensor_rearm - Each bit location in this field corresponds to a
+ * particular sensor within the state sensor, where bit [0] corresponds
+ * to the first state sensor (sensor offset 0) and bit [7] corresponds
+ * to the eighth sensor (sensor offset 7), sequentially.
+ * @param[out] reserved - value: 0x00
+ * @return pldm_completion_codes
+ */
+
+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);
+
+/** @brief Encode GetStateSensorReadings response data
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - PLDM completion code
+ * @param[out] comp_sensor_count - The number of individual sets of sensor
+ * information that this command accesses
+ * @param[out] field - Each stateField is an instance of a stateField structure
+ * that is used to return the present operational state setting and the
+ * present state and event state for a particular set of sensor
+ * information contained within the state sensor
+ * @param[out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ */
+
+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);
+
+/* GetNumericEffecterValue */
+
+/** @brief Decode GetNumericEffecterValue request data
+ *
+ * @param[in] msg - Request message
+ * @param[in] payload_length - Length of request message payload
+ * @param[out] effecter_id - used to identify and access the effecter
+ * @return pldm_completion_codes
+ */
+int decode_get_numeric_effecter_value_req(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint16_t *effecter_id);
+
+/** @brief Create a PLDM response message for GetNumericEffecterValue
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - PLDM completion code
+ * @param[in] effecter_data_size - The bit width and format of the setting
+ * value for the effecter.
+ * value:{uint8,sint8,uint16,sint16,uint32,sint32}
+ * @param[in] effecter_oper_state - The state of the effecter itself
+ * @param[in] pending_value - The pending numeric value setting of the
+ * effecter. The effecterDataSize field indicates the number of
+ * bits used for this field
+ * @param[in] present_value - The present numeric value setting of the
+ * effecter. The effecterDataSize indicates the number of bits
+ * used for this field
+ * @param[out] msg - Message will be written to this
+ * @param[in] payload_length - Length of request message payload
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+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, uint8_t *pending_value, uint8_t *present_value,
+ struct pldm_msg *msg, size_t payload_length);
+
+/* GetSensorReading */
+
+/** @brief Decode GetSensorReading request data
+ *
+ * @param[in] msg - Request message
+ * @param[in] payload_length - Length of request message payload
+ * @param[out] sensor_id - A handle that is used to identify and access
+ * the sensor
+ * @param[out] rearm_event_state - true = manually re-arm EventState after
+ * responding to this request, false = no manual re-arm
+ * @return pldm_completion_codes
+ */
+
+int decode_get_sensor_reading_req(const struct pldm_msg *msg,
+ size_t payload_length, uint16_t *sensor_id,
+ bool8_t *rearm_event_state);
+
+/** @brief Encode GetSensorReading response data
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - PLDM completion code
+ * @param[out] sensor_data_size - The bit width and format of reading and
+ * threshold values
+ * @param[out] sensor_operational_state - The state of the sensor itself
+ * @param[out] sensor_event_message_enable - value: { noEventGeneration,
+ * eventsDisabled, eventsEnabled, opEventsOnlyEnabled,
+ * stateEventsOnlyEnabled }
+ * @param[out] present_state - The most recently assessed state value monitored
+ * by the sensor
+ * @param[out] previous_state - The state that the presentState was entered
+ * from
+ * @param[out] event_state - Indicates which threshold crossing assertion
+ * events have been detected
+ * @param[out] present_reading - The present value indicated by the sensor
+ * @param[out] msg - Message will be written to this
+ * @param[in] payload_length - Length of request message payload
+ * @return pldm_completion_codes
+ */
+
+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,
+ uint8_t *present_reading, struct pldm_msg *msg, size_t payload_length);
+
+/* Requester */
+
+/*GetPDRRepositoryInfo*/
+
+/** @brief Encode GetPDRRepositoryInfo response data
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - PLDM completion code
+ * @param[in] repository_state - PLDM repository state
+ * @param[in] update_time - When the standard PDR repository data was
+ * originally created
+ * @param[in] oem_update_time - when OEM PDRs in the PDR Repository were
+ * originally created
+ * @param[in] record_count - Total number of PDRs in this repository
+ * @param[in] repository_size - Size of the PDR Repository in bytes
+ * @param[in] largest_record_size - Size of the largest record in the PDR
+ * Repository in bytes
+ * @param[in] data_transfer_handle_timeout - Data transmission timeout
+ * @param[out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ */
+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);
+
+/* GetPDR */
+
+/** @brief Create a PLDM request message for GetPDR
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] record_hndl - The recordHandle value for the PDR to be retrieved
+ * @param[in] data_transfer_hndl - Handle used to identify a particular
+ * multipart PDR data transfer operation
+ * @param[in] transfer_op_flag - Flag to indicate the first or subsequent
+ * portion of transfer
+ * @param[in] request_cnt - The maximum number of record bytes requested
+ * @param[in] record_chg_num - Used to determine whether the PDR has changed
+ * while PDR transfer is going on
+ * @param[out] msg - Message will be written to this
+ * @param[in] payload_length - Length of request message payload
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+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);
+
+/** @brief Decode GetPDR response data
+ *
+ * Note:
+ * * If the return value is not PLDM_SUCCESS, it represents a
+ * transport layer error.
+ * * If the completion_code value is not PLDM_SUCCESS, it represents a
+ * protocol layer error and all the out-parameters are invalid.
+ *
+ * @param[in] msg - Request message
+ * @param[in] payload_length - Length of request message payload
+ * @param[out] completion_code - PLDM completion code
+ * @param[out] next_record_hndl - The recordHandle for the PDR that is next in
+ * the PDR Repository
+ * @param[out] next_data_transfer_hndl - A handle that identifies the next
+ * portion of the PDR data to be transferred, if any
+ * @param[out] transfer_flag - Indicates the portion of PDR data being
+ * transferred
+ * @param[out] resp_cnt - The number of recordData bytes returned in this
+ * response
+ * @param[out] record_data - PDR data bytes of length resp_cnt, or NULL to
+ * skip the copy and place the actual length in resp_cnt.
+ * @param[in] record_data_length - Length of record_data
+ * @param[out] transfer_crc - A CRC-8 for the overall PDR. This is present only
+ * in the last part of a PDR being transferred
+ * @return pldm_completion_codes
+ */
+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);
+
+/* SetStateEffecterStates */
+
+/** @brief Create a PLDM request message for SetStateEffecterStates
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] effecter_id - used to identify and access the effecter
+ * @param[in] comp_effecter_count - number of individual sets of effecter
+ * information. Upto eight sets of state effecter info can be accessed
+ * for a given effecter.
+ * @param[in] field - each unit is an instance of the stateField structure
+ * that is used to set the requested state for a particular effecter
+ * within the state effecter. This field holds the starting address of
+ * the stateField values. The user is responsible to allocate the
+ * memory prior to calling this command. The user has to allocate the
+ * field parameter as sizeof(set_effecter_state_field) *
+ * comp_effecter_count
+ * @param[out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+
+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);
+
+/** @brief Decode SetStateEffecterStates response data
+ *
+ * Note:
+ * * If the return value is not PLDM_SUCCESS, it represents a
+ * transport layer error.
+ * * If the completion_code value is not PLDM_SUCCESS, it represents a
+ * protocol layer error and all the out-parameters are invalid.
+ *
+ * @param[in] msg - Request message
+ * @param[in] payload_length - Length of response message payload
+ * @param[out] completion_code - PLDM completion code
+ * @return pldm_completion_codes
+ */
+int decode_set_state_effecter_states_resp(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint8_t *completion_code);
+
+/* SetNumericEffecterValue */
+
+/** @brief Create a PLDM request message for SetNumericEffecterValue
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] effecter_id - used to identify and access the effecter
+ * @param[in] effecter_data_size - The bit width and format of the setting
+ * value for the effecter.
+ * value:{uint8,sint8,uint16,sint16,uint32,sint32}
+ * @param[in] effecter_value - The setting value of numeric effecter being
+ * requested.
+ * @param[in] payload_length - Length of request message payload
+ * @param[out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+int encode_set_numeric_effecter_value_req(
+ uint8_t instance_id, uint16_t effecter_id, uint8_t effecter_data_size,
+ uint8_t *effecter_value, struct pldm_msg *msg, size_t payload_length);
+
+/** @brief Decode SetNumericEffecterValue response data
+ * @param[in] msg - Request message
+ * @param[in] payload_length - Length of response message payload
+ * @param[out] completion_code - PLDM completion code
+ * @return pldm_completion_codes
+ */
+int decode_set_numeric_effecter_value_resp(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint8_t *completion_code);
+
+/** @brief Create a PLDM request message for GetStateSensorReadings
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] sensor_id - used to identify and access the simple or composite
+ * sensor
+ * @param[in] sensorRearm - Each bit location in this field corresponds to a
+ * particular sensor within the state sensor, where bit [0] corresponds
+ * to the first state sensor (sensor offset 0) and bit [7] corresponds
+ * to the eighth sensor (sensor offset 7), sequentially
+ * @param[in] reserved - value: 0x00
+ * @param[out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+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);
+
+/** @brief Decode GetStateSensorReadings response data
+ *
+ * @param[in] msg - Request message
+ * @param[in] payload_length - Length of response message payload
+ * @param[out] completion_code - PLDM completion code
+ * @param[in,out] comp_sensor_count - The number of individual sets of sensor
+ * information that this command accesses
+ * @param[out] field - Each stateField is an instance of a stateField structure
+ * that is used to return the present operational state setting and the
+ * present state and event state for a particular set of sensor
+ * information contained within the state sensor
+ * @return pldm_completion_codes
+ */
+
+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);
+
+/* PlatformEventMessage */
+
+/** @brief Decode PlatformEventMessage request data
+ * @param[in] msg - Request message
+ * @param[in] payload_length - Length of response message payload
+ * @param[out] format_version - Version of the event format
+ * @param[out] tid - Terminus ID for the terminus that originated the event
+ * message
+ * @param[out] event_class - The class of event being sent
+ * @param[out] event_data_offset - Offset where the event data should be read
+ * from pldm msg
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Encode PlatformEventMessage response data
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - PLDM completion code
+ * @param[in] platform_event_status - Response status of the event message
+ * command
+ * @param[out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+int encode_platform_event_message_resp(uint8_t instance_id,
+ uint8_t completion_code,
+ uint8_t platform_event_status,
+ struct pldm_msg *msg);
+
+/** @brief Encode PlatformEventMessage request data
+ * @param[in] instance_id - Message's instance id
+ * @param[in] format_version - Version of the event format
+ * @param[in] tid - Terminus ID for the terminus that originated the event
+ * message
+ * @param[in] event_class - The class of event being sent
+ * @param[in] event_data - the event data should be read from pldm msg
+ * @param[in] event_data_length - Length of the event data
+ * @param[out] msg - Request message
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+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);
+
+/** @brief Decode PlatformEventMessage response data
+ * @param[in] msg - Request message
+ * @param[in] payload_length - Length of Response message payload
+ * @param[out] completion_code - PLDM completion code
+ * @param[out] platform_event_status - Response status of the event message
+ * command
+ * @return pldm_completion_codes
+ */
+int decode_platform_event_message_resp(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint8_t *completion_code,
+ uint8_t *platform_event_status);
+
+/** @brief Decode sensorEventData response data
+ *
+ * @param[in] event_data - event data from the response message
+ * @param[in] event_data_length - length of the event data
+ * @param[out] sensor_id - sensorID value of the sensor
+ * @param[out] sensor_event_class_type - Type of sensor event class
+ * @param[out] event_class_data_offset - Offset where the event class data
+ * should be read from event data
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'event_data'
+ */
+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);
+
+/** @brief Decode sensorOpState response data
+ *
+ * @param[in] sensor_data - sensor_data for sensorEventClass = sensorOpState
+ * @param[in] sensor_data_length - Length of sensor_data
+ * @param[out] present_op_state - The sensorOperationalState value from the
+ * state change that triggered the event message
+ * @param[out] previous_op_state - The sensorOperationalState value for the
+ * state from which the present state was entered
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'sensor_data'
+ */
+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);
+
+/** @brief Decode stateSensorState response data
+ *
+ * @param[in] sensor_data - sensor_data for sensorEventClass = stateSensorState
+ * @param[in] sensor_data_length - Length of sensor_data
+ * @param[out] sensor_offset - Identifies which state sensor within a composite
+ * state sensor the event is being returned for
+ * @param[out] event_state - The event state value from the state change that
+ * triggered the event message
+ * @param[out] previous_event_state - The event state value for the state from
+ * which the present event state was entered
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'sensor_data'
+ */
+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);
+
+/** @brief Decode numericSensorState response data
+ *
+ * @param[in] sensor_data - sensor_data for sensorEventClass =
+ * numericSensorState
+ * @param[in] sensor_data_length - Length of sensor_data
+ * @param[out] event_state - The eventState value from the state change that
+ * triggered the event message
+ * @param[out] previous_event_state - The eventState value for the state from
+ * which the present state was entered
+ * @param[out] sensor_data_size - The bit width and format of reading and
+ * threshold values that the sensor returns
+ * @param[out] present_reading - The present value indicated by the sensor
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'sensor_data'
+ */
+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);
+
+/* GetNumericEffecterValue */
+
+/** @brief Create a PLDM request message for GetNumericEffecterValue
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] effecter_id - used to identify and access the effecter
+ * @param[out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+int encode_get_numeric_effecter_value_req(uint8_t instance_id,
+ uint16_t effecter_id,
+ struct pldm_msg *msg);
+
+/** @brief Create a PLDM response message for GetNumericEffecterValue
+ *
+ * @param[in] msg - Request message
+ * @param[in] payload_length - Length of request message payload
+ * @param[out] completion_code - PLDM completion code
+ * @param[out] effecter_data_size - The bit width and format of the setting
+ * value for the effecter.
+ * value:{uint8,sint8,uint16,sint16,uint32,sint32}
+ * @param[out] effecter_oper_state - The state of the effecter itself
+ * @param[out] pending_value - The pending numeric value setting of the
+ * effecter. The effecterDataSize field indicates the number of
+ * bits used for this field
+ * @param[out] present_value - The present numeric value setting of the
+ * effecter. The effecterDataSize indicates the number of bits
+ * used for this field
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Decode pldmPDRRepositoryChgEvent response data
+ *
+ * @param[in] event_data - eventData for pldmPDRRepositoryChgEvent
+ * @param[in] event_data_size - Length of event_data
+ * @param[out] event_data_format - This field indicates if the changedRecords
+ * are of PDR Types or PDR Record Handles
+ * @param[out] number_of_change_records - The number of changeRecords following
+ * this field
+ * @param[out] change_record_data_offset - Identifies where changeRecord data
+ * is located within event_data
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'event_data'
+ */
+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);
+
+/** @brief Encode PLDM PDR Repository Change eventData
+ * @param[in] event_data_format - Format of this event data (e.g.
+ * FORMAT_IS_PDR_HANDLES)
+ * @param[in] number_of_change_records - Number of changeRecords in this
+ * eventData
+ * @param[in] event_data_operations - Array of eventDataOperations
+ * (e.g. RECORDS_ADDED) for each changeRecord in this eventData. This array
+ * should contain number_of_change_records elements.
+ * @param[in] numbers_of_change_entries - Array of numbers of changeEntrys
+ * for each changeRecord in this eventData. This array should contain
+ * number_of_change_records elements.
+ * @param[in] change_entries - 2-dimensional array of arrays of changeEntrys,
+ * one array per changeRecord in this eventData. The toplevel array should
+ * contain number_of_change_records elements. Each subarray [i] should
+ * contain numbers_of_change_entries[i] elements.
+ * @param[in] event_data - The eventData will be encoded into this. This entire
+ * structure must be max_change_records_size long. It must be large enough
+ * to accomodate the data to be encoded. The caller is responsible for
+ * allocating and deallocating it, including the variable-size
+ * 'event_data.change_records' field. If this parameter is NULL,
+ * PLDM_SUCCESS will be returned and actual_change_records_size will be set
+ * to reflect the required size of the structure.
+ * @param[out] actual_change_records_size - The actual number of meaningful
+ * encoded bytes in event_data. The caller can over-allocate memory and use
+ * this output to determine the real size of the structure.
+ * @param[in] max_change_records_size - The size of event_data in bytes. If the
+ * encoded message would be larger than this value, an error is returned.
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'event_data.change_records'
+ */
+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);
+
+/** @brief Encode event data for a PLDM Sensor Event
+ *
+ * @param[out] event_data The object to store the encoded event in
+ * @param[in] event_data_size Size of the allocation for event_data
+ * @param[in] sensor_id Sensor ID
+ * @param[in] sensor_event_class Sensor event class
+ * @param[in] sensor_offset Offset
+ * @param[in] event_state Event state
+ * @param[in] previous_event_state Previous event state
+ * @param[out] actual_event_data_size The real size in bytes of the event_data
+ * @return int pldm_completion_codes PLDM_SUCCESS/PLDM_ERROR_INVALID_LENGTH
+ * @note If event_data is NULL, then *actual_event_data_size will be set to
+ * reflect the size of the event data, and PLDM_SUCCESS will be returned.
+ * @note The caller is responsible for allocating and deallocating the
+ * event_data
+ */
+int encode_sensor_event_data(struct pldm_sensor_event_data *event_data,
+ size_t event_data_size, uint16_t sensor_id,
+ enum sensor_event_class_states sensor_event_class,
+ uint8_t sensor_offset, uint8_t event_state,
+ uint8_t previous_event_state,
+ size_t *actual_event_data_size);
+
+/** @brief Decode PldmPDRRepositoryChangeRecord response data
+ *
+ * @param[in] change_record_data - changeRecordData for
+ * pldmPDRRepositoryChgEvent
+ * @param[in] change_record_data_size - Length of change_record_data
+ * @param[out] event_data_operation - This field indicates the changeEntries
+ * operation types
+ * @param[out] number_of_change_entries - The number of changeEntries following
+ * this field
+ * @param[out] change_entry_data_offset - Identifies where changeEntries data
+ * is located within change_record_data
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'change_record_data'
+ */
+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);
+
+/* GetSensorReading */
+
+/** @brief Encode GetSensorReading request data
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] sensor_id - A handle that is used to identify and access the
+ * sensor
+ * @param[in] rearm_event_state - true = manually re-arm EventState after
+ * responding to this request, false = no manual re-arm
+ * @param[out] msg - Message will be written to this
+ * @return pldm_completion_codes
+ * @note Caller is responsible for memory alloc and dealloc of param
+ * 'msg.payload'
+ */
+int encode_get_sensor_reading_req(uint8_t instance_id, uint16_t sensor_id,
+ bool8_t rearm_event_state,
+ struct pldm_msg *msg);
+
+/** @brief Decode GetSensorReading response data
+ *
+ * @param[in] msg - Request message
+ * @param[in] payload_length - Length of response message payload
+ * @param[out] completion_code - PLDM completion code
+ * @param[out] sensor_data_size - The bit width and format of reading and
+ * threshold values
+ * @param[out] sensor_operational_state - The state of the sensor itself
+ * @param[out] sensor_event_message_enable - value: { noEventGeneration,
+ * eventsDisabled, eventsEnabled, opEventsOnlyEnabled,
+ * stateEventsOnlyEnabled }
+ * @param[out] present_state - The most recently assessed state value monitored
+ * by the sensor
+ * @param[out] previous_state - The state that the presentState was entered
+ * from
+ * @param[out] event_state - Indicates which threshold crossing assertion
+ * events have been detected
+ * @param[out] present_reading - The present value indicated by the sensor
+ * @return pldm_completion_codes
+ */
+
+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);
+
+/** @brief Encode the SetEventReceiver request message
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] event_message_global_enable - This value is used to enable or
+ * disable event message generation from the terminus value: {
+ * disable, enableAsync, enablePolling, enableAsyncKeepAlive }
+ * @param[in] transport_protocol_type - This value is provided in the request
+ * to help the responder verify that the content of the
+ * eventReceiverAddressInfo field used in this request is correct for
+ * the messaging protocol supported by the terminus.
+ * @param[in] event_receiver_address_info - this value is a medium and
+ * protocol-specific address that the responder should use when
+ * transmitting event messages using the indicated protocol
+ * @param[in] heartbeat_timer - Amount of time in seconds after each elapsing
+ * of which the terminus shall emit a heartbeat event to the receiver
+ * @param[out] msg - Argument to capture the Message
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Decode the SetEventReceiver response message
+ *
+ * @param[in] msg - Request message
+ * @param[in] payload_length - Length of response message payload
+ * @param[out] completion_code - PLDM completion code
+ * @return pldm_completion_codes
+ */
+int decode_set_event_receiver_resp(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint8_t *completion_code);
+
+/** @brief Decode the SetEventReceiver request message
+ *
+ * @param[in] msg - Request message
+ * @param[in] payload_length - Length of request message payload
+ * @param[out] event_message_global_enable - This value is used to enable or
+ * disable event message generation from the terminus value: {
+ * disable, enableAsync, enablePolling, enableAsyncKeepAlive }
+ * @param[out] transport_protocol_type - This value is provided in the request
+ * to help the responder verify that the content of the
+ * eventReceiverAddressInfo field used in this request is correct for
+ * the messaging protocol supported by the terminus.
+ * @param[out] event_receiver_address_info - This value is a medium and
+ * protocol-specific address that the responder should use when
+ * transmitting event messages using the indicated protocol
+ * @param[out] heartbeat_timer - Amount of time in seconds after each elapsing
+ * of which the terminus shall emit a heartbeat event to the receiver
+ * @return pldm_completion_codes
+ */
+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);
+
+/** @brief Encode the SetEventReceiver response message
+ *
+ * @param[in] instance_id - Message's instance id
+ * @param[in] completion_code - PLDM completion code
+ * @param[out] msg - Argument to capture the Message
+ * @return pldm_completion_codes
+ */
+int encode_set_event_receiver_resp(uint8_t instance_id, uint8_t completion_code,
+ struct pldm_msg *msg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PLATFORM_H */
diff --git a/pldm/libpldm/pldm_types.h b/pldm/libpldm/pldm_types.h
new file mode 100644
index 00000000..3c5f0864
--- /dev/null
+++ b/pldm/libpldm/pldm_types.h
@@ -0,0 +1,165 @@
+#ifndef PLDM_TYPES_H
+#define PLDM_TYPES_H
+
+#include <stdint.h>
+
+typedef union {
+ uint8_t byte;
+ struct {
+ uint8_t bit0 : 1;
+ uint8_t bit1 : 1;
+ uint8_t bit2 : 1;
+ uint8_t bit3 : 1;
+ uint8_t bit4 : 1;
+ uint8_t bit5 : 1;
+ uint8_t bit6 : 1;
+ uint8_t bit7 : 1;
+ } __attribute__((packed)) bits;
+} bitfield8_t;
+
+/** @struct pldm_version
+ *
+ *
+ */
+typedef struct pldm_version {
+ uint8_t major;
+ uint8_t minor;
+ uint8_t update;
+ uint8_t alpha;
+} __attribute__((packed)) ver32_t;
+
+typedef uint8_t bool8_t;
+
+typedef union {
+ uint16_t value;
+ struct {
+ uint8_t bit0 : 1;
+ uint8_t bit1 : 1;
+ uint8_t bit2 : 1;
+ uint8_t bit3 : 1;
+ uint8_t bit4 : 1;
+ uint8_t bit5 : 1;
+ uint8_t bit6 : 1;
+ uint8_t bit7 : 1;
+ uint8_t bit8 : 1;
+ uint8_t bit9 : 1;
+ uint8_t bit10 : 1;
+ uint8_t bit11 : 1;
+ uint8_t bit12 : 1;
+ uint8_t bit13 : 1;
+ uint8_t bit14 : 1;
+ uint8_t bit15 : 1;
+ } __attribute__((packed)) bits;
+} bitfield16_t;
+
+typedef union {
+ uint32_t value;
+ struct {
+ uint8_t bit0 : 1;
+ uint8_t bit1 : 1;
+ uint8_t bit2 : 1;
+ uint8_t bit3 : 1;
+ uint8_t bit4 : 1;
+ uint8_t bit5 : 1;
+ uint8_t bit6 : 1;
+ uint8_t bit7 : 1;
+ uint8_t bit8 : 1;
+ uint8_t bit9 : 1;
+ uint8_t bit10 : 1;
+ uint8_t bit11 : 1;
+ uint8_t bit12 : 1;
+ uint8_t bit13 : 1;
+ uint8_t bit14 : 1;
+ uint8_t bit15 : 1;
+ uint8_t bit16 : 1;
+ uint8_t bit17 : 1;
+ uint8_t bit18 : 1;
+ uint8_t bit19 : 1;
+ uint8_t bit20 : 1;
+ uint8_t bit21 : 1;
+ uint8_t bit22 : 1;
+ uint8_t bit23 : 1;
+ uint8_t bit24 : 1;
+ uint8_t bit25 : 1;
+ uint8_t bit26 : 1;
+ uint8_t bit27 : 1;
+ uint8_t bit28 : 1;
+ uint8_t bit29 : 1;
+ uint8_t bit30 : 1;
+ uint8_t bit31 : 1;
+ } __attribute__((packed)) bits;
+} bitfield32_t;
+
+typedef union {
+ uint64_t value;
+ struct {
+ uint8_t bit0 : 1;
+ uint8_t bit1 : 1;
+ uint8_t bit2 : 1;
+ uint8_t bit3 : 1;
+ uint8_t bit4 : 1;
+ uint8_t bit5 : 1;
+ uint8_t bit6 : 1;
+ uint8_t bit7 : 1;
+ uint8_t bit8 : 1;
+ uint8_t bit9 : 1;
+ uint8_t bit10 : 1;
+ uint8_t bit11 : 1;
+ uint8_t bit12 : 1;
+ uint8_t bit13 : 1;
+ uint8_t bit14 : 1;
+ uint8_t bit15 : 1;
+ uint8_t bit16 : 1;
+ uint8_t bit17 : 1;
+ uint8_t bit18 : 1;
+ uint8_t bit19 : 1;
+ uint8_t bit20 : 1;
+ uint8_t bit21 : 1;
+ uint8_t bit22 : 1;
+ uint8_t bit23 : 1;
+ uint8_t bit24 : 1;
+ uint8_t bit25 : 1;
+ uint8_t bit26 : 1;
+ uint8_t bit27 : 1;
+ uint8_t bit28 : 1;
+ uint8_t bit29 : 1;
+ uint8_t bit30 : 1;
+ uint8_t bit31 : 1;
+ uint8_t bit32 : 1;
+ uint8_t bit33 : 1;
+ uint8_t bit34 : 1;
+ uint8_t bit35 : 1;
+ uint8_t bit36 : 1;
+ uint8_t bit37 : 1;
+ uint8_t bit38 : 1;
+ uint8_t bit39 : 1;
+ uint8_t bit40 : 1;
+ uint8_t bit41 : 1;
+ uint8_t bit42 : 1;
+ uint8_t bit43 : 1;
+ uint8_t bit44 : 1;
+ uint8_t bit45 : 1;
+ uint8_t bit46 : 1;
+ uint8_t bit47 : 1;
+ uint8_t bit48 : 1;
+ uint8_t bit49 : 1;
+ uint8_t bit50 : 1;
+ uint8_t bit51 : 1;
+ uint8_t bit52 : 1;
+ uint8_t bit53 : 1;
+ uint8_t bit54 : 1;
+ uint8_t bit55 : 1;
+ uint8_t bit56 : 1;
+ uint8_t bit57 : 1;
+ uint8_t bit58 : 1;
+ uint8_t bit59 : 1;
+ uint8_t bit60 : 1;
+ uint8_t bit61 : 1;
+ uint8_t bit62 : 1;
+ uint8_t bit63 : 1;
+ } __attribute__((packed)) bits;
+} bitfield64_t;
+
+typedef float real32_t;
+
+#endif /* PLDM_TYPES_H */
diff --git a/pldm/libpldm/state_set.h b/pldm/libpldm/state_set.h
new file mode 100644
index 00000000..23fd91c3
--- /dev/null
+++ b/pldm/libpldm/state_set.h
@@ -0,0 +1,236 @@
+#ifndef STATE_SET_H
+#define STATE_SET_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @brief PLDM State Set IDs in DSP0249_1.1.0 specification
+ */
+enum pldm_state_set_ids {
+
+ /* Table 1 - General State Sets */
+ PLDM_STATE_SET_HEALTH_STATE = 1,
+ PLDM_STATE_SET_AVAILABILITY = 2,
+ PLDM_STATE_SET_PREDICTIVE_CONDITION = 3,
+ PLDM_STATE_SET_REDUNDANCY_STATUS = 4,
+ PLDM_STATE_SET_HEALTH_REDUNDANCY_TREND = 5,
+ PLDM_STATE_SET_GROUP_RESOURCE_LEVEL = 6,
+ PLDM_STATE_SET_REDUNDANCY_ENTITY_ROLE = 7,
+ PLDM_STATE_SET_OPERATIONAL_STATUS = 8,
+ PLDM_STATE_SET_OPERATIONAL_STRESS_STATUS = 9,
+ PLDM_STATE_SET_OPERATIONAL_FAULT_STATUS = 10,
+ PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS = 11,
+ PLDM_STATE_SET_OPERATIONAL_CONNECTION_STATUS = 12,
+ PLDM_STATE_SET_PRESENCE = 13,
+ PLDM_STATE_SET_PERFORMANCE = 14,
+ PLDM_STATE_SET_CONFIGURATION_STATE = 15,
+ PLDM_STATE_SET_CHANGED_CONFIGURATION = 16,
+ PLDM_STATE_SET_IDENTIFY_STATE = 17,
+ PLDM_STATE_SET_VERSION = 18,
+ PLDM_STATE_SET_ALARM_STATE = 19,
+ PLDM_STATE_SET_DEVICE_INITIALIZATION = 20,
+ PLDM_STATE_SET_THERMAL_TRIP = 21,
+
+ /* Table 2 - Communication State Sets */
+ PLDM_STATE_SET_HEARTBEAT = 32,
+ PLDM_STATE_SET_LINK_STATE = 33,
+
+ /* Table 3 - General Sensor State Sets */
+ PLDM_STATE_SET_SMOKE_STATE = 64,
+ PLDM_STATE_SET_HUMIDITY_STATE = 65,
+ PLDM_STATE_SET_DOOR_STATE = 66,
+ PLDM_STATE_SET_SWITCH_STATE = 67,
+
+ /* Table 4 - Security-Related State Sets */
+ PLDM_STATE_SET_LOCK_STATE = 96,
+ PLDM_STATE_SET_PHYSICAL_SECURITY = 97,
+ PLDM_STATE_SET_DOCK_AUTHORIZATION = 98,
+ PLDM_STATE_SET_HW_SECURITY = 99,
+ PLDM_STATE_SET_PHYSICAL_COMM_CONNECTION = 100,
+ PLDM_STATE_SET_COMM_LEASH_STATUS = 101,
+ PLDM_STATE_SET_FOREIGN_NW_DETECTION_STATUS = 102,
+ PLDM_STATE_SET_PASSWORD_PROTECTED_ACCESS_SECURITY = 103,
+ PLDM_STATE_SET_SECURITY_ACCESS_PRIVILEGE_LEVEL = 104,
+ PLDM_STATE_SET_SESSION_AUDIT = 105,
+
+ /* Table 5 - Software-Related State Sets */
+ PLDM_STATE_SET_SW_TERMINATION_STATUS = 129,
+
+ /* Table 6 - Redundant Storage Media (RAID) State Sets */
+ PLDM_STATE_SET_STORAGE_MEDIA_ACTIVITY = 160,
+
+ /* Table 7 - Boot-Related State Sets */
+ PLDM_STATE_SET_BOOT_RESTART_CAUSE = 192,
+ PLDM_STATE_SET_BOOT_RESTART_REQUEST = 193,
+ PLDM_STATE_SET_ENTITY_BOOT_STATUS = 194,
+ PLDM_STATE_SET_BOOT_ERROR_STATUS = 195,
+ PLDM_STATE_SET_BOOT_PROGRESS = 196,
+ PLDM_STATE_SET_SYS_FIRMWARE_HANG = 197,
+ PLDM_STATE_SET_POST_ERRORS = 198,
+
+ /* Table 8 - Monitored System-Related State Sets */
+ PLDM_STATE_SET_LOG_FILL_STATUS = 225,
+ PLDM_STATE_SET_LOG_FILTER_STATUS = 226,
+ PLDM_STATE_SET_LOG_TIMESTAMP_CHANGE = 227,
+ PLDM_STATE_SET_INTERRUPT_REQUESTED = 228,
+ PLDM_STATE_SET_INTERRUPT_RECEIVED = 229,
+ PLDM_STATE_SET_DIAGNOSTIC_INTERRUPT_REQUESTED = 230,
+ PLDM_STATE_SET_DIAGNOSTIC_INTERRUPT_RECEIVED = 231,
+ PLDM_STATE_SET_IO_CHANNEL_CHECK_NMI_REQUESTED = 232,
+ PLDM_STATE_SET_IO_CHANNEL_CHECK_NMI_RECEIVED = 233,
+ PLDM_STATE_SET_FATAL_NMI_REQUESTED = 234,
+ PLDM_STATE_SET_FATAL_NMI_RECEIVED = 235,
+ PLDM_STATE_SET_SOFTWARE_NMI_REQUESTED = 236,
+ PLDM_STATE_SET_SOFTWARE_NMI_RECEIVED = 237,
+ PLDM_STATE_SET_SMI_REQUESTED = 238,
+ PLDM_STATE_SET_SMI_RECEIVED = 238,
+ PLDM_STATE_SET_PCI_PERR_REQUESTED = 239,
+ PLDM_STATE_SET_PCI_PERR_RECEIVED = 240,
+ PLDM_STATE_SET_PCI_SERR_REQUESTED = 241,
+ PLDM_STATE_SET_PCI_SERR_RECEIVED = 242,
+ PLDM_STATE_SET_BUS_ERROR_STATUS = 243,
+ PLDM_STATE_SET_WATCHDOG_STATUS = 244,
+
+ /* Table 9 - Power-Related State Sets */
+ PLDM_STATE_SET_POWER_SUPPLY_STATE = 256,
+ PLDM_STATE_SET_DEVICE_POWER_STATE = 257,
+ PLDM_STATE_SET_ACPI_POWER_STATE = 258,
+ PLDM_STATE_SET_BACKUP_POWER_SOURCE = 259,
+ PLDM_STATE_SET_SYSTEM_POWER_STATE = 260,
+ PLDM_STATE_SET_BATTERY_ACTIVITY = 261,
+ PLDM_STATE_SET_BATTERY_STATE = 262,
+
+ /* Table 10 - Processor-Related State Sets */
+ PLDM_STATE_SET_PROC_POWER_STATE = 288,
+ PLDM_STATE_SET_POWER_PERFORMANCE_STATE = 289,
+ PLDM_STATE_SET_PROC_ERROR_STATUS = 290,
+ PLDM_STATE_SET_BIST_FAILURE_STATUS = 291,
+ PLDM_STATE_SET_IBIST_FAILURE_STATUS = 292,
+ PLDM_STATE_SET_PROC_HANG_IN_POST = 293,
+ PLDM_STATE_SET_PROC_STARTUP_FAILURE = 294,
+ PLDM_STATE_SET_UNCORRECTABLE_CPU_ERROR = 295,
+ PLDM_STATE_SET_MACHINE_CHECK_ERROR = 296,
+ PLDM_STATE_SET_CORRECTED_MACHINE_CHECK = 297,
+
+ /* Table 11 - Memory-Related State Sets */
+ PLDM_STATE_SET_CACHE_STATUS = 320,
+ PLDM_STATE_SET_MEMORY_ERROR_STATUS = 321,
+ PLDM_STATE_SET_REDUNDANT_MEMORY_ACTIVITY_STATUS = 322,
+
+ /* Table 12 - Storage Device State Sets */
+ PLDM_STATE_SET_ERROR_DETECTION_STATUS = 330,
+ PLDM_STATE_SET_STUCK_BIT_STATUS = 331,
+ PLDM_STATE_SET_SCRUB_STATUS = 332,
+
+ /* Table 13 - Slot/Module State Sets */
+ PLDM_STATE_SET_SLOT_OCCUPANCY = 352,
+ PLDM_STATE_SET_SLOT_STATE = 353,
+};
+
+/* @brief List of states for the Health State state set (ID 1).
+ */
+enum pldm_state_set_health_state_values {
+ PLDM_STATE_SET_HEALTH_STATE_NORMAL = 1,
+ PLDM_STATE_SET_HEALTH_STATE_NON_CRITICAL = 2,
+ PLDM_STATE_SET_HEALTH_STATE_CRITICAL = 3,
+ PLDM_STATE_SET_HEALTH_STATE_FATAL = 4,
+ PLDM_STATE_SET_HEALTH_STATE_UPPER_NON_CRITICAL = 5,
+ PLDM_STATE_SET_HEALTH_STATE_LOWER_NON_CRITICAL = 6,
+ PLDM_STATE_SET_HEALTH_STATE_UPPER_CRITICAL = 7,
+ PLDM_STATE_SET_HEALTH_STATE_LOWER_CRITICAL = 8,
+ PLDM_STATE_SET_HEALTH_STATE_UPPER_FATAL = 9,
+ PLDM_STATE_SET_HEALTH_STATE_LOWER_FATAL = 10,
+};
+
+/* @brief List of states for the State Set Availability (ID 2),
+ */
+enum pldm_state_set_availability_values {
+ PLDM_STATE_SET_AVAILABILITY_REBOOTING = 8
+};
+
+/* @brief List of states for the Operational Fault status (ID 10).
+ */
+enum pldm_state_set_operational_fault_status_values {
+ PLDM_STATE_SET_OPERATIONAL_FAULT_STATUS_NORMAL = 1,
+ PLDM_STATE_SET_OPERATIONAL_FAULT_STATUS_STRESSED = 2,
+};
+
+/* @brief List of states for the Operational Running Status state set (ID 11).
+ */
+enum pldm_state_set_operational_running_status_values {
+ PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STARTING = 1,
+ PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPING = 2,
+ PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_STOPPED = 3,
+ PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_IN_SERVICE = 4,
+ PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_ABORTED = 5,
+ PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_DORMANT = 6
+};
+
+/* @brief List of states for the Set Identify state (ID 17).
+ */
+enum pldm_state_set_identify_state_values {
+ PLDM_STATE_SET_IDENTIFY_STATE_UNASSERTED = 1,
+ PLDM_STATE_SET_IDENTIFY_STATE_ASSERTED = 2,
+};
+
+/* @brief List of states for the Set Thermal Trip state set (ID 21).
+ */
+enum pldm_state_set_thermal_trip_values {
+ PLDM_STATE_SET_THERMAL_TRIP_STATUS_NORMAL = 1,
+ PLDM_STATE_SET_THERMAL_TRIP_STATUS_THERMAL_TRIP = 2,
+};
+
+/* @brief List of states for the Software-related state set (ID 129).
+ */
+enum pldm_software_termination_status_values {
+ PLDM_SW_TERM_NORMAL = 1,
+ PLDM_SW_TERM_SOFTWARE_TERMINATION_DETECTED = 2,
+ PLDM_SW_TERM_CRITICAL_STOP_DURING_LOAD_INITIALIZATION = 3,
+ PLDM_SW_TERM_RUN_TIME_CRITICAL_STOP = 4,
+ PLDM_SW_TERM_GRACEFUL_SHUTDOWN_REQUESTED = 5,
+ PLDM_SW_TERM_GRACEFUL_RESTART_REQUESTED = 6,
+ PLDM_SW_TERM_GRACEFUL_SHUTDOWN = 7,
+ PLDM_SW_TERM_TERMINATION_REQUEST_FAILED = 8,
+};
+
+/* @brief List of states for the Boot Restart Cause state set (ID 192).
+ */
+enum pldm_state_set_boot_restart_cause_values {
+ PLDM_STATE_SET_BOOT_RESTART_CAUSE_POWERED_UP = 1,
+ PLDM_STATE_SET_BOOT_RESTART_CAUSE_HARD_RESET = 2,
+ PLDM_STATE_SET_BOOT_RESTART_CAUSE_WARM_RESET = 3,
+ PLDM_STATE_SET_BOOT_RESTART_CAUSE_MANUAL_HARD_RESET = 4,
+ PLDM_STATE_SET_BOOT_RESTART_CAUSE_MANUAL_WARM_RESET = 5,
+ PLDM_STATE_SET_BOOT_RESTART_CAUSE_SYSTEM_RESTART = 6,
+ PLDM_STATE_SET_BOOT_RESTART_CAUSE_WATCHDOG_TIMEOUT = 7
+};
+
+/* @brief List of states for the Boot Progress state set (ID 196).
+ */
+enum pldm_state_set_boot_progress_state_values {
+ PLDM_STATE_SET_BOOT_PROG_STATE_NOT_ACTIVE = 1,
+ PLDM_STATE_SET_BOOT_PROG_STATE_COMPLETED = 2,
+ PLDM_STATE_SET_BOOT_PROG_STATE_MEM_INITIALIZATION = 3,
+ PLDM_STATE_SET_BOOT_PROG_STATE_SEC_PROC_INITIALIZATION = 5,
+ PLDM_STATE_SET_BOOT_PROG_STATE_PCI_RESORUCE_CONFIG = 9,
+ PLDM_STATE_SET_BOOT_PROG_STATE_STARTING_OP_SYS = 21,
+ PLDM_STATE_SET_BOOT_PROG_STATE_BASE_BOARD_INITIALIZATION = 22,
+ PLDM_STATE_SET_BOOT_PROG_STATE_PRIMARY_PROC_INITIALIZATION = 26,
+};
+
+/* @brief List of states for the System Power State set (ID 260).
+ */
+enum pldm_state_set_system_power_state_values {
+ PLDM_STATE_SET_SYS_POWER_STATE_OFF_SOFT_GRACEFUL = 9
+};
+
+/* OEM ranges */
+#define PLDM_OEM_STATE_SET_ID_START 32768
+#define PLDM_OEM_STATE_SET_ID_END 65535
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* STATE_SET_H */
diff --git a/pldm/libpldm/states.h b/pldm/libpldm/states.h
new file mode 100644
index 00000000..a89648df
--- /dev/null
+++ b/pldm/libpldm/states.h
@@ -0,0 +1,27 @@
+#ifndef STATES_H
+#define STATES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "pldm_types.h"
+
+/** @brief PLDM enums for the boot progress state set
+ */
+enum pldm_boot_progress_states {
+ PLDM_BOOT_NOT_ACTIVE = 1,
+ PLDM_BOOT_COMPLETED = 2,
+};
+
+/** @brief PLDM enums for system power states
+ */
+enum pldm_system_power_states {
+ PLDM_OFF_SOFT_GRACEFUL = 9,
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* STATES_H */
diff --git a/pldm/libpldm/utils.c b/pldm/libpldm/utils.c
new file mode 100644
index 00000000..0bfe99a2
--- /dev/null
+++ b/pldm/libpldm/utils.c
@@ -0,0 +1,211 @@
+#include "utils.h"
+#include "base.h"
+#include <stdio.h>
+
+/** CRC32 code derived from work by Gary S. Brown.
+ * http://web.mit.edu/freebsd/head/sys/libkern/crc32.c
+ *
+ * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
+ * code or tables extracted from it, as desired without restriction.
+ *
+ */
+static uint32_t crc32_tab[] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+ 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+ 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+ 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+ 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+ 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+ 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+ 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+ 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+ 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+ 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d};
+
+/* 0x07(polynomial: x8+x2+x1+1)
+ */
+static const uint8_t crc8_table[] = {
+ 0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, 0x38, 0x3f, 0x36, 0x31,
+ 0x24, 0x23, 0x2a, 0x2d, 0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65,
+ 0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d, 0xe0, 0xe7, 0xee, 0xe9,
+ 0xfc, 0xfb, 0xf2, 0xf5, 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd,
+ 0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, 0xa8, 0xaf, 0xa6, 0xa1,
+ 0xb4, 0xb3, 0xba, 0xbd, 0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2,
+ 0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea, 0xb7, 0xb0, 0xb9, 0xbe,
+ 0xab, 0xac, 0xa5, 0xa2, 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a,
+ 0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, 0x1f, 0x18, 0x11, 0x16,
+ 0x03, 0x04, 0x0d, 0x0a, 0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42,
+ 0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a, 0x89, 0x8e, 0x87, 0x80,
+ 0x95, 0x92, 0x9b, 0x9c, 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4,
+ 0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec, 0xc1, 0xc6, 0xcf, 0xc8,
+ 0xdd, 0xda, 0xd3, 0xd4, 0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c,
+ 0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44, 0x19, 0x1e, 0x17, 0x10,
+ 0x05, 0x02, 0x0b, 0x0c, 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34,
+ 0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, 0x76, 0x71, 0x78, 0x7f,
+ 0x6a, 0x6d, 0x64, 0x63, 0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b,
+ 0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13, 0xae, 0xa9, 0xa0, 0xa7,
+ 0xb2, 0xb5, 0xbc, 0xbb, 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83,
+ 0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, 0xe6, 0xe1, 0xe8, 0xef,
+ 0xfa, 0xfd, 0xf4, 0xf3};
+
+uint32_t pldm_crc32(const void *data, size_t size)
+{
+ const uint8_t *p = data;
+ uint32_t crc = ~0U;
+ while (size--)
+ crc = crc32_tab[(crc ^ *p++) & 0xff] ^ (crc >> 8);
+ return crc ^ ~0U;
+}
+
+uint8_t crc8(const void *data, size_t size)
+{
+ const uint8_t *p = data;
+ uint8_t crc = 0x00;
+ while (size--)
+ crc = crc8_table[crc ^ *p++];
+ return crc;
+}
+
+static int print_version_field(uint8_t bcd, char *buffer, size_t buffer_size)
+{
+ int v;
+ if (bcd == 0xff)
+ return 0;
+ if ((bcd & 0xf0) == 0xf0) {
+ v = bcd & 0x0f;
+ return snprintf(buffer, buffer_size, "%d", v);
+ }
+ v = ((bcd >> 4) * 10) + (bcd & 0x0f);
+ return snprintf(buffer, buffer_size, "%02d", v);
+}
+
+#define POINTER_MOVE(rc, buffer, buffer_size, original_size) \
+ do { \
+ if (rc < 0) \
+ return rc; \
+ if ((size_t)rc >= buffer_size) \
+ return original_size - 1; \
+ buffer += rc; \
+ buffer_size -= rc; \
+ } while (0)
+
+int ver2str(const ver32_t *version, char *buffer, size_t buffer_size)
+{
+ int rc;
+ size_t original_size = buffer_size;
+ rc = print_version_field(version->major, buffer, buffer_size);
+ POINTER_MOVE(rc, buffer, buffer_size, original_size);
+ rc = snprintf(buffer, buffer_size, ".");
+ POINTER_MOVE(rc, buffer, buffer_size, original_size);
+ rc = print_version_field(version->minor, buffer, buffer_size);
+ POINTER_MOVE(rc, buffer, buffer_size, original_size);
+ if (version->update != 0xff) {
+ rc = snprintf(buffer, buffer_size, ".");
+ POINTER_MOVE(rc, buffer, buffer_size, original_size);
+ rc = print_version_field(version->update, buffer, buffer_size);
+ POINTER_MOVE(rc, buffer, buffer_size, original_size);
+ }
+ if (version->alpha != 0) {
+ rc = snprintf(buffer, buffer_size, "%c", version->alpha);
+ POINTER_MOVE(rc, buffer, buffer_size, original_size);
+ }
+ return original_size - buffer_size;
+}
+
+uint8_t bcd2dec8(uint8_t bcd)
+{
+ uint8_t dec = (bcd >> 4) * 10 + (bcd & 0x0f);
+ return dec;
+}
+
+uint8_t dec2bcd8(uint8_t dec)
+{
+ uint8_t bcd = (dec % 10) | (dec / 10) << 4;
+ return bcd;
+}
+
+uint16_t bcd2dec16(uint16_t bcd)
+{
+ return bcd2dec8(bcd >> 8) * 100 + bcd2dec8(bcd & 0xff);
+}
+
+uint16_t dec2bcd16(uint16_t dec)
+{
+ return dec2bcd8(dec % 100) | dec2bcd8(dec / 100) << 8;
+}
+
+uint32_t bcd2dec32(uint32_t bcd)
+{
+ return bcd2dec16(bcd >> 16) * 10000 + bcd2dec16(bcd & 0xffff);
+}
+
+uint32_t dec2bcd32(uint32_t dec)
+{
+ return dec2bcd16(dec % 10000) | dec2bcd16(dec / 10000) << 16;
+}
+
+bool is_time_legal(uint8_t seconds, uint8_t minutes, uint8_t hours, uint8_t day,
+ uint8_t month, uint16_t year)
+{
+ if (month < 1 || month > 12) {
+ return false;
+ }
+ static const int days[13] = {0, 31, 28, 31, 30, 31, 30,
+ 31, 31, 30, 31, 30, 31};
+ int rday = days[month];
+ if (month == 2 &&
+ ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))) {
+ rday += 1;
+ }
+ if (year < 1970 || day < 1 || day > rday || seconds > 59 ||
+ minutes > 59 || hours > 23) {
+ return false;
+ }
+ return true;
+}
+
+bool is_transfer_flag_valid(uint8_t transfer_flag)
+{
+ switch (transfer_flag) {
+ case PLDM_START:
+ case PLDM_MIDDLE:
+ case PLDM_END:
+ case PLDM_START_AND_END:
+ return true;
+
+ default:
+ return false;
+ }
+}
diff --git a/pldm/libpldm/utils.h b/pldm/libpldm/utils.h
new file mode 100644
index 00000000..7258c7a8
--- /dev/null
+++ b/pldm/libpldm/utils.h
@@ -0,0 +1,108 @@
+#ifndef UTILS_H__
+#define UTILS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "pldm_types.h"
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+/** @struct variable_field
+ *
+ * Structure representing variable field in the pldm message
+ */
+struct variable_field {
+ const uint8_t *ptr;
+ size_t length;
+};
+
+/** @brief Compute Crc8(same as the one used by SMBUS)
+ *
+ * @param[in] data - Pointer to the target data
+ * @param[in] size - Size of the data
+ * @return The checksum
+ */
+uint8_t crc8(const void *data, size_t size);
+
+/** @brief Compute Crc32(same as the one used by IEEE802.3)
+ *
+ * @param[in] data - Pointer to the target data
+ * @param[in] size - Size of the data
+ * @return The checksum
+ */
+uint32_t pldm_crc32(const void *data, size_t size);
+
+/** @brief Convert ver32_t to string
+ * @param[in] version - Pointer to ver32_t
+ * @param[out] buffer - Pointer to the buffer
+ * @param[in] buffer_size - Size of the buffer
+ * @return The number of characters(excluding the null byte) or negative if
+ * error is encountered
+ */
+int ver2str(const ver32_t *version, char *buffer, size_t buffer_size);
+
+/** @brief Convert bcd number(uint8_t) to decimal
+ * @param[in] bcd - bcd number
+ * @return the decimal number
+ */
+uint8_t bcd2dec8(uint8_t bcd);
+
+/** @brief Convert decimal number(uint8_t) to bcd
+ * @param[in] dec - decimal number
+ * @return the bcd number
+ */
+uint8_t dec2bcd8(uint8_t dec);
+
+/** @brief Convert bcd number(uint16_t) to decimal
+ * @param[in] bcd - bcd number
+ * @return the decimal number
+ */
+uint16_t bcd2dec16(uint16_t bcd);
+
+/** @brief Convert decimal number(uint16_t) to bcd
+ * @param[in] dec - decimal number
+ * @return the bcd number
+ */
+uint16_t dec2bcd16(uint16_t dec);
+
+/** @brief Convert bcd number(uint32_t) to decimal
+ * @param[in] bcd - bcd number
+ * @return the decimal number
+ */
+uint32_t bcd2dec32(uint32_t bcd);
+
+/** @brief Convert decimal number(uint32_t) to bcd
+ * @param[in] dec - decimal number
+ * @return the bcd number
+ */
+uint32_t dec2bcd32(uint32_t dec);
+
+/** @brief Check whether the input time is legal
+ *
+ * @param[in] seconds. Value range 0~59
+ * @param[in] minutes. Value range 0~59
+ * @param[in] hours. Value range 0~23
+ * @param[in] day. Value range 1~31
+ * @param[in] month. Value range 1~12
+ * @param[in] year. Value range 1970~
+ * @return true if time is legal,false if time is illegal
+ */
+bool is_time_legal(uint8_t seconds, uint8_t minutes, uint8_t hours, uint8_t day,
+ uint8_t month, uint16_t year);
+
+/** @brief Check whether transfer flag is valid
+ *
+ * @param[in] transfer_flag - TransferFlag
+ *
+ * @return true if transfer flag is valid, false if not
+ */
+bool is_transfer_flag_valid(uint8_t transfer_flag);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--
2.35.1
More information about the Skiboot
mailing list