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