blob: e7befe840f9c5fe7c39f311abd10de1314457fa6 [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,
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000339 pldm_package_header_information_pad *hdr,
340 struct pldm_package *pkg)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930341{
Andrew Jeffery2613c272025-03-12 14:15:41 +1030342 static const struct pldm_package_header_format_revision_info {
343 pldm_uuid identifier;
344 size_t magic;
Carter Chen01782742025-06-25 13:53:50 +0800345 } revision_info[1 + PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H] = {
Andrew Jeffery2613c272025-03-12 14:15:41 +1030346 [0] = {
347 .identifier = {0},
348 .magic = 0,
349 },
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000350 [PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H] = {
Andrew Jeffery2613c272025-03-12 14:15:41 +1030351 .identifier = PLDM_PACKAGE_HEADER_IDENTIFIER_V1_0,
352 .magic =
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000353 LIBPLDM_SIZEAT(struct pldm_package, iter) +
354 LIBPLDM_SIZEAT(struct pldm__package_header_information, package_version_string) +
Andrew Jeffery2613c272025-03-12 14:15:41 +1030355 LIBPLDM_SIZEAT(struct pldm_package_firmware_device_id_record, firmware_device_package_data) +
356 LIBPLDM_SIZEAT(struct pldm_descriptor, descriptor_data) +
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000357 LIBPLDM_SIZEAT(struct pldm_package_component_image_information, component_version_string)
Andrew Jeffery2613c272025-03-12 14:15:41 +1030358 },
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000359 [PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR02H] = {
Andrew Jeffery2613c272025-03-12 14:15:41 +1030360 .identifier = PLDM_PACKAGE_HEADER_IDENTIFIER_V1_1,
361 .magic =
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000362 LIBPLDM_SIZEAT(struct pldm_package, iter) +
363 LIBPLDM_SIZEAT(struct pldm__package_header_information, package_version_string) +
Andrew Jeffery2613c272025-03-12 14:15:41 +1030364 LIBPLDM_SIZEAT(struct pldm_package_firmware_device_id_record, firmware_device_package_data) +
365 LIBPLDM_SIZEAT(struct pldm_descriptor, descriptor_data) +
366 LIBPLDM_SIZEAT(struct pldm_package_downstream_device_id_record, package_data) +
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000367 LIBPLDM_SIZEAT(struct pldm_package_component_image_information, component_version_string)
Andrew Jeffery2613c272025-03-12 14:15:41 +1030368 },
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000369 [PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR03H] = {
Carter Chenf72cf6f2025-06-24 15:34:49 +0800370 .identifier = PLDM_PACKAGE_HEADER_IDENTIFIER_V1_2,
371 .magic =
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000372 LIBPLDM_SIZEAT(struct pldm_package, iter) +
373 LIBPLDM_SIZEAT(struct pldm__package_header_information, package_version_string) +
Carter Chenf72cf6f2025-06-24 15:34:49 +0800374 LIBPLDM_SIZEAT(struct pldm_package_firmware_device_id_record, firmware_device_package_data) +
375 LIBPLDM_SIZEAT(struct pldm_descriptor, descriptor_data) +
376 LIBPLDM_SIZEAT(struct pldm_package_downstream_device_id_record, package_data) +
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000377 LIBPLDM_SIZEAT(struct pldm_package_component_image_information, component_opaque_data)
Carter Chenf72cf6f2025-06-24 15:34:49 +0800378 },
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000379 [PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H] = {
Carter Chen01782742025-06-25 13:53:50 +0800380 .identifier = PLDM_PACKAGE_HEADER_IDENTIFIER_V1_3,
381 .magic =
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000382 LIBPLDM_SIZEAT(struct pldm_package, iter) +
383 LIBPLDM_SIZEAT(struct pldm__package_header_information, package_version_string) +
Carter Chen01782742025-06-25 13:53:50 +0800384 LIBPLDM_SIZEAT(struct pldm_package_firmware_device_id_record, reference_manifest_data) +
385 LIBPLDM_SIZEAT(struct pldm_descriptor, descriptor_data) +
386 LIBPLDM_SIZEAT(struct pldm_package_downstream_device_id_record, reference_manifest_data) +
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000387 LIBPLDM_SIZEAT(struct pldm_package_component_image_information, component_opaque_data)
Carter Chen01782742025-06-25 13:53:50 +0800388 },
Andrew Jeffery2613c272025-03-12 14:15:41 +1030389 };
390
391 const struct pldm_package_header_format_revision_info *info;
Carter Chen01782742025-06-25 13:53:50 +0800392 uint32_t package_payload_checksum = 0;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030393 uint32_t package_header_checksum = 0;
394 size_t package_header_variable_size;
395 size_t package_header_payload_size;
John Chung7a8d9322025-08-27 20:56:19 -0500396 const void *package_payload_offset;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030397 size_t package_header_areas_size;
398 uint16_t package_header_size;
Carter Chen01782742025-06-25 13:53:50 +0800399 size_t package_payload_size;
John Chung7a8d9322025-08-27 20:56:19 -0500400 PLDM_MSGBUF_RO_DEFINE_P(buf);
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030401 int checksums = 1;
402 int rc;
403
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000404 if (pkg->state != PLDM_PACKAGE_PARSE_INIT) {
405 return -EINVAL;
406 }
407
408 if (pin->meta.version > 0u) {
Andrew Jeffery2613c272025-03-12 14:15:41 +1030409 return -ENOTSUP;
410 }
411
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000412 if (pin->format.revision == 0u) {
Andrew Jeffery2613c272025-03-12 14:15:41 +1030413 return -EINVAL;
414 }
415
Carter Chen01782742025-06-25 13:53:50 +0800416 if (pin->format.revision > PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H) {
Andrew Jeffery2613c272025-03-12 14:15:41 +1030417 return -ENOTSUP;
418 }
419 static_assert(ARRAY_SIZE(revision_info) ==
Carter Chen01782742025-06-25 13:53:50 +0800420 1 + PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H,
Andrew Jeffery2613c272025-03-12 14:15:41 +1030421 "Mismatched array bounds test");
422
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000423 info = &revision_info[(size_t)pin->format.revision];
Andrew Jeffery2613c272025-03-12 14:15:41 +1030424 if (memcmp(&pin->format.identifier, info->identifier,
425 sizeof(info->identifier)) != 0) {
426 return -ENOTSUP;
427 }
428
429 if (pin->meta.magic != info->magic) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030430 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930431 }
432
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030433 rc = pldm_msgbuf_init_errno(buf, PLDM_FWUP_PACKAGE_HEADER_FIXED_SIZE,
434 data, length);
435 if (rc) {
436 return rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930437 }
438
Andrew Jeffery2613c272025-03-12 14:15:41 +1030439 rc = pldm_msgbuf_extract_array(buf,
440 sizeof(hdr->package_header_identifier),
441 hdr->package_header_identifier,
442 sizeof(hdr->package_header_identifier));
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030443 if (rc) {
444 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930445 }
446
Andrew Jeffery2613c272025-03-12 14:15:41 +1030447 if (memcmp(revision_info[PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H]
448 .identifier,
449 hdr->package_header_identifier,
450 sizeof(hdr->package_header_identifier)) != 0 &&
451 memcmp(revision_info[PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR02H]
452 .identifier,
453 hdr->package_header_identifier,
Carter Chenf72cf6f2025-06-24 15:34:49 +0800454 sizeof(hdr->package_header_identifier)) != 0 &&
455 memcmp(revision_info[PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR03H]
456 .identifier,
457 hdr->package_header_identifier,
Carter Chen01782742025-06-25 13:53:50 +0800458 sizeof(hdr->package_header_identifier)) != 0 &&
459 memcmp(revision_info[PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H]
460 .identifier,
461 hdr->package_header_identifier,
Andrew Jeffery2613c272025-03-12 14:15:41 +1030462 sizeof(hdr->package_header_identifier)) != 0) {
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030463 return pldm_msgbuf_discard(buf, -ENOTSUP);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930464 }
465
Andrew Jeffery2613c272025-03-12 14:15:41 +1030466 rc = pldm_msgbuf_extract(buf, hdr->package_header_format_revision);
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030467 if (rc) {
468 return pldm_msgbuf_discard(buf, rc);
469 }
Andrew Jeffery2613c272025-03-12 14:15:41 +1030470 if (hdr->package_header_format_revision > pin->format.revision) {
471 return pldm_msgbuf_discard(buf, -ENOTSUP);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930472 }
473
Carter Chen01782742025-06-25 13:53:50 +0800474 if (hdr->package_header_format_revision >=
475 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H) {
476 checksums = 2;
477 }
478
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030479 rc = pldm_msgbuf_extract(buf, package_header_size);
480 if (rc) {
481 return pldm_msgbuf_discard(buf, rc);
482 }
483
Andrew Jeffery2613c272025-03-12 14:15:41 +1030484 rc = pldm_msgbuf_extract_array(buf,
485 sizeof(hdr->package_release_date_time),
486 hdr->package_release_date_time,
487 sizeof(hdr->package_release_date_time));
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030488 if (rc) {
489 return pldm_msgbuf_discard(buf, rc);
490 }
491
Andrew Jeffery2613c272025-03-12 14:15:41 +1030492 rc = pldm_msgbuf_extract(buf, hdr->component_bitmap_bit_length);
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030493 if (rc) {
494 return pldm_msgbuf_discard(buf, rc);
495 }
Andrew Jeffery2613c272025-03-12 14:15:41 +1030496 if (hdr->component_bitmap_bit_length & 7) {
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030497 return pldm_msgbuf_discard(buf, -EPROTO);
498 }
499
Andrew Jeffery2613c272025-03-12 14:15:41 +1030500 rc = pldm_msgbuf_extract(buf, hdr->package_version_string_type);
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030501 if (rc) {
502 return pldm_msgbuf_discard(buf, rc);
503 }
Andrew Jeffery2613c272025-03-12 14:15:41 +1030504 if (!is_string_type_valid(hdr->package_version_string_type)) {
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030505 return pldm_msgbuf_discard(buf, -EPROTO);
506 }
507
508 rc = pldm_msgbuf_extract_uint8_to_size(
Andrew Jeffery2613c272025-03-12 14:15:41 +1030509 buf, hdr->package_version_string.length);
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030510 if (rc) {
511 return pldm_msgbuf_discard(buf, rc);
512 }
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030513
John Chung7a8d9322025-08-27 20:56:19 -0500514 pldm_msgbuf_span_required(
515 buf, hdr->package_version_string.length,
516 (const void **)&hdr->package_version_string.ptr);
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030517
518 if (package_header_size < (PLDM_FWUP_PACKAGE_HEADER_FIXED_SIZE + 3 +
519 checksums * sizeof(uint32_t))) {
Andrew Jeffery2613c272025-03-12 14:15:41 +1030520 return pldm_msgbuf_discard(buf, -EOVERFLOW);
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030521 }
522 package_header_payload_size =
523 package_header_size - (checksums * sizeof(uint32_t));
524 package_header_variable_size = package_header_payload_size -
525 PLDM_FWUP_PACKAGE_HEADER_FIXED_SIZE;
526
Andrew Jeffery2613c272025-03-12 14:15:41 +1030527 if (package_header_variable_size < hdr->package_version_string.length) {
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030528 return pldm_msgbuf_discard(buf, -EOVERFLOW);
529 }
530
531 package_header_areas_size = package_header_variable_size -
Andrew Jeffery2613c272025-03-12 14:15:41 +1030532 hdr->package_version_string.length;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030533 rc = pldm_msgbuf_span_required(buf, package_header_areas_size,
John Chung7a8d9322025-08-27 20:56:19 -0500534 (const void **)&pkg->areas.ptr);
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030535 if (rc) {
536 return pldm_msgbuf_discard(buf, rc);
537 }
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000538 pkg->areas.length = package_header_areas_size;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030539
540 pldm_msgbuf_extract(buf, package_header_checksum);
541
Carter Chen01782742025-06-25 13:53:50 +0800542 if (hdr->package_header_format_revision >=
543 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H) {
544 pldm_msgbuf_extract(buf, package_payload_checksum);
545 rc = pldm_msgbuf_span_remaining(buf, &package_payload_offset,
546 &package_payload_size);
547 if (rc) {
548 return pldm_msgbuf_discard(buf, rc);
549 }
550 } else {
551 package_payload_offset = NULL;
552 package_payload_size = 0;
553 }
554
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030555 rc = pldm_msgbuf_complete(buf);
556 if (rc) {
557 return rc;
558 }
559
Carter Chenff78bca2025-06-25 10:33:31 +0800560 rc = pldm_edac_crc32_validate(package_header_checksum, data,
561 package_header_payload_size);
562 if (rc) {
Andrew Jeffery2613c272025-03-12 14:15:41 +1030563#if 0
Carter Chenff78bca2025-06-25 10:33:31 +0800564 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 +1030565#endif
Carter Chenff78bca2025-06-25 10:33:31 +0800566 return rc;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030567 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930568
Carter Chen01782742025-06-25 13:53:50 +0800569 if (hdr->package_header_format_revision >=
570 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H) {
571 rc = pldm_edac_crc32_validate(package_payload_checksum,
572 package_payload_offset,
573 package_payload_size);
574 if (rc) {
575#if 0
576 printf("payload checksum failure, expected: %#08" PRIx32 ", found: %#08" PRIx32 "\n", package_payload_checksum, pldm_edac_crc32(package_payload_offset, package_payload_size));
577#endif
578 return rc;
579 }
580 }
581
Andrew Jeffery2613c272025-03-12 14:15:41 +1030582 /* We stash these to resolve component images later */
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000583 pkg->pin = pin;
584 pkg->hdr = hdr;
585 pkg->state = PLDM_PACKAGE_PARSE_HEADER;
Andrew Jeffery72442de2025-08-12 08:47:42 +0000586 pkg->flags = 0;
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000587 pkg->package.ptr = data;
588 pkg->package.length = length;
Andrew Jeffery2613c272025-03-12 14:15:41 +1030589
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030590 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930591}
592
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930593LIBPLDM_ABI_STABLE
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030594int decode_pldm_package_header_info(
595 const uint8_t *data, size_t length,
596 struct pldm_package_header_information *package_header_info,
597 struct variable_field *package_version_str)
598{
Andrew Jeffery2613c272025-03-12 14:15:41 +1030599 DEFINE_PLDM_PACKAGE_FORMAT_PIN_FR01H(pin);
600 pldm_package_header_information_pad hdr;
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000601 struct pldm_package pkg = { 0 };
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030602 int rc;
603
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030604 if (!data || !package_header_info || !package_version_str) {
605 return PLDM_ERROR_INVALID_DATA;
606 }
607
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000608 rc = decode_pldm_package_header_info_errno(data, length, &pin, &hdr,
609 &pkg);
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030610 if (rc < 0) {
611 return pldm_xlate_errno(rc);
612 }
613
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030614 static_assert(sizeof(package_header_info->uuid) ==
Andrew Jeffery2613c272025-03-12 14:15:41 +1030615 sizeof(hdr.package_header_identifier),
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030616 "UUID field size");
Andrew Jeffery2613c272025-03-12 14:15:41 +1030617 memcpy(package_header_info->uuid, hdr.package_header_identifier,
618 sizeof(hdr.package_header_identifier));
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030619 package_header_info->package_header_format_version =
Andrew Jeffery2613c272025-03-12 14:15:41 +1030620 hdr.package_header_format_revision;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030621 memcpy(&package_header_info->package_header_size, data + 17,
622 sizeof(package_header_info->package_header_size));
623 LE16TOH(package_header_info->package_header_size);
624 static_assert(sizeof(package_header_info->package_release_date_time) ==
Andrew Jeffery2613c272025-03-12 14:15:41 +1030625 sizeof(hdr.package_release_date_time),
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030626 "TIMESTAMP104 field size");
627 memcpy(package_header_info->package_release_date_time,
Andrew Jeffery2613c272025-03-12 14:15:41 +1030628 hdr.package_release_date_time,
629 sizeof(hdr.package_release_date_time));
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030630 package_header_info->component_bitmap_bit_length =
Andrew Jeffery2613c272025-03-12 14:15:41 +1030631 hdr.component_bitmap_bit_length;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030632 package_header_info->package_version_string_type =
Andrew Jeffery2613c272025-03-12 14:15:41 +1030633 hdr.package_version_string_type;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030634 package_header_info->package_version_string_length =
Andrew Jeffery2613c272025-03-12 14:15:41 +1030635 hdr.package_version_string.length;
636 *package_version_str = hdr.package_version_string;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030637
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030638 return PLDM_SUCCESS;
639}
640
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000641/* Currently only used for decode_firmware_device_id_record_errno() */
John Chung7a8d9322025-08-27 20:56:19 -0500642static int pldm_msgbuf_init_dynamic_uint16(struct pldm_msgbuf_ro *buf,
643 size_t req, void *data, size_t len,
Andrew Jeffery2613c272025-03-12 14:15:41 +1030644 void **tail_data, size_t *tail_len)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930645{
John Chung7a8d9322025-08-27 20:56:19 -0500646 const void *dyn_start;
Andrew Jeffery2613c272025-03-12 14:15:41 +1030647 size_t dyn_length;
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000648 int rc;
649
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000650 rc = pldm_msgbuf_init_errno(buf, req, data, len);
651 if (rc) {
652 return rc;
653 }
Andrew Jeffery2613c272025-03-12 14:15:41 +1030654 /*
655 * Extract the record length from the first field, then reinitialise the msgbuf
656 * after determining that it's safe to do so
657 */
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000658
Andrew Jeffery2613c272025-03-12 14:15:41 +1030659 rc = pldm_msgbuf_extract_uint16_to_size(buf, dyn_length);
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000660 if (rc) {
661 return pldm_msgbuf_discard(buf, rc);
662 }
663
664 rc = pldm_msgbuf_complete(buf);
665 if (rc) {
666 return rc;
667 }
668
669 rc = pldm_msgbuf_init_errno(buf, req, data, len);
670 if (rc) {
671 return rc;
672 }
673
674 /* Ensure there's no arithmetic funkiness and the span is within buffer bounds */
Andrew Jeffery2613c272025-03-12 14:15:41 +1030675 rc = pldm_msgbuf_span_required(buf, dyn_length, &dyn_start);
676 if (rc) {
677 return pldm_msgbuf_discard(buf, rc);
678 }
679
John Chung7a8d9322025-08-27 20:56:19 -0500680 rc = pldm_msgbuf_span_remaining(buf, (const void **)tail_data,
681 tail_len);
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000682 if (rc) {
683 return pldm_msgbuf_discard(buf, rc);
684 }
685
686 rc = pldm_msgbuf_complete(buf);
687 if (rc) {
688 return rc;
689 }
690
Andrew Jeffery2613c272025-03-12 14:15:41 +1030691 return pldm_msgbuf_init_errno(buf, req, dyn_start, dyn_length);
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000692}
693
694#define PLDM_FWUP_FIRMWARE_DEVICE_ID_RECORD_MIN_SIZE 11
Andrew Jeffery2613c272025-03-12 14:15:41 +1030695static int decode_pldm_package_firmware_device_id_record_errno(
696 const pldm_package_header_information_pad *hdr,
697 struct variable_field *field,
698 struct pldm_package_firmware_device_id_record *rec)
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000699{
Carter Chen01782742025-06-25 13:53:50 +0800700 size_t firmware_device_package_data_offset;
John Chung7a8d9322025-08-27 20:56:19 -0500701 PLDM_MSGBUF_RO_DEFINE_P(buf);
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000702 uint16_t record_len = 0;
703 int rc;
704
Andrew Jeffery2613c272025-03-12 14:15:41 +1030705 if (!hdr || !field || !rec || !field->ptr) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030706 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930707 }
708
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000709 rc = pldm_msgbuf_init_dynamic_uint16(
Andrew Jeffery2613c272025-03-12 14:15:41 +1030710 buf, PLDM_FWUP_FIRMWARE_DEVICE_ID_RECORD_MIN_SIZE,
711 (void *)field->ptr, field->length, (void **)&field->ptr,
712 &field->length);
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000713 if (rc) {
714 return rc;
715 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930716
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000717 pldm_msgbuf_extract(buf, record_len);
718 pldm_msgbuf_extract(buf, rec->descriptor_count);
719 pldm_msgbuf_extract(buf, rec->device_update_option_flags.value);
720
721 rc = pldm_msgbuf_extract(buf,
722 rec->component_image_set_version_string_type);
723 if (rc) {
724 return pldm_msgbuf_discard(buf, rc);
725 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930726 if (!is_string_type_valid(
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000727 rec->component_image_set_version_string_type)) {
728 return pldm_msgbuf_discard(buf, -EPROTO);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930729 }
730
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000731 rc = pldm_msgbuf_extract_uint8_to_size(
732 buf, rec->component_image_set_version_string.length);
733 if (rc) {
734 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930735 }
736
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000737 if (rec->component_image_set_version_string.length == 0) {
738 return pldm_msgbuf_discard(buf, -EPROTO);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930739 }
740
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000741 rc = pldm_msgbuf_extract_uint16_to_size(
742 buf, rec->firmware_device_package_data.length);
743 if (rc) {
744 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930745 }
746
Carter Chen01782742025-06-25 13:53:50 +0800747 if (hdr->package_header_format_revision >=
748 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H) {
749 rc = pldm_msgbuf_extract_uint32_to_size(
750 buf, rec->reference_manifest_data.length);
751 if (rc) {
752 return pldm_msgbuf_discard(buf, rc);
753 }
754 } else {
755 rec->reference_manifest_data.length = 0;
756 }
757
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000758 assert((hdr->component_bitmap_bit_length & 7) == 0);
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000759 rc = pldm_msgbuf_span_required(
Andrew Jeffery2613c272025-03-12 14:15:41 +1030760 buf, hdr->component_bitmap_bit_length / 8,
John Chung7a8d9322025-08-27 20:56:19 -0500761 (const void **)&rec->applicable_components.bitmap.ptr);
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000762 if (rc) {
763 return pldm_msgbuf_discard(buf, rc);
764 }
765 rec->applicable_components.bitmap.length =
Andrew Jeffery2613c272025-03-12 14:15:41 +1030766 hdr->component_bitmap_bit_length / 8;
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000767
768 pldm_msgbuf_span_required(
769 buf, rec->component_image_set_version_string.length,
John Chung7a8d9322025-08-27 20:56:19 -0500770 (const void **)&rec->component_image_set_version_string.ptr);
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000771
Carter Chen01782742025-06-25 13:53:50 +0800772 /* The total length reserved for `package_data` and `reference_manifest_data` */
773 firmware_device_package_data_offset =
774 rec->firmware_device_package_data.length +
775 rec->reference_manifest_data.length;
776
777 pldm_msgbuf_span_until(buf, firmware_device_package_data_offset,
John Chung7a8d9322025-08-27 20:56:19 -0500778 (const void **)&rec->record_descriptors.ptr,
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000779 &rec->record_descriptors.length);
780
781 pldm_msgbuf_span_required(
782 buf, rec->firmware_device_package_data.length,
John Chung7a8d9322025-08-27 20:56:19 -0500783 (const void **)&rec->firmware_device_package_data.ptr);
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000784 if (!rec->firmware_device_package_data.length) {
785 rec->firmware_device_package_data.ptr = NULL;
786 }
787
Carter Chen01782742025-06-25 13:53:50 +0800788 if (hdr->package_header_format_revision >=
789 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H) {
790 pldm_msgbuf_span_required(
791 buf, rec->reference_manifest_data.length,
John Chung7a8d9322025-08-27 20:56:19 -0500792 (const void **)&rec->reference_manifest_data.ptr);
Carter Chen01782742025-06-25 13:53:50 +0800793
794 } else {
795 assert(rec->reference_manifest_data.length == 0);
796 rec->reference_manifest_data.ptr = NULL;
797 }
798
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000799 return pldm_msgbuf_complete_consumed(buf);
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030800}
801
802LIBPLDM_ABI_STABLE
803int decode_firmware_device_id_record(
804 const uint8_t *data, size_t length,
805 uint16_t component_bitmap_bit_length,
806 struct pldm_firmware_device_id_record *fw_device_id_record,
807 struct variable_field *applicable_components,
808 struct variable_field *comp_image_set_version_str,
809 struct variable_field *record_descriptors,
810 struct variable_field *fw_device_pkg_data)
811{
Andrew Jeffery2613c272025-03-12 14:15:41 +1030812 struct pldm_package_firmware_device_id_record rec;
813 pldm_package_header_information_pad hdr;
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030814 int rc;
815
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000816 if (!data || !fw_device_id_record || !applicable_components ||
817 !comp_image_set_version_str || !record_descriptors ||
818 !fw_device_pkg_data) {
819 return PLDM_ERROR_INVALID_DATA;
820 }
821
Andrew Jeffery2613c272025-03-12 14:15:41 +1030822 hdr.package_header_format_revision =
823 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H;
824 hdr.component_bitmap_bit_length = component_bitmap_bit_length;
825
826 rc = decode_pldm_package_firmware_device_id_record_errno(
827 &hdr, &(struct variable_field){ data, length }, &rec);
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030828 if (rc < 0) {
829 return pldm_xlate_errno(rc);
830 }
831
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000832 memcpy(&fw_device_id_record->record_length, data,
833 sizeof(fw_device_id_record->record_length));
834 LE16TOH(fw_device_id_record->record_length);
835 fw_device_id_record->descriptor_count = rec.descriptor_count;
836 fw_device_id_record->device_update_option_flags =
837 rec.device_update_option_flags;
838 fw_device_id_record->comp_image_set_version_string_type =
839 rec.component_image_set_version_string_type;
840 fw_device_id_record->comp_image_set_version_string_length =
841 rec.component_image_set_version_string.length;
842 fw_device_id_record->fw_device_pkg_data_length =
843 rec.firmware_device_package_data.length;
844 *applicable_components = rec.applicable_components.bitmap;
845 *comp_image_set_version_str = rec.component_image_set_version_string;
846 *record_descriptors = rec.record_descriptors;
847 *fw_device_pkg_data = rec.firmware_device_package_data;
848
Andrew Jeffery9c766792022-08-10 23:12:49 +0930849 return PLDM_SUCCESS;
850}
851
Unive Tiene5c3f142024-12-13 14:14:19 +0800852LIBPLDM_ABI_STABLE
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030853int decode_pldm_descriptor_from_iter(struct pldm_descriptor_iter *iter,
854 struct pldm_descriptor *desc)
855{
John Chung7a8d9322025-08-27 20:56:19 -0500856 PLDM_MSGBUF_RO_DEFINE_P(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030857 int rc;
858
859 if (!iter || !iter->field || !desc) {
860 return -EINVAL;
861 }
862
863 rc = pldm_msgbuf_init_errno(buf, PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN,
864 iter->field->ptr, iter->field->length);
865 if (rc) {
866 return rc;
867 }
868
869 pldm_msgbuf_extract(buf, desc->descriptor_type);
870 rc = pldm_msgbuf_extract(buf, desc->descriptor_length);
871 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +1030872 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030873 }
874
875 desc->descriptor_data = NULL;
876 pldm_msgbuf_span_required(buf, desc->descriptor_length,
John Chung7a8d9322025-08-27 20:56:19 -0500877 (const void **)&desc->descriptor_data);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030878 iter->field->ptr = NULL;
John Chung7a8d9322025-08-27 20:56:19 -0500879 pldm_msgbuf_span_remaining(buf, (const void **)&iter->field->ptr,
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030880 &iter->field->length);
881
Andrew Jeffery70d21c92025-03-05 12:59:42 +1030882 return pldm_msgbuf_complete(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030883}
884
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030885static int decode_descriptor_type_length_value_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030886 const void *data, size_t length, uint16_t *descriptor_type,
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030887 struct variable_field *descriptor_data)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930888{
889 uint16_t descriptor_length = 0;
890
891 if (data == NULL || descriptor_type == NULL ||
892 descriptor_data == NULL) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030893 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930894 }
895
896 if (length < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030897 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930898 }
899
900 struct pldm_descriptor_tlv *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930901 (struct pldm_descriptor_tlv *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930902
903 *descriptor_type = le16toh(entry->descriptor_type);
904 descriptor_length = le16toh(entry->descriptor_length);
905 if (*descriptor_type != PLDM_FWUP_VENDOR_DEFINED) {
906 if (descriptor_length !=
907 get_descriptor_type_length(*descriptor_type)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030908 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930909 }
910 }
911
912 if (length < (sizeof(*descriptor_type) + sizeof(descriptor_length) +
913 descriptor_length)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030914 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930915 }
916
917 descriptor_data->ptr = entry->descriptor_data;
918 descriptor_data->length = descriptor_length;
919
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030920 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930921}
922
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930923LIBPLDM_ABI_STABLE
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030924int decode_descriptor_type_length_value(const uint8_t *data, size_t length,
925 uint16_t *descriptor_type,
926 struct variable_field *descriptor_data)
927{
928 int rc;
929
930 rc = decode_descriptor_type_length_value_errno(
931 data, length, descriptor_type, descriptor_data);
932 if (rc < 0) {
933 return pldm_xlate_errno(rc);
934 }
935
936 return PLDM_SUCCESS;
937}
938
939static int decode_vendor_defined_descriptor_value_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030940 const void *data, size_t length, uint8_t *descriptor_title_str_type,
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930941 struct variable_field *descriptor_title_str,
942 struct variable_field *descriptor_data)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930943{
944 if (data == NULL || descriptor_title_str_type == NULL ||
945 descriptor_title_str == NULL || descriptor_data == NULL) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030946 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930947 }
948
949 if (length < sizeof(struct pldm_vendor_defined_descriptor_title_data)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030950 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930951 }
952
953 struct pldm_vendor_defined_descriptor_title_data *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930954 (struct pldm_vendor_defined_descriptor_title_data *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930955 if (!is_string_type_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930956 entry->vendor_defined_descriptor_title_str_type) ||
Andrew Jeffery9c766792022-08-10 23:12:49 +0930957 (entry->vendor_defined_descriptor_title_str_len == 0)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030958 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930959 }
960
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530961 // Assuming at least 1 byte of VendorDefinedDescriptorData
Andrew Jeffery9c766792022-08-10 23:12:49 +0930962 if (length < (sizeof(struct pldm_vendor_defined_descriptor_title_data) +
963 entry->vendor_defined_descriptor_title_str_len)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030964 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930965 }
966
967 *descriptor_title_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930968 entry->vendor_defined_descriptor_title_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930969 descriptor_title_str->ptr = entry->vendor_defined_descriptor_title_str;
970 descriptor_title_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930971 entry->vendor_defined_descriptor_title_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930972
973 descriptor_data->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930974 descriptor_title_str->ptr + descriptor_title_str->length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930975 descriptor_data->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930976 length -
977 sizeof(entry->vendor_defined_descriptor_title_str_type) -
978 sizeof(entry->vendor_defined_descriptor_title_str_len) -
979 descriptor_title_str->length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930980
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030981 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930982}
983
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930984LIBPLDM_ABI_STABLE
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030985int decode_vendor_defined_descriptor_value(
986 const uint8_t *data, size_t length, uint8_t *descriptor_title_str_type,
987 struct variable_field *descriptor_title_str,
988 struct variable_field *descriptor_data)
989{
990 int rc;
991
992 rc = decode_vendor_defined_descriptor_value_errno(
993 data, length, descriptor_title_str_type, descriptor_title_str,
994 descriptor_data);
995 if (rc < 0) {
996 return pldm_xlate_errno(rc);
997 }
998
999 return PLDM_SUCCESS;
1000}
1001
1002static int decode_pldm_comp_image_info_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +10301003 const void *data, size_t length,
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301004 struct pldm_component_image_information *pldm_comp_image_info,
1005 struct variable_field *comp_version_str)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301006{
1007 if (data == NULL || pldm_comp_image_info == NULL ||
1008 comp_version_str == NULL) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +10301009 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301010 }
1011
1012 if (length < sizeof(struct pldm_component_image_information)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +10301013 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301014 }
1015
1016 struct pldm_component_image_information *data_header =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301017 (struct pldm_component_image_information *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301018
1019 if (!is_string_type_valid(data_header->comp_version_string_type) ||
1020 (data_header->comp_version_string_length == 0)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +10301021 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301022 }
1023
1024 if (length < sizeof(struct pldm_component_image_information) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301025 data_header->comp_version_string_length) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +10301026 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301027 }
1028
1029 pldm_comp_image_info->comp_classification =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301030 le16toh(data_header->comp_classification);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301031 pldm_comp_image_info->comp_identifier =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301032 le16toh(data_header->comp_identifier);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301033 pldm_comp_image_info->comp_comparison_stamp =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301034 le32toh(data_header->comp_comparison_stamp);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301035 pldm_comp_image_info->comp_options.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301036 le16toh(data_header->comp_options.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301037 pldm_comp_image_info->requested_comp_activation_method.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301038 le16toh(data_header->requested_comp_activation_method.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301039 pldm_comp_image_info->comp_location_offset =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301040 le32toh(data_header->comp_location_offset);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301041 pldm_comp_image_info->comp_size = le32toh(data_header->comp_size);
1042 pldm_comp_image_info->comp_version_string_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301043 data_header->comp_version_string_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301044 pldm_comp_image_info->comp_version_string_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301045 data_header->comp_version_string_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301046
1047 if ((pldm_comp_image_info->comp_options.bits.bit1 == false &&
1048 pldm_comp_image_info->comp_comparison_stamp !=
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301049 PLDM_FWUP_INVALID_COMPONENT_COMPARISON_TIMESTAMP)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +10301050 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301051 }
1052
1053 if (pldm_comp_image_info->comp_location_offset == 0 ||
1054 pldm_comp_image_info->comp_size == 0) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +10301055 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301056 }
1057
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +10301058 comp_version_str->ptr = (const uint8_t *)data +
1059 sizeof(struct pldm_component_image_information);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301060 comp_version_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301061 pldm_comp_image_info->comp_version_string_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301062
Andrew Jeffery779e9db2025-02-21 12:14:28 +10301063 return 0;
1064}
1065
1066LIBPLDM_ABI_STABLE
1067int decode_pldm_comp_image_info(
1068 const uint8_t *data, size_t length,
1069 struct pldm_component_image_information *pldm_comp_image_info,
1070 struct variable_field *comp_version_str)
1071{
1072 int rc;
1073
1074 rc = decode_pldm_comp_image_info_errno(
1075 data, length, pldm_comp_image_info, comp_version_str);
1076 if (rc < 0) {
1077 return pldm_xlate_errno(rc);
1078 }
1079
Andrew Jeffery9c766792022-08-10 23:12:49 +09301080 return PLDM_SUCCESS;
1081}
1082
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301083LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301084int encode_query_device_identifiers_req(uint8_t instance_id,
1085 size_t payload_length,
1086 struct pldm_msg *msg)
1087{
1088 if (msg == NULL) {
1089 return PLDM_ERROR_INVALID_DATA;
1090 }
1091
1092 if (payload_length != PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES) {
1093 return PLDM_ERROR_INVALID_LENGTH;
1094 }
1095
1096 return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
1097 PLDM_QUERY_DEVICE_IDENTIFIERS, msg);
1098}
1099
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301100LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301101int decode_query_device_identifiers_resp(const struct pldm_msg *msg,
1102 size_t payload_length,
1103 uint8_t *completion_code,
1104 uint32_t *device_identifiers_len,
1105 uint8_t *descriptor_count,
1106 uint8_t **descriptor_data)
1107{
1108 if (msg == NULL || completion_code == NULL ||
1109 device_identifiers_len == NULL || descriptor_count == NULL ||
1110 descriptor_data == NULL) {
1111 return PLDM_ERROR_INVALID_DATA;
1112 }
1113
1114 *completion_code = msg->payload[0];
1115 if (PLDM_SUCCESS != *completion_code) {
1116 return PLDM_SUCCESS;
1117 }
1118
1119 if (payload_length <
1120 sizeof(struct pldm_query_device_identifiers_resp)) {
1121 return PLDM_ERROR_INVALID_LENGTH;
1122 }
1123
1124 struct pldm_query_device_identifiers_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301125 (struct pldm_query_device_identifiers_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301126 *device_identifiers_len = le32toh(response->device_identifiers_len);
1127
1128 if (*device_identifiers_len < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {
1129 return PLDM_ERROR_INVALID_LENGTH;
1130 }
1131
1132 if (payload_length !=
1133 sizeof(struct pldm_query_device_identifiers_resp) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301134 *device_identifiers_len) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301135 return PLDM_ERROR_INVALID_LENGTH;
1136 }
1137 *descriptor_count = response->descriptor_count;
1138
1139 if (*descriptor_count == 0) {
1140 return PLDM_ERROR_INVALID_DATA;
1141 }
1142 *descriptor_data =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301143 (uint8_t *)(msg->payload +
1144 sizeof(struct pldm_query_device_identifiers_resp));
Andrew Jeffery9c766792022-08-10 23:12:49 +09301145 return PLDM_SUCCESS;
1146}
1147
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001148LIBPLDM_ABI_TESTING
1149int encode_query_device_identifiers_resp(
1150 uint8_t instance_id, uint8_t descriptor_count,
1151 const struct pldm_descriptor *descriptors, struct pldm_msg *msg,
1152 size_t *payload_length)
1153{
John Chung7a8d9322025-08-27 20:56:19 -05001154 PLDM_MSGBUF_RW_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001155 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001156
1157 if (descriptors == NULL || msg == NULL || payload_length == NULL) {
1158 return -EINVAL;
1159 }
1160
1161 if (descriptor_count < 1) {
1162 return -EINVAL;
1163 }
1164
1165 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
1166 PLDM_QUERY_DEVICE_IDENTIFIERS, msg);
1167 if (rc) {
1168 return -EINVAL;
1169 }
1170
1171 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
1172 if (rc) {
1173 return rc;
1174 }
1175
1176 /* Determine total length */
1177 uint32_t device_identifiers_len = 0;
1178 for (uint8_t i = 0; i < descriptor_count; i++) {
1179 const struct pldm_descriptor *d = &descriptors[i];
1180 device_identifiers_len +=
1181 2 * sizeof(uint16_t) + d->descriptor_length;
1182 }
1183
1184 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
1185 pldm_msgbuf_insert(buf, device_identifiers_len);
1186 pldm_msgbuf_insert(buf, descriptor_count);
1187
1188 for (uint8_t i = 0; i < descriptor_count; i++) {
1189 const struct pldm_descriptor *d = &descriptors[i];
1190 pldm_msgbuf_insert(buf, d->descriptor_type);
1191 pldm_msgbuf_insert(buf, d->descriptor_length);
1192 if (d->descriptor_data == NULL) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301193 return pldm_msgbuf_discard(buf, -EINVAL);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001194 }
1195 rc = pldm_msgbuf_insert_array(
1196 buf, d->descriptor_length,
1197 (const uint8_t *)d->descriptor_data,
1198 d->descriptor_length);
1199 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301200 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001201 }
1202 }
1203
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301204 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001205}
1206
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301207LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301208int encode_get_firmware_parameters_req(uint8_t instance_id,
1209 size_t payload_length,
1210 struct pldm_msg *msg)
1211{
1212 if (msg == NULL) {
1213 return PLDM_ERROR_INVALID_DATA;
1214 }
1215
1216 if (payload_length != PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES) {
1217 return PLDM_ERROR_INVALID_LENGTH;
1218 }
1219
1220 return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
1221 PLDM_GET_FIRMWARE_PARAMETERS, msg);
1222}
1223
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301224LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301225int decode_get_firmware_parameters_resp(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301226 const struct pldm_msg *msg, size_t payload_length,
1227 struct pldm_get_firmware_parameters_resp *resp_data,
1228 struct variable_field *active_comp_image_set_ver_str,
1229 struct variable_field *pending_comp_image_set_ver_str,
1230 struct variable_field *comp_parameter_table)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301231{
1232 if (msg == NULL || resp_data == NULL ||
1233 active_comp_image_set_ver_str == NULL ||
1234 pending_comp_image_set_ver_str == NULL ||
1235 comp_parameter_table == NULL || !payload_length) {
1236 return PLDM_ERROR_INVALID_DATA;
1237 }
1238
1239 resp_data->completion_code = msg->payload[0];
1240 if (PLDM_SUCCESS != resp_data->completion_code) {
1241 return PLDM_SUCCESS;
1242 }
1243
1244 if (payload_length < sizeof(struct pldm_get_firmware_parameters_resp)) {
1245 return PLDM_ERROR_INVALID_LENGTH;
1246 }
1247
1248 struct pldm_get_firmware_parameters_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301249 (struct pldm_get_firmware_parameters_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301250
1251 if (!is_string_type_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301252 response->active_comp_image_set_ver_str_type) ||
Andrew Jeffery9c766792022-08-10 23:12:49 +09301253 (response->active_comp_image_set_ver_str_len == 0)) {
1254 return PLDM_ERROR_INVALID_DATA;
1255 }
1256
1257 if (response->pending_comp_image_set_ver_str_len == 0) {
1258 if (response->pending_comp_image_set_ver_str_type !=
1259 PLDM_STR_TYPE_UNKNOWN) {
1260 return PLDM_ERROR_INVALID_DATA;
1261 }
1262 } else {
1263 if (!is_string_type_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301264 response->pending_comp_image_set_ver_str_type)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301265 return PLDM_ERROR_INVALID_DATA;
1266 }
1267 }
1268
1269 size_t partial_response_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301270 sizeof(struct pldm_get_firmware_parameters_resp) +
1271 response->active_comp_image_set_ver_str_len +
1272 response->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301273
1274 if (payload_length < partial_response_length) {
1275 return PLDM_ERROR_INVALID_LENGTH;
1276 }
1277
1278 resp_data->capabilities_during_update.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301279 le32toh(response->capabilities_during_update.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301280 resp_data->comp_count = le16toh(response->comp_count);
1281 resp_data->active_comp_image_set_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301282 response->active_comp_image_set_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301283 resp_data->active_comp_image_set_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301284 response->active_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301285 resp_data->pending_comp_image_set_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301286 response->pending_comp_image_set_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301287 resp_data->pending_comp_image_set_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301288 response->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301289
1290 active_comp_image_set_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301291 msg->payload + sizeof(struct pldm_get_firmware_parameters_resp);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301292 active_comp_image_set_ver_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301293 resp_data->active_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301294
1295 if (resp_data->pending_comp_image_set_ver_str_len != 0) {
1296 pending_comp_image_set_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301297 msg->payload +
1298 sizeof(struct pldm_get_firmware_parameters_resp) +
1299 resp_data->active_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301300 pending_comp_image_set_ver_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301301 resp_data->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301302 } else {
1303 pending_comp_image_set_ver_str->ptr = NULL;
1304 pending_comp_image_set_ver_str->length = 0;
1305 }
1306
1307 if (payload_length > partial_response_length && resp_data->comp_count) {
1308 comp_parameter_table->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301309 msg->payload +
1310 sizeof(struct pldm_get_firmware_parameters_resp) +
1311 resp_data->active_comp_image_set_ver_str_len +
1312 resp_data->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301313 comp_parameter_table->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301314 payload_length - partial_response_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301315 } else {
1316 comp_parameter_table->ptr = NULL;
1317 comp_parameter_table->length = 0;
1318 }
1319
1320 return PLDM_SUCCESS;
1321}
1322
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001323LIBPLDM_ABI_TESTING
1324int encode_get_firmware_parameters_resp(
1325 uint8_t instance_id,
1326 const struct pldm_get_firmware_parameters_resp_full *resp_data,
1327 struct pldm_msg *msg, size_t *payload_length)
1328{
John Chung7a8d9322025-08-27 20:56:19 -05001329 PLDM_MSGBUF_RW_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001330 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001331
1332 if (resp_data == NULL || msg == NULL || payload_length == NULL) {
1333 return -EINVAL;
1334 }
1335
1336 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
1337 PLDM_GET_FIRMWARE_PARAMETERS, msg);
1338 if (rc) {
1339 return -EINVAL;
1340 }
1341
1342 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
1343 if (rc) {
1344 return rc;
1345 }
1346
1347 pldm_msgbuf_insert(buf, resp_data->completion_code);
1348 pldm_msgbuf_insert(buf, resp_data->capabilities_during_update.value);
1349 pldm_msgbuf_insert(buf, resp_data->comp_count);
1350 pldm_msgbuf_insert(buf,
1351 resp_data->active_comp_image_set_ver_str.str_type);
1352 pldm_msgbuf_insert(buf,
1353 resp_data->active_comp_image_set_ver_str.str_len);
1354 pldm_msgbuf_insert(buf,
1355 resp_data->pending_comp_image_set_ver_str.str_type);
1356 pldm_msgbuf_insert(buf,
1357 resp_data->pending_comp_image_set_ver_str.str_len);
1358 /* String data appended */
1359 rc = pldm_msgbuf_insert_array(
1360 buf, resp_data->active_comp_image_set_ver_str.str_len,
1361 resp_data->active_comp_image_set_ver_str.str_data,
1362 resp_data->active_comp_image_set_ver_str.str_len);
1363 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301364 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001365 }
1366 rc = pldm_msgbuf_insert_array(
1367 buf, resp_data->pending_comp_image_set_ver_str.str_len,
1368 resp_data->pending_comp_image_set_ver_str.str_data,
1369 resp_data->pending_comp_image_set_ver_str.str_len);
1370 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301371 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001372 }
1373
1374 /* Further calls to encode_get_firmware_parameters_resp_comp_entry
1375 * will populate the remainder */
1376
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301377 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001378}
1379
1380LIBPLDM_ABI_TESTING
1381int encode_get_firmware_parameters_resp_comp_entry(
1382 const struct pldm_component_parameter_entry_full *comp,
1383 uint8_t *payload, size_t *payload_length)
1384{
John Chung7a8d9322025-08-27 20:56:19 -05001385 PLDM_MSGBUF_RW_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001386 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001387
1388 if (comp == NULL || payload == NULL || payload_length == NULL) {
1389 return -EINVAL;
1390 }
1391
1392 rc = pldm_msgbuf_init_errno(buf, 0, payload, *payload_length);
1393 if (rc) {
1394 return rc;
1395 }
1396
1397 pldm_msgbuf_insert(buf, comp->comp_classification);
1398 pldm_msgbuf_insert(buf, comp->comp_identifier);
1399 pldm_msgbuf_insert(buf, comp->comp_classification_index);
1400
1401 pldm_msgbuf_insert(buf, comp->active_ver.comparison_stamp);
1402 pldm_msgbuf_insert(buf, (uint8_t)comp->active_ver.str.str_type);
1403 pldm_msgbuf_insert(buf, comp->active_ver.str.str_len);
1404 rc = pldm_msgbuf_insert_array(buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1405 comp->active_ver.date,
1406 PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN);
1407 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301408 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001409 }
1410
1411 pldm_msgbuf_insert(buf, comp->pending_ver.comparison_stamp);
1412 pldm_msgbuf_insert(buf, (uint8_t)comp->pending_ver.str.str_type);
1413 pldm_msgbuf_insert(buf, comp->pending_ver.str.str_len);
1414 rc = pldm_msgbuf_insert_array(buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1415 comp->pending_ver.date,
1416 PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN);
1417 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301418 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001419 }
1420
1421 pldm_msgbuf_insert(buf, comp->comp_activation_methods.value);
1422 pldm_msgbuf_insert(buf, comp->capabilities_during_update.value);
1423
1424 rc = pldm_msgbuf_insert_array(buf, comp->active_ver.str.str_len,
1425 comp->active_ver.str.str_data,
1426 comp->active_ver.str.str_len);
1427 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301428 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001429 }
1430 rc = pldm_msgbuf_insert_array(buf, comp->pending_ver.str.str_len,
1431 comp->pending_ver.str.str_data,
1432 comp->pending_ver.str.str_len);
1433 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301434 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001435 }
1436
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301437 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001438}
1439
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301440LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301441int decode_get_firmware_parameters_resp_comp_entry(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301442 const uint8_t *data, size_t length,
1443 struct pldm_component_parameter_entry *component_data,
1444 struct variable_field *active_comp_ver_str,
1445 struct variable_field *pending_comp_ver_str)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301446{
1447 if (data == NULL || component_data == NULL ||
1448 active_comp_ver_str == NULL || pending_comp_ver_str == NULL) {
1449 return PLDM_ERROR_INVALID_DATA;
1450 }
1451
1452 if (length < sizeof(struct pldm_component_parameter_entry)) {
1453 return PLDM_ERROR_INVALID_LENGTH;
1454 }
1455
1456 struct pldm_component_parameter_entry *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301457 (struct pldm_component_parameter_entry *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301458
1459 size_t entry_length = sizeof(struct pldm_component_parameter_entry) +
1460 entry->active_comp_ver_str_len +
1461 entry->pending_comp_ver_str_len;
1462
1463 if (length < entry_length) {
1464 return PLDM_ERROR_INVALID_LENGTH;
1465 }
1466
1467 component_data->comp_classification =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301468 le16toh(entry->comp_classification);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301469 component_data->comp_identifier = le16toh(entry->comp_identifier);
1470 component_data->comp_classification_index =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301471 entry->comp_classification_index;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301472 component_data->active_comp_comparison_stamp =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301473 le32toh(entry->active_comp_comparison_stamp);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301474 component_data->active_comp_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301475 entry->active_comp_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301476 component_data->active_comp_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301477 entry->active_comp_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301478 memcpy(component_data->active_comp_release_date,
1479 entry->active_comp_release_date,
1480 sizeof(entry->active_comp_release_date));
1481 component_data->pending_comp_comparison_stamp =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301482 le32toh(entry->pending_comp_comparison_stamp);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301483 component_data->pending_comp_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301484 entry->pending_comp_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301485 component_data->pending_comp_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301486 entry->pending_comp_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301487 memcpy(component_data->pending_comp_release_date,
1488 entry->pending_comp_release_date,
1489 sizeof(entry->pending_comp_release_date));
1490 component_data->comp_activation_methods.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301491 le16toh(entry->comp_activation_methods.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301492 component_data->capabilities_during_update.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301493 le32toh(entry->capabilities_during_update.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301494
1495 if (entry->active_comp_ver_str_len != 0) {
1496 active_comp_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301497 data + sizeof(struct pldm_component_parameter_entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301498 active_comp_ver_str->length = entry->active_comp_ver_str_len;
1499 } else {
1500 active_comp_ver_str->ptr = NULL;
1501 active_comp_ver_str->length = 0;
1502 }
1503
1504 if (entry->pending_comp_ver_str_len != 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301505 pending_comp_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301506 data + sizeof(struct pldm_component_parameter_entry) +
1507 entry->active_comp_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301508 pending_comp_ver_str->length = entry->pending_comp_ver_str_len;
1509 } else {
1510 pending_comp_ver_str->ptr = NULL;
1511 pending_comp_ver_str->length = 0;
1512 }
1513 return PLDM_SUCCESS;
1514}
1515
Unive Tiene5c3f142024-12-13 14:14:19 +08001516LIBPLDM_ABI_STABLE
Chris Wang4c1f2c72024-03-21 17:09:44 +08001517int encode_query_downstream_devices_req(uint8_t instance_id,
1518 struct pldm_msg *msg)
1519{
1520 if (msg == NULL) {
Unive Tien71e935c2024-11-25 17:21:43 +08001521 return -EINVAL;
Chris Wang4c1f2c72024-03-21 17:09:44 +08001522 }
1523
Unive Tien71e935c2024-11-25 17:21:43 +08001524 return encode_pldm_header_only_errno(PLDM_REQUEST, instance_id,
1525 PLDM_FWUP,
1526 PLDM_QUERY_DOWNSTREAM_DEVICES,
1527 msg);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001528}
1529
Unive Tiene5c3f142024-12-13 14:14:19 +08001530LIBPLDM_ABI_STABLE
Chris Wang4c1f2c72024-03-21 17:09:44 +08001531int decode_query_downstream_devices_resp(
1532 const struct pldm_msg *msg, size_t payload_length,
1533 struct pldm_query_downstream_devices_resp *resp_data)
1534{
John Chung7a8d9322025-08-27 20:56:19 -05001535 PLDM_MSGBUF_RO_DEFINE_P(buf);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001536 int rc;
1537
1538 if (msg == NULL || resp_data == NULL || !payload_length) {
Unive Tien71e935c2024-11-25 17:21:43 +08001539 return -EINVAL;
Chris Wang4c1f2c72024-03-21 17:09:44 +08001540 }
1541
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301542 rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1543 msg->payload, payload_length);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001544 if (rc) {
1545 return rc;
1546 }
1547
1548 rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1549 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301550 return pldm_msgbuf_discard(buf, rc);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001551 }
1552 if (PLDM_SUCCESS != resp_data->completion_code) {
1553 // Return the CC directly without decoding the rest of the payload
Andrew Jefferya1896962025-03-03 21:41:25 +10301554 return pldm_msgbuf_complete(buf);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001555 }
1556
1557 if (payload_length < PLDM_QUERY_DOWNSTREAM_DEVICES_RESP_BYTES) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301558 return pldm_msgbuf_discard(buf, -EBADMSG);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001559 }
1560
1561 rc = pldm_msgbuf_extract(buf,
1562 resp_data->downstream_device_update_supported);
1563 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301564 return pldm_msgbuf_discard(buf, rc);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001565 }
1566
1567 if (!is_downstream_device_update_support_valid(
1568 resp_data->downstream_device_update_supported)) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301569 return pldm_msgbuf_discard(buf, -EINVAL);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001570 }
1571
1572 pldm_msgbuf_extract(buf, resp_data->number_of_downstream_devices);
1573 pldm_msgbuf_extract(buf, resp_data->max_number_of_downstream_devices);
1574 pldm_msgbuf_extract(buf, resp_data->capabilities.value);
1575
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301576 return pldm_msgbuf_complete_consumed(buf);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001577}
1578
Unive Tiene5c3f142024-12-13 14:14:19 +08001579LIBPLDM_ABI_STABLE
Chris Wang458475a2024-03-26 17:59:19 +08001580int encode_query_downstream_identifiers_req(
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001581 uint8_t instance_id,
1582 const struct pldm_query_downstream_identifiers_req *params_req,
1583 struct pldm_msg *msg, size_t payload_length)
Chris Wang458475a2024-03-26 17:59:19 +08001584{
John Chung7a8d9322025-08-27 20:56:19 -05001585 PLDM_MSGBUF_RW_DEFINE_P(buf);
Chris Wang458475a2024-03-26 17:59:19 +08001586 int rc;
1587
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001588 if (!msg || !params_req) {
Unive Tien71e935c2024-11-25 17:21:43 +08001589 return -EINVAL;
Chris Wang458475a2024-03-26 17:59:19 +08001590 }
1591
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001592 if (!is_transfer_operation_flag_valid(
1593 (enum transfer_op_flag)
1594 params_req->transfer_operation_flag)) {
Unive Tien71e935c2024-11-25 17:21:43 +08001595 return -EINVAL;
Chris Wang458475a2024-03-26 17:59:19 +08001596 }
1597
1598 struct pldm_header_info header = { 0 };
1599 header.instance = instance_id;
1600 header.msg_type = PLDM_REQUEST;
1601 header.pldm_type = PLDM_FWUP;
1602 header.command = PLDM_QUERY_DOWNSTREAM_IDENTIFIERS;
Unive Tien71e935c2024-11-25 17:21:43 +08001603 rc = pack_pldm_header_errno(&header, &(msg->hdr));
Chris Wang458475a2024-03-26 17:59:19 +08001604 if (rc) {
1605 return rc;
1606 }
1607
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301608 rc = pldm_msgbuf_init_errno(buf,
1609 PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_REQ_BYTES,
1610 msg->payload, payload_length);
Chris Wang458475a2024-03-26 17:59:19 +08001611 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001612 return rc;
Chris Wang458475a2024-03-26 17:59:19 +08001613 }
1614
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001615 pldm_msgbuf_insert(buf, params_req->data_transfer_handle);
Chris Wang458475a2024-03-26 17:59:19 +08001616 // Data correctness has been verified, cast it to 1-byte data directly.
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001617 pldm_msgbuf_insert(buf, params_req->transfer_operation_flag);
Chris Wang458475a2024-03-26 17:59:19 +08001618
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301619 return pldm_msgbuf_complete(buf);
Chris Wang458475a2024-03-26 17:59:19 +08001620}
1621
Unive Tiene5c3f142024-12-13 14:14:19 +08001622LIBPLDM_ABI_STABLE
Chris Wang458475a2024-03-26 17:59:19 +08001623int decode_query_downstream_identifiers_resp(
1624 const struct pldm_msg *msg, size_t payload_length,
1625 struct pldm_query_downstream_identifiers_resp *resp_data,
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301626 struct pldm_downstream_device_iter *iter)
Chris Wang458475a2024-03-26 17:59:19 +08001627{
John Chung7a8d9322025-08-27 20:56:19 -05001628 PLDM_MSGBUF_RO_DEFINE_P(buf);
1629 const void *remaining = NULL;
Unive Tien71e935c2024-11-25 17:21:43 +08001630 int rc = 0;
Chris Wang458475a2024-03-26 17:59:19 +08001631
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301632 if (msg == NULL || resp_data == NULL || iter == NULL ||
Chris Wang458475a2024-03-26 17:59:19 +08001633 !payload_length) {
Unive Tien71e935c2024-11-25 17:21:43 +08001634 return -EINVAL;
Chris Wang458475a2024-03-26 17:59:19 +08001635 }
1636
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301637 rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1638 msg->payload, payload_length);
Chris Wang458475a2024-03-26 17:59:19 +08001639 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001640 return rc;
Chris Wang458475a2024-03-26 17:59:19 +08001641 }
1642
1643 rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1644 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301645 return pldm_msgbuf_discard(buf, rc);
Chris Wang458475a2024-03-26 17:59:19 +08001646 }
1647 if (PLDM_SUCCESS != resp_data->completion_code) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301648 return pldm_msgbuf_complete(buf);
Chris Wang458475a2024-03-26 17:59:19 +08001649 }
1650
1651 if (payload_length < PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_RESP_MIN_LEN) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301652 return pldm_msgbuf_discard(buf, -EBADMSG);
Chris Wang458475a2024-03-26 17:59:19 +08001653 }
1654
1655 pldm_msgbuf_extract(buf, resp_data->next_data_transfer_handle);
1656 pldm_msgbuf_extract(buf, resp_data->transfer_flag);
1657
1658 rc = pldm_msgbuf_extract(buf, resp_data->downstream_devices_length);
1659 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301660 return pldm_msgbuf_discard(buf, rc);
Chris Wang458475a2024-03-26 17:59:19 +08001661 }
1662
1663 pldm_msgbuf_extract(buf, resp_data->number_of_downstream_devices);
Andrew Jefferya1896962025-03-03 21:41:25 +10301664 pldm_msgbuf_span_required(buf, resp_data->downstream_devices_length,
1665 &remaining);
Chris Wang458475a2024-03-26 17:59:19 +08001666
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301667 rc = pldm_msgbuf_complete(buf);
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301668 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001669 return rc;
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301670 }
1671
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301672 iter->field.ptr = remaining;
1673 iter->field.length = resp_data->downstream_devices_length;
1674 iter->devs = resp_data->number_of_downstream_devices;
1675
Unive Tien71e935c2024-11-25 17:21:43 +08001676 return 0;
Chris Wang458475a2024-03-26 17:59:19 +08001677}
1678
Unive Tiene5c3f142024-12-13 14:14:19 +08001679LIBPLDM_ABI_STABLE
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301680int decode_pldm_downstream_device_from_iter(
1681 struct pldm_downstream_device_iter *iter,
1682 struct pldm_downstream_device *dev)
1683{
John Chung7a8d9322025-08-27 20:56:19 -05001684 PLDM_MSGBUF_RO_DEFINE_P(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301685 int rc;
1686
Andrew Jefferya1896962025-03-03 21:41:25 +10301687 if (!iter || !iter->field.ptr || !dev) {
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301688 return -EINVAL;
1689 }
1690
1691 rc = pldm_msgbuf_init_errno(buf, 3, iter->field.ptr,
1692 iter->field.length);
1693 if (rc) {
1694 return rc;
1695 }
1696
1697 pldm_msgbuf_extract(buf, dev->downstream_device_index);
1698 pldm_msgbuf_extract(buf, dev->downstream_descriptor_count);
John Chung7a8d9322025-08-27 20:56:19 -05001699 pldm_msgbuf_span_remaining(buf, (const void **)&iter->field.ptr,
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301700 &iter->field.length);
1701
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301702 return pldm_msgbuf_complete(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301703}
1704
Unive Tiene5c3f142024-12-13 14:14:19 +08001705LIBPLDM_ABI_STABLE
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301706int encode_get_downstream_firmware_parameters_req(
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001707 uint8_t instance_id,
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301708 const struct pldm_get_downstream_firmware_parameters_req *params_req,
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001709 struct pldm_msg *msg, size_t payload_length)
Chris Wangb6ef35b2024-07-03 09:35:42 +08001710{
John Chung7a8d9322025-08-27 20:56:19 -05001711 PLDM_MSGBUF_RW_DEFINE_P(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001712 int rc;
1713
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001714 if (!msg || !params_req) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001715 return -EINVAL;
1716 }
1717
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001718 if (!is_transfer_operation_flag_valid(
1719 (enum transfer_op_flag)
1720 params_req->transfer_operation_flag)) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001721 return -EBADMSG;
1722 }
1723
1724 struct pldm_header_info header = { 0 };
1725 header.instance = instance_id;
1726 header.msg_type = PLDM_REQUEST;
1727 header.pldm_type = PLDM_FWUP;
1728 header.command = PLDM_QUERY_DOWNSTREAM_FIRMWARE_PARAMETERS;
1729 rc = pack_pldm_header_errno(&header, &msg->hdr);
1730 if (rc < 0) {
1731 return rc;
1732 }
1733
Andrew Jeffery53b08672025-03-04 12:26:18 +10301734 rc = pldm_msgbuf_init_errno(
1735 buf, PLDM_GET_DOWNSTREAM_FIRMWARE_PARAMETERS_REQ_BYTES,
1736 msg->payload, payload_length);
1737 if (rc < 0) {
1738 return rc;
1739 }
1740
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001741 pldm_msgbuf_insert(buf, params_req->data_transfer_handle);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001742 // Data correctness has been verified, cast it to 1-byte data directly.
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001743 pldm_msgbuf_insert(buf, params_req->transfer_operation_flag);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001744
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301745 return pldm_msgbuf_complete(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001746}
1747
Unive Tiene5c3f142024-12-13 14:14:19 +08001748LIBPLDM_ABI_STABLE
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301749int decode_get_downstream_firmware_parameters_resp(
Chris Wangb6ef35b2024-07-03 09:35:42 +08001750 const struct pldm_msg *msg, size_t payload_length,
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301751 struct pldm_get_downstream_firmware_parameters_resp *resp_data,
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301752 struct pldm_downstream_device_parameters_iter *iter)
Chris Wangb6ef35b2024-07-03 09:35:42 +08001753{
John Chung7a8d9322025-08-27 20:56:19 -05001754 PLDM_MSGBUF_RO_DEFINE_P(buf);
1755 const void *remaining = NULL;
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301756 size_t length;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001757 int rc;
1758
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301759 if (msg == NULL || resp_data == NULL || iter == NULL) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001760 return -EINVAL;
1761 }
1762
1763 rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1764 msg->payload, payload_length);
1765 if (rc < 0) {
1766 return rc;
1767 }
1768
1769 rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1770 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301771 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001772 }
1773 if (PLDM_SUCCESS != resp_data->completion_code) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301774 return pldm_msgbuf_complete(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001775 }
1776
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301777 if (payload_length <
1778 PLDM_GET_DOWNSTREAM_FIRMWARE_PARAMETERS_RESP_MIN_LEN) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301779 return pldm_msgbuf_discard(buf, -EBADMSG);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001780 }
1781
1782 pldm_msgbuf_extract(buf, resp_data->next_data_transfer_handle);
1783 pldm_msgbuf_extract(buf, resp_data->transfer_flag);
1784 pldm_msgbuf_extract(buf,
1785 resp_data->fdp_capabilities_during_update.value);
1786 pldm_msgbuf_extract(buf, resp_data->downstream_device_count);
1787
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301788 rc = pldm_msgbuf_span_remaining(buf, &remaining, &length);
1789 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301790 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301791 }
1792
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301793 rc = pldm_msgbuf_complete(buf);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301794 if (rc) {
1795 return rc;
1796 }
1797
1798 iter->field.ptr = remaining;
1799 iter->field.length = length;
1800 iter->entries = resp_data->downstream_device_count;
1801
1802 return 0;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001803}
1804
Unive Tiene5c3f142024-12-13 14:14:19 +08001805LIBPLDM_ABI_STABLE
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301806int decode_pldm_downstream_device_parameters_entry_from_iter(
1807 struct pldm_downstream_device_parameters_iter *iter,
1808 struct pldm_downstream_device_parameters_entry *entry)
Chris Wangb6ef35b2024-07-03 09:35:42 +08001809{
John Chung7a8d9322025-08-27 20:56:19 -05001810 PLDM_MSGBUF_RO_DEFINE_P(buf);
1811 const void *comp_ver_str;
1812 const void *cursor;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001813 size_t remaining;
1814 int rc;
1815
Andrew Jefferya1896962025-03-03 21:41:25 +10301816 if (iter == NULL || iter->field.ptr == NULL || entry == NULL) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001817 return -EINVAL;
1818 }
1819
1820 rc = pldm_msgbuf_init_errno(
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301821 buf, PLDM_DOWNSTREAM_DEVICE_PARAMETERS_ENTRY_MIN_LEN,
1822 iter->field.ptr, iter->field.length);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001823 if (rc < 0) {
1824 return rc;
1825 }
1826
1827 pldm_msgbuf_extract(buf, entry->downstream_device_index);
1828 pldm_msgbuf_extract(buf, entry->active_comp_comparison_stamp);
1829 pldm_msgbuf_extract(buf, entry->active_comp_ver_str_type);
1830 rc = pldm_msgbuf_extract(buf, entry->active_comp_ver_str_len);
1831 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301832 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001833 }
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001834 rc = pldm_msgbuf_extract_array(buf,
1835 PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1836 entry->active_comp_release_date,
1837 sizeof(entry->active_comp_release_date));
1838 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301839 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001840 }
1841
Chris Wangb6ef35b2024-07-03 09:35:42 +08001842 // Fill the last byte with NULL character
1843 entry->active_comp_release_date[PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN] =
1844 '\0';
1845
1846 pldm_msgbuf_extract(buf, entry->pending_comp_comparison_stamp);
1847 pldm_msgbuf_extract(buf, entry->pending_comp_ver_str_type);
1848 rc = pldm_msgbuf_extract(buf, entry->pending_comp_ver_str_len);
1849 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301850 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001851 }
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001852
1853 rc = pldm_msgbuf_extract_array(
1854 buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1855 entry->pending_comp_release_date,
1856 sizeof(entry->pending_comp_release_date));
1857 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301858 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001859 }
1860
Chris Wangb6ef35b2024-07-03 09:35:42 +08001861 // Fill the last byte with NULL character
1862 entry->pending_comp_release_date[PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN] =
1863 '\0';
1864
1865 pldm_msgbuf_extract(buf, entry->comp_activation_methods.value);
1866 pldm_msgbuf_extract(buf, entry->capabilities_during_update.value);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001867
Andrew Jefferya1896962025-03-03 21:41:25 +10301868 rc = pldm_msgbuf_span_required(buf, entry->active_comp_ver_str_len,
1869 &comp_ver_str);
1870 if (rc < 0) {
1871 return pldm_msgbuf_discard(buf, rc);
1872 }
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301873 entry->active_comp_ver_str = comp_ver_str;
1874
Andrew Jefferya1896962025-03-03 21:41:25 +10301875 rc = pldm_msgbuf_span_required(buf, entry->pending_comp_ver_str_len,
1876 &comp_ver_str);
1877 if (rc < 0) {
1878 return pldm_msgbuf_discard(buf, rc);
1879 }
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301880 entry->pending_comp_ver_str = comp_ver_str;
1881
Chris Wangb6ef35b2024-07-03 09:35:42 +08001882 rc = pldm_msgbuf_span_remaining(buf, &cursor, &remaining);
1883 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301884 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001885 }
1886
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301887 iter->field.ptr = cursor;
1888 iter->field.length = remaining;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001889
Andrew Jefferya1896962025-03-03 21:41:25 +10301890 return pldm_msgbuf_complete(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001891}
1892
Sora Su06eadd02025-05-27 11:28:51 +08001893LIBPLDM_ABI_TESTING
1894int encode_request_downstream_device_update_req(
1895 uint8_t instance_id,
1896 const struct pldm_request_downstream_device_update_req *req_data,
1897 struct pldm_msg *msg, size_t *payload_length)
1898{
John Chung7a8d9322025-08-27 20:56:19 -05001899 PLDM_MSGBUF_RW_DEFINE_P(buf);
Sora Su06eadd02025-05-27 11:28:51 +08001900 int rc;
1901
1902 if (!req_data || !msg || !payload_length ||
1903 req_data->maximum_downstream_device_transfer_size <
1904 PLDM_FWUP_BASELINE_TRANSFER_SIZE ||
1905 req_data->maximum_outstanding_transfer_requests <
1906 PLDM_FWUP_MIN_OUTSTANDING_REQ) {
1907 return -EINVAL;
1908 }
1909
1910 rc = encode_pldm_header_only_errno(
1911 PLDM_REQUEST, instance_id, PLDM_FWUP,
1912 PLDM_REQUEST_DOWNSTREAM_DEVICE_UPDATE, msg);
1913 if (rc) {
1914 return rc;
1915 }
1916
1917 rc = pldm_msgbuf_init_errno(buf,
1918 PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES,
1919 msg->payload, *payload_length);
1920 if (rc) {
1921 return rc;
1922 }
1923
1924 pldm_msgbuf_insert(buf,
1925 req_data->maximum_downstream_device_transfer_size);
1926 pldm_msgbuf_insert(buf,
1927 req_data->maximum_outstanding_transfer_requests);
1928 pldm_msgbuf_insert(buf,
1929 req_data->downstream_device_package_data_length);
1930
1931 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
1932}
1933
1934LIBPLDM_ABI_TESTING
1935int decode_request_downstream_device_update_req(
1936 const struct pldm_msg *msg, size_t payload_length,
1937 struct pldm_request_downstream_device_update_req *req)
1938{
1939 int rc;
John Chung7a8d9322025-08-27 20:56:19 -05001940 PLDM_MSGBUF_RO_DEFINE_P(buf);
Sora Su06eadd02025-05-27 11:28:51 +08001941
1942 if (!msg || !req) {
1943 return -EINVAL;
1944 }
1945
1946 rc = pldm_msgbuf_init_errno(buf,
1947 PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES,
1948 msg->payload, payload_length);
1949 if (rc) {
1950 return rc;
1951 }
1952
1953 pldm_msgbuf_extract(buf, req->maximum_downstream_device_transfer_size);
1954 pldm_msgbuf_extract(buf, req->maximum_outstanding_transfer_requests);
1955 pldm_msgbuf_extract(buf, req->downstream_device_package_data_length);
1956
1957 return pldm_msgbuf_complete_consumed(buf);
1958}
1959
1960LIBPLDM_ABI_TESTING
1961int encode_request_downstream_device_update_resp(
1962 uint8_t instance_id,
1963 const struct pldm_request_downstream_device_update_resp *resp_data,
1964 struct pldm_msg *msg, size_t *payload_length)
1965{
John Chung7a8d9322025-08-27 20:56:19 -05001966 PLDM_MSGBUF_RW_DEFINE_P(buf);
Sora Su06eadd02025-05-27 11:28:51 +08001967 int rc;
1968
1969 if (!resp_data || !msg || !payload_length) {
1970 return -EINVAL;
1971 }
1972
1973 rc = encode_pldm_header_only_errno(
1974 PLDM_RESPONSE, instance_id, PLDM_FWUP,
1975 PLDM_REQUEST_DOWNSTREAM_DEVICE_UPDATE, msg);
1976 if (rc) {
1977 return rc;
1978 }
1979
1980 rc = pldm_msgbuf_init_errno(
1981 buf, PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES, msg->payload,
1982 *payload_length);
1983 if (rc) {
1984 return rc;
1985 }
1986
1987 pldm_msgbuf_insert(buf, resp_data->completion_code);
1988 pldm_msgbuf_insert(buf, resp_data->downstream_device_meta_data_length);
1989 pldm_msgbuf_insert(
1990 buf, resp_data->downstream_device_will_send_get_package_data);
1991 pldm_msgbuf_insert(buf,
1992 resp_data->get_package_data_maximum_transfer_size);
1993
1994 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
1995}
1996
1997LIBPLDM_ABI_TESTING
1998int decode_request_downstream_device_update_resp(
1999 const struct pldm_msg *msg, size_t payload_length,
2000 struct pldm_request_downstream_device_update_resp *resp_data)
2001{
John Chung7a8d9322025-08-27 20:56:19 -05002002 PLDM_MSGBUF_RO_DEFINE_P(buf);
Sora Su06eadd02025-05-27 11:28:51 +08002003 int rc;
2004
2005 if (!msg || !resp_data) {
2006 return -EINVAL;
2007 }
2008
2009 rc = pldm_msg_has_error(msg,
2010 PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES);
2011 if (rc) {
2012 resp_data->completion_code = rc;
2013 return 0;
2014 }
2015
2016 rc = pldm_msgbuf_init_errno(
2017 buf, PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES, msg->payload,
2018 payload_length);
2019 if (rc) {
2020 return rc;
2021 }
2022
2023 pldm_msgbuf_extract(buf, resp_data->completion_code);
2024 pldm_msgbuf_extract(buf, resp_data->downstream_device_meta_data_length);
2025 pldm_msgbuf_extract(
2026 buf, resp_data->downstream_device_will_send_get_package_data);
2027 pldm_msgbuf_extract(buf,
2028 resp_data->get_package_data_maximum_transfer_size);
2029
2030 return pldm_msgbuf_complete_consumed(buf);
2031}
2032
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302033LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302034int encode_request_update_req(uint8_t instance_id, uint32_t max_transfer_size,
2035 uint16_t num_of_comp,
2036 uint8_t max_outstanding_transfer_req,
2037 uint16_t pkg_data_len,
2038 uint8_t comp_image_set_ver_str_type,
2039 uint8_t comp_image_set_ver_str_len,
2040 const struct variable_field *comp_img_set_ver_str,
2041 struct pldm_msg *msg, size_t payload_length)
2042{
2043 if (comp_img_set_ver_str == NULL || comp_img_set_ver_str->ptr == NULL ||
2044 msg == NULL) {
2045 return PLDM_ERROR_INVALID_DATA;
2046 }
2047
2048 if (payload_length != sizeof(struct pldm_request_update_req) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302049 comp_img_set_ver_str->length) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302050 return PLDM_ERROR_INVALID_LENGTH;
2051 }
2052
2053 if ((comp_image_set_ver_str_len == 0) ||
2054 (comp_image_set_ver_str_len != comp_img_set_ver_str->length)) {
2055 return PLDM_ERROR_INVALID_DATA;
2056 }
2057
2058 if ((max_transfer_size < PLDM_FWUP_BASELINE_TRANSFER_SIZE) ||
2059 (max_outstanding_transfer_req < PLDM_FWUP_MIN_OUTSTANDING_REQ)) {
2060 return PLDM_ERROR_INVALID_DATA;
2061 }
2062
2063 if (!is_string_type_valid(comp_image_set_ver_str_type)) {
2064 return PLDM_ERROR_INVALID_DATA;
2065 }
2066
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302067 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302068 header.instance = instance_id;
2069 header.msg_type = PLDM_REQUEST;
2070 header.pldm_type = PLDM_FWUP;
2071 header.command = PLDM_REQUEST_UPDATE;
2072 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2073 if (rc) {
2074 return rc;
2075 }
2076
2077 struct pldm_request_update_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302078 (struct pldm_request_update_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302079
2080 request->max_transfer_size = htole32(max_transfer_size);
2081 request->num_of_comp = htole16(num_of_comp);
2082 request->max_outstanding_transfer_req = max_outstanding_transfer_req;
2083 request->pkg_data_len = htole16(pkg_data_len);
2084 request->comp_image_set_ver_str_type = comp_image_set_ver_str_type;
2085 request->comp_image_set_ver_str_len = comp_image_set_ver_str_len;
2086
2087 memcpy(msg->payload + sizeof(struct pldm_request_update_req),
2088 comp_img_set_ver_str->ptr, comp_img_set_ver_str->length);
2089
2090 return PLDM_SUCCESS;
2091}
2092
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002093LIBPLDM_ABI_TESTING
2094int decode_request_update_req(const struct pldm_msg *msg, size_t payload_length,
2095 struct pldm_request_update_req_full *req)
2096{
2097 int rc;
2098 uint8_t t;
John Chung7a8d9322025-08-27 20:56:19 -05002099 PLDM_MSGBUF_RO_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002100
2101 if (msg == NULL || req == NULL) {
2102 return -EINVAL;
2103 }
2104
2105 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2106 if (rc) {
2107 return rc;
2108 }
2109
2110 pldm_msgbuf_extract(buf, req->max_transfer_size);
2111 pldm_msgbuf_extract(buf, req->num_of_comp);
2112 pldm_msgbuf_extract(buf, req->max_outstanding_transfer_req);
2113 pldm_msgbuf_extract(buf, req->pkg_data_len);
2114 rc = pldm_msgbuf_extract(buf, t);
2115 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302116 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002117 }
2118 if (t > PLDM_STR_TYPE_UTF_16BE) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302119 return pldm_msgbuf_discard(buf, -EBADMSG);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002120 }
2121 req->image_set_ver.str_type = (enum pldm_firmware_update_string_type)t;
2122 pldm_msgbuf_extract(buf, req->image_set_ver.str_len);
2123 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302124 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002125 }
2126
2127 rc = pldm_msgbuf_extract_array(buf, req->image_set_ver.str_len,
2128 req->image_set_ver.str_data,
2129 PLDM_FIRMWARE_MAX_STRING);
2130 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302131 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002132 }
2133
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302134 return pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002135}
2136
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302137LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302138int decode_request_update_resp(const struct pldm_msg *msg,
2139 size_t payload_length, uint8_t *completion_code,
2140 uint16_t *fd_meta_data_len,
2141 uint8_t *fd_will_send_pkg_data)
2142{
2143 if (msg == NULL || completion_code == NULL ||
2144 fd_meta_data_len == NULL || fd_will_send_pkg_data == NULL ||
2145 !payload_length) {
2146 return PLDM_ERROR_INVALID_DATA;
2147 }
2148
2149 *completion_code = msg->payload[0];
2150 if (*completion_code != PLDM_SUCCESS) {
2151 return PLDM_SUCCESS;
2152 }
2153
2154 if (payload_length != sizeof(struct pldm_request_update_resp)) {
2155 return PLDM_ERROR_INVALID_LENGTH;
2156 }
2157
2158 struct pldm_request_update_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302159 (struct pldm_request_update_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302160
2161 *fd_meta_data_len = le16toh(response->fd_meta_data_len);
2162 *fd_will_send_pkg_data = response->fd_will_send_pkg_data;
2163
2164 return PLDM_SUCCESS;
2165}
2166
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002167LIBPLDM_ABI_TESTING
2168int encode_request_update_resp(uint8_t instance_id,
2169 const struct pldm_request_update_resp *resp_data,
2170 struct pldm_msg *msg, size_t *payload_length)
2171{
John Chung7a8d9322025-08-27 20:56:19 -05002172 PLDM_MSGBUF_RW_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002173 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002174
2175 if (msg == NULL || payload_length == NULL) {
2176 return -EINVAL;
2177 }
2178
2179 struct pldm_header_info header = {
2180 .instance = instance_id,
2181 .msg_type = PLDM_RESPONSE,
2182 .pldm_type = PLDM_FWUP,
2183 .command = PLDM_REQUEST_UPDATE,
2184 };
2185 rc = pack_pldm_header(&header, &(msg->hdr));
2186 if (rc) {
2187 return -EINVAL;
2188 }
2189
2190 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2191 if (rc) {
2192 return rc;
2193 }
2194
2195 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2196 pldm_msgbuf_insert(buf, resp_data->fd_meta_data_len);
2197 pldm_msgbuf_insert(buf, resp_data->fd_will_send_pkg_data);
2198
2199 /* TODO: DSP0267 1.3.0 adds GetPackageDataMaximumTransferSize */
2200
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302201 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002202}
2203
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302204LIBPLDM_ABI_STABLE
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302205int encode_pass_component_table_req(uint8_t instance_id, uint8_t transfer_flag,
2206 uint16_t comp_classification,
2207 uint16_t comp_identifier,
2208 uint8_t comp_classification_index,
2209 uint32_t comp_comparison_stamp,
2210 uint8_t comp_ver_str_type,
2211 uint8_t comp_ver_str_len,
2212 const struct variable_field *comp_ver_str,
2213 struct pldm_msg *msg, size_t payload_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09302214{
2215 if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) {
2216 return PLDM_ERROR_INVALID_DATA;
2217 }
2218
2219 if (payload_length != sizeof(struct pldm_pass_component_table_req) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302220 comp_ver_str->length) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302221 return PLDM_ERROR_INVALID_LENGTH;
2222 }
2223
2224 if ((comp_ver_str_len == 0) ||
2225 (comp_ver_str_len != comp_ver_str->length)) {
2226 return PLDM_ERROR_INVALID_DATA;
2227 }
2228
2229 if (!is_transfer_flag_valid(transfer_flag)) {
Manojkiran Eda3643e742025-05-19 12:03:54 +05302230 return PLDM_FWUP_INVALID_TRANSFER_OPERATION_FLAG;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302231 }
2232
2233 if (!is_string_type_valid(comp_ver_str_type)) {
2234 return PLDM_ERROR_INVALID_DATA;
2235 }
2236
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302237 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302238 header.instance = instance_id;
2239 header.msg_type = PLDM_REQUEST;
2240 header.pldm_type = PLDM_FWUP;
2241 header.command = PLDM_PASS_COMPONENT_TABLE;
2242 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2243 if (rc) {
2244 return rc;
2245 }
2246
2247 struct pldm_pass_component_table_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302248 (struct pldm_pass_component_table_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302249
2250 request->transfer_flag = transfer_flag;
2251 request->comp_classification = htole16(comp_classification);
2252 request->comp_identifier = htole16(comp_identifier);
2253 request->comp_classification_index = comp_classification_index;
2254 request->comp_comparison_stamp = htole32(comp_comparison_stamp);
2255 request->comp_ver_str_type = comp_ver_str_type;
2256 request->comp_ver_str_len = comp_ver_str_len;
2257
2258 memcpy(msg->payload + sizeof(struct pldm_pass_component_table_req),
2259 comp_ver_str->ptr, comp_ver_str->length);
2260
2261 return PLDM_SUCCESS;
2262}
2263
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002264LIBPLDM_ABI_TESTING
2265int decode_pass_component_table_req(
2266 const struct pldm_msg *msg, size_t payload_length,
2267 struct pldm_pass_component_table_req_full *pcomp)
2268{
2269 int rc;
2270 uint8_t t;
John Chung7a8d9322025-08-27 20:56:19 -05002271 PLDM_MSGBUF_RO_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002272
2273 if (msg == NULL || pcomp == NULL) {
2274 return -EINVAL;
2275 }
2276
2277 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2278 if (rc) {
2279 return rc;
2280 }
2281
2282 pldm_msgbuf_extract(buf, pcomp->transfer_flag);
2283 pldm_msgbuf_extract(buf, pcomp->comp_classification);
2284 pldm_msgbuf_extract(buf, pcomp->comp_identifier);
2285 pldm_msgbuf_extract(buf, pcomp->comp_classification_index);
2286 pldm_msgbuf_extract(buf, pcomp->comp_comparison_stamp);
2287 rc = pldm_msgbuf_extract(buf, t);
2288 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302289 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002290 }
2291 if (t > PLDM_STR_TYPE_UTF_16BE) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302292 return pldm_msgbuf_discard(buf, -EBADMSG);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002293 }
2294 pcomp->version.str_type = (enum pldm_firmware_update_string_type)t;
2295 rc = pldm_msgbuf_extract(buf, pcomp->version.str_len);
2296 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302297 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002298 }
2299 rc = pldm_msgbuf_extract_array(buf, pcomp->version.str_len,
2300 pcomp->version.str_data,
2301 PLDM_FIRMWARE_MAX_STRING);
2302 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302303 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002304 }
2305
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302306 return pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002307}
2308
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302309LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302310int decode_pass_component_table_resp(const struct pldm_msg *msg,
2311 const size_t payload_length,
2312 uint8_t *completion_code,
2313 uint8_t *comp_resp,
2314 uint8_t *comp_resp_code)
2315{
2316 if (msg == NULL || completion_code == NULL || comp_resp == NULL ||
2317 comp_resp_code == NULL || !payload_length) {
2318 return PLDM_ERROR_INVALID_DATA;
2319 }
2320
2321 *completion_code = msg->payload[0];
2322 if (*completion_code != PLDM_SUCCESS) {
2323 return PLDM_SUCCESS;
2324 }
2325
2326 if (payload_length != sizeof(struct pldm_pass_component_table_resp)) {
2327 return PLDM_ERROR_INVALID_LENGTH;
2328 }
2329
2330 struct pldm_pass_component_table_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302331 (struct pldm_pass_component_table_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302332
2333 if (!is_comp_resp_valid(response->comp_resp)) {
2334 return PLDM_ERROR_INVALID_DATA;
2335 }
2336
2337 if (!is_comp_resp_code_valid(response->comp_resp_code)) {
2338 return PLDM_ERROR_INVALID_DATA;
2339 }
2340
2341 *comp_resp = response->comp_resp;
2342 *comp_resp_code = response->comp_resp_code;
2343
2344 return PLDM_SUCCESS;
2345}
2346
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002347LIBPLDM_ABI_TESTING
2348int encode_pass_component_table_resp(
2349 uint8_t instance_id,
2350 const struct pldm_pass_component_table_resp *resp_data,
2351 struct pldm_msg *msg, size_t *payload_length)
2352{
John Chung7a8d9322025-08-27 20:56:19 -05002353 PLDM_MSGBUF_RW_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002354 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002355
2356 if (msg == NULL || payload_length == NULL) {
2357 return -EINVAL;
2358 }
2359
2360 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2361 PLDM_PASS_COMPONENT_TABLE, msg);
2362 if (rc) {
2363 return -EINVAL;
2364 }
2365
2366 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2367 if (rc) {
2368 return rc;
2369 }
2370
2371 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2372 pldm_msgbuf_insert(buf, resp_data->comp_resp);
2373 pldm_msgbuf_insert(buf, resp_data->comp_resp_code);
2374
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302375 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002376}
2377
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302378LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302379int encode_update_component_req(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302380 uint8_t instance_id, uint16_t comp_classification,
2381 uint16_t comp_identifier, uint8_t comp_classification_index,
2382 uint32_t comp_comparison_stamp, uint32_t comp_image_size,
2383 bitfield32_t update_option_flags, uint8_t comp_ver_str_type,
2384 uint8_t comp_ver_str_len, const struct variable_field *comp_ver_str,
2385 struct pldm_msg *msg, size_t payload_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09302386{
2387 if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) {
2388 return PLDM_ERROR_INVALID_DATA;
2389 }
2390
2391 if (payload_length !=
2392 sizeof(struct pldm_update_component_req) + comp_ver_str->length) {
2393 return PLDM_ERROR_INVALID_LENGTH;
2394 }
2395
2396 if (!comp_image_size) {
2397 return PLDM_ERROR_INVALID_DATA;
2398 }
2399
2400 if ((comp_ver_str_len == 0) ||
2401 (comp_ver_str_len != comp_ver_str->length)) {
2402 return PLDM_ERROR_INVALID_DATA;
2403 }
2404
2405 if (!is_string_type_valid(comp_ver_str_type)) {
2406 return PLDM_ERROR_INVALID_DATA;
2407 }
2408
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302409 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302410 header.instance = instance_id;
2411 header.msg_type = PLDM_REQUEST;
2412 header.pldm_type = PLDM_FWUP;
2413 header.command = PLDM_UPDATE_COMPONENT;
2414 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2415 if (rc) {
2416 return rc;
2417 }
2418
2419 struct pldm_update_component_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302420 (struct pldm_update_component_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302421
2422 request->comp_classification = htole16(comp_classification);
2423 request->comp_identifier = htole16(comp_identifier);
2424 request->comp_classification_index = comp_classification_index;
2425 request->comp_comparison_stamp = htole32(comp_comparison_stamp);
2426 request->comp_image_size = htole32(comp_image_size);
2427 request->update_option_flags.value = htole32(update_option_flags.value);
2428 request->comp_ver_str_type = comp_ver_str_type;
2429 request->comp_ver_str_len = comp_ver_str_len;
2430
2431 memcpy(msg->payload + sizeof(struct pldm_update_component_req),
2432 comp_ver_str->ptr, comp_ver_str->length);
2433
2434 return PLDM_SUCCESS;
2435}
2436
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002437LIBPLDM_ABI_TESTING
2438int decode_update_component_req(const struct pldm_msg *msg,
2439 size_t payload_length,
2440 struct pldm_update_component_req_full *up)
2441{
2442 int rc;
2443 uint8_t t;
John Chung7a8d9322025-08-27 20:56:19 -05002444 PLDM_MSGBUF_RO_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002445
2446 if (msg == NULL || up == NULL) {
2447 return -EINVAL;
2448 }
2449
2450 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2451 if (rc) {
2452 return rc;
2453 }
2454
2455 pldm_msgbuf_extract(buf, up->comp_classification);
2456 pldm_msgbuf_extract(buf, up->comp_identifier);
2457 pldm_msgbuf_extract(buf, up->comp_classification_index);
2458 pldm_msgbuf_extract(buf, up->comp_comparison_stamp);
2459 pldm_msgbuf_extract(buf, up->comp_image_size);
2460 pldm_msgbuf_extract(buf, up->update_option_flags.value);
2461 rc = pldm_msgbuf_extract(buf, t);
2462 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302463 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002464 }
2465 if (t > PLDM_STR_TYPE_UTF_16BE) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302466 return pldm_msgbuf_discard(buf, -EBADMSG);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002467 }
2468 up->version.str_type = (enum pldm_firmware_update_string_type)t;
2469 rc = pldm_msgbuf_extract(buf, up->version.str_len);
2470 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302471 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002472 }
2473 rc = pldm_msgbuf_extract_array(buf, up->version.str_len,
2474 up->version.str_data,
2475 PLDM_FIRMWARE_MAX_STRING);
2476 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302477 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002478 }
2479
Andrew Jefferya1896962025-03-03 21:41:25 +10302480 return pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002481}
2482
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302483LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302484int decode_update_component_resp(const struct pldm_msg *msg,
2485 size_t payload_length,
2486 uint8_t *completion_code,
2487 uint8_t *comp_compatibility_resp,
2488 uint8_t *comp_compatibility_resp_code,
2489 bitfield32_t *update_option_flags_enabled,
2490 uint16_t *time_before_req_fw_data)
2491{
2492 if (msg == NULL || completion_code == NULL ||
2493 comp_compatibility_resp == NULL ||
2494 comp_compatibility_resp_code == NULL ||
2495 update_option_flags_enabled == NULL ||
2496 time_before_req_fw_data == NULL || !payload_length) {
2497 return PLDM_ERROR_INVALID_DATA;
2498 }
2499
2500 *completion_code = msg->payload[0];
2501 if (*completion_code != PLDM_SUCCESS) {
2502 return PLDM_SUCCESS;
2503 }
2504
2505 if (payload_length != sizeof(struct pldm_update_component_resp)) {
2506 return PLDM_ERROR_INVALID_LENGTH;
2507 }
2508
2509 struct pldm_update_component_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302510 (struct pldm_update_component_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302511
2512 if (!is_comp_compatibility_resp_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302513 response->comp_compatibility_resp)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302514 return PLDM_ERROR_INVALID_DATA;
2515 }
2516
2517 if (!is_comp_compatibility_resp_code_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302518 response->comp_compatibility_resp_code)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302519 return PLDM_ERROR_INVALID_DATA;
2520 }
2521
2522 *comp_compatibility_resp = response->comp_compatibility_resp;
2523 *comp_compatibility_resp_code = response->comp_compatibility_resp_code;
2524 update_option_flags_enabled->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302525 le32toh(response->update_option_flags_enabled.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302526 *time_before_req_fw_data = le16toh(response->time_before_req_fw_data);
2527
2528 return PLDM_SUCCESS;
2529}
2530
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002531LIBPLDM_ABI_TESTING
2532int encode_update_component_resp(
2533 uint8_t instance_id, const struct pldm_update_component_resp *resp_data,
2534 struct pldm_msg *msg, size_t *payload_length)
2535{
John Chung7a8d9322025-08-27 20:56:19 -05002536 PLDM_MSGBUF_RW_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002537 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002538
2539 if (msg == NULL || payload_length == NULL) {
2540 return -EINVAL;
2541 }
2542
2543 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2544 PLDM_UPDATE_COMPONENT, msg);
2545 if (rc) {
2546 return -EINVAL;
2547 }
2548
2549 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2550 if (rc) {
2551 return rc;
2552 }
2553
2554 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2555 pldm_msgbuf_insert(buf, resp_data->comp_compatibility_resp);
2556 pldm_msgbuf_insert(buf, resp_data->comp_compatibility_resp_code);
2557 pldm_msgbuf_insert(buf, resp_data->update_option_flags_enabled.value);
2558 pldm_msgbuf_insert(buf, resp_data->time_before_req_fw_data);
2559
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302560 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002561}
2562
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302563LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302564int decode_request_firmware_data_req(const struct pldm_msg *msg,
2565 size_t payload_length, uint32_t *offset,
2566 uint32_t *length)
2567{
2568 if (msg == NULL || offset == NULL || length == NULL) {
2569 return PLDM_ERROR_INVALID_DATA;
2570 }
2571 if (payload_length != sizeof(struct pldm_request_firmware_data_req)) {
2572 return PLDM_ERROR_INVALID_LENGTH;
2573 }
2574 struct pldm_request_firmware_data_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302575 (struct pldm_request_firmware_data_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302576 *offset = le32toh(request->offset);
2577 *length = le32toh(request->length);
2578
2579 if (*length < PLDM_FWUP_BASELINE_TRANSFER_SIZE) {
2580 return PLDM_FWUP_INVALID_TRANSFER_LENGTH;
2581 }
2582
2583 return PLDM_SUCCESS;
2584}
2585
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002586LIBPLDM_ABI_TESTING
2587int encode_request_firmware_data_req(
2588 uint8_t instance_id,
2589 const struct pldm_request_firmware_data_req *req_params,
2590 struct pldm_msg *msg, size_t *payload_length)
2591{
John Chung7a8d9322025-08-27 20:56:19 -05002592 PLDM_MSGBUF_RW_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002593 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002594
2595 if (msg == NULL || payload_length == NULL) {
2596 return -EINVAL;
2597 }
2598
2599 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2600 PLDM_REQUEST_FIRMWARE_DATA, msg);
2601 if (rc) {
2602 return -EINVAL;
2603 }
2604
2605 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2606 if (rc) {
2607 return rc;
2608 }
2609
2610 pldm_msgbuf_insert(buf, req_params->offset);
2611 pldm_msgbuf_insert(buf, req_params->length);
2612
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302613 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002614}
2615
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302616LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302617int encode_request_firmware_data_resp(uint8_t instance_id,
2618 uint8_t completion_code,
2619 struct pldm_msg *msg,
2620 size_t payload_length)
2621{
2622 if (msg == NULL || !payload_length) {
2623 return PLDM_ERROR_INVALID_DATA;
2624 }
2625
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302626 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302627 header.instance = instance_id;
2628 header.msg_type = PLDM_RESPONSE;
2629 header.pldm_type = PLDM_FWUP;
2630 header.command = PLDM_REQUEST_FIRMWARE_DATA;
2631 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2632 if (rc) {
2633 return rc;
2634 }
2635
2636 msg->payload[0] = completion_code;
2637
2638 return PLDM_SUCCESS;
2639}
2640
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302641LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302642int decode_transfer_complete_req(const struct pldm_msg *msg,
2643 size_t payload_length,
2644 uint8_t *transfer_result)
2645{
2646 if (msg == NULL || transfer_result == NULL) {
2647 return PLDM_ERROR_INVALID_DATA;
2648 }
2649
2650 if (payload_length != sizeof(*transfer_result)) {
2651 return PLDM_ERROR_INVALID_LENGTH;
2652 }
2653
2654 *transfer_result = msg->payload[0];
2655 return PLDM_SUCCESS;
2656}
2657
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002658LIBPLDM_ABI_TESTING
2659int encode_transfer_complete_req(uint8_t instance_id, uint8_t transfer_result,
2660 struct pldm_msg *msg, size_t *payload_length)
2661{
John Chung7a8d9322025-08-27 20:56:19 -05002662 PLDM_MSGBUF_RW_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002663 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002664
2665 if (msg == NULL || payload_length == NULL) {
2666 return -EINVAL;
2667 }
2668
2669 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2670 PLDM_TRANSFER_COMPLETE, msg);
2671 if (rc) {
2672 return -EINVAL;
2673 }
2674
2675 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2676 if (rc) {
2677 return rc;
2678 }
2679
Andrew Jefferya1896962025-03-03 21:41:25 +10302680 pldm_msgbuf_insert(buf, transfer_result);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002681
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302682 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002683}
2684
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302685LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302686int encode_transfer_complete_resp(uint8_t instance_id, uint8_t completion_code,
2687 struct pldm_msg *msg, size_t payload_length)
2688{
2689 if (msg == NULL) {
2690 return PLDM_ERROR_INVALID_DATA;
2691 }
2692
2693 if (payload_length != sizeof(completion_code)) {
2694 return PLDM_ERROR_INVALID_LENGTH;
2695 }
2696
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302697 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302698 header.instance = instance_id;
2699 header.msg_type = PLDM_RESPONSE;
2700 header.pldm_type = PLDM_FWUP;
2701 header.command = PLDM_TRANSFER_COMPLETE;
2702 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2703 if (rc) {
2704 return rc;
2705 }
2706
2707 msg->payload[0] = completion_code;
2708
2709 return PLDM_SUCCESS;
2710}
2711
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302712LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302713int decode_verify_complete_req(const struct pldm_msg *msg,
2714 size_t payload_length, uint8_t *verify_result)
2715{
2716 if (msg == NULL || verify_result == NULL) {
2717 return PLDM_ERROR_INVALID_DATA;
2718 }
2719
2720 if (payload_length != sizeof(*verify_result)) {
2721 return PLDM_ERROR_INVALID_LENGTH;
2722 }
2723
2724 *verify_result = msg->payload[0];
2725 return PLDM_SUCCESS;
2726}
2727
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002728LIBPLDM_ABI_TESTING
2729int encode_verify_complete_req(uint8_t instance_id, uint8_t verify_result,
2730 struct pldm_msg *msg, size_t *payload_length)
2731{
John Chung7a8d9322025-08-27 20:56:19 -05002732 PLDM_MSGBUF_RW_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002733 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002734
2735 if (msg == NULL || payload_length == NULL) {
2736 return -EINVAL;
2737 }
2738
2739 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2740 PLDM_VERIFY_COMPLETE, msg);
2741 if (rc) {
2742 return EINVAL;
2743 }
2744
2745 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2746 if (rc) {
2747 return rc;
2748 }
2749
Andrew Jefferya1896962025-03-03 21:41:25 +10302750 pldm_msgbuf_insert(buf, verify_result);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002751
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_verify_complete_resp(uint8_t instance_id, uint8_t completion_code,
2757 struct pldm_msg *msg, size_t payload_length)
2758{
2759 if (msg == NULL) {
2760 return PLDM_ERROR_INVALID_DATA;
2761 }
2762
2763 if (payload_length != sizeof(completion_code)) {
2764 return PLDM_ERROR_INVALID_LENGTH;
2765 }
2766
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_VERIFY_COMPLETE;
2772 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2773 if (rc) {
2774 return rc;
2775 }
2776
2777 msg->payload[0] = completion_code;
2778
2779 return PLDM_SUCCESS;
2780}
2781
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302782LIBPLDM_ABI_STABLE
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302783int decode_apply_complete_req(const struct pldm_msg *msg, size_t payload_length,
2784 uint8_t *apply_result,
2785 bitfield16_t *comp_activation_methods_modification)
Andrew Jeffery9c766792022-08-10 23:12:49 +09302786{
2787 if (msg == NULL || apply_result == NULL ||
2788 comp_activation_methods_modification == NULL) {
2789 return PLDM_ERROR_INVALID_DATA;
2790 }
2791
2792 if (payload_length != sizeof(struct pldm_apply_complete_req)) {
2793 return PLDM_ERROR_INVALID_LENGTH;
2794 }
2795
2796 struct pldm_apply_complete_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302797 (struct pldm_apply_complete_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302798
2799 *apply_result = request->apply_result;
2800 comp_activation_methods_modification->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302801 le16toh(request->comp_activation_methods_modification.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302802
2803 if ((*apply_result != PLDM_FWUP_APPLY_SUCCESS_WITH_ACTIVATION_METHOD) &&
2804 comp_activation_methods_modification->value) {
2805 return PLDM_ERROR_INVALID_DATA;
2806 }
2807
2808 return PLDM_SUCCESS;
2809}
2810
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002811LIBPLDM_ABI_TESTING
2812int encode_apply_complete_req(uint8_t instance_id,
2813 const struct pldm_apply_complete_req *req_data,
2814 struct pldm_msg *msg, size_t *payload_length)
2815{
John Chung7a8d9322025-08-27 20:56:19 -05002816 PLDM_MSGBUF_RW_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002817 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002818
2819 if (msg == NULL || payload_length == NULL) {
2820 return -EINVAL;
2821 }
2822
2823 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2824 PLDM_APPLY_COMPLETE, msg);
2825 if (rc) {
2826 return -EINVAL;
2827 }
2828
2829 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2830 if (rc) {
2831 return rc;
2832 }
2833
2834 pldm_msgbuf_insert(buf, req_data->apply_result);
2835 pldm_msgbuf_insert(
2836 buf, req_data->comp_activation_methods_modification.value);
2837
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302838 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002839}
2840
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302841LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302842int encode_apply_complete_resp(uint8_t instance_id, uint8_t completion_code,
2843 struct pldm_msg *msg, size_t payload_length)
2844{
2845 if (msg == NULL) {
2846 return PLDM_ERROR_INVALID_DATA;
2847 }
2848
2849 if (payload_length != sizeof(completion_code)) {
2850 return PLDM_ERROR_INVALID_LENGTH;
2851 }
2852
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302853 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302854 header.instance = instance_id;
2855 header.msg_type = PLDM_RESPONSE;
2856 header.pldm_type = PLDM_FWUP;
2857 header.command = PLDM_APPLY_COMPLETE;
2858 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2859 if (rc) {
2860 return rc;
2861 }
2862
2863 msg->payload[0] = completion_code;
2864
2865 return PLDM_SUCCESS;
2866}
2867
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002868LIBPLDM_ABI_TESTING
2869int decode_activate_firmware_req(const struct pldm_msg *msg,
2870 size_t payload_length, bool *self_contained)
2871{
Andrew Jefferya1896962025-03-03 21:41:25 +10302872 uint8_t self_contained_u8 = 0;
John Chung7a8d9322025-08-27 20:56:19 -05002873 PLDM_MSGBUF_RO_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002874 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002875
2876 if (msg == NULL || self_contained == NULL) {
2877 return -EINVAL;
2878 }
2879
2880 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2881 if (rc) {
2882 return 0;
2883 }
2884
Andrew Jefferya1896962025-03-03 21:41:25 +10302885 pldm_msgbuf_extract(buf, self_contained_u8);
2886
2887 rc = pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002888 if (rc) {
2889 return rc;
2890 }
Andrew Jefferya1896962025-03-03 21:41:25 +10302891
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002892 *self_contained = (bool)self_contained_u8;
2893 return 0;
2894}
2895
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302896LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302897int encode_activate_firmware_req(uint8_t instance_id,
2898 bool8_t self_contained_activation_req,
2899 struct pldm_msg *msg, size_t payload_length)
2900{
2901 if (msg == NULL) {
2902 return PLDM_ERROR_INVALID_DATA;
2903 }
2904
2905 if (payload_length != sizeof(struct pldm_activate_firmware_req)) {
2906 return PLDM_ERROR_INVALID_LENGTH;
2907 }
2908
2909 if (!is_self_contained_activation_req_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302910 self_contained_activation_req)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302911 return PLDM_ERROR_INVALID_DATA;
2912 }
2913
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302914 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302915 header.instance = instance_id;
2916 header.msg_type = PLDM_REQUEST;
2917 header.pldm_type = PLDM_FWUP;
2918 header.command = PLDM_ACTIVATE_FIRMWARE;
2919 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2920 if (rc) {
2921 return rc;
2922 }
2923
2924 struct pldm_activate_firmware_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302925 (struct pldm_activate_firmware_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302926
2927 request->self_contained_activation_req = self_contained_activation_req;
2928
2929 return PLDM_SUCCESS;
2930}
2931
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302932LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302933int decode_activate_firmware_resp(const struct pldm_msg *msg,
2934 size_t payload_length,
2935 uint8_t *completion_code,
2936 uint16_t *estimated_time_activation)
2937{
2938 if (msg == NULL || completion_code == NULL ||
2939 estimated_time_activation == NULL || !payload_length) {
2940 return PLDM_ERROR_INVALID_DATA;
2941 }
2942
2943 *completion_code = msg->payload[0];
2944 if (*completion_code != PLDM_SUCCESS) {
2945 return PLDM_SUCCESS;
2946 }
2947
2948 if (payload_length != sizeof(struct pldm_activate_firmware_resp)) {
2949 return PLDM_ERROR_INVALID_LENGTH;
2950 }
2951
2952 struct pldm_activate_firmware_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302953 (struct pldm_activate_firmware_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302954
2955 *estimated_time_activation =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302956 le16toh(response->estimated_time_activation);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302957
2958 return PLDM_SUCCESS;
2959}
2960
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002961LIBPLDM_ABI_TESTING
2962int encode_activate_firmware_resp(
2963 uint8_t instance_id,
2964 const struct pldm_activate_firmware_resp *resp_data,
2965 struct pldm_msg *msg, size_t *payload_length)
2966{
John Chung7a8d9322025-08-27 20:56:19 -05002967 PLDM_MSGBUF_RW_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002968 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002969
2970 if (msg == NULL || payload_length == NULL) {
2971 return -EINVAL;
2972 }
2973
2974 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2975 PLDM_ACTIVATE_FIRMWARE, msg);
2976 if (rc) {
2977 return -EINVAL;
2978 }
2979
2980 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2981 if (rc) {
2982 return rc;
2983 }
2984
2985 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2986 pldm_msgbuf_insert(buf, resp_data->estimated_time_activation);
2987
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302988 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002989}
2990
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302991LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302992int encode_get_status_req(uint8_t instance_id, struct pldm_msg *msg,
2993 size_t payload_length)
2994{
2995 if (msg == NULL) {
2996 return PLDM_ERROR_INVALID_DATA;
2997 }
2998
2999 if (payload_length != PLDM_GET_STATUS_REQ_BYTES) {
3000 return PLDM_ERROR_INVALID_LENGTH;
3001 }
3002
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303003 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09303004 header.instance = instance_id;
3005 header.msg_type = PLDM_REQUEST;
3006 header.pldm_type = PLDM_FWUP;
3007 header.command = PLDM_GET_STATUS;
3008 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
3009 if (rc) {
3010 return rc;
3011 }
3012
3013 return PLDM_SUCCESS;
3014}
3015
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09303016LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09303017int decode_get_status_resp(const struct pldm_msg *msg, size_t payload_length,
3018 uint8_t *completion_code, uint8_t *current_state,
3019 uint8_t *previous_state, uint8_t *aux_state,
3020 uint8_t *aux_state_status, uint8_t *progress_percent,
3021 uint8_t *reason_code,
3022 bitfield32_t *update_option_flags_enabled)
3023{
3024 if (msg == NULL || completion_code == NULL || current_state == NULL ||
3025 previous_state == NULL || aux_state == NULL ||
3026 aux_state_status == NULL || progress_percent == NULL ||
3027 reason_code == NULL || update_option_flags_enabled == NULL ||
3028 !payload_length) {
3029 return PLDM_ERROR_INVALID_DATA;
3030 }
3031
3032 *completion_code = msg->payload[0];
3033 if (*completion_code != PLDM_SUCCESS) {
3034 return PLDM_SUCCESS;
3035 }
3036
3037 if (payload_length != sizeof(struct pldm_get_status_resp)) {
3038 return PLDM_ERROR_INVALID_LENGTH;
3039 }
3040 struct pldm_get_status_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303041 (struct pldm_get_status_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09303042
3043 if (!is_state_valid(response->current_state)) {
3044 return PLDM_ERROR_INVALID_DATA;
3045 }
3046 if (!is_state_valid(response->previous_state)) {
3047 return PLDM_ERROR_INVALID_DATA;
3048 }
3049 if (!is_aux_state_valid(response->aux_state)) {
3050 return PLDM_ERROR_INVALID_DATA;
3051 }
3052 if (!is_aux_state_status_valid(response->aux_state_status)) {
3053 return PLDM_ERROR_INVALID_DATA;
3054 }
3055 if (response->progress_percent > PLDM_FWUP_MAX_PROGRESS_PERCENT) {
3056 return PLDM_ERROR_INVALID_DATA;
3057 }
3058 if (!is_reason_code_valid(response->reason_code)) {
3059 return PLDM_ERROR_INVALID_DATA;
3060 }
3061
3062 if ((response->current_state == PLDM_FD_STATE_IDLE) ||
3063 (response->current_state == PLDM_FD_STATE_LEARN_COMPONENTS) ||
3064 (response->current_state == PLDM_FD_STATE_READY_XFER)) {
3065 if (response->aux_state !=
3066 PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER) {
3067 return PLDM_ERROR_INVALID_DATA;
3068 }
3069 }
3070
3071 *current_state = response->current_state;
3072 *previous_state = response->previous_state;
3073 *aux_state = response->aux_state;
3074 *aux_state_status = response->aux_state_status;
3075 *progress_percent = response->progress_percent;
3076 *reason_code = response->reason_code;
3077 update_option_flags_enabled->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303078 le32toh(response->update_option_flags_enabled.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09303079
3080 return PLDM_SUCCESS;
3081}
3082
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003083LIBPLDM_ABI_TESTING
3084int encode_get_status_resp(uint8_t instance_id,
3085 const struct pldm_get_status_resp *status,
3086 struct pldm_msg *msg, size_t *payload_length)
3087{
John Chung7a8d9322025-08-27 20:56:19 -05003088 PLDM_MSGBUF_RW_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003089 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003090
3091 if (status == NULL || msg == NULL || payload_length == NULL) {
3092 return -EINVAL;
3093 }
3094
3095 if (status->completion_code != PLDM_SUCCESS) {
3096 return -EINVAL;
3097 }
3098
3099 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
3100 PLDM_GET_STATUS, msg);
3101 if (rc) {
3102 return -EINVAL;
3103 }
3104
3105 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
3106 if (rc) {
3107 return rc;
3108 }
3109
3110 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
3111 pldm_msgbuf_insert(buf, status->current_state);
3112 pldm_msgbuf_insert(buf, status->previous_state);
3113 pldm_msgbuf_insert(buf, status->aux_state);
3114 pldm_msgbuf_insert(buf, status->aux_state_status);
3115 pldm_msgbuf_insert(buf, status->progress_percent);
3116 pldm_msgbuf_insert(buf, status->reason_code);
3117 pldm_msgbuf_insert(buf, status->update_option_flags_enabled.value);
3118
Andrew Jeffery70d21c92025-03-05 12:59:42 +10303119 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003120}
3121
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09303122LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09303123int encode_cancel_update_component_req(uint8_t instance_id,
3124 struct pldm_msg *msg,
3125 size_t payload_length)
3126{
3127 if (msg == NULL) {
3128 return PLDM_ERROR_INVALID_DATA;
3129 }
3130
3131 if (payload_length != PLDM_CANCEL_UPDATE_COMPONENT_REQ_BYTES) {
3132 return PLDM_ERROR_INVALID_LENGTH;
3133 }
3134
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303135 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09303136 header.instance = instance_id;
3137 header.msg_type = PLDM_REQUEST;
3138 header.pldm_type = PLDM_FWUP;
3139 header.command = PLDM_CANCEL_UPDATE_COMPONENT;
3140 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
3141 if (rc) {
3142 return rc;
3143 }
3144
3145 return PLDM_SUCCESS;
3146}
3147
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09303148LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09303149int decode_cancel_update_component_resp(const struct pldm_msg *msg,
3150 size_t payload_length,
3151 uint8_t *completion_code)
3152{
3153 if (msg == NULL || completion_code == NULL) {
3154 return PLDM_ERROR_INVALID_DATA;
3155 }
3156
3157 if (payload_length != sizeof(*completion_code)) {
3158 return PLDM_ERROR_INVALID_LENGTH;
3159 }
3160
3161 *completion_code = msg->payload[0];
3162 return PLDM_SUCCESS;
3163}
3164
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09303165LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09303166int encode_cancel_update_req(uint8_t instance_id, struct pldm_msg *msg,
3167 size_t payload_length)
3168{
3169 if (msg == NULL) {
3170 return PLDM_ERROR_INVALID_DATA;
3171 }
3172
3173 if (payload_length != PLDM_CANCEL_UPDATE_REQ_BYTES) {
3174 return PLDM_ERROR_INVALID_LENGTH;
3175 }
3176
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303177 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09303178 header.instance = instance_id;
3179 header.msg_type = PLDM_REQUEST;
3180 header.pldm_type = PLDM_FWUP;
3181 header.command = PLDM_CANCEL_UPDATE;
3182 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
3183 if (rc) {
3184 return rc;
3185 }
3186
3187 return PLDM_SUCCESS;
3188}
3189
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09303190LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09303191int decode_cancel_update_resp(const struct pldm_msg *msg, size_t payload_length,
3192 uint8_t *completion_code,
3193 bool8_t *non_functioning_component_indication,
3194 bitfield64_t *non_functioning_component_bitmap)
3195{
3196 if (msg == NULL || completion_code == NULL ||
3197 non_functioning_component_indication == NULL ||
3198 non_functioning_component_bitmap == NULL || !payload_length) {
3199 return PLDM_ERROR_INVALID_DATA;
3200 }
3201
3202 *completion_code = msg->payload[0];
3203 if (*completion_code != PLDM_SUCCESS) {
3204 return PLDM_SUCCESS;
3205 }
3206
3207 if (payload_length != sizeof(struct pldm_cancel_update_resp)) {
3208 return PLDM_ERROR_INVALID_LENGTH;
3209 }
3210 struct pldm_cancel_update_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303211 (struct pldm_cancel_update_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09303212
3213 if (!is_non_functioning_component_indication_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303214 response->non_functioning_component_indication)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09303215 return PLDM_ERROR_INVALID_DATA;
3216 }
3217
3218 *non_functioning_component_indication =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303219 response->non_functioning_component_indication;
Andrew Jeffery9c766792022-08-10 23:12:49 +09303220
3221 if (*non_functioning_component_indication) {
3222 non_functioning_component_bitmap->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303223 le64toh(response->non_functioning_component_bitmap);
Andrew Jeffery9c766792022-08-10 23:12:49 +09303224 }
3225
3226 return PLDM_SUCCESS;
3227}
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003228
3229LIBPLDM_ABI_TESTING
3230int encode_cancel_update_resp(uint8_t instance_id,
3231 const struct pldm_cancel_update_resp *resp_data,
3232 struct pldm_msg *msg, size_t *payload_length)
3233{
John Chung7a8d9322025-08-27 20:56:19 -05003234 PLDM_MSGBUF_RW_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003235 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003236
3237 if (msg == NULL || payload_length == NULL) {
3238 return -EINVAL;
3239 }
3240
3241 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
3242 PLDM_CANCEL_UPDATE, msg);
3243 if (rc) {
3244 return -EINVAL;
3245 }
3246
3247 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
3248 if (rc) {
3249 return rc;
3250 }
3251
3252 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
3253 pldm_msgbuf_insert(buf,
3254 resp_data->non_functioning_component_indication);
3255 pldm_msgbuf_insert(buf, resp_data->non_functioning_component_bitmap);
3256
Andrew Jeffery70d21c92025-03-05 12:59:42 +10303257 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003258}
Andrew Jeffery2613c272025-03-12 14:15:41 +10303259
Unive Tienf6ef78f2025-06-12 09:39:38 +08003260LIBPLDM_ABI_STABLE
Andrew Jeffery2613c272025-03-12 14:15:41 +10303261int decode_pldm_firmware_update_package(
3262 const void *data, size_t length,
3263 const struct pldm_package_format_pin *pin,
Andrew Jeffery72442de2025-08-12 08:47:42 +00003264 pldm_package_header_information_pad *hdr, struct pldm_package *pkg,
3265 uint32_t flags)
Andrew Jeffery2613c272025-03-12 14:15:41 +10303266{
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003267 if (!data || !pin || !hdr || !pkg) {
Andrew Jeffery2613c272025-03-12 14:15:41 +10303268 return -EINVAL;
3269 }
3270
Andrew Jeffery72442de2025-08-12 08:47:42 +00003271 if (flags) {
3272 return -EINVAL;
3273 }
3274
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003275 return decode_pldm_package_header_info_errno(data, length, pin, hdr,
3276 pkg);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303277}
3278
Unive Tienf6ef78f2025-06-12 09:39:38 +08003279LIBPLDM_ABI_STABLE
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003280int pldm_package_firmware_device_id_record_iter_init(struct pldm_package *pkg)
Andrew Jeffery2613c272025-03-12 14:15:41 +10303281{
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003282 struct pldm_package_iter *iter;
John Chung7a8d9322025-08-27 20:56:19 -05003283 PLDM_MSGBUF_RO_DEFINE_P(buf);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303284 int rc;
3285
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003286 if (!pkg || !pkg->pin || !pkg->hdr) {
Andrew Jeffery2613c272025-03-12 14:15:41 +10303287 return -EINVAL;
3288 }
3289
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003290 assert(pkg->pin->format.revision >=
3291 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
3292 assert(pkg->pin->format.revision <=
3293 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H);
3294 assert(pkg->hdr->package_header_format_revision >=
3295 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
3296 assert(pkg->hdr->package_header_format_revision <=
3297 pkg->pin->format.revision);
3298
3299 if (pkg->state != PLDM_PACKAGE_PARSE_HEADER) {
3300 return -EPROTO;
3301 }
3302
3303 if (!pkg->areas.ptr) {
3304 return -EINVAL;
3305 }
3306
3307 pkg->state = PLDM_PACKAGE_PARSE_FIRMWARE_DEVICES;
3308
3309 iter = &pkg->iter;
3310 iter->field = pkg->areas;
Andrew Jeffery2613c272025-03-12 14:15:41 +10303311
3312 /* Extract the fd record id count */
3313 rc = pldm_msgbuf_init_errno(buf, 1, iter->field.ptr,
3314 iter->field.length);
3315 if (rc) {
3316 return rc;
3317 }
3318
3319 pldm_msgbuf_extract_uint8_to_size(buf, iter->entries);
John Chung7a8d9322025-08-27 20:56:19 -05003320 pldm_msgbuf_span_remaining(buf, (const void **)&iter->field.ptr,
Andrew Jeffery2613c272025-03-12 14:15:41 +10303321 &iter->field.length);
3322
3323 return pldm_msgbuf_complete(buf);
3324}
3325
Unive Tienf6ef78f2025-06-12 09:39:38 +08003326LIBPLDM_ABI_STABLE
Andrew Jeffery2613c272025-03-12 14:15:41 +10303327int decode_pldm_package_firmware_device_id_record_from_iter(
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003328 struct pldm_package *pkg LIBPLDM_CC_UNUSED,
Andrew Jeffery2613c272025-03-12 14:15:41 +10303329 struct pldm_package_firmware_device_id_record *rec)
3330{
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003331 if (!pkg) {
Andrew Jeffery2613c272025-03-12 14:15:41 +10303332 return -EINVAL;
3333 }
3334
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003335 if (pkg->state != PLDM_PACKAGE_PARSE_FIRMWARE_DEVICES) {
3336 return -EPROTO;
3337 }
Andrew Jeffery2613c272025-03-12 14:15:41 +10303338
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003339 return decode_pldm_package_firmware_device_id_record_errno(
3340 pkg->hdr, &pkg->iter.field, rec);
3341}
3342
Unive Tienf6ef78f2025-06-12 09:39:38 +08003343LIBPLDM_ABI_STABLE
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003344int pldm_package_downstream_device_id_record_iter_init(struct pldm_package *pkg)
3345{
3346 struct pldm_package_iter *iter;
John Chung7a8d9322025-08-27 20:56:19 -05003347 PLDM_MSGBUF_RO_DEFINE_P(buf);
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003348 int rc;
3349
3350 if (!pkg || !pkg->pin || !pkg->hdr) {
3351 return -EINVAL;
3352 }
3353
3354 assert(pkg->pin->format.revision >=
3355 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
3356 assert(pkg->pin->format.revision <=
3357 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H);
3358 assert(pkg->hdr->package_header_format_revision >=
3359 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
3360 assert(pkg->hdr->package_header_format_revision <=
3361 pkg->pin->format.revision);
3362
3363 if (pkg->state != PLDM_PACKAGE_PARSE_FIRMWARE_DEVICES) {
3364 return -EPROTO;
3365 }
3366
3367 if (pkg->pin->format.revision ==
3368 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H) {
3369 return -EPROTO;
3370 }
3371
3372 if (!pkg->iter.field.ptr) {
3373 return -EINVAL;
3374 }
3375 iter = &pkg->iter;
3376
3377 pkg->state = PLDM_PACKAGE_PARSE_DOWNSTREAM_DEVICES;
3378
3379 /* Where:
3380 *
3381 * 1. The pin revision is greater than 1, and
3382 * 2. The package header format revision is 1
3383 *
3384 * We must account for the invocation of this function but present no downstream
3385 * devices, as they're not specified.
3386 */
3387 if (pkg->hdr->package_header_format_revision ==
3388 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H) {
3389 iter->entries = 0;
Andrew Jeffery2613c272025-03-12 14:15:41 +10303390 return 0;
3391 }
3392
3393 /* Extract the dd record id count */
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003394 rc = pldm_msgbuf_init_errno(buf, 1, iter->field.ptr,
3395 iter->field.length);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303396 if (rc) {
3397 return rc;
3398 }
3399
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003400 pldm_msgbuf_extract_uint8_to_size(buf, iter->entries);
John Chung7a8d9322025-08-27 20:56:19 -05003401 pldm_msgbuf_span_remaining(buf, (const void **)&iter->field.ptr,
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003402 &iter->field.length);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303403
3404 return pldm_msgbuf_complete(buf);
3405}
3406
3407#define PLDM_FWUP_DOWNSTREAM_DEVICE_ID_RECORD_MIN_SIZE 11
Unive Tienf6ef78f2025-06-12 09:39:38 +08003408LIBPLDM_ABI_STABLE
Andrew Jeffery2613c272025-03-12 14:15:41 +10303409int decode_pldm_package_downstream_device_id_record_from_iter(
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003410 struct pldm_package *pkg,
Andrew Jeffery2613c272025-03-12 14:15:41 +10303411 struct pldm_package_downstream_device_id_record *rec)
3412{
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003413 struct pldm_package_iter *iter;
Carter Chen01782742025-06-25 13:53:50 +08003414 size_t package_data_offset;
John Chung7a8d9322025-08-27 20:56:19 -05003415 PLDM_MSGBUF_RO_DEFINE_P(buf);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303416 uint16_t record_len = 0;
3417 int rc;
3418
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003419 if (!pkg || !rec || !pkg->hdr) {
Andrew Jeffery2613c272025-03-12 14:15:41 +10303420 return -EINVAL;
3421 }
3422
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003423 if (pkg->state != PLDM_PACKAGE_PARSE_DOWNSTREAM_DEVICES) {
Andrew Jeffery2613c272025-03-12 14:15:41 +10303424 return -EPROTO;
3425 }
3426
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003427 assert(pkg->hdr->package_header_format_revision >
3428 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
3429
3430 if (!pkg->iter.field.ptr) {
3431 return -EINVAL;
3432 }
3433 iter = &pkg->iter;
3434
Andrew Jeffery2613c272025-03-12 14:15:41 +10303435 rc = pldm_msgbuf_init_dynamic_uint16(
3436 buf, PLDM_FWUP_DOWNSTREAM_DEVICE_ID_RECORD_MIN_SIZE,
3437 (void *)iter->field.ptr, iter->field.length,
3438 (void **)&iter->field.ptr, &iter->field.length);
3439 if (rc) {
3440 return pldm_msgbuf_discard(buf, rc);
3441 }
3442
3443 pldm_msgbuf_extract(buf, record_len);
3444 pldm_msgbuf_extract(buf, rec->descriptor_count);
3445
3446 rc = pldm_msgbuf_extract(buf, rec->update_option_flags.value);
3447 if (rc) {
3448 return pldm_msgbuf_discard(buf, rc);
3449 }
3450
3451 rc = pldm_msgbuf_extract(
3452 buf, rec->self_contained_activation_min_version_string_type);
3453 if (rc) {
3454 return pldm_msgbuf_discard(buf, rc);
3455 }
3456 if (!is_string_type_valid(
3457 rec->self_contained_activation_min_version_string_type)) {
3458 return pldm_msgbuf_discard(buf, -EPROTO);
3459 }
3460
3461 rc = pldm_msgbuf_extract_uint8_to_size(
3462 buf, rec->self_contained_activation_min_version_string.length);
3463 if (rc) {
3464 return pldm_msgbuf_discard(buf, rc);
3465 }
3466
3467 rc = pldm_msgbuf_extract_uint16_to_size(buf, rec->package_data.length);
3468 if (rc) {
3469 return pldm_msgbuf_discard(buf, rc);
3470 }
3471
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003472 if (pkg->hdr->package_header_format_revision >=
Carter Chen01782742025-06-25 13:53:50 +08003473 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H) {
3474 pldm_msgbuf_extract_uint32_to_size(
3475 buf, rec->reference_manifest_data.length);
3476 } else {
3477 rec->reference_manifest_data.length = 0;
3478 }
3479
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003480 assert((pkg->hdr->component_bitmap_bit_length & 7) == 0);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303481 rc = pldm_msgbuf_span_required(
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003482 buf, pkg->hdr->component_bitmap_bit_length / 8,
John Chung7a8d9322025-08-27 20:56:19 -05003483 (const void **)&rec->applicable_components.bitmap.ptr);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303484 if (rc) {
3485 return pldm_msgbuf_discard(buf, rc);
3486 }
3487 rec->applicable_components.bitmap.length =
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003488 pkg->hdr->component_bitmap_bit_length / 8;
Andrew Jeffery2613c272025-03-12 14:15:41 +10303489
3490 pldm_msgbuf_span_required(
3491 buf, rec->self_contained_activation_min_version_string.length,
John Chung7a8d9322025-08-27 20:56:19 -05003492 (const void **)&rec
3493 ->self_contained_activation_min_version_string.ptr);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303494 if (rec->update_option_flags.bits.bit0) {
3495 pldm_msgbuf_extract(
3496 buf,
3497 rec->self_contained_activation_min_version_comparison_stamp);
3498 } else {
3499 rec->self_contained_activation_min_version_comparison_stamp = 0;
3500 }
3501
Carter Chen01782742025-06-25 13:53:50 +08003502 /* The total length reserved for `package_data` and `reference_manifest_data` */
3503 package_data_offset =
3504 rec->package_data.length + rec->reference_manifest_data.length;
3505
3506 pldm_msgbuf_span_until(buf, package_data_offset,
John Chung7a8d9322025-08-27 20:56:19 -05003507 (const void **)&rec->record_descriptors.ptr,
Andrew Jeffery2613c272025-03-12 14:15:41 +10303508 &rec->record_descriptors.length);
3509
3510 pldm_msgbuf_span_required(buf, rec->package_data.length,
John Chung7a8d9322025-08-27 20:56:19 -05003511 (const void **)&rec->package_data.ptr);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303512
Carter Chen01782742025-06-25 13:53:50 +08003513 /* Supported in package header revision 1.3 (FR04H) and above. */
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003514 if (pkg->hdr->package_header_format_revision >=
Carter Chen01782742025-06-25 13:53:50 +08003515 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H) {
3516 pldm_msgbuf_span_required(
3517 buf, rec->reference_manifest_data.length,
John Chung7a8d9322025-08-27 20:56:19 -05003518 (const void **)&rec->reference_manifest_data.ptr);
Carter Chen01782742025-06-25 13:53:50 +08003519 } else {
3520 assert(rec->reference_manifest_data.length == 0);
3521 rec->reference_manifest_data.ptr = NULL;
3522 }
3523
Andrew Jeffery2613c272025-03-12 14:15:41 +10303524 return pldm_msgbuf_complete_consumed(buf);
3525}
3526
Unive Tienf6ef78f2025-06-12 09:39:38 +08003527LIBPLDM_ABI_STABLE
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003528int pldm_package_component_image_information_iter_init(struct pldm_package *pkg)
Andrew Jeffery2613c272025-03-12 14:15:41 +10303529{
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003530 struct pldm_package_iter *iter;
Andrew Jeffery2613c272025-03-12 14:15:41 +10303531 uint16_t component_image_count;
John Chung7a8d9322025-08-27 20:56:19 -05003532 PLDM_MSGBUF_RO_DEFINE_P(buf);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303533 int rc;
3534
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003535 if (!pkg || !pkg->pin || !pkg->hdr) {
Andrew Jeffery2613c272025-03-12 14:15:41 +10303536 return -EINVAL;
3537 }
3538
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003539 assert(pkg->pin->format.revision >=
3540 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
3541 assert(pkg->pin->format.revision <=
3542 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H);
3543 assert(pkg->hdr->package_header_format_revision >=
3544 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
3545 assert(pkg->hdr->package_header_format_revision <=
3546 pkg->pin->format.revision);
3547
3548 if (pkg->state == PLDM_PACKAGE_PARSE_FIRMWARE_DEVICES) {
3549 if (pkg->pin->format.revision !=
3550 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H ||
3551 pkg->hdr->package_header_format_revision !=
3552 pkg->pin->format.revision) {
3553 return -EPROTO;
3554 }
3555 } else if (pkg->state == PLDM_PACKAGE_PARSE_DOWNSTREAM_DEVICES) {
3556 assert(pkg->pin->format.revision !=
3557 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
3558 } else {
3559 return -EPROTO;
3560 }
3561
3562 if (!pkg->iter.field.ptr) {
3563 return -EINVAL;
3564 }
3565 iter = &pkg->iter;
3566
3567 pkg->state = PLDM_PACKAGE_PARSE_COMPONENT_IMAGE_INFORMATION;
Andrew Jeffery2613c272025-03-12 14:15:41 +10303568
3569 /* Extract the component image count */
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003570 rc = pldm_msgbuf_init_errno(buf, 1, iter->field.ptr,
3571 iter->field.length);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303572 if (rc) {
3573 return rc;
3574 }
3575
3576 rc = pldm_msgbuf_extract(buf, component_image_count);
3577 if (rc) {
3578 return pldm_msgbuf_discard(buf, rc);
3579 }
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003580 iter->entries = component_image_count;
Andrew Jeffery2613c272025-03-12 14:15:41 +10303581
John Chung7a8d9322025-08-27 20:56:19 -05003582 pldm_msgbuf_span_remaining(buf, (const void **)&iter->field.ptr,
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003583 &iter->field.length);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303584
3585 return pldm_msgbuf_complete(buf);
3586}
3587
3588#define PLDM_FWUP_COMPONENT_IMAGE_INFORMATION_MIN_SIZE 22
Unive Tienf6ef78f2025-06-12 09:39:38 +08003589LIBPLDM_ABI_STABLE
Andrew Jeffery2613c272025-03-12 14:15:41 +10303590int decode_pldm_package_component_image_information_from_iter(
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003591 struct pldm_package *pkg,
Andrew Jeffery2613c272025-03-12 14:15:41 +10303592 struct pldm_package_component_image_information *info)
3593{
3594 uint32_t component_location_offset = 0;
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003595 struct pldm_package_iter *iter;
Andrew Jeffery2613c272025-03-12 14:15:41 +10303596 uint32_t component_size = 0;
John Chung7a8d9322025-08-27 20:56:19 -05003597 PLDM_MSGBUF_RO_DEFINE_P(buf);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303598 int rc;
3599
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003600 if (!pkg || !info) {
Andrew Jeffery2613c272025-03-12 14:15:41 +10303601 return -EINVAL;
3602 }
3603
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003604 if (pkg->state != PLDM_PACKAGE_PARSE_COMPONENT_IMAGE_INFORMATION) {
Andrew Jeffery2613c272025-03-12 14:15:41 +10303605 return -EPROTO;
3606 }
3607
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003608 if (!pkg->iter.field.ptr) {
3609 return -EINVAL;
3610 }
3611 iter = &pkg->iter;
3612
Andrew Jeffery2613c272025-03-12 14:15:41 +10303613 rc = pldm_msgbuf_init_errno(
3614 buf, PLDM_FWUP_COMPONENT_IMAGE_INFORMATION_MIN_SIZE,
3615 iter->field.ptr, iter->field.length);
3616 if (rc) {
3617 return rc;
3618 }
3619
3620 pldm_msgbuf_extract(buf, info->component_classification);
3621 pldm_msgbuf_extract(buf, info->component_identifier);
3622 pldm_msgbuf_extract(buf, info->component_comparison_stamp);
3623 pldm_msgbuf_extract(buf, info->component_options.value);
3624 pldm_msgbuf_extract(buf,
3625 info->requested_component_activation_method.value);
3626 pldm_msgbuf_extract(buf, component_location_offset);
3627 pldm_msgbuf_extract(buf, component_size);
3628
3629 rc = pldm_msgbuf_extract(buf, info->component_version_string_type);
3630 if (rc) {
3631 return pldm_msgbuf_discard(buf, rc);
3632 }
3633 if (!is_string_type_valid(info->component_version_string_type)) {
3634 return pldm_msgbuf_discard(buf, -EPROTO);
3635 }
3636
3637 rc = pldm_msgbuf_extract_uint8_to_size(
3638 buf, info->component_version_string.length);
3639 if (rc) {
3640 return pldm_msgbuf_discard(buf, rc);
3641 }
3642
John Chung7a8d9322025-08-27 20:56:19 -05003643 pldm_msgbuf_span_required(
3644 buf, info->component_version_string.length,
3645 (const void **)&info->component_version_string.ptr);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303646
Carter Chenf72cf6f2025-06-24 15:34:49 +08003647 /* Supported in package header revision 1.2 (FR03H) and above. */
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003648 if (pkg->hdr->package_header_format_revision >=
Carter Chenf72cf6f2025-06-24 15:34:49 +08003649 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR03H) {
3650 rc = pldm_msgbuf_extract_uint32_to_size(
3651 buf, info->component_opaque_data.length);
3652 if (rc) {
3653 return pldm_msgbuf_discard(buf, rc);
3654 }
3655 pldm_msgbuf_span_required(
3656 buf, info->component_opaque_data.length,
John Chung7a8d9322025-08-27 20:56:19 -05003657 (const void **)&info->component_opaque_data.ptr);
Carter Chenf72cf6f2025-06-24 15:34:49 +08003658 } else {
3659 info->component_opaque_data.length = 0;
3660 }
3661
3662 if (info->component_opaque_data.length == 0) {
3663 info->component_opaque_data.ptr = NULL;
3664 }
3665
John Chung7a8d9322025-08-27 20:56:19 -05003666 pldm_msgbuf_span_remaining(buf, (const void **)&iter->field.ptr,
Andrew Jeffery2613c272025-03-12 14:15:41 +10303667 &iter->field.length);
3668
3669 rc = pldm_msgbuf_complete_consumed(buf);
3670 if (rc) {
3671 return rc;
3672 }
3673
3674 if (info->component_classification > 0x000d &&
3675 info->component_classification < 0x8000) {
3676 return -EPROTO;
3677 }
3678
3679 /* Resolve the component image in memory */
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003680 rc = pldm_msgbuf_init_errno(buf, 0, pkg->package.ptr,
3681 pkg->package.length);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303682 if (rc) {
3683 return rc;
3684 }
3685
3686 pldm_msgbuf_span_required(buf, component_location_offset, NULL);
3687 pldm_msgbuf_span_required(buf, component_size,
John Chung7a8d9322025-08-27 20:56:19 -05003688 (const void **)&info->component_image.ptr);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303689
3690 rc = pldm_msgbuf_complete(buf);
3691 if (rc) {
3692 return rc;
3693 }
3694
3695 info->component_image.length = component_size;
3696
3697 return 0;
3698}