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