blob: 8c2e1dbc7f74528a26aadc5c05fa969662d9d48f [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;
585 pkg->package.ptr = data;
586 pkg->package.length = length;
Andrew Jeffery2613c272025-03-12 14:15:41 +1030587
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030588 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930589}
590
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930591LIBPLDM_ABI_STABLE
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030592int decode_pldm_package_header_info(
593 const uint8_t *data, size_t length,
594 struct pldm_package_header_information *package_header_info,
595 struct variable_field *package_version_str)
596{
Andrew Jeffery2613c272025-03-12 14:15:41 +1030597 DEFINE_PLDM_PACKAGE_FORMAT_PIN_FR01H(pin);
598 pldm_package_header_information_pad hdr;
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000599 struct pldm_package pkg = { 0 };
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030600 int rc;
601
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030602 if (!data || !package_header_info || !package_version_str) {
603 return PLDM_ERROR_INVALID_DATA;
604 }
605
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000606 rc = decode_pldm_package_header_info_errno(data, length, &pin, &hdr,
607 &pkg);
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030608 if (rc < 0) {
609 return pldm_xlate_errno(rc);
610 }
611
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030612 static_assert(sizeof(package_header_info->uuid) ==
Andrew Jeffery2613c272025-03-12 14:15:41 +1030613 sizeof(hdr.package_header_identifier),
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030614 "UUID field size");
Andrew Jeffery2613c272025-03-12 14:15:41 +1030615 memcpy(package_header_info->uuid, hdr.package_header_identifier,
616 sizeof(hdr.package_header_identifier));
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030617 package_header_info->package_header_format_version =
Andrew Jeffery2613c272025-03-12 14:15:41 +1030618 hdr.package_header_format_revision;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030619 memcpy(&package_header_info->package_header_size, data + 17,
620 sizeof(package_header_info->package_header_size));
621 LE16TOH(package_header_info->package_header_size);
622 static_assert(sizeof(package_header_info->package_release_date_time) ==
Andrew Jeffery2613c272025-03-12 14:15:41 +1030623 sizeof(hdr.package_release_date_time),
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030624 "TIMESTAMP104 field size");
625 memcpy(package_header_info->package_release_date_time,
Andrew Jeffery2613c272025-03-12 14:15:41 +1030626 hdr.package_release_date_time,
627 sizeof(hdr.package_release_date_time));
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030628 package_header_info->component_bitmap_bit_length =
Andrew Jeffery2613c272025-03-12 14:15:41 +1030629 hdr.component_bitmap_bit_length;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030630 package_header_info->package_version_string_type =
Andrew Jeffery2613c272025-03-12 14:15:41 +1030631 hdr.package_version_string_type;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030632 package_header_info->package_version_string_length =
Andrew Jeffery2613c272025-03-12 14:15:41 +1030633 hdr.package_version_string.length;
634 *package_version_str = hdr.package_version_string;
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030635
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030636 return PLDM_SUCCESS;
637}
638
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000639/* Currently only used for decode_firmware_device_id_record_errno() */
640static int pldm_msgbuf_init_dynamic_uint16(struct pldm_msgbuf *buf, size_t req,
Andrew Jeffery2613c272025-03-12 14:15:41 +1030641 void *data, size_t len,
642 void **tail_data, size_t *tail_len)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930643{
Andrew Jeffery2613c272025-03-12 14:15:41 +1030644 size_t dyn_length;
645 void *dyn_start;
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000646 int rc;
647
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000648 rc = pldm_msgbuf_init_errno(buf, req, data, len);
649 if (rc) {
650 return rc;
651 }
Andrew Jeffery2613c272025-03-12 14:15:41 +1030652 /*
653 * Extract the record length from the first field, then reinitialise the msgbuf
654 * after determining that it's safe to do so
655 */
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000656
Andrew Jeffery2613c272025-03-12 14:15:41 +1030657 rc = pldm_msgbuf_extract_uint16_to_size(buf, dyn_length);
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000658 if (rc) {
659 return pldm_msgbuf_discard(buf, rc);
660 }
661
662 rc = pldm_msgbuf_complete(buf);
663 if (rc) {
664 return rc;
665 }
666
667 rc = pldm_msgbuf_init_errno(buf, req, data, len);
668 if (rc) {
669 return rc;
670 }
671
672 /* Ensure there's no arithmetic funkiness and the span is within buffer bounds */
Andrew Jeffery2613c272025-03-12 14:15:41 +1030673 rc = pldm_msgbuf_span_required(buf, dyn_length, &dyn_start);
674 if (rc) {
675 return pldm_msgbuf_discard(buf, rc);
676 }
677
678 rc = pldm_msgbuf_span_remaining(buf, tail_data, tail_len);
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000679 if (rc) {
680 return pldm_msgbuf_discard(buf, rc);
681 }
682
683 rc = pldm_msgbuf_complete(buf);
684 if (rc) {
685 return rc;
686 }
687
Andrew Jeffery2613c272025-03-12 14:15:41 +1030688 return pldm_msgbuf_init_errno(buf, req, dyn_start, dyn_length);
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000689}
690
691#define PLDM_FWUP_FIRMWARE_DEVICE_ID_RECORD_MIN_SIZE 11
Andrew Jeffery2613c272025-03-12 14:15:41 +1030692static int decode_pldm_package_firmware_device_id_record_errno(
693 const pldm_package_header_information_pad *hdr,
694 struct variable_field *field,
695 struct pldm_package_firmware_device_id_record *rec)
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000696{
Carter Chen01782742025-06-25 13:53:50 +0800697 size_t firmware_device_package_data_offset;
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000698 PLDM_MSGBUF_DEFINE_P(buf);
699 uint16_t record_len = 0;
700 int rc;
701
Andrew Jeffery2613c272025-03-12 14:15:41 +1030702 if (!hdr || !field || !rec || !field->ptr) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030703 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930704 }
705
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000706 rc = pldm_msgbuf_init_dynamic_uint16(
Andrew Jeffery2613c272025-03-12 14:15:41 +1030707 buf, PLDM_FWUP_FIRMWARE_DEVICE_ID_RECORD_MIN_SIZE,
708 (void *)field->ptr, field->length, (void **)&field->ptr,
709 &field->length);
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000710 if (rc) {
711 return rc;
712 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930713
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000714 pldm_msgbuf_extract(buf, record_len);
715 pldm_msgbuf_extract(buf, rec->descriptor_count);
716 pldm_msgbuf_extract(buf, rec->device_update_option_flags.value);
717
718 rc = pldm_msgbuf_extract(buf,
719 rec->component_image_set_version_string_type);
720 if (rc) {
721 return pldm_msgbuf_discard(buf, rc);
722 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930723 if (!is_string_type_valid(
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000724 rec->component_image_set_version_string_type)) {
725 return pldm_msgbuf_discard(buf, -EPROTO);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930726 }
727
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000728 rc = pldm_msgbuf_extract_uint8_to_size(
729 buf, rec->component_image_set_version_string.length);
730 if (rc) {
731 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930732 }
733
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000734 if (rec->component_image_set_version_string.length == 0) {
735 return pldm_msgbuf_discard(buf, -EPROTO);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930736 }
737
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000738 rc = pldm_msgbuf_extract_uint16_to_size(
739 buf, rec->firmware_device_package_data.length);
740 if (rc) {
741 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930742 }
743
Carter Chen01782742025-06-25 13:53:50 +0800744 if (hdr->package_header_format_revision >=
745 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H) {
746 rc = pldm_msgbuf_extract_uint32_to_size(
747 buf, rec->reference_manifest_data.length);
748 if (rc) {
749 return pldm_msgbuf_discard(buf, rc);
750 }
751 } else {
752 rec->reference_manifest_data.length = 0;
753 }
754
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +0000755 assert((hdr->component_bitmap_bit_length & 7) == 0);
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000756 rc = pldm_msgbuf_span_required(
Andrew Jeffery2613c272025-03-12 14:15:41 +1030757 buf, hdr->component_bitmap_bit_length / 8,
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000758 (void **)&rec->applicable_components.bitmap.ptr);
759 if (rc) {
760 return pldm_msgbuf_discard(buf, rc);
761 }
762 rec->applicable_components.bitmap.length =
Andrew Jeffery2613c272025-03-12 14:15:41 +1030763 hdr->component_bitmap_bit_length / 8;
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000764
765 pldm_msgbuf_span_required(
766 buf, rec->component_image_set_version_string.length,
767 (void **)&rec->component_image_set_version_string.ptr);
768
Carter Chen01782742025-06-25 13:53:50 +0800769 /* The total length reserved for `package_data` and `reference_manifest_data` */
770 firmware_device_package_data_offset =
771 rec->firmware_device_package_data.length +
772 rec->reference_manifest_data.length;
773
774 pldm_msgbuf_span_until(buf, firmware_device_package_data_offset,
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000775 (void **)&rec->record_descriptors.ptr,
776 &rec->record_descriptors.length);
777
778 pldm_msgbuf_span_required(
779 buf, rec->firmware_device_package_data.length,
780 (void **)&rec->firmware_device_package_data.ptr);
781 if (!rec->firmware_device_package_data.length) {
782 rec->firmware_device_package_data.ptr = NULL;
783 }
784
Carter Chen01782742025-06-25 13:53:50 +0800785 if (hdr->package_header_format_revision >=
786 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H) {
787 pldm_msgbuf_span_required(
788 buf, rec->reference_manifest_data.length,
789 (void **)&rec->reference_manifest_data.ptr);
790
791 } else {
792 assert(rec->reference_manifest_data.length == 0);
793 rec->reference_manifest_data.ptr = NULL;
794 }
795
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000796 return pldm_msgbuf_complete_consumed(buf);
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030797}
798
799LIBPLDM_ABI_STABLE
800int decode_firmware_device_id_record(
801 const uint8_t *data, size_t length,
802 uint16_t component_bitmap_bit_length,
803 struct pldm_firmware_device_id_record *fw_device_id_record,
804 struct variable_field *applicable_components,
805 struct variable_field *comp_image_set_version_str,
806 struct variable_field *record_descriptors,
807 struct variable_field *fw_device_pkg_data)
808{
Andrew Jeffery2613c272025-03-12 14:15:41 +1030809 struct pldm_package_firmware_device_id_record rec;
810 pldm_package_header_information_pad hdr;
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030811 int rc;
812
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000813 if (!data || !fw_device_id_record || !applicable_components ||
814 !comp_image_set_version_str || !record_descriptors ||
815 !fw_device_pkg_data) {
816 return PLDM_ERROR_INVALID_DATA;
817 }
818
Andrew Jeffery2613c272025-03-12 14:15:41 +1030819 hdr.package_header_format_revision =
820 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H;
821 hdr.component_bitmap_bit_length = component_bitmap_bit_length;
822
823 rc = decode_pldm_package_firmware_device_id_record_errno(
824 &hdr, &(struct variable_field){ data, length }, &rec);
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030825 if (rc < 0) {
826 return pldm_xlate_errno(rc);
827 }
828
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000829 memcpy(&fw_device_id_record->record_length, data,
830 sizeof(fw_device_id_record->record_length));
831 LE16TOH(fw_device_id_record->record_length);
832 fw_device_id_record->descriptor_count = rec.descriptor_count;
833 fw_device_id_record->device_update_option_flags =
834 rec.device_update_option_flags;
835 fw_device_id_record->comp_image_set_version_string_type =
836 rec.component_image_set_version_string_type;
837 fw_device_id_record->comp_image_set_version_string_length =
838 rec.component_image_set_version_string.length;
839 fw_device_id_record->fw_device_pkg_data_length =
840 rec.firmware_device_package_data.length;
841 *applicable_components = rec.applicable_components.bitmap;
842 *comp_image_set_version_str = rec.component_image_set_version_string;
843 *record_descriptors = rec.record_descriptors;
844 *fw_device_pkg_data = rec.firmware_device_package_data;
845
Andrew Jeffery9c766792022-08-10 23:12:49 +0930846 return PLDM_SUCCESS;
847}
848
Unive Tiene5c3f142024-12-13 14:14:19 +0800849LIBPLDM_ABI_STABLE
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030850int decode_pldm_descriptor_from_iter(struct pldm_descriptor_iter *iter,
851 struct pldm_descriptor *desc)
852{
Andrew Jefferya1896962025-03-03 21:41:25 +1030853 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030854 int rc;
855
856 if (!iter || !iter->field || !desc) {
857 return -EINVAL;
858 }
859
860 rc = pldm_msgbuf_init_errno(buf, PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN,
861 iter->field->ptr, iter->field->length);
862 if (rc) {
863 return rc;
864 }
865
866 pldm_msgbuf_extract(buf, desc->descriptor_type);
867 rc = pldm_msgbuf_extract(buf, desc->descriptor_length);
868 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +1030869 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030870 }
871
872 desc->descriptor_data = NULL;
873 pldm_msgbuf_span_required(buf, desc->descriptor_length,
874 (void **)&desc->descriptor_data);
875 iter->field->ptr = NULL;
876 pldm_msgbuf_span_remaining(buf, (void **)&iter->field->ptr,
877 &iter->field->length);
878
Andrew Jeffery70d21c92025-03-05 12:59:42 +1030879 return pldm_msgbuf_complete(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030880}
881
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030882static int decode_descriptor_type_length_value_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030883 const void *data, size_t length, uint16_t *descriptor_type,
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030884 struct variable_field *descriptor_data)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930885{
886 uint16_t descriptor_length = 0;
887
888 if (data == NULL || descriptor_type == NULL ||
889 descriptor_data == NULL) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030890 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930891 }
892
893 if (length < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030894 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930895 }
896
897 struct pldm_descriptor_tlv *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930898 (struct pldm_descriptor_tlv *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930899
900 *descriptor_type = le16toh(entry->descriptor_type);
901 descriptor_length = le16toh(entry->descriptor_length);
902 if (*descriptor_type != PLDM_FWUP_VENDOR_DEFINED) {
903 if (descriptor_length !=
904 get_descriptor_type_length(*descriptor_type)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030905 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930906 }
907 }
908
909 if (length < (sizeof(*descriptor_type) + sizeof(descriptor_length) +
910 descriptor_length)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030911 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930912 }
913
914 descriptor_data->ptr = entry->descriptor_data;
915 descriptor_data->length = descriptor_length;
916
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030917 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930918}
919
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930920LIBPLDM_ABI_STABLE
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030921int decode_descriptor_type_length_value(const uint8_t *data, size_t length,
922 uint16_t *descriptor_type,
923 struct variable_field *descriptor_data)
924{
925 int rc;
926
927 rc = decode_descriptor_type_length_value_errno(
928 data, length, descriptor_type, descriptor_data);
929 if (rc < 0) {
930 return pldm_xlate_errno(rc);
931 }
932
933 return PLDM_SUCCESS;
934}
935
936static int decode_vendor_defined_descriptor_value_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030937 const void *data, size_t length, uint8_t *descriptor_title_str_type,
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930938 struct variable_field *descriptor_title_str,
939 struct variable_field *descriptor_data)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930940{
941 if (data == NULL || descriptor_title_str_type == NULL ||
942 descriptor_title_str == NULL || descriptor_data == NULL) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030943 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930944 }
945
946 if (length < sizeof(struct pldm_vendor_defined_descriptor_title_data)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030947 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930948 }
949
950 struct pldm_vendor_defined_descriptor_title_data *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930951 (struct pldm_vendor_defined_descriptor_title_data *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930952 if (!is_string_type_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930953 entry->vendor_defined_descriptor_title_str_type) ||
Andrew Jeffery9c766792022-08-10 23:12:49 +0930954 (entry->vendor_defined_descriptor_title_str_len == 0)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030955 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930956 }
957
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530958 // Assuming at least 1 byte of VendorDefinedDescriptorData
Andrew Jeffery9c766792022-08-10 23:12:49 +0930959 if (length < (sizeof(struct pldm_vendor_defined_descriptor_title_data) +
960 entry->vendor_defined_descriptor_title_str_len)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030961 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930962 }
963
964 *descriptor_title_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930965 entry->vendor_defined_descriptor_title_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930966 descriptor_title_str->ptr = entry->vendor_defined_descriptor_title_str;
967 descriptor_title_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930968 entry->vendor_defined_descriptor_title_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930969
970 descriptor_data->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930971 descriptor_title_str->ptr + descriptor_title_str->length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930972 descriptor_data->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930973 length -
974 sizeof(entry->vendor_defined_descriptor_title_str_type) -
975 sizeof(entry->vendor_defined_descriptor_title_str_len) -
976 descriptor_title_str->length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930977
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030978 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930979}
980
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930981LIBPLDM_ABI_STABLE
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030982int decode_vendor_defined_descriptor_value(
983 const uint8_t *data, size_t length, uint8_t *descriptor_title_str_type,
984 struct variable_field *descriptor_title_str,
985 struct variable_field *descriptor_data)
986{
987 int rc;
988
989 rc = decode_vendor_defined_descriptor_value_errno(
990 data, length, descriptor_title_str_type, descriptor_title_str,
991 descriptor_data);
992 if (rc < 0) {
993 return pldm_xlate_errno(rc);
994 }
995
996 return PLDM_SUCCESS;
997}
998
999static int decode_pldm_comp_image_info_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +10301000 const void *data, size_t length,
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301001 struct pldm_component_image_information *pldm_comp_image_info,
1002 struct variable_field *comp_version_str)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301003{
1004 if (data == NULL || pldm_comp_image_info == NULL ||
1005 comp_version_str == NULL) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +10301006 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301007 }
1008
1009 if (length < sizeof(struct pldm_component_image_information)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +10301010 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301011 }
1012
1013 struct pldm_component_image_information *data_header =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301014 (struct pldm_component_image_information *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301015
1016 if (!is_string_type_valid(data_header->comp_version_string_type) ||
1017 (data_header->comp_version_string_length == 0)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +10301018 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301019 }
1020
1021 if (length < sizeof(struct pldm_component_image_information) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301022 data_header->comp_version_string_length) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +10301023 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301024 }
1025
1026 pldm_comp_image_info->comp_classification =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301027 le16toh(data_header->comp_classification);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301028 pldm_comp_image_info->comp_identifier =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301029 le16toh(data_header->comp_identifier);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301030 pldm_comp_image_info->comp_comparison_stamp =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301031 le32toh(data_header->comp_comparison_stamp);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301032 pldm_comp_image_info->comp_options.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301033 le16toh(data_header->comp_options.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301034 pldm_comp_image_info->requested_comp_activation_method.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301035 le16toh(data_header->requested_comp_activation_method.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301036 pldm_comp_image_info->comp_location_offset =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301037 le32toh(data_header->comp_location_offset);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301038 pldm_comp_image_info->comp_size = le32toh(data_header->comp_size);
1039 pldm_comp_image_info->comp_version_string_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301040 data_header->comp_version_string_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301041 pldm_comp_image_info->comp_version_string_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301042 data_header->comp_version_string_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301043
1044 if ((pldm_comp_image_info->comp_options.bits.bit1 == false &&
1045 pldm_comp_image_info->comp_comparison_stamp !=
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301046 PLDM_FWUP_INVALID_COMPONENT_COMPARISON_TIMESTAMP)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +10301047 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301048 }
1049
1050 if (pldm_comp_image_info->comp_location_offset == 0 ||
1051 pldm_comp_image_info->comp_size == 0) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +10301052 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301053 }
1054
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +10301055 comp_version_str->ptr = (const uint8_t *)data +
1056 sizeof(struct pldm_component_image_information);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301057 comp_version_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301058 pldm_comp_image_info->comp_version_string_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301059
Andrew Jeffery779e9db2025-02-21 12:14:28 +10301060 return 0;
1061}
1062
1063LIBPLDM_ABI_STABLE
1064int decode_pldm_comp_image_info(
1065 const uint8_t *data, size_t length,
1066 struct pldm_component_image_information *pldm_comp_image_info,
1067 struct variable_field *comp_version_str)
1068{
1069 int rc;
1070
1071 rc = decode_pldm_comp_image_info_errno(
1072 data, length, pldm_comp_image_info, comp_version_str);
1073 if (rc < 0) {
1074 return pldm_xlate_errno(rc);
1075 }
1076
Andrew Jeffery9c766792022-08-10 23:12:49 +09301077 return PLDM_SUCCESS;
1078}
1079
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301080LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301081int encode_query_device_identifiers_req(uint8_t instance_id,
1082 size_t payload_length,
1083 struct pldm_msg *msg)
1084{
1085 if (msg == NULL) {
1086 return PLDM_ERROR_INVALID_DATA;
1087 }
1088
1089 if (payload_length != PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES) {
1090 return PLDM_ERROR_INVALID_LENGTH;
1091 }
1092
1093 return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
1094 PLDM_QUERY_DEVICE_IDENTIFIERS, msg);
1095}
1096
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301097LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301098int decode_query_device_identifiers_resp(const struct pldm_msg *msg,
1099 size_t payload_length,
1100 uint8_t *completion_code,
1101 uint32_t *device_identifiers_len,
1102 uint8_t *descriptor_count,
1103 uint8_t **descriptor_data)
1104{
1105 if (msg == NULL || completion_code == NULL ||
1106 device_identifiers_len == NULL || descriptor_count == NULL ||
1107 descriptor_data == NULL) {
1108 return PLDM_ERROR_INVALID_DATA;
1109 }
1110
1111 *completion_code = msg->payload[0];
1112 if (PLDM_SUCCESS != *completion_code) {
1113 return PLDM_SUCCESS;
1114 }
1115
1116 if (payload_length <
1117 sizeof(struct pldm_query_device_identifiers_resp)) {
1118 return PLDM_ERROR_INVALID_LENGTH;
1119 }
1120
1121 struct pldm_query_device_identifiers_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301122 (struct pldm_query_device_identifiers_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301123 *device_identifiers_len = le32toh(response->device_identifiers_len);
1124
1125 if (*device_identifiers_len < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {
1126 return PLDM_ERROR_INVALID_LENGTH;
1127 }
1128
1129 if (payload_length !=
1130 sizeof(struct pldm_query_device_identifiers_resp) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301131 *device_identifiers_len) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301132 return PLDM_ERROR_INVALID_LENGTH;
1133 }
1134 *descriptor_count = response->descriptor_count;
1135
1136 if (*descriptor_count == 0) {
1137 return PLDM_ERROR_INVALID_DATA;
1138 }
1139 *descriptor_data =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301140 (uint8_t *)(msg->payload +
1141 sizeof(struct pldm_query_device_identifiers_resp));
Andrew Jeffery9c766792022-08-10 23:12:49 +09301142 return PLDM_SUCCESS;
1143}
1144
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001145LIBPLDM_ABI_TESTING
1146int encode_query_device_identifiers_resp(
1147 uint8_t instance_id, uint8_t descriptor_count,
1148 const struct pldm_descriptor *descriptors, struct pldm_msg *msg,
1149 size_t *payload_length)
1150{
Andrew Jefferya1896962025-03-03 21:41:25 +10301151 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001152 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001153
1154 if (descriptors == NULL || msg == NULL || payload_length == NULL) {
1155 return -EINVAL;
1156 }
1157
1158 if (descriptor_count < 1) {
1159 return -EINVAL;
1160 }
1161
1162 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
1163 PLDM_QUERY_DEVICE_IDENTIFIERS, msg);
1164 if (rc) {
1165 return -EINVAL;
1166 }
1167
1168 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
1169 if (rc) {
1170 return rc;
1171 }
1172
1173 /* Determine total length */
1174 uint32_t device_identifiers_len = 0;
1175 for (uint8_t i = 0; i < descriptor_count; i++) {
1176 const struct pldm_descriptor *d = &descriptors[i];
1177 device_identifiers_len +=
1178 2 * sizeof(uint16_t) + d->descriptor_length;
1179 }
1180
1181 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
1182 pldm_msgbuf_insert(buf, device_identifiers_len);
1183 pldm_msgbuf_insert(buf, descriptor_count);
1184
1185 for (uint8_t i = 0; i < descriptor_count; i++) {
1186 const struct pldm_descriptor *d = &descriptors[i];
1187 pldm_msgbuf_insert(buf, d->descriptor_type);
1188 pldm_msgbuf_insert(buf, d->descriptor_length);
1189 if (d->descriptor_data == NULL) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301190 return pldm_msgbuf_discard(buf, -EINVAL);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001191 }
1192 rc = pldm_msgbuf_insert_array(
1193 buf, d->descriptor_length,
1194 (const uint8_t *)d->descriptor_data,
1195 d->descriptor_length);
1196 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301197 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001198 }
1199 }
1200
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301201 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001202}
1203
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301204LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301205int encode_get_firmware_parameters_req(uint8_t instance_id,
1206 size_t payload_length,
1207 struct pldm_msg *msg)
1208{
1209 if (msg == NULL) {
1210 return PLDM_ERROR_INVALID_DATA;
1211 }
1212
1213 if (payload_length != PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES) {
1214 return PLDM_ERROR_INVALID_LENGTH;
1215 }
1216
1217 return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
1218 PLDM_GET_FIRMWARE_PARAMETERS, msg);
1219}
1220
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301221LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301222int decode_get_firmware_parameters_resp(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301223 const struct pldm_msg *msg, size_t payload_length,
1224 struct pldm_get_firmware_parameters_resp *resp_data,
1225 struct variable_field *active_comp_image_set_ver_str,
1226 struct variable_field *pending_comp_image_set_ver_str,
1227 struct variable_field *comp_parameter_table)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301228{
1229 if (msg == NULL || resp_data == NULL ||
1230 active_comp_image_set_ver_str == NULL ||
1231 pending_comp_image_set_ver_str == NULL ||
1232 comp_parameter_table == NULL || !payload_length) {
1233 return PLDM_ERROR_INVALID_DATA;
1234 }
1235
1236 resp_data->completion_code = msg->payload[0];
1237 if (PLDM_SUCCESS != resp_data->completion_code) {
1238 return PLDM_SUCCESS;
1239 }
1240
1241 if (payload_length < sizeof(struct pldm_get_firmware_parameters_resp)) {
1242 return PLDM_ERROR_INVALID_LENGTH;
1243 }
1244
1245 struct pldm_get_firmware_parameters_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301246 (struct pldm_get_firmware_parameters_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301247
1248 if (!is_string_type_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301249 response->active_comp_image_set_ver_str_type) ||
Andrew Jeffery9c766792022-08-10 23:12:49 +09301250 (response->active_comp_image_set_ver_str_len == 0)) {
1251 return PLDM_ERROR_INVALID_DATA;
1252 }
1253
1254 if (response->pending_comp_image_set_ver_str_len == 0) {
1255 if (response->pending_comp_image_set_ver_str_type !=
1256 PLDM_STR_TYPE_UNKNOWN) {
1257 return PLDM_ERROR_INVALID_DATA;
1258 }
1259 } else {
1260 if (!is_string_type_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301261 response->pending_comp_image_set_ver_str_type)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301262 return PLDM_ERROR_INVALID_DATA;
1263 }
1264 }
1265
1266 size_t partial_response_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301267 sizeof(struct pldm_get_firmware_parameters_resp) +
1268 response->active_comp_image_set_ver_str_len +
1269 response->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301270
1271 if (payload_length < partial_response_length) {
1272 return PLDM_ERROR_INVALID_LENGTH;
1273 }
1274
1275 resp_data->capabilities_during_update.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301276 le32toh(response->capabilities_during_update.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301277 resp_data->comp_count = le16toh(response->comp_count);
1278 resp_data->active_comp_image_set_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301279 response->active_comp_image_set_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301280 resp_data->active_comp_image_set_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301281 response->active_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301282 resp_data->pending_comp_image_set_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301283 response->pending_comp_image_set_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301284 resp_data->pending_comp_image_set_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301285 response->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301286
1287 active_comp_image_set_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301288 msg->payload + sizeof(struct pldm_get_firmware_parameters_resp);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301289 active_comp_image_set_ver_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301290 resp_data->active_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301291
1292 if (resp_data->pending_comp_image_set_ver_str_len != 0) {
1293 pending_comp_image_set_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301294 msg->payload +
1295 sizeof(struct pldm_get_firmware_parameters_resp) +
1296 resp_data->active_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301297 pending_comp_image_set_ver_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301298 resp_data->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301299 } else {
1300 pending_comp_image_set_ver_str->ptr = NULL;
1301 pending_comp_image_set_ver_str->length = 0;
1302 }
1303
1304 if (payload_length > partial_response_length && resp_data->comp_count) {
1305 comp_parameter_table->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301306 msg->payload +
1307 sizeof(struct pldm_get_firmware_parameters_resp) +
1308 resp_data->active_comp_image_set_ver_str_len +
1309 resp_data->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301310 comp_parameter_table->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301311 payload_length - partial_response_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301312 } else {
1313 comp_parameter_table->ptr = NULL;
1314 comp_parameter_table->length = 0;
1315 }
1316
1317 return PLDM_SUCCESS;
1318}
1319
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001320LIBPLDM_ABI_TESTING
1321int encode_get_firmware_parameters_resp(
1322 uint8_t instance_id,
1323 const struct pldm_get_firmware_parameters_resp_full *resp_data,
1324 struct pldm_msg *msg, size_t *payload_length)
1325{
Andrew Jefferya1896962025-03-03 21:41:25 +10301326 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001327 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001328
1329 if (resp_data == NULL || msg == NULL || payload_length == NULL) {
1330 return -EINVAL;
1331 }
1332
1333 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
1334 PLDM_GET_FIRMWARE_PARAMETERS, msg);
1335 if (rc) {
1336 return -EINVAL;
1337 }
1338
1339 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
1340 if (rc) {
1341 return rc;
1342 }
1343
1344 pldm_msgbuf_insert(buf, resp_data->completion_code);
1345 pldm_msgbuf_insert(buf, resp_data->capabilities_during_update.value);
1346 pldm_msgbuf_insert(buf, resp_data->comp_count);
1347 pldm_msgbuf_insert(buf,
1348 resp_data->active_comp_image_set_ver_str.str_type);
1349 pldm_msgbuf_insert(buf,
1350 resp_data->active_comp_image_set_ver_str.str_len);
1351 pldm_msgbuf_insert(buf,
1352 resp_data->pending_comp_image_set_ver_str.str_type);
1353 pldm_msgbuf_insert(buf,
1354 resp_data->pending_comp_image_set_ver_str.str_len);
1355 /* String data appended */
1356 rc = pldm_msgbuf_insert_array(
1357 buf, resp_data->active_comp_image_set_ver_str.str_len,
1358 resp_data->active_comp_image_set_ver_str.str_data,
1359 resp_data->active_comp_image_set_ver_str.str_len);
1360 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301361 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001362 }
1363 rc = pldm_msgbuf_insert_array(
1364 buf, resp_data->pending_comp_image_set_ver_str.str_len,
1365 resp_data->pending_comp_image_set_ver_str.str_data,
1366 resp_data->pending_comp_image_set_ver_str.str_len);
1367 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301368 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001369 }
1370
1371 /* Further calls to encode_get_firmware_parameters_resp_comp_entry
1372 * will populate the remainder */
1373
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301374 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001375}
1376
1377LIBPLDM_ABI_TESTING
1378int encode_get_firmware_parameters_resp_comp_entry(
1379 const struct pldm_component_parameter_entry_full *comp,
1380 uint8_t *payload, size_t *payload_length)
1381{
Andrew Jefferya1896962025-03-03 21:41:25 +10301382 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001383 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001384
1385 if (comp == NULL || payload == NULL || payload_length == NULL) {
1386 return -EINVAL;
1387 }
1388
1389 rc = pldm_msgbuf_init_errno(buf, 0, payload, *payload_length);
1390 if (rc) {
1391 return rc;
1392 }
1393
1394 pldm_msgbuf_insert(buf, comp->comp_classification);
1395 pldm_msgbuf_insert(buf, comp->comp_identifier);
1396 pldm_msgbuf_insert(buf, comp->comp_classification_index);
1397
1398 pldm_msgbuf_insert(buf, comp->active_ver.comparison_stamp);
1399 pldm_msgbuf_insert(buf, (uint8_t)comp->active_ver.str.str_type);
1400 pldm_msgbuf_insert(buf, comp->active_ver.str.str_len);
1401 rc = pldm_msgbuf_insert_array(buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1402 comp->active_ver.date,
1403 PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN);
1404 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301405 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001406 }
1407
1408 pldm_msgbuf_insert(buf, comp->pending_ver.comparison_stamp);
1409 pldm_msgbuf_insert(buf, (uint8_t)comp->pending_ver.str.str_type);
1410 pldm_msgbuf_insert(buf, comp->pending_ver.str.str_len);
1411 rc = pldm_msgbuf_insert_array(buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1412 comp->pending_ver.date,
1413 PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN);
1414 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301415 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001416 }
1417
1418 pldm_msgbuf_insert(buf, comp->comp_activation_methods.value);
1419 pldm_msgbuf_insert(buf, comp->capabilities_during_update.value);
1420
1421 rc = pldm_msgbuf_insert_array(buf, comp->active_ver.str.str_len,
1422 comp->active_ver.str.str_data,
1423 comp->active_ver.str.str_len);
1424 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301425 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001426 }
1427 rc = pldm_msgbuf_insert_array(buf, comp->pending_ver.str.str_len,
1428 comp->pending_ver.str.str_data,
1429 comp->pending_ver.str.str_len);
1430 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301431 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001432 }
1433
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301434 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001435}
1436
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301437LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301438int decode_get_firmware_parameters_resp_comp_entry(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301439 const uint8_t *data, size_t length,
1440 struct pldm_component_parameter_entry *component_data,
1441 struct variable_field *active_comp_ver_str,
1442 struct variable_field *pending_comp_ver_str)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301443{
1444 if (data == NULL || component_data == NULL ||
1445 active_comp_ver_str == NULL || pending_comp_ver_str == NULL) {
1446 return PLDM_ERROR_INVALID_DATA;
1447 }
1448
1449 if (length < sizeof(struct pldm_component_parameter_entry)) {
1450 return PLDM_ERROR_INVALID_LENGTH;
1451 }
1452
1453 struct pldm_component_parameter_entry *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301454 (struct pldm_component_parameter_entry *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301455
1456 size_t entry_length = sizeof(struct pldm_component_parameter_entry) +
1457 entry->active_comp_ver_str_len +
1458 entry->pending_comp_ver_str_len;
1459
1460 if (length < entry_length) {
1461 return PLDM_ERROR_INVALID_LENGTH;
1462 }
1463
1464 component_data->comp_classification =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301465 le16toh(entry->comp_classification);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301466 component_data->comp_identifier = le16toh(entry->comp_identifier);
1467 component_data->comp_classification_index =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301468 entry->comp_classification_index;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301469 component_data->active_comp_comparison_stamp =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301470 le32toh(entry->active_comp_comparison_stamp);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301471 component_data->active_comp_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301472 entry->active_comp_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301473 component_data->active_comp_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301474 entry->active_comp_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301475 memcpy(component_data->active_comp_release_date,
1476 entry->active_comp_release_date,
1477 sizeof(entry->active_comp_release_date));
1478 component_data->pending_comp_comparison_stamp =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301479 le32toh(entry->pending_comp_comparison_stamp);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301480 component_data->pending_comp_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301481 entry->pending_comp_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301482 component_data->pending_comp_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301483 entry->pending_comp_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301484 memcpy(component_data->pending_comp_release_date,
1485 entry->pending_comp_release_date,
1486 sizeof(entry->pending_comp_release_date));
1487 component_data->comp_activation_methods.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301488 le16toh(entry->comp_activation_methods.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301489 component_data->capabilities_during_update.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301490 le32toh(entry->capabilities_during_update.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301491
1492 if (entry->active_comp_ver_str_len != 0) {
1493 active_comp_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301494 data + sizeof(struct pldm_component_parameter_entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301495 active_comp_ver_str->length = entry->active_comp_ver_str_len;
1496 } else {
1497 active_comp_ver_str->ptr = NULL;
1498 active_comp_ver_str->length = 0;
1499 }
1500
1501 if (entry->pending_comp_ver_str_len != 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301502 pending_comp_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301503 data + sizeof(struct pldm_component_parameter_entry) +
1504 entry->active_comp_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301505 pending_comp_ver_str->length = entry->pending_comp_ver_str_len;
1506 } else {
1507 pending_comp_ver_str->ptr = NULL;
1508 pending_comp_ver_str->length = 0;
1509 }
1510 return PLDM_SUCCESS;
1511}
1512
Unive Tiene5c3f142024-12-13 14:14:19 +08001513LIBPLDM_ABI_STABLE
Chris Wang4c1f2c72024-03-21 17:09:44 +08001514int encode_query_downstream_devices_req(uint8_t instance_id,
1515 struct pldm_msg *msg)
1516{
1517 if (msg == NULL) {
Unive Tien71e935c2024-11-25 17:21:43 +08001518 return -EINVAL;
Chris Wang4c1f2c72024-03-21 17:09:44 +08001519 }
1520
Unive Tien71e935c2024-11-25 17:21:43 +08001521 return encode_pldm_header_only_errno(PLDM_REQUEST, instance_id,
1522 PLDM_FWUP,
1523 PLDM_QUERY_DOWNSTREAM_DEVICES,
1524 msg);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001525}
1526
Unive Tiene5c3f142024-12-13 14:14:19 +08001527LIBPLDM_ABI_STABLE
Chris Wang4c1f2c72024-03-21 17:09:44 +08001528int decode_query_downstream_devices_resp(
1529 const struct pldm_msg *msg, size_t payload_length,
1530 struct pldm_query_downstream_devices_resp *resp_data)
1531{
Andrew Jefferya1896962025-03-03 21:41:25 +10301532 PLDM_MSGBUF_DEFINE_P(buf);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001533 int rc;
1534
1535 if (msg == NULL || resp_data == NULL || !payload_length) {
Unive Tien71e935c2024-11-25 17:21:43 +08001536 return -EINVAL;
Chris Wang4c1f2c72024-03-21 17:09:44 +08001537 }
1538
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301539 rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1540 msg->payload, payload_length);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001541 if (rc) {
1542 return rc;
1543 }
1544
1545 rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1546 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301547 return pldm_msgbuf_discard(buf, rc);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001548 }
1549 if (PLDM_SUCCESS != resp_data->completion_code) {
1550 // Return the CC directly without decoding the rest of the payload
Andrew Jefferya1896962025-03-03 21:41:25 +10301551 return pldm_msgbuf_complete(buf);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001552 }
1553
1554 if (payload_length < PLDM_QUERY_DOWNSTREAM_DEVICES_RESP_BYTES) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301555 return pldm_msgbuf_discard(buf, -EBADMSG);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001556 }
1557
1558 rc = pldm_msgbuf_extract(buf,
1559 resp_data->downstream_device_update_supported);
1560 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301561 return pldm_msgbuf_discard(buf, rc);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001562 }
1563
1564 if (!is_downstream_device_update_support_valid(
1565 resp_data->downstream_device_update_supported)) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301566 return pldm_msgbuf_discard(buf, -EINVAL);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001567 }
1568
1569 pldm_msgbuf_extract(buf, resp_data->number_of_downstream_devices);
1570 pldm_msgbuf_extract(buf, resp_data->max_number_of_downstream_devices);
1571 pldm_msgbuf_extract(buf, resp_data->capabilities.value);
1572
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301573 return pldm_msgbuf_complete_consumed(buf);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001574}
1575
Unive Tiene5c3f142024-12-13 14:14:19 +08001576LIBPLDM_ABI_STABLE
Chris Wang458475a2024-03-26 17:59:19 +08001577int encode_query_downstream_identifiers_req(
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001578 uint8_t instance_id,
1579 const struct pldm_query_downstream_identifiers_req *params_req,
1580 struct pldm_msg *msg, size_t payload_length)
Chris Wang458475a2024-03-26 17:59:19 +08001581{
Andrew Jefferya1896962025-03-03 21:41:25 +10301582 PLDM_MSGBUF_DEFINE_P(buf);
Chris Wang458475a2024-03-26 17:59:19 +08001583 int rc;
1584
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001585 if (!msg || !params_req) {
Unive Tien71e935c2024-11-25 17:21:43 +08001586 return -EINVAL;
Chris Wang458475a2024-03-26 17:59:19 +08001587 }
1588
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001589 if (!is_transfer_operation_flag_valid(
1590 (enum transfer_op_flag)
1591 params_req->transfer_operation_flag)) {
Unive Tien71e935c2024-11-25 17:21:43 +08001592 return -EINVAL;
Chris Wang458475a2024-03-26 17:59:19 +08001593 }
1594
1595 struct pldm_header_info header = { 0 };
1596 header.instance = instance_id;
1597 header.msg_type = PLDM_REQUEST;
1598 header.pldm_type = PLDM_FWUP;
1599 header.command = PLDM_QUERY_DOWNSTREAM_IDENTIFIERS;
Unive Tien71e935c2024-11-25 17:21:43 +08001600 rc = pack_pldm_header_errno(&header, &(msg->hdr));
Chris Wang458475a2024-03-26 17:59:19 +08001601 if (rc) {
1602 return rc;
1603 }
1604
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301605 rc = pldm_msgbuf_init_errno(buf,
1606 PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_REQ_BYTES,
1607 msg->payload, payload_length);
Chris Wang458475a2024-03-26 17:59:19 +08001608 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001609 return rc;
Chris Wang458475a2024-03-26 17:59:19 +08001610 }
1611
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001612 pldm_msgbuf_insert(buf, params_req->data_transfer_handle);
Chris Wang458475a2024-03-26 17:59:19 +08001613 // Data correctness has been verified, cast it to 1-byte data directly.
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001614 pldm_msgbuf_insert(buf, params_req->transfer_operation_flag);
Chris Wang458475a2024-03-26 17:59:19 +08001615
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301616 return pldm_msgbuf_complete(buf);
Chris Wang458475a2024-03-26 17:59:19 +08001617}
1618
Unive Tiene5c3f142024-12-13 14:14:19 +08001619LIBPLDM_ABI_STABLE
Chris Wang458475a2024-03-26 17:59:19 +08001620int decode_query_downstream_identifiers_resp(
1621 const struct pldm_msg *msg, size_t payload_length,
1622 struct pldm_query_downstream_identifiers_resp *resp_data,
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301623 struct pldm_downstream_device_iter *iter)
Chris Wang458475a2024-03-26 17:59:19 +08001624{
Andrew Jefferya1896962025-03-03 21:41:25 +10301625 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301626 void *remaining = NULL;
Unive Tien71e935c2024-11-25 17:21:43 +08001627 int rc = 0;
Chris Wang458475a2024-03-26 17:59:19 +08001628
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301629 if (msg == NULL || resp_data == NULL || iter == NULL ||
Chris Wang458475a2024-03-26 17:59:19 +08001630 !payload_length) {
Unive Tien71e935c2024-11-25 17:21:43 +08001631 return -EINVAL;
Chris Wang458475a2024-03-26 17:59:19 +08001632 }
1633
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301634 rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1635 msg->payload, payload_length);
Chris Wang458475a2024-03-26 17:59:19 +08001636 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001637 return rc;
Chris Wang458475a2024-03-26 17:59:19 +08001638 }
1639
1640 rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1641 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301642 return pldm_msgbuf_discard(buf, rc);
Chris Wang458475a2024-03-26 17:59:19 +08001643 }
1644 if (PLDM_SUCCESS != resp_data->completion_code) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301645 return pldm_msgbuf_complete(buf);
Chris Wang458475a2024-03-26 17:59:19 +08001646 }
1647
1648 if (payload_length < PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_RESP_MIN_LEN) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301649 return pldm_msgbuf_discard(buf, -EBADMSG);
Chris Wang458475a2024-03-26 17:59:19 +08001650 }
1651
1652 pldm_msgbuf_extract(buf, resp_data->next_data_transfer_handle);
1653 pldm_msgbuf_extract(buf, resp_data->transfer_flag);
1654
1655 rc = pldm_msgbuf_extract(buf, resp_data->downstream_devices_length);
1656 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301657 return pldm_msgbuf_discard(buf, rc);
Chris Wang458475a2024-03-26 17:59:19 +08001658 }
1659
1660 pldm_msgbuf_extract(buf, resp_data->number_of_downstream_devices);
Andrew Jefferya1896962025-03-03 21:41:25 +10301661 pldm_msgbuf_span_required(buf, resp_data->downstream_devices_length,
1662 &remaining);
Chris Wang458475a2024-03-26 17:59:19 +08001663
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301664 rc = pldm_msgbuf_complete(buf);
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301665 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001666 return rc;
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301667 }
1668
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301669 iter->field.ptr = remaining;
1670 iter->field.length = resp_data->downstream_devices_length;
1671 iter->devs = resp_data->number_of_downstream_devices;
1672
Unive Tien71e935c2024-11-25 17:21:43 +08001673 return 0;
Chris Wang458475a2024-03-26 17:59:19 +08001674}
1675
Unive Tiene5c3f142024-12-13 14:14:19 +08001676LIBPLDM_ABI_STABLE
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301677int decode_pldm_downstream_device_from_iter(
1678 struct pldm_downstream_device_iter *iter,
1679 struct pldm_downstream_device *dev)
1680{
Andrew Jefferya1896962025-03-03 21:41:25 +10301681 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301682 int rc;
1683
Andrew Jefferya1896962025-03-03 21:41:25 +10301684 if (!iter || !iter->field.ptr || !dev) {
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301685 return -EINVAL;
1686 }
1687
1688 rc = pldm_msgbuf_init_errno(buf, 3, iter->field.ptr,
1689 iter->field.length);
1690 if (rc) {
1691 return rc;
1692 }
1693
1694 pldm_msgbuf_extract(buf, dev->downstream_device_index);
1695 pldm_msgbuf_extract(buf, dev->downstream_descriptor_count);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301696 pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
1697 &iter->field.length);
1698
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301699 return pldm_msgbuf_complete(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301700}
1701
Unive Tiene5c3f142024-12-13 14:14:19 +08001702LIBPLDM_ABI_STABLE
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301703int encode_get_downstream_firmware_parameters_req(
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001704 uint8_t instance_id,
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301705 const struct pldm_get_downstream_firmware_parameters_req *params_req,
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001706 struct pldm_msg *msg, size_t payload_length)
Chris Wangb6ef35b2024-07-03 09:35:42 +08001707{
Andrew Jefferya1896962025-03-03 21:41:25 +10301708 PLDM_MSGBUF_DEFINE_P(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001709 int rc;
1710
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001711 if (!msg || !params_req) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001712 return -EINVAL;
1713 }
1714
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001715 if (!is_transfer_operation_flag_valid(
1716 (enum transfer_op_flag)
1717 params_req->transfer_operation_flag)) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001718 return -EBADMSG;
1719 }
1720
1721 struct pldm_header_info header = { 0 };
1722 header.instance = instance_id;
1723 header.msg_type = PLDM_REQUEST;
1724 header.pldm_type = PLDM_FWUP;
1725 header.command = PLDM_QUERY_DOWNSTREAM_FIRMWARE_PARAMETERS;
1726 rc = pack_pldm_header_errno(&header, &msg->hdr);
1727 if (rc < 0) {
1728 return rc;
1729 }
1730
Andrew Jeffery53b08672025-03-04 12:26:18 +10301731 rc = pldm_msgbuf_init_errno(
1732 buf, PLDM_GET_DOWNSTREAM_FIRMWARE_PARAMETERS_REQ_BYTES,
1733 msg->payload, payload_length);
1734 if (rc < 0) {
1735 return rc;
1736 }
1737
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001738 pldm_msgbuf_insert(buf, params_req->data_transfer_handle);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001739 // Data correctness has been verified, cast it to 1-byte data directly.
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001740 pldm_msgbuf_insert(buf, params_req->transfer_operation_flag);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001741
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301742 return pldm_msgbuf_complete(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001743}
1744
Unive Tiene5c3f142024-12-13 14:14:19 +08001745LIBPLDM_ABI_STABLE
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301746int decode_get_downstream_firmware_parameters_resp(
Chris Wangb6ef35b2024-07-03 09:35:42 +08001747 const struct pldm_msg *msg, size_t payload_length,
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301748 struct pldm_get_downstream_firmware_parameters_resp *resp_data,
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301749 struct pldm_downstream_device_parameters_iter *iter)
Chris Wangb6ef35b2024-07-03 09:35:42 +08001750{
Andrew Jefferya1896962025-03-03 21:41:25 +10301751 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301752 void *remaining = NULL;
1753 size_t length;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001754 int rc;
1755
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301756 if (msg == NULL || resp_data == NULL || iter == NULL) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001757 return -EINVAL;
1758 }
1759
1760 rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1761 msg->payload, payload_length);
1762 if (rc < 0) {
1763 return rc;
1764 }
1765
1766 rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1767 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301768 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001769 }
1770 if (PLDM_SUCCESS != resp_data->completion_code) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301771 return pldm_msgbuf_complete(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001772 }
1773
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301774 if (payload_length <
1775 PLDM_GET_DOWNSTREAM_FIRMWARE_PARAMETERS_RESP_MIN_LEN) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301776 return pldm_msgbuf_discard(buf, -EBADMSG);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001777 }
1778
1779 pldm_msgbuf_extract(buf, resp_data->next_data_transfer_handle);
1780 pldm_msgbuf_extract(buf, resp_data->transfer_flag);
1781 pldm_msgbuf_extract(buf,
1782 resp_data->fdp_capabilities_during_update.value);
1783 pldm_msgbuf_extract(buf, resp_data->downstream_device_count);
1784
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301785 rc = pldm_msgbuf_span_remaining(buf, &remaining, &length);
1786 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301787 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301788 }
1789
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301790 rc = pldm_msgbuf_complete(buf);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301791 if (rc) {
1792 return rc;
1793 }
1794
1795 iter->field.ptr = remaining;
1796 iter->field.length = length;
1797 iter->entries = resp_data->downstream_device_count;
1798
1799 return 0;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001800}
1801
Unive Tiene5c3f142024-12-13 14:14:19 +08001802LIBPLDM_ABI_STABLE
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301803int decode_pldm_downstream_device_parameters_entry_from_iter(
1804 struct pldm_downstream_device_parameters_iter *iter,
1805 struct pldm_downstream_device_parameters_entry *entry)
Chris Wangb6ef35b2024-07-03 09:35:42 +08001806{
Andrew Jefferya1896962025-03-03 21:41:25 +10301807 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301808 void *comp_ver_str;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001809 size_t remaining;
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301810 void *cursor;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001811 int rc;
1812
Andrew Jefferya1896962025-03-03 21:41:25 +10301813 if (iter == NULL || iter->field.ptr == NULL || entry == NULL) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001814 return -EINVAL;
1815 }
1816
1817 rc = pldm_msgbuf_init_errno(
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301818 buf, PLDM_DOWNSTREAM_DEVICE_PARAMETERS_ENTRY_MIN_LEN,
1819 iter->field.ptr, iter->field.length);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001820 if (rc < 0) {
1821 return rc;
1822 }
1823
1824 pldm_msgbuf_extract(buf, entry->downstream_device_index);
1825 pldm_msgbuf_extract(buf, entry->active_comp_comparison_stamp);
1826 pldm_msgbuf_extract(buf, entry->active_comp_ver_str_type);
1827 rc = pldm_msgbuf_extract(buf, entry->active_comp_ver_str_len);
1828 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301829 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001830 }
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001831 rc = pldm_msgbuf_extract_array(buf,
1832 PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1833 entry->active_comp_release_date,
1834 sizeof(entry->active_comp_release_date));
1835 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301836 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001837 }
1838
Chris Wangb6ef35b2024-07-03 09:35:42 +08001839 // Fill the last byte with NULL character
1840 entry->active_comp_release_date[PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN] =
1841 '\0';
1842
1843 pldm_msgbuf_extract(buf, entry->pending_comp_comparison_stamp);
1844 pldm_msgbuf_extract(buf, entry->pending_comp_ver_str_type);
1845 rc = pldm_msgbuf_extract(buf, entry->pending_comp_ver_str_len);
1846 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301847 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001848 }
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001849
1850 rc = pldm_msgbuf_extract_array(
1851 buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1852 entry->pending_comp_release_date,
1853 sizeof(entry->pending_comp_release_date));
1854 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301855 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001856 }
1857
Chris Wangb6ef35b2024-07-03 09:35:42 +08001858 // Fill the last byte with NULL character
1859 entry->pending_comp_release_date[PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN] =
1860 '\0';
1861
1862 pldm_msgbuf_extract(buf, entry->comp_activation_methods.value);
1863 pldm_msgbuf_extract(buf, entry->capabilities_during_update.value);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001864
Andrew Jefferya1896962025-03-03 21:41:25 +10301865 rc = pldm_msgbuf_span_required(buf, entry->active_comp_ver_str_len,
1866 &comp_ver_str);
1867 if (rc < 0) {
1868 return pldm_msgbuf_discard(buf, rc);
1869 }
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301870 entry->active_comp_ver_str = comp_ver_str;
1871
Andrew Jefferya1896962025-03-03 21:41:25 +10301872 rc = pldm_msgbuf_span_required(buf, entry->pending_comp_ver_str_len,
1873 &comp_ver_str);
1874 if (rc < 0) {
1875 return pldm_msgbuf_discard(buf, rc);
1876 }
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301877 entry->pending_comp_ver_str = comp_ver_str;
1878
Chris Wangb6ef35b2024-07-03 09:35:42 +08001879 rc = pldm_msgbuf_span_remaining(buf, &cursor, &remaining);
1880 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301881 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001882 }
1883
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301884 iter->field.ptr = cursor;
1885 iter->field.length = remaining;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001886
Andrew Jefferya1896962025-03-03 21:41:25 +10301887 return pldm_msgbuf_complete(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001888}
1889
Sora Su06eadd02025-05-27 11:28:51 +08001890LIBPLDM_ABI_TESTING
1891int encode_request_downstream_device_update_req(
1892 uint8_t instance_id,
1893 const struct pldm_request_downstream_device_update_req *req_data,
1894 struct pldm_msg *msg, size_t *payload_length)
1895{
1896 PLDM_MSGBUF_DEFINE_P(buf);
1897 int rc;
1898
1899 if (!req_data || !msg || !payload_length ||
1900 req_data->maximum_downstream_device_transfer_size <
1901 PLDM_FWUP_BASELINE_TRANSFER_SIZE ||
1902 req_data->maximum_outstanding_transfer_requests <
1903 PLDM_FWUP_MIN_OUTSTANDING_REQ) {
1904 return -EINVAL;
1905 }
1906
1907 rc = encode_pldm_header_only_errno(
1908 PLDM_REQUEST, instance_id, PLDM_FWUP,
1909 PLDM_REQUEST_DOWNSTREAM_DEVICE_UPDATE, msg);
1910 if (rc) {
1911 return rc;
1912 }
1913
1914 rc = pldm_msgbuf_init_errno(buf,
1915 PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES,
1916 msg->payload, *payload_length);
1917 if (rc) {
1918 return rc;
1919 }
1920
1921 pldm_msgbuf_insert(buf,
1922 req_data->maximum_downstream_device_transfer_size);
1923 pldm_msgbuf_insert(buf,
1924 req_data->maximum_outstanding_transfer_requests);
1925 pldm_msgbuf_insert(buf,
1926 req_data->downstream_device_package_data_length);
1927
1928 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
1929}
1930
1931LIBPLDM_ABI_TESTING
1932int decode_request_downstream_device_update_req(
1933 const struct pldm_msg *msg, size_t payload_length,
1934 struct pldm_request_downstream_device_update_req *req)
1935{
1936 int rc;
1937 PLDM_MSGBUF_DEFINE_P(buf);
1938
1939 if (!msg || !req) {
1940 return -EINVAL;
1941 }
1942
1943 rc = pldm_msgbuf_init_errno(buf,
1944 PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES,
1945 msg->payload, payload_length);
1946 if (rc) {
1947 return rc;
1948 }
1949
1950 pldm_msgbuf_extract(buf, req->maximum_downstream_device_transfer_size);
1951 pldm_msgbuf_extract(buf, req->maximum_outstanding_transfer_requests);
1952 pldm_msgbuf_extract(buf, req->downstream_device_package_data_length);
1953
1954 return pldm_msgbuf_complete_consumed(buf);
1955}
1956
1957LIBPLDM_ABI_TESTING
1958int encode_request_downstream_device_update_resp(
1959 uint8_t instance_id,
1960 const struct pldm_request_downstream_device_update_resp *resp_data,
1961 struct pldm_msg *msg, size_t *payload_length)
1962{
1963 PLDM_MSGBUF_DEFINE_P(buf);
1964 int rc;
1965
1966 if (!resp_data || !msg || !payload_length) {
1967 return -EINVAL;
1968 }
1969
1970 rc = encode_pldm_header_only_errno(
1971 PLDM_RESPONSE, instance_id, PLDM_FWUP,
1972 PLDM_REQUEST_DOWNSTREAM_DEVICE_UPDATE, msg);
1973 if (rc) {
1974 return rc;
1975 }
1976
1977 rc = pldm_msgbuf_init_errno(
1978 buf, PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES, msg->payload,
1979 *payload_length);
1980 if (rc) {
1981 return rc;
1982 }
1983
1984 pldm_msgbuf_insert(buf, resp_data->completion_code);
1985 pldm_msgbuf_insert(buf, resp_data->downstream_device_meta_data_length);
1986 pldm_msgbuf_insert(
1987 buf, resp_data->downstream_device_will_send_get_package_data);
1988 pldm_msgbuf_insert(buf,
1989 resp_data->get_package_data_maximum_transfer_size);
1990
1991 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
1992}
1993
1994LIBPLDM_ABI_TESTING
1995int decode_request_downstream_device_update_resp(
1996 const struct pldm_msg *msg, size_t payload_length,
1997 struct pldm_request_downstream_device_update_resp *resp_data)
1998{
1999 PLDM_MSGBUF_DEFINE_P(buf);
2000 int rc;
2001
2002 if (!msg || !resp_data) {
2003 return -EINVAL;
2004 }
2005
2006 rc = pldm_msg_has_error(msg,
2007 PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES);
2008 if (rc) {
2009 resp_data->completion_code = rc;
2010 return 0;
2011 }
2012
2013 rc = pldm_msgbuf_init_errno(
2014 buf, PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES, msg->payload,
2015 payload_length);
2016 if (rc) {
2017 return rc;
2018 }
2019
2020 pldm_msgbuf_extract(buf, resp_data->completion_code);
2021 pldm_msgbuf_extract(buf, resp_data->downstream_device_meta_data_length);
2022 pldm_msgbuf_extract(
2023 buf, resp_data->downstream_device_will_send_get_package_data);
2024 pldm_msgbuf_extract(buf,
2025 resp_data->get_package_data_maximum_transfer_size);
2026
2027 return pldm_msgbuf_complete_consumed(buf);
2028}
2029
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302030LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302031int encode_request_update_req(uint8_t instance_id, uint32_t max_transfer_size,
2032 uint16_t num_of_comp,
2033 uint8_t max_outstanding_transfer_req,
2034 uint16_t pkg_data_len,
2035 uint8_t comp_image_set_ver_str_type,
2036 uint8_t comp_image_set_ver_str_len,
2037 const struct variable_field *comp_img_set_ver_str,
2038 struct pldm_msg *msg, size_t payload_length)
2039{
2040 if (comp_img_set_ver_str == NULL || comp_img_set_ver_str->ptr == NULL ||
2041 msg == NULL) {
2042 return PLDM_ERROR_INVALID_DATA;
2043 }
2044
2045 if (payload_length != sizeof(struct pldm_request_update_req) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302046 comp_img_set_ver_str->length) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302047 return PLDM_ERROR_INVALID_LENGTH;
2048 }
2049
2050 if ((comp_image_set_ver_str_len == 0) ||
2051 (comp_image_set_ver_str_len != comp_img_set_ver_str->length)) {
2052 return PLDM_ERROR_INVALID_DATA;
2053 }
2054
2055 if ((max_transfer_size < PLDM_FWUP_BASELINE_TRANSFER_SIZE) ||
2056 (max_outstanding_transfer_req < PLDM_FWUP_MIN_OUTSTANDING_REQ)) {
2057 return PLDM_ERROR_INVALID_DATA;
2058 }
2059
2060 if (!is_string_type_valid(comp_image_set_ver_str_type)) {
2061 return PLDM_ERROR_INVALID_DATA;
2062 }
2063
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302064 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302065 header.instance = instance_id;
2066 header.msg_type = PLDM_REQUEST;
2067 header.pldm_type = PLDM_FWUP;
2068 header.command = PLDM_REQUEST_UPDATE;
2069 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2070 if (rc) {
2071 return rc;
2072 }
2073
2074 struct pldm_request_update_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302075 (struct pldm_request_update_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302076
2077 request->max_transfer_size = htole32(max_transfer_size);
2078 request->num_of_comp = htole16(num_of_comp);
2079 request->max_outstanding_transfer_req = max_outstanding_transfer_req;
2080 request->pkg_data_len = htole16(pkg_data_len);
2081 request->comp_image_set_ver_str_type = comp_image_set_ver_str_type;
2082 request->comp_image_set_ver_str_len = comp_image_set_ver_str_len;
2083
2084 memcpy(msg->payload + sizeof(struct pldm_request_update_req),
2085 comp_img_set_ver_str->ptr, comp_img_set_ver_str->length);
2086
2087 return PLDM_SUCCESS;
2088}
2089
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002090LIBPLDM_ABI_TESTING
2091int decode_request_update_req(const struct pldm_msg *msg, size_t payload_length,
2092 struct pldm_request_update_req_full *req)
2093{
2094 int rc;
2095 uint8_t t;
Andrew Jefferya1896962025-03-03 21:41:25 +10302096 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002097
2098 if (msg == NULL || req == NULL) {
2099 return -EINVAL;
2100 }
2101
2102 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2103 if (rc) {
2104 return rc;
2105 }
2106
2107 pldm_msgbuf_extract(buf, req->max_transfer_size);
2108 pldm_msgbuf_extract(buf, req->num_of_comp);
2109 pldm_msgbuf_extract(buf, req->max_outstanding_transfer_req);
2110 pldm_msgbuf_extract(buf, req->pkg_data_len);
2111 rc = pldm_msgbuf_extract(buf, t);
2112 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302113 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002114 }
2115 if (t > PLDM_STR_TYPE_UTF_16BE) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302116 return pldm_msgbuf_discard(buf, -EBADMSG);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002117 }
2118 req->image_set_ver.str_type = (enum pldm_firmware_update_string_type)t;
2119 pldm_msgbuf_extract(buf, req->image_set_ver.str_len);
2120 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302121 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002122 }
2123
2124 rc = pldm_msgbuf_extract_array(buf, req->image_set_ver.str_len,
2125 req->image_set_ver.str_data,
2126 PLDM_FIRMWARE_MAX_STRING);
2127 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302128 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002129 }
2130
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302131 return pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002132}
2133
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302134LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302135int decode_request_update_resp(const struct pldm_msg *msg,
2136 size_t payload_length, uint8_t *completion_code,
2137 uint16_t *fd_meta_data_len,
2138 uint8_t *fd_will_send_pkg_data)
2139{
2140 if (msg == NULL || completion_code == NULL ||
2141 fd_meta_data_len == NULL || fd_will_send_pkg_data == NULL ||
2142 !payload_length) {
2143 return PLDM_ERROR_INVALID_DATA;
2144 }
2145
2146 *completion_code = msg->payload[0];
2147 if (*completion_code != PLDM_SUCCESS) {
2148 return PLDM_SUCCESS;
2149 }
2150
2151 if (payload_length != sizeof(struct pldm_request_update_resp)) {
2152 return PLDM_ERROR_INVALID_LENGTH;
2153 }
2154
2155 struct pldm_request_update_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302156 (struct pldm_request_update_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302157
2158 *fd_meta_data_len = le16toh(response->fd_meta_data_len);
2159 *fd_will_send_pkg_data = response->fd_will_send_pkg_data;
2160
2161 return PLDM_SUCCESS;
2162}
2163
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002164LIBPLDM_ABI_TESTING
2165int encode_request_update_resp(uint8_t instance_id,
2166 const struct pldm_request_update_resp *resp_data,
2167 struct pldm_msg *msg, size_t *payload_length)
2168{
Andrew Jefferya1896962025-03-03 21:41:25 +10302169 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002170 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002171
2172 if (msg == NULL || payload_length == NULL) {
2173 return -EINVAL;
2174 }
2175
2176 struct pldm_header_info header = {
2177 .instance = instance_id,
2178 .msg_type = PLDM_RESPONSE,
2179 .pldm_type = PLDM_FWUP,
2180 .command = PLDM_REQUEST_UPDATE,
2181 };
2182 rc = pack_pldm_header(&header, &(msg->hdr));
2183 if (rc) {
2184 return -EINVAL;
2185 }
2186
2187 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2188 if (rc) {
2189 return rc;
2190 }
2191
2192 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2193 pldm_msgbuf_insert(buf, resp_data->fd_meta_data_len);
2194 pldm_msgbuf_insert(buf, resp_data->fd_will_send_pkg_data);
2195
2196 /* TODO: DSP0267 1.3.0 adds GetPackageDataMaximumTransferSize */
2197
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302198 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002199}
2200
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302201LIBPLDM_ABI_STABLE
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302202int encode_pass_component_table_req(uint8_t instance_id, uint8_t transfer_flag,
2203 uint16_t comp_classification,
2204 uint16_t comp_identifier,
2205 uint8_t comp_classification_index,
2206 uint32_t comp_comparison_stamp,
2207 uint8_t comp_ver_str_type,
2208 uint8_t comp_ver_str_len,
2209 const struct variable_field *comp_ver_str,
2210 struct pldm_msg *msg, size_t payload_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09302211{
2212 if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) {
2213 return PLDM_ERROR_INVALID_DATA;
2214 }
2215
2216 if (payload_length != sizeof(struct pldm_pass_component_table_req) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302217 comp_ver_str->length) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302218 return PLDM_ERROR_INVALID_LENGTH;
2219 }
2220
2221 if ((comp_ver_str_len == 0) ||
2222 (comp_ver_str_len != comp_ver_str->length)) {
2223 return PLDM_ERROR_INVALID_DATA;
2224 }
2225
2226 if (!is_transfer_flag_valid(transfer_flag)) {
Manojkiran Eda3643e742025-05-19 12:03:54 +05302227 return PLDM_FWUP_INVALID_TRANSFER_OPERATION_FLAG;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302228 }
2229
2230 if (!is_string_type_valid(comp_ver_str_type)) {
2231 return PLDM_ERROR_INVALID_DATA;
2232 }
2233
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302234 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302235 header.instance = instance_id;
2236 header.msg_type = PLDM_REQUEST;
2237 header.pldm_type = PLDM_FWUP;
2238 header.command = PLDM_PASS_COMPONENT_TABLE;
2239 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2240 if (rc) {
2241 return rc;
2242 }
2243
2244 struct pldm_pass_component_table_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302245 (struct pldm_pass_component_table_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302246
2247 request->transfer_flag = transfer_flag;
2248 request->comp_classification = htole16(comp_classification);
2249 request->comp_identifier = htole16(comp_identifier);
2250 request->comp_classification_index = comp_classification_index;
2251 request->comp_comparison_stamp = htole32(comp_comparison_stamp);
2252 request->comp_ver_str_type = comp_ver_str_type;
2253 request->comp_ver_str_len = comp_ver_str_len;
2254
2255 memcpy(msg->payload + sizeof(struct pldm_pass_component_table_req),
2256 comp_ver_str->ptr, comp_ver_str->length);
2257
2258 return PLDM_SUCCESS;
2259}
2260
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002261LIBPLDM_ABI_TESTING
2262int decode_pass_component_table_req(
2263 const struct pldm_msg *msg, size_t payload_length,
2264 struct pldm_pass_component_table_req_full *pcomp)
2265{
2266 int rc;
2267 uint8_t t;
Andrew Jefferya1896962025-03-03 21:41:25 +10302268 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002269
2270 if (msg == NULL || pcomp == NULL) {
2271 return -EINVAL;
2272 }
2273
2274 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2275 if (rc) {
2276 return rc;
2277 }
2278
2279 pldm_msgbuf_extract(buf, pcomp->transfer_flag);
2280 pldm_msgbuf_extract(buf, pcomp->comp_classification);
2281 pldm_msgbuf_extract(buf, pcomp->comp_identifier);
2282 pldm_msgbuf_extract(buf, pcomp->comp_classification_index);
2283 pldm_msgbuf_extract(buf, pcomp->comp_comparison_stamp);
2284 rc = pldm_msgbuf_extract(buf, t);
2285 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302286 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002287 }
2288 if (t > PLDM_STR_TYPE_UTF_16BE) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302289 return pldm_msgbuf_discard(buf, -EBADMSG);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002290 }
2291 pcomp->version.str_type = (enum pldm_firmware_update_string_type)t;
2292 rc = pldm_msgbuf_extract(buf, pcomp->version.str_len);
2293 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302294 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002295 }
2296 rc = pldm_msgbuf_extract_array(buf, pcomp->version.str_len,
2297 pcomp->version.str_data,
2298 PLDM_FIRMWARE_MAX_STRING);
2299 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302300 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002301 }
2302
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302303 return pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002304}
2305
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302306LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302307int decode_pass_component_table_resp(const struct pldm_msg *msg,
2308 const size_t payload_length,
2309 uint8_t *completion_code,
2310 uint8_t *comp_resp,
2311 uint8_t *comp_resp_code)
2312{
2313 if (msg == NULL || completion_code == NULL || comp_resp == NULL ||
2314 comp_resp_code == NULL || !payload_length) {
2315 return PLDM_ERROR_INVALID_DATA;
2316 }
2317
2318 *completion_code = msg->payload[0];
2319 if (*completion_code != PLDM_SUCCESS) {
2320 return PLDM_SUCCESS;
2321 }
2322
2323 if (payload_length != sizeof(struct pldm_pass_component_table_resp)) {
2324 return PLDM_ERROR_INVALID_LENGTH;
2325 }
2326
2327 struct pldm_pass_component_table_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302328 (struct pldm_pass_component_table_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302329
2330 if (!is_comp_resp_valid(response->comp_resp)) {
2331 return PLDM_ERROR_INVALID_DATA;
2332 }
2333
2334 if (!is_comp_resp_code_valid(response->comp_resp_code)) {
2335 return PLDM_ERROR_INVALID_DATA;
2336 }
2337
2338 *comp_resp = response->comp_resp;
2339 *comp_resp_code = response->comp_resp_code;
2340
2341 return PLDM_SUCCESS;
2342}
2343
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002344LIBPLDM_ABI_TESTING
2345int encode_pass_component_table_resp(
2346 uint8_t instance_id,
2347 const struct pldm_pass_component_table_resp *resp_data,
2348 struct pldm_msg *msg, size_t *payload_length)
2349{
Andrew Jefferya1896962025-03-03 21:41:25 +10302350 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002351 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002352
2353 if (msg == NULL || payload_length == NULL) {
2354 return -EINVAL;
2355 }
2356
2357 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2358 PLDM_PASS_COMPONENT_TABLE, msg);
2359 if (rc) {
2360 return -EINVAL;
2361 }
2362
2363 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2364 if (rc) {
2365 return rc;
2366 }
2367
2368 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2369 pldm_msgbuf_insert(buf, resp_data->comp_resp);
2370 pldm_msgbuf_insert(buf, resp_data->comp_resp_code);
2371
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302372 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002373}
2374
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302375LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302376int encode_update_component_req(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302377 uint8_t instance_id, uint16_t comp_classification,
2378 uint16_t comp_identifier, uint8_t comp_classification_index,
2379 uint32_t comp_comparison_stamp, uint32_t comp_image_size,
2380 bitfield32_t update_option_flags, uint8_t comp_ver_str_type,
2381 uint8_t comp_ver_str_len, const struct variable_field *comp_ver_str,
2382 struct pldm_msg *msg, size_t payload_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09302383{
2384 if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) {
2385 return PLDM_ERROR_INVALID_DATA;
2386 }
2387
2388 if (payload_length !=
2389 sizeof(struct pldm_update_component_req) + comp_ver_str->length) {
2390 return PLDM_ERROR_INVALID_LENGTH;
2391 }
2392
2393 if (!comp_image_size) {
2394 return PLDM_ERROR_INVALID_DATA;
2395 }
2396
2397 if ((comp_ver_str_len == 0) ||
2398 (comp_ver_str_len != comp_ver_str->length)) {
2399 return PLDM_ERROR_INVALID_DATA;
2400 }
2401
2402 if (!is_string_type_valid(comp_ver_str_type)) {
2403 return PLDM_ERROR_INVALID_DATA;
2404 }
2405
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302406 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302407 header.instance = instance_id;
2408 header.msg_type = PLDM_REQUEST;
2409 header.pldm_type = PLDM_FWUP;
2410 header.command = PLDM_UPDATE_COMPONENT;
2411 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2412 if (rc) {
2413 return rc;
2414 }
2415
2416 struct pldm_update_component_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302417 (struct pldm_update_component_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302418
2419 request->comp_classification = htole16(comp_classification);
2420 request->comp_identifier = htole16(comp_identifier);
2421 request->comp_classification_index = comp_classification_index;
2422 request->comp_comparison_stamp = htole32(comp_comparison_stamp);
2423 request->comp_image_size = htole32(comp_image_size);
2424 request->update_option_flags.value = htole32(update_option_flags.value);
2425 request->comp_ver_str_type = comp_ver_str_type;
2426 request->comp_ver_str_len = comp_ver_str_len;
2427
2428 memcpy(msg->payload + sizeof(struct pldm_update_component_req),
2429 comp_ver_str->ptr, comp_ver_str->length);
2430
2431 return PLDM_SUCCESS;
2432}
2433
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002434LIBPLDM_ABI_TESTING
2435int decode_update_component_req(const struct pldm_msg *msg,
2436 size_t payload_length,
2437 struct pldm_update_component_req_full *up)
2438{
2439 int rc;
2440 uint8_t t;
Andrew Jefferya1896962025-03-03 21:41:25 +10302441 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002442
2443 if (msg == NULL || up == NULL) {
2444 return -EINVAL;
2445 }
2446
2447 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2448 if (rc) {
2449 return rc;
2450 }
2451
2452 pldm_msgbuf_extract(buf, up->comp_classification);
2453 pldm_msgbuf_extract(buf, up->comp_identifier);
2454 pldm_msgbuf_extract(buf, up->comp_classification_index);
2455 pldm_msgbuf_extract(buf, up->comp_comparison_stamp);
2456 pldm_msgbuf_extract(buf, up->comp_image_size);
2457 pldm_msgbuf_extract(buf, up->update_option_flags.value);
2458 rc = pldm_msgbuf_extract(buf, t);
2459 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302460 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002461 }
2462 if (t > PLDM_STR_TYPE_UTF_16BE) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302463 return pldm_msgbuf_discard(buf, -EBADMSG);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002464 }
2465 up->version.str_type = (enum pldm_firmware_update_string_type)t;
2466 rc = pldm_msgbuf_extract(buf, up->version.str_len);
2467 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302468 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002469 }
2470 rc = pldm_msgbuf_extract_array(buf, up->version.str_len,
2471 up->version.str_data,
2472 PLDM_FIRMWARE_MAX_STRING);
2473 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302474 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002475 }
2476
Andrew Jefferya1896962025-03-03 21:41:25 +10302477 return pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002478}
2479
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302480LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302481int decode_update_component_resp(const struct pldm_msg *msg,
2482 size_t payload_length,
2483 uint8_t *completion_code,
2484 uint8_t *comp_compatibility_resp,
2485 uint8_t *comp_compatibility_resp_code,
2486 bitfield32_t *update_option_flags_enabled,
2487 uint16_t *time_before_req_fw_data)
2488{
2489 if (msg == NULL || completion_code == NULL ||
2490 comp_compatibility_resp == NULL ||
2491 comp_compatibility_resp_code == NULL ||
2492 update_option_flags_enabled == NULL ||
2493 time_before_req_fw_data == NULL || !payload_length) {
2494 return PLDM_ERROR_INVALID_DATA;
2495 }
2496
2497 *completion_code = msg->payload[0];
2498 if (*completion_code != PLDM_SUCCESS) {
2499 return PLDM_SUCCESS;
2500 }
2501
2502 if (payload_length != sizeof(struct pldm_update_component_resp)) {
2503 return PLDM_ERROR_INVALID_LENGTH;
2504 }
2505
2506 struct pldm_update_component_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302507 (struct pldm_update_component_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302508
2509 if (!is_comp_compatibility_resp_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302510 response->comp_compatibility_resp)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302511 return PLDM_ERROR_INVALID_DATA;
2512 }
2513
2514 if (!is_comp_compatibility_resp_code_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302515 response->comp_compatibility_resp_code)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302516 return PLDM_ERROR_INVALID_DATA;
2517 }
2518
2519 *comp_compatibility_resp = response->comp_compatibility_resp;
2520 *comp_compatibility_resp_code = response->comp_compatibility_resp_code;
2521 update_option_flags_enabled->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302522 le32toh(response->update_option_flags_enabled.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302523 *time_before_req_fw_data = le16toh(response->time_before_req_fw_data);
2524
2525 return PLDM_SUCCESS;
2526}
2527
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002528LIBPLDM_ABI_TESTING
2529int encode_update_component_resp(
2530 uint8_t instance_id, const struct pldm_update_component_resp *resp_data,
2531 struct pldm_msg *msg, size_t *payload_length)
2532{
Andrew Jefferya1896962025-03-03 21:41:25 +10302533 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002534 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002535
2536 if (msg == NULL || payload_length == NULL) {
2537 return -EINVAL;
2538 }
2539
2540 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2541 PLDM_UPDATE_COMPONENT, msg);
2542 if (rc) {
2543 return -EINVAL;
2544 }
2545
2546 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2547 if (rc) {
2548 return rc;
2549 }
2550
2551 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2552 pldm_msgbuf_insert(buf, resp_data->comp_compatibility_resp);
2553 pldm_msgbuf_insert(buf, resp_data->comp_compatibility_resp_code);
2554 pldm_msgbuf_insert(buf, resp_data->update_option_flags_enabled.value);
2555 pldm_msgbuf_insert(buf, resp_data->time_before_req_fw_data);
2556
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302557 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002558}
2559
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302560LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302561int decode_request_firmware_data_req(const struct pldm_msg *msg,
2562 size_t payload_length, uint32_t *offset,
2563 uint32_t *length)
2564{
2565 if (msg == NULL || offset == NULL || length == NULL) {
2566 return PLDM_ERROR_INVALID_DATA;
2567 }
2568 if (payload_length != sizeof(struct pldm_request_firmware_data_req)) {
2569 return PLDM_ERROR_INVALID_LENGTH;
2570 }
2571 struct pldm_request_firmware_data_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302572 (struct pldm_request_firmware_data_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302573 *offset = le32toh(request->offset);
2574 *length = le32toh(request->length);
2575
2576 if (*length < PLDM_FWUP_BASELINE_TRANSFER_SIZE) {
2577 return PLDM_FWUP_INVALID_TRANSFER_LENGTH;
2578 }
2579
2580 return PLDM_SUCCESS;
2581}
2582
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002583LIBPLDM_ABI_TESTING
2584int encode_request_firmware_data_req(
2585 uint8_t instance_id,
2586 const struct pldm_request_firmware_data_req *req_params,
2587 struct pldm_msg *msg, size_t *payload_length)
2588{
Andrew Jefferya1896962025-03-03 21:41:25 +10302589 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002590 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002591
2592 if (msg == NULL || payload_length == NULL) {
2593 return -EINVAL;
2594 }
2595
2596 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2597 PLDM_REQUEST_FIRMWARE_DATA, msg);
2598 if (rc) {
2599 return -EINVAL;
2600 }
2601
2602 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2603 if (rc) {
2604 return rc;
2605 }
2606
2607 pldm_msgbuf_insert(buf, req_params->offset);
2608 pldm_msgbuf_insert(buf, req_params->length);
2609
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302610 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002611}
2612
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302613LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302614int encode_request_firmware_data_resp(uint8_t instance_id,
2615 uint8_t completion_code,
2616 struct pldm_msg *msg,
2617 size_t payload_length)
2618{
2619 if (msg == NULL || !payload_length) {
2620 return PLDM_ERROR_INVALID_DATA;
2621 }
2622
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302623 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302624 header.instance = instance_id;
2625 header.msg_type = PLDM_RESPONSE;
2626 header.pldm_type = PLDM_FWUP;
2627 header.command = PLDM_REQUEST_FIRMWARE_DATA;
2628 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2629 if (rc) {
2630 return rc;
2631 }
2632
2633 msg->payload[0] = completion_code;
2634
2635 return PLDM_SUCCESS;
2636}
2637
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302638LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302639int decode_transfer_complete_req(const struct pldm_msg *msg,
2640 size_t payload_length,
2641 uint8_t *transfer_result)
2642{
2643 if (msg == NULL || transfer_result == NULL) {
2644 return PLDM_ERROR_INVALID_DATA;
2645 }
2646
2647 if (payload_length != sizeof(*transfer_result)) {
2648 return PLDM_ERROR_INVALID_LENGTH;
2649 }
2650
2651 *transfer_result = msg->payload[0];
2652 return PLDM_SUCCESS;
2653}
2654
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002655LIBPLDM_ABI_TESTING
2656int encode_transfer_complete_req(uint8_t instance_id, uint8_t transfer_result,
2657 struct pldm_msg *msg, size_t *payload_length)
2658{
Andrew Jefferya1896962025-03-03 21:41:25 +10302659 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002660 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002661
2662 if (msg == NULL || payload_length == NULL) {
2663 return -EINVAL;
2664 }
2665
2666 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2667 PLDM_TRANSFER_COMPLETE, msg);
2668 if (rc) {
2669 return -EINVAL;
2670 }
2671
2672 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2673 if (rc) {
2674 return rc;
2675 }
2676
Andrew Jefferya1896962025-03-03 21:41:25 +10302677 pldm_msgbuf_insert(buf, transfer_result);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002678
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302679 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002680}
2681
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302682LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302683int encode_transfer_complete_resp(uint8_t instance_id, uint8_t completion_code,
2684 struct pldm_msg *msg, size_t payload_length)
2685{
2686 if (msg == NULL) {
2687 return PLDM_ERROR_INVALID_DATA;
2688 }
2689
2690 if (payload_length != sizeof(completion_code)) {
2691 return PLDM_ERROR_INVALID_LENGTH;
2692 }
2693
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302694 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302695 header.instance = instance_id;
2696 header.msg_type = PLDM_RESPONSE;
2697 header.pldm_type = PLDM_FWUP;
2698 header.command = PLDM_TRANSFER_COMPLETE;
2699 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2700 if (rc) {
2701 return rc;
2702 }
2703
2704 msg->payload[0] = completion_code;
2705
2706 return PLDM_SUCCESS;
2707}
2708
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302709LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302710int decode_verify_complete_req(const struct pldm_msg *msg,
2711 size_t payload_length, uint8_t *verify_result)
2712{
2713 if (msg == NULL || verify_result == NULL) {
2714 return PLDM_ERROR_INVALID_DATA;
2715 }
2716
2717 if (payload_length != sizeof(*verify_result)) {
2718 return PLDM_ERROR_INVALID_LENGTH;
2719 }
2720
2721 *verify_result = msg->payload[0];
2722 return PLDM_SUCCESS;
2723}
2724
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002725LIBPLDM_ABI_TESTING
2726int encode_verify_complete_req(uint8_t instance_id, uint8_t verify_result,
2727 struct pldm_msg *msg, size_t *payload_length)
2728{
Andrew Jefferya1896962025-03-03 21:41:25 +10302729 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002730 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002731
2732 if (msg == NULL || payload_length == NULL) {
2733 return -EINVAL;
2734 }
2735
2736 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2737 PLDM_VERIFY_COMPLETE, msg);
2738 if (rc) {
2739 return EINVAL;
2740 }
2741
2742 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2743 if (rc) {
2744 return rc;
2745 }
2746
Andrew Jefferya1896962025-03-03 21:41:25 +10302747 pldm_msgbuf_insert(buf, verify_result);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002748
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302749 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002750}
2751
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302752LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302753int encode_verify_complete_resp(uint8_t instance_id, uint8_t completion_code,
2754 struct pldm_msg *msg, size_t payload_length)
2755{
2756 if (msg == NULL) {
2757 return PLDM_ERROR_INVALID_DATA;
2758 }
2759
2760 if (payload_length != sizeof(completion_code)) {
2761 return PLDM_ERROR_INVALID_LENGTH;
2762 }
2763
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302764 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302765 header.instance = instance_id;
2766 header.msg_type = PLDM_RESPONSE;
2767 header.pldm_type = PLDM_FWUP;
2768 header.command = PLDM_VERIFY_COMPLETE;
2769 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2770 if (rc) {
2771 return rc;
2772 }
2773
2774 msg->payload[0] = completion_code;
2775
2776 return PLDM_SUCCESS;
2777}
2778
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302779LIBPLDM_ABI_STABLE
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302780int decode_apply_complete_req(const struct pldm_msg *msg, size_t payload_length,
2781 uint8_t *apply_result,
2782 bitfield16_t *comp_activation_methods_modification)
Andrew Jeffery9c766792022-08-10 23:12:49 +09302783{
2784 if (msg == NULL || apply_result == NULL ||
2785 comp_activation_methods_modification == NULL) {
2786 return PLDM_ERROR_INVALID_DATA;
2787 }
2788
2789 if (payload_length != sizeof(struct pldm_apply_complete_req)) {
2790 return PLDM_ERROR_INVALID_LENGTH;
2791 }
2792
2793 struct pldm_apply_complete_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302794 (struct pldm_apply_complete_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302795
2796 *apply_result = request->apply_result;
2797 comp_activation_methods_modification->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302798 le16toh(request->comp_activation_methods_modification.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302799
2800 if ((*apply_result != PLDM_FWUP_APPLY_SUCCESS_WITH_ACTIVATION_METHOD) &&
2801 comp_activation_methods_modification->value) {
2802 return PLDM_ERROR_INVALID_DATA;
2803 }
2804
2805 return PLDM_SUCCESS;
2806}
2807
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002808LIBPLDM_ABI_TESTING
2809int encode_apply_complete_req(uint8_t instance_id,
2810 const struct pldm_apply_complete_req *req_data,
2811 struct pldm_msg *msg, size_t *payload_length)
2812{
Andrew Jefferya1896962025-03-03 21:41:25 +10302813 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002814 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002815
2816 if (msg == NULL || payload_length == NULL) {
2817 return -EINVAL;
2818 }
2819
2820 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2821 PLDM_APPLY_COMPLETE, msg);
2822 if (rc) {
2823 return -EINVAL;
2824 }
2825
2826 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2827 if (rc) {
2828 return rc;
2829 }
2830
2831 pldm_msgbuf_insert(buf, req_data->apply_result);
2832 pldm_msgbuf_insert(
2833 buf, req_data->comp_activation_methods_modification.value);
2834
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302835 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002836}
2837
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302838LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302839int encode_apply_complete_resp(uint8_t instance_id, uint8_t completion_code,
2840 struct pldm_msg *msg, size_t payload_length)
2841{
2842 if (msg == NULL) {
2843 return PLDM_ERROR_INVALID_DATA;
2844 }
2845
2846 if (payload_length != sizeof(completion_code)) {
2847 return PLDM_ERROR_INVALID_LENGTH;
2848 }
2849
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302850 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302851 header.instance = instance_id;
2852 header.msg_type = PLDM_RESPONSE;
2853 header.pldm_type = PLDM_FWUP;
2854 header.command = PLDM_APPLY_COMPLETE;
2855 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2856 if (rc) {
2857 return rc;
2858 }
2859
2860 msg->payload[0] = completion_code;
2861
2862 return PLDM_SUCCESS;
2863}
2864
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002865LIBPLDM_ABI_TESTING
2866int decode_activate_firmware_req(const struct pldm_msg *msg,
2867 size_t payload_length, bool *self_contained)
2868{
Andrew Jefferya1896962025-03-03 21:41:25 +10302869 uint8_t self_contained_u8 = 0;
2870 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002871 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002872
2873 if (msg == NULL || self_contained == NULL) {
2874 return -EINVAL;
2875 }
2876
2877 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2878 if (rc) {
2879 return 0;
2880 }
2881
Andrew Jefferya1896962025-03-03 21:41:25 +10302882 pldm_msgbuf_extract(buf, self_contained_u8);
2883
2884 rc = pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002885 if (rc) {
2886 return rc;
2887 }
Andrew Jefferya1896962025-03-03 21:41:25 +10302888
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002889 *self_contained = (bool)self_contained_u8;
2890 return 0;
2891}
2892
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302893LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302894int encode_activate_firmware_req(uint8_t instance_id,
2895 bool8_t self_contained_activation_req,
2896 struct pldm_msg *msg, size_t payload_length)
2897{
2898 if (msg == NULL) {
2899 return PLDM_ERROR_INVALID_DATA;
2900 }
2901
2902 if (payload_length != sizeof(struct pldm_activate_firmware_req)) {
2903 return PLDM_ERROR_INVALID_LENGTH;
2904 }
2905
2906 if (!is_self_contained_activation_req_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302907 self_contained_activation_req)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302908 return PLDM_ERROR_INVALID_DATA;
2909 }
2910
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302911 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302912 header.instance = instance_id;
2913 header.msg_type = PLDM_REQUEST;
2914 header.pldm_type = PLDM_FWUP;
2915 header.command = PLDM_ACTIVATE_FIRMWARE;
2916 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2917 if (rc) {
2918 return rc;
2919 }
2920
2921 struct pldm_activate_firmware_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302922 (struct pldm_activate_firmware_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302923
2924 request->self_contained_activation_req = self_contained_activation_req;
2925
2926 return PLDM_SUCCESS;
2927}
2928
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302929LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302930int decode_activate_firmware_resp(const struct pldm_msg *msg,
2931 size_t payload_length,
2932 uint8_t *completion_code,
2933 uint16_t *estimated_time_activation)
2934{
2935 if (msg == NULL || completion_code == NULL ||
2936 estimated_time_activation == NULL || !payload_length) {
2937 return PLDM_ERROR_INVALID_DATA;
2938 }
2939
2940 *completion_code = msg->payload[0];
2941 if (*completion_code != PLDM_SUCCESS) {
2942 return PLDM_SUCCESS;
2943 }
2944
2945 if (payload_length != sizeof(struct pldm_activate_firmware_resp)) {
2946 return PLDM_ERROR_INVALID_LENGTH;
2947 }
2948
2949 struct pldm_activate_firmware_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302950 (struct pldm_activate_firmware_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302951
2952 *estimated_time_activation =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302953 le16toh(response->estimated_time_activation);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302954
2955 return PLDM_SUCCESS;
2956}
2957
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002958LIBPLDM_ABI_TESTING
2959int encode_activate_firmware_resp(
2960 uint8_t instance_id,
2961 const struct pldm_activate_firmware_resp *resp_data,
2962 struct pldm_msg *msg, size_t *payload_length)
2963{
Andrew Jefferya1896962025-03-03 21:41:25 +10302964 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002965 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002966
2967 if (msg == NULL || payload_length == NULL) {
2968 return -EINVAL;
2969 }
2970
2971 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2972 PLDM_ACTIVATE_FIRMWARE, msg);
2973 if (rc) {
2974 return -EINVAL;
2975 }
2976
2977 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2978 if (rc) {
2979 return rc;
2980 }
2981
2982 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2983 pldm_msgbuf_insert(buf, resp_data->estimated_time_activation);
2984
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302985 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002986}
2987
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302988LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302989int encode_get_status_req(uint8_t instance_id, struct pldm_msg *msg,
2990 size_t payload_length)
2991{
2992 if (msg == NULL) {
2993 return PLDM_ERROR_INVALID_DATA;
2994 }
2995
2996 if (payload_length != PLDM_GET_STATUS_REQ_BYTES) {
2997 return PLDM_ERROR_INVALID_LENGTH;
2998 }
2999
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303000 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09303001 header.instance = instance_id;
3002 header.msg_type = PLDM_REQUEST;
3003 header.pldm_type = PLDM_FWUP;
3004 header.command = PLDM_GET_STATUS;
3005 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
3006 if (rc) {
3007 return rc;
3008 }
3009
3010 return PLDM_SUCCESS;
3011}
3012
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09303013LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09303014int decode_get_status_resp(const struct pldm_msg *msg, size_t payload_length,
3015 uint8_t *completion_code, uint8_t *current_state,
3016 uint8_t *previous_state, uint8_t *aux_state,
3017 uint8_t *aux_state_status, uint8_t *progress_percent,
3018 uint8_t *reason_code,
3019 bitfield32_t *update_option_flags_enabled)
3020{
3021 if (msg == NULL || completion_code == NULL || current_state == NULL ||
3022 previous_state == NULL || aux_state == NULL ||
3023 aux_state_status == NULL || progress_percent == NULL ||
3024 reason_code == NULL || update_option_flags_enabled == NULL ||
3025 !payload_length) {
3026 return PLDM_ERROR_INVALID_DATA;
3027 }
3028
3029 *completion_code = msg->payload[0];
3030 if (*completion_code != PLDM_SUCCESS) {
3031 return PLDM_SUCCESS;
3032 }
3033
3034 if (payload_length != sizeof(struct pldm_get_status_resp)) {
3035 return PLDM_ERROR_INVALID_LENGTH;
3036 }
3037 struct pldm_get_status_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303038 (struct pldm_get_status_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09303039
3040 if (!is_state_valid(response->current_state)) {
3041 return PLDM_ERROR_INVALID_DATA;
3042 }
3043 if (!is_state_valid(response->previous_state)) {
3044 return PLDM_ERROR_INVALID_DATA;
3045 }
3046 if (!is_aux_state_valid(response->aux_state)) {
3047 return PLDM_ERROR_INVALID_DATA;
3048 }
3049 if (!is_aux_state_status_valid(response->aux_state_status)) {
3050 return PLDM_ERROR_INVALID_DATA;
3051 }
3052 if (response->progress_percent > PLDM_FWUP_MAX_PROGRESS_PERCENT) {
3053 return PLDM_ERROR_INVALID_DATA;
3054 }
3055 if (!is_reason_code_valid(response->reason_code)) {
3056 return PLDM_ERROR_INVALID_DATA;
3057 }
3058
3059 if ((response->current_state == PLDM_FD_STATE_IDLE) ||
3060 (response->current_state == PLDM_FD_STATE_LEARN_COMPONENTS) ||
3061 (response->current_state == PLDM_FD_STATE_READY_XFER)) {
3062 if (response->aux_state !=
3063 PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER) {
3064 return PLDM_ERROR_INVALID_DATA;
3065 }
3066 }
3067
3068 *current_state = response->current_state;
3069 *previous_state = response->previous_state;
3070 *aux_state = response->aux_state;
3071 *aux_state_status = response->aux_state_status;
3072 *progress_percent = response->progress_percent;
3073 *reason_code = response->reason_code;
3074 update_option_flags_enabled->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303075 le32toh(response->update_option_flags_enabled.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09303076
3077 return PLDM_SUCCESS;
3078}
3079
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003080LIBPLDM_ABI_TESTING
3081int encode_get_status_resp(uint8_t instance_id,
3082 const struct pldm_get_status_resp *status,
3083 struct pldm_msg *msg, size_t *payload_length)
3084{
Andrew Jefferya1896962025-03-03 21:41:25 +10303085 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003086 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003087
3088 if (status == NULL || msg == NULL || payload_length == NULL) {
3089 return -EINVAL;
3090 }
3091
3092 if (status->completion_code != PLDM_SUCCESS) {
3093 return -EINVAL;
3094 }
3095
3096 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
3097 PLDM_GET_STATUS, msg);
3098 if (rc) {
3099 return -EINVAL;
3100 }
3101
3102 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
3103 if (rc) {
3104 return rc;
3105 }
3106
3107 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
3108 pldm_msgbuf_insert(buf, status->current_state);
3109 pldm_msgbuf_insert(buf, status->previous_state);
3110 pldm_msgbuf_insert(buf, status->aux_state);
3111 pldm_msgbuf_insert(buf, status->aux_state_status);
3112 pldm_msgbuf_insert(buf, status->progress_percent);
3113 pldm_msgbuf_insert(buf, status->reason_code);
3114 pldm_msgbuf_insert(buf, status->update_option_flags_enabled.value);
3115
Andrew Jeffery70d21c92025-03-05 12:59:42 +10303116 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003117}
3118
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09303119LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09303120int encode_cancel_update_component_req(uint8_t instance_id,
3121 struct pldm_msg *msg,
3122 size_t payload_length)
3123{
3124 if (msg == NULL) {
3125 return PLDM_ERROR_INVALID_DATA;
3126 }
3127
3128 if (payload_length != PLDM_CANCEL_UPDATE_COMPONENT_REQ_BYTES) {
3129 return PLDM_ERROR_INVALID_LENGTH;
3130 }
3131
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303132 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09303133 header.instance = instance_id;
3134 header.msg_type = PLDM_REQUEST;
3135 header.pldm_type = PLDM_FWUP;
3136 header.command = PLDM_CANCEL_UPDATE_COMPONENT;
3137 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
3138 if (rc) {
3139 return rc;
3140 }
3141
3142 return PLDM_SUCCESS;
3143}
3144
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09303145LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09303146int decode_cancel_update_component_resp(const struct pldm_msg *msg,
3147 size_t payload_length,
3148 uint8_t *completion_code)
3149{
3150 if (msg == NULL || completion_code == NULL) {
3151 return PLDM_ERROR_INVALID_DATA;
3152 }
3153
3154 if (payload_length != sizeof(*completion_code)) {
3155 return PLDM_ERROR_INVALID_LENGTH;
3156 }
3157
3158 *completion_code = msg->payload[0];
3159 return PLDM_SUCCESS;
3160}
3161
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09303162LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09303163int encode_cancel_update_req(uint8_t instance_id, struct pldm_msg *msg,
3164 size_t payload_length)
3165{
3166 if (msg == NULL) {
3167 return PLDM_ERROR_INVALID_DATA;
3168 }
3169
3170 if (payload_length != PLDM_CANCEL_UPDATE_REQ_BYTES) {
3171 return PLDM_ERROR_INVALID_LENGTH;
3172 }
3173
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303174 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09303175 header.instance = instance_id;
3176 header.msg_type = PLDM_REQUEST;
3177 header.pldm_type = PLDM_FWUP;
3178 header.command = PLDM_CANCEL_UPDATE;
3179 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
3180 if (rc) {
3181 return rc;
3182 }
3183
3184 return PLDM_SUCCESS;
3185}
3186
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09303187LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09303188int decode_cancel_update_resp(const struct pldm_msg *msg, size_t payload_length,
3189 uint8_t *completion_code,
3190 bool8_t *non_functioning_component_indication,
3191 bitfield64_t *non_functioning_component_bitmap)
3192{
3193 if (msg == NULL || completion_code == NULL ||
3194 non_functioning_component_indication == NULL ||
3195 non_functioning_component_bitmap == NULL || !payload_length) {
3196 return PLDM_ERROR_INVALID_DATA;
3197 }
3198
3199 *completion_code = msg->payload[0];
3200 if (*completion_code != PLDM_SUCCESS) {
3201 return PLDM_SUCCESS;
3202 }
3203
3204 if (payload_length != sizeof(struct pldm_cancel_update_resp)) {
3205 return PLDM_ERROR_INVALID_LENGTH;
3206 }
3207 struct pldm_cancel_update_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303208 (struct pldm_cancel_update_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09303209
3210 if (!is_non_functioning_component_indication_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303211 response->non_functioning_component_indication)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09303212 return PLDM_ERROR_INVALID_DATA;
3213 }
3214
3215 *non_functioning_component_indication =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303216 response->non_functioning_component_indication;
Andrew Jeffery9c766792022-08-10 23:12:49 +09303217
3218 if (*non_functioning_component_indication) {
3219 non_functioning_component_bitmap->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303220 le64toh(response->non_functioning_component_bitmap);
Andrew Jeffery9c766792022-08-10 23:12:49 +09303221 }
3222
3223 return PLDM_SUCCESS;
3224}
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003225
3226LIBPLDM_ABI_TESTING
3227int encode_cancel_update_resp(uint8_t instance_id,
3228 const struct pldm_cancel_update_resp *resp_data,
3229 struct pldm_msg *msg, size_t *payload_length)
3230{
Andrew Jefferya1896962025-03-03 21:41:25 +10303231 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003232 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003233
3234 if (msg == NULL || payload_length == NULL) {
3235 return -EINVAL;
3236 }
3237
3238 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
3239 PLDM_CANCEL_UPDATE, msg);
3240 if (rc) {
3241 return -EINVAL;
3242 }
3243
3244 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
3245 if (rc) {
3246 return rc;
3247 }
3248
3249 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
3250 pldm_msgbuf_insert(buf,
3251 resp_data->non_functioning_component_indication);
3252 pldm_msgbuf_insert(buf, resp_data->non_functioning_component_bitmap);
3253
Andrew Jeffery70d21c92025-03-05 12:59:42 +10303254 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003255}
Andrew Jeffery2613c272025-03-12 14:15:41 +10303256
3257LIBPLDM_ABI_TESTING
3258int decode_pldm_firmware_update_package(
3259 const void *data, size_t length,
3260 const struct pldm_package_format_pin *pin,
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003261 pldm_package_header_information_pad *hdr, struct pldm_package *pkg)
Andrew Jeffery2613c272025-03-12 14:15:41 +10303262{
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003263 if (!data || !pin || !hdr || !pkg) {
Andrew Jeffery2613c272025-03-12 14:15:41 +10303264 return -EINVAL;
3265 }
3266
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003267 return decode_pldm_package_header_info_errno(data, length, pin, hdr,
3268 pkg);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303269}
3270
3271LIBPLDM_ABI_TESTING
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003272int pldm_package_firmware_device_id_record_iter_init(struct pldm_package *pkg)
Andrew Jeffery2613c272025-03-12 14:15:41 +10303273{
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003274 struct pldm_package_iter *iter;
Andrew Jeffery2613c272025-03-12 14:15:41 +10303275 PLDM_MSGBUF_DEFINE_P(buf);
3276 int rc;
3277
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003278 if (!pkg || !pkg->pin || !pkg->hdr) {
Andrew Jeffery2613c272025-03-12 14:15:41 +10303279 return -EINVAL;
3280 }
3281
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003282 assert(pkg->pin->format.revision >=
3283 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
3284 assert(pkg->pin->format.revision <=
3285 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H);
3286 assert(pkg->hdr->package_header_format_revision >=
3287 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
3288 assert(pkg->hdr->package_header_format_revision <=
3289 pkg->pin->format.revision);
3290
3291 if (pkg->state != PLDM_PACKAGE_PARSE_HEADER) {
3292 return -EPROTO;
3293 }
3294
3295 if (!pkg->areas.ptr) {
3296 return -EINVAL;
3297 }
3298
3299 pkg->state = PLDM_PACKAGE_PARSE_FIRMWARE_DEVICES;
3300
3301 iter = &pkg->iter;
3302 iter->field = pkg->areas;
Andrew Jeffery2613c272025-03-12 14:15:41 +10303303
3304 /* Extract the fd record id count */
3305 rc = pldm_msgbuf_init_errno(buf, 1, iter->field.ptr,
3306 iter->field.length);
3307 if (rc) {
3308 return rc;
3309 }
3310
3311 pldm_msgbuf_extract_uint8_to_size(buf, iter->entries);
3312 pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
3313 &iter->field.length);
3314
3315 return pldm_msgbuf_complete(buf);
3316}
3317
3318LIBPLDM_ABI_TESTING
3319int decode_pldm_package_firmware_device_id_record_from_iter(
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003320 struct pldm_package *pkg LIBPLDM_CC_UNUSED,
Andrew Jeffery2613c272025-03-12 14:15:41 +10303321 struct pldm_package_firmware_device_id_record *rec)
3322{
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003323 if (!pkg) {
Andrew Jeffery2613c272025-03-12 14:15:41 +10303324 return -EINVAL;
3325 }
3326
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003327 if (pkg->state != PLDM_PACKAGE_PARSE_FIRMWARE_DEVICES) {
3328 return -EPROTO;
3329 }
Andrew Jeffery2613c272025-03-12 14:15:41 +10303330
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003331 return decode_pldm_package_firmware_device_id_record_errno(
3332 pkg->hdr, &pkg->iter.field, rec);
3333}
3334
3335LIBPLDM_ABI_TESTING
3336int pldm_package_downstream_device_id_record_iter_init(struct pldm_package *pkg)
3337{
3338 struct pldm_package_iter *iter;
3339 PLDM_MSGBUF_DEFINE_P(buf);
3340 int rc;
3341
3342 if (!pkg || !pkg->pin || !pkg->hdr) {
3343 return -EINVAL;
3344 }
3345
3346 assert(pkg->pin->format.revision >=
3347 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
3348 assert(pkg->pin->format.revision <=
3349 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H);
3350 assert(pkg->hdr->package_header_format_revision >=
3351 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
3352 assert(pkg->hdr->package_header_format_revision <=
3353 pkg->pin->format.revision);
3354
3355 if (pkg->state != PLDM_PACKAGE_PARSE_FIRMWARE_DEVICES) {
3356 return -EPROTO;
3357 }
3358
3359 if (pkg->pin->format.revision ==
3360 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H) {
3361 return -EPROTO;
3362 }
3363
3364 if (!pkg->iter.field.ptr) {
3365 return -EINVAL;
3366 }
3367 iter = &pkg->iter;
3368
3369 pkg->state = PLDM_PACKAGE_PARSE_DOWNSTREAM_DEVICES;
3370
3371 /* Where:
3372 *
3373 * 1. The pin revision is greater than 1, and
3374 * 2. The package header format revision is 1
3375 *
3376 * We must account for the invocation of this function but present no downstream
3377 * devices, as they're not specified.
3378 */
3379 if (pkg->hdr->package_header_format_revision ==
3380 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H) {
3381 iter->entries = 0;
Andrew Jeffery2613c272025-03-12 14:15:41 +10303382 return 0;
3383 }
3384
3385 /* Extract the dd record id count */
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003386 rc = pldm_msgbuf_init_errno(buf, 1, iter->field.ptr,
3387 iter->field.length);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303388 if (rc) {
3389 return rc;
3390 }
3391
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003392 pldm_msgbuf_extract_uint8_to_size(buf, iter->entries);
3393 pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
3394 &iter->field.length);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303395
3396 return pldm_msgbuf_complete(buf);
3397}
3398
3399#define PLDM_FWUP_DOWNSTREAM_DEVICE_ID_RECORD_MIN_SIZE 11
3400LIBPLDM_ABI_TESTING
3401int decode_pldm_package_downstream_device_id_record_from_iter(
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003402 struct pldm_package *pkg,
Andrew Jeffery2613c272025-03-12 14:15:41 +10303403 struct pldm_package_downstream_device_id_record *rec)
3404{
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003405 struct pldm_package_iter *iter;
Carter Chen01782742025-06-25 13:53:50 +08003406 size_t package_data_offset;
Andrew Jeffery2613c272025-03-12 14:15:41 +10303407 PLDM_MSGBUF_DEFINE_P(buf);
3408 uint16_t record_len = 0;
3409 int rc;
3410
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003411 if (!pkg || !rec || !pkg->hdr) {
Andrew Jeffery2613c272025-03-12 14:15:41 +10303412 return -EINVAL;
3413 }
3414
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003415 if (pkg->state != PLDM_PACKAGE_PARSE_DOWNSTREAM_DEVICES) {
Andrew Jeffery2613c272025-03-12 14:15:41 +10303416 return -EPROTO;
3417 }
3418
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003419 assert(pkg->hdr->package_header_format_revision >
3420 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
3421
3422 if (!pkg->iter.field.ptr) {
3423 return -EINVAL;
3424 }
3425 iter = &pkg->iter;
3426
Andrew Jeffery2613c272025-03-12 14:15:41 +10303427 rc = pldm_msgbuf_init_dynamic_uint16(
3428 buf, PLDM_FWUP_DOWNSTREAM_DEVICE_ID_RECORD_MIN_SIZE,
3429 (void *)iter->field.ptr, iter->field.length,
3430 (void **)&iter->field.ptr, &iter->field.length);
3431 if (rc) {
3432 return pldm_msgbuf_discard(buf, rc);
3433 }
3434
3435 pldm_msgbuf_extract(buf, record_len);
3436 pldm_msgbuf_extract(buf, rec->descriptor_count);
3437
3438 rc = pldm_msgbuf_extract(buf, rec->update_option_flags.value);
3439 if (rc) {
3440 return pldm_msgbuf_discard(buf, rc);
3441 }
3442
3443 rc = pldm_msgbuf_extract(
3444 buf, rec->self_contained_activation_min_version_string_type);
3445 if (rc) {
3446 return pldm_msgbuf_discard(buf, rc);
3447 }
3448 if (!is_string_type_valid(
3449 rec->self_contained_activation_min_version_string_type)) {
3450 return pldm_msgbuf_discard(buf, -EPROTO);
3451 }
3452
3453 rc = pldm_msgbuf_extract_uint8_to_size(
3454 buf, rec->self_contained_activation_min_version_string.length);
3455 if (rc) {
3456 return pldm_msgbuf_discard(buf, rc);
3457 }
3458
3459 rc = pldm_msgbuf_extract_uint16_to_size(buf, rec->package_data.length);
3460 if (rc) {
3461 return pldm_msgbuf_discard(buf, rc);
3462 }
3463
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003464 if (pkg->hdr->package_header_format_revision >=
Carter Chen01782742025-06-25 13:53:50 +08003465 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H) {
3466 pldm_msgbuf_extract_uint32_to_size(
3467 buf, rec->reference_manifest_data.length);
3468 } else {
3469 rec->reference_manifest_data.length = 0;
3470 }
3471
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003472 assert((pkg->hdr->component_bitmap_bit_length & 7) == 0);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303473 rc = pldm_msgbuf_span_required(
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003474 buf, pkg->hdr->component_bitmap_bit_length / 8,
Andrew Jeffery2613c272025-03-12 14:15:41 +10303475 (void **)&rec->applicable_components.bitmap.ptr);
3476 if (rc) {
3477 return pldm_msgbuf_discard(buf, rc);
3478 }
3479 rec->applicable_components.bitmap.length =
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003480 pkg->hdr->component_bitmap_bit_length / 8;
Andrew Jeffery2613c272025-03-12 14:15:41 +10303481
3482 pldm_msgbuf_span_required(
3483 buf, rec->self_contained_activation_min_version_string.length,
3484 (void **)&rec->self_contained_activation_min_version_string.ptr);
3485 if (rec->update_option_flags.bits.bit0) {
3486 pldm_msgbuf_extract(
3487 buf,
3488 rec->self_contained_activation_min_version_comparison_stamp);
3489 } else {
3490 rec->self_contained_activation_min_version_comparison_stamp = 0;
3491 }
3492
Carter Chen01782742025-06-25 13:53:50 +08003493 /* The total length reserved for `package_data` and `reference_manifest_data` */
3494 package_data_offset =
3495 rec->package_data.length + rec->reference_manifest_data.length;
3496
3497 pldm_msgbuf_span_until(buf, package_data_offset,
Andrew Jeffery2613c272025-03-12 14:15:41 +10303498 (void **)&rec->record_descriptors.ptr,
3499 &rec->record_descriptors.length);
3500
3501 pldm_msgbuf_span_required(buf, rec->package_data.length,
3502 (void **)&rec->package_data.ptr);
3503
Carter Chen01782742025-06-25 13:53:50 +08003504 /* Supported in package header revision 1.3 (FR04H) and above. */
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003505 if (pkg->hdr->package_header_format_revision >=
Carter Chen01782742025-06-25 13:53:50 +08003506 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H) {
3507 pldm_msgbuf_span_required(
3508 buf, rec->reference_manifest_data.length,
3509 (void **)&rec->reference_manifest_data.ptr);
3510 } else {
3511 assert(rec->reference_manifest_data.length == 0);
3512 rec->reference_manifest_data.ptr = NULL;
3513 }
3514
Andrew Jeffery2613c272025-03-12 14:15:41 +10303515 return pldm_msgbuf_complete_consumed(buf);
3516}
3517
3518LIBPLDM_ABI_TESTING
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003519int pldm_package_component_image_information_iter_init(struct pldm_package *pkg)
Andrew Jeffery2613c272025-03-12 14:15:41 +10303520{
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003521 struct pldm_package_iter *iter;
Andrew Jeffery2613c272025-03-12 14:15:41 +10303522 uint16_t component_image_count;
3523 PLDM_MSGBUF_DEFINE_P(buf);
3524 int rc;
3525
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003526 if (!pkg || !pkg->pin || !pkg->hdr) {
Andrew Jeffery2613c272025-03-12 14:15:41 +10303527 return -EINVAL;
3528 }
3529
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003530 assert(pkg->pin->format.revision >=
3531 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
3532 assert(pkg->pin->format.revision <=
3533 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H);
3534 assert(pkg->hdr->package_header_format_revision >=
3535 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
3536 assert(pkg->hdr->package_header_format_revision <=
3537 pkg->pin->format.revision);
3538
3539 if (pkg->state == PLDM_PACKAGE_PARSE_FIRMWARE_DEVICES) {
3540 if (pkg->pin->format.revision !=
3541 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H ||
3542 pkg->hdr->package_header_format_revision !=
3543 pkg->pin->format.revision) {
3544 return -EPROTO;
3545 }
3546 } else if (pkg->state == PLDM_PACKAGE_PARSE_DOWNSTREAM_DEVICES) {
3547 assert(pkg->pin->format.revision !=
3548 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
3549 } else {
3550 return -EPROTO;
3551 }
3552
3553 if (!pkg->iter.field.ptr) {
3554 return -EINVAL;
3555 }
3556 iter = &pkg->iter;
3557
3558 pkg->state = PLDM_PACKAGE_PARSE_COMPONENT_IMAGE_INFORMATION;
Andrew Jeffery2613c272025-03-12 14:15:41 +10303559
3560 /* Extract the component image count */
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003561 rc = pldm_msgbuf_init_errno(buf, 1, iter->field.ptr,
3562 iter->field.length);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303563 if (rc) {
3564 return rc;
3565 }
3566
3567 rc = pldm_msgbuf_extract(buf, component_image_count);
3568 if (rc) {
3569 return pldm_msgbuf_discard(buf, rc);
3570 }
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003571 iter->entries = component_image_count;
Andrew Jeffery2613c272025-03-12 14:15:41 +10303572
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003573 pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
3574 &iter->field.length);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303575
3576 return pldm_msgbuf_complete(buf);
3577}
3578
3579#define PLDM_FWUP_COMPONENT_IMAGE_INFORMATION_MIN_SIZE 22
3580LIBPLDM_ABI_TESTING
3581int decode_pldm_package_component_image_information_from_iter(
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003582 struct pldm_package *pkg,
Andrew Jeffery2613c272025-03-12 14:15:41 +10303583 struct pldm_package_component_image_information *info)
3584{
3585 uint32_t component_location_offset = 0;
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003586 struct pldm_package_iter *iter;
Andrew Jeffery2613c272025-03-12 14:15:41 +10303587 uint32_t component_size = 0;
3588 PLDM_MSGBUF_DEFINE_P(buf);
3589 int rc;
3590
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003591 if (!pkg || !info) {
Andrew Jeffery2613c272025-03-12 14:15:41 +10303592 return -EINVAL;
3593 }
3594
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003595 if (pkg->state != PLDM_PACKAGE_PARSE_COMPONENT_IMAGE_INFORMATION) {
Andrew Jeffery2613c272025-03-12 14:15:41 +10303596 return -EPROTO;
3597 }
3598
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003599 if (!pkg->iter.field.ptr) {
3600 return -EINVAL;
3601 }
3602 iter = &pkg->iter;
3603
Andrew Jeffery2613c272025-03-12 14:15:41 +10303604 rc = pldm_msgbuf_init_errno(
3605 buf, PLDM_FWUP_COMPONENT_IMAGE_INFORMATION_MIN_SIZE,
3606 iter->field.ptr, iter->field.length);
3607 if (rc) {
3608 return rc;
3609 }
3610
3611 pldm_msgbuf_extract(buf, info->component_classification);
3612 pldm_msgbuf_extract(buf, info->component_identifier);
3613 pldm_msgbuf_extract(buf, info->component_comparison_stamp);
3614 pldm_msgbuf_extract(buf, info->component_options.value);
3615 pldm_msgbuf_extract(buf,
3616 info->requested_component_activation_method.value);
3617 pldm_msgbuf_extract(buf, component_location_offset);
3618 pldm_msgbuf_extract(buf, component_size);
3619
3620 rc = pldm_msgbuf_extract(buf, info->component_version_string_type);
3621 if (rc) {
3622 return pldm_msgbuf_discard(buf, rc);
3623 }
3624 if (!is_string_type_valid(info->component_version_string_type)) {
3625 return pldm_msgbuf_discard(buf, -EPROTO);
3626 }
3627
3628 rc = pldm_msgbuf_extract_uint8_to_size(
3629 buf, info->component_version_string.length);
3630 if (rc) {
3631 return pldm_msgbuf_discard(buf, rc);
3632 }
3633
3634 pldm_msgbuf_span_required(buf, info->component_version_string.length,
3635 (void **)&info->component_version_string.ptr);
3636
Carter Chenf72cf6f2025-06-24 15:34:49 +08003637 /* Supported in package header revision 1.2 (FR03H) and above. */
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003638 if (pkg->hdr->package_header_format_revision >=
Carter Chenf72cf6f2025-06-24 15:34:49 +08003639 PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR03H) {
3640 rc = pldm_msgbuf_extract_uint32_to_size(
3641 buf, info->component_opaque_data.length);
3642 if (rc) {
3643 return pldm_msgbuf_discard(buf, rc);
3644 }
3645 pldm_msgbuf_span_required(
3646 buf, info->component_opaque_data.length,
3647 (void **)&info->component_opaque_data.ptr);
3648 } else {
3649 info->component_opaque_data.length = 0;
3650 }
3651
3652 if (info->component_opaque_data.length == 0) {
3653 info->component_opaque_data.ptr = NULL;
3654 }
3655
Andrew Jeffery2613c272025-03-12 14:15:41 +10303656 pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
3657 &iter->field.length);
3658
3659 rc = pldm_msgbuf_complete_consumed(buf);
3660 if (rc) {
3661 return rc;
3662 }
3663
3664 if (info->component_classification > 0x000d &&
3665 info->component_classification < 0x8000) {
3666 return -EPROTO;
3667 }
3668
3669 /* Resolve the component image in memory */
Andrew Jefferyc53c6fe2025-08-11 07:44:38 +00003670 rc = pldm_msgbuf_init_errno(buf, 0, pkg->package.ptr,
3671 pkg->package.length);
Andrew Jeffery2613c272025-03-12 14:15:41 +10303672 if (rc) {
3673 return rc;
3674 }
3675
3676 pldm_msgbuf_span_required(buf, component_location_offset, NULL);
3677 pldm_msgbuf_span_required(buf, component_size,
3678 (void **)&info->component_image.ptr);
3679
3680 rc = pldm_msgbuf_complete(buf);
3681 if (rc) {
3682 return rc;
3683 }
3684
3685 info->component_image.length = component_size;
3686
3687 return 0;
3688}