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