xref: /openbmc/libpldm/src/dsp/firmware_update.c (revision 2613c2785d5cd5e4c007d1bca8bb414079c85ffb)
1 /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
2 #include "api.h"
3 #include "array.h"
4 #include "compiler.h"
5 #include "dsp/base.h"
6 #include "msgbuf.h"
7 #include <libpldm/base.h>
8 #include <libpldm/compiler.h>
9 #include <libpldm/firmware_update.h>
10 #include <libpldm/utils.h>
11 
12 #include <endian.h>
13 #include <stdbool.h>
14 #include <string.h>
15 
16 static_assert(PLDM_FIRMWARE_MAX_STRING <= UINT8_MAX, "too large");
17 
18 /** @brief Check whether string type value is valid
19  *
20  *  @return true if string type value is valid, false if not
21  */
is_string_type_valid(uint8_t string_type)22 static bool is_string_type_valid(uint8_t string_type)
23 {
24 	switch (string_type) {
25 	case PLDM_STR_TYPE_UNKNOWN:
26 		return false;
27 	case PLDM_STR_TYPE_ASCII:
28 	case PLDM_STR_TYPE_UTF_8:
29 	case PLDM_STR_TYPE_UTF_16:
30 	case PLDM_STR_TYPE_UTF_16LE:
31 	case PLDM_STR_TYPE_UTF_16BE:
32 		return true;
33 	default:
34 		return false;
35 	}
36 }
37 
38 /** @brief Return the length of the descriptor type described in firmware update
39  *         specification
40  *
41  *  @return length of the descriptor type if descriptor type is valid else
42  *          return 0
43  */
get_descriptor_type_length(uint16_t descriptor_type)44 static uint16_t get_descriptor_type_length(uint16_t descriptor_type)
45 {
46 	switch (descriptor_type) {
47 	case PLDM_FWUP_PCI_VENDOR_ID:
48 		return PLDM_FWUP_PCI_VENDOR_ID_LENGTH;
49 	case PLDM_FWUP_IANA_ENTERPRISE_ID:
50 		return PLDM_FWUP_IANA_ENTERPRISE_ID_LENGTH;
51 	case PLDM_FWUP_UUID:
52 		return PLDM_FWUP_UUID_LENGTH;
53 	case PLDM_FWUP_PNP_VENDOR_ID:
54 		return PLDM_FWUP_PNP_VENDOR_ID_LENGTH;
55 	case PLDM_FWUP_ACPI_VENDOR_ID:
56 		return PLDM_FWUP_ACPI_VENDOR_ID_LENGTH;
57 	case PLDM_FWUP_IEEE_ASSIGNED_COMPANY_ID:
58 		return PLDM_FWUP_IEEE_ASSIGNED_COMPANY_ID_LENGTH;
59 	case PLDM_FWUP_SCSI_VENDOR_ID:
60 		return PLDM_FWUP_SCSI_VENDOR_ID_LENGTH;
61 	case PLDM_FWUP_PCI_DEVICE_ID:
62 		return PLDM_FWUP_PCI_DEVICE_ID_LENGTH;
63 	case PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID:
64 		return PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID_LENGTH;
65 	case PLDM_FWUP_PCI_SUBSYSTEM_ID:
66 		return PLDM_FWUP_PCI_SUBSYSTEM_ID_LENGTH;
67 	case PLDM_FWUP_PCI_REVISION_ID:
68 		return PLDM_FWUP_PCI_REVISION_ID_LENGTH;
69 	case PLDM_FWUP_PNP_PRODUCT_IDENTIFIER:
70 		return PLDM_FWUP_PNP_PRODUCT_IDENTIFIER_LENGTH;
71 	case PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER:
72 		return PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER_LENGTH;
73 	case PLDM_FWUP_ASCII_MODEL_NUMBER_LONG_STRING:
74 		return PLDM_FWUP_ASCII_MODEL_NUMBER_LONG_STRING_LENGTH;
75 	case PLDM_FWUP_ASCII_MODEL_NUMBER_SHORT_STRING:
76 		return PLDM_FWUP_ASCII_MODEL_NUMBER_SHORT_STRING_LENGTH;
77 	case PLDM_FWUP_SCSI_PRODUCT_ID:
78 		return PLDM_FWUP_SCSI_PRODUCT_ID_LENGTH;
79 	case PLDM_FWUP_UBM_CONTROLLER_DEVICE_CODE:
80 		return PLDM_FWUP_UBM_CONTROLLER_DEVICE_CODE_LENGTH;
81 	default:
82 		return 0;
83 	}
84 }
85 
is_downstream_device_update_support_valid(uint8_t resp)86 static bool is_downstream_device_update_support_valid(uint8_t resp)
87 {
88 	switch (resp) {
89 	case PLDM_FWUP_DOWNSTREAM_DEVICE_UPDATE_NOT_SUPPORTED:
90 	case PLDM_FWUP_DOWNSTREAM_DEVICE_UPDATE_SUPPORTED:
91 		return true;
92 	default:
93 		return false;
94 	}
95 }
96 
97 static bool
is_transfer_operation_flag_valid(enum transfer_op_flag transfer_op_flag)98 is_transfer_operation_flag_valid(enum transfer_op_flag transfer_op_flag)
99 {
100 	switch (transfer_op_flag) {
101 	case PLDM_GET_NEXTPART:
102 	case PLDM_GET_FIRSTPART:
103 		return true;
104 	default:
105 		return false;
106 	}
107 }
108 
109 /** @brief Check whether ComponentResponse is valid
110  *
111  *  @return true if ComponentResponse is valid, false if not
112  */
is_comp_resp_valid(uint8_t comp_resp)113 static bool is_comp_resp_valid(uint8_t comp_resp)
114 {
115 	switch (comp_resp) {
116 	case PLDM_CR_COMP_CAN_BE_UPDATED:
117 	case PLDM_CR_COMP_MAY_BE_UPDATEABLE:
118 		return true;
119 
120 	default:
121 		return false;
122 	}
123 }
124 
125 /** @brief Check whether ComponentResponseCode is valid
126  *
127  *  @return true if ComponentResponseCode is valid, false if not
128  */
is_comp_resp_code_valid(uint8_t comp_resp_code)129 static bool is_comp_resp_code_valid(uint8_t comp_resp_code)
130 {
131 	switch (comp_resp_code) {
132 	case PLDM_CRC_COMP_CAN_BE_UPDATED:
133 	case PLDM_CRC_COMP_COMPARISON_STAMP_IDENTICAL:
134 	case PLDM_CRC_COMP_COMPARISON_STAMP_LOWER:
135 	case PLDM_CRC_INVALID_COMP_COMPARISON_STAMP:
136 	case PLDM_CRC_COMP_CONFLICT:
137 	case PLDM_CRC_COMP_PREREQUISITES_NOT_MET:
138 	case PLDM_CRC_COMP_NOT_SUPPORTED:
139 	case PLDM_CRC_COMP_SECURITY_RESTRICTIONS:
140 	case PLDM_CRC_INCOMPLETE_COMP_IMAGE_SET:
141 	case PLDM_CRC_ACTIVE_IMAGE_NOT_UPDATEABLE_SUBSEQUENTLY:
142 	case PLDM_CRC_COMP_VER_STR_IDENTICAL:
143 	case PLDM_CRC_COMP_VER_STR_LOWER:
144 		return true;
145 
146 	default:
147 		if (comp_resp_code >=
148 			    PLDM_CRC_VENDOR_COMP_RESP_CODE_RANGE_MIN &&
149 		    comp_resp_code <=
150 			    PLDM_CRC_VENDOR_COMP_RESP_CODE_RANGE_MAX) {
151 			return true;
152 		}
153 		return false;
154 	}
155 }
156 
157 /** @brief Check whether ComponentCompatibilityResponse is valid
158  *
159  *  @return true if ComponentCompatibilityResponse is valid, false if not
160  */
is_comp_compatibility_resp_valid(uint8_t comp_compatibility_resp)161 static bool is_comp_compatibility_resp_valid(uint8_t comp_compatibility_resp)
162 {
163 	switch (comp_compatibility_resp) {
164 	case PLDM_CCR_COMP_CAN_BE_UPDATED:
165 	case PLDM_CCR_COMP_CANNOT_BE_UPDATED:
166 		return true;
167 
168 	default:
169 		return false;
170 	}
171 }
172 
173 /** @brief Check whether ComponentCompatibilityResponse Code is valid
174  *
175  *  @return true if ComponentCompatibilityResponse Code is valid, false if not
176  */
177 static bool
is_comp_compatibility_resp_code_valid(uint8_t comp_compatibility_resp_code)178 is_comp_compatibility_resp_code_valid(uint8_t comp_compatibility_resp_code)
179 {
180 	switch (comp_compatibility_resp_code) {
181 	case PLDM_CCRC_NO_RESPONSE_CODE:
182 	case PLDM_CCRC_COMP_COMPARISON_STAMP_IDENTICAL:
183 	case PLDM_CCRC_COMP_COMPARISON_STAMP_LOWER:
184 	case PLDM_CCRC_INVALID_COMP_COMPARISON_STAMP:
185 	case PLDM_CCRC_COMP_CONFLICT:
186 	case PLDM_CCRC_COMP_PREREQUISITES_NOT_MET:
187 	case PLDM_CCRC_COMP_NOT_SUPPORTED:
188 	case PLDM_CCRC_COMP_SECURITY_RESTRICTIONS:
189 	case PLDM_CRC_INCOMPLETE_COMP_IMAGE_SET:
190 	case PLDM_CCRC_COMP_INFO_NO_MATCH:
191 	case PLDM_CCRC_COMP_VER_STR_IDENTICAL:
192 	case PLDM_CCRC_COMP_VER_STR_LOWER:
193 		return true;
194 
195 	default:
196 		if (comp_compatibility_resp_code >=
197 			    PLDM_CCRC_VENDOR_COMP_RESP_CODE_RANGE_MIN &&
198 		    comp_compatibility_resp_code <=
199 			    PLDM_CCRC_VENDOR_COMP_RESP_CODE_RANGE_MAX) {
200 			return true;
201 		}
202 		return false;
203 	}
204 }
205 
206 /** @brief Check whether SelfContainedActivationRequest is valid
207  *
208  *  @return true if SelfContainedActivationRequest is valid, false if not
209  */
210 static bool
is_self_contained_activation_req_valid(bool8_t self_contained_activation_req)211 is_self_contained_activation_req_valid(bool8_t self_contained_activation_req)
212 {
213 	switch (self_contained_activation_req) {
214 	case PLDM_NOT_ACTIVATE_SELF_CONTAINED_COMPONENTS:
215 	case PLDM_ACTIVATE_SELF_CONTAINED_COMPONENTS:
216 		return true;
217 
218 	default:
219 		return false;
220 	}
221 }
222 
223 /** @brief Check if current or previous status in GetStatus command response is
224  *         valid
225  *
226  *	@param[in] state - current or previous different state machine state of
227  *                     the FD
228  *	@return true if state is valid, false if not
229  */
is_state_valid(uint8_t state)230 static bool is_state_valid(uint8_t state)
231 {
232 	switch (state) {
233 	case PLDM_FD_STATE_IDLE:
234 	case PLDM_FD_STATE_LEARN_COMPONENTS:
235 	case PLDM_FD_STATE_READY_XFER:
236 	case PLDM_FD_STATE_DOWNLOAD:
237 	case PLDM_FD_STATE_VERIFY:
238 	case PLDM_FD_STATE_APPLY:
239 	case PLDM_FD_STATE_ACTIVATE:
240 		return true;
241 
242 	default:
243 		return false;
244 	}
245 }
246 
247 /** @brief Check if aux state in GetStatus command response is valid
248  *
249  *  @param[in] aux_state - provides additional information to the UA to describe
250  *                         the current operation state of the FD/FDP
251  *
252  *	@return true if aux state is valid, false if not
253  */
is_aux_state_valid(uint8_t aux_state)254 static bool is_aux_state_valid(uint8_t aux_state)
255 {
256 	switch (aux_state) {
257 	case PLDM_FD_OPERATION_IN_PROGRESS:
258 	case PLDM_FD_OPERATION_SUCCESSFUL:
259 	case PLDM_FD_OPERATION_FAILED:
260 	case PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER:
261 		return true;
262 
263 	default:
264 		return false;
265 	}
266 }
267 
268 /** @brief Check if aux state status in GetStatus command response is valid
269  *
270  *	@param[in] aux_state_status - aux state status
271  *
272  *	@return true if aux state status is valid, false if not
273  */
is_aux_state_status_valid(uint8_t aux_state_status)274 static bool is_aux_state_status_valid(uint8_t aux_state_status)
275 {
276 	if (aux_state_status == PLDM_FD_AUX_STATE_IN_PROGRESS_OR_SUCCESS ||
277 	    aux_state_status == PLDM_FD_TIMEOUT ||
278 	    aux_state_status == PLDM_FD_GENERIC_ERROR ||
279 	    (aux_state_status >= PLDM_FD_VENDOR_DEFINED_STATUS_CODE_START &&
280 	     aux_state_status <= PLDM_FD_VENDOR_DEFINED_STATUS_CODE_END)) {
281 		return true;
282 	}
283 
284 	return false;
285 }
286 
287 /** @brief Check if reason code in GetStatus command response is valid
288  *
289  *	@param[in] reason_code - provides the reason for why the current state
290  *                           entered the IDLE state
291  *
292  *	@return true if reason code is valid, false if not
293  */
is_reason_code_valid(uint8_t reason_code)294 static bool is_reason_code_valid(uint8_t reason_code)
295 {
296 	switch (reason_code) {
297 	case PLDM_FD_INITIALIZATION:
298 	case PLDM_FD_ACTIVATE_FW:
299 	case PLDM_FD_CANCEL_UPDATE:
300 	case PLDM_FD_TIMEOUT_LEARN_COMPONENT:
301 	case PLDM_FD_TIMEOUT_READY_XFER:
302 	case PLDM_FD_TIMEOUT_DOWNLOAD:
303 	case PLDM_FD_TIMEOUT_VERIFY:
304 	case PLDM_FD_TIMEOUT_APPLY:
305 		return true;
306 
307 	default:
308 		if (reason_code >= PLDM_FD_STATUS_VENDOR_DEFINED_MIN) {
309 			return true;
310 		}
311 		return false;
312 	}
313 }
314 
315 /** @brief Check if non functioning component indication in CancelUpdate
316  *         response is valid
317  *
318  *  @return true if non functioning component indication is valid, false if not
319  */
is_non_functioning_component_indication_valid(bool8_t non_functioning_component_indication)320 static bool is_non_functioning_component_indication_valid(
321 	bool8_t non_functioning_component_indication)
322 {
323 	switch (non_functioning_component_indication) {
324 	case PLDM_FWUP_COMPONENTS_FUNCTIONING:
325 	case PLDM_FWUP_COMPONENTS_NOT_FUNCTIONING:
326 		return true;
327 
328 	default:
329 		return false;
330 	}
331 }
332 
333 #define PLDM_FWUP_PACKAGE_HEADER_FIXED_SIZE 36
334 LIBPLDM_CC_NONNULL
335 static int
decode_pldm_package_header_info_errno(const void * data,size_t length,const struct pldm_package_format_pin * pin,pldm_package_header_information_pad * hdr)336 decode_pldm_package_header_info_errno(const void *data, size_t length,
337 				      const struct pldm_package_format_pin *pin,
338 				      pldm_package_header_information_pad *hdr)
339 {
340 	static const struct pldm_package_header_format_revision_info {
341 		pldm_uuid identifier;
342 		size_t magic;
343 	} revision_info[1 + PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR02H] = {
344 		[0] = {
345 			.identifier = {0},
346 			.magic = 0,
347 		},
348 		[PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H] = { /* PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H */
349 			.identifier = PLDM_PACKAGE_HEADER_IDENTIFIER_V1_0,
350 			.magic =
351 				LIBPLDM_SIZEAT(struct pldm__package_header_information, package) +
352 				LIBPLDM_SIZEAT(struct pldm_package_firmware_device_id_record, firmware_device_package_data) +
353 				LIBPLDM_SIZEAT(struct pldm_descriptor, descriptor_data) +
354 				LIBPLDM_SIZEAT(struct pldm_package_component_image_information, component_version_string) +
355 				LIBPLDM_SIZEAT(struct pldm_package_iter, infos)
356 		},
357 		[PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR02H] = { /* PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR02H */
358 			.identifier = PLDM_PACKAGE_HEADER_IDENTIFIER_V1_1,
359 			.magic =
360 				LIBPLDM_SIZEAT(struct pldm__package_header_information, package) +
361 				LIBPLDM_SIZEAT(struct pldm_package_firmware_device_id_record, firmware_device_package_data) +
362 				LIBPLDM_SIZEAT(struct pldm_descriptor, descriptor_data) +
363 				LIBPLDM_SIZEAT(struct pldm_package_downstream_device_id_record, package_data) +
364 				LIBPLDM_SIZEAT(struct pldm_package_component_image_information, component_version_string) +
365 				LIBPLDM_SIZEAT(struct pldm_package_iter, infos),
366 		},
367 	};
368 
369 	const struct pldm_package_header_format_revision_info *info;
370 	uint32_t package_header_checksum = 0;
371 	size_t package_header_variable_size;
372 	size_t package_header_payload_size;
373 	size_t package_header_areas_size;
374 	uint16_t package_header_size;
375 	PLDM_MSGBUF_DEFINE_P(buf);
376 	int checksums = 1;
377 	int rc;
378 
379 	if (pin->meta.version > 0) {
380 		return -ENOTSUP;
381 	}
382 
383 	if (pin->format.revision == 0) {
384 		return -EINVAL;
385 	}
386 
387 	if (pin->format.revision > PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR02H) {
388 		return -ENOTSUP;
389 	}
390 	static_assert(ARRAY_SIZE(revision_info) ==
391 			      1 + PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR02H,
392 		      "Mismatched array bounds test");
393 
394 	info = &revision_info[pin->format.revision];
395 	if (memcmp(&pin->format.identifier, info->identifier,
396 		   sizeof(info->identifier)) != 0) {
397 		return -ENOTSUP;
398 	}
399 
400 	if (pin->meta.magic != info->magic) {
401 		return -EINVAL;
402 	}
403 
404 	rc = pldm_msgbuf_init_errno(buf, PLDM_FWUP_PACKAGE_HEADER_FIXED_SIZE,
405 				    data, length);
406 	if (rc) {
407 		return rc;
408 	}
409 
410 	rc = pldm_msgbuf_extract_array(buf,
411 				       sizeof(hdr->package_header_identifier),
412 				       hdr->package_header_identifier,
413 				       sizeof(hdr->package_header_identifier));
414 	if (rc) {
415 		return pldm_msgbuf_discard(buf, rc);
416 	}
417 
418 	if (memcmp(revision_info[PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H]
419 			   .identifier,
420 		   hdr->package_header_identifier,
421 		   sizeof(hdr->package_header_identifier)) != 0 &&
422 	    memcmp(revision_info[PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR02H]
423 			   .identifier,
424 		   hdr->package_header_identifier,
425 		   sizeof(hdr->package_header_identifier)) != 0) {
426 		return pldm_msgbuf_discard(buf, -ENOTSUP);
427 	}
428 
429 	rc = pldm_msgbuf_extract(buf, hdr->package_header_format_revision);
430 	if (rc) {
431 		return pldm_msgbuf_discard(buf, rc);
432 	}
433 	if (hdr->package_header_format_revision > pin->format.revision) {
434 		return pldm_msgbuf_discard(buf, -ENOTSUP);
435 	}
436 
437 	rc = pldm_msgbuf_extract(buf, package_header_size);
438 	if (rc) {
439 		return pldm_msgbuf_discard(buf, rc);
440 	}
441 
442 	rc = pldm_msgbuf_extract_array(buf,
443 				       sizeof(hdr->package_release_date_time),
444 				       hdr->package_release_date_time,
445 				       sizeof(hdr->package_release_date_time));
446 	if (rc) {
447 		return pldm_msgbuf_discard(buf, rc);
448 	}
449 
450 	rc = pldm_msgbuf_extract(buf, hdr->component_bitmap_bit_length);
451 	if (rc) {
452 		return pldm_msgbuf_discard(buf, rc);
453 	}
454 	if (hdr->component_bitmap_bit_length & 7) {
455 		return pldm_msgbuf_discard(buf, -EPROTO);
456 	}
457 
458 	rc = pldm_msgbuf_extract(buf, hdr->package_version_string_type);
459 	if (rc) {
460 		return pldm_msgbuf_discard(buf, rc);
461 	}
462 	if (!is_string_type_valid(hdr->package_version_string_type)) {
463 		return pldm_msgbuf_discard(buf, -EPROTO);
464 	}
465 
466 	rc = pldm_msgbuf_extract_uint8_to_size(
467 		buf, hdr->package_version_string.length);
468 	if (rc) {
469 		return pldm_msgbuf_discard(buf, rc);
470 	}
471 
472 	pldm_msgbuf_span_required(buf, hdr->package_version_string.length,
473 				  (void **)&hdr->package_version_string.ptr);
474 
475 	if (package_header_size < (PLDM_FWUP_PACKAGE_HEADER_FIXED_SIZE + 3 +
476 				   checksums * sizeof(uint32_t))) {
477 		return pldm_msgbuf_discard(buf, -EOVERFLOW);
478 	}
479 	package_header_payload_size =
480 		package_header_size - (checksums * sizeof(uint32_t));
481 	package_header_variable_size = package_header_payload_size -
482 				       PLDM_FWUP_PACKAGE_HEADER_FIXED_SIZE;
483 
484 	if (package_header_variable_size < hdr->package_version_string.length) {
485 		return pldm_msgbuf_discard(buf, -EOVERFLOW);
486 	}
487 
488 	package_header_areas_size = package_header_variable_size -
489 				    hdr->package_version_string.length;
490 	rc = pldm_msgbuf_span_required(buf, package_header_areas_size,
491 				       (void **)&hdr->areas.ptr);
492 	if (rc) {
493 		return pldm_msgbuf_discard(buf, rc);
494 	}
495 	hdr->areas.length = package_header_areas_size;
496 
497 	pldm_msgbuf_extract(buf, package_header_checksum);
498 
499 	rc = pldm_msgbuf_complete(buf);
500 	if (rc) {
501 		return rc;
502 	}
503 
504 	// TODO: pldm_edac_crc32_test(uint32_t expected, const void *data, size_t len)
505 	if (package_header_checksum !=
506 	    pldm_edac_crc32(data, package_header_payload_size)) {
507 #if 0
508 		printf("checksum failure, expected: %#08" PRIx32 ", found: %#08" PRIx32 "\n", package_header_checksum, pldm_edac_crc32(data, package_header_payload_size));
509 #endif
510 		return -EUCLEAN;
511 	}
512 
513 	/* We stash these to resolve component images later */
514 	hdr->package.ptr = data;
515 	hdr->package.length = length;
516 
517 	return 0;
518 }
519 
520 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)521 int decode_pldm_package_header_info(
522 	const uint8_t *data, size_t length,
523 	struct pldm_package_header_information *package_header_info,
524 	struct variable_field *package_version_str)
525 {
526 	DEFINE_PLDM_PACKAGE_FORMAT_PIN_FR01H(pin);
527 	pldm_package_header_information_pad hdr;
528 	int rc;
529 
530 	if (!data || !package_header_info || !package_version_str) {
531 		return PLDM_ERROR_INVALID_DATA;
532 	}
533 
534 	rc = decode_pldm_package_header_info_errno(data, length, &pin, &hdr);
535 	if (rc < 0) {
536 		return pldm_xlate_errno(rc);
537 	}
538 
539 	static_assert(sizeof(package_header_info->uuid) ==
540 			      sizeof(hdr.package_header_identifier),
541 		      "UUID field size");
542 	memcpy(package_header_info->uuid, hdr.package_header_identifier,
543 	       sizeof(hdr.package_header_identifier));
544 	package_header_info->package_header_format_version =
545 		hdr.package_header_format_revision;
546 	memcpy(&package_header_info->package_header_size, data + 17,
547 	       sizeof(package_header_info->package_header_size));
548 	LE16TOH(package_header_info->package_header_size);
549 	static_assert(sizeof(package_header_info->package_release_date_time) ==
550 			      sizeof(hdr.package_release_date_time),
551 		      "TIMESTAMP104 field size");
552 	memcpy(package_header_info->package_release_date_time,
553 	       hdr.package_release_date_time,
554 	       sizeof(hdr.package_release_date_time));
555 	package_header_info->component_bitmap_bit_length =
556 		hdr.component_bitmap_bit_length;
557 	package_header_info->package_version_string_type =
558 		hdr.package_version_string_type;
559 	package_header_info->package_version_string_length =
560 		hdr.package_version_string.length;
561 	*package_version_str = hdr.package_version_string;
562 
563 	return PLDM_SUCCESS;
564 }
565 
566 /* Currently only used for decode_firmware_device_id_record_errno() */
pldm_msgbuf_init_dynamic_uint16(struct pldm_msgbuf * buf,size_t req,void * data,size_t len,void ** tail_data,size_t * tail_len)567 static int pldm_msgbuf_init_dynamic_uint16(struct pldm_msgbuf *buf, size_t req,
568 					   void *data, size_t len,
569 					   void **tail_data, size_t *tail_len)
570 {
571 	size_t dyn_length;
572 	void *dyn_start;
573 	int rc;
574 
575 	rc = pldm_msgbuf_init_errno(buf, req, data, len);
576 	if (rc) {
577 		return rc;
578 	}
579 	/*
580 	 * Extract the record length from the first field, then reinitialise the msgbuf
581 	 * after determining that it's safe to do so
582 	 */
583 
584 	rc = pldm_msgbuf_extract_uint16_to_size(buf, dyn_length);
585 	if (rc) {
586 		return pldm_msgbuf_discard(buf, rc);
587 	}
588 
589 	rc = pldm_msgbuf_complete(buf);
590 	if (rc) {
591 		return rc;
592 	}
593 
594 	rc = pldm_msgbuf_init_errno(buf, req, data, len);
595 	if (rc) {
596 		return rc;
597 	}
598 
599 	/* Ensure there's no arithmetic funkiness and the span is within buffer bounds */
600 	rc = pldm_msgbuf_span_required(buf, dyn_length, &dyn_start);
601 	if (rc) {
602 		return pldm_msgbuf_discard(buf, rc);
603 	}
604 
605 	rc = pldm_msgbuf_span_remaining(buf, tail_data, tail_len);
606 	if (rc) {
607 		return pldm_msgbuf_discard(buf, rc);
608 	}
609 
610 	rc = pldm_msgbuf_complete(buf);
611 	if (rc) {
612 		return rc;
613 	}
614 
615 	return pldm_msgbuf_init_errno(buf, req, dyn_start, dyn_length);
616 }
617 
618 #define PLDM_FWUP_FIRMWARE_DEVICE_ID_RECORD_MIN_SIZE 11
decode_pldm_package_firmware_device_id_record_errno(const pldm_package_header_information_pad * hdr,struct variable_field * field,struct pldm_package_firmware_device_id_record * rec)619 static int decode_pldm_package_firmware_device_id_record_errno(
620 	const pldm_package_header_information_pad *hdr,
621 	struct variable_field *field,
622 	struct pldm_package_firmware_device_id_record *rec)
623 {
624 	PLDM_MSGBUF_DEFINE_P(buf);
625 	uint16_t record_len = 0;
626 	int rc;
627 
628 	if (!hdr || !field || !rec || !field->ptr) {
629 		return -EINVAL;
630 	}
631 
632 	if (hdr->component_bitmap_bit_length & 7) {
633 		return -EPROTO;
634 	}
635 
636 	rc = pldm_msgbuf_init_dynamic_uint16(
637 		buf, PLDM_FWUP_FIRMWARE_DEVICE_ID_RECORD_MIN_SIZE,
638 		(void *)field->ptr, field->length, (void **)&field->ptr,
639 		&field->length);
640 	if (rc) {
641 		return rc;
642 	}
643 
644 	pldm_msgbuf_extract(buf, record_len);
645 	pldm_msgbuf_extract(buf, rec->descriptor_count);
646 	pldm_msgbuf_extract(buf, rec->device_update_option_flags.value);
647 
648 	rc = pldm_msgbuf_extract(buf,
649 				 rec->component_image_set_version_string_type);
650 	if (rc) {
651 		return pldm_msgbuf_discard(buf, rc);
652 	}
653 	if (!is_string_type_valid(
654 		    rec->component_image_set_version_string_type)) {
655 		return pldm_msgbuf_discard(buf, -EPROTO);
656 	}
657 
658 	rc = pldm_msgbuf_extract_uint8_to_size(
659 		buf, rec->component_image_set_version_string.length);
660 	if (rc) {
661 		return pldm_msgbuf_discard(buf, rc);
662 	}
663 
664 	if (rec->component_image_set_version_string.length == 0) {
665 		return pldm_msgbuf_discard(buf, -EPROTO);
666 	}
667 
668 	rc = pldm_msgbuf_extract_uint16_to_size(
669 		buf, rec->firmware_device_package_data.length);
670 	if (rc) {
671 		return pldm_msgbuf_discard(buf, rc);
672 	}
673 
674 	rc = pldm_msgbuf_span_required(
675 		buf, hdr->component_bitmap_bit_length / 8,
676 		(void **)&rec->applicable_components.bitmap.ptr);
677 	if (rc) {
678 		return pldm_msgbuf_discard(buf, rc);
679 	}
680 	rec->applicable_components.bitmap.length =
681 		hdr->component_bitmap_bit_length / 8;
682 
683 	pldm_msgbuf_span_required(
684 		buf, rec->component_image_set_version_string.length,
685 		(void **)&rec->component_image_set_version_string.ptr);
686 
687 	pldm_msgbuf_span_until(buf, rec->firmware_device_package_data.length,
688 			       (void **)&rec->record_descriptors.ptr,
689 			       &rec->record_descriptors.length);
690 
691 	pldm_msgbuf_span_required(
692 		buf, rec->firmware_device_package_data.length,
693 		(void **)&rec->firmware_device_package_data.ptr);
694 	if (!rec->firmware_device_package_data.length) {
695 		rec->firmware_device_package_data.ptr = NULL;
696 	}
697 
698 	return pldm_msgbuf_complete_consumed(buf);
699 }
700 
701 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)702 int decode_firmware_device_id_record(
703 	const uint8_t *data, size_t length,
704 	uint16_t component_bitmap_bit_length,
705 	struct pldm_firmware_device_id_record *fw_device_id_record,
706 	struct variable_field *applicable_components,
707 	struct variable_field *comp_image_set_version_str,
708 	struct variable_field *record_descriptors,
709 	struct variable_field *fw_device_pkg_data)
710 {
711 	struct pldm_package_firmware_device_id_record rec;
712 	pldm_package_header_information_pad hdr;
713 	int rc;
714 
715 	if (!data || !fw_device_id_record || !applicable_components ||
716 	    !comp_image_set_version_str || !record_descriptors ||
717 	    !fw_device_pkg_data) {
718 		return PLDM_ERROR_INVALID_DATA;
719 	}
720 
721 	hdr.package_header_format_revision =
722 		PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H;
723 	hdr.component_bitmap_bit_length = component_bitmap_bit_length;
724 
725 	rc = decode_pldm_package_firmware_device_id_record_errno(
726 		&hdr, &(struct variable_field){ data, length }, &rec);
727 	if (rc < 0) {
728 		return pldm_xlate_errno(rc);
729 	}
730 
731 	memcpy(&fw_device_id_record->record_length, data,
732 	       sizeof(fw_device_id_record->record_length));
733 	LE16TOH(fw_device_id_record->record_length);
734 	fw_device_id_record->descriptor_count = rec.descriptor_count;
735 	fw_device_id_record->device_update_option_flags =
736 		rec.device_update_option_flags;
737 	fw_device_id_record->comp_image_set_version_string_type =
738 		rec.component_image_set_version_string_type;
739 	fw_device_id_record->comp_image_set_version_string_length =
740 		rec.component_image_set_version_string.length;
741 	fw_device_id_record->fw_device_pkg_data_length =
742 		rec.firmware_device_package_data.length;
743 	*applicable_components = rec.applicable_components.bitmap;
744 	*comp_image_set_version_str = rec.component_image_set_version_string;
745 	*record_descriptors = rec.record_descriptors;
746 	*fw_device_pkg_data = rec.firmware_device_package_data;
747 
748 	return PLDM_SUCCESS;
749 }
750 
751 LIBPLDM_ABI_STABLE
decode_pldm_descriptor_from_iter(struct pldm_descriptor_iter * iter,struct pldm_descriptor * desc)752 int decode_pldm_descriptor_from_iter(struct pldm_descriptor_iter *iter,
753 				     struct pldm_descriptor *desc)
754 {
755 	PLDM_MSGBUF_DEFINE_P(buf);
756 	int rc;
757 
758 	if (!iter || !iter->field || !desc) {
759 		return -EINVAL;
760 	}
761 
762 	rc = pldm_msgbuf_init_errno(buf, PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN,
763 				    iter->field->ptr, iter->field->length);
764 	if (rc) {
765 		return rc;
766 	}
767 
768 	pldm_msgbuf_extract(buf, desc->descriptor_type);
769 	rc = pldm_msgbuf_extract(buf, desc->descriptor_length);
770 	if (rc) {
771 		return pldm_msgbuf_discard(buf, rc);
772 	}
773 
774 	desc->descriptor_data = NULL;
775 	pldm_msgbuf_span_required(buf, desc->descriptor_length,
776 				  (void **)&desc->descriptor_data);
777 	iter->field->ptr = NULL;
778 	pldm_msgbuf_span_remaining(buf, (void **)&iter->field->ptr,
779 				   &iter->field->length);
780 
781 	return pldm_msgbuf_complete(buf);
782 }
783 
decode_descriptor_type_length_value_errno(const void * data,size_t length,uint16_t * descriptor_type,struct variable_field * descriptor_data)784 static int decode_descriptor_type_length_value_errno(
785 	const void *data, size_t length, uint16_t *descriptor_type,
786 	struct variable_field *descriptor_data)
787 {
788 	uint16_t descriptor_length = 0;
789 
790 	if (data == NULL || descriptor_type == NULL ||
791 	    descriptor_data == NULL) {
792 		return -EINVAL;
793 	}
794 
795 	if (length < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {
796 		return -EOVERFLOW;
797 	}
798 
799 	struct pldm_descriptor_tlv *entry =
800 		(struct pldm_descriptor_tlv *)(data);
801 
802 	*descriptor_type = le16toh(entry->descriptor_type);
803 	descriptor_length = le16toh(entry->descriptor_length);
804 	if (*descriptor_type != PLDM_FWUP_VENDOR_DEFINED) {
805 		if (descriptor_length !=
806 		    get_descriptor_type_length(*descriptor_type)) {
807 			return -EBADMSG;
808 		}
809 	}
810 
811 	if (length < (sizeof(*descriptor_type) + sizeof(descriptor_length) +
812 		      descriptor_length)) {
813 		return -EOVERFLOW;
814 	}
815 
816 	descriptor_data->ptr = entry->descriptor_data;
817 	descriptor_data->length = descriptor_length;
818 
819 	return 0;
820 }
821 
822 LIBPLDM_ABI_STABLE
decode_descriptor_type_length_value(const uint8_t * data,size_t length,uint16_t * descriptor_type,struct variable_field * descriptor_data)823 int decode_descriptor_type_length_value(const uint8_t *data, size_t length,
824 					uint16_t *descriptor_type,
825 					struct variable_field *descriptor_data)
826 {
827 	int rc;
828 
829 	rc = decode_descriptor_type_length_value_errno(
830 		data, length, descriptor_type, descriptor_data);
831 	if (rc < 0) {
832 		return pldm_xlate_errno(rc);
833 	}
834 
835 	return PLDM_SUCCESS;
836 }
837 
decode_vendor_defined_descriptor_value_errno(const void * data,size_t length,uint8_t * descriptor_title_str_type,struct variable_field * descriptor_title_str,struct variable_field * descriptor_data)838 static int decode_vendor_defined_descriptor_value_errno(
839 	const void *data, size_t length, uint8_t *descriptor_title_str_type,
840 	struct variable_field *descriptor_title_str,
841 	struct variable_field *descriptor_data)
842 {
843 	if (data == NULL || descriptor_title_str_type == NULL ||
844 	    descriptor_title_str == NULL || descriptor_data == NULL) {
845 		return -EINVAL;
846 	}
847 
848 	if (length < sizeof(struct pldm_vendor_defined_descriptor_title_data)) {
849 		return -EOVERFLOW;
850 	}
851 
852 	struct pldm_vendor_defined_descriptor_title_data *entry =
853 		(struct pldm_vendor_defined_descriptor_title_data *)(data);
854 	if (!is_string_type_valid(
855 		    entry->vendor_defined_descriptor_title_str_type) ||
856 	    (entry->vendor_defined_descriptor_title_str_len == 0)) {
857 		return -EBADMSG;
858 	}
859 
860 	// Assuming at least 1 byte of VendorDefinedDescriptorData
861 	if (length < (sizeof(struct pldm_vendor_defined_descriptor_title_data) +
862 		      entry->vendor_defined_descriptor_title_str_len)) {
863 		return -EOVERFLOW;
864 	}
865 
866 	*descriptor_title_str_type =
867 		entry->vendor_defined_descriptor_title_str_type;
868 	descriptor_title_str->ptr = entry->vendor_defined_descriptor_title_str;
869 	descriptor_title_str->length =
870 		entry->vendor_defined_descriptor_title_str_len;
871 
872 	descriptor_data->ptr =
873 		descriptor_title_str->ptr + descriptor_title_str->length;
874 	descriptor_data->length =
875 		length -
876 		sizeof(entry->vendor_defined_descriptor_title_str_type) -
877 		sizeof(entry->vendor_defined_descriptor_title_str_len) -
878 		descriptor_title_str->length;
879 
880 	return 0;
881 }
882 
883 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)884 int decode_vendor_defined_descriptor_value(
885 	const uint8_t *data, size_t length, uint8_t *descriptor_title_str_type,
886 	struct variable_field *descriptor_title_str,
887 	struct variable_field *descriptor_data)
888 {
889 	int rc;
890 
891 	rc = decode_vendor_defined_descriptor_value_errno(
892 		data, length, descriptor_title_str_type, descriptor_title_str,
893 		descriptor_data);
894 	if (rc < 0) {
895 		return pldm_xlate_errno(rc);
896 	}
897 
898 	return PLDM_SUCCESS;
899 }
900 
decode_pldm_comp_image_info_errno(const void * data,size_t length,struct pldm_component_image_information * pldm_comp_image_info,struct variable_field * comp_version_str)901 static int decode_pldm_comp_image_info_errno(
902 	const void *data, size_t length,
903 	struct pldm_component_image_information *pldm_comp_image_info,
904 	struct variable_field *comp_version_str)
905 {
906 	if (data == NULL || pldm_comp_image_info == NULL ||
907 	    comp_version_str == NULL) {
908 		return -EINVAL;
909 	}
910 
911 	if (length < sizeof(struct pldm_component_image_information)) {
912 		return -EOVERFLOW;
913 	}
914 
915 	struct pldm_component_image_information *data_header =
916 		(struct pldm_component_image_information *)(data);
917 
918 	if (!is_string_type_valid(data_header->comp_version_string_type) ||
919 	    (data_header->comp_version_string_length == 0)) {
920 		return -EBADMSG;
921 	}
922 
923 	if (length < sizeof(struct pldm_component_image_information) +
924 			     data_header->comp_version_string_length) {
925 		return -EOVERFLOW;
926 	}
927 
928 	pldm_comp_image_info->comp_classification =
929 		le16toh(data_header->comp_classification);
930 	pldm_comp_image_info->comp_identifier =
931 		le16toh(data_header->comp_identifier);
932 	pldm_comp_image_info->comp_comparison_stamp =
933 		le32toh(data_header->comp_comparison_stamp);
934 	pldm_comp_image_info->comp_options.value =
935 		le16toh(data_header->comp_options.value);
936 	pldm_comp_image_info->requested_comp_activation_method.value =
937 		le16toh(data_header->requested_comp_activation_method.value);
938 	pldm_comp_image_info->comp_location_offset =
939 		le32toh(data_header->comp_location_offset);
940 	pldm_comp_image_info->comp_size = le32toh(data_header->comp_size);
941 	pldm_comp_image_info->comp_version_string_type =
942 		data_header->comp_version_string_type;
943 	pldm_comp_image_info->comp_version_string_length =
944 		data_header->comp_version_string_length;
945 
946 	if ((pldm_comp_image_info->comp_options.bits.bit1 == false &&
947 	     pldm_comp_image_info->comp_comparison_stamp !=
948 		     PLDM_FWUP_INVALID_COMPONENT_COMPARISON_TIMESTAMP)) {
949 		return -EBADMSG;
950 	}
951 
952 	if (pldm_comp_image_info->comp_location_offset == 0 ||
953 	    pldm_comp_image_info->comp_size == 0) {
954 		return -EBADMSG;
955 	}
956 
957 	comp_version_str->ptr = (const uint8_t *)data +
958 				sizeof(struct pldm_component_image_information);
959 	comp_version_str->length =
960 		pldm_comp_image_info->comp_version_string_length;
961 
962 	return 0;
963 }
964 
965 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)966 int decode_pldm_comp_image_info(
967 	const uint8_t *data, size_t length,
968 	struct pldm_component_image_information *pldm_comp_image_info,
969 	struct variable_field *comp_version_str)
970 {
971 	int rc;
972 
973 	rc = decode_pldm_comp_image_info_errno(
974 		data, length, pldm_comp_image_info, comp_version_str);
975 	if (rc < 0) {
976 		return pldm_xlate_errno(rc);
977 	}
978 
979 	return PLDM_SUCCESS;
980 }
981 
982 LIBPLDM_ABI_STABLE
encode_query_device_identifiers_req(uint8_t instance_id,size_t payload_length,struct pldm_msg * msg)983 int encode_query_device_identifiers_req(uint8_t instance_id,
984 					size_t payload_length,
985 					struct pldm_msg *msg)
986 {
987 	if (msg == NULL) {
988 		return PLDM_ERROR_INVALID_DATA;
989 	}
990 
991 	if (payload_length != PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES) {
992 		return PLDM_ERROR_INVALID_LENGTH;
993 	}
994 
995 	return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
996 				       PLDM_QUERY_DEVICE_IDENTIFIERS, msg);
997 }
998 
999 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)1000 int decode_query_device_identifiers_resp(const struct pldm_msg *msg,
1001 					 size_t payload_length,
1002 					 uint8_t *completion_code,
1003 					 uint32_t *device_identifiers_len,
1004 					 uint8_t *descriptor_count,
1005 					 uint8_t **descriptor_data)
1006 {
1007 	if (msg == NULL || completion_code == NULL ||
1008 	    device_identifiers_len == NULL || descriptor_count == NULL ||
1009 	    descriptor_data == NULL) {
1010 		return PLDM_ERROR_INVALID_DATA;
1011 	}
1012 
1013 	*completion_code = msg->payload[0];
1014 	if (PLDM_SUCCESS != *completion_code) {
1015 		return PLDM_SUCCESS;
1016 	}
1017 
1018 	if (payload_length <
1019 	    sizeof(struct pldm_query_device_identifiers_resp)) {
1020 		return PLDM_ERROR_INVALID_LENGTH;
1021 	}
1022 
1023 	struct pldm_query_device_identifiers_resp *response =
1024 		(struct pldm_query_device_identifiers_resp *)msg->payload;
1025 	*device_identifiers_len = le32toh(response->device_identifiers_len);
1026 
1027 	if (*device_identifiers_len < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {
1028 		return PLDM_ERROR_INVALID_LENGTH;
1029 	}
1030 
1031 	if (payload_length !=
1032 	    sizeof(struct pldm_query_device_identifiers_resp) +
1033 		    *device_identifiers_len) {
1034 		return PLDM_ERROR_INVALID_LENGTH;
1035 	}
1036 	*descriptor_count = response->descriptor_count;
1037 
1038 	if (*descriptor_count == 0) {
1039 		return PLDM_ERROR_INVALID_DATA;
1040 	}
1041 	*descriptor_data =
1042 		(uint8_t *)(msg->payload +
1043 			    sizeof(struct pldm_query_device_identifiers_resp));
1044 	return PLDM_SUCCESS;
1045 }
1046 
1047 LIBPLDM_ABI_TESTING
encode_query_device_identifiers_resp(uint8_t instance_id,uint8_t descriptor_count,const struct pldm_descriptor * descriptors,struct pldm_msg * msg,size_t * payload_length)1048 int encode_query_device_identifiers_resp(
1049 	uint8_t instance_id, uint8_t descriptor_count,
1050 	const struct pldm_descriptor *descriptors, struct pldm_msg *msg,
1051 	size_t *payload_length)
1052 {
1053 	PLDM_MSGBUF_DEFINE_P(buf);
1054 	int rc;
1055 
1056 	if (descriptors == NULL || msg == NULL || payload_length == NULL) {
1057 		return -EINVAL;
1058 	}
1059 
1060 	if (descriptor_count < 1) {
1061 		return -EINVAL;
1062 	}
1063 
1064 	rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
1065 				     PLDM_QUERY_DEVICE_IDENTIFIERS, msg);
1066 	if (rc) {
1067 		return -EINVAL;
1068 	}
1069 
1070 	rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
1071 	if (rc) {
1072 		return rc;
1073 	}
1074 
1075 	/* Determine total length */
1076 	uint32_t device_identifiers_len = 0;
1077 	for (uint8_t i = 0; i < descriptor_count; i++) {
1078 		const struct pldm_descriptor *d = &descriptors[i];
1079 		device_identifiers_len +=
1080 			2 * sizeof(uint16_t) + d->descriptor_length;
1081 	}
1082 
1083 	pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
1084 	pldm_msgbuf_insert(buf, device_identifiers_len);
1085 	pldm_msgbuf_insert(buf, descriptor_count);
1086 
1087 	for (uint8_t i = 0; i < descriptor_count; i++) {
1088 		const struct pldm_descriptor *d = &descriptors[i];
1089 		pldm_msgbuf_insert(buf, d->descriptor_type);
1090 		pldm_msgbuf_insert(buf, d->descriptor_length);
1091 		if (d->descriptor_data == NULL) {
1092 			return pldm_msgbuf_discard(buf, -EINVAL);
1093 		}
1094 		rc = pldm_msgbuf_insert_array(
1095 			buf, d->descriptor_length,
1096 			(const uint8_t *)d->descriptor_data,
1097 			d->descriptor_length);
1098 		if (rc) {
1099 			return pldm_msgbuf_discard(buf, rc);
1100 		}
1101 	}
1102 
1103 	return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
1104 }
1105 
1106 LIBPLDM_ABI_STABLE
encode_get_firmware_parameters_req(uint8_t instance_id,size_t payload_length,struct pldm_msg * msg)1107 int encode_get_firmware_parameters_req(uint8_t instance_id,
1108 				       size_t payload_length,
1109 				       struct pldm_msg *msg)
1110 {
1111 	if (msg == NULL) {
1112 		return PLDM_ERROR_INVALID_DATA;
1113 	}
1114 
1115 	if (payload_length != PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES) {
1116 		return PLDM_ERROR_INVALID_LENGTH;
1117 	}
1118 
1119 	return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
1120 				       PLDM_GET_FIRMWARE_PARAMETERS, msg);
1121 }
1122 
1123 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)1124 int decode_get_firmware_parameters_resp(
1125 	const struct pldm_msg *msg, size_t payload_length,
1126 	struct pldm_get_firmware_parameters_resp *resp_data,
1127 	struct variable_field *active_comp_image_set_ver_str,
1128 	struct variable_field *pending_comp_image_set_ver_str,
1129 	struct variable_field *comp_parameter_table)
1130 {
1131 	if (msg == NULL || resp_data == NULL ||
1132 	    active_comp_image_set_ver_str == NULL ||
1133 	    pending_comp_image_set_ver_str == NULL ||
1134 	    comp_parameter_table == NULL || !payload_length) {
1135 		return PLDM_ERROR_INVALID_DATA;
1136 	}
1137 
1138 	resp_data->completion_code = msg->payload[0];
1139 	if (PLDM_SUCCESS != resp_data->completion_code) {
1140 		return PLDM_SUCCESS;
1141 	}
1142 
1143 	if (payload_length < sizeof(struct pldm_get_firmware_parameters_resp)) {
1144 		return PLDM_ERROR_INVALID_LENGTH;
1145 	}
1146 
1147 	struct pldm_get_firmware_parameters_resp *response =
1148 		(struct pldm_get_firmware_parameters_resp *)msg->payload;
1149 
1150 	if (!is_string_type_valid(
1151 		    response->active_comp_image_set_ver_str_type) ||
1152 	    (response->active_comp_image_set_ver_str_len == 0)) {
1153 		return PLDM_ERROR_INVALID_DATA;
1154 	}
1155 
1156 	if (response->pending_comp_image_set_ver_str_len == 0) {
1157 		if (response->pending_comp_image_set_ver_str_type !=
1158 		    PLDM_STR_TYPE_UNKNOWN) {
1159 			return PLDM_ERROR_INVALID_DATA;
1160 		}
1161 	} else {
1162 		if (!is_string_type_valid(
1163 			    response->pending_comp_image_set_ver_str_type)) {
1164 			return PLDM_ERROR_INVALID_DATA;
1165 		}
1166 	}
1167 
1168 	size_t partial_response_length =
1169 		sizeof(struct pldm_get_firmware_parameters_resp) +
1170 		response->active_comp_image_set_ver_str_len +
1171 		response->pending_comp_image_set_ver_str_len;
1172 
1173 	if (payload_length < partial_response_length) {
1174 		return PLDM_ERROR_INVALID_LENGTH;
1175 	}
1176 
1177 	resp_data->capabilities_during_update.value =
1178 		le32toh(response->capabilities_during_update.value);
1179 	resp_data->comp_count = le16toh(response->comp_count);
1180 	resp_data->active_comp_image_set_ver_str_type =
1181 		response->active_comp_image_set_ver_str_type;
1182 	resp_data->active_comp_image_set_ver_str_len =
1183 		response->active_comp_image_set_ver_str_len;
1184 	resp_data->pending_comp_image_set_ver_str_type =
1185 		response->pending_comp_image_set_ver_str_type;
1186 	resp_data->pending_comp_image_set_ver_str_len =
1187 		response->pending_comp_image_set_ver_str_len;
1188 
1189 	active_comp_image_set_ver_str->ptr =
1190 		msg->payload + sizeof(struct pldm_get_firmware_parameters_resp);
1191 	active_comp_image_set_ver_str->length =
1192 		resp_data->active_comp_image_set_ver_str_len;
1193 
1194 	if (resp_data->pending_comp_image_set_ver_str_len != 0) {
1195 		pending_comp_image_set_ver_str->ptr =
1196 			msg->payload +
1197 			sizeof(struct pldm_get_firmware_parameters_resp) +
1198 			resp_data->active_comp_image_set_ver_str_len;
1199 		pending_comp_image_set_ver_str->length =
1200 			resp_data->pending_comp_image_set_ver_str_len;
1201 	} else {
1202 		pending_comp_image_set_ver_str->ptr = NULL;
1203 		pending_comp_image_set_ver_str->length = 0;
1204 	}
1205 
1206 	if (payload_length > partial_response_length && resp_data->comp_count) {
1207 		comp_parameter_table->ptr =
1208 			msg->payload +
1209 			sizeof(struct pldm_get_firmware_parameters_resp) +
1210 			resp_data->active_comp_image_set_ver_str_len +
1211 			resp_data->pending_comp_image_set_ver_str_len;
1212 		comp_parameter_table->length =
1213 			payload_length - partial_response_length;
1214 	} else {
1215 		comp_parameter_table->ptr = NULL;
1216 		comp_parameter_table->length = 0;
1217 	}
1218 
1219 	return PLDM_SUCCESS;
1220 }
1221 
1222 LIBPLDM_ABI_TESTING
encode_get_firmware_parameters_resp(uint8_t instance_id,const struct pldm_get_firmware_parameters_resp_full * resp_data,struct pldm_msg * msg,size_t * payload_length)1223 int encode_get_firmware_parameters_resp(
1224 	uint8_t instance_id,
1225 	const struct pldm_get_firmware_parameters_resp_full *resp_data,
1226 	struct pldm_msg *msg, size_t *payload_length)
1227 {
1228 	PLDM_MSGBUF_DEFINE_P(buf);
1229 	int rc;
1230 
1231 	if (resp_data == NULL || msg == NULL || payload_length == NULL) {
1232 		return -EINVAL;
1233 	}
1234 
1235 	rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
1236 				     PLDM_GET_FIRMWARE_PARAMETERS, msg);
1237 	if (rc) {
1238 		return -EINVAL;
1239 	}
1240 
1241 	rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
1242 	if (rc) {
1243 		return rc;
1244 	}
1245 
1246 	pldm_msgbuf_insert(buf, resp_data->completion_code);
1247 	pldm_msgbuf_insert(buf, resp_data->capabilities_during_update.value);
1248 	pldm_msgbuf_insert(buf, resp_data->comp_count);
1249 	pldm_msgbuf_insert(buf,
1250 			   resp_data->active_comp_image_set_ver_str.str_type);
1251 	pldm_msgbuf_insert(buf,
1252 			   resp_data->active_comp_image_set_ver_str.str_len);
1253 	pldm_msgbuf_insert(buf,
1254 			   resp_data->pending_comp_image_set_ver_str.str_type);
1255 	pldm_msgbuf_insert(buf,
1256 			   resp_data->pending_comp_image_set_ver_str.str_len);
1257 	/* String data appended */
1258 	rc = pldm_msgbuf_insert_array(
1259 		buf, resp_data->active_comp_image_set_ver_str.str_len,
1260 		resp_data->active_comp_image_set_ver_str.str_data,
1261 		resp_data->active_comp_image_set_ver_str.str_len);
1262 	if (rc) {
1263 		return pldm_msgbuf_discard(buf, rc);
1264 	}
1265 	rc = pldm_msgbuf_insert_array(
1266 		buf, resp_data->pending_comp_image_set_ver_str.str_len,
1267 		resp_data->pending_comp_image_set_ver_str.str_data,
1268 		resp_data->pending_comp_image_set_ver_str.str_len);
1269 	if (rc) {
1270 		return pldm_msgbuf_discard(buf, rc);
1271 	}
1272 
1273 	/* Further calls to encode_get_firmware_parameters_resp_comp_entry
1274 	 * will populate the remainder */
1275 
1276 	return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
1277 }
1278 
1279 LIBPLDM_ABI_TESTING
encode_get_firmware_parameters_resp_comp_entry(const struct pldm_component_parameter_entry_full * comp,uint8_t * payload,size_t * payload_length)1280 int encode_get_firmware_parameters_resp_comp_entry(
1281 	const struct pldm_component_parameter_entry_full *comp,
1282 	uint8_t *payload, size_t *payload_length)
1283 {
1284 	PLDM_MSGBUF_DEFINE_P(buf);
1285 	int rc;
1286 
1287 	if (comp == NULL || payload == NULL || payload_length == NULL) {
1288 		return -EINVAL;
1289 	}
1290 
1291 	rc = pldm_msgbuf_init_errno(buf, 0, payload, *payload_length);
1292 	if (rc) {
1293 		return rc;
1294 	}
1295 
1296 	pldm_msgbuf_insert(buf, comp->comp_classification);
1297 	pldm_msgbuf_insert(buf, comp->comp_identifier);
1298 	pldm_msgbuf_insert(buf, comp->comp_classification_index);
1299 
1300 	pldm_msgbuf_insert(buf, comp->active_ver.comparison_stamp);
1301 	pldm_msgbuf_insert(buf, (uint8_t)comp->active_ver.str.str_type);
1302 	pldm_msgbuf_insert(buf, comp->active_ver.str.str_len);
1303 	rc = pldm_msgbuf_insert_array(buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1304 				      comp->active_ver.date,
1305 				      PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN);
1306 	if (rc) {
1307 		return pldm_msgbuf_discard(buf, rc);
1308 	}
1309 
1310 	pldm_msgbuf_insert(buf, comp->pending_ver.comparison_stamp);
1311 	pldm_msgbuf_insert(buf, (uint8_t)comp->pending_ver.str.str_type);
1312 	pldm_msgbuf_insert(buf, comp->pending_ver.str.str_len);
1313 	rc = pldm_msgbuf_insert_array(buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1314 				      comp->pending_ver.date,
1315 				      PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN);
1316 	if (rc) {
1317 		return pldm_msgbuf_discard(buf, rc);
1318 	}
1319 
1320 	pldm_msgbuf_insert(buf, comp->comp_activation_methods.value);
1321 	pldm_msgbuf_insert(buf, comp->capabilities_during_update.value);
1322 
1323 	rc = pldm_msgbuf_insert_array(buf, comp->active_ver.str.str_len,
1324 				      comp->active_ver.str.str_data,
1325 				      comp->active_ver.str.str_len);
1326 	if (rc) {
1327 		return pldm_msgbuf_discard(buf, rc);
1328 	}
1329 	rc = pldm_msgbuf_insert_array(buf, comp->pending_ver.str.str_len,
1330 				      comp->pending_ver.str.str_data,
1331 				      comp->pending_ver.str.str_len);
1332 	if (rc) {
1333 		return pldm_msgbuf_discard(buf, rc);
1334 	}
1335 
1336 	return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
1337 }
1338 
1339 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)1340 int decode_get_firmware_parameters_resp_comp_entry(
1341 	const uint8_t *data, size_t length,
1342 	struct pldm_component_parameter_entry *component_data,
1343 	struct variable_field *active_comp_ver_str,
1344 	struct variable_field *pending_comp_ver_str)
1345 {
1346 	if (data == NULL || component_data == NULL ||
1347 	    active_comp_ver_str == NULL || pending_comp_ver_str == NULL) {
1348 		return PLDM_ERROR_INVALID_DATA;
1349 	}
1350 
1351 	if (length < sizeof(struct pldm_component_parameter_entry)) {
1352 		return PLDM_ERROR_INVALID_LENGTH;
1353 	}
1354 
1355 	struct pldm_component_parameter_entry *entry =
1356 		(struct pldm_component_parameter_entry *)(data);
1357 
1358 	size_t entry_length = sizeof(struct pldm_component_parameter_entry) +
1359 			      entry->active_comp_ver_str_len +
1360 			      entry->pending_comp_ver_str_len;
1361 
1362 	if (length < entry_length) {
1363 		return PLDM_ERROR_INVALID_LENGTH;
1364 	}
1365 
1366 	component_data->comp_classification =
1367 		le16toh(entry->comp_classification);
1368 	component_data->comp_identifier = le16toh(entry->comp_identifier);
1369 	component_data->comp_classification_index =
1370 		entry->comp_classification_index;
1371 	component_data->active_comp_comparison_stamp =
1372 		le32toh(entry->active_comp_comparison_stamp);
1373 	component_data->active_comp_ver_str_type =
1374 		entry->active_comp_ver_str_type;
1375 	component_data->active_comp_ver_str_len =
1376 		entry->active_comp_ver_str_len;
1377 	memcpy(component_data->active_comp_release_date,
1378 	       entry->active_comp_release_date,
1379 	       sizeof(entry->active_comp_release_date));
1380 	component_data->pending_comp_comparison_stamp =
1381 		le32toh(entry->pending_comp_comparison_stamp);
1382 	component_data->pending_comp_ver_str_type =
1383 		entry->pending_comp_ver_str_type;
1384 	component_data->pending_comp_ver_str_len =
1385 		entry->pending_comp_ver_str_len;
1386 	memcpy(component_data->pending_comp_release_date,
1387 	       entry->pending_comp_release_date,
1388 	       sizeof(entry->pending_comp_release_date));
1389 	component_data->comp_activation_methods.value =
1390 		le16toh(entry->comp_activation_methods.value);
1391 	component_data->capabilities_during_update.value =
1392 		le32toh(entry->capabilities_during_update.value);
1393 
1394 	if (entry->active_comp_ver_str_len != 0) {
1395 		active_comp_ver_str->ptr =
1396 			data + sizeof(struct pldm_component_parameter_entry);
1397 		active_comp_ver_str->length = entry->active_comp_ver_str_len;
1398 	} else {
1399 		active_comp_ver_str->ptr = NULL;
1400 		active_comp_ver_str->length = 0;
1401 	}
1402 
1403 	if (entry->pending_comp_ver_str_len != 0) {
1404 		pending_comp_ver_str->ptr =
1405 			data + sizeof(struct pldm_component_parameter_entry) +
1406 			entry->active_comp_ver_str_len;
1407 		pending_comp_ver_str->length = entry->pending_comp_ver_str_len;
1408 	} else {
1409 		pending_comp_ver_str->ptr = NULL;
1410 		pending_comp_ver_str->length = 0;
1411 	}
1412 	return PLDM_SUCCESS;
1413 }
1414 
1415 LIBPLDM_ABI_STABLE
encode_query_downstream_devices_req(uint8_t instance_id,struct pldm_msg * msg)1416 int encode_query_downstream_devices_req(uint8_t instance_id,
1417 					struct pldm_msg *msg)
1418 {
1419 	if (msg == NULL) {
1420 		return -EINVAL;
1421 	}
1422 
1423 	return encode_pldm_header_only_errno(PLDM_REQUEST, instance_id,
1424 					     PLDM_FWUP,
1425 					     PLDM_QUERY_DOWNSTREAM_DEVICES,
1426 					     msg);
1427 }
1428 
1429 LIBPLDM_ABI_STABLE
decode_query_downstream_devices_resp(const struct pldm_msg * msg,size_t payload_length,struct pldm_query_downstream_devices_resp * resp_data)1430 int decode_query_downstream_devices_resp(
1431 	const struct pldm_msg *msg, size_t payload_length,
1432 	struct pldm_query_downstream_devices_resp *resp_data)
1433 {
1434 	PLDM_MSGBUF_DEFINE_P(buf);
1435 	int rc;
1436 
1437 	if (msg == NULL || resp_data == NULL || !payload_length) {
1438 		return -EINVAL;
1439 	}
1440 
1441 	rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1442 				    msg->payload, payload_length);
1443 	if (rc) {
1444 		return rc;
1445 	}
1446 
1447 	rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1448 	if (rc) {
1449 		return pldm_msgbuf_discard(buf, rc);
1450 	}
1451 	if (PLDM_SUCCESS != resp_data->completion_code) {
1452 		// Return the CC directly without decoding the rest of the payload
1453 		return pldm_msgbuf_complete(buf);
1454 	}
1455 
1456 	if (payload_length < PLDM_QUERY_DOWNSTREAM_DEVICES_RESP_BYTES) {
1457 		return pldm_msgbuf_discard(buf, -EBADMSG);
1458 	}
1459 
1460 	rc = pldm_msgbuf_extract(buf,
1461 				 resp_data->downstream_device_update_supported);
1462 	if (rc) {
1463 		return pldm_msgbuf_discard(buf, rc);
1464 	}
1465 
1466 	if (!is_downstream_device_update_support_valid(
1467 		    resp_data->downstream_device_update_supported)) {
1468 		return pldm_msgbuf_discard(buf, -EINVAL);
1469 	}
1470 
1471 	pldm_msgbuf_extract(buf, resp_data->number_of_downstream_devices);
1472 	pldm_msgbuf_extract(buf, resp_data->max_number_of_downstream_devices);
1473 	pldm_msgbuf_extract(buf, resp_data->capabilities.value);
1474 
1475 	return pldm_msgbuf_complete_consumed(buf);
1476 }
1477 
1478 LIBPLDM_ABI_STABLE
encode_query_downstream_identifiers_req(uint8_t instance_id,const struct pldm_query_downstream_identifiers_req * params_req,struct pldm_msg * msg,size_t payload_length)1479 int encode_query_downstream_identifiers_req(
1480 	uint8_t instance_id,
1481 	const struct pldm_query_downstream_identifiers_req *params_req,
1482 	struct pldm_msg *msg, size_t payload_length)
1483 {
1484 	PLDM_MSGBUF_DEFINE_P(buf);
1485 	int rc;
1486 
1487 	if (!msg || !params_req) {
1488 		return -EINVAL;
1489 	}
1490 
1491 	if (!is_transfer_operation_flag_valid(
1492 		    (enum transfer_op_flag)
1493 			    params_req->transfer_operation_flag)) {
1494 		return -EINVAL;
1495 	}
1496 
1497 	struct pldm_header_info header = { 0 };
1498 	header.instance = instance_id;
1499 	header.msg_type = PLDM_REQUEST;
1500 	header.pldm_type = PLDM_FWUP;
1501 	header.command = PLDM_QUERY_DOWNSTREAM_IDENTIFIERS;
1502 	rc = pack_pldm_header_errno(&header, &(msg->hdr));
1503 	if (rc) {
1504 		return rc;
1505 	}
1506 
1507 	rc = pldm_msgbuf_init_errno(buf,
1508 				    PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_REQ_BYTES,
1509 				    msg->payload, payload_length);
1510 	if (rc) {
1511 		return rc;
1512 	}
1513 
1514 	pldm_msgbuf_insert(buf, params_req->data_transfer_handle);
1515 	// Data correctness has been verified, cast it to 1-byte data directly.
1516 	pldm_msgbuf_insert(buf, params_req->transfer_operation_flag);
1517 
1518 	return pldm_msgbuf_complete(buf);
1519 }
1520 
1521 LIBPLDM_ABI_STABLE
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)1522 int decode_query_downstream_identifiers_resp(
1523 	const struct pldm_msg *msg, size_t payload_length,
1524 	struct pldm_query_downstream_identifiers_resp *resp_data,
1525 	struct pldm_downstream_device_iter *iter)
1526 {
1527 	PLDM_MSGBUF_DEFINE_P(buf);
1528 	void *remaining = NULL;
1529 	int rc = 0;
1530 
1531 	if (msg == NULL || resp_data == NULL || iter == NULL ||
1532 	    !payload_length) {
1533 		return -EINVAL;
1534 	}
1535 
1536 	rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1537 				    msg->payload, payload_length);
1538 	if (rc) {
1539 		return rc;
1540 	}
1541 
1542 	rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1543 	if (rc) {
1544 		return pldm_msgbuf_discard(buf, rc);
1545 	}
1546 	if (PLDM_SUCCESS != resp_data->completion_code) {
1547 		return pldm_msgbuf_complete(buf);
1548 	}
1549 
1550 	if (payload_length < PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_RESP_MIN_LEN) {
1551 		return pldm_msgbuf_discard(buf, -EBADMSG);
1552 	}
1553 
1554 	pldm_msgbuf_extract(buf, resp_data->next_data_transfer_handle);
1555 	pldm_msgbuf_extract(buf, resp_data->transfer_flag);
1556 
1557 	rc = pldm_msgbuf_extract(buf, resp_data->downstream_devices_length);
1558 	if (rc) {
1559 		return pldm_msgbuf_discard(buf, rc);
1560 	}
1561 
1562 	pldm_msgbuf_extract(buf, resp_data->number_of_downstream_devices);
1563 	pldm_msgbuf_span_required(buf, resp_data->downstream_devices_length,
1564 				  &remaining);
1565 
1566 	rc = pldm_msgbuf_complete(buf);
1567 	if (rc) {
1568 		return rc;
1569 	}
1570 
1571 	iter->field.ptr = remaining;
1572 	iter->field.length = resp_data->downstream_devices_length;
1573 	iter->devs = resp_data->number_of_downstream_devices;
1574 
1575 	return 0;
1576 }
1577 
1578 LIBPLDM_ABI_STABLE
decode_pldm_downstream_device_from_iter(struct pldm_downstream_device_iter * iter,struct pldm_downstream_device * dev)1579 int decode_pldm_downstream_device_from_iter(
1580 	struct pldm_downstream_device_iter *iter,
1581 	struct pldm_downstream_device *dev)
1582 {
1583 	PLDM_MSGBUF_DEFINE_P(buf);
1584 	int rc;
1585 
1586 	if (!iter || !iter->field.ptr || !dev) {
1587 		return -EINVAL;
1588 	}
1589 
1590 	rc = pldm_msgbuf_init_errno(buf, 3, iter->field.ptr,
1591 				    iter->field.length);
1592 	if (rc) {
1593 		return rc;
1594 	}
1595 
1596 	pldm_msgbuf_extract(buf, dev->downstream_device_index);
1597 	pldm_msgbuf_extract(buf, dev->downstream_descriptor_count);
1598 	pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
1599 				   &iter->field.length);
1600 
1601 	return pldm_msgbuf_complete(buf);
1602 }
1603 
1604 LIBPLDM_ABI_STABLE
encode_get_downstream_firmware_parameters_req(uint8_t instance_id,const struct pldm_get_downstream_firmware_parameters_req * params_req,struct pldm_msg * msg,size_t payload_length)1605 int encode_get_downstream_firmware_parameters_req(
1606 	uint8_t instance_id,
1607 	const struct pldm_get_downstream_firmware_parameters_req *params_req,
1608 	struct pldm_msg *msg, size_t payload_length)
1609 {
1610 	PLDM_MSGBUF_DEFINE_P(buf);
1611 	int rc;
1612 
1613 	if (!msg || !params_req) {
1614 		return -EINVAL;
1615 	}
1616 
1617 	if (!is_transfer_operation_flag_valid(
1618 		    (enum transfer_op_flag)
1619 			    params_req->transfer_operation_flag)) {
1620 		return -EBADMSG;
1621 	}
1622 
1623 	struct pldm_header_info header = { 0 };
1624 	header.instance = instance_id;
1625 	header.msg_type = PLDM_REQUEST;
1626 	header.pldm_type = PLDM_FWUP;
1627 	header.command = PLDM_QUERY_DOWNSTREAM_FIRMWARE_PARAMETERS;
1628 	rc = pack_pldm_header_errno(&header, &msg->hdr);
1629 	if (rc < 0) {
1630 		return rc;
1631 	}
1632 
1633 	rc = pldm_msgbuf_init_errno(
1634 		buf, PLDM_GET_DOWNSTREAM_FIRMWARE_PARAMETERS_REQ_BYTES,
1635 		msg->payload, payload_length);
1636 	if (rc < 0) {
1637 		return rc;
1638 	}
1639 
1640 	pldm_msgbuf_insert(buf, params_req->data_transfer_handle);
1641 	// Data correctness has been verified, cast it to 1-byte data directly.
1642 	pldm_msgbuf_insert(buf, params_req->transfer_operation_flag);
1643 
1644 	return pldm_msgbuf_complete(buf);
1645 }
1646 
1647 LIBPLDM_ABI_STABLE
decode_get_downstream_firmware_parameters_resp(const struct pldm_msg * msg,size_t payload_length,struct pldm_get_downstream_firmware_parameters_resp * resp_data,struct pldm_downstream_device_parameters_iter * iter)1648 int decode_get_downstream_firmware_parameters_resp(
1649 	const struct pldm_msg *msg, size_t payload_length,
1650 	struct pldm_get_downstream_firmware_parameters_resp *resp_data,
1651 	struct pldm_downstream_device_parameters_iter *iter)
1652 {
1653 	PLDM_MSGBUF_DEFINE_P(buf);
1654 	void *remaining = NULL;
1655 	size_t length;
1656 	int rc;
1657 
1658 	if (msg == NULL || resp_data == NULL || iter == NULL) {
1659 		return -EINVAL;
1660 	}
1661 
1662 	rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1663 				    msg->payload, payload_length);
1664 	if (rc < 0) {
1665 		return rc;
1666 	}
1667 
1668 	rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1669 	if (rc < 0) {
1670 		return pldm_msgbuf_discard(buf, rc);
1671 	}
1672 	if (PLDM_SUCCESS != resp_data->completion_code) {
1673 		return pldm_msgbuf_complete(buf);
1674 	}
1675 
1676 	if (payload_length <
1677 	    PLDM_GET_DOWNSTREAM_FIRMWARE_PARAMETERS_RESP_MIN_LEN) {
1678 		return pldm_msgbuf_discard(buf, -EBADMSG);
1679 	}
1680 
1681 	pldm_msgbuf_extract(buf, resp_data->next_data_transfer_handle);
1682 	pldm_msgbuf_extract(buf, resp_data->transfer_flag);
1683 	pldm_msgbuf_extract(buf,
1684 			    resp_data->fdp_capabilities_during_update.value);
1685 	pldm_msgbuf_extract(buf, resp_data->downstream_device_count);
1686 
1687 	rc = pldm_msgbuf_span_remaining(buf, &remaining, &length);
1688 	if (rc) {
1689 		return pldm_msgbuf_discard(buf, rc);
1690 	}
1691 
1692 	rc = pldm_msgbuf_complete(buf);
1693 	if (rc) {
1694 		return rc;
1695 	}
1696 
1697 	iter->field.ptr = remaining;
1698 	iter->field.length = length;
1699 	iter->entries = resp_data->downstream_device_count;
1700 
1701 	return 0;
1702 }
1703 
1704 LIBPLDM_ABI_STABLE
decode_pldm_downstream_device_parameters_entry_from_iter(struct pldm_downstream_device_parameters_iter * iter,struct pldm_downstream_device_parameters_entry * entry)1705 int decode_pldm_downstream_device_parameters_entry_from_iter(
1706 	struct pldm_downstream_device_parameters_iter *iter,
1707 	struct pldm_downstream_device_parameters_entry *entry)
1708 {
1709 	PLDM_MSGBUF_DEFINE_P(buf);
1710 	void *comp_ver_str;
1711 	size_t remaining;
1712 	void *cursor;
1713 	int rc;
1714 
1715 	if (iter == NULL || iter->field.ptr == NULL || entry == NULL) {
1716 		return -EINVAL;
1717 	}
1718 
1719 	rc = pldm_msgbuf_init_errno(
1720 		buf, PLDM_DOWNSTREAM_DEVICE_PARAMETERS_ENTRY_MIN_LEN,
1721 		iter->field.ptr, iter->field.length);
1722 	if (rc < 0) {
1723 		return rc;
1724 	}
1725 
1726 	pldm_msgbuf_extract(buf, entry->downstream_device_index);
1727 	pldm_msgbuf_extract(buf, entry->active_comp_comparison_stamp);
1728 	pldm_msgbuf_extract(buf, entry->active_comp_ver_str_type);
1729 	rc = pldm_msgbuf_extract(buf, entry->active_comp_ver_str_len);
1730 	if (rc < 0) {
1731 		return pldm_msgbuf_discard(buf, rc);
1732 	}
1733 	rc = pldm_msgbuf_extract_array(buf,
1734 				       PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1735 				       entry->active_comp_release_date,
1736 				       sizeof(entry->active_comp_release_date));
1737 	if (rc < 0) {
1738 		return pldm_msgbuf_discard(buf, rc);
1739 	}
1740 
1741 	// Fill the last byte with NULL character
1742 	entry->active_comp_release_date[PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN] =
1743 		'\0';
1744 
1745 	pldm_msgbuf_extract(buf, entry->pending_comp_comparison_stamp);
1746 	pldm_msgbuf_extract(buf, entry->pending_comp_ver_str_type);
1747 	rc = pldm_msgbuf_extract(buf, entry->pending_comp_ver_str_len);
1748 	if (rc < 0) {
1749 		return pldm_msgbuf_discard(buf, rc);
1750 	}
1751 
1752 	rc = pldm_msgbuf_extract_array(
1753 		buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1754 		entry->pending_comp_release_date,
1755 		sizeof(entry->pending_comp_release_date));
1756 	if (rc < 0) {
1757 		return pldm_msgbuf_discard(buf, rc);
1758 	}
1759 
1760 	// Fill the last byte with NULL character
1761 	entry->pending_comp_release_date[PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN] =
1762 		'\0';
1763 
1764 	pldm_msgbuf_extract(buf, entry->comp_activation_methods.value);
1765 	pldm_msgbuf_extract(buf, entry->capabilities_during_update.value);
1766 
1767 	rc = pldm_msgbuf_span_required(buf, entry->active_comp_ver_str_len,
1768 				       &comp_ver_str);
1769 	if (rc < 0) {
1770 		return pldm_msgbuf_discard(buf, rc);
1771 	}
1772 	entry->active_comp_ver_str = comp_ver_str;
1773 
1774 	rc = pldm_msgbuf_span_required(buf, entry->pending_comp_ver_str_len,
1775 				       &comp_ver_str);
1776 	if (rc < 0) {
1777 		return pldm_msgbuf_discard(buf, rc);
1778 	}
1779 	entry->pending_comp_ver_str = comp_ver_str;
1780 
1781 	rc = pldm_msgbuf_span_remaining(buf, &cursor, &remaining);
1782 	if (rc < 0) {
1783 		return pldm_msgbuf_discard(buf, rc);
1784 	}
1785 
1786 	iter->field.ptr = cursor;
1787 	iter->field.length = remaining;
1788 
1789 	return pldm_msgbuf_complete(buf);
1790 }
1791 
1792 LIBPLDM_ABI_TESTING
encode_request_downstream_device_update_req(uint8_t instance_id,const struct pldm_request_downstream_device_update_req * req_data,struct pldm_msg * msg,size_t * payload_length)1793 int encode_request_downstream_device_update_req(
1794 	uint8_t instance_id,
1795 	const struct pldm_request_downstream_device_update_req *req_data,
1796 	struct pldm_msg *msg, size_t *payload_length)
1797 {
1798 	PLDM_MSGBUF_DEFINE_P(buf);
1799 	int rc;
1800 
1801 	if (!req_data || !msg || !payload_length ||
1802 	    req_data->maximum_downstream_device_transfer_size <
1803 		    PLDM_FWUP_BASELINE_TRANSFER_SIZE ||
1804 	    req_data->maximum_outstanding_transfer_requests <
1805 		    PLDM_FWUP_MIN_OUTSTANDING_REQ) {
1806 		return -EINVAL;
1807 	}
1808 
1809 	rc = encode_pldm_header_only_errno(
1810 		PLDM_REQUEST, instance_id, PLDM_FWUP,
1811 		PLDM_REQUEST_DOWNSTREAM_DEVICE_UPDATE, msg);
1812 	if (rc) {
1813 		return rc;
1814 	}
1815 
1816 	rc = pldm_msgbuf_init_errno(buf,
1817 				    PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES,
1818 				    msg->payload, *payload_length);
1819 	if (rc) {
1820 		return rc;
1821 	}
1822 
1823 	pldm_msgbuf_insert(buf,
1824 			   req_data->maximum_downstream_device_transfer_size);
1825 	pldm_msgbuf_insert(buf,
1826 			   req_data->maximum_outstanding_transfer_requests);
1827 	pldm_msgbuf_insert(buf,
1828 			   req_data->downstream_device_package_data_length);
1829 
1830 	return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
1831 }
1832 
1833 LIBPLDM_ABI_TESTING
decode_request_downstream_device_update_req(const struct pldm_msg * msg,size_t payload_length,struct pldm_request_downstream_device_update_req * req)1834 int decode_request_downstream_device_update_req(
1835 	const struct pldm_msg *msg, size_t payload_length,
1836 	struct pldm_request_downstream_device_update_req *req)
1837 {
1838 	int rc;
1839 	PLDM_MSGBUF_DEFINE_P(buf);
1840 
1841 	if (!msg || !req) {
1842 		return -EINVAL;
1843 	}
1844 
1845 	rc = pldm_msgbuf_init_errno(buf,
1846 				    PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES,
1847 				    msg->payload, payload_length);
1848 	if (rc) {
1849 		return rc;
1850 	}
1851 
1852 	pldm_msgbuf_extract(buf, req->maximum_downstream_device_transfer_size);
1853 	pldm_msgbuf_extract(buf, req->maximum_outstanding_transfer_requests);
1854 	pldm_msgbuf_extract(buf, req->downstream_device_package_data_length);
1855 
1856 	return pldm_msgbuf_complete_consumed(buf);
1857 }
1858 
1859 LIBPLDM_ABI_TESTING
encode_request_downstream_device_update_resp(uint8_t instance_id,const struct pldm_request_downstream_device_update_resp * resp_data,struct pldm_msg * msg,size_t * payload_length)1860 int encode_request_downstream_device_update_resp(
1861 	uint8_t instance_id,
1862 	const struct pldm_request_downstream_device_update_resp *resp_data,
1863 	struct pldm_msg *msg, size_t *payload_length)
1864 {
1865 	PLDM_MSGBUF_DEFINE_P(buf);
1866 	int rc;
1867 
1868 	if (!resp_data || !msg || !payload_length) {
1869 		return -EINVAL;
1870 	}
1871 
1872 	rc = encode_pldm_header_only_errno(
1873 		PLDM_RESPONSE, instance_id, PLDM_FWUP,
1874 		PLDM_REQUEST_DOWNSTREAM_DEVICE_UPDATE, msg);
1875 	if (rc) {
1876 		return rc;
1877 	}
1878 
1879 	rc = pldm_msgbuf_init_errno(
1880 		buf, PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES, msg->payload,
1881 		*payload_length);
1882 	if (rc) {
1883 		return rc;
1884 	}
1885 
1886 	pldm_msgbuf_insert(buf, resp_data->completion_code);
1887 	pldm_msgbuf_insert(buf, resp_data->downstream_device_meta_data_length);
1888 	pldm_msgbuf_insert(
1889 		buf, resp_data->downstream_device_will_send_get_package_data);
1890 	pldm_msgbuf_insert(buf,
1891 			   resp_data->get_package_data_maximum_transfer_size);
1892 
1893 	return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
1894 }
1895 
1896 LIBPLDM_ABI_TESTING
decode_request_downstream_device_update_resp(const struct pldm_msg * msg,size_t payload_length,struct pldm_request_downstream_device_update_resp * resp_data)1897 int decode_request_downstream_device_update_resp(
1898 	const struct pldm_msg *msg, size_t payload_length,
1899 	struct pldm_request_downstream_device_update_resp *resp_data)
1900 {
1901 	PLDM_MSGBUF_DEFINE_P(buf);
1902 	int rc;
1903 
1904 	if (!msg || !resp_data) {
1905 		return -EINVAL;
1906 	}
1907 
1908 	rc = pldm_msg_has_error(msg,
1909 				PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES);
1910 	if (rc) {
1911 		resp_data->completion_code = rc;
1912 		return 0;
1913 	}
1914 
1915 	rc = pldm_msgbuf_init_errno(
1916 		buf, PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES, msg->payload,
1917 		payload_length);
1918 	if (rc) {
1919 		return rc;
1920 	}
1921 
1922 	pldm_msgbuf_extract(buf, resp_data->completion_code);
1923 	pldm_msgbuf_extract(buf, resp_data->downstream_device_meta_data_length);
1924 	pldm_msgbuf_extract(
1925 		buf, resp_data->downstream_device_will_send_get_package_data);
1926 	pldm_msgbuf_extract(buf,
1927 			    resp_data->get_package_data_maximum_transfer_size);
1928 
1929 	return pldm_msgbuf_complete_consumed(buf);
1930 }
1931 
1932 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)1933 int encode_request_update_req(uint8_t instance_id, uint32_t max_transfer_size,
1934 			      uint16_t num_of_comp,
1935 			      uint8_t max_outstanding_transfer_req,
1936 			      uint16_t pkg_data_len,
1937 			      uint8_t comp_image_set_ver_str_type,
1938 			      uint8_t comp_image_set_ver_str_len,
1939 			      const struct variable_field *comp_img_set_ver_str,
1940 			      struct pldm_msg *msg, size_t payload_length)
1941 {
1942 	if (comp_img_set_ver_str == NULL || comp_img_set_ver_str->ptr == NULL ||
1943 	    msg == NULL) {
1944 		return PLDM_ERROR_INVALID_DATA;
1945 	}
1946 
1947 	if (payload_length != sizeof(struct pldm_request_update_req) +
1948 				      comp_img_set_ver_str->length) {
1949 		return PLDM_ERROR_INVALID_LENGTH;
1950 	}
1951 
1952 	if ((comp_image_set_ver_str_len == 0) ||
1953 	    (comp_image_set_ver_str_len != comp_img_set_ver_str->length)) {
1954 		return PLDM_ERROR_INVALID_DATA;
1955 	}
1956 
1957 	if ((max_transfer_size < PLDM_FWUP_BASELINE_TRANSFER_SIZE) ||
1958 	    (max_outstanding_transfer_req < PLDM_FWUP_MIN_OUTSTANDING_REQ)) {
1959 		return PLDM_ERROR_INVALID_DATA;
1960 	}
1961 
1962 	if (!is_string_type_valid(comp_image_set_ver_str_type)) {
1963 		return PLDM_ERROR_INVALID_DATA;
1964 	}
1965 
1966 	struct pldm_header_info header = { 0 };
1967 	header.instance = instance_id;
1968 	header.msg_type = PLDM_REQUEST;
1969 	header.pldm_type = PLDM_FWUP;
1970 	header.command = PLDM_REQUEST_UPDATE;
1971 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1972 	if (rc) {
1973 		return rc;
1974 	}
1975 
1976 	struct pldm_request_update_req *request =
1977 		(struct pldm_request_update_req *)msg->payload;
1978 
1979 	request->max_transfer_size = htole32(max_transfer_size);
1980 	request->num_of_comp = htole16(num_of_comp);
1981 	request->max_outstanding_transfer_req = max_outstanding_transfer_req;
1982 	request->pkg_data_len = htole16(pkg_data_len);
1983 	request->comp_image_set_ver_str_type = comp_image_set_ver_str_type;
1984 	request->comp_image_set_ver_str_len = comp_image_set_ver_str_len;
1985 
1986 	memcpy(msg->payload + sizeof(struct pldm_request_update_req),
1987 	       comp_img_set_ver_str->ptr, comp_img_set_ver_str->length);
1988 
1989 	return PLDM_SUCCESS;
1990 }
1991 
1992 LIBPLDM_ABI_TESTING
decode_request_update_req(const struct pldm_msg * msg,size_t payload_length,struct pldm_request_update_req_full * req)1993 int decode_request_update_req(const struct pldm_msg *msg, size_t payload_length,
1994 			      struct pldm_request_update_req_full *req)
1995 {
1996 	int rc;
1997 	uint8_t t;
1998 	PLDM_MSGBUF_DEFINE_P(buf);
1999 
2000 	if (msg == NULL || req == NULL) {
2001 		return -EINVAL;
2002 	}
2003 
2004 	rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2005 	if (rc) {
2006 		return rc;
2007 	}
2008 
2009 	pldm_msgbuf_extract(buf, req->max_transfer_size);
2010 	pldm_msgbuf_extract(buf, req->num_of_comp);
2011 	pldm_msgbuf_extract(buf, req->max_outstanding_transfer_req);
2012 	pldm_msgbuf_extract(buf, req->pkg_data_len);
2013 	rc = pldm_msgbuf_extract(buf, t);
2014 	if (rc) {
2015 		return pldm_msgbuf_discard(buf, rc);
2016 	}
2017 	if (t > PLDM_STR_TYPE_UTF_16BE) {
2018 		return pldm_msgbuf_discard(buf, -EBADMSG);
2019 	}
2020 	req->image_set_ver.str_type = (enum pldm_firmware_update_string_type)t;
2021 	pldm_msgbuf_extract(buf, req->image_set_ver.str_len);
2022 	if (rc) {
2023 		return pldm_msgbuf_discard(buf, rc);
2024 	}
2025 
2026 	rc = pldm_msgbuf_extract_array(buf, req->image_set_ver.str_len,
2027 				       req->image_set_ver.str_data,
2028 				       PLDM_FIRMWARE_MAX_STRING);
2029 	if (rc) {
2030 		return pldm_msgbuf_discard(buf, rc);
2031 	}
2032 
2033 	return pldm_msgbuf_complete_consumed(buf);
2034 }
2035 
2036 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)2037 int decode_request_update_resp(const struct pldm_msg *msg,
2038 			       size_t payload_length, uint8_t *completion_code,
2039 			       uint16_t *fd_meta_data_len,
2040 			       uint8_t *fd_will_send_pkg_data)
2041 {
2042 	if (msg == NULL || completion_code == NULL ||
2043 	    fd_meta_data_len == NULL || fd_will_send_pkg_data == NULL ||
2044 	    !payload_length) {
2045 		return PLDM_ERROR_INVALID_DATA;
2046 	}
2047 
2048 	*completion_code = msg->payload[0];
2049 	if (*completion_code != PLDM_SUCCESS) {
2050 		return PLDM_SUCCESS;
2051 	}
2052 
2053 	if (payload_length != sizeof(struct pldm_request_update_resp)) {
2054 		return PLDM_ERROR_INVALID_LENGTH;
2055 	}
2056 
2057 	struct pldm_request_update_resp *response =
2058 		(struct pldm_request_update_resp *)msg->payload;
2059 
2060 	*fd_meta_data_len = le16toh(response->fd_meta_data_len);
2061 	*fd_will_send_pkg_data = response->fd_will_send_pkg_data;
2062 
2063 	return PLDM_SUCCESS;
2064 }
2065 
2066 LIBPLDM_ABI_TESTING
encode_request_update_resp(uint8_t instance_id,const struct pldm_request_update_resp * resp_data,struct pldm_msg * msg,size_t * payload_length)2067 int encode_request_update_resp(uint8_t instance_id,
2068 			       const struct pldm_request_update_resp *resp_data,
2069 			       struct pldm_msg *msg, size_t *payload_length)
2070 {
2071 	PLDM_MSGBUF_DEFINE_P(buf);
2072 	int rc;
2073 
2074 	if (msg == NULL || payload_length == NULL) {
2075 		return -EINVAL;
2076 	}
2077 
2078 	struct pldm_header_info header = {
2079 		.instance = instance_id,
2080 		.msg_type = PLDM_RESPONSE,
2081 		.pldm_type = PLDM_FWUP,
2082 		.command = PLDM_REQUEST_UPDATE,
2083 	};
2084 	rc = pack_pldm_header(&header, &(msg->hdr));
2085 	if (rc) {
2086 		return -EINVAL;
2087 	}
2088 
2089 	rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2090 	if (rc) {
2091 		return rc;
2092 	}
2093 
2094 	pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2095 	pldm_msgbuf_insert(buf, resp_data->fd_meta_data_len);
2096 	pldm_msgbuf_insert(buf, resp_data->fd_will_send_pkg_data);
2097 
2098 	/* TODO: DSP0267 1.3.0 adds GetPackageDataMaximumTransferSize */
2099 
2100 	return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
2101 }
2102 
2103 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)2104 int encode_pass_component_table_req(uint8_t instance_id, uint8_t transfer_flag,
2105 				    uint16_t comp_classification,
2106 				    uint16_t comp_identifier,
2107 				    uint8_t comp_classification_index,
2108 				    uint32_t comp_comparison_stamp,
2109 				    uint8_t comp_ver_str_type,
2110 				    uint8_t comp_ver_str_len,
2111 				    const struct variable_field *comp_ver_str,
2112 				    struct pldm_msg *msg, size_t payload_length)
2113 {
2114 	if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) {
2115 		return PLDM_ERROR_INVALID_DATA;
2116 	}
2117 
2118 	if (payload_length != sizeof(struct pldm_pass_component_table_req) +
2119 				      comp_ver_str->length) {
2120 		return PLDM_ERROR_INVALID_LENGTH;
2121 	}
2122 
2123 	if ((comp_ver_str_len == 0) ||
2124 	    (comp_ver_str_len != comp_ver_str->length)) {
2125 		return PLDM_ERROR_INVALID_DATA;
2126 	}
2127 
2128 	if (!is_transfer_flag_valid(transfer_flag)) {
2129 		return PLDM_FWUP_INVALID_TRANSFER_OPERATION_FLAG;
2130 	}
2131 
2132 	if (!is_string_type_valid(comp_ver_str_type)) {
2133 		return PLDM_ERROR_INVALID_DATA;
2134 	}
2135 
2136 	struct pldm_header_info header = { 0 };
2137 	header.instance = instance_id;
2138 	header.msg_type = PLDM_REQUEST;
2139 	header.pldm_type = PLDM_FWUP;
2140 	header.command = PLDM_PASS_COMPONENT_TABLE;
2141 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2142 	if (rc) {
2143 		return rc;
2144 	}
2145 
2146 	struct pldm_pass_component_table_req *request =
2147 		(struct pldm_pass_component_table_req *)msg->payload;
2148 
2149 	request->transfer_flag = transfer_flag;
2150 	request->comp_classification = htole16(comp_classification);
2151 	request->comp_identifier = htole16(comp_identifier);
2152 	request->comp_classification_index = comp_classification_index;
2153 	request->comp_comparison_stamp = htole32(comp_comparison_stamp);
2154 	request->comp_ver_str_type = comp_ver_str_type;
2155 	request->comp_ver_str_len = comp_ver_str_len;
2156 
2157 	memcpy(msg->payload + sizeof(struct pldm_pass_component_table_req),
2158 	       comp_ver_str->ptr, comp_ver_str->length);
2159 
2160 	return PLDM_SUCCESS;
2161 }
2162 
2163 LIBPLDM_ABI_TESTING
decode_pass_component_table_req(const struct pldm_msg * msg,size_t payload_length,struct pldm_pass_component_table_req_full * pcomp)2164 int decode_pass_component_table_req(
2165 	const struct pldm_msg *msg, size_t payload_length,
2166 	struct pldm_pass_component_table_req_full *pcomp)
2167 {
2168 	int rc;
2169 	uint8_t t;
2170 	PLDM_MSGBUF_DEFINE_P(buf);
2171 
2172 	if (msg == NULL || pcomp == NULL) {
2173 		return -EINVAL;
2174 	}
2175 
2176 	rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2177 	if (rc) {
2178 		return rc;
2179 	}
2180 
2181 	pldm_msgbuf_extract(buf, pcomp->transfer_flag);
2182 	pldm_msgbuf_extract(buf, pcomp->comp_classification);
2183 	pldm_msgbuf_extract(buf, pcomp->comp_identifier);
2184 	pldm_msgbuf_extract(buf, pcomp->comp_classification_index);
2185 	pldm_msgbuf_extract(buf, pcomp->comp_comparison_stamp);
2186 	rc = pldm_msgbuf_extract(buf, t);
2187 	if (rc) {
2188 		return pldm_msgbuf_discard(buf, rc);
2189 	}
2190 	if (t > PLDM_STR_TYPE_UTF_16BE) {
2191 		return pldm_msgbuf_discard(buf, -EBADMSG);
2192 	}
2193 	pcomp->version.str_type = (enum pldm_firmware_update_string_type)t;
2194 	rc = pldm_msgbuf_extract(buf, pcomp->version.str_len);
2195 	if (rc) {
2196 		return pldm_msgbuf_discard(buf, rc);
2197 	}
2198 	rc = pldm_msgbuf_extract_array(buf, pcomp->version.str_len,
2199 				       pcomp->version.str_data,
2200 				       PLDM_FIRMWARE_MAX_STRING);
2201 	if (rc) {
2202 		return pldm_msgbuf_discard(buf, rc);
2203 	}
2204 
2205 	return pldm_msgbuf_complete_consumed(buf);
2206 }
2207 
2208 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)2209 int decode_pass_component_table_resp(const struct pldm_msg *msg,
2210 				     const size_t payload_length,
2211 				     uint8_t *completion_code,
2212 				     uint8_t *comp_resp,
2213 				     uint8_t *comp_resp_code)
2214 {
2215 	if (msg == NULL || completion_code == NULL || comp_resp == NULL ||
2216 	    comp_resp_code == NULL || !payload_length) {
2217 		return PLDM_ERROR_INVALID_DATA;
2218 	}
2219 
2220 	*completion_code = msg->payload[0];
2221 	if (*completion_code != PLDM_SUCCESS) {
2222 		return PLDM_SUCCESS;
2223 	}
2224 
2225 	if (payload_length != sizeof(struct pldm_pass_component_table_resp)) {
2226 		return PLDM_ERROR_INVALID_LENGTH;
2227 	}
2228 
2229 	struct pldm_pass_component_table_resp *response =
2230 		(struct pldm_pass_component_table_resp *)msg->payload;
2231 
2232 	if (!is_comp_resp_valid(response->comp_resp)) {
2233 		return PLDM_ERROR_INVALID_DATA;
2234 	}
2235 
2236 	if (!is_comp_resp_code_valid(response->comp_resp_code)) {
2237 		return PLDM_ERROR_INVALID_DATA;
2238 	}
2239 
2240 	*comp_resp = response->comp_resp;
2241 	*comp_resp_code = response->comp_resp_code;
2242 
2243 	return PLDM_SUCCESS;
2244 }
2245 
2246 LIBPLDM_ABI_TESTING
encode_pass_component_table_resp(uint8_t instance_id,const struct pldm_pass_component_table_resp * resp_data,struct pldm_msg * msg,size_t * payload_length)2247 int encode_pass_component_table_resp(
2248 	uint8_t instance_id,
2249 	const struct pldm_pass_component_table_resp *resp_data,
2250 	struct pldm_msg *msg, size_t *payload_length)
2251 {
2252 	PLDM_MSGBUF_DEFINE_P(buf);
2253 	int rc;
2254 
2255 	if (msg == NULL || payload_length == NULL) {
2256 		return -EINVAL;
2257 	}
2258 
2259 	rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2260 				     PLDM_PASS_COMPONENT_TABLE, msg);
2261 	if (rc) {
2262 		return -EINVAL;
2263 	}
2264 
2265 	rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2266 	if (rc) {
2267 		return rc;
2268 	}
2269 
2270 	pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2271 	pldm_msgbuf_insert(buf, resp_data->comp_resp);
2272 	pldm_msgbuf_insert(buf, resp_data->comp_resp_code);
2273 
2274 	return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
2275 }
2276 
2277 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)2278 int encode_update_component_req(
2279 	uint8_t instance_id, uint16_t comp_classification,
2280 	uint16_t comp_identifier, uint8_t comp_classification_index,
2281 	uint32_t comp_comparison_stamp, uint32_t comp_image_size,
2282 	bitfield32_t update_option_flags, uint8_t comp_ver_str_type,
2283 	uint8_t comp_ver_str_len, const struct variable_field *comp_ver_str,
2284 	struct pldm_msg *msg, size_t payload_length)
2285 {
2286 	if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) {
2287 		return PLDM_ERROR_INVALID_DATA;
2288 	}
2289 
2290 	if (payload_length !=
2291 	    sizeof(struct pldm_update_component_req) + comp_ver_str->length) {
2292 		return PLDM_ERROR_INVALID_LENGTH;
2293 	}
2294 
2295 	if (!comp_image_size) {
2296 		return PLDM_ERROR_INVALID_DATA;
2297 	}
2298 
2299 	if ((comp_ver_str_len == 0) ||
2300 	    (comp_ver_str_len != comp_ver_str->length)) {
2301 		return PLDM_ERROR_INVALID_DATA;
2302 	}
2303 
2304 	if (!is_string_type_valid(comp_ver_str_type)) {
2305 		return PLDM_ERROR_INVALID_DATA;
2306 	}
2307 
2308 	struct pldm_header_info header = { 0 };
2309 	header.instance = instance_id;
2310 	header.msg_type = PLDM_REQUEST;
2311 	header.pldm_type = PLDM_FWUP;
2312 	header.command = PLDM_UPDATE_COMPONENT;
2313 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2314 	if (rc) {
2315 		return rc;
2316 	}
2317 
2318 	struct pldm_update_component_req *request =
2319 		(struct pldm_update_component_req *)msg->payload;
2320 
2321 	request->comp_classification = htole16(comp_classification);
2322 	request->comp_identifier = htole16(comp_identifier);
2323 	request->comp_classification_index = comp_classification_index;
2324 	request->comp_comparison_stamp = htole32(comp_comparison_stamp);
2325 	request->comp_image_size = htole32(comp_image_size);
2326 	request->update_option_flags.value = htole32(update_option_flags.value);
2327 	request->comp_ver_str_type = comp_ver_str_type;
2328 	request->comp_ver_str_len = comp_ver_str_len;
2329 
2330 	memcpy(msg->payload + sizeof(struct pldm_update_component_req),
2331 	       comp_ver_str->ptr, comp_ver_str->length);
2332 
2333 	return PLDM_SUCCESS;
2334 }
2335 
2336 LIBPLDM_ABI_TESTING
decode_update_component_req(const struct pldm_msg * msg,size_t payload_length,struct pldm_update_component_req_full * up)2337 int decode_update_component_req(const struct pldm_msg *msg,
2338 				size_t payload_length,
2339 				struct pldm_update_component_req_full *up)
2340 {
2341 	int rc;
2342 	uint8_t t;
2343 	PLDM_MSGBUF_DEFINE_P(buf);
2344 
2345 	if (msg == NULL || up == NULL) {
2346 		return -EINVAL;
2347 	}
2348 
2349 	rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2350 	if (rc) {
2351 		return rc;
2352 	}
2353 
2354 	pldm_msgbuf_extract(buf, up->comp_classification);
2355 	pldm_msgbuf_extract(buf, up->comp_identifier);
2356 	pldm_msgbuf_extract(buf, up->comp_classification_index);
2357 	pldm_msgbuf_extract(buf, up->comp_comparison_stamp);
2358 	pldm_msgbuf_extract(buf, up->comp_image_size);
2359 	pldm_msgbuf_extract(buf, up->update_option_flags.value);
2360 	rc = pldm_msgbuf_extract(buf, t);
2361 	if (rc) {
2362 		return pldm_msgbuf_discard(buf, rc);
2363 	}
2364 	if (t > PLDM_STR_TYPE_UTF_16BE) {
2365 		return pldm_msgbuf_discard(buf, -EBADMSG);
2366 	}
2367 	up->version.str_type = (enum pldm_firmware_update_string_type)t;
2368 	rc = pldm_msgbuf_extract(buf, up->version.str_len);
2369 	if (rc) {
2370 		return pldm_msgbuf_discard(buf, rc);
2371 	}
2372 	rc = pldm_msgbuf_extract_array(buf, up->version.str_len,
2373 				       up->version.str_data,
2374 				       PLDM_FIRMWARE_MAX_STRING);
2375 	if (rc) {
2376 		return pldm_msgbuf_discard(buf, rc);
2377 	}
2378 
2379 	return pldm_msgbuf_complete_consumed(buf);
2380 }
2381 
2382 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)2383 int decode_update_component_resp(const struct pldm_msg *msg,
2384 				 size_t payload_length,
2385 				 uint8_t *completion_code,
2386 				 uint8_t *comp_compatibility_resp,
2387 				 uint8_t *comp_compatibility_resp_code,
2388 				 bitfield32_t *update_option_flags_enabled,
2389 				 uint16_t *time_before_req_fw_data)
2390 {
2391 	if (msg == NULL || completion_code == NULL ||
2392 	    comp_compatibility_resp == NULL ||
2393 	    comp_compatibility_resp_code == NULL ||
2394 	    update_option_flags_enabled == NULL ||
2395 	    time_before_req_fw_data == NULL || !payload_length) {
2396 		return PLDM_ERROR_INVALID_DATA;
2397 	}
2398 
2399 	*completion_code = msg->payload[0];
2400 	if (*completion_code != PLDM_SUCCESS) {
2401 		return PLDM_SUCCESS;
2402 	}
2403 
2404 	if (payload_length != sizeof(struct pldm_update_component_resp)) {
2405 		return PLDM_ERROR_INVALID_LENGTH;
2406 	}
2407 
2408 	struct pldm_update_component_resp *response =
2409 		(struct pldm_update_component_resp *)msg->payload;
2410 
2411 	if (!is_comp_compatibility_resp_valid(
2412 		    response->comp_compatibility_resp)) {
2413 		return PLDM_ERROR_INVALID_DATA;
2414 	}
2415 
2416 	if (!is_comp_compatibility_resp_code_valid(
2417 		    response->comp_compatibility_resp_code)) {
2418 		return PLDM_ERROR_INVALID_DATA;
2419 	}
2420 
2421 	*comp_compatibility_resp = response->comp_compatibility_resp;
2422 	*comp_compatibility_resp_code = response->comp_compatibility_resp_code;
2423 	update_option_flags_enabled->value =
2424 		le32toh(response->update_option_flags_enabled.value);
2425 	*time_before_req_fw_data = le16toh(response->time_before_req_fw_data);
2426 
2427 	return PLDM_SUCCESS;
2428 }
2429 
2430 LIBPLDM_ABI_TESTING
encode_update_component_resp(uint8_t instance_id,const struct pldm_update_component_resp * resp_data,struct pldm_msg * msg,size_t * payload_length)2431 int encode_update_component_resp(
2432 	uint8_t instance_id, const struct pldm_update_component_resp *resp_data,
2433 	struct pldm_msg *msg, size_t *payload_length)
2434 {
2435 	PLDM_MSGBUF_DEFINE_P(buf);
2436 	int rc;
2437 
2438 	if (msg == NULL || payload_length == NULL) {
2439 		return -EINVAL;
2440 	}
2441 
2442 	rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2443 				     PLDM_UPDATE_COMPONENT, msg);
2444 	if (rc) {
2445 		return -EINVAL;
2446 	}
2447 
2448 	rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2449 	if (rc) {
2450 		return rc;
2451 	}
2452 
2453 	pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2454 	pldm_msgbuf_insert(buf, resp_data->comp_compatibility_resp);
2455 	pldm_msgbuf_insert(buf, resp_data->comp_compatibility_resp_code);
2456 	pldm_msgbuf_insert(buf, resp_data->update_option_flags_enabled.value);
2457 	pldm_msgbuf_insert(buf, resp_data->time_before_req_fw_data);
2458 
2459 	return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
2460 }
2461 
2462 LIBPLDM_ABI_STABLE
decode_request_firmware_data_req(const struct pldm_msg * msg,size_t payload_length,uint32_t * offset,uint32_t * length)2463 int decode_request_firmware_data_req(const struct pldm_msg *msg,
2464 				     size_t payload_length, uint32_t *offset,
2465 				     uint32_t *length)
2466 {
2467 	if (msg == NULL || offset == NULL || length == NULL) {
2468 		return PLDM_ERROR_INVALID_DATA;
2469 	}
2470 	if (payload_length != sizeof(struct pldm_request_firmware_data_req)) {
2471 		return PLDM_ERROR_INVALID_LENGTH;
2472 	}
2473 	struct pldm_request_firmware_data_req *request =
2474 		(struct pldm_request_firmware_data_req *)msg->payload;
2475 	*offset = le32toh(request->offset);
2476 	*length = le32toh(request->length);
2477 
2478 	if (*length < PLDM_FWUP_BASELINE_TRANSFER_SIZE) {
2479 		return PLDM_FWUP_INVALID_TRANSFER_LENGTH;
2480 	}
2481 
2482 	return PLDM_SUCCESS;
2483 }
2484 
2485 LIBPLDM_ABI_TESTING
encode_request_firmware_data_req(uint8_t instance_id,const struct pldm_request_firmware_data_req * req_params,struct pldm_msg * msg,size_t * payload_length)2486 int encode_request_firmware_data_req(
2487 	uint8_t instance_id,
2488 	const struct pldm_request_firmware_data_req *req_params,
2489 	struct pldm_msg *msg, size_t *payload_length)
2490 {
2491 	PLDM_MSGBUF_DEFINE_P(buf);
2492 	int rc;
2493 
2494 	if (msg == NULL || payload_length == NULL) {
2495 		return -EINVAL;
2496 	}
2497 
2498 	rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2499 				     PLDM_REQUEST_FIRMWARE_DATA, msg);
2500 	if (rc) {
2501 		return -EINVAL;
2502 	}
2503 
2504 	rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2505 	if (rc) {
2506 		return rc;
2507 	}
2508 
2509 	pldm_msgbuf_insert(buf, req_params->offset);
2510 	pldm_msgbuf_insert(buf, req_params->length);
2511 
2512 	return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
2513 }
2514 
2515 LIBPLDM_ABI_STABLE
encode_request_firmware_data_resp(uint8_t instance_id,uint8_t completion_code,struct pldm_msg * msg,size_t payload_length)2516 int encode_request_firmware_data_resp(uint8_t instance_id,
2517 				      uint8_t completion_code,
2518 				      struct pldm_msg *msg,
2519 				      size_t payload_length)
2520 {
2521 	if (msg == NULL || !payload_length) {
2522 		return PLDM_ERROR_INVALID_DATA;
2523 	}
2524 
2525 	struct pldm_header_info header = { 0 };
2526 	header.instance = instance_id;
2527 	header.msg_type = PLDM_RESPONSE;
2528 	header.pldm_type = PLDM_FWUP;
2529 	header.command = PLDM_REQUEST_FIRMWARE_DATA;
2530 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2531 	if (rc) {
2532 		return rc;
2533 	}
2534 
2535 	msg->payload[0] = completion_code;
2536 
2537 	return PLDM_SUCCESS;
2538 }
2539 
2540 LIBPLDM_ABI_STABLE
decode_transfer_complete_req(const struct pldm_msg * msg,size_t payload_length,uint8_t * transfer_result)2541 int decode_transfer_complete_req(const struct pldm_msg *msg,
2542 				 size_t payload_length,
2543 				 uint8_t *transfer_result)
2544 {
2545 	if (msg == NULL || transfer_result == NULL) {
2546 		return PLDM_ERROR_INVALID_DATA;
2547 	}
2548 
2549 	if (payload_length != sizeof(*transfer_result)) {
2550 		return PLDM_ERROR_INVALID_LENGTH;
2551 	}
2552 
2553 	*transfer_result = msg->payload[0];
2554 	return PLDM_SUCCESS;
2555 }
2556 
2557 LIBPLDM_ABI_TESTING
encode_transfer_complete_req(uint8_t instance_id,uint8_t transfer_result,struct pldm_msg * msg,size_t * payload_length)2558 int encode_transfer_complete_req(uint8_t instance_id, uint8_t transfer_result,
2559 				 struct pldm_msg *msg, size_t *payload_length)
2560 {
2561 	PLDM_MSGBUF_DEFINE_P(buf);
2562 	int rc;
2563 
2564 	if (msg == NULL || payload_length == NULL) {
2565 		return -EINVAL;
2566 	}
2567 
2568 	rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2569 				     PLDM_TRANSFER_COMPLETE, msg);
2570 	if (rc) {
2571 		return -EINVAL;
2572 	}
2573 
2574 	rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2575 	if (rc) {
2576 		return rc;
2577 	}
2578 
2579 	pldm_msgbuf_insert(buf, transfer_result);
2580 
2581 	return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
2582 }
2583 
2584 LIBPLDM_ABI_STABLE
encode_transfer_complete_resp(uint8_t instance_id,uint8_t completion_code,struct pldm_msg * msg,size_t payload_length)2585 int encode_transfer_complete_resp(uint8_t instance_id, uint8_t completion_code,
2586 				  struct pldm_msg *msg, size_t payload_length)
2587 {
2588 	if (msg == NULL) {
2589 		return PLDM_ERROR_INVALID_DATA;
2590 	}
2591 
2592 	if (payload_length != sizeof(completion_code)) {
2593 		return PLDM_ERROR_INVALID_LENGTH;
2594 	}
2595 
2596 	struct pldm_header_info header = { 0 };
2597 	header.instance = instance_id;
2598 	header.msg_type = PLDM_RESPONSE;
2599 	header.pldm_type = PLDM_FWUP;
2600 	header.command = PLDM_TRANSFER_COMPLETE;
2601 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2602 	if (rc) {
2603 		return rc;
2604 	}
2605 
2606 	msg->payload[0] = completion_code;
2607 
2608 	return PLDM_SUCCESS;
2609 }
2610 
2611 LIBPLDM_ABI_STABLE
decode_verify_complete_req(const struct pldm_msg * msg,size_t payload_length,uint8_t * verify_result)2612 int decode_verify_complete_req(const struct pldm_msg *msg,
2613 			       size_t payload_length, uint8_t *verify_result)
2614 {
2615 	if (msg == NULL || verify_result == NULL) {
2616 		return PLDM_ERROR_INVALID_DATA;
2617 	}
2618 
2619 	if (payload_length != sizeof(*verify_result)) {
2620 		return PLDM_ERROR_INVALID_LENGTH;
2621 	}
2622 
2623 	*verify_result = msg->payload[0];
2624 	return PLDM_SUCCESS;
2625 }
2626 
2627 LIBPLDM_ABI_TESTING
encode_verify_complete_req(uint8_t instance_id,uint8_t verify_result,struct pldm_msg * msg,size_t * payload_length)2628 int encode_verify_complete_req(uint8_t instance_id, uint8_t verify_result,
2629 			       struct pldm_msg *msg, size_t *payload_length)
2630 {
2631 	PLDM_MSGBUF_DEFINE_P(buf);
2632 	int rc;
2633 
2634 	if (msg == NULL || payload_length == NULL) {
2635 		return -EINVAL;
2636 	}
2637 
2638 	rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2639 				     PLDM_VERIFY_COMPLETE, msg);
2640 	if (rc) {
2641 		return EINVAL;
2642 	}
2643 
2644 	rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2645 	if (rc) {
2646 		return rc;
2647 	}
2648 
2649 	pldm_msgbuf_insert(buf, verify_result);
2650 
2651 	return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
2652 }
2653 
2654 LIBPLDM_ABI_STABLE
encode_verify_complete_resp(uint8_t instance_id,uint8_t completion_code,struct pldm_msg * msg,size_t payload_length)2655 int encode_verify_complete_resp(uint8_t instance_id, uint8_t completion_code,
2656 				struct pldm_msg *msg, size_t payload_length)
2657 {
2658 	if (msg == NULL) {
2659 		return PLDM_ERROR_INVALID_DATA;
2660 	}
2661 
2662 	if (payload_length != sizeof(completion_code)) {
2663 		return PLDM_ERROR_INVALID_LENGTH;
2664 	}
2665 
2666 	struct pldm_header_info header = { 0 };
2667 	header.instance = instance_id;
2668 	header.msg_type = PLDM_RESPONSE;
2669 	header.pldm_type = PLDM_FWUP;
2670 	header.command = PLDM_VERIFY_COMPLETE;
2671 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2672 	if (rc) {
2673 		return rc;
2674 	}
2675 
2676 	msg->payload[0] = completion_code;
2677 
2678 	return PLDM_SUCCESS;
2679 }
2680 
2681 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)2682 int decode_apply_complete_req(const struct pldm_msg *msg, size_t payload_length,
2683 			      uint8_t *apply_result,
2684 			      bitfield16_t *comp_activation_methods_modification)
2685 {
2686 	if (msg == NULL || apply_result == NULL ||
2687 	    comp_activation_methods_modification == NULL) {
2688 		return PLDM_ERROR_INVALID_DATA;
2689 	}
2690 
2691 	if (payload_length != sizeof(struct pldm_apply_complete_req)) {
2692 		return PLDM_ERROR_INVALID_LENGTH;
2693 	}
2694 
2695 	struct pldm_apply_complete_req *request =
2696 		(struct pldm_apply_complete_req *)msg->payload;
2697 
2698 	*apply_result = request->apply_result;
2699 	comp_activation_methods_modification->value =
2700 		le16toh(request->comp_activation_methods_modification.value);
2701 
2702 	if ((*apply_result != PLDM_FWUP_APPLY_SUCCESS_WITH_ACTIVATION_METHOD) &&
2703 	    comp_activation_methods_modification->value) {
2704 		return PLDM_ERROR_INVALID_DATA;
2705 	}
2706 
2707 	return PLDM_SUCCESS;
2708 }
2709 
2710 LIBPLDM_ABI_TESTING
encode_apply_complete_req(uint8_t instance_id,const struct pldm_apply_complete_req * req_data,struct pldm_msg * msg,size_t * payload_length)2711 int encode_apply_complete_req(uint8_t instance_id,
2712 			      const struct pldm_apply_complete_req *req_data,
2713 			      struct pldm_msg *msg, size_t *payload_length)
2714 {
2715 	PLDM_MSGBUF_DEFINE_P(buf);
2716 	int rc;
2717 
2718 	if (msg == NULL || payload_length == NULL) {
2719 		return -EINVAL;
2720 	}
2721 
2722 	rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2723 				     PLDM_APPLY_COMPLETE, msg);
2724 	if (rc) {
2725 		return -EINVAL;
2726 	}
2727 
2728 	rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2729 	if (rc) {
2730 		return rc;
2731 	}
2732 
2733 	pldm_msgbuf_insert(buf, req_data->apply_result);
2734 	pldm_msgbuf_insert(
2735 		buf, req_data->comp_activation_methods_modification.value);
2736 
2737 	return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
2738 }
2739 
2740 LIBPLDM_ABI_STABLE
encode_apply_complete_resp(uint8_t instance_id,uint8_t completion_code,struct pldm_msg * msg,size_t payload_length)2741 int encode_apply_complete_resp(uint8_t instance_id, uint8_t completion_code,
2742 			       struct pldm_msg *msg, size_t payload_length)
2743 {
2744 	if (msg == NULL) {
2745 		return PLDM_ERROR_INVALID_DATA;
2746 	}
2747 
2748 	if (payload_length != sizeof(completion_code)) {
2749 		return PLDM_ERROR_INVALID_LENGTH;
2750 	}
2751 
2752 	struct pldm_header_info header = { 0 };
2753 	header.instance = instance_id;
2754 	header.msg_type = PLDM_RESPONSE;
2755 	header.pldm_type = PLDM_FWUP;
2756 	header.command = PLDM_APPLY_COMPLETE;
2757 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2758 	if (rc) {
2759 		return rc;
2760 	}
2761 
2762 	msg->payload[0] = completion_code;
2763 
2764 	return PLDM_SUCCESS;
2765 }
2766 
2767 LIBPLDM_ABI_TESTING
decode_activate_firmware_req(const struct pldm_msg * msg,size_t payload_length,bool * self_contained)2768 int decode_activate_firmware_req(const struct pldm_msg *msg,
2769 				 size_t payload_length, bool *self_contained)
2770 {
2771 	uint8_t self_contained_u8 = 0;
2772 	PLDM_MSGBUF_DEFINE_P(buf);
2773 	int rc;
2774 
2775 	if (msg == NULL || self_contained == NULL) {
2776 		return -EINVAL;
2777 	}
2778 
2779 	rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2780 	if (rc) {
2781 		return 0;
2782 	}
2783 
2784 	pldm_msgbuf_extract(buf, self_contained_u8);
2785 
2786 	rc = pldm_msgbuf_complete_consumed(buf);
2787 	if (rc) {
2788 		return rc;
2789 	}
2790 
2791 	*self_contained = (bool)self_contained_u8;
2792 	return 0;
2793 }
2794 
2795 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)2796 int encode_activate_firmware_req(uint8_t instance_id,
2797 				 bool8_t self_contained_activation_req,
2798 				 struct pldm_msg *msg, size_t payload_length)
2799 {
2800 	if (msg == NULL) {
2801 		return PLDM_ERROR_INVALID_DATA;
2802 	}
2803 
2804 	if (payload_length != sizeof(struct pldm_activate_firmware_req)) {
2805 		return PLDM_ERROR_INVALID_LENGTH;
2806 	}
2807 
2808 	if (!is_self_contained_activation_req_valid(
2809 		    self_contained_activation_req)) {
2810 		return PLDM_ERROR_INVALID_DATA;
2811 	}
2812 
2813 	struct pldm_header_info header = { 0 };
2814 	header.instance = instance_id;
2815 	header.msg_type = PLDM_REQUEST;
2816 	header.pldm_type = PLDM_FWUP;
2817 	header.command = PLDM_ACTIVATE_FIRMWARE;
2818 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2819 	if (rc) {
2820 		return rc;
2821 	}
2822 
2823 	struct pldm_activate_firmware_req *request =
2824 		(struct pldm_activate_firmware_req *)msg->payload;
2825 
2826 	request->self_contained_activation_req = self_contained_activation_req;
2827 
2828 	return PLDM_SUCCESS;
2829 }
2830 
2831 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)2832 int decode_activate_firmware_resp(const struct pldm_msg *msg,
2833 				  size_t payload_length,
2834 				  uint8_t *completion_code,
2835 				  uint16_t *estimated_time_activation)
2836 {
2837 	if (msg == NULL || completion_code == NULL ||
2838 	    estimated_time_activation == NULL || !payload_length) {
2839 		return PLDM_ERROR_INVALID_DATA;
2840 	}
2841 
2842 	*completion_code = msg->payload[0];
2843 	if (*completion_code != PLDM_SUCCESS) {
2844 		return PLDM_SUCCESS;
2845 	}
2846 
2847 	if (payload_length != sizeof(struct pldm_activate_firmware_resp)) {
2848 		return PLDM_ERROR_INVALID_LENGTH;
2849 	}
2850 
2851 	struct pldm_activate_firmware_resp *response =
2852 		(struct pldm_activate_firmware_resp *)msg->payload;
2853 
2854 	*estimated_time_activation =
2855 		le16toh(response->estimated_time_activation);
2856 
2857 	return PLDM_SUCCESS;
2858 }
2859 
2860 LIBPLDM_ABI_TESTING
encode_activate_firmware_resp(uint8_t instance_id,const struct pldm_activate_firmware_resp * resp_data,struct pldm_msg * msg,size_t * payload_length)2861 int encode_activate_firmware_resp(
2862 	uint8_t instance_id,
2863 	const struct pldm_activate_firmware_resp *resp_data,
2864 	struct pldm_msg *msg, size_t *payload_length)
2865 {
2866 	PLDM_MSGBUF_DEFINE_P(buf);
2867 	int rc;
2868 
2869 	if (msg == NULL || payload_length == NULL) {
2870 		return -EINVAL;
2871 	}
2872 
2873 	rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2874 				     PLDM_ACTIVATE_FIRMWARE, msg);
2875 	if (rc) {
2876 		return -EINVAL;
2877 	}
2878 
2879 	rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2880 	if (rc) {
2881 		return rc;
2882 	}
2883 
2884 	pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2885 	pldm_msgbuf_insert(buf, resp_data->estimated_time_activation);
2886 
2887 	return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
2888 }
2889 
2890 LIBPLDM_ABI_STABLE
encode_get_status_req(uint8_t instance_id,struct pldm_msg * msg,size_t payload_length)2891 int encode_get_status_req(uint8_t instance_id, struct pldm_msg *msg,
2892 			  size_t payload_length)
2893 {
2894 	if (msg == NULL) {
2895 		return PLDM_ERROR_INVALID_DATA;
2896 	}
2897 
2898 	if (payload_length != PLDM_GET_STATUS_REQ_BYTES) {
2899 		return PLDM_ERROR_INVALID_LENGTH;
2900 	}
2901 
2902 	struct pldm_header_info header = { 0 };
2903 	header.instance = instance_id;
2904 	header.msg_type = PLDM_REQUEST;
2905 	header.pldm_type = PLDM_FWUP;
2906 	header.command = PLDM_GET_STATUS;
2907 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2908 	if (rc) {
2909 		return rc;
2910 	}
2911 
2912 	return PLDM_SUCCESS;
2913 }
2914 
2915 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)2916 int decode_get_status_resp(const struct pldm_msg *msg, size_t payload_length,
2917 			   uint8_t *completion_code, uint8_t *current_state,
2918 			   uint8_t *previous_state, uint8_t *aux_state,
2919 			   uint8_t *aux_state_status, uint8_t *progress_percent,
2920 			   uint8_t *reason_code,
2921 			   bitfield32_t *update_option_flags_enabled)
2922 {
2923 	if (msg == NULL || completion_code == NULL || current_state == NULL ||
2924 	    previous_state == NULL || aux_state == NULL ||
2925 	    aux_state_status == NULL || progress_percent == NULL ||
2926 	    reason_code == NULL || update_option_flags_enabled == NULL ||
2927 	    !payload_length) {
2928 		return PLDM_ERROR_INVALID_DATA;
2929 	}
2930 
2931 	*completion_code = msg->payload[0];
2932 	if (*completion_code != PLDM_SUCCESS) {
2933 		return PLDM_SUCCESS;
2934 	}
2935 
2936 	if (payload_length != sizeof(struct pldm_get_status_resp)) {
2937 		return PLDM_ERROR_INVALID_LENGTH;
2938 	}
2939 	struct pldm_get_status_resp *response =
2940 		(struct pldm_get_status_resp *)msg->payload;
2941 
2942 	if (!is_state_valid(response->current_state)) {
2943 		return PLDM_ERROR_INVALID_DATA;
2944 	}
2945 	if (!is_state_valid(response->previous_state)) {
2946 		return PLDM_ERROR_INVALID_DATA;
2947 	}
2948 	if (!is_aux_state_valid(response->aux_state)) {
2949 		return PLDM_ERROR_INVALID_DATA;
2950 	}
2951 	if (!is_aux_state_status_valid(response->aux_state_status)) {
2952 		return PLDM_ERROR_INVALID_DATA;
2953 	}
2954 	if (response->progress_percent > PLDM_FWUP_MAX_PROGRESS_PERCENT) {
2955 		return PLDM_ERROR_INVALID_DATA;
2956 	}
2957 	if (!is_reason_code_valid(response->reason_code)) {
2958 		return PLDM_ERROR_INVALID_DATA;
2959 	}
2960 
2961 	if ((response->current_state == PLDM_FD_STATE_IDLE) ||
2962 	    (response->current_state == PLDM_FD_STATE_LEARN_COMPONENTS) ||
2963 	    (response->current_state == PLDM_FD_STATE_READY_XFER)) {
2964 		if (response->aux_state !=
2965 		    PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER) {
2966 			return PLDM_ERROR_INVALID_DATA;
2967 		}
2968 	}
2969 
2970 	*current_state = response->current_state;
2971 	*previous_state = response->previous_state;
2972 	*aux_state = response->aux_state;
2973 	*aux_state_status = response->aux_state_status;
2974 	*progress_percent = response->progress_percent;
2975 	*reason_code = response->reason_code;
2976 	update_option_flags_enabled->value =
2977 		le32toh(response->update_option_flags_enabled.value);
2978 
2979 	return PLDM_SUCCESS;
2980 }
2981 
2982 LIBPLDM_ABI_TESTING
encode_get_status_resp(uint8_t instance_id,const struct pldm_get_status_resp * status,struct pldm_msg * msg,size_t * payload_length)2983 int encode_get_status_resp(uint8_t instance_id,
2984 			   const struct pldm_get_status_resp *status,
2985 			   struct pldm_msg *msg, size_t *payload_length)
2986 {
2987 	PLDM_MSGBUF_DEFINE_P(buf);
2988 	int rc;
2989 
2990 	if (status == NULL || msg == NULL || payload_length == NULL) {
2991 		return -EINVAL;
2992 	}
2993 
2994 	if (status->completion_code != PLDM_SUCCESS) {
2995 		return -EINVAL;
2996 	}
2997 
2998 	rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2999 				     PLDM_GET_STATUS, msg);
3000 	if (rc) {
3001 		return -EINVAL;
3002 	}
3003 
3004 	rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
3005 	if (rc) {
3006 		return rc;
3007 	}
3008 
3009 	pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
3010 	pldm_msgbuf_insert(buf, status->current_state);
3011 	pldm_msgbuf_insert(buf, status->previous_state);
3012 	pldm_msgbuf_insert(buf, status->aux_state);
3013 	pldm_msgbuf_insert(buf, status->aux_state_status);
3014 	pldm_msgbuf_insert(buf, status->progress_percent);
3015 	pldm_msgbuf_insert(buf, status->reason_code);
3016 	pldm_msgbuf_insert(buf, status->update_option_flags_enabled.value);
3017 
3018 	return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
3019 }
3020 
3021 LIBPLDM_ABI_STABLE
encode_cancel_update_component_req(uint8_t instance_id,struct pldm_msg * msg,size_t payload_length)3022 int encode_cancel_update_component_req(uint8_t instance_id,
3023 				       struct pldm_msg *msg,
3024 				       size_t payload_length)
3025 {
3026 	if (msg == NULL) {
3027 		return PLDM_ERROR_INVALID_DATA;
3028 	}
3029 
3030 	if (payload_length != PLDM_CANCEL_UPDATE_COMPONENT_REQ_BYTES) {
3031 		return PLDM_ERROR_INVALID_LENGTH;
3032 	}
3033 
3034 	struct pldm_header_info header = { 0 };
3035 	header.instance = instance_id;
3036 	header.msg_type = PLDM_REQUEST;
3037 	header.pldm_type = PLDM_FWUP;
3038 	header.command = PLDM_CANCEL_UPDATE_COMPONENT;
3039 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
3040 	if (rc) {
3041 		return rc;
3042 	}
3043 
3044 	return PLDM_SUCCESS;
3045 }
3046 
3047 LIBPLDM_ABI_STABLE
decode_cancel_update_component_resp(const struct pldm_msg * msg,size_t payload_length,uint8_t * completion_code)3048 int decode_cancel_update_component_resp(const struct pldm_msg *msg,
3049 					size_t payload_length,
3050 					uint8_t *completion_code)
3051 {
3052 	if (msg == NULL || completion_code == NULL) {
3053 		return PLDM_ERROR_INVALID_DATA;
3054 	}
3055 
3056 	if (payload_length != sizeof(*completion_code)) {
3057 		return PLDM_ERROR_INVALID_LENGTH;
3058 	}
3059 
3060 	*completion_code = msg->payload[0];
3061 	return PLDM_SUCCESS;
3062 }
3063 
3064 LIBPLDM_ABI_STABLE
encode_cancel_update_req(uint8_t instance_id,struct pldm_msg * msg,size_t payload_length)3065 int encode_cancel_update_req(uint8_t instance_id, struct pldm_msg *msg,
3066 			     size_t payload_length)
3067 {
3068 	if (msg == NULL) {
3069 		return PLDM_ERROR_INVALID_DATA;
3070 	}
3071 
3072 	if (payload_length != PLDM_CANCEL_UPDATE_REQ_BYTES) {
3073 		return PLDM_ERROR_INVALID_LENGTH;
3074 	}
3075 
3076 	struct pldm_header_info header = { 0 };
3077 	header.instance = instance_id;
3078 	header.msg_type = PLDM_REQUEST;
3079 	header.pldm_type = PLDM_FWUP;
3080 	header.command = PLDM_CANCEL_UPDATE;
3081 	uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
3082 	if (rc) {
3083 		return rc;
3084 	}
3085 
3086 	return PLDM_SUCCESS;
3087 }
3088 
3089 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)3090 int decode_cancel_update_resp(const struct pldm_msg *msg, size_t payload_length,
3091 			      uint8_t *completion_code,
3092 			      bool8_t *non_functioning_component_indication,
3093 			      bitfield64_t *non_functioning_component_bitmap)
3094 {
3095 	if (msg == NULL || completion_code == NULL ||
3096 	    non_functioning_component_indication == NULL ||
3097 	    non_functioning_component_bitmap == NULL || !payload_length) {
3098 		return PLDM_ERROR_INVALID_DATA;
3099 	}
3100 
3101 	*completion_code = msg->payload[0];
3102 	if (*completion_code != PLDM_SUCCESS) {
3103 		return PLDM_SUCCESS;
3104 	}
3105 
3106 	if (payload_length != sizeof(struct pldm_cancel_update_resp)) {
3107 		return PLDM_ERROR_INVALID_LENGTH;
3108 	}
3109 	struct pldm_cancel_update_resp *response =
3110 		(struct pldm_cancel_update_resp *)msg->payload;
3111 
3112 	if (!is_non_functioning_component_indication_valid(
3113 		    response->non_functioning_component_indication)) {
3114 		return PLDM_ERROR_INVALID_DATA;
3115 	}
3116 
3117 	*non_functioning_component_indication =
3118 		response->non_functioning_component_indication;
3119 
3120 	if (*non_functioning_component_indication) {
3121 		non_functioning_component_bitmap->value =
3122 			le64toh(response->non_functioning_component_bitmap);
3123 	}
3124 
3125 	return PLDM_SUCCESS;
3126 }
3127 
3128 LIBPLDM_ABI_TESTING
encode_cancel_update_resp(uint8_t instance_id,const struct pldm_cancel_update_resp * resp_data,struct pldm_msg * msg,size_t * payload_length)3129 int encode_cancel_update_resp(uint8_t instance_id,
3130 			      const struct pldm_cancel_update_resp *resp_data,
3131 			      struct pldm_msg *msg, size_t *payload_length)
3132 {
3133 	PLDM_MSGBUF_DEFINE_P(buf);
3134 	int rc;
3135 
3136 	if (msg == NULL || payload_length == NULL) {
3137 		return -EINVAL;
3138 	}
3139 
3140 	rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
3141 				     PLDM_CANCEL_UPDATE, msg);
3142 	if (rc) {
3143 		return -EINVAL;
3144 	}
3145 
3146 	rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
3147 	if (rc) {
3148 		return rc;
3149 	}
3150 
3151 	pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
3152 	pldm_msgbuf_insert(buf,
3153 			   resp_data->non_functioning_component_indication);
3154 	pldm_msgbuf_insert(buf, resp_data->non_functioning_component_bitmap);
3155 
3156 	return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
3157 }
3158 
3159 LIBPLDM_ABI_TESTING
decode_pldm_firmware_update_package(const void * data,size_t length,const struct pldm_package_format_pin * pin,pldm_package_header_information_pad * hdr,struct pldm_package_iter * iter)3160 int decode_pldm_firmware_update_package(
3161 	const void *data, size_t length,
3162 	const struct pldm_package_format_pin *pin,
3163 	pldm_package_header_information_pad *hdr,
3164 	struct pldm_package_iter *iter)
3165 {
3166 	if (!data || !pin || !hdr || !iter) {
3167 		return -EINVAL;
3168 	}
3169 
3170 	iter->hdr = hdr;
3171 
3172 	return decode_pldm_package_header_info_errno(data, length, pin, hdr);
3173 }
3174 
3175 LIBPLDM_ABI_TESTING
pldm_package_firmware_device_id_record_iter_init(const pldm_package_header_information_pad * hdr,struct pldm_package_firmware_device_id_record_iter * iter)3176 int pldm_package_firmware_device_id_record_iter_init(
3177 	const pldm_package_header_information_pad *hdr,
3178 	struct pldm_package_firmware_device_id_record_iter *iter)
3179 {
3180 	PLDM_MSGBUF_DEFINE_P(buf);
3181 	int rc;
3182 
3183 	if (!hdr || !iter || !hdr->areas.ptr) {
3184 		return -EINVAL;
3185 	}
3186 
3187 	iter->field = hdr->areas;
3188 
3189 	/* Extract the fd record id count */
3190 	rc = pldm_msgbuf_init_errno(buf, 1, iter->field.ptr,
3191 				    iter->field.length);
3192 	if (rc) {
3193 		return rc;
3194 	}
3195 
3196 	pldm_msgbuf_extract_uint8_to_size(buf, iter->entries);
3197 	pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
3198 				   &iter->field.length);
3199 
3200 	return pldm_msgbuf_complete(buf);
3201 }
3202 
3203 LIBPLDM_ABI_TESTING
decode_pldm_package_firmware_device_id_record_from_iter(const pldm_package_header_information_pad * hdr,struct pldm_package_firmware_device_id_record_iter * iter,struct pldm_package_firmware_device_id_record * rec)3204 int decode_pldm_package_firmware_device_id_record_from_iter(
3205 	const pldm_package_header_information_pad *hdr,
3206 	struct pldm_package_firmware_device_id_record_iter *iter,
3207 	struct pldm_package_firmware_device_id_record *rec)
3208 {
3209 	return decode_pldm_package_firmware_device_id_record_errno(
3210 		hdr, &iter->field, rec);
3211 }
3212 
3213 LIBPLDM_ABI_TESTING
pldm_package_downstream_device_id_record_iter_init(const pldm_package_header_information_pad * hdr,struct pldm_package_firmware_device_id_record_iter * fds,struct pldm_package_downstream_device_id_record_iter * dds)3214 int pldm_package_downstream_device_id_record_iter_init(
3215 	const pldm_package_header_information_pad *hdr,
3216 	struct pldm_package_firmware_device_id_record_iter *fds,
3217 	struct pldm_package_downstream_device_id_record_iter *dds)
3218 {
3219 	PLDM_MSGBUF_DEFINE_P(buf);
3220 	int rc;
3221 
3222 	if (!hdr || !fds || !dds || !fds->field.ptr) {
3223 		return -EINVAL;
3224 	}
3225 
3226 	dds->field = fds->field;
3227 	fds->field.ptr = NULL;
3228 	fds->field.length = 0;
3229 
3230 	/* Downstream device ID records aren't specified in revision 1 */
3231 	if (hdr->package_header_format_revision <
3232 	    PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR02H) {
3233 		dds->entries = 0;
3234 		return 0;
3235 	}
3236 
3237 	/* Extract the dd record id count */
3238 	rc = pldm_msgbuf_init_errno(buf, 1, dds->field.ptr, dds->field.length);
3239 	if (rc) {
3240 		return rc;
3241 	}
3242 
3243 	pldm_msgbuf_extract_uint8_to_size(buf, dds->entries);
3244 	pldm_msgbuf_span_remaining(buf, (void **)&dds->field.ptr,
3245 				   &dds->field.length);
3246 
3247 	return pldm_msgbuf_complete(buf);
3248 }
3249 
3250 #define PLDM_FWUP_DOWNSTREAM_DEVICE_ID_RECORD_MIN_SIZE 11
3251 LIBPLDM_ABI_TESTING
decode_pldm_package_downstream_device_id_record_from_iter(const pldm_package_header_information_pad * hdr,struct pldm_package_downstream_device_id_record_iter * iter,struct pldm_package_downstream_device_id_record * rec)3252 int decode_pldm_package_downstream_device_id_record_from_iter(
3253 	const pldm_package_header_information_pad *hdr,
3254 	struct pldm_package_downstream_device_id_record_iter *iter,
3255 	struct pldm_package_downstream_device_id_record *rec)
3256 {
3257 	PLDM_MSGBUF_DEFINE_P(buf);
3258 	uint16_t record_len = 0;
3259 	int rc;
3260 
3261 	if (!hdr || !iter || !rec || !iter->field.ptr) {
3262 		return -EINVAL;
3263 	}
3264 
3265 	if (hdr->package_header_format_revision <
3266 	    PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR02H) {
3267 		/* Should not be reached due to corresponding test in iter initialisation */
3268 		return -ENOTSUP;
3269 	}
3270 
3271 	if (hdr->component_bitmap_bit_length & 7) {
3272 		return -EPROTO;
3273 	}
3274 
3275 	rc = pldm_msgbuf_init_dynamic_uint16(
3276 		buf, PLDM_FWUP_DOWNSTREAM_DEVICE_ID_RECORD_MIN_SIZE,
3277 		(void *)iter->field.ptr, iter->field.length,
3278 		(void **)&iter->field.ptr, &iter->field.length);
3279 	if (rc) {
3280 		return pldm_msgbuf_discard(buf, rc);
3281 	}
3282 
3283 	pldm_msgbuf_extract(buf, record_len);
3284 	pldm_msgbuf_extract(buf, rec->descriptor_count);
3285 
3286 	rc = pldm_msgbuf_extract(buf, rec->update_option_flags.value);
3287 	if (rc) {
3288 		return pldm_msgbuf_discard(buf, rc);
3289 	}
3290 
3291 	rc = pldm_msgbuf_extract(
3292 		buf, rec->self_contained_activation_min_version_string_type);
3293 	if (rc) {
3294 		return pldm_msgbuf_discard(buf, rc);
3295 	}
3296 	if (!is_string_type_valid(
3297 		    rec->self_contained_activation_min_version_string_type)) {
3298 		return pldm_msgbuf_discard(buf, -EPROTO);
3299 	}
3300 
3301 	rc = pldm_msgbuf_extract_uint8_to_size(
3302 		buf, rec->self_contained_activation_min_version_string.length);
3303 	if (rc) {
3304 		return pldm_msgbuf_discard(buf, rc);
3305 	}
3306 
3307 	rc = pldm_msgbuf_extract_uint16_to_size(buf, rec->package_data.length);
3308 	if (rc) {
3309 		return pldm_msgbuf_discard(buf, rc);
3310 	}
3311 
3312 	rc = pldm_msgbuf_span_required(
3313 		buf, hdr->component_bitmap_bit_length / 8,
3314 		(void **)&rec->applicable_components.bitmap.ptr);
3315 	if (rc) {
3316 		return pldm_msgbuf_discard(buf, rc);
3317 	}
3318 	rec->applicable_components.bitmap.length =
3319 		hdr->component_bitmap_bit_length / 8;
3320 
3321 	pldm_msgbuf_span_required(
3322 		buf, rec->self_contained_activation_min_version_string.length,
3323 		(void **)&rec->self_contained_activation_min_version_string.ptr);
3324 	if (rec->update_option_flags.bits.bit0) {
3325 		pldm_msgbuf_extract(
3326 			buf,
3327 			rec->self_contained_activation_min_version_comparison_stamp);
3328 	} else {
3329 		rec->self_contained_activation_min_version_comparison_stamp = 0;
3330 	}
3331 
3332 	pldm_msgbuf_span_until(buf, rec->package_data.length,
3333 			       (void **)&rec->record_descriptors.ptr,
3334 			       &rec->record_descriptors.length);
3335 
3336 	pldm_msgbuf_span_required(buf, rec->package_data.length,
3337 				  (void **)&rec->package_data.ptr);
3338 
3339 	return pldm_msgbuf_complete_consumed(buf);
3340 }
3341 
3342 LIBPLDM_ABI_TESTING
pldm_package_component_image_information_iter_init(const pldm_package_header_information_pad * hdr LIBPLDM_CC_UNUSED,struct pldm_package_downstream_device_id_record_iter * dds,struct pldm_package_component_image_information_iter * infos)3343 int pldm_package_component_image_information_iter_init(
3344 	const pldm_package_header_information_pad *hdr LIBPLDM_CC_UNUSED,
3345 	struct pldm_package_downstream_device_id_record_iter *dds,
3346 	struct pldm_package_component_image_information_iter *infos)
3347 {
3348 	uint16_t component_image_count;
3349 	PLDM_MSGBUF_DEFINE_P(buf);
3350 	int rc;
3351 
3352 	if (!dds || !infos) {
3353 		return -EINVAL;
3354 	}
3355 
3356 	infos->field = dds->field;
3357 	dds->field.ptr = NULL;
3358 	dds->field.length = 0;
3359 
3360 	/* Extract the component image count */
3361 	rc = pldm_msgbuf_init_errno(buf, 1, infos->field.ptr,
3362 				    infos->field.length);
3363 	if (rc) {
3364 		return rc;
3365 	}
3366 
3367 	rc = pldm_msgbuf_extract(buf, component_image_count);
3368 	if (rc) {
3369 		return pldm_msgbuf_discard(buf, rc);
3370 	}
3371 	infos->entries = component_image_count;
3372 
3373 	pldm_msgbuf_span_remaining(buf, (void **)&infos->field.ptr,
3374 				   &infos->field.length);
3375 
3376 	return pldm_msgbuf_complete(buf);
3377 }
3378 
3379 #define PLDM_FWUP_COMPONENT_IMAGE_INFORMATION_MIN_SIZE 22
3380 LIBPLDM_ABI_TESTING
decode_pldm_package_component_image_information_from_iter(const pldm_package_header_information_pad * hdr,struct pldm_package_component_image_information_iter * iter,struct pldm_package_component_image_information * info)3381 int decode_pldm_package_component_image_information_from_iter(
3382 	const pldm_package_header_information_pad *hdr,
3383 	struct pldm_package_component_image_information_iter *iter,
3384 	struct pldm_package_component_image_information *info)
3385 {
3386 	uint32_t component_location_offset = 0;
3387 	uint32_t component_size = 0;
3388 	PLDM_MSGBUF_DEFINE_P(buf);
3389 	int rc;
3390 
3391 	if (!hdr || !iter || !info || !iter->field.ptr) {
3392 		return -EINVAL;
3393 	}
3394 
3395 	if (hdr->component_bitmap_bit_length & 7) {
3396 		return -EPROTO;
3397 	}
3398 
3399 	rc = pldm_msgbuf_init_errno(
3400 		buf, PLDM_FWUP_COMPONENT_IMAGE_INFORMATION_MIN_SIZE,
3401 		iter->field.ptr, iter->field.length);
3402 	if (rc) {
3403 		return rc;
3404 	}
3405 
3406 	pldm_msgbuf_extract(buf, info->component_classification);
3407 	pldm_msgbuf_extract(buf, info->component_identifier);
3408 	pldm_msgbuf_extract(buf, info->component_comparison_stamp);
3409 	pldm_msgbuf_extract(buf, info->component_options.value);
3410 	pldm_msgbuf_extract(buf,
3411 			    info->requested_component_activation_method.value);
3412 	pldm_msgbuf_extract(buf, component_location_offset);
3413 	pldm_msgbuf_extract(buf, component_size);
3414 
3415 	rc = pldm_msgbuf_extract(buf, info->component_version_string_type);
3416 	if (rc) {
3417 		return pldm_msgbuf_discard(buf, rc);
3418 	}
3419 	if (!is_string_type_valid(info->component_version_string_type)) {
3420 		return pldm_msgbuf_discard(buf, -EPROTO);
3421 	}
3422 
3423 	rc = pldm_msgbuf_extract_uint8_to_size(
3424 		buf, info->component_version_string.length);
3425 	if (rc) {
3426 		return pldm_msgbuf_discard(buf, rc);
3427 	}
3428 
3429 	pldm_msgbuf_span_required(buf, info->component_version_string.length,
3430 				  (void **)&info->component_version_string.ptr);
3431 
3432 	pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
3433 				   &iter->field.length);
3434 
3435 	rc = pldm_msgbuf_complete_consumed(buf);
3436 	if (rc) {
3437 		return rc;
3438 	}
3439 
3440 	if (info->component_classification > 0x000d &&
3441 	    info->component_classification < 0x8000) {
3442 		return -EPROTO;
3443 	}
3444 
3445 	/* Resolve the component image in memory */
3446 	rc = pldm_msgbuf_init_errno(buf, 0, hdr->package.ptr,
3447 				    hdr->package.length);
3448 	if (rc) {
3449 		return rc;
3450 	}
3451 
3452 	pldm_msgbuf_span_required(buf, component_location_offset, NULL);
3453 	pldm_msgbuf_span_required(buf, component_size,
3454 				  (void **)&info->component_image.ptr);
3455 
3456 	rc = pldm_msgbuf_complete(buf);
3457 	if (rc) {
3458 		return rc;
3459 	}
3460 
3461 	info->component_image.length = component_size;
3462 
3463 	return 0;
3464 }
3465