blob: 7381546d0f838c9d02334215954e9f2b13d6ac5c [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;
396 size_t package_header_areas_size;
397 uint16_t package_header_size;
Carter Chen01782742025-06-25 13:53:50 +0800398 void *package_payload_offset;
399 size_t package_payload_size;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030400 PLDM_MSGBUF_DEFINE_P(buf);
401 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
Andrew Jeffery2613c272025-03-12 14:15:41 +1030514 pldm_msgbuf_span_required(buf, hdr->package_version_string.length,
515 (void **)&hdr->package_version_string.ptr);
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030516
517 if (package_header_size < (PLDM_FWUP_PACKAGE_HEADER_FIXED_SIZE + 3 +
518 checksums * sizeof(uint32_t))) {
Andrew Jeffery2613c272025-03-12 14:15:41 +1030519 return pldm_msgbuf_discard(buf, -EOVERFLOW);
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030520 }
521 package_header_payload_size =
522 package_header_size - (checksums * sizeof(uint32_t));
523 package_header_variable_size = package_header_payload_size -
524 PLDM_FWUP_PACKAGE_HEADER_FIXED_SIZE;
525
Andrew Jeffery2613c272025-03-12 14:15:41 +1030526 if (package_header_variable_size < hdr->package_version_string.length) {
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030527 return pldm_msgbuf_discard(buf, -EOVERFLOW);
528 }
529
530 package_header_areas_size = package_header_variable_size -
Andrew Jeffery2613c272025-03-12 14:15:41 +1030531 hdr->package_version_string.length;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030532 rc = pldm_msgbuf_span_required(buf, package_header_areas_size,
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000533 (void **)&pkg->areas.ptr);
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030534 if (rc) {
535 return pldm_msgbuf_discard(buf, rc);
536 }
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000537 pkg->areas.length = package_header_areas_size;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030538
539 pldm_msgbuf_extract(buf, package_header_checksum);
540
Carter Chen01782742025-06-25 13:53:50 +0800541 if (hdr->package_header_format_revision >=
542 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H) {
543 pldm_msgbuf_extract(buf, package_payload_checksum);
544 rc = pldm_msgbuf_span_remaining(buf, &package_payload_offset,
545 &package_payload_size);
546 if (rc) {
547 return pldm_msgbuf_discard(buf, rc);
548 }
549 } else {
550 package_payload_offset = NULL;
551 package_payload_size = 0;
552 }
553
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030554 rc = pldm_msgbuf_complete(buf);
555 if (rc) {
556 return rc;
557 }
558
Carter Chenff78bca2025-06-25 10:33:31 +0800559 rc = pldm_edac_crc32_validate(package_header_checksum, data,
560 package_header_payload_size);
561 if (rc) {
Andrew Jeffery2613c272025-03-12 14:15:41 +1030562#if 0
Carter Chenff78bca2025-06-25 10:33:31 +0800563 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 +1030564#endif
Carter Chenff78bca2025-06-25 10:33:31 +0800565 return rc;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030566 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930567
Carter Chen01782742025-06-25 13:53:50 +0800568 if (hdr->package_header_format_revision >=
569 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H) {
570 rc = pldm_edac_crc32_validate(package_payload_checksum,
571 package_payload_offset,
572 package_payload_size);
573 if (rc) {
574#if 0
575 printf("payload checksum failure, expected: %#08" PRIx32 ", found: %#08" PRIx32 "\n", package_payload_checksum, pldm_edac_crc32(package_payload_offset, package_payload_size));
576#endif
577 return rc;
578 }
579 }
580
Andrew Jeffery2613c272025-03-12 14:15:41 +1030581 /* We stash these to resolve component images later */
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000582 pkg->pin = pin;
583 pkg->hdr = hdr;
584 pkg->state = PLDM_PACKAGE_PARSE_HEADER;
Andrew Jeffery72442de2025-08-12 08:47:42 +0000585 pkg->flags = 0;
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000586 pkg->package.ptr = data;
587 pkg->package.length = length;
Andrew Jeffery2613c272025-03-12 14:15:41 +1030588
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030589 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930590}
591
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930592LIBPLDM_ABI_STABLE
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030593int decode_pldm_package_header_info(
594 const uint8_t *data, size_t length,
595 struct pldm_package_header_information *package_header_info,
596 struct variable_field *package_version_str)
597{
Andrew Jeffery2613c272025-03-12 14:15:41 +1030598 DEFINE_PLDM_PACKAGE_FORMAT_PIN_FR01H(pin);
599 pldm_package_header_information_pad hdr;
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000600 struct pldm_package pkg = { 0 };
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030601 int rc;
602
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030603 if (!data || !package_header_info || !package_version_str) {
604 return PLDM_ERROR_INVALID_DATA;
605 }
606
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000607 rc = decode_pldm_package_header_info_errno(data, length, &pin, &hdr,
608 &pkg);
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030609 if (rc < 0) {
610 return pldm_xlate_errno(rc);
611 }
612
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030613 static_assert(sizeof(package_header_info->uuid) ==
Andrew Jeffery2613c272025-03-12 14:15:41 +1030614 sizeof(hdr.package_header_identifier),
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030615 "UUID field size");
Andrew Jeffery2613c272025-03-12 14:15:41 +1030616 memcpy(package_header_info->uuid, hdr.package_header_identifier,
617 sizeof(hdr.package_header_identifier));
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030618 package_header_info->package_header_format_version =
Andrew Jeffery2613c272025-03-12 14:15:41 +1030619 hdr.package_header_format_revision;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030620 memcpy(&package_header_info->package_header_size, data + 17,
621 sizeof(package_header_info->package_header_size));
622 LE16TOH(package_header_info->package_header_size);
623 static_assert(sizeof(package_header_info->package_release_date_time) ==
Andrew Jeffery2613c272025-03-12 14:15:41 +1030624 sizeof(hdr.package_release_date_time),
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030625 "TIMESTAMP104 field size");
626 memcpy(package_header_info->package_release_date_time,
Andrew Jeffery2613c272025-03-12 14:15:41 +1030627 hdr.package_release_date_time,
628 sizeof(hdr.package_release_date_time));
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030629 package_header_info->component_bitmap_bit_length =
Andrew Jeffery2613c272025-03-12 14:15:41 +1030630 hdr.component_bitmap_bit_length;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030631 package_header_info->package_version_string_type =
Andrew Jeffery2613c272025-03-12 14:15:41 +1030632 hdr.package_version_string_type;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030633 package_header_info->package_version_string_length =
Andrew Jeffery2613c272025-03-12 14:15:41 +1030634 hdr.package_version_string.length;
635 *package_version_str = hdr.package_version_string;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030636
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030637 return PLDM_SUCCESS;
638}
639
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000640/* Currently only used for decode_firmware_device_id_record_errno() */
641static int pldm_msgbuf_init_dynamic_uint16(struct pldm_msgbuf *buf, size_t req,
Andrew Jeffery2613c272025-03-12 14:15:41 +1030642 void *data, size_t len,
643 void **tail_data, size_t *tail_len)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930644{
Andrew Jeffery2613c272025-03-12 14:15:41 +1030645 size_t dyn_length;
646 void *dyn_start;
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000647 int rc;
648
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000649 rc = pldm_msgbuf_init_errno(buf, req, data, len);
650 if (rc) {
651 return rc;
652 }
Andrew Jeffery2613c272025-03-12 14:15:41 +1030653 /*
654 * Extract the record length from the first field, then reinitialise the msgbuf
655 * after determining that it's safe to do so
656 */
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000657
Andrew Jeffery2613c272025-03-12 14:15:41 +1030658 rc = pldm_msgbuf_extract_uint16_to_size(buf, dyn_length);
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000659 if (rc) {
660 return pldm_msgbuf_discard(buf, rc);
661 }
662
663 rc = pldm_msgbuf_complete(buf);
664 if (rc) {
665 return rc;
666 }
667
668 rc = pldm_msgbuf_init_errno(buf, req, data, len);
669 if (rc) {
670 return rc;
671 }
672
673 /* Ensure there's no arithmetic funkiness and the span is within buffer bounds */
Andrew Jeffery2613c272025-03-12 14:15:41 +1030674 rc = pldm_msgbuf_span_required(buf, dyn_length, &dyn_start);
675 if (rc) {
676 return pldm_msgbuf_discard(buf, rc);
677 }
678
679 rc = pldm_msgbuf_span_remaining(buf, tail_data, tail_len);
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000680 if (rc) {
681 return pldm_msgbuf_discard(buf, rc);
682 }
683
684 rc = pldm_msgbuf_complete(buf);
685 if (rc) {
686 return rc;
687 }
688
Andrew Jeffery2613c272025-03-12 14:15:41 +1030689 return pldm_msgbuf_init_errno(buf, req, dyn_start, dyn_length);
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000690}
691
692#define PLDM_FWUP_FIRMWARE_DEVICE_ID_RECORD_MIN_SIZE 11
Andrew Jeffery2613c272025-03-12 14:15:41 +1030693static int decode_pldm_package_firmware_device_id_record_errno(
694 const pldm_package_header_information_pad *hdr,
695 struct variable_field *field,
696 struct pldm_package_firmware_device_id_record *rec)
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000697{
Carter Chen01782742025-06-25 13:53:50 +0800698 size_t firmware_device_package_data_offset;
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000699 PLDM_MSGBUF_DEFINE_P(buf);
700 uint16_t record_len = 0;
701 int rc;
702
Andrew Jeffery2613c272025-03-12 14:15:41 +1030703 if (!hdr || !field || !rec || !field->ptr) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030704 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930705 }
706
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000707 rc = pldm_msgbuf_init_dynamic_uint16(
Andrew Jeffery2613c272025-03-12 14:15:41 +1030708 buf, PLDM_FWUP_FIRMWARE_DEVICE_ID_RECORD_MIN_SIZE,
709 (void *)field->ptr, field->length, (void **)&field->ptr,
710 &field->length);
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000711 if (rc) {
712 return rc;
713 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930714
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000715 pldm_msgbuf_extract(buf, record_len);
716 pldm_msgbuf_extract(buf, rec->descriptor_count);
717 pldm_msgbuf_extract(buf, rec->device_update_option_flags.value);
718
719 rc = pldm_msgbuf_extract(buf,
720 rec->component_image_set_version_string_type);
721 if (rc) {
722 return pldm_msgbuf_discard(buf, rc);
723 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930724 if (!is_string_type_valid(
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000725 rec->component_image_set_version_string_type)) {
726 return pldm_msgbuf_discard(buf, -EPROTO);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930727 }
728
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000729 rc = pldm_msgbuf_extract_uint8_to_size(
730 buf, rec->component_image_set_version_string.length);
731 if (rc) {
732 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930733 }
734
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000735 if (rec->component_image_set_version_string.length == 0) {
736 return pldm_msgbuf_discard(buf, -EPROTO);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930737 }
738
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000739 rc = pldm_msgbuf_extract_uint16_to_size(
740 buf, rec->firmware_device_package_data.length);
741 if (rc) {
742 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930743 }
744
Carter Chen01782742025-06-25 13:53:50 +0800745 if (hdr->package_header_format_revision >=
746 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H) {
747 rc = pldm_msgbuf_extract_uint32_to_size(
748 buf, rec->reference_manifest_data.length);
749 if (rc) {
750 return pldm_msgbuf_discard(buf, rc);
751 }
752 } else {
753 rec->reference_manifest_data.length = 0;
754 }
755
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000756 assert((hdr->component_bitmap_bit_length & 7) == 0);
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000757 rc = pldm_msgbuf_span_required(
Andrew Jeffery2613c272025-03-12 14:15:41 +1030758 buf, hdr->component_bitmap_bit_length / 8,
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000759 (void **)&rec->applicable_components.bitmap.ptr);
760 if (rc) {
761 return pldm_msgbuf_discard(buf, rc);
762 }
763 rec->applicable_components.bitmap.length =
Andrew Jeffery2613c272025-03-12 14:15:41 +1030764 hdr->component_bitmap_bit_length / 8;
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000765
766 pldm_msgbuf_span_required(
767 buf, rec->component_image_set_version_string.length,
768 (void **)&rec->component_image_set_version_string.ptr);
769
Carter Chen01782742025-06-25 13:53:50 +0800770 /* The total length reserved for `package_data` and `reference_manifest_data` */
771 firmware_device_package_data_offset =
772 rec->firmware_device_package_data.length +
773 rec->reference_manifest_data.length;
774
775 pldm_msgbuf_span_until(buf, firmware_device_package_data_offset,
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000776 (void **)&rec->record_descriptors.ptr,
777 &rec->record_descriptors.length);
778
779 pldm_msgbuf_span_required(
780 buf, rec->firmware_device_package_data.length,
781 (void **)&rec->firmware_device_package_data.ptr);
782 if (!rec->firmware_device_package_data.length) {
783 rec->firmware_device_package_data.ptr = NULL;
784 }
785
Carter Chen01782742025-06-25 13:53:50 +0800786 if (hdr->package_header_format_revision >=
787 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H) {
788 pldm_msgbuf_span_required(
789 buf, rec->reference_manifest_data.length,
790 (void **)&rec->reference_manifest_data.ptr);
791
792 } else {
793 assert(rec->reference_manifest_data.length == 0);
794 rec->reference_manifest_data.ptr = NULL;
795 }
796
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000797 return pldm_msgbuf_complete_consumed(buf);
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030798}
799
800LIBPLDM_ABI_STABLE
801int decode_firmware_device_id_record(
802 const uint8_t *data, size_t length,
803 uint16_t component_bitmap_bit_length,
804 struct pldm_firmware_device_id_record *fw_device_id_record,
805 struct variable_field *applicable_components,
806 struct variable_field *comp_image_set_version_str,
807 struct variable_field *record_descriptors,
808 struct variable_field *fw_device_pkg_data)
809{
Andrew Jeffery2613c272025-03-12 14:15:41 +1030810 struct pldm_package_firmware_device_id_record rec;
811 pldm_package_header_information_pad hdr;
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030812 int rc;
813
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000814 if (!data || !fw_device_id_record || !applicable_components ||
815 !comp_image_set_version_str || !record_descriptors ||
816 !fw_device_pkg_data) {
817 return PLDM_ERROR_INVALID_DATA;
818 }
819
Andrew Jeffery2613c272025-03-12 14:15:41 +1030820 hdr.package_header_format_revision =
821 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H;
822 hdr.component_bitmap_bit_length = component_bitmap_bit_length;
823
824 rc = decode_pldm_package_firmware_device_id_record_errno(
825 &hdr, &(struct variable_field){ data, length }, &rec);
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030826 if (rc < 0) {
827 return pldm_xlate_errno(rc);
828 }
829
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000830 memcpy(&fw_device_id_record->record_length, data,
831 sizeof(fw_device_id_record->record_length));
832 LE16TOH(fw_device_id_record->record_length);
833 fw_device_id_record->descriptor_count = rec.descriptor_count;
834 fw_device_id_record->device_update_option_flags =
835 rec.device_update_option_flags;
836 fw_device_id_record->comp_image_set_version_string_type =
837 rec.component_image_set_version_string_type;
838 fw_device_id_record->comp_image_set_version_string_length =
839 rec.component_image_set_version_string.length;
840 fw_device_id_record->fw_device_pkg_data_length =
841 rec.firmware_device_package_data.length;
842 *applicable_components = rec.applicable_components.bitmap;
843 *comp_image_set_version_str = rec.component_image_set_version_string;
844 *record_descriptors = rec.record_descriptors;
845 *fw_device_pkg_data = rec.firmware_device_package_data;
846
Andrew Jeffery9c766792022-08-10 23:12:49 +0930847 return PLDM_SUCCESS;
848}
849
Unive Tiene5c3f142024-12-13 14:14:19 +0800850LIBPLDM_ABI_STABLE
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030851int decode_pldm_descriptor_from_iter(struct pldm_descriptor_iter *iter,
852 struct pldm_descriptor *desc)
853{
Andrew Jefferya1896962025-03-03 21:41:25 +1030854 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030855 int rc;
856
857 if (!iter || !iter->field || !desc) {
858 return -EINVAL;
859 }
860
861 rc = pldm_msgbuf_init_errno(buf, PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN,
862 iter->field->ptr, iter->field->length);
863 if (rc) {
864 return rc;
865 }
866
867 pldm_msgbuf_extract(buf, desc->descriptor_type);
868 rc = pldm_msgbuf_extract(buf, desc->descriptor_length);
869 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +1030870 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030871 }
872
873 desc->descriptor_data = NULL;
874 pldm_msgbuf_span_required(buf, desc->descriptor_length,
875 (void **)&desc->descriptor_data);
876 iter->field->ptr = NULL;
877 pldm_msgbuf_span_remaining(buf, (void **)&iter->field->ptr,
878 &iter->field->length);
879
Andrew Jeffery70d21c92025-03-05 12:59:42 +1030880 return pldm_msgbuf_complete(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030881}
882
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030883static int decode_descriptor_type_length_value_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030884 const void *data, size_t length, uint16_t *descriptor_type,
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030885 struct variable_field *descriptor_data)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930886{
887 uint16_t descriptor_length = 0;
888
889 if (data == NULL || descriptor_type == NULL ||
890 descriptor_data == NULL) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030891 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930892 }
893
894 if (length < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030895 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930896 }
897
898 struct pldm_descriptor_tlv *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930899 (struct pldm_descriptor_tlv *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930900
901 *descriptor_type = le16toh(entry->descriptor_type);
902 descriptor_length = le16toh(entry->descriptor_length);
903 if (*descriptor_type != PLDM_FWUP_VENDOR_DEFINED) {
904 if (descriptor_length !=
905 get_descriptor_type_length(*descriptor_type)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030906 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930907 }
908 }
909
910 if (length < (sizeof(*descriptor_type) + sizeof(descriptor_length) +
911 descriptor_length)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030912 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930913 }
914
915 descriptor_data->ptr = entry->descriptor_data;
916 descriptor_data->length = descriptor_length;
917
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030918 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930919}
920
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930921LIBPLDM_ABI_STABLE
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030922int decode_descriptor_type_length_value(const uint8_t *data, size_t length,
923 uint16_t *descriptor_type,
924 struct variable_field *descriptor_data)
925{
926 int rc;
927
928 rc = decode_descriptor_type_length_value_errno(
929 data, length, descriptor_type, descriptor_data);
930 if (rc < 0) {
931 return pldm_xlate_errno(rc);
932 }
933
934 return PLDM_SUCCESS;
935}
936
937static int decode_vendor_defined_descriptor_value_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030938 const void *data, size_t length, uint8_t *descriptor_title_str_type,
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930939 struct variable_field *descriptor_title_str,
940 struct variable_field *descriptor_data)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930941{
942 if (data == NULL || descriptor_title_str_type == NULL ||
943 descriptor_title_str == NULL || descriptor_data == NULL) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030944 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930945 }
946
947 if (length < sizeof(struct pldm_vendor_defined_descriptor_title_data)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030948 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930949 }
950
951 struct pldm_vendor_defined_descriptor_title_data *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930952 (struct pldm_vendor_defined_descriptor_title_data *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930953 if (!is_string_type_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930954 entry->vendor_defined_descriptor_title_str_type) ||
Andrew Jeffery9c766792022-08-10 23:12:49 +0930955 (entry->vendor_defined_descriptor_title_str_len == 0)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030956 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930957 }
958
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530959 // Assuming at least 1 byte of VendorDefinedDescriptorData
Andrew Jeffery9c766792022-08-10 23:12:49 +0930960 if (length < (sizeof(struct pldm_vendor_defined_descriptor_title_data) +
961 entry->vendor_defined_descriptor_title_str_len)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030962 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930963 }
964
965 *descriptor_title_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930966 entry->vendor_defined_descriptor_title_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930967 descriptor_title_str->ptr = entry->vendor_defined_descriptor_title_str;
968 descriptor_title_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930969 entry->vendor_defined_descriptor_title_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930970
971 descriptor_data->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930972 descriptor_title_str->ptr + descriptor_title_str->length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930973 descriptor_data->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930974 length -
975 sizeof(entry->vendor_defined_descriptor_title_str_type) -
976 sizeof(entry->vendor_defined_descriptor_title_str_len) -
977 descriptor_title_str->length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930978
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030979 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930980}
981
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930982LIBPLDM_ABI_STABLE
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030983int decode_vendor_defined_descriptor_value(
984 const uint8_t *data, size_t length, uint8_t *descriptor_title_str_type,
985 struct variable_field *descriptor_title_str,
986 struct variable_field *descriptor_data)
987{
988 int rc;
989
990 rc = decode_vendor_defined_descriptor_value_errno(
991 data, length, descriptor_title_str_type, descriptor_title_str,
992 descriptor_data);
993 if (rc < 0) {
994 return pldm_xlate_errno(rc);
995 }
996
997 return PLDM_SUCCESS;
998}
999
1000static int decode_pldm_comp_image_info_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +10301001 const void *data, size_t length,
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301002 struct pldm_component_image_information *pldm_comp_image_info,
1003 struct variable_field *comp_version_str)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301004{
1005 if (data == NULL || pldm_comp_image_info == NULL ||
1006 comp_version_str == NULL) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +10301007 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301008 }
1009
1010 if (length < sizeof(struct pldm_component_image_information)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +10301011 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301012 }
1013
1014 struct pldm_component_image_information *data_header =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301015 (struct pldm_component_image_information *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301016
1017 if (!is_string_type_valid(data_header->comp_version_string_type) ||
1018 (data_header->comp_version_string_length == 0)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +10301019 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301020 }
1021
1022 if (length < sizeof(struct pldm_component_image_information) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301023 data_header->comp_version_string_length) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +10301024 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301025 }
1026
1027 pldm_comp_image_info->comp_classification =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301028 le16toh(data_header->comp_classification);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301029 pldm_comp_image_info->comp_identifier =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301030 le16toh(data_header->comp_identifier);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301031 pldm_comp_image_info->comp_comparison_stamp =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301032 le32toh(data_header->comp_comparison_stamp);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301033 pldm_comp_image_info->comp_options.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301034 le16toh(data_header->comp_options.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301035 pldm_comp_image_info->requested_comp_activation_method.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301036 le16toh(data_header->requested_comp_activation_method.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301037 pldm_comp_image_info->comp_location_offset =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301038 le32toh(data_header->comp_location_offset);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301039 pldm_comp_image_info->comp_size = le32toh(data_header->comp_size);
1040 pldm_comp_image_info->comp_version_string_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301041 data_header->comp_version_string_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301042 pldm_comp_image_info->comp_version_string_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301043 data_header->comp_version_string_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301044
1045 if ((pldm_comp_image_info->comp_options.bits.bit1 == false &&
1046 pldm_comp_image_info->comp_comparison_stamp !=
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301047 PLDM_FWUP_INVALID_COMPONENT_COMPARISON_TIMESTAMP)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +10301048 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301049 }
1050
1051 if (pldm_comp_image_info->comp_location_offset == 0 ||
1052 pldm_comp_image_info->comp_size == 0) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +10301053 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301054 }
1055
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +10301056 comp_version_str->ptr = (const uint8_t *)data +
1057 sizeof(struct pldm_component_image_information);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301058 comp_version_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301059 pldm_comp_image_info->comp_version_string_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301060
Andrew Jeffery779e9db2025-02-21 12:14:28 +10301061 return 0;
1062}
1063
1064LIBPLDM_ABI_STABLE
1065int decode_pldm_comp_image_info(
1066 const uint8_t *data, size_t length,
1067 struct pldm_component_image_information *pldm_comp_image_info,
1068 struct variable_field *comp_version_str)
1069{
1070 int rc;
1071
1072 rc = decode_pldm_comp_image_info_errno(
1073 data, length, pldm_comp_image_info, comp_version_str);
1074 if (rc < 0) {
1075 return pldm_xlate_errno(rc);
1076 }
1077
Andrew Jeffery9c766792022-08-10 23:12:49 +09301078 return PLDM_SUCCESS;
1079}
1080
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301081LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301082int encode_query_device_identifiers_req(uint8_t instance_id,
1083 size_t payload_length,
1084 struct pldm_msg *msg)
1085{
1086 if (msg == NULL) {
1087 return PLDM_ERROR_INVALID_DATA;
1088 }
1089
1090 if (payload_length != PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES) {
1091 return PLDM_ERROR_INVALID_LENGTH;
1092 }
1093
1094 return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
1095 PLDM_QUERY_DEVICE_IDENTIFIERS, msg);
1096}
1097
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301098LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301099int decode_query_device_identifiers_resp(const struct pldm_msg *msg,
1100 size_t payload_length,
1101 uint8_t *completion_code,
1102 uint32_t *device_identifiers_len,
1103 uint8_t *descriptor_count,
1104 uint8_t **descriptor_data)
1105{
1106 if (msg == NULL || completion_code == NULL ||
1107 device_identifiers_len == NULL || descriptor_count == NULL ||
1108 descriptor_data == NULL) {
1109 return PLDM_ERROR_INVALID_DATA;
1110 }
1111
1112 *completion_code = msg->payload[0];
1113 if (PLDM_SUCCESS != *completion_code) {
1114 return PLDM_SUCCESS;
1115 }
1116
1117 if (payload_length <
1118 sizeof(struct pldm_query_device_identifiers_resp)) {
1119 return PLDM_ERROR_INVALID_LENGTH;
1120 }
1121
1122 struct pldm_query_device_identifiers_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301123 (struct pldm_query_device_identifiers_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301124 *device_identifiers_len = le32toh(response->device_identifiers_len);
1125
1126 if (*device_identifiers_len < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {
1127 return PLDM_ERROR_INVALID_LENGTH;
1128 }
1129
1130 if (payload_length !=
1131 sizeof(struct pldm_query_device_identifiers_resp) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301132 *device_identifiers_len) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301133 return PLDM_ERROR_INVALID_LENGTH;
1134 }
1135 *descriptor_count = response->descriptor_count;
1136
1137 if (*descriptor_count == 0) {
1138 return PLDM_ERROR_INVALID_DATA;
1139 }
1140 *descriptor_data =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301141 (uint8_t *)(msg->payload +
1142 sizeof(struct pldm_query_device_identifiers_resp));
Andrew Jeffery9c766792022-08-10 23:12:49 +09301143 return PLDM_SUCCESS;
1144}
1145
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001146LIBPLDM_ABI_TESTING
1147int encode_query_device_identifiers_resp(
1148 uint8_t instance_id, uint8_t descriptor_count,
1149 const struct pldm_descriptor *descriptors, struct pldm_msg *msg,
1150 size_t *payload_length)
1151{
Andrew Jefferya1896962025-03-03 21:41:25 +10301152 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001153 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001154
1155 if (descriptors == NULL || msg == NULL || payload_length == NULL) {
1156 return -EINVAL;
1157 }
1158
1159 if (descriptor_count < 1) {
1160 return -EINVAL;
1161 }
1162
1163 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
1164 PLDM_QUERY_DEVICE_IDENTIFIERS, msg);
1165 if (rc) {
1166 return -EINVAL;
1167 }
1168
1169 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
1170 if (rc) {
1171 return rc;
1172 }
1173
1174 /* Determine total length */
1175 uint32_t device_identifiers_len = 0;
1176 for (uint8_t i = 0; i < descriptor_count; i++) {
1177 const struct pldm_descriptor *d = &descriptors[i];
1178 device_identifiers_len +=
1179 2 * sizeof(uint16_t) + d->descriptor_length;
1180 }
1181
1182 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
1183 pldm_msgbuf_insert(buf, device_identifiers_len);
1184 pldm_msgbuf_insert(buf, descriptor_count);
1185
1186 for (uint8_t i = 0; i < descriptor_count; i++) {
1187 const struct pldm_descriptor *d = &descriptors[i];
1188 pldm_msgbuf_insert(buf, d->descriptor_type);
1189 pldm_msgbuf_insert(buf, d->descriptor_length);
1190 if (d->descriptor_data == NULL) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301191 return pldm_msgbuf_discard(buf, -EINVAL);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001192 }
1193 rc = pldm_msgbuf_insert_array(
1194 buf, d->descriptor_length,
1195 (const uint8_t *)d->descriptor_data,
1196 d->descriptor_length);
1197 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301198 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001199 }
1200 }
1201
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301202 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001203}
1204
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301205LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301206int encode_get_firmware_parameters_req(uint8_t instance_id,
1207 size_t payload_length,
1208 struct pldm_msg *msg)
1209{
1210 if (msg == NULL) {
1211 return PLDM_ERROR_INVALID_DATA;
1212 }
1213
1214 if (payload_length != PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES) {
1215 return PLDM_ERROR_INVALID_LENGTH;
1216 }
1217
1218 return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
1219 PLDM_GET_FIRMWARE_PARAMETERS, msg);
1220}
1221
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301222LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301223int decode_get_firmware_parameters_resp(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301224 const struct pldm_msg *msg, size_t payload_length,
1225 struct pldm_get_firmware_parameters_resp *resp_data,
1226 struct variable_field *active_comp_image_set_ver_str,
1227 struct variable_field *pending_comp_image_set_ver_str,
1228 struct variable_field *comp_parameter_table)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301229{
1230 if (msg == NULL || resp_data == NULL ||
1231 active_comp_image_set_ver_str == NULL ||
1232 pending_comp_image_set_ver_str == NULL ||
1233 comp_parameter_table == NULL || !payload_length) {
1234 return PLDM_ERROR_INVALID_DATA;
1235 }
1236
1237 resp_data->completion_code = msg->payload[0];
1238 if (PLDM_SUCCESS != resp_data->completion_code) {
1239 return PLDM_SUCCESS;
1240 }
1241
1242 if (payload_length < sizeof(struct pldm_get_firmware_parameters_resp)) {
1243 return PLDM_ERROR_INVALID_LENGTH;
1244 }
1245
1246 struct pldm_get_firmware_parameters_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301247 (struct pldm_get_firmware_parameters_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301248
1249 if (!is_string_type_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301250 response->active_comp_image_set_ver_str_type) ||
Andrew Jeffery9c766792022-08-10 23:12:49 +09301251 (response->active_comp_image_set_ver_str_len == 0)) {
1252 return PLDM_ERROR_INVALID_DATA;
1253 }
1254
1255 if (response->pending_comp_image_set_ver_str_len == 0) {
1256 if (response->pending_comp_image_set_ver_str_type !=
1257 PLDM_STR_TYPE_UNKNOWN) {
1258 return PLDM_ERROR_INVALID_DATA;
1259 }
1260 } else {
1261 if (!is_string_type_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301262 response->pending_comp_image_set_ver_str_type)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301263 return PLDM_ERROR_INVALID_DATA;
1264 }
1265 }
1266
1267 size_t partial_response_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301268 sizeof(struct pldm_get_firmware_parameters_resp) +
1269 response->active_comp_image_set_ver_str_len +
1270 response->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301271
1272 if (payload_length < partial_response_length) {
1273 return PLDM_ERROR_INVALID_LENGTH;
1274 }
1275
1276 resp_data->capabilities_during_update.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301277 le32toh(response->capabilities_during_update.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301278 resp_data->comp_count = le16toh(response->comp_count);
1279 resp_data->active_comp_image_set_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301280 response->active_comp_image_set_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301281 resp_data->active_comp_image_set_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301282 response->active_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301283 resp_data->pending_comp_image_set_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301284 response->pending_comp_image_set_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301285 resp_data->pending_comp_image_set_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301286 response->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301287
1288 active_comp_image_set_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301289 msg->payload + sizeof(struct pldm_get_firmware_parameters_resp);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301290 active_comp_image_set_ver_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301291 resp_data->active_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301292
1293 if (resp_data->pending_comp_image_set_ver_str_len != 0) {
1294 pending_comp_image_set_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301295 msg->payload +
1296 sizeof(struct pldm_get_firmware_parameters_resp) +
1297 resp_data->active_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301298 pending_comp_image_set_ver_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301299 resp_data->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301300 } else {
1301 pending_comp_image_set_ver_str->ptr = NULL;
1302 pending_comp_image_set_ver_str->length = 0;
1303 }
1304
1305 if (payload_length > partial_response_length && resp_data->comp_count) {
1306 comp_parameter_table->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301307 msg->payload +
1308 sizeof(struct pldm_get_firmware_parameters_resp) +
1309 resp_data->active_comp_image_set_ver_str_len +
1310 resp_data->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301311 comp_parameter_table->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301312 payload_length - partial_response_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301313 } else {
1314 comp_parameter_table->ptr = NULL;
1315 comp_parameter_table->length = 0;
1316 }
1317
1318 return PLDM_SUCCESS;
1319}
1320
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001321LIBPLDM_ABI_TESTING
1322int encode_get_firmware_parameters_resp(
1323 uint8_t instance_id,
1324 const struct pldm_get_firmware_parameters_resp_full *resp_data,
1325 struct pldm_msg *msg, size_t *payload_length)
1326{
Andrew Jefferya1896962025-03-03 21:41:25 +10301327 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001328 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001329
1330 if (resp_data == NULL || msg == NULL || payload_length == NULL) {
1331 return -EINVAL;
1332 }
1333
1334 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
1335 PLDM_GET_FIRMWARE_PARAMETERS, msg);
1336 if (rc) {
1337 return -EINVAL;
1338 }
1339
1340 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
1341 if (rc) {
1342 return rc;
1343 }
1344
1345 pldm_msgbuf_insert(buf, resp_data->completion_code);
1346 pldm_msgbuf_insert(buf, resp_data->capabilities_during_update.value);
1347 pldm_msgbuf_insert(buf, resp_data->comp_count);
1348 pldm_msgbuf_insert(buf,
1349 resp_data->active_comp_image_set_ver_str.str_type);
1350 pldm_msgbuf_insert(buf,
1351 resp_data->active_comp_image_set_ver_str.str_len);
1352 pldm_msgbuf_insert(buf,
1353 resp_data->pending_comp_image_set_ver_str.str_type);
1354 pldm_msgbuf_insert(buf,
1355 resp_data->pending_comp_image_set_ver_str.str_len);
1356 /* String data appended */
1357 rc = pldm_msgbuf_insert_array(
1358 buf, resp_data->active_comp_image_set_ver_str.str_len,
1359 resp_data->active_comp_image_set_ver_str.str_data,
1360 resp_data->active_comp_image_set_ver_str.str_len);
1361 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301362 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001363 }
1364 rc = pldm_msgbuf_insert_array(
1365 buf, resp_data->pending_comp_image_set_ver_str.str_len,
1366 resp_data->pending_comp_image_set_ver_str.str_data,
1367 resp_data->pending_comp_image_set_ver_str.str_len);
1368 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301369 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001370 }
1371
1372 /* Further calls to encode_get_firmware_parameters_resp_comp_entry
1373 * will populate the remainder */
1374
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301375 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001376}
1377
1378LIBPLDM_ABI_TESTING
1379int encode_get_firmware_parameters_resp_comp_entry(
1380 const struct pldm_component_parameter_entry_full *comp,
1381 uint8_t *payload, size_t *payload_length)
1382{
Andrew Jefferya1896962025-03-03 21:41:25 +10301383 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001384 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001385
1386 if (comp == NULL || payload == NULL || payload_length == NULL) {
1387 return -EINVAL;
1388 }
1389
1390 rc = pldm_msgbuf_init_errno(buf, 0, payload, *payload_length);
1391 if (rc) {
1392 return rc;
1393 }
1394
1395 pldm_msgbuf_insert(buf, comp->comp_classification);
1396 pldm_msgbuf_insert(buf, comp->comp_identifier);
1397 pldm_msgbuf_insert(buf, comp->comp_classification_index);
1398
1399 pldm_msgbuf_insert(buf, comp->active_ver.comparison_stamp);
1400 pldm_msgbuf_insert(buf, (uint8_t)comp->active_ver.str.str_type);
1401 pldm_msgbuf_insert(buf, comp->active_ver.str.str_len);
1402 rc = pldm_msgbuf_insert_array(buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1403 comp->active_ver.date,
1404 PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN);
1405 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301406 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001407 }
1408
1409 pldm_msgbuf_insert(buf, comp->pending_ver.comparison_stamp);
1410 pldm_msgbuf_insert(buf, (uint8_t)comp->pending_ver.str.str_type);
1411 pldm_msgbuf_insert(buf, comp->pending_ver.str.str_len);
1412 rc = pldm_msgbuf_insert_array(buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1413 comp->pending_ver.date,
1414 PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN);
1415 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301416 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001417 }
1418
1419 pldm_msgbuf_insert(buf, comp->comp_activation_methods.value);
1420 pldm_msgbuf_insert(buf, comp->capabilities_during_update.value);
1421
1422 rc = pldm_msgbuf_insert_array(buf, comp->active_ver.str.str_len,
1423 comp->active_ver.str.str_data,
1424 comp->active_ver.str.str_len);
1425 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301426 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001427 }
1428 rc = pldm_msgbuf_insert_array(buf, comp->pending_ver.str.str_len,
1429 comp->pending_ver.str.str_data,
1430 comp->pending_ver.str.str_len);
1431 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301432 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001433 }
1434
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301435 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001436}
1437
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301438LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301439int decode_get_firmware_parameters_resp_comp_entry(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301440 const uint8_t *data, size_t length,
1441 struct pldm_component_parameter_entry *component_data,
1442 struct variable_field *active_comp_ver_str,
1443 struct variable_field *pending_comp_ver_str)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301444{
1445 if (data == NULL || component_data == NULL ||
1446 active_comp_ver_str == NULL || pending_comp_ver_str == NULL) {
1447 return PLDM_ERROR_INVALID_DATA;
1448 }
1449
1450 if (length < sizeof(struct pldm_component_parameter_entry)) {
1451 return PLDM_ERROR_INVALID_LENGTH;
1452 }
1453
1454 struct pldm_component_parameter_entry *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301455 (struct pldm_component_parameter_entry *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301456
1457 size_t entry_length = sizeof(struct pldm_component_parameter_entry) +
1458 entry->active_comp_ver_str_len +
1459 entry->pending_comp_ver_str_len;
1460
1461 if (length < entry_length) {
1462 return PLDM_ERROR_INVALID_LENGTH;
1463 }
1464
1465 component_data->comp_classification =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301466 le16toh(entry->comp_classification);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301467 component_data->comp_identifier = le16toh(entry->comp_identifier);
1468 component_data->comp_classification_index =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301469 entry->comp_classification_index;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301470 component_data->active_comp_comparison_stamp =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301471 le32toh(entry->active_comp_comparison_stamp);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301472 component_data->active_comp_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301473 entry->active_comp_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301474 component_data->active_comp_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301475 entry->active_comp_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301476 memcpy(component_data->active_comp_release_date,
1477 entry->active_comp_release_date,
1478 sizeof(entry->active_comp_release_date));
1479 component_data->pending_comp_comparison_stamp =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301480 le32toh(entry->pending_comp_comparison_stamp);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301481 component_data->pending_comp_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301482 entry->pending_comp_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301483 component_data->pending_comp_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301484 entry->pending_comp_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301485 memcpy(component_data->pending_comp_release_date,
1486 entry->pending_comp_release_date,
1487 sizeof(entry->pending_comp_release_date));
1488 component_data->comp_activation_methods.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301489 le16toh(entry->comp_activation_methods.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301490 component_data->capabilities_during_update.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301491 le32toh(entry->capabilities_during_update.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301492
1493 if (entry->active_comp_ver_str_len != 0) {
1494 active_comp_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301495 data + sizeof(struct pldm_component_parameter_entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301496 active_comp_ver_str->length = entry->active_comp_ver_str_len;
1497 } else {
1498 active_comp_ver_str->ptr = NULL;
1499 active_comp_ver_str->length = 0;
1500 }
1501
1502 if (entry->pending_comp_ver_str_len != 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301503 pending_comp_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301504 data + sizeof(struct pldm_component_parameter_entry) +
1505 entry->active_comp_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301506 pending_comp_ver_str->length = entry->pending_comp_ver_str_len;
1507 } else {
1508 pending_comp_ver_str->ptr = NULL;
1509 pending_comp_ver_str->length = 0;
1510 }
1511 return PLDM_SUCCESS;
1512}
1513
Unive Tiene5c3f142024-12-13 14:14:19 +08001514LIBPLDM_ABI_STABLE
Chris Wang4c1f2c72024-03-21 17:09:44 +08001515int encode_query_downstream_devices_req(uint8_t instance_id,
1516 struct pldm_msg *msg)
1517{
1518 if (msg == NULL) {
Unive Tien71e935c2024-11-25 17:21:43 +08001519 return -EINVAL;
Chris Wang4c1f2c72024-03-21 17:09:44 +08001520 }
1521
Unive Tien71e935c2024-11-25 17:21:43 +08001522 return encode_pldm_header_only_errno(PLDM_REQUEST, instance_id,
1523 PLDM_FWUP,
1524 PLDM_QUERY_DOWNSTREAM_DEVICES,
1525 msg);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001526}
1527
Unive Tiene5c3f142024-12-13 14:14:19 +08001528LIBPLDM_ABI_STABLE
Chris Wang4c1f2c72024-03-21 17:09:44 +08001529int decode_query_downstream_devices_resp(
1530 const struct pldm_msg *msg, size_t payload_length,
1531 struct pldm_query_downstream_devices_resp *resp_data)
1532{
Andrew Jefferya1896962025-03-03 21:41:25 +10301533 PLDM_MSGBUF_DEFINE_P(buf);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001534 int rc;
1535
1536 if (msg == NULL || resp_data == NULL || !payload_length) {
Unive Tien71e935c2024-11-25 17:21:43 +08001537 return -EINVAL;
Chris Wang4c1f2c72024-03-21 17:09:44 +08001538 }
1539
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301540 rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1541 msg->payload, payload_length);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001542 if (rc) {
1543 return rc;
1544 }
1545
1546 rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1547 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301548 return pldm_msgbuf_discard(buf, rc);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001549 }
1550 if (PLDM_SUCCESS != resp_data->completion_code) {
1551 // Return the CC directly without decoding the rest of the payload
Andrew Jefferya1896962025-03-03 21:41:25 +10301552 return pldm_msgbuf_complete(buf);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001553 }
1554
1555 if (payload_length < PLDM_QUERY_DOWNSTREAM_DEVICES_RESP_BYTES) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301556 return pldm_msgbuf_discard(buf, -EBADMSG);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001557 }
1558
1559 rc = pldm_msgbuf_extract(buf,
1560 resp_data->downstream_device_update_supported);
1561 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301562 return pldm_msgbuf_discard(buf, rc);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001563 }
1564
1565 if (!is_downstream_device_update_support_valid(
1566 resp_data->downstream_device_update_supported)) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301567 return pldm_msgbuf_discard(buf, -EINVAL);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001568 }
1569
1570 pldm_msgbuf_extract(buf, resp_data->number_of_downstream_devices);
1571 pldm_msgbuf_extract(buf, resp_data->max_number_of_downstream_devices);
1572 pldm_msgbuf_extract(buf, resp_data->capabilities.value);
1573
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301574 return pldm_msgbuf_complete_consumed(buf);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001575}
1576
Unive Tiene5c3f142024-12-13 14:14:19 +08001577LIBPLDM_ABI_STABLE
Chris Wang458475a2024-03-26 17:59:19 +08001578int encode_query_downstream_identifiers_req(
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001579 uint8_t instance_id,
1580 const struct pldm_query_downstream_identifiers_req *params_req,
1581 struct pldm_msg *msg, size_t payload_length)
Chris Wang458475a2024-03-26 17:59:19 +08001582{
Andrew Jefferya1896962025-03-03 21:41:25 +10301583 PLDM_MSGBUF_DEFINE_P(buf);
Chris Wang458475a2024-03-26 17:59:19 +08001584 int rc;
1585
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001586 if (!msg || !params_req) {
Unive Tien71e935c2024-11-25 17:21:43 +08001587 return -EINVAL;
Chris Wang458475a2024-03-26 17:59:19 +08001588 }
1589
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001590 if (!is_transfer_operation_flag_valid(
1591 (enum transfer_op_flag)
1592 params_req->transfer_operation_flag)) {
Unive Tien71e935c2024-11-25 17:21:43 +08001593 return -EINVAL;
Chris Wang458475a2024-03-26 17:59:19 +08001594 }
1595
1596 struct pldm_header_info header = { 0 };
1597 header.instance = instance_id;
1598 header.msg_type = PLDM_REQUEST;
1599 header.pldm_type = PLDM_FWUP;
1600 header.command = PLDM_QUERY_DOWNSTREAM_IDENTIFIERS;
Unive Tien71e935c2024-11-25 17:21:43 +08001601 rc = pack_pldm_header_errno(&header, &(msg->hdr));
Chris Wang458475a2024-03-26 17:59:19 +08001602 if (rc) {
1603 return rc;
1604 }
1605
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301606 rc = pldm_msgbuf_init_errno(buf,
1607 PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_REQ_BYTES,
1608 msg->payload, payload_length);
Chris Wang458475a2024-03-26 17:59:19 +08001609 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001610 return rc;
Chris Wang458475a2024-03-26 17:59:19 +08001611 }
1612
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001613 pldm_msgbuf_insert(buf, params_req->data_transfer_handle);
Chris Wang458475a2024-03-26 17:59:19 +08001614 // Data correctness has been verified, cast it to 1-byte data directly.
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001615 pldm_msgbuf_insert(buf, params_req->transfer_operation_flag);
Chris Wang458475a2024-03-26 17:59:19 +08001616
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301617 return pldm_msgbuf_complete(buf);
Chris Wang458475a2024-03-26 17:59:19 +08001618}
1619
Unive Tiene5c3f142024-12-13 14:14:19 +08001620LIBPLDM_ABI_STABLE
Chris Wang458475a2024-03-26 17:59:19 +08001621int decode_query_downstream_identifiers_resp(
1622 const struct pldm_msg *msg, size_t payload_length,
1623 struct pldm_query_downstream_identifiers_resp *resp_data,
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301624 struct pldm_downstream_device_iter *iter)
Chris Wang458475a2024-03-26 17:59:19 +08001625{
Andrew Jefferya1896962025-03-03 21:41:25 +10301626 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301627 void *remaining = NULL;
Unive Tien71e935c2024-11-25 17:21:43 +08001628 int rc = 0;
Chris Wang458475a2024-03-26 17:59:19 +08001629
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301630 if (msg == NULL || resp_data == NULL || iter == NULL ||
Chris Wang458475a2024-03-26 17:59:19 +08001631 !payload_length) {
Unive Tien71e935c2024-11-25 17:21:43 +08001632 return -EINVAL;
Chris Wang458475a2024-03-26 17:59:19 +08001633 }
1634
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301635 rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1636 msg->payload, payload_length);
Chris Wang458475a2024-03-26 17:59:19 +08001637 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001638 return rc;
Chris Wang458475a2024-03-26 17:59:19 +08001639 }
1640
1641 rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1642 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301643 return pldm_msgbuf_discard(buf, rc);
Chris Wang458475a2024-03-26 17:59:19 +08001644 }
1645 if (PLDM_SUCCESS != resp_data->completion_code) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301646 return pldm_msgbuf_complete(buf);
Chris Wang458475a2024-03-26 17:59:19 +08001647 }
1648
1649 if (payload_length < PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_RESP_MIN_LEN) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301650 return pldm_msgbuf_discard(buf, -EBADMSG);
Chris Wang458475a2024-03-26 17:59:19 +08001651 }
1652
1653 pldm_msgbuf_extract(buf, resp_data->next_data_transfer_handle);
1654 pldm_msgbuf_extract(buf, resp_data->transfer_flag);
1655
1656 rc = pldm_msgbuf_extract(buf, resp_data->downstream_devices_length);
1657 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301658 return pldm_msgbuf_discard(buf, rc);
Chris Wang458475a2024-03-26 17:59:19 +08001659 }
1660
1661 pldm_msgbuf_extract(buf, resp_data->number_of_downstream_devices);
Andrew Jefferya1896962025-03-03 21:41:25 +10301662 pldm_msgbuf_span_required(buf, resp_data->downstream_devices_length,
1663 &remaining);
Chris Wang458475a2024-03-26 17:59:19 +08001664
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301665 rc = pldm_msgbuf_complete(buf);
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301666 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001667 return rc;
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301668 }
1669
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301670 iter->field.ptr = remaining;
1671 iter->field.length = resp_data->downstream_devices_length;
1672 iter->devs = resp_data->number_of_downstream_devices;
1673
Unive Tien71e935c2024-11-25 17:21:43 +08001674 return 0;
Chris Wang458475a2024-03-26 17:59:19 +08001675}
1676
Unive Tiene5c3f142024-12-13 14:14:19 +08001677LIBPLDM_ABI_STABLE
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301678int decode_pldm_downstream_device_from_iter(
1679 struct pldm_downstream_device_iter *iter,
1680 struct pldm_downstream_device *dev)
1681{
Andrew Jefferya1896962025-03-03 21:41:25 +10301682 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301683 int rc;
1684
Andrew Jefferya1896962025-03-03 21:41:25 +10301685 if (!iter || !iter->field.ptr || !dev) {
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301686 return -EINVAL;
1687 }
1688
1689 rc = pldm_msgbuf_init_errno(buf, 3, iter->field.ptr,
1690 iter->field.length);
1691 if (rc) {
1692 return rc;
1693 }
1694
1695 pldm_msgbuf_extract(buf, dev->downstream_device_index);
1696 pldm_msgbuf_extract(buf, dev->downstream_descriptor_count);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301697 pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
1698 &iter->field.length);
1699
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301700 return pldm_msgbuf_complete(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301701}
1702
Unive Tiene5c3f142024-12-13 14:14:19 +08001703LIBPLDM_ABI_STABLE
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301704int encode_get_downstream_firmware_parameters_req(
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001705 uint8_t instance_id,
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301706 const struct pldm_get_downstream_firmware_parameters_req *params_req,
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001707 struct pldm_msg *msg, size_t payload_length)
Chris Wangb6ef35b2024-07-03 09:35:42 +08001708{
Andrew Jefferya1896962025-03-03 21:41:25 +10301709 PLDM_MSGBUF_DEFINE_P(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001710 int rc;
1711
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001712 if (!msg || !params_req) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001713 return -EINVAL;
1714 }
1715
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001716 if (!is_transfer_operation_flag_valid(
1717 (enum transfer_op_flag)
1718 params_req->transfer_operation_flag)) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001719 return -EBADMSG;
1720 }
1721
1722 struct pldm_header_info header = { 0 };
1723 header.instance = instance_id;
1724 header.msg_type = PLDM_REQUEST;
1725 header.pldm_type = PLDM_FWUP;
1726 header.command = PLDM_QUERY_DOWNSTREAM_FIRMWARE_PARAMETERS;
1727 rc = pack_pldm_header_errno(&header, &msg->hdr);
1728 if (rc < 0) {
1729 return rc;
1730 }
1731
Andrew Jeffery53b08672025-03-04 12:26:18 +10301732 rc = pldm_msgbuf_init_errno(
1733 buf, PLDM_GET_DOWNSTREAM_FIRMWARE_PARAMETERS_REQ_BYTES,
1734 msg->payload, payload_length);
1735 if (rc < 0) {
1736 return rc;
1737 }
1738
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001739 pldm_msgbuf_insert(buf, params_req->data_transfer_handle);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001740 // Data correctness has been verified, cast it to 1-byte data directly.
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001741 pldm_msgbuf_insert(buf, params_req->transfer_operation_flag);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001742
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301743 return pldm_msgbuf_complete(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001744}
1745
Unive Tiene5c3f142024-12-13 14:14:19 +08001746LIBPLDM_ABI_STABLE
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301747int decode_get_downstream_firmware_parameters_resp(
Chris Wangb6ef35b2024-07-03 09:35:42 +08001748 const struct pldm_msg *msg, size_t payload_length,
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301749 struct pldm_get_downstream_firmware_parameters_resp *resp_data,
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301750 struct pldm_downstream_device_parameters_iter *iter)
Chris Wangb6ef35b2024-07-03 09:35:42 +08001751{
Andrew Jefferya1896962025-03-03 21:41:25 +10301752 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301753 void *remaining = NULL;
1754 size_t length;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001755 int rc;
1756
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301757 if (msg == NULL || resp_data == NULL || iter == NULL) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001758 return -EINVAL;
1759 }
1760
1761 rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1762 msg->payload, payload_length);
1763 if (rc < 0) {
1764 return rc;
1765 }
1766
1767 rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1768 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301769 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001770 }
1771 if (PLDM_SUCCESS != resp_data->completion_code) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301772 return pldm_msgbuf_complete(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001773 }
1774
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301775 if (payload_length <
1776 PLDM_GET_DOWNSTREAM_FIRMWARE_PARAMETERS_RESP_MIN_LEN) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301777 return pldm_msgbuf_discard(buf, -EBADMSG);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001778 }
1779
1780 pldm_msgbuf_extract(buf, resp_data->next_data_transfer_handle);
1781 pldm_msgbuf_extract(buf, resp_data->transfer_flag);
1782 pldm_msgbuf_extract(buf,
1783 resp_data->fdp_capabilities_during_update.value);
1784 pldm_msgbuf_extract(buf, resp_data->downstream_device_count);
1785
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301786 rc = pldm_msgbuf_span_remaining(buf, &remaining, &length);
1787 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301788 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301789 }
1790
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301791 rc = pldm_msgbuf_complete(buf);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301792 if (rc) {
1793 return rc;
1794 }
1795
1796 iter->field.ptr = remaining;
1797 iter->field.length = length;
1798 iter->entries = resp_data->downstream_device_count;
1799
1800 return 0;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001801}
1802
Unive Tiene5c3f142024-12-13 14:14:19 +08001803LIBPLDM_ABI_STABLE
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301804int decode_pldm_downstream_device_parameters_entry_from_iter(
1805 struct pldm_downstream_device_parameters_iter *iter,
1806 struct pldm_downstream_device_parameters_entry *entry)
Chris Wangb6ef35b2024-07-03 09:35:42 +08001807{
Andrew Jefferya1896962025-03-03 21:41:25 +10301808 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301809 void *comp_ver_str;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001810 size_t remaining;
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301811 void *cursor;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001812 int rc;
1813
Andrew Jefferya1896962025-03-03 21:41:25 +10301814 if (iter == NULL || iter->field.ptr == NULL || entry == NULL) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001815 return -EINVAL;
1816 }
1817
1818 rc = pldm_msgbuf_init_errno(
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301819 buf, PLDM_DOWNSTREAM_DEVICE_PARAMETERS_ENTRY_MIN_LEN,
1820 iter->field.ptr, iter->field.length);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001821 if (rc < 0) {
1822 return rc;
1823 }
1824
1825 pldm_msgbuf_extract(buf, entry->downstream_device_index);
1826 pldm_msgbuf_extract(buf, entry->active_comp_comparison_stamp);
1827 pldm_msgbuf_extract(buf, entry->active_comp_ver_str_type);
1828 rc = pldm_msgbuf_extract(buf, entry->active_comp_ver_str_len);
1829 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301830 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001831 }
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001832 rc = pldm_msgbuf_extract_array(buf,
1833 PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1834 entry->active_comp_release_date,
1835 sizeof(entry->active_comp_release_date));
1836 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301837 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001838 }
1839
Chris Wangb6ef35b2024-07-03 09:35:42 +08001840 // Fill the last byte with NULL character
1841 entry->active_comp_release_date[PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN] =
1842 '\0';
1843
1844 pldm_msgbuf_extract(buf, entry->pending_comp_comparison_stamp);
1845 pldm_msgbuf_extract(buf, entry->pending_comp_ver_str_type);
1846 rc = pldm_msgbuf_extract(buf, entry->pending_comp_ver_str_len);
1847 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301848 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001849 }
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001850
1851 rc = pldm_msgbuf_extract_array(
1852 buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1853 entry->pending_comp_release_date,
1854 sizeof(entry->pending_comp_release_date));
1855 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301856 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001857 }
1858
Chris Wangb6ef35b2024-07-03 09:35:42 +08001859 // Fill the last byte with NULL character
1860 entry->pending_comp_release_date[PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN] =
1861 '\0';
1862
1863 pldm_msgbuf_extract(buf, entry->comp_activation_methods.value);
1864 pldm_msgbuf_extract(buf, entry->capabilities_during_update.value);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001865
Andrew Jefferya1896962025-03-03 21:41:25 +10301866 rc = pldm_msgbuf_span_required(buf, entry->active_comp_ver_str_len,
1867 &comp_ver_str);
1868 if (rc < 0) {
1869 return pldm_msgbuf_discard(buf, rc);
1870 }
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301871 entry->active_comp_ver_str = comp_ver_str;
1872
Andrew Jefferya1896962025-03-03 21:41:25 +10301873 rc = pldm_msgbuf_span_required(buf, entry->pending_comp_ver_str_len,
1874 &comp_ver_str);
1875 if (rc < 0) {
1876 return pldm_msgbuf_discard(buf, rc);
1877 }
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301878 entry->pending_comp_ver_str = comp_ver_str;
1879
Chris Wangb6ef35b2024-07-03 09:35:42 +08001880 rc = pldm_msgbuf_span_remaining(buf, &cursor, &remaining);
1881 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301882 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001883 }
1884
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301885 iter->field.ptr = cursor;
1886 iter->field.length = remaining;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001887
Andrew Jefferya1896962025-03-03 21:41:25 +10301888 return pldm_msgbuf_complete(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001889}
1890
Sora Su06eadd02025-05-27 11:28:51 +08001891LIBPLDM_ABI_TESTING
1892int encode_request_downstream_device_update_req(
1893 uint8_t instance_id,
1894 const struct pldm_request_downstream_device_update_req *req_data,
1895 struct pldm_msg *msg, size_t *payload_length)
1896{
1897 PLDM_MSGBUF_DEFINE_P(buf);
1898 int rc;
1899
1900 if (!req_data || !msg || !payload_length ||
1901 req_data->maximum_downstream_device_transfer_size <
1902 PLDM_FWUP_BASELINE_TRANSFER_SIZE ||
1903 req_data->maximum_outstanding_transfer_requests <
1904 PLDM_FWUP_MIN_OUTSTANDING_REQ) {
1905 return -EINVAL;
1906 }
1907
1908 rc = encode_pldm_header_only_errno(
1909 PLDM_REQUEST, instance_id, PLDM_FWUP,
1910 PLDM_REQUEST_DOWNSTREAM_DEVICE_UPDATE, msg);
1911 if (rc) {
1912 return rc;
1913 }
1914
1915 rc = pldm_msgbuf_init_errno(buf,
1916 PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES,
1917 msg->payload, *payload_length);
1918 if (rc) {
1919 return rc;
1920 }
1921
1922 pldm_msgbuf_insert(buf,
1923 req_data->maximum_downstream_device_transfer_size);
1924 pldm_msgbuf_insert(buf,
1925 req_data->maximum_outstanding_transfer_requests);
1926 pldm_msgbuf_insert(buf,
1927 req_data->downstream_device_package_data_length);
1928
1929 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
1930}
1931
1932LIBPLDM_ABI_TESTING
1933int decode_request_downstream_device_update_req(
1934 const struct pldm_msg *msg, size_t payload_length,
1935 struct pldm_request_downstream_device_update_req *req)
1936{
1937 int rc;
1938 PLDM_MSGBUF_DEFINE_P(buf);
1939
1940 if (!msg || !req) {
1941 return -EINVAL;
1942 }
1943
1944 rc = pldm_msgbuf_init_errno(buf,
1945 PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES,
1946 msg->payload, payload_length);
1947 if (rc) {
1948 return rc;
1949 }
1950
1951 pldm_msgbuf_extract(buf, req->maximum_downstream_device_transfer_size);
1952 pldm_msgbuf_extract(buf, req->maximum_outstanding_transfer_requests);
1953 pldm_msgbuf_extract(buf, req->downstream_device_package_data_length);
1954
1955 return pldm_msgbuf_complete_consumed(buf);
1956}
1957
1958LIBPLDM_ABI_TESTING
1959int encode_request_downstream_device_update_resp(
1960 uint8_t instance_id,
1961 const struct pldm_request_downstream_device_update_resp *resp_data,
1962 struct pldm_msg *msg, size_t *payload_length)
1963{
1964 PLDM_MSGBUF_DEFINE_P(buf);
1965 int rc;
1966
1967 if (!resp_data || !msg || !payload_length) {
1968 return -EINVAL;
1969 }
1970
1971 rc = encode_pldm_header_only_errno(
1972 PLDM_RESPONSE, instance_id, PLDM_FWUP,
1973 PLDM_REQUEST_DOWNSTREAM_DEVICE_UPDATE, msg);
1974 if (rc) {
1975 return rc;
1976 }
1977
1978 rc = pldm_msgbuf_init_errno(
1979 buf, PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES, msg->payload,
1980 *payload_length);
1981 if (rc) {
1982 return rc;
1983 }
1984
1985 pldm_msgbuf_insert(buf, resp_data->completion_code);
1986 pldm_msgbuf_insert(buf, resp_data->downstream_device_meta_data_length);
1987 pldm_msgbuf_insert(
1988 buf, resp_data->downstream_device_will_send_get_package_data);
1989 pldm_msgbuf_insert(buf,
1990 resp_data->get_package_data_maximum_transfer_size);
1991
1992 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
1993}
1994
1995LIBPLDM_ABI_TESTING
1996int decode_request_downstream_device_update_resp(
1997 const struct pldm_msg *msg, size_t payload_length,
1998 struct pldm_request_downstream_device_update_resp *resp_data)
1999{
2000 PLDM_MSGBUF_DEFINE_P(buf);
2001 int rc;
2002
2003 if (!msg || !resp_data) {
2004 return -EINVAL;
2005 }
2006
2007 rc = pldm_msg_has_error(msg,
2008 PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES);
2009 if (rc) {
2010 resp_data->completion_code = rc;
2011 return 0;
2012 }
2013
2014 rc = pldm_msgbuf_init_errno(
2015 buf, PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES, msg->payload,
2016 payload_length);
2017 if (rc) {
2018 return rc;
2019 }
2020
2021 pldm_msgbuf_extract(buf, resp_data->completion_code);
2022 pldm_msgbuf_extract(buf, resp_data->downstream_device_meta_data_length);
2023 pldm_msgbuf_extract(
2024 buf, resp_data->downstream_device_will_send_get_package_data);
2025 pldm_msgbuf_extract(buf,
2026 resp_data->get_package_data_maximum_transfer_size);
2027
2028 return pldm_msgbuf_complete_consumed(buf);
2029}
2030
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302031LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302032int encode_request_update_req(uint8_t instance_id, uint32_t max_transfer_size,
2033 uint16_t num_of_comp,
2034 uint8_t max_outstanding_transfer_req,
2035 uint16_t pkg_data_len,
2036 uint8_t comp_image_set_ver_str_type,
2037 uint8_t comp_image_set_ver_str_len,
2038 const struct variable_field *comp_img_set_ver_str,
2039 struct pldm_msg *msg, size_t payload_length)
2040{
2041 if (comp_img_set_ver_str == NULL || comp_img_set_ver_str->ptr == NULL ||
2042 msg == NULL) {
2043 return PLDM_ERROR_INVALID_DATA;
2044 }
2045
2046 if (payload_length != sizeof(struct pldm_request_update_req) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302047 comp_img_set_ver_str->length) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302048 return PLDM_ERROR_INVALID_LENGTH;
2049 }
2050
2051 if ((comp_image_set_ver_str_len == 0) ||
2052 (comp_image_set_ver_str_len != comp_img_set_ver_str->length)) {
2053 return PLDM_ERROR_INVALID_DATA;
2054 }
2055
2056 if ((max_transfer_size < PLDM_FWUP_BASELINE_TRANSFER_SIZE) ||
2057 (max_outstanding_transfer_req < PLDM_FWUP_MIN_OUTSTANDING_REQ)) {
2058 return PLDM_ERROR_INVALID_DATA;
2059 }
2060
2061 if (!is_string_type_valid(comp_image_set_ver_str_type)) {
2062 return PLDM_ERROR_INVALID_DATA;
2063 }
2064
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302065 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302066 header.instance = instance_id;
2067 header.msg_type = PLDM_REQUEST;
2068 header.pldm_type = PLDM_FWUP;
2069 header.command = PLDM_REQUEST_UPDATE;
2070 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2071 if (rc) {
2072 return rc;
2073 }
2074
2075 struct pldm_request_update_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302076 (struct pldm_request_update_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302077
2078 request->max_transfer_size = htole32(max_transfer_size);
2079 request->num_of_comp = htole16(num_of_comp);
2080 request->max_outstanding_transfer_req = max_outstanding_transfer_req;
2081 request->pkg_data_len = htole16(pkg_data_len);
2082 request->comp_image_set_ver_str_type = comp_image_set_ver_str_type;
2083 request->comp_image_set_ver_str_len = comp_image_set_ver_str_len;
2084
2085 memcpy(msg->payload + sizeof(struct pldm_request_update_req),
2086 comp_img_set_ver_str->ptr, comp_img_set_ver_str->length);
2087
2088 return PLDM_SUCCESS;
2089}
2090
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002091LIBPLDM_ABI_TESTING
2092int decode_request_update_req(const struct pldm_msg *msg, size_t payload_length,
2093 struct pldm_request_update_req_full *req)
2094{
2095 int rc;
2096 uint8_t t;
Andrew Jefferya1896962025-03-03 21:41:25 +10302097 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002098
2099 if (msg == NULL || req == NULL) {
2100 return -EINVAL;
2101 }
2102
2103 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2104 if (rc) {
2105 return rc;
2106 }
2107
2108 pldm_msgbuf_extract(buf, req->max_transfer_size);
2109 pldm_msgbuf_extract(buf, req->num_of_comp);
2110 pldm_msgbuf_extract(buf, req->max_outstanding_transfer_req);
2111 pldm_msgbuf_extract(buf, req->pkg_data_len);
2112 rc = pldm_msgbuf_extract(buf, t);
2113 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302114 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002115 }
2116 if (t > PLDM_STR_TYPE_UTF_16BE) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302117 return pldm_msgbuf_discard(buf, -EBADMSG);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002118 }
2119 req->image_set_ver.str_type = (enum pldm_firmware_update_string_type)t;
2120 pldm_msgbuf_extract(buf, req->image_set_ver.str_len);
2121 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302122 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002123 }
2124
2125 rc = pldm_msgbuf_extract_array(buf, req->image_set_ver.str_len,
2126 req->image_set_ver.str_data,
2127 PLDM_FIRMWARE_MAX_STRING);
2128 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302129 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002130 }
2131
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302132 return pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002133}
2134
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302135LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302136int decode_request_update_resp(const struct pldm_msg *msg,
2137 size_t payload_length, uint8_t *completion_code,
2138 uint16_t *fd_meta_data_len,
2139 uint8_t *fd_will_send_pkg_data)
2140{
2141 if (msg == NULL || completion_code == NULL ||
2142 fd_meta_data_len == NULL || fd_will_send_pkg_data == NULL ||
2143 !payload_length) {
2144 return PLDM_ERROR_INVALID_DATA;
2145 }
2146
2147 *completion_code = msg->payload[0];
2148 if (*completion_code != PLDM_SUCCESS) {
2149 return PLDM_SUCCESS;
2150 }
2151
2152 if (payload_length != sizeof(struct pldm_request_update_resp)) {
2153 return PLDM_ERROR_INVALID_LENGTH;
2154 }
2155
2156 struct pldm_request_update_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302157 (struct pldm_request_update_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302158
2159 *fd_meta_data_len = le16toh(response->fd_meta_data_len);
2160 *fd_will_send_pkg_data = response->fd_will_send_pkg_data;
2161
2162 return PLDM_SUCCESS;
2163}
2164
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002165LIBPLDM_ABI_TESTING
2166int encode_request_update_resp(uint8_t instance_id,
2167 const struct pldm_request_update_resp *resp_data,
2168 struct pldm_msg *msg, size_t *payload_length)
2169{
Andrew Jefferya1896962025-03-03 21:41:25 +10302170 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002171 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002172
2173 if (msg == NULL || payload_length == NULL) {
2174 return -EINVAL;
2175 }
2176
2177 struct pldm_header_info header = {
2178 .instance = instance_id,
2179 .msg_type = PLDM_RESPONSE,
2180 .pldm_type = PLDM_FWUP,
2181 .command = PLDM_REQUEST_UPDATE,
2182 };
2183 rc = pack_pldm_header(&header, &(msg->hdr));
2184 if (rc) {
2185 return -EINVAL;
2186 }
2187
2188 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2189 if (rc) {
2190 return rc;
2191 }
2192
2193 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2194 pldm_msgbuf_insert(buf, resp_data->fd_meta_data_len);
2195 pldm_msgbuf_insert(buf, resp_data->fd_will_send_pkg_data);
2196
2197 /* TODO: DSP0267 1.3.0 adds GetPackageDataMaximumTransferSize */
2198
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302199 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002200}
2201
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302202LIBPLDM_ABI_STABLE
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302203int encode_pass_component_table_req(uint8_t instance_id, uint8_t transfer_flag,
2204 uint16_t comp_classification,
2205 uint16_t comp_identifier,
2206 uint8_t comp_classification_index,
2207 uint32_t comp_comparison_stamp,
2208 uint8_t comp_ver_str_type,
2209 uint8_t comp_ver_str_len,
2210 const struct variable_field *comp_ver_str,
2211 struct pldm_msg *msg, size_t payload_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09302212{
2213 if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) {
2214 return PLDM_ERROR_INVALID_DATA;
2215 }
2216
2217 if (payload_length != sizeof(struct pldm_pass_component_table_req) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302218 comp_ver_str->length) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302219 return PLDM_ERROR_INVALID_LENGTH;
2220 }
2221
2222 if ((comp_ver_str_len == 0) ||
2223 (comp_ver_str_len != comp_ver_str->length)) {
2224 return PLDM_ERROR_INVALID_DATA;
2225 }
2226
2227 if (!is_transfer_flag_valid(transfer_flag)) {
Manojkiran Eda3643e742025-05-19 12:03:54 +05302228 return PLDM_FWUP_INVALID_TRANSFER_OPERATION_FLAG;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302229 }
2230
2231 if (!is_string_type_valid(comp_ver_str_type)) {
2232 return PLDM_ERROR_INVALID_DATA;
2233 }
2234
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302235 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302236 header.instance = instance_id;
2237 header.msg_type = PLDM_REQUEST;
2238 header.pldm_type = PLDM_FWUP;
2239 header.command = PLDM_PASS_COMPONENT_TABLE;
2240 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2241 if (rc) {
2242 return rc;
2243 }
2244
2245 struct pldm_pass_component_table_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302246 (struct pldm_pass_component_table_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302247
2248 request->transfer_flag = transfer_flag;
2249 request->comp_classification = htole16(comp_classification);
2250 request->comp_identifier = htole16(comp_identifier);
2251 request->comp_classification_index = comp_classification_index;
2252 request->comp_comparison_stamp = htole32(comp_comparison_stamp);
2253 request->comp_ver_str_type = comp_ver_str_type;
2254 request->comp_ver_str_len = comp_ver_str_len;
2255
2256 memcpy(msg->payload + sizeof(struct pldm_pass_component_table_req),
2257 comp_ver_str->ptr, comp_ver_str->length);
2258
2259 return PLDM_SUCCESS;
2260}
2261
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002262LIBPLDM_ABI_TESTING
2263int decode_pass_component_table_req(
2264 const struct pldm_msg *msg, size_t payload_length,
2265 struct pldm_pass_component_table_req_full *pcomp)
2266{
2267 int rc;
2268 uint8_t t;
Andrew Jefferya1896962025-03-03 21:41:25 +10302269 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002270
2271 if (msg == NULL || pcomp == NULL) {
2272 return -EINVAL;
2273 }
2274
2275 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2276 if (rc) {
2277 return rc;
2278 }
2279
2280 pldm_msgbuf_extract(buf, pcomp->transfer_flag);
2281 pldm_msgbuf_extract(buf, pcomp->comp_classification);
2282 pldm_msgbuf_extract(buf, pcomp->comp_identifier);
2283 pldm_msgbuf_extract(buf, pcomp->comp_classification_index);
2284 pldm_msgbuf_extract(buf, pcomp->comp_comparison_stamp);
2285 rc = pldm_msgbuf_extract(buf, t);
2286 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302287 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002288 }
2289 if (t > PLDM_STR_TYPE_UTF_16BE) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302290 return pldm_msgbuf_discard(buf, -EBADMSG);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002291 }
2292 pcomp->version.str_type = (enum pldm_firmware_update_string_type)t;
2293 rc = pldm_msgbuf_extract(buf, pcomp->version.str_len);
2294 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302295 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002296 }
2297 rc = pldm_msgbuf_extract_array(buf, pcomp->version.str_len,
2298 pcomp->version.str_data,
2299 PLDM_FIRMWARE_MAX_STRING);
2300 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302301 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002302 }
2303
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302304 return pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002305}
2306
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302307LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302308int decode_pass_component_table_resp(const struct pldm_msg *msg,
2309 const size_t payload_length,
2310 uint8_t *completion_code,
2311 uint8_t *comp_resp,
2312 uint8_t *comp_resp_code)
2313{
2314 if (msg == NULL || completion_code == NULL || comp_resp == NULL ||
2315 comp_resp_code == NULL || !payload_length) {
2316 return PLDM_ERROR_INVALID_DATA;
2317 }
2318
2319 *completion_code = msg->payload[0];
2320 if (*completion_code != PLDM_SUCCESS) {
2321 return PLDM_SUCCESS;
2322 }
2323
2324 if (payload_length != sizeof(struct pldm_pass_component_table_resp)) {
2325 return PLDM_ERROR_INVALID_LENGTH;
2326 }
2327
2328 struct pldm_pass_component_table_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302329 (struct pldm_pass_component_table_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302330
2331 if (!is_comp_resp_valid(response->comp_resp)) {
2332 return PLDM_ERROR_INVALID_DATA;
2333 }
2334
2335 if (!is_comp_resp_code_valid(response->comp_resp_code)) {
2336 return PLDM_ERROR_INVALID_DATA;
2337 }
2338
2339 *comp_resp = response->comp_resp;
2340 *comp_resp_code = response->comp_resp_code;
2341
2342 return PLDM_SUCCESS;
2343}
2344
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002345LIBPLDM_ABI_TESTING
2346int encode_pass_component_table_resp(
2347 uint8_t instance_id,
2348 const struct pldm_pass_component_table_resp *resp_data,
2349 struct pldm_msg *msg, size_t *payload_length)
2350{
Andrew Jefferya1896962025-03-03 21:41:25 +10302351 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002352 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002353
2354 if (msg == NULL || payload_length == NULL) {
2355 return -EINVAL;
2356 }
2357
2358 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2359 PLDM_PASS_COMPONENT_TABLE, msg);
2360 if (rc) {
2361 return -EINVAL;
2362 }
2363
2364 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2365 if (rc) {
2366 return rc;
2367 }
2368
2369 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2370 pldm_msgbuf_insert(buf, resp_data->comp_resp);
2371 pldm_msgbuf_insert(buf, resp_data->comp_resp_code);
2372
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302373 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002374}
2375
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302376LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302377int encode_update_component_req(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302378 uint8_t instance_id, uint16_t comp_classification,
2379 uint16_t comp_identifier, uint8_t comp_classification_index,
2380 uint32_t comp_comparison_stamp, uint32_t comp_image_size,
2381 bitfield32_t update_option_flags, uint8_t comp_ver_str_type,
2382 uint8_t comp_ver_str_len, const struct variable_field *comp_ver_str,
2383 struct pldm_msg *msg, size_t payload_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09302384{
2385 if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) {
2386 return PLDM_ERROR_INVALID_DATA;
2387 }
2388
2389 if (payload_length !=
2390 sizeof(struct pldm_update_component_req) + comp_ver_str->length) {
2391 return PLDM_ERROR_INVALID_LENGTH;
2392 }
2393
2394 if (!comp_image_size) {
2395 return PLDM_ERROR_INVALID_DATA;
2396 }
2397
2398 if ((comp_ver_str_len == 0) ||
2399 (comp_ver_str_len != comp_ver_str->length)) {
2400 return PLDM_ERROR_INVALID_DATA;
2401 }
2402
2403 if (!is_string_type_valid(comp_ver_str_type)) {
2404 return PLDM_ERROR_INVALID_DATA;
2405 }
2406
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302407 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302408 header.instance = instance_id;
2409 header.msg_type = PLDM_REQUEST;
2410 header.pldm_type = PLDM_FWUP;
2411 header.command = PLDM_UPDATE_COMPONENT;
2412 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2413 if (rc) {
2414 return rc;
2415 }
2416
2417 struct pldm_update_component_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302418 (struct pldm_update_component_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302419
2420 request->comp_classification = htole16(comp_classification);
2421 request->comp_identifier = htole16(comp_identifier);
2422 request->comp_classification_index = comp_classification_index;
2423 request->comp_comparison_stamp = htole32(comp_comparison_stamp);
2424 request->comp_image_size = htole32(comp_image_size);
2425 request->update_option_flags.value = htole32(update_option_flags.value);
2426 request->comp_ver_str_type = comp_ver_str_type;
2427 request->comp_ver_str_len = comp_ver_str_len;
2428
2429 memcpy(msg->payload + sizeof(struct pldm_update_component_req),
2430 comp_ver_str->ptr, comp_ver_str->length);
2431
2432 return PLDM_SUCCESS;
2433}
2434
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002435LIBPLDM_ABI_TESTING
2436int decode_update_component_req(const struct pldm_msg *msg,
2437 size_t payload_length,
2438 struct pldm_update_component_req_full *up)
2439{
2440 int rc;
2441 uint8_t t;
Andrew Jefferya1896962025-03-03 21:41:25 +10302442 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002443
2444 if (msg == NULL || up == NULL) {
2445 return -EINVAL;
2446 }
2447
2448 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2449 if (rc) {
2450 return rc;
2451 }
2452
2453 pldm_msgbuf_extract(buf, up->comp_classification);
2454 pldm_msgbuf_extract(buf, up->comp_identifier);
2455 pldm_msgbuf_extract(buf, up->comp_classification_index);
2456 pldm_msgbuf_extract(buf, up->comp_comparison_stamp);
2457 pldm_msgbuf_extract(buf, up->comp_image_size);
2458 pldm_msgbuf_extract(buf, up->update_option_flags.value);
2459 rc = pldm_msgbuf_extract(buf, t);
2460 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302461 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002462 }
2463 if (t > PLDM_STR_TYPE_UTF_16BE) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302464 return pldm_msgbuf_discard(buf, -EBADMSG);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002465 }
2466 up->version.str_type = (enum pldm_firmware_update_string_type)t;
2467 rc = pldm_msgbuf_extract(buf, up->version.str_len);
2468 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302469 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002470 }
2471 rc = pldm_msgbuf_extract_array(buf, up->version.str_len,
2472 up->version.str_data,
2473 PLDM_FIRMWARE_MAX_STRING);
2474 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302475 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002476 }
2477
Andrew Jefferya1896962025-03-03 21:41:25 +10302478 return pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002479}
2480
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302481LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302482int decode_update_component_resp(const struct pldm_msg *msg,
2483 size_t payload_length,
2484 uint8_t *completion_code,
2485 uint8_t *comp_compatibility_resp,
2486 uint8_t *comp_compatibility_resp_code,
2487 bitfield32_t *update_option_flags_enabled,
2488 uint16_t *time_before_req_fw_data)
2489{
2490 if (msg == NULL || completion_code == NULL ||
2491 comp_compatibility_resp == NULL ||
2492 comp_compatibility_resp_code == NULL ||
2493 update_option_flags_enabled == NULL ||
2494 time_before_req_fw_data == NULL || !payload_length) {
2495 return PLDM_ERROR_INVALID_DATA;
2496 }
2497
2498 *completion_code = msg->payload[0];
2499 if (*completion_code != PLDM_SUCCESS) {
2500 return PLDM_SUCCESS;
2501 }
2502
2503 if (payload_length != sizeof(struct pldm_update_component_resp)) {
2504 return PLDM_ERROR_INVALID_LENGTH;
2505 }
2506
2507 struct pldm_update_component_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302508 (struct pldm_update_component_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302509
2510 if (!is_comp_compatibility_resp_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302511 response->comp_compatibility_resp)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302512 return PLDM_ERROR_INVALID_DATA;
2513 }
2514
2515 if (!is_comp_compatibility_resp_code_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302516 response->comp_compatibility_resp_code)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302517 return PLDM_ERROR_INVALID_DATA;
2518 }
2519
2520 *comp_compatibility_resp = response->comp_compatibility_resp;
2521 *comp_compatibility_resp_code = response->comp_compatibility_resp_code;
2522 update_option_flags_enabled->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302523 le32toh(response->update_option_flags_enabled.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302524 *time_before_req_fw_data = le16toh(response->time_before_req_fw_data);
2525
2526 return PLDM_SUCCESS;
2527}
2528
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002529LIBPLDM_ABI_TESTING
2530int encode_update_component_resp(
2531 uint8_t instance_id, const struct pldm_update_component_resp *resp_data,
2532 struct pldm_msg *msg, size_t *payload_length)
2533{
Andrew Jefferya1896962025-03-03 21:41:25 +10302534 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002535 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002536
2537 if (msg == NULL || payload_length == NULL) {
2538 return -EINVAL;
2539 }
2540
2541 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2542 PLDM_UPDATE_COMPONENT, msg);
2543 if (rc) {
2544 return -EINVAL;
2545 }
2546
2547 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2548 if (rc) {
2549 return rc;
2550 }
2551
2552 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2553 pldm_msgbuf_insert(buf, resp_data->comp_compatibility_resp);
2554 pldm_msgbuf_insert(buf, resp_data->comp_compatibility_resp_code);
2555 pldm_msgbuf_insert(buf, resp_data->update_option_flags_enabled.value);
2556 pldm_msgbuf_insert(buf, resp_data->time_before_req_fw_data);
2557
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302558 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002559}
2560
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302561LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302562int decode_request_firmware_data_req(const struct pldm_msg *msg,
2563 size_t payload_length, uint32_t *offset,
2564 uint32_t *length)
2565{
2566 if (msg == NULL || offset == NULL || length == NULL) {
2567 return PLDM_ERROR_INVALID_DATA;
2568 }
2569 if (payload_length != sizeof(struct pldm_request_firmware_data_req)) {
2570 return PLDM_ERROR_INVALID_LENGTH;
2571 }
2572 struct pldm_request_firmware_data_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302573 (struct pldm_request_firmware_data_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302574 *offset = le32toh(request->offset);
2575 *length = le32toh(request->length);
2576
2577 if (*length < PLDM_FWUP_BASELINE_TRANSFER_SIZE) {
2578 return PLDM_FWUP_INVALID_TRANSFER_LENGTH;
2579 }
2580
2581 return PLDM_SUCCESS;
2582}
2583
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002584LIBPLDM_ABI_TESTING
2585int encode_request_firmware_data_req(
2586 uint8_t instance_id,
2587 const struct pldm_request_firmware_data_req *req_params,
2588 struct pldm_msg *msg, size_t *payload_length)
2589{
Andrew Jefferya1896962025-03-03 21:41:25 +10302590 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002591 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002592
2593 if (msg == NULL || payload_length == NULL) {
2594 return -EINVAL;
2595 }
2596
2597 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2598 PLDM_REQUEST_FIRMWARE_DATA, msg);
2599 if (rc) {
2600 return -EINVAL;
2601 }
2602
2603 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2604 if (rc) {
2605 return rc;
2606 }
2607
2608 pldm_msgbuf_insert(buf, req_params->offset);
2609 pldm_msgbuf_insert(buf, req_params->length);
2610
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302611 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002612}
2613
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302614LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302615int encode_request_firmware_data_resp(uint8_t instance_id,
2616 uint8_t completion_code,
2617 struct pldm_msg *msg,
2618 size_t payload_length)
2619{
2620 if (msg == NULL || !payload_length) {
2621 return PLDM_ERROR_INVALID_DATA;
2622 }
2623
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302624 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302625 header.instance = instance_id;
2626 header.msg_type = PLDM_RESPONSE;
2627 header.pldm_type = PLDM_FWUP;
2628 header.command = PLDM_REQUEST_FIRMWARE_DATA;
2629 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2630 if (rc) {
2631 return rc;
2632 }
2633
2634 msg->payload[0] = completion_code;
2635
2636 return PLDM_SUCCESS;
2637}
2638
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302639LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302640int decode_transfer_complete_req(const struct pldm_msg *msg,
2641 size_t payload_length,
2642 uint8_t *transfer_result)
2643{
2644 if (msg == NULL || transfer_result == NULL) {
2645 return PLDM_ERROR_INVALID_DATA;
2646 }
2647
2648 if (payload_length != sizeof(*transfer_result)) {
2649 return PLDM_ERROR_INVALID_LENGTH;
2650 }
2651
2652 *transfer_result = msg->payload[0];
2653 return PLDM_SUCCESS;
2654}
2655
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002656LIBPLDM_ABI_TESTING
2657int encode_transfer_complete_req(uint8_t instance_id, uint8_t transfer_result,
2658 struct pldm_msg *msg, size_t *payload_length)
2659{
Andrew Jefferya1896962025-03-03 21:41:25 +10302660 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002661 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002662
2663 if (msg == NULL || payload_length == NULL) {
2664 return -EINVAL;
2665 }
2666
2667 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2668 PLDM_TRANSFER_COMPLETE, msg);
2669 if (rc) {
2670 return -EINVAL;
2671 }
2672
2673 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2674 if (rc) {
2675 return rc;
2676 }
2677
Andrew Jefferya1896962025-03-03 21:41:25 +10302678 pldm_msgbuf_insert(buf, transfer_result);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002679
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302680 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002681}
2682
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302683LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302684int encode_transfer_complete_resp(uint8_t instance_id, uint8_t completion_code,
2685 struct pldm_msg *msg, size_t payload_length)
2686{
2687 if (msg == NULL) {
2688 return PLDM_ERROR_INVALID_DATA;
2689 }
2690
2691 if (payload_length != sizeof(completion_code)) {
2692 return PLDM_ERROR_INVALID_LENGTH;
2693 }
2694
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302695 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302696 header.instance = instance_id;
2697 header.msg_type = PLDM_RESPONSE;
2698 header.pldm_type = PLDM_FWUP;
2699 header.command = PLDM_TRANSFER_COMPLETE;
2700 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2701 if (rc) {
2702 return rc;
2703 }
2704
2705 msg->payload[0] = completion_code;
2706
2707 return PLDM_SUCCESS;
2708}
2709
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302710LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302711int decode_verify_complete_req(const struct pldm_msg *msg,
2712 size_t payload_length, uint8_t *verify_result)
2713{
2714 if (msg == NULL || verify_result == NULL) {
2715 return PLDM_ERROR_INVALID_DATA;
2716 }
2717
2718 if (payload_length != sizeof(*verify_result)) {
2719 return PLDM_ERROR_INVALID_LENGTH;
2720 }
2721
2722 *verify_result = msg->payload[0];
2723 return PLDM_SUCCESS;
2724}
2725
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002726LIBPLDM_ABI_TESTING
2727int encode_verify_complete_req(uint8_t instance_id, uint8_t verify_result,
2728 struct pldm_msg *msg, size_t *payload_length)
2729{
Andrew Jefferya1896962025-03-03 21:41:25 +10302730 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002731 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002732
2733 if (msg == NULL || payload_length == NULL) {
2734 return -EINVAL;
2735 }
2736
2737 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2738 PLDM_VERIFY_COMPLETE, msg);
2739 if (rc) {
2740 return EINVAL;
2741 }
2742
2743 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2744 if (rc) {
2745 return rc;
2746 }
2747
Andrew Jefferya1896962025-03-03 21:41:25 +10302748 pldm_msgbuf_insert(buf, verify_result);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002749
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302750 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002751}
2752
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302753LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302754int encode_verify_complete_resp(uint8_t instance_id, uint8_t completion_code,
2755 struct pldm_msg *msg, size_t payload_length)
2756{
2757 if (msg == NULL) {
2758 return PLDM_ERROR_INVALID_DATA;
2759 }
2760
2761 if (payload_length != sizeof(completion_code)) {
2762 return PLDM_ERROR_INVALID_LENGTH;
2763 }
2764
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302765 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302766 header.instance = instance_id;
2767 header.msg_type = PLDM_RESPONSE;
2768 header.pldm_type = PLDM_FWUP;
2769 header.command = PLDM_VERIFY_COMPLETE;
2770 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2771 if (rc) {
2772 return rc;
2773 }
2774
2775 msg->payload[0] = completion_code;
2776
2777 return PLDM_SUCCESS;
2778}
2779
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302780LIBPLDM_ABI_STABLE
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302781int decode_apply_complete_req(const struct pldm_msg *msg, size_t payload_length,
2782 uint8_t *apply_result,
2783 bitfield16_t *comp_activation_methods_modification)
Andrew Jeffery9c766792022-08-10 23:12:49 +09302784{
2785 if (msg == NULL || apply_result == NULL ||
2786 comp_activation_methods_modification == NULL) {
2787 return PLDM_ERROR_INVALID_DATA;
2788 }
2789
2790 if (payload_length != sizeof(struct pldm_apply_complete_req)) {
2791 return PLDM_ERROR_INVALID_LENGTH;
2792 }
2793
2794 struct pldm_apply_complete_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302795 (struct pldm_apply_complete_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302796
2797 *apply_result = request->apply_result;
2798 comp_activation_methods_modification->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302799 le16toh(request->comp_activation_methods_modification.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302800
2801 if ((*apply_result != PLDM_FWUP_APPLY_SUCCESS_WITH_ACTIVATION_METHOD) &&
2802 comp_activation_methods_modification->value) {
2803 return PLDM_ERROR_INVALID_DATA;
2804 }
2805
2806 return PLDM_SUCCESS;
2807}
2808
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002809LIBPLDM_ABI_TESTING
2810int encode_apply_complete_req(uint8_t instance_id,
2811 const struct pldm_apply_complete_req *req_data,
2812 struct pldm_msg *msg, size_t *payload_length)
2813{
Andrew Jefferya1896962025-03-03 21:41:25 +10302814 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002815 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002816
2817 if (msg == NULL || payload_length == NULL) {
2818 return -EINVAL;
2819 }
2820
2821 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2822 PLDM_APPLY_COMPLETE, msg);
2823 if (rc) {
2824 return -EINVAL;
2825 }
2826
2827 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2828 if (rc) {
2829 return rc;
2830 }
2831
2832 pldm_msgbuf_insert(buf, req_data->apply_result);
2833 pldm_msgbuf_insert(
2834 buf, req_data->comp_activation_methods_modification.value);
2835
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302836 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002837}
2838
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302839LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302840int encode_apply_complete_resp(uint8_t instance_id, uint8_t completion_code,
2841 struct pldm_msg *msg, size_t payload_length)
2842{
2843 if (msg == NULL) {
2844 return PLDM_ERROR_INVALID_DATA;
2845 }
2846
2847 if (payload_length != sizeof(completion_code)) {
2848 return PLDM_ERROR_INVALID_LENGTH;
2849 }
2850
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302851 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302852 header.instance = instance_id;
2853 header.msg_type = PLDM_RESPONSE;
2854 header.pldm_type = PLDM_FWUP;
2855 header.command = PLDM_APPLY_COMPLETE;
2856 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2857 if (rc) {
2858 return rc;
2859 }
2860
2861 msg->payload[0] = completion_code;
2862
2863 return PLDM_SUCCESS;
2864}
2865
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002866LIBPLDM_ABI_TESTING
2867int decode_activate_firmware_req(const struct pldm_msg *msg,
2868 size_t payload_length, bool *self_contained)
2869{
Andrew Jefferya1896962025-03-03 21:41:25 +10302870 uint8_t self_contained_u8 = 0;
2871 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002872 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002873
2874 if (msg == NULL || self_contained == NULL) {
2875 return -EINVAL;
2876 }
2877
2878 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2879 if (rc) {
2880 return 0;
2881 }
2882
Andrew Jefferya1896962025-03-03 21:41:25 +10302883 pldm_msgbuf_extract(buf, self_contained_u8);
2884
2885 rc = pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002886 if (rc) {
2887 return rc;
2888 }
Andrew Jefferya1896962025-03-03 21:41:25 +10302889
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002890 *self_contained = (bool)self_contained_u8;
2891 return 0;
2892}
2893
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302894LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302895int encode_activate_firmware_req(uint8_t instance_id,
2896 bool8_t self_contained_activation_req,
2897 struct pldm_msg *msg, size_t payload_length)
2898{
2899 if (msg == NULL) {
2900 return PLDM_ERROR_INVALID_DATA;
2901 }
2902
2903 if (payload_length != sizeof(struct pldm_activate_firmware_req)) {
2904 return PLDM_ERROR_INVALID_LENGTH;
2905 }
2906
2907 if (!is_self_contained_activation_req_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302908 self_contained_activation_req)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302909 return PLDM_ERROR_INVALID_DATA;
2910 }
2911
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302912 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302913 header.instance = instance_id;
2914 header.msg_type = PLDM_REQUEST;
2915 header.pldm_type = PLDM_FWUP;
2916 header.command = PLDM_ACTIVATE_FIRMWARE;
2917 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2918 if (rc) {
2919 return rc;
2920 }
2921
2922 struct pldm_activate_firmware_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302923 (struct pldm_activate_firmware_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302924
2925 request->self_contained_activation_req = self_contained_activation_req;
2926
2927 return PLDM_SUCCESS;
2928}
2929
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302930LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302931int decode_activate_firmware_resp(const struct pldm_msg *msg,
2932 size_t payload_length,
2933 uint8_t *completion_code,
2934 uint16_t *estimated_time_activation)
2935{
2936 if (msg == NULL || completion_code == NULL ||
2937 estimated_time_activation == NULL || !payload_length) {
2938 return PLDM_ERROR_INVALID_DATA;
2939 }
2940
2941 *completion_code = msg->payload[0];
2942 if (*completion_code != PLDM_SUCCESS) {
2943 return PLDM_SUCCESS;
2944 }
2945
2946 if (payload_length != sizeof(struct pldm_activate_firmware_resp)) {
2947 return PLDM_ERROR_INVALID_LENGTH;
2948 }
2949
2950 struct pldm_activate_firmware_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302951 (struct pldm_activate_firmware_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302952
2953 *estimated_time_activation =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302954 le16toh(response->estimated_time_activation);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302955
2956 return PLDM_SUCCESS;
2957}
2958
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002959LIBPLDM_ABI_TESTING
2960int encode_activate_firmware_resp(
2961 uint8_t instance_id,
2962 const struct pldm_activate_firmware_resp *resp_data,
2963 struct pldm_msg *msg, size_t *payload_length)
2964{
Andrew Jefferya1896962025-03-03 21:41:25 +10302965 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002966 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002967
2968 if (msg == NULL || payload_length == NULL) {
2969 return -EINVAL;
2970 }
2971
2972 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2973 PLDM_ACTIVATE_FIRMWARE, msg);
2974 if (rc) {
2975 return -EINVAL;
2976 }
2977
2978 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2979 if (rc) {
2980 return rc;
2981 }
2982
2983 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2984 pldm_msgbuf_insert(buf, resp_data->estimated_time_activation);
2985
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302986 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002987}
2988
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302989LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302990int encode_get_status_req(uint8_t instance_id, struct pldm_msg *msg,
2991 size_t payload_length)
2992{
2993 if (msg == NULL) {
2994 return PLDM_ERROR_INVALID_DATA;
2995 }
2996
2997 if (payload_length != PLDM_GET_STATUS_REQ_BYTES) {
2998 return PLDM_ERROR_INVALID_LENGTH;
2999 }
3000
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303001 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09303002 header.instance = instance_id;
3003 header.msg_type = PLDM_REQUEST;
3004 header.pldm_type = PLDM_FWUP;
3005 header.command = PLDM_GET_STATUS;
3006 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
3007 if (rc) {
3008 return rc;
3009 }
3010
3011 return PLDM_SUCCESS;
3012}
3013
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09303014LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09303015int decode_get_status_resp(const struct pldm_msg *msg, size_t payload_length,
3016 uint8_t *completion_code, uint8_t *current_state,
3017 uint8_t *previous_state, uint8_t *aux_state,
3018 uint8_t *aux_state_status, uint8_t *progress_percent,
3019 uint8_t *reason_code,
3020 bitfield32_t *update_option_flags_enabled)
3021{
3022 if (msg == NULL || completion_code == NULL || current_state == NULL ||
3023 previous_state == NULL || aux_state == NULL ||
3024 aux_state_status == NULL || progress_percent == NULL ||
3025 reason_code == NULL || update_option_flags_enabled == NULL ||
3026 !payload_length) {
3027 return PLDM_ERROR_INVALID_DATA;
3028 }
3029
3030 *completion_code = msg->payload[0];
3031 if (*completion_code != PLDM_SUCCESS) {
3032 return PLDM_SUCCESS;
3033 }
3034
3035 if (payload_length != sizeof(struct pldm_get_status_resp)) {
3036 return PLDM_ERROR_INVALID_LENGTH;
3037 }
3038 struct pldm_get_status_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303039 (struct pldm_get_status_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09303040
3041 if (!is_state_valid(response->current_state)) {
3042 return PLDM_ERROR_INVALID_DATA;
3043 }
3044 if (!is_state_valid(response->previous_state)) {
3045 return PLDM_ERROR_INVALID_DATA;
3046 }
3047 if (!is_aux_state_valid(response->aux_state)) {
3048 return PLDM_ERROR_INVALID_DATA;
3049 }
3050 if (!is_aux_state_status_valid(response->aux_state_status)) {
3051 return PLDM_ERROR_INVALID_DATA;
3052 }
3053 if (response->progress_percent > PLDM_FWUP_MAX_PROGRESS_PERCENT) {
3054 return PLDM_ERROR_INVALID_DATA;
3055 }
3056 if (!is_reason_code_valid(response->reason_code)) {
3057 return PLDM_ERROR_INVALID_DATA;
3058 }
3059
3060 if ((response->current_state == PLDM_FD_STATE_IDLE) ||
3061 (response->current_state == PLDM_FD_STATE_LEARN_COMPONENTS) ||
3062 (response->current_state == PLDM_FD_STATE_READY_XFER)) {
3063 if (response->aux_state !=
3064 PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER) {
3065 return PLDM_ERROR_INVALID_DATA;
3066 }
3067 }
3068
3069 *current_state = response->current_state;
3070 *previous_state = response->previous_state;
3071 *aux_state = response->aux_state;
3072 *aux_state_status = response->aux_state_status;
3073 *progress_percent = response->progress_percent;
3074 *reason_code = response->reason_code;
3075 update_option_flags_enabled->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303076 le32toh(response->update_option_flags_enabled.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09303077
3078 return PLDM_SUCCESS;
3079}
3080
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003081LIBPLDM_ABI_TESTING
3082int encode_get_status_resp(uint8_t instance_id,
3083 const struct pldm_get_status_resp *status,
3084 struct pldm_msg *msg, size_t *payload_length)
3085{
Andrew Jefferya1896962025-03-03 21:41:25 +10303086 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003087 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003088
3089 if (status == NULL || msg == NULL || payload_length == NULL) {
3090 return -EINVAL;
3091 }
3092
3093 if (status->completion_code != PLDM_SUCCESS) {
3094 return -EINVAL;
3095 }
3096
3097 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
3098 PLDM_GET_STATUS, msg);
3099 if (rc) {
3100 return -EINVAL;
3101 }
3102
3103 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
3104 if (rc) {
3105 return rc;
3106 }
3107
3108 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
3109 pldm_msgbuf_insert(buf, status->current_state);
3110 pldm_msgbuf_insert(buf, status->previous_state);
3111 pldm_msgbuf_insert(buf, status->aux_state);
3112 pldm_msgbuf_insert(buf, status->aux_state_status);
3113 pldm_msgbuf_insert(buf, status->progress_percent);
3114 pldm_msgbuf_insert(buf, status->reason_code);
3115 pldm_msgbuf_insert(buf, status->update_option_flags_enabled.value);
3116
Andrew Jeffery70d21c92025-03-05 12:59:42 +10303117 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003118}
3119
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09303120LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09303121int encode_cancel_update_component_req(uint8_t instance_id,
3122 struct pldm_msg *msg,
3123 size_t payload_length)
3124{
3125 if (msg == NULL) {
3126 return PLDM_ERROR_INVALID_DATA;
3127 }
3128
3129 if (payload_length != PLDM_CANCEL_UPDATE_COMPONENT_REQ_BYTES) {
3130 return PLDM_ERROR_INVALID_LENGTH;
3131 }
3132
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303133 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09303134 header.instance = instance_id;
3135 header.msg_type = PLDM_REQUEST;
3136 header.pldm_type = PLDM_FWUP;
3137 header.command = PLDM_CANCEL_UPDATE_COMPONENT;
3138 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
3139 if (rc) {
3140 return rc;
3141 }
3142
3143 return PLDM_SUCCESS;
3144}
3145
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09303146LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09303147int decode_cancel_update_component_resp(const struct pldm_msg *msg,
3148 size_t payload_length,
3149 uint8_t *completion_code)
3150{
3151 if (msg == NULL || completion_code == NULL) {
3152 return PLDM_ERROR_INVALID_DATA;
3153 }
3154
3155 if (payload_length != sizeof(*completion_code)) {
3156 return PLDM_ERROR_INVALID_LENGTH;
3157 }
3158
3159 *completion_code = msg->payload[0];
3160 return PLDM_SUCCESS;
3161}
3162
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09303163LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09303164int encode_cancel_update_req(uint8_t instance_id, struct pldm_msg *msg,
3165 size_t payload_length)
3166{
3167 if (msg == NULL) {
3168 return PLDM_ERROR_INVALID_DATA;
3169 }
3170
3171 if (payload_length != PLDM_CANCEL_UPDATE_REQ_BYTES) {
3172 return PLDM_ERROR_INVALID_LENGTH;
3173 }
3174
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303175 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09303176 header.instance = instance_id;
3177 header.msg_type = PLDM_REQUEST;
3178 header.pldm_type = PLDM_FWUP;
3179 header.command = PLDM_CANCEL_UPDATE;
3180 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
3181 if (rc) {
3182 return rc;
3183 }
3184
3185 return PLDM_SUCCESS;
3186}
3187
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09303188LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09303189int decode_cancel_update_resp(const struct pldm_msg *msg, size_t payload_length,
3190 uint8_t *completion_code,
3191 bool8_t *non_functioning_component_indication,
3192 bitfield64_t *non_functioning_component_bitmap)
3193{
3194 if (msg == NULL || completion_code == NULL ||
3195 non_functioning_component_indication == NULL ||
3196 non_functioning_component_bitmap == NULL || !payload_length) {
3197 return PLDM_ERROR_INVALID_DATA;
3198 }
3199
3200 *completion_code = msg->payload[0];
3201 if (*completion_code != PLDM_SUCCESS) {
3202 return PLDM_SUCCESS;
3203 }
3204
3205 if (payload_length != sizeof(struct pldm_cancel_update_resp)) {
3206 return PLDM_ERROR_INVALID_LENGTH;
3207 }
3208 struct pldm_cancel_update_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303209 (struct pldm_cancel_update_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09303210
3211 if (!is_non_functioning_component_indication_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303212 response->non_functioning_component_indication)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09303213 return PLDM_ERROR_INVALID_DATA;
3214 }
3215
3216 *non_functioning_component_indication =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303217 response->non_functioning_component_indication;
Andrew Jeffery9c766792022-08-10 23:12:49 +09303218
3219 if (*non_functioning_component_indication) {
3220 non_functioning_component_bitmap->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303221 le64toh(response->non_functioning_component_bitmap);
Andrew Jeffery9c766792022-08-10 23:12:49 +09303222 }
3223
3224 return PLDM_SUCCESS;
3225}
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003226
3227LIBPLDM_ABI_TESTING
3228int encode_cancel_update_resp(uint8_t instance_id,
3229 const struct pldm_cancel_update_resp *resp_data,
3230 struct pldm_msg *msg, size_t *payload_length)
3231{
Andrew Jefferya1896962025-03-03 21:41:25 +10303232 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003233 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003234
3235 if (msg == NULL || payload_length == NULL) {
3236 return -EINVAL;
3237 }
3238
3239 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
3240 PLDM_CANCEL_UPDATE, msg);
3241 if (rc) {
3242 return -EINVAL;
3243 }
3244
3245 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
3246 if (rc) {
3247 return rc;
3248 }
3249
3250 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
3251 pldm_msgbuf_insert(buf,
3252 resp_data->non_functioning_component_indication);
3253 pldm_msgbuf_insert(buf, resp_data->non_functioning_component_bitmap);
3254
Andrew Jeffery70d21c92025-03-05 12:59:42 +10303255 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003256}
Andrew Jeffery2613c272025-03-12 14:15:41 +10303257
Unive Tienf6ef78f2025-06-12 09:39:38 +08003258LIBPLDM_ABI_STABLE
Andrew Jeffery2613c272025-03-12 14:15:41 +10303259int decode_pldm_firmware_update_package(
3260 const void *data, size_t length,
3261 const struct pldm_package_format_pin *pin,
Andrew Jeffery72442de2025-08-12 08:47:42 +00003262 pldm_package_header_information_pad *hdr, struct pldm_package *pkg,
3263 uint32_t flags)
Andrew Jeffery2613c272025-03-12 14:15:41 +10303264{
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003265 if (!data || !pin || !hdr || !pkg) {
Andrew Jeffery2613c272025-03-12 14:15:41 +10303266 return -EINVAL;
3267 }
3268
Andrew Jeffery72442de2025-08-12 08:47:42 +00003269 if (flags) {
3270 return -EINVAL;
3271 }
3272
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003273 return decode_pldm_package_header_info_errno(data, length, pin, hdr,
3274 pkg);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303275}
3276
Unive Tienf6ef78f2025-06-12 09:39:38 +08003277LIBPLDM_ABI_STABLE
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003278int pldm_package_firmware_device_id_record_iter_init(struct pldm_package *pkg)
Andrew Jeffery2613c272025-03-12 14:15:41 +10303279{
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003280 struct pldm_package_iter *iter;
Andrew Jeffery2613c272025-03-12 14:15:41 +10303281 PLDM_MSGBUF_DEFINE_P(buf);
3282 int rc;
3283
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003284 if (!pkg || !pkg->pin || !pkg->hdr) {
Andrew Jeffery2613c272025-03-12 14:15:41 +10303285 return -EINVAL;
3286 }
3287
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003288 assert(pkg->pin->format.revision >=
3289 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
3290 assert(pkg->pin->format.revision <=
3291 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H);
3292 assert(pkg->hdr->package_header_format_revision >=
3293 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
3294 assert(pkg->hdr->package_header_format_revision <=
3295 pkg->pin->format.revision);
3296
3297 if (pkg->state != PLDM_PACKAGE_PARSE_HEADER) {
3298 return -EPROTO;
3299 }
3300
3301 if (!pkg->areas.ptr) {
3302 return -EINVAL;
3303 }
3304
3305 pkg->state = PLDM_PACKAGE_PARSE_FIRMWARE_DEVICES;
3306
3307 iter = &pkg->iter;
3308 iter->field = pkg->areas;
Andrew Jeffery2613c272025-03-12 14:15:41 +10303309
3310 /* Extract the fd record id count */
3311 rc = pldm_msgbuf_init_errno(buf, 1, iter->field.ptr,
3312 iter->field.length);
3313 if (rc) {
3314 return rc;
3315 }
3316
3317 pldm_msgbuf_extract_uint8_to_size(buf, iter->entries);
3318 pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
3319 &iter->field.length);
3320
3321 return pldm_msgbuf_complete(buf);
3322}
3323
Unive Tienf6ef78f2025-06-12 09:39:38 +08003324LIBPLDM_ABI_STABLE
Andrew Jeffery2613c272025-03-12 14:15:41 +10303325int decode_pldm_package_firmware_device_id_record_from_iter(
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003326 struct pldm_package *pkg LIBPLDM_CC_UNUSED,
Andrew Jeffery2613c272025-03-12 14:15:41 +10303327 struct pldm_package_firmware_device_id_record *rec)
3328{
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003329 if (!pkg) {
Andrew Jeffery2613c272025-03-12 14:15:41 +10303330 return -EINVAL;
3331 }
3332
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003333 if (pkg->state != PLDM_PACKAGE_PARSE_FIRMWARE_DEVICES) {
3334 return -EPROTO;
3335 }
Andrew Jeffery2613c272025-03-12 14:15:41 +10303336
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003337 return decode_pldm_package_firmware_device_id_record_errno(
3338 pkg->hdr, &pkg->iter.field, rec);
3339}
3340
Unive Tienf6ef78f2025-06-12 09:39:38 +08003341LIBPLDM_ABI_STABLE
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003342int pldm_package_downstream_device_id_record_iter_init(struct pldm_package *pkg)
3343{
3344 struct pldm_package_iter *iter;
3345 PLDM_MSGBUF_DEFINE_P(buf);
3346 int rc;
3347
3348 if (!pkg || !pkg->pin || !pkg->hdr) {
3349 return -EINVAL;
3350 }
3351
3352 assert(pkg->pin->format.revision >=
3353 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
3354 assert(pkg->pin->format.revision <=
3355 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H);
3356 assert(pkg->hdr->package_header_format_revision >=
3357 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
3358 assert(pkg->hdr->package_header_format_revision <=
3359 pkg->pin->format.revision);
3360
3361 if (pkg->state != PLDM_PACKAGE_PARSE_FIRMWARE_DEVICES) {
3362 return -EPROTO;
3363 }
3364
3365 if (pkg->pin->format.revision ==
3366 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H) {
3367 return -EPROTO;
3368 }
3369
3370 if (!pkg->iter.field.ptr) {
3371 return -EINVAL;
3372 }
3373 iter = &pkg->iter;
3374
3375 pkg->state = PLDM_PACKAGE_PARSE_DOWNSTREAM_DEVICES;
3376
3377 /* Where:
3378 *
3379 * 1. The pin revision is greater than 1, and
3380 * 2. The package header format revision is 1
3381 *
3382 * We must account for the invocation of this function but present no downstream
3383 * devices, as they're not specified.
3384 */
3385 if (pkg->hdr->package_header_format_revision ==
3386 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H) {
3387 iter->entries = 0;
Andrew Jeffery2613c272025-03-12 14:15:41 +10303388 return 0;
3389 }
3390
3391 /* Extract the dd record id count */
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003392 rc = pldm_msgbuf_init_errno(buf, 1, iter->field.ptr,
3393 iter->field.length);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303394 if (rc) {
3395 return rc;
3396 }
3397
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003398 pldm_msgbuf_extract_uint8_to_size(buf, iter->entries);
3399 pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
3400 &iter->field.length);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303401
3402 return pldm_msgbuf_complete(buf);
3403}
3404
3405#define PLDM_FWUP_DOWNSTREAM_DEVICE_ID_RECORD_MIN_SIZE 11
Unive Tienf6ef78f2025-06-12 09:39:38 +08003406LIBPLDM_ABI_STABLE
Andrew Jeffery2613c272025-03-12 14:15:41 +10303407int decode_pldm_package_downstream_device_id_record_from_iter(
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003408 struct pldm_package *pkg,
Andrew Jeffery2613c272025-03-12 14:15:41 +10303409 struct pldm_package_downstream_device_id_record *rec)
3410{
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003411 struct pldm_package_iter *iter;
Carter Chen01782742025-06-25 13:53:50 +08003412 size_t package_data_offset;
Andrew Jeffery2613c272025-03-12 14:15:41 +10303413 PLDM_MSGBUF_DEFINE_P(buf);
3414 uint16_t record_len = 0;
3415 int rc;
3416
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003417 if (!pkg || !rec || !pkg->hdr) {
Andrew Jeffery2613c272025-03-12 14:15:41 +10303418 return -EINVAL;
3419 }
3420
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003421 if (pkg->state != PLDM_PACKAGE_PARSE_DOWNSTREAM_DEVICES) {
Andrew Jeffery2613c272025-03-12 14:15:41 +10303422 return -EPROTO;
3423 }
3424
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003425 assert(pkg->hdr->package_header_format_revision >
3426 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
3427
3428 if (!pkg->iter.field.ptr) {
3429 return -EINVAL;
3430 }
3431 iter = &pkg->iter;
3432
Andrew Jeffery2613c272025-03-12 14:15:41 +10303433 rc = pldm_msgbuf_init_dynamic_uint16(
3434 buf, PLDM_FWUP_DOWNSTREAM_DEVICE_ID_RECORD_MIN_SIZE,
3435 (void *)iter->field.ptr, iter->field.length,
3436 (void **)&iter->field.ptr, &iter->field.length);
3437 if (rc) {
3438 return pldm_msgbuf_discard(buf, rc);
3439 }
3440
3441 pldm_msgbuf_extract(buf, record_len);
3442 pldm_msgbuf_extract(buf, rec->descriptor_count);
3443
3444 rc = pldm_msgbuf_extract(buf, rec->update_option_flags.value);
3445 if (rc) {
3446 return pldm_msgbuf_discard(buf, rc);
3447 }
3448
3449 rc = pldm_msgbuf_extract(
3450 buf, rec->self_contained_activation_min_version_string_type);
3451 if (rc) {
3452 return pldm_msgbuf_discard(buf, rc);
3453 }
3454 if (!is_string_type_valid(
3455 rec->self_contained_activation_min_version_string_type)) {
3456 return pldm_msgbuf_discard(buf, -EPROTO);
3457 }
3458
3459 rc = pldm_msgbuf_extract_uint8_to_size(
3460 buf, rec->self_contained_activation_min_version_string.length);
3461 if (rc) {
3462 return pldm_msgbuf_discard(buf, rc);
3463 }
3464
3465 rc = pldm_msgbuf_extract_uint16_to_size(buf, rec->package_data.length);
3466 if (rc) {
3467 return pldm_msgbuf_discard(buf, rc);
3468 }
3469
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003470 if (pkg->hdr->package_header_format_revision >=
Carter Chen01782742025-06-25 13:53:50 +08003471 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H) {
3472 pldm_msgbuf_extract_uint32_to_size(
3473 buf, rec->reference_manifest_data.length);
3474 } else {
3475 rec->reference_manifest_data.length = 0;
3476 }
3477
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003478 assert((pkg->hdr->component_bitmap_bit_length & 7) == 0);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303479 rc = pldm_msgbuf_span_required(
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003480 buf, pkg->hdr->component_bitmap_bit_length / 8,
Andrew Jeffery2613c272025-03-12 14:15:41 +10303481 (void **)&rec->applicable_components.bitmap.ptr);
3482 if (rc) {
3483 return pldm_msgbuf_discard(buf, rc);
3484 }
3485 rec->applicable_components.bitmap.length =
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003486 pkg->hdr->component_bitmap_bit_length / 8;
Andrew Jeffery2613c272025-03-12 14:15:41 +10303487
3488 pldm_msgbuf_span_required(
3489 buf, rec->self_contained_activation_min_version_string.length,
3490 (void **)&rec->self_contained_activation_min_version_string.ptr);
3491 if (rec->update_option_flags.bits.bit0) {
3492 pldm_msgbuf_extract(
3493 buf,
3494 rec->self_contained_activation_min_version_comparison_stamp);
3495 } else {
3496 rec->self_contained_activation_min_version_comparison_stamp = 0;
3497 }
3498
Carter Chen01782742025-06-25 13:53:50 +08003499 /* The total length reserved for `package_data` and `reference_manifest_data` */
3500 package_data_offset =
3501 rec->package_data.length + rec->reference_manifest_data.length;
3502
3503 pldm_msgbuf_span_until(buf, package_data_offset,
Andrew Jeffery2613c272025-03-12 14:15:41 +10303504 (void **)&rec->record_descriptors.ptr,
3505 &rec->record_descriptors.length);
3506
3507 pldm_msgbuf_span_required(buf, rec->package_data.length,
3508 (void **)&rec->package_data.ptr);
3509
Carter Chen01782742025-06-25 13:53:50 +08003510 /* Supported in package header revision 1.3 (FR04H) and above. */
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003511 if (pkg->hdr->package_header_format_revision >=
Carter Chen01782742025-06-25 13:53:50 +08003512 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H) {
3513 pldm_msgbuf_span_required(
3514 buf, rec->reference_manifest_data.length,
3515 (void **)&rec->reference_manifest_data.ptr);
3516 } else {
3517 assert(rec->reference_manifest_data.length == 0);
3518 rec->reference_manifest_data.ptr = NULL;
3519 }
3520
Andrew Jeffery2613c272025-03-12 14:15:41 +10303521 return pldm_msgbuf_complete_consumed(buf);
3522}
3523
Unive Tienf6ef78f2025-06-12 09:39:38 +08003524LIBPLDM_ABI_STABLE
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003525int pldm_package_component_image_information_iter_init(struct pldm_package *pkg)
Andrew Jeffery2613c272025-03-12 14:15:41 +10303526{
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003527 struct pldm_package_iter *iter;
Andrew Jeffery2613c272025-03-12 14:15:41 +10303528 uint16_t component_image_count;
3529 PLDM_MSGBUF_DEFINE_P(buf);
3530 int rc;
3531
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003532 if (!pkg || !pkg->pin || !pkg->hdr) {
Andrew Jeffery2613c272025-03-12 14:15:41 +10303533 return -EINVAL;
3534 }
3535
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003536 assert(pkg->pin->format.revision >=
3537 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
3538 assert(pkg->pin->format.revision <=
3539 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H);
3540 assert(pkg->hdr->package_header_format_revision >=
3541 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
3542 assert(pkg->hdr->package_header_format_revision <=
3543 pkg->pin->format.revision);
3544
3545 if (pkg->state == PLDM_PACKAGE_PARSE_FIRMWARE_DEVICES) {
3546 if (pkg->pin->format.revision !=
3547 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H ||
3548 pkg->hdr->package_header_format_revision !=
3549 pkg->pin->format.revision) {
3550 return -EPROTO;
3551 }
3552 } else if (pkg->state == PLDM_PACKAGE_PARSE_DOWNSTREAM_DEVICES) {
3553 assert(pkg->pin->format.revision !=
3554 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
3555 } else {
3556 return -EPROTO;
3557 }
3558
3559 if (!pkg->iter.field.ptr) {
3560 return -EINVAL;
3561 }
3562 iter = &pkg->iter;
3563
3564 pkg->state = PLDM_PACKAGE_PARSE_COMPONENT_IMAGE_INFORMATION;
Andrew Jeffery2613c272025-03-12 14:15:41 +10303565
3566 /* Extract the component image count */
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003567 rc = pldm_msgbuf_init_errno(buf, 1, iter->field.ptr,
3568 iter->field.length);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303569 if (rc) {
3570 return rc;
3571 }
3572
3573 rc = pldm_msgbuf_extract(buf, component_image_count);
3574 if (rc) {
3575 return pldm_msgbuf_discard(buf, rc);
3576 }
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003577 iter->entries = component_image_count;
Andrew Jeffery2613c272025-03-12 14:15:41 +10303578
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003579 pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
3580 &iter->field.length);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303581
3582 return pldm_msgbuf_complete(buf);
3583}
3584
3585#define PLDM_FWUP_COMPONENT_IMAGE_INFORMATION_MIN_SIZE 22
Unive Tienf6ef78f2025-06-12 09:39:38 +08003586LIBPLDM_ABI_STABLE
Andrew Jeffery2613c272025-03-12 14:15:41 +10303587int decode_pldm_package_component_image_information_from_iter(
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003588 struct pldm_package *pkg,
Andrew Jeffery2613c272025-03-12 14:15:41 +10303589 struct pldm_package_component_image_information *info)
3590{
3591 uint32_t component_location_offset = 0;
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003592 struct pldm_package_iter *iter;
Andrew Jeffery2613c272025-03-12 14:15:41 +10303593 uint32_t component_size = 0;
3594 PLDM_MSGBUF_DEFINE_P(buf);
3595 int rc;
3596
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003597 if (!pkg || !info) {
Andrew Jeffery2613c272025-03-12 14:15:41 +10303598 return -EINVAL;
3599 }
3600
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003601 if (pkg->state != PLDM_PACKAGE_PARSE_COMPONENT_IMAGE_INFORMATION) {
Andrew Jeffery2613c272025-03-12 14:15:41 +10303602 return -EPROTO;
3603 }
3604
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003605 if (!pkg->iter.field.ptr) {
3606 return -EINVAL;
3607 }
3608 iter = &pkg->iter;
3609
Andrew Jeffery2613c272025-03-12 14:15:41 +10303610 rc = pldm_msgbuf_init_errno(
3611 buf, PLDM_FWUP_COMPONENT_IMAGE_INFORMATION_MIN_SIZE,
3612 iter->field.ptr, iter->field.length);
3613 if (rc) {
3614 return rc;
3615 }
3616
3617 pldm_msgbuf_extract(buf, info->component_classification);
3618 pldm_msgbuf_extract(buf, info->component_identifier);
3619 pldm_msgbuf_extract(buf, info->component_comparison_stamp);
3620 pldm_msgbuf_extract(buf, info->component_options.value);
3621 pldm_msgbuf_extract(buf,
3622 info->requested_component_activation_method.value);
3623 pldm_msgbuf_extract(buf, component_location_offset);
3624 pldm_msgbuf_extract(buf, component_size);
3625
3626 rc = pldm_msgbuf_extract(buf, info->component_version_string_type);
3627 if (rc) {
3628 return pldm_msgbuf_discard(buf, rc);
3629 }
3630 if (!is_string_type_valid(info->component_version_string_type)) {
3631 return pldm_msgbuf_discard(buf, -EPROTO);
3632 }
3633
3634 rc = pldm_msgbuf_extract_uint8_to_size(
3635 buf, info->component_version_string.length);
3636 if (rc) {
3637 return pldm_msgbuf_discard(buf, rc);
3638 }
3639
3640 pldm_msgbuf_span_required(buf, info->component_version_string.length,
3641 (void **)&info->component_version_string.ptr);
3642
Carter Chenf72cf6f2025-06-24 15:34:49 +08003643 /* Supported in package header revision 1.2 (FR03H) and above. */
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003644 if (pkg->hdr->package_header_format_revision >=
Carter Chenf72cf6f2025-06-24 15:34:49 +08003645 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR03H) {
3646 rc = pldm_msgbuf_extract_uint32_to_size(
3647 buf, info->component_opaque_data.length);
3648 if (rc) {
3649 return pldm_msgbuf_discard(buf, rc);
3650 }
3651 pldm_msgbuf_span_required(
3652 buf, info->component_opaque_data.length,
3653 (void **)&info->component_opaque_data.ptr);
3654 } else {
3655 info->component_opaque_data.length = 0;
3656 }
3657
3658 if (info->component_opaque_data.length == 0) {
3659 info->component_opaque_data.ptr = NULL;
3660 }
3661
Andrew Jeffery2613c272025-03-12 14:15:41 +10303662 pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
3663 &iter->field.length);
3664
3665 rc = pldm_msgbuf_complete_consumed(buf);
3666 if (rc) {
3667 return rc;
3668 }
3669
3670 if (info->component_classification > 0x000d &&
3671 info->component_classification < 0x8000) {
3672 return -EPROTO;
3673 }
3674
3675 /* Resolve the component image in memory */
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003676 rc = pldm_msgbuf_init_errno(buf, 0, pkg->package.ptr,
3677 pkg->package.length);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303678 if (rc) {
3679 return rc;
3680 }
3681
3682 pldm_msgbuf_span_required(buf, component_location_offset, NULL);
3683 pldm_msgbuf_span_required(buf, component_size,
3684 (void **)&info->component_image.ptr);
3685
3686 rc = pldm_msgbuf_complete(buf);
3687 if (rc) {
3688 return rc;
3689 }
3690
3691 info->component_image.length = component_size;
3692
3693 return 0;
3694}