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