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