blob: 25b29a749f19e8258060bddbb069b0e385a24766 [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 Jeffery779e9db2025-02-21 12:14:28 +1030329static int decode_pldm_package_header_info_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030330 const void *data, size_t length,
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930331 struct pldm_package_header_information *package_header_info,
332 struct variable_field *package_version_str)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930333{
334 if (data == NULL || package_header_info == NULL ||
335 package_version_str == NULL) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030336 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930337 }
338
339 if (length < sizeof(struct pldm_package_header_information)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030340 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930341 }
342
343 struct pldm_package_header_information *data_header =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930344 (struct pldm_package_header_information *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930345
346 if (!is_string_type_valid(data_header->package_version_string_type) ||
347 (data_header->package_version_string_length == 0)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030348 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930349 }
350
351 if (length < sizeof(struct pldm_package_header_information) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930352 data_header->package_version_string_length) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030353 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930354 }
355
356 if ((data_header->component_bitmap_bit_length %
357 PLDM_FWUP_COMPONENT_BITMAP_MULTIPLE) != 0) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030358 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930359 }
360
361 memcpy(package_header_info->uuid, data_header->uuid,
362 sizeof(data_header->uuid));
363 package_header_info->package_header_format_version =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930364 data_header->package_header_format_version;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930365 package_header_info->package_header_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930366 le16toh(data_header->package_header_size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930367 memcpy(package_header_info->package_release_date_time,
368 data_header->package_release_date_time,
369 sizeof(data_header->package_release_date_time));
370 package_header_info->component_bitmap_bit_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930371 le16toh(data_header->component_bitmap_bit_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930372 package_header_info->package_version_string_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930373 data_header->package_version_string_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930374 package_header_info->package_version_string_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930375 data_header->package_version_string_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930376 package_version_str->ptr =
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030377 (const uint8_t *)data +
378 sizeof(struct pldm_package_header_information);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930379 package_version_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930380 package_header_info->package_version_string_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930381
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030382 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930383}
384
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930385LIBPLDM_ABI_STABLE
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030386int decode_pldm_package_header_info(
387 const uint8_t *data, size_t length,
388 struct pldm_package_header_information *package_header_info,
389 struct variable_field *package_version_str)
390{
391 int rc;
392
393 rc = decode_pldm_package_header_info_errno(
394 data, length, package_header_info, package_version_str);
395 if (rc < 0) {
396 return pldm_xlate_errno(rc);
397 }
398
399 return PLDM_SUCCESS;
400}
401
402static int decode_firmware_device_id_record_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030403 const void *data, size_t length, uint16_t component_bitmap_bit_length,
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930404 struct pldm_firmware_device_id_record *fw_device_id_record,
405 struct variable_field *applicable_components,
406 struct variable_field *comp_image_set_version_str,
407 struct variable_field *record_descriptors,
408 struct variable_field *fw_device_pkg_data)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930409{
410 if (data == NULL || fw_device_id_record == NULL ||
411 applicable_components == NULL ||
412 comp_image_set_version_str == NULL || record_descriptors == NULL ||
413 fw_device_pkg_data == NULL) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030414 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930415 }
416
417 if (length < sizeof(struct pldm_firmware_device_id_record)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030418 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930419 }
420
421 if ((component_bitmap_bit_length %
422 PLDM_FWUP_COMPONENT_BITMAP_MULTIPLE) != 0) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030423 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930424 }
425
426 struct pldm_firmware_device_id_record *data_record =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930427 (struct pldm_firmware_device_id_record *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930428
429 if (!is_string_type_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930430 data_record->comp_image_set_version_string_type) ||
Andrew Jeffery9c766792022-08-10 23:12:49 +0930431 (data_record->comp_image_set_version_string_length == 0)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030432 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930433 }
434
435 fw_device_id_record->record_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930436 le16toh(data_record->record_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930437 fw_device_id_record->descriptor_count = data_record->descriptor_count;
438 fw_device_id_record->device_update_option_flags.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930439 le32toh(data_record->device_update_option_flags.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930440 fw_device_id_record->comp_image_set_version_string_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930441 data_record->comp_image_set_version_string_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930442 fw_device_id_record->comp_image_set_version_string_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930443 data_record->comp_image_set_version_string_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930444 fw_device_id_record->fw_device_pkg_data_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930445 le16toh(data_record->fw_device_pkg_data_length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930446
447 if (length < fw_device_id_record->record_length) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030448 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930449 }
450
451 uint16_t applicable_components_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930452 component_bitmap_bit_length /
453 PLDM_FWUP_COMPONENT_BITMAP_MULTIPLE;
Matt Johnstonc4d1c8b2024-12-18 11:16:55 +0800454 size_t calc_min_record_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930455 sizeof(struct pldm_firmware_device_id_record) +
456 applicable_components_length +
457 data_record->comp_image_set_version_string_length +
458 PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN +
459 fw_device_id_record->fw_device_pkg_data_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930460
461 if (fw_device_id_record->record_length < calc_min_record_length) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030462 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930463 }
464
465 applicable_components->ptr =
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030466 (const uint8_t *)data +
467 sizeof(struct pldm_firmware_device_id_record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930468 applicable_components->length = applicable_components_length;
469
470 comp_image_set_version_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930471 applicable_components->ptr + applicable_components->length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930472 comp_image_set_version_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930473 fw_device_id_record->comp_image_set_version_string_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930474
475 record_descriptors->ptr = comp_image_set_version_str->ptr +
476 comp_image_set_version_str->length;
477 record_descriptors->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930478 fw_device_id_record->record_length -
479 sizeof(struct pldm_firmware_device_id_record) -
480 applicable_components_length -
481 fw_device_id_record->comp_image_set_version_string_length -
482 fw_device_id_record->fw_device_pkg_data_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930483
484 if (fw_device_id_record->fw_device_pkg_data_length) {
485 fw_device_pkg_data->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930486 record_descriptors->ptr + record_descriptors->length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930487 fw_device_pkg_data->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930488 fw_device_id_record->fw_device_pkg_data_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930489 }
490
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030491 return 0;
492}
493
494LIBPLDM_ABI_STABLE
495int decode_firmware_device_id_record(
496 const uint8_t *data, size_t length,
497 uint16_t component_bitmap_bit_length,
498 struct pldm_firmware_device_id_record *fw_device_id_record,
499 struct variable_field *applicable_components,
500 struct variable_field *comp_image_set_version_str,
501 struct variable_field *record_descriptors,
502 struct variable_field *fw_device_pkg_data)
503{
504 int rc;
505
506 rc = decode_firmware_device_id_record_errno(
507 data, length, component_bitmap_bit_length, fw_device_id_record,
508 applicable_components, comp_image_set_version_str,
509 record_descriptors, fw_device_pkg_data);
510 if (rc < 0) {
511 return pldm_xlate_errno(rc);
512 }
513
Andrew Jeffery9c766792022-08-10 23:12:49 +0930514 return PLDM_SUCCESS;
515}
516
Unive Tiene5c3f142024-12-13 14:14:19 +0800517LIBPLDM_ABI_STABLE
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030518int decode_pldm_descriptor_from_iter(struct pldm_descriptor_iter *iter,
519 struct pldm_descriptor *desc)
520{
Andrew Jefferya1896962025-03-03 21:41:25 +1030521 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030522 int rc;
523
524 if (!iter || !iter->field || !desc) {
525 return -EINVAL;
526 }
527
528 rc = pldm_msgbuf_init_errno(buf, PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN,
529 iter->field->ptr, iter->field->length);
530 if (rc) {
531 return rc;
532 }
533
534 pldm_msgbuf_extract(buf, desc->descriptor_type);
535 rc = pldm_msgbuf_extract(buf, desc->descriptor_length);
536 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +1030537 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030538 }
539
540 desc->descriptor_data = NULL;
541 pldm_msgbuf_span_required(buf, desc->descriptor_length,
542 (void **)&desc->descriptor_data);
543 iter->field->ptr = NULL;
544 pldm_msgbuf_span_remaining(buf, (void **)&iter->field->ptr,
545 &iter->field->length);
546
Andrew Jeffery70d21c92025-03-05 12:59:42 +1030547 return pldm_msgbuf_complete(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +1030548}
549
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030550static int decode_descriptor_type_length_value_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030551 const void *data, size_t length, uint16_t *descriptor_type,
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030552 struct variable_field *descriptor_data)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930553{
554 uint16_t descriptor_length = 0;
555
556 if (data == NULL || descriptor_type == NULL ||
557 descriptor_data == NULL) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030558 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930559 }
560
561 if (length < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030562 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930563 }
564
565 struct pldm_descriptor_tlv *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930566 (struct pldm_descriptor_tlv *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930567
568 *descriptor_type = le16toh(entry->descriptor_type);
569 descriptor_length = le16toh(entry->descriptor_length);
570 if (*descriptor_type != PLDM_FWUP_VENDOR_DEFINED) {
571 if (descriptor_length !=
572 get_descriptor_type_length(*descriptor_type)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030573 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930574 }
575 }
576
577 if (length < (sizeof(*descriptor_type) + sizeof(descriptor_length) +
578 descriptor_length)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030579 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930580 }
581
582 descriptor_data->ptr = entry->descriptor_data;
583 descriptor_data->length = descriptor_length;
584
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030585 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930586}
587
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930588LIBPLDM_ABI_STABLE
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030589int decode_descriptor_type_length_value(const uint8_t *data, size_t length,
590 uint16_t *descriptor_type,
591 struct variable_field *descriptor_data)
592{
593 int rc;
594
595 rc = decode_descriptor_type_length_value_errno(
596 data, length, descriptor_type, descriptor_data);
597 if (rc < 0) {
598 return pldm_xlate_errno(rc);
599 }
600
601 return PLDM_SUCCESS;
602}
603
604static int decode_vendor_defined_descriptor_value_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030605 const void *data, size_t length, uint8_t *descriptor_title_str_type,
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930606 struct variable_field *descriptor_title_str,
607 struct variable_field *descriptor_data)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930608{
609 if (data == NULL || descriptor_title_str_type == NULL ||
610 descriptor_title_str == NULL || descriptor_data == NULL) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030611 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930612 }
613
614 if (length < sizeof(struct pldm_vendor_defined_descriptor_title_data)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030615 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930616 }
617
618 struct pldm_vendor_defined_descriptor_title_data *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930619 (struct pldm_vendor_defined_descriptor_title_data *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930620 if (!is_string_type_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930621 entry->vendor_defined_descriptor_title_str_type) ||
Andrew Jeffery9c766792022-08-10 23:12:49 +0930622 (entry->vendor_defined_descriptor_title_str_len == 0)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030623 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930624 }
625
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530626 // Assuming at least 1 byte of VendorDefinedDescriptorData
Andrew Jeffery9c766792022-08-10 23:12:49 +0930627 if (length < (sizeof(struct pldm_vendor_defined_descriptor_title_data) +
628 entry->vendor_defined_descriptor_title_str_len)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030629 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930630 }
631
632 *descriptor_title_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930633 entry->vendor_defined_descriptor_title_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930634 descriptor_title_str->ptr = entry->vendor_defined_descriptor_title_str;
635 descriptor_title_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930636 entry->vendor_defined_descriptor_title_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930637
638 descriptor_data->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930639 descriptor_title_str->ptr + descriptor_title_str->length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930640 descriptor_data->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930641 length -
642 sizeof(entry->vendor_defined_descriptor_title_str_type) -
643 sizeof(entry->vendor_defined_descriptor_title_str_len) -
644 descriptor_title_str->length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930645
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030646 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930647}
648
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930649LIBPLDM_ABI_STABLE
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030650int decode_vendor_defined_descriptor_value(
651 const uint8_t *data, size_t length, uint8_t *descriptor_title_str_type,
652 struct variable_field *descriptor_title_str,
653 struct variable_field *descriptor_data)
654{
655 int rc;
656
657 rc = decode_vendor_defined_descriptor_value_errno(
658 data, length, descriptor_title_str_type, descriptor_title_str,
659 descriptor_data);
660 if (rc < 0) {
661 return pldm_xlate_errno(rc);
662 }
663
664 return PLDM_SUCCESS;
665}
666
667static int decode_pldm_comp_image_info_errno(
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030668 const void *data, size_t length,
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930669 struct pldm_component_image_information *pldm_comp_image_info,
670 struct variable_field *comp_version_str)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930671{
672 if (data == NULL || pldm_comp_image_info == NULL ||
673 comp_version_str == NULL) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030674 return -EINVAL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930675 }
676
677 if (length < sizeof(struct pldm_component_image_information)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030678 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930679 }
680
681 struct pldm_component_image_information *data_header =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930682 (struct pldm_component_image_information *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930683
684 if (!is_string_type_valid(data_header->comp_version_string_type) ||
685 (data_header->comp_version_string_length == 0)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030686 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930687 }
688
689 if (length < sizeof(struct pldm_component_image_information) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930690 data_header->comp_version_string_length) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030691 return -EOVERFLOW;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930692 }
693
694 pldm_comp_image_info->comp_classification =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930695 le16toh(data_header->comp_classification);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930696 pldm_comp_image_info->comp_identifier =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930697 le16toh(data_header->comp_identifier);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930698 pldm_comp_image_info->comp_comparison_stamp =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930699 le32toh(data_header->comp_comparison_stamp);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930700 pldm_comp_image_info->comp_options.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930701 le16toh(data_header->comp_options.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930702 pldm_comp_image_info->requested_comp_activation_method.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930703 le16toh(data_header->requested_comp_activation_method.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930704 pldm_comp_image_info->comp_location_offset =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930705 le32toh(data_header->comp_location_offset);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930706 pldm_comp_image_info->comp_size = le32toh(data_header->comp_size);
707 pldm_comp_image_info->comp_version_string_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930708 data_header->comp_version_string_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930709 pldm_comp_image_info->comp_version_string_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930710 data_header->comp_version_string_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930711
712 if ((pldm_comp_image_info->comp_options.bits.bit1 == false &&
713 pldm_comp_image_info->comp_comparison_stamp !=
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930714 PLDM_FWUP_INVALID_COMPONENT_COMPARISON_TIMESTAMP)) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030715 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930716 }
717
718 if (pldm_comp_image_info->comp_location_offset == 0 ||
719 pldm_comp_image_info->comp_size == 0) {
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030720 return -EBADMSG;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930721 }
722
Andrew Jeffery0ba6aa02025-03-06 11:22:37 +1030723 comp_version_str->ptr = (const uint8_t *)data +
724 sizeof(struct pldm_component_image_information);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930725 comp_version_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930726 pldm_comp_image_info->comp_version_string_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930727
Andrew Jeffery779e9db2025-02-21 12:14:28 +1030728 return 0;
729}
730
731LIBPLDM_ABI_STABLE
732int decode_pldm_comp_image_info(
733 const uint8_t *data, size_t length,
734 struct pldm_component_image_information *pldm_comp_image_info,
735 struct variable_field *comp_version_str)
736{
737 int rc;
738
739 rc = decode_pldm_comp_image_info_errno(
740 data, length, pldm_comp_image_info, comp_version_str);
741 if (rc < 0) {
742 return pldm_xlate_errno(rc);
743 }
744
Andrew Jeffery9c766792022-08-10 23:12:49 +0930745 return PLDM_SUCCESS;
746}
747
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930748LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930749int encode_query_device_identifiers_req(uint8_t instance_id,
750 size_t payload_length,
751 struct pldm_msg *msg)
752{
753 if (msg == NULL) {
754 return PLDM_ERROR_INVALID_DATA;
755 }
756
757 if (payload_length != PLDM_QUERY_DEVICE_IDENTIFIERS_REQ_BYTES) {
758 return PLDM_ERROR_INVALID_LENGTH;
759 }
760
761 return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
762 PLDM_QUERY_DEVICE_IDENTIFIERS, msg);
763}
764
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930765LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930766int decode_query_device_identifiers_resp(const struct pldm_msg *msg,
767 size_t payload_length,
768 uint8_t *completion_code,
769 uint32_t *device_identifiers_len,
770 uint8_t *descriptor_count,
771 uint8_t **descriptor_data)
772{
773 if (msg == NULL || completion_code == NULL ||
774 device_identifiers_len == NULL || descriptor_count == NULL ||
775 descriptor_data == NULL) {
776 return PLDM_ERROR_INVALID_DATA;
777 }
778
779 *completion_code = msg->payload[0];
780 if (PLDM_SUCCESS != *completion_code) {
781 return PLDM_SUCCESS;
782 }
783
784 if (payload_length <
785 sizeof(struct pldm_query_device_identifiers_resp)) {
786 return PLDM_ERROR_INVALID_LENGTH;
787 }
788
789 struct pldm_query_device_identifiers_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930790 (struct pldm_query_device_identifiers_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930791 *device_identifiers_len = le32toh(response->device_identifiers_len);
792
793 if (*device_identifiers_len < PLDM_FWUP_DEVICE_DESCRIPTOR_MIN_LEN) {
794 return PLDM_ERROR_INVALID_LENGTH;
795 }
796
797 if (payload_length !=
798 sizeof(struct pldm_query_device_identifiers_resp) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930799 *device_identifiers_len) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930800 return PLDM_ERROR_INVALID_LENGTH;
801 }
802 *descriptor_count = response->descriptor_count;
803
804 if (*descriptor_count == 0) {
805 return PLDM_ERROR_INVALID_DATA;
806 }
807 *descriptor_data =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930808 (uint8_t *)(msg->payload +
809 sizeof(struct pldm_query_device_identifiers_resp));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930810 return PLDM_SUCCESS;
811}
812
Matt Johnstoncf9a2df2024-11-07 15:29:29 +0800813LIBPLDM_ABI_TESTING
814int encode_query_device_identifiers_resp(
815 uint8_t instance_id, uint8_t descriptor_count,
816 const struct pldm_descriptor *descriptors, struct pldm_msg *msg,
817 size_t *payload_length)
818{
Andrew Jefferya1896962025-03-03 21:41:25 +1030819 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +0800820 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +0800821
822 if (descriptors == NULL || msg == NULL || payload_length == NULL) {
823 return -EINVAL;
824 }
825
826 if (descriptor_count < 1) {
827 return -EINVAL;
828 }
829
830 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
831 PLDM_QUERY_DEVICE_IDENTIFIERS, msg);
832 if (rc) {
833 return -EINVAL;
834 }
835
836 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
837 if (rc) {
838 return rc;
839 }
840
841 /* Determine total length */
842 uint32_t device_identifiers_len = 0;
843 for (uint8_t i = 0; i < descriptor_count; i++) {
844 const struct pldm_descriptor *d = &descriptors[i];
845 device_identifiers_len +=
846 2 * sizeof(uint16_t) + d->descriptor_length;
847 }
848
849 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
850 pldm_msgbuf_insert(buf, device_identifiers_len);
851 pldm_msgbuf_insert(buf, descriptor_count);
852
853 for (uint8_t i = 0; i < descriptor_count; i++) {
854 const struct pldm_descriptor *d = &descriptors[i];
855 pldm_msgbuf_insert(buf, d->descriptor_type);
856 pldm_msgbuf_insert(buf, d->descriptor_length);
857 if (d->descriptor_data == NULL) {
Andrew Jefferya1896962025-03-03 21:41:25 +1030858 return pldm_msgbuf_discard(buf, -EINVAL);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +0800859 }
860 rc = pldm_msgbuf_insert_array(
861 buf, d->descriptor_length,
862 (const uint8_t *)d->descriptor_data,
863 d->descriptor_length);
864 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +1030865 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +0800866 }
867 }
868
Andrew Jeffery70d21c92025-03-05 12:59:42 +1030869 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +0800870}
871
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930872LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930873int encode_get_firmware_parameters_req(uint8_t instance_id,
874 size_t payload_length,
875 struct pldm_msg *msg)
876{
877 if (msg == NULL) {
878 return PLDM_ERROR_INVALID_DATA;
879 }
880
881 if (payload_length != PLDM_GET_FIRMWARE_PARAMETERS_REQ_BYTES) {
882 return PLDM_ERROR_INVALID_LENGTH;
883 }
884
885 return encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
886 PLDM_GET_FIRMWARE_PARAMETERS, msg);
887}
888
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930889LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930890int decode_get_firmware_parameters_resp(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930891 const struct pldm_msg *msg, size_t payload_length,
892 struct pldm_get_firmware_parameters_resp *resp_data,
893 struct variable_field *active_comp_image_set_ver_str,
894 struct variable_field *pending_comp_image_set_ver_str,
895 struct variable_field *comp_parameter_table)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930896{
897 if (msg == NULL || resp_data == NULL ||
898 active_comp_image_set_ver_str == NULL ||
899 pending_comp_image_set_ver_str == NULL ||
900 comp_parameter_table == NULL || !payload_length) {
901 return PLDM_ERROR_INVALID_DATA;
902 }
903
904 resp_data->completion_code = msg->payload[0];
905 if (PLDM_SUCCESS != resp_data->completion_code) {
906 return PLDM_SUCCESS;
907 }
908
909 if (payload_length < sizeof(struct pldm_get_firmware_parameters_resp)) {
910 return PLDM_ERROR_INVALID_LENGTH;
911 }
912
913 struct pldm_get_firmware_parameters_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930914 (struct pldm_get_firmware_parameters_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930915
916 if (!is_string_type_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930917 response->active_comp_image_set_ver_str_type) ||
Andrew Jeffery9c766792022-08-10 23:12:49 +0930918 (response->active_comp_image_set_ver_str_len == 0)) {
919 return PLDM_ERROR_INVALID_DATA;
920 }
921
922 if (response->pending_comp_image_set_ver_str_len == 0) {
923 if (response->pending_comp_image_set_ver_str_type !=
924 PLDM_STR_TYPE_UNKNOWN) {
925 return PLDM_ERROR_INVALID_DATA;
926 }
927 } else {
928 if (!is_string_type_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930929 response->pending_comp_image_set_ver_str_type)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930930 return PLDM_ERROR_INVALID_DATA;
931 }
932 }
933
934 size_t partial_response_length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930935 sizeof(struct pldm_get_firmware_parameters_resp) +
936 response->active_comp_image_set_ver_str_len +
937 response->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930938
939 if (payload_length < partial_response_length) {
940 return PLDM_ERROR_INVALID_LENGTH;
941 }
942
943 resp_data->capabilities_during_update.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930944 le32toh(response->capabilities_during_update.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930945 resp_data->comp_count = le16toh(response->comp_count);
946 resp_data->active_comp_image_set_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930947 response->active_comp_image_set_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930948 resp_data->active_comp_image_set_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930949 response->active_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930950 resp_data->pending_comp_image_set_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930951 response->pending_comp_image_set_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930952 resp_data->pending_comp_image_set_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930953 response->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930954
955 active_comp_image_set_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930956 msg->payload + sizeof(struct pldm_get_firmware_parameters_resp);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930957 active_comp_image_set_ver_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930958 resp_data->active_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930959
960 if (resp_data->pending_comp_image_set_ver_str_len != 0) {
961 pending_comp_image_set_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930962 msg->payload +
963 sizeof(struct pldm_get_firmware_parameters_resp) +
964 resp_data->active_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930965 pending_comp_image_set_ver_str->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930966 resp_data->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930967 } else {
968 pending_comp_image_set_ver_str->ptr = NULL;
969 pending_comp_image_set_ver_str->length = 0;
970 }
971
972 if (payload_length > partial_response_length && resp_data->comp_count) {
973 comp_parameter_table->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930974 msg->payload +
975 sizeof(struct pldm_get_firmware_parameters_resp) +
976 resp_data->active_comp_image_set_ver_str_len +
977 resp_data->pending_comp_image_set_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930978 comp_parameter_table->length =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930979 payload_length - partial_response_length;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930980 } else {
981 comp_parameter_table->ptr = NULL;
982 comp_parameter_table->length = 0;
983 }
984
985 return PLDM_SUCCESS;
986}
987
Matt Johnstoncf9a2df2024-11-07 15:29:29 +0800988LIBPLDM_ABI_TESTING
989int encode_get_firmware_parameters_resp(
990 uint8_t instance_id,
991 const struct pldm_get_firmware_parameters_resp_full *resp_data,
992 struct pldm_msg *msg, size_t *payload_length)
993{
Andrew Jefferya1896962025-03-03 21:41:25 +1030994 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +0800995 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +0800996
997 if (resp_data == NULL || msg == NULL || payload_length == NULL) {
998 return -EINVAL;
999 }
1000
1001 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
1002 PLDM_GET_FIRMWARE_PARAMETERS, msg);
1003 if (rc) {
1004 return -EINVAL;
1005 }
1006
1007 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
1008 if (rc) {
1009 return rc;
1010 }
1011
1012 pldm_msgbuf_insert(buf, resp_data->completion_code);
1013 pldm_msgbuf_insert(buf, resp_data->capabilities_during_update.value);
1014 pldm_msgbuf_insert(buf, resp_data->comp_count);
1015 pldm_msgbuf_insert(buf,
1016 resp_data->active_comp_image_set_ver_str.str_type);
1017 pldm_msgbuf_insert(buf,
1018 resp_data->active_comp_image_set_ver_str.str_len);
1019 pldm_msgbuf_insert(buf,
1020 resp_data->pending_comp_image_set_ver_str.str_type);
1021 pldm_msgbuf_insert(buf,
1022 resp_data->pending_comp_image_set_ver_str.str_len);
1023 /* String data appended */
1024 rc = pldm_msgbuf_insert_array(
1025 buf, resp_data->active_comp_image_set_ver_str.str_len,
1026 resp_data->active_comp_image_set_ver_str.str_data,
1027 resp_data->active_comp_image_set_ver_str.str_len);
1028 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301029 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001030 }
1031 rc = pldm_msgbuf_insert_array(
1032 buf, resp_data->pending_comp_image_set_ver_str.str_len,
1033 resp_data->pending_comp_image_set_ver_str.str_data,
1034 resp_data->pending_comp_image_set_ver_str.str_len);
1035 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301036 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001037 }
1038
1039 /* Further calls to encode_get_firmware_parameters_resp_comp_entry
1040 * will populate the remainder */
1041
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301042 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001043}
1044
1045LIBPLDM_ABI_TESTING
1046int encode_get_firmware_parameters_resp_comp_entry(
1047 const struct pldm_component_parameter_entry_full *comp,
1048 uint8_t *payload, size_t *payload_length)
1049{
Andrew Jefferya1896962025-03-03 21:41:25 +10301050 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001051 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001052
1053 if (comp == NULL || payload == NULL || payload_length == NULL) {
1054 return -EINVAL;
1055 }
1056
1057 rc = pldm_msgbuf_init_errno(buf, 0, payload, *payload_length);
1058 if (rc) {
1059 return rc;
1060 }
1061
1062 pldm_msgbuf_insert(buf, comp->comp_classification);
1063 pldm_msgbuf_insert(buf, comp->comp_identifier);
1064 pldm_msgbuf_insert(buf, comp->comp_classification_index);
1065
1066 pldm_msgbuf_insert(buf, comp->active_ver.comparison_stamp);
1067 pldm_msgbuf_insert(buf, (uint8_t)comp->active_ver.str.str_type);
1068 pldm_msgbuf_insert(buf, comp->active_ver.str.str_len);
1069 rc = pldm_msgbuf_insert_array(buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1070 comp->active_ver.date,
1071 PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN);
1072 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301073 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001074 }
1075
1076 pldm_msgbuf_insert(buf, comp->pending_ver.comparison_stamp);
1077 pldm_msgbuf_insert(buf, (uint8_t)comp->pending_ver.str.str_type);
1078 pldm_msgbuf_insert(buf, comp->pending_ver.str.str_len);
1079 rc = pldm_msgbuf_insert_array(buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1080 comp->pending_ver.date,
1081 PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN);
1082 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301083 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001084 }
1085
1086 pldm_msgbuf_insert(buf, comp->comp_activation_methods.value);
1087 pldm_msgbuf_insert(buf, comp->capabilities_during_update.value);
1088
1089 rc = pldm_msgbuf_insert_array(buf, comp->active_ver.str.str_len,
1090 comp->active_ver.str.str_data,
1091 comp->active_ver.str.str_len);
1092 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301093 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001094 }
1095 rc = pldm_msgbuf_insert_array(buf, comp->pending_ver.str.str_len,
1096 comp->pending_ver.str.str_data,
1097 comp->pending_ver.str.str_len);
1098 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301099 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001100 }
1101
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301102 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001103}
1104
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301105LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301106int decode_get_firmware_parameters_resp_comp_entry(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301107 const uint8_t *data, size_t length,
1108 struct pldm_component_parameter_entry *component_data,
1109 struct variable_field *active_comp_ver_str,
1110 struct variable_field *pending_comp_ver_str)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301111{
1112 if (data == NULL || component_data == NULL ||
1113 active_comp_ver_str == NULL || pending_comp_ver_str == NULL) {
1114 return PLDM_ERROR_INVALID_DATA;
1115 }
1116
1117 if (length < sizeof(struct pldm_component_parameter_entry)) {
1118 return PLDM_ERROR_INVALID_LENGTH;
1119 }
1120
1121 struct pldm_component_parameter_entry *entry =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301122 (struct pldm_component_parameter_entry *)(data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301123
1124 size_t entry_length = sizeof(struct pldm_component_parameter_entry) +
1125 entry->active_comp_ver_str_len +
1126 entry->pending_comp_ver_str_len;
1127
1128 if (length < entry_length) {
1129 return PLDM_ERROR_INVALID_LENGTH;
1130 }
1131
1132 component_data->comp_classification =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301133 le16toh(entry->comp_classification);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301134 component_data->comp_identifier = le16toh(entry->comp_identifier);
1135 component_data->comp_classification_index =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301136 entry->comp_classification_index;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301137 component_data->active_comp_comparison_stamp =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301138 le32toh(entry->active_comp_comparison_stamp);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301139 component_data->active_comp_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301140 entry->active_comp_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301141 component_data->active_comp_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301142 entry->active_comp_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301143 memcpy(component_data->active_comp_release_date,
1144 entry->active_comp_release_date,
1145 sizeof(entry->active_comp_release_date));
1146 component_data->pending_comp_comparison_stamp =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301147 le32toh(entry->pending_comp_comparison_stamp);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301148 component_data->pending_comp_ver_str_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301149 entry->pending_comp_ver_str_type;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301150 component_data->pending_comp_ver_str_len =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301151 entry->pending_comp_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301152 memcpy(component_data->pending_comp_release_date,
1153 entry->pending_comp_release_date,
1154 sizeof(entry->pending_comp_release_date));
1155 component_data->comp_activation_methods.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301156 le16toh(entry->comp_activation_methods.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301157 component_data->capabilities_during_update.value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301158 le32toh(entry->capabilities_during_update.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301159
1160 if (entry->active_comp_ver_str_len != 0) {
1161 active_comp_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301162 data + sizeof(struct pldm_component_parameter_entry);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301163 active_comp_ver_str->length = entry->active_comp_ver_str_len;
1164 } else {
1165 active_comp_ver_str->ptr = NULL;
1166 active_comp_ver_str->length = 0;
1167 }
1168
1169 if (entry->pending_comp_ver_str_len != 0) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301170 pending_comp_ver_str->ptr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301171 data + sizeof(struct pldm_component_parameter_entry) +
1172 entry->active_comp_ver_str_len;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301173 pending_comp_ver_str->length = entry->pending_comp_ver_str_len;
1174 } else {
1175 pending_comp_ver_str->ptr = NULL;
1176 pending_comp_ver_str->length = 0;
1177 }
1178 return PLDM_SUCCESS;
1179}
1180
Unive Tiene5c3f142024-12-13 14:14:19 +08001181LIBPLDM_ABI_STABLE
Chris Wang4c1f2c72024-03-21 17:09:44 +08001182int encode_query_downstream_devices_req(uint8_t instance_id,
1183 struct pldm_msg *msg)
1184{
1185 if (msg == NULL) {
Unive Tien71e935c2024-11-25 17:21:43 +08001186 return -EINVAL;
Chris Wang4c1f2c72024-03-21 17:09:44 +08001187 }
1188
Unive Tien71e935c2024-11-25 17:21:43 +08001189 return encode_pldm_header_only_errno(PLDM_REQUEST, instance_id,
1190 PLDM_FWUP,
1191 PLDM_QUERY_DOWNSTREAM_DEVICES,
1192 msg);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001193}
1194
Unive Tiene5c3f142024-12-13 14:14:19 +08001195LIBPLDM_ABI_STABLE
Chris Wang4c1f2c72024-03-21 17:09:44 +08001196int decode_query_downstream_devices_resp(
1197 const struct pldm_msg *msg, size_t payload_length,
1198 struct pldm_query_downstream_devices_resp *resp_data)
1199{
Andrew Jefferya1896962025-03-03 21:41:25 +10301200 PLDM_MSGBUF_DEFINE_P(buf);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001201 int rc;
1202
1203 if (msg == NULL || resp_data == NULL || !payload_length) {
Unive Tien71e935c2024-11-25 17:21:43 +08001204 return -EINVAL;
Chris Wang4c1f2c72024-03-21 17:09:44 +08001205 }
1206
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301207 rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1208 msg->payload, payload_length);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001209 if (rc) {
1210 return rc;
1211 }
1212
1213 rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1214 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301215 return pldm_msgbuf_discard(buf, rc);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001216 }
1217 if (PLDM_SUCCESS != resp_data->completion_code) {
1218 // Return the CC directly without decoding the rest of the payload
Andrew Jefferya1896962025-03-03 21:41:25 +10301219 return pldm_msgbuf_complete(buf);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001220 }
1221
1222 if (payload_length < PLDM_QUERY_DOWNSTREAM_DEVICES_RESP_BYTES) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301223 return pldm_msgbuf_discard(buf, -EBADMSG);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001224 }
1225
1226 rc = pldm_msgbuf_extract(buf,
1227 resp_data->downstream_device_update_supported);
1228 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301229 return pldm_msgbuf_discard(buf, rc);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001230 }
1231
1232 if (!is_downstream_device_update_support_valid(
1233 resp_data->downstream_device_update_supported)) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301234 return pldm_msgbuf_discard(buf, -EINVAL);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001235 }
1236
1237 pldm_msgbuf_extract(buf, resp_data->number_of_downstream_devices);
1238 pldm_msgbuf_extract(buf, resp_data->max_number_of_downstream_devices);
1239 pldm_msgbuf_extract(buf, resp_data->capabilities.value);
1240
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301241 return pldm_msgbuf_complete_consumed(buf);
Chris Wang4c1f2c72024-03-21 17:09:44 +08001242}
1243
Unive Tiene5c3f142024-12-13 14:14:19 +08001244LIBPLDM_ABI_STABLE
Chris Wang458475a2024-03-26 17:59:19 +08001245int encode_query_downstream_identifiers_req(
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001246 uint8_t instance_id,
1247 const struct pldm_query_downstream_identifiers_req *params_req,
1248 struct pldm_msg *msg, size_t payload_length)
Chris Wang458475a2024-03-26 17:59:19 +08001249{
Andrew Jefferya1896962025-03-03 21:41:25 +10301250 PLDM_MSGBUF_DEFINE_P(buf);
Chris Wang458475a2024-03-26 17:59:19 +08001251 int rc;
1252
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001253 if (!msg || !params_req) {
Unive Tien71e935c2024-11-25 17:21:43 +08001254 return -EINVAL;
Chris Wang458475a2024-03-26 17:59:19 +08001255 }
1256
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001257 if (!is_transfer_operation_flag_valid(
1258 (enum transfer_op_flag)
1259 params_req->transfer_operation_flag)) {
Unive Tien71e935c2024-11-25 17:21:43 +08001260 return -EINVAL;
Chris Wang458475a2024-03-26 17:59:19 +08001261 }
1262
1263 struct pldm_header_info header = { 0 };
1264 header.instance = instance_id;
1265 header.msg_type = PLDM_REQUEST;
1266 header.pldm_type = PLDM_FWUP;
1267 header.command = PLDM_QUERY_DOWNSTREAM_IDENTIFIERS;
Unive Tien71e935c2024-11-25 17:21:43 +08001268 rc = pack_pldm_header_errno(&header, &(msg->hdr));
Chris Wang458475a2024-03-26 17:59:19 +08001269 if (rc) {
1270 return rc;
1271 }
1272
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301273 rc = pldm_msgbuf_init_errno(buf,
1274 PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_REQ_BYTES,
1275 msg->payload, payload_length);
Chris Wang458475a2024-03-26 17:59:19 +08001276 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001277 return rc;
Chris Wang458475a2024-03-26 17:59:19 +08001278 }
1279
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001280 pldm_msgbuf_insert(buf, params_req->data_transfer_handle);
Chris Wang458475a2024-03-26 17:59:19 +08001281 // Data correctness has been verified, cast it to 1-byte data directly.
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001282 pldm_msgbuf_insert(buf, params_req->transfer_operation_flag);
Chris Wang458475a2024-03-26 17:59:19 +08001283
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301284 return pldm_msgbuf_complete(buf);
Chris Wang458475a2024-03-26 17:59:19 +08001285}
1286
Unive Tiene5c3f142024-12-13 14:14:19 +08001287LIBPLDM_ABI_STABLE
Chris Wang458475a2024-03-26 17:59:19 +08001288int decode_query_downstream_identifiers_resp(
1289 const struct pldm_msg *msg, size_t payload_length,
1290 struct pldm_query_downstream_identifiers_resp *resp_data,
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301291 struct pldm_downstream_device_iter *iter)
Chris Wang458475a2024-03-26 17:59:19 +08001292{
Andrew Jefferya1896962025-03-03 21:41:25 +10301293 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301294 void *remaining = NULL;
Unive Tien71e935c2024-11-25 17:21:43 +08001295 int rc = 0;
Chris Wang458475a2024-03-26 17:59:19 +08001296
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301297 if (msg == NULL || resp_data == NULL || iter == NULL ||
Chris Wang458475a2024-03-26 17:59:19 +08001298 !payload_length) {
Unive Tien71e935c2024-11-25 17:21:43 +08001299 return -EINVAL;
Chris Wang458475a2024-03-26 17:59:19 +08001300 }
1301
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301302 rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1303 msg->payload, payload_length);
Chris Wang458475a2024-03-26 17:59:19 +08001304 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001305 return rc;
Chris Wang458475a2024-03-26 17:59:19 +08001306 }
1307
1308 rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1309 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301310 return pldm_msgbuf_discard(buf, rc);
Chris Wang458475a2024-03-26 17:59:19 +08001311 }
1312 if (PLDM_SUCCESS != resp_data->completion_code) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301313 return pldm_msgbuf_complete(buf);
Chris Wang458475a2024-03-26 17:59:19 +08001314 }
1315
1316 if (payload_length < PLDM_QUERY_DOWNSTREAM_IDENTIFIERS_RESP_MIN_LEN) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301317 return pldm_msgbuf_discard(buf, -EBADMSG);
Chris Wang458475a2024-03-26 17:59:19 +08001318 }
1319
1320 pldm_msgbuf_extract(buf, resp_data->next_data_transfer_handle);
1321 pldm_msgbuf_extract(buf, resp_data->transfer_flag);
1322
1323 rc = pldm_msgbuf_extract(buf, resp_data->downstream_devices_length);
1324 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301325 return pldm_msgbuf_discard(buf, rc);
Chris Wang458475a2024-03-26 17:59:19 +08001326 }
1327
1328 pldm_msgbuf_extract(buf, resp_data->number_of_downstream_devices);
Andrew Jefferya1896962025-03-03 21:41:25 +10301329 pldm_msgbuf_span_required(buf, resp_data->downstream_devices_length,
1330 &remaining);
Chris Wang458475a2024-03-26 17:59:19 +08001331
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301332 rc = pldm_msgbuf_complete(buf);
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301333 if (rc) {
Unive Tien71e935c2024-11-25 17:21:43 +08001334 return rc;
Andrew Jeffery830c1eb2024-10-04 10:48:10 +09301335 }
1336
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301337 iter->field.ptr = remaining;
1338 iter->field.length = resp_data->downstream_devices_length;
1339 iter->devs = resp_data->number_of_downstream_devices;
1340
Unive Tien71e935c2024-11-25 17:21:43 +08001341 return 0;
Chris Wang458475a2024-03-26 17:59:19 +08001342}
1343
Unive Tiene5c3f142024-12-13 14:14:19 +08001344LIBPLDM_ABI_STABLE
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301345int decode_pldm_downstream_device_from_iter(
1346 struct pldm_downstream_device_iter *iter,
1347 struct pldm_downstream_device *dev)
1348{
Andrew Jefferya1896962025-03-03 21:41:25 +10301349 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301350 int rc;
1351
Andrew Jefferya1896962025-03-03 21:41:25 +10301352 if (!iter || !iter->field.ptr || !dev) {
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301353 return -EINVAL;
1354 }
1355
1356 rc = pldm_msgbuf_init_errno(buf, 3, iter->field.ptr,
1357 iter->field.length);
1358 if (rc) {
1359 return rc;
1360 }
1361
1362 pldm_msgbuf_extract(buf, dev->downstream_device_index);
1363 pldm_msgbuf_extract(buf, dev->downstream_descriptor_count);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301364 pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
1365 &iter->field.length);
1366
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301367 return pldm_msgbuf_complete(buf);
Andrew Jeffery3a2c6582024-11-07 16:30:36 +10301368}
1369
Unive Tiene5c3f142024-12-13 14:14:19 +08001370LIBPLDM_ABI_STABLE
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301371int encode_get_downstream_firmware_parameters_req(
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001372 uint8_t instance_id,
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301373 const struct pldm_get_downstream_firmware_parameters_req *params_req,
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001374 struct pldm_msg *msg, size_t payload_length)
Chris Wangb6ef35b2024-07-03 09:35:42 +08001375{
Andrew Jefferya1896962025-03-03 21:41:25 +10301376 PLDM_MSGBUF_DEFINE_P(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001377 int rc;
1378
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001379 if (!msg || !params_req) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001380 return -EINVAL;
1381 }
1382
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001383 if (!is_transfer_operation_flag_valid(
1384 (enum transfer_op_flag)
1385 params_req->transfer_operation_flag)) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001386 return -EBADMSG;
1387 }
1388
1389 struct pldm_header_info header = { 0 };
1390 header.instance = instance_id;
1391 header.msg_type = PLDM_REQUEST;
1392 header.pldm_type = PLDM_FWUP;
1393 header.command = PLDM_QUERY_DOWNSTREAM_FIRMWARE_PARAMETERS;
1394 rc = pack_pldm_header_errno(&header, &msg->hdr);
1395 if (rc < 0) {
1396 return rc;
1397 }
1398
Andrew Jeffery53b08672025-03-04 12:26:18 +10301399 rc = pldm_msgbuf_init_errno(
1400 buf, PLDM_GET_DOWNSTREAM_FIRMWARE_PARAMETERS_REQ_BYTES,
1401 msg->payload, payload_length);
1402 if (rc < 0) {
1403 return rc;
1404 }
1405
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001406 pldm_msgbuf_insert(buf, params_req->data_transfer_handle);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001407 // Data correctness has been verified, cast it to 1-byte data directly.
Unive Tiend2f8a7e2024-11-27 10:59:34 +08001408 pldm_msgbuf_insert(buf, params_req->transfer_operation_flag);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001409
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301410 return pldm_msgbuf_complete(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001411}
1412
Unive Tiene5c3f142024-12-13 14:14:19 +08001413LIBPLDM_ABI_STABLE
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301414int decode_get_downstream_firmware_parameters_resp(
Chris Wangb6ef35b2024-07-03 09:35:42 +08001415 const struct pldm_msg *msg, size_t payload_length,
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301416 struct pldm_get_downstream_firmware_parameters_resp *resp_data,
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301417 struct pldm_downstream_device_parameters_iter *iter)
Chris Wangb6ef35b2024-07-03 09:35:42 +08001418{
Andrew Jefferya1896962025-03-03 21:41:25 +10301419 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301420 void *remaining = NULL;
1421 size_t length;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001422 int rc;
1423
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301424 if (msg == NULL || resp_data == NULL || iter == NULL) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001425 return -EINVAL;
1426 }
1427
1428 rc = pldm_msgbuf_init_errno(buf, PLDM_OPTIONAL_COMMAND_RESP_MIN_LEN,
1429 msg->payload, payload_length);
1430 if (rc < 0) {
1431 return rc;
1432 }
1433
1434 rc = pldm_msgbuf_extract(buf, resp_data->completion_code);
1435 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301436 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001437 }
1438 if (PLDM_SUCCESS != resp_data->completion_code) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301439 return pldm_msgbuf_complete(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001440 }
1441
Andrew Jeffery6a97b792024-12-09 13:46:51 +10301442 if (payload_length <
1443 PLDM_GET_DOWNSTREAM_FIRMWARE_PARAMETERS_RESP_MIN_LEN) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301444 return pldm_msgbuf_discard(buf, -EBADMSG);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001445 }
1446
1447 pldm_msgbuf_extract(buf, resp_data->next_data_transfer_handle);
1448 pldm_msgbuf_extract(buf, resp_data->transfer_flag);
1449 pldm_msgbuf_extract(buf,
1450 resp_data->fdp_capabilities_during_update.value);
1451 pldm_msgbuf_extract(buf, resp_data->downstream_device_count);
1452
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301453 rc = pldm_msgbuf_span_remaining(buf, &remaining, &length);
1454 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301455 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301456 }
1457
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301458 rc = pldm_msgbuf_complete(buf);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301459 if (rc) {
1460 return rc;
1461 }
1462
1463 iter->field.ptr = remaining;
1464 iter->field.length = length;
1465 iter->entries = resp_data->downstream_device_count;
1466
1467 return 0;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001468}
1469
Unive Tiene5c3f142024-12-13 14:14:19 +08001470LIBPLDM_ABI_STABLE
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301471int decode_pldm_downstream_device_parameters_entry_from_iter(
1472 struct pldm_downstream_device_parameters_iter *iter,
1473 struct pldm_downstream_device_parameters_entry *entry)
Chris Wangb6ef35b2024-07-03 09:35:42 +08001474{
Andrew Jefferya1896962025-03-03 21:41:25 +10301475 PLDM_MSGBUF_DEFINE_P(buf);
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301476 void *comp_ver_str;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001477 size_t remaining;
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301478 void *cursor;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001479 int rc;
1480
Andrew Jefferya1896962025-03-03 21:41:25 +10301481 if (iter == NULL || iter->field.ptr == NULL || entry == NULL) {
Chris Wangb6ef35b2024-07-03 09:35:42 +08001482 return -EINVAL;
1483 }
1484
1485 rc = pldm_msgbuf_init_errno(
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301486 buf, PLDM_DOWNSTREAM_DEVICE_PARAMETERS_ENTRY_MIN_LEN,
1487 iter->field.ptr, iter->field.length);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001488 if (rc < 0) {
1489 return rc;
1490 }
1491
1492 pldm_msgbuf_extract(buf, entry->downstream_device_index);
1493 pldm_msgbuf_extract(buf, entry->active_comp_comparison_stamp);
1494 pldm_msgbuf_extract(buf, entry->active_comp_ver_str_type);
1495 rc = pldm_msgbuf_extract(buf, entry->active_comp_ver_str_len);
1496 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301497 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001498 }
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001499 rc = pldm_msgbuf_extract_array(buf,
1500 PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1501 entry->active_comp_release_date,
1502 sizeof(entry->active_comp_release_date));
1503 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301504 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001505 }
1506
Chris Wangb6ef35b2024-07-03 09:35:42 +08001507 // Fill the last byte with NULL character
1508 entry->active_comp_release_date[PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN] =
1509 '\0';
1510
1511 pldm_msgbuf_extract(buf, entry->pending_comp_comparison_stamp);
1512 pldm_msgbuf_extract(buf, entry->pending_comp_ver_str_type);
1513 rc = pldm_msgbuf_extract(buf, entry->pending_comp_ver_str_len);
1514 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301515 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001516 }
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001517
1518 rc = pldm_msgbuf_extract_array(
1519 buf, PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN,
1520 entry->pending_comp_release_date,
1521 sizeof(entry->pending_comp_release_date));
1522 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301523 return pldm_msgbuf_discard(buf, rc);
Andrew Jeffery0a1be3c2024-08-11 08:34:10 +00001524 }
1525
Chris Wangb6ef35b2024-07-03 09:35:42 +08001526 // Fill the last byte with NULL character
1527 entry->pending_comp_release_date[PLDM_FWUP_COMPONENT_RELEASE_DATA_LEN] =
1528 '\0';
1529
1530 pldm_msgbuf_extract(buf, entry->comp_activation_methods.value);
1531 pldm_msgbuf_extract(buf, entry->capabilities_during_update.value);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001532
Andrew Jefferya1896962025-03-03 21:41:25 +10301533 rc = pldm_msgbuf_span_required(buf, entry->active_comp_ver_str_len,
1534 &comp_ver_str);
1535 if (rc < 0) {
1536 return pldm_msgbuf_discard(buf, rc);
1537 }
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301538 entry->active_comp_ver_str = comp_ver_str;
1539
Andrew Jefferya1896962025-03-03 21:41:25 +10301540 rc = pldm_msgbuf_span_required(buf, entry->pending_comp_ver_str_len,
1541 &comp_ver_str);
1542 if (rc < 0) {
1543 return pldm_msgbuf_discard(buf, rc);
1544 }
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301545 entry->pending_comp_ver_str = comp_ver_str;
1546
Chris Wangb6ef35b2024-07-03 09:35:42 +08001547 rc = pldm_msgbuf_span_remaining(buf, &cursor, &remaining);
1548 if (rc < 0) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301549 return pldm_msgbuf_discard(buf, rc);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001550 }
1551
Andrew Jeffery5a5129b2024-12-04 16:12:40 +10301552 iter->field.ptr = cursor;
1553 iter->field.length = remaining;
Chris Wangb6ef35b2024-07-03 09:35:42 +08001554
Andrew Jefferya1896962025-03-03 21:41:25 +10301555 return pldm_msgbuf_complete(buf);
Chris Wangb6ef35b2024-07-03 09:35:42 +08001556}
1557
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301558LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301559int encode_request_update_req(uint8_t instance_id, uint32_t max_transfer_size,
1560 uint16_t num_of_comp,
1561 uint8_t max_outstanding_transfer_req,
1562 uint16_t pkg_data_len,
1563 uint8_t comp_image_set_ver_str_type,
1564 uint8_t comp_image_set_ver_str_len,
1565 const struct variable_field *comp_img_set_ver_str,
1566 struct pldm_msg *msg, size_t payload_length)
1567{
1568 if (comp_img_set_ver_str == NULL || comp_img_set_ver_str->ptr == NULL ||
1569 msg == NULL) {
1570 return PLDM_ERROR_INVALID_DATA;
1571 }
1572
1573 if (payload_length != sizeof(struct pldm_request_update_req) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301574 comp_img_set_ver_str->length) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301575 return PLDM_ERROR_INVALID_LENGTH;
1576 }
1577
1578 if ((comp_image_set_ver_str_len == 0) ||
1579 (comp_image_set_ver_str_len != comp_img_set_ver_str->length)) {
1580 return PLDM_ERROR_INVALID_DATA;
1581 }
1582
1583 if ((max_transfer_size < PLDM_FWUP_BASELINE_TRANSFER_SIZE) ||
1584 (max_outstanding_transfer_req < PLDM_FWUP_MIN_OUTSTANDING_REQ)) {
1585 return PLDM_ERROR_INVALID_DATA;
1586 }
1587
1588 if (!is_string_type_valid(comp_image_set_ver_str_type)) {
1589 return PLDM_ERROR_INVALID_DATA;
1590 }
1591
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301592 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09301593 header.instance = instance_id;
1594 header.msg_type = PLDM_REQUEST;
1595 header.pldm_type = PLDM_FWUP;
1596 header.command = PLDM_REQUEST_UPDATE;
1597 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1598 if (rc) {
1599 return rc;
1600 }
1601
1602 struct pldm_request_update_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301603 (struct pldm_request_update_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301604
1605 request->max_transfer_size = htole32(max_transfer_size);
1606 request->num_of_comp = htole16(num_of_comp);
1607 request->max_outstanding_transfer_req = max_outstanding_transfer_req;
1608 request->pkg_data_len = htole16(pkg_data_len);
1609 request->comp_image_set_ver_str_type = comp_image_set_ver_str_type;
1610 request->comp_image_set_ver_str_len = comp_image_set_ver_str_len;
1611
1612 memcpy(msg->payload + sizeof(struct pldm_request_update_req),
1613 comp_img_set_ver_str->ptr, comp_img_set_ver_str->length);
1614
1615 return PLDM_SUCCESS;
1616}
1617
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001618LIBPLDM_ABI_TESTING
1619int decode_request_update_req(const struct pldm_msg *msg, size_t payload_length,
1620 struct pldm_request_update_req_full *req)
1621{
1622 int rc;
1623 uint8_t t;
Andrew Jefferya1896962025-03-03 21:41:25 +10301624 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001625
1626 if (msg == NULL || req == NULL) {
1627 return -EINVAL;
1628 }
1629
1630 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
1631 if (rc) {
1632 return rc;
1633 }
1634
1635 pldm_msgbuf_extract(buf, req->max_transfer_size);
1636 pldm_msgbuf_extract(buf, req->num_of_comp);
1637 pldm_msgbuf_extract(buf, req->max_outstanding_transfer_req);
1638 pldm_msgbuf_extract(buf, req->pkg_data_len);
1639 rc = pldm_msgbuf_extract(buf, t);
1640 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301641 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001642 }
1643 if (t > PLDM_STR_TYPE_UTF_16BE) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301644 return pldm_msgbuf_discard(buf, -EBADMSG);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001645 }
1646 req->image_set_ver.str_type = (enum pldm_firmware_update_string_type)t;
1647 pldm_msgbuf_extract(buf, req->image_set_ver.str_len);
1648 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301649 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001650 }
1651
1652 rc = pldm_msgbuf_extract_array(buf, req->image_set_ver.str_len,
1653 req->image_set_ver.str_data,
1654 PLDM_FIRMWARE_MAX_STRING);
1655 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301656 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001657 }
1658
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301659 return pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001660}
1661
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301662LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301663int decode_request_update_resp(const struct pldm_msg *msg,
1664 size_t payload_length, uint8_t *completion_code,
1665 uint16_t *fd_meta_data_len,
1666 uint8_t *fd_will_send_pkg_data)
1667{
1668 if (msg == NULL || completion_code == NULL ||
1669 fd_meta_data_len == NULL || fd_will_send_pkg_data == NULL ||
1670 !payload_length) {
1671 return PLDM_ERROR_INVALID_DATA;
1672 }
1673
1674 *completion_code = msg->payload[0];
1675 if (*completion_code != PLDM_SUCCESS) {
1676 return PLDM_SUCCESS;
1677 }
1678
1679 if (payload_length != sizeof(struct pldm_request_update_resp)) {
1680 return PLDM_ERROR_INVALID_LENGTH;
1681 }
1682
1683 struct pldm_request_update_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301684 (struct pldm_request_update_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301685
1686 *fd_meta_data_len = le16toh(response->fd_meta_data_len);
1687 *fd_will_send_pkg_data = response->fd_will_send_pkg_data;
1688
1689 return PLDM_SUCCESS;
1690}
1691
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001692LIBPLDM_ABI_TESTING
1693int encode_request_update_resp(uint8_t instance_id,
1694 const struct pldm_request_update_resp *resp_data,
1695 struct pldm_msg *msg, size_t *payload_length)
1696{
Andrew Jefferya1896962025-03-03 21:41:25 +10301697 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001698 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001699
1700 if (msg == NULL || payload_length == NULL) {
1701 return -EINVAL;
1702 }
1703
1704 struct pldm_header_info header = {
1705 .instance = instance_id,
1706 .msg_type = PLDM_RESPONSE,
1707 .pldm_type = PLDM_FWUP,
1708 .command = PLDM_REQUEST_UPDATE,
1709 };
1710 rc = pack_pldm_header(&header, &(msg->hdr));
1711 if (rc) {
1712 return -EINVAL;
1713 }
1714
1715 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
1716 if (rc) {
1717 return rc;
1718 }
1719
1720 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
1721 pldm_msgbuf_insert(buf, resp_data->fd_meta_data_len);
1722 pldm_msgbuf_insert(buf, resp_data->fd_will_send_pkg_data);
1723
1724 /* TODO: DSP0267 1.3.0 adds GetPackageDataMaximumTransferSize */
1725
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301726 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001727}
1728
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301729LIBPLDM_ABI_STABLE
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301730int encode_pass_component_table_req(uint8_t instance_id, uint8_t transfer_flag,
1731 uint16_t comp_classification,
1732 uint16_t comp_identifier,
1733 uint8_t comp_classification_index,
1734 uint32_t comp_comparison_stamp,
1735 uint8_t comp_ver_str_type,
1736 uint8_t comp_ver_str_len,
1737 const struct variable_field *comp_ver_str,
1738 struct pldm_msg *msg, size_t payload_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301739{
1740 if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) {
1741 return PLDM_ERROR_INVALID_DATA;
1742 }
1743
1744 if (payload_length != sizeof(struct pldm_pass_component_table_req) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301745 comp_ver_str->length) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301746 return PLDM_ERROR_INVALID_LENGTH;
1747 }
1748
1749 if ((comp_ver_str_len == 0) ||
1750 (comp_ver_str_len != comp_ver_str->length)) {
1751 return PLDM_ERROR_INVALID_DATA;
1752 }
1753
1754 if (!is_transfer_flag_valid(transfer_flag)) {
1755 return PLDM_INVALID_TRANSFER_OPERATION_FLAG;
1756 }
1757
1758 if (!is_string_type_valid(comp_ver_str_type)) {
1759 return PLDM_ERROR_INVALID_DATA;
1760 }
1761
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301762 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09301763 header.instance = instance_id;
1764 header.msg_type = PLDM_REQUEST;
1765 header.pldm_type = PLDM_FWUP;
1766 header.command = PLDM_PASS_COMPONENT_TABLE;
1767 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1768 if (rc) {
1769 return rc;
1770 }
1771
1772 struct pldm_pass_component_table_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301773 (struct pldm_pass_component_table_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301774
1775 request->transfer_flag = transfer_flag;
1776 request->comp_classification = htole16(comp_classification);
1777 request->comp_identifier = htole16(comp_identifier);
1778 request->comp_classification_index = comp_classification_index;
1779 request->comp_comparison_stamp = htole32(comp_comparison_stamp);
1780 request->comp_ver_str_type = comp_ver_str_type;
1781 request->comp_ver_str_len = comp_ver_str_len;
1782
1783 memcpy(msg->payload + sizeof(struct pldm_pass_component_table_req),
1784 comp_ver_str->ptr, comp_ver_str->length);
1785
1786 return PLDM_SUCCESS;
1787}
1788
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001789LIBPLDM_ABI_TESTING
1790int decode_pass_component_table_req(
1791 const struct pldm_msg *msg, size_t payload_length,
1792 struct pldm_pass_component_table_req_full *pcomp)
1793{
1794 int rc;
1795 uint8_t t;
Andrew Jefferya1896962025-03-03 21:41:25 +10301796 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001797
1798 if (msg == NULL || pcomp == NULL) {
1799 return -EINVAL;
1800 }
1801
1802 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
1803 if (rc) {
1804 return rc;
1805 }
1806
1807 pldm_msgbuf_extract(buf, pcomp->transfer_flag);
1808 pldm_msgbuf_extract(buf, pcomp->comp_classification);
1809 pldm_msgbuf_extract(buf, pcomp->comp_identifier);
1810 pldm_msgbuf_extract(buf, pcomp->comp_classification_index);
1811 pldm_msgbuf_extract(buf, pcomp->comp_comparison_stamp);
1812 rc = pldm_msgbuf_extract(buf, t);
1813 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301814 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001815 }
1816 if (t > PLDM_STR_TYPE_UTF_16BE) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301817 return pldm_msgbuf_discard(buf, -EBADMSG);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001818 }
1819 pcomp->version.str_type = (enum pldm_firmware_update_string_type)t;
1820 rc = pldm_msgbuf_extract(buf, pcomp->version.str_len);
1821 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301822 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001823 }
1824 rc = pldm_msgbuf_extract_array(buf, pcomp->version.str_len,
1825 pcomp->version.str_data,
1826 PLDM_FIRMWARE_MAX_STRING);
1827 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301828 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001829 }
1830
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301831 return pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001832}
1833
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301834LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301835int decode_pass_component_table_resp(const struct pldm_msg *msg,
1836 const size_t payload_length,
1837 uint8_t *completion_code,
1838 uint8_t *comp_resp,
1839 uint8_t *comp_resp_code)
1840{
1841 if (msg == NULL || completion_code == NULL || comp_resp == NULL ||
1842 comp_resp_code == NULL || !payload_length) {
1843 return PLDM_ERROR_INVALID_DATA;
1844 }
1845
1846 *completion_code = msg->payload[0];
1847 if (*completion_code != PLDM_SUCCESS) {
1848 return PLDM_SUCCESS;
1849 }
1850
1851 if (payload_length != sizeof(struct pldm_pass_component_table_resp)) {
1852 return PLDM_ERROR_INVALID_LENGTH;
1853 }
1854
1855 struct pldm_pass_component_table_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301856 (struct pldm_pass_component_table_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301857
1858 if (!is_comp_resp_valid(response->comp_resp)) {
1859 return PLDM_ERROR_INVALID_DATA;
1860 }
1861
1862 if (!is_comp_resp_code_valid(response->comp_resp_code)) {
1863 return PLDM_ERROR_INVALID_DATA;
1864 }
1865
1866 *comp_resp = response->comp_resp;
1867 *comp_resp_code = response->comp_resp_code;
1868
1869 return PLDM_SUCCESS;
1870}
1871
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001872LIBPLDM_ABI_TESTING
1873int encode_pass_component_table_resp(
1874 uint8_t instance_id,
1875 const struct pldm_pass_component_table_resp *resp_data,
1876 struct pldm_msg *msg, size_t *payload_length)
1877{
Andrew Jefferya1896962025-03-03 21:41:25 +10301878 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001879 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001880
1881 if (msg == NULL || payload_length == NULL) {
1882 return -EINVAL;
1883 }
1884
1885 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
1886 PLDM_PASS_COMPONENT_TABLE, msg);
1887 if (rc) {
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_insert_uint8(buf, PLDM_SUCCESS);
1897 pldm_msgbuf_insert(buf, resp_data->comp_resp);
1898 pldm_msgbuf_insert(buf, resp_data->comp_resp_code);
1899
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301900 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001901}
1902
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301903LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301904int encode_update_component_req(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301905 uint8_t instance_id, uint16_t comp_classification,
1906 uint16_t comp_identifier, uint8_t comp_classification_index,
1907 uint32_t comp_comparison_stamp, uint32_t comp_image_size,
1908 bitfield32_t update_option_flags, uint8_t comp_ver_str_type,
1909 uint8_t comp_ver_str_len, const struct variable_field *comp_ver_str,
1910 struct pldm_msg *msg, size_t payload_length)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301911{
1912 if (comp_ver_str == NULL || comp_ver_str->ptr == NULL || msg == NULL) {
1913 return PLDM_ERROR_INVALID_DATA;
1914 }
1915
1916 if (payload_length !=
1917 sizeof(struct pldm_update_component_req) + comp_ver_str->length) {
1918 return PLDM_ERROR_INVALID_LENGTH;
1919 }
1920
1921 if (!comp_image_size) {
1922 return PLDM_ERROR_INVALID_DATA;
1923 }
1924
1925 if ((comp_ver_str_len == 0) ||
1926 (comp_ver_str_len != comp_ver_str->length)) {
1927 return PLDM_ERROR_INVALID_DATA;
1928 }
1929
1930 if (!is_string_type_valid(comp_ver_str_type)) {
1931 return PLDM_ERROR_INVALID_DATA;
1932 }
1933
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301934 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09301935 header.instance = instance_id;
1936 header.msg_type = PLDM_REQUEST;
1937 header.pldm_type = PLDM_FWUP;
1938 header.command = PLDM_UPDATE_COMPONENT;
1939 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
1940 if (rc) {
1941 return rc;
1942 }
1943
1944 struct pldm_update_component_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301945 (struct pldm_update_component_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301946
1947 request->comp_classification = htole16(comp_classification);
1948 request->comp_identifier = htole16(comp_identifier);
1949 request->comp_classification_index = comp_classification_index;
1950 request->comp_comparison_stamp = htole32(comp_comparison_stamp);
1951 request->comp_image_size = htole32(comp_image_size);
1952 request->update_option_flags.value = htole32(update_option_flags.value);
1953 request->comp_ver_str_type = comp_ver_str_type;
1954 request->comp_ver_str_len = comp_ver_str_len;
1955
1956 memcpy(msg->payload + sizeof(struct pldm_update_component_req),
1957 comp_ver_str->ptr, comp_ver_str->length);
1958
1959 return PLDM_SUCCESS;
1960}
1961
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001962LIBPLDM_ABI_TESTING
1963int decode_update_component_req(const struct pldm_msg *msg,
1964 size_t payload_length,
1965 struct pldm_update_component_req_full *up)
1966{
1967 int rc;
1968 uint8_t t;
Andrew Jefferya1896962025-03-03 21:41:25 +10301969 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001970
1971 if (msg == NULL || up == NULL) {
1972 return -EINVAL;
1973 }
1974
1975 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
1976 if (rc) {
1977 return rc;
1978 }
1979
1980 pldm_msgbuf_extract(buf, up->comp_classification);
1981 pldm_msgbuf_extract(buf, up->comp_identifier);
1982 pldm_msgbuf_extract(buf, up->comp_classification_index);
1983 pldm_msgbuf_extract(buf, up->comp_comparison_stamp);
1984 pldm_msgbuf_extract(buf, up->comp_image_size);
1985 pldm_msgbuf_extract(buf, up->update_option_flags.value);
1986 rc = pldm_msgbuf_extract(buf, t);
1987 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301988 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001989 }
1990 if (t > PLDM_STR_TYPE_UTF_16BE) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301991 return pldm_msgbuf_discard(buf, -EBADMSG);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001992 }
1993 up->version.str_type = (enum pldm_firmware_update_string_type)t;
1994 rc = pldm_msgbuf_extract(buf, up->version.str_len);
1995 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301996 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08001997 }
1998 rc = pldm_msgbuf_extract_array(buf, up->version.str_len,
1999 up->version.str_data,
2000 PLDM_FIRMWARE_MAX_STRING);
2001 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302002 return pldm_msgbuf_discard(buf, rc);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002003 }
2004
Andrew Jefferya1896962025-03-03 21:41:25 +10302005 return pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002006}
2007
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302008LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302009int decode_update_component_resp(const struct pldm_msg *msg,
2010 size_t payload_length,
2011 uint8_t *completion_code,
2012 uint8_t *comp_compatibility_resp,
2013 uint8_t *comp_compatibility_resp_code,
2014 bitfield32_t *update_option_flags_enabled,
2015 uint16_t *time_before_req_fw_data)
2016{
2017 if (msg == NULL || completion_code == NULL ||
2018 comp_compatibility_resp == NULL ||
2019 comp_compatibility_resp_code == NULL ||
2020 update_option_flags_enabled == NULL ||
2021 time_before_req_fw_data == NULL || !payload_length) {
2022 return PLDM_ERROR_INVALID_DATA;
2023 }
2024
2025 *completion_code = msg->payload[0];
2026 if (*completion_code != PLDM_SUCCESS) {
2027 return PLDM_SUCCESS;
2028 }
2029
2030 if (payload_length != sizeof(struct pldm_update_component_resp)) {
2031 return PLDM_ERROR_INVALID_LENGTH;
2032 }
2033
2034 struct pldm_update_component_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302035 (struct pldm_update_component_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302036
2037 if (!is_comp_compatibility_resp_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302038 response->comp_compatibility_resp)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302039 return PLDM_ERROR_INVALID_DATA;
2040 }
2041
2042 if (!is_comp_compatibility_resp_code_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302043 response->comp_compatibility_resp_code)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302044 return PLDM_ERROR_INVALID_DATA;
2045 }
2046
2047 *comp_compatibility_resp = response->comp_compatibility_resp;
2048 *comp_compatibility_resp_code = response->comp_compatibility_resp_code;
2049 update_option_flags_enabled->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302050 le32toh(response->update_option_flags_enabled.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302051 *time_before_req_fw_data = le16toh(response->time_before_req_fw_data);
2052
2053 return PLDM_SUCCESS;
2054}
2055
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002056LIBPLDM_ABI_TESTING
2057int encode_update_component_resp(
2058 uint8_t instance_id, const struct pldm_update_component_resp *resp_data,
2059 struct pldm_msg *msg, size_t *payload_length)
2060{
Andrew Jefferya1896962025-03-03 21:41:25 +10302061 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002062 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002063
2064 if (msg == NULL || payload_length == NULL) {
2065 return -EINVAL;
2066 }
2067
2068 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2069 PLDM_UPDATE_COMPONENT, msg);
2070 if (rc) {
2071 return -EINVAL;
2072 }
2073
2074 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2075 if (rc) {
2076 return rc;
2077 }
2078
2079 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2080 pldm_msgbuf_insert(buf, resp_data->comp_compatibility_resp);
2081 pldm_msgbuf_insert(buf, resp_data->comp_compatibility_resp_code);
2082 pldm_msgbuf_insert(buf, resp_data->update_option_flags_enabled.value);
2083 pldm_msgbuf_insert(buf, resp_data->time_before_req_fw_data);
2084
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302085 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002086}
2087
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302088LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302089int decode_request_firmware_data_req(const struct pldm_msg *msg,
2090 size_t payload_length, uint32_t *offset,
2091 uint32_t *length)
2092{
2093 if (msg == NULL || offset == NULL || length == NULL) {
2094 return PLDM_ERROR_INVALID_DATA;
2095 }
2096 if (payload_length != sizeof(struct pldm_request_firmware_data_req)) {
2097 return PLDM_ERROR_INVALID_LENGTH;
2098 }
2099 struct pldm_request_firmware_data_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302100 (struct pldm_request_firmware_data_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302101 *offset = le32toh(request->offset);
2102 *length = le32toh(request->length);
2103
2104 if (*length < PLDM_FWUP_BASELINE_TRANSFER_SIZE) {
2105 return PLDM_FWUP_INVALID_TRANSFER_LENGTH;
2106 }
2107
2108 return PLDM_SUCCESS;
2109}
2110
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002111LIBPLDM_ABI_TESTING
2112int encode_request_firmware_data_req(
2113 uint8_t instance_id,
2114 const struct pldm_request_firmware_data_req *req_params,
2115 struct pldm_msg *msg, size_t *payload_length)
2116{
Andrew Jefferya1896962025-03-03 21:41:25 +10302117 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002118 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002119
2120 if (msg == NULL || payload_length == NULL) {
2121 return -EINVAL;
2122 }
2123
2124 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2125 PLDM_REQUEST_FIRMWARE_DATA, msg);
2126 if (rc) {
2127 return -EINVAL;
2128 }
2129
2130 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2131 if (rc) {
2132 return rc;
2133 }
2134
2135 pldm_msgbuf_insert(buf, req_params->offset);
2136 pldm_msgbuf_insert(buf, req_params->length);
2137
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302138 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002139}
2140
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302141LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302142int encode_request_firmware_data_resp(uint8_t instance_id,
2143 uint8_t completion_code,
2144 struct pldm_msg *msg,
2145 size_t payload_length)
2146{
2147 if (msg == NULL || !payload_length) {
2148 return PLDM_ERROR_INVALID_DATA;
2149 }
2150
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302151 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302152 header.instance = instance_id;
2153 header.msg_type = PLDM_RESPONSE;
2154 header.pldm_type = PLDM_FWUP;
2155 header.command = PLDM_REQUEST_FIRMWARE_DATA;
2156 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2157 if (rc) {
2158 return rc;
2159 }
2160
2161 msg->payload[0] = completion_code;
2162
2163 return PLDM_SUCCESS;
2164}
2165
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302166LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302167int decode_transfer_complete_req(const struct pldm_msg *msg,
2168 size_t payload_length,
2169 uint8_t *transfer_result)
2170{
2171 if (msg == NULL || transfer_result == NULL) {
2172 return PLDM_ERROR_INVALID_DATA;
2173 }
2174
2175 if (payload_length != sizeof(*transfer_result)) {
2176 return PLDM_ERROR_INVALID_LENGTH;
2177 }
2178
2179 *transfer_result = msg->payload[0];
2180 return PLDM_SUCCESS;
2181}
2182
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002183LIBPLDM_ABI_TESTING
2184int encode_transfer_complete_req(uint8_t instance_id, uint8_t transfer_result,
2185 struct pldm_msg *msg, size_t *payload_length)
2186{
Andrew Jefferya1896962025-03-03 21:41:25 +10302187 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002188 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002189
2190 if (msg == NULL || payload_length == NULL) {
2191 return -EINVAL;
2192 }
2193
2194 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2195 PLDM_TRANSFER_COMPLETE, msg);
2196 if (rc) {
2197 return -EINVAL;
2198 }
2199
2200 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2201 if (rc) {
2202 return rc;
2203 }
2204
Andrew Jefferya1896962025-03-03 21:41:25 +10302205 pldm_msgbuf_insert(buf, transfer_result);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002206
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302207 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002208}
2209
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302210LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302211int encode_transfer_complete_resp(uint8_t instance_id, uint8_t completion_code,
2212 struct pldm_msg *msg, size_t payload_length)
2213{
2214 if (msg == NULL) {
2215 return PLDM_ERROR_INVALID_DATA;
2216 }
2217
2218 if (payload_length != sizeof(completion_code)) {
2219 return PLDM_ERROR_INVALID_LENGTH;
2220 }
2221
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302222 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302223 header.instance = instance_id;
2224 header.msg_type = PLDM_RESPONSE;
2225 header.pldm_type = PLDM_FWUP;
2226 header.command = PLDM_TRANSFER_COMPLETE;
2227 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2228 if (rc) {
2229 return rc;
2230 }
2231
2232 msg->payload[0] = completion_code;
2233
2234 return PLDM_SUCCESS;
2235}
2236
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302237LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302238int decode_verify_complete_req(const struct pldm_msg *msg,
2239 size_t payload_length, uint8_t *verify_result)
2240{
2241 if (msg == NULL || verify_result == NULL) {
2242 return PLDM_ERROR_INVALID_DATA;
2243 }
2244
2245 if (payload_length != sizeof(*verify_result)) {
2246 return PLDM_ERROR_INVALID_LENGTH;
2247 }
2248
2249 *verify_result = msg->payload[0];
2250 return PLDM_SUCCESS;
2251}
2252
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002253LIBPLDM_ABI_TESTING
2254int encode_verify_complete_req(uint8_t instance_id, uint8_t verify_result,
2255 struct pldm_msg *msg, size_t *payload_length)
2256{
Andrew Jefferya1896962025-03-03 21:41:25 +10302257 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002258 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002259
2260 if (msg == NULL || payload_length == NULL) {
2261 return -EINVAL;
2262 }
2263
2264 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2265 PLDM_VERIFY_COMPLETE, msg);
2266 if (rc) {
2267 return EINVAL;
2268 }
2269
2270 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2271 if (rc) {
2272 return rc;
2273 }
2274
Andrew Jefferya1896962025-03-03 21:41:25 +10302275 pldm_msgbuf_insert(buf, verify_result);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002276
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302277 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002278}
2279
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302280LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302281int encode_verify_complete_resp(uint8_t instance_id, uint8_t completion_code,
2282 struct pldm_msg *msg, size_t payload_length)
2283{
2284 if (msg == NULL) {
2285 return PLDM_ERROR_INVALID_DATA;
2286 }
2287
2288 if (payload_length != sizeof(completion_code)) {
2289 return PLDM_ERROR_INVALID_LENGTH;
2290 }
2291
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302292 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302293 header.instance = instance_id;
2294 header.msg_type = PLDM_RESPONSE;
2295 header.pldm_type = PLDM_FWUP;
2296 header.command = PLDM_VERIFY_COMPLETE;
2297 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2298 if (rc) {
2299 return rc;
2300 }
2301
2302 msg->payload[0] = completion_code;
2303
2304 return PLDM_SUCCESS;
2305}
2306
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302307LIBPLDM_ABI_STABLE
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302308int decode_apply_complete_req(const struct pldm_msg *msg, size_t payload_length,
2309 uint8_t *apply_result,
2310 bitfield16_t *comp_activation_methods_modification)
Andrew Jeffery9c766792022-08-10 23:12:49 +09302311{
2312 if (msg == NULL || apply_result == NULL ||
2313 comp_activation_methods_modification == NULL) {
2314 return PLDM_ERROR_INVALID_DATA;
2315 }
2316
2317 if (payload_length != sizeof(struct pldm_apply_complete_req)) {
2318 return PLDM_ERROR_INVALID_LENGTH;
2319 }
2320
2321 struct pldm_apply_complete_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302322 (struct pldm_apply_complete_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302323
2324 *apply_result = request->apply_result;
2325 comp_activation_methods_modification->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302326 le16toh(request->comp_activation_methods_modification.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302327
2328 if ((*apply_result != PLDM_FWUP_APPLY_SUCCESS_WITH_ACTIVATION_METHOD) &&
2329 comp_activation_methods_modification->value) {
2330 return PLDM_ERROR_INVALID_DATA;
2331 }
2332
2333 return PLDM_SUCCESS;
2334}
2335
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002336LIBPLDM_ABI_TESTING
2337int encode_apply_complete_req(uint8_t instance_id,
2338 const struct pldm_apply_complete_req *req_data,
2339 struct pldm_msg *msg, size_t *payload_length)
2340{
Andrew Jefferya1896962025-03-03 21:41:25 +10302341 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002342 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002343
2344 if (msg == NULL || payload_length == NULL) {
2345 return -EINVAL;
2346 }
2347
2348 rc = encode_pldm_header_only(PLDM_REQUEST, instance_id, PLDM_FWUP,
2349 PLDM_APPLY_COMPLETE, msg);
2350 if (rc) {
2351 return -EINVAL;
2352 }
2353
2354 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2355 if (rc) {
2356 return rc;
2357 }
2358
2359 pldm_msgbuf_insert(buf, req_data->apply_result);
2360 pldm_msgbuf_insert(
2361 buf, req_data->comp_activation_methods_modification.value);
2362
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302363 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002364}
2365
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302366LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302367int encode_apply_complete_resp(uint8_t instance_id, uint8_t completion_code,
2368 struct pldm_msg *msg, size_t payload_length)
2369{
2370 if (msg == NULL) {
2371 return PLDM_ERROR_INVALID_DATA;
2372 }
2373
2374 if (payload_length != sizeof(completion_code)) {
2375 return PLDM_ERROR_INVALID_LENGTH;
2376 }
2377
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302378 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302379 header.instance = instance_id;
2380 header.msg_type = PLDM_RESPONSE;
2381 header.pldm_type = PLDM_FWUP;
2382 header.command = PLDM_APPLY_COMPLETE;
2383 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2384 if (rc) {
2385 return rc;
2386 }
2387
2388 msg->payload[0] = completion_code;
2389
2390 return PLDM_SUCCESS;
2391}
2392
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002393LIBPLDM_ABI_TESTING
2394int decode_activate_firmware_req(const struct pldm_msg *msg,
2395 size_t payload_length, bool *self_contained)
2396{
Andrew Jefferya1896962025-03-03 21:41:25 +10302397 uint8_t self_contained_u8 = 0;
2398 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002399 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002400
2401 if (msg == NULL || self_contained == NULL) {
2402 return -EINVAL;
2403 }
2404
2405 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, payload_length);
2406 if (rc) {
2407 return 0;
2408 }
2409
Andrew Jefferya1896962025-03-03 21:41:25 +10302410 pldm_msgbuf_extract(buf, self_contained_u8);
2411
2412 rc = pldm_msgbuf_complete_consumed(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002413 if (rc) {
2414 return rc;
2415 }
Andrew Jefferya1896962025-03-03 21:41:25 +10302416
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002417 *self_contained = (bool)self_contained_u8;
2418 return 0;
2419}
2420
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302421LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302422int encode_activate_firmware_req(uint8_t instance_id,
2423 bool8_t self_contained_activation_req,
2424 struct pldm_msg *msg, size_t payload_length)
2425{
2426 if (msg == NULL) {
2427 return PLDM_ERROR_INVALID_DATA;
2428 }
2429
2430 if (payload_length != sizeof(struct pldm_activate_firmware_req)) {
2431 return PLDM_ERROR_INVALID_LENGTH;
2432 }
2433
2434 if (!is_self_contained_activation_req_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302435 self_contained_activation_req)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302436 return PLDM_ERROR_INVALID_DATA;
2437 }
2438
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302439 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302440 header.instance = instance_id;
2441 header.msg_type = PLDM_REQUEST;
2442 header.pldm_type = PLDM_FWUP;
2443 header.command = PLDM_ACTIVATE_FIRMWARE;
2444 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2445 if (rc) {
2446 return rc;
2447 }
2448
2449 struct pldm_activate_firmware_req *request =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302450 (struct pldm_activate_firmware_req *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302451
2452 request->self_contained_activation_req = self_contained_activation_req;
2453
2454 return PLDM_SUCCESS;
2455}
2456
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302457LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302458int decode_activate_firmware_resp(const struct pldm_msg *msg,
2459 size_t payload_length,
2460 uint8_t *completion_code,
2461 uint16_t *estimated_time_activation)
2462{
2463 if (msg == NULL || completion_code == NULL ||
2464 estimated_time_activation == NULL || !payload_length) {
2465 return PLDM_ERROR_INVALID_DATA;
2466 }
2467
2468 *completion_code = msg->payload[0];
2469 if (*completion_code != PLDM_SUCCESS) {
2470 return PLDM_SUCCESS;
2471 }
2472
2473 if (payload_length != sizeof(struct pldm_activate_firmware_resp)) {
2474 return PLDM_ERROR_INVALID_LENGTH;
2475 }
2476
2477 struct pldm_activate_firmware_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302478 (struct pldm_activate_firmware_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302479
2480 *estimated_time_activation =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302481 le16toh(response->estimated_time_activation);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302482
2483 return PLDM_SUCCESS;
2484}
2485
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002486LIBPLDM_ABI_TESTING
2487int encode_activate_firmware_resp(
2488 uint8_t instance_id,
2489 const struct pldm_activate_firmware_resp *resp_data,
2490 struct pldm_msg *msg, size_t *payload_length)
2491{
Andrew Jefferya1896962025-03-03 21:41:25 +10302492 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002493 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002494
2495 if (msg == NULL || payload_length == NULL) {
2496 return -EINVAL;
2497 }
2498
2499 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2500 PLDM_ACTIVATE_FIRMWARE, msg);
2501 if (rc) {
2502 return -EINVAL;
2503 }
2504
2505 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2506 if (rc) {
2507 return rc;
2508 }
2509
2510 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2511 pldm_msgbuf_insert(buf, resp_data->estimated_time_activation);
2512
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302513 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002514}
2515
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302516LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302517int encode_get_status_req(uint8_t instance_id, struct pldm_msg *msg,
2518 size_t payload_length)
2519{
2520 if (msg == NULL) {
2521 return PLDM_ERROR_INVALID_DATA;
2522 }
2523
2524 if (payload_length != PLDM_GET_STATUS_REQ_BYTES) {
2525 return PLDM_ERROR_INVALID_LENGTH;
2526 }
2527
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302528 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302529 header.instance = instance_id;
2530 header.msg_type = PLDM_REQUEST;
2531 header.pldm_type = PLDM_FWUP;
2532 header.command = PLDM_GET_STATUS;
2533 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2534 if (rc) {
2535 return rc;
2536 }
2537
2538 return PLDM_SUCCESS;
2539}
2540
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302541LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302542int decode_get_status_resp(const struct pldm_msg *msg, size_t payload_length,
2543 uint8_t *completion_code, uint8_t *current_state,
2544 uint8_t *previous_state, uint8_t *aux_state,
2545 uint8_t *aux_state_status, uint8_t *progress_percent,
2546 uint8_t *reason_code,
2547 bitfield32_t *update_option_flags_enabled)
2548{
2549 if (msg == NULL || completion_code == NULL || current_state == NULL ||
2550 previous_state == NULL || aux_state == NULL ||
2551 aux_state_status == NULL || progress_percent == NULL ||
2552 reason_code == NULL || update_option_flags_enabled == NULL ||
2553 !payload_length) {
2554 return PLDM_ERROR_INVALID_DATA;
2555 }
2556
2557 *completion_code = msg->payload[0];
2558 if (*completion_code != PLDM_SUCCESS) {
2559 return PLDM_SUCCESS;
2560 }
2561
2562 if (payload_length != sizeof(struct pldm_get_status_resp)) {
2563 return PLDM_ERROR_INVALID_LENGTH;
2564 }
2565 struct pldm_get_status_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302566 (struct pldm_get_status_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302567
2568 if (!is_state_valid(response->current_state)) {
2569 return PLDM_ERROR_INVALID_DATA;
2570 }
2571 if (!is_state_valid(response->previous_state)) {
2572 return PLDM_ERROR_INVALID_DATA;
2573 }
2574 if (!is_aux_state_valid(response->aux_state)) {
2575 return PLDM_ERROR_INVALID_DATA;
2576 }
2577 if (!is_aux_state_status_valid(response->aux_state_status)) {
2578 return PLDM_ERROR_INVALID_DATA;
2579 }
2580 if (response->progress_percent > PLDM_FWUP_MAX_PROGRESS_PERCENT) {
2581 return PLDM_ERROR_INVALID_DATA;
2582 }
2583 if (!is_reason_code_valid(response->reason_code)) {
2584 return PLDM_ERROR_INVALID_DATA;
2585 }
2586
2587 if ((response->current_state == PLDM_FD_STATE_IDLE) ||
2588 (response->current_state == PLDM_FD_STATE_LEARN_COMPONENTS) ||
2589 (response->current_state == PLDM_FD_STATE_READY_XFER)) {
2590 if (response->aux_state !=
2591 PLDM_FD_IDLE_LEARN_COMPONENTS_READ_XFER) {
2592 return PLDM_ERROR_INVALID_DATA;
2593 }
2594 }
2595
2596 *current_state = response->current_state;
2597 *previous_state = response->previous_state;
2598 *aux_state = response->aux_state;
2599 *aux_state_status = response->aux_state_status;
2600 *progress_percent = response->progress_percent;
2601 *reason_code = response->reason_code;
2602 update_option_flags_enabled->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302603 le32toh(response->update_option_flags_enabled.value);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302604
2605 return PLDM_SUCCESS;
2606}
2607
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002608LIBPLDM_ABI_TESTING
2609int encode_get_status_resp(uint8_t instance_id,
2610 const struct pldm_get_status_resp *status,
2611 struct pldm_msg *msg, size_t *payload_length)
2612{
Andrew Jefferya1896962025-03-03 21:41:25 +10302613 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002614 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002615
2616 if (status == NULL || msg == NULL || payload_length == NULL) {
2617 return -EINVAL;
2618 }
2619
2620 if (status->completion_code != PLDM_SUCCESS) {
2621 return -EINVAL;
2622 }
2623
2624 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2625 PLDM_GET_STATUS, msg);
2626 if (rc) {
2627 return -EINVAL;
2628 }
2629
2630 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2631 if (rc) {
2632 return rc;
2633 }
2634
2635 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2636 pldm_msgbuf_insert(buf, status->current_state);
2637 pldm_msgbuf_insert(buf, status->previous_state);
2638 pldm_msgbuf_insert(buf, status->aux_state);
2639 pldm_msgbuf_insert(buf, status->aux_state_status);
2640 pldm_msgbuf_insert(buf, status->progress_percent);
2641 pldm_msgbuf_insert(buf, status->reason_code);
2642 pldm_msgbuf_insert(buf, status->update_option_flags_enabled.value);
2643
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302644 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002645}
2646
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302647LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302648int encode_cancel_update_component_req(uint8_t instance_id,
2649 struct pldm_msg *msg,
2650 size_t payload_length)
2651{
2652 if (msg == NULL) {
2653 return PLDM_ERROR_INVALID_DATA;
2654 }
2655
2656 if (payload_length != PLDM_CANCEL_UPDATE_COMPONENT_REQ_BYTES) {
2657 return PLDM_ERROR_INVALID_LENGTH;
2658 }
2659
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302660 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302661 header.instance = instance_id;
2662 header.msg_type = PLDM_REQUEST;
2663 header.pldm_type = PLDM_FWUP;
2664 header.command = PLDM_CANCEL_UPDATE_COMPONENT;
2665 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2666 if (rc) {
2667 return rc;
2668 }
2669
2670 return PLDM_SUCCESS;
2671}
2672
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302673LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302674int decode_cancel_update_component_resp(const struct pldm_msg *msg,
2675 size_t payload_length,
2676 uint8_t *completion_code)
2677{
2678 if (msg == NULL || completion_code == NULL) {
2679 return PLDM_ERROR_INVALID_DATA;
2680 }
2681
2682 if (payload_length != sizeof(*completion_code)) {
2683 return PLDM_ERROR_INVALID_LENGTH;
2684 }
2685
2686 *completion_code = msg->payload[0];
2687 return PLDM_SUCCESS;
2688}
2689
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302690LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302691int encode_cancel_update_req(uint8_t instance_id, struct pldm_msg *msg,
2692 size_t payload_length)
2693{
2694 if (msg == NULL) {
2695 return PLDM_ERROR_INVALID_DATA;
2696 }
2697
2698 if (payload_length != PLDM_CANCEL_UPDATE_REQ_BYTES) {
2699 return PLDM_ERROR_INVALID_LENGTH;
2700 }
2701
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302702 struct pldm_header_info header = { 0 };
Andrew Jeffery9c766792022-08-10 23:12:49 +09302703 header.instance = instance_id;
2704 header.msg_type = PLDM_REQUEST;
2705 header.pldm_type = PLDM_FWUP;
2706 header.command = PLDM_CANCEL_UPDATE;
2707 uint8_t rc = pack_pldm_header(&header, &(msg->hdr));
2708 if (rc) {
2709 return rc;
2710 }
2711
2712 return PLDM_SUCCESS;
2713}
2714
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09302715LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09302716int decode_cancel_update_resp(const struct pldm_msg *msg, size_t payload_length,
2717 uint8_t *completion_code,
2718 bool8_t *non_functioning_component_indication,
2719 bitfield64_t *non_functioning_component_bitmap)
2720{
2721 if (msg == NULL || completion_code == NULL ||
2722 non_functioning_component_indication == NULL ||
2723 non_functioning_component_bitmap == NULL || !payload_length) {
2724 return PLDM_ERROR_INVALID_DATA;
2725 }
2726
2727 *completion_code = msg->payload[0];
2728 if (*completion_code != PLDM_SUCCESS) {
2729 return PLDM_SUCCESS;
2730 }
2731
2732 if (payload_length != sizeof(struct pldm_cancel_update_resp)) {
2733 return PLDM_ERROR_INVALID_LENGTH;
2734 }
2735 struct pldm_cancel_update_resp *response =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302736 (struct pldm_cancel_update_resp *)msg->payload;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302737
2738 if (!is_non_functioning_component_indication_valid(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302739 response->non_functioning_component_indication)) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09302740 return PLDM_ERROR_INVALID_DATA;
2741 }
2742
2743 *non_functioning_component_indication =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302744 response->non_functioning_component_indication;
Andrew Jeffery9c766792022-08-10 23:12:49 +09302745
2746 if (*non_functioning_component_indication) {
2747 non_functioning_component_bitmap->value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09302748 le64toh(response->non_functioning_component_bitmap);
Andrew Jeffery9c766792022-08-10 23:12:49 +09302749 }
2750
2751 return PLDM_SUCCESS;
2752}
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002753
2754LIBPLDM_ABI_TESTING
2755int encode_cancel_update_resp(uint8_t instance_id,
2756 const struct pldm_cancel_update_resp *resp_data,
2757 struct pldm_msg *msg, size_t *payload_length)
2758{
Andrew Jefferya1896962025-03-03 21:41:25 +10302759 PLDM_MSGBUF_DEFINE_P(buf);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002760 int rc;
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002761
2762 if (msg == NULL || payload_length == NULL) {
2763 return -EINVAL;
2764 }
2765
2766 rc = encode_pldm_header_only(PLDM_RESPONSE, instance_id, PLDM_FWUP,
2767 PLDM_CANCEL_UPDATE, msg);
2768 if (rc) {
2769 return -EINVAL;
2770 }
2771
2772 rc = pldm_msgbuf_init_errno(buf, 0, msg->payload, *payload_length);
2773 if (rc) {
2774 return rc;
2775 }
2776
2777 pldm_msgbuf_insert_uint8(buf, PLDM_SUCCESS);
2778 pldm_msgbuf_insert(buf,
2779 resp_data->non_functioning_component_indication);
2780 pldm_msgbuf_insert(buf, resp_data->non_functioning_component_bitmap);
2781
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302782 return pldm_msgbuf_complete_used(buf, *payload_length, payload_length);
Matt Johnstoncf9a2df2024-11-07 15:29:29 +08002783}