blob: a074472322593170eb570a73c56991f8eec44a4f [file] [log] [blame]
Patrick Williams691668f2023-11-01 08:19:10 -05001/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09302#include "api.h"
Andrew Jeffery2613c272025-03-12 14:15:41 +10303#include "array.h"
4#include "compiler.h"
Chris Wangb6ef35b2024-07-03 09:35:42 +08005#include "dsp/base.h"
Chris Wang4c1f2c72024-03-21 17:09:44 +08006#include "msgbuf.h"
Andrew Jefferybacbbac2025-03-12 04:02:18 +00007#include <libpldm/base.h>
Andrew Jeffery2613c272025-03-12 14:15:41 +10308#include <libpldm/compiler.h>
Andrew Jefferyb0c1d202023-11-07 22:08:44 +10309#include <libpldm/firmware_update.h>
10#include <libpldm/utils.h>
11
Andrew Jeffery9c766792022-08-10 23:12:49 +093012#include <endian.h>
Manojkiran Eda9a8e4972022-11-28 16:38:21 +053013#include <stdbool.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +093014#include <string.h>
15
Matt Johnstoncf9a2df2024-11-07 15:29:29 +080016static_assert(PLDM_FIRMWARE_MAX_STRING <= UINT8_MAX, "too large");
17
Andrew Jeffery9c766792022-08-10 23:12:49 +093018/** @brief Check whether string type value is valid
19 *
20 * @return true if string type value is valid, false if not
21 */
22static bool is_string_type_valid(uint8_t string_type)
23{
24 switch (string_type) {
25 case PLDM_STR_TYPE_UNKNOWN:
26 return false;
27 case PLDM_STR_TYPE_ASCII:
28 case PLDM_STR_TYPE_UTF_8:
29 case PLDM_STR_TYPE_UTF_16:
30 case PLDM_STR_TYPE_UTF_16LE:
31 case PLDM_STR_TYPE_UTF_16BE:
32 return true;
33 default:
34 return false;
35 }
36}
37
38/** @brief Return the length of the descriptor type described in firmware update
39 * specification
40 *
41 * @return length of the descriptor type if descriptor type is valid else
42 * return 0
43 */
44static uint16_t get_descriptor_type_length(uint16_t descriptor_type)
45{
46 switch (descriptor_type) {
Andrew Jeffery9c766792022-08-10 23:12:49 +093047 case PLDM_FWUP_PCI_VENDOR_ID:
48 return PLDM_FWUP_PCI_VENDOR_ID_LENGTH;
49 case PLDM_FWUP_IANA_ENTERPRISE_ID:
50 return PLDM_FWUP_IANA_ENTERPRISE_ID_LENGTH;
51 case PLDM_FWUP_UUID:
52 return PLDM_FWUP_UUID_LENGTH;
53 case PLDM_FWUP_PNP_VENDOR_ID:
54 return PLDM_FWUP_PNP_VENDOR_ID_LENGTH;
55 case PLDM_FWUP_ACPI_VENDOR_ID:
56 return PLDM_FWUP_ACPI_VENDOR_ID_LENGTH;
57 case PLDM_FWUP_IEEE_ASSIGNED_COMPANY_ID:
58 return PLDM_FWUP_IEEE_ASSIGNED_COMPANY_ID_LENGTH;
59 case PLDM_FWUP_SCSI_VENDOR_ID:
60 return PLDM_FWUP_SCSI_VENDOR_ID_LENGTH;
61 case PLDM_FWUP_PCI_DEVICE_ID:
62 return PLDM_FWUP_PCI_DEVICE_ID_LENGTH;
63 case PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID:
64 return PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID_LENGTH;
65 case PLDM_FWUP_PCI_SUBSYSTEM_ID:
66 return PLDM_FWUP_PCI_SUBSYSTEM_ID_LENGTH;
67 case PLDM_FWUP_PCI_REVISION_ID:
68 return PLDM_FWUP_PCI_REVISION_ID_LENGTH;
69 case PLDM_FWUP_PNP_PRODUCT_IDENTIFIER:
70 return PLDM_FWUP_PNP_PRODUCT_IDENTIFIER_LENGTH;
71 case PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER:
72 return PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER_LENGTH;
73 case PLDM_FWUP_ASCII_MODEL_NUMBER_LONG_STRING:
74 return PLDM_FWUP_ASCII_MODEL_NUMBER_LONG_STRING_LENGTH;
75 case PLDM_FWUP_ASCII_MODEL_NUMBER_SHORT_STRING:
76 return PLDM_FWUP_ASCII_MODEL_NUMBER_SHORT_STRING_LENGTH;
77 case PLDM_FWUP_SCSI_PRODUCT_ID:
78 return PLDM_FWUP_SCSI_PRODUCT_ID_LENGTH;
79 case PLDM_FWUP_UBM_CONTROLLER_DEVICE_CODE:
80 return PLDM_FWUP_UBM_CONTROLLER_DEVICE_CODE_LENGTH;
81 default:
82 return 0;
83 }
84}
85
Chris Wang4c1f2c72024-03-21 17:09:44 +080086static bool is_downstream_device_update_support_valid(uint8_t resp)
87{
88 switch (resp) {
89 case PLDM_FWUP_DOWNSTREAM_DEVICE_UPDATE_NOT_SUPPORTED:
90 case PLDM_FWUP_DOWNSTREAM_DEVICE_UPDATE_SUPPORTED:
91 return true;
92 default:
93 return false;
94 }
95}
96
Chris Wang458475a2024-03-26 17:59:19 +080097static bool
98is_transfer_operation_flag_valid(enum transfer_op_flag transfer_op_flag)
99{
100 switch (transfer_op_flag) {
101 case PLDM_GET_NEXTPART:
102 case PLDM_GET_FIRSTPART:
103 return true;
104 default:
105 return false;
106 }
107}
108
Andrew Jeffery9c766792022-08-10 23:12:49 +0930109/** @brief Check whether ComponentResponse is valid
110 *
111 * @return true if ComponentResponse is valid, false if not
112 */
113static bool is_comp_resp_valid(uint8_t comp_resp)
114{
115 switch (comp_resp) {
116 case PLDM_CR_COMP_CAN_BE_UPDATED:
117 case PLDM_CR_COMP_MAY_BE_UPDATEABLE:
118 return true;
119
120 default:
121 return false;
122 }
123}
124
125/** @brief Check whether ComponentResponseCode is valid
126 *
127 * @return true if ComponentResponseCode is valid, false if not
128 */
129static bool is_comp_resp_code_valid(uint8_t comp_resp_code)
130{
131 switch (comp_resp_code) {
132 case PLDM_CRC_COMP_CAN_BE_UPDATED:
133 case PLDM_CRC_COMP_COMPARISON_STAMP_IDENTICAL:
134 case PLDM_CRC_COMP_COMPARISON_STAMP_LOWER:
135 case PLDM_CRC_INVALID_COMP_COMPARISON_STAMP:
136 case PLDM_CRC_COMP_CONFLICT:
137 case PLDM_CRC_COMP_PREREQUISITES_NOT_MET:
138 case PLDM_CRC_COMP_NOT_SUPPORTED:
139 case PLDM_CRC_COMP_SECURITY_RESTRICTIONS:
140 case PLDM_CRC_INCOMPLETE_COMP_IMAGE_SET:
141 case PLDM_CRC_ACTIVE_IMAGE_NOT_UPDATEABLE_SUBSEQUENTLY:
142 case PLDM_CRC_COMP_VER_STR_IDENTICAL:
143 case PLDM_CRC_COMP_VER_STR_LOWER:
144 return true;
145
146 default:
147 if (comp_resp_code >=
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930148 PLDM_CRC_VENDOR_COMP_RESP_CODE_RANGE_MIN &&
Andrew Jeffery9c766792022-08-10 23:12:49 +0930149 comp_resp_code <=
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930150 PLDM_CRC_VENDOR_COMP_RESP_CODE_RANGE_MAX) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930151 return true;
152 }
153 return false;
154 }
155}
156
157/** @brief Check whether ComponentCompatibilityResponse is valid
158 *
159 * @return true if ComponentCompatibilityResponse is valid, false if not
160 */
161static bool is_comp_compatibility_resp_valid(uint8_t comp_compatibility_resp)
162{
163 switch (comp_compatibility_resp) {
164 case PLDM_CCR_COMP_CAN_BE_UPDATED:
165 case PLDM_CCR_COMP_CANNOT_BE_UPDATED:
166 return true;
167
168 default:
169 return false;
170 }
171}
172
173/** @brief Check whether ComponentCompatibilityResponse Code is valid
174 *
175 * @return true if ComponentCompatibilityResponse Code is valid, false if not
176 */
177static bool
178is_comp_compatibility_resp_code_valid(uint8_t comp_compatibility_resp_code)
179{
180 switch (comp_compatibility_resp_code) {
181 case PLDM_CCRC_NO_RESPONSE_CODE:
182 case PLDM_CCRC_COMP_COMPARISON_STAMP_IDENTICAL:
183 case PLDM_CCRC_COMP_COMPARISON_STAMP_LOWER:
184 case PLDM_CCRC_INVALID_COMP_COMPARISON_STAMP:
185 case PLDM_CCRC_COMP_CONFLICT:
186 case PLDM_CCRC_COMP_PREREQUISITES_NOT_MET:
187 case PLDM_CCRC_COMP_NOT_SUPPORTED:
188 case PLDM_CCRC_COMP_SECURITY_RESTRICTIONS:
189 case PLDM_CRC_INCOMPLETE_COMP_IMAGE_SET:
190 case PLDM_CCRC_COMP_INFO_NO_MATCH:
191 case PLDM_CCRC_COMP_VER_STR_IDENTICAL:
192 case PLDM_CCRC_COMP_VER_STR_LOWER:
193 return true;
194
195 default:
196 if (comp_compatibility_resp_code >=
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930197 PLDM_CCRC_VENDOR_COMP_RESP_CODE_RANGE_MIN &&
Andrew Jeffery9c766792022-08-10 23:12:49 +0930198 comp_compatibility_resp_code <=
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930199 PLDM_CCRC_VENDOR_COMP_RESP_CODE_RANGE_MAX) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930200 return true;
201 }
202 return false;
203 }
204}
205
206/** @brief Check whether SelfContainedActivationRequest is valid
207 *
208 * @return true if SelfContainedActivationRequest is valid, false if not
209 */
210static bool
211is_self_contained_activation_req_valid(bool8_t self_contained_activation_req)
212{
213 switch (self_contained_activation_req) {
214 case PLDM_NOT_ACTIVATE_SELF_CONTAINED_COMPONENTS:
215 case PLDM_ACTIVATE_SELF_CONTAINED_COMPONENTS:
216 return true;
217
218 default:
219 return false;
220 }
221}
222
223/** @brief Check if current or previous status in GetStatus command response is
224 * valid
225 *
226 * @param[in] state - current or previous different state machine state of
227 * the FD
228 * @return true if state is valid, false if not
229 */
230static bool is_state_valid(uint8_t state)
231{
232 switch (state) {
233 case PLDM_FD_STATE_IDLE:
234 case PLDM_FD_STATE_LEARN_COMPONENTS:
235 case PLDM_FD_STATE_READY_XFER:
236 case PLDM_FD_STATE_DOWNLOAD:
237 case PLDM_FD_STATE_VERIFY:
238 case PLDM_FD_STATE_APPLY:
239 case PLDM_FD_STATE_ACTIVATE:
240 return true;
241
242 default:
243 return false;
244 }
245}
246
247/** @brief Check if aux state in GetStatus command response is valid
248 *
249 * @param[in] aux_state - provides additional information to the UA to describe
250 * the current operation state of the FD/FDP
251 *
252 * @return true if aux state is valid, false if not
253 */
254static bool is_aux_state_valid(uint8_t aux_state)
255{
256 switch (aux_state) {
257 case PLDM_FD_OPERATION_IN_PROGRESS:
258 case PLDM_FD_OPERATION_SUCCESSFUL:
259 case PLDM_FD_OPERATION_FAILED:
260 case PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER:
261 return true;
262
263 default:
264 return false;
265 }
266}
267
268/** @brief Check if aux state status in GetStatus command response is valid
269 *
270 * @param[in] aux_state_status - aux state status
271 *
272 * @return true if aux state status is valid, false if not
273 */
274static bool is_aux_state_status_valid(uint8_t aux_state_status)
275{
276 if (aux_state_status == PLDM_FD_AUX_STATE_IN_PROGRESS_OR_SUCCESS ||
277 aux_state_status == PLDM_FD_TIMEOUT ||
Andrew Jeffery67f7ed92023-04-05 14:00:00 +0930278 aux_state_status == PLDM_FD_GENERIC_ERROR ||
279 (aux_state_status >= PLDM_FD_VENDOR_DEFINED_STATUS_CODE_START &&
280 aux_state_status <= PLDM_FD_VENDOR_DEFINED_STATUS_CODE_END)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930281 return true;
282 }
283
284 return false;
285}
286
287/** @brief Check if reason code in GetStatus command response is valid
288 *
289 * @param[in] reason_code - provides the reason for why the current state
290 * entered the IDLE state
291 *
292 * @return true if reason code is valid, false if not
293 */
294static bool is_reason_code_valid(uint8_t reason_code)
295{
Andrew Jeffery9c766792022-08-10 23:12:49 +0930296 switch (reason_code) {
297 case PLDM_FD_INITIALIZATION:
298 case PLDM_FD_ACTIVATE_FW:
299 case PLDM_FD_CANCEL_UPDATE:
300 case PLDM_FD_TIMEOUT_LEARN_COMPONENT:
301 case PLDM_FD_TIMEOUT_READY_XFER:
302 case PLDM_FD_TIMEOUT_DOWNLOAD:
303 case PLDM_FD_TIMEOUT_VERIFY:
304 case PLDM_FD_TIMEOUT_APPLY:
305 return true;
306
307 default:
308 if (reason_code >= PLDM_FD_STATUS_VENDOR_DEFINED_MIN) {
309 return true;
310 }
311 return false;
312 }
313}
314
315/** @brief Check if non functioning component indication in CancelUpdate
316 * response is valid
317 *
318 * @return true if non functioning component indication is valid, false if not
319 */
320static bool is_non_functioning_component_indication_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930321 bool8_t non_functioning_component_indication)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930322{
323 switch (non_functioning_component_indication) {
324 case PLDM_FWUP_COMPONENTS_FUNCTIONING:
325 case PLDM_FWUP_COMPONENTS_NOT_FUNCTIONING:
326 return true;
327
328 default:
329 return false;
330 }
331}
332
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030333#define PLDM_FWUP_PACKAGE_HEADER_FIXED_SIZE 36
Andrew Jeffery2613c272025-03-12 14:15:41 +1030334LIBPLDM_CC_NONNULL
335static int
336decode_pldm_package_header_info_errno(const void *data, size_t length,
337 const struct pldm_package_format_pin *pin,
338 pldm_package_header_information_pad *hdr)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930339{
Andrew Jeffery2613c272025-03-12 14:15:41 +1030340 static const struct pldm_package_header_format_revision_info {
341 pldm_uuid identifier;
342 size_t magic;
343 } revision_info[1 + PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR02H] = {
344 [0] = {
345 .identifier = {0},
346 .magic = 0,
347 },
348 [PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H] = { /* PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H */
349 .identifier = PLDM_PACKAGE_HEADER_IDENTIFIER_V1_0,
350 .magic =
351 LIBPLDM_SIZEAT(struct pldm__package_header_information, package) +
352 LIBPLDM_SIZEAT(struct pldm_package_firmware_device_id_record, firmware_device_package_data) +
353 LIBPLDM_SIZEAT(struct pldm_descriptor, descriptor_data) +
354 LIBPLDM_SIZEAT(struct pldm_package_component_image_information, component_version_string) +
355 LIBPLDM_SIZEAT(struct pldm_package_iter, infos)
356 },
357 [PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR02H] = { /* PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR02H */
358 .identifier = PLDM_PACKAGE_HEADER_IDENTIFIER_V1_1,
359 .magic =
360 LIBPLDM_SIZEAT(struct pldm__package_header_information, package) +
361 LIBPLDM_SIZEAT(struct pldm_package_firmware_device_id_record, firmware_device_package_data) +
362 LIBPLDM_SIZEAT(struct pldm_descriptor, descriptor_data) +
363 LIBPLDM_SIZEAT(struct pldm_package_downstream_device_id_record, package_data) +
364 LIBPLDM_SIZEAT(struct pldm_package_component_image_information, component_version_string) +
365 LIBPLDM_SIZEAT(struct pldm_package_iter, infos),
366 },
367 };
368
369 const struct pldm_package_header_format_revision_info *info;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030370 uint32_t package_header_checksum = 0;
371 size_t package_header_variable_size;
372 size_t package_header_payload_size;
373 size_t package_header_areas_size;
374 uint16_t package_header_size;
375 PLDM_MSGBUF_DEFINE_P(buf);
376 int checksums = 1;
377 int rc;
378
Andrew Jeffery2613c272025-03-12 14:15:41 +1030379 if (pin->meta.version > 0) {
380 return -ENOTSUP;
381 }
382
383 if (pin->format.revision == 0) {
384 return -EINVAL;
385 }
386
387 if (pin->format.revision > PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR02H) {
388 return -ENOTSUP;
389 }
390 static_assert(ARRAY_SIZE(revision_info) ==
391 1 + PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR02H,
392 "Mismatched array bounds test");
393
394 info = &revision_info[pin->format.revision];
395 if (memcmp(&pin->format.identifier, info->identifier,
396 sizeof(info->identifier)) != 0) {
397 return -ENOTSUP;
398 }
399
400 if (pin->meta.magic != info->magic) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030401 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930402 }
403
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030404 rc = pldm_msgbuf_init_errno(buf, PLDM_FWUP_PACKAGE_HEADER_FIXED_SIZE,
405 data, length);
406 if (rc) {
407 return rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930408 }
409
Andrew Jeffery2613c272025-03-12 14:15:41 +1030410 rc = pldm_msgbuf_extract_array(buf,
411 sizeof(hdr->package_header_identifier),
412 hdr->package_header_identifier,
413 sizeof(hdr->package_header_identifier));
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030414 if (rc) {
415 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930416 }
417
Andrew Jeffery2613c272025-03-12 14:15:41 +1030418 if (memcmp(revision_info[PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H]
419 .identifier,
420 hdr->package_header_identifier,
421 sizeof(hdr->package_header_identifier)) != 0 &&
422 memcmp(revision_info[PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR02H]
423 .identifier,
424 hdr->package_header_identifier,
425 sizeof(hdr->package_header_identifier)) != 0) {
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030426 return pldm_msgbuf_discard(buf, -ENOTSUP);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930427 }
428
Andrew Jeffery2613c272025-03-12 14:15:41 +1030429 rc = pldm_msgbuf_extract(buf, hdr->package_header_format_revision);
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030430 if (rc) {
431 return pldm_msgbuf_discard(buf, rc);
432 }
Andrew Jeffery2613c272025-03-12 14:15:41 +1030433 if (hdr->package_header_format_revision > pin->format.revision) {
434 return pldm_msgbuf_discard(buf, -ENOTSUP);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930435 }
436
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030437 rc = pldm_msgbuf_extract(buf, package_header_size);
438 if (rc) {
439 return pldm_msgbuf_discard(buf, rc);
440 }
441
Andrew Jeffery2613c272025-03-12 14:15:41 +1030442 rc = pldm_msgbuf_extract_array(buf,
443 sizeof(hdr->package_release_date_time),
444 hdr->package_release_date_time,
445 sizeof(hdr->package_release_date_time));
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030446 if (rc) {
447 return pldm_msgbuf_discard(buf, rc);
448 }
449
Andrew Jeffery2613c272025-03-12 14:15:41 +1030450 rc = pldm_msgbuf_extract(buf, hdr->component_bitmap_bit_length);
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030451 if (rc) {
452 return pldm_msgbuf_discard(buf, rc);
453 }
Andrew Jeffery2613c272025-03-12 14:15:41 +1030454 if (hdr->component_bitmap_bit_length & 7) {
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030455 return pldm_msgbuf_discard(buf, -EPROTO);
456 }
457
Andrew Jeffery2613c272025-03-12 14:15:41 +1030458 rc = pldm_msgbuf_extract(buf, hdr->package_version_string_type);
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030459 if (rc) {
460 return pldm_msgbuf_discard(buf, rc);
461 }
Andrew Jeffery2613c272025-03-12 14:15:41 +1030462 if (!is_string_type_valid(hdr->package_version_string_type)) {
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030463 return pldm_msgbuf_discard(buf, -EPROTO);
464 }
465
466 rc = pldm_msgbuf_extract_uint8_to_size(
Andrew Jeffery2613c272025-03-12 14:15:41 +1030467 buf, hdr->package_version_string.length);
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030468 if (rc) {
469 return pldm_msgbuf_discard(buf, rc);
470 }
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030471
Andrew Jeffery2613c272025-03-12 14:15:41 +1030472 pldm_msgbuf_span_required(buf, hdr->package_version_string.length,
473 (void **)&hdr->package_version_string.ptr);
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030474
475 if (package_header_size < (PLDM_FWUP_PACKAGE_HEADER_FIXED_SIZE + 3 +
476 checksums * sizeof(uint32_t))) {
Andrew Jeffery2613c272025-03-12 14:15:41 +1030477 return pldm_msgbuf_discard(buf, -EOVERFLOW);
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030478 }
479 package_header_payload_size =
480 package_header_size - (checksums * sizeof(uint32_t));
481 package_header_variable_size = package_header_payload_size -
482 PLDM_FWUP_PACKAGE_HEADER_FIXED_SIZE;
483
Andrew Jeffery2613c272025-03-12 14:15:41 +1030484 if (package_header_variable_size < hdr->package_version_string.length) {
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030485 return pldm_msgbuf_discard(buf, -EOVERFLOW);
486 }
487
488 package_header_areas_size = package_header_variable_size -
Andrew Jeffery2613c272025-03-12 14:15:41 +1030489 hdr->package_version_string.length;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030490 rc = pldm_msgbuf_span_required(buf, package_header_areas_size,
Andrew Jeffery2613c272025-03-12 14:15:41 +1030491 (void **)&hdr->areas.ptr);
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030492 if (rc) {
493 return pldm_msgbuf_discard(buf, rc);
494 }
Andrew Jeffery2613c272025-03-12 14:15:41 +1030495 hdr->areas.length = package_header_areas_size;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030496
497 pldm_msgbuf_extract(buf, package_header_checksum);
498
499 rc = pldm_msgbuf_complete(buf);
500 if (rc) {
501 return rc;
502 }
503
Andrew Jeffery2613c272025-03-12 14:15:41 +1030504 // TODO: pldm_edac_crc32_test(uint32_t expected, const void *data, size_t len)
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030505 if (package_header_checksum !=
Andrew Jeffery2613c272025-03-12 14:15:41 +1030506 pldm_edac_crc32(data, package_header_payload_size)) {
507#if 0
508 printf("checksum failure, expected: %#08" PRIx32 ", found: %#08" PRIx32 "\n", package_header_checksum, pldm_edac_crc32(data, package_header_payload_size));
509#endif
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030510 return -EUCLEAN;
511 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930512
Andrew Jeffery2613c272025-03-12 14:15:41 +1030513 /* We stash these to resolve component images later */
514 hdr->package.ptr = data;
515 hdr->package.length = length;
516
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030517 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930518}
519
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930520LIBPLDM_ABI_STABLE
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030521int decode_pldm_package_header_info(
522 const uint8_t *data, size_t length,
523 struct pldm_package_header_information *package_header_info,
524 struct variable_field *package_version_str)
525{
Andrew Jeffery2613c272025-03-12 14:15:41 +1030526 DEFINE_PLDM_PACKAGE_FORMAT_PIN_FR01H(pin);
527 pldm_package_header_information_pad hdr;
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030528 int rc;
529
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030530 if (!data || !package_header_info || !package_version_str) {
531 return PLDM_ERROR_INVALID_DATA;
532 }
533
Andrew Jeffery2613c272025-03-12 14:15:41 +1030534 rc = decode_pldm_package_header_info_errno(data, length, &pin, &hdr);
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030535 if (rc < 0) {
536 return pldm_xlate_errno(rc);
537 }
538
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030539 static_assert(sizeof(package_header_info->uuid) ==
Andrew Jeffery2613c272025-03-12 14:15:41 +1030540 sizeof(hdr.package_header_identifier),
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030541 "UUID field size");
Andrew Jeffery2613c272025-03-12 14:15:41 +1030542 memcpy(package_header_info->uuid, hdr.package_header_identifier,
543 sizeof(hdr.package_header_identifier));
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030544 package_header_info->package_header_format_version =
Andrew Jeffery2613c272025-03-12 14:15:41 +1030545 hdr.package_header_format_revision;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030546 memcpy(&package_header_info->package_header_size, data + 17,
547 sizeof(package_header_info->package_header_size));
548 LE16TOH(package_header_info->package_header_size);
549 static_assert(sizeof(package_header_info->package_release_date_time) ==
Andrew Jeffery2613c272025-03-12 14:15:41 +1030550 sizeof(hdr.package_release_date_time),
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030551 "TIMESTAMP104 field size");
552 memcpy(package_header_info->package_release_date_time,
Andrew Jeffery2613c272025-03-12 14:15:41 +1030553 hdr.package_release_date_time,
554 sizeof(hdr.package_release_date_time));
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030555 package_header_info->component_bitmap_bit_length =
Andrew Jeffery2613c272025-03-12 14:15:41 +1030556 hdr.component_bitmap_bit_length;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030557 package_header_info->package_version_string_type =
Andrew Jeffery2613c272025-03-12 14:15:41 +1030558 hdr.package_version_string_type;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030559 package_header_info->package_version_string_length =
Andrew Jeffery2613c272025-03-12 14:15:41 +1030560 hdr.package_version_string.length;
561 *package_version_str = hdr.package_version_string;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030562
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030563 return PLDM_SUCCESS;
564}
565
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000566/* Currently only used for decode_firmware_device_id_record_errno() */
567static int pldm_msgbuf_init_dynamic_uint16(struct pldm_msgbuf *buf, size_t req,
Andrew Jeffery2613c272025-03-12 14:15:41 +1030568 void *data, size_t len,
569 void **tail_data, size_t *tail_len)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930570{
Andrew Jeffery2613c272025-03-12 14:15:41 +1030571 size_t dyn_length;
572 void *dyn_start;
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000573 int rc;
574
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000575 rc = pldm_msgbuf_init_errno(buf, req, data, len);
576 if (rc) {
577 return rc;
578 }
Andrew Jeffery2613c272025-03-12 14:15:41 +1030579 /*
580 * Extract the record length from the first field, then reinitialise the msgbuf
581 * after determining that it's safe to do so
582 */
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000583
Andrew Jeffery2613c272025-03-12 14:15:41 +1030584 rc = pldm_msgbuf_extract_uint16_to_size(buf, dyn_length);
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000585 if (rc) {
586 return pldm_msgbuf_discard(buf, rc);
587 }
588
589 rc = pldm_msgbuf_complete(buf);
590 if (rc) {
591 return rc;
592 }
593
594 rc = pldm_msgbuf_init_errno(buf, req, data, len);
595 if (rc) {
596 return rc;
597 }
598
599 /* Ensure there's no arithmetic funkiness and the span is within buffer bounds */
Andrew Jeffery2613c272025-03-12 14:15:41 +1030600 rc = pldm_msgbuf_span_required(buf, dyn_length, &dyn_start);
601 if (rc) {
602 return pldm_msgbuf_discard(buf, rc);
603 }
604
605 rc = pldm_msgbuf_span_remaining(buf, tail_data, tail_len);
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000606 if (rc) {
607 return pldm_msgbuf_discard(buf, rc);
608 }
609
610 rc = pldm_msgbuf_complete(buf);
611 if (rc) {
612 return rc;
613 }
614
Andrew Jeffery2613c272025-03-12 14:15:41 +1030615 return pldm_msgbuf_init_errno(buf, req, dyn_start, dyn_length);
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000616}
617
618#define PLDM_FWUP_FIRMWARE_DEVICE_ID_RECORD_MIN_SIZE 11
Andrew Jeffery2613c272025-03-12 14:15:41 +1030619static int decode_pldm_package_firmware_device_id_record_errno(
620 const pldm_package_header_information_pad *hdr,
621 struct variable_field *field,
622 struct pldm_package_firmware_device_id_record *rec)
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000623{
624 PLDM_MSGBUF_DEFINE_P(buf);
625 uint16_t record_len = 0;
626 int rc;
627
Andrew Jeffery2613c272025-03-12 14:15:41 +1030628 if (!hdr || !field || !rec || !field->ptr) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030629 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930630 }
631
Andrew Jeffery2613c272025-03-12 14:15:41 +1030632 if (hdr->component_bitmap_bit_length & 7) {
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000633 return -EPROTO;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930634 }
635
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000636 rc = pldm_msgbuf_init_dynamic_uint16(
Andrew Jeffery2613c272025-03-12 14:15:41 +1030637 buf, PLDM_FWUP_FIRMWARE_DEVICE_ID_RECORD_MIN_SIZE,
638 (void *)field->ptr, field->length, (void **)&field->ptr,
639 &field->length);
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000640 if (rc) {
641 return rc;
642 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930643
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000644 pldm_msgbuf_extract(buf, record_len);
645 pldm_msgbuf_extract(buf, rec->descriptor_count);
646 pldm_msgbuf_extract(buf, rec->device_update_option_flags.value);
647
648 rc = pldm_msgbuf_extract(buf,
649 rec->component_image_set_version_string_type);
650 if (rc) {
651 return pldm_msgbuf_discard(buf, rc);
652 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930653 if (!is_string_type_valid(
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000654 rec->component_image_set_version_string_type)) {
655 return pldm_msgbuf_discard(buf, -EPROTO);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930656 }
657
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000658 rc = pldm_msgbuf_extract_uint8_to_size(
659 buf, rec->component_image_set_version_string.length);
660 if (rc) {
661 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930662 }
663
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000664 if (rec->component_image_set_version_string.length == 0) {
665 return pldm_msgbuf_discard(buf, -EPROTO);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930666 }
667
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000668 rc = pldm_msgbuf_extract_uint16_to_size(
669 buf, rec->firmware_device_package_data.length);
670 if (rc) {
671 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930672 }
673
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000674 rc = pldm_msgbuf_span_required(
Andrew Jeffery2613c272025-03-12 14:15:41 +1030675 buf, hdr->component_bitmap_bit_length / 8,
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000676 (void **)&rec->applicable_components.bitmap.ptr);
677 if (rc) {
678 return pldm_msgbuf_discard(buf, rc);
679 }
680 rec->applicable_components.bitmap.length =
Andrew Jeffery2613c272025-03-12 14:15:41 +1030681 hdr->component_bitmap_bit_length / 8;
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000682
683 pldm_msgbuf_span_required(
684 buf, rec->component_image_set_version_string.length,
685 (void **)&rec->component_image_set_version_string.ptr);
686
687 pldm_msgbuf_span_until(buf, rec->firmware_device_package_data.length,
688 (void **)&rec->record_descriptors.ptr,
689 &rec->record_descriptors.length);
690
691 pldm_msgbuf_span_required(
692 buf, rec->firmware_device_package_data.length,
693 (void **)&rec->firmware_device_package_data.ptr);
694 if (!rec->firmware_device_package_data.length) {
695 rec->firmware_device_package_data.ptr = NULL;
696 }
697
698 return pldm_msgbuf_complete_consumed(buf);
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030699}
700
701LIBPLDM_ABI_STABLE
702int decode_firmware_device_id_record(
703 const uint8_t *data, size_t length,
704 uint16_t component_bitmap_bit_length,
705 struct pldm_firmware_device_id_record *fw_device_id_record,
706 struct variable_field *applicable_components,
707 struct variable_field *comp_image_set_version_str,
708 struct variable_field *record_descriptors,
709 struct variable_field *fw_device_pkg_data)
710{
Andrew Jeffery2613c272025-03-12 14:15:41 +1030711 struct pldm_package_firmware_device_id_record rec;
712 pldm_package_header_information_pad hdr;
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030713 int rc;
714
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000715 if (!data || !fw_device_id_record || !applicable_components ||
716 !comp_image_set_version_str || !record_descriptors ||
717 !fw_device_pkg_data) {
718 return PLDM_ERROR_INVALID_DATA;
719 }
720
Andrew Jeffery2613c272025-03-12 14:15:41 +1030721 hdr.package_header_format_revision =
722 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H;
723 hdr.component_bitmap_bit_length = component_bitmap_bit_length;
724
725 rc = decode_pldm_package_firmware_device_id_record_errno(
726 &hdr, &(struct variable_field){ data, length }, &rec);
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030727 if (rc < 0) {
728 return pldm_xlate_errno(rc);
729 }
730
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000731 memcpy(&fw_device_id_record->record_length, data,
732 sizeof(fw_device_id_record->record_length));
733 LE16TOH(fw_device_id_record->record_length);
734 fw_device_id_record->descriptor_count = rec.descriptor_count;
735 fw_device_id_record->device_update_option_flags =
736 rec.device_update_option_flags;
737 fw_device_id_record->comp_image_set_version_string_type =
738 rec.component_image_set_version_string_type;
739 fw_device_id_record->comp_image_set_version_string_length =
740 rec.component_image_set_version_string.length;
741 fw_device_id_record->fw_device_pkg_data_length =
742 rec.firmware_device_package_data.length;
743 *applicable_components = rec.applicable_components.bitmap;
744 *comp_image_set_version_str = rec.component_image_set_version_string;
745 *record_descriptors = rec.record_descriptors;
746 *fw_device_pkg_data = rec.firmware_device_package_data;
747
Andrew Jeffery9c766792022-08-10 23:12:49 +0930748 return PLDM_SUCCESS;
749}
750
Unive Tiene5c3f142024-12-13 14:14:19 +0800751LIBPLDM_ABI_STABLE
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030752int decode_pldm_descriptor_from_iter(struct pldm_descriptor_iter *iter,
753 struct pldm_descriptor *desc)
754{
Andrew Jefferya1896962025-03-03 21:41:25 +1030755 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030756 int rc;
757
758 if (!iter || !iter->field || !desc) {
759 return -EINVAL;
760 }
761
762 rc = pldm_msgbuf_init_errno(buf, PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN,
763 iter->field->ptr, iter->field->length);
764 if (rc) {
765 return rc;
766 }
767
768 pldm_msgbuf_extract(buf, desc->descriptor_type);
769 rc = pldm_msgbuf_extract(buf, desc->descriptor_length);
770 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +1030771 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030772 }
773
774 desc->descriptor_data = NULL;
775 pldm_msgbuf_span_required(buf, desc->descriptor_length,
776 (void **)&desc->descriptor_data);
777 iter->field->ptr = NULL;
778 pldm_msgbuf_span_remaining(buf, (void **)&iter->field->ptr,
779 &iter->field->length);
780
Andrew Jeffery70d21c92025-03-05 12:59:42 +1030781 return pldm_msgbuf_complete(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030782}
783
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030784static int decode_descriptor_type_length_value_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030785 const void *data, size_t length, uint16_t *descriptor_type,
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030786 struct variable_field *descriptor_data)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930787{
788 uint16_t descriptor_length = 0;
789
790 if (data == NULL || descriptor_type == NULL ||
791 descriptor_data == NULL) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030792 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930793 }
794
795 if (length < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030796 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930797 }
798
799 struct pldm_descriptor_tlv *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930800 (struct pldm_descriptor_tlv *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930801
802 *descriptor_type = le16toh(entry->descriptor_type);
803 descriptor_length = le16toh(entry->descriptor_length);
804 if (*descriptor_type != PLDM_FWUP_VENDOR_DEFINED) {
805 if (descriptor_length !=
806 get_descriptor_type_length(*descriptor_type)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030807 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930808 }
809 }
810
811 if (length < (sizeof(*descriptor_type) + sizeof(descriptor_length) +
812 descriptor_length)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030813 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930814 }
815
816 descriptor_data->ptr = entry->descriptor_data;
817 descriptor_data->length = descriptor_length;
818
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030819 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930820}
821
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930822LIBPLDM_ABI_STABLE
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030823int decode_descriptor_type_length_value(const uint8_t *data, size_t length,
824 uint16_t *descriptor_type,
825 struct variable_field *descriptor_data)
826{
827 int rc;
828
829 rc = decode_descriptor_type_length_value_errno(
830 data, length, descriptor_type, descriptor_data);
831 if (rc < 0) {
832 return pldm_xlate_errno(rc);
833 }
834
835 return PLDM_SUCCESS;
836}
837
838static int decode_vendor_defined_descriptor_value_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030839 const void *data, size_t length, uint8_t *descriptor_title_str_type,
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930840 struct variable_field *descriptor_title_str,
841 struct variable_field *descriptor_data)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930842{
843 if (data == NULL || descriptor_title_str_type == NULL ||
844 descriptor_title_str == NULL || descriptor_data == NULL) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030845 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930846 }
847
848 if (length < sizeof(struct pldm_vendor_defined_descriptor_title_data)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030849 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930850 }
851
852 struct pldm_vendor_defined_descriptor_title_data *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930853 (struct pldm_vendor_defined_descriptor_title_data *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930854 if (!is_string_type_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930855 entry->vendor_defined_descriptor_title_str_type) ||
Andrew Jeffery9c766792022-08-10 23:12:49 +0930856 (entry->vendor_defined_descriptor_title_str_len == 0)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030857 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930858 }
859
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530860 // Assuming at least 1 byte of VendorDefinedDescriptorData
Andrew Jeffery9c766792022-08-10 23:12:49 +0930861 if (length < (sizeof(struct pldm_vendor_defined_descriptor_title_data) +
862 entry->vendor_defined_descriptor_title_str_len)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030863 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930864 }
865
866 *descriptor_title_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930867 entry->vendor_defined_descriptor_title_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930868 descriptor_title_str->ptr = entry->vendor_defined_descriptor_title_str;
869 descriptor_title_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930870 entry->vendor_defined_descriptor_title_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930871
872 descriptor_data->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930873 descriptor_title_str->ptr + descriptor_title_str->length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930874 descriptor_data->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930875 length -
876 sizeof(entry->vendor_defined_descriptor_title_str_type) -
877 sizeof(entry->vendor_defined_descriptor_title_str_len) -
878 descriptor_title_str->length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930879
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030880 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930881}
882
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930883LIBPLDM_ABI_STABLE
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030884int decode_vendor_defined_descriptor_value(
885 const uint8_t *data, size_t length, uint8_t *descriptor_title_str_type,
886 struct variable_field *descriptor_title_str,
887 struct variable_field *descriptor_data)
888{
889 int rc;
890
891 rc = decode_vendor_defined_descriptor_value_errno(
892 data, length, descriptor_title_str_type, descriptor_title_str,
893 descriptor_data);
894 if (rc < 0) {
895 return pldm_xlate_errno(rc);
896 }
897
898 return PLDM_SUCCESS;
899}
900
901static int decode_pldm_comp_image_info_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030902 const void *data, size_t length,
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930903 struct pldm_component_image_information *pldm_comp_image_info,
904 struct variable_field *comp_version_str)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930905{
906 if (data == NULL || pldm_comp_image_info == NULL ||
907 comp_version_str == NULL) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030908 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930909 }
910
911 if (length < sizeof(struct pldm_component_image_information)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030912 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930913 }
914
915 struct pldm_component_image_information *data_header =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930916 (struct pldm_component_image_information *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930917
918 if (!is_string_type_valid(data_header->comp_version_string_type) ||
919 (data_header->comp_version_string_length == 0)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030920 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930921 }
922
923 if (length < sizeof(struct pldm_component_image_information) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930924 data_header->comp_version_string_length) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030925 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930926 }
927
928 pldm_comp_image_info->comp_classification =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930929 le16toh(data_header->comp_classification);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930930 pldm_comp_image_info->comp_identifier =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930931 le16toh(data_header->comp_identifier);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930932 pldm_comp_image_info->comp_comparison_stamp =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930933 le32toh(data_header->comp_comparison_stamp);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930934 pldm_comp_image_info->comp_options.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930935 le16toh(data_header->comp_options.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930936 pldm_comp_image_info->requested_comp_activation_method.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930937 le16toh(data_header->requested_comp_activation_method.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930938 pldm_comp_image_info->comp_location_offset =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930939 le32toh(data_header->comp_location_offset);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930940 pldm_comp_image_info->comp_size = le32toh(data_header->comp_size);
941 pldm_comp_image_info->comp_version_string_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930942 data_header->comp_version_string_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930943 pldm_comp_image_info->comp_version_string_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930944 data_header->comp_version_string_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930945
946 if ((pldm_comp_image_info->comp_options.bits.bit1 == false &&
947 pldm_comp_image_info->comp_comparison_stamp !=
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930948 PLDM_FWUP_INVALID_COMPONENT_COMPARISON_TIMESTAMP)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030949 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930950 }
951
952 if (pldm_comp_image_info->comp_location_offset == 0 ||
953 pldm_comp_image_info->comp_size == 0) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030954 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930955 }
956
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030957 comp_version_str->ptr = (const uint8_t *)data +
958 sizeof(struct pldm_component_image_information);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930959 comp_version_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930960 pldm_comp_image_info->comp_version_string_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930961
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030962 return 0;
963}
964
965LIBPLDM_ABI_STABLE
966int decode_pldm_comp_image_info(
967 const uint8_t *data, size_t length,
968 struct pldm_component_image_information *pldm_comp_image_info,
969 struct variable_field *comp_version_str)
970{
971 int rc;
972
973 rc = decode_pldm_comp_image_info_errno(
974 data, length, pldm_comp_image_info, comp_version_str);
975 if (rc < 0) {
976 return pldm_xlate_errno(rc);
977 }
978
Andrew Jeffery9c766792022-08-10 23:12:49 +0930979 return PLDM_SUCCESS;
980}
981
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930982LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930983int encode_query_device_identifiers_req(uint8_t instance_id,
984 size_t payload_length,
985 struct pldm_msg *msg)
986{
987 if (msg == NULL) {
988 return PLDM_ERROR_INVALID_DATA;
989 }
990
991 if (payload_length != PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES) {
992 return PLDM_ERROR_INVALID_LENGTH;
993 }
994
995 return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
996 PLDM_QUERY_DEVICE_IDENTIFIERS, msg);
997}
998
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930999LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301000int decode_query_device_identifiers_resp(const struct pldm_msg *msg,
1001 size_t payload_length,
1002 uint8_t *completion_code,
1003 uint32_t *device_identifiers_len,
1004 uint8_t *descriptor_count,
1005 uint8_t **descriptor_data)
1006{
1007 if (msg == NULL || completion_code == NULL ||
1008 device_identifiers_len == NULL || descriptor_count == NULL ||
1009 descriptor_data == NULL) {
1010 return PLDM_ERROR_INVALID_DATA;
1011 }
1012
1013 *completion_code = msg->payload[0];
1014 if (PLDM_SUCCESS != *completion_code) {
1015 return PLDM_SUCCESS;
1016 }
1017
1018 if (payload_length <
1019 sizeof(struct pldm_query_device_identifiers_resp)) {
1020 return PLDM_ERROR_INVALID_LENGTH;
1021 }
1022
1023 struct pldm_query_device_identifiers_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301024 (struct pldm_query_device_identifiers_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301025 *device_identifiers_len = le32toh(response->device_identifiers_len);
1026
1027 if (*device_identifiers_len < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {
1028 return PLDM_ERROR_INVALID_LENGTH;
1029 }
1030
1031 if (payload_length !=
1032 sizeof(struct pldm_query_device_identifiers_resp) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301033 *device_identifiers_len) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301034 return PLDM_ERROR_INVALID_LENGTH;
1035 }
1036 *descriptor_count = response->descriptor_count;
1037
1038 if (*descriptor_count == 0) {
1039 return PLDM_ERROR_INVALID_DATA;
1040 }
1041 *descriptor_data =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301042 (uint8_t *)(msg->payload +
1043 sizeof(struct pldm_query_device_identifiers_resp));
Andrew Jeffery9c766792022-08-10 23:12:49 +09301044 return PLDM_SUCCESS;
1045}
1046
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001047LIBPLDM_ABI_TESTING
1048int encode_query_device_identifiers_resp(
1049 uint8_t instance_id, uint8_t descriptor_count,
1050 const struct pldm_descriptor *descriptors, struct pldm_msg *msg,
1051 size_t *payload_length)
1052{
Andrew Jefferya1896962025-03-03 21:41:25 +10301053 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001054 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001055
1056 if (descriptors == NULL || msg == NULL || payload_length == NULL) {
1057 return -EINVAL;
1058 }
1059
1060 if (descriptor_count < 1) {
1061 return -EINVAL;
1062 }
1063
1064 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
1065 PLDM_QUERY_DEVICE_IDENTIFIERS, msg);
1066 if (rc) {
1067 return -EINVAL;
1068 }
1069
1070 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
1071 if (rc) {
1072 return rc;
1073 }
1074
1075 /* Determine total length */
1076 uint32_t device_identifiers_len = 0;
1077 for (uint8_t i = 0; i < descriptor_count; i++) {
1078 const struct pldm_descriptor *d = &descriptors[i];
1079 device_identifiers_len +=
1080 2 * sizeof(uint16_t) + d->descriptor_length;
1081 }
1082
1083 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
1084 pldm_msgbuf_insert(buf, device_identifiers_len);
1085 pldm_msgbuf_insert(buf, descriptor_count);
1086
1087 for (uint8_t i = 0; i < descriptor_count; i++) {
1088 const struct pldm_descriptor *d = &descriptors[i];
1089 pldm_msgbuf_insert(buf, d->descriptor_type);
1090 pldm_msgbuf_insert(buf, d->descriptor_length);
1091 if (d->descriptor_data == NULL) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301092 return pldm_msgbuf_discard(buf, -EINVAL);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001093 }
1094 rc = pldm_msgbuf_insert_array(
1095 buf, d->descriptor_length,
1096 (const uint8_t *)d->descriptor_data,
1097 d->descriptor_length);
1098 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301099 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001100 }
1101 }
1102
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301103 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001104}
1105
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301106LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301107int encode_get_firmware_parameters_req(uint8_t instance_id,
1108 size_t payload_length,
1109 struct pldm_msg *msg)
1110{
1111 if (msg == NULL) {
1112 return PLDM_ERROR_INVALID_DATA;
1113 }
1114
1115 if (payload_length != PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES) {
1116 return PLDM_ERROR_INVALID_LENGTH;
1117 }
1118
1119 return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
1120 PLDM_GET_FIRMWARE_PARAMETERS, msg);
1121}
1122
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301123LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301124int decode_get_firmware_parameters_resp(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301125 const struct pldm_msg *msg, size_t payload_length,
1126 struct pldm_get_firmware_parameters_resp *resp_data,
1127 struct variable_field *active_comp_image_set_ver_str,
1128 struct variable_field *pending_comp_image_set_ver_str,
1129 struct variable_field *comp_parameter_table)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301130{
1131 if (msg == NULL || resp_data == NULL ||
1132 active_comp_image_set_ver_str == NULL ||
1133 pending_comp_image_set_ver_str == NULL ||
1134 comp_parameter_table == NULL || !payload_length) {
1135 return PLDM_ERROR_INVALID_DATA;
1136 }
1137
1138 resp_data->completion_code = msg->payload[0];
1139 if (PLDM_SUCCESS != resp_data->completion_code) {
1140 return PLDM_SUCCESS;
1141 }
1142
1143 if (payload_length < sizeof(struct pldm_get_firmware_parameters_resp)) {
1144 return PLDM_ERROR_INVALID_LENGTH;
1145 }
1146
1147 struct pldm_get_firmware_parameters_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301148 (struct pldm_get_firmware_parameters_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301149
1150 if (!is_string_type_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301151 response->active_comp_image_set_ver_str_type) ||
Andrew Jeffery9c766792022-08-10 23:12:49 +09301152 (response->active_comp_image_set_ver_str_len == 0)) {
1153 return PLDM_ERROR_INVALID_DATA;
1154 }
1155
1156 if (response->pending_comp_image_set_ver_str_len == 0) {
1157 if (response->pending_comp_image_set_ver_str_type !=
1158 PLDM_STR_TYPE_UNKNOWN) {
1159 return PLDM_ERROR_INVALID_DATA;
1160 }
1161 } else {
1162 if (!is_string_type_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301163 response->pending_comp_image_set_ver_str_type)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301164 return PLDM_ERROR_INVALID_DATA;
1165 }
1166 }
1167
1168 size_t partial_response_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301169 sizeof(struct pldm_get_firmware_parameters_resp) +
1170 response->active_comp_image_set_ver_str_len +
1171 response->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301172
1173 if (payload_length < partial_response_length) {
1174 return PLDM_ERROR_INVALID_LENGTH;
1175 }
1176
1177 resp_data->capabilities_during_update.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301178 le32toh(response->capabilities_during_update.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301179 resp_data->comp_count = le16toh(response->comp_count);
1180 resp_data->active_comp_image_set_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301181 response->active_comp_image_set_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301182 resp_data->active_comp_image_set_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301183 response->active_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301184 resp_data->pending_comp_image_set_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301185 response->pending_comp_image_set_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301186 resp_data->pending_comp_image_set_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301187 response->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301188
1189 active_comp_image_set_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301190 msg->payload + sizeof(struct pldm_get_firmware_parameters_resp);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301191 active_comp_image_set_ver_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301192 resp_data->active_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301193
1194 if (resp_data->pending_comp_image_set_ver_str_len != 0) {
1195 pending_comp_image_set_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301196 msg->payload +
1197 sizeof(struct pldm_get_firmware_parameters_resp) +
1198 resp_data->active_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301199 pending_comp_image_set_ver_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301200 resp_data->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301201 } else {
1202 pending_comp_image_set_ver_str->ptr = NULL;
1203 pending_comp_image_set_ver_str->length = 0;
1204 }
1205
1206 if (payload_length > partial_response_length && resp_data->comp_count) {
1207 comp_parameter_table->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301208 msg->payload +
1209 sizeof(struct pldm_get_firmware_parameters_resp) +
1210 resp_data->active_comp_image_set_ver_str_len +
1211 resp_data->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301212 comp_parameter_table->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301213 payload_length - partial_response_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301214 } else {
1215 comp_parameter_table->ptr = NULL;
1216 comp_parameter_table->length = 0;
1217 }
1218
1219 return PLDM_SUCCESS;
1220}
1221
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001222LIBPLDM_ABI_TESTING
1223int encode_get_firmware_parameters_resp(
1224 uint8_t instance_id,
1225 const struct pldm_get_firmware_parameters_resp_full *resp_data,
1226 struct pldm_msg *msg, size_t *payload_length)
1227{
Andrew Jefferya1896962025-03-03 21:41:25 +10301228 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001229 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001230
1231 if (resp_data == NULL || msg == NULL || payload_length == NULL) {
1232 return -EINVAL;
1233 }
1234
1235 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
1236 PLDM_GET_FIRMWARE_PARAMETERS, msg);
1237 if (rc) {
1238 return -EINVAL;
1239 }
1240
1241 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
1242 if (rc) {
1243 return rc;
1244 }
1245
1246 pldm_msgbuf_insert(buf, resp_data->completion_code);
1247 pldm_msgbuf_insert(buf, resp_data->capabilities_during_update.value);
1248 pldm_msgbuf_insert(buf, resp_data->comp_count);
1249 pldm_msgbuf_insert(buf,
1250 resp_data->active_comp_image_set_ver_str.str_type);
1251 pldm_msgbuf_insert(buf,
1252 resp_data->active_comp_image_set_ver_str.str_len);
1253 pldm_msgbuf_insert(buf,
1254 resp_data->pending_comp_image_set_ver_str.str_type);
1255 pldm_msgbuf_insert(buf,
1256 resp_data->pending_comp_image_set_ver_str.str_len);
1257 /* String data appended */
1258 rc = pldm_msgbuf_insert_array(
1259 buf, resp_data->active_comp_image_set_ver_str.str_len,
1260 resp_data->active_comp_image_set_ver_str.str_data,
1261 resp_data->active_comp_image_set_ver_str.str_len);
1262 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301263 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001264 }
1265 rc = pldm_msgbuf_insert_array(
1266 buf, resp_data->pending_comp_image_set_ver_str.str_len,
1267 resp_data->pending_comp_image_set_ver_str.str_data,
1268 resp_data->pending_comp_image_set_ver_str.str_len);
1269 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301270 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001271 }
1272
1273 /* Further calls to encode_get_firmware_parameters_resp_comp_entry
1274 * will populate the remainder */
1275
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301276 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001277}
1278
1279LIBPLDM_ABI_TESTING
1280int encode_get_firmware_parameters_resp_comp_entry(
1281 const struct pldm_component_parameter_entry_full *comp,
1282 uint8_t *payload, size_t *payload_length)
1283{
Andrew Jefferya1896962025-03-03 21:41:25 +10301284 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001285 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001286
1287 if (comp == NULL || payload == NULL || payload_length == NULL) {
1288 return -EINVAL;
1289 }
1290
1291 rc = pldm_msgbuf_init_errno(buf, 0, payload, *payload_length);
1292 if (rc) {
1293 return rc;
1294 }
1295
1296 pldm_msgbuf_insert(buf, comp->comp_classification);
1297 pldm_msgbuf_insert(buf, comp->comp_identifier);
1298 pldm_msgbuf_insert(buf, comp->comp_classification_index);
1299
1300 pldm_msgbuf_insert(buf, comp->active_ver.comparison_stamp);
1301 pldm_msgbuf_insert(buf, (uint8_t)comp->active_ver.str.str_type);
1302 pldm_msgbuf_insert(buf, comp->active_ver.str.str_len);
1303 rc = pldm_msgbuf_insert_array(buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1304 comp->active_ver.date,
1305 PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN);
1306 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301307 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001308 }
1309
1310 pldm_msgbuf_insert(buf, comp->pending_ver.comparison_stamp);
1311 pldm_msgbuf_insert(buf, (uint8_t)comp->pending_ver.str.str_type);
1312 pldm_msgbuf_insert(buf, comp->pending_ver.str.str_len);
1313 rc = pldm_msgbuf_insert_array(buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1314 comp->pending_ver.date,
1315 PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN);
1316 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301317 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001318 }
1319
1320 pldm_msgbuf_insert(buf, comp->comp_activation_methods.value);
1321 pldm_msgbuf_insert(buf, comp->capabilities_during_update.value);
1322
1323 rc = pldm_msgbuf_insert_array(buf, comp->active_ver.str.str_len,
1324 comp->active_ver.str.str_data,
1325 comp->active_ver.str.str_len);
1326 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301327 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001328 }
1329 rc = pldm_msgbuf_insert_array(buf, comp->pending_ver.str.str_len,
1330 comp->pending_ver.str.str_data,
1331 comp->pending_ver.str.str_len);
1332 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301333 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001334 }
1335
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301336 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001337}
1338
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301339LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301340int decode_get_firmware_parameters_resp_comp_entry(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301341 const uint8_t *data, size_t length,
1342 struct pldm_component_parameter_entry *component_data,
1343 struct variable_field *active_comp_ver_str,
1344 struct variable_field *pending_comp_ver_str)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301345{
1346 if (data == NULL || component_data == NULL ||
1347 active_comp_ver_str == NULL || pending_comp_ver_str == NULL) {
1348 return PLDM_ERROR_INVALID_DATA;
1349 }
1350
1351 if (length < sizeof(struct pldm_component_parameter_entry)) {
1352 return PLDM_ERROR_INVALID_LENGTH;
1353 }
1354
1355 struct pldm_component_parameter_entry *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301356 (struct pldm_component_parameter_entry *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301357
1358 size_t entry_length = sizeof(struct pldm_component_parameter_entry) +
1359 entry->active_comp_ver_str_len +
1360 entry->pending_comp_ver_str_len;
1361
1362 if (length < entry_length) {
1363 return PLDM_ERROR_INVALID_LENGTH;
1364 }
1365
1366 component_data->comp_classification =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301367 le16toh(entry->comp_classification);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301368 component_data->comp_identifier = le16toh(entry->comp_identifier);
1369 component_data->comp_classification_index =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301370 entry->comp_classification_index;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301371 component_data->active_comp_comparison_stamp =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301372 le32toh(entry->active_comp_comparison_stamp);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301373 component_data->active_comp_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301374 entry->active_comp_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301375 component_data->active_comp_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301376 entry->active_comp_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301377 memcpy(component_data->active_comp_release_date,
1378 entry->active_comp_release_date,
1379 sizeof(entry->active_comp_release_date));
1380 component_data->pending_comp_comparison_stamp =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301381 le32toh(entry->pending_comp_comparison_stamp);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301382 component_data->pending_comp_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301383 entry->pending_comp_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301384 component_data->pending_comp_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301385 entry->pending_comp_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301386 memcpy(component_data->pending_comp_release_date,
1387 entry->pending_comp_release_date,
1388 sizeof(entry->pending_comp_release_date));
1389 component_data->comp_activation_methods.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301390 le16toh(entry->comp_activation_methods.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301391 component_data->capabilities_during_update.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301392 le32toh(entry->capabilities_during_update.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301393
1394 if (entry->active_comp_ver_str_len != 0) {
1395 active_comp_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301396 data + sizeof(struct pldm_component_parameter_entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301397 active_comp_ver_str->length = entry->active_comp_ver_str_len;
1398 } else {
1399 active_comp_ver_str->ptr = NULL;
1400 active_comp_ver_str->length = 0;
1401 }
1402
1403 if (entry->pending_comp_ver_str_len != 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301404 pending_comp_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301405 data + sizeof(struct pldm_component_parameter_entry) +
1406 entry->active_comp_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301407 pending_comp_ver_str->length = entry->pending_comp_ver_str_len;
1408 } else {
1409 pending_comp_ver_str->ptr = NULL;
1410 pending_comp_ver_str->length = 0;
1411 }
1412 return PLDM_SUCCESS;
1413}
1414
Unive Tiene5c3f142024-12-13 14:14:19 +08001415LIBPLDM_ABI_STABLE
Chris Wang4c1f2c72024-03-21 17:09:44 +08001416int encode_query_downstream_devices_req(uint8_t instance_id,
1417 struct pldm_msg *msg)
1418{
1419 if (msg == NULL) {
Unive Tien71e935c2024-11-25 17:21:43 +08001420 return -EINVAL;
Chris Wang4c1f2c72024-03-21 17:09:44 +08001421 }
1422
Unive Tien71e935c2024-11-25 17:21:43 +08001423 return encode_pldm_header_only_errno(PLDM_REQUEST, instance_id,
1424 PLDM_FWUP,
1425 PLDM_QUERY_DOWNSTREAM_DEVICES,
1426 msg);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001427}
1428
Unive Tiene5c3f142024-12-13 14:14:19 +08001429LIBPLDM_ABI_STABLE
Chris Wang4c1f2c72024-03-21 17:09:44 +08001430int decode_query_downstream_devices_resp(
1431 const struct pldm_msg *msg, size_t payload_length,
1432 struct pldm_query_downstream_devices_resp *resp_data)
1433{
Andrew Jefferya1896962025-03-03 21:41:25 +10301434 PLDM_MSGBUF_DEFINE_P(buf);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001435 int rc;
1436
1437 if (msg == NULL || resp_data == NULL || !payload_length) {
Unive Tien71e935c2024-11-25 17:21:43 +08001438 return -EINVAL;
Chris Wang4c1f2c72024-03-21 17:09:44 +08001439 }
1440
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301441 rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1442 msg->payload, payload_length);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001443 if (rc) {
1444 return rc;
1445 }
1446
1447 rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1448 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301449 return pldm_msgbuf_discard(buf, rc);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001450 }
1451 if (PLDM_SUCCESS != resp_data->completion_code) {
1452 // Return the CC directly without decoding the rest of the payload
Andrew Jefferya1896962025-03-03 21:41:25 +10301453 return pldm_msgbuf_complete(buf);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001454 }
1455
1456 if (payload_length < PLDM_QUERY_DOWNSTREAM_DEVICES_RESP_BYTES) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301457 return pldm_msgbuf_discard(buf, -EBADMSG);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001458 }
1459
1460 rc = pldm_msgbuf_extract(buf,
1461 resp_data->downstream_device_update_supported);
1462 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301463 return pldm_msgbuf_discard(buf, rc);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001464 }
1465
1466 if (!is_downstream_device_update_support_valid(
1467 resp_data->downstream_device_update_supported)) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301468 return pldm_msgbuf_discard(buf, -EINVAL);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001469 }
1470
1471 pldm_msgbuf_extract(buf, resp_data->number_of_downstream_devices);
1472 pldm_msgbuf_extract(buf, resp_data->max_number_of_downstream_devices);
1473 pldm_msgbuf_extract(buf, resp_data->capabilities.value);
1474
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301475 return pldm_msgbuf_complete_consumed(buf);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001476}
1477
Unive Tiene5c3f142024-12-13 14:14:19 +08001478LIBPLDM_ABI_STABLE
Chris Wang458475a2024-03-26 17:59:19 +08001479int encode_query_downstream_identifiers_req(
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001480 uint8_t instance_id,
1481 const struct pldm_query_downstream_identifiers_req *params_req,
1482 struct pldm_msg *msg, size_t payload_length)
Chris Wang458475a2024-03-26 17:59:19 +08001483{
Andrew Jefferya1896962025-03-03 21:41:25 +10301484 PLDM_MSGBUF_DEFINE_P(buf);
Chris Wang458475a2024-03-26 17:59:19 +08001485 int rc;
1486
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001487 if (!msg || !params_req) {
Unive Tien71e935c2024-11-25 17:21:43 +08001488 return -EINVAL;
Chris Wang458475a2024-03-26 17:59:19 +08001489 }
1490
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001491 if (!is_transfer_operation_flag_valid(
1492 (enum transfer_op_flag)
1493 params_req->transfer_operation_flag)) {
Unive Tien71e935c2024-11-25 17:21:43 +08001494 return -EINVAL;
Chris Wang458475a2024-03-26 17:59:19 +08001495 }
1496
1497 struct pldm_header_info header = { 0 };
1498 header.instance = instance_id;
1499 header.msg_type = PLDM_REQUEST;
1500 header.pldm_type = PLDM_FWUP;
1501 header.command = PLDM_QUERY_DOWNSTREAM_IDENTIFIERS;
Unive Tien71e935c2024-11-25 17:21:43 +08001502 rc = pack_pldm_header_errno(&header, &(msg->hdr));
Chris Wang458475a2024-03-26 17:59:19 +08001503 if (rc) {
1504 return rc;
1505 }
1506
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301507 rc = pldm_msgbuf_init_errno(buf,
1508 PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_REQ_BYTES,
1509 msg->payload, payload_length);
Chris Wang458475a2024-03-26 17:59:19 +08001510 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001511 return rc;
Chris Wang458475a2024-03-26 17:59:19 +08001512 }
1513
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001514 pldm_msgbuf_insert(buf, params_req->data_transfer_handle);
Chris Wang458475a2024-03-26 17:59:19 +08001515 // Data correctness has been verified, cast it to 1-byte data directly.
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001516 pldm_msgbuf_insert(buf, params_req->transfer_operation_flag);
Chris Wang458475a2024-03-26 17:59:19 +08001517
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301518 return pldm_msgbuf_complete(buf);
Chris Wang458475a2024-03-26 17:59:19 +08001519}
1520
Unive Tiene5c3f142024-12-13 14:14:19 +08001521LIBPLDM_ABI_STABLE
Chris Wang458475a2024-03-26 17:59:19 +08001522int decode_query_downstream_identifiers_resp(
1523 const struct pldm_msg *msg, size_t payload_length,
1524 struct pldm_query_downstream_identifiers_resp *resp_data,
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301525 struct pldm_downstream_device_iter *iter)
Chris Wang458475a2024-03-26 17:59:19 +08001526{
Andrew Jefferya1896962025-03-03 21:41:25 +10301527 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301528 void *remaining = NULL;
Unive Tien71e935c2024-11-25 17:21:43 +08001529 int rc = 0;
Chris Wang458475a2024-03-26 17:59:19 +08001530
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301531 if (msg == NULL || resp_data == NULL || iter == NULL ||
Chris Wang458475a2024-03-26 17:59:19 +08001532 !payload_length) {
Unive Tien71e935c2024-11-25 17:21:43 +08001533 return -EINVAL;
Chris Wang458475a2024-03-26 17:59:19 +08001534 }
1535
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301536 rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1537 msg->payload, payload_length);
Chris Wang458475a2024-03-26 17:59:19 +08001538 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001539 return rc;
Chris Wang458475a2024-03-26 17:59:19 +08001540 }
1541
1542 rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1543 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301544 return pldm_msgbuf_discard(buf, rc);
Chris Wang458475a2024-03-26 17:59:19 +08001545 }
1546 if (PLDM_SUCCESS != resp_data->completion_code) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301547 return pldm_msgbuf_complete(buf);
Chris Wang458475a2024-03-26 17:59:19 +08001548 }
1549
1550 if (payload_length < PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_RESP_MIN_LEN) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301551 return pldm_msgbuf_discard(buf, -EBADMSG);
Chris Wang458475a2024-03-26 17:59:19 +08001552 }
1553
1554 pldm_msgbuf_extract(buf, resp_data->next_data_transfer_handle);
1555 pldm_msgbuf_extract(buf, resp_data->transfer_flag);
1556
1557 rc = pldm_msgbuf_extract(buf, resp_data->downstream_devices_length);
1558 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301559 return pldm_msgbuf_discard(buf, rc);
Chris Wang458475a2024-03-26 17:59:19 +08001560 }
1561
1562 pldm_msgbuf_extract(buf, resp_data->number_of_downstream_devices);
Andrew Jefferya1896962025-03-03 21:41:25 +10301563 pldm_msgbuf_span_required(buf, resp_data->downstream_devices_length,
1564 &remaining);
Chris Wang458475a2024-03-26 17:59:19 +08001565
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301566 rc = pldm_msgbuf_complete(buf);
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301567 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001568 return rc;
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301569 }
1570
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301571 iter->field.ptr = remaining;
1572 iter->field.length = resp_data->downstream_devices_length;
1573 iter->devs = resp_data->number_of_downstream_devices;
1574
Unive Tien71e935c2024-11-25 17:21:43 +08001575 return 0;
Chris Wang458475a2024-03-26 17:59:19 +08001576}
1577
Unive Tiene5c3f142024-12-13 14:14:19 +08001578LIBPLDM_ABI_STABLE
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301579int decode_pldm_downstream_device_from_iter(
1580 struct pldm_downstream_device_iter *iter,
1581 struct pldm_downstream_device *dev)
1582{
Andrew Jefferya1896962025-03-03 21:41:25 +10301583 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301584 int rc;
1585
Andrew Jefferya1896962025-03-03 21:41:25 +10301586 if (!iter || !iter->field.ptr || !dev) {
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301587 return -EINVAL;
1588 }
1589
1590 rc = pldm_msgbuf_init_errno(buf, 3, iter->field.ptr,
1591 iter->field.length);
1592 if (rc) {
1593 return rc;
1594 }
1595
1596 pldm_msgbuf_extract(buf, dev->downstream_device_index);
1597 pldm_msgbuf_extract(buf, dev->downstream_descriptor_count);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301598 pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
1599 &iter->field.length);
1600
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301601 return pldm_msgbuf_complete(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301602}
1603
Unive Tiene5c3f142024-12-13 14:14:19 +08001604LIBPLDM_ABI_STABLE
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301605int encode_get_downstream_firmware_parameters_req(
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001606 uint8_t instance_id,
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301607 const struct pldm_get_downstream_firmware_parameters_req *params_req,
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001608 struct pldm_msg *msg, size_t payload_length)
Chris Wangb6ef35b2024-07-03 09:35:42 +08001609{
Andrew Jefferya1896962025-03-03 21:41:25 +10301610 PLDM_MSGBUF_DEFINE_P(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001611 int rc;
1612
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001613 if (!msg || !params_req) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001614 return -EINVAL;
1615 }
1616
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001617 if (!is_transfer_operation_flag_valid(
1618 (enum transfer_op_flag)
1619 params_req->transfer_operation_flag)) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001620 return -EBADMSG;
1621 }
1622
1623 struct pldm_header_info header = { 0 };
1624 header.instance = instance_id;
1625 header.msg_type = PLDM_REQUEST;
1626 header.pldm_type = PLDM_FWUP;
1627 header.command = PLDM_QUERY_DOWNSTREAM_FIRMWARE_PARAMETERS;
1628 rc = pack_pldm_header_errno(&header, &msg->hdr);
1629 if (rc < 0) {
1630 return rc;
1631 }
1632
Andrew Jeffery53b08672025-03-04 12:26:18 +10301633 rc = pldm_msgbuf_init_errno(
1634 buf, PLDM_GET_DOWNSTREAM_FIRMWARE_PARAMETERS_REQ_BYTES,
1635 msg->payload, payload_length);
1636 if (rc < 0) {
1637 return rc;
1638 }
1639
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001640 pldm_msgbuf_insert(buf, params_req->data_transfer_handle);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001641 // Data correctness has been verified, cast it to 1-byte data directly.
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001642 pldm_msgbuf_insert(buf, params_req->transfer_operation_flag);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001643
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301644 return pldm_msgbuf_complete(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001645}
1646
Unive Tiene5c3f142024-12-13 14:14:19 +08001647LIBPLDM_ABI_STABLE
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301648int decode_get_downstream_firmware_parameters_resp(
Chris Wangb6ef35b2024-07-03 09:35:42 +08001649 const struct pldm_msg *msg, size_t payload_length,
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301650 struct pldm_get_downstream_firmware_parameters_resp *resp_data,
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301651 struct pldm_downstream_device_parameters_iter *iter)
Chris Wangb6ef35b2024-07-03 09:35:42 +08001652{
Andrew Jefferya1896962025-03-03 21:41:25 +10301653 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301654 void *remaining = NULL;
1655 size_t length;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001656 int rc;
1657
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301658 if (msg == NULL || resp_data == NULL || iter == NULL) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001659 return -EINVAL;
1660 }
1661
1662 rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1663 msg->payload, payload_length);
1664 if (rc < 0) {
1665 return rc;
1666 }
1667
1668 rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1669 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301670 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001671 }
1672 if (PLDM_SUCCESS != resp_data->completion_code) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301673 return pldm_msgbuf_complete(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001674 }
1675
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301676 if (payload_length <
1677 PLDM_GET_DOWNSTREAM_FIRMWARE_PARAMETERS_RESP_MIN_LEN) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301678 return pldm_msgbuf_discard(buf, -EBADMSG);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001679 }
1680
1681 pldm_msgbuf_extract(buf, resp_data->next_data_transfer_handle);
1682 pldm_msgbuf_extract(buf, resp_data->transfer_flag);
1683 pldm_msgbuf_extract(buf,
1684 resp_data->fdp_capabilities_during_update.value);
1685 pldm_msgbuf_extract(buf, resp_data->downstream_device_count);
1686
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301687 rc = pldm_msgbuf_span_remaining(buf, &remaining, &length);
1688 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301689 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301690 }
1691
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301692 rc = pldm_msgbuf_complete(buf);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301693 if (rc) {
1694 return rc;
1695 }
1696
1697 iter->field.ptr = remaining;
1698 iter->field.length = length;
1699 iter->entries = resp_data->downstream_device_count;
1700
1701 return 0;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001702}
1703
Unive Tiene5c3f142024-12-13 14:14:19 +08001704LIBPLDM_ABI_STABLE
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301705int decode_pldm_downstream_device_parameters_entry_from_iter(
1706 struct pldm_downstream_device_parameters_iter *iter,
1707 struct pldm_downstream_device_parameters_entry *entry)
Chris Wangb6ef35b2024-07-03 09:35:42 +08001708{
Andrew Jefferya1896962025-03-03 21:41:25 +10301709 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301710 void *comp_ver_str;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001711 size_t remaining;
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301712 void *cursor;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001713 int rc;
1714
Andrew Jefferya1896962025-03-03 21:41:25 +10301715 if (iter == NULL || iter->field.ptr == NULL || entry == NULL) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001716 return -EINVAL;
1717 }
1718
1719 rc = pldm_msgbuf_init_errno(
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301720 buf, PLDM_DOWNSTREAM_DEVICE_PARAMETERS_ENTRY_MIN_LEN,
1721 iter->field.ptr, iter->field.length);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001722 if (rc < 0) {
1723 return rc;
1724 }
1725
1726 pldm_msgbuf_extract(buf, entry->downstream_device_index);
1727 pldm_msgbuf_extract(buf, entry->active_comp_comparison_stamp);
1728 pldm_msgbuf_extract(buf, entry->active_comp_ver_str_type);
1729 rc = pldm_msgbuf_extract(buf, entry->active_comp_ver_str_len);
1730 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301731 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001732 }
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001733 rc = pldm_msgbuf_extract_array(buf,
1734 PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1735 entry->active_comp_release_date,
1736 sizeof(entry->active_comp_release_date));
1737 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301738 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001739 }
1740
Chris Wangb6ef35b2024-07-03 09:35:42 +08001741 // Fill the last byte with NULL character
1742 entry->active_comp_release_date[PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN] =
1743 '\0';
1744
1745 pldm_msgbuf_extract(buf, entry->pending_comp_comparison_stamp);
1746 pldm_msgbuf_extract(buf, entry->pending_comp_ver_str_type);
1747 rc = pldm_msgbuf_extract(buf, entry->pending_comp_ver_str_len);
1748 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301749 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001750 }
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001751
1752 rc = pldm_msgbuf_extract_array(
1753 buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1754 entry->pending_comp_release_date,
1755 sizeof(entry->pending_comp_release_date));
1756 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301757 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001758 }
1759
Chris Wangb6ef35b2024-07-03 09:35:42 +08001760 // Fill the last byte with NULL character
1761 entry->pending_comp_release_date[PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN] =
1762 '\0';
1763
1764 pldm_msgbuf_extract(buf, entry->comp_activation_methods.value);
1765 pldm_msgbuf_extract(buf, entry->capabilities_during_update.value);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001766
Andrew Jefferya1896962025-03-03 21:41:25 +10301767 rc = pldm_msgbuf_span_required(buf, entry->active_comp_ver_str_len,
1768 &comp_ver_str);
1769 if (rc < 0) {
1770 return pldm_msgbuf_discard(buf, rc);
1771 }
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301772 entry->active_comp_ver_str = comp_ver_str;
1773
Andrew Jefferya1896962025-03-03 21:41:25 +10301774 rc = pldm_msgbuf_span_required(buf, entry->pending_comp_ver_str_len,
1775 &comp_ver_str);
1776 if (rc < 0) {
1777 return pldm_msgbuf_discard(buf, rc);
1778 }
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301779 entry->pending_comp_ver_str = comp_ver_str;
1780
Chris Wangb6ef35b2024-07-03 09:35:42 +08001781 rc = pldm_msgbuf_span_remaining(buf, &cursor, &remaining);
1782 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301783 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001784 }
1785
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301786 iter->field.ptr = cursor;
1787 iter->field.length = remaining;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001788
Andrew Jefferya1896962025-03-03 21:41:25 +10301789 return pldm_msgbuf_complete(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001790}
1791
Sora Su06eadd02025-05-27 11:28:51 +08001792LIBPLDM_ABI_TESTING
1793int encode_request_downstream_device_update_req(
1794 uint8_t instance_id,
1795 const struct pldm_request_downstream_device_update_req *req_data,
1796 struct pldm_msg *msg, size_t *payload_length)
1797{
1798 PLDM_MSGBUF_DEFINE_P(buf);
1799 int rc;
1800
1801 if (!req_data || !msg || !payload_length ||
1802 req_data->maximum_downstream_device_transfer_size <
1803 PLDM_FWUP_BASELINE_TRANSFER_SIZE ||
1804 req_data->maximum_outstanding_transfer_requests <
1805 PLDM_FWUP_MIN_OUTSTANDING_REQ) {
1806 return -EINVAL;
1807 }
1808
1809 rc = encode_pldm_header_only_errno(
1810 PLDM_REQUEST, instance_id, PLDM_FWUP,
1811 PLDM_REQUEST_DOWNSTREAM_DEVICE_UPDATE, msg);
1812 if (rc) {
1813 return rc;
1814 }
1815
1816 rc = pldm_msgbuf_init_errno(buf,
1817 PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES,
1818 msg->payload, *payload_length);
1819 if (rc) {
1820 return rc;
1821 }
1822
1823 pldm_msgbuf_insert(buf,
1824 req_data->maximum_downstream_device_transfer_size);
1825 pldm_msgbuf_insert(buf,
1826 req_data->maximum_outstanding_transfer_requests);
1827 pldm_msgbuf_insert(buf,
1828 req_data->downstream_device_package_data_length);
1829
1830 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
1831}
1832
1833LIBPLDM_ABI_TESTING
1834int decode_request_downstream_device_update_req(
1835 const struct pldm_msg *msg, size_t payload_length,
1836 struct pldm_request_downstream_device_update_req *req)
1837{
1838 int rc;
1839 PLDM_MSGBUF_DEFINE_P(buf);
1840
1841 if (!msg || !req) {
1842 return -EINVAL;
1843 }
1844
1845 rc = pldm_msgbuf_init_errno(buf,
1846 PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES,
1847 msg->payload, payload_length);
1848 if (rc) {
1849 return rc;
1850 }
1851
1852 pldm_msgbuf_extract(buf, req->maximum_downstream_device_transfer_size);
1853 pldm_msgbuf_extract(buf, req->maximum_outstanding_transfer_requests);
1854 pldm_msgbuf_extract(buf, req->downstream_device_package_data_length);
1855
1856 return pldm_msgbuf_complete_consumed(buf);
1857}
1858
1859LIBPLDM_ABI_TESTING
1860int encode_request_downstream_device_update_resp(
1861 uint8_t instance_id,
1862 const struct pldm_request_downstream_device_update_resp *resp_data,
1863 struct pldm_msg *msg, size_t *payload_length)
1864{
1865 PLDM_MSGBUF_DEFINE_P(buf);
1866 int rc;
1867
1868 if (!resp_data || !msg || !payload_length) {
1869 return -EINVAL;
1870 }
1871
1872 rc = encode_pldm_header_only_errno(
1873 PLDM_RESPONSE, instance_id, PLDM_FWUP,
1874 PLDM_REQUEST_DOWNSTREAM_DEVICE_UPDATE, msg);
1875 if (rc) {
1876 return rc;
1877 }
1878
1879 rc = pldm_msgbuf_init_errno(
1880 buf, PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES, msg->payload,
1881 *payload_length);
1882 if (rc) {
1883 return rc;
1884 }
1885
1886 pldm_msgbuf_insert(buf, resp_data->completion_code);
1887 pldm_msgbuf_insert(buf, resp_data->downstream_device_meta_data_length);
1888 pldm_msgbuf_insert(
1889 buf, resp_data->downstream_device_will_send_get_package_data);
1890 pldm_msgbuf_insert(buf,
1891 resp_data->get_package_data_maximum_transfer_size);
1892
1893 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
1894}
1895
1896LIBPLDM_ABI_TESTING
1897int decode_request_downstream_device_update_resp(
1898 const struct pldm_msg *msg, size_t payload_length,
1899 struct pldm_request_downstream_device_update_resp *resp_data)
1900{
1901 PLDM_MSGBUF_DEFINE_P(buf);
1902 int rc;
1903
1904 if (!msg || !resp_data) {
1905 return -EINVAL;
1906 }
1907
1908 rc = pldm_msg_has_error(msg,
1909 PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES);
1910 if (rc) {
1911 resp_data->completion_code = rc;
1912 return 0;
1913 }
1914
1915 rc = pldm_msgbuf_init_errno(
1916 buf, PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES, msg->payload,
1917 payload_length);
1918 if (rc) {
1919 return rc;
1920 }
1921
1922 pldm_msgbuf_extract(buf, resp_data->completion_code);
1923 pldm_msgbuf_extract(buf, resp_data->downstream_device_meta_data_length);
1924 pldm_msgbuf_extract(
1925 buf, resp_data->downstream_device_will_send_get_package_data);
1926 pldm_msgbuf_extract(buf,
1927 resp_data->get_package_data_maximum_transfer_size);
1928
1929 return pldm_msgbuf_complete_consumed(buf);
1930}
1931
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301932LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301933int encode_request_update_req(uint8_t instance_id, uint32_t max_transfer_size,
1934 uint16_t num_of_comp,
1935 uint8_t max_outstanding_transfer_req,
1936 uint16_t pkg_data_len,
1937 uint8_t comp_image_set_ver_str_type,
1938 uint8_t comp_image_set_ver_str_len,
1939 const struct variable_field *comp_img_set_ver_str,
1940 struct pldm_msg *msg, size_t payload_length)
1941{
1942 if (comp_img_set_ver_str == NULL || comp_img_set_ver_str->ptr == NULL ||
1943 msg == NULL) {
1944 return PLDM_ERROR_INVALID_DATA;
1945 }
1946
1947 if (payload_length != sizeof(struct pldm_request_update_req) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301948 comp_img_set_ver_str->length) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301949 return PLDM_ERROR_INVALID_LENGTH;
1950 }
1951
1952 if ((comp_image_set_ver_str_len == 0) ||
1953 (comp_image_set_ver_str_len != comp_img_set_ver_str->length)) {
1954 return PLDM_ERROR_INVALID_DATA;
1955 }
1956
1957 if ((max_transfer_size < PLDM_FWUP_BASELINE_TRANSFER_SIZE) ||
1958 (max_outstanding_transfer_req < PLDM_FWUP_MIN_OUTSTANDING_REQ)) {
1959 return PLDM_ERROR_INVALID_DATA;
1960 }
1961
1962 if (!is_string_type_valid(comp_image_set_ver_str_type)) {
1963 return PLDM_ERROR_INVALID_DATA;
1964 }
1965
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301966 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09301967 header.instance = instance_id;
1968 header.msg_type = PLDM_REQUEST;
1969 header.pldm_type = PLDM_FWUP;
1970 header.command = PLDM_REQUEST_UPDATE;
1971 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1972 if (rc) {
1973 return rc;
1974 }
1975
1976 struct pldm_request_update_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301977 (struct pldm_request_update_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301978
1979 request->max_transfer_size = htole32(max_transfer_size);
1980 request->num_of_comp = htole16(num_of_comp);
1981 request->max_outstanding_transfer_req = max_outstanding_transfer_req;
1982 request->pkg_data_len = htole16(pkg_data_len);
1983 request->comp_image_set_ver_str_type = comp_image_set_ver_str_type;
1984 request->comp_image_set_ver_str_len = comp_image_set_ver_str_len;
1985
1986 memcpy(msg->payload + sizeof(struct pldm_request_update_req),
1987 comp_img_set_ver_str->ptr, comp_img_set_ver_str->length);
1988
1989 return PLDM_SUCCESS;
1990}
1991
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001992LIBPLDM_ABI_TESTING
1993int decode_request_update_req(const struct pldm_msg *msg, size_t payload_length,
1994 struct pldm_request_update_req_full *req)
1995{
1996 int rc;
1997 uint8_t t;
Andrew Jefferya1896962025-03-03 21:41:25 +10301998 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001999
2000 if (msg == NULL || req == NULL) {
2001 return -EINVAL;
2002 }
2003
2004 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2005 if (rc) {
2006 return rc;
2007 }
2008
2009 pldm_msgbuf_extract(buf, req->max_transfer_size);
2010 pldm_msgbuf_extract(buf, req->num_of_comp);
2011 pldm_msgbuf_extract(buf, req->max_outstanding_transfer_req);
2012 pldm_msgbuf_extract(buf, req->pkg_data_len);
2013 rc = pldm_msgbuf_extract(buf, t);
2014 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302015 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002016 }
2017 if (t > PLDM_STR_TYPE_UTF_16BE) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302018 return pldm_msgbuf_discard(buf, -EBADMSG);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002019 }
2020 req->image_set_ver.str_type = (enum pldm_firmware_update_string_type)t;
2021 pldm_msgbuf_extract(buf, req->image_set_ver.str_len);
2022 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302023 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002024 }
2025
2026 rc = pldm_msgbuf_extract_array(buf, req->image_set_ver.str_len,
2027 req->image_set_ver.str_data,
2028 PLDM_FIRMWARE_MAX_STRING);
2029 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302030 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002031 }
2032
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302033 return pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002034}
2035
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302036LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302037int decode_request_update_resp(const struct pldm_msg *msg,
2038 size_t payload_length, uint8_t *completion_code,
2039 uint16_t *fd_meta_data_len,
2040 uint8_t *fd_will_send_pkg_data)
2041{
2042 if (msg == NULL || completion_code == NULL ||
2043 fd_meta_data_len == NULL || fd_will_send_pkg_data == NULL ||
2044 !payload_length) {
2045 return PLDM_ERROR_INVALID_DATA;
2046 }
2047
2048 *completion_code = msg->payload[0];
2049 if (*completion_code != PLDM_SUCCESS) {
2050 return PLDM_SUCCESS;
2051 }
2052
2053 if (payload_length != sizeof(struct pldm_request_update_resp)) {
2054 return PLDM_ERROR_INVALID_LENGTH;
2055 }
2056
2057 struct pldm_request_update_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302058 (struct pldm_request_update_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302059
2060 *fd_meta_data_len = le16toh(response->fd_meta_data_len);
2061 *fd_will_send_pkg_data = response->fd_will_send_pkg_data;
2062
2063 return PLDM_SUCCESS;
2064}
2065
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002066LIBPLDM_ABI_TESTING
2067int encode_request_update_resp(uint8_t instance_id,
2068 const struct pldm_request_update_resp *resp_data,
2069 struct pldm_msg *msg, size_t *payload_length)
2070{
Andrew Jefferya1896962025-03-03 21:41:25 +10302071 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002072 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002073
2074 if (msg == NULL || payload_length == NULL) {
2075 return -EINVAL;
2076 }
2077
2078 struct pldm_header_info header = {
2079 .instance = instance_id,
2080 .msg_type = PLDM_RESPONSE,
2081 .pldm_type = PLDM_FWUP,
2082 .command = PLDM_REQUEST_UPDATE,
2083 };
2084 rc = pack_pldm_header(&header, &(msg->hdr));
2085 if (rc) {
2086 return -EINVAL;
2087 }
2088
2089 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2090 if (rc) {
2091 return rc;
2092 }
2093
2094 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2095 pldm_msgbuf_insert(buf, resp_data->fd_meta_data_len);
2096 pldm_msgbuf_insert(buf, resp_data->fd_will_send_pkg_data);
2097
2098 /* TODO: DSP0267 1.3.0 adds GetPackageDataMaximumTransferSize */
2099
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302100 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002101}
2102
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302103LIBPLDM_ABI_STABLE
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302104int encode_pass_component_table_req(uint8_t instance_id, uint8_t transfer_flag,
2105 uint16_t comp_classification,
2106 uint16_t comp_identifier,
2107 uint8_t comp_classification_index,
2108 uint32_t comp_comparison_stamp,
2109 uint8_t comp_ver_str_type,
2110 uint8_t comp_ver_str_len,
2111 const struct variable_field *comp_ver_str,
2112 struct pldm_msg *msg, size_t payload_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09302113{
2114 if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) {
2115 return PLDM_ERROR_INVALID_DATA;
2116 }
2117
2118 if (payload_length != sizeof(struct pldm_pass_component_table_req) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302119 comp_ver_str->length) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302120 return PLDM_ERROR_INVALID_LENGTH;
2121 }
2122
2123 if ((comp_ver_str_len == 0) ||
2124 (comp_ver_str_len != comp_ver_str->length)) {
2125 return PLDM_ERROR_INVALID_DATA;
2126 }
2127
2128 if (!is_transfer_flag_valid(transfer_flag)) {
Manojkiran Eda3643e742025-05-19 12:03:54 +05302129 return PLDM_FWUP_INVALID_TRANSFER_OPERATION_FLAG;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302130 }
2131
2132 if (!is_string_type_valid(comp_ver_str_type)) {
2133 return PLDM_ERROR_INVALID_DATA;
2134 }
2135
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302136 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302137 header.instance = instance_id;
2138 header.msg_type = PLDM_REQUEST;
2139 header.pldm_type = PLDM_FWUP;
2140 header.command = PLDM_PASS_COMPONENT_TABLE;
2141 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2142 if (rc) {
2143 return rc;
2144 }
2145
2146 struct pldm_pass_component_table_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302147 (struct pldm_pass_component_table_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302148
2149 request->transfer_flag = transfer_flag;
2150 request->comp_classification = htole16(comp_classification);
2151 request->comp_identifier = htole16(comp_identifier);
2152 request->comp_classification_index = comp_classification_index;
2153 request->comp_comparison_stamp = htole32(comp_comparison_stamp);
2154 request->comp_ver_str_type = comp_ver_str_type;
2155 request->comp_ver_str_len = comp_ver_str_len;
2156
2157 memcpy(msg->payload + sizeof(struct pldm_pass_component_table_req),
2158 comp_ver_str->ptr, comp_ver_str->length);
2159
2160 return PLDM_SUCCESS;
2161}
2162
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002163LIBPLDM_ABI_TESTING
2164int decode_pass_component_table_req(
2165 const struct pldm_msg *msg, size_t payload_length,
2166 struct pldm_pass_component_table_req_full *pcomp)
2167{
2168 int rc;
2169 uint8_t t;
Andrew Jefferya1896962025-03-03 21:41:25 +10302170 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002171
2172 if (msg == NULL || pcomp == NULL) {
2173 return -EINVAL;
2174 }
2175
2176 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2177 if (rc) {
2178 return rc;
2179 }
2180
2181 pldm_msgbuf_extract(buf, pcomp->transfer_flag);
2182 pldm_msgbuf_extract(buf, pcomp->comp_classification);
2183 pldm_msgbuf_extract(buf, pcomp->comp_identifier);
2184 pldm_msgbuf_extract(buf, pcomp->comp_classification_index);
2185 pldm_msgbuf_extract(buf, pcomp->comp_comparison_stamp);
2186 rc = pldm_msgbuf_extract(buf, t);
2187 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302188 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002189 }
2190 if (t > PLDM_STR_TYPE_UTF_16BE) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302191 return pldm_msgbuf_discard(buf, -EBADMSG);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002192 }
2193 pcomp->version.str_type = (enum pldm_firmware_update_string_type)t;
2194 rc = pldm_msgbuf_extract(buf, pcomp->version.str_len);
2195 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302196 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002197 }
2198 rc = pldm_msgbuf_extract_array(buf, pcomp->version.str_len,
2199 pcomp->version.str_data,
2200 PLDM_FIRMWARE_MAX_STRING);
2201 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302202 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002203 }
2204
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302205 return pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002206}
2207
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302208LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302209int decode_pass_component_table_resp(const struct pldm_msg *msg,
2210 const size_t payload_length,
2211 uint8_t *completion_code,
2212 uint8_t *comp_resp,
2213 uint8_t *comp_resp_code)
2214{
2215 if (msg == NULL || completion_code == NULL || comp_resp == NULL ||
2216 comp_resp_code == NULL || !payload_length) {
2217 return PLDM_ERROR_INVALID_DATA;
2218 }
2219
2220 *completion_code = msg->payload[0];
2221 if (*completion_code != PLDM_SUCCESS) {
2222 return PLDM_SUCCESS;
2223 }
2224
2225 if (payload_length != sizeof(struct pldm_pass_component_table_resp)) {
2226 return PLDM_ERROR_INVALID_LENGTH;
2227 }
2228
2229 struct pldm_pass_component_table_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302230 (struct pldm_pass_component_table_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302231
2232 if (!is_comp_resp_valid(response->comp_resp)) {
2233 return PLDM_ERROR_INVALID_DATA;
2234 }
2235
2236 if (!is_comp_resp_code_valid(response->comp_resp_code)) {
2237 return PLDM_ERROR_INVALID_DATA;
2238 }
2239
2240 *comp_resp = response->comp_resp;
2241 *comp_resp_code = response->comp_resp_code;
2242
2243 return PLDM_SUCCESS;
2244}
2245
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002246LIBPLDM_ABI_TESTING
2247int encode_pass_component_table_resp(
2248 uint8_t instance_id,
2249 const struct pldm_pass_component_table_resp *resp_data,
2250 struct pldm_msg *msg, size_t *payload_length)
2251{
Andrew Jefferya1896962025-03-03 21:41:25 +10302252 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002253 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002254
2255 if (msg == NULL || payload_length == NULL) {
2256 return -EINVAL;
2257 }
2258
2259 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2260 PLDM_PASS_COMPONENT_TABLE, msg);
2261 if (rc) {
2262 return -EINVAL;
2263 }
2264
2265 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2266 if (rc) {
2267 return rc;
2268 }
2269
2270 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2271 pldm_msgbuf_insert(buf, resp_data->comp_resp);
2272 pldm_msgbuf_insert(buf, resp_data->comp_resp_code);
2273
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302274 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002275}
2276
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302277LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302278int encode_update_component_req(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302279 uint8_t instance_id, uint16_t comp_classification,
2280 uint16_t comp_identifier, uint8_t comp_classification_index,
2281 uint32_t comp_comparison_stamp, uint32_t comp_image_size,
2282 bitfield32_t update_option_flags, uint8_t comp_ver_str_type,
2283 uint8_t comp_ver_str_len, const struct variable_field *comp_ver_str,
2284 struct pldm_msg *msg, size_t payload_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09302285{
2286 if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) {
2287 return PLDM_ERROR_INVALID_DATA;
2288 }
2289
2290 if (payload_length !=
2291 sizeof(struct pldm_update_component_req) + comp_ver_str->length) {
2292 return PLDM_ERROR_INVALID_LENGTH;
2293 }
2294
2295 if (!comp_image_size) {
2296 return PLDM_ERROR_INVALID_DATA;
2297 }
2298
2299 if ((comp_ver_str_len == 0) ||
2300 (comp_ver_str_len != comp_ver_str->length)) {
2301 return PLDM_ERROR_INVALID_DATA;
2302 }
2303
2304 if (!is_string_type_valid(comp_ver_str_type)) {
2305 return PLDM_ERROR_INVALID_DATA;
2306 }
2307
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302308 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302309 header.instance = instance_id;
2310 header.msg_type = PLDM_REQUEST;
2311 header.pldm_type = PLDM_FWUP;
2312 header.command = PLDM_UPDATE_COMPONENT;
2313 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2314 if (rc) {
2315 return rc;
2316 }
2317
2318 struct pldm_update_component_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302319 (struct pldm_update_component_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302320
2321 request->comp_classification = htole16(comp_classification);
2322 request->comp_identifier = htole16(comp_identifier);
2323 request->comp_classification_index = comp_classification_index;
2324 request->comp_comparison_stamp = htole32(comp_comparison_stamp);
2325 request->comp_image_size = htole32(comp_image_size);
2326 request->update_option_flags.value = htole32(update_option_flags.value);
2327 request->comp_ver_str_type = comp_ver_str_type;
2328 request->comp_ver_str_len = comp_ver_str_len;
2329
2330 memcpy(msg->payload + sizeof(struct pldm_update_component_req),
2331 comp_ver_str->ptr, comp_ver_str->length);
2332
2333 return PLDM_SUCCESS;
2334}
2335
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002336LIBPLDM_ABI_TESTING
2337int decode_update_component_req(const struct pldm_msg *msg,
2338 size_t payload_length,
2339 struct pldm_update_component_req_full *up)
2340{
2341 int rc;
2342 uint8_t t;
Andrew Jefferya1896962025-03-03 21:41:25 +10302343 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002344
2345 if (msg == NULL || up == NULL) {
2346 return -EINVAL;
2347 }
2348
2349 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2350 if (rc) {
2351 return rc;
2352 }
2353
2354 pldm_msgbuf_extract(buf, up->comp_classification);
2355 pldm_msgbuf_extract(buf, up->comp_identifier);
2356 pldm_msgbuf_extract(buf, up->comp_classification_index);
2357 pldm_msgbuf_extract(buf, up->comp_comparison_stamp);
2358 pldm_msgbuf_extract(buf, up->comp_image_size);
2359 pldm_msgbuf_extract(buf, up->update_option_flags.value);
2360 rc = pldm_msgbuf_extract(buf, t);
2361 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302362 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002363 }
2364 if (t > PLDM_STR_TYPE_UTF_16BE) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302365 return pldm_msgbuf_discard(buf, -EBADMSG);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002366 }
2367 up->version.str_type = (enum pldm_firmware_update_string_type)t;
2368 rc = pldm_msgbuf_extract(buf, up->version.str_len);
2369 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302370 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002371 }
2372 rc = pldm_msgbuf_extract_array(buf, up->version.str_len,
2373 up->version.str_data,
2374 PLDM_FIRMWARE_MAX_STRING);
2375 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302376 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002377 }
2378
Andrew Jefferya1896962025-03-03 21:41:25 +10302379 return pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002380}
2381
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302382LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302383int decode_update_component_resp(const struct pldm_msg *msg,
2384 size_t payload_length,
2385 uint8_t *completion_code,
2386 uint8_t *comp_compatibility_resp,
2387 uint8_t *comp_compatibility_resp_code,
2388 bitfield32_t *update_option_flags_enabled,
2389 uint16_t *time_before_req_fw_data)
2390{
2391 if (msg == NULL || completion_code == NULL ||
2392 comp_compatibility_resp == NULL ||
2393 comp_compatibility_resp_code == NULL ||
2394 update_option_flags_enabled == NULL ||
2395 time_before_req_fw_data == NULL || !payload_length) {
2396 return PLDM_ERROR_INVALID_DATA;
2397 }
2398
2399 *completion_code = msg->payload[0];
2400 if (*completion_code != PLDM_SUCCESS) {
2401 return PLDM_SUCCESS;
2402 }
2403
2404 if (payload_length != sizeof(struct pldm_update_component_resp)) {
2405 return PLDM_ERROR_INVALID_LENGTH;
2406 }
2407
2408 struct pldm_update_component_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302409 (struct pldm_update_component_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302410
2411 if (!is_comp_compatibility_resp_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302412 response->comp_compatibility_resp)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302413 return PLDM_ERROR_INVALID_DATA;
2414 }
2415
2416 if (!is_comp_compatibility_resp_code_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302417 response->comp_compatibility_resp_code)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302418 return PLDM_ERROR_INVALID_DATA;
2419 }
2420
2421 *comp_compatibility_resp = response->comp_compatibility_resp;
2422 *comp_compatibility_resp_code = response->comp_compatibility_resp_code;
2423 update_option_flags_enabled->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302424 le32toh(response->update_option_flags_enabled.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302425 *time_before_req_fw_data = le16toh(response->time_before_req_fw_data);
2426
2427 return PLDM_SUCCESS;
2428}
2429
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002430LIBPLDM_ABI_TESTING
2431int encode_update_component_resp(
2432 uint8_t instance_id, const struct pldm_update_component_resp *resp_data,
2433 struct pldm_msg *msg, size_t *payload_length)
2434{
Andrew Jefferya1896962025-03-03 21:41:25 +10302435 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002436 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002437
2438 if (msg == NULL || payload_length == NULL) {
2439 return -EINVAL;
2440 }
2441
2442 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2443 PLDM_UPDATE_COMPONENT, msg);
2444 if (rc) {
2445 return -EINVAL;
2446 }
2447
2448 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2449 if (rc) {
2450 return rc;
2451 }
2452
2453 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2454 pldm_msgbuf_insert(buf, resp_data->comp_compatibility_resp);
2455 pldm_msgbuf_insert(buf, resp_data->comp_compatibility_resp_code);
2456 pldm_msgbuf_insert(buf, resp_data->update_option_flags_enabled.value);
2457 pldm_msgbuf_insert(buf, resp_data->time_before_req_fw_data);
2458
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302459 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002460}
2461
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302462LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302463int decode_request_firmware_data_req(const struct pldm_msg *msg,
2464 size_t payload_length, uint32_t *offset,
2465 uint32_t *length)
2466{
2467 if (msg == NULL || offset == NULL || length == NULL) {
2468 return PLDM_ERROR_INVALID_DATA;
2469 }
2470 if (payload_length != sizeof(struct pldm_request_firmware_data_req)) {
2471 return PLDM_ERROR_INVALID_LENGTH;
2472 }
2473 struct pldm_request_firmware_data_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302474 (struct pldm_request_firmware_data_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302475 *offset = le32toh(request->offset);
2476 *length = le32toh(request->length);
2477
2478 if (*length < PLDM_FWUP_BASELINE_TRANSFER_SIZE) {
2479 return PLDM_FWUP_INVALID_TRANSFER_LENGTH;
2480 }
2481
2482 return PLDM_SUCCESS;
2483}
2484
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002485LIBPLDM_ABI_TESTING
2486int encode_request_firmware_data_req(
2487 uint8_t instance_id,
2488 const struct pldm_request_firmware_data_req *req_params,
2489 struct pldm_msg *msg, size_t *payload_length)
2490{
Andrew Jefferya1896962025-03-03 21:41:25 +10302491 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002492 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002493
2494 if (msg == NULL || payload_length == NULL) {
2495 return -EINVAL;
2496 }
2497
2498 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2499 PLDM_REQUEST_FIRMWARE_DATA, msg);
2500 if (rc) {
2501 return -EINVAL;
2502 }
2503
2504 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2505 if (rc) {
2506 return rc;
2507 }
2508
2509 pldm_msgbuf_insert(buf, req_params->offset);
2510 pldm_msgbuf_insert(buf, req_params->length);
2511
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302512 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002513}
2514
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302515LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302516int encode_request_firmware_data_resp(uint8_t instance_id,
2517 uint8_t completion_code,
2518 struct pldm_msg *msg,
2519 size_t payload_length)
2520{
2521 if (msg == NULL || !payload_length) {
2522 return PLDM_ERROR_INVALID_DATA;
2523 }
2524
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302525 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302526 header.instance = instance_id;
2527 header.msg_type = PLDM_RESPONSE;
2528 header.pldm_type = PLDM_FWUP;
2529 header.command = PLDM_REQUEST_FIRMWARE_DATA;
2530 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2531 if (rc) {
2532 return rc;
2533 }
2534
2535 msg->payload[0] = completion_code;
2536
2537 return PLDM_SUCCESS;
2538}
2539
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302540LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302541int decode_transfer_complete_req(const struct pldm_msg *msg,
2542 size_t payload_length,
2543 uint8_t *transfer_result)
2544{
2545 if (msg == NULL || transfer_result == NULL) {
2546 return PLDM_ERROR_INVALID_DATA;
2547 }
2548
2549 if (payload_length != sizeof(*transfer_result)) {
2550 return PLDM_ERROR_INVALID_LENGTH;
2551 }
2552
2553 *transfer_result = msg->payload[0];
2554 return PLDM_SUCCESS;
2555}
2556
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002557LIBPLDM_ABI_TESTING
2558int encode_transfer_complete_req(uint8_t instance_id, uint8_t transfer_result,
2559 struct pldm_msg *msg, size_t *payload_length)
2560{
Andrew Jefferya1896962025-03-03 21:41:25 +10302561 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002562 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002563
2564 if (msg == NULL || payload_length == NULL) {
2565 return -EINVAL;
2566 }
2567
2568 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2569 PLDM_TRANSFER_COMPLETE, msg);
2570 if (rc) {
2571 return -EINVAL;
2572 }
2573
2574 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2575 if (rc) {
2576 return rc;
2577 }
2578
Andrew Jefferya1896962025-03-03 21:41:25 +10302579 pldm_msgbuf_insert(buf, transfer_result);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002580
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302581 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002582}
2583
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302584LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302585int encode_transfer_complete_resp(uint8_t instance_id, uint8_t completion_code,
2586 struct pldm_msg *msg, size_t payload_length)
2587{
2588 if (msg == NULL) {
2589 return PLDM_ERROR_INVALID_DATA;
2590 }
2591
2592 if (payload_length != sizeof(completion_code)) {
2593 return PLDM_ERROR_INVALID_LENGTH;
2594 }
2595
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302596 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302597 header.instance = instance_id;
2598 header.msg_type = PLDM_RESPONSE;
2599 header.pldm_type = PLDM_FWUP;
2600 header.command = PLDM_TRANSFER_COMPLETE;
2601 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2602 if (rc) {
2603 return rc;
2604 }
2605
2606 msg->payload[0] = completion_code;
2607
2608 return PLDM_SUCCESS;
2609}
2610
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302611LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302612int decode_verify_complete_req(const struct pldm_msg *msg,
2613 size_t payload_length, uint8_t *verify_result)
2614{
2615 if (msg == NULL || verify_result == NULL) {
2616 return PLDM_ERROR_INVALID_DATA;
2617 }
2618
2619 if (payload_length != sizeof(*verify_result)) {
2620 return PLDM_ERROR_INVALID_LENGTH;
2621 }
2622
2623 *verify_result = msg->payload[0];
2624 return PLDM_SUCCESS;
2625}
2626
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002627LIBPLDM_ABI_TESTING
2628int encode_verify_complete_req(uint8_t instance_id, uint8_t verify_result,
2629 struct pldm_msg *msg, size_t *payload_length)
2630{
Andrew Jefferya1896962025-03-03 21:41:25 +10302631 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002632 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002633
2634 if (msg == NULL || payload_length == NULL) {
2635 return -EINVAL;
2636 }
2637
2638 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2639 PLDM_VERIFY_COMPLETE, msg);
2640 if (rc) {
2641 return EINVAL;
2642 }
2643
2644 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2645 if (rc) {
2646 return rc;
2647 }
2648
Andrew Jefferya1896962025-03-03 21:41:25 +10302649 pldm_msgbuf_insert(buf, verify_result);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002650
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302651 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002652}
2653
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302654LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302655int encode_verify_complete_resp(uint8_t instance_id, uint8_t completion_code,
2656 struct pldm_msg *msg, size_t payload_length)
2657{
2658 if (msg == NULL) {
2659 return PLDM_ERROR_INVALID_DATA;
2660 }
2661
2662 if (payload_length != sizeof(completion_code)) {
2663 return PLDM_ERROR_INVALID_LENGTH;
2664 }
2665
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302666 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302667 header.instance = instance_id;
2668 header.msg_type = PLDM_RESPONSE;
2669 header.pldm_type = PLDM_FWUP;
2670 header.command = PLDM_VERIFY_COMPLETE;
2671 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2672 if (rc) {
2673 return rc;
2674 }
2675
2676 msg->payload[0] = completion_code;
2677
2678 return PLDM_SUCCESS;
2679}
2680
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302681LIBPLDM_ABI_STABLE
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302682int decode_apply_complete_req(const struct pldm_msg *msg, size_t payload_length,
2683 uint8_t *apply_result,
2684 bitfield16_t *comp_activation_methods_modification)
Andrew Jeffery9c766792022-08-10 23:12:49 +09302685{
2686 if (msg == NULL || apply_result == NULL ||
2687 comp_activation_methods_modification == NULL) {
2688 return PLDM_ERROR_INVALID_DATA;
2689 }
2690
2691 if (payload_length != sizeof(struct pldm_apply_complete_req)) {
2692 return PLDM_ERROR_INVALID_LENGTH;
2693 }
2694
2695 struct pldm_apply_complete_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302696 (struct pldm_apply_complete_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302697
2698 *apply_result = request->apply_result;
2699 comp_activation_methods_modification->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302700 le16toh(request->comp_activation_methods_modification.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302701
2702 if ((*apply_result != PLDM_FWUP_APPLY_SUCCESS_WITH_ACTIVATION_METHOD) &&
2703 comp_activation_methods_modification->value) {
2704 return PLDM_ERROR_INVALID_DATA;
2705 }
2706
2707 return PLDM_SUCCESS;
2708}
2709
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002710LIBPLDM_ABI_TESTING
2711int encode_apply_complete_req(uint8_t instance_id,
2712 const struct pldm_apply_complete_req *req_data,
2713 struct pldm_msg *msg, size_t *payload_length)
2714{
Andrew Jefferya1896962025-03-03 21:41:25 +10302715 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002716 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002717
2718 if (msg == NULL || payload_length == NULL) {
2719 return -EINVAL;
2720 }
2721
2722 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2723 PLDM_APPLY_COMPLETE, msg);
2724 if (rc) {
2725 return -EINVAL;
2726 }
2727
2728 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2729 if (rc) {
2730 return rc;
2731 }
2732
2733 pldm_msgbuf_insert(buf, req_data->apply_result);
2734 pldm_msgbuf_insert(
2735 buf, req_data->comp_activation_methods_modification.value);
2736
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302737 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002738}
2739
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302740LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302741int encode_apply_complete_resp(uint8_t instance_id, uint8_t completion_code,
2742 struct pldm_msg *msg, size_t payload_length)
2743{
2744 if (msg == NULL) {
2745 return PLDM_ERROR_INVALID_DATA;
2746 }
2747
2748 if (payload_length != sizeof(completion_code)) {
2749 return PLDM_ERROR_INVALID_LENGTH;
2750 }
2751
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302752 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302753 header.instance = instance_id;
2754 header.msg_type = PLDM_RESPONSE;
2755 header.pldm_type = PLDM_FWUP;
2756 header.command = PLDM_APPLY_COMPLETE;
2757 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2758 if (rc) {
2759 return rc;
2760 }
2761
2762 msg->payload[0] = completion_code;
2763
2764 return PLDM_SUCCESS;
2765}
2766
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002767LIBPLDM_ABI_TESTING
2768int decode_activate_firmware_req(const struct pldm_msg *msg,
2769 size_t payload_length, bool *self_contained)
2770{
Andrew Jefferya1896962025-03-03 21:41:25 +10302771 uint8_t self_contained_u8 = 0;
2772 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002773 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002774
2775 if (msg == NULL || self_contained == NULL) {
2776 return -EINVAL;
2777 }
2778
2779 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2780 if (rc) {
2781 return 0;
2782 }
2783
Andrew Jefferya1896962025-03-03 21:41:25 +10302784 pldm_msgbuf_extract(buf, self_contained_u8);
2785
2786 rc = pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002787 if (rc) {
2788 return rc;
2789 }
Andrew Jefferya1896962025-03-03 21:41:25 +10302790
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002791 *self_contained = (bool)self_contained_u8;
2792 return 0;
2793}
2794
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302795LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302796int encode_activate_firmware_req(uint8_t instance_id,
2797 bool8_t self_contained_activation_req,
2798 struct pldm_msg *msg, size_t payload_length)
2799{
2800 if (msg == NULL) {
2801 return PLDM_ERROR_INVALID_DATA;
2802 }
2803
2804 if (payload_length != sizeof(struct pldm_activate_firmware_req)) {
2805 return PLDM_ERROR_INVALID_LENGTH;
2806 }
2807
2808 if (!is_self_contained_activation_req_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302809 self_contained_activation_req)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302810 return PLDM_ERROR_INVALID_DATA;
2811 }
2812
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302813 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302814 header.instance = instance_id;
2815 header.msg_type = PLDM_REQUEST;
2816 header.pldm_type = PLDM_FWUP;
2817 header.command = PLDM_ACTIVATE_FIRMWARE;
2818 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2819 if (rc) {
2820 return rc;
2821 }
2822
2823 struct pldm_activate_firmware_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302824 (struct pldm_activate_firmware_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302825
2826 request->self_contained_activation_req = self_contained_activation_req;
2827
2828 return PLDM_SUCCESS;
2829}
2830
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302831LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302832int decode_activate_firmware_resp(const struct pldm_msg *msg,
2833 size_t payload_length,
2834 uint8_t *completion_code,
2835 uint16_t *estimated_time_activation)
2836{
2837 if (msg == NULL || completion_code == NULL ||
2838 estimated_time_activation == NULL || !payload_length) {
2839 return PLDM_ERROR_INVALID_DATA;
2840 }
2841
2842 *completion_code = msg->payload[0];
2843 if (*completion_code != PLDM_SUCCESS) {
2844 return PLDM_SUCCESS;
2845 }
2846
2847 if (payload_length != sizeof(struct pldm_activate_firmware_resp)) {
2848 return PLDM_ERROR_INVALID_LENGTH;
2849 }
2850
2851 struct pldm_activate_firmware_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302852 (struct pldm_activate_firmware_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302853
2854 *estimated_time_activation =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302855 le16toh(response->estimated_time_activation);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302856
2857 return PLDM_SUCCESS;
2858}
2859
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002860LIBPLDM_ABI_TESTING
2861int encode_activate_firmware_resp(
2862 uint8_t instance_id,
2863 const struct pldm_activate_firmware_resp *resp_data,
2864 struct pldm_msg *msg, size_t *payload_length)
2865{
Andrew Jefferya1896962025-03-03 21:41:25 +10302866 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002867 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002868
2869 if (msg == NULL || payload_length == NULL) {
2870 return -EINVAL;
2871 }
2872
2873 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2874 PLDM_ACTIVATE_FIRMWARE, msg);
2875 if (rc) {
2876 return -EINVAL;
2877 }
2878
2879 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2880 if (rc) {
2881 return rc;
2882 }
2883
2884 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2885 pldm_msgbuf_insert(buf, resp_data->estimated_time_activation);
2886
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302887 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002888}
2889
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302890LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302891int encode_get_status_req(uint8_t instance_id, struct pldm_msg *msg,
2892 size_t payload_length)
2893{
2894 if (msg == NULL) {
2895 return PLDM_ERROR_INVALID_DATA;
2896 }
2897
2898 if (payload_length != PLDM_GET_STATUS_REQ_BYTES) {
2899 return PLDM_ERROR_INVALID_LENGTH;
2900 }
2901
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302902 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302903 header.instance = instance_id;
2904 header.msg_type = PLDM_REQUEST;
2905 header.pldm_type = PLDM_FWUP;
2906 header.command = PLDM_GET_STATUS;
2907 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2908 if (rc) {
2909 return rc;
2910 }
2911
2912 return PLDM_SUCCESS;
2913}
2914
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302915LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302916int decode_get_status_resp(const struct pldm_msg *msg, size_t payload_length,
2917 uint8_t *completion_code, uint8_t *current_state,
2918 uint8_t *previous_state, uint8_t *aux_state,
2919 uint8_t *aux_state_status, uint8_t *progress_percent,
2920 uint8_t *reason_code,
2921 bitfield32_t *update_option_flags_enabled)
2922{
2923 if (msg == NULL || completion_code == NULL || current_state == NULL ||
2924 previous_state == NULL || aux_state == NULL ||
2925 aux_state_status == NULL || progress_percent == NULL ||
2926 reason_code == NULL || update_option_flags_enabled == NULL ||
2927 !payload_length) {
2928 return PLDM_ERROR_INVALID_DATA;
2929 }
2930
2931 *completion_code = msg->payload[0];
2932 if (*completion_code != PLDM_SUCCESS) {
2933 return PLDM_SUCCESS;
2934 }
2935
2936 if (payload_length != sizeof(struct pldm_get_status_resp)) {
2937 return PLDM_ERROR_INVALID_LENGTH;
2938 }
2939 struct pldm_get_status_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302940 (struct pldm_get_status_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302941
2942 if (!is_state_valid(response->current_state)) {
2943 return PLDM_ERROR_INVALID_DATA;
2944 }
2945 if (!is_state_valid(response->previous_state)) {
2946 return PLDM_ERROR_INVALID_DATA;
2947 }
2948 if (!is_aux_state_valid(response->aux_state)) {
2949 return PLDM_ERROR_INVALID_DATA;
2950 }
2951 if (!is_aux_state_status_valid(response->aux_state_status)) {
2952 return PLDM_ERROR_INVALID_DATA;
2953 }
2954 if (response->progress_percent > PLDM_FWUP_MAX_PROGRESS_PERCENT) {
2955 return PLDM_ERROR_INVALID_DATA;
2956 }
2957 if (!is_reason_code_valid(response->reason_code)) {
2958 return PLDM_ERROR_INVALID_DATA;
2959 }
2960
2961 if ((response->current_state == PLDM_FD_STATE_IDLE) ||
2962 (response->current_state == PLDM_FD_STATE_LEARN_COMPONENTS) ||
2963 (response->current_state == PLDM_FD_STATE_READY_XFER)) {
2964 if (response->aux_state !=
2965 PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER) {
2966 return PLDM_ERROR_INVALID_DATA;
2967 }
2968 }
2969
2970 *current_state = response->current_state;
2971 *previous_state = response->previous_state;
2972 *aux_state = response->aux_state;
2973 *aux_state_status = response->aux_state_status;
2974 *progress_percent = response->progress_percent;
2975 *reason_code = response->reason_code;
2976 update_option_flags_enabled->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302977 le32toh(response->update_option_flags_enabled.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302978
2979 return PLDM_SUCCESS;
2980}
2981
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002982LIBPLDM_ABI_TESTING
2983int encode_get_status_resp(uint8_t instance_id,
2984 const struct pldm_get_status_resp *status,
2985 struct pldm_msg *msg, size_t *payload_length)
2986{
Andrew Jefferya1896962025-03-03 21:41:25 +10302987 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002988 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002989
2990 if (status == NULL || msg == NULL || payload_length == NULL) {
2991 return -EINVAL;
2992 }
2993
2994 if (status->completion_code != PLDM_SUCCESS) {
2995 return -EINVAL;
2996 }
2997
2998 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2999 PLDM_GET_STATUS, msg);
3000 if (rc) {
3001 return -EINVAL;
3002 }
3003
3004 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
3005 if (rc) {
3006 return rc;
3007 }
3008
3009 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
3010 pldm_msgbuf_insert(buf, status->current_state);
3011 pldm_msgbuf_insert(buf, status->previous_state);
3012 pldm_msgbuf_insert(buf, status->aux_state);
3013 pldm_msgbuf_insert(buf, status->aux_state_status);
3014 pldm_msgbuf_insert(buf, status->progress_percent);
3015 pldm_msgbuf_insert(buf, status->reason_code);
3016 pldm_msgbuf_insert(buf, status->update_option_flags_enabled.value);
3017
Andrew Jeffery70d21c92025-03-05 12:59:42 +10303018 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003019}
3020
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09303021LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09303022int encode_cancel_update_component_req(uint8_t instance_id,
3023 struct pldm_msg *msg,
3024 size_t payload_length)
3025{
3026 if (msg == NULL) {
3027 return PLDM_ERROR_INVALID_DATA;
3028 }
3029
3030 if (payload_length != PLDM_CANCEL_UPDATE_COMPONENT_REQ_BYTES) {
3031 return PLDM_ERROR_INVALID_LENGTH;
3032 }
3033
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303034 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09303035 header.instance = instance_id;
3036 header.msg_type = PLDM_REQUEST;
3037 header.pldm_type = PLDM_FWUP;
3038 header.command = PLDM_CANCEL_UPDATE_COMPONENT;
3039 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
3040 if (rc) {
3041 return rc;
3042 }
3043
3044 return PLDM_SUCCESS;
3045}
3046
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09303047LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09303048int decode_cancel_update_component_resp(const struct pldm_msg *msg,
3049 size_t payload_length,
3050 uint8_t *completion_code)
3051{
3052 if (msg == NULL || completion_code == NULL) {
3053 return PLDM_ERROR_INVALID_DATA;
3054 }
3055
3056 if (payload_length != sizeof(*completion_code)) {
3057 return PLDM_ERROR_INVALID_LENGTH;
3058 }
3059
3060 *completion_code = msg->payload[0];
3061 return PLDM_SUCCESS;
3062}
3063
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09303064LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09303065int encode_cancel_update_req(uint8_t instance_id, struct pldm_msg *msg,
3066 size_t payload_length)
3067{
3068 if (msg == NULL) {
3069 return PLDM_ERROR_INVALID_DATA;
3070 }
3071
3072 if (payload_length != PLDM_CANCEL_UPDATE_REQ_BYTES) {
3073 return PLDM_ERROR_INVALID_LENGTH;
3074 }
3075
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303076 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09303077 header.instance = instance_id;
3078 header.msg_type = PLDM_REQUEST;
3079 header.pldm_type = PLDM_FWUP;
3080 header.command = PLDM_CANCEL_UPDATE;
3081 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
3082 if (rc) {
3083 return rc;
3084 }
3085
3086 return PLDM_SUCCESS;
3087}
3088
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09303089LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09303090int decode_cancel_update_resp(const struct pldm_msg *msg, size_t payload_length,
3091 uint8_t *completion_code,
3092 bool8_t *non_functioning_component_indication,
3093 bitfield64_t *non_functioning_component_bitmap)
3094{
3095 if (msg == NULL || completion_code == NULL ||
3096 non_functioning_component_indication == NULL ||
3097 non_functioning_component_bitmap == NULL || !payload_length) {
3098 return PLDM_ERROR_INVALID_DATA;
3099 }
3100
3101 *completion_code = msg->payload[0];
3102 if (*completion_code != PLDM_SUCCESS) {
3103 return PLDM_SUCCESS;
3104 }
3105
3106 if (payload_length != sizeof(struct pldm_cancel_update_resp)) {
3107 return PLDM_ERROR_INVALID_LENGTH;
3108 }
3109 struct pldm_cancel_update_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303110 (struct pldm_cancel_update_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09303111
3112 if (!is_non_functioning_component_indication_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303113 response->non_functioning_component_indication)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09303114 return PLDM_ERROR_INVALID_DATA;
3115 }
3116
3117 *non_functioning_component_indication =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303118 response->non_functioning_component_indication;
Andrew Jeffery9c766792022-08-10 23:12:49 +09303119
3120 if (*non_functioning_component_indication) {
3121 non_functioning_component_bitmap->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303122 le64toh(response->non_functioning_component_bitmap);
Andrew Jeffery9c766792022-08-10 23:12:49 +09303123 }
3124
3125 return PLDM_SUCCESS;
3126}
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003127
3128LIBPLDM_ABI_TESTING
3129int encode_cancel_update_resp(uint8_t instance_id,
3130 const struct pldm_cancel_update_resp *resp_data,
3131 struct pldm_msg *msg, size_t *payload_length)
3132{
Andrew Jefferya1896962025-03-03 21:41:25 +10303133 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003134 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003135
3136 if (msg == NULL || payload_length == NULL) {
3137 return -EINVAL;
3138 }
3139
3140 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
3141 PLDM_CANCEL_UPDATE, msg);
3142 if (rc) {
3143 return -EINVAL;
3144 }
3145
3146 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
3147 if (rc) {
3148 return rc;
3149 }
3150
3151 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
3152 pldm_msgbuf_insert(buf,
3153 resp_data->non_functioning_component_indication);
3154 pldm_msgbuf_insert(buf, resp_data->non_functioning_component_bitmap);
3155
Andrew Jeffery70d21c92025-03-05 12:59:42 +10303156 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003157}
Andrew Jeffery2613c272025-03-12 14:15:41 +10303158
3159LIBPLDM_ABI_TESTING
3160int decode_pldm_firmware_update_package(
3161 const void *data, size_t length,
3162 const struct pldm_package_format_pin *pin,
3163 pldm_package_header_information_pad *hdr,
3164 struct pldm_package_iter *iter)
3165{
3166 if (!data || !pin || !hdr || !iter) {
3167 return -EINVAL;
3168 }
3169
3170 iter->hdr = hdr;
3171
3172 return decode_pldm_package_header_info_errno(data, length, pin, hdr);
3173}
3174
3175LIBPLDM_ABI_TESTING
3176int pldm_package_firmware_device_id_record_iter_init(
3177 const pldm_package_header_information_pad *hdr,
3178 struct pldm_package_firmware_device_id_record_iter *iter)
3179{
3180 PLDM_MSGBUF_DEFINE_P(buf);
3181 int rc;
3182
3183 if (!hdr || !iter || !hdr->areas.ptr) {
3184 return -EINVAL;
3185 }
3186
3187 iter->field = hdr->areas;
3188
3189 /* Extract the fd record id count */
3190 rc = pldm_msgbuf_init_errno(buf, 1, iter->field.ptr,
3191 iter->field.length);
3192 if (rc) {
3193 return rc;
3194 }
3195
3196 pldm_msgbuf_extract_uint8_to_size(buf, iter->entries);
3197 pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
3198 &iter->field.length);
3199
3200 return pldm_msgbuf_complete(buf);
3201}
3202
3203LIBPLDM_ABI_TESTING
3204int decode_pldm_package_firmware_device_id_record_from_iter(
3205 const pldm_package_header_information_pad *hdr,
3206 struct pldm_package_firmware_device_id_record_iter *iter,
3207 struct pldm_package_firmware_device_id_record *rec)
3208{
3209 return decode_pldm_package_firmware_device_id_record_errno(
3210 hdr, &iter->field, rec);
3211}
3212
3213LIBPLDM_ABI_TESTING
3214int pldm_package_downstream_device_id_record_iter_init(
3215 const pldm_package_header_information_pad *hdr,
3216 struct pldm_package_firmware_device_id_record_iter *fds,
3217 struct pldm_package_downstream_device_id_record_iter *dds)
3218{
3219 PLDM_MSGBUF_DEFINE_P(buf);
3220 int rc;
3221
3222 if (!hdr || !fds || !dds || !fds->field.ptr) {
3223 return -EINVAL;
3224 }
3225
3226 dds->field = fds->field;
3227 fds->field.ptr = NULL;
3228 fds->field.length = 0;
3229
3230 /* Downstream device ID records aren't specified in revision 1 */
3231 if (hdr->package_header_format_revision <
3232 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR02H) {
3233 dds->entries = 0;
3234 return 0;
3235 }
3236
3237 /* Extract the dd record id count */
3238 rc = pldm_msgbuf_init_errno(buf, 1, dds->field.ptr, dds->field.length);
3239 if (rc) {
3240 return rc;
3241 }
3242
3243 pldm_msgbuf_extract_uint8_to_size(buf, dds->entries);
3244 pldm_msgbuf_span_remaining(buf, (void **)&dds->field.ptr,
3245 &dds->field.length);
3246
3247 return pldm_msgbuf_complete(buf);
3248}
3249
3250#define PLDM_FWUP_DOWNSTREAM_DEVICE_ID_RECORD_MIN_SIZE 11
3251LIBPLDM_ABI_TESTING
3252int decode_pldm_package_downstream_device_id_record_from_iter(
3253 const pldm_package_header_information_pad *hdr,
3254 struct pldm_package_downstream_device_id_record_iter *iter,
3255 struct pldm_package_downstream_device_id_record *rec)
3256{
3257 PLDM_MSGBUF_DEFINE_P(buf);
3258 uint16_t record_len = 0;
3259 int rc;
3260
3261 if (!hdr || !iter || !rec || !iter->field.ptr) {
3262 return -EINVAL;
3263 }
3264
3265 if (hdr->package_header_format_revision <
3266 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR02H) {
3267 /* Should not be reached due to corresponding test in iter initialisation */
3268 return -ENOTSUP;
3269 }
3270
3271 if (hdr->component_bitmap_bit_length & 7) {
3272 return -EPROTO;
3273 }
3274
3275 rc = pldm_msgbuf_init_dynamic_uint16(
3276 buf, PLDM_FWUP_DOWNSTREAM_DEVICE_ID_RECORD_MIN_SIZE,
3277 (void *)iter->field.ptr, iter->field.length,
3278 (void **)&iter->field.ptr, &iter->field.length);
3279 if (rc) {
3280 return pldm_msgbuf_discard(buf, rc);
3281 }
3282
3283 pldm_msgbuf_extract(buf, record_len);
3284 pldm_msgbuf_extract(buf, rec->descriptor_count);
3285
3286 rc = pldm_msgbuf_extract(buf, rec->update_option_flags.value);
3287 if (rc) {
3288 return pldm_msgbuf_discard(buf, rc);
3289 }
3290
3291 rc = pldm_msgbuf_extract(
3292 buf, rec->self_contained_activation_min_version_string_type);
3293 if (rc) {
3294 return pldm_msgbuf_discard(buf, rc);
3295 }
3296 if (!is_string_type_valid(
3297 rec->self_contained_activation_min_version_string_type)) {
3298 return pldm_msgbuf_discard(buf, -EPROTO);
3299 }
3300
3301 rc = pldm_msgbuf_extract_uint8_to_size(
3302 buf, rec->self_contained_activation_min_version_string.length);
3303 if (rc) {
3304 return pldm_msgbuf_discard(buf, rc);
3305 }
3306
3307 rc = pldm_msgbuf_extract_uint16_to_size(buf, rec->package_data.length);
3308 if (rc) {
3309 return pldm_msgbuf_discard(buf, rc);
3310 }
3311
3312 rc = pldm_msgbuf_span_required(
3313 buf, hdr->component_bitmap_bit_length / 8,
3314 (void **)&rec->applicable_components.bitmap.ptr);
3315 if (rc) {
3316 return pldm_msgbuf_discard(buf, rc);
3317 }
3318 rec->applicable_components.bitmap.length =
3319 hdr->component_bitmap_bit_length / 8;
3320
3321 pldm_msgbuf_span_required(
3322 buf, rec->self_contained_activation_min_version_string.length,
3323 (void **)&rec->self_contained_activation_min_version_string.ptr);
3324 if (rec->update_option_flags.bits.bit0) {
3325 pldm_msgbuf_extract(
3326 buf,
3327 rec->self_contained_activation_min_version_comparison_stamp);
3328 } else {
3329 rec->self_contained_activation_min_version_comparison_stamp = 0;
3330 }
3331
3332 pldm_msgbuf_span_until(buf, rec->package_data.length,
3333 (void **)&rec->record_descriptors.ptr,
3334 &rec->record_descriptors.length);
3335
3336 pldm_msgbuf_span_required(buf, rec->package_data.length,
3337 (void **)&rec->package_data.ptr);
3338
3339 return pldm_msgbuf_complete_consumed(buf);
3340}
3341
3342LIBPLDM_ABI_TESTING
3343int pldm_package_component_image_information_iter_init(
3344 const pldm_package_header_information_pad *hdr LIBPLDM_CC_UNUSED,
3345 struct pldm_package_downstream_device_id_record_iter *dds,
3346 struct pldm_package_component_image_information_iter *infos)
3347{
3348 uint16_t component_image_count;
3349 PLDM_MSGBUF_DEFINE_P(buf);
3350 int rc;
3351
3352 if (!dds || !infos) {
3353 return -EINVAL;
3354 }
3355
3356 infos->field = dds->field;
3357 dds->field.ptr = NULL;
3358 dds->field.length = 0;
3359
3360 /* Extract the component image count */
3361 rc = pldm_msgbuf_init_errno(buf, 1, infos->field.ptr,
3362 infos->field.length);
3363 if (rc) {
3364 return rc;
3365 }
3366
3367 rc = pldm_msgbuf_extract(buf, component_image_count);
3368 if (rc) {
3369 return pldm_msgbuf_discard(buf, rc);
3370 }
3371 infos->entries = component_image_count;
3372
3373 pldm_msgbuf_span_remaining(buf, (void **)&infos->field.ptr,
3374 &infos->field.length);
3375
3376 return pldm_msgbuf_complete(buf);
3377}
3378
3379#define PLDM_FWUP_COMPONENT_IMAGE_INFORMATION_MIN_SIZE 22
3380LIBPLDM_ABI_TESTING
3381int decode_pldm_package_component_image_information_from_iter(
3382 const pldm_package_header_information_pad *hdr,
3383 struct pldm_package_component_image_information_iter *iter,
3384 struct pldm_package_component_image_information *info)
3385{
3386 uint32_t component_location_offset = 0;
3387 uint32_t component_size = 0;
3388 PLDM_MSGBUF_DEFINE_P(buf);
3389 int rc;
3390
3391 if (!hdr || !iter || !info || !iter->field.ptr) {
3392 return -EINVAL;
3393 }
3394
3395 if (hdr->component_bitmap_bit_length & 7) {
3396 return -EPROTO;
3397 }
3398
3399 rc = pldm_msgbuf_init_errno(
3400 buf, PLDM_FWUP_COMPONENT_IMAGE_INFORMATION_MIN_SIZE,
3401 iter->field.ptr, iter->field.length);
3402 if (rc) {
3403 return rc;
3404 }
3405
3406 pldm_msgbuf_extract(buf, info->component_classification);
3407 pldm_msgbuf_extract(buf, info->component_identifier);
3408 pldm_msgbuf_extract(buf, info->component_comparison_stamp);
3409 pldm_msgbuf_extract(buf, info->component_options.value);
3410 pldm_msgbuf_extract(buf,
3411 info->requested_component_activation_method.value);
3412 pldm_msgbuf_extract(buf, component_location_offset);
3413 pldm_msgbuf_extract(buf, component_size);
3414
3415 rc = pldm_msgbuf_extract(buf, info->component_version_string_type);
3416 if (rc) {
3417 return pldm_msgbuf_discard(buf, rc);
3418 }
3419 if (!is_string_type_valid(info->component_version_string_type)) {
3420 return pldm_msgbuf_discard(buf, -EPROTO);
3421 }
3422
3423 rc = pldm_msgbuf_extract_uint8_to_size(
3424 buf, info->component_version_string.length);
3425 if (rc) {
3426 return pldm_msgbuf_discard(buf, rc);
3427 }
3428
3429 pldm_msgbuf_span_required(buf, info->component_version_string.length,
3430 (void **)&info->component_version_string.ptr);
3431
3432 pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
3433 &iter->field.length);
3434
3435 rc = pldm_msgbuf_complete_consumed(buf);
3436 if (rc) {
3437 return rc;
3438 }
3439
3440 if (info->component_classification > 0x000d &&
3441 info->component_classification < 0x8000) {
3442 return -EPROTO;
3443 }
3444
3445 /* Resolve the component image in memory */
3446 rc = pldm_msgbuf_init_errno(buf, 0, hdr->package.ptr,
3447 hdr->package.length);
3448 if (rc) {
3449 return rc;
3450 }
3451
3452 pldm_msgbuf_span_required(buf, component_location_offset, NULL);
3453 pldm_msgbuf_span_required(buf, component_size,
3454 (void **)&info->component_image.ptr);
3455
3456 rc = pldm_msgbuf_complete(buf);
3457 if (rc) {
3458 return rc;
3459 }
3460
3461 info->component_image.length = component_size;
3462
3463 return 0;
3464}