blob: d733d0ad38b7fbb5bffbc6366cd5f507d4e74fec [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"
Carter Chenff78bca2025-06-25 10:33:31 +08004#include "utils.h"
Andrew Jeffery2613c272025-03-12 14:15:41 +10305#include "compiler.h"
Chris Wangb6ef35b2024-07-03 09:35:42 +08006#include "dsp/base.h"
Chris Wang4c1f2c72024-03-21 17:09:44 +08007#include "msgbuf.h"
Andrew Jefferybacbbac2025-03-12 04:02:18 +00008#include <libpldm/base.h>
Andrew Jeffery2613c272025-03-12 14:15:41 +10309#include <libpldm/compiler.h>
Andrew Jefferyb0c1d202023-11-07 22:08:44 +103010#include <libpldm/firmware_update.h>
11#include <libpldm/utils.h>
12
Andrew Jeffery9c766792022-08-10 23:12:49 +093013#include <endian.h>
Manojkiran Eda9a8e4972022-11-28 16:38:21 +053014#include <stdbool.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +093015#include <string.h>
16
Matt Johnstoncf9a2df2024-11-07 15:29:29 +080017static_assert(PLDM_FIRMWARE_MAX_STRING <= UINT8_MAX, "too large");
18
Andrew Jeffery9c766792022-08-10 23:12:49 +093019/** @brief Check whether string type value is valid
20 *
21 * @return true if string type value is valid, false if not
22 */
23static bool is_string_type_valid(uint8_t string_type)
24{
25 switch (string_type) {
26 case PLDM_STR_TYPE_UNKNOWN:
27 return false;
28 case PLDM_STR_TYPE_ASCII:
29 case PLDM_STR_TYPE_UTF_8:
30 case PLDM_STR_TYPE_UTF_16:
31 case PLDM_STR_TYPE_UTF_16LE:
32 case PLDM_STR_TYPE_UTF_16BE:
33 return true;
34 default:
35 return false;
36 }
37}
38
39/** @brief Return the length of the descriptor type described in firmware update
40 * specification
41 *
42 * @return length of the descriptor type if descriptor type is valid else
43 * return 0
44 */
45static uint16_t get_descriptor_type_length(uint16_t descriptor_type)
46{
47 switch (descriptor_type) {
Andrew Jeffery9c766792022-08-10 23:12:49 +093048 case PLDM_FWUP_PCI_VENDOR_ID:
49 return PLDM_FWUP_PCI_VENDOR_ID_LENGTH;
50 case PLDM_FWUP_IANA_ENTERPRISE_ID:
51 return PLDM_FWUP_IANA_ENTERPRISE_ID_LENGTH;
52 case PLDM_FWUP_UUID:
53 return PLDM_FWUP_UUID_LENGTH;
54 case PLDM_FWUP_PNP_VENDOR_ID:
55 return PLDM_FWUP_PNP_VENDOR_ID_LENGTH;
56 case PLDM_FWUP_ACPI_VENDOR_ID:
57 return PLDM_FWUP_ACPI_VENDOR_ID_LENGTH;
58 case PLDM_FWUP_IEEE_ASSIGNED_COMPANY_ID:
59 return PLDM_FWUP_IEEE_ASSIGNED_COMPANY_ID_LENGTH;
60 case PLDM_FWUP_SCSI_VENDOR_ID:
61 return PLDM_FWUP_SCSI_VENDOR_ID_LENGTH;
62 case PLDM_FWUP_PCI_DEVICE_ID:
63 return PLDM_FWUP_PCI_DEVICE_ID_LENGTH;
64 case PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID:
65 return PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID_LENGTH;
66 case PLDM_FWUP_PCI_SUBSYSTEM_ID:
67 return PLDM_FWUP_PCI_SUBSYSTEM_ID_LENGTH;
68 case PLDM_FWUP_PCI_REVISION_ID:
69 return PLDM_FWUP_PCI_REVISION_ID_LENGTH;
70 case PLDM_FWUP_PNP_PRODUCT_IDENTIFIER:
71 return PLDM_FWUP_PNP_PRODUCT_IDENTIFIER_LENGTH;
72 case PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER:
73 return PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER_LENGTH;
74 case PLDM_FWUP_ASCII_MODEL_NUMBER_LONG_STRING:
75 return PLDM_FWUP_ASCII_MODEL_NUMBER_LONG_STRING_LENGTH;
76 case PLDM_FWUP_ASCII_MODEL_NUMBER_SHORT_STRING:
77 return PLDM_FWUP_ASCII_MODEL_NUMBER_SHORT_STRING_LENGTH;
78 case PLDM_FWUP_SCSI_PRODUCT_ID:
79 return PLDM_FWUP_SCSI_PRODUCT_ID_LENGTH;
80 case PLDM_FWUP_UBM_CONTROLLER_DEVICE_CODE:
81 return PLDM_FWUP_UBM_CONTROLLER_DEVICE_CODE_LENGTH;
82 default:
83 return 0;
84 }
85}
86
Chris Wang4c1f2c72024-03-21 17:09:44 +080087static bool is_downstream_device_update_support_valid(uint8_t resp)
88{
89 switch (resp) {
90 case PLDM_FWUP_DOWNSTREAM_DEVICE_UPDATE_NOT_SUPPORTED:
91 case PLDM_FWUP_DOWNSTREAM_DEVICE_UPDATE_SUPPORTED:
92 return true;
93 default:
94 return false;
95 }
96}
97
Chris Wang458475a2024-03-26 17:59:19 +080098static bool
99is_transfer_operation_flag_valid(enum transfer_op_flag transfer_op_flag)
100{
101 switch (transfer_op_flag) {
102 case PLDM_GET_NEXTPART:
103 case PLDM_GET_FIRSTPART:
104 return true;
105 default:
106 return false;
107 }
108}
109
Andrew Jeffery9c766792022-08-10 23:12:49 +0930110/** @brief Check whether ComponentResponse is valid
111 *
112 * @return true if ComponentResponse is valid, false if not
113 */
114static bool is_comp_resp_valid(uint8_t comp_resp)
115{
116 switch (comp_resp) {
117 case PLDM_CR_COMP_CAN_BE_UPDATED:
118 case PLDM_CR_COMP_MAY_BE_UPDATEABLE:
119 return true;
120
121 default:
122 return false;
123 }
124}
125
126/** @brief Check whether ComponentResponseCode is valid
127 *
128 * @return true if ComponentResponseCode is valid, false if not
129 */
130static bool is_comp_resp_code_valid(uint8_t comp_resp_code)
131{
132 switch (comp_resp_code) {
133 case PLDM_CRC_COMP_CAN_BE_UPDATED:
134 case PLDM_CRC_COMP_COMPARISON_STAMP_IDENTICAL:
135 case PLDM_CRC_COMP_COMPARISON_STAMP_LOWER:
136 case PLDM_CRC_INVALID_COMP_COMPARISON_STAMP:
137 case PLDM_CRC_COMP_CONFLICT:
138 case PLDM_CRC_COMP_PREREQUISITES_NOT_MET:
139 case PLDM_CRC_COMP_NOT_SUPPORTED:
140 case PLDM_CRC_COMP_SECURITY_RESTRICTIONS:
141 case PLDM_CRC_INCOMPLETE_COMP_IMAGE_SET:
142 case PLDM_CRC_ACTIVE_IMAGE_NOT_UPDATEABLE_SUBSEQUENTLY:
143 case PLDM_CRC_COMP_VER_STR_IDENTICAL:
144 case PLDM_CRC_COMP_VER_STR_LOWER:
145 return true;
146
147 default:
148 if (comp_resp_code >=
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930149 PLDM_CRC_VENDOR_COMP_RESP_CODE_RANGE_MIN &&
Andrew Jeffery9c766792022-08-10 23:12:49 +0930150 comp_resp_code <=
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930151 PLDM_CRC_VENDOR_COMP_RESP_CODE_RANGE_MAX) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930152 return true;
153 }
154 return false;
155 }
156}
157
158/** @brief Check whether ComponentCompatibilityResponse is valid
159 *
160 * @return true if ComponentCompatibilityResponse is valid, false if not
161 */
162static bool is_comp_compatibility_resp_valid(uint8_t comp_compatibility_resp)
163{
164 switch (comp_compatibility_resp) {
165 case PLDM_CCR_COMP_CAN_BE_UPDATED:
166 case PLDM_CCR_COMP_CANNOT_BE_UPDATED:
167 return true;
168
169 default:
170 return false;
171 }
172}
173
174/** @brief Check whether ComponentCompatibilityResponse Code is valid
175 *
176 * @return true if ComponentCompatibilityResponse Code is valid, false if not
177 */
178static bool
179is_comp_compatibility_resp_code_valid(uint8_t comp_compatibility_resp_code)
180{
181 switch (comp_compatibility_resp_code) {
182 case PLDM_CCRC_NO_RESPONSE_CODE:
183 case PLDM_CCRC_COMP_COMPARISON_STAMP_IDENTICAL:
184 case PLDM_CCRC_COMP_COMPARISON_STAMP_LOWER:
185 case PLDM_CCRC_INVALID_COMP_COMPARISON_STAMP:
186 case PLDM_CCRC_COMP_CONFLICT:
187 case PLDM_CCRC_COMP_PREREQUISITES_NOT_MET:
188 case PLDM_CCRC_COMP_NOT_SUPPORTED:
189 case PLDM_CCRC_COMP_SECURITY_RESTRICTIONS:
190 case PLDM_CRC_INCOMPLETE_COMP_IMAGE_SET:
191 case PLDM_CCRC_COMP_INFO_NO_MATCH:
192 case PLDM_CCRC_COMP_VER_STR_IDENTICAL:
193 case PLDM_CCRC_COMP_VER_STR_LOWER:
194 return true;
195
196 default:
197 if (comp_compatibility_resp_code >=
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930198 PLDM_CCRC_VENDOR_COMP_RESP_CODE_RANGE_MIN &&
Andrew Jeffery9c766792022-08-10 23:12:49 +0930199 comp_compatibility_resp_code <=
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930200 PLDM_CCRC_VENDOR_COMP_RESP_CODE_RANGE_MAX) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930201 return true;
202 }
203 return false;
204 }
205}
206
207/** @brief Check whether SelfContainedActivationRequest is valid
208 *
209 * @return true if SelfContainedActivationRequest is valid, false if not
210 */
211static bool
212is_self_contained_activation_req_valid(bool8_t self_contained_activation_req)
213{
214 switch (self_contained_activation_req) {
215 case PLDM_NOT_ACTIVATE_SELF_CONTAINED_COMPONENTS:
216 case PLDM_ACTIVATE_SELF_CONTAINED_COMPONENTS:
217 return true;
218
219 default:
220 return false;
221 }
222}
223
224/** @brief Check if current or previous status in GetStatus command response is
225 * valid
226 *
227 * @param[in] state - current or previous different state machine state of
228 * the FD
229 * @return true if state is valid, false if not
230 */
231static bool is_state_valid(uint8_t state)
232{
233 switch (state) {
234 case PLDM_FD_STATE_IDLE:
235 case PLDM_FD_STATE_LEARN_COMPONENTS:
236 case PLDM_FD_STATE_READY_XFER:
237 case PLDM_FD_STATE_DOWNLOAD:
238 case PLDM_FD_STATE_VERIFY:
239 case PLDM_FD_STATE_APPLY:
240 case PLDM_FD_STATE_ACTIVATE:
241 return true;
242
243 default:
244 return false;
245 }
246}
247
248/** @brief Check if aux state in GetStatus command response is valid
249 *
250 * @param[in] aux_state - provides additional information to the UA to describe
251 * the current operation state of the FD/FDP
252 *
253 * @return true if aux state is valid, false if not
254 */
255static bool is_aux_state_valid(uint8_t aux_state)
256{
257 switch (aux_state) {
258 case PLDM_FD_OPERATION_IN_PROGRESS:
259 case PLDM_FD_OPERATION_SUCCESSFUL:
260 case PLDM_FD_OPERATION_FAILED:
261 case PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER:
262 return true;
263
264 default:
265 return false;
266 }
267}
268
269/** @brief Check if aux state status in GetStatus command response is valid
270 *
271 * @param[in] aux_state_status - aux state status
272 *
273 * @return true if aux state status is valid, false if not
274 */
275static bool is_aux_state_status_valid(uint8_t aux_state_status)
276{
277 if (aux_state_status == PLDM_FD_AUX_STATE_IN_PROGRESS_OR_SUCCESS ||
278 aux_state_status == PLDM_FD_TIMEOUT ||
Andrew Jeffery67f7ed92023-04-05 14:00:00 +0930279 aux_state_status == PLDM_FD_GENERIC_ERROR ||
280 (aux_state_status >= PLDM_FD_VENDOR_DEFINED_STATUS_CODE_START &&
281 aux_state_status <= PLDM_FD_VENDOR_DEFINED_STATUS_CODE_END)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930282 return true;
283 }
284
285 return false;
286}
287
288/** @brief Check if reason code in GetStatus command response is valid
289 *
290 * @param[in] reason_code - provides the reason for why the current state
291 * entered the IDLE state
292 *
293 * @return true if reason code is valid, false if not
294 */
295static bool is_reason_code_valid(uint8_t reason_code)
296{
Andrew Jeffery9c766792022-08-10 23:12:49 +0930297 switch (reason_code) {
298 case PLDM_FD_INITIALIZATION:
299 case PLDM_FD_ACTIVATE_FW:
300 case PLDM_FD_CANCEL_UPDATE:
301 case PLDM_FD_TIMEOUT_LEARN_COMPONENT:
302 case PLDM_FD_TIMEOUT_READY_XFER:
303 case PLDM_FD_TIMEOUT_DOWNLOAD:
304 case PLDM_FD_TIMEOUT_VERIFY:
305 case PLDM_FD_TIMEOUT_APPLY:
306 return true;
307
308 default:
309 if (reason_code >= PLDM_FD_STATUS_VENDOR_DEFINED_MIN) {
310 return true;
311 }
312 return false;
313 }
314}
315
316/** @brief Check if non functioning component indication in CancelUpdate
317 * response is valid
318 *
319 * @return true if non functioning component indication is valid, false if not
320 */
321static bool is_non_functioning_component_indication_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930322 bool8_t non_functioning_component_indication)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930323{
324 switch (non_functioning_component_indication) {
325 case PLDM_FWUP_COMPONENTS_FUNCTIONING:
326 case PLDM_FWUP_COMPONENTS_NOT_FUNCTIONING:
327 return true;
328
329 default:
330 return false;
331 }
332}
333
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030334#define PLDM_FWUP_PACKAGE_HEADER_FIXED_SIZE 36
Andrew Jeffery2613c272025-03-12 14:15:41 +1030335LIBPLDM_CC_NONNULL
336static int
337decode_pldm_package_header_info_errno(const void *data, size_t length,
338 const struct pldm_package_format_pin *pin,
339 pldm_package_header_information_pad *hdr)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930340{
Andrew Jeffery2613c272025-03-12 14:15:41 +1030341 static const struct pldm_package_header_format_revision_info {
342 pldm_uuid identifier;
343 size_t magic;
Carter Chenf72cf6f2025-06-24 15:34:49 +0800344 } revision_info[1 + PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR03H] = {
Andrew Jeffery2613c272025-03-12 14:15:41 +1030345 [0] = {
346 .identifier = {0},
347 .magic = 0,
348 },
349 [PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H] = { /* PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H */
350 .identifier = PLDM_PACKAGE_HEADER_IDENTIFIER_V1_0,
351 .magic =
352 LIBPLDM_SIZEAT(struct pldm__package_header_information, package) +
353 LIBPLDM_SIZEAT(struct pldm_package_firmware_device_id_record, firmware_device_package_data) +
354 LIBPLDM_SIZEAT(struct pldm_descriptor, descriptor_data) +
355 LIBPLDM_SIZEAT(struct pldm_package_component_image_information, component_version_string) +
356 LIBPLDM_SIZEAT(struct pldm_package_iter, infos)
357 },
358 [PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR02H] = { /* PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR02H */
359 .identifier = PLDM_PACKAGE_HEADER_IDENTIFIER_V1_1,
360 .magic =
361 LIBPLDM_SIZEAT(struct pldm__package_header_information, package) +
362 LIBPLDM_SIZEAT(struct pldm_package_firmware_device_id_record, firmware_device_package_data) +
363 LIBPLDM_SIZEAT(struct pldm_descriptor, descriptor_data) +
364 LIBPLDM_SIZEAT(struct pldm_package_downstream_device_id_record, package_data) +
365 LIBPLDM_SIZEAT(struct pldm_package_component_image_information, component_version_string) +
366 LIBPLDM_SIZEAT(struct pldm_package_iter, infos),
367 },
Carter Chenf72cf6f2025-06-24 15:34:49 +0800368 [PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR03H] = { /* PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR03H */
369 .identifier = PLDM_PACKAGE_HEADER_IDENTIFIER_V1_2,
370 .magic =
371 LIBPLDM_SIZEAT(struct pldm__package_header_information, package) +
372 LIBPLDM_SIZEAT(struct pldm_package_firmware_device_id_record, firmware_device_package_data) +
373 LIBPLDM_SIZEAT(struct pldm_descriptor, descriptor_data) +
374 LIBPLDM_SIZEAT(struct pldm_package_downstream_device_id_record, package_data) +
375 LIBPLDM_SIZEAT(struct pldm_package_component_image_information, component_opaque_data) +
376 LIBPLDM_SIZEAT(struct pldm_package_iter, infos),
377 },
Andrew Jeffery2613c272025-03-12 14:15:41 +1030378 };
379
380 const struct pldm_package_header_format_revision_info *info;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030381 uint32_t package_header_checksum = 0;
382 size_t package_header_variable_size;
383 size_t package_header_payload_size;
384 size_t package_header_areas_size;
385 uint16_t package_header_size;
386 PLDM_MSGBUF_DEFINE_P(buf);
387 int checksums = 1;
388 int rc;
389
Andrew Jeffery2613c272025-03-12 14:15:41 +1030390 if (pin->meta.version > 0) {
391 return -ENOTSUP;
392 }
393
394 if (pin->format.revision == 0) {
395 return -EINVAL;
396 }
397
Carter Chenf72cf6f2025-06-24 15:34:49 +0800398 if (pin->format.revision > PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR03H) {
Andrew Jeffery2613c272025-03-12 14:15:41 +1030399 return -ENOTSUP;
400 }
401 static_assert(ARRAY_SIZE(revision_info) ==
Carter Chenf72cf6f2025-06-24 15:34:49 +0800402 1 + PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR03H,
Andrew Jeffery2613c272025-03-12 14:15:41 +1030403 "Mismatched array bounds test");
404
405 info = &revision_info[pin->format.revision];
406 if (memcmp(&pin->format.identifier, info->identifier,
407 sizeof(info->identifier)) != 0) {
408 return -ENOTSUP;
409 }
410
411 if (pin->meta.magic != info->magic) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030412 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930413 }
414
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030415 rc = pldm_msgbuf_init_errno(buf, PLDM_FWUP_PACKAGE_HEADER_FIXED_SIZE,
416 data, length);
417 if (rc) {
418 return rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930419 }
420
Andrew Jeffery2613c272025-03-12 14:15:41 +1030421 rc = pldm_msgbuf_extract_array(buf,
422 sizeof(hdr->package_header_identifier),
423 hdr->package_header_identifier,
424 sizeof(hdr->package_header_identifier));
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030425 if (rc) {
426 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930427 }
428
Andrew Jeffery2613c272025-03-12 14:15:41 +1030429 if (memcmp(revision_info[PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H]
430 .identifier,
431 hdr->package_header_identifier,
432 sizeof(hdr->package_header_identifier)) != 0 &&
433 memcmp(revision_info[PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR02H]
434 .identifier,
435 hdr->package_header_identifier,
Carter Chenf72cf6f2025-06-24 15:34:49 +0800436 sizeof(hdr->package_header_identifier)) != 0 &&
437 memcmp(revision_info[PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR03H]
438 .identifier,
439 hdr->package_header_identifier,
Andrew Jeffery2613c272025-03-12 14:15:41 +1030440 sizeof(hdr->package_header_identifier)) != 0) {
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030441 return pldm_msgbuf_discard(buf, -ENOTSUP);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930442 }
443
Andrew Jeffery2613c272025-03-12 14:15:41 +1030444 rc = pldm_msgbuf_extract(buf, hdr->package_header_format_revision);
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030445 if (rc) {
446 return pldm_msgbuf_discard(buf, rc);
447 }
Andrew Jeffery2613c272025-03-12 14:15:41 +1030448 if (hdr->package_header_format_revision > pin->format.revision) {
449 return pldm_msgbuf_discard(buf, -ENOTSUP);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930450 }
451
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030452 rc = pldm_msgbuf_extract(buf, package_header_size);
453 if (rc) {
454 return pldm_msgbuf_discard(buf, rc);
455 }
456
Andrew Jeffery2613c272025-03-12 14:15:41 +1030457 rc = pldm_msgbuf_extract_array(buf,
458 sizeof(hdr->package_release_date_time),
459 hdr->package_release_date_time,
460 sizeof(hdr->package_release_date_time));
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030461 if (rc) {
462 return pldm_msgbuf_discard(buf, rc);
463 }
464
Andrew Jeffery2613c272025-03-12 14:15:41 +1030465 rc = pldm_msgbuf_extract(buf, hdr->component_bitmap_bit_length);
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030466 if (rc) {
467 return pldm_msgbuf_discard(buf, rc);
468 }
Andrew Jeffery2613c272025-03-12 14:15:41 +1030469 if (hdr->component_bitmap_bit_length & 7) {
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030470 return pldm_msgbuf_discard(buf, -EPROTO);
471 }
472
Andrew Jeffery2613c272025-03-12 14:15:41 +1030473 rc = pldm_msgbuf_extract(buf, hdr->package_version_string_type);
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030474 if (rc) {
475 return pldm_msgbuf_discard(buf, rc);
476 }
Andrew Jeffery2613c272025-03-12 14:15:41 +1030477 if (!is_string_type_valid(hdr->package_version_string_type)) {
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030478 return pldm_msgbuf_discard(buf, -EPROTO);
479 }
480
481 rc = pldm_msgbuf_extract_uint8_to_size(
Andrew Jeffery2613c272025-03-12 14:15:41 +1030482 buf, hdr->package_version_string.length);
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030483 if (rc) {
484 return pldm_msgbuf_discard(buf, rc);
485 }
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030486
Andrew Jeffery2613c272025-03-12 14:15:41 +1030487 pldm_msgbuf_span_required(buf, hdr->package_version_string.length,
488 (void **)&hdr->package_version_string.ptr);
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030489
490 if (package_header_size < (PLDM_FWUP_PACKAGE_HEADER_FIXED_SIZE + 3 +
491 checksums * sizeof(uint32_t))) {
Andrew Jeffery2613c272025-03-12 14:15:41 +1030492 return pldm_msgbuf_discard(buf, -EOVERFLOW);
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030493 }
494 package_header_payload_size =
495 package_header_size - (checksums * sizeof(uint32_t));
496 package_header_variable_size = package_header_payload_size -
497 PLDM_FWUP_PACKAGE_HEADER_FIXED_SIZE;
498
Andrew Jeffery2613c272025-03-12 14:15:41 +1030499 if (package_header_variable_size < hdr->package_version_string.length) {
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030500 return pldm_msgbuf_discard(buf, -EOVERFLOW);
501 }
502
503 package_header_areas_size = package_header_variable_size -
Andrew Jeffery2613c272025-03-12 14:15:41 +1030504 hdr->package_version_string.length;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030505 rc = pldm_msgbuf_span_required(buf, package_header_areas_size,
Andrew Jeffery2613c272025-03-12 14:15:41 +1030506 (void **)&hdr->areas.ptr);
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030507 if (rc) {
508 return pldm_msgbuf_discard(buf, rc);
509 }
Andrew Jeffery2613c272025-03-12 14:15:41 +1030510 hdr->areas.length = package_header_areas_size;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030511
512 pldm_msgbuf_extract(buf, package_header_checksum);
513
514 rc = pldm_msgbuf_complete(buf);
515 if (rc) {
516 return rc;
517 }
518
Carter Chenff78bca2025-06-25 10:33:31 +0800519 rc = pldm_edac_crc32_validate(package_header_checksum, data,
520 package_header_payload_size);
521 if (rc) {
Andrew Jeffery2613c272025-03-12 14:15:41 +1030522#if 0
Carter Chenff78bca2025-06-25 10:33:31 +0800523 printf("header checksum failure, expected: %#08" PRIx32 ", found: %#08" PRIx32 "\n", package_header_checksum, pldm_edac_crc32(data, package_header_payload_size));
Andrew Jeffery2613c272025-03-12 14:15:41 +1030524#endif
Carter Chenff78bca2025-06-25 10:33:31 +0800525 return rc;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030526 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930527
Andrew Jeffery2613c272025-03-12 14:15:41 +1030528 /* We stash these to resolve component images later */
529 hdr->package.ptr = data;
530 hdr->package.length = length;
531
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030532 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930533}
534
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930535LIBPLDM_ABI_STABLE
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030536int decode_pldm_package_header_info(
537 const uint8_t *data, size_t length,
538 struct pldm_package_header_information *package_header_info,
539 struct variable_field *package_version_str)
540{
Andrew Jeffery2613c272025-03-12 14:15:41 +1030541 DEFINE_PLDM_PACKAGE_FORMAT_PIN_FR01H(pin);
542 pldm_package_header_information_pad hdr;
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030543 int rc;
544
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030545 if (!data || !package_header_info || !package_version_str) {
546 return PLDM_ERROR_INVALID_DATA;
547 }
548
Andrew Jeffery2613c272025-03-12 14:15:41 +1030549 rc = decode_pldm_package_header_info_errno(data, length, &pin, &hdr);
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030550 if (rc < 0) {
551 return pldm_xlate_errno(rc);
552 }
553
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030554 static_assert(sizeof(package_header_info->uuid) ==
Andrew Jeffery2613c272025-03-12 14:15:41 +1030555 sizeof(hdr.package_header_identifier),
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030556 "UUID field size");
Andrew Jeffery2613c272025-03-12 14:15:41 +1030557 memcpy(package_header_info->uuid, hdr.package_header_identifier,
558 sizeof(hdr.package_header_identifier));
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030559 package_header_info->package_header_format_version =
Andrew Jeffery2613c272025-03-12 14:15:41 +1030560 hdr.package_header_format_revision;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030561 memcpy(&package_header_info->package_header_size, data + 17,
562 sizeof(package_header_info->package_header_size));
563 LE16TOH(package_header_info->package_header_size);
564 static_assert(sizeof(package_header_info->package_release_date_time) ==
Andrew Jeffery2613c272025-03-12 14:15:41 +1030565 sizeof(hdr.package_release_date_time),
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030566 "TIMESTAMP104 field size");
567 memcpy(package_header_info->package_release_date_time,
Andrew Jeffery2613c272025-03-12 14:15:41 +1030568 hdr.package_release_date_time,
569 sizeof(hdr.package_release_date_time));
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030570 package_header_info->component_bitmap_bit_length =
Andrew Jeffery2613c272025-03-12 14:15:41 +1030571 hdr.component_bitmap_bit_length;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030572 package_header_info->package_version_string_type =
Andrew Jeffery2613c272025-03-12 14:15:41 +1030573 hdr.package_version_string_type;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030574 package_header_info->package_version_string_length =
Andrew Jeffery2613c272025-03-12 14:15:41 +1030575 hdr.package_version_string.length;
576 *package_version_str = hdr.package_version_string;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030577
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030578 return PLDM_SUCCESS;
579}
580
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000581/* Currently only used for decode_firmware_device_id_record_errno() */
582static int pldm_msgbuf_init_dynamic_uint16(struct pldm_msgbuf *buf, size_t req,
Andrew Jeffery2613c272025-03-12 14:15:41 +1030583 void *data, size_t len,
584 void **tail_data, size_t *tail_len)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930585{
Andrew Jeffery2613c272025-03-12 14:15:41 +1030586 size_t dyn_length;
587 void *dyn_start;
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000588 int rc;
589
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000590 rc = pldm_msgbuf_init_errno(buf, req, data, len);
591 if (rc) {
592 return rc;
593 }
Andrew Jeffery2613c272025-03-12 14:15:41 +1030594 /*
595 * Extract the record length from the first field, then reinitialise the msgbuf
596 * after determining that it's safe to do so
597 */
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000598
Andrew Jeffery2613c272025-03-12 14:15:41 +1030599 rc = pldm_msgbuf_extract_uint16_to_size(buf, dyn_length);
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000600 if (rc) {
601 return pldm_msgbuf_discard(buf, rc);
602 }
603
604 rc = pldm_msgbuf_complete(buf);
605 if (rc) {
606 return rc;
607 }
608
609 rc = pldm_msgbuf_init_errno(buf, req, data, len);
610 if (rc) {
611 return rc;
612 }
613
614 /* Ensure there's no arithmetic funkiness and the span is within buffer bounds */
Andrew Jeffery2613c272025-03-12 14:15:41 +1030615 rc = pldm_msgbuf_span_required(buf, dyn_length, &dyn_start);
616 if (rc) {
617 return pldm_msgbuf_discard(buf, rc);
618 }
619
620 rc = pldm_msgbuf_span_remaining(buf, tail_data, tail_len);
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000621 if (rc) {
622 return pldm_msgbuf_discard(buf, rc);
623 }
624
625 rc = pldm_msgbuf_complete(buf);
626 if (rc) {
627 return rc;
628 }
629
Andrew Jeffery2613c272025-03-12 14:15:41 +1030630 return pldm_msgbuf_init_errno(buf, req, dyn_start, dyn_length);
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000631}
632
633#define PLDM_FWUP_FIRMWARE_DEVICE_ID_RECORD_MIN_SIZE 11
Andrew Jeffery2613c272025-03-12 14:15:41 +1030634static int decode_pldm_package_firmware_device_id_record_errno(
635 const pldm_package_header_information_pad *hdr,
636 struct variable_field *field,
637 struct pldm_package_firmware_device_id_record *rec)
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000638{
639 PLDM_MSGBUF_DEFINE_P(buf);
640 uint16_t record_len = 0;
641 int rc;
642
Andrew Jeffery2613c272025-03-12 14:15:41 +1030643 if (!hdr || !field || !rec || !field->ptr) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030644 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930645 }
646
Andrew Jeffery2613c272025-03-12 14:15:41 +1030647 if (hdr->component_bitmap_bit_length & 7) {
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000648 return -EPROTO;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930649 }
650
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000651 rc = pldm_msgbuf_init_dynamic_uint16(
Andrew Jeffery2613c272025-03-12 14:15:41 +1030652 buf, PLDM_FWUP_FIRMWARE_DEVICE_ID_RECORD_MIN_SIZE,
653 (void *)field->ptr, field->length, (void **)&field->ptr,
654 &field->length);
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000655 if (rc) {
656 return rc;
657 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930658
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000659 pldm_msgbuf_extract(buf, record_len);
660 pldm_msgbuf_extract(buf, rec->descriptor_count);
661 pldm_msgbuf_extract(buf, rec->device_update_option_flags.value);
662
663 rc = pldm_msgbuf_extract(buf,
664 rec->component_image_set_version_string_type);
665 if (rc) {
666 return pldm_msgbuf_discard(buf, rc);
667 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930668 if (!is_string_type_valid(
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000669 rec->component_image_set_version_string_type)) {
670 return pldm_msgbuf_discard(buf, -EPROTO);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930671 }
672
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000673 rc = pldm_msgbuf_extract_uint8_to_size(
674 buf, rec->component_image_set_version_string.length);
675 if (rc) {
676 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930677 }
678
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000679 if (rec->component_image_set_version_string.length == 0) {
680 return pldm_msgbuf_discard(buf, -EPROTO);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930681 }
682
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000683 rc = pldm_msgbuf_extract_uint16_to_size(
684 buf, rec->firmware_device_package_data.length);
685 if (rc) {
686 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930687 }
688
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000689 rc = pldm_msgbuf_span_required(
Andrew Jeffery2613c272025-03-12 14:15:41 +1030690 buf, hdr->component_bitmap_bit_length / 8,
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000691 (void **)&rec->applicable_components.bitmap.ptr);
692 if (rc) {
693 return pldm_msgbuf_discard(buf, rc);
694 }
695 rec->applicable_components.bitmap.length =
Andrew Jeffery2613c272025-03-12 14:15:41 +1030696 hdr->component_bitmap_bit_length / 8;
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000697
698 pldm_msgbuf_span_required(
699 buf, rec->component_image_set_version_string.length,
700 (void **)&rec->component_image_set_version_string.ptr);
701
702 pldm_msgbuf_span_until(buf, rec->firmware_device_package_data.length,
703 (void **)&rec->record_descriptors.ptr,
704 &rec->record_descriptors.length);
705
706 pldm_msgbuf_span_required(
707 buf, rec->firmware_device_package_data.length,
708 (void **)&rec->firmware_device_package_data.ptr);
709 if (!rec->firmware_device_package_data.length) {
710 rec->firmware_device_package_data.ptr = NULL;
711 }
712
713 return pldm_msgbuf_complete_consumed(buf);
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030714}
715
716LIBPLDM_ABI_STABLE
717int decode_firmware_device_id_record(
718 const uint8_t *data, size_t length,
719 uint16_t component_bitmap_bit_length,
720 struct pldm_firmware_device_id_record *fw_device_id_record,
721 struct variable_field *applicable_components,
722 struct variable_field *comp_image_set_version_str,
723 struct variable_field *record_descriptors,
724 struct variable_field *fw_device_pkg_data)
725{
Andrew Jeffery2613c272025-03-12 14:15:41 +1030726 struct pldm_package_firmware_device_id_record rec;
727 pldm_package_header_information_pad hdr;
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030728 int rc;
729
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000730 if (!data || !fw_device_id_record || !applicable_components ||
731 !comp_image_set_version_str || !record_descriptors ||
732 !fw_device_pkg_data) {
733 return PLDM_ERROR_INVALID_DATA;
734 }
735
Andrew Jeffery2613c272025-03-12 14:15:41 +1030736 hdr.package_header_format_revision =
737 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H;
738 hdr.component_bitmap_bit_length = component_bitmap_bit_length;
739
740 rc = decode_pldm_package_firmware_device_id_record_errno(
741 &hdr, &(struct variable_field){ data, length }, &rec);
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030742 if (rc < 0) {
743 return pldm_xlate_errno(rc);
744 }
745
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000746 memcpy(&fw_device_id_record->record_length, data,
747 sizeof(fw_device_id_record->record_length));
748 LE16TOH(fw_device_id_record->record_length);
749 fw_device_id_record->descriptor_count = rec.descriptor_count;
750 fw_device_id_record->device_update_option_flags =
751 rec.device_update_option_flags;
752 fw_device_id_record->comp_image_set_version_string_type =
753 rec.component_image_set_version_string_type;
754 fw_device_id_record->comp_image_set_version_string_length =
755 rec.component_image_set_version_string.length;
756 fw_device_id_record->fw_device_pkg_data_length =
757 rec.firmware_device_package_data.length;
758 *applicable_components = rec.applicable_components.bitmap;
759 *comp_image_set_version_str = rec.component_image_set_version_string;
760 *record_descriptors = rec.record_descriptors;
761 *fw_device_pkg_data = rec.firmware_device_package_data;
762
Andrew Jeffery9c766792022-08-10 23:12:49 +0930763 return PLDM_SUCCESS;
764}
765
Unive Tiene5c3f142024-12-13 14:14:19 +0800766LIBPLDM_ABI_STABLE
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030767int decode_pldm_descriptor_from_iter(struct pldm_descriptor_iter *iter,
768 struct pldm_descriptor *desc)
769{
Andrew Jefferya1896962025-03-03 21:41:25 +1030770 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030771 int rc;
772
773 if (!iter || !iter->field || !desc) {
774 return -EINVAL;
775 }
776
777 rc = pldm_msgbuf_init_errno(buf, PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN,
778 iter->field->ptr, iter->field->length);
779 if (rc) {
780 return rc;
781 }
782
783 pldm_msgbuf_extract(buf, desc->descriptor_type);
784 rc = pldm_msgbuf_extract(buf, desc->descriptor_length);
785 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +1030786 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030787 }
788
789 desc->descriptor_data = NULL;
790 pldm_msgbuf_span_required(buf, desc->descriptor_length,
791 (void **)&desc->descriptor_data);
792 iter->field->ptr = NULL;
793 pldm_msgbuf_span_remaining(buf, (void **)&iter->field->ptr,
794 &iter->field->length);
795
Andrew Jeffery70d21c92025-03-05 12:59:42 +1030796 return pldm_msgbuf_complete(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030797}
798
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030799static int decode_descriptor_type_length_value_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030800 const void *data, size_t length, uint16_t *descriptor_type,
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030801 struct variable_field *descriptor_data)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930802{
803 uint16_t descriptor_length = 0;
804
805 if (data == NULL || descriptor_type == NULL ||
806 descriptor_data == NULL) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030807 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930808 }
809
810 if (length < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030811 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930812 }
813
814 struct pldm_descriptor_tlv *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930815 (struct pldm_descriptor_tlv *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930816
817 *descriptor_type = le16toh(entry->descriptor_type);
818 descriptor_length = le16toh(entry->descriptor_length);
819 if (*descriptor_type != PLDM_FWUP_VENDOR_DEFINED) {
820 if (descriptor_length !=
821 get_descriptor_type_length(*descriptor_type)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030822 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930823 }
824 }
825
826 if (length < (sizeof(*descriptor_type) + sizeof(descriptor_length) +
827 descriptor_length)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030828 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930829 }
830
831 descriptor_data->ptr = entry->descriptor_data;
832 descriptor_data->length = descriptor_length;
833
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030834 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930835}
836
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930837LIBPLDM_ABI_STABLE
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030838int decode_descriptor_type_length_value(const uint8_t *data, size_t length,
839 uint16_t *descriptor_type,
840 struct variable_field *descriptor_data)
841{
842 int rc;
843
844 rc = decode_descriptor_type_length_value_errno(
845 data, length, descriptor_type, descriptor_data);
846 if (rc < 0) {
847 return pldm_xlate_errno(rc);
848 }
849
850 return PLDM_SUCCESS;
851}
852
853static int decode_vendor_defined_descriptor_value_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030854 const void *data, size_t length, uint8_t *descriptor_title_str_type,
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930855 struct variable_field *descriptor_title_str,
856 struct variable_field *descriptor_data)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930857{
858 if (data == NULL || descriptor_title_str_type == NULL ||
859 descriptor_title_str == NULL || descriptor_data == NULL) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030860 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930861 }
862
863 if (length < sizeof(struct pldm_vendor_defined_descriptor_title_data)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030864 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930865 }
866
867 struct pldm_vendor_defined_descriptor_title_data *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930868 (struct pldm_vendor_defined_descriptor_title_data *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930869 if (!is_string_type_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930870 entry->vendor_defined_descriptor_title_str_type) ||
Andrew Jeffery9c766792022-08-10 23:12:49 +0930871 (entry->vendor_defined_descriptor_title_str_len == 0)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030872 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930873 }
874
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530875 // Assuming at least 1 byte of VendorDefinedDescriptorData
Andrew Jeffery9c766792022-08-10 23:12:49 +0930876 if (length < (sizeof(struct pldm_vendor_defined_descriptor_title_data) +
877 entry->vendor_defined_descriptor_title_str_len)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030878 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930879 }
880
881 *descriptor_title_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930882 entry->vendor_defined_descriptor_title_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930883 descriptor_title_str->ptr = entry->vendor_defined_descriptor_title_str;
884 descriptor_title_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930885 entry->vendor_defined_descriptor_title_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930886
887 descriptor_data->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930888 descriptor_title_str->ptr + descriptor_title_str->length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930889 descriptor_data->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930890 length -
891 sizeof(entry->vendor_defined_descriptor_title_str_type) -
892 sizeof(entry->vendor_defined_descriptor_title_str_len) -
893 descriptor_title_str->length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930894
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030895 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930896}
897
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930898LIBPLDM_ABI_STABLE
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030899int decode_vendor_defined_descriptor_value(
900 const uint8_t *data, size_t length, uint8_t *descriptor_title_str_type,
901 struct variable_field *descriptor_title_str,
902 struct variable_field *descriptor_data)
903{
904 int rc;
905
906 rc = decode_vendor_defined_descriptor_value_errno(
907 data, length, descriptor_title_str_type, descriptor_title_str,
908 descriptor_data);
909 if (rc < 0) {
910 return pldm_xlate_errno(rc);
911 }
912
913 return PLDM_SUCCESS;
914}
915
916static int decode_pldm_comp_image_info_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030917 const void *data, size_t length,
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930918 struct pldm_component_image_information *pldm_comp_image_info,
919 struct variable_field *comp_version_str)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930920{
921 if (data == NULL || pldm_comp_image_info == NULL ||
922 comp_version_str == NULL) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030923 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930924 }
925
926 if (length < sizeof(struct pldm_component_image_information)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030927 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930928 }
929
930 struct pldm_component_image_information *data_header =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930931 (struct pldm_component_image_information *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930932
933 if (!is_string_type_valid(data_header->comp_version_string_type) ||
934 (data_header->comp_version_string_length == 0)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030935 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930936 }
937
938 if (length < sizeof(struct pldm_component_image_information) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930939 data_header->comp_version_string_length) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030940 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930941 }
942
943 pldm_comp_image_info->comp_classification =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930944 le16toh(data_header->comp_classification);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930945 pldm_comp_image_info->comp_identifier =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930946 le16toh(data_header->comp_identifier);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930947 pldm_comp_image_info->comp_comparison_stamp =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930948 le32toh(data_header->comp_comparison_stamp);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930949 pldm_comp_image_info->comp_options.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930950 le16toh(data_header->comp_options.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930951 pldm_comp_image_info->requested_comp_activation_method.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930952 le16toh(data_header->requested_comp_activation_method.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930953 pldm_comp_image_info->comp_location_offset =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930954 le32toh(data_header->comp_location_offset);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930955 pldm_comp_image_info->comp_size = le32toh(data_header->comp_size);
956 pldm_comp_image_info->comp_version_string_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930957 data_header->comp_version_string_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930958 pldm_comp_image_info->comp_version_string_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930959 data_header->comp_version_string_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930960
961 if ((pldm_comp_image_info->comp_options.bits.bit1 == false &&
962 pldm_comp_image_info->comp_comparison_stamp !=
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930963 PLDM_FWUP_INVALID_COMPONENT_COMPARISON_TIMESTAMP)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030964 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930965 }
966
967 if (pldm_comp_image_info->comp_location_offset == 0 ||
968 pldm_comp_image_info->comp_size == 0) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030969 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930970 }
971
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030972 comp_version_str->ptr = (const uint8_t *)data +
973 sizeof(struct pldm_component_image_information);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930974 comp_version_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930975 pldm_comp_image_info->comp_version_string_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930976
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030977 return 0;
978}
979
980LIBPLDM_ABI_STABLE
981int decode_pldm_comp_image_info(
982 const uint8_t *data, size_t length,
983 struct pldm_component_image_information *pldm_comp_image_info,
984 struct variable_field *comp_version_str)
985{
986 int rc;
987
988 rc = decode_pldm_comp_image_info_errno(
989 data, length, pldm_comp_image_info, comp_version_str);
990 if (rc < 0) {
991 return pldm_xlate_errno(rc);
992 }
993
Andrew Jeffery9c766792022-08-10 23:12:49 +0930994 return PLDM_SUCCESS;
995}
996
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930997LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930998int encode_query_device_identifiers_req(uint8_t instance_id,
999 size_t payload_length,
1000 struct pldm_msg *msg)
1001{
1002 if (msg == NULL) {
1003 return PLDM_ERROR_INVALID_DATA;
1004 }
1005
1006 if (payload_length != PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES) {
1007 return PLDM_ERROR_INVALID_LENGTH;
1008 }
1009
1010 return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
1011 PLDM_QUERY_DEVICE_IDENTIFIERS, msg);
1012}
1013
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301014LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301015int decode_query_device_identifiers_resp(const struct pldm_msg *msg,
1016 size_t payload_length,
1017 uint8_t *completion_code,
1018 uint32_t *device_identifiers_len,
1019 uint8_t *descriptor_count,
1020 uint8_t **descriptor_data)
1021{
1022 if (msg == NULL || completion_code == NULL ||
1023 device_identifiers_len == NULL || descriptor_count == NULL ||
1024 descriptor_data == NULL) {
1025 return PLDM_ERROR_INVALID_DATA;
1026 }
1027
1028 *completion_code = msg->payload[0];
1029 if (PLDM_SUCCESS != *completion_code) {
1030 return PLDM_SUCCESS;
1031 }
1032
1033 if (payload_length <
1034 sizeof(struct pldm_query_device_identifiers_resp)) {
1035 return PLDM_ERROR_INVALID_LENGTH;
1036 }
1037
1038 struct pldm_query_device_identifiers_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301039 (struct pldm_query_device_identifiers_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301040 *device_identifiers_len = le32toh(response->device_identifiers_len);
1041
1042 if (*device_identifiers_len < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {
1043 return PLDM_ERROR_INVALID_LENGTH;
1044 }
1045
1046 if (payload_length !=
1047 sizeof(struct pldm_query_device_identifiers_resp) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301048 *device_identifiers_len) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301049 return PLDM_ERROR_INVALID_LENGTH;
1050 }
1051 *descriptor_count = response->descriptor_count;
1052
1053 if (*descriptor_count == 0) {
1054 return PLDM_ERROR_INVALID_DATA;
1055 }
1056 *descriptor_data =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301057 (uint8_t *)(msg->payload +
1058 sizeof(struct pldm_query_device_identifiers_resp));
Andrew Jeffery9c766792022-08-10 23:12:49 +09301059 return PLDM_SUCCESS;
1060}
1061
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001062LIBPLDM_ABI_TESTING
1063int encode_query_device_identifiers_resp(
1064 uint8_t instance_id, uint8_t descriptor_count,
1065 const struct pldm_descriptor *descriptors, struct pldm_msg *msg,
1066 size_t *payload_length)
1067{
Andrew Jefferya1896962025-03-03 21:41:25 +10301068 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001069 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001070
1071 if (descriptors == NULL || msg == NULL || payload_length == NULL) {
1072 return -EINVAL;
1073 }
1074
1075 if (descriptor_count < 1) {
1076 return -EINVAL;
1077 }
1078
1079 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
1080 PLDM_QUERY_DEVICE_IDENTIFIERS, msg);
1081 if (rc) {
1082 return -EINVAL;
1083 }
1084
1085 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
1086 if (rc) {
1087 return rc;
1088 }
1089
1090 /* Determine total length */
1091 uint32_t device_identifiers_len = 0;
1092 for (uint8_t i = 0; i < descriptor_count; i++) {
1093 const struct pldm_descriptor *d = &descriptors[i];
1094 device_identifiers_len +=
1095 2 * sizeof(uint16_t) + d->descriptor_length;
1096 }
1097
1098 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
1099 pldm_msgbuf_insert(buf, device_identifiers_len);
1100 pldm_msgbuf_insert(buf, descriptor_count);
1101
1102 for (uint8_t i = 0; i < descriptor_count; i++) {
1103 const struct pldm_descriptor *d = &descriptors[i];
1104 pldm_msgbuf_insert(buf, d->descriptor_type);
1105 pldm_msgbuf_insert(buf, d->descriptor_length);
1106 if (d->descriptor_data == NULL) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301107 return pldm_msgbuf_discard(buf, -EINVAL);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001108 }
1109 rc = pldm_msgbuf_insert_array(
1110 buf, d->descriptor_length,
1111 (const uint8_t *)d->descriptor_data,
1112 d->descriptor_length);
1113 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301114 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001115 }
1116 }
1117
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301118 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001119}
1120
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301121LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301122int encode_get_firmware_parameters_req(uint8_t instance_id,
1123 size_t payload_length,
1124 struct pldm_msg *msg)
1125{
1126 if (msg == NULL) {
1127 return PLDM_ERROR_INVALID_DATA;
1128 }
1129
1130 if (payload_length != PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES) {
1131 return PLDM_ERROR_INVALID_LENGTH;
1132 }
1133
1134 return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
1135 PLDM_GET_FIRMWARE_PARAMETERS, msg);
1136}
1137
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301138LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301139int decode_get_firmware_parameters_resp(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301140 const struct pldm_msg *msg, size_t payload_length,
1141 struct pldm_get_firmware_parameters_resp *resp_data,
1142 struct variable_field *active_comp_image_set_ver_str,
1143 struct variable_field *pending_comp_image_set_ver_str,
1144 struct variable_field *comp_parameter_table)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301145{
1146 if (msg == NULL || resp_data == NULL ||
1147 active_comp_image_set_ver_str == NULL ||
1148 pending_comp_image_set_ver_str == NULL ||
1149 comp_parameter_table == NULL || !payload_length) {
1150 return PLDM_ERROR_INVALID_DATA;
1151 }
1152
1153 resp_data->completion_code = msg->payload[0];
1154 if (PLDM_SUCCESS != resp_data->completion_code) {
1155 return PLDM_SUCCESS;
1156 }
1157
1158 if (payload_length < sizeof(struct pldm_get_firmware_parameters_resp)) {
1159 return PLDM_ERROR_INVALID_LENGTH;
1160 }
1161
1162 struct pldm_get_firmware_parameters_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301163 (struct pldm_get_firmware_parameters_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301164
1165 if (!is_string_type_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301166 response->active_comp_image_set_ver_str_type) ||
Andrew Jeffery9c766792022-08-10 23:12:49 +09301167 (response->active_comp_image_set_ver_str_len == 0)) {
1168 return PLDM_ERROR_INVALID_DATA;
1169 }
1170
1171 if (response->pending_comp_image_set_ver_str_len == 0) {
1172 if (response->pending_comp_image_set_ver_str_type !=
1173 PLDM_STR_TYPE_UNKNOWN) {
1174 return PLDM_ERROR_INVALID_DATA;
1175 }
1176 } else {
1177 if (!is_string_type_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301178 response->pending_comp_image_set_ver_str_type)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301179 return PLDM_ERROR_INVALID_DATA;
1180 }
1181 }
1182
1183 size_t partial_response_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301184 sizeof(struct pldm_get_firmware_parameters_resp) +
1185 response->active_comp_image_set_ver_str_len +
1186 response->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301187
1188 if (payload_length < partial_response_length) {
1189 return PLDM_ERROR_INVALID_LENGTH;
1190 }
1191
1192 resp_data->capabilities_during_update.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301193 le32toh(response->capabilities_during_update.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301194 resp_data->comp_count = le16toh(response->comp_count);
1195 resp_data->active_comp_image_set_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301196 response->active_comp_image_set_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301197 resp_data->active_comp_image_set_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301198 response->active_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301199 resp_data->pending_comp_image_set_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301200 response->pending_comp_image_set_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301201 resp_data->pending_comp_image_set_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301202 response->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301203
1204 active_comp_image_set_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301205 msg->payload + sizeof(struct pldm_get_firmware_parameters_resp);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301206 active_comp_image_set_ver_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301207 resp_data->active_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301208
1209 if (resp_data->pending_comp_image_set_ver_str_len != 0) {
1210 pending_comp_image_set_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301211 msg->payload +
1212 sizeof(struct pldm_get_firmware_parameters_resp) +
1213 resp_data->active_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301214 pending_comp_image_set_ver_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301215 resp_data->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301216 } else {
1217 pending_comp_image_set_ver_str->ptr = NULL;
1218 pending_comp_image_set_ver_str->length = 0;
1219 }
1220
1221 if (payload_length > partial_response_length && resp_data->comp_count) {
1222 comp_parameter_table->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301223 msg->payload +
1224 sizeof(struct pldm_get_firmware_parameters_resp) +
1225 resp_data->active_comp_image_set_ver_str_len +
1226 resp_data->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301227 comp_parameter_table->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301228 payload_length - partial_response_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301229 } else {
1230 comp_parameter_table->ptr = NULL;
1231 comp_parameter_table->length = 0;
1232 }
1233
1234 return PLDM_SUCCESS;
1235}
1236
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001237LIBPLDM_ABI_TESTING
1238int encode_get_firmware_parameters_resp(
1239 uint8_t instance_id,
1240 const struct pldm_get_firmware_parameters_resp_full *resp_data,
1241 struct pldm_msg *msg, size_t *payload_length)
1242{
Andrew Jefferya1896962025-03-03 21:41:25 +10301243 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001244 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001245
1246 if (resp_data == NULL || msg == NULL || payload_length == NULL) {
1247 return -EINVAL;
1248 }
1249
1250 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
1251 PLDM_GET_FIRMWARE_PARAMETERS, msg);
1252 if (rc) {
1253 return -EINVAL;
1254 }
1255
1256 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
1257 if (rc) {
1258 return rc;
1259 }
1260
1261 pldm_msgbuf_insert(buf, resp_data->completion_code);
1262 pldm_msgbuf_insert(buf, resp_data->capabilities_during_update.value);
1263 pldm_msgbuf_insert(buf, resp_data->comp_count);
1264 pldm_msgbuf_insert(buf,
1265 resp_data->active_comp_image_set_ver_str.str_type);
1266 pldm_msgbuf_insert(buf,
1267 resp_data->active_comp_image_set_ver_str.str_len);
1268 pldm_msgbuf_insert(buf,
1269 resp_data->pending_comp_image_set_ver_str.str_type);
1270 pldm_msgbuf_insert(buf,
1271 resp_data->pending_comp_image_set_ver_str.str_len);
1272 /* String data appended */
1273 rc = pldm_msgbuf_insert_array(
1274 buf, resp_data->active_comp_image_set_ver_str.str_len,
1275 resp_data->active_comp_image_set_ver_str.str_data,
1276 resp_data->active_comp_image_set_ver_str.str_len);
1277 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301278 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001279 }
1280 rc = pldm_msgbuf_insert_array(
1281 buf, resp_data->pending_comp_image_set_ver_str.str_len,
1282 resp_data->pending_comp_image_set_ver_str.str_data,
1283 resp_data->pending_comp_image_set_ver_str.str_len);
1284 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301285 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001286 }
1287
1288 /* Further calls to encode_get_firmware_parameters_resp_comp_entry
1289 * will populate the remainder */
1290
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301291 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001292}
1293
1294LIBPLDM_ABI_TESTING
1295int encode_get_firmware_parameters_resp_comp_entry(
1296 const struct pldm_component_parameter_entry_full *comp,
1297 uint8_t *payload, size_t *payload_length)
1298{
Andrew Jefferya1896962025-03-03 21:41:25 +10301299 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001300 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001301
1302 if (comp == NULL || payload == NULL || payload_length == NULL) {
1303 return -EINVAL;
1304 }
1305
1306 rc = pldm_msgbuf_init_errno(buf, 0, payload, *payload_length);
1307 if (rc) {
1308 return rc;
1309 }
1310
1311 pldm_msgbuf_insert(buf, comp->comp_classification);
1312 pldm_msgbuf_insert(buf, comp->comp_identifier);
1313 pldm_msgbuf_insert(buf, comp->comp_classification_index);
1314
1315 pldm_msgbuf_insert(buf, comp->active_ver.comparison_stamp);
1316 pldm_msgbuf_insert(buf, (uint8_t)comp->active_ver.str.str_type);
1317 pldm_msgbuf_insert(buf, comp->active_ver.str.str_len);
1318 rc = pldm_msgbuf_insert_array(buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1319 comp->active_ver.date,
1320 PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN);
1321 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301322 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001323 }
1324
1325 pldm_msgbuf_insert(buf, comp->pending_ver.comparison_stamp);
1326 pldm_msgbuf_insert(buf, (uint8_t)comp->pending_ver.str.str_type);
1327 pldm_msgbuf_insert(buf, comp->pending_ver.str.str_len);
1328 rc = pldm_msgbuf_insert_array(buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1329 comp->pending_ver.date,
1330 PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN);
1331 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301332 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001333 }
1334
1335 pldm_msgbuf_insert(buf, comp->comp_activation_methods.value);
1336 pldm_msgbuf_insert(buf, comp->capabilities_during_update.value);
1337
1338 rc = pldm_msgbuf_insert_array(buf, comp->active_ver.str.str_len,
1339 comp->active_ver.str.str_data,
1340 comp->active_ver.str.str_len);
1341 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301342 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001343 }
1344 rc = pldm_msgbuf_insert_array(buf, comp->pending_ver.str.str_len,
1345 comp->pending_ver.str.str_data,
1346 comp->pending_ver.str.str_len);
1347 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301348 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001349 }
1350
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301351 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001352}
1353
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301354LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301355int decode_get_firmware_parameters_resp_comp_entry(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301356 const uint8_t *data, size_t length,
1357 struct pldm_component_parameter_entry *component_data,
1358 struct variable_field *active_comp_ver_str,
1359 struct variable_field *pending_comp_ver_str)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301360{
1361 if (data == NULL || component_data == NULL ||
1362 active_comp_ver_str == NULL || pending_comp_ver_str == NULL) {
1363 return PLDM_ERROR_INVALID_DATA;
1364 }
1365
1366 if (length < sizeof(struct pldm_component_parameter_entry)) {
1367 return PLDM_ERROR_INVALID_LENGTH;
1368 }
1369
1370 struct pldm_component_parameter_entry *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301371 (struct pldm_component_parameter_entry *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301372
1373 size_t entry_length = sizeof(struct pldm_component_parameter_entry) +
1374 entry->active_comp_ver_str_len +
1375 entry->pending_comp_ver_str_len;
1376
1377 if (length < entry_length) {
1378 return PLDM_ERROR_INVALID_LENGTH;
1379 }
1380
1381 component_data->comp_classification =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301382 le16toh(entry->comp_classification);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301383 component_data->comp_identifier = le16toh(entry->comp_identifier);
1384 component_data->comp_classification_index =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301385 entry->comp_classification_index;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301386 component_data->active_comp_comparison_stamp =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301387 le32toh(entry->active_comp_comparison_stamp);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301388 component_data->active_comp_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301389 entry->active_comp_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301390 component_data->active_comp_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301391 entry->active_comp_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301392 memcpy(component_data->active_comp_release_date,
1393 entry->active_comp_release_date,
1394 sizeof(entry->active_comp_release_date));
1395 component_data->pending_comp_comparison_stamp =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301396 le32toh(entry->pending_comp_comparison_stamp);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301397 component_data->pending_comp_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301398 entry->pending_comp_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301399 component_data->pending_comp_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301400 entry->pending_comp_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301401 memcpy(component_data->pending_comp_release_date,
1402 entry->pending_comp_release_date,
1403 sizeof(entry->pending_comp_release_date));
1404 component_data->comp_activation_methods.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301405 le16toh(entry->comp_activation_methods.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301406 component_data->capabilities_during_update.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301407 le32toh(entry->capabilities_during_update.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301408
1409 if (entry->active_comp_ver_str_len != 0) {
1410 active_comp_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301411 data + sizeof(struct pldm_component_parameter_entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301412 active_comp_ver_str->length = entry->active_comp_ver_str_len;
1413 } else {
1414 active_comp_ver_str->ptr = NULL;
1415 active_comp_ver_str->length = 0;
1416 }
1417
1418 if (entry->pending_comp_ver_str_len != 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301419 pending_comp_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301420 data + sizeof(struct pldm_component_parameter_entry) +
1421 entry->active_comp_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301422 pending_comp_ver_str->length = entry->pending_comp_ver_str_len;
1423 } else {
1424 pending_comp_ver_str->ptr = NULL;
1425 pending_comp_ver_str->length = 0;
1426 }
1427 return PLDM_SUCCESS;
1428}
1429
Unive Tiene5c3f142024-12-13 14:14:19 +08001430LIBPLDM_ABI_STABLE
Chris Wang4c1f2c72024-03-21 17:09:44 +08001431int encode_query_downstream_devices_req(uint8_t instance_id,
1432 struct pldm_msg *msg)
1433{
1434 if (msg == NULL) {
Unive Tien71e935c2024-11-25 17:21:43 +08001435 return -EINVAL;
Chris Wang4c1f2c72024-03-21 17:09:44 +08001436 }
1437
Unive Tien71e935c2024-11-25 17:21:43 +08001438 return encode_pldm_header_only_errno(PLDM_REQUEST, instance_id,
1439 PLDM_FWUP,
1440 PLDM_QUERY_DOWNSTREAM_DEVICES,
1441 msg);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001442}
1443
Unive Tiene5c3f142024-12-13 14:14:19 +08001444LIBPLDM_ABI_STABLE
Chris Wang4c1f2c72024-03-21 17:09:44 +08001445int decode_query_downstream_devices_resp(
1446 const struct pldm_msg *msg, size_t payload_length,
1447 struct pldm_query_downstream_devices_resp *resp_data)
1448{
Andrew Jefferya1896962025-03-03 21:41:25 +10301449 PLDM_MSGBUF_DEFINE_P(buf);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001450 int rc;
1451
1452 if (msg == NULL || resp_data == NULL || !payload_length) {
Unive Tien71e935c2024-11-25 17:21:43 +08001453 return -EINVAL;
Chris Wang4c1f2c72024-03-21 17:09:44 +08001454 }
1455
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301456 rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1457 msg->payload, payload_length);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001458 if (rc) {
1459 return rc;
1460 }
1461
1462 rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1463 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301464 return pldm_msgbuf_discard(buf, rc);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001465 }
1466 if (PLDM_SUCCESS != resp_data->completion_code) {
1467 // Return the CC directly without decoding the rest of the payload
Andrew Jefferya1896962025-03-03 21:41:25 +10301468 return pldm_msgbuf_complete(buf);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001469 }
1470
1471 if (payload_length < PLDM_QUERY_DOWNSTREAM_DEVICES_RESP_BYTES) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301472 return pldm_msgbuf_discard(buf, -EBADMSG);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001473 }
1474
1475 rc = pldm_msgbuf_extract(buf,
1476 resp_data->downstream_device_update_supported);
1477 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301478 return pldm_msgbuf_discard(buf, rc);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001479 }
1480
1481 if (!is_downstream_device_update_support_valid(
1482 resp_data->downstream_device_update_supported)) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301483 return pldm_msgbuf_discard(buf, -EINVAL);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001484 }
1485
1486 pldm_msgbuf_extract(buf, resp_data->number_of_downstream_devices);
1487 pldm_msgbuf_extract(buf, resp_data->max_number_of_downstream_devices);
1488 pldm_msgbuf_extract(buf, resp_data->capabilities.value);
1489
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301490 return pldm_msgbuf_complete_consumed(buf);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001491}
1492
Unive Tiene5c3f142024-12-13 14:14:19 +08001493LIBPLDM_ABI_STABLE
Chris Wang458475a2024-03-26 17:59:19 +08001494int encode_query_downstream_identifiers_req(
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001495 uint8_t instance_id,
1496 const struct pldm_query_downstream_identifiers_req *params_req,
1497 struct pldm_msg *msg, size_t payload_length)
Chris Wang458475a2024-03-26 17:59:19 +08001498{
Andrew Jefferya1896962025-03-03 21:41:25 +10301499 PLDM_MSGBUF_DEFINE_P(buf);
Chris Wang458475a2024-03-26 17:59:19 +08001500 int rc;
1501
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001502 if (!msg || !params_req) {
Unive Tien71e935c2024-11-25 17:21:43 +08001503 return -EINVAL;
Chris Wang458475a2024-03-26 17:59:19 +08001504 }
1505
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001506 if (!is_transfer_operation_flag_valid(
1507 (enum transfer_op_flag)
1508 params_req->transfer_operation_flag)) {
Unive Tien71e935c2024-11-25 17:21:43 +08001509 return -EINVAL;
Chris Wang458475a2024-03-26 17:59:19 +08001510 }
1511
1512 struct pldm_header_info header = { 0 };
1513 header.instance = instance_id;
1514 header.msg_type = PLDM_REQUEST;
1515 header.pldm_type = PLDM_FWUP;
1516 header.command = PLDM_QUERY_DOWNSTREAM_IDENTIFIERS;
Unive Tien71e935c2024-11-25 17:21:43 +08001517 rc = pack_pldm_header_errno(&header, &(msg->hdr));
Chris Wang458475a2024-03-26 17:59:19 +08001518 if (rc) {
1519 return rc;
1520 }
1521
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301522 rc = pldm_msgbuf_init_errno(buf,
1523 PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_REQ_BYTES,
1524 msg->payload, payload_length);
Chris Wang458475a2024-03-26 17:59:19 +08001525 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001526 return rc;
Chris Wang458475a2024-03-26 17:59:19 +08001527 }
1528
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001529 pldm_msgbuf_insert(buf, params_req->data_transfer_handle);
Chris Wang458475a2024-03-26 17:59:19 +08001530 // Data correctness has been verified, cast it to 1-byte data directly.
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001531 pldm_msgbuf_insert(buf, params_req->transfer_operation_flag);
Chris Wang458475a2024-03-26 17:59:19 +08001532
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301533 return pldm_msgbuf_complete(buf);
Chris Wang458475a2024-03-26 17:59:19 +08001534}
1535
Unive Tiene5c3f142024-12-13 14:14:19 +08001536LIBPLDM_ABI_STABLE
Chris Wang458475a2024-03-26 17:59:19 +08001537int decode_query_downstream_identifiers_resp(
1538 const struct pldm_msg *msg, size_t payload_length,
1539 struct pldm_query_downstream_identifiers_resp *resp_data,
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301540 struct pldm_downstream_device_iter *iter)
Chris Wang458475a2024-03-26 17:59:19 +08001541{
Andrew Jefferya1896962025-03-03 21:41:25 +10301542 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301543 void *remaining = NULL;
Unive Tien71e935c2024-11-25 17:21:43 +08001544 int rc = 0;
Chris Wang458475a2024-03-26 17:59:19 +08001545
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301546 if (msg == NULL || resp_data == NULL || iter == NULL ||
Chris Wang458475a2024-03-26 17:59:19 +08001547 !payload_length) {
Unive Tien71e935c2024-11-25 17:21:43 +08001548 return -EINVAL;
Chris Wang458475a2024-03-26 17:59:19 +08001549 }
1550
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301551 rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1552 msg->payload, payload_length);
Chris Wang458475a2024-03-26 17:59:19 +08001553 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001554 return rc;
Chris Wang458475a2024-03-26 17:59:19 +08001555 }
1556
1557 rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
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 if (PLDM_SUCCESS != resp_data->completion_code) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301562 return pldm_msgbuf_complete(buf);
Chris Wang458475a2024-03-26 17:59:19 +08001563 }
1564
1565 if (payload_length < PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_RESP_MIN_LEN) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301566 return pldm_msgbuf_discard(buf, -EBADMSG);
Chris Wang458475a2024-03-26 17:59:19 +08001567 }
1568
1569 pldm_msgbuf_extract(buf, resp_data->next_data_transfer_handle);
1570 pldm_msgbuf_extract(buf, resp_data->transfer_flag);
1571
1572 rc = pldm_msgbuf_extract(buf, resp_data->downstream_devices_length);
1573 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301574 return pldm_msgbuf_discard(buf, rc);
Chris Wang458475a2024-03-26 17:59:19 +08001575 }
1576
1577 pldm_msgbuf_extract(buf, resp_data->number_of_downstream_devices);
Andrew Jefferya1896962025-03-03 21:41:25 +10301578 pldm_msgbuf_span_required(buf, resp_data->downstream_devices_length,
1579 &remaining);
Chris Wang458475a2024-03-26 17:59:19 +08001580
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301581 rc = pldm_msgbuf_complete(buf);
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301582 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001583 return rc;
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301584 }
1585
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301586 iter->field.ptr = remaining;
1587 iter->field.length = resp_data->downstream_devices_length;
1588 iter->devs = resp_data->number_of_downstream_devices;
1589
Unive Tien71e935c2024-11-25 17:21:43 +08001590 return 0;
Chris Wang458475a2024-03-26 17:59:19 +08001591}
1592
Unive Tiene5c3f142024-12-13 14:14:19 +08001593LIBPLDM_ABI_STABLE
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301594int decode_pldm_downstream_device_from_iter(
1595 struct pldm_downstream_device_iter *iter,
1596 struct pldm_downstream_device *dev)
1597{
Andrew Jefferya1896962025-03-03 21:41:25 +10301598 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301599 int rc;
1600
Andrew Jefferya1896962025-03-03 21:41:25 +10301601 if (!iter || !iter->field.ptr || !dev) {
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301602 return -EINVAL;
1603 }
1604
1605 rc = pldm_msgbuf_init_errno(buf, 3, iter->field.ptr,
1606 iter->field.length);
1607 if (rc) {
1608 return rc;
1609 }
1610
1611 pldm_msgbuf_extract(buf, dev->downstream_device_index);
1612 pldm_msgbuf_extract(buf, dev->downstream_descriptor_count);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301613 pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
1614 &iter->field.length);
1615
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301616 return pldm_msgbuf_complete(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301617}
1618
Unive Tiene5c3f142024-12-13 14:14:19 +08001619LIBPLDM_ABI_STABLE
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301620int encode_get_downstream_firmware_parameters_req(
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001621 uint8_t instance_id,
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301622 const struct pldm_get_downstream_firmware_parameters_req *params_req,
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001623 struct pldm_msg *msg, size_t payload_length)
Chris Wangb6ef35b2024-07-03 09:35:42 +08001624{
Andrew Jefferya1896962025-03-03 21:41:25 +10301625 PLDM_MSGBUF_DEFINE_P(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001626 int rc;
1627
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001628 if (!msg || !params_req) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001629 return -EINVAL;
1630 }
1631
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001632 if (!is_transfer_operation_flag_valid(
1633 (enum transfer_op_flag)
1634 params_req->transfer_operation_flag)) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001635 return -EBADMSG;
1636 }
1637
1638 struct pldm_header_info header = { 0 };
1639 header.instance = instance_id;
1640 header.msg_type = PLDM_REQUEST;
1641 header.pldm_type = PLDM_FWUP;
1642 header.command = PLDM_QUERY_DOWNSTREAM_FIRMWARE_PARAMETERS;
1643 rc = pack_pldm_header_errno(&header, &msg->hdr);
1644 if (rc < 0) {
1645 return rc;
1646 }
1647
Andrew Jeffery53b08672025-03-04 12:26:18 +10301648 rc = pldm_msgbuf_init_errno(
1649 buf, PLDM_GET_DOWNSTREAM_FIRMWARE_PARAMETERS_REQ_BYTES,
1650 msg->payload, payload_length);
1651 if (rc < 0) {
1652 return rc;
1653 }
1654
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001655 pldm_msgbuf_insert(buf, params_req->data_transfer_handle);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001656 // Data correctness has been verified, cast it to 1-byte data directly.
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001657 pldm_msgbuf_insert(buf, params_req->transfer_operation_flag);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001658
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301659 return pldm_msgbuf_complete(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001660}
1661
Unive Tiene5c3f142024-12-13 14:14:19 +08001662LIBPLDM_ABI_STABLE
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301663int decode_get_downstream_firmware_parameters_resp(
Chris Wangb6ef35b2024-07-03 09:35:42 +08001664 const struct pldm_msg *msg, size_t payload_length,
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301665 struct pldm_get_downstream_firmware_parameters_resp *resp_data,
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301666 struct pldm_downstream_device_parameters_iter *iter)
Chris Wangb6ef35b2024-07-03 09:35:42 +08001667{
Andrew Jefferya1896962025-03-03 21:41:25 +10301668 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301669 void *remaining = NULL;
1670 size_t length;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001671 int rc;
1672
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301673 if (msg == NULL || resp_data == NULL || iter == NULL) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001674 return -EINVAL;
1675 }
1676
1677 rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1678 msg->payload, payload_length);
1679 if (rc < 0) {
1680 return rc;
1681 }
1682
1683 rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1684 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301685 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001686 }
1687 if (PLDM_SUCCESS != resp_data->completion_code) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301688 return pldm_msgbuf_complete(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001689 }
1690
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301691 if (payload_length <
1692 PLDM_GET_DOWNSTREAM_FIRMWARE_PARAMETERS_RESP_MIN_LEN) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301693 return pldm_msgbuf_discard(buf, -EBADMSG);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001694 }
1695
1696 pldm_msgbuf_extract(buf, resp_data->next_data_transfer_handle);
1697 pldm_msgbuf_extract(buf, resp_data->transfer_flag);
1698 pldm_msgbuf_extract(buf,
1699 resp_data->fdp_capabilities_during_update.value);
1700 pldm_msgbuf_extract(buf, resp_data->downstream_device_count);
1701
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301702 rc = pldm_msgbuf_span_remaining(buf, &remaining, &length);
1703 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301704 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301705 }
1706
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301707 rc = pldm_msgbuf_complete(buf);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301708 if (rc) {
1709 return rc;
1710 }
1711
1712 iter->field.ptr = remaining;
1713 iter->field.length = length;
1714 iter->entries = resp_data->downstream_device_count;
1715
1716 return 0;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001717}
1718
Unive Tiene5c3f142024-12-13 14:14:19 +08001719LIBPLDM_ABI_STABLE
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301720int decode_pldm_downstream_device_parameters_entry_from_iter(
1721 struct pldm_downstream_device_parameters_iter *iter,
1722 struct pldm_downstream_device_parameters_entry *entry)
Chris Wangb6ef35b2024-07-03 09:35:42 +08001723{
Andrew Jefferya1896962025-03-03 21:41:25 +10301724 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301725 void *comp_ver_str;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001726 size_t remaining;
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301727 void *cursor;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001728 int rc;
1729
Andrew Jefferya1896962025-03-03 21:41:25 +10301730 if (iter == NULL || iter->field.ptr == NULL || entry == NULL) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001731 return -EINVAL;
1732 }
1733
1734 rc = pldm_msgbuf_init_errno(
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301735 buf, PLDM_DOWNSTREAM_DEVICE_PARAMETERS_ENTRY_MIN_LEN,
1736 iter->field.ptr, iter->field.length);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001737 if (rc < 0) {
1738 return rc;
1739 }
1740
1741 pldm_msgbuf_extract(buf, entry->downstream_device_index);
1742 pldm_msgbuf_extract(buf, entry->active_comp_comparison_stamp);
1743 pldm_msgbuf_extract(buf, entry->active_comp_ver_str_type);
1744 rc = pldm_msgbuf_extract(buf, entry->active_comp_ver_str_len);
1745 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301746 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001747 }
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001748 rc = pldm_msgbuf_extract_array(buf,
1749 PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1750 entry->active_comp_release_date,
1751 sizeof(entry->active_comp_release_date));
1752 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301753 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001754 }
1755
Chris Wangb6ef35b2024-07-03 09:35:42 +08001756 // Fill the last byte with NULL character
1757 entry->active_comp_release_date[PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN] =
1758 '\0';
1759
1760 pldm_msgbuf_extract(buf, entry->pending_comp_comparison_stamp);
1761 pldm_msgbuf_extract(buf, entry->pending_comp_ver_str_type);
1762 rc = pldm_msgbuf_extract(buf, entry->pending_comp_ver_str_len);
1763 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301764 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001765 }
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001766
1767 rc = pldm_msgbuf_extract_array(
1768 buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1769 entry->pending_comp_release_date,
1770 sizeof(entry->pending_comp_release_date));
1771 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301772 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001773 }
1774
Chris Wangb6ef35b2024-07-03 09:35:42 +08001775 // Fill the last byte with NULL character
1776 entry->pending_comp_release_date[PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN] =
1777 '\0';
1778
1779 pldm_msgbuf_extract(buf, entry->comp_activation_methods.value);
1780 pldm_msgbuf_extract(buf, entry->capabilities_during_update.value);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001781
Andrew Jefferya1896962025-03-03 21:41:25 +10301782 rc = pldm_msgbuf_span_required(buf, entry->active_comp_ver_str_len,
1783 &comp_ver_str);
1784 if (rc < 0) {
1785 return pldm_msgbuf_discard(buf, rc);
1786 }
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301787 entry->active_comp_ver_str = comp_ver_str;
1788
Andrew Jefferya1896962025-03-03 21:41:25 +10301789 rc = pldm_msgbuf_span_required(buf, entry->pending_comp_ver_str_len,
1790 &comp_ver_str);
1791 if (rc < 0) {
1792 return pldm_msgbuf_discard(buf, rc);
1793 }
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301794 entry->pending_comp_ver_str = comp_ver_str;
1795
Chris Wangb6ef35b2024-07-03 09:35:42 +08001796 rc = pldm_msgbuf_span_remaining(buf, &cursor, &remaining);
1797 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301798 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001799 }
1800
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301801 iter->field.ptr = cursor;
1802 iter->field.length = remaining;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001803
Andrew Jefferya1896962025-03-03 21:41:25 +10301804 return pldm_msgbuf_complete(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001805}
1806
Sora Su06eadd02025-05-27 11:28:51 +08001807LIBPLDM_ABI_TESTING
1808int encode_request_downstream_device_update_req(
1809 uint8_t instance_id,
1810 const struct pldm_request_downstream_device_update_req *req_data,
1811 struct pldm_msg *msg, size_t *payload_length)
1812{
1813 PLDM_MSGBUF_DEFINE_P(buf);
1814 int rc;
1815
1816 if (!req_data || !msg || !payload_length ||
1817 req_data->maximum_downstream_device_transfer_size <
1818 PLDM_FWUP_BASELINE_TRANSFER_SIZE ||
1819 req_data->maximum_outstanding_transfer_requests <
1820 PLDM_FWUP_MIN_OUTSTANDING_REQ) {
1821 return -EINVAL;
1822 }
1823
1824 rc = encode_pldm_header_only_errno(
1825 PLDM_REQUEST, instance_id, PLDM_FWUP,
1826 PLDM_REQUEST_DOWNSTREAM_DEVICE_UPDATE, msg);
1827 if (rc) {
1828 return rc;
1829 }
1830
1831 rc = pldm_msgbuf_init_errno(buf,
1832 PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES,
1833 msg->payload, *payload_length);
1834 if (rc) {
1835 return rc;
1836 }
1837
1838 pldm_msgbuf_insert(buf,
1839 req_data->maximum_downstream_device_transfer_size);
1840 pldm_msgbuf_insert(buf,
1841 req_data->maximum_outstanding_transfer_requests);
1842 pldm_msgbuf_insert(buf,
1843 req_data->downstream_device_package_data_length);
1844
1845 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
1846}
1847
1848LIBPLDM_ABI_TESTING
1849int decode_request_downstream_device_update_req(
1850 const struct pldm_msg *msg, size_t payload_length,
1851 struct pldm_request_downstream_device_update_req *req)
1852{
1853 int rc;
1854 PLDM_MSGBUF_DEFINE_P(buf);
1855
1856 if (!msg || !req) {
1857 return -EINVAL;
1858 }
1859
1860 rc = pldm_msgbuf_init_errno(buf,
1861 PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES,
1862 msg->payload, payload_length);
1863 if (rc) {
1864 return rc;
1865 }
1866
1867 pldm_msgbuf_extract(buf, req->maximum_downstream_device_transfer_size);
1868 pldm_msgbuf_extract(buf, req->maximum_outstanding_transfer_requests);
1869 pldm_msgbuf_extract(buf, req->downstream_device_package_data_length);
1870
1871 return pldm_msgbuf_complete_consumed(buf);
1872}
1873
1874LIBPLDM_ABI_TESTING
1875int encode_request_downstream_device_update_resp(
1876 uint8_t instance_id,
1877 const struct pldm_request_downstream_device_update_resp *resp_data,
1878 struct pldm_msg *msg, size_t *payload_length)
1879{
1880 PLDM_MSGBUF_DEFINE_P(buf);
1881 int rc;
1882
1883 if (!resp_data || !msg || !payload_length) {
1884 return -EINVAL;
1885 }
1886
1887 rc = encode_pldm_header_only_errno(
1888 PLDM_RESPONSE, instance_id, PLDM_FWUP,
1889 PLDM_REQUEST_DOWNSTREAM_DEVICE_UPDATE, msg);
1890 if (rc) {
1891 return rc;
1892 }
1893
1894 rc = pldm_msgbuf_init_errno(
1895 buf, PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES, msg->payload,
1896 *payload_length);
1897 if (rc) {
1898 return rc;
1899 }
1900
1901 pldm_msgbuf_insert(buf, resp_data->completion_code);
1902 pldm_msgbuf_insert(buf, resp_data->downstream_device_meta_data_length);
1903 pldm_msgbuf_insert(
1904 buf, resp_data->downstream_device_will_send_get_package_data);
1905 pldm_msgbuf_insert(buf,
1906 resp_data->get_package_data_maximum_transfer_size);
1907
1908 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
1909}
1910
1911LIBPLDM_ABI_TESTING
1912int decode_request_downstream_device_update_resp(
1913 const struct pldm_msg *msg, size_t payload_length,
1914 struct pldm_request_downstream_device_update_resp *resp_data)
1915{
1916 PLDM_MSGBUF_DEFINE_P(buf);
1917 int rc;
1918
1919 if (!msg || !resp_data) {
1920 return -EINVAL;
1921 }
1922
1923 rc = pldm_msg_has_error(msg,
1924 PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES);
1925 if (rc) {
1926 resp_data->completion_code = rc;
1927 return 0;
1928 }
1929
1930 rc = pldm_msgbuf_init_errno(
1931 buf, PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES, msg->payload,
1932 payload_length);
1933 if (rc) {
1934 return rc;
1935 }
1936
1937 pldm_msgbuf_extract(buf, resp_data->completion_code);
1938 pldm_msgbuf_extract(buf, resp_data->downstream_device_meta_data_length);
1939 pldm_msgbuf_extract(
1940 buf, resp_data->downstream_device_will_send_get_package_data);
1941 pldm_msgbuf_extract(buf,
1942 resp_data->get_package_data_maximum_transfer_size);
1943
1944 return pldm_msgbuf_complete_consumed(buf);
1945}
1946
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301947LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301948int encode_request_update_req(uint8_t instance_id, uint32_t max_transfer_size,
1949 uint16_t num_of_comp,
1950 uint8_t max_outstanding_transfer_req,
1951 uint16_t pkg_data_len,
1952 uint8_t comp_image_set_ver_str_type,
1953 uint8_t comp_image_set_ver_str_len,
1954 const struct variable_field *comp_img_set_ver_str,
1955 struct pldm_msg *msg, size_t payload_length)
1956{
1957 if (comp_img_set_ver_str == NULL || comp_img_set_ver_str->ptr == NULL ||
1958 msg == NULL) {
1959 return PLDM_ERROR_INVALID_DATA;
1960 }
1961
1962 if (payload_length != sizeof(struct pldm_request_update_req) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301963 comp_img_set_ver_str->length) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301964 return PLDM_ERROR_INVALID_LENGTH;
1965 }
1966
1967 if ((comp_image_set_ver_str_len == 0) ||
1968 (comp_image_set_ver_str_len != comp_img_set_ver_str->length)) {
1969 return PLDM_ERROR_INVALID_DATA;
1970 }
1971
1972 if ((max_transfer_size < PLDM_FWUP_BASELINE_TRANSFER_SIZE) ||
1973 (max_outstanding_transfer_req < PLDM_FWUP_MIN_OUTSTANDING_REQ)) {
1974 return PLDM_ERROR_INVALID_DATA;
1975 }
1976
1977 if (!is_string_type_valid(comp_image_set_ver_str_type)) {
1978 return PLDM_ERROR_INVALID_DATA;
1979 }
1980
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301981 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09301982 header.instance = instance_id;
1983 header.msg_type = PLDM_REQUEST;
1984 header.pldm_type = PLDM_FWUP;
1985 header.command = PLDM_REQUEST_UPDATE;
1986 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1987 if (rc) {
1988 return rc;
1989 }
1990
1991 struct pldm_request_update_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301992 (struct pldm_request_update_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301993
1994 request->max_transfer_size = htole32(max_transfer_size);
1995 request->num_of_comp = htole16(num_of_comp);
1996 request->max_outstanding_transfer_req = max_outstanding_transfer_req;
1997 request->pkg_data_len = htole16(pkg_data_len);
1998 request->comp_image_set_ver_str_type = comp_image_set_ver_str_type;
1999 request->comp_image_set_ver_str_len = comp_image_set_ver_str_len;
2000
2001 memcpy(msg->payload + sizeof(struct pldm_request_update_req),
2002 comp_img_set_ver_str->ptr, comp_img_set_ver_str->length);
2003
2004 return PLDM_SUCCESS;
2005}
2006
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002007LIBPLDM_ABI_TESTING
2008int decode_request_update_req(const struct pldm_msg *msg, size_t payload_length,
2009 struct pldm_request_update_req_full *req)
2010{
2011 int rc;
2012 uint8_t t;
Andrew Jefferya1896962025-03-03 21:41:25 +10302013 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002014
2015 if (msg == NULL || req == NULL) {
2016 return -EINVAL;
2017 }
2018
2019 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2020 if (rc) {
2021 return rc;
2022 }
2023
2024 pldm_msgbuf_extract(buf, req->max_transfer_size);
2025 pldm_msgbuf_extract(buf, req->num_of_comp);
2026 pldm_msgbuf_extract(buf, req->max_outstanding_transfer_req);
2027 pldm_msgbuf_extract(buf, req->pkg_data_len);
2028 rc = pldm_msgbuf_extract(buf, t);
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 if (t > PLDM_STR_TYPE_UTF_16BE) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302033 return pldm_msgbuf_discard(buf, -EBADMSG);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002034 }
2035 req->image_set_ver.str_type = (enum pldm_firmware_update_string_type)t;
2036 pldm_msgbuf_extract(buf, req->image_set_ver.str_len);
2037 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302038 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002039 }
2040
2041 rc = pldm_msgbuf_extract_array(buf, req->image_set_ver.str_len,
2042 req->image_set_ver.str_data,
2043 PLDM_FIRMWARE_MAX_STRING);
2044 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302045 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002046 }
2047
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302048 return pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002049}
2050
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302051LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302052int decode_request_update_resp(const struct pldm_msg *msg,
2053 size_t payload_length, uint8_t *completion_code,
2054 uint16_t *fd_meta_data_len,
2055 uint8_t *fd_will_send_pkg_data)
2056{
2057 if (msg == NULL || completion_code == NULL ||
2058 fd_meta_data_len == NULL || fd_will_send_pkg_data == NULL ||
2059 !payload_length) {
2060 return PLDM_ERROR_INVALID_DATA;
2061 }
2062
2063 *completion_code = msg->payload[0];
2064 if (*completion_code != PLDM_SUCCESS) {
2065 return PLDM_SUCCESS;
2066 }
2067
2068 if (payload_length != sizeof(struct pldm_request_update_resp)) {
2069 return PLDM_ERROR_INVALID_LENGTH;
2070 }
2071
2072 struct pldm_request_update_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302073 (struct pldm_request_update_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302074
2075 *fd_meta_data_len = le16toh(response->fd_meta_data_len);
2076 *fd_will_send_pkg_data = response->fd_will_send_pkg_data;
2077
2078 return PLDM_SUCCESS;
2079}
2080
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002081LIBPLDM_ABI_TESTING
2082int encode_request_update_resp(uint8_t instance_id,
2083 const struct pldm_request_update_resp *resp_data,
2084 struct pldm_msg *msg, size_t *payload_length)
2085{
Andrew Jefferya1896962025-03-03 21:41:25 +10302086 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002087 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002088
2089 if (msg == NULL || payload_length == NULL) {
2090 return -EINVAL;
2091 }
2092
2093 struct pldm_header_info header = {
2094 .instance = instance_id,
2095 .msg_type = PLDM_RESPONSE,
2096 .pldm_type = PLDM_FWUP,
2097 .command = PLDM_REQUEST_UPDATE,
2098 };
2099 rc = pack_pldm_header(&header, &(msg->hdr));
2100 if (rc) {
2101 return -EINVAL;
2102 }
2103
2104 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2105 if (rc) {
2106 return rc;
2107 }
2108
2109 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2110 pldm_msgbuf_insert(buf, resp_data->fd_meta_data_len);
2111 pldm_msgbuf_insert(buf, resp_data->fd_will_send_pkg_data);
2112
2113 /* TODO: DSP0267 1.3.0 adds GetPackageDataMaximumTransferSize */
2114
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302115 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002116}
2117
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302118LIBPLDM_ABI_STABLE
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302119int encode_pass_component_table_req(uint8_t instance_id, uint8_t transfer_flag,
2120 uint16_t comp_classification,
2121 uint16_t comp_identifier,
2122 uint8_t comp_classification_index,
2123 uint32_t comp_comparison_stamp,
2124 uint8_t comp_ver_str_type,
2125 uint8_t comp_ver_str_len,
2126 const struct variable_field *comp_ver_str,
2127 struct pldm_msg *msg, size_t payload_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09302128{
2129 if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) {
2130 return PLDM_ERROR_INVALID_DATA;
2131 }
2132
2133 if (payload_length != sizeof(struct pldm_pass_component_table_req) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302134 comp_ver_str->length) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302135 return PLDM_ERROR_INVALID_LENGTH;
2136 }
2137
2138 if ((comp_ver_str_len == 0) ||
2139 (comp_ver_str_len != comp_ver_str->length)) {
2140 return PLDM_ERROR_INVALID_DATA;
2141 }
2142
2143 if (!is_transfer_flag_valid(transfer_flag)) {
Manojkiran Eda3643e742025-05-19 12:03:54 +05302144 return PLDM_FWUP_INVALID_TRANSFER_OPERATION_FLAG;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302145 }
2146
2147 if (!is_string_type_valid(comp_ver_str_type)) {
2148 return PLDM_ERROR_INVALID_DATA;
2149 }
2150
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302151 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302152 header.instance = instance_id;
2153 header.msg_type = PLDM_REQUEST;
2154 header.pldm_type = PLDM_FWUP;
2155 header.command = PLDM_PASS_COMPONENT_TABLE;
2156 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2157 if (rc) {
2158 return rc;
2159 }
2160
2161 struct pldm_pass_component_table_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302162 (struct pldm_pass_component_table_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302163
2164 request->transfer_flag = transfer_flag;
2165 request->comp_classification = htole16(comp_classification);
2166 request->comp_identifier = htole16(comp_identifier);
2167 request->comp_classification_index = comp_classification_index;
2168 request->comp_comparison_stamp = htole32(comp_comparison_stamp);
2169 request->comp_ver_str_type = comp_ver_str_type;
2170 request->comp_ver_str_len = comp_ver_str_len;
2171
2172 memcpy(msg->payload + sizeof(struct pldm_pass_component_table_req),
2173 comp_ver_str->ptr, comp_ver_str->length);
2174
2175 return PLDM_SUCCESS;
2176}
2177
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002178LIBPLDM_ABI_TESTING
2179int decode_pass_component_table_req(
2180 const struct pldm_msg *msg, size_t payload_length,
2181 struct pldm_pass_component_table_req_full *pcomp)
2182{
2183 int rc;
2184 uint8_t t;
Andrew Jefferya1896962025-03-03 21:41:25 +10302185 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002186
2187 if (msg == NULL || pcomp == NULL) {
2188 return -EINVAL;
2189 }
2190
2191 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2192 if (rc) {
2193 return rc;
2194 }
2195
2196 pldm_msgbuf_extract(buf, pcomp->transfer_flag);
2197 pldm_msgbuf_extract(buf, pcomp->comp_classification);
2198 pldm_msgbuf_extract(buf, pcomp->comp_identifier);
2199 pldm_msgbuf_extract(buf, pcomp->comp_classification_index);
2200 pldm_msgbuf_extract(buf, pcomp->comp_comparison_stamp);
2201 rc = pldm_msgbuf_extract(buf, t);
2202 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302203 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002204 }
2205 if (t > PLDM_STR_TYPE_UTF_16BE) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302206 return pldm_msgbuf_discard(buf, -EBADMSG);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002207 }
2208 pcomp->version.str_type = (enum pldm_firmware_update_string_type)t;
2209 rc = pldm_msgbuf_extract(buf, pcomp->version.str_len);
2210 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302211 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002212 }
2213 rc = pldm_msgbuf_extract_array(buf, pcomp->version.str_len,
2214 pcomp->version.str_data,
2215 PLDM_FIRMWARE_MAX_STRING);
2216 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302217 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002218 }
2219
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302220 return pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002221}
2222
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302223LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302224int decode_pass_component_table_resp(const struct pldm_msg *msg,
2225 const size_t payload_length,
2226 uint8_t *completion_code,
2227 uint8_t *comp_resp,
2228 uint8_t *comp_resp_code)
2229{
2230 if (msg == NULL || completion_code == NULL || comp_resp == NULL ||
2231 comp_resp_code == NULL || !payload_length) {
2232 return PLDM_ERROR_INVALID_DATA;
2233 }
2234
2235 *completion_code = msg->payload[0];
2236 if (*completion_code != PLDM_SUCCESS) {
2237 return PLDM_SUCCESS;
2238 }
2239
2240 if (payload_length != sizeof(struct pldm_pass_component_table_resp)) {
2241 return PLDM_ERROR_INVALID_LENGTH;
2242 }
2243
2244 struct pldm_pass_component_table_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302245 (struct pldm_pass_component_table_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302246
2247 if (!is_comp_resp_valid(response->comp_resp)) {
2248 return PLDM_ERROR_INVALID_DATA;
2249 }
2250
2251 if (!is_comp_resp_code_valid(response->comp_resp_code)) {
2252 return PLDM_ERROR_INVALID_DATA;
2253 }
2254
2255 *comp_resp = response->comp_resp;
2256 *comp_resp_code = response->comp_resp_code;
2257
2258 return PLDM_SUCCESS;
2259}
2260
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002261LIBPLDM_ABI_TESTING
2262int encode_pass_component_table_resp(
2263 uint8_t instance_id,
2264 const struct pldm_pass_component_table_resp *resp_data,
2265 struct pldm_msg *msg, size_t *payload_length)
2266{
Andrew Jefferya1896962025-03-03 21:41:25 +10302267 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002268 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002269
2270 if (msg == NULL || payload_length == NULL) {
2271 return -EINVAL;
2272 }
2273
2274 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2275 PLDM_PASS_COMPONENT_TABLE, msg);
2276 if (rc) {
2277 return -EINVAL;
2278 }
2279
2280 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2281 if (rc) {
2282 return rc;
2283 }
2284
2285 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2286 pldm_msgbuf_insert(buf, resp_data->comp_resp);
2287 pldm_msgbuf_insert(buf, resp_data->comp_resp_code);
2288
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302289 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002290}
2291
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302292LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302293int encode_update_component_req(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302294 uint8_t instance_id, uint16_t comp_classification,
2295 uint16_t comp_identifier, uint8_t comp_classification_index,
2296 uint32_t comp_comparison_stamp, uint32_t comp_image_size,
2297 bitfield32_t update_option_flags, uint8_t comp_ver_str_type,
2298 uint8_t comp_ver_str_len, const struct variable_field *comp_ver_str,
2299 struct pldm_msg *msg, size_t payload_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09302300{
2301 if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) {
2302 return PLDM_ERROR_INVALID_DATA;
2303 }
2304
2305 if (payload_length !=
2306 sizeof(struct pldm_update_component_req) + comp_ver_str->length) {
2307 return PLDM_ERROR_INVALID_LENGTH;
2308 }
2309
2310 if (!comp_image_size) {
2311 return PLDM_ERROR_INVALID_DATA;
2312 }
2313
2314 if ((comp_ver_str_len == 0) ||
2315 (comp_ver_str_len != comp_ver_str->length)) {
2316 return PLDM_ERROR_INVALID_DATA;
2317 }
2318
2319 if (!is_string_type_valid(comp_ver_str_type)) {
2320 return PLDM_ERROR_INVALID_DATA;
2321 }
2322
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302323 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302324 header.instance = instance_id;
2325 header.msg_type = PLDM_REQUEST;
2326 header.pldm_type = PLDM_FWUP;
2327 header.command = PLDM_UPDATE_COMPONENT;
2328 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2329 if (rc) {
2330 return rc;
2331 }
2332
2333 struct pldm_update_component_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302334 (struct pldm_update_component_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302335
2336 request->comp_classification = htole16(comp_classification);
2337 request->comp_identifier = htole16(comp_identifier);
2338 request->comp_classification_index = comp_classification_index;
2339 request->comp_comparison_stamp = htole32(comp_comparison_stamp);
2340 request->comp_image_size = htole32(comp_image_size);
2341 request->update_option_flags.value = htole32(update_option_flags.value);
2342 request->comp_ver_str_type = comp_ver_str_type;
2343 request->comp_ver_str_len = comp_ver_str_len;
2344
2345 memcpy(msg->payload + sizeof(struct pldm_update_component_req),
2346 comp_ver_str->ptr, comp_ver_str->length);
2347
2348 return PLDM_SUCCESS;
2349}
2350
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002351LIBPLDM_ABI_TESTING
2352int decode_update_component_req(const struct pldm_msg *msg,
2353 size_t payload_length,
2354 struct pldm_update_component_req_full *up)
2355{
2356 int rc;
2357 uint8_t t;
Andrew Jefferya1896962025-03-03 21:41:25 +10302358 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002359
2360 if (msg == NULL || up == NULL) {
2361 return -EINVAL;
2362 }
2363
2364 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2365 if (rc) {
2366 return rc;
2367 }
2368
2369 pldm_msgbuf_extract(buf, up->comp_classification);
2370 pldm_msgbuf_extract(buf, up->comp_identifier);
2371 pldm_msgbuf_extract(buf, up->comp_classification_index);
2372 pldm_msgbuf_extract(buf, up->comp_comparison_stamp);
2373 pldm_msgbuf_extract(buf, up->comp_image_size);
2374 pldm_msgbuf_extract(buf, up->update_option_flags.value);
2375 rc = pldm_msgbuf_extract(buf, t);
2376 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302377 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002378 }
2379 if (t > PLDM_STR_TYPE_UTF_16BE) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302380 return pldm_msgbuf_discard(buf, -EBADMSG);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002381 }
2382 up->version.str_type = (enum pldm_firmware_update_string_type)t;
2383 rc = pldm_msgbuf_extract(buf, up->version.str_len);
2384 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302385 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002386 }
2387 rc = pldm_msgbuf_extract_array(buf, up->version.str_len,
2388 up->version.str_data,
2389 PLDM_FIRMWARE_MAX_STRING);
2390 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302391 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002392 }
2393
Andrew Jefferya1896962025-03-03 21:41:25 +10302394 return pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002395}
2396
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302397LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302398int decode_update_component_resp(const struct pldm_msg *msg,
2399 size_t payload_length,
2400 uint8_t *completion_code,
2401 uint8_t *comp_compatibility_resp,
2402 uint8_t *comp_compatibility_resp_code,
2403 bitfield32_t *update_option_flags_enabled,
2404 uint16_t *time_before_req_fw_data)
2405{
2406 if (msg == NULL || completion_code == NULL ||
2407 comp_compatibility_resp == NULL ||
2408 comp_compatibility_resp_code == NULL ||
2409 update_option_flags_enabled == NULL ||
2410 time_before_req_fw_data == NULL || !payload_length) {
2411 return PLDM_ERROR_INVALID_DATA;
2412 }
2413
2414 *completion_code = msg->payload[0];
2415 if (*completion_code != PLDM_SUCCESS) {
2416 return PLDM_SUCCESS;
2417 }
2418
2419 if (payload_length != sizeof(struct pldm_update_component_resp)) {
2420 return PLDM_ERROR_INVALID_LENGTH;
2421 }
2422
2423 struct pldm_update_component_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302424 (struct pldm_update_component_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302425
2426 if (!is_comp_compatibility_resp_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302427 response->comp_compatibility_resp)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302428 return PLDM_ERROR_INVALID_DATA;
2429 }
2430
2431 if (!is_comp_compatibility_resp_code_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302432 response->comp_compatibility_resp_code)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302433 return PLDM_ERROR_INVALID_DATA;
2434 }
2435
2436 *comp_compatibility_resp = response->comp_compatibility_resp;
2437 *comp_compatibility_resp_code = response->comp_compatibility_resp_code;
2438 update_option_flags_enabled->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302439 le32toh(response->update_option_flags_enabled.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302440 *time_before_req_fw_data = le16toh(response->time_before_req_fw_data);
2441
2442 return PLDM_SUCCESS;
2443}
2444
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002445LIBPLDM_ABI_TESTING
2446int encode_update_component_resp(
2447 uint8_t instance_id, const struct pldm_update_component_resp *resp_data,
2448 struct pldm_msg *msg, size_t *payload_length)
2449{
Andrew Jefferya1896962025-03-03 21:41:25 +10302450 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002451 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002452
2453 if (msg == NULL || payload_length == NULL) {
2454 return -EINVAL;
2455 }
2456
2457 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2458 PLDM_UPDATE_COMPONENT, msg);
2459 if (rc) {
2460 return -EINVAL;
2461 }
2462
2463 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2464 if (rc) {
2465 return rc;
2466 }
2467
2468 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2469 pldm_msgbuf_insert(buf, resp_data->comp_compatibility_resp);
2470 pldm_msgbuf_insert(buf, resp_data->comp_compatibility_resp_code);
2471 pldm_msgbuf_insert(buf, resp_data->update_option_flags_enabled.value);
2472 pldm_msgbuf_insert(buf, resp_data->time_before_req_fw_data);
2473
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302474 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002475}
2476
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302477LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302478int decode_request_firmware_data_req(const struct pldm_msg *msg,
2479 size_t payload_length, uint32_t *offset,
2480 uint32_t *length)
2481{
2482 if (msg == NULL || offset == NULL || length == NULL) {
2483 return PLDM_ERROR_INVALID_DATA;
2484 }
2485 if (payload_length != sizeof(struct pldm_request_firmware_data_req)) {
2486 return PLDM_ERROR_INVALID_LENGTH;
2487 }
2488 struct pldm_request_firmware_data_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302489 (struct pldm_request_firmware_data_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302490 *offset = le32toh(request->offset);
2491 *length = le32toh(request->length);
2492
2493 if (*length < PLDM_FWUP_BASELINE_TRANSFER_SIZE) {
2494 return PLDM_FWUP_INVALID_TRANSFER_LENGTH;
2495 }
2496
2497 return PLDM_SUCCESS;
2498}
2499
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002500LIBPLDM_ABI_TESTING
2501int encode_request_firmware_data_req(
2502 uint8_t instance_id,
2503 const struct pldm_request_firmware_data_req *req_params,
2504 struct pldm_msg *msg, size_t *payload_length)
2505{
Andrew Jefferya1896962025-03-03 21:41:25 +10302506 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002507 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002508
2509 if (msg == NULL || payload_length == NULL) {
2510 return -EINVAL;
2511 }
2512
2513 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2514 PLDM_REQUEST_FIRMWARE_DATA, msg);
2515 if (rc) {
2516 return -EINVAL;
2517 }
2518
2519 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2520 if (rc) {
2521 return rc;
2522 }
2523
2524 pldm_msgbuf_insert(buf, req_params->offset);
2525 pldm_msgbuf_insert(buf, req_params->length);
2526
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302527 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002528}
2529
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302530LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302531int encode_request_firmware_data_resp(uint8_t instance_id,
2532 uint8_t completion_code,
2533 struct pldm_msg *msg,
2534 size_t payload_length)
2535{
2536 if (msg == NULL || !payload_length) {
2537 return PLDM_ERROR_INVALID_DATA;
2538 }
2539
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302540 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302541 header.instance = instance_id;
2542 header.msg_type = PLDM_RESPONSE;
2543 header.pldm_type = PLDM_FWUP;
2544 header.command = PLDM_REQUEST_FIRMWARE_DATA;
2545 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2546 if (rc) {
2547 return rc;
2548 }
2549
2550 msg->payload[0] = completion_code;
2551
2552 return PLDM_SUCCESS;
2553}
2554
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302555LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302556int decode_transfer_complete_req(const struct pldm_msg *msg,
2557 size_t payload_length,
2558 uint8_t *transfer_result)
2559{
2560 if (msg == NULL || transfer_result == NULL) {
2561 return PLDM_ERROR_INVALID_DATA;
2562 }
2563
2564 if (payload_length != sizeof(*transfer_result)) {
2565 return PLDM_ERROR_INVALID_LENGTH;
2566 }
2567
2568 *transfer_result = msg->payload[0];
2569 return PLDM_SUCCESS;
2570}
2571
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002572LIBPLDM_ABI_TESTING
2573int encode_transfer_complete_req(uint8_t instance_id, uint8_t transfer_result,
2574 struct pldm_msg *msg, size_t *payload_length)
2575{
Andrew Jefferya1896962025-03-03 21:41:25 +10302576 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002577 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002578
2579 if (msg == NULL || payload_length == NULL) {
2580 return -EINVAL;
2581 }
2582
2583 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2584 PLDM_TRANSFER_COMPLETE, msg);
2585 if (rc) {
2586 return -EINVAL;
2587 }
2588
2589 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2590 if (rc) {
2591 return rc;
2592 }
2593
Andrew Jefferya1896962025-03-03 21:41:25 +10302594 pldm_msgbuf_insert(buf, transfer_result);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002595
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302596 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002597}
2598
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302599LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302600int encode_transfer_complete_resp(uint8_t instance_id, uint8_t completion_code,
2601 struct pldm_msg *msg, size_t payload_length)
2602{
2603 if (msg == NULL) {
2604 return PLDM_ERROR_INVALID_DATA;
2605 }
2606
2607 if (payload_length != sizeof(completion_code)) {
2608 return PLDM_ERROR_INVALID_LENGTH;
2609 }
2610
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302611 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302612 header.instance = instance_id;
2613 header.msg_type = PLDM_RESPONSE;
2614 header.pldm_type = PLDM_FWUP;
2615 header.command = PLDM_TRANSFER_COMPLETE;
2616 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2617 if (rc) {
2618 return rc;
2619 }
2620
2621 msg->payload[0] = completion_code;
2622
2623 return PLDM_SUCCESS;
2624}
2625
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302626LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302627int decode_verify_complete_req(const struct pldm_msg *msg,
2628 size_t payload_length, uint8_t *verify_result)
2629{
2630 if (msg == NULL || verify_result == NULL) {
2631 return PLDM_ERROR_INVALID_DATA;
2632 }
2633
2634 if (payload_length != sizeof(*verify_result)) {
2635 return PLDM_ERROR_INVALID_LENGTH;
2636 }
2637
2638 *verify_result = msg->payload[0];
2639 return PLDM_SUCCESS;
2640}
2641
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002642LIBPLDM_ABI_TESTING
2643int encode_verify_complete_req(uint8_t instance_id, uint8_t verify_result,
2644 struct pldm_msg *msg, size_t *payload_length)
2645{
Andrew Jefferya1896962025-03-03 21:41:25 +10302646 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002647 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002648
2649 if (msg == NULL || payload_length == NULL) {
2650 return -EINVAL;
2651 }
2652
2653 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2654 PLDM_VERIFY_COMPLETE, msg);
2655 if (rc) {
2656 return EINVAL;
2657 }
2658
2659 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2660 if (rc) {
2661 return rc;
2662 }
2663
Andrew Jefferya1896962025-03-03 21:41:25 +10302664 pldm_msgbuf_insert(buf, verify_result);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002665
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302666 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002667}
2668
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302669LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302670int encode_verify_complete_resp(uint8_t instance_id, uint8_t completion_code,
2671 struct pldm_msg *msg, size_t payload_length)
2672{
2673 if (msg == NULL) {
2674 return PLDM_ERROR_INVALID_DATA;
2675 }
2676
2677 if (payload_length != sizeof(completion_code)) {
2678 return PLDM_ERROR_INVALID_LENGTH;
2679 }
2680
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302681 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302682 header.instance = instance_id;
2683 header.msg_type = PLDM_RESPONSE;
2684 header.pldm_type = PLDM_FWUP;
2685 header.command = PLDM_VERIFY_COMPLETE;
2686 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2687 if (rc) {
2688 return rc;
2689 }
2690
2691 msg->payload[0] = completion_code;
2692
2693 return PLDM_SUCCESS;
2694}
2695
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302696LIBPLDM_ABI_STABLE
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302697int decode_apply_complete_req(const struct pldm_msg *msg, size_t payload_length,
2698 uint8_t *apply_result,
2699 bitfield16_t *comp_activation_methods_modification)
Andrew Jeffery9c766792022-08-10 23:12:49 +09302700{
2701 if (msg == NULL || apply_result == NULL ||
2702 comp_activation_methods_modification == NULL) {
2703 return PLDM_ERROR_INVALID_DATA;
2704 }
2705
2706 if (payload_length != sizeof(struct pldm_apply_complete_req)) {
2707 return PLDM_ERROR_INVALID_LENGTH;
2708 }
2709
2710 struct pldm_apply_complete_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302711 (struct pldm_apply_complete_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302712
2713 *apply_result = request->apply_result;
2714 comp_activation_methods_modification->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302715 le16toh(request->comp_activation_methods_modification.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302716
2717 if ((*apply_result != PLDM_FWUP_APPLY_SUCCESS_WITH_ACTIVATION_METHOD) &&
2718 comp_activation_methods_modification->value) {
2719 return PLDM_ERROR_INVALID_DATA;
2720 }
2721
2722 return PLDM_SUCCESS;
2723}
2724
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002725LIBPLDM_ABI_TESTING
2726int encode_apply_complete_req(uint8_t instance_id,
2727 const struct pldm_apply_complete_req *req_data,
2728 struct pldm_msg *msg, size_t *payload_length)
2729{
Andrew Jefferya1896962025-03-03 21:41:25 +10302730 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002731 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002732
2733 if (msg == NULL || payload_length == NULL) {
2734 return -EINVAL;
2735 }
2736
2737 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2738 PLDM_APPLY_COMPLETE, msg);
2739 if (rc) {
2740 return -EINVAL;
2741 }
2742
2743 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2744 if (rc) {
2745 return rc;
2746 }
2747
2748 pldm_msgbuf_insert(buf, req_data->apply_result);
2749 pldm_msgbuf_insert(
2750 buf, req_data->comp_activation_methods_modification.value);
2751
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302752 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002753}
2754
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302755LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302756int encode_apply_complete_resp(uint8_t instance_id, uint8_t completion_code,
2757 struct pldm_msg *msg, size_t payload_length)
2758{
2759 if (msg == NULL) {
2760 return PLDM_ERROR_INVALID_DATA;
2761 }
2762
2763 if (payload_length != sizeof(completion_code)) {
2764 return PLDM_ERROR_INVALID_LENGTH;
2765 }
2766
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302767 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302768 header.instance = instance_id;
2769 header.msg_type = PLDM_RESPONSE;
2770 header.pldm_type = PLDM_FWUP;
2771 header.command = PLDM_APPLY_COMPLETE;
2772 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2773 if (rc) {
2774 return rc;
2775 }
2776
2777 msg->payload[0] = completion_code;
2778
2779 return PLDM_SUCCESS;
2780}
2781
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002782LIBPLDM_ABI_TESTING
2783int decode_activate_firmware_req(const struct pldm_msg *msg,
2784 size_t payload_length, bool *self_contained)
2785{
Andrew Jefferya1896962025-03-03 21:41:25 +10302786 uint8_t self_contained_u8 = 0;
2787 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002788 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002789
2790 if (msg == NULL || self_contained == NULL) {
2791 return -EINVAL;
2792 }
2793
2794 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2795 if (rc) {
2796 return 0;
2797 }
2798
Andrew Jefferya1896962025-03-03 21:41:25 +10302799 pldm_msgbuf_extract(buf, self_contained_u8);
2800
2801 rc = pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002802 if (rc) {
2803 return rc;
2804 }
Andrew Jefferya1896962025-03-03 21:41:25 +10302805
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002806 *self_contained = (bool)self_contained_u8;
2807 return 0;
2808}
2809
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302810LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302811int encode_activate_firmware_req(uint8_t instance_id,
2812 bool8_t self_contained_activation_req,
2813 struct pldm_msg *msg, size_t payload_length)
2814{
2815 if (msg == NULL) {
2816 return PLDM_ERROR_INVALID_DATA;
2817 }
2818
2819 if (payload_length != sizeof(struct pldm_activate_firmware_req)) {
2820 return PLDM_ERROR_INVALID_LENGTH;
2821 }
2822
2823 if (!is_self_contained_activation_req_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302824 self_contained_activation_req)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302825 return PLDM_ERROR_INVALID_DATA;
2826 }
2827
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302828 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302829 header.instance = instance_id;
2830 header.msg_type = PLDM_REQUEST;
2831 header.pldm_type = PLDM_FWUP;
2832 header.command = PLDM_ACTIVATE_FIRMWARE;
2833 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2834 if (rc) {
2835 return rc;
2836 }
2837
2838 struct pldm_activate_firmware_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302839 (struct pldm_activate_firmware_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302840
2841 request->self_contained_activation_req = self_contained_activation_req;
2842
2843 return PLDM_SUCCESS;
2844}
2845
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302846LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302847int decode_activate_firmware_resp(const struct pldm_msg *msg,
2848 size_t payload_length,
2849 uint8_t *completion_code,
2850 uint16_t *estimated_time_activation)
2851{
2852 if (msg == NULL || completion_code == NULL ||
2853 estimated_time_activation == NULL || !payload_length) {
2854 return PLDM_ERROR_INVALID_DATA;
2855 }
2856
2857 *completion_code = msg->payload[0];
2858 if (*completion_code != PLDM_SUCCESS) {
2859 return PLDM_SUCCESS;
2860 }
2861
2862 if (payload_length != sizeof(struct pldm_activate_firmware_resp)) {
2863 return PLDM_ERROR_INVALID_LENGTH;
2864 }
2865
2866 struct pldm_activate_firmware_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302867 (struct pldm_activate_firmware_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302868
2869 *estimated_time_activation =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302870 le16toh(response->estimated_time_activation);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302871
2872 return PLDM_SUCCESS;
2873}
2874
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002875LIBPLDM_ABI_TESTING
2876int encode_activate_firmware_resp(
2877 uint8_t instance_id,
2878 const struct pldm_activate_firmware_resp *resp_data,
2879 struct pldm_msg *msg, size_t *payload_length)
2880{
Andrew Jefferya1896962025-03-03 21:41:25 +10302881 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002882 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002883
2884 if (msg == NULL || payload_length == NULL) {
2885 return -EINVAL;
2886 }
2887
2888 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2889 PLDM_ACTIVATE_FIRMWARE, msg);
2890 if (rc) {
2891 return -EINVAL;
2892 }
2893
2894 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2895 if (rc) {
2896 return rc;
2897 }
2898
2899 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2900 pldm_msgbuf_insert(buf, resp_data->estimated_time_activation);
2901
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302902 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002903}
2904
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302905LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302906int encode_get_status_req(uint8_t instance_id, struct pldm_msg *msg,
2907 size_t payload_length)
2908{
2909 if (msg == NULL) {
2910 return PLDM_ERROR_INVALID_DATA;
2911 }
2912
2913 if (payload_length != PLDM_GET_STATUS_REQ_BYTES) {
2914 return PLDM_ERROR_INVALID_LENGTH;
2915 }
2916
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302917 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302918 header.instance = instance_id;
2919 header.msg_type = PLDM_REQUEST;
2920 header.pldm_type = PLDM_FWUP;
2921 header.command = PLDM_GET_STATUS;
2922 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2923 if (rc) {
2924 return rc;
2925 }
2926
2927 return PLDM_SUCCESS;
2928}
2929
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302930LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302931int decode_get_status_resp(const struct pldm_msg *msg, size_t payload_length,
2932 uint8_t *completion_code, uint8_t *current_state,
2933 uint8_t *previous_state, uint8_t *aux_state,
2934 uint8_t *aux_state_status, uint8_t *progress_percent,
2935 uint8_t *reason_code,
2936 bitfield32_t *update_option_flags_enabled)
2937{
2938 if (msg == NULL || completion_code == NULL || current_state == NULL ||
2939 previous_state == NULL || aux_state == NULL ||
2940 aux_state_status == NULL || progress_percent == NULL ||
2941 reason_code == NULL || update_option_flags_enabled == NULL ||
2942 !payload_length) {
2943 return PLDM_ERROR_INVALID_DATA;
2944 }
2945
2946 *completion_code = msg->payload[0];
2947 if (*completion_code != PLDM_SUCCESS) {
2948 return PLDM_SUCCESS;
2949 }
2950
2951 if (payload_length != sizeof(struct pldm_get_status_resp)) {
2952 return PLDM_ERROR_INVALID_LENGTH;
2953 }
2954 struct pldm_get_status_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302955 (struct pldm_get_status_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302956
2957 if (!is_state_valid(response->current_state)) {
2958 return PLDM_ERROR_INVALID_DATA;
2959 }
2960 if (!is_state_valid(response->previous_state)) {
2961 return PLDM_ERROR_INVALID_DATA;
2962 }
2963 if (!is_aux_state_valid(response->aux_state)) {
2964 return PLDM_ERROR_INVALID_DATA;
2965 }
2966 if (!is_aux_state_status_valid(response->aux_state_status)) {
2967 return PLDM_ERROR_INVALID_DATA;
2968 }
2969 if (response->progress_percent > PLDM_FWUP_MAX_PROGRESS_PERCENT) {
2970 return PLDM_ERROR_INVALID_DATA;
2971 }
2972 if (!is_reason_code_valid(response->reason_code)) {
2973 return PLDM_ERROR_INVALID_DATA;
2974 }
2975
2976 if ((response->current_state == PLDM_FD_STATE_IDLE) ||
2977 (response->current_state == PLDM_FD_STATE_LEARN_COMPONENTS) ||
2978 (response->current_state == PLDM_FD_STATE_READY_XFER)) {
2979 if (response->aux_state !=
2980 PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER) {
2981 return PLDM_ERROR_INVALID_DATA;
2982 }
2983 }
2984
2985 *current_state = response->current_state;
2986 *previous_state = response->previous_state;
2987 *aux_state = response->aux_state;
2988 *aux_state_status = response->aux_state_status;
2989 *progress_percent = response->progress_percent;
2990 *reason_code = response->reason_code;
2991 update_option_flags_enabled->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302992 le32toh(response->update_option_flags_enabled.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302993
2994 return PLDM_SUCCESS;
2995}
2996
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002997LIBPLDM_ABI_TESTING
2998int encode_get_status_resp(uint8_t instance_id,
2999 const struct pldm_get_status_resp *status,
3000 struct pldm_msg *msg, size_t *payload_length)
3001{
Andrew Jefferya1896962025-03-03 21:41:25 +10303002 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003003 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003004
3005 if (status == NULL || msg == NULL || payload_length == NULL) {
3006 return -EINVAL;
3007 }
3008
3009 if (status->completion_code != PLDM_SUCCESS) {
3010 return -EINVAL;
3011 }
3012
3013 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
3014 PLDM_GET_STATUS, msg);
3015 if (rc) {
3016 return -EINVAL;
3017 }
3018
3019 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
3020 if (rc) {
3021 return rc;
3022 }
3023
3024 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
3025 pldm_msgbuf_insert(buf, status->current_state);
3026 pldm_msgbuf_insert(buf, status->previous_state);
3027 pldm_msgbuf_insert(buf, status->aux_state);
3028 pldm_msgbuf_insert(buf, status->aux_state_status);
3029 pldm_msgbuf_insert(buf, status->progress_percent);
3030 pldm_msgbuf_insert(buf, status->reason_code);
3031 pldm_msgbuf_insert(buf, status->update_option_flags_enabled.value);
3032
Andrew Jeffery70d21c92025-03-05 12:59:42 +10303033 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003034}
3035
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09303036LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09303037int encode_cancel_update_component_req(uint8_t instance_id,
3038 struct pldm_msg *msg,
3039 size_t payload_length)
3040{
3041 if (msg == NULL) {
3042 return PLDM_ERROR_INVALID_DATA;
3043 }
3044
3045 if (payload_length != PLDM_CANCEL_UPDATE_COMPONENT_REQ_BYTES) {
3046 return PLDM_ERROR_INVALID_LENGTH;
3047 }
3048
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303049 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09303050 header.instance = instance_id;
3051 header.msg_type = PLDM_REQUEST;
3052 header.pldm_type = PLDM_FWUP;
3053 header.command = PLDM_CANCEL_UPDATE_COMPONENT;
3054 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
3055 if (rc) {
3056 return rc;
3057 }
3058
3059 return PLDM_SUCCESS;
3060}
3061
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09303062LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09303063int decode_cancel_update_component_resp(const struct pldm_msg *msg,
3064 size_t payload_length,
3065 uint8_t *completion_code)
3066{
3067 if (msg == NULL || completion_code == NULL) {
3068 return PLDM_ERROR_INVALID_DATA;
3069 }
3070
3071 if (payload_length != sizeof(*completion_code)) {
3072 return PLDM_ERROR_INVALID_LENGTH;
3073 }
3074
3075 *completion_code = msg->payload[0];
3076 return PLDM_SUCCESS;
3077}
3078
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09303079LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09303080int encode_cancel_update_req(uint8_t instance_id, struct pldm_msg *msg,
3081 size_t payload_length)
3082{
3083 if (msg == NULL) {
3084 return PLDM_ERROR_INVALID_DATA;
3085 }
3086
3087 if (payload_length != PLDM_CANCEL_UPDATE_REQ_BYTES) {
3088 return PLDM_ERROR_INVALID_LENGTH;
3089 }
3090
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303091 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09303092 header.instance = instance_id;
3093 header.msg_type = PLDM_REQUEST;
3094 header.pldm_type = PLDM_FWUP;
3095 header.command = PLDM_CANCEL_UPDATE;
3096 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
3097 if (rc) {
3098 return rc;
3099 }
3100
3101 return PLDM_SUCCESS;
3102}
3103
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09303104LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09303105int decode_cancel_update_resp(const struct pldm_msg *msg, size_t payload_length,
3106 uint8_t *completion_code,
3107 bool8_t *non_functioning_component_indication,
3108 bitfield64_t *non_functioning_component_bitmap)
3109{
3110 if (msg == NULL || completion_code == NULL ||
3111 non_functioning_component_indication == NULL ||
3112 non_functioning_component_bitmap == NULL || !payload_length) {
3113 return PLDM_ERROR_INVALID_DATA;
3114 }
3115
3116 *completion_code = msg->payload[0];
3117 if (*completion_code != PLDM_SUCCESS) {
3118 return PLDM_SUCCESS;
3119 }
3120
3121 if (payload_length != sizeof(struct pldm_cancel_update_resp)) {
3122 return PLDM_ERROR_INVALID_LENGTH;
3123 }
3124 struct pldm_cancel_update_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303125 (struct pldm_cancel_update_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09303126
3127 if (!is_non_functioning_component_indication_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303128 response->non_functioning_component_indication)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09303129 return PLDM_ERROR_INVALID_DATA;
3130 }
3131
3132 *non_functioning_component_indication =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303133 response->non_functioning_component_indication;
Andrew Jeffery9c766792022-08-10 23:12:49 +09303134
3135 if (*non_functioning_component_indication) {
3136 non_functioning_component_bitmap->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303137 le64toh(response->non_functioning_component_bitmap);
Andrew Jeffery9c766792022-08-10 23:12:49 +09303138 }
3139
3140 return PLDM_SUCCESS;
3141}
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003142
3143LIBPLDM_ABI_TESTING
3144int encode_cancel_update_resp(uint8_t instance_id,
3145 const struct pldm_cancel_update_resp *resp_data,
3146 struct pldm_msg *msg, size_t *payload_length)
3147{
Andrew Jefferya1896962025-03-03 21:41:25 +10303148 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003149 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003150
3151 if (msg == NULL || payload_length == NULL) {
3152 return -EINVAL;
3153 }
3154
3155 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
3156 PLDM_CANCEL_UPDATE, msg);
3157 if (rc) {
3158 return -EINVAL;
3159 }
3160
3161 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
3162 if (rc) {
3163 return rc;
3164 }
3165
3166 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
3167 pldm_msgbuf_insert(buf,
3168 resp_data->non_functioning_component_indication);
3169 pldm_msgbuf_insert(buf, resp_data->non_functioning_component_bitmap);
3170
Andrew Jeffery70d21c92025-03-05 12:59:42 +10303171 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003172}
Andrew Jeffery2613c272025-03-12 14:15:41 +10303173
3174LIBPLDM_ABI_TESTING
3175int decode_pldm_firmware_update_package(
3176 const void *data, size_t length,
3177 const struct pldm_package_format_pin *pin,
3178 pldm_package_header_information_pad *hdr,
3179 struct pldm_package_iter *iter)
3180{
3181 if (!data || !pin || !hdr || !iter) {
3182 return -EINVAL;
3183 }
3184
3185 iter->hdr = hdr;
3186
3187 return decode_pldm_package_header_info_errno(data, length, pin, hdr);
3188}
3189
3190LIBPLDM_ABI_TESTING
3191int pldm_package_firmware_device_id_record_iter_init(
3192 const pldm_package_header_information_pad *hdr,
3193 struct pldm_package_firmware_device_id_record_iter *iter)
3194{
3195 PLDM_MSGBUF_DEFINE_P(buf);
3196 int rc;
3197
3198 if (!hdr || !iter || !hdr->areas.ptr) {
3199 return -EINVAL;
3200 }
3201
3202 iter->field = hdr->areas;
3203
3204 /* Extract the fd record id count */
3205 rc = pldm_msgbuf_init_errno(buf, 1, iter->field.ptr,
3206 iter->field.length);
3207 if (rc) {
3208 return rc;
3209 }
3210
3211 pldm_msgbuf_extract_uint8_to_size(buf, iter->entries);
3212 pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
3213 &iter->field.length);
3214
3215 return pldm_msgbuf_complete(buf);
3216}
3217
3218LIBPLDM_ABI_TESTING
3219int decode_pldm_package_firmware_device_id_record_from_iter(
3220 const pldm_package_header_information_pad *hdr,
3221 struct pldm_package_firmware_device_id_record_iter *iter,
3222 struct pldm_package_firmware_device_id_record *rec)
3223{
3224 return decode_pldm_package_firmware_device_id_record_errno(
3225 hdr, &iter->field, rec);
3226}
3227
3228LIBPLDM_ABI_TESTING
3229int pldm_package_downstream_device_id_record_iter_init(
3230 const pldm_package_header_information_pad *hdr,
3231 struct pldm_package_firmware_device_id_record_iter *fds,
3232 struct pldm_package_downstream_device_id_record_iter *dds)
3233{
3234 PLDM_MSGBUF_DEFINE_P(buf);
3235 int rc;
3236
3237 if (!hdr || !fds || !dds || !fds->field.ptr) {
3238 return -EINVAL;
3239 }
3240
3241 dds->field = fds->field;
3242 fds->field.ptr = NULL;
3243 fds->field.length = 0;
3244
3245 /* Downstream device ID records aren't specified in revision 1 */
3246 if (hdr->package_header_format_revision <
3247 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR02H) {
3248 dds->entries = 0;
3249 return 0;
3250 }
3251
3252 /* Extract the dd record id count */
3253 rc = pldm_msgbuf_init_errno(buf, 1, dds->field.ptr, dds->field.length);
3254 if (rc) {
3255 return rc;
3256 }
3257
3258 pldm_msgbuf_extract_uint8_to_size(buf, dds->entries);
3259 pldm_msgbuf_span_remaining(buf, (void **)&dds->field.ptr,
3260 &dds->field.length);
3261
3262 return pldm_msgbuf_complete(buf);
3263}
3264
3265#define PLDM_FWUP_DOWNSTREAM_DEVICE_ID_RECORD_MIN_SIZE 11
3266LIBPLDM_ABI_TESTING
3267int decode_pldm_package_downstream_device_id_record_from_iter(
3268 const pldm_package_header_information_pad *hdr,
3269 struct pldm_package_downstream_device_id_record_iter *iter,
3270 struct pldm_package_downstream_device_id_record *rec)
3271{
3272 PLDM_MSGBUF_DEFINE_P(buf);
3273 uint16_t record_len = 0;
3274 int rc;
3275
3276 if (!hdr || !iter || !rec || !iter->field.ptr) {
3277 return -EINVAL;
3278 }
3279
3280 if (hdr->package_header_format_revision <
3281 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR02H) {
3282 /* Should not be reached due to corresponding test in iter initialisation */
3283 return -ENOTSUP;
3284 }
3285
3286 if (hdr->component_bitmap_bit_length & 7) {
3287 return -EPROTO;
3288 }
3289
3290 rc = pldm_msgbuf_init_dynamic_uint16(
3291 buf, PLDM_FWUP_DOWNSTREAM_DEVICE_ID_RECORD_MIN_SIZE,
3292 (void *)iter->field.ptr, iter->field.length,
3293 (void **)&iter->field.ptr, &iter->field.length);
3294 if (rc) {
3295 return pldm_msgbuf_discard(buf, rc);
3296 }
3297
3298 pldm_msgbuf_extract(buf, record_len);
3299 pldm_msgbuf_extract(buf, rec->descriptor_count);
3300
3301 rc = pldm_msgbuf_extract(buf, rec->update_option_flags.value);
3302 if (rc) {
3303 return pldm_msgbuf_discard(buf, rc);
3304 }
3305
3306 rc = pldm_msgbuf_extract(
3307 buf, rec->self_contained_activation_min_version_string_type);
3308 if (rc) {
3309 return pldm_msgbuf_discard(buf, rc);
3310 }
3311 if (!is_string_type_valid(
3312 rec->self_contained_activation_min_version_string_type)) {
3313 return pldm_msgbuf_discard(buf, -EPROTO);
3314 }
3315
3316 rc = pldm_msgbuf_extract_uint8_to_size(
3317 buf, rec->self_contained_activation_min_version_string.length);
3318 if (rc) {
3319 return pldm_msgbuf_discard(buf, rc);
3320 }
3321
3322 rc = pldm_msgbuf_extract_uint16_to_size(buf, rec->package_data.length);
3323 if (rc) {
3324 return pldm_msgbuf_discard(buf, rc);
3325 }
3326
3327 rc = pldm_msgbuf_span_required(
3328 buf, hdr->component_bitmap_bit_length / 8,
3329 (void **)&rec->applicable_components.bitmap.ptr);
3330 if (rc) {
3331 return pldm_msgbuf_discard(buf, rc);
3332 }
3333 rec->applicable_components.bitmap.length =
3334 hdr->component_bitmap_bit_length / 8;
3335
3336 pldm_msgbuf_span_required(
3337 buf, rec->self_contained_activation_min_version_string.length,
3338 (void **)&rec->self_contained_activation_min_version_string.ptr);
3339 if (rec->update_option_flags.bits.bit0) {
3340 pldm_msgbuf_extract(
3341 buf,
3342 rec->self_contained_activation_min_version_comparison_stamp);
3343 } else {
3344 rec->self_contained_activation_min_version_comparison_stamp = 0;
3345 }
3346
3347 pldm_msgbuf_span_until(buf, rec->package_data.length,
3348 (void **)&rec->record_descriptors.ptr,
3349 &rec->record_descriptors.length);
3350
3351 pldm_msgbuf_span_required(buf, rec->package_data.length,
3352 (void **)&rec->package_data.ptr);
3353
3354 return pldm_msgbuf_complete_consumed(buf);
3355}
3356
3357LIBPLDM_ABI_TESTING
3358int pldm_package_component_image_information_iter_init(
3359 const pldm_package_header_information_pad *hdr LIBPLDM_CC_UNUSED,
3360 struct pldm_package_downstream_device_id_record_iter *dds,
3361 struct pldm_package_component_image_information_iter *infos)
3362{
3363 uint16_t component_image_count;
3364 PLDM_MSGBUF_DEFINE_P(buf);
3365 int rc;
3366
3367 if (!dds || !infos) {
3368 return -EINVAL;
3369 }
3370
3371 infos->field = dds->field;
3372 dds->field.ptr = NULL;
3373 dds->field.length = 0;
3374
3375 /* Extract the component image count */
3376 rc = pldm_msgbuf_init_errno(buf, 1, infos->field.ptr,
3377 infos->field.length);
3378 if (rc) {
3379 return rc;
3380 }
3381
3382 rc = pldm_msgbuf_extract(buf, component_image_count);
3383 if (rc) {
3384 return pldm_msgbuf_discard(buf, rc);
3385 }
3386 infos->entries = component_image_count;
3387
3388 pldm_msgbuf_span_remaining(buf, (void **)&infos->field.ptr,
3389 &infos->field.length);
3390
3391 return pldm_msgbuf_complete(buf);
3392}
3393
3394#define PLDM_FWUP_COMPONENT_IMAGE_INFORMATION_MIN_SIZE 22
3395LIBPLDM_ABI_TESTING
3396int decode_pldm_package_component_image_information_from_iter(
3397 const pldm_package_header_information_pad *hdr,
3398 struct pldm_package_component_image_information_iter *iter,
3399 struct pldm_package_component_image_information *info)
3400{
3401 uint32_t component_location_offset = 0;
3402 uint32_t component_size = 0;
3403 PLDM_MSGBUF_DEFINE_P(buf);
3404 int rc;
3405
3406 if (!hdr || !iter || !info || !iter->field.ptr) {
3407 return -EINVAL;
3408 }
3409
3410 if (hdr->component_bitmap_bit_length & 7) {
3411 return -EPROTO;
3412 }
3413
3414 rc = pldm_msgbuf_init_errno(
3415 buf, PLDM_FWUP_COMPONENT_IMAGE_INFORMATION_MIN_SIZE,
3416 iter->field.ptr, iter->field.length);
3417 if (rc) {
3418 return rc;
3419 }
3420
3421 pldm_msgbuf_extract(buf, info->component_classification);
3422 pldm_msgbuf_extract(buf, info->component_identifier);
3423 pldm_msgbuf_extract(buf, info->component_comparison_stamp);
3424 pldm_msgbuf_extract(buf, info->component_options.value);
3425 pldm_msgbuf_extract(buf,
3426 info->requested_component_activation_method.value);
3427 pldm_msgbuf_extract(buf, component_location_offset);
3428 pldm_msgbuf_extract(buf, component_size);
3429
3430 rc = pldm_msgbuf_extract(buf, info->component_version_string_type);
3431 if (rc) {
3432 return pldm_msgbuf_discard(buf, rc);
3433 }
3434 if (!is_string_type_valid(info->component_version_string_type)) {
3435 return pldm_msgbuf_discard(buf, -EPROTO);
3436 }
3437
3438 rc = pldm_msgbuf_extract_uint8_to_size(
3439 buf, info->component_version_string.length);
3440 if (rc) {
3441 return pldm_msgbuf_discard(buf, rc);
3442 }
3443
3444 pldm_msgbuf_span_required(buf, info->component_version_string.length,
3445 (void **)&info->component_version_string.ptr);
3446
Carter Chenf72cf6f2025-06-24 15:34:49 +08003447 /* Supported in package header revision 1.2 (FR03H) and above. */
3448 if (hdr->package_header_format_revision >=
3449 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR03H) {
3450 rc = pldm_msgbuf_extract_uint32_to_size(
3451 buf, info->component_opaque_data.length);
3452 if (rc) {
3453 return pldm_msgbuf_discard(buf, rc);
3454 }
3455 pldm_msgbuf_span_required(
3456 buf, info->component_opaque_data.length,
3457 (void **)&info->component_opaque_data.ptr);
3458 } else {
3459 info->component_opaque_data.length = 0;
3460 }
3461
3462 if (info->component_opaque_data.length == 0) {
3463 info->component_opaque_data.ptr = NULL;
3464 }
3465
Andrew Jeffery2613c272025-03-12 14:15:41 +10303466 pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
3467 &iter->field.length);
3468
3469 rc = pldm_msgbuf_complete_consumed(buf);
3470 if (rc) {
3471 return rc;
3472 }
3473
3474 if (info->component_classification > 0x000d &&
3475 info->component_classification < 0x8000) {
3476 return -EPROTO;
3477 }
3478
3479 /* Resolve the component image in memory */
3480 rc = pldm_msgbuf_init_errno(buf, 0, hdr->package.ptr,
3481 hdr->package.length);
3482 if (rc) {
3483 return rc;
3484 }
3485
3486 pldm_msgbuf_span_required(buf, component_location_offset, NULL);
3487 pldm_msgbuf_span_required(buf, component_size,
3488 (void **)&info->component_image.ptr);
3489
3490 rc = pldm_msgbuf_complete(buf);
3491 if (rc) {
3492 return rc;
3493 }
3494
3495 info->component_image.length = component_size;
3496
3497 return 0;
3498}