xref: /openbmc/libpldm/src/dsp/fru.c (revision 36324f6b)
1 /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
2 #include <libpldm/base.h>
3 #include <libpldm/fru.h>
4 #include <libpldm/utils.h>
5 
6 #include <assert.h>
7 #include <endian.h>
8 #include <stdbool.h>
9 #include <stdint.h>
10 #include <string.h>
11 
12 LIBPLDM_ABI_STABLE
encode_get_fru_record_table_metadata_req(uint8_t instance_id,struct pldm_msg * msg,size_t payload_length)13 int encode_get_fru_record_table_metadata_req(uint8_t instance_id,
14 					     struct pldm_msg *msg,
15 					     size_t payload_length)
16 {
17 	if (msg == NULL) {
18 		return PLDM_ERROR_INVALID_DATA;
19 	}
20 
21 	if (payload_length != PLDM_GET_FRU_RECORD_TABLE_METADATA_REQ_BYTES) {
22 		return PLDM_ERROR_INVALID_LENGTH;
23 	}
24 
25 	struct pldm_header_info header = { 0 };
26 	header.instance = instance_id;
27 	header.msg_type = PLDM_REQUEST;
28 	header.pldm_type = PLDM_FRU;
29 	header.command = PLDM_GET_FRU_RECORD_TABLE_METADATA;
30 
31 	return pack_pldm_header(&header, &(msg->hdr));
32 }
33 
34 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)35 int decode_get_fru_record_table_metadata_resp(
36 	const struct pldm_msg *msg, size_t payload_length,
37 	uint8_t *completion_code, uint8_t *fru_data_major_version,
38 	uint8_t *fru_data_minor_version, uint32_t *fru_table_maximum_size,
39 	uint32_t *fru_table_length, uint16_t *total_record_set_identifiers,
40 	uint16_t *total_table_records, uint32_t *checksum)
41 {
42 	if (msg == NULL || completion_code == NULL ||
43 	    fru_data_major_version == NULL || fru_data_minor_version == NULL ||
44 	    fru_table_maximum_size == NULL || fru_table_length == NULL ||
45 	    total_record_set_identifiers == NULL ||
46 	    total_table_records == NULL || checksum == NULL) {
47 		return PLDM_ERROR_INVALID_DATA;
48 	}
49 
50 	*completion_code = msg->payload[0];
51 	if (PLDM_SUCCESS != *completion_code) {
52 		return PLDM_SUCCESS;
53 	}
54 
55 	if (payload_length != PLDM_GET_FRU_RECORD_TABLE_METADATA_RESP_BYTES) {
56 		return PLDM_ERROR_INVALID_LENGTH;
57 	}
58 
59 	struct pldm_get_fru_record_table_metadata_resp *response =
60 		(struct pldm_get_fru_record_table_metadata_resp *)msg->payload;
61 
62 	*fru_data_major_version = response->fru_data_major_version;
63 	*fru_data_minor_version = response->fru_data_minor_version;
64 	*fru_table_maximum_size = le32toh(response->fru_table_maximum_size);
65 	*fru_table_length = le32toh(response->fru_table_length);
66 	*total_record_set_identifiers =
67 		le16toh(response->total_record_set_identifiers);
68 	*total_table_records = le16toh(response->total_table_records);
69 	*checksum = le32toh(response->checksum);
70 
71 	return PLDM_SUCCESS;
72 }
73 
74 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)75 int encode_get_fru_record_table_metadata_resp(
76 	uint8_t instance_id, uint8_t completion_code,
77 	uint8_t fru_data_major_version, uint8_t fru_data_minor_version,
78 	uint32_t fru_table_maximum_size, uint32_t fru_table_length,
79 	uint16_t total_record_set_identifiers, uint16_t total_table_records,
80 	uint32_t checksum, struct pldm_msg *msg)
81 {
82 	if (msg == NULL) {
83 		return PLDM_ERROR_INVALID_DATA;
84 	}
85 
86 	struct pldm_header_info header = { 0 };
87 	header.msg_type = PLDM_RESPONSE;
88 	header.instance = instance_id;
89 	header.pldm_type = PLDM_FRU;
90 	header.command = PLDM_GET_FRU_RECORD_TABLE_METADATA;
91 
92 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
93 	if (PLDM_SUCCESS != rc) {
94 		return rc;
95 	}
96 
97 	struct pldm_get_fru_record_table_metadata_resp *response =
98 		(struct pldm_get_fru_record_table_metadata_resp *)msg->payload;
99 	response->completion_code = completion_code;
100 	if (response->completion_code == PLDM_SUCCESS) {
101 		response->fru_data_major_version = fru_data_major_version;
102 		response->fru_data_minor_version = fru_data_minor_version;
103 		response->fru_table_maximum_size =
104 			htole32(fru_table_maximum_size);
105 		response->fru_table_length = htole32(fru_table_length);
106 		response->total_record_set_identifiers =
107 			htole16(total_record_set_identifiers);
108 		response->total_table_records = htole16(total_table_records);
109 		response->checksum = htole32(checksum);
110 	}
111 
112 	return PLDM_SUCCESS;
113 }
114 
115 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)116 int decode_get_fru_record_table_req(const struct pldm_msg *msg,
117 				    size_t payload_length,
118 				    uint32_t *data_transfer_handle,
119 				    uint8_t *transfer_operation_flag)
120 {
121 	if (msg == NULL || data_transfer_handle == NULL ||
122 	    transfer_operation_flag == NULL) {
123 		return PLDM_ERROR_INVALID_DATA;
124 	}
125 
126 	if (payload_length != PLDM_GET_FRU_RECORD_TABLE_REQ_BYTES) {
127 		return PLDM_ERROR_INVALID_LENGTH;
128 	}
129 
130 	struct pldm_get_fru_record_table_req *req =
131 		(struct pldm_get_fru_record_table_req *)msg->payload;
132 
133 	*data_transfer_handle = le32toh(req->data_transfer_handle);
134 	*transfer_operation_flag = req->transfer_operation_flag;
135 
136 	return PLDM_SUCCESS;
137 }
138 
139 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)140 int encode_get_fru_record_table_resp(uint8_t instance_id,
141 				     uint8_t completion_code,
142 				     uint32_t next_data_transfer_handle,
143 				     uint8_t transfer_flag,
144 				     struct pldm_msg *msg)
145 {
146 	if (msg == NULL) {
147 		return PLDM_ERROR_INVALID_DATA;
148 	}
149 
150 	struct pldm_header_info header = { 0 };
151 	header.msg_type = PLDM_RESPONSE;
152 	header.instance = instance_id;
153 	header.pldm_type = PLDM_FRU;
154 	header.command = PLDM_GET_FRU_RECORD_TABLE;
155 
156 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
157 	if (rc > PLDM_SUCCESS) {
158 		return rc;
159 	}
160 
161 	struct pldm_get_fru_record_table_resp *resp =
162 		(struct pldm_get_fru_record_table_resp *)msg->payload;
163 
164 	resp->completion_code = completion_code;
165 
166 	if (resp->completion_code == PLDM_SUCCESS) {
167 		resp->next_data_transfer_handle =
168 			htole32(next_data_transfer_handle);
169 		resp->transfer_flag = transfer_flag;
170 	}
171 
172 	return PLDM_SUCCESS;
173 }
174 
175 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)176 int encode_fru_record(uint8_t *fru_table, size_t total_size, size_t *curr_size,
177 		      uint16_t record_set_id, uint8_t record_type,
178 		      uint8_t num_frus, uint8_t encoding, uint8_t *tlvs,
179 		      size_t tlvs_size)
180 {
181 	size_t record_hdr_size = sizeof(struct pldm_fru_record_data_format) -
182 				 sizeof(struct pldm_fru_record_tlv);
183 
184 	if (fru_table == NULL || curr_size == NULL || !tlvs_size) {
185 		return PLDM_ERROR_INVALID_DATA;
186 	}
187 
188 	if (SIZE_MAX - *curr_size < record_hdr_size) {
189 		return PLDM_ERROR_INVALID_LENGTH;
190 	}
191 
192 	if (SIZE_MAX - (*curr_size + record_hdr_size) < tlvs_size) {
193 		return PLDM_ERROR_INVALID_LENGTH;
194 	}
195 
196 	if (total_size < *curr_size + record_hdr_size) {
197 		return PLDM_ERROR_INVALID_LENGTH;
198 	}
199 
200 	if (total_size - (*curr_size + record_hdr_size) < tlvs_size) {
201 		return PLDM_ERROR_INVALID_LENGTH;
202 	}
203 
204 	struct pldm_fru_record_data_format *record =
205 		(struct pldm_fru_record_data_format *)(fru_table + *curr_size);
206 	record->record_set_id = htole16(record_set_id);
207 	record->record_type = record_type;
208 	record->num_fru_fields = num_frus;
209 	record->encoding_type = encoding;
210 	*curr_size += record_hdr_size;
211 
212 	if (tlvs) {
213 		memcpy(fru_table + *curr_size, tlvs, tlvs_size);
214 		*curr_size += tlvs_size;
215 	}
216 
217 	return PLDM_SUCCESS;
218 }
219 
is_table_end(const struct pldm_fru_record_data_format * p,const void * table,size_t table_size)220 static bool is_table_end(const struct pldm_fru_record_data_format *p,
221 			 const void *table, size_t table_size)
222 {
223 	return p >=
224 	       (const struct pldm_fru_record_data_format *)((uint8_t *)table +
225 							    table_size);
226 }
227 
228 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)229 int get_fru_record_by_option(const uint8_t *table, size_t table_size,
230 			     uint8_t *record_table, size_t *record_size,
231 			     uint16_t rsi, uint8_t rt, uint8_t ft)
232 {
233 	const struct pldm_fru_record_data_format *record_data_src =
234 		(const struct pldm_fru_record_data_format *)table;
235 	struct pldm_fru_record_data_format *record_data_dest;
236 	int count = 0;
237 
238 	const struct pldm_fru_record_tlv *tlv;
239 	size_t len;
240 	uint8_t *pos = record_table;
241 
242 	while (!is_table_end(record_data_src, table, table_size)) {
243 		if ((record_data_src->record_set_id != htole16(rsi) &&
244 		     rsi != 0) ||
245 		    (record_data_src->record_type != rt && rt != 0)) {
246 			tlv = record_data_src->tlvs;
247 			for (int i = 0; i < record_data_src->num_fru_fields;
248 			     i++) {
249 				len = sizeof(*tlv) - 1 + tlv->length;
250 				tlv = (const struct pldm_fru_record_tlv
251 					       *)((char *)tlv + len);
252 			}
253 			record_data_src =
254 				(const struct pldm_fru_record_data_format
255 					 *)(tlv);
256 			continue;
257 		}
258 
259 		len = sizeof(struct pldm_fru_record_data_format) -
260 		      sizeof(struct pldm_fru_record_tlv);
261 
262 		if (pos - record_table + len >= *record_size) {
263 			return PLDM_ERROR_INVALID_LENGTH;
264 		}
265 		memcpy(pos, record_data_src, len);
266 
267 		record_data_dest = (struct pldm_fru_record_data_format *)pos;
268 		pos += len;
269 
270 		tlv = record_data_src->tlvs;
271 		count = 0;
272 		for (int i = 0; i < record_data_src->num_fru_fields; i++) {
273 			len = sizeof(*tlv) - 1 + tlv->length;
274 			if (tlv->type == ft || ft == 0) {
275 				if (pos - record_table + len >= *record_size) {
276 					return PLDM_ERROR_INVALID_LENGTH;
277 				}
278 				memcpy(pos, tlv, len);
279 				pos += len;
280 				count++;
281 			}
282 			tlv = (const struct pldm_fru_record_tlv *)((char *)tlv +
283 								   len);
284 		}
285 		record_data_dest->num_fru_fields = count;
286 		record_data_src =
287 			(const struct pldm_fru_record_data_format *)(tlv);
288 	}
289 
290 	*record_size = pos - record_table;
291 
292 	return PLDM_SUCCESS;
293 }
294 
295 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)296 int encode_get_fru_record_by_option_req(
297 	uint8_t instance_id, uint32_t data_transfer_handle,
298 	uint16_t fru_table_handle, uint16_t record_set_identifier,
299 	uint8_t record_type, uint8_t field_type, uint8_t transfer_op_flag,
300 	struct pldm_msg *msg, size_t payload_length)
301 {
302 	if (msg == NULL) {
303 		return PLDM_ERROR_INVALID_DATA;
304 	}
305 
306 	if (payload_length !=
307 	    sizeof(struct pldm_get_fru_record_by_option_req)) {
308 		return PLDM_ERROR_INVALID_LENGTH;
309 	}
310 
311 	struct pldm_header_info header = { 0 };
312 	header.instance = instance_id;
313 	header.msg_type = PLDM_REQUEST;
314 	header.pldm_type = PLDM_FRU;
315 	header.command = PLDM_GET_FRU_RECORD_BY_OPTION;
316 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
317 	if (rc != PLDM_SUCCESS) {
318 		return rc;
319 	}
320 
321 	struct pldm_get_fru_record_by_option_req *req =
322 		(struct pldm_get_fru_record_by_option_req *)msg->payload;
323 
324 	req->data_transfer_handle = htole32(data_transfer_handle);
325 	req->fru_table_handle = htole16(fru_table_handle);
326 	req->record_set_identifier = htole16(record_set_identifier);
327 	req->record_type = record_type;
328 	req->field_type = field_type;
329 	req->transfer_op_flag = transfer_op_flag;
330 
331 	return PLDM_SUCCESS;
332 }
333 
334 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)335 int decode_get_fru_record_by_option_req(
336 	const struct pldm_msg *msg, size_t payload_length,
337 	uint32_t *data_transfer_handle, uint16_t *fru_table_handle,
338 	uint16_t *record_set_identifier, uint8_t *record_type,
339 	uint8_t *field_type, uint8_t *transfer_op_flag)
340 {
341 	if (msg == NULL || data_transfer_handle == NULL ||
342 	    fru_table_handle == NULL || record_set_identifier == NULL ||
343 	    record_type == NULL || field_type == NULL ||
344 	    transfer_op_flag == NULL) {
345 		return PLDM_ERROR_INVALID_DATA;
346 	}
347 
348 	if (payload_length !=
349 	    sizeof(struct pldm_get_fru_record_by_option_req)) {
350 		return PLDM_ERROR_INVALID_LENGTH;
351 	}
352 
353 	struct pldm_get_fru_record_by_option_req *req =
354 		(struct pldm_get_fru_record_by_option_req *)msg->payload;
355 
356 	*data_transfer_handle = le32toh(req->data_transfer_handle);
357 	*fru_table_handle = le16toh(req->fru_table_handle);
358 	*record_set_identifier = le16toh(req->record_set_identifier);
359 	*record_type = req->record_type;
360 	*field_type = req->field_type;
361 	*transfer_op_flag = req->transfer_op_flag;
362 	return PLDM_SUCCESS;
363 }
364 
365 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)366 int encode_get_fru_record_by_option_resp(uint8_t instance_id,
367 					 uint8_t completion_code,
368 					 uint32_t next_data_transfer_handle,
369 					 uint8_t transfer_flag,
370 					 const void *fru_structure_data,
371 					 size_t data_size, struct pldm_msg *msg,
372 					 size_t payload_length)
373 {
374 	if (msg == NULL || fru_structure_data == NULL) {
375 		return PLDM_ERROR_INVALID_DATA;
376 	}
377 
378 	if (payload_length < PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES) {
379 		return PLDM_ERROR_INVALID_LENGTH;
380 	}
381 
382 	if (payload_length - PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES <
383 	    data_size) {
384 		return PLDM_ERROR_INVALID_LENGTH;
385 	}
386 
387 	struct pldm_header_info header = { 0 };
388 	header.instance = instance_id;
389 	header.msg_type = PLDM_RESPONSE;
390 	header.pldm_type = PLDM_FRU;
391 	header.command = PLDM_GET_FRU_RECORD_BY_OPTION;
392 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
393 	if (rc != PLDM_SUCCESS) {
394 		return rc;
395 	}
396 
397 	struct pldm_get_fru_record_by_option_resp *resp =
398 		(struct pldm_get_fru_record_by_option_resp *)msg->payload;
399 
400 	resp->completion_code = completion_code;
401 	resp->next_data_transfer_handle = htole32(next_data_transfer_handle);
402 	resp->transfer_flag = transfer_flag;
403 
404 	if (completion_code == PLDM_SUCCESS) {
405 		memcpy(resp->fru_structure_data, fru_structure_data, data_size);
406 	}
407 
408 	return PLDM_SUCCESS;
409 }
410 
411 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)412 int decode_get_fru_record_by_option_resp(
413 	const struct pldm_msg *msg, size_t payload_length,
414 	uint8_t *completion_code, uint32_t *next_transfer_handle,
415 	uint8_t *transfer_flag, struct variable_field *fru_structure_data)
416 {
417 	if (msg == NULL || completion_code == NULL ||
418 	    next_transfer_handle == NULL || transfer_flag == NULL ||
419 	    fru_structure_data == NULL) {
420 		return PLDM_ERROR_INVALID_DATA;
421 	}
422 
423 	*completion_code = msg->payload[0];
424 	if (PLDM_SUCCESS != *completion_code) {
425 		return PLDM_SUCCESS;
426 	}
427 
428 	if (payload_length < PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES) {
429 		return PLDM_ERROR_INVALID_LENGTH;
430 	}
431 
432 	struct pldm_get_fru_record_by_option_resp *resp =
433 		(struct pldm_get_fru_record_by_option_resp *)msg->payload;
434 
435 	*next_transfer_handle = le32toh(resp->next_data_transfer_handle);
436 	*transfer_flag = resp->transfer_flag;
437 	fru_structure_data->ptr = resp->fru_structure_data;
438 	fru_structure_data->length =
439 		payload_length - PLDM_GET_FRU_RECORD_BY_OPTION_MIN_RESP_BYTES;
440 
441 	return PLDM_SUCCESS;
442 }
443 
444 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)445 int encode_get_fru_record_table_req(uint8_t instance_id,
446 				    uint32_t data_transfer_handle,
447 				    uint8_t transfer_operation_flag,
448 				    struct pldm_msg *msg, size_t payload_length)
449 
450 {
451 	if (msg == NULL) {
452 		return PLDM_ERROR_INVALID_DATA;
453 	}
454 	if (payload_length != sizeof(struct pldm_get_fru_record_table_req)) {
455 		return PLDM_ERROR_INVALID_LENGTH;
456 	}
457 
458 	struct pldm_header_info header = { 0 };
459 	header.msg_type = PLDM_REQUEST;
460 	header.instance = instance_id;
461 	header.pldm_type = PLDM_FRU;
462 	header.command = PLDM_GET_FRU_RECORD_TABLE;
463 
464 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
465 	if (rc != PLDM_SUCCESS) {
466 		return rc;
467 	}
468 
469 	struct pldm_get_fru_record_table_req *req =
470 		(struct pldm_get_fru_record_table_req *)msg->payload;
471 	req->data_transfer_handle = htole32(data_transfer_handle);
472 	req->transfer_operation_flag = transfer_operation_flag;
473 
474 	return PLDM_SUCCESS;
475 }
476 
477 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)478 int decode_get_fru_record_table_resp_safe(
479 	const struct pldm_msg *msg, size_t payload_length,
480 	uint8_t *completion_code, uint32_t *next_data_transfer_handle,
481 	uint8_t *transfer_flag, uint8_t *fru_record_table_data,
482 	size_t *fru_record_table_length, size_t max_fru_record_table_length)
483 {
484 	if (msg == NULL || completion_code == NULL ||
485 	    next_data_transfer_handle == NULL || transfer_flag == NULL ||
486 	    fru_record_table_data == NULL || fru_record_table_length == NULL) {
487 		return PLDM_ERROR_INVALID_DATA;
488 	}
489 
490 	*completion_code = msg->payload[0];
491 	if (PLDM_SUCCESS != *completion_code) {
492 		return PLDM_SUCCESS;
493 	}
494 	if (payload_length <= PLDM_GET_FRU_RECORD_TABLE_MIN_RESP_BYTES) {
495 		return PLDM_ERROR_INVALID_LENGTH;
496 	}
497 
498 	struct pldm_get_fru_record_table_resp *resp =
499 		(struct pldm_get_fru_record_table_resp *)msg->payload;
500 
501 	*next_data_transfer_handle = le32toh(resp->next_data_transfer_handle);
502 	*transfer_flag = resp->transfer_flag;
503 
504 	*fru_record_table_length =
505 		payload_length - PLDM_GET_FRU_RECORD_TABLE_MIN_RESP_BYTES;
506 
507 	if (*fru_record_table_length > max_fru_record_table_length) {
508 		return PLDM_ERROR_INVALID_LENGTH;
509 	}
510 
511 	memcpy(fru_record_table_data, resp->fru_record_table_data,
512 	       *fru_record_table_length);
513 
514 	return PLDM_SUCCESS;
515 }
516 
517 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)518 int decode_get_fru_record_table_resp(const struct pldm_msg *msg,
519 				     size_t payload_length,
520 				     uint8_t *completion_code,
521 				     uint32_t *next_data_transfer_handle,
522 				     uint8_t *transfer_flag,
523 				     uint8_t *fru_record_table_data,
524 				     size_t *fru_record_table_length)
525 {
526 	return decode_get_fru_record_table_resp_safe(
527 		msg, payload_length, completion_code, next_data_transfer_handle,
528 		transfer_flag, fru_record_table_data, fru_record_table_length,
529 		(size_t)-1);
530 }
531 
532 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)533 int decode_set_fru_record_table_req(const struct pldm_msg *msg,
534 				    size_t payload_length,
535 				    uint32_t *data_transfer_handle,
536 				    uint8_t *transfer_flag,
537 				    struct variable_field *fru_table_data)
538 
539 {
540 	if (msg == NULL || data_transfer_handle == NULL ||
541 	    transfer_flag == NULL || fru_table_data == NULL) {
542 		return PLDM_ERROR_INVALID_DATA;
543 	}
544 
545 	if (payload_length <= PLDM_SET_FRU_RECORD_TABLE_MIN_REQ_BYTES) {
546 		return PLDM_ERROR_INVALID_LENGTH;
547 	}
548 
549 	struct pldm_set_fru_record_table_req *req =
550 		(struct pldm_set_fru_record_table_req *)msg->payload;
551 
552 	*data_transfer_handle = le32toh(req->data_transfer_handle);
553 	*transfer_flag = req->transfer_flag;
554 	fru_table_data->length =
555 		payload_length - PLDM_SET_FRU_RECORD_TABLE_MIN_REQ_BYTES;
556 	fru_table_data->ptr = req->fru_record_table_data;
557 
558 	return PLDM_SUCCESS;
559 }
560 
561 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)562 int encode_set_fru_record_table_resp(uint8_t instance_id,
563 				     uint8_t completion_code,
564 				     uint32_t next_data_transfer_handle,
565 				     size_t payload_length,
566 				     struct pldm_msg *msg)
567 {
568 	if (msg == NULL) {
569 		return PLDM_ERROR_INVALID_DATA;
570 	}
571 	if (payload_length != PLDM_SET_FRU_RECORD_TABLE_RESP_BYTES) {
572 		return PLDM_ERROR_INVALID_LENGTH;
573 	}
574 
575 	struct pldm_header_info header = { 0 };
576 	header.instance = instance_id;
577 	header.msg_type = PLDM_RESPONSE;
578 	header.pldm_type = PLDM_FRU;
579 	header.command = PLDM_SET_FRU_RECORD_TABLE;
580 
581 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
582 	if (PLDM_SUCCESS != rc) {
583 		return rc;
584 	}
585 
586 	struct pldm_set_fru_record_table_resp *response =
587 		(struct pldm_set_fru_record_table_resp *)msg->payload;
588 	response->completion_code = completion_code;
589 	response->next_data_transfer_handle =
590 		htole32(next_data_transfer_handle);
591 
592 	return PLDM_SUCCESS;
593 }
594