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