blob: ac7937ee9c648b0a7d19244a8b793ee02a5a7a1c [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"
Chris Wangb6ef35b2024-07-03 09:35:42 +08003#include "dsp/base.h"
Chris Wang4c1f2c72024-03-21 17:09:44 +08004#include "msgbuf.h"
Andrew Jefferybacbbac2025-03-12 04:02:18 +00005#include <libpldm/base.h>
Andrew Jefferyb0c1d202023-11-07 22:08:44 +10306#include <libpldm/firmware_update.h>
7#include <libpldm/utils.h>
8
Andrew Jeffery9c766792022-08-10 23:12:49 +09309#include <endian.h>
Manojkiran Eda9a8e4972022-11-28 16:38:21 +053010#include <stdbool.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +093011#include <string.h>
12
Matt Johnstoncf9a2df2024-11-07 15:29:29 +080013static_assert(PLDM_FIRMWARE_MAX_STRING <= UINT8_MAX, "too large");
14
Andrew Jeffery9c766792022-08-10 23:12:49 +093015/** @brief Check whether string type value is valid
16 *
17 * @return true if string type value is valid, false if not
18 */
19static bool is_string_type_valid(uint8_t string_type)
20{
21 switch (string_type) {
22 case PLDM_STR_TYPE_UNKNOWN:
23 return false;
24 case PLDM_STR_TYPE_ASCII:
25 case PLDM_STR_TYPE_UTF_8:
26 case PLDM_STR_TYPE_UTF_16:
27 case PLDM_STR_TYPE_UTF_16LE:
28 case PLDM_STR_TYPE_UTF_16BE:
29 return true;
30 default:
31 return false;
32 }
33}
34
35/** @brief Return the length of the descriptor type described in firmware update
36 * specification
37 *
38 * @return length of the descriptor type if descriptor type is valid else
39 * return 0
40 */
41static uint16_t get_descriptor_type_length(uint16_t descriptor_type)
42{
43 switch (descriptor_type) {
Andrew Jeffery9c766792022-08-10 23:12:49 +093044 case PLDM_FWUP_PCI_VENDOR_ID:
45 return PLDM_FWUP_PCI_VENDOR_ID_LENGTH;
46 case PLDM_FWUP_IANA_ENTERPRISE_ID:
47 return PLDM_FWUP_IANA_ENTERPRISE_ID_LENGTH;
48 case PLDM_FWUP_UUID:
49 return PLDM_FWUP_UUID_LENGTH;
50 case PLDM_FWUP_PNP_VENDOR_ID:
51 return PLDM_FWUP_PNP_VENDOR_ID_LENGTH;
52 case PLDM_FWUP_ACPI_VENDOR_ID:
53 return PLDM_FWUP_ACPI_VENDOR_ID_LENGTH;
54 case PLDM_FWUP_IEEE_ASSIGNED_COMPANY_ID:
55 return PLDM_FWUP_IEEE_ASSIGNED_COMPANY_ID_LENGTH;
56 case PLDM_FWUP_SCSI_VENDOR_ID:
57 return PLDM_FWUP_SCSI_VENDOR_ID_LENGTH;
58 case PLDM_FWUP_PCI_DEVICE_ID:
59 return PLDM_FWUP_PCI_DEVICE_ID_LENGTH;
60 case PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID:
61 return PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID_LENGTH;
62 case PLDM_FWUP_PCI_SUBSYSTEM_ID:
63 return PLDM_FWUP_PCI_SUBSYSTEM_ID_LENGTH;
64 case PLDM_FWUP_PCI_REVISION_ID:
65 return PLDM_FWUP_PCI_REVISION_ID_LENGTH;
66 case PLDM_FWUP_PNP_PRODUCT_IDENTIFIER:
67 return PLDM_FWUP_PNP_PRODUCT_IDENTIFIER_LENGTH;
68 case PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER:
69 return PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER_LENGTH;
70 case PLDM_FWUP_ASCII_MODEL_NUMBER_LONG_STRING:
71 return PLDM_FWUP_ASCII_MODEL_NUMBER_LONG_STRING_LENGTH;
72 case PLDM_FWUP_ASCII_MODEL_NUMBER_SHORT_STRING:
73 return PLDM_FWUP_ASCII_MODEL_NUMBER_SHORT_STRING_LENGTH;
74 case PLDM_FWUP_SCSI_PRODUCT_ID:
75 return PLDM_FWUP_SCSI_PRODUCT_ID_LENGTH;
76 case PLDM_FWUP_UBM_CONTROLLER_DEVICE_CODE:
77 return PLDM_FWUP_UBM_CONTROLLER_DEVICE_CODE_LENGTH;
78 default:
79 return 0;
80 }
81}
82
Chris Wang4c1f2c72024-03-21 17:09:44 +080083static bool is_downstream_device_update_support_valid(uint8_t resp)
84{
85 switch (resp) {
86 case PLDM_FWUP_DOWNSTREAM_DEVICE_UPDATE_NOT_SUPPORTED:
87 case PLDM_FWUP_DOWNSTREAM_DEVICE_UPDATE_SUPPORTED:
88 return true;
89 default:
90 return false;
91 }
92}
93
Chris Wang458475a2024-03-26 17:59:19 +080094static bool
95is_transfer_operation_flag_valid(enum transfer_op_flag transfer_op_flag)
96{
97 switch (transfer_op_flag) {
98 case PLDM_GET_NEXTPART:
99 case PLDM_GET_FIRSTPART:
100 return true;
101 default:
102 return false;
103 }
104}
105
Andrew Jeffery9c766792022-08-10 23:12:49 +0930106/** @brief Check whether ComponentResponse is valid
107 *
108 * @return true if ComponentResponse is valid, false if not
109 */
110static bool is_comp_resp_valid(uint8_t comp_resp)
111{
112 switch (comp_resp) {
113 case PLDM_CR_COMP_CAN_BE_UPDATED:
114 case PLDM_CR_COMP_MAY_BE_UPDATEABLE:
115 return true;
116
117 default:
118 return false;
119 }
120}
121
122/** @brief Check whether ComponentResponseCode is valid
123 *
124 * @return true if ComponentResponseCode is valid, false if not
125 */
126static bool is_comp_resp_code_valid(uint8_t comp_resp_code)
127{
128 switch (comp_resp_code) {
129 case PLDM_CRC_COMP_CAN_BE_UPDATED:
130 case PLDM_CRC_COMP_COMPARISON_STAMP_IDENTICAL:
131 case PLDM_CRC_COMP_COMPARISON_STAMP_LOWER:
132 case PLDM_CRC_INVALID_COMP_COMPARISON_STAMP:
133 case PLDM_CRC_COMP_CONFLICT:
134 case PLDM_CRC_COMP_PREREQUISITES_NOT_MET:
135 case PLDM_CRC_COMP_NOT_SUPPORTED:
136 case PLDM_CRC_COMP_SECURITY_RESTRICTIONS:
137 case PLDM_CRC_INCOMPLETE_COMP_IMAGE_SET:
138 case PLDM_CRC_ACTIVE_IMAGE_NOT_UPDATEABLE_SUBSEQUENTLY:
139 case PLDM_CRC_COMP_VER_STR_IDENTICAL:
140 case PLDM_CRC_COMP_VER_STR_LOWER:
141 return true;
142
143 default:
144 if (comp_resp_code >=
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930145 PLDM_CRC_VENDOR_COMP_RESP_CODE_RANGE_MIN &&
Andrew Jeffery9c766792022-08-10 23:12:49 +0930146 comp_resp_code <=
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930147 PLDM_CRC_VENDOR_COMP_RESP_CODE_RANGE_MAX) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930148 return true;
149 }
150 return false;
151 }
152}
153
154/** @brief Check whether ComponentCompatibilityResponse is valid
155 *
156 * @return true if ComponentCompatibilityResponse is valid, false if not
157 */
158static bool is_comp_compatibility_resp_valid(uint8_t comp_compatibility_resp)
159{
160 switch (comp_compatibility_resp) {
161 case PLDM_CCR_COMP_CAN_BE_UPDATED:
162 case PLDM_CCR_COMP_CANNOT_BE_UPDATED:
163 return true;
164
165 default:
166 return false;
167 }
168}
169
170/** @brief Check whether ComponentCompatibilityResponse Code is valid
171 *
172 * @return true if ComponentCompatibilityResponse Code is valid, false if not
173 */
174static bool
175is_comp_compatibility_resp_code_valid(uint8_t comp_compatibility_resp_code)
176{
177 switch (comp_compatibility_resp_code) {
178 case PLDM_CCRC_NO_RESPONSE_CODE:
179 case PLDM_CCRC_COMP_COMPARISON_STAMP_IDENTICAL:
180 case PLDM_CCRC_COMP_COMPARISON_STAMP_LOWER:
181 case PLDM_CCRC_INVALID_COMP_COMPARISON_STAMP:
182 case PLDM_CCRC_COMP_CONFLICT:
183 case PLDM_CCRC_COMP_PREREQUISITES_NOT_MET:
184 case PLDM_CCRC_COMP_NOT_SUPPORTED:
185 case PLDM_CCRC_COMP_SECURITY_RESTRICTIONS:
186 case PLDM_CRC_INCOMPLETE_COMP_IMAGE_SET:
187 case PLDM_CCRC_COMP_INFO_NO_MATCH:
188 case PLDM_CCRC_COMP_VER_STR_IDENTICAL:
189 case PLDM_CCRC_COMP_VER_STR_LOWER:
190 return true;
191
192 default:
193 if (comp_compatibility_resp_code >=
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930194 PLDM_CCRC_VENDOR_COMP_RESP_CODE_RANGE_MIN &&
Andrew Jeffery9c766792022-08-10 23:12:49 +0930195 comp_compatibility_resp_code <=
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930196 PLDM_CCRC_VENDOR_COMP_RESP_CODE_RANGE_MAX) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930197 return true;
198 }
199 return false;
200 }
201}
202
203/** @brief Check whether SelfContainedActivationRequest is valid
204 *
205 * @return true if SelfContainedActivationRequest is valid, false if not
206 */
207static bool
208is_self_contained_activation_req_valid(bool8_t self_contained_activation_req)
209{
210 switch (self_contained_activation_req) {
211 case PLDM_NOT_ACTIVATE_SELF_CONTAINED_COMPONENTS:
212 case PLDM_ACTIVATE_SELF_CONTAINED_COMPONENTS:
213 return true;
214
215 default:
216 return false;
217 }
218}
219
220/** @brief Check if current or previous status in GetStatus command response is
221 * valid
222 *
223 * @param[in] state - current or previous different state machine state of
224 * the FD
225 * @return true if state is valid, false if not
226 */
227static bool is_state_valid(uint8_t state)
228{
229 switch (state) {
230 case PLDM_FD_STATE_IDLE:
231 case PLDM_FD_STATE_LEARN_COMPONENTS:
232 case PLDM_FD_STATE_READY_XFER:
233 case PLDM_FD_STATE_DOWNLOAD:
234 case PLDM_FD_STATE_VERIFY:
235 case PLDM_FD_STATE_APPLY:
236 case PLDM_FD_STATE_ACTIVATE:
237 return true;
238
239 default:
240 return false;
241 }
242}
243
244/** @brief Check if aux state in GetStatus command response is valid
245 *
246 * @param[in] aux_state - provides additional information to the UA to describe
247 * the current operation state of the FD/FDP
248 *
249 * @return true if aux state is valid, false if not
250 */
251static bool is_aux_state_valid(uint8_t aux_state)
252{
253 switch (aux_state) {
254 case PLDM_FD_OPERATION_IN_PROGRESS:
255 case PLDM_FD_OPERATION_SUCCESSFUL:
256 case PLDM_FD_OPERATION_FAILED:
257 case PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER:
258 return true;
259
260 default:
261 return false;
262 }
263}
264
265/** @brief Check if aux state status in GetStatus command response is valid
266 *
267 * @param[in] aux_state_status - aux state status
268 *
269 * @return true if aux state status is valid, false if not
270 */
271static bool is_aux_state_status_valid(uint8_t aux_state_status)
272{
273 if (aux_state_status == PLDM_FD_AUX_STATE_IN_PROGRESS_OR_SUCCESS ||
274 aux_state_status == PLDM_FD_TIMEOUT ||
Andrew Jeffery67f7ed92023-04-05 14:00:00 +0930275 aux_state_status == PLDM_FD_GENERIC_ERROR ||
276 (aux_state_status >= PLDM_FD_VENDOR_DEFINED_STATUS_CODE_START &&
277 aux_state_status <= PLDM_FD_VENDOR_DEFINED_STATUS_CODE_END)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930278 return true;
279 }
280
281 return false;
282}
283
284/** @brief Check if reason code in GetStatus command response is valid
285 *
286 * @param[in] reason_code - provides the reason for why the current state
287 * entered the IDLE state
288 *
289 * @return true if reason code is valid, false if not
290 */
291static bool is_reason_code_valid(uint8_t reason_code)
292{
Andrew Jeffery9c766792022-08-10 23:12:49 +0930293 switch (reason_code) {
294 case PLDM_FD_INITIALIZATION:
295 case PLDM_FD_ACTIVATE_FW:
296 case PLDM_FD_CANCEL_UPDATE:
297 case PLDM_FD_TIMEOUT_LEARN_COMPONENT:
298 case PLDM_FD_TIMEOUT_READY_XFER:
299 case PLDM_FD_TIMEOUT_DOWNLOAD:
300 case PLDM_FD_TIMEOUT_VERIFY:
301 case PLDM_FD_TIMEOUT_APPLY:
302 return true;
303
304 default:
305 if (reason_code >= PLDM_FD_STATUS_VENDOR_DEFINED_MIN) {
306 return true;
307 }
308 return false;
309 }
310}
311
312/** @brief Check if non functioning component indication in CancelUpdate
313 * response is valid
314 *
315 * @return true if non functioning component indication is valid, false if not
316 */
317static bool is_non_functioning_component_indication_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930318 bool8_t non_functioning_component_indication)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930319{
320 switch (non_functioning_component_indication) {
321 case PLDM_FWUP_COMPONENTS_FUNCTIONING:
322 case PLDM_FWUP_COMPONENTS_NOT_FUNCTIONING:
323 return true;
324
325 default:
326 return false;
327 }
328}
329
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030330// Identifier for a valid PLDM Firmware Update Package for Version 1.0.x as per
331// spec
332static const uint8_t PLDM_FWUP_HDR_IDENTIFIER_V1[PLDM_FWUP_UUID_LENGTH] = {
333 0xF0, 0x18, 0x87, 0x8C, 0xCB, 0x7D, 0x49, 0x43,
334 0x98, 0x00, 0xA0, 0x2F, 0x05, 0x9A, 0xCA, 0x02
335};
336
337/* TODO: Remove struct pldm_package_header_information from public header, rename padded struct, drop typedef */
338struct pldm__package_header_information {
339 uint8_t package_header_identifier[PLDM_FWUP_UUID_LENGTH];
340 uint8_t package_header_format_revision;
341 uint8_t package_release_date_time[PLDM_TIMESTAMP104_SIZE];
342 uint16_t component_bitmap_bit_length;
343 uint8_t package_version_string_type;
344 struct variable_field package_version_string;
345 struct variable_field areas;
346 struct variable_field images;
347};
348typedef struct pldm__package_header_information
349 pldm_package_header_information_pad;
350
351#define PLDM_FWUP_PACKAGE_HEADER_FIXED_SIZE 36
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030352static int decode_pldm_package_header_info_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030353 const void *data, size_t length,
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030354 pldm_package_header_information_pad *header)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930355{
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030356 uint32_t package_header_checksum = 0;
357 size_t package_header_variable_size;
358 size_t package_header_payload_size;
359 size_t package_header_areas_size;
360 uint16_t package_header_size;
361 PLDM_MSGBUF_DEFINE_P(buf);
362 int checksums = 1;
363 int rc;
364
365 if (!data || !header) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030366 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930367 }
368
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030369 rc = pldm_msgbuf_init_errno(buf, PLDM_FWUP_PACKAGE_HEADER_FIXED_SIZE,
370 data, length);
371 if (rc) {
372 return rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930373 }
374
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030375 rc = pldm_msgbuf_extract_array(
376 buf, sizeof(header->package_header_identifier),
377 header->package_header_identifier,
378 sizeof(header->package_header_identifier));
379 if (rc) {
380 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930381 }
382
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030383 static_assert(sizeof(PLDM_FWUP_HDR_IDENTIFIER_V1) ==
384 sizeof(header->package_header_identifier),
385 "UUID field size");
386 if (memcmp(PLDM_FWUP_HDR_IDENTIFIER_V1,
387 header->package_header_identifier,
388 sizeof(PLDM_FWUP_HDR_IDENTIFIER_V1)) != 0) {
389 return pldm_msgbuf_discard(buf, -ENOTSUP);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930390 }
391
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030392 rc = pldm_msgbuf_extract(buf, header->package_header_format_revision);
393 if (rc) {
394 return pldm_msgbuf_discard(buf, rc);
395 }
396 if (header->package_header_format_revision != 0x01) {
397 return pldm_msgbuf_discard(buf, -EBADMSG);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930398 }
399
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030400 rc = pldm_msgbuf_extract(buf, package_header_size);
401 if (rc) {
402 return pldm_msgbuf_discard(buf, rc);
403 }
404
405 rc = pldm_msgbuf_extract_array(
406 buf, sizeof(header->package_release_date_time),
407 header->package_release_date_time,
408 sizeof(header->package_release_date_time));
409 if (rc) {
410 return pldm_msgbuf_discard(buf, rc);
411 }
412
413 rc = pldm_msgbuf_extract(buf, header->component_bitmap_bit_length);
414 if (rc) {
415 return pldm_msgbuf_discard(buf, rc);
416 }
417 if (header->component_bitmap_bit_length & 7) {
418 return pldm_msgbuf_discard(buf, -EPROTO);
419 }
420
421 rc = pldm_msgbuf_extract(buf, header->package_version_string_type);
422 if (rc) {
423 return pldm_msgbuf_discard(buf, rc);
424 }
425 if (!is_string_type_valid(header->package_version_string_type)) {
426 return pldm_msgbuf_discard(buf, -EPROTO);
427 }
428
429 rc = pldm_msgbuf_extract_uint8_to_size(
430 buf, header->package_version_string.length);
431 if (rc) {
432 return pldm_msgbuf_discard(buf, rc);
433 }
434 if (header->package_version_string.length == 0) {
435 return pldm_msgbuf_discard(buf, -EBADMSG);
436 }
437
438 pldm_msgbuf_span_required(buf, header->package_version_string.length,
439 (void **)&header->package_version_string.ptr);
440
441 if (package_header_size < (PLDM_FWUP_PACKAGE_HEADER_FIXED_SIZE + 3 +
442 checksums * sizeof(uint32_t))) {
443 return pldm_msgbuf_discard(buf, -EBADMSG);
444 }
445 package_header_payload_size =
446 package_header_size - (checksums * sizeof(uint32_t));
447 package_header_variable_size = package_header_payload_size -
448 PLDM_FWUP_PACKAGE_HEADER_FIXED_SIZE;
449
450 if (package_header_variable_size <
451 header->package_version_string.length) {
452 return pldm_msgbuf_discard(buf, -EOVERFLOW);
453 }
454
455 package_header_areas_size = package_header_variable_size -
456 header->package_version_string.length;
457 rc = pldm_msgbuf_span_required(buf, package_header_areas_size,
458 (void **)&header->areas.ptr);
459 if (rc) {
460 return pldm_msgbuf_discard(buf, rc);
461 }
462 header->areas.length = package_header_areas_size;
463
464 pldm_msgbuf_extract(buf, package_header_checksum);
465
466 rc = pldm_msgbuf_complete(buf);
467 if (rc) {
468 return rc;
469 }
470
471 if (package_header_checksum !=
472 crc32(data, package_header_payload_size)) {
473 return -EUCLEAN;
474 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930475
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030476 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930477}
478
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930479LIBPLDM_ABI_STABLE
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030480int decode_pldm_package_header_info(
481 const uint8_t *data, size_t length,
482 struct pldm_package_header_information *package_header_info,
483 struct variable_field *package_version_str)
484{
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030485 pldm_package_header_information_pad header;
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030486 int rc;
487
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030488 if (!data || !package_header_info || !package_version_str) {
489 return PLDM_ERROR_INVALID_DATA;
490 }
491
492 rc = decode_pldm_package_header_info_errno(data, length, &header);
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030493 if (rc < 0) {
494 return pldm_xlate_errno(rc);
495 }
496
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030497 static_assert(sizeof(package_header_info->uuid) ==
498 sizeof(header.package_header_identifier),
499 "UUID field size");
500 memcpy(package_header_info->uuid, header.package_header_identifier,
501 sizeof(header.package_header_identifier));
502 package_header_info->package_header_format_version =
503 header.package_header_format_revision;
504 memcpy(&package_header_info->package_header_size, data + 17,
505 sizeof(package_header_info->package_header_size));
506 LE16TOH(package_header_info->package_header_size);
507 static_assert(sizeof(package_header_info->package_release_date_time) ==
508 sizeof(header.package_release_date_time),
509 "TIMESTAMP104 field size");
510 memcpy(package_header_info->package_release_date_time,
511 header.package_release_date_time,
512 sizeof(header.package_release_date_time));
513 package_header_info->component_bitmap_bit_length =
514 header.component_bitmap_bit_length;
515 package_header_info->package_version_string_type =
516 header.package_version_string_type;
517 package_header_info->package_version_string_length =
518 header.package_version_string.length;
519 *package_version_str = header.package_version_string;
520
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030521 return PLDM_SUCCESS;
522}
523
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000524struct pldm_component_bitmap {
525 struct variable_field bitmap;
526};
527
528/* TODO: Remove struct pldm_firmware_device_id_record from public header, rename padded struct, drop typedef */
529struct pldm__firmware_device_id_record {
530 uint8_t descriptor_count;
531 bitfield32_t device_update_option_flags;
532 uint8_t component_image_set_version_string_type;
533 struct variable_field component_image_set_version_string;
534 struct pldm_component_bitmap applicable_components;
535 struct variable_field record_descriptors;
536 struct variable_field firmware_device_package_data;
537};
538typedef struct pldm__firmware_device_id_record
539 pldm_firmware_device_id_record_pad;
540
541/* Currently only used for decode_firmware_device_id_record_errno() */
542static int pldm_msgbuf_init_dynamic_uint16(struct pldm_msgbuf *buf, size_t req,
543 const void *data, size_t len)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930544{
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000545 uint16_t dyn;
546 void *start;
547 int rc;
548
549 /*
550 * Extract the record length from the first field, then reinitialise the msgbuf
551 * after determining that it's safe to do so
552 */
553
554 rc = pldm_msgbuf_init_errno(buf, req, data, len);
555 if (rc) {
556 return rc;
557 }
558
559 rc = pldm_msgbuf_extract(buf, dyn);
560 if (rc) {
561 return pldm_msgbuf_discard(buf, rc);
562 }
563
564 rc = pldm_msgbuf_complete(buf);
565 if (rc) {
566 return rc;
567 }
568
569 rc = pldm_msgbuf_init_errno(buf, req, data, len);
570 if (rc) {
571 return rc;
572 }
573
574 /* Ensure there's no arithmetic funkiness and the span is within buffer bounds */
575 rc = pldm_msgbuf_span_required(buf, dyn, &start);
576 if (rc) {
577 return pldm_msgbuf_discard(buf, rc);
578 }
579
580 rc = pldm_msgbuf_complete(buf);
581 if (rc) {
582 return rc;
583 }
584
585 return pldm_msgbuf_init_errno(buf, req, start, dyn);
586}
587
588#define PLDM_FWUP_FIRMWARE_DEVICE_ID_RECORD_MIN_SIZE 11
589static int decode_firmware_device_id_record_errno(
590 const void *data, size_t length,
591 pldm_package_header_information_pad *header,
592 pldm_firmware_device_id_record_pad *rec)
593{
594 PLDM_MSGBUF_DEFINE_P(buf);
595 uint16_t record_len = 0;
596 int rc;
597
598 if (!data || !header || !rec) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030599 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930600 }
601
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000602 if (header->package_header_format_revision != 1) {
603 return -ENOTSUP;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930604 }
605
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000606 if (header->component_bitmap_bit_length & 7) {
607 return -EPROTO;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930608 }
609
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000610 rc = pldm_msgbuf_init_dynamic_uint16(
611 buf, PLDM_FWUP_FIRMWARE_DEVICE_ID_RECORD_MIN_SIZE, data,
612 length);
613 if (rc) {
614 return rc;
615 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930616
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000617 pldm_msgbuf_extract(buf, record_len);
618 pldm_msgbuf_extract(buf, rec->descriptor_count);
619 pldm_msgbuf_extract(buf, rec->device_update_option_flags.value);
620
621 rc = pldm_msgbuf_extract(buf,
622 rec->component_image_set_version_string_type);
623 if (rc) {
624 return pldm_msgbuf_discard(buf, rc);
625 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930626 if (!is_string_type_valid(
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000627 rec->component_image_set_version_string_type)) {
628 return pldm_msgbuf_discard(buf, -EPROTO);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930629 }
630
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000631 rc = pldm_msgbuf_extract_uint8_to_size(
632 buf, rec->component_image_set_version_string.length);
633 if (rc) {
634 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930635 }
636
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000637 if (rec->component_image_set_version_string.length == 0) {
638 return pldm_msgbuf_discard(buf, -EPROTO);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930639 }
640
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000641 rc = pldm_msgbuf_extract_uint16_to_size(
642 buf, rec->firmware_device_package_data.length);
643 if (rc) {
644 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930645 }
646
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000647 rc = pldm_msgbuf_span_required(
648 buf, header->component_bitmap_bit_length / 8,
649 (void **)&rec->applicable_components.bitmap.ptr);
650 if (rc) {
651 return pldm_msgbuf_discard(buf, rc);
652 }
653 rec->applicable_components.bitmap.length =
654 header->component_bitmap_bit_length / 8;
655
656 pldm_msgbuf_span_required(
657 buf, rec->component_image_set_version_string.length,
658 (void **)&rec->component_image_set_version_string.ptr);
659
660 pldm_msgbuf_span_until(buf, rec->firmware_device_package_data.length,
661 (void **)&rec->record_descriptors.ptr,
662 &rec->record_descriptors.length);
663
664 pldm_msgbuf_span_required(
665 buf, rec->firmware_device_package_data.length,
666 (void **)&rec->firmware_device_package_data.ptr);
667 if (!rec->firmware_device_package_data.length) {
668 rec->firmware_device_package_data.ptr = NULL;
669 }
670
671 return pldm_msgbuf_complete_consumed(buf);
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030672}
673
674LIBPLDM_ABI_STABLE
675int decode_firmware_device_id_record(
676 const uint8_t *data, size_t length,
677 uint16_t component_bitmap_bit_length,
678 struct pldm_firmware_device_id_record *fw_device_id_record,
679 struct variable_field *applicable_components,
680 struct variable_field *comp_image_set_version_str,
681 struct variable_field *record_descriptors,
682 struct variable_field *fw_device_pkg_data)
683{
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000684 pldm_package_header_information_pad header = { 0 };
685 pldm_firmware_device_id_record_pad rec = { 0 };
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030686 int rc;
687
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000688 if (!data || !fw_device_id_record || !applicable_components ||
689 !comp_image_set_version_str || !record_descriptors ||
690 !fw_device_pkg_data) {
691 return PLDM_ERROR_INVALID_DATA;
692 }
693
694 header.component_bitmap_bit_length = component_bitmap_bit_length;
695 memcpy(header.package_header_identifier, PLDM_FWUP_HDR_IDENTIFIER_V1,
696 sizeof(PLDM_FWUP_HDR_IDENTIFIER_V1));
697 header.package_header_format_revision = 1;
698 rc = decode_firmware_device_id_record_errno(data, length, &header,
699 &rec);
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030700 if (rc < 0) {
701 return pldm_xlate_errno(rc);
702 }
703
Andrew Jefferybacbbac2025-03-12 04:02:18 +0000704 memcpy(&fw_device_id_record->record_length, data,
705 sizeof(fw_device_id_record->record_length));
706 LE16TOH(fw_device_id_record->record_length);
707 fw_device_id_record->descriptor_count = rec.descriptor_count;
708 fw_device_id_record->device_update_option_flags =
709 rec.device_update_option_flags;
710 fw_device_id_record->comp_image_set_version_string_type =
711 rec.component_image_set_version_string_type;
712 fw_device_id_record->comp_image_set_version_string_length =
713 rec.component_image_set_version_string.length;
714 fw_device_id_record->fw_device_pkg_data_length =
715 rec.firmware_device_package_data.length;
716 *applicable_components = rec.applicable_components.bitmap;
717 *comp_image_set_version_str = rec.component_image_set_version_string;
718 *record_descriptors = rec.record_descriptors;
719 *fw_device_pkg_data = rec.firmware_device_package_data;
720
Andrew Jeffery9c766792022-08-10 23:12:49 +0930721 return PLDM_SUCCESS;
722}
723
Unive Tiene5c3f142024-12-13 14:14:19 +0800724LIBPLDM_ABI_STABLE
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030725int decode_pldm_descriptor_from_iter(struct pldm_descriptor_iter *iter,
726 struct pldm_descriptor *desc)
727{
Andrew Jefferya1896962025-03-03 21:41:25 +1030728 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030729 int rc;
730
731 if (!iter || !iter->field || !desc) {
732 return -EINVAL;
733 }
734
735 rc = pldm_msgbuf_init_errno(buf, PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN,
736 iter->field->ptr, iter->field->length);
737 if (rc) {
738 return rc;
739 }
740
741 pldm_msgbuf_extract(buf, desc->descriptor_type);
742 rc = pldm_msgbuf_extract(buf, desc->descriptor_length);
743 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +1030744 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030745 }
746
747 desc->descriptor_data = NULL;
748 pldm_msgbuf_span_required(buf, desc->descriptor_length,
749 (void **)&desc->descriptor_data);
750 iter->field->ptr = NULL;
751 pldm_msgbuf_span_remaining(buf, (void **)&iter->field->ptr,
752 &iter->field->length);
753
Andrew Jeffery70d21c92025-03-05 12:59:42 +1030754 return pldm_msgbuf_complete(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030755}
756
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030757static int decode_descriptor_type_length_value_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030758 const void *data, size_t length, uint16_t *descriptor_type,
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030759 struct variable_field *descriptor_data)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930760{
761 uint16_t descriptor_length = 0;
762
763 if (data == NULL || descriptor_type == NULL ||
764 descriptor_data == NULL) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030765 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930766 }
767
768 if (length < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030769 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930770 }
771
772 struct pldm_descriptor_tlv *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930773 (struct pldm_descriptor_tlv *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930774
775 *descriptor_type = le16toh(entry->descriptor_type);
776 descriptor_length = le16toh(entry->descriptor_length);
777 if (*descriptor_type != PLDM_FWUP_VENDOR_DEFINED) {
778 if (descriptor_length !=
779 get_descriptor_type_length(*descriptor_type)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030780 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930781 }
782 }
783
784 if (length < (sizeof(*descriptor_type) + sizeof(descriptor_length) +
785 descriptor_length)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030786 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930787 }
788
789 descriptor_data->ptr = entry->descriptor_data;
790 descriptor_data->length = descriptor_length;
791
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030792 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930793}
794
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930795LIBPLDM_ABI_STABLE
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030796int decode_descriptor_type_length_value(const uint8_t *data, size_t length,
797 uint16_t *descriptor_type,
798 struct variable_field *descriptor_data)
799{
800 int rc;
801
802 rc = decode_descriptor_type_length_value_errno(
803 data, length, descriptor_type, descriptor_data);
804 if (rc < 0) {
805 return pldm_xlate_errno(rc);
806 }
807
808 return PLDM_SUCCESS;
809}
810
811static int decode_vendor_defined_descriptor_value_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030812 const void *data, size_t length, uint8_t *descriptor_title_str_type,
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930813 struct variable_field *descriptor_title_str,
814 struct variable_field *descriptor_data)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930815{
816 if (data == NULL || descriptor_title_str_type == NULL ||
817 descriptor_title_str == NULL || descriptor_data == NULL) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030818 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930819 }
820
821 if (length < sizeof(struct pldm_vendor_defined_descriptor_title_data)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030822 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930823 }
824
825 struct pldm_vendor_defined_descriptor_title_data *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930826 (struct pldm_vendor_defined_descriptor_title_data *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930827 if (!is_string_type_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930828 entry->vendor_defined_descriptor_title_str_type) ||
Andrew Jeffery9c766792022-08-10 23:12:49 +0930829 (entry->vendor_defined_descriptor_title_str_len == 0)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030830 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930831 }
832
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530833 // Assuming at least 1 byte of VendorDefinedDescriptorData
Andrew Jeffery9c766792022-08-10 23:12:49 +0930834 if (length < (sizeof(struct pldm_vendor_defined_descriptor_title_data) +
835 entry->vendor_defined_descriptor_title_str_len)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030836 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930837 }
838
839 *descriptor_title_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930840 entry->vendor_defined_descriptor_title_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930841 descriptor_title_str->ptr = entry->vendor_defined_descriptor_title_str;
842 descriptor_title_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930843 entry->vendor_defined_descriptor_title_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930844
845 descriptor_data->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930846 descriptor_title_str->ptr + descriptor_title_str->length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930847 descriptor_data->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930848 length -
849 sizeof(entry->vendor_defined_descriptor_title_str_type) -
850 sizeof(entry->vendor_defined_descriptor_title_str_len) -
851 descriptor_title_str->length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930852
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030853 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930854}
855
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930856LIBPLDM_ABI_STABLE
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030857int decode_vendor_defined_descriptor_value(
858 const uint8_t *data, size_t length, uint8_t *descriptor_title_str_type,
859 struct variable_field *descriptor_title_str,
860 struct variable_field *descriptor_data)
861{
862 int rc;
863
864 rc = decode_vendor_defined_descriptor_value_errno(
865 data, length, descriptor_title_str_type, descriptor_title_str,
866 descriptor_data);
867 if (rc < 0) {
868 return pldm_xlate_errno(rc);
869 }
870
871 return PLDM_SUCCESS;
872}
873
874static int decode_pldm_comp_image_info_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030875 const void *data, size_t length,
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930876 struct pldm_component_image_information *pldm_comp_image_info,
877 struct variable_field *comp_version_str)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930878{
879 if (data == NULL || pldm_comp_image_info == NULL ||
880 comp_version_str == NULL) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030881 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930882 }
883
884 if (length < sizeof(struct pldm_component_image_information)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030885 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930886 }
887
888 struct pldm_component_image_information *data_header =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930889 (struct pldm_component_image_information *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930890
891 if (!is_string_type_valid(data_header->comp_version_string_type) ||
892 (data_header->comp_version_string_length == 0)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030893 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930894 }
895
896 if (length < sizeof(struct pldm_component_image_information) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930897 data_header->comp_version_string_length) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030898 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930899 }
900
901 pldm_comp_image_info->comp_classification =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930902 le16toh(data_header->comp_classification);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930903 pldm_comp_image_info->comp_identifier =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930904 le16toh(data_header->comp_identifier);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930905 pldm_comp_image_info->comp_comparison_stamp =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930906 le32toh(data_header->comp_comparison_stamp);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930907 pldm_comp_image_info->comp_options.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930908 le16toh(data_header->comp_options.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930909 pldm_comp_image_info->requested_comp_activation_method.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930910 le16toh(data_header->requested_comp_activation_method.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930911 pldm_comp_image_info->comp_location_offset =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930912 le32toh(data_header->comp_location_offset);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930913 pldm_comp_image_info->comp_size = le32toh(data_header->comp_size);
914 pldm_comp_image_info->comp_version_string_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930915 data_header->comp_version_string_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930916 pldm_comp_image_info->comp_version_string_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930917 data_header->comp_version_string_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930918
919 if ((pldm_comp_image_info->comp_options.bits.bit1 == false &&
920 pldm_comp_image_info->comp_comparison_stamp !=
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930921 PLDM_FWUP_INVALID_COMPONENT_COMPARISON_TIMESTAMP)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030922 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930923 }
924
925 if (pldm_comp_image_info->comp_location_offset == 0 ||
926 pldm_comp_image_info->comp_size == 0) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030927 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930928 }
929
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030930 comp_version_str->ptr = (const uint8_t *)data +
931 sizeof(struct pldm_component_image_information);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930932 comp_version_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930933 pldm_comp_image_info->comp_version_string_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930934
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030935 return 0;
936}
937
938LIBPLDM_ABI_STABLE
939int decode_pldm_comp_image_info(
940 const uint8_t *data, size_t length,
941 struct pldm_component_image_information *pldm_comp_image_info,
942 struct variable_field *comp_version_str)
943{
944 int rc;
945
946 rc = decode_pldm_comp_image_info_errno(
947 data, length, pldm_comp_image_info, comp_version_str);
948 if (rc < 0) {
949 return pldm_xlate_errno(rc);
950 }
951
Andrew Jeffery9c766792022-08-10 23:12:49 +0930952 return PLDM_SUCCESS;
953}
954
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930955LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930956int encode_query_device_identifiers_req(uint8_t instance_id,
957 size_t payload_length,
958 struct pldm_msg *msg)
959{
960 if (msg == NULL) {
961 return PLDM_ERROR_INVALID_DATA;
962 }
963
964 if (payload_length != PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES) {
965 return PLDM_ERROR_INVALID_LENGTH;
966 }
967
968 return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
969 PLDM_QUERY_DEVICE_IDENTIFIERS, msg);
970}
971
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930972LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930973int decode_query_device_identifiers_resp(const struct pldm_msg *msg,
974 size_t payload_length,
975 uint8_t *completion_code,
976 uint32_t *device_identifiers_len,
977 uint8_t *descriptor_count,
978 uint8_t **descriptor_data)
979{
980 if (msg == NULL || completion_code == NULL ||
981 device_identifiers_len == NULL || descriptor_count == NULL ||
982 descriptor_data == NULL) {
983 return PLDM_ERROR_INVALID_DATA;
984 }
985
986 *completion_code = msg->payload[0];
987 if (PLDM_SUCCESS != *completion_code) {
988 return PLDM_SUCCESS;
989 }
990
991 if (payload_length <
992 sizeof(struct pldm_query_device_identifiers_resp)) {
993 return PLDM_ERROR_INVALID_LENGTH;
994 }
995
996 struct pldm_query_device_identifiers_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930997 (struct pldm_query_device_identifiers_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930998 *device_identifiers_len = le32toh(response->device_identifiers_len);
999
1000 if (*device_identifiers_len < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {
1001 return PLDM_ERROR_INVALID_LENGTH;
1002 }
1003
1004 if (payload_length !=
1005 sizeof(struct pldm_query_device_identifiers_resp) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301006 *device_identifiers_len) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301007 return PLDM_ERROR_INVALID_LENGTH;
1008 }
1009 *descriptor_count = response->descriptor_count;
1010
1011 if (*descriptor_count == 0) {
1012 return PLDM_ERROR_INVALID_DATA;
1013 }
1014 *descriptor_data =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301015 (uint8_t *)(msg->payload +
1016 sizeof(struct pldm_query_device_identifiers_resp));
Andrew Jeffery9c766792022-08-10 23:12:49 +09301017 return PLDM_SUCCESS;
1018}
1019
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001020LIBPLDM_ABI_TESTING
1021int encode_query_device_identifiers_resp(
1022 uint8_t instance_id, uint8_t descriptor_count,
1023 const struct pldm_descriptor *descriptors, struct pldm_msg *msg,
1024 size_t *payload_length)
1025{
Andrew Jefferya1896962025-03-03 21:41:25 +10301026 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001027 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001028
1029 if (descriptors == NULL || msg == NULL || payload_length == NULL) {
1030 return -EINVAL;
1031 }
1032
1033 if (descriptor_count < 1) {
1034 return -EINVAL;
1035 }
1036
1037 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
1038 PLDM_QUERY_DEVICE_IDENTIFIERS, msg);
1039 if (rc) {
1040 return -EINVAL;
1041 }
1042
1043 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
1044 if (rc) {
1045 return rc;
1046 }
1047
1048 /* Determine total length */
1049 uint32_t device_identifiers_len = 0;
1050 for (uint8_t i = 0; i < descriptor_count; i++) {
1051 const struct pldm_descriptor *d = &descriptors[i];
1052 device_identifiers_len +=
1053 2 * sizeof(uint16_t) + d->descriptor_length;
1054 }
1055
1056 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
1057 pldm_msgbuf_insert(buf, device_identifiers_len);
1058 pldm_msgbuf_insert(buf, descriptor_count);
1059
1060 for (uint8_t i = 0; i < descriptor_count; i++) {
1061 const struct pldm_descriptor *d = &descriptors[i];
1062 pldm_msgbuf_insert(buf, d->descriptor_type);
1063 pldm_msgbuf_insert(buf, d->descriptor_length);
1064 if (d->descriptor_data == NULL) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301065 return pldm_msgbuf_discard(buf, -EINVAL);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001066 }
1067 rc = pldm_msgbuf_insert_array(
1068 buf, d->descriptor_length,
1069 (const uint8_t *)d->descriptor_data,
1070 d->descriptor_length);
1071 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301072 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001073 }
1074 }
1075
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301076 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001077}
1078
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301079LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301080int encode_get_firmware_parameters_req(uint8_t instance_id,
1081 size_t payload_length,
1082 struct pldm_msg *msg)
1083{
1084 if (msg == NULL) {
1085 return PLDM_ERROR_INVALID_DATA;
1086 }
1087
1088 if (payload_length != PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES) {
1089 return PLDM_ERROR_INVALID_LENGTH;
1090 }
1091
1092 return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
1093 PLDM_GET_FIRMWARE_PARAMETERS, msg);
1094}
1095
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301096LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301097int decode_get_firmware_parameters_resp(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301098 const struct pldm_msg *msg, size_t payload_length,
1099 struct pldm_get_firmware_parameters_resp *resp_data,
1100 struct variable_field *active_comp_image_set_ver_str,
1101 struct variable_field *pending_comp_image_set_ver_str,
1102 struct variable_field *comp_parameter_table)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301103{
1104 if (msg == NULL || resp_data == NULL ||
1105 active_comp_image_set_ver_str == NULL ||
1106 pending_comp_image_set_ver_str == NULL ||
1107 comp_parameter_table == NULL || !payload_length) {
1108 return PLDM_ERROR_INVALID_DATA;
1109 }
1110
1111 resp_data->completion_code = msg->payload[0];
1112 if (PLDM_SUCCESS != resp_data->completion_code) {
1113 return PLDM_SUCCESS;
1114 }
1115
1116 if (payload_length < sizeof(struct pldm_get_firmware_parameters_resp)) {
1117 return PLDM_ERROR_INVALID_LENGTH;
1118 }
1119
1120 struct pldm_get_firmware_parameters_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301121 (struct pldm_get_firmware_parameters_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301122
1123 if (!is_string_type_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301124 response->active_comp_image_set_ver_str_type) ||
Andrew Jeffery9c766792022-08-10 23:12:49 +09301125 (response->active_comp_image_set_ver_str_len == 0)) {
1126 return PLDM_ERROR_INVALID_DATA;
1127 }
1128
1129 if (response->pending_comp_image_set_ver_str_len == 0) {
1130 if (response->pending_comp_image_set_ver_str_type !=
1131 PLDM_STR_TYPE_UNKNOWN) {
1132 return PLDM_ERROR_INVALID_DATA;
1133 }
1134 } else {
1135 if (!is_string_type_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301136 response->pending_comp_image_set_ver_str_type)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301137 return PLDM_ERROR_INVALID_DATA;
1138 }
1139 }
1140
1141 size_t partial_response_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301142 sizeof(struct pldm_get_firmware_parameters_resp) +
1143 response->active_comp_image_set_ver_str_len +
1144 response->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301145
1146 if (payload_length < partial_response_length) {
1147 return PLDM_ERROR_INVALID_LENGTH;
1148 }
1149
1150 resp_data->capabilities_during_update.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301151 le32toh(response->capabilities_during_update.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301152 resp_data->comp_count = le16toh(response->comp_count);
1153 resp_data->active_comp_image_set_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301154 response->active_comp_image_set_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301155 resp_data->active_comp_image_set_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301156 response->active_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301157 resp_data->pending_comp_image_set_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301158 response->pending_comp_image_set_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301159 resp_data->pending_comp_image_set_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301160 response->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301161
1162 active_comp_image_set_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301163 msg->payload + sizeof(struct pldm_get_firmware_parameters_resp);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301164 active_comp_image_set_ver_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301165 resp_data->active_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301166
1167 if (resp_data->pending_comp_image_set_ver_str_len != 0) {
1168 pending_comp_image_set_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301169 msg->payload +
1170 sizeof(struct pldm_get_firmware_parameters_resp) +
1171 resp_data->active_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301172 pending_comp_image_set_ver_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301173 resp_data->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301174 } else {
1175 pending_comp_image_set_ver_str->ptr = NULL;
1176 pending_comp_image_set_ver_str->length = 0;
1177 }
1178
1179 if (payload_length > partial_response_length && resp_data->comp_count) {
1180 comp_parameter_table->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301181 msg->payload +
1182 sizeof(struct pldm_get_firmware_parameters_resp) +
1183 resp_data->active_comp_image_set_ver_str_len +
1184 resp_data->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301185 comp_parameter_table->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301186 payload_length - partial_response_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301187 } else {
1188 comp_parameter_table->ptr = NULL;
1189 comp_parameter_table->length = 0;
1190 }
1191
1192 return PLDM_SUCCESS;
1193}
1194
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001195LIBPLDM_ABI_TESTING
1196int encode_get_firmware_parameters_resp(
1197 uint8_t instance_id,
1198 const struct pldm_get_firmware_parameters_resp_full *resp_data,
1199 struct pldm_msg *msg, size_t *payload_length)
1200{
Andrew Jefferya1896962025-03-03 21:41:25 +10301201 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001202 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001203
1204 if (resp_data == NULL || msg == NULL || payload_length == NULL) {
1205 return -EINVAL;
1206 }
1207
1208 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
1209 PLDM_GET_FIRMWARE_PARAMETERS, msg);
1210 if (rc) {
1211 return -EINVAL;
1212 }
1213
1214 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
1215 if (rc) {
1216 return rc;
1217 }
1218
1219 pldm_msgbuf_insert(buf, resp_data->completion_code);
1220 pldm_msgbuf_insert(buf, resp_data->capabilities_during_update.value);
1221 pldm_msgbuf_insert(buf, resp_data->comp_count);
1222 pldm_msgbuf_insert(buf,
1223 resp_data->active_comp_image_set_ver_str.str_type);
1224 pldm_msgbuf_insert(buf,
1225 resp_data->active_comp_image_set_ver_str.str_len);
1226 pldm_msgbuf_insert(buf,
1227 resp_data->pending_comp_image_set_ver_str.str_type);
1228 pldm_msgbuf_insert(buf,
1229 resp_data->pending_comp_image_set_ver_str.str_len);
1230 /* String data appended */
1231 rc = pldm_msgbuf_insert_array(
1232 buf, resp_data->active_comp_image_set_ver_str.str_len,
1233 resp_data->active_comp_image_set_ver_str.str_data,
1234 resp_data->active_comp_image_set_ver_str.str_len);
1235 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301236 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001237 }
1238 rc = pldm_msgbuf_insert_array(
1239 buf, resp_data->pending_comp_image_set_ver_str.str_len,
1240 resp_data->pending_comp_image_set_ver_str.str_data,
1241 resp_data->pending_comp_image_set_ver_str.str_len);
1242 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301243 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001244 }
1245
1246 /* Further calls to encode_get_firmware_parameters_resp_comp_entry
1247 * will populate the remainder */
1248
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301249 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001250}
1251
1252LIBPLDM_ABI_TESTING
1253int encode_get_firmware_parameters_resp_comp_entry(
1254 const struct pldm_component_parameter_entry_full *comp,
1255 uint8_t *payload, size_t *payload_length)
1256{
Andrew Jefferya1896962025-03-03 21:41:25 +10301257 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001258 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001259
1260 if (comp == NULL || payload == NULL || payload_length == NULL) {
1261 return -EINVAL;
1262 }
1263
1264 rc = pldm_msgbuf_init_errno(buf, 0, payload, *payload_length);
1265 if (rc) {
1266 return rc;
1267 }
1268
1269 pldm_msgbuf_insert(buf, comp->comp_classification);
1270 pldm_msgbuf_insert(buf, comp->comp_identifier);
1271 pldm_msgbuf_insert(buf, comp->comp_classification_index);
1272
1273 pldm_msgbuf_insert(buf, comp->active_ver.comparison_stamp);
1274 pldm_msgbuf_insert(buf, (uint8_t)comp->active_ver.str.str_type);
1275 pldm_msgbuf_insert(buf, comp->active_ver.str.str_len);
1276 rc = pldm_msgbuf_insert_array(buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1277 comp->active_ver.date,
1278 PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN);
1279 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301280 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001281 }
1282
1283 pldm_msgbuf_insert(buf, comp->pending_ver.comparison_stamp);
1284 pldm_msgbuf_insert(buf, (uint8_t)comp->pending_ver.str.str_type);
1285 pldm_msgbuf_insert(buf, comp->pending_ver.str.str_len);
1286 rc = pldm_msgbuf_insert_array(buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1287 comp->pending_ver.date,
1288 PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN);
1289 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301290 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001291 }
1292
1293 pldm_msgbuf_insert(buf, comp->comp_activation_methods.value);
1294 pldm_msgbuf_insert(buf, comp->capabilities_during_update.value);
1295
1296 rc = pldm_msgbuf_insert_array(buf, comp->active_ver.str.str_len,
1297 comp->active_ver.str.str_data,
1298 comp->active_ver.str.str_len);
1299 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301300 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001301 }
1302 rc = pldm_msgbuf_insert_array(buf, comp->pending_ver.str.str_len,
1303 comp->pending_ver.str.str_data,
1304 comp->pending_ver.str.str_len);
1305 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301306 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001307 }
1308
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301309 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001310}
1311
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301312LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301313int decode_get_firmware_parameters_resp_comp_entry(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301314 const uint8_t *data, size_t length,
1315 struct pldm_component_parameter_entry *component_data,
1316 struct variable_field *active_comp_ver_str,
1317 struct variable_field *pending_comp_ver_str)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301318{
1319 if (data == NULL || component_data == NULL ||
1320 active_comp_ver_str == NULL || pending_comp_ver_str == NULL) {
1321 return PLDM_ERROR_INVALID_DATA;
1322 }
1323
1324 if (length < sizeof(struct pldm_component_parameter_entry)) {
1325 return PLDM_ERROR_INVALID_LENGTH;
1326 }
1327
1328 struct pldm_component_parameter_entry *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301329 (struct pldm_component_parameter_entry *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301330
1331 size_t entry_length = sizeof(struct pldm_component_parameter_entry) +
1332 entry->active_comp_ver_str_len +
1333 entry->pending_comp_ver_str_len;
1334
1335 if (length < entry_length) {
1336 return PLDM_ERROR_INVALID_LENGTH;
1337 }
1338
1339 component_data->comp_classification =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301340 le16toh(entry->comp_classification);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301341 component_data->comp_identifier = le16toh(entry->comp_identifier);
1342 component_data->comp_classification_index =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301343 entry->comp_classification_index;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301344 component_data->active_comp_comparison_stamp =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301345 le32toh(entry->active_comp_comparison_stamp);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301346 component_data->active_comp_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301347 entry->active_comp_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301348 component_data->active_comp_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301349 entry->active_comp_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301350 memcpy(component_data->active_comp_release_date,
1351 entry->active_comp_release_date,
1352 sizeof(entry->active_comp_release_date));
1353 component_data->pending_comp_comparison_stamp =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301354 le32toh(entry->pending_comp_comparison_stamp);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301355 component_data->pending_comp_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301356 entry->pending_comp_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301357 component_data->pending_comp_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301358 entry->pending_comp_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301359 memcpy(component_data->pending_comp_release_date,
1360 entry->pending_comp_release_date,
1361 sizeof(entry->pending_comp_release_date));
1362 component_data->comp_activation_methods.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301363 le16toh(entry->comp_activation_methods.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301364 component_data->capabilities_during_update.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301365 le32toh(entry->capabilities_during_update.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301366
1367 if (entry->active_comp_ver_str_len != 0) {
1368 active_comp_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301369 data + sizeof(struct pldm_component_parameter_entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301370 active_comp_ver_str->length = entry->active_comp_ver_str_len;
1371 } else {
1372 active_comp_ver_str->ptr = NULL;
1373 active_comp_ver_str->length = 0;
1374 }
1375
1376 if (entry->pending_comp_ver_str_len != 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301377 pending_comp_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301378 data + sizeof(struct pldm_component_parameter_entry) +
1379 entry->active_comp_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301380 pending_comp_ver_str->length = entry->pending_comp_ver_str_len;
1381 } else {
1382 pending_comp_ver_str->ptr = NULL;
1383 pending_comp_ver_str->length = 0;
1384 }
1385 return PLDM_SUCCESS;
1386}
1387
Unive Tiene5c3f142024-12-13 14:14:19 +08001388LIBPLDM_ABI_STABLE
Chris Wang4c1f2c72024-03-21 17:09:44 +08001389int encode_query_downstream_devices_req(uint8_t instance_id,
1390 struct pldm_msg *msg)
1391{
1392 if (msg == NULL) {
Unive Tien71e935c2024-11-25 17:21:43 +08001393 return -EINVAL;
Chris Wang4c1f2c72024-03-21 17:09:44 +08001394 }
1395
Unive Tien71e935c2024-11-25 17:21:43 +08001396 return encode_pldm_header_only_errno(PLDM_REQUEST, instance_id,
1397 PLDM_FWUP,
1398 PLDM_QUERY_DOWNSTREAM_DEVICES,
1399 msg);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001400}
1401
Unive Tiene5c3f142024-12-13 14:14:19 +08001402LIBPLDM_ABI_STABLE
Chris Wang4c1f2c72024-03-21 17:09:44 +08001403int decode_query_downstream_devices_resp(
1404 const struct pldm_msg *msg, size_t payload_length,
1405 struct pldm_query_downstream_devices_resp *resp_data)
1406{
Andrew Jefferya1896962025-03-03 21:41:25 +10301407 PLDM_MSGBUF_DEFINE_P(buf);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001408 int rc;
1409
1410 if (msg == NULL || resp_data == NULL || !payload_length) {
Unive Tien71e935c2024-11-25 17:21:43 +08001411 return -EINVAL;
Chris Wang4c1f2c72024-03-21 17:09:44 +08001412 }
1413
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301414 rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1415 msg->payload, payload_length);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001416 if (rc) {
1417 return rc;
1418 }
1419
1420 rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1421 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301422 return pldm_msgbuf_discard(buf, rc);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001423 }
1424 if (PLDM_SUCCESS != resp_data->completion_code) {
1425 // Return the CC directly without decoding the rest of the payload
Andrew Jefferya1896962025-03-03 21:41:25 +10301426 return pldm_msgbuf_complete(buf);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001427 }
1428
1429 if (payload_length < PLDM_QUERY_DOWNSTREAM_DEVICES_RESP_BYTES) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301430 return pldm_msgbuf_discard(buf, -EBADMSG);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001431 }
1432
1433 rc = pldm_msgbuf_extract(buf,
1434 resp_data->downstream_device_update_supported);
1435 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301436 return pldm_msgbuf_discard(buf, rc);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001437 }
1438
1439 if (!is_downstream_device_update_support_valid(
1440 resp_data->downstream_device_update_supported)) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301441 return pldm_msgbuf_discard(buf, -EINVAL);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001442 }
1443
1444 pldm_msgbuf_extract(buf, resp_data->number_of_downstream_devices);
1445 pldm_msgbuf_extract(buf, resp_data->max_number_of_downstream_devices);
1446 pldm_msgbuf_extract(buf, resp_data->capabilities.value);
1447
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301448 return pldm_msgbuf_complete_consumed(buf);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001449}
1450
Unive Tiene5c3f142024-12-13 14:14:19 +08001451LIBPLDM_ABI_STABLE
Chris Wang458475a2024-03-26 17:59:19 +08001452int encode_query_downstream_identifiers_req(
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001453 uint8_t instance_id,
1454 const struct pldm_query_downstream_identifiers_req *params_req,
1455 struct pldm_msg *msg, size_t payload_length)
Chris Wang458475a2024-03-26 17:59:19 +08001456{
Andrew Jefferya1896962025-03-03 21:41:25 +10301457 PLDM_MSGBUF_DEFINE_P(buf);
Chris Wang458475a2024-03-26 17:59:19 +08001458 int rc;
1459
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001460 if (!msg || !params_req) {
Unive Tien71e935c2024-11-25 17:21:43 +08001461 return -EINVAL;
Chris Wang458475a2024-03-26 17:59:19 +08001462 }
1463
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001464 if (!is_transfer_operation_flag_valid(
1465 (enum transfer_op_flag)
1466 params_req->transfer_operation_flag)) {
Unive Tien71e935c2024-11-25 17:21:43 +08001467 return -EINVAL;
Chris Wang458475a2024-03-26 17:59:19 +08001468 }
1469
1470 struct pldm_header_info header = { 0 };
1471 header.instance = instance_id;
1472 header.msg_type = PLDM_REQUEST;
1473 header.pldm_type = PLDM_FWUP;
1474 header.command = PLDM_QUERY_DOWNSTREAM_IDENTIFIERS;
Unive Tien71e935c2024-11-25 17:21:43 +08001475 rc = pack_pldm_header_errno(&header, &(msg->hdr));
Chris Wang458475a2024-03-26 17:59:19 +08001476 if (rc) {
1477 return rc;
1478 }
1479
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301480 rc = pldm_msgbuf_init_errno(buf,
1481 PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_REQ_BYTES,
1482 msg->payload, payload_length);
Chris Wang458475a2024-03-26 17:59:19 +08001483 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001484 return rc;
Chris Wang458475a2024-03-26 17:59:19 +08001485 }
1486
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001487 pldm_msgbuf_insert(buf, params_req->data_transfer_handle);
Chris Wang458475a2024-03-26 17:59:19 +08001488 // Data correctness has been verified, cast it to 1-byte data directly.
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001489 pldm_msgbuf_insert(buf, params_req->transfer_operation_flag);
Chris Wang458475a2024-03-26 17:59:19 +08001490
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301491 return pldm_msgbuf_complete(buf);
Chris Wang458475a2024-03-26 17:59:19 +08001492}
1493
Unive Tiene5c3f142024-12-13 14:14:19 +08001494LIBPLDM_ABI_STABLE
Chris Wang458475a2024-03-26 17:59:19 +08001495int decode_query_downstream_identifiers_resp(
1496 const struct pldm_msg *msg, size_t payload_length,
1497 struct pldm_query_downstream_identifiers_resp *resp_data,
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301498 struct pldm_downstream_device_iter *iter)
Chris Wang458475a2024-03-26 17:59:19 +08001499{
Andrew Jefferya1896962025-03-03 21:41:25 +10301500 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301501 void *remaining = NULL;
Unive Tien71e935c2024-11-25 17:21:43 +08001502 int rc = 0;
Chris Wang458475a2024-03-26 17:59:19 +08001503
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301504 if (msg == NULL || resp_data == NULL || iter == NULL ||
Chris Wang458475a2024-03-26 17:59:19 +08001505 !payload_length) {
Unive Tien71e935c2024-11-25 17:21:43 +08001506 return -EINVAL;
Chris Wang458475a2024-03-26 17:59:19 +08001507 }
1508
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301509 rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1510 msg->payload, payload_length);
Chris Wang458475a2024-03-26 17:59:19 +08001511 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001512 return rc;
Chris Wang458475a2024-03-26 17:59:19 +08001513 }
1514
1515 rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1516 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301517 return pldm_msgbuf_discard(buf, rc);
Chris Wang458475a2024-03-26 17:59:19 +08001518 }
1519 if (PLDM_SUCCESS != resp_data->completion_code) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301520 return pldm_msgbuf_complete(buf);
Chris Wang458475a2024-03-26 17:59:19 +08001521 }
1522
1523 if (payload_length < PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_RESP_MIN_LEN) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301524 return pldm_msgbuf_discard(buf, -EBADMSG);
Chris Wang458475a2024-03-26 17:59:19 +08001525 }
1526
1527 pldm_msgbuf_extract(buf, resp_data->next_data_transfer_handle);
1528 pldm_msgbuf_extract(buf, resp_data->transfer_flag);
1529
1530 rc = pldm_msgbuf_extract(buf, resp_data->downstream_devices_length);
1531 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301532 return pldm_msgbuf_discard(buf, rc);
Chris Wang458475a2024-03-26 17:59:19 +08001533 }
1534
1535 pldm_msgbuf_extract(buf, resp_data->number_of_downstream_devices);
Andrew Jefferya1896962025-03-03 21:41:25 +10301536 pldm_msgbuf_span_required(buf, resp_data->downstream_devices_length,
1537 &remaining);
Chris Wang458475a2024-03-26 17:59:19 +08001538
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301539 rc = pldm_msgbuf_complete(buf);
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301540 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001541 return rc;
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301542 }
1543
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301544 iter->field.ptr = remaining;
1545 iter->field.length = resp_data->downstream_devices_length;
1546 iter->devs = resp_data->number_of_downstream_devices;
1547
Unive Tien71e935c2024-11-25 17:21:43 +08001548 return 0;
Chris Wang458475a2024-03-26 17:59:19 +08001549}
1550
Unive Tiene5c3f142024-12-13 14:14:19 +08001551LIBPLDM_ABI_STABLE
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301552int decode_pldm_downstream_device_from_iter(
1553 struct pldm_downstream_device_iter *iter,
1554 struct pldm_downstream_device *dev)
1555{
Andrew Jefferya1896962025-03-03 21:41:25 +10301556 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301557 int rc;
1558
Andrew Jefferya1896962025-03-03 21:41:25 +10301559 if (!iter || !iter->field.ptr || !dev) {
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301560 return -EINVAL;
1561 }
1562
1563 rc = pldm_msgbuf_init_errno(buf, 3, iter->field.ptr,
1564 iter->field.length);
1565 if (rc) {
1566 return rc;
1567 }
1568
1569 pldm_msgbuf_extract(buf, dev->downstream_device_index);
1570 pldm_msgbuf_extract(buf, dev->downstream_descriptor_count);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301571 pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
1572 &iter->field.length);
1573
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301574 return pldm_msgbuf_complete(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301575}
1576
Unive Tiene5c3f142024-12-13 14:14:19 +08001577LIBPLDM_ABI_STABLE
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301578int encode_get_downstream_firmware_parameters_req(
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001579 uint8_t instance_id,
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301580 const struct pldm_get_downstream_firmware_parameters_req *params_req,
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001581 struct pldm_msg *msg, size_t payload_length)
Chris Wangb6ef35b2024-07-03 09:35:42 +08001582{
Andrew Jefferya1896962025-03-03 21:41:25 +10301583 PLDM_MSGBUF_DEFINE_P(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001584 int rc;
1585
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001586 if (!msg || !params_req) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001587 return -EINVAL;
1588 }
1589
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001590 if (!is_transfer_operation_flag_valid(
1591 (enum transfer_op_flag)
1592 params_req->transfer_operation_flag)) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001593 return -EBADMSG;
1594 }
1595
1596 struct pldm_header_info header = { 0 };
1597 header.instance = instance_id;
1598 header.msg_type = PLDM_REQUEST;
1599 header.pldm_type = PLDM_FWUP;
1600 header.command = PLDM_QUERY_DOWNSTREAM_FIRMWARE_PARAMETERS;
1601 rc = pack_pldm_header_errno(&header, &msg->hdr);
1602 if (rc < 0) {
1603 return rc;
1604 }
1605
Andrew Jeffery53b08672025-03-04 12:26:18 +10301606 rc = pldm_msgbuf_init_errno(
1607 buf, PLDM_GET_DOWNSTREAM_FIRMWARE_PARAMETERS_REQ_BYTES,
1608 msg->payload, payload_length);
1609 if (rc < 0) {
1610 return rc;
1611 }
1612
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001613 pldm_msgbuf_insert(buf, params_req->data_transfer_handle);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001614 // Data correctness has been verified, cast it to 1-byte data directly.
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001615 pldm_msgbuf_insert(buf, params_req->transfer_operation_flag);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001616
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301617 return pldm_msgbuf_complete(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001618}
1619
Unive Tiene5c3f142024-12-13 14:14:19 +08001620LIBPLDM_ABI_STABLE
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301621int decode_get_downstream_firmware_parameters_resp(
Chris Wangb6ef35b2024-07-03 09:35:42 +08001622 const struct pldm_msg *msg, size_t payload_length,
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301623 struct pldm_get_downstream_firmware_parameters_resp *resp_data,
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301624 struct pldm_downstream_device_parameters_iter *iter)
Chris Wangb6ef35b2024-07-03 09:35:42 +08001625{
Andrew Jefferya1896962025-03-03 21:41:25 +10301626 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301627 void *remaining = NULL;
1628 size_t length;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001629 int rc;
1630
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301631 if (msg == NULL || resp_data == NULL || iter == NULL) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001632 return -EINVAL;
1633 }
1634
1635 rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1636 msg->payload, payload_length);
1637 if (rc < 0) {
1638 return rc;
1639 }
1640
1641 rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1642 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301643 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001644 }
1645 if (PLDM_SUCCESS != resp_data->completion_code) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301646 return pldm_msgbuf_complete(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001647 }
1648
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301649 if (payload_length <
1650 PLDM_GET_DOWNSTREAM_FIRMWARE_PARAMETERS_RESP_MIN_LEN) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301651 return pldm_msgbuf_discard(buf, -EBADMSG);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001652 }
1653
1654 pldm_msgbuf_extract(buf, resp_data->next_data_transfer_handle);
1655 pldm_msgbuf_extract(buf, resp_data->transfer_flag);
1656 pldm_msgbuf_extract(buf,
1657 resp_data->fdp_capabilities_during_update.value);
1658 pldm_msgbuf_extract(buf, resp_data->downstream_device_count);
1659
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301660 rc = pldm_msgbuf_span_remaining(buf, &remaining, &length);
1661 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301662 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301663 }
1664
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301665 rc = pldm_msgbuf_complete(buf);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301666 if (rc) {
1667 return rc;
1668 }
1669
1670 iter->field.ptr = remaining;
1671 iter->field.length = length;
1672 iter->entries = resp_data->downstream_device_count;
1673
1674 return 0;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001675}
1676
Unive Tiene5c3f142024-12-13 14:14:19 +08001677LIBPLDM_ABI_STABLE
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301678int decode_pldm_downstream_device_parameters_entry_from_iter(
1679 struct pldm_downstream_device_parameters_iter *iter,
1680 struct pldm_downstream_device_parameters_entry *entry)
Chris Wangb6ef35b2024-07-03 09:35:42 +08001681{
Andrew Jefferya1896962025-03-03 21:41:25 +10301682 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301683 void *comp_ver_str;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001684 size_t remaining;
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301685 void *cursor;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001686 int rc;
1687
Andrew Jefferya1896962025-03-03 21:41:25 +10301688 if (iter == NULL || iter->field.ptr == NULL || entry == NULL) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001689 return -EINVAL;
1690 }
1691
1692 rc = pldm_msgbuf_init_errno(
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301693 buf, PLDM_DOWNSTREAM_DEVICE_PARAMETERS_ENTRY_MIN_LEN,
1694 iter->field.ptr, iter->field.length);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001695 if (rc < 0) {
1696 return rc;
1697 }
1698
1699 pldm_msgbuf_extract(buf, entry->downstream_device_index);
1700 pldm_msgbuf_extract(buf, entry->active_comp_comparison_stamp);
1701 pldm_msgbuf_extract(buf, entry->active_comp_ver_str_type);
1702 rc = pldm_msgbuf_extract(buf, entry->active_comp_ver_str_len);
1703 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301704 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001705 }
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001706 rc = pldm_msgbuf_extract_array(buf,
1707 PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1708 entry->active_comp_release_date,
1709 sizeof(entry->active_comp_release_date));
1710 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301711 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001712 }
1713
Chris Wangb6ef35b2024-07-03 09:35:42 +08001714 // Fill the last byte with NULL character
1715 entry->active_comp_release_date[PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN] =
1716 '\0';
1717
1718 pldm_msgbuf_extract(buf, entry->pending_comp_comparison_stamp);
1719 pldm_msgbuf_extract(buf, entry->pending_comp_ver_str_type);
1720 rc = pldm_msgbuf_extract(buf, entry->pending_comp_ver_str_len);
1721 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301722 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001723 }
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001724
1725 rc = pldm_msgbuf_extract_array(
1726 buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1727 entry->pending_comp_release_date,
1728 sizeof(entry->pending_comp_release_date));
1729 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301730 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001731 }
1732
Chris Wangb6ef35b2024-07-03 09:35:42 +08001733 // Fill the last byte with NULL character
1734 entry->pending_comp_release_date[PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN] =
1735 '\0';
1736
1737 pldm_msgbuf_extract(buf, entry->comp_activation_methods.value);
1738 pldm_msgbuf_extract(buf, entry->capabilities_during_update.value);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001739
Andrew Jefferya1896962025-03-03 21:41:25 +10301740 rc = pldm_msgbuf_span_required(buf, entry->active_comp_ver_str_len,
1741 &comp_ver_str);
1742 if (rc < 0) {
1743 return pldm_msgbuf_discard(buf, rc);
1744 }
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301745 entry->active_comp_ver_str = comp_ver_str;
1746
Andrew Jefferya1896962025-03-03 21:41:25 +10301747 rc = pldm_msgbuf_span_required(buf, entry->pending_comp_ver_str_len,
1748 &comp_ver_str);
1749 if (rc < 0) {
1750 return pldm_msgbuf_discard(buf, rc);
1751 }
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301752 entry->pending_comp_ver_str = comp_ver_str;
1753
Chris Wangb6ef35b2024-07-03 09:35:42 +08001754 rc = pldm_msgbuf_span_remaining(buf, &cursor, &remaining);
1755 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301756 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001757 }
1758
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301759 iter->field.ptr = cursor;
1760 iter->field.length = remaining;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001761
Andrew Jefferya1896962025-03-03 21:41:25 +10301762 return pldm_msgbuf_complete(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001763}
1764
Sora Su06eadd02025-05-27 11:28:51 +08001765LIBPLDM_ABI_TESTING
1766int encode_request_downstream_device_update_req(
1767 uint8_t instance_id,
1768 const struct pldm_request_downstream_device_update_req *req_data,
1769 struct pldm_msg *msg, size_t *payload_length)
1770{
1771 PLDM_MSGBUF_DEFINE_P(buf);
1772 int rc;
1773
1774 if (!req_data || !msg || !payload_length ||
1775 req_data->maximum_downstream_device_transfer_size <
1776 PLDM_FWUP_BASELINE_TRANSFER_SIZE ||
1777 req_data->maximum_outstanding_transfer_requests <
1778 PLDM_FWUP_MIN_OUTSTANDING_REQ) {
1779 return -EINVAL;
1780 }
1781
1782 rc = encode_pldm_header_only_errno(
1783 PLDM_REQUEST, instance_id, PLDM_FWUP,
1784 PLDM_REQUEST_DOWNSTREAM_DEVICE_UPDATE, msg);
1785 if (rc) {
1786 return rc;
1787 }
1788
1789 rc = pldm_msgbuf_init_errno(buf,
1790 PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES,
1791 msg->payload, *payload_length);
1792 if (rc) {
1793 return rc;
1794 }
1795
1796 pldm_msgbuf_insert(buf,
1797 req_data->maximum_downstream_device_transfer_size);
1798 pldm_msgbuf_insert(buf,
1799 req_data->maximum_outstanding_transfer_requests);
1800 pldm_msgbuf_insert(buf,
1801 req_data->downstream_device_package_data_length);
1802
1803 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
1804}
1805
1806LIBPLDM_ABI_TESTING
1807int decode_request_downstream_device_update_req(
1808 const struct pldm_msg *msg, size_t payload_length,
1809 struct pldm_request_downstream_device_update_req *req)
1810{
1811 int rc;
1812 PLDM_MSGBUF_DEFINE_P(buf);
1813
1814 if (!msg || !req) {
1815 return -EINVAL;
1816 }
1817
1818 rc = pldm_msgbuf_init_errno(buf,
1819 PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES,
1820 msg->payload, payload_length);
1821 if (rc) {
1822 return rc;
1823 }
1824
1825 pldm_msgbuf_extract(buf, req->maximum_downstream_device_transfer_size);
1826 pldm_msgbuf_extract(buf, req->maximum_outstanding_transfer_requests);
1827 pldm_msgbuf_extract(buf, req->downstream_device_package_data_length);
1828
1829 return pldm_msgbuf_complete_consumed(buf);
1830}
1831
1832LIBPLDM_ABI_TESTING
1833int encode_request_downstream_device_update_resp(
1834 uint8_t instance_id,
1835 const struct pldm_request_downstream_device_update_resp *resp_data,
1836 struct pldm_msg *msg, size_t *payload_length)
1837{
1838 PLDM_MSGBUF_DEFINE_P(buf);
1839 int rc;
1840
1841 if (!resp_data || !msg || !payload_length) {
1842 return -EINVAL;
1843 }
1844
1845 rc = encode_pldm_header_only_errno(
1846 PLDM_RESPONSE, instance_id, PLDM_FWUP,
1847 PLDM_REQUEST_DOWNSTREAM_DEVICE_UPDATE, msg);
1848 if (rc) {
1849 return rc;
1850 }
1851
1852 rc = pldm_msgbuf_init_errno(
1853 buf, PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES, msg->payload,
1854 *payload_length);
1855 if (rc) {
1856 return rc;
1857 }
1858
1859 pldm_msgbuf_insert(buf, resp_data->completion_code);
1860 pldm_msgbuf_insert(buf, resp_data->downstream_device_meta_data_length);
1861 pldm_msgbuf_insert(
1862 buf, resp_data->downstream_device_will_send_get_package_data);
1863 pldm_msgbuf_insert(buf,
1864 resp_data->get_package_data_maximum_transfer_size);
1865
1866 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
1867}
1868
1869LIBPLDM_ABI_TESTING
1870int decode_request_downstream_device_update_resp(
1871 const struct pldm_msg *msg, size_t payload_length,
1872 struct pldm_request_downstream_device_update_resp *resp_data)
1873{
1874 PLDM_MSGBUF_DEFINE_P(buf);
1875 int rc;
1876
1877 if (!msg || !resp_data) {
1878 return -EINVAL;
1879 }
1880
1881 rc = pldm_msg_has_error(msg,
1882 PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES);
1883 if (rc) {
1884 resp_data->completion_code = rc;
1885 return 0;
1886 }
1887
1888 rc = pldm_msgbuf_init_errno(
1889 buf, PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES, msg->payload,
1890 payload_length);
1891 if (rc) {
1892 return rc;
1893 }
1894
1895 pldm_msgbuf_extract(buf, resp_data->completion_code);
1896 pldm_msgbuf_extract(buf, resp_data->downstream_device_meta_data_length);
1897 pldm_msgbuf_extract(
1898 buf, resp_data->downstream_device_will_send_get_package_data);
1899 pldm_msgbuf_extract(buf,
1900 resp_data->get_package_data_maximum_transfer_size);
1901
1902 return pldm_msgbuf_complete_consumed(buf);
1903}
1904
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301905LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301906int encode_request_update_req(uint8_t instance_id, uint32_t max_transfer_size,
1907 uint16_t num_of_comp,
1908 uint8_t max_outstanding_transfer_req,
1909 uint16_t pkg_data_len,
1910 uint8_t comp_image_set_ver_str_type,
1911 uint8_t comp_image_set_ver_str_len,
1912 const struct variable_field *comp_img_set_ver_str,
1913 struct pldm_msg *msg, size_t payload_length)
1914{
1915 if (comp_img_set_ver_str == NULL || comp_img_set_ver_str->ptr == NULL ||
1916 msg == NULL) {
1917 return PLDM_ERROR_INVALID_DATA;
1918 }
1919
1920 if (payload_length != sizeof(struct pldm_request_update_req) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301921 comp_img_set_ver_str->length) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301922 return PLDM_ERROR_INVALID_LENGTH;
1923 }
1924
1925 if ((comp_image_set_ver_str_len == 0) ||
1926 (comp_image_set_ver_str_len != comp_img_set_ver_str->length)) {
1927 return PLDM_ERROR_INVALID_DATA;
1928 }
1929
1930 if ((max_transfer_size < PLDM_FWUP_BASELINE_TRANSFER_SIZE) ||
1931 (max_outstanding_transfer_req < PLDM_FWUP_MIN_OUTSTANDING_REQ)) {
1932 return PLDM_ERROR_INVALID_DATA;
1933 }
1934
1935 if (!is_string_type_valid(comp_image_set_ver_str_type)) {
1936 return PLDM_ERROR_INVALID_DATA;
1937 }
1938
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301939 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09301940 header.instance = instance_id;
1941 header.msg_type = PLDM_REQUEST;
1942 header.pldm_type = PLDM_FWUP;
1943 header.command = PLDM_REQUEST_UPDATE;
1944 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1945 if (rc) {
1946 return rc;
1947 }
1948
1949 struct pldm_request_update_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301950 (struct pldm_request_update_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301951
1952 request->max_transfer_size = htole32(max_transfer_size);
1953 request->num_of_comp = htole16(num_of_comp);
1954 request->max_outstanding_transfer_req = max_outstanding_transfer_req;
1955 request->pkg_data_len = htole16(pkg_data_len);
1956 request->comp_image_set_ver_str_type = comp_image_set_ver_str_type;
1957 request->comp_image_set_ver_str_len = comp_image_set_ver_str_len;
1958
1959 memcpy(msg->payload + sizeof(struct pldm_request_update_req),
1960 comp_img_set_ver_str->ptr, comp_img_set_ver_str->length);
1961
1962 return PLDM_SUCCESS;
1963}
1964
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001965LIBPLDM_ABI_TESTING
1966int decode_request_update_req(const struct pldm_msg *msg, size_t payload_length,
1967 struct pldm_request_update_req_full *req)
1968{
1969 int rc;
1970 uint8_t t;
Andrew Jefferya1896962025-03-03 21:41:25 +10301971 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001972
1973 if (msg == NULL || req == NULL) {
1974 return -EINVAL;
1975 }
1976
1977 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
1978 if (rc) {
1979 return rc;
1980 }
1981
1982 pldm_msgbuf_extract(buf, req->max_transfer_size);
1983 pldm_msgbuf_extract(buf, req->num_of_comp);
1984 pldm_msgbuf_extract(buf, req->max_outstanding_transfer_req);
1985 pldm_msgbuf_extract(buf, req->pkg_data_len);
1986 rc = pldm_msgbuf_extract(buf, t);
1987 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301988 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001989 }
1990 if (t > PLDM_STR_TYPE_UTF_16BE) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301991 return pldm_msgbuf_discard(buf, -EBADMSG);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001992 }
1993 req->image_set_ver.str_type = (enum pldm_firmware_update_string_type)t;
1994 pldm_msgbuf_extract(buf, req->image_set_ver.str_len);
1995 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301996 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001997 }
1998
1999 rc = pldm_msgbuf_extract_array(buf, req->image_set_ver.str_len,
2000 req->image_set_ver.str_data,
2001 PLDM_FIRMWARE_MAX_STRING);
2002 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302003 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002004 }
2005
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302006 return pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002007}
2008
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302009LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302010int decode_request_update_resp(const struct pldm_msg *msg,
2011 size_t payload_length, uint8_t *completion_code,
2012 uint16_t *fd_meta_data_len,
2013 uint8_t *fd_will_send_pkg_data)
2014{
2015 if (msg == NULL || completion_code == NULL ||
2016 fd_meta_data_len == NULL || fd_will_send_pkg_data == NULL ||
2017 !payload_length) {
2018 return PLDM_ERROR_INVALID_DATA;
2019 }
2020
2021 *completion_code = msg->payload[0];
2022 if (*completion_code != PLDM_SUCCESS) {
2023 return PLDM_SUCCESS;
2024 }
2025
2026 if (payload_length != sizeof(struct pldm_request_update_resp)) {
2027 return PLDM_ERROR_INVALID_LENGTH;
2028 }
2029
2030 struct pldm_request_update_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302031 (struct pldm_request_update_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302032
2033 *fd_meta_data_len = le16toh(response->fd_meta_data_len);
2034 *fd_will_send_pkg_data = response->fd_will_send_pkg_data;
2035
2036 return PLDM_SUCCESS;
2037}
2038
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002039LIBPLDM_ABI_TESTING
2040int encode_request_update_resp(uint8_t instance_id,
2041 const struct pldm_request_update_resp *resp_data,
2042 struct pldm_msg *msg, size_t *payload_length)
2043{
Andrew Jefferya1896962025-03-03 21:41:25 +10302044 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002045 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002046
2047 if (msg == NULL || payload_length == NULL) {
2048 return -EINVAL;
2049 }
2050
2051 struct pldm_header_info header = {
2052 .instance = instance_id,
2053 .msg_type = PLDM_RESPONSE,
2054 .pldm_type = PLDM_FWUP,
2055 .command = PLDM_REQUEST_UPDATE,
2056 };
2057 rc = pack_pldm_header(&header, &(msg->hdr));
2058 if (rc) {
2059 return -EINVAL;
2060 }
2061
2062 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2063 if (rc) {
2064 return rc;
2065 }
2066
2067 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2068 pldm_msgbuf_insert(buf, resp_data->fd_meta_data_len);
2069 pldm_msgbuf_insert(buf, resp_data->fd_will_send_pkg_data);
2070
2071 /* TODO: DSP0267 1.3.0 adds GetPackageDataMaximumTransferSize */
2072
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302073 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002074}
2075
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302076LIBPLDM_ABI_STABLE
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302077int encode_pass_component_table_req(uint8_t instance_id, uint8_t transfer_flag,
2078 uint16_t comp_classification,
2079 uint16_t comp_identifier,
2080 uint8_t comp_classification_index,
2081 uint32_t comp_comparison_stamp,
2082 uint8_t comp_ver_str_type,
2083 uint8_t comp_ver_str_len,
2084 const struct variable_field *comp_ver_str,
2085 struct pldm_msg *msg, size_t payload_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09302086{
2087 if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) {
2088 return PLDM_ERROR_INVALID_DATA;
2089 }
2090
2091 if (payload_length != sizeof(struct pldm_pass_component_table_req) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302092 comp_ver_str->length) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302093 return PLDM_ERROR_INVALID_LENGTH;
2094 }
2095
2096 if ((comp_ver_str_len == 0) ||
2097 (comp_ver_str_len != comp_ver_str->length)) {
2098 return PLDM_ERROR_INVALID_DATA;
2099 }
2100
2101 if (!is_transfer_flag_valid(transfer_flag)) {
Manojkiran Eda3643e742025-05-19 12:03:54 +05302102 return PLDM_FWUP_INVALID_TRANSFER_OPERATION_FLAG;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302103 }
2104
2105 if (!is_string_type_valid(comp_ver_str_type)) {
2106 return PLDM_ERROR_INVALID_DATA;
2107 }
2108
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302109 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302110 header.instance = instance_id;
2111 header.msg_type = PLDM_REQUEST;
2112 header.pldm_type = PLDM_FWUP;
2113 header.command = PLDM_PASS_COMPONENT_TABLE;
2114 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2115 if (rc) {
2116 return rc;
2117 }
2118
2119 struct pldm_pass_component_table_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302120 (struct pldm_pass_component_table_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302121
2122 request->transfer_flag = transfer_flag;
2123 request->comp_classification = htole16(comp_classification);
2124 request->comp_identifier = htole16(comp_identifier);
2125 request->comp_classification_index = comp_classification_index;
2126 request->comp_comparison_stamp = htole32(comp_comparison_stamp);
2127 request->comp_ver_str_type = comp_ver_str_type;
2128 request->comp_ver_str_len = comp_ver_str_len;
2129
2130 memcpy(msg->payload + sizeof(struct pldm_pass_component_table_req),
2131 comp_ver_str->ptr, comp_ver_str->length);
2132
2133 return PLDM_SUCCESS;
2134}
2135
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002136LIBPLDM_ABI_TESTING
2137int decode_pass_component_table_req(
2138 const struct pldm_msg *msg, size_t payload_length,
2139 struct pldm_pass_component_table_req_full *pcomp)
2140{
2141 int rc;
2142 uint8_t t;
Andrew Jefferya1896962025-03-03 21:41:25 +10302143 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002144
2145 if (msg == NULL || pcomp == NULL) {
2146 return -EINVAL;
2147 }
2148
2149 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2150 if (rc) {
2151 return rc;
2152 }
2153
2154 pldm_msgbuf_extract(buf, pcomp->transfer_flag);
2155 pldm_msgbuf_extract(buf, pcomp->comp_classification);
2156 pldm_msgbuf_extract(buf, pcomp->comp_identifier);
2157 pldm_msgbuf_extract(buf, pcomp->comp_classification_index);
2158 pldm_msgbuf_extract(buf, pcomp->comp_comparison_stamp);
2159 rc = pldm_msgbuf_extract(buf, t);
2160 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302161 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002162 }
2163 if (t > PLDM_STR_TYPE_UTF_16BE) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302164 return pldm_msgbuf_discard(buf, -EBADMSG);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002165 }
2166 pcomp->version.str_type = (enum pldm_firmware_update_string_type)t;
2167 rc = pldm_msgbuf_extract(buf, pcomp->version.str_len);
2168 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302169 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002170 }
2171 rc = pldm_msgbuf_extract_array(buf, pcomp->version.str_len,
2172 pcomp->version.str_data,
2173 PLDM_FIRMWARE_MAX_STRING);
2174 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302175 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002176 }
2177
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302178 return pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002179}
2180
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302181LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302182int decode_pass_component_table_resp(const struct pldm_msg *msg,
2183 const size_t payload_length,
2184 uint8_t *completion_code,
2185 uint8_t *comp_resp,
2186 uint8_t *comp_resp_code)
2187{
2188 if (msg == NULL || completion_code == NULL || comp_resp == NULL ||
2189 comp_resp_code == NULL || !payload_length) {
2190 return PLDM_ERROR_INVALID_DATA;
2191 }
2192
2193 *completion_code = msg->payload[0];
2194 if (*completion_code != PLDM_SUCCESS) {
2195 return PLDM_SUCCESS;
2196 }
2197
2198 if (payload_length != sizeof(struct pldm_pass_component_table_resp)) {
2199 return PLDM_ERROR_INVALID_LENGTH;
2200 }
2201
2202 struct pldm_pass_component_table_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302203 (struct pldm_pass_component_table_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302204
2205 if (!is_comp_resp_valid(response->comp_resp)) {
2206 return PLDM_ERROR_INVALID_DATA;
2207 }
2208
2209 if (!is_comp_resp_code_valid(response->comp_resp_code)) {
2210 return PLDM_ERROR_INVALID_DATA;
2211 }
2212
2213 *comp_resp = response->comp_resp;
2214 *comp_resp_code = response->comp_resp_code;
2215
2216 return PLDM_SUCCESS;
2217}
2218
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002219LIBPLDM_ABI_TESTING
2220int encode_pass_component_table_resp(
2221 uint8_t instance_id,
2222 const struct pldm_pass_component_table_resp *resp_data,
2223 struct pldm_msg *msg, size_t *payload_length)
2224{
Andrew Jefferya1896962025-03-03 21:41:25 +10302225 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002226 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002227
2228 if (msg == NULL || payload_length == NULL) {
2229 return -EINVAL;
2230 }
2231
2232 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2233 PLDM_PASS_COMPONENT_TABLE, msg);
2234 if (rc) {
2235 return -EINVAL;
2236 }
2237
2238 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2239 if (rc) {
2240 return rc;
2241 }
2242
2243 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2244 pldm_msgbuf_insert(buf, resp_data->comp_resp);
2245 pldm_msgbuf_insert(buf, resp_data->comp_resp_code);
2246
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302247 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002248}
2249
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302250LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302251int encode_update_component_req(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302252 uint8_t instance_id, uint16_t comp_classification,
2253 uint16_t comp_identifier, uint8_t comp_classification_index,
2254 uint32_t comp_comparison_stamp, uint32_t comp_image_size,
2255 bitfield32_t update_option_flags, uint8_t comp_ver_str_type,
2256 uint8_t comp_ver_str_len, const struct variable_field *comp_ver_str,
2257 struct pldm_msg *msg, size_t payload_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09302258{
2259 if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) {
2260 return PLDM_ERROR_INVALID_DATA;
2261 }
2262
2263 if (payload_length !=
2264 sizeof(struct pldm_update_component_req) + comp_ver_str->length) {
2265 return PLDM_ERROR_INVALID_LENGTH;
2266 }
2267
2268 if (!comp_image_size) {
2269 return PLDM_ERROR_INVALID_DATA;
2270 }
2271
2272 if ((comp_ver_str_len == 0) ||
2273 (comp_ver_str_len != comp_ver_str->length)) {
2274 return PLDM_ERROR_INVALID_DATA;
2275 }
2276
2277 if (!is_string_type_valid(comp_ver_str_type)) {
2278 return PLDM_ERROR_INVALID_DATA;
2279 }
2280
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302281 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302282 header.instance = instance_id;
2283 header.msg_type = PLDM_REQUEST;
2284 header.pldm_type = PLDM_FWUP;
2285 header.command = PLDM_UPDATE_COMPONENT;
2286 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2287 if (rc) {
2288 return rc;
2289 }
2290
2291 struct pldm_update_component_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302292 (struct pldm_update_component_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302293
2294 request->comp_classification = htole16(comp_classification);
2295 request->comp_identifier = htole16(comp_identifier);
2296 request->comp_classification_index = comp_classification_index;
2297 request->comp_comparison_stamp = htole32(comp_comparison_stamp);
2298 request->comp_image_size = htole32(comp_image_size);
2299 request->update_option_flags.value = htole32(update_option_flags.value);
2300 request->comp_ver_str_type = comp_ver_str_type;
2301 request->comp_ver_str_len = comp_ver_str_len;
2302
2303 memcpy(msg->payload + sizeof(struct pldm_update_component_req),
2304 comp_ver_str->ptr, comp_ver_str->length);
2305
2306 return PLDM_SUCCESS;
2307}
2308
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002309LIBPLDM_ABI_TESTING
2310int decode_update_component_req(const struct pldm_msg *msg,
2311 size_t payload_length,
2312 struct pldm_update_component_req_full *up)
2313{
2314 int rc;
2315 uint8_t t;
Andrew Jefferya1896962025-03-03 21:41:25 +10302316 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002317
2318 if (msg == NULL || up == NULL) {
2319 return -EINVAL;
2320 }
2321
2322 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2323 if (rc) {
2324 return rc;
2325 }
2326
2327 pldm_msgbuf_extract(buf, up->comp_classification);
2328 pldm_msgbuf_extract(buf, up->comp_identifier);
2329 pldm_msgbuf_extract(buf, up->comp_classification_index);
2330 pldm_msgbuf_extract(buf, up->comp_comparison_stamp);
2331 pldm_msgbuf_extract(buf, up->comp_image_size);
2332 pldm_msgbuf_extract(buf, up->update_option_flags.value);
2333 rc = pldm_msgbuf_extract(buf, t);
2334 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302335 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002336 }
2337 if (t > PLDM_STR_TYPE_UTF_16BE) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302338 return pldm_msgbuf_discard(buf, -EBADMSG);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002339 }
2340 up->version.str_type = (enum pldm_firmware_update_string_type)t;
2341 rc = pldm_msgbuf_extract(buf, up->version.str_len);
2342 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302343 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002344 }
2345 rc = pldm_msgbuf_extract_array(buf, up->version.str_len,
2346 up->version.str_data,
2347 PLDM_FIRMWARE_MAX_STRING);
2348 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302349 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002350 }
2351
Andrew Jefferya1896962025-03-03 21:41:25 +10302352 return pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002353}
2354
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302355LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302356int decode_update_component_resp(const struct pldm_msg *msg,
2357 size_t payload_length,
2358 uint8_t *completion_code,
2359 uint8_t *comp_compatibility_resp,
2360 uint8_t *comp_compatibility_resp_code,
2361 bitfield32_t *update_option_flags_enabled,
2362 uint16_t *time_before_req_fw_data)
2363{
2364 if (msg == NULL || completion_code == NULL ||
2365 comp_compatibility_resp == NULL ||
2366 comp_compatibility_resp_code == NULL ||
2367 update_option_flags_enabled == NULL ||
2368 time_before_req_fw_data == NULL || !payload_length) {
2369 return PLDM_ERROR_INVALID_DATA;
2370 }
2371
2372 *completion_code = msg->payload[0];
2373 if (*completion_code != PLDM_SUCCESS) {
2374 return PLDM_SUCCESS;
2375 }
2376
2377 if (payload_length != sizeof(struct pldm_update_component_resp)) {
2378 return PLDM_ERROR_INVALID_LENGTH;
2379 }
2380
2381 struct pldm_update_component_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302382 (struct pldm_update_component_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302383
2384 if (!is_comp_compatibility_resp_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302385 response->comp_compatibility_resp)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302386 return PLDM_ERROR_INVALID_DATA;
2387 }
2388
2389 if (!is_comp_compatibility_resp_code_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302390 response->comp_compatibility_resp_code)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302391 return PLDM_ERROR_INVALID_DATA;
2392 }
2393
2394 *comp_compatibility_resp = response->comp_compatibility_resp;
2395 *comp_compatibility_resp_code = response->comp_compatibility_resp_code;
2396 update_option_flags_enabled->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302397 le32toh(response->update_option_flags_enabled.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302398 *time_before_req_fw_data = le16toh(response->time_before_req_fw_data);
2399
2400 return PLDM_SUCCESS;
2401}
2402
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002403LIBPLDM_ABI_TESTING
2404int encode_update_component_resp(
2405 uint8_t instance_id, const struct pldm_update_component_resp *resp_data,
2406 struct pldm_msg *msg, size_t *payload_length)
2407{
Andrew Jefferya1896962025-03-03 21:41:25 +10302408 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002409 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002410
2411 if (msg == NULL || payload_length == NULL) {
2412 return -EINVAL;
2413 }
2414
2415 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2416 PLDM_UPDATE_COMPONENT, msg);
2417 if (rc) {
2418 return -EINVAL;
2419 }
2420
2421 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2422 if (rc) {
2423 return rc;
2424 }
2425
2426 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2427 pldm_msgbuf_insert(buf, resp_data->comp_compatibility_resp);
2428 pldm_msgbuf_insert(buf, resp_data->comp_compatibility_resp_code);
2429 pldm_msgbuf_insert(buf, resp_data->update_option_flags_enabled.value);
2430 pldm_msgbuf_insert(buf, resp_data->time_before_req_fw_data);
2431
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302432 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002433}
2434
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302435LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302436int decode_request_firmware_data_req(const struct pldm_msg *msg,
2437 size_t payload_length, uint32_t *offset,
2438 uint32_t *length)
2439{
2440 if (msg == NULL || offset == NULL || length == NULL) {
2441 return PLDM_ERROR_INVALID_DATA;
2442 }
2443 if (payload_length != sizeof(struct pldm_request_firmware_data_req)) {
2444 return PLDM_ERROR_INVALID_LENGTH;
2445 }
2446 struct pldm_request_firmware_data_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302447 (struct pldm_request_firmware_data_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302448 *offset = le32toh(request->offset);
2449 *length = le32toh(request->length);
2450
2451 if (*length < PLDM_FWUP_BASELINE_TRANSFER_SIZE) {
2452 return PLDM_FWUP_INVALID_TRANSFER_LENGTH;
2453 }
2454
2455 return PLDM_SUCCESS;
2456}
2457
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002458LIBPLDM_ABI_TESTING
2459int encode_request_firmware_data_req(
2460 uint8_t instance_id,
2461 const struct pldm_request_firmware_data_req *req_params,
2462 struct pldm_msg *msg, size_t *payload_length)
2463{
Andrew Jefferya1896962025-03-03 21:41:25 +10302464 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002465 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002466
2467 if (msg == NULL || payload_length == NULL) {
2468 return -EINVAL;
2469 }
2470
2471 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2472 PLDM_REQUEST_FIRMWARE_DATA, msg);
2473 if (rc) {
2474 return -EINVAL;
2475 }
2476
2477 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2478 if (rc) {
2479 return rc;
2480 }
2481
2482 pldm_msgbuf_insert(buf, req_params->offset);
2483 pldm_msgbuf_insert(buf, req_params->length);
2484
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302485 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002486}
2487
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302488LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302489int encode_request_firmware_data_resp(uint8_t instance_id,
2490 uint8_t completion_code,
2491 struct pldm_msg *msg,
2492 size_t payload_length)
2493{
2494 if (msg == NULL || !payload_length) {
2495 return PLDM_ERROR_INVALID_DATA;
2496 }
2497
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302498 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302499 header.instance = instance_id;
2500 header.msg_type = PLDM_RESPONSE;
2501 header.pldm_type = PLDM_FWUP;
2502 header.command = PLDM_REQUEST_FIRMWARE_DATA;
2503 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2504 if (rc) {
2505 return rc;
2506 }
2507
2508 msg->payload[0] = completion_code;
2509
2510 return PLDM_SUCCESS;
2511}
2512
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302513LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302514int decode_transfer_complete_req(const struct pldm_msg *msg,
2515 size_t payload_length,
2516 uint8_t *transfer_result)
2517{
2518 if (msg == NULL || transfer_result == NULL) {
2519 return PLDM_ERROR_INVALID_DATA;
2520 }
2521
2522 if (payload_length != sizeof(*transfer_result)) {
2523 return PLDM_ERROR_INVALID_LENGTH;
2524 }
2525
2526 *transfer_result = msg->payload[0];
2527 return PLDM_SUCCESS;
2528}
2529
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002530LIBPLDM_ABI_TESTING
2531int encode_transfer_complete_req(uint8_t instance_id, uint8_t transfer_result,
2532 struct pldm_msg *msg, size_t *payload_length)
2533{
Andrew Jefferya1896962025-03-03 21:41:25 +10302534 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002535 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002536
2537 if (msg == NULL || payload_length == NULL) {
2538 return -EINVAL;
2539 }
2540
2541 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2542 PLDM_TRANSFER_COMPLETE, msg);
2543 if (rc) {
2544 return -EINVAL;
2545 }
2546
2547 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2548 if (rc) {
2549 return rc;
2550 }
2551
Andrew Jefferya1896962025-03-03 21:41:25 +10302552 pldm_msgbuf_insert(buf, transfer_result);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002553
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302554 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002555}
2556
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302557LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302558int encode_transfer_complete_resp(uint8_t instance_id, uint8_t completion_code,
2559 struct pldm_msg *msg, size_t payload_length)
2560{
2561 if (msg == NULL) {
2562 return PLDM_ERROR_INVALID_DATA;
2563 }
2564
2565 if (payload_length != sizeof(completion_code)) {
2566 return PLDM_ERROR_INVALID_LENGTH;
2567 }
2568
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302569 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302570 header.instance = instance_id;
2571 header.msg_type = PLDM_RESPONSE;
2572 header.pldm_type = PLDM_FWUP;
2573 header.command = PLDM_TRANSFER_COMPLETE;
2574 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2575 if (rc) {
2576 return rc;
2577 }
2578
2579 msg->payload[0] = completion_code;
2580
2581 return PLDM_SUCCESS;
2582}
2583
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302584LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302585int decode_verify_complete_req(const struct pldm_msg *msg,
2586 size_t payload_length, uint8_t *verify_result)
2587{
2588 if (msg == NULL || verify_result == NULL) {
2589 return PLDM_ERROR_INVALID_DATA;
2590 }
2591
2592 if (payload_length != sizeof(*verify_result)) {
2593 return PLDM_ERROR_INVALID_LENGTH;
2594 }
2595
2596 *verify_result = msg->payload[0];
2597 return PLDM_SUCCESS;
2598}
2599
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002600LIBPLDM_ABI_TESTING
2601int encode_verify_complete_req(uint8_t instance_id, uint8_t verify_result,
2602 struct pldm_msg *msg, size_t *payload_length)
2603{
Andrew Jefferya1896962025-03-03 21:41:25 +10302604 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002605 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002606
2607 if (msg == NULL || payload_length == NULL) {
2608 return -EINVAL;
2609 }
2610
2611 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2612 PLDM_VERIFY_COMPLETE, msg);
2613 if (rc) {
2614 return EINVAL;
2615 }
2616
2617 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2618 if (rc) {
2619 return rc;
2620 }
2621
Andrew Jefferya1896962025-03-03 21:41:25 +10302622 pldm_msgbuf_insert(buf, verify_result);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002623
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302624 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002625}
2626
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302627LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302628int encode_verify_complete_resp(uint8_t instance_id, uint8_t completion_code,
2629 struct pldm_msg *msg, size_t payload_length)
2630{
2631 if (msg == NULL) {
2632 return PLDM_ERROR_INVALID_DATA;
2633 }
2634
2635 if (payload_length != sizeof(completion_code)) {
2636 return PLDM_ERROR_INVALID_LENGTH;
2637 }
2638
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302639 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302640 header.instance = instance_id;
2641 header.msg_type = PLDM_RESPONSE;
2642 header.pldm_type = PLDM_FWUP;
2643 header.command = PLDM_VERIFY_COMPLETE;
2644 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2645 if (rc) {
2646 return rc;
2647 }
2648
2649 msg->payload[0] = completion_code;
2650
2651 return PLDM_SUCCESS;
2652}
2653
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302654LIBPLDM_ABI_STABLE
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302655int decode_apply_complete_req(const struct pldm_msg *msg, size_t payload_length,
2656 uint8_t *apply_result,
2657 bitfield16_t *comp_activation_methods_modification)
Andrew Jeffery9c766792022-08-10 23:12:49 +09302658{
2659 if (msg == NULL || apply_result == NULL ||
2660 comp_activation_methods_modification == NULL) {
2661 return PLDM_ERROR_INVALID_DATA;
2662 }
2663
2664 if (payload_length != sizeof(struct pldm_apply_complete_req)) {
2665 return PLDM_ERROR_INVALID_LENGTH;
2666 }
2667
2668 struct pldm_apply_complete_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302669 (struct pldm_apply_complete_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302670
2671 *apply_result = request->apply_result;
2672 comp_activation_methods_modification->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302673 le16toh(request->comp_activation_methods_modification.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302674
2675 if ((*apply_result != PLDM_FWUP_APPLY_SUCCESS_WITH_ACTIVATION_METHOD) &&
2676 comp_activation_methods_modification->value) {
2677 return PLDM_ERROR_INVALID_DATA;
2678 }
2679
2680 return PLDM_SUCCESS;
2681}
2682
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002683LIBPLDM_ABI_TESTING
2684int encode_apply_complete_req(uint8_t instance_id,
2685 const struct pldm_apply_complete_req *req_data,
2686 struct pldm_msg *msg, size_t *payload_length)
2687{
Andrew Jefferya1896962025-03-03 21:41:25 +10302688 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002689 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002690
2691 if (msg == NULL || payload_length == NULL) {
2692 return -EINVAL;
2693 }
2694
2695 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2696 PLDM_APPLY_COMPLETE, msg);
2697 if (rc) {
2698 return -EINVAL;
2699 }
2700
2701 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2702 if (rc) {
2703 return rc;
2704 }
2705
2706 pldm_msgbuf_insert(buf, req_data->apply_result);
2707 pldm_msgbuf_insert(
2708 buf, req_data->comp_activation_methods_modification.value);
2709
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302710 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002711}
2712
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302713LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302714int encode_apply_complete_resp(uint8_t instance_id, uint8_t completion_code,
2715 struct pldm_msg *msg, size_t payload_length)
2716{
2717 if (msg == NULL) {
2718 return PLDM_ERROR_INVALID_DATA;
2719 }
2720
2721 if (payload_length != sizeof(completion_code)) {
2722 return PLDM_ERROR_INVALID_LENGTH;
2723 }
2724
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302725 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302726 header.instance = instance_id;
2727 header.msg_type = PLDM_RESPONSE;
2728 header.pldm_type = PLDM_FWUP;
2729 header.command = PLDM_APPLY_COMPLETE;
2730 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2731 if (rc) {
2732 return rc;
2733 }
2734
2735 msg->payload[0] = completion_code;
2736
2737 return PLDM_SUCCESS;
2738}
2739
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002740LIBPLDM_ABI_TESTING
2741int decode_activate_firmware_req(const struct pldm_msg *msg,
2742 size_t payload_length, bool *self_contained)
2743{
Andrew Jefferya1896962025-03-03 21:41:25 +10302744 uint8_t self_contained_u8 = 0;
2745 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002746 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002747
2748 if (msg == NULL || self_contained == NULL) {
2749 return -EINVAL;
2750 }
2751
2752 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2753 if (rc) {
2754 return 0;
2755 }
2756
Andrew Jefferya1896962025-03-03 21:41:25 +10302757 pldm_msgbuf_extract(buf, self_contained_u8);
2758
2759 rc = pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002760 if (rc) {
2761 return rc;
2762 }
Andrew Jefferya1896962025-03-03 21:41:25 +10302763
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002764 *self_contained = (bool)self_contained_u8;
2765 return 0;
2766}
2767
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302768LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302769int encode_activate_firmware_req(uint8_t instance_id,
2770 bool8_t self_contained_activation_req,
2771 struct pldm_msg *msg, size_t payload_length)
2772{
2773 if (msg == NULL) {
2774 return PLDM_ERROR_INVALID_DATA;
2775 }
2776
2777 if (payload_length != sizeof(struct pldm_activate_firmware_req)) {
2778 return PLDM_ERROR_INVALID_LENGTH;
2779 }
2780
2781 if (!is_self_contained_activation_req_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302782 self_contained_activation_req)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302783 return PLDM_ERROR_INVALID_DATA;
2784 }
2785
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302786 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302787 header.instance = instance_id;
2788 header.msg_type = PLDM_REQUEST;
2789 header.pldm_type = PLDM_FWUP;
2790 header.command = PLDM_ACTIVATE_FIRMWARE;
2791 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2792 if (rc) {
2793 return rc;
2794 }
2795
2796 struct pldm_activate_firmware_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302797 (struct pldm_activate_firmware_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302798
2799 request->self_contained_activation_req = self_contained_activation_req;
2800
2801 return PLDM_SUCCESS;
2802}
2803
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302804LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302805int decode_activate_firmware_resp(const struct pldm_msg *msg,
2806 size_t payload_length,
2807 uint8_t *completion_code,
2808 uint16_t *estimated_time_activation)
2809{
2810 if (msg == NULL || completion_code == NULL ||
2811 estimated_time_activation == NULL || !payload_length) {
2812 return PLDM_ERROR_INVALID_DATA;
2813 }
2814
2815 *completion_code = msg->payload[0];
2816 if (*completion_code != PLDM_SUCCESS) {
2817 return PLDM_SUCCESS;
2818 }
2819
2820 if (payload_length != sizeof(struct pldm_activate_firmware_resp)) {
2821 return PLDM_ERROR_INVALID_LENGTH;
2822 }
2823
2824 struct pldm_activate_firmware_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302825 (struct pldm_activate_firmware_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302826
2827 *estimated_time_activation =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302828 le16toh(response->estimated_time_activation);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302829
2830 return PLDM_SUCCESS;
2831}
2832
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002833LIBPLDM_ABI_TESTING
2834int encode_activate_firmware_resp(
2835 uint8_t instance_id,
2836 const struct pldm_activate_firmware_resp *resp_data,
2837 struct pldm_msg *msg, size_t *payload_length)
2838{
Andrew Jefferya1896962025-03-03 21:41:25 +10302839 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002840 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002841
2842 if (msg == NULL || payload_length == NULL) {
2843 return -EINVAL;
2844 }
2845
2846 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2847 PLDM_ACTIVATE_FIRMWARE, msg);
2848 if (rc) {
2849 return -EINVAL;
2850 }
2851
2852 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2853 if (rc) {
2854 return rc;
2855 }
2856
2857 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2858 pldm_msgbuf_insert(buf, resp_data->estimated_time_activation);
2859
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302860 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002861}
2862
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302863LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302864int encode_get_status_req(uint8_t instance_id, struct pldm_msg *msg,
2865 size_t payload_length)
2866{
2867 if (msg == NULL) {
2868 return PLDM_ERROR_INVALID_DATA;
2869 }
2870
2871 if (payload_length != PLDM_GET_STATUS_REQ_BYTES) {
2872 return PLDM_ERROR_INVALID_LENGTH;
2873 }
2874
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302875 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302876 header.instance = instance_id;
2877 header.msg_type = PLDM_REQUEST;
2878 header.pldm_type = PLDM_FWUP;
2879 header.command = PLDM_GET_STATUS;
2880 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2881 if (rc) {
2882 return rc;
2883 }
2884
2885 return PLDM_SUCCESS;
2886}
2887
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302888LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302889int decode_get_status_resp(const struct pldm_msg *msg, size_t payload_length,
2890 uint8_t *completion_code, uint8_t *current_state,
2891 uint8_t *previous_state, uint8_t *aux_state,
2892 uint8_t *aux_state_status, uint8_t *progress_percent,
2893 uint8_t *reason_code,
2894 bitfield32_t *update_option_flags_enabled)
2895{
2896 if (msg == NULL || completion_code == NULL || current_state == NULL ||
2897 previous_state == NULL || aux_state == NULL ||
2898 aux_state_status == NULL || progress_percent == NULL ||
2899 reason_code == NULL || update_option_flags_enabled == NULL ||
2900 !payload_length) {
2901 return PLDM_ERROR_INVALID_DATA;
2902 }
2903
2904 *completion_code = msg->payload[0];
2905 if (*completion_code != PLDM_SUCCESS) {
2906 return PLDM_SUCCESS;
2907 }
2908
2909 if (payload_length != sizeof(struct pldm_get_status_resp)) {
2910 return PLDM_ERROR_INVALID_LENGTH;
2911 }
2912 struct pldm_get_status_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302913 (struct pldm_get_status_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302914
2915 if (!is_state_valid(response->current_state)) {
2916 return PLDM_ERROR_INVALID_DATA;
2917 }
2918 if (!is_state_valid(response->previous_state)) {
2919 return PLDM_ERROR_INVALID_DATA;
2920 }
2921 if (!is_aux_state_valid(response->aux_state)) {
2922 return PLDM_ERROR_INVALID_DATA;
2923 }
2924 if (!is_aux_state_status_valid(response->aux_state_status)) {
2925 return PLDM_ERROR_INVALID_DATA;
2926 }
2927 if (response->progress_percent > PLDM_FWUP_MAX_PROGRESS_PERCENT) {
2928 return PLDM_ERROR_INVALID_DATA;
2929 }
2930 if (!is_reason_code_valid(response->reason_code)) {
2931 return PLDM_ERROR_INVALID_DATA;
2932 }
2933
2934 if ((response->current_state == PLDM_FD_STATE_IDLE) ||
2935 (response->current_state == PLDM_FD_STATE_LEARN_COMPONENTS) ||
2936 (response->current_state == PLDM_FD_STATE_READY_XFER)) {
2937 if (response->aux_state !=
2938 PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER) {
2939 return PLDM_ERROR_INVALID_DATA;
2940 }
2941 }
2942
2943 *current_state = response->current_state;
2944 *previous_state = response->previous_state;
2945 *aux_state = response->aux_state;
2946 *aux_state_status = response->aux_state_status;
2947 *progress_percent = response->progress_percent;
2948 *reason_code = response->reason_code;
2949 update_option_flags_enabled->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302950 le32toh(response->update_option_flags_enabled.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302951
2952 return PLDM_SUCCESS;
2953}
2954
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002955LIBPLDM_ABI_TESTING
2956int encode_get_status_resp(uint8_t instance_id,
2957 const struct pldm_get_status_resp *status,
2958 struct pldm_msg *msg, size_t *payload_length)
2959{
Andrew Jefferya1896962025-03-03 21:41:25 +10302960 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002961 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002962
2963 if (status == NULL || msg == NULL || payload_length == NULL) {
2964 return -EINVAL;
2965 }
2966
2967 if (status->completion_code != PLDM_SUCCESS) {
2968 return -EINVAL;
2969 }
2970
2971 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2972 PLDM_GET_STATUS, 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, status->current_state);
2984 pldm_msgbuf_insert(buf, status->previous_state);
2985 pldm_msgbuf_insert(buf, status->aux_state);
2986 pldm_msgbuf_insert(buf, status->aux_state_status);
2987 pldm_msgbuf_insert(buf, status->progress_percent);
2988 pldm_msgbuf_insert(buf, status->reason_code);
2989 pldm_msgbuf_insert(buf, status->update_option_flags_enabled.value);
2990
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302991 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002992}
2993
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302994LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302995int encode_cancel_update_component_req(uint8_t instance_id,
2996 struct pldm_msg *msg,
2997 size_t payload_length)
2998{
2999 if (msg == NULL) {
3000 return PLDM_ERROR_INVALID_DATA;
3001 }
3002
3003 if (payload_length != PLDM_CANCEL_UPDATE_COMPONENT_REQ_BYTES) {
3004 return PLDM_ERROR_INVALID_LENGTH;
3005 }
3006
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303007 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09303008 header.instance = instance_id;
3009 header.msg_type = PLDM_REQUEST;
3010 header.pldm_type = PLDM_FWUP;
3011 header.command = PLDM_CANCEL_UPDATE_COMPONENT;
3012 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
3013 if (rc) {
3014 return rc;
3015 }
3016
3017 return PLDM_SUCCESS;
3018}
3019
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09303020LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09303021int decode_cancel_update_component_resp(const struct pldm_msg *msg,
3022 size_t payload_length,
3023 uint8_t *completion_code)
3024{
3025 if (msg == NULL || completion_code == NULL) {
3026 return PLDM_ERROR_INVALID_DATA;
3027 }
3028
3029 if (payload_length != sizeof(*completion_code)) {
3030 return PLDM_ERROR_INVALID_LENGTH;
3031 }
3032
3033 *completion_code = msg->payload[0];
3034 return PLDM_SUCCESS;
3035}
3036
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09303037LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09303038int encode_cancel_update_req(uint8_t instance_id, struct pldm_msg *msg,
3039 size_t payload_length)
3040{
3041 if (msg == NULL) {
3042 return PLDM_ERROR_INVALID_DATA;
3043 }
3044
3045 if (payload_length != PLDM_CANCEL_UPDATE_REQ_BYTES) {
3046 return PLDM_ERROR_INVALID_LENGTH;
3047 }
3048
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303049 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09303050 header.instance = instance_id;
3051 header.msg_type = PLDM_REQUEST;
3052 header.pldm_type = PLDM_FWUP;
3053 header.command = PLDM_CANCEL_UPDATE;
3054 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
3055 if (rc) {
3056 return rc;
3057 }
3058
3059 return PLDM_SUCCESS;
3060}
3061
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09303062LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09303063int decode_cancel_update_resp(const struct pldm_msg *msg, size_t payload_length,
3064 uint8_t *completion_code,
3065 bool8_t *non_functioning_component_indication,
3066 bitfield64_t *non_functioning_component_bitmap)
3067{
3068 if (msg == NULL || completion_code == NULL ||
3069 non_functioning_component_indication == NULL ||
3070 non_functioning_component_bitmap == NULL || !payload_length) {
3071 return PLDM_ERROR_INVALID_DATA;
3072 }
3073
3074 *completion_code = msg->payload[0];
3075 if (*completion_code != PLDM_SUCCESS) {
3076 return PLDM_SUCCESS;
3077 }
3078
3079 if (payload_length != sizeof(struct pldm_cancel_update_resp)) {
3080 return PLDM_ERROR_INVALID_LENGTH;
3081 }
3082 struct pldm_cancel_update_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303083 (struct pldm_cancel_update_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09303084
3085 if (!is_non_functioning_component_indication_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303086 response->non_functioning_component_indication)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09303087 return PLDM_ERROR_INVALID_DATA;
3088 }
3089
3090 *non_functioning_component_indication =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303091 response->non_functioning_component_indication;
Andrew Jeffery9c766792022-08-10 23:12:49 +09303092
3093 if (*non_functioning_component_indication) {
3094 non_functioning_component_bitmap->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303095 le64toh(response->non_functioning_component_bitmap);
Andrew Jeffery9c766792022-08-10 23:12:49 +09303096 }
3097
3098 return PLDM_SUCCESS;
3099}
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003100
3101LIBPLDM_ABI_TESTING
3102int encode_cancel_update_resp(uint8_t instance_id,
3103 const struct pldm_cancel_update_resp *resp_data,
3104 struct pldm_msg *msg, size_t *payload_length)
3105{
Andrew Jefferya1896962025-03-03 21:41:25 +10303106 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003107 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003108
3109 if (msg == NULL || payload_length == NULL) {
3110 return -EINVAL;
3111 }
3112
3113 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
3114 PLDM_CANCEL_UPDATE, msg);
3115 if (rc) {
3116 return -EINVAL;
3117 }
3118
3119 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
3120 if (rc) {
3121 return rc;
3122 }
3123
3124 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
3125 pldm_msgbuf_insert(buf,
3126 resp_data->non_functioning_component_indication);
3127 pldm_msgbuf_insert(buf, resp_data->non_functioning_component_bitmap);
3128
Andrew Jeffery70d21c92025-03-05 12:59:42 +10303129 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003130}