xref: /openbmc/libpldm/src/dsp/firmware_update.c (revision a9892499)
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  */
is_string_type_valid(uint8_t string_type)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  */
get_descriptor_type_length(uint16_t descriptor_type)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 
is_downstream_device_update_support_valid(uint8_t resp)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
is_transfer_operation_flag_valid(enum transfer_op_flag transfer_op_flag)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  */
is_comp_resp_valid(uint8_t comp_resp)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  */
is_comp_resp_code_valid(uint8_t comp_resp_code)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  */
is_comp_compatibility_resp_valid(uint8_t comp_compatibility_resp)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
is_comp_compatibility_resp_code_valid(uint8_t comp_compatibility_resp_code)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
is_self_contained_activation_req_valid(bool8_t self_contained_activation_req)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  */
is_state_valid(uint8_t state)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  */
is_aux_state_valid(uint8_t aux_state)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  */
is_aux_state_status_valid(uint8_t aux_state_status)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  */
is_reason_code_valid(uint8_t reason_code)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  */
is_non_functioning_component_indication_valid(bool8_t non_functioning_component_indication)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
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)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
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)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_STABLE
decode_descriptor_type_length_value(const uint8_t * data,size_t length,uint16_t * descriptor_type,struct variable_field * descriptor_data)477 int decode_descriptor_type_length_value(const uint8_t *data, size_t length,
478 					uint16_t *descriptor_type,
479 					struct variable_field *descriptor_data)
480 {
481 	uint16_t descriptor_length = 0;
482 
483 	if (data == NULL || descriptor_type == NULL ||
484 	    descriptor_data == NULL) {
485 		return PLDM_ERROR_INVALID_DATA;
486 	}
487 
488 	if (length < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {
489 		return PLDM_ERROR_INVALID_LENGTH;
490 	}
491 
492 	struct pldm_descriptor_tlv *entry =
493 		(struct pldm_descriptor_tlv *)(data);
494 
495 	*descriptor_type = le16toh(entry->descriptor_type);
496 	descriptor_length = le16toh(entry->descriptor_length);
497 	if (*descriptor_type != PLDM_FWUP_VENDOR_DEFINED) {
498 		if (descriptor_length !=
499 		    get_descriptor_type_length(*descriptor_type)) {
500 			return PLDM_ERROR_INVALID_LENGTH;
501 		}
502 	}
503 
504 	if (length < (sizeof(*descriptor_type) + sizeof(descriptor_length) +
505 		      descriptor_length)) {
506 		return PLDM_ERROR_INVALID_LENGTH;
507 	}
508 
509 	descriptor_data->ptr = entry->descriptor_data;
510 	descriptor_data->length = descriptor_length;
511 
512 	return PLDM_SUCCESS;
513 }
514 
515 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)516 int decode_vendor_defined_descriptor_value(
517 	const uint8_t *data, size_t length, uint8_t *descriptor_title_str_type,
518 	struct variable_field *descriptor_title_str,
519 	struct variable_field *descriptor_data)
520 {
521 	if (data == NULL || descriptor_title_str_type == NULL ||
522 	    descriptor_title_str == NULL || descriptor_data == NULL) {
523 		return PLDM_ERROR_INVALID_DATA;
524 	}
525 
526 	if (length < sizeof(struct pldm_vendor_defined_descriptor_title_data)) {
527 		return PLDM_ERROR_INVALID_LENGTH;
528 	}
529 
530 	struct pldm_vendor_defined_descriptor_title_data *entry =
531 		(struct pldm_vendor_defined_descriptor_title_data *)(data);
532 	if (!is_string_type_valid(
533 		    entry->vendor_defined_descriptor_title_str_type) ||
534 	    (entry->vendor_defined_descriptor_title_str_len == 0)) {
535 		return PLDM_ERROR_INVALID_DATA;
536 	}
537 
538 	// Assuming at least 1 byte of VendorDefinedDescriptorData
539 	if (length < (sizeof(struct pldm_vendor_defined_descriptor_title_data) +
540 		      entry->vendor_defined_descriptor_title_str_len)) {
541 		return PLDM_ERROR_INVALID_LENGTH;
542 	}
543 
544 	*descriptor_title_str_type =
545 		entry->vendor_defined_descriptor_title_str_type;
546 	descriptor_title_str->ptr = entry->vendor_defined_descriptor_title_str;
547 	descriptor_title_str->length =
548 		entry->vendor_defined_descriptor_title_str_len;
549 
550 	descriptor_data->ptr =
551 		descriptor_title_str->ptr + descriptor_title_str->length;
552 	descriptor_data->length =
553 		length -
554 		sizeof(entry->vendor_defined_descriptor_title_str_type) -
555 		sizeof(entry->vendor_defined_descriptor_title_str_len) -
556 		descriptor_title_str->length;
557 
558 	return PLDM_SUCCESS;
559 }
560 
561 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)562 int decode_pldm_comp_image_info(
563 	const uint8_t *data, size_t length,
564 	struct pldm_component_image_information *pldm_comp_image_info,
565 	struct variable_field *comp_version_str)
566 {
567 	if (data == NULL || pldm_comp_image_info == NULL ||
568 	    comp_version_str == NULL) {
569 		return PLDM_ERROR_INVALID_DATA;
570 	}
571 
572 	if (length < sizeof(struct pldm_component_image_information)) {
573 		return PLDM_ERROR_INVALID_LENGTH;
574 	}
575 
576 	struct pldm_component_image_information *data_header =
577 		(struct pldm_component_image_information *)(data);
578 
579 	if (!is_string_type_valid(data_header->comp_version_string_type) ||
580 	    (data_header->comp_version_string_length == 0)) {
581 		return PLDM_ERROR_INVALID_DATA;
582 	}
583 
584 	if (length < sizeof(struct pldm_component_image_information) +
585 			     data_header->comp_version_string_length) {
586 		return PLDM_ERROR_INVALID_LENGTH;
587 	}
588 
589 	pldm_comp_image_info->comp_classification =
590 		le16toh(data_header->comp_classification);
591 	pldm_comp_image_info->comp_identifier =
592 		le16toh(data_header->comp_identifier);
593 	pldm_comp_image_info->comp_comparison_stamp =
594 		le32toh(data_header->comp_comparison_stamp);
595 	pldm_comp_image_info->comp_options.value =
596 		le16toh(data_header->comp_options.value);
597 	pldm_comp_image_info->requested_comp_activation_method.value =
598 		le16toh(data_header->requested_comp_activation_method.value);
599 	pldm_comp_image_info->comp_location_offset =
600 		le32toh(data_header->comp_location_offset);
601 	pldm_comp_image_info->comp_size = le32toh(data_header->comp_size);
602 	pldm_comp_image_info->comp_version_string_type =
603 		data_header->comp_version_string_type;
604 	pldm_comp_image_info->comp_version_string_length =
605 		data_header->comp_version_string_length;
606 
607 	if ((pldm_comp_image_info->comp_options.bits.bit1 == false &&
608 	     pldm_comp_image_info->comp_comparison_stamp !=
609 		     PLDM_FWUP_INVALID_COMPONENT_COMPARISON_TIMESTAMP)) {
610 		return PLDM_ERROR_INVALID_DATA;
611 	}
612 
613 	if (pldm_comp_image_info->comp_location_offset == 0 ||
614 	    pldm_comp_image_info->comp_size == 0) {
615 		return PLDM_ERROR_INVALID_DATA;
616 	}
617 
618 	comp_version_str->ptr =
619 		data + sizeof(struct pldm_component_image_information);
620 	comp_version_str->length =
621 		pldm_comp_image_info->comp_version_string_length;
622 
623 	return PLDM_SUCCESS;
624 }
625 
626 LIBPLDM_ABI_STABLE
encode_query_device_identifiers_req(uint8_t instance_id,size_t payload_length,struct pldm_msg * msg)627 int encode_query_device_identifiers_req(uint8_t instance_id,
628 					size_t payload_length,
629 					struct pldm_msg *msg)
630 {
631 	if (msg == NULL) {
632 		return PLDM_ERROR_INVALID_DATA;
633 	}
634 
635 	if (payload_length != PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES) {
636 		return PLDM_ERROR_INVALID_LENGTH;
637 	}
638 
639 	return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
640 				       PLDM_QUERY_DEVICE_IDENTIFIERS, msg);
641 }
642 
643 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)644 int decode_query_device_identifiers_resp(const struct pldm_msg *msg,
645 					 size_t payload_length,
646 					 uint8_t *completion_code,
647 					 uint32_t *device_identifiers_len,
648 					 uint8_t *descriptor_count,
649 					 uint8_t **descriptor_data)
650 {
651 	if (msg == NULL || completion_code == NULL ||
652 	    device_identifiers_len == NULL || descriptor_count == NULL ||
653 	    descriptor_data == NULL) {
654 		return PLDM_ERROR_INVALID_DATA;
655 	}
656 
657 	*completion_code = msg->payload[0];
658 	if (PLDM_SUCCESS != *completion_code) {
659 		return PLDM_SUCCESS;
660 	}
661 
662 	if (payload_length <
663 	    sizeof(struct pldm_query_device_identifiers_resp)) {
664 		return PLDM_ERROR_INVALID_LENGTH;
665 	}
666 
667 	struct pldm_query_device_identifiers_resp *response =
668 		(struct pldm_query_device_identifiers_resp *)msg->payload;
669 	*device_identifiers_len = le32toh(response->device_identifiers_len);
670 
671 	if (*device_identifiers_len < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {
672 		return PLDM_ERROR_INVALID_LENGTH;
673 	}
674 
675 	if (payload_length !=
676 	    sizeof(struct pldm_query_device_identifiers_resp) +
677 		    *device_identifiers_len) {
678 		return PLDM_ERROR_INVALID_LENGTH;
679 	}
680 	*descriptor_count = response->descriptor_count;
681 
682 	if (*descriptor_count == 0) {
683 		return PLDM_ERROR_INVALID_DATA;
684 	}
685 	*descriptor_data =
686 		(uint8_t *)(msg->payload +
687 			    sizeof(struct pldm_query_device_identifiers_resp));
688 	return PLDM_SUCCESS;
689 }
690 
691 LIBPLDM_ABI_STABLE
encode_get_firmware_parameters_req(uint8_t instance_id,size_t payload_length,struct pldm_msg * msg)692 int encode_get_firmware_parameters_req(uint8_t instance_id,
693 				       size_t payload_length,
694 				       struct pldm_msg *msg)
695 {
696 	if (msg == NULL) {
697 		return PLDM_ERROR_INVALID_DATA;
698 	}
699 
700 	if (payload_length != PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES) {
701 		return PLDM_ERROR_INVALID_LENGTH;
702 	}
703 
704 	return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
705 				       PLDM_GET_FIRMWARE_PARAMETERS, msg);
706 }
707 
708 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)709 int decode_get_firmware_parameters_resp(
710 	const struct pldm_msg *msg, size_t payload_length,
711 	struct pldm_get_firmware_parameters_resp *resp_data,
712 	struct variable_field *active_comp_image_set_ver_str,
713 	struct variable_field *pending_comp_image_set_ver_str,
714 	struct variable_field *comp_parameter_table)
715 {
716 	if (msg == NULL || resp_data == NULL ||
717 	    active_comp_image_set_ver_str == NULL ||
718 	    pending_comp_image_set_ver_str == NULL ||
719 	    comp_parameter_table == NULL || !payload_length) {
720 		return PLDM_ERROR_INVALID_DATA;
721 	}
722 
723 	resp_data->completion_code = msg->payload[0];
724 	if (PLDM_SUCCESS != resp_data->completion_code) {
725 		return PLDM_SUCCESS;
726 	}
727 
728 	if (payload_length < sizeof(struct pldm_get_firmware_parameters_resp)) {
729 		return PLDM_ERROR_INVALID_LENGTH;
730 	}
731 
732 	struct pldm_get_firmware_parameters_resp *response =
733 		(struct pldm_get_firmware_parameters_resp *)msg->payload;
734 
735 	if (!is_string_type_valid(
736 		    response->active_comp_image_set_ver_str_type) ||
737 	    (response->active_comp_image_set_ver_str_len == 0)) {
738 		return PLDM_ERROR_INVALID_DATA;
739 	}
740 
741 	if (response->pending_comp_image_set_ver_str_len == 0) {
742 		if (response->pending_comp_image_set_ver_str_type !=
743 		    PLDM_STR_TYPE_UNKNOWN) {
744 			return PLDM_ERROR_INVALID_DATA;
745 		}
746 	} else {
747 		if (!is_string_type_valid(
748 			    response->pending_comp_image_set_ver_str_type)) {
749 			return PLDM_ERROR_INVALID_DATA;
750 		}
751 	}
752 
753 	size_t partial_response_length =
754 		sizeof(struct pldm_get_firmware_parameters_resp) +
755 		response->active_comp_image_set_ver_str_len +
756 		response->pending_comp_image_set_ver_str_len;
757 
758 	if (payload_length < partial_response_length) {
759 		return PLDM_ERROR_INVALID_LENGTH;
760 	}
761 
762 	resp_data->capabilities_during_update.value =
763 		le32toh(response->capabilities_during_update.value);
764 	resp_data->comp_count = le16toh(response->comp_count);
765 	resp_data->active_comp_image_set_ver_str_type =
766 		response->active_comp_image_set_ver_str_type;
767 	resp_data->active_comp_image_set_ver_str_len =
768 		response->active_comp_image_set_ver_str_len;
769 	resp_data->pending_comp_image_set_ver_str_type =
770 		response->pending_comp_image_set_ver_str_type;
771 	resp_data->pending_comp_image_set_ver_str_len =
772 		response->pending_comp_image_set_ver_str_len;
773 
774 	active_comp_image_set_ver_str->ptr =
775 		msg->payload + sizeof(struct pldm_get_firmware_parameters_resp);
776 	active_comp_image_set_ver_str->length =
777 		resp_data->active_comp_image_set_ver_str_len;
778 
779 	if (resp_data->pending_comp_image_set_ver_str_len != 0) {
780 		pending_comp_image_set_ver_str->ptr =
781 			msg->payload +
782 			sizeof(struct pldm_get_firmware_parameters_resp) +
783 			resp_data->active_comp_image_set_ver_str_len;
784 		pending_comp_image_set_ver_str->length =
785 			resp_data->pending_comp_image_set_ver_str_len;
786 	} else {
787 		pending_comp_image_set_ver_str->ptr = NULL;
788 		pending_comp_image_set_ver_str->length = 0;
789 	}
790 
791 	if (payload_length > partial_response_length && resp_data->comp_count) {
792 		comp_parameter_table->ptr =
793 			msg->payload +
794 			sizeof(struct pldm_get_firmware_parameters_resp) +
795 			resp_data->active_comp_image_set_ver_str_len +
796 			resp_data->pending_comp_image_set_ver_str_len;
797 		comp_parameter_table->length =
798 			payload_length - partial_response_length;
799 	} else {
800 		comp_parameter_table->ptr = NULL;
801 		comp_parameter_table->length = 0;
802 	}
803 
804 	return PLDM_SUCCESS;
805 }
806 
807 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)808 int decode_get_firmware_parameters_resp_comp_entry(
809 	const uint8_t *data, size_t length,
810 	struct pldm_component_parameter_entry *component_data,
811 	struct variable_field *active_comp_ver_str,
812 	struct variable_field *pending_comp_ver_str)
813 {
814 	if (data == NULL || component_data == NULL ||
815 	    active_comp_ver_str == NULL || pending_comp_ver_str == NULL) {
816 		return PLDM_ERROR_INVALID_DATA;
817 	}
818 
819 	if (length < sizeof(struct pldm_component_parameter_entry)) {
820 		return PLDM_ERROR_INVALID_LENGTH;
821 	}
822 
823 	struct pldm_component_parameter_entry *entry =
824 		(struct pldm_component_parameter_entry *)(data);
825 
826 	size_t entry_length = sizeof(struct pldm_component_parameter_entry) +
827 			      entry->active_comp_ver_str_len +
828 			      entry->pending_comp_ver_str_len;
829 
830 	if (length < entry_length) {
831 		return PLDM_ERROR_INVALID_LENGTH;
832 	}
833 
834 	component_data->comp_classification =
835 		le16toh(entry->comp_classification);
836 	component_data->comp_identifier = le16toh(entry->comp_identifier);
837 	component_data->comp_classification_index =
838 		entry->comp_classification_index;
839 	component_data->active_comp_comparison_stamp =
840 		le32toh(entry->active_comp_comparison_stamp);
841 	component_data->active_comp_ver_str_type =
842 		entry->active_comp_ver_str_type;
843 	component_data->active_comp_ver_str_len =
844 		entry->active_comp_ver_str_len;
845 	memcpy(component_data->active_comp_release_date,
846 	       entry->active_comp_release_date,
847 	       sizeof(entry->active_comp_release_date));
848 	component_data->pending_comp_comparison_stamp =
849 		le32toh(entry->pending_comp_comparison_stamp);
850 	component_data->pending_comp_ver_str_type =
851 		entry->pending_comp_ver_str_type;
852 	component_data->pending_comp_ver_str_len =
853 		entry->pending_comp_ver_str_len;
854 	memcpy(component_data->pending_comp_release_date,
855 	       entry->pending_comp_release_date,
856 	       sizeof(entry->pending_comp_release_date));
857 	component_data->comp_activation_methods.value =
858 		le16toh(entry->comp_activation_methods.value);
859 	component_data->capabilities_during_update.value =
860 		le32toh(entry->capabilities_during_update.value);
861 
862 	if (entry->active_comp_ver_str_len != 0) {
863 		active_comp_ver_str->ptr =
864 			data + sizeof(struct pldm_component_parameter_entry);
865 		active_comp_ver_str->length = entry->active_comp_ver_str_len;
866 	} else {
867 		active_comp_ver_str->ptr = NULL;
868 		active_comp_ver_str->length = 0;
869 	}
870 
871 	if (entry->pending_comp_ver_str_len != 0) {
872 		pending_comp_ver_str->ptr =
873 			data + sizeof(struct pldm_component_parameter_entry) +
874 			entry->active_comp_ver_str_len;
875 		pending_comp_ver_str->length = entry->pending_comp_ver_str_len;
876 	} else {
877 		pending_comp_ver_str->ptr = NULL;
878 		pending_comp_ver_str->length = 0;
879 	}
880 	return PLDM_SUCCESS;
881 }
882 
883 LIBPLDM_ABI_TESTING
encode_query_downstream_devices_req(uint8_t instance_id,struct pldm_msg * msg)884 int encode_query_downstream_devices_req(uint8_t instance_id,
885 					struct pldm_msg *msg)
886 {
887 	if (msg == NULL) {
888 		return PLDM_ERROR_INVALID_DATA;
889 	}
890 
891 	return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
892 				       PLDM_QUERY_DOWNSTREAM_DEVICES, msg);
893 }
894 
895 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)896 int decode_query_downstream_devices_resp(
897 	const struct pldm_msg *msg, size_t payload_length,
898 	struct pldm_query_downstream_devices_resp *resp_data)
899 {
900 	struct pldm_msgbuf _buf;
901 	struct pldm_msgbuf *buf = &_buf;
902 	int rc;
903 
904 	if (msg == NULL || resp_data == NULL || !payload_length) {
905 		return PLDM_ERROR_INVALID_DATA;
906 	}
907 
908 	rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
909 				    msg->payload, payload_length);
910 	if (rc) {
911 		return rc;
912 	}
913 
914 	rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
915 	if (rc) {
916 		return pldm_xlate_errno(rc);
917 	}
918 	if (PLDM_SUCCESS != resp_data->completion_code) {
919 		// Return the CC directly without decoding the rest of the payload
920 		return PLDM_SUCCESS;
921 	}
922 
923 	if (payload_length < PLDM_QUERY_DOWNSTREAM_DEVICES_RESP_BYTES) {
924 		return PLDM_ERROR_INVALID_LENGTH;
925 	}
926 
927 	rc = pldm_msgbuf_extract(buf,
928 				 resp_data->downstream_device_update_supported);
929 	if (rc) {
930 		return pldm_xlate_errno(rc);
931 	}
932 
933 	if (!is_downstream_device_update_support_valid(
934 		    resp_data->downstream_device_update_supported)) {
935 		return PLDM_ERROR_INVALID_DATA;
936 	}
937 
938 	pldm_msgbuf_extract(buf, resp_data->number_of_downstream_devices);
939 	pldm_msgbuf_extract(buf, resp_data->max_number_of_downstream_devices);
940 	pldm_msgbuf_extract(buf, resp_data->capabilities.value);
941 
942 	rc = pldm_msgbuf_destroy_consumed(buf);
943 	if (rc) {
944 		pldm_xlate_errno(rc);
945 	}
946 
947 	return PLDM_SUCCESS;
948 }
949 
950 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)951 int encode_query_downstream_identifiers_req(
952 	uint8_t instance_id, uint32_t data_transfer_handle,
953 	enum transfer_op_flag transfer_operation_flag, struct pldm_msg *msg,
954 	size_t payload_length)
955 {
956 	struct pldm_msgbuf _buf;
957 	struct pldm_msgbuf *buf = &_buf;
958 	int rc;
959 
960 	if (msg == NULL) {
961 		return PLDM_ERROR_INVALID_DATA;
962 	}
963 
964 	if (!is_transfer_operation_flag_valid(transfer_operation_flag)) {
965 		return PLDM_INVALID_TRANSFER_OPERATION_FLAG;
966 	}
967 
968 	struct pldm_header_info header = { 0 };
969 	header.instance = instance_id;
970 	header.msg_type = PLDM_REQUEST;
971 	header.pldm_type = PLDM_FWUP;
972 	header.command = PLDM_QUERY_DOWNSTREAM_IDENTIFIERS;
973 	rc = pack_pldm_header(&header, &(msg->hdr));
974 	if (rc) {
975 		return rc;
976 	}
977 
978 	rc = pldm_msgbuf_init_errno(buf,
979 				    PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_REQ_BYTES,
980 				    msg->payload, payload_length);
981 	if (rc) {
982 		return pldm_xlate_errno(rc);
983 	}
984 
985 	pldm_msgbuf_insert(buf, data_transfer_handle);
986 	// Data correctness has been verified, cast it to 1-byte data directly.
987 	pldm_msgbuf_insert(buf, (uint8_t)transfer_operation_flag);
988 
989 	rc = pldm_msgbuf_destroy(buf);
990 	if (rc) {
991 		return pldm_xlate_errno(rc);
992 	}
993 
994 	return PLDM_SUCCESS;
995 }
996 
997 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)998 int decode_query_downstream_identifiers_resp(
999 	const struct pldm_msg *msg, size_t payload_length,
1000 	struct pldm_query_downstream_identifiers_resp *resp_data,
1001 	struct variable_field *downstream_devices)
1002 {
1003 	struct pldm_msgbuf _buf;
1004 	struct pldm_msgbuf *buf = &_buf;
1005 	int rc = PLDM_ERROR;
1006 
1007 	if (msg == NULL || resp_data == NULL || downstream_devices == NULL ||
1008 	    !payload_length) {
1009 		return PLDM_ERROR_INVALID_DATA;
1010 	}
1011 
1012 	rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1013 				    msg->payload, payload_length);
1014 	if (rc) {
1015 		return pldm_xlate_errno(rc);
1016 	}
1017 
1018 	rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1019 	if (rc) {
1020 		return pldm_xlate_errno(rc);
1021 	}
1022 	if (PLDM_SUCCESS != resp_data->completion_code) {
1023 		return PLDM_SUCCESS;
1024 	}
1025 
1026 	if (payload_length < PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_RESP_MIN_LEN) {
1027 		return PLDM_ERROR_INVALID_LENGTH;
1028 	}
1029 
1030 	pldm_msgbuf_extract(buf, resp_data->next_data_transfer_handle);
1031 	pldm_msgbuf_extract(buf, resp_data->transfer_flag);
1032 
1033 	rc = pldm_msgbuf_extract(buf, resp_data->downstream_devices_length);
1034 	if (rc) {
1035 		return pldm_xlate_errno(rc);
1036 	}
1037 
1038 	pldm_msgbuf_extract(buf, resp_data->number_of_downstream_devices);
1039 	rc = pldm_msgbuf_span_required(buf,
1040 				       resp_data->downstream_devices_length,
1041 				       (void **)&downstream_devices->ptr);
1042 	if (rc) {
1043 		return pldm_xlate_errno(rc);
1044 	}
1045 	downstream_devices->length = resp_data->downstream_devices_length;
1046 
1047 	rc = pldm_msgbuf_destroy(buf);
1048 	if (rc) {
1049 		return pldm_xlate_errno(rc);
1050 	}
1051 
1052 	return PLDM_SUCCESS;
1053 }
1054 
1055 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)1056 int encode_get_downstream_firmware_params_req(
1057 	uint8_t instance_id, uint32_t data_transfer_handle,
1058 	enum transfer_op_flag transfer_operation_flag, struct pldm_msg *msg,
1059 	size_t payload_length)
1060 {
1061 	struct pldm_msgbuf _buf;
1062 	struct pldm_msgbuf *buf = &_buf;
1063 	int rc;
1064 
1065 	if (msg == NULL) {
1066 		return -EINVAL;
1067 	}
1068 
1069 	rc = pldm_msgbuf_init_errno(
1070 		buf, PLDM_GET_DOWNSTREAM_FIRMWARE_PARAMS_REQ_BYTES,
1071 		msg->payload, payload_length);
1072 	if (rc < 0) {
1073 		return rc;
1074 	}
1075 
1076 	if (!is_transfer_operation_flag_valid(transfer_operation_flag)) {
1077 		return -EBADMSG;
1078 	}
1079 
1080 	struct pldm_header_info header = { 0 };
1081 	header.instance = instance_id;
1082 	header.msg_type = PLDM_REQUEST;
1083 	header.pldm_type = PLDM_FWUP;
1084 	header.command = PLDM_QUERY_DOWNSTREAM_FIRMWARE_PARAMETERS;
1085 	rc = pack_pldm_header_errno(&header, &msg->hdr);
1086 	if (rc < 0) {
1087 		return rc;
1088 	}
1089 
1090 	pldm_msgbuf_insert(buf, data_transfer_handle);
1091 	// Data correctness has been verified, cast it to 1-byte data directly.
1092 	pldm_msgbuf_insert(buf, (uint8_t)transfer_operation_flag);
1093 
1094 	return pldm_msgbuf_destroy(buf);
1095 }
1096 
1097 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)1098 int decode_get_downstream_firmware_params_resp(
1099 	const struct pldm_msg *msg, size_t payload_length,
1100 	struct pldm_get_downstream_firmware_params_resp *resp_data,
1101 	struct variable_field *downstream_device_param_table)
1102 {
1103 	struct pldm_msgbuf _buf;
1104 	struct pldm_msgbuf *buf = &_buf;
1105 	int rc;
1106 
1107 	if (msg == NULL || resp_data == NULL ||
1108 	    downstream_device_param_table == NULL) {
1109 		return -EINVAL;
1110 	}
1111 
1112 	rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1113 				    msg->payload, payload_length);
1114 	if (rc < 0) {
1115 		return rc;
1116 	}
1117 
1118 	rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1119 	if (rc < 0) {
1120 		return rc;
1121 	}
1122 	if (PLDM_SUCCESS != resp_data->completion_code) {
1123 		return 0;
1124 	}
1125 
1126 	if (payload_length < PLDM_GET_DOWNSTREAM_FIRMWARE_PARAMS_RESP_MIN_LEN) {
1127 		return -EBADMSG;
1128 	}
1129 
1130 	pldm_msgbuf_extract(buf, resp_data->next_data_transfer_handle);
1131 	pldm_msgbuf_extract(buf, resp_data->transfer_flag);
1132 	pldm_msgbuf_extract(buf,
1133 			    resp_data->fdp_capabilities_during_update.value);
1134 	pldm_msgbuf_extract(buf, resp_data->downstream_device_count);
1135 
1136 	return pldm_msgbuf_span_remaining(
1137 		buf, (void **)&downstream_device_param_table->ptr,
1138 		&downstream_device_param_table->length);
1139 }
1140 
1141 LIBPLDM_ABI_TESTING
decode_downstream_device_parameter_table_entry(struct variable_field * data,struct pldm_downstream_device_parameter_entry * entry,struct variable_field * versions)1142 int decode_downstream_device_parameter_table_entry(
1143 	struct variable_field *data,
1144 	struct pldm_downstream_device_parameter_entry *entry,
1145 	struct variable_field *versions)
1146 {
1147 	struct pldm_msgbuf _buf;
1148 	struct pldm_msgbuf *buf = &_buf;
1149 	void *cursor = NULL;
1150 	size_t remaining;
1151 	int rc;
1152 
1153 	if (data == NULL || entry == NULL || versions == NULL) {
1154 		return -EINVAL;
1155 	}
1156 
1157 	rc = pldm_msgbuf_init_errno(
1158 		buf, PLDM_DOWNSTREAM_DEVICE_PARAMETER_ENTRY_MIN_LEN, data->ptr,
1159 		data->length);
1160 	if (rc < 0) {
1161 		return rc;
1162 	}
1163 
1164 	pldm_msgbuf_extract(buf, entry->downstream_device_index);
1165 	pldm_msgbuf_extract(buf, entry->active_comp_comparison_stamp);
1166 	pldm_msgbuf_extract(buf, entry->active_comp_ver_str_type);
1167 	rc = pldm_msgbuf_extract(buf, entry->active_comp_ver_str_len);
1168 	if (rc < 0) {
1169 		return rc;
1170 	}
1171 	rc = pldm_msgbuf_extract_array(buf,
1172 				       PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1173 				       entry->active_comp_release_date,
1174 				       sizeof(entry->active_comp_release_date));
1175 	if (rc < 0) {
1176 		return rc;
1177 	}
1178 
1179 	// Fill the last byte with NULL character
1180 	entry->active_comp_release_date[PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN] =
1181 		'\0';
1182 
1183 	pldm_msgbuf_extract(buf, entry->pending_comp_comparison_stamp);
1184 	pldm_msgbuf_extract(buf, entry->pending_comp_ver_str_type);
1185 	rc = pldm_msgbuf_extract(buf, entry->pending_comp_ver_str_len);
1186 	if (rc < 0) {
1187 		return rc;
1188 	}
1189 
1190 	rc = pldm_msgbuf_extract_array(
1191 		buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1192 		entry->pending_comp_release_date,
1193 		sizeof(entry->pending_comp_release_date));
1194 	if (rc < 0) {
1195 		return rc;
1196 	}
1197 
1198 	// Fill the last byte with NULL character
1199 	entry->pending_comp_release_date[PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN] =
1200 		'\0';
1201 
1202 	pldm_msgbuf_extract(buf, entry->comp_activation_methods.value);
1203 	pldm_msgbuf_extract(buf, entry->capabilities_during_update.value);
1204 	const size_t versions_len = entry->active_comp_ver_str_len +
1205 				    entry->pending_comp_ver_str_len;
1206 	rc = pldm_msgbuf_span_required(buf, versions_len,
1207 				       (void **)&versions->ptr);
1208 	if (rc < 0) {
1209 		return rc;
1210 	}
1211 	versions->length = versions_len;
1212 
1213 	rc = pldm_msgbuf_span_remaining(buf, &cursor, &remaining);
1214 	if (rc < 0) {
1215 		return rc;
1216 	}
1217 
1218 	data->ptr = cursor;
1219 	data->length = remaining;
1220 
1221 	return 0;
1222 }
1223 
1224 LIBPLDM_ABI_TESTING
decode_downstream_device_parameter_table_entry_versions(const struct variable_field * versions,struct pldm_downstream_device_parameter_entry * entry,char * active,size_t active_len,char * pending,size_t pending_len)1225 int decode_downstream_device_parameter_table_entry_versions(
1226 	const struct variable_field *versions,
1227 	struct pldm_downstream_device_parameter_entry *entry, char *active,
1228 	size_t active_len, char *pending, size_t pending_len)
1229 {
1230 	struct pldm_msgbuf _buf;
1231 	struct pldm_msgbuf *buf = &_buf;
1232 	int rc;
1233 
1234 	if (versions == NULL || versions->ptr == NULL || !versions->length ||
1235 	    entry == NULL || active == NULL || pending == NULL) {
1236 		return -EINVAL;
1237 	}
1238 
1239 	if (!active_len || active_len - 1 < entry->active_comp_ver_str_len) {
1240 		return -EOVERFLOW;
1241 	}
1242 
1243 	if (!pending_len || pending_len - 1 < entry->pending_comp_ver_str_len) {
1244 		return -EOVERFLOW;
1245 	}
1246 
1247 	/* This API should be called after decode_downstream_device_parameter_table_entry
1248 	 * has successfully decoded the entry, assume the entry data is valid here.
1249 	 */
1250 	const size_t versions_len = entry->active_comp_ver_str_len +
1251 				    entry->pending_comp_ver_str_len;
1252 	rc = pldm_msgbuf_init_errno(buf, versions_len, versions->ptr,
1253 				    versions->length);
1254 	if (rc < 0) {
1255 		return rc;
1256 	}
1257 
1258 	rc = pldm_msgbuf_extract_array(buf, entry->active_comp_ver_str_len,
1259 				       active, active_len);
1260 	if (rc < 0) {
1261 		return rc;
1262 	}
1263 
1264 	active[entry->active_comp_ver_str_len] = '\0';
1265 	rc = pldm_msgbuf_extract_array(buf, entry->pending_comp_ver_str_len,
1266 				       pending, pending_len);
1267 	if (rc < 0) {
1268 		return rc;
1269 	}
1270 
1271 	pending[entry->pending_comp_ver_str_len] = '\0';
1272 
1273 	entry->active_comp_ver_str = active;
1274 	entry->pending_comp_ver_str = pending;
1275 
1276 	return pldm_msgbuf_destroy_consumed(buf);
1277 }
1278 
1279 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)1280 int encode_request_update_req(uint8_t instance_id, uint32_t max_transfer_size,
1281 			      uint16_t num_of_comp,
1282 			      uint8_t max_outstanding_transfer_req,
1283 			      uint16_t pkg_data_len,
1284 			      uint8_t comp_image_set_ver_str_type,
1285 			      uint8_t comp_image_set_ver_str_len,
1286 			      const struct variable_field *comp_img_set_ver_str,
1287 			      struct pldm_msg *msg, size_t payload_length)
1288 {
1289 	if (comp_img_set_ver_str == NULL || comp_img_set_ver_str->ptr == NULL ||
1290 	    msg == NULL) {
1291 		return PLDM_ERROR_INVALID_DATA;
1292 	}
1293 
1294 	if (payload_length != sizeof(struct pldm_request_update_req) +
1295 				      comp_img_set_ver_str->length) {
1296 		return PLDM_ERROR_INVALID_LENGTH;
1297 	}
1298 
1299 	if ((comp_image_set_ver_str_len == 0) ||
1300 	    (comp_image_set_ver_str_len != comp_img_set_ver_str->length)) {
1301 		return PLDM_ERROR_INVALID_DATA;
1302 	}
1303 
1304 	if ((max_transfer_size < PLDM_FWUP_BASELINE_TRANSFER_SIZE) ||
1305 	    (max_outstanding_transfer_req < PLDM_FWUP_MIN_OUTSTANDING_REQ)) {
1306 		return PLDM_ERROR_INVALID_DATA;
1307 	}
1308 
1309 	if (!is_string_type_valid(comp_image_set_ver_str_type)) {
1310 		return PLDM_ERROR_INVALID_DATA;
1311 	}
1312 
1313 	struct pldm_header_info header = { 0 };
1314 	header.instance = instance_id;
1315 	header.msg_type = PLDM_REQUEST;
1316 	header.pldm_type = PLDM_FWUP;
1317 	header.command = PLDM_REQUEST_UPDATE;
1318 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1319 	if (rc) {
1320 		return rc;
1321 	}
1322 
1323 	struct pldm_request_update_req *request =
1324 		(struct pldm_request_update_req *)msg->payload;
1325 
1326 	request->max_transfer_size = htole32(max_transfer_size);
1327 	request->num_of_comp = htole16(num_of_comp);
1328 	request->max_outstanding_transfer_req = max_outstanding_transfer_req;
1329 	request->pkg_data_len = htole16(pkg_data_len);
1330 	request->comp_image_set_ver_str_type = comp_image_set_ver_str_type;
1331 	request->comp_image_set_ver_str_len = comp_image_set_ver_str_len;
1332 
1333 	memcpy(msg->payload + sizeof(struct pldm_request_update_req),
1334 	       comp_img_set_ver_str->ptr, comp_img_set_ver_str->length);
1335 
1336 	return PLDM_SUCCESS;
1337 }
1338 
1339 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)1340 int decode_request_update_resp(const struct pldm_msg *msg,
1341 			       size_t payload_length, uint8_t *completion_code,
1342 			       uint16_t *fd_meta_data_len,
1343 			       uint8_t *fd_will_send_pkg_data)
1344 {
1345 	if (msg == NULL || completion_code == NULL ||
1346 	    fd_meta_data_len == NULL || fd_will_send_pkg_data == NULL ||
1347 	    !payload_length) {
1348 		return PLDM_ERROR_INVALID_DATA;
1349 	}
1350 
1351 	*completion_code = msg->payload[0];
1352 	if (*completion_code != PLDM_SUCCESS) {
1353 		return PLDM_SUCCESS;
1354 	}
1355 
1356 	if (payload_length != sizeof(struct pldm_request_update_resp)) {
1357 		return PLDM_ERROR_INVALID_LENGTH;
1358 	}
1359 
1360 	struct pldm_request_update_resp *response =
1361 		(struct pldm_request_update_resp *)msg->payload;
1362 
1363 	*fd_meta_data_len = le16toh(response->fd_meta_data_len);
1364 	*fd_will_send_pkg_data = response->fd_will_send_pkg_data;
1365 
1366 	return PLDM_SUCCESS;
1367 }
1368 
1369 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)1370 int encode_pass_component_table_req(uint8_t instance_id, uint8_t transfer_flag,
1371 				    uint16_t comp_classification,
1372 				    uint16_t comp_identifier,
1373 				    uint8_t comp_classification_index,
1374 				    uint32_t comp_comparison_stamp,
1375 				    uint8_t comp_ver_str_type,
1376 				    uint8_t comp_ver_str_len,
1377 				    const struct variable_field *comp_ver_str,
1378 				    struct pldm_msg *msg, size_t payload_length)
1379 {
1380 	if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) {
1381 		return PLDM_ERROR_INVALID_DATA;
1382 	}
1383 
1384 	if (payload_length != sizeof(struct pldm_pass_component_table_req) +
1385 				      comp_ver_str->length) {
1386 		return PLDM_ERROR_INVALID_LENGTH;
1387 	}
1388 
1389 	if ((comp_ver_str_len == 0) ||
1390 	    (comp_ver_str_len != comp_ver_str->length)) {
1391 		return PLDM_ERROR_INVALID_DATA;
1392 	}
1393 
1394 	if (!is_transfer_flag_valid(transfer_flag)) {
1395 		return PLDM_INVALID_TRANSFER_OPERATION_FLAG;
1396 	}
1397 
1398 	if (!is_string_type_valid(comp_ver_str_type)) {
1399 		return PLDM_ERROR_INVALID_DATA;
1400 	}
1401 
1402 	struct pldm_header_info header = { 0 };
1403 	header.instance = instance_id;
1404 	header.msg_type = PLDM_REQUEST;
1405 	header.pldm_type = PLDM_FWUP;
1406 	header.command = PLDM_PASS_COMPONENT_TABLE;
1407 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1408 	if (rc) {
1409 		return rc;
1410 	}
1411 
1412 	struct pldm_pass_component_table_req *request =
1413 		(struct pldm_pass_component_table_req *)msg->payload;
1414 
1415 	request->transfer_flag = transfer_flag;
1416 	request->comp_classification = htole16(comp_classification);
1417 	request->comp_identifier = htole16(comp_identifier);
1418 	request->comp_classification_index = comp_classification_index;
1419 	request->comp_comparison_stamp = htole32(comp_comparison_stamp);
1420 	request->comp_ver_str_type = comp_ver_str_type;
1421 	request->comp_ver_str_len = comp_ver_str_len;
1422 
1423 	memcpy(msg->payload + sizeof(struct pldm_pass_component_table_req),
1424 	       comp_ver_str->ptr, comp_ver_str->length);
1425 
1426 	return PLDM_SUCCESS;
1427 }
1428 
1429 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)1430 int decode_pass_component_table_resp(const struct pldm_msg *msg,
1431 				     const size_t payload_length,
1432 				     uint8_t *completion_code,
1433 				     uint8_t *comp_resp,
1434 				     uint8_t *comp_resp_code)
1435 {
1436 	if (msg == NULL || completion_code == NULL || comp_resp == NULL ||
1437 	    comp_resp_code == NULL || !payload_length) {
1438 		return PLDM_ERROR_INVALID_DATA;
1439 	}
1440 
1441 	*completion_code = msg->payload[0];
1442 	if (*completion_code != PLDM_SUCCESS) {
1443 		return PLDM_SUCCESS;
1444 	}
1445 
1446 	if (payload_length != sizeof(struct pldm_pass_component_table_resp)) {
1447 		return PLDM_ERROR_INVALID_LENGTH;
1448 	}
1449 
1450 	struct pldm_pass_component_table_resp *response =
1451 		(struct pldm_pass_component_table_resp *)msg->payload;
1452 
1453 	if (!is_comp_resp_valid(response->comp_resp)) {
1454 		return PLDM_ERROR_INVALID_DATA;
1455 	}
1456 
1457 	if (!is_comp_resp_code_valid(response->comp_resp_code)) {
1458 		return PLDM_ERROR_INVALID_DATA;
1459 	}
1460 
1461 	*comp_resp = response->comp_resp;
1462 	*comp_resp_code = response->comp_resp_code;
1463 
1464 	return PLDM_SUCCESS;
1465 }
1466 
1467 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)1468 int encode_update_component_req(
1469 	uint8_t instance_id, uint16_t comp_classification,
1470 	uint16_t comp_identifier, uint8_t comp_classification_index,
1471 	uint32_t comp_comparison_stamp, uint32_t comp_image_size,
1472 	bitfield32_t update_option_flags, uint8_t comp_ver_str_type,
1473 	uint8_t comp_ver_str_len, const struct variable_field *comp_ver_str,
1474 	struct pldm_msg *msg, size_t payload_length)
1475 {
1476 	if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) {
1477 		return PLDM_ERROR_INVALID_DATA;
1478 	}
1479 
1480 	if (payload_length !=
1481 	    sizeof(struct pldm_update_component_req) + comp_ver_str->length) {
1482 		return PLDM_ERROR_INVALID_LENGTH;
1483 	}
1484 
1485 	if (!comp_image_size) {
1486 		return PLDM_ERROR_INVALID_DATA;
1487 	}
1488 
1489 	if ((comp_ver_str_len == 0) ||
1490 	    (comp_ver_str_len != comp_ver_str->length)) {
1491 		return PLDM_ERROR_INVALID_DATA;
1492 	}
1493 
1494 	if (!is_string_type_valid(comp_ver_str_type)) {
1495 		return PLDM_ERROR_INVALID_DATA;
1496 	}
1497 
1498 	struct pldm_header_info header = { 0 };
1499 	header.instance = instance_id;
1500 	header.msg_type = PLDM_REQUEST;
1501 	header.pldm_type = PLDM_FWUP;
1502 	header.command = PLDM_UPDATE_COMPONENT;
1503 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1504 	if (rc) {
1505 		return rc;
1506 	}
1507 
1508 	struct pldm_update_component_req *request =
1509 		(struct pldm_update_component_req *)msg->payload;
1510 
1511 	request->comp_classification = htole16(comp_classification);
1512 	request->comp_identifier = htole16(comp_identifier);
1513 	request->comp_classification_index = comp_classification_index;
1514 	request->comp_comparison_stamp = htole32(comp_comparison_stamp);
1515 	request->comp_image_size = htole32(comp_image_size);
1516 	request->update_option_flags.value = htole32(update_option_flags.value);
1517 	request->comp_ver_str_type = comp_ver_str_type;
1518 	request->comp_ver_str_len = comp_ver_str_len;
1519 
1520 	memcpy(msg->payload + sizeof(struct pldm_update_component_req),
1521 	       comp_ver_str->ptr, comp_ver_str->length);
1522 
1523 	return PLDM_SUCCESS;
1524 }
1525 
1526 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)1527 int decode_update_component_resp(const struct pldm_msg *msg,
1528 				 size_t payload_length,
1529 				 uint8_t *completion_code,
1530 				 uint8_t *comp_compatibility_resp,
1531 				 uint8_t *comp_compatibility_resp_code,
1532 				 bitfield32_t *update_option_flags_enabled,
1533 				 uint16_t *time_before_req_fw_data)
1534 {
1535 	if (msg == NULL || completion_code == NULL ||
1536 	    comp_compatibility_resp == NULL ||
1537 	    comp_compatibility_resp_code == NULL ||
1538 	    update_option_flags_enabled == NULL ||
1539 	    time_before_req_fw_data == NULL || !payload_length) {
1540 		return PLDM_ERROR_INVALID_DATA;
1541 	}
1542 
1543 	*completion_code = msg->payload[0];
1544 	if (*completion_code != PLDM_SUCCESS) {
1545 		return PLDM_SUCCESS;
1546 	}
1547 
1548 	if (payload_length != sizeof(struct pldm_update_component_resp)) {
1549 		return PLDM_ERROR_INVALID_LENGTH;
1550 	}
1551 
1552 	struct pldm_update_component_resp *response =
1553 		(struct pldm_update_component_resp *)msg->payload;
1554 
1555 	if (!is_comp_compatibility_resp_valid(
1556 		    response->comp_compatibility_resp)) {
1557 		return PLDM_ERROR_INVALID_DATA;
1558 	}
1559 
1560 	if (!is_comp_compatibility_resp_code_valid(
1561 		    response->comp_compatibility_resp_code)) {
1562 		return PLDM_ERROR_INVALID_DATA;
1563 	}
1564 
1565 	*comp_compatibility_resp = response->comp_compatibility_resp;
1566 	*comp_compatibility_resp_code = response->comp_compatibility_resp_code;
1567 	update_option_flags_enabled->value =
1568 		le32toh(response->update_option_flags_enabled.value);
1569 	*time_before_req_fw_data = le16toh(response->time_before_req_fw_data);
1570 
1571 	return PLDM_SUCCESS;
1572 }
1573 
1574 LIBPLDM_ABI_STABLE
decode_request_firmware_data_req(const struct pldm_msg * msg,size_t payload_length,uint32_t * offset,uint32_t * length)1575 int decode_request_firmware_data_req(const struct pldm_msg *msg,
1576 				     size_t payload_length, uint32_t *offset,
1577 				     uint32_t *length)
1578 {
1579 	if (msg == NULL || offset == NULL || length == NULL) {
1580 		return PLDM_ERROR_INVALID_DATA;
1581 	}
1582 	if (payload_length != sizeof(struct pldm_request_firmware_data_req)) {
1583 		return PLDM_ERROR_INVALID_LENGTH;
1584 	}
1585 	struct pldm_request_firmware_data_req *request =
1586 		(struct pldm_request_firmware_data_req *)msg->payload;
1587 	*offset = le32toh(request->offset);
1588 	*length = le32toh(request->length);
1589 
1590 	if (*length < PLDM_FWUP_BASELINE_TRANSFER_SIZE) {
1591 		return PLDM_FWUP_INVALID_TRANSFER_LENGTH;
1592 	}
1593 
1594 	return PLDM_SUCCESS;
1595 }
1596 
1597 LIBPLDM_ABI_STABLE
encode_request_firmware_data_resp(uint8_t instance_id,uint8_t completion_code,struct pldm_msg * msg,size_t payload_length)1598 int encode_request_firmware_data_resp(uint8_t instance_id,
1599 				      uint8_t completion_code,
1600 				      struct pldm_msg *msg,
1601 				      size_t payload_length)
1602 {
1603 	if (msg == NULL || !payload_length) {
1604 		return PLDM_ERROR_INVALID_DATA;
1605 	}
1606 
1607 	struct pldm_header_info header = { 0 };
1608 	header.instance = instance_id;
1609 	header.msg_type = PLDM_RESPONSE;
1610 	header.pldm_type = PLDM_FWUP;
1611 	header.command = PLDM_REQUEST_FIRMWARE_DATA;
1612 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1613 	if (rc) {
1614 		return rc;
1615 	}
1616 
1617 	msg->payload[0] = completion_code;
1618 
1619 	return PLDM_SUCCESS;
1620 }
1621 
1622 LIBPLDM_ABI_STABLE
decode_transfer_complete_req(const struct pldm_msg * msg,size_t payload_length,uint8_t * transfer_result)1623 int decode_transfer_complete_req(const struct pldm_msg *msg,
1624 				 size_t payload_length,
1625 				 uint8_t *transfer_result)
1626 {
1627 	if (msg == NULL || transfer_result == NULL) {
1628 		return PLDM_ERROR_INVALID_DATA;
1629 	}
1630 
1631 	if (payload_length != sizeof(*transfer_result)) {
1632 		return PLDM_ERROR_INVALID_LENGTH;
1633 	}
1634 
1635 	*transfer_result = msg->payload[0];
1636 	return PLDM_SUCCESS;
1637 }
1638 
1639 LIBPLDM_ABI_STABLE
encode_transfer_complete_resp(uint8_t instance_id,uint8_t completion_code,struct pldm_msg * msg,size_t payload_length)1640 int encode_transfer_complete_resp(uint8_t instance_id, uint8_t completion_code,
1641 				  struct pldm_msg *msg, size_t payload_length)
1642 {
1643 	if (msg == NULL) {
1644 		return PLDM_ERROR_INVALID_DATA;
1645 	}
1646 
1647 	if (payload_length != sizeof(completion_code)) {
1648 		return PLDM_ERROR_INVALID_LENGTH;
1649 	}
1650 
1651 	struct pldm_header_info header = { 0 };
1652 	header.instance = instance_id;
1653 	header.msg_type = PLDM_RESPONSE;
1654 	header.pldm_type = PLDM_FWUP;
1655 	header.command = PLDM_TRANSFER_COMPLETE;
1656 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1657 	if (rc) {
1658 		return rc;
1659 	}
1660 
1661 	msg->payload[0] = completion_code;
1662 
1663 	return PLDM_SUCCESS;
1664 }
1665 
1666 LIBPLDM_ABI_STABLE
decode_verify_complete_req(const struct pldm_msg * msg,size_t payload_length,uint8_t * verify_result)1667 int decode_verify_complete_req(const struct pldm_msg *msg,
1668 			       size_t payload_length, uint8_t *verify_result)
1669 {
1670 	if (msg == NULL || verify_result == NULL) {
1671 		return PLDM_ERROR_INVALID_DATA;
1672 	}
1673 
1674 	if (payload_length != sizeof(*verify_result)) {
1675 		return PLDM_ERROR_INVALID_LENGTH;
1676 	}
1677 
1678 	*verify_result = msg->payload[0];
1679 	return PLDM_SUCCESS;
1680 }
1681 
1682 LIBPLDM_ABI_STABLE
encode_verify_complete_resp(uint8_t instance_id,uint8_t completion_code,struct pldm_msg * msg,size_t payload_length)1683 int encode_verify_complete_resp(uint8_t instance_id, uint8_t completion_code,
1684 				struct pldm_msg *msg, size_t payload_length)
1685 {
1686 	if (msg == NULL) {
1687 		return PLDM_ERROR_INVALID_DATA;
1688 	}
1689 
1690 	if (payload_length != sizeof(completion_code)) {
1691 		return PLDM_ERROR_INVALID_LENGTH;
1692 	}
1693 
1694 	struct pldm_header_info header = { 0 };
1695 	header.instance = instance_id;
1696 	header.msg_type = PLDM_RESPONSE;
1697 	header.pldm_type = PLDM_FWUP;
1698 	header.command = PLDM_VERIFY_COMPLETE;
1699 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1700 	if (rc) {
1701 		return rc;
1702 	}
1703 
1704 	msg->payload[0] = completion_code;
1705 
1706 	return PLDM_SUCCESS;
1707 }
1708 
1709 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)1710 int decode_apply_complete_req(const struct pldm_msg *msg, size_t payload_length,
1711 			      uint8_t *apply_result,
1712 			      bitfield16_t *comp_activation_methods_modification)
1713 {
1714 	if (msg == NULL || apply_result == NULL ||
1715 	    comp_activation_methods_modification == NULL) {
1716 		return PLDM_ERROR_INVALID_DATA;
1717 	}
1718 
1719 	if (payload_length != sizeof(struct pldm_apply_complete_req)) {
1720 		return PLDM_ERROR_INVALID_LENGTH;
1721 	}
1722 
1723 	struct pldm_apply_complete_req *request =
1724 		(struct pldm_apply_complete_req *)msg->payload;
1725 
1726 	*apply_result = request->apply_result;
1727 	comp_activation_methods_modification->value =
1728 		le16toh(request->comp_activation_methods_modification.value);
1729 
1730 	if ((*apply_result != PLDM_FWUP_APPLY_SUCCESS_WITH_ACTIVATION_METHOD) &&
1731 	    comp_activation_methods_modification->value) {
1732 		return PLDM_ERROR_INVALID_DATA;
1733 	}
1734 
1735 	return PLDM_SUCCESS;
1736 }
1737 
1738 LIBPLDM_ABI_STABLE
encode_apply_complete_resp(uint8_t instance_id,uint8_t completion_code,struct pldm_msg * msg,size_t payload_length)1739 int encode_apply_complete_resp(uint8_t instance_id, uint8_t completion_code,
1740 			       struct pldm_msg *msg, size_t payload_length)
1741 {
1742 	if (msg == NULL) {
1743 		return PLDM_ERROR_INVALID_DATA;
1744 	}
1745 
1746 	if (payload_length != sizeof(completion_code)) {
1747 		return PLDM_ERROR_INVALID_LENGTH;
1748 	}
1749 
1750 	struct pldm_header_info header = { 0 };
1751 	header.instance = instance_id;
1752 	header.msg_type = PLDM_RESPONSE;
1753 	header.pldm_type = PLDM_FWUP;
1754 	header.command = PLDM_APPLY_COMPLETE;
1755 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1756 	if (rc) {
1757 		return rc;
1758 	}
1759 
1760 	msg->payload[0] = completion_code;
1761 
1762 	return PLDM_SUCCESS;
1763 }
1764 
1765 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)1766 int encode_activate_firmware_req(uint8_t instance_id,
1767 				 bool8_t self_contained_activation_req,
1768 				 struct pldm_msg *msg, size_t payload_length)
1769 {
1770 	if (msg == NULL) {
1771 		return PLDM_ERROR_INVALID_DATA;
1772 	}
1773 
1774 	if (payload_length != sizeof(struct pldm_activate_firmware_req)) {
1775 		return PLDM_ERROR_INVALID_LENGTH;
1776 	}
1777 
1778 	if (!is_self_contained_activation_req_valid(
1779 		    self_contained_activation_req)) {
1780 		return PLDM_ERROR_INVALID_DATA;
1781 	}
1782 
1783 	struct pldm_header_info header = { 0 };
1784 	header.instance = instance_id;
1785 	header.msg_type = PLDM_REQUEST;
1786 	header.pldm_type = PLDM_FWUP;
1787 	header.command = PLDM_ACTIVATE_FIRMWARE;
1788 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1789 	if (rc) {
1790 		return rc;
1791 	}
1792 
1793 	struct pldm_activate_firmware_req *request =
1794 		(struct pldm_activate_firmware_req *)msg->payload;
1795 
1796 	request->self_contained_activation_req = self_contained_activation_req;
1797 
1798 	return PLDM_SUCCESS;
1799 }
1800 
1801 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)1802 int decode_activate_firmware_resp(const struct pldm_msg *msg,
1803 				  size_t payload_length,
1804 				  uint8_t *completion_code,
1805 				  uint16_t *estimated_time_activation)
1806 {
1807 	if (msg == NULL || completion_code == NULL ||
1808 	    estimated_time_activation == NULL || !payload_length) {
1809 		return PLDM_ERROR_INVALID_DATA;
1810 	}
1811 
1812 	*completion_code = msg->payload[0];
1813 	if (*completion_code != PLDM_SUCCESS) {
1814 		return PLDM_SUCCESS;
1815 	}
1816 
1817 	if (payload_length != sizeof(struct pldm_activate_firmware_resp)) {
1818 		return PLDM_ERROR_INVALID_LENGTH;
1819 	}
1820 
1821 	struct pldm_activate_firmware_resp *response =
1822 		(struct pldm_activate_firmware_resp *)msg->payload;
1823 
1824 	*estimated_time_activation =
1825 		le16toh(response->estimated_time_activation);
1826 
1827 	return PLDM_SUCCESS;
1828 }
1829 
1830 LIBPLDM_ABI_STABLE
encode_get_status_req(uint8_t instance_id,struct pldm_msg * msg,size_t payload_length)1831 int encode_get_status_req(uint8_t instance_id, struct pldm_msg *msg,
1832 			  size_t payload_length)
1833 {
1834 	if (msg == NULL) {
1835 		return PLDM_ERROR_INVALID_DATA;
1836 	}
1837 
1838 	if (payload_length != PLDM_GET_STATUS_REQ_BYTES) {
1839 		return PLDM_ERROR_INVALID_LENGTH;
1840 	}
1841 
1842 	struct pldm_header_info header = { 0 };
1843 	header.instance = instance_id;
1844 	header.msg_type = PLDM_REQUEST;
1845 	header.pldm_type = PLDM_FWUP;
1846 	header.command = PLDM_GET_STATUS;
1847 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1848 	if (rc) {
1849 		return rc;
1850 	}
1851 
1852 	return PLDM_SUCCESS;
1853 }
1854 
1855 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)1856 int decode_get_status_resp(const struct pldm_msg *msg, size_t payload_length,
1857 			   uint8_t *completion_code, uint8_t *current_state,
1858 			   uint8_t *previous_state, uint8_t *aux_state,
1859 			   uint8_t *aux_state_status, uint8_t *progress_percent,
1860 			   uint8_t *reason_code,
1861 			   bitfield32_t *update_option_flags_enabled)
1862 {
1863 	if (msg == NULL || completion_code == NULL || current_state == NULL ||
1864 	    previous_state == NULL || aux_state == NULL ||
1865 	    aux_state_status == NULL || progress_percent == NULL ||
1866 	    reason_code == NULL || update_option_flags_enabled == NULL ||
1867 	    !payload_length) {
1868 		return PLDM_ERROR_INVALID_DATA;
1869 	}
1870 
1871 	*completion_code = msg->payload[0];
1872 	if (*completion_code != PLDM_SUCCESS) {
1873 		return PLDM_SUCCESS;
1874 	}
1875 
1876 	if (payload_length != sizeof(struct pldm_get_status_resp)) {
1877 		return PLDM_ERROR_INVALID_LENGTH;
1878 	}
1879 	struct pldm_get_status_resp *response =
1880 		(struct pldm_get_status_resp *)msg->payload;
1881 
1882 	if (!is_state_valid(response->current_state)) {
1883 		return PLDM_ERROR_INVALID_DATA;
1884 	}
1885 	if (!is_state_valid(response->previous_state)) {
1886 		return PLDM_ERROR_INVALID_DATA;
1887 	}
1888 	if (!is_aux_state_valid(response->aux_state)) {
1889 		return PLDM_ERROR_INVALID_DATA;
1890 	}
1891 	if (!is_aux_state_status_valid(response->aux_state_status)) {
1892 		return PLDM_ERROR_INVALID_DATA;
1893 	}
1894 	if (response->progress_percent > PLDM_FWUP_MAX_PROGRESS_PERCENT) {
1895 		return PLDM_ERROR_INVALID_DATA;
1896 	}
1897 	if (!is_reason_code_valid(response->reason_code)) {
1898 		return PLDM_ERROR_INVALID_DATA;
1899 	}
1900 
1901 	if ((response->current_state == PLDM_FD_STATE_IDLE) ||
1902 	    (response->current_state == PLDM_FD_STATE_LEARN_COMPONENTS) ||
1903 	    (response->current_state == PLDM_FD_STATE_READY_XFER)) {
1904 		if (response->aux_state !=
1905 		    PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER) {
1906 			return PLDM_ERROR_INVALID_DATA;
1907 		}
1908 	}
1909 
1910 	*current_state = response->current_state;
1911 	*previous_state = response->previous_state;
1912 	*aux_state = response->aux_state;
1913 	*aux_state_status = response->aux_state_status;
1914 	*progress_percent = response->progress_percent;
1915 	*reason_code = response->reason_code;
1916 	update_option_flags_enabled->value =
1917 		le32toh(response->update_option_flags_enabled.value);
1918 
1919 	return PLDM_SUCCESS;
1920 }
1921 
1922 LIBPLDM_ABI_STABLE
encode_cancel_update_component_req(uint8_t instance_id,struct pldm_msg * msg,size_t payload_length)1923 int encode_cancel_update_component_req(uint8_t instance_id,
1924 				       struct pldm_msg *msg,
1925 				       size_t payload_length)
1926 {
1927 	if (msg == NULL) {
1928 		return PLDM_ERROR_INVALID_DATA;
1929 	}
1930 
1931 	if (payload_length != PLDM_CANCEL_UPDATE_COMPONENT_REQ_BYTES) {
1932 		return PLDM_ERROR_INVALID_LENGTH;
1933 	}
1934 
1935 	struct pldm_header_info header = { 0 };
1936 	header.instance = instance_id;
1937 	header.msg_type = PLDM_REQUEST;
1938 	header.pldm_type = PLDM_FWUP;
1939 	header.command = PLDM_CANCEL_UPDATE_COMPONENT;
1940 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1941 	if (rc) {
1942 		return rc;
1943 	}
1944 
1945 	return PLDM_SUCCESS;
1946 }
1947 
1948 LIBPLDM_ABI_STABLE
decode_cancel_update_component_resp(const struct pldm_msg * msg,size_t payload_length,uint8_t * completion_code)1949 int decode_cancel_update_component_resp(const struct pldm_msg *msg,
1950 					size_t payload_length,
1951 					uint8_t *completion_code)
1952 {
1953 	if (msg == NULL || completion_code == NULL) {
1954 		return PLDM_ERROR_INVALID_DATA;
1955 	}
1956 
1957 	if (payload_length != sizeof(*completion_code)) {
1958 		return PLDM_ERROR_INVALID_LENGTH;
1959 	}
1960 
1961 	*completion_code = msg->payload[0];
1962 	return PLDM_SUCCESS;
1963 }
1964 
1965 LIBPLDM_ABI_STABLE
encode_cancel_update_req(uint8_t instance_id,struct pldm_msg * msg,size_t payload_length)1966 int encode_cancel_update_req(uint8_t instance_id, struct pldm_msg *msg,
1967 			     size_t payload_length)
1968 {
1969 	if (msg == NULL) {
1970 		return PLDM_ERROR_INVALID_DATA;
1971 	}
1972 
1973 	if (payload_length != PLDM_CANCEL_UPDATE_REQ_BYTES) {
1974 		return PLDM_ERROR_INVALID_LENGTH;
1975 	}
1976 
1977 	struct pldm_header_info header = { 0 };
1978 	header.instance = instance_id;
1979 	header.msg_type = PLDM_REQUEST;
1980 	header.pldm_type = PLDM_FWUP;
1981 	header.command = PLDM_CANCEL_UPDATE;
1982 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1983 	if (rc) {
1984 		return rc;
1985 	}
1986 
1987 	return PLDM_SUCCESS;
1988 }
1989 
1990 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)1991 int decode_cancel_update_resp(const struct pldm_msg *msg, size_t payload_length,
1992 			      uint8_t *completion_code,
1993 			      bool8_t *non_functioning_component_indication,
1994 			      bitfield64_t *non_functioning_component_bitmap)
1995 {
1996 	if (msg == NULL || completion_code == NULL ||
1997 	    non_functioning_component_indication == NULL ||
1998 	    non_functioning_component_bitmap == NULL || !payload_length) {
1999 		return PLDM_ERROR_INVALID_DATA;
2000 	}
2001 
2002 	*completion_code = msg->payload[0];
2003 	if (*completion_code != PLDM_SUCCESS) {
2004 		return PLDM_SUCCESS;
2005 	}
2006 
2007 	if (payload_length != sizeof(struct pldm_cancel_update_resp)) {
2008 		return PLDM_ERROR_INVALID_LENGTH;
2009 	}
2010 	struct pldm_cancel_update_resp *response =
2011 		(struct pldm_cancel_update_resp *)msg->payload;
2012 
2013 	if (!is_non_functioning_component_indication_valid(
2014 		    response->non_functioning_component_indication)) {
2015 		return PLDM_ERROR_INVALID_DATA;
2016 	}
2017 
2018 	*non_functioning_component_indication =
2019 		response->non_functioning_component_indication;
2020 
2021 	if (*non_functioning_component_indication) {
2022 		non_functioning_component_bitmap->value =
2023 			le64toh(response->non_functioning_component_bitmap);
2024 	}
2025 
2026 	return PLDM_SUCCESS;
2027 }
2028