xref: /openbmc/libpldm/src/dsp/firmware_update.c (revision d2f8a7e3b37634ec0e42230a8ad14411f34e9149)
1 /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
2 #include "api.h"
3 #include "dsp/base.h"
4 #include "msgbuf.h"
5 #include <libpldm/firmware_update.h>
6 #include <libpldm/utils.h>
7 
8 #include <endian.h>
9 #include <stdbool.h>
10 #include <string.h>
11 
12 /** @brief Check whether string type value is valid
13  *
14  *  @return true if string type value is valid, false if not
15  */
16 static bool is_string_type_valid(uint8_t string_type)
17 {
18 	switch (string_type) {
19 	case PLDM_STR_TYPE_UNKNOWN:
20 		return false;
21 	case PLDM_STR_TYPE_ASCII:
22 	case PLDM_STR_TYPE_UTF_8:
23 	case PLDM_STR_TYPE_UTF_16:
24 	case PLDM_STR_TYPE_UTF_16LE:
25 	case PLDM_STR_TYPE_UTF_16BE:
26 		return true;
27 	default:
28 		return false;
29 	}
30 }
31 
32 /** @brief Return the length of the descriptor type described in firmware update
33  *         specification
34  *
35  *  @return length of the descriptor type if descriptor type is valid else
36  *          return 0
37  */
38 static uint16_t get_descriptor_type_length(uint16_t descriptor_type)
39 {
40 	switch (descriptor_type) {
41 	case PLDM_FWUP_PCI_VENDOR_ID:
42 		return PLDM_FWUP_PCI_VENDOR_ID_LENGTH;
43 	case PLDM_FWUP_IANA_ENTERPRISE_ID:
44 		return PLDM_FWUP_IANA_ENTERPRISE_ID_LENGTH;
45 	case PLDM_FWUP_UUID:
46 		return PLDM_FWUP_UUID_LENGTH;
47 	case PLDM_FWUP_PNP_VENDOR_ID:
48 		return PLDM_FWUP_PNP_VENDOR_ID_LENGTH;
49 	case PLDM_FWUP_ACPI_VENDOR_ID:
50 		return PLDM_FWUP_ACPI_VENDOR_ID_LENGTH;
51 	case PLDM_FWUP_IEEE_ASSIGNED_COMPANY_ID:
52 		return PLDM_FWUP_IEEE_ASSIGNED_COMPANY_ID_LENGTH;
53 	case PLDM_FWUP_SCSI_VENDOR_ID:
54 		return PLDM_FWUP_SCSI_VENDOR_ID_LENGTH;
55 	case PLDM_FWUP_PCI_DEVICE_ID:
56 		return PLDM_FWUP_PCI_DEVICE_ID_LENGTH;
57 	case PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID:
58 		return PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID_LENGTH;
59 	case PLDM_FWUP_PCI_SUBSYSTEM_ID:
60 		return PLDM_FWUP_PCI_SUBSYSTEM_ID_LENGTH;
61 	case PLDM_FWUP_PCI_REVISION_ID:
62 		return PLDM_FWUP_PCI_REVISION_ID_LENGTH;
63 	case PLDM_FWUP_PNP_PRODUCT_IDENTIFIER:
64 		return PLDM_FWUP_PNP_PRODUCT_IDENTIFIER_LENGTH;
65 	case PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER:
66 		return PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER_LENGTH;
67 	case PLDM_FWUP_ASCII_MODEL_NUMBER_LONG_STRING:
68 		return PLDM_FWUP_ASCII_MODEL_NUMBER_LONG_STRING_LENGTH;
69 	case PLDM_FWUP_ASCII_MODEL_NUMBER_SHORT_STRING:
70 		return PLDM_FWUP_ASCII_MODEL_NUMBER_SHORT_STRING_LENGTH;
71 	case PLDM_FWUP_SCSI_PRODUCT_ID:
72 		return PLDM_FWUP_SCSI_PRODUCT_ID_LENGTH;
73 	case PLDM_FWUP_UBM_CONTROLLER_DEVICE_CODE:
74 		return PLDM_FWUP_UBM_CONTROLLER_DEVICE_CODE_LENGTH;
75 	default:
76 		return 0;
77 	}
78 }
79 
80 static bool is_downstream_device_update_support_valid(uint8_t resp)
81 {
82 	switch (resp) {
83 	case PLDM_FWUP_DOWNSTREAM_DEVICE_UPDATE_NOT_SUPPORTED:
84 	case PLDM_FWUP_DOWNSTREAM_DEVICE_UPDATE_SUPPORTED:
85 		return true;
86 	default:
87 		return false;
88 	}
89 }
90 
91 static bool
92 is_transfer_operation_flag_valid(enum transfer_op_flag transfer_op_flag)
93 {
94 	switch (transfer_op_flag) {
95 	case PLDM_GET_NEXTPART:
96 	case PLDM_GET_FIRSTPART:
97 		return true;
98 	default:
99 		return false;
100 	}
101 }
102 
103 /** @brief Check whether ComponentResponse is valid
104  *
105  *  @return true if ComponentResponse is valid, false if not
106  */
107 static bool is_comp_resp_valid(uint8_t comp_resp)
108 {
109 	switch (comp_resp) {
110 	case PLDM_CR_COMP_CAN_BE_UPDATED:
111 	case PLDM_CR_COMP_MAY_BE_UPDATEABLE:
112 		return true;
113 
114 	default:
115 		return false;
116 	}
117 }
118 
119 /** @brief Check whether ComponentResponseCode is valid
120  *
121  *  @return true if ComponentResponseCode is valid, false if not
122  */
123 static bool is_comp_resp_code_valid(uint8_t comp_resp_code)
124 {
125 	switch (comp_resp_code) {
126 	case PLDM_CRC_COMP_CAN_BE_UPDATED:
127 	case PLDM_CRC_COMP_COMPARISON_STAMP_IDENTICAL:
128 	case PLDM_CRC_COMP_COMPARISON_STAMP_LOWER:
129 	case PLDM_CRC_INVALID_COMP_COMPARISON_STAMP:
130 	case PLDM_CRC_COMP_CONFLICT:
131 	case PLDM_CRC_COMP_PREREQUISITES_NOT_MET:
132 	case PLDM_CRC_COMP_NOT_SUPPORTED:
133 	case PLDM_CRC_COMP_SECURITY_RESTRICTIONS:
134 	case PLDM_CRC_INCOMPLETE_COMP_IMAGE_SET:
135 	case PLDM_CRC_ACTIVE_IMAGE_NOT_UPDATEABLE_SUBSEQUENTLY:
136 	case PLDM_CRC_COMP_VER_STR_IDENTICAL:
137 	case PLDM_CRC_COMP_VER_STR_LOWER:
138 		return true;
139 
140 	default:
141 		if (comp_resp_code >=
142 			    PLDM_CRC_VENDOR_COMP_RESP_CODE_RANGE_MIN &&
143 		    comp_resp_code <=
144 			    PLDM_CRC_VENDOR_COMP_RESP_CODE_RANGE_MAX) {
145 			return true;
146 		}
147 		return false;
148 	}
149 }
150 
151 /** @brief Check whether ComponentCompatibilityResponse is valid
152  *
153  *  @return true if ComponentCompatibilityResponse is valid, false if not
154  */
155 static bool is_comp_compatibility_resp_valid(uint8_t comp_compatibility_resp)
156 {
157 	switch (comp_compatibility_resp) {
158 	case PLDM_CCR_COMP_CAN_BE_UPDATED:
159 	case PLDM_CCR_COMP_CANNOT_BE_UPDATED:
160 		return true;
161 
162 	default:
163 		return false;
164 	}
165 }
166 
167 /** @brief Check whether ComponentCompatibilityResponse Code is valid
168  *
169  *  @return true if ComponentCompatibilityResponse Code is valid, false if not
170  */
171 static bool
172 is_comp_compatibility_resp_code_valid(uint8_t comp_compatibility_resp_code)
173 {
174 	switch (comp_compatibility_resp_code) {
175 	case PLDM_CCRC_NO_RESPONSE_CODE:
176 	case PLDM_CCRC_COMP_COMPARISON_STAMP_IDENTICAL:
177 	case PLDM_CCRC_COMP_COMPARISON_STAMP_LOWER:
178 	case PLDM_CCRC_INVALID_COMP_COMPARISON_STAMP:
179 	case PLDM_CCRC_COMP_CONFLICT:
180 	case PLDM_CCRC_COMP_PREREQUISITES_NOT_MET:
181 	case PLDM_CCRC_COMP_NOT_SUPPORTED:
182 	case PLDM_CCRC_COMP_SECURITY_RESTRICTIONS:
183 	case PLDM_CRC_INCOMPLETE_COMP_IMAGE_SET:
184 	case PLDM_CCRC_COMP_INFO_NO_MATCH:
185 	case PLDM_CCRC_COMP_VER_STR_IDENTICAL:
186 	case PLDM_CCRC_COMP_VER_STR_LOWER:
187 		return true;
188 
189 	default:
190 		if (comp_compatibility_resp_code >=
191 			    PLDM_CCRC_VENDOR_COMP_RESP_CODE_RANGE_MIN &&
192 		    comp_compatibility_resp_code <=
193 			    PLDM_CCRC_VENDOR_COMP_RESP_CODE_RANGE_MAX) {
194 			return true;
195 		}
196 		return false;
197 	}
198 }
199 
200 /** @brief Check whether SelfContainedActivationRequest is valid
201  *
202  *  @return true if SelfContainedActivationRequest is valid, false if not
203  */
204 static bool
205 is_self_contained_activation_req_valid(bool8_t self_contained_activation_req)
206 {
207 	switch (self_contained_activation_req) {
208 	case PLDM_NOT_ACTIVATE_SELF_CONTAINED_COMPONENTS:
209 	case PLDM_ACTIVATE_SELF_CONTAINED_COMPONENTS:
210 		return true;
211 
212 	default:
213 		return false;
214 	}
215 }
216 
217 /** @brief Check if current or previous status in GetStatus command response is
218  *         valid
219  *
220  *	@param[in] state - current or previous different state machine state of
221  *                     the FD
222  *	@return true if state is valid, false if not
223  */
224 static bool is_state_valid(uint8_t state)
225 {
226 	switch (state) {
227 	case PLDM_FD_STATE_IDLE:
228 	case PLDM_FD_STATE_LEARN_COMPONENTS:
229 	case PLDM_FD_STATE_READY_XFER:
230 	case PLDM_FD_STATE_DOWNLOAD:
231 	case PLDM_FD_STATE_VERIFY:
232 	case PLDM_FD_STATE_APPLY:
233 	case PLDM_FD_STATE_ACTIVATE:
234 		return true;
235 
236 	default:
237 		return false;
238 	}
239 }
240 
241 /** @brief Check if aux state in GetStatus command response is valid
242  *
243  *  @param[in] aux_state - provides additional information to the UA to describe
244  *                         the current operation state of the FD/FDP
245  *
246  *	@return true if aux state is valid, false if not
247  */
248 static bool is_aux_state_valid(uint8_t aux_state)
249 {
250 	switch (aux_state) {
251 	case PLDM_FD_OPERATION_IN_PROGRESS:
252 	case PLDM_FD_OPERATION_SUCCESSFUL:
253 	case PLDM_FD_OPERATION_FAILED:
254 	case PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER:
255 		return true;
256 
257 	default:
258 		return false;
259 	}
260 }
261 
262 /** @brief Check if aux state status in GetStatus command response is valid
263  *
264  *	@param[in] aux_state_status - aux state status
265  *
266  *	@return true if aux state status is valid, false if not
267  */
268 static bool is_aux_state_status_valid(uint8_t aux_state_status)
269 {
270 	if (aux_state_status == PLDM_FD_AUX_STATE_IN_PROGRESS_OR_SUCCESS ||
271 	    aux_state_status == PLDM_FD_TIMEOUT ||
272 	    aux_state_status == PLDM_FD_GENERIC_ERROR ||
273 	    (aux_state_status >= PLDM_FD_VENDOR_DEFINED_STATUS_CODE_START &&
274 	     aux_state_status <= PLDM_FD_VENDOR_DEFINED_STATUS_CODE_END)) {
275 		return true;
276 	}
277 
278 	return false;
279 }
280 
281 /** @brief Check if reason code in GetStatus command response is valid
282  *
283  *	@param[in] reason_code - provides the reason for why the current state
284  *                           entered the IDLE state
285  *
286  *	@return true if reason code is valid, false if not
287  */
288 static bool is_reason_code_valid(uint8_t reason_code)
289 {
290 	switch (reason_code) {
291 	case PLDM_FD_INITIALIZATION:
292 	case PLDM_FD_ACTIVATE_FW:
293 	case PLDM_FD_CANCEL_UPDATE:
294 	case PLDM_FD_TIMEOUT_LEARN_COMPONENT:
295 	case PLDM_FD_TIMEOUT_READY_XFER:
296 	case PLDM_FD_TIMEOUT_DOWNLOAD:
297 	case PLDM_FD_TIMEOUT_VERIFY:
298 	case PLDM_FD_TIMEOUT_APPLY:
299 		return true;
300 
301 	default:
302 		if (reason_code >= PLDM_FD_STATUS_VENDOR_DEFINED_MIN) {
303 			return true;
304 		}
305 		return false;
306 	}
307 }
308 
309 /** @brief Check if non functioning component indication in CancelUpdate
310  *         response is valid
311  *
312  *  @return true if non functioning component indication is valid, false if not
313  */
314 static bool is_non_functioning_component_indication_valid(
315 	bool8_t non_functioning_component_indication)
316 {
317 	switch (non_functioning_component_indication) {
318 	case PLDM_FWUP_COMPONENTS_FUNCTIONING:
319 	case PLDM_FWUP_COMPONENTS_NOT_FUNCTIONING:
320 		return true;
321 
322 	default:
323 		return false;
324 	}
325 }
326 
327 LIBPLDM_ABI_STABLE
328 int decode_pldm_package_header_info(
329 	const uint8_t *data, size_t length,
330 	struct pldm_package_header_information *package_header_info,
331 	struct variable_field *package_version_str)
332 {
333 	if (data == NULL || package_header_info == NULL ||
334 	    package_version_str == NULL) {
335 		return PLDM_ERROR_INVALID_DATA;
336 	}
337 
338 	if (length < sizeof(struct pldm_package_header_information)) {
339 		return PLDM_ERROR_INVALID_LENGTH;
340 	}
341 
342 	struct pldm_package_header_information *data_header =
343 		(struct pldm_package_header_information *)(data);
344 
345 	if (!is_string_type_valid(data_header->package_version_string_type) ||
346 	    (data_header->package_version_string_length == 0)) {
347 		return PLDM_ERROR_INVALID_DATA;
348 	}
349 
350 	if (length < sizeof(struct pldm_package_header_information) +
351 			     data_header->package_version_string_length) {
352 		return PLDM_ERROR_INVALID_LENGTH;
353 	}
354 
355 	if ((data_header->component_bitmap_bit_length %
356 	     PLDM_FWUP_COMPONENT_BITMAP_MULTIPLE) != 0) {
357 		return PLDM_ERROR_INVALID_DATA;
358 	}
359 
360 	memcpy(package_header_info->uuid, data_header->uuid,
361 	       sizeof(data_header->uuid));
362 	package_header_info->package_header_format_version =
363 		data_header->package_header_format_version;
364 	package_header_info->package_header_size =
365 		le16toh(data_header->package_header_size);
366 	memcpy(package_header_info->package_release_date_time,
367 	       data_header->package_release_date_time,
368 	       sizeof(data_header->package_release_date_time));
369 	package_header_info->component_bitmap_bit_length =
370 		le16toh(data_header->component_bitmap_bit_length);
371 	package_header_info->package_version_string_type =
372 		data_header->package_version_string_type;
373 	package_header_info->package_version_string_length =
374 		data_header->package_version_string_length;
375 	package_version_str->ptr =
376 		data + sizeof(struct pldm_package_header_information);
377 	package_version_str->length =
378 		package_header_info->package_version_string_length;
379 
380 	return PLDM_SUCCESS;
381 }
382 
383 LIBPLDM_ABI_STABLE
384 int decode_firmware_device_id_record(
385 	const uint8_t *data, size_t length,
386 	uint16_t component_bitmap_bit_length,
387 	struct pldm_firmware_device_id_record *fw_device_id_record,
388 	struct variable_field *applicable_components,
389 	struct variable_field *comp_image_set_version_str,
390 	struct variable_field *record_descriptors,
391 	struct variable_field *fw_device_pkg_data)
392 {
393 	if (data == NULL || fw_device_id_record == NULL ||
394 	    applicable_components == NULL ||
395 	    comp_image_set_version_str == NULL || record_descriptors == NULL ||
396 	    fw_device_pkg_data == NULL) {
397 		return PLDM_ERROR_INVALID_DATA;
398 	}
399 
400 	if (length < sizeof(struct pldm_firmware_device_id_record)) {
401 		return PLDM_ERROR_INVALID_LENGTH;
402 	}
403 
404 	if ((component_bitmap_bit_length %
405 	     PLDM_FWUP_COMPONENT_BITMAP_MULTIPLE) != 0) {
406 		return PLDM_ERROR_INVALID_DATA;
407 	}
408 
409 	struct pldm_firmware_device_id_record *data_record =
410 		(struct pldm_firmware_device_id_record *)(data);
411 
412 	if (!is_string_type_valid(
413 		    data_record->comp_image_set_version_string_type) ||
414 	    (data_record->comp_image_set_version_string_length == 0)) {
415 		return PLDM_ERROR_INVALID_DATA;
416 	}
417 
418 	fw_device_id_record->record_length =
419 		le16toh(data_record->record_length);
420 	fw_device_id_record->descriptor_count = data_record->descriptor_count;
421 	fw_device_id_record->device_update_option_flags.value =
422 		le32toh(data_record->device_update_option_flags.value);
423 	fw_device_id_record->comp_image_set_version_string_type =
424 		data_record->comp_image_set_version_string_type;
425 	fw_device_id_record->comp_image_set_version_string_length =
426 		data_record->comp_image_set_version_string_length;
427 	fw_device_id_record->fw_device_pkg_data_length =
428 		le16toh(data_record->fw_device_pkg_data_length);
429 
430 	if (length < fw_device_id_record->record_length) {
431 		return PLDM_ERROR_INVALID_LENGTH;
432 	}
433 
434 	uint16_t applicable_components_length =
435 		component_bitmap_bit_length /
436 		PLDM_FWUP_COMPONENT_BITMAP_MULTIPLE;
437 	uint16_t calc_min_record_length =
438 		sizeof(struct pldm_firmware_device_id_record) +
439 		applicable_components_length +
440 		data_record->comp_image_set_version_string_length +
441 		PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN +
442 		fw_device_id_record->fw_device_pkg_data_length;
443 
444 	if (fw_device_id_record->record_length < calc_min_record_length) {
445 		return PLDM_ERROR_INVALID_LENGTH;
446 	}
447 
448 	applicable_components->ptr =
449 		data + sizeof(struct pldm_firmware_device_id_record);
450 	applicable_components->length = applicable_components_length;
451 
452 	comp_image_set_version_str->ptr =
453 		applicable_components->ptr + applicable_components->length;
454 	comp_image_set_version_str->length =
455 		fw_device_id_record->comp_image_set_version_string_length;
456 
457 	record_descriptors->ptr = comp_image_set_version_str->ptr +
458 				  comp_image_set_version_str->length;
459 	record_descriptors->length =
460 		fw_device_id_record->record_length -
461 		sizeof(struct pldm_firmware_device_id_record) -
462 		applicable_components_length -
463 		fw_device_id_record->comp_image_set_version_string_length -
464 		fw_device_id_record->fw_device_pkg_data_length;
465 
466 	if (fw_device_id_record->fw_device_pkg_data_length) {
467 		fw_device_pkg_data->ptr =
468 			record_descriptors->ptr + record_descriptors->length;
469 		fw_device_pkg_data->length =
470 			fw_device_id_record->fw_device_pkg_data_length;
471 	}
472 
473 	return PLDM_SUCCESS;
474 }
475 
476 LIBPLDM_ABI_TESTING
477 int decode_pldm_descriptor_from_iter(struct pldm_descriptor_iter *iter,
478 				     struct pldm_descriptor *desc)
479 {
480 	struct pldm_msgbuf _buf;
481 	struct pldm_msgbuf *buf = &_buf;
482 	int rc;
483 
484 	if (!iter || !iter->field || !desc) {
485 		return -EINVAL;
486 	}
487 
488 	rc = pldm_msgbuf_init_errno(buf, PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN,
489 				    iter->field->ptr, iter->field->length);
490 	if (rc) {
491 		return rc;
492 	}
493 
494 	pldm_msgbuf_extract(buf, desc->descriptor_type);
495 	rc = pldm_msgbuf_extract(buf, desc->descriptor_length);
496 	if (rc) {
497 		return rc;
498 	}
499 
500 	desc->descriptor_data = NULL;
501 	pldm_msgbuf_span_required(buf, desc->descriptor_length,
502 				  (void **)&desc->descriptor_data);
503 	iter->field->ptr = NULL;
504 	pldm_msgbuf_span_remaining(buf, (void **)&iter->field->ptr,
505 				   &iter->field->length);
506 
507 	return pldm_msgbuf_destroy(buf);
508 }
509 
510 LIBPLDM_ABI_STABLE
511 int decode_descriptor_type_length_value(const uint8_t *data, size_t length,
512 					uint16_t *descriptor_type,
513 					struct variable_field *descriptor_data)
514 {
515 	uint16_t descriptor_length = 0;
516 
517 	if (data == NULL || descriptor_type == NULL ||
518 	    descriptor_data == NULL) {
519 		return PLDM_ERROR_INVALID_DATA;
520 	}
521 
522 	if (length < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {
523 		return PLDM_ERROR_INVALID_LENGTH;
524 	}
525 
526 	struct pldm_descriptor_tlv *entry =
527 		(struct pldm_descriptor_tlv *)(data);
528 
529 	*descriptor_type = le16toh(entry->descriptor_type);
530 	descriptor_length = le16toh(entry->descriptor_length);
531 	if (*descriptor_type != PLDM_FWUP_VENDOR_DEFINED) {
532 		if (descriptor_length !=
533 		    get_descriptor_type_length(*descriptor_type)) {
534 			return PLDM_ERROR_INVALID_LENGTH;
535 		}
536 	}
537 
538 	if (length < (sizeof(*descriptor_type) + sizeof(descriptor_length) +
539 		      descriptor_length)) {
540 		return PLDM_ERROR_INVALID_LENGTH;
541 	}
542 
543 	descriptor_data->ptr = entry->descriptor_data;
544 	descriptor_data->length = descriptor_length;
545 
546 	return PLDM_SUCCESS;
547 }
548 
549 LIBPLDM_ABI_STABLE
550 int decode_vendor_defined_descriptor_value(
551 	const uint8_t *data, size_t length, uint8_t *descriptor_title_str_type,
552 	struct variable_field *descriptor_title_str,
553 	struct variable_field *descriptor_data)
554 {
555 	if (data == NULL || descriptor_title_str_type == NULL ||
556 	    descriptor_title_str == NULL || descriptor_data == NULL) {
557 		return PLDM_ERROR_INVALID_DATA;
558 	}
559 
560 	if (length < sizeof(struct pldm_vendor_defined_descriptor_title_data)) {
561 		return PLDM_ERROR_INVALID_LENGTH;
562 	}
563 
564 	struct pldm_vendor_defined_descriptor_title_data *entry =
565 		(struct pldm_vendor_defined_descriptor_title_data *)(data);
566 	if (!is_string_type_valid(
567 		    entry->vendor_defined_descriptor_title_str_type) ||
568 	    (entry->vendor_defined_descriptor_title_str_len == 0)) {
569 		return PLDM_ERROR_INVALID_DATA;
570 	}
571 
572 	// Assuming at least 1 byte of VendorDefinedDescriptorData
573 	if (length < (sizeof(struct pldm_vendor_defined_descriptor_title_data) +
574 		      entry->vendor_defined_descriptor_title_str_len)) {
575 		return PLDM_ERROR_INVALID_LENGTH;
576 	}
577 
578 	*descriptor_title_str_type =
579 		entry->vendor_defined_descriptor_title_str_type;
580 	descriptor_title_str->ptr = entry->vendor_defined_descriptor_title_str;
581 	descriptor_title_str->length =
582 		entry->vendor_defined_descriptor_title_str_len;
583 
584 	descriptor_data->ptr =
585 		descriptor_title_str->ptr + descriptor_title_str->length;
586 	descriptor_data->length =
587 		length -
588 		sizeof(entry->vendor_defined_descriptor_title_str_type) -
589 		sizeof(entry->vendor_defined_descriptor_title_str_len) -
590 		descriptor_title_str->length;
591 
592 	return PLDM_SUCCESS;
593 }
594 
595 LIBPLDM_ABI_STABLE
596 int decode_pldm_comp_image_info(
597 	const uint8_t *data, size_t length,
598 	struct pldm_component_image_information *pldm_comp_image_info,
599 	struct variable_field *comp_version_str)
600 {
601 	if (data == NULL || pldm_comp_image_info == NULL ||
602 	    comp_version_str == NULL) {
603 		return PLDM_ERROR_INVALID_DATA;
604 	}
605 
606 	if (length < sizeof(struct pldm_component_image_information)) {
607 		return PLDM_ERROR_INVALID_LENGTH;
608 	}
609 
610 	struct pldm_component_image_information *data_header =
611 		(struct pldm_component_image_information *)(data);
612 
613 	if (!is_string_type_valid(data_header->comp_version_string_type) ||
614 	    (data_header->comp_version_string_length == 0)) {
615 		return PLDM_ERROR_INVALID_DATA;
616 	}
617 
618 	if (length < sizeof(struct pldm_component_image_information) +
619 			     data_header->comp_version_string_length) {
620 		return PLDM_ERROR_INVALID_LENGTH;
621 	}
622 
623 	pldm_comp_image_info->comp_classification =
624 		le16toh(data_header->comp_classification);
625 	pldm_comp_image_info->comp_identifier =
626 		le16toh(data_header->comp_identifier);
627 	pldm_comp_image_info->comp_comparison_stamp =
628 		le32toh(data_header->comp_comparison_stamp);
629 	pldm_comp_image_info->comp_options.value =
630 		le16toh(data_header->comp_options.value);
631 	pldm_comp_image_info->requested_comp_activation_method.value =
632 		le16toh(data_header->requested_comp_activation_method.value);
633 	pldm_comp_image_info->comp_location_offset =
634 		le32toh(data_header->comp_location_offset);
635 	pldm_comp_image_info->comp_size = le32toh(data_header->comp_size);
636 	pldm_comp_image_info->comp_version_string_type =
637 		data_header->comp_version_string_type;
638 	pldm_comp_image_info->comp_version_string_length =
639 		data_header->comp_version_string_length;
640 
641 	if ((pldm_comp_image_info->comp_options.bits.bit1 == false &&
642 	     pldm_comp_image_info->comp_comparison_stamp !=
643 		     PLDM_FWUP_INVALID_COMPONENT_COMPARISON_TIMESTAMP)) {
644 		return PLDM_ERROR_INVALID_DATA;
645 	}
646 
647 	if (pldm_comp_image_info->comp_location_offset == 0 ||
648 	    pldm_comp_image_info->comp_size == 0) {
649 		return PLDM_ERROR_INVALID_DATA;
650 	}
651 
652 	comp_version_str->ptr =
653 		data + sizeof(struct pldm_component_image_information);
654 	comp_version_str->length =
655 		pldm_comp_image_info->comp_version_string_length;
656 
657 	return PLDM_SUCCESS;
658 }
659 
660 LIBPLDM_ABI_STABLE
661 int encode_query_device_identifiers_req(uint8_t instance_id,
662 					size_t payload_length,
663 					struct pldm_msg *msg)
664 {
665 	if (msg == NULL) {
666 		return PLDM_ERROR_INVALID_DATA;
667 	}
668 
669 	if (payload_length != PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES) {
670 		return PLDM_ERROR_INVALID_LENGTH;
671 	}
672 
673 	return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
674 				       PLDM_QUERY_DEVICE_IDENTIFIERS, msg);
675 }
676 
677 LIBPLDM_ABI_STABLE
678 int decode_query_device_identifiers_resp(const struct pldm_msg *msg,
679 					 size_t payload_length,
680 					 uint8_t *completion_code,
681 					 uint32_t *device_identifiers_len,
682 					 uint8_t *descriptor_count,
683 					 uint8_t **descriptor_data)
684 {
685 	if (msg == NULL || completion_code == NULL ||
686 	    device_identifiers_len == NULL || descriptor_count == NULL ||
687 	    descriptor_data == NULL) {
688 		return PLDM_ERROR_INVALID_DATA;
689 	}
690 
691 	*completion_code = msg->payload[0];
692 	if (PLDM_SUCCESS != *completion_code) {
693 		return PLDM_SUCCESS;
694 	}
695 
696 	if (payload_length <
697 	    sizeof(struct pldm_query_device_identifiers_resp)) {
698 		return PLDM_ERROR_INVALID_LENGTH;
699 	}
700 
701 	struct pldm_query_device_identifiers_resp *response =
702 		(struct pldm_query_device_identifiers_resp *)msg->payload;
703 	*device_identifiers_len = le32toh(response->device_identifiers_len);
704 
705 	if (*device_identifiers_len < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {
706 		return PLDM_ERROR_INVALID_LENGTH;
707 	}
708 
709 	if (payload_length !=
710 	    sizeof(struct pldm_query_device_identifiers_resp) +
711 		    *device_identifiers_len) {
712 		return PLDM_ERROR_INVALID_LENGTH;
713 	}
714 	*descriptor_count = response->descriptor_count;
715 
716 	if (*descriptor_count == 0) {
717 		return PLDM_ERROR_INVALID_DATA;
718 	}
719 	*descriptor_data =
720 		(uint8_t *)(msg->payload +
721 			    sizeof(struct pldm_query_device_identifiers_resp));
722 	return PLDM_SUCCESS;
723 }
724 
725 LIBPLDM_ABI_STABLE
726 int encode_get_firmware_parameters_req(uint8_t instance_id,
727 				       size_t payload_length,
728 				       struct pldm_msg *msg)
729 {
730 	if (msg == NULL) {
731 		return PLDM_ERROR_INVALID_DATA;
732 	}
733 
734 	if (payload_length != PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES) {
735 		return PLDM_ERROR_INVALID_LENGTH;
736 	}
737 
738 	return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
739 				       PLDM_GET_FIRMWARE_PARAMETERS, msg);
740 }
741 
742 LIBPLDM_ABI_STABLE
743 int decode_get_firmware_parameters_resp(
744 	const struct pldm_msg *msg, size_t payload_length,
745 	struct pldm_get_firmware_parameters_resp *resp_data,
746 	struct variable_field *active_comp_image_set_ver_str,
747 	struct variable_field *pending_comp_image_set_ver_str,
748 	struct variable_field *comp_parameter_table)
749 {
750 	if (msg == NULL || resp_data == NULL ||
751 	    active_comp_image_set_ver_str == NULL ||
752 	    pending_comp_image_set_ver_str == NULL ||
753 	    comp_parameter_table == NULL || !payload_length) {
754 		return PLDM_ERROR_INVALID_DATA;
755 	}
756 
757 	resp_data->completion_code = msg->payload[0];
758 	if (PLDM_SUCCESS != resp_data->completion_code) {
759 		return PLDM_SUCCESS;
760 	}
761 
762 	if (payload_length < sizeof(struct pldm_get_firmware_parameters_resp)) {
763 		return PLDM_ERROR_INVALID_LENGTH;
764 	}
765 
766 	struct pldm_get_firmware_parameters_resp *response =
767 		(struct pldm_get_firmware_parameters_resp *)msg->payload;
768 
769 	if (!is_string_type_valid(
770 		    response->active_comp_image_set_ver_str_type) ||
771 	    (response->active_comp_image_set_ver_str_len == 0)) {
772 		return PLDM_ERROR_INVALID_DATA;
773 	}
774 
775 	if (response->pending_comp_image_set_ver_str_len == 0) {
776 		if (response->pending_comp_image_set_ver_str_type !=
777 		    PLDM_STR_TYPE_UNKNOWN) {
778 			return PLDM_ERROR_INVALID_DATA;
779 		}
780 	} else {
781 		if (!is_string_type_valid(
782 			    response->pending_comp_image_set_ver_str_type)) {
783 			return PLDM_ERROR_INVALID_DATA;
784 		}
785 	}
786 
787 	size_t partial_response_length =
788 		sizeof(struct pldm_get_firmware_parameters_resp) +
789 		response->active_comp_image_set_ver_str_len +
790 		response->pending_comp_image_set_ver_str_len;
791 
792 	if (payload_length < partial_response_length) {
793 		return PLDM_ERROR_INVALID_LENGTH;
794 	}
795 
796 	resp_data->capabilities_during_update.value =
797 		le32toh(response->capabilities_during_update.value);
798 	resp_data->comp_count = le16toh(response->comp_count);
799 	resp_data->active_comp_image_set_ver_str_type =
800 		response->active_comp_image_set_ver_str_type;
801 	resp_data->active_comp_image_set_ver_str_len =
802 		response->active_comp_image_set_ver_str_len;
803 	resp_data->pending_comp_image_set_ver_str_type =
804 		response->pending_comp_image_set_ver_str_type;
805 	resp_data->pending_comp_image_set_ver_str_len =
806 		response->pending_comp_image_set_ver_str_len;
807 
808 	active_comp_image_set_ver_str->ptr =
809 		msg->payload + sizeof(struct pldm_get_firmware_parameters_resp);
810 	active_comp_image_set_ver_str->length =
811 		resp_data->active_comp_image_set_ver_str_len;
812 
813 	if (resp_data->pending_comp_image_set_ver_str_len != 0) {
814 		pending_comp_image_set_ver_str->ptr =
815 			msg->payload +
816 			sizeof(struct pldm_get_firmware_parameters_resp) +
817 			resp_data->active_comp_image_set_ver_str_len;
818 		pending_comp_image_set_ver_str->length =
819 			resp_data->pending_comp_image_set_ver_str_len;
820 	} else {
821 		pending_comp_image_set_ver_str->ptr = NULL;
822 		pending_comp_image_set_ver_str->length = 0;
823 	}
824 
825 	if (payload_length > partial_response_length && resp_data->comp_count) {
826 		comp_parameter_table->ptr =
827 			msg->payload +
828 			sizeof(struct pldm_get_firmware_parameters_resp) +
829 			resp_data->active_comp_image_set_ver_str_len +
830 			resp_data->pending_comp_image_set_ver_str_len;
831 		comp_parameter_table->length =
832 			payload_length - partial_response_length;
833 	} else {
834 		comp_parameter_table->ptr = NULL;
835 		comp_parameter_table->length = 0;
836 	}
837 
838 	return PLDM_SUCCESS;
839 }
840 
841 LIBPLDM_ABI_STABLE
842 int decode_get_firmware_parameters_resp_comp_entry(
843 	const uint8_t *data, size_t length,
844 	struct pldm_component_parameter_entry *component_data,
845 	struct variable_field *active_comp_ver_str,
846 	struct variable_field *pending_comp_ver_str)
847 {
848 	if (data == NULL || component_data == NULL ||
849 	    active_comp_ver_str == NULL || pending_comp_ver_str == NULL) {
850 		return PLDM_ERROR_INVALID_DATA;
851 	}
852 
853 	if (length < sizeof(struct pldm_component_parameter_entry)) {
854 		return PLDM_ERROR_INVALID_LENGTH;
855 	}
856 
857 	struct pldm_component_parameter_entry *entry =
858 		(struct pldm_component_parameter_entry *)(data);
859 
860 	size_t entry_length = sizeof(struct pldm_component_parameter_entry) +
861 			      entry->active_comp_ver_str_len +
862 			      entry->pending_comp_ver_str_len;
863 
864 	if (length < entry_length) {
865 		return PLDM_ERROR_INVALID_LENGTH;
866 	}
867 
868 	component_data->comp_classification =
869 		le16toh(entry->comp_classification);
870 	component_data->comp_identifier = le16toh(entry->comp_identifier);
871 	component_data->comp_classification_index =
872 		entry->comp_classification_index;
873 	component_data->active_comp_comparison_stamp =
874 		le32toh(entry->active_comp_comparison_stamp);
875 	component_data->active_comp_ver_str_type =
876 		entry->active_comp_ver_str_type;
877 	component_data->active_comp_ver_str_len =
878 		entry->active_comp_ver_str_len;
879 	memcpy(component_data->active_comp_release_date,
880 	       entry->active_comp_release_date,
881 	       sizeof(entry->active_comp_release_date));
882 	component_data->pending_comp_comparison_stamp =
883 		le32toh(entry->pending_comp_comparison_stamp);
884 	component_data->pending_comp_ver_str_type =
885 		entry->pending_comp_ver_str_type;
886 	component_data->pending_comp_ver_str_len =
887 		entry->pending_comp_ver_str_len;
888 	memcpy(component_data->pending_comp_release_date,
889 	       entry->pending_comp_release_date,
890 	       sizeof(entry->pending_comp_release_date));
891 	component_data->comp_activation_methods.value =
892 		le16toh(entry->comp_activation_methods.value);
893 	component_data->capabilities_during_update.value =
894 		le32toh(entry->capabilities_during_update.value);
895 
896 	if (entry->active_comp_ver_str_len != 0) {
897 		active_comp_ver_str->ptr =
898 			data + sizeof(struct pldm_component_parameter_entry);
899 		active_comp_ver_str->length = entry->active_comp_ver_str_len;
900 	} else {
901 		active_comp_ver_str->ptr = NULL;
902 		active_comp_ver_str->length = 0;
903 	}
904 
905 	if (entry->pending_comp_ver_str_len != 0) {
906 		pending_comp_ver_str->ptr =
907 			data + sizeof(struct pldm_component_parameter_entry) +
908 			entry->active_comp_ver_str_len;
909 		pending_comp_ver_str->length = entry->pending_comp_ver_str_len;
910 	} else {
911 		pending_comp_ver_str->ptr = NULL;
912 		pending_comp_ver_str->length = 0;
913 	}
914 	return PLDM_SUCCESS;
915 }
916 
917 LIBPLDM_ABI_TESTING
918 int encode_query_downstream_devices_req(uint8_t instance_id,
919 					struct pldm_msg *msg)
920 {
921 	if (msg == NULL) {
922 		return -EINVAL;
923 	}
924 
925 	return encode_pldm_header_only_errno(PLDM_REQUEST, instance_id,
926 					     PLDM_FWUP,
927 					     PLDM_QUERY_DOWNSTREAM_DEVICES,
928 					     msg);
929 }
930 
931 LIBPLDM_ABI_TESTING
932 int decode_query_downstream_devices_resp(
933 	const struct pldm_msg *msg, size_t payload_length,
934 	struct pldm_query_downstream_devices_resp *resp_data)
935 {
936 	struct pldm_msgbuf _buf;
937 	struct pldm_msgbuf *buf = &_buf;
938 	int rc;
939 
940 	if (msg == NULL || resp_data == NULL || !payload_length) {
941 		return -EINVAL;
942 	}
943 
944 	rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
945 				    msg->payload, payload_length);
946 	if (rc) {
947 		return rc;
948 	}
949 
950 	rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
951 	if (rc) {
952 		return rc;
953 	}
954 	if (PLDM_SUCCESS != resp_data->completion_code) {
955 		// Return the CC directly without decoding the rest of the payload
956 		return 0;
957 	}
958 
959 	if (payload_length < PLDM_QUERY_DOWNSTREAM_DEVICES_RESP_BYTES) {
960 		return -EBADMSG;
961 	}
962 
963 	rc = pldm_msgbuf_extract(buf,
964 				 resp_data->downstream_device_update_supported);
965 	if (rc) {
966 		return rc;
967 	}
968 
969 	if (!is_downstream_device_update_support_valid(
970 		    resp_data->downstream_device_update_supported)) {
971 		return -EINVAL;
972 	}
973 
974 	pldm_msgbuf_extract(buf, resp_data->number_of_downstream_devices);
975 	pldm_msgbuf_extract(buf, resp_data->max_number_of_downstream_devices);
976 	pldm_msgbuf_extract(buf, resp_data->capabilities.value);
977 
978 	return pldm_msgbuf_destroy_consumed(buf);
979 }
980 
981 LIBPLDM_ABI_TESTING
982 int encode_query_downstream_identifiers_req(
983 	uint8_t instance_id,
984 	const struct pldm_query_downstream_identifiers_req *params_req,
985 	struct pldm_msg *msg, size_t payload_length)
986 {
987 	struct pldm_msgbuf _buf;
988 	struct pldm_msgbuf *buf = &_buf;
989 	int rc;
990 
991 	if (!msg || !params_req) {
992 		return -EINVAL;
993 	}
994 
995 	if (!is_transfer_operation_flag_valid(
996 		    (enum transfer_op_flag)
997 			    params_req->transfer_operation_flag)) {
998 		return -EINVAL;
999 	}
1000 
1001 	struct pldm_header_info header = { 0 };
1002 	header.instance = instance_id;
1003 	header.msg_type = PLDM_REQUEST;
1004 	header.pldm_type = PLDM_FWUP;
1005 	header.command = PLDM_QUERY_DOWNSTREAM_IDENTIFIERS;
1006 	rc = pack_pldm_header_errno(&header, &(msg->hdr));
1007 	if (rc) {
1008 		return rc;
1009 	}
1010 
1011 	rc = pldm_msgbuf_init_errno(buf,
1012 				    PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_REQ_BYTES,
1013 				    msg->payload, payload_length);
1014 	if (rc) {
1015 		return rc;
1016 	}
1017 
1018 	pldm_msgbuf_insert(buf, params_req->data_transfer_handle);
1019 	// Data correctness has been verified, cast it to 1-byte data directly.
1020 	pldm_msgbuf_insert(buf, params_req->transfer_operation_flag);
1021 
1022 	return pldm_msgbuf_destroy(buf);
1023 }
1024 
1025 LIBPLDM_ABI_TESTING
1026 int decode_query_downstream_identifiers_resp(
1027 	const struct pldm_msg *msg, size_t payload_length,
1028 	struct pldm_query_downstream_identifiers_resp *resp_data,
1029 	struct pldm_downstream_device_iter *iter)
1030 {
1031 	struct pldm_msgbuf _buf;
1032 	struct pldm_msgbuf *buf = &_buf;
1033 	void *remaining = NULL;
1034 	int rc = 0;
1035 
1036 	if (msg == NULL || resp_data == NULL || iter == NULL ||
1037 	    !payload_length) {
1038 		return -EINVAL;
1039 	}
1040 
1041 	rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1042 				    msg->payload, payload_length);
1043 	if (rc) {
1044 		return rc;
1045 	}
1046 
1047 	rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1048 	if (rc) {
1049 		return rc;
1050 	}
1051 	if (PLDM_SUCCESS != resp_data->completion_code) {
1052 		return 0;
1053 	}
1054 
1055 	if (payload_length < PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_RESP_MIN_LEN) {
1056 		return -EBADMSG;
1057 	}
1058 
1059 	pldm_msgbuf_extract(buf, resp_data->next_data_transfer_handle);
1060 	pldm_msgbuf_extract(buf, resp_data->transfer_flag);
1061 
1062 	rc = pldm_msgbuf_extract(buf, resp_data->downstream_devices_length);
1063 	if (rc) {
1064 		return rc;
1065 	}
1066 
1067 	pldm_msgbuf_extract(buf, resp_data->number_of_downstream_devices);
1068 	rc = pldm_msgbuf_span_required(
1069 		buf, resp_data->downstream_devices_length, &remaining);
1070 	if (rc) {
1071 		return rc;
1072 	}
1073 
1074 	rc = pldm_msgbuf_destroy(buf);
1075 	if (rc) {
1076 		return rc;
1077 	}
1078 
1079 	iter->field.ptr = remaining;
1080 	iter->field.length = resp_data->downstream_devices_length;
1081 	iter->devs = resp_data->number_of_downstream_devices;
1082 
1083 	return 0;
1084 }
1085 
1086 LIBPLDM_ABI_TESTING
1087 int decode_pldm_downstream_device_from_iter(
1088 	struct pldm_downstream_device_iter *iter,
1089 	struct pldm_downstream_device *dev)
1090 {
1091 	struct pldm_msgbuf _buf;
1092 	struct pldm_msgbuf *buf = &_buf;
1093 	int rc;
1094 
1095 	if (!iter || !dev) {
1096 		return -EINVAL;
1097 	}
1098 
1099 	rc = pldm_msgbuf_init_errno(buf, 3, iter->field.ptr,
1100 				    iter->field.length);
1101 	if (rc) {
1102 		return rc;
1103 	}
1104 
1105 	pldm_msgbuf_extract(buf, dev->downstream_device_index);
1106 	pldm_msgbuf_extract(buf, dev->downstream_descriptor_count);
1107 	iter->field.ptr = NULL;
1108 	pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
1109 				   &iter->field.length);
1110 
1111 	return pldm_msgbuf_destroy(buf);
1112 }
1113 
1114 LIBPLDM_ABI_TESTING
1115 int encode_get_downstream_firmware_params_req(
1116 	uint8_t instance_id,
1117 	const struct pldm_get_downstream_firmware_params_req *params_req,
1118 	struct pldm_msg *msg, size_t payload_length)
1119 {
1120 	struct pldm_msgbuf _buf;
1121 	struct pldm_msgbuf *buf = &_buf;
1122 	int rc;
1123 
1124 	if (!msg || !params_req) {
1125 		return -EINVAL;
1126 	}
1127 
1128 	rc = pldm_msgbuf_init_errno(
1129 		buf, PLDM_GET_DOWNSTREAM_FIRMWARE_PARAMS_REQ_BYTES,
1130 		msg->payload, payload_length);
1131 	if (rc < 0) {
1132 		return rc;
1133 	}
1134 
1135 	if (!is_transfer_operation_flag_valid(
1136 		    (enum transfer_op_flag)
1137 			    params_req->transfer_operation_flag)) {
1138 		return -EBADMSG;
1139 	}
1140 
1141 	struct pldm_header_info header = { 0 };
1142 	header.instance = instance_id;
1143 	header.msg_type = PLDM_REQUEST;
1144 	header.pldm_type = PLDM_FWUP;
1145 	header.command = PLDM_QUERY_DOWNSTREAM_FIRMWARE_PARAMETERS;
1146 	rc = pack_pldm_header_errno(&header, &msg->hdr);
1147 	if (rc < 0) {
1148 		return rc;
1149 	}
1150 
1151 	pldm_msgbuf_insert(buf, params_req->data_transfer_handle);
1152 	// Data correctness has been verified, cast it to 1-byte data directly.
1153 	pldm_msgbuf_insert(buf, params_req->transfer_operation_flag);
1154 
1155 	return pldm_msgbuf_destroy(buf);
1156 }
1157 
1158 LIBPLDM_ABI_TESTING
1159 int decode_get_downstream_firmware_params_resp(
1160 	const struct pldm_msg *msg, size_t payload_length,
1161 	struct pldm_get_downstream_firmware_params_resp *resp_data,
1162 	struct variable_field *downstream_device_param_table)
1163 {
1164 	struct pldm_msgbuf _buf;
1165 	struct pldm_msgbuf *buf = &_buf;
1166 	int rc;
1167 
1168 	if (msg == NULL || resp_data == NULL ||
1169 	    downstream_device_param_table == NULL) {
1170 		return -EINVAL;
1171 	}
1172 
1173 	rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1174 				    msg->payload, payload_length);
1175 	if (rc < 0) {
1176 		return rc;
1177 	}
1178 
1179 	rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1180 	if (rc < 0) {
1181 		return rc;
1182 	}
1183 	if (PLDM_SUCCESS != resp_data->completion_code) {
1184 		return 0;
1185 	}
1186 
1187 	if (payload_length < PLDM_GET_DOWNSTREAM_FIRMWARE_PARAMS_RESP_MIN_LEN) {
1188 		return -EBADMSG;
1189 	}
1190 
1191 	pldm_msgbuf_extract(buf, resp_data->next_data_transfer_handle);
1192 	pldm_msgbuf_extract(buf, resp_data->transfer_flag);
1193 	pldm_msgbuf_extract(buf,
1194 			    resp_data->fdp_capabilities_during_update.value);
1195 	pldm_msgbuf_extract(buf, resp_data->downstream_device_count);
1196 
1197 	return pldm_msgbuf_span_remaining(
1198 		buf, (void **)&downstream_device_param_table->ptr,
1199 		&downstream_device_param_table->length);
1200 }
1201 
1202 LIBPLDM_ABI_TESTING
1203 int decode_downstream_device_parameter_table_entry(
1204 	struct variable_field *data,
1205 	struct pldm_downstream_device_parameter_entry *entry,
1206 	struct variable_field *versions)
1207 {
1208 	struct pldm_msgbuf _buf;
1209 	struct pldm_msgbuf *buf = &_buf;
1210 	void *cursor = NULL;
1211 	size_t remaining;
1212 	int rc;
1213 
1214 	if (data == NULL || entry == NULL || versions == NULL) {
1215 		return -EINVAL;
1216 	}
1217 
1218 	rc = pldm_msgbuf_init_errno(
1219 		buf, PLDM_DOWNSTREAM_DEVICE_PARAMETER_ENTRY_MIN_LEN, data->ptr,
1220 		data->length);
1221 	if (rc < 0) {
1222 		return rc;
1223 	}
1224 
1225 	pldm_msgbuf_extract(buf, entry->downstream_device_index);
1226 	pldm_msgbuf_extract(buf, entry->active_comp_comparison_stamp);
1227 	pldm_msgbuf_extract(buf, entry->active_comp_ver_str_type);
1228 	rc = pldm_msgbuf_extract(buf, entry->active_comp_ver_str_len);
1229 	if (rc < 0) {
1230 		return rc;
1231 	}
1232 	rc = pldm_msgbuf_extract_array(buf,
1233 				       PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1234 				       entry->active_comp_release_date,
1235 				       sizeof(entry->active_comp_release_date));
1236 	if (rc < 0) {
1237 		return rc;
1238 	}
1239 
1240 	// Fill the last byte with NULL character
1241 	entry->active_comp_release_date[PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN] =
1242 		'\0';
1243 
1244 	pldm_msgbuf_extract(buf, entry->pending_comp_comparison_stamp);
1245 	pldm_msgbuf_extract(buf, entry->pending_comp_ver_str_type);
1246 	rc = pldm_msgbuf_extract(buf, entry->pending_comp_ver_str_len);
1247 	if (rc < 0) {
1248 		return rc;
1249 	}
1250 
1251 	rc = pldm_msgbuf_extract_array(
1252 		buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1253 		entry->pending_comp_release_date,
1254 		sizeof(entry->pending_comp_release_date));
1255 	if (rc < 0) {
1256 		return rc;
1257 	}
1258 
1259 	// Fill the last byte with NULL character
1260 	entry->pending_comp_release_date[PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN] =
1261 		'\0';
1262 
1263 	pldm_msgbuf_extract(buf, entry->comp_activation_methods.value);
1264 	pldm_msgbuf_extract(buf, entry->capabilities_during_update.value);
1265 	const size_t versions_len = entry->active_comp_ver_str_len +
1266 				    entry->pending_comp_ver_str_len;
1267 	rc = pldm_msgbuf_span_required(buf, versions_len,
1268 				       (void **)&versions->ptr);
1269 	if (rc < 0) {
1270 		return rc;
1271 	}
1272 	versions->length = versions_len;
1273 
1274 	rc = pldm_msgbuf_span_remaining(buf, &cursor, &remaining);
1275 	if (rc < 0) {
1276 		return rc;
1277 	}
1278 
1279 	data->ptr = cursor;
1280 	data->length = remaining;
1281 
1282 	return 0;
1283 }
1284 
1285 LIBPLDM_ABI_TESTING
1286 int decode_downstream_device_parameter_table_entry_versions(
1287 	const struct variable_field *versions,
1288 	struct pldm_downstream_device_parameter_entry *entry, char *active,
1289 	size_t active_len, char *pending, size_t pending_len)
1290 {
1291 	struct pldm_msgbuf _buf;
1292 	struct pldm_msgbuf *buf = &_buf;
1293 	int rc;
1294 
1295 	if (versions == NULL || versions->ptr == NULL || !versions->length ||
1296 	    entry == NULL || active == NULL || pending == NULL) {
1297 		return -EINVAL;
1298 	}
1299 
1300 	if (!active_len || active_len - 1 < entry->active_comp_ver_str_len) {
1301 		return -EOVERFLOW;
1302 	}
1303 
1304 	if (!pending_len || pending_len - 1 < entry->pending_comp_ver_str_len) {
1305 		return -EOVERFLOW;
1306 	}
1307 
1308 	/* This API should be called after decode_downstream_device_parameter_table_entry
1309 	 * has successfully decoded the entry, assume the entry data is valid here.
1310 	 */
1311 	const size_t versions_len = entry->active_comp_ver_str_len +
1312 				    entry->pending_comp_ver_str_len;
1313 	rc = pldm_msgbuf_init_errno(buf, versions_len, versions->ptr,
1314 				    versions->length);
1315 	if (rc < 0) {
1316 		return rc;
1317 	}
1318 
1319 	rc = pldm_msgbuf_extract_array(buf, entry->active_comp_ver_str_len,
1320 				       active, active_len);
1321 	if (rc < 0) {
1322 		return rc;
1323 	}
1324 
1325 	active[entry->active_comp_ver_str_len] = '\0';
1326 	rc = pldm_msgbuf_extract_array(buf, entry->pending_comp_ver_str_len,
1327 				       pending, pending_len);
1328 	if (rc < 0) {
1329 		return rc;
1330 	}
1331 
1332 	pending[entry->pending_comp_ver_str_len] = '\0';
1333 
1334 	entry->active_comp_ver_str = active;
1335 	entry->pending_comp_ver_str = pending;
1336 
1337 	return pldm_msgbuf_destroy_consumed(buf);
1338 }
1339 
1340 LIBPLDM_ABI_STABLE
1341 int encode_request_update_req(uint8_t instance_id, uint32_t max_transfer_size,
1342 			      uint16_t num_of_comp,
1343 			      uint8_t max_outstanding_transfer_req,
1344 			      uint16_t pkg_data_len,
1345 			      uint8_t comp_image_set_ver_str_type,
1346 			      uint8_t comp_image_set_ver_str_len,
1347 			      const struct variable_field *comp_img_set_ver_str,
1348 			      struct pldm_msg *msg, size_t payload_length)
1349 {
1350 	if (comp_img_set_ver_str == NULL || comp_img_set_ver_str->ptr == NULL ||
1351 	    msg == NULL) {
1352 		return PLDM_ERROR_INVALID_DATA;
1353 	}
1354 
1355 	if (payload_length != sizeof(struct pldm_request_update_req) +
1356 				      comp_img_set_ver_str->length) {
1357 		return PLDM_ERROR_INVALID_LENGTH;
1358 	}
1359 
1360 	if ((comp_image_set_ver_str_len == 0) ||
1361 	    (comp_image_set_ver_str_len != comp_img_set_ver_str->length)) {
1362 		return PLDM_ERROR_INVALID_DATA;
1363 	}
1364 
1365 	if ((max_transfer_size < PLDM_FWUP_BASELINE_TRANSFER_SIZE) ||
1366 	    (max_outstanding_transfer_req < PLDM_FWUP_MIN_OUTSTANDING_REQ)) {
1367 		return PLDM_ERROR_INVALID_DATA;
1368 	}
1369 
1370 	if (!is_string_type_valid(comp_image_set_ver_str_type)) {
1371 		return PLDM_ERROR_INVALID_DATA;
1372 	}
1373 
1374 	struct pldm_header_info header = { 0 };
1375 	header.instance = instance_id;
1376 	header.msg_type = PLDM_REQUEST;
1377 	header.pldm_type = PLDM_FWUP;
1378 	header.command = PLDM_REQUEST_UPDATE;
1379 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1380 	if (rc) {
1381 		return rc;
1382 	}
1383 
1384 	struct pldm_request_update_req *request =
1385 		(struct pldm_request_update_req *)msg->payload;
1386 
1387 	request->max_transfer_size = htole32(max_transfer_size);
1388 	request->num_of_comp = htole16(num_of_comp);
1389 	request->max_outstanding_transfer_req = max_outstanding_transfer_req;
1390 	request->pkg_data_len = htole16(pkg_data_len);
1391 	request->comp_image_set_ver_str_type = comp_image_set_ver_str_type;
1392 	request->comp_image_set_ver_str_len = comp_image_set_ver_str_len;
1393 
1394 	memcpy(msg->payload + sizeof(struct pldm_request_update_req),
1395 	       comp_img_set_ver_str->ptr, comp_img_set_ver_str->length);
1396 
1397 	return PLDM_SUCCESS;
1398 }
1399 
1400 LIBPLDM_ABI_STABLE
1401 int decode_request_update_resp(const struct pldm_msg *msg,
1402 			       size_t payload_length, uint8_t *completion_code,
1403 			       uint16_t *fd_meta_data_len,
1404 			       uint8_t *fd_will_send_pkg_data)
1405 {
1406 	if (msg == NULL || completion_code == NULL ||
1407 	    fd_meta_data_len == NULL || fd_will_send_pkg_data == NULL ||
1408 	    !payload_length) {
1409 		return PLDM_ERROR_INVALID_DATA;
1410 	}
1411 
1412 	*completion_code = msg->payload[0];
1413 	if (*completion_code != PLDM_SUCCESS) {
1414 		return PLDM_SUCCESS;
1415 	}
1416 
1417 	if (payload_length != sizeof(struct pldm_request_update_resp)) {
1418 		return PLDM_ERROR_INVALID_LENGTH;
1419 	}
1420 
1421 	struct pldm_request_update_resp *response =
1422 		(struct pldm_request_update_resp *)msg->payload;
1423 
1424 	*fd_meta_data_len = le16toh(response->fd_meta_data_len);
1425 	*fd_will_send_pkg_data = response->fd_will_send_pkg_data;
1426 
1427 	return PLDM_SUCCESS;
1428 }
1429 
1430 LIBPLDM_ABI_STABLE
1431 int encode_pass_component_table_req(uint8_t instance_id, uint8_t transfer_flag,
1432 				    uint16_t comp_classification,
1433 				    uint16_t comp_identifier,
1434 				    uint8_t comp_classification_index,
1435 				    uint32_t comp_comparison_stamp,
1436 				    uint8_t comp_ver_str_type,
1437 				    uint8_t comp_ver_str_len,
1438 				    const struct variable_field *comp_ver_str,
1439 				    struct pldm_msg *msg, size_t payload_length)
1440 {
1441 	if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) {
1442 		return PLDM_ERROR_INVALID_DATA;
1443 	}
1444 
1445 	if (payload_length != sizeof(struct pldm_pass_component_table_req) +
1446 				      comp_ver_str->length) {
1447 		return PLDM_ERROR_INVALID_LENGTH;
1448 	}
1449 
1450 	if ((comp_ver_str_len == 0) ||
1451 	    (comp_ver_str_len != comp_ver_str->length)) {
1452 		return PLDM_ERROR_INVALID_DATA;
1453 	}
1454 
1455 	if (!is_transfer_flag_valid(transfer_flag)) {
1456 		return PLDM_INVALID_TRANSFER_OPERATION_FLAG;
1457 	}
1458 
1459 	if (!is_string_type_valid(comp_ver_str_type)) {
1460 		return PLDM_ERROR_INVALID_DATA;
1461 	}
1462 
1463 	struct pldm_header_info header = { 0 };
1464 	header.instance = instance_id;
1465 	header.msg_type = PLDM_REQUEST;
1466 	header.pldm_type = PLDM_FWUP;
1467 	header.command = PLDM_PASS_COMPONENT_TABLE;
1468 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1469 	if (rc) {
1470 		return rc;
1471 	}
1472 
1473 	struct pldm_pass_component_table_req *request =
1474 		(struct pldm_pass_component_table_req *)msg->payload;
1475 
1476 	request->transfer_flag = transfer_flag;
1477 	request->comp_classification = htole16(comp_classification);
1478 	request->comp_identifier = htole16(comp_identifier);
1479 	request->comp_classification_index = comp_classification_index;
1480 	request->comp_comparison_stamp = htole32(comp_comparison_stamp);
1481 	request->comp_ver_str_type = comp_ver_str_type;
1482 	request->comp_ver_str_len = comp_ver_str_len;
1483 
1484 	memcpy(msg->payload + sizeof(struct pldm_pass_component_table_req),
1485 	       comp_ver_str->ptr, comp_ver_str->length);
1486 
1487 	return PLDM_SUCCESS;
1488 }
1489 
1490 LIBPLDM_ABI_STABLE
1491 int decode_pass_component_table_resp(const struct pldm_msg *msg,
1492 				     const size_t payload_length,
1493 				     uint8_t *completion_code,
1494 				     uint8_t *comp_resp,
1495 				     uint8_t *comp_resp_code)
1496 {
1497 	if (msg == NULL || completion_code == NULL || comp_resp == NULL ||
1498 	    comp_resp_code == NULL || !payload_length) {
1499 		return PLDM_ERROR_INVALID_DATA;
1500 	}
1501 
1502 	*completion_code = msg->payload[0];
1503 	if (*completion_code != PLDM_SUCCESS) {
1504 		return PLDM_SUCCESS;
1505 	}
1506 
1507 	if (payload_length != sizeof(struct pldm_pass_component_table_resp)) {
1508 		return PLDM_ERROR_INVALID_LENGTH;
1509 	}
1510 
1511 	struct pldm_pass_component_table_resp *response =
1512 		(struct pldm_pass_component_table_resp *)msg->payload;
1513 
1514 	if (!is_comp_resp_valid(response->comp_resp)) {
1515 		return PLDM_ERROR_INVALID_DATA;
1516 	}
1517 
1518 	if (!is_comp_resp_code_valid(response->comp_resp_code)) {
1519 		return PLDM_ERROR_INVALID_DATA;
1520 	}
1521 
1522 	*comp_resp = response->comp_resp;
1523 	*comp_resp_code = response->comp_resp_code;
1524 
1525 	return PLDM_SUCCESS;
1526 }
1527 
1528 LIBPLDM_ABI_STABLE
1529 int encode_update_component_req(
1530 	uint8_t instance_id, uint16_t comp_classification,
1531 	uint16_t comp_identifier, uint8_t comp_classification_index,
1532 	uint32_t comp_comparison_stamp, uint32_t comp_image_size,
1533 	bitfield32_t update_option_flags, uint8_t comp_ver_str_type,
1534 	uint8_t comp_ver_str_len, const struct variable_field *comp_ver_str,
1535 	struct pldm_msg *msg, size_t payload_length)
1536 {
1537 	if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) {
1538 		return PLDM_ERROR_INVALID_DATA;
1539 	}
1540 
1541 	if (payload_length !=
1542 	    sizeof(struct pldm_update_component_req) + comp_ver_str->length) {
1543 		return PLDM_ERROR_INVALID_LENGTH;
1544 	}
1545 
1546 	if (!comp_image_size) {
1547 		return PLDM_ERROR_INVALID_DATA;
1548 	}
1549 
1550 	if ((comp_ver_str_len == 0) ||
1551 	    (comp_ver_str_len != comp_ver_str->length)) {
1552 		return PLDM_ERROR_INVALID_DATA;
1553 	}
1554 
1555 	if (!is_string_type_valid(comp_ver_str_type)) {
1556 		return PLDM_ERROR_INVALID_DATA;
1557 	}
1558 
1559 	struct pldm_header_info header = { 0 };
1560 	header.instance = instance_id;
1561 	header.msg_type = PLDM_REQUEST;
1562 	header.pldm_type = PLDM_FWUP;
1563 	header.command = PLDM_UPDATE_COMPONENT;
1564 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1565 	if (rc) {
1566 		return rc;
1567 	}
1568 
1569 	struct pldm_update_component_req *request =
1570 		(struct pldm_update_component_req *)msg->payload;
1571 
1572 	request->comp_classification = htole16(comp_classification);
1573 	request->comp_identifier = htole16(comp_identifier);
1574 	request->comp_classification_index = comp_classification_index;
1575 	request->comp_comparison_stamp = htole32(comp_comparison_stamp);
1576 	request->comp_image_size = htole32(comp_image_size);
1577 	request->update_option_flags.value = htole32(update_option_flags.value);
1578 	request->comp_ver_str_type = comp_ver_str_type;
1579 	request->comp_ver_str_len = comp_ver_str_len;
1580 
1581 	memcpy(msg->payload + sizeof(struct pldm_update_component_req),
1582 	       comp_ver_str->ptr, comp_ver_str->length);
1583 
1584 	return PLDM_SUCCESS;
1585 }
1586 
1587 LIBPLDM_ABI_STABLE
1588 int decode_update_component_resp(const struct pldm_msg *msg,
1589 				 size_t payload_length,
1590 				 uint8_t *completion_code,
1591 				 uint8_t *comp_compatibility_resp,
1592 				 uint8_t *comp_compatibility_resp_code,
1593 				 bitfield32_t *update_option_flags_enabled,
1594 				 uint16_t *time_before_req_fw_data)
1595 {
1596 	if (msg == NULL || completion_code == NULL ||
1597 	    comp_compatibility_resp == NULL ||
1598 	    comp_compatibility_resp_code == NULL ||
1599 	    update_option_flags_enabled == NULL ||
1600 	    time_before_req_fw_data == NULL || !payload_length) {
1601 		return PLDM_ERROR_INVALID_DATA;
1602 	}
1603 
1604 	*completion_code = msg->payload[0];
1605 	if (*completion_code != PLDM_SUCCESS) {
1606 		return PLDM_SUCCESS;
1607 	}
1608 
1609 	if (payload_length != sizeof(struct pldm_update_component_resp)) {
1610 		return PLDM_ERROR_INVALID_LENGTH;
1611 	}
1612 
1613 	struct pldm_update_component_resp *response =
1614 		(struct pldm_update_component_resp *)msg->payload;
1615 
1616 	if (!is_comp_compatibility_resp_valid(
1617 		    response->comp_compatibility_resp)) {
1618 		return PLDM_ERROR_INVALID_DATA;
1619 	}
1620 
1621 	if (!is_comp_compatibility_resp_code_valid(
1622 		    response->comp_compatibility_resp_code)) {
1623 		return PLDM_ERROR_INVALID_DATA;
1624 	}
1625 
1626 	*comp_compatibility_resp = response->comp_compatibility_resp;
1627 	*comp_compatibility_resp_code = response->comp_compatibility_resp_code;
1628 	update_option_flags_enabled->value =
1629 		le32toh(response->update_option_flags_enabled.value);
1630 	*time_before_req_fw_data = le16toh(response->time_before_req_fw_data);
1631 
1632 	return PLDM_SUCCESS;
1633 }
1634 
1635 LIBPLDM_ABI_STABLE
1636 int decode_request_firmware_data_req(const struct pldm_msg *msg,
1637 				     size_t payload_length, uint32_t *offset,
1638 				     uint32_t *length)
1639 {
1640 	if (msg == NULL || offset == NULL || length == NULL) {
1641 		return PLDM_ERROR_INVALID_DATA;
1642 	}
1643 	if (payload_length != sizeof(struct pldm_request_firmware_data_req)) {
1644 		return PLDM_ERROR_INVALID_LENGTH;
1645 	}
1646 	struct pldm_request_firmware_data_req *request =
1647 		(struct pldm_request_firmware_data_req *)msg->payload;
1648 	*offset = le32toh(request->offset);
1649 	*length = le32toh(request->length);
1650 
1651 	if (*length < PLDM_FWUP_BASELINE_TRANSFER_SIZE) {
1652 		return PLDM_FWUP_INVALID_TRANSFER_LENGTH;
1653 	}
1654 
1655 	return PLDM_SUCCESS;
1656 }
1657 
1658 LIBPLDM_ABI_STABLE
1659 int encode_request_firmware_data_resp(uint8_t instance_id,
1660 				      uint8_t completion_code,
1661 				      struct pldm_msg *msg,
1662 				      size_t payload_length)
1663 {
1664 	if (msg == NULL || !payload_length) {
1665 		return PLDM_ERROR_INVALID_DATA;
1666 	}
1667 
1668 	struct pldm_header_info header = { 0 };
1669 	header.instance = instance_id;
1670 	header.msg_type = PLDM_RESPONSE;
1671 	header.pldm_type = PLDM_FWUP;
1672 	header.command = PLDM_REQUEST_FIRMWARE_DATA;
1673 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1674 	if (rc) {
1675 		return rc;
1676 	}
1677 
1678 	msg->payload[0] = completion_code;
1679 
1680 	return PLDM_SUCCESS;
1681 }
1682 
1683 LIBPLDM_ABI_STABLE
1684 int decode_transfer_complete_req(const struct pldm_msg *msg,
1685 				 size_t payload_length,
1686 				 uint8_t *transfer_result)
1687 {
1688 	if (msg == NULL || transfer_result == NULL) {
1689 		return PLDM_ERROR_INVALID_DATA;
1690 	}
1691 
1692 	if (payload_length != sizeof(*transfer_result)) {
1693 		return PLDM_ERROR_INVALID_LENGTH;
1694 	}
1695 
1696 	*transfer_result = msg->payload[0];
1697 	return PLDM_SUCCESS;
1698 }
1699 
1700 LIBPLDM_ABI_STABLE
1701 int encode_transfer_complete_resp(uint8_t instance_id, uint8_t completion_code,
1702 				  struct pldm_msg *msg, size_t payload_length)
1703 {
1704 	if (msg == NULL) {
1705 		return PLDM_ERROR_INVALID_DATA;
1706 	}
1707 
1708 	if (payload_length != sizeof(completion_code)) {
1709 		return PLDM_ERROR_INVALID_LENGTH;
1710 	}
1711 
1712 	struct pldm_header_info header = { 0 };
1713 	header.instance = instance_id;
1714 	header.msg_type = PLDM_RESPONSE;
1715 	header.pldm_type = PLDM_FWUP;
1716 	header.command = PLDM_TRANSFER_COMPLETE;
1717 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1718 	if (rc) {
1719 		return rc;
1720 	}
1721 
1722 	msg->payload[0] = completion_code;
1723 
1724 	return PLDM_SUCCESS;
1725 }
1726 
1727 LIBPLDM_ABI_STABLE
1728 int decode_verify_complete_req(const struct pldm_msg *msg,
1729 			       size_t payload_length, uint8_t *verify_result)
1730 {
1731 	if (msg == NULL || verify_result == NULL) {
1732 		return PLDM_ERROR_INVALID_DATA;
1733 	}
1734 
1735 	if (payload_length != sizeof(*verify_result)) {
1736 		return PLDM_ERROR_INVALID_LENGTH;
1737 	}
1738 
1739 	*verify_result = msg->payload[0];
1740 	return PLDM_SUCCESS;
1741 }
1742 
1743 LIBPLDM_ABI_STABLE
1744 int encode_verify_complete_resp(uint8_t instance_id, uint8_t completion_code,
1745 				struct pldm_msg *msg, size_t payload_length)
1746 {
1747 	if (msg == NULL) {
1748 		return PLDM_ERROR_INVALID_DATA;
1749 	}
1750 
1751 	if (payload_length != sizeof(completion_code)) {
1752 		return PLDM_ERROR_INVALID_LENGTH;
1753 	}
1754 
1755 	struct pldm_header_info header = { 0 };
1756 	header.instance = instance_id;
1757 	header.msg_type = PLDM_RESPONSE;
1758 	header.pldm_type = PLDM_FWUP;
1759 	header.command = PLDM_VERIFY_COMPLETE;
1760 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1761 	if (rc) {
1762 		return rc;
1763 	}
1764 
1765 	msg->payload[0] = completion_code;
1766 
1767 	return PLDM_SUCCESS;
1768 }
1769 
1770 LIBPLDM_ABI_STABLE
1771 int decode_apply_complete_req(const struct pldm_msg *msg, size_t payload_length,
1772 			      uint8_t *apply_result,
1773 			      bitfield16_t *comp_activation_methods_modification)
1774 {
1775 	if (msg == NULL || apply_result == NULL ||
1776 	    comp_activation_methods_modification == NULL) {
1777 		return PLDM_ERROR_INVALID_DATA;
1778 	}
1779 
1780 	if (payload_length != sizeof(struct pldm_apply_complete_req)) {
1781 		return PLDM_ERROR_INVALID_LENGTH;
1782 	}
1783 
1784 	struct pldm_apply_complete_req *request =
1785 		(struct pldm_apply_complete_req *)msg->payload;
1786 
1787 	*apply_result = request->apply_result;
1788 	comp_activation_methods_modification->value =
1789 		le16toh(request->comp_activation_methods_modification.value);
1790 
1791 	if ((*apply_result != PLDM_FWUP_APPLY_SUCCESS_WITH_ACTIVATION_METHOD) &&
1792 	    comp_activation_methods_modification->value) {
1793 		return PLDM_ERROR_INVALID_DATA;
1794 	}
1795 
1796 	return PLDM_SUCCESS;
1797 }
1798 
1799 LIBPLDM_ABI_STABLE
1800 int encode_apply_complete_resp(uint8_t instance_id, uint8_t completion_code,
1801 			       struct pldm_msg *msg, size_t payload_length)
1802 {
1803 	if (msg == NULL) {
1804 		return PLDM_ERROR_INVALID_DATA;
1805 	}
1806 
1807 	if (payload_length != sizeof(completion_code)) {
1808 		return PLDM_ERROR_INVALID_LENGTH;
1809 	}
1810 
1811 	struct pldm_header_info header = { 0 };
1812 	header.instance = instance_id;
1813 	header.msg_type = PLDM_RESPONSE;
1814 	header.pldm_type = PLDM_FWUP;
1815 	header.command = PLDM_APPLY_COMPLETE;
1816 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1817 	if (rc) {
1818 		return rc;
1819 	}
1820 
1821 	msg->payload[0] = completion_code;
1822 
1823 	return PLDM_SUCCESS;
1824 }
1825 
1826 LIBPLDM_ABI_STABLE
1827 int encode_activate_firmware_req(uint8_t instance_id,
1828 				 bool8_t self_contained_activation_req,
1829 				 struct pldm_msg *msg, size_t payload_length)
1830 {
1831 	if (msg == NULL) {
1832 		return PLDM_ERROR_INVALID_DATA;
1833 	}
1834 
1835 	if (payload_length != sizeof(struct pldm_activate_firmware_req)) {
1836 		return PLDM_ERROR_INVALID_LENGTH;
1837 	}
1838 
1839 	if (!is_self_contained_activation_req_valid(
1840 		    self_contained_activation_req)) {
1841 		return PLDM_ERROR_INVALID_DATA;
1842 	}
1843 
1844 	struct pldm_header_info header = { 0 };
1845 	header.instance = instance_id;
1846 	header.msg_type = PLDM_REQUEST;
1847 	header.pldm_type = PLDM_FWUP;
1848 	header.command = PLDM_ACTIVATE_FIRMWARE;
1849 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1850 	if (rc) {
1851 		return rc;
1852 	}
1853 
1854 	struct pldm_activate_firmware_req *request =
1855 		(struct pldm_activate_firmware_req *)msg->payload;
1856 
1857 	request->self_contained_activation_req = self_contained_activation_req;
1858 
1859 	return PLDM_SUCCESS;
1860 }
1861 
1862 LIBPLDM_ABI_STABLE
1863 int decode_activate_firmware_resp(const struct pldm_msg *msg,
1864 				  size_t payload_length,
1865 				  uint8_t *completion_code,
1866 				  uint16_t *estimated_time_activation)
1867 {
1868 	if (msg == NULL || completion_code == NULL ||
1869 	    estimated_time_activation == NULL || !payload_length) {
1870 		return PLDM_ERROR_INVALID_DATA;
1871 	}
1872 
1873 	*completion_code = msg->payload[0];
1874 	if (*completion_code != PLDM_SUCCESS) {
1875 		return PLDM_SUCCESS;
1876 	}
1877 
1878 	if (payload_length != sizeof(struct pldm_activate_firmware_resp)) {
1879 		return PLDM_ERROR_INVALID_LENGTH;
1880 	}
1881 
1882 	struct pldm_activate_firmware_resp *response =
1883 		(struct pldm_activate_firmware_resp *)msg->payload;
1884 
1885 	*estimated_time_activation =
1886 		le16toh(response->estimated_time_activation);
1887 
1888 	return PLDM_SUCCESS;
1889 }
1890 
1891 LIBPLDM_ABI_STABLE
1892 int encode_get_status_req(uint8_t instance_id, struct pldm_msg *msg,
1893 			  size_t payload_length)
1894 {
1895 	if (msg == NULL) {
1896 		return PLDM_ERROR_INVALID_DATA;
1897 	}
1898 
1899 	if (payload_length != PLDM_GET_STATUS_REQ_BYTES) {
1900 		return PLDM_ERROR_INVALID_LENGTH;
1901 	}
1902 
1903 	struct pldm_header_info header = { 0 };
1904 	header.instance = instance_id;
1905 	header.msg_type = PLDM_REQUEST;
1906 	header.pldm_type = PLDM_FWUP;
1907 	header.command = PLDM_GET_STATUS;
1908 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1909 	if (rc) {
1910 		return rc;
1911 	}
1912 
1913 	return PLDM_SUCCESS;
1914 }
1915 
1916 LIBPLDM_ABI_STABLE
1917 int decode_get_status_resp(const struct pldm_msg *msg, size_t payload_length,
1918 			   uint8_t *completion_code, uint8_t *current_state,
1919 			   uint8_t *previous_state, uint8_t *aux_state,
1920 			   uint8_t *aux_state_status, uint8_t *progress_percent,
1921 			   uint8_t *reason_code,
1922 			   bitfield32_t *update_option_flags_enabled)
1923 {
1924 	if (msg == NULL || completion_code == NULL || current_state == NULL ||
1925 	    previous_state == NULL || aux_state == NULL ||
1926 	    aux_state_status == NULL || progress_percent == NULL ||
1927 	    reason_code == NULL || update_option_flags_enabled == NULL ||
1928 	    !payload_length) {
1929 		return PLDM_ERROR_INVALID_DATA;
1930 	}
1931 
1932 	*completion_code = msg->payload[0];
1933 	if (*completion_code != PLDM_SUCCESS) {
1934 		return PLDM_SUCCESS;
1935 	}
1936 
1937 	if (payload_length != sizeof(struct pldm_get_status_resp)) {
1938 		return PLDM_ERROR_INVALID_LENGTH;
1939 	}
1940 	struct pldm_get_status_resp *response =
1941 		(struct pldm_get_status_resp *)msg->payload;
1942 
1943 	if (!is_state_valid(response->current_state)) {
1944 		return PLDM_ERROR_INVALID_DATA;
1945 	}
1946 	if (!is_state_valid(response->previous_state)) {
1947 		return PLDM_ERROR_INVALID_DATA;
1948 	}
1949 	if (!is_aux_state_valid(response->aux_state)) {
1950 		return PLDM_ERROR_INVALID_DATA;
1951 	}
1952 	if (!is_aux_state_status_valid(response->aux_state_status)) {
1953 		return PLDM_ERROR_INVALID_DATA;
1954 	}
1955 	if (response->progress_percent > PLDM_FWUP_MAX_PROGRESS_PERCENT) {
1956 		return PLDM_ERROR_INVALID_DATA;
1957 	}
1958 	if (!is_reason_code_valid(response->reason_code)) {
1959 		return PLDM_ERROR_INVALID_DATA;
1960 	}
1961 
1962 	if ((response->current_state == PLDM_FD_STATE_IDLE) ||
1963 	    (response->current_state == PLDM_FD_STATE_LEARN_COMPONENTS) ||
1964 	    (response->current_state == PLDM_FD_STATE_READY_XFER)) {
1965 		if (response->aux_state !=
1966 		    PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER) {
1967 			return PLDM_ERROR_INVALID_DATA;
1968 		}
1969 	}
1970 
1971 	*current_state = response->current_state;
1972 	*previous_state = response->previous_state;
1973 	*aux_state = response->aux_state;
1974 	*aux_state_status = response->aux_state_status;
1975 	*progress_percent = response->progress_percent;
1976 	*reason_code = response->reason_code;
1977 	update_option_flags_enabled->value =
1978 		le32toh(response->update_option_flags_enabled.value);
1979 
1980 	return PLDM_SUCCESS;
1981 }
1982 
1983 LIBPLDM_ABI_STABLE
1984 int encode_cancel_update_component_req(uint8_t instance_id,
1985 				       struct pldm_msg *msg,
1986 				       size_t payload_length)
1987 {
1988 	if (msg == NULL) {
1989 		return PLDM_ERROR_INVALID_DATA;
1990 	}
1991 
1992 	if (payload_length != PLDM_CANCEL_UPDATE_COMPONENT_REQ_BYTES) {
1993 		return PLDM_ERROR_INVALID_LENGTH;
1994 	}
1995 
1996 	struct pldm_header_info header = { 0 };
1997 	header.instance = instance_id;
1998 	header.msg_type = PLDM_REQUEST;
1999 	header.pldm_type = PLDM_FWUP;
2000 	header.command = PLDM_CANCEL_UPDATE_COMPONENT;
2001 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2002 	if (rc) {
2003 		return rc;
2004 	}
2005 
2006 	return PLDM_SUCCESS;
2007 }
2008 
2009 LIBPLDM_ABI_STABLE
2010 int decode_cancel_update_component_resp(const struct pldm_msg *msg,
2011 					size_t payload_length,
2012 					uint8_t *completion_code)
2013 {
2014 	if (msg == NULL || completion_code == NULL) {
2015 		return PLDM_ERROR_INVALID_DATA;
2016 	}
2017 
2018 	if (payload_length != sizeof(*completion_code)) {
2019 		return PLDM_ERROR_INVALID_LENGTH;
2020 	}
2021 
2022 	*completion_code = msg->payload[0];
2023 	return PLDM_SUCCESS;
2024 }
2025 
2026 LIBPLDM_ABI_STABLE
2027 int encode_cancel_update_req(uint8_t instance_id, struct pldm_msg *msg,
2028 			     size_t payload_length)
2029 {
2030 	if (msg == NULL) {
2031 		return PLDM_ERROR_INVALID_DATA;
2032 	}
2033 
2034 	if (payload_length != PLDM_CANCEL_UPDATE_REQ_BYTES) {
2035 		return PLDM_ERROR_INVALID_LENGTH;
2036 	}
2037 
2038 	struct pldm_header_info header = { 0 };
2039 	header.instance = instance_id;
2040 	header.msg_type = PLDM_REQUEST;
2041 	header.pldm_type = PLDM_FWUP;
2042 	header.command = PLDM_CANCEL_UPDATE;
2043 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2044 	if (rc) {
2045 		return rc;
2046 	}
2047 
2048 	return PLDM_SUCCESS;
2049 }
2050 
2051 LIBPLDM_ABI_STABLE
2052 int decode_cancel_update_resp(const struct pldm_msg *msg, size_t payload_length,
2053 			      uint8_t *completion_code,
2054 			      bool8_t *non_functioning_component_indication,
2055 			      bitfield64_t *non_functioning_component_bitmap)
2056 {
2057 	if (msg == NULL || completion_code == NULL ||
2058 	    non_functioning_component_indication == NULL ||
2059 	    non_functioning_component_bitmap == NULL || !payload_length) {
2060 		return PLDM_ERROR_INVALID_DATA;
2061 	}
2062 
2063 	*completion_code = msg->payload[0];
2064 	if (*completion_code != PLDM_SUCCESS) {
2065 		return PLDM_SUCCESS;
2066 	}
2067 
2068 	if (payload_length != sizeof(struct pldm_cancel_update_resp)) {
2069 		return PLDM_ERROR_INVALID_LENGTH;
2070 	}
2071 	struct pldm_cancel_update_resp *response =
2072 		(struct pldm_cancel_update_resp *)msg->payload;
2073 
2074 	if (!is_non_functioning_component_indication_valid(
2075 		    response->non_functioning_component_indication)) {
2076 		return PLDM_ERROR_INVALID_DATA;
2077 	}
2078 
2079 	*non_functioning_component_indication =
2080 		response->non_functioning_component_indication;
2081 
2082 	if (*non_functioning_component_indication) {
2083 		non_functioning_component_bitmap->value =
2084 			le64toh(response->non_functioning_component_bitmap);
2085 	}
2086 
2087 	return PLDM_SUCCESS;
2088 }
2089