blob: d6e4e98dba2c1a0a2097ab43c0c21f98353fed23 [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 Jefferyb0c1d202023-11-07 22:08:44 +10305#include <libpldm/firmware_update.h>
6#include <libpldm/utils.h>
7
Andrew Jeffery9c766792022-08-10 23:12:49 +09308#include <endian.h>
Manojkiran Eda9a8e4972022-11-28 16:38:21 +05309#include <stdbool.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +093010#include <string.h>
11
Matt Johnstoncf9a2df2024-11-07 15:29:29 +080012static_assert(PLDM_FIRMWARE_MAX_STRING <= UINT8_MAX, "too large");
13
Andrew Jeffery9c766792022-08-10 23:12:49 +093014/** @brief Check whether string type value is valid
15 *
16 * @return true if string type value is valid, false if not
17 */
18static bool is_string_type_valid(uint8_t string_type)
19{
20 switch (string_type) {
21 case PLDM_STR_TYPE_UNKNOWN:
22 return false;
23 case PLDM_STR_TYPE_ASCII:
24 case PLDM_STR_TYPE_UTF_8:
25 case PLDM_STR_TYPE_UTF_16:
26 case PLDM_STR_TYPE_UTF_16LE:
27 case PLDM_STR_TYPE_UTF_16BE:
28 return true;
29 default:
30 return false;
31 }
32}
33
34/** @brief Return the length of the descriptor type described in firmware update
35 * specification
36 *
37 * @return length of the descriptor type if descriptor type is valid else
38 * return 0
39 */
40static uint16_t get_descriptor_type_length(uint16_t descriptor_type)
41{
42 switch (descriptor_type) {
Andrew Jeffery9c766792022-08-10 23:12:49 +093043 case PLDM_FWUP_PCI_VENDOR_ID:
44 return PLDM_FWUP_PCI_VENDOR_ID_LENGTH;
45 case PLDM_FWUP_IANA_ENTERPRISE_ID:
46 return PLDM_FWUP_IANA_ENTERPRISE_ID_LENGTH;
47 case PLDM_FWUP_UUID:
48 return PLDM_FWUP_UUID_LENGTH;
49 case PLDM_FWUP_PNP_VENDOR_ID:
50 return PLDM_FWUP_PNP_VENDOR_ID_LENGTH;
51 case PLDM_FWUP_ACPI_VENDOR_ID:
52 return PLDM_FWUP_ACPI_VENDOR_ID_LENGTH;
53 case PLDM_FWUP_IEEE_ASSIGNED_COMPANY_ID:
54 return PLDM_FWUP_IEEE_ASSIGNED_COMPANY_ID_LENGTH;
55 case PLDM_FWUP_SCSI_VENDOR_ID:
56 return PLDM_FWUP_SCSI_VENDOR_ID_LENGTH;
57 case PLDM_FWUP_PCI_DEVICE_ID:
58 return PLDM_FWUP_PCI_DEVICE_ID_LENGTH;
59 case PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID:
60 return PLDM_FWUP_PCI_SUBSYSTEM_VENDOR_ID_LENGTH;
61 case PLDM_FWUP_PCI_SUBSYSTEM_ID:
62 return PLDM_FWUP_PCI_SUBSYSTEM_ID_LENGTH;
63 case PLDM_FWUP_PCI_REVISION_ID:
64 return PLDM_FWUP_PCI_REVISION_ID_LENGTH;
65 case PLDM_FWUP_PNP_PRODUCT_IDENTIFIER:
66 return PLDM_FWUP_PNP_PRODUCT_IDENTIFIER_LENGTH;
67 case PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER:
68 return PLDM_FWUP_ACPI_PRODUCT_IDENTIFIER_LENGTH;
69 case PLDM_FWUP_ASCII_MODEL_NUMBER_LONG_STRING:
70 return PLDM_FWUP_ASCII_MODEL_NUMBER_LONG_STRING_LENGTH;
71 case PLDM_FWUP_ASCII_MODEL_NUMBER_SHORT_STRING:
72 return PLDM_FWUP_ASCII_MODEL_NUMBER_SHORT_STRING_LENGTH;
73 case PLDM_FWUP_SCSI_PRODUCT_ID:
74 return PLDM_FWUP_SCSI_PRODUCT_ID_LENGTH;
75 case PLDM_FWUP_UBM_CONTROLLER_DEVICE_CODE:
76 return PLDM_FWUP_UBM_CONTROLLER_DEVICE_CODE_LENGTH;
77 default:
78 return 0;
79 }
80}
81
Chris Wang4c1f2c72024-03-21 17:09:44 +080082static bool is_downstream_device_update_support_valid(uint8_t resp)
83{
84 switch (resp) {
85 case PLDM_FWUP_DOWNSTREAM_DEVICE_UPDATE_NOT_SUPPORTED:
86 case PLDM_FWUP_DOWNSTREAM_DEVICE_UPDATE_SUPPORTED:
87 return true;
88 default:
89 return false;
90 }
91}
92
Chris Wang458475a2024-03-26 17:59:19 +080093static bool
94is_transfer_operation_flag_valid(enum transfer_op_flag transfer_op_flag)
95{
96 switch (transfer_op_flag) {
97 case PLDM_GET_NEXTPART:
98 case PLDM_GET_FIRSTPART:
99 return true;
100 default:
101 return false;
102 }
103}
104
Andrew Jeffery9c766792022-08-10 23:12:49 +0930105/** @brief Check whether ComponentResponse is valid
106 *
107 * @return true if ComponentResponse is valid, false if not
108 */
109static bool is_comp_resp_valid(uint8_t comp_resp)
110{
111 switch (comp_resp) {
112 case PLDM_CR_COMP_CAN_BE_UPDATED:
113 case PLDM_CR_COMP_MAY_BE_UPDATEABLE:
114 return true;
115
116 default:
117 return false;
118 }
119}
120
121/** @brief Check whether ComponentResponseCode is valid
122 *
123 * @return true if ComponentResponseCode is valid, false if not
124 */
125static bool is_comp_resp_code_valid(uint8_t comp_resp_code)
126{
127 switch (comp_resp_code) {
128 case PLDM_CRC_COMP_CAN_BE_UPDATED:
129 case PLDM_CRC_COMP_COMPARISON_STAMP_IDENTICAL:
130 case PLDM_CRC_COMP_COMPARISON_STAMP_LOWER:
131 case PLDM_CRC_INVALID_COMP_COMPARISON_STAMP:
132 case PLDM_CRC_COMP_CONFLICT:
133 case PLDM_CRC_COMP_PREREQUISITES_NOT_MET:
134 case PLDM_CRC_COMP_NOT_SUPPORTED:
135 case PLDM_CRC_COMP_SECURITY_RESTRICTIONS:
136 case PLDM_CRC_INCOMPLETE_COMP_IMAGE_SET:
137 case PLDM_CRC_ACTIVE_IMAGE_NOT_UPDATEABLE_SUBSEQUENTLY:
138 case PLDM_CRC_COMP_VER_STR_IDENTICAL:
139 case PLDM_CRC_COMP_VER_STR_LOWER:
140 return true;
141
142 default:
143 if (comp_resp_code >=
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930144 PLDM_CRC_VENDOR_COMP_RESP_CODE_RANGE_MIN &&
Andrew Jeffery9c766792022-08-10 23:12:49 +0930145 comp_resp_code <=
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930146 PLDM_CRC_VENDOR_COMP_RESP_CODE_RANGE_MAX) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930147 return true;
148 }
149 return false;
150 }
151}
152
153/** @brief Check whether ComponentCompatibilityResponse is valid
154 *
155 * @return true if ComponentCompatibilityResponse is valid, false if not
156 */
157static bool is_comp_compatibility_resp_valid(uint8_t comp_compatibility_resp)
158{
159 switch (comp_compatibility_resp) {
160 case PLDM_CCR_COMP_CAN_BE_UPDATED:
161 case PLDM_CCR_COMP_CANNOT_BE_UPDATED:
162 return true;
163
164 default:
165 return false;
166 }
167}
168
169/** @brief Check whether ComponentCompatibilityResponse Code is valid
170 *
171 * @return true if ComponentCompatibilityResponse Code is valid, false if not
172 */
173static bool
174is_comp_compatibility_resp_code_valid(uint8_t comp_compatibility_resp_code)
175{
176 switch (comp_compatibility_resp_code) {
177 case PLDM_CCRC_NO_RESPONSE_CODE:
178 case PLDM_CCRC_COMP_COMPARISON_STAMP_IDENTICAL:
179 case PLDM_CCRC_COMP_COMPARISON_STAMP_LOWER:
180 case PLDM_CCRC_INVALID_COMP_COMPARISON_STAMP:
181 case PLDM_CCRC_COMP_CONFLICT:
182 case PLDM_CCRC_COMP_PREREQUISITES_NOT_MET:
183 case PLDM_CCRC_COMP_NOT_SUPPORTED:
184 case PLDM_CCRC_COMP_SECURITY_RESTRICTIONS:
185 case PLDM_CRC_INCOMPLETE_COMP_IMAGE_SET:
186 case PLDM_CCRC_COMP_INFO_NO_MATCH:
187 case PLDM_CCRC_COMP_VER_STR_IDENTICAL:
188 case PLDM_CCRC_COMP_VER_STR_LOWER:
189 return true;
190
191 default:
192 if (comp_compatibility_resp_code >=
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930193 PLDM_CCRC_VENDOR_COMP_RESP_CODE_RANGE_MIN &&
Andrew Jeffery9c766792022-08-10 23:12:49 +0930194 comp_compatibility_resp_code <=
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930195 PLDM_CCRC_VENDOR_COMP_RESP_CODE_RANGE_MAX) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930196 return true;
197 }
198 return false;
199 }
200}
201
202/** @brief Check whether SelfContainedActivationRequest is valid
203 *
204 * @return true if SelfContainedActivationRequest is valid, false if not
205 */
206static bool
207is_self_contained_activation_req_valid(bool8_t self_contained_activation_req)
208{
209 switch (self_contained_activation_req) {
210 case PLDM_NOT_ACTIVATE_SELF_CONTAINED_COMPONENTS:
211 case PLDM_ACTIVATE_SELF_CONTAINED_COMPONENTS:
212 return true;
213
214 default:
215 return false;
216 }
217}
218
219/** @brief Check if current or previous status in GetStatus command response is
220 * valid
221 *
222 * @param[in] state - current or previous different state machine state of
223 * the FD
224 * @return true if state is valid, false if not
225 */
226static bool is_state_valid(uint8_t state)
227{
228 switch (state) {
229 case PLDM_FD_STATE_IDLE:
230 case PLDM_FD_STATE_LEARN_COMPONENTS:
231 case PLDM_FD_STATE_READY_XFER:
232 case PLDM_FD_STATE_DOWNLOAD:
233 case PLDM_FD_STATE_VERIFY:
234 case PLDM_FD_STATE_APPLY:
235 case PLDM_FD_STATE_ACTIVATE:
236 return true;
237
238 default:
239 return false;
240 }
241}
242
243/** @brief Check if aux state in GetStatus command response is valid
244 *
245 * @param[in] aux_state - provides additional information to the UA to describe
246 * the current operation state of the FD/FDP
247 *
248 * @return true if aux state is valid, false if not
249 */
250static bool is_aux_state_valid(uint8_t aux_state)
251{
252 switch (aux_state) {
253 case PLDM_FD_OPERATION_IN_PROGRESS:
254 case PLDM_FD_OPERATION_SUCCESSFUL:
255 case PLDM_FD_OPERATION_FAILED:
256 case PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER:
257 return true;
258
259 default:
260 return false;
261 }
262}
263
264/** @brief Check if aux state status in GetStatus command response is valid
265 *
266 * @param[in] aux_state_status - aux state status
267 *
268 * @return true if aux state status is valid, false if not
269 */
270static bool is_aux_state_status_valid(uint8_t aux_state_status)
271{
272 if (aux_state_status == PLDM_FD_AUX_STATE_IN_PROGRESS_OR_SUCCESS ||
273 aux_state_status == PLDM_FD_TIMEOUT ||
Andrew Jeffery67f7ed92023-04-05 14:00:00 +0930274 aux_state_status == PLDM_FD_GENERIC_ERROR ||
275 (aux_state_status >= PLDM_FD_VENDOR_DEFINED_STATUS_CODE_START &&
276 aux_state_status <= PLDM_FD_VENDOR_DEFINED_STATUS_CODE_END)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930277 return true;
278 }
279
280 return false;
281}
282
283/** @brief Check if reason code in GetStatus command response is valid
284 *
285 * @param[in] reason_code - provides the reason for why the current state
286 * entered the IDLE state
287 *
288 * @return true if reason code is valid, false if not
289 */
290static bool is_reason_code_valid(uint8_t reason_code)
291{
Andrew Jeffery9c766792022-08-10 23:12:49 +0930292 switch (reason_code) {
293 case PLDM_FD_INITIALIZATION:
294 case PLDM_FD_ACTIVATE_FW:
295 case PLDM_FD_CANCEL_UPDATE:
296 case PLDM_FD_TIMEOUT_LEARN_COMPONENT:
297 case PLDM_FD_TIMEOUT_READY_XFER:
298 case PLDM_FD_TIMEOUT_DOWNLOAD:
299 case PLDM_FD_TIMEOUT_VERIFY:
300 case PLDM_FD_TIMEOUT_APPLY:
301 return true;
302
303 default:
304 if (reason_code >= PLDM_FD_STATUS_VENDOR_DEFINED_MIN) {
305 return true;
306 }
307 return false;
308 }
309}
310
311/** @brief Check if non functioning component indication in CancelUpdate
312 * response is valid
313 *
314 * @return true if non functioning component indication is valid, false if not
315 */
316static bool is_non_functioning_component_indication_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930317 bool8_t non_functioning_component_indication)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930318{
319 switch (non_functioning_component_indication) {
320 case PLDM_FWUP_COMPONENTS_FUNCTIONING:
321 case PLDM_FWUP_COMPONENTS_NOT_FUNCTIONING:
322 return true;
323
324 default:
325 return false;
326 }
327}
328
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030329// Identifier for a valid PLDM Firmware Update Package for Version 1.0.x as per
330// spec
331static const uint8_t PLDM_FWUP_HDR_IDENTIFIER_V1[PLDM_FWUP_UUID_LENGTH] = {
332 0xF0, 0x18, 0x87, 0x8C, 0xCB, 0x7D, 0x49, 0x43,
333 0x98, 0x00, 0xA0, 0x2F, 0x05, 0x9A, 0xCA, 0x02
334};
335
336/* TODO: Remove struct pldm_package_header_information from public header, rename padded struct, drop typedef */
337struct pldm__package_header_information {
338 uint8_t package_header_identifier[PLDM_FWUP_UUID_LENGTH];
339 uint8_t package_header_format_revision;
340 uint8_t package_release_date_time[PLDM_TIMESTAMP104_SIZE];
341 uint16_t component_bitmap_bit_length;
342 uint8_t package_version_string_type;
343 struct variable_field package_version_string;
344 struct variable_field areas;
345 struct variable_field images;
346};
347typedef struct pldm__package_header_information
348 pldm_package_header_information_pad;
349
350#define PLDM_FWUP_PACKAGE_HEADER_FIXED_SIZE 36
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030351static int decode_pldm_package_header_info_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030352 const void *data, size_t length,
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030353 pldm_package_header_information_pad *header)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930354{
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030355 uint32_t package_header_checksum = 0;
356 size_t package_header_variable_size;
357 size_t package_header_payload_size;
358 size_t package_header_areas_size;
359 uint16_t package_header_size;
360 PLDM_MSGBUF_DEFINE_P(buf);
361 int checksums = 1;
362 int rc;
363
364 if (!data || !header) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030365 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930366 }
367
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030368 rc = pldm_msgbuf_init_errno(buf, PLDM_FWUP_PACKAGE_HEADER_FIXED_SIZE,
369 data, length);
370 if (rc) {
371 return rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930372 }
373
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030374 rc = pldm_msgbuf_extract_array(
375 buf, sizeof(header->package_header_identifier),
376 header->package_header_identifier,
377 sizeof(header->package_header_identifier));
378 if (rc) {
379 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930380 }
381
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030382 static_assert(sizeof(PLDM_FWUP_HDR_IDENTIFIER_V1) ==
383 sizeof(header->package_header_identifier),
384 "UUID field size");
385 if (memcmp(PLDM_FWUP_HDR_IDENTIFIER_V1,
386 header->package_header_identifier,
387 sizeof(PLDM_FWUP_HDR_IDENTIFIER_V1)) != 0) {
388 return pldm_msgbuf_discard(buf, -ENOTSUP);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930389 }
390
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030391 rc = pldm_msgbuf_extract(buf, header->package_header_format_revision);
392 if (rc) {
393 return pldm_msgbuf_discard(buf, rc);
394 }
395 if (header->package_header_format_revision != 0x01) {
396 return pldm_msgbuf_discard(buf, -EBADMSG);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930397 }
398
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030399 rc = pldm_msgbuf_extract(buf, package_header_size);
400 if (rc) {
401 return pldm_msgbuf_discard(buf, rc);
402 }
403
404 rc = pldm_msgbuf_extract_array(
405 buf, sizeof(header->package_release_date_time),
406 header->package_release_date_time,
407 sizeof(header->package_release_date_time));
408 if (rc) {
409 return pldm_msgbuf_discard(buf, rc);
410 }
411
412 rc = pldm_msgbuf_extract(buf, header->component_bitmap_bit_length);
413 if (rc) {
414 return pldm_msgbuf_discard(buf, rc);
415 }
416 if (header->component_bitmap_bit_length & 7) {
417 return pldm_msgbuf_discard(buf, -EPROTO);
418 }
419
420 rc = pldm_msgbuf_extract(buf, header->package_version_string_type);
421 if (rc) {
422 return pldm_msgbuf_discard(buf, rc);
423 }
424 if (!is_string_type_valid(header->package_version_string_type)) {
425 return pldm_msgbuf_discard(buf, -EPROTO);
426 }
427
428 rc = pldm_msgbuf_extract_uint8_to_size(
429 buf, header->package_version_string.length);
430 if (rc) {
431 return pldm_msgbuf_discard(buf, rc);
432 }
433 if (header->package_version_string.length == 0) {
434 return pldm_msgbuf_discard(buf, -EBADMSG);
435 }
436
437 pldm_msgbuf_span_required(buf, header->package_version_string.length,
438 (void **)&header->package_version_string.ptr);
439
440 if (package_header_size < (PLDM_FWUP_PACKAGE_HEADER_FIXED_SIZE + 3 +
441 checksums * sizeof(uint32_t))) {
442 return pldm_msgbuf_discard(buf, -EBADMSG);
443 }
444 package_header_payload_size =
445 package_header_size - (checksums * sizeof(uint32_t));
446 package_header_variable_size = package_header_payload_size -
447 PLDM_FWUP_PACKAGE_HEADER_FIXED_SIZE;
448
449 if (package_header_variable_size <
450 header->package_version_string.length) {
451 return pldm_msgbuf_discard(buf, -EOVERFLOW);
452 }
453
454 package_header_areas_size = package_header_variable_size -
455 header->package_version_string.length;
456 rc = pldm_msgbuf_span_required(buf, package_header_areas_size,
457 (void **)&header->areas.ptr);
458 if (rc) {
459 return pldm_msgbuf_discard(buf, rc);
460 }
461 header->areas.length = package_header_areas_size;
462
463 pldm_msgbuf_extract(buf, package_header_checksum);
464
465 rc = pldm_msgbuf_complete(buf);
466 if (rc) {
467 return rc;
468 }
469
470 if (package_header_checksum !=
471 crc32(data, package_header_payload_size)) {
472 return -EUCLEAN;
473 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930474
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030475 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930476}
477
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930478LIBPLDM_ABI_STABLE
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030479int decode_pldm_package_header_info(
480 const uint8_t *data, size_t length,
481 struct pldm_package_header_information *package_header_info,
482 struct variable_field *package_version_str)
483{
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030484 pldm_package_header_information_pad header;
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030485 int rc;
486
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030487 if (!data || !package_header_info || !package_version_str) {
488 return PLDM_ERROR_INVALID_DATA;
489 }
490
491 rc = decode_pldm_package_header_info_errno(data, length, &header);
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030492 if (rc < 0) {
493 return pldm_xlate_errno(rc);
494 }
495
Andrew Jeffery150b06c2025-03-12 14:17:42 +1030496 static_assert(sizeof(package_header_info->uuid) ==
497 sizeof(header.package_header_identifier),
498 "UUID field size");
499 memcpy(package_header_info->uuid, header.package_header_identifier,
500 sizeof(header.package_header_identifier));
501 package_header_info->package_header_format_version =
502 header.package_header_format_revision;
503 memcpy(&package_header_info->package_header_size, data + 17,
504 sizeof(package_header_info->package_header_size));
505 LE16TOH(package_header_info->package_header_size);
506 static_assert(sizeof(package_header_info->package_release_date_time) ==
507 sizeof(header.package_release_date_time),
508 "TIMESTAMP104 field size");
509 memcpy(package_header_info->package_release_date_time,
510 header.package_release_date_time,
511 sizeof(header.package_release_date_time));
512 package_header_info->component_bitmap_bit_length =
513 header.component_bitmap_bit_length;
514 package_header_info->package_version_string_type =
515 header.package_version_string_type;
516 package_header_info->package_version_string_length =
517 header.package_version_string.length;
518 *package_version_str = header.package_version_string;
519
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030520 return PLDM_SUCCESS;
521}
522
523static int decode_firmware_device_id_record_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030524 const void *data, size_t length, uint16_t component_bitmap_bit_length,
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930525 struct pldm_firmware_device_id_record *fw_device_id_record,
526 struct variable_field *applicable_components,
527 struct variable_field *comp_image_set_version_str,
528 struct variable_field *record_descriptors,
529 struct variable_field *fw_device_pkg_data)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930530{
531 if (data == NULL || fw_device_id_record == NULL ||
532 applicable_components == NULL ||
533 comp_image_set_version_str == NULL || record_descriptors == NULL ||
534 fw_device_pkg_data == NULL) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030535 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930536 }
537
538 if (length < sizeof(struct pldm_firmware_device_id_record)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030539 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930540 }
541
542 if ((component_bitmap_bit_length %
543 PLDM_FWUP_COMPONENT_BITMAP_MULTIPLE) != 0) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030544 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930545 }
546
547 struct pldm_firmware_device_id_record *data_record =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930548 (struct pldm_firmware_device_id_record *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930549
550 if (!is_string_type_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930551 data_record->comp_image_set_version_string_type) ||
Andrew Jeffery9c766792022-08-10 23:12:49 +0930552 (data_record->comp_image_set_version_string_length == 0)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030553 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930554 }
555
556 fw_device_id_record->record_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930557 le16toh(data_record->record_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930558 fw_device_id_record->descriptor_count = data_record->descriptor_count;
559 fw_device_id_record->device_update_option_flags.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930560 le32toh(data_record->device_update_option_flags.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930561 fw_device_id_record->comp_image_set_version_string_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930562 data_record->comp_image_set_version_string_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930563 fw_device_id_record->comp_image_set_version_string_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930564 data_record->comp_image_set_version_string_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930565 fw_device_id_record->fw_device_pkg_data_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930566 le16toh(data_record->fw_device_pkg_data_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930567
568 if (length < fw_device_id_record->record_length) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030569 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930570 }
571
572 uint16_t applicable_components_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930573 component_bitmap_bit_length /
574 PLDM_FWUP_COMPONENT_BITMAP_MULTIPLE;
Matt Johnstonc4d1c8b2024-12-18 11:16:55 +0800575 size_t calc_min_record_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930576 sizeof(struct pldm_firmware_device_id_record) +
577 applicable_components_length +
578 data_record->comp_image_set_version_string_length +
579 PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN +
580 fw_device_id_record->fw_device_pkg_data_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930581
582 if (fw_device_id_record->record_length < calc_min_record_length) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030583 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930584 }
585
586 applicable_components->ptr =
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030587 (const uint8_t *)data +
588 sizeof(struct pldm_firmware_device_id_record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930589 applicable_components->length = applicable_components_length;
590
591 comp_image_set_version_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930592 applicable_components->ptr + applicable_components->length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930593 comp_image_set_version_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930594 fw_device_id_record->comp_image_set_version_string_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930595
596 record_descriptors->ptr = comp_image_set_version_str->ptr +
597 comp_image_set_version_str->length;
598 record_descriptors->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930599 fw_device_id_record->record_length -
600 sizeof(struct pldm_firmware_device_id_record) -
601 applicable_components_length -
602 fw_device_id_record->comp_image_set_version_string_length -
603 fw_device_id_record->fw_device_pkg_data_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930604
605 if (fw_device_id_record->fw_device_pkg_data_length) {
606 fw_device_pkg_data->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930607 record_descriptors->ptr + record_descriptors->length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930608 fw_device_pkg_data->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930609 fw_device_id_record->fw_device_pkg_data_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930610 }
611
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030612 return 0;
613}
614
615LIBPLDM_ABI_STABLE
616int decode_firmware_device_id_record(
617 const uint8_t *data, size_t length,
618 uint16_t component_bitmap_bit_length,
619 struct pldm_firmware_device_id_record *fw_device_id_record,
620 struct variable_field *applicable_components,
621 struct variable_field *comp_image_set_version_str,
622 struct variable_field *record_descriptors,
623 struct variable_field *fw_device_pkg_data)
624{
625 int rc;
626
627 rc = decode_firmware_device_id_record_errno(
628 data, length, component_bitmap_bit_length, fw_device_id_record,
629 applicable_components, comp_image_set_version_str,
630 record_descriptors, fw_device_pkg_data);
631 if (rc < 0) {
632 return pldm_xlate_errno(rc);
633 }
634
Andrew Jeffery9c766792022-08-10 23:12:49 +0930635 return PLDM_SUCCESS;
636}
637
Unive Tiene5c3f142024-12-13 14:14:19 +0800638LIBPLDM_ABI_STABLE
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030639int decode_pldm_descriptor_from_iter(struct pldm_descriptor_iter *iter,
640 struct pldm_descriptor *desc)
641{
Andrew Jefferya1896962025-03-03 21:41:25 +1030642 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030643 int rc;
644
645 if (!iter || !iter->field || !desc) {
646 return -EINVAL;
647 }
648
649 rc = pldm_msgbuf_init_errno(buf, PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN,
650 iter->field->ptr, iter->field->length);
651 if (rc) {
652 return rc;
653 }
654
655 pldm_msgbuf_extract(buf, desc->descriptor_type);
656 rc = pldm_msgbuf_extract(buf, desc->descriptor_length);
657 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +1030658 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030659 }
660
661 desc->descriptor_data = NULL;
662 pldm_msgbuf_span_required(buf, desc->descriptor_length,
663 (void **)&desc->descriptor_data);
664 iter->field->ptr = NULL;
665 pldm_msgbuf_span_remaining(buf, (void **)&iter->field->ptr,
666 &iter->field->length);
667
Andrew Jeffery70d21c92025-03-05 12:59:42 +1030668 return pldm_msgbuf_complete(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030669}
670
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030671static int decode_descriptor_type_length_value_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030672 const void *data, size_t length, uint16_t *descriptor_type,
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030673 struct variable_field *descriptor_data)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930674{
675 uint16_t descriptor_length = 0;
676
677 if (data == NULL || descriptor_type == NULL ||
678 descriptor_data == NULL) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030679 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930680 }
681
682 if (length < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030683 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930684 }
685
686 struct pldm_descriptor_tlv *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930687 (struct pldm_descriptor_tlv *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930688
689 *descriptor_type = le16toh(entry->descriptor_type);
690 descriptor_length = le16toh(entry->descriptor_length);
691 if (*descriptor_type != PLDM_FWUP_VENDOR_DEFINED) {
692 if (descriptor_length !=
693 get_descriptor_type_length(*descriptor_type)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030694 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930695 }
696 }
697
698 if (length < (sizeof(*descriptor_type) + sizeof(descriptor_length) +
699 descriptor_length)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030700 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930701 }
702
703 descriptor_data->ptr = entry->descriptor_data;
704 descriptor_data->length = descriptor_length;
705
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030706 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930707}
708
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930709LIBPLDM_ABI_STABLE
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030710int decode_descriptor_type_length_value(const uint8_t *data, size_t length,
711 uint16_t *descriptor_type,
712 struct variable_field *descriptor_data)
713{
714 int rc;
715
716 rc = decode_descriptor_type_length_value_errno(
717 data, length, descriptor_type, descriptor_data);
718 if (rc < 0) {
719 return pldm_xlate_errno(rc);
720 }
721
722 return PLDM_SUCCESS;
723}
724
725static int decode_vendor_defined_descriptor_value_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030726 const void *data, size_t length, uint8_t *descriptor_title_str_type,
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930727 struct variable_field *descriptor_title_str,
728 struct variable_field *descriptor_data)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930729{
730 if (data == NULL || descriptor_title_str_type == NULL ||
731 descriptor_title_str == NULL || descriptor_data == NULL) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030732 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930733 }
734
735 if (length < sizeof(struct pldm_vendor_defined_descriptor_title_data)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030736 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930737 }
738
739 struct pldm_vendor_defined_descriptor_title_data *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930740 (struct pldm_vendor_defined_descriptor_title_data *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930741 if (!is_string_type_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930742 entry->vendor_defined_descriptor_title_str_type) ||
Andrew Jeffery9c766792022-08-10 23:12:49 +0930743 (entry->vendor_defined_descriptor_title_str_len == 0)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030744 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930745 }
746
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530747 // Assuming at least 1 byte of VendorDefinedDescriptorData
Andrew Jeffery9c766792022-08-10 23:12:49 +0930748 if (length < (sizeof(struct pldm_vendor_defined_descriptor_title_data) +
749 entry->vendor_defined_descriptor_title_str_len)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030750 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930751 }
752
753 *descriptor_title_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930754 entry->vendor_defined_descriptor_title_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930755 descriptor_title_str->ptr = entry->vendor_defined_descriptor_title_str;
756 descriptor_title_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930757 entry->vendor_defined_descriptor_title_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930758
759 descriptor_data->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930760 descriptor_title_str->ptr + descriptor_title_str->length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930761 descriptor_data->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930762 length -
763 sizeof(entry->vendor_defined_descriptor_title_str_type) -
764 sizeof(entry->vendor_defined_descriptor_title_str_len) -
765 descriptor_title_str->length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930766
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030767 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930768}
769
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930770LIBPLDM_ABI_STABLE
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030771int decode_vendor_defined_descriptor_value(
772 const uint8_t *data, size_t length, uint8_t *descriptor_title_str_type,
773 struct variable_field *descriptor_title_str,
774 struct variable_field *descriptor_data)
775{
776 int rc;
777
778 rc = decode_vendor_defined_descriptor_value_errno(
779 data, length, descriptor_title_str_type, descriptor_title_str,
780 descriptor_data);
781 if (rc < 0) {
782 return pldm_xlate_errno(rc);
783 }
784
785 return PLDM_SUCCESS;
786}
787
788static int decode_pldm_comp_image_info_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030789 const void *data, size_t length,
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930790 struct pldm_component_image_information *pldm_comp_image_info,
791 struct variable_field *comp_version_str)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930792{
793 if (data == NULL || pldm_comp_image_info == NULL ||
794 comp_version_str == NULL) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030795 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930796 }
797
798 if (length < sizeof(struct pldm_component_image_information)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030799 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930800 }
801
802 struct pldm_component_image_information *data_header =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930803 (struct pldm_component_image_information *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930804
805 if (!is_string_type_valid(data_header->comp_version_string_type) ||
806 (data_header->comp_version_string_length == 0)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030807 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930808 }
809
810 if (length < sizeof(struct pldm_component_image_information) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930811 data_header->comp_version_string_length) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030812 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930813 }
814
815 pldm_comp_image_info->comp_classification =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930816 le16toh(data_header->comp_classification);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930817 pldm_comp_image_info->comp_identifier =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930818 le16toh(data_header->comp_identifier);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930819 pldm_comp_image_info->comp_comparison_stamp =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930820 le32toh(data_header->comp_comparison_stamp);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930821 pldm_comp_image_info->comp_options.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930822 le16toh(data_header->comp_options.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930823 pldm_comp_image_info->requested_comp_activation_method.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930824 le16toh(data_header->requested_comp_activation_method.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930825 pldm_comp_image_info->comp_location_offset =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930826 le32toh(data_header->comp_location_offset);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930827 pldm_comp_image_info->comp_size = le32toh(data_header->comp_size);
828 pldm_comp_image_info->comp_version_string_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930829 data_header->comp_version_string_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930830 pldm_comp_image_info->comp_version_string_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930831 data_header->comp_version_string_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930832
833 if ((pldm_comp_image_info->comp_options.bits.bit1 == false &&
834 pldm_comp_image_info->comp_comparison_stamp !=
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930835 PLDM_FWUP_INVALID_COMPONENT_COMPARISON_TIMESTAMP)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030836 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930837 }
838
839 if (pldm_comp_image_info->comp_location_offset == 0 ||
840 pldm_comp_image_info->comp_size == 0) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030841 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930842 }
843
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030844 comp_version_str->ptr = (const uint8_t *)data +
845 sizeof(struct pldm_component_image_information);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930846 comp_version_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930847 pldm_comp_image_info->comp_version_string_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930848
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030849 return 0;
850}
851
852LIBPLDM_ABI_STABLE
853int decode_pldm_comp_image_info(
854 const uint8_t *data, size_t length,
855 struct pldm_component_image_information *pldm_comp_image_info,
856 struct variable_field *comp_version_str)
857{
858 int rc;
859
860 rc = decode_pldm_comp_image_info_errno(
861 data, length, pldm_comp_image_info, comp_version_str);
862 if (rc < 0) {
863 return pldm_xlate_errno(rc);
864 }
865
Andrew Jeffery9c766792022-08-10 23:12:49 +0930866 return PLDM_SUCCESS;
867}
868
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930869LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930870int encode_query_device_identifiers_req(uint8_t instance_id,
871 size_t payload_length,
872 struct pldm_msg *msg)
873{
874 if (msg == NULL) {
875 return PLDM_ERROR_INVALID_DATA;
876 }
877
878 if (payload_length != PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES) {
879 return PLDM_ERROR_INVALID_LENGTH;
880 }
881
882 return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
883 PLDM_QUERY_DEVICE_IDENTIFIERS, msg);
884}
885
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930886LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930887int decode_query_device_identifiers_resp(const struct pldm_msg *msg,
888 size_t payload_length,
889 uint8_t *completion_code,
890 uint32_t *device_identifiers_len,
891 uint8_t *descriptor_count,
892 uint8_t **descriptor_data)
893{
894 if (msg == NULL || completion_code == NULL ||
895 device_identifiers_len == NULL || descriptor_count == NULL ||
896 descriptor_data == NULL) {
897 return PLDM_ERROR_INVALID_DATA;
898 }
899
900 *completion_code = msg->payload[0];
901 if (PLDM_SUCCESS != *completion_code) {
902 return PLDM_SUCCESS;
903 }
904
905 if (payload_length <
906 sizeof(struct pldm_query_device_identifiers_resp)) {
907 return PLDM_ERROR_INVALID_LENGTH;
908 }
909
910 struct pldm_query_device_identifiers_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930911 (struct pldm_query_device_identifiers_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930912 *device_identifiers_len = le32toh(response->device_identifiers_len);
913
914 if (*device_identifiers_len < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {
915 return PLDM_ERROR_INVALID_LENGTH;
916 }
917
918 if (payload_length !=
919 sizeof(struct pldm_query_device_identifiers_resp) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930920 *device_identifiers_len) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930921 return PLDM_ERROR_INVALID_LENGTH;
922 }
923 *descriptor_count = response->descriptor_count;
924
925 if (*descriptor_count == 0) {
926 return PLDM_ERROR_INVALID_DATA;
927 }
928 *descriptor_data =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930929 (uint8_t *)(msg->payload +
930 sizeof(struct pldm_query_device_identifiers_resp));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930931 return PLDM_SUCCESS;
932}
933
Matt Johnstoncf9a2df2024-11-07 15:29:29 +0800934LIBPLDM_ABI_TESTING
935int encode_query_device_identifiers_resp(
936 uint8_t instance_id, uint8_t descriptor_count,
937 const struct pldm_descriptor *descriptors, struct pldm_msg *msg,
938 size_t *payload_length)
939{
Andrew Jefferya1896962025-03-03 21:41:25 +1030940 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +0800941 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +0800942
943 if (descriptors == NULL || msg == NULL || payload_length == NULL) {
944 return -EINVAL;
945 }
946
947 if (descriptor_count < 1) {
948 return -EINVAL;
949 }
950
951 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
952 PLDM_QUERY_DEVICE_IDENTIFIERS, msg);
953 if (rc) {
954 return -EINVAL;
955 }
956
957 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
958 if (rc) {
959 return rc;
960 }
961
962 /* Determine total length */
963 uint32_t device_identifiers_len = 0;
964 for (uint8_t i = 0; i < descriptor_count; i++) {
965 const struct pldm_descriptor *d = &descriptors[i];
966 device_identifiers_len +=
967 2 * sizeof(uint16_t) + d->descriptor_length;
968 }
969
970 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
971 pldm_msgbuf_insert(buf, device_identifiers_len);
972 pldm_msgbuf_insert(buf, descriptor_count);
973
974 for (uint8_t i = 0; i < descriptor_count; i++) {
975 const struct pldm_descriptor *d = &descriptors[i];
976 pldm_msgbuf_insert(buf, d->descriptor_type);
977 pldm_msgbuf_insert(buf, d->descriptor_length);
978 if (d->descriptor_data == NULL) {
Andrew Jefferya1896962025-03-03 21:41:25 +1030979 return pldm_msgbuf_discard(buf, -EINVAL);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +0800980 }
981 rc = pldm_msgbuf_insert_array(
982 buf, d->descriptor_length,
983 (const uint8_t *)d->descriptor_data,
984 d->descriptor_length);
985 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +1030986 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +0800987 }
988 }
989
Andrew Jeffery70d21c92025-03-05 12:59:42 +1030990 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +0800991}
992
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930993LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930994int encode_get_firmware_parameters_req(uint8_t instance_id,
995 size_t payload_length,
996 struct pldm_msg *msg)
997{
998 if (msg == NULL) {
999 return PLDM_ERROR_INVALID_DATA;
1000 }
1001
1002 if (payload_length != PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES) {
1003 return PLDM_ERROR_INVALID_LENGTH;
1004 }
1005
1006 return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
1007 PLDM_GET_FIRMWARE_PARAMETERS, msg);
1008}
1009
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301010LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301011int decode_get_firmware_parameters_resp(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301012 const struct pldm_msg *msg, size_t payload_length,
1013 struct pldm_get_firmware_parameters_resp *resp_data,
1014 struct variable_field *active_comp_image_set_ver_str,
1015 struct variable_field *pending_comp_image_set_ver_str,
1016 struct variable_field *comp_parameter_table)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301017{
1018 if (msg == NULL || resp_data == NULL ||
1019 active_comp_image_set_ver_str == NULL ||
1020 pending_comp_image_set_ver_str == NULL ||
1021 comp_parameter_table == NULL || !payload_length) {
1022 return PLDM_ERROR_INVALID_DATA;
1023 }
1024
1025 resp_data->completion_code = msg->payload[0];
1026 if (PLDM_SUCCESS != resp_data->completion_code) {
1027 return PLDM_SUCCESS;
1028 }
1029
1030 if (payload_length < sizeof(struct pldm_get_firmware_parameters_resp)) {
1031 return PLDM_ERROR_INVALID_LENGTH;
1032 }
1033
1034 struct pldm_get_firmware_parameters_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301035 (struct pldm_get_firmware_parameters_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301036
1037 if (!is_string_type_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301038 response->active_comp_image_set_ver_str_type) ||
Andrew Jeffery9c766792022-08-10 23:12:49 +09301039 (response->active_comp_image_set_ver_str_len == 0)) {
1040 return PLDM_ERROR_INVALID_DATA;
1041 }
1042
1043 if (response->pending_comp_image_set_ver_str_len == 0) {
1044 if (response->pending_comp_image_set_ver_str_type !=
1045 PLDM_STR_TYPE_UNKNOWN) {
1046 return PLDM_ERROR_INVALID_DATA;
1047 }
1048 } else {
1049 if (!is_string_type_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301050 response->pending_comp_image_set_ver_str_type)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301051 return PLDM_ERROR_INVALID_DATA;
1052 }
1053 }
1054
1055 size_t partial_response_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301056 sizeof(struct pldm_get_firmware_parameters_resp) +
1057 response->active_comp_image_set_ver_str_len +
1058 response->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301059
1060 if (payload_length < partial_response_length) {
1061 return PLDM_ERROR_INVALID_LENGTH;
1062 }
1063
1064 resp_data->capabilities_during_update.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301065 le32toh(response->capabilities_during_update.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301066 resp_data->comp_count = le16toh(response->comp_count);
1067 resp_data->active_comp_image_set_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301068 response->active_comp_image_set_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301069 resp_data->active_comp_image_set_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301070 response->active_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301071 resp_data->pending_comp_image_set_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301072 response->pending_comp_image_set_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301073 resp_data->pending_comp_image_set_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301074 response->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301075
1076 active_comp_image_set_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301077 msg->payload + sizeof(struct pldm_get_firmware_parameters_resp);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301078 active_comp_image_set_ver_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301079 resp_data->active_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301080
1081 if (resp_data->pending_comp_image_set_ver_str_len != 0) {
1082 pending_comp_image_set_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301083 msg->payload +
1084 sizeof(struct pldm_get_firmware_parameters_resp) +
1085 resp_data->active_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301086 pending_comp_image_set_ver_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301087 resp_data->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301088 } else {
1089 pending_comp_image_set_ver_str->ptr = NULL;
1090 pending_comp_image_set_ver_str->length = 0;
1091 }
1092
1093 if (payload_length > partial_response_length && resp_data->comp_count) {
1094 comp_parameter_table->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301095 msg->payload +
1096 sizeof(struct pldm_get_firmware_parameters_resp) +
1097 resp_data->active_comp_image_set_ver_str_len +
1098 resp_data->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301099 comp_parameter_table->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301100 payload_length - partial_response_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301101 } else {
1102 comp_parameter_table->ptr = NULL;
1103 comp_parameter_table->length = 0;
1104 }
1105
1106 return PLDM_SUCCESS;
1107}
1108
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001109LIBPLDM_ABI_TESTING
1110int encode_get_firmware_parameters_resp(
1111 uint8_t instance_id,
1112 const struct pldm_get_firmware_parameters_resp_full *resp_data,
1113 struct pldm_msg *msg, size_t *payload_length)
1114{
Andrew Jefferya1896962025-03-03 21:41:25 +10301115 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001116 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001117
1118 if (resp_data == NULL || msg == NULL || payload_length == NULL) {
1119 return -EINVAL;
1120 }
1121
1122 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
1123 PLDM_GET_FIRMWARE_PARAMETERS, msg);
1124 if (rc) {
1125 return -EINVAL;
1126 }
1127
1128 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
1129 if (rc) {
1130 return rc;
1131 }
1132
1133 pldm_msgbuf_insert(buf, resp_data->completion_code);
1134 pldm_msgbuf_insert(buf, resp_data->capabilities_during_update.value);
1135 pldm_msgbuf_insert(buf, resp_data->comp_count);
1136 pldm_msgbuf_insert(buf,
1137 resp_data->active_comp_image_set_ver_str.str_type);
1138 pldm_msgbuf_insert(buf,
1139 resp_data->active_comp_image_set_ver_str.str_len);
1140 pldm_msgbuf_insert(buf,
1141 resp_data->pending_comp_image_set_ver_str.str_type);
1142 pldm_msgbuf_insert(buf,
1143 resp_data->pending_comp_image_set_ver_str.str_len);
1144 /* String data appended */
1145 rc = pldm_msgbuf_insert_array(
1146 buf, resp_data->active_comp_image_set_ver_str.str_len,
1147 resp_data->active_comp_image_set_ver_str.str_data,
1148 resp_data->active_comp_image_set_ver_str.str_len);
1149 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301150 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001151 }
1152 rc = pldm_msgbuf_insert_array(
1153 buf, resp_data->pending_comp_image_set_ver_str.str_len,
1154 resp_data->pending_comp_image_set_ver_str.str_data,
1155 resp_data->pending_comp_image_set_ver_str.str_len);
1156 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301157 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001158 }
1159
1160 /* Further calls to encode_get_firmware_parameters_resp_comp_entry
1161 * will populate the remainder */
1162
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301163 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001164}
1165
1166LIBPLDM_ABI_TESTING
1167int encode_get_firmware_parameters_resp_comp_entry(
1168 const struct pldm_component_parameter_entry_full *comp,
1169 uint8_t *payload, size_t *payload_length)
1170{
Andrew Jefferya1896962025-03-03 21:41:25 +10301171 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001172 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001173
1174 if (comp == NULL || payload == NULL || payload_length == NULL) {
1175 return -EINVAL;
1176 }
1177
1178 rc = pldm_msgbuf_init_errno(buf, 0, payload, *payload_length);
1179 if (rc) {
1180 return rc;
1181 }
1182
1183 pldm_msgbuf_insert(buf, comp->comp_classification);
1184 pldm_msgbuf_insert(buf, comp->comp_identifier);
1185 pldm_msgbuf_insert(buf, comp->comp_classification_index);
1186
1187 pldm_msgbuf_insert(buf, comp->active_ver.comparison_stamp);
1188 pldm_msgbuf_insert(buf, (uint8_t)comp->active_ver.str.str_type);
1189 pldm_msgbuf_insert(buf, comp->active_ver.str.str_len);
1190 rc = pldm_msgbuf_insert_array(buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1191 comp->active_ver.date,
1192 PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN);
1193 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301194 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001195 }
1196
1197 pldm_msgbuf_insert(buf, comp->pending_ver.comparison_stamp);
1198 pldm_msgbuf_insert(buf, (uint8_t)comp->pending_ver.str.str_type);
1199 pldm_msgbuf_insert(buf, comp->pending_ver.str.str_len);
1200 rc = pldm_msgbuf_insert_array(buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1201 comp->pending_ver.date,
1202 PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN);
1203 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301204 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001205 }
1206
1207 pldm_msgbuf_insert(buf, comp->comp_activation_methods.value);
1208 pldm_msgbuf_insert(buf, comp->capabilities_during_update.value);
1209
1210 rc = pldm_msgbuf_insert_array(buf, comp->active_ver.str.str_len,
1211 comp->active_ver.str.str_data,
1212 comp->active_ver.str.str_len);
1213 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301214 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001215 }
1216 rc = pldm_msgbuf_insert_array(buf, comp->pending_ver.str.str_len,
1217 comp->pending_ver.str.str_data,
1218 comp->pending_ver.str.str_len);
1219 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301220 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001221 }
1222
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301223 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001224}
1225
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301226LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301227int decode_get_firmware_parameters_resp_comp_entry(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301228 const uint8_t *data, size_t length,
1229 struct pldm_component_parameter_entry *component_data,
1230 struct variable_field *active_comp_ver_str,
1231 struct variable_field *pending_comp_ver_str)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301232{
1233 if (data == NULL || component_data == NULL ||
1234 active_comp_ver_str == NULL || pending_comp_ver_str == NULL) {
1235 return PLDM_ERROR_INVALID_DATA;
1236 }
1237
1238 if (length < sizeof(struct pldm_component_parameter_entry)) {
1239 return PLDM_ERROR_INVALID_LENGTH;
1240 }
1241
1242 struct pldm_component_parameter_entry *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301243 (struct pldm_component_parameter_entry *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301244
1245 size_t entry_length = sizeof(struct pldm_component_parameter_entry) +
1246 entry->active_comp_ver_str_len +
1247 entry->pending_comp_ver_str_len;
1248
1249 if (length < entry_length) {
1250 return PLDM_ERROR_INVALID_LENGTH;
1251 }
1252
1253 component_data->comp_classification =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301254 le16toh(entry->comp_classification);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301255 component_data->comp_identifier = le16toh(entry->comp_identifier);
1256 component_data->comp_classification_index =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301257 entry->comp_classification_index;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301258 component_data->active_comp_comparison_stamp =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301259 le32toh(entry->active_comp_comparison_stamp);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301260 component_data->active_comp_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301261 entry->active_comp_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301262 component_data->active_comp_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301263 entry->active_comp_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301264 memcpy(component_data->active_comp_release_date,
1265 entry->active_comp_release_date,
1266 sizeof(entry->active_comp_release_date));
1267 component_data->pending_comp_comparison_stamp =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301268 le32toh(entry->pending_comp_comparison_stamp);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301269 component_data->pending_comp_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301270 entry->pending_comp_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301271 component_data->pending_comp_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301272 entry->pending_comp_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301273 memcpy(component_data->pending_comp_release_date,
1274 entry->pending_comp_release_date,
1275 sizeof(entry->pending_comp_release_date));
1276 component_data->comp_activation_methods.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301277 le16toh(entry->comp_activation_methods.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301278 component_data->capabilities_during_update.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301279 le32toh(entry->capabilities_during_update.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301280
1281 if (entry->active_comp_ver_str_len != 0) {
1282 active_comp_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301283 data + sizeof(struct pldm_component_parameter_entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301284 active_comp_ver_str->length = entry->active_comp_ver_str_len;
1285 } else {
1286 active_comp_ver_str->ptr = NULL;
1287 active_comp_ver_str->length = 0;
1288 }
1289
1290 if (entry->pending_comp_ver_str_len != 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301291 pending_comp_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301292 data + sizeof(struct pldm_component_parameter_entry) +
1293 entry->active_comp_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301294 pending_comp_ver_str->length = entry->pending_comp_ver_str_len;
1295 } else {
1296 pending_comp_ver_str->ptr = NULL;
1297 pending_comp_ver_str->length = 0;
1298 }
1299 return PLDM_SUCCESS;
1300}
1301
Unive Tiene5c3f142024-12-13 14:14:19 +08001302LIBPLDM_ABI_STABLE
Chris Wang4c1f2c72024-03-21 17:09:44 +08001303int encode_query_downstream_devices_req(uint8_t instance_id,
1304 struct pldm_msg *msg)
1305{
1306 if (msg == NULL) {
Unive Tien71e935c2024-11-25 17:21:43 +08001307 return -EINVAL;
Chris Wang4c1f2c72024-03-21 17:09:44 +08001308 }
1309
Unive Tien71e935c2024-11-25 17:21:43 +08001310 return encode_pldm_header_only_errno(PLDM_REQUEST, instance_id,
1311 PLDM_FWUP,
1312 PLDM_QUERY_DOWNSTREAM_DEVICES,
1313 msg);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001314}
1315
Unive Tiene5c3f142024-12-13 14:14:19 +08001316LIBPLDM_ABI_STABLE
Chris Wang4c1f2c72024-03-21 17:09:44 +08001317int decode_query_downstream_devices_resp(
1318 const struct pldm_msg *msg, size_t payload_length,
1319 struct pldm_query_downstream_devices_resp *resp_data)
1320{
Andrew Jefferya1896962025-03-03 21:41:25 +10301321 PLDM_MSGBUF_DEFINE_P(buf);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001322 int rc;
1323
1324 if (msg == NULL || resp_data == NULL || !payload_length) {
Unive Tien71e935c2024-11-25 17:21:43 +08001325 return -EINVAL;
Chris Wang4c1f2c72024-03-21 17:09:44 +08001326 }
1327
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301328 rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1329 msg->payload, payload_length);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001330 if (rc) {
1331 return rc;
1332 }
1333
1334 rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1335 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301336 return pldm_msgbuf_discard(buf, rc);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001337 }
1338 if (PLDM_SUCCESS != resp_data->completion_code) {
1339 // Return the CC directly without decoding the rest of the payload
Andrew Jefferya1896962025-03-03 21:41:25 +10301340 return pldm_msgbuf_complete(buf);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001341 }
1342
1343 if (payload_length < PLDM_QUERY_DOWNSTREAM_DEVICES_RESP_BYTES) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301344 return pldm_msgbuf_discard(buf, -EBADMSG);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001345 }
1346
1347 rc = pldm_msgbuf_extract(buf,
1348 resp_data->downstream_device_update_supported);
1349 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301350 return pldm_msgbuf_discard(buf, rc);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001351 }
1352
1353 if (!is_downstream_device_update_support_valid(
1354 resp_data->downstream_device_update_supported)) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301355 return pldm_msgbuf_discard(buf, -EINVAL);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001356 }
1357
1358 pldm_msgbuf_extract(buf, resp_data->number_of_downstream_devices);
1359 pldm_msgbuf_extract(buf, resp_data->max_number_of_downstream_devices);
1360 pldm_msgbuf_extract(buf, resp_data->capabilities.value);
1361
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301362 return pldm_msgbuf_complete_consumed(buf);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001363}
1364
Unive Tiene5c3f142024-12-13 14:14:19 +08001365LIBPLDM_ABI_STABLE
Chris Wang458475a2024-03-26 17:59:19 +08001366int encode_query_downstream_identifiers_req(
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001367 uint8_t instance_id,
1368 const struct pldm_query_downstream_identifiers_req *params_req,
1369 struct pldm_msg *msg, size_t payload_length)
Chris Wang458475a2024-03-26 17:59:19 +08001370{
Andrew Jefferya1896962025-03-03 21:41:25 +10301371 PLDM_MSGBUF_DEFINE_P(buf);
Chris Wang458475a2024-03-26 17:59:19 +08001372 int rc;
1373
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001374 if (!msg || !params_req) {
Unive Tien71e935c2024-11-25 17:21:43 +08001375 return -EINVAL;
Chris Wang458475a2024-03-26 17:59:19 +08001376 }
1377
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001378 if (!is_transfer_operation_flag_valid(
1379 (enum transfer_op_flag)
1380 params_req->transfer_operation_flag)) {
Unive Tien71e935c2024-11-25 17:21:43 +08001381 return -EINVAL;
Chris Wang458475a2024-03-26 17:59:19 +08001382 }
1383
1384 struct pldm_header_info header = { 0 };
1385 header.instance = instance_id;
1386 header.msg_type = PLDM_REQUEST;
1387 header.pldm_type = PLDM_FWUP;
1388 header.command = PLDM_QUERY_DOWNSTREAM_IDENTIFIERS;
Unive Tien71e935c2024-11-25 17:21:43 +08001389 rc = pack_pldm_header_errno(&header, &(msg->hdr));
Chris Wang458475a2024-03-26 17:59:19 +08001390 if (rc) {
1391 return rc;
1392 }
1393
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301394 rc = pldm_msgbuf_init_errno(buf,
1395 PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_REQ_BYTES,
1396 msg->payload, payload_length);
Chris Wang458475a2024-03-26 17:59:19 +08001397 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001398 return rc;
Chris Wang458475a2024-03-26 17:59:19 +08001399 }
1400
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001401 pldm_msgbuf_insert(buf, params_req->data_transfer_handle);
Chris Wang458475a2024-03-26 17:59:19 +08001402 // Data correctness has been verified, cast it to 1-byte data directly.
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001403 pldm_msgbuf_insert(buf, params_req->transfer_operation_flag);
Chris Wang458475a2024-03-26 17:59:19 +08001404
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301405 return pldm_msgbuf_complete(buf);
Chris Wang458475a2024-03-26 17:59:19 +08001406}
1407
Unive Tiene5c3f142024-12-13 14:14:19 +08001408LIBPLDM_ABI_STABLE
Chris Wang458475a2024-03-26 17:59:19 +08001409int decode_query_downstream_identifiers_resp(
1410 const struct pldm_msg *msg, size_t payload_length,
1411 struct pldm_query_downstream_identifiers_resp *resp_data,
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301412 struct pldm_downstream_device_iter *iter)
Chris Wang458475a2024-03-26 17:59:19 +08001413{
Andrew Jefferya1896962025-03-03 21:41:25 +10301414 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301415 void *remaining = NULL;
Unive Tien71e935c2024-11-25 17:21:43 +08001416 int rc = 0;
Chris Wang458475a2024-03-26 17:59:19 +08001417
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301418 if (msg == NULL || resp_data == NULL || iter == NULL ||
Chris Wang458475a2024-03-26 17:59:19 +08001419 !payload_length) {
Unive Tien71e935c2024-11-25 17:21:43 +08001420 return -EINVAL;
Chris Wang458475a2024-03-26 17:59:19 +08001421 }
1422
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301423 rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1424 msg->payload, payload_length);
Chris Wang458475a2024-03-26 17:59:19 +08001425 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001426 return rc;
Chris Wang458475a2024-03-26 17:59:19 +08001427 }
1428
1429 rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1430 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301431 return pldm_msgbuf_discard(buf, rc);
Chris Wang458475a2024-03-26 17:59:19 +08001432 }
1433 if (PLDM_SUCCESS != resp_data->completion_code) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301434 return pldm_msgbuf_complete(buf);
Chris Wang458475a2024-03-26 17:59:19 +08001435 }
1436
1437 if (payload_length < PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_RESP_MIN_LEN) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301438 return pldm_msgbuf_discard(buf, -EBADMSG);
Chris Wang458475a2024-03-26 17:59:19 +08001439 }
1440
1441 pldm_msgbuf_extract(buf, resp_data->next_data_transfer_handle);
1442 pldm_msgbuf_extract(buf, resp_data->transfer_flag);
1443
1444 rc = pldm_msgbuf_extract(buf, resp_data->downstream_devices_length);
1445 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301446 return pldm_msgbuf_discard(buf, rc);
Chris Wang458475a2024-03-26 17:59:19 +08001447 }
1448
1449 pldm_msgbuf_extract(buf, resp_data->number_of_downstream_devices);
Andrew Jefferya1896962025-03-03 21:41:25 +10301450 pldm_msgbuf_span_required(buf, resp_data->downstream_devices_length,
1451 &remaining);
Chris Wang458475a2024-03-26 17:59:19 +08001452
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301453 rc = pldm_msgbuf_complete(buf);
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301454 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001455 return rc;
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301456 }
1457
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301458 iter->field.ptr = remaining;
1459 iter->field.length = resp_data->downstream_devices_length;
1460 iter->devs = resp_data->number_of_downstream_devices;
1461
Unive Tien71e935c2024-11-25 17:21:43 +08001462 return 0;
Chris Wang458475a2024-03-26 17:59:19 +08001463}
1464
Unive Tiene5c3f142024-12-13 14:14:19 +08001465LIBPLDM_ABI_STABLE
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301466int decode_pldm_downstream_device_from_iter(
1467 struct pldm_downstream_device_iter *iter,
1468 struct pldm_downstream_device *dev)
1469{
Andrew Jefferya1896962025-03-03 21:41:25 +10301470 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301471 int rc;
1472
Andrew Jefferya1896962025-03-03 21:41:25 +10301473 if (!iter || !iter->field.ptr || !dev) {
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301474 return -EINVAL;
1475 }
1476
1477 rc = pldm_msgbuf_init_errno(buf, 3, iter->field.ptr,
1478 iter->field.length);
1479 if (rc) {
1480 return rc;
1481 }
1482
1483 pldm_msgbuf_extract(buf, dev->downstream_device_index);
1484 pldm_msgbuf_extract(buf, dev->downstream_descriptor_count);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301485 pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
1486 &iter->field.length);
1487
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301488 return pldm_msgbuf_complete(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301489}
1490
Unive Tiene5c3f142024-12-13 14:14:19 +08001491LIBPLDM_ABI_STABLE
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301492int encode_get_downstream_firmware_parameters_req(
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001493 uint8_t instance_id,
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301494 const struct pldm_get_downstream_firmware_parameters_req *params_req,
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001495 struct pldm_msg *msg, size_t payload_length)
Chris Wangb6ef35b2024-07-03 09:35:42 +08001496{
Andrew Jefferya1896962025-03-03 21:41:25 +10301497 PLDM_MSGBUF_DEFINE_P(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001498 int rc;
1499
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001500 if (!msg || !params_req) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001501 return -EINVAL;
1502 }
1503
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001504 if (!is_transfer_operation_flag_valid(
1505 (enum transfer_op_flag)
1506 params_req->transfer_operation_flag)) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001507 return -EBADMSG;
1508 }
1509
1510 struct pldm_header_info header = { 0 };
1511 header.instance = instance_id;
1512 header.msg_type = PLDM_REQUEST;
1513 header.pldm_type = PLDM_FWUP;
1514 header.command = PLDM_QUERY_DOWNSTREAM_FIRMWARE_PARAMETERS;
1515 rc = pack_pldm_header_errno(&header, &msg->hdr);
1516 if (rc < 0) {
1517 return rc;
1518 }
1519
Andrew Jeffery53b08672025-03-04 12:26:18 +10301520 rc = pldm_msgbuf_init_errno(
1521 buf, PLDM_GET_DOWNSTREAM_FIRMWARE_PARAMETERS_REQ_BYTES,
1522 msg->payload, payload_length);
1523 if (rc < 0) {
1524 return rc;
1525 }
1526
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001527 pldm_msgbuf_insert(buf, params_req->data_transfer_handle);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001528 // Data correctness has been verified, cast it to 1-byte data directly.
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001529 pldm_msgbuf_insert(buf, params_req->transfer_operation_flag);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001530
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301531 return pldm_msgbuf_complete(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001532}
1533
Unive Tiene5c3f142024-12-13 14:14:19 +08001534LIBPLDM_ABI_STABLE
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301535int decode_get_downstream_firmware_parameters_resp(
Chris Wangb6ef35b2024-07-03 09:35:42 +08001536 const struct pldm_msg *msg, size_t payload_length,
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301537 struct pldm_get_downstream_firmware_parameters_resp *resp_data,
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301538 struct pldm_downstream_device_parameters_iter *iter)
Chris Wangb6ef35b2024-07-03 09:35:42 +08001539{
Andrew Jefferya1896962025-03-03 21:41:25 +10301540 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301541 void *remaining = NULL;
1542 size_t length;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001543 int rc;
1544
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301545 if (msg == NULL || resp_data == NULL || iter == NULL) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001546 return -EINVAL;
1547 }
1548
1549 rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1550 msg->payload, payload_length);
1551 if (rc < 0) {
1552 return rc;
1553 }
1554
1555 rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1556 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301557 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001558 }
1559 if (PLDM_SUCCESS != resp_data->completion_code) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301560 return pldm_msgbuf_complete(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001561 }
1562
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301563 if (payload_length <
1564 PLDM_GET_DOWNSTREAM_FIRMWARE_PARAMETERS_RESP_MIN_LEN) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301565 return pldm_msgbuf_discard(buf, -EBADMSG);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001566 }
1567
1568 pldm_msgbuf_extract(buf, resp_data->next_data_transfer_handle);
1569 pldm_msgbuf_extract(buf, resp_data->transfer_flag);
1570 pldm_msgbuf_extract(buf,
1571 resp_data->fdp_capabilities_during_update.value);
1572 pldm_msgbuf_extract(buf, resp_data->downstream_device_count);
1573
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301574 rc = pldm_msgbuf_span_remaining(buf, &remaining, &length);
1575 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301576 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301577 }
1578
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301579 rc = pldm_msgbuf_complete(buf);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301580 if (rc) {
1581 return rc;
1582 }
1583
1584 iter->field.ptr = remaining;
1585 iter->field.length = length;
1586 iter->entries = resp_data->downstream_device_count;
1587
1588 return 0;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001589}
1590
Unive Tiene5c3f142024-12-13 14:14:19 +08001591LIBPLDM_ABI_STABLE
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301592int decode_pldm_downstream_device_parameters_entry_from_iter(
1593 struct pldm_downstream_device_parameters_iter *iter,
1594 struct pldm_downstream_device_parameters_entry *entry)
Chris Wangb6ef35b2024-07-03 09:35:42 +08001595{
Andrew Jefferya1896962025-03-03 21:41:25 +10301596 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301597 void *comp_ver_str;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001598 size_t remaining;
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301599 void *cursor;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001600 int rc;
1601
Andrew Jefferya1896962025-03-03 21:41:25 +10301602 if (iter == NULL || iter->field.ptr == NULL || entry == NULL) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001603 return -EINVAL;
1604 }
1605
1606 rc = pldm_msgbuf_init_errno(
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301607 buf, PLDM_DOWNSTREAM_DEVICE_PARAMETERS_ENTRY_MIN_LEN,
1608 iter->field.ptr, iter->field.length);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001609 if (rc < 0) {
1610 return rc;
1611 }
1612
1613 pldm_msgbuf_extract(buf, entry->downstream_device_index);
1614 pldm_msgbuf_extract(buf, entry->active_comp_comparison_stamp);
1615 pldm_msgbuf_extract(buf, entry->active_comp_ver_str_type);
1616 rc = pldm_msgbuf_extract(buf, entry->active_comp_ver_str_len);
1617 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301618 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001619 }
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001620 rc = pldm_msgbuf_extract_array(buf,
1621 PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1622 entry->active_comp_release_date,
1623 sizeof(entry->active_comp_release_date));
1624 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301625 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001626 }
1627
Chris Wangb6ef35b2024-07-03 09:35:42 +08001628 // Fill the last byte with NULL character
1629 entry->active_comp_release_date[PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN] =
1630 '\0';
1631
1632 pldm_msgbuf_extract(buf, entry->pending_comp_comparison_stamp);
1633 pldm_msgbuf_extract(buf, entry->pending_comp_ver_str_type);
1634 rc = pldm_msgbuf_extract(buf, entry->pending_comp_ver_str_len);
1635 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301636 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001637 }
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001638
1639 rc = pldm_msgbuf_extract_array(
1640 buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1641 entry->pending_comp_release_date,
1642 sizeof(entry->pending_comp_release_date));
1643 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301644 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001645 }
1646
Chris Wangb6ef35b2024-07-03 09:35:42 +08001647 // Fill the last byte with NULL character
1648 entry->pending_comp_release_date[PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN] =
1649 '\0';
1650
1651 pldm_msgbuf_extract(buf, entry->comp_activation_methods.value);
1652 pldm_msgbuf_extract(buf, entry->capabilities_during_update.value);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001653
Andrew Jefferya1896962025-03-03 21:41:25 +10301654 rc = pldm_msgbuf_span_required(buf, entry->active_comp_ver_str_len,
1655 &comp_ver_str);
1656 if (rc < 0) {
1657 return pldm_msgbuf_discard(buf, rc);
1658 }
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301659 entry->active_comp_ver_str = comp_ver_str;
1660
Andrew Jefferya1896962025-03-03 21:41:25 +10301661 rc = pldm_msgbuf_span_required(buf, entry->pending_comp_ver_str_len,
1662 &comp_ver_str);
1663 if (rc < 0) {
1664 return pldm_msgbuf_discard(buf, rc);
1665 }
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301666 entry->pending_comp_ver_str = comp_ver_str;
1667
Chris Wangb6ef35b2024-07-03 09:35:42 +08001668 rc = pldm_msgbuf_span_remaining(buf, &cursor, &remaining);
1669 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301670 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001671 }
1672
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301673 iter->field.ptr = cursor;
1674 iter->field.length = remaining;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001675
Andrew Jefferya1896962025-03-03 21:41:25 +10301676 return pldm_msgbuf_complete(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001677}
1678
Sora Su06eadd02025-05-27 11:28:51 +08001679LIBPLDM_ABI_TESTING
1680int encode_request_downstream_device_update_req(
1681 uint8_t instance_id,
1682 const struct pldm_request_downstream_device_update_req *req_data,
1683 struct pldm_msg *msg, size_t *payload_length)
1684{
1685 PLDM_MSGBUF_DEFINE_P(buf);
1686 int rc;
1687
1688 if (!req_data || !msg || !payload_length ||
1689 req_data->maximum_downstream_device_transfer_size <
1690 PLDM_FWUP_BASELINE_TRANSFER_SIZE ||
1691 req_data->maximum_outstanding_transfer_requests <
1692 PLDM_FWUP_MIN_OUTSTANDING_REQ) {
1693 return -EINVAL;
1694 }
1695
1696 rc = encode_pldm_header_only_errno(
1697 PLDM_REQUEST, instance_id, PLDM_FWUP,
1698 PLDM_REQUEST_DOWNSTREAM_DEVICE_UPDATE, msg);
1699 if (rc) {
1700 return rc;
1701 }
1702
1703 rc = pldm_msgbuf_init_errno(buf,
1704 PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES,
1705 msg->payload, *payload_length);
1706 if (rc) {
1707 return rc;
1708 }
1709
1710 pldm_msgbuf_insert(buf,
1711 req_data->maximum_downstream_device_transfer_size);
1712 pldm_msgbuf_insert(buf,
1713 req_data->maximum_outstanding_transfer_requests);
1714 pldm_msgbuf_insert(buf,
1715 req_data->downstream_device_package_data_length);
1716
1717 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
1718}
1719
1720LIBPLDM_ABI_TESTING
1721int decode_request_downstream_device_update_req(
1722 const struct pldm_msg *msg, size_t payload_length,
1723 struct pldm_request_downstream_device_update_req *req)
1724{
1725 int rc;
1726 PLDM_MSGBUF_DEFINE_P(buf);
1727
1728 if (!msg || !req) {
1729 return -EINVAL;
1730 }
1731
1732 rc = pldm_msgbuf_init_errno(buf,
1733 PLDM_DOWNSTREAM_DEVICE_UPDATE_REQUEST_BYTES,
1734 msg->payload, payload_length);
1735 if (rc) {
1736 return rc;
1737 }
1738
1739 pldm_msgbuf_extract(buf, req->maximum_downstream_device_transfer_size);
1740 pldm_msgbuf_extract(buf, req->maximum_outstanding_transfer_requests);
1741 pldm_msgbuf_extract(buf, req->downstream_device_package_data_length);
1742
1743 return pldm_msgbuf_complete_consumed(buf);
1744}
1745
1746LIBPLDM_ABI_TESTING
1747int encode_request_downstream_device_update_resp(
1748 uint8_t instance_id,
1749 const struct pldm_request_downstream_device_update_resp *resp_data,
1750 struct pldm_msg *msg, size_t *payload_length)
1751{
1752 PLDM_MSGBUF_DEFINE_P(buf);
1753 int rc;
1754
1755 if (!resp_data || !msg || !payload_length) {
1756 return -EINVAL;
1757 }
1758
1759 rc = encode_pldm_header_only_errno(
1760 PLDM_RESPONSE, instance_id, PLDM_FWUP,
1761 PLDM_REQUEST_DOWNSTREAM_DEVICE_UPDATE, msg);
1762 if (rc) {
1763 return rc;
1764 }
1765
1766 rc = pldm_msgbuf_init_errno(
1767 buf, PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES, msg->payload,
1768 *payload_length);
1769 if (rc) {
1770 return rc;
1771 }
1772
1773 pldm_msgbuf_insert(buf, resp_data->completion_code);
1774 pldm_msgbuf_insert(buf, resp_data->downstream_device_meta_data_length);
1775 pldm_msgbuf_insert(
1776 buf, resp_data->downstream_device_will_send_get_package_data);
1777 pldm_msgbuf_insert(buf,
1778 resp_data->get_package_data_maximum_transfer_size);
1779
1780 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
1781}
1782
1783LIBPLDM_ABI_TESTING
1784int decode_request_downstream_device_update_resp(
1785 const struct pldm_msg *msg, size_t payload_length,
1786 struct pldm_request_downstream_device_update_resp *resp_data)
1787{
1788 PLDM_MSGBUF_DEFINE_P(buf);
1789 int rc;
1790
1791 if (!msg || !resp_data) {
1792 return -EINVAL;
1793 }
1794
1795 rc = pldm_msg_has_error(msg,
1796 PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES);
1797 if (rc) {
1798 resp_data->completion_code = rc;
1799 return 0;
1800 }
1801
1802 rc = pldm_msgbuf_init_errno(
1803 buf, PLDM_DOWNSTREAM_DEVICE_UPDATE_RESPONSE_BYTES, msg->payload,
1804 payload_length);
1805 if (rc) {
1806 return rc;
1807 }
1808
1809 pldm_msgbuf_extract(buf, resp_data->completion_code);
1810 pldm_msgbuf_extract(buf, resp_data->downstream_device_meta_data_length);
1811 pldm_msgbuf_extract(
1812 buf, resp_data->downstream_device_will_send_get_package_data);
1813 pldm_msgbuf_extract(buf,
1814 resp_data->get_package_data_maximum_transfer_size);
1815
1816 return pldm_msgbuf_complete_consumed(buf);
1817}
1818
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301819LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301820int encode_request_update_req(uint8_t instance_id, uint32_t max_transfer_size,
1821 uint16_t num_of_comp,
1822 uint8_t max_outstanding_transfer_req,
1823 uint16_t pkg_data_len,
1824 uint8_t comp_image_set_ver_str_type,
1825 uint8_t comp_image_set_ver_str_len,
1826 const struct variable_field *comp_img_set_ver_str,
1827 struct pldm_msg *msg, size_t payload_length)
1828{
1829 if (comp_img_set_ver_str == NULL || comp_img_set_ver_str->ptr == NULL ||
1830 msg == NULL) {
1831 return PLDM_ERROR_INVALID_DATA;
1832 }
1833
1834 if (payload_length != sizeof(struct pldm_request_update_req) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301835 comp_img_set_ver_str->length) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301836 return PLDM_ERROR_INVALID_LENGTH;
1837 }
1838
1839 if ((comp_image_set_ver_str_len == 0) ||
1840 (comp_image_set_ver_str_len != comp_img_set_ver_str->length)) {
1841 return PLDM_ERROR_INVALID_DATA;
1842 }
1843
1844 if ((max_transfer_size < PLDM_FWUP_BASELINE_TRANSFER_SIZE) ||
1845 (max_outstanding_transfer_req < PLDM_FWUP_MIN_OUTSTANDING_REQ)) {
1846 return PLDM_ERROR_INVALID_DATA;
1847 }
1848
1849 if (!is_string_type_valid(comp_image_set_ver_str_type)) {
1850 return PLDM_ERROR_INVALID_DATA;
1851 }
1852
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301853 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09301854 header.instance = instance_id;
1855 header.msg_type = PLDM_REQUEST;
1856 header.pldm_type = PLDM_FWUP;
1857 header.command = PLDM_REQUEST_UPDATE;
1858 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1859 if (rc) {
1860 return rc;
1861 }
1862
1863 struct pldm_request_update_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301864 (struct pldm_request_update_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301865
1866 request->max_transfer_size = htole32(max_transfer_size);
1867 request->num_of_comp = htole16(num_of_comp);
1868 request->max_outstanding_transfer_req = max_outstanding_transfer_req;
1869 request->pkg_data_len = htole16(pkg_data_len);
1870 request->comp_image_set_ver_str_type = comp_image_set_ver_str_type;
1871 request->comp_image_set_ver_str_len = comp_image_set_ver_str_len;
1872
1873 memcpy(msg->payload + sizeof(struct pldm_request_update_req),
1874 comp_img_set_ver_str->ptr, comp_img_set_ver_str->length);
1875
1876 return PLDM_SUCCESS;
1877}
1878
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001879LIBPLDM_ABI_TESTING
1880int decode_request_update_req(const struct pldm_msg *msg, size_t payload_length,
1881 struct pldm_request_update_req_full *req)
1882{
1883 int rc;
1884 uint8_t t;
Andrew Jefferya1896962025-03-03 21:41:25 +10301885 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001886
1887 if (msg == NULL || req == NULL) {
1888 return -EINVAL;
1889 }
1890
1891 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
1892 if (rc) {
1893 return rc;
1894 }
1895
1896 pldm_msgbuf_extract(buf, req->max_transfer_size);
1897 pldm_msgbuf_extract(buf, req->num_of_comp);
1898 pldm_msgbuf_extract(buf, req->max_outstanding_transfer_req);
1899 pldm_msgbuf_extract(buf, req->pkg_data_len);
1900 rc = pldm_msgbuf_extract(buf, t);
1901 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301902 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001903 }
1904 if (t > PLDM_STR_TYPE_UTF_16BE) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301905 return pldm_msgbuf_discard(buf, -EBADMSG);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001906 }
1907 req->image_set_ver.str_type = (enum pldm_firmware_update_string_type)t;
1908 pldm_msgbuf_extract(buf, req->image_set_ver.str_len);
1909 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301910 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001911 }
1912
1913 rc = pldm_msgbuf_extract_array(buf, req->image_set_ver.str_len,
1914 req->image_set_ver.str_data,
1915 PLDM_FIRMWARE_MAX_STRING);
1916 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301917 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001918 }
1919
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301920 return pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001921}
1922
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301923LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301924int decode_request_update_resp(const struct pldm_msg *msg,
1925 size_t payload_length, uint8_t *completion_code,
1926 uint16_t *fd_meta_data_len,
1927 uint8_t *fd_will_send_pkg_data)
1928{
1929 if (msg == NULL || completion_code == NULL ||
1930 fd_meta_data_len == NULL || fd_will_send_pkg_data == NULL ||
1931 !payload_length) {
1932 return PLDM_ERROR_INVALID_DATA;
1933 }
1934
1935 *completion_code = msg->payload[0];
1936 if (*completion_code != PLDM_SUCCESS) {
1937 return PLDM_SUCCESS;
1938 }
1939
1940 if (payload_length != sizeof(struct pldm_request_update_resp)) {
1941 return PLDM_ERROR_INVALID_LENGTH;
1942 }
1943
1944 struct pldm_request_update_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301945 (struct pldm_request_update_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301946
1947 *fd_meta_data_len = le16toh(response->fd_meta_data_len);
1948 *fd_will_send_pkg_data = response->fd_will_send_pkg_data;
1949
1950 return PLDM_SUCCESS;
1951}
1952
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001953LIBPLDM_ABI_TESTING
1954int encode_request_update_resp(uint8_t instance_id,
1955 const struct pldm_request_update_resp *resp_data,
1956 struct pldm_msg *msg, size_t *payload_length)
1957{
Andrew Jefferya1896962025-03-03 21:41:25 +10301958 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001959 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001960
1961 if (msg == NULL || payload_length == NULL) {
1962 return -EINVAL;
1963 }
1964
1965 struct pldm_header_info header = {
1966 .instance = instance_id,
1967 .msg_type = PLDM_RESPONSE,
1968 .pldm_type = PLDM_FWUP,
1969 .command = PLDM_REQUEST_UPDATE,
1970 };
1971 rc = pack_pldm_header(&header, &(msg->hdr));
1972 if (rc) {
1973 return -EINVAL;
1974 }
1975
1976 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
1977 if (rc) {
1978 return rc;
1979 }
1980
1981 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
1982 pldm_msgbuf_insert(buf, resp_data->fd_meta_data_len);
1983 pldm_msgbuf_insert(buf, resp_data->fd_will_send_pkg_data);
1984
1985 /* TODO: DSP0267 1.3.0 adds GetPackageDataMaximumTransferSize */
1986
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301987 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001988}
1989
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301990LIBPLDM_ABI_STABLE
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301991int encode_pass_component_table_req(uint8_t instance_id, uint8_t transfer_flag,
1992 uint16_t comp_classification,
1993 uint16_t comp_identifier,
1994 uint8_t comp_classification_index,
1995 uint32_t comp_comparison_stamp,
1996 uint8_t comp_ver_str_type,
1997 uint8_t comp_ver_str_len,
1998 const struct variable_field *comp_ver_str,
1999 struct pldm_msg *msg, size_t payload_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09302000{
2001 if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) {
2002 return PLDM_ERROR_INVALID_DATA;
2003 }
2004
2005 if (payload_length != sizeof(struct pldm_pass_component_table_req) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302006 comp_ver_str->length) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302007 return PLDM_ERROR_INVALID_LENGTH;
2008 }
2009
2010 if ((comp_ver_str_len == 0) ||
2011 (comp_ver_str_len != comp_ver_str->length)) {
2012 return PLDM_ERROR_INVALID_DATA;
2013 }
2014
2015 if (!is_transfer_flag_valid(transfer_flag)) {
Manojkiran Eda3643e742025-05-19 12:03:54 +05302016 return PLDM_FWUP_INVALID_TRANSFER_OPERATION_FLAG;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302017 }
2018
2019 if (!is_string_type_valid(comp_ver_str_type)) {
2020 return PLDM_ERROR_INVALID_DATA;
2021 }
2022
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302023 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302024 header.instance = instance_id;
2025 header.msg_type = PLDM_REQUEST;
2026 header.pldm_type = PLDM_FWUP;
2027 header.command = PLDM_PASS_COMPONENT_TABLE;
2028 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2029 if (rc) {
2030 return rc;
2031 }
2032
2033 struct pldm_pass_component_table_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302034 (struct pldm_pass_component_table_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302035
2036 request->transfer_flag = transfer_flag;
2037 request->comp_classification = htole16(comp_classification);
2038 request->comp_identifier = htole16(comp_identifier);
2039 request->comp_classification_index = comp_classification_index;
2040 request->comp_comparison_stamp = htole32(comp_comparison_stamp);
2041 request->comp_ver_str_type = comp_ver_str_type;
2042 request->comp_ver_str_len = comp_ver_str_len;
2043
2044 memcpy(msg->payload + sizeof(struct pldm_pass_component_table_req),
2045 comp_ver_str->ptr, comp_ver_str->length);
2046
2047 return PLDM_SUCCESS;
2048}
2049
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002050LIBPLDM_ABI_TESTING
2051int decode_pass_component_table_req(
2052 const struct pldm_msg *msg, size_t payload_length,
2053 struct pldm_pass_component_table_req_full *pcomp)
2054{
2055 int rc;
2056 uint8_t t;
Andrew Jefferya1896962025-03-03 21:41:25 +10302057 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002058
2059 if (msg == NULL || pcomp == NULL) {
2060 return -EINVAL;
2061 }
2062
2063 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2064 if (rc) {
2065 return rc;
2066 }
2067
2068 pldm_msgbuf_extract(buf, pcomp->transfer_flag);
2069 pldm_msgbuf_extract(buf, pcomp->comp_classification);
2070 pldm_msgbuf_extract(buf, pcomp->comp_identifier);
2071 pldm_msgbuf_extract(buf, pcomp->comp_classification_index);
2072 pldm_msgbuf_extract(buf, pcomp->comp_comparison_stamp);
2073 rc = pldm_msgbuf_extract(buf, t);
2074 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302075 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002076 }
2077 if (t > PLDM_STR_TYPE_UTF_16BE) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302078 return pldm_msgbuf_discard(buf, -EBADMSG);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002079 }
2080 pcomp->version.str_type = (enum pldm_firmware_update_string_type)t;
2081 rc = pldm_msgbuf_extract(buf, pcomp->version.str_len);
2082 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302083 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002084 }
2085 rc = pldm_msgbuf_extract_array(buf, pcomp->version.str_len,
2086 pcomp->version.str_data,
2087 PLDM_FIRMWARE_MAX_STRING);
2088 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302089 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002090 }
2091
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302092 return pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002093}
2094
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302095LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302096int decode_pass_component_table_resp(const struct pldm_msg *msg,
2097 const size_t payload_length,
2098 uint8_t *completion_code,
2099 uint8_t *comp_resp,
2100 uint8_t *comp_resp_code)
2101{
2102 if (msg == NULL || completion_code == NULL || comp_resp == NULL ||
2103 comp_resp_code == NULL || !payload_length) {
2104 return PLDM_ERROR_INVALID_DATA;
2105 }
2106
2107 *completion_code = msg->payload[0];
2108 if (*completion_code != PLDM_SUCCESS) {
2109 return PLDM_SUCCESS;
2110 }
2111
2112 if (payload_length != sizeof(struct pldm_pass_component_table_resp)) {
2113 return PLDM_ERROR_INVALID_LENGTH;
2114 }
2115
2116 struct pldm_pass_component_table_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302117 (struct pldm_pass_component_table_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302118
2119 if (!is_comp_resp_valid(response->comp_resp)) {
2120 return PLDM_ERROR_INVALID_DATA;
2121 }
2122
2123 if (!is_comp_resp_code_valid(response->comp_resp_code)) {
2124 return PLDM_ERROR_INVALID_DATA;
2125 }
2126
2127 *comp_resp = response->comp_resp;
2128 *comp_resp_code = response->comp_resp_code;
2129
2130 return PLDM_SUCCESS;
2131}
2132
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002133LIBPLDM_ABI_TESTING
2134int encode_pass_component_table_resp(
2135 uint8_t instance_id,
2136 const struct pldm_pass_component_table_resp *resp_data,
2137 struct pldm_msg *msg, size_t *payload_length)
2138{
Andrew Jefferya1896962025-03-03 21:41:25 +10302139 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002140 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002141
2142 if (msg == NULL || payload_length == NULL) {
2143 return -EINVAL;
2144 }
2145
2146 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2147 PLDM_PASS_COMPONENT_TABLE, msg);
2148 if (rc) {
2149 return -EINVAL;
2150 }
2151
2152 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2153 if (rc) {
2154 return rc;
2155 }
2156
2157 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2158 pldm_msgbuf_insert(buf, resp_data->comp_resp);
2159 pldm_msgbuf_insert(buf, resp_data->comp_resp_code);
2160
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302161 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002162}
2163
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302164LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302165int encode_update_component_req(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302166 uint8_t instance_id, uint16_t comp_classification,
2167 uint16_t comp_identifier, uint8_t comp_classification_index,
2168 uint32_t comp_comparison_stamp, uint32_t comp_image_size,
2169 bitfield32_t update_option_flags, uint8_t comp_ver_str_type,
2170 uint8_t comp_ver_str_len, const struct variable_field *comp_ver_str,
2171 struct pldm_msg *msg, size_t payload_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09302172{
2173 if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) {
2174 return PLDM_ERROR_INVALID_DATA;
2175 }
2176
2177 if (payload_length !=
2178 sizeof(struct pldm_update_component_req) + comp_ver_str->length) {
2179 return PLDM_ERROR_INVALID_LENGTH;
2180 }
2181
2182 if (!comp_image_size) {
2183 return PLDM_ERROR_INVALID_DATA;
2184 }
2185
2186 if ((comp_ver_str_len == 0) ||
2187 (comp_ver_str_len != comp_ver_str->length)) {
2188 return PLDM_ERROR_INVALID_DATA;
2189 }
2190
2191 if (!is_string_type_valid(comp_ver_str_type)) {
2192 return PLDM_ERROR_INVALID_DATA;
2193 }
2194
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302195 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302196 header.instance = instance_id;
2197 header.msg_type = PLDM_REQUEST;
2198 header.pldm_type = PLDM_FWUP;
2199 header.command = PLDM_UPDATE_COMPONENT;
2200 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2201 if (rc) {
2202 return rc;
2203 }
2204
2205 struct pldm_update_component_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302206 (struct pldm_update_component_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302207
2208 request->comp_classification = htole16(comp_classification);
2209 request->comp_identifier = htole16(comp_identifier);
2210 request->comp_classification_index = comp_classification_index;
2211 request->comp_comparison_stamp = htole32(comp_comparison_stamp);
2212 request->comp_image_size = htole32(comp_image_size);
2213 request->update_option_flags.value = htole32(update_option_flags.value);
2214 request->comp_ver_str_type = comp_ver_str_type;
2215 request->comp_ver_str_len = comp_ver_str_len;
2216
2217 memcpy(msg->payload + sizeof(struct pldm_update_component_req),
2218 comp_ver_str->ptr, comp_ver_str->length);
2219
2220 return PLDM_SUCCESS;
2221}
2222
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002223LIBPLDM_ABI_TESTING
2224int decode_update_component_req(const struct pldm_msg *msg,
2225 size_t payload_length,
2226 struct pldm_update_component_req_full *up)
2227{
2228 int rc;
2229 uint8_t t;
Andrew Jefferya1896962025-03-03 21:41:25 +10302230 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002231
2232 if (msg == NULL || up == NULL) {
2233 return -EINVAL;
2234 }
2235
2236 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2237 if (rc) {
2238 return rc;
2239 }
2240
2241 pldm_msgbuf_extract(buf, up->comp_classification);
2242 pldm_msgbuf_extract(buf, up->comp_identifier);
2243 pldm_msgbuf_extract(buf, up->comp_classification_index);
2244 pldm_msgbuf_extract(buf, up->comp_comparison_stamp);
2245 pldm_msgbuf_extract(buf, up->comp_image_size);
2246 pldm_msgbuf_extract(buf, up->update_option_flags.value);
2247 rc = pldm_msgbuf_extract(buf, t);
2248 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302249 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002250 }
2251 if (t > PLDM_STR_TYPE_UTF_16BE) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302252 return pldm_msgbuf_discard(buf, -EBADMSG);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002253 }
2254 up->version.str_type = (enum pldm_firmware_update_string_type)t;
2255 rc = pldm_msgbuf_extract(buf, up->version.str_len);
2256 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302257 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002258 }
2259 rc = pldm_msgbuf_extract_array(buf, up->version.str_len,
2260 up->version.str_data,
2261 PLDM_FIRMWARE_MAX_STRING);
2262 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302263 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002264 }
2265
Andrew Jefferya1896962025-03-03 21:41:25 +10302266 return pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002267}
2268
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302269LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302270int decode_update_component_resp(const struct pldm_msg *msg,
2271 size_t payload_length,
2272 uint8_t *completion_code,
2273 uint8_t *comp_compatibility_resp,
2274 uint8_t *comp_compatibility_resp_code,
2275 bitfield32_t *update_option_flags_enabled,
2276 uint16_t *time_before_req_fw_data)
2277{
2278 if (msg == NULL || completion_code == NULL ||
2279 comp_compatibility_resp == NULL ||
2280 comp_compatibility_resp_code == NULL ||
2281 update_option_flags_enabled == NULL ||
2282 time_before_req_fw_data == NULL || !payload_length) {
2283 return PLDM_ERROR_INVALID_DATA;
2284 }
2285
2286 *completion_code = msg->payload[0];
2287 if (*completion_code != PLDM_SUCCESS) {
2288 return PLDM_SUCCESS;
2289 }
2290
2291 if (payload_length != sizeof(struct pldm_update_component_resp)) {
2292 return PLDM_ERROR_INVALID_LENGTH;
2293 }
2294
2295 struct pldm_update_component_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302296 (struct pldm_update_component_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302297
2298 if (!is_comp_compatibility_resp_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302299 response->comp_compatibility_resp)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302300 return PLDM_ERROR_INVALID_DATA;
2301 }
2302
2303 if (!is_comp_compatibility_resp_code_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302304 response->comp_compatibility_resp_code)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302305 return PLDM_ERROR_INVALID_DATA;
2306 }
2307
2308 *comp_compatibility_resp = response->comp_compatibility_resp;
2309 *comp_compatibility_resp_code = response->comp_compatibility_resp_code;
2310 update_option_flags_enabled->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302311 le32toh(response->update_option_flags_enabled.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302312 *time_before_req_fw_data = le16toh(response->time_before_req_fw_data);
2313
2314 return PLDM_SUCCESS;
2315}
2316
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002317LIBPLDM_ABI_TESTING
2318int encode_update_component_resp(
2319 uint8_t instance_id, const struct pldm_update_component_resp *resp_data,
2320 struct pldm_msg *msg, size_t *payload_length)
2321{
Andrew Jefferya1896962025-03-03 21:41:25 +10302322 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002323 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002324
2325 if (msg == NULL || payload_length == NULL) {
2326 return -EINVAL;
2327 }
2328
2329 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2330 PLDM_UPDATE_COMPONENT, msg);
2331 if (rc) {
2332 return -EINVAL;
2333 }
2334
2335 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2336 if (rc) {
2337 return rc;
2338 }
2339
2340 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2341 pldm_msgbuf_insert(buf, resp_data->comp_compatibility_resp);
2342 pldm_msgbuf_insert(buf, resp_data->comp_compatibility_resp_code);
2343 pldm_msgbuf_insert(buf, resp_data->update_option_flags_enabled.value);
2344 pldm_msgbuf_insert(buf, resp_data->time_before_req_fw_data);
2345
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302346 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002347}
2348
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302349LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302350int decode_request_firmware_data_req(const struct pldm_msg *msg,
2351 size_t payload_length, uint32_t *offset,
2352 uint32_t *length)
2353{
2354 if (msg == NULL || offset == NULL || length == NULL) {
2355 return PLDM_ERROR_INVALID_DATA;
2356 }
2357 if (payload_length != sizeof(struct pldm_request_firmware_data_req)) {
2358 return PLDM_ERROR_INVALID_LENGTH;
2359 }
2360 struct pldm_request_firmware_data_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302361 (struct pldm_request_firmware_data_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302362 *offset = le32toh(request->offset);
2363 *length = le32toh(request->length);
2364
2365 if (*length < PLDM_FWUP_BASELINE_TRANSFER_SIZE) {
2366 return PLDM_FWUP_INVALID_TRANSFER_LENGTH;
2367 }
2368
2369 return PLDM_SUCCESS;
2370}
2371
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002372LIBPLDM_ABI_TESTING
2373int encode_request_firmware_data_req(
2374 uint8_t instance_id,
2375 const struct pldm_request_firmware_data_req *req_params,
2376 struct pldm_msg *msg, size_t *payload_length)
2377{
Andrew Jefferya1896962025-03-03 21:41:25 +10302378 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002379 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002380
2381 if (msg == NULL || payload_length == NULL) {
2382 return -EINVAL;
2383 }
2384
2385 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2386 PLDM_REQUEST_FIRMWARE_DATA, msg);
2387 if (rc) {
2388 return -EINVAL;
2389 }
2390
2391 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2392 if (rc) {
2393 return rc;
2394 }
2395
2396 pldm_msgbuf_insert(buf, req_params->offset);
2397 pldm_msgbuf_insert(buf, req_params->length);
2398
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302399 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002400}
2401
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302402LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302403int encode_request_firmware_data_resp(uint8_t instance_id,
2404 uint8_t completion_code,
2405 struct pldm_msg *msg,
2406 size_t payload_length)
2407{
2408 if (msg == NULL || !payload_length) {
2409 return PLDM_ERROR_INVALID_DATA;
2410 }
2411
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302412 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302413 header.instance = instance_id;
2414 header.msg_type = PLDM_RESPONSE;
2415 header.pldm_type = PLDM_FWUP;
2416 header.command = PLDM_REQUEST_FIRMWARE_DATA;
2417 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2418 if (rc) {
2419 return rc;
2420 }
2421
2422 msg->payload[0] = completion_code;
2423
2424 return PLDM_SUCCESS;
2425}
2426
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302427LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302428int decode_transfer_complete_req(const struct pldm_msg *msg,
2429 size_t payload_length,
2430 uint8_t *transfer_result)
2431{
2432 if (msg == NULL || transfer_result == NULL) {
2433 return PLDM_ERROR_INVALID_DATA;
2434 }
2435
2436 if (payload_length != sizeof(*transfer_result)) {
2437 return PLDM_ERROR_INVALID_LENGTH;
2438 }
2439
2440 *transfer_result = msg->payload[0];
2441 return PLDM_SUCCESS;
2442}
2443
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002444LIBPLDM_ABI_TESTING
2445int encode_transfer_complete_req(uint8_t instance_id, uint8_t transfer_result,
2446 struct pldm_msg *msg, size_t *payload_length)
2447{
Andrew Jefferya1896962025-03-03 21:41:25 +10302448 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002449 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002450
2451 if (msg == NULL || payload_length == NULL) {
2452 return -EINVAL;
2453 }
2454
2455 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2456 PLDM_TRANSFER_COMPLETE, msg);
2457 if (rc) {
2458 return -EINVAL;
2459 }
2460
2461 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2462 if (rc) {
2463 return rc;
2464 }
2465
Andrew Jefferya1896962025-03-03 21:41:25 +10302466 pldm_msgbuf_insert(buf, transfer_result);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002467
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302468 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002469}
2470
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302471LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302472int encode_transfer_complete_resp(uint8_t instance_id, uint8_t completion_code,
2473 struct pldm_msg *msg, size_t payload_length)
2474{
2475 if (msg == NULL) {
2476 return PLDM_ERROR_INVALID_DATA;
2477 }
2478
2479 if (payload_length != sizeof(completion_code)) {
2480 return PLDM_ERROR_INVALID_LENGTH;
2481 }
2482
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302483 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302484 header.instance = instance_id;
2485 header.msg_type = PLDM_RESPONSE;
2486 header.pldm_type = PLDM_FWUP;
2487 header.command = PLDM_TRANSFER_COMPLETE;
2488 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2489 if (rc) {
2490 return rc;
2491 }
2492
2493 msg->payload[0] = completion_code;
2494
2495 return PLDM_SUCCESS;
2496}
2497
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302498LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302499int decode_verify_complete_req(const struct pldm_msg *msg,
2500 size_t payload_length, uint8_t *verify_result)
2501{
2502 if (msg == NULL || verify_result == NULL) {
2503 return PLDM_ERROR_INVALID_DATA;
2504 }
2505
2506 if (payload_length != sizeof(*verify_result)) {
2507 return PLDM_ERROR_INVALID_LENGTH;
2508 }
2509
2510 *verify_result = msg->payload[0];
2511 return PLDM_SUCCESS;
2512}
2513
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002514LIBPLDM_ABI_TESTING
2515int encode_verify_complete_req(uint8_t instance_id, uint8_t verify_result,
2516 struct pldm_msg *msg, size_t *payload_length)
2517{
Andrew Jefferya1896962025-03-03 21:41:25 +10302518 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002519 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002520
2521 if (msg == NULL || payload_length == NULL) {
2522 return -EINVAL;
2523 }
2524
2525 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2526 PLDM_VERIFY_COMPLETE, msg);
2527 if (rc) {
2528 return EINVAL;
2529 }
2530
2531 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2532 if (rc) {
2533 return rc;
2534 }
2535
Andrew Jefferya1896962025-03-03 21:41:25 +10302536 pldm_msgbuf_insert(buf, verify_result);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002537
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302538 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002539}
2540
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302541LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302542int encode_verify_complete_resp(uint8_t instance_id, uint8_t completion_code,
2543 struct pldm_msg *msg, size_t payload_length)
2544{
2545 if (msg == NULL) {
2546 return PLDM_ERROR_INVALID_DATA;
2547 }
2548
2549 if (payload_length != sizeof(completion_code)) {
2550 return PLDM_ERROR_INVALID_LENGTH;
2551 }
2552
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302553 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302554 header.instance = instance_id;
2555 header.msg_type = PLDM_RESPONSE;
2556 header.pldm_type = PLDM_FWUP;
2557 header.command = PLDM_VERIFY_COMPLETE;
2558 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2559 if (rc) {
2560 return rc;
2561 }
2562
2563 msg->payload[0] = completion_code;
2564
2565 return PLDM_SUCCESS;
2566}
2567
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302568LIBPLDM_ABI_STABLE
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302569int decode_apply_complete_req(const struct pldm_msg *msg, size_t payload_length,
2570 uint8_t *apply_result,
2571 bitfield16_t *comp_activation_methods_modification)
Andrew Jeffery9c766792022-08-10 23:12:49 +09302572{
2573 if (msg == NULL || apply_result == NULL ||
2574 comp_activation_methods_modification == NULL) {
2575 return PLDM_ERROR_INVALID_DATA;
2576 }
2577
2578 if (payload_length != sizeof(struct pldm_apply_complete_req)) {
2579 return PLDM_ERROR_INVALID_LENGTH;
2580 }
2581
2582 struct pldm_apply_complete_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302583 (struct pldm_apply_complete_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302584
2585 *apply_result = request->apply_result;
2586 comp_activation_methods_modification->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302587 le16toh(request->comp_activation_methods_modification.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302588
2589 if ((*apply_result != PLDM_FWUP_APPLY_SUCCESS_WITH_ACTIVATION_METHOD) &&
2590 comp_activation_methods_modification->value) {
2591 return PLDM_ERROR_INVALID_DATA;
2592 }
2593
2594 return PLDM_SUCCESS;
2595}
2596
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002597LIBPLDM_ABI_TESTING
2598int encode_apply_complete_req(uint8_t instance_id,
2599 const struct pldm_apply_complete_req *req_data,
2600 struct pldm_msg *msg, size_t *payload_length)
2601{
Andrew Jefferya1896962025-03-03 21:41:25 +10302602 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002603 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002604
2605 if (msg == NULL || payload_length == NULL) {
2606 return -EINVAL;
2607 }
2608
2609 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2610 PLDM_APPLY_COMPLETE, msg);
2611 if (rc) {
2612 return -EINVAL;
2613 }
2614
2615 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2616 if (rc) {
2617 return rc;
2618 }
2619
2620 pldm_msgbuf_insert(buf, req_data->apply_result);
2621 pldm_msgbuf_insert(
2622 buf, req_data->comp_activation_methods_modification.value);
2623
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_apply_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_APPLY_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
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002654LIBPLDM_ABI_TESTING
2655int decode_activate_firmware_req(const struct pldm_msg *msg,
2656 size_t payload_length, bool *self_contained)
2657{
Andrew Jefferya1896962025-03-03 21:41:25 +10302658 uint8_t self_contained_u8 = 0;
2659 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002660 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002661
2662 if (msg == NULL || self_contained == NULL) {
2663 return -EINVAL;
2664 }
2665
2666 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2667 if (rc) {
2668 return 0;
2669 }
2670
Andrew Jefferya1896962025-03-03 21:41:25 +10302671 pldm_msgbuf_extract(buf, self_contained_u8);
2672
2673 rc = pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002674 if (rc) {
2675 return rc;
2676 }
Andrew Jefferya1896962025-03-03 21:41:25 +10302677
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002678 *self_contained = (bool)self_contained_u8;
2679 return 0;
2680}
2681
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302682LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302683int encode_activate_firmware_req(uint8_t instance_id,
2684 bool8_t self_contained_activation_req,
2685 struct pldm_msg *msg, size_t payload_length)
2686{
2687 if (msg == NULL) {
2688 return PLDM_ERROR_INVALID_DATA;
2689 }
2690
2691 if (payload_length != sizeof(struct pldm_activate_firmware_req)) {
2692 return PLDM_ERROR_INVALID_LENGTH;
2693 }
2694
2695 if (!is_self_contained_activation_req_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302696 self_contained_activation_req)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302697 return PLDM_ERROR_INVALID_DATA;
2698 }
2699
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302700 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302701 header.instance = instance_id;
2702 header.msg_type = PLDM_REQUEST;
2703 header.pldm_type = PLDM_FWUP;
2704 header.command = PLDM_ACTIVATE_FIRMWARE;
2705 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2706 if (rc) {
2707 return rc;
2708 }
2709
2710 struct pldm_activate_firmware_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302711 (struct pldm_activate_firmware_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302712
2713 request->self_contained_activation_req = self_contained_activation_req;
2714
2715 return PLDM_SUCCESS;
2716}
2717
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302718LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302719int decode_activate_firmware_resp(const struct pldm_msg *msg,
2720 size_t payload_length,
2721 uint8_t *completion_code,
2722 uint16_t *estimated_time_activation)
2723{
2724 if (msg == NULL || completion_code == NULL ||
2725 estimated_time_activation == NULL || !payload_length) {
2726 return PLDM_ERROR_INVALID_DATA;
2727 }
2728
2729 *completion_code = msg->payload[0];
2730 if (*completion_code != PLDM_SUCCESS) {
2731 return PLDM_SUCCESS;
2732 }
2733
2734 if (payload_length != sizeof(struct pldm_activate_firmware_resp)) {
2735 return PLDM_ERROR_INVALID_LENGTH;
2736 }
2737
2738 struct pldm_activate_firmware_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302739 (struct pldm_activate_firmware_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302740
2741 *estimated_time_activation =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302742 le16toh(response->estimated_time_activation);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302743
2744 return PLDM_SUCCESS;
2745}
2746
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002747LIBPLDM_ABI_TESTING
2748int encode_activate_firmware_resp(
2749 uint8_t instance_id,
2750 const struct pldm_activate_firmware_resp *resp_data,
2751 struct pldm_msg *msg, size_t *payload_length)
2752{
Andrew Jefferya1896962025-03-03 21:41:25 +10302753 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002754 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002755
2756 if (msg == NULL || payload_length == NULL) {
2757 return -EINVAL;
2758 }
2759
2760 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2761 PLDM_ACTIVATE_FIRMWARE, msg);
2762 if (rc) {
2763 return -EINVAL;
2764 }
2765
2766 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2767 if (rc) {
2768 return rc;
2769 }
2770
2771 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2772 pldm_msgbuf_insert(buf, resp_data->estimated_time_activation);
2773
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302774 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002775}
2776
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302777LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302778int encode_get_status_req(uint8_t instance_id, struct pldm_msg *msg,
2779 size_t payload_length)
2780{
2781 if (msg == NULL) {
2782 return PLDM_ERROR_INVALID_DATA;
2783 }
2784
2785 if (payload_length != PLDM_GET_STATUS_REQ_BYTES) {
2786 return PLDM_ERROR_INVALID_LENGTH;
2787 }
2788
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302789 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302790 header.instance = instance_id;
2791 header.msg_type = PLDM_REQUEST;
2792 header.pldm_type = PLDM_FWUP;
2793 header.command = PLDM_GET_STATUS;
2794 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2795 if (rc) {
2796 return rc;
2797 }
2798
2799 return PLDM_SUCCESS;
2800}
2801
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302802LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302803int decode_get_status_resp(const struct pldm_msg *msg, size_t payload_length,
2804 uint8_t *completion_code, uint8_t *current_state,
2805 uint8_t *previous_state, uint8_t *aux_state,
2806 uint8_t *aux_state_status, uint8_t *progress_percent,
2807 uint8_t *reason_code,
2808 bitfield32_t *update_option_flags_enabled)
2809{
2810 if (msg == NULL || completion_code == NULL || current_state == NULL ||
2811 previous_state == NULL || aux_state == NULL ||
2812 aux_state_status == NULL || progress_percent == NULL ||
2813 reason_code == NULL || update_option_flags_enabled == NULL ||
2814 !payload_length) {
2815 return PLDM_ERROR_INVALID_DATA;
2816 }
2817
2818 *completion_code = msg->payload[0];
2819 if (*completion_code != PLDM_SUCCESS) {
2820 return PLDM_SUCCESS;
2821 }
2822
2823 if (payload_length != sizeof(struct pldm_get_status_resp)) {
2824 return PLDM_ERROR_INVALID_LENGTH;
2825 }
2826 struct pldm_get_status_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302827 (struct pldm_get_status_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302828
2829 if (!is_state_valid(response->current_state)) {
2830 return PLDM_ERROR_INVALID_DATA;
2831 }
2832 if (!is_state_valid(response->previous_state)) {
2833 return PLDM_ERROR_INVALID_DATA;
2834 }
2835 if (!is_aux_state_valid(response->aux_state)) {
2836 return PLDM_ERROR_INVALID_DATA;
2837 }
2838 if (!is_aux_state_status_valid(response->aux_state_status)) {
2839 return PLDM_ERROR_INVALID_DATA;
2840 }
2841 if (response->progress_percent > PLDM_FWUP_MAX_PROGRESS_PERCENT) {
2842 return PLDM_ERROR_INVALID_DATA;
2843 }
2844 if (!is_reason_code_valid(response->reason_code)) {
2845 return PLDM_ERROR_INVALID_DATA;
2846 }
2847
2848 if ((response->current_state == PLDM_FD_STATE_IDLE) ||
2849 (response->current_state == PLDM_FD_STATE_LEARN_COMPONENTS) ||
2850 (response->current_state == PLDM_FD_STATE_READY_XFER)) {
2851 if (response->aux_state !=
2852 PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER) {
2853 return PLDM_ERROR_INVALID_DATA;
2854 }
2855 }
2856
2857 *current_state = response->current_state;
2858 *previous_state = response->previous_state;
2859 *aux_state = response->aux_state;
2860 *aux_state_status = response->aux_state_status;
2861 *progress_percent = response->progress_percent;
2862 *reason_code = response->reason_code;
2863 update_option_flags_enabled->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302864 le32toh(response->update_option_flags_enabled.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302865
2866 return PLDM_SUCCESS;
2867}
2868
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002869LIBPLDM_ABI_TESTING
2870int encode_get_status_resp(uint8_t instance_id,
2871 const struct pldm_get_status_resp *status,
2872 struct pldm_msg *msg, size_t *payload_length)
2873{
Andrew Jefferya1896962025-03-03 21:41:25 +10302874 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002875 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002876
2877 if (status == NULL || msg == NULL || payload_length == NULL) {
2878 return -EINVAL;
2879 }
2880
2881 if (status->completion_code != PLDM_SUCCESS) {
2882 return -EINVAL;
2883 }
2884
2885 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2886 PLDM_GET_STATUS, msg);
2887 if (rc) {
2888 return -EINVAL;
2889 }
2890
2891 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2892 if (rc) {
2893 return rc;
2894 }
2895
2896 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2897 pldm_msgbuf_insert(buf, status->current_state);
2898 pldm_msgbuf_insert(buf, status->previous_state);
2899 pldm_msgbuf_insert(buf, status->aux_state);
2900 pldm_msgbuf_insert(buf, status->aux_state_status);
2901 pldm_msgbuf_insert(buf, status->progress_percent);
2902 pldm_msgbuf_insert(buf, status->reason_code);
2903 pldm_msgbuf_insert(buf, status->update_option_flags_enabled.value);
2904
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302905 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002906}
2907
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302908LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302909int encode_cancel_update_component_req(uint8_t instance_id,
2910 struct pldm_msg *msg,
2911 size_t payload_length)
2912{
2913 if (msg == NULL) {
2914 return PLDM_ERROR_INVALID_DATA;
2915 }
2916
2917 if (payload_length != PLDM_CANCEL_UPDATE_COMPONENT_REQ_BYTES) {
2918 return PLDM_ERROR_INVALID_LENGTH;
2919 }
2920
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302921 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302922 header.instance = instance_id;
2923 header.msg_type = PLDM_REQUEST;
2924 header.pldm_type = PLDM_FWUP;
2925 header.command = PLDM_CANCEL_UPDATE_COMPONENT;
2926 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2927 if (rc) {
2928 return rc;
2929 }
2930
2931 return PLDM_SUCCESS;
2932}
2933
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302934LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302935int decode_cancel_update_component_resp(const struct pldm_msg *msg,
2936 size_t payload_length,
2937 uint8_t *completion_code)
2938{
2939 if (msg == NULL || completion_code == NULL) {
2940 return PLDM_ERROR_INVALID_DATA;
2941 }
2942
2943 if (payload_length != sizeof(*completion_code)) {
2944 return PLDM_ERROR_INVALID_LENGTH;
2945 }
2946
2947 *completion_code = msg->payload[0];
2948 return PLDM_SUCCESS;
2949}
2950
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302951LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302952int encode_cancel_update_req(uint8_t instance_id, struct pldm_msg *msg,
2953 size_t payload_length)
2954{
2955 if (msg == NULL) {
2956 return PLDM_ERROR_INVALID_DATA;
2957 }
2958
2959 if (payload_length != PLDM_CANCEL_UPDATE_REQ_BYTES) {
2960 return PLDM_ERROR_INVALID_LENGTH;
2961 }
2962
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302963 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302964 header.instance = instance_id;
2965 header.msg_type = PLDM_REQUEST;
2966 header.pldm_type = PLDM_FWUP;
2967 header.command = PLDM_CANCEL_UPDATE;
2968 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2969 if (rc) {
2970 return rc;
2971 }
2972
2973 return PLDM_SUCCESS;
2974}
2975
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302976LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302977int decode_cancel_update_resp(const struct pldm_msg *msg, size_t payload_length,
2978 uint8_t *completion_code,
2979 bool8_t *non_functioning_component_indication,
2980 bitfield64_t *non_functioning_component_bitmap)
2981{
2982 if (msg == NULL || completion_code == NULL ||
2983 non_functioning_component_indication == NULL ||
2984 non_functioning_component_bitmap == NULL || !payload_length) {
2985 return PLDM_ERROR_INVALID_DATA;
2986 }
2987
2988 *completion_code = msg->payload[0];
2989 if (*completion_code != PLDM_SUCCESS) {
2990 return PLDM_SUCCESS;
2991 }
2992
2993 if (payload_length != sizeof(struct pldm_cancel_update_resp)) {
2994 return PLDM_ERROR_INVALID_LENGTH;
2995 }
2996 struct pldm_cancel_update_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302997 (struct pldm_cancel_update_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302998
2999 if (!is_non_functioning_component_indication_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303000 response->non_functioning_component_indication)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09303001 return PLDM_ERROR_INVALID_DATA;
3002 }
3003
3004 *non_functioning_component_indication =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303005 response->non_functioning_component_indication;
Andrew Jeffery9c766792022-08-10 23:12:49 +09303006
3007 if (*non_functioning_component_indication) {
3008 non_functioning_component_bitmap->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09303009 le64toh(response->non_functioning_component_bitmap);
Andrew Jeffery9c766792022-08-10 23:12:49 +09303010 }
3011
3012 return PLDM_SUCCESS;
3013}
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003014
3015LIBPLDM_ABI_TESTING
3016int encode_cancel_update_resp(uint8_t instance_id,
3017 const struct pldm_cancel_update_resp *resp_data,
3018 struct pldm_msg *msg, size_t *payload_length)
3019{
Andrew Jefferya1896962025-03-03 21:41:25 +10303020 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003021 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003022
3023 if (msg == NULL || payload_length == NULL) {
3024 return -EINVAL;
3025 }
3026
3027 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
3028 PLDM_CANCEL_UPDATE, msg);
3029 if (rc) {
3030 return -EINVAL;
3031 }
3032
3033 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
3034 if (rc) {
3035 return rc;
3036 }
3037
3038 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
3039 pldm_msgbuf_insert(buf,
3040 resp_data->non_functioning_component_indication);
3041 pldm_msgbuf_insert(buf, resp_data->non_functioning_component_bitmap);
3042
Andrew Jeffery70d21c92025-03-05 12:59:42 +10303043 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08003044}