xref: /openbmc/libpldm/src/dsp/fru.c (revision 36324f6bea8c5de1e380659bb56aca5e0b8724b4)
148761c62SAndrew Jeffery /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
248761c62SAndrew Jeffery #include <libpldm/base.h>
348761c62SAndrew Jeffery #include <libpldm/fru.h>
448761c62SAndrew Jeffery #include <libpldm/utils.h>
548761c62SAndrew Jeffery 
648761c62SAndrew Jeffery #include <assert.h>
748761c62SAndrew Jeffery #include <endian.h>
848761c62SAndrew Jeffery #include <stdbool.h>
948761c62SAndrew Jeffery #include <stdint.h>
1048761c62SAndrew Jeffery #include <string.h>
1148761c62SAndrew Jeffery 
1248761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
encode_get_fru_record_table_metadata_req(uint8_t instance_id,struct pldm_msg * msg,size_t payload_length)1348761c62SAndrew Jeffery int encode_get_fru_record_table_metadata_req(uint8_t instance_id,
1448761c62SAndrew Jeffery 					     struct pldm_msg *msg,
1548761c62SAndrew Jeffery 					     size_t payload_length)
1648761c62SAndrew Jeffery {
1748761c62SAndrew Jeffery 	if (msg == NULL) {
1848761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
1948761c62SAndrew Jeffery 	}
2048761c62SAndrew Jeffery 
2148761c62SAndrew Jeffery 	if (payload_length != PLDM_GET_FRU_RECORD_TABLE_METADATA_REQ_BYTES) {
2248761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
2348761c62SAndrew Jeffery 	}
2448761c62SAndrew Jeffery 
2548761c62SAndrew Jeffery 	struct pldm_header_info header = { 0 };
2648761c62SAndrew Jeffery 	header.instance = instance_id;
2748761c62SAndrew Jeffery 	header.msg_type = PLDM_REQUEST;
2848761c62SAndrew Jeffery 	header.pldm_type = PLDM_FRU;
2948761c62SAndrew Jeffery 	header.command = PLDM_GET_FRU_RECORD_TABLE_METADATA;
3048761c62SAndrew Jeffery 
3148761c62SAndrew Jeffery 	return pack_pldm_header(&header, &(msg->hdr));
3248761c62SAndrew Jeffery }
3348761c62SAndrew Jeffery 
3448761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
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)3548761c62SAndrew Jeffery int decode_get_fru_record_table_metadata_resp(
3648761c62SAndrew Jeffery 	const struct pldm_msg *msg, size_t payload_length,
3748761c62SAndrew Jeffery 	uint8_t *completion_code, uint8_t *fru_data_major_version,
3848761c62SAndrew Jeffery 	uint8_t *fru_data_minor_version, uint32_t *fru_table_maximum_size,
3948761c62SAndrew Jeffery 	uint32_t *fru_table_length, uint16_t *total_record_set_identifiers,
4048761c62SAndrew Jeffery 	uint16_t *total_table_records, uint32_t *checksum)
4148761c62SAndrew Jeffery {
4248761c62SAndrew Jeffery 	if (msg == NULL || completion_code == NULL ||
4348761c62SAndrew Jeffery 	    fru_data_major_version == NULL || fru_data_minor_version == NULL ||
4448761c62SAndrew Jeffery 	    fru_table_maximum_size == NULL || fru_table_length == NULL ||
4548761c62SAndrew Jeffery 	    total_record_set_identifiers == NULL ||
4648761c62SAndrew Jeffery 	    total_table_records == NULL || checksum == NULL) {
4748761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
4848761c62SAndrew Jeffery 	}
4948761c62SAndrew Jeffery 
5048761c62SAndrew Jeffery 	*completion_code = msg->payload[0];
5148761c62SAndrew Jeffery 	if (PLDM_SUCCESS != *completion_code) {
5248761c62SAndrew Jeffery 		return PLDM_SUCCESS;
5348761c62SAndrew Jeffery 	}
5448761c62SAndrew Jeffery 
5548761c62SAndrew Jeffery 	if (payload_length != PLDM_GET_FRU_RECORD_TABLE_METADATA_RESP_BYTES) {
5648761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
5748761c62SAndrew Jeffery 	}
5848761c62SAndrew Jeffery 
5948761c62SAndrew Jeffery 	struct pldm_get_fru_record_table_metadata_resp *response =
6048761c62SAndrew Jeffery 		(struct pldm_get_fru_record_table_metadata_resp *)msg->payload;
6148761c62SAndrew Jeffery 
6248761c62SAndrew Jeffery 	*fru_data_major_version = response->fru_data_major_version;
6348761c62SAndrew Jeffery 	*fru_data_minor_version = response->fru_data_minor_version;
6448761c62SAndrew Jeffery 	*fru_table_maximum_size = le32toh(response->fru_table_maximum_size);
6548761c62SAndrew Jeffery 	*fru_table_length = le32toh(response->fru_table_length);
6648761c62SAndrew Jeffery 	*total_record_set_identifiers =
6748761c62SAndrew Jeffery 		le16toh(response->total_record_set_identifiers);
6848761c62SAndrew Jeffery 	*total_table_records = le16toh(response->total_table_records);
6948761c62SAndrew Jeffery 	*checksum = le32toh(response->checksum);
7048761c62SAndrew Jeffery 
7148761c62SAndrew Jeffery 	return PLDM_SUCCESS;
7248761c62SAndrew Jeffery }
7348761c62SAndrew Jeffery 
7448761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
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)7548761c62SAndrew Jeffery int encode_get_fru_record_table_metadata_resp(
7648761c62SAndrew Jeffery 	uint8_t instance_id, uint8_t completion_code,
7748761c62SAndrew Jeffery 	uint8_t fru_data_major_version, uint8_t fru_data_minor_version,
7848761c62SAndrew Jeffery 	uint32_t fru_table_maximum_size, uint32_t fru_table_length,
7948761c62SAndrew Jeffery 	uint16_t total_record_set_identifiers, uint16_t total_table_records,
8048761c62SAndrew Jeffery 	uint32_t checksum, struct pldm_msg *msg)
8148761c62SAndrew Jeffery {
8248761c62SAndrew Jeffery 	if (msg == NULL) {
8348761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
8448761c62SAndrew Jeffery 	}
8548761c62SAndrew Jeffery 
8648761c62SAndrew Jeffery 	struct pldm_header_info header = { 0 };
8748761c62SAndrew Jeffery 	header.msg_type = PLDM_RESPONSE;
8848761c62SAndrew Jeffery 	header.instance = instance_id;
8948761c62SAndrew Jeffery 	header.pldm_type = PLDM_FRU;
9048761c62SAndrew Jeffery 	header.command = PLDM_GET_FRU_RECORD_TABLE_METADATA;
9148761c62SAndrew Jeffery 
9248761c62SAndrew Jeffery 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
9348761c62SAndrew Jeffery 	if (PLDM_SUCCESS != rc) {
9448761c62SAndrew Jeffery 		return rc;
9548761c62SAndrew Jeffery 	}
9648761c62SAndrew Jeffery 
9748761c62SAndrew Jeffery 	struct pldm_get_fru_record_table_metadata_resp *response =
9848761c62SAndrew Jeffery 		(struct pldm_get_fru_record_table_metadata_resp *)msg->payload;
9948761c62SAndrew Jeffery 	response->completion_code = completion_code;
10048761c62SAndrew Jeffery 	if (response->completion_code == PLDM_SUCCESS) {
10148761c62SAndrew Jeffery 		response->fru_data_major_version = fru_data_major_version;
10248761c62SAndrew Jeffery 		response->fru_data_minor_version = fru_data_minor_version;
10348761c62SAndrew Jeffery 		response->fru_table_maximum_size =
10448761c62SAndrew Jeffery 			htole32(fru_table_maximum_size);
10548761c62SAndrew Jeffery 		response->fru_table_length = htole32(fru_table_length);
10648761c62SAndrew Jeffery 		response->total_record_set_identifiers =
10748761c62SAndrew Jeffery 			htole16(total_record_set_identifiers);
10848761c62SAndrew Jeffery 		response->total_table_records = htole16(total_table_records);
10948761c62SAndrew Jeffery 		response->checksum = htole32(checksum);
11048761c62SAndrew Jeffery 	}
11148761c62SAndrew Jeffery 
11248761c62SAndrew Jeffery 	return PLDM_SUCCESS;
11348761c62SAndrew Jeffery }
11448761c62SAndrew Jeffery 
11548761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
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)11648761c62SAndrew Jeffery int decode_get_fru_record_table_req(const struct pldm_msg *msg,
11748761c62SAndrew Jeffery 				    size_t payload_length,
11848761c62SAndrew Jeffery 				    uint32_t *data_transfer_handle,
11948761c62SAndrew Jeffery 				    uint8_t *transfer_operation_flag)
12048761c62SAndrew Jeffery {
12148761c62SAndrew Jeffery 	if (msg == NULL || data_transfer_handle == NULL ||
12248761c62SAndrew Jeffery 	    transfer_operation_flag == NULL) {
12348761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
12448761c62SAndrew Jeffery 	}
12548761c62SAndrew Jeffery 
12648761c62SAndrew Jeffery 	if (payload_length != PLDM_GET_FRU_RECORD_TABLE_REQ_BYTES) {
12748761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
12848761c62SAndrew Jeffery 	}
12948761c62SAndrew Jeffery 
13048761c62SAndrew Jeffery 	struct pldm_get_fru_record_table_req *req =
13148761c62SAndrew Jeffery 		(struct pldm_get_fru_record_table_req *)msg->payload;
13248761c62SAndrew Jeffery 
13348761c62SAndrew Jeffery 	*data_transfer_handle = le32toh(req->data_transfer_handle);
13448761c62SAndrew Jeffery 	*transfer_operation_flag = req->transfer_operation_flag;
13548761c62SAndrew Jeffery 
13648761c62SAndrew Jeffery 	return PLDM_SUCCESS;
13748761c62SAndrew Jeffery }
13848761c62SAndrew Jeffery 
13948761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
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)14048761c62SAndrew Jeffery int encode_get_fru_record_table_resp(uint8_t instance_id,
14148761c62SAndrew Jeffery 				     uint8_t completion_code,
14248761c62SAndrew Jeffery 				     uint32_t next_data_transfer_handle,
14348761c62SAndrew Jeffery 				     uint8_t transfer_flag,
14448761c62SAndrew Jeffery 				     struct pldm_msg *msg)
14548761c62SAndrew Jeffery {
14648761c62SAndrew Jeffery 	if (msg == NULL) {
14748761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
14848761c62SAndrew Jeffery 	}
14948761c62SAndrew Jeffery 
15048761c62SAndrew Jeffery 	struct pldm_header_info header = { 0 };
15148761c62SAndrew Jeffery 	header.msg_type = PLDM_RESPONSE;
15248761c62SAndrew Jeffery 	header.instance = instance_id;
15348761c62SAndrew Jeffery 	header.pldm_type = PLDM_FRU;
15448761c62SAndrew Jeffery 	header.command = PLDM_GET_FRU_RECORD_TABLE;
15548761c62SAndrew Jeffery 
15648761c62SAndrew Jeffery 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
15748761c62SAndrew Jeffery 	if (rc > PLDM_SUCCESS) {
15848761c62SAndrew Jeffery 		return rc;
15948761c62SAndrew Jeffery 	}
16048761c62SAndrew Jeffery 
16148761c62SAndrew Jeffery 	struct pldm_get_fru_record_table_resp *resp =
16248761c62SAndrew Jeffery 		(struct pldm_get_fru_record_table_resp *)msg->payload;
16348761c62SAndrew Jeffery 
16448761c62SAndrew Jeffery 	resp->completion_code = completion_code;
16548761c62SAndrew Jeffery 
16648761c62SAndrew Jeffery 	if (resp->completion_code == PLDM_SUCCESS) {
16748761c62SAndrew Jeffery 		resp->next_data_transfer_handle =
16848761c62SAndrew Jeffery 			htole32(next_data_transfer_handle);
16948761c62SAndrew Jeffery 		resp->transfer_flag = transfer_flag;
17048761c62SAndrew Jeffery 	}
17148761c62SAndrew Jeffery 
17248761c62SAndrew Jeffery 	return PLDM_SUCCESS;
17348761c62SAndrew Jeffery }
17448761c62SAndrew Jeffery 
175*36324f6bSAndrew Jeffery LIBPLDM_ABI_DEPRECATED_UNSAFE
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)17648761c62SAndrew Jeffery int encode_fru_record(uint8_t *fru_table, size_t total_size, size_t *curr_size,
17748761c62SAndrew Jeffery 		      uint16_t record_set_id, uint8_t record_type,
17848761c62SAndrew Jeffery 		      uint8_t num_frus, uint8_t encoding, uint8_t *tlvs,
17948761c62SAndrew Jeffery 		      size_t tlvs_size)
18048761c62SAndrew Jeffery {
18148761c62SAndrew Jeffery 	size_t record_hdr_size = sizeof(struct pldm_fru_record_data_format) -
18248761c62SAndrew Jeffery 				 sizeof(struct pldm_fru_record_tlv);
18348761c62SAndrew Jeffery 
18448761c62SAndrew Jeffery 	if (fru_table == NULL || curr_size == NULL || !tlvs_size) {
18548761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
18648761c62SAndrew Jeffery 	}
187d7d08f65SAndrew Jeffery 
188d7d08f65SAndrew Jeffery 	if (SIZE_MAX - *curr_size < record_hdr_size) {
189d7d08f65SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
190d7d08f65SAndrew Jeffery 	}
191d7d08f65SAndrew Jeffery 
192d7d08f65SAndrew Jeffery 	if (SIZE_MAX - (*curr_size + record_hdr_size) < tlvs_size) {
193d7d08f65SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
194d7d08f65SAndrew Jeffery 	}
195d7d08f65SAndrew Jeffery 
196d7d08f65SAndrew Jeffery 	if (total_size < *curr_size + record_hdr_size) {
197d7d08f65SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
198d7d08f65SAndrew Jeffery 	}
199d7d08f65SAndrew Jeffery 
200d7d08f65SAndrew Jeffery 	if (total_size - (*curr_size + record_hdr_size) < tlvs_size) {
20148761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
20248761c62SAndrew Jeffery 	}
20348761c62SAndrew Jeffery 
20448761c62SAndrew Jeffery 	struct pldm_fru_record_data_format *record =
20548761c62SAndrew Jeffery 		(struct pldm_fru_record_data_format *)(fru_table + *curr_size);
20648761c62SAndrew Jeffery 	record->record_set_id = htole16(record_set_id);
20748761c62SAndrew Jeffery 	record->record_type = record_type;
20848761c62SAndrew Jeffery 	record->num_fru_fields = num_frus;
20948761c62SAndrew Jeffery 	record->encoding_type = encoding;
21048761c62SAndrew Jeffery 	*curr_size += record_hdr_size;
21148761c62SAndrew Jeffery 
21248761c62SAndrew Jeffery 	if (tlvs) {
21348761c62SAndrew Jeffery 		memcpy(fru_table + *curr_size, tlvs, tlvs_size);
21448761c62SAndrew Jeffery 		*curr_size += tlvs_size;
21548761c62SAndrew Jeffery 	}
21648761c62SAndrew Jeffery 
21748761c62SAndrew Jeffery 	return PLDM_SUCCESS;
21848761c62SAndrew Jeffery }
21948761c62SAndrew Jeffery 
is_table_end(const struct pldm_fru_record_data_format * p,const void * table,size_t table_size)22048761c62SAndrew Jeffery static bool is_table_end(const struct pldm_fru_record_data_format *p,
22148761c62SAndrew Jeffery 			 const void *table, size_t table_size)
22248761c62SAndrew Jeffery {
22348761c62SAndrew Jeffery 	return p >=
22448761c62SAndrew Jeffery 	       (const struct pldm_fru_record_data_format *)((uint8_t *)table +
22548761c62SAndrew Jeffery 							    table_size);
22648761c62SAndrew Jeffery }
22748761c62SAndrew Jeffery 
22848761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
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)229d9b70ba7SAndrew Jeffery int get_fru_record_by_option(const uint8_t *table, size_t table_size,
23048761c62SAndrew Jeffery 			     uint8_t *record_table, size_t *record_size,
23148761c62SAndrew Jeffery 			     uint16_t rsi, uint8_t rt, uint8_t ft)
23248761c62SAndrew Jeffery {
23348761c62SAndrew Jeffery 	const struct pldm_fru_record_data_format *record_data_src =
23448761c62SAndrew Jeffery 		(const struct pldm_fru_record_data_format *)table;
23548761c62SAndrew Jeffery 	struct pldm_fru_record_data_format *record_data_dest;
23648761c62SAndrew Jeffery 	int count = 0;
23748761c62SAndrew Jeffery 
23848761c62SAndrew Jeffery 	const struct pldm_fru_record_tlv *tlv;
23948761c62SAndrew Jeffery 	size_t len;
24048761c62SAndrew Jeffery 	uint8_t *pos = record_table;
24148761c62SAndrew Jeffery 
24248761c62SAndrew Jeffery 	while (!is_table_end(record_data_src, table, table_size)) {
24348761c62SAndrew Jeffery 		if ((record_data_src->record_set_id != htole16(rsi) &&
24448761c62SAndrew Jeffery 		     rsi != 0) ||
24548761c62SAndrew Jeffery 		    (record_data_src->record_type != rt && rt != 0)) {
24648761c62SAndrew Jeffery 			tlv = record_data_src->tlvs;
24748761c62SAndrew Jeffery 			for (int i = 0; i < record_data_src->num_fru_fields;
24848761c62SAndrew Jeffery 			     i++) {
24948761c62SAndrew Jeffery 				len = sizeof(*tlv) - 1 + tlv->length;
25048761c62SAndrew Jeffery 				tlv = (const struct pldm_fru_record_tlv
25148761c62SAndrew Jeffery 					       *)((char *)tlv + len);
25248761c62SAndrew Jeffery 			}
25348761c62SAndrew Jeffery 			record_data_src =
25448761c62SAndrew Jeffery 				(const struct pldm_fru_record_data_format
25548761c62SAndrew Jeffery 					 *)(tlv);
25648761c62SAndrew Jeffery 			continue;
25748761c62SAndrew Jeffery 		}
25848761c62SAndrew Jeffery 
25948761c62SAndrew Jeffery 		len = sizeof(struct pldm_fru_record_data_format) -
26048761c62SAndrew Jeffery 		      sizeof(struct pldm_fru_record_tlv);
26148761c62SAndrew Jeffery 
26248761c62SAndrew Jeffery 		if (pos - record_table + len >= *record_size) {
26348761c62SAndrew Jeffery 			return PLDM_ERROR_INVALID_LENGTH;
26448761c62SAndrew Jeffery 		}
26548761c62SAndrew Jeffery 		memcpy(pos, record_data_src, len);
26648761c62SAndrew Jeffery 
26748761c62SAndrew Jeffery 		record_data_dest = (struct pldm_fru_record_data_format *)pos;
26848761c62SAndrew Jeffery 		pos += len;
26948761c62SAndrew Jeffery 
27048761c62SAndrew Jeffery 		tlv = record_data_src->tlvs;
27148761c62SAndrew Jeffery 		count = 0;
27248761c62SAndrew Jeffery 		for (int i = 0; i < record_data_src->num_fru_fields; i++) {
27348761c62SAndrew Jeffery 			len = sizeof(*tlv) - 1 + tlv->length;
27448761c62SAndrew Jeffery 			if (tlv->type == ft || ft == 0) {
27548761c62SAndrew Jeffery 				if (pos - record_table + len >= *record_size) {
27648761c62SAndrew Jeffery 					return PLDM_ERROR_INVALID_LENGTH;
27748761c62SAndrew Jeffery 				}
27848761c62SAndrew Jeffery 				memcpy(pos, tlv, len);
27948761c62SAndrew Jeffery 				pos += len;
28048761c62SAndrew Jeffery 				count++;
28148761c62SAndrew Jeffery 			}
28248761c62SAndrew Jeffery 			tlv = (const struct pldm_fru_record_tlv *)((char *)tlv +
28348761c62SAndrew Jeffery 								   len);
28448761c62SAndrew Jeffery 		}
28548761c62SAndrew Jeffery 		record_data_dest->num_fru_fields = count;
28648761c62SAndrew Jeffery 		record_data_src =
28748761c62SAndrew Jeffery 			(const struct pldm_fru_record_data_format *)(tlv);
28848761c62SAndrew Jeffery 	}
28948761c62SAndrew Jeffery 
29048761c62SAndrew Jeffery 	*record_size = pos - record_table;
29148761c62SAndrew Jeffery 
29248761c62SAndrew Jeffery 	return PLDM_SUCCESS;
29348761c62SAndrew Jeffery }
29448761c62SAndrew Jeffery 
29548761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
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)29648761c62SAndrew Jeffery int encode_get_fru_record_by_option_req(
29748761c62SAndrew Jeffery 	uint8_t instance_id, uint32_t data_transfer_handle,
29848761c62SAndrew Jeffery 	uint16_t fru_table_handle, uint16_t record_set_identifier,
29948761c62SAndrew Jeffery 	uint8_t record_type, uint8_t field_type, uint8_t transfer_op_flag,
30048761c62SAndrew Jeffery 	struct pldm_msg *msg, size_t payload_length)
30148761c62SAndrew Jeffery {
30248761c62SAndrew Jeffery 	if (msg == NULL) {
30348761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
30448761c62SAndrew Jeffery 	}
30548761c62SAndrew Jeffery 
30648761c62SAndrew Jeffery 	if (payload_length !=
30748761c62SAndrew Jeffery 	    sizeof(struct pldm_get_fru_record_by_option_req)) {
30848761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
30948761c62SAndrew Jeffery 	}
31048761c62SAndrew Jeffery 
31148761c62SAndrew Jeffery 	struct pldm_header_info header = { 0 };
31248761c62SAndrew Jeffery 	header.instance = instance_id;
31348761c62SAndrew Jeffery 	header.msg_type = PLDM_REQUEST;
31448761c62SAndrew Jeffery 	header.pldm_type = PLDM_FRU;
31548761c62SAndrew Jeffery 	header.command = PLDM_GET_FRU_RECORD_BY_OPTION;
31648761c62SAndrew Jeffery 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
31748761c62SAndrew Jeffery 	if (rc != PLDM_SUCCESS) {
31848761c62SAndrew Jeffery 		return rc;
31948761c62SAndrew Jeffery 	}
32048761c62SAndrew Jeffery 
32148761c62SAndrew Jeffery 	struct pldm_get_fru_record_by_option_req *req =
32248761c62SAndrew Jeffery 		(struct pldm_get_fru_record_by_option_req *)msg->payload;
32348761c62SAndrew Jeffery 
32448761c62SAndrew Jeffery 	req->data_transfer_handle = htole32(data_transfer_handle);
32548761c62SAndrew Jeffery 	req->fru_table_handle = htole16(fru_table_handle);
32648761c62SAndrew Jeffery 	req->record_set_identifier = htole16(record_set_identifier);
32748761c62SAndrew Jeffery 	req->record_type = record_type;
32848761c62SAndrew Jeffery 	req->field_type = field_type;
32948761c62SAndrew Jeffery 	req->transfer_op_flag = transfer_op_flag;
33048761c62SAndrew Jeffery 
33148761c62SAndrew Jeffery 	return PLDM_SUCCESS;
33248761c62SAndrew Jeffery }
33348761c62SAndrew Jeffery 
33448761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
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)33548761c62SAndrew Jeffery int decode_get_fru_record_by_option_req(
33648761c62SAndrew Jeffery 	const struct pldm_msg *msg, size_t payload_length,
33748761c62SAndrew Jeffery 	uint32_t *data_transfer_handle, uint16_t *fru_table_handle,
33848761c62SAndrew Jeffery 	uint16_t *record_set_identifier, uint8_t *record_type,
33948761c62SAndrew Jeffery 	uint8_t *field_type, uint8_t *transfer_op_flag)
34048761c62SAndrew Jeffery {
34148761c62SAndrew Jeffery 	if (msg == NULL || data_transfer_handle == NULL ||
34248761c62SAndrew Jeffery 	    fru_table_handle == NULL || record_set_identifier == NULL ||
34348761c62SAndrew Jeffery 	    record_type == NULL || field_type == NULL ||
34448761c62SAndrew Jeffery 	    transfer_op_flag == NULL) {
34548761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
34648761c62SAndrew Jeffery 	}
34748761c62SAndrew Jeffery 
34848761c62SAndrew Jeffery 	if (payload_length !=
34948761c62SAndrew Jeffery 	    sizeof(struct pldm_get_fru_record_by_option_req)) {
35048761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
35148761c62SAndrew Jeffery 	}
35248761c62SAndrew Jeffery 
35348761c62SAndrew Jeffery 	struct pldm_get_fru_record_by_option_req *req =
35448761c62SAndrew Jeffery 		(struct pldm_get_fru_record_by_option_req *)msg->payload;
35548761c62SAndrew Jeffery 
35648761c62SAndrew Jeffery 	*data_transfer_handle = le32toh(req->data_transfer_handle);
35748761c62SAndrew Jeffery 	*fru_table_handle = le16toh(req->fru_table_handle);
35848761c62SAndrew Jeffery 	*record_set_identifier = le16toh(req->record_set_identifier);
35948761c62SAndrew Jeffery 	*record_type = req->record_type;
36048761c62SAndrew Jeffery 	*field_type = req->field_type;
36148761c62SAndrew Jeffery 	*transfer_op_flag = req->transfer_op_flag;
36248761c62SAndrew Jeffery 	return PLDM_SUCCESS;
36348761c62SAndrew Jeffery }
36448761c62SAndrew Jeffery 
36548761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
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)36648761c62SAndrew Jeffery int encode_get_fru_record_by_option_resp(uint8_t instance_id,
36748761c62SAndrew Jeffery 					 uint8_t completion_code,
36848761c62SAndrew Jeffery 					 uint32_t next_data_transfer_handle,
36948761c62SAndrew Jeffery 					 uint8_t transfer_flag,
37048761c62SAndrew Jeffery 					 const void *fru_structure_data,
37148761c62SAndrew Jeffery 					 size_t data_size, struct pldm_msg *msg,
37248761c62SAndrew Jeffery 					 size_t payload_length)
37348761c62SAndrew Jeffery {
37448761c62SAndrew Jeffery 	if (msg == NULL || fru_structure_data == NULL) {
37548761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
37648761c62SAndrew Jeffery 	}
37748761c62SAndrew Jeffery 
37882c34815SAndrew Jeffery 	if (payload_length < PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES) {
37982c34815SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
38082c34815SAndrew Jeffery 	}
38182c34815SAndrew Jeffery 
38282c34815SAndrew Jeffery 	if (payload_length - PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES <
38382c34815SAndrew Jeffery 	    data_size) {
38448761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
38548761c62SAndrew Jeffery 	}
38648761c62SAndrew Jeffery 
38748761c62SAndrew Jeffery 	struct pldm_header_info header = { 0 };
38848761c62SAndrew Jeffery 	header.instance = instance_id;
38948761c62SAndrew Jeffery 	header.msg_type = PLDM_RESPONSE;
39048761c62SAndrew Jeffery 	header.pldm_type = PLDM_FRU;
39148761c62SAndrew Jeffery 	header.command = PLDM_GET_FRU_RECORD_BY_OPTION;
39248761c62SAndrew Jeffery 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
39348761c62SAndrew Jeffery 	if (rc != PLDM_SUCCESS) {
39448761c62SAndrew Jeffery 		return rc;
39548761c62SAndrew Jeffery 	}
39648761c62SAndrew Jeffery 
39748761c62SAndrew Jeffery 	struct pldm_get_fru_record_by_option_resp *resp =
39848761c62SAndrew Jeffery 		(struct pldm_get_fru_record_by_option_resp *)msg->payload;
39948761c62SAndrew Jeffery 
40048761c62SAndrew Jeffery 	resp->completion_code = completion_code;
40148761c62SAndrew Jeffery 	resp->next_data_transfer_handle = htole32(next_data_transfer_handle);
40248761c62SAndrew Jeffery 	resp->transfer_flag = transfer_flag;
40348761c62SAndrew Jeffery 
40448761c62SAndrew Jeffery 	if (completion_code == PLDM_SUCCESS) {
40548761c62SAndrew Jeffery 		memcpy(resp->fru_structure_data, fru_structure_data, data_size);
40648761c62SAndrew Jeffery 	}
40748761c62SAndrew Jeffery 
40848761c62SAndrew Jeffery 	return PLDM_SUCCESS;
40948761c62SAndrew Jeffery }
41048761c62SAndrew Jeffery 
41148761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
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)41248761c62SAndrew Jeffery int decode_get_fru_record_by_option_resp(
41348761c62SAndrew Jeffery 	const struct pldm_msg *msg, size_t payload_length,
41448761c62SAndrew Jeffery 	uint8_t *completion_code, uint32_t *next_transfer_handle,
41548761c62SAndrew Jeffery 	uint8_t *transfer_flag, struct variable_field *fru_structure_data)
41648761c62SAndrew Jeffery {
41748761c62SAndrew Jeffery 	if (msg == NULL || completion_code == NULL ||
41848761c62SAndrew Jeffery 	    next_transfer_handle == NULL || transfer_flag == NULL ||
41948761c62SAndrew Jeffery 	    fru_structure_data == NULL) {
42048761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
42148761c62SAndrew Jeffery 	}
42248761c62SAndrew Jeffery 
42348761c62SAndrew Jeffery 	*completion_code = msg->payload[0];
42448761c62SAndrew Jeffery 	if (PLDM_SUCCESS != *completion_code) {
42548761c62SAndrew Jeffery 		return PLDM_SUCCESS;
42648761c62SAndrew Jeffery 	}
42748761c62SAndrew Jeffery 
42848761c62SAndrew Jeffery 	if (payload_length < PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES) {
42948761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
43048761c62SAndrew Jeffery 	}
43148761c62SAndrew Jeffery 
43248761c62SAndrew Jeffery 	struct pldm_get_fru_record_by_option_resp *resp =
43348761c62SAndrew Jeffery 		(struct pldm_get_fru_record_by_option_resp *)msg->payload;
43448761c62SAndrew Jeffery 
43548761c62SAndrew Jeffery 	*next_transfer_handle = le32toh(resp->next_data_transfer_handle);
43648761c62SAndrew Jeffery 	*transfer_flag = resp->transfer_flag;
43748761c62SAndrew Jeffery 	fru_structure_data->ptr = resp->fru_structure_data;
43848761c62SAndrew Jeffery 	fru_structure_data->length =
43948761c62SAndrew Jeffery 		payload_length - PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES;
44048761c62SAndrew Jeffery 
44148761c62SAndrew Jeffery 	return PLDM_SUCCESS;
44248761c62SAndrew Jeffery }
44348761c62SAndrew Jeffery 
44448761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
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)44548761c62SAndrew Jeffery int encode_get_fru_record_table_req(uint8_t instance_id,
44648761c62SAndrew Jeffery 				    uint32_t data_transfer_handle,
44748761c62SAndrew Jeffery 				    uint8_t transfer_operation_flag,
44848761c62SAndrew Jeffery 				    struct pldm_msg *msg, size_t payload_length)
44948761c62SAndrew Jeffery 
45048761c62SAndrew Jeffery {
45148761c62SAndrew Jeffery 	if (msg == NULL) {
45248761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
45348761c62SAndrew Jeffery 	}
45448761c62SAndrew Jeffery 	if (payload_length != sizeof(struct pldm_get_fru_record_table_req)) {
45548761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
45648761c62SAndrew Jeffery 	}
45748761c62SAndrew Jeffery 
45848761c62SAndrew Jeffery 	struct pldm_header_info header = { 0 };
45948761c62SAndrew Jeffery 	header.msg_type = PLDM_REQUEST;
46048761c62SAndrew Jeffery 	header.instance = instance_id;
46148761c62SAndrew Jeffery 	header.pldm_type = PLDM_FRU;
46248761c62SAndrew Jeffery 	header.command = PLDM_GET_FRU_RECORD_TABLE;
46348761c62SAndrew Jeffery 
46448761c62SAndrew Jeffery 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
46548761c62SAndrew Jeffery 	if (rc != PLDM_SUCCESS) {
46648761c62SAndrew Jeffery 		return rc;
46748761c62SAndrew Jeffery 	}
46848761c62SAndrew Jeffery 
46948761c62SAndrew Jeffery 	struct pldm_get_fru_record_table_req *req =
47048761c62SAndrew Jeffery 		(struct pldm_get_fru_record_table_req *)msg->payload;
47148761c62SAndrew Jeffery 	req->data_transfer_handle = htole32(data_transfer_handle);
47248761c62SAndrew Jeffery 	req->transfer_operation_flag = transfer_operation_flag;
47348761c62SAndrew Jeffery 
47448761c62SAndrew Jeffery 	return PLDM_SUCCESS;
47548761c62SAndrew Jeffery }
47648761c62SAndrew Jeffery 
47748761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
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)47848761c62SAndrew Jeffery int decode_get_fru_record_table_resp_safe(
47948761c62SAndrew Jeffery 	const struct pldm_msg *msg, size_t payload_length,
48048761c62SAndrew Jeffery 	uint8_t *completion_code, uint32_t *next_data_transfer_handle,
48148761c62SAndrew Jeffery 	uint8_t *transfer_flag, uint8_t *fru_record_table_data,
48248761c62SAndrew Jeffery 	size_t *fru_record_table_length, size_t max_fru_record_table_length)
48348761c62SAndrew Jeffery {
48448761c62SAndrew Jeffery 	if (msg == NULL || completion_code == NULL ||
48548761c62SAndrew Jeffery 	    next_data_transfer_handle == NULL || transfer_flag == NULL ||
48648761c62SAndrew Jeffery 	    fru_record_table_data == NULL || fru_record_table_length == NULL) {
48748761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
48848761c62SAndrew Jeffery 	}
48948761c62SAndrew Jeffery 
49048761c62SAndrew Jeffery 	*completion_code = msg->payload[0];
49148761c62SAndrew Jeffery 	if (PLDM_SUCCESS != *completion_code) {
49248761c62SAndrew Jeffery 		return PLDM_SUCCESS;
49348761c62SAndrew Jeffery 	}
49448761c62SAndrew Jeffery 	if (payload_length <= PLDM_GET_FRU_RECORD_TABLE_MIN_RESP_BYTES) {
49548761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
49648761c62SAndrew Jeffery 	}
49748761c62SAndrew Jeffery 
49848761c62SAndrew Jeffery 	struct pldm_get_fru_record_table_resp *resp =
49948761c62SAndrew Jeffery 		(struct pldm_get_fru_record_table_resp *)msg->payload;
50048761c62SAndrew Jeffery 
50148761c62SAndrew Jeffery 	*next_data_transfer_handle = le32toh(resp->next_data_transfer_handle);
50248761c62SAndrew Jeffery 	*transfer_flag = resp->transfer_flag;
50348761c62SAndrew Jeffery 
50448761c62SAndrew Jeffery 	*fru_record_table_length =
50548761c62SAndrew Jeffery 		payload_length - PLDM_GET_FRU_RECORD_TABLE_MIN_RESP_BYTES;
50648761c62SAndrew Jeffery 
50748761c62SAndrew Jeffery 	if (*fru_record_table_length > max_fru_record_table_length) {
50848761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
50948761c62SAndrew Jeffery 	}
51048761c62SAndrew Jeffery 
51148761c62SAndrew Jeffery 	memcpy(fru_record_table_data, resp->fru_record_table_data,
51248761c62SAndrew Jeffery 	       *fru_record_table_length);
51348761c62SAndrew Jeffery 
51448761c62SAndrew Jeffery 	return PLDM_SUCCESS;
51548761c62SAndrew Jeffery }
51648761c62SAndrew Jeffery 
51748761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
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)51848761c62SAndrew Jeffery int decode_get_fru_record_table_resp(const struct pldm_msg *msg,
51948761c62SAndrew Jeffery 				     size_t payload_length,
52048761c62SAndrew Jeffery 				     uint8_t *completion_code,
52148761c62SAndrew Jeffery 				     uint32_t *next_data_transfer_handle,
52248761c62SAndrew Jeffery 				     uint8_t *transfer_flag,
52348761c62SAndrew Jeffery 				     uint8_t *fru_record_table_data,
52448761c62SAndrew Jeffery 				     size_t *fru_record_table_length)
52548761c62SAndrew Jeffery {
52648761c62SAndrew Jeffery 	return decode_get_fru_record_table_resp_safe(
52748761c62SAndrew Jeffery 		msg, payload_length, completion_code, next_data_transfer_handle,
52848761c62SAndrew Jeffery 		transfer_flag, fru_record_table_data, fru_record_table_length,
52948761c62SAndrew Jeffery 		(size_t)-1);
53048761c62SAndrew Jeffery }
53148761c62SAndrew Jeffery 
53248761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
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)53348761c62SAndrew Jeffery int decode_set_fru_record_table_req(const struct pldm_msg *msg,
53448761c62SAndrew Jeffery 				    size_t payload_length,
53548761c62SAndrew Jeffery 				    uint32_t *data_transfer_handle,
53648761c62SAndrew Jeffery 				    uint8_t *transfer_flag,
53748761c62SAndrew Jeffery 				    struct variable_field *fru_table_data)
53848761c62SAndrew Jeffery 
53948761c62SAndrew Jeffery {
54048761c62SAndrew Jeffery 	if (msg == NULL || data_transfer_handle == NULL ||
54148761c62SAndrew Jeffery 	    transfer_flag == NULL || fru_table_data == NULL) {
54248761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
54348761c62SAndrew Jeffery 	}
54448761c62SAndrew Jeffery 
54548761c62SAndrew Jeffery 	if (payload_length <= PLDM_SET_FRU_RECORD_TABLE_MIN_REQ_BYTES) {
54648761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
54748761c62SAndrew Jeffery 	}
54848761c62SAndrew Jeffery 
54948761c62SAndrew Jeffery 	struct pldm_set_fru_record_table_req *req =
55048761c62SAndrew Jeffery 		(struct pldm_set_fru_record_table_req *)msg->payload;
55148761c62SAndrew Jeffery 
55248761c62SAndrew Jeffery 	*data_transfer_handle = le32toh(req->data_transfer_handle);
55348761c62SAndrew Jeffery 	*transfer_flag = req->transfer_flag;
55448761c62SAndrew Jeffery 	fru_table_data->length =
55548761c62SAndrew Jeffery 		payload_length - PLDM_SET_FRU_RECORD_TABLE_MIN_REQ_BYTES;
55648761c62SAndrew Jeffery 	fru_table_data->ptr = req->fru_record_table_data;
55748761c62SAndrew Jeffery 
55848761c62SAndrew Jeffery 	return PLDM_SUCCESS;
55948761c62SAndrew Jeffery }
56048761c62SAndrew Jeffery 
56148761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
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)56248761c62SAndrew Jeffery int encode_set_fru_record_table_resp(uint8_t instance_id,
56348761c62SAndrew Jeffery 				     uint8_t completion_code,
56448761c62SAndrew Jeffery 				     uint32_t next_data_transfer_handle,
56548761c62SAndrew Jeffery 				     size_t payload_length,
56648761c62SAndrew Jeffery 				     struct pldm_msg *msg)
56748761c62SAndrew Jeffery {
56848761c62SAndrew Jeffery 	if (msg == NULL) {
56948761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_DATA;
57048761c62SAndrew Jeffery 	}
57148761c62SAndrew Jeffery 	if (payload_length != PLDM_SET_FRU_RECORD_TABLE_RESP_BYTES) {
57248761c62SAndrew Jeffery 		return PLDM_ERROR_INVALID_LENGTH;
57348761c62SAndrew Jeffery 	}
57448761c62SAndrew Jeffery 
57548761c62SAndrew Jeffery 	struct pldm_header_info header = { 0 };
57648761c62SAndrew Jeffery 	header.instance = instance_id;
57748761c62SAndrew Jeffery 	header.msg_type = PLDM_RESPONSE;
57848761c62SAndrew Jeffery 	header.pldm_type = PLDM_FRU;
57948761c62SAndrew Jeffery 	header.command = PLDM_SET_FRU_RECORD_TABLE;
58048761c62SAndrew Jeffery 
58148761c62SAndrew Jeffery 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
58248761c62SAndrew Jeffery 	if (PLDM_SUCCESS != rc) {
58348761c62SAndrew Jeffery 		return rc;
58448761c62SAndrew Jeffery 	}
58548761c62SAndrew Jeffery 
58648761c62SAndrew Jeffery 	struct pldm_set_fru_record_table_resp *response =
58748761c62SAndrew Jeffery 		(struct pldm_set_fru_record_table_resp *)msg->payload;
58848761c62SAndrew Jeffery 	response->completion_code = completion_code;
58948761c62SAndrew Jeffery 	response->next_data_transfer_handle =
59048761c62SAndrew Jeffery 		htole32(next_data_transfer_handle);
59148761c62SAndrew Jeffery 
59248761c62SAndrew Jeffery 	return PLDM_SUCCESS;
59348761c62SAndrew Jeffery }
594