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