libpldm: Migrate to subproject
Organize files in libpldm to make it a subproject
In the current state, libpldm is not readily consumable
as a subproject.This commit does all the necessary re-organisation
of the source code to make it work as a subproject.
There are no .c/.h files changes in this commit, only meson
changes and re-organising the code structure.
Signed-off-by: Manojkiran Eda <manojkiran.eda@gmail.com>
Change-Id: I20a71c0c972b1fd81fb359d604433618799102c6
diff --git a/src/base.c b/src/base.c
new file mode 100644
index 0000000..9a5ae09
--- /dev/null
+++ b/src/base.c
@@ -0,0 +1,488 @@
+#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 decode_multipart_receive_req(
+ const struct pldm_msg *msg, size_t payload_length, uint8_t *pldm_type,
+ uint8_t *transfer_opflag, uint32_t *transfer_ctx, uint32_t *transfer_handle,
+ uint32_t *section_offset, uint32_t *section_length)
+{
+ if (msg == NULL || pldm_type == NULL || transfer_opflag == NULL ||
+ transfer_ctx == NULL || transfer_handle == NULL ||
+ section_offset == NULL || section_length == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (payload_length != PLDM_MULTIPART_RECEIVE_REQ_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_multipart_receive_req *request =
+ (struct pldm_multipart_receive_req *)msg->payload;
+
+ if (request->pldm_type != PLDM_BASE) {
+ return PLDM_ERROR_INVALID_PLDM_TYPE;
+ }
+
+ // Any enum value above PLDM_XFER_CURRENT_PART is invalid.
+ if (request->transfer_opflag > PLDM_XFER_CURRENT_PART) {
+ return PLDM_INVALID_TRANSFER_OPERATION_FLAG;
+ }
+
+ // A section offset of 0 is only valid on FIRST_PART or COMPLETE Xfers.
+ uint32_t sec_offset = le32toh(request->section_offset);
+ if (sec_offset == 0 &&
+ (request->transfer_opflag != PLDM_XFER_FIRST_PART &&
+ request->transfer_opflag != PLDM_XFER_COMPLETE)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ uint32_t handle = le32toh(request->transfer_handle);
+ if (handle == 0 && request->transfer_opflag != PLDM_XFER_COMPLETE) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ *pldm_type = request->pldm_type;
+ *transfer_opflag = request->transfer_opflag;
+ *transfer_ctx = request->transfer_ctx;
+ *transfer_handle = handle;
+ *section_offset = sec_offset;
+ *section_length = le32toh(request->section_length);
+
+ return PLDM_SUCCESS;
+}
+
+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/src/bios.c b/src/bios.c
new file mode 100644
index 0000000..8d93a6a
--- /dev/null
+++ b/src/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/src/bios_table.c b/src/bios_table.c
new file mode 100644
index 0000000..ea9f669
--- /dev/null
+++ b/src/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 = 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 = crc32(table, size - 4);
+
+ return src_crc == dst_crc;
+}
diff --git a/src/firmware_update.c b/src/firmware_update.c
new file mode 100644
index 0000000..59d1f9d
--- /dev/null
+++ b/src/firmware_update.c
@@ -0,0 +1,1568 @@
+#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->package_release_date_time,
+ data_header->package_release_date_time,
+ sizeof(data_header->package_release_date_time));
+ package_header_info->component_bitmap_bit_length =
+ le16toh(data_header->component_bitmap_bit_length);
+ package_header_info->package_version_string_type =
+ data_header->package_version_string_type;
+ package_header_info->package_version_string_length =
+ data_header->package_version_string_length;
+ package_version_str->ptr =
+ data + sizeof(struct pldm_package_header_information);
+ package_version_str->length =
+ package_header_info->package_version_string_length;
+
+ return PLDM_SUCCESS;
+}
+
+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_compatibility_resp,
+ uint8_t *comp_compatibility_resp_code,
+ bitfield32_t *update_option_flags_enabled,
+ uint16_t *time_before_req_fw_data)
+{
+ if (msg == NULL || completion_code == NULL ||
+ comp_compatibility_resp == NULL ||
+ comp_compatibility_resp_code == NULL ||
+ update_option_flags_enabled == NULL ||
+ time_before_req_fw_data == NULL || !payload_length) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ *completion_code = msg->payload[0];
+ if (*completion_code != PLDM_SUCCESS) {
+ return PLDM_SUCCESS;
+ }
+
+ if (payload_length != sizeof(struct pldm_update_component_resp)) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_update_component_resp *response =
+ (struct pldm_update_component_resp *)msg->payload;
+
+ if (!is_comp_compatibility_resp_valid(
+ response->comp_compatibility_resp)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (!is_comp_compatibility_resp_code_valid(
+ response->comp_compatibility_resp_code)) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ *comp_compatibility_resp = response->comp_compatibility_resp;
+ *comp_compatibility_resp_code = response->comp_compatibility_resp_code;
+ update_option_flags_enabled->value =
+ le32toh(response->update_option_flags_enabled.value);
+ *time_before_req_fw_data = le16toh(response->time_before_req_fw_data);
+
+ return PLDM_SUCCESS;
+}
+
+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/src/fru.c b/src/fru.c
new file mode 100644
index 0000000..fa79f2b
--- /dev/null
+++ b/src/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/src/meson.build b/src/meson.build
new file mode 100644
index 0000000..fc44e8a
--- /dev/null
+++ b/src/meson.build
@@ -0,0 +1,19 @@
+
+libpldm_sources += files(
+ 'base.c',
+ 'bios.c',
+ 'platform.c',
+ 'bios_table.c',
+ 'firmware_update.c',
+ 'fru.c',
+ 'pdr.c',
+ 'utils.c'
+ )
+
+if get_option('oem-ibm').enabled()
+ subdir('oem/ibm')
+endif
+
+if get_option('requester-api').enabled()
+ subdir('requester')
+endif
diff --git a/src/oem/ibm/file_io.c b/src/oem/ibm/file_io.c
new file mode 100644
index 0000000..b3464cb
--- /dev/null
+++ b/src/oem/ibm/file_io.c
@@ -0,0 +1,1056 @@
+#include "libpldm/file_io.h"
+#include <endian.h>
+#include <string.h>
+
+int decode_rw_file_memory_req(const struct pldm_msg *msg, size_t payload_length,
+ uint32_t *file_handle, uint32_t *offset,
+ uint32_t *length, uint64_t *address)
+{
+ if (msg == NULL || file_handle == NULL || offset == NULL ||
+ length == NULL || address == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (payload_length != PLDM_RW_FILE_MEM_REQ_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_read_write_file_memory_req *request =
+ (struct pldm_read_write_file_memory_req *)msg->payload;
+
+ *file_handle = le32toh(request->file_handle);
+ *offset = le32toh(request->offset);
+ *length = le32toh(request->length);
+ *address = le64toh(request->address);
+
+ return PLDM_SUCCESS;
+}
+
+int encode_rw_file_memory_resp(uint8_t instance_id, uint8_t command,
+ uint8_t completion_code, uint32_t length,
+ struct pldm_msg *msg)
+{
+ if (msg == NULL) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_header_info header = {0};
+ header.msg_type = PLDM_RESPONSE;
+ header.instance = instance_id;
+ header.pldm_type = PLDM_OEM;
+ header.command = command;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+
+ struct pldm_read_write_file_memory_resp *response =
+ (struct pldm_read_write_file_memory_resp *)msg->payload;
+ response->completion_code = completion_code;
+ if (response->completion_code == PLDM_SUCCESS) {
+ response->length = htole32(length);
+ }
+
+ return PLDM_SUCCESS;
+}
+
+int encode_rw_file_memory_req(uint8_t instance_id, uint8_t command,
+ uint32_t file_handle, uint32_t offset,
+ uint32_t length, uint64_t address,
+ 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_OEM;
+ header.command = command;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+
+ struct pldm_read_write_file_memory_req *req =
+ (struct pldm_read_write_file_memory_req *)msg->payload;
+ req->file_handle = htole32(file_handle);
+ req->offset = htole32(offset);
+ req->length = htole32(length);
+ req->address = htole64(address);
+ return PLDM_SUCCESS;
+}
+
+int decode_rw_file_memory_resp(const struct pldm_msg *msg,
+ size_t payload_length, uint8_t *completion_code,
+ uint32_t *length)
+{
+ if (msg == NULL || length == NULL || completion_code == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (payload_length != PLDM_RW_FILE_MEM_RESP_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_read_write_file_memory_resp *response =
+ (struct pldm_read_write_file_memory_resp *)msg->payload;
+ *completion_code = response->completion_code;
+ if (*completion_code == PLDM_SUCCESS) {
+ *length = le32toh(response->length);
+ }
+
+ return PLDM_SUCCESS;
+}
+
+int decode_get_file_table_req(const struct pldm_msg *msg, size_t payload_length,
+ uint32_t *transfer_handle,
+ uint8_t *transfer_opflag, uint8_t *table_type)
+{
+ if (msg == NULL || transfer_handle == NULL || transfer_opflag == NULL ||
+ table_type == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (payload_length != PLDM_GET_FILE_TABLE_REQ_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_get_file_table_req *request =
+ (struct pldm_get_file_table_req *)msg->payload;
+
+ *transfer_handle = le32toh(request->transfer_handle);
+ *transfer_opflag = request->operation_flag;
+ *table_type = request->table_type;
+
+ return PLDM_SUCCESS;
+}
+
+int encode_get_file_table_resp(uint8_t instance_id, uint8_t completion_code,
+ uint32_t next_transfer_handle,
+ uint8_t transfer_flag, const uint8_t *table_data,
+ size_t table_size, struct pldm_msg *msg)
+{
+ if (msg == NULL) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_header_info header = {0};
+ header.msg_type = PLDM_RESPONSE;
+ header.instance = instance_id;
+ header.pldm_type = PLDM_OEM;
+ header.command = PLDM_GET_FILE_TABLE;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+
+ struct pldm_get_file_table_resp *response =
+ (struct pldm_get_file_table_resp *)msg->payload;
+ response->completion_code = completion_code;
+
+ if (completion_code == PLDM_SUCCESS) {
+ response->next_transfer_handle = htole32(next_transfer_handle);
+ response->transfer_flag = transfer_flag;
+ memcpy(response->table_data, table_data, table_size);
+ }
+
+ return PLDM_SUCCESS;
+}
+
+int encode_get_file_table_req(uint8_t instance_id, uint32_t transfer_handle,
+ uint8_t transfer_opflag, 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_OEM;
+ header.command = PLDM_GET_FILE_TABLE;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+
+ struct pldm_get_file_table_req *request =
+ (struct pldm_get_file_table_req *)msg->payload;
+
+ request->transfer_handle = htole32(transfer_handle);
+ request->operation_flag = transfer_opflag;
+ request->table_type = table_type;
+ return PLDM_SUCCESS;
+}
+
+int decode_get_file_table_resp(const struct pldm_msg *msg,
+ size_t payload_length, uint8_t *completion_code,
+ uint32_t *next_transfer_handle,
+ uint8_t *transfer_flag,
+ uint8_t *file_table_data_start_offset,
+ size_t *file_table_length)
+{
+ if (msg == NULL || transfer_flag == NULL ||
+ next_transfer_handle == NULL || completion_code == NULL ||
+ file_table_data_start_offset == NULL || file_table_length == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (payload_length <= PLDM_GET_FILE_TABLE_MIN_RESP_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ *completion_code = msg->payload[0];
+
+ if (PLDM_SUCCESS != *completion_code) {
+ return PLDM_SUCCESS;
+ }
+
+ struct pldm_get_file_table_resp *response =
+ (struct pldm_get_file_table_resp *)msg->payload;
+
+ *next_transfer_handle = le32toh(response->next_transfer_handle);
+ *transfer_flag = response->transfer_flag;
+ *file_table_data_start_offset = sizeof(*completion_code) +
+ sizeof(*next_transfer_handle) +
+ sizeof(*transfer_flag);
+ *file_table_length =
+ payload_length - PLDM_GET_FILE_TABLE_MIN_RESP_BYTES;
+
+ return PLDM_SUCCESS;
+}
+
+int decode_read_file_req(const struct pldm_msg *msg, size_t payload_length,
+ uint32_t *file_handle, uint32_t *offset,
+ uint32_t *length)
+{
+ if (msg == NULL || file_handle == NULL || offset == NULL ||
+ length == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (payload_length != PLDM_READ_FILE_REQ_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_read_file_req *request =
+ (struct pldm_read_file_req *)msg->payload;
+
+ *file_handle = le32toh(request->file_handle);
+ *offset = le32toh(request->offset);
+ *length = le32toh(request->length);
+
+ return PLDM_SUCCESS;
+}
+
+int encode_read_file_req(uint8_t instance_id, uint32_t file_handle,
+ uint32_t offset, uint32_t length, struct pldm_msg *msg)
+{
+ if (msg == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (length == 0) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_header_info header = {0};
+ header.msg_type = PLDM_REQUEST;
+ header.instance = instance_id;
+ header.pldm_type = PLDM_OEM;
+ header.command = PLDM_READ_FILE;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+
+ struct pldm_read_file_req *request =
+ (struct pldm_read_file_req *)msg->payload;
+
+ request->file_handle = htole32(file_handle);
+ request->offset = htole32(offset);
+ request->length = htole32(length);
+
+ return PLDM_SUCCESS;
+}
+
+int decode_read_file_resp(const struct pldm_msg *msg, size_t payload_length,
+ uint8_t *completion_code, uint32_t *length,
+ size_t *file_data_offset)
+{
+ if (msg == NULL || completion_code == NULL || length == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (payload_length < PLDM_READ_FILE_RESP_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_read_file_resp *response =
+ (struct pldm_read_file_resp *)msg->payload;
+
+ *completion_code = response->completion_code;
+ if (*completion_code == PLDM_SUCCESS) {
+ *length = le32toh(response->length);
+ if (payload_length != PLDM_READ_FILE_RESP_BYTES + *length) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+ *file_data_offset = sizeof(*completion_code) + sizeof(*length);
+ }
+
+ return PLDM_SUCCESS;
+}
+
+int encode_read_file_resp(uint8_t instance_id, uint8_t completion_code,
+ uint32_t 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_OEM;
+ header.command = PLDM_READ_FILE;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+
+ struct pldm_read_file_resp *response =
+ (struct pldm_read_file_resp *)msg->payload;
+ response->completion_code = completion_code;
+
+ if (response->completion_code == PLDM_SUCCESS) {
+ response->length = htole32(length);
+ }
+
+ return PLDM_SUCCESS;
+}
+
+int decode_write_file_req(const struct pldm_msg *msg, size_t payload_length,
+ uint32_t *file_handle, uint32_t *offset,
+ uint32_t *length, size_t *file_data_offset)
+{
+ if (msg == NULL || file_handle == NULL || length == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (payload_length < PLDM_WRITE_FILE_REQ_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_write_file_req *request =
+ (struct pldm_write_file_req *)msg->payload;
+
+ *file_handle = le32toh(request->file_handle);
+ *offset = le32toh(request->offset);
+ *length = le32toh(request->length);
+ if (payload_length != PLDM_WRITE_FILE_REQ_BYTES + *length) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+ *file_data_offset =
+ sizeof(*file_handle) + sizeof(*offset) + sizeof(*length);
+
+ return PLDM_SUCCESS;
+}
+
+int encode_write_file_req(uint8_t instance_id, uint32_t file_handle,
+ uint32_t offset, uint32_t length,
+ struct pldm_msg *msg)
+{
+ if (msg == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (length == 0) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_header_info header = {0};
+ header.msg_type = PLDM_REQUEST;
+ header.instance = instance_id;
+ header.pldm_type = PLDM_OEM;
+ header.command = PLDM_WRITE_FILE;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+
+ struct pldm_write_file_req *request =
+ (struct pldm_write_file_req *)msg->payload;
+
+ request->file_handle = htole32(file_handle);
+ request->offset = htole32(offset);
+ request->length = htole32(length);
+
+ return PLDM_SUCCESS;
+}
+
+int decode_write_file_resp(const struct pldm_msg *msg, size_t payload_length,
+ uint8_t *completion_code, uint32_t *length)
+{
+ if (msg == NULL || completion_code == NULL || length == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (payload_length != PLDM_WRITE_FILE_RESP_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_write_file_resp *response =
+ (struct pldm_write_file_resp *)msg->payload;
+
+ *completion_code = le32toh(response->completion_code);
+ if (response->completion_code == PLDM_SUCCESS) {
+ *length = le32toh(response->length);
+ }
+
+ return PLDM_SUCCESS;
+}
+
+int encode_write_file_resp(uint8_t instance_id, uint8_t completion_code,
+ uint32_t 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_OEM;
+ header.command = PLDM_WRITE_FILE;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+
+ struct pldm_write_file_resp *response =
+ (struct pldm_write_file_resp *)msg->payload;
+ response->completion_code = completion_code;
+
+ if (response->completion_code == PLDM_SUCCESS) {
+ response->length = htole32(length);
+ }
+
+ return PLDM_SUCCESS;
+}
+
+int decode_rw_file_by_type_memory_req(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint16_t *file_type,
+ uint32_t *file_handle, uint32_t *offset,
+ uint32_t *length, uint64_t *address)
+{
+ if (msg == NULL || file_type == NULL || file_handle == NULL ||
+ offset == NULL || length == NULL || address == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (payload_length != PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_read_write_file_by_type_memory_req *request =
+ (struct pldm_read_write_file_by_type_memory_req *)msg->payload;
+ *file_type = le16toh(request->file_type);
+ *file_handle = le32toh(request->file_handle);
+ *offset = le32toh(request->offset);
+ *length = le32toh(request->length);
+ *address = le64toh(request->address);
+
+ return PLDM_SUCCESS;
+}
+
+int encode_rw_file_by_type_memory_resp(uint8_t instance_id, uint8_t command,
+ uint8_t completion_code, uint32_t 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_OEM;
+ header.command = command;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+
+ struct pldm_read_write_file_by_type_memory_resp *response =
+ (struct pldm_read_write_file_by_type_memory_resp *)msg->payload;
+ response->completion_code = completion_code;
+ if (response->completion_code == PLDM_SUCCESS) {
+ response->length = htole32(length);
+ }
+
+ return PLDM_SUCCESS;
+}
+
+int encode_rw_file_by_type_memory_req(uint8_t instance_id, uint8_t command,
+ uint16_t file_type, uint32_t file_handle,
+ uint32_t offset, uint32_t length,
+ uint64_t address, 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_OEM;
+ header.command = command;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+
+ struct pldm_read_write_file_by_type_memory_req *req =
+ (struct pldm_read_write_file_by_type_memory_req *)msg->payload;
+ req->file_type = htole16(file_type);
+ req->file_handle = htole32(file_handle);
+ req->offset = htole32(offset);
+ req->length = htole32(length);
+ req->address = htole64(address);
+
+ return PLDM_SUCCESS;
+}
+
+int decode_rw_file_by_type_memory_resp(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint8_t *completion_code,
+ uint32_t *length)
+{
+ if (msg == NULL || length == NULL || completion_code == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (payload_length != PLDM_RW_FILE_BY_TYPE_MEM_RESP_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_read_write_file_by_type_memory_resp *response =
+ (struct pldm_read_write_file_by_type_memory_resp *)msg->payload;
+ *completion_code = response->completion_code;
+ if (*completion_code == PLDM_SUCCESS) {
+ *length = le32toh(response->length);
+ }
+
+ return PLDM_SUCCESS;
+}
+
+int decode_new_file_req(const struct pldm_msg *msg, size_t payload_length,
+ uint16_t *file_type, uint32_t *file_handle,
+ uint64_t *length)
+{
+ if (msg == NULL || file_type == NULL || file_handle == NULL ||
+ length == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (payload_length != PLDM_NEW_FILE_REQ_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_new_file_req *request =
+ (struct pldm_new_file_req *)msg->payload;
+ *file_type = le16toh(request->file_type);
+ *file_handle = le32toh(request->file_handle);
+ *length = le64toh(request->length);
+
+ return PLDM_SUCCESS;
+}
+
+int encode_new_file_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_OEM;
+ header.command = PLDM_NEW_FILE_AVAILABLE;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+
+ struct pldm_new_file_resp *response =
+ (struct pldm_new_file_resp *)msg->payload;
+ response->completion_code = completion_code;
+
+ return PLDM_SUCCESS;
+}
+
+int encode_new_file_req(uint8_t instance_id, uint16_t file_type,
+ uint32_t file_handle, uint64_t length,
+ 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_OEM;
+ header.command = PLDM_NEW_FILE_AVAILABLE;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+
+ struct pldm_new_file_req *req =
+ (struct pldm_new_file_req *)msg->payload;
+ req->file_type = htole16(file_type);
+ req->file_handle = htole32(file_handle);
+ req->length = htole64(length);
+
+ return PLDM_SUCCESS;
+}
+
+int decode_new_file_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_NEW_FILE_RESP_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_new_file_resp *response =
+ (struct pldm_new_file_resp *)msg->payload;
+ *completion_code = response->completion_code;
+
+ return PLDM_SUCCESS;
+}
+
+int decode_rw_file_by_type_req(const struct pldm_msg *msg,
+ size_t payload_length, uint16_t *file_type,
+ uint32_t *file_handle, uint32_t *offset,
+ uint32_t *length)
+{
+ if (msg == NULL || file_type == NULL || file_handle == NULL ||
+ offset == NULL || length == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (payload_length < PLDM_RW_FILE_BY_TYPE_REQ_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_read_write_file_by_type_req *request =
+ (struct pldm_read_write_file_by_type_req *)msg->payload;
+ *file_type = le16toh(request->file_type);
+ *file_handle = le32toh(request->file_handle);
+ *offset = le32toh(request->offset);
+ *length = le32toh(request->length);
+
+ return PLDM_SUCCESS;
+}
+
+int encode_rw_file_by_type_resp(uint8_t instance_id, uint8_t command,
+ uint8_t completion_code, uint32_t length,
+ struct pldm_msg *msg)
+{
+ if (msg == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ if (command != PLDM_READ_FILE_BY_TYPE &&
+ command != PLDM_WRITE_FILE_BY_TYPE) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ struct pldm_header_info header = {0};
+ header.msg_type = PLDM_RESPONSE;
+ header.instance = instance_id;
+ header.pldm_type = PLDM_OEM;
+ header.command = command;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+
+ struct pldm_read_write_file_by_type_resp *response =
+ (struct pldm_read_write_file_by_type_resp *)msg->payload;
+ response->completion_code = completion_code;
+ if (response->completion_code == PLDM_SUCCESS) {
+ response->length = htole32(length);
+ }
+
+ return PLDM_SUCCESS;
+}
+
+int encode_rw_file_by_type_req(uint8_t instance_id, uint8_t command,
+ uint16_t file_type, uint32_t file_handle,
+ uint32_t offset, uint32_t length,
+ struct pldm_msg *msg)
+{
+ if (msg == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+ if (command != PLDM_READ_FILE_BY_TYPE &&
+ command != PLDM_WRITE_FILE_BY_TYPE) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ struct pldm_header_info header = {0};
+ header.msg_type = PLDM_REQUEST;
+ header.instance = instance_id;
+ header.pldm_type = PLDM_OEM;
+ header.command = command;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+
+ struct pldm_read_write_file_by_type_req *req =
+ (struct pldm_read_write_file_by_type_req *)msg->payload;
+ req->file_type = htole16(file_type);
+ req->file_handle = htole32(file_handle);
+ req->offset = htole32(offset);
+ req->length = htole32(length);
+
+ return PLDM_SUCCESS;
+}
+
+int decode_rw_file_by_type_resp(const struct pldm_msg *msg,
+ size_t payload_length, uint8_t *completion_code,
+ uint32_t *length)
+{
+ if (msg == NULL || length == NULL || completion_code == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (payload_length != PLDM_RW_FILE_BY_TYPE_RESP_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_read_write_file_by_type_resp *response =
+ (struct pldm_read_write_file_by_type_resp *)msg->payload;
+ *completion_code = response->completion_code;
+ if (*completion_code == PLDM_SUCCESS) {
+ *length = le32toh(response->length);
+ }
+
+ return PLDM_SUCCESS;
+}
+
+int decode_file_ack_req(const struct pldm_msg *msg, size_t payload_length,
+ uint16_t *file_type, uint32_t *file_handle,
+ uint8_t *file_status)
+{
+ if (msg == NULL || file_type == NULL || file_handle == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (payload_length != PLDM_FILE_ACK_REQ_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_file_ack_req *request =
+ (struct pldm_file_ack_req *)msg->payload;
+ *file_type = le16toh(request->file_type);
+ *file_handle = le32toh(request->file_handle);
+ *file_status = request->file_status;
+
+ return PLDM_SUCCESS;
+}
+
+int encode_file_ack_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_OEM;
+ header.command = PLDM_FILE_ACK;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+
+ struct pldm_file_ack_resp *response =
+ (struct pldm_file_ack_resp *)msg->payload;
+ response->completion_code = completion_code;
+
+ return PLDM_SUCCESS;
+}
+
+int encode_file_ack_req(uint8_t instance_id, uint16_t file_type,
+ uint32_t file_handle, uint8_t file_status,
+ 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_OEM;
+ header.command = PLDM_FILE_ACK;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+
+ struct pldm_file_ack_req *req =
+ (struct pldm_file_ack_req *)msg->payload;
+ req->file_type = htole16(file_type);
+ req->file_handle = htole32(file_handle);
+ req->file_status = file_status;
+
+ return PLDM_SUCCESS;
+}
+
+int decode_file_ack_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_FILE_ACK_RESP_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_file_ack_resp *response =
+ (struct pldm_file_ack_resp *)msg->payload;
+ *completion_code = response->completion_code;
+
+ return PLDM_SUCCESS;
+}
+
+int encode_file_ack_with_meta_data_req(
+ uint8_t instance_id, uint16_t file_type, uint32_t file_handle,
+ uint8_t file_status, uint32_t file_meta_data_1, uint32_t file_meta_data_2,
+ uint32_t file_meta_data_3, uint32_t file_meta_data_4, 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_OEM;
+ header.command = PLDM_FILE_ACK_WITH_META_DATA;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+
+ struct pldm_file_ack_with_meta_data_req *req =
+ (struct pldm_file_ack_with_meta_data_req *)msg->payload;
+ req->file_type = htole16(file_type);
+ req->file_handle = htole32(file_handle);
+ req->file_status = file_status;
+ req->file_meta_data_1 = htole32(file_meta_data_1);
+ req->file_meta_data_2 = htole32(file_meta_data_2);
+ req->file_meta_data_3 = htole32(file_meta_data_3);
+ req->file_meta_data_4 = htole32(file_meta_data_4);
+
+ return PLDM_SUCCESS;
+}
+
+int decode_file_ack_with_meta_data_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_FILE_ACK_WITH_META_DATA_RESP_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_file_ack_with_meta_data_resp *response =
+ (struct pldm_file_ack_with_meta_data_resp *)msg->payload;
+ *completion_code = response->completion_code;
+
+ return PLDM_SUCCESS;
+}
+
+int decode_file_ack_with_meta_data_req(
+ const struct pldm_msg *msg, size_t payload_length, uint16_t *file_type,
+ uint32_t *file_handle, uint8_t *file_status, uint32_t *file_meta_data_1,
+ uint32_t *file_meta_data_2, uint32_t *file_meta_data_3,
+ uint32_t *file_meta_data_4)
+{
+ if (msg == NULL || file_type == NULL || file_handle == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (payload_length != PLDM_FILE_ACK_WITH_META_DATA_REQ_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_file_ack_with_meta_data_req *request =
+ (struct pldm_file_ack_with_meta_data_req *)msg->payload;
+ *file_type = le16toh(request->file_type);
+ *file_handle = le32toh(request->file_handle);
+ *file_status = request->file_status;
+ *file_meta_data_1 = le32toh(request->file_meta_data_1);
+ *file_meta_data_2 = le32toh(request->file_meta_data_2);
+ *file_meta_data_3 = le32toh(request->file_meta_data_3);
+ *file_meta_data_4 = le32toh(request->file_meta_data_4);
+
+ return PLDM_SUCCESS;
+}
+
+int encode_file_ack_with_meta_data_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_OEM;
+ header.command = PLDM_FILE_ACK_WITH_META_DATA;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+
+ struct pldm_file_ack_with_meta_data_resp *response =
+ (struct pldm_file_ack_with_meta_data_resp *)msg->payload;
+ response->completion_code = completion_code;
+
+ return PLDM_SUCCESS;
+}
+
+int encode_new_file_with_metadata_req(
+ uint8_t instance_id, uint16_t file_type, uint32_t file_handle,
+ uint64_t length, uint32_t file_meta_data_1, uint32_t file_meta_data_2,
+ uint32_t file_meta_data_3, uint32_t file_meta_data_4, 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_OEM;
+ header.command = PLDM_NEW_FILE_AVAILABLE_WITH_META_DATA;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+
+ struct pldm_new_file_with_metadata_req *req =
+ (struct pldm_new_file_with_metadata_req *)msg->payload;
+ req->file_type = htole16(file_type);
+ req->file_handle = htole32(file_handle);
+ req->length = htole64(length);
+ req->file_meta_data_1 = htole32(file_meta_data_1);
+ req->file_meta_data_2 = htole32(file_meta_data_2);
+ req->file_meta_data_3 = htole32(file_meta_data_3);
+ req->file_meta_data_4 = htole32(file_meta_data_4);
+
+ return PLDM_SUCCESS;
+}
+
+int decode_new_file_with_metadata_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_NEW_FILE_AVAILABLE_WITH_META_DATA_RESP_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_new_file_with_metadata_resp *response =
+ (struct pldm_new_file_with_metadata_resp *)msg->payload;
+
+ *completion_code = msg->payload[0];
+ if (*completion_code == PLDM_SUCCESS) {
+ *completion_code = response->completion_code;
+ }
+ return PLDM_SUCCESS;
+}
+
+int decode_new_file_with_metadata_req(
+ const struct pldm_msg *msg, size_t payload_length, uint16_t *file_type,
+ uint32_t *file_handle, uint64_t *length, uint32_t *file_meta_data_1,
+ uint32_t *file_meta_data_2, uint32_t *file_meta_data_3,
+ uint32_t *file_meta_data_4)
+{
+ if (msg == NULL || file_type == NULL || file_handle == NULL ||
+ length == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (payload_length !=
+ PLDM_NEW_FILE_AVAILABLE_WITH_META_DATA_REQ_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_new_file_with_metadata_req *request =
+ (struct pldm_new_file_with_metadata_req *)msg->payload;
+ *file_type = le16toh(request->file_type);
+ *file_handle = le32toh(request->file_handle);
+ *length = le64toh(request->length);
+ *file_meta_data_1 = le32toh(request->file_meta_data_1);
+ *file_meta_data_2 = le32toh(request->file_meta_data_2);
+ *file_meta_data_3 = le32toh(request->file_meta_data_3);
+ *file_meta_data_4 = le32toh(request->file_meta_data_4);
+
+ return PLDM_SUCCESS;
+}
+
+int encode_new_file_with_metadata_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_OEM;
+ header.command = PLDM_NEW_FILE_AVAILABLE_WITH_META_DATA;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+
+ struct pldm_new_file_with_metadata_resp *response =
+ (struct pldm_new_file_with_metadata_resp *)msg->payload;
+
+ if (response->completion_code == PLDM_SUCCESS) {
+ response->completion_code = completion_code;
+ }
+
+ return PLDM_SUCCESS;
+}
diff --git a/src/oem/ibm/host.c b/src/oem/ibm/host.c
new file mode 100644
index 0000000..d557a41
--- /dev/null
+++ b/src/oem/ibm/host.c
@@ -0,0 +1,106 @@
+#include <endian.h>
+#include <string.h>
+
+#include "libpldm/host.h"
+
+int encode_get_alert_status_req(uint8_t instance_id, uint8_t version_id,
+ struct pldm_msg *msg, size_t payload_length)
+{
+ if (msg == NULL) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ if (payload_length != PLDM_GET_ALERT_STATUS_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_OEM;
+ header.command = PLDM_HOST_GET_ALERT_STATUS;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+
+ msg->payload[0] = version_id;
+
+ return PLDM_SUCCESS;
+}
+
+int decode_get_alert_status_resp(const struct pldm_msg *msg,
+ size_t payload_length,
+ uint8_t *completion_code, uint32_t *rack_entry,
+ uint32_t *pri_cec_node)
+{
+ if (msg == NULL || completion_code == NULL || rack_entry == NULL ||
+ pri_cec_node == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ *completion_code = msg->payload[0];
+ if (PLDM_SUCCESS != *completion_code) {
+ return PLDM_SUCCESS;
+ }
+
+ if (payload_length != PLDM_GET_ALERT_STATUS_RESP_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ struct pldm_get_alert_status_resp *response =
+ (struct pldm_get_alert_status_resp *)msg->payload;
+
+ *rack_entry = le32toh(response->rack_entry);
+ *pri_cec_node = le32toh(response->pri_cec_node);
+
+ return PLDM_SUCCESS;
+}
+
+int decode_get_alert_status_req(const struct pldm_msg *msg,
+ size_t payload_length, uint8_t *version_id)
+{
+ if (msg == NULL || version_id == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (payload_length != PLDM_GET_ALERT_STATUS_REQ_BYTES) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ *version_id = msg->payload[0];
+
+ return PLDM_SUCCESS;
+}
+
+int encode_get_alert_status_resp(uint8_t instance_id, uint8_t completion_code,
+ uint32_t rack_entry, uint32_t pri_cec_node,
+ struct pldm_msg *msg, size_t payload_length)
+{
+ if (msg == NULL) {
+ return PLDM_ERROR_INVALID_LENGTH;
+ }
+
+ if (payload_length != PLDM_GET_ALERT_STATUS_RESP_BYTES) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ struct pldm_header_info header = {0};
+ header.msg_type = PLDM_RESPONSE;
+ header.instance = instance_id;
+ header.pldm_type = PLDM_OEM;
+ header.command = PLDM_HOST_GET_ALERT_STATUS;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+
+ struct pldm_get_alert_status_resp *response =
+ (struct pldm_get_alert_status_resp *)msg->payload;
+
+ response->completion_code = completion_code;
+ response->rack_entry = htole32(rack_entry);
+ response->pri_cec_node = htole32(pri_cec_node);
+
+ return PLDM_SUCCESS;
+}
diff --git a/src/oem/ibm/meson.build b/src/oem/ibm/meson.build
new file mode 100644
index 0000000..04bb24f
--- /dev/null
+++ b/src/oem/ibm/meson.build
@@ -0,0 +1,5 @@
+libpldm_sources += files(
+ 'file_io.c',
+ 'host.c',
+ 'platform.c'
+ )
diff --git a/src/oem/ibm/platform.c b/src/oem/ibm/platform.c
new file mode 100644
index 0000000..15e9463
--- /dev/null
+++ b/src/oem/ibm/platform.c
@@ -0,0 +1,50 @@
+#include "libpldm/platform.h"
+#include "libpldm/platform_oem_ibm.h"
+#include <string.h>
+
+int encode_bios_attribute_update_event_req(uint8_t instance_id,
+ uint8_t format_version, uint8_t tid,
+ uint8_t num_handles,
+ const uint8_t *list_of_handles,
+ size_t payload_length,
+ struct pldm_msg *msg)
+{
+ if (format_version != 1) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (msg == NULL || list_of_handles == NULL) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (num_handles == 0) {
+ return PLDM_ERROR_INVALID_DATA;
+ }
+
+ if (payload_length !=
+ (PLDM_PLATFORM_EVENT_MESSAGE_MIN_REQ_BYTES + sizeof(num_handles) +
+ (num_handles * sizeof(uint16_t)))) {
+ 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_PLATFORM_EVENT_MESSAGE;
+ uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
+ if (rc != PLDM_SUCCESS) {
+ return rc;
+ }
+
+ struct pldm_bios_attribute_update_event_req *request =
+ (struct pldm_bios_attribute_update_event_req *)msg->payload;
+ request->format_version = format_version;
+ request->tid = tid;
+ request->event_class = PLDM_EVENT_TYPE_OEM_EVENT_BIOS_ATTRIBUTE_UPDATE;
+ request->num_handles = num_handles;
+ memcpy(request->bios_attribute_handles, list_of_handles,
+ num_handles * sizeof(uint16_t));
+
+ return PLDM_SUCCESS;
+}
diff --git a/src/pdr.c b/src/pdr.c
new file mode 100644
index 0000000..b057e3d
--- /dev/null
+++ b/src/pdr.c
@@ -0,0 +1,971 @@
+#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;
+ uint16_t terminus_handle;
+} pldm_pdr_record;
+
+typedef struct pldm_pdr {
+ uint32_t record_count;
+ uint32_t size;
+ pldm_pdr_record *first;
+ pldm_pdr_record *last;
+} pldm_pdr;
+
+static inline uint32_t get_next_record_handle(const pldm_pdr *repo,
+ const pldm_pdr_record *record)
+{
+ assert(repo != NULL);
+ assert(record != NULL);
+
+ if (record == repo->last) {
+ return 0;
+ }
+ return record->next->record_handle;
+}
+
+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,
+ uint16_t terminus_handle)
+{
+ 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;
+ record->terminus_handle = terminus_handle;
+ 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,
+ uint16_t terminus_handle)
+{
+ assert(size != 0);
+ assert(data != NULL);
+
+ pldm_pdr_record *record = make_new_record(
+ repo, data, size, record_handle, is_remote, terminus_handle);
+ 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,
+ terminus_handle);
+}
+
+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,
+ uint16_t terminus_handle)
+{
+ uint8_t pdr[size];
+ uint8_t *start = pdr;
+
+ struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
+ hdr->version = 1;
+ hdr->record_handle = 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, terminus_handle);
+}
+
+static void entity_association_pdr_add_entry(pldm_entity_node *curr,
+ pldm_pdr *repo, bool is_remote,
+ uint16_t terminus_handle)
+{
+ uint8_t num_logical_children =
+ pldm_entity_get_num_children(curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
+ uint8_t num_physical_children =
+ pldm_entity_get_num_children(curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
+
+ 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, terminus_handle);
+ }
+
+ 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,
+ terminus_handle);
+ }
+}
+
+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,
+ uint16_t terminus_handle)
+{
+ 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,
+ terminus_handle);
+ }
+ entity_association_pdr_add(curr->next_sibling, repo, entities,
+ num_entities, is_remote, terminus_handle);
+ entity_association_pdr_add(curr->first_child, repo, entities,
+ num_entities, is_remote, terminus_handle);
+}
+
+void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
+ pldm_pdr *repo, bool is_remote,
+ uint16_t terminus_handle)
+{
+ assert(tree != NULL);
+ assert(repo != NULL);
+
+ entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
+ terminus_handle);
+}
+
+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, uint16_t terminus_handle)
+{
+ assert(repo != NULL);
+
+ entity_association_pdr_add(node, repo, entities, num_entities,
+ is_remote, terminus_handle);
+}
+
+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_pdrs_by_terminus_handle(pldm_pdr *repo,
+ uint16_t terminus_handle)
+{
+ 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->terminus_handle == terminus_handle) {
+ if (repo->first == record) {
+ repo->first = next;
+ } else {
+ prev->next = next;
+ }
+ if (repo->last == record) {
+ repo->last = prev;
+ }
+ if (record->data) {
+ free(record->data);
+ }
+ --repo->record_count;
+ repo->size -= record->size;
+ free(record);
+ removed = true;
+ } else {
+ prev = record;
+ }
+ record = next;
+ }
+
+ if (removed == true) {
+ record = repo->first;
+ uint32_t record_handle = 0;
+ while (record != NULL) {
+ record->record_handle = ++record_handle;
+ if (record->data != NULL) {
+ struct pldm_pdr_hdr *hdr =
+ (struct pldm_pdr_hdr *)(record->data);
+ hdr->record_handle =
+ htole32(record->record_handle);
+ }
+ record = record->next;
+ }
+ }
+}
+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/src/platform.c b/src/platform.c
new file mode 100644
index 0000000..8b83747
--- /dev/null
+++ b/src/platform.c
@@ -0,0 +1,1703 @@
+#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;
+ }
+
+ *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/src/requester/meson.build b/src/requester/meson.build
new file mode 100644
index 0000000..6798d02
--- /dev/null
+++ b/src/requester/meson.build
@@ -0,0 +1,3 @@
+libpldm_sources += files(
+ 'pldm.c'
+ )
diff --git a/src/requester/pldm.c b/src/requester/pldm.c
new file mode 100644
index 0000000..932f55e
--- /dev/null
+++ b/src/requester/pldm.c
@@ -0,0 +1,188 @@
+#include "pldm.h"
+#include "base.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+const uint8_t MCTP_MSG_TYPE_PLDM = 1;
+
+pldm_requester_rc_t pldm_open()
+{
+ int fd = -1;
+ int rc = -1;
+
+ fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
+ if (-1 == fd) {
+ return fd;
+ }
+
+ const char path[] = "\0mctp-mux";
+ struct sockaddr_un addr;
+ addr.sun_family = AF_UNIX;
+ memcpy(addr.sun_path, path, sizeof(path) - 1);
+ rc = connect(fd, (struct sockaddr *)&addr,
+ sizeof(path) + sizeof(addr.sun_family) - 1);
+ if (-1 == rc) {
+ return PLDM_REQUESTER_OPEN_FAIL;
+ }
+ rc = write(fd, &MCTP_MSG_TYPE_PLDM, sizeof(MCTP_MSG_TYPE_PLDM));
+ if (-1 == rc) {
+ return PLDM_REQUESTER_OPEN_FAIL;
+ }
+
+ return fd;
+}
+
+/**
+ * @brief Read MCTP socket. If there's data available, return success only if
+ * data is a PLDM message.
+ *
+ * @param[in] eid - destination MCTP eid
+ * @param[in] mctp_fd - MCTP socket fd
+ * @param[out] pldm_resp_msg - *pldm_resp_msg will point to PLDM msg,
+ * this function allocates memory, caller to free(*pldm_resp_msg) on
+ * success.
+ * @param[out] resp_msg_len - caller owned pointer that will be made point to
+ * the size of the PLDM msg.
+ *
+ * @return pldm_requester_rc_t (errno may be set). failure is returned even
+ * when data was read, but wasn't a PLDM response message
+ */
+static pldm_requester_rc_t mctp_recv(mctp_eid_t eid, int mctp_fd,
+ uint8_t **pldm_resp_msg,
+ size_t *resp_msg_len)
+{
+ ssize_t min_len = sizeof(eid) + sizeof(MCTP_MSG_TYPE_PLDM) +
+ sizeof(struct pldm_msg_hdr);
+ ssize_t length = recv(mctp_fd, NULL, 0, MSG_PEEK | MSG_TRUNC);
+ if (length <= 0) {
+ return PLDM_REQUESTER_RECV_FAIL;
+ } else if (length < min_len) {
+ /* read and discard */
+ uint8_t buf[length];
+ recv(mctp_fd, buf, length, 0);
+ return PLDM_REQUESTER_INVALID_RECV_LEN;
+ } else {
+ struct iovec iov[2];
+ size_t mctp_prefix_len =
+ sizeof(eid) + sizeof(MCTP_MSG_TYPE_PLDM);
+ uint8_t mctp_prefix[mctp_prefix_len];
+ size_t pldm_len = length - mctp_prefix_len;
+ iov[0].iov_len = mctp_prefix_len;
+ iov[0].iov_base = mctp_prefix;
+ *pldm_resp_msg = malloc(pldm_len);
+ iov[1].iov_len = pldm_len;
+ iov[1].iov_base = *pldm_resp_msg;
+ struct msghdr msg = {0};
+ msg.msg_iov = iov;
+ msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]);
+ ssize_t bytes = recvmsg(mctp_fd, &msg, 0);
+ if (length != bytes) {
+ free(*pldm_resp_msg);
+ return PLDM_REQUESTER_INVALID_RECV_LEN;
+ }
+ if ((mctp_prefix[0] != eid) ||
+ (mctp_prefix[1] != MCTP_MSG_TYPE_PLDM)) {
+ free(*pldm_resp_msg);
+ return PLDM_REQUESTER_NOT_PLDM_MSG;
+ }
+ *resp_msg_len = pldm_len;
+ return PLDM_REQUESTER_SUCCESS;
+ }
+}
+
+pldm_requester_rc_t pldm_recv_any(mctp_eid_t eid, int mctp_fd,
+ uint8_t **pldm_resp_msg, size_t *resp_msg_len)
+{
+ pldm_requester_rc_t rc =
+ mctp_recv(eid, mctp_fd, pldm_resp_msg, resp_msg_len);
+ if (rc != PLDM_REQUESTER_SUCCESS) {
+ return rc;
+ }
+
+ struct pldm_msg_hdr *hdr = (struct pldm_msg_hdr *)(*pldm_resp_msg);
+ if (hdr->request != PLDM_RESPONSE) {
+ free(*pldm_resp_msg);
+ return PLDM_REQUESTER_NOT_RESP_MSG;
+ }
+
+ uint8_t pldm_rc = 0;
+ if (*resp_msg_len < (sizeof(struct pldm_msg_hdr) + sizeof(pldm_rc))) {
+ free(*pldm_resp_msg);
+ return PLDM_REQUESTER_RESP_MSG_TOO_SMALL;
+ }
+
+ return PLDM_REQUESTER_SUCCESS;
+}
+
+pldm_requester_rc_t pldm_recv(mctp_eid_t eid, int mctp_fd, uint8_t instance_id,
+ uint8_t **pldm_resp_msg, size_t *resp_msg_len)
+{
+ pldm_requester_rc_t rc =
+ pldm_recv_any(eid, mctp_fd, pldm_resp_msg, resp_msg_len);
+ if (rc != PLDM_REQUESTER_SUCCESS) {
+ return rc;
+ }
+
+ struct pldm_msg_hdr *hdr = (struct pldm_msg_hdr *)(*pldm_resp_msg);
+ if (hdr->instance_id != instance_id) {
+ free(*pldm_resp_msg);
+ return PLDM_REQUESTER_INSTANCE_ID_MISMATCH;
+ }
+
+ return PLDM_REQUESTER_SUCCESS;
+}
+
+pldm_requester_rc_t pldm_send_recv(mctp_eid_t eid, int mctp_fd,
+ const uint8_t *pldm_req_msg,
+ size_t req_msg_len, uint8_t **pldm_resp_msg,
+ size_t *resp_msg_len)
+{
+ struct pldm_msg_hdr *hdr = (struct pldm_msg_hdr *)pldm_req_msg;
+ if ((hdr->request != PLDM_REQUEST) &&
+ (hdr->request != PLDM_ASYNC_REQUEST_NOTIFY)) {
+ return PLDM_REQUESTER_NOT_REQ_MSG;
+ }
+
+ pldm_requester_rc_t rc =
+ pldm_send(eid, mctp_fd, pldm_req_msg, req_msg_len);
+ if (rc != PLDM_REQUESTER_SUCCESS) {
+ return rc;
+ }
+
+ while (1) {
+ rc = pldm_recv(eid, mctp_fd, hdr->instance_id, pldm_resp_msg,
+ resp_msg_len);
+ if (rc == PLDM_REQUESTER_SUCCESS) {
+ break;
+ }
+ }
+
+ return rc;
+}
+
+pldm_requester_rc_t pldm_send(mctp_eid_t eid, int mctp_fd,
+ const uint8_t *pldm_req_msg, size_t req_msg_len)
+{
+ uint8_t hdr[2] = {eid, MCTP_MSG_TYPE_PLDM};
+
+ struct iovec iov[2];
+ iov[0].iov_base = hdr;
+ iov[0].iov_len = sizeof(hdr);
+ iov[1].iov_base = (uint8_t *)pldm_req_msg;
+ iov[1].iov_len = req_msg_len;
+
+ struct msghdr msg = {0};
+ msg.msg_iov = iov;
+ msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]);
+
+ ssize_t rc = sendmsg(mctp_fd, &msg, 0);
+ if (rc == -1) {
+ return PLDM_REQUESTER_SEND_FAIL;
+ }
+ return PLDM_REQUESTER_SUCCESS;
+}
diff --git a/src/utils.c b/src/utils.c
new file mode 100644
index 0000000..0a1e33c
--- /dev/null
+++ b/src/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 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;
+ }
+}